diff --git a/.gitattributes b/.gitattributes index e58996311..e375d2543 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,12 @@ *.odin linguist-language=Odin * text=auto - # These files must always have *nix line-endings Makefile text eol=lf -*.sh text eol=lf \ No newline at end of file +*.sh text eol=lf +vendor/box2d/lib/box2d_windows_amd64_avx2.lib filter=lfs diff=lfs merge=lfs -text +vendor/box2d/lib/box2d_windows_amd64_sse2.lib filter=lfs diff=lfs merge=lfs -text +vendor/miniaudio/lib/miniaudio.lib filter=lfs diff=lfs merge=lfs -text +vendor/sdl3/SDL3.dll filter=lfs diff=lfs merge=lfs -text +vendor/sdl3/SDL3.lib filter=lfs diff=lfs merge=lfs -text +vendor/sdl3/mixer/*.dll filter=lfs diff=lfs merge=lfs -text +vendor/sdl3/mixer/*.lib filter=lfs diff=lfs merge=lfs -text diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc5e4f592..dd49b8ff8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ jobs: name: NetBSD Build, Check, and Test runs-on: ubuntu-latest env: - PKGSRC_BRANCH: 2025Q2 + PKGSRC_BRANCH: 2025Q4 steps: - uses: actions/checkout@v4 - name: Build, Check, and Test @@ -93,8 +93,8 @@ jobs: if: matrix.os == 'macos-latest' run: | brew update - brew install llvm@20 wasmtime lua@5.4 lld - echo "$(brew --prefix llvm@20)/bin" >> $GITHUB_PATH + brew install llvm@22 wasmtime lua@5.4 lld + echo "$(brew --prefix llvm@22)/bin" >> $GITHUB_PATH - name: Download LLVM (Ubuntu) if: matrix.os == 'ubuntu-latest' || matrix.os == 'ubuntu-24.04-arm' @@ -139,8 +139,19 @@ jobs: run: ./odin test tests/core/normal.odin -file -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address - name: Optimized Core library tests run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address + - name: Wycheproof tests + + run: ./odin test tests/core/crypto/wycheproof -vet -vet-tabs -strict-style -vet-style -vet-cast -warnings-as-errors -disallow-do -o:speed - name: Vendor library tests run: ./odin test tests/vendor -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address + if: matrix.os != 'macos-15-intel' && matrix.os != 'macos-latest' + - name: Vendor library tests (MacOS ARM) + run: ./odin test tests/vendor -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address -extra-linker-flags:"-L/opt/homebrew/opt/lua@5.4/lib" + if: matrix.os == 'macos-latest' + - name: Vendor library tests (MacOS Intel) + run: ./odin test tests/vendor -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address -extra-linker-flags:"-L/usr/local/opt/lua@5.4/lib" + if: matrix.os == 'macos-15-intel' + - name: Internals tests run: ./odin test tests/internal -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address - name: GitHub Issue tests @@ -156,18 +167,14 @@ jobs: - name: Check benchmarks run: ./odin check tests/benchmark -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point + - name: Odin check examples/all for Linux i386 if: matrix.os == 'ubuntu-latest' run: ./odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_i386 - - name: Odin check examples/all for Linux arm64 - if: matrix.os == 'ubuntu-latest' - run: ./odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_arm64 - - name: Odin check examples/all for FreeBSD amd64 - if: matrix.os == 'ubuntu-latest' - run: ./odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freebsd_amd64 - name: Odin check examples/all for OpenBSD amd64 if: matrix.os == 'ubuntu-latest' run: ./odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:openbsd_amd64 + - name: Odin check examples/all for js_wasm32 if: matrix.os == 'ubuntu-latest' run: ./odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point -target:js_wasm32 @@ -178,12 +185,6 @@ jobs: - name: Odin check examples/all/sdl3 for Linux i386 if: matrix.os == 'ubuntu-latest' run: ./odin check examples/all/sdl3 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point -target:linux_i386 - - name: Odin check examples/all/sdl3 for Linux arm64 - if: matrix.os == 'ubuntu-latest' - run: ./odin check examples/all/sdl3 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point -target:linux_arm64 - - name: Odin check examples/all/sdl3 for FreeBSD amd64 - if: matrix.os == 'ubuntu-latest' - run: ./odin check examples/all/sdl3 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point -target:freebsd_amd64 - name: Odin check examples/all/sdl3 for OpenBSD amd64 if: matrix.os == 'ubuntu-latest' run: ./odin check examples/all/sdl3 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point -target:openbsd_amd64 @@ -197,7 +198,7 @@ jobs: - name: build Odin shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" ./build.bat 1 - name: Odin version run: ./odin version @@ -206,70 +207,75 @@ jobs: - name: Odin check shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" odin check examples/demo -vet - name: Odin run shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" odin run examples/demo - name: Odin run -debug shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" odin run examples/demo -debug -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do - name: Odin check examples/all shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do - name: Odin check examples/all/sdl3 shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" odin check examples/all/sdl3 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point - name: Core library tests shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" odin test tests/core/normal.odin -file -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address - name: Optimized core library tests shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" odin test tests/core/speed.odin -o:speed -file -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address + - name: Wycheproof tests + shell: cmd + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + odin test tests/core/crypto/wycheproof -vet -vet-tabs -strict-style -vet-style -vet-cast -warnings-as-errors -disallow-do -o:speed -microarch:native - name: Vendor library tests shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" copy vendor\lua\5.4\windows\*.dll . odin test tests/vendor -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address - name: Odin internals tests shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" odin test tests/internal -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address - name: Check issues shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" cd tests/issues call run.bat - name: Check benchmarks shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" odin check tests/benchmark -vet -strict-style -no-entry-point - name: Odin documentation tests shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" cd tests\documentation call build.bat - name: Odin check examples/all for Windows 32bits shell: cmd run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" odin check examples/all -strict-style -target:windows_i386 build_linux_riscv64: diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 48ea93ded..c7858c82c 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -12,6 +12,8 @@ jobs: runs-on: windows-2022 steps: - uses: actions/checkout@v4 + with: + lfs: true - name: build Odin shell: cmd run: | @@ -47,6 +49,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + lfs: true - name: (Linux) Download LLVM and Build Odin run: | docker run --rm -v "$PWD:/src" -w /src alpine sh -c ' @@ -87,6 +91,8 @@ jobs: runs-on: ubuntu-24.04-arm steps: - uses: actions/checkout@v4 + with: + lfs: true - name: (Linux ARM) Download LLVM and Build Odin run: | docker run --rm -v "$PWD:/src" -w /src arm64v8/alpine sh -c ' @@ -127,6 +133,8 @@ jobs: runs-on: macos-15-intel steps: - uses: actions/checkout@v4 + with: + lfs: true - name: Download LLVM and setup PATH run: | brew update @@ -166,6 +174,8 @@ jobs: runs-on: macos-latest # ARM machine steps: - uses: actions/checkout@v4 + with: + lfs: true - name: Download LLVM and setup PATH run: | brew update diff --git a/.gitignore b/.gitignore index 4efb5d73e..00dbcc2a5 100644 --- a/.gitignore +++ b/.gitignore @@ -279,6 +279,9 @@ demo.bin libLLVM*.so* *.a +# WASM +*.wasm + # shared collection shared/ diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 41a1ae1ee..ee99da1b3 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -38,6 +38,8 @@ count_ones :: proc(x: $T) -> T where type_is_integer(T) || type_is_sim count_zeros :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) --- count_trailing_zeros :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) --- count_leading_zeros :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) --- +count_trailing_ones :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) --- +count_leading_ones :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) --- reverse_bits :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) --- byte_swap :: proc(x: $T) -> T where type_is_integer(T) || type_is_float(T) --- @@ -75,7 +77,9 @@ prefetch_write_instruction :: proc(address: rawptr, #const locality: i32 /* 0..= prefetch_write_data :: proc(address: rawptr, #const locality: i32 /* 0..=3 */) --- // Compiler Hints -expect :: proc(val, expected_val: $T) -> T --- +expect :: proc(val, expected_val: $T) -> T --- +likely :: proc(val: $T) -> T where type_is_boolean(T) --- +unlikely :: proc(val: $T) -> T where type_is_boolean(T) --- // Linux and Darwin Only syscall :: proc(id: uintptr, args: ..uintptr) -> uintptr --- @@ -178,6 +182,7 @@ type_is_bit_set :: proc($T: typeid) -> bool --- type_is_bit_field :: proc($T: typeid) -> bool --- type_is_simd_vector :: proc($T: typeid) -> bool --- type_is_matrix :: proc($T: typeid) -> bool --- +type_is_fixed_capacity_dynamic_array :: proc($T: typeid) -> bool --- type_has_nil :: proc($T: typeid) -> bool --- @@ -220,6 +225,8 @@ type_is_superset_of :: proc($Super, $Sub: typeid) -> bool --- type_field_index_of :: proc($T: typeid, $name: string) -> uintptr --- +type_fixed_capacity_dynamic_array_len_offset :: proc($T: typeid/[dynamic; $N]$E) -> uintptr --- + // "Contiguous" means that the set of enum constants, when sorted, have a difference of either 0 or 1 between consecutive values. // This is the exact opposite of "sparse". type_enum_is_contiguous :: proc($T: typeid) -> bool where type_is_enum(T) --- @@ -355,7 +362,7 @@ has_target_feature :: proc($test: $T) -> bool where type_is_string(T) || type_is // Utility Calls -concatentate :: proc(x, y: $T, z: ..T) -> T where type_is_array(T) || type_is_slice(T) --- +concatenate :: proc(x, y: $T, z: ..T) -> T where type_is_array(T) || type_is_slice(T) --- // Returns the value of the procedure where `x` must be a call expression procedure_of :: proc(x: $T) -> T where type_is_proc(T) --- diff --git a/base/runtime/core.odin b/base/runtime/core.odin index 58a0b8ad1..dbd8ba468 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -39,6 +39,10 @@ Calling_Convention :: enum u8 { Win64 = 9, SysV = 10, + + Preserve_None = 11, + Preserve_Most = 12, + Preserve_All = 13, } Type_Info_Enum_Value :: distinct i64 @@ -122,6 +126,7 @@ Type_Info_Struct_Flag :: enum u8 { raw_union = 1, all_or_none = 2, align = 3, + simple = 4, } Type_Info_Struct :: struct { @@ -136,7 +141,7 @@ Type_Info_Struct :: struct { flags: Type_Info_Struct_Flags, - // These are only set iff this structure is an SOA structure + // These are only set if and only if (⟺) this structure is an SOA structure soa_kind: Type_Info_Struct_Soa_Kind, soa_len: i32, soa_base_type: ^Type_Info, @@ -165,10 +170,11 @@ Type_Info_Map :: struct { map_info: ^Map_Info, } Type_Info_Bit_Set :: struct { - elem: ^Type_Info, - underlying: ^Type_Info, // Possibly nil - lower: i64, - upper: i64, + elem: ^Type_Info, + underlying: ^Type_Info, + explicit_underlying: bool, // false = bit_set[T], true = bit_set[T, U] + lower: i64, + upper: i64, } Type_Info_Simd_Vector :: struct { elem: ^Type_Info, @@ -200,6 +206,14 @@ Type_Info_Bit_Field :: struct { field_count: int, } +Type_Info_Fixed_Capacity_Dynamic_Array :: struct { + elem: ^Type_Info, + elem_size: int, + capacity: int, + len_offset: uintptr, +} + + Type_Info_Flag :: enum u8 { Comparable = 0, Simple_Compare = 1, @@ -240,6 +254,7 @@ Type_Info :: struct { Type_Info_Matrix, Type_Info_Soa_Pointer, Type_Info_Bit_Field, + Type_Info_Fixed_Capacity_Dynamic_Array, }, } @@ -419,6 +434,11 @@ Raw_Dynamic_Array :: struct { allocator: Allocator, } +Raw_Fixed_Capacity_Dynamic_Array :: struct($Capacity: uint, $T: typeid) { + data: [Capacity]T, + len: int, +} + // The raw, type-erased representation of a map. // // 32-bytes on 64-bit @@ -653,9 +673,8 @@ type_info_base :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { return base } - // type_info_core returns the core-type of a `^Type_Info` stripping the `distinct`ness from the first level AND/OR -// returns the backing integer type of an enum or bit_set `^Type_Info`. +// returns the backing integer type of an enum `^Type_Info`. // This is also aliased as `type_info_base_without_enum` @(require_results) type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { @@ -675,11 +694,35 @@ type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { return base } -// type_info_base_without_enum returns the core-type of a `^Type_Info` stripping the `distinct`ness from the first level AND/OR + + +// type_info_underlying returns the underlying (backing) type of a `^Type_Info` stripping the `distinct`ness from the first level AND/OR +// returns the backing integer type of an enum `^Type_Info` AND/OR the underlying integer type of a bit_set or bit_field. +@(require_results) +type_info_underlying :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { + if info == nil { + return nil + } + + base := info + loop: for { + #partial switch i in base.variant { + case Type_Info_Named: base = i.base + case Type_Info_Enum: base = i.base + case Type_Info_Bit_Set: base = i.underlying + case Type_Info_Bit_Field: base = i.backing_type + case: break loop + } + } + return base +} + +// `type_info_base_without_enum` returns the core-type of a `^Type_Info` stripping the `distinct`ness from the first level AND/OR // returns the backing integer type of an enum or bit_set `^Type_Info`. // This is also aliased as `type_info_core` type_info_base_without_enum :: type_info_core +@(require_results) __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check { n := u64(len(type_table)) i := transmute(u64)id % n @@ -695,14 +738,16 @@ __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check when !ODIN_NO_RTTI { // typeid_base returns the base-type of a `typeid` stripping the `distinct`ness from the first level + @(require_results) typeid_base :: proc "contextless" (id: typeid) -> typeid { ti := type_info_of(id) ti = type_info_base(ti) return ti.id } // typeid_core returns the core-type of a `typeid` stripping the `distinct`ness from the first level AND/OR - // returns the backing integer type of an enum or bit_set `typeid`. + // returns the backing integer type of an enum `typeid`. // This is also aliased as `typeid_base_without_enum` + @(require_results) typeid_core :: proc "contextless" (id: typeid) -> typeid { ti := type_info_core(type_info_of(id)) return ti.id @@ -712,6 +757,12 @@ when !ODIN_NO_RTTI { // returns the backing integer type of an enum or bit_set `typeid`. // This is also aliased as `typeid_core` typeid_base_without_enum :: typeid_core + + @(require_results) + typeid_underlying :: proc "contextless" (id: typeid) -> typeid { + ti := type_info_underlying(type_info_of(id)) + return ti.id + } } diff --git a/base/runtime/core_builtin.odin b/base/runtime/core_builtin.odin index 9f3fcbf9a..fe76ee5a5 100644 --- a/base/runtime/core_builtin.odin +++ b/base/runtime/core_builtin.odin @@ -119,14 +119,14 @@ copy :: proc{copy_slice, copy_from_string, copy_from_string16} -// `unordered_remove` removed the element at the specified `index`. It does so by replacing the current end value +// `unordered_remove_dynamic_array` removed the element at the specified `index`. It does so by replacing the current end value // with the old value, and reducing the length of the dynamic array by 1. // // Note: This is an O(1) operation. // Note: If you want the elements to remain in their order, use `ordered_remove`. // Note: If the index is out of bounds, this procedure will panic. @builtin -unordered_remove :: proc(array: ^$D/[dynamic]$T, #any_int index: int, loc := #caller_location) #no_bounds_check { +unordered_remove_dynamic_array :: proc(array: ^$D/[dynamic]$T, #any_int index: int, loc := #caller_location) #no_bounds_check { bounds_check_error_loc(loc, index, len(array)) n := len(array)-1 if index != n { @@ -134,13 +134,13 @@ unordered_remove :: proc(array: ^$D/[dynamic]$T, #any_int index: int, loc := #ca } (^Raw_Dynamic_Array)(array).len -= 1 } -// `ordered_remove` removed the element at the specified `index` whilst keeping the order of the other elements. +// `ordered_remove_dynamic_array` removed the element at the specified `index` whilst keeping the order of the other elements. // // Note: This is an O(N) operation. // Note: If the elements do not have to remain in their order, prefer `unordered_remove`. // Note: If the index is out of bounds, this procedure will panic. @builtin -ordered_remove :: proc(array: ^$D/[dynamic]$T, #any_int index: int, loc := #caller_location) #no_bounds_check { +ordered_remove_dynamic_array :: proc(array: ^$D/[dynamic]$T, #any_int index: int, loc := #caller_location) #no_bounds_check { bounds_check_error_loc(loc, index, len(array)) if index+1 < len(array) { copy(array[index:], array[index+1:]) @@ -148,12 +148,12 @@ ordered_remove :: proc(array: ^$D/[dynamic]$T, #any_int index: int, loc := #call (^Raw_Dynamic_Array)(array).len -= 1 } -// `remove_range` removes a range of elements specified by the range `lo` and `hi`, whilst keeping the order of the other elements. +// `remove_range_dynamic_array` removes a range of elements specified by the range `lo` and `hi`, whilst keeping the order of the other elements. // // Note: This is an O(N) operation. // Note: If the range is out of bounds, this procedure will panic. @builtin -remove_range :: proc(array: ^$D/[dynamic]$T, #any_int lo, hi: int, loc := #caller_location) #no_bounds_check { +remove_range_dynamic_array :: proc(array: ^$D/[dynamic]$T, #any_int lo, hi: int, loc := #caller_location) #no_bounds_check { slice_expr_error_lo_hi_loc(loc, lo, hi, len(array)) n := max(hi-lo, 0) if n > 0 { @@ -164,29 +164,117 @@ remove_range :: proc(array: ^$D/[dynamic]$T, #any_int lo, hi: int, loc := #calle } } +// `unordered_remove_fixed_capacity_dynamic_array` removed the element at the specified `index`. It does so by replacing the current end value +// with the old value, and reducing the length of the dynamic array by 1. +// +// Note: This is an O(1) operation. +// Note: If you want the elements to remain in their order, use `ordered_remove`. +// Note: If the index is out of bounds, this procedure will panic. +@builtin +unordered_remove_fixed_capacity_dynamic_array :: proc(array: ^$D/[dynamic; $N]$E, #any_int index: int, loc := #caller_location) #no_bounds_check { + bounds_check_error_loc(loc, index, len(array)) + n := len(array)-1 + if index != n { + array[index] = array[n] + } + (^Raw_Fixed_Capacity_Dynamic_Array(N, E))(array).len -= 1 +} +// `ordered_remove_fixed_capacity_dynamic_array` removed the element at the specified `index` whilst keeping the order of the other elements. +// +// Note: This is an O(N) operation. +// Note: If the elements do not have to remain in their order, prefer `unordered_remove`. +// Note: If the index is out of bounds, this procedure will panic. +@builtin +ordered_remove_fixed_capacity_dynamic_array :: proc(array: ^$D/[dynamic; $N]$E, #any_int index: int, loc := #caller_location) #no_bounds_check { + bounds_check_error_loc(loc, index, len(array)) + if index+1 < len(array) { + copy(array[index:], array[index+1:]) + } + (^Raw_Fixed_Capacity_Dynamic_Array(N, E))(array).len -= 1 +} -// `pop` will remove and return the end value of dynamic array `array` and reduces the length of `array` by 1. +// `remove_range_fixed_capacity_dynamic_array` removes a range of elements specified by the range `lo` and `hi`, whilst keeping the order of the other elements. +// +// Note: This is an O(N) operation. +// Note: If the range is out of bounds, this procedure will panic. +@builtin +remove_range_fixed_capacity_dynamic_array :: proc(array: ^$D/[dynamic; $N]$E, #any_int lo, hi: int, loc := #caller_location) #no_bounds_check { + slice_expr_error_lo_hi_loc(loc, lo, hi, len(array)) + n := max(hi-lo, 0) + if n > 0 { + if hi != len(array) { + copy(array[lo:], array[hi:]) + } + (^Raw_Fixed_Capacity_Dynamic_Array(N, E))(array).len -= n + } +} + +@builtin +unordered_remove :: proc{ + unordered_remove_dynamic_array, + unordered_remove_fixed_capacity_dynamic_array, +} + + +@builtin +ordered_remove :: proc{ + ordered_remove_dynamic_array, + ordered_remove_fixed_capacity_dynamic_array, +} + +@builtin +remove_range :: proc{ + remove_range_dynamic_array, + remove_range_fixed_capacity_dynamic_array, +} + + + +// `pop_dynamic_array` will remove and return the end value of dynamic array `array` and reduces the length of `array` by 1. // // Note: If the dynamic array has no elements (`len(array) == 0`), this procedure will panic. @builtin -pop :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check { +pop_dynamic_array :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check { assert(len(array) > 0, loc=loc) - _pop_type_erased(&res, (^Raw_Dynamic_Array)(array), size_of(E)) + _pop_dynamic_array_type_erased(&res, (^Raw_Dynamic_Array)(array), size_of(E)) return res } -_pop_type_erased :: proc(res: rawptr, array: ^Raw_Dynamic_Array, elem_size: int, loc := #caller_location) { +_pop_dynamic_array_type_erased :: proc(res: rawptr, array: ^Raw_Dynamic_Array, elem_size: int) { end := rawptr(uintptr(array.data) + uintptr(elem_size*(array.len-1))) intrinsics.mem_copy_non_overlapping(res, end, elem_size) array.len -= 1 } +// `pop_fixed_capacity_dynamic_array` will remove and return the end value of fixed capacity dynamic array `array` and reduces the length of `array` by 1. +// +// Note: If the fixed capacity dynamic array has no elements (`len(array) == 0`), this procedure will panic. +@builtin +pop_fixed_capacity_dynamic_array :: proc(array: ^$T/[dynamic; $N]$E, loc := #caller_location) -> (res: E) #no_bounds_check { + assert(len(array) > 0, loc=loc) -// `pop_safe` trys to remove and return the end value of dynamic array `array` and reduces the length of `array` by 1. + elem_size :: size_of(E) + end := rawptr(uintptr(array) + uintptr(elem_size*(len(array)-1))) + intrinsics.mem_copy_non_overlapping(&res, end, elem_size) + (^Raw_Fixed_Capacity_Dynamic_Array(N, E))(array).len -= 1 + return res +} + + +// `pop` will remove and return the end value of dynamic array `array` and reduces the length of `array` by 1. +// +// Note: If the dynamic array has no elements (`len(array) == 0`), this procedure will panic. +@builtin +pop :: proc{ + pop_dynamic_array, + pop_fixed_capacity_dynamic_array, +} + +// `pop_safe_dynamic_array` trys to remove and return the end value of dynamic array `array` and reduces the length of `array` by 1. // If the operation is not possible, it will return false. @builtin -pop_safe :: proc "contextless" (array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check { +pop_safe_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check { if len(array) == 0 { return } @@ -195,11 +283,32 @@ pop_safe :: proc "contextless" (array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #n return } -// `pop_front` will remove and return the first value of dynamic array `array` and reduces the length of `array` by 1. +// `pop_safe_fixed_capacity_dynamic_array` trys to remove and return the end value of dynamic array `array` and reduces the length of `array` by 1. +// If the operation is not possible, it will return false. +@builtin +pop_safe_fixed_capacity_dynamic_array :: proc "contextless" (array: ^$T/[dynamic; $N]$E) -> (res: E, ok: bool) #no_bounds_check { + if len(array) == 0 { + return + } + res, ok = array[len(array)-1], true + (^Raw_Fixed_Capacity_Dynamic_Array(N, E))(array).len -= 1 + return +} + +// `pop_safe` trys to remove and return the end value of dynamic array `array` and reduces the length of `array` by 1. +// If the operation is not possible, it will return false. +@builtin +pop_safe :: proc{ + pop_safe_dynamic_array, + pop_safe_fixed_capacity_dynamic_array, +} + + +// `pop_front_dynamic_array` will remove and return the first value of dynamic array `array` and reduces the length of `array` by 1. // // Note: If the dynamic array as no elements (`len(array) == 0`), this procedure will panic. @builtin -pop_front :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check { +pop_front_dynamic_array :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check { assert(len(array) > 0, loc=loc) res = array[0] if len(array) > 1 { @@ -209,10 +318,35 @@ pop_front :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) # return res } -// `pop_front_safe` trys to return and remove the first value of dynamic array `array` and reduces the length of `array` by 1. +// `pop_front_fixed_capacity_dynamic_array` will remove and return the first value of fixed capacity dynamic array `array` and reduces the length of `array` by 1. +// +// Note: If the fixed capacity dynamic array as no elements (`len(array) == 0`), this procedure will panic. +@builtin +pop_front_fixed_capacity_dynamic_array :: proc(array: ^$T/[dynamic; $N]$E, loc := #caller_location) -> (res: E) #no_bounds_check { + assert(len(array) > 0, loc=loc) + res = array[0] + if len(array) > 1 { + copy(array[0:], array[1:]) + } + (^Raw_Fixed_Capacity_Dynamic_Array(N, E))(array).len -= 1 + return res +} + + +// `pop_front` will remove and return the first value of dynamic array `array` and reduces the length of `array` by 1. +// +// Note: If the dynamic array as no elements (`len(array) == 0`), this procedure will panic. +@builtin +pop_front :: proc{ + pop_front_dynamic_array, + pop_front_fixed_capacity_dynamic_array, +} + + +// `pop_front_safe_dynamic_array` trys to return and remove the first value of dynamic array `array` and reduces the length of `array` by 1. // If the operation is not possible, it will return false. @builtin -pop_front_safe :: proc "contextless" (array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check { +pop_front_safe_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check { if len(array) == 0 { return } @@ -224,12 +358,37 @@ pop_front_safe :: proc "contextless" (array: ^$T/[dynamic]$E) -> (res: E, ok: bo return } +// `pop_front_safe_fixed_capacity_dynamic_array` trys to return and remove the first value of dynamic array `array` and reduces the length of `array` by 1. +// If the operation is not possible, it will return false. +@builtin +pop_front_safe_fixed_capacity_dynamic_array :: proc "contextless" (array: ^$T/[dynamic; $N]$E) -> (res: E, ok: bool) #no_bounds_check { + if len(array) == 0 { + return + } + res, ok = array[0], true + if len(array) > 1 { + copy(array[0:], array[1:]) + } + (^Raw_Fixed_Capacity_Dynamic_Array(N, E))(array).len -= 1 + return +} + +// `pop_front_safe` trys to return and remove the first value of dynamic array `array` and reduces the length of `array` by 1. +// If the operation is not possible, it will return false. +@builtin +pop_front_safe :: proc { + pop_front_safe_dynamic_array, + pop_front_safe_fixed_capacity_dynamic_array, +} + + // `clear` will set the length of a passed dynamic array or map to `0` @builtin clear :: proc{ clear_dynamic_array, clear_map, + clear_fixed_capacity_dynamic_array, clear_soa_dynamic_array, } @@ -254,6 +413,7 @@ non_zero_reserve :: proc{ @builtin resize :: proc{ resize_dynamic_array, + resize_fixed_capacity_dynamic_array, resize_soa, } @@ -261,13 +421,17 @@ resize :: proc{ @builtin non_zero_resize :: proc{ non_zero_resize_dynamic_array, + non_zero_resize_fixed_capacity_dynamic_array, non_zero_resize_soa, } // Shrinks the capacity of a dynamic array or map down to the current length, or the given capacity. @builtin -shrink :: proc{shrink_dynamic_array, shrink_map} +shrink :: proc{ + shrink_dynamic_array, + shrink_map, +} // `free` will try to free the passed pointer, with the given `allocator` if the allocator supports this operation. @builtin @@ -357,7 +521,7 @@ new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, @(builtin, require_results) new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) #optional_allocator_error { - t = (^T)(raw_data(mem_alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return)) + t = (^T)(raw_data(mem_alloc_non_zeroed(size_of(T), align_of(T), allocator, loc) or_return)) if t != nil { t^ = data } @@ -430,7 +594,6 @@ _make_dynamic_array_len_cap :: proc(array: ^Raw_Dynamic_Array, size_of_elem, ali array.data = raw_data(data) array.len = 0 if use_zero else len array.cap = 0 if use_zero else cap - array.allocator = allocator return } @@ -667,6 +830,15 @@ non_zero_append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, l return _append_elem_string(array, arg, false, loc) } +// `non_zero_append_elem_fixed_capacity_string` appends a string to the end of a dynamic array of bytes, without zeroing any reserved memory +// +// Note: Prefer using the procedure group `non_zero_append`. +@builtin +non_zero_append_elem_fixed_capacity_string :: proc "contextless" (array: ^$T/[dynamic; $N]$E/u8, arg: $A/string) -> (n: int) { + return append_fixed_capacity_elem(array, transmute([]byte)arg) +} + + // The append_string built-in procedure appends multiple strings to the end of a [dynamic]u8 like type // @@ -684,6 +856,57 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_ return } + +// `append_fixed_capacity_elem` appends an element to the end of a fixed capacity dynamic array. Returns 0 on failure +@builtin +append_fixed_capacity_elem :: proc "contextless" (array: ^$T/[dynamic; $N]$E, #no_broadcast arg: E) -> (n: int) { + Raw :: Raw_Fixed_Capacity_Dynamic_Array(N, E) + + if (^Raw)(array).len >= N { + return 0 + } + + when size_of(E) != 0 { + #no_bounds_check (^Raw)(array).data[(^Raw)(array).len] = arg + } + (^Raw)(array).len += 1 + return 1 +} + + +// `append_fixed_capacity_elem` appends an element to the end of a fixed capacity dynamic array. Returns 0 on failure +@builtin +append_fixed_capacity_elems :: proc "contextless" (array: ^$T/[dynamic; $N]$E, #no_broadcast args: ..E) -> (n: int) { + Raw :: Raw_Fixed_Capacity_Dynamic_Array(N, E) + raw := (^Raw)(array) + + n = min(N - len(array), len(args)) + + #no_bounds_check when size_of(E) != 0 { + intrinsics.mem_copy(&raw.data[raw.len], raw_data(args), n*size_of(E)) + } + + raw.len += n + return n +} + +// The append_fixed_capacity_string built-in procedure appends multiple strings to the end of a [dynamic]u8 like type +// +// Note: Prefer using the procedure group `append`. +@builtin +append_fixed_capacity_string :: proc "contextless" (array: ^$T/[dynamic; $N]$E/u8, args: ..string) -> (n: int) { + n_arg: int + for arg in args { + n_arg = append_fixed_capacity_elems(array, ..transmute([]E)(arg)) + n += n_arg + if n_arg < len(arg) { + return + } + } + return +} + + // The append built-in procedure appends elements to the end of a dynamic array @builtin append :: proc{ @@ -691,6 +914,10 @@ append :: proc{ append_elems, append_elem_string, + append_fixed_capacity_elem, + append_fixed_capacity_elems, + append_fixed_capacity_string, + append_soa_elem, append_soa_elems, } @@ -701,6 +928,10 @@ non_zero_append :: proc{ non_zero_append_elems, non_zero_append_elem_string, + append_fixed_capacity_elem, + append_fixed_capacity_elems, + non_zero_append_elem_fixed_capacity_string, + non_zero_append_soa_elem, non_zero_append_soa_elems, } @@ -709,7 +940,7 @@ non_zero_append :: proc{ // `append_nothing` appends an empty value to a dynamic array. It returns `1, nil` if successful, and `0, err` when it was not possible, // whatever `err` happens to be. @builtin -append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { +append_nothing_dynamic_array :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { if array == nil { return 0, nil } @@ -718,6 +949,27 @@ append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (n: i return len(array)-prev_len, nil } +// `append_nothing` appends an empty value to a dynamic array. It returns `1, nil` if successful, and `0, err` when it was not possible, +// whatever `err` happens to be. +@builtin +append_nothing_fixed_capacity_dynamic_array :: proc "contextless" (array: ^$T/[dynamic; $N]$E) -> (n: int, ok: bool) { + if array == nil { + return 0, true + } + prev_len := len(array) + resize_fixed_capacity_dynamic_array(array, len(array)+1) or_return + return len(array)-prev_len, true +} + + +// `append_nothing` appends an empty value to a dynamic array. It returns `1, nil` if successful, and `0, err` when it was not possible, +// whatever `err` happens to be. +@builtin +append_nothing :: proc{ + append_nothing_dynamic_array, + append_nothing_fixed_capacity_dynamic_array, +} + // `inject_at_elem` injects an element in a dynamic array at a specified index and moves the previous elements after that index "across" @builtin @@ -793,12 +1045,92 @@ inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, #any_int index: int, ar return } + +// `inject_at_elem_fixed_capacity_dynamic_array` injects an element in a dynamic array at a specified index and moves the previous elements after that index "across" +@builtin +inject_at_elem_fixed_capacity_dynamic_array :: proc(array: ^$T/[dynamic; $N]$E, #any_int index: int, #no_broadcast arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check { + when !ODIN_NO_BOUNDS_CHECK { + ensure(index >= 0, "Index must be positive.", loc) + } + if array == nil { + return false + } + n := max(len(array), index) + m :: 1 + new_size := n + m + + resize(array, new_size) or_return + when size_of(E) != 0 { + copy(array[index + m:], array[index:]) + array[index] = arg + } + return true +} + +// `inject_at_elems_fixed_capacity_dynamic_array` injects multiple elements in a dynamic array at a specified index and moves the previous elements after that index "across" +@builtin +inject_at_elems_fixed_capacity_dynamic_array :: proc(array: ^$T/[dynamic; $N]$E, #any_int index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check { + when !ODIN_NO_BOUNDS_CHECK { + ensure(index >= 0, "Index must be positive.", loc) + } + if array == nil { + return false + } + if len(args) == 0 { + return true + } + + n := max(len(array), index) + m := len(args) + new_size := n + m + + resize(array, new_size) or_return + when size_of(E) != 0 { + copy(array[index + m:], array[index:]) + copy(array[index:], args) + } + return true +} + +// `inject_at_elem_string_fixed_capacity_dynamic_array` injects a string into a dynamic array at a specified index and moves the previous elements after that index "across" +@builtin +inject_at_elem_string_fixed_capacity_dynamic_array :: proc(array: ^$T/[dynamic; $N]$E/u8, #any_int index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check { + when !ODIN_NO_BOUNDS_CHECK { + ensure(index >= 0, "Index must be positive.", loc) + } + if array == nil { + return false + } + if len(arg) == 0 { + return true + } + + n := max(len(array), index) + m := len(arg) + new_size := n + m + + resize(array, new_size) or_return + copy(array[index+m:], array[index:]) + copy(array[index:], arg) + return true +} + + // `inject_at` injects something into a dynamic array at a specified index and moves the previous elements after that index "across" -@builtin inject_at :: proc{inject_at_elem, inject_at_elems, inject_at_elem_string} +@builtin +inject_at :: proc{ + inject_at_elem, + inject_at_elems, + inject_at_elem_string, + + inject_at_elem_fixed_capacity_dynamic_array, + inject_at_elems_fixed_capacity_dynamic_array, + inject_at_elem_string_fixed_capacity_dynamic_array, +} -// `assign_at_elem` assigns a value at a given index. If the requested index is smaller than the current +// `assign_at_elem` assigns a value at a given index. If the requested index is past the end of the current // size of the dynamic array, it will attempt to `resize` the a new length of `index+1` and then assign as `index`. @builtin assign_at_elem :: proc(array: ^$T/[dynamic]$E, #any_int index: int, arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { @@ -814,7 +1146,7 @@ assign_at_elem :: proc(array: ^$T/[dynamic]$E, #any_int index: int, arg: E, loc } -// `assign_at_elems` assigns a values at a given index. If the requested index is smaller than the current +// `assign_at_elems` assigns a values at a given index. If the requested index is past the end of the current // size of the dynamic array, it will attempt to `resize` the a new length of `index+len(args)` and then assign as `index`. @builtin assign_at_elems :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { @@ -832,7 +1164,7 @@ assign_at_elems :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadca return } -// `assign_at_elem_string` assigns a string at a given index. If the requested index is smaller than the current +// `assign_at_elem_string` assigns a string at a given index. If the requested index is past the end of the current // size of the dynamic array, it will attempt to `resize` the a new length of `index+len(arg)` and then assign as `index`. @builtin assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, #any_int index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { @@ -850,15 +1182,72 @@ assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, #any_int index: int, ar return } -// `assign_at` assigns a value at a given index. If the requested index is smaller than the current + +// `assign_at_elem_fixed_capacity_dynamic_array` assigns a value at a given index. If the requested index is past the end of the current +// size of the dynamic array, it will attempt to `resize` the a new length of `index+1` and then assign as `index`. +@builtin +assign_at_elem_fixed_capacity_dynamic_array :: proc "contextless" (array: ^$T/[dynamic; $N]$E, #any_int index: int, arg: E) -> (ok: bool) #no_bounds_check { + if index < len(array) { + array[index] = arg + ok = true + } else { + resize(array, index+1, loc) or_return + array[index] = arg + ok = true + } + return +} + + +// `assign_at_elems_fixed_capacity_dynamic_array` assigns a values at a given index. If the requested index is past the end of the current +// size of the dynamic array, it will attempt to `resize` the a new length of `index+len(args)` and then assign as `index`. +@builtin +assign_at_elems_fixed_capacity_dynamic_array :: proc "contextless" (array: ^$T/[dynamic; $N]$E, #any_int index: int, #no_broadcast args: ..E) -> (ok: bool) #no_bounds_check { + new_size := index + len(args) + if len(args) == 0 { + ok = true + } else if new_size < len(array) { + copy(array[index:], args) + ok = true + } else { + resize(array, new_size, loc) or_return + copy(array[index:], args) + ok = true + } + return +} + +// `assign_at_elem_string_fixed_capacity_dynamic_array` assigns a string at a given index. If the requested index is past the end of the current +// size of the dynamic array, it will attempt to `resize` the a new length of `index+len(arg)` and then assign as `index`. +@builtin +assign_at_elem_string_fixed_capacity_dynamic_array :: proc "contextless" (array: ^$T/[dynamic; $N]$E/u8, #any_int index: int, arg: string) -> (ok: bool) #no_bounds_check { + new_size := index + len(arg) + if len(arg) == 0 { + ok = true + } else if new_size < len(array) { + copy(array[index:], arg) + ok = true + } else { + resize(array, new_size, loc) or_return + copy(array[index:], arg) + ok = true + } + return +} + + +// `assign_at` assigns a value at a given index. If the requested index is past the end of the current // size of the dynamic array, it will attempt to `resize` the a new length of `index+size_needed` and then assign as `index`. @builtin assign_at :: proc{ assign_at_elem, assign_at_elems, assign_at_elem_string, -} + assign_at_elem_fixed_capacity_dynamic_array, + assign_at_elems_fixed_capacity_dynamic_array, + assign_at_elem_string_fixed_capacity_dynamic_array, +} @@ -872,6 +1261,16 @@ clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) { } } +// `clear_fixed_capacity_dynamic_array` will set the length of a passed dynamic array to `0` +// +// Note: Prefer the procedure group `clear`. +@builtin +clear_fixed_capacity_dynamic_array :: proc "contextless" (array: ^$T/[dynamic; $N]$E) { + if array != nil { + (^Raw_Fixed_Capacity_Dynamic_Array(N, E))(array).len = 0 + } +} + // `reserve_dynamic_array` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`). // // When a memory resize allocation is required, the memory will be asked to be zeroed (i.e. it calls `mem_resize`). @@ -888,8 +1287,8 @@ _reserve_dynamic_array :: #force_no_inline proc(a: ^Raw_Dynamic_Array, size_of_e if a.allocator.procedure == nil { a.allocator = context.allocator + assert(a.allocator.procedure != nil) } - assert(a.allocator.procedure != nil) old_size := a.cap * size_of_elem new_size := capacity * size_of_elem @@ -948,8 +1347,8 @@ _resize_dynamic_array :: #force_no_inline proc(a: ^Raw_Dynamic_Array, size_of_el if a.allocator.procedure == nil { a.allocator = context.allocator + assert(a.allocator.procedure != nil) } - assert(a.allocator.procedure != nil) old_size := a.cap * size_of_elem new_size := length * size_of_elem @@ -991,6 +1390,43 @@ non_zero_resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int length: i return _resize_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), length, false, loc=loc) } + + +// `resize_fixed_capacity_dynamic_array` will try to resize memory of a passed fixed capacity dynamic array or map to the requested element count (setting the `len`, and possibly `cap`). +// +// Note: Prefer the procedure group `resize` +@builtin +resize_fixed_capacity_dynamic_array :: proc "contextless" (array: ^$T/[dynamic; $N]$E, #any_int length: int) -> bool { + if array == nil { + return false + } + if len(array) < length { + size_of_elem :: size_of(E) + + num_reused := min(N, length) - len(array) + intrinsics.mem_zero(([^]byte)(array)[len(array)*size_of_elem:], num_reused*size_of_elem) + } + + raw := (^Raw_Fixed_Capacity_Dynamic_Array(N, E))(array) + new_length := clamp(length, 0, N) + raw.len = new_length + return true +} + +// `non_zero_resize_fixed_capacity_dynamic_array` will try to resize memory of a passed fixed capacity dynamic array or map to the requested element count (setting the `len`, and possibly `cap`). +// +// Note: Prefer the procedure group `resize` +@builtin +non_zero_resize_fixed_capacity_dynamic_array :: proc "contextless" (array: ^$T/[dynamic; $N]$E, #any_int length: int) -> bool { + if array == nil { + return false + } + raw := (^Raw_Fixed_Capacity_Dynamic_Array(N, E))(array) + new_length := clamp(length, 0, N) + raw.len = new_length + return true +} + // Shrinks the capacity of a dynamic array down to the current length, or the given capacity. // // If `new_cap` is negative, then `len(array)` is used. @@ -1000,6 +1436,7 @@ non_zero_resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int length: i // If `len(array) < new_cap`, then `len(array)` will be left unchanged. // // Note: Prefer the procedure group `shrink` +@builtin shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int new_cap := -1, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) { return _shrink_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), new_cap, loc) } @@ -1017,8 +1454,8 @@ _shrink_dynamic_array :: proc(a: ^Raw_Dynamic_Array, size_of_elem, align_of_elem if a.allocator.procedure == nil { a.allocator = context.allocator + assert(a.allocator.procedure != nil) } - assert(a.allocator.procedure != nil) old_size := a.cap * size_of_elem new_size := new_cap * size_of_elem @@ -1088,7 +1525,7 @@ card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int { -// Evaluates the condition and panics the program iff the condition is false. +// Evaluates the condition and panics the program if and only if (⟺) the condition is false. // This uses the `context.assertion_failure_procedure` to assert. // // This routine will be ignored when `ODIN_DISABLE_ASSERT` is true. @@ -1112,7 +1549,7 @@ assert :: proc(condition: bool, message := #caller_expression(condition), loc := } } -// Evaluates the condition and panics the program iff the condition is false. +// Evaluates the condition and panics the program if and only if (⟺) the condition is false. // This uses the `context.assertion_failure_procedure` to assert. // This routine ignores `ODIN_DISABLE_ASSERT`, and will always execute. @builtin @@ -1152,7 +1589,7 @@ unimplemented :: proc(message := "", loc := #caller_location) -> ! { p("not yet implemented", message, loc) } -// Evaluates the condition and panics the program iff the condition is false. +// Evaluates the condition and panics the program if and only if (⟺) the condition is false. // This uses the `default_assertion_contextless_failure_proc` to assert. // // This routine will be ignored when `ODIN_DISABLE_ASSERT` is true. @@ -1172,7 +1609,7 @@ assert_contextless :: proc "contextless" (condition: bool, message := #caller_ex } } -// Evaluates the condition and panics the program iff the condition is false. +// Evaluates the condition and panics the program if and only if (⟺) the condition is false. // This uses the `default_assertion_contextless_failure_proc` to assert. @builtin ensure_contextless :: proc "contextless" (condition: bool, message := #caller_expression(condition), loc := #caller_location) { diff --git a/base/runtime/core_builtin_soa.odin b/base/runtime/core_builtin_soa.odin index 0ccc8fd9b..e9a284a04 100644 --- a/base/runtime/core_builtin_soa.odin +++ b/base/runtime/core_builtin_soa.odin @@ -105,8 +105,8 @@ make_soa_aligned :: proc($T: typeid/#soa[]$E, #any_int length, alignment: int, a allocator := allocator if allocator.procedure == nil { allocator = context.allocator + assert(allocator.procedure != nil) } - assert(allocator.procedure != nil) new_bytes: []byte new_bytes, err = allocator.procedure( @@ -240,8 +240,8 @@ _reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, zero_memory: boo if array.allocator.procedure == nil { array.allocator = context.allocator + assert(array.allocator.procedure != nil) } - assert(array.allocator.procedure != nil) footer := raw_soa_footer(array) if size_of(E) == 0 { @@ -615,7 +615,7 @@ inject_at_elems_soa :: proc(array: ^$T/#soa[dynamic]$E, #any_int index: int, #no // `inject_at_soa` injects something into a dynamic SOA array at a specified index and moves the previous elements after that index "across" @builtin inject_at_soa :: proc{inject_at_elem_soa, inject_at_elems_soa} - +@builtin delete_soa_slice :: proc(array: $T/#soa[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { field_count :: len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E) when field_count != 0 { @@ -626,6 +626,7 @@ delete_soa_slice :: proc(array: $T/#soa[]$E, allocator := context.allocator, loc return nil } +@builtin delete_soa_dynamic_array :: proc(array: $T/#soa[dynamic]$E, loc := #caller_location) -> Allocator_Error { field_count :: len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E) when field_count != 0 { @@ -644,7 +645,7 @@ delete_soa :: proc{ delete_soa_dynamic_array, } - +@builtin clear_soa_dynamic_array :: proc(array: ^$T/#soa[dynamic]$E) { field_count :: len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E) when field_count != 0 { diff --git a/base/runtime/default_temp_allocator_arena.odin b/base/runtime/default_temp_allocator_arena.odin index 8f4821b4a..eafaf9fbe 100644 --- a/base/runtime/default_temp_allocator_arena.odin +++ b/base/runtime/default_temp_allocator_arena.odin @@ -235,6 +235,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, if start < old_end && old_end == block.used && new_end <= block.capacity { // grow data in-place, adjusting next allocation block.used = uint(new_end) + arena.total_used = uint(new_end) data = block.base[start:new_end] // sanitizer.address_unpoison(data) return diff --git a/base/runtime/dynamic_array_internal.odin b/base/runtime/dynamic_array_internal.odin index 267ee0785..514e0e782 100644 --- a/base/runtime/dynamic_array_internal.odin +++ b/base/runtime/dynamic_array_internal.odin @@ -18,8 +18,8 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: // assuming that appending/reserving will set the allocator, if it is not already set. if array.allocator.procedure == nil { array.allocator = context.allocator + assert(array.allocator.procedure != nil) } - assert(array.allocator.procedure != nil) if cap <= array.cap { return true @@ -52,8 +52,8 @@ __dynamic_array_shrink :: proc(array_: rawptr, elem_size, elem_align: int, new_c // assuming that appending/reserving will set the allocator, if it is not already set. if array.allocator.procedure == nil { array.allocator = context.allocator + assert(array.allocator.procedure != nil) } - assert(array.allocator.procedure != nil) if new_cap > array.cap { return diff --git a/base/runtime/dynamic_map_internal.odin b/base/runtime/dynamic_map_internal.odin index 298b586f5..73a152845 100644 --- a/base/runtime/dynamic_map_internal.odin +++ b/base/runtime/dynamic_map_internal.odin @@ -283,7 +283,9 @@ map_desired_position :: #force_inline proc "contextless" (m: Raw_Map, hash: Map_ map_probe_distance :: #force_inline proc "contextless" (m: Raw_Map, hash: Map_Hash, slot: uintptr) -> uintptr { // We do not use map_cap since we know the capacity will not be zero here. capacity := uintptr(1) << map_log2_cap(m) - return (slot + capacity - map_desired_position(m, hash)) & (capacity - 1) + + // return (slot + capacity - map_desired_position(m, hash)) & (capacity - 1) + return (slot - uintptr(hash)) & (capacity - 1) // NOTE(bill): this is equivalent to the above, but less operations } // When working with the type-erased structure at runtime we need information diff --git a/base/runtime/error_checks.odin b/base/runtime/error_checks.odin index 32a895c3f..46a8f9b1d 100644 --- a/base/runtime/error_checks.odin +++ b/base/runtime/error_checks.odin @@ -12,7 +12,7 @@ bounds_trap :: proc "contextless" () -> ! { } @(no_instrumentation) -type_assertion_trap :: proc "contextless" () -> ! { +type_assertion_trap_contextless :: proc "contextless" () -> ! { when ODIN_OS == .Windows { windows_trap_type_assertion() } else when ODIN_OS == .Orca { @@ -137,20 +137,22 @@ matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32 when ODIN_NO_RTTI { - type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32) { + type_assertion_check_with_context :: proc "odin" (ok: bool, file: string, line, column: i32) { if ok { return } @(cold, no_instrumentation) - handle_error :: proc "contextless" (file: string, line, column: i32) -> ! { - print_caller_location(Source_Code_Location{file, line, column, ""}) - print_string(" Invalid type assertion\n") - type_assertion_trap() + handle_error :: proc "odin" (file: string, line, column: i32) -> ! { + p := context.assertion_failure_proc + if p == nil { + p = default_assertion_failure_proc + } + p("type assertion", "Invalid type assertion", Source_Code_Location{file, line, column, ""}) } handle_error(file, line, column) } - type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32) { + type_assertion_check_contextless :: proc "contextless" (ok: bool, file: string, line, column: i32) { if ok { return } @@ -158,12 +160,71 @@ when ODIN_NO_RTTI { handle_error :: proc "contextless" (file: string, line, column: i32) -> ! { print_caller_location(Source_Code_Location{file, line, column, ""}) print_string(" Invalid type assertion\n") - type_assertion_trap() + type_assertion_trap_contextless() + } + handle_error(file, line, column) + } + + type_assertion_check2_with_context :: proc "odin" (ok: bool, file: string, line, column: i32) { + if ok { + return + } + @(cold, no_instrumentation) + handle_error :: proc "odin" (file: string, line, column: i32) -> ! { + p := context.assertion_failure_proc + if p == nil { + p = default_assertion_failure_proc + } + p("type assertion", "Invalid type assertion", Source_Code_Location{file, line, column, ""}) + } + + handle_error(file, line, column) + } + + type_assertion_check2_contextless :: proc "contextless" (ok: bool, file: string, line, column: i32) { + if ok { + return + } + @(cold, no_instrumentation) + handle_error :: proc "contextless" (file: string, line, column: i32) -> ! { + print_caller_location(Source_Code_Location{file, line, column, ""}) + print_string(" Invalid type assertion\n") + type_assertion_trap_contextless() } handle_error(file, line, column) } } else { - type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid) { + @(private="file") + TYPE_ASSERTION_BUFFER_SIZE :: 1024 + + type_assertion_check_with_context :: proc "odin" (ok: bool, file: string, line, column: i32, from, to: typeid) { + if ok { + return + } + @(cold, no_instrumentation) + handle_error :: proc "odin" (file: string, line, column: i32, from, to: typeid) -> ! { + do_msg :: proc "contextless" (i: ^int, buf: []byte, file: string, line, column: i32, from, to: typeid) -> bool { + write_string(i, buf, "Invalid type assertion from ") or_return + write_typeid(i, buf, from) or_return + write_string(i, buf, " to ") or_return + write_typeid(i, buf, to) or_return + return true + } + + buf: [TYPE_ASSERTION_BUFFER_SIZE]byte + i := 0 + _ = do_msg(&i, buf[:], file, line, column, from, to) + + p := context.assertion_failure_proc + if p == nil { + p = default_assertion_failure_proc + } + p("type assertion", string(buf[:i]), Source_Code_Location{file, line, column, ""}) + } + handle_error(file, line, column, from, to) + } + + type_assertion_check_contextless :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid) { if ok { return } @@ -175,47 +236,90 @@ when ODIN_NO_RTTI { print_string(" to ") print_typeid(to) print_byte('\n') - type_assertion_trap() + type_assertion_trap_contextless() } handle_error(file, line, column, from, to) } - type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid, from_data: rawptr) { + @(private="file") + type_assertion_variant_type :: proc "contextless" (id: typeid, data: rawptr) -> typeid { + if id == nil || data == nil { + return id + } + ti := type_info_base(type_info_of(id)) + #partial switch v in ti.variant { + case Type_Info_Any: + return (^any)(data).id + case Type_Info_Union: + if v.tag_type == nil { + if (^rawptr)(data)^ == nil { + return nil + } + return v.variants[0].id + + } + + tag_ptr := uintptr(data) + v.tag_offset + idx := 0 + switch v.tag_type.size { + case 1: idx = int( (^u8)(tag_ptr)^); if !v.no_nil { idx -= 1 } + case 2: idx = int( (^u16)(tag_ptr)^); if !v.no_nil { idx -= 1 } + case 4: idx = int( (^u32)(tag_ptr)^); if !v.no_nil { idx -= 1 } + case 8: idx = int( (^u64)(tag_ptr)^); if !v.no_nil { idx -= 1 } + case 16: idx = int((^u128)(tag_ptr)^); if !v.no_nil { idx -= 1 } + } + if idx < 0 { + return nil + } else if idx < len(v.variants) { + return v.variants[idx].id + } + } + return id + } + + type_assertion_check2_with_context :: proc "odin" (ok: bool, file: string, line, column: i32, from, to: typeid, from_data: rawptr) { if ok { return } - variant_type :: proc "contextless" (id: typeid, data: rawptr) -> typeid { - if id == nil || data == nil { - return id - } - ti := type_info_base(type_info_of(id)) - #partial switch v in ti.variant { - case Type_Info_Any: - return (^any)(data).id - case Type_Info_Union: - tag_ptr := uintptr(data) + v.tag_offset - idx := 0 - switch v.tag_type.size { - case 1: idx = int((^u8)(tag_ptr)^) - 1 - case 2: idx = int((^u16)(tag_ptr)^) - 1 - case 4: idx = int((^u32)(tag_ptr)^) - 1 - case 8: idx = int((^u64)(tag_ptr)^) - 1 - case 16: idx = int((^u128)(tag_ptr)^) - 1 - } - if idx < 0 { - return nil - } else if idx < len(v.variants) { - return v.variants[idx].id + @(cold, no_instrumentation) + handle_error :: proc "odin" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) -> ! { + do_msg :: proc "contextless" (i: ^int, buf: []byte, file: string, line, column: i32, from, to, actual: typeid) -> bool { + write_string(i, buf, "Invalid type assertion from ") or_return + write_typeid(i, buf, from) or_return + write_string(i, buf, " to ") or_return + write_typeid(i, buf, to) or_return + if actual != from { + write_string(i, buf, ", actual type: ") or_return + write_typeid(i, buf, actual) or_return } + return true } - return id + + actual := type_assertion_variant_type(from, from_data) + + buf: [TYPE_ASSERTION_BUFFER_SIZE]byte + i := 0 + _ = do_msg(&i, buf[:], file, line, column, from, to, actual) + + p := context.assertion_failure_proc + if p == nil { + p = default_assertion_failure_proc + } + p("type assertion", string(buf[:i]), Source_Code_Location{file, line, column, ""}) + } + handle_error(file, line, column, from, to, from_data) + } + + type_assertion_check2_contextless :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid, from_data: rawptr) { + if ok { + return } @(cold, no_instrumentation) handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) -> ! { - actual := variant_type(from, from_data) + actual := type_assertion_variant_type(from, from_data) print_caller_location(Source_Code_Location{file, line, column, ""}) print_string(" Invalid type assertion from ") @@ -227,7 +331,7 @@ when ODIN_NO_RTTI { print_typeid(actual) } print_byte('\n') - type_assertion_trap() + type_assertion_trap_contextless() } handle_error(file, line, column, from, to, from_data) } diff --git a/base/runtime/internal.odin b/base/runtime/internal.odin index 0e674aca8..12f0dceca 100644 --- a/base/runtime/internal.odin +++ b/base/runtime/internal.odin @@ -7,10 +7,11 @@ import "base:intrinsics" IS_WASM :: ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 @(private) -RUNTIME_LINKAGE :: "strong" when ( - ODIN_USE_SEPARATE_MODULES || - ODIN_BUILD_MODE == .Dynamic || - !ODIN_NO_CRT) else "internal" +RUNTIME_LINKAGE :: "strong" when ODIN_USE_SEPARATE_MODULES else + "internal" when ODIN_NO_ENTRY_POINT && (ODIN_BUILD_MODE == .Static || ODIN_BUILD_MODE == .Dynamic || ODIN_BUILD_MODE == .Object) else + "strong" when ODIN_BUILD_MODE == .Dynamic else + "strong" when !ODIN_NO_CRT else + "internal" RUNTIME_REQUIRE :: false // !ODIN_TILDE @(private) @@ -147,6 +148,7 @@ mem_alloc_non_zeroed :: #force_no_inline proc(size: int, alignment: int = DEFAUL return allocator.procedure(allocator.data, .Alloc_Non_Zeroed, size, alignment, nil, 0, loc) } +@builtin mem_free :: #force_no_inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { if ptr == nil || allocator.procedure == nil { return nil @@ -171,7 +173,7 @@ mem_free_bytes :: #force_no_inline proc(bytes: []byte, allocator := context.allo return err } - +@builtin mem_free_all :: #force_no_inline proc(allocator := context.allocator, loc := #caller_location) -> (err: Allocator_Error) { if allocator.procedure != nil { _, err = allocator.procedure(allocator.data, .Free_All, 0, 0, nil, 0, loc) @@ -340,7 +342,7 @@ memory_compare :: proc "contextless" (x, y: rawptr, n: int) -> int #no_bounds_ch case y == nil: return +1 } a, b := cast([^]byte)x, cast([^]byte)y - + n := uint(n) i := uint(0) m := uint(0) @@ -716,7 +718,7 @@ quaternion256_eq :: #force_inline proc "contextless" (a, b: quaternion256) -> bo quaternion256_ne :: #force_inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b) } -string_decode_rune :: proc "contextless" (s: string) -> (rune, int) { +string_decode_rune :: proc "contextless" (s: string) -> (rune, int) #no_bounds_check { // NOTE(bill): Duplicated here to remove dependency on package unicode/utf8 @(static, rodata) accept_sizes := [256]u8{ @@ -795,7 +797,7 @@ string_decode_rune :: proc "contextless" (s: string) -> (rune, int) { return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4 } -string_decode_last_rune :: proc "contextless" (s: string) -> (rune, int) { +string_decode_last_rune :: proc "contextless" (s: string) -> (rune, int) #no_bounds_check { RUNE_ERROR :: '\ufffd' RUNE_SELF :: 0x80 UTF_MAX :: 4 @@ -831,7 +833,7 @@ string_decode_last_rune :: proc "contextless" (s: string) -> (rune, int) { } -string16_decode_rune :: proc "contextless" (s: string16) -> (rune, int) { +string16_decode_rune :: proc "contextless" (s: string16) -> (rune, int) #no_bounds_check { REPLACEMENT_CHAR :: '\ufffd' _surr1 :: 0xd800 _surr2 :: 0xdc00 @@ -859,7 +861,7 @@ string16_decode_rune :: proc "contextless" (s: string16) -> (rune, int) { return r, w } -string16_decode_last_rune :: proc "contextless" (s: string16) -> (rune, int) { +string16_decode_last_rune :: proc "contextless" (s: string16) -> (rune, int) #no_bounds_check { REPLACEMENT_CHAR :: '\ufffd' _surr1 :: 0xd800 _surr2 :: 0xdc00 @@ -1408,4 +1410,3 @@ when .Address in ODIN_SANITIZER_FLAGS { __asan_unpoison_memory_region :: proc "system" (address: rawptr, size: uint) --- } } - diff --git a/base/runtime/os_specific_essence.odin b/base/runtime/os_specific_essence.odin new file mode 100644 index 000000000..9d4b0c968 --- /dev/null +++ b/base/runtime/os_specific_essence.odin @@ -0,0 +1,14 @@ +#+build essence +#+private +package runtime + +_HAS_RAND_BYTES :: false + +// TODO(bill): reimplement `os.write` +_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) { + return 0, -1 +} + +_exit :: proc "contextless" (code: int) -> ! { + trap() +} \ No newline at end of file diff --git a/base/runtime/print.odin b/base/runtime/print.odin index 90119c699..ad205d887 100644 --- a/base/runtime/print.odin +++ b/base/runtime/print.odin @@ -184,10 +184,11 @@ print_rune :: #force_no_inline proc "contextless" (r: rune) -> int #no_bounds_ch print_u64 :: #force_no_inline proc "contextless" (x: u64) #no_bounds_check { + b :: u64(10) + u := x + a: [129]byte i := len(a) - b := u64(10) - u := x for u >= b { i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b] u /= b @@ -199,11 +200,9 @@ print_u64 :: #force_no_inline proc "contextless" (x: u64) #no_bounds_check { print_i64 :: #force_no_inline proc "contextless" (x: i64) #no_bounds_check { - b :: i64(10) - - u := x - neg := u < 0 - u = abs(u) + b :: u64(10) + u := u64(abs(x)) + neg := x < 0 a: [129]byte i := len(a) @@ -281,11 +280,22 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) { print_byte('i' if info.signed else 'u') print_u64(u64(8*ti.size)) } + switch info.endianness { + case .Platform: // nothing + case .Little: print_string("le") + case .Big: print_string("be") + } + case Type_Info_Rune: print_string("rune") case Type_Info_Float: print_byte('f') print_u64(u64(8*ti.size)) + switch info.endianness { + case .Platform: // nothing + case .Little: print_string("le") + case .Big: print_string("be") + } case Type_Info_Complex: print_string("complex") print_u64(u64(8*ti.size)) @@ -382,6 +392,12 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) { print_string("[]") print_type(info.elem) + case Type_Info_Fixed_Capacity_Dynamic_Array: + print_string("[dynamic; ") + print_u64(u64(info.capacity)) + print_string("]") + print_type(info.elem) + case Type_Info_Map: print_string("map[") print_type(info.key) @@ -411,6 +427,7 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) { if .packed in info.flags { print_string("#packed ") } if .raw_union in info.flags { print_string("#raw_union ") } if .all_or_none in info.flags { print_string("#all_or_none ") } + if .simple in info.flags { print_string("#simple ") } if .align in info.flags { print_string("#align(") print_u64(u64(ti.align)) @@ -467,7 +484,7 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) { print_string("..") print_i64(info.upper) } - if info.underlying != nil { + if info.explicit_underlying { print_string("; ") print_type(info.underlying) } @@ -495,6 +512,9 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) { print_type(info.elem) case Type_Info_Matrix: + if info.layout == .Row_Major { + print_string("#row_major ") + } print_string("matrix[") print_u64(u64(info.row_count)) print_string(", ") @@ -503,3 +523,425 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) { print_type(info.elem) } } + + +@(require_results) +write_string :: proc "contextless" (i: ^int, dst: []byte, src: string) -> bool { + if i^ < len(dst) { + i^ += copy(dst[i^:], src) + return true + } + return false +} + + +@(require_results) +write_byte :: proc "contextless" (i: ^int, dst: []byte, src: byte) -> bool { + if i^ < len(dst) { + dst[i^] = src + i^ += 1 + return true + } + return false +} + + +@(require_results) +write_u64 :: proc "contextless" (j: ^int, dst: []byte, x: u64) -> bool { + if j^ < len(dst) { + b :: u64(10) + u := x + + a: [129]byte + i := len(a) + for u >= b { + i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b] + u /= b + } + i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b] + + return write_string(j, dst, string(a[i:])) + } + return false +} + +@(require_results) +write_i64 :: proc "contextless" (j: ^int, dst: []byte, x: i64) -> bool { + if j^ < len(dst) { + b :: u64(10) + u := u64(abs(x)) + neg := x < 0 + + a: [129]byte + i := len(a) + for u >= b { + i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b] + u /= b + } + i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b] + if neg { + i -= 1; a[i] = '-' + } + + return write_string(j, dst, string(a[i:])) + } + return false +} + + +@(require_results) +write_caller_location :: #force_no_inline proc "contextless" (i: ^int, buf: []byte, loc: Source_Code_Location) -> bool { + write_string(i, buf, loc.file_path) or_return + + when ODIN_ERROR_POS_STYLE == .Default { + write_byte(i, buf, '(') or_return + write_u64 (i, buf, u64(loc.line)) or_return + if loc.column != 0 { + write_byte(i, buf, ':') or_return + write_u64 (i, buf, u64(loc.column)) or_return + } + write_byte(i, buf, ')') or_return + return true + } else when ODIN_ERROR_POS_STYLE == .Unix { + write_byte(i, buf, ':') or_return + write_u64 (i, buf, u64(loc.line)) or_return + if loc.column != 0 { + write_byte(i, buf, ':') or_return + write_u64 (i, buf, u64(loc.column)) or_return + } + write_byte(i, buf, ':') or_return + return true + } else { + #panic("unhandled ODIN_ERROR_POS_STYLE") + } +} + +@(require_results) +write_typeid :: #force_no_inline proc "contextless" (i: ^int, buf: []byte, id: typeid) -> bool { + when ODIN_NO_RTTI { + if id == nil { + write_string(i, buf, "nil") or_return + } else { + write_string(i, buf, "") or_return + } + } else { + if id == nil { + write_string(i, buf, "nil") or_return + } else { + ti := type_info_of(id) + write_write_type(i, buf, ti) or_return + } + } + return true +} + + +@(require_results) +write_rune :: #force_no_inline proc "contextless" (i: ^int, buf: []byte, r: rune) -> (written: int, ok: bool) #no_bounds_check { + RUNE_SELF :: 0x80 + + if r < RUNE_SELF { + write_byte(i, buf,byte(r)) or_return + return 1, true + } + + b, n := encode_rune(r) + prev := i^ + write_string(i, buf, string(b[:n])) or_return + return i^ - prev, true +} + +@(require_results) +write_encoded_rune :: #force_no_inline proc "contextless" (i: ^int, buf: []byte, r: rune) -> bool { + write_byte(i, buf, '\'') or_return + + switch r { + case '\a': write_string(i, buf, "\\a") or_return + case '\b': write_string(i, buf, "\\b") or_return + case '\e': write_string(i, buf, "\\e") or_return + case '\f': write_string(i, buf, "\\f") or_return + case '\n': write_string(i, buf, "\\n") or_return + case '\r': write_string(i, buf, "\\r") or_return + case '\t': write_string(i, buf, "\\t") or_return + case '\v': write_string(i, buf, "\\v") or_return + case: + if r <= 0 { + write_string(i, buf, "\\x00") or_return + } else if r < 32 { + n0, n1 := u8(r) >> 4, u8(r) & 0xf + write_string(i, buf, "\\x") or_return + write_byte (i, buf, _INTEGER_DIGITS_VAR[n0]) or_return + write_byte (i, buf, _INTEGER_DIGITS_VAR[n1]) or_return + } else { + _ = write_rune(i, buf, r) or_return + } + } + + write_byte(i, buf, '\'') or_return + return true +} + +@(optimization_mode="favor_size") +write_write_type :: #force_no_inline proc "contextless" (i: ^int, buf: []byte, ti: ^Type_Info) -> bool { + if ti == nil { + write_string(i, buf, "nil") or_return + return true + } + + switch info in ti.variant { + case Type_Info_Named: + write_string(i, buf, info.name) or_return + case Type_Info_Integer: + switch ti.id { + case int: write_string(i, buf, "int") or_return + case uint: write_string(i, buf, "uint") or_return + case uintptr: write_string(i, buf, "uintptr") or_return + case: + write_byte(i, buf, 'i' if info.signed else 'u') or_return + write_u64 (i, buf, u64(8*ti.size)) or_return + } + switch info.endianness { + case .Platform: // nothing + case .Little: write_string(i, buf, "le") or_return + case .Big: write_string(i, buf, "be") or_return + } + + case Type_Info_Rune: + write_string(i, buf, "rune") or_return + case Type_Info_Float: + write_byte(i, buf, 'f') or_return + write_u64(i, buf, u64(8*ti.size)) or_return + switch info.endianness { + case .Platform: // nothing + case .Little: write_string(i, buf, "le") or_return + case .Big: write_string(i, buf, "be") or_return + } + + case Type_Info_Complex: + write_string(i, buf, "complex") or_return + write_u64 (i, buf, u64(8*ti.size)) or_return + case Type_Info_Quaternion: + write_string(i, buf, "quaternion") or_return + write_u64 (i, buf, u64(8*ti.size)) or_return + case Type_Info_String: + if info.is_cstring { + write_byte(i, buf, 'c') or_return + } + write_string(i, buf, "string") or_return + switch info.encoding { + case .UTF_8: /**/ + case .UTF_16: write_string(i, buf, "16") or_return + } + case Type_Info_Boolean: + switch ti.id { + case bool: write_string(i, buf, "bool") or_return + case: + write_byte(i, buf, 'b') or_return + write_u64 (i, buf, u64(8*ti.size)) or_return + } + case Type_Info_Any: + write_string(i, buf, "any") or_return + case Type_Info_Type_Id: + write_string(i, buf, "typeid") or_return + + case Type_Info_Pointer: + if info.elem == nil { + write_string(i, buf, "rawptr") or_return + } else { + write_string (i, buf, "^") or_return + write_write_type(i, buf, info.elem) or_return + } + case Type_Info_Multi_Pointer: + write_string (i, buf, "[^]") or_return + write_write_type(i, buf, info.elem) or_return + case Type_Info_Soa_Pointer: + write_string (i, buf, "#soa ^") or_return + write_write_type(i, buf, info.elem) or_return + case Type_Info_Procedure: + write_string(i, buf, "proc") or_return + if info.params == nil { + write_string(i, buf, "()") or_return + } else { + t := info.params.variant.(Type_Info_Parameters) + write_byte(i, buf, '(') or_return + for t, j in t.types { + if j > 0 { write_string(i, buf, ", ") or_return } + write_write_type(i, buf, t) or_return + } + write_string(i, buf, ")") or_return + } + if info.results != nil { + write_string (i, buf, " -> ") or_return + write_write_type(i, buf, info.results) or_return + } + case Type_Info_Parameters: + count := len(info.names) + if count != 1 { write_byte(i, buf, '(') or_return } + for name, j in info.names { + if j > 0 { write_string(i, buf, ", ") or_return } + + t := info.types[j] + + if len(name) > 0 { + write_string(i, buf, name) or_return + write_string(i, buf, ": ") or_return + } + write_write_type(i, buf, t) or_return + } + if count != 1 { write_string(i, buf, ")") or_return } + + case Type_Info_Array: + write_byte (i, buf, '[') or_return + write_u64 (i, buf, u64(info.count)) or_return + write_byte (i, buf, ']') or_return + write_write_type(i, buf, info.elem) or_return + + case Type_Info_Enumerated_Array: + if info.is_sparse { + write_string(i, buf, "#sparse") or_return + } + write_byte (i, buf, '[') or_return + write_write_type(i, buf, info.index) or_return + write_byte (i, buf, ']') or_return + write_write_type(i, buf, info.elem) or_return + + + case Type_Info_Dynamic_Array: + write_string (i, buf, "[dynamic]") or_return + write_write_type(i, buf, info.elem) or_return + case Type_Info_Slice: + write_string (i, buf, "[]") or_return + write_write_type(i, buf, info.elem) or_return + + case Type_Info_Fixed_Capacity_Dynamic_Array: + write_string (i, buf, "[dynamic; ") or_return + write_u64 (i, buf, u64(info.capacity)) or_return + write_string (i, buf, "]") or_return + write_write_type(i, buf, info.elem) or_return + + case Type_Info_Map: + write_string (i, buf, "map[") or_return + write_write_type(i, buf, info.key) or_return + write_byte (i, buf, ']') or_return + write_write_type(i, buf, info.value) or_return + + case Type_Info_Struct: + switch info.soa_kind { + case .None: // Ignore + case .Fixed: + write_string (i, buf, "#soa[") or_return + write_u64 (i, buf, u64(info.soa_len)) or_return + write_byte (i, buf, ']') or_return + write_write_type(i, buf, info.soa_base_type) or_return + return true + case .Slice: + write_string (i, buf, "#soa[]") or_return + write_write_type(i, buf, info.soa_base_type) or_return + return true + case .Dynamic: + write_string (i, buf, "#soa[dynamic]") or_return + write_write_type(i, buf, info.soa_base_type) or_return + return true + } + + write_string(i, buf, "struct ") or_return + if .packed in info.flags { write_string(i, buf, "#packed ") or_return } + if .raw_union in info.flags { write_string(i, buf, "#raw_union ") or_return } + if .all_or_none in info.flags { write_string(i, buf, "#all_or_none ") or_return } + if .simple in info.flags { write_string(i, buf, "#simple ") or_return } + if .align in info.flags { + write_string(i, buf, "#align(") or_return + write_u64(i, buf, u64(ti.align)) or_return + write_string(i, buf, ") ") or_return + } + write_byte(i, buf, '{') or_return + for name, j in info.names[:info.field_count] { + if j > 0 { write_string(i, buf, ", ") or_return } + write_string (i, buf, name) or_return + write_string (i, buf, ": ") or_return + write_write_type(i, buf, info.types[j]) or_return + } + write_byte(i, buf, '}') or_return + + case Type_Info_Union: + write_string(i, buf, "union ") or_return + if info.custom_align { + write_string(i, buf, "#align(") or_return + write_u64 (i, buf, u64(ti.align)) or_return + write_string(i, buf, ") ") or_return + } + if info.no_nil { + write_string(i, buf, "#no_nil ") or_return + } + write_byte(i, buf, '{') or_return + for variant, j in info.variants { + if j > 0 { write_string(i, buf, ", ") or_return } + write_write_type(i, buf, variant) or_return + } + write_string(i, buf, "}") or_return + + case Type_Info_Enum: + write_string (i, buf, "enum ") or_return + write_write_type(i, buf, info.base) or_return + write_string (i, buf, " {") or_return + for name, j in info.names { + if j > 0 { write_string(i, buf, ", ") or_return } + write_string(i, buf, name) or_return + } + write_string(i, buf, "}") or_return + + case Type_Info_Bit_Set: + write_string(i, buf, "bit_set[") or_return + + #partial switch elem in type_info_base(info.elem).variant { + case Type_Info_Enum: + write_write_type(i, buf, info.elem) or_return + case Type_Info_Rune: + write_encoded_rune(i, buf, rune(info.lower)) or_return + write_string (i, buf, "..") or_return + write_encoded_rune(i, buf, rune(info.upper)) or_return + case: + write_i64 (i, buf, info.lower) or_return + write_string(i, buf, "..") or_return + write_i64 (i, buf, info.upper) or_return + } + if info.explicit_underlying { + write_string (i, buf, "; ") or_return + write_write_type(i, buf, info.underlying) or_return + } + write_byte(i, buf, ']') or_return + + case Type_Info_Bit_Field: + write_string (i, buf, "bit_field ") or_return + write_write_type(i, buf, info.backing_type) or_return + write_string (i, buf, " {") or_return + for name, j in info.names[:info.field_count] { + if j > 0 { write_string(i, buf, ", ") or_return } + write_string (i, buf, name) or_return + write_string (i, buf, ": ") or_return + write_write_type(i, buf, info.types[j]) or_return + write_string (i, buf, " | ") or_return + write_u64 (i, buf, u64(info.bit_sizes[j])) or_return + } + write_byte(i, buf, '}') or_return + + + case Type_Info_Simd_Vector: + write_string (i, buf, "#simd[") or_return + write_u64 (i, buf, u64(info.count)) or_return + write_byte (i, buf, ']') or_return + write_write_type(i, buf, info.elem) or_return + + case Type_Info_Matrix: + if info.layout == .Row_Major { + write_string(i, buf, "#row_major ") or_return + } + write_string (i, buf, "matrix[") or_return + write_u64 (i, buf, u64(info.row_count)) or_return + write_string (i, buf, ", ") or_return + write_u64 (i, buf, u64(info.column_count)) or_return + write_string (i, buf, "]") or_return + write_write_type(i, buf, info.elem) or_return + } + return true +} \ No newline at end of file diff --git a/base/runtime/random_generator_chacha8_simd256.odin b/base/runtime/random_generator_chacha8_simd256.odin index c0985f456..f2ccb6934 100644 --- a/base/runtime/random_generator_chacha8_simd256.odin +++ b/base/runtime/random_generator_chacha8_simd256.odin @@ -136,7 +136,7 @@ chacha8rand_refill_simd256 :: proc(r: ^Default_Random_State) { // // LLVM appears not to consider "this instruction is totally // awful on the given microarchitcture", which leads to - // `VPCOMPRESSED` being generated iff AVX512 support is + // `VPCOMPRESSED` being generated if and only if (⟺) AVX512 support is // enabled for `intrinsics.simd_masked_compress_store`. // On Zen 4, this leads to a 50% performance regression vs // the 128-bit SIMD code. diff --git a/bin/radlink.exe b/bin/radlink.exe index bb2fd206e..8fb74fcd7 100644 Binary files a/bin/radlink.exe and b/bin/radlink.exe differ diff --git a/build.bat b/build.bat index 32c2ae658..b6e8b890d 100644 --- a/build.bat +++ b/build.bat @@ -94,6 +94,7 @@ if %release_mode% EQU 0 ( rem Debug set compiler_warnings= ^ -W4 -WX ^ -wd4100 -wd4101 -wd4127 -wd4146 ^ + -wd4324 ^ -wd4505 ^ -wd4456 -wd4457 diff --git a/build_odin.sh b/build_odin.sh index b9545a6b5..ee891e41e 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -26,36 +26,42 @@ error() { exit 1 } +SUPPORTED_LLVM_VERSIONS="22 21 20 19 18 17 14" + # Brew advises people not to add llvm to their $PATH, so try and use brew to find it. if [ -z "$LLVM_CONFIG" ] && [ -n "$(command -v brew)" ]; then - if [ -n "$(command -v $(brew --prefix llvm@21)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@21)/bin/llvm-config" - elif [ -n "$(command -v $(brew --prefix llvm@20)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@20)/bin/llvm-config" - elif [ -n "$(command -v $(brew --prefix llvm@19)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@19)/bin/llvm-config" - elif [ -n "$(command -v $(brew --prefix llvm@18)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@18)/bin/llvm-config" - elif [ -n "$(command -v $(brew --prefix llvm@17)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@17)/bin/llvm-config" - elif [ -n "$(command -v $(brew --prefix llvm@14)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@14)/bin/llvm-config" - fi + for V in $SUPPORTED_LLVM_VERSIONS; do + if [ -n "$(command -v $(brew --prefix llvm@$V)/bin/llvm-config)" ]; then + LLVM_CONFIG="$(brew --prefix llvm@$V)/bin/llvm-config" + break + fi + done fi if [ -z "$LLVM_CONFIG" ]; then - # darwin, linux, openbsd - if [ -n "$(command -v llvm-config-21)" ]; then LLVM_CONFIG="llvm-config-21" - elif [ -n "$(command -v llvm-config-20)" ]; then LLVM_CONFIG="llvm-config-20" - elif [ -n "$(command -v llvm-config-19)" ]; then LLVM_CONFIG="llvm-config-19" - elif [ -n "$(command -v llvm-config-18)" ]; then LLVM_CONFIG="llvm-config-18" - elif [ -n "$(command -v llvm-config-17)" ]; then LLVM_CONFIG="llvm-config-17" - elif [ -n "$(command -v llvm-config-14)" ]; then LLVM_CONFIG="llvm-config-14" - # freebsd - elif [ -n "$(command -v llvm-config21)" ]; then LLVM_CONFIG="llvm-config21" - elif [ -n "$(command -v llvm-config20)" ]; then LLVM_CONFIG="llvm-config20" - elif [ -n "$(command -v llvm-config19)" ]; then LLVM_CONFIG="llvm-config19" - elif [ -n "$(command -v llvm-config18)" ]; then LLVM_CONFIG="llvm-config18" - elif [ -n "$(command -v llvm-config17)" ]; then LLVM_CONFIG="llvm-config17" - elif [ -n "$(command -v llvm-config14)" ]; then LLVM_CONFIG="llvm-config14" - # fallback - elif [ -n "$(command -v llvm-config)" ]; then LLVM_CONFIG="llvm-config" - else - error "No llvm-config command found. Set LLVM_CONFIG to proceed." + DEFAULT_VERSION="" + + if [ -n "$(command -v llvm-config)" ]; then + DEFAULT_VERSION=$(llvm-config --version | awk -F. '{print $1}') + fi + + for V in $SUPPORTED_LLVM_VERSIONS; do + if [ "$DEFAULT_VERSION" = "$V" ]; then + LLVM_CONFIG="llvm-config" + break + # darwin, linux, openbsd + elif [ -n "$(command -v "llvm-config-$V")" ]; then + LLVM_CONFIG="llvm-config-$V" + break + # freebsd + elif [ -n "$(command -v "llvm-config$V")" ]; then + LLVM_CONFIG="llvm-config$V" + break + fi + done + + if [ -z "$LLVM_CONFIG" ]; then + error "No supported llvm-config command found. Set LLVM_CONFIG to proceed." fi fi @@ -72,8 +78,8 @@ LLVM_VERSION_MAJOR="$(echo $LLVM_VERSION | awk -F. '{print $1}')" LLVM_VERSION_MINOR="$(echo $LLVM_VERSION | awk -F. '{print $2}')" LLVM_VERSION_PATCH="$(echo $LLVM_VERSION | awk -F. '{print $3}')" -if [ $LLVM_VERSION_MAJOR -lt 14 ] || ([ $LLVM_VERSION_MAJOR -gt 14 ] && [ $LLVM_VERSION_MAJOR -lt 17 ]) || [ $LLVM_VERSION_MAJOR -gt 21 ]; then - error "Invalid LLVM version $LLVM_VERSION: must be 14, 17, 18, 19, 20, or 21" +if [ $LLVM_VERSION_MAJOR -lt 14 ] || ([ $LLVM_VERSION_MAJOR -gt 14 ] && [ $LLVM_VERSION_MAJOR -lt 17 ]) || [ $LLVM_VERSION_MAJOR -gt 22 ]; then + error "Invalid LLVM version $LLVM_VERSION: must be 14, 17, 18, 19, 20, 21 or 22" fi case "$OS_NAME" in diff --git a/core/bufio/reader.odin b/core/bufio/reader.odin index 7ab7da5b7..e361612d2 100644 --- a/core/bufio/reader.odin +++ b/core/bufio/reader.odin @@ -1,14 +1,14 @@ package bufio +import "base:runtime" import "core:io" -import "core:mem" import "core:unicode/utf8" import "core:bytes" // Reader is a buffered wrapper for an io.Reader Reader :: struct { buf: []byte, - buf_allocator: mem.Allocator, + buf_allocator: runtime.Allocator, rd: io.Reader, // reader r, w: int, // read and write positions for buf @@ -45,7 +45,7 @@ reader_init_with_buf :: proc(b: ^Reader, rd: io.Reader, buf: []byte) { b.buf = buf } -// reader_destroy destroys the underlying buffer with its associated allocator IFF that allocator has been set +// reader_destroy destroys the underlying buffer with its associated allocator if and only if (⟺) that allocator has been set reader_destroy :: proc(b: ^Reader) { delete(b.buf, b.buf_allocator) b^ = {} diff --git a/core/bufio/scanner.odin b/core/bufio/scanner.odin index 27d29c685..b03437866 100644 --- a/core/bufio/scanner.odin +++ b/core/bufio/scanner.odin @@ -1,10 +1,10 @@ package bufio -import "core:bytes" -import "core:io" -import "core:mem" -import "core:unicode/utf8" +import "base:runtime" import "base:intrinsics" +import "core:io" +import "core:bytes" +import "core:unicode/utf8" // Extra errors returns by scanning procedures Scanner_Extra_Error :: enum i32 { @@ -60,7 +60,15 @@ scanner_init_with_buffer :: proc(s: ^Scanner, r: io.Reader, buf: []byte) -> ^Sca s.r = r s.split = scan_lines s.max_token_size = DEFAULT_MAX_SCAN_TOKEN_SIZE - s.buf = mem.buffer_from_slice(buf) + s.buf = transmute([dynamic]byte)runtime.Raw_Dynamic_Array{ + data = raw_data(buf), + len = 0, + cap = len(buf), + allocator = runtime.Allocator{ + procedure = runtime.nil_allocator_proc, + data = nil, + }, + } resize(&s.buf, cap(s.buf)) return s } diff --git a/core/bufio/writer.odin b/core/bufio/writer.odin index 618264933..9d5ef3481 100644 --- a/core/bufio/writer.odin +++ b/core/bufio/writer.odin @@ -1,14 +1,14 @@ package bufio +import "base:runtime" import "core:io" -import "core:mem" import "core:unicode/utf8" // import "core:bytes" // Writer is a buffered wrapper for an io.Writer Writer :: struct { buf: []byte, - buf_allocator: mem.Allocator, + buf_allocator: runtime.Allocator, wr: io.Writer, n: int, @@ -35,7 +35,7 @@ writer_init_with_buf :: proc(b: ^Writer, wr: io.Writer, buf: []byte) { b.buf = buf } -// writer_destroy destroys the underlying buffer with its associated allocator IFF that allocator has been set +// writer_destroy destroys the underlying buffer with its associated allocator if and only if (⟺) that allocator has been set writer_destroy :: proc(b: ^Writer) { delete(b.buf, b.buf_allocator) b^ = {} diff --git a/core/bytes/buffer.odin b/core/bytes/buffer.odin index dd4b378c0..5fd3145b7 100644 --- a/core/bytes/buffer.odin +++ b/core/bytes/buffer.odin @@ -176,6 +176,11 @@ buffer_write_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int, loc := #caller_loca return buffer_write(b, ([^]byte)(ptr)[:size], loc=loc) } +buffer_write_slice :: proc(b: ^Buffer, slice: $S/[]$T, loc := #caller_location) -> (n: int, err: io.Error) { + size := len(slice)*size_of(T) + return buffer_write(b, ([^]byte)(raw_data(slice))[:size], loc=loc) +} + buffer_write_string :: proc(b: ^Buffer, s: string, loc := #caller_location) -> (n: int, err: io.Error) { b.last_read = .Invalid m, ok := _buffer_try_grow(b, len(s), loc=loc) @@ -248,6 +253,12 @@ buffer_read_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io. return buffer_read(b, ([^]byte)(ptr)[:size]) } +buffer_read_slice :: proc(b: ^Buffer, slice: $S/[]$T) -> (n: int, err: io.Error) { + size := len(slice)*size_of(T) + return buffer_read(b, ([^]byte)(raw_data(slice))[:size]) +} + + buffer_read_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.Error) { if len(p) == 0 { return 0, nil diff --git a/core/bytes/bytes.odin b/core/bytes/bytes.odin index 79de89d2f..55eca5386 100644 --- a/core/bytes/bytes.odin +++ b/core/bytes/bytes.odin @@ -1,8 +1,8 @@ // Procedures for manipulation of `[]byte` slices. package bytes +import "base:runtime" import "base:intrinsics" -import "core:mem" import "core:simd" import "core:unicode" import "core:unicode/utf8" @@ -35,20 +35,20 @@ SCANNER_SENTINEL_MIN_128: simd.u8x16 : u8(0xff) SIMD_REG_SIZE_128 :: 16 clone :: proc(s: []byte, allocator := context.allocator, loc := #caller_location) -> []byte { - c := make([]byte, len(s), allocator, loc) + c := make([]byte, len(s), allocator, loc=loc) copy(c, s) return c[:len(s)] } -clone_safe :: proc(s: []byte, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: mem.Allocator_Error) { - c := make([]byte, len(s), allocator, loc) or_return +clone_safe :: proc(s: []byte, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: runtime.Allocator_Error) { + c := make([]byte, len(s), allocator, loc=loc) or_return copy(c, s) return c[:len(s)], nil } ptr_from_slice :: ptr_from_bytes ptr_from_bytes :: proc(str: []byte) -> ^byte { - d := transmute(mem.Raw_String)str + d := transmute(runtime.Raw_String)str return d.data } @@ -67,10 +67,16 @@ truncate_to_rune :: proc(str: []byte, r: rune) -> []byte { return str[:n] } -// Compares two strings, returning a value representing which one comes first lexiographically. -// -1 for `a`; 1 for `b`, or 0 if they are equal. +// Compares two []byte, returning a value representing which one comes first lexiographically. +// Returns: -1 for `lhs`, 1 for `rhs`, or 0 if they are equal. compare :: proc(lhs, rhs: []byte) -> int { - return mem.compare(lhs, rhs) + res := runtime.memory_compare(raw_data(lhs), raw_data(rhs), min(len(lhs), len(rhs))) + if res == 0 && len(lhs) != len(rhs) { + return len(lhs) <= len(rhs) ? -1 : +1 + } else if len(lhs) == 0 && len(rhs) == 0 { + return 0 + } + return res } contains_rune :: proc(s: []byte, r: rune) -> int { @@ -157,7 +163,7 @@ has_suffix :: proc(s, suffix: []byte) -> bool { } -join :: proc(a: [][]byte, sep: []byte, allocator := context.allocator) -> []byte { +join :: proc(a: [][]byte, sep: []byte, allocator := context.allocator, loc := #caller_location) -> []byte { if len(a) == 0 { return nil } @@ -167,7 +173,7 @@ join :: proc(a: [][]byte, sep: []byte, allocator := context.allocator) -> []byte n += len(s) } - b := make([]byte, n, allocator) + b := make([]byte, n, allocator, loc=loc) i := copy(b, a[0]) for s in a[1:] { i += copy(b[i:], sep) @@ -176,7 +182,7 @@ join :: proc(a: [][]byte, sep: []byte, allocator := context.allocator) -> []byte return b } -join_safe :: proc(a: [][]byte, sep: []byte, allocator := context.allocator) -> (data: []byte, err: mem.Allocator_Error) { +join_safe :: proc(a: [][]byte, sep: []byte, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: runtime.Allocator_Error) { if len(a) == 0 { return nil, nil } @@ -186,7 +192,7 @@ join_safe :: proc(a: [][]byte, sep: []byte, allocator := context.allocator) -> ( n += len(s) } - b := make([]byte, n, allocator) or_return + b := make([]byte, n, allocator, loc=loc) or_return i := copy(b, a[0]) for s in a[1:] { i += copy(b[i:], sep) @@ -195,7 +201,7 @@ join_safe :: proc(a: [][]byte, sep: []byte, allocator := context.allocator) -> ( return b, nil } -concatenate :: proc(a: [][]byte, allocator := context.allocator) -> []byte { +concatenate :: proc(a: [][]byte, allocator := context.allocator, loc := #caller_location) -> []byte { if len(a) == 0 { return nil } @@ -204,7 +210,7 @@ concatenate :: proc(a: [][]byte, allocator := context.allocator) -> []byte { for s in a { n += len(s) } - b := make([]byte, n, allocator) + b := make([]byte, n, allocator, loc=loc) i := 0 for s in a { i += copy(b[i:], s) @@ -212,7 +218,7 @@ concatenate :: proc(a: [][]byte, allocator := context.allocator) -> []byte { return b } -concatenate_safe :: proc(a: [][]byte, allocator := context.allocator) -> (data: []byte, err: mem.Allocator_Error) { +concatenate_safe :: proc(a: [][]byte, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: runtime.Allocator_Error) { if len(a) == 0 { return nil, nil } @@ -221,7 +227,7 @@ concatenate_safe :: proc(a: [][]byte, allocator := context.allocator) -> (data: for s in a { n += len(s) } - b := make([]byte, n, allocator) or_return + b := make([]byte, n, allocator, loc=loc) or_return i := 0 for s in a { i += copy(b[i:], s) @@ -231,7 +237,7 @@ concatenate_safe :: proc(a: [][]byte, allocator := context.allocator) -> (data: @private -_split :: proc(s, sep: []byte, sep_save, n: int, allocator := context.allocator) -> [][]byte { +_split :: proc(s, sep: []byte, sep_save, n: int, allocator := context.allocator, loc := #caller_location) -> [][]byte { s, n := s, n if n == 0 { @@ -244,7 +250,7 @@ _split :: proc(s, sep: []byte, sep_save, n: int, allocator := context.allocator) n = l } - res := make([dynamic][]byte, n, allocator) + res := make([dynamic][]byte, n, allocator, loc=loc) for i := 0; i < n-1; i += 1 { _, w := utf8.decode_rune(s) res[i] = s[:w] @@ -260,7 +266,7 @@ _split :: proc(s, sep: []byte, sep_save, n: int, allocator := context.allocator) n = count(s, sep) + 1 } - res := make([dynamic][]byte, n, allocator) + res := make([dynamic][]byte, n, allocator, loc=loc) n -= 1 @@ -278,20 +284,20 @@ _split :: proc(s, sep: []byte, sep_save, n: int, allocator := context.allocator) return res[:i+1] } -split :: proc(s, sep: []byte, allocator := context.allocator) -> [][]byte { - return _split(s, sep, 0, -1, allocator) +split :: proc(s, sep: []byte, allocator := context.allocator, loc := #caller_location) -> [][]byte { + return _split(s, sep, 0, -1, allocator, loc) } -split_n :: proc(s, sep: []byte, n: int, allocator := context.allocator) -> [][]byte { - return _split(s, sep, 0, n, allocator) +split_n :: proc(s, sep: []byte, n: int, allocator := context.allocator, loc := #caller_location) -> [][]byte { + return _split(s, sep, 0, n, allocator, loc) } -split_after :: proc(s, sep: []byte, allocator := context.allocator) -> [][]byte { - return _split(s, sep, len(sep), -1, allocator) +split_after :: proc(s, sep: []byte, allocator := context.allocator, loc := #caller_location) -> [][]byte { + return _split(s, sep, len(sep), -1, allocator, loc) } -split_after_n :: proc(s, sep: []byte, n: int, allocator := context.allocator) -> [][]byte { - return _split(s, sep, len(sep), n, allocator) +split_after_n :: proc(s, sep: []byte, n: int, allocator := context.allocator, loc := #caller_location) -> [][]byte { + return _split(s, sep, len(sep), n, allocator, loc) } @@ -768,14 +774,14 @@ count :: proc(s, substr: []byte) -> int { } -repeat :: proc(s: []byte, count: int, allocator := context.allocator) -> []byte { +repeat :: proc(s: []byte, count: int, allocator := context.allocator, loc := #caller_location) -> []byte { if count < 0 { panic("bytes: negative repeat count") } else if count > 0 && (len(s)*count)/count != len(s) { panic("bytes: repeat count will cause an overflow") } - b := make([]byte, len(s)*count, allocator) + b := make([]byte, len(s)*count, allocator, loc=loc) i := copy(b, s) for i < len(b) { // 2^N trick to reduce the need to copy copy(b[i:], b[:i]) @@ -784,12 +790,12 @@ repeat :: proc(s: []byte, count: int, allocator := context.allocator) -> []byte return b } -replace_all :: proc(s, old, new: []byte, allocator := context.allocator) -> (output: []byte, was_allocation: bool) { - return replace(s, old, new, -1, allocator) +replace_all :: proc(s, old, new: []byte, allocator := context.allocator, loc := #caller_location) -> (output: []byte, was_allocation: bool) { + return replace(s, old, new, -1, allocator, loc) } // if n < 0, no limit on the number of replacements -replace :: proc(s, old, new: []byte, n: int, allocator := context.allocator) -> (output: []byte, was_allocation: bool) { +replace :: proc(s, old, new: []byte, n: int, allocator := context.allocator, loc := #caller_location) -> (output: []byte, was_allocation: bool) { if string(old) == string(new) || n == 0 { was_allocation = false output = s @@ -805,7 +811,7 @@ replace :: proc(s, old, new: []byte, n: int, allocator := context.allocator) -> } - t := make([]byte, len(s) + byte_count*(len(new) - len(old)), allocator) + t := make([]byte, len(s) + byte_count*(len(new) - len(old)), allocator, loc=loc) was_allocation = true w := 0 @@ -829,12 +835,12 @@ replace :: proc(s, old, new: []byte, n: int, allocator := context.allocator) -> return } -remove :: proc(s, key: []byte, n: int, allocator := context.allocator) -> (output: []byte, was_allocation: bool) { - return replace(s, key, {}, n, allocator) +remove :: proc(s, key: []byte, n: int, allocator := context.allocator, loc := #caller_location) -> (output: []byte, was_allocation: bool) { + return replace(s, key, {}, n, allocator, loc) } -remove_all :: proc(s, key: []byte, allocator := context.allocator) -> (output: []byte, was_allocation: bool) { - return remove(s, key, -1, allocator) +remove_all :: proc(s, key: []byte, allocator := context.allocator, loc := #caller_location) -> (output: []byte, was_allocation: bool) { + return remove(s, key, -1, allocator, loc) } @(private) _ascii_space := [256]u8{'\t' = 1, '\n' = 1, '\v' = 1, '\f' = 1, '\r' = 1, ' ' = 1} @@ -991,16 +997,18 @@ trim_left :: proc(s: []byte, cutset: []byte) -> []byte { if s == nil || cutset == nil { return s } - state := cutset - return trim_left_proc_with_state(s, is_in_cutset, &state) + begin := 0; end := len(s) + for ; begin < end && index_byte(cutset, s[begin]) >= 0; begin += 1 {} + return s[begin:] } trim_right :: proc(s: []byte, cutset: []byte) -> []byte { if s == nil || cutset == nil { return s } - state := cutset - return trim_right_proc_with_state(s, is_in_cutset, &state) + begin := 0; end := len(s) + for ; end > begin && index_byte(cutset, s[end - 1]) >= 0; end -= 1 {} + return s[:end] } trim :: proc(s: []byte, cutset: []byte) -> []byte { @@ -1046,7 +1054,7 @@ trim_suffix :: proc(s, suffix: []byte) -> []byte { return s } -split_multi :: proc(s: []byte, substrs: [][]byte, skip_empty := false, allocator := context.allocator) -> [][]byte #no_bounds_check { +split_multi :: proc(s: []byte, substrs: [][]byte, skip_empty := false, allocator := context.allocator, loc := #caller_location) -> [][]byte #no_bounds_check { if s == nil || len(substrs) <= 0 { return nil } @@ -1094,7 +1102,7 @@ split_multi :: proc(s: []byte, substrs: [][]byte, skip_empty := false, allocator return nil } - buf := make([][]byte, n, allocator) + buf := make([][]byte, n, allocator, loc=loc) n, i, l = 0, 0, 0 @@ -1181,10 +1189,10 @@ split_multi_iterator :: proc(s: ^[]byte, substrs: [][]byte, skip_empty := false) // Scrubs invalid utf-8 characters and replaces them with the replacement string // Adjacent invalid bytes are only replaced once -scrub :: proc(s: []byte, replacement: []byte, allocator := context.allocator) -> []byte { +scrub :: proc(s: []byte, replacement: []byte, allocator := context.allocator, loc := #caller_location) -> []byte { str := s b: Buffer - buffer_init_allocator(&b, 0, len(s), allocator) + buffer_init_allocator(&b, 0, len(s), allocator, loc) has_error := false cursor := 0 @@ -1196,11 +1204,11 @@ scrub :: proc(s: []byte, replacement: []byte, allocator := context.allocator) -> if r == utf8.RUNE_ERROR { if !has_error { has_error = true - buffer_write(&b, origin[:cursor]) + buffer_write(&b, origin[:cursor], loc) } } else if has_error { has_error = false - buffer_write(&b, replacement) + buffer_write(&b, replacement, loc) origin = origin[cursor:] cursor = 0 @@ -1214,10 +1222,10 @@ scrub :: proc(s: []byte, replacement: []byte, allocator := context.allocator) -> } -reverse :: proc(s: []byte, allocator := context.allocator) -> []byte { +reverse :: proc(s: []byte, allocator := context.allocator, loc := #caller_location) -> []byte { str := s n := len(str) - buf := make([]byte, n) + buf := make([]byte, n, loc=loc) i := n for len(str) > 0 { @@ -1229,7 +1237,7 @@ reverse :: proc(s: []byte, allocator := context.allocator) -> []byte { return buf } -expand_tabs :: proc(s: []byte, tab_size: int, allocator := context.allocator) -> []byte { +expand_tabs :: proc(s: []byte, tab_size: int, allocator := context.allocator, loc := #caller_location) -> []byte { if tab_size <= 0 { panic("tab size must be positive") } @@ -1240,7 +1248,7 @@ expand_tabs :: proc(s: []byte, tab_size: int, allocator := context.allocator) -> } b: Buffer - buffer_init_allocator(&b, 0, len(s), allocator) + buffer_init_allocator(&b, 0, len(s), allocator, loc=loc) str := s column: int @@ -1252,7 +1260,7 @@ expand_tabs :: proc(s: []byte, tab_size: int, allocator := context.allocator) -> expand := tab_size - column%tab_size for i := 0; i < expand; i += 1 { - buffer_write_byte(&b, ' ') + buffer_write_byte(&b, ' ', loc) } column += expand @@ -1263,7 +1271,7 @@ expand_tabs :: proc(s: []byte, tab_size: int, allocator := context.allocator) -> column += w } - buffer_write_rune(&b, r) + buffer_write_rune(&b, r, loc) } str = str[w:] @@ -1288,59 +1296,59 @@ partition :: proc(str, sep: []byte) -> (head, match, tail: []byte) { center_justify :: centre_justify // NOTE(bill): Because Americans exist // centre_justify returns a byte slice with a pad byte slice at boths sides if the str's rune length is smaller than length -centre_justify :: proc(str: []byte, length: int, pad: []byte, allocator := context.allocator) -> []byte { +centre_justify :: proc(str: []byte, length: int, pad: []byte, allocator := context.allocator, loc := #caller_location) -> []byte { n := rune_count(str) if n >= length || pad == nil { - return clone(str, allocator) + return clone(str, allocator, loc) } remains := length-1 pad_len := rune_count(pad) b: Buffer - buffer_init_allocator(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator) + buffer_init_allocator(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator, loc) write_pad_string(&b, pad, pad_len, remains/2) - buffer_write(&b, str) + buffer_write(&b, str, loc) write_pad_string(&b, pad, pad_len, (remains+1)/2) return buffer_to_bytes(&b) } // left_justify returns a byte slice with a pad byte slice at left side if the str's rune length is smaller than length -left_justify :: proc(str: []byte, length: int, pad: []byte, allocator := context.allocator) -> []byte { +left_justify :: proc(str: []byte, length: int, pad: []byte, allocator := context.allocator, loc := #caller_location) -> []byte { n := rune_count(str) if n >= length || pad == nil { - return clone(str, allocator) + return clone(str, allocator, loc) } remains := length-1 pad_len := rune_count(pad) b: Buffer - buffer_init_allocator(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator) + buffer_init_allocator(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator, loc) - buffer_write(&b, str) + buffer_write(&b, str, loc) write_pad_string(&b, pad, pad_len, remains) return buffer_to_bytes(&b) } // right_justify returns a byte slice with a pad byte slice at right side if the str's rune length is smaller than length -right_justify :: proc(str: []byte, length: int, pad: []byte, allocator := context.allocator) -> []byte { +right_justify :: proc(str: []byte, length: int, pad: []byte, allocator := context.allocator, loc := #caller_location) -> []byte { n := rune_count(str) if n >= length || pad == nil { - return clone(str, allocator) + return clone(str, allocator, loc) } remains := length-1 pad_len := rune_count(pad) b: Buffer - buffer_init_allocator(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator) + buffer_init_allocator(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator, loc) write_pad_string(&b, pad, pad_len, remains) - buffer_write(&b, str) + buffer_write(&b, str, loc) return buffer_to_bytes(&b) } @@ -1349,11 +1357,11 @@ right_justify :: proc(str: []byte, length: int, pad: []byte, allocator := contex @private -write_pad_string :: proc(b: ^Buffer, pad: []byte, pad_len, remains: int) { +write_pad_string :: proc(b: ^Buffer, pad: []byte, pad_len, remains: int, loc := #caller_location) { repeats := remains / pad_len for i := 0; i < repeats; i += 1 { - buffer_write(b, pad) + buffer_write(b, pad, loc) } n := remains % pad_len @@ -1361,7 +1369,7 @@ write_pad_string :: proc(b: ^Buffer, pad: []byte, pad_len, remains: int) { for i := 0; i < n; i += 1 { r, width := utf8.decode_rune(p) - buffer_write_rune(b, r) + buffer_write_rune(b, r, loc) p = p[width:] } } @@ -1369,7 +1377,7 @@ write_pad_string :: proc(b: ^Buffer, pad: []byte, pad_len, remains: int) { // fields splits the byte slice s around each instance of one or more consecutive white space character, defined by unicode.is_space // returning a slice of subslices of s or an empty slice if s only contains white space -fields :: proc(s: []byte, allocator := context.allocator) -> [][]byte #no_bounds_check { +fields :: proc(s: []byte, allocator := context.allocator, loc := #caller_location) -> [][]byte #no_bounds_check { n := 0 was_space := 1 set_bits := u8(0) @@ -1384,14 +1392,14 @@ fields :: proc(s: []byte, allocator := context.allocator) -> [][]byte #no_bounds } if set_bits >= utf8.RUNE_SELF { - return fields_proc(s, unicode.is_space, allocator) + return fields_proc(s, unicode.is_space, allocator, loc) } if n == 0 { return nil } - a := make([][]byte, n, allocator) + a := make([][]byte, n, allocator, loc=loc) na := 0 field_start := 0 i := 0 @@ -1425,15 +1433,15 @@ fields :: proc(s: []byte, allocator := context.allocator) -> [][]byte #no_bounds // // fields_proc makes no guarantee about the order in which it calls f(ch) // it assumes that `f` always returns the same value for a given ch -fields_proc :: proc(s: []byte, f: proc(rune) -> bool, allocator := context.allocator) -> [][]byte #no_bounds_check { - subslices := make([dynamic][]byte, 0, 32, allocator) +fields_proc :: proc(s: []byte, f: proc(rune) -> bool, allocator := context.allocator, loc := #caller_location) -> [][]byte #no_bounds_check { + subslices := make([dynamic][]byte, 0, 32, allocator, loc=loc) start, end := -1, -1 for r, offset in string(s) { end = offset if f(r) { if start >= 0 { - append(&subslices, s[start : end]) + append(&subslices, s[start : end], loc=loc) // -1 could be used, but just speed it up through bitwise not // gotta love 2's complement start = ~start @@ -1446,13 +1454,13 @@ fields_proc :: proc(s: []byte, f: proc(rune) -> bool, allocator := context.alloc } if start >= 0 { - append(&subslices, s[start : len(s)]) + append(&subslices, s[start : len(s)], loc=loc) } return subslices[:] } -// alias returns true iff a and b have a non-zero length, and any part of +// alias returns true if and only if (⟺) a and b have a non-zero length, and any part of // a overlaps with b. alias :: proc "contextless" (a, b: []byte) -> bool { a_len, b_len := len(a), len(b) @@ -1466,7 +1474,7 @@ alias :: proc "contextless" (a, b: []byte) -> bool { return a_start <= b_end && b_start <= a_end } -// alias_inexactly returns true iff a and b have a non-zero length, +// alias_inexactly returns true if and only if (⟺) a and b have a non-zero length, // the base pointer of a and b are NOT equal, and any part of a overlaps // with b (ie: `alias(a, b)` with an exception that returns false for // `a == b`, `b = a[:len(a)-69]` and similar conditions). diff --git a/core/bytes/reader.odin b/core/bytes/reader.odin index 184f93835..189a269ed 100644 --- a/core/bytes/reader.odin +++ b/core/bytes/reader.odin @@ -61,6 +61,27 @@ reader_read_at :: proc(r: ^Reader, p: []byte, off: i64) -> (n: int, err: io.Erro } return } +reader_read_slice :: proc(r: ^Reader, slice: $T/[]$S) -> (n: int, err: io.Error) { + b := ([^]byte)(raw_data(slice))[:len(slice)*size_of(S)] + return reader_read(r, b) +} + +reader_read_slice_at :: proc(r: ^Reader, slice: $T/[]$S, off: i64) -> (n: int, err: io.Error) { + b := ([^]byte)(raw_data(slice))[:len(slice)*size_of(S)] + return reader_read_at(r, b, off) +} + +reader_read_ptr :: proc(r: ^Reader, data: rawptr, len: int) -> (n: int, err: io.Error) { + b := ([^]byte)(data)[:len] + return reader_read(r, b) +} + +reader_read_ptr_at :: proc(r: ^Reader, data: rawptr, len: int, off: i64) -> (n: int, err: io.Error) { + b := ([^]byte)(data)[:len] + return reader_read_at(r, b, off) +} + + reader_read_byte :: proc(r: ^Reader) -> (byte, io.Error) { r.prev_rune = -1 if r.i >= i64(len(r.s)) { diff --git a/core/c/libc/math.odin b/core/c/libc/math.odin index d0a015c70..bc3dd9034 100644 --- a/core/c/libc/math.odin +++ b/core/c/libc/math.odin @@ -154,12 +154,12 @@ _nan_bit_pattern := ~u64(0) // On amd64 Windows and Linux, float_t and double_t are respectively both // their usual types. On x86 it's not possible to define these types correctly -// since they would be long double which Odin does have support for. +// since they would be long double which Odin does NOT have support for. float_t :: float double_t :: double NAN := transmute(double)(_nan_bit_pattern) -INFINITY :: 1e5000 +INFINITY :: 0h7ff00000_00000000 // +Inf HUGE_VALF :: INFINITY HUGE_VAL :: double(INFINITY) diff --git a/core/compress/common.odin b/core/compress/common.odin index d78aec328..07ea7b71c 100644 --- a/core/compress/common.odin +++ b/core/compress/common.odin @@ -368,8 +368,6 @@ refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width := if len(z.input_data) != 0 { b = u64(z.input_data[0]) z.input_data = z.input_data[1:] - } else { - b = 0 } z.code_buffer |= b << u8(z.num_bits) diff --git a/core/compress/gzip/doc.odin b/core/compress/gzip/doc.odin index c20ebc33a..e4b1929dd 100644 --- a/core/compress/gzip/doc.odin +++ b/core/compress/gzip/doc.odin @@ -5,6 +5,7 @@ Example: import "core:bytes" import "core:os" import "core:compress" + import "core:compress/gzip" import "core:fmt" // Small GZIP file with fextra, fname and fcomment present. @@ -22,7 +23,8 @@ Example: main :: proc() { // Set up output buffer. - buf := bytes.Buffer{} + buf: bytes.Buffer + defer bytes.buffer_destroy(&buf) stdout :: proc(s: string) { os.write_string(os.stdout, s) @@ -31,15 +33,13 @@ Example: os.write_string(os.stderr, s) } - args := os.args - - if len(args) < 2 { + if len(os.args) < 2 { stderr("No input file specified.\n") - err := load(data=TEST, buf=&buf, known_gzip_size=len(TEST)) + err := gzip.load(data=TEST, buf=&buf, known_gzip_size=len(TEST)) if err == nil { - stdout("Displaying test vector: ") + stdout("Displaying test vector: \"") stdout(bytes.buffer_to_string(&buf)) - stdout("\n") + stdout("\"\n") } else { fmt.printf("gzip.load returned %v\n", err) } @@ -47,35 +47,31 @@ Example: os.exit(0) } - // The rest are all files. - args = args[1:] - err: Error + for file in os.args[1:] { + err: gzip.Error - for file in args { if file == "-" { // Read from stdin - s := os.stream_from_handle(os.stdin) ctx := &compress.Context_Stream_Input{ - input = s, + input = os.stdin.stream, } - err = load(ctx, &buf) + err = gzip.load(ctx, &buf) } else { - err = load(file, &buf) + err = gzip.load(file, &buf) } - if err != nil { - if err != E_General.File_Not_Found { - stderr("File not found: ") - stderr(file) - stderr("\n") - os.exit(1) - } + switch err { + case nil: + stdout(bytes.buffer_to_string(&buf)) + case gzip.E_General.File_Not_Found: + stderr("File not found: ") + stderr(file) + stderr("\n") + os.exit(1) + case: stderr("GZIP returned an error.\n") - bytes.buffer_destroy(&buf) os.exit(2) } - stdout(bytes.buffer_to_string(&buf)) } - bytes.buffer_destroy(&buf) } */ package compress_gzip diff --git a/core/compress/gzip/gzip.odin b/core/compress/gzip/gzip.odin index 7dc8120e4..aedbe3a83 100644 --- a/core/compress/gzip/gzip.odin +++ b/core/compress/gzip/gzip.odin @@ -107,14 +107,10 @@ load :: proc{load_from_bytes, load_from_file, load_from_context} load_from_file :: proc(filename: string, buf: ^bytes.Buffer, expected_output_size := -1, allocator := context.allocator) -> (err: Error) { context.allocator = allocator - data, ok := os.read_entire_file(filename) - defer delete(data) + file_data, file_err := os.read_entire_file(filename, allocator) + defer delete(file_data) - err = E_General.File_Not_Found - if ok { - err = load_from_bytes(data, buf, len(data), expected_output_size) - } - return + return load_from_bytes(file_data, buf, len(file_data), expected_output_size) if file_err == nil else E_General.File_Not_Found } load_from_bytes :: proc(data: []byte, buf: ^bytes.Buffer, known_gzip_size := -1, expected_output_size := -1, allocator := context.allocator) -> (err: Error) { diff --git a/core/compress/zlib/zlib.odin b/core/compress/zlib/zlib.odin index b9189c1f1..72664846e 100644 --- a/core/compress/zlib/zlib.odin +++ b/core/compress/zlib/zlib.odin @@ -1,4 +1,4 @@ -#+vet !using-param +#+feature using-stmt package compress_zlib /* @@ -326,7 +326,7 @@ decode_huffman :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bo return 0, .Code_Buffer_Malformed } compress.refill_lsb(z) - if z.num_bits > 63 { + if z.code_buffer == 0 { return 0, .Stream_Too_Short } } @@ -491,7 +491,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all */ expected_output_size = max(max(expected_output_size, compress.COMPRESS_OUTPUT_ALLOCATE_MIN), 512) - // fmt.printf("\nZLIB: Expected Payload Size: %v\n\n", expected_output_size); + // fmt.printfln("ZLIB: Expected Payload Size: %v", expected_output_size) if expected_output_size > 0 && expected_output_size <= compress.COMPRESS_OUTPUT_ALLOCATE_MAX { /* @@ -522,11 +522,16 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all final := u32(0) type := u32(0) + defer if int(z.bytes_written) != len(z.output.buf) { + resize(&z.output.buf, int(z.bytes_written)) + } + for { final = compress.read_bits_lsb(z, 1) type = compress.read_bits_lsb(z, 2) - // fmt.printf("Final: %v | Type: %v\n", final, type) + // fmt.printfln("len(z): %v", len(z.input_data)) + // fmt.printfln("Final: %v | Type: %v", final, type) switch type { case 0: @@ -561,7 +566,6 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all case 3: return .BType_3 case: - // fmt.printf("Err: %v | Final: %v | Type: %v\n", err, final, type) if type == 1 { // Use fixed code lengths. build_huffman(z_repeat, Z_FIXED_LENGTH[:]) or_return @@ -590,7 +594,6 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all for n < ntot { c = decode_huffman(z, codelength_ht) or_return - if c < 0 || c >= 19 { return .Huffman_Bad_Code_Lengths } @@ -635,15 +638,12 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all } parse_huffman_block(z, z_repeat, z_offset) or_return } + if final == 1 { break } } - if int(z.bytes_written) != len(z.output.buf) { - resize(&z.output.buf, int(z.bytes_written)) or_return - } - return nil } diff --git a/core/container/avl/avl.odin b/core/container/avl/avl.odin index 6c7216c29..1208cd213 100644 --- a/core/container/avl/avl.odin +++ b/core/container/avl/avl.odin @@ -100,20 +100,20 @@ len :: proc "contextless" (t: ^$T/Tree($Value)) -> int { return t._size } -// first returns the first node in the tree (in-order) or nil iff +// first returns the first node in the tree (in-order) or nil if and only if (⟺) // the tree is empty. first :: proc "contextless" (t: ^$T/Tree($Value)) -> ^Node(Value) { return tree_first_or_last_in_order(t, Direction.Backward) } -// last returns the last element in the tree (in-order) or nil iff +// last returns the last element in the tree (in-order) or nil if and only if (⟺) // the tree is empty. last :: proc "contextless" (t: ^$T/Tree($Value)) -> ^Node(Value) { return tree_first_or_last_in_order(t, Direction.Forward) } // find finds the value in the tree, and returns the corresponding -// node or nil iff the value is not present. +// node or nil if and only if (⟺) the value is not present. find :: proc(t: ^$T/Tree($Value), value: Value) -> ^Node(Value) { cur := t._root descend_loop: for cur != nil { @@ -168,7 +168,7 @@ find_or_insert :: proc( return } -// remove removes a node or value from the tree, and returns true iff the +// remove removes a node or value from the tree, and returns true if and only if (⟺) the // removal was successful. While the node's value will be left intact, // the node itself will be freed via the tree's node allocator. remove :: proc { @@ -176,7 +176,7 @@ remove :: proc { remove_node, } -// remove_value removes a value from the tree, and returns true iff the +// remove_value removes a value from the tree, and returns true if and only if (⟺) the // removal was successful. While the node's value will be left intact, // the node itself will be freed via the tree's node allocator. remove_value :: proc(t: ^$T/Tree($Value), value: Value, call_on_remove: bool = true) -> bool { @@ -187,7 +187,7 @@ remove_value :: proc(t: ^$T/Tree($Value), value: Value, call_on_remove: bool = t return remove_node(t, n, call_on_remove) } -// remove_node removes a node from the tree, and returns true iff the +// remove_node removes a node from the tree, and returns true if and only if (⟺) the // removal was successful. While the node's value will be left intact, // the node itself will be freed via the tree's node allocator. remove_node :: proc(t: ^$T/Tree($Value), node: ^Node(Value), call_on_remove: bool = true) -> bool { @@ -281,14 +281,14 @@ iterator_from_pos :: proc "contextless" ( } // iterator_get returns the node currently pointed to by the iterator, -// or nil iff the node has been removed, the tree is empty, or the end +// or nil if and only if (⟺) the node has been removed, the tree is empty, or the end // of the tree has been reached. iterator_get :: proc "contextless" (it: ^$I/Iterator($Value)) -> ^Node(Value) { return it._cur } // iterator_remove removes the node currently pointed to by the iterator, -// and returns true iff the removal was successful. Semantics are the +// and returns true if and only if (⟺) the removal was successful. Semantics are the // same as the Tree remove. iterator_remove :: proc(it: ^$I/Iterator($Value), call_on_remove: bool = true) -> bool { if it._cur == nil { @@ -304,7 +304,7 @@ iterator_remove :: proc(it: ^$I/Iterator($Value), call_on_remove: bool = true) - } // iterator_next advances the iterator and returns the (node, true) or -// or (nil, false) iff the end of the tree has been reached. +// or (nil, false) if and only if (⟺) the end of the tree has been reached. // // Note: The first call to iterator_next will return the first node instead // of advancing the iterator. diff --git a/core/container/bit_array/bit_array.odin b/core/container/bit_array/bit_array.odin index 85b941d12..7d74d9ba7 100644 --- a/core/container/bit_array/bit_array.odin +++ b/core/container/bit_array/bit_array.odin @@ -2,7 +2,6 @@ package container_dynamic_bit_array import "base:builtin" import "base:intrinsics" -import "core:mem" /* Note that these constants are dependent on the backing being a u64. @@ -329,7 +328,7 @@ Inputs: */ clear :: proc(ba: ^Bit_Array) { if ba == nil { return } - mem.zero_slice(ba.bits[:]) + intrinsics.mem_zero(raw_data(ba.bits), builtin.len(ba.bits) * NUM_BITS / 8) } /* Gets the length of set and unset valid bits in the Bit_Array. diff --git a/core/container/handle_map/doc.odin b/core/container/handle_map/doc.odin new file mode 100644 index 000000000..16b285982 --- /dev/null +++ b/core/container/handle_map/doc.odin @@ -0,0 +1,60 @@ +/* +Handle-based map using either fixed-length arrays, or exponential arrays from "core:container/xar". + +Example: + import hm "core:container/handle_map" + + Handle :: hm.Handle32 + + Entity :: struct { + handle: Handle, + pos: [2]f32, + } + + { // static map + entities: hm.Static_Handle_Map(1024, Entity, Handle) + + h1 := hm.add(&entities, Entity{pos = {1, 4}}) + h2 := hm.add(&entities, Entity{pos = {9, 16}}) + + if e, ok := hm.get(&entities, h2); ok { + e.pos.x += 32 + } + + hm.remove(&entities, h1) + + h3 := hm.add(&entities, Entity{pos = {6, 7}}) + assert(hm.is_valid(entities, h3)) + + it := hm.iterator_make(&entities) + for e, h in hm.iterate(&it) { + assert(hm.is_valid(entities, h)) + e.pos += {1, 2} + } + } + + { // dynamic map + entities: hm.Dynamic_Handle_Map(Entity, Handle) + hm.dynamic_init(&entities, context.allocator) + defer hm.dynamic_destroy(&entities) + + h1 := hm.add(&entities, Entity{pos = {1, 4}}) + h2 := hm.add(&entities, Entity{pos = {9, 16}}) + + if e, ok := hm.get(&entities, h2); ok { + e.pos.x += 32 + } + + hm.remove(&entities, h1) + + h3 := hm.add(&entities, Entity{pos = {6, 7}}) + assert(hm.is_valid(entities, h3)) + + it := hm.iterator_make(&entities) + for e, h in hm.iterate(&it) { + assert(hm.is_valid(entities, h)) + e.pos += {1, 2} + } + } +*/ +package container_handle_map \ No newline at end of file diff --git a/core/container/handle_map/dynamic_handle_map.odin b/core/container/handle_map/dynamic_handle_map.odin new file mode 100644 index 000000000..09ea92f82 --- /dev/null +++ b/core/container/handle_map/dynamic_handle_map.odin @@ -0,0 +1,142 @@ +package container_handle_map + +import "base:runtime" +import "base:builtin" +import "base:intrinsics" +@(require) import "core:container/xar" + +Dynamic_Handle_Map :: struct($T: typeid, $Handle_Type: typeid) + where + intrinsics.type_has_field(Handle_Type, "idx"), + intrinsics.type_has_field(Handle_Type, "gen"), + intrinsics.type_is_unsigned(intrinsics.type_field_type(Handle_Type, "idx")), + intrinsics.type_is_unsigned(intrinsics.type_field_type(Handle_Type, "gen")), + intrinsics.type_field_type(Handle_Type, "idx") == intrinsics.type_field_type(Handle_Type, "gen"), + + intrinsics.type_has_field (T, "handle"), + intrinsics.type_field_type(T, "handle") == Handle_Type { + + items: xar.Array(T, 4), + unused_items: xar.Array(u32, 4), +} + +dynamic_init :: proc(m: ^$D/Dynamic_Handle_Map($T, $Handle_Type), allocator: runtime.Allocator) { + xar.init(&m.items, allocator) + xar.init(&m.unused_items, allocator) +} + +dynamic_destroy :: proc(m: ^$D/Dynamic_Handle_Map($T, $Handle_Type)) { + xar.destroy(&m.unused_items) + xar.destroy(&m.items) +} + +@(require_results) +dynamic_add :: proc(m: ^$D/Dynamic_Handle_Map($T, $Handle_Type), item: T, loc := #caller_location) -> (handle: Handle_Type, err: runtime.Allocator_Error) #optional_allocator_error { + if xar.len(m.unused_items) > 0 { + i := xar.pop(&m.unused_items) + ptr := xar.get_ptr_unsafe(&m.items, i) + prev_gen := ptr.handle.gen + ptr^ = item + + ptr.handle.idx = auto_cast i + ptr.handle.gen = auto_cast (prev_gen + 1) + return ptr.handle, nil + } + + if xar.len(m.items) == 0 { + // initialize the zero-value sentinel + xar.append(&m.items, T{}, loc) or_return + } + + _ = xar.append(&m.items, item, loc) or_return + i := xar.len(m.items)-1 + + ptr := xar.get_ptr_unsafe(&m.items, i) + + ptr.handle.idx = auto_cast i + ptr.handle.gen = 1 + return ptr.handle, nil +} + +@(require_results) +dynamic_get :: proc "contextless" (m: ^$D/Dynamic_Handle_Map($T, $Handle_Type), h: Handle_Type) -> (^T, bool) #optional_ok { + if h.idx <= 0 || int(u32(h.idx)) >= xar.len(m.items) { + return nil, false + } + if e := xar.get_ptr_unsafe(&m.items, h.idx); e.handle == h { + return e, true + } + return nil, false +} + +dynamic_remove :: proc(m: ^$D/Dynamic_Handle_Map($T, $Handle_Type), h: Handle_Type, loc := #caller_location) -> (found: bool, err: runtime.Allocator_Error) { + if h.idx <= 0 || int(u32(h.idx)) >= xar.len(m.items) { + return false, nil + } + + if item := xar.get_ptr(&m.items, h.idx); item.handle == h { + xar.append(&m.unused_items, u32(h.idx), loc) or_return + item.handle.idx = 0 + return true, nil + } + + return false, nil +} + +@(require_results) +dynamic_is_valid :: proc "contextless" (m: ^$D/Dynamic_Handle_Map($T, $Handle_Type), h: Handle_Type) -> bool { + return h.idx > 0 && int(u32(h.idx)) < xar.len(m.items) && xar.get_ptr_unsafe(&m.items, h.idx).handle == h +} + +// Returns the number of possibly valid items in the handle map. +@(require_results) +dynamic_len :: proc "contextless" (m: $D/Dynamic_Handle_Map($T, $Handle_Type)) -> uint { + n := xar.len(m.items) - xar.len(m.unused_items) + return uint(n-1 if n > 0 else 0) +} + +@(require_results) +dynamic_cap :: proc "contextless" (m: $D/Dynamic_Handle_Map($T, $Handle_Type)) -> uint { + n := xar.cap(m.items) + return uint(n-1 if n > 0 else 0) +} + +dynamic_clear :: proc "contextless" (m: ^$D/Dynamic_Handle_Map($T, $Handle_Type)) { + xar.clear(&m.items) + xar.clear(&m.unused_items) +} + + +// An iterator for a handle map. +Dynamic_Handle_Map_Iterator :: struct($D: typeid) { + m: ^D, + index: int, +} + +// Makes an iterator from a handle map. +@(require_results) +dynamic_iterator_make :: proc "contextless" (m: ^$D/Dynamic_Handle_Map($T, $Handle_Type)) -> Dynamic_Handle_Map_Iterator(D) { + return {m, 1} +} + +/* + Iterate over a handle map. It will skip over unused item slots (e.g. handle.idx == 0). + Usage: + it := hm.dynamic_iterator_make(&the_dynamic_handle_map) + for item, handle in hm.iterate(&it) { + ... + } +*/ +@(require_results) +dynamic_iterate :: proc "contextless" (it: ^$DHI/Dynamic_Handle_Map_Iterator($D/Dynamic_Handle_Map($T, $Handle_Type))) -> (val: ^T, h: Handle_Type, ok: bool) { + for _ in it.index.. (handle: Handle_Type, ok: bool) #optional_ok { + if i := m.next_unused; i != 0 { + ptr := &m.items[i] + + m.next_unused = m.unused_items[i] + m.unused_items[i] = 0 + + prev_gen := ptr.handle.gen + ptr^ = item + + ptr.handle.idx = auto_cast i + ptr.handle.gen = auto_cast (prev_gen + 1) + m.unused_len -= 1 + return ptr.handle, true + } + + if m.used_len == 0 { + // initialize the zero-value sentinel + m.items[0] = {} + m.used_len += 1 + } + + if m.used_len == builtin.len(m.items) { + return {}, false + } + + ptr := &m.items[m.used_len] + ptr^ = item + + ptr.handle.idx = auto_cast m.used_len + ptr.handle.gen = 1 + m.used_len += 1 + return ptr.handle, true +} + +// `get` a stable pointer of type `^T` by resolving the handle `h`. If the handle is not valid, then `nil, false` is returned. +@(require_results) +static_get :: proc "contextless" (m: ^$H/Static_Handle_Map($N, $T, $Handle_Type), h: Handle_Type) -> (^T, bool) #optional_ok { + if h.idx <= 0 || u32(h.idx) >= m.used_len { + return nil, false + } + if e := &m.items[h.idx]; e.handle == h { + return e, true + } + return nil, false +} + +// `remove` an item from the handle map from the handle `h`. +static_remove :: proc "contextless" (m: ^$H/Static_Handle_Map($N, $T, $Handle_Type), h: Handle_Type) -> bool { + if h.idx <= 0 || u32(h.idx) >= m.used_len { + return false + } + + if item := &m.items[h.idx]; item.handle == h { + m.unused_items[h.idx] = m.next_unused + m.next_unused = u32(h.idx) + m.unused_len += 1 + item.handle.idx = 0 + return true + } + + return false +} + +// Returns true when the handle `h` is valid relating to the handle map. +@(require_results) +static_is_valid :: proc "contextless" (m: $H/Static_Handle_Map($N, $T, $Handle_Type), h: Handle_Type) -> bool { + return h.idx > 0 && u32(h.idx) < m.used_len && m.items[h.idx].handle == h +} + +// Returns the number of possibly valid items in the handle map. +@(require_results) +static_len :: proc "contextless" (m: $H/Static_Handle_Map($N, $T, $Handle_Type)) -> uint { + n := uint(m.used_len) - uint(m.unused_len) + return n-1 if n > 0 else 0 +} + +// Returns the capacity of the items in a handle map. +// This is equivalent to `N-1` as the zero value is reserved for the zero-value sentinel. +@(require_results) +static_cap :: proc "contextless" (m: $H/Static_Handle_Map($N, $T, $Handle_Type)) -> uint { + // We could just return `N` but I am doing this for clarity + return builtin.len(m.items)-1 +} + +// `clear` the handle map by zeroing all of the memory. +// Internally this does not do `m^ = {}` but rather uses `intrinsics.mem_zero` explicitly improve performance. +static_clear :: proc "contextless" (m: ^$H/Static_Handle_Map($N, $T, $Handle_Type)) { + intrinsics.mem_zero(m, size_of(m^)) +} + +// An iterator for a handle map. +Static_Handle_Map_Iterator :: struct($H: typeid) { + m: ^H, + index: u32, +} + +// Makes an iterator from a handle map. +@(require_results) +static_iterator_make :: proc "contextless" (m: ^$H/Static_Handle_Map($N, $T, $Handle_Type)) -> Static_Handle_Map_Iterator(H) { + return {m, 1} +} + +/* + Iterate over a handle map. It will skip over unused item slots (e.g. handle.idx == 0). + Usage: + it := hm.iterator_make(&the_handle_map) + for item, handle in hm.iterate(&it) { + ... + } +*/ +@(require_results) +static_iterate :: proc "contextless" (it: ^$HI/Static_Handle_Map_Iterator($H/Static_Handle_Map($N, $T, $Handle_Type))) -> (val: ^T, h: Handle_Type, ok: bool) { + for _ in it.index.. (err: runtime.Allocator_Error) + where intrinsics.type_has_field(T, link_field), + intrinsics.type_field_type(T, link_field) == ^T { + p.link_off = offset_of_by_string(T, link_field) + return _pool_arena_init(&p.arena, block_size) +} + +destroy :: proc(p: ^Pool($T)) { + elem := sync.atomic_exchange_explicit(&p.free_list, nil, .Acquire) + + sync.atomic_store_explicit(&p.num_ready, 0, .Relaxed) + + when .Address in ODIN_SANITIZER_FLAGS { + for ; elem != nil; elem = _get_next(p, elem) { + _unpoison_elem(p, elem) + } + } else { + _ = elem + } + + _pool_arena_destroy(&p.arena) + p.arena = {} +} + +@(require_results) +get :: proc(p: ^Pool($T)) -> (elem: ^T, err: runtime.Allocator_Error) #optional_allocator_error { + defer sync.atomic_add_explicit(&p.num_outstanding, 1, .Relaxed) + + for { + elem = sync.atomic_load_explicit(&p.free_list, .Acquire) + if elem == nil { + // NOTE: pool arena has an internal lock. + return new(T, _pool_arena_allocator(&p.arena)) + } + + if _, ok := sync.atomic_compare_exchange_weak_explicit(&p.free_list, elem, _get_next(p, elem), .Acquire, .Relaxed); ok { + _set_next(p, elem, nil) + _unpoison_elem(p, elem) + sync.atomic_sub_explicit(&p.num_ready, 1, .Relaxed) + return + } + } +} + +put :: proc(p: ^Pool($T), elem: ^T) { + intrinsics.mem_zero(elem, size_of(T)) + _poison_elem(p, elem) + + defer sync.atomic_sub_explicit(&p.num_outstanding, 1, .Relaxed) + defer sync.atomic_add_explicit(&p.num_ready, 1, .Relaxed) + + for { + head := sync.atomic_load_explicit(&p.free_list, .Relaxed) + _set_next(p, elem, head) + if _, ok := sync.atomic_compare_exchange_weak_explicit(&p.free_list, head, elem, .Release, .Relaxed); ok { + return + } + } +} + +num_outstanding :: proc(p: ^Pool($T)) -> int { + return sync.atomic_load(&p.num_outstanding) +} + +num_ready :: proc(p: ^Pool($T)) -> int { + return sync.atomic_load(&p.num_ready) +} + +cap :: proc(p: ^Pool($T)) -> int { + return sync.atomic_load(&p.num_ready) + sync.atomic_load(&p.num_outstanding) +} + +_get_next :: proc(p: ^Pool($T), elem: ^T) -> ^T { + return (^^T)(uintptr(elem) + p.link_off)^ +} + +_set_next :: proc(p: ^Pool($T), elem: ^T, next: ^T) { + (^^T)(uintptr(elem) + p.link_off)^ = next +} + +_poison_elem :: proc(p: ^Pool($T), elem: ^T) { + when .Address in ODIN_SANITIZER_FLAGS { + if p.link_off > 0 { + sanitizer.address_poison_rawptr(elem, int(p.link_off)) + } + + len := size_of(T) - p.link_off - size_of(rawptr) + if len > 0 { + ptr := rawptr(uintptr(elem) + p.link_off + size_of(rawptr)) + sanitizer.address_poison_rawptr(ptr, int(len)) + } + } +} + +_unpoison_elem :: proc(p: ^Pool($T), elem: ^T) { + when .Address in ODIN_SANITIZER_FLAGS { + if p.link_off > 0 { + sanitizer.address_unpoison_rawptr(elem, int(p.link_off)) + } + + len := size_of(T) - p.link_off - size_of(rawptr) + if len > 0 { + ptr := rawptr(uintptr(elem) + p.link_off + size_of(rawptr)) + sanitizer.address_unpoison_rawptr(ptr, int(len)) + } + } +} diff --git a/core/container/pool/pool_arena_others.odin b/core/container/pool/pool_arena_others.odin new file mode 100644 index 000000000..d2e01ffb7 --- /dev/null +++ b/core/container/pool/pool_arena_others.odin @@ -0,0 +1,27 @@ +#+build !darwin +#+build !freebsd +#+build !openbsd +#+build !netbsd +#+build !linux +#+build !windows +#+private +package container_pool + +import "base:runtime" + +_Pool_Arena :: runtime.Arena + +_DEFAULT_BLOCK_SIZE :: runtime.Megabyte + +_pool_arena_init :: proc(arena: ^Pool_Arena, block_size: uint = DEFAULT_BLOCK_SIZE) -> (err: runtime.Allocator_Error) { + runtime.arena_init(arena, block_size, runtime.default_allocator()) or_return + return +} + +_pool_arena_allocator :: proc(arena: ^Pool_Arena) -> runtime.Allocator { + return runtime.arena_allocator(arena) +} + +_pool_arena_destroy :: proc(arena: ^Pool_Arena) { + runtime.arena_destroy(arena) +} diff --git a/core/container/pool/pool_arena_virtual.odin b/core/container/pool/pool_arena_virtual.odin new file mode 100644 index 000000000..d622990fd --- /dev/null +++ b/core/container/pool/pool_arena_virtual.odin @@ -0,0 +1,22 @@ +#+build darwin, freebsd, openbsd, netbsd, linux, windows +package container_pool + +import "base:runtime" +import "core:mem/virtual" + +_Pool_Arena :: virtual.Arena + +_DEFAULT_BLOCK_SIZE :: runtime.Gigabyte + +_pool_arena_init :: proc(arena: ^Pool_Arena, block_size: uint = DEFAULT_BLOCK_SIZE) -> (err: runtime.Allocator_Error) { + virtual.arena_init_growing(arena, block_size) or_return + return +} + +_pool_arena_allocator :: proc(arena: ^Pool_Arena) -> runtime.Allocator { + return virtual.arena_allocator(arena) +} + +_pool_arena_destroy :: proc(arena: ^Pool_Arena) { + virtual.arena_destroy(arena) +} diff --git a/core/container/priority_queue/doc.odin b/core/container/priority_queue/doc.odin new file mode 100644 index 000000000..7779e6e0a --- /dev/null +++ b/core/container/priority_queue/doc.odin @@ -0,0 +1,53 @@ +/* +A priority queue data structure. + +Important: It needs to be initialized with `less` and `swap` procedures, see `init` and `init_from_dynamic_array`. + +Example: + import "base:runtime" + import pq "core:container/priority_queue" + + main :: proc() { + Printer_Job :: struct { + user_id: u64, + weight: enum u8 {Highest, High, Normal, Low, Idle}, + } + + q: pq.Priority_Queue(Printer_Job) + pq.init( + pq = &q, + less = proc(a, b: Printer_Job) -> bool { + // Jobs will be sorted in order of increasing weight + return a.weight < b.weight + }, + swap = pq.default_swap_proc(Printer_Job), + ) + defer pq.destroy(&q) + + // Add jobs with random weights + for _ in 0..<100 { + job: Printer_Job = --- + assert(runtime.random_generator_read_ptr(context.random_generator, &job, size_of(job))) + pq.push(&q, job) + } + + // Drain jobs in order of importance + last: Printer_Job + for pq.len(q) > 0 { + v := pq.pop(&q) + assert(v.weight >= last.weight) + last = v + } + + // Queue empty? + assert(pq.len(q) == 0) + + // Add one more job + pq.push(&q, Printer_Job{user_id = 42, weight = .Idle}) + + // Cancel all jobs + pq.clear(&q) + assert(pq.len(q) == 0) + } +*/ +package container_priority_queue \ No newline at end of file diff --git a/core/container/priority_queue/priority_queue.odin b/core/container/priority_queue/priority_queue.odin index c9ef807c5..c7e9f61dc 100644 --- a/core/container/priority_queue/priority_queue.odin +++ b/core/container/priority_queue/priority_queue.odin @@ -1,9 +1,12 @@ -// A priority queue data structure. package container_priority_queue import "base:builtin" import "base:runtime" +// Priority Queue. +// +// Important: It needs to be initialized with `less` and `swap` procedures, see `init` and `init_from_dynamic_array`. +// See `doc.odin` for an example. Priority_Queue :: struct($T: typeid) { queue: [dynamic]T, diff --git a/core/container/rbtree/rbtree.odin b/core/container/rbtree/rbtree.odin index 35ce21413..c138838df 100644 --- a/core/container/rbtree/rbtree.odin +++ b/core/container/rbtree/rbtree.odin @@ -91,24 +91,24 @@ destroy :: proc(t: ^$T/Tree($Key, $Value), call_on_remove: bool = true) { } } -len :: proc "contextless" (t: ^$T/Tree($Key, $Value)) -> (node_count: int) { +len :: proc "contextless" (t: $T/Tree($Key, $Value)) -> (node_count: int) { return t._size } -// first returns the first node in the tree (in-order) or nil iff +// first returns the first node in the tree (in-order) or nil if and only if (⟺) // the tree is empty. first :: proc "contextless" (t: ^$T/Tree($Key, $Value)) -> ^Node(Key, Value) { return tree_first_or_last_in_order(t, Direction.Backward) } -// last returns the last element in the tree (in-order) or nil iff +// last returns the last element in the tree (in-order) or nil if and only if (⟺) // the tree is empty. last :: proc "contextless" (t: ^$T/Tree($Key, $Value)) -> ^Node(Key, Value) { return tree_first_or_last_in_order(t, Direction.Forward) } -// find finds the key in the tree, and returns the corresponding node, or nil iff the value is not present. -find :: proc(t: ^$T/Tree($Key, $Value), key: Key) -> (node: ^Node(Key, Value)) { +// find finds the key in the tree, and returns the corresponding node, or nil if and only if (⟺) the value is not present. +find :: proc(t: $T/Tree($Key, $Value), key: Key) -> (node: ^Node(Key, Value)) { node = t._root for node != nil { switch t._cmp_fn(key, node.key) { @@ -120,8 +120,8 @@ find :: proc(t: ^$T/Tree($Key, $Value), key: Key) -> (node: ^Node(Key, Value)) { return node } -// find_value finds the key in the tree, and returns the corresponding value, or nil iff the value is not present. -find_value :: proc(t: ^$T/Tree($Key, $Value), key: Key) -> (value: Value, ok: bool) #optional_ok { +// find_value finds the key in the tree, and returns the corresponding value, or nil if and only if (⟺) the value is not present. +find_value :: proc(t: $T/Tree($Key, $Value), key: Key) -> (value: Value, ok: bool) #optional_ok { if n := find(t, key); n != nil { return n.value, true } @@ -154,7 +154,7 @@ find_or_insert :: proc(t: ^$T/Tree($Key, $Value), key: Key, value: Value) -> (n: return n, true, nil } -// remove removes a node or value from the tree, and returns true iff the +// remove removes a node or value from the tree, and returns true if and only if (⟺) the // removal was successful. While the node's value will be left intact, // the node itself will be freed via the tree's node allocator. remove :: proc { @@ -162,18 +162,18 @@ remove :: proc { remove_node, } -// remove_value removes a value from the tree, and returns true iff the +// remove_value removes a value from the tree, and returns true if and only if (⟺) the // removal was successful. While the node's key + value will be left intact, // the node itself will be freed via the tree's node allocator. remove_key :: proc(t: ^$T/Tree($Key, $Value), key: Key, call_on_remove := true) -> bool { - n := find(t, key) + n := find(t^, key) if n == nil { return false // Key not found, nothing to do } return remove_node(t, n, call_on_remove) } -// remove_node removes a node from the tree, and returns true iff the +// remove_node removes a node from the tree, and returns true if and only if (⟺) the // removal was successful. While the node's key + value will be left intact, // the node itself will be freed via the tree's node allocator. remove_node :: proc(t: ^$T/Tree($Key, $Value), node: ^$N/Node(Key, Value), call_on_remove := true) -> (found: bool) { @@ -235,14 +235,14 @@ iterator_from_pos :: proc "contextless" (t: ^$T/Tree($Key, $Value), pos: ^Node(K } // iterator_get returns the node currently pointed to by the iterator, -// or nil iff the node has been removed, the tree is empty, or the end +// or nil if and only if (⟺) the node has been removed, the tree is empty, or the end // of the tree has been reached. iterator_get :: proc "contextless" (it: ^$I/Iterator($Key, $Value)) -> ^Node(Key, Value) { return it._cur } // iterator_remove removes the node currently pointed to by the iterator, -// and returns true iff the removal was successful. Semantics are the +// and returns true if and only if (⟺) the removal was successful. Semantics are the // same as the Tree remove. iterator_remove :: proc(it: ^$I/Iterator($Key, $Value), call_on_remove: bool = true) -> bool { if it._cur == nil { @@ -258,7 +258,7 @@ iterator_remove :: proc(it: ^$I/Iterator($Key, $Value), call_on_remove: bool = t } // iterator_next advances the iterator and returns the (node, true) or -// or (nil, false) iff the end of the tree has been reached. +// or (nil, false) if and only if (⟺) the end of the tree has been reached. // // Note: The first call to iterator_next will return the first node instead // of advancing the iterator. diff --git a/core/container/small_array/doc.odin b/core/container/small_array/doc.odin index 21d000a10..5696ae58c 100644 --- a/core/container/small_array/doc.odin +++ b/core/container/small_array/doc.odin @@ -1,4 +1,6 @@ /* +Deprecation Notice: Prefer using `[dynamic; N]T` (fixed capacity dynamic arrays). + A dynamic array-like interface on a stack-allocated, fixed-size array. The `Small_Array` type is optimal for scenarios where you need diff --git a/core/container/small_array/small_array.odin b/core/container/small_array/small_array.odin index b1674566d..901ed419e 100644 --- a/core/container/small_array/small_array.odin +++ b/core/container/small_array/small_array.odin @@ -21,7 +21,7 @@ Example: } */ Small_Array :: struct($N: int, $T: typeid) where N >= 0 { - data: [N]T, + data: [N]T `fmt:",len"`, len: int, } @@ -386,7 +386,7 @@ Attempts to add the given element at the beginning. This operation assumes that the small-array is not empty. Note: Performing this operation will cause pointers obtained -through get_ptr(_save) to reference incorrect elements. +through get_ptr(_safe) to reference incorrect elements. **Inputs** - `a`: A pointer to the small-array @@ -466,7 +466,7 @@ Removes and returns the first element of the small-array. This operation assumes that the small-array is not empty. Note: Performing this operation will cause pointers obtained -through get_ptr(_save) to reference incorrect elements. +through get_ptr(_safe) to reference incorrect elements. **Inputs** - `a`: A pointer to the small-array @@ -542,7 +542,7 @@ Attempts to remove and return the first element of the small array. Unlike `pop_front`, it does not assume that the array is non-empty. Note: Performing this operation will cause pointers obtained -through get_ptr(_save) to reference incorrect elements. +through get_ptr(_safe) to reference incorrect elements. **Inputs** - `a`: A pointer to the small-array @@ -616,7 +616,7 @@ consume :: proc "odin" (a: ^$A/Small_Array($N, $T), count: int, loc := #caller_l Removes the element at the specified index while retaining order. Note: Performing this operation will cause pointers obtained -through get_ptr(_save) to reference incorrect elements. +through get_ptr(_safe) to reference incorrect elements. **Inputs** - `a`: A pointer to the small-array @@ -754,7 +754,7 @@ push_back_elems :: proc "contextless" (a: ^$A/Small_Array($N, $T), items: ..T) - Tries to insert an element at the specified position. Note: Performing this operation will cause pointers obtained -through get_ptr(_save) to reference incorrect elements. +through get_ptr(_safe) to reference incorrect elements. **Inputs** - `a`: A pointer to the small-array diff --git a/core/container/xar/freelist.odin b/core/container/xar/freelist.odin new file mode 100644 index 000000000..4b11014f5 --- /dev/null +++ b/core/container/xar/freelist.odin @@ -0,0 +1,157 @@ +package container_xar + +@(require) import "base:runtime" + +Freelist_Array :: struct($T: typeid, $SHIFT: uint) where + 0 < SHIFT, + SHIFT <= MAX_SHIFT, + size_of(T) >= size_of(^T) { + array: Array(T, SHIFT), + freelist: ^T, +} + +freelist_init :: proc(x: ^$X/Freelist_Array($T, $SHIFT), allocator := context.allocator) { + init(&x.array, allocator) + x.freelist = nil +} + +freelist_destroy :: proc(x: ^$X/Freelist_Array($T, $SHIFT)) { + destroy(&x.array) + x.freelist = nil +} + +freelist_clear :: proc(x: ^$X/Freelist_Array($T, $SHIFT)) { + clear(&x.array) + x.freelist = nil +} + +@(require_results) +freelist_push_with_index :: proc(x: ^$X/Freelist_Array($T, $SHIFT), value: T, loc := #caller_location) -> (ptr: ^T, index: int, err: runtime.Allocator_Error) { + if x.freelist != nil { + slot := x.freelist + idx, found := freelist_linear_search(x, slot) + assert(found) + x.freelist = (^^T)(slot)^ + slot^ = value + return slot, idx, nil + } + idx := x.array.len + ptr = array_push_back_elem_and_get_ptr(&x.array, value, loc) or_return + return ptr, idx, nil +} + +@(require_results) +freelist_push :: proc(x: ^$X/Freelist_Array($T, $SHIFT), value: T, loc := #caller_location) -> (ptr: ^T, err: runtime.Allocator_Error) { + ptr, _, err = freelist_push_with_index(x, value, loc) + return +} + +freelist_pop :: proc(x: ^$X/Freelist_Array($T, $SHIFT), #any_int index: int, loc := #caller_location) -> T { + item := array_get_ptr(&x.array, index, loc) + result := item^ + (^^T)(item)^ = x.freelist + x.freelist = item + return result +} + +freelist_release :: proc(x: ^$X/Freelist_Array($T, $SHIFT), #any_int index: int, loc := #caller_location) { + item := array_get_ptr(&x.array, index, loc) + (^^T)(item)^ = x.freelist + x.freelist = item +} + +@(require_results) +freelist_linear_search :: proc(x: ^$X/Freelist_Array($T, $SHIFT), ptr: ^T) -> (index: int, found: bool) { + base := 0 + for chunk, c in x.array.chunks { + if chunk == nil { + break + } + chunk_cap := 1 << (SHIFT + uint(c if c > 0 else 1) - 1) + ptr_addr := uintptr(ptr) + chunk_start_addr := uintptr(chunk) + chunk_end_addr := chunk_start_addr + uintptr(chunk_cap * size_of(T)) + if chunk_start_addr <= ptr_addr && ptr_addr < chunk_end_addr { + offset := int(ptr_addr - chunk_start_addr) / size_of(T) + return base + offset, true + } + base += chunk_cap + } + return -1, false +} + +@(require_results) +freelist_get :: proc(x: ^$X/Freelist_Array($T, $SHIFT), #any_int index: int, loc := #caller_location) -> T { + return array_get(&x.array, index, loc) +} + +@(require_results) +freelist_get_ptr :: proc(x: ^$X/Freelist_Array($T, $SHIFT), #any_int index: int, loc := #caller_location) -> ^T { + return array_get_ptr(&x.array, index, loc) +} + +freelist_set :: proc(x: ^$X/Freelist_Array($T, $SHIFT), #any_int index: int, value: T, loc := #caller_location) { + array_set(&x.array, index, value, loc) +} + +@(require_results) +freelist_len :: proc(x: $X/Freelist_Array($T, $SHIFT)) -> int { + return x.array.len +} + +@(require_results) +freelist_cap :: proc(x: $X/Freelist_Array($T, $SHIFT)) -> int { + return array_cap(x.array) +} + +@(require_results) +freelist_is_freed :: proc(x: ^$X/Freelist_Array($T, $SHIFT), #any_int index: int) -> bool { + ptr := array_get_ptr(&x.array, index) + current := x.freelist + for current != nil { + if current == ptr { + return true + } + current = (^^T)(current)^ + } + return false +} + +Freelist_Iterator :: struct($T: typeid, $SHIFT: uint) { + freelist_array: ^Freelist_Array(T, SHIFT), + idx: int, +} + +freelist_iterator :: proc(x: ^$X/Freelist_Array($T, $SHIFT)) -> Freelist_Iterator(T, SHIFT) { + return {freelist_array = x, idx = 0} +} + +@(require_results) +freelist_iterate_by_val :: proc(it: ^Freelist_Iterator($T, $SHIFT)) -> (val: T, idx: int, ok: bool) { + for it.idx < it.freelist_array.array.len { + if !freelist_is_freed(it.freelist_array, it.idx) { + val = array_get(&it.freelist_array.array, it.idx) + idx = it.idx + it.idx += 1 + return val, idx, true + } + it.idx += 1 + } + it.idx = 0 + return +} + +@(require_results) +freelist_iterate_by_ptr :: proc(it: ^Freelist_Iterator($T, $SHIFT)) -> (val: ^T, idx: int, ok: bool) { + for it.idx < it.freelist_array.array.len { + if !freelist_is_freed(it.freelist_array, it.idx) { + val = array_get_ptr(&it.freelist_array.array, it.idx) + idx = it.idx + it.idx += 1 + return val, idx, true + } + it.idx += 1 + } + it.idx = 0 + return +} diff --git a/core/container/xar/xar.odin b/core/container/xar/xar.odin new file mode 100644 index 000000000..08b2b2d32 --- /dev/null +++ b/core/container/xar/xar.odin @@ -0,0 +1,538 @@ +/* + Exponential Array (Xar). + + A dynamically growing array using exponentially-sized chunks, providing stable + memory addresses for all elements. Unlike `[dynamic]T`, elements are never + moved once allocated, making it safe to hold pointers to elements. + + For more information: https://azmr.uk/dyn/#exponential-arrayxar + + Example: + + import "core:container/xar" + + example :: proc() { + x: xar.Array(int, 4) + defer xar.destroy(&x) + + xar.push_back(&x, 10) + xar.push_back(&x, 20) + xar.push_back(&x, 30) + + ptr := xar.get_ptr(&x, 1) // ptr remains valid after more push_backs + xar.push_back(&x, 40) + fmt.println(ptr^) // prints 20 + } +*/ +package container_xar + +@(require) import "base:intrinsics" +@(require) import "base:runtime" + +PLATFORM_BITS :: 8*size_of(uint) +_LOG2_PLATFORM_BITS :: intrinsics.constant_log2(PLATFORM_BITS) + +MAX_SHIFT :: PLATFORM_BITS>>1 + +/* + An Exponential Array with stable element addresses. + + Unlike `[dynamic]T` which reallocates and moves elements when growing, `Array` + allocates separate chunks of exponentially increasing size. This guarantees + that pointers to elements remain valid for the lifetime of the container. + + Fields: + - `chunks`: Fixed array of multi-pointers to allocated chunks + - `len`: Number of elements currently stored + - `allocator`: Allocator used for chunk allocations + + Type Parameters: + - `T`: The element type + - `SHIFT`: Controls initial chunk size (1 << SHIFT). Must be in range (0, MAX_SHIFT]. + Larger values mean fewer, bigger chunks. Recommended: 4-8. + + Chunk sizes grow as: + - `chunks[0]`: 1 << SHIFT elements + - `chunks[1]`: 1 << SHIFT elements + - `chunks[2]`: 1 << (SHIFT + 1) elements + - `chunks[3]`: 1 << (SHIFT + 2) elements + - `chunks[4]`: 1 << (SHIFT + 3) elements + - ...and so on + + Example: + + import "core:container/xar" + + example :: proc() { + // Xar with initial chunk size of 16 (1 << 4) + x: xar.Array(My_Struct, 4) + defer xar.destroy(&x) + } +*/ +Array :: struct($T: typeid, $SHIFT: uint) where 0 < SHIFT, SHIFT <= MAX_SHIFT { + chunks: [(1 << (_LOG2_PLATFORM_BITS - intrinsics.constant_log2(SHIFT))) + 1][^]T, + len: int, + allocator: runtime.Allocator, +} + + +/* +Initializes an exponential array with the given allocator. + +**Inputs** +- `x`: Pointer to the exponential array to initialize +- `allocator`: Allocator to use for chunk allocations (defaults to context.allocator) +*/ +array_init :: proc(x: ^$X/Array($T, $SHIFT), allocator := context.allocator) { + x^ = {allocator = allocator} +} + +/* +Frees all allocated chunks and resets the exponential array. + +**Inputs** +- `x`: Pointer to the exponential array to destroy +*/ +array_destroy :: proc(x: ^$X/Array($T, $SHIFT)) { + #reverse for c, i in x.chunks { + if c != nil { + n := 1 << (SHIFT + uint(i if i > 0 else 1) - 1) + size_in_bytes := n * size_of(T) + runtime.mem_free_with_size(c, size_in_bytes, x.allocator) + } + } + x^ = {} +} + +/* +Resets the array's length to zero without freeing memory. +Allocated chunks are retained for reuse. +*/ +array_clear :: proc "contextless" (x: ^$X/Array($T, $SHIFT)) { + x.len = 0 +} + +// Returns the length of the exponential-array +@(require_results) +array_len :: proc "contextless" (x: $X/Array($T, $SHIFT)) -> int { + return x.len +} + +// Returns the number of allocated elements +@(require_results) +array_cap :: proc "contextless" (x: $X/Array($T, $SHIFT)) -> int { + #reverse for c, i in x.chunks { + if c != nil { + return 1 << (SHIFT + uint(i if i > 0 else 1)) + } + } + return 0 +} + +// Internal: computes chunk index, element index within chunk, and chunk capacity for a given index. +@(require_results) +_meta_get :: #force_inline proc "contextless" ($SHIFT: uint, index: uint) -> (chunk_idx, elem_idx, chunk_cap: uint) { + elem_idx = index + chunk_cap = uint(1) << SHIFT + chunk_idx = 0 + + index_shift := index >> SHIFT + if index_shift > 0 { + N :: 8*size_of(uint)-1 + CLZ :: intrinsics.count_leading_zeros + chunk_idx = N-CLZ(index_shift) // MSB(index_shift) + + chunk_cap = 1 << (chunk_idx + SHIFT) + elem_idx -= chunk_cap + chunk_idx += 1 + } + + return +} +/* +Get a copy of the element at the specified index. + +**Inputs** +- `x`: Pointer to the exponential array +- `index`: Position of the element (0-indexed) + +**Returns** +- a copy of the element +*/ +@(require_results) +array_get :: proc(x: ^$X/Array($T, $SHIFT), #any_int index: int, loc := #caller_location) -> (val: T) #no_bounds_check { + runtime.bounds_check_error_loc(loc, index, x.len) + chunk_idx, elem_idx, _ := _meta_get(SHIFT, uint(index)) + return x.chunks[chunk_idx][elem_idx] +} + +/* +Get a pointer to the element at the specified index. + +The returned pointer remains valid even after additional elements are added, +as long as the element is not removed and the array is not destroyed. + +**Inputs** +- `x`: Pointer to the exponential array +- `index`: Position of the element (0-indexed) + +**Returns** +- a stable pointer to the element + +Example: + + import "core:container/xar" + + get_ptr_example :: proc() { + x: xar.Array(int, 4) + defer xar.destroy(&x) + + xar.push_back(&x, 100) + ptr := xar.get_ptr(&x, 0) + + // Pointer remains valid after growing + for i in 0..<1000 { + xar.push_back(&x, i) + } + + fmt.println(ptr^) // Still prints 100 + } +*/ +@(require_results) +array_get_ptr :: proc(x: ^$X/Array($T, $SHIFT), #any_int index: int, loc := #caller_location) -> (val: ^T) #no_bounds_check { + runtime.bounds_check_error_loc(loc, index, x.len) + chunk_idx, elem_idx, _ := _meta_get(SHIFT, uint(index)) + return &x.chunks[chunk_idx][elem_idx] +} + +// No bounds checking +@(require_results) +array_get_ptr_unsafe :: proc "contextless" (x: ^$X/Array($T, $SHIFT), #any_int index: int) -> (val: ^T) #no_bounds_check { + chunk_idx, elem_idx, _ := _meta_get(SHIFT, uint(index)) + return &x.chunks[chunk_idx][elem_idx] +} + +/* +Set the element at the specified index to the given value. + +**Inputs** +- `x`: Pointer to the exponential array +- `index`: Position of the element (0-indexed) +- `value`: The value to set +*/ +array_set :: proc(x: ^$X/Array($T, $SHIFT), #any_int index: int, value: T, loc := #caller_location) #no_bounds_check { + runtime.bounds_check_error_loc(loc, index, x.len) + chunk_idx, elem_idx, _ := _meta_get(SHIFT, uint(index)) + x.chunks[chunk_idx][elem_idx] = value +} + +array_append :: proc{array_push_back_elem, array_push_back_elems} +array_push_back :: proc{array_push_back_elem, array_push_back_elems} + + +/* +Append an element to the end of the exponential array. +Allocates a new chunk if necessary. Existing elements aren't moved, and their pointers remain stable. + +**Inputs** +- `x`: Pointer to the exponential array +- `value`: The element to append + +**Returns** +- number of elements added (always 1 on success) +- allocation error if chunk allocation failed + +Example: + + import "core:container/xar" + + push_back_example :: proc() { + x: xar.Array(string, 4) + defer xar.destroy(&x) + + xar.push_back(&x, "hello") + xar.push_back(&x, "world") + + fmt.println(xar.get(&x, 0)) // hello + fmt.println(xar.get(&x, 1)) // world + } +*/ +array_push_back_elem :: proc(x: ^$X/Array($T, $SHIFT), value: T, loc := #caller_location) -> (n: int, err: runtime.Allocator_Error) { + if x.allocator.procedure == nil { + // to minic `[dynamic]T` behaviour + x.allocator = context.allocator + } + + chunk_idx, elem_idx, chunk_cap := _meta_get(SHIFT, uint(x.len)) + if x.chunks[chunk_idx] == nil { + x.chunks[chunk_idx] = make([^]T, chunk_cap, x.allocator) or_return + } + x.chunks[chunk_idx][elem_idx] = value + x.len += 1 + n = 1 + return +} + +/* +Append multiple elements to the end of the exponential array. + +**Inputs** +- `x`: Pointer to the exponential array +- `values`: The elements to append + +**Returns** +- number of elements successfully added +- allocation error if chunk allocation failed (partial append possible) +*/ +array_push_back_elems :: proc(x: ^$X/Array($T, $SHIFT), values: ..T, loc := #caller_location) -> (n: int, err: runtime.Allocator_Error) { + for value in values { + n += array_push_back_elem(x, value, loc) or_return + } + return +} + +array_append_and_get_ptr :: array_push_back_elem_and_get_ptr +append_and_get_ptr :: array_push_back_elem_and_get_ptr + +/* +Append an element and return a stable pointer to it. +This is useful when you need to initialize a complex struct in-place or +retain a reference to the newly added element. + +**Inputs** +- `x`: Pointer to the exponential array +- `value`: The element to append + +**Returns** +- a stable pointer to the newly added element +- allocation error if chunk allocation failed + +Example: + + import "core:container/xar" + + push_back_and_get_ptr_example :: proc() { + x: xar.Array(My_Struct, 4) + defer xar.destroy(&x) + + ptr := xar.push_back_elem_and_get_ptr(&x, My_Struct{}) or_else panic("alloc failed") + ptr.field = 42 // Initialize in-place + } +*/ +@(require_results) +array_push_back_elem_and_get_ptr :: proc(x: ^$X/Array($T, $SHIFT), value: T, loc := #caller_location) -> (ptr: ^T, err: runtime.Allocator_Error) { + if x.allocator.procedure == nil { + // to minic `[dynamic]T` behaviour + x.allocator = context.allocator + } + + chunk_idx, elem_idx, chunk_cap := _meta_get(SHIFT, uint(x.len)) + if x.chunks[chunk_idx] == nil { + x.chunks[chunk_idx] = make([^]T, chunk_cap, x.allocator) or_return + } + x.chunks[chunk_idx][elem_idx] = value + x.len += 1 + ptr = &x.chunks[chunk_idx][elem_idx] + return +} + +// `pop` will remove and return the end value of an exponential array `x` and reduces the length of the array by 1. +// +// Note: If the exponential array has no elements (`xar.len(x) == 0`), this procedure will panic. +array_pop :: proc(x: ^$X/Array($T, $SHIFT), loc := #caller_location) -> (val: T) { + assert(x.len > 0, loc=loc) + index := uint(x.len-1) + chunk_idx, elem_idx, _ := _meta_get(SHIFT, index) + x.len -= 1 + return x.chunks[chunk_idx][elem_idx] +} + +// `pop_safe` trys to remove and return the end value of dynamic array `x` and reduces the length of the array by 1. +// If the operation is not possible, it will return false. +@(require_results) +array_pop_safe :: proc(x: ^$X/Array($T, $SHIFT)) -> (val: T, ok: bool) { + if x.len == 0 { + return + } + index := uint(x.len-1) + chunk_idx, elem_idx, _ := _meta_get(SHIFT, index) + x.len -= 1 + + val = x.chunks[chunk_idx][elem_idx] + ok = true + return +} + +/* + `unordered_remove` removed the element at the specified `index`. It does so by replacing the current end value + with the old value, and reducing the length of the exponential array by 1. + + Note: This is an O(1) operation. + Note: This is currently no procedure that is the equivalent of an "ordered_remove" + Note: If the index is out of bounds, this procedure will panic. + + Note: Pointers to the last element become invalid (it gets moved). Pointers to other elements remain valid. + + Example: + + import "core:encoding/xar" + + unordered_remove_example :: proc() { + x: xar.Array(int, 4) + defer xar.destroy(&x) + + xar.push_back(&x, 10) + xar.push_back(&x, 20) + xar.push_back(&x, 30) + + xar.unordered_remove(&x, 0) // Removes 10, replaces with 30 + + // Array now contains [30, 20] + fmt.println(xar.get(&x, 0)) // 30 + fmt.println(xar.get(&x, 1)) // 20 + } +*/ +array_unordered_remove :: proc(x: ^$X/Array($T, $SHIFT), #any_int index: int, loc := #caller_location) { + runtime.bounds_check_error_loc(loc, index, x.len) + n := x.len-1 + if index != n { + end := array_get(x, n) + array_set(x, index, end) + } + x.len -= 1 +} + +@(require_results) +array_linear_search :: proc(x: ^$X/Array($T, $SHIFT), elem: T) -> (index: int, found: bool) where intrinsics.type_is_comparable(T) { + it := array_iterator(x) + for val, i in array_iterate_by_val(it) { + if val == elem { + return i, true + } + } + return -1, false +} + + +/* +Iterator state for traversing a `Xar`. + +Fields: +- `xar`: Pointer to the exponential array being iterated +- `idx`: Current iteration index +*/ +Array_Iterator :: struct($T: typeid, $SHIFT: uint) { + xar: ^Array(T, SHIFT), + idx: int, +} + +/* +Create an iterator for traversing the exponential array. + +**Inputs** +- `xar`: Pointer to the exponential array + +**Returns** +- an iterator positioned at the start + +Example: + + import "core:container/xar" + import "core:fmt" + + iterator_example :: proc() { + x: xar.Array(int, 4) + defer xar.destroy(&x) + + xar.push_back(&x, 10) + xar.push_back(&x, 20) + xar.push_back(&x, 30) + + it := xar.iterator(&x) + for val in xar.iterate_by_ptr(&it) { + fmt.println(val^) + } + } + +Output: + + 10 + 20 + 30 +*/ +array_iterator :: proc(xar: ^$X/Array($T, $SHIFT)) -> Array_Iterator(T, SHIFT) { + return {xar = auto_cast xar, idx = 0} +} + +/* +Advance the iterator and returns the next element. + +**Inputs** +- `it`: Pointer to the iterator + +**Returns** +- current element +- `true` if an element was returned, `false` if iteration is complete +*/ +array_iterate_by_val :: proc(it: ^Array_Iterator($T, $SHIFT)) -> (val: T, idx: int, ok: bool) { + if it.idx >= it.xar.len { + it.idx = 0 + return + } + val = array_get(it.xar, it.idx) + idx = it.idx + it.idx += 1 + return val, idx, true +} + + +/* +Advance the iterator and returns a pointer to the next element. + +**Inputs** +- `it`: Pointer to the iterator + +**Returns** +- pointer to the current element +- `true` if an element was returned, `false` if iteration is complete +*/ +array_iterate_by_ptr :: proc(it: ^Array_Iterator($T, $SHIFT)) -> (val: ^T, idx: int, ok: bool) { + if it.idx >= it.xar.len { + it.idx = 0 + return + } + val = array_get_ptr(it.xar, it.idx) + idx = it.idx + it.idx += 1 + return val, idx, true +} + + + + +init :: proc{array_init, freelist_init} +destroy :: proc{array_destroy, freelist_destroy} +clear :: proc{array_clear, freelist_clear} +len :: proc{array_len, freelist_len} +cap :: proc{array_cap, freelist_cap} +get :: proc{array_get, freelist_get} +get_ptr_unsafe :: proc{array_get_ptr_unsafe} +get_ptr :: proc{array_get_ptr, freelist_get_ptr} +set :: proc{array_set, freelist_set} +append :: proc{array_push_back_elem, array_push_back_elems} +push_back :: proc{array_push_back_elem, array_push_back_elems} +push_back_elem :: proc{array_push_back_elem} +push_back_elems :: proc{array_push_back_elems} +push_back_elem_and_get_ptr:: proc{array_push_back_elem_and_get_ptr} +pop :: proc{array_pop, freelist_pop} +pop_safe :: proc{array_pop_safe} +unordered_remove :: proc{array_unordered_remove} +iterator :: proc{array_iterator, freelist_iterator} +iterate_by_val :: proc{array_iterate_by_val, freelist_iterate_by_val} +iterate_by_ptr :: proc{array_iterate_by_ptr, freelist_iterate_by_ptr} + +push_with_index :: proc{freelist_push_with_index} +push :: proc{freelist_push} +release :: proc{freelist_release} +linear_search :: proc{array_linear_search, freelist_linear_search} +is_freed :: proc{freelist_is_freed} \ No newline at end of file diff --git a/core/crypto/_aes/ct64/api.odin b/core/crypto/_aes/ct64/api.odin index f57a630b1..08acd37ed 100644 --- a/core/crypto/_aes/ct64/api.odin +++ b/core/crypto/_aes/ct64/api.odin @@ -1,7 +1,6 @@ package aes_ct64 -import "base:intrinsics" -import "core:mem" +import "core:crypto" STRIDE :: 4 @@ -82,5 +81,5 @@ decrypt_blocks :: proc(ctx: ^Context, dst, src: [][]byte) { // reset sanitizes the Context. The Context must be re-initialized to // be used again. reset :: proc(ctx: ^Context) { - mem.zero_explicit(ctx, size_of(ctx)) -} + crypto.zero_explicit(ctx, size_of(ctx)) +} \ No newline at end of file diff --git a/core/crypto/_aes/ct64/ct64_dec.odin b/core/crypto/_aes/ct64/ct64_dec.odin index 408ee6002..6fca7a5f2 100644 --- a/core/crypto/_aes/ct64/ct64_dec.odin +++ b/core/crypto/_aes/ct64/ct64_dec.odin @@ -22,8 +22,6 @@ package aes_ct64 -import "base:intrinsics" - inv_sub_bytes :: proc "contextless" (q: ^[8]u64) { // AES S-box is: // S(x) = A(I(x)) ^ 0x63 diff --git a/core/crypto/_aes/ct64/ct64_keysched.odin b/core/crypto/_aes/ct64/ct64_keysched.odin index 0f00bba57..d0004dd5a 100644 --- a/core/crypto/_aes/ct64/ct64_keysched.odin +++ b/core/crypto/_aes/ct64/ct64_keysched.odin @@ -22,9 +22,9 @@ package aes_ct64 +import "core:crypto" import "core:crypto/_aes" import "core:encoding/endian" -import "core:mem" @(private, require_results) sub_word :: proc "contextless" (x: u32) -> u32 { @@ -35,7 +35,7 @@ sub_word :: proc "contextless" (x: u32) -> u32 { orthogonalize(&q) ret := u32(q[0]) - mem.zero_explicit(&q[0], size_of(u64)) + crypto.zero_explicit(&q[0], size_of(u64)) return ret } @@ -97,8 +97,8 @@ keysched :: proc "contextless" (comp_skey: []u64, key: []byte) -> int { (q[7] & 0x8888888888888888) } - mem.zero_explicit(&skey, size_of(skey)) - mem.zero_explicit(&q, size_of(q)) + crypto.zero_explicit(&skey, size_of(skey)) + crypto.zero_explicit(&q, size_of(q)) return num_rounds } diff --git a/core/crypto/_aes/hw/api.odin b/core/crypto/_aes/hw/api.odin new file mode 100644 index 000000000..09f674657 --- /dev/null +++ b/core/crypto/_aes/hw/api.odin @@ -0,0 +1,69 @@ +package aes_hw + +@(require) import "core:sys/info" + +// is_supported returns true if and only if (⟺) hardware accelerated AES +// is supported. +is_supported :: proc "contextless" () -> bool { + when ODIN_ARCH == .amd64 { + // Note: Everything with AES-NI has support for + // the required SSE extxtensions. + req_features :: info.CPU_Features{ + .sse2, + .ssse3, + .sse41, + .aes, + } + return info.cpu_features() >= req_features + } else when ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32 { + req_features :: info.CPU_Features{ + .asimd, + .aes, + } + return info.cpu_features() >= req_features + } else { + return false + } +} + +// is_ghash_supported returns true if and only if (⟺) hardware accelerated +// GHASH is supported. +is_ghash_supported :: proc "contextless" () -> bool { + // Just having hardware GHASH is silly. + if !is_supported() { + return false + } + + when ODIN_ARCH == .amd64 { + return info.cpu_features() >= info.CPU_Features{ + .pclmulqdq, + } + } else when ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32{ + // Once we can actually use this, we can re-enable this. + // + // return info.cpu_features() >= info.CPU_Features{ + // .pmull, + // } + return false + } else { + return false + } +} + +// Context is a keyed AES (ECB) instance. +Context :: struct { + // Note: The ideal thing to do is for the expanded round keys to be + // arrays of `u8x16`, however that implies alignment (or using AVX). + // + // All the people using e-waste processors that don't support an + // instruction set that has been around for over 10 years are why + // we can't have nice things. + _sk_exp_enc: [15][16]byte, + _sk_exp_dec: [15][16]byte, + _num_rounds: int, +} + +// init initializes a context for AES with the provided key. +init :: proc(ctx: ^Context, key: []byte) { + keysched(ctx, key) +} diff --git a/core/crypto/_aes/hw_intel/ghash.odin b/core/crypto/_aes/hw/ghash_intel.odin similarity index 99% rename from core/crypto/_aes/hw_intel/ghash.odin rename to core/crypto/_aes/hw/ghash_intel.odin index 5f51b614b..d80816d5d 100644 --- a/core/crypto/_aes/hw_intel/ghash.odin +++ b/core/crypto/_aes/hw/ghash_intel.odin @@ -21,7 +21,7 @@ // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #+build amd64 -package aes_hw_intel +package aes_hw import "base:intrinsics" import "core:crypto/_aes" diff --git a/core/crypto/_aes/hw/intrinsics_arm.odin b/core/crypto/_aes/hw/intrinsics_arm.odin new file mode 100644 index 000000000..ccd8efa8f --- /dev/null +++ b/core/crypto/_aes/hw/intrinsics_arm.odin @@ -0,0 +1,115 @@ +#+build arm64,arm32 +package aes_hw + +import "core:simd" +import "core:simd/arm" + +// https://blog.michaelbrase.com/2018/05/08/emulating-x86-aes-intrinsics-on-armv8-a/ + +TARGET_FEATURES :: "neon,aes" +HAS_GHASH :: false // Temporary + +@(require_results, enable_target_feature = "aes") +aesdec :: #force_inline proc "c" (data, key: simd.u8x16) -> simd.u8x16 { + return simd.bit_xor(arm.vaesimcq_u8(arm.vaesdq_u8(data, simd.u8x16{})), key) +} + +@(require_results, enable_target_feature = "aes") +aesdeclast :: #force_inline proc "c" (data, key: simd.u8x16) -> simd.u8x16 { + return simd.bit_xor(arm.vaesdq_u8(data, simd.u8x16{}), key) +} + +@(require_results, enable_target_feature = "aes") +aesenc :: #force_inline proc "c" (data, key: simd.u8x16) -> simd.u8x16 { + return simd.bit_xor(arm.vaesmcq_u8(arm.vaeseq_u8(data, simd.u8x16{})), key) +} + +@(require_results, enable_target_feature = "aes") +aesenclast :: #force_inline proc "c" (data, key: simd.u8x16) -> simd.u8x16 { + return simd.bit_xor(arm.vaeseq_u8(data, simd.u8x16{}), key) +} + +aesimc :: arm.vaesimcq_u8 + +@(require_results, enable_target_feature = "aes") +aeskeygenassist :: #force_inline proc "c" (data: simd.u8x16, $IMM8: u8) -> simd.u8x16 { + a := arm.vaeseq_u8(data, simd.u8x16{}) // AESE does ShiftRows and SubBytes on A + + // Undo ShiftRows step from AESE and extract X1 and X3 + dest := simd.swizzle( + a, + 0x04, 0x01, 0x0e, 0x0b, // SubBytes(X1) + 0x01, 0x0e, 0x0b, 0x04, // ROT(SubBytes(X1)) + 0x0c, 0x09, 0x06, 0x03, // SubBytes(X3) + 0x09, 0x06, 0x03, 0x0c, // ROT(SubBytes(X3)) + ) + + rcons := simd.u8x16{ + 0, 0, 0, 0, + IMM8, 0, 0, 0, + 0, 0, 0, 0, + IMM8, 0, 0, 0, + } + + return simd.bit_xor(dest, rcons) +} + +// The keyschedule implementation is easier to read with some extra +// Intel intrinsics that are emulated by built-in LLVM ops anyway. + +@(private, require_results, enable_target_feature = TARGET_FEATURES) +_mm_slli_si128 :: #force_inline proc "c" (a: simd.u8x16, $IMM8: u32) -> simd.u8x16 { + shift :: IMM8 & 0xff + + // This needs to emit behavior identical to PSLLDQ which is as follows: + // + // TEMP := COUNT + // IF (TEMP > 15) THEN TEMP := 16; FI + // DEST := DEST << (TEMP * 8) + // DEST[MAXVL-1:128] (Unmodified) + + return simd.shuffle( + simd.u8x16{}, + a, + 0 when shift > 15 else (16 - shift + 0), + 1 when shift > 15 else (16 - shift + 1), + 2 when shift > 15 else (16 - shift + 2), + 3 when shift > 15 else (16 - shift + 3), + 4 when shift > 15 else (16 - shift + 4), + 5 when shift > 15 else (16 - shift + 5), + 6 when shift > 15 else (16 - shift + 6), + 7 when shift > 15 else (16 - shift + 7), + 8 when shift > 15 else (16 - shift + 8), + 9 when shift > 15 else (16 - shift + 9), + 10 when shift > 15 else (16 - shift + 10), + 11 when shift > 15 else (16 - shift + 11), + 12 when shift > 15 else (16 - shift + 12), + 13 when shift > 15 else (16 - shift + 13), + 14 when shift > 15 else (16 - shift + 14), + 15 when shift > 15 else (16 - shift + 15), + ) +} + +@(private, require_results, enable_target_feature = TARGET_FEATURES) +_mm_shuffle_epi32 :: #force_inline proc "c" (a: simd.u8x16, $IMM8: u32) -> simd.u8x16 { + v := transmute(simd.i32x4)a + return transmute(simd.u8x16)simd.shuffle( + v, + v, + IMM8 & 0b11, + (IMM8 >> 2) & 0b11, + (IMM8 >> 4) & 0b11, + (IMM8 >> 6) & 0b11, + ) +} + +@(private, require_results, enable_target_feature = TARGET_FEATURES) +_mm_shuffle_ps :: #force_inline proc "c" (a, b: simd.u8x16, $MASK: u32) -> simd.u8x16 { + return transmute(simd.u8x16)simd.shuffle( + transmute(simd.u32x4)(a), + transmute(simd.u32x4)(b), + u32(MASK) & 0b11, + (u32(MASK)>>2) & 0b11, + ((u32(MASK)>>4) & 0b11)+4, + ((u32(MASK)>>6) & 0b11)+4) +} diff --git a/core/crypto/_aes/hw/intrinsics_intel.odin b/core/crypto/_aes/hw/intrinsics_intel.odin new file mode 100644 index 000000000..25399dfae --- /dev/null +++ b/core/crypto/_aes/hw/intrinsics_intel.odin @@ -0,0 +1,55 @@ +#+build amd64 +package aes_hw + +import "core:simd" +import "core:simd/x86" + +// Intel/RISC-V semantics. + +TARGET_FEATURES :: "sse,sse2,ssse3,sse4.1,aes" +HAS_GHASH :: true + +@(require_results, enable_target_feature = "aes") +aesdec :: #force_inline proc "c" (data, key: simd.u8x16) -> simd.u8x16 { + return transmute(simd.u8x16)(x86._mm_aesdec_si128(transmute(x86.__m128i)(data), transmute(x86.__m128i)(key))) +} + +@(require_results, enable_target_feature = "aes") +aesdeclast :: #force_inline proc "c" (data, key: simd.u8x16) -> simd.u8x16 { + return transmute(simd.u8x16)(x86._mm_aesdeclast_si128(transmute(x86.__m128i)(data), transmute(x86.__m128i)(key))) +} + +@(require_results, enable_target_feature = "aes") +aesenc :: #force_inline proc "c" (data, key: simd.u8x16) -> simd.u8x16 { + return transmute(simd.u8x16)(x86._mm_aesenc_si128(transmute(x86.__m128i)(data), transmute(x86.__m128i)(key))) +} + +@(require_results, enable_target_feature = "aes") +aesenclast :: #force_inline proc "c" (data, key: simd.u8x16) -> simd.u8x16 { + return transmute(simd.u8x16)(x86._mm_aesenclast_si128(transmute(x86.__m128i)(data), transmute(x86.__m128i)(key))) +} + +@(require_results, enable_target_feature = "aes") +aesimc :: #force_inline proc "c" (data: simd.u8x16) -> simd.u8x16 { + return transmute(simd.u8x16)(x86._mm_aesimc_si128(transmute(x86.__m128i)(data))) +} + +@(require_results, enable_target_feature = "aes") +aeskeygenassist :: #force_inline proc "c" (data: simd.u8x16, $IMM8: u8) -> simd.u8x16 { + return transmute(simd.u8x16)(x86._mm_aeskeygenassist_si128(transmute(x86.__m128i)(data), IMM8)) +} + +@(private, require_results, enable_target_feature = TARGET_FEATURES) +_mm_slli_si128 :: #force_inline proc "c" (a: simd.u8x16, $IMM8: u32) -> simd.u8x16 { + return transmute(simd.u8x16)(x86._mm_slli_si128(transmute(x86.__m128i)(a), IMM8)) +} + +@(private, require_results, enable_target_feature = TARGET_FEATURES) +_mm_shuffle_epi32 :: #force_inline proc "c" (a: simd.u8x16, $IMM8: u32) -> simd.u8x16 { + return transmute(simd.u8x16)(x86._mm_shuffle_epi32(transmute(x86.__m128i)(a), IMM8)) +} + +@(private, require_results, enable_target_feature = TARGET_FEATURES) +_mm_shuffle_ps :: #force_inline proc "c" (a, b: simd.u8x16, $MASK: u32) -> simd.u8x16 { + return transmute(simd.u8x16)(x86._mm_shuffle_ps(transmute(x86.__m128)(a), transmute(x86.__m128)(b), MASK)) +} diff --git a/core/crypto/_aes/hw/keysched_hw.odin b/core/crypto/_aes/hw/keysched_hw.odin new file mode 100644 index 000000000..7d85c43b7 --- /dev/null +++ b/core/crypto/_aes/hw/keysched_hw.odin @@ -0,0 +1,181 @@ +// Copyright (c) 2017 Thomas Pornin +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “AS IS” AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#+build amd64,arm64,arm32 +package aes_hw + +import "base:intrinsics" +import "core:crypto" +import "core:crypto/_aes" +import "core:simd" + +// Inspiration taken from BearSSL's AES-NI implementation. +// +// Note: This assumes that the SROA optimization pass is enabled to be +// anything resembling performant otherwise, LLVM will not elide a massive +// number of redundant loads/stores it generates for every intrinsic call. + +@(private = "file", require_results, enable_target_feature = TARGET_FEATURES) +expand_step128 :: #force_inline proc(k1, k2: simd.u8x16) -> simd.u8x16 { + k1, k2 := k1, k2 + + k2 = _mm_shuffle_epi32(k2, 0xff) + k1 = simd.bit_xor(k1, _mm_slli_si128(k1, 0x04)) + k1 = simd.bit_xor(k1, _mm_slli_si128(k1, 0x04)) + k1 = simd.bit_xor(k1, _mm_slli_si128(k1, 0x04)) + return simd.bit_xor(k1, k2) +} + +@(private = "file", require_results, enable_target_feature = TARGET_FEATURES) +expand_step192a :: #force_inline proc (k1_, k2_: ^simd.u8x16, k3: simd.u8x16) -> (simd.u8x16, simd.u8x16) { + k1, k2, k3 := k1_^, k2_^, k3 + + k3 = _mm_shuffle_epi32(k3, 0x55) + k1 = simd.bit_xor(k1, _mm_slli_si128(k1, 0x04)) + k1 = simd.bit_xor(k1, _mm_slli_si128(k1, 0x04)) + k1 = simd.bit_xor(k1, _mm_slli_si128(k1, 0x04)) + k1 = simd.bit_xor(k1, k3) + + tmp := k2 + k2 = simd.bit_xor(k2, _mm_slli_si128(k2, 0x04)) + k2 = simd.bit_xor(k2, _mm_shuffle_epi32(k1, 0xff)) + + k1_, k2_ := k1_, k2_ + k1_^, k2_^ = k1, k2 + + r1 := _mm_shuffle_ps(tmp, k1, 0x44) + r2 := _mm_shuffle_ps(k1, k2, 0x4e) + + return r1, r2 +} + +@(private = "file", require_results, enable_target_feature = TARGET_FEATURES) +expand_step192b :: #force_inline proc (k1_, k2_: ^simd.u8x16, k3: simd.u8x16) -> simd.u8x16 { + k1, k2, k3 := k1_^, k2_^, k3 + + k3 = _mm_shuffle_epi32(k3, 0x55) + k1 = simd.bit_xor(k1, _mm_slli_si128(k1, 0x04)) + k1 = simd.bit_xor(k1, _mm_slli_si128(k1, 0x04)) + k1 = simd.bit_xor(k1, _mm_slli_si128(k1, 0x04)) + k1 = simd.bit_xor(k1, k3) + + k2 = simd.bit_xor(k2, _mm_slli_si128(k2, 0x04)) + k2 = simd.bit_xor(k2, _mm_shuffle_epi32(k1, 0xff)) + + k1_, k2_ := k1_, k2_ + k1_^, k2_^ = k1, k2 + + return k1 +} + +@(private = "file", require_results, enable_target_feature = TARGET_FEATURES) +expand_step256b :: #force_inline proc(k1, k2: simd.u8x16) -> simd.u8x16 { + k1, k2 := k1, k2 + + k2 = _mm_shuffle_epi32(k2, 0xaa) + k1 = simd.bit_xor(k1, _mm_slli_si128(k1, 0x04)) + k1 = simd.bit_xor(k1, _mm_slli_si128(k1, 0x04)) + k1 = simd.bit_xor(k1, _mm_slli_si128(k1, 0x04)) + return simd.bit_xor(k1, k2) +} + +@(private = "file", enable_target_feature = TARGET_FEATURES) +derive_dec_keys :: proc(ctx: ^Context, sks: ^[15]simd.u8x16, num_rounds: int) { + intrinsics.unaligned_store((^simd.u8x16)(&ctx._sk_exp_dec[0]), sks[num_rounds]) + for i in 1 ..< num_rounds { + tmp := aesimc(sks[i]) + intrinsics.unaligned_store((^simd.u8x16)(&ctx._sk_exp_dec[num_rounds - i]), tmp) + } + intrinsics.unaligned_store((^simd.u8x16)(&ctx._sk_exp_dec[num_rounds]), sks[0]) +} + +@(private, enable_target_feature = TARGET_FEATURES) +keysched :: proc(ctx: ^Context, key: []byte) { + sks: [15]simd.u8x16 = --- + + // Compute the encryption keys. + num_rounds, key_len := 0, len(key) + switch key_len { + case _aes.KEY_SIZE_128: + sks[0] = intrinsics.unaligned_load((^simd.u8x16)(raw_data(key))) + sks[1] = expand_step128(sks[0], aeskeygenassist(sks[0], 0x01)) + sks[2] = expand_step128(sks[1], aeskeygenassist(sks[1], 0x02)) + sks[3] = expand_step128(sks[2], aeskeygenassist(sks[2], 0x04)) + sks[4] = expand_step128(sks[3], aeskeygenassist(sks[3], 0x08)) + sks[5] = expand_step128(sks[4], aeskeygenassist(sks[4], 0x10)) + sks[6] = expand_step128(sks[5], aeskeygenassist(sks[5], 0x20)) + sks[7] = expand_step128(sks[6], aeskeygenassist(sks[6], 0x40)) + sks[8] = expand_step128(sks[7], aeskeygenassist(sks[7], 0x80)) + sks[9] = expand_step128(sks[8], aeskeygenassist(sks[8], 0x1b)) + sks[10] = expand_step128(sks[9], aeskeygenassist(sks[9], 0x36)) + num_rounds = _aes.ROUNDS_128 + case _aes.KEY_SIZE_192: + k0 := intrinsics.unaligned_load((^simd.u8x16)(raw_data(key))) + + k1_tmp: [16]byte + copy(k1_tmp[:], key[16:24]) + k1 := intrinsics.unaligned_load((^simd.u8x16)(&k1_tmp)) + crypto.zero_explicit(&k1_tmp, size_of(k1_tmp)) + + sks[0] = k0 + sks[1], sks[2] = expand_step192a(&k0, &k1, aeskeygenassist(k1, 0x01)) + sks[3] = expand_step192b(&k0, &k1, aeskeygenassist(k1, 0x02)) + sks[4], sks[5] = expand_step192a(&k0, &k1, aeskeygenassist(k1, 0x04)) + sks[6] = expand_step192b(&k0, &k1, aeskeygenassist(k1, 0x08)) + sks[7], sks[8] = expand_step192a(&k0, &k1, aeskeygenassist(k1, 0x10)) + sks[9] = expand_step192b(&k0, &k1, aeskeygenassist(k1, 0x20)) + sks[10], sks[11] = expand_step192a(&k0, &k1, aeskeygenassist(k1, 0x40)) + sks[12] = expand_step192b(&k0, &k1, aeskeygenassist(k1, 0x80)) + num_rounds = _aes.ROUNDS_192 + + case _aes.KEY_SIZE_256: + sks[0] = intrinsics.unaligned_load((^simd.u8x16)(raw_data(key))) + sks[1] = intrinsics.unaligned_load((^simd.u8x16)(raw_data(key[16:]))) + sks[2] = expand_step128(sks[0], aeskeygenassist(sks[1], 0x01)) + sks[3] = expand_step256b(sks[1], aeskeygenassist(sks[2], 0x01)) + sks[4] = expand_step128(sks[2], aeskeygenassist(sks[3], 0x02)) + sks[5] = expand_step256b(sks[3], aeskeygenassist(sks[4], 0x02)) + sks[6] = expand_step128(sks[4], aeskeygenassist(sks[5], 0x04)) + sks[7] = expand_step256b(sks[5], aeskeygenassist(sks[6], 0x04)) + sks[8] = expand_step128(sks[6], aeskeygenassist(sks[7], 0x08)) + sks[9] = expand_step256b(sks[7], aeskeygenassist(sks[8], 0x08)) + sks[10] = expand_step128(sks[8], aeskeygenassist(sks[9], 0x10)) + sks[11] = expand_step256b(sks[9], aeskeygenassist(sks[10], 0x10)) + sks[12] = expand_step128(sks[10], aeskeygenassist(sks[11], 0x20)) + sks[13] = expand_step256b(sks[11], aeskeygenassist(sks[12], 0x20)) + sks[14] = expand_step128(sks[12], aeskeygenassist(sks[13], 0x40)) + num_rounds = _aes.ROUNDS_256 + case: + panic("crypto/aes: invalid AES key size") + } + for i in 0 ..= num_rounds { + intrinsics.unaligned_store((^simd.u8x16)(&ctx._sk_exp_enc[i]), sks[i]) + } + + // Compute the decryption keys. GCM and CTR do not need this, however + // ECB, CBC, OCB3, etc do. + derive_dec_keys(ctx, &sks, num_rounds) + + ctx._num_rounds = num_rounds + + crypto.zero_explicit(&sks, size_of(sks)) +} diff --git a/core/crypto/_aes/hw/unsupported.odin b/core/crypto/_aes/hw/unsupported.odin new file mode 100644 index 000000000..3fb31b6b8 --- /dev/null +++ b/core/crypto/_aes/hw/unsupported.odin @@ -0,0 +1,11 @@ +#+build !amd64 +#+build !arm64 +#+build !arm32 +package aes_hw + +HAS_GHASH :: false + +@(private) +keysched :: proc(ctx: ^Context, key: []byte) { + panic("crypto/aes: hardware implementation unsupported") +} diff --git a/core/crypto/_aes/hw_intel/api.odin b/core/crypto/_aes/hw_intel/api.odin deleted file mode 100644 index 502d56213..000000000 --- a/core/crypto/_aes/hw_intel/api.odin +++ /dev/null @@ -1,43 +0,0 @@ -#+build amd64 -package aes_hw_intel - -import "core:sys/info" - -// is_supported returns true iff hardware accelerated AES -// is supported. -is_supported :: proc "contextless" () -> bool { - features, ok := info.cpu.features.? - if !ok { - return false - } - - // Note: Everything with AES-NI and PCLMULQDQ has support for - // the required SSE extxtensions. - req_features :: info.CPU_Features{ - .sse2, - .ssse3, - .sse41, - .aes, - .pclmulqdq, - } - return features >= req_features -} - -// Context is a keyed AES (ECB) instance. -Context :: struct { - // Note: The ideal thing to do is for the expanded round keys to be - // arrays of `__m128i`, however that implies alignment (or using AVX). - // - // All the people using e-waste processors that don't support an - // insturction set that has been around for over 10 years are why - // we can't have nice things. - _sk_exp_enc: [15][16]byte, - _sk_exp_dec: [15][16]byte, - _num_rounds: int, -} - -// init initializes a context for AES with the provided key. -init :: proc(ctx: ^Context, key: []byte) { - keysched(ctx, key) -} - diff --git a/core/crypto/_aes/hw_intel/hw_intel_keysched.odin b/core/crypto/_aes/hw_intel/hw_intel_keysched.odin deleted file mode 100644 index bdf0d3066..000000000 --- a/core/crypto/_aes/hw_intel/hw_intel_keysched.odin +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) 2017 Thomas Pornin -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “AS IS” AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#+build amd64 -package aes_hw_intel - -import "base:intrinsics" -import "core:crypto/_aes" -import "core:mem" -import "core:simd/x86" - -// Intel AES-NI based implementation. Inspiration taken from BearSSL. -// -// Note: This assumes that the SROA optimization pass is enabled to be -// anything resembling performat otherwise, LLVM will not elide a massive -// number of redundant loads/stores it generates for every intrinsic call. - -@(private = "file", require_results, enable_target_feature = "sse2") -expand_step128 :: #force_inline proc(k1, k2: x86.__m128i) -> x86.__m128i { - k1, k2 := k1, k2 - - k2 = x86._mm_shuffle_epi32(k2, 0xff) - k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04)) - k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04)) - k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04)) - return x86._mm_xor_si128(k1, k2) -} - -@(private = "file", require_results, enable_target_feature = "sse,sse2") -expand_step192a :: #force_inline proc (k1_, k2_: ^x86.__m128i, k3: x86.__m128i) -> (x86.__m128i, x86.__m128i) { - k1, k2, k3 := k1_^, k2_^, k3 - - k3 = x86._mm_shuffle_epi32(k3, 0x55) - k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04)) - k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04)) - k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04)) - k1 = x86._mm_xor_si128(k1, k3) - - tmp := k2 - k2 = x86._mm_xor_si128(k2, x86._mm_slli_si128(k2, 0x04)) - k2 = x86._mm_xor_si128(k2, x86._mm_shuffle_epi32(k1, 0xff)) - - k1_, k2_ := k1_, k2_ - k1_^, k2_^ = k1, k2 - - r1 := transmute(x86.__m128i)(x86._mm_shuffle_ps(transmute(x86.__m128)(tmp), transmute(x86.__m128)(k1), 0x44)) - r2 := transmute(x86.__m128i)(x86._mm_shuffle_ps(transmute(x86.__m128)(k1), transmute(x86.__m128)(k2), 0x4e)) - - return r1, r2 -} - -@(private = "file", require_results, enable_target_feature = "sse2") -expand_step192b :: #force_inline proc (k1_, k2_: ^x86.__m128i, k3: x86.__m128i) -> x86.__m128i { - k1, k2, k3 := k1_^, k2_^, k3 - - k3 = x86._mm_shuffle_epi32(k3, 0x55) - k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04)) - k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04)) - k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04)) - k1 = x86._mm_xor_si128(k1, k3) - - k2 = x86._mm_xor_si128(k2, x86._mm_slli_si128(k2, 0x04)) - k2 = x86._mm_xor_si128(k2, x86._mm_shuffle_epi32(k1, 0xff)) - - k1_, k2_ := k1_, k2_ - k1_^, k2_^ = k1, k2 - - return k1 -} - -@(private = "file", require_results, enable_target_feature = "sse2") -expand_step256b :: #force_inline proc(k1, k2: x86.__m128i) -> x86.__m128i { - k1, k2 := k1, k2 - - k2 = x86._mm_shuffle_epi32(k2, 0xaa) - k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04)) - k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04)) - k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04)) - return x86._mm_xor_si128(k1, k2) -} - -@(private = "file", enable_target_feature = "aes") -derive_dec_keys :: proc(ctx: ^Context, sks: ^[15]x86.__m128i, num_rounds: int) { - intrinsics.unaligned_store((^x86.__m128i)(&ctx._sk_exp_dec[0]), sks[num_rounds]) - for i in 1 ..< num_rounds { - tmp := x86._mm_aesimc_si128(sks[i]) - intrinsics.unaligned_store((^x86.__m128i)(&ctx._sk_exp_dec[num_rounds - i]), tmp) - } - intrinsics.unaligned_store((^x86.__m128i)(&ctx._sk_exp_dec[num_rounds]), sks[0]) -} - -@(private, enable_target_feature = "sse,sse2,aes") -keysched :: proc(ctx: ^Context, key: []byte) { - sks: [15]x86.__m128i = --- - - // Compute the encryption keys. - num_rounds, key_len := 0, len(key) - switch key_len { - case _aes.KEY_SIZE_128: - sks[0] = intrinsics.unaligned_load((^x86.__m128i)(raw_data(key))) - sks[1] = expand_step128(sks[0], x86._mm_aeskeygenassist_si128(sks[0], 0x01)) - sks[2] = expand_step128(sks[1], x86._mm_aeskeygenassist_si128(sks[1], 0x02)) - sks[3] = expand_step128(sks[2], x86._mm_aeskeygenassist_si128(sks[2], 0x04)) - sks[4] = expand_step128(sks[3], x86._mm_aeskeygenassist_si128(sks[3], 0x08)) - sks[5] = expand_step128(sks[4], x86._mm_aeskeygenassist_si128(sks[4], 0x10)) - sks[6] = expand_step128(sks[5], x86._mm_aeskeygenassist_si128(sks[5], 0x20)) - sks[7] = expand_step128(sks[6], x86._mm_aeskeygenassist_si128(sks[6], 0x40)) - sks[8] = expand_step128(sks[7], x86._mm_aeskeygenassist_si128(sks[7], 0x80)) - sks[9] = expand_step128(sks[8], x86._mm_aeskeygenassist_si128(sks[8], 0x1b)) - sks[10] = expand_step128(sks[9], x86._mm_aeskeygenassist_si128(sks[9], 0x36)) - num_rounds = _aes.ROUNDS_128 - case _aes.KEY_SIZE_192: - k0 := intrinsics.unaligned_load((^x86.__m128i)(raw_data(key))) - k1 := x86.__m128i{ - intrinsics.unaligned_load((^i64)(raw_data(key[16:]))), - 0, - } - sks[0] = k0 - sks[1], sks[2] = expand_step192a(&k0, &k1, x86._mm_aeskeygenassist_si128(k1, 0x01)) - sks[3] = expand_step192b(&k0, &k1, x86._mm_aeskeygenassist_si128(k1, 0x02)) - sks[4], sks[5] = expand_step192a(&k0, &k1, x86._mm_aeskeygenassist_si128(k1, 0x04)) - sks[6] = expand_step192b(&k0, &k1, x86._mm_aeskeygenassist_si128(k1, 0x08)) - sks[7], sks[8] = expand_step192a(&k0, &k1, x86._mm_aeskeygenassist_si128(k1, 0x10)) - sks[9] = expand_step192b(&k0, &k1, x86._mm_aeskeygenassist_si128(k1, 0x20)) - sks[10], sks[11] = expand_step192a(&k0, &k1, x86._mm_aeskeygenassist_si128(k1, 0x40)) - sks[12] = expand_step192b(&k0, &k1, x86._mm_aeskeygenassist_si128(k1, 0x80)) - num_rounds = _aes.ROUNDS_192 - case _aes.KEY_SIZE_256: - sks[0] = intrinsics.unaligned_load((^x86.__m128i)(raw_data(key))) - sks[1] = intrinsics.unaligned_load((^x86.__m128i)(raw_data(key[16:]))) - sks[2] = expand_step128(sks[0], x86._mm_aeskeygenassist_si128(sks[1], 0x01)) - sks[3] = expand_step256b(sks[1], x86._mm_aeskeygenassist_si128(sks[2], 0x01)) - sks[4] = expand_step128(sks[2], x86._mm_aeskeygenassist_si128(sks[3], 0x02)) - sks[5] = expand_step256b(sks[3], x86._mm_aeskeygenassist_si128(sks[4], 0x02)) - sks[6] = expand_step128(sks[4], x86._mm_aeskeygenassist_si128(sks[5], 0x04)) - sks[7] = expand_step256b(sks[5], x86._mm_aeskeygenassist_si128(sks[6], 0x04)) - sks[8] = expand_step128(sks[6], x86._mm_aeskeygenassist_si128(sks[7], 0x08)) - sks[9] = expand_step256b(sks[7], x86._mm_aeskeygenassist_si128(sks[8], 0x08)) - sks[10] = expand_step128(sks[8], x86._mm_aeskeygenassist_si128(sks[9], 0x10)) - sks[11] = expand_step256b(sks[9], x86._mm_aeskeygenassist_si128(sks[10], 0x10)) - sks[12] = expand_step128(sks[10], x86._mm_aeskeygenassist_si128(sks[11], 0x20)) - sks[13] = expand_step256b(sks[11], x86._mm_aeskeygenassist_si128(sks[12], 0x20)) - sks[14] = expand_step128(sks[12], x86._mm_aeskeygenassist_si128(sks[13], 0x40)) - num_rounds = _aes.ROUNDS_256 - case: - panic("crypto/aes: invalid AES key size") - } - for i in 0 ..= num_rounds { - intrinsics.unaligned_store((^x86.__m128i)(&ctx._sk_exp_enc[i]), sks[i]) - } - - // Compute the decryption keys. GCM and CTR do not need this, however - // ECB, CBC, OCB3, etc do. - derive_dec_keys(ctx, &sks, num_rounds) - - ctx._num_rounds = num_rounds - - mem.zero_explicit(&sks, size_of(sks)) -} diff --git a/core/crypto/_blake2/blake2.odin b/core/crypto/_blake2/blake2.odin index 487e93b83..cf7111c70 100644 --- a/core/crypto/_blake2/blake2.odin +++ b/core/crypto/_blake2/blake2.odin @@ -10,25 +10,21 @@ package _blake2 Implementation of the BLAKE2 hashing algorithm, as defined in and */ +import "base:intrinsics" +import "core:crypto" import "core:encoding/endian" -import "core:mem" BLAKE2S_BLOCK_SIZE :: 64 BLAKE2S_SIZE :: 32 BLAKE2B_BLOCK_SIZE :: 128 BLAKE2B_SIZE :: 64 -MAX_SIZE :: 255 - Blake2s_Context :: struct { h: [8]u32, t: [2]u32, f: [2]u32, x: [BLAKE2S_BLOCK_SIZE]byte, nx: int, - ih: [8]u32, - padded_key: [BLAKE2S_BLOCK_SIZE]byte, - is_keyed: bool, size: byte, is_last_node: bool, @@ -41,9 +37,6 @@ Blake2b_Context :: struct { f: [2]u64, x: [BLAKE2B_BLOCK_SIZE]byte, nx: int, - ih: [8]u64, - padded_key: [BLAKE2B_BLOCK_SIZE]byte, - is_keyed: bool, size: byte, is_last_node: bool, @@ -86,11 +79,12 @@ BLAKE2B_IV := [8]u64 { init :: proc "contextless" (ctx: ^$T, cfg: ^Blake2_Config) { when T == Blake2s_Context { - max_size :: BLAKE2S_SIZE + MAX_SIZE :: BLAKE2S_SIZE } else when T == Blake2b_Context { - max_size :: BLAKE2B_SIZE + MAX_SIZE :: BLAKE2B_SIZE } - ensure_contextless(cfg.size <= max_size, "blake2: requested output size exceeeds algorithm max") + ensure_contextless(cfg.size <= MAX_SIZE, "blake2: requested output size exceeeds algorithm max") + ensure_contextless(len(cfg.key) <= MAX_SIZE, "blake2: requested key size exceeeds algorithm max") // To save having to allocate a scratch buffer, use the internal // data buffer (`ctx.x`), as it is exactly the correct size. @@ -133,7 +127,7 @@ init :: proc "contextless" (ctx: ^$T, cfg: ^Blake2_Config) { p[17] = cfg.tree.(Blake2_Tree).inner_hash_size } } else { - p[2], p[3] = 1, 1 + p[2], p[3], p[4], p[5], p[6], p[7] = 1, 1, 0, 0, 0, 0 } ctx.size = cfg.size for i := 0; i < 8; i += 1 { @@ -145,23 +139,17 @@ init :: proc "contextless" (ctx: ^$T, cfg: ^Blake2_Config) { } } - mem.zero(&ctx.x, size_of(ctx.x)) // Done with the scratch space, no barrier. + intrinsics.mem_zero(&ctx.x, size_of(ctx.x)) // Done with the scratch space, no barrier. if cfg.tree != nil && cfg.tree.(Blake2_Tree).is_last_node { ctx.is_last_node = true } if len(cfg.key) > 0 { - copy(ctx.padded_key[:], cfg.key) - update(ctx, ctx.padded_key[:]) - ctx.is_keyed = true + copy(ctx.x[:], cfg.key) + ctx.nx = len(ctx.x) + } else { + ctx.nx = 0 } - copy(ctx.ih[:], ctx.h[:]) - copy(ctx.h[:], ctx.ih[:]) - if ctx.is_keyed { - update(ctx, ctx.padded_key[:]) - } - - ctx.nx = 0 ctx.is_initialized = true } @@ -171,22 +159,22 @@ update :: proc "contextless" (ctx: ^$T, p: []byte) { p := p when T == Blake2s_Context { - block_size :: BLAKE2S_BLOCK_SIZE + BLOCK_SIZE :: BLAKE2S_BLOCK_SIZE } else when T == Blake2b_Context { - block_size :: BLAKE2B_BLOCK_SIZE + BLOCK_SIZE :: BLAKE2B_BLOCK_SIZE } - left := block_size - ctx.nx + left := BLOCK_SIZE - ctx.nx if len(p) > left { copy(ctx.x[ctx.nx:], p[:left]) p = p[left:] blocks(ctx, ctx.x[:]) ctx.nx = 0 } - if len(p) > block_size { - n := len(p) &~ (block_size - 1) + if len(p) > BLOCK_SIZE { + n := len(p) &~ (BLOCK_SIZE - 1) if n == len(p) { - n -= block_size + n -= BLOCK_SIZE } blocks(ctx, p[:n]) p = p[n:] @@ -222,17 +210,11 @@ reset :: proc "contextless" (ctx: ^$T) { return } - mem.zero_explicit(ctx, size_of(ctx^)) + crypto.zero_explicit(ctx, size_of(ctx^)) } @(private) blake2s_final :: proc "contextless" (ctx: ^Blake2s_Context, hash: []byte) { - if ctx.is_keyed { - for i := 0; i < len(ctx.padded_key); i += 1 { - ctx.padded_key[i] = 0 - } - } - dec := BLAKE2S_BLOCK_SIZE - u32(ctx.nx) if ctx.t[0] < dec { ctx.t[1] -= 1 @@ -244,23 +226,20 @@ blake2s_final :: proc "contextless" (ctx: ^Blake2s_Context, hash: []byte) { ctx.f[1] = 0xffffffff } + for i := ctx.nx; i < BLAKE2S_BLOCK_SIZE; i+= 1 { + ctx.x[i] = 0 + } blocks(ctx, ctx.x[:]) dst: [BLAKE2S_SIZE]byte for i := 0; i < BLAKE2S_SIZE / 4; i += 1 { endian.unchecked_put_u32le(dst[i * 4:], ctx.h[i]) } - copy(hash, dst[:]) + copy(hash, dst[:ctx.size]) } @(private) blake2b_final :: proc "contextless" (ctx: ^Blake2b_Context, hash: []byte) { - if ctx.is_keyed { - for i := 0; i < len(ctx.padded_key); i += 1 { - ctx.padded_key[i] = 0 - } - } - dec := BLAKE2B_BLOCK_SIZE - u64(ctx.nx) if ctx.t[0] < dec { ctx.t[1] -= 1 @@ -272,6 +251,9 @@ blake2b_final :: proc "contextless" (ctx: ^Blake2b_Context, hash: []byte) { ctx.f[1] = 0xffffffffffffffff } + for i := ctx.nx; i < BLAKE2B_BLOCK_SIZE; i+= 1 { + ctx.x[i] = 0 + } blocks(ctx, ctx.x[:]) dst: [BLAKE2B_SIZE]byte diff --git a/core/crypto/_chacha20/chacha20.odin b/core/crypto/_chacha20/chacha20.odin index 1a4b5a507..7d94d8a95 100644 --- a/core/crypto/_chacha20/chacha20.odin +++ b/core/crypto/_chacha20/chacha20.odin @@ -1,8 +1,8 @@ package _chacha20 +import "core:crypto" import "core:encoding/endian" import "core:math/bits" -import "core:mem" // KEY_SIZE is the (X)ChaCha20 key size in bytes. KEY_SIZE :: 32 @@ -88,8 +88,8 @@ seek :: proc(ctx: ^Context, block_nr: u64) { // reset sanitizes the Context. The Context must be re-initialized to // be used again. reset :: proc(ctx: ^Context) { - mem.zero_explicit(&ctx._s, size_of(ctx._s)) - mem.zero_explicit(&ctx._buffer, size_of(ctx._buffer)) + crypto.zero_explicit(&ctx._s, size_of(ctx._s)) + crypto.zero_explicit(&ctx._buffer, size_of(ctx._buffer)) ctx._is_initialized = false } @@ -116,4 +116,4 @@ check_counter_limit :: proc(ctx: ^Context, nr_blocks: int) { } ensure(ctr_ok, "crypto/chacha20: maximum (X)ChaCha20 keystream per IV reached") -} +} \ No newline at end of file diff --git a/core/crypto/_chacha20/ref/chacha20_ref.odin b/core/crypto/_chacha20/ref/chacha20_ref.odin index c111c1c76..c4e6bca98 100644 --- a/core/crypto/_chacha20/ref/chacha20_ref.odin +++ b/core/crypto/_chacha20/ref/chacha20_ref.odin @@ -4,133 +4,68 @@ import "core:crypto/_chacha20" import "core:encoding/endian" import "core:math/bits" +// At least with LLVM21 force_inline produces identical perf to +// manual inlining, yay. +@(private) +quarter_round :: #force_inline proc "contextless" (a, b, c, d: u32) -> (u32, u32, u32, u32) { + a, b, c, d := a, b, c, d + + a += b + d ~= a + d = bits.rotate_left32(d, 16) + + c += d + b ~= c + b = bits.rotate_left32(b, 12) + + a += b + d ~= a + d = bits.rotate_left32(d, 8) + + c += d + b ~= c + b = bits.rotate_left32(b, 7) + + return a, b, c, d +} + stream_blocks :: proc(ctx: ^_chacha20.Context, dst, src: []byte, nr_blocks: int) { // Enforce the maximum consumed keystream per IV. _chacha20.check_counter_limit(ctx, nr_blocks) dst, src := dst, src x := &ctx._s + + + // Filippo Valsorda made an observation that only one of the column + // round depends on the counter (s12), so it is worth precomputing + // and reusing across multiple blocks. As far as I know, only Go's + // chacha implementation does this. + + p1, p5, p9, p13 := quarter_round(_chacha20.SIGMA_1, x[5], x[9], x[13]) + p2, p6, p10, p14 := quarter_round(_chacha20.SIGMA_2, x[6], x[10], x[14]) + p3, p7, p11, p15 := quarter_round(_chacha20.SIGMA_3, x[7], x[11], x[15]) + for n := 0; n < nr_blocks; n = n + 1 { - x0, x1, x2, x3 := - _chacha20.SIGMA_0, _chacha20.SIGMA_1, _chacha20.SIGMA_2, _chacha20.SIGMA_3 - x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := - x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15] + // First column round that depends on the counter + p0, p4, p8, p12 := quarter_round(_chacha20.SIGMA_0, x[4], x[8], x[12]) - for i := _chacha20.ROUNDS; i > 0; i = i - 2 { - // Even when forcing inlining manually inlining all of - // these is decently faster. + // First diagonal round + x0, x5, x10, x15 := quarter_round(p0, p5, p10, p15) + x1, x6, x11, x12 := quarter_round(p1, p6, p11, p12) + x2, x7, x8, x13 := quarter_round(p2, p7, p8, p13) + x3, x4, x9, x14 := quarter_round(p3, p4, p9, p14) - // quarterround(x, 0, 4, 8, 12) - x0 += x4 - x12 ~= x0 - x12 = bits.rotate_left32(x12, 16) - x8 += x12 - x4 ~= x8 - x4 = bits.rotate_left32(x4, 12) - x0 += x4 - x12 ~= x0 - x12 = bits.rotate_left32(x12, 8) - x8 += x12 - x4 ~= x8 - x4 = bits.rotate_left32(x4, 7) + for i := _chacha20.ROUNDS - 2; i > 0; i = i - 2 { + x0, x4, x8, x12 = quarter_round(x0, x4, x8, x12) + x1, x5, x9, x13 = quarter_round(x1, x5, x9, x13) + x2, x6, x10, x14 = quarter_round(x2, x6, x10, x14) + x3, x7, x11, x15 = quarter_round(x3, x7, x11, x15) - // quarterround(x, 1, 5, 9, 13) - x1 += x5 - x13 ~= x1 - x13 = bits.rotate_left32(x13, 16) - x9 += x13 - x5 ~= x9 - x5 = bits.rotate_left32(x5, 12) - x1 += x5 - x13 ~= x1 - x13 = bits.rotate_left32(x13, 8) - x9 += x13 - x5 ~= x9 - x5 = bits.rotate_left32(x5, 7) - - // quarterround(x, 2, 6, 10, 14) - x2 += x6 - x14 ~= x2 - x14 = bits.rotate_left32(x14, 16) - x10 += x14 - x6 ~= x10 - x6 = bits.rotate_left32(x6, 12) - x2 += x6 - x14 ~= x2 - x14 = bits.rotate_left32(x14, 8) - x10 += x14 - x6 ~= x10 - x6 = bits.rotate_left32(x6, 7) - - // quarterround(x, 3, 7, 11, 15) - x3 += x7 - x15 ~= x3 - x15 = bits.rotate_left32(x15, 16) - x11 += x15 - x7 ~= x11 - x7 = bits.rotate_left32(x7, 12) - x3 += x7 - x15 ~= x3 - x15 = bits.rotate_left32(x15, 8) - x11 += x15 - x7 ~= x11 - x7 = bits.rotate_left32(x7, 7) - - // quarterround(x, 0, 5, 10, 15) - x0 += x5 - x15 ~= x0 - x15 = bits.rotate_left32(x15, 16) - x10 += x15 - x5 ~= x10 - x5 = bits.rotate_left32(x5, 12) - x0 += x5 - x15 ~= x0 - x15 = bits.rotate_left32(x15, 8) - x10 += x15 - x5 ~= x10 - x5 = bits.rotate_left32(x5, 7) - - // quarterround(x, 1, 6, 11, 12) - x1 += x6 - x12 ~= x1 - x12 = bits.rotate_left32(x12, 16) - x11 += x12 - x6 ~= x11 - x6 = bits.rotate_left32(x6, 12) - x1 += x6 - x12 ~= x1 - x12 = bits.rotate_left32(x12, 8) - x11 += x12 - x6 ~= x11 - x6 = bits.rotate_left32(x6, 7) - - // quarterround(x, 2, 7, 8, 13) - x2 += x7 - x13 ~= x2 - x13 = bits.rotate_left32(x13, 16) - x8 += x13 - x7 ~= x8 - x7 = bits.rotate_left32(x7, 12) - x2 += x7 - x13 ~= x2 - x13 = bits.rotate_left32(x13, 8) - x8 += x13 - x7 ~= x8 - x7 = bits.rotate_left32(x7, 7) - - // quarterround(x, 3, 4, 9, 14) - x3 += x4 - x14 ~= x3 - x14 = bits.rotate_left32(x14, 16) - x9 += x14 - x4 ~= x9 - x4 = bits.rotate_left32(x4, 12) - x3 += x4 - x14 ~= x3 - x14 = bits.rotate_left32(x14, 8) - x9 += x14 - x4 ~= x9 - x4 = bits.rotate_left32(x4, 7) + x0, x5, x10, x15 = quarter_round(x0, x5, x10, x15) + x1, x6, x11, x12 = quarter_round(x1, x6, x11, x12) + x2, x7, x8, x13 = quarter_round(x2, x7, x8, x13) + x3, x4, x9, x14 = quarter_round(x3, x4, x9, x14) } x0 += _chacha20.SIGMA_0 @@ -236,117 +171,15 @@ hchacha20 :: proc "contextless" (dst, key, iv: []byte) { x15 := endian.unchecked_get_u32le(iv[12:16]) for i := _chacha20.ROUNDS; i > 0; i = i - 2 { - // quarterround(x, 0, 4, 8, 12) - x0 += x4 - x12 ~= x0 - x12 = bits.rotate_left32(x12, 16) - x8 += x12 - x4 ~= x8 - x4 = bits.rotate_left32(x4, 12) - x0 += x4 - x12 ~= x0 - x12 = bits.rotate_left32(x12, 8) - x8 += x12 - x4 ~= x8 - x4 = bits.rotate_left32(x4, 7) + x0, x4, x8, x12 = quarter_round(x0, x4, x8, x12) + x1, x5, x9, x13 = quarter_round(x1, x5, x9, x13) + x2, x6, x10, x14 = quarter_round(x2, x6, x10, x14) + x3, x7, x11, x15 = quarter_round(x3, x7, x11, x15) - // quarterround(x, 1, 5, 9, 13) - x1 += x5 - x13 ~= x1 - x13 = bits.rotate_left32(x13, 16) - x9 += x13 - x5 ~= x9 - x5 = bits.rotate_left32(x5, 12) - x1 += x5 - x13 ~= x1 - x13 = bits.rotate_left32(x13, 8) - x9 += x13 - x5 ~= x9 - x5 = bits.rotate_left32(x5, 7) - - // quarterround(x, 2, 6, 10, 14) - x2 += x6 - x14 ~= x2 - x14 = bits.rotate_left32(x14, 16) - x10 += x14 - x6 ~= x10 - x6 = bits.rotate_left32(x6, 12) - x2 += x6 - x14 ~= x2 - x14 = bits.rotate_left32(x14, 8) - x10 += x14 - x6 ~= x10 - x6 = bits.rotate_left32(x6, 7) - - // quarterround(x, 3, 7, 11, 15) - x3 += x7 - x15 ~= x3 - x15 = bits.rotate_left32(x15, 16) - x11 += x15 - x7 ~= x11 - x7 = bits.rotate_left32(x7, 12) - x3 += x7 - x15 ~= x3 - x15 = bits.rotate_left32(x15, 8) - x11 += x15 - x7 ~= x11 - x7 = bits.rotate_left32(x7, 7) - - // quarterround(x, 0, 5, 10, 15) - x0 += x5 - x15 ~= x0 - x15 = bits.rotate_left32(x15, 16) - x10 += x15 - x5 ~= x10 - x5 = bits.rotate_left32(x5, 12) - x0 += x5 - x15 ~= x0 - x15 = bits.rotate_left32(x15, 8) - x10 += x15 - x5 ~= x10 - x5 = bits.rotate_left32(x5, 7) - - // quarterround(x, 1, 6, 11, 12) - x1 += x6 - x12 ~= x1 - x12 = bits.rotate_left32(x12, 16) - x11 += x12 - x6 ~= x11 - x6 = bits.rotate_left32(x6, 12) - x1 += x6 - x12 ~= x1 - x12 = bits.rotate_left32(x12, 8) - x11 += x12 - x6 ~= x11 - x6 = bits.rotate_left32(x6, 7) - - // quarterround(x, 2, 7, 8, 13) - x2 += x7 - x13 ~= x2 - x13 = bits.rotate_left32(x13, 16) - x8 += x13 - x7 ~= x8 - x7 = bits.rotate_left32(x7, 12) - x2 += x7 - x13 ~= x2 - x13 = bits.rotate_left32(x13, 8) - x8 += x13 - x7 ~= x8 - x7 = bits.rotate_left32(x7, 7) - - // quarterround(x, 3, 4, 9, 14) - x3 += x4 - x14 ~= x3 - x14 = bits.rotate_left32(x14, 16) - x9 += x14 - x4 ~= x9 - x4 = bits.rotate_left32(x4, 12) - x3 += x4 - x14 ~= x3 - x14 = bits.rotate_left32(x14, 8) - x9 += x14 - x4 ~= x9 - x4 = bits.rotate_left32(x4, 7) + x0, x5, x10, x15 = quarter_round(x0, x5, x10, x15) + x1, x6, x11, x12 = quarter_round(x1, x6, x11, x12) + x2, x7, x8, x13 = quarter_round(x2, x7, x8, x13) + x3, x4, x9, x14 = quarter_round(x3, x4, x9, x14) } endian.unchecked_put_u32le(dst[0:4], x0) diff --git a/core/crypto/_chacha20/simd128/chacha20_simd128.odin b/core/crypto/_chacha20/simd128/chacha20_simd128.odin index 4bf40e240..fd48074df 100644 --- a/core/crypto/_chacha20/simd128/chacha20_simd128.odin +++ b/core/crypto/_chacha20/simd128/chacha20_simd128.odin @@ -215,7 +215,7 @@ _store_simd128 :: #force_inline proc "contextless" ( intrinsics.unaligned_store((^simd.u32x4)(dst[3:]), v3) } -// is_performant returns true iff the target and current host both support +// is_performant returns true if and only if (⟺) the target and current host both support // "enough" 128-bit SIMD to make this implementation performant. is_performant :: proc "contextless" () -> bool { when ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32 || ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 || ODIN_ARCH == .riscv64 { @@ -227,12 +227,7 @@ is_performant :: proc "contextless" () -> bool { req_features :: info.CPU_Features{.V} } - features, ok := info.cpu.features.? - if !ok { - return false - } - - return features >= req_features + return info.cpu_features() >= req_features } else when ODIN_ARCH == .wasm64p32 || ODIN_ARCH == .wasm32 { return intrinsics.has_target_feature("simd128") } else { diff --git a/core/crypto/_chacha20/simd256/chacha20_simd256.odin b/core/crypto/_chacha20/simd256/chacha20_simd256.odin index 12fffeb2f..c2f709aec 100644 --- a/core/crypto/_chacha20/simd256/chacha20_simd256.odin +++ b/core/crypto/_chacha20/simd256/chacha20_simd256.odin @@ -36,17 +36,12 @@ _VEC_ZERO_ONE: simd.u64x4 : {0, 0, 1, 0} @(private = "file") _VEC_TWO: simd.u64x4 : {2, 0, 2, 0} -// is_performant returns true iff the target and current host both support +// is_performant returns true if and only if (⟺) the target and current host both support // "enough" SIMD to make this implementation performant. is_performant :: proc "contextless" () -> bool { req_features :: info.CPU_Features{.avx, .avx2} - features, ok := info.cpu.features.? - if !ok { - return false - } - - return features >= req_features + return info.cpu_features() >= req_features } @(private = "file") diff --git a/core/crypto/_edwards25519/edwards25519.odin b/core/crypto/_edwards25519/edwards25519.odin index d6f01d497..dddfaef02 100644 --- a/core/crypto/_edwards25519/edwards25519.odin +++ b/core/crypto/_edwards25519/edwards25519.odin @@ -13,7 +13,8 @@ See: import "core:crypto" import field "core:crypto/_fiat/field_curve25519" -import "core:mem" + +zero_explicit :: crypto.zero_explicit // Group_Element is an edwards25519 group element, as extended homogenous // coordinates, which represents the affine point `(x, y)` as `(X, Y, Z, T)`, @@ -96,7 +97,7 @@ Group_Element :: struct { } ge_clear :: proc "contextless" (ge: ^Group_Element) { - mem.zero_explicit(ge, size_of(Group_Element)) + zero_explicit(ge, size_of(Group_Element)) } ge_set :: proc "contextless" (ge, a: ^Group_Element) { @@ -159,7 +160,7 @@ ge_set_bytes :: proc "contextless" (ge: ^Group_Element, b: []byte) -> bool { ge_cond_assign(ge, &tmp, is_canonical) - mem.zero_explicit(&buf, size_of(buf)) + zero_explicit(&buf, size_of(buf)) return is_canonical == 1 } @@ -195,7 +196,6 @@ ge_generator :: proc "contextless" (ge: ^Group_Element) { ge_set(ge, &GE_BASEPOINT) } -@(private) Addend_Group_Element :: struct { y2_minus_x2: field.Loose_Field_Element, // t1 y2_plus_x2: field.Loose_Field_Element, // t3 @@ -203,7 +203,6 @@ Addend_Group_Element :: struct { two_times_z2: field.Loose_Field_Element, // t5 } -@(private) ge_addend_set :: proc "contextless" (ge_a: ^Addend_Group_Element, ge: ^Group_Element) { field.fe_sub(&ge_a.y2_minus_x2, &ge.y, &ge.x) field.fe_add(&ge_a.y2_plus_x2, &ge.y, &ge.x) @@ -233,8 +232,8 @@ ge_add :: proc "contextless" (ge, a, b: ^Group_Element) { scratch: Add_Scratch = --- ge_add_addend(ge, a, &b_, &scratch) - mem.zero_explicit(&b_, size_of(Addend_Group_Element)) - mem.zero_explicit(&scratch, size_of(Add_Scratch)) + zero_explicit(&b_, size_of(Addend_Group_Element)) + zero_explicit(&scratch, size_of(Add_Scratch)) } @(private) @@ -354,7 +353,7 @@ ge_double :: proc "contextless" (ge, a: ^Group_Element, scratch: ^Double_Scratch field.fe_carry_mul(&ge.z, F, G_) if sanitize { - mem.zero_explicit(scratch, size_of(Double_Scratch)) + zero_explicit(scratch, size_of(Double_Scratch)) } } @@ -420,6 +419,6 @@ ge_in_prime_order_subgroup_vartime :: proc "contextless" (ge: ^Group_Element) -> // that is a ~50% speedup, and a lot of added complexity for something // that is better solved by "just use ristretto255". tmp: Group_Element = --- - _ge_scalarmult(&tmp, ge, &SC_ELL, true) + ge_scalarmult_raw(&tmp, ge, &SC_ELL, true) return ge_equal(&tmp, &GE_IDENTITY) == 1 -} +} \ No newline at end of file diff --git a/core/crypto/_edwards25519/edwards25519_scalar.odin b/core/crypto/_edwards25519/edwards25519_scalar.odin index 68c79a6e8..5dff03f67 100644 --- a/core/crypto/_edwards25519/edwards25519_scalar.odin +++ b/core/crypto/_edwards25519/edwards25519_scalar.odin @@ -1,7 +1,6 @@ package _edwards25519 import field "core:crypto/_fiat/field_scalar25519" -import "core:mem" Scalar :: field.Montgomery_Domain_Field_Element @@ -19,7 +18,7 @@ sc_set_u64 :: proc "contextless" (sc: ^Scalar, i: u64) { tmp := field.Non_Montgomery_Domain_Field_Element{i, 0, 0, 0} field.fe_to_montgomery(sc, &tmp) - mem.zero_explicit(&tmp, size_of(tmp)) + zero_explicit(&tmp, size_of(tmp)) } @(require_results) @@ -36,7 +35,7 @@ sc_set_bytes_rfc8032 :: proc "contextless" (sc: ^Scalar, b: []byte) { } sc_clear :: proc "contextless" (sc: ^Scalar) { - mem.zero_explicit(sc, size_of(Scalar)) + zero_explicit(sc, size_of(Scalar)) } sc_set :: field.fe_set diff --git a/core/crypto/_edwards25519/edwards25519_scalar_mul.odin b/core/crypto/_edwards25519/edwards25519_scalar_mul.odin index 757a51257..548062c78 100644 --- a/core/crypto/_edwards25519/edwards25519_scalar_mul.odin +++ b/core/crypto/_edwards25519/edwards25519_scalar_mul.odin @@ -1,130 +1,23 @@ package _edwards25519 +import "core:crypto" import field "core:crypto/_fiat/field_scalar25519" -import "core:math/bits" -import "core:mem" - -// GE_BASEPOINT_TABLE is 1 * G, ... 15 * G, in precomputed format. -// -// Note: When generating, the values were reduced to Tight_Field_Element -// ranges, even though that is not required. -@(private) -GE_BASEPOINT_TABLE := Multiply_Table { - { - {62697248952638, 204681361388450, 631292143396476, 338455783676468, 1213667448819585}, - {1288382639258501, 245678601348599, 269427782077623, 1462984067271730, 137412439391563}, - {301289933810280, 1259582250014073, 1422107436869536, 796239922652654, 1953934009299142}, - {2, 0, 0, 0, 0}, - }, - { - {1519297034332653, 1098796920435767, 1823476547744119, 808144629470969, 2110930855619772}, - {338005982828284, 1667856962156925, 100399270107451, 1604566703601691, 1950338038771369}, - {1920505767731247, 1443759578976892, 1659852098357048, 1484431291070208, 275018744912646}, - {763163817085987, 2195095074806923, 2167883174351839, 1868059999999762, 911071066608705}, - }, - { - {960627541894068, 1314966688943942, 1126875971034044, 2059608312958945, 605975666152586}, - {1714478358025626, 2209607666607510, 1600912834284834, 496072478982142, 481970031861896}, - {851735079403194, 1088965826757164, 141569479297499, 602804610059257, 2004026468601520}, - {197585529552380, 324719066578543, 564481854250498, 1173818332764578, 35452976395676}, - }, - { - {1152980410747203, 2196804280851952, 25745194962557, 1915167295473129, 1266299690309224}, - {809905889679060, 979732230071345, 1509972345538142, 188492426534402, 818965583123815}, - {997685409185036, 1451818320876327, 2126681166774509, 2000509606057528, 235432372486854}, - {887734189279642, 1460338685162044, 877378220074262, 102436391401299, 153369156847490}, - }, - { - {2056621900836770, 1821657694132497, 1627986892909426, 1163363868678833, 1108873376459226}, - {1187697490593623, 1066539945237335, 885654531892000, 1357534489491782, 359370291392448}, - {1509033452137525, 1305318174298508, 613642471748944, 1987256352550234, 1044283663101541}, - {220105720697037, 387661783287620, 328296827867762, 360035589590664, 795213236824054}, - }, - { - {1820794733038396, 1612235121681074, 757405923441402, 1094031020892801, 231025333128907}, - {1639067873254194, 1484176557946322, 300800382144789, 1329915446659183, 1211704578730455}, - {641900794791527, 1711751746971612, 179044712319955, 576455585963824, 1852617592509865}, - {743549047192397, 685091042550147, 1952415336873496, 1965124675654685, 513364998442917}, - }, - { - {1004557076870448, 1762911374844520, 1330807633622723, 384072910939787, 953849032243810}, - {2178275058221458, 257933183722891, 376684351537894, 2010189102001786, 1981824297484148}, - {1332915663881114, 1286540505502549, 1741691283561518, 977214932156314, 1764059494778091}, - {429702949064027, 1368332611650677, 2019867176450999, 2212258376161746, 526160996742554}, - }, - { - {2098932988258576, 2203688382075948, 2120400160059479, 1748488020948146, 1203264167282624}, - {677131386735829, 1850249298025188, 672782146532031, 2144145693078904, 2088656272813787}, - {1065622343976192, 1573853211848116, 223560413590068, 333846833073379, 27832122205830}, - {1781008836504573, 917619542051793, 544322748939913, 882577394308384, 1720521246471195}, - }, - { - {660120928379860, 2081944024858618, 1878411111349191, 424587356517195, 2111317439894005}, - {1834193977811532, 1864164086863319, 797334633289424, 150410812403062, 2085177078466389}, - {1438117271371866, 783915531014482, 388731514584658, 292113935417795, 1945855002546714}, - {1678140823166658, 679103239148744, 614102761596238, 1052962498997885, 1863983323810390}, - }, - { - {1690309392496233, 1116333140326275, 1377242323631039, 717196888780674, 82724646713353}, - {1722370213432106, 74265192976253, 264239578448472, 1714909985012994, 2216984958602173}, - {2010482366920922, 1294036471886319, 566466395005815, 1631955803657320, 1751698647538458}, - {1073230604155753, 1159087041338551, 1664057985455483, 127472702826203, 1339591128522371}, - }, - { - {478053307175577, 2179515791720985, 21146535423512, 1831683844029536, 462805561553981}, - {1945267486565588, 1298536818409655, 2214511796262989, 1904981051429012, 252904800782086}, - {268945954671210, 222740425595395, 1208025911856230, 1080418823003555, 75929831922483}, - {1884784014268948, 643868448202966, 978736549726821, 46385971089796, 1296884812292320}, - }, - { - {1861159462859103, 7077532564710, 963010365896826, 1938780006785270, 766241051941647}, - {1778966986051906, 1713995999765361, 1394565822271816, 1366699246468722, 1213407027149475}, - {1978989286560907, 2135084162045594, 1951565508865477, 671788336314416, 293123929458176}, - {902608944504080, 2167765718046481, 1285718473078022, 1222562171329269, 492109027844479}, - }, - { - {1820807832746213, 1029220580458586, 1101997555432203, 1039081975563572, 202477981158221}, - {1866134980680205, 2222325502763386, 1830284629571201, 1046966214478970, 418381946936795}, - {1783460633291322, 1719505443254998, 1810489639976220, 877049370713018, 2187801198742619}, - {197118243000763, 305493867565736, 518814410156522, 1656246186645170, 901894734874934}, - }, - { - {225454942125915, 478410476654509, 600524586037746, 643450007230715, 1018615928259319}, - {1733330584845708, 881092297970296, 507039890129464, 496397090721598, 2230888519577628}, - {690155664737246, 1010454785646677, 753170144375012, 1651277613844874, 1622648796364156}, - {1321310321891618, 1089655277873603, 235891750867089, 815878279563688, 1709264240047556}, - }, - { - {805027036551342, 1387174275567452, 1156538511461704, 1465897486692171, 1208567094120903}, - {2228417017817483, 202885584970535, 2182114782271881, 2077405042592934, 1029684358182774}, - {460447547653983, 627817697755692, 524899434670834, 1228019344939427, 740684787777653}, - {849757462467675, 447476306919899, 422618957298818, 302134659227815, 675831828440895}, - }, -} +import subtle "core:crypto/_subtle" ge_scalarmult :: proc "contextless" (ge, p: ^Group_Element, sc: ^Scalar) { tmp: field.Non_Montgomery_Domain_Field_Element field.fe_from_montgomery(&tmp, sc) - _ge_scalarmult(ge, p, &tmp) + ge_scalarmult_raw(ge, p, &tmp) - mem.zero_explicit(&tmp, size_of(tmp)) -} - -ge_scalarmult_basepoint :: proc "contextless" (ge: ^Group_Element, sc: ^Scalar) { - // Something like the comb method from "Fast and compact elliptic-curve - // cryptography" Section 3.3, would be more performant, but more - // complex. - // - // - https://eprint.iacr.org/2012/309 - ge_scalarmult(ge, &GE_BASEPOINT, sc) + zero_explicit(&tmp, size_of(tmp)) } ge_scalarmult_vartime :: proc "contextless" (ge, p: ^Group_Element, sc: ^Scalar) { tmp: field.Non_Montgomery_Domain_Field_Element field.fe_from_montgomery(&tmp, sc) - _ge_scalarmult(ge, p, &tmp, true) + ge_scalarmult_raw(ge, p, &tmp, true) } ge_double_scalarmult_basepoint_vartime :: proc "contextless" ( @@ -147,6 +40,12 @@ ge_double_scalarmult_basepoint_vartime :: proc "contextless" ( A_tbl: Multiply_Table = --- mul_tbl_set(&A_tbl, A, &tmp_add) + when crypto.COMPACT_IMPLS == true { + G_tbl: Multiply_Table = --- + mul_tbl_set(&G_tbl, &GE_BASEPOINT, &tmp_add) + } else { + tmp_bp_addend: Basepoint_Addend_Group_Element = --- + } sc_a, sc_b: field.Non_Montgomery_Domain_Field_Element field.fe_from_montgomery(&sc_a, a) @@ -170,21 +69,28 @@ ge_double_scalarmult_basepoint_vartime :: proc "contextless" ( ge_double(&tmp, &tmp, &tmp_dbl) } mul_tbl_add(&tmp, &A_tbl, hi_a, &tmp_add, &tmp_addend, true) - mul_tbl_add(&tmp, &GE_BASEPOINT_TABLE, hi_b, &tmp_add, &tmp_addend, true) + when crypto.COMPACT_IMPLS == true { + mul_tbl_add(&tmp, &G_tbl, hi_b, &tmp_add, &tmp_addend, true) + } else { + mul_bp_tbl_add(&tmp, GE_BASEPOINT_TABLE, hi_b, &tmp_add, &tmp_bp_addend, true) + } ge_double(&tmp, &tmp, &tmp_dbl) ge_double(&tmp, &tmp, &tmp_dbl) ge_double(&tmp, &tmp, &tmp_dbl) ge_double(&tmp, &tmp, &tmp_dbl) mul_tbl_add(&tmp, &A_tbl, lo_a, &tmp_add, &tmp_addend, true) - mul_tbl_add(&tmp, &GE_BASEPOINT_TABLE, lo_b, &tmp_add, &tmp_addend, true) + when crypto.COMPACT_IMPLS == true { + mul_tbl_add(&tmp, &G_tbl, lo_b, &tmp_add, &tmp_addend, true) + } else { + mul_bp_tbl_add(&tmp, GE_BASEPOINT_TABLE, lo_b, &tmp_add, &tmp_bp_addend, true) + } } ge_set(ge, &tmp) } -@(private) -_ge_scalarmult :: proc "contextless" ( +ge_scalarmult_raw :: proc "contextless" ( ge, p: ^Group_Element, sc: ^field.Non_Montgomery_Domain_Field_Element, unsafe_is_vartime := false, @@ -227,9 +133,9 @@ _ge_scalarmult :: proc "contextless" ( if !unsafe_is_vartime { ge_clear(&tmp) - mem.zero_explicit(&tmp_add, size_of(Add_Scratch)) - mem.zero_explicit(&tmp_addend, size_of(Addend_Group_Element)) - mem.zero_explicit(&tmp_dbl, size_of(Double_Scratch)) + zero_explicit(&tmp_add, size_of(Add_Scratch)) + zero_explicit(&tmp_addend, size_of(Addend_Group_Element)) + zero_explicit(&tmp_dbl, size_of(Double_Scratch)) } } @@ -281,8 +187,8 @@ mul_tbl_add :: proc "contextless" ( {2, 0, 0, 0, 0}, // z * 2 } for i := u64(1); i < 16; i = i + 1 { - _, ctrl := bits.sub_u64(0, (i ~ idx), 0) - ge_addend_conditional_assign(tmp_addend, &tbl[i - 1], int(~ctrl) & 1) + ctrl := subtle.eq(i, idx) + ge_addend_conditional_assign(tmp_addend, &tbl[i - 1], int(ctrl)) } ge_add_addend(ge, ge, tmp_addend, tmp_add) } diff --git a/core/crypto/_edwards25519/edwards25519_scalar_mul_base.odin b/core/crypto/_edwards25519/edwards25519_scalar_mul_base.odin new file mode 100644 index 000000000..51305af2a --- /dev/null +++ b/core/crypto/_edwards25519/edwards25519_scalar_mul_base.odin @@ -0,0 +1,146 @@ +package _edwards25519 + +import "core:crypto" +import field "core:crypto/_fiat/field_curve25519" +import scalar "core:crypto/_fiat/field_scalar25519" +import subtle "core:crypto/_subtle" + +ge_scalarmult_basepoint :: proc "contextless" (ge: ^Group_Element, sc: ^Scalar) { + when crypto.COMPACT_IMPLS == true { + ge_scalarmult(ge, &GE_BASEPOINT, sc) + } else { + tmp_sc: scalar.Non_Montgomery_Domain_Field_Element + scalar.fe_from_montgomery(&tmp_sc, sc) + + tmp_add: Add_Scratch = --- + tmp_addend: Basepoint_Addend_Group_Element = --- + + ge_identity(ge) + for i in 0..<32 { + limb := i / 8 + shift := uint(i & 7) * 8 + limb_byte := tmp_sc[limb] >> shift + + hi, lo := (limb_byte >> 4) & 0x0f, limb_byte & 0x0f + mul_bp_tbl_add(ge, &Gen_Multiply_Table_edwards25519_lo[i], lo, &tmp_add, &tmp_addend, false) + mul_bp_tbl_add(ge, &Gen_Multiply_Table_edwards25519_hi[i], hi, &tmp_add, &tmp_addend, false) + } + + zero_explicit(&tmp_sc, size_of(tmp_sc)) + zero_explicit(&tmp_add, size_of(Add_Scratch)) + zero_explicit(&tmp_addend, size_of(Basepoint_Addend_Group_Element)) + } +} + +when crypto.COMPACT_IMPLS == false { + @(private="file",rodata) + TWO_TIMES_Z2 := field.Loose_Field_Element{2, 0, 0, 0, 0} + + @(private) + Basepoint_Addend_Group_Element :: struct { + y2_minus_x2: field.Loose_Field_Element, // t1 + y2_plus_x2: field.Loose_Field_Element, // t3 + k_times_t2: field.Tight_Field_Element, // t4 + } + + @(private) + Basepoint_Multiply_Table :: [15]Basepoint_Addend_Group_Element + + @(private) + ge_bp_addend_conditional_assign :: proc "contextless" (ge_a, a: ^Basepoint_Addend_Group_Element, ctrl: int) { + field.fe_cond_select(&ge_a.y2_minus_x2, &ge_a.y2_minus_x2, &a.y2_minus_x2, ctrl) + field.fe_cond_select(&ge_a.y2_plus_x2, &ge_a.y2_plus_x2, &a.y2_plus_x2, ctrl) + field.fe_cond_select(&ge_a.k_times_t2, &ge_a.k_times_t2, &a.k_times_t2, ctrl) + } + + @(private) + ge_add_bp_addend :: proc "contextless" ( + ge, a: ^Group_Element, + b: ^Basepoint_Addend_Group_Element, + scratch: ^Add_Scratch, + ) { + // https://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3 + // Assumptions: k=2*d, z = 1 (precomputation ftw) + // + // t0 = Y1-X1 + // t1 = Y2-X2 + // A = t0*t1 + // t2 = Y1+X1 + // t3 = Y2+X2 + // B = t2*t3 + // t4 = k*T2 + // C = T1*t4 + // t5 = 2*Z2 + // D = Z1*t5 + // E = B-A + // F = D-C + // G = D+C + // H = B+A + // X3 = E*F + // Y3 = G*H + // T3 = E*H + // Z3 = F*G + // + // In order to make the scalar multiply faster, the addend is provided + // as a `Addend_Group_Element` with t1, t3, t4, and t5 precomputed, as + // it is trivially obvious that those are the only values used by the + // formula that are directly dependent on `b`, and are only dependent + // on `b` and constants. This saves 1 sub, 2 adds, and 1 multiply, + // each time the intermediate representation can be reused. + + A, B, C, D := &scratch.A, &scratch.B, &scratch.C, &scratch.D + E, F, G, H := &scratch.E, &scratch.F, &scratch.G, &scratch.H + t0, t2 := &scratch.t0, &scratch.t2 + + field.fe_sub(t0, &a.y, &a.x) + t1 := &b.y2_minus_x2 + field.fe_carry_mul(A, t0, t1) + field.fe_add(t2, &a.y, &a.x) + t3 := &b.y2_plus_x2 + field.fe_carry_mul(B, t2, t3) + t4 := &b.k_times_t2 + field.fe_carry_mul(C, field.fe_relax_cast(&a.t), field.fe_relax_cast(t4)) + field.fe_carry_mul(D, field.fe_relax_cast(&a.z), &TWO_TIMES_Z2) + field.fe_sub(E, B, A) + field.fe_sub(F, D, C) + field.fe_add(G, D, C) + field.fe_add(H, B, A) + field.fe_carry_mul(&ge.x, E, F) + field.fe_carry_mul(&ge.y, G, H) + field.fe_carry_mul(&ge.t, E, H) + field.fe_carry_mul(&ge.z, F, G) + } + + @(private) + mul_bp_tbl_add :: proc "contextless" ( + ge: ^Group_Element, + tbl: ^Basepoint_Multiply_Table, + idx: u64, + tmp_add: ^Add_Scratch, + tmp_addend: ^Basepoint_Addend_Group_Element, + unsafe_is_vartime: bool, + ) { + // Variable time lookup, with the addition omitted entirely if idx == 0. + if unsafe_is_vartime { + // Skip adding the point at infinity. + if idx != 0 { + ge_add_bp_addend(ge, ge, &tbl[idx-1], tmp_add) + } + return + } + + // Constant time lookup. + tmp_addend^ = { + // Point at infinity (0, 1, 1, 0) in precomputed form, note + // that the precomputed tables rescale so that `Z = 1`. + {1, 0, 0, 0, 0}, // y - x + {1, 0, 0, 0, 0}, // y + x + {0, 0, 0, 0, 0}, // t * 2d + } + for i := u64(1); i < 16; i = i + 1 { + ctrl := subtle.eq(i, idx) + ge_bp_addend_conditional_assign(tmp_addend, &tbl[i - 1], int(ctrl)) + } + ge_add_bp_addend(ge, ge, tmp_addend, tmp_add) + } +} diff --git a/core/crypto/_edwards25519/edwards25519_table.odin b/core/crypto/_edwards25519/edwards25519_table.odin new file mode 100644 index 000000000..029b08418 --- /dev/null +++ b/core/crypto/_edwards25519/edwards25519_table.odin @@ -0,0 +1,4947 @@ +package _edwards25519 + +/* + ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ +*/ + +import "core:crypto" + +when crypto.COMPACT_IMPLS == false { + @(private,rodata) + Gen_Multiply_Table_edwards25519_lo := [32]Basepoint_Multiply_Table { + { + { + {4566296876323096, 4708280988758944, 2883091957081722, 4842055411046963, 5717267076190079}, + {3540182452943730, 2497478415033846, 2521227595762870, 1462984067271729, 2389212253076811}, + {301289933810280, 1259582250014073, 1422107436869536, 796239922652654, 1953934009299142}, + }, + { + {4966907458672021, 4936584233144657, 6114240989277698, 5254498676225494, 4146642117106832}, + {3632771708514775, 790832306631235, 2067202295274102, 1995808275510000, 1566530869037010}, + {748439484463711, 1033211726465151, 1396005112841647, 1611506220286469, 1972177495910992}, + }, + { + {4820158664987218, 4429624038632138, 3711242400124238, 3713328211397903, 3003390509798844}, + {1601611775252272, 1720807796594148, 1132070835939856, 3512254832574799, 2147779492816910}, + {1850748884277385, 1200145853858453, 1068094770532492, 672251375690438, 1586055907191707}, + }, + { + {3946190272469145, 6239505675006654, 5208669189437987, 5151632689063553, 5199813637784664}, + {934282339813791, 1846903124198670, 1172395437954843, 1007037127761661, 1830588347719256}, + {1121406372216585, 192876649532226, 190294192191717, 1994165897297032, 2245000007398739}, + }, + { + {4928851390486164, 2860263086157808, 4946162173083730, 5341365721927258, 4878154719998387}, + {769950342298400, 2384754244604994, 3095885746880802, 3225892188161580, 2977876099231263}, + {1086255230780037, 274979815921559, 1960002765731872, 929474102396301, 1190409889297339}, + }, + { + {4510980453010577, 4649810060060977, 4808503203819400, 5702468951241614, 3249489646904341}, + {1388594989461809, 316767091099457, 2646098655878230, 1230079486801004, 1440737038838979}, + {1181317918772081, 114573476638901, 262805072233344, 265712217171332, 294181933805782}, + }, + { + {4271167442657675, 2928511714391884, 4614310625181828, 3360446656227271, 5021391587042608}, + {2916800678241215, 2065379846933858, 2622030924071124, 2602788184473875, 1233371373142984}, + {965130719900578, 247011430587952, 526356006571389, 91986625355052, 2157223321444601}, + }, + { + {4325401225737414, 4534620752133203, 4768100597167576, 4751634318022197, 3282052041613534}, + {4320419353804412, 4218074731744053, 957728544705548, 729906502578991, 2411634706750414}, + {551790716293402, 1989538725166328, 801169423371717, 2052451893578887, 678432056995012}, + }, + { + {6229274597883966, 4185445767544427, 3794144352961029, 6271388400944242, 5801047593299399}, + {1802695059464988, 1664899123557221, 2845359304426105, 2160434469266658, 3179370264440279}, + {1381809363726107, 1430341051343062, 2061843536018959, 1551778050872521, 2036394857967624}, + }, + { + {3190293695332791, 4165728475672253, 4346255112396895, 3238346181288697, 4562115113555210}, + {1569908045411451, 706723917266915, 1500941167088851, 2522858060362189, 3442327746686552}, + {1454533688490200, 416156769327623, 1344514353803379, 1816391251363763, 259908591619060}, + }, + { + {4322190032257826, 3710718875543082, 5127771470387916, 5558932420078259, 4937587148103002}, + {4222693909998302, 2779866139518454, 1619374932191226, 2207306624415883, 1169170329061080}, + {893653801273833, 1168026499324677, 1242553501121234, 1306366254304474, 1086752658510815}, + }, + { + {4366666225767590, 5094682881462444, 5444160766003964, 2663859630225193, 4386427788371457}, + {1548398643541286, 3090755542662214, 2368065889335542, 1878116023572279, 2384475613352909}, + {1571032457823571, 1253760059932116, 665829584253800, 109400965270906, 981221002823741}, + }, + { + {6475278226276205, 4841626135259659, 5265997707342765, 5158696113477971, 4545898660066816}, + {2465253816303469, 3191571337672685, 1159882208056013, 2569188183312765, 621213314200686}, + {177130678690680, 1754759263300204, 1864311296286618, 1180675631479880, 1292726903152791}, + }, + { + {3248252964508250, 5061531253750778, 5542769770211014, 4619085244233909, 5311803534193606}, + {2375959787421170, 2263885670311134, 2822409136676350, 3122669455540755, 1947192330052816}, + {498660636760962, 1605652986893012, 893278769679967, 1769999239723039, 646478004325289}, + }, + { + {5574001150447352, 3524291821486207, 4161953422248557, 4327379335382018, 3442969602526468}, + {1913163449625248, 2712579013977241, 2193883288642313, 1008900146920800, 1721983679009502}, + {692896803108118, 500174642072499, 2068223309439677, 1162190621851337, 1426986007309901}, + }, + }, + { + { + {5457238221803851, 3344133750480297, 5923374394087185, 3057477798065323, 3111028807187760}, + {1368953770187805, 3042147450398169, 2689308289352409, 2142576377050579, 1932081720066286}, + {1200766035879111, 20142053207432, 1465634435977050, 1645256912097844, 295121984874596}, + }, + { + {5563698449899448, 3838625675758736, 4715900944610621, 4227102525088801, 5170323687134830}, + {1735718747031538, 1248237894295956, 1204753118328107, 976066523550493, 2317743583219840}, + {1091990273418756, 1572899409348578, 80968014455247, 306009358661350, 1520450739132526}, + }, + { + {4403130087311393, 3013844998431429, 3939874146236762, 3074845922691006, 3159402582764738}, + {3732317023121341, 1511153322193951, 3496143672676420, 2556587964178488, 2620936670181690}, + {2047386910586836, 168470092900250, 1552838872594810, 340951180073789, 360819374702533}, + }, + { + {5483833971283375, 6215856366616550, 5092534899560758, 4707898440462492, 3093598134728534}, + {1982622644432037, 2014393600336956, 2380709022489462, 3869592437614438, 2357094095599062}, + {197561292938973, 454817274782871, 1963754960082318, 2113372252160468, 971377527342673}, + }, + { + {5235862574050758, 3926212577912309, 4434256219348056, 5854494381844745, 2810258686980493}, + {2416499262514576, 2254927265442919, 3451304785234000, 1766155447043651, 1899238924683527}, + {2103305098582922, 1960809151316468, 715134605001343, 1454892949167181, 40827143824949}, + }, + { + {4483855840793217, 3239143728269862, 4367394306679708, 4071397886477406, 3371105467700097}, + {1239289043050193, 1744654158124578, 758702410031698, 4048562808759936, 2253402870349013}, + {320153677847348, 939613871605645, 641883205761567, 1930009789398224, 329165806634126}, + }, + { + {4780421392687930, 3788635404873276, 3557012555097608, 4565073531580670, 4303176850668304}, + {3232730304159378, 1242488692177892, 1251446316964684, 1086618677993530, 1961430968465772}, + {833449923882501, 1750270368490475, 1123347002068295, 185477424765687, 278090826653186}, + }, + { + {3756645926444593, 3454896102689928, 5065739048841913, 4777932644822338, 3536143867460687}, + {794524995833413, 1849907304548286, 2305148486158393, 1272368559505216, 1147304168324779}, + {483048732424432, 2116063063343382, 30120189902313, 292451576741007, 1156379271702225}, + }, + { + {5884070579505425, 5535277330947453, 5603542025663670, 4776593639127153, 4995715838681551}, + {2505290486961759, 2288457607049763, 1322694247668132, 2996684795874985, 1441775943403867}, + {1862130357601747, 1576563056403606, 1053598539514442, 836379099899856, 1745075449649052}, + }, + { + {4271432792719273, 4354519732898601, 3841949260311002, 4278872468826501, 3182588946344969}, + {994086190120795, 2265566763472579, 1778668799717474, 1759565368702851, 1705243805775865}, + {208457126969992, 1306788169067141, 1504881061177412, 778305094530678, 286650467791603}, + }, + { + {3704308183084302, 4667642921024280, 3735446294701327, 4710970560312866, 5219863835152358}, + {1155946475009464, 1378854908418478, 3050476655608427, 738141412602796, 1805371589338096}, + {1627667107954997, 2038498693464737, 380348381597727, 693747096546728, 1241364634477378}, + }, + { + {4610118268113321, 3236474426265456, 4804410568671572, 4099577866548348, 3504102383946080}, + {748123900738723, 2239140288387656, 322477057520882, 2644973441419796, 1290933190145308}, + {2218076336525385, 339947754397137, 1735892619490, 1441988709036711, 932991353908008}, + }, + { + {5176295056640358, 3403895808063209, 3860193783232080, 4018349594328251, 4528337169205809}, + {2638983432827646, 2268258692789757, 3287339174338050, 1299412654822337, 936917254750873}, + {430804656367208, 1812394904738259, 550528638373630, 2103769550939254, 443986453677108}, + }, + { + {4019814909194368, 2925457503142305, 3944973873459804, 4250278944002558, 4031746156495663}, + {3925945607985574, 2164215477088927, 2286513560718006, 3385980103702156, 1734257170111047}, + {38890723392351, 853701573154564, 966467672212375, 417321296433946, 554926061377915}, + }, + { + {5000002949084352, 4896484517581292, 5148976024567894, 4815058842461170, 4176010608048328}, + {1720782684885150, 798987029915204, 1610161967147136, 3970529737234552, 936254274515738}, + {562662523022136, 737396420860869, 1964828496205405, 271079414894445, 1393713695470127}, + }, + }, + { + { + {4641332589184683, 2958470737602587, 5890637714236266, 6469243441056846, 3636576929381593}, + {3180171966714267, 2147692869914563, 1455665844462196, 1986737809425946, 2437006863943337}, + {481144981981577, 2053319313589856, 2065402289827512, 617954271490316, 1106602634668125}, + }, + { + {5160989980743332, 3250299780570808, 5495492964276292, 5314069834477255, 2594939618294032}, + {2948097833334040, 3145099472726142, 1148636718636008, 2278533891034865, 2203955659340680}, + {791736669492960, 934767652997115, 824656780392914, 1759463253018643, 361530362383518}, + }, + { + {5791086827335700, 4467111755065554, 3804728204617233, 6168459157050691, 3376804788950489}, + {2022541353055578, 4346500076272714, 3802807888710933, 2494585331103411, 2947785218648809}, + {677434665154918, 989582503122485, 1817429540898386, 1052904935475344, 1143826298169798}, + }, + { + {3025160502526487, 6318980957908565, 4867373065037870, 5043229614440699, 3035080247933683}, + {2619066141993637, 2570231002607651, 2947429167440602, 2885885471266079, 2276381426249673}, + {180820816194166, 168937968377394, 748416242794470, 1227281252254508, 1567587861004268}, + }, + { + {4236540720225255, 5582763806770724, 3307821162947907, 3911758370168910, 3340328882710774}, + {2730575372268893, 2062896624554806, 2951191072970647, 2609899222113120, 1277310261461760}, + {580736401511151, 1842931091388998, 1177201471228238, 2075460256527244, 1301133425678027}, + }, + { + {3547095551954881, 3966542127392273, 5049182669833076, 6538011303633046, 3765047903698852}, + {1515728832059163, 1575261009617579, 1510246567196186, 2442877836294952, 2368461529974388}, + {230710545179830, 30821514358353, 760704303452229, 390668103790604, 573437871383156}, + }, + { + {4354054137171033, 3822632479902001, 4538296533915119, 4245013553492583, 4574238179641958}, + {3421179921230875, 2514967047430861, 4274701112739695, 3071700566936367, 4275698278559832}, + {894132856735058, 548675863558441, 845349339503395, 1942269668326667, 1615682209874691}, + }, + { + {5296988143897756, 3567256897335281, 4224086813027664, 4153625766737702, 4841869104592905}, + {3539470031223082, 1222355136884919, 1846481788678694, 1150426571265110, 1613523400722047}, + {550201530671806, 778605267108140, 2063911101902983, 115500557286349, 2041641272971022}, + }, + { + {2639140850252425, 3988225053741778, 4109492541046027, 4467731762307139, 4788525019017799}, + {1956266817271455, 2914237312642832, 2018010448016151, 4042065159660719, 3422400064417223}, + {1185820244523867, 953640094456191, 1426524678517613, 1191533398208458, 1993578549159852}, + }, + { + {4724762102005390, 3941768459309593, 3168985852401486, 5230753070525336, 5120855380354436}, + {2162922301975048, 2584871642802941, 2903836488265486, 2034914383000476, 1973107217149520}, + {1225503059018859, 1744932331605022, 393061606917651, 2045141059558447, 1187823695528756}, + }, + { + {3873867956612972, 5901886943623014, 4214442512189194, 3726570129804851, 4003114175771373}, + {2499971111138236, 1856344473990516, 2851460465748678, 1490509710033167, 3414551741933391}, + {1569106592395768, 1670704805332568, 2011861983976474, 822492307064908, 1138495702641636}, + }, + { + {4611233673112936, 4109919865110418, 3874636387071312, 4304609757893158, 4158539624577373}, + {3888656531434102, 3371559592472684, 2495053387333630, 3579436360572308, 1114431352259831}, + {2209993507106795, 1762615018349199, 1687296090930185, 9491601628221, 870532128794902}, + }, + { + {4833972836221169, 5399132877586271, 4606616407949355, 4080860583790927, 4239964386503137}, + {1305913677624121, 3558400184075999, 3275823038503467, 3454063433790229, 1309514508446881}, + {1566723549675548, 1397175496983691, 504231980459915, 306990234666329, 1744893526714441}, + }, + { + {4014795958128859, 5054570465100501, 3081378639295577, 5833550217358299, 3899560884622359}, + {972376391789061, 1850852472634117, 2719443704140285, 2186622623776515, 3209686661433313}, + {2171782442569495, 1594104418173184, 1848207566547320, 2195471209947031, 1091928745815642}, + }, + { + {4698583634348737, 4028817484747578, 3922491723357167, 4921897981297279, 5070174707952522}, + {3952749170677737, 509151538148928, 2600240333845125, 2270835069234179, 3790913978189516}, + {1587050028613976, 1757976429633698, 440367736554514, 102469500615778, 1293087093446941}, + }, + }, + { + { + {4765314848902696, 4047154143755239, 3748677840535530, 5003339347891547, 4892630780044264}, + {717255318455100, 519313764361315, 2080406977303708, 541981206705521, 774328150311600}, + {1997217696294013, 1717306351628065, 1684313917746180, 1644426076011410, 1857378133465451}, + }, + { + {4274106452868777, 5229895690942370, 4818944681819138, 3310533142834467, 5951800763431172}, + {3727234538477877, 2328731709971226, 3368528843456914, 2002544139318041, 2977347647489186}, + {1710065158525665, 1895094923036397, 123988286168546, 1145519900776355, 1607510767693874}, + }, + { + {6052094801116259, 4945910156597034, 3249872360685630, 5056653985755776, 5148423953746665}, + {2813405189107769, 1071733543815036, 2383296312486238, 1946868434569998, 3079937947649451}, + {1445526537029440, 2225519789662536, 914628859347385, 1064754194555068, 1660295614401091}, + }, + { + {5380526401591301, 2806418790173460, 3263856123526812, 3091761635239858, 3666299153992924}, + {3451490036797185, 2275827949507588, 2318438102929588, 2309425969971222, 2816893781664854}, + {703047626104145, 1266841406201770, 165556500219173, 486991595001879, 1011325891650656}, + }, + { + {4838486554794399, 4993110726592022, 4632760493337220, 3972608926828727, 2871500009334501}, + {1622861044480487, 1156394801573634, 4120932379100752, 2578903799462977, 2095342781472283}, + {1646545795166119, 1758370782583567, 714746174550637, 1472693650165135, 898994790308209}, + }, + { + {4062996033667232, 5572569452904097, 4793202602203933, 4240755857296838, 5367161970768862}, + {2585203586724508, 2547572356138185, 1693106465353609, 912330357530760, 2723035471635610}, + {906282429780072, 2108672665779781, 432396390473936, 150625823801893, 1708930497638539}, + }, + { + {3731585820952935, 6242481486437170, 4572245823847061, 4398306869785574, 5751262444905966}, + {925664675702309, 2273216662253932, 4083236455546587, 601157008940112, 2623617868729744}, + {52035296774456, 939969390708103, 312023458773250, 59873523517659, 1231345905848899}, + }, + { + {4632957969763174, 4184611431390023, 5680349018170176, 4901639977232284, 5674379295460919}, + {2895154920100990, 2541986621181021, 2013561737429022, 2571447883196794, 2645536492181409}, + {2051980782668029, 121859921510665, 2048329875753063, 1235229850149665, 519062146124755}, + }, + { + {4207228868621988, 4953881226819951, 4139842782246336, 4298958943276773, 3359727402165629}, + {947983997565204, 1512975730400883, 4017071259732234, 765863411195419, 2287620622340759}, + {2248717923990509, 953644234015146, 118881148429301, 1244045737066019, 519708790776758}, + }, + { + {5697680122778496, 6228365759267448, 4861216723530833, 4702869303488893, 5552489090348314}, + {1440754265571108, 2717772629254708, 2851948946836421, 3389483713931559, 1448786922664578}, + {843777949621211, 1435525643946674, 1087149831109219, 1794919173070415, 1112222323032617}, + }, + { + {5102037877608319, 4652686712219969, 3897951345871191, 3585818368367414, 5206224086433126}, + {1659077274827511, 3292962448731851, 3877468219103951, 1516723029470630, 2756801757695330}, + {1080269027468022, 217052522911549, 1656325362355128, 1627927536138189, 547476742306034}, + }, + { + {4629572650764889, 5482991583454262, 5026118951697692, 3386284302539994, 4183091862778757}, + {4049116095173975, 2853051218008192, 874408124299498, 2811479573934506, 3061819813989639}, + {1673853233469462, 2069508754540826, 444570721431342, 318669192295723, 1286647860911061}, + }, + { + {5230179910306733, 4570722910725029, 2679420725332655, 3219299251684998, 5101899978929471}, + {3368016050367733, 1864179846991811, 2025579249953153, 2185933453914170, 3081358815633795}, + {1120488984292940, 268864491510849, 230793761352121, 54153081190951, 1544798876643945}, + }, + { + {4594071143939477, 4032573207368795, 3586642054806445, 2633280388282362, 4204685405148786}, + {3215023450765629, 1989745848107067, 2317683847606295, 2073505048594828, 792770882411102}, + {213368529611304, 716996641453362, 1913278462832177, 1585475497182388, 563601091454134}, + }, + { + {2835663672936090, 4829603014808807, 3487022863582034, 2792788055117753, 4407939774570859}, + {1893732627269868, 2896260158734549, 1988156739597398, 2606708976150985, 1947694156880429}, + {1687313081048019, 7705508083870, 487993091259388, 560742684726806, 779697153923449}, + }, + }, + { + { + {4089455896800313, 6013733676182565, 5409863301562555, 4072864011490980, 5068974752046796}, + {3859970785658325, 2667608874045675, 1350468408164765, 2038620059057678, 3278704299674360}, + {578027192365650, 2034800251375322, 2128954087207123, 478816193810521, 2196171989962750}, + }, + { + {4965788985850512, 4036616547844474, 3863134115336615, 3555738077628787, 5211189187689919}, + {1633188840273120, 3104586986058956, 1548762607215795, 1266275218902681, 3359018017010381}, + {1038829280972848, 38176604650029, 753193246598573, 1136076426528122, 595709990562434}, + }, + { + {4508300680732578, 6151240693672842, 5551152629612579, 4175434827081223, 4710569942272560}, + {3660251634545082, 2194984964010832, 2198361797561729, 1061962440055713, 1645147963442934}, + {1750479161778571, 1362553355169293, 1891721260220598, 966109370862782, 1024913988299801}, + }, + { + {5140408161043668, 3514001525352806, 4894551007701094, 3915220506382540, 5065550949127901}, + {2464498862816952, 1117950018299774, 1873945661751056, 3655602735669306, 2382695896337945}, + {520731594438141, 1446301499955692, 273753264629267, 1565101517999256, 1019411827004672}, + }, + { + {3716451775537782, 3735537109406964, 3771250375020764, 3413229645449032, 4909514625550472}, + {3178327305714638, 3443653291096626, 734233225181170, 2435838701226518, 4042225960010590}, + {996126634382301, 796204125879525, 127517800546509, 344155944689303, 615279846169038}, + }, + { + {5126516964784293, 5722588804459529, 5788457340217086, 5474101689079853, 4854624835487584}, + {2990523894660505, 2188666632415295, 1961313708559162, 1506545807547587, 3403101452654988}, + {2067814584765580, 1677855129927492, 2086109782475197, 235286517313238, 1416314046739645}, + }, + { + {5182089550298661, 4268457398409278, 4594577010420123, 5530431534605076, 5118871120313016}, + {2838644076315587, 2559244195637442, 458399356043425, 2853867838192310, 3280348017100490}, + {301225714012278, 1094837270268560, 1202288391010439, 644352775178361, 1647055902137983}, + }, + { + {5639203700568665, 3935121894170720, 5272747431747178, 4338487944274660, 5404045310490874}, + {1210746697896459, 1416608304244708, 2938287290903104, 3496931005119382, 3303038150540984}, + {1971518477615628, 401909519527336, 448627091057375, 1409486868273821, 1214789035034363}, + }, + { + {5099963449143288, 5521329395009146, 5925708408867572, 4221709339736212, 4612387286592975}, + {1894554173291056, 3439387781984292, 2885767225889068, 620075308547710, 1923191105660691}, + {2193142205372254, 2249202758109308, 136771833945490, 2136446252990850, 1913453314551631}, + }, + { + {3519416739470062, 5800837512824035, 5629830750568439, 3858242948002290, 4384918516791051}, + {1031287572005306, 2743053635058531, 1307200063174499, 886968262945288, 322139622562321}, + {1603190765881197, 1131168289986667, 1851325240689452, 1811918922856612, 1688789764638099}, + }, + { + {5675121438563826, 3813646429348722, 6155915780969232, 4550135853787182, 3281226794470063}, + {1227916715088978, 3565721991039408, 2825753167382054, 446650609575830, 3201068492916497}, + {465975618381320, 1757724298980204, 2172737911773281, 1844204403201116, 367200393612929}, + }, + { + {4053304559591831, 4763567221009860, 6256382270106074, 5569940279565028, 4297628970970611}, + {522695684014153, 2454309386747442, 1812320598717590, 1790060723730286, 513480358702681}, + {1695032670616248, 1588968761785032, 699742416328216, 547685855993128, 1790235994988743}, + }, + { + {3776137870634381, 3800031162558423, 5542451196069607, 4330978223940644, 5450131593237007}, + {3411403847639229, 1506626399353463, 2324339461338721, 1195836709245006, 2829489236982793}, + {263703254267006, 1082588170565097, 2024394221181425, 46543794553459, 2110417854356146}, + }, + { + {5712489756196259, 4857601027744288, 4243491518458906, 4901936639181452, 4456074323550475}, + {2520601556174181, 1164555774547222, 2770926848501726, 3208860864993280, 497236288525621}, + {247502314830666, 1623351904090299, 1162047175878913, 1697644630093486, 776531516340321}, + }, + { + {2686302584388573, 3722578779150130, 6045187633044733, 3467509394641570, 3302975571798606}, + {2408284467064191, 2899235622132542, 2270755745458389, 1460665123127634, 2622446416668442}, + {625008843842459, 305089228555404, 1124988453243439, 123919845855976, 788637610781258}, + }, + }, + { + { + {3297030136943183, 5321806228516302, 2882313002761349, 3923846342683379, 5310803644932932}, + {1364039144731711, 1897497433586190, 2203097701135459, 2397261210496499, 1349844460790698}, + {439961968385997, 386362664488986, 1382706320807688, 309894000125359, 2207801346498567}, + }, + { + {4255565910583278, 4673673686605660, 3392924072653217, 3737219707166220, 3825562634713972}, + {3480804500082836, 3172443782216110, 2375775707596425, 2933223806901024, 1400559197080972}, + {729905708611432, 1270323270673202, 123353058984288, 426460209632942, 2195574535456672}, + }, + { + {4013408251151364, 5086960474897299, 3838506203370739, 4408856413264508, 3422492183371019}, + {1271140255321216, 2044363183174497, 2303925201319937, 3696920060379952, 3194341800024331}, + {871476219910823, 1878769545097794, 2241832391238412, 548957640601001, 690047440233174}, + }, + { + {3251428812313581, 5636436335863895, 4336541488202699, 4972942980386107, 5182382616078529}, + {2548994545820755, 1366347803776819, 3552985325930849, 561849853336293, 1533554921345731}, + {2189427607417022, 699801937082607, 412764402319267, 1478091893643349, 2244675696854460}, + }, + { + {5012160783311108, 5470528103057159, 4488517614835378, 2676343672262544, 4341072770671390}, + {3964091869651792, 2456213404310121, 3657538451018088, 2660781114515010, 3112882032961968}, + {221245220129925, 1156020201681217, 491145634799213, 542422431960839, 828100817819207}, + }, + { + {2810886626483710, 5076777331583206, 6133336711186896, 3651619527147841, 3898754191951285}, + {2405556784925632, 1299874139923976, 2644898978945750, 1058234455773021, 996989038681183}, + {1887963056288059, 228507035730124, 1468368348640282, 930557653420194, 613513962454686}, + }, + { + {5579887344422086, 5618055197913529, 4690896687085975, 4754046511662615, 4136987326235786}, + {1224529808187534, 1577022856702685, 2206946542980843, 625883007765001, 2531730607197406}, + {902497362940219, 76749815795675, 1657927525633846, 1420238379745202, 1340321636548352}, + }, + { + {5132340287409247, 4194838312213087, 4971385975164381, 5596941055673869, 4739013486883497}, + {1129576631190765, 3533793823712575, 996844254743017, 2509676177174497, 3402650555740265}, + {237425418909360, 469614029179605, 1512389769174935, 1241726368345357, 441602891065214}, + }, + { + {5266234055777943, 3166499093963215, 4159587332862448, 3232787848503690, 6261694765772425}, + {2508069708566903, 2982887287210837, 1712829089863354, 1739545432690564, 1853100260794477}, + {4642168584761, 1314096799362798, 1620739012635580, 444075187404753, 76135520441225}, + }, + { + {5167832514805982, 5410004641404511, 3809624149844670, 4773980049888932, 3778278866830004}, + {1717340294466846, 3145810307460687, 1904170181110298, 3950114374260626, 2248427553137502}, + {1356583144121446, 1439603152129038, 880464721166116, 426511648446184, 1044401386572766}, + }, + { + {3827273464157640, 5470853620720833, 4235776821907793, 5432246822532161, 4674460658804935}, + {3682691082267936, 1935676112917301, 3170276622979891, 2876033130676637, 1596266630249199}, + {1484505136430423, 343818915658679, 1066931341976591, 1574952097402529, 895157643469052}, + }, + { + {6636210482709397, 2566644085561849, 4278449441656290, 5708653335234549, 6540605640281063}, + {2193735258244385, 2265742668153213, 2801601661178220, 1573679250261669, 2218164822512395}, + {125908919015544, 908539856510216, 254196493329521, 1841783557943867, 1826956209112337}, + }, + { + {4015848574593688, 5374261932338028, 4759505940569418, 5686761164384680, 3410517186063399}, + {1218465765165754, 1222399589933778, 4149598104194804, 2307999947285970, 2530437726498307}, + {1352017428769842, 1226345478088737, 1834808987089176, 171935268241134, 1252599135760918}, + }, + { + {4391913968320982, 5643346087738336, 3260878495624279, 6345563729780486, 6485738780527396}, + {269241043449612, 1713401415896622, 3060740655644691, 2228155591500882, 2273523243235430}, + {994025955714788, 1395495501299355, 1717525291885154, 64780760930213, 1492125616744822}, + }, + { + {4496571738540020, 6137682561017990, 4165346179942417, 4589212756752962, 5249152453870163}, + {2859457773452122, 2592803086422694, 761249806099561, 4355723617152898, 2688955778843975}, + {686675614020084, 1129369471718576, 1361332769753183, 814390480194826, 1958437091006724}, + }, + }, + { + { + {4212554477605918, 5000640585259457, 4161632664968341, 3523231950682073, 4471580181706187}, + {3988217766743784, 726531315520507, 1833335034432527, 1629442561574747, 2876218732971333}, + {1537037379417136, 1358865369268262, 2130838645654099, 828733687040705, 1999987652890901}, + }, + { + {4063362146350583, 3753681832692920, 4465563314774246, 4863172707090131, 4539970192419610}, + {629042105241795, 1098854999137608, 887281544569320, 3674901833560025, 2259711072636808}, + {218907117361280, 1209298913016966, 1944312619096112, 1130690631451061, 1342327389191701}, + }, + { + {4482501699248035, 5851772807709469, 4424655942309844, 5930138373494266, 4947793108696645}, + {1369976867854685, 1396479602419169, 4017456468084104, 2203659200586298, 3250127649802489}, + {784210426627951, 918204562375674, 1284546780452985, 1324534636134684, 1872449409642708}, + }, + { + {4153660020381144, 4256288935750983, 3877646875253483, 3225329557085126, 4327087498998152}, + {2571438643225542, 2848082470493653, 2037902696412607, 1557219121643918, 341938082688094}, + {1371853944110545, 1042332820512553, 1949855697918254, 1791195775521505, 37487364849293}, + }, + { + {4334516943269102, 4531429052909917, 4649254694042464, 3942327023530758, 6368860137043973}, + {687200189577836, 1082536651125675, 2896024754556794, 2592723009743198, 2595381160432643}, + {1059729620568824, 2163709103470266, 1440302280256872, 1769143160546397, 869830310425069}, + }, + { + {4276621734726805, 4930548302820644, 2846933097770719, 4975460488256465, 2852121493098246}, + {3861316033464273, 777277757338816, 2101121130363987, 550762194946473, 1905542338659364}, + {598474602406721, 1468128276358244, 1191923149557635, 1501376424093216, 1281662691293476}, + }, + { + {2971320059272372, 4896980339002840, 4635950028233875, 3795071084495975, 4071343109483907}, + {1721138489890688, 1264336102277790, 2684864359106535, 1359988423149465, 3813671107094695}, + {396397949784152, 1811354474471839, 1362679985304303, 2117033964846756, 498041172552279}, + }, + { + {5154223559778472, 3389351102095821, 4377023217300786, 3977457826906518, 4386692778803043}, + {1812471844975748, 1856491995543149, 126579494584102, 3288044672967868, 1975108050082549}, + {522584000310195, 1241762481390450, 1743702789495384, 2227404127826575, 1686746002148897}, + }, + { + {4080889153606423, 5116319911316914, 4006591728131774, 4350736921528591, 4198995697088691}, + {3932341308304797, 1612580099028530, 2937385230920440, 1836672506516533, 517164940700103}, + {1413348606155183, 810499206093511, 1138057743946731, 1556315649471799, 993617155135620}, + }, + { + {5656453792030509, 6079591987914126, 5929179648294721, 5230798899043491, 3370342887971873}, + {2735841961308013, 2116601197688202, 2652241807415589, 1945152844924315, 2885012584681659}, + {551620533268687, 1182887684657061, 1043366705332762, 944140538303658, 2240921917214007}, + }, + { + {2427888929082724, 4467682652740956, 5335339067201761, 5550886290485514, 5050956980777821}, + {2247945978763224, 215736457901546, 1047424049356243, 1389596126698944, 816935367913617}, + {1146743855918524, 1418503734887175, 843342293437400, 1502230097098390, 1240491010654824}, + }, + { + {6701933119211633, 5059229274152685, 4982837924778640, 4159052306481152, 4290369756778959}, + {2204538589507457, 3142843240983995, 2451576614290660, 3204217003708084, 2887474477188681}, + {510455031824465, 465163402943305, 2022658124081289, 1881132727821470, 31746160856543}, + }, + { + {5097091659825113, 2826376647382075, 3998920599703675, 3513481695405562, 5076475699131519}, + {1330330618013145, 2313004235002329, 3963525218487729, 2303930585911304, 2755772190474933}, + {944243695677568, 255912283647788, 1855489019383837, 1244636060478392, 1911682985774639}, + }, + { + {5024454158738700, 2514912085825565, 3852574473189297, 4034915921452192, 3904120669219782}, + {3843903221055742, 2416642267747155, 1715729591405051, 1735036083660438, 1182009761997504}, + {1140604273028187, 1352033415206334, 1448886815181311, 941652546197192, 1001542060535421}, + }, + { + {4277058348919964, 5364603224614130, 5366326037527057, 4814184001945705, 5895346951506596}, + {3602696745610322, 2198425366751348, 1768623515003979, 2456584282641319, 3022619356175890}, + {1305849451281975, 726672899606505, 2105928429843370, 246834240873219, 1573506984361288}, + }, + }, + { + { + {4821701574825479, 4751738035366345, 3733704008989173, 4812878081681692, 3510316573903125}, + {427904865186293, 1703211129693455, 1585368107547509, 3688784302429584, 3012988348299225}, + {1275068538599310, 513726919533379, 349926553492294, 688428871968420, 1702400196000666}, + }, + { + {3810616250567627, 4214696146321770, 5841309449432647, 3753213644462184, 4798035793202427}, + {3313663849950481, 3213411074010628, 2573659446386085, 3297400443644764, 1985130202504037}, + {818359826554971, 1862173000996177, 626821592884859, 573655738872376, 1749691246745455}, + }, + { + {4398313517418541, 5088388527765162, 4968565284650452, 4435773453041373, 4741970786827285}, + {1988022651432119, 3333911312271288, 1834020786104820, 3706626690108935, 692929915223121}, + {1129007025494441, 2197883144413266, 265142755578169, 971864464758890, 1983715884903702}, + }, + { + {4948148597287912, 3704086267538602, 4365531255192057, 2896988087581106, 5313917252680007}, + {1291366624493056, 2633256531874362, 1711482489312443, 1815233647702022, 3144079596677715}, + {2242724082797924, 1373354730327868, 1006520110883049, 2147330369940688, 1151816104883620}, + }, + { + {4667323107306775, 4619024517173644, 3407816205266473, 6398541848123859, 4222349233671575}, + {3997520014069025, 4163522956860564, 2056329390702073, 2607026987995097, 3131032608056347}, + {681981452362484, 267208874112496, 1374683991933094, 638600984916117, 646178654558546}, + }, + { + {2512483707152304, 5357659933447732, 5417239179350606, 4508304204210617, 2532054624493958}, + {2265178468539480, 2358037120714814, 1944412051589650, 4093776581610705, 2482502633520820}, + {715374893080287, 1173334812210491, 1806524662079626, 1894596008000979, 398905715033393}, + }, + { + {4348221360643351, 4174322814635610, 5293430650247335, 4930894772059273, 4824523600532224}, + {2751826223412909, 3848231101880618, 1420380351989369, 3237011375206737, 392444930785632}, + {1927770723575450, 1485792977512719, 1850996108474547, 551696031508956, 2126047405475647}, + }, + { + {2635705015322199, 3111746811317117, 5359223495008139, 3268925594263041, 3046050645563056}, + {2112099158080129, 2994370617594963, 2258284371762679, 1951119898618915, 2344890196388664}, + {77571826285752, 999304298101753, 487841111777762, 1038031143212339, 339066367948762}, + }, + { + {5619164208408509, 4079972709845361, 3927824185200012, 3681293890692042, 5452751544406703}, + {2191882696778049, 531264700870777, 3039670365049278, 1359665656266722, 3162072763716517}, + {1570940255668145, 688547574737286, 1632136413236589, 2053774689811525, 676669102580803}, + }, + { + {5183231995448322, 4155796849234556, 4791323788081582, 4471675968988079, 5711715782924180}, + {3207409007530338, 935702897763596, 729948770061474, 1584905172662705, 2425339805308626}, + {288239669792058, 2152796035840109, 162317061559789, 1257054119617939, 421141027109762}, + }, + { + {4958697699223355, 3221953471379609, 2818398572467973, 5875894486831009, 3850357049774603}, + {642422906756119, 3171839279489789, 1695193497886789, 3040583315302385, 3362141503479163}, + {1042979452017909, 1774768735282920, 464726722030945, 1465185933073826, 1382968477576580}, + }, + { + {3858506126065685, 4410239993278318, 3464562222229353, 3841799127123745, 3236074797259687}, + {3342987691574741, 2002872538662690, 3240810091817983, 3479310152893167, 2490884376592639}, + {2139337814897324, 178720275772072, 596052025976159, 666224594355251, 630639510547398}, + }, + { + {2744437082123657, 4441348097375482, 3869182720347428, 4304304367735980, 3086995265547722}, + {2392789380667179, 812658446707360, 1599624958311986, 214741817968452, 1436587626236000}, + {130387450082061, 1779587373012878, 417414670169839, 716150862374041, 154849814949784}, + }, + { + {4442837550688441, 4997631045842130, 5291735080737359, 4549950120656089, 4456650325708853}, + {2746366883922045, 2305345226446032, 2885706560860073, 4092938150156125, 656228807731693}, + {1456049106825164, 137394514200521, 2140871605490631, 1643256698410764, 679389221519059}, + }, + { + {3925184987729414, 3825370065750239, 2928329430708313, 5366989011209685, 4444246216420488}, + {2346187442256272, 1014027377437197, 2069628555505675, 1559427210701775, 1456229816012936}, + {2009324336353948, 1468073297564484, 1969534512584396, 827056802549955, 104599952309039}, + }, + }, + { + { + {5505012288893163, 2599996010752544, 3918414180409193, 3140224808718007, 2832547501486604}, + {2926794589205781, 2517835660016036, 826951213393477, 1405007746162285, 1781791018620876}, + {1939560076207777, 1409892634407635, 552574736069277, 383854338280405, 190706709864139}, + }, + { + {5180561690600497, 4132075350834054, 4298520825287953, 5392062874453498, 5821901179394561}, + {2177087163428741, 1439255351721944, 3459870654068041, 2230616362004768, 1396886392021913}, + {1466980508178206, 617045217998949, 652303580573628, 757303753529064, 207583137376902}, + }, + { + {4105782219090338, 4130463869936394, 6031610648174487, 5523226095524059, 5632038039559529}, + {3762856566592150, 2357202940576524, 2745234706458093, 1091943425335975, 1802717338077427}, + {1963939888391106, 293456433791664, 697897559513649, 985882796904380, 796244541237972}, + }, + { + {3680158110175880, 5530714909790973, 4808440325428831, 4945009801397122, 4071158169963819}, + {2668570812315008, 2641455366112301, 1314476859406755, 1749382513022778, 3413705412424739}, + {204943430200135, 1554861433819175, 216426658514651, 264149070665950, 2047097371738319}, + }, + { + {5165635210954903, 4790335732463592, 5635372627881110, 5322093841581933, 4976543419424973}, + {1934415182909015, 1393285083565062, 2768209145458208, 3409490548679139, 2372839480279515}, + {665784778135882, 1893179629898606, 808313193813106, 276797254706413, 1563426179676396}, + }, + { + {4283233217201481, 4707596242598657, 4674086796207577, 5485113232161884, 3095373778602077}, + {945205108984213, 2778077376644543, 1324180513733565, 1666970227868664, 2405347422974421}, + {1476570093962618, 838514669399805, 1857930577281364, 2017007352225784, 317085545220047}, + }, + { + {3545343323078703, 4395424422887793, 5561961194168003, 4717696754764488, 3198688329157975}, + {1461557121912823, 1600674043318359, 2157134900399597, 1670641601940616, 2379565397488531}, + {357067959932916, 1290876214345711, 521245575443703, 1494975468601005, 800942377643885}, + }, + { + {5120856274973686, 3903907574784685, 4109012860330718, 3337396988900217, 3069232573515769}, + {2817916472785262, 820247422481739, 994464017954148, 2578957425371613, 2344391131796991}, + {771808161440705, 1323510426395069, 680497615846440, 851580615547985, 1320806384849017}, + }, + { + {6662756671601401, 5055771079546289, 4642910898897859, 4274227027260534, 5833718441044794}, + {2335519494956627, 3820365010713627, 1944201046475949, 1640913863967574, 2358631279976586}, + {990528501134234, 1330224017810407, 1573804236508381, 942270438439677, 25201841708767}, + }, + { + {5526427987749634, 4518401023168866, 4921120012283882, 4779318497665973, 4555652731610533}, + {2646721458762538, 1247587116821480, 2586827199616378, 3932021497491885, 969339720975687}, + {1595456591254808, 1919330451560855, 265402806641622, 1560117962587834, 1169927205192232}, + }, + { + {4189409997656536, 4659089518495636, 6000827340603279, 5702161301408170, 5941261317517041}, + {3317917962903276, 1668664191271588, 1899844145838597, 1696011444672828, 2282054748309227}, + {2126527989994119, 1465890683922518, 416427350021352, 1618807264846944, 1588324622180673}, + }, + { + {4009588676432813, 4225252562340771, 5138392626199289, 6147384375179966, 4323738229760897}, + {2550824143198317, 3724772924079255, 2640826097206085, 2805004284285778, 3725892598967957}, + {901870527597111, 1300831444709451, 1795706127510368, 1590464383227069, 60287918150860}, + }, + { + {4260735023331218, 2752239523202930, 4432983289513289, 6073621772440017, 5069964246448815}, + {2411640257311042, 2404639281373100, 935718519552991, 2182928933394409, 3181304181386605}, + {301088722784222, 902977224984285, 1485824849826196, 864674789855395, 2204280040105719}, + }, + { + {5294452585150653, 4378774784126084, 2684611835446325, 6054460125397337, 3113938028918105}, + {1102630701890799, 2202327440719776, 1844385418066207, 1719220574774295, 3022438833862057}, + {1192644591215061, 1951970263153038, 182489349589207, 1072483329544407, 1425993434915257}, + }, + { + {3759682407110969, 4757463391782573, 6126440026160055, 4699689556446215, 5715476431941391}, + {2696424379059465, 2927324693839557, 2595575928464217, 3964369572567959, 2720628440266425}, + {786193544150213, 816842401151828, 2071842707112420, 581055055128968, 310970557266803}, + }, + }, + { + { + {3579768107573076, 3587300666628503, 3653386978219511, 5061736939322935, 6054960176639396}, + {1219260086131896, 2898968820282063, 2331400938444953, 2161724213426747, 2656661710745446}, + {417621685193956, 1429953819744454, 396157358457099, 1940470778873255, 214000046234152}, + }, + { + {3878872728667188, 4463402894965320, 4164169415301751, 3443570249906556, 4439109571211107}, + {1268047918491954, 2172375426948536, 1533916099229249, 1761293575457130, 3842422480712013}, + {1149147819689533, 378692712667677, 828475842424202, 2218619146419342, 70688125792186}, + }, + { + {4292523638342576, 4903155265245570, 5136143002823489, 3124449750693297, 5738994354400728}, + {3551539230764990, 3690416477138006, 3788528892189659, 2053896748919837, 3260220846276494}, + {2211311599327900, 2139787259888175, 938706616835350, 12609661139114, 2081897930719789}, + }, + { + {4097322728303089, 5725797875706037, 4654440700130628, 4178828883626228, 5693513031868506}, + {1324994503390431, 2588782144267879, 1183998925654176, 3343454479598522, 2300527487656566}, + {1079559557592645, 2215338383666441, 1903569501302605, 49033973033940, 305703433934152}, + }, + { + {3683815626821508, 4943964422665864, 3647446876506747, 4228674336449825, 5438052000093847}, + {2346453219102138, 3637921163538246, 3313930291577009, 2288353761164521, 3085469462634093}, + {1296625309219774, 2068273464883862, 1858621048097805, 1492281814208508, 2235868981918946}, + }, + { + {3534262737397977, 5245485311356750, 4279554456512807, 2770789343226274, 4078409823241192}, + {1490330266465551, 1858795661361448, 3688040948655011, 2546373032584894, 3459939824714180}, + {1525827120027511, 723686461809551, 1597702369236987, 244802101764964, 1502833890372311}, + }, + { + {6545268376680796, 4436205135889147, 3885200451296283, 4362482319222146, 6551744017455139}, + {2365421849929742, 3485539881431101, 2925909765963743, 2114345180342964, 2418564326541511}, + {503058759232932, 760293024620937, 2027152777219493, 666858468148475, 1539184379870952}, + }, + { + {2929839349119735, 5074186917559835, 3857102490299366, 4399562376560948, 3957863610776951}, + {1916168475367211, 3167426246226591, 883217071712574, 363427871374304, 1976029821251593}, + {1439489648586438, 2194580753290951, 832380563557396, 561521973970522, 584497280718389}, + }, + { + {4107979200870526, 4899400547785857, 5175087145170849, 5761419237914916, 2674185367684618}, + {1133946710417756, 499737269360777, 1645961935513831, 2259932248870354, 2394185034627430}, + {2211650710341615, 1916525167795392, 2219254718801699, 1123275886572725, 2065912631812720}, + }, + { + {2942743383283030, 4661681143781323, 4853180648224206, 3984362536169634, 3769046963947699}, + {2547466619616960, 1599890997313053, 1767449403100900, 3146589914609346, 2442645855602917}, + {1023269497317835, 1006858415503750, 2159836138753919, 1535892167365222, 826474553854585}, + }, + { + {4044410514205452, 4788613576788997, 4922881390894542, 4505428839963076, 3254381502973105}, + {2881011303685958, 323260022642283, 2392511825935364, 2680218607241472, 2086628284323147}, + {1011041096783712, 1570461284958064, 399516828994561, 1037957371973381, 293292885426852}, + }, + { + {3922699440356983, 4166667378343946, 4637678914861614, 4901406304713256, 5486018227566634}, + {3894750463833161, 836931108663410, 4007195920412586, 1173057924841174, 2662523305285872}, + {2047497366930440, 1249020434696646, 353399299276962, 1824831452522161, 1950016482901783}, + }, + { + {6367491312268994, 5392176809230541, 4683379383522741, 4425977262002237, 5566950871345983}, + {2375227161224824, 2257267128164595, 1056955680380401, 2844088942852363, 1386644755985081}, + {1251794829999036, 1772886866476173, 955066187540246, 1232293719330892, 396636503102089}, + }, + { + {5348918388440793, 5110360065015040, 4585673363095533, 4391593798666572, 4556880644633940}, + {2531431177429893, 1987695830473810, 227622233346307, 1010967397553478, 1341018389661594}, + {83039271672929, 423138535583767, 1183109031328467, 165324254826210, 1340545562288681}, + }, + { + {4651180052187971, 4721139042433965, 4397263424421690, 3818446426246947, 4163799598655846}, + {1971810452973589, 1766684231420693, 299216980507446, 1405770006429853, 3505404036582454}, + {814876839307346, 1973981610718707, 715190907115349, 1240128743335375, 100752655285750}, + }, + }, + { + { + {5917065716904928, 4914443718136124, 5900862973774566, 4911826770493904, 3846361616833057}, + {2439789269177838, 681223515948274, 1933493571072456, 1872921007304880, 2739962177820919}, + {2102170800973153, 719462588665004, 1479649438510153, 1097529543970028, 1302363283777685}, + }, + { + {5650165172926835, 3913771113130458, 4910281332119388, 5068052063776583, 5612709493199633}, + {3193865531532443, 3321113493038208, 2007341951411050, 2322773230131539, 1419433790163705}, + {2214421081775077, 1165671861210569, 1890453018796184, 3556249878661, 442116172656317}, + }, + { + {5118771546583273, 6027449032225062, 3106360274232749, 4318897183975962, 4017125662271289}, + {3005630360306059, 1666955059895018, 1530775289309243, 3371786842789394, 2164156153857579}, + {1094538949313667, 1796592198908825, 870221004284388, 2025558921863561, 1699010892802384}, + }, + { + {3266123011223623, 3120950453625853, 6259609570067094, 3586752371060918, 6048545006453369}, + {1951351290725195, 1916457206844795, 2449824998123274, 1909076887557594, 1938542290318919}, + {764055910920305, 1603590757375439, 146805246592357, 1843313433854297, 954279890114939}, + }, + { + {4578096739917745, 5243693780562643, 3997054445402827, 5231313513873625, 3534834178102174}, + {80113526615731, 764536758732259, 3306939158785481, 2721052465444637, 2869697326116762}, + {525892105991110, 1723776830270342, 1476444848991936, 573789489857760, 133864092632978}, + }, + { + {4567722854714830, 3491727534333040, 3612522797131151, 4726210441025156, 4566029114558485}, + {2794411533877810, 1986812262899320, 1162535242465837, 2733298779828712, 2796400347268869}, + {1793193323953132, 91096687857833, 70945970938921, 2158587638946380, 1537042406482111}, + }, + { + {4644957907857340, 4595035516942998, 5590808199923137, 4081399466208167, 3445106834328894}, + {1895854577604590, 3646695522634664, 1728548428495943, 3392664713925397, 2815445147288308}, + {1611230858525381, 950720175540785, 499589887488610, 2001656988495019, 88977313255908}, + }, + { + {5377566504324214, 5594237977720934, 3960359138874383, 2924144408487157, 5824037597070734}, + {3440880315164906, 2184348804772596, 3292618539427567, 2018318290311833, 1712060030915354}, + {1508590048271766, 1131769479776094, 101550868699323, 428297785557897, 561791648661744}, + }, + { + {4856954879111275, 4243615896786977, 5034997993102829, 5162125577354786, 4490078142041683}, + {432920540217177, 290770592514699, 627484756484379, 3076610223383366, 982836063036305}, + {1857779135539838, 1774848070278290, 1383862392183037, 1948805685118077, 1143607656457264}, + }, + { + {5925968830616980, 5475584226682352, 5076614308992012, 5422447722241084, 4871259074999718}, + {1741735203658460, 2040511596280954, 3245879940788742, 1750904751318660, 1289068422789788}, + {103031326341235, 1843731695283489, 1066974994445109, 1210433521778964, 118970268237578}, + }, + { + {5029675928196841, 3837944199959690, 3856667351331398, 4299101000305422, 4340504849680591}, + {1990983617046169, 3106460878930032, 1275461113767736, 1443049000516840, 1724142301140669}, + {888262946735860, 1859763056800716, 714395964694532, 57820586821189, 354182478325612}, + }, + { + {3800325421725661, 5577357186452733, 3783169523012609, 5425955064608896, 6347571520159237}, + {1658219197861187, 1494360717755939, 1921505970326949, 3049386312266838, 2475279382922093}, + {1290766154788448, 1600589032610209, 784792370088015, 423204440383515, 459184860068298}, + }, + { + {3425205252763663, 5240056527358710, 4140356292677088, 4578393707504979, 5259386798582854}, + {2215101089214073, 1997062079162084, 1249116849924618, 465107085276733, 1293244424458276}, + {880894898454805, 639667973647762, 200272726605326, 297199521205209, 1640420309599773}, + }, + { + {4024399276644653, 4828207338948134, 4459991457755541, 6377452215012324, 4100282940590511}, + {658635179203333, 3717891363165700, 3673816673290121, 2129566854376278, 1443087419989351}, + {1532654097308642, 1958497386525981, 111717506991097, 1708848284574815, 1306115185198907}, + }, + { + {6112399743594082, 4482370964094274, 5295504988778619, 4900443159383520, 4202262340818045}, + {2039429018914652, 3043146685732704, 1364716986897875, 1031303003048000, 1123429638631433}, + {765045651502510, 451621180435426, 15885268584069, 767513226653014, 768056106241896}, + }, + }, + { + { + {4032987623010691, 3949423965177593, 3633193504625235, 4678793759655164, 3734854480100484}, + {3008217384184691, 2489682092917849, 2136263418594015, 1701968045454886, 2955512998822720}, + {2175517777364616, 708781536456029, 955668231122942, 1967557500069555, 2021208005604118}, + }, + { + {3694962906564668, 2643675345331409, 4432646948339879, 4968138170389248, 3845898010522424}, + {3366935780292116, 2476017186636029, 915967306279221, 593866251291540, 2813546907893254}, + {850858855888869, 319436476624586, 327807784938441, 740785849558761, 17128415486016}, + }, + { + {3776976050663564, 5477805104091557, 2545236069347884, 4651869248468534, 4641561625804457}, + {2132756334090048, 2788047633840893, 2300706964962114, 2860273011285942, 3513489358708031}, + {1121075518299410, 2071745529082111, 1265567917414828, 1648196578317805, 496232102750820}, + }, + { + {5158525177930532, 3420610809262104, 2827455773116173, 5409358332231883, 5000374192034028}, + {2374121042985030, 3274721891178932, 2001275453369483, 2017441881607947, 3245005694463250}, + {1954109525779738, 2117022646152485, 338102630417180, 1194140505732026, 107881734943492}, + }, + { + {4610031103869799, 4566082599491057, 6017046282479905, 5310858379140016, 4504138118839608}, + {1714785840001267, 4288299832366837, 1876380234251965, 2056717182974196, 1645855254384642}, + {2002850762893643, 1243624520538135, 1486040410574605, 2184752338181213, 378495998083531}, + }, + { + {4119798625761979, 5219024680951196, 4543568213831910, 4424867828271409, 5157422279171799}, + {922510868424903, 1089502620807680, 402544072617374, 1131446598479839, 1290278588136533}, + {162892278589453, 182585796682149, 75093073137630, 497037941226502, 133871727117371}, + }, + { + {4201115364782060, 3320803158679711, 4190964847185163, 3800027019416103, 4185567469546654}, + {4166396390264918, 1608999621851577, 1987629837704609, 1519655314857977, 1819193753409464}, + {1730519386931635, 1393284965610134, 1597143735726030, 416032382447158, 1429665248828629}, + }, + { + {4551201741097278, 3774114323393256, 2689506075058172, 3065835144123274, 2587730464618792}, + {360275475604546, 2799635544748326, 2467160717872776, 2848446553564254, 2584509464110332}, + {1291597595523886, 1058020588994081, 402837842324045, 1363323695882781, 2105763393033193}, + }, + { + {5895867926878639, 6191714343966274, 3878657686711880, 3772412065246579, 5254560912358513}, + {1828399243003455, 2730967851207580, 2809663501613790, 3291961475373747, 2085819249159773}, + {1604304703501714, 1563946362290690, 2128875205288733, 257625874150601, 2149102916187814}, + }, + { + {5883573429799187, 4805272859062230, 2886195180819460, 4460210052098162, 3528150621150027}, + {1960233741679201, 2996857902780426, 2245274121401778, 4454263006625692, 1110175461750907}, + {1392548583294657, 697289852607029, 746483005053522, 734366559550160, 929768637070953}, + }, + { + {5047299589947009, 4992620901798841, 5716112978503343, 3741839332315327, 4983937719789158}, + {1673816614349955, 3255360796858239, 2753984593405885, 2969035246796379, 2420194805583742}, + {1159863250954626, 1438000622355742, 254045494246044, 1734996482788294, 484539502358623}, + }, + { + {3740619537304301, 4538691700403019, 5325131682689719, 4744914552382795, 3720848390661317}, + {1212935253295623, 2026300849238541, 3447883684227245, 1364910689032303, 3019520894163467}, + {2014517785153097, 1607430272140319, 1855018731367383, 2200629261829065, 987339037980209}, + }, + { + {4426735416351775, 4348191232564971, 5508438055207952, 2420023948055060, 6131298111765032}, + {2763109171958591, 4020627496535071, 3147539030064750, 2177710318971894, 2463269685396658}, + {831460863845953, 1946524324541207, 761958653274011, 1366775091595921, 1187427455457947}, + }, + { + {3125773853625002, 4814913241945202, 4262512130702308, 3321059176595839, 3567623941809388}, + {2822285257464218, 607639870769094, 2857291392676774, 2362021242026611, 3328398883102618}, + {1972329598509655, 34473001166350, 1728817301333588, 1539479676009467, 1694458836743324}, + }, + { + {4805304108915754, 5125985383393506, 5019883131944028, 4580919291870093, 4156575634700942}, + {1575955157633628, 3067048601687650, 2501496271474334, 4193474980184415, 3288209175931426}, + {1442686188453203, 1751694580158105, 824989332883473, 614995267948452, 1497907423783166}, + }, + }, + { + { + {4408790844622027, 4479344310838572, 4120849908116869, 3006675674164362, 4006042157952305}, + {2361321796251793, 3967057562270386, 1112231216891515, 2046641005101484, 2386048970842261}, + {1846089562873800, 98894784984326, 1412430299204844, 171351226625762, 1100604760929008}, + }, + { + {5371908961903233, 6206610140112367, 4204489822423303, 4507924897296559, 4322883368647362}, + {2335972195815721, 2751510784385293, 425749630620777, 1762872794206857, 2864642415813208}, + {523094549451158, 401938899487815, 1407690589076010, 2022387426254453, 158660516411257}, + }, + { + {3975648787468681, 4460622334219928, 3970548136462187, 4226068267807189, 3446012315943388}, + {612867287630009, 2700012425789062, 2823428891104443, 1466796750919375, 1728478129663858}, + {1254114807944608, 977770684047110, 2010756238954993, 1783628927194099, 1525962994408256}, + }, + { + {5270938303411141, 3005889362003651, 3774991859324322, 4939345652492557, 5016292135810879}, + {2484263871921055, 1948628555342433, 1835348780427694, 1031609499437291, 2316271920603621}, + {1255955808701983, 1700487367990941, 1166401238800299, 1175121994891534, 1190934801395380}, + }, + { + {5381119574505877, 4424637839817897, 4775904018594624, 3906943141245230, 5389829033800309}, + {2600943821853521, 1337012557669161, 1475912332999108, 3573418268585706, 2299411105589567}, + {375806028254706, 214463229793940, 572906353144089, 572168269875638, 697556386112979}, + }, + { + {4199915895763317, 4306698118173043, 4456738998669147, 4714126432522633, 3038393400292872}, + {1168827102357825, 823864273033637, 4323338565789945, 788062026895923, 2851378154428610}, + {1915320147894736, 156481169009469, 655050471180417, 592917090415421, 2165897438660879}, + }, + { + {3081796668531198, 4720661405375633, 3938365723488886, 5850548444590341, 6227423178100675}, + {1726336468579724, 1119932070398949, 1929199510967666, 2285718602008207, 1836837863503149}, + {384301494966394, 687038900403062, 2211195391021739, 254684538421383, 1245698430589680}, + }, + { + {3700877198419411, 4541885072828491, 4388337472863078, 4398292814526820, 5228760778493620}, + {1247567493562669, 4229981908141095, 2435671288478202, 806570235643434, 2540261331753164}, + {1201928866368855, 800415690605445, 1703146756828343, 997278587541744, 1858284414104014}, + }, + { + {3752846457602541, 6051774917153047, 3492614771149749, 5278195549012933, 3851678670548516}, + {1251637423994861, 2037585266091733, 1171182249847439, 1503770304884899, 1938920423810268}, + {2232651154426557, 514116965743385, 983369998596377, 1516132019440103, 1692302360068816}, + }, + { + {4860689994687041, 4138464101331517, 4969836424606600, 3370757908330089, 3017690336853320}, + {3753543276036939, 3037198013841237, 3063121586956950, 2967087171212783, 2388800428725970}, + {1485716675407214, 1159619625081800, 197549418633523, 776030397384998, 252064880140599}, + }, + { + {4116450327020509, 4602447751059104, 4624188822504437, 3786392386215792, 4018069243702311}, + {3871066258534097, 182982139320960, 3846997414183091, 1246347657803786, 966334158538299}, + {2049526525941781, 1431983169228179, 3669291297222, 769041933664973, 1760968694339914}, + }, + { + {5411552533375856, 4680723354107633, 5764453140711672, 3663956673248104, 5834177820168369}, + {2029548972200054, 541413050113871, 2564963424993232, 3150712544977872, 2699322542672271}, + {513500031822581, 836561902873502, 82127696349010, 1591221763097659, 725989684331322}, + }, + { + {4424236584915172, 3098952863411429, 2785705377786181, 4107549518995786, 5362683219257666}, + {1071376590195254, 1910139340535847, 1936705400579295, 3523841068963764, 2356086500199738}, + {357287898232758, 1026512116626804, 1875958986125314, 1743551742697910, 1876232951311596}, + }, + { + {4332669232306147, 5882550009365637, 3881970305785489, 6570990168178499, 3489314838073396}, + {294975596735049, 2145292931466411, 3320625656613141, 2284954433570209, 3090254877821144}, + {1234852195927098, 3815763342761, 2085449281682153, 516098044852331, 164426832090235}, + }, + { + {3292223948318582, 4463121371440286, 5163264330075513, 4550237542693388, 4544934760614835}, + {2590122580645644, 1011386629068498, 960875975353535, 3791419723576010, 2273772136048635}, + {1749858954947675, 1561651915395372, 1738700200168191, 397865176422134, 1467025336447738}, + }, + }, + { + { + {3011428551915689, 3264493287961099, 4857379860456993, 4749679688758046, 4282178671364408}, + {2608268623334125, 3034173730618399, 1718002439402869, 3644022065904502, 663171266061950}, + {2040672435071076, 888593182036908, 1298443657189359, 1804780278521327, 354070726137060}, + }, + { + {4711536788361604, 4516566538409613, 5324597415653586, 3262240285890532, 3953172703826057}, + {1894938527423184, 3715012855162525, 2726210319182898, 2499094776718546, 877975941029127}, + {218882774543183, 533427444716285, 1233243976733245, 435054256891319, 1509568989549904}, + }, + { + {4802737216830789, 3846171402668813, 5371658121409568, 4761371218007175, 4056812806828167}, + {4140638349397055, 3303977572025869, 3465353617009382, 2420981822812579, 2715174081801119}, + {1806842755664364, 2098896946025095, 1356630998422878, 1458279806348064, 347755825962072}, + }, + { + {5169106331623846, 4777370102540357, 5302836601573124, 5351928617448052, 4063248596493177}, + {1402334161391744, 3811883484731547, 1008585416617746, 1147797150908892, 1420416683642459}, + {1468412523962641, 771866649897997, 1931766110147832, 799561180078482, 524837559150077}, + }, + { + {5770203524895319, 4659978036228594, 3527448837914025, 4951338033258915, 4756786089433589}, + {2223212657821831, 2882216061048914, 2144451165500327, 3068710944633039, 3276150872095279}, + {2022215964509735, 136144366993649, 1800716593296582, 1193970603800203, 871675847064218}, + }, + { + {5731767721917939, 4837733510733388, 5091167195790575, 4937212217651675, 5106990027743699}, + {1862751661970309, 851596246739884, 1519315554814041, 3794598280232697, 3669775149586767}, + {121893973206505, 1843345804916664, 1703118377384911, 497810164760654, 101150811654673}, + }, + { + {2836122124869624, 4884260866172613, 4618439021898554, 2906882084185319, 4363655839720099}, + {2710146069631716, 2542709749304591, 1452768413850678, 2802722688939463, 1537286854336537}, + {996965581008991, 2148998626477022, 1012273164934654, 1073876063914522, 1688031788934939}, + }, + { + {3949497701489527, 5838943331198768, 5334888242577534, 5453016312620545, 4792359904762516}, + {3175286832534829, 2085106799623354, 2779882615305384, 1606206360876187, 2987706905397772}, + {1419122478109648, 1325574567803701, 602393874111094, 2107893372601700, 1314159682671307}, + }, + { + {4954618339278337, 3422305785425208, 4565328836139485, 3192891441493866, 4836379953614308}, + {855396458506247, 2470294140783466, 4436061492213979, 1754097632720488, 4112391040574456}, + {985511568884890, 583904209238998, 516128993365349, 1235577837475387, 1449904660690748}, + }, + { + {5895940682517746, 4393238442290827, 4244687834629046, 5245476345580864, 4795864303032094}, + {1477173810966796, 3207978347793495, 2656860913951054, 825157489520718, 2782873637674750}, + {12931323257125, 562700432679180, 780577595442459, 440747171628074, 31993258894121}, + }, + { + {5231235667053925, 5090675513104692, 4933657013889560, 5325938777525481, 4583903281916140}, + {2159229926833831, 1114556221271056, 2050697214928106, 2553796628978461, 2874553280901592}, + {1487427059839672, 1966052937474419, 398866894053509, 2040723626090668, 1223074007342359}, + }, + { + {3294796902098517, 3902877656361122, 4227499257540629, 5627711142390550, 5038311124292534}, + {2677874505039557, 678833394869758, 3687464289589147, 1992670845292812, 654778477108270}, + {651854196246431, 2602668557028, 1822678077647200, 2072267608435533, 435243653222236}, + }, + { + {4313218743534013, 3972172746637215, 5399714135650344, 5547659251980199, 4837224811093838}, + {2487053592812311, 2315738098787275, 1210583464083714, 1056644723032111, 781277197910636}, + {864616322745343, 1362699579128647, 1361407419724038, 495664202671974, 662016549521786}, + }, + { + {6154029469581357, 5498138279894180, 3281752713530018, 3501917375982713, 4910547940594210}, + {2672416110637939, 3245298985644332, 1344078619347414, 2037703067415133, 2697812769645364}, + {325041473989085, 842410640177049, 1052993540865892, 2093280369201601, 361408260911216}, + }, + { + {4388597398802075, 4997551911436129, 2851157853262017, 4795345418726848, 4139150667184165}, + {1519253497716003, 3826826078266703, 2262276529333275, 1386373334348474, 3240242941348023}, + {763973845167102, 1151501355459051, 1283654593302800, 584312404348728, 1219116745359281}, + }, + }, + { + { + {5676939182921069, 5322204711648077, 4551121131734783, 5427708347935459, 5239023033125000}, + {2201150872731785, 2180241023425241, 2349463270108411, 1633405770247823, 3100744856129234}, + {830104860549448, 1886653193241086, 1600929509383773, 1475051275443631, 286679780900937}, + }, + { + {4781988283280724, 4990742996470332, 5431361832879221, 4684617167544704, 3868686514426533}, + {3828911108518224, 3282698983453994, 2396700729978777, 4216472406664814, 2820189914640497}, + {1191033906638969, 940823957346562, 1606870843663445, 861684761499847, 658674867251089}, + }, + { + {5126469419668815, 4155719092635613, 4174388435346876, 3772374525285681, 5590700387545135}, + {1875032594195527, 1427106132796197, 2976536204647406, 3153660325729987, 2887068310954007}, + {25465949416618, 1693639527318811, 1526153382657203, 125943137857169, 145276964043999}, + }, + { + {4258045666458167, 5238362362206654, 4758242557133921, 3658013106441212, 2491103563202933}, + {2466539671654587, 920212862967914, 4191701364657517, 3463662605460468, 2336897329405367}, + {1619678837192149, 1919424032779215, 1357391272956794, 1525634040073113, 1310226789796241}, + }, + { + {4248523125120879, 4096142580252307, 5489055327836539, 3417724495086206, 4815108317240624}, + {3292563523447371, 1704449869235351, 2857062884141577, 1998838089036354, 1312142911487502}, + {43173156290518, 2202883069785309, 1137787467085917, 1733636061944606, 1394992037553852}, + }, + { + {4449014387058033, 5297853724611810, 5533789687884231, 2519432329227148, 4292277862887871}, + {670078326344559, 2807454838744604, 2723759199967685, 2141455487356408, 849015953823125}, + {1812516004670529, 1609256702920783, 1706897079364493, 258549904773295, 996051247540686}, + }, + { + {5827060326775227, 5766290385251485, 3123576947163146, 5563678522359472, 3964036703348132}, + {1540374301420565, 1764656898914615, 1810104162020396, 3175608592848336, 2916189887881826}, + {1696163952057966, 1391710137550823, 608793846867416, 1034391509472039, 1780770894075012}, + }, + { + {5101135942842208, 4543974686113080, 4194056217641295, 5689084272866427, 2564466095709391}, + {1367603834210822, 4383788460268472, 890353773628143, 1908908219165595, 2522636708938139}, + {1919411405316294, 1234508526402192, 1066863051997083, 1008444703737597, 1348810787701552}, + }, + { + {4132340278436948, 4005982088010057, 3308609415246807, 3692550296463618, 3956871570338410}, + {1096972188133236, 3816049499915451, 1251976741328773, 1219603529073670, 1078899265206338}, + {950202511700693, 1240039391743494, 1169033682725545, 1423696267961315, 86935143579550}, + }, + { + {4756214981813576, 5522632333569959, 3862983342357100, 4309495274365548, 5713360895956932}, + {2683363149107878, 1470385524874179, 725539084456484, 3271790833618750, 1222340934084308}, + {200587706310533, 896271240996831, 1147839003219597, 673448965331479, 548900916085084}, + }, + { + {3550032568832337, 4838968015489313, 4675889877479625, 3212531632461645, 4765584451232964}, + {1405860849520605, 738725235942165, 399531320766275, 3195580921007755, 1958618144816834}, + {94349687650983, 306368484955948, 1759034073892087, 2030110332880331, 1270749214795711}, + }, + { + {2967631947537871, 4383349957254579, 3922288445505558, 5226885511958431, 3995794596785200}, + {1753118377928377, 3368465588051047, 1755914948419738, 3441455854862245, 647766692547292}, + {2005162920381704, 1507493192705080, 1430523618875617, 131673490468702, 662093487452573}, + }, + { + {2747463689102953, 5007357876041009, 5072033195962826, 4670246809435049, 5673751346141763}, + {2718321167227969, 855141819034537, 1769780985173952, 3439183400564947, 1192259870209089}, + {747964066233340, 2037427400347459, 49693847757217, 2003202980691532, 2230561945728266}, + }, + { + {4747984612298188, 4723422270130357, 4628272886928943, 3839214906514725, 5200339299152060}, + {1424576382204282, 350051250024461, 3895326653518337, 3070821812734749, 3346444741017048}, + {2021002858021100, 839958875652478, 2080082610761570, 1282995787185392, 313106058533657}, + }, + { + {5293324356940491, 3886891387640488, 5386021427475165, 4491415749098830, 3988924707585306}, + {2136145829133251, 713070507515938, 1951333115623761, 3770252317439440, 1824831508473442}, + {2203533335083089, 2130417962449796, 217179607020589, 153498131255469, 1884913426826060}, + }, + }, + { + { + {6357530995067419, 4511707601241201, 4853814131499793, 3027006748267833, 4004117462852039}, + {2102881477513865, 3822074379630609, 1573617900503707, 2270462449417831, 2232324307922097}, + {1417148368003523, 721357181628282, 505725498207811, 373232277872983, 261634707184480}, + }, + { + {3519916180986434, 5063756715513304, 5306226466970938, 4461989750290959, 5633593412950483}, + {2186733281493248, 2250694917008620, 1014829812957440, 2731797975137637, 2335366007561721}, + {615183387352312, 917611676109240, 878893615973325, 978940963313282, 938686890583575}, + }, + { + {4051478965894094, 5415732403270882, 4529567395411473, 4935730075960955, 4778168617632490}, + {522024729211672, 3296859129001056, 1892245413707789, 1907891107684253, 2059998109500714}, + {98698809797682, 2144627600856209, 1907959298569602, 811491302610148, 1262481774981493}, + }, + { + {5721409450692386, 4425747098618406, 6490527463642820, 3639914744810785, 4516285758530664}, + {1791451399743152, 1713538728337276, 2370149810942738, 1882306388849953, 158235232210248}, + {1650875518872272, 1136263858253897, 1732115601395988, 734312880662190, 1252904681142109}, + }, + { + {5306746809205765, 3120741251682392, 2568099116674910, 5447095217001045, 2823024101589818}, + {2624786269799113, 2777230729143418, 2116279931702134, 2753222527273063, 1907002872974924}, + {227742695588364, 1776969298667369, 628602552821802, 457210915378118, 2041906378111140}, + }, + { + {3832015885289562, 4129797318027691, 5360746788631408, 5207122354148972, 4434563787896849}, + {815000523470260, 3164885502413555, 3303859931956420, 1345536665214222, 541623413135555}, + {1870080310923419, 71988220958492, 1783225432016732, 615915287105016, 1035570475990230}, + }, + { + {4881216209018060, 3833780216763759, 5307643745501116, 4286182636729437, 5147443675842680}, + {2982787564515398, 857613889540279, 1083813157271766, 1002817255970169, 1719228484436074}, + {176957326463017, 1573744060478586, 528642225008045, 1816109618372371, 1515140189765006}, + }, + { + {2695191990687280, 4737393024215632, 4451306435997662, 3263658520201184, 3226476650748376}, + {1888911448245718, 3638910709296328, 4176303607751676, 1731539523700948, 2230378382645454}, + {1846351103143623, 1949984838808427, 671247021915253, 1946756846184401, 1929296930380217}, + }, + { + {4257691815043557, 4587099125055339, 4378829326829150, 4530783676112038, 5088169500723328}, + {2633154847819111, 2373317802678415, 4226812651282694, 3531985668346704, 3254298087102270}, + {1896123626988797, 1131351092678624, 1831358114864483, 1263257519094555, 153161823153575}, + }, + { + {5013999188326350, 5342051120597129, 5658875547575315, 4993589587822012, 3418484323529615}, + {2875848054604140, 2609079967536269, 3221396114275243, 1330649045956928, 1828925625187427}, + {85523512650066, 1145743424577874, 270900922559567, 1781500837265517, 1998986005265292}, + }, + { + {4300315009401728, 4620112123771453, 2612760971016545, 3052063778972094, 4706549333122035}, + {2904227921845290, 4267364811643403, 1994336236107343, 2172724361186958, 2854607055726693}, + {2127639189718319, 2205729457048157, 1849555339256920, 1751645797856968, 1883138982486949}, + }, + { + {3989916020510698, 4741941595447558, 5214589701377240, 4351148330446081, 3428672470823222}, + {762600272699964, 2753498328779892, 3316416370655704, 526788695246361, 3062867170941268}, + {1503368613839734, 2009362771486879, 495897391474535, 1905468005297555, 272387388531978}, + }, + { + {5813046901089551, 5050432868964283, 4705275668110217, 4196337029208819, 5257156494192722}, + {1830890930331365, 3828112268992685, 3895633691902557, 3356965264729727, 2386741853982022}, + {995710478389517, 1430833880042694, 1172677663947400, 1545257382741759, 1798260148494462}, + }, + { + {5205850356707429, 4686811868434220, 5616916192509070, 4494846080958018, 5419646380822597}, + {1276458355120913, 2527187906858810, 1130163473530636, 3533175711581762, 2161750040536619}, + {1025062667466023, 43711902086443, 2210112172846377, 233136450830559, 1412931651896051}, + }, + { + {3560341629038503, 4545538003102686, 5283269045082286, 4816839347899222, 4801547130939062}, + {2448047678851139, 599053419172738, 3080495073729726, 1198848441856844, 1359787207816262}, + {555971766815523, 2160228751293088, 266579216919501, 408880354152864, 2184471346102790}, + }, + }, + { + { + {5195617294728737, 5226905206197221, 3889841953548511, 5251818933360801, 4838188827894395}, + {849646212451983, 1410198775302919, 2325567699868943, 1641663456615811, 3014056086137659}, + {22893968530686, 2235758574399251, 1661465835630252, 925707319443452, 1203475116966621}, + }, + { + {3154905071699595, 4930741522303542, 5064786644540271, 4136130058087200, 4165945522107466}, + {3053098849470395, 3985092410411378, 1664508947088595, 2719548934677170, 3899298398220870}, + {1344191060517578, 1960935031767890, 1518838929955259, 1781502350597190, 1564784025565682}, + }, + { + {4168985401048642, 5601942199123232, 4509535428414908, 4252327476037085, 6042239923552064}, + {2925523165433334, 1979969272514922, 3427087126180756, 1187589090978665, 1881897672213940}, + {2495540013192, 678856913479236, 224998292422872, 219635787698590, 1972465269000940}, + }, + { + {4698182657338567, 5017916408838259, 3081477769920918, 3928215500558329, 5313704211766335}, + {271413961212179, 3604851875156899, 2596511104968730, 2014925838520661, 2006221033113941}, + {1980510813313589, 1948645276483975, 152063780665900, 129968026417582, 256984195613935}, + }, + { + {5300264442994823, 3794960652558197, 6004497419208260, 6170915605358895, 5102903504401205}, + {1860190562533083, 1936576191345085, 2712900106391212, 1811043097042829, 3209286562992083}, + {1151480509533204, 2136010406720455, 738796060240027, 319298003765044, 1150614464349587}, + }, + { + {5520821677598445, 4505587343518853, 4486119403320947, 5124882310463887, 4384352945448272}, + {1731069268103131, 2987442261301335, 1364750481334267, 2669032653668119, 3178908082812908}, + {1567828528453324, 1017807205202360, 565295260895298, 829541698429100, 307243822276582}, + }, + { + {4341766796632437, 4105940157601428, 4403780572905254, 4391581105946996, 4661670073235412}, + {249079270936229, 1501514259790706, 3199709537890096, 944551802437486, 2804458577667728}, + {1338766321464554, 1906702607371284, 1519569445519894, 115384726262267, 1393058953390992}, + }, + { + {4136644411018817, 5105079697639574, 5123803130450031, 3331327213803161, 3453876506817262}, + {3616421371950629, 3764188048593604, 1926731583198685, 2041482526432505, 3172200936019022}, + {840922919763324, 727955812569642, 1303406629750194, 522898432152867, 294161410441865}, + }, + { + {5565570118069330, 4591619629413879, 3505524267391659, 5911065393515679, 5626780252302286}, + {2954349327665336, 2875421537282295, 1177907047549607, 2315244756624323, 3303388475971642}, + {1193532613439179, 1341357357703238, 1857522674746129, 587336359047056, 1462817734082691}, + }, + { + {5032608083579310, 5556680383291862, 4639031978972564, 2550751933150061, 4661900946642239}, + {981709001326388, 2228829982452486, 1195252744174570, 1961335123791201, 473922585791741}, + {158547452916311, 1806851940249257, 1888549274109445, 1234535032385844, 755999937979748}, + }, + { + {5099505633219587, 3654947652195304, 4632839805758299, 3516983533390311, 3156502843280841}, + {2235936902666817, 1844821659342916, 4255944160143733, 2705728103151199, 1360010073190141}, + {1966276380904262, 1243659846916250, 1230287549611464, 1790496592504769, 385075881855087}, + }, + { + {5102974111125320, 5352605641984611, 4254853167292498, 4166876022626639, 4692858050734664}, + {808958715657412, 2787760179369277, 2812754371047796, 3109195163271007, 3174221799565416}, + {1970356456788069, 1887106101566224, 2120741856788965, 1887465058487327, 166078852378175}, + }, + { + {5268074145727905, 3102961204581063, 5775739741243707, 6623549226998551, 5355512520264473}, + {1475882426726637, 2923995069592105, 2595116660588037, 2134573872614909, 2857982748479313}, + {957649428811476, 1521919451665798, 1487878569331559, 1715152263604455, 2000934618350472}, + }, + { + {3462276468747197, 4403243110229213, 5274708467449337, 4946143993185919, 6100123938510411}, + {2624197675552195, 2160845895419703, 991891416996825, 2705836223851003, 2307139020684469}, + {231885416467149, 648441606302746, 1371491506634443, 193373311482025, 2106953050161716}, + }, + { + {2408565470230034, 4633147941257550, 4425551739809483, 4183865634168848, 4784444305258783}, + {2307403528152576, 3136574081495182, 3694424861021853, 1950918571001278, 1747697954472435}, + {931185174846608, 872635055344100, 1155298897916392, 1344438153479985, 863698029056587}, + }, + }, + { + { + {2611656183523465, 4684513982859178, 5365326100017121, 4722407564633480, 2827426586917747}, + {2605560604520539, 1598361541848742, 3374705511887547, 4174333403844152, 2670907514351827}, + {755467689082474, 909202735047934, 730078068932500, 936309075711518, 2007798262842972}, + }, + { + {3236138991462016, 3067527600191131, 3896954399398994, 3910874778063800, 3938401465669403}, + {1609384177904054, 2614544999293875, 1335318541768200, 3052765584121496, 2799677792952659}, + {1697863093781930, 599794399429786, 1104556219769607, 830560774794755, 12812858601017}, + }, + { + {4108730476499120, 5181690479373092, 4171978954440413, 3511327647445115, 4559140599266006}, + {1168737550514982, 897832437380552, 463140296333799, 2554364413707795, 2008360505135500}, + {1158643631044921, 476554103621892, 178447851439725, 1305025542653569, 103433927680625}, + }, + { + {3077203098880308, 4396008401246031, 4177351818329890, 6418777467377480, 5519551756318358}, + {2176793111709008, 3828525530035639, 2009350167273522, 2012390194631546, 2125297410909580}, + {1807108316634472, 1534392066433717, 347342975407218, 1153820745616376, 7375003497471}, + }, + { + {4732167545780233, 5368693586150714, 2609883700135802, 4663217517029815, 3612437739977844}, + {3234860815484973, 2683011703586488, 2201903782961092, 3069193724749589, 2214616493042166}, + {234147501399755, 2229469128637390, 2175289352258889, 1397401514549353, 1885288963089922}, + }, + { + {5617390325210756, 5554766767336738, 5549530285921438, 6514965868913137, 3937966638306001}, + {3363562226636810, 2504649386192636, 3300514047508588, 2397910909286693, 1237505378776769}, + {1054097349305049, 1872495070333352, 182121071220717, 1064378906787311, 100273572924182}, + }, + { + {4607833422014698, 3800719604873494, 4476341726952553, 4306709190801725, 3295603202700400}, + {3558210666856834, 1627717417672446, 2302783034773665, 1109249951172249, 3122001602766640}, + {216762189468802, 707284285441622, 190678557969733, 973969342604308, 1403009538434867}, + }, + { + {4847405480488793, 3554016671099447, 2818672356908788, 4302938753224251, 4825028485754775}, + {3530824104723725, 2596576648903557, 2525521909702446, 4086000250496689, 634517197663803}, + {470067171324852, 1618629234173951, 2000092177515639, 7307679772789, 1117521120249968}, + }, + { + {4032307292940140, 4855742012511787, 4007061004220393, 4186026976205829, 5188147460015837}, + {1726290253928048, 2108179153379055, 3599306339052623, 3804322907336713, 740669388116407}, + {1893601910775915, 1893561171028788, 174914675480509, 2073460144115735, 250678301747773}, + }, + { + {5696478198308385, 3135077959467853, 5039986204304988, 5696739636381970, 5163380137461980}, + {1473356281060031, 1850501243620073, 559809451272168, 2164039335364390, 2799937740729438}, + {506406583155327, 1903499899096002, 445887262445598, 866962765497367, 55809365421254}, + }, + { + {5290224396694939, 4705669579710662, 4614921349557141, 5027610124814334, 5088773866023979}, + {2009707214072007, 3490160897828618, 275706542492147, 1283471147003836, 2026672645131195}, + {1123457689056584, 2213608670005209, 1379370540202855, 2074314852377531, 864461310144552}, + }, + { + {5111150460891680, 4275734012505621, 4206718452855061, 3888755110807716, 5005016151412877}, + {2967787444233740, 1413004988964951, 690605351712577, 3813861694171786, 728516486273669}, + {2016155040846069, 1480238949730910, 882386999623863, 1367342654128568, 589184047321896}, + }, + { + {3850772783035735, 4143292076634522, 5556861502206409, 4279143658707597, 3550043180479289}, + {3493927566017921, 3571431901909570, 2627286406743953, 2047641118374561, 1730233493072697}, + {272317805124786, 1812925138663726, 1217316351219782, 1182300795957412, 1252963393607199}, + }, + { + {5371799854215572, 3393967588858477, 5067027508227680, 3852577519740789, 4734905175716170}, + {3515527020405104, 2159318542704715, 1058260913419646, 2981918447395233, 1340478002453928}, + {896362445577855, 1547885531466434, 942263962614365, 1148475609702329, 2122889133222112}, + }, + { + {5312477093520487, 3952229351525915, 5253212242457428, 4756871683292235, 4134773488559657}, + {2735014629385533, 1581591485505255, 1720528958990566, 4161950575359359, 2332085424554487}, + {704970088806441, 1168889861388831, 354811087636935, 1536113135588939, 2212112893107236}, + }, + }, + { + { + {2828809211088312, 6295039889156786, 4429443549656884, 4678145777282455, 5916104705152820}, + {2529951391976704, 1810282338562946, 1771599529530998, 3635459223356879, 2937173228157088}, + {893719721537457, 1201282458018197, 1522349501711173, 58011597740583, 1130406465887139}, + }, + { + {4766083398225008, 5494110682478710, 2778685366456944, 2823464210331405, 4857685817649218}, + {412607348255434, 1280455764199780, 2233277987330768, 2265979894086913, 2583384512102412}, + {1820352417585487, 24495617171480, 1547899057533253, 10041836186225, 480457105094042}, + }, + { + {5647768329980203, 5108044017780681, 3796340935441384, 4177115363811274, 5130001056264497}, + {2023310314989233, 2889705151211129, 2106474638900686, 2809620524769320, 1687858215057825}, + {1922168257351784, 2018674099908659, 1776454117494445, 956539191509034, 36031129147635}, + }, + { + {4561842048916374, 4287612509327089, 4370291679808170, 5695284091186768, 4550521144824593}, + {2796444352433270, 1039872944430373, 3128550222815858, 2962457525011798, 3468752501170219}, + {272268252444639, 1374166457774292, 2230115177009552, 1053149803909880, 1354288411641016}, + }, + { + {5697036697171416, 5404706777075284, 5503272547981905, 4981184452172701, 4867839206068339}, + {1857910905368338, 1754729879288912, 3137745277795125, 1516096106802165, 1602902393369811}, + {886299989548838, 1538292895758047, 1590564179491896, 1944527126709657, 837344427345298}, + }, + { + {3561647617580592, 3713951676498321, 4714970494042065, 3796394966388927, 5531291426324585}, + {3006358179063534, 1712186480903617, 3955456640022779, 3002110732175033, 2770795853936147}, + {803217563745370, 1884799722343599, 1357706345069218, 2244955901722095, 730869460037413}, + }, + { + {5199950995983500, 5997984878609744, 5241636760987426, 5139985135222038, 5431082849981900}, + {2941099284981214, 1831210565161070, 3626987155270686, 3358084791231418, 1893781834054268}, + {1949114198209333, 1104419699537997, 783495707664463, 1747473107602770, 2002634765788641}, + }, + { + {3320700462489453, 4258691810757797, 5637648896716044, 3890560459865337, 4307195898311025}, + {1607325776830197, 2782683755100581, 1451089452727894, 3833490970768671, 496100432831153}, + {2222475519314561, 1870703901472013, 1884051508440561, 1344072275216753, 1318025677799069}, + }, + { + {4037612142179094, 2987286320918074, 5334840876971305, 3892287190264789, 5794263680951471}, + {471926402845486, 2814813543274642, 3620200888572759, 1728489506884653, 3177161343196207}, + {1819395223745913, 594758877920007, 1653753349717506, 242640844960873, 963869472910932}, + }, + { + {2936569169465705, 6049214516933086, 5963733906800640, 4231427100807371, 4853047066834829}, + {2548596925868729, 2662135700065828, 2088163736824992, 2331981460676031, 2771125203890139}, + {780634400476978, 637764048158951, 901014587909154, 1354805333992459, 2018934308296179}, + }, + { + {2797688906622325, 3428210403110380, 5022584852934687, 3295825468273441, 5705393166486691}, + {2111199241475135, 1851629318616336, 1992578166276991, 2095428925801999, 1218266125748465}, + {1810680242312559, 952287178947563, 681241246062059, 1252456339225424, 1959931529139639}, + }, + { + {4919536354167776, 4843044804249283, 4705930511557457, 5262690042745614, 4386984625976838}, + {3747081830160208, 1520760409479969, 1598412209810121, 1654404133831532, 437659257098574}, + {744124236937047, 1544378156616778, 715829909389559, 2120659842894185, 72002654880101}, + }, + { + {4563826663843359, 5185090504058247, 5145727029702249, 5011944329783380, 5313803489832094}, + {244278499662023, 2000287644883357, 3512120660608951, 1998820466139820, 2107051881706162}, + {1061541907539207, 1129143356143074, 459133314948729, 1177985907118634, 1224368687812524}, + }, + { + {3152842550820126, 4081984728409524, 3254259750651619, 4604329179757860, 4471438744025494}, + {2383716445654654, 2845501105364248, 3179274641918483, 2181012191586748, 4055424112922904}, + {1792270341351139, 2065266134997868, 51895527839218, 798734893906822, 992253836606399}, + }, + { + {4950351600164207, 5298895157252043, 5150281689404603, 4544152582549862, 5356669996354042}, + {1927020266981541, 1747143248428675, 1588706088137551, 1077596294054796, 1170976366872068}, + {1001666581039191, 1742276948383877, 1379478310433234, 767654427573973, 2047968425937961}, + }, + }, + { + { + {4511412834337187, 4698043828798044, 4323205223211753, 5569204703546807, 6149086417101785}, + {155711679280637, 681100400509288, 389811735211209, 2135723811340709, 2660533024889373}, + {16625790644959, 1647648827778410, 1579910185572704, 436452271048548, 121070048451050}, + }, + { + {4694164895067901, 2924655519713304, 4842396181739721, 4841286895864398, 5356846476062228}, + {3289062842237779, 2820185594063076, 2549752917829677, 3810384325616458, 2238221839292470}, + {1763863028400139, 766498079432444, 1321118624818005, 69494294452268, 858786744165651}, + }, + { + {4869852729848717, 5029275869879305, 3701410808950684, 3435100659007430, 4689559933862040}, + {3543856582248253, 1456632109855637, 3352431060735432, 1386133165675320, 3484698163879000}, + {28315355815982, 460422265558930, 1799675876678724, 1969256312504498, 1051823843138725}, + }, + { + {4558284163736209, 4461809852221468, 5698584425525803, 5038838655144199, 3768154892986607}, + {2408714813047231, 3857948219405196, 1665208410108429, 2569443092377519, 1383783705665319}, + {1484387703771650, 198537510937949, 2186282186359116, 617687444857508, 647477376402122}, + }, + { + {4662985813836019, 4129426407048187, 5122336824431007, 5530273911701301, 3409921574477931}, + {2147715541830533, 2751832352131065, 2898179830570073, 2604027669016369, 1488268620408051}, + {1744544377739822, 1964054180355661, 1685781755873170, 2169740670377448, 1286112621104591}, + }, + { + {3854053602374273, 4943141672260381, 4472148111349729, 5161477038123364, 4661051199882732}, + {2333777063470241, 3919742931398333, 3920783633320113, 1605016835177614, 1353960708075544}, + {1029287186166717, 65860128430192, 525298368814832, 1491902500801986, 1461064796385400}, + }, + { + {3437283298068479, 3608139386273800, 5088531994686943, 4605732407316964, 6296522248487285}, + {2660016802414475, 2121095722306988, 913562102267595, 1879708920318308, 2492861262121979}, + {1966196870701923, 2230044620318636, 1425982460745905, 261167817826569, 46517743394330}, + }, + { + {6233793835087996, 4935389669690266, 6335114860649961, 3623880366453827, 5578113556752255}, + {2358877405280588, 3136759755857592, 2279106683482647, 2224911448949389, 3216151871930471}, + {1450880638731607, 1019861580989005, 1229729455116861, 1174945729836143, 826083146840706}, + }, + { + {3994140066248694, 3181522224560048, 3364322700715335, 6108496090134019, 4266308196944062}, + {978398934730796, 1804963209584982, 2902083217855803, 2011728779166715, 3070976799182328}, + {494691910923538, 1903565874798025, 2115181773831520, 2000771501496645, 2163753695162256}, + }, + { + {4499039401984510, 2919282610904813, 3371698570925682, 3170519001059914, 5250127479378489}, + {1654039515014884, 2484661430680993, 2620692000541228, 2669599656280070, 2398652280696967}, + {2019971150480802, 2112841493625261, 237154577131804, 1674207955014809, 1389703158284583}, + }, + { + {4706814366157303, 5336609175411517, 4757963599977030, 4060364649415927, 3640669095240911}, + {780624938414169, 3404608320205059, 1982958325444026, 3570514777233615, 984254926012775}, + {1463658959517057, 1983397723547684, 41055560978805, 424638764130418, 491755157953272}, + }, + { + {3257295355011901, 4096776962011503, 4487597369409850, 5876979850901767, 6030505591690325}, + {2935104701953453, 3989681641092319, 3306366339882358, 2374391350196501, 1896075761392399}, + {1262337399368722, 1039133447611747, 917288766852537, 1931663063827599, 386956994697158}, + }, + { + {5865485955051801, 4898975626365390, 5709055439582716, 3072783210395629, 4352817622936409}, + {2724577252043037, 1050316213165918, 2370342271552724, 2792859709284319, 2760145987712013}, + {1677351910521822, 152891770438727, 738510373109788, 1296476386064424, 1219545250565005}, + }, + { + {2955221061271345, 5973180148171190, 3740903689178612, 4255579446112404, 4178816467357894}, + {1908022307626643, 2469819122662084, 1583327987932656, 3442462106139746, 599498145240366}, + {220308000962909, 460573332431611, 732078470162760, 467340602781483, 1127652895548970}, + }, + { + {4256843681823156, 4695170685669586, 4012905106498514, 5492595949894092, 4822219141250098}, + {1289113762003406, 2808167474320130, 1666802361626320, 1051654028271354, 1724653376239634}, + {1695390634076771, 1517610099990508, 1248456812719894, 2178282202616225, 905038523003109}, + }, + }, + { + { + {4388488268525257, 4351308814649541, 3942600308931722, 3469443492260723, 3080520458769465}, + {1899935429242705, 1602068751520477, 940583196550370, 2334230882739107, 1540863155745695}, + {765548025667841, 462473984016099, 998061409979798, 546353034089527, 2212508972466858}, + }, + { + {6305035755313584, 3986236631593136, 5772327717715563, 4670602724441205, 4485397579520202}, + {2298375097456408, 3144370785258318, 1281983193144089, 1491520128287375, 75847005908304}, + {1997562060465113, 1048700225534011, 7615603985628, 1855310849546841, 2242557647635213}, + }, + { + {3608844722049986, 2980930458947685, 6266068700289474, 3617433430563704, 4684882533775436}, + {1161017320376250, 2744424393854291, 2169815802355236, 3228296595417790, 1770879511019628}, + {1080413443139865, 1155205815510486, 1848782073549786, 622566975152580, 124965574467971}, + }, + { + {4272336182688229, 4705861119105631, 3304969482836130, 4308331792957791, 5281765142064806}, + {1184526762066993, 247622751762817, 2943928830891604, 3071818503097743, 2188697339828084}, + {237404399610207, 1308324858405118, 1229680749538400, 720131409105291, 1958958863624906}, + }, + { + {4785126936528543, 2288770346086770, 3118706734562790, 4474082416637981, 5793198356960377}, + {2767383321724075, 2269456792542436, 1717918437373988, 1568052070792483, 2298775616809171}, + {1278207464902042, 494742455008756, 1262082121427081, 1577236621659884, 1888786707293291}, + }, + { + {4316050955753838, 6170021230760201, 3671071179000687, 2720567588588102, 4695134757737078}, + {353042527954210, 1830056151907359, 1111731275799225, 2426760769524072, 404312815582674}, + {1716987058588002, 1859366439773457, 1767194234188234, 64476199777924, 1117233614485261}, + }, + { + {4802445580021739, 5669686216323056, 5683496153608928, 3599612573083939, 3664745203781455}, + {3236091949205521, 2386938060636506, 2220652137473166, 1722843421165029, 2442282371698157}, + {1143239552672925, 906436640714209, 2177000572812152, 2075299936108548, 325186347798433}, + }, + { + {4921698295511420, 2966865811406529, 3723715952061302, 4420370150973604, 5441412310007539}, + {2972824668060020, 2936287674948563, 3625238557779406, 2193186935276994, 1387043709851261}, + {1043584187226485, 2143395746619356, 2209558562919611, 482427979307092, 847556718384018}, + }, + { + {6539978005364395, 5005405360675302, 4390281321854973, 5817765520609028, 2885569505406129}, + {2401607320460403, 912267207660896, 2797776548107885, 1401692837350636, 2770414290856347}, + {904627574235583, 366582160013268, 1919276459982818, 683852563070972, 849013528013132}, + }, + { + {4382884022719489, 3331418080941236, 4472875449005139, 4019500438389598, 4463034067898545}, + {314313360314847, 1556311374160012, 3420403310565817, 1814168775579274, 3865931899404825}, + {2211811396782717, 1987727116500422, 1201194143426517, 1988979712261853, 884086138400803}, + }, + { + {3928195125806252, 4506628847593763, 4871806493038737, 5468133301160088, 4718975813247195}, + {3157237349544610, 2087027997220233, 1635119994381095, 1685873597006198, 3264645977099821}, + {554990822829571, 1043610604169755, 239155874009083, 1207029530220679, 1248980877883503}, + }, + { + {2330609380614712, 5282631639681642, 3679411410269759, 2770673432637308, 3778717181908177}, + {2321085204756486, 3204498878947842, 1897195179818497, 2221896934640248, 2249233024322127}, + {1100828805329651, 38323682820671, 233339076341529, 570439134676859, 373923102906827}, + }, + { + {4822469807205745, 4578534577854527, 3814578293772758, 6210971875752572, 3469875307698085}, + {650556138336187, 1140806781381529, 1319490550148986, 2443218412602398, 2092597895198457}, + {24874372349398, 672413878008022, 2109618619032869, 617580455983017, 643082448965145}, + }, + { + {3702942502950483, 4221261673998955, 4525315300848625, 5031967728773077, 4411934662665867}, + {895116466708821, 2311360532554913, 1331906084934491, 1442649827370867, 985339602059253}, + {1101806460504208, 48906420814555, 455540794156723, 777238833441277, 678815750013174}, + }, + { + {4956217544664282, 4411017504484405, 3654474138314413, 5155000128389593, 4413650344518487}, + {1203258470211606, 2883266356628027, 1508156827359997, 3638270983429361, 1401834110583505}, + {928961391578986, 832907369443124, 468987297840672, 1558723144077997, 1418280592841651}, + }, + }, + { + { + {3309129437554730, 5123933694799617, 4965300486638528, 6516081243872351, 2549068382794184}, + {1248731221520740, 1465200936117687, 2792603306395388, 2304778448366139, 2513234303861356}, + {1055352180870759, 1553151421852298, 1510903185371259, 1470458349428097, 1226259419062731}, + }, + { + {4550600281784187, 3256554237859110, 4119844627242950, 4676836561429904, 5092370827107509}, + {3744788603986897, 3042126439258578, 3441906842094992, 3641194565844440, 3872208010289441}, + {30498470091663, 1082245510489825, 576771653181956, 806509986132686, 1317634017056939}, + }, + { + {5619235959382811, 4106140804649401, 4587392324740009, 4223977265679267, 2709254929742834}, + {2672107869436803, 3745154677001249, 2417006535213335, 4136645508605033, 2065456951573058}, + {1698968457310898, 1435137169051090, 1083661677032510, 938363267483709, 340103887207182}, + }, + { + {4745319008032005, 4813628148687644, 3467681137065440, 3660014790178871, 4392941970152610}, + {1995325341336555, 911500251774648, 2415810569088940, 855378419194761, 3825401211214090}, + {1315157046163473, 727368447885818, 1363466668108618, 1668921439990361, 1398483384337907}, + }, + { + {6557196758364187, 4276231499541578, 4485350770690107, 4264207089194792, 3124346806789687}, + {2326829491984875, 3267188020145720, 1849729037055211, 4191614430138232, 2696204044080201}, + {1217269667678610, 599909351968693, 1390077048548598, 1471879360694802, 739586172317596}, + }, + { + {4384302481090479, 4717978973545909, 3754548127453306, 4211871514743047, 3605771636328385}, + {3970118453066023, 1560510726633957, 3156262694845170, 1418028351780051, 2346204163137185}, + {319394212043702, 2127459436033571, 717646691535162, 663366796076914, 318459064945314}, + }, + { + {3198885719919217, 2575084544179354, 3737578377662447, 5232176448882889, 5405183975072780}, + {2657789238608841, 1960452633787082, 2919148848086913, 3744474074452359, 1451061489880786}, + {1575783124125742, 2126210792434375, 1569430791264065, 1402582372904727, 1891780248341114}, + }, + { + {5242752265626106, 4326735213088803, 5009083294116390, 3863683170199334, 2880454449080125}, + {3090232019245924, 4249503325136911, 3270591693593114, 1662001808174330, 2330127946643001}, + {1822054032121349, 643057948186973, 7306757352712, 577249257962099, 284735863382083}, + }, + { + {3757294655239106, 4149870483813681, 3943074023634421, 5011331412913659, 4204233544524725}, + {765300458944758, 1962420935223063, 1006865922596525, 556125259357651, 517324314261719}, + {947503289917657, 1503416272497360, 836151367440855, 2025240512839119, 1506056841382176}, + }, + { + {3987605469554571, 4216854847559852, 4606485208582710, 4025002076531210, 5771502720173311}, + {789866795586711, 1219783998007690, 3399339961859034, 1430246873258510, 2263938746297911}, + {272907227620417, 585056874977936, 374400386458564, 1047259762290717, 466584497787787}, + }, + { + {4513305810099276, 3713543936920641, 5881885803512264, 4985359422621344, 5854329220017841}, + {2489594831593530, 2868670421452777, 2653264259914146, 778139640543916, 2896054888052141}, + {67965761977879, 1140658137927248, 1433664110101982, 1907417172350895, 1009746387131234}, + }, + { + {4657525718512496, 4017020332264511, 5032007516852528, 4196574218153666, 4558814287479470}, + {3191788312902362, 1662632170533261, 3849731434302862, 816384760006536, 2103376627071646}, + {98516339668203, 1987095201806236, 109825731538912, 249333174781555, 868887613476084}, + }, + { + {4551570896172554, 4811478172541458, 3661911804185849, 2859956435208139, 3775782540863495}, + {4251836217943410, 1527544805122594, 1416199226269029, 2604023934400523, 2761395386595757}, + {1642831683324706, 1693640639567753, 543897185448748, 1014750779914025, 2000933536049400}, + }, + { + {5616692888384001, 4085181778999311, 5359480780192985, 4168165762634953, 3706985665716275}, + {3046363118074651, 1033878254661623, 1432711896868579, 565399048183279, 1486610644259929}, + {1956000744629083, 2124722115672587, 1869890027060221, 1779425010763214, 2251549887150752}, + }, + { + {5403435201118585, 6603374055023538, 4448450050924979, 4204020352279014, 3319690980306662}, + {1147686993699695, 2183664403489392, 3736291649220767, 3475178747642004, 1656820196694734}, + {993108364179144, 45592857828226, 1223718961690034, 1931120528549047, 1402978202475587}, + }, + }, + { + { + {4707745854342560, 3882311012719969, 4467035027860010, 2426465723968789, 5459727301387711}, + {3618358370049178, 1448606567552085, 3730680834630016, 2417602993041145, 1115718458123497}, + {1562934578796716, 1070893489712745, 11324610642270, 958989751581897, 2172552325473805}, + }, + { + {2875482372335866, 3589666323156759, 5493912977577144, 3566036429447715, 3416572787955522}, + {1770564423056008, 2987323445349813, 1326060113795288, 1509650369341127, 2317692235267932}, + {223256821462517, 723690150104139, 1000261663630601, 933280913953265, 254872671543046}, + }, + { + {5739703102637456, 4089685696952464, 5529672212600950, 5529465141325467, 4053764715117380}, + {1969087237026022, 2876595539132372, 1335555107635968, 2069986355593023, 3963899963027150}, + {1115241013365517, 1712251818829143, 2148864332502771, 2096001471438138, 2235017246626125}, + }, + { + {4621952399709001, 5571208339175198, 5938396303563992, 3935039984233637, 4734466397277932}, + {3551068012286861, 2047148477845620, 2165648650132450, 1612539282026145, 2765997725314138}, + {1850689576796636, 1601590730430274, 1139674615958142, 1954384401440257, 76039205311}, + }, + { + {4398511437540326, 5006878555391994, 2877652875936652, 3360921192078354, 5537453437282356}, + {1723387471374172, 3249101280723658, 2785727448808904, 2272728458379212, 1756575222802512}, + {571005965509422, 2005213373292546, 1016697270349626, 56607856974274, 914438579435146}, + }, + { + {4021767746362864, 3947693133441663, 5655463017046415, 4032842598082935, 4903887401788780}, + {1346698876211176, 2076651707527589, 3336561384795453, 2517134292513653, 1068954492309670}, + {1851867764003121, 403841933237558, 820549523771987, 761292590207581, 1743735048551143}, + }, + { + {4789545034251916, 5151774024717947, 3350203576317227, 5870147068473486, 3757676696824463}, + {410915148140008, 2107072311871739, 3256167275561751, 2351484709082008, 1180818713503223}, + {672095903120153, 1675918957959872, 636236529315028, 1569297300327696, 2164144194785875}, + }, + { + {3867157095427632, 4907857238986876, 4412001163466224, 5664547006559450, 3829838433234787}, + {1902708175321798, 3287143344600686, 1178560808893262, 2552895497743394, 1280977479761117}, + {2013087639791217, 822734930507457, 1785668418619014, 1668650702946164, 389450875221715}, + }, + { + {5139170412209073, 4498594321446990, 3403045096731472, 3523999116931205, 4892973820656308}, + {3100339582931283, 3780065035763732, 3107854667684806, 1176538847728659, 2470425204007084}, + {1439699951361262, 2030141811121675, 1327540074439450, 98760879510567, 2124055188161162}, + }, + { + {5069757928527025, 4269771696870248, 3491008216607494, 2929486207919899, 2963259194922213}, + {1719771161855965, 3899474813414394, 1311077187368436, 1710977333891379, 2936225820601205}, + {630007537003875, 1879755431232807, 1841434412649072, 139825159320909, 1444684178970403}, + }, + { + {4165024628959566, 3986473160684857, 4482720357638229, 3477188964410991, 6063532098390286}, + {2735367442263082, 3037388464741161, 708840305892227, 3376016746983163, 2424461132835430}, + {1692345998026512, 1336264953003836, 472200476738834, 443198297543894, 865332172690922}, + }, + { + {3583240374232032, 6672838339902029, 3302719127491245, 4817707424315947, 3846209753841235}, + {1940518928195986, 2204192709398575, 2559878786338619, 1240694154295451, 3150360999940643}, + {978334155462452, 259156758770697, 1998397384612038, 868981902819036, 526720567050341}, + }, + { + {6295419175112392, 5922842429035919, 3280130237310527, 6154864010584464, 4672381744259604}, + {2495384380697450, 2529087473815087, 3152074437283087, 2705660594301054, 3756859018180124}, + {2829664309620, 1216345963700610, 1352213880784545, 1343440385603407, 1678896558555000}, + }, + { + {4462327178876654, 4861692839162759, 4026088282699843, 4559864737475196, 4141921357362458}, + {970323584385428, 1841886145157987, 771455069751873, 2995416444511372, 1381697279273918}, + {833881464516252, 722547189080954, 1385674139934263, 1947516117258013, 237073770273705}, + }, + { + {4933913084823421, 4670123363141682, 4900446203904881, 4055286352327374, 4290448492223496}, + {2942776662601173, 2578009269314716, 544737250664645, 2975699597442162, 2099680134205576}, + {452946908538500, 838029561099231, 448300214621162, 402872419278705, 704999550269611}, + }, + }, + { + { + {5798682425720784, 4343644325181242, 6354948599958312, 4506974667055090, 5293040366083331}, + {2705718263383616, 2358206633614248, 2072540975937134, 308588860670238, 1304394580755385}, + {2083069137186154, 848523102004566, 993982213589257, 1405313299916317, 1532824818698468}, + }, + { + {4034211192773531, 5600324567335276, 4531193018091912, 2794041663976599, 3792137612125120}, + {3747761112537659, 1397203457344778, 4026750030752190, 2391102557240943, 2318403398028034}, + {693543956581437, 171507720360750, 1557908942697227, 1074697073443438, 1104093109037196}, + }, + { + {4735029189573542, 3778090050106418, 6524974691396918, 6024554123028535, 3058137605210362}, + {345288228393400, 3351443383432420, 2386681722088990, 1740551994106739, 2500011992985018}, + {1079623667189886, 872403650198613, 766894200588288, 2163700860774109, 2023464507911816}, + }, + { + {3748938635589832, 3296620064200837, 3994393700108731, 5740803740117332, 5352647078187481}, + {854645372543796, 1936406001954827, 2403260476226501, 3077125552956802, 1554306377287555}, + {667962773375330, 1897271816877105, 1399712621683474, 1143302161683099, 2081798441209593}, + }, + { + {3324209478486170, 4398737310762775, 3760579922605898, 5439367229755348, 5616400060914562}, + {2378947665252234, 1936114012888109, 1704424366552046, 3108474694401560, 2968403435020606}, + {333549023751292, 280219272863308, 2104176666454852, 1036466864875785, 536135186520207}, + }, + { + {5689714689958878, 4503409610653732, 5602544085249448, 3404912574886620, 4043425317102514}, + {2625466093568366, 2398257055215356, 2555916080813104, 2667888562832962, 3510376944868638}, + {1870078460219737, 2129630962183380, 852283639691142, 292865602592851, 401904317342226}, + }, + { + {3798100817109506, 4962694127433334, 3349468332060557, 6283897397500138, 2972563107372854}, + {1361070124828016, 815664541425524, 3278598711049919, 1951790935390646, 2807674705520038}, + {1212405311403990, 1536693382542438, 61028431067459, 1863929423417129, 1223219538638038}, + }, + { + {4842650611581872, 5104986353880267, 4917334859504562, 3217991068822474, 6343075526828654}, + {1294303766540260, 3435357279640341, 3134071170918340, 2315654383110622, 2213283684565086}, + {235605972169408, 2174055643032978, 1538335001838863, 1281866796917192, 1815940222628465}, + }, + { + {6283914285320299, 4538885684827819, 5272821644392905, 4741145486323262, 3695595414404375}, + {2328903345630831, 383243669352281, 873975569357849, 1167517986625404, 1819176154401511}, + {1015569285123052, 366271559910559, 607712860974980, 1151136439806917, 1092279314442070}, + }, + { + {4644837603275095, 4182486257496369, 5680847280055574, 5281364304268108, 4017310458808244}, + {608363524539665, 1518910856395189, 2487752246555640, 1408491254860196, 1242950972146918}, + {724510145626490, 1990648995683735, 1234513756420164, 776971151906420, 1819715569230741}, + }, + { + {4025210576522653, 5037391877366464, 6220723743247171, 4107687904850403, 5536810198272054}, + {1367586897505451, 2009604536185136, 2660752171350541, 2665866783498593, 3368014404783418}, + {1205287993924177, 1639266049462139, 1103796806037893, 1538960177870822, 829889727712499}, + }, + { + {4793558625576028, 3882027570562344, 4207241179173547, 5281023204511977, 6361433483438371}, + {3281892459792280, 1933131048782198, 2351228493867205, 2032809616708977, 2534356983068777}, + {909754464411828, 785219392684958, 1338541457752162, 826789969638535, 2048189131938215}, + }, + { + {5399590275296719, 3849598676683261, 3407829328170797, 4201689601652353, 3895190733841783}, + {1015687460377127, 2173401063127799, 2017987633047477, 748955581941445, 630511527938929}, + {2101074774193018, 2001243087608708, 801641610437734, 1519697986446082, 594845713523709}, + }, + { + {4827244732148509, 4706350784965857, 3625459412499055, 5917778693464512, 5372808769862558}, + {1452942110247071, 1201823364506117, 2330240170803201, 2907618912660148, 2069141053434694}, + {745779946397307, 916664696261756, 1535477642186117, 1334763610638931, 1366843744138046}, + }, + { + {4176014068905464, 4252766041468492, 3589174288259552, 3776062686798003, 4986282119113185}, + {1092579010212274, 1203724605936750, 2270767453066752, 2458071886656347, 2443647576082745}, + {318795329870799, 185430882319687, 1286511919273276, 657817007383756, 40641447918263}, + }, + }, + { + { + {4538870843995520, 3964150480707053, 5487263883039355, 4602170887743532, 5736245235930330}, + {1632352921721536, 1833328609514701, 2092779091951987, 4175756015558474, 2210068022482918}, + {1998172393429622, 1798947921427073, 784387737563581, 1589352214827263, 1589861734168180}, + }, + { + {5350015016975595, 2997963309224426, 3081458566511327, 5095667333327441, 5460842165191887}, + {1733739258725305, 2283515530744786, 2453769758904107, 3243892858242237, 1194308773174555}, + {1758148849754419, 619249044817679, 168089007997045, 1371497636330523, 1867101418880350}, + }, + { + {3965982201013836, 5981456109444663, 5078495317312678, 4410918223912516, 3807332263401822}, + {2578433797894864, 2513559319756263, 1700682323676192, 1577907266349064, 3469447477068264}, + {853828206885131, 998498946036955, 1835887550391235, 207627336608048, 258363815956050}, + }, + { + {3753463041754121, 3606679279252159, 3696232489183494, 3149612277537848, 5358662226124843}, + {2392941288336925, 3488528558590503, 2894901233585134, 1646615130509172, 1208239602291765}, + {714380763546606, 1032824444965790, 1774073483745338, 1063840874947367, 1738680636537158}, + }, + { + {3423450128487239, 6070685071936072, 3705460605693651, 3009714346694508, 6123110970148691}, + {1640635546696233, 2884968766877360, 2212651044092395, 2282390772269100, 2620315074574625}, + {420958967093237, 971103481109486, 2169549185607107, 1301191633558497, 1661514101014240}, + }, + { + {5625132717515116, 5524850964392681, 4614069623317915, 3762859588443640, 4361835721816909}, + {3158923465503550, 1332556122804145, 4075855067109735, 3619414031128206, 1982558335973171}, + {303213233384524, 2061932261128138, 352862124777736, 40828818670255, 249879468482660}, + }, + { + {3697491154222530, 4544214010492622, 4905703930515359, 4988733897248726, 6163038950957920}, + {856559257852200, 2760317478634258, 3629993581580163, 3975258940632376, 1962275756614520}, + {20057458979482, 1183363722525800, 2140003847237215, 2053873950687614, 2112017736174909}, + }, + { + {2961281310713750, 5035281843536219, 4820563396802425, 4066115702139011, 4762159869794599}, + {2228654250927986, 3735391177100515, 1368661293910955, 3328311098862539, 526650682059607}, + {1053447823660455, 1955135194248683, 1010900954918985, 1182614026976701, 1240051576966610}, + }, + { + {3576347446000839, 3504021369715234, 3286921249007623, 6268908633911267, 4898262353027354}, + {2053850994061963, 1755999209417110, 2842496597997123, 1978798188794297, 1107741233360060}, + {1587558591633082, 1224310153016076, 373416710356490, 733639236443698, 365919571874338}, + }, + { + {4922046667787666, 5384603941382862, 3355282705253058, 5052638190916511, 4442324355401649}, + {716350205934888, 1153032590403764, 2797021656648850, 1143194352934997, 4271302979058629}, + {1588274760900072, 933817618340883, 731655082380959, 688238385999711, 637984915480250}, + }, + { + {4217060480329358, 4374528391636951, 5478312030233942, 5051281083802439, 5405881257383323}, + {413138784837996, 173345891427747, 1873100191622562, 899752727618929, 3454430648436331}, + {830072102529414, 1185948406051604, 1521170049452316, 1259798181998483, 735064905966282}, + }, + { + {5515669600102047, 5759134783811579, 4357089500282138, 5244472517255288, 5695631524373921}, + {2842166480737527, 2947367283673209, 2706356593419314, 2971106642583260, 2444234893549177}, + {1396164055858898, 2228551364195726, 611382817170935, 1662418665433346, 1079098567119990}, + }, + { + {3828208352345746, 5742603493540025, 5912515684826959, 5415942702105867, 4409414272784258}, + {2895166868245672, 3153594867376981, 2883799413649215, 1877187137914547, 1124004944737352}, + {1249379796419407, 1201460644559526, 1259226742776869, 583948750717161, 1178519968480157}, + }, + { + {4715510278636375, 4324771002227588, 4218850944267831, 4037187367673896, 4505301806813551}, + {660737143139077, 1635830759165556, 795647058595473, 2117049403264300, 2692853476865573}, + {1654844956375931, 767321709128720, 475080629455448, 116932684758291, 96451917556060}, + }, + { + {5797033177541322, 5021581754974953, 4978830133961786, 5973534325336756, 4105099431310062}, + {1777561190222404, 3757586069945925, 2868096822929350, 1968746982919962, 1089633650980574}, + {833672890421142, 647759906668054, 572517465546269, 402134952667751, 2083275174687780}, + }, + }, + { + { + {6352542060466074, 3833809696215741, 4101092554705390, 3320298136988035, 4253202043484731}, + {1957943897155478, 1788667368028035, 2389492723714354, 2252839333292309, 3078204576998275}, + {1528282417624269, 2142492439828191, 2179662545816034, 362568973150328, 1591374675250271}, + }, + { + {4265077968872559, 2914460285039701, 3045781039391514, 4915306233356239, 5308090560495285}, + {2411826493119617, 2484141002903963, 2149181472355544, 598041771119831, 2435658815595421}, + {2051892037280204, 488391251096321, 2230187337030708, 930221970662692, 679002758255210}, + }, + { + {3713635732994642, 4207056293821675, 4684465815183558, 6055578880035022, 5061343489334444}, + {1530723630438670, 875873929577927, 2593359947955236, 2701702933216000, 1055551308214178}, + {359179641731115, 1324915145732949, 902828372691474, 294254275669987, 1887036027752957}, + }, + { + {4324702538941745, 2563932266428659, 4813530513012704, 5499843939988947, 3842301114037549}, + {4295071423139571, 2038225437857463, 1317528426475850, 1398989128982787, 2027639881006861}, + {1397254305160710, 695734355138021, 2233992044438756, 1776180593969996, 1085588199351115}, + }, + { + {4202522275076530, 6411445226225292, 4074557295320773, 4373367518435491, 4577411558841716}, + {2692366865016258, 2506694600041928, 2745669038615469, 1556322069683365, 3819256354004466}, + {387139307395758, 2058036430315676, 1220915649965325, 1794832055328951, 1230009312169328}, + }, + { + {3379372614866712, 3476543574256943, 5779819517217769, 3781538535387827, 3841619480557100}, + {1765973779329498, 2911143873132225, 2271621715291913, 3553728154996461, 3368065817761132}, + {2181229378964934, 2190885205260020, 1511536077659137, 1246504208580490, 668883326494241}, + }, + { + {4227237865914097, 5575401147370301, 5098251926594813, 4129497466354055, 3741435180672532}, + {2689666469258543, 2920826224880015, 2333696811665585, 523874406393177, 2496851874620484}, + {958592545673770, 233048016518599, 851568750216589, 567703851596087, 1740300006094761}, + }, + { + {3792569420294954, 4400089757531324, 6101403783497940, 5734203344054362, 3067223272494699}, + {2014540178270324, 192672779514432, 2465676996326778, 2194819933853410, 1716422829364835}, + {1738560251245018, 1779576754536888, 1783765347671392, 1880170990446751, 1088225159617541}, + }, + { + {4447695422728303, 2418292515870024, 5595971144063629, 5081870838292807, 5209525481880645}, + {2916521632160477, 2343112140697014, 1601700300762337, 1763148914953177, 2708190975156259}, + {1339021042945816, 1840804708066696, 877961221559635, 1281458842745501, 1950851850845276}, + }, + { + {4786922334540966, 4955024641438784, 2989160972656404, 5186429632708936, 4984389249074409}, + {1020393680308960, 3834711966547082, 2322726956159582, 995949551108034, 3035172379117141}, + {2248087612518599, 173333799263920, 1744928838552182, 957368524885377, 1722980339454003}, + }, + { + {3826226586501329, 4985391470235567, 3706778387862153, 5001039432994919, 3643485069381971}, + {2453664361158331, 3658664111645897, 2133047286876873, 2891246599919261, 1077039773701841}, + {1403674776792037, 176114870970230, 204752269254815, 823265703401663, 973549049711641}, + }, + { + {4428694302478430, 4279516097530892, 4558829707092394, 4506689423374814, 3060727770678082}, + {3511507258617268, 2341694334736402, 3023178443373630, 4119452783133958, 1541883672814480}, + {273175012476053, 353915697751570, 1920076197363975, 2096923665433891, 694182114426694}, + }, + { + {4184692084971979, 4134060280811983, 3170779668973105, 4456307003709940, 4308299286729100}, + {2273158812011175, 3253770145986191, 1455430838863125, 1701216872600126, 1994907074166318}, + {854928709890819, 247698160098706, 1293104197995963, 648230677212306, 784063325867838}, + }, + { + {4504036913969323, 5450574207835078, 6042071388766678, 4918868602774744, 5356088910233627}, + {2995726671480383, 3106924626287182, 2718750693945174, 3268809265740618, 1129470954185503}, + {2104894828289916, 873144584667742, 506537740149646, 646077767532773, 1966868865211605}, + }, + { + {6048446108790732, 5524115631172029, 4165751037432881, 4331639016561072, 5291322591785068}, + {2269347023399866, 1910686315635227, 654955394153571, 2857416503175088, 847850165913280}, + {836953051260559, 1769743545147988, 699239118029628, 825806019782225, 1990070083297713}, + }, + }, + { + { + {3395265304118584, 3783994539881306, 5596876372865192, 4984641333486582, 4373205247246409}, + {2911103727614740, 1956447718227572, 1830568515922666, 3092868863429656, 1669607124206367}, + {1686424298744462, 1451806974487153, 266296068846582, 1834686947542675, 1720762336132256}, + }, + { + {3458195995174227, 4836757775805549, 3654433306506668, 5623690819092521, 4197273928235755}, + {3141016840074207, 3295090436969907, 3107924901237156, 1669272323124635, 1603340330827879}, + {766720088232571, 1512222781191002, 1189719893490790, 2091302129467914, 2141418006894941}, + }, + { + {5441759705376431, 3673576132738420, 4193443048427021, 4683601810691313, 3666180150435792}, + {2671463460991841, 1998875112167986, 3678399683938955, 3406728169064757, 2738338345823434}, + {398001940109652, 1577721237663248, 1012748649830402, 1540516006905144, 1011684812884559}, + }, + { + {3248461355092589, 5959477015323422, 2996112620542523, 4642813523567241, 5503882535918283}, + {1653276489969611, 2257881638852872, 1921777941170835, 1604139841794531, 3113010867325889}, + {1450817495603008, 1476865707053229, 1030490562252053, 620966950353376, 1744760161539058}, + }, + { + {3213965769821056, 5620199287619286, 4685689805377309, 5959205094392245, 4699653216173778}, + {2811528223687828, 2288856475326432, 2038622963352005, 1637244893271723, 3278365165924196}, + {796863823080135, 1897365583584155, 420466939481601, 2165972651724672, 932177357788289}, + }, + { + {4468743695984567, 4898440950560817, 4474456712004917, 5061786181321024, 3329036690710436}, + {877047233620613, 1375632631944375, 2895573425567369, 2911822552533124, 2271153746017078}, + {801118384953213, 1914330175515892, 574541023311511, 1471123787903705, 1526158900256288}, + }, + { + {3726318200450545, 4012593435854444, 5660999417843231, 3874664121744144, 4669027921793287}, + {3201417702772463, 2207116611267330, 3164719852826535, 2752958352884036, 2314162374456719}, + {1961673048027128, 102619413083113, 1051982726768458, 1603657989805485, 1941613251499678}, + }, + { + {3486506407007189, 5586943518586412, 3150073788000181, 3892658932084745, 4661178025941644}, + {1401939116319247, 2587106153588320, 2323846009771033, 862423201496005, 3102318568216632}, + {1143483057726416, 1992614991758919, 674268662140796, 1773370048077526, 674318359920189}, + }, + { + {5249032546684913, 4376477734728695, 5192833668695386, 3879528383130666, 4673544232718438}, + {2001586827113779, 3745189534067065, 1944288247515270, 3801531181100442, 2035001711257644}, + {1821331151892312, 1302058705892077, 1823533497142581, 1477427445977593, 1256884978338733}, + }, + { + {3816568398797501, 4280523703434080, 5575370580457579, 6556193442157265, 5400032142723120}, + {3676887960291627, 2721875544375886, 1949386962401535, 2062484445640651, 1831148391448868}, + {1098621584553762, 479766126028979, 50128556582829, 1793185955386011, 957643491878541}, + }, + { + {5624964178025902, 5881679035334285, 5337334188128135, 3373245272349238, 6030340196395357}, + {1686491261026354, 2930481776329103, 2527067703865047, 1879410757156738, 2416602562794561}, + {1954783342191961, 1776196854323048, 1073865783628317, 126006585556188, 551111053703277}, + }, + { + {5863020639436884, 5014608403303800, 3487461172336056, 4625089084538493, 3002443292699384}, + {1844293295362196, 3776383490821424, 1827935191421176, 1761145652561373, 2654244832682184}, + {2163920127813722, 1809848067831371, 1226486593520438, 6568253441272, 318658165188350}, + }, + { + {5229528028782988, 3740161041125714, 3628427289315213, 5072860979211871, 5962952384148406}, + {1112209403436618, 3603724598892882, 3004743983803641, 1636637612372587, 1910870598142670}, + {1139920697586991, 989775023258908, 1562720488536799, 1457380545841604, 910097567659210}, + }, + { + {3041059796685021, 3926553231646481, 4587262528244901, 5282743084605635, 4777345624727557}, + {2431004626164709, 3854783312160059, 3273298459729433, 3386841277003151, 3777213922766615}, + {295894405919626, 1325594150172422, 673838771367222, 604280180076012, 485577818727658}, + }, + { + {3793091552131313, 4374989255749447, 4298473526457935, 3586546830561382, 4785727997920673}, + {3556189185732659, 4013352737062889, 2854416081619439, 1896415948116520, 654670146226537}, + {139962000945005, 2246840272939065, 40902718655534, 1533074280944617, 1032382655251714}, + }, + }, + { + { + {3758431901841840, 4379281609207426, 5017412546860750, 4644243343298864, 4946076247670812}, + {1835401379538542, 173900035308392, 818247630716732, 4013900225838034, 1021506399448290}, + {2056683376856736, 219094741662735, 2193541883188309, 1841182310235800, 556477468664293}, + }, + { + {4597695873914911, 5426082008537486, 4528117456116057, 4391230322227749, 4348938857916251}, + {3566819241596075, 1049075855992602, 4318372866671791, 2518704280870781, 2040482348591519}, + {537697207950515, 1399352016347350, 1563663552106345, 2148749520888918, 549922092988516}, + }, + { + {4827183563480027, 4225372812262903, 3444018843651805, 4582954431755768, 5877642652930841}, + {1747985413252415, 680511052635695, 1809559829982725, 2846074064615302, 2453472984431229}, + {213277331329947, 416202017849623, 1950535221091783, 1313441578103244, 2171386783823658}, + }, + { + {6124178045615487, 5044634958558963, 4487585538139111, 4406665622773445, 4226427082437073}, + {2440888617915079, 993969372859109, 3147669935222235, 3799101348983503, 1477373024911349}, + {1346805451740245, 1350981335690626, 942744349501813, 2155094562545502, 1012483751693409}, + }, + { + {3326465926121696, 4752879014110088, 3426137740310600, 3810813345691727, 3724087589204368}, + {2107080134091762, 1132567062788208, 1824935377687210, 769194804343737, 1857941799971888}, + {1872620123779532, 1892932666768992, 1921559078394978, 1270573311796160, 1438913646755037}, + }, + { + {3280128640868324, 3962843103655104, 3602632284060180, 4174964503289574, 5999255996217406}, + {3089190001333428, 3264053113908846, 989780015893986, 1351393287739814, 2580427560230798}, + {1900828492104143, 430212361082163, 687437570852799, 832514536673512, 1685641495940794}, + }, + { + {5679936010824454, 3977277108025017, 4516300250042949, 2929815522503454, 4666323705890374}, + {3094432661621646, 605670026766215, 290836444839585, 2415010588577604, 2213815011799644}, + {1448049969043497, 1789411762943521, 385587766217753, 90201620913498, 832999441066823}, + }, + { + {3515424710267724, 5606202029043823, 5029901811084866, 4403815652814045, 3735639122175257}, + {2767886146978542, 2240508292484615, 3603469341851756, 3475055379001735, 3002035638112385}, + {442991718646863, 1599275157036458, 1925389027579192, 899514691371390, 350263251085160}, + }, + { + {5324956849177719, 3429271620480873, 5513927382492506, 4069478768490913, 4487763984887828}, + {1005736577196489, 1703778335600507, 1256787933200658, 1273583601164519, 4154995520392582}, + {1181460621741892, 515102888370257, 660560226785527, 1121970691511835, 1609869229541589}, + }, + { + {5276536763892090, 4684953471965519, 6139261731383556, 3763310979241977, 3999629994843744}, + {3197840386614072, 2673429719431285, 2328666993391622, 1601604658039797, 754388419948612}, + {2189230067083086, 574898679774723, 1093556583385601, 1590603941933467, 1876625616519950}, + }, + { + {3739860822512771, 4605148533211466, 4174048138272099, 4387338734269228, 2880424850917010}, + {2359748764236743, 2750393191088290, 1526008165088803, 1669725971211966, 2233234520219112}, + {42208074517808, 919916618772548, 1864146060012263, 405874007551625, 167276017170589}, + }, + { + {4682022353746882, 6009429539947866, 2947942480787000, 5087407628431820, 4667285753466106}, + {1939674698340922, 2060465757190214, 2418157875657274, 1687699771189262, 236132178171812}, + {674205207435332, 837990472116301, 1170756550883494, 611962296440926, 1446026806940794}, + }, + { + {4797835609201808, 3649645875831679, 5195894411777247, 3424984715982399, 5322304250778016}, + {3454576586408064, 2256192384569215, 2864444376813541, 2134820396191597, 1047034985188490}, + {1582224761030916, 260261512990929, 1131518591198333, 94648525453241, 270083062170054}, + }, + { + {5595107036983877, 4494054900752656, 3263812520261324, 5044525307237686, 3722017695712965}, + {1188525422166779, 3589855283768506, 1782193012394260, 2155228647422980, 3120862178456839}, + {1981581840102891, 142303636665554, 2039535378650111, 1181156234198923, 1967834468546111}, + }, + { + {5706915977082882, 3753081378072469, 2510190141605996, 4045103810631250, 4992176450645285}, + {1947964231400572, 2169451112529873, 2463002605422706, 3228930307152278, 597158871609891}, + {1385883488372791, 1890958046379947, 2126979282588918, 17215697802179, 562809648160246}, + }, + }, + { + { + {6060806645993160, 4844231320170097, 3729525723161433, 2866535765304666, 4285036937432013}, + {1689713572022124, 2845654372939621, 3229894858477217, 1985127338729498, 3927868934032873}, + {968764929340557, 1225534776710944, 662967304013036, 1155521416178595, 791142883466590}, + }, + { + {5626780938473300, 5189175572245936, 2759405279195173, 3664390275802720, 2819817138913873}, + {1487081286167458, 3244839255500182, 1792378982844639, 2950452258685122, 2153908693179753}, + {560258797465417, 2193971151466401, 1824086900849026, 579056363542056, 1690063960036441}, + }, + { + {4383124982462505, 3428436472114155, 6260522268883476, 3642043430861258, 4218124990723630}, + {1918407319222397, 2605567366745211, 1930426334528098, 1564816146005724, 4113142195393344}, + {2063958120364491, 2140267332393533, 699896251574968, 273268351312140, 375580724713232}, + }, + { + {4285699823073660, 3996702683556035, 4442379901602887, 6453074611624616, 4734649381664242}, + {2024297515263178, 2668759143407935, 3330814048702549, 2423412039258430, 1031677520051052}, + {343868674606581, 550155864008088, 1450580864229630, 481603765195050, 896972360018042}, + }, + { + {6032529693711055, 6108603534430070, 3306860895022921, 5961918729318160, 5737795472583636}, + {2151139328380127, 2566545695770176, 2311556639460451, 1676664391494650, 2048348075599360}, + {830430507734812, 1780282976102377, 1425386760709037, 362399353095425, 2168861579799910}, + }, + { + {3935550130401342, 5155878315656623, 3473598574878785, 4149160495161916, 4823257793397838}, + {3407562046415562, 980662895504005, 2053766700883521, 2742766027762854, 2762205690726604}, + {618808732869972, 72755186759744, 2060379135624181, 1730731526741822, 48862757828238}, + }, + { + {4481933078376341, 5067550582461519, 4294715789111644, 5330913983663967, 5175628607523309}, + {3714971784278753, 3394840525452699, 614590986558882, 1409210575145591, 1882816996436803}, + {264204366029760, 1654686424479449, 2185050199932931, 2207056159091748, 506015669043634}, + }, + { + {4317070754263612, 4535076723640848, 4810021506483985, 4685558271307180, 4158905350371329}, + {1784446333136550, 1973746527984364, 334856327359575, 3408569589569858, 3275749938360725}, + {1496516440779464, 1748485652986458, 872778352227340, 818358834654919, 97932669284220}, + }, + { + {3850207796558603, 3727422831028406, 3797434477252654, 4293213262701836, 4516227523843066}, + {2048146359190201, 2164495845485630, 1987127118350888, 3702022928556186, 1248356726771194}, + {1517919028451878, 1390653207300047, 480997424969526, 463880049786815, 1566994328535414}, + }, + { + {4207292859242158, 4439237956877375, 6466630861755493, 6117169411664878, 6203775439423042}, + {2630289459558480, 2051409995957989, 2137890426251559, 2865150520767226, 2183646505352378}, + {250950165450403, 2108575357747549, 1858230594483734, 184468003072844, 1358638013010624}, + }, + { + {4795165927742161, 3556821674590553, 4452234877886028, 4063350508177236, 4357194618603124}, + {1363161060275889, 2019577584627825, 655391965916958, 2833727353647238, 2341948580614770}, + {1778982619924496, 1328609079558951, 1163827266617015, 1019320353990254, 830400209170522}, + }, + { + {3688756718408583, 4561393289356786, 5750092980695080, 4477840229539135, 3932387371938841}, + {891039147350711, 498786796467410, 3025350790192290, 652448826471937, 3394872208963829}, + {913282769158846, 347533899935257, 99606006705773, 1452035970297517, 2212487011762079}, + }, + { + {3066351608928554, 4959266561713426, 3505484480779672, 3313237988086280, 3214107063996871}, + {2440372328053980, 3986555651364494, 2478020726949882, 3029257951861872, 1322928669372349}, + {1259703414196061, 804804682694258, 2147323977049515, 252131006189623, 2246814133555350}, + }, + { + {4603288585029083, 4275494842669350, 4559975392494094, 5326825482142171, 4885471931566349}, + {616470521493849, 390707946935204, 1334622907385598, 2029831529830923, 2813735341554671}, + {1307353080865175, 1065210115652369, 1698012640184922, 2095589265946492, 688919666182564}, + }, + { + {4119409763828209, 5174415249772511, 6589359183715483, 3474134685034925, 3261800548024222}, + {3800663179733707, 1510662538907767, 2305029203181277, 1120480520235783, 2745749397969076}, + {959187641997964, 1919963359331922, 1067802756608566, 851276549968152, 2180947835690309}, + }, + }, + { + { + {5516816602304168, 5042521547053092, 4167576536206804, 6246422068954372, 4138350501601902}, + {2723435829455580, 2924255216478824, 1804995246884102, 1842309243470804, 3753662318666930}, + {2094270000643336, 303971879192276, 40801275554748, 649448917027930, 1818544418535447}, + }, + { + {5719674169295574, 4553720561304003, 3817628817819056, 2973527969819827, 4852805692036683}, + {2241737709499146, 549397817447461, 838180519319392, 1725686958520781, 3957438894582995}, + {948617110470858, 346222547451945, 1126511960599975, 1759386906004538, 493053284802266}, + }, + { + {4357186931049660, 4248263218811680, 5806608241664995, 5355507743318703, 5857341677159129}, + {1454933046815146, 3126495827951610, 1467170975468587, 1432316382418897, 2111710746366763}, + {750300956351719, 1487736556065813, 15158817002104, 1511998221598392, 971739901354129}, + }, + { + {3486884278433110, 3417910960117329, 3997194671566838, 3657316287568287, 4508063131522112}, + {1874648163531674, 2124487685930551, 1810030029384882, 918400043048335, 2838148440985898}, + {1663810156463827, 327797390285791, 1341846161759410, 1964121122800605, 1747470312055380}, + }, + { + {4458441089863460, 3942387623406751, 3851973436510373, 4407895911319668, 3358622222233463}, + {660005247548214, 2071860029952887, 3610548013635355, 911703252219106, 3266179736709079}, + {1344788193552206, 1949552134239140, 1735915881729557, 675891104100469, 1834220014427292}, + }, + { + {5125820669443841, 3461946287724414, 3994046236028930, 5907438988749520, 4920789118266230}, + {1920949492387945, 2410685102072778, 2322108077349280, 2877838278583064, 3719881539786256}, + {22727256592983, 168471543384997, 1324340989803650, 1839310709638189, 504999476432775}, + }, + { + {3589266475777094, 5791244982040267, 6521619274146678, 2903981043059491, 5401611380582210}, + {3565040332441556, 1721896294296941, 2304063388272514, 2065069734239231, 3056710287109878}, + {1969792547910734, 779969968247557, 2011350094423418, 1823964252907487, 1058949448296945}, + }, + { + {5777164948769480, 3890309495649820, 5262835493859430, 5169614751717201, 5401583088313899}, + {2459143550747250, 1118176942430252, 3010694408233412, 806764629546265, 1157700123092949}, + {1717263794012298, 1059601762860786, 1837819172257618, 1054130665797229, 680893204263559}, + }, + { + {2942680342150880, 4278613828995852, 5350213167690156, 2989120782966715, 4123142629949771}, + {2556444502235146, 1613361869622030, 1402717375340694, 2348339985765731, 3489511500408293}, + {1426750262638336, 314863572574246, 1394348337483702, 1967765724676815, 1262927622887481}, + }, + { + {4948972567610721, 4760459340435499, 4508373064131856, 4400791580495755, 3326118030989422}, + {2602109836867459, 1003276938441793, 244450874677932, 2495574856155249, 3110870831093824}, + {1089876164348856, 610853718362589, 290946077126125, 1189633635903067, 238116851513210}, + }, + { + {5818313990376412, 3745131403850386, 4984633161305300, 4588134365279068, 5605706152381173}, + {2574353462387544, 1744531678913296, 2081810750651984, 1255482175291668, 1579377192487289}, + {1077984189936462, 1101581309304165, 229118769946835, 213129071862971, 1105903869282826}, + }, + { + {4244657319305304, 4848112240284328, 4808999745724375, 4645297205085174, 4469873257565411}, + {2568686941901236, 1277107033850968, 2743723193537219, 3580901504461986, 430697021449829}, + {5110283730621, 236925008060043, 590130982419942, 541274580551940, 2155487465178420}, + }, + { + {4504922761302740, 3620992509914934, 3198533798350925, 3770782329534318, 5363163230411568}, + {275387113122210, 3501532982637668, 2704624275342757, 1489585626413894, 3573009822045302}, + {1859877583133149, 1445451213294944, 309288119160981, 1843441717427399, 584114977316234}, + }, + { + {4103673694186728, 6461574165907240, 3718162222127163, 6247603847194471, 5772831446786927}, + {2087653679988656, 2238424089144458, 2130407033226307, 1889280872742259, 2146873922212313}, + {500701236542790, 1839091700792145, 218488889984877, 1301749778593414, 614810966957821}, + }, + { + {4649730463510780, 3151390162038927, 5365410818081747, 5007340477551264, 5551016597277571}, + {2300360039943938, 1529233553127717, 3500096717284879, 3664531564773424, 3173693672061933}, + {882756809520167, 998774482479105, 593908492257531, 1132796830151366, 1780707297956298}, + }, + }, + { + { + {4583071810090063, 6354729884420668, 4077544622618353, 3073467147166315, 5285394920882441}, + {2237039662793603, 2249022333361206, 2058613546633703, 2401253908530527, 2215176649164581}, + {755822026485370, 152464789723500, 1178207602290608, 410307889503239, 156581253571278}, + }, + { + {3747179848085639, 4828649103787668, 4549946522264427, 3805208654040102, 5332579729206178}, + {3669985309815545, 2736319981413860, 3898537095128197, 3653287498355512, 1349185550126960}, + {1280337889310282, 2070832742866672, 1640940617225222, 2098284908289951, 450929509534434}, + }, + { + {5758557848470941, 5656835588370337, 3194707518654080, 2888905217772639, 5652892897517762}, + {2659503167684029, 2378371955168899, 2537839641198868, 1999255076709337, 2030511179441770}, + {894249020470196, 400291701616810, 406878712230981, 1599128793487393, 1145868722604026}, + }, + { + {4956087140669123, 3603920362709815, 3425295697596203, 4250911519607256, 4870927757824721}, + {3749755063888563, 2361916158338507, 1128535642171975, 1900106496009660, 2381592531146157}, + {1717539401269642, 1475188995688487, 891921989653942, 836824441505699, 1885988485608364}, + }, + { + {4274232174887052, 5592415718055546, 4229643212225114, 4106634029575971, 5067838489399852}, + {3493583935107776, 2439136865632830, 3370281625921440, 2680547565621609, 2282158712612572}, + {938868489100585, 1100285072929025, 1017806255688848, 1957262154788833, 152787950560442}, + }, + { + {3546872176125197, 5434827532059909, 3607531246326933, 5425835363204530, 5395826856780703}, + {3119119231364171, 2872271776627789, 2477832016990963, 2593801257642876, 1761675818237335}, + {1680989767906154, 535362787031440, 2136691276706570, 1942228485381244, 1267350086882274}, + }, + { + {2787309244260446, 2798685347422569, 6028275236918294, 4389895566536949, 3512537903582074}, + {2617818047455756, 2684460443440843, 2378209521329782, 1973842949591661, 2897427157127624}, + {1159906385590467, 2198530004321610, 714559485023225, 81880727882151, 1484020820037082}, + }, + { + {4265412029331945, 4082570389605622, 2787935123905079, 2861072139265641, 4774283971865508}, + {1377485731340769, 2046328105512000, 1802058637158797, 2313945950453421, 1356993908853900}, + {1237542585982777, 2228682050256790, 1385281931622824, 593183794882890, 493654978552689}, + }, + { + {4433747840806046, 3721621780348463, 4999137013220096, 4950695012032930, 2963731882329120}, + {3700733741689868, 2019165860436683, 839545028551310, 954045289946680, 2857671609142350}, + {2031235379883797, 946220755552074, 1457648474415011, 1222951728743327, 1610191601040290}, + }, + { + {4162295633314539, 4747504508371898, 5420102803358852, 5241263790326999, 4652112494046944}, + {3713236670706339, 1708249553383010, 1441184960961852, 2138372449656361, 2208801341603864}, + {743176047113998, 1210025633688996, 1298930577649249, 2241929289171655, 319185600078644}, + }, + { + {2463674019917897, 4802840710289795, 3812247475965604, 5281339404908102, 6114735096224475}, + {2361755477281753, 3920079557094249, 1772761852174940, 2188727617473580, 1972330964627961}, + {2224894613062235, 459022333460366, 853633232091964, 42662368548958, 1428459390829900}, + }, + { + {5876939711261840, 5483557082287477, 3340896169956977, 4741202975388493, 3246978129870096}, + {1888400628800904, 3246442970371919, 2048876033526183, 418388094414663, 2174354817875660}, + {1865410028261408, 627467389699032, 146077987303115, 1698467014229834, 2014393109530681}, + }, + { + {3339126822971782, 5967460547143544, 4911389289674917, 4202215034765918, 5578073611339204}, + {2670644791837462, 2651763434193316, 2285020046276825, 2227807589256768, 1464013488829088}, + {1806473647942365, 538787999504182, 512973154409687, 1944932181085518, 1069910541821032}, + }, + { + {2634758329364868, 4859512915801802, 4928387675794414, 4438135586288705, 5912306986153546}, + {2593937978996354, 2409464365976668, 2076140577147016, 4427101675063297, 1879995664155906}, + {407209884855019, 2088464831333939, 2111856537862679, 1631244096914416, 1074707055277992}, + }, + { + {4379690451347501, 4147722372858437, 6043474882489476, 3830885552726038, 5483938823325814}, + {502401202015803, 2110371415921011, 2529666734456328, 2767243204597450, 2341774206366416}, + {1547018311600067, 615783499206767, 485547569767288, 1517514580034299, 457611163959317}, + }, + }, + { + { + {6197629798333913, 2753838380751446, 3942959878910714, 3201428133247434, 4778709814063561}, + {2299141301692989, 1891414891220256, 983894663308928, 2427961581972066, 3378060928864955}, + {1124515748676336, 1661673816593408, 1499640319059718, 1584929449166988, 558148594103306}, + }, + { + {3540740886557976, 3183587715724649, 4694330636229537, 4258659768352436, 5509531109592197}, + {1784525599998356, 1619698033617383, 2097300287550715, 2510065271789004, 1905684794832757}, + {1465551264822703, 152905080555927, 680334307368453, 173227184634745, 666407097159852}, + }, + { + {4674947851286115, 5166365727170883, 4965938571130991, 4970517390710808, 2908711106554361}, + {2111017076203943, 3630560299479595, 1248583954016455, 3604089008549670, 1895180776543895}, + {488623681976577, 866497561541722, 1708105560937768, 1673781214218839, 1506146329818807}, + }, + { + {5492578995360943, 3611529141261548, 3553634070931276, 4797740788199803, 4532947899647969}, + {2412225278142205, 950394373239688, 2682296937026182, 711676555398831, 320964687779005}, + {1434382743317910, 100082049942065, 221102347892623, 186982837860588, 1305765053501834}, + }, + { + {3443537155111802, 4098841848663610, 3634013358734303, 3291752209395695, 5292412486267354}, + {2205916462268190, 2751663643476068, 961960554686615, 2409862576442233, 1841471168298304}, + {1346965964571152, 1291881610839830, 2142916164336056, 786821641205979, 1571709146321039}, + }, + { + {4996047770903428, 2555904966356003, 4013566981986303, 4737382312068285, 4233095136791335}, + {787164375951248, 2454669019058437, 3608390234717387, 1431233331032509, 786341368775957}, + {665807507761866, 1343384868355425, 895831046139653, 439338948736892, 1986828765695105}, + }, + { + {5356490725342733, 4068788685039808, 6047372383097019, 3426510449207690, 4705728718095123}, + {3007896024559801, 1721699973539148, 2510565115413133, 1390588532210644, 1212530909934781}, + {1205281565824323, 22430498399418, 992947814485516, 1392458699738672, 688441466734558}, + }, + { + {3538981275120648, 2874522279215958, 5384551777942367, 2992835507144444, 4815164902360267}, + {3302427242100220, 1955849529137134, 2171162376368357, 2343545681983462, 447733118757825}, + {1003649078149734, 545233927396469, 1849786171789880, 1318943684880434, 280345687170552}, + }, + { + {3979319739304371, 3173810108641712, 3480574285526200, 3800294424979384, 3983333585686372}, + {2754253003222887, 2275532945921888, 3105484814506120, 2795714951112672, 3618146930096140}, + {247596824353536, 285396193673154, 686289557053653, 399468081949262, 249109087231255}, + }, + { + {2723125664053674, 3464927193948491, 5445834280101391, 5612124161635761, 2933099654237696}, + {2672303537844268, 2038791134455123, 3285678115022383, 2900519586434405, 1978453542160588}, + {1705147526637648, 1274613803517124, 1602845665731412, 1064073198174681, 1486788069078519}, + }, + { + {4077390367222227, 3800932136610666, 4160144924974108, 3561238039866711, 5997919559096945}, + {819031393505739, 2088275424107290, 1796234646803442, 1388708737598893, 2937136216710939}, + {944757498200715, 2015594302768299, 813220261760372, 867002775164821, 501734915431717}, + }, + { + {4424498381651951, 4370145165962473, 4303795913232316, 4673352990886468, 3539252307041619}, + {4258052207216187, 3760480385682185, 3206156011228824, 4088908699869294, 3011569459811111}, + {1187304510804619, 1384816718516187, 514455602674227, 392638325371554, 588228521113051}, + }, + { + {4219797873858933, 4958627631706417, 4511020049341415, 3218925652522905, 5097166154822735}, + {2789655568104153, 4038602698967181, 1701909246528643, 2824012136983963, 2400715389506309}, + {1130277769648576, 1946206888578836, 1343266549795147, 2083590873042325, 264064594409097}, + }, + { + {3196954689864360, 3706526534080788, 3004981697061754, 5970179548131185, 5036616655131901}, + {1526130015031824, 3071067159569878, 2312643039801922, 2400491084238785, 2092334718179931}, + {1720808849496600, 410920656934828, 864594478015792, 229141760159822, 2037677155881017}, + }, + { + {5749040666310109, 2431937887261040, 3580364244969437, 4752008191428386, 4786853370158738}, + {1789863266178839, 2202012677135000, 2680121806416879, 1722812656485926, 572531509973556}, + {2175782751601278, 1608407337873936, 816706054544173, 258225706360159, 1478818623198000}, + }, + }, + } + + @(private,rodata) + Gen_Multiply_Table_edwards25519_hi := [32]Basepoint_Multiply_Table { + { + { + {4593529082752461, 4913481494458327, 5105340091484689, 3450213179198615, 5857240422918567}, + {1412482364088803, 4062389850048069, 923779398567547, 2023841154802081, 2607705760638543}, + {1825728698698411, 497946242397168, 105715611816086, 968568072676853, 592999326381074}, + }, + { + {4495184218325789, 5289073944532264, 4218636788579151, 4988461406676953, 4686478434934441}, + {2949190053601679, 1979948019919136, 2471186112468189, 3573963359061221, 2216896082446061}, + {743917567567859, 870447381138646, 392196079309387, 1786878704882853, 1520161635991866}, + }, + { + {4744444857419634, 3144662423000833, 2994206879871174, 4901643262699391, 4923693546628412}, + {3089537977529994, 1888948267748045, 1789290739253972, 2597750135306899, 3142762081370390}, + {1764333363430455, 898309455329908, 1381444383468949, 620561614151766, 158377983927494}, + }, + { + {5941345963042037, 3413323930288462, 5115763723871020, 3248416926384114, 5473315945632476}, + {2269111888817457, 3231588657429924, 3123230781695332, 1299656894822778, 1180051671372258}, + {407953783981, 1647278360877740, 584504284208188, 906066565536232, 1341016264992694}, + }, + { + {2432346762050178, 4412970725632038, 3922648159237080, 3005442494216723, 4442116552336937}, + {2381425302937802, 1387820520945502, 3125986768243210, 2463732477189113, 4185413214185067}, + {286790540720370, 376171092666609, 1535083117539001, 143466475958698, 1595136426572043}, + }, + { + {4277560779811042, 4605632954767560, 4619246140475080, 3484505719110307, 4989421629835765}, + {2829089547178292, 1790256014216198, 1797656649279268, 2562891052522691, 493980515519391}, + {62004126799683, 1668357417723485, 402010966421038, 827662362499868, 620754241677270}, + }, + { + {3919396572999125, 3838658814915336, 3750839246192093, 3726674239012627, 3831212626851778}, + {1227888687423439, 2913177985394946, 2412294236854021, 2805130984485539, 1308360976872086}, + {1643929373822818, 59659873139317, 1165353313134798, 2003225793255085, 1953102130608543}, + }, + { + {4114999970343247, 3274056679568382, 3954123294817179, 3769263204026901, 4245068682986802}, + {898618711827587, 1314215296781160, 1302503840208753, 3496738988099889, 1698289814254750}, + {1392999845620760, 634309693840701, 815492400002072, 340703897996290, 2038693787178716}, + }, + { + {5214250944985254, 5214298257940112, 3933846341585754, 5894386249523842, 5770685254784336}, + {1934541077562988, 2222946897208970, 2251242179056732, 1591285457544104, 2747813687509638}, + {1016675746743198, 874873189324170, 1360411561434916, 1581878592793672, 1548505102984557}, + }, + { + {4769452847684060, 4913417142027999, 4139599914472574, 5727971436547121, 5162246544117082}, + {2615904366263746, 737197398316645, 1602932940462504, 2167985252180769, 2559960808783062}, + {1882565165016312, 1581434850744420, 1900290919378503, 1985953844470085, 2168995994538833}, + }, + { + {4554120491153816, 4069860035617982, 4340413640826432, 3211862620694644, 5818608637282174}, + {1544885394173400, 1572082853154176, 1022098019061266, 2766927411109582, 2094149897716596}, + {1565161503379169, 1009067677698409, 1758464151571027, 1604769367828030, 1207412426608003}, + }, + { + {4015717287484591, 5253478309058146, 4070204443357591, 4445835852409645, 4665111518123177}, + {2854833619490147, 3573568625503236, 536183518454769, 2263990573554737, 4044861757799243}, + {1398840935273285, 790488576331737, 33415624257391, 1637374533896247, 2205752015162110}, + }, + { + {4260625486568009, 4637770924690903, 6480430642402074, 5542751059832424, 5622960391176990}, + {3715812780985479, 1012232238437221, 2466752896497024, 2611001871592954, 2143269004082900}, + {1886046851462393, 702395341735300, 737389004224425, 943477665979721, 723064819201181}, + }, + { + {5226062982149706, 4477280967632100, 3095356746333787, 4567645348066962, 4846495995079660}, + {2444351104229624, 212638631228834, 2148034812459853, 1041500100514044, 3853826660522166}, + {273084620529389, 1358348733025497, 1143735162114047, 1683813303234668, 2163735276562013}, + }, + { + {5320556456798805, 4779694419891170, 4876824494496501, 5903452387913251, 4729985500450036}, + {3477960290395163, 2468183980355970, 2936794001231177, 2308108181814059, 1969019168758558}, + {2160310767797410, 344164523453241, 83129919763985, 1315117733435601, 945559910324390}, + }, + }, + { + { + {4363327446469061, 2701839972520523, 6527685309871122, 4056456213766895, 3880569128224647}, + {423177393665983, 2333545232306939, 2028971153113312, 2728157354019203, 3777730507929771}, + {1435691822393684, 1850026012837208, 2218717487026642, 81859254010196, 244808221751742}, + }, + { + {4151019106002309, 4804743010530635, 3757223421954400, 4766036153424381, 6107544569595961}, + {821837003520359, 4010299059749559, 2863227431802226, 4078726431091997, 2442551264358059}, + {1428688544729295, 109069749881410, 270830364539996, 1755181768867140, 162349670944771}, + }, + { + {4642027397896088, 5510058210884768, 4553756231196669, 5068441159437344, 6370925538331183}, + {2639121586131590, 2408957406336796, 3986248100020063, 2989795052558558, 2164082093074357}, + {309881142350067, 2106019349943259, 816133263871674, 2018031260992166, 1563425406132832}, + }, + { + {4395494918929745, 3011447404605211, 3917145931603942, 2759967153620848, 6379442527779295}, + {1498799085180043, 1744340656397133, 2064851197592072, 2429833814776112, 2145324400616903}, + {614788980313577, 1501513053451003, 1472055221710495, 1920317897819127, 2208964791748263}, + }, + { + {3560784093342680, 4994362478801752, 3255476397621627, 4445556105981925, 4954471675599246}, + {2150595732685700, 3115920468099904, 1640951315905191, 3465930332728019, 2707896919197916}, + {612249867445962, 159208429955777, 563950177277347, 561041393363217, 1270750549218661}, + }, + { + {4520180469529123, 3948074172686157, 4376189225516076, 4643310756673520, 5392469157863016}, + {2055033216205027, 2461832572574425, 2742691255886072, 1052243367900374, 2752099767668600}, + {1827261746419924, 1468053133723229, 425022050209163, 1161272199376693, 589189496874922}, + }, + { + {4438522896195229, 5675329383977909, 4882438618733149, 5825827678555036, 4497535703422370}, + {2005207463235253, 2001528853385595, 1602253387656095, 3101879903751894, 2375325873201006}, + {847469444462207, 318959830531389, 408429171873782, 1661514071773102, 909441091898553}, + }, + { + {4102243665939998, 4215863334856383, 4408378320450327, 4622977479151665, 4039328475229204}, + {2174491994328136, 493557282042709, 3602705188549813, 3249913558677235, 2748481399349512}, + {758760864397232, 1830650226770835, 326981597370189, 1345979301472296, 174985669849506}, + }, + { + {3114038058163888, 4115257910705954, 5304962337604028, 4942520420915651, 4570979005352829}, + {1616868525778916, 2685769941228860, 1500533033491414, 2505164168102999, 2558430770009979}, + {2210398167996316, 2029125611734957, 1527318329127090, 226535237621728, 757747276478551}, + }, + { + {5660830910412470, 4039716640180729, 3468207460119772, 4614076381392168, 2442548670982292}, + {2039774403824382, 3183946537620297, 1982095153858182, 1293586830098836, 2438708503064038}, + {1357360519318812, 2045548381976834, 1766860667272665, 994521972889149, 393185631961961}, + }, + { + {6365035791876788, 3957527440519852, 4079038689927398, 4319831229004816, 3943934873019078}, + {2354388502926730, 2133757859975250, 3747940319461896, 1050624714408746, 3528225787559372}, + {1423510913950154, 1407788039482417, 761922275972375, 1783557942644647, 464730646959110}, + }, + { + {5146524748212414, 5035960985653238, 5028883959266913, 3282581313444735, 3905335483972979}, + {950694750709616, 2909132113066654, 2692353349246129, 2659905077175497, 978201784181073}, + {1078796318026741, 2070782433025097, 1700702188087909, 1447652546515478, 2144027848464236}, + }, + { + {4464099897473286, 3120477039861599, 5276369827125764, 3567131403687606, 4968190256098962}, + {4085811716920468, 2616309657099343, 775638006452370, 3253232221169984, 2587485588949578}, + {1012423034220617, 2045371869775344, 1260737445157584, 1833095526522043, 1066294173319533}, + }, + { + {5773192417487042, 4517701999097386, 4655557572427803, 5616698382540752, 3371552871839388}, + {2877566362774786, 4401330265553408, 3208625757371899, 1399785720487456, 2531340752609210}, + {1640471888126382, 1014801052117284, 1178704129888297, 982929852576812, 981292318502343}, + }, + { + {6476452238344334, 4693003674971858, 5211751500997938, 4121351294551163, 3152533251509898}, + {2011936343019114, 1133486795463590, 2647435457385352, 2628952425675517, 2374701464984626}, + {1245374341789768, 946202302464214, 1370924353088231, 682015131982855, 1275473548530510}, + }, + }, + { + { + {4235275101318885, 4886666925763093, 3781172458925008, 4774837350787537, 4519905633498379}, + {4159636855200485, 3150221611558687, 1363421772307006, 4120947913313657, 252053503603381}, + {45902352975738, 1246446699820833, 173320410042641, 1542230462600972, 692910725375140}, + }, + { + {4486356754653352, 5011982731057698, 2800477110646540, 4053556040992402, 5267180761554575}, + {710084928405448, 2105676789486896, 2420643007484910, 2605134634368896, 3302669631199693}, + {2191680341805656, 1972509245077282, 981795995975654, 852454486043614, 1189735660434765}, + }, + { + {4897930998338676, 4879106310620971, 4682586750207620, 6132197307461033, 4233426591406375}, + {3995777047683048, 3833719910688599, 2444044754441170, 2232313400412571, 1420975603500953}, + {1931343025077052, 1393738210614177, 622857924319466, 1123524882306454, 1963513295012502}, + }, + { + {4596722267439639, 4583990247552416, 3156713638372258, 5382313953040853, 4261038954366871}, + {1850504730697909, 4381679472853618, 2011448898092860, 2090154061858281, 1857166627539261}, + {1509035496076582, 1583601071466027, 421912810565136, 1678479534084506, 2033502297510813}, + }, + { + {5152283091655165, 5421718026722430, 3997156174417042, 5001987993936945, 4470112047504242}, + {2238137325796915, 1165391281982950, 2048774700033766, 1309041739154703, 3204681887791132}, + {520151332809519, 1588829471961614, 2166353389460390, 404024831468766, 1335244071323823}, + }, + { + {4644249663336450, 4507701753581319, 3592182426303562, 3683130545837732, 4598992005732335}, + {2528474489315892, 2071299735249833, 2619224970187272, 3271465188079442, 1519932762444249}, + {1935180256227856, 250757393177447, 1959439731378182, 1297506762666169, 575184640324100}, + }, + { + {3998007896814392, 4789639746579090, 5427007329099910, 5561733860472916, 4408133776555178}, + {3563813919863414, 1486712601904120, 2979081810490774, 1807789883906314, 3546555493967378}, + {1438068615152094, 34949160848567, 1911746456436447, 1412684293826264, 1046374507505090}, + }, + { + {3358198622960838, 3580145032458308, 6285906454262483, 4413045221104222, 5178477068028319}, + {1493476678908308, 3319155065445914, 2088667670293411, 3599225826407670, 3126758502479837}, + {1428599160764785, 602821281250279, 1877258833313507, 333285098655770, 740310036947361}, + }, + { + {4437738381533964, 4511430215080912, 4623800711093479, 3858159170572748, 3792114250503483}, + {2569231089452712, 3770152139328302, 3269539085929031, 2383025095054982, 2248498609425137}, + {375535123602711, 924645774628115, 2045840727994073, 766250909414083, 1069698092749769}, + }, + { + {4435294130703604, 4934879817377642, 3598080452693711, 4396369088299832, 6194434176750643}, + {3899859044211942, 3058237431324156, 1669265990252613, 3808823766704698, 1861135005644935}, + {1352954153117419, 632457759471481, 85028188501619, 1852310027888311, 1569233778435479}, + }, + { + {4994607739226691, 3549890051462689, 4602469939135293, 5262974664864567, 5829540047772287}, + {1177033227220429, 1414982090591775, 1722841418062421, 3232176376002923, 1625133154241833}, + {478074309368979, 623121553345246, 885068774570210, 117698677138481, 109006840646140}, + }, + { + {3228583777446740, 3685494966163883, 3859895584510878, 4132565491795209, 3602518465644145}, + {1476961150268616, 2321154243603617, 737795879830106, 3409730959236147, 2062873179003703}, + {1329749333731727, 46254713998516, 373767480531871, 1933047124368118, 430092326122748}, + }, + { + {4068619402415723, 3955796447715502, 3724578346370833, 4337532310052478, 4252452058492903}, + {2483442550312325, 3615812911108800, 2858427288312835, 2135393495237610, 596254727540093}, + {8959488931169, 1768025271694380, 2157573235225770, 292082063715064, 330646837880843}, + }, + { + {5129020796146722, 5575913156701592, 4643684154507286, 5052753294034768, 4627882199658166}, + {1682783588724042, 2651474877391040, 965357158907406, 1910483514645702, 1644451034905796}, + {976078747227308, 1952905065031031, 949292862704054, 1492592732072346, 1010921457352162}, + }, + { + {4006410514827696, 4367363852356865, 3108174070644550, 3399842446392251, 3651405461962036}, + {2963842949036336, 1110443523197923, 2370466150687958, 2051405852060769, 1998735788124574}, + {629291283140720, 1484410172308977, 1230690465849055, 1563468011476927, 1425159147311735}, + }, + }, + { + { + {5585239563455525, 4610636723895044, 5486382712767880, 5982393863492935, 4225244847092674}, + {2874785617528993, 1037465406252872, 3296887051144680, 2286839599744315, 786748793374778}, + {1152063960223905, 1495207756023516, 403624329924470, 288757773501508, 634701074033280}, + }, + { + {4288607522123402, 4846896146524989, 4707359298406332, 5135207568875886, 3789334229842457}, + {2917883701302634, 2925085599109681, 4014710226846848, 912132719741982, 2714081319314151}, + {204576686258175, 1916354881141604, 2182213405559566, 836541881049164, 1393662576855498}, + }, + { + {5759444997810940, 4193440837630205, 2993247029494710, 4574723038696780, 5462384317223070}, + {1429326167011008, 3849536799125309, 2267296904452424, 3653618160132546, 2008400870233860}, + {1583200791922713, 581155064879634, 776749520692821, 82151283071376, 1733847968592305}, + }, + { + {5824219020582313, 4082583579489045, 5236716515955319, 4695754388607834, 4087929633004663}, + {2723457493421297, 2288104271131495, 1889807602666693, 571526543144584, 2151183507738315}, + {216379584390389, 359329711860756, 2220840445637019, 1935487238453911, 314381139238943}, + }, + { + {6324432942393073, 3866303010803999, 3020114267775140, 4943018510078408, 2696166744880915}, + {2134908988986295, 2962507202980067, 1681144354786142, 1678261855220080, 2165079891714277}, + {839191618399610, 151822034158330, 65272611705697, 938153274860627, 14360318777459}, + }, + { + {3118414549517527, 4750668024533744, 4389573074356623, 3687569756425714, 5338903547055573}, + {1473478682616257, 3633382583874766, 1909784146543313, 3349986706799106, 993668408613515}, + {364270308207016, 667227739516977, 122427551474936, 957177061876827, 1110258403339423}, + }, + { + {4256211953323020, 5655880769308112, 5147711084133693, 3515346496193909, 3997285326966523}, + {3727619641010474, 1181551732606964, 2600588673325403, 2469054944509579, 3385365618247725}, + {858909692206820, 61057235030988, 1105898533486092, 2202030785898301, 1422234761465688}, + }, + { + {4566369519147140, 3936942479708331, 4946651352770194, 5597737572220025, 4038789996699983}, + {1354120322856538, 3567014996875285, 3125649205892726, 3221576024570935, 3804405204938131}, + {758252632702114, 914226082256766, 434171717412081, 779505540917105, 51590353584795}, + }, + { + {4416135541622855, 4651530410104026, 3833614791957416, 6714310821280595, 6038964345007539}, + {3122819969959355, 1154192626573742, 3197914057178582, 2213609121110881, 2415518693959367}, + {1900133378602138, 577297894556411, 1975904780443420, 367702995667978, 971695605371773}, + }, + { + {5691739211507754, 3947360890016266, 6002902486092077, 2925962297163746, 4016189592321792}, + {1294948213915982, 1859247234048810, 2826079115120605, 2717796469093276, 1254328736376524}, + {1309911522909577, 1419436642934017, 1066858837800204, 1932820656369018, 1183788306261091}, + }, + { + {4373293771099146, 6029412334349101, 4603988300239160, 2779063318785645, 3538182001391078}, + {354784062716014, 2960996156215287, 737478213901140, 2448765213738437, 2443710778345986}, + {37327849111839, 283459044945755, 353933224898901, 1645288254358965, 1295375429334450}, + }, + { + {3677292170794769, 3117650463171591, 4719239493455234, 4362161261080430, 5717636534074846}, + {2663608264759869, 2105855808111831, 3795920549032608, 3588992239888494, 2806554331792318}, + {2036310356419974, 1862941437683537, 2122628002305950, 427826430955887, 291402007632220}, + }, + { + {3100956993836596, 4149163064979557, 5785693523916593, 4751072583726928, 3316412298207139}, + {2400585099524078, 845178406557315, 1712123121349035, 1518690883002826, 2049951197688491}, + {1805653877101595, 2041224626272278, 851063029095866, 1497753468187708, 1406228898239886}, + }, + { + {5260996583106547, 4838608075273405, 5366327117123850, 4982440029922063, 5698050109664171}, + {3676073115087797, 2883668558141193, 2503071760256012, 1640618939206309, 3001604944016599}, + {463897193543924, 852129647033757, 2185610432355774, 914719594057928, 342067349817283}, + }, + { + {3765905247379871, 6338723143452534, 4484328730824797, 5536719681008311, 2764639921823257}, + {1030797243840613, 2110720517661432, 1415230398470209, 2977956931886379, 1982287306571007}, + {2180738906930659, 1806951067450075, 36005005692651, 303238055099928, 190139573853343}, + }, + }, + { + { + {4025496086329564, 5028184343166740, 4304607245262868, 5977861543210978, 5975943712754890}, + {1773953341907106, 1826809791300708, 924874532383668, 2964289914628984, 3000051694532148}, + {1048828262296911, 626018299495748, 1536855937015065, 557005099579827, 205000143299648}, + }, + { + {3686649646834702, 3431735540864864, 3540678075266127, 4755119958422340, 4426577953698517}, + {941815577996700, 1930911276112812, 3001621068228165, 1967675522206374, 892948220720651}, + {39364207708032, 54077643340559, 47072300438335, 484490203728205, 330170579231628}, + }, + { + {4702834568738627, 3291678731018536, 5642230899808367, 3758646432111623, 5155137589229851}, + {1020447780607279, 2803044870250806, 1618835409581889, 2925650123847541, 2605959132875331}, + {1190283817822151, 29815862110548, 1401771831527381, 1814017508050437, 751331585591881}, + }, + { + {5109595606310342, 4551817631663576, 4964640045962167, 2568185324125768, 6484076393091613}, + {2159866514586362, 1758376548473728, 1635569740383557, 2443910752037966, 2023235829583533}, + {535848012622913, 543536404720769, 149076814975879, 1567757637416350, 1002851193383852}, + }, + { + {3815561875504886, 4987304354260221, 4882489851059671, 5118054256243381, 4641807084989976}, + {850247344591352, 3894610597706487, 1974409276090169, 1605973976114297, 3601811238228268}, + {66796032196982, 83108349878636, 1058512765854606, 355785880766958, 2173660513649027}, + }, + { + {5137434473036957, 5769675136285847, 5436511544403722, 4264839407576387, 4266175067727596}, + {1941123290917747, 2316977311376991, 2913763383192580, 1172954226263395, 1951085968954154}, + {1331723279107642, 360406964548232, 602431788387748, 1292398959539176, 347247628588850}, + }, + { + {5432516922132898, 3078886318864995, 4583513191179486, 5867019372106709, 3411264839291911}, + {2170226002806030, 1739335733478471, 4017472424997012, 2918660155665329, 2793865679796361}, + {245885669910192, 255454579697350, 869246923980317, 823008017430135, 2047987637517532}, + }, + { + {4988197221931747, 4124266159815332, 4025663002514467, 4403069876409057, 2825978174946111}, + {3615548446949869, 2386240595324376, 1969460953567929, 2939417927358269, 1831662708850445}, + {1325588019367749, 1763566216507756, 445592400440775, 1009027711126237, 1471076108623188}, + }, + { + {3535455324868691, 4187842716980314, 6000482158112321, 3740505414106560, 5271856051582847}, + {1181816564414671, 1156678021972118, 2682384137206273, 2260248858296388, 1100324256765571}, + {1487590095774723, 277659353917859, 1381509894936782, 1061130669028904, 1364761503808628}, + }, + { + {4778189969823672, 4001451898457449, 6113563635354943, 3279804336055010, 3551539211588960}, + {3358253142401746, 2070882729090991, 2076758122179069, 2612730216279296, 2875157527961954}, + {1082784010061460, 1534894036268453, 1852407202514802, 2109696474131863, 1530718911157644}, + }, + { + {4923904010378051, 4401333064112293, 4345896142363128, 4462036896398403, 4199434117360330}, + {3404425764066199, 790431937118435, 2117892820897492, 1747418170252123, 2322149428381644}, + {1548552607325007, 2020524571521392, 198565314654983, 490668591018400, 531050967405176}, + }, + { + {5145969570912646, 3496492300608685, 4069590843971303, 4335556955800239, 3325377629546533}, + {2623126033999932, 3437252355580701, 1673392257908819, 1954440682865467, 2560737733895255}, + {516406018439380, 1624367135427190, 1319745729116992, 1076628515910554, 819495581575694}, + }, + { + {4005978810673255, 3160053273427578, 4474659303213566, 4173935427495701, 5201857712754300}, + {843136030895887, 1929944939303616, 884551308418834, 1356687291240061, 2259204804361506}, + {1461715846997541, 2038281458208083, 2119767535863762, 636224052565171, 1712721429371389}, + }, + { + {4975731433879692, 3888553624589664, 5228917373823987, 5038386998880250, 4707655682255612}, + {3409114563124612, 1820064381354618, 2421007346773091, 3239920960596314, 3726969650504610}, + {475869807928836, 887669112822100, 481835223948027, 1468799954696850, 1370247723645687}, + }, + { + {5954383345631578, 3742995524386402, 3611065523713845, 4447231480190211, 4725820376570018}, + {1943063487159002, 2890245371286974, 2837035330843453, 1080549927676027, 867285909606140}, + {1413582027032622, 1273926892909999, 726179076119442, 699229594605794, 406422835715518}, + }, + }, + { + { + {4513888950241631, 3212738446973608, 4558390526464820, 4859080230791315, 5273416148656656}, + {1326059070986753, 1683859889439034, 3052200172327874, 3805600625804475, 3687690452819464}, + {1081752225631401, 201284952113932, 1619339403526661, 1533363030164674, 1727571790703503}, + }, + { + {4206177554516483, 5468031785191800, 5978090949319557, 4899439545685678, 3929672195094815}, + {3151535789445747, 1741766716299828, 1742063303545331, 2027626928190420, 2245203856982753}, + {868012933261061, 1472665613225898, 1744063644616181, 1350305502884983, 2227467074628670}, + }, + { + {4669057309967741, 5650515638764201, 3042033906165361, 4078124455841206, 5666341739515191}, + {3587030559572189, 2850528363281919, 2974216851298661, 3227895056003248, 1349661756105253}, + {1313383948772993, 1074655824143287, 20040386640896, 305794891855170, 2123092901229151}, + }, + { + {4199945629383318, 3594320984526977, 4229880092041671, 6384664478996443, 4732837782434517}, + {2744443256254860, 1013874505344583, 1972732629285783, 1936827407065469, 1830481951704579}, + {634737804354539, 422989080575800, 1774993942417585, 688011718282303, 581542014403477}, + }, + { + {2816888940207091, 3903781507184007, 3616069829367681, 5525450216549915, 3780846206608878}, + {2517199667227667, 856367096857961, 2630571629218547, 1768604592283813, 3688963458794126}, + {1683677903016217, 2036167240589310, 262287609979509, 977873833112269, 433284640623898}, + }, + { + {5477402921384451, 3117269161199628, 6049837891653338, 6034999812243824, 5356551064760510}, + {1755760392036121, 2130115351478138, 2694425247498002, 2043622709923142, 2338295058055586}, + {1425112218383847, 329346717672590, 378517748485393, 1806152114945447, 1211275024279312}, + }, + { + {3594715588472482, 3844045487620198, 4484578538777484, 3113667148844230, 4337495224693479}, + {1968587687914188, 2881021730370090, 1429009633828432, 2770076641127580, 2012343565772575}, + {1629969809602186, 1106234784906336, 863587490378700, 1792807263239898, 1429043938024750}, + }, + { + {5737804770941067, 5078013196347608, 3898224610791405, 4804530531188967, 3180800540121608}, + {1973106012015851, 2593923400059844, 833516958919695, 2182197879897069, 1721403407106648}, + {1591076166555979, 849361769125080, 1443799738863429, 166584794343739, 1861773413238536}, + }, + { + {5730227718465208, 5596273386383722, 4195854427433762, 4069266668520101, 4524280540784068}, + {1968981310480276, 1950975116204498, 2592307802896060, 3813918534870745, 2620661073133464}, + {936764653391291, 1452448249608980, 1312847510424692, 1846051928374105, 531372961271999}, + }, + { + {5549943196407418, 3432818760073271, 3449244033859606, 5283577488399029, 4864604608008479}, + {1733819728686816, 2936024966547233, 1590816041651632, 3163811004299109, 2676757470677367}, + {1319097278964637, 787422552977413, 1599496421811883, 1959379193761008, 1506646670818903}, + }, + { + {4227254412838170, 4548570321204425, 4285644009760393, 3751016940211786, 4098838617641914}, + {1732471582908700, 1866076266304485, 2819215151172481, 3074745073420508, 2774887501545996}, + {717261628309176, 1858796230699344, 551077134877547, 149402535309098, 2105648961714394}, + }, + { + {3871916223505114, 4749816457502813, 5358561311326743, 4112663885073414, 4137415642080692}, + {1127279535151728, 1199265744257977, 1248562495202825, 1868357952639788, 917052103965266}, + {25664888255034, 1628004430886188, 1439984389498414, 1961957176184883, 182596205772698}, + }, + { + {4179077756813138, 5647690538147405, 3274850245594335, 4319226212135161, 3864148139899748}, + {1739387701061410, 3112148637704823, 3028846916651989, 3700388643798173, 2412185850016002}, + {975143220058337, 825243809988211, 515186464897625, 1179464291552333, 2112614471328036}, + }, + { + {4947873049161087, 4901033700427489, 6675583808729484, 4941667050946228, 3120269525234559}, + {2996598747660015, 449189546044795, 2197501482114022, 3158206489499126, 2705800926920583}, + {96737353895103, 1534044505139178, 563303281603459, 407703386650348, 1821870774469537}, + }, + { + {5049500432849751, 6040441932911013, 5618655093441099, 5061587505104794, 3837175101097290}, + {2654088892951999, 2871006956063187, 1742690076584393, 921899537851044, 1870021525725886}, + {1637444308641066, 1472124432669136, 741811397216072, 1252880060061292, 423564866101658}, + }, + }, + { + { + {4796818337004571, 6222611117014093, 3083419469630983, 3862822099971652, 6509664209117283}, + {1171837083014025, 2516532715963947, 1770010974323603, 2517908022038722, 2020794083615321}, + {762321251771152, 1460210191529427, 2248797163104578, 217468651569622, 63003536153574}, + }, + { + {4259858178043342, 5554955317979561, 3911791110113593, 5525892988208900, 5545696994818748}, + {391588043113892, 2202456919563943, 3869688632614537, 2945959779196464, 2143606811138354}, + {719793864170869, 1411477466905009, 1515019021063010, 1483421690183889, 1704042941619334}, + }, + { + {3034963268199750, 5870224135513779, 4115305817554936, 5421579290342892, 3835694901998808}, + {2769635787032504, 2958323523618463, 1537480429839772, 1483278086593314, 1378968978067758}, + {1315034452637574, 1172434640681242, 1135533609020364, 253349230877293, 161211572823476}, + }, + { + {3942650253210285, 3918824117103583, 4001647299508483, 5240554545879312, 5035373070605317}, + {2659408003097885, 2049444491227493, 2594690944032877, 3421228755254048, 848234126951057}, + {437225545901468, 888271756229202, 903344393515123, 162913205438885, 1475178706291532}, + }, + { + {4287921885063088, 5041248821201299, 5585484729625036, 5534367719396511, 4532272822475758}, + {3707293450173872, 751219268219695, 1525065253586106, 2054680090861517, 1393874745922970}, + {1910711495320594, 321017884248758, 1651671690842787, 527123817162741, 847944616444202}, + }, + { + {3415231495445846, 4190597015532201, 4905073239386883, 4940927269911495, 5980840029199164}, + {1474221667712446, 3068688770339565, 1358088375247373, 1853329794010803, 2931295009606082}, + {70084211861389, 1248863300280704, 1009402227613886, 1445171656255193, 728732085908498}, + }, + { + {3340501878764401, 5410923356778271, 6030788584012822, 5594611759355304, 5267577702264329}, + {2869750492870027, 1153392601340917, 2754776472841130, 1100510641818700, 2870221151280913}, + {1481950048975238, 97096668186528, 429204027887699, 1510003697018425, 2114825823462494}, + }, + { + {5159850395392603, 5067743945456882, 4551909910661973, 4393814096795878, 6145580658249508}, + {1440929316705129, 1633730452330828, 3657204567294737, 3657918436987822, 2561724546723194}, + {809017030155597, 1831934834657405, 58189812416765, 1517873507099267, 889681994437792}, + }, + { + {4153444167566628, 4372997703941365, 4839161526733376, 2653398635504610, 5324373835991045}, + {4007354401668216, 1201450641763461, 1526795422335006, 2273741230894754, 2130356372280991}, + {1057020591512462, 1324094020999413, 655956927766596, 659874727272243, 2024954110083652}, + }, + { + {5839605326568475, 3831434019746100, 4883240784156331, 3880003889048305, 4841910074653809}, + {2844236939823231, 3043783621566488, 3890227240890757, 3800769469380331, 3175183419371011}, + {863608592350445, 1111828464904337, 322487356734403, 60843367779474, 775147863897458}, + }, + { + {4129677439236364, 4363616958764152, 3255333433286932, 4071265658640216, 5527560633207578}, + {3501906805856088, 2995655036831742, 1989943322549290, 3334534687075832, 3371315397704424}, + {471893887981193, 1459834432249674, 229072407724256, 1165980516905022, 1036865507138076}, + }, + { + {5587927329012785, 4196019533185475, 3488244055775669, 4788679066807545, 3936797203887245}, + {2334971095120001, 1054095219722721, 1729452124624259, 3446754994849569, 3835890504040419}, + {883720982539262, 2126174835830047, 1858128110066030, 1402309396930944, 1358212283922371}, + }, + { + {5437236132245684, 2619202868264644, 4266616048403094, 3779544081061673, 3472381895789909}, + {1158559475833858, 2227035258871772, 2170552210791850, 1087363571520417, 2867304161007231}, + {116357390237056, 38114324586368, 853586347213800, 1638943134635811, 1882124412005945}, + }, + { + {2871025108215057, 3893039278529517, 3878244260089116, 3893554424872522, 4708186328386966}, + {1760242418163439, 3855738944127473, 2877581036561996, 3253911846338252, 671018190326366}, + {1641735698439468, 1630160111859414, 1920036824528970, 346120100914920, 385076471695398}, + }, + { + {3934974918427731, 3807320560303621, 5860456491598573, 5199210868384009, 5781319959443384}, + {819456425532597, 2215390016559513, 2301197053109143, 771274648900875, 1303516882225152}, + {1530178090161037, 1646502716614548, 1058228190532635, 1522572712238470, 991147078780643}, + }, + }, + { + { + {3763364100157977, 4436158450653533, 3664705850096563, 4592883978910063, 4855668048892712}, + {3431442042489897, 3670457457720097, 2927483669898581, 2847896260114069, 3422237175305894}, + {1907217462504765, 679044428705663, 1371479879514675, 1420793148384765, 190685345044087}, + }, + { + {5140896563326095, 4954544354938625, 5148671791011404, 4813313238272129, 4814788700593711}, + {3528505813008031, 3913030166310689, 3457534787545946, 784019563379975, 1449546143149561}, + {2213525665395526, 146358659614731, 1573034916169973, 1131167148341295, 1194403623212224}, + }, + { + {3034590507214084, 3771531416844161, 4279939895181473, 5778619660734332, 4308244183318381}, + {2105305689409168, 1932040296635725, 2559301608776867, 1653053081843050, 3498476220207615}, + {1916484225176, 1896106466807315, 1279953155660650, 1725386140841619, 757101416534772}, + }, + { + {6555214085737347, 2980588876755702, 4785845115539682, 4430693817238987, 4107141749770380}, + {2133488547373079, 2884934342093682, 1652284377802152, 4287340267215791, 2741073463083472}, + {655928016394658, 1087485647128905, 1281789693328119, 2088439151211398, 1863153332596984}, + }, + { + {5220143354789533, 4303392603719785, 3697665521216293, 5367115036779017, 3354674257103145}, + {2461817469666051, 4062983661511151, 1323101412046937, 1360571080713195, 1716626899554003}, + {1790273650925445, 2180187262630477, 28219260774301, 1951582862584504, 1059160821201578}, + }, + { + {3706860118974125, 6182298149062642, 3206841902738667, 4986080379139384, 3223876357324169}, + {3108934357344473, 2823383892309930, 2709776767813967, 2732378265738840, 1695118712507849}, + {95538772778706, 1914880923031197, 417513632407841, 1767845086605839, 832379724270193}, + }, + { + {5132941124964776, 4798553016886828, 4052101096460607, 4475816634870178, 3176602159556433}, + {1456443406045738, 4161184975160682, 816382632051403, 3678387736600146, 2166890266198131}, + {393110820654303, 662371396172458, 1370237312917823, 2034119121136113, 904928937827}, + }, + { + {5075422185081409, 4699433492834214, 5948286955155472, 5933498265459676, 6441657203628461}, + {1257344135899307, 2776494249972420, 1637109398723534, 1801319038042246, 2082644998926031}, + {189274223123103, 2188109173279445, 1461570511269332, 151886143484743, 1557837550414982}, + }, + { + {4365365818590957, 5180206223815189, 5035374537630803, 5955216889373899, 4177347431591518}, + {4105224954841159, 3814048291702159, 1805828417935849, 1548444252518409, 3761242775865814}, + {966697507230426, 1689614203301123, 867370120071235, 563108996765880, 1552869095947518}, + }, + { + {6190612622769392, 5262116783421509, 5770823033954832, 4892678801476142, 3789326136184388}, + {2680510164419078, 3125272296703659, 2480535210869218, 464721098622880, 1141684153257222}, + {1871952745325912, 144470913279784, 434631777342778, 552837449330893, 642852750438644}, + }, + { + {4755508755993467, 3653868693631672, 5880862524139354, 3244860344044728, 4481011039901531}, + {1809358219650823, 2339660560948574, 2410584439137912, 1286742564054194, 3633419878206029}, + {64765075641768, 68764899017819, 1968408548264810, 2037002115471749, 211556643344747}, + }, + { + {5543625841706618, 4560629261024327, 4731751483103768, 6307249547601622, 5012757099435702}, + {3301009531661216, 2677459079264873, 2707326467220240, 2261655438430016, 2962646350850358}, + {1579401584164790, 1951017356653076, 1801209077919862, 1153368800641031, 1775772413220140}, + }, + { + {3556317598507403, 5934251293404526, 4176527831714322, 5239968931380200, 4506603999756496}, + {2798836099557035, 2002468979873228, 1132424890166086, 2388404451698808, 664387721246094}, + {1947208168676528, 1750536949518976, 835780038339521, 1802624114603814, 1867663782159356}, + }, + { + {5351331441108046, 4901733280572801, 5434846723443585, 4372148225205494, 4376250516119689}, + {2519667781375866, 1132412577764719, 2322930879998983, 1660817657158452, 2806576583179867}, + {1273923691469553, 1862566872300733, 2236121435313308, 274949363314112, 477088969758259}, + }, + { + {3358480296518006, 3814827118577810, 5033804317047304, 4803399909431456, 4940637069622359}, + {1965761504739774, 3200209926214852, 3722168784530754, 3464219522306102, 1953662369491229}, + {1946412430894973, 2031215026716789, 1150845535883051, 749273986980949, 1433091314912259}, + }, + }, + { + { + {4565135018699993, 4952235844716789, 4332776238462736, 3944983589420527, 3534528668424353}, + {875483311206731, 1070293195031859, 1281389774974538, 2234860500431395, 3030484939064537}, + {2191861413872447, 1998107865473216, 135161483760725, 1133778951112075, 2177808149908975}, + }, + { + {4472607877838387, 4680291079417999, 5266381476904463, 5448529984859500, 6037873358663623}, + {1355285592679599, 3216332013847453, 2858567121370219, 2432376038574376, 2734263724238645}, + {449706520184472, 2214233011551797, 684523848529734, 431843026966950, 1758835924810462}, + }, + { + {3413242279346498, 4524603375434282, 2637627437993422, 4373910262118552, 5420094068912965}, + {1617166089281188, 448710947316786, 2017034644293574, 1886691422085664, 2375442150405559}, + {1239614751060180, 254449956067847, 1915952567259905, 391989559805324, 853553448301328}, + }, + { + {4142542119790983, 4675453183245373, 3888287250251838, 5522078723840086, 5552692716915124}, + {1381495390544381, 584763141985101, 3131504846670548, 2565162572339012, 2037973653370614}, + {762375715838646, 553562190209386, 1146347552263484, 824188464596685, 1830942666102590}, + }, + { + {5823375217862555, 4240127004291848, 4611065015006224, 3518908128296096, 4915429068500234}, + {1348374701112873, 3953700554194482, 3402331094627540, 2804779645909956, 2204826476892034}, + {2119092558617159, 1045482671389213, 690197889240825, 471826136635342, 1637923217880356}, + }, + { + {4059066650158007, 5141565698162354, 3733026015817812, 4875063676054927, 2832005231346927}, + {2181081937454965, 1121830291087960, 2832579231299976, 3124836269482413, 2225668708158199}, + {1193994157146400, 1628108083694642, 1021885296427132, 816068909639879, 2088480068848711}, + }, + { + {3180618525607636, 5342429333917474, 5008239417572170, 3506064373977331, 4538653079573275}, + {1673050054377632, 1765054067091528, 2962973405879830, 2339273872052899, 3950931503569149}, + {2229241184614921, 2107352800266199, 77312115078922, 2151892262530718, 947910914861383}, + }, + { + {5320544374459840, 4141095319362425, 3313360370605015, 5185507100540960, 3283266576250376}, + {1528297312537716, 2187935649407647, 2967731417391411, 3155021192657576, 1577434241618944}, + {1385713524190245, 153942078459639, 747467190641094, 1446053675113471, 429215290527338}, + }, + { + {4130033413775598, 5253437474448919, 5186743122906330, 3072446418934431, 4486276088811881}, + {3865635552262096, 2111934227084997, 1803460783795098, 2595364764305293, 4294038033412459}, + {1939054538963024, 1515892461529143, 2145315228101212, 206131396483318, 1207808442703235}, + }, + { + {4285235833599064, 5004869505494285, 5398338412388895, 5145057161859867, 6219558308357834}, + {2122251221692966, 1686529461497383, 3592144721245791, 946103181235971, 2261774551055452}, + {1519512635495115, 1879830706415200, 631994832099345, 90552542491442, 1074938948794598}, + }, + { + {4349405123860786, 3135193611243628, 4214940643324649, 5373877724549797, 3499285433136967}, + {699708361184464, 2781323063917462, 1664177773796467, 2129061781951253, 2929310224293355}, + {881819301152893, 1404208553713523, 1706641996539966, 685345252606027, 879987031868371}, + }, + { + {2629920833708073, 3077736686198199, 6153945246604194, 5109883364128321, 4007866927409167}, + {2201062670972485, 2517508956278887, 2681660437016124, 2026769404043331, 1562746334284849}, + {2029537774099989, 798336123274982, 962765795717174, 1441375461370721, 595792417755859}, + }, + { + {6147148440188849, 3255264873123981, 3737719663259093, 4820083084252873, 5252844759112604}, + {2825984342500049, 2739886905391569, 1677188826435105, 1932192000687991, 3155126576093338}, + {75347910850483, 59335245365512, 2051925237105745, 2044824231668461, 970303688628601}, + }, + { + {5763564504160432, 5421442243725773, 3588496091914407, 5369436266097375, 3995085142922692}, + {2488955180168268, 1799719498283103, 3012193868704087, 3191119683274303, 1313407450591024}, + {1669605168509235, 1046380333598262, 8317204728147, 1002144485955824, 1980712166998785}, + }, + { + {5208877095968696, 4101472145123500, 4547654469901586, 4596473001183302, 5108183921345691}, + {1614319198851918, 1592777501272444, 2078178842786638, 1134074463419502, 3406886179792273}, + {46520703266015, 1463053727782106, 1641431035629451, 1167993397224604, 1860200763335910}, + }, + }, + { + { + {3011332796830409, 3293305844851756, 4350706657635174, 6528175041183782, 5633500660447495}, + {1684548552982151, 2512680297050328, 2151565475089600, 2240257948464080, 2357334086387757}, + {2245889758290233, 1304556815701186, 1427348922813143, 221464961710041, 2149077757654506}, + }, + { + {5021889171679330, 4462128123863397, 5496067810219064, 3884382915013647, 4592260500935750}, + {1200977971745538, 679604753110803, 2370440117588934, 2264961098110051, 1017048311556208}, + {1190992926530423, 1046016291129455, 1934369009614752, 958221374199446, 762751542850234}, + }, + { + {3460977055305417, 5402529018730102, 3060601098222640, 3497142554641379, 4775614304897016}, + {1196600994744545, 1547369290503378, 2035231477477616, 1257032246257935, 2729013549752394}, + {1316355169784636, 2159471323343549, 195437001734225, 1784725127680235, 23628188515854}, + }, + { + {4414887133757738, 4702915728776787, 4098231006823107, 4707645820548353, 4031420634244190}, + {4034197670769956, 2299895540249251, 3720313013014369, 1169924369129605, 1452708652401532}, + {246845927125542, 475207520380026, 1495857355234583, 1332907410765356, 1137190823002655}, + }, + { + {4619638086363716, 5112231939480403, 3430351651754637, 4072797244384643, 5452815353333736}, + {402770419372162, 3130948749709529, 2422951975073025, 1521258543891683, 3268450338566556}, + {122249525311324, 1126352422834922, 929325077009082, 782368628240853, 94217591211022}, + }, + { + {4962635153104108, 5274135403834507, 4755774461820061, 4383546262262835, 5457666487690905}, + {2990995606289826, 3021922427972001, 302802129599791, 1502244105829111, 1773114045409669}, + {156241863414061, 496518516536107, 402847929676013, 1139792271454333, 1977247161507402}, + }, + { + {5032814130431534, 4760678921877281, 4442869438253961, 5565429687944605, 4317400766530169}, + {2463323770855702, 3896470221755473, 756431515781897, 3201672938286523, 2288460277235041}, + {1855056967762827, 1495181328549832, 966278130514841, 758391654071223, 467588501531856}, + }, + { + {4817034814919500, 4208076967893683, 5868839484739037, 5852497340094076, 4630054499608831}, + {2436900424213206, 1954148435588967, 1712385658617173, 2723793304425402, 681838917243489}, + {1439947543028469, 885225692302481, 1285222886469976, 1588398795428018, 1298691185892088}, + }, + { + {3166915207030205, 4221727132556131, 5745276646060520, 5830694990900872, 4237998343894079}, + {1368851636374513, 585540725726993, 2239345036245042, 3124363364569248, 2914970196697053}, + {1206666555409985, 1789371104267935, 1925466428785716, 378678703847709, 378978574609534}, + }, + { + {3049990186077834, 4282707068721497, 4031467457902549, 5045270642251952, 5619239366726696}, + {2247218341382540, 3733105160936895, 1542123681165149, 3690639696246556, 2686757663719606}, + {1131525507915411, 151967851358587, 1334045685598637, 1807594577522576, 1666949318203671}, + }, + { + {5317642436905001, 4262905497079623, 3806587609027544, 3162214737577195, 4598325819108034}, + {2322709256244499, 3364701239080335, 1085438519194966, 2211341194954781, 2734280485747362}, + {547075051672667, 1927631982974242, 603999740914722, 1974345687792190, 310412755046628}, + }, + { + {3092260334664458, 6358353190373839, 4150234089958180, 4141601803005412, 4164851538431420}, + {2480565549840732, 2510439995547619, 2534702111260990, 2561344597955166, 619102460354386}, + {1996829248620682, 1059563669319507, 2240440638640706, 1599145288747177, 407659118560947}, + }, + { + {3115383537041122, 4344887992692310, 5501863024972572, 3993241570720752, 3416751871823654}, + {1717619697579090, 3621794853637170, 2666986311609642, 3029150476191498, 2414353362640396}, + {2142003785026841, 2167906365984504, 1742773278204754, 812925480008831, 429368090247755}, + }, + { + {4184856094603567, 5404235283771230, 3764176438258862, 4280121628742729, 3445790640140600}, + {2656068733977443, 2976637537776442, 1238993222325972, 1554795161393303, 2131523863405492}, + {1574345185045103, 2079161140310195, 2092484433153763, 1408980124437971, 44981420431371}, + }, + { + {6193742471986890, 3621814037880206, 5498721010846514, 4536848636334539, 4762288817182267}, + {2703599140394458, 1961129680427764, 3192043467883058, 4259887504588631, 2455375021790255}, + {1758602597767485, 709830862658938, 931608374711636, 2198476269423406, 69272189710304}, + }, + }, + { + { + {3960691793618422, 4697205665896081, 4233023106925560, 3551947497905370, 3667490775726784}, + {2716251404526112, 1631117916585969, 4014857913931082, 2213037729836094, 1396521499150134}, + {296206175452724, 658879322369119, 97943562265366, 1761747874053347, 665498744562262}, + }, + { + {4542146017866057, 2313615921887147, 4181202139006694, 4414799599657545, 5341405847272363}, + {1200760264207189, 2304738880112015, 1927960174691144, 1569518880089323, 1152309979337507}, + {2038947849479643, 237162323211423, 2065816839891168, 419806183479203, 384865548997533}, + }, + { + {4632532202820720, 6679838284939842, 5003934316625137, 4209971835933588, 5519581415427037}, + {1152764853239608, 2282089860477202, 1601380253073465, 898105377854964, 1583948862629235}, + {1558193059260245, 1778073808602536, 402624851529717, 66752783641769, 824353727713740}, + }, + { + {4121947878564012, 3974762513146561, 4400688676047089, 3750758292493538, 5582121141429898}, + {1987770197713484, 751549594590657, 4130774294058181, 2772087960475462, 2398377455469772}, + {1021194340773145, 2214506742467645, 1946787888944335, 2047968106648641, 1821857137920583}, + }, + { + {4817011285691457, 3821500381976103, 5867746283021767, 5892999478528259, 3614975724251316}, + {520345345283715, 993525428347841, 3082505540027545, 1401316007351695, 2524441889115400}, + {540709883326476, 664748033877723, 77460650157458, 1882229467398241, 1217186023704288}, + }, + { + {3888704843022071, 3022592939512474, 5839771089230787, 4705593175556810, 4617871784452989}, + {1148904473568401, 2292434344833748, 2860017655924869, 896886146116790, 1793557015614071}, + {738867948290551, 1113067062951318, 2239418068162676, 2235388618772922, 321946428440080}, + }, + { + {5186369799189058, 3697173555759488, 4262727107695046, 3185380591286776, 4149807772745719}, + {2507278187062390, 1965300287234722, 1455241861966706, 2358026574953040, 2356583034323921}, + {1141974899967420, 1197500508248512, 1725264994009043, 1639228663875285, 1766256613674282}, + }, + { + {4859130511022316, 3438619274603782, 4274393918753007, 4542539306472407, 5021829178357491}, + {1473307785816396, 2183888493524504, 3592230148429221, 2872086545946123, 718894511556159}, + {200438687964996, 1579389594103736, 1144999901302662, 1292188560016150, 1342060233269448}, + }, + { + {5322785092917218, 3564464821553428, 2465159528975281, 5838118438127962, 4862308511365583}, + {2206232904105334, 2908798660147806, 2169658158959269, 2724132358944628, 392390928972895}, + {883459081700629, 1602090588151437, 768552508263143, 1181944834979084, 1796139787109480}, + }, + { + {5591293901585158, 5161437494483979, 4307878889760969, 4546298250229339, 4189604893397730}, + {2182554744233356, 926666458178889, 2790825304990041, 2529147957716171, 951582391464256}, + {187571578269437, 1207365261045700, 1671287753495621, 128062601272884, 1097620007687094}, + }, + { + {5979255840859055, 5170212343908976, 6251571908864416, 4044340797680332, 5873982661311143}, + {1856097540852989, 989253754708050, 2232404724159712, 538127825012338, 2301974812680125}, + {875553341339604, 2202671771469035, 1916683928798488, 1628926854796717, 2104927509529811}, + }, + { + {4738081053584946, 2875665464097852, 4082354471082712, 3079977082389326, 4643006842643895}, + {4085499965974240, 2403823491084742, 3352533311494316, 2981802103584372, 2409154352569497}, + {822917758900752, 1019777701975664, 1564136027018780, 1218107309963297, 1014127758290355}, + }, + { + {4211670720265322, 5260586114139374, 4117778612287885, 5761523698172883, 4942445429900242}, + {2233928901439648, 3249090656816698, 2685023842449397, 2515328324903077, 2780554742949852}, + {1119507853423473, 902873322434013, 1683813506511239, 99271672214794, 1043609318229518}, + }, + { + {4881172173279202, 3599812968457896, 5389450859587312, 4590538673755018, 5926347639505399}, + {2643454724039014, 1385194776028482, 3573341970152704, 2554149121763820, 2626184303949707}, + {1041863798926969, 1989079677249410, 910600041636905, 172639986070412, 958797345271109}, + }, + { + {4102514793801097, 3799057862785664, 3089506143944932, 2968464716766741, 4933382932746089}, + {2671084000631505, 3069928136724336, 1615118202102194, 2860128525830493, 1072943882334681}, + {2239551548278550, 1569208624262185, 270318489599140, 666224807173956, 272660472277513}, + }, + }, + { + { + {3788400011322929, 5238791757709216, 4201438471307196, 5718998504437804, 4699660978114753}, + {831848399557275, 2203944328508070, 1205773492199750, 2947899883606056, 1258775953756159}, + {801855642469056, 1726062700700587, 1064722548099106, 1128997468587175, 1368420390253860}, + }, + { + {5220756346668707, 4207778951928942, 4451591079714714, 5561602467108901, 3701332347939515}, + {1095027470911861, 1309452919940954, 2417363745862806, 3417231569067727, 1895316643922203}, + {2142749866659158, 1962490102531981, 1691447155265793, 1827079035266074, 3803331638058}, + }, + { + {4981668826515757, 5644770367578110, 5443857182354756, 3149391452129516, 4066238206100559}, + {3356282538281353, 2251921811216688, 2887149285344786, 1384857237573084, 4057072468959031}, + {399619403797256, 1517816986720610, 1503473770785461, 1650204761619743, 2016574488970872}, + }, + { + {4082671840470154, 3874834197714005, 4437883298126266, 4222220664757293, 2316031680718393}, + {1452497321657782, 1539338328736177, 4156757905713634, 1587402592924883, 2189645592400953}, + {481460971838645, 495603062939192, 2081146895236470, 971761350637757, 742727604094484}, + }, + { + {5515673501962670, 4546389793895825, 5000269413610660, 4603828815474748, 3900836987569214}, + {2460924811417180, 3521984551624439, 1511404974611240, 375249799211988, 3782407540620780}, + {2048665788177445, 1408893800498572, 1918636993246022, 317961445367427, 656800592778138}, + }, + { + {2426976075633155, 3651600221015543, 3234264849290625, 2473309309095632, 4407296503206636}, + {2422350949934017, 943103623278343, 1291301021890213, 2346315203451818, 4112725099426082}, + {269878912827170, 1290670313639785, 2170448731381563, 1730590899024060, 665688666929019}, + }, + { + {5000413361992888, 3347912965056552, 5787242209541388, 3819792442922756, 4847625000360540}, + {1580177441875156, 2506058297611016, 2934789696579346, 1061310370544480, 596660656376680}, + {1957905575869340, 963138800079095, 1346185076450932, 33814819376238, 1624717058267694}, + }, + { + {2861980301667765, 3354887551296141, 3948074513800240, 4019265998902801, 4754514631586968}, + {1661216359883315, 1198665005326425, 3475476495296842, 881743418686047, 635325796191538}, + {1196599610725063, 2100294611545468, 412113633351820, 925880965367657, 519930913383517}, + }, + { + {5571468672275863, 5188072583684019, 4251873319339365, 2576514881889354, 4045293404267572}, + {2133507738629437, 1327217318093765, 1889369311142453, 2479101608310052, 4045149986308216}, + {703846410484025, 1348842341032186, 1685275777321460, 1615795108904065, 1475415532006380}, + }, + { + {5398949984609248, 3762655856514160, 2412712349948059, 5169973908847336, 4334869322214508}, + {2999632416625302, 3110726069588902, 2228895586394623, 2800522251491198, 2224895404394358}, + {1399061587160944, 1205421803029276, 519683572464804, 340023786200115, 2172700699519595}, + }, + { + {3574689489677767, 5335925023065998, 5369256661040087, 3129592424352108, 5388737531811449}, + {2700892402458353, 2743476698281872, 1953844576554527, 1836651043988628, 2962536972306493}, + {1357694877428531, 1765161852606993, 1167042823088862, 1400958578522448, 1847208195529391}, + }, + { + {3867728253589687, 3773111053869328, 4368860594965835, 6133882052967679, 2533060702765705}, + {2290736769578191, 3757556884488538, 782075793204873, 1953945334364505, 2306213589322841}, + {1820300206186415, 335405661683482, 1092574996911739, 2062461927997493, 39506950020151}, + }, + { + {5534612992751919, 3746157517504511, 4108089392798474, 5131771932089590, 5617809945843001}, + {1342645331878441, 2000053418116353, 2168383944146424, 681027567941522, 1213562615764099}, + {379321638440622, 996302411355145, 1880571763884906, 1004856333759537, 501836588196832}, + }, + { + {4231662813561705, 4640318983129989, 3064518357303150, 5343343094006261, 6450142130522077}, + {1145892199839501, 1078673486712789, 3022417549910920, 1612895247211701, 2324179764588241}, + {1972676776834949, 44492199500322, 1456097929669866, 211262343295697, 1045510624803264}, + }, + { + {5968931973016112, 6019428128447854, 5757013441564652, 4431402751536781, 3192943415309330}, + {1480229165025206, 2054505377286776, 3099784048655970, 3055900157449953, 1375885673210420}, + {1812738520892942, 2084676765238369, 510773948276259, 934572202757904, 537600238103234}, + }, + }, + { + { + {3613080834135665, 5774088788979550, 4480966629462376, 4981692702949983, 5531898286124606}, + {1941100238292769, 1530763972357988, 2941717574786124, 517834246099701, 3268301290369396}, + {402477551873128, 1206353712079331, 1931900782149571, 353151698548753, 227661813611943}, + }, + { + {5770945118915754, 5544555209532203, 5448202195803091, 2841016429831070, 4428081881985983}, + {3042160696267866, 1193039775906917, 2708874250955853, 1880772252763310, 1647664574467171}, + {1801318854301087, 529217444026518, 41439150499132, 1819497139150034, 1914318279506430}, + }, + { + {4617843866085510, 3963473780045850, 4530695843220841, 5152831422757274, 6255165884461126}, + {3653392334037390, 2119290268348412, 1662789932544495, 3712853444146946, 1761023449047586}, + {1892648843913435, 1079776332626104, 1111039290977790, 1827479485396386, 859677304170245}, + }, + { + {6135115193251795, 4578420287793605, 3485955900327480, 5405600312155654, 4983545824887909}, + {1955745180210457, 1703319703537271, 2019166049085294, 3363246542620192, 3873119138750761}, + {1700391063795585, 361747633083750, 1216968456947850, 1993842710713264, 601267006969711}, + }, + { + {4925286822096059, 5955810075280268, 4224518592023607, 4497079033823924, 4700697585549198}, + {1335348453199749, 2692696552964594, 3243268312448681, 1958567111536422, 1194502970771976}, + {1656217138482787, 491628805607466, 1679451179466805, 970181505842258, 1534105889461948}, + }, + { + {4204969625278834, 2839735694548476, 5311815348914771, 3424730456556302, 5437312551033891}, + {1051919605857270, 2689758516764280, 3195630903391853, 2321619474659180, 1445811115388039}, + {1160289603260459, 1956223108351205, 1733312353955470, 208731931777063, 2163609865075088}, + }, + { + {6171922307530267, 3416689909413961, 4398780048782414, 3348704297294309, 4794281577167533}, + {2605760676899691, 2518935989171471, 1655039766011588, 2352706753121153, 1606429966007503}, + {1142834714776341, 85770505106288, 713866520631433, 440023537352050, 178697006218663}, + }, + { + {5369775152479351, 2976619105904851, 4320166487861154, 4349283416973378, 5052617030572584}, + {1815823837273367, 2562753791013569, 1539789395052836, 3647749880076906, 1631063017998020}, + {534961844628464, 1393583055120721, 1748351260324708, 1375538226727024, 2193309623120304}, + }, + { + {4362511965756519, 3334861441534551, 3560279110881819, 4504033277345817, 3695270180099552}, + {872424258749169, 3269419467389617, 2236476348626173, 2024356220545311, 2898783963621386}, + {1239822839121281, 1734625037061034, 1644113104753887, 838912630061655, 2165081997489666}, + }, + { + {4719668160615989, 4954232553381592, 3407504093515639, 6056696583065019, 4080126483053229}, + {2648578609770085, 3690844259333424, 2082598280716609, 2564691042641275, 1346520144951773}, + {1979149515238517, 717801405945362, 2104011649567412, 1561125545440573, 2157118688047562}, + }, + { + {4177174713439601, 5431484182531219, 4912403072956818, 3423215719262779, 6067629588380508}, + {1808742790957793, 2747803311617739, 3845306078978452, 1924084822718509, 2264852519642740}, + {1767189866398838, 835676264200014, 201596448765126, 1979907908451931, 1442810524651041}, + }, + { + {4409296057792696, 4346067875211154, 3459237364299404, 4853798679576266, 4468808308660588}, + {128841748532646, 4150186054273698, 3256924437045680, 4019614742906956, 337338633748078}, + {1077226425497346, 607378044682866, 1485491791574172, 1074180848747199, 1023053128705595}, + }, + { + {5804603278915694, 2796027819585631, 5011026665884139, 5833743165576011, 5103566912764066}, + {2493359374165148, 2464080592904187, 1933101226851633, 1880342534882667, 2417917477223840}, + {1284426144747169, 2005093245564178, 229493920382094, 1642769566056222, 1596652614163344}, + }, + { + {4478501502615841, 5105996638711000, 4307245809257853, 2912192821294412, 4442483575340114}, + {3490678780709549, 2722972627744756, 4141726367382933, 2626667232874306, 3706338015195278}, + {978951056774557, 1610590016630807, 2160020521521822, 2222969528403014, 1290838415735858}, + }, + { + {4233395101645091, 4760048839668621, 3419853204404814, 3555462417010423, 4295491197124032}, + {3136023326660957, 3195581484142287, 2364500047372050, 978391045278571, 2088093684065312}, + {319754006496675, 2078141843592369, 1381704035073408, 2135424637477137, 1217419566529670}, + }, + }, + { + { + {5290773769928918, 4793813444262905, 4720763845546248, 4081316225438835, 4093406366409350}, + {2219813055094868, 3751054103166673, 764148091645988, 3042364539660805, 2174498914560536}, + {1346839273131020, 1947175237418499, 2130499171815608, 841760904333801, 793011313347544}, + }, + { + {3890099439122631, 5436725454634839, 3526358179473960, 4130205528836253, 4143183670329231}, + {2705685430041151, 1931337763813343, 1867986078235466, 963301853857219, 3203544659615889}, + {548016394257586, 1770170736821935, 883041007523403, 1244492123782548, 1874837894534970}, + }, + { + {6107029440448048, 3899130796270571, 5350832732145407, 5288086135111572, 5016688224136320}, + {2322745137203416, 3712079434453421, 1656136902347805, 1063047643279494, 2347290530652372}, + {1585044732618145, 79674660750176, 2047172033863331, 558016866726219, 1811700039750197}, + }, + { + {2903508896190354, 3572836747669154, 5671992452104047, 3145254132994495, 4870698970274559}, + {1980868732324310, 2459850087283418, 1500353534094477, 1977074025846907, 686785408890947}, + {1977199595236300, 927859862391871, 2045825765550850, 1189431662969386, 451125616133550}, + }, + { + {4264958907260919, 4637613300323186, 4723189721727247, 6439587034668993, 4270210266819895}, + {1981177153373343, 1776706813610008, 2956634306768875, 2113399644330229, 364175990188877}, + {1473984112024647, 2212143402178000, 1913009700964560, 489799262080055, 1390546130501803}, + }, + { + {4617432771154388, 2768922884406316, 3194759053322417, 3846588214005790, 4684848439540931}, + {3696338004009516, 2296500736839486, 1483385825107721, 732704435299560, 4093200809844903}, + {781495195344331, 819872919567170, 2058369589741763, 131552040816437, 1143952030551876}, + }, + { + {6045398880892501, 3274164683120730, 3537206235588588, 4953070760072151, 4494335279262109}, + {1632591054957791, 1584029964350608, 1679919371947982, 3412378076716233, 2572356071530817}, + {118276417181988, 2048136038162801, 1736078553924029, 677257986431580, 711847529279284}, + }, + { + {3634115225339518, 3407128374975375, 2997970212274081, 3493862836273928, 3535607408159120}, + {3574732327388664, 2600283522407089, 2877235052318169, 1647316986471086, 1495874784707614}, + {889518489432828, 1216748566987677, 2027061052060458, 268044074097160, 1539610510772867}, + }, + { + {4611501240201625, 4770963666624495, 4338415201879424, 4860883825935208, 4028006785359735}, + {259543849715615, 3116307281996357, 1555340861337048, 2140193697629416, 1035789313751911}, + {1026218773492650, 930245039288082, 1822875264087643, 479782375672284, 1931812455503119}, + }, + { + {4148807861057856, 5812728864755237, 4601316267327746, 6043565150382029, 4199151665681887}, + {3394871127325058, 3191785534223821, 2085795470524552, 2385926585602461, 399655200529949}, + {1057229833653287, 1828041669558530, 1006577782987596, 2162474092618005, 1568476132284973}, + }, + { + {5547684346917888, 4989218016843942, 4586613652979209, 4863124308009928, 6207570019680129}, + {2566237642336854, 3970491812994094, 2598212316441047, 2240782240471054, 2552742376593093}, + {716486226259134, 773421749453144, 1784612269854183, 1741938572500414, 1834164482186148}, + }, + { + {3117421109623856, 3461685839753353, 4955306417606165, 4558294861196235, 5602064404959934}, + {2273224772261066, 1223111129900149, 1584682650834635, 2022200125401455, 1373728084078920}, + {913182622593832, 2001872744868184, 882970207556847, 299806317329996, 1726046908726060}, + }, + { + {6249588231739606, 3368998262120903, 5239047789721372, 3406210943086424, 4754518606052966}, + {2248618336554706, 1339184282498129, 769038678141320, 3217160515726744, 1715873134108166}, + {1976228100247818, 1272400462149307, 1572190226615598, 852044049472028, 1055275428347366}, + }, + { + {5284373775928701, 3618431820022764, 4020557586503952, 4433032839002146, 4171326821228907}, + {2417108732168755, 2170003784635000, 3518440054867754, 3152772966589030, 704341378948759}, + {1290493724571150, 2122276831263561, 1747969631590180, 1399718798480988, 139803941068636}, + }, + { + {4427994415528072, 5149611644022833, 5193849655888518, 3398788549762908, 6113634201730634}, + {216319500947386, 1455486684654953, 828483179169328, 2183296040357724, 2625210482982860}, + {478303205586551, 304131100485205, 248369703081454, 371320991720787, 1635813582756365}, + }, + }, + { + { + {5252346966668309, 5639208782676701, 4075417215389880, 4364690112290244, 3384680235809138}, + {2429491642409009, 1283094434250487, 3316839113847160, 4229629869361324, 2675780619596520}, + {2176454779743876, 931093459142961, 2244697379845986, 723779257225747, 962795008037376}, + }, + { + {4164637625281563, 5566305816206016, 4655415916130208, 4180775155367792, 5707768410211632}, + {1861517597691605, 1772481620932890, 2629476438960640, 2705827759458320, 2107910124630170}, + {683279446283480, 2167544438614321, 1975855992985379, 780955320484514, 780910621778643}, + }, + { + {3955544259328322, 4458238333874171, 5864190420414532, 4345033257929994, 2857162289792042}, + {2686358254975148, 4179751356732233, 2499687248272490, 1241163995738960, 2778131269016956}, + {1074884828909420, 432905047961772, 1185537826254838, 52144045776742, 1826277929133963}, + }, + { + {5684453359674447, 4877177488298427, 2422407833284604, 4605478777171110, 4729984701613103}, + {2156715047802967, 1276772803921323, 2380233522537438, 1960794365816568, 2680384519257273}, + {1862177374063425, 1873700738552432, 308885709393483, 2100622082080360, 1104535253282502}, + }, + { + {3931149063775879, 4254429699498962, 6662929352488607, 4079587572542558, 4855364761755442}, + {3711640686247983, 421582154826228, 2220646689506683, 1208894292386914, 2152820272048462}, + {1565335522994081, 54406341126738, 599331788389250, 1486039135212823, 940991227185565}, + }, + { + {4398457498029638, 4929754658751446, 3952574300737926, 4493043596943885, 5305461811863411}, + {3849064215739384, 4001520908708098, 3463231867051918, 3642198741522237, 1030072339730421}, + {225800753248600, 1001289196776939, 1570695157447337, 474142387326152, 1860241406570283}, + }, + { + {4817367953033495, 5599987240264127, 4736311445242884, 5430531336232182, 4460173530026570}, + {1052973111938531, 2823516883980375, 662638871434014, 2738994056625648, 563864123356550}, + {823857549390635, 2207592640971793, 1855512257490888, 1911413747439725, 1853809846918105}, + }, + { + {6194718989753531, 3626032976625365, 3751630707315810, 4477700840286220, 5452904257109698}, + {2036109024667887, 3040585821349743, 2780985384011476, 1970818175728284, 2968438634461420}, + {695616701038646, 20368455765111, 619664083096696, 723635083382804, 1023760209767255}, + }, + { + {5008707213573776, 2859949901187285, 4290065003741713, 5151870738966180, 3127611889915462}, + {574462324973718, 2125329428751385, 570545018291281, 1476031513731508, 2680835412613570}, + {1517596182333361, 1429983941782802, 1900615890395770, 1911469027059364, 1851356681596334}, + }, + { + {4891662727757105, 6078189791872620, 4341252688115798, 4009612276132060, 4158882628774497}, + {2178830616846417, 2794898270987790, 2339865206643716, 2923242275980220, 1745466521002355}, + {841969861771844, 1234567333486718, 2104638753106763, 1445233761721300, 2209267998342752}, + }, + { + {6440345201923204, 5723637287574387, 5903930483115066, 5778502423080164, 5079904071191760}, + {2035275243828198, 2745418930619871, 2632830605513978, 2519743098631716, 707209224772602}, + {2049800384050253, 382336843047910, 1465264697408643, 242728978654073, 1821420259893325}, + }, + { + {3385848358825911, 2850931104925851, 3458310588278305, 4579597908985563, 4607881337942919}, + {1816700573507985, 2213627388818419, 2637198541463171, 3087473887817081, 2837589033715179}, + {1073720617318924, 1636814037227948, 1227321319951543, 598345156599653, 544027576937438}, + }, + { + {3741365114761762, 3465142572701024, 4346453033629668, 3800732328304411, 5207004929940855}, + {3530134215235346, 1497788707695478, 3538247705814828, 1425334926184197, 3292646832985731}, + {368165631658486, 1427424960871770, 667823977725231, 123986789130850, 789476314816796}, + }, + { + {5183377371949700, 4172584964939172, 4687335701106073, 2534986101578472, 4297053492878574}, + {2375597255557748, 846038920993436, 1398943082722053, 2179038637021886, 325133433602556}, + {1814357252172511, 1812991482130874, 1545461112716185, 2228739665628687, 1030416912136148}, + }, + { + {4102150726478441, 5089888860858732, 3167069131929673, 3336166645247640, 4708635432875520}, + {1325239906989203, 2989936170895398, 2414201768248283, 1851733918704382, 3428546124237928}, + {296568059020374, 1937661788490502, 1994712548479216, 1341415580517821, 919259617560208}, + }, + }, + { + { + {6274182990169406, 4386048988056353, 4097025350643424, 5127499815238002, 5572164902186574}, + {1895408474337392, 1335954976788533, 3236941534902540, 2378721630147940, 1461766309882914}, + {1291953286798969, 2102679466898679, 1596002078575263, 1387588817990761, 2143444637427225}, + }, + { + {5996694561997207, 5683227612437284, 4899213524992592, 4856689735436656, 6404791836913969}, + {2772496102790967, 2917238652453944, 1731727230740742, 2247887220248582, 2143609474706149}, + {923819152192005, 1415712944791087, 1125410698033067, 788009900900011, 869993295869018}, + }, + { + {4786795669239288, 3398808358640920, 4513626939909643, 5985598090247291, 2945790096837940}, + {2456756643078196, 3060894189290238, 3759434421535873, 2442805763764489, 2819028797217160}, + {1757819380032415, 1458259160758992, 404747119062789, 1242483165113555, 1521264843142355}, + }, + { + {4457446227801342, 6427880138295914, 6656730008666805, 3937171933580687, 5754864538579708}, + {1177246463904108, 2488433613267172, 2328478208484747, 3802230570654315, 2344609059443716}, + {1519155588261854, 483899768651806, 1235345257217886, 467640517750393, 1224438957323827}, + }, + { + {5102603430061893, 3128470923287158, 5801341356388264, 4525678559978591, 4718363529583899}, + {1246208485680505, 2848653521425806, 2416405253631000, 3077610602170527, 831805919056409}, + {2045656886162419, 2245569838876242, 1361334406977685, 1370170063372453, 1784586163491838}, + }, + { + {4556063502635342, 5531207665521536, 4057497943029825, 4507014901377590, 3148382369498868}, + {737891874041388, 2451689755512888, 2972729929575783, 1153163677723624, 2631153364835664}, + {1021578499394252, 2003506226907156, 1906928204664703, 617432881327189, 487770381544088}, + }, + { + {2772215428108171, 4464024296635705, 4854458470465137, 4051326172605262, 4041843916653002}, + {1808240492311657, 683215352347115, 2786075502512133, 2784661866757750, 3917451132840122}, + {956648481954026, 2096247164218896, 1027480742584033, 928233599700570, 2122240338574709}, + }, + { + {4629946233006760, 5291553581528148, 3270843847622640, 6572477208034336, 6154625523788459}, + {629205712253428, 2948018954745502, 2240941577462354, 2419373201820060, 2682153541398885}, + {948811544154236, 95827271348811, 971972540788513, 1752656910961976, 1577613288465037}, + }, + { + {5687495579915904, 5920739705585144, 3623686905482864, 4279799360588693, 4937051703985742}, + {2733819029729102, 2941383700719094, 2344126789319304, 272099344396033, 3469931440006564}, + {1155109808876838, 498663775049656, 2009409241380161, 1654861553852237, 2195711930770443}, + }, + { + {4562514450276878, 3610360397280214, 3754786033717112, 6274151337271952, 4102082344471456}, + {3779237395015718, 2531855739502292, 1076300728317328, 2341702386635930, 2037036009072308}, + {357187236460800, 1343207422743391, 1557831743447331, 138875622916216, 2073308474766668}, + }, + { + {4318248447888802, 5457191060945059, 3575720381879889, 5537122891348075, 4658291618481620}, + {1058927027601226, 2097000197595935, 3018484019405255, 1294660112618737, 2932877913314978}, + {216145844764492, 1876995804123388, 1188737931982599, 1588244200049402, 1850009625550870}, + }, + { + {3352537291082093, 5839102984451201, 2319458858510810, 5312519694669356, 2539572161961088}, + {1971880260906249, 2590822963635857, 2283171542295386, 888730652847270, 2069077006720618}, + {986114249350619, 899447833294837, 753796294360457, 1686315816498457, 1484432111173806}, + }, + { + {5781412563046772, 2829048727661187, 4098529237644982, 5146692071916491, 4319033371720950}, + {2231959129524362, 2353147866489543, 1361542642038984, 3436571318049649, 613122764422636}, + {1553151906564201, 42706246613546, 1656634422023210, 337580524133816, 1382068281260380}, + }, + { + {4318188098974879, 4190975253205867, 5053353859489555, 3624409471895100, 5734877817656224}, + {339244995001665, 1760160432424305, 2510143032086917, 900873257630652, 1381243383153778}, + {1027887039599863, 645983151773049, 940633405940384, 791297293294468, 113951612418342}, + }, + { + {4421127861301280, 3227473132618256, 3897823766346675, 4531675054348192, 2597262173415879}, + {497984229256388, 1528193624284798, 3083402776323261, 2834076054300848, 2004534517066737}, + {707308783184531, 1723910086807466, 791458836921758, 441590831592448, 1945299136569002}, + }, + }, + { + { + {5139590791061503, 5074296034161507, 3861111523264964, 4286794753368429, 4613589462411916}, + {1370912655100557, 2279879075953359, 1535348789227130, 2242808749632369, 3061442465980918}, + {2128769772677977, 2142654242576520, 2016094652496998, 2132031230853467, 725434888027655}, + }, + { + {4677803618766960, 5273930469290190, 4617970826042730, 4133081282480847, 4583310983505940}, + {2135073895739904, 3472442449797848, 1493509767807810, 3843639135014989, 1420071562059334}, + {1420603492551010, 679640550295814, 1617533903828801, 780154362635607, 1319780020899258}, + }, + { + {3937068127551315, 5594824685351819, 4538337787238312, 3523378410763828, 5437114214061846}, + {3695575212053185, 2594449599707103, 2742930959436192, 1161286236132678, 2345020968733648}, + {194815921686333, 1256736762545940, 1408742447743650, 304562218341097, 2021464306176092}, + }, + { + {3212222966285493, 3266851872779616, 4336733687401440, 4794872810759007, 4424169619295461}, + {2759763070229743, 2724175318859802, 3031057691838938, 3431189823632909, 2961517144339711}, + {440075250919582, 694825884103652, 2159700403414911, 116894270435230, 1425927073727904}, + }, + { + {4841955313295828, 3461757100553382, 4305435906781420, 3691116875116057, 5298851817605162}, + {1064910415642974, 3095607189587094, 3908971853500052, 2189460887246833, 1354043476687700}, + {1262675707031055, 1219816744922490, 519257628155087, 1497570437960201, 1372594887264798}, + }, + { + {5466094472208141, 5012579346250577, 4661027376097750, 4434802656317810, 3968075278352583}, + {3315525263287981, 943900907578117, 1225723797770692, 4182671057889152, 2697481958411475}, + {1933555860608921, 1275569655188916, 234812135397482, 96042287368239, 386392083574324}, + }, + { + {3319477981428303, 4681888525996228, 6591617607940267, 2604452186053658, 2972488992219816}, + {2831773176554005, 3864996001314642, 2395563170308483, 2090271503443448, 1893990359510416}, + {1681588555670186, 980191207008201, 2154581399538671, 540872424183046, 1943954489289499}, + }, + { + {5977124761029192, 4538331973533215, 5533519881915667, 3479901172100047, 4656405250637608}, + {2363082790805374, 4242757803000485, 2669759818118169, 3333816374844969, 1325118659202748}, + {183359648873960, 382111728086623, 1969766109298473, 2071169946252387, 242935538497060}, + }, + { + {5188738692165469, 2664732629276594, 4968279324223179, 4960443399326301, 4436427572176893}, + {3490990196257229, 2560345203268680, 794851537166791, 1532423795715657, 621302931359813}, + {440189527159075, 2095498912423497, 1575373142262611, 744594360742511, 1157079567398109}, + }, + { + {4869958177792820, 3889970905101269, 4570550615789326, 4496205440964732, 3848931098885666}, + {3870071548603662, 3041096274835181, 2350925463456272, 1091637746528482, 1355815234248438}, + {927792763323382, 1304575354366273, 612939300770904, 1630367810979451, 174107168815644}, + }, + { + {6136927367908702, 5203222247970547, 4888252310796559, 4897189790028520, 4586519387439588}, + {2831448685067634, 1668205588574421, 3161976938852725, 1027424964992432, 2026369259616642}, + {1735694076750726, 1266349638286480, 1493849675863588, 296961022463490, 1483126610434799}, + }, + { + {4654087895073878, 3931119431920957, 3810992402627745, 4571904269427127, 4481981159091504}, + {2466558329032204, 2314404658847041, 2524639581935109, 805442192808499, 1270294344302086}, + {750996510156456, 401855193068398, 58073276915611, 87767580153872, 241880537805683}, + }, + { + {6336062814229381, 5495468976405173, 3085611334327622, 3929566749867368, 4056705138744772}, + {2170745323194467, 1059898966987983, 1821678094574528, 3224522071822304, 3177794562815748}, + {697769608468752, 1369430004061620, 1388586673198089, 909114275708814, 1146450457999407}, + }, + { + {4238043779316857, 3868604149115822, 3602737573195351, 4491948926777684, 2593111277688382}, + {1942420724187743, 1230266918978492, 2950156777850293, 1491177343837674, 2151732388834046}, + {1552628609460396, 385059438618066, 1935679554618991, 1586643703562239, 274738755241324}, + }, + { + {3708634080771636, 3376471647619972, 4144079859874091, 5260099970974267, 5044960426451952}, + {1260464362728368, 2320200151112594, 3280988120127265, 1454370155862373, 3222503455600234}, + {1286187906300863, 286639393218233, 960541512944676, 756511343610150, 732619979206969}, + }, + }, + { + { + {5720776037989329, 3408557855252881, 2836745411300455, 4905300285896935, 2440518813003965}, + {2216608521812979, 1133671267609171, 1886801270451833, 693723450681229, 2177664326279079}, + {2233307833752057, 720411965215730, 1519169695491573, 1249545629073374, 42274079495163}, + }, + { + {5289248568149457, 3817875509053716, 4457685664702894, 4876101051290378, 4294494794724040}, + {3280020244834293, 1318628129209810, 3119398368735896, 391516159010622, 618793687544686}, + {354305362086679, 1512134460741612, 359672307646707, 182487842123724, 70434142068276}, + }, + { + {3945557653570869, 3088092003227000, 5454351386185562, 3234451172420338, 4724702104276340}, + {3276624651778803, 2433844765263326, 2790865929084436, 1963658167580138, 3140414260467690}, + {46706548238824, 1986500518838735, 2027136585204085, 1143580830274421, 237034819567290}, + }, + { + {3929429576586958, 2793383744028645, 5887317021163886, 3203394573309402, 4670385004087593}, + {3462257554153900, 2215903401275259, 1545855048122212, 1560256833448838, 235678314205821}, + {1032532177573683, 1507169914894481, 893954872249259, 1464210961075811, 2248024514969267}, + }, + { + {2517873563818259, 5567259846017152, 4253295986752699, 5558170137710973, 4039120007239859}, + {2215196432839229, 1453988298479780, 3162959582154309, 1417180860727485, 1916001465630095}, + {1593076635649167, 613414152324278, 1398118686752976, 1550186634066418, 2024312475795755}, + }, + { + {4524027900175525, 4847878416694692, 3091409665235077, 4862578993236379, 5350599804185218}, + {1611115816843085, 1564686497935112, 2631443498765253, 2543391790063645, 1070282314438176}, + {1370619542022553, 13593976629245, 670888839522668, 29909561835083, 1113994299778657}, + }, + { + {2995680265327027, 5241715165954044, 3953258701883675, 3989602332635833, 3953848187775337}, + {2462467670415027, 3084380814586442, 979195344857407, 761623507948939, 2354116769190033}, + {1653806661942935, 798938977173667, 1204504651898865, 2012775328403335, 959133953735021}, + }, + { + {4988340255562522, 6250762111649497, 4210027774413747, 4281026073914171, 4124289570254779}, + {3308091097868222, 2438171792492677, 666572176305849, 2221533064225315, 1302577527793701}, + {2246982488380161, 704048527252770, 449031029656446, 2000971659049725, 1830758195793359}, + }, + { + {3190675561821798, 6722820056714491, 5018399111078811, 5991624407670525, 4249280343842061}, + {3052270247598664, 2252472217742059, 2434081171992329, 2672797197928279, 2602890651310523}, + {2144671346446832, 542864631780587, 1155108742000404, 1404732713614448, 240293866423412}, + }, + { + {5121381423145567, 4833873167604293, 4028173334112257, 5524034306881884, 6230562353876706}, + {1307308592059221, 784383479594685, 1720750519626457, 1912081034355222, 2024784929774716}, + {22174994285057, 375276401373336, 1210941030392323, 1903374444438123, 1011323371888298}, + }, + { + {4798470629258750, 3939993567755513, 3967862752630070, 3290332526819821, 3061464921693387}, + {2998794565294986, 2057935584763381, 2899577223808862, 1519188817940759, 1842063844888831}, + {892208073348264, 1880270486117637, 1866139692669281, 577642276098528, 159304923876906}, + }, + { + {4601033632870689, 5799253896657058, 5779104046600604, 4218473381777077, 5066296163965867}, + {3118817410699903, 1416293682313136, 1358642285736990, 4016697695252823, 3785048363131621}, + {841452637470330, 509851329084465, 315943768852800, 745051417948746, 1317978823624451}, + }, + { + {2960724265045759, 3581409910547792, 4757575913235420, 6009932939538924, 4725476498610383}, + {2216474880678649, 1883045416719140, 3557095587267860, 2414252121862082, 3019618269128831}, + {1790146986408439, 1266311794146205, 923857310756466, 2043374401317120, 726369229085659}, + }, + { + {4878312571596775, 4222794967531206, 3321677379160160, 3406594510676891, 4743132105473153}, + {1047639500605479, 3268483579465284, 2206428670313250, 1688287562131353, 1668007864663417}, + {1777656298881359, 367886496899263, 1134571758927624, 161297709883194, 864111924164392}, + }, + { + {4770637647109604, 5356580318440110, 6456410085143486, 5251963198009528, 4612863117603799}, + {3459496839496426, 1172866796116672, 2087657719164010, 3611579473502448, 2226199443508323}, + {179962092093812, 1434865358203901, 1509301171184812, 465007053005824, 1606826267425619}, + }, + }, + { + { + {4321570421086801, 5728967329483361, 3790752945733902, 4440201295898093, 4632192800649486}, + {477207916553285, 1488064260202941, 1661453866463954, 1141228074051855, 672072650786576}, + {916404312971536, 1000014350915647, 1498754584389763, 67530592482209, 1667646385756724}, + }, + { + {3838511633005352, 3067059108181153, 5859654687359949, 4517853996250692, 5491933645129578}, + {810369747020164, 2237618141036509, 2282241440976077, 396142955464532, 2314156456627292}, + {498205650210982, 2029447832739442, 1287708517665602, 2063154761502015, 592549403529808}, + }, + { + {4850172605519114, 4864656344540316, 4532814144934823, 3437824613452670, 4812474608554159}, + {1466752538541840, 2035538193320560, 138132610685025, 1256421706559322, 2431850955679681}, + {1297525937307453, 1360474818962172, 1057976529132470, 481516036122456, 1284896343639676}, + }, + { + {5776741280656995, 5103737594811281, 3360081478971068, 6111393754727746, 4779680024426854}, + {2645933668955707, 3274005597891379, 2656619141981518, 1746214054851430, 3053032647501696}, + {1625278703177771, 652272403287866, 1130860155562117, 1467718191751280, 170296377586353}, + }, + { + {5094219073783849, 5735075135248235, 5606322495206271, 3754059419692243, 4180105537366398}, + {1002349488419261, 3232903243006485, 1398184721429427, 3601262477434907, 4062926820203090}, + {1577778325058339, 2215369962281551, 1331723269758849, 1939632256423674, 52886968354553}, + }, + { + {4933187999581607, 5092493367263378, 3356435735616918, 5217407324510779, 5497406740649621}, + {2729077630033003, 1888615867921888, 2296393402013134, 839924021249031, 1005736290727363}, + {1035587952296453, 772571610990610, 1703146381743864, 447715678256778, 1714287687955168}, + }, + { + {3002761637349276, 4331640081948673, 3834120280377754, 5089609293083651, 3261373019366335}, + {2386307482062396, 240967146617557, 971317535064000, 2019271157069067, 1502539203059821}, + {1328811798417377, 1232170334974369, 1723370191641238, 2166559558468187, 1898556240276951}, + }, + { + {3941047590826269, 4239692035015583, 4490403838767533, 6564872456977192, 4670461766802655}, + {1386180360119611, 3273074614881159, 1729880193705623, 2228606406348098, 1592392117444361}, + {419731549689034, 1989626747750813, 1591278351630992, 1092786235861584, 177178675215960}, + }, + { + {3436683241673758, 3662206674778039, 4373967447323555, 4097363846812803, 4031597646782708}, + {2639672814451512, 3326947991249179, 1680625793199947, 2034248047548953, 721741001003862}, + {1591050698007192, 1091674239474205, 394086386458446, 652864259466208, 252826649880832}, + }, + { + {6202959881484310, 3301137131128391, 3338332791366416, 4386834101046813, 4586134902683138}, + {1761951583445986, 1682354370625515, 1311814077921538, 2232552485157187, 352715570060390}, + {1983847550347734, 1877133028995354, 991701922936357, 942306684083689, 199141297262892}, + }, + { + {4356558984118475, 5693420396107718, 2518386381195401, 4410955637518553, 6067546162903212}, + {748677842691767, 2802469894128656, 2167458034960803, 3580904381157207, 1663021749531972}, + {672345752527423, 987721649439917, 75559353638139, 1202381658061142, 2218885179346238}, + }, + { + {4510531718276206, 5025970311617705, 4298550255570023, 4702464919238073, 3154067300975759}, + {874026063340854, 581394977884979, 2805876061084699, 3945101577343195, 1873084195329207}, + {262642087469467, 394043452244726, 1877384193205089, 135064540003798, 932774458922892}, + }, + { + {3677176615657209, 5004677940509387, 5802006239792640, 4988806137854665, 3142553109499622}, + {2906530412387425, 538942497799423, 3006485045211118, 2701192894331127, 1774793046411044}, + {2163097510860120, 1657639324428092, 324536800194710, 2127826550215010, 1492179302504548}, + }, + { + {4271383757866077, 5161359851331481, 4409665194889791, 3535427764785290, 4743868535366280}, + {2870306695118697, 854883599481521, 1175220622088095, 2190379234235038, 2693308800279672}, + {1469265779048270, 1543845332050728, 2202017995300452, 1928013995331013, 1762032763505452}, + }, + { + {4636656908840010, 5500309513430418, 4897834655713547, 3941193903783821, 4553608952670061}, + {4333916659134460, 1850388591545996, 3627944035206357, 918659547384777, 3374247281351833}, + {2000039510485295, 1183834045401091, 1338556774925931, 1549179790309018, 394428288927656}, + }, + }, + { + { + {3733446780128548, 4970314905751830, 6278139198254466, 4792154002496454, 5723581693713173}, + {1185838263017942, 1658025814770644, 2664414501602854, 2015508295646822, 2967017530049915}, + {1569664128884381, 407663338845983, 2002256010544711, 671085899312035, 984282527793076}, + }, + { + {6341328981945826, 6310526850187699, 3023871274454732, 5578860681574207, 4775900505114104}, + {2574316560560394, 2331223963461233, 2542672004494602, 3174853647927431, 3104624426621216}, + {946711433665760, 2239987349934557, 803861660898522, 2156551410386926, 1502787654920122}, + }, + { + {5437578969471140, 5951179206758851, 5248530961634439, 6426502251854756, 4209704034918088}, + {1002763931894790, 2216555692070697, 3344391891538061, 2095372815347836, 831620519830306}, + {2050669866355306, 2190774465449013, 2058969733807763, 270320273862327, 1870514939355617}, + }, + { + {5155857617776227, 4397988213497465, 3243709928117524, 5944645730694783, 4773063750957235}, + {1975814150439887, 3149875793027583, 1261444197722906, 2760429640974761, 1552966352555279}, + {1633514016507671, 758793436105214, 1666766843388618, 1223902548045585, 233185566290059}, + }, + { + {6335824036525539, 5936753389140468, 4473577463180534, 4906816011267918, 4087654058111774}, + {2368975804221909, 2457041955704880, 3876216785098924, 563819279426048, 3675362390258876}, + {2039348563488973, 248927546652694, 729506739622176, 397171022735714, 1644628056647629}, + }, + { + {5425812761915260, 3810529789490661, 5049333453822998, 4123755530302819, 5615639585264776}, + {2534643198043490, 3071062759450233, 3687767943508924, 594097030236781, 2123224284522922}, + {1869384197190792, 1569592234203114, 2196362163965849, 1717386471659459, 39685498183014}, + }, + { + {4635535175474129, 4605530976221652, 3458801108619450, 4871255059096226, 3508659268324931}, + {1421109370612225, 2276342051030278, 1620731107586926, 2516053916114754, 1357365806509465}, + {985026127753438, 120648499984234, 3776067837201, 1121956503069595, 1317952564469757}, + }, + { + {4522971017836409, 4687828520937668, 5703673191623277, 2940799383081666, 2787006346014769}, + {339460334667999, 3256039500082500, 1203428024902643, 1634973881827916, 2329743371713673}, + {1781496335107774, 734939096367772, 1979958937781877, 860043149833798, 2198713547814584}, + }, + { + {4721820132212972, 5501981664895244, 5264058468541187, 3740873078980979, 5716647821232484}, + {4072332661836284, 1169250173411574, 2007338871529421, 2541018716077961, 3008200101154560}, + {1725071616252177, 449990873352396, 128827658985361, 673241280853224, 751856515144447}, + }, + { + {3453037913720095, 3978754968490530, 3848210473954340, 4246376002566406, 5322220851863886}, + {2584349971388389, 535927716206948, 1961578137923504, 2896060138321356, 2010651373680674}, + {1156080784099315, 481555143811545, 967562545637573, 1677675896966263, 907265960192535}, + }, + { + {4332897500521172, 5216833051048471, 3346087018588415, 4384949392542339, 3375716091409272}, + {3883496497463828, 2136509343818925, 2434189290622529, 429179343434029, 2077816145810058}, + {1658461349569569, 1605536581882396, 1366404149694713, 1196969327840593, 1143971682907018}, + }, + { + {5400721311066691, 4902133966014442, 5147618958116264, 4262202967114947, 5920636443351740}, + {3544460334984043, 1818177095892812, 1745908205006280, 4216608321683323, 1892854460405668}, + {665225119661694, 619309150141627, 1122802004923883, 2010090924812740, 381608939276442}, + }, + { + {3196661699712892, 3684791960878407, 5290400087132528, 4583612441617304, 4269495094598113}, + {1614570977912342, 1623735166790269, 2524803999133080, 2496475358487958, 1935280705616725}, + {1092465046248360, 2063398303783148, 1002343547076250, 391684155494682, 1710560533943348}, + }, + { + {4070608883224340, 3070202986942604, 4904606928783937, 3666937738681094, 5479190180948687}, + {535566969681230, 1737993760203276, 701172348317595, 1733855888978568, 2134615712849277}, + {606893040022944, 2129386574985473, 1699765919891957, 528478848080626, 79217852843510}, + }, + { + {2896556608610982, 6055695907875122, 3732440132349395, 5309166170174244, 2721831575240156}, + {2885737548308128, 2508747900193688, 3606366888469287, 2465312058009042, 1828731582217566}, + {1349811289350391, 1890659682051631, 851360755267261, 2227128394068535, 1024384097528052}, + }, + }, + { + { + {4787547620178774, 3158654330243465, 4256768153665325, 5186246574371168, 4755687815664005}, + {997854281022512, 2623211910140591, 385221936050651, 1659016544729114, 609442868038809}, + {1619428378651736, 1579845830028655, 3625310117685, 170605089295866, 1149673757755609}, + }, + { + {3771360214195724, 3008816652878868, 5465610693671022, 3583291267492728, 4869891036079898}, + {1431189333362726, 2522236815322768, 1841157954619916, 2384464325206820, 2357706544622962}, + {437646608465794, 2094793895484999, 1468162389698058, 248477625893392, 1999708435919408}, + }, + { + {3334695520371433, 3812203917821368, 4517495595943886, 3819008971940261, 3192333158392848}, + {2403562525071701, 3731091650393632, 28706304084430, 2945476990326655, 1695373042660190}, + {11430723322929, 1391830113841252, 1337273140327877, 418617211527096, 2156223821909844}, + }, + { + {3474862062180912, 3882457043015231, 4997421855422554, 3623087331366693, 3980925476191710}, + {2057796043232644, 2263408613360807, 3848582899143280, 1729533403820747, 3162991736601526}, + {43999776827657, 989331901442862, 147120313740048, 495021300047603, 2007031690017476}, + }, + { + {4569310600539567, 3932567990833912, 3385323568255113, 4454797311017655, 5850805500278008}, + {166834800897807, 3648978260893606, 1512008134852981, 3519745367019255, 2891621521405984}, + {1308871835809784, 2116706717414875, 56029465436904, 467188187972025, 1826981082270550}, + }, + { + {4470097619807732, 4636615835029003, 5384758368025606, 3313145881106330, 4330528852662105}, + {1956939819397260, 3815569263781231, 1153022458216286, 2428547349977954, 223633771534995}, + {277297371046776, 1016671322777094, 1912173712739697, 1941234701885292, 1286651577841525}, + }, + { + {5516226444917799, 3864412772019280, 3317545876897683, 3844965839466476, 3985391436490214}, + {2680601238774939, 761018381922150, 3233893633186507, 710728397015564, 1856525231801054}, + {634704084825404, 2129536576841980, 1242863233687290, 1573321106629022, 128474589505663}, + }, + { + {4461600283819019, 5688762331492453, 3571771069068464, 3623234953171514, 5735065250408243}, + {129496500081781, 1790297098324227, 1302842166366374, 1122296729486616, 3168849968185895}, + {627678063257079, 716314893721428, 1223825394014331, 504272345435927, 1599415310067837}, + }, + { + {4497146074973338, 4258524581640411, 3327175345569250, 2988994176227077, 5267912111147682}, + {1802641032705090, 1392499306540523, 1496089620367494, 2312128812044035, 3539470476015736}, + {1352081061607517, 1142882484908029, 664622054563474, 278618602320570, 1557574337895879}, + }, + { + {6186532378029907, 2657902210141327, 3418543318248038, 4786173749208350, 3954647920849896}, + {2160964425547565, 2522131549551103, 2469825005211132, 304256310615628, 1406273379451890}, + {66232156124863, 1741674194899368, 1229742843930407, 260078220485178, 2065725536502563}, + }, + { + {4851046938453980, 3469458552849808, 4088972952218884, 2434262635154865, 5173422452060032}, + {2864583883600790, 1179256560411448, 605392730024768, 2131319985409857, 1797303368136290}, + {1658701641668087, 42705500105455, 1620862321227524, 1064411845535234, 1929505696020986}, + }, + { + {4163795150867629, 5312083389544253, 5442631052553893, 4817195733891862, 3463190319377281}, + {1759675286353623, 1663207329829539, 2312695704742071, 376287419379108, 3196993252356633}, + {1986557906737275, 810826505070108, 96017120328357, 1696299441261906, 1606104856145766}, + }, + { + {3549586047215341, 4636877962062236, 3055155796794642, 2987219577785020, 3528907845687172}, + {3376650841822935, 1032192126856158, 2069071282143034, 2845533170222998, 2607538492640606}, + {1660552858343061, 1231765925349274, 796446050473330, 1786065193241069, 1494189638115097}, + }, + { + {4395801598993052, 5237162742484602, 4130001086185514, 4318996219007855, 6361901289989183}, + {2175013070553356, 3320762044970614, 1143129099999600, 1532959129324381, 2553098860474181}, + {745372522040276, 1748456103797955, 2181743850112213, 796241938657904, 1942989014453742}, + }, + { + {4940563260328687, 3680309631021837, 5780417720128217, 4290252794057113, 4860748118629541}, + {1446945700457117, 3425847613673611, 1973622627786407, 1807324498582473, 848150045623407}, + {1097351026844646, 982517101132756, 149747537095472, 442788546176214, 1331800448358921}, + }, + }, + { + { + {3048999410076971, 3892379313272499, 4501182485180276, 6013415726786911, 3538900302869245}, + {1912748982362695, 3472588964406961, 2955977531735648, 2975418449611955, 1539793845278547}, + {2120957025321772, 1416788979770990, 1248163529640000, 1057479098339217, 1345904049070916}, + }, + { + {4595431001667912, 3778027149812221, 3607566563474045, 5108294493186449, 4683353521871733}, + {1020723204932740, 3177502390904871, 993238884888759, 1734688533140183, 2122148469059677}, + {1672839208916523, 1716495024680343, 1707076061183264, 765180466790910, 2017432747304428}, + }, + { + {4097011095397840, 4818396343707634, 3336533547899513, 4282281512848069, 4911825398741721}, + {2414052521429936, 1593372837632108, 2670905511225157, 3908207528779377, 2363908827003723}, + {192171151121229, 1275967732855104, 1864584199775891, 1693406950762857, 451756333138903}, + }, + { + {4727218507536765, 6731370918172898, 4514881522289443, 4346751476412392, 5345399511692591}, + {1612422054090625, 2236845889213344, 2363747608937251, 1594023725720586, 2961152477238633}, + {1485832258557624, 680071864680695, 1288498699771584, 258483455916573, 1782424270254224}, + }, + { + {4145911876469356, 3824464555215015, 4696287494265278, 5681915693477289, 3460241462730997}, + {2899290323536300, 2148582833270035, 4306072922611340, 2565743726502417, 1518458853723029}, + {1953522143805027, 882595907666496, 958109305864079, 1523427692628869, 1741273556819203}, + }, + { + {6076430972133454, 5015736489916628, 3553768171633221, 4610709058364067, 5082978176345714}, + {2177453523879316, 3719629127010202, 1578609310805205, 3246652757763105, 1948868370865272}, + {2160967413246114, 497546389595616, 235866284515227, 1209326819476215, 385381334474653}, + }, + { + {3922495052587829, 4494539022460083, 4247467603322628, 4394626550110741, 4540112411631648}, + {2794088217731505, 3925821314042297, 3967932263264306, 599992304591101, 3777014795396442}, + {2143663924692386, 1851559468934078, 1845266597269129, 477022990956902, 2179267609261901}, + }, + { + {2757964045702557, 3562399862100370, 5308617563064155, 3110477941637017, 5056214367828129}, + {1958983221377553, 2178877734404748, 1849996731612977, 1835657059247969, 2041180109654311}, + {724524272708234, 661221141789934, 1298795839460575, 1322772218421097, 837427426454482}, + }, + { + {4223608019735549, 5288655260236562, 4785575153888318, 4056483408937593, 3471372655277242}, + {2219315301228611, 1125545597629890, 951081168531596, 568553052705851, 1412860720276020}, + {1137419035579219, 1404302123897914, 70650994795979, 286534554383837, 1248950723208565}, + }, + { + {4430704978424231, 4715040112563554, 3462858870799989, 3675716202870984, 4333024567010524}, + {142500909440961, 3483510976010918, 1633124654372333, 2818821059903848, 1198913332019644}, + {752727997883595, 729011045815856, 344467882917129, 1083479075474047, 1987011026378575}, + }, + { + {4459355955251918, 4177516598428064, 5081135773938774, 3284517801964245, 5485650974376915}, + {928716952855914, 4109673353080708, 989163284951296, 2771681491221325, 1739599539253359}, + {884564007355359, 1882230710793852, 1848620432404050, 211924733371920, 1690861583639863}, + }, + { + {3370568370567081, 5191721693684414, 4210754480734108, 6164440545771688, 5649472005268314}, + {1901455587402533, 813369714566932, 4131962295906966, 1890594180896940, 2481388378410460}, + {226931392632329, 1641783547024066, 245880824976242, 244030597682497, 308840717750219}, + }, + { + {4699529728790440, 3682875431198511, 3687823620487174, 2935047689154352, 3634282712140374}, + {3094491104014232, 1130377028133465, 857472228100160, 2846610482750732, 1997728196650988}, + {832395901935430, 2063621809284227, 195191804737031, 1295260648818684, 140470149874586}, + }, + { + {3598626358333843, 5555876347138442, 3551001516031801, 5418563562930746, 3796685043861386}, + {1119383319424479, 3370445532080284, 2202737095147899, 2643552313073446, 2526474007824020}, + {436475423231066, 206987015606375, 214066996087725, 524361410769522, 1866248992304042}, + }, + { + {5215692725695751, 3669441050652411, 4674665916750844, 5316221279699436, 6443632653069401}, + {1081002530185607, 2909820960350251, 3592240835659126, 2824950488355670, 2408518769691813}, + {2202470261312694, 1511198785606944, 1434711629178163, 1742102768767586, 1282697956395292}, + }, + }, + { + { + {5324690866715337, 5533327845613105, 4036930034597607, 4638490931056674, 5650412235017737}, + {1638260469631915, 1786040878698661, 3158389239420729, 3835314628196980, 2413700758553481}, + {960395712488566, 1090263312831733, 1493488072165035, 718337273853885, 140550395520083}, + }, + { + {4569832948050874, 4985100205291785, 3844846206585447, 3819690642434847, 2746468303866686}, + {2833809135953840, 3714738963129863, 1699035707213511, 1260336843200283, 2274544359656356}, + {447501697246828, 643764017641830, 598739660833153, 477276555234445, 722964385617133}, + }, + { + {5743873914285031, 3319094314541157, 4059899116934908, 4330486197588569, 3357811959011823}, + {1468688697571051, 2930932730830707, 2981359468083280, 2467829883996923, 1572642054261959}, + {601523810297856, 895074627148937, 773977692709653, 1905383167427875, 1540507530397039}, + }, + { + {2901461178567113, 4994292130181829, 3331309663039004, 5793381747506001, 5040143301404956}, + {2651347872114579, 1239727848347325, 3161955024122276, 2712053429837225, 3725184595174532}, + {1148448246837183, 1915539016170074, 727268432049334, 838952046766961, 1100979659516489}, + }, + { + {4313788896597005, 3731391587318928, 5481675874227619, 5342116794928851, 4858074158134343}, + {2801484252789311, 1308243333207398, 3101163188310017, 2902551501956635, 1782136170508091}, + {1354449553272043, 1085110494903468, 2224048655022783, 1932600057639272, 200912869737304}, + }, + { + {3988802802744946, 3054267513827163, 5506469409446024, 5207893419318903, 6705457585999423}, + {768379161979176, 2950328772092937, 1384131174334606, 2825110025249585, 2256845801064479}, + {1328818899805024, 1356396048253838, 60665341223248, 1567700157316511, 290562887661571}, + }, + { + {4789838652012215, 4990599721334973, 5868836171113556, 5456092296292492, 4808665632941719}, + {2083771618977947, 3859777942731437, 1586868936731178, 2520556279463752, 2196980677006699}, + {1179288489475667, 394266093483806, 2023843107238627, 906600297586329, 1987935808498095}, + }, + { + {4852377011852760, 4268226436451965, 5725799343439052, 4170083215192005, 4497273560337215}, + {2190648163527070, 1182302286459911, 1698709705179966, 2858053760026903, 512030280417031}, + {1766029976663583, 578113072554872, 1407762358462124, 1251410333318914, 1519685697291309}, + }, + { + {2425211004658582, 3219329122771349, 4160786304284559, 4915538208049169, 4859858046454066}, + {2165465146173096, 1900611060212209, 1042730545588351, 2014093929109019, 1810920073473014}, + {2188210814895132, 862494540176239, 429026747909695, 420692388686242, 398456856483386}, + }, + { + {5384113697440972, 4249326538414056, 3736088109548391, 4776181701890428, 4340637335144904}, + {2182481135659358, 1214620204337280, 1322637461359405, 3608648111407434, 919105498759084}, + {825616994407031, 220978982016139, 419943662189285, 2047052177976116, 183513451940769}, + }, + { + {4383853436467396, 5616868348446865, 2380427384672103, 4007620388627955, 4745758889436972}, + {3034925520134716, 2558549339328923, 2273570634299175, 2355590727329921, 1721435535499274}, + {397259122369220, 1632965024772390, 1358524229763907, 634652123170537, 1300732316858513}, + }, + { + {4537722552642641, 4406953311574034, 4747655843802439, 4621074214609984, 4656289262373784}, + {3211235434961971, 649442782529810, 632841582251763, 3220605671079152, 3939184634719634}, + {596504540509310, 1411595783429460, 320205765945468, 1703829528897671, 791135694264620}, + }, + { + {3935303504608645, 5231587761610764, 4492307054736833, 4099267906214233, 3895141043651931}, + {2905973217158121, 3180461607923868, 3881652820548741, 1616810006326533, 2007934577851039}, + {1723586093910128, 42167711405468, 711328489930847, 1802621686437750, 138939056743574}, + }, + { + {3535285454280039, 4143874578497438, 4378537178006869, 5183808895312002, 4029558557190188}, + {2822051371235755, 1171790929970038, 2832133858385125, 3449345178331124, 1343246277400448}, + {201514708798683, 714458960438240, 193526864900221, 289856941669808, 677692044183495}, + }, + { + {3390373253525299, 5571978408447513, 3881939102950573, 5664584550774172, 3541416731496846}, + {3067220342787603, 1318716141230895, 859940092247599, 2796965663112684, 1325031219234520}, + {520206601828502, 827736556609109, 1548115289807569, 226762337353952, 901425653289102}, + }, + }, + { + { + {3876784047658153, 3427402741453803, 4260413043643610, 5364266100628625, 4512454692213601}, + {3846988412720927, 1464526558278043, 4150028797303466, 3612037356861449, 561355623244019}, + {427225699371050, 88989906931284, 374954954790275, 1891881595245671, 72849256625193}, + }, + { + {3916811195383628, 3630554563432754, 4990637953666720, 3851134441999325, 2556181869064802}, + {2335839984116276, 1931214780001052, 3695690881878730, 1666635094108941, 2394874384507690}, + {487618024041635, 1610635862259296, 1930277174961405, 2060246530132043, 471988063294585}, + }, + { + {5204676678666455, 6002573394041257, 5469218649554576, 5103810246282644, 5450232393144287}, + {2223680929791699, 2255695602856973, 2223372744379624, 2581758136991750, 1157672051964719}, + {1191620799152162, 584262428445493, 1654487633336816, 80589900150873, 1778885798645876}, + }, + { + {3804876885771689, 3030718867413702, 5084806164730577, 4351829583495248, 4696365675416595}, + {3277232365416075, 1648743746278574, 2268484584766767, 347896520603034, 3388269197255745}, + {437947250844137, 170970937295705, 294909197597269, 2210849722009323, 1802271999575202}, + }, + { + {6229784974313861, 4445187233108198, 4141897661886957, 4112739300676286, 4973450766687119}, + {2452873695124259, 3183518466635188, 3225011157480339, 1530254508436786, 2236389510678133}, + {1718640585909930, 289464657861405, 256448940553760, 1840710967168708, 1367355358576031}, + }, + { + {4418094237484866, 3862166158397851, 6312584233293658, 4170168684472692, 3205101920356659}, + {845231506816104, 3749601727822635, 2431461776355856, 2145415545771870, 1633953832787249}, + {1855071951306216, 234835319416374, 608676288546844, 311106921331784, 1424607004261872}, + }, + { + {5534887235292980, 4955913319898744, 4436282654044178, 5157071574798331, 5799145956361697}, + {3127590738217404, 2607909890139434, 625984861031328, 898713331800149, 1867577233264451}, + {865238419718368, 2167660602098967, 849033435333870, 1879862001988212, 2194604163295964}, + }, + { + {5028901701646599, 4744711118820448, 3470202116031185, 5070974802044518, 5029459282472967}, + {2597573876967117, 3500480183251406, 3245567533116125, 2884144221342044, 2745802723161587}, + {1262037831799441, 1761445988918060, 1818282615037362, 643977010061831, 1670449776207217}, + }, + { + {3900064283125076, 2932367474353790, 3722342375883231, 3973709010425436, 4168589452466075}, + {1182011269637170, 1702301475425876, 1754593023447641, 1069325582888970, 3665084705482905}, + {1389152123534754, 679131622889370, 1335753122628610, 2193861582528949, 1750442867995809}, + }, + { + {5195225631658915, 4626594891714746, 5530846200979591, 5835469573794033, 6108601962615813}, + {2118803625617181, 1938389959549060, 3158628651247723, 2603939933464505, 1887075807282899}, + {1094771758119662, 1784696951595960, 1586111086846247, 1024621381632866, 1336860396265070}, + }, + { + {4962714218495987, 4686221014092595, 2854843506884281, 5460710344297905, 3609844163230280}, + {3350136365379549, 514082045997139, 1809601258343901, 1359082981819817, 2325132321451910}, + {816435505147956, 959029754172122, 1905562189095432, 809602990954940, 205405869295}, + }, + { + {4658319919071161, 5037557822453179, 3052863244608605, 4920651274442715, 4594868309263967}, + {2357418342397899, 1599797957446167, 1723240952262061, 1521319741808023, 1244021174200017}, + {1682663787527018, 508342182938395, 1334960042435994, 788285033210835, 1620852797020940}, + }, + { + {4468831118271270, 5037652592706325, 3842859113890724, 5119527774959881, 6070895395223645}, + {2858969631689118, 3774837200669161, 3030920205974308, 3569621881524763, 2272136016309579}, + {1457792005629762, 1504843532852533, 117754270187566, 1653728802150419, 956441650806976}, + }, + { + {3858799123389730, 4813864196253754, 3424673118223091, 3586667532616773, 4976228037682591}, + {1240797555104590, 3504953395544138, 2270523358088921, 1192446004554973, 1265977430218831}, + {209033356623489, 521030133202188, 2210759687093959, 1391735568682749, 2066024683275958}, + }, + { + {4447381514683745, 3805818101586919, 5048484781457783, 3805764540626535, 4979430662961349}, + {4372830229780273, 3385211896687553, 1322477629921689, 1744994285972241, 2453525332947167}, + {469280089327132, 1530255390484981, 1847838662987617, 2225747405410001, 1682362262024675}, + }, + }, + { + { + {4202827224002136, 3028138102214431, 3666469969152450, 2607795400549083, 3461406593763699}, + {2143318224651032, 2985185441001099, 2506505238926850, 2498470302228395, 1442295963272081}, + {2200224066087308, 1167051805827953, 161446888552827, 1516422365939770, 1942535836845300}, + }, + { + {5171889208942910, 4780829163437052, 5016462198638337, 6470156341077032, 3046275441821918}, + {3482226206224520, 997104644926830, 3305574633418067, 2147764348670690, 1676514761128454}, + {1628314393858778, 1997743320994668, 1561201521750924, 1869590045554733, 1810714681142288}, + }, + { + {4681454419314826, 3433609902051237, 2919531098016978, 4380876633130549, 3072926890864646}, + {1675422916543594, 2672408744787477, 2759217149054666, 640362125760161, 2799605921604096}, + {1484872832783728, 72255685107270, 1098972476164964, 1732914770170238, 145186792002379}, + }, + { + {3935383441158753, 4973709539651372, 4161806475746733, 2598419220788322, 4556716999515219}, + {1372652207334635, 2531888280983978, 3771287204988285, 2258792327010408, 640671581341507}, + {156581553787681, 307978851206907, 1451582278870485, 442722234791876, 662472042575165}, + }, + { + {2866740058396235, 3493635817947651, 2400937210085123, 3122677618181344, 4447500274280321}, + {2082652078388943, 2745645971502049, 2295760696601975, 2362848920638954, 2370414183207021}, + {1712668510139487, 784271226274642, 827073136956465, 1001465329762964, 1662630974562798}, + }, + { + {5156175574821430, 4359502037960358, 5222120068062442, 4645531980214215, 4676244221442153}, + {818080711416948, 3611895686544640, 2535691662679364, 3086441935441805, 787978368976315}, + {1509857525874286, 1496970584948645, 399828714647739, 1863753979948441, 2149707660031809}, + }, + { + {4144865997618639, 5339859640465925, 4438288719418715, 4715011715150674, 3610459694506906}, + {2952195132229463, 3345568150314393, 1768906295222689, 2025477905414216, 2995593107979034}, + {1951144383031056, 1085048452592587, 499199223423315, 2055889411465929, 698006601614245}, + }, + { + {4183964222033211, 4817865139479783, 6220809882369837, 3643181163556103, 5929569705519063}, + {700816495675241, 1165569165048171, 2172597164236109, 1071655796287173, 2392628493878193}, + {1862104717906915, 1752261107932084, 1874923294613947, 1008681858018398, 628821150989939}, + }, + { + {4161348428018682, 4510282473079517, 4817307873546246, 3901464805798077, 5820970885668019}, + {2393760120508366, 2923675062487769, 3447512431195440, 3853675368087017, 2900110716170471}, + {271735680629051, 645447398246691, 1438808971583999, 792432482423730, 947645802664175}, + }, + { + {5548911597254848, 4313111803014757, 4159094458160020, 3906456530516599, 4703406736341543}, + {2468698810952212, 4159587806133767, 3895277333299798, 2370621230252749, 366242246574179}, + {1891237336529861, 2200322075990278, 1389309370267760, 1284260243869154, 2019396638376055}, + }, + { + {6612681523843925, 4270864305450289, 3731318918021201, 3544862780769488, 5178202040634906}, + {2135755065262843, 1122607271257525, 923542923082409, 2860818598984322, 1922554972749380}, + {242471180181642, 559887731579688, 2072408437063313, 1092425853708654, 1508919031894623}, + }, + { + {5872377157668488, 4408911728296550, 4215455815151923, 4350437538061339, 4304102307657902}, + {3016579539029836, 3430456847285690, 2439572409111001, 3210834728649259, 3775979784664836}, + {681181014012506, 1995504690201206, 1747715035603252, 100305442172708, 1898381133318416}, + }, + { + {3131841243480282, 5236372530773376, 5021877536268058, 4866190361541948, 3290429298804025}, + {1471590353308208, 967056793878588, 3802522075784380, 4004598771731972, 2024618065937019}, + {1109658864423422, 2103734444560570, 2073023657041166, 369769649281723, 817132219307245}, + }, + { + {5632635968843701, 4247258704551623, 6265280169576672, 4815811703628991, 4268679712320579}, + {2186780367255445, 4183850462668485, 2677999934662660, 2880987810780319, 4113828005081983}, + {1441842413844030, 161967823757178, 143843657267759, 468984586211790, 1403635869302761}, + }, + { + {4465016058776751, 5317359619864273, 5237005983845137, 3609875861871372, 3464614715951065}, + {2238448064725901, 3110619177809235, 2162294075762619, 2319911679772150, 2285011619226311}, + {19804365830533, 1686591959644968, 641957734952114, 1534607041731245, 2021106986001419}, + }, + }, + { + { + {4685063337509321, 4828498939602920, 5252037453775058, 5946493173698145, 5385655016202805}, + {944214205150673, 2365379166371694, 3557291173836860, 2962349586178017, 1508433893219247}, + {99837384801727, 2128746966172064, 1728087272474317, 1660968164341303, 2094478837305487}, + }, + { + {5059816654277047, 4494318859907208, 5234935703112714, 5064000806734505, 4673368238982494}, + {1045092786794937, 922156857253434, 2823065772236182, 3280047208436923, 400144133024674}, + {1350540322092981, 428507123444697, 863081413402232, 950089447398951, 118865435494230}, + }, + { + {4685872193140817, 2986094649249487, 3994164430284207, 4339988837278092, 5456344527489565}, + {1863120758931529, 2615255562194237, 2546630581550601, 3581241606812888, 3495878108380709}, + {317239144147936, 1378693805440304, 1613995646839215, 1790616997152168, 1664744641804674}, + }, + { + {5168378766438094, 5613439416641824, 4644053531787994, 3823661418550054, 4036137961950509}, + {3162078769819650, 3145982897294820, 830213734772942, 1343060696486484, 611721765217825}, + {220994375354681, 1633125608855915, 2233079832150828, 144297568151940, 217868145580028}, + }, + { + {6394803792754188, 6132368335021053, 5067197744306631, 5563640033331609, 3502674887523375}, + {2185253522527390, 1722061079589371, 929518249744037, 2473172243807197, 3427214482375105}, + {579681536856473, 1962714631533051, 518559321779053, 971489356480100, 509262501560864}, + }, + { + {3925113491817113, 2597442932750426, 4547336592857079, 3567634098715516, 4305879739481027}, + {3780232691597615, 2387499794027268, 780855157188913, 1744928736206446, 1837149863417515}, + {1612827416827303, 1149821613065205, 1844912308905994, 429769677786205, 1866058244678788}, + }, + { + {5323969415910835, 5007501896425241, 4051100888248418, 6293526281093731, 4819708586854638}, + {1087967203355487, 1504313118437159, 1271975234407042, 2125305808015759, 1278369242007838}, + {2109491846902798, 1459244188614787, 1145316246074802, 537401043713173, 2076110035136585}, + }, + { + {5420343519672736, 5167540178478133, 5227270808193702, 3857502656954627, 5090553389549522}, + {2543056198437618, 3682981507069573, 1492922137755706, 2553269698918225, 3362719634517442}, + {641798503068060, 129975789967638, 2167736719761015, 31631641435626, 350785183214734}, + }, + { + {5066057417347081, 4106102383764030, 4636402204189217, 3166449457097492, 6512612113974837}, + {2326671091720579, 1608331768972414, 2153369779460415, 2214666295188594, 2144539481917009}, + {467300109694399, 1693264194394125, 270333528447105, 650109201517682, 1183509432017698}, + }, + { + {4980219730800404, 4347683389360629, 3797217994168414, 3968193844610984, 5065496827863311}, + {1399648064845078, 1606346276621799, 2881852436764688, 2553259795593478, 3428187511626105}, + {301865991723133, 208252052427984, 51972802328726, 2021710333754506, 1378508945174500}, + }, + { + {3184436513057976, 3574184872992923, 3980701068825082, 5420309832432621, 4126883464345483}, + {1378603098333140, 3238698568766207, 2846856431574260, 3096436218915115, 3811649319155499}, + {847831302663356, 1506598425567944, 1109350264779453, 1031639907526886, 1887329321191319}, + }, + { + {2729102328832984, 5496148280158443, 4624803589574900, 4730709608222510, 6347472137270048}, + {2243355286660512, 3259846408864417, 1913072889496856, 753019988978676, 2074854260894060}, + {1050426720469833, 301805153257576, 1393268630450121, 1286505995795045, 1587323866723540}, + }, + { + {5177553689561919, 4133777550475335, 3692495435897478, 3458719135916346, 4458613993531757}, + {2247714139881915, 2782180885900161, 2312112468846576, 1680267679651832, 1590058688526667}, + {714977855392027, 2020332496651261, 1788558438911234, 1873232632822523, 503071332489421}, + }, + { + {3928537419758315, 4962617917721336, 5009684278125795, 5080330424879792, 4736452659996568}, + {1885791717393579, 3608519904666432, 3804656767054515, 3734399316619142, 280860879781734}, + {222453425419780, 1881231455372494, 356159674087381, 2031436073565603, 1587722788974501}, + }, + { + {5557830146603019, 3189235339941465, 4073380612031396, 4406171020530468, 3729384279482635}, + {1262604590990019, 2611597233679237, 1167025725287256, 4282778604598424, 782190165854895}, + {2186405536221393, 1904322539012708, 152608078674767, 560457311616919, 22952815837658}, + }, + }, + { + { + {5410522905087843, 3457067311541871, 3734790664132962, 5317892036251255, 5789103873795877}, + {1051236049852089, 3090035912523931, 3653329677163146, 3071361720175865, 1695547314615009}, + {342012360452061, 1887029215668228, 1155449753977691, 310762800506541, 1868750527042639}, + }, + { + {6005811139638228, 5026414264668887, 4377100252408278, 4270582517957803, 3422272486715601}, + {2698577143176842, 1182111476573107, 2613378546611642, 3220851371976805, 2803670963190147}, + {883746203814773, 276737323512287, 2229390196673160, 2155663378443822, 635390057802745}, + }, + { + {4097156896954595, 4786624081470779, 3512858804636033, 4586748051134289, 3866073874774231}, + {840689961188261, 2918655679606741, 2236632145763387, 553161305644429, 3021893411965909}, + {1649953183870355, 2176771717569818, 1233096109604549, 1152511702037810, 560573824644263}, + }, + { + {3626792084314328, 3138501138424139, 5501515071454841, 3948607545905590, 5453543250308683}, + {3279453112825750, 2682669747401601, 2291239772155005, 3644653666115630, 3532224357711467}, + {380965098906693, 835788132761480, 2232989119976139, 2205277179143298, 1175904351372329}, + }, + { + {5088419201363648, 3175894686165450, 5299797135086175, 2983523363221301, 4220825923293130}, + {1276840412816828, 2771169526519092, 2136012615148103, 2431893903507465, 1217611106137226}, + {2073239372536943, 30649016949678, 644492521678981, 305840627193069, 109901429265295}, + }, + { + {5139707358045825, 4688671704193624, 4352852502302345, 6384641621021538, 3836551482242832}, + {1192657509706017, 2505894684845872, 2556098156240875, 2309411544504528, 1820864150951982}, + {1002466072624564, 1231676492638173, 1795061881446222, 564780581799518, 2025621015597595}, + }, + { + {4858692159454824, 3985618384769197, 4768611969748369, 3070997304216167, 4648245907091308}, + {3367644801750200, 3754604094141859, 1751381457602879, 2418709533236081, 3882122160708146}, + {374714050779396, 405289438859672, 1963133877676048, 2112584561135192, 1143185401022561}, + }, + { + {3846711807981435, 4505402219442327, 5146862869313170, 4623705187751987, 5565609289355471}, + {1926650836092769, 1141267952622767, 3387976667434360, 2038056869767013, 1320936551384977}, + {283489509389185, 614480115735096, 278795579529276, 1166609138076060, 1715497286463476}, + }, + { + {4275758633577087, 3861278996194559, 4466252217383748, 3665496078445880, 4058888268167473}, + {3871692294074427, 1764539273907035, 2887939385751194, 2243961968498350, 871865948439469}, + {2109468136302879, 794757759853720, 236685909745726, 1503678842333224, 2147818470882973}, + }, + { + {6104878619412512, 3485890441294438, 4220586739682332, 4017322426737508, 6001128289990864}, + {2677372099733352, 3437936829126546, 1424452207982980, 3507913002098314, 1735468130831162}, + {1938075620777682, 1762081466410536, 1564991344244054, 1376297777594771, 248036172502508}, + }, + { + {3778095331789531, 4910813465857036, 5137553967349467, 4984396828084641, 3687371747598377}, + {1479550570874507, 2294055327463876, 3724831818626703, 1654245262468829, 3019040190597313}, + {1873423061916096, 248167770548070, 903648623666602, 2087943940366473, 547940262578569}, + }, + { + {4725001988101218, 6546220549270451, 3469130078731384, 5687075187757928, 3413336519371176}, + {1413358533598756, 2252005803690891, 1458088388485468, 1671589233622260, 1797166284473808}, + {523276182513223, 343307024193534, 937383689926833, 1330219799726239, 2232356434433501}, + }, + { + {3569532147039540, 4195918401728545, 5115321889044388, 6609417783186476, 3958938427322120}, + {2397395505704106, 1262743052475361, 2547892063055852, 2321536665849090, 2021113849426924}, + {141428615990698, 1565258204511290, 2188430123291708, 1781055032390171, 763358600759749}, + }, + { + {3906824289179955, 5654339223566203, 5504976063361072, 6361176910130113, 5155227057638370}, + {721005728190537, 2847737995575099, 3056729868442396, 2393716554993649, 3467469336561398}, + {160800301986322, 534920738504617, 1465194074759867, 132949302971740, 1176455782582044}, + }, + { + {3433889410020031, 3665956712149865, 5366646390977683, 5367384152674927, 4795948454618784}, + {1902504950598053, 1202752625490289, 2565725054888499, 3023474686925025, 3059561010324150}, + {1935479944158543, 1102588664377385, 1651606970291190, 1048887489959304, 1677042940335362}, + }, + }, + { + { + {3858553186233324, 4192597543704949, 4422265554716229, 5060918874051413, 4251667779718110}, + {2960733565044348, 2107676482823115, 1657279889267301, 1609984394439769, 1082526754413784}, + {1823622181083017, 408967151178094, 2033143529389867, 2209724434343478, 918118538477317}, + }, + { + {6088716933512995, 6116095372188681, 4275776721065459, 4475819482692536, 4685952285527508}, + {2842268335288737, 1888183319191451, 3692488899816305, 1677336684221250, 4176880757505444}, + {463491021439363, 1750609461077078, 1169967881279297, 474253519600450, 901070375860211}, + }, + { + {4400692422952866, 4659690717529996, 4722795303748102, 4016471577087528, 3702653606869112}, + {3485976485792634, 1118156106770038, 3653108520059592, 2301046652704138, 2381698882921202}, + {288029433804634, 1918327772711516, 1858109617364668, 1548745667412753, 1635036158704975}, + }, + { + {4899918186072737, 5587073618198231, 5408433162977742, 4217274871182020, 3058703542950255}, + {1915560744141461, 3219944346867669, 1684794323668364, 813038486884416, 2736974530406253}, + {131383425958682, 1726194406199626, 1195125520329959, 1269440178344704, 1934708138886976}, + }, + { + {2560939345231273, 4301322442066007, 4073130192422468, 4440850393019204, 4883344655404735}, + {2185121667669569, 1115206785572251, 704158439711004, 2133851508118048, 1251130304627637}, + {1895230235031468, 1896812472261458, 768470747222158, 1996242383935516, 1420798451369434}, + }, + { + {5839795121226482, 2867951589507385, 4636256264448023, 3052659764389740, 5026931603960818}, + {1579856931436900, 2447051767839229, 2868067823655589, 1688893962924788, 2116170079089324}, + {556211501812000, 449190026847667, 2036295767110360, 128995208617458, 1118467502984960}, + }, + { + {5602461071232607, 3307918487728174, 2854017338064603, 5855272157497266, 6150895900635822}, + {3398390622800229, 1820230761045332, 2690748155578623, 3095835968664066, 2530217218349662}, + {1878982227582804, 1431346083601994, 1534977024077189, 2155113334662581, 1782950372830762}, + }, + { + {4697661970186985, 3763132135142867, 5033467660349912, 2907155321697052, 4660465007863417}, + {2604312744349849, 2452708102821815, 3230466926286856, 2118488738947708, 2304478471957885}, + {1390885694073460, 1816639772663275, 1066627353945560, 1454561122724455, 848860562366790}, + }, + { + {5540829116940004, 3948748499449809, 5260550454870879, 4676389564943908, 4383546683050662}, + {2563789831020858, 3343718595008637, 2259025389677919, 1392665428080842, 3671467539073936}, + {981545110828877, 510698765880228, 2161678679515528, 1436791773758609, 1673597748298096}, + }, + { + {4329713062953095, 4939339976361997, 4958702235647932, 3268883154176961, 6391544885910171}, + {3614223297666549, 3897390208178715, 2811994039134574, 2958689501074087, 2363866533687133}, + {1294858674770242, 529668890256843, 2030539078163824, 294693146073477, 969527805905143}, + }, + { + {4670371383742225, 4002936514889177, 4966859846610707, 4736741110602146, 4760957427324248}, + {1176127152490445, 1894013131106171, 1812632908007715, 3751034747324574, 2289873378487758}, + {61868149975749, 236120696290007, 608351327055311, 1829919587421069, 1627340269896729}, + }, + { + {5062259960708944, 2689430826280744, 4108030288846956, 3316359330121699, 5641758926485313}, + {3722896082959268, 1863222026681564, 2044934869352810, 1385880696113195, 1308481967864035}, + {1796753889379582, 2232245583163596, 176790521107364, 133826841897595, 1041041183235991}, + }, + { + {3537934576014922, 2998428847270897, 5788967881664907, 4283416153137820, 3545722873501844}, + {3424639235617092, 2530506041245943, 3202402279176211, 1867524240141886, 1078908361802522}, + {1442655471934418, 1764674447040318, 316317796980033, 318184491515700, 1168933061547497}, + }, + { + {3599845082833499, 3896846545871592, 4303714095196951, 4532827504261802, 6020561742040974}, + {1580156396502051, 3208244370687690, 223926404960589, 565074765027696, 2169726994764050}, + {1942280341359651, 50425926664281, 1816034234875212, 880607828368837, 2092912650330571}, + }, + { + {5512765861463031, 4125716632501591, 4924530697112776, 5238255918415337, 3653602071478327}, + {1344167653424867, 1048535312223495, 1948741777806718, 3072730820612467, 1645288196866883}, + {1745152490874503, 1836336442271605, 2042898833391948, 1540893062903555, 1183365031475960}, + }, + }, + { + { + {5866266958495514, 5059063420853561, 4485040531648720, 3733835905319672, 3149359201467933}, + {2684460961013652, 3709949712072759, 1783966662497692, 1338383483986408, 1938129546538183}, + {40033251972751, 73885946378640, 1935473366247146, 1461619709267546, 1211799649582059}, + }, + { + {5250457209059169, 6625476149991574, 2830402208757038, 2943786524207392, 4303078760549837}, + {2301225069080269, 2184860938031358, 2273332051328548, 1704804667098002, 1911735781256473}, + {2217303387266656, 2227853943602075, 1384266551040407, 847818056628355, 1874126181291960}, + }, + { + {5228171959238562, 2572808713483427, 4818692310321808, 3983994866935258, 3614639592657195}, + {2763608237796206, 2346801614322209, 3045306834104040, 1893958852943478, 1490859261541415}, + {247688480299164, 1512873113726713, 1351630747308477, 937439467136054, 1030677695284257}, + }, + { + {3673708668048072, 4665314801263177, 6233349558231934, 6339984458236183, 4552548914816150}, + {3247306673138258, 2425869243107473, 2622484905091774, 2040657700179409, 1450858492090282}, + {1636572211186580, 2000987144770729, 1893417472062746, 196779160527558, 1557344243161357}, + }, + { + {6493926578942193, 4543542057302668, 3472731731448002, 3629201377772109, 5141975006754257}, + {2310006248725699, 1647962485872618, 2823143389536034, 2192050419207497, 1818655878772515}, + {1024434193686880, 2242250021719251, 564307645117404, 690001361734624, 239056809198959}, + }, + { + {4713019913612655, 4128228433667681, 5028024885108113, 5705734794679268, 3306562584580656}, + {3717108646348257, 4084515682195001, 3812051722646527, 1684888211341314, 1618372056987552}, + {1877409538331051, 337692456674055, 879114692044355, 2186377676371749, 1343387843321657}, + }, + { + {4142192651183813, 3524721259616285, 3594705099270661, 3959153982160586, 5413021910706886}, + {3669516570196207, 2121969005742829, 1652467606544375, 2698034847882520, 3275951535145684}, + {535664786267626, 858000264335400, 1392803193793530, 460772165692459, 1244185301942167}, + }, + { + {4502106313596470, 6443346829525378, 5721231993875900, 4681113914034302, 5472479613319256}, + {1495731174651276, 2532746921337410, 2156800382632014, 1987445924091844, 3448117379338544}, + {483117633444291, 1721449975252800, 2014677970681898, 2079902425951169, 117285229800651}, + }, + { + {3261832527463430, 3508653912421559, 5988429677058390, 5333822038484553, 3271080652355482}, + {2204547407113574, 2042779888674267, 2424936780736806, 1416144793524967, 2647730853119196}, + {417006946097712, 816142170165382, 321665320486095, 1120596382678137, 995334532083163}, + }, + { + {5667435300952982, 4583050105149113, 3937627982933697, 2917941244133350, 3746324610420174}, + {1654154218632292, 2424649854522191, 2118483268871125, 2658103876978958, 3351121693690514}, + {1757087236610187, 114932695265885, 1498710897730185, 1732388966595209, 145995973897689}, + }, + { + {3747574781762871, 3444173068370155, 2989065545095348, 5144077823603124, 5597474176298234}, + {808058917355435, 1642072317689253, 1764756051109168, 1619463984060522, 2971052737331444}, + {344784500521841, 753070981245028, 1021287645349333, 896645545453199, 449568974542070}, + }, + { + {5037125630216086, 4317087092146610, 4394758621519137, 3169411347551391, 3200762148534134}, + {3758879149962654, 2267958484085658, 725842773817223, 2203610500470887, 1640888914156664}, + {1753063336824455, 1632699439142352, 654655992711894, 254878945844677, 1142235737877277}, + }, + { + {3668977677139265, 4332641682100108, 3590347451295966, 5242849066395039, 2727116665213341}, + {3248235630095651, 1380466035309490, 1790683862609512, 3542725848725101, 2663722245169429}, + {863640852068414, 1530602868551714, 1707160942886152, 54230982937714, 122819573759751}, + }, + { + {5532810941110268, 4585437113624970, 5116705204102219, 3665108856301161, 3445572551989045}, + {2829139259902194, 3388923696568854, 2569841942150467, 2697982670988693, 2163914772008849}, + {2076653457069888, 1193685867720358, 1325584969753937, 1501472994346955, 87079528165998}, + }, + { + {4556025881223574, 5720430347742651, 6074363308505144, 4027406626756934, 2527767620430889}, + {2142131119871606, 2984501701896371, 2717746191530066, 2203225891573820, 2175517225379719}, + {897107227346093, 455907621058237, 864390863340574, 316655721359786, 1688391871841069}, + }, + }, + { + { + {5225107848603314, 3997985175873023, 2901647838494787, 3895284350008311, 5682946636557185}, + {3523031484358436, 2824636666213863, 2395141832526945, 770528850757883, 2501907940021781}, + {722866669050453, 648025000876863, 272387785321835, 1191578896340587, 133025146298323}, + }, + { + {4430018927628058, 5528149113975034, 3884602704599257, 4041974594447505, 3905022194274965}, + {82857304500618, 1554338034359360, 760468202446199, 2344834461467455, 688719719651551}, + {2128452325542740, 952454207454828, 1516099560539414, 1362377470631451, 1181280467630705}, + }, + { + {3877905624740973, 5612025444592814, 3620377076227448, 3557624466809644, 5794884625077990}, + {1234316951156125, 2774803744202148, 3038336850143346, 2839603046584234, 1645722164542234}, + {894237486099210, 1516039905189318, 1740044048087400, 593444525063043, 2109764897178862}, + }, + { + {3625360958175610, 5708422748846073, 3787265901576189, 6157656721094708, 5961588011087405}, + {1482109974932762, 1512691293799179, 3308418655922299, 1669766513116242, 1645628848588889}, + {134048702591674, 1512942576919112, 1666722043826583, 1830910766776036, 90483195207340}, + }, + { + {3762249153136541, 5419647444574112, 5020263484993746, 3697437793067561, 3831953348456062}, + {2494438010166937, 1432383122970498, 3625127628421620, 1764585753875763, 2715866922646858}, + {914153294895020, 1485178337004016, 1172992438642136, 742396957515979, 1460451697085215}, + }, + { + {3293341585462216, 4914585647995248, 3425647660888775, 3851476795826281, 2935952374714235}, + {2881676317687314, 3127597808111770, 1680974550469383, 2631492786928655, 2080467460645229}, + {1084836891982052, 405373371974756, 392292573225522, 1228291428535054, 196706224397467}, + }, + { + {5422966393229312, 3517798661028565, 3491057102408135, 5349612585124235, 5098313025804708}, + {2181085219797570, 2438267619893703, 1398091257339579, 1543623638852333, 2275879750497956}, + {1451708073273912, 640663458576442, 472967005176057, 1940369909273489, 1650816055376110}, + }, + { + {5775591770146864, 4809727687563635, 4066767569195787, 3927850608944429, 5542524111957037}, + {2856057239056516, 3899713821492127, 1178627125851433, 3276833765573271, 1528786153297881}, + {1406590024268518, 1220852036090080, 364949301397175, 1654716393716139, 143122595639438}, + }, + { + {3092682960222618, 5760168522994174, 4966136799494047, 6183321071200806, 5955160799299141}, + {1679800253914106, 1418780742199926, 3419507991072325, 2296436046846462, 2072736467396911}, + {882943817583285, 484844826182032, 423720125645701, 79705330082926, 518433021584838}, + }, + { + {4303808439591566, 4492049110308958, 5005208589399660, 3449528090765045, 3218284505011813}, + {3283940803229324, 4459508559485836, 940189907838090, 1705424518756533, 2039165337931945}, + {892563649969864, 218618659831677, 483384434921296, 1959503286788495, 846111377588119}, + }, + { + {3736052427633640, 3240841928280071, 4678563487154791, 3752373267871112, 4181937274986806}, + {2003615224309886, 1453829786196949, 4170849260029473, 2196915936737576, 3465659437703250}, + {870814358129174, 1509533025339595, 2053081266530331, 1737753718216259, 77875205064950}, + }, + { + {6295693526685959, 4477016414498074, 4045516627237016, 5610462754780940, 5285590675711912}, + {2091650387347437, 4186999032385018, 3695680781345242, 1318896896580492, 3133525015024966}, + {2057751622403208, 2124826136415213, 2162400122701924, 512312961318735, 2072953190856236}, + }, + { + {3421075047723659, 5902999844007244, 5257660560322253, 4411230485782045, 3851018473810833}, + {1356912041975431, 2088651341684568, 2115599337938785, 4037573216393849, 2652908467965391}, + {356251628924273, 2088769627568139, 187882754343055, 394347310503797, 1449630398452630}, + }, + { + {3682820885194585, 5173915763318849, 2521868910298419, 4165015930825951, 4883528324075009}, + {1067127578201981, 2883441503009643, 2032675011298617, 3963320928045487, 1183903438950389}, + {1431421126152216, 738544074023370, 2193830823196529, 1671561335663722, 717735409657132}, + }, + { + {4201586389811353, 4375880219104829, 4192199017276052, 4416844421544609, 3903714904213483}, + {1449584304781523, 3077329128471461, 2135282471631868, 3283981709093825, 2025731372310411}, + {1183319077995597, 1294226945214786, 1175504892926680, 1065468559536653, 2201437139069262}, + }, + }, + { + { + {3505559764260479, 6013086951275753, 5081911139396344, 4716516055339902, 4005184608137658}, + {1941635877650331, 2292936607701027, 802548087270426, 553714331402352, 2637835706093694}, + {1415499622184076, 11739232724558, 1448526577403933, 77973485783393, 148463223858677}, + }, + { + {3556556070469100, 6104580777770606, 3153395731542438, 4746347503688425, 3530835687615003}, + {2563241728545350, 2900457320970642, 2021653799300720, 4081786454058715, 1684057546885165}, + {531432570362576, 1071513573823369, 449672118652203, 98547521251379, 260579416510065}, + }, + { + {3113402949202118, 3224343282781895, 6393340053990193, 4574021187583530, 4354743893457091}, + {2098297300858722, 1637995723173513, 2132191683177015, 592134746032938, 1044637126699087}, + {607038018090674, 1768950085932612, 1176147243379098, 1239851308662055, 1164850159859507}, + }, + { + {6544624144736846, 3158440120316048, 4122467747600782, 3270454787206357, 5173743677397902}, + {2302101840952822, 2675605826160506, 3431414289057246, 2525090851992001, 1591101869035052}, + {67986117053250, 143032219413988, 187059126532888, 1606721935579222, 2108737133289470}, + }, + { + {5726022544095362, 3724045113988627, 3515582956648241, 4176155101637246, 5525745188146662}, + {1710358734492362, 2952544254120043, 2348808532032187, 3458396516769880, 1537007452608630}, + {63942543002426, 322070337950512, 1601643046070686, 1223905889282175, 1741111665223434}, + }, + { + {5315895417052113, 4828375526334729, 4444010786735381, 5993309905616190, 3640401138113649}, + {2860407040121293, 1177142915116463, 3145140653940871, 1733521080031482, 3186874796199337}, + {731527977617797, 464892677638406, 850380242165564, 1707297435867315, 797914062581028}, + }, + { + {4481445847621310, 4194775426039896, 4717484155432068, 3203129625283069, 3774741254649070}, + {2200385186612512, 3830080434695126, 3332312936597714, 1819075993402941, 3697021137208346}, + {1808087344592199, 1917986815291197, 1736625562156353, 1691009053422774, 699554104203468}, + }, + { + {5048623459093582, 3345582890430421, 3965077987869649, 4640623371578895, 4912032720993151}, + {2302864341793270, 2363316925891845, 1559429527589511, 2124275860379685, 1685170275648173}, + {567087552892581, 1562927351866469, 299640978917608, 868196882482839, 81953139898216}, + }, + { + {4967323480101032, 4012272011745302, 3862894427518599, 4308636686245327, 5217499651112315}, + {1252667495912574, 926763760798846, 829943705996489, 1227324880932263, 964621170655609}, + {955876088496614, 2071382636271538, 1339562676294470, 1915921082315197, 857114822306108}, + }, + { + {3257326910061677, 5127439013196396, 4310630254544639, 4686443315427179, 4724730249377907}, + {2936128018106963, 1695470026893168, 2973127512604355, 1666309508011309, 2226049713730899}, + {1512722216346670, 113316334999619, 1851114541854723, 1700671412068281, 1858477808352196}, + }, + { + {5998097796107191, 4771418173207581, 4274779313964863, 6374384720876343, 3691059377431806}, + {1747059722842985, 1151985779666741, 2579873034214805, 2259025270175461, 1104167228907676}, + {1120011747324768, 1881628887342023, 2214290331844435, 486356580332714, 2162135539567334}, + }, + { + {5415017211564966, 4131956504736867, 4606393482137328, 4786286211324892, 4752001899018321}, + {3516707084985218, 3646421870194647, 1944208348735794, 2748388507091938, 2933933255585587}, + {939102610898658, 657762889309704, 1555084457788919, 1150153333777593, 1006706590082496}, + }, + { + {3543688234603472, 4194712450230855, 3880927772745797, 3426761679103243, 3127058186392728}, + {3187981953742084, 2855163365535635, 2396035850573347, 3426339364174055, 2041647909167010}, + {463905214510220, 1910840871806134, 115888611524937, 1537009142155618, 880221457903699}, + }, + { + {5589672840238728, 3432294293459350, 5387677215955058, 6169144676112659, 5379715338757042}, + {1784370156336156, 2235499907922716, 2025309612181078, 2188885065316605, 3233083367725482}, + {417210119430620, 1641361429213146, 1508617462812435, 1831075688628217, 1813350286884393}, + }, + { + {3676762525127118, 5016274613231870, 5279594930346407, 2746860593795830, 4531082394479975}, + {2603791557859206, 567981304762832, 3180006238725203, 2675077654404820, 258215834034235}, + {1643563927005454, 1423516315292419, 46523883479803, 1501791298376850, 1157127033006661}, + }, + }, + { + { + {4640633429716646, 4436352535262760, 5042663907988027, 4328339913162644, 4318409930240684}, + {1650059244213924, 1415687339027798, 3751941600642035, 2204874486713656, 3546077689782506}, + {1247200432261975, 265507035905438, 1620404126253617, 117362009527087, 1746435297969059}, + }, + { + {5340736267872142, 3295470429174750, 4407135163398927, 3488366482378904, 3746520348111790}, + {1068629703061668, 3236562504536698, 3481748917474479, 2110232841828030, 1092532788851750}, + {1306097687903586, 1372543655508231, 1658076721821581, 2200003583698537, 780636112677937}, + }, + { + {5226077937175337, 5692428823576533, 5689014150777050, 3908825240466348, 6345259720261058}, + {3066336104509029, 2314860930152579, 3056640011863338, 2260092480216528, 2073254466378784}, + {479894784370716, 1925880613677947, 2183487522494884, 625094381313712, 854845126872293}, + }, + { + {5197618157762598, 4433464121961190, 3260681654961795, 4120975634792281, 5835262176061498}, + {817093479351430, 4088761935787052, 3171716785010059, 2728541872107727, 1520644895959802}, + {1207982418891449, 1577854720087533, 2009037012572541, 1476807775109585, 764858983320152}, + }, + { + {4643752207568541, 4177425086748798, 2717351689863297, 4063904331524798, 6079476938692958}, + {292623621294171, 1087309087737456, 2573455597713993, 859400146466928, 2565065720265056}, + {1960514462005953, 1030291725190195, 357278058611993, 503261352420903, 409647200988996}, + }, + { + {4137436424426920, 3760583205467834, 5814704535202459, 3679343367155289, 3544651677301793}, + {1640564024541742, 3450104780081118, 1372955845260037, 2487953912194947, 1964015174577549}, + {1832104727099167, 996069167520846, 1100729754186688, 1771584084767106, 2117261745027080}, + }, + { + {4431020636065029, 5503695293870154, 4553592025467096, 4019460577334316, 4832018945114183}, + {1199122074926019, 2522059134402784, 397875262207322, 3119865606750668, 1432109594857765}, + {1875633950147766, 1109790076082089, 897660652998513, 1428078707156757, 908826481148722}, + }, + { + {5054013235620828, 5378852271051704, 4293253473160895, 4319499063151422, 5340758119594162}, + {2634018106321626, 2505108247629684, 3126341578772617, 2016974307899050, 1468999769476078}, + {2013224690617610, 881120726963113, 2087874148443678, 930634847072563, 2100154549645766}, + }, + { + {4096027168378681, 4674912073837464, 4651610619813038, 4659750027669693, 4079639323873143}, + {651560684224625, 2530373654189494, 3125510882371828, 1936741789282769, 4026872663838631}, + {1094258812694036, 1294242138409324, 1090035173467081, 1763568378228799, 1431407300427851}, + }, + { + {5901866474833548, 4953841416438018, 5227230958845012, 5669922347444024, 5683271169352586}, + {2172262341405882, 2561868572136046, 3688730950551326, 2503867014426524, 2213093161812464}, + {1951192547947024, 851119993124706, 1847432304733109, 1277897613708864, 601543383482271}, + }, + { + {3631710539670242, 3768950590313261, 5303952111138864, 5325131792733564, 5315344346171139}, + {3338513542876810, 3006290156706597, 1350992246942434, 903865514364164, 3147437075515383}, + {2230520732543357, 1272781658952307, 896500518331525, 1553870550296913, 1174834176365255}, + }, + { + {4212629881454302, 3511449460350501, 3310343538794185, 3281266357642722, 4487974828971768}, + {2969785173831624, 1505727885325259, 2813024274382127, 1442092766966006, 2775912811267378}, + {1226820412291019, 1429525834475644, 2118443840955994, 611048578379551, 1393279248359119}, + }, + { + {2549845597186375, 3623100753864553, 3499310120841001, 3967554171599715, 5734430215634972}, + {1995271425552231, 3083791126213951, 3279752729240055, 1320836376731637, 2619696559790542}, + {209938911194598, 1168941097549542, 1505719700014288, 296602403362327, 585510095036421}, + }, + { + {4596693410811983, 3239555606447835, 5319792910601399, 5807716310972140, 4978776737081211}, + {4298118886570999, 2595714642338047, 2582204981507639, 2283950348816052, 2880808000087105}, + {1625024000487589, 1577328585741835, 1748162688303583, 1508135442094103, 494130659185316}, + }, + { + {5133202328939711, 5161068400634691, 4982689133170151, 5479854286391464, 3974357722065660}, + {2759508860286693, 3544879646603215, 2393702940511177, 1786833813469860, 2879003887330732}, + {374825657994223, 798281160160783, 1037106323566812, 1491213365794340, 786385610113834}, + }, + }, + } + + GE_BASEPOINT_TABLE := &Gen_Multiply_Table_edwards25519_lo[0] +} diff --git a/core/crypto/_edwards25519/tools/edwards_gen_tables.odin b/core/crypto/_edwards25519/tools/edwards_gen_tables.odin new file mode 100644 index 000000000..a204e6ac6 --- /dev/null +++ b/core/crypto/_edwards25519/tools/edwards_gen_tables.odin @@ -0,0 +1,138 @@ +package edwards_tools + +import ed "core:crypto/_edwards25519" +import field "core:crypto/_fiat/field_curve25519" +import scalar "core:crypto/_fiat/field_scalar25519" +import "core:encoding/endian" +import "core:fmt" +import path "core:path/filepath" +import "core:os" +import "core:strings" + +// Yes this leaks memory, fite me IRL. + +GENERATED :: `/* + ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ +*/` + +@(private, rodata) +FE_D2 := field.Tight_Field_Element { + 1859910466990425, + 932731440258426, + 1072319116312658, + 1815898335770999, + 633789495995903, +} + +main :: proc() { + Basepoint_Addend_Group_Element :: struct { + y2_minus_x2: field.Loose_Field_Element, // t1 + y2_plus_x2: field.Loose_Field_Element, // t3 + k_times_t2: field.Tight_Field_Element, // t4 + } + Basepoint_Multiply_Table :: [15]Basepoint_Addend_Group_Element + + ge_bp_addend_set := proc(ge_a: ^Basepoint_Addend_Group_Element, ge: ^ed.Group_Element) { + // We rescale so Z == 1, so T = X * Y + x_, y_, z_inv: field.Tight_Field_Element + field.fe_carry_inv(&z_inv, field.fe_relax_cast(&ge.z)) + field.fe_carry_mul(&x_, field.fe_relax_cast(&ge.x), field.fe_relax_cast(&z_inv)) + field.fe_carry_mul(&y_, field.fe_relax_cast(&ge.y), field.fe_relax_cast(&z_inv)) + + field.fe_sub(&ge_a.y2_minus_x2, &y_, &x_) + field.fe_add(&ge_a.y2_plus_x2, &y_, &x_) + field.fe_carry_mul(&ge_a.k_times_t2, field.fe_relax_cast(&x_), field.fe_relax_cast(&y_)) + field.fe_carry_mul(&ge_a.k_times_t2, field.fe_relax_cast(&ge_a.k_times_t2), field.fe_relax_cast(&FE_D2)) + } + + Multiply_Table_hi: [32]Basepoint_Multiply_Table + Multiply_Table_lo: [32]Basepoint_Multiply_Table + + sc_set_unchecked := proc(sc: ^scalar.Non_Montgomery_Domain_Field_Element, b: []byte) { + sc[0] = endian.unchecked_get_u64le(b[0:]) + sc[1] = endian.unchecked_get_u64le(b[8:]) + sc[2] = endian.unchecked_get_u64le(b[16:]) + sc[3] = endian.unchecked_get_u64le(b[24:]) + } + + g, p: ed.Group_Element + ed.ge_generator(&g) + + sc: scalar.Non_Montgomery_Domain_Field_Element + + // Precompute ([1,15] << n) * G multiples of G, LSB->MSB + for i in 0..<32 { + b: [32]byte + for j in 1..<16 { + b[i] = u8(j) + sc_set_unchecked(&sc, b[:]) + ed.ge_scalarmult_raw(&p, &g, &sc, true) + ge_bp_addend_set(&Multiply_Table_lo[i][j-1], &p) + + b[i] = u8(j) << 4 + sc_set_unchecked(&sc, b[:]) + ed.ge_scalarmult_raw(&p, &g, &sc, true) + ge_bp_addend_set(&Multiply_Table_hi[i][j-1], &p) + + b[i] = 0 + } + } + + fn, err := path.join({ODIN_ROOT, "core", "crypto", "_edwards25519", "edwards25519_table.odin"}, context.allocator) + if err != .None { + fmt.eprintfln("Join path error for edwards25519_table.odin: %v", err); + os.exit(1); + } + bld: strings.Builder + w := strings.to_writer(&bld) + + fmt.wprintln(w, "package _edwards25519") + fmt.wprintln(w, "") + fmt.wprintln(w, GENERATED) + fmt.wprintln(w, "") + fmt.wprintln(w, "import \"core:crypto\"") + fmt.wprintln(w, "") + fmt.wprintln(w, "when crypto.COMPACT_IMPLS == false {") + + fmt.wprintln(w, "\t@(private,rodata)") + fmt.wprintln(w, "\tGen_Multiply_Table_edwards25519_lo := [32]Basepoint_Multiply_Table {") + for &v in Multiply_Table_lo { + fmt.wprintln(w, "\t\t{") + for &ap in v { + fmt.wprintln(w, "\t\t\t{") + + t1, t3, t4 := &ap.y2_minus_x2, &ap.y2_plus_x2, &ap.k_times_t2 + fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d, %d},\n", t1[0], t1[1], t1[2], t1[3], t1[4]) + fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d, %d},\n", t3[0], t3[1], t3[2], t3[3], t3[4]) + fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d, %d},\n", t4[0], t4[1], t4[2], t4[3], t4[4]) + + fmt.wprintln(w, "\t\t\t},") + } + fmt.wprintln(w, "\t\t},") + } + fmt.wprintln(w, "\t}\n") + + fmt.wprintln(w, "\t@(private,rodata)") + fmt.wprintln(w, "\tGen_Multiply_Table_edwards25519_hi := [32]Basepoint_Multiply_Table {") + for &v in Multiply_Table_hi { + fmt.wprintln(w, "\t\t{") + for &ap in v { + fmt.wprintln(w, "\t\t\t{") + + t1, t3, t4 := &ap.y2_minus_x2, &ap.y2_plus_x2, &ap.k_times_t2 + fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d, %d},\n", t1[0], t1[1], t1[2], t1[3], t1[4]) + fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d, %d},\n", t3[0], t3[1], t3[2], t3[3], t3[4]) + fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d, %d},\n", t4[0], t4[1], t4[2], t4[3], t4[4]) + + fmt.wprintln(w, "\t\t\t},") + } + fmt.wprintln(w, "\t\t},") + } + fmt.wprintln(w, "\t}\n") + + fmt.wprintln(w, "\tGE_BASEPOINT_TABLE := &Gen_Multiply_Table_edwards25519_lo[0]") + + fmt.wprintln(w, "}") + + _ = os.write_entire_file(fn, transmute([]byte)(strings.to_string(bld))) +} diff --git a/core/crypto/_fiat/field_curve25519/field.odin b/core/crypto/_fiat/field_curve25519/field.odin index 04fc87659..ac6e284b7 100644 --- a/core/crypto/_fiat/field_curve25519/field.odin +++ b/core/crypto/_fiat/field_curve25519/field.odin @@ -1,7 +1,8 @@ package field_curve25519 import "core:crypto" -import "core:mem" + +zero_explicit :: crypto.zero_explicit fe_relax_cast :: #force_inline proc "contextless" ( arg1: ^Tight_Field_Element, @@ -18,7 +19,7 @@ fe_tighten_cast :: #force_inline proc "contextless" ( fe_clear :: proc "contextless" ( arg1: $T, ) where T == ^Tight_Field_Element || T == ^Loose_Field_Element { - mem.zero_explicit(arg1, size_of(arg1^)) + zero_explicit(arg1, size_of(arg1^)) } fe_clear_vec :: proc "contextless" ( @@ -38,7 +39,7 @@ fe_from_bytes :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^[32]byte _fe_from_bytes(out1, &tmp1) - mem.zero_explicit(&tmp1, size_of(tmp1)) + zero_explicit(&tmp1, size_of(tmp1)) } fe_is_negative :: proc "contextless" (arg1: ^Tight_Field_Element) -> int { @@ -47,7 +48,7 @@ fe_is_negative :: proc "contextless" (arg1: ^Tight_Field_Element) -> int { fe_to_bytes(&tmp1, arg1) ret := tmp1[0] & 1 - mem.zero_explicit(&tmp1, size_of(tmp1)) + zero_explicit(&tmp1, size_of(tmp1)) return int(ret) } @@ -59,8 +60,8 @@ fe_equal :: proc "contextless" (arg1, arg2: ^Tight_Field_Element) -> int { fe_to_bytes(&tmp2, arg2) ret := crypto.compare_constant_time(tmp1[:], tmp2[:]) - mem.zero_explicit(&tmp1, size_of(tmp1)) - mem.zero_explicit(&tmp2, size_of(tmp2)) + zero_explicit(&tmp1, size_of(tmp1)) + zero_explicit(&tmp2, size_of(tmp2)) return ret } @@ -72,7 +73,7 @@ fe_equal_bytes :: proc "contextless" (arg1: ^Tight_Field_Element, arg2: ^[32]byt ret := crypto.compare_constant_time(tmp1[:], arg2[:]) - mem.zero_explicit(&tmp1, size_of(tmp1)) + zero_explicit(&tmp1, size_of(tmp1)) return ret } @@ -175,7 +176,7 @@ fe_carry_sqrt_ratio_m1 :: proc "contextless" ( fe_carry_abs(out1, r) fe_clear_vec([]^Tight_Field_Element{&w, &tmp1, &tmp2, &tmp3}) - mem.zero_explicit(&b, size_of(b)) + zero_explicit(&b, size_of(b)) return correct_sign_sqrt | flipped_sign_sqrt } diff --git a/core/crypto/_fiat/field_curve448/field.odin b/core/crypto/_fiat/field_curve448/field.odin index 540d88f28..bb077cb1e 100644 --- a/core/crypto/_fiat/field_curve448/field.odin +++ b/core/crypto/_fiat/field_curve448/field.odin @@ -1,6 +1,6 @@ package field_curve448 -import "core:mem" +import "core:crypto" fe_relax_cast :: #force_inline proc "contextless" ( arg1: ^Tight_Field_Element, @@ -17,7 +17,7 @@ fe_tighten_cast :: #force_inline proc "contextless" ( fe_clear :: proc "contextless" ( arg1: $T, ) where T == ^Tight_Field_Element || T == ^Loose_Field_Element { - mem.zero_explicit(arg1, size_of(arg1^)) + crypto.zero_explicit(arg1, size_of(arg1^)) } fe_clear_vec :: proc "contextless" ( diff --git a/core/crypto/_fiat/field_p256r1/field.odin b/core/crypto/_fiat/field_p256r1/field.odin new file mode 100644 index 000000000..f7dd978aa --- /dev/null +++ b/core/crypto/_fiat/field_p256r1/field.odin @@ -0,0 +1,345 @@ +package field_p256r1 + +import "core:crypto" +import subtle "core:crypto/_subtle" +import "core:encoding/endian" +import "core:math/bits" + +fe_clear :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) { + crypto.zero_explicit(arg1, size_of(Montgomery_Domain_Field_Element)) +} + +fe_clear_vec :: proc "contextless" ( + arg1: []^Montgomery_Domain_Field_Element, +) { + for fe in arg1 { + fe_clear(fe) + } +} + +fe_from_bytes :: proc "contextless" ( + out1: ^Montgomery_Domain_Field_Element, + arg1: []byte, + unsafe_assume_canonical := false, +) -> bool { + ensure_contextless(len(arg1) == 32, "p256r1: invalid fe input buffer") + + // Note: We assume the input is in big-endian. + tmp := Non_Montgomery_Domain_Field_Element { + endian.unchecked_get_u64be(arg1[24:]), + endian.unchecked_get_u64be(arg1[16:]), + endian.unchecked_get_u64be(arg1[8:]), + endian.unchecked_get_u64be(arg1[0:]), + } + defer crypto.zero_explicit(&tmp, size_of(tmp)) + + // Check that tmp is in the the range [0, ELL). + if !unsafe_assume_canonical { + _, borrow := bits.sub_u64(ELL[0] - 1, tmp[0], 0) + _, borrow = bits.sub_u64(ELL[1], tmp[1], borrow) + _, borrow = bits.sub_u64(ELL[2], tmp[2], borrow) + _, borrow = bits.sub_u64(ELL[3], tmp[3], borrow) + if borrow != 0 { + return false + } + } + + fe_to_montgomery(out1, &tmp) + + return true +} + +fe_to_bytes :: proc "contextless" (out1: []byte, arg1: ^Montgomery_Domain_Field_Element) { + ensure_contextless(len(out1) == 32, "p256r1: invalid fe output buffer") + + tmp: Non_Montgomery_Domain_Field_Element = --- + fe_from_montgomery(&tmp, arg1) + + // Note: Likewise, output in big-endian. + endian.unchecked_put_u64be(out1[24:], tmp[0]) + endian.unchecked_put_u64be(out1[16:], tmp[1]) + endian.unchecked_put_u64be(out1[8:], tmp[2]) + endian.unchecked_put_u64be(out1[0:], tmp[3]) + + crypto.zero_explicit(&tmp, size_of(tmp)) +} + +@(require_results) +fe_equal :: proc "contextless" (arg1, arg2: ^Montgomery_Domain_Field_Element) -> int { + tmp: Montgomery_Domain_Field_Element = --- + fe_sub(&tmp, arg1, arg2) + + // This will only underflow if and only if (⟺) arg1 == arg2, and we return the borrow, + // which will be 1. + is_eq := subtle.u64_is_zero(fe_non_zero(&tmp)) + + fe_clear(&tmp) + + return int(is_eq) +} + +@(require_results) +fe_is_odd :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) -> int { + tmp: Non_Montgomery_Domain_Field_Element = --- + defer crypto.zero_explicit(&tmp, size_of(tmp)) + + fe_from_montgomery(&tmp, arg1) + return int(tmp[0] & 1) +} + +fe_pow2k :: proc "contextless" ( + out1: ^Montgomery_Domain_Field_Element, + arg1: ^Montgomery_Domain_Field_Element, + arg2: uint, +) { + // Special case: `arg1^(2 * 0) = 1`, though this should never happen. + if arg2 == 0 { + fe_one(out1) + return + } + + fe_square(out1, arg1) + for _ in 1 ..< arg2 { + fe_square(out1, out1) + } +} + +fe_inv :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) { + // Inversion computation is derived from the addition chain: + // + // _10 = 2*1 + // _11 = 1 + _10 + // _110 = 2*_11 + // _111 = 1 + _110 + // _111000 = _111 << 3 + // _111111 = _111 + _111000 + // x12 = _111111 << 6 + _111111 + // x15 = x12 << 3 + _111 + // x16 = 2*x15 + 1 + // x32 = x16 << 16 + x16 + // i53 = x32 << 15 + // x47 = x15 + i53 + // i263 = ((i53 << 17 + 1) << 143 + x47) << 47 + // return (x47 + i263) << 2 + // + // Operations: 255 squares 11 multiplies + // + // Generated by github.com/mmcloughlin/addchain v0.4.0. + + // Note: Need to stash `arg1` (`xx`) in the case that `out1`/`arg1` alias, + // as `arg1` is used after `out1` has been altered. + t0, t1, xx: Montgomery_Domain_Field_Element = ---, ---, arg1^ + + // Step 1: z = x^0x2 + fe_square(out1, arg1) + + // Step 2: z = x^0x3 + fe_mul(out1, &xx, out1) + + // Step 3: z = x^0x6 + fe_square(out1, out1) + + // Step 4: z = x^0x7 + fe_mul(out1, &xx, out1) + + // Step 7: t0 = x^0x38 + fe_pow2k(&t0, out1, 3) + + // Step 8: t0 = x^0x3f + fe_mul(&t0, out1, &t0) + + // Step 14: t1 = x^0xfc0 + fe_pow2k(&t1, &t0, 6) + + // Step 15: t0 = x^0xfff + fe_mul(&t0, &t0, &t1) + + // Step 18: t0 = x^0x7ff8 + fe_pow2k(&t0, &t0, 3) + + // Step 19: z = x^0x7fff + fe_mul(out1, out1, &t0) + + // Step 20: t0 = x^0xfffe + fe_square(&t0, out1) + + // Step 21: t0 = x^0xffff + fe_mul(&t0, &xx, &t0) + + // Step 37: t1 = x^0xffff0000 + fe_pow2k(&t1, &t0, 16) + + // Step 38: t0 = x^0xffffffff + fe_mul(&t0, &t0, &t1) + + // Step 53: t0 = x^0x7fffffff8000 + fe_pow2k(&t0, &t0, 15) + + // Step 54: z = x^0x7fffffffffff + fe_mul(out1, out1, &t0) + + // Step 71: t0 = x^0xffffffff00000000 + fe_pow2k(&t0, &t0, 17) + + // Step 72: t0 = x^0xffffffff00000001 + fe_mul(&t0, &xx, &t0) + + // Step 215: t0 = x^0x7fffffff80000000800000000000000000000000000000000000 + fe_pow2k(&t0, &t0, 143) + + // Step 216: t0 = x^0x7fffffff800000008000000000000000000000007fffffffffff + fe_mul(&t0, out1, &t0) + + // Step 263: t0 = x^0x3fffffffc00000004000000000000000000000003fffffffffff800000000000 + fe_pow2k(&t0, &t0, 47) + + // Step 264: z = x^0x3fffffffc00000004000000000000000000000003fffffffffffffffffffffff + fe_mul(out1, out1, &t0) + + // Step 266: z = x^0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc + fe_pow2k(out1, out1, 2) + + fe_mul(out1, out1, &xx) + + fe_clear_vec([]^Montgomery_Domain_Field_Element{&t0, &t1, &xx}) +} + +@(require_results) +fe_sqrt :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) -> int { + // Square root candidate can be derived via exponentiation by `(p + 1) / 4` + // From sage: 28948022302589062190674361737351893382521535853822578548883407827216774463488 + // + // Inversion computation is derived from the addition chain: + // + // _10 = 2*1 + // _11 = 1 + _10 + // _1100 = _11 << 2 + // _1111 = _11 + _1100 + // _11110000 = _1111 << 4 + // _11111111 = _1111 + _11110000 + // x16 = _11111111 << 8 + _11111111 + // x32 = x16 << 16 + x16 + // return ((x32 << 32 + 1) << 96 + 1) << 94 + // + // Operations: 253 squares 7 multiplies + // + // Generated by github.com/mmcloughlin/addchain v0.4.0. + + // Likewise this tramples over arg1, so stash another copy. + t0, xx: Montgomery_Domain_Field_Element = ---, arg1^ + + // Step 1: z = x^0x2 + fe_square(out1, arg1) + + // Step 2: z = x^0x3 + fe_mul(out1, &xx, out1) + + // Step 4: t0 = x^0xc + fe_pow2k(&t0, &xx, 2) + + // Step 5: z = x^0xf + fe_mul(out1, out1, &t0) + + // Step 9: t0 = x^0xf0 + fe_pow2k(&t0, out1, 4) + + // Step 10: z = x^0xff + fe_mul(out1, out1, &t0) + + // Step 18: t0 = x^0xff00 + fe_pow2k(&t0, out1, 8) + + // Step 19: z = x^0xffff + fe_mul(out1, out1, &t0) + + // Step 35: t0 = x^0xffff0000 + fe_pow2k(&t0, out1, 16) + + // Step 36: z = x^0xffffffff + fe_mul(out1, out1, &t0) + + // Step 68: z = x^0xffffffff00000000 + fe_pow2k(out1, out1, 32) + + // Step 69: z = x^0xffffffff00000001 + fe_mul(out1, &xx, out1) + + // Step 165: z = x^0xffffffff00000001000000000000000000000000 + fe_pow2k(out1, out1, 96) + + // Step 166: z = x^0xffffffff00000001000000000000000000000001 + fe_mul(out1, &xx, out1) + + // Step 260: z = x^0x3fffffffc0000000400000000000000000000000400000000000000000000000 + fe_pow2k(out1, out1, 94) + + // Ensure that our candidate is actually the square root. + check, zero: Montgomery_Domain_Field_Element + fe_square(&check, out1) + + is_valid := fe_equal(&check, &xx) + fe_cond_select(out1, &zero, out1, is_valid) + + fe_clear_vec([]^Montgomery_Domain_Field_Element{&t0, &xx, &check}) + + return is_valid +} + +fe_zero :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element) { + out1[0] = 0 + out1[1] = 0 + out1[2] = 0 + out1[3] = 0 +} + +fe_set :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) { + x1 := arg1[0] + x2 := arg1[1] + x3 := arg1[2] + x4 := arg1[3] + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 +} + +@(optimization_mode = "none") +fe_cond_swap :: #force_no_inline proc "contextless" (out1, out2: ^Montgomery_Domain_Field_Element, arg1: int) { + mask := (u64(arg1) * 0xffffffffffffffff) + x := (out1[0] ~ out2[0]) & mask + x1, y1 := out1[0] ~ x, out2[0] ~ x + x = (out1[1] ~ out2[1]) & mask + x2, y2 := out1[1] ~ x, out2[1] ~ x + x = (out1[2] ~ out2[2]) & mask + x3, y3 := out1[2] ~ x, out2[2] ~ x + x = (out1[3] ~ out2[3]) & mask + x4, y4 := out1[3] ~ x, out2[3] ~ x + out1[0], out2[0] = x1, y1 + out1[1], out2[1] = x2, y2 + out1[2], out2[2] = x3, y3 + out1[3], out2[3] = x4, y4 +} + +@(optimization_mode = "none") +fe_cond_select :: #force_no_inline proc "contextless" ( + out1, arg1, arg2: ^Montgomery_Domain_Field_Element, + arg3: int, +) { + mask := (u64(arg3) * 0xffffffffffffffff) + x1 := ((mask & arg2[0]) | ((~mask) & arg1[0])) + x2 := ((mask & arg2[1]) | ((~mask) & arg1[1])) + x3 := ((mask & arg2[2]) | ((~mask) & arg1[2])) + x4 := ((mask & arg2[3]) | ((~mask) & arg1[3])) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 +} + +fe_cond_negate :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element, ctrl: int) { + tmp1: Montgomery_Domain_Field_Element = --- + fe_opp(&tmp1, arg1) + fe_cond_select(out1, arg1, &tmp1, ctrl) + + fe_clear(&tmp1) +} diff --git a/core/crypto/_fiat/field_p256r1/field64.odin b/core/crypto/_fiat/field_p256r1/field64.odin new file mode 100644 index 000000000..940f2cd07 --- /dev/null +++ b/core/crypto/_fiat/field_p256r1/field64.odin @@ -0,0 +1,501 @@ +// The BSD 1-Clause License (BSD-1-Clause) +// +// Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, +// Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package field_p256r1 + +// The file provides arithmetic on the field Z/(2^256 - 2^224 + 2^192 + 2^96 - 1) +// using a 64-bit Montgomery form internal representation. It is derived +// primarily from the machine generated Golang output from the fiat-crypto +// project. +// +// While the base implementation is provably correct, this implementation +// makes no such claims as the port and optimizations were done by hand. +// +// WARNING: While big-endian is the common representation used for this +// curve, the fiat output uses least-significant-limb first. + +import fiat "core:crypto/_fiat" +import "core:math/bits" + +// ELL is the saturated representation of the field order, least-significant +// limb first. +ELL :: [4]u64{0xffffffffffffffff, 0xffffffff, 0x0, 0xffffffff00000001} + +Montgomery_Domain_Field_Element :: distinct [4]u64 +Non_Montgomery_Domain_Field_Element :: distinct [4]u64 + +fe_mul :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + x6, x5 := bits.mul_u64(x4, arg2[3]) + x8, x7 := bits.mul_u64(x4, arg2[2]) + x10, x9 := bits.mul_u64(x4, arg2[1]) + x12, x11 := bits.mul_u64(x4, arg2[0]) + x13, x14 := bits.add_u64(x12, x9, u64(0x0)) + x15, x16 := bits.add_u64(x10, x7, u64(fiat.u1(x14))) + x17, x18 := bits.add_u64(x8, x5, u64(fiat.u1(x16))) + x19 := (u64(fiat.u1(x18)) + x6) + x21, x20 := bits.mul_u64(x11, 0xffffffff00000001) + x23, x22 := bits.mul_u64(x11, 0xffffffff) + x25, x24 := bits.mul_u64(x11, 0xffffffffffffffff) + x26, x27 := bits.add_u64(x25, x22, u64(0x0)) + x28 := (u64(fiat.u1(x27)) + x23) + _, x30 := bits.add_u64(x11, x24, u64(0x0)) + x31, x32 := bits.add_u64(x13, x26, u64(fiat.u1(x30))) + x33, x34 := bits.add_u64(x15, x28, u64(fiat.u1(x32))) + x35, x36 := bits.add_u64(x17, x20, u64(fiat.u1(x34))) + x37, x38 := bits.add_u64(x19, x21, u64(fiat.u1(x36))) + x40, x39 := bits.mul_u64(x1, arg2[3]) + x42, x41 := bits.mul_u64(x1, arg2[2]) + x44, x43 := bits.mul_u64(x1, arg2[1]) + x46, x45 := bits.mul_u64(x1, arg2[0]) + x47, x48 := bits.add_u64(x46, x43, u64(0x0)) + x49, x50 := bits.add_u64(x44, x41, u64(fiat.u1(x48))) + x51, x52 := bits.add_u64(x42, x39, u64(fiat.u1(x50))) + x53 := (u64(fiat.u1(x52)) + x40) + x54, x55 := bits.add_u64(x31, x45, u64(0x0)) + x56, x57 := bits.add_u64(x33, x47, u64(fiat.u1(x55))) + x58, x59 := bits.add_u64(x35, x49, u64(fiat.u1(x57))) + x60, x61 := bits.add_u64(x37, x51, u64(fiat.u1(x59))) + x62, x63 := bits.add_u64(u64(fiat.u1(x38)), x53, u64(fiat.u1(x61))) + x65, x64 := bits.mul_u64(x54, 0xffffffff00000001) + x67, x66 := bits.mul_u64(x54, 0xffffffff) + x69, x68 := bits.mul_u64(x54, 0xffffffffffffffff) + x70, x71 := bits.add_u64(x69, x66, u64(0x0)) + x72 := (u64(fiat.u1(x71)) + x67) + _, x74 := bits.add_u64(x54, x68, u64(0x0)) + x75, x76 := bits.add_u64(x56, x70, u64(fiat.u1(x74))) + x77, x78 := bits.add_u64(x58, x72, u64(fiat.u1(x76))) + x79, x80 := bits.add_u64(x60, x64, u64(fiat.u1(x78))) + x81, x82 := bits.add_u64(x62, x65, u64(fiat.u1(x80))) + x83 := (u64(fiat.u1(x82)) + u64(fiat.u1(x63))) + x85, x84 := bits.mul_u64(x2, arg2[3]) + x87, x86 := bits.mul_u64(x2, arg2[2]) + x89, x88 := bits.mul_u64(x2, arg2[1]) + x91, x90 := bits.mul_u64(x2, arg2[0]) + x92, x93 := bits.add_u64(x91, x88, u64(0x0)) + x94, x95 := bits.add_u64(x89, x86, u64(fiat.u1(x93))) + x96, x97 := bits.add_u64(x87, x84, u64(fiat.u1(x95))) + x98 := (u64(fiat.u1(x97)) + x85) + x99, x100 := bits.add_u64(x75, x90, u64(0x0)) + x101, x102 := bits.add_u64(x77, x92, u64(fiat.u1(x100))) + x103, x104 := bits.add_u64(x79, x94, u64(fiat.u1(x102))) + x105, x106 := bits.add_u64(x81, x96, u64(fiat.u1(x104))) + x107, x108 := bits.add_u64(x83, x98, u64(fiat.u1(x106))) + x110, x109 := bits.mul_u64(x99, 0xffffffff00000001) + x112, x111 := bits.mul_u64(x99, 0xffffffff) + x114, x113 := bits.mul_u64(x99, 0xffffffffffffffff) + x115, x116 := bits.add_u64(x114, x111, u64(0x0)) + x117 := (u64(fiat.u1(x116)) + x112) + _, x119 := bits.add_u64(x99, x113, u64(0x0)) + x120, x121 := bits.add_u64(x101, x115, u64(fiat.u1(x119))) + x122, x123 := bits.add_u64(x103, x117, u64(fiat.u1(x121))) + x124, x125 := bits.add_u64(x105, x109, u64(fiat.u1(x123))) + x126, x127 := bits.add_u64(x107, x110, u64(fiat.u1(x125))) + x128 := (u64(fiat.u1(x127)) + u64(fiat.u1(x108))) + x130, x129 := bits.mul_u64(x3, arg2[3]) + x132, x131 := bits.mul_u64(x3, arg2[2]) + x134, x133 := bits.mul_u64(x3, arg2[1]) + x136, x135 := bits.mul_u64(x3, arg2[0]) + x137, x138 := bits.add_u64(x136, x133, u64(0x0)) + x139, x140 := bits.add_u64(x134, x131, u64(fiat.u1(x138))) + x141, x142 := bits.add_u64(x132, x129, u64(fiat.u1(x140))) + x143 := (u64(fiat.u1(x142)) + x130) + x144, x145 := bits.add_u64(x120, x135, u64(0x0)) + x146, x147 := bits.add_u64(x122, x137, u64(fiat.u1(x145))) + x148, x149 := bits.add_u64(x124, x139, u64(fiat.u1(x147))) + x150, x151 := bits.add_u64(x126, x141, u64(fiat.u1(x149))) + x152, x153 := bits.add_u64(x128, x143, u64(fiat.u1(x151))) + x155, x154 := bits.mul_u64(x144, 0xffffffff00000001) + x157, x156 := bits.mul_u64(x144, 0xffffffff) + x159, x158 := bits.mul_u64(x144, 0xffffffffffffffff) + x160, x161 := bits.add_u64(x159, x156, u64(0x0)) + x162 := (u64(fiat.u1(x161)) + x157) + _, x164 := bits.add_u64(x144, x158, u64(0x0)) + x165, x166 := bits.add_u64(x146, x160, u64(fiat.u1(x164))) + x167, x168 := bits.add_u64(x148, x162, u64(fiat.u1(x166))) + x169, x170 := bits.add_u64(x150, x154, u64(fiat.u1(x168))) + x171, x172 := bits.add_u64(x152, x155, u64(fiat.u1(x170))) + x173 := (u64(fiat.u1(x172)) + u64(fiat.u1(x153))) + x174, x175 := bits.sub_u64(x165, 0xffffffffffffffff, u64(0x0)) + x176, x177 := bits.sub_u64(x167, 0xffffffff, u64(fiat.u1(x175))) + x178, x179 := bits.sub_u64(x169, u64(0x0), u64(fiat.u1(x177))) + x180, x181 := bits.sub_u64(x171, 0xffffffff00000001, u64(fiat.u1(x179))) + _, x183 := bits.sub_u64(x173, u64(0x0), u64(fiat.u1(x181))) + x184 := fiat.cmovznz_u64(fiat.u1(x183), x174, x165) + x185 := fiat.cmovznz_u64(fiat.u1(x183), x176, x167) + x186 := fiat.cmovznz_u64(fiat.u1(x183), x178, x169) + x187 := fiat.cmovznz_u64(fiat.u1(x183), x180, x171) + out1[0] = x184 + out1[1] = x185 + out1[2] = x186 + out1[3] = x187 +} + +fe_square :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + x6, x5 := bits.mul_u64(x4, arg1[3]) + x8, x7 := bits.mul_u64(x4, arg1[2]) + x10, x9 := bits.mul_u64(x4, arg1[1]) + x12, x11 := bits.mul_u64(x4, arg1[0]) + x13, x14 := bits.add_u64(x12, x9, u64(0x0)) + x15, x16 := bits.add_u64(x10, x7, u64(fiat.u1(x14))) + x17, x18 := bits.add_u64(x8, x5, u64(fiat.u1(x16))) + x19 := (u64(fiat.u1(x18)) + x6) + x21, x20 := bits.mul_u64(x11, 0xffffffff00000001) + x23, x22 := bits.mul_u64(x11, 0xffffffff) + x25, x24 := bits.mul_u64(x11, 0xffffffffffffffff) + x26, x27 := bits.add_u64(x25, x22, u64(0x0)) + x28 := (u64(fiat.u1(x27)) + x23) + _, x30 := bits.add_u64(x11, x24, u64(0x0)) + x31, x32 := bits.add_u64(x13, x26, u64(fiat.u1(x30))) + x33, x34 := bits.add_u64(x15, x28, u64(fiat.u1(x32))) + x35, x36 := bits.add_u64(x17, x20, u64(fiat.u1(x34))) + x37, x38 := bits.add_u64(x19, x21, u64(fiat.u1(x36))) + x40, x39 := bits.mul_u64(x1, arg1[3]) + x42, x41 := bits.mul_u64(x1, arg1[2]) + x44, x43 := bits.mul_u64(x1, arg1[1]) + x46, x45 := bits.mul_u64(x1, arg1[0]) + x47, x48 := bits.add_u64(x46, x43, u64(0x0)) + x49, x50 := bits.add_u64(x44, x41, u64(fiat.u1(x48))) + x51, x52 := bits.add_u64(x42, x39, u64(fiat.u1(x50))) + x53 := (u64(fiat.u1(x52)) + x40) + x54, x55 := bits.add_u64(x31, x45, u64(0x0)) + x56, x57 := bits.add_u64(x33, x47, u64(fiat.u1(x55))) + x58, x59 := bits.add_u64(x35, x49, u64(fiat.u1(x57))) + x60, x61 := bits.add_u64(x37, x51, u64(fiat.u1(x59))) + x62, x63 := bits.add_u64(u64(fiat.u1(x38)), x53, u64(fiat.u1(x61))) + x65, x64 := bits.mul_u64(x54, 0xffffffff00000001) + x67, x66 := bits.mul_u64(x54, 0xffffffff) + x69, x68 := bits.mul_u64(x54, 0xffffffffffffffff) + x70, x71 := bits.add_u64(x69, x66, u64(0x0)) + x72 := (u64(fiat.u1(x71)) + x67) + _, x74 := bits.add_u64(x54, x68, u64(0x0)) + x75, x76 := bits.add_u64(x56, x70, u64(fiat.u1(x74))) + x77, x78 := bits.add_u64(x58, x72, u64(fiat.u1(x76))) + x79, x80 := bits.add_u64(x60, x64, u64(fiat.u1(x78))) + x81, x82 := bits.add_u64(x62, x65, u64(fiat.u1(x80))) + x83 := (u64(fiat.u1(x82)) + u64(fiat.u1(x63))) + x85, x84 := bits.mul_u64(x2, arg1[3]) + x87, x86 := bits.mul_u64(x2, arg1[2]) + x89, x88 := bits.mul_u64(x2, arg1[1]) + x91, x90 := bits.mul_u64(x2, arg1[0]) + x92, x93 := bits.add_u64(x91, x88, u64(0x0)) + x94, x95 := bits.add_u64(x89, x86, u64(fiat.u1(x93))) + x96, x97 := bits.add_u64(x87, x84, u64(fiat.u1(x95))) + x98 := (u64(fiat.u1(x97)) + x85) + x99, x100 := bits.add_u64(x75, x90, u64(0x0)) + x101, x102 := bits.add_u64(x77, x92, u64(fiat.u1(x100))) + x103, x104 := bits.add_u64(x79, x94, u64(fiat.u1(x102))) + x105, x106 := bits.add_u64(x81, x96, u64(fiat.u1(x104))) + x107, x108 := bits.add_u64(x83, x98, u64(fiat.u1(x106))) + x110, x109 := bits.mul_u64(x99, 0xffffffff00000001) + x112, x111 := bits.mul_u64(x99, 0xffffffff) + x114, x113 := bits.mul_u64(x99, 0xffffffffffffffff) + x115, x116 := bits.add_u64(x114, x111, u64(0x0)) + x117 := (u64(fiat.u1(x116)) + x112) + _, x119 := bits.add_u64(x99, x113, u64(0x0)) + x120, x121 := bits.add_u64(x101, x115, u64(fiat.u1(x119))) + x122, x123 := bits.add_u64(x103, x117, u64(fiat.u1(x121))) + x124, x125 := bits.add_u64(x105, x109, u64(fiat.u1(x123))) + x126, x127 := bits.add_u64(x107, x110, u64(fiat.u1(x125))) + x128 := (u64(fiat.u1(x127)) + u64(fiat.u1(x108))) + x130, x129 := bits.mul_u64(x3, arg1[3]) + x132, x131 := bits.mul_u64(x3, arg1[2]) + x134, x133 := bits.mul_u64(x3, arg1[1]) + x136, x135 := bits.mul_u64(x3, arg1[0]) + x137, x138 := bits.add_u64(x136, x133, u64(0x0)) + x139, x140 := bits.add_u64(x134, x131, u64(fiat.u1(x138))) + x141, x142 := bits.add_u64(x132, x129, u64(fiat.u1(x140))) + x143 := (u64(fiat.u1(x142)) + x130) + x144, x145 := bits.add_u64(x120, x135, u64(0x0)) + x146, x147 := bits.add_u64(x122, x137, u64(fiat.u1(x145))) + x148, x149 := bits.add_u64(x124, x139, u64(fiat.u1(x147))) + x150, x151 := bits.add_u64(x126, x141, u64(fiat.u1(x149))) + x152, x153 := bits.add_u64(x128, x143, u64(fiat.u1(x151))) + x155, x154 := bits.mul_u64(x144, 0xffffffff00000001) + x157, x156 := bits.mul_u64(x144, 0xffffffff) + x159, x158 := bits.mul_u64(x144, 0xffffffffffffffff) + x160, x161 := bits.add_u64(x159, x156, u64(0x0)) + x162 := (u64(fiat.u1(x161)) + x157) + _, x164 := bits.add_u64(x144, x158, u64(0x0)) + x165, x166 := bits.add_u64(x146, x160, u64(fiat.u1(x164))) + x167, x168 := bits.add_u64(x148, x162, u64(fiat.u1(x166))) + x169, x170 := bits.add_u64(x150, x154, u64(fiat.u1(x168))) + x171, x172 := bits.add_u64(x152, x155, u64(fiat.u1(x170))) + x173 := (u64(fiat.u1(x172)) + u64(fiat.u1(x153))) + x174, x175 := bits.sub_u64(x165, 0xffffffffffffffff, u64(0x0)) + x176, x177 := bits.sub_u64(x167, 0xffffffff, u64(fiat.u1(x175))) + x178, x179 := bits.sub_u64(x169, u64(0x0), u64(fiat.u1(x177))) + x180, x181 := bits.sub_u64(x171, 0xffffffff00000001, u64(fiat.u1(x179))) + _, x183 := bits.sub_u64(x173, u64(0x0), u64(fiat.u1(x181))) + x184 := fiat.cmovznz_u64(fiat.u1(x183), x174, x165) + x185 := fiat.cmovznz_u64(fiat.u1(x183), x176, x167) + x186 := fiat.cmovznz_u64(fiat.u1(x183), x178, x169) + x187 := fiat.cmovznz_u64(fiat.u1(x183), x180, x171) + out1[0] = x184 + out1[1] = x185 + out1[2] = x186 + out1[3] = x187 +} + +fe_add :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) { + x1, x2 := bits.add_u64(arg1[0], arg2[0], u64(0x0)) + x3, x4 := bits.add_u64(arg1[1], arg2[1], u64(fiat.u1(x2))) + x5, x6 := bits.add_u64(arg1[2], arg2[2], u64(fiat.u1(x4))) + x7, x8 := bits.add_u64(arg1[3], arg2[3], u64(fiat.u1(x6))) + x9, x10 := bits.sub_u64(x1, 0xffffffffffffffff, u64(0x0)) + x11, x12 := bits.sub_u64(x3, 0xffffffff, u64(fiat.u1(x10))) + x13, x14 := bits.sub_u64(x5, u64(0x0), u64(fiat.u1(x12))) + x15, x16 := bits.sub_u64(x7, 0xffffffff00000001, u64(fiat.u1(x14))) + _, x18 := bits.sub_u64(u64(fiat.u1(x8)), u64(0x0), u64(fiat.u1(x16))) + x19 := fiat.cmovznz_u64(fiat.u1(x18), x9, x1) + x20 := fiat.cmovznz_u64(fiat.u1(x18), x11, x3) + x21 := fiat.cmovznz_u64(fiat.u1(x18), x13, x5) + x22 := fiat.cmovznz_u64(fiat.u1(x18), x15, x7) + out1[0] = x19 + out1[1] = x20 + out1[2] = x21 + out1[3] = x22 +} + +fe_sub :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) { + x1, x2 := bits.sub_u64(arg1[0], arg2[0], u64(0x0)) + x3, x4 := bits.sub_u64(arg1[1], arg2[1], u64(fiat.u1(x2))) + x5, x6 := bits.sub_u64(arg1[2], arg2[2], u64(fiat.u1(x4))) + x7, x8 := bits.sub_u64(arg1[3], arg2[3], u64(fiat.u1(x6))) + x9 := fiat.cmovznz_u64(fiat.u1(x8), u64(0x0), 0xffffffffffffffff) + x10, x11 := bits.add_u64(x1, x9, u64(0x0)) + x12, x13 := bits.add_u64(x3, (x9 & 0xffffffff), u64(fiat.u1(x11))) + x14, x15 := bits.add_u64(x5, u64(0x0), u64(fiat.u1(x13))) + x16, _ := bits.add_u64(x7, (x9 & 0xffffffff00000001), u64(fiat.u1(x15))) + out1[0] = x10 + out1[1] = x12 + out1[2] = x14 + out1[3] = x16 +} + +fe_opp :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) { + x1, x2 := bits.sub_u64(u64(0x0), arg1[0], u64(0x0)) + x3, x4 := bits.sub_u64(u64(0x0), arg1[1], u64(fiat.u1(x2))) + x5, x6 := bits.sub_u64(u64(0x0), arg1[2], u64(fiat.u1(x4))) + x7, x8 := bits.sub_u64(u64(0x0), arg1[3], u64(fiat.u1(x6))) + x9 := fiat.cmovznz_u64(fiat.u1(x8), u64(0x0), 0xffffffffffffffff) + x10, x11 := bits.add_u64(x1, x9, u64(0x0)) + x12, x13 := bits.add_u64(x3, (x9 & 0xffffffff), u64(fiat.u1(x11))) + x14, x15 := bits.add_u64(x5, u64(0x0), u64(fiat.u1(x13))) + x16, _ := bits.add_u64(x7, (x9 & 0xffffffff00000001), u64(fiat.u1(x15))) + out1[0] = x10 + out1[1] = x12 + out1[2] = x14 + out1[3] = x16 +} + +fe_one :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element) { + out1[0] = 0x1 + out1[1] = 0xffffffff00000000 + out1[2] = 0xffffffffffffffff + out1[3] = 0xfffffffe +} + +fe_non_zero :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) -> u64 { + return arg1[0] | (arg1[1] | (arg1[2] | arg1[3])) +} + +@(optimization_mode = "none") +fe_cond_assign :: #force_no_inline proc "contextless" ( + out1, arg1: ^Montgomery_Domain_Field_Element, + arg2: int, +) { + x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0]) + x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1]) + x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2]) + x4 := fiat.cmovznz_u64(fiat.u1(arg2), out1[3], arg1[3]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 +} + +fe_from_montgomery :: proc "contextless" ( + out1: ^Non_Montgomery_Domain_Field_Element, + arg1: ^Montgomery_Domain_Field_Element, +) { + x1 := arg1[0] + x3, x2 := bits.mul_u64(x1, 0xffffffff00000001) + x5, x4 := bits.mul_u64(x1, 0xffffffff) + x7, x6 := bits.mul_u64(x1, 0xffffffffffffffff) + x8, x9 := bits.add_u64(x7, x4, u64(0x0)) + _, x11 := bits.add_u64(x1, x6, u64(0x0)) + x12, x13 := bits.add_u64(u64(0x0), x8, u64(fiat.u1(x11))) + x14, x15 := bits.add_u64(x12, arg1[1], u64(0x0)) + x17, x16 := bits.mul_u64(x14, 0xffffffff00000001) + x19, x18 := bits.mul_u64(x14, 0xffffffff) + x21, x20 := bits.mul_u64(x14, 0xffffffffffffffff) + x22, x23 := bits.add_u64(x21, x18, u64(0x0)) + _, x25 := bits.add_u64(x14, x20, u64(0x0)) + x26, x27 := bits.add_u64((u64(fiat.u1(x15)) + (u64(fiat.u1(x13)) + (u64(fiat.u1(x9)) + x5))), x22, u64(fiat.u1(x25))) + x28, x29 := bits.add_u64(x2, (u64(fiat.u1(x23)) + x19), u64(fiat.u1(x27))) + x30, x31 := bits.add_u64(x3, x16, u64(fiat.u1(x29))) + x32, x33 := bits.add_u64(x26, arg1[2], u64(0x0)) + x34, x35 := bits.add_u64(x28, u64(0x0), u64(fiat.u1(x33))) + x36, x37 := bits.add_u64(x30, u64(0x0), u64(fiat.u1(x35))) + x39, x38 := bits.mul_u64(x32, 0xffffffff00000001) + x41, x40 := bits.mul_u64(x32, 0xffffffff) + x43, x42 := bits.mul_u64(x32, 0xffffffffffffffff) + x44, x45 := bits.add_u64(x43, x40, u64(0x0)) + _, x47 := bits.add_u64(x32, x42, u64(0x0)) + x48, x49 := bits.add_u64(x34, x44, u64(fiat.u1(x47))) + x50, x51 := bits.add_u64(x36, (u64(fiat.u1(x45)) + x41), u64(fiat.u1(x49))) + x52, x53 := bits.add_u64((u64(fiat.u1(x37)) + (u64(fiat.u1(x31)) + x17)), x38, u64(fiat.u1(x51))) + x54, x55 := bits.add_u64(x48, arg1[3], u64(0x0)) + x56, x57 := bits.add_u64(x50, u64(0x0), u64(fiat.u1(x55))) + x58, x59 := bits.add_u64(x52, u64(0x0), u64(fiat.u1(x57))) + x61, x60 := bits.mul_u64(x54, 0xffffffff00000001) + x63, x62 := bits.mul_u64(x54, 0xffffffff) + x65, x64 := bits.mul_u64(x54, 0xffffffffffffffff) + x66, x67 := bits.add_u64(x65, x62, u64(0x0)) + _, x69 := bits.add_u64(x54, x64, u64(0x0)) + x70, x71 := bits.add_u64(x56, x66, u64(fiat.u1(x69))) + x72, x73 := bits.add_u64(x58, (u64(fiat.u1(x67)) + x63), u64(fiat.u1(x71))) + x74, x75 := bits.add_u64((u64(fiat.u1(x59)) + (u64(fiat.u1(x53)) + x39)), x60, u64(fiat.u1(x73))) + x76 := (u64(fiat.u1(x75)) + x61) + x77, x78 := bits.sub_u64(x70, 0xffffffffffffffff, u64(0x0)) + x79, x80 := bits.sub_u64(x72, 0xffffffff, u64(fiat.u1(x78))) + x81, x82 := bits.sub_u64(x74, u64(0x0), u64(fiat.u1(x80))) + x83, x84 := bits.sub_u64(x76, 0xffffffff00000001, u64(fiat.u1(x82))) + _, x86 := bits.sub_u64(u64(0x0), u64(0x0), u64(fiat.u1(x84))) + x87 := fiat.cmovznz_u64(fiat.u1(x86), x77, x70) + x88 := fiat.cmovznz_u64(fiat.u1(x86), x79, x72) + x89 := fiat.cmovznz_u64(fiat.u1(x86), x81, x74) + x90 := fiat.cmovznz_u64(fiat.u1(x86), x83, x76) + out1[0] = x87 + out1[1] = x88 + out1[2] = x89 + out1[3] = x90 +} + +fe_to_montgomery :: proc "contextless" ( + out1: ^Montgomery_Domain_Field_Element, + arg1: ^Non_Montgomery_Domain_Field_Element, +) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + x6, x5 := bits.mul_u64(x4, 0x4fffffffd) + x8, x7 := bits.mul_u64(x4, 0xfffffffffffffffe) + x10, x9 := bits.mul_u64(x4, 0xfffffffbffffffff) + x12, x11 := bits.mul_u64(x4, 0x3) + x13, x14 := bits.add_u64(x12, x9, u64(0x0)) + x15, x16 := bits.add_u64(x10, x7, u64(fiat.u1(x14))) + x17, x18 := bits.add_u64(x8, x5, u64(fiat.u1(x16))) + x20, x19 := bits.mul_u64(x11, 0xffffffff00000001) + x22, x21 := bits.mul_u64(x11, 0xffffffff) + x24, x23 := bits.mul_u64(x11, 0xffffffffffffffff) + x25, x26 := bits.add_u64(x24, x21, u64(0x0)) + _, x28 := bits.add_u64(x11, x23, u64(0x0)) + x29, x30 := bits.add_u64(x13, x25, u64(fiat.u1(x28))) + x31, x32 := bits.add_u64(x15, (u64(fiat.u1(x26)) + x22), u64(fiat.u1(x30))) + x33, x34 := bits.add_u64(x17, x19, u64(fiat.u1(x32))) + x35, x36 := bits.add_u64((u64(fiat.u1(x18)) + x6), x20, u64(fiat.u1(x34))) + x38, x37 := bits.mul_u64(x1, 0x4fffffffd) + x40, x39 := bits.mul_u64(x1, 0xfffffffffffffffe) + x42, x41 := bits.mul_u64(x1, 0xfffffffbffffffff) + x44, x43 := bits.mul_u64(x1, 0x3) + x45, x46 := bits.add_u64(x44, x41, u64(0x0)) + x47, x48 := bits.add_u64(x42, x39, u64(fiat.u1(x46))) + x49, x50 := bits.add_u64(x40, x37, u64(fiat.u1(x48))) + x51, x52 := bits.add_u64(x29, x43, u64(0x0)) + x53, x54 := bits.add_u64(x31, x45, u64(fiat.u1(x52))) + x55, x56 := bits.add_u64(x33, x47, u64(fiat.u1(x54))) + x57, x58 := bits.add_u64(x35, x49, u64(fiat.u1(x56))) + x60, x59 := bits.mul_u64(x51, 0xffffffff00000001) + x62, x61 := bits.mul_u64(x51, 0xffffffff) + x64, x63 := bits.mul_u64(x51, 0xffffffffffffffff) + x65, x66 := bits.add_u64(x64, x61, u64(0x0)) + _, x68 := bits.add_u64(x51, x63, u64(0x0)) + x69, x70 := bits.add_u64(x53, x65, u64(fiat.u1(x68))) + x71, x72 := bits.add_u64(x55, (u64(fiat.u1(x66)) + x62), u64(fiat.u1(x70))) + x73, x74 := bits.add_u64(x57, x59, u64(fiat.u1(x72))) + x75, x76 := bits.add_u64(((u64(fiat.u1(x58)) + u64(fiat.u1(x36))) + (u64(fiat.u1(x50)) + x38)), x60, u64(fiat.u1(x74))) + x78, x77 := bits.mul_u64(x2, 0x4fffffffd) + x80, x79 := bits.mul_u64(x2, 0xfffffffffffffffe) + x82, x81 := bits.mul_u64(x2, 0xfffffffbffffffff) + x84, x83 := bits.mul_u64(x2, 0x3) + x85, x86 := bits.add_u64(x84, x81, u64(0x0)) + x87, x88 := bits.add_u64(x82, x79, u64(fiat.u1(x86))) + x89, x90 := bits.add_u64(x80, x77, u64(fiat.u1(x88))) + x91, x92 := bits.add_u64(x69, x83, u64(0x0)) + x93, x94 := bits.add_u64(x71, x85, u64(fiat.u1(x92))) + x95, x96 := bits.add_u64(x73, x87, u64(fiat.u1(x94))) + x97, x98 := bits.add_u64(x75, x89, u64(fiat.u1(x96))) + x100, x99 := bits.mul_u64(x91, 0xffffffff00000001) + x102, x101 := bits.mul_u64(x91, 0xffffffff) + x104, x103 := bits.mul_u64(x91, 0xffffffffffffffff) + x105, x106 := bits.add_u64(x104, x101, u64(0x0)) + _, x108 := bits.add_u64(x91, x103, u64(0x0)) + x109, x110 := bits.add_u64(x93, x105, u64(fiat.u1(x108))) + x111, x112 := bits.add_u64(x95, (u64(fiat.u1(x106)) + x102), u64(fiat.u1(x110))) + x113, x114 := bits.add_u64(x97, x99, u64(fiat.u1(x112))) + x115, x116 := bits.add_u64(((u64(fiat.u1(x98)) + u64(fiat.u1(x76))) + (u64(fiat.u1(x90)) + x78)), x100, u64(fiat.u1(x114))) + x118, x117 := bits.mul_u64(x3, 0x4fffffffd) + x120, x119 := bits.mul_u64(x3, 0xfffffffffffffffe) + x122, x121 := bits.mul_u64(x3, 0xfffffffbffffffff) + x124, x123 := bits.mul_u64(x3, 0x3) + x125, x126 := bits.add_u64(x124, x121, u64(0x0)) + x127, x128 := bits.add_u64(x122, x119, u64(fiat.u1(x126))) + x129, x130 := bits.add_u64(x120, x117, u64(fiat.u1(x128))) + x131, x132 := bits.add_u64(x109, x123, u64(0x0)) + x133, x134 := bits.add_u64(x111, x125, u64(fiat.u1(x132))) + x135, x136 := bits.add_u64(x113, x127, u64(fiat.u1(x134))) + x137, x138 := bits.add_u64(x115, x129, u64(fiat.u1(x136))) + x140, x139 := bits.mul_u64(x131, 0xffffffff00000001) + x142, x141 := bits.mul_u64(x131, 0xffffffff) + x144, x143 := bits.mul_u64(x131, 0xffffffffffffffff) + x145, x146 := bits.add_u64(x144, x141, u64(0x0)) + _, x148 := bits.add_u64(x131, x143, u64(0x0)) + x149, x150 := bits.add_u64(x133, x145, u64(fiat.u1(x148))) + x151, x152 := bits.add_u64(x135, (u64(fiat.u1(x146)) + x142), u64(fiat.u1(x150))) + x153, x154 := bits.add_u64(x137, x139, u64(fiat.u1(x152))) + x155, x156 := bits.add_u64(((u64(fiat.u1(x138)) + u64(fiat.u1(x116))) + (u64(fiat.u1(x130)) + x118)), x140, u64(fiat.u1(x154))) + x157, x158 := bits.sub_u64(x149, 0xffffffffffffffff, u64(0x0)) + x159, x160 := bits.sub_u64(x151, 0xffffffff, u64(fiat.u1(x158))) + x161, x162 := bits.sub_u64(x153, u64(0x0), u64(fiat.u1(x160))) + x163, x164 := bits.sub_u64(x155, 0xffffffff00000001, u64(fiat.u1(x162))) + _, x166 := bits.sub_u64(u64(fiat.u1(x156)), u64(0x0), u64(fiat.u1(x164))) + x167 := fiat.cmovznz_u64(fiat.u1(x166), x157, x149) + x168 := fiat.cmovznz_u64(fiat.u1(x166), x159, x151) + x169 := fiat.cmovznz_u64(fiat.u1(x166), x161, x153) + x170 := fiat.cmovznz_u64(fiat.u1(x166), x163, x155) + out1[0] = x167 + out1[1] = x168 + out1[2] = x169 + out1[3] = x170 +} diff --git a/core/crypto/_fiat/field_p384r1/field.odin b/core/crypto/_fiat/field_p384r1/field.odin new file mode 100644 index 000000000..2bddff18c --- /dev/null +++ b/core/crypto/_fiat/field_p384r1/field.odin @@ -0,0 +1,436 @@ +package field_p384r1 + +import "core:crypto" +import subtle "core:crypto/_subtle" +import "core:encoding/endian" +import "core:math/bits" + +fe_clear :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) { + crypto.zero_explicit(arg1, size_of(Montgomery_Domain_Field_Element)) +} + +fe_clear_vec :: proc "contextless" ( + arg1: []^Montgomery_Domain_Field_Element, +) { + for fe in arg1 { + fe_clear(fe) + } +} + +fe_from_bytes :: proc "contextless" ( + out1: ^Montgomery_Domain_Field_Element, + arg1: []byte, + unsafe_assume_canonical := false, +) -> bool { + ensure_contextless(len(arg1) == 48, "p384r1: invalid fe input buffer") + + // Note: We assume the input is in big-endian. + tmp := Non_Montgomery_Domain_Field_Element { + endian.unchecked_get_u64be(arg1[40:]), + endian.unchecked_get_u64be(arg1[32:]), + endian.unchecked_get_u64be(arg1[24:]), + endian.unchecked_get_u64be(arg1[16:]), + endian.unchecked_get_u64be(arg1[8:]), + endian.unchecked_get_u64be(arg1[0:]), + } + defer crypto.zero_explicit(&tmp, size_of(tmp)) + + // Check that tmp is in the the range [0, ELL). + if !unsafe_assume_canonical { + _, borrow := bits.sub_u64(ELL[0] - 1, tmp[0], 0) + _, borrow = bits.sub_u64(ELL[1], tmp[1], borrow) + _, borrow = bits.sub_u64(ELL[2], tmp[2], borrow) + _, borrow = bits.sub_u64(ELL[3], tmp[3], borrow) + _, borrow = bits.sub_u64(ELL[4], tmp[4], borrow) + _, borrow = bits.sub_u64(ELL[5], tmp[5], borrow) + if borrow != 0 { + return false + } + } + + fe_to_montgomery(out1, &tmp) + + return true +} + +fe_to_bytes :: proc "contextless" (out1: []byte, arg1: ^Montgomery_Domain_Field_Element) { + ensure_contextless(len(out1) == 48, "p384r1: invalid fe output buffer") + + tmp: Non_Montgomery_Domain_Field_Element = --- + fe_from_montgomery(&tmp, arg1) + + // Note: Likewise, output in big-endian. + endian.unchecked_put_u64be(out1[40:], tmp[0]) + endian.unchecked_put_u64be(out1[32:], tmp[1]) + endian.unchecked_put_u64be(out1[24:], tmp[2]) + endian.unchecked_put_u64be(out1[16:], tmp[3]) + endian.unchecked_put_u64be(out1[8:], tmp[4]) + endian.unchecked_put_u64be(out1[0:], tmp[5]) + + crypto.zero_explicit(&tmp, size_of(tmp)) +} + +@(require_results) +fe_equal :: proc "contextless" (arg1, arg2: ^Montgomery_Domain_Field_Element) -> int { + tmp: Montgomery_Domain_Field_Element = --- + fe_sub(&tmp, arg1, arg2) + + // This will only underflow if and only if (⟺) arg1 == arg2, and we return the borrow, + // which will be 1. + is_eq := subtle.u64_is_zero(fe_non_zero(&tmp)) + + fe_clear(&tmp) + + return int(is_eq) +} + +@(require_results) +fe_is_odd :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) -> int { + tmp: Non_Montgomery_Domain_Field_Element = --- + defer crypto.zero_explicit(&tmp, size_of(tmp)) + + fe_from_montgomery(&tmp, arg1) + return int(tmp[0] & 1) +} + +fe_pow2k :: proc "contextless" ( + out1: ^Montgomery_Domain_Field_Element, + arg1: ^Montgomery_Domain_Field_Element, + arg2: uint, +) { + // Special case: `arg1^(2 * 0) = 1`, though this should never happen. + if arg2 == 0 { + fe_one(out1) + return + } + + fe_square(out1, arg1) + for _ in 1 ..< arg2 { + fe_square(out1, out1) + } +} + +fe_inv :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) { + // Inversion computation is derived from the addition chain: + // + // _10 = 2*1 + // _11 = 1 + _10 + // _110 = 2*_11 + // _111 = 1 + _110 + // _111000 = _111 << 3 + // _111111 = _111 + _111000 + // x12 = _111111 << 6 + _111111 + // x24 = x12 << 12 + x12 + // x30 = x24 << 6 + _111111 + // x31 = 2*x30 + 1 + // x32 = 2*x31 + 1 + // x63 = x32 << 31 + x31 + // x126 = x63 << 63 + x63 + // x252 = x126 << 126 + x126 + // x255 = x252 << 3 + _111 + // return ((x255 << 33 + x32) << 94 + x30) << 2 + // + // Operations: 383 squares 14 multiplies + // + // Generated by github.com/mmcloughlin/addchain v0.4.0. + + // Note: Need to stash `arg1` (`xx`) in the case that `out1`/`arg1` alias, + // as `arg1` is used after `out1` has been altered. + t0, t1, t2, t3, xx: Montgomery_Domain_Field_Element = ---, ---, ---, ---, arg1^ + + // Step 1: z = x^0x2 + fe_square(out1, arg1) + + // Step 2: z = x^0x3 + fe_mul(out1, &xx, out1) + + // Step 3: z = x^0x6 + fe_square(out1, out1) + + // Step 4: t1 = x^0x7 + fe_mul(&t1, &xx, out1) + + // Step 7: z = x^0x38 + fe_pow2k(out1, &t1, 3) + + // Step 8: z = x^0x3f + fe_mul(out1, &t1, out1) + + // Step 14: t0 = x^0xfc0 + fe_pow2k(&t0, out1, 6) + + // Step 15: t0 = x^0xfff + fe_mul(&t0, out1, &t0) + + // Step 27: t2 = x^0xfff000 + fe_pow2k(&t2, &t0, 12) + + // Step 28: t0 = x^0xffffff + fe_mul(&t0, &t0, &t2) + + // Step 34: t0 = x^0x3fffffc0 + fe_pow2k(&t0, &t0, 6) + + // Step 35: z = x^0x3fffffff + fe_mul(out1, out1, &t0) + + // Step 36: t0 = x^0x7ffffffe + fe_square(&t0, out1) + + // Step 37: t2 = x^0x7fffffff + fe_mul(&t2, &xx, &t0) + + // Step 38: t0 = x^0xfffffffe + fe_square(&t0, &t2) + + // Step 39: t0 = x^0xffffffff + fe_mul(&t0, &xx, &t0) + + // Step 70: t3 = x^0x7fffffff80000000 + fe_pow2k(&t3, &t0, 31) + + // Step 71: t2 = x^0x7fffffffffffffff + fe_mul(&t2, &t2, &t3) + + // Step 134: t3 = x^0x3fffffffffffffff8000000000000000 + fe_pow2k(&t3, &t2, 63) + + // Step 135: t2 = x^0x3fffffffffffffffffffffffffffffff + fe_mul(&t2, &t2, &t3) + + // Step 261: t3 = x^0xfffffffffffffffffffffffffffffffc0000000000000000000000000000000 + fe_pow2k(&t3, &t2, 126) + + // Step 262: t2 = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + fe_mul(&t2, &t2, &t3) + + // Step 265: t2 = x^0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8 + fe_pow2k(&t2, &t2, 3) + + // Step 266: t1 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + fe_mul(&t1, &t1, &t2) + + // Step 299: t1 = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00000000 + fe_pow2k(&t1, &t1, 33) + + // Step 300: t0 = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff + fe_mul(&t0, &t0, &t1) + + // Step 394: t0 = x^0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffc00000000000000000000000 + fe_pow2k(&t0, &t0, 94) + + // Step 395: z = x^0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffc0000000000000003fffffff + fe_mul(out1, out1, &t0) + + // Step 397: z = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc + fe_pow2k(out1, out1, 2) + + fe_mul(out1, out1, &xx) + + fe_clear_vec([]^Montgomery_Domain_Field_Element{&t0, &t1, &t2, &t3, &xx}) +} + +@(require_results) +fe_sqrt :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) -> int { + // Square root candidate can be derived via exponentiation by `(p + 1) / 4` + // From sage: 9850501549098619803069760025035903451269934817616361666987073351061430442874217582261816522064734500465401743278080 + // + // Inversion computation is derived from the addition chain: + // + // _10 = 2*1 + // _11 = 1 + _10 + // _110 = 2*_11 + // _111 = 1 + _110 + // _111000 = _111 << 3 + // _111111 = _111 + _111000 + // x12 = _111111 << 6 + _111111 + // x24 = x12 << 12 + x12 + // x30 = x24 << 6 + _111111 + // x31 = 2*x30 + 1 + // x32 = 2*x31 + 1 + // x63 = x32 << 31 + x31 + // x126 = x63 << 63 + x63 + // x252 = x126 << 126 + x126 + // x255 = x252 << 3 + _111 + // return ((x255 << 33 + x32) << 94 + x30) << 2 + // + // Operations: 383 squares 14 multiplies + // + // Generated by github.com/mmcloughlin/addchain v0.4.0. + + // Likewise this tramples over arg1, so stash another copy. + t0, t1, t2, t3, xx: Montgomery_Domain_Field_Element = ---, ---, ---, ---, arg1^ + + // Step 1: z = x^0x2 + fe_square(out1, arg1) + + // Step 2: z = x^0x3 + fe_mul(out1, &xx, out1) + + // Step 3: z = x^0x6 + fe_square(out1, out1) + + // Step 4: t1 = x^0x7 + fe_mul(&t1, &xx, out1) + + // Step 7: z = x^0x38 + fe_pow2k(out1, &t1, 3) + + // Step 8: z = x^0x3f + fe_mul(out1, &t1, out1) + + // Step 14: t0 = x^0xfc0 + fe_pow2k(&t0, out1, 6) + + // Step 15: t0 = x^0xfff + fe_mul(&t0, out1, &t0) + + // Step 27: t2 = x^0xfff000 + fe_pow2k(&t2, &t0, 12) + + // Step 28: t0 = x^0xffffff + fe_mul(&t0, &t0, &t2) + + // Step 34: t0 = x^0x3fffffc0 + fe_pow2k(&t0, &t0, 6) + + // Step 35: z = x^0x3fffffff + fe_mul(out1, out1, &t0) + + // Step 36: t0 = x^0x7ffffffe + fe_square(&t0, out1) + + // Step 37: t2 = x^0x7fffffff + fe_mul(&t2, &xx, &t0) + + // Step 38: t0 = x^0xfffffffe + fe_square(&t0, &t2) + + // Step 39: t0 = x^0xffffffff + fe_mul(&t0, &xx, &t0) + + // Step 70: t3 = x^0x7fffffff80000000 + fe_pow2k(&t3, &t0, 31) + + // Step 71: t2 = x^0x7fffffffffffffff + fe_mul(&t2, &t2, &t3) + + // Step 134: t3 = x^0x3fffffffffffffff8000000000000000 + fe_pow2k(&t3, &t2, 63) + + // Step 135: t2 = x^0x3fffffffffffffffffffffffffffffff + fe_mul(&t2, &t2, &t3) + + // Step 261: t3 = x^0xfffffffffffffffffffffffffffffffc0000000000000000000000000000000 + fe_pow2k(&t3, &t2, 126) + + // Step 262: t2 = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + fe_mul(&t2, &t2, &t3) + + // Step 265: t2 = x^0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8 + fe_pow2k(&t2, &t2, 3) + + // Step 266: t1 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + fe_mul(&t1, &t1, &t2) + + // Step 299: t1 = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00000000 + fe_pow2k(&t1, &t1, 33) + + // Step 300: t0 = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff + fe_mul(&t0, &t0, &t1) + + // Step 394: t0 = x^0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffc00000000000000000000000 + fe_pow2k(&t0, &t0, 94) + + // Step 395: z = x^0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffc0000000000000003fffffff + fe_mul(out1, out1, &t0) + + // Step 397: z = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc + fe_pow2k(out1, out1, 2) + + // Ensure that our candidate is actually the square root. + check, zero: Montgomery_Domain_Field_Element + fe_square(&check, out1) + + is_valid := fe_equal(&check, &xx) + fe_cond_select(out1, &zero, out1, is_valid) + + fe_clear_vec([]^Montgomery_Domain_Field_Element{&t0, &t1, &t2, &t3, &xx, &check}) + + return is_valid +} + +fe_zero :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element) { + out1[0] = 0 + out1[1] = 0 + out1[2] = 0 + out1[3] = 0 + out1[4] = 0 + out1[5] = 0 +} + +fe_set :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) { + x1 := arg1[0] + x2 := arg1[1] + x3 := arg1[2] + x4 := arg1[3] + x5 := arg1[4] + x6 := arg1[5] + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 + out1[5] = x6 +} + +@(optimization_mode = "none") +fe_cond_swap :: #force_no_inline proc "contextless" (out1, out2: ^Montgomery_Domain_Field_Element, arg1: int) { + mask := (u64(arg1) * 0xffffffffffffffff) + x := (out1[0] ~ out2[0]) & mask + x1, y1 := out1[0] ~ x, out2[0] ~ x + x = (out1[1] ~ out2[1]) & mask + x2, y2 := out1[1] ~ x, out2[1] ~ x + x = (out1[2] ~ out2[2]) & mask + x3, y3 := out1[2] ~ x, out2[2] ~ x + x = (out1[3] ~ out2[3]) & mask + x4, y4 := out1[3] ~ x, out2[3] ~ x + x = (out1[4] ~ out2[4]) & mask + x5, y5 := out1[4] ~ x, out2[4] ~ x + x = (out1[5] ~ out2[5]) & mask + x6, y6 := out1[5] ~ x, out2[5] ~ x + out1[0], out2[0] = x1, y1 + out1[1], out2[1] = x2, y2 + out1[2], out2[2] = x3, y3 + out1[3], out2[3] = x4, y4 + out1[4], out2[4] = x5, y5 + out1[5], out2[5] = x6, y6 +} + +@(optimization_mode = "none") +fe_cond_select :: #force_no_inline proc "contextless" ( + out1, arg1, arg2: ^Montgomery_Domain_Field_Element, + arg3: int, +) { + mask := (u64(arg3) * 0xffffffffffffffff) + x1 := ((mask & arg2[0]) | ((~mask) & arg1[0])) + x2 := ((mask & arg2[1]) | ((~mask) & arg1[1])) + x3 := ((mask & arg2[2]) | ((~mask) & arg1[2])) + x4 := ((mask & arg2[3]) | ((~mask) & arg1[3])) + x5 := ((mask & arg2[4]) | ((~mask) & arg1[4])) + x6 := ((mask & arg2[5]) | ((~mask) & arg1[5])) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 + out1[5] = x6 +} + +fe_cond_negate :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element, ctrl: int) { + tmp1: Montgomery_Domain_Field_Element = --- + fe_opp(&tmp1, arg1) + fe_cond_select(out1, arg1, &tmp1, ctrl) + + fe_clear(&tmp1) +} diff --git a/core/crypto/_fiat/field_p384r1/field64.odin b/core/crypto/_fiat/field_p384r1/field64.odin new file mode 100644 index 000000000..493f24b17 --- /dev/null +++ b/core/crypto/_fiat/field_p384r1/field64.odin @@ -0,0 +1,1063 @@ +// The BSD 1-Clause License (BSD-1-Clause) +// +// Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, +// Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package field_p384r1 + +// The file provides arithmetic on the field Z/(2^384 - 2^128 - 2^96 + 2^32 - 1) +// using a 64-bit Montgomery form internal representation. It is derived +// primarily from the machine generated Golang output from the fiat-crypto +// project. +// +// While the base implementation is provably correct, this implementation +// makes no such claims as the port and optimizations were done by hand. +// +// WARNING: While big-endian is the common representation used for this +// curve, the fiat output uses least-significant-limb first. + +import fiat "core:crypto/_fiat" +import "core:math/bits" + +// ELL is the saturated representation of the field order, least-significant +// limb first. +ELL :: [6]u64{0xffffffff, 0xffffffff00000000, 0xfffffffffffffffe, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff} + +Montgomery_Domain_Field_Element :: distinct [6]u64 +Non_Montgomery_Domain_Field_Element :: distinct [6]u64 + +fe_mul :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[4] + x5 := arg1[5] + x6 := arg1[0] + x8, x7 := bits.mul_u64(x6, arg2[5]) + x10, x9 := bits.mul_u64(x6, arg2[4]) + x12, x11 := bits.mul_u64(x6, arg2[3]) + x14, x13 := bits.mul_u64(x6, arg2[2]) + x16, x15 := bits.mul_u64(x6, arg2[1]) + x18, x17 := bits.mul_u64(x6, arg2[0]) + x19, x20 := bits.add_u64(x18, x15, u64(0x0)) + x21, x22 := bits.add_u64(x16, x13, u64(fiat.u1(x20))) + x23, x24 := bits.add_u64(x14, x11, u64(fiat.u1(x22))) + x25, x26 := bits.add_u64(x12, x9, u64(fiat.u1(x24))) + x27, x28 := bits.add_u64(x10, x7, u64(fiat.u1(x26))) + x29 := (u64(fiat.u1(x28)) + x8) + _, x30 := bits.mul_u64(x17, 0x100000001) + x33, x32 := bits.mul_u64(x30, 0xffffffffffffffff) + x35, x34 := bits.mul_u64(x30, 0xffffffffffffffff) + x37, x36 := bits.mul_u64(x30, 0xffffffffffffffff) + x39, x38 := bits.mul_u64(x30, 0xfffffffffffffffe) + x41, x40 := bits.mul_u64(x30, 0xffffffff00000000) + x43, x42 := bits.mul_u64(x30, 0xffffffff) + x44, x45 := bits.add_u64(x43, x40, u64(0x0)) + x46, x47 := bits.add_u64(x41, x38, u64(fiat.u1(x45))) + x48, x49 := bits.add_u64(x39, x36, u64(fiat.u1(x47))) + x50, x51 := bits.add_u64(x37, x34, u64(fiat.u1(x49))) + x52, x53 := bits.add_u64(x35, x32, u64(fiat.u1(x51))) + x54 := (u64(fiat.u1(x53)) + x33) + _, x56 := bits.add_u64(x17, x42, u64(0x0)) + x57, x58 := bits.add_u64(x19, x44, u64(fiat.u1(x56))) + x59, x60 := bits.add_u64(x21, x46, u64(fiat.u1(x58))) + x61, x62 := bits.add_u64(x23, x48, u64(fiat.u1(x60))) + x63, x64 := bits.add_u64(x25, x50, u64(fiat.u1(x62))) + x65, x66 := bits.add_u64(x27, x52, u64(fiat.u1(x64))) + x67, x68 := bits.add_u64(x29, x54, u64(fiat.u1(x66))) + x70, x69 := bits.mul_u64(x1, arg2[5]) + x72, x71 := bits.mul_u64(x1, arg2[4]) + x74, x73 := bits.mul_u64(x1, arg2[3]) + x76, x75 := bits.mul_u64(x1, arg2[2]) + x78, x77 := bits.mul_u64(x1, arg2[1]) + x80, x79 := bits.mul_u64(x1, arg2[0]) + x81, x82 := bits.add_u64(x80, x77, u64(0x0)) + x83, x84 := bits.add_u64(x78, x75, u64(fiat.u1(x82))) + x85, x86 := bits.add_u64(x76, x73, u64(fiat.u1(x84))) + x87, x88 := bits.add_u64(x74, x71, u64(fiat.u1(x86))) + x89, x90 := bits.add_u64(x72, x69, u64(fiat.u1(x88))) + x91 := (u64(fiat.u1(x90)) + x70) + x92, x93 := bits.add_u64(x57, x79, u64(0x0)) + x94, x95 := bits.add_u64(x59, x81, u64(fiat.u1(x93))) + x96, x97 := bits.add_u64(x61, x83, u64(fiat.u1(x95))) + x98, x99 := bits.add_u64(x63, x85, u64(fiat.u1(x97))) + x100, x101 := bits.add_u64(x65, x87, u64(fiat.u1(x99))) + x102, x103 := bits.add_u64(x67, x89, u64(fiat.u1(x101))) + x104, x105 := bits.add_u64(u64(fiat.u1(x68)), x91, u64(fiat.u1(x103))) + _, x106 := bits.mul_u64(x92, 0x100000001) + x109, x108 := bits.mul_u64(x106, 0xffffffffffffffff) + x111, x110 := bits.mul_u64(x106, 0xffffffffffffffff) + x113, x112 := bits.mul_u64(x106, 0xffffffffffffffff) + x115, x114 := bits.mul_u64(x106, 0xfffffffffffffffe) + x117, x116 := bits.mul_u64(x106, 0xffffffff00000000) + x119, x118 := bits.mul_u64(x106, 0xffffffff) + x120, x121 := bits.add_u64(x119, x116, u64(0x0)) + x122, x123 := bits.add_u64(x117, x114, u64(fiat.u1(x121))) + x124, x125 := bits.add_u64(x115, x112, u64(fiat.u1(x123))) + x126, x127 := bits.add_u64(x113, x110, u64(fiat.u1(x125))) + x128, x129 := bits.add_u64(x111, x108, u64(fiat.u1(x127))) + x130 := (u64(fiat.u1(x129)) + x109) + _, x132 := bits.add_u64(x92, x118, u64(0x0)) + x133, x134 := bits.add_u64(x94, x120, u64(fiat.u1(x132))) + x135, x136 := bits.add_u64(x96, x122, u64(fiat.u1(x134))) + x137, x138 := bits.add_u64(x98, x124, u64(fiat.u1(x136))) + x139, x140 := bits.add_u64(x100, x126, u64(fiat.u1(x138))) + x141, x142 := bits.add_u64(x102, x128, u64(fiat.u1(x140))) + x143, x144 := bits.add_u64(x104, x130, u64(fiat.u1(x142))) + x145 := (u64(fiat.u1(x144)) + u64(fiat.u1(x105))) + x147, x146 := bits.mul_u64(x2, arg2[5]) + x149, x148 := bits.mul_u64(x2, arg2[4]) + x151, x150 := bits.mul_u64(x2, arg2[3]) + x153, x152 := bits.mul_u64(x2, arg2[2]) + x155, x154 := bits.mul_u64(x2, arg2[1]) + x157, x156 := bits.mul_u64(x2, arg2[0]) + x158, x159 := bits.add_u64(x157, x154, u64(0x0)) + x160, x161 := bits.add_u64(x155, x152, u64(fiat.u1(x159))) + x162, x163 := bits.add_u64(x153, x150, u64(fiat.u1(x161))) + x164, x165 := bits.add_u64(x151, x148, u64(fiat.u1(x163))) + x166, x167 := bits.add_u64(x149, x146, u64(fiat.u1(x165))) + x168 := (u64(fiat.u1(x167)) + x147) + x169, x170 := bits.add_u64(x133, x156, u64(0x0)) + x171, x172 := bits.add_u64(x135, x158, u64(fiat.u1(x170))) + x173, x174 := bits.add_u64(x137, x160, u64(fiat.u1(x172))) + x175, x176 := bits.add_u64(x139, x162, u64(fiat.u1(x174))) + x177, x178 := bits.add_u64(x141, x164, u64(fiat.u1(x176))) + x179, x180 := bits.add_u64(x143, x166, u64(fiat.u1(x178))) + x181, x182 := bits.add_u64(x145, x168, u64(fiat.u1(x180))) + _, x183 := bits.mul_u64(x169, 0x100000001) + x186, x185 := bits.mul_u64(x183, 0xffffffffffffffff) + x188, x187 := bits.mul_u64(x183, 0xffffffffffffffff) + x190, x189 := bits.mul_u64(x183, 0xffffffffffffffff) + x192, x191 := bits.mul_u64(x183, 0xfffffffffffffffe) + x194, x193 := bits.mul_u64(x183, 0xffffffff00000000) + x196, x195 := bits.mul_u64(x183, 0xffffffff) + x197, x198 := bits.add_u64(x196, x193, u64(0x0)) + x199, x200 := bits.add_u64(x194, x191, u64(fiat.u1(x198))) + x201, x202 := bits.add_u64(x192, x189, u64(fiat.u1(x200))) + x203, x204 := bits.add_u64(x190, x187, u64(fiat.u1(x202))) + x205, x206 := bits.add_u64(x188, x185, u64(fiat.u1(x204))) + x207 := (u64(fiat.u1(x206)) + x186) + _, x209 := bits.add_u64(x169, x195, u64(0x0)) + x210, x211 := bits.add_u64(x171, x197, u64(fiat.u1(x209))) + x212, x213 := bits.add_u64(x173, x199, u64(fiat.u1(x211))) + x214, x215 := bits.add_u64(x175, x201, u64(fiat.u1(x213))) + x216, x217 := bits.add_u64(x177, x203, u64(fiat.u1(x215))) + x218, x219 := bits.add_u64(x179, x205, u64(fiat.u1(x217))) + x220, x221 := bits.add_u64(x181, x207, u64(fiat.u1(x219))) + x222 := (u64(fiat.u1(x221)) + u64(fiat.u1(x182))) + x224, x223 := bits.mul_u64(x3, arg2[5]) + x226, x225 := bits.mul_u64(x3, arg2[4]) + x228, x227 := bits.mul_u64(x3, arg2[3]) + x230, x229 := bits.mul_u64(x3, arg2[2]) + x232, x231 := bits.mul_u64(x3, arg2[1]) + x234, x233 := bits.mul_u64(x3, arg2[0]) + x235, x236 := bits.add_u64(x234, x231, u64(0x0)) + x237, x238 := bits.add_u64(x232, x229, u64(fiat.u1(x236))) + x239, x240 := bits.add_u64(x230, x227, u64(fiat.u1(x238))) + x241, x242 := bits.add_u64(x228, x225, u64(fiat.u1(x240))) + x243, x244 := bits.add_u64(x226, x223, u64(fiat.u1(x242))) + x245 := (u64(fiat.u1(x244)) + x224) + x246, x247 := bits.add_u64(x210, x233, u64(0x0)) + x248, x249 := bits.add_u64(x212, x235, u64(fiat.u1(x247))) + x250, x251 := bits.add_u64(x214, x237, u64(fiat.u1(x249))) + x252, x253 := bits.add_u64(x216, x239, u64(fiat.u1(x251))) + x254, x255 := bits.add_u64(x218, x241, u64(fiat.u1(x253))) + x256, x257 := bits.add_u64(x220, x243, u64(fiat.u1(x255))) + x258, x259 := bits.add_u64(x222, x245, u64(fiat.u1(x257))) + _, x260 := bits.mul_u64(x246, 0x100000001) + x263, x262 := bits.mul_u64(x260, 0xffffffffffffffff) + x265, x264 := bits.mul_u64(x260, 0xffffffffffffffff) + x267, x266 := bits.mul_u64(x260, 0xffffffffffffffff) + x269, x268 := bits.mul_u64(x260, 0xfffffffffffffffe) + x271, x270 := bits.mul_u64(x260, 0xffffffff00000000) + x273, x272 := bits.mul_u64(x260, 0xffffffff) + x274, x275 := bits.add_u64(x273, x270, u64(0x0)) + x276, x277 := bits.add_u64(x271, x268, u64(fiat.u1(x275))) + x278, x279 := bits.add_u64(x269, x266, u64(fiat.u1(x277))) + x280, x281 := bits.add_u64(x267, x264, u64(fiat.u1(x279))) + x282, x283 := bits.add_u64(x265, x262, u64(fiat.u1(x281))) + x284 := (u64(fiat.u1(x283)) + x263) + _, x286 := bits.add_u64(x246, x272, u64(0x0)) + x287, x288 := bits.add_u64(x248, x274, u64(fiat.u1(x286))) + x289, x290 := bits.add_u64(x250, x276, u64(fiat.u1(x288))) + x291, x292 := bits.add_u64(x252, x278, u64(fiat.u1(x290))) + x293, x294 := bits.add_u64(x254, x280, u64(fiat.u1(x292))) + x295, x296 := bits.add_u64(x256, x282, u64(fiat.u1(x294))) + x297, x298 := bits.add_u64(x258, x284, u64(fiat.u1(x296))) + x299 := (u64(fiat.u1(x298)) + u64(fiat.u1(x259))) + x301, x300 := bits.mul_u64(x4, arg2[5]) + x303, x302 := bits.mul_u64(x4, arg2[4]) + x305, x304 := bits.mul_u64(x4, arg2[3]) + x307, x306 := bits.mul_u64(x4, arg2[2]) + x309, x308 := bits.mul_u64(x4, arg2[1]) + x311, x310 := bits.mul_u64(x4, arg2[0]) + x312, x313 := bits.add_u64(x311, x308, u64(0x0)) + x314, x315 := bits.add_u64(x309, x306, u64(fiat.u1(x313))) + x316, x317 := bits.add_u64(x307, x304, u64(fiat.u1(x315))) + x318, x319 := bits.add_u64(x305, x302, u64(fiat.u1(x317))) + x320, x321 := bits.add_u64(x303, x300, u64(fiat.u1(x319))) + x322 := (u64(fiat.u1(x321)) + x301) + x323, x324 := bits.add_u64(x287, x310, u64(0x0)) + x325, x326 := bits.add_u64(x289, x312, u64(fiat.u1(x324))) + x327, x328 := bits.add_u64(x291, x314, u64(fiat.u1(x326))) + x329, x330 := bits.add_u64(x293, x316, u64(fiat.u1(x328))) + x331, x332 := bits.add_u64(x295, x318, u64(fiat.u1(x330))) + x333, x334 := bits.add_u64(x297, x320, u64(fiat.u1(x332))) + x335, x336 := bits.add_u64(x299, x322, u64(fiat.u1(x334))) + _, x337 := bits.mul_u64(x323, 0x100000001) + x340, x339 := bits.mul_u64(x337, 0xffffffffffffffff) + x342, x341 := bits.mul_u64(x337, 0xffffffffffffffff) + x344, x343 := bits.mul_u64(x337, 0xffffffffffffffff) + x346, x345 := bits.mul_u64(x337, 0xfffffffffffffffe) + x348, x347 := bits.mul_u64(x337, 0xffffffff00000000) + x350, x349 := bits.mul_u64(x337, 0xffffffff) + x351, x352 := bits.add_u64(x350, x347, u64(0x0)) + x353, x354 := bits.add_u64(x348, x345, u64(fiat.u1(x352))) + x355, x356 := bits.add_u64(x346, x343, u64(fiat.u1(x354))) + x357, x358 := bits.add_u64(x344, x341, u64(fiat.u1(x356))) + x359, x360 := bits.add_u64(x342, x339, u64(fiat.u1(x358))) + x361 := (u64(fiat.u1(x360)) + x340) + _, x363 := bits.add_u64(x323, x349, u64(0x0)) + x364, x365 := bits.add_u64(x325, x351, u64(fiat.u1(x363))) + x366, x367 := bits.add_u64(x327, x353, u64(fiat.u1(x365))) + x368, x369 := bits.add_u64(x329, x355, u64(fiat.u1(x367))) + x370, x371 := bits.add_u64(x331, x357, u64(fiat.u1(x369))) + x372, x373 := bits.add_u64(x333, x359, u64(fiat.u1(x371))) + x374, x375 := bits.add_u64(x335, x361, u64(fiat.u1(x373))) + x376 := (u64(fiat.u1(x375)) + u64(fiat.u1(x336))) + x378, x377 := bits.mul_u64(x5, arg2[5]) + x380, x379 := bits.mul_u64(x5, arg2[4]) + x382, x381 := bits.mul_u64(x5, arg2[3]) + x384, x383 := bits.mul_u64(x5, arg2[2]) + x386, x385 := bits.mul_u64(x5, arg2[1]) + x388, x387 := bits.mul_u64(x5, arg2[0]) + x389, x390 := bits.add_u64(x388, x385, u64(0x0)) + x391, x392 := bits.add_u64(x386, x383, u64(fiat.u1(x390))) + x393, x394 := bits.add_u64(x384, x381, u64(fiat.u1(x392))) + x395, x396 := bits.add_u64(x382, x379, u64(fiat.u1(x394))) + x397, x398 := bits.add_u64(x380, x377, u64(fiat.u1(x396))) + x399 := (u64(fiat.u1(x398)) + x378) + x400, x401 := bits.add_u64(x364, x387, u64(0x0)) + x402, x403 := bits.add_u64(x366, x389, u64(fiat.u1(x401))) + x404, x405 := bits.add_u64(x368, x391, u64(fiat.u1(x403))) + x406, x407 := bits.add_u64(x370, x393, u64(fiat.u1(x405))) + x408, x409 := bits.add_u64(x372, x395, u64(fiat.u1(x407))) + x410, x411 := bits.add_u64(x374, x397, u64(fiat.u1(x409))) + x412, x413 := bits.add_u64(x376, x399, u64(fiat.u1(x411))) + _, x414 := bits.mul_u64(x400, 0x100000001) + x417, x416 := bits.mul_u64(x414, 0xffffffffffffffff) + x419, x418 := bits.mul_u64(x414, 0xffffffffffffffff) + x421, x420 := bits.mul_u64(x414, 0xffffffffffffffff) + x423, x422 := bits.mul_u64(x414, 0xfffffffffffffffe) + x425, x424 := bits.mul_u64(x414, 0xffffffff00000000) + x427, x426 := bits.mul_u64(x414, 0xffffffff) + x428, x429 := bits.add_u64(x427, x424, u64(0x0)) + x430, x431 := bits.add_u64(x425, x422, u64(fiat.u1(x429))) + x432, x433 := bits.add_u64(x423, x420, u64(fiat.u1(x431))) + x434, x435 := bits.add_u64(x421, x418, u64(fiat.u1(x433))) + x436, x437 := bits.add_u64(x419, x416, u64(fiat.u1(x435))) + x438 := (u64(fiat.u1(x437)) + x417) + _, x440 := bits.add_u64(x400, x426, u64(0x0)) + x441, x442 := bits.add_u64(x402, x428, u64(fiat.u1(x440))) + x443, x444 := bits.add_u64(x404, x430, u64(fiat.u1(x442))) + x445, x446 := bits.add_u64(x406, x432, u64(fiat.u1(x444))) + x447, x448 := bits.add_u64(x408, x434, u64(fiat.u1(x446))) + x449, x450 := bits.add_u64(x410, x436, u64(fiat.u1(x448))) + x451, x452 := bits.add_u64(x412, x438, u64(fiat.u1(x450))) + x453 := (u64(fiat.u1(x452)) + u64(fiat.u1(x413))) + x454, x455 := bits.sub_u64(x441, 0xffffffff, u64(0x0)) + x456, x457 := bits.sub_u64(x443, 0xffffffff00000000, u64(fiat.u1(x455))) + x458, x459 := bits.sub_u64(x445, 0xfffffffffffffffe, u64(fiat.u1(x457))) + x460, x461 := bits.sub_u64(x447, 0xffffffffffffffff, u64(fiat.u1(x459))) + x462, x463 := bits.sub_u64(x449, 0xffffffffffffffff, u64(fiat.u1(x461))) + x464, x465 := bits.sub_u64(x451, 0xffffffffffffffff, u64(fiat.u1(x463))) + _, x467 := bits.sub_u64(x453, u64(0x0), u64(fiat.u1(x465))) + x468 := fiat.cmovznz_u64(fiat.u1(x467), x454, x441) + x469 := fiat.cmovznz_u64(fiat.u1(x467), x456, x443) + x470 := fiat.cmovznz_u64(fiat.u1(x467), x458, x445) + x471 := fiat.cmovznz_u64(fiat.u1(x467), x460, x447) + x472 := fiat.cmovznz_u64(fiat.u1(x467), x462, x449) + x473 := fiat.cmovznz_u64(fiat.u1(x467), x464, x451) + out1[0] = x468 + out1[1] = x469 + out1[2] = x470 + out1[3] = x471 + out1[4] = x472 + out1[5] = x473 +} + +fe_square :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[4] + x5 := arg1[5] + x6 := arg1[0] + x8, x7 := bits.mul_u64(x6, arg1[5]) + x10, x9 := bits.mul_u64(x6, arg1[4]) + x12, x11 := bits.mul_u64(x6, arg1[3]) + x14, x13 := bits.mul_u64(x6, arg1[2]) + x16, x15 := bits.mul_u64(x6, arg1[1]) + x18, x17 := bits.mul_u64(x6, arg1[0]) + x19, x20 := bits.add_u64(x18, x15, u64(0x0)) + x21, x22 := bits.add_u64(x16, x13, u64(fiat.u1(x20))) + x23, x24 := bits.add_u64(x14, x11, u64(fiat.u1(x22))) + x25, x26 := bits.add_u64(x12, x9, u64(fiat.u1(x24))) + x27, x28 := bits.add_u64(x10, x7, u64(fiat.u1(x26))) + x29 := (u64(fiat.u1(x28)) + x8) + _, x30 := bits.mul_u64(x17, 0x100000001) + x33, x32 := bits.mul_u64(x30, 0xffffffffffffffff) + x35, x34 := bits.mul_u64(x30, 0xffffffffffffffff) + x37, x36 := bits.mul_u64(x30, 0xffffffffffffffff) + x39, x38 := bits.mul_u64(x30, 0xfffffffffffffffe) + x41, x40 := bits.mul_u64(x30, 0xffffffff00000000) + x43, x42 := bits.mul_u64(x30, 0xffffffff) + x44, x45 := bits.add_u64(x43, x40, u64(0x0)) + x46, x47 := bits.add_u64(x41, x38, u64(fiat.u1(x45))) + x48, x49 := bits.add_u64(x39, x36, u64(fiat.u1(x47))) + x50, x51 := bits.add_u64(x37, x34, u64(fiat.u1(x49))) + x52, x53 := bits.add_u64(x35, x32, u64(fiat.u1(x51))) + x54 := (u64(fiat.u1(x53)) + x33) + _, x56 := bits.add_u64(x17, x42, u64(0x0)) + x57, x58 := bits.add_u64(x19, x44, u64(fiat.u1(x56))) + x59, x60 := bits.add_u64(x21, x46, u64(fiat.u1(x58))) + x61, x62 := bits.add_u64(x23, x48, u64(fiat.u1(x60))) + x63, x64 := bits.add_u64(x25, x50, u64(fiat.u1(x62))) + x65, x66 := bits.add_u64(x27, x52, u64(fiat.u1(x64))) + x67, x68 := bits.add_u64(x29, x54, u64(fiat.u1(x66))) + x70, x69 := bits.mul_u64(x1, arg1[5]) + x72, x71 := bits.mul_u64(x1, arg1[4]) + x74, x73 := bits.mul_u64(x1, arg1[3]) + x76, x75 := bits.mul_u64(x1, arg1[2]) + x78, x77 := bits.mul_u64(x1, arg1[1]) + x80, x79 := bits.mul_u64(x1, arg1[0]) + x81, x82 := bits.add_u64(x80, x77, u64(0x0)) + x83, x84 := bits.add_u64(x78, x75, u64(fiat.u1(x82))) + x85, x86 := bits.add_u64(x76, x73, u64(fiat.u1(x84))) + x87, x88 := bits.add_u64(x74, x71, u64(fiat.u1(x86))) + x89, x90 := bits.add_u64(x72, x69, u64(fiat.u1(x88))) + x91 := (u64(fiat.u1(x90)) + x70) + x92, x93 := bits.add_u64(x57, x79, u64(0x0)) + x94, x95 := bits.add_u64(x59, x81, u64(fiat.u1(x93))) + x96, x97 := bits.add_u64(x61, x83, u64(fiat.u1(x95))) + x98, x99 := bits.add_u64(x63, x85, u64(fiat.u1(x97))) + x100, x101 := bits.add_u64(x65, x87, u64(fiat.u1(x99))) + x102, x103 := bits.add_u64(x67, x89, u64(fiat.u1(x101))) + x104, x105 := bits.add_u64(u64(fiat.u1(x68)), x91, u64(fiat.u1(x103))) + _, x106 := bits.mul_u64(x92, 0x100000001) + x109, x108 := bits.mul_u64(x106, 0xffffffffffffffff) + x111, x110 := bits.mul_u64(x106, 0xffffffffffffffff) + x113, x112 := bits.mul_u64(x106, 0xffffffffffffffff) + x115, x114 := bits.mul_u64(x106, 0xfffffffffffffffe) + x117, x116 := bits.mul_u64(x106, 0xffffffff00000000) + x119, x118 := bits.mul_u64(x106, 0xffffffff) + x120, x121 := bits.add_u64(x119, x116, u64(0x0)) + x122, x123 := bits.add_u64(x117, x114, u64(fiat.u1(x121))) + x124, x125 := bits.add_u64(x115, x112, u64(fiat.u1(x123))) + x126, x127 := bits.add_u64(x113, x110, u64(fiat.u1(x125))) + x128, x129 := bits.add_u64(x111, x108, u64(fiat.u1(x127))) + x130 := (u64(fiat.u1(x129)) + x109) + _, x132 := bits.add_u64(x92, x118, u64(0x0)) + x133, x134 := bits.add_u64(x94, x120, u64(fiat.u1(x132))) + x135, x136 := bits.add_u64(x96, x122, u64(fiat.u1(x134))) + x137, x138 := bits.add_u64(x98, x124, u64(fiat.u1(x136))) + x139, x140 := bits.add_u64(x100, x126, u64(fiat.u1(x138))) + x141, x142 := bits.add_u64(x102, x128, u64(fiat.u1(x140))) + x143, x144 := bits.add_u64(x104, x130, u64(fiat.u1(x142))) + x145 := (u64(fiat.u1(x144)) + u64(fiat.u1(x105))) + x147, x146 := bits.mul_u64(x2, arg1[5]) + x149, x148 := bits.mul_u64(x2, arg1[4]) + x151, x150 := bits.mul_u64(x2, arg1[3]) + x153, x152 := bits.mul_u64(x2, arg1[2]) + x155, x154 := bits.mul_u64(x2, arg1[1]) + x157, x156 := bits.mul_u64(x2, arg1[0]) + x158, x159 := bits.add_u64(x157, x154, u64(0x0)) + x160, x161 := bits.add_u64(x155, x152, u64(fiat.u1(x159))) + x162, x163 := bits.add_u64(x153, x150, u64(fiat.u1(x161))) + x164, x165 := bits.add_u64(x151, x148, u64(fiat.u1(x163))) + x166, x167 := bits.add_u64(x149, x146, u64(fiat.u1(x165))) + x168 := (u64(fiat.u1(x167)) + x147) + x169, x170 := bits.add_u64(x133, x156, u64(0x0)) + x171, x172 := bits.add_u64(x135, x158, u64(fiat.u1(x170))) + x173, x174 := bits.add_u64(x137, x160, u64(fiat.u1(x172))) + x175, x176 := bits.add_u64(x139, x162, u64(fiat.u1(x174))) + x177, x178 := bits.add_u64(x141, x164, u64(fiat.u1(x176))) + x179, x180 := bits.add_u64(x143, x166, u64(fiat.u1(x178))) + x181, x182 := bits.add_u64(x145, x168, u64(fiat.u1(x180))) + _, x183 := bits.mul_u64(x169, 0x100000001) + x186, x185 := bits.mul_u64(x183, 0xffffffffffffffff) + x188, x187 := bits.mul_u64(x183, 0xffffffffffffffff) + x190, x189 := bits.mul_u64(x183, 0xffffffffffffffff) + x192, x191 := bits.mul_u64(x183, 0xfffffffffffffffe) + x194, x193 := bits.mul_u64(x183, 0xffffffff00000000) + x196, x195 := bits.mul_u64(x183, 0xffffffff) + x197, x198 := bits.add_u64(x196, x193, u64(0x0)) + x199, x200 := bits.add_u64(x194, x191, u64(fiat.u1(x198))) + x201, x202 := bits.add_u64(x192, x189, u64(fiat.u1(x200))) + x203, x204 := bits.add_u64(x190, x187, u64(fiat.u1(x202))) + x205, x206 := bits.add_u64(x188, x185, u64(fiat.u1(x204))) + x207 := (u64(fiat.u1(x206)) + x186) + _, x209 := bits.add_u64(x169, x195, u64(0x0)) + x210, x211 := bits.add_u64(x171, x197, u64(fiat.u1(x209))) + x212, x213 := bits.add_u64(x173, x199, u64(fiat.u1(x211))) + x214, x215 := bits.add_u64(x175, x201, u64(fiat.u1(x213))) + x216, x217 := bits.add_u64(x177, x203, u64(fiat.u1(x215))) + x218, x219 := bits.add_u64(x179, x205, u64(fiat.u1(x217))) + x220, x221 := bits.add_u64(x181, x207, u64(fiat.u1(x219))) + x222 := (u64(fiat.u1(x221)) + u64(fiat.u1(x182))) + x224, x223 := bits.mul_u64(x3, arg1[5]) + x226, x225 := bits.mul_u64(x3, arg1[4]) + x228, x227 := bits.mul_u64(x3, arg1[3]) + x230, x229 := bits.mul_u64(x3, arg1[2]) + x232, x231 := bits.mul_u64(x3, arg1[1]) + x234, x233 := bits.mul_u64(x3, arg1[0]) + x235, x236 := bits.add_u64(x234, x231, u64(0x0)) + x237, x238 := bits.add_u64(x232, x229, u64(fiat.u1(x236))) + x239, x240 := bits.add_u64(x230, x227, u64(fiat.u1(x238))) + x241, x242 := bits.add_u64(x228, x225, u64(fiat.u1(x240))) + x243, x244 := bits.add_u64(x226, x223, u64(fiat.u1(x242))) + x245 := (u64(fiat.u1(x244)) + x224) + x246, x247 := bits.add_u64(x210, x233, u64(0x0)) + x248, x249 := bits.add_u64(x212, x235, u64(fiat.u1(x247))) + x250, x251 := bits.add_u64(x214, x237, u64(fiat.u1(x249))) + x252, x253 := bits.add_u64(x216, x239, u64(fiat.u1(x251))) + x254, x255 := bits.add_u64(x218, x241, u64(fiat.u1(x253))) + x256, x257 := bits.add_u64(x220, x243, u64(fiat.u1(x255))) + x258, x259 := bits.add_u64(x222, x245, u64(fiat.u1(x257))) + _, x260 := bits.mul_u64(x246, 0x100000001) + x263, x262 := bits.mul_u64(x260, 0xffffffffffffffff) + x265, x264 := bits.mul_u64(x260, 0xffffffffffffffff) + x267, x266 := bits.mul_u64(x260, 0xffffffffffffffff) + x269, x268 := bits.mul_u64(x260, 0xfffffffffffffffe) + x271, x270 := bits.mul_u64(x260, 0xffffffff00000000) + x273, x272 := bits.mul_u64(x260, 0xffffffff) + x274, x275 := bits.add_u64(x273, x270, u64(0x0)) + x276, x277 := bits.add_u64(x271, x268, u64(fiat.u1(x275))) + x278, x279 := bits.add_u64(x269, x266, u64(fiat.u1(x277))) + x280, x281 := bits.add_u64(x267, x264, u64(fiat.u1(x279))) + x282, x283 := bits.add_u64(x265, x262, u64(fiat.u1(x281))) + x284 := (u64(fiat.u1(x283)) + x263) + _, x286 := bits.add_u64(x246, x272, u64(0x0)) + x287, x288 := bits.add_u64(x248, x274, u64(fiat.u1(x286))) + x289, x290 := bits.add_u64(x250, x276, u64(fiat.u1(x288))) + x291, x292 := bits.add_u64(x252, x278, u64(fiat.u1(x290))) + x293, x294 := bits.add_u64(x254, x280, u64(fiat.u1(x292))) + x295, x296 := bits.add_u64(x256, x282, u64(fiat.u1(x294))) + x297, x298 := bits.add_u64(x258, x284, u64(fiat.u1(x296))) + x299 := (u64(fiat.u1(x298)) + u64(fiat.u1(x259))) + x301, x300 := bits.mul_u64(x4, arg1[5]) + x303, x302 := bits.mul_u64(x4, arg1[4]) + x305, x304 := bits.mul_u64(x4, arg1[3]) + x307, x306 := bits.mul_u64(x4, arg1[2]) + x309, x308 := bits.mul_u64(x4, arg1[1]) + x311, x310 := bits.mul_u64(x4, arg1[0]) + x312, x313 := bits.add_u64(x311, x308, u64(0x0)) + x314, x315 := bits.add_u64(x309, x306, u64(fiat.u1(x313))) + x316, x317 := bits.add_u64(x307, x304, u64(fiat.u1(x315))) + x318, x319 := bits.add_u64(x305, x302, u64(fiat.u1(x317))) + x320, x321 := bits.add_u64(x303, x300, u64(fiat.u1(x319))) + x322 := (u64(fiat.u1(x321)) + x301) + x323, x324 := bits.add_u64(x287, x310, u64(0x0)) + x325, x326 := bits.add_u64(x289, x312, u64(fiat.u1(x324))) + x327, x328 := bits.add_u64(x291, x314, u64(fiat.u1(x326))) + x329, x330 := bits.add_u64(x293, x316, u64(fiat.u1(x328))) + x331, x332 := bits.add_u64(x295, x318, u64(fiat.u1(x330))) + x333, x334 := bits.add_u64(x297, x320, u64(fiat.u1(x332))) + x335, x336 := bits.add_u64(x299, x322, u64(fiat.u1(x334))) + _, x337 := bits.mul_u64(x323, 0x100000001) + x340, x339 := bits.mul_u64(x337, 0xffffffffffffffff) + x342, x341 := bits.mul_u64(x337, 0xffffffffffffffff) + x344, x343 := bits.mul_u64(x337, 0xffffffffffffffff) + x346, x345 := bits.mul_u64(x337, 0xfffffffffffffffe) + x348, x347 := bits.mul_u64(x337, 0xffffffff00000000) + x350, x349 := bits.mul_u64(x337, 0xffffffff) + x351, x352 := bits.add_u64(x350, x347, u64(0x0)) + x353, x354 := bits.add_u64(x348, x345, u64(fiat.u1(x352))) + x355, x356 := bits.add_u64(x346, x343, u64(fiat.u1(x354))) + x357, x358 := bits.add_u64(x344, x341, u64(fiat.u1(x356))) + x359, x360 := bits.add_u64(x342, x339, u64(fiat.u1(x358))) + x361 := (u64(fiat.u1(x360)) + x340) + _, x363 := bits.add_u64(x323, x349, u64(0x0)) + x364, x365 := bits.add_u64(x325, x351, u64(fiat.u1(x363))) + x366, x367 := bits.add_u64(x327, x353, u64(fiat.u1(x365))) + x368, x369 := bits.add_u64(x329, x355, u64(fiat.u1(x367))) + x370, x371 := bits.add_u64(x331, x357, u64(fiat.u1(x369))) + x372, x373 := bits.add_u64(x333, x359, u64(fiat.u1(x371))) + x374, x375 := bits.add_u64(x335, x361, u64(fiat.u1(x373))) + x376 := (u64(fiat.u1(x375)) + u64(fiat.u1(x336))) + x378, x377 := bits.mul_u64(x5, arg1[5]) + x380, x379 := bits.mul_u64(x5, arg1[4]) + x382, x381 := bits.mul_u64(x5, arg1[3]) + x384, x383 := bits.mul_u64(x5, arg1[2]) + x386, x385 := bits.mul_u64(x5, arg1[1]) + x388, x387 := bits.mul_u64(x5, arg1[0]) + x389, x390 := bits.add_u64(x388, x385, u64(0x0)) + x391, x392 := bits.add_u64(x386, x383, u64(fiat.u1(x390))) + x393, x394 := bits.add_u64(x384, x381, u64(fiat.u1(x392))) + x395, x396 := bits.add_u64(x382, x379, u64(fiat.u1(x394))) + x397, x398 := bits.add_u64(x380, x377, u64(fiat.u1(x396))) + x399 := (u64(fiat.u1(x398)) + x378) + x400, x401 := bits.add_u64(x364, x387, u64(0x0)) + x402, x403 := bits.add_u64(x366, x389, u64(fiat.u1(x401))) + x404, x405 := bits.add_u64(x368, x391, u64(fiat.u1(x403))) + x406, x407 := bits.add_u64(x370, x393, u64(fiat.u1(x405))) + x408, x409 := bits.add_u64(x372, x395, u64(fiat.u1(x407))) + x410, x411 := bits.add_u64(x374, x397, u64(fiat.u1(x409))) + x412, x413 := bits.add_u64(x376, x399, u64(fiat.u1(x411))) + _, x414 := bits.mul_u64(x400, 0x100000001) + x417, x416 := bits.mul_u64(x414, 0xffffffffffffffff) + x419, x418 := bits.mul_u64(x414, 0xffffffffffffffff) + x421, x420 := bits.mul_u64(x414, 0xffffffffffffffff) + x423, x422 := bits.mul_u64(x414, 0xfffffffffffffffe) + x425, x424 := bits.mul_u64(x414, 0xffffffff00000000) + x427, x426 := bits.mul_u64(x414, 0xffffffff) + x428, x429 := bits.add_u64(x427, x424, u64(0x0)) + x430, x431 := bits.add_u64(x425, x422, u64(fiat.u1(x429))) + x432, x433 := bits.add_u64(x423, x420, u64(fiat.u1(x431))) + x434, x435 := bits.add_u64(x421, x418, u64(fiat.u1(x433))) + x436, x437 := bits.add_u64(x419, x416, u64(fiat.u1(x435))) + x438 := (u64(fiat.u1(x437)) + x417) + _, x440 := bits.add_u64(x400, x426, u64(0x0)) + x441, x442 := bits.add_u64(x402, x428, u64(fiat.u1(x440))) + x443, x444 := bits.add_u64(x404, x430, u64(fiat.u1(x442))) + x445, x446 := bits.add_u64(x406, x432, u64(fiat.u1(x444))) + x447, x448 := bits.add_u64(x408, x434, u64(fiat.u1(x446))) + x449, x450 := bits.add_u64(x410, x436, u64(fiat.u1(x448))) + x451, x452 := bits.add_u64(x412, x438, u64(fiat.u1(x450))) + x453 := (u64(fiat.u1(x452)) + u64(fiat.u1(x413))) + x454, x455 := bits.sub_u64(x441, 0xffffffff, u64(0x0)) + x456, x457 := bits.sub_u64(x443, 0xffffffff00000000, u64(fiat.u1(x455))) + x458, x459 := bits.sub_u64(x445, 0xfffffffffffffffe, u64(fiat.u1(x457))) + x460, x461 := bits.sub_u64(x447, 0xffffffffffffffff, u64(fiat.u1(x459))) + x462, x463 := bits.sub_u64(x449, 0xffffffffffffffff, u64(fiat.u1(x461))) + x464, x465 := bits.sub_u64(x451, 0xffffffffffffffff, u64(fiat.u1(x463))) + _, x467 := bits.sub_u64(x453, u64(0x0), u64(fiat.u1(x465))) + x468 := fiat.cmovznz_u64(fiat.u1(x467), x454, x441) + x469 := fiat.cmovznz_u64(fiat.u1(x467), x456, x443) + x470 := fiat.cmovznz_u64(fiat.u1(x467), x458, x445) + x471 := fiat.cmovznz_u64(fiat.u1(x467), x460, x447) + x472 := fiat.cmovznz_u64(fiat.u1(x467), x462, x449) + x473 := fiat.cmovznz_u64(fiat.u1(x467), x464, x451) + out1[0] = x468 + out1[1] = x469 + out1[2] = x470 + out1[3] = x471 + out1[4] = x472 + out1[5] = x473 +} + +fe_add :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) { + x1, x2 := bits.add_u64(arg1[0], arg2[0], u64(0x0)) + x3, x4 := bits.add_u64(arg1[1], arg2[1], u64(fiat.u1(x2))) + x5, x6 := bits.add_u64(arg1[2], arg2[2], u64(fiat.u1(x4))) + x7, x8 := bits.add_u64(arg1[3], arg2[3], u64(fiat.u1(x6))) + x9, x10 := bits.add_u64(arg1[4], arg2[4], u64(fiat.u1(x8))) + x11, x12 := bits.add_u64(arg1[5], arg2[5], u64(fiat.u1(x10))) + x13, x14 := bits.sub_u64(x1, 0xffffffff, u64(0x0)) + x15, x16 := bits.sub_u64(x3, 0xffffffff00000000, u64(fiat.u1(x14))) + x17, x18 := bits.sub_u64(x5, 0xfffffffffffffffe, u64(fiat.u1(x16))) + x19, x20 := bits.sub_u64(x7, 0xffffffffffffffff, u64(fiat.u1(x18))) + x21, x22 := bits.sub_u64(x9, 0xffffffffffffffff, u64(fiat.u1(x20))) + x23, x24 := bits.sub_u64(x11, 0xffffffffffffffff, u64(fiat.u1(x22))) + _, x26 := bits.sub_u64(u64(fiat.u1(x12)), u64(0x0), u64(fiat.u1(x24))) + x27 := fiat.cmovznz_u64(fiat.u1(x26), x13, x1) + x28 := fiat.cmovznz_u64(fiat.u1(x26), x15, x3) + x29 := fiat.cmovznz_u64(fiat.u1(x26), x17, x5) + x30 := fiat.cmovznz_u64(fiat.u1(x26), x19, x7) + x31 := fiat.cmovznz_u64(fiat.u1(x26), x21, x9) + x32 := fiat.cmovznz_u64(fiat.u1(x26), x23, x11) + out1[0] = x27 + out1[1] = x28 + out1[2] = x29 + out1[3] = x30 + out1[4] = x31 + out1[5] = x32 +} + +fe_sub :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) { + x1, x2 := bits.sub_u64(arg1[0], arg2[0], u64(0x0)) + x3, x4 := bits.sub_u64(arg1[1], arg2[1], u64(fiat.u1(x2))) + x5, x6 := bits.sub_u64(arg1[2], arg2[2], u64(fiat.u1(x4))) + x7, x8 := bits.sub_u64(arg1[3], arg2[3], u64(fiat.u1(x6))) + x9, x10 := bits.sub_u64(arg1[4], arg2[4], u64(fiat.u1(x8))) + x11, x12 := bits.sub_u64(arg1[5], arg2[5], u64(fiat.u1(x10))) + x13 := fiat.cmovznz_u64(fiat.u1(x12), u64(0x0), 0xffffffffffffffff) + x14, x15 := bits.add_u64(x1, (x13 & 0xffffffff), u64(0x0)) + x16, x17 := bits.add_u64(x3, (x13 & 0xffffffff00000000), u64(fiat.u1(x15))) + x18, x19 := bits.add_u64(x5, (x13 & 0xfffffffffffffffe), u64(fiat.u1(x17))) + x20, x21 := bits.add_u64(x7, x13, u64(fiat.u1(x19))) + x22, x23 := bits.add_u64(x9, x13, u64(fiat.u1(x21))) + x24, _ := bits.add_u64(x11, x13, u64(fiat.u1(x23))) + out1[0] = x14 + out1[1] = x16 + out1[2] = x18 + out1[3] = x20 + out1[4] = x22 + out1[5] = x24 +} + +fe_opp :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) { + x1, x2 := bits.sub_u64(u64(0x0), arg1[0], u64(0x0)) + x3, x4 := bits.sub_u64(u64(0x0), arg1[1], u64(fiat.u1(x2))) + x5, x6 := bits.sub_u64(u64(0x0), arg1[2], u64(fiat.u1(x4))) + x7, x8 := bits.sub_u64(u64(0x0), arg1[3], u64(fiat.u1(x6))) + x9, x10 := bits.sub_u64(u64(0x0), arg1[4], u64(fiat.u1(x8))) + x11, x12 := bits.sub_u64(u64(0x0), arg1[5], u64(fiat.u1(x10))) + x13 := fiat.cmovznz_u64(fiat.u1(x12), u64(0x0), 0xffffffffffffffff) + x14, x15 := bits.add_u64(x1, (x13 & 0xffffffff), u64(0x0)) + x16, x17 := bits.add_u64(x3, (x13 & 0xffffffff00000000), u64(fiat.u1(x15))) + x18, x19 := bits.add_u64(x5, (x13 & 0xfffffffffffffffe), u64(fiat.u1(x17))) + x20, x21 := bits.add_u64(x7, x13, u64(fiat.u1(x19))) + x22, x23 := bits.add_u64(x9, x13, u64(fiat.u1(x21))) + x24, _ := bits.add_u64(x11, x13, u64(fiat.u1(x23))) + out1[0] = x14 + out1[1] = x16 + out1[2] = x18 + out1[3] = x20 + out1[4] = x22 + out1[5] = x24 +} + +fe_one :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element) { + out1[0] = 0xffffffff00000001 + out1[1] = 0xffffffff + out1[2] = 0x1 + out1[3] = 0x0 + out1[4] = 0x0 + out1[5] = 0x0 +} + +fe_non_zero :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) -> u64 { + return (arg1[0] | (arg1[1] | (arg1[2] | (arg1[3] | (arg1[4] | arg1[5]))))) +} + +@(optimization_mode = "none") +fe_cond_assign :: #force_no_inline proc "contextless" ( + out1, arg1: ^Montgomery_Domain_Field_Element, + arg2: int, +) { + x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0]) + x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1]) + x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2]) + x4 := fiat.cmovznz_u64(fiat.u1(arg2), out1[3], arg1[3]) + x5 := fiat.cmovznz_u64(fiat.u1(arg2), out1[4], arg1[4]) + x6 := fiat.cmovznz_u64(fiat.u1(arg2), out1[5], arg1[5]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 + out1[5] = x6 +} + +fe_from_montgomery :: proc "contextless" ( + out1: ^Non_Montgomery_Domain_Field_Element, + arg1: ^Montgomery_Domain_Field_Element, +) { + x1 := arg1[0] + _, x2 := bits.mul_u64(x1, 0x100000001) + x5, x4 := bits.mul_u64(x2, 0xffffffffffffffff) + x7, x6 := bits.mul_u64(x2, 0xffffffffffffffff) + x9, x8 := bits.mul_u64(x2, 0xffffffffffffffff) + x11, x10 := bits.mul_u64(x2, 0xfffffffffffffffe) + x13, x12 := bits.mul_u64(x2, 0xffffffff00000000) + x15, x14 := bits.mul_u64(x2, 0xffffffff) + x16, x17 := bits.add_u64(x15, x12, u64(0x0)) + x18, x19 := bits.add_u64(x13, x10, u64(fiat.u1(x17))) + x20, x21 := bits.add_u64(x11, x8, u64(fiat.u1(x19))) + x22, x23 := bits.add_u64(x9, x6, u64(fiat.u1(x21))) + x24, x25 := bits.add_u64(x7, x4, u64(fiat.u1(x23))) + _, x27 := bits.add_u64(x1, x14, u64(0x0)) + x28, x29 := bits.add_u64(u64(0x0), x16, u64(fiat.u1(x27))) + x30, x31 := bits.add_u64(u64(0x0), x18, u64(fiat.u1(x29))) + x32, x33 := bits.add_u64(u64(0x0), x20, u64(fiat.u1(x31))) + x34, x35 := bits.add_u64(u64(0x0), x22, u64(fiat.u1(x33))) + x36, x37 := bits.add_u64(u64(0x0), x24, u64(fiat.u1(x35))) + x38, x39 := bits.add_u64(u64(0x0), (u64(fiat.u1(x25)) + x5), u64(fiat.u1(x37))) + x40, x41 := bits.add_u64(x28, arg1[1], u64(0x0)) + x42, x43 := bits.add_u64(x30, u64(0x0), u64(fiat.u1(x41))) + x44, x45 := bits.add_u64(x32, u64(0x0), u64(fiat.u1(x43))) + x46, x47 := bits.add_u64(x34, u64(0x0), u64(fiat.u1(x45))) + x48, x49 := bits.add_u64(x36, u64(0x0), u64(fiat.u1(x47))) + x50, x51 := bits.add_u64(x38, u64(0x0), u64(fiat.u1(x49))) + _, x52 := bits.mul_u64(x40, 0x100000001) + x55, x54 := bits.mul_u64(x52, 0xffffffffffffffff) + x57, x56 := bits.mul_u64(x52, 0xffffffffffffffff) + x59, x58 := bits.mul_u64(x52, 0xffffffffffffffff) + x61, x60 := bits.mul_u64(x52, 0xfffffffffffffffe) + x63, x62 := bits.mul_u64(x52, 0xffffffff00000000) + x65, x64 := bits.mul_u64(x52, 0xffffffff) + x66, x67 := bits.add_u64(x65, x62, u64(0x0)) + x68, x69 := bits.add_u64(x63, x60, u64(fiat.u1(x67))) + x70, x71 := bits.add_u64(x61, x58, u64(fiat.u1(x69))) + x72, x73 := bits.add_u64(x59, x56, u64(fiat.u1(x71))) + x74, x75 := bits.add_u64(x57, x54, u64(fiat.u1(x73))) + _, x77 := bits.add_u64(x40, x64, u64(0x0)) + x78, x79 := bits.add_u64(x42, x66, u64(fiat.u1(x77))) + x80, x81 := bits.add_u64(x44, x68, u64(fiat.u1(x79))) + x82, x83 := bits.add_u64(x46, x70, u64(fiat.u1(x81))) + x84, x85 := bits.add_u64(x48, x72, u64(fiat.u1(x83))) + x86, x87 := bits.add_u64(x50, x74, u64(fiat.u1(x85))) + x88, x89 := bits.add_u64((u64(fiat.u1(x51)) + u64(fiat.u1(x39))), (u64(fiat.u1(x75)) + x55), u64(fiat.u1(x87))) + x90, x91 := bits.add_u64(x78, arg1[2], u64(0x0)) + x92, x93 := bits.add_u64(x80, u64(0x0), u64(fiat.u1(x91))) + x94, x95 := bits.add_u64(x82, u64(0x0), u64(fiat.u1(x93))) + x96, x97 := bits.add_u64(x84, u64(0x0), u64(fiat.u1(x95))) + x98, x99 := bits.add_u64(x86, u64(0x0), u64(fiat.u1(x97))) + x100, x101 := bits.add_u64(x88, u64(0x0), u64(fiat.u1(x99))) + _, x102 := bits.mul_u64(x90, 0x100000001) + x105, x104 := bits.mul_u64(x102, 0xffffffffffffffff) + x107, x106 := bits.mul_u64(x102, 0xffffffffffffffff) + x109, x108 := bits.mul_u64(x102, 0xffffffffffffffff) + x111, x110 := bits.mul_u64(x102, 0xfffffffffffffffe) + x113, x112 := bits.mul_u64(x102, 0xffffffff00000000) + x115, x114 := bits.mul_u64(x102, 0xffffffff) + x116, x117 := bits.add_u64(x115, x112, u64(0x0)) + x118, x119 := bits.add_u64(x113, x110, u64(fiat.u1(x117))) + x120, x121 := bits.add_u64(x111, x108, u64(fiat.u1(x119))) + x122, x123 := bits.add_u64(x109, x106, u64(fiat.u1(x121))) + x124, x125 := bits.add_u64(x107, x104, u64(fiat.u1(x123))) + _, x127 := bits.add_u64(x90, x114, u64(0x0)) + x128, x129 := bits.add_u64(x92, x116, u64(fiat.u1(x127))) + x130, x131 := bits.add_u64(x94, x118, u64(fiat.u1(x129))) + x132, x133 := bits.add_u64(x96, x120, u64(fiat.u1(x131))) + x134, x135 := bits.add_u64(x98, x122, u64(fiat.u1(x133))) + x136, x137 := bits.add_u64(x100, x124, u64(fiat.u1(x135))) + x138, x139 := bits.add_u64((u64(fiat.u1(x101)) + u64(fiat.u1(x89))), (u64(fiat.u1(x125)) + x105), u64(fiat.u1(x137))) + x140, x141 := bits.add_u64(x128, arg1[3], u64(0x0)) + x142, x143 := bits.add_u64(x130, u64(0x0), u64(fiat.u1(x141))) + x144, x145 := bits.add_u64(x132, u64(0x0), u64(fiat.u1(x143))) + x146, x147 := bits.add_u64(x134, u64(0x0), u64(fiat.u1(x145))) + x148, x149 := bits.add_u64(x136, u64(0x0), u64(fiat.u1(x147))) + x150, x151 := bits.add_u64(x138, u64(0x0), u64(fiat.u1(x149))) + _, x152 := bits.mul_u64(x140, 0x100000001) + x155, x154 := bits.mul_u64(x152, 0xffffffffffffffff) + x157, x156 := bits.mul_u64(x152, 0xffffffffffffffff) + x159, x158 := bits.mul_u64(x152, 0xffffffffffffffff) + x161, x160 := bits.mul_u64(x152, 0xfffffffffffffffe) + x163, x162 := bits.mul_u64(x152, 0xffffffff00000000) + x165, x164 := bits.mul_u64(x152, 0xffffffff) + x166, x167 := bits.add_u64(x165, x162, u64(0x0)) + x168, x169 := bits.add_u64(x163, x160, u64(fiat.u1(x167))) + x170, x171 := bits.add_u64(x161, x158, u64(fiat.u1(x169))) + x172, x173 := bits.add_u64(x159, x156, u64(fiat.u1(x171))) + x174, x175 := bits.add_u64(x157, x154, u64(fiat.u1(x173))) + _, x177 := bits.add_u64(x140, x164, u64(0x0)) + x178, x179 := bits.add_u64(x142, x166, u64(fiat.u1(x177))) + x180, x181 := bits.add_u64(x144, x168, u64(fiat.u1(x179))) + x182, x183 := bits.add_u64(x146, x170, u64(fiat.u1(x181))) + x184, x185 := bits.add_u64(x148, x172, u64(fiat.u1(x183))) + x186, x187 := bits.add_u64(x150, x174, u64(fiat.u1(x185))) + x188, x189 := bits.add_u64((u64(fiat.u1(x151)) + u64(fiat.u1(x139))), (u64(fiat.u1(x175)) + x155), u64(fiat.u1(x187))) + x190, x191 := bits.add_u64(x178, arg1[4], u64(0x0)) + x192, x193 := bits.add_u64(x180, u64(0x0), u64(fiat.u1(x191))) + x194, x195 := bits.add_u64(x182, u64(0x0), u64(fiat.u1(x193))) + x196, x197 := bits.add_u64(x184, u64(0x0), u64(fiat.u1(x195))) + x198, x199 := bits.add_u64(x186, u64(0x0), u64(fiat.u1(x197))) + x200, x201 := bits.add_u64(x188, u64(0x0), u64(fiat.u1(x199))) + _, x202 := bits.mul_u64(x190, 0x100000001) + x205, x204 := bits.mul_u64(x202, 0xffffffffffffffff) + x207, x206 := bits.mul_u64(x202, 0xffffffffffffffff) + x209, x208 := bits.mul_u64(x202, 0xffffffffffffffff) + x211, x210 := bits.mul_u64(x202, 0xfffffffffffffffe) + x213, x212 := bits.mul_u64(x202, 0xffffffff00000000) + x215, x214 := bits.mul_u64(x202, 0xffffffff) + x216, x217 := bits.add_u64(x215, x212, u64(0x0)) + x218, x219 := bits.add_u64(x213, x210, u64(fiat.u1(x217))) + x220, x221 := bits.add_u64(x211, x208, u64(fiat.u1(x219))) + x222, x223 := bits.add_u64(x209, x206, u64(fiat.u1(x221))) + x224, x225 := bits.add_u64(x207, x204, u64(fiat.u1(x223))) + _, x227 := bits.add_u64(x190, x214, u64(0x0)) + x228, x229 := bits.add_u64(x192, x216, u64(fiat.u1(x227))) + x230, x231 := bits.add_u64(x194, x218, u64(fiat.u1(x229))) + x232, x233 := bits.add_u64(x196, x220, u64(fiat.u1(x231))) + x234, x235 := bits.add_u64(x198, x222, u64(fiat.u1(x233))) + x236, x237 := bits.add_u64(x200, x224, u64(fiat.u1(x235))) + x238, x239 := bits.add_u64((u64(fiat.u1(x201)) + u64(fiat.u1(x189))), (u64(fiat.u1(x225)) + x205), u64(fiat.u1(x237))) + x240, x241 := bits.add_u64(x228, arg1[5], u64(0x0)) + x242, x243 := bits.add_u64(x230, u64(0x0), u64(fiat.u1(x241))) + x244, x245 := bits.add_u64(x232, u64(0x0), u64(fiat.u1(x243))) + x246, x247 := bits.add_u64(x234, u64(0x0), u64(fiat.u1(x245))) + x248, x249 := bits.add_u64(x236, u64(0x0), u64(fiat.u1(x247))) + x250, x251 := bits.add_u64(x238, u64(0x0), u64(fiat.u1(x249))) + _, x252 := bits.mul_u64(x240, 0x100000001) + x255, x254 := bits.mul_u64(x252, 0xffffffffffffffff) + x257, x256 := bits.mul_u64(x252, 0xffffffffffffffff) + x259, x258 := bits.mul_u64(x252, 0xffffffffffffffff) + x261, x260 := bits.mul_u64(x252, 0xfffffffffffffffe) + x263, x262 := bits.mul_u64(x252, 0xffffffff00000000) + x265, x264 := bits.mul_u64(x252, 0xffffffff) + x266, x267 := bits.add_u64(x265, x262, u64(0x0)) + x268, x269 := bits.add_u64(x263, x260, u64(fiat.u1(x267))) + x270, x271 := bits.add_u64(x261, x258, u64(fiat.u1(x269))) + x272, x273 := bits.add_u64(x259, x256, u64(fiat.u1(x271))) + x274, x275 := bits.add_u64(x257, x254, u64(fiat.u1(x273))) + _, x277 := bits.add_u64(x240, x264, u64(0x0)) + x278, x279 := bits.add_u64(x242, x266, u64(fiat.u1(x277))) + x280, x281 := bits.add_u64(x244, x268, u64(fiat.u1(x279))) + x282, x283 := bits.add_u64(x246, x270, u64(fiat.u1(x281))) + x284, x285 := bits.add_u64(x248, x272, u64(fiat.u1(x283))) + x286, x287 := bits.add_u64(x250, x274, u64(fiat.u1(x285))) + x288, x289 := bits.add_u64((u64(fiat.u1(x251)) + u64(fiat.u1(x239))), (u64(fiat.u1(x275)) + x255), u64(fiat.u1(x287))) + x290, x291 := bits.sub_u64(x278, 0xffffffff, u64(0x0)) + x292, x293 := bits.sub_u64(x280, 0xffffffff00000000, u64(fiat.u1(x291))) + x294, x295 := bits.sub_u64(x282, 0xfffffffffffffffe, u64(fiat.u1(x293))) + x296, x297 := bits.sub_u64(x284, 0xffffffffffffffff, u64(fiat.u1(x295))) + x298, x299 := bits.sub_u64(x286, 0xffffffffffffffff, u64(fiat.u1(x297))) + x300, x301 := bits.sub_u64(x288, 0xffffffffffffffff, u64(fiat.u1(x299))) + _, x303 := bits.sub_u64(u64(fiat.u1(x289)), u64(0x0), u64(fiat.u1(x301))) + x304 := fiat.cmovznz_u64(fiat.u1(x303), x290, x278) + x305 := fiat.cmovznz_u64(fiat.u1(x303), x292, x280) + x306 := fiat.cmovznz_u64(fiat.u1(x303), x294, x282) + x307 := fiat.cmovznz_u64(fiat.u1(x303), x296, x284) + x308 := fiat.cmovznz_u64(fiat.u1(x303), x298, x286) + x309 := fiat.cmovznz_u64(fiat.u1(x303), x300, x288) + out1[0] = x304 + out1[1] = x305 + out1[2] = x306 + out1[3] = x307 + out1[4] = x308 + out1[5] = x309 +} + +fe_to_montgomery :: proc "contextless" ( + out1: ^Montgomery_Domain_Field_Element, + arg1: ^Non_Montgomery_Domain_Field_Element, +) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[4] + x5 := arg1[5] + x6 := arg1[0] + x8, x7 := bits.mul_u64(x6, 0x200000000) + x10, x9 := bits.mul_u64(x6, 0xfffffffe00000000) + x12, x11 := bits.mul_u64(x6, 0x200000000) + x14, x13 := bits.mul_u64(x6, 0xfffffffe00000001) + x15, x16 := bits.add_u64(x14, x11, u64(0x0)) + x17, x18 := bits.add_u64(x12, x9, u64(fiat.u1(x16))) + x19, x20 := bits.add_u64(x10, x7, u64(fiat.u1(x18))) + x21, x22 := bits.add_u64(x8, x6, u64(fiat.u1(x20))) + _, x23 := bits.mul_u64(x13, 0x100000001) + x26, x25 := bits.mul_u64(x23, 0xffffffffffffffff) + x28, x27 := bits.mul_u64(x23, 0xffffffffffffffff) + x30, x29 := bits.mul_u64(x23, 0xffffffffffffffff) + x32, x31 := bits.mul_u64(x23, 0xfffffffffffffffe) + x34, x33 := bits.mul_u64(x23, 0xffffffff00000000) + x36, x35 := bits.mul_u64(x23, 0xffffffff) + x37, x38 := bits.add_u64(x36, x33, u64(0x0)) + x39, x40 := bits.add_u64(x34, x31, u64(fiat.u1(x38))) + x41, x42 := bits.add_u64(x32, x29, u64(fiat.u1(x40))) + x43, x44 := bits.add_u64(x30, x27, u64(fiat.u1(x42))) + x45, x46 := bits.add_u64(x28, x25, u64(fiat.u1(x44))) + _, x48 := bits.add_u64(x13, x35, u64(0x0)) + x49, x50 := bits.add_u64(x15, x37, u64(fiat.u1(x48))) + x51, x52 := bits.add_u64(x17, x39, u64(fiat.u1(x50))) + x53, x54 := bits.add_u64(x19, x41, u64(fiat.u1(x52))) + x55, x56 := bits.add_u64(x21, x43, u64(fiat.u1(x54))) + x57, x58 := bits.add_u64(u64(fiat.u1(x22)), x45, u64(fiat.u1(x56))) + x59, x60 := bits.add_u64(u64(0x0), (u64(fiat.u1(x46)) + x26), u64(fiat.u1(x58))) + x62, x61 := bits.mul_u64(x1, 0x200000000) + x64, x63 := bits.mul_u64(x1, 0xfffffffe00000000) + x66, x65 := bits.mul_u64(x1, 0x200000000) + x68, x67 := bits.mul_u64(x1, 0xfffffffe00000001) + x69, x70 := bits.add_u64(x68, x65, u64(0x0)) + x71, x72 := bits.add_u64(x66, x63, u64(fiat.u1(x70))) + x73, x74 := bits.add_u64(x64, x61, u64(fiat.u1(x72))) + x75, x76 := bits.add_u64(x62, x1, u64(fiat.u1(x74))) + x77, x78 := bits.add_u64(x49, x67, u64(0x0)) + x79, x80 := bits.add_u64(x51, x69, u64(fiat.u1(x78))) + x81, x82 := bits.add_u64(x53, x71, u64(fiat.u1(x80))) + x83, x84 := bits.add_u64(x55, x73, u64(fiat.u1(x82))) + x85, x86 := bits.add_u64(x57, x75, u64(fiat.u1(x84))) + x87, x88 := bits.add_u64(x59, u64(fiat.u1(x76)), u64(fiat.u1(x86))) + _, x89 := bits.mul_u64(x77, 0x100000001) + x92, x91 := bits.mul_u64(x89, 0xffffffffffffffff) + x94, x93 := bits.mul_u64(x89, 0xffffffffffffffff) + x96, x95 := bits.mul_u64(x89, 0xffffffffffffffff) + x98, x97 := bits.mul_u64(x89, 0xfffffffffffffffe) + x100, x99 := bits.mul_u64(x89, 0xffffffff00000000) + x102, x101 := bits.mul_u64(x89, 0xffffffff) + x103, x104 := bits.add_u64(x102, x99, u64(0x0)) + x105, x106 := bits.add_u64(x100, x97, u64(fiat.u1(x104))) + x107, x108 := bits.add_u64(x98, x95, u64(fiat.u1(x106))) + x109, x110 := bits.add_u64(x96, x93, u64(fiat.u1(x108))) + x111, x112 := bits.add_u64(x94, x91, u64(fiat.u1(x110))) + _, x114 := bits.add_u64(x77, x101, u64(0x0)) + x115, x116 := bits.add_u64(x79, x103, u64(fiat.u1(x114))) + x117, x118 := bits.add_u64(x81, x105, u64(fiat.u1(x116))) + x119, x120 := bits.add_u64(x83, x107, u64(fiat.u1(x118))) + x121, x122 := bits.add_u64(x85, x109, u64(fiat.u1(x120))) + x123, x124 := bits.add_u64(x87, x111, u64(fiat.u1(x122))) + x125, x126 := bits.add_u64((u64(fiat.u1(x88)) + u64(fiat.u1(x60))), (u64(fiat.u1(x112)) + x92), u64(fiat.u1(x124))) + x128, x127 := bits.mul_u64(x2, 0x200000000) + x130, x129 := bits.mul_u64(x2, 0xfffffffe00000000) + x132, x131 := bits.mul_u64(x2, 0x200000000) + x134, x133 := bits.mul_u64(x2, 0xfffffffe00000001) + x135, x136 := bits.add_u64(x134, x131, u64(0x0)) + x137, x138 := bits.add_u64(x132, x129, u64(fiat.u1(x136))) + x139, x140 := bits.add_u64(x130, x127, u64(fiat.u1(x138))) + x141, x142 := bits.add_u64(x128, x2, u64(fiat.u1(x140))) + x143, x144 := bits.add_u64(x115, x133, u64(0x0)) + x145, x146 := bits.add_u64(x117, x135, u64(fiat.u1(x144))) + x147, x148 := bits.add_u64(x119, x137, u64(fiat.u1(x146))) + x149, x150 := bits.add_u64(x121, x139, u64(fiat.u1(x148))) + x151, x152 := bits.add_u64(x123, x141, u64(fiat.u1(x150))) + x153, x154 := bits.add_u64(x125, u64(fiat.u1(x142)), u64(fiat.u1(x152))) + _, x155 := bits.mul_u64(x143, 0x100000001) + x158, x157 := bits.mul_u64(x155, 0xffffffffffffffff) + x160, x159 := bits.mul_u64(x155, 0xffffffffffffffff) + x162, x161 := bits.mul_u64(x155, 0xffffffffffffffff) + x164, x163 := bits.mul_u64(x155, 0xfffffffffffffffe) + x166, x165 := bits.mul_u64(x155, 0xffffffff00000000) + x168, x167 := bits.mul_u64(x155, 0xffffffff) + x169, x170 := bits.add_u64(x168, x165, u64(0x0)) + x171, x172 := bits.add_u64(x166, x163, u64(fiat.u1(x170))) + x173, x174 := bits.add_u64(x164, x161, u64(fiat.u1(x172))) + x175, x176 := bits.add_u64(x162, x159, u64(fiat.u1(x174))) + x177, x178 := bits.add_u64(x160, x157, u64(fiat.u1(x176))) + _, x180 := bits.add_u64(x143, x167, u64(0x0)) + x181, x182 := bits.add_u64(x145, x169, u64(fiat.u1(x180))) + x183, x184 := bits.add_u64(x147, x171, u64(fiat.u1(x182))) + x185, x186 := bits.add_u64(x149, x173, u64(fiat.u1(x184))) + x187, x188 := bits.add_u64(x151, x175, u64(fiat.u1(x186))) + x189, x190 := bits.add_u64(x153, x177, u64(fiat.u1(x188))) + x191, x192 := bits.add_u64((u64(fiat.u1(x154)) + u64(fiat.u1(x126))), (u64(fiat.u1(x178)) + x158), u64(fiat.u1(x190))) + x194, x193 := bits.mul_u64(x3, 0x200000000) + x196, x195 := bits.mul_u64(x3, 0xfffffffe00000000) + x198, x197 := bits.mul_u64(x3, 0x200000000) + x200, x199 := bits.mul_u64(x3, 0xfffffffe00000001) + x201, x202 := bits.add_u64(x200, x197, u64(0x0)) + x203, x204 := bits.add_u64(x198, x195, u64(fiat.u1(x202))) + x205, x206 := bits.add_u64(x196, x193, u64(fiat.u1(x204))) + x207, x208 := bits.add_u64(x194, x3, u64(fiat.u1(x206))) + x209, x210 := bits.add_u64(x181, x199, u64(0x0)) + x211, x212 := bits.add_u64(x183, x201, u64(fiat.u1(x210))) + x213, x214 := bits.add_u64(x185, x203, u64(fiat.u1(x212))) + x215, x216 := bits.add_u64(x187, x205, u64(fiat.u1(x214))) + x217, x218 := bits.add_u64(x189, x207, u64(fiat.u1(x216))) + x219, x220 := bits.add_u64(x191, u64(fiat.u1(x208)), u64(fiat.u1(x218))) + _, x221 := bits.mul_u64(x209, 0x100000001) + x224, x223 := bits.mul_u64(x221, 0xffffffffffffffff) + x226, x225 := bits.mul_u64(x221, 0xffffffffffffffff) + x228, x227 := bits.mul_u64(x221, 0xffffffffffffffff) + x230, x229 := bits.mul_u64(x221, 0xfffffffffffffffe) + x232, x231 := bits.mul_u64(x221, 0xffffffff00000000) + x234, x233 := bits.mul_u64(x221, 0xffffffff) + x235, x236 := bits.add_u64(x234, x231, u64(0x0)) + x237, x238 := bits.add_u64(x232, x229, u64(fiat.u1(x236))) + x239, x240 := bits.add_u64(x230, x227, u64(fiat.u1(x238))) + x241, x242 := bits.add_u64(x228, x225, u64(fiat.u1(x240))) + x243, x244 := bits.add_u64(x226, x223, u64(fiat.u1(x242))) + _, x246 := bits.add_u64(x209, x233, u64(0x0)) + x247, x248 := bits.add_u64(x211, x235, u64(fiat.u1(x246))) + x249, x250 := bits.add_u64(x213, x237, u64(fiat.u1(x248))) + x251, x252 := bits.add_u64(x215, x239, u64(fiat.u1(x250))) + x253, x254 := bits.add_u64(x217, x241, u64(fiat.u1(x252))) + x255, x256 := bits.add_u64(x219, x243, u64(fiat.u1(x254))) + x257, x258 := bits.add_u64((u64(fiat.u1(x220)) + u64(fiat.u1(x192))), (u64(fiat.u1(x244)) + x224), u64(fiat.u1(x256))) + x260, x259 := bits.mul_u64(x4, 0x200000000) + x262, x261 := bits.mul_u64(x4, 0xfffffffe00000000) + x264, x263 := bits.mul_u64(x4, 0x200000000) + x266, x265 := bits.mul_u64(x4, 0xfffffffe00000001) + x267, x268 := bits.add_u64(x266, x263, u64(0x0)) + x269, x270 := bits.add_u64(x264, x261, u64(fiat.u1(x268))) + x271, x272 := bits.add_u64(x262, x259, u64(fiat.u1(x270))) + x273, x274 := bits.add_u64(x260, x4, u64(fiat.u1(x272))) + x275, x276 := bits.add_u64(x247, x265, u64(0x0)) + x277, x278 := bits.add_u64(x249, x267, u64(fiat.u1(x276))) + x279, x280 := bits.add_u64(x251, x269, u64(fiat.u1(x278))) + x281, x282 := bits.add_u64(x253, x271, u64(fiat.u1(x280))) + x283, x284 := bits.add_u64(x255, x273, u64(fiat.u1(x282))) + x285, x286 := bits.add_u64(x257, u64(fiat.u1(x274)), u64(fiat.u1(x284))) + _, x287 := bits.mul_u64(x275, 0x100000001) + x290, x289 := bits.mul_u64(x287, 0xffffffffffffffff) + x292, x291 := bits.mul_u64(x287, 0xffffffffffffffff) + x294, x293 := bits.mul_u64(x287, 0xffffffffffffffff) + x296, x295 := bits.mul_u64(x287, 0xfffffffffffffffe) + x298, x297 := bits.mul_u64(x287, 0xffffffff00000000) + x300, x299 := bits.mul_u64(x287, 0xffffffff) + x301, x302 := bits.add_u64(x300, x297, u64(0x0)) + x303, x304 := bits.add_u64(x298, x295, u64(fiat.u1(x302))) + x305, x306 := bits.add_u64(x296, x293, u64(fiat.u1(x304))) + x307, x308 := bits.add_u64(x294, x291, u64(fiat.u1(x306))) + x309, x310 := bits.add_u64(x292, x289, u64(fiat.u1(x308))) + _, x312 := bits.add_u64(x275, x299, u64(0x0)) + x313, x314 := bits.add_u64(x277, x301, u64(fiat.u1(x312))) + x315, x316 := bits.add_u64(x279, x303, u64(fiat.u1(x314))) + x317, x318 := bits.add_u64(x281, x305, u64(fiat.u1(x316))) + x319, x320 := bits.add_u64(x283, x307, u64(fiat.u1(x318))) + x321, x322 := bits.add_u64(x285, x309, u64(fiat.u1(x320))) + x323, x324 := bits.add_u64((u64(fiat.u1(x286)) + u64(fiat.u1(x258))), (u64(fiat.u1(x310)) + x290), u64(fiat.u1(x322))) + x326, x325 := bits.mul_u64(x5, 0x200000000) + x328, x327 := bits.mul_u64(x5, 0xfffffffe00000000) + x330, x329 := bits.mul_u64(x5, 0x200000000) + x332, x331 := bits.mul_u64(x5, 0xfffffffe00000001) + x333, x334 := bits.add_u64(x332, x329, u64(0x0)) + x335, x336 := bits.add_u64(x330, x327, u64(fiat.u1(x334))) + x337, x338 := bits.add_u64(x328, x325, u64(fiat.u1(x336))) + x339, x340 := bits.add_u64(x326, x5, u64(fiat.u1(x338))) + x341, x342 := bits.add_u64(x313, x331, u64(0x0)) + x343, x344 := bits.add_u64(x315, x333, u64(fiat.u1(x342))) + x345, x346 := bits.add_u64(x317, x335, u64(fiat.u1(x344))) + x347, x348 := bits.add_u64(x319, x337, u64(fiat.u1(x346))) + x349, x350 := bits.add_u64(x321, x339, u64(fiat.u1(x348))) + x351, x352 := bits.add_u64(x323, u64(fiat.u1(x340)), u64(fiat.u1(x350))) + _, x353 := bits.mul_u64(x341, 0x100000001) + x356, x355 := bits.mul_u64(x353, 0xffffffffffffffff) + x358, x357 := bits.mul_u64(x353, 0xffffffffffffffff) + x360, x359 := bits.mul_u64(x353, 0xffffffffffffffff) + x362, x361 := bits.mul_u64(x353, 0xfffffffffffffffe) + x364, x363 := bits.mul_u64(x353, 0xffffffff00000000) + x366, x365 := bits.mul_u64(x353, 0xffffffff) + x367, x368 := bits.add_u64(x366, x363, u64(0x0)) + x369, x370 := bits.add_u64(x364, x361, u64(fiat.u1(x368))) + x371, x372 := bits.add_u64(x362, x359, u64(fiat.u1(x370))) + x373, x374 := bits.add_u64(x360, x357, u64(fiat.u1(x372))) + x375, x376 := bits.add_u64(x358, x355, u64(fiat.u1(x374))) + _, x378 := bits.add_u64(x341, x365, u64(0x0)) + x379, x380 := bits.add_u64(x343, x367, u64(fiat.u1(x378))) + x381, x382 := bits.add_u64(x345, x369, u64(fiat.u1(x380))) + x383, x384 := bits.add_u64(x347, x371, u64(fiat.u1(x382))) + x385, x386 := bits.add_u64(x349, x373, u64(fiat.u1(x384))) + x387, x388 := bits.add_u64(x351, x375, u64(fiat.u1(x386))) + x389, x390 := bits.add_u64((u64(fiat.u1(x352)) + u64(fiat.u1(x324))), (u64(fiat.u1(x376)) + x356), u64(fiat.u1(x388))) + x391, x392 := bits.sub_u64(x379, 0xffffffff, u64(0x0)) + x393, x394 := bits.sub_u64(x381, 0xffffffff00000000, u64(fiat.u1(x392))) + x395, x396 := bits.sub_u64(x383, 0xfffffffffffffffe, u64(fiat.u1(x394))) + x397, x398 := bits.sub_u64(x385, 0xffffffffffffffff, u64(fiat.u1(x396))) + x399, x400 := bits.sub_u64(x387, 0xffffffffffffffff, u64(fiat.u1(x398))) + x401, x402 := bits.sub_u64(x389, 0xffffffffffffffff, u64(fiat.u1(x400))) + _, x404 := bits.sub_u64(u64(fiat.u1(x390)), u64(0x0), u64(fiat.u1(x402))) + x405 := fiat.cmovznz_u64(fiat.u1(x404), x391, x379) + x406 := fiat.cmovznz_u64(fiat.u1(x404), x393, x381) + x407 := fiat.cmovznz_u64(fiat.u1(x404), x395, x383) + x408 := fiat.cmovznz_u64(fiat.u1(x404), x397, x385) + x409 := fiat.cmovznz_u64(fiat.u1(x404), x399, x387) + x410 := fiat.cmovznz_u64(fiat.u1(x404), x401, x389) + out1[0] = x405 + out1[1] = x406 + out1[2] = x407 + out1[3] = x408 + out1[4] = x409 + out1[5] = x410 +} diff --git a/core/crypto/_fiat/field_poly1305/field.odin b/core/crypto/_fiat/field_poly1305/field.odin index caaece98e..244ddceb8 100644 --- a/core/crypto/_fiat/field_poly1305/field.odin +++ b/core/crypto/_fiat/field_poly1305/field.odin @@ -1,7 +1,7 @@ package field_poly1305 +import "core:crypto" import "core:encoding/endian" -import "core:mem" fe_relax_cast :: #force_inline proc "contextless" ( arg1: ^Tight_Field_Element, @@ -57,7 +57,7 @@ fe_from_u64s :: proc "contextless" (out1: ^Tight_Field_Element, lo, hi: u64) { _fe_from_bytes(out1, &tmp) // This routine is only used to deserialize `r` which is confidential. - mem.zero_explicit(&tmp, size_of(tmp)) + crypto.zero_explicit(&tmp, size_of(tmp)) } fe_zero :: proc "contextless" (out1: ^Tight_Field_Element) { diff --git a/core/crypto/_fiat/field_scalar25519/field.odin b/core/crypto/_fiat/field_scalar25519/field.odin index 933637c54..181a6ce8d 100644 --- a/core/crypto/_fiat/field_scalar25519/field.odin +++ b/core/crypto/_fiat/field_scalar25519/field.odin @@ -1,8 +1,9 @@ package field_scalar25519 +import "core:crypto" +import subtle "core:crypto/_subtle" import "core:encoding/endian" import "core:math/bits" -import "core:mem" @(private, rodata) _TWO_168 := Montgomery_Domain_Field_Element { @@ -20,7 +21,7 @@ _TWO_336 := Montgomery_Domain_Field_Element { } fe_clear :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) { - mem.zero_explicit(arg1, size_of(Montgomery_Domain_Field_Element)) + crypto.zero_explicit(arg1, size_of(Montgomery_Domain_Field_Element)) } fe_from_bytes :: proc "contextless" ( @@ -34,7 +35,7 @@ fe_from_bytes :: proc "contextless" ( endian.unchecked_get_u64le(arg1[16:]), endian.unchecked_get_u64le(arg1[24:]), } - defer mem.zero_explicit(&tmp, size_of(tmp)) + defer crypto.zero_explicit(&tmp, size_of(tmp)) // Check that tmp is in the the range [0, ELL). if !unsafe_assume_canonical { @@ -66,7 +67,7 @@ fe_from_bytes_rfc8032 :: proc "contextless" ( fe_from_bytes_wide(out1, &tmp) - mem.zero_explicit(&tmp, size_of(tmp)) + crypto.zero_explicit(&tmp, size_of(tmp)) } fe_from_bytes_wide :: proc "contextless" ( @@ -100,7 +101,7 @@ _fe_from_bytes_short :: proc "contextless" (out1: ^Montgomery_Domain_Field_Eleme copy(tmp[:], arg1) _ = fe_from_bytes(out1, &tmp, true) - mem.zero_explicit(&tmp, size_of(tmp)) + crypto.zero_explicit(&tmp, size_of(tmp)) } fe_to_bytes :: proc "contextless" (out1: []byte, arg1: ^Montgomery_Domain_Field_Element) { @@ -114,20 +115,18 @@ fe_to_bytes :: proc "contextless" (out1: []byte, arg1: ^Montgomery_Domain_Field_ endian.unchecked_put_u64le(out1[16:], tmp[2]) endian.unchecked_put_u64le(out1[24:], tmp[3]) - mem.zero_explicit(&tmp, size_of(tmp)) + crypto.zero_explicit(&tmp, size_of(tmp)) } fe_equal :: proc "contextless" (arg1, arg2: ^Montgomery_Domain_Field_Element) -> int { tmp: Montgomery_Domain_Field_Element fe_sub(&tmp, arg1, arg2) - // This will only underflow iff arg1 == arg2, and we return the borrow, - // which will be 1. - _, borrow := bits.sub_u64(fe_non_zero(&tmp), 1, 0) + is_eq := subtle.eq(fe_non_zero(&tmp), 0) fe_clear(&tmp) - return int(borrow) + return int(is_eq) } fe_zero :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element) { diff --git a/core/crypto/_fiat/field_scalarp256r1/field.odin b/core/crypto/_fiat/field_scalarp256r1/field.odin new file mode 100644 index 000000000..802f3382e --- /dev/null +++ b/core/crypto/_fiat/field_scalarp256r1/field.odin @@ -0,0 +1,478 @@ +package field_scalarp256r1 + +import "core:crypto" +import subtle "core:crypto/_subtle" +import "core:encoding/endian" +import "core:math/bits" + +@(private, rodata) +TWO_192 := Montgomery_Domain_Field_Element{ + 2482910415990817935, + 2879494685571067143, + 8732918506673730078, + 85565669603516024, +} +@(private, rodata) +TWO_384 := Montgomery_Domain_Field_Element{ + 2127524300190691059, + 17014302137236182484, + 16604910261202196099, + 3621421107472562910, +} +// 2^384 % p (From sage) +// 0x431905529c0166ce652e96b7ccca0a99679b73e19ad16947f01cf013fc632551 + +fe_clear :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) { + crypto.zero_explicit(arg1, size_of(Montgomery_Domain_Field_Element)) +} + +fe_clear_vec :: proc "contextless" ( + arg1: []^Montgomery_Domain_Field_Element, +) { + for fe in arg1 { + fe_clear(fe) + } +} + +fe_from_bytes :: proc "contextless" ( + out1: ^Montgomery_Domain_Field_Element, + arg1: []byte, +) -> bool { + ensure_contextless(len(out1) <= 64, "p256r1: invalid scalar input buffer") + + is_canonical := false + s_len := len(arg1) + switch { + case s_len < 32: + // No way this can be greater than the order. + fe_unchecked_set(out1, arg1) + is_canonical = true + case s_len == 32: + // It is quite likely that a reduction mod p is required, + // as the order of the curve is sufficiently smaller than + // 2^256-1, so just check if we actually needed to reduced + // and do the reduction anyway, so that things that require + // canonical scalars can reject non-canonical encodings. + is_canonical = fe_is_canonical(arg1) + fallthrough + case: + // Use Frank Denis' trick, as documented by Filippo Valsorda + // at https://words.filippo.io/dispatches/wide-reduction/ + // + // "I represent the value as a+b*2^192+c*2^384" + // + // Note: Omitting the `c` computation is fine as, reduction + // being length dependent provides no useful timing information. + + // Zero extend to 512-bits. + src_512: [64]byte + copy(src_512[64-s_len:], arg1) + defer crypto.zero_explicit(&src_512, size_of(src_512)) + + fe_unchecked_set(out1, src_512[40:]) // a + b: Montgomery_Domain_Field_Element + fe_unchecked_set(&b, src_512[16:40]) // b + + fe_mul(&b, &b, &TWO_192) + fe_add(out1, out1, &b) + if s_len >= 48 { + c: Montgomery_Domain_Field_Element + fe_unchecked_set(&c, src_512[:16]) // c + fe_mul(&c, &c, &TWO_384) + fe_add(out1, out1, &c) + + fe_clear(&c) + } + + fe_clear(&b) + } + + return !is_canonical +} + +@(private) +fe_is_canonical :: proc "contextless" (arg1: []byte) -> bool { + _, borrow := bits.sub_u64(ELL[0] - 1, endian.unchecked_get_u64be(arg1[24:]), 0) + _, borrow = bits.sub_u64(ELL[1], endian.unchecked_get_u64be(arg1[16:]), borrow) + _, borrow = bits.sub_u64(ELL[2], endian.unchecked_get_u64be(arg1[8:]), borrow) + _, borrow = bits.sub_u64(ELL[3], endian.unchecked_get_u64be(arg1[0:]), borrow) + return borrow == 0 +} + +@(private) +fe_unchecked_set :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element, arg1: []byte) { + arg1_256: [32]byte + defer crypto.zero_explicit(&arg1_256, size_of(arg1_256)) + copy(arg1_256[32-len(arg1):], arg1) + + tmp := Non_Montgomery_Domain_Field_Element { + endian.unchecked_get_u64be(arg1_256[24:]), + endian.unchecked_get_u64be(arg1_256[16:]), + endian.unchecked_get_u64be(arg1_256[8:]), + endian.unchecked_get_u64be(arg1_256[0:]), + } + defer crypto.zero_explicit(&tmp, size_of(tmp)) + + fe_to_montgomery(out1, &tmp) +} + +fe_to_bytes :: proc "contextless" (out1: []byte, arg1: ^Montgomery_Domain_Field_Element) { + ensure_contextless(len(out1) == 32, "p256r1: invalid scalar output buffer") + + tmp: Non_Montgomery_Domain_Field_Element = --- + fe_from_montgomery(&tmp, arg1) + + // Note: Likewise, output in big-endian. + endian.unchecked_put_u64be(out1[24:], tmp[0]) + endian.unchecked_put_u64be(out1[16:], tmp[1]) + endian.unchecked_put_u64be(out1[8:], tmp[2]) + endian.unchecked_put_u64be(out1[0:], tmp[3]) + + crypto.zero_explicit(&tmp, size_of(tmp)) +} + +fe_equal :: proc "contextless" (arg1, arg2: ^Montgomery_Domain_Field_Element) -> int { + tmp: Montgomery_Domain_Field_Element = --- + fe_sub(&tmp, arg1, arg2) + + is_eq := subtle.eq(fe_non_zero(&tmp), 0) + + fe_clear(&tmp) + + return int(is_eq) +} + +fe_is_odd :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) -> int { + tmp: Non_Montgomery_Domain_Field_Element = --- + defer crypto.zero_explicit(&tmp, size_of(tmp)) + + fe_from_montgomery(&tmp, arg1) + return int(tmp[0] & 1) +} + +fe_zero :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element) { + out1[0] = 0 + out1[1] = 0 + out1[2] = 0 + out1[3] = 0 +} + +fe_set :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) { + x1 := arg1[0] + x2 := arg1[1] + x3 := arg1[2] + x4 := arg1[3] + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 +} + +@(optimization_mode = "none") +fe_cond_swap :: #force_no_inline proc "contextless" (out1, out2: ^Montgomery_Domain_Field_Element, arg1: int) { + mask := (u64(arg1) * 0xffffffffffffffff) + x := (out1[0] ~ out2[0]) & mask + x1, y1 := out1[0] ~ x, out2[0] ~ x + x = (out1[1] ~ out2[1]) & mask + x2, y2 := out1[1] ~ x, out2[1] ~ x + x = (out1[2] ~ out2[2]) & mask + x3, y3 := out1[2] ~ x, out2[2] ~ x + x = (out1[3] ~ out2[3]) & mask + x4, y4 := out1[3] ~ x, out2[3] ~ x + out1[0], out2[0] = x1, y1 + out1[1], out2[1] = x2, y2 + out1[2], out2[2] = x3, y3 + out1[3], out2[3] = x4, y4 +} + +@(optimization_mode = "none") +fe_cond_select :: #force_no_inline proc "contextless" ( + out1, arg1, arg2: ^Montgomery_Domain_Field_Element, + arg3: int, +) { + mask := (u64(arg3) * 0xffffffffffffffff) + x1 := ((mask & arg2[0]) | ((~mask) & arg1[0])) + x2 := ((mask & arg2[1]) | ((~mask) & arg1[1])) + x3 := ((mask & arg2[2]) | ((~mask) & arg1[2])) + x4 := ((mask & arg2[3]) | ((~mask) & arg1[3])) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 +} + +fe_cond_negate :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element, ctrl: int) { + tmp1: Montgomery_Domain_Field_Element = --- + fe_opp(&tmp1, arg1) + fe_cond_select(out1, arg1, &tmp1, ctrl) + + fe_clear(&tmp1) +} + +fe_pow2k :: proc "contextless" ( + out1: ^Montgomery_Domain_Field_Element, + arg1: ^Montgomery_Domain_Field_Element, + arg2: uint, +) { + // Special case: `arg1^(2 * 0) = 1`, though this should never happen. + if arg2 == 0 { + fe_one(out1) + return + } + + fe_square(out1, arg1) + for _ in 1 ..< arg2 { + fe_square(out1, out1) + } +} + +fe_inv :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) { + // Inversion computation is derived from the addition chain: + // + // _10 = 2*1 + // _100 = 2*_10 + // _101 = 1 + _100 + // _110 = 1 + _101 + // _1001 = _100 + _101 + // _1111 = _110 + _1001 + // _10010 = 2*_1001 + // _10101 = _110 + _1111 + // _11000 = _110 + _10010 + // _11010 = _10 + _11000 + // _101111 = _10101 + _11010 + // _111000 = _1001 + _101111 + // _111101 = _101 + _111000 + // _111111 = _10 + _111101 + // _1001111 = _10010 + _111101 + // _1100001 = _10010 + _1001111 + // _1100011 = _10 + _1100001 + // _1110011 = _10010 + _1100001 + // _1110111 = _100 + _1110011 + // _1111101 = _110 + _1110111 + // _10010101 = _11000 + _1111101 + // _10100111 = _10010 + _10010101 + // _10101101 = _110 + _10100111 + // _11100101 = _111000 + _10101101 + // _11111111 = _11010 + _11100101 + // x16 = _11111111 << 8 + _11111111 + // x32 = x16 << 16 + x16 + // i133 = ((x32 << 48 + x16) << 16 + x16) << 16 + // i158 = ((x16 + i133) << 16 + x16) << 6 + _101111 + // i186 = ((i158 << 9 + _1110011) << 8 + _1111101) << 9 + // i206 = ((_10101101 + i186) << 8 + _10100111) << 9 + _101111 + // i236 = ((i206 << 8 + _111101) << 11 + _1001111) << 9 + // i257 = ((_1110111 + i236) << 10 + _11100101) << 8 + _1100001 + // i286 = ((i257 << 7 + _111111) << 10 + _1100011) << 10 + // return (_10010101 + i286) << 6 + _1111 + // + // Operations: 251 squares 43 multiplies + // + // Generated by github.com/mmcloughlin/addchain v0.4.0. + + // Note: Need to stash `arg1` (`xx`) in the case that `out1`/`arg1` alias, + // as `arg1` is used after `out1` has been altered. + t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, xx: Montgomery_Domain_Field_Element = ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, arg1^ + + // Step 1: t1 = x^0x2 + fe_square(&t1, arg1) + + // Step 2: t5 = x^0x4 + fe_square(&t5, &t1) + + // Step 3: t2 = x^0x5 + fe_mul(&t2, arg1, &t5) + + // Step 4: t10 = x^0x6 + fe_mul(&t10, arg1, &t2) + + // Step 5: t3 = x^0x9 + fe_mul(&t3, &t5, &t2) + + // Step 6: z = x^0xf + fe_mul(out1, &t10, &t3) + + // Step 7: t9 = x^0x12 + fe_square(&t9, &t3) + + // Step 8: t4 = x^0x15 + fe_mul(&t4, &t10, out1) + + // Step 9: t0 = x^0x18 + fe_mul(&t0, &t10, &t9) + + // Step 10: t13 = x^0x1a + fe_mul(&t13, &t1, &t0) + + // Step 11: t8 = x^0x2f + fe_mul(&t8, &t4, &t13) + + // Step 12: t4 = x^0x38 + fe_mul(&t4, &t3, &t8) + + // Step 13: t7 = x^0x3d + fe_mul(&t7, &t2, &t4) + + // Step 14: t2 = x^0x3f + fe_mul(&t2, &t1, &t7) + + // Step 15: t6 = x^0x4f + fe_mul(&t6, &t9, &t7) + + // Step 16: t3 = x^0x61 + fe_mul(&t3, &t9, &t6) + + // Step 17: t1 = x^0x63 + fe_mul(&t1, &t1, &t3) + + // Step 18: t12 = x^0x73 + fe_mul(&t12, &t9, &t3) + + // Step 19: t5 = x^0x77 + fe_mul(&t5, &t5, &t12) + + // Step 20: t11 = x^0x7d + fe_mul(&t11, &t10, &t5) + + // Step 21: t0 = x^0x95 + fe_mul(&t0, &t0, &t11) + + // Step 22: t9 = x^0xa7 + fe_mul(&t9, &t9, &t0) + + // Step 23: t10 = x^0xad + fe_mul(&t10, &t10, &t9) + + // Step 24: t4 = x^0xe5 + fe_mul(&t4, &t4, &t10) + + // Step 25: t13 = x^0xff + fe_mul(&t13, &t13, &t4) + + // Step 33: t14 = x^0xff00 + fe_pow2k(&t14, &t13, 8) + + // Step 34: t13 = x^0xffff + fe_mul(&t13, &t13, &t14) + + // Step 50: t14 = x^0xffff0000 + fe_pow2k(&t14, &t13, 16) + + // Step 51: t14 = x^0xffffffff + fe_mul(&t14, &t13, &t14) + + // Step 99: t14 = x^0xffffffff000000000000 + fe_pow2k(&t14, &t14, 48) + + // Step 100: t14 = x^0xffffffff00000000ffff + fe_mul(&t14, &t13, &t14) + + // Step 116: t14 = x^0xffffffff00000000ffff0000 + fe_pow2k(&t14, &t14, 16) + + // Step 117: t14 = x^0xffffffff00000000ffffffff + fe_mul(&t14, &t13, &t14) + + // Step 133: t14 = x^0xffffffff00000000ffffffff0000 + fe_pow2k(&t14, &t14, 16) + + // Step 134: t14 = x^0xffffffff00000000ffffffffffff + fe_mul(&t14, &t13, &t14) + + // Step 150: t14 = x^0xffffffff00000000ffffffffffff0000 + fe_pow2k(&t14, &t14, 16) + + // Step 151: t13 = x^0xffffffff00000000ffffffffffffffff + fe_mul(&t13, &t13, &t14) + + // Step 157: t13 = x^0x3fffffffc00000003fffffffffffffffc0 + fe_pow2k(&t13, &t13, 6) + + // Step 158: t13 = x^0x3fffffffc00000003fffffffffffffffef + fe_mul(&t13, &t8, &t13) + + // Step 167: t13 = x^0x7fffffff800000007fffffffffffffffde00 + fe_pow2k(&t13, &t13, 9) + + // Step 168: t12 = x^0x7fffffff800000007fffffffffffffffde73 + fe_mul(&t12, &t12, &t13) + + // Step 176: t12 = x^0x7fffffff800000007fffffffffffffffde7300 + fe_pow2k(&t12, &t12, 8) + + // Step 177: t11 = x^0x7fffffff800000007fffffffffffffffde737d + fe_mul(&t11, &t11, &t12) + + // Step 186: t11 = x^0xffffffff00000000ffffffffffffffffbce6fa00 + fe_pow2k(&t11, &t11, 9) + + // Step 187: t10 = x^0xffffffff00000000ffffffffffffffffbce6faad + fe_mul(&t10, &t10, &t11) + + // Step 195: t10 = x^0xffffffff00000000ffffffffffffffffbce6faad00 + fe_pow2k(&t10, &t10, 8) + + // Step 196: t9 = x^0xffffffff00000000ffffffffffffffffbce6faada7 + fe_mul(&t9, &t9, &t10) + + // Step 205: t9 = x^0x1fffffffe00000001ffffffffffffffff79cdf55b4e00 + fe_pow2k(&t9, &t9, 9) + + // Step 206: t8 = x^0x1fffffffe00000001ffffffffffffffff79cdf55b4e2f + fe_mul(&t8, &t8, &t9) + + // Step 214: t8 = x^0x1fffffffe00000001ffffffffffffffff79cdf55b4e2f00 + fe_pow2k(&t8, &t8, 8) + + // Step 215: t7 = x^0x1fffffffe00000001ffffffffffffffff79cdf55b4e2f3d + fe_mul(&t7, &t7, &t8) + + // Step 226: t7 = x^0xffffffff00000000ffffffffffffffffbce6faada7179e800 + fe_pow2k(&t7, &t7, 11) + + // Step 227: t6 = x^0xffffffff00000000ffffffffffffffffbce6faada7179e84f + fe_mul(&t6, &t6, &t7) + + // Step 236: t6 = x^0x1fffffffe00000001ffffffffffffffff79cdf55b4e2f3d09e00 + fe_pow2k(&t6, &t6, 9) + + // Step 237: t5 = x^0x1fffffffe00000001ffffffffffffffff79cdf55b4e2f3d09e77 + fe_mul(&t5, &t5, &t6) + + // Step 247: t5 = x^0x7fffffff800000007fffffffffffffffde737d56d38bcf4279dc00 + fe_pow2k(&t5, &t5, 10) + + // Step 248: t4 = x^0x7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5 + fe_mul(&t4, &t4, &t5) + + // Step 256: t4 = x^0x7fffffff800000007fffffffffffffffde737d56d38bcf4279dce500 + fe_pow2k(&t4, &t4, 8) + + // Step 257: t3 = x^0x7fffffff800000007fffffffffffffffde737d56d38bcf4279dce561 + fe_mul(&t3, &t3, &t4) + + // Step 264: t3 = x^0x3fffffffc00000003fffffffffffffffef39beab69c5e7a13cee72b080 + fe_pow2k(&t3, &t3, 7) + + // Step 265: t2 = x^0x3fffffffc00000003fffffffffffffffef39beab69c5e7a13cee72b0bf + fe_mul(&t2, &t2, &t3) + + // Step 275: t2 = x^0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc00 + fe_pow2k(&t2, &t2, 10) + + // Step 276: t1 = x^0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63 + fe_mul(&t1, &t1, &t2) + + // Step 286: t1 = x^0x3fffffffc00000003fffffffffffffffef39beab69c5e7a13cee72b0bf18c00 + fe_pow2k(&t1, &t1, 10) + + // Step 287: t0 = x^0x3fffffffc00000003fffffffffffffffef39beab69c5e7a13cee72b0bf18c95 + fe_mul(&t0, &t0, &t1) + + // Step 293: t0 = x^0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632540 + fe_pow2k(&t0, &t0, 6) + + // Step 294: z = x^0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f + fe_mul(out1, out1, &t0) + + fe_clear_vec([]^Montgomery_Domain_Field_Element{&t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7, &t8, &t9, &t10, &t11, &t12, &t13, &t14, &xx}) +} diff --git a/core/crypto/_fiat/field_scalarp256r1/field64.odin b/core/crypto/_fiat/field_scalarp256r1/field64.odin new file mode 100644 index 000000000..4217374a7 --- /dev/null +++ b/core/crypto/_fiat/field_scalarp256r1/field64.odin @@ -0,0 +1,569 @@ +// The BSD 1-Clause License (BSD-1-Clause) +// +// Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, +// Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package field_scalarp256r1 + +// The file provides arithmetic on the field Z/(2^256 - 2^224 + 2^192 - +// 89188191075325690597107910205041859247) using a 64-bit Montgomery form +// internal representation. It is derived primarily from the machine +// generated Golang output from the fiat-crypto project. +// +// While the base implementation is provably correct, this implementation +// makes no such claims as the port and optimizations were done by hand. +// +// WARNING: While big-endian is the common representation used for this +// curve, the fiat output uses least-significant-limb first. + +import fiat "core:crypto/_fiat" +import "core:math/bits" + +// ELL is the saturated representation of the field order, least-significant +// limb first. +ELL :: [4]u64{0xf3b9cac2fc632551, 0xbce6faada7179e84, 0xffffffffffffffff, 0xffffffff00000000} + +Montgomery_Domain_Field_Element :: distinct [4]u64 +Non_Montgomery_Domain_Field_Element :: distinct [4]u64 + +fe_mul :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + x6, x5 := bits.mul_u64(x4, arg2[3]) + x8, x7 := bits.mul_u64(x4, arg2[2]) + x10, x9 := bits.mul_u64(x4, arg2[1]) + x12, x11 := bits.mul_u64(x4, arg2[0]) + x13, x14 := bits.add_u64(x12, x9, u64(0x0)) + x15, x16 := bits.add_u64(x10, x7, u64(fiat.u1(x14))) + x17, x18 := bits.add_u64(x8, x5, u64(fiat.u1(x16))) + x19 := (u64(fiat.u1(x18)) + x6) + _, x20 := bits.mul_u64(x11, 0xccd1c8aaee00bc4f) + x23, x22 := bits.mul_u64(x20, 0xffffffff00000000) + x25, x24 := bits.mul_u64(x20, 0xffffffffffffffff) + x27, x26 := bits.mul_u64(x20, 0xbce6faada7179e84) + x29, x28 := bits.mul_u64(x20, 0xf3b9cac2fc632551) + x30, x31 := bits.add_u64(x29, x26, u64(0x0)) + x32, x33 := bits.add_u64(x27, x24, u64(fiat.u1(x31))) + x34, x35 := bits.add_u64(x25, x22, u64(fiat.u1(x33))) + x36 := (u64(fiat.u1(x35)) + x23) + _, x38 := bits.add_u64(x11, x28, u64(0x0)) + x39, x40 := bits.add_u64(x13, x30, u64(fiat.u1(x38))) + x41, x42 := bits.add_u64(x15, x32, u64(fiat.u1(x40))) + x43, x44 := bits.add_u64(x17, x34, u64(fiat.u1(x42))) + x45, x46 := bits.add_u64(x19, x36, u64(fiat.u1(x44))) + x48, x47 := bits.mul_u64(x1, arg2[3]) + x50, x49 := bits.mul_u64(x1, arg2[2]) + x52, x51 := bits.mul_u64(x1, arg2[1]) + x54, x53 := bits.mul_u64(x1, arg2[0]) + x55, x56 := bits.add_u64(x54, x51, u64(0x0)) + x57, x58 := bits.add_u64(x52, x49, u64(fiat.u1(x56))) + x59, x60 := bits.add_u64(x50, x47, u64(fiat.u1(x58))) + x61 := (u64(fiat.u1(x60)) + x48) + x62, x63 := bits.add_u64(x39, x53, u64(0x0)) + x64, x65 := bits.add_u64(x41, x55, u64(fiat.u1(x63))) + x66, x67 := bits.add_u64(x43, x57, u64(fiat.u1(x65))) + x68, x69 := bits.add_u64(x45, x59, u64(fiat.u1(x67))) + x70, x71 := bits.add_u64(u64(fiat.u1(x46)), x61, u64(fiat.u1(x69))) + _, x72 := bits.mul_u64(x62, 0xccd1c8aaee00bc4f) + x75, x74 := bits.mul_u64(x72, 0xffffffff00000000) + x77, x76 := bits.mul_u64(x72, 0xffffffffffffffff) + x79, x78 := bits.mul_u64(x72, 0xbce6faada7179e84) + x81, x80 := bits.mul_u64(x72, 0xf3b9cac2fc632551) + x82, x83 := bits.add_u64(x81, x78, u64(0x0)) + x84, x85 := bits.add_u64(x79, x76, u64(fiat.u1(x83))) + x86, x87 := bits.add_u64(x77, x74, u64(fiat.u1(x85))) + x88 := (u64(fiat.u1(x87)) + x75) + _, x90 := bits.add_u64(x62, x80, u64(0x0)) + x91, x92 := bits.add_u64(x64, x82, u64(fiat.u1(x90))) + x93, x94 := bits.add_u64(x66, x84, u64(fiat.u1(x92))) + x95, x96 := bits.add_u64(x68, x86, u64(fiat.u1(x94))) + x97, x98 := bits.add_u64(x70, x88, u64(fiat.u1(x96))) + x99 := (u64(fiat.u1(x98)) + u64(fiat.u1(x71))) + x101, x100 := bits.mul_u64(x2, arg2[3]) + x103, x102 := bits.mul_u64(x2, arg2[2]) + x105, x104 := bits.mul_u64(x2, arg2[1]) + x107, x106 := bits.mul_u64(x2, arg2[0]) + x108, x109 := bits.add_u64(x107, x104, u64(0x0)) + x110, x111 := bits.add_u64(x105, x102, u64(fiat.u1(x109))) + x112, x113 := bits.add_u64(x103, x100, u64(fiat.u1(x111))) + x114 := (u64(fiat.u1(x113)) + x101) + x115, x116 := bits.add_u64(x91, x106, u64(0x0)) + x117, x118 := bits.add_u64(x93, x108, u64(fiat.u1(x116))) + x119, x120 := bits.add_u64(x95, x110, u64(fiat.u1(x118))) + x121, x122 := bits.add_u64(x97, x112, u64(fiat.u1(x120))) + x123, x124 := bits.add_u64(x99, x114, u64(fiat.u1(x122))) + _, x125 := bits.mul_u64(x115, 0xccd1c8aaee00bc4f) + x128, x127 := bits.mul_u64(x125, 0xffffffff00000000) + x130, x129 := bits.mul_u64(x125, 0xffffffffffffffff) + x132, x131 := bits.mul_u64(x125, 0xbce6faada7179e84) + x134, x133 := bits.mul_u64(x125, 0xf3b9cac2fc632551) + x135, x136 := bits.add_u64(x134, x131, u64(0x0)) + x137, x138 := bits.add_u64(x132, x129, u64(fiat.u1(x136))) + x139, x140 := bits.add_u64(x130, x127, u64(fiat.u1(x138))) + x141 := (u64(fiat.u1(x140)) + x128) + _, x143 := bits.add_u64(x115, x133, u64(0x0)) + x144, x145 := bits.add_u64(x117, x135, u64(fiat.u1(x143))) + x146, x147 := bits.add_u64(x119, x137, u64(fiat.u1(x145))) + x148, x149 := bits.add_u64(x121, x139, u64(fiat.u1(x147))) + x150, x151 := bits.add_u64(x123, x141, u64(fiat.u1(x149))) + x152 := (u64(fiat.u1(x151)) + u64(fiat.u1(x124))) + x154, x153 := bits.mul_u64(x3, arg2[3]) + x156, x155 := bits.mul_u64(x3, arg2[2]) + x158, x157 := bits.mul_u64(x3, arg2[1]) + x160, x159 := bits.mul_u64(x3, arg2[0]) + x161, x162 := bits.add_u64(x160, x157, u64(0x0)) + x163, x164 := bits.add_u64(x158, x155, u64(fiat.u1(x162))) + x165, x166 := bits.add_u64(x156, x153, u64(fiat.u1(x164))) + x167 := (u64(fiat.u1(x166)) + x154) + x168, x169 := bits.add_u64(x144, x159, u64(0x0)) + x170, x171 := bits.add_u64(x146, x161, u64(fiat.u1(x169))) + x172, x173 := bits.add_u64(x148, x163, u64(fiat.u1(x171))) + x174, x175 := bits.add_u64(x150, x165, u64(fiat.u1(x173))) + x176, x177 := bits.add_u64(x152, x167, u64(fiat.u1(x175))) + _, x178 := bits.mul_u64(x168, 0xccd1c8aaee00bc4f) + x181, x180 := bits.mul_u64(x178, 0xffffffff00000000) + x183, x182 := bits.mul_u64(x178, 0xffffffffffffffff) + x185, x184 := bits.mul_u64(x178, 0xbce6faada7179e84) + x187, x186 := bits.mul_u64(x178, 0xf3b9cac2fc632551) + x188, x189 := bits.add_u64(x187, x184, u64(0x0)) + x190, x191 := bits.add_u64(x185, x182, u64(fiat.u1(x189))) + x192, x193 := bits.add_u64(x183, x180, u64(fiat.u1(x191))) + x194 := (u64(fiat.u1(x193)) + x181) + _, x196 := bits.add_u64(x168, x186, u64(0x0)) + x197, x198 := bits.add_u64(x170, x188, u64(fiat.u1(x196))) + x199, x200 := bits.add_u64(x172, x190, u64(fiat.u1(x198))) + x201, x202 := bits.add_u64(x174, x192, u64(fiat.u1(x200))) + x203, x204 := bits.add_u64(x176, x194, u64(fiat.u1(x202))) + x205 := (u64(fiat.u1(x204)) + u64(fiat.u1(x177))) + x206, x207 := bits.sub_u64(x197, 0xf3b9cac2fc632551, u64(0x0)) + x208, x209 := bits.sub_u64(x199, 0xbce6faada7179e84, u64(fiat.u1(x207))) + x210, x211 := bits.sub_u64(x201, 0xffffffffffffffff, u64(fiat.u1(x209))) + x212, x213 := bits.sub_u64(x203, 0xffffffff00000000, u64(fiat.u1(x211))) + _, x215 := bits.sub_u64(x205, u64(0x0), u64(fiat.u1(x213))) + x216 := fiat.cmovznz_u64(fiat.u1(x215), x206, x197) + x217 := fiat.cmovznz_u64(fiat.u1(x215), x208, x199) + x218 := fiat.cmovznz_u64(fiat.u1(x215), x210, x201) + x219 := fiat.cmovznz_u64(fiat.u1(x215), x212, x203) + out1[0] = x216 + out1[1] = x217 + out1[2] = x218 + out1[3] = x219 +} + +fe_square :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + x6, x5 := bits.mul_u64(x4, arg1[3]) + x8, x7 := bits.mul_u64(x4, arg1[2]) + x10, x9 := bits.mul_u64(x4, arg1[1]) + x12, x11 := bits.mul_u64(x4, arg1[0]) + x13, x14 := bits.add_u64(x12, x9, u64(0x0)) + x15, x16 := bits.add_u64(x10, x7, u64(fiat.u1(x14))) + x17, x18 := bits.add_u64(x8, x5, u64(fiat.u1(x16))) + x19 := (u64(fiat.u1(x18)) + x6) + _, x20 := bits.mul_u64(x11, 0xccd1c8aaee00bc4f) + x23, x22 := bits.mul_u64(x20, 0xffffffff00000000) + x25, x24 := bits.mul_u64(x20, 0xffffffffffffffff) + x27, x26 := bits.mul_u64(x20, 0xbce6faada7179e84) + x29, x28 := bits.mul_u64(x20, 0xf3b9cac2fc632551) + x30, x31 := bits.add_u64(x29, x26, u64(0x0)) + x32, x33 := bits.add_u64(x27, x24, u64(fiat.u1(x31))) + x34, x35 := bits.add_u64(x25, x22, u64(fiat.u1(x33))) + x36 := (u64(fiat.u1(x35)) + x23) + _, x38 := bits.add_u64(x11, x28, u64(0x0)) + x39, x40 := bits.add_u64(x13, x30, u64(fiat.u1(x38))) + x41, x42 := bits.add_u64(x15, x32, u64(fiat.u1(x40))) + x43, x44 := bits.add_u64(x17, x34, u64(fiat.u1(x42))) + x45, x46 := bits.add_u64(x19, x36, u64(fiat.u1(x44))) + x48, x47 := bits.mul_u64(x1, arg1[3]) + x50, x49 := bits.mul_u64(x1, arg1[2]) + x52, x51 := bits.mul_u64(x1, arg1[1]) + x54, x53 := bits.mul_u64(x1, arg1[0]) + x55, x56 := bits.add_u64(x54, x51, u64(0x0)) + x57, x58 := bits.add_u64(x52, x49, u64(fiat.u1(x56))) + x59, x60 := bits.add_u64(x50, x47, u64(fiat.u1(x58))) + x61 := (u64(fiat.u1(x60)) + x48) + x62, x63 := bits.add_u64(x39, x53, u64(0x0)) + x64, x65 := bits.add_u64(x41, x55, u64(fiat.u1(x63))) + x66, x67 := bits.add_u64(x43, x57, u64(fiat.u1(x65))) + x68, x69 := bits.add_u64(x45, x59, u64(fiat.u1(x67))) + x70, x71 := bits.add_u64(u64(fiat.u1(x46)), x61, u64(fiat.u1(x69))) + _, x72 := bits.mul_u64(x62, 0xccd1c8aaee00bc4f) + x75, x74 := bits.mul_u64(x72, 0xffffffff00000000) + x77, x76 := bits.mul_u64(x72, 0xffffffffffffffff) + x79, x78 := bits.mul_u64(x72, 0xbce6faada7179e84) + x81, x80 := bits.mul_u64(x72, 0xf3b9cac2fc632551) + x82, x83 := bits.add_u64(x81, x78, u64(0x0)) + x84, x85 := bits.add_u64(x79, x76, u64(fiat.u1(x83))) + x86, x87 := bits.add_u64(x77, x74, u64(fiat.u1(x85))) + x88 := (u64(fiat.u1(x87)) + x75) + _, x90 := bits.add_u64(x62, x80, u64(0x0)) + x91, x92 := bits.add_u64(x64, x82, u64(fiat.u1(x90))) + x93, x94 := bits.add_u64(x66, x84, u64(fiat.u1(x92))) + x95, x96 := bits.add_u64(x68, x86, u64(fiat.u1(x94))) + x97, x98 := bits.add_u64(x70, x88, u64(fiat.u1(x96))) + x99 := (u64(fiat.u1(x98)) + u64(fiat.u1(x71))) + x101, x100 := bits.mul_u64(x2, arg1[3]) + x103, x102 := bits.mul_u64(x2, arg1[2]) + x105, x104 := bits.mul_u64(x2, arg1[1]) + x107, x106 := bits.mul_u64(x2, arg1[0]) + x108, x109 := bits.add_u64(x107, x104, u64(0x0)) + x110, x111 := bits.add_u64(x105, x102, u64(fiat.u1(x109))) + x112, x113 := bits.add_u64(x103, x100, u64(fiat.u1(x111))) + x114 := (u64(fiat.u1(x113)) + x101) + x115, x116 := bits.add_u64(x91, x106, u64(0x0)) + x117, x118 := bits.add_u64(x93, x108, u64(fiat.u1(x116))) + x119, x120 := bits.add_u64(x95, x110, u64(fiat.u1(x118))) + x121, x122 := bits.add_u64(x97, x112, u64(fiat.u1(x120))) + x123, x124 := bits.add_u64(x99, x114, u64(fiat.u1(x122))) + _, x125 := bits.mul_u64(x115, 0xccd1c8aaee00bc4f) + x128, x127 := bits.mul_u64(x125, 0xffffffff00000000) + x130, x129 := bits.mul_u64(x125, 0xffffffffffffffff) + x132, x131 := bits.mul_u64(x125, 0xbce6faada7179e84) + x134, x133 := bits.mul_u64(x125, 0xf3b9cac2fc632551) + x135, x136 := bits.add_u64(x134, x131, u64(0x0)) + x137, x138 := bits.add_u64(x132, x129, u64(fiat.u1(x136))) + x139, x140 := bits.add_u64(x130, x127, u64(fiat.u1(x138))) + x141 := (u64(fiat.u1(x140)) + x128) + _, x143 := bits.add_u64(x115, x133, u64(0x0)) + x144, x145 := bits.add_u64(x117, x135, u64(fiat.u1(x143))) + x146, x147 := bits.add_u64(x119, x137, u64(fiat.u1(x145))) + x148, x149 := bits.add_u64(x121, x139, u64(fiat.u1(x147))) + x150, x151 := bits.add_u64(x123, x141, u64(fiat.u1(x149))) + x152 := (u64(fiat.u1(x151)) + u64(fiat.u1(x124))) + x154, x153 := bits.mul_u64(x3, arg1[3]) + x156, x155 := bits.mul_u64(x3, arg1[2]) + x158, x157 := bits.mul_u64(x3, arg1[1]) + x160, x159 := bits.mul_u64(x3, arg1[0]) + x161, x162 := bits.add_u64(x160, x157, u64(0x0)) + x163, x164 := bits.add_u64(x158, x155, u64(fiat.u1(x162))) + x165, x166 := bits.add_u64(x156, x153, u64(fiat.u1(x164))) + x167 := (u64(fiat.u1(x166)) + x154) + x168, x169 := bits.add_u64(x144, x159, u64(0x0)) + x170, x171 := bits.add_u64(x146, x161, u64(fiat.u1(x169))) + x172, x173 := bits.add_u64(x148, x163, u64(fiat.u1(x171))) + x174, x175 := bits.add_u64(x150, x165, u64(fiat.u1(x173))) + x176, x177 := bits.add_u64(x152, x167, u64(fiat.u1(x175))) + _, x178 := bits.mul_u64(x168, 0xccd1c8aaee00bc4f) + x181, x180 := bits.mul_u64(x178, 0xffffffff00000000) + x183, x182 := bits.mul_u64(x178, 0xffffffffffffffff) + x185, x184 := bits.mul_u64(x178, 0xbce6faada7179e84) + x187, x186 := bits.mul_u64(x178, 0xf3b9cac2fc632551) + x188, x189 := bits.add_u64(x187, x184, u64(0x0)) + x190, x191 := bits.add_u64(x185, x182, u64(fiat.u1(x189))) + x192, x193 := bits.add_u64(x183, x180, u64(fiat.u1(x191))) + x194 := (u64(fiat.u1(x193)) + x181) + _, x196 := bits.add_u64(x168, x186, u64(0x0)) + x197, x198 := bits.add_u64(x170, x188, u64(fiat.u1(x196))) + x199, x200 := bits.add_u64(x172, x190, u64(fiat.u1(x198))) + x201, x202 := bits.add_u64(x174, x192, u64(fiat.u1(x200))) + x203, x204 := bits.add_u64(x176, x194, u64(fiat.u1(x202))) + x205 := (u64(fiat.u1(x204)) + u64(fiat.u1(x177))) + x206, x207 := bits.sub_u64(x197, 0xf3b9cac2fc632551, u64(0x0)) + x208, x209 := bits.sub_u64(x199, 0xbce6faada7179e84, u64(fiat.u1(x207))) + x210, x211 := bits.sub_u64(x201, 0xffffffffffffffff, u64(fiat.u1(x209))) + x212, x213 := bits.sub_u64(x203, 0xffffffff00000000, u64(fiat.u1(x211))) + _, x215 := bits.sub_u64(x205, u64(0x0), u64(fiat.u1(x213))) + x216 := fiat.cmovznz_u64(fiat.u1(x215), x206, x197) + x217 := fiat.cmovznz_u64(fiat.u1(x215), x208, x199) + x218 := fiat.cmovznz_u64(fiat.u1(x215), x210, x201) + x219 := fiat.cmovznz_u64(fiat.u1(x215), x212, x203) + out1[0] = x216 + out1[1] = x217 + out1[2] = x218 + out1[3] = x219 +} + +fe_add :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) { + x1, x2 := bits.add_u64(arg1[0], arg2[0], u64(0x0)) + x3, x4 := bits.add_u64(arg1[1], arg2[1], u64(fiat.u1(x2))) + x5, x6 := bits.add_u64(arg1[2], arg2[2], u64(fiat.u1(x4))) + x7, x8 := bits.add_u64(arg1[3], arg2[3], u64(fiat.u1(x6))) + x9, x10 := bits.sub_u64(x1, 0xf3b9cac2fc632551, u64(0x0)) + x11, x12 := bits.sub_u64(x3, 0xbce6faada7179e84, u64(fiat.u1(x10))) + x13, x14 := bits.sub_u64(x5, 0xffffffffffffffff, u64(fiat.u1(x12))) + x15, x16 := bits.sub_u64(x7, 0xffffffff00000000, u64(fiat.u1(x14))) + _, x18 := bits.sub_u64(u64(fiat.u1(x8)), u64(0x0), u64(fiat.u1(x16))) + x19 := fiat.cmovznz_u64(fiat.u1(x18), x9, x1) + x20 := fiat.cmovznz_u64(fiat.u1(x18), x11, x3) + x21 := fiat.cmovznz_u64(fiat.u1(x18), x13, x5) + x22 := fiat.cmovznz_u64(fiat.u1(x18), x15, x7) + out1[0] = x19 + out1[1] = x20 + out1[2] = x21 + out1[3] = x22 +} + +fe_sub :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) { + x1, x2 := bits.sub_u64(arg1[0], arg2[0], u64(0x0)) + x3, x4 := bits.sub_u64(arg1[1], arg2[1], u64(fiat.u1(x2))) + x5, x6 := bits.sub_u64(arg1[2], arg2[2], u64(fiat.u1(x4))) + x7, x8 := bits.sub_u64(arg1[3], arg2[3], u64(fiat.u1(x6))) + x9 := fiat.cmovznz_u64(fiat.u1(x8), u64(0x0), 0xffffffffffffffff) + x10, x11 := bits.add_u64(x1, (x9 & 0xf3b9cac2fc632551), u64(0x0)) + x12, x13 := bits.add_u64(x3, (x9 & 0xbce6faada7179e84), u64(fiat.u1(x11))) + x14, x15 := bits.add_u64(x5, x9, u64(fiat.u1(x13))) + x16, _ := bits.add_u64(x7, (x9 & 0xffffffff00000000), u64(fiat.u1(x15))) + out1[0] = x10 + out1[1] = x12 + out1[2] = x14 + out1[3] = x16 +} + +fe_opp :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) { + x1, x2 := bits.sub_u64(u64(0x0), arg1[0], u64(0x0)) + x3, x4 := bits.sub_u64(u64(0x0), arg1[1], u64(fiat.u1(x2))) + x5, x6 := bits.sub_u64(u64(0x0), arg1[2], u64(fiat.u1(x4))) + x7, x8 := bits.sub_u64(u64(0x0), arg1[3], u64(fiat.u1(x6))) + x9 := fiat.cmovznz_u64(fiat.u1(x8), u64(0x0), 0xffffffffffffffff) + x10, x11 := bits.add_u64(x1, (x9 & 0xf3b9cac2fc632551), u64(0x0)) + x12, x13 := bits.add_u64(x3, (x9 & 0xbce6faada7179e84), u64(fiat.u1(x11))) + x14, x15 := bits.add_u64(x5, x9, u64(fiat.u1(x13))) + x16, _ := bits.add_u64(x7, (x9 & 0xffffffff00000000), u64(fiat.u1(x15))) + out1[0] = x10 + out1[1] = x12 + out1[2] = x14 + out1[3] = x16 +} + +fe_one :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element) { + out1[0] = 0xc46353d039cdaaf + out1[1] = 0x4319055258e8617b + out1[2] = u64(0x0) + out1[3] = 0xffffffff +} + +fe_non_zero :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) -> u64 { + return arg1[0] | (arg1[1] | (arg1[2] | arg1[3])) +} + +@(optimization_mode = "none") +fe_cond_assign :: #force_no_inline proc "contextless" ( + out1, arg1: ^Montgomery_Domain_Field_Element, + arg2: int, +) { + x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0]) + x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1]) + x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2]) + x4 := fiat.cmovznz_u64(fiat.u1(arg2), out1[3], arg1[3]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 +} + +fe_from_montgomery :: proc "contextless" ( + out1: ^Non_Montgomery_Domain_Field_Element, + arg1: ^Montgomery_Domain_Field_Element, +) { + x1 := arg1[0] + _, x2 := bits.mul_u64(x1, 0xccd1c8aaee00bc4f) + x5, x4 := bits.mul_u64(x2, 0xffffffff00000000) + x7, x6 := bits.mul_u64(x2, 0xffffffffffffffff) + x9, x8 := bits.mul_u64(x2, 0xbce6faada7179e84) + x11, x10 := bits.mul_u64(x2, 0xf3b9cac2fc632551) + x12, x13 := bits.add_u64(x11, x8, u64(0x0)) + x14, x15 := bits.add_u64(x9, x6, u64(fiat.u1(x13))) + x16, x17 := bits.add_u64(x7, x4, u64(fiat.u1(x15))) + _, x19 := bits.add_u64(x1, x10, u64(0x0)) + x20, x21 := bits.add_u64(u64(0x0), x12, u64(fiat.u1(x19))) + x22, x23 := bits.add_u64(u64(0x0), x14, u64(fiat.u1(x21))) + x24, x25 := bits.add_u64(u64(0x0), x16, u64(fiat.u1(x23))) + x26, x27 := bits.add_u64(x20, arg1[1], u64(0x0)) + x28, x29 := bits.add_u64(x22, u64(0x0), u64(fiat.u1(x27))) + x30, x31 := bits.add_u64(x24, u64(0x0), u64(fiat.u1(x29))) + _, x32 := bits.mul_u64(x26, 0xccd1c8aaee00bc4f) + x35, x34 := bits.mul_u64(x32, 0xffffffff00000000) + x37, x36 := bits.mul_u64(x32, 0xffffffffffffffff) + x39, x38 := bits.mul_u64(x32, 0xbce6faada7179e84) + x41, x40 := bits.mul_u64(x32, 0xf3b9cac2fc632551) + x42, x43 := bits.add_u64(x41, x38, u64(0x0)) + x44, x45 := bits.add_u64(x39, x36, u64(fiat.u1(x43))) + x46, x47 := bits.add_u64(x37, x34, u64(fiat.u1(x45))) + _, x49 := bits.add_u64(x26, x40, u64(0x0)) + x50, x51 := bits.add_u64(x28, x42, u64(fiat.u1(x49))) + x52, x53 := bits.add_u64(x30, x44, u64(fiat.u1(x51))) + x54, x55 := bits.add_u64((u64(fiat.u1(x31)) + (u64(fiat.u1(x25)) + (u64(fiat.u1(x17)) + x5))), x46, u64(fiat.u1(x53))) + x56, x57 := bits.add_u64(x50, arg1[2], u64(0x0)) + x58, x59 := bits.add_u64(x52, u64(0x0), u64(fiat.u1(x57))) + x60, x61 := bits.add_u64(x54, u64(0x0), u64(fiat.u1(x59))) + _, x62 := bits.mul_u64(x56, 0xccd1c8aaee00bc4f) + x65, x64 := bits.mul_u64(x62, 0xffffffff00000000) + x67, x66 := bits.mul_u64(x62, 0xffffffffffffffff) + x69, x68 := bits.mul_u64(x62, 0xbce6faada7179e84) + x71, x70 := bits.mul_u64(x62, 0xf3b9cac2fc632551) + x72, x73 := bits.add_u64(x71, x68, u64(0x0)) + x74, x75 := bits.add_u64(x69, x66, u64(fiat.u1(x73))) + x76, x77 := bits.add_u64(x67, x64, u64(fiat.u1(x75))) + _, x79 := bits.add_u64(x56, x70, u64(0x0)) + x80, x81 := bits.add_u64(x58, x72, u64(fiat.u1(x79))) + x82, x83 := bits.add_u64(x60, x74, u64(fiat.u1(x81))) + x84, x85 := bits.add_u64((u64(fiat.u1(x61)) + (u64(fiat.u1(x55)) + (u64(fiat.u1(x47)) + x35))), x76, u64(fiat.u1(x83))) + x86, x87 := bits.add_u64(x80, arg1[3], u64(0x0)) + x88, x89 := bits.add_u64(x82, u64(0x0), u64(fiat.u1(x87))) + x90, x91 := bits.add_u64(x84, u64(0x0), u64(fiat.u1(x89))) + _, x92 := bits.mul_u64(x86, 0xccd1c8aaee00bc4f) + x95, x94 := bits.mul_u64(x92, 0xffffffff00000000) + x97, x96 := bits.mul_u64(x92, 0xffffffffffffffff) + x99, x98 := bits.mul_u64(x92, 0xbce6faada7179e84) + x101, x100 := bits.mul_u64(x92, 0xf3b9cac2fc632551) + x102, x103 := bits.add_u64(x101, x98, u64(0x0)) + x104, x105 := bits.add_u64(x99, x96, u64(fiat.u1(x103))) + x106, x107 := bits.add_u64(x97, x94, u64(fiat.u1(x105))) + _, x109 := bits.add_u64(x86, x100, u64(0x0)) + x110, x111 := bits.add_u64(x88, x102, u64(fiat.u1(x109))) + x112, x113 := bits.add_u64(x90, x104, u64(fiat.u1(x111))) + x114, x115 := bits.add_u64((u64(fiat.u1(x91)) + (u64(fiat.u1(x85)) + (u64(fiat.u1(x77)) + x65))), x106, u64(fiat.u1(x113))) + x116 := (u64(fiat.u1(x115)) + (u64(fiat.u1(x107)) + x95)) + x117, x118 := bits.sub_u64(x110, 0xf3b9cac2fc632551, u64(0x0)) + x119, x120 := bits.sub_u64(x112, 0xbce6faada7179e84, u64(fiat.u1(x118))) + x121, x122 := bits.sub_u64(x114, 0xffffffffffffffff, u64(fiat.u1(x120))) + x123, x124 := bits.sub_u64(x116, 0xffffffff00000000, u64(fiat.u1(x122))) + _, x126 := bits.sub_u64(u64(0x0), u64(0x0), u64(fiat.u1(x124))) + x127 := fiat.cmovznz_u64(fiat.u1(x126), x117, x110) + x128 := fiat.cmovznz_u64(fiat.u1(x126), x119, x112) + x129 := fiat.cmovznz_u64(fiat.u1(x126), x121, x114) + x130 := fiat.cmovznz_u64(fiat.u1(x126), x123, x116) + out1[0] = x127 + out1[1] = x128 + out1[2] = x129 + out1[3] = x130 +} + +fe_to_montgomery :: proc "contextless" ( + out1: ^Montgomery_Domain_Field_Element, + arg1: ^Non_Montgomery_Domain_Field_Element, +) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + x6, x5 := bits.mul_u64(x4, 0x66e12d94f3d95620) + x8, x7 := bits.mul_u64(x4, 0x2845b2392b6bec59) + x10, x9 := bits.mul_u64(x4, 0x4699799c49bd6fa6) + x12, x11 := bits.mul_u64(x4, 0x83244c95be79eea2) + x13, x14 := bits.add_u64(x12, x9, u64(0x0)) + x15, x16 := bits.add_u64(x10, x7, u64(fiat.u1(x14))) + x17, x18 := bits.add_u64(x8, x5, u64(fiat.u1(x16))) + _, x19 := bits.mul_u64(x11, 0xccd1c8aaee00bc4f) + x22, x21 := bits.mul_u64(x19, 0xffffffff00000000) + x24, x23 := bits.mul_u64(x19, 0xffffffffffffffff) + x26, x25 := bits.mul_u64(x19, 0xbce6faada7179e84) + x28, x27 := bits.mul_u64(x19, 0xf3b9cac2fc632551) + x29, x30 := bits.add_u64(x28, x25, u64(0x0)) + x31, x32 := bits.add_u64(x26, x23, u64(fiat.u1(x30))) + x33, x34 := bits.add_u64(x24, x21, u64(fiat.u1(x32))) + _, x36 := bits.add_u64(x11, x27, u64(0x0)) + x37, x38 := bits.add_u64(x13, x29, u64(fiat.u1(x36))) + x39, x40 := bits.add_u64(x15, x31, u64(fiat.u1(x38))) + x41, x42 := bits.add_u64(x17, x33, u64(fiat.u1(x40))) + x43, x44 := bits.add_u64((u64(fiat.u1(x18)) + x6), (u64(fiat.u1(x34)) + x22), u64(fiat.u1(x42))) + x46, x45 := bits.mul_u64(x1, 0x66e12d94f3d95620) + x48, x47 := bits.mul_u64(x1, 0x2845b2392b6bec59) + x50, x49 := bits.mul_u64(x1, 0x4699799c49bd6fa6) + x52, x51 := bits.mul_u64(x1, 0x83244c95be79eea2) + x53, x54 := bits.add_u64(x52, x49, u64(0x0)) + x55, x56 := bits.add_u64(x50, x47, u64(fiat.u1(x54))) + x57, x58 := bits.add_u64(x48, x45, u64(fiat.u1(x56))) + x59, x60 := bits.add_u64(x37, x51, u64(0x0)) + x61, x62 := bits.add_u64(x39, x53, u64(fiat.u1(x60))) + x63, x64 := bits.add_u64(x41, x55, u64(fiat.u1(x62))) + x65, x66 := bits.add_u64(x43, x57, u64(fiat.u1(x64))) + _, x67 := bits.mul_u64(x59, 0xccd1c8aaee00bc4f) + x70, x69 := bits.mul_u64(x67, 0xffffffff00000000) + x72, x71 := bits.mul_u64(x67, 0xffffffffffffffff) + x74, x73 := bits.mul_u64(x67, 0xbce6faada7179e84) + x76, x75 := bits.mul_u64(x67, 0xf3b9cac2fc632551) + x77, x78 := bits.add_u64(x76, x73, u64(0x0)) + x79, x80 := bits.add_u64(x74, x71, u64(fiat.u1(x78))) + x81, x82 := bits.add_u64(x72, x69, u64(fiat.u1(x80))) + _, x84 := bits.add_u64(x59, x75, u64(0x0)) + x85, x86 := bits.add_u64(x61, x77, u64(fiat.u1(x84))) + x87, x88 := bits.add_u64(x63, x79, u64(fiat.u1(x86))) + x89, x90 := bits.add_u64(x65, x81, u64(fiat.u1(x88))) + x91, x92 := bits.add_u64(((u64(fiat.u1(x66)) + u64(fiat.u1(x44))) + (u64(fiat.u1(x58)) + x46)), (u64(fiat.u1(x82)) + x70), u64(fiat.u1(x90))) + x94, x93 := bits.mul_u64(x2, 0x66e12d94f3d95620) + x96, x95 := bits.mul_u64(x2, 0x2845b2392b6bec59) + x98, x97 := bits.mul_u64(x2, 0x4699799c49bd6fa6) + x100, x99 := bits.mul_u64(x2, 0x83244c95be79eea2) + x101, x102 := bits.add_u64(x100, x97, u64(0x0)) + x103, x104 := bits.add_u64(x98, x95, u64(fiat.u1(x102))) + x105, x106 := bits.add_u64(x96, x93, u64(fiat.u1(x104))) + x107, x108 := bits.add_u64(x85, x99, u64(0x0)) + x109, x110 := bits.add_u64(x87, x101, u64(fiat.u1(x108))) + x111, x112 := bits.add_u64(x89, x103, u64(fiat.u1(x110))) + x113, x114 := bits.add_u64(x91, x105, u64(fiat.u1(x112))) + _, x115 := bits.mul_u64(x107, 0xccd1c8aaee00bc4f) + x118, x117 := bits.mul_u64(x115, 0xffffffff00000000) + x120, x119 := bits.mul_u64(x115, 0xffffffffffffffff) + x122, x121 := bits.mul_u64(x115, 0xbce6faada7179e84) + x124, x123 := bits.mul_u64(x115, 0xf3b9cac2fc632551) + x125, x126 := bits.add_u64(x124, x121, u64(0x0)) + x127, x128 := bits.add_u64(x122, x119, u64(fiat.u1(x126))) + x129, x130 := bits.add_u64(x120, x117, u64(fiat.u1(x128))) + _, x132 := bits.add_u64(x107, x123, u64(0x0)) + x133, x134 := bits.add_u64(x109, x125, u64(fiat.u1(x132))) + x135, x136 := bits.add_u64(x111, x127, u64(fiat.u1(x134))) + x137, x138 := bits.add_u64(x113, x129, u64(fiat.u1(x136))) + x139, x140 := bits.add_u64(((u64(fiat.u1(x114)) + u64(fiat.u1(x92))) + (u64(fiat.u1(x106)) + x94)), (u64(fiat.u1(x130)) + x118), u64(fiat.u1(x138))) + x142, x141 := bits.mul_u64(x3, 0x66e12d94f3d95620) + x144, x143 := bits.mul_u64(x3, 0x2845b2392b6bec59) + x146, x145 := bits.mul_u64(x3, 0x4699799c49bd6fa6) + x148, x147 := bits.mul_u64(x3, 0x83244c95be79eea2) + x149, x150 := bits.add_u64(x148, x145, u64(0x0)) + x151, x152 := bits.add_u64(x146, x143, u64(fiat.u1(x150))) + x153, x154 := bits.add_u64(x144, x141, u64(fiat.u1(x152))) + x155, x156 := bits.add_u64(x133, x147, u64(0x0)) + x157, x158 := bits.add_u64(x135, x149, u64(fiat.u1(x156))) + x159, x160 := bits.add_u64(x137, x151, u64(fiat.u1(x158))) + x161, x162 := bits.add_u64(x139, x153, u64(fiat.u1(x160))) + _, x163 := bits.mul_u64(x155, 0xccd1c8aaee00bc4f) + x166, x165 := bits.mul_u64(x163, 0xffffffff00000000) + x168, x167 := bits.mul_u64(x163, 0xffffffffffffffff) + x170, x169 := bits.mul_u64(x163, 0xbce6faada7179e84) + x172, x171 := bits.mul_u64(x163, 0xf3b9cac2fc632551) + x173, x174 := bits.add_u64(x172, x169, u64(0x0)) + x175, x176 := bits.add_u64(x170, x167, u64(fiat.u1(x174))) + x177, x178 := bits.add_u64(x168, x165, u64(fiat.u1(x176))) + _, x180 := bits.add_u64(x155, x171, u64(0x0)) + x181, x182 := bits.add_u64(x157, x173, u64(fiat.u1(x180))) + x183, x184 := bits.add_u64(x159, x175, u64(fiat.u1(x182))) + x185, x186 := bits.add_u64(x161, x177, u64(fiat.u1(x184))) + x187, x188 := bits.add_u64(((u64(fiat.u1(x162)) + u64(fiat.u1(x140))) + (u64(fiat.u1(x154)) + x142)), (u64(fiat.u1(x178)) + x166), u64(fiat.u1(x186))) + x189, x190 := bits.sub_u64(x181, 0xf3b9cac2fc632551, u64(0x0)) + x191, x192 := bits.sub_u64(x183, 0xbce6faada7179e84, u64(fiat.u1(x190))) + x193, x194 := bits.sub_u64(x185, 0xffffffffffffffff, u64(fiat.u1(x192))) + x195, x196 := bits.sub_u64(x187, 0xffffffff00000000, u64(fiat.u1(x194))) + _, x198 := bits.sub_u64(u64(fiat.u1(x188)), u64(0x0), u64(fiat.u1(x196))) + x199 := fiat.cmovznz_u64(fiat.u1(x198), x189, x181) + x200 := fiat.cmovznz_u64(fiat.u1(x198), x191, x183) + x201 := fiat.cmovznz_u64(fiat.u1(x198), x193, x185) + x202 := fiat.cmovznz_u64(fiat.u1(x198), x195, x187) + out1[0] = x199 + out1[1] = x200 + out1[2] = x201 + out1[3] = x202 +} diff --git a/core/crypto/_fiat/field_scalarp384r1/field.odin b/core/crypto/_fiat/field_scalarp384r1/field.odin new file mode 100644 index 000000000..cfc27f322 --- /dev/null +++ b/core/crypto/_fiat/field_scalarp384r1/field.odin @@ -0,0 +1,607 @@ +package field_scalarp384r1 + +import "core:crypto" +import subtle "core:crypto/_subtle" +import "core:encoding/endian" +import "core:math/bits" + +@(private, rodata) +TWO_256 := Montgomery_Domain_Field_Element{ + 17975668497346362272, + 12895982994901192340, + 1913828944324294218, + 902107514168524577, + 1374695839762142861, + 12098342389602539653, +} + +fe_clear :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) { + crypto.zero_explicit(arg1, size_of(Montgomery_Domain_Field_Element)) +} + +fe_clear_vec :: proc "contextless" ( + arg1: []^Montgomery_Domain_Field_Element, +) { + for fe in arg1 { + fe_clear(fe) + } +} + +fe_from_bytes :: proc "contextless" ( + out1: ^Montgomery_Domain_Field_Element, + arg1: []byte, +) -> bool { + ensure_contextless(len(out1) <= 64, "p384r1: invalid scalar input buffer") + + is_canonical := false + s_len := len(arg1) + switch { + case s_len < 48: + // No way this can be greater than the order. + fe_unchecked_set(out1, arg1) + is_canonical = true + case s_len == 48: + // There is no way for any 384-bit value to be >= 2n, so + // the reduction can be done by `src - n` and a conditional + // select based on the underflow. + // + // It is *extremely* unlikely that the reduction is actually + // needed. + tmp: Non_Montgomery_Domain_Field_Element = --- + fe_unchecked_set_saturated(&tmp, arg1) + reduced := tmp + defer crypto.zero_explicit(&tmp, size_of(tmp)) + defer crypto.zero_explicit(&reduced, size_of(reduced)) + + borrow: u64 + reduced[0], borrow = bits.sub_u64(tmp[0], ELL[0], borrow) + reduced[1], borrow = bits.sub_u64(tmp[1], ELL[1], borrow) + reduced[2], borrow = bits.sub_u64(tmp[2], ELL[2], borrow) + reduced[3], borrow = bits.sub_u64(tmp[3], ELL[3], borrow) + reduced[4], borrow = bits.sub_u64(tmp[4], ELL[4], borrow) + reduced[5], borrow = bits.sub_u64(tmp[5], ELL[5], borrow) + need_reduced := subtle.u64_is_zero(borrow) + + fe_cond_select(&tmp, &tmp, &reduced, int(need_reduced)) + fe_to_montgomery(out1, &tmp) + + is_canonical = need_reduced == 0 + case: + // Use Frank Denis' trick, as documented by Filippo Valsorda + // at https://words.filippo.io/dispatches/wide-reduction/ + // + // "I represent the value as a+b*2^192+c*2^384" + // + // Since digests beyond 512-bits are unrealistic, we do + // "a+b*2^256" + + // Zero extend to 512-bits. + src_512: [64]byte + copy(src_512[64-s_len:], arg1) + defer crypto.zero_explicit(&src_512, size_of(src_512)) + + fe_unchecked_set(out1, src_512[32:]) // a + b: Montgomery_Domain_Field_Element + fe_unchecked_set(&b, src_512[:32]) // b + + fe_mul(&b, &b, &TWO_256) + fe_add(out1, out1, &b) + + fe_clear(&b) + } + + return !is_canonical +} + +@(private) +fe_is_canonical :: proc "contextless" (arg1: []byte) -> bool { + _, borrow := bits.sub_u64(ELL[0] - 1, endian.unchecked_get_u64be(arg1[40:]), 0) + _, borrow = bits.sub_u64(ELL[1], endian.unchecked_get_u64be(arg1[32:]), borrow) + _, borrow = bits.sub_u64(ELL[2], endian.unchecked_get_u64be(arg1[24:]), borrow) + _, borrow = bits.sub_u64(ELL[3], endian.unchecked_get_u64be(arg1[16:]), borrow) + _, borrow = bits.sub_u64(ELL[4], endian.unchecked_get_u64be(arg1[8:]), borrow) + _, borrow = bits.sub_u64(ELL[5], endian.unchecked_get_u64be(arg1[0:]), borrow) + return borrow == 0 +} + +@(private="file") +fe_unchecked_set_saturated :: proc "contextless" (out1: ^Non_Montgomery_Domain_Field_Element, arg1: []byte) { + out1[0] = endian.unchecked_get_u64be(arg1[40:]) + out1[1] = endian.unchecked_get_u64be(arg1[32:]) + out1[2] = endian.unchecked_get_u64be(arg1[24:]) + out1[3] = endian.unchecked_get_u64be(arg1[16:]) + out1[4] = endian.unchecked_get_u64be(arg1[8:]) + out1[5] = endian.unchecked_get_u64be(arg1[0:]) +} + +@(private) +fe_unchecked_set :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element, arg1: []byte) { + arg1_384: [48]byte + defer crypto.zero_explicit(&arg1_384, size_of(arg1_384)) + copy(arg1_384[48-len(arg1):], arg1) + + tmp: Non_Montgomery_Domain_Field_Element = --- + fe_unchecked_set_saturated(&tmp, arg1_384[:]) + defer crypto.zero_explicit(&tmp, size_of(tmp)) + + fe_to_montgomery(out1, &tmp) +} + +fe_to_bytes :: proc "contextless" (out1: []byte, arg1: ^Montgomery_Domain_Field_Element) { + ensure_contextless(len(out1) == 48, "p384r1: invalid scalar output buffer") + + tmp: Non_Montgomery_Domain_Field_Element = --- + fe_from_montgomery(&tmp, arg1) + + // Note: Likewise, output in big-endian. + endian.unchecked_put_u64be(out1[40:], tmp[0]) + endian.unchecked_put_u64be(out1[32:], tmp[1]) + endian.unchecked_put_u64be(out1[24:], tmp[2]) + endian.unchecked_put_u64be(out1[16:], tmp[3]) + endian.unchecked_put_u64be(out1[8:], tmp[4]) + endian.unchecked_put_u64be(out1[0:], tmp[5]) + + crypto.zero_explicit(&tmp, size_of(tmp)) +} + +fe_equal :: proc "contextless" (arg1, arg2: ^Montgomery_Domain_Field_Element) -> int { + tmp: Montgomery_Domain_Field_Element = --- + fe_sub(&tmp, arg1, arg2) + + is_eq := subtle.eq(fe_non_zero(&tmp), 0) + + fe_clear(&tmp) + + return int(is_eq) +} + +fe_is_odd :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) -> int { + tmp: Non_Montgomery_Domain_Field_Element = --- + defer crypto.zero_explicit(&tmp, size_of(tmp)) + + fe_from_montgomery(&tmp, arg1) + return int(tmp[0] & 1) +} + +fe_zero :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element) { + out1[0] = 0 + out1[1] = 0 + out1[2] = 0 + out1[3] = 0 + out1[4] = 0 + out1[5] = 0 +} + +fe_set :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) { + x1 := arg1[0] + x2 := arg1[1] + x3 := arg1[2] + x4 := arg1[3] + x5 := arg1[4] + x6 := arg1[5] + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 + out1[5] = x6 +} + +@(optimization_mode = "none") +fe_cond_swap :: #force_no_inline proc "contextless" (out1, out2: ^Montgomery_Domain_Field_Element, arg1: int) { + mask := (u64(arg1) * 0xffffffffffffffff) + x := (out1[0] ~ out2[0]) & mask + x1, y1 := out1[0] ~ x, out2[0] ~ x + x = (out1[1] ~ out2[1]) & mask + x2, y2 := out1[1] ~ x, out2[1] ~ x + x = (out1[2] ~ out2[2]) & mask + x3, y3 := out1[2] ~ x, out2[2] ~ x + x = (out1[3] ~ out2[3]) & mask + x4, y4 := out1[3] ~ x, out2[3] ~ x + x = (out1[4] ~ out2[4]) & mask + x5, y5 := out1[4] ~ x, out2[4] ~ x + x = (out1[5] ~ out2[5]) & mask + x6, y6 := out1[5] ~ x, out2[5] ~ x + out1[0], out2[0] = x1, y1 + out1[1], out2[1] = x2, y2 + out1[2], out2[2] = x3, y3 + out1[3], out2[3] = x4, y4 + out1[4], out2[4] = x5, y5 + out1[5], out2[5] = x6, y6 +} + +@(optimization_mode = "none") +fe_cond_select :: #force_no_inline proc "contextless" ( + out1, arg1, arg2: ^$T, + arg3: int, +) where T == Montgomery_Domain_Field_Element || T == Non_Montgomery_Domain_Field_Element { + mask := (u64(arg3) * 0xffffffffffffffff) + x1 := ((mask & arg2[0]) | ((~mask) & arg1[0])) + x2 := ((mask & arg2[1]) | ((~mask) & arg1[1])) + x3 := ((mask & arg2[2]) | ((~mask) & arg1[2])) + x4 := ((mask & arg2[3]) | ((~mask) & arg1[3])) + x5 := ((mask & arg2[4]) | ((~mask) & arg1[4])) + x6 := ((mask & arg2[5]) | ((~mask) & arg1[5])) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 + out1[5] = x6 +} + +fe_cond_negate :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element, ctrl: int) { + tmp1: Montgomery_Domain_Field_Element = --- + fe_opp(&tmp1, arg1) + fe_cond_select(out1, arg1, &tmp1, ctrl) + + fe_clear(&tmp1) +} + +fe_pow2k :: proc "contextless" ( + out1: ^Montgomery_Domain_Field_Element, + arg1: ^Montgomery_Domain_Field_Element, + arg2: uint, +) { + // Special case: `arg1^(2 * 0) = 1`, though this should never happen. + if arg2 == 0 { + fe_one(out1) + return + } + + fe_square(out1, arg1) + for _ in 1 ..< arg2 { + fe_square(out1, out1) + } +} + +fe_inv :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) { + // Inversion computation is derived from the addition chain: + // + // _10 = 2*1 + // _11 = 1 + _10 + // _101 = _10 + _11 + // _111 = _10 + _101 + // _1001 = _10 + _111 + // _1011 = _10 + _1001 + // _1101 = _10 + _1011 + // _1111 = _10 + _1101 + // _11110 = 2*_1111 + // _11111 = 1 + _11110 + // _1111100 = _11111 << 2 + // i14 = _1111100 << 2 + // i26 = (i14 << 3 + _1111100) << 7 + i14 + // i42 = i26 << 15 + i26 + // x64 = i42 << 30 + i42 + _1111 + // x128 = x64 << 64 + x64 + // x192 = x128 << 64 + x64 + // x194 = x192 << 2 + _11 + // i225 = ((x194 << 6 + _111) << 3 + _11) << 7 + // i235 = 2*((_1101 + i225) << 6 + _1101) + 1 + // i258 = ((i235 << 11 + _11111) << 2 + 1) << 8 + // i269 = ((_1101 + i258) << 2 + _11) << 6 + _1011 + // i286 = ((i269 << 4 + _111) << 6 + _11111) << 5 + // i308 = ((_1011 + i286) << 10 + _1101) << 9 + _1101 + // i323 = ((i308 << 4 + _1011) << 6 + _1001) << 3 + // i340 = ((1 + i323) << 7 + _1011) << 7 + _101 + // i357 = ((i340 << 5 + _111) << 5 + _1111) << 5 + // i369 = ((_1011 + i357) << 4 + _1011) << 5 + _111 + // i387 = ((i369 << 3 + _11) << 7 + _11) << 6 + // i397 = ((_1011 + i387) << 4 + _101) << 3 + _11 + // i413 = ((i397 << 4 + _11) << 4 + _11) << 6 + // i427 = ((_101 + i413) << 5 + _101) << 6 + _1011 + // return (2*i427 + 1) << 4 + 1 + // + // Operations: 381 squares 53 multiplies + // + // Generated by github.com/mmcloughlin/addchain v0.4.0. + + // Note: Need to stash `arg1` (`xx`) in the case that `out1`/`arg1` alias, + // as `arg1` is used after `out1` has been altered. + t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, xx: Montgomery_Domain_Field_Element = ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, arg1^ + + // Step 1: t3 = x^0x2 + fe_square(&t3, arg1) + + // Step 2: t1 = x^0x3 + fe_mul(&t1, arg1, &t3) + + // Step 3: t0 = x^0x5 + fe_mul(&t0, &t3, &t1) + + // Step 4: t2 = x^0x7 + fe_mul(&t2, &t3, &t0) + + // Step 5: t4 = x^0x9 + fe_mul(&t4, &t3, &t2) + + // Step 6: z = x^0xb + fe_mul(out1, &t3, &t4) + + // Step 7: t5 = x^0xd + fe_mul(&t5, &t3, out1) + + // Step 8: t3 = x^0xf + fe_mul(&t3, &t3, &t5) + + // Step 9: t6 = x^0x1e + fe_square(&t6, &t3) + + // Step 10: t6 = x^0x1f + fe_mul(&t6, &xx, &t6) + + // Step 12: t8 = x^0x7c + fe_pow2k(&t8, &t6, 2) + + // Step 14: t7 = x^0x1f0 + fe_pow2k(&t7, &t8, 2) + + // Step 17: t9 = x^0xf80 + fe_pow2k(&t9, &t7, 3) + + // Step 18: t8 = x^0xffc + fe_mul(&t8, &t8, &t9) + + // Step 25: t8 = x^0x7fe00 + fe_pow2k(&t8, &t8, 7) + + // Step 26: t7 = x^0x7fff0 + fe_mul(&t7, &t7, &t8) + + // Step 41: t8 = x^0x3fff80000 + fe_pow2k(&t8, &t7, 15) + + // Step 42: t7 = x^0x3fffffff0 + fe_mul(&t7, &t7, &t8) + + // Step 72: t8 = x^0xfffffffc00000000 + fe_pow2k(&t8, &t7, 30) + + // Step 73: t7 = x^0xfffffffffffffff0 + fe_mul(&t7, &t7, &t8) + + // Step 74: t7 = x^0xffffffffffffffff + fe_mul(&t7, &t3, &t7) + + // Step 138: t8 = x^0xffffffffffffffff0000000000000000 + fe_pow2k(&t8, &t7, 64) + + // Step 139: t8 = x^0xffffffffffffffffffffffffffffffff + fe_mul(&t8, &t7, &t8) + + // Step 203: t8 = x^0xffffffffffffffffffffffffffffffff0000000000000000 + fe_pow2k(&t8, &t8, 64) + + // Step 204: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffff + fe_mul(&t7, &t7, &t8) + + // Step 206: t7 = x^0x3fffffffffffffffffffffffffffffffffffffffffffffffc + fe_pow2k(&t7, &t7, 2) + + // Step 207: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff + fe_mul(&t7, &t1, &t7) + + // Step 213: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc0 + fe_pow2k(&t7, &t7, 6) + + // Step 214: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7 + fe_mul(&t7, &t2, &t7) + + // Step 217: t7 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe38 + fe_pow2k(&t7, &t7, 3) + + // Step 218: t7 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b + fe_mul(&t7, &t1, &t7) + + // Step 225: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d80 + fe_pow2k(&t7, &t7, 7) + + // Step 226: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d + fe_mul(&t7, &t5, &t7) + + // Step 232: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc76340 + fe_pow2k(&t7, &t7, 6) + + // Step 233: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d + fe_mul(&t7, &t5, &t7) + + // Step 234: t7 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69a + fe_square(&t7, &t7) + + // Step 235: t7 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b + fe_mul(&t7, &xx, &t7) + + // Step 246: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d800 + fe_pow2k(&t7, &t7, 11) + + // Step 247: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f + fe_mul(&t7, &t6, &t7) + + // Step 249: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607c + fe_pow2k(&t7, &t7, 2) + + // Step 250: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d + fe_mul(&t7, &xx, &t7) + + // Step 258: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d00 + fe_pow2k(&t7, &t7, 8) + + // Step 259: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0d + fe_mul(&t7, &t5, &t7) + + // Step 261: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f434 + fe_pow2k(&t7, &t7, 2) + + // Step 262: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f437 + fe_mul(&t7, &t1, &t7) + + // Step 268: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dc0 + fe_pow2k(&t7, &t7, 6) + + // Step 269: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb + fe_mul(&t7, out1, &t7) + + // Step 273: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb0 + fe_pow2k(&t7, &t7, 4) + + // Step 274: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb7 + fe_mul(&t7, &t2, &t7) + + // Step 280: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372dc0 + fe_pow2k(&t7, &t7, 6) + + // Step 281: t6 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf + fe_mul(&t6, &t6, &t7) + + // Step 286: t6 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbe0 + fe_pow2k(&t6, &t6, 5) + + // Step 287: t6 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb + fe_mul(&t6, out1, &t6) + + // Step 297: t6 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac00 + fe_pow2k(&t6, &t6, 10) + + // Step 298: t6 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d + fe_mul(&t6, &t5, &t6) + + // Step 307: t6 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a00 + fe_pow2k(&t6, &t6, 9) + + // Step 308: t5 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0d + fe_mul(&t5, &t5, &t6) + + // Step 312: t5 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0d0 + fe_pow2k(&t5, &t5, 4) + + // Step 313: t5 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db + fe_mul(&t5, out1, &t5) + + // Step 319: t5 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c0 + fe_pow2k(&t5, &t5, 6) + + // Step 320: t4 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c9 + fe_mul(&t4, &t4, &t5) + + // Step 323: t4 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb0341b648 + fe_pow2k(&t4, &t4, 3) + + // Step 324: t4 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb0341b649 + fe_mul(&t4, &xx, &t4) + + // Step 331: t4 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db2480 + fe_pow2k(&t4, &t4, 7) + + // Step 332: t4 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b + fe_mul(&t4, out1, &t4) + + // Step 339: t4 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d924580 + fe_pow2k(&t4, &t4, 7) + + // Step 340: t4 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d924585 + fe_mul(&t4, &t0, &t4) + + // Step 345: t4 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a0 + fe_pow2k(&t4, &t4, 5) + + // Step 346: t4 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a7 + fe_mul(&t4, &t2, &t4) + + // Step 351: t4 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb0341b6491614e0 + fe_pow2k(&t4, &t4, 5) + + // Step 352: t3 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb0341b6491614ef + fe_mul(&t3, &t3, &t4) + + // Step 357: t3 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29de0 + fe_pow2k(&t3, &t3, 5) + + // Step 358: t3 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29deb + fe_mul(&t3, out1, &t3) + + // Step 362: t3 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29deb0 + fe_pow2k(&t3, &t3, 4) + + // Step 363: t3 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb + fe_mul(&t3, out1, &t3) + + // Step 368: t3 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd760 + fe_pow2k(&t3, &t3, 5) + + // Step 369: t2 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd767 + fe_mul(&t2, &t2, &t3) + + // Step 372: t2 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb38 + fe_pow2k(&t2, &t2, 3) + + // Step 373: t2 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb3b + fe_mul(&t2, &t1, &t2) + + // Step 380: t2 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb0341b6491614ef5d9d80 + fe_pow2k(&t2, &t2, 7) + + // Step 381: t2 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb0341b6491614ef5d9d83 + fe_mul(&t2, &t1, &t2) + + // Step 387: t2 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd76760c0 + fe_pow2k(&t2, &t2, 6) + + // Step 388: t2 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd76760cb + fe_mul(&t2, out1, &t2) + + // Step 392: t2 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd76760cb0 + fe_pow2k(&t2, &t2, 4) + + // Step 393: t2 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd76760cb5 + fe_mul(&t2, &t0, &t2) + + // Step 396: t2 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb3b065a8 + fe_pow2k(&t2, &t2, 3) + + // Step 397: t2 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb3b065ab + fe_mul(&t2, &t1, &t2) + + // Step 401: t2 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb3b065ab0 + fe_pow2k(&t2, &t2, 4) + + // Step 402: t2 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb3b065ab3 + fe_mul(&t2, &t1, &t2) + + // Step 406: t2 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb3b065ab30 + fe_pow2k(&t2, &t2, 4) + + // Step 407: t1 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb3b065ab33 + fe_mul(&t1, &t1, &t2) + + // Step 413: t1 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc0 + fe_pow2k(&t1, &t1, 6) + + // Step 414: t1 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc5 + fe_mul(&t1, &t0, &t1) + + // Step 419: t1 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb0341b6491614ef5d9d832d5998a0 + fe_pow2k(&t1, &t1, 5) + + // Step 420: t0 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb0341b6491614ef5d9d832d5998a5 + fe_mul(&t0, &t0, &t1) + + // Step 426: t0 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd76760cb56662940 + fe_pow2k(&t0, &t0, 6) + + // Step 427: z = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b + fe_mul(out1, out1, &t0) + + // Step 428: z = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc5296 + fe_square(out1, out1) + + // Step 429: z = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc5297 + fe_mul(out1, &xx, out1) + + // Step 433: z = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52970 + fe_pow2k(out1, out1, 4) + + // Step 434: z = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52971 + fe_mul(out1, &xx, out1) + + fe_clear_vec([]^Montgomery_Domain_Field_Element{&t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7, &t8, &t9, &xx}) +} diff --git a/core/crypto/_fiat/field_scalarp384r1/field64.odin b/core/crypto/_fiat/field_scalarp384r1/field64.odin new file mode 100644 index 000000000..ce29060e8 --- /dev/null +++ b/core/crypto/_fiat/field_scalarp384r1/field64.odin @@ -0,0 +1,1081 @@ +// The BSD 1-Clause License (BSD-1-Clause) +// +// Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, +// Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package field_scalarp384r1 + +// The file provides arithmetic on the field Z/(2^384 - 1388124618062372383947042015309946732620727252194336364173) +// using a 64-bit Montgomery form internal representation. It is derived +// primarily from the machine generated Golang output from the fiat-crypto +// project. +// +// While the base implementation is provably correct, this implementation +// makes no such claims as the port and optimizations were done by hand. +// +// WARNING: While big-endian is the common representation used for this +// curve, the fiat output uses least-significant-limb first. + +import fiat "core:crypto/_fiat" +import "core:math/bits" + +// ELL is the saturated representation of the field order, least-significant +// limb first. +ELL :: [6]u64{0xecec196accc52973, 0x581a0db248b0a77a, 0xc7634d81f4372ddf, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff} + +Montgomery_Domain_Field_Element :: distinct [6]u64 +Non_Montgomery_Domain_Field_Element :: distinct [6]u64 + +fe_mul :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[4] + x5 := arg1[5] + x6 := arg1[0] + x8, x7 := bits.mul_u64(x6, arg2[5]) + x10, x9 := bits.mul_u64(x6, arg2[4]) + x12, x11 := bits.mul_u64(x6, arg2[3]) + x14, x13 := bits.mul_u64(x6, arg2[2]) + x16, x15 := bits.mul_u64(x6, arg2[1]) + x18, x17 := bits.mul_u64(x6, arg2[0]) + x19, x20 := bits.add_u64(x18, x15, u64(0x0)) + x21, x22 := bits.add_u64(x16, x13, u64(fiat.u1(x20))) + x23, x24 := bits.add_u64(x14, x11, u64(fiat.u1(x22))) + x25, x26 := bits.add_u64(x12, x9, u64(fiat.u1(x24))) + x27, x28 := bits.add_u64(x10, x7, u64(fiat.u1(x26))) + x29 := (u64(fiat.u1(x28)) + x8) + _, x30 := bits.mul_u64(x17, 0x6ed46089e88fdc45) + x33, x32 := bits.mul_u64(x30, 0xffffffffffffffff) + x35, x34 := bits.mul_u64(x30, 0xffffffffffffffff) + x37, x36 := bits.mul_u64(x30, 0xffffffffffffffff) + x39, x38 := bits.mul_u64(x30, 0xc7634d81f4372ddf) + x41, x40 := bits.mul_u64(x30, 0x581a0db248b0a77a) + x43, x42 := bits.mul_u64(x30, 0xecec196accc52973) + x44, x45 := bits.add_u64(x43, x40, u64(0x0)) + x46, x47 := bits.add_u64(x41, x38, u64(fiat.u1(x45))) + x48, x49 := bits.add_u64(x39, x36, u64(fiat.u1(x47))) + x50, x51 := bits.add_u64(x37, x34, u64(fiat.u1(x49))) + x52, x53 := bits.add_u64(x35, x32, u64(fiat.u1(x51))) + x54 := (u64(fiat.u1(x53)) + x33) + _, x56 := bits.add_u64(x17, x42, u64(0x0)) + x57, x58 := bits.add_u64(x19, x44, u64(fiat.u1(x56))) + x59, x60 := bits.add_u64(x21, x46, u64(fiat.u1(x58))) + x61, x62 := bits.add_u64(x23, x48, u64(fiat.u1(x60))) + x63, x64 := bits.add_u64(x25, x50, u64(fiat.u1(x62))) + x65, x66 := bits.add_u64(x27, x52, u64(fiat.u1(x64))) + x67, x68 := bits.add_u64(x29, x54, u64(fiat.u1(x66))) + x70, x69 := bits.mul_u64(x1, arg2[5]) + x72, x71 := bits.mul_u64(x1, arg2[4]) + x74, x73 := bits.mul_u64(x1, arg2[3]) + x76, x75 := bits.mul_u64(x1, arg2[2]) + x78, x77 := bits.mul_u64(x1, arg2[1]) + x80, x79 := bits.mul_u64(x1, arg2[0]) + x81, x82 := bits.add_u64(x80, x77, u64(0x0)) + x83, x84 := bits.add_u64(x78, x75, u64(fiat.u1(x82))) + x85, x86 := bits.add_u64(x76, x73, u64(fiat.u1(x84))) + x87, x88 := bits.add_u64(x74, x71, u64(fiat.u1(x86))) + x89, x90 := bits.add_u64(x72, x69, u64(fiat.u1(x88))) + x91 := (u64(fiat.u1(x90)) + x70) + x92, x93 := bits.add_u64(x57, x79, u64(0x0)) + x94, x95 := bits.add_u64(x59, x81, u64(fiat.u1(x93))) + x96, x97 := bits.add_u64(x61, x83, u64(fiat.u1(x95))) + x98, x99 := bits.add_u64(x63, x85, u64(fiat.u1(x97))) + x100, x101 := bits.add_u64(x65, x87, u64(fiat.u1(x99))) + x102, x103 := bits.add_u64(x67, x89, u64(fiat.u1(x101))) + x104, x105 := bits.add_u64(u64(fiat.u1(x68)), x91, u64(fiat.u1(x103))) + _, x106 := bits.mul_u64(x92, 0x6ed46089e88fdc45) + x109, x108 := bits.mul_u64(x106, 0xffffffffffffffff) + x111, x110 := bits.mul_u64(x106, 0xffffffffffffffff) + x113, x112 := bits.mul_u64(x106, 0xffffffffffffffff) + x115, x114 := bits.mul_u64(x106, 0xc7634d81f4372ddf) + x117, x116 := bits.mul_u64(x106, 0x581a0db248b0a77a) + x119, x118 := bits.mul_u64(x106, 0xecec196accc52973) + x120, x121 := bits.add_u64(x119, x116, u64(0x0)) + x122, x123 := bits.add_u64(x117, x114, u64(fiat.u1(x121))) + x124, x125 := bits.add_u64(x115, x112, u64(fiat.u1(x123))) + x126, x127 := bits.add_u64(x113, x110, u64(fiat.u1(x125))) + x128, x129 := bits.add_u64(x111, x108, u64(fiat.u1(x127))) + x130 := (u64(fiat.u1(x129)) + x109) + _, x132 := bits.add_u64(x92, x118, u64(0x0)) + x133, x134 := bits.add_u64(x94, x120, u64(fiat.u1(x132))) + x135, x136 := bits.add_u64(x96, x122, u64(fiat.u1(x134))) + x137, x138 := bits.add_u64(x98, x124, u64(fiat.u1(x136))) + x139, x140 := bits.add_u64(x100, x126, u64(fiat.u1(x138))) + x141, x142 := bits.add_u64(x102, x128, u64(fiat.u1(x140))) + x143, x144 := bits.add_u64(x104, x130, u64(fiat.u1(x142))) + x145 := (u64(fiat.u1(x144)) + u64(fiat.u1(x105))) + x147, x146 := bits.mul_u64(x2, arg2[5]) + x149, x148 := bits.mul_u64(x2, arg2[4]) + x151, x150 := bits.mul_u64(x2, arg2[3]) + x153, x152 := bits.mul_u64(x2, arg2[2]) + x155, x154 := bits.mul_u64(x2, arg2[1]) + x157, x156 := bits.mul_u64(x2, arg2[0]) + x158, x159 := bits.add_u64(x157, x154, u64(0x0)) + x160, x161 := bits.add_u64(x155, x152, u64(fiat.u1(x159))) + x162, x163 := bits.add_u64(x153, x150, u64(fiat.u1(x161))) + x164, x165 := bits.add_u64(x151, x148, u64(fiat.u1(x163))) + x166, x167 := bits.add_u64(x149, x146, u64(fiat.u1(x165))) + x168 := (u64(fiat.u1(x167)) + x147) + x169, x170 := bits.add_u64(x133, x156, u64(0x0)) + x171, x172 := bits.add_u64(x135, x158, u64(fiat.u1(x170))) + x173, x174 := bits.add_u64(x137, x160, u64(fiat.u1(x172))) + x175, x176 := bits.add_u64(x139, x162, u64(fiat.u1(x174))) + x177, x178 := bits.add_u64(x141, x164, u64(fiat.u1(x176))) + x179, x180 := bits.add_u64(x143, x166, u64(fiat.u1(x178))) + x181, x182 := bits.add_u64(x145, x168, u64(fiat.u1(x180))) + _, x183 := bits.mul_u64(x169, 0x6ed46089e88fdc45) + x186, x185 := bits.mul_u64(x183, 0xffffffffffffffff) + x188, x187 := bits.mul_u64(x183, 0xffffffffffffffff) + x190, x189 := bits.mul_u64(x183, 0xffffffffffffffff) + x192, x191 := bits.mul_u64(x183, 0xc7634d81f4372ddf) + x194, x193 := bits.mul_u64(x183, 0x581a0db248b0a77a) + x196, x195 := bits.mul_u64(x183, 0xecec196accc52973) + x197, x198 := bits.add_u64(x196, x193, u64(0x0)) + x199, x200 := bits.add_u64(x194, x191, u64(fiat.u1(x198))) + x201, x202 := bits.add_u64(x192, x189, u64(fiat.u1(x200))) + x203, x204 := bits.add_u64(x190, x187, u64(fiat.u1(x202))) + x205, x206 := bits.add_u64(x188, x185, u64(fiat.u1(x204))) + x207 := (u64(fiat.u1(x206)) + x186) + _, x209 := bits.add_u64(x169, x195, u64(0x0)) + x210, x211 := bits.add_u64(x171, x197, u64(fiat.u1(x209))) + x212, x213 := bits.add_u64(x173, x199, u64(fiat.u1(x211))) + x214, x215 := bits.add_u64(x175, x201, u64(fiat.u1(x213))) + x216, x217 := bits.add_u64(x177, x203, u64(fiat.u1(x215))) + x218, x219 := bits.add_u64(x179, x205, u64(fiat.u1(x217))) + x220, x221 := bits.add_u64(x181, x207, u64(fiat.u1(x219))) + x222 := (u64(fiat.u1(x221)) + u64(fiat.u1(x182))) + x224, x223 := bits.mul_u64(x3, arg2[5]) + x226, x225 := bits.mul_u64(x3, arg2[4]) + x228, x227 := bits.mul_u64(x3, arg2[3]) + x230, x229 := bits.mul_u64(x3, arg2[2]) + x232, x231 := bits.mul_u64(x3, arg2[1]) + x234, x233 := bits.mul_u64(x3, arg2[0]) + x235, x236 := bits.add_u64(x234, x231, u64(0x0)) + x237, x238 := bits.add_u64(x232, x229, u64(fiat.u1(x236))) + x239, x240 := bits.add_u64(x230, x227, u64(fiat.u1(x238))) + x241, x242 := bits.add_u64(x228, x225, u64(fiat.u1(x240))) + x243, x244 := bits.add_u64(x226, x223, u64(fiat.u1(x242))) + x245 := (u64(fiat.u1(x244)) + x224) + x246, x247 := bits.add_u64(x210, x233, u64(0x0)) + x248, x249 := bits.add_u64(x212, x235, u64(fiat.u1(x247))) + x250, x251 := bits.add_u64(x214, x237, u64(fiat.u1(x249))) + x252, x253 := bits.add_u64(x216, x239, u64(fiat.u1(x251))) + x254, x255 := bits.add_u64(x218, x241, u64(fiat.u1(x253))) + x256, x257 := bits.add_u64(x220, x243, u64(fiat.u1(x255))) + x258, x259 := bits.add_u64(x222, x245, u64(fiat.u1(x257))) + _, x260 := bits.mul_u64(x246, 0x6ed46089e88fdc45) + x263, x262 := bits.mul_u64(x260, 0xffffffffffffffff) + x265, x264 := bits.mul_u64(x260, 0xffffffffffffffff) + x267, x266 := bits.mul_u64(x260, 0xffffffffffffffff) + x269, x268 := bits.mul_u64(x260, 0xc7634d81f4372ddf) + x271, x270 := bits.mul_u64(x260, 0x581a0db248b0a77a) + x273, x272 := bits.mul_u64(x260, 0xecec196accc52973) + x274, x275 := bits.add_u64(x273, x270, u64(0x0)) + x276, x277 := bits.add_u64(x271, x268, u64(fiat.u1(x275))) + x278, x279 := bits.add_u64(x269, x266, u64(fiat.u1(x277))) + x280, x281 := bits.add_u64(x267, x264, u64(fiat.u1(x279))) + x282, x283 := bits.add_u64(x265, x262, u64(fiat.u1(x281))) + x284 := (u64(fiat.u1(x283)) + x263) + _, x286 := bits.add_u64(x246, x272, u64(0x0)) + x287, x288 := bits.add_u64(x248, x274, u64(fiat.u1(x286))) + x289, x290 := bits.add_u64(x250, x276, u64(fiat.u1(x288))) + x291, x292 := bits.add_u64(x252, x278, u64(fiat.u1(x290))) + x293, x294 := bits.add_u64(x254, x280, u64(fiat.u1(x292))) + x295, x296 := bits.add_u64(x256, x282, u64(fiat.u1(x294))) + x297, x298 := bits.add_u64(x258, x284, u64(fiat.u1(x296))) + x299 := (u64(fiat.u1(x298)) + u64(fiat.u1(x259))) + x301, x300 := bits.mul_u64(x4, arg2[5]) + x303, x302 := bits.mul_u64(x4, arg2[4]) + x305, x304 := bits.mul_u64(x4, arg2[3]) + x307, x306 := bits.mul_u64(x4, arg2[2]) + x309, x308 := bits.mul_u64(x4, arg2[1]) + x311, x310 := bits.mul_u64(x4, arg2[0]) + x312, x313 := bits.add_u64(x311, x308, u64(0x0)) + x314, x315 := bits.add_u64(x309, x306, u64(fiat.u1(x313))) + x316, x317 := bits.add_u64(x307, x304, u64(fiat.u1(x315))) + x318, x319 := bits.add_u64(x305, x302, u64(fiat.u1(x317))) + x320, x321 := bits.add_u64(x303, x300, u64(fiat.u1(x319))) + x322 := (u64(fiat.u1(x321)) + x301) + x323, x324 := bits.add_u64(x287, x310, u64(0x0)) + x325, x326 := bits.add_u64(x289, x312, u64(fiat.u1(x324))) + x327, x328 := bits.add_u64(x291, x314, u64(fiat.u1(x326))) + x329, x330 := bits.add_u64(x293, x316, u64(fiat.u1(x328))) + x331, x332 := bits.add_u64(x295, x318, u64(fiat.u1(x330))) + x333, x334 := bits.add_u64(x297, x320, u64(fiat.u1(x332))) + x335, x336 := bits.add_u64(x299, x322, u64(fiat.u1(x334))) + _, x337 := bits.mul_u64(x323, 0x6ed46089e88fdc45) + x340, x339 := bits.mul_u64(x337, 0xffffffffffffffff) + x342, x341 := bits.mul_u64(x337, 0xffffffffffffffff) + x344, x343 := bits.mul_u64(x337, 0xffffffffffffffff) + x346, x345 := bits.mul_u64(x337, 0xc7634d81f4372ddf) + x348, x347 := bits.mul_u64(x337, 0x581a0db248b0a77a) + x350, x349 := bits.mul_u64(x337, 0xecec196accc52973) + x351, x352 := bits.add_u64(x350, x347, u64(0x0)) + x353, x354 := bits.add_u64(x348, x345, u64(fiat.u1(x352))) + x355, x356 := bits.add_u64(x346, x343, u64(fiat.u1(x354))) + x357, x358 := bits.add_u64(x344, x341, u64(fiat.u1(x356))) + x359, x360 := bits.add_u64(x342, x339, u64(fiat.u1(x358))) + x361 := (u64(fiat.u1(x360)) + x340) + _, x363 := bits.add_u64(x323, x349, u64(0x0)) + x364, x365 := bits.add_u64(x325, x351, u64(fiat.u1(x363))) + x366, x367 := bits.add_u64(x327, x353, u64(fiat.u1(x365))) + x368, x369 := bits.add_u64(x329, x355, u64(fiat.u1(x367))) + x370, x371 := bits.add_u64(x331, x357, u64(fiat.u1(x369))) + x372, x373 := bits.add_u64(x333, x359, u64(fiat.u1(x371))) + x374, x375 := bits.add_u64(x335, x361, u64(fiat.u1(x373))) + x376 := (u64(fiat.u1(x375)) + u64(fiat.u1(x336))) + x378, x377 := bits.mul_u64(x5, arg2[5]) + x380, x379 := bits.mul_u64(x5, arg2[4]) + x382, x381 := bits.mul_u64(x5, arg2[3]) + x384, x383 := bits.mul_u64(x5, arg2[2]) + x386, x385 := bits.mul_u64(x5, arg2[1]) + x388, x387 := bits.mul_u64(x5, arg2[0]) + x389, x390 := bits.add_u64(x388, x385, u64(0x0)) + x391, x392 := bits.add_u64(x386, x383, u64(fiat.u1(x390))) + x393, x394 := bits.add_u64(x384, x381, u64(fiat.u1(x392))) + x395, x396 := bits.add_u64(x382, x379, u64(fiat.u1(x394))) + x397, x398 := bits.add_u64(x380, x377, u64(fiat.u1(x396))) + x399 := (u64(fiat.u1(x398)) + x378) + x400, x401 := bits.add_u64(x364, x387, u64(0x0)) + x402, x403 := bits.add_u64(x366, x389, u64(fiat.u1(x401))) + x404, x405 := bits.add_u64(x368, x391, u64(fiat.u1(x403))) + x406, x407 := bits.add_u64(x370, x393, u64(fiat.u1(x405))) + x408, x409 := bits.add_u64(x372, x395, u64(fiat.u1(x407))) + x410, x411 := bits.add_u64(x374, x397, u64(fiat.u1(x409))) + x412, x413 := bits.add_u64(x376, x399, u64(fiat.u1(x411))) + _, x414 := bits.mul_u64(x400, 0x6ed46089e88fdc45) + x417, x416 := bits.mul_u64(x414, 0xffffffffffffffff) + x419, x418 := bits.mul_u64(x414, 0xffffffffffffffff) + x421, x420 := bits.mul_u64(x414, 0xffffffffffffffff) + x423, x422 := bits.mul_u64(x414, 0xc7634d81f4372ddf) + x425, x424 := bits.mul_u64(x414, 0x581a0db248b0a77a) + x427, x426 := bits.mul_u64(x414, 0xecec196accc52973) + x428, x429 := bits.add_u64(x427, x424, u64(0x0)) + x430, x431 := bits.add_u64(x425, x422, u64(fiat.u1(x429))) + x432, x433 := bits.add_u64(x423, x420, u64(fiat.u1(x431))) + x434, x435 := bits.add_u64(x421, x418, u64(fiat.u1(x433))) + x436, x437 := bits.add_u64(x419, x416, u64(fiat.u1(x435))) + x438 := (u64(fiat.u1(x437)) + x417) + _, x440 := bits.add_u64(x400, x426, u64(0x0)) + x441, x442 := bits.add_u64(x402, x428, u64(fiat.u1(x440))) + x443, x444 := bits.add_u64(x404, x430, u64(fiat.u1(x442))) + x445, x446 := bits.add_u64(x406, x432, u64(fiat.u1(x444))) + x447, x448 := bits.add_u64(x408, x434, u64(fiat.u1(x446))) + x449, x450 := bits.add_u64(x410, x436, u64(fiat.u1(x448))) + x451, x452 := bits.add_u64(x412, x438, u64(fiat.u1(x450))) + x453 := (u64(fiat.u1(x452)) + u64(fiat.u1(x413))) + x454, x455 := bits.sub_u64(x441, 0xecec196accc52973, u64(0x0)) + x456, x457 := bits.sub_u64(x443, 0x581a0db248b0a77a, u64(fiat.u1(x455))) + x458, x459 := bits.sub_u64(x445, 0xc7634d81f4372ddf, u64(fiat.u1(x457))) + x460, x461 := bits.sub_u64(x447, 0xffffffffffffffff, u64(fiat.u1(x459))) + x462, x463 := bits.sub_u64(x449, 0xffffffffffffffff, u64(fiat.u1(x461))) + x464, x465 := bits.sub_u64(x451, 0xffffffffffffffff, u64(fiat.u1(x463))) + _, x467 := bits.sub_u64(x453, u64(0x0), u64(fiat.u1(x465))) + x468 := fiat.cmovznz_u64(fiat.u1(x467), x454, x441) + x469 := fiat.cmovznz_u64(fiat.u1(x467), x456, x443) + x470 := fiat.cmovznz_u64(fiat.u1(x467), x458, x445) + x471 := fiat.cmovznz_u64(fiat.u1(x467), x460, x447) + x472 := fiat.cmovznz_u64(fiat.u1(x467), x462, x449) + x473 := fiat.cmovznz_u64(fiat.u1(x467), x464, x451) + out1[0] = x468 + out1[1] = x469 + out1[2] = x470 + out1[3] = x471 + out1[4] = x472 + out1[5] = x473 +} + +fe_square :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[4] + x5 := arg1[5] + x6 := arg1[0] + x8, x7 := bits.mul_u64(x6, arg1[5]) + x10, x9 := bits.mul_u64(x6, arg1[4]) + x12, x11 := bits.mul_u64(x6, arg1[3]) + x14, x13 := bits.mul_u64(x6, arg1[2]) + x16, x15 := bits.mul_u64(x6, arg1[1]) + x18, x17 := bits.mul_u64(x6, arg1[0]) + x19, x20 := bits.add_u64(x18, x15, u64(0x0)) + x21, x22 := bits.add_u64(x16, x13, u64(fiat.u1(x20))) + x23, x24 := bits.add_u64(x14, x11, u64(fiat.u1(x22))) + x25, x26 := bits.add_u64(x12, x9, u64(fiat.u1(x24))) + x27, x28 := bits.add_u64(x10, x7, u64(fiat.u1(x26))) + x29 := (u64(fiat.u1(x28)) + x8) + _, x30 := bits.mul_u64(x17, 0x6ed46089e88fdc45) + x33, x32 := bits.mul_u64(x30, 0xffffffffffffffff) + x35, x34 := bits.mul_u64(x30, 0xffffffffffffffff) + x37, x36 := bits.mul_u64(x30, 0xffffffffffffffff) + x39, x38 := bits.mul_u64(x30, 0xc7634d81f4372ddf) + x41, x40 := bits.mul_u64(x30, 0x581a0db248b0a77a) + x43, x42 := bits.mul_u64(x30, 0xecec196accc52973) + x44, x45 := bits.add_u64(x43, x40, u64(0x0)) + x46, x47 := bits.add_u64(x41, x38, u64(fiat.u1(x45))) + x48, x49 := bits.add_u64(x39, x36, u64(fiat.u1(x47))) + x50, x51 := bits.add_u64(x37, x34, u64(fiat.u1(x49))) + x52, x53 := bits.add_u64(x35, x32, u64(fiat.u1(x51))) + x54 := (u64(fiat.u1(x53)) + x33) + _, x56 := bits.add_u64(x17, x42, u64(0x0)) + x57, x58 := bits.add_u64(x19, x44, u64(fiat.u1(x56))) + x59, x60 := bits.add_u64(x21, x46, u64(fiat.u1(x58))) + x61, x62 := bits.add_u64(x23, x48, u64(fiat.u1(x60))) + x63, x64 := bits.add_u64(x25, x50, u64(fiat.u1(x62))) + x65, x66 := bits.add_u64(x27, x52, u64(fiat.u1(x64))) + x67, x68 := bits.add_u64(x29, x54, u64(fiat.u1(x66))) + x70, x69 := bits.mul_u64(x1, arg1[5]) + x72, x71 := bits.mul_u64(x1, arg1[4]) + x74, x73 := bits.mul_u64(x1, arg1[3]) + x76, x75 := bits.mul_u64(x1, arg1[2]) + x78, x77 := bits.mul_u64(x1, arg1[1]) + x80, x79 := bits.mul_u64(x1, arg1[0]) + x81, x82 := bits.add_u64(x80, x77, u64(0x0)) + x83, x84 := bits.add_u64(x78, x75, u64(fiat.u1(x82))) + x85, x86 := bits.add_u64(x76, x73, u64(fiat.u1(x84))) + x87, x88 := bits.add_u64(x74, x71, u64(fiat.u1(x86))) + x89, x90 := bits.add_u64(x72, x69, u64(fiat.u1(x88))) + x91 := (u64(fiat.u1(x90)) + x70) + x92, x93 := bits.add_u64(x57, x79, u64(0x0)) + x94, x95 := bits.add_u64(x59, x81, u64(fiat.u1(x93))) + x96, x97 := bits.add_u64(x61, x83, u64(fiat.u1(x95))) + x98, x99 := bits.add_u64(x63, x85, u64(fiat.u1(x97))) + x100, x101 := bits.add_u64(x65, x87, u64(fiat.u1(x99))) + x102, x103 := bits.add_u64(x67, x89, u64(fiat.u1(x101))) + x104, x105 := bits.add_u64(u64(fiat.u1(x68)), x91, u64(fiat.u1(x103))) + _, x106 := bits.mul_u64(x92, 0x6ed46089e88fdc45) + x109, x108 := bits.mul_u64(x106, 0xffffffffffffffff) + x111, x110 := bits.mul_u64(x106, 0xffffffffffffffff) + x113, x112 := bits.mul_u64(x106, 0xffffffffffffffff) + x115, x114 := bits.mul_u64(x106, 0xc7634d81f4372ddf) + x117, x116 := bits.mul_u64(x106, 0x581a0db248b0a77a) + x119, x118 := bits.mul_u64(x106, 0xecec196accc52973) + x120, x121 := bits.add_u64(x119, x116, u64(0x0)) + x122, x123 := bits.add_u64(x117, x114, u64(fiat.u1(x121))) + x124, x125 := bits.add_u64(x115, x112, u64(fiat.u1(x123))) + x126, x127 := bits.add_u64(x113, x110, u64(fiat.u1(x125))) + x128, x129 := bits.add_u64(x111, x108, u64(fiat.u1(x127))) + x130 := (u64(fiat.u1(x129)) + x109) + _, x132 := bits.add_u64(x92, x118, u64(0x0)) + x133, x134 := bits.add_u64(x94, x120, u64(fiat.u1(x132))) + x135, x136 := bits.add_u64(x96, x122, u64(fiat.u1(x134))) + x137, x138 := bits.add_u64(x98, x124, u64(fiat.u1(x136))) + x139, x140 := bits.add_u64(x100, x126, u64(fiat.u1(x138))) + x141, x142 := bits.add_u64(x102, x128, u64(fiat.u1(x140))) + x143, x144 := bits.add_u64(x104, x130, u64(fiat.u1(x142))) + x145 := (u64(fiat.u1(x144)) + u64(fiat.u1(x105))) + x147, x146 := bits.mul_u64(x2, arg1[5]) + x149, x148 := bits.mul_u64(x2, arg1[4]) + x151, x150 := bits.mul_u64(x2, arg1[3]) + x153, x152 := bits.mul_u64(x2, arg1[2]) + x155, x154 := bits.mul_u64(x2, arg1[1]) + x157, x156 := bits.mul_u64(x2, arg1[0]) + x158, x159 := bits.add_u64(x157, x154, u64(0x0)) + x160, x161 := bits.add_u64(x155, x152, u64(fiat.u1(x159))) + x162, x163 := bits.add_u64(x153, x150, u64(fiat.u1(x161))) + x164, x165 := bits.add_u64(x151, x148, u64(fiat.u1(x163))) + x166, x167 := bits.add_u64(x149, x146, u64(fiat.u1(x165))) + x168 := (u64(fiat.u1(x167)) + x147) + x169, x170 := bits.add_u64(x133, x156, u64(0x0)) + x171, x172 := bits.add_u64(x135, x158, u64(fiat.u1(x170))) + x173, x174 := bits.add_u64(x137, x160, u64(fiat.u1(x172))) + x175, x176 := bits.add_u64(x139, x162, u64(fiat.u1(x174))) + x177, x178 := bits.add_u64(x141, x164, u64(fiat.u1(x176))) + x179, x180 := bits.add_u64(x143, x166, u64(fiat.u1(x178))) + x181, x182 := bits.add_u64(x145, x168, u64(fiat.u1(x180))) + _, x183 := bits.mul_u64(x169, 0x6ed46089e88fdc45) + x186, x185 := bits.mul_u64(x183, 0xffffffffffffffff) + x188, x187 := bits.mul_u64(x183, 0xffffffffffffffff) + x190, x189 := bits.mul_u64(x183, 0xffffffffffffffff) + x192, x191 := bits.mul_u64(x183, 0xc7634d81f4372ddf) + x194, x193 := bits.mul_u64(x183, 0x581a0db248b0a77a) + x196, x195 := bits.mul_u64(x183, 0xecec196accc52973) + x197, x198 := bits.add_u64(x196, x193, u64(0x0)) + x199, x200 := bits.add_u64(x194, x191, u64(fiat.u1(x198))) + x201, x202 := bits.add_u64(x192, x189, u64(fiat.u1(x200))) + x203, x204 := bits.add_u64(x190, x187, u64(fiat.u1(x202))) + x205, x206 := bits.add_u64(x188, x185, u64(fiat.u1(x204))) + x207 := (u64(fiat.u1(x206)) + x186) + _, x209 := bits.add_u64(x169, x195, u64(0x0)) + x210, x211 := bits.add_u64(x171, x197, u64(fiat.u1(x209))) + x212, x213 := bits.add_u64(x173, x199, u64(fiat.u1(x211))) + x214, x215 := bits.add_u64(x175, x201, u64(fiat.u1(x213))) + x216, x217 := bits.add_u64(x177, x203, u64(fiat.u1(x215))) + x218, x219 := bits.add_u64(x179, x205, u64(fiat.u1(x217))) + x220, x221 := bits.add_u64(x181, x207, u64(fiat.u1(x219))) + x222 := (u64(fiat.u1(x221)) + u64(fiat.u1(x182))) + x224, x223 := bits.mul_u64(x3, arg1[5]) + x226, x225 := bits.mul_u64(x3, arg1[4]) + x228, x227 := bits.mul_u64(x3, arg1[3]) + x230, x229 := bits.mul_u64(x3, arg1[2]) + x232, x231 := bits.mul_u64(x3, arg1[1]) + x234, x233 := bits.mul_u64(x3, arg1[0]) + x235, x236 := bits.add_u64(x234, x231, u64(0x0)) + x237, x238 := bits.add_u64(x232, x229, u64(fiat.u1(x236))) + x239, x240 := bits.add_u64(x230, x227, u64(fiat.u1(x238))) + x241, x242 := bits.add_u64(x228, x225, u64(fiat.u1(x240))) + x243, x244 := bits.add_u64(x226, x223, u64(fiat.u1(x242))) + x245 := (u64(fiat.u1(x244)) + x224) + x246, x247 := bits.add_u64(x210, x233, u64(0x0)) + x248, x249 := bits.add_u64(x212, x235, u64(fiat.u1(x247))) + x250, x251 := bits.add_u64(x214, x237, u64(fiat.u1(x249))) + x252, x253 := bits.add_u64(x216, x239, u64(fiat.u1(x251))) + x254, x255 := bits.add_u64(x218, x241, u64(fiat.u1(x253))) + x256, x257 := bits.add_u64(x220, x243, u64(fiat.u1(x255))) + x258, x259 := bits.add_u64(x222, x245, u64(fiat.u1(x257))) + _, x260 := bits.mul_u64(x246, 0x6ed46089e88fdc45) + x263, x262 := bits.mul_u64(x260, 0xffffffffffffffff) + x265, x264 := bits.mul_u64(x260, 0xffffffffffffffff) + x267, x266 := bits.mul_u64(x260, 0xffffffffffffffff) + x269, x268 := bits.mul_u64(x260, 0xc7634d81f4372ddf) + x271, x270 := bits.mul_u64(x260, 0x581a0db248b0a77a) + x273, x272 := bits.mul_u64(x260, 0xecec196accc52973) + x274, x275 := bits.add_u64(x273, x270, u64(0x0)) + x276, x277 := bits.add_u64(x271, x268, u64(fiat.u1(x275))) + x278, x279 := bits.add_u64(x269, x266, u64(fiat.u1(x277))) + x280, x281 := bits.add_u64(x267, x264, u64(fiat.u1(x279))) + x282, x283 := bits.add_u64(x265, x262, u64(fiat.u1(x281))) + x284 := (u64(fiat.u1(x283)) + x263) + _, x286 := bits.add_u64(x246, x272, u64(0x0)) + x287, x288 := bits.add_u64(x248, x274, u64(fiat.u1(x286))) + x289, x290 := bits.add_u64(x250, x276, u64(fiat.u1(x288))) + x291, x292 := bits.add_u64(x252, x278, u64(fiat.u1(x290))) + x293, x294 := bits.add_u64(x254, x280, u64(fiat.u1(x292))) + x295, x296 := bits.add_u64(x256, x282, u64(fiat.u1(x294))) + x297, x298 := bits.add_u64(x258, x284, u64(fiat.u1(x296))) + x299 := (u64(fiat.u1(x298)) + u64(fiat.u1(x259))) + x301, x300 := bits.mul_u64(x4, arg1[5]) + x303, x302 := bits.mul_u64(x4, arg1[4]) + x305, x304 := bits.mul_u64(x4, arg1[3]) + x307, x306 := bits.mul_u64(x4, arg1[2]) + x309, x308 := bits.mul_u64(x4, arg1[1]) + x311, x310 := bits.mul_u64(x4, arg1[0]) + x312, x313 := bits.add_u64(x311, x308, u64(0x0)) + x314, x315 := bits.add_u64(x309, x306, u64(fiat.u1(x313))) + x316, x317 := bits.add_u64(x307, x304, u64(fiat.u1(x315))) + x318, x319 := bits.add_u64(x305, x302, u64(fiat.u1(x317))) + x320, x321 := bits.add_u64(x303, x300, u64(fiat.u1(x319))) + x322 := (u64(fiat.u1(x321)) + x301) + x323, x324 := bits.add_u64(x287, x310, u64(0x0)) + x325, x326 := bits.add_u64(x289, x312, u64(fiat.u1(x324))) + x327, x328 := bits.add_u64(x291, x314, u64(fiat.u1(x326))) + x329, x330 := bits.add_u64(x293, x316, u64(fiat.u1(x328))) + x331, x332 := bits.add_u64(x295, x318, u64(fiat.u1(x330))) + x333, x334 := bits.add_u64(x297, x320, u64(fiat.u1(x332))) + x335, x336 := bits.add_u64(x299, x322, u64(fiat.u1(x334))) + _, x337 := bits.mul_u64(x323, 0x6ed46089e88fdc45) + x340, x339 := bits.mul_u64(x337, 0xffffffffffffffff) + x342, x341 := bits.mul_u64(x337, 0xffffffffffffffff) + x344, x343 := bits.mul_u64(x337, 0xffffffffffffffff) + x346, x345 := bits.mul_u64(x337, 0xc7634d81f4372ddf) + x348, x347 := bits.mul_u64(x337, 0x581a0db248b0a77a) + x350, x349 := bits.mul_u64(x337, 0xecec196accc52973) + x351, x352 := bits.add_u64(x350, x347, u64(0x0)) + x353, x354 := bits.add_u64(x348, x345, u64(fiat.u1(x352))) + x355, x356 := bits.add_u64(x346, x343, u64(fiat.u1(x354))) + x357, x358 := bits.add_u64(x344, x341, u64(fiat.u1(x356))) + x359, x360 := bits.add_u64(x342, x339, u64(fiat.u1(x358))) + x361 := (u64(fiat.u1(x360)) + x340) + _, x363 := bits.add_u64(x323, x349, u64(0x0)) + x364, x365 := bits.add_u64(x325, x351, u64(fiat.u1(x363))) + x366, x367 := bits.add_u64(x327, x353, u64(fiat.u1(x365))) + x368, x369 := bits.add_u64(x329, x355, u64(fiat.u1(x367))) + x370, x371 := bits.add_u64(x331, x357, u64(fiat.u1(x369))) + x372, x373 := bits.add_u64(x333, x359, u64(fiat.u1(x371))) + x374, x375 := bits.add_u64(x335, x361, u64(fiat.u1(x373))) + x376 := (u64(fiat.u1(x375)) + u64(fiat.u1(x336))) + x378, x377 := bits.mul_u64(x5, arg1[5]) + x380, x379 := bits.mul_u64(x5, arg1[4]) + x382, x381 := bits.mul_u64(x5, arg1[3]) + x384, x383 := bits.mul_u64(x5, arg1[2]) + x386, x385 := bits.mul_u64(x5, arg1[1]) + x388, x387 := bits.mul_u64(x5, arg1[0]) + x389, x390 := bits.add_u64(x388, x385, u64(0x0)) + x391, x392 := bits.add_u64(x386, x383, u64(fiat.u1(x390))) + x393, x394 := bits.add_u64(x384, x381, u64(fiat.u1(x392))) + x395, x396 := bits.add_u64(x382, x379, u64(fiat.u1(x394))) + x397, x398 := bits.add_u64(x380, x377, u64(fiat.u1(x396))) + x399 := (u64(fiat.u1(x398)) + x378) + x400, x401 := bits.add_u64(x364, x387, u64(0x0)) + x402, x403 := bits.add_u64(x366, x389, u64(fiat.u1(x401))) + x404, x405 := bits.add_u64(x368, x391, u64(fiat.u1(x403))) + x406, x407 := bits.add_u64(x370, x393, u64(fiat.u1(x405))) + x408, x409 := bits.add_u64(x372, x395, u64(fiat.u1(x407))) + x410, x411 := bits.add_u64(x374, x397, u64(fiat.u1(x409))) + x412, x413 := bits.add_u64(x376, x399, u64(fiat.u1(x411))) + _, x414 := bits.mul_u64(x400, 0x6ed46089e88fdc45) + x417, x416 := bits.mul_u64(x414, 0xffffffffffffffff) + x419, x418 := bits.mul_u64(x414, 0xffffffffffffffff) + x421, x420 := bits.mul_u64(x414, 0xffffffffffffffff) + x423, x422 := bits.mul_u64(x414, 0xc7634d81f4372ddf) + x425, x424 := bits.mul_u64(x414, 0x581a0db248b0a77a) + x427, x426 := bits.mul_u64(x414, 0xecec196accc52973) + x428, x429 := bits.add_u64(x427, x424, u64(0x0)) + x430, x431 := bits.add_u64(x425, x422, u64(fiat.u1(x429))) + x432, x433 := bits.add_u64(x423, x420, u64(fiat.u1(x431))) + x434, x435 := bits.add_u64(x421, x418, u64(fiat.u1(x433))) + x436, x437 := bits.add_u64(x419, x416, u64(fiat.u1(x435))) + x438 := (u64(fiat.u1(x437)) + x417) + _, x440 := bits.add_u64(x400, x426, u64(0x0)) + x441, x442 := bits.add_u64(x402, x428, u64(fiat.u1(x440))) + x443, x444 := bits.add_u64(x404, x430, u64(fiat.u1(x442))) + x445, x446 := bits.add_u64(x406, x432, u64(fiat.u1(x444))) + x447, x448 := bits.add_u64(x408, x434, u64(fiat.u1(x446))) + x449, x450 := bits.add_u64(x410, x436, u64(fiat.u1(x448))) + x451, x452 := bits.add_u64(x412, x438, u64(fiat.u1(x450))) + x453 := (u64(fiat.u1(x452)) + u64(fiat.u1(x413))) + x454, x455 := bits.sub_u64(x441, 0xecec196accc52973, u64(0x0)) + x456, x457 := bits.sub_u64(x443, 0x581a0db248b0a77a, u64(fiat.u1(x455))) + x458, x459 := bits.sub_u64(x445, 0xc7634d81f4372ddf, u64(fiat.u1(x457))) + x460, x461 := bits.sub_u64(x447, 0xffffffffffffffff, u64(fiat.u1(x459))) + x462, x463 := bits.sub_u64(x449, 0xffffffffffffffff, u64(fiat.u1(x461))) + x464, x465 := bits.sub_u64(x451, 0xffffffffffffffff, u64(fiat.u1(x463))) + _, x467 := bits.sub_u64(x453, u64(0x0), u64(fiat.u1(x465))) + x468 := fiat.cmovznz_u64(fiat.u1(x467), x454, x441) + x469 := fiat.cmovznz_u64(fiat.u1(x467), x456, x443) + x470 := fiat.cmovznz_u64(fiat.u1(x467), x458, x445) + x471 := fiat.cmovznz_u64(fiat.u1(x467), x460, x447) + x472 := fiat.cmovznz_u64(fiat.u1(x467), x462, x449) + x473 := fiat.cmovznz_u64(fiat.u1(x467), x464, x451) + out1[0] = x468 + out1[1] = x469 + out1[2] = x470 + out1[3] = x471 + out1[4] = x472 + out1[5] = x473 +} + +fe_add :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) { + x1, x2 := bits.add_u64(arg1[0], arg2[0], u64(0x0)) + x3, x4 := bits.add_u64(arg1[1], arg2[1], u64(fiat.u1(x2))) + x5, x6 := bits.add_u64(arg1[2], arg2[2], u64(fiat.u1(x4))) + x7, x8 := bits.add_u64(arg1[3], arg2[3], u64(fiat.u1(x6))) + x9, x10 := bits.add_u64(arg1[4], arg2[4], u64(fiat.u1(x8))) + x11, x12 := bits.add_u64(arg1[5], arg2[5], u64(fiat.u1(x10))) + x13, x14 := bits.sub_u64(x1, 0xecec196accc52973, u64(0x0)) + x15, x16 := bits.sub_u64(x3, 0x581a0db248b0a77a, u64(fiat.u1(x14))) + x17, x18 := bits.sub_u64(x5, 0xc7634d81f4372ddf, u64(fiat.u1(x16))) + x19, x20 := bits.sub_u64(x7, 0xffffffffffffffff, u64(fiat.u1(x18))) + x21, x22 := bits.sub_u64(x9, 0xffffffffffffffff, u64(fiat.u1(x20))) + x23, x24 := bits.sub_u64(x11, 0xffffffffffffffff, u64(fiat.u1(x22))) + _, x26 := bits.sub_u64(u64(fiat.u1(x12)), u64(0x0), u64(fiat.u1(x24))) + x27 := fiat.cmovznz_u64(fiat.u1(x26), x13, x1) + x28 := fiat.cmovznz_u64(fiat.u1(x26), x15, x3) + x29 := fiat.cmovznz_u64(fiat.u1(x26), x17, x5) + x30 := fiat.cmovznz_u64(fiat.u1(x26), x19, x7) + x31 := fiat.cmovznz_u64(fiat.u1(x26), x21, x9) + x32 := fiat.cmovznz_u64(fiat.u1(x26), x23, x11) + out1[0] = x27 + out1[1] = x28 + out1[2] = x29 + out1[3] = x30 + out1[4] = x31 + out1[5] = x32 +} + +fe_sub :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) { + x1, x2 := bits.sub_u64(arg1[0], arg2[0], u64(0x0)) + x3, x4 := bits.sub_u64(arg1[1], arg2[1], u64(fiat.u1(x2))) + x5, x6 := bits.sub_u64(arg1[2], arg2[2], u64(fiat.u1(x4))) + x7, x8 := bits.sub_u64(arg1[3], arg2[3], u64(fiat.u1(x6))) + x9, x10 := bits.sub_u64(arg1[4], arg2[4], u64(fiat.u1(x8))) + x11, x12 := bits.sub_u64(arg1[5], arg2[5], u64(fiat.u1(x10))) + x13 := fiat.cmovznz_u64(fiat.u1(x12), u64(0x0), 0xffffffffffffffff) + x14, x15 := bits.add_u64(x1, (x13 & 0xecec196accc52973), u64(0x0)) + x16, x17 := bits.add_u64(x3, (x13 & 0x581a0db248b0a77a), u64(fiat.u1(x15))) + x18, x19 := bits.add_u64(x5, (x13 & 0xc7634d81f4372ddf), u64(fiat.u1(x17))) + x20, x21 := bits.add_u64(x7, x13, u64(fiat.u1(x19))) + x22, x23 := bits.add_u64(x9, x13, u64(fiat.u1(x21))) + x24, _ := bits.add_u64(x11, x13, u64(fiat.u1(x23))) + out1[0] = x14 + out1[1] = x16 + out1[2] = x18 + out1[3] = x20 + out1[4] = x22 + out1[5] = x24 +} + +fe_opp :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) { + x1, x2 := bits.sub_u64(u64(0x0), arg1[0], u64(0x0)) + x3, x4 := bits.sub_u64(u64(0x0), arg1[1], u64(fiat.u1(x2))) + x5, x6 := bits.sub_u64(u64(0x0), arg1[2], u64(fiat.u1(x4))) + x7, x8 := bits.sub_u64(u64(0x0), arg1[3], u64(fiat.u1(x6))) + x9, x10 := bits.sub_u64(u64(0x0), arg1[4], u64(fiat.u1(x8))) + x11, x12 := bits.sub_u64(u64(0x0), arg1[5], u64(fiat.u1(x10))) + x13 := fiat.cmovznz_u64(fiat.u1(x12), u64(0x0), 0xffffffffffffffff) + x14, x15 := bits.add_u64(x1, (x13 & 0xecec196accc52973), u64(0x0)) + x16, x17 := bits.add_u64(x3, (x13 & 0x581a0db248b0a77a), u64(fiat.u1(x15))) + x18, x19 := bits.add_u64(x5, (x13 & 0xc7634d81f4372ddf), u64(fiat.u1(x17))) + x20, x21 := bits.add_u64(x7, x13, u64(fiat.u1(x19))) + x22, x23 := bits.add_u64(x9, x13, u64(fiat.u1(x21))) + x24, _ := bits.add_u64(x11, x13, u64(fiat.u1(x23))) + out1[0] = x14 + out1[1] = x16 + out1[2] = x18 + out1[3] = x20 + out1[4] = x22 + out1[5] = x24 +} + +fe_one :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element) { + out1[0] = 0x1313e695333ad68d + out1[1] = 0xa7e5f24db74f5885 + out1[2] = 0x389cb27e0bc8d220 + out1[3] = 0x0 + out1[4] = 0x0 + out1[5] = 0x0 +} + +fe_non_zero :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) -> u64 { + return (arg1[0] | (arg1[1] | (arg1[2] | (arg1[3] | (arg1[4] | arg1[5]))))) +} + +@(optimization_mode = "none") +fe_cond_assign :: #force_no_inline proc "contextless" ( + out1, arg1: ^Montgomery_Domain_Field_Element, + arg2: int, +) { + x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0]) + x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1]) + x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2]) + x4 := fiat.cmovznz_u64(fiat.u1(arg2), out1[3], arg1[3]) + x5 := fiat.cmovznz_u64(fiat.u1(arg2), out1[4], arg1[4]) + x6 := fiat.cmovznz_u64(fiat.u1(arg2), out1[5], arg1[5]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 + out1[5] = x6 +} + +fe_from_montgomery :: proc "contextless" ( + out1: ^Non_Montgomery_Domain_Field_Element, + arg1: ^Montgomery_Domain_Field_Element, +) { + x1 := arg1[0] + _, x2 := bits.mul_u64(x1, 0x6ed46089e88fdc45) + x5, x4 := bits.mul_u64(x2, 0xffffffffffffffff) + x7, x6 := bits.mul_u64(x2, 0xffffffffffffffff) + x9, x8 := bits.mul_u64(x2, 0xffffffffffffffff) + x11, x10 := bits.mul_u64(x2, 0xc7634d81f4372ddf) + x13, x12 := bits.mul_u64(x2, 0x581a0db248b0a77a) + x15, x14 := bits.mul_u64(x2, 0xecec196accc52973) + x16, x17 := bits.add_u64(x15, x12, u64(0x0)) + x18, x19 := bits.add_u64(x13, x10, u64(fiat.u1(x17))) + x20, x21 := bits.add_u64(x11, x8, u64(fiat.u1(x19))) + x22, x23 := bits.add_u64(x9, x6, u64(fiat.u1(x21))) + x24, x25 := bits.add_u64(x7, x4, u64(fiat.u1(x23))) + _, x27 := bits.add_u64(x1, x14, u64(0x0)) + x28, x29 := bits.add_u64(u64(0x0), x16, u64(fiat.u1(x27))) + x30, x31 := bits.add_u64(u64(0x0), x18, u64(fiat.u1(x29))) + x32, x33 := bits.add_u64(u64(0x0), x20, u64(fiat.u1(x31))) + x34, x35 := bits.add_u64(u64(0x0), x22, u64(fiat.u1(x33))) + x36, x37 := bits.add_u64(u64(0x0), x24, u64(fiat.u1(x35))) + x38, x39 := bits.add_u64(u64(0x0), (u64(fiat.u1(x25)) + x5), u64(fiat.u1(x37))) + x40, x41 := bits.add_u64(x28, arg1[1], u64(0x0)) + x42, x43 := bits.add_u64(x30, u64(0x0), u64(fiat.u1(x41))) + x44, x45 := bits.add_u64(x32, u64(0x0), u64(fiat.u1(x43))) + x46, x47 := bits.add_u64(x34, u64(0x0), u64(fiat.u1(x45))) + x48, x49 := bits.add_u64(x36, u64(0x0), u64(fiat.u1(x47))) + x50, x51 := bits.add_u64(x38, u64(0x0), u64(fiat.u1(x49))) + _, x52 := bits.mul_u64(x40, 0x6ed46089e88fdc45) + x55, x54 := bits.mul_u64(x52, 0xffffffffffffffff) + x57, x56 := bits.mul_u64(x52, 0xffffffffffffffff) + x59, x58 := bits.mul_u64(x52, 0xffffffffffffffff) + x61, x60 := bits.mul_u64(x52, 0xc7634d81f4372ddf) + x63, x62 := bits.mul_u64(x52, 0x581a0db248b0a77a) + x65, x64 := bits.mul_u64(x52, 0xecec196accc52973) + x66, x67 := bits.add_u64(x65, x62, u64(0x0)) + x68, x69 := bits.add_u64(x63, x60, u64(fiat.u1(x67))) + x70, x71 := bits.add_u64(x61, x58, u64(fiat.u1(x69))) + x72, x73 := bits.add_u64(x59, x56, u64(fiat.u1(x71))) + x74, x75 := bits.add_u64(x57, x54, u64(fiat.u1(x73))) + _, x77 := bits.add_u64(x40, x64, u64(0x0)) + x78, x79 := bits.add_u64(x42, x66, u64(fiat.u1(x77))) + x80, x81 := bits.add_u64(x44, x68, u64(fiat.u1(x79))) + x82, x83 := bits.add_u64(x46, x70, u64(fiat.u1(x81))) + x84, x85 := bits.add_u64(x48, x72, u64(fiat.u1(x83))) + x86, x87 := bits.add_u64(x50, x74, u64(fiat.u1(x85))) + x88, x89 := bits.add_u64((u64(fiat.u1(x51)) + u64(fiat.u1(x39))), (u64(fiat.u1(x75)) + x55), u64(fiat.u1(x87))) + x90, x91 := bits.add_u64(x78, arg1[2], u64(0x0)) + x92, x93 := bits.add_u64(x80, u64(0x0), u64(fiat.u1(x91))) + x94, x95 := bits.add_u64(x82, u64(0x0), u64(fiat.u1(x93))) + x96, x97 := bits.add_u64(x84, u64(0x0), u64(fiat.u1(x95))) + x98, x99 := bits.add_u64(x86, u64(0x0), u64(fiat.u1(x97))) + x100, x101 := bits.add_u64(x88, u64(0x0), u64(fiat.u1(x99))) + _, x102 := bits.mul_u64(x90, 0x6ed46089e88fdc45) + x105, x104 := bits.mul_u64(x102, 0xffffffffffffffff) + x107, x106 := bits.mul_u64(x102, 0xffffffffffffffff) + x109, x108 := bits.mul_u64(x102, 0xffffffffffffffff) + x111, x110 := bits.mul_u64(x102, 0xc7634d81f4372ddf) + x113, x112 := bits.mul_u64(x102, 0x581a0db248b0a77a) + x115, x114 := bits.mul_u64(x102, 0xecec196accc52973) + x116, x117 := bits.add_u64(x115, x112, u64(0x0)) + x118, x119 := bits.add_u64(x113, x110, u64(fiat.u1(x117))) + x120, x121 := bits.add_u64(x111, x108, u64(fiat.u1(x119))) + x122, x123 := bits.add_u64(x109, x106, u64(fiat.u1(x121))) + x124, x125 := bits.add_u64(x107, x104, u64(fiat.u1(x123))) + _, x127 := bits.add_u64(x90, x114, u64(0x0)) + x128, x129 := bits.add_u64(x92, x116, u64(fiat.u1(x127))) + x130, x131 := bits.add_u64(x94, x118, u64(fiat.u1(x129))) + x132, x133 := bits.add_u64(x96, x120, u64(fiat.u1(x131))) + x134, x135 := bits.add_u64(x98, x122, u64(fiat.u1(x133))) + x136, x137 := bits.add_u64(x100, x124, u64(fiat.u1(x135))) + x138, x139 := bits.add_u64((u64(fiat.u1(x101)) + u64(fiat.u1(x89))), (u64(fiat.u1(x125)) + x105), u64(fiat.u1(x137))) + x140, x141 := bits.add_u64(x128, arg1[3], u64(0x0)) + x142, x143 := bits.add_u64(x130, u64(0x0), u64(fiat.u1(x141))) + x144, x145 := bits.add_u64(x132, u64(0x0), u64(fiat.u1(x143))) + x146, x147 := bits.add_u64(x134, u64(0x0), u64(fiat.u1(x145))) + x148, x149 := bits.add_u64(x136, u64(0x0), u64(fiat.u1(x147))) + x150, x151 := bits.add_u64(x138, u64(0x0), u64(fiat.u1(x149))) + _, x152 := bits.mul_u64(x140, 0x6ed46089e88fdc45) + x155, x154 := bits.mul_u64(x152, 0xffffffffffffffff) + x157, x156 := bits.mul_u64(x152, 0xffffffffffffffff) + x159, x158 := bits.mul_u64(x152, 0xffffffffffffffff) + x161, x160 := bits.mul_u64(x152, 0xc7634d81f4372ddf) + x163, x162 := bits.mul_u64(x152, 0x581a0db248b0a77a) + x165, x164 := bits.mul_u64(x152, 0xecec196accc52973) + x166, x167 := bits.add_u64(x165, x162, u64(0x0)) + x168, x169 := bits.add_u64(x163, x160, u64(fiat.u1(x167))) + x170, x171 := bits.add_u64(x161, x158, u64(fiat.u1(x169))) + x172, x173 := bits.add_u64(x159, x156, u64(fiat.u1(x171))) + x174, x175 := bits.add_u64(x157, x154, u64(fiat.u1(x173))) + _, x177 := bits.add_u64(x140, x164, u64(0x0)) + x178, x179 := bits.add_u64(x142, x166, u64(fiat.u1(x177))) + x180, x181 := bits.add_u64(x144, x168, u64(fiat.u1(x179))) + x182, x183 := bits.add_u64(x146, x170, u64(fiat.u1(x181))) + x184, x185 := bits.add_u64(x148, x172, u64(fiat.u1(x183))) + x186, x187 := bits.add_u64(x150, x174, u64(fiat.u1(x185))) + x188, x189 := bits.add_u64((u64(fiat.u1(x151)) + u64(fiat.u1(x139))), (u64(fiat.u1(x175)) + x155), u64(fiat.u1(x187))) + x190, x191 := bits.add_u64(x178, arg1[4], u64(0x0)) + x192, x193 := bits.add_u64(x180, u64(0x0), u64(fiat.u1(x191))) + x194, x195 := bits.add_u64(x182, u64(0x0), u64(fiat.u1(x193))) + x196, x197 := bits.add_u64(x184, u64(0x0), u64(fiat.u1(x195))) + x198, x199 := bits.add_u64(x186, u64(0x0), u64(fiat.u1(x197))) + x200, x201 := bits.add_u64(x188, u64(0x0), u64(fiat.u1(x199))) + _, x202 := bits.mul_u64(x190, 0x6ed46089e88fdc45) + x205, x204 := bits.mul_u64(x202, 0xffffffffffffffff) + x207, x206 := bits.mul_u64(x202, 0xffffffffffffffff) + x209, x208 := bits.mul_u64(x202, 0xffffffffffffffff) + x211, x210 := bits.mul_u64(x202, 0xc7634d81f4372ddf) + x213, x212 := bits.mul_u64(x202, 0x581a0db248b0a77a) + x215, x214 := bits.mul_u64(x202, 0xecec196accc52973) + x216, x217 := bits.add_u64(x215, x212, u64(0x0)) + x218, x219 := bits.add_u64(x213, x210, u64(fiat.u1(x217))) + x220, x221 := bits.add_u64(x211, x208, u64(fiat.u1(x219))) + x222, x223 := bits.add_u64(x209, x206, u64(fiat.u1(x221))) + x224, x225 := bits.add_u64(x207, x204, u64(fiat.u1(x223))) + _, x227 := bits.add_u64(x190, x214, u64(0x0)) + x228, x229 := bits.add_u64(x192, x216, u64(fiat.u1(x227))) + x230, x231 := bits.add_u64(x194, x218, u64(fiat.u1(x229))) + x232, x233 := bits.add_u64(x196, x220, u64(fiat.u1(x231))) + x234, x235 := bits.add_u64(x198, x222, u64(fiat.u1(x233))) + x236, x237 := bits.add_u64(x200, x224, u64(fiat.u1(x235))) + x238, x239 := bits.add_u64((u64(fiat.u1(x201)) + u64(fiat.u1(x189))), (u64(fiat.u1(x225)) + x205), u64(fiat.u1(x237))) + x240, x241 := bits.add_u64(x228, arg1[5], u64(0x0)) + x242, x243 := bits.add_u64(x230, u64(0x0), u64(fiat.u1(x241))) + x244, x245 := bits.add_u64(x232, u64(0x0), u64(fiat.u1(x243))) + x246, x247 := bits.add_u64(x234, u64(0x0), u64(fiat.u1(x245))) + x248, x249 := bits.add_u64(x236, u64(0x0), u64(fiat.u1(x247))) + x250, x251 := bits.add_u64(x238, u64(0x0), u64(fiat.u1(x249))) + _, x252 := bits.mul_u64(x240, 0x6ed46089e88fdc45) + x255, x254 := bits.mul_u64(x252, 0xffffffffffffffff) + x257, x256 := bits.mul_u64(x252, 0xffffffffffffffff) + x259, x258 := bits.mul_u64(x252, 0xffffffffffffffff) + x261, x260 := bits.mul_u64(x252, 0xc7634d81f4372ddf) + x263, x262 := bits.mul_u64(x252, 0x581a0db248b0a77a) + x265, x264 := bits.mul_u64(x252, 0xecec196accc52973) + x266, x267 := bits.add_u64(x265, x262, u64(0x0)) + x268, x269 := bits.add_u64(x263, x260, u64(fiat.u1(x267))) + x270, x271 := bits.add_u64(x261, x258, u64(fiat.u1(x269))) + x272, x273 := bits.add_u64(x259, x256, u64(fiat.u1(x271))) + x274, x275 := bits.add_u64(x257, x254, u64(fiat.u1(x273))) + _, x277 := bits.add_u64(x240, x264, u64(0x0)) + x278, x279 := bits.add_u64(x242, x266, u64(fiat.u1(x277))) + x280, x281 := bits.add_u64(x244, x268, u64(fiat.u1(x279))) + x282, x283 := bits.add_u64(x246, x270, u64(fiat.u1(x281))) + x284, x285 := bits.add_u64(x248, x272, u64(fiat.u1(x283))) + x286, x287 := bits.add_u64(x250, x274, u64(fiat.u1(x285))) + x288, x289 := bits.add_u64((u64(fiat.u1(x251)) + u64(fiat.u1(x239))), (u64(fiat.u1(x275)) + x255), u64(fiat.u1(x287))) + x290, x291 := bits.sub_u64(x278, 0xecec196accc52973, u64(0x0)) + x292, x293 := bits.sub_u64(x280, 0x581a0db248b0a77a, u64(fiat.u1(x291))) + x294, x295 := bits.sub_u64(x282, 0xc7634d81f4372ddf, u64(fiat.u1(x293))) + x296, x297 := bits.sub_u64(x284, 0xffffffffffffffff, u64(fiat.u1(x295))) + x298, x299 := bits.sub_u64(x286, 0xffffffffffffffff, u64(fiat.u1(x297))) + x300, x301 := bits.sub_u64(x288, 0xffffffffffffffff, u64(fiat.u1(x299))) + _, x303 := bits.sub_u64(u64(fiat.u1(x289)), u64(0x0), u64(fiat.u1(x301))) + x304 := fiat.cmovznz_u64(fiat.u1(x303), x290, x278) + x305 := fiat.cmovznz_u64(fiat.u1(x303), x292, x280) + x306 := fiat.cmovznz_u64(fiat.u1(x303), x294, x282) + x307 := fiat.cmovznz_u64(fiat.u1(x303), x296, x284) + x308 := fiat.cmovznz_u64(fiat.u1(x303), x298, x286) + x309 := fiat.cmovznz_u64(fiat.u1(x303), x300, x288) + out1[0] = x304 + out1[1] = x305 + out1[2] = x306 + out1[3] = x307 + out1[4] = x308 + out1[5] = x309 +} + +fe_to_montgomery :: proc "contextless" ( + out1: ^Montgomery_Domain_Field_Element, + arg1: ^Non_Montgomery_Domain_Field_Element, +) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[4] + x5 := arg1[5] + x6 := arg1[0] + x8, x7 := bits.mul_u64(x6, 0xc84ee012b39bf21) + x10, x9 := bits.mul_u64(x6, 0x3fb05b7a28266895) + x12, x11 := bits.mul_u64(x6, 0xd40d49174aab1cc5) + x14, x13 := bits.mul_u64(x6, 0xbc3e483afcb82947) + x16, x15 := bits.mul_u64(x6, 0xff3d81e5df1aa419) + x18, x17 := bits.mul_u64(x6, 0x2d319b2419b409a9) + x19, x20 := bits.add_u64(x18, x15, u64(0x0)) + x21, x22 := bits.add_u64(x16, x13, u64(fiat.u1(x20))) + x23, x24 := bits.add_u64(x14, x11, u64(fiat.u1(x22))) + x25, x26 := bits.add_u64(x12, x9, u64(fiat.u1(x24))) + x27, x28 := bits.add_u64(x10, x7, u64(fiat.u1(x26))) + _, x29 := bits.mul_u64(x17, 0x6ed46089e88fdc45) + x32, x31 := bits.mul_u64(x29, 0xffffffffffffffff) + x34, x33 := bits.mul_u64(x29, 0xffffffffffffffff) + x36, x35 := bits.mul_u64(x29, 0xffffffffffffffff) + x38, x37 := bits.mul_u64(x29, 0xc7634d81f4372ddf) + x40, x39 := bits.mul_u64(x29, 0x581a0db248b0a77a) + x42, x41 := bits.mul_u64(x29, 0xecec196accc52973) + x43, x44 := bits.add_u64(x42, x39, u64(0x0)) + x45, x46 := bits.add_u64(x40, x37, u64(fiat.u1(x44))) + x47, x48 := bits.add_u64(x38, x35, u64(fiat.u1(x46))) + x49, x50 := bits.add_u64(x36, x33, u64(fiat.u1(x48))) + x51, x52 := bits.add_u64(x34, x31, u64(fiat.u1(x50))) + _, x54 := bits.add_u64(x17, x41, u64(0x0)) + x55, x56 := bits.add_u64(x19, x43, u64(fiat.u1(x54))) + x57, x58 := bits.add_u64(x21, x45, u64(fiat.u1(x56))) + x59, x60 := bits.add_u64(x23, x47, u64(fiat.u1(x58))) + x61, x62 := bits.add_u64(x25, x49, u64(fiat.u1(x60))) + x63, x64 := bits.add_u64(x27, x51, u64(fiat.u1(x62))) + x65, x66 := bits.add_u64((u64(fiat.u1(x28)) + x8), (u64(fiat.u1(x52)) + x32), u64(fiat.u1(x64))) + x68, x67 := bits.mul_u64(x1, 0xc84ee012b39bf21) + x70, x69 := bits.mul_u64(x1, 0x3fb05b7a28266895) + x72, x71 := bits.mul_u64(x1, 0xd40d49174aab1cc5) + x74, x73 := bits.mul_u64(x1, 0xbc3e483afcb82947) + x76, x75 := bits.mul_u64(x1, 0xff3d81e5df1aa419) + x78, x77 := bits.mul_u64(x1, 0x2d319b2419b409a9) + x79, x80 := bits.add_u64(x78, x75, u64(0x0)) + x81, x82 := bits.add_u64(x76, x73, u64(fiat.u1(x80))) + x83, x84 := bits.add_u64(x74, x71, u64(fiat.u1(x82))) + x85, x86 := bits.add_u64(x72, x69, u64(fiat.u1(x84))) + x87, x88 := bits.add_u64(x70, x67, u64(fiat.u1(x86))) + x89, x90 := bits.add_u64(x55, x77, u64(0x0)) + x91, x92 := bits.add_u64(x57, x79, u64(fiat.u1(x90))) + x93, x94 := bits.add_u64(x59, x81, u64(fiat.u1(x92))) + x95, x96 := bits.add_u64(x61, x83, u64(fiat.u1(x94))) + x97, x98 := bits.add_u64(x63, x85, u64(fiat.u1(x96))) + x99, x100 := bits.add_u64(x65, x87, u64(fiat.u1(x98))) + _, x101 := bits.mul_u64(x89, 0x6ed46089e88fdc45) + x104, x103 := bits.mul_u64(x101, 0xffffffffffffffff) + x106, x105 := bits.mul_u64(x101, 0xffffffffffffffff) + x108, x107 := bits.mul_u64(x101, 0xffffffffffffffff) + x110, x109 := bits.mul_u64(x101, 0xc7634d81f4372ddf) + x112, x111 := bits.mul_u64(x101, 0x581a0db248b0a77a) + x114, x113 := bits.mul_u64(x101, 0xecec196accc52973) + x115, x116 := bits.add_u64(x114, x111, u64(0x0)) + x117, x118 := bits.add_u64(x112, x109, u64(fiat.u1(x116))) + x119, x120 := bits.add_u64(x110, x107, u64(fiat.u1(x118))) + x121, x122 := bits.add_u64(x108, x105, u64(fiat.u1(x120))) + x123, x124 := bits.add_u64(x106, x103, u64(fiat.u1(x122))) + _, x126 := bits.add_u64(x89, x113, u64(0x0)) + x127, x128 := bits.add_u64(x91, x115, u64(fiat.u1(x126))) + x129, x130 := bits.add_u64(x93, x117, u64(fiat.u1(x128))) + x131, x132 := bits.add_u64(x95, x119, u64(fiat.u1(x130))) + x133, x134 := bits.add_u64(x97, x121, u64(fiat.u1(x132))) + x135, x136 := bits.add_u64(x99, x123, u64(fiat.u1(x134))) + x137, x138 := bits.add_u64(((u64(fiat.u1(x100)) + u64(fiat.u1(x66))) + (u64(fiat.u1(x88)) + x68)), (u64(fiat.u1(x124)) + x104), u64(fiat.u1(x136))) + x140, x139 := bits.mul_u64(x2, 0xc84ee012b39bf21) + x142, x141 := bits.mul_u64(x2, 0x3fb05b7a28266895) + x144, x143 := bits.mul_u64(x2, 0xd40d49174aab1cc5) + x146, x145 := bits.mul_u64(x2, 0xbc3e483afcb82947) + x148, x147 := bits.mul_u64(x2, 0xff3d81e5df1aa419) + x150, x149 := bits.mul_u64(x2, 0x2d319b2419b409a9) + x151, x152 := bits.add_u64(x150, x147, u64(0x0)) + x153, x154 := bits.add_u64(x148, x145, u64(fiat.u1(x152))) + x155, x156 := bits.add_u64(x146, x143, u64(fiat.u1(x154))) + x157, x158 := bits.add_u64(x144, x141, u64(fiat.u1(x156))) + x159, x160 := bits.add_u64(x142, x139, u64(fiat.u1(x158))) + x161, x162 := bits.add_u64(x127, x149, u64(0x0)) + x163, x164 := bits.add_u64(x129, x151, u64(fiat.u1(x162))) + x165, x166 := bits.add_u64(x131, x153, u64(fiat.u1(x164))) + x167, x168 := bits.add_u64(x133, x155, u64(fiat.u1(x166))) + x169, x170 := bits.add_u64(x135, x157, u64(fiat.u1(x168))) + x171, x172 := bits.add_u64(x137, x159, u64(fiat.u1(x170))) + _, x173 := bits.mul_u64(x161, 0x6ed46089e88fdc45) + x176, x175 := bits.mul_u64(x173, 0xffffffffffffffff) + x178, x177 := bits.mul_u64(x173, 0xffffffffffffffff) + x180, x179 := bits.mul_u64(x173, 0xffffffffffffffff) + x182, x181 := bits.mul_u64(x173, 0xc7634d81f4372ddf) + x184, x183 := bits.mul_u64(x173, 0x581a0db248b0a77a) + x186, x185 := bits.mul_u64(x173, 0xecec196accc52973) + x187, x188 := bits.add_u64(x186, x183, u64(0x0)) + x189, x190 := bits.add_u64(x184, x181, u64(fiat.u1(x188))) + x191, x192 := bits.add_u64(x182, x179, u64(fiat.u1(x190))) + x193, x194 := bits.add_u64(x180, x177, u64(fiat.u1(x192))) + x195, x196 := bits.add_u64(x178, x175, u64(fiat.u1(x194))) + _, x198 := bits.add_u64(x161, x185, u64(0x0)) + x199, x200 := bits.add_u64(x163, x187, u64(fiat.u1(x198))) + x201, x202 := bits.add_u64(x165, x189, u64(fiat.u1(x200))) + x203, x204 := bits.add_u64(x167, x191, u64(fiat.u1(x202))) + x205, x206 := bits.add_u64(x169, x193, u64(fiat.u1(x204))) + x207, x208 := bits.add_u64(x171, x195, u64(fiat.u1(x206))) + x209, x210 := bits.add_u64(((u64(fiat.u1(x172)) + u64(fiat.u1(x138))) + (u64(fiat.u1(x160)) + x140)), (u64(fiat.u1(x196)) + x176), u64(fiat.u1(x208))) + x212, x211 := bits.mul_u64(x3, 0xc84ee012b39bf21) + x214, x213 := bits.mul_u64(x3, 0x3fb05b7a28266895) + x216, x215 := bits.mul_u64(x3, 0xd40d49174aab1cc5) + x218, x217 := bits.mul_u64(x3, 0xbc3e483afcb82947) + x220, x219 := bits.mul_u64(x3, 0xff3d81e5df1aa419) + x222, x221 := bits.mul_u64(x3, 0x2d319b2419b409a9) + x223, x224 := bits.add_u64(x222, x219, u64(0x0)) + x225, x226 := bits.add_u64(x220, x217, u64(fiat.u1(x224))) + x227, x228 := bits.add_u64(x218, x215, u64(fiat.u1(x226))) + x229, x230 := bits.add_u64(x216, x213, u64(fiat.u1(x228))) + x231, x232 := bits.add_u64(x214, x211, u64(fiat.u1(x230))) + x233, x234 := bits.add_u64(x199, x221, u64(0x0)) + x235, x236 := bits.add_u64(x201, x223, u64(fiat.u1(x234))) + x237, x238 := bits.add_u64(x203, x225, u64(fiat.u1(x236))) + x239, x240 := bits.add_u64(x205, x227, u64(fiat.u1(x238))) + x241, x242 := bits.add_u64(x207, x229, u64(fiat.u1(x240))) + x243, x244 := bits.add_u64(x209, x231, u64(fiat.u1(x242))) + _, x245 := bits.mul_u64(x233, 0x6ed46089e88fdc45) + x248, x247 := bits.mul_u64(x245, 0xffffffffffffffff) + x250, x249 := bits.mul_u64(x245, 0xffffffffffffffff) + x252, x251 := bits.mul_u64(x245, 0xffffffffffffffff) + x254, x253 := bits.mul_u64(x245, 0xc7634d81f4372ddf) + x256, x255 := bits.mul_u64(x245, 0x581a0db248b0a77a) + x258, x257 := bits.mul_u64(x245, 0xecec196accc52973) + x259, x260 := bits.add_u64(x258, x255, u64(0x0)) + x261, x262 := bits.add_u64(x256, x253, u64(fiat.u1(x260))) + x263, x264 := bits.add_u64(x254, x251, u64(fiat.u1(x262))) + x265, x266 := bits.add_u64(x252, x249, u64(fiat.u1(x264))) + x267, x268 := bits.add_u64(x250, x247, u64(fiat.u1(x266))) + _, x270 := bits.add_u64(x233, x257, u64(0x0)) + x271, x272 := bits.add_u64(x235, x259, u64(fiat.u1(x270))) + x273, x274 := bits.add_u64(x237, x261, u64(fiat.u1(x272))) + x275, x276 := bits.add_u64(x239, x263, u64(fiat.u1(x274))) + x277, x278 := bits.add_u64(x241, x265, u64(fiat.u1(x276))) + x279, x280 := bits.add_u64(x243, x267, u64(fiat.u1(x278))) + x281, x282 := bits.add_u64(((u64(fiat.u1(x244)) + u64(fiat.u1(x210))) + (u64(fiat.u1(x232)) + x212)), (u64(fiat.u1(x268)) + x248), u64(fiat.u1(x280))) + x284, x283 := bits.mul_u64(x4, 0xc84ee012b39bf21) + x286, x285 := bits.mul_u64(x4, 0x3fb05b7a28266895) + x288, x287 := bits.mul_u64(x4, 0xd40d49174aab1cc5) + x290, x289 := bits.mul_u64(x4, 0xbc3e483afcb82947) + x292, x291 := bits.mul_u64(x4, 0xff3d81e5df1aa419) + x294, x293 := bits.mul_u64(x4, 0x2d319b2419b409a9) + x295, x296 := bits.add_u64(x294, x291, u64(0x0)) + x297, x298 := bits.add_u64(x292, x289, u64(fiat.u1(x296))) + x299, x300 := bits.add_u64(x290, x287, u64(fiat.u1(x298))) + x301, x302 := bits.add_u64(x288, x285, u64(fiat.u1(x300))) + x303, x304 := bits.add_u64(x286, x283, u64(fiat.u1(x302))) + x305, x306 := bits.add_u64(x271, x293, u64(0x0)) + x307, x308 := bits.add_u64(x273, x295, u64(fiat.u1(x306))) + x309, x310 := bits.add_u64(x275, x297, u64(fiat.u1(x308))) + x311, x312 := bits.add_u64(x277, x299, u64(fiat.u1(x310))) + x313, x314 := bits.add_u64(x279, x301, u64(fiat.u1(x312))) + x315, x316 := bits.add_u64(x281, x303, u64(fiat.u1(x314))) + _, x317 := bits.mul_u64(x305, 0x6ed46089e88fdc45) + x320, x319 := bits.mul_u64(x317, 0xffffffffffffffff) + x322, x321 := bits.mul_u64(x317, 0xffffffffffffffff) + x324, x323 := bits.mul_u64(x317, 0xffffffffffffffff) + x326, x325 := bits.mul_u64(x317, 0xc7634d81f4372ddf) + x328, x327 := bits.mul_u64(x317, 0x581a0db248b0a77a) + x330, x329 := bits.mul_u64(x317, 0xecec196accc52973) + x331, x332 := bits.add_u64(x330, x327, u64(0x0)) + x333, x334 := bits.add_u64(x328, x325, u64(fiat.u1(x332))) + x335, x336 := bits.add_u64(x326, x323, u64(fiat.u1(x334))) + x337, x338 := bits.add_u64(x324, x321, u64(fiat.u1(x336))) + x339, x340 := bits.add_u64(x322, x319, u64(fiat.u1(x338))) + _, x342 := bits.add_u64(x305, x329, u64(0x0)) + x343, x344 := bits.add_u64(x307, x331, u64(fiat.u1(x342))) + x345, x346 := bits.add_u64(x309, x333, u64(fiat.u1(x344))) + x347, x348 := bits.add_u64(x311, x335, u64(fiat.u1(x346))) + x349, x350 := bits.add_u64(x313, x337, u64(fiat.u1(x348))) + x351, x352 := bits.add_u64(x315, x339, u64(fiat.u1(x350))) + x353, x354 := bits.add_u64(((u64(fiat.u1(x316)) + u64(fiat.u1(x282))) + (u64(fiat.u1(x304)) + x284)), (u64(fiat.u1(x340)) + x320), u64(fiat.u1(x352))) + x356, x355 := bits.mul_u64(x5, 0xc84ee012b39bf21) + x358, x357 := bits.mul_u64(x5, 0x3fb05b7a28266895) + x360, x359 := bits.mul_u64(x5, 0xd40d49174aab1cc5) + x362, x361 := bits.mul_u64(x5, 0xbc3e483afcb82947) + x364, x363 := bits.mul_u64(x5, 0xff3d81e5df1aa419) + x366, x365 := bits.mul_u64(x5, 0x2d319b2419b409a9) + x367, x368 := bits.add_u64(x366, x363, u64(0x0)) + x369, x370 := bits.add_u64(x364, x361, u64(fiat.u1(x368))) + x371, x372 := bits.add_u64(x362, x359, u64(fiat.u1(x370))) + x373, x374 := bits.add_u64(x360, x357, u64(fiat.u1(x372))) + x375, x376 := bits.add_u64(x358, x355, u64(fiat.u1(x374))) + x377, x378 := bits.add_u64(x343, x365, u64(0x0)) + x379, x380 := bits.add_u64(x345, x367, u64(fiat.u1(x378))) + x381, x382 := bits.add_u64(x347, x369, u64(fiat.u1(x380))) + x383, x384 := bits.add_u64(x349, x371, u64(fiat.u1(x382))) + x385, x386 := bits.add_u64(x351, x373, u64(fiat.u1(x384))) + x387, x388 := bits.add_u64(x353, x375, u64(fiat.u1(x386))) + _, x389 := bits.mul_u64(x377, 0x6ed46089e88fdc45) + x392, x391 := bits.mul_u64(x389, 0xffffffffffffffff) + x394, x393 := bits.mul_u64(x389, 0xffffffffffffffff) + x396, x395 := bits.mul_u64(x389, 0xffffffffffffffff) + x398, x397 := bits.mul_u64(x389, 0xc7634d81f4372ddf) + x400, x399 := bits.mul_u64(x389, 0x581a0db248b0a77a) + x402, x401 := bits.mul_u64(x389, 0xecec196accc52973) + x403, x404 := bits.add_u64(x402, x399, u64(0x0)) + x405, x406 := bits.add_u64(x400, x397, u64(fiat.u1(x404))) + x407, x408 := bits.add_u64(x398, x395, u64(fiat.u1(x406))) + x409, x410 := bits.add_u64(x396, x393, u64(fiat.u1(x408))) + x411, x412 := bits.add_u64(x394, x391, u64(fiat.u1(x410))) + _, x414 := bits.add_u64(x377, x401, u64(0x0)) + x415, x416 := bits.add_u64(x379, x403, u64(fiat.u1(x414))) + x417, x418 := bits.add_u64(x381, x405, u64(fiat.u1(x416))) + x419, x420 := bits.add_u64(x383, x407, u64(fiat.u1(x418))) + x421, x422 := bits.add_u64(x385, x409, u64(fiat.u1(x420))) + x423, x424 := bits.add_u64(x387, x411, u64(fiat.u1(x422))) + x425, x426 := bits.add_u64(((u64(fiat.u1(x388)) + u64(fiat.u1(x354))) + (u64(fiat.u1(x376)) + x356)), (u64(fiat.u1(x412)) + x392), u64(fiat.u1(x424))) + x427, x428 := bits.sub_u64(x415, 0xecec196accc52973, u64(0x0)) + x429, x430 := bits.sub_u64(x417, 0x581a0db248b0a77a, u64(fiat.u1(x428))) + x431, x432 := bits.sub_u64(x419, 0xc7634d81f4372ddf, u64(fiat.u1(x430))) + x433, x434 := bits.sub_u64(x421, 0xffffffffffffffff, u64(fiat.u1(x432))) + x435, x436 := bits.sub_u64(x423, 0xffffffffffffffff, u64(fiat.u1(x434))) + x437, x438 := bits.sub_u64(x425, 0xffffffffffffffff, u64(fiat.u1(x436))) + _, x440 := bits.sub_u64(u64(fiat.u1(x426)), u64(0x0), u64(fiat.u1(x438))) + x441 := fiat.cmovznz_u64(fiat.u1(x440), x427, x415) + x442 := fiat.cmovznz_u64(fiat.u1(x440), x429, x417) + x443 := fiat.cmovznz_u64(fiat.u1(x440), x431, x419) + x444 := fiat.cmovznz_u64(fiat.u1(x440), x433, x421) + x445 := fiat.cmovznz_u64(fiat.u1(x440), x435, x423) + x446 := fiat.cmovznz_u64(fiat.u1(x440), x437, x425) + out1[0] = x441 + out1[1] = x442 + out1[2] = x443 + out1[3] = x444 + out1[4] = x445 + out1[5] = x446 +} diff --git a/core/crypto/_sha3/sha3.odin b/core/crypto/_sha3/sha3.odin index 02b0b6578..b2d032b31 100644 --- a/core/crypto/_sha3/sha3.odin +++ b/core/crypto/_sha3/sha3.odin @@ -16,7 +16,7 @@ package _sha3 */ import "core:math/bits" -import "core:mem" +import "core:crypto" ROUNDS :: 24 @@ -179,7 +179,7 @@ reset :: proc "contextless" (ctx: ^Context) { return } - mem.zero_explicit(ctx, size_of(ctx^)) + crypto.zero_explicit(ctx, size_of(ctx^)) } shake_xof :: proc "contextless" (ctx: ^Context) { diff --git a/core/crypto/_subtle/subtle.odin b/core/crypto/_subtle/subtle.odin new file mode 100644 index 000000000..454066e4a --- /dev/null +++ b/core/crypto/_subtle/subtle.odin @@ -0,0 +1,42 @@ +/* +Various useful bit operations in constant time. +*/ +package _subtle + +import "core:math/bits" + +// byte_eq returns 1 if and only if (⟺) a == b, 0 otherwise. +@(optimization_mode="none") +byte_eq :: proc "contextless" (a, b: byte) -> int { + v := a ~ b + + // v == 0 if and only if (⟺) a == b. The subtraction will underflow, setting the + // sign bit, which will get returned. + return int((u32(v)-1) >> 31) +} + +// u64_eq returns 1 if and only if (⟺) a == b, 0 otherwise. +@(optimization_mode="none") +u64_eq :: proc "contextless" (a, b: u64) -> u64 { + _, borrow := bits.sub_u64(0, a ~ b, 0) + return (~borrow) & 1 +} + +eq :: proc { + byte_eq, + u64_eq, +} + +// u64_is_zero returns 1 if and only if (⟺) a == 0, 0 otherwise. +@(optimization_mode="none") +u64_is_zero :: proc "contextless" (a: u64) -> u64 { + _, borrow := bits.sub_u64(a, 1, 0) + return borrow +} + +// u64_is_non_zero returns 1 if and only if (⟺) a != 0, 0 otherwise. +@(optimization_mode="none") +u64_is_non_zero :: proc "contextless" (a: u64) -> u64 { + is_zero := u64_is_zero(a) + return (~is_zero) & 1 +} diff --git a/core/crypto/_weierstrass/fe.odin b/core/crypto/_weierstrass/fe.odin new file mode 100644 index 000000000..8ff6fe346 --- /dev/null +++ b/core/crypto/_weierstrass/fe.odin @@ -0,0 +1,205 @@ +package _weierstrass + +import p256r1 "core:crypto/_fiat/field_p256r1" +import p384r1 "core:crypto/_fiat/field_p384r1" +import subtle "core:crypto/_subtle" + +Field_Element_p256r1 :: p256r1.Montgomery_Domain_Field_Element +Field_Element_p384r1 :: p384r1.Montgomery_Domain_Field_Element + +FE_SIZE_P256R1 :: 32 +FE_SIZE_P384R1 :: 48 + +fe_clear :: proc { + p256r1.fe_clear, + p384r1.fe_clear, +} + +fe_clear_vec :: proc { + p256r1.fe_clear_vec, + p384r1.fe_clear_vec, +} + +fe_set_bytes :: proc { + p256r1.fe_from_bytes, + p384r1.fe_from_bytes, +} + +fe_bytes :: proc { + p256r1.fe_to_bytes, + p384r1.fe_to_bytes, +} + +fe_set :: proc { + p256r1.fe_set, + p384r1.fe_set, +} + +fe_zero :: proc { + p256r1.fe_zero, + p384r1.fe_zero, +} + +fe_a :: proc { + fe_a_p256r1, + fe_a_p384r1, +} + +fe_b :: proc { + fe_b_p256r1, + fe_b_p384r1, +} + +fe_gen_x :: proc { + fe_gen_x_p256r1, + fe_gen_x_p384r1, +} + +fe_gen_y :: proc { + fe_gen_y_p256r1, + fe_gen_y_p384r1, +} + +fe_one :: proc { + p256r1.fe_one, + p384r1.fe_one, +} + +fe_add :: proc { + p256r1.fe_add, + p384r1.fe_add, +} + +fe_sub :: proc { + p256r1.fe_sub, + p384r1.fe_sub, +} + +fe_negate :: proc { + p256r1.fe_opp, + p384r1.fe_opp, +} + +fe_mul :: proc { + p256r1.fe_mul, + p384r1.fe_mul, +} + +fe_square :: proc { + p256r1.fe_square, + p384r1.fe_square, +} + +fe_inv :: proc { + p256r1.fe_inv, + p384r1.fe_inv, +} + +fe_sqrt :: proc { + p256r1.fe_sqrt, + p384r1.fe_sqrt, +} + +fe_equal :: proc { + p256r1.fe_equal, + p384r1.fe_equal, +} + +fe_is_odd :: proc { + p256r1.fe_is_odd, + p384r1.fe_is_odd, +} + +fe_is_zero :: proc { + fe_is_zero_p256r1, + fe_is_zero_p384r1, +} + +fe_cond_select :: proc { + p256r1.fe_cond_select, + p384r1.fe_cond_select, +} + +fe_a_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) { + // a = 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc + // = -3 mod p + fe[0] = 18446744073709551612 + fe[1] = 17179869183 + fe[2] = 0 + fe[3] = 18446744056529682436 +} + +fe_b_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) { + // b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b + fe[0] = 15608596021259845087 + fe[1] = 12461466548982526096 + fe[2] = 16546823903870267094 + fe[3] = 15866188208926050356 +} + +fe_gen_x_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) { + // G_x = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296 + fe[0] = 8784043285714375740 + fe[1] = 8483257759279461889 + fe[2] = 8789745728267363600 + fe[3] = 1770019616739251654 +} + +fe_gen_y_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) { + // G_y = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5 + fe[0] = 15992936863339206154 + fe[1] = 10037038012062884956 + fe[2] = 15197544864945402661 + fe[3] = 9615747158586711429 +} + +fe_a_p384r1 :: proc "contextless" (fe: ^Field_Element_p384r1) { + // a = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc + // = -3 mod p + fe[0] = 17179869180 + fe[1] = 18446744056529682432 + fe[2] = 18446744073709551611 + fe[3] = 18446744073709551615 + fe[4] = 18446744073709551615 + fe[5] = 18446744073709551615 +} + +fe_b_p384r1 :: proc "contextless" (fe: ^Field_Element_p384r1) { + // b = 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef + fe[0] = 581395848458481100 + fe[1] = 17809957346689692396 + fe[2] = 8643006485390950958 + fe[3] = 16372638458395724514 + fe[4] = 13126622871277412500 + fe[5] = 14774077593024970745 +} + +fe_gen_x_p384r1 :: proc "contextless" (fe: ^Field_Element_p384r1) { + // G_x = 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7 + fe[0] = 4454189113653900584 + fe[1] = 2369870743683386936 + fe[2] = 9771750146904378734 + fe[3] = 7229551204834152191 + fe[4] = 9308930686126579243 + fe[5] = 5564951339003155731 +} + +fe_gen_y_p384r1 :: proc "contextless" (fe: ^Field_Element_p384r1) { + // G_y = 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f + fe[0] = 2523209505731486974 + fe[1] = 11655219901025790380 + fe[2] = 10064955099576512592 + fe[3] = 14322381509056856025 + fe[4] = 15960759442596276288 + fe[5] = 3132442392059561449 +} + +@(require_results) +fe_is_zero_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) -> int { + return int(subtle.u64_is_zero(p256r1.fe_non_zero(fe))) +} + +@(require_results) +fe_is_zero_p384r1 :: proc "contextless" (fe: ^Field_Element_p384r1) -> int { + return int(subtle.u64_is_zero(p384r1.fe_non_zero(fe))) +} diff --git a/core/crypto/_weierstrass/point.odin b/core/crypto/_weierstrass/point.odin new file mode 100644 index 000000000..0e6e48678 --- /dev/null +++ b/core/crypto/_weierstrass/point.odin @@ -0,0 +1,580 @@ +package _weierstrass + +/* +This implements prime order short Weierstrass curves defined over a field +k with char(k) != 2, 3 (`y^2 = x^3 + ax + b`). for the purpose of +implementing ECDH and ECDSA. Use of this package for other purposes is +NOT RECOMMENDED. + +As an explicit simplicity/performance tradeoff, projective representation +was chosen so that it is possible to use the complete addition +formulas. + +See: +- https://eprint.iacr.org/2015/1060.pdf +- https://hyperelliptic.org/EFD/g1p/auto-shortw-projective.html + +WARNING: The point addition and doubling formulas are specialized for +`a = -3`, which covers secp256r1, secp384r1, secp521r1, FRP256v1, SM2, +and GOST 34.10. The brainpool curves and secp256k1 are NOT SUPPORTED +and would require slightly different formulas. +*/ + +Point_p256r1 :: struct { + x: Field_Element_p256r1, + y: Field_Element_p256r1, + z: Field_Element_p256r1, +} + +Point_p384r1 :: struct { + x: Field_Element_p384r1, + y: Field_Element_p384r1, + z: Field_Element_p384r1, +} + +@(require_results) +pt_set_xy_bytes :: proc "contextless" (p: ^$T, x_raw, y_raw: []byte) -> bool { + when T == Point_p256r1 { + FE_SZ :: FE_SIZE_P256R1 + x, y: Field_Element_p256r1 + defer fe_clear_vec([]^Field_Element_p256r1{&x, &y}) + } else when T == Point_p384r1 { + FE_SZ :: FE_SIZE_P384R1 + x, y: Field_Element_p384r1 + defer fe_clear_vec([]^Field_Element_p384r1{&x, &y}) + } else { + #panic("weierstrass: invalid curve") + } + + if len(x_raw) != FE_SZ || len(y_raw) != FE_SZ { + return false + } + + if !fe_set_bytes(&x, x_raw) { + return false + } + if !fe_set_bytes(&y, y_raw) { + return false + } + if !is_on_curve(&x, &y) { + return false + } + + fe_set(&p.x, &x) + fe_set(&p.y, &y) + fe_one(&p.z) + + return true +} + +@(require_results) +pt_set_x_bytes :: proc "contextless" (p: ^$T, x_raw: []byte, y_is_odd: int) -> bool { + when T == Point_p256r1 { + FE_SZ :: FE_SIZE_P256R1 + x, y, yy, y_neg: Field_Element_p256r1 + defer fe_clear_vec([]^Field_Element_p256r1{&x, &y, &yy, &y_neg}) + } else when T == Point_p384r1 { + FE_SZ :: FE_SIZE_P384R1 + x, y, yy, y_neg: Field_Element_p384r1 + defer fe_clear_vec([]^Field_Element_p384r1{&x, &y, &yy, &y_neg}) + } else { + #panic("weierstrass: invalid curve") + } + + if len(x_raw) != FE_SZ { + return false + } + + if !fe_set_bytes(&x, x_raw) { + return false + } + set_yy_candidate(&yy, &x) + if fe_sqrt(&y, &yy) != 1 { + return false + } + + // Pick the correct y-coordinate. + fe_negate(&y_neg, &y) + parity_neq := (y_is_odd ~ fe_is_odd(&y)) & 1 + + fe_set(&p.x, &x) + fe_cond_select(&p.y, &y, &y_neg, parity_neq) + fe_one(&p.z) + + return true +} + +@(require_results) +pt_bytes :: proc "contextless" (x, y: []byte, p: ^$T) -> bool { + when T == Point_p256r1 { + FE_SZ :: FE_SIZE_P256R1 + } else when T == Point_p384r1 { + FE_SZ :: FE_SIZE_P384R1 + } else { + #panic("weierstrass: invalid curve") + } + + if pt_is_identity(p) == 1 { + return false + } + + // Convert to affine coordinates. + pt_rescale(p, p) + + switch len(x) { + case 0: + case FE_SZ: + fe_bytes(x, &p.x) + case: + panic_contextless("weierstrass: invalid x buffer") + } + switch len(y) { + case 0: + case FE_SZ: + fe_bytes(y, &p.y) + case: + panic_contextless("weierstrass: invalid y buffer") + } + + return true +} + +pt_set :: proc "contextless" (p, q: ^$T) { + fe_set(&p.x, &q.x) + fe_set(&p.y, &q.y) + fe_set(&p.z, &q.z) +} + +pt_identity :: proc "contextless" (p: ^$T) { + fe_zero(&p.x) + fe_one(&p.y) + fe_zero(&p.z) +} + +pt_generator :: proc "contextless" (p: ^$T) { + fe_gen_x(&p.x) + fe_gen_y(&p.y) + fe_one(&p.z) +} + +pt_clear :: proc "contextless" (p: ^$T) { + fe_clear(&p.x) + fe_clear(&p.y) + fe_clear(&p.z) +} + +pt_clear_vec :: proc "contextless" (arg: []^$T) { + for p in arg { + pt_clear(p) + } +} + +pt_add :: proc "contextless" (p, a, b: ^$T) { + // Algorithm 4 from "Complete addition formulas for prime + // order elliptic curves" by Renes, Costello, and Batina. + // + // The formula is complete in that it is valid for all a and b, + // without exceptions or extra assumptions about the inputs. + // + // The operation costs are `12M + 2mb + 29a`. + + when T == Point_p256r1 { + t0, t1, t2, t3, t4, b_fe: Field_Element_p256r1 + x3, y3, z3: Field_Element_p256r1 + defer fe_clear_vec([]^Field_Element_p256r1{&t0, &t1, &t2, &t3, &t4, &x3, &y3, &z3}) + } else when T == Point_p384r1 { + t0, t1, t2, t3, t4, b_fe: Field_Element_p384r1 + x3, y3, z3: Field_Element_p384r1 + defer fe_clear_vec([]^Field_Element_p384r1{&t0, &t1, &t2, &t3, &t4, &x3, &y3, &z3}) + } else { + #panic("weierstrass: invalid curve") + } + + x1, y1, z1 := &a.x, &a.y, &a.z + x2, y2, z2 := &b.x, &b.y, &b.z + + fe_b(&b_fe) + + // t0 := X1 * X2 ; t1 := Y1 * Y2 ; t2 := Z1 * Z2 ; + fe_mul(&t0, x1, x2) + fe_mul(&t1, y1, y2) + fe_mul(&t2, z1, z2) + + // t3 := X1 + Y1 ; t4 := X2 + Y2 ; t3 := t3 * t4 ; + fe_add(&t3, x1, y1) + fe_add(&t4, x2, y2) + fe_mul(&t3, &t3, &t4) + + // t4 := t0 + t1 ; t3 := t3 - t4 ; t4 := Y1 + Z1 ; + fe_add(&t4, &t0, &t1) + fe_sub(&t3, &t3, &t4) + fe_add(&t4, y1, z1) + + // X3 := Y2 + Z2 ; t4 := t4 * X3 ; X3 := t1 + t2 ; + fe_add(&x3, y2, z2) + fe_mul(&t4, &t4, &x3) + fe_add(&x3, &t1, &t2) + + // t4 := t4 - X3 ; X3 := X1 + Z1 ; Y3 := X2 + Z2 ; + fe_sub(&t4, &t4, &x3) + fe_add(&x3, x1, z1) + fe_add(&y3, x2, z2) + + // X3 := X3 * Y3 ; Y3 := t0 + t2 ; Y3 := X3 - Y3 ; + fe_mul(&x3, &x3, &y3) + fe_add(&y3, &t0, &t2) + fe_sub(&y3, &x3, &y3) + + // Z3 := b * t2 ; X3 := Y3 - Z3 ; Z3 := X3 + X3 ; + fe_mul(&z3, &b_fe, &t2) + fe_sub(&x3, &y3, &z3) + fe_add(&z3, &x3, &x3) + + // X3 := X3 + Z3 ; Z3 := t1 - X3 ; X3 := t1 + X3 ; + fe_add(&x3, &x3, &z3) + fe_sub(&z3, &t1, &x3) + fe_add(&x3, &t1, &x3) + + // Y3 := b * Y3 ; t1 := t2 + t2 ; t2 := t1 + t2 ; + fe_mul(&y3, &b_fe, &y3) + fe_add(&t1, &t2, &t2) + fe_add(&t2, &t1, &t2) + + // Y3 := Y3 - t2 ; Y3 := Y3 - t0 ; t1 := Y3 + Y3 ; + fe_sub(&y3, &y3, &t2) + fe_sub(&y3, &y3, &t0) + fe_add(&t1, &y3, &y3) + + // Y3 := t1 + Y3 ; t1 := t0 + t0 ; t0 := t1 + t0 ; + fe_add(&y3, &t1, &y3) + fe_add(&t1, &t0, &t0) + fe_add(&t0, &t1, &t0) + + // t0 := t0 - t2 ; t1 := t4 * Y3 ; t2 := t0 * Y3 ; + fe_sub(&t0, &t0, &t2) + fe_mul(&t1, &t4, &y3) + fe_mul(&t2, &t0, &y3) + + // Y3 := X3 * Z3 ; Y3 := Y3 + t2 ; X3 := t3 * X3 ; + fe_mul(&y3, &x3, &z3) + fe_add(&y3, &y3, &t2) + fe_mul(&x3, &t3, &x3) + + // X3 := X3 - t1 ; Z3 := t4 * Z3 ; t1 := t3 * t0 ; + fe_sub(&x3, &x3, &t1) + fe_mul(&z3, &t4, &z3) + fe_mul(&t1, &t3, &t0) + + // Z3 := Z3 + t1 ; + fe_add(&z3, &z3, &t1) + + // return X3 , Y3 , Z3 ; + fe_set(&p.x, &x3) + fe_set(&p.y, &y3) + fe_set(&p.z, &z3) +} + +@(private) +pt_add_mixed :: proc "contextless" (p, a: ^$T, x2, y2: ^$U) { + // Algorithm 5 from "Complete addition formulas for prime + // order elliptic curves" by Renes, Costello, and Batina. + // + // The formula is mixed in that it assumes the z-coordinate + // of the addend (`Z2`) is `1`, meaning that it CAN NOT + // handle the addend being the point at infinity. + // + // The operation costs are `11M + 2mb + 23a` saving + // `1M + 6a` over `pt_add`. + + when T == Point_p256r1 && U == Field_Element_p256r1 { + t0, t1, t2, t3, t4, b_fe: Field_Element_p256r1 + x3, y3, z3: Field_Element_p256r1 + defer fe_clear_vec([]^Field_Element_p256r1{&t0, &t1, &t2, &t3, &t4, &x3, &y3, &z3}) + } else when T == Point_p384r1 { + t0, t1, t2, t3, t4, b_fe: Field_Element_p384r1 + x3, y3, z3: Field_Element_p384r1 + defer fe_clear_vec([]^Field_Element_p384r1{&t0, &t1, &t2, &t3, &t4, &x3, &y3, &z3}) + } else { + #panic("weierstrass: invalid curve") + } + + x1, y1, z1 := &a.x, &a.y, &a.z + + fe_b(&b_fe) + + // t0 := X1 * X2 ; t1 := Y1 * Y2 ; t3 := X2 + Y2 ; + fe_mul(&t0, x1, x2) + fe_mul(&t1, y1, y2) + fe_add(&t3, x2, y2) + + // t4 := X1 + Y1 ; t3 := t3 * t4 ; t4 := t0 + t1 ; + fe_add(&t4, x1, y1) + fe_mul(&t3, &t3, &t4) + fe_add(&t4, &t0, &t1) + + // t3 := t3 − t4 ; t4 := Y2 * Z1 ; t4 := t4 + Y1 ; + fe_sub(&t3, &t3, &t4) + fe_mul(&t4, y2, z1) + fe_add(&t4, &t4, y1) + + // Y3 := X2 * Z1 ; Y3 := Y3 + X1 ; Z3 := b * Z1 ; + fe_mul(&y3, x2, z1) + fe_add(&y3, &y3, x1) + fe_mul(&z3, &b_fe, z1) + + // X3 := Y3 − Z3 ; Z3 := X3 + X3 ; X3 := X3 + Z3 ; + fe_sub(&x3, &y3, &z3) + fe_add(&z3, &x3, &x3) + fe_add(&x3, &x3, &z3) + + // Z3 := t1 − X3 ; X3 := t1 + X3 ;. Y3 := b * Y3 ; + fe_sub(&z3, &t1, &x3) + fe_add(&x3, &t1, &x3) + fe_mul(&y3, &b_fe, &y3) + + // t1 := Z1 + Z1 ; t2 := t1 + Z1 ; Y3 := Y3 − t2 ; + fe_add(&t1, z1, z1) + fe_add(&t2, &t1, z1) + fe_sub(&y3, &y3, &t2) + + // Y3 := Y3 − t0 ; t1 := Y3 + Y3 ; Y3 := t1 + Y3 ; + fe_sub(&y3, &y3, &t0) + fe_add(&t1, &y3, &y3) + fe_add(&y3, &t1, &y3) + + // t1 := t0 + t0 ; t0 := t1 + t0 ; t0 := t0 − t2 ; + fe_add(&t1, &t0, &t0) + fe_add(&t0, &t1, &t0) + fe_sub(&t0, &t0, &t2) + + // t1 := t4 * Y3 ; t2 := t0 * Y3 ; Y3 := X3 * Z3 ; + fe_mul(&t1, &t4, &y3) + fe_mul(&t2, &t0, &y3) + fe_mul(&y3, &x3, &z3) + + // Y3 := Y3 + t2 ; X3 := t3 * X3 ; X3 := X3 − t1 ; + fe_add(&y3, &y3, &t2) + fe_mul(&x3, &t3, &x3) + fe_sub(&x3, &x3, &t1) + + // Z3 := t4 * Z3 ; t1 := t3 * t0 ; Z3 := Z3 + t1 ; + fe_mul(&z3, &t4, &z3) + fe_mul(&t1, &t3, &t0) + fe_add(&z3, &z3, &t1) + + // return X3 , Y3 , Z3 ; + fe_set(&p.x, &x3) + fe_set(&p.y, &y3) + fe_set(&p.z, &z3) +} + +pt_double :: proc "contextless" (p, a: ^$T) { + // Algorithm 6 from "Complete addition formulas for prime + // order elliptic curves" by Renes, Costello, and Batina. + // + // The formula is complete in that it is valid for all a, + // without exceptions or extra assumptions about the inputs. + // + // The operation costs are `8M + 3S + 2mb + 21a`. + + when T == Point_p256r1 { + t0, t1, t2, t3, b_fe: Field_Element_p256r1 + x3, y3, z3: Field_Element_p256r1 + defer fe_clear_vec([]^Field_Element_p256r1{&t0, &t1, &t2, &t3, &x3, &y3, &z3}) + } else when T == Point_p384r1 { + t0, t1, t2, t3, b_fe: Field_Element_p384r1 + x3, y3, z3: Field_Element_p384r1 + defer fe_clear_vec([]^Field_Element_p384r1{&t0, &t1, &t2, &t3, &x3, &y3, &z3}) + } else { + #panic("weierstrass: invalid curve") + } + + x, y, z := &a.x, &a.y, &a.z + + fe_b(&b_fe) + + // t0 := X ^2; t1 := Y ^2; t2 := Z ^2; + fe_square(&t0, x) + fe_square(&t1, y) + fe_square(&t2, z) + + // t3 := X * Y ; t3 := t3 + t3 ; Z3 := X * Z ; + fe_mul(&t3, x, y) + fe_add(&t3, &t3, &t3) + fe_mul(&z3, x, z) + + // Z3 := Z3 + Z3 ; Y3 := b * t2 ; Y3 := Y3 - Z3 ; + fe_add(&z3, &z3, &z3) + fe_mul(&y3, &b_fe, &t2) + fe_sub(&y3, &y3, &z3) + + // X3 := Y3 + Y3 ; Y3 := X3 + Y3 ; X3 := t1 - Y3 ; + fe_add(&x3, &y3, &y3) + fe_add(&y3, &x3, &y3) + fe_sub(&x3, &t1, &y3) + + // Y3 := t1 + Y3 ; Y3 := X3 * Y3 ; X3 := X3 * t3 ; + fe_add(&y3, &t1, &y3) + fe_mul(&y3, &x3, &y3) + fe_mul(&x3, &x3, &t3) + + // t3 := t2 + t2 ; t2 := t2 + t3 ; Z3 := b * Z3 ; + fe_add(&t3, &t2, &t2) + fe_add(&t2, &t2, &t3) + fe_mul(&z3, &b_fe, &z3) + + // Z3 := Z3 - t2 ; Z3 := Z3 - t0 ; t3 := Z3 + Z3 ; + fe_sub(&z3, &z3, &t2) + fe_sub(&z3, &z3, &t0) + fe_add(&t3, &z3, &z3) + + // Z3 := Z3 + t3 ; t3 := t0 + t0 ; t0 := t3 + t0 ; + fe_add(&z3, &z3, &t3) + fe_add(&t3, &t0, &t0) + fe_add(&t0, &t3, &t0) + + // t0 := t0 - t2 ; t0 := t0 * Z3 ; Y3 := Y3 + t0 ; + fe_sub(&t0, &t0, &t2) + fe_mul(&t0, &t0, &z3) + fe_add(&y3, &y3, &t0) + + // t0 := Y * Z ; t0 := t0 + t0 ; Z3 := t0 * Z3 ; + fe_mul(&t0, y, z) + fe_add(&t0, &t0, &t0) + fe_mul(&z3, &t0, &z3) + + // X3 := X3 - Z3 ; Z3 := t0 * t1 ; Z3 := Z3 + Z3 ; + fe_sub(&x3, &x3, &z3) + fe_mul(&z3, &t0, &t1) + fe_add(&z3, &z3, &z3) + + // Z3 := Z3 + Z3 ; + fe_add(&z3, &z3, &z3) + + // return X3 , Y3 , Z3 ; + fe_set(&p.x, &x3) + fe_set(&p.y, &y3) + fe_set(&p.z, &z3) +} + +pt_sub :: proc "contextless" (p, a, b: ^$T) { + b_neg: T + pt_negate(&b_neg, b) + pt_add(p, a, &b_neg) + + fe_clear(&b_neg) +} + +pt_negate :: proc "contextless" (p, a: ^$T) { + fe_set(&p.x, &a.x) + fe_negate(&p.y, &a.y) + fe_set(&p.z, &a.z) +} + +pt_rescale :: proc "contextless" (p, a: ^$T) { + // A = 1/Z1 + // X3 = A*X1 + // Y3 = A*Y1 + // Z3 = 1 + // + // As per "From A to Z: Projective coordinates leakage in the wild" + // leaking the Z-coordinate is bad. The modular inversion algorithm + // used in this library is based on Fermat's Little Theorem. + // + // See: https://eprint.iacr.org/2020/432.pdf + + was_identity := pt_is_identity(a) + + when T == Point_p256r1 { + z_inv: Field_Element_p256r1 + } else when T == Point_p384r1 { + z_inv: Field_Element_p384r1 + } else { + #panic("weierstrass: invalid curve") + } + + ident: T + fe_inv(&z_inv, &a.z) + fe_mul(&p.x, &a.x, &z_inv) + fe_mul(&p.y, &a.y, &z_inv) + fe_one(&p.z) + + pt_identity(&ident) + pt_cond_select(p, p, &ident, was_identity) + + fe_clear(&z_inv) +} + +pt_cond_select :: proc "contextless" (p, a, b: ^$T, ctrl: int) { + fe_cond_select(&p.x, &a.x, &b.x, ctrl) + fe_cond_select(&p.y, &a.y, &b.y, ctrl) + fe_cond_select(&p.z, &a.z, &b.z, ctrl) +} + +@(require_results) +pt_equal :: proc "contextless" (a, b: ^$T) -> int { + when T == Point_p256r1 { + x1z2, x2z1, y1z2, y2z1: Field_Element_p256r1 + } else when T == Point_p384r1 { + x1z2, x2z1, y1z2, y2z1: Field_Element_p384r1 + } else { + #panic("weierstrass: invalid curve") + } + + // Check X1Z2 == X2Z1 && Y1Z2 == Y2Z1 + fe_mul(&x1z2, &a.x, &b.z) + fe_mul(&x2z1, &b.x, &a.z) + + fe_mul(&y1z2, &a.y, &b.z) + fe_mul(&y2z1, &b.y, &a.z) + + return fe_equal(&x1z2, &x2z1) & fe_equal(&y1z2, &y2z1) +} + +@(require_results) +pt_is_identity :: proc "contextless" (p: ^$T) -> int { + return fe_is_zero(&p.z) +} + +@(require_results) +pt_is_y_odd :: proc "contextless" (p: ^$T) -> int { + tmp: T + defer pt_clear(&tmp) + + fe_set(&tmp, p) + pt_rescale(&tmp) + + return fe_is_odd(&tmp.y) +} + +@(private) +is_on_curve :: proc "contextless" (x, y: ^$T) -> bool { + maybe_yy, yy: T + defer fe_clear_vec([]^T{&maybe_yy, &yy}) + + // RHS: x^3 + ax + b + set_yy_candidate(&maybe_yy, x) + + // LHS: y^2 + fe_square(&yy, y) + + return fe_equal(&maybe_yy, &yy) == 1 +} + +@(private) +set_yy_candidate :: proc "contextless" (maybe_yy, x: ^$T) { + // RHS: x^3 + ax + b + rhs, tmp: T + + fe_square(&tmp, x) + fe_mul(&rhs, &tmp, x) + + fe_a(&tmp) + fe_mul(&tmp, &tmp, x) + fe_add(&rhs, &rhs, &tmp) + + fe_b(&tmp) + fe_add(maybe_yy, &rhs, &tmp) + + fe_clear(&rhs) +} diff --git a/core/crypto/_weierstrass/point_s11n_sec.odin b/core/crypto/_weierstrass/point_s11n_sec.odin new file mode 100644 index 000000000..56d017e5e --- /dev/null +++ b/core/crypto/_weierstrass/point_s11n_sec.odin @@ -0,0 +1,99 @@ +package _weierstrass + +@(require) import "core:crypto" + +@(private) +SEC_PREFIX_IDENTITY :: 0x00 +@(private) +SEC_PREFIX_COMPRESSED_EVEN :: 0x02 +@(private) +SEC_PREFIX_COMPRESSED_ODD :: 0x03 +SEC_PREFIX_UNCOMPRESSED :: 0x04 + +@(require_results) +pt_set_sec_bytes :: proc "contextless" (p: ^$T, b: []byte) -> bool { + when T == Point_p256r1 { + FE_SZ :: FE_SIZE_P256R1 + } else when T == Point_p384r1 { + FE_SZ :: FE_SIZE_P384R1 + } else { + #panic("weierstrass: invalid curve") + } + + b_len := len(b) + if b_len < 1 { + return false + } + + switch b[0] { + case SEC_PREFIX_IDENTITY: + if b_len != 1 { + return false + } + pt_identity(p) + return true + case SEC_PREFIX_COMPRESSED_EVEN, SEC_PREFIX_COMPRESSED_ODD: + if b_len != 1 + FE_SZ { + return false + } + y_is_odd := b[0] - SEC_PREFIX_COMPRESSED_EVEN + return pt_set_x_bytes(p, b[1:], int(y_is_odd)) + case SEC_PREFIX_UNCOMPRESSED: + if b_len != 1 + 2 * FE_SZ { + return false + } + x, y := b[1:1+FE_SZ], b[1+FE_SZ:] + return pt_set_xy_bytes(p, x, y) + case: + return false + } +} + +@(require_results) +pt_sec_bytes :: proc "contextless" (b: []byte, p: ^$T, compressed: bool) -> bool { + when T == Point_p256r1 { + FE_SZ :: FE_SIZE_P256R1 + } else when T == Point_p384r1 { + FE_SZ :: FE_SIZE_P384R1 + } else { + #panic("weierstrass: invalid curve") + } + + b_len := len(b) + if pt_is_identity(p) == 1 { + if b_len != 1 { + return false + } + b[0] = SEC_PREFIX_IDENTITY + return true + } + + x, y: []byte + y_: [FE_SZ]byte + switch compressed { + case true: + if b_len != 1 + FE_SZ { + return false + } + x, y = b[1:], y_[:] + case false: + if b_len != 1 + 2 * FE_SZ { + return false + } + b[0]= SEC_PREFIX_UNCOMPRESSED + x, y = b[1:1+FE_SZ], b[1+FE_SZ:] + } + if !pt_bytes(x, y, p) { + return false + } + if compressed { + // Instead of calling pt_is_y_odd, just serializing + // y into a temp buffer and checking the parity saves + // 1 redundant rescale call. + y_is_odd := byte(y[FE_SZ-1] & 1) + b[0] = SEC_PREFIX_COMPRESSED_EVEN + y_is_odd + crypto.zero_explicit(&y_, size_of(y_)) + } + + return true +} diff --git a/core/crypto/_weierstrass/sc.odin b/core/crypto/_weierstrass/sc.odin new file mode 100644 index 000000000..1ecfea6f9 --- /dev/null +++ b/core/crypto/_weierstrass/sc.odin @@ -0,0 +1,142 @@ +package _weierstrass + +@(require) import "core:crypto" +import p256r1 "core:crypto/_fiat/field_scalarp256r1" +import p384r1 "core:crypto/_fiat/field_scalarp384r1" +import subtle "core:crypto/_subtle" + +Scalar_p256r1 :: p256r1.Montgomery_Domain_Field_Element +Scalar_p384r1 :: p384r1.Montgomery_Domain_Field_Element + +SC_SIZE_P256R1 :: 32 +SC_SIZE_P384R1 :: 48 +SC_SIZE_MAX :: SC_SIZE_P384R1 + +sc_size :: proc "contextless" (sc: ^$T) -> int where T == Scalar_p256r1 || T == Scalar_p384r1 { + when T == Scalar_p256r1 { + return SC_SIZE_P256R1 + } else when T == Scalar_p384r1 { + return SC_SIZE_P384R1 + } +} + +sc_set_random :: proc(sc: ^$T) where T == Scalar_p256r1 || T == Scalar_p384r1 { + ensure(crypto.HAS_RAND_BYTES, "weierstrass: entropy source required") + + b: [48]byte = --- + defer crypto.zero_explicit(&b, size_of(b)) + + when T == Scalar_p256r1 { + // 384-bits reduced makes the modulo bias insignificant + for { + crypto.rand_bytes(b[:]) + _ = sc_set_bytes(sc, b[:]) + if sc_is_zero(sc) == 0 { // Likely + break + } + } + } else when T == Scalar_p384r1 { + for { + crypto.rand_bytes(b[:]) + did_reduce := sc_set_bytes(sc, b[:]) + if !did_reduce && sc_is_zero(sc) == 0 { // Likely + break + } + } + } +} + +sc_clear :: proc { + p256r1.fe_clear, + p384r1.fe_clear, +} + +sc_clear_vec :: proc { + p256r1.fe_clear_vec, + p384r1.fe_clear_vec, +} + +sc_set_bytes :: proc { + p256r1.fe_from_bytes, + p384r1.fe_from_bytes, +} + +sc_bytes :: proc { + p256r1.fe_to_bytes, + p384r1.fe_to_bytes, +} + +sc_set :: proc { + p256r1.fe_set, + p384r1.fe_set, +} + +sc_zero :: proc { + p256r1.fe_zero, + p384r1.fe_zero, +} + +sc_one :: proc { + p256r1.fe_one, + p384r1.fe_one, +} + +sc_add :: proc { + p256r1.fe_add, + p384r1.fe_add, +} + +sc_sub :: proc { + p256r1.fe_sub, + p384r1.fe_sub, +} + +sc_negate :: proc { + p256r1.fe_opp, + p384r1.fe_opp, +} + +sc_mul :: proc { + p256r1.fe_mul, + p384r1.fe_mul, +} + +sc_square :: proc { + p256r1.fe_square, + p384r1.fe_square, +} + +sc_inv :: proc { + p256r1.fe_inv, + p384r1.fe_inv, +} + +sc_cond_assign :: proc { + p256r1.fe_cond_assign, + p384r1.fe_cond_assign, +} + +sc_equal :: proc { + p256r1.fe_equal, + p384r1.fe_equal, +} + +sc_is_odd :: proc { + p256r1.fe_is_odd, + p384r1.fe_is_odd, +} + +sc_is_zero :: proc { + sc_is_zero_p256r1, + sc_is_zero_p384r1, +} + +@(require_results) +sc_is_zero_p256r1 :: proc "contextless" (fe: ^Scalar_p256r1) -> int { + return int(subtle.u64_is_zero(p256r1.fe_non_zero(fe))) +} + +@(require_results) +sc_is_zero_p384r1 :: proc "contextless" (fe: ^Scalar_p384r1) -> int { + return int(subtle.u64_is_zero(p384r1.fe_non_zero(fe))) +} diff --git a/core/crypto/_weierstrass/scalar_mul.odin b/core/crypto/_weierstrass/scalar_mul.odin new file mode 100644 index 000000000..eb3fa1459 --- /dev/null +++ b/core/crypto/_weierstrass/scalar_mul.odin @@ -0,0 +1,299 @@ +package _weierstrass + +import "core:crypto" +@(require) import subtle "core:crypto/_subtle" + +pt_scalar_mul :: proc "contextless" ( + p, a: ^$T, + sc: ^$S, + unsafe_is_vartime: bool = false, +) { + when T == Point_p256r1 && S == Scalar_p256r1 { + SC_SZ :: SC_SIZE_P256R1 + } else when T == Point_p384r1 && S == Scalar_p384r1 { + SC_SZ :: SC_SIZE_P384R1 + } else { + #panic("weierstrass: invalid curve") + } + + b: [SC_SZ]byte = --- + sc_bytes(b[:], sc) + + pt_scalar_mul_bytes(p, a, b[:], unsafe_is_vartime) + + if !unsafe_is_vartime { + crypto.zero_explicit(&b, size_of(b)) + } +} + +pt_scalar_mul_bytes :: proc "contextless" ( + p, a: ^$T, + sc: []byte, + unsafe_is_vartime: bool = false, +) { + when T == Point_p256r1 { + p_tbl: Multiply_Table_p256r1 = --- + q, tmp: Point_p256r1 = ---, --- + SC_SZ :: SC_SIZE_P256R1 + } else when T == Point_p384r1 { + p_tbl: Multiply_Table_p384r1 = --- + q, tmp: Point_p384r1 = ---, --- + SC_SZ :: SC_SIZE_P384R1 + } else { + #panic("weierstrass: invalid curve") + } + + assert_contextless(len(sc) == SC_SZ, "weierstrass: invalid scalar size") + mul_tbl_set(&p_tbl, a, unsafe_is_vartime) + + pt_identity(&q) + for limb_byte, i in sc { + hi, lo := (limb_byte >> 4) & 0x0f, limb_byte & 0x0f + + if i != 0 { + pt_double(&q, &q) + pt_double(&q, &q) + pt_double(&q, &q) + pt_double(&q, &q) + } + mul_tbl_lookup_add(&q, &tmp, &p_tbl, u64(hi), unsafe_is_vartime) + + pt_double(&q, &q) + pt_double(&q, &q) + pt_double(&q, &q) + pt_double(&q, &q) + mul_tbl_lookup_add(&q, &tmp, &p_tbl, u64(lo), unsafe_is_vartime) + } + + pt_set(p, &q) + + if !unsafe_is_vartime { + crypto.zero_explicit(&p_tbl, size_of(p_tbl)) + pt_clear_vec([]^T{&q, &tmp}) + } +} + +pt_double_scalar_mul_generator_vartime :: proc "contextless" ( + p, q: ^$T, + sc_g, sc_q: ^$Q, +) { + // Strauss-Shamir, commonly referred to as the "Shamir trick", + // saves half the doublings, relative to doing this the naive way. + // + // Note: In the unlikely event where we support curves with an + // efficent endomorphism (secp256k1), scalarmul + GLV is faster. + when T == Point_p256r1 && Q == Scalar_p256r1 { + q_tbl: Multiply_Table_p256r1 = --- + SC_SZ :: SC_SIZE_P256R1 + } else when T == Point_p384r1 && Q == Scalar_p384r1 { + q_tbl: Multiply_Table_p384r1 = --- + SC_SZ :: SC_SIZE_P384R1 + } else { + #panic("weierstrass: invalid curve") + } + + sc_q_bytes, sc_g_bytes: [SC_SZ]byte = ---, --- + sc_bytes(sc_q_bytes[:], sc_q) + sc_bytes(sc_g_bytes[:], sc_g) + + r, tmp: T = ---, --- + when crypto.COMPACT_IMPLS == true { + pt_generator(&r) + when T == Point_p256r1 { + g_tbl: Multiply_Table_p256r1 = --- + } else when T == Point_p384r1 { + g_tbl: Multiply_Table_p384r1 = --- + } + mul_tbl_set(&g_tbl, &r, true) + } else { + when T == Point_p256r1 { + g_tbl := &Gen_Multiply_Table_p256r1_lo[31] + } else when T == Point_p384r1 { + g_tbl := &Gen_Multiply_Table_p384r1_lo[47] + } + } + mul_tbl_set(&q_tbl, q, true) + + pt_identity(&r) + for i in 0..> 4) & 0x0f, limb_byte_q & 0x0f + hi_g, lo_g := (limb_byte_g >> 4) & 0x0f, limb_byte_g & 0x0f + + if i != 0 { + pt_double(&r, &r) + pt_double(&r, &r) + pt_double(&r, &r) + pt_double(&r, &r) + } + mul_tbl_lookup_add(&r, &tmp, &q_tbl, u64(hi_q), true) + when crypto.COMPACT_IMPLS == true { + mul_tbl_lookup_add(&r, &tmp, &g_tbl, u64(hi_g), true) + } else { + mul_affine_tbl_lookup_add(&r, &tmp, g_tbl, u64(hi_g), true) + } + + pt_double(&r, &r) + pt_double(&r, &r) + pt_double(&r, &r) + pt_double(&r, &r) + mul_tbl_lookup_add(&r, &tmp, &q_tbl, u64(lo_q), true) + when crypto.COMPACT_IMPLS == true { + mul_tbl_lookup_add(&r, &tmp, &g_tbl, u64(lo_g), true) + } else { + mul_affine_tbl_lookup_add(&r, &tmp, g_tbl, u64(lo_g), true) + } + } + + pt_set(p, &r) +} + +when crypto.COMPACT_IMPLS == true { + pt_scalar_mul_generator :: proc "contextless" ( + p: ^$T, + sc: ^$S, + unsafe_is_vartime: bool = false, + ) { + g: T + pt_generator(&g) + + pt_scalar_mul(p, &g, sc, unsafe_is_vartime) + } +} else { + pt_scalar_mul_generator :: proc "contextless" ( + p: ^$T, + sc: ^$S, + unsafe_is_vartime: bool = false, + ) { + when T == Point_p256r1 && S == Scalar_p256r1 { + p_tbl_hi := &Gen_Multiply_Table_p256r1_hi + p_tbl_lo := &Gen_Multiply_Table_p256r1_lo + tmp: Point_p256r1 = --- + SC_SZ :: SC_SIZE_P256R1 + } else when T == Point_p384r1 && S == Scalar_p384r1 { + p_tbl_hi := &Gen_Multiply_Table_p384r1_hi + p_tbl_lo := &Gen_Multiply_Table_p384r1_lo + tmp: Point_p384r1 = --- + SC_SZ :: SC_SIZE_P384R1 + } else { + #panic("weierstrass: invalid curve") + } + + b: [SC_SZ]byte + sc_bytes(b[:], sc) + + pt_identity(p) + for limb_byte, i in b { + hi, lo := (limb_byte >> 4) & 0x0f, limb_byte & 0x0f + mul_affine_tbl_lookup_add(p, &tmp, &p_tbl_hi[i], u64(hi), unsafe_is_vartime) + mul_affine_tbl_lookup_add(p, &tmp, &p_tbl_lo[i], u64(lo), unsafe_is_vartime) + } + + if !unsafe_is_vartime { + crypto.zero_explicit(&b, size_of(b)) + pt_clear(&tmp) + } + } +} + +@(private="file") +Multiply_Table_p256r1 :: [15]Point_p256r1 +@(private="file") +Multiply_Table_p384r1 :: [15]Point_p384r1 + +@(private="file") +mul_tbl_set :: proc "contextless"( + tbl: ^$T, + point: ^$U, + unsafe_is_vartime: bool, +) { + when T == Multiply_Table_p256r1 && U == Point_p256r1{ + tmp: Point_p256r1 + } else when T == Multiply_Table_p384r1 && U == Point_p384r1{ + tmp: Point_p384r1 + } else { + #panic("weierstrass: invalid curve") + } + + pt_set(&tmp, point) + pt_set(&tbl[0], &tmp) + for i in 1 ..<15 { + pt_add(&tmp, &tmp, point) + pt_set(&tbl[i], &tmp) + } + + if !unsafe_is_vartime { + pt_clear(&tmp) + } +} + +@(private="file") +mul_tbl_lookup_add :: proc "contextless" ( + point, tmp: ^$T, + tbl: ^$U, + idx: u64, + unsafe_is_vartime: bool, + ) { + if unsafe_is_vartime { + switch idx { + case 0: + case: + pt_add(point, point, &tbl[idx - 1]) + } + return + } + + pt_identity(tmp) + for i in u64(1)..<16 { + ctrl := subtle.eq(i, idx) + pt_cond_select(tmp, tmp, &tbl[i - 1], int(ctrl)) + } + + pt_add(point, point, tmp) +} + +when crypto.COMPACT_IMPLS == false { + @(private) + Affine_Point_p256r1 :: struct { + x: Field_Element_p256r1, + y: Field_Element_p256r1, + } + + @(private) + Affine_Point_p384r1 :: struct { + x: Field_Element_p384r1, + y: Field_Element_p384r1, + } + + @(private="file") + mul_affine_tbl_lookup_add :: proc "contextless" ( + point, tmp: ^$T, + tbl: ^$U, + idx: u64, + unsafe_is_vartime: bool, + ) { + if unsafe_is_vartime { + switch idx { + case 0: + case: + pt_add_mixed(point, point, &tbl[idx - 1].x, &tbl[idx - 1].y) + } + return + } + + pt_identity(tmp) + for i in u64(1)..<16 { + ctrl := int(subtle.eq(i, idx)) + fe_cond_select(&tmp.x, &tmp.x, &tbl[i - 1].x, ctrl) + fe_cond_select(&tmp.y, &tmp.y, &tbl[i - 1].y, ctrl) + } + + // The mixed addition formula assumes that the addend is not + // the neutral element. Do the addition regardless, and then + // conditionally select the right result. + pt_add_mixed(tmp, point, &tmp.x, &tmp.y) + + ctrl := subtle.u64_is_non_zero(idx) + pt_cond_select(point, point, tmp, int(ctrl)) + } +} diff --git a/core/crypto/_weierstrass/secp256r1_table.odin b/core/crypto/_weierstrass/secp256r1_table.odin new file mode 100644 index 000000000..1a6bc3ef6 --- /dev/null +++ b/core/crypto/_weierstrass/secp256r1_table.odin @@ -0,0 +1,3985 @@ +package _weierstrass + +/* + ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ +*/ + +import "core:crypto" + +when crypto.COMPACT_IMPLS == false { + @(private,rodata) + Gen_Multiply_Table_p256r1_hi := [32][15]Affine_Point_p256r1 { + { + { + {9259451175701532574, 15597985540941612547, 4541553034987877619, 8927802479718285609}, + {14672230714928802576, 14284617950605306700, 13339970812390782046, 787078889494395850}, + }, + { + {18165439414433063919, 14693282888419586094, 14992616289789993230, 13232208150801553912}, + {16850347485914337693, 223364064845089224, 7302899015436300563, 4391216311540396088}, + }, + { + {12558388403188680537, 10687978569513354810, 9373570856564649772, 4079327722512691465}, + {5372437374337150740, 3297421622932790851, 9326853593823854687, 8305371884938201251}, + }, + { + {13121472331750731303, 323745485980480220, 15110308702528119977, 4696302365805118372}, + {9859094500834571602, 5315656270700787939, 4187063204400651801, 1695695129564818327}, + }, + { + {12817586844019849804, 15425488216915741929, 15293562913126043054, 11770898970765978555}, + {6806103820345670787, 17789094149138630459, 3807781571713999192, 5823254011289457198}, + }, + { + {10112524230916015604, 13571143908656270599, 6031089010487808103, 5774558171390644848}, + {1808959243244841573, 14071312530426692155, 9241399242704553402, 9836150050655369231}, + }, + { + {14083007972403535491, 16009534514129505275, 12481249112231139039, 10309390659262581143}, + {5782517315325366794, 16717384553294759530, 4578392002424884134, 239005024949492645}, + }, + { + {1836857790164349346, 11263074778654917115, 4786985732596838094, 10525445084936097674}, + {1484357665966453236, 3110871407036679558, 1668700683093601768, 2736269131339849752}, + }, + { + {9249362594190920246, 8088172462140746331, 4080107866285682736, 16205599538438551353}, + {18312943145606312277, 9100632964181080418, 3969991115337154345, 5340098959750368315}, + }, + { + {12122448407048035645, 2891250339380982359, 12794212052932523400, 7166035112141500392}, + {15777441312724841162, 4552528682229856831, 2210391301762911476, 16410254680957321386}, + }, + { + {6910044784455706429, 11951245774670922855, 207795885948948810, 3884359690300962405}, + {4578772752480772344, 2948797025787714138, 16774444535658202808, 1388183483009000463}, + }, + { + {16561979129019905420, 1881862411760441386, 15441950514711322010, 12933020223458438856}, + {5570341451312029630, 18172638959728259059, 9074261777549091198, 6171200053222754816}, + }, + { + {10126435102176037237, 1545112930055760251, 11563139991870561593, 10766754172364938834}, + {5116781688621052838, 14471715119500781375, 4724882615229687192, 10031687030722046325}, + }, + { + {15016829467434780812, 6777508689306592732, 3811682306063049290, 11475361222871876387}, + {6080948654298953274, 11612742274762615033, 5268311600240325047, 9147351973710519861}, + }, + { + {12130203770930472759, 3880998309361490881, 8807462332494735511, 9291388074337055133}, + {18165312304248982432, 12733144434841535979, 18090195697688236271, 5825342884125782172}, + }, + }, + { + { + {194633990068625151, 1028128699653523895, 7436102537486268753, 1855520454959348468}, + {5098690958966904466, 3342676718901330604, 6942212660412942406, 16510188838209674083}, + }, + { + {7963995066277321795, 14986230345162551366, 10616366460602472778, 16186943329215681149}, + {9522855644164647723, 9858336437877021178, 16344942402271072884, 18027353494090590022}, + }, + { + {13392726161043192788, 7606793939450765773, 9543984695709321129, 6135912406103198328}, + {10903991926178685177, 529801710637680784, 8207012095420105234, 4590962949922268360}, + }, + { + {13175608910844763921, 11168387468381338510, 5555873864224342205, 17780559602571640345}, + {1582669533588472814, 8145133762789622706, 1625372887980692455, 4576809104068554285}, + }, + { + {17616803153811079355, 17809794753465712025, 10788493879428408032, 1263026253532745742}, + {331896291298606534, 13299145463579793142, 8951131463540898010, 11121758705853021600}, + }, + { + {17015522374255846157, 7155392284047197223, 1248775493117789546, 9199472299655737207}, + {13126885324657282947, 12092989376083683289, 2035698983314262432, 835441512024005104}, + }, + { + {12481871371020004325, 15786477648044981224, 2586272424816191689, 4208704695692543659}, + {16940467964964992440, 11207566805119564978, 2858987625603639630, 9561510646236248154}, + }, + { + {2900978533555060931, 1749946807863203576, 11705734511931072459, 4446980691693419424}, + {14437524160594907241, 12795912566640000773, 10400036254697939154, 8356113088668925361}, + }, + { + {3770654812111500682, 7723332701546321657, 12057007323752084660, 11871339027463593983}, + {8927366002257844381, 331175455338905356, 6085376066711046662, 195998713859126244}, + }, + { + {15888580251537997623, 14253909833728698978, 14445538492667230716, 4028538972354525849}, + {7720263170150940477, 1190890222876864097, 8657188516818851005, 1987613286973742753}, + }, + { + {1556082539082087499, 9191446579576007527, 16923484407567577707, 4662661048159090855}, + {12760778972220173745, 3942937056545553996, 12952479961991875179, 8914103212381870290}, + }, + { + {8900726473285671992, 890209742292473781, 16059468388719373167, 16577940938542233221}, + {17381766864962227733, 231915274132518769, 16477817024012878700, 15646021286310268545}, + }, + { + {10104554368814337641, 170400126349943750, 16051269335758964391, 7842493858299913771}, + {9246756702190574744, 110682656515867335, 11402798562961521905, 17325237240525801251}, + }, + { + {15837018286366797690, 18114413810565810328, 9441874034567150801, 14075941137889189393}, + {12786763055047269260, 9121030808281463204, 1713778999270814105, 17015261864438490667}, + }, + { + {12997570542605430113, 5500897611058123544, 4160129407772614089, 13768264346635084004}, + {6638654171187871203, 6080635069726153281, 2255431148803290413, 3789670411999607189}, + }, + }, + { + { + {1830819081327272165, 11951292080860646547, 18002500803418629938, 13317986695217403840}, + {5005574200470766330, 10138179785738652504, 1610518863105278224, 13309443265578956954}, + }, + { + {14192194428653714479, 11578618567931657764, 6032668189933768881, 15981535562386193924}, + {8925792218631314923, 9408714146004183681, 8859017894477140398, 1675606340537058506}, + }, + { + {3265119697568866078, 13753322853248061974, 15435163376825672274, 13646180516491714938}, + {15620545622955090250, 18241486585498394565, 459566729126467878, 9728217493753855944}, + }, + { + {9883406233903270985, 17184231210468300584, 5498903678702785900, 6903833261382863389}, + {11489138095102981636, 9021901931786177471, 3227433089132150317, 16639455550797627042}, + }, + { + {839045372102318861, 2032615141683118500, 1921816835840256924, 504869150737570005}, + {15932184001422473505, 7849475855313305697, 1189994394722618598, 9874798350548229684}, + }, + { + {4636201671610663345, 16662311204732135584, 12398897461787695675, 1355753199357412657}, + {14695655628527768564, 1692838776852698754, 7346906782826540912, 14869028424564984700}, + }, + { + {14240080119980315297, 4751983902385717684, 7941412103662252178, 4796803816695225123}, + {9327986654018000413, 15111345676387005726, 3582558555283734415, 11913156735178831102}, + }, + { + {12915868875134296756, 3071143582305760275, 10848717856747030010, 10973183887638314967}, + {5983269487036236823, 9885184706933333413, 14509493669845681951, 9669608065801379977}, + }, + { + {7848634325810890057, 4356492357483949442, 8777700982672429871, 447737364627887590}, + {2892466086138453900, 12013259293340538023, 3423275627272380730, 11171074631447548946}, + }, + { + {14593553227914306527, 7393098159726367793, 959457858782426605, 12924066827318848802}, + {14790800265003508462, 13805969419986022239, 4408523909823076864, 16722715416825698787}, + }, + { + {8554182115079118694, 17233907570567075631, 12336560627384786590, 5123566378696582545}, + {96401035522143140, 10138155491929979850, 17651328686428132420, 3453390145222258032}, + }, + { + {16197242500758474188, 3349369240724295499, 9422940308750670637, 16888844525585804807}, + {14045424784406071799, 13180603138700207746, 2683581192503868543, 3842875784859878}, + }, + { + {17498073686183419231, 6922314891526280784, 16083733402282932920, 15425477806093217459}, + {12425976625898608391, 16458101989314253841, 10013521940061058050, 10858868879196007236}, + }, + { + {123600201037598181, 6690762836954208162, 17157040810691942664, 15263405971805161132}, + {8685477170453562173, 10331174323986544033, 5789045082422148337, 3007978469441468974}, + }, + { + {2402095889286816125, 18054120920831753009, 11753130221915918396, 10341553510464463050}, + {280903370426929900, 14994955837151914025, 13551362401871479612, 14711789630561753093}, + }, + }, + { + { + {14086745261650819748, 17953107869776717888, 1777725846494438428, 2765314406831814212}, + {2603997194371852991, 2223517025105045134, 15579901335531749634, 6571733615332171148}, + }, + { + {5478465698516556930, 287443454357750768, 12201204663663129285, 782849770204658255}, + {11270045035009204251, 18152683972363144337, 10463300037926642739, 14363641589598863851}, + }, + { + {3790592075869665284, 5120320091554329756, 15361581282394028709, 14360464660911164915}, + {15249656958991931940, 2563751872827049233, 13745792006936646733, 14572943674933168173}, + }, + { + {3167679014977537749, 3417445004776702290, 1709246158507866266, 5861367897285174360}, + {8437429877561342262, 17231607446243478748, 16047596399306766948, 17656438585829685897}, + }, + { + {12977336347094692192, 13723871955002954132, 17399919575273038847, 16163973860244779675}, + {14997921584659740746, 6543247361992425067, 4675926398794487109, 17580512382853194054}, + }, + { + {10778828023580771765, 9812611440536367405, 14168149065325522570, 6692229110872358750}, + {11010962724400581057, 13055203605065073902, 11396463140731730116, 16969789651736772232}, + }, + { + {3285258013801327520, 14114268241282882888, 5367399533198476395, 17277410244918727028}, + {2751895479568588421, 751309667192066167, 13038472116718581917, 16013586354334596135}, + }, + { + {12364168614988940500, 13194367252463423118, 12223406606527741280, 5014139294736037086}, + {11244699482831816093, 5336498572491451990, 14268404582568856142, 14502318820969599316}, + }, + { + {13295673091232554814, 313981772853781347, 11829785736449464030, 13341198421333360997}, + {16787450350663111566, 6525407229623764159, 2012189087039636323, 2110887590404698758}, + }, + { + {16984895766311549717, 1057465499230843916, 13565444352859773343, 1019268943988786852}, + {2190009140530404855, 10045598732295352970, 4789803496780829836, 10700158388954091321}, + }, + { + {14840255112988420500, 10066628133368048408, 6527354835873855384, 16106607076894419125}, + {3989024604987083046, 10713316697020150694, 16811389107269552264, 11294596059797019619}, + }, + { + {622403023838932676, 11423409007234191765, 17086830255702454786, 1213655124481948199}, + {3976593910085142945, 6315875935390432543, 17947502153968859628, 18031540937011531543}, + }, + { + {342675887578148289, 18366454547938469828, 3853530442390999217, 7499455395579634652}, + {768597405171336502, 1636271570683567151, 16786205337983572309, 13056241332863199715}, + }, + { + {15991153618414855143, 803325462494472241, 5709347424437559249, 10138502962472290727}, + {4675124205115228106, 9599016746550345197, 2769443894695609085, 12311020551315051087}, + }, + { + {11470964304318784059, 17313372553735202469, 10686997186364536871, 9228453594798060121}, + {57933324335302024, 8931389936300346353, 17823596478938529898, 1126996688113949835}, + }, + }, + { + { + {15804957839814547154, 7924193945337173678, 1080401129055171214, 10816444561878528576}, + {13171610473229361771, 8099842733764406841, 9284741070210451667, 9245195215372025289}, + }, + { + {7185947197544988797, 13306809398790059447, 11440959253278285287, 15084384140482244570}, + {5059824327869316332, 7585354587200615362, 6801884469610571467, 6427162399794357267}, + }, + { + {1505501490785526604, 6062033360335279190, 13214531355927393851, 8869230490276248430}, + {11596558698255017116, 6698268011950867978, 15445165013361223076, 4910055064120213146}, + }, + { + {1453348772281274490, 13028088570940491471, 16100623112750251840, 5210244400259879874}, + {9443916155735416174, 16869520919318450506, 7479400208826706574, 14374970913352602458}, + }, + { + {13057495656815142976, 1743194961605203063, 15733599697884179267, 3501754291485677593}, + {7405256272105757266, 12344297842308545819, 3389605493339498760, 3092252531918600248}, + }, + { + {5038191990715247960, 2723916483244871576, 4891019526710760134, 11094632341133260369}, + {6274429941353136467, 1408871421293516065, 12455625869488488781, 3401549469990652817}, + }, + { + {4716563932720198201, 1584625214845878997, 13213357619008940082, 13122950207230795185}, + {12303370001794463898, 6725033180592084698, 12302152314224424594, 6139100303374835750}, + }, + { + {10149597276931117465, 5778043705364022356, 13888443605241209218, 6889225091714429810}, + {16209363638493043975, 8516350006446457646, 9214830076046105138, 8894115046323798175}, + }, + { + {161027176918876103, 2287100732338401479, 16561946444121779293, 9805329436091376243}, + {11473978632757961256, 1245289731366992705, 7338435771556366282, 15749864527919116005}, + }, + { + {2753237807828198865, 11508305846735597339, 9058745440380813449, 3960739040735759442}, + {17921955885187582871, 10231929062430218022, 18115018235326517243, 17854413167898372208}, + }, + { + {638684488109167329, 14596365931372343092, 1917271942976854297, 12291978018935761003}, + {5076527739384635812, 7833625460571766680, 17060902137821849350, 17134703695475138982}, + }, + { + {13026208197163596446, 1935567165776196957, 17296090833026336866, 8461284827078097590}, + {14545382879887213077, 3302103559307506085, 16026840048628844803, 4599071908983273604}, + }, + { + {9156540407095300222, 7598243263658987831, 1996711254516517688, 13013193687414837552}, + {116495354444693499, 12803585308662671588, 8278106437192580735, 3374263264867687146}, + }, + { + {4318910866113560561, 8122780372606489166, 11952351993471767425, 9581759925599323445}, + {12268585667545114307, 7286163136539353394, 12697490728074784421, 7270019569202782882}, + }, + { + {16247467139569457576, 14043942371464607677, 6338399572126720647, 9528527345786650933}, + {16344656963096275115, 13804658662065732334, 2991248997774547140, 12174436388699549119}, + }, + }, + { + { + {1169887957113173798, 4936710663791789838, 8029349457377894665, 3317691225106441967}, + {3622769674498678594, 1954144360900150482, 1432045977341997899, 934737636789214593}, + }, + { + {9646181593082190523, 16068017411165381498, 13319927590045936565, 6113055520205251774}, + {5576373032696512038, 13880344501714804196, 12022206929479211261, 7387979357081975315}, + }, + { + {13553890993911526641, 1237937561304731611, 11053651340854998814, 8737874920379363783}, + {15414508226001886918, 9311523317130687807, 12080742822716708234, 4715194040021784977}, + }, + { + {17182132836049601530, 1486820395924546410, 14089047182364760490, 5375431386740917568}, + {2352352269256972682, 6220398075470064021, 11444733678216077372, 8173002234516562536}, + }, + { + {7896339057146013415, 17613745684396593735, 4238258305077796259, 15438639564771394288}, + {1482402451684594916, 3104492350488980260, 5195487229736262641, 1361150797580203482}, + }, + { + {15949855327936545010, 15892613064802301412, 7776232754624386979, 2193423430757249310}, + {10751855334513902678, 13772090376350944100, 5644047706587449960, 370992037484721524}, + }, + { + {16329953561108738383, 14553061366216182492, 5112198484879130320, 1893048255589705004}, + {11469678860036344015, 8992526488267920066, 18208245559304821518, 8980963391041920447}, + }, + { + {5783711159088718530, 3503029393593618754, 10736192136662142256, 15443859608128978668}, + {271805305647187927, 8244170003029416464, 17017071503038388446, 2536084345379259313}, + }, + { + {9850291665987916519, 6499970366121170030, 7001995026899086280, 9961826319039756858}, + {7497823327397141096, 6975352931548332265, 4068344268340314997, 15888973419716629698}, + }, + { + {3982898776583485812, 10403233710814076420, 8681461491810344216, 4116685619183896910}, + {18192868132325233114, 17377077437999490605, 17997716263755054576, 10376686656480866118}, + }, + { + {3479412946560984795, 5044366097675527819, 13707564929638264911, 5666779920208401261}, + {10137470376683230183, 2075467328249870088, 11457126564907274413, 13701087332649256159}, + }, + { + {12574253652565934836, 8388159655344384255, 16127953452716629313, 1877819316325313228}, + {8945746653921217760, 4616678606113198065, 1336330019150074567, 11910289150769410280}, + }, + { + {9565592090082898867, 1968790057506790036, 4797721149040405609, 13125809848505545280}, + {14122665390767023537, 17271175538744290850, 16007653062195668190, 16371835205840876479}, + }, + { + {10409691258933377688, 13736467137095186370, 2757793467881882435, 12443439690522935631}, + {17601924849565694404, 988048065500720515, 7554063443268400107, 4274248596892038508}, + }, + { + {8972162505776549196, 16209364130421564220, 13018196697272262431, 418388148277092169}, + {11645493996879973039, 5024734975063482607, 3708889997144620499, 11208942121415360714}, + }, + }, + { + { + {17596113920958619489, 11920824479658301378, 3786905428099710821, 11112764289322906111}, + {8817260450068629272, 6518847791514184438, 14593687325057339783, 18018581321332807475}, + }, + { + {2056254186648603335, 12143016575009965669, 3290271983033386616, 4338404082685850854}, + {12660444972475266123, 6345409453044955404, 13278869140778657354, 10063005167581762786}, + }, + { + {5303950317664091150, 17409642188139937758, 12135894348302287058, 16444741243419918751}, + {13935885817311324323, 8496908197501732703, 12163317723288843510, 16891353436915314685}, + }, + { + {4168420842704770545, 338440394515115377, 2102734009665481092, 9772725684473416465}, + {1247616337419130000, 4222072446972129729, 4836898447189504007, 9154346000276664999}, + }, + { + {14649401370738987318, 10044081678892811795, 1306517740393103656, 16586067283450489622}, + {8211832777731897494, 12849393859171286949, 17327526552807783018, 14171704619529498238}, + }, + { + {12849053390245557890, 12693731077061619694, 5891211584023409476, 1008960642219209210}, + {15593393872187214387, 7381248773473326001, 16559656086795428559, 2106025108820858934}, + }, + { + {4347667984894353308, 2129883711661222690, 1076488804494872856, 15059968377755299195}, + {12380937310378496242, 16425480883270944108, 4769192332535557551, 10388305045430499744}, + }, + { + {8553482596123775980, 12627020622203381515, 10774788686070344669, 6271789114731522097}, + {6270586844349642345, 5584690155569770537, 9478526526319537174, 3405597782572827563}, + }, + { + {10255408065071335198, 2384996481315588922, 10679447117297819075, 3734157461055440416}, + {1635042286365643780, 11321809677772938996, 2373960964139986040, 4869129159740273704}, + }, + { + {16681657814739017038, 2045405432090866328, 9473434018957974472, 5549808619751464269}, + {3650191693776946828, 15805634549736708741, 16764187297356548667, 6849534466635874363}, + }, + { + {15295973549776084894, 8150873746601283651, 8017271980921908229, 4899654767305073834}, + {15257501950484641691, 17365331272978440066, 14582514748324426172, 14727798284858071666}, + }, + { + {3180828552573045472, 17698570278585440462, 8986722854533057232, 4518665117523514004}, + {1718699978312382231, 16973074530347269964, 5684175730451960274, 17228649521631238473}, + }, + { + {2897180423141326703, 13691273076814343144, 2967066815351306232, 1032540647518716635}, + {16365716239989474776, 9503666134295232767, 4599017511227366879, 14475021161770955579}, + }, + { + {4512626226592149712, 13575110216387069176, 13488662643497927183, 9673147324484250604}, + {143936220816719815, 2307325398241477161, 468315224038772027, 17743582630124600591}, + }, + { + {1476494936296433813, 3408612621327299295, 11632756669813257564, 14296719897220703576}, + {2241234207239321749, 12237974399755684219, 16253635131573079566, 11892871179872526079}, + }, + }, + { + { + {9440495138081785154, 17328162383695942099, 1870751290505230781, 17987066187778049275}, + {9952223038481207705, 10126409487298126876, 1181369784146909444, 8158422380540037915}, + }, + { + {10892870009313407934, 5709686117526627488, 16343828906887149047, 16063790174205876315}, + {9076070192754075075, 4639156357669822592, 4904064385440242264, 5942264027390072320}, + }, + { + {14586043427955633062, 1886633882927769308, 12786104261802569226, 17414735423561048102}, + {3869682486341171982, 17146691898427698057, 9886217016173201579, 17515773620461053745}, + }, + { + {17271984572727555145, 2097715321690717305, 5328035183708920909, 13206781766168781008}, + {5915693606819932446, 3870849056297265622, 18070792155150730518, 7786839743829304936}, + }, + { + {14091274565690260814, 5039742420071412611, 2322945829654574283, 7678395717670225646}, + {17396071770599775867, 4747582460834310767, 13387178106758137047, 7224458787360678986}, + }, + { + {2020583809775623843, 3803516109208330416, 10492323079463714031, 18244921722581618682}, + {6400055933742731191, 18370212581946723247, 11415812944884122048, 5987324147127294665}, + }, + { + {3106709870210381627, 3437108621064387068, 3265644153772373951, 14353255805499610949}, + {11329727508866046420, 5461257448868659690, 8139681370942905079, 8439558396411914298}, + }, + { + {7939886940063870939, 3597929036186322512, 12732772396498766041, 13300425267730247515}, + {2345112231224079293, 12327614629296314761, 17106102937162407683, 1702694317559034053}, + }, + { + {4276582831142955483, 1304336253044853784, 18317056640605949326, 11200473213973297420}, + {3937030502759894542, 2315314353886242360, 2673827662906962132, 9781744582918546067}, + }, + { + {17837268310687096164, 10122495457633601623, 11985150009870152981, 11282144500794610389}, + {13999168735732598559, 9030771445951876212, 6423904381826094276, 6148980837201061250}, + }, + { + {14621142736654260750, 1806201536162806753, 12562675185535659971, 5326177198980139868}, + {8675433132905478434, 10796034085894917871, 7562073626744691385, 1491977564717017512}, + }, + { + {8821632341545057929, 16708916351043551467, 9171560460858577216, 5711973041149612575}, + {15808302665077457285, 8412173943543358851, 12602476370021215716, 4778674887660148537}, + }, + { + {7524796586818405222, 5468491023058834244, 7965536127579551161, 9575670558568595724}, + {4020611179055350793, 186082735900253826, 11198349470461895384, 2693853052562145978}, + }, + { + {7977371007734934919, 1442746893361509157, 15080044066626816201, 9179319344686817504}, + {17927184654813605164, 16541635384799094673, 1663389722548868092, 9157422724003022421}, + }, + { + {4167146676307544690, 12042136744739037957, 6606952994938338836, 7554398412699794678}, + {11844277247778765775, 8165791089025933303, 14954338535964037723, 16693854111477654477}, + }, + }, + { + { + {5841260956815214452, 9461234662498869948, 4761949640006529525, 18229823346336752572}, + {16055957459773168413, 4272222475092786627, 18249888117586812770, 4531982814021269346}, + }, + { + {7270238601276019194, 7318279377964882079, 5226788506940171017, 16838449902078450273}, + {3375184937745100689, 16320655850583231520, 2173229791272659780, 9816381971766204380}, + }, + { + {17113448198982970082, 8879656883528014268, 15215762680430094206, 15232212751792759071}, + {13699137317730183483, 11815206710130297569, 12298409691055054593, 2192455093917691024}, + }, + { + {9742819322069712752, 8779224519997661749, 2591205872359340025, 9144644967919881415}, + {10495832103710459914, 4557264342687723360, 935865282128150338, 7120324256648044882}, + }, + { + {4683169301229531061, 14940390399739549639, 13128742567354398401, 15222231511210090535}, + {7352694898928671332, 1221555526903686446, 8697118143614336514, 14515400523185205597}, + }, + { + {10239864229747754958, 12477284975467600510, 14054830413782031834, 17752968481181892755}, + {16082713391521411762, 17191329716867535304, 11245514405315337909, 15159733745232554536}, + }, + { + {15444441705629456398, 12030687282161152512, 16500102437404896225, 11467410246278043769}, + {14031300093087427598, 14458597378298191386, 9434445586505481169, 18221119130471329822}, + }, + { + {12694666558858009121, 10992313774737315187, 6046508760845509477, 16818819584649823054}, + {10464090160691032219, 1221502600750419478, 8658907655588546849, 16110628890984509877}, + }, + { + {14304143349839262251, 13048055876309896774, 8676204847923624352, 8365498293767636038}, + {13565995665971214654, 10895028049457785231, 5911971723937387023, 8436244239466286317}, + }, + { + {11501032393232899227, 3895174794911924947, 3230698222875450976, 7264134402609589101}, + {18091100044992147344, 13252184705645692134, 8424205723200969631, 5731735154358029264}, + }, + { + {12163905774765001813, 3911227235818691672, 9833792088244333742, 6413344327541478453}, + {15325942369130325853, 12629318625161567307, 8784755949357111975, 9462269284575183222}, + }, + { + {2157617452419341992, 3753997642171159286, 6553292364671628995, 4814048166016850277}, + {6152139240994642263, 14066819599579263267, 7377541740373798192, 17830582976167057789}, + }, + { + {6906089045659836134, 17967958089618664024, 13353206790928340833, 14671934547763383296}, + {12187232481950713594, 8718528695481423527, 18137604428804898613, 17758096361511845106}, + }, + { + {17646581888040948752, 8252837592394234071, 2508742924483223473, 5332070238932154531}, + {13165985796861395246, 4409584176627274781, 9230253121183107430, 8784052955551358471}, + }, + { + {5394535031187713437, 5279515585052353937, 14159976884067043134, 10130852155763718010}, + {13777927158878861230, 14015445621678244733, 3350717438960860318, 7071836838770144750}, + }, + }, + { + { + {10708602749843635238, 8046488591192123621, 11391158257016334553, 2512908912806916201}, + {14760224624269838038, 2631910198880826809, 2387247811669872033, 2048193899742148806}, + }, + { + {17392983665205025720, 12603331233691760840, 3752711326309791976, 8281544857330094164}, + {17004651346561270106, 10399322540256775923, 9721299450284863176, 3725182263994944884}, + }, + { + {13643198694788276032, 8127425924819487897, 14165945065582850538, 16520977003164405917}, + {1941948502806705647, 12390949208067741787, 17112117376594486408, 10232906951259490042}, + }, + { + {74190110112564319, 11227229657066745164, 10151080599595091944, 16591051376074591375}, + {8256332495682655293, 7127985739945537626, 5708687346183367016, 18310921046455023281}, + }, + { + {10040565835468209502, 3986586816478505371, 7957179672896506016, 13347112914739722590}, + {14099734293320932556, 13921950344400895005, 17478414833301838037, 961445463330402797}, + }, + { + {10553899634420153414, 4215979268474142438, 3643081140297634139, 11620906704125380460}, + {17733628678553828301, 137473878710304143, 6211837577294956591, 13926110616399428016}, + }, + { + {15203257341351417031, 11597829209697937782, 17317571979811895272, 15929491640570317745}, + {5731227916276913121, 17093153916149088230, 3908757069480556294, 18211818355208735794}, + }, + { + {6887629766078662088, 15330755394432598442, 14144608177273202986, 13258654996547018856}, + {8975611270007504091, 16869834856279102361, 12707970875852047823, 8520055680055874514}, + }, + { + {1643407997152867899, 5400650551136488814, 14663391437159245064, 4743209938058826866}, + {1728998201888511561, 11238331920657195520, 11617984741897247805, 13858029141809651878}, + }, + { + {14003691155137683825, 14641672309228817657, 4031783205073356111, 7414359968614421153}, + {8166814052414482491, 5209260157266028169, 17555696996149558694, 9780166780476833956}, + }, + { + {16029688335186691281, 4244772808651443261, 6450459413414527821, 695875191412722741}, + {11104054226249884864, 146461617619843327, 17480214580411209436, 11285418463967817315}, + }, + { + {4922928863857449168, 7226901725606965824, 7568276305032368752, 6253457805758596797}, + {14345040877576203078, 1718759302498746946, 3544444746772280646, 17880302727399449566}, + }, + { + {10693864548794383214, 736148233485985101, 5241869061152863453, 7166954323782542739}, + {16861482585847848251, 11483636939866570861, 5950529069765100144, 700887039653157350}, + }, + { + {3906969739692830848, 5546431121705298614, 10491799900914853406, 5871175286230239238}, + {2851574662174517162, 5511397532379144624, 17409985391224790540, 319012646822749823}, + }, + { + {15269778527761027251, 16471737837294177924, 8830398856035267114, 8206807757132984992}, + {1421214226977370752, 14233751335943482739, 9668238787333455452, 8700964319357541954}, + }, + }, + { + { + {16477698187919702699, 2757160833848759781, 5976267476122243443, 7375951277779829055}, + {6525111513935493528, 9969722922172879681, 12582700753056539952, 3861958159147836631}, + }, + { + {6001837395299394988, 7545846298204709215, 6662102781970969966, 12696054550672669874}, + {7436995610194789060, 9042605089262227561, 11621508125069628605, 7289479057360149973}, + }, + { + {9447061002880879247, 14620964119546151815, 12310553083192998735, 15923694411935453454}, + {7392925129127637753, 14135139889986895975, 12760571438361221130, 17000514617803354735}, + }, + { + {15555649500689005370, 7857014165815014600, 4664069234996337119, 8058230521837307501}, + {18090421626009183450, 9278179697462444898, 17138879353097908770, 18285223269807746171}, + }, + { + {6099842409325199202, 2732701612070195412, 18229871238556385053, 10275023622778520796}, + {5986266691884320152, 9796109565274465130, 8132405984970989382, 4521405733027618902}, + }, + { + {7427469853953577123, 9581104712231034671, 1702722776800247878, 12656779221313783543}, + {17977155285174544822, 7208039998659519604, 16978428797146101290, 4487821481774245164}, + }, + { + {8040999562333134211, 6854344540855006667, 2481534773419348751, 15571316619985340537}, + {10089854957334316687, 4775911690791701632, 15619815835608539594, 336338508421162031}, + }, + { + {12741225973381753432, 5461579923265799106, 4348015554411389960, 14970536173310927872}, + {11568371199139699619, 11748662751675667230, 15495664823061891700, 670495577617908409}, + }, + { + {6065163107315563308, 10179715614080542168, 15046885616273736618, 3965401047645186422}, + {7013093813183571821, 6087826007582017410, 14469686436525543908, 9620661780899615891}, + }, + { + {4469547109588409455, 11124190799085603197, 7471495874998642156, 14754586999614006506}, + {88849924092797594, 3031352551776027825, 15701321561580429717, 783416358537121491}, + }, + { + {16899538363784443428, 1224176808212436099, 8044883358999763192, 8119246882922976226}, + {1602185320898819533, 7795133078900055750, 15379182653822915088, 11717676755990779936}, + }, + { + {9865772269601493999, 7325690007062740244, 18437964667185475354, 9546360111100619473}, + {6266116854923135821, 295905071295541234, 16037468634731642095, 16602609756229843150}, + }, + { + {9871952371310035629, 16929106233175362415, 3445554197529258762, 1598752868683659684}, + {10123732080482057842, 2393692486932623922, 2380673894473467164, 14578017559552626408}, + }, + { + {16688239163561330036, 11170579336923472003, 3699145675255553709, 3266133724446548264}, + {13646430870088709566, 9802235972068927845, 4016187574117121322, 8646347483626678378}, + }, + { + {3473609455134319994, 8666646689587058890, 10588670228528079578, 1636194164122827747}, + {10443498896203771168, 1711092164750178258, 3641509682909832777, 11037852869436666140}, + }, + }, + { + { + {15254713655124736464, 6283719686609422435, 5417864180357938798, 14010638809605797246}, + {10873690600705871523, 15014239467130590294, 15765460219545280655, 6048061577845125750}, + }, + { + {12012729503226546642, 4811951115754240681, 2652621264600062520, 1108958391967017223}, + {2508980100759035797, 9023233544151778447, 11183557587641545146, 10726727280840759519}, + }, + { + {396296174223428093, 16763788748988621834, 10606803701784640909, 2399987183687936561}, + {3641562114746393614, 8536687357022564742, 14532545286961725758, 14658331097531946901}, + }, + { + {2386026063595321071, 9144724461940169335, 13121187420621518554, 17351696676224980491}, + {143495028693925520, 4590642171152119027, 8655406817079059692, 10005507077955932112}, + }, + { + {2047964090310465728, 14133690277069748515, 8287749071957055844, 16821270580974431218}, + {10324684883587585565, 9652498187344172497, 2461802306013063247, 15048850312040680643}, + }, + { + {105705035058376953, 7541598459498134635, 6627685529861836787, 5724525771392188178}, + {13865897118300842617, 627652561624109853, 167084371112939132, 14192831153344015422}, + }, + { + {12837696619944805389, 13470316523008526719, 3074966674353053986, 2630814767089382743}, + {13353767941686870870, 11405513520090968568, 3071969598389884693, 8212421686942839224}, + }, + { + {3464453985305889088, 7486900500389940957, 8944303108517222303, 18319933556403836918}, + {6782476025105836770, 12822840946923377510, 2799592944286097404, 8737598030273298051}, + }, + { + {170025682710985810, 13049055489275530431, 1714038719952287416, 8470425667049459662}, + {15692449588624337561, 6306908925988159475, 7292362624201217567, 10084542069209889549}, + }, + { + {5788423445465760069, 7489854375947810149, 2512436350424132958, 18422682564857699600}, + {5177251288327577128, 13879051611542381588, 12430182880452441435, 16367520376757404605}, + }, + { + {1828702178325893477, 504110179554648546, 13285173922848349127, 15811513724231368560}, + {5009291056218383875, 12726125712718222937, 2511326207435121241, 4878070763721166868}, + }, + { + {3151967592390934907, 8745573685636820318, 6591530195811780291, 2269684725432150574}, + {7575618284647930930, 14430170051221190457, 17370623489799706048, 17190167628015666439}, + }, + { + {13971505255871035961, 14447456703883945351, 7749508685925819836, 12281701633335081378}, + {4638096293890044597, 16388439049639616700, 2805317369196495081, 5611057071508020450}, + }, + { + {3416635149605340108, 10996030428276056653, 14121021550848949146, 17748729969482499931}, + {12079053778595035959, 7473419378019222577, 1862205264236631673, 13655366704192015583}, + }, + { + {4817911180954611512, 14468615228783100826, 5900448495927012352, 2522071476550218088}, + {15649024877429766334, 3445298745493942789, 2295617386899137580, 18376023059372246253}, + }, + }, + { + { + {5228416958727036186, 12534300056259911378, 6859045937063682340, 16561718753727911412}, + {9427589074776024847, 4167904055656501509, 10156691045253563236, 17557096561606923049}, + }, + { + {12847261474293104380, 15935635664155479706, 11956861064550631146, 11743590506948225647}, + {15973092866215748716, 8269726904881958353, 15639962392523441528, 15171417818360069012}, + }, + { + {2605212343977737441, 18393471024186189813, 2302707671753008158, 8606549841034095192}, + {3842822953634987820, 3094721493917442423, 6408313759447502937, 13486364200254727287}, + }, + { + {2191808101092881088, 128992526124656216, 738676021426139131, 10157323147642681558}, + {11221959943853120586, 18255489816550713347, 10885231659068427649, 12104397395119665023}, + }, + { + {7707807226411417919, 16609863548699265350, 17639371636697428128, 8755472387723764172}, + {164779854477783265, 9714199241756765614, 3491355372893948450, 17683742455036967163}, + }, + { + {13595758632462338296, 14515163666150177917, 6720823780841221770, 15071435664343609336}, + {9016075014492765983, 16881277609836316886, 6969993988115170067, 15419704786434737070}, + }, + { + {14933348768149415725, 8499210770493553168, 6778840616148281272, 13282837866452012488}, + {12007326272174861053, 11172739862019218274, 15202495365302649711, 8797477675597086120}, + }, + { + {17862558746132168231, 4941846130090682869, 17131557654945008226, 5312800819142473968}, + {5818269467205924209, 13458582047859447022, 2683428091382447153, 12956887954464730664}, + }, + { + {11820752998821943867, 5623379642132478491, 11666807493120740820, 7241997274572162616}, + {17165010508995490690, 1769225877906480182, 3814296306467163522, 1913823003062817434}, + }, + { + {11936813336110488997, 3878433838529606580, 6540053284493149566, 10610279324743393563}, + {14079852809920102066, 9176732841330794388, 14287311909822853963, 7146204303626670196}, + }, + { + {1222343790928490335, 2199405396044383670, 14080919887213592148, 7341303626667347624}, + {11784881532696657518, 17307742911086150556, 6036132721599132043, 12167106497065306941}, + }, + { + {13817073203406999359, 7220729284169210756, 14908407498603601482, 13536224989620701632}, + {1615171540711527931, 2063856048260214664, 10622581435417474559, 16378505765730768032}, + }, + { + {6855676470217754770, 9517149712286624325, 11080380031068971680, 667425509348698033}, + {6136243307299269825, 5326577850303193160, 16120190278345757447, 1982981965726975383}, + }, + { + {15399454106099176868, 3988744407816581672, 3596277710300384050, 15129113714633923498}, + {1554582462382333698, 3164553872715651710, 12729140363982748426, 16366728035709811784}, + }, + { + {11647936211409428873, 14704462653811533865, 10005129575282387925, 1526194796943187368}, + {10906326807488904308, 18256878690674435807, 13093574545395154003, 12352810226542367406}, + }, + }, + { + { + {17055119974261943875, 6266720893662254540, 13102139953381148874, 5249314164321788611}, + {7157525732140787612, 15381277459195914226, 17265025258266710353, 17573500432599548120}, + }, + { + {940679263188661008, 14653357165718140350, 15439920797347843673, 9415587255510557494}, + {18115037054677722678, 8165849408798239027, 17369387099667572407, 17619066457126678815}, + }, + { + {8649149223282317557, 7756351751136698462, 18239772072009739451, 9817506578949224559}, + {18378033667730800420, 16794121140066562876, 5288247581483071333, 12402303517382928119}, + }, + { + {11047138821675365077, 8918121441180891972, 26692501222219426, 15248413052700323978}, + {7305399157133896461, 7065644238942265367, 3949166834387057064, 14178248206708015607}, + }, + { + {2031270890855333638, 16982096442429440651, 16686304398848635900, 5829842366016448839}, + {14111080098472974183, 12565301877743332219, 1685254887702201709, 10638099573980009130}, + }, + { + {9618597135962048429, 4323708363301758294, 1934098864729515110, 12038442338797726450}, + {8373847126955513333, 3300151407444969023, 15888126952439796914, 1426880256839266097}, + }, + { + {6428576619669681259, 7657770350257045071, 17839413659396163406, 4702043961312931605}, + {8200928556018997183, 13282376860743810804, 13005614455417667639, 17419029631791664639}, + }, + { + {69860179712677448, 15464996655458230480, 15095351218136595554, 3792171085643513009}, + {3187131848664503636, 12713332789590787064, 6278731049699775392, 1597379696359884724}, + }, + { + {15673011075664376010, 15519225812231888543, 1336371877669824820, 4354970830277120843}, + {8744720488959125220, 17541792919601146935, 14299260104084112815, 16082554294713598652}, + }, + { + {13540612390708052286, 10213354985487483900, 11366371415587713866, 10334937577432263044}, + {13368390835254255145, 13453645319717588760, 6303196127329783110, 1204334422768264234}, + }, + { + {18221540219239501535, 8536815826205784644, 17328509446048600304, 13923028809228258331}, + {13984621134784540482, 10254983270679630247, 17457131706329229663, 927850905006752032}, + }, + { + {3952205381894147962, 11371446109407143937, 7231851263356642380, 11612512368538303138}, + {5227214975837085115, 10737565048439707166, 6333629542995218640, 12386725921557807638}, + }, + { + {3772067962000745672, 4436468403847408320, 10612599615182677580, 13738755391074136269}, + {13665557786177426407, 14568219921857752, 2691062926825113708, 14666515738377567975}, + }, + { + {5392936538333570234, 10526292103645946001, 14132494129869423619, 7207059073717065545}, + {283545293669631007, 15845011600683983526, 5081287846871250008, 17931854980704528162}, + }, + { + {8364400939527235175, 7959571573625351093, 15849019287994534535, 6982609389731776566}, + {6287382484291579264, 16496145344132275167, 12062306229709713775, 312030175316686885}, + }, + }, + { + { + {17224650011872599657, 11430188086182976152, 12892063618843720029, 5912993124689510433}, + {7069617917494051681, 1298012103142698333, 7943359430865057535, 9329776843721719539}, + }, + { + {9464085603669036454, 7848014338005901108, 2368914226155404065, 11578416111848517850}, + {6323647866244499941, 14399589996703947996, 2824522520842155768, 391310842153371124}, + }, + { + {9948650801233133770, 5836115460383443197, 11404170696974449207, 4791020823967734476}, + {423024247809958592, 11251668387880260801, 5562546584223492723, 578572156618131794}, + }, + { + {13988854693674964723, 10817154032069031941, 3171651998645961547, 5518712225783687705}, + {14706905091132091970, 13960758460934966876, 12141035142079693145, 3149939820435101269}, + }, + { + {2505301881938098126, 9962323478923652140, 9312199523950444342, 12957822502673689705}, + {8060810607849163143, 737408553843844193, 8143568733429881786, 18003168270780769476}, + }, + { + {4460927228453411137, 16058422703785787527, 8016770980039986075, 11450941100964860520}, + {2742597710491507274, 16940752978671801273, 5897441526901650840, 5926672707007682446}, + }, + { + {5772778048593061508, 15424756817708323928, 11842041259277183807, 17669952685051160523}, + {5405007811515938363, 4415223809135251038, 2223192286456742546, 15742105795795272774}, + }, + { + {11809342655313500273, 16822704101813284237, 13097372075606737923, 5463281428453250615}, + {11967866991673525562, 6828790575157689223, 12568831962097805646, 8385980093725157349}, + }, + { + {8090324765778815982, 15997433100218204643, 7771766025433829989, 914551143312324786}, + {4640358803642182649, 17428148208737756210, 12144967737399770998, 15075125743380741412}, + }, + { + {5954807828598238451, 3186352433639831389, 333598278340882889, 8647732331490039308}, + {3706589107409903019, 7338319463305947507, 3829684452513478938, 8551967121356509963}, + }, + { + {16753777599759754869, 12028154198579512953, 7911616552276519044, 789841268294170739}, + {8228995103825761982, 14293958931719060336, 2778055819582565008, 1399082948378499882}, + }, + { + {12492565198527218900, 17337285577296730202, 15088344513573802417, 4272568906387671217}, + {2365541522321646412, 678395397666822608, 437334842774934301, 13443327606166079837}, + }, + { + {1266313952277763194, 11470850617813390661, 10426389264474337810, 2996447663006153747}, + {15218295359022152122, 14634539952819815592, 1775270187047190460, 2942637199921677956}, + }, + { + {4952377176677649521, 7473631065005310719, 7363684030854414233, 12556891399998587233}, + {2190850394642244911, 5458637782288631421, 270926994697866523, 5528436328062366401}, + }, + { + {9497175173535366966, 25345745857275253, 5047829133239508177, 5340238103822773099}, + {3133339556064328840, 666970525709876149, 15575505473500291502, 12769675806855640654}, + }, + }, + { + { + {7669790431656261769, 2776517632462593286, 11694025667665633506, 9533794089008895277}, + {2895611631120558023, 11551410655448788956, 10026541900772270925, 6243136875017000843}, + }, + { + {9434484992529186384, 16435748047660609525, 16190660694150989986, 7083965852434071085}, + {4216306437741910756, 2698742177539497614, 5199793642504009017, 17298424769819019160}, + }, + { + {4041169394784902550, 5699517344009382913, 5306272267462320559, 15846674482556330025}, + {2606351264228884283, 4162585980422107281, 3715151019132039005, 6607223447043258693}, + }, + { + {8168579295855409503, 16727569921530031841, 6182114460261837773, 8940603165471931374}, + {6081572078077526926, 5890840443923124563, 11215305828294759727, 2875117534361804712}, + }, + { + {9045974983664041829, 905036705033699463, 6962033946652121779, 3027264198782618401}, + {13786415307358010100, 3643342525745067473, 13641958783381681886, 15675065537779359584}, + }, + { + {7507377696839752642, 1061259379811757443, 10276590160392917813, 6889137095037822679}, + {16373913505782725550, 12287733095803524526, 5695917172259210496, 6360958736925918808}, + }, + { + {7459854586357006968, 702429387211615855, 8231296036461604410, 628323703857882004}, + {1059802628602873385, 12517208225099517507, 2368172548334856593, 4792344750094708709}, + }, + { + {18352334786472886037, 7096021570596476676, 17045407505128867173, 2467670847537319400}, + {2225663888244226889, 1876713214939672742, 5329943993157142620, 12168650975912182188}, + }, + { + {6639850268372381409, 2284514769224558945, 15390110317831975716, 13933785559694229008}, + {12787641603764341997, 793886210532292741, 3222136169196008839, 11104892506868626444}, + }, + { + {12660547967989039787, 2109392063597767300, 9889743271997754037, 11803327596624324036}, + {6940409327849314286, 1466399127363116843, 2572333022681966275, 4216097356402537802}, + }, + { + {16858757460581672909, 5838407119753001493, 4453405435911954669, 2828665451507432751}, + {13657966632733241760, 6875986784381874300, 2390233934255482553, 17386653779125555159}, + }, + { + {2976756344404126744, 17032556609402836559, 16348907464011574182, 2196781021202618892}, + {8270822867494340805, 4738372358350764889, 6088256422707334932, 17121369334507507505}, + }, + { + {2081729301541563384, 5577186154173396778, 1865152567701500436, 1422284589642218069}, + {2489023909725140903, 276494395149046869, 17420927169263487236, 8292343688801608074}, + }, + { + {7819174654675104600, 12778055482430336726, 14615848543490171611, 17498415175263742825}, + {4785899184222234034, 5227136636239697699, 1570704808469050246, 2858953380860123257}, + }, + { + {4323577007857413306, 10524228743339400397, 5418808897687027557, 5939367271366264075}, + {3569359126353670574, 12961495213964770607, 8906990808988099905, 261084295374207271}, + }, + }, + { + { + {14408045416865494124, 2442199381796557002, 10475326303775862953, 13637445125954159957}, + {3778313603630758744, 9247460369874272772, 17572237597883145087, 11338350096360776602}, + }, + { + {4336697789732072031, 16054848662858822197, 17934449813415035557, 14518380622432694666}, + {14100582434152190048, 6262866632984449325, 18069160441815400774, 9798342103009260692}, + }, + { + {17244020587062193870, 7625407515295016845, 12692919397126044801, 739129074276464779}, + {977900962655641355, 1516169712468716336, 16875961107875019625, 1582931498538195018}, + }, + { + {687104890149081183, 1938816743979859301, 11342071981175913904, 4270322127259097184}, + {4964776270155503160, 17849333582861534767, 15814479527332819692, 8083943565773123408}, + }, + { + {7977186743666958490, 3126199553548085949, 16879636338977836444, 16647578924708995556}, + {5526017172393528596, 11328754652335568585, 8095074058116436597, 14648690727521713743}, + }, + { + {18335678403814425235, 13764304056086998207, 18139296224460762074, 17620705673387523052}, + {16059975647897396183, 14392541906869470064, 13641721532745636092, 6122032872822720831}, + }, + { + {13983401929934353021, 13860725962778449344, 11760533704789481157, 12566657951327299627}, + {14697122142882732522, 1606632877136342124, 7872716135734366961, 18220536079227927821}, + }, + { + {3986890035154628803, 15316660330065019741, 11560940574529263780, 12576851520091035878}, + {10883944418224886092, 9908329441525486205, 11238684990962507809, 12900626758810151662}, + }, + { + {2629393050548942288, 6363222898077806203, 18404650886731368903, 2691451856029551156}, + {5104932743043229112, 1302939624985069019, 11820239270922660661, 16228045717328023331}, + }, + { + {778457530134061801, 4290661013056586404, 12033745869654330486, 17833837257536520292}, + {950548111600899172, 16026254932420015523, 14620989142158250051, 8236598933984161995}, + }, + { + {8828068000936861634, 10901971915827198521, 15635295283164640480, 352740455954411610}, + {4853015383138960329, 2945696874639059776, 7204307993540375148, 11980890732241054979}, + }, + { + {4077800412543228484, 7173833470188867493, 4604439809988262876, 8090706047559948234}, + {6117166546062912279, 15748537214854486946, 16719594636199001564, 563850925691991999}, + }, + { + {4802884399593912281, 13437020732272033050, 12197788481695720547, 2162699662292229581}, + {4193517889478995518, 8610646873096992408, 9485787089338760040, 12392145097158647056}, + }, + { + {18079795516810465755, 15723042000668265475, 12488322519570427659, 14012836221417650412}, + {6534900133691249330, 8115921632235353076, 4093907116172233459, 16784728000548766561}, + }, + { + {6262200118048820167, 12719453838344002789, 5526427573572313315, 8520226123932607126}, + {3618116539863181413, 14020033065434801713, 15675496263723836857, 11987954535452978647}, + }, + }, + { + { + {10847249691051757241, 13332329214721571156, 12457628412284474075, 17044657510482764070}, + {5218221397478351943, 6922630493693541156, 6207927102810766143, 5644846665334649748}, + }, + { + {6506371904134856034, 9541373683805144018, 3149037850125132851, 7111810601994573897}, + {16732445693192247884, 4994069681898274622, 7223719243730104348, 5649174084086150712}, + }, + { + {16562962997045986629, 1977585352264948582, 15588655103333244279, 253344970359156714}, + {12939363813291366775, 12548224526376199974, 14450582788883748364, 5869541533939881460}, + }, + { + {13970586842647892965, 3680317572634289692, 3416494470839852757, 8341497967750607131}, + {5522860734580749818, 6847292760525096386, 9317394708872196559, 8522252330730808934}, + }, + { + {6838341670149165895, 12326189699069923388, 9258908232339348843, 17297038041466207989}, + {5242182985453021593, 9648294165629935142, 9715128265517308395, 2662662536493743894}, + }, + { + {6790869670806738567, 4499989093713728199, 17496748050437205626, 7194829324969293638}, + {18432532588985091708, 12041300075343806904, 7788543067151959941, 13703334460383638224}, + }, + { + {5996381448168274884, 8108757135223610234, 8067369725584584297, 7184925262427750366}, + {8199341143188441284, 13031376443169557016, 16036606349050125404, 11958720833222295864}, + }, + { + {9293668142017263584, 17134656749295164870, 5879480323258506465, 4788695233340705697}, + {17809277710857366810, 15157733645094688870, 14143869691462709080, 3162286338158090229}, + }, + { + {16056959590901591813, 1082823161154599460, 10221040439441372421, 18283403891485112294}, + {17582486701671091218, 6489397700174053547, 3952499348250646760, 4381145145005361247}, + }, + { + {464321249842430028, 11444362575253049653, 2734975360475017776, 4746579078625212558}, + {11326126526565916100, 7840007639237722362, 7545779893877671555, 8952053274372957788}, + }, + { + {9171324502111757965, 11245577625425383295, 15294815109909975990, 12306264653913762086}, + {5906268309303228662, 2685370982867857233, 5470203265560800284, 1354105134944127233}, + }, + { + {10610818607308010986, 1017341076592473937, 13259969743043862138, 1850907007366751943}, + {7689302552902672401, 15375957693502270090, 13877050204486881614, 16441247744335371320}, + }, + { + {18161720198110725057, 14887135440336057963, 6790952723850964648, 15120775513153544155}, + {11797493458812299470, 9090758778610315656, 605835259544633945, 14755333155432393992}, + }, + { + {14967102006962978091, 4301508725220174920, 11299977101982031802, 14410789725331022027}, + {17005709003661351591, 9843840931527318478, 11917612896070173894, 12007179364072802553}, + }, + { + {15913542135925395264, 2830138374220921671, 6395020779026969444, 1239443258852925290}, + {4519359001030231260, 9606729174209623750, 14291346135557028396, 16179513817501558495}, + }, + }, + { + { + {10223936123327786454, 2321887803300626936, 13607747528117965743, 10456421630388400123}, + {3266519591187534953, 1053691207967834494, 7151443045753788549, 18124688636664828399}, + }, + { + {6946488664257064464, 9775328903143754150, 58700362449753229, 7901817271072273406}, + {5074738678159003249, 18397239731906005785, 15911102965988125888, 9277654580204145348}, + }, + { + {1874700306906525099, 7337351570334852732, 7954195906114335343, 17230226427261850070}, + {5181329498860909261, 107167242193237170, 4364856176182710332, 14611171841443342914}, + }, + { + {10990327814895720476, 16588412771027628390, 2850177278998422188, 11569813740328484871}, + {3922148781422941186, 3581659216490446242, 3646872304052351376, 10887870617200051198}, + }, + { + {8175121141368087217, 15079393830876652065, 16766987879267543828, 10582796406546815217}, + {16832256009371376870, 10042650470778064892, 17867163453935683780, 7123418345572641116}, + }, + { + {1782651072016504775, 11033882508408412333, 11105300284232190625, 3276372405089292929}, + {6399472468041061588, 15319690780388315076, 4928530863063375966, 11596222198340277418}, + }, + { + {5452424185619067445, 12050433097586021281, 15018766900844679217, 273234254926088220}, + {15426383635547379531, 5213762666043737626, 2829185842069118470, 3230799283770935127}, + }, + { + {280030342772428106, 17354882606189694746, 17455445295460080284, 18076709382926018941}, + {9895982528034548913, 13681172423928175330, 1656433131309057012, 11935757350437721114}, + }, + { + {14437472586336929440, 17387041914242263390, 14861577074379746687, 5146556788377906297}, + {13036814755814090195, 15108836859245573802, 1667563994642521213, 14722845469958372258}, + }, + { + {7781061995240980266, 2066078418484154391, 4089376589847114892, 2434843609506038666}, + {18376509832460312721, 7187709121160627756, 2455436656049651823, 14419116837518875372}, + }, + { + {1270185079976403265, 9214436628411717184, 15450450827683432913, 2880014804806096082}, + {15448799931519826757, 10080240282127928735, 10673974088219619287, 12998944469117087518}, + }, + { + {18028691745165748687, 8931519595829275195, 18379893031942930865, 12120980098075498008}, + {9596371470855895261, 4133427878071274570, 13159312399982591699, 1639865074052258019}, + }, + { + {1661696187746428348, 2656198437014978712, 13769477291975851694, 12512848714492869444}, + {5980926616932344693, 15821983893144953005, 5816015630031200526, 15887565799959254415}, + }, + { + {16463929919291729278, 14920112063826664828, 10056471508435050704, 10696267144984026763}, + {12049530292963090991, 11926086636123189182, 9464890378472966538, 9719194510330239601}, + }, + { + {18110249193861022779, 5612784685592189906, 11360454032996393150, 6795401682138043705}, + {1961398978248902107, 8999847457729547905, 8941741619641401180, 6086938661427918241}, + }, + }, + { + { + {1119490156854665483, 16772836556735128526, 8607715508817325509, 9931017263385440911}, + {8799481055779587022, 11740562709785257943, 1956849872282864970, 595288629437737005}, + }, + { + {11601570184515356415, 11247678357869162156, 8415095559389686315, 9625816053586466047}, + {11807876143163335372, 15690209134241397733, 8684637224468015605, 15974968144193406020}, + }, + { + {6498861108824484382, 4670555282769381189, 6606014320886832914, 17078765892830617318}, + {546267528591230105, 17808649363082080722, 3219358059129920687, 9180845247506322192}, + }, + { + {11275984449259340674, 14922638629881602958, 17186426309348732477, 2094500549052461127}, + {1245672419927595636, 7529921141299797945, 3181089597449057707, 7749529014968942143}, + }, + { + {11277133910568934671, 4278895672933635880, 5062049475469993812, 2827897582327968966}, + {2992831031801695571, 13244636528396736375, 11509629662092358067, 9385849226639579800}, + }, + { + {8454236707620433029, 10192313737667573051, 18232259474515025711, 6196538652828521245}, + {6326999652188467228, 7611130140249634596, 5729331023083628955, 9386297316005425714}, + }, + { + {7621274909358193632, 3619625095597194913, 18038386254997645285, 17262892689028255302}, + {17953989125460428814, 4571031913557658215, 12218524221515562809, 12016327352942264220}, + }, + { + {12842581296013847382, 7845624487558348664, 8747439372999364825, 849305823897878133}, + {2217292264321907974, 8173534404179332054, 3588643190593022889, 12047811416592660080}, + }, + { + {8121746263843271081, 10363835147942471345, 312023379108980148, 17191823034761670562}, + {315776409136454719, 8322002171533871918, 659256727451485128, 6073539214057006838}, + }, + { + {5999134638957620752, 14196265207258829507, 5400793612736232063, 16259338359738368573}, + {11179852704740695306, 3486799782309774463, 3060529319750906379, 3540275797284687957}, + }, + { + {5485176043812882513, 10727553589889164848, 5617457077214333092, 15937493816713568462}, + {6287330459840726949, 5451240171054977850, 3524414944972920777, 8740440597273129486}, + }, + { + {6959527445237219799, 17170778245769606301, 807762173031474321, 9151445233487017286}, + {15103411489939446333, 7976669669591851659, 14824323986579638641, 1535817133122800221}, + }, + { + {13993486080187419934, 14882121651768660644, 7947881871819932407, 1364312030151957949}, + {10673187305202558690, 15038997055055408315, 9268330880459316485, 4319340556575124142}, + }, + { + {12846922591360496097, 15518450931549829779, 3843880753372237176, 11741559986398913430}, + {16974382348775305594, 7085384294841794242, 10278478682851578175, 16997904984485898637}, + }, + { + {13670930062027115328, 9912297966339314023, 17061419147322177635, 6220676237879734303}, + {12723388668517709225, 14967294924815531226, 7286002704046609276, 2105494380036834916}, + }, + }, + { + { + {17955247196574331290, 285928599571507431, 11902987704297070981, 2841167725097799100}, + {9281167410796848363, 16444340476026142274, 3423202423051178709, 9101021305726472246}, + }, + { + {8869273893561412239, 10349812081309865197, 8913824872487209090, 3148808685596180274}, + {530908416884501807, 10284103744075805979, 13606889938905754722, 2418062398586758364}, + }, + { + {2298603653884322501, 601221199968240092, 1285112712738261659, 13882709760355308533}, + {13563254433762438170, 13447718334658435053, 13493687958886238103, 11032778298151679283}, + }, + { + {8626760324117733843, 16403951745962159364, 5837394731212322914, 6847167719031297053}, + {2888142337636247281, 3409818743436360750, 1677113113408664401, 1222157560539217476}, + }, + { + {2294668553308381923, 17165287249067859297, 9897724011823072967, 17409851874231284314}, + {13888575318617508639, 12092766090379658603, 8412268183255186961, 8046572777745318483}, + }, + { + {13178439025428734594, 16388038968589028071, 16165750006742628176, 17903639397633243161}, + {9560319088110737392, 7888974492854359310, 16116323630343158496, 10177829649622711030}, + }, + { + {2378363646789710539, 494954399989334038, 6915496914984330558, 757197055392642378}, + {9097171378505823650, 12104288338329241488, 1905673690814481722, 13011078677095066032}, + }, + { + {12712274459771886808, 15748114764509451764, 1994630377849062253, 564390855806287868}, + {135493276425567450, 4305883520257541088, 4842008929542073044, 7035106970720249617}, + }, + { + {4772079965696324995, 15925041062593990538, 2818172089014580505, 11304215074611546986}, + {10130691823118346040, 11796228810049908587, 9262801389703476249, 6629344122525229781}, + }, + { + {11045983914861167112, 14106148195606833916, 4442596873181225087, 15627975325288846806}, + {8173496855557146242, 6061080385918934423, 5233260187121969538, 17554093556474728494}, + }, + { + {12122792368758575262, 810814789452398299, 6387727669765211854, 3304731719391402237}, + {15296845834923103160, 3685348582131767195, 12636335057478947340, 16971253767099552987}, + }, + { + {12345454807632743424, 11546569651702761483, 8873100774001529421, 7001975923028025552}, + {8129283832066039281, 18147888225504425296, 3510907297028745651, 897602195837260824}, + }, + { + {17896345382362222994, 2167374959533815311, 5029128091600127895, 1770543276160593316}, + {17234124146043512942, 5338191548265818047, 15676046602975694398, 1943153641089805200}, + }, + { + {11084819495273800718, 12966507689731825252, 15026437832429189138, 2506312683689776139}, + {7417463323869895004, 9819555221238697390, 1250200244896601539, 1394555910521460172}, + }, + { + {2221512141494043286, 9203854585477888176, 12171379127551511504, 10667358469120985695}, + {3795093165005123272, 6129005969593025264, 8738204659003189419, 5273583671698415302}, + }, + }, + { + { + {16549155412115374305, 75977962737081600, 8870825488941031605, 7403557657089993256}, + {5825394234709429518, 11978746413791918409, 1876293130790608838, 9416631623519692610}, + }, + { + {12346821858361333862, 6352722970730511156, 9920942104315084988, 10492373916708072181}, + {11163323626947992791, 17035282992056675772, 835685192553490421, 12792459312570503983}, + }, + { + {10447922451077327640, 1515090998837129975, 13498807582085718212, 1212623301098019779}, + {11573518650162536086, 4823461685803772444, 7289704908733783271, 13167881392748327839}, + }, + { + {16959954449957105311, 11051594981465026138, 16062472412226411858, 1976004115345602080}, + {3630495248560019222, 12698191555196404138, 10107923614229901155, 1597725222698864118}, + }, + { + {3416019089997140849, 3011417601086561495, 6275242351124667286, 14197557183081060761}, + {5633711018871057458, 9723496411345030748, 13910057756335530832, 7285051335492395815}, + }, + { + {16774605620279328247, 10223834398868957807, 15781733027568799739, 2607095622729296315}, + {16499590296954181006, 7576646116121533069, 16638313875339315529, 14296194207652471696}, + }, + { + {12874411821611501068, 1998417862388106640, 13882642435422318946, 5791129521978463837}, + {7512934139125398199, 6966283273373526248, 5475728301311080129, 13542211842758381589}, + }, + { + {7798993150530415596, 3288770257171840452, 13373286069558329631, 9784279046496345014}, + {15725032660238528813, 16038931923358478835, 6921788930154218900, 6093507035435214187}, + }, + { + {12194839527972802101, 8376199250979271449, 9055995864116790217, 8125030124567662718}, + {1070812422878398727, 3950906148308170707, 10121516919638719072, 813471384549762068}, + }, + { + {7610605259962047827, 14617655900985224117, 16089669078196617440, 10594009761533811214}, + {3425971360520359121, 1245021768718221594, 16690372892586114152, 9933179766195044175}, + }, + { + {15142732720676276463, 17435583143726694663, 6030257647680338377, 243683009289621849}, + {3064238900429394982, 7655019927497549159, 4484400084400458429, 11650860345018651068}, + }, + { + {16203650576183697977, 17614744533772112337, 1119292890050870301, 4574885263986729787}, + {8108207498737924504, 9708434439316056191, 10676823369888368482, 1078311554675991883}, + }, + { + {6876202174636220158, 18057502510666060150, 7821730895845187783, 8882321799602877790}, + {16220624224336230256, 15562800387021280583, 3043825293109091520, 697130162105054983}, + }, + { + {5394549491776704087, 14795348078061113966, 14206080764200897220, 4623073019242398493}, + {5850602047109930316, 13783531993760979209, 14764346975698048641, 8951680172224205890}, + }, + { + {7302725075484262769, 12572584665857403749, 6499691362933905099, 14476353114356185371}, + {7381716148644532401, 1573798302334388880, 8128390307766282880, 14547454176248589604}, + }, + }, + { + { + {4477325369345373420, 299141931133875776, 6787652129916359301, 2498016036564260464}, + {13342319943892943548, 11124287719737492205, 2456333599771808442, 5084719026388755304}, + }, + { + {12246932755942887931, 10842213418139067847, 1827392608284960926, 6961756951208563550}, + {14626966634382828071, 12653808277900379805, 3359368990539585596, 1190255644328095727}, + }, + { + {14845756090430871381, 1260135108359348096, 18373249503604334230, 14931345532671487262}, + {8304897926217252744, 16639705302116302354, 14578633917159176703, 5624357498623418462}, + }, + { + {10836955050615624183, 6228108794259714192, 3769609579318360527, 1481673673659326756}, + {301329772189110029, 3574710782304999603, 3037244905687722509, 14442941761397229485}, + }, + { + {3863379967423475252, 4598414140150397553, 13498347034161095546, 5995458763090398343}, + {8994138995797612256, 1053878477247308872, 16525881906724873538, 16597989933510424042}, + }, + { + {18195618552940791509, 12801347400921689158, 13372055618013067129, 14929951832730936581}, + {2563109394536979589, 3392102243539970867, 2978145866937578695, 15809561751101461921}, + }, + { + {6470844231261685519, 4860920111547376221, 6133864928365904793, 8914566156785557227}, + {8258394874597607714, 4464810914649217913, 120457844518757378, 18209291810039348360}, + }, + { + {7739110373965523311, 11019153332996240080, 7346010155518751797, 14853737521111213548}, + {2542883237207113209, 11015136828834421504, 1998601666328316353, 1540417751495800469}, + }, + { + {3376092179741497360, 12221254335784366861, 5282973200516004163, 11372960528472533628}, + {8188139842572259074, 3946305224334575645, 16643338862665650950, 5859492058050333909}, + }, + { + {14916042081488114271, 3303190861468284762, 14234546272335492538, 5776190344932209905}, + {16339988209459724195, 10022514953301624769, 7878363685856556300, 3127365206552843780}, + }, + { + {8340102858481562978, 5401806343794775245, 12619159636229742566, 16221085737347795155}, + {1241298364136442056, 9142635103215118982, 14403222699038355211, 12145678822325215894}, + }, + { + {599034134015360884, 11263317530774995092, 6667501365379084069, 9844276013103312691}, + {7566306886180438990, 13702768345615509363, 12525031963170717968, 8463786212988210464}, + }, + { + {7279390679700007004, 10579602100702377479, 4366146547587324748, 6962092370680728424}, + {16372420580520124739, 4597019194685908384, 13217149760366044828, 7222487257194391332}, + }, + { + {8454830421421057736, 4100731209937375984, 18348214289895908213, 6778376865226169852}, + {12945227893790929647, 1818657910008686277, 3629900123705314093, 2861658388952811590}, + }, + { + {15882969890737930334, 5849157078791136995, 10068103243390577755, 13131421240079433547}, + {10404642120419399290, 8199866428750316037, 1032443962738597455, 15582122438927179496}, + }, + }, + { + { + {6390361653475754940, 1093882175267357438, 3784079074949811167, 17343872969822169769}, + {3359715652121662979, 16808529787251986583, 5169730697018536870, 52766949850965558}, + }, + { + {13147212495082910072, 5628914243538540648, 439989514095330941, 7620472329041817834}, + {4272251824771633288, 16564977601507013119, 5441117136715882317, 5622571730905974389}, + }, + { + {4207421531032215145, 7924589143024019458, 5496622772676523695, 7061817399179278712}, + {7371689806847905735, 8282663810521090335, 11422487361383982601, 6397294642072086677}, + }, + { + {960381383357168877, 16774709963697143275, 17896181076874992240, 1150415168189819777}, + {5498481130530161530, 6895900060791069290, 2079514944189747822, 3428689507902936354}, + }, + { + {12056920178557394302, 5131253251712581899, 16251877995882633963, 10883064494054484051}, + {9473274815269607947, 8874308005470196739, 4412709653190846630, 16469366225886156991}, + }, + { + {3547198835521135552, 9940690805769919242, 15170549880149605690, 10701681269101530298}, + {5914809102954412895, 15790219349994701461, 13664049285300230863, 5735249081148743651}, + }, + { + {14753645881295168970, 9410794713982813264, 13485977523338061503, 14267793994973767571}, + {15813187206361118954, 16449603969001878152, 17705410933007144731, 10960511750491378082}, + }, + { + {4669722990542640772, 10017368027073540045, 13392819319228640800, 1070815632453829996}, + {7274130058405640448, 4460835865761538026, 15283885107956150892, 5815884817303156137}, + }, + { + {3469614802230980914, 18060080625283048965, 580464295809221798, 3338153928139206412}, + {9845192339392693455, 13250323899168115720, 11058696855422647818, 9665232062806155902}, + }, + { + {14461336556325939926, 16946363864290460645, 17546878353664479567, 17949437676666656135}, + {7932367178689988878, 4806368097560008659, 3460529608269790679, 6065321700046177254}, + }, + { + {16883816924971606835, 5486714189826473375, 15204267662844332028, 17199232837602035696}, + {15958749676770074119, 5540664038667498053, 15914281753951743318, 12225053486711127081}, + }, + { + {15346266095840263783, 14129675453960658911, 1781465630073142581, 12398710533895277470}, + {17697074063253841985, 13826156613321578228, 8855030685964401164, 3749659313217692983}, + }, + { + {14888039192306165275, 11233459160096048886, 709252573146299872, 17614748022803380926}, + {10853790173866038588, 2988411430602910678, 1343284586410250367, 4491892393582674365}, + }, + { + {5653853395031137185, 11847098886335071270, 15046954358935848863, 490763079643421287}, + {3113500211585712650, 15997550469331041114, 5281575885072775975, 2887311255648554506}, + }, + { + {5376335754670737023, 13164671289498247151, 6846569847526260467, 5496656304894178122}, + {2009132493403453913, 17250524577747091030, 2315376314333653245, 142024984008484689}, + }, + }, + { + { + {7237168574323016859, 17908810107504968137, 16225708127838178121, 11127095986977103648}, + {9346291308317410251, 7381283458277047010, 15168602815371846943, 9193719743691734294}, + }, + { + {9607254959726458411, 16837156817186931862, 16178143308706847393, 10970721795101931539}, + {10840376278605273092, 8298765077094727469, 15520543037910966843, 11484620381947762562}, + }, + { + {17395070963094117711, 7608132718922490881, 6531178971071758016, 1302814667007331361}, + {4002629363862769670, 14649492495298089937, 6868174210142585697, 15456170652716048683}, + }, + { + {3688308493559609536, 5123828159813683938, 6245436817220183971, 13062234263274605325}, + {1313395302496832996, 4961840797708687855, 4990192311341859196, 5283131006216350959}, + }, + { + {16952735659396950704, 1249482796824289329, 17859504101404809981, 13260403650830168625}, + {1583343855370236084, 11389120333403185826, 13676599385745755008, 5066667130137739346}, + }, + { + {4799264864906918301, 18347145714884655971, 17034125441088681346, 11828378178487279470}, + {1759038296522081901, 9582407833575609381, 4195817009050503354, 12618256395967210055}, + }, + { + {6486755100213398364, 5270923715575268322, 9268255346880651103, 3147724493117082267}, + {16710318779269985633, 1240462642985509644, 2400811796254219369, 13670743068809614358}, + }, + { + {11437779990773246594, 13609113239383378152, 31268927496646090, 11618772705165035208}, + {3078024460365036167, 12138983306908962712, 4779157919015181380, 11901698850260672002}, + }, + { + {14642787507945832432, 16258081639927585935, 2560321462542164242, 16286882196975458174}, + {4328159372518768969, 14313553865397841147, 13769372656320240568, 8950675126435331579}, + }, + { + {1309709344837422378, 18403288028608342631, 17102350491414677993, 1133523394849437315}, + {12526496222782003755, 5447309058259018864, 17311120581405946631, 3760058661125144368}, + }, + { + {17891474172606596407, 320094264574086461, 93927075222964142, 14355817838636249140}, + {1777882427773785068, 8237021421587560510, 11520559469641852991, 10567910693910023157}, + }, + { + {9164300764173563614, 12322279811717869943, 2768902015676238485, 7761799112151133995}, + {5740162933856370894, 8043946608495226840, 8923704438836381869, 15189322655373943849}, + }, + { + {12046275966378825708, 5909386969214935556, 1201990704907881028, 12128549009950617306}, + {10773478878317625320, 4554854625564648958, 14029736945871573056, 1353247251064221090}, + }, + { + {11909123603272307101, 5517949035179831783, 3295386484950432959, 5605137795524476293}, + {10718654547602473221, 4984952409581272095, 883267724006996723, 17328431094026829348}, + }, + { + {13671210467347025770, 9980617617519781731, 8339868735163579231, 2150724314757661915}, + {8571153021065445899, 9146903697769397191, 9122246102814640373, 7744779513085605450}, + }, + }, + { + { + {9508384588323002196, 4786531415304518048, 2690306308552249535, 12208815515689370850}, + {5145548243685871201, 1536915039528215765, 709289946127949333, 7152734178531880864}, + }, + { + {9627905753364576437, 12776456422166281355, 2851899644189834214, 16998174196920379994}, + {9001602524188761177, 8960294999163663712, 6580949973363012183, 7568306074815116797}, + }, + { + {7686633626025788546, 8110394872630496906, 8482210436161892079, 16882855163559885891}, + {1154081680627148904, 12804224766760790394, 1850455828762691082, 14191115350906359627}, + }, + { + {13345381996769253014, 6278048669175242345, 15990349685835870151, 16358261962292186792}, + {8505261070637963021, 9396725065098564446, 15331953351049782155, 16194796339208321205}, + }, + { + {15505898598362934929, 16825210854979603981, 4697782190623959274, 9370503401456774242}, + {12874840227707962403, 6119547445810629810, 9764164009057494220, 5416853666956021065}, + }, + { + {7699498684510298360, 16542285627069734869, 200751785530104649, 6985944962584804095}, + {7365545959109847649, 14865387755379324112, 4167319688751668987, 12162483513847343974}, + }, + { + {1039980316046001816, 7207503221801597145, 10591680158322288825, 11266400320575557454}, + {10706275395641440317, 9288394947884616208, 10167533985006762418, 1456585988309878747}, + }, + { + {7076257175157660597, 13221730879315432464, 4499548735964119085, 7559253754663705944}, + {10196808438730350168, 2391718471837563931, 914409564589897387, 6649744842278078706}, + }, + { + {10039057354622246685, 7195562849416781100, 17696866082062058984, 3668253949076972503}, + {3291647709604288622, 14581068695089559804, 10104544037456163379, 5446494334499941155}, + }, + { + {11083442423555675697, 16463352501129765262, 8326106600927169880, 14461723217830443766}, + {8960039240507947123, 6112452535158412156, 16298251376476091126, 5185774007776019173}, + }, + { + {5801222283949474418, 13946418525037992779, 2275515160040674505, 3244981365190546382}, + {9460698310301428534, 14807942233170768102, 6180104492182570514, 4695926909096500015}, + }, + { + {5502356275170104522, 12750322860129485966, 9581277511584938955, 3872282844937972630}, + {13668854758739140874, 15020438121087800965, 4581631138384430657, 13296613956093963588}, + }, + { + {7394309355461523862, 5374161350639568117, 2763783634295242959, 10215168014269656712}, + {10862202275249464165, 16813773246956503013, 4644566761082532589, 15300517379307655907}, + }, + { + {10894319502247195436, 16018449015752583379, 7936971022695592164, 8273950599391165937}, + {1130484969598457981, 10652972605389048300, 5964985167476071140, 1178111465674979168}, + }, + { + {3215460690308212256, 13044009109542950831, 1248575312568743704, 5805472854961471970}, + {16935262056111009166, 14323719510498371522, 4137201278518680629, 9262447671880633672}, + }, + }, + { + { + {10228366644420455452, 12084265406352277347, 10265869676493821892, 3560143954870272139}, + {14368775225608592689, 13173522067191372913, 3592475039513249949, 11243554718624931135}, + }, + { + {6543255501112359319, 6063422531520498671, 17228726254778244409, 7570754775709645369}, + {18222396492501523182, 14903937974816691813, 1216646642383641441, 7602781158453005929}, + }, + { + {14568782576170814716, 17582848432122737506, 1079387064102681806, 17278567874821675408}, + {3094302191119669899, 3730448048895347901, 3508894590334961422, 14091660942919228106}, + }, + { + {13329033749048978810, 4765695903433858377, 4452680451529163940, 5638854187414651620}, + {7897503022043776206, 17187635538005569019, 17766753195497526986, 13201529234556380285}, + }, + { + {8934119620399766972, 4226481091885914732, 16000709195004445297, 14687868180928846933}, + {16269913392757896907, 18294005838441325342, 17625669613551023126, 10864307042201644469}, + }, + { + {14722530431277419104, 12333728409662476827, 4162946257347548625, 7052045338975163666}, + {16435875989376103923, 527141841571514699, 8480360258792897962, 4322786951393806781}, + }, + { + {14380803034817149259, 11042134597430846555, 9992762805140200547, 9895143575678511242}, + {3228768306004664915, 16153114680219541243, 12036181641761325912, 491369524302296324}, + }, + { + {12320933424684960076, 8906954611339502145, 16931708732547376267, 6446897311644431583}, + {13749563256713530203, 11522599770043814384, 14455556215959342791, 9022955938835504923}, + }, + { + {8738648866901281761, 4688741093801776285, 17069682640810525423, 7158141773766072053}, + {11460933790638879246, 687134766504463570, 7796313120876518884, 11150451731319135164}, + }, + { + {13652684811535265600, 8494726433844453583, 15999979552047212740, 16433235792902853942}, + {13641303900302396790, 418630713805776951, 13090797093697365883, 6529658430803752768}, + }, + { + {3944614182924380177, 9542495129087581473, 6699683662731923419, 5017219913619823514}, + {17045736494588140273, 3578045824537114332, 15234910011456151711, 4392310298224006475}, + }, + { + {13050963220563520130, 16311879939705207639, 12461297624582251388, 9677731599265769222}, + {5160679975931966230, 3218707041599533629, 17098083534384492023, 2330141721984719029}, + }, + { + {8245975647138927146, 11496799090887525271, 1709462103065191917, 18401529677683893204}, + {13971543411749700717, 15107687167816783802, 7171906080161032790, 2549191081579169610}, + }, + { + {17251496610557148115, 13056982918233222110, 16321077587645226911, 15873643227887663856}, + {7790198561388957118, 9539520576306975575, 15234893276112958324, 12999697377068360422}, + }, + { + {16169560456946825943, 18091964243071526492, 4341876361632902705, 7532668331381251135}, + {15346381760818990405, 18301333564088079147, 6565096728885044125, 2494845330727350075}, + }, + }, + { + { + {16319476863352440541, 10283930715856640343, 17675054544532098447, 11261132162985242084}, + {13712716897981761400, 2681907143459288706, 6930256922080133347, 1445069157579547822}, + }, + { + {16928574868467385886, 166417019993787654, 5882811520342817815, 14106304179344008065}, + {3747123724781081800, 197109533566874475, 14303280595714789450, 15457633026018307066}, + }, + { + {10773597511592584859, 12552868588431074640, 13500771767160426835, 8002499270056378440}, + {13792839099998553174, 12949371255843262119, 1713974340992291550, 16150173130483658061}, + }, + { + {14745984256428057001, 9333707338036985191, 15365925315303462, 11789129028059619744}, + {7873100217437235208, 5289763977161829145, 17731215200358323788, 8876377479309635703}, + }, + { + {265950821974454804, 5047467530470542278, 17523044368516619801, 10054436503372765176}, + {10321185867287373431, 1212061937729015591, 15311258419138633926, 11236518538207084768}, + }, + { + {10904693956407098222, 9013418755007070130, 15510005599846320670, 995378633446250700}, + {12234095025518917836, 6689106237771514188, 2809193993744369126, 548124799387888260}, + }, + { + {267350765778774337, 2853877351938464055, 3677119082593358544, 7685335121077514739}, + {6491980094762370981, 1384870316654548002, 10568872345228996498, 241629538659623878}, + }, + { + {5839400175629113441, 5238299193248381245, 16787876416022887315, 6051613843621920008}, + {9219569873668974552, 5916753090530931032, 13390630214643423749, 3265335490455191268}, + }, + { + {1507475744849985303, 2597075068965622770, 14968669113917266926, 597606442423659891}, + {44293923912414886, 3832651144752540816, 17438860065613195810, 782112340603343331}, + }, + { + {9050896199196733903, 6427608033444590004, 13787696679536621857, 9682087046920409188}, + {4519093754155995429, 13564098392055667371, 10512507082236058799, 5289934424008191746}, + }, + { + {3477191607403300916, 18283244229745029067, 8462159792484018099, 3056576498976014760}, + {7259283167233712785, 12530251965039903998, 10232104933720625111, 14190745998092156987}, + }, + { + {15759362035410895911, 16075598437961371531, 4651513528876405575, 7694151626503869614}, + {14468862724637972284, 1838601521755586245, 4168957446435305706, 8694905613027663664}, + }, + { + {14825552838983151434, 8639609968952840931, 15547914584352392016, 2313507499500708287}, + {6902543375698033684, 9987468886016348918, 9068175779860656258, 6899641689193116297}, + }, + { + {7449110402827616954, 5689206471789540768, 12722069021950813669, 16017131401246233663}, + {2240977975275954837, 4794705713606614946, 5734937900461809607, 118285984764445639}, + }, + { + {13917685647531721740, 2432096911145792817, 17733637484624159521, 3848601825403209903}, + {8192433211051054683, 17388066421914150767, 14336306308847565282, 7501625553608785022}, + }, + }, + { + { + {9194523390605857831, 2335161171394626054, 12290490336543843159, 12464172604156286188}, + {15842196578033029974, 9081285134201585379, 6123406461662038242, 5504260508195082396}, + }, + { + {9599159247384506427, 13011559959971256245, 6331802547989957841, 2642320882309956905}, + {9140255367820630480, 6883541786494880896, 9560822438260750771, 9273862677291701694}, + }, + { + {12578940088863451089, 4698579870843180556, 13634180401794570924, 15763130743395284022}, + {7444441842547931942, 4944622454458561492, 9589156490791486440, 14762328488235724618}, + }, + { + {6185067974942684922, 6452325785873503452, 15247257292915812252, 3689324664200339196}, + {3264129576054154137, 14977721630214750038, 10720913377937894256, 15914487080763816378}, + }, + { + {8926126498606164569, 12956394005759769716, 16902149488499586013, 7841840983349613625}, + {10587053251468526108, 696362153501209498, 9784750880259098186, 1207696323194229080}, + }, + { + {6366297849225708271, 1653728037493780302, 924103820671018926, 2050213326049184692}, + {5527413390519421127, 129805527414320490, 11550889572378802302, 15667992622431666977}, + }, + { + {3759028419971240833, 201899490644698259, 16787882148977818573, 3755266958958128460}, + {16997526157701685291, 6920710029293447897, 14077301651040071328, 10880144992445166875}, + }, + { + {5498621600689515064, 11498885804037952971, 12697073118321478539, 13999008478737234463}, + {4324885099420360642, 14021182496192299466, 10763088992583373843, 12898585157666243299}, + }, + { + {9367059860785010847, 15787147891143727655, 2519720658767337732, 11593809545681651942}, + {11966083811953753216, 12761111316475086277, 5681625861426437827, 15920587591610358813}, + }, + { + {390729441391219522, 16780558466241830343, 1374488446906327562, 10865131913700232628}, + {10115076211715532468, 18184016780675566832, 8365356477197603014, 672096097598251136}, + }, + { + {2393424067712509928, 16879911507754196299, 6441307574161100589, 2818743579517374412}, + {7083174841445248189, 3410683030590349702, 14697584027599531676, 8328975445543175696}, + }, + { + {11622402383521841588, 18271726976204770291, 4805501248621435402, 13483122453682180759}, + {9288143526654965614, 4688427612851085031, 3280806057528512375, 2249349779106893174}, + }, + { + {6807440366000180651, 16399452121226315247, 5098169947999459087, 3558234272787006753}, + {1792969085845015294, 5524357634740353242, 9429244535996516945, 3937357214017147760}, + }, + { + {15504868609044485967, 6752328153557303622, 3778610801922734369, 13830970685441980645}, + {8715733351182855585, 13970559751738714496, 11410776131378170826, 5487441016062951646}, + }, + { + {13162254303511925286, 1500183854026947752, 6344593292969383689, 13968537166293685529}, + {3100593991852309751, 464141462036312207, 5107705843278430088, 1965835506583809167}, + }, + }, + { + { + {12081034000518110752, 2773740877021737013, 6429475399936543899, 6804412599792308979}, + {16082860502313571182, 10013838454082912732, 7176778953927883654, 8065751639278576331}, + }, + { + {17741525051518363144, 1374267330336191942, 4677891169679898540, 9639823611685431337}, + {5482431056894095950, 6629146695374718376, 3884574854221819712, 13266790928096813258}, + }, + { + {17505459029376928465, 14087658194607915364, 12240552390931686885, 1809009366037859941}, + {9468395484396723291, 9446052656478984520, 3720796795453397330, 18035355127900871187}, + }, + { + {18221138344920380175, 16761112742545021198, 14421639991115588619, 9419167563943683547}, + {6237248361283446238, 889754338720059891, 2289880386545166424, 4280148734121099084}, + }, + { + {5259165122317589354, 6306061166879114159, 2622163270351284906, 15212813592118086979}, + {11497359168652342849, 7085380391293263482, 11799059272489792659, 4912160901181298022}, + }, + { + {10512473611770099290, 11735037909076331019, 2922606398008539984, 2599799834378751770}, + {10226702495047936424, 6109026252412854338, 15572556822827169237, 11993701786788749663}, + }, + { + {5106897453764491321, 10540479232768400094, 3938246597140945859, 13156157265138481529}, + {4932443191001849637, 11374218582626530502, 2907557293167002437, 6807344711257391317}, + }, + { + {3993197157612782947, 14810882170056329119, 3476738916713041107, 1512933700383846542}, + {17820889751141311776, 9132720567660500233, 17598924894608972696, 9704537908665702455}, + }, + { + {12121941964759747109, 161674837074510172, 2599887134944602725, 10582301831176576187}, + {17746858667522793487, 10735346620578591475, 90382511151212475, 8756617880518165297}, + }, + { + {13269854730742674802, 16128423099443070808, 3557230428644480193, 9637953317416090984}, + {6295039911768726240, 7019479692290635445, 11667616931857432446, 7159479331923350611}, + }, + { + {14416651741118525418, 10180867452897498870, 5073925566889872021, 17399294023945814271}, + {2042657564518230341, 3364886656428812718, 6324877312192616572, 12778324589036538810}, + }, + { + {10574237360751578123, 5116798422805306054, 14491722292795290218, 10799156134310323684}, + {12689926633011134844, 2658342468671191169, 15293758403109373386, 16248058473163364262}, + }, + { + {17412396133163580666, 6474892296180387693, 3334160446575187305, 12749216946172573968}, + {18160154520597666127, 8818156595950176943, 16077267238396508593, 12651459389529897136}, + }, + { + {7837268594975894598, 3733413917041538879, 9408433334074005916, 9807113299110084489}, + {673053561909802023, 10235823672366472244, 9197803481286702511, 5670973022205283920}, + }, + { + {4435804333677545569, 12530066828083700918, 14652119799285589695, 7610189145859517535}, + {16049951379406478991, 1895939661259683634, 10886955028200106760, 10575752015672416378}, + }, + }, + { + { + {7454214833719424418, 2128900810399984335, 8254953962723841408, 5341529923812819418}, + {11486532916552139238, 4528331821405917357, 5048485034448492541, 4189495710753944825}, + }, + { + {9223539587116638677, 879142711399260546, 2878829560233905572, 13081522393987952773}, + {3067261963348061547, 16008150780594711643, 5466468631453287640, 16659147898971349582}, + }, + { + {8047766502132608624, 8715815570878148809, 9093649079884580138, 3437267783531715968}, + {17562225708466062266, 3512667182749067601, 9223059995161026858, 1366690634827047376}, + }, + { + {17929132376737482163, 5565926714491294456, 5252303555134107501, 8169975563698132305}, + {1829326230943509100, 13780918661853274468, 17736665596871232627, 4246797342334307384}, + }, + { + {5113556452592134569, 7304867793218750141, 6016631926489320290, 16471860203547627727}, + {3444471410714850041, 16571738096215232488, 2003912224952639024, 4203884000388032492}, + }, + { + {16858425223672505353, 3192567884201479579, 1688923188642613263, 4159042130811153987}, + {14900413503869744297, 7521485042788722327, 14038093805562042641, 14713051866364662650}, + }, + { + {3738774192924465076, 14037618828827556145, 12882915396530927286, 10882862194263941815}, + {13115222579444494605, 18244214260845794346, 17217867059738274194, 2458870331386500577}, + }, + { + {8768788172344064509, 2761897497254272960, 1400167175024837359, 2591319596670212133}, + {1499652044223484974, 6820326453941021707, 9701009499879906773, 6897435972338565418}, + }, + { + {8314355711464256163, 8435944020779763783, 1814803522962187872, 1875253356755380905}, + {8214588085484192137, 18062045700553127821, 6649947905482043494, 3119726140944397531}, + }, + { + {11881571666857493523, 6300786026612414187, 4928573492087752294, 18343550313462089203}, + {6770642120472453960, 11296815027803718740, 17312916793783562794, 13028515123652649961}, + }, + { + {583508939637547757, 3195115082527873085, 8497784022800549923, 15135719419829981016}, + {1180291993378114150, 5447281494912347899, 4710517655176242215, 606503081693490000}, + }, + { + {17732293765863716052, 853971165248416821, 2022886284923413326, 7522564752651732633}, + {1417954193520965954, 5046659528429172066, 11426939225844711305, 17687206690616539318}, + }, + { + {6518552374736169438, 7940416740434530770, 15228615103587329007, 10662504584317997513}, + {18370800756791469891, 5564085264882124489, 51043856061444814, 11996026931884728651}, + }, + { + {7009195269496826002, 18330778751427846129, 7903886241001925539, 8198930484643879628}, + {5453546027419466587, 10378692433982210944, 2242412603379120569, 14762161396393277464}, + }, + { + {6146718865488327808, 8559779132928137805, 14001994895150170346, 9915701789711858841}, + {17119408219089522083, 4345363585985782988, 7559492126634131602, 17074565022279033371}, + }, + }, + { + { + {9262509587234749312, 6377906816499461739, 15415592259881792841, 6113140067088447267}, + {17505803833889144731, 3922849788840338823, 6180172597177093790, 7272741317181956640}, + }, + { + {15620168851912893400, 13762314693487747007, 13577625382054330775, 4116976667540664996}, + {712200332640207605, 9098568002202933512, 8905476951567380032, 7075673514150314660}, + }, + { + {7724870937269356050, 12054277107553403808, 1881284905431205309, 14429595888039183277}, + {4176419490283315185, 803567059653412279, 12138878637145159139, 9651152331113389250}, + }, + { + {15811459837282651008, 4038049993244767161, 9054218236388056577, 10807376403937048775}, + {11113869110590438959, 10336442539492421506, 9228056645601479672, 2983388754829658480}, + }, + { + {5272549712777700740, 3890998652469537324, 2338530655383446899, 13889100994494825258}, + {2605827345546331653, 1946537408424111099, 5960128674616374312, 2996461229050766944}, + }, + { + {9235630643187100528, 7874836741106774683, 1509645736063284557, 1291934408179243533}, + {2170879231846765016, 18243888082459973651, 266993053446290594, 4551583084211481457}, + }, + { + {7680050744092380106, 10728235076013009138, 5020205498410121740, 8174117988374987111}, + {15823303896577313648, 6268651341788131847, 16646239256422284672, 7277830349937654337}, + }, + { + {7189376137127712298, 9147574701720272724, 3983921661449444789, 12479790317447783959}, + {13221020976679959405, 13001868979553711359, 17918176319017234744, 18030393246529651080}, + }, + { + {1277346094474678251, 9498303380775859142, 5384923668452161486, 1780647986160100011}, + {8642790494747200341, 9734232043260261391, 5142834828615817260, 13851307413031336094}, + }, + { + {13856162196947802633, 8991033151317963811, 9758143338284799726, 16669930361261935141}, + {2769693485089420097, 14961618614592883242, 6027973048684521312, 339045855685213514}, + }, + { + {4705473345956039571, 17384553086897199761, 4490030246274451948, 1509996255726148943}, + {13542663230247432557, 15148026535112827520, 10014941605271261089, 5488071105468657298}, + }, + { + {13903368497828271814, 8050546449078305498, 6932373216915935575, 16010012759059004304}, + {15451708272653450375, 211711129247219149, 10435723642185827585, 17790507800712341232}, + }, + { + {11196283625212661460, 11223173364796389182, 15927254202510526683, 15939111530538795368}, + {3486548927974609940, 8233744837082586587, 7138041412908951164, 12863368836600604627}, + }, + { + {587498550288996803, 9937849083717302378, 17460580580397185843, 16850270092759302710}, + {8661654791709545973, 2350686583325065432, 14816283856648791595, 13021196930055398267}, + }, + { + {9641099975481205848, 5936405208377074167, 16926315209235053832, 9612898534540818137}, + {17782980290875306043, 4118599702370009503, 5379494204096737612, 10529123509904334042}, + }, + }, + } + + @(private,rodata) + Gen_Multiply_Table_p256r1_lo := [32][15]Affine_Point_p256r1 { + { + { + {17511864284462479051, 4391315454785363822, 16633389246499252566, 4290325975494843430}, + {15912670649662225191, 14172733821603328367, 12709802627494541709, 9648238681838878635}, + }, + { + {12840624483048662115, 13614226123606379619, 15087571995173849344, 1395488309690794621}, + {7173958427217959878, 1198561064176820332, 16821886260165681626, 10019479169661217935}, + }, + { + {9901328250515532535, 12796305315632203942, 10819069447660403847, 12542238242508661240}, + {17077777737462854238, 4364294351375777648, 8335244153165894685, 8863541604979427311}, + }, + { + {11029520456752683158, 2297291237551781454, 7934683676555855479, 1563954733146546128}, + {2252805128528536255, 10523375695822939112, 4598652721256818062, 17493379105069761435}, + }, + { + {2747551692916263132, 3151123035150683281, 13938314333309683791, 11970864255483579560}, + {7894236725861110998, 10515613623232567716, 10445557830757066839, 11155097727742050955}, + }, + { + {9569762631377921701, 10341967309273270300, 4697570564829842013, 16684762125903667303}, + {5281929071085172097, 13027961546412671127, 18398764602992176314, 3872796039504642974}, + }, + { + {5035609627965208105, 6338722048255995169, 11594969687968475335, 5639340633771742838}, + {6928934109570365590, 11589609913085167707, 18353534295019770247, 6879412911232288750}, + }, + { + {10042008593756684008, 6713471518385846030, 10961845838926538977, 855334359173719954}, + {7598642325962297361, 18006511265377032901, 6844179774752820363, 248341098560552116}, + }, + { + {12797853895127133352, 17314687680589848148, 4801569699821499927, 9711604734594547217}, + {8212610645535363590, 17221681508724305642, 11398663136094709935, 14918164175449979798}, + }, + { + {14940688064094792027, 10874356086032303420, 9942334156288812894, 18314945846365913248}, + {2026773265909278528, 13079907189666226787, 2413436844382479762, 17172916412715413729}, + }, + { + {6906211734178583215, 2568977141255648055, 12122130143181371713, 828440041422552532}, + {9361946962651414191, 8982763378443381215, 13842936470438971226, 14726899303190381422}, + }, + { + {15233793159839573220, 7091365221489488397, 7026505041428577564, 7614138360854053029}, + {5906758210005848219, 18266182645583974519, 15465977441750183309, 15365799046100584430}, + }, + { + {5523310814149808824, 11103439607538154330, 10292039577546071548, 1169663949743807030}, + {902203905701917473, 12346725749938989079, 17633270407605278415, 6960688675023695455}, + }, + { + {4505161139988645144, 10689463780805884897, 9379083335142738351, 1333253488693735633}, + {16044931735888519844, 16145584549427855743, 15405407720239538978, 11239573776554839202}, + }, + { + {6975554318981968975, 15982286720404911512, 1685931425716796252, 17715405440768877495}, + {4827607732096558544, 6375626601740689475, 3502039151843227915, 12085565714635174559}, + }, + }, + { + { + {1190044221726873109, 732025666411072563, 7781096808432277694, 13079879637655900365}, + {9048680577986693793, 12528346194104542124, 10575369576322629835, 14068913038053465964}, + }, + { + {3297775431071502652, 7947266993949467566, 6161673381820779563, 10604626734847205996}, + {17669018066064502925, 2386071939136502354, 1076023928806956187, 16075459682742916440}, + }, + { + {12387028018538599950, 5791681577936683396, 7536922194386052138, 15377770247350254336}, + {6564316170002440575, 10629371267149545956, 16125760269901494382, 16051398044897962024}, + }, + { + {6237354803374899565, 1782400080026955610, 16115027077529639342, 17907259814836219524}, + {13179234383592426160, 7302978467158243198, 13607720993463749225, 6693531817169120736}, + }, + { + {9659467198848065929, 13765104107473534739, 820057324758632016, 16604163594878267405}, + {15321524555426147294, 14524167419333362957, 157291234996957911, 3689488130722730671}, + }, + { + {13896531645245568605, 13598412639648980920, 3875086557856143664, 9242105512956135595}, + {17410265178284161091, 14904754836127450463, 2354327747158525902, 3858493849578874654}, + }, + { + {17288438225198818690, 15275190140700748774, 14532856272428522409, 2192294551011758591}, + {4275966798014984695, 13252812474545742114, 8604705074440591847, 504054699541924162}, + }, + { + {3623027910997185067, 15957466839356832933, 3504133700071704955, 4135728439139397021}, + {1160600455691338871, 4431928072859292239, 1542956305318065546, 14109181184369694855}, + }, + { + {9135041378474229537, 15626265487594878380, 2645257479784082878, 8105679948445763432}, + {8579715781576202730, 13437359533149316300, 4344754720520585005, 13326372852934103673}, + }, + { + {11341622086474305983, 17104958945811183278, 8154944722722765678, 6696975609844549775}, + {10895966360082878017, 2277686037575837054, 12236842881540344526, 2086470279064067791}, + }, + { + {2942668817124399651, 11439025398519255779, 17477264434671471242, 9606507094132585461}, + {1771475584689465869, 10791261379080046759, 12901998265727968789, 16423426725595035468}, + }, + { + {555419805011031621, 13715683285513290290, 15526654591995532751, 7023761423093873354}, + {15093366433178982304, 8625749648874372840, 6412297471587129206, 12161114204724955762}, + }, + { + {9362623422820895267, 6491356159483508885, 8543224082493101588, 17290929683278258587}, + {17348088672546490894, 3323350644823701753, 398525379151271104, 17794417664139368677}, + }, + { + {5880914635028486784, 2898124605786107494, 7953506026198179840, 2189477357380899574}, + {11207122442953694293, 9288539232660208671, 13527697625010979453, 448462453367651162}, + }, + { + {11262205719433170585, 7539606872920196479, 492385789142086954, 16036594120332851267}, + {8084547797138041354, 10063336189771527714, 2484395715469739911, 4879298610504146231}, + }, + }, + { + { + {10457697409306668434, 7830477435299250296, 7772379952622394912, 6109610138112185532}, + {4382803614711332911, 286231563340803504, 14408860285425706036, 9445290615796219321}, + }, + { + {8838210194055479741, 16190279688839291456, 16520121358582757556, 16768959728701970634}, + {17279896910204983538, 3582816187015369256, 372137484481226748, 12972230207718993241}, + }, + { + {5372953569411270487, 17808033035436856194, 18122397266105109983, 7100719381161799491}, + {14789750485957107776, 7797117101197801156, 3512936690589352328, 17020065099624467120}, + }, + { + {11480031272463364121, 2525856087688686375, 5875255653057452580, 5606696614467440464}, + {12094715534218447962, 6173479337351577758, 18244015404482482803, 13199349349511499695}, + }, + { + {15137716704658930971, 10986987873306909694, 1939043496821343401, 831824210330752494}, + {1056638569496361761, 1714583153436391847, 5183439003162975519, 1665087783666164342}, + }, + { + {8618628902870211609, 18064648431799903596, 7274877928823092285, 5660734703123876155}, + {17178150811821260605, 5485275535084805985, 12607767610318589165, 2215859519135800862}, + }, + { + {14525253431314563485, 18061438239992695424, 3753059877845742067, 6434164734885086330}, + {7925955539869645215, 5236273722884803492, 17135463959633855728, 1885217581414238490}, + }, + { + {6097225965006328457, 2630336000831717722, 7049638698786526134, 4203465038263485233}, + {4677974565964393904, 16044036678123636261, 7266049959100300634, 11339674070148504929}, + }, + { + {8932509163442546090, 15088719838810504543, 16380598316811388529, 11816509227456545305}, + {16117098651837966507, 6506253137957995237, 7842840841723336777, 14854630695614255489}, + }, + { + {13319400996902371533, 7582870533150862327, 3853021819016824068, 1553148791440569506}, + {1383156799113954152, 15192818247458559870, 16096167687117464686, 6356494963887209448}, + }, + { + {16159738883836847557, 12797888767862801410, 14516904553705186948, 13070086184381080434}, + {916885380224317954, 9486576895096666538, 2320292919516422975, 5019772534786350963}, + }, + { + {1979992348876614621, 7494083465935166973, 16035723662722831744, 6820849908885211777}, + {16740735239901023053, 2017530162004533409, 3087262288875984227, 9072904925376793991}, + }, + { + {11716934526135332476, 433379719600995157, 14981324743710487461, 16580162143428931768}, + {17678216037230646787, 2252837520490636634, 15914299694597684738, 15253999728204986937}, + }, + { + {15673599333229961794, 8862902775863712472, 7565222536246787763, 6724910605061440481}, + {5835390808530098179, 9647776340035782792, 1038074137838521743, 3352456378381259564}, + }, + { + {13166325906224116930, 10408481058915151795, 13583679214409957982, 13238337156927685694}, + {16088785436819834700, 15860660615594092228, 6472158593272826810, 15600310172166391652}, + }, + }, + { + { + {16375505785562641226, 4903074653735993511, 10355787845763031761, 3188849033041803587}, + {3145147452182864049, 13878747873108378466, 2798650520315922121, 2325962694441538199}, + }, + { + {11530583608023224967, 15979155166527001287, 592931868138800645, 5361781029549479856}, + {11246418752830406096, 11882251984248471436, 12026389461944629423, 12289077922798223820}, + }, + { + {1328339467113622233, 13374824154992864223, 12057132015324007824, 8507647484414695512}, + {9286016370798146986, 9083798709648036612, 4312959727577073260, 3732271624824420608}, + }, + { + {14129872794455315922, 16354810591314135702, 3177417010197743958, 16494351130927698692}, + {16557765056328447818, 3139394196704738651, 16891813998271303650, 7374470997276173905}, + }, + { + {1547814412223404746, 14194709348405912167, 15771028929623393801, 10945048172868684389}, + {11234483878611528405, 9542605377580701681, 4555391547268120796, 14916872217451960022}, + }, + { + {15490131882364039637, 5140304620645573547, 9403655757498826823, 9824850954989176893}, + {6366139388903157264, 1981838834216345294, 14659870286877979556, 12091578124492612524}, + }, + { + {6832171775190531128, 7903951882621813138, 13717573220828409267, 15400575122727850054}, + {6101307565293576434, 17226772767105983314, 3485283905347036760, 18439321272895583847}, + }, + { + {6289130721434350290, 16129337673129720846, 6648351866142453445, 7705983837166554199}, + {8120136556582544814, 7924417299222764443, 7821995671300500892, 17697662726179084739}, + }, + { + {6669506511185916061, 7036555931205961476, 15471324228012955656, 1075869467462424743}, + {14834182808856841386, 9481869408708862398, 193651363902981365, 3496053494343565969}, + }, + { + {15198290782478916101, 16205293865829644684, 2104596565474767471, 7783918193658109501}, + {1567469099169331732, 11324634977690198924, 1374141643017900909, 18368642394438425630}, + }, + { + {13389638006727712302, 17518324493263447682, 13178832200681259657, 8955667391164524441}, + {9331759525815425703, 12920722511913101049, 15807602761711044426, 17873219821625976662}, + }, + { + {12103811390374960600, 2801185238127939998, 16289223959107648345, 17243660994858386104}, + {14818957729322960498, 10018491794651971206, 5502065678180783560, 4158378425043433526}, + }, + { + {10278921174996593635, 4630624563386647486, 11179643216044347020, 8701826069861381281}, + {5839989039471676569, 3060138177923841885, 11279648082143612852, 15207786733412131883}, + }, + { + {18277950978951138342, 2577918906618404946, 11684553042740786163, 3082582313241836872}, + {5222056779189126973, 7794579876203167869, 8527673475629739407, 9851790541007784515}, + }, + { + {671618501514350673, 3455246317052893537, 18161533457452722900, 8968434886308785175}, + {8445049055511813064, 16897132794064300993, 14420937999674600470, 11110627336577683437}, + }, + }, + { + { + {11535283160083833975, 15102917952496589829, 12909095696891909745, 4611119212602854744}, + {4195756524232932570, 3754603965149529000, 11539276962358607816, 4401424391553230481}, + }, + { + {6842993463058627120, 2708745114617181146, 3832382691810282630, 10333834458057320812}, + {15028197197004077388, 7681293343255119354, 16227537691626587485, 6703363869832495607}, + }, + { + {17567108285065737529, 8693245930330183070, 4025672038042952121, 3491067119247522844}, + {2100799837993193702, 9579542950705774054, 5091525285265581997, 1806757015709820088}, + }, + { + {7757354840118131559, 16227348978414023262, 5800861674805516343, 16486235803248700961}, + {15646700163023677309, 504258765210816549, 13724147899924699697, 13588899538317277096}, + }, + { + {15895596198730294923, 12513494396374459899, 13552575153453342654, 11312160635199213507}, + {12446618129881485796, 11286186116805515445, 1584191291800429567, 10188741008566636830}, + }, + { + {10157626021970320469, 6580688164585715207, 17158416694471177787, 2873484006255074946}, + {14852216457444863041, 7463041347566136496, 2190030775722958628, 1116223035803602728}, + }, + { + {8598875756176012541, 2146658618778432566, 17575736667490551813, 3602654209723135985}, + {7223347129734689099, 7256921024940026570, 12249118963297692963, 18168532365040819099}, + }, + { + {7585174044375463988, 2491923406404093282, 9355733262044036112, 11484079611349577325}, + {13145030009254943291, 1234932884591406048, 479845670619308618, 87735010308690865}, + }, + { + {17307641427543377277, 5862898330718319545, 485176909118483750, 9845223919324484076}, + {4293549583740204024, 12765124043303931186, 17870894781132657382, 6508172378961793849}, + }, + { + {14234156373312856400, 16210939788814051708, 6478880037923038392, 10435512103812909561}, + {18142844321802359753, 3243996803126554757, 395603619159523019, 10213589535656704607}, + }, + { + {13256075137060741204, 991285459654295161, 7857174835799942102, 16201105040554625727}, + {18398612085349994216, 4512860776717176840, 3521452275695011919, 10622137733045360311}, + }, + { + {14993897771652736376, 3320388672992783302, 18421556740970114213, 7438967127794745135}, + {15048397725789819354, 12721899159423777001, 1135125102123667189, 6637485660805148630}, + }, + { + {205606553319362431, 15484041062449893984, 12896720585684759529, 16675624014916513672}, + {7579112430564108390, 4602460356900251082, 2677787525524280838, 16723483619407414479}, + }, + { + {17981939084373319995, 3989926231875116241, 15342509934701840045, 12999252495311233519}, + {15389919024942778009, 6136335679373143315, 4117381415379544275, 13342256463740646775}, + }, + { + {7622769999043907199, 15227992053145045634, 2719412067263856950, 17811161335980566241}, + {15036003689029442301, 4919601685231030712, 6756893600905532338, 18029567067112075531}, + }, + }, + { + { + {8492025373682814159, 9341562763134230960, 10104358220305514878, 17545404790574939459}, + {15737064134098795026, 3880597485411313924, 388663918823974597, 15032915458906101183}, + }, + { + {9452334891928331309, 15207477416486363718, 8081596400773698461, 7528187414539292243}, + {4773782664413845594, 9435822414884353799, 2722451711480791323, 13642248100035410269}, + }, + { + {14202843175914986568, 9421566354325954710, 8667368258699634314, 8733557788892402517}, + {331451278037425751, 1109013653863287548, 8802742738207038150, 4667769857523050796}, + }, + { + {16570512961992288509, 15784840936011612960, 17797638261217375128, 10589124475671334830}, + {16848440972121709899, 697679021479737566, 1456738239410270672, 7214966028857473701}, + }, + { + {13782421991242364698, 14661156263311647121, 4726455119103158850, 5026680986111581594}, + {15610213195880130268, 13703306863846075517, 1371700218221235399, 16792392307217237043}, + }, + { + {3250188629442787152, 2728518744775098354, 3140694818026767341, 17566141747707001105}, + {9569291890730505101, 4439949820491175035, 13751802166620923317, 6602549032413906269}, + }, + { + {1067242659333881602, 11852011445832610026, 10644339539182752718, 15519552867360295119}, + {8817864336906465495, 8844034637292547409, 8850766994595652906, 5299330403389585218}, + }, + { + {11434157439953722433, 9090860151661100670, 8407869262026581159, 17882547383849407986}, + {5277257988019769029, 11463853580825342183, 13607489835500075467, 16878800997498950751}, + }, + { + {11526703690786988415, 6919770449526881259, 6713486711636442468, 14697284704991333147}, + {5405738839499060129, 4737011393825878948, 8707677918280383477, 16881185094380241198}, + }, + { + {9056014389564242176, 13179419520216397988, 9815298409700670396, 15302091100015307530}, + {12552178314548371153, 3975519917079954227, 17211203317279781814, 17755252427177154090}, + }, + { + {14056502343958951437, 9570378325961888046, 18335930130582329417, 12188057598786655680}, + {605832426765150582, 15265028749599155713, 4881763628803375168, 425422732543303669}, + }, + { + {16059297404709367406, 8426877510924536482, 15269952608796785555, 6256768900860981984}, + {13142655793714702073, 14566340391957173918, 17147065283704191109, 879106195264399}, + }, + { + {14152733561556558931, 6788431167332998309, 2303657738205239031, 12712406085467592411}, + {1740483284496903693, 7206807366776489586, 13420608648010812358, 9180900918550128115}, + }, + { + {7193311017682954852, 7916342489073401148, 7990830552202175554, 15066065171478273830}, + {15601436495559985484, 11056245839590890541, 15963012082312968312, 7270947051909344657}, + }, + { + {5010740583028703301, 15413348048560455978, 2028314374959411194, 16685660750422250777}, + {14284468905357216559, 13715859397068327775, 400943255937053645, 15390787503961331119}, + }, + }, + { + { + {2707032230021934480, 14943945588296447659, 13333962501998857701, 10603744732015256400}, + {3386903941135274495, 8507451908469049716, 9231176235773710950, 995464562185179329}, + }, + { + {1497127512412966214, 11292269970549257426, 13920714718237672232, 1363993524078475237}, + {3687544717271789391, 14097532154250414203, 8367320351336033564, 11089672460564007700}, + }, + { + {16993953276024768829, 12025590727803527383, 2672535181364381995, 2183111709986676538}, + {14822521615475063339, 10618745739454592027, 9957515072444869664, 4797521918890127374}, + }, + { + {18097777493026370528, 398882723487597643, 10462164796529820357, 7704526739683689547}, + {12438059168025171393, 8163001730991802064, 3319372757738711275, 11518015261707325261}, + }, + { + {7809927122217534998, 6003738786706135597, 16541272992243715653, 11352602417510156921}, + {6070703545889058045, 3742828100079104877, 9416263310824977145, 1406892456840131842}, + }, + { + {4005088727670892586, 10215872293486093012, 7634075494800881158, 7707144163086802537}, + {7085702388211248163, 12168208652772836726, 16347414703478252736, 9386623607672009940}, + }, + { + {16530167766100505402, 14672843572926881623, 10752276706209340624, 6888427606311779724}, + {9060900993058482991, 10439396339124215720, 17640982730425880863, 12916411341252677116}, + }, + { + {11776245660806714247, 18129100488268011560, 15389929343761297429, 14544292652959164154}, + {18063319363114104433, 13433144948667100183, 462314076175867487, 1862686058702915115}, + }, + { + {17306422602774323327, 17272002328208118653, 9314885036861009829, 7485631191912561636}, + {1933835651414138452, 15231897024969540970, 507247317572839552, 10741595984991150047}, + }, + { + {18297797979313130180, 16976628082093243813, 13059060093619519046, 6865085966096869228}, + {15021840537243000183, 17843637254308940381, 13122764022765250336, 12556030904692962295}, + }, + { + {11175787671000337381, 17757097628648374409, 13408571223487217321, 2720103532070247452}, + {3237822932023459208, 10155101091021157316, 13910068101949253623, 648579517754264097}, + }, + { + {16597587101652675879, 3941450686064909756, 17635514250964078220, 13107347044039852240}, + {8910347370050088758, 3114023981351548745, 5209360756412143979, 8990623441581200588}, + }, + { + {7692284195082081732, 15977071788000084350, 3594719301791478282, 16545490512039598136}, + {7629535887569375952, 3241949087900065139, 170526822997903747, 3422990592513330514}, + }, + { + {5473399325468482480, 2511351254139828397, 1124856552206019504, 210074180589003934}, + {9693298849967626723, 16185054013081266938, 16070865229793723400, 734500463998096984}, + }, + { + {4895849847827915947, 15252720925614851036, 5944268852782996266, 8171510665067151601}, + {10594809041696466609, 4377920841124876663, 3816206760439007336, 17150624011379500381}, + }, + }, + { + { + {6266830413981331818, 10890859480409122410, 738708598357264321, 9241173142142102299}, + {9152169484987657321, 12122430118903337055, 14270062735458703743, 13877635605034675649}, + }, + { + {4572419849863661964, 16330741525817240677, 5456771007607263420, 8798510164381810403}, + {16547183593064549865, 11355135595370359779, 17581910791451710925, 11684604415749005488}, + }, + { + {2766130068233451740, 15909689412657372214, 3272828023364980896, 12907534005596438003}, + {7065629942275705493, 10609982651084321649, 17330343421617897811, 1746246157222856918}, + }, + { + {13168953859078137190, 9072500190247791267, 11090199374278127099, 3503847851309060744}, + {14395788825673846582, 15073993563711333791, 12879874391706003251, 15417028700542288171}, + }, + { + {2686132933630431595, 334448852204016400, 5636563341880055087, 3897420469445246068}, + {10569177829735084588, 8244586887721364305, 17973493209847502315, 18083956436923498083}, + }, + { + {15514509130323617046, 9833490355170899102, 12028021566105512521, 6349458533674010018}, + {13470024118569549588, 7867188201997717819, 6110792121234766402, 9917858515766574695}, + }, + { + {8273062939911446888, 1936638151089648185, 44602505720759914, 7839132833110815763}, + {13045756168264521992, 5375972549477973022, 16964151563535745964, 2871770426902555432}, + }, + { + {14164643693563803212, 6386904235704679249, 931435629437735510, 4496152555914735639}, + {820099532545743339, 13419988718062417698, 8948965620484833159, 7238410427920554862}, + }, + { + {4387941928212462673, 8023190031094282215, 12322462122895470016, 17311901330042910195}, + {16445894183838823370, 690424095855074674, 12820742226551488738, 227935274674223825}, + }, + { + {17437729542205914525, 8439533239207225162, 2862942422640746698, 7340866642549630610}, + {6770451500989398335, 17262212260581413381, 2156505157624055602, 12195119268846383898}, + }, + { + {13685370053507732180, 8304030489296890211, 7042719123662732989, 12115154796394040286}, + {10496877583013829980, 8909625177349683785, 5268451666475070682, 8910488385056259560}, + }, + { + {8874918984373509240, 6652428549855789281, 14866714872885601270, 12093494664302554643}, + {10149999253136441007, 1611873554177023520, 10271627298853910516, 15171882630355491729}, + }, + { + {17085353800722834618, 3271271583189511718, 9338466116389304614, 4685545953421459012}, + {5059702655119414343, 201476627889215522, 6388612869673101372, 8357217932305360896}, + }, + { + {1836621694151238424, 11438765101326043062, 5537182303007083642, 2657011195641217678}, + {15370176245454161308, 1478361893117141052, 8729368992402422055, 4807782542738120272}, + }, + { + {5084555197036037383, 500829604818691390, 8128181767026348964, 17895639808733462562}, + {4138748420878083709, 267892430674902987, 8954358455330696651, 1946224964877667668}, + }, + }, + { + { + {17561670470565298976, 9524122142014309347, 12619871254022879995, 4098610542031538614}, + {8338691110372464881, 4378598564044777665, 16435680634249352743, 12067828180476756532}, + }, + { + {12574920924242276218, 18146097977073890534, 18281543194137545725, 4432773597060264867}, + {797962164984225968, 13432184750641235201, 12394976215803938078, 3054137600383896411}, + }, + { + {12910897300898239001, 14116919300756610521, 9737100313909655285, 8792063194563201934}, + {924297264228895146, 975866810375743708, 14953819883516375119, 9992561966868201517}, + }, + { + {18270562314314829224, 17574550722906577917, 15522987576586641271, 4200899284963891561}, + {15719788437321868967, 18390235318178988753, 17371818886753265385, 4583380351670429228}, + }, + { + {11290716045321163897, 423611636875887759, 8716385793549629027, 8029377844845093468}, + {16573848460451650185, 15094868140191104543, 14624483608434776103, 9086586764934160662}, + }, + { + {1320522168839874087, 6395673054871725696, 7793960979093413321, 11402054451286901177}, + {17278080290632229040, 3823680337747309837, 7840042035002848151, 17839593774203285281}, + }, + { + {10024545625018137606, 3780616370895328213, 1516632588067435378, 13846630703933575818}, + {14323905768888574358, 16062987352815864444, 13444338098535013457, 13400662018607341910}, + }, + { + {10102001197913431240, 6211688443233768420, 1986665099237206297, 9248907879269017005}, + {3081890249882755206, 7828527646248386813, 12676034092230326487, 14655968027461080131}, + }, + { + {3763532248936424432, 13507960710132312440, 2003243330622949364, 8723351916784911918}, + {17411870179533482591, 495549359712213584, 6958432541445845486, 7674356092204128350}, + }, + { + {11814337248412299972, 9347461245743305200, 15456560932072269534, 9579754357941936175}, + {2098168907840746456, 2063921976437345588, 9267808714920405578, 6482702408130663270}, + }, + { + {3313415711246730386, 4607422129142883607, 278072683866121896, 830840258180061490}, + {16961959739026004139, 7896385585906900106, 7610238284391475173, 7231671772874233939}, + }, + { + {11464797300361906821, 1444449385286554508, 12433005157477847389, 964895564896662942}, + {8457290958728547067, 7044433897330872257, 12292673928275053405, 13679355097865192207}, + }, + { + {15352304695586484723, 1527883079108513336, 5890042963344522083, 13407971103520766077}, + {12385239629152188662, 315706510218287516, 5361117161753711484, 8824676525356150938}, + }, + { + {4555925933619499493, 14889603365479712329, 15898222225673484215, 878884802170861101}, + {430001626591485427, 881428142547721183, 653855015067704092, 11378990354467312809}, + }, + { + {10219225570653005145, 9205374019534090202, 16828986596058027743, 1089575570166892706}, + {3079144130112884386, 4682944567048139400, 7674497449298779575, 14137535283566239898}, + }, + }, + { + { + {13266892287530449189, 2232961926857263527, 5934654989155432442, 5415975493246016158}, + {17117784386882463158, 3875398271691758986, 15755743581177209843, 11380746535012415659}, + }, + { + {10162459499000477259, 7534168794800651527, 6320985751131807192, 9263840233901040421}, + {12178625283764017250, 13143797113231152006, 13089053551699608219, 13480464010111258056}, + }, + { + {11426681347395118622, 17135867298562042628, 10870734720453621112, 13803364322975322217}, + {9740527283062276630, 13765238480893165263, 4792349632705804116, 18359029140065847048}, + }, + { + {1420251412241033168, 6449255753238336368, 7468624722117319576, 5716072259994197219}, + {8165015263320602150, 4757529151848960259, 2040364517493350115, 11069642333484542749}, + }, + { + {9434687670958330812, 4808705744496679962, 13910334628239183613, 2628594509406050235}, + {10055911465166862298, 8069256921143792190, 11886968715847498191, 6351594160398684406}, + }, + { + {5472832021993175857, 6120966193470238758, 13156950075464061259, 14833372202848630444}, + {5760885723102571027, 18022572190906170343, 9870918995920897221, 9546055667466056471}, + }, + { + {17124591880405051324, 3379747334483646957, 2084957978131092947, 2413497199486596627}, + {2867893699156486423, 1357836849049583382, 13607307985344221035, 18039194570940763745}, + }, + { + {13230815692170010235, 10662664037814374845, 10120384214921531334, 8892863196093018212}, + {4443096401408136417, 1896901619181196514, 739574867683694091, 11233952771600927581}, + }, + { + {13885878918475208407, 18415131106660406656, 14362601436612948914, 5740711586144226035}, + {220574937152712384, 16774016249557318959, 4658351269477373440, 7890975779439252404}, + }, + { + {16628715286876183012, 5300385226682547206, 4493053153469218188, 6690552861098862065}, + {9359345201611660030, 17390357193161728482, 9283655448484665614, 13747647357786913441}, + }, + { + {3101241556869117917, 4731590937333975732, 8347709942856514723, 580858462407103829}, + {8937550160715031857, 563888416351720575, 6928865729903641398, 8295908905021542009}, + }, + { + {2219303446125808132, 7766409607764464233, 4492816761527421087, 1687012079818776091}, + {9967512906892097592, 8099397263797608226, 264054732854154094, 14515622825083967497}, + }, + { + {10586626338424063837, 11285305220583812031, 1552873676034063335, 7108571382532772330}, + {12077600502438115659, 4925647731241250576, 887903929602864140, 3575833277214438245}, + }, + { + {14685642695197717757, 4830460343095831969, 1748938116371486214, 3212377924501398108}, + {7575821759023381902, 4416593227203343304, 17810665332121047202, 5387420006905173437}, + }, + { + {8644732068940188724, 17116805484232699355, 6611042643736763845, 12686480611232016266}, + {13422256101258226329, 15901664205323922499, 100273141428472746, 3184681836469139902}, + }, + }, + { + { + {2754563581284692865, 11257360722362829387, 8254261291934606879, 10023569920325096229}, + {7980898855627864603, 17162063449612285703, 9275759455936104363, 15936804738099638644}, + }, + { + {303387668469489035, 7978391052264888020, 15413722057350324494, 508608987485166058}, + {5585753287556892522, 1344134516582665443, 15144279405777509214, 17014353449841567149}, + }, + { + {12518577022215294774, 11347384788122950558, 17122718824958020364, 5431993665805279177}, + {1445831254446028321, 9845654210244803480, 18315778529692612284, 930563922336183289}, + }, + { + {4894710987714215219, 15704993603878996107, 1606204036324478223, 14308635149530198932}, + {5026736228773269251, 2911689442372084137, 9004077539360196849, 7770049130277452000}, + }, + { + {2745120518194234905, 17255944807561408883, 7371907591838942770, 11781525288383871227}, + {7814952754785494862, 15022715213812536212, 4112388658963418656, 13703771908397991335}, + }, + { + {17455440140812341569, 16738670164475421762, 13259904130186215994, 2168106064304872507}, + {1969289843772256992, 9025317999701057831, 5835661391798891929, 3826587698101558069}, + }, + { + {9149648374608464235, 7248346993716635643, 17283919168525322365, 10107681064815728795}, + {12176813938029507719, 15110337574289033068, 2436453685316043712, 5876967059744625564}, + }, + { + {6197919059881189313, 3300993078638782623, 9357667752372201437, 17688129755135009447}, + {5477090746558113696, 12602024521188880300, 15889961935507293355, 7135039746373941272}, + }, + { + {12561063426893244305, 3079971284510744316, 15695857190375815873, 16730673956207425338}, + {12065477821845465116, 13846158368121919228, 2126156187526559500, 3005167441915916768}, + }, + { + {3858987859895327040, 17043903959888117395, 5861237635520080595, 3292646198413575902}, + {14286644557048422360, 14346409530388980974, 12583555046601155161, 4665981927428063991}, + }, + { + {7657686120974201842, 2388299767028319466, 17934808017791217639, 16708640707026372313}, + {14122341266134976486, 9547124998857374491, 11194069918436025923, 14657538980930727877}, + }, + { + {18115789712912297420, 6543740714573413570, 1955886376702349613, 14736853369719086334}, + {3914330395250768396, 7607848156418885173, 18220633528980056514, 11930952850158858930}, + }, + { + {17010681753474701341, 6961088634819162945, 18395881317121515295, 11611411242007267179}, + {7996717433149311639, 2687736005475404867, 15340214362731923149, 7116441414289074727}, + }, + { + {14302198697220662403, 11915041511943922518, 12363437164440173650, 4047410026894059083}, + {11439743031696133447, 8776097395071907030, 6851061783357383945, 16484733576581941012}, + }, + { + {2861660066704264713, 16453202148771053225, 10039035813504063627, 6275446616881871868}, + {7150609984920482782, 11100941755544354363, 6219760433202580646, 2875377482232912143}, + }, + }, + { + { + {15290817014272444879, 8012864091692295774, 7591940515496590516, 9299619125326026848}, + {7297256232167521068, 17861204372399797627, 3100022958796565106, 15313770879200204613}, + }, + { + {9902363248877274636, 15776195244792726061, 1935342462634574355, 16572507349421626602}, + {7503944294807242065, 7454248748618678609, 2837392985175901475, 16494567631149775512}, + }, + { + {7821919851875204434, 3437243050078433703, 16281279739393410040, 3105985403882097775}, + {6392071520880083076, 2042340026857542253, 2492719020444109453, 7325465357665053546}, + }, + { + {12299242278498309265, 117303082144788574, 18382936515565701803, 7941141688858846015}, + {14923823358299367958, 15681089039073030752, 16878721085421212785, 3933697483394042011}, + }, + { + {17669228922922186836, 6423621568318435743, 16298886067880336557, 11009276012664659704}, + {2934438101395245878, 7492928446481808311, 1311515713186855284, 4493146166488261630}, + }, + { + {14009653500169461120, 12982754496644678513, 14586034645437015762, 18126832542767444974}, + {627541781236454235, 3801503508930355635, 14654684147782092084, 4179096323459534629}, + }, + { + {14829342742512426992, 12453047655591346244, 13146459409240287380, 18077963306248855764}, + {17149389409735171474, 13591892902058002302, 13872587256559899629, 15878632005942819501}, + }, + { + {2878536922988449879, 8819365314325664735, 2696760638950720974, 11357179421800829605}, + {14730809809256560583, 16277258726425730599, 13189689275745970592, 13769784951430309444}, + }, + { + {14706229979050107962, 8679247682181027680, 9705538653507374238, 12793525936716723768}, + {10022723640772366793, 2224403391050849804, 11511158380587667232, 3250960576892370870}, + }, + { + {17671892277522139639, 1384260767972381005, 7623504419117295292, 11197930232971575240}, + {14867469242175831789, 897596747715880677, 3892483173599058531, 13453254609965163080}, + }, + { + {2690362926234343281, 12134546410412600166, 15715872358030533545, 18160163251393343275}, + {12233720002415141519, 556081697748597124, 1099809960955937522, 15489604457800724223}, + }, + { + {10292669945637125918, 13595563061674492799, 18301330068714272653, 16981073598172019270}, + {4022713583718555211, 847970754090163894, 12867993617169467387, 10021141621864633865}, + }, + { + {5408393826294570360, 16896935186698126584, 13028972412622343885, 7850626233281656805}, + {962076344521148275, 12332350290936839731, 1774588207039851940, 17877147526933423087}, + }, + { + {11625440764115934244, 17372224561416726989, 13457342366450471135, 1569549943944038472}, + {17753658357081801983, 14093490077993040859, 1282770820260996510, 16402793994329437670}, + }, + { + {13086054618104175873, 11714492854942191582, 1743587223054035136, 5474094059388998723}, + {13150833497051757606, 17129392131927259958, 5739140380294248045, 10239738807213437974}, + }, + }, + { + { + {3631886121917081375, 14286411187847401959, 1546298555066841633, 4790996540037176549}, + {9541492152219486842, 12304868498960755609, 11426775785781090329, 10793898029125361155}, + }, + { + {10932352970046201499, 5875690226460998551, 3699681560657289718, 8665743594825198441}, + {10232089728487302472, 15664572298733091969, 7267222702489958195, 10552093353886118696}, + }, + { + {4008236965647744142, 8547116629188387980, 13874587567755370880, 12696453513706541959}, + {10752386832421030566, 365775083075323708, 14295272684753058141, 11024897725724291722}, + }, + { + {2399232949134869057, 16408469118941953277, 17229778225562184411, 15990256768949242309}, + {10694906341686584836, 2816242351659628719, 10794163145486835660, 15601904974333104002}, + }, + { + {1158521281204350113, 6232098057848694897, 12517518152351190341, 17852831094628421272}, + {11653774695260269881, 4420518556213490728, 13835371272800239099, 12119809446886544909}, + }, + { + {5143546864201185527, 6400878864024957342, 15513803558106064076, 6712861984922181478}, + {15623960351786428150, 3094277713920675576, 6184647748693682810, 7857605928718754519}, + }, + { + {2219152199405421709, 5367881810186787185, 9606063680551349934, 18233690822105957780}, + {9941441403610160291, 14996958158691873775, 4936282940888570414, 16608409936766385729}, + }, + { + {13270099407878039596, 11569032926557804346, 7759575992876193458, 8239088820951102451}, + {9633607727685959064, 9775909232917811341, 12297921731498614906, 14756100221590046549}, + }, + { + {3076166255574886489, 5587891405059542759, 2449830540875545916, 15616237426524550707}, + {17820334717580127167, 11506219580693301288, 15242532286743473103, 3266057695402840388}, + }, + { + {7193168093115966016, 8050992763687139302, 9734357192061785185, 15553552690657851227}, + {4632257996795951659, 1007158456255834509, 17052740163052114844, 15619284827675470063}, + }, + { + {4224824291132201768, 5709863556852834901, 13539485156399791894, 10330250853413634451}, + {2817020820518906625, 14306724568884734914, 10421968182740721623, 6943068506740047695}, + }, + { + {10830476567180688368, 10003074695797360184, 5589380226277136479, 14952961630386717087}, + {6354514974022878533, 3426762794422332369, 17950815054280597743, 14940277403242978595}, + }, + { + {14582622177810553114, 2819236216667324430, 11333005326119114902, 15900677556115860419}, + {12265999577465855236, 14521351376076108710, 3999293994697120555, 2365385934872188434}, + }, + { + {1803647016552158312, 12981833819573589527, 11371133227762071, 8210800033974528109}, + {16927172347295306236, 11674533305143999306, 1514600283696801303, 17036724058500952986}, + }, + { + {15551380071341300893, 1378878534597097794, 16601031904934455368, 14515377519758777108}, + {7039813638645241317, 12524221355672362377, 10483072291636269482, 5711815649533531303}, + }, + }, + { + { + {9246769514475702626, 5788284997389507365, 15857897362850327403, 13864676801095094218}, + {12881526722328523267, 2620841421323221200, 12599981775316397124, 12820989846844560040}, + }, + { + {13066648645100247757, 16727492115601921665, 15749471761440498106, 937594351871983779}, + {8381111811209734349, 10884357918725639691, 781591570669492079, 12778743765298428266}, + }, + { + {1797915488494232282, 17274756142259274463, 14207994319179101777, 9405903752538915237}, + {9001743317941152797, 15048752608061590843, 4925745663463425863, 17143694017177138485}, + }, + { + {11613437975225156304, 8619196433402562266, 11907033287998837424, 5056904365610561965}, + {7637552956459333558, 2827449950719061527, 9998507085256853501, 9238562885525900325}, + }, + { + {13246436769495027717, 5445015753017977819, 16266739009580878036, 15566606095998238977}, + {12196078605380432771, 4854324313875295137, 10974170498288217052, 6425550765546527417}, + }, + { + {14574824159194628650, 16992289415800830701, 3499062703303067574, 11220872042664151226}, + {18135860701984580530, 13630928571014923388, 2913126838766947469, 15869180955632349704}, + }, + { + {10621010745328025245, 14637275395423748577, 12928463178963493980, 3270672471462681194}, + {11765440832075775157, 8138439106739837848, 10004644076263261924, 12582897670868871780}, + }, + { + {9605391611675301152, 14014632424042523224, 4638465078692570733, 3013469722048440965}, + {10972600060210514686, 4497572559400894366, 2652629676209366276, 15827846806499715082}, + }, + { + {216774559418075105, 7056732230404238374, 4342481467357759950, 16143194646968227790}, + {12304857685680249595, 5021239809847286634, 745754913624924064, 1603290801266214539}, + }, + { + {2784418922013631805, 3554650219010546629, 8896448905401216908, 13445015286698819482}, + {6508982623352460996, 3322529327934132311, 18417788670080975365, 17554108945303789353}, + }, + { + {17620122226715347133, 9738429733440215024, 15577771434516492888, 12422193389576942718}, + {18383756008252443605, 12736926759685644351, 16981429110294392086, 11999528928951986433}, + }, + { + {14489177617081844909, 15995916840320959685, 6361381313838994395, 11146176143708648759}, + {17190512001934479207, 8406914945663974955, 18073221191428103088, 14075266763636071788}, + }, + { + {11493260321718935244, 7134447477334726345, 10489281872281557152, 6145540581503915475}, + {4002857892747271740, 5167943945955725680, 2892864850826359384, 16887114279977647596}, + }, + { + {16493058314197913501, 14642843949567816202, 8421201635021034279, 3645913604138483317}, + {6127272877310948153, 3660286308390076870, 14343325047340052700, 5355450922054278073}, + }, + { + {8426383571761073988, 17627146217941553397, 7396223609641674418, 2402241526082789613}, + {4067059813672963823, 10306840429023537942, 18342506396531908477, 7249869764848707701}, + }, + }, + { + { + {13937553904380032591, 9165760362893872288, 14159606902675650669, 7794101517494576908}, + {11994596892880464164, 16211278212275417034, 1568324133241165712, 6579463633356173526}, + }, + { + {369660229032730089, 11851915833529805698, 13485269529443969890, 1270120511649175022}, + {9128783725626301238, 6173048611666804214, 14151404531169195672, 18241008099921643437}, + }, + { + {16331025972320545471, 6852381640421896437, 9324740413214863495, 15718339035381717722}, + {1521756232012903545, 5431459367124818841, 5364830919043042094, 11104748870982011750}, + }, + { + {16226789363155700046, 13734705589524056856, 9629995513492843231, 2636144377026081617}, + {1233405076007260313, 2119672919365858964, 4932766292290315579, 4185117177904214366}, + }, + { + {6556637108078954923, 854911879338322327, 17335608616262058670, 8212786550755149003}, + {8111194132924193031, 15689965289081013375, 16641361924274000294, 13131032775030004856}, + }, + { + {8653575060724839982, 11482527594744353256, 10837608928215660048, 3651629796762058243}, + {7098570919231943894, 16903422906687575782, 6449467519885582678, 14455694979526406871}, + }, + { + {781149662684377075, 9606778745577048892, 16642923833572014687, 6804945833779567806}, + {7749938807818369385, 4119995592971432914, 17172069782410404367, 11558710124840085255}, + }, + { + {16996170392430604056, 2476294162951949891, 6677439492116109133, 1649550562276235959}, + {7307278264575968221, 17128676264244010843, 9768062299436691373, 3825325732056225433}, + }, + { + {6593955722549970555, 17069122731812152854, 9033349482403834703, 17728559655579364768}, + {16586780540128534825, 13307658170018069777, 3129405955501687685, 11183053750385689524}, + }, + { + {396019325068553604, 11523268935121791712, 15099363117146465288, 15263791092270534216}, + {13442484747453660303, 9234120847672647934, 12419564747087042045, 11765927783051357577}, + }, + { + {6946885342337567475, 7614129273290805579, 5593360004251714058, 12661112521307810378}, + {3109170497657341517, 17179338146382046416, 10757457188650866858, 6777926602245453235}, + }, + { + {5861627228365499618, 5011684805137210454, 1579621475012951778, 11535371650014354624}, + {12847902922833318241, 4997014846790385136, 9875988184618650628, 13094082946822736823}, + }, + { + {2372542806512167707, 4770713673953713652, 14348746494327256696, 7497346441434630132}, + {8937635379675246570, 8485257033326447249, 9021969910533595955, 17083952234675640995}, + }, + { + {15253158548483712314, 10967825792345015198, 9742716807127259344, 14359543366972625129}, + {6622650705673586588, 10738437674137632549, 1628663686364470696, 6788821495127737255}, + }, + { + {10456049238997614164, 3762844951386993276, 489305084297229810, 1360312650067674972}, + {11869321173985817492, 5817931657599210177, 16741327479242559412, 1205037582258757668}, + }, + }, + { + { + {7109145612337154341, 10502845970727626855, 6527587047878193251, 7049690136888681718}, + {16750703006415156202, 2559311261501721445, 1222802194566919230, 18019462938525560766}, + }, + { + {2592184418896595488, 1723751460114310463, 11198512454461769811, 6203707848404803677}, + {2601731234271436477, 18186700975610533226, 4757569424831899615, 13359873383138312209}, + }, + { + {13904640252203718708, 10747313134117021792, 14667070697514384141, 2600977347774743546}, + {15498986940124021079, 14740645313274577011, 17403811028932224808, 8060102076475954685}, + }, + { + {12990649636107730851, 13002224935892458030, 4380799638612122791, 7935443787987894924}, + {10438069978940053126, 302419699431148366, 551508078777729872, 366155636877501719}, + }, + { + {14734735764746786753, 1378251478826083755, 13509550209468602124, 14458158239096821346}, + {5681313138148713219, 9054039627425609375, 4235536482830620712, 1502753755874778370}, + }, + { + {8914021876030553161, 9071747156187788379, 14974736924255494885, 17070198435868341999}, + {3643991391224035758, 260637732328275649, 17609644917816078225, 2302996326941944665}, + }, + { + {5888744936142942064, 17277140802638358763, 10290028650289820825, 1940657436863195045}, + {10796401239257150661, 7788083050548605852, 13474393003015663489, 8961936186303685357}, + }, + { + {16407225233842256953, 13423683834633513951, 17454464203550700633, 6033758555290610449}, + {5063673994339442907, 12250392784929419939, 5954485814444410119, 10099095370725442279}, + }, + { + {4687621216548073298, 12683256962895584277, 1406415612737291460, 3991320149877222007}, + {403384179417053146, 7072351635192146705, 14388831570324308780, 2518546598792352745}, + }, + { + {2866701220158780648, 14345701180700655413, 10383205903323525163, 14561034237887346332}, + {4525630512028460468, 7470042867870921036, 12498636959757093905, 14959680069767374094}, + }, + { + {939355076355747784, 236998652239230884, 7862332576114728232, 3008745396212765985}, + {16892515157128448879, 1688671543548974140, 582235491724828261, 2879861045707356356}, + }, + { + {5793581539270397654, 12067972155882240315, 1914416028486337582, 2044052608129533771}, + {1045680055817519578, 6183307954634642810, 1115903654002488241, 9729229622559998051}, + }, + { + {11505233554542243613, 13650372171621554098, 11886401428750724176, 2616122636264787282}, + {9807875738265530891, 2065326856613209663, 3841177149705795822, 12478836916087572836}, + }, + { + {8725096612265348131, 16959754534248500306, 3934616751368449170, 887912345061829880}, + {11410178859948957868, 12867384504930748729, 4367798270196663137, 4359910421693489126}, + }, + { + {18221589825782480868, 15875305463032670629, 1054133002549446970, 2220911650204683784}, + {10874691797030180071, 13903803155513130100, 14873882741737344436, 9374498718172057556}, + }, + }, + { + { + {4471613312912718060, 13601785177495103328, 8083849806888905297, 9053545412554844461}, + {1876605639999952155, 6124537911475118673, 16877891074567085688, 16541720065079132344}, + }, + { + {18138305348849897995, 11498878557125400853, 14125346336359365201, 11991638807788804369}, + {13935355764550912568, 16209147067155729660, 11086190285777019292, 16727288863943596410}, + }, + { + {8873152377611229668, 6260821826956744083, 11489383533808918262, 6585112195310961861}, + {7365821041919648819, 1936165695028211587, 16164747634991415711, 17957320776652490392}, + }, + { + {13065030057172289846, 7278765836407486850, 383827150208081081, 7832055893191054601}, + {5249323286889945617, 1631661912887095912, 4431088469837785451, 2866263172993336891}, + }, + { + {6140213328062333551, 16704025329777067037, 5839832043209342792, 9196354634862869885}, + {2735762290983671190, 5323501742548818139, 3199127466610501482, 6719610946615763192}, + }, + { + {4032564124345275293, 240208626666701335, 10264845378648897042, 15608289126091352415}, + {17866864241918154829, 6207477318890336372, 491708931325462670, 7002400618323099260}, + }, + { + {11507747783030541234, 13683043390668171754, 9924966309328785763, 5549516466627385909}, + {3724001483041449858, 2408778220985427590, 10510707601023430105, 12862520912519186496}, + }, + { + {5012372868660694231, 12033652755433827667, 5960732801180177919, 6089487525155575261}, + {18400192045204062277, 12754175136438960528, 6170965736016609163, 10141374482047067946}, + }, + { + {11781193922347227447, 16937876011211881637, 2982972111293427964, 1728244726890919596}, + {3327997232304084768, 4754833121145407334, 5871027825507908591, 15772493911709624273}, + }, + { + {5862944033912881884, 11132730978666088350, 12167180155548291888, 16449838286695349787}, + {14399676610730016345, 17071083123672650337, 13727728787831175379, 7507765123422748291}, + }, + { + {4883057314704644529, 6606742732149784343, 16070555141087563722, 8408294891669305261}, + {4298316003054547788, 1573237855902568238, 5357176885445018289, 5855732582172939202}, + }, + { + {11721126538980357625, 7216004194033429913, 12765889884935948315, 6003399149613653734}, + {4571046290325663920, 15023470461830485075, 11463513436288928362, 16135217522406374542}, + }, + { + {14300855104129153291, 11491527690078786162, 5674183453812271017, 5044682546652747711}, + {9153978680942338831, 400454762074409409, 12351470849648616331, 10559229320903248832}, + }, + { + {11839166519633311143, 16489041153719856002, 4820713204385149226, 13768001962143023630}, + {13107713406478328396, 15471245828032402460, 6733652296473831544, 7665657127090105428}, + }, + { + {6114372925011600760, 13061069979571997963, 12156991017966837826, 12403009591138383583}, + {5761958709898299258, 1907771304051897263, 3007439379929412593, 18410854883912163962}, + }, + }, + { + { + {10153847769616409178, 16591913677701651064, 11369151065084080884, 9493662847124813178}, + {14299126668179023903, 2451525064998641745, 16055696673728703463, 7600736037142850105}, + }, + { + {3339871688614476269, 2937156932445032796, 2071344655111136329, 509603454456841298}, + {10929109734329673813, 4531629375826317764, 1802431569220697099, 7971315018970882891}, + }, + { + {831440329504272059, 17398063681351066636, 14954668702259408996, 5717183520144440084}, + {5683898996859918421, 9613688159291425744, 14476049487507222229, 3689544236835488368}, + }, + { + {4307546666223047416, 13914498777427309061, 6812156124789414732, 1680174913762530491}, + {6756325174405757110, 2535144759174364990, 11263393915003278429, 14767595249676286403}, + }, + { + {16671897597823309975, 8846923580617118936, 16420413907022376284, 2344779928765541883}, + {13727655669851883280, 934227091954463432, 4722713881950047653, 11812583008287470589}, + }, + { + {5321392406277114518, 347488367118035707, 13877286915167943316, 9829617275563347891}, + {12220860524024630629, 12190721936758412489, 7308208895364574537, 1525158119497637419}, + }, + { + {12984508126047021344, 13884472939864196037, 7382834581395586970, 11638480609720520178}, + {3822030693056621440, 16565826187005934945, 8411123762207988382, 1177726217844912325}, + }, + { + {6981289090623415465, 8930069945493884157, 8223216504978132408, 796477795300774057}, + {3120155459209743472, 14825603392456550470, 3711879425019804830, 11041054473536223927}, + }, + { + {6533202055887887500, 8435346764005128028, 14910943752455571727, 12906760590440667071}, + {6009159206340842586, 15232286290711710102, 13101554303130256987, 9535887764075322183}, + }, + { + {2364828287094520952, 12465747625792776806, 2520175043973011525, 17224593222741233568}, + {1891958595100476046, 14167979679885431508, 6587293950576996181, 438078840840804918}, + }, + { + {3740623254035318453, 2026091438664349886, 10842473205058238690, 5471257179527938221}, + {7725900701946760330, 2830662433803069280, 17799722315873409980, 10759084277615005300}, + }, + { + {14135544350792474553, 6171419888118563156, 12495035851387242130, 2843310747449412555}, + {5668766087526340552, 10117858698838396246, 5181027414039980750, 13247490124270426}, + }, + { + {5630566354382744149, 13019515676216329576, 5170054423571001981, 6980215251505169036}, + {12147009277250683724, 5685374899516102781, 10470553909247052379, 13479624060240397189}, + }, + { + {9352291669847160009, 8941401423217216209, 14488820078509299610, 16185610851702419585}, + {11995025321082820298, 8447817180287020945, 5861763576711981236, 14278368152612939946}, + }, + { + {17266177108677586607, 54295173557875478, 6565771227548453510, 11327083086584790599}, + {2516266639353612660, 16450448808532150212, 4693041555468884719, 10262468795248362309}, + }, + }, + { + { + {2365455792963674834, 2249234228455309648, 5237136544555745182, 8814246419234451463}, + {13017813702607013347, 2241193992640629733, 17982226236989862510, 9800528153239873634}, + }, + { + {17271890190678399664, 284117971978206043, 14999643475704678808, 6264699496666119083}, + {8859934981351804429, 8300880062060532031, 3667839168820458685, 17133003164910522197}, + }, + { + {17791633957402883820, 5938849497629314459, 8356801465373786047, 3163889445599730677}, + {9723709910898285412, 2841967670768995554, 10896757438566636700, 7434996874241771203}, + }, + { + {14086272070125896854, 12009239107306499026, 6592816798466831203, 11371087141421707743}, + {16277593907837607793, 16449564916599232060, 17471042072158213549, 11953382410698485455}, + }, + { + {14613304240735929191, 7658770973133328064, 3028731168325633068, 1486737152001467114}, + {16715835021406106944, 15214200823642287507, 18441898204110447697, 5669963154424393607}, + }, + { + {8381651800836461905, 275661552864412688, 5548629401959193001, 7174991431295718071}, + {7441251258233899268, 14052832476485122412, 301250917807487282, 17797202428295526090}, + }, + { + {16448089571044203401, 1396460397790470601, 9796571033221459545, 8162511506983092708}, + {13893406727199803081, 16188892369453405032, 16023105002157964343, 7061289566170423383}, + }, + { + {8743817608749172620, 7804846024944300667, 507107926259802795, 5258061329638283805}, + {15071070675288472598, 1848743106176521296, 16295570828486620412, 7409462376590083349}, + }, + { + {2825832734356158434, 10662490421734807455, 6363563030616301959, 16552149102037287266}, + {8852342875874616869, 16848248230809388411, 6581680050166700198, 245046966305064563}, + }, + { + {7828655274510399422, 8354801505584011854, 17818478328917068523, 17325245990806811268}, + {750899848242404370, 6729023687199559366, 5406329621088392947, 9196565205678366888}, + }, + { + {8064539304829538257, 6441901327220658696, 17278408443193767018, 6094106832683864460}, + {9824329910822370076, 5272517980512991724, 8211352561755619726, 16303987070546290759}, + }, + { + {16798983177239698753, 12189491924433050580, 9517619110936281609, 17570406314312177597}, + {9873809692789257777, 7539953961664846819, 14652839873293130968, 11082914471633564328}, + }, + { + {5471221015674785794, 8844747884377425274, 10084666525179707178, 11340747033059217003}, + {7295797213045550755, 8395678759725657352, 9654316500807954493, 9062353099996695484}, + }, + { + {4588282548354659427, 7317148840331807496, 1344326657487996813, 1542409176821028318}, + {16178223850158437787, 14916858636047869579, 13512744779273961596, 13549205429423761570}, + }, + { + {12307321769285447055, 293357554223804370, 1007020265087773203, 701738899338647839}, + {12276634770118212432, 14777553112070534726, 4541693432120405052, 9103025487888313415}, + }, + }, + { + { + {5757832545805155636, 17609080533053427627, 13855662030602089892, 9622498683452213297}, + {12281586442064581946, 610529441714948581, 14740357477019436626, 16983190111725558863}, + }, + { + {8470173855499872166, 15915210069852758660, 12368087246231545517, 3867174158581293223}, + {9082358201271846042, 16663463402757176964, 13740908859955866819, 7748969412274962298}, + }, + { + {13375424826931892789, 8508645806391261552, 18359272328758476903, 16433208398005282080}, + {13071423254987294580, 7999383023651164492, 14514701556577587750, 4848295889377673720}, + }, + { + {1020519568493754982, 10467781020270669620, 17607771250627508499, 6620300538436640218}, + {3858527175523168333, 13798129597334232823, 12495322651937391008, 3926713306087152023}, + }, + { + {5116038770086590715, 9943789276328255827, 13715439407309914230, 4887040860130243503}, + {18288477612078228131, 7640050573721350378, 14537362862524718973, 1658575506924200900}, + }, + { + {18400486168653423966, 18026904540891591040, 2037921821724043966, 18010956304511658647}, + {3751340308708032971, 16275459031633957091, 17177866831427164840, 1635431811339422016}, + }, + { + {3897330996014812355, 14347736534650088376, 16862404119462964612, 12216005411754788835}, + {11561909516001453735, 6261639657930189859, 9101978764314050064, 12280333151331067982}, + }, + { + {910276569977357717, 2872810615152156462, 1942106118995935911, 8734004121981822024}, + {13862118436432879698, 1912639548162720505, 13060137938875924732, 10642216911059510120}, + }, + { + {5132232031613377471, 3053931945527415993, 2695169719602504430, 11855046366025891084}, + {16462491222215366712, 16664416596202206835, 3077124688577987843, 7109495326459366311}, + }, + { + {3858762384693274897, 7520194928987242278, 4496744297661574884, 16159343214247089321}, + {6441167128044578145, 3604951495694157848, 3072075325567814428, 1964798869371174506}, + }, + { + {13689578474000942304, 8998724267038772595, 3350174507425430811, 15015413657749135511}, + {4848907595494161497, 7935644131326131098, 385849363817229511, 10087353746314516691}, + }, + { + {6067717601858189468, 10438404859927821308, 9991403870358837471, 17728358586134467771}, + {13476949968946830198, 7311235997042381570, 4429835371823736972, 17463216455983091974}, + }, + { + {3446799583712077997, 6763499387263152328, 9231082163128267527, 7733182914440272884}, + {17225092062157610409, 8163842076250628108, 14230171836718858439, 8195740716303697476}, + }, + { + {57759226194841354, 14962480748390190557, 2047254208877381876, 2830450574091058648}, + {14905486147404440754, 15792397930637469157, 16383409053580142957, 8686506861607761226}, + }, + { + {11120178572139812895, 11534611317577597022, 10437856602660752754, 13925966850017814278}, + {16776862023867799947, 17362554889424346260, 3408825299914455645, 2606150045870067742}, + }, + }, + { + { + {12109367644744157376, 18037756988516427980, 814572839386760074, 913616818805172815}, + {12974490864633240943, 5228203788953366069, 11458421156905635350, 14534725545904442520}, + }, + { + {13918155529832261002, 12953608416498491778, 4285102780598248527, 15853935066983430239}, + {2610351403194505517, 14905969693015035277, 12043976761492019990, 3883507340167876094}, + }, + { + {5439519346074792827, 2176389624009388617, 2631244572392601375, 15049241095214776941}, + {16292195309463965431, 4379169091046493311, 2454237863606964835, 16333960950959567989}, + }, + { + {10994470105201067642, 16033352651464686189, 15774427704233149170, 4596106024708523955}, + {8854068685612048031, 13529126595187822090, 11509928293490788309, 11620850709434334690}, + }, + { + {267621988570094461, 10587206279243947181, 11593510291287574067, 14787400314862354894}, + {4136983718443464652, 2976380359687256413, 11142324903811863489, 4610908641771667701}, + }, + { + {296274281547444433, 3085587185113256560, 12609265193181717917, 4535801536028989527}, + {3096496338675531142, 9292526016029159200, 13112825412047135381, 16663099831183411702}, + }, + { + {2767353193349225715, 8712112934471091092, 608599382922156785, 4028449356066786979}, + {17542394472389324402, 8680897831809226389, 7666317335732585298, 17261030852301003617}, + }, + { + {2068337952936280662, 6856444059219131741, 17213926210819196459, 513413453513211652}, + {5520465604253824995, 12970886588014924605, 12296275668437451137, 16808287251356954962}, + }, + { + {15914937173048753781, 12510295026185206015, 15954705664179129326, 9689253582699600268}, + {15356442010394775998, 2438265211465631320, 15141425278420483672, 17026865278332658671}, + }, + { + {775118291486058191, 14811108570252044526, 1277462327112210144, 1303109520734915949}, + {17662756477349124684, 3447822852149651619, 6150341860560710757, 13223916277431807977}, + }, + { + {9324118164416603919, 86833914568469678, 16815316898277944489, 5015780480822908208}, + {4077581079810359659, 6644887514971920354, 4892606269782662646, 12780428915404556278}, + }, + { + {3413637388791433603, 16937929882486384885, 11215805046681294327, 11559398419268924015}, + {11697258172757450737, 6137795229387768085, 3190984692021653574, 15347236891154706739}, + }, + { + {12504195828868930633, 14311735968635225029, 3580069346315758668, 12909891866007218579}, + {10780120525711488015, 17942431687417272891, 4966616543136223651, 11565637729828595342}, + }, + { + {12013939709036934636, 4233656138400235608, 5744753585886244254, 7800398410233442143}, + {15609887409465530711, 11633197710359969914, 4221051249637072360, 11317958694020095179}, + }, + { + {5703670472856822602, 8043375474958283103, 2470834322231268196, 13020386017071254236}, + {13795230438353673114, 9108571599173545401, 10145331563807416240, 17474439008571566321}, + }, + }, + { + { + {16430555432520738762, 11225321696360643709, 11777973654353154098, 13133115227828884393}, + {17678738157022850345, 1586660156856830642, 840647763693221003, 8645742354464326466}, + }, + { + {3598736754916501501, 4827022662021197854, 8203180748141933720, 10283251600632599041}, + {16186680658340956808, 15183393398087319142, 8714402370450665212, 13217902016653171217}, + }, + { + {11743016372336018414, 6125536020759642301, 16563280170798047733, 14529052521060111789}, + {15253502329174644388, 1556763737841306861, 3041940064290508531, 18020881359462953336}, + }, + { + {2297585344913389180, 13965959247788377604, 11341378863608387800, 9890953382689640379}, + {10443523266835246852, 9631856696811288063, 6944503116553031744, 10030824122780966395}, + }, + { + {6636244234467769744, 18284390012667441869, 722929822219329257, 3274166388651987221}, + {13177791837760949480, 2568122970128111127, 3477167651270374316, 11371867850093288299}, + }, + { + {12876460969864886954, 4692925517843901006, 17390372170975588763, 14692578774429957295}, + {1759864963511373267, 12016553435172103063, 13015881292003590351, 16187569590073958370}, + }, + { + {5868176722765418764, 8429364877332796959, 7785756492654137899, 14975349488807886278}, + {3272010964035218775, 8946396491617515063, 3774503492701710541, 2113917870331282160}, + }, + { + {13276631120161396750, 16968574704982977753, 2376454925072971568, 9477134218094425043}, + {13784622991820528988, 2074505569780291922, 14294803056569335889, 8759684036994631222}, + }, + { + {9884417819806228161, 10473583853313294601, 14339795822328931094, 8504498283323826917}, + {526127293629665058, 10891388783681447537, 4568472708151557518, 10369081088106148862}, + }, + { + {14875690099724520068, 15708131372860771936, 15063351920655636623, 13673754555867312132}, + {15920462627529593070, 9885706734937065436, 16823591115242423655, 1258777215756511827}, + }, + { + {8202515950988182345, 14546423651242108828, 14227698061016162353, 10918615690964448766}, + {17106085332738434415, 16355746637376756806, 990444867181428081, 15553043817355146246}, + }, + { + {3823475181283510630, 10848691050793796395, 6491636971888772243, 757676231362735550}, + {8973136455980928416, 6503381298194573307, 7834237673135397878, 10787325521157907075}, + }, + { + {455211601892268020, 1552688795129565862, 8165081519906588268, 5446810663215253742}, + {6750786745561416995, 6997284811902307211, 16012972729607911414, 9114458230677816387}, + }, + { + {10975008541567105079, 3750365577590028809, 13516995106985748006, 8919511738051569176}, + {12930984911878205493, 14293252788401143455, 1989517604536428154, 10167748824687611261}, + }, + { + {4403033949751056724, 8371165401092074176, 4457099049748166877, 18160854660487137945}, + {18090711188318162626, 2052332783995780991, 10990843822512572670, 8096670640545581193}, + }, + }, + { + { + {987127652983079722, 6872208513691823695, 10110578719299008714, 16457381243184327116}, + {10779072738879347999, 5965282398006505989, 18251577267494363268, 9321323379108563422}, + }, + { + {6119049170407437179, 12938407708038792521, 10105420405825346383, 3416306788177016826}, + {330648587825212481, 125568991290568141, 13857127346570918649, 4376080986981308805}, + }, + { + {5930434126597036589, 11240994623469578584, 839346533006694594, 10015087329724081709}, + {6285097815938761787, 17244606485954860090, 11523249727882012981, 7178451948850151803}, + }, + { + {16733615335426327004, 14833564736134873977, 15736159435317472941, 17560193966711884894}, + {4670172300306758374, 9477713670983496835, 14243955354032737980, 6459864769649694970}, + }, + { + {16053517698989562256, 2069464650596796670, 18305730134729303993, 1090863611964008044}, + {10595928817546105363, 11743183506441120484, 8584767248013363683, 9187452830514379903}, + }, + { + {6938579711827578880, 16268282168771714072, 4567473305742437221, 754548046014059669}, + {7773636946295303572, 8132380485366854656, 5054542590195827722, 6074347500754248128}, + }, + { + {3955857908381474930, 11852678900999621852, 13783017203403417097, 13616745777931267488}, + {13189924588414196918, 14519927295809952876, 9334100965942760501, 15172548734242885286}, + }, + { + {4869852132020793901, 14921212823114724347, 14342559113353033349, 13336827701782657309}, + {11168346789878684452, 9790480725902426052, 9171116079841529936, 9268902731763220711}, + }, + { + {4417372365016540659, 17280138652899703220, 6650972319709075180, 11252221422799491438}, + {6825784270383052414, 18308562203755695191, 4237445205082731447, 8485872406483449772}, + }, + { + {11718726714045105993, 2624508790343569765, 5794111482300008213, 12819216567095091385}, + {285329842793152354, 17257707863943097374, 16912487373614458842, 9501952033607497057}, + }, + { + {13074643344738491288, 8505193022029238118, 9932652098552590323, 267408114280737600}, + {14802861246220332716, 17506028737327736269, 15929083591675282371, 10937680132245212187}, + }, + { + {16688733766460131050, 12777635326299184071, 7769405825716531061, 12435979606514844725}, + {2767987141420672349, 6723940414217341603, 16114182069580717377, 4541113259200434040}, + }, + { + {8506371389960537559, 18031198550689409305, 11510251852995503442, 1923472385053944821}, + {6189904387119195613, 345664413118550356, 6439003191582953600, 18344385760549575361}, + }, + { + {5320548958745018096, 8341561189829530680, 3327828110998403156, 17981346269177513223}, + {14254804273025688074, 11111147827704077234, 9093333670517437191, 7272552282364063165}, + }, + { + {7587268797387514088, 4402481408866840263, 11260815389095334885, 14391444701764948710}, + {4224880318604689771, 2472148458660279030, 961218007313548745, 13826356220879831691}, + }, + }, + { + { + {5733697799130763963, 962857090393715865, 10538932452511329419, 3413281437172590207}, + {6635428480179771287, 4404718679994229138, 329074170931436370, 17746708206910902139}, + }, + { + {179238781994802586, 9017860544212172426, 16179187983079961859, 1380105261896053495}, + {6187003332254463653, 9896593306091975718, 17181949235068293496, 6820143159816507763}, + }, + { + {4652378169433586070, 2069013165869224423, 13972912433480425078, 2248203233787863058}, + {12819880125496785064, 12462800229583867169, 7969192387226362512, 15450728326339004590}, + }, + { + {11156900805411912784, 1737275748212365168, 16993486692205800040, 12538938066475152524}, + {13167476167764338790, 17373319366642541595, 6054831428930905282, 7118452124011953000}, + }, + { + {15319323094268250368, 15751569639563379275, 9174762389399453601, 5359273060607997116}, + {7548480167962649047, 4093535200286790152, 18255003581953064302, 17037929372197430710}, + }, + { + {3640693116491518731, 9689920283410066894, 16070225083132083168, 13505008973802466003}, + {750230942699692016, 15522838682331888368, 112268476925002814, 17491605970126192984}, + }, + { + {16769567946241955549, 17099752525969374817, 14041401861628609700, 13883170585376164878}, + {1568639950869924595, 7305902646691031157, 12536573783075304502, 12490145094151973568}, + }, + { + {743288751022377974, 9226164090128370715, 17669221687181604232, 1117842260351396541}, + {17697784451833850722, 14382209306891991103, 16951372733687268016, 188390802712613066}, + }, + { + {7332583781810119624, 11974900502289827649, 9825039434151224666, 13612433455140779130}, + {11167094757836568968, 148858902984029622, 4325547061862811500, 8439987427904092212}, + }, + { + {9775040802880336170, 2183956155792599391, 10102475962557589963, 14902149990037881859}, + {7528893974593517583, 18271333130592009124, 11812759747597590978, 3931581515688264350}, + }, + { + {7368734173241076742, 12419301291748626639, 10534790951032501149, 16676926058266807225}, + {13614593066288445663, 5547469267128540754, 5071513241190976074, 6206141439571986364}, + }, + { + {13268209255833199938, 16633146482265079265, 6044233937395578074, 1733872861371247406}, + {14239198956565602758, 4036306057099495106, 1778912298053970082, 6174082695927204648}, + }, + { + {9563897475320169888, 3828463449263891363, 4522408683909966848, 10085044841903958270}, + {15115863363467748291, 3921763467143122522, 3241611744432406503, 16149166019569794702}, + }, + { + {13355027832202142668, 13259310595418810737, 16638224598838046396, 388655643128437049}, + {6131988039969669992, 16758867465997134050, 793705445085763779, 16225736542798627427}, + }, + { + {12060616483613851492, 11185023117529741833, 15286366164051065546, 5407795227432242447}, + {3261413161331398298, 7182873809282605970, 2155509494582452911, 16998725707829879258}, + }, + }, + { + { + {14380343880230315251, 6834909096379668102, 15975839936772635678, 7738230945027714388}, + {7971648870467745046, 8320128435052726628, 10820026056424631461, 7058118462476293754}, + }, + { + {11165438517321289842, 8661037418831619311, 4401480924846865713, 9355650368902126256}, + {14352422544185763829, 12268031594529744663, 17607497268577344783, 12698954426769962214}, + }, + { + {5091534986326281709, 8005812102849517353, 17366496686564185717, 3658878980438307796}, + {8455810244524637026, 7649393961871195909, 8629386422022530934, 507133797409068858}, + }, + { + {10098955144981013765, 4095621933458866623, 313357785962326778, 14880249056209398407}, + {10605627454111004262, 7841561005378789988, 5015399193497762029, 5818383539901203899}, + }, + { + {829322392873083372, 3459913121476606612, 4547714508342797986, 5801286056105229312}, + {11591136160675314269, 17965845487226778560, 7022309609363885527, 5990586084398664157}, + }, + { + {6288277991521986035, 12231480617236286340, 8633990423689180869, 13535190275290488690}, + {13419223868164389899, 17622732596713666209, 10071779220640400024, 9451660464882303005}, + }, + { + {11761084765182152401, 9226969173242076459, 5445719591917489914, 9371133174853825566}, + {18381867235964583187, 17262888224001222346, 1934253649802391267, 3574888052111089863}, + }, + { + {15270079546607712667, 8471883658965202468, 10333206241569264742, 7414741159725097798}, + {7709713706668701850, 4461310100162632915, 10099194304024685274, 4760203118683828795}, + }, + { + {784143359277603248, 15514589681861498400, 4131024411374659852, 3624433493936743696}, + {3251402229976672212, 4649659622203715244, 926933500763282104, 6444675794782453444}, + }, + { + {3756269038539504739, 7020323719189662644, 9035687928909659722, 10611580746254894906}, + {6310976205075048332, 11776014447017145895, 18193543588427463707, 12941703752632419110}, + }, + { + {13258346207952257162, 14737306929596267614, 139896257833059475, 5049568122463438631}, + {12260461320589066027, 46497756452454082, 15185750105748824007, 3681406295924007900}, + }, + { + {2833339165549332500, 18300762432878821923, 13251805801497937312, 17798840894981774941}, + {10659715417364364943, 9241413425866019176, 9144746556705463526, 18018473193185776281}, + }, + { + {7436336871105679313, 3718902224813103412, 8186181643677715434, 17182578567975462342}, + {659724975715028710, 9425698860660002856, 796351253238186633, 18323943433898241577}, + }, + { + {13500588337778130334, 15143039800006025480, 5471884014140775766, 8599189774825271733}, + {14063442714998210193, 17130659899212878144, 2181888550891204616, 13594088124987533554}, + }, + { + {16216101853436910766, 13302132899821289315, 8876723129840557561, 2026846371223185778}, + {7753254296964005427, 16607365864296868674, 1800351426181020953, 12473523172043936884}, + }, + }, + { + { + {14734199666349771791, 4159865781008764547, 4413963548436270853, 4489431649937855880}, + {2824856157476907519, 5111945927271461159, 9825486821405155220, 7657332565522279292}, + }, + { + {8798422177670065832, 1250388939918922012, 5145324733132743026, 3716299737175574168}, + {14387202892738514375, 10255681359895407489, 8563822744122397080, 18430417713920116013}, + }, + { + {7857399215288147901, 2593284350589299949, 10086687882410147351, 14407837835956327624}, + {4469878646287387405, 6845712208092605310, 3019047164798827279, 2760591274816994522}, + }, + { + {10930605176025081830, 5850835312463207607, 9603163404664606781, 15623771803942139684}, + {4096748595672894276, 13060617166821837740, 11222939712741281346, 18445178894593253710}, + }, + { + {7976335583419810431, 16568954524837045521, 5581116346602990350, 18369129318179031997}, + {1930478946186473631, 14255806344323769850, 5302512325798050097, 10008570767203424472}, + }, + { + {929118050943456183, 445163760697913504, 7208246135487165437, 13565354217377841149}, + {3835063466770003968, 8214155842021576753, 2078717035803259674, 12502657820500987763}, + }, + { + {17741004372977419914, 16320851348541958575, 11853008901690968430, 9954777341381304447}, + {14274892887030297417, 10721339848307167540, 8731332510371325649, 13676383433520290197}, + }, + { + {6251805914672095769, 1063060143452094078, 16647397170554915088, 15454955736319919321}, + {11509235104607349098, 8441647766544589978, 956121464218389431, 10752793912033728149}, + }, + { + {14879603883666664508, 11158422912437249402, 8667988090392051507, 12702057193823135575}, + {13234479167199208223, 13752955092077643608, 1117550756888145931, 1184967682872965330}, + }, + { + {7004802666964716824, 395433501626287206, 16674151908279399004, 2279551165611331131}, + {18032555740803644790, 3573953642384243989, 9892480504006025100, 2397759375236735831}, + }, + { + {15032723931727013905, 4176673226777913017, 7270920367565154969, 8867675920919464620}, + {8174119413251699506, 15030539680120439131, 12325981936900309518, 2932283844656871802}, + }, + { + {3227890727136855788, 10772277744280338071, 10065219931092397730, 17233706446636791341}, + {1372997838851103811, 14430098741859995846, 3290287064497023581, 13054133915521430696}, + }, + { + {3404625123065318735, 11884832674715736469, 16513753127836546671, 2355202492840722899}, + {2182039060332057784, 17942518439766613327, 16731345075928062112, 5501869092504492134}, + }, + { + {15704211025163561149, 14596679078416770266, 10262177146233936833, 12443005669252298316}, + {1541294166390346144, 2952804996209068760, 15358481016273272880, 1321729586231860999}, + }, + { + {6862865331233391228, 15106279167311639122, 3283008666555627541, 13405610967904725343}, + {9845239597399801983, 10764942720093673542, 6506992344666983370, 2483131164245259278}, + }, + }, + { + { + {9844707592410952215, 8167497709587672711, 18115463401502884199, 8471563375691441535}, + {17525405040226359165, 2460181803833371342, 3375780580907171205, 3024376384135966552}, + }, + { + {18138724984190926809, 4154767406604950048, 5209478936276366634, 15469512148904762872}, + {3613429290324777670, 12631812917445459751, 10280179062385049041, 19656860716268566}, + }, + { + {14203862032167128161, 13470939927320077756, 10327441827790615277, 10318573137694660185}, + {14560780313347476436, 17088464982837309355, 733937949060316950, 14069325810788446179}, + }, + { + {12030193727051241373, 13981191132445467472, 18205169646206905593, 12162181194046583886}, + {10929925499200074058, 15291772758590352491, 8452344520852919320, 8199821440451878776}, + }, + { + {702956275289752726, 11856189935311796245, 14185745521831658392, 4370665693013677718}, + {4339320942948136612, 7422618440224759582, 871840009976682819, 1758213746931263134}, + }, + { + {7463305936638691553, 10552402742907536443, 9732741351132553899, 194397927117005699}, + {12837197785265289115, 4412933472643099429, 12440864981406580998, 17072316007921211511}, + }, + { + {5025653014579399483, 6266285559889618786, 17667439302823084142, 8837073500207072384}, + {16230880878690171580, 8966359704103918073, 2671625161783975934, 5761959268140569579}, + }, + { + {9876482463501409337, 17331045017548147052, 17542726936580732548, 8299195336372136083}, + {12891767721269002608, 14062358772374813347, 4165127680073507756, 16350672737379495431}, + }, + { + {15987859092221739938, 10999006767011320329, 16931834873460681704, 40989027820989117}, + {16439290771012023473, 6900965556474667785, 7253680936177336810, 17240235510851599487}, + }, + { + {4114449005477323279, 11333071244606712260, 5639227616302034307, 15107257128889549417}, + {5046122977641767311, 17558812465185003134, 18137671581165086239, 4382776603153058089}, + }, + { + {18024760665596162063, 4581156045659391508, 968287218068232238, 9228777525067749703}, + {17309990917327276325, 7114941925430814300, 16735731670154258613, 6290532662018771504}, + }, + { + {7595271959296927018, 15286771623821390629, 980612661413312852, 5738158184597378995}, + {6972117550390447038, 6246497134979772260, 2935831443692029059, 12837371529160496660}, + }, + { + {10790135298802805255, 7259368218310211690, 12050916808246223984, 2030323364779525994}, + {12824594050397534312, 4098150364864727064, 15604500991562385767, 2831443658783115116}, + }, + { + {6469454686530052235, 2594644969515545140, 5284951626835069400, 14441180041267617906}, + {16001664398759990060, 13049178223054879255, 3268931999230968043, 3072360434503949622}, + }, + { + {4565530397071857053, 857029374864691712, 15955478286869670604, 17781316921869181573}, + {16457191703043818907, 5989113593649065091, 4425872606756635499, 4532030700973621003}, + }, + }, + { + { + {2317249352525369754, 15030797481081533168, 12237590576308284360, 15660076992611440873}, + {11341015819700735887, 8280257602754365719, 9212501234696283343, 9673375202141178099}, + }, + { + {9762534010701623728, 15349113802811029024, 8305297169667044246, 18013018210154476198}, + {18414050009163335761, 2190126859433916996, 5444481274452218807, 13415988647365667724}, + }, + { + {11641532224340210206, 71261001011952801, 2321745415903209397, 6595984444855093239}, + {10341299657770272718, 11529878689049370930, 14381510695605158203, 6869272773579747365}, + }, + { + {1073778278665127828, 301289653767944933, 11482324780950168317, 10626716202328004967}, + {7258024014655363102, 12597648090458567878, 2617914106162603499, 12324652644266476584}, + }, + { + {13957732574177025801, 1100344278733481546, 12156946932617203965, 2007756425747006287}, + {16454508610548016441, 18058668363064769203, 15619001054652658323, 1201476243910931863}, + }, + { + {16341334571424533804, 4657494880554316004, 18092783076286521475, 19832895869027143}, + {8667365497283429486, 11501953273367138162, 5832487631687776985, 664754160781757174}, + }, + { + {13524719886605363170, 11553593166914861649, 12034020205580665813, 985175984881624722}, + {11040631342644137311, 12107496606245418129, 7328748654066365904, 14741972847454326011}, + }, + { + {12828567388121500364, 2264959796189127526, 6222205589523394088, 8827682270015065013}, + {2619170858745203321, 14835030117099398518, 5960028394532808010, 2233397097850889639}, + }, + { + {3879642723354138203, 5439355518658448857, 14194463322012776543, 14947367699252203702}, + {11497182458118153903, 16347396442451668378, 16912659817226286851, 6972297461053626970}, + }, + { + {14953681219966965709, 18116944572750863844, 16774540053916392198, 6518998682436778354}, + {11207035159486725904, 17279266785091386830, 15987732680339874714, 4953887381255790681}, + }, + { + {18128055290529398111, 4838636144867908799, 17655818333374840693, 5013823741985131317}, + {1920449774281311783, 13898340137609808546, 861099289958274037, 12441596565887895930}, + }, + { + {7244015348755525626, 13520825180887535513, 9165067445392785660, 9250553550156732893}, + {15663564389384259196, 5724018088820370997, 11379531752316746866, 17687565409319417941}, + }, + { + {11050714794366707475, 12230144450501707996, 12363862313107363407, 6348205119671766380}, + {14263471584626838352, 7350100163762375926, 1902788311165167298, 11691126042005505984}, + }, + { + {3948847772791576201, 11933738159609952054, 15749315384347059669, 8831922078851474178}, + {8463496071867925621, 12756218686011120865, 4691766390469398064, 5252134452066688477}, + }, + { + {4880806069791899809, 11099088460364672063, 12627384861893315861, 4239079797011518662}, + {14560690935803003234, 15267325636353169132, 16919582304973803583, 10073876067858458517}, + }, + }, + { + { + {15695265447782578013, 15506558718447241194, 12341861439298989232, 18400958156300100845}, + {13704811286967591150, 5802260047239067846, 3266013253411255445, 9892957742319181954}, + }, + { + {6053458788987550519, 3243549259991905443, 17990025476026266205, 3918149716414968130}, + {562225565996136148, 12175287017902713154, 16317970834262634990, 5431198806775607012}, + }, + { + {15123186170178367264, 3054913246068400920, 8130663466272395280, 2852812622149318730}, + {6747630551931917110, 18302049774259156971, 3663865061939346221, 12340091610704678811}, + }, + { + {17453312277789785069, 1148609799196055657, 5931758962926317381, 5297597381576544508}, + {9136842287749269744, 3007653173299649609, 12364677607049679091, 3656932227466449489}, + }, + { + {17732801126130995365, 16093023291975796560, 17028512234142609413, 6293028118993952199}, + {4019599708379609715, 3557632583507755601, 16737140015288442165, 7041678499288317736}, + }, + { + {5187842645752673199, 14914432544387315508, 4944360914161982641, 4177329533692612281}, + {18423887817846407126, 11935898134550505219, 9191754399457615042, 962223885189306707}, + }, + { + {5467152559317256227, 13407023128339380091, 656806207084558176, 10823228592509573890}, + {282802378108427873, 13003319652664166176, 11501612671901244594, 8595770155487539951}, + }, + { + {1805255869285898834, 11676967700876044626, 3486630203654875772, 8366336693945605431}, + {17874084888474647879, 8803709150655606891, 680993178667234696, 1603785777136148315}, + }, + { + {3637712241808318043, 1673622542455477465, 14468899013751477571, 6607241816357171779}, + {2332200248940843815, 14077155355848738174, 17298155509321457563, 13624623885136011130}, + }, + { + {12550073596584561722, 13898852145577133829, 31360866049197404, 12629522544897401454}, + {4563446134761510332, 7272813487383198495, 16767195814334178362, 13600498026689482359}, + }, + { + {5170414136067325373, 10875290278133558518, 7331268231382198947, 4082234313337835514}, + {11725295114019619895, 6488017511603508543, 11399466652931338200, 2898113599278666684}, + }, + { + {7553418756944942759, 2324485560009697358, 16004009784734101843, 8345371056076551939}, + {7377284629098981027, 11049718262343754276, 8021605820736410979, 8175349759714152494}, + }, + { + {805625092558946929, 11996029844853502332, 1725029464967101849, 8189609560660709539}, + {10396089572662865065, 1756007811373736605, 7645529329516777410, 2608132938055260111}, + }, + { + {17014595621244604813, 1574499958190108567, 8684546755761322906, 9997538531915911005}, + {5652402150243592363, 6315865356369667235, 8687115108443972047, 12369176255146729475}, + }, + { + {5117004045853299762, 2238407612548002914, 12392667457861900490, 10614312910576266709}, + {6446577503758597410, 3767883614425995197, 17954966454260719539, 5233322901463099}, + }, + }, + { + { + {1081257522368061155, 16144982029632101790, 2280210790959566458, 5000326950136078873}, + {10441086845859171982, 5717080014740953823, 16816253740467637151, 5185838557034755093}, + }, + { + {3897734650128449985, 3892478283047854402, 153850176068596076, 4448963435449755938}, + {9911011406822436713, 6379744721342779297, 360324666931028426, 8002086405015565067}, + }, + { + {13662666854424521459, 17028614494600252018, 13372166182804100759, 8978661571842967509}, + {1689945315009228820, 9997133634912151808, 4070075534875432478, 5780712439158341418}, + }, + { + {18068291112584812890, 10288580446655316879, 16866690514199445805, 15458664010538199871}, + {17175925202246173890, 12208778610361755998, 927739404697616036, 10330183209424493139}, + }, + { + {4422872630455196261, 14815650254807917367, 9426346157598724768, 17764302665164113296}, + {9474027272970951461, 3048886202121388617, 7073604597785890399, 9516006646305083675}, + }, + { + {16541317581647968302, 7221753201217091047, 554497992080233562, 12743131795939254731}, + {6113032707000257613, 4448176364247161206, 738044254484725063, 3096942233684051465}, + }, + { + {2801392933730991479, 15502003900939246745, 11340323610824656109, 13690394827169426680}, + {2298413291804124677, 12243772219106809119, 9550327342593445260, 18354548835264437008}, + }, + { + {17095781462759061506, 13984950766342782369, 7038608479806172868, 7073471193601880894}, + {9212126909381119712, 15865851343492198107, 3874039137971369196, 15366505242302572319}, + }, + { + {10476508037395688256, 5905562397524931472, 15147896444621280595, 3856601647293477321}, + {4204909177546012159, 17515684210872904454, 12561834979880779760, 6477848309789627185}, + }, + { + {3226022509034031128, 5771385963704757771, 17861700165696478115, 14976034400726774156}, + {17945959497662269352, 6322288130414861016, 3008853024335853994, 5599925939427067989}, + }, + { + {15408448007738805625, 3855259080280453396, 11776434265478354726, 11784885919111239520}, + {8108981861486003291, 16553896039002150783, 5694423121092647200, 16414563259092889693}, + }, + { + {3235058267792568155, 8030551941244615429, 12851363585510555514, 9786973022560471711}, + {4901414898060251968, 13240438628487941170, 4707852389766057435, 6503805666511566831}, + }, + { + {1178073204986944698, 10685133932326477495, 11710162005310407793, 11019188929725710305}, + {16244991946372165706, 3272168887117805467, 15045747299972144833, 8155681972478369649}, + }, + { + {12308450869393289693, 14268794937571237354, 9141189178824378983, 11605207657904000518}, + {17071770108549330148, 11045960524457021256, 13807710432855107212, 8427718050873363613}, + }, + { + {16762196363426636910, 7316863360113205703, 7937998445095491508, 3946557199536080470}, + {16019910399697645039, 11522845950519380293, 2362453023191035102, 6547077716792082654}, + }, + }, + { + { + {5218985848865375996, 5835476376320976237, 9096499658845542933, 8952489298840360492}, + {16605895184424459659, 505731104315931813, 17784248872812610986, 4151555707609374291}, + }, + { + {4963953120977916566, 6585250545846301109, 4490972754776862709, 10674499592300479120}, + {17494988318349821345, 1814042777264686189, 8938395423478059768, 9062966010283426056}, + }, + { + {3879469818714011415, 11493820457829716643, 10091807027724827301, 5032134849078736052}, + {18015749204009276046, 9667758283246223357, 4629693773460610802, 3807196436109718946}, + }, + { + {5724217930909760221, 15420221591912350415, 9910465013739250802, 12511683773790779491}, + {2841532862707547306, 16614426471009646589, 407574220261191228, 17422057170120224031}, + }, + { + {3725101809714764432, 2995111022132376824, 9338883729618021504, 8824923738291347476}, + {3745497072215538317, 3576446898425965872, 2350077748663612773, 15793255155885543355}, + }, + { + {12904339001067417585, 1972265247859388742, 8908590936681392405, 10320719400504224158}, + {8298368064038407143, 2105745729886511647, 16509751074757847095, 15156289751671616565}, + }, + { + {885617946245226760, 17871561572095909264, 16413308527330544768, 2938750343525834336}, + {6332736376778563648, 16772687696658236231, 9760470695949399178, 17420556823805232882}, + }, + { + {4407657041250297528, 13832960959347315977, 15056546959967740939, 4350443362134191429}, + {8013419913016572733, 8888684099801298477, 15401479253620745715, 18279947201669400847}, + }, + { + {16774767206504477529, 15784248755460218800, 890363416232172440, 6798249980336291014}, + {1295939576916968887, 14501516576359061383, 5181286196215569291, 8884842683907072200}, + }, + { + {12906144535917740163, 4179201185048577793, 8949647323841299627, 2168773816567792706}, + {1715683170634778607, 9901501903322086192, 7624633731287546358, 10530124063631858009}, + }, + { + {14199956317346734484, 13250211595320054421, 18197952479293091552, 16161313407818957084}, + {17435507292968186894, 6560268436714668609, 1299607057816966726, 8157462320016248727}, + }, + { + {3603583288706717651, 17387128326071547512, 17907604816622771553, 17853094381965037384}, + {12273843852205811233, 13840584476006398280, 2018654168596055410, 11549248055135584644}, + }, + { + {4742377140579111706, 845465928037625085, 12028953960657292824, 16438644767032965255}, + {17377088622232632294, 1631558517096568450, 11363064014018667511, 6006029335296807862}, + }, + { + {8877393780281438935, 9848923171251074575, 1554975198005028643, 2251034043951525516}, + {9696558687758873050, 3889942916226212472, 8326933892612496812, 7463785348361544799}, + }, + { + {4205364996189816688, 5453611962777060261, 16993840011943171053, 11689161310506207011}, + {16699173739044458906, 6254168288000491517, 12642281218300963313, 10028950653175051753}, + }, + }, + { + { + {8784043285714375740, 8483257759279461889, 8789745728267363600, 1770019616739251654}, + {15992936863339206154, 10037038012062884956, 15197544864945402661, 9615747158586711429}, + }, + { + {9583737883674400333, 12279877754802111101, 8296198976379850969, 17778859909846088251}, + {3401986641240187301, 1525831644595056632, 1849003687033449918, 8702493044913179195}, + }, + { + {18423170064697770279, 12693387071620743675, 7398701556189346968, 2779682216903406718}, + {12703629940499916779, 6358598532389273114, 8683512038509439374, 15415938252666293255}, + }, + { + {8408419572923862476, 5066733120953500019, 926242532005776114, 6301489109130024811}, + {3285079390283344806, 1685054835664548935, 7740622190510199342, 9561507292862134371}, + }, + { + {13698695174800826869, 10442832251048252285, 10672604962207744524, 14485711676978308040}, + {16947216143812808464, 8342189264337602603, 3837253281927274344, 8331789856935110934}, + }, + { + {4627808394696681034, 6174000022702321214, 15351247319787348909, 1371147458593240691}, + {10651965436787680331, 2998319090323362997, 17592419471314886417, 11874181791118522207}, + }, + { + {524165018444839759, 3157588572894920951, 17599692088379947784, 1421537803477597699}, + {2902517390503550285, 7440776657136679901, 17263207614729765269, 16928425260420958311}, + }, + { + {2878166099891431311, 5056053391262430293, 10345032411278802027, 13214556496570163981}, + {17698482058276194679, 2441850938900527637, 1314061001345252336, 6263402014353842038}, + }, + { + {8487436533858443496, 12386798851261442113, 3224748875345095424, 16166568617729909099}, + {2213369110503306004, 6246347469485852131, 3129440554298978074, 605269941184323483}, + }, + { + {3177531230451277512, 11022989490494865721, 8321856985295555401, 14727273563873821327}, + {876865438755954294, 14139765236890058248, 6880705719513638354, 8678887646434118325}, + }, + { + {16896703203004244996, 11377226897030111200, 2302364246994590389, 4499255394192625779}, + {1906858144627445384, 2670515414718439880, 868537809054295101, 7535366755622172814}, + }, + { + {339769604981749608, 12384581172556225075, 2596838235904096350, 5684069910326796630}, + {913125548148611907, 1661497269948077623, 2892028918424825190, 9220412792897768138}, + }, + { + {14754959387565938441, 1023838193204581133, 13599978343236540433, 8323909593307920217}, + {3852032956982813055, 7526785533690696419, 8993798556223495105, 18140648187477079959}, + }, + { + {11692087196810962506, 1328079167955601379, 1664008958165329504, 18063501818261063470}, + {2861243404839114859, 13702578580056324034, 16781565866279299035, 1524194541633674171}, + }, + { + {8267721299596412251, 273633183929630283, 17164190306640434032, 16332882679719778825}, + {4663567915067622493, 15521151801790569253, 7273215397645141911, 2324445691280731636}, + }, + }, + } +} diff --git a/core/crypto/_weierstrass/secp384r1_table.odin b/core/crypto/_weierstrass/secp384r1_table.odin new file mode 100644 index 000000000..338e7b9b9 --- /dev/null +++ b/core/crypto/_weierstrass/secp384r1_table.odin @@ -0,0 +1,5969 @@ +package _weierstrass + +/* + ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ +*/ + +import "core:crypto" + +when crypto.COMPACT_IMPLS == false { + @(private,rodata) + Gen_Multiply_Table_p384r1_hi := [48][15]Affine_Point_p384r1 { + { + { + {3349844787980918824, 5700721700487043153, 1581288787708942329, 17304888540980539863, 3234495129650039747, 11694852976059594522}, + {11454526365474276483, 17280055605583648274, 11483041770187710052, 15064860306174908787, 9425940298043390756, 7831029453110477537}, + }, + { + {10854210904801992286, 8255439613636595718, 1316348857406525596, 2282633625581246438, 14438173431932387987, 5673747503677604393}, + {8960903665589529841, 14030078906563026478, 466971755747792240, 16909751879911376491, 8261483486653352128, 12597935804442306524}, + }, + { + {6447508696227153408, 2759028665179735381, 794515856920409590, 14869397668262921446, 10588017418631076914, 12633095840797167228}, + {6607496461698970477, 6359006165521880122, 16663268705047656412, 18219762716186036953, 13315075775889493847, 6546871415552527515}, + }, + { + {4250815476678138550, 17073439466111852958, 3750529698426925825, 1904641224225602431, 7274009899457528107, 9209596034767199086}, + {6863361867383511223, 4099555040981761624, 16013520265914987211, 17330863835225155437, 15236683723773407531, 9886066912739647523}, + }, + { + {6548020115141006009, 2051287398488083721, 18013217855858620214, 17512108880758082211, 9657257807517110121, 13349423389223700059}, + {11448378503671870177, 16607356707891652776, 17986139470446831883, 2256897346286898360, 7779521166731257394, 14734261666263853530}, + }, + { + {16451156334851086799, 10433346012762661878, 1154088382826340721, 13920053107889463035, 12824812460638933002, 5771020232226448223}, + {10182053156369870491, 9953188423679889138, 3623574174398550414, 6539131418856354537, 4739863922718165110, 13968548469751179186}, + }, + { + {5057596744164756370, 12108644536263189339, 15628783732405749711, 9182850460131890127, 7755150145219327164, 12512487145101794871}, + {9783765255428637296, 17231411912625418137, 3031503376230558613, 3001321323125863884, 3711029936425287900, 18364899108493632271}, + }, + { + {4364170143483158168, 3837420327812895040, 11153877356291905762, 8627127623255240713, 10258093926722597263, 6966392554053872709}, + {13838494481389844004, 12447754423026187562, 14673290292701904554, 6888547195036401202, 3349351868797716527, 6817319933710697746}, + }, + { + {18016384373848540113, 7565820187757705205, 16185660972256070888, 2502822820839506307, 3880408517672548187, 4194119666426113160}, + {15694892319489811154, 4832422690840974597, 900725859486443418, 10265913502031862890, 1864821221915885738, 3700988259937570428}, + }, + { + {8488064655818993057, 13159008538953946469, 11028809874392449897, 11486244481861659915, 8569628704299090359, 2892252873674546430}, + {2941671072611665985, 9930810186813308033, 10852463932839803129, 6122756170654615426, 13303416592882569572, 6113713156059966484}, + }, + { + {10029451401870245184, 17181275891609445610, 1563464611048571891, 9249056941485261951, 15488363863106956591, 17426032626929358463}, + {3624362630716884995, 17733027703464349615, 12615837230382222165, 2899993379581625588, 10641197672343453466, 6876651786059986401}, + }, + { + {12941176093218387209, 18012784992688854716, 17630514364742901970, 7489207242388660276, 3300101790738216151, 165750267447677843}, + {17420203378203929547, 18429168937941287247, 12685766409811315467, 17062737254687688913, 11583537930945240085, 374101281300528640}, + }, + { + {16294845494152982505, 7182435875615992692, 3318017447157242087, 6087688366366383495, 328984259793137604, 14904070120287703952}, + {565244652741101966, 4951466181341698004, 11866318921579101416, 6194578547220221350, 15631557042652121752, 10545898140965819968}, + }, + { + {15745305462398415447, 6816971438675772065, 1075554629877262698, 8234899837982726223, 3512560196005219004, 17693290669008338152}, + {14638482525770633011, 15865918008670368297, 11359271142073926365, 17074664191994857570, 15613938350520725613, 17352596771318223922}, + }, + { + {6627628274763979245, 6430867977390741183, 16640991507592485950, 13915161472308593069, 9005635619537074355, 17136188005588780957}, + {6349032855227933129, 13790585653547635104, 6107878840283566203, 17101678754123509440, 4589529453987745844, 8778990861876837520}, + }, + }, + { + { + {8752339740764879889, 17204670892025727113, 13948917001537480663, 6015237120129105404, 12568825630768815527, 17098885903057916524}, + {3196947359408104404, 10557260209896054933, 15941743809901771731, 11319635393284889026, 15404036538896402776, 1823888675766330133}, + }, + { + {469276640564380241, 10942708362323945260, 5172129155405724574, 17521202989307779782, 285237824018528197, 14755519896084931015}, + {13450199151338167480, 4987469637889591012, 11072253743028383225, 4126494248833488207, 10403393469323319433, 14468451395906602570}, + }, + { + {10409556101848104492, 2312052479304391304, 8367833927637255749, 12718782815503837000, 12586549663603169139, 10099896633356211470}, + {7897182246145608734, 6279866437607856313, 15077509973591020067, 1920596236429885894, 8944171611482738124, 468560753431799278}, + }, + { + {14398196793687807397, 8276491336766244001, 16962771698246445022, 8043838882426521864, 3609036178188456346, 17961572587511875610}, + {10659300691638275682, 12905326140192521229, 651286293824175704, 6550291910155090287, 10359196978363721745, 8054349679302352396}, + }, + { + {14267646986135279321, 8023233762563366251, 3277224320191152598, 2431726775717059350, 3733051418604042579, 11078740418949781682}, + {4641466211631370887, 5972034612476576125, 11061332758238937654, 565694857032650296, 15196808723752961845, 5493285531974069465}, + }, + { + {18369275680877034088, 3644498253900435800, 5207654447363684810, 15054017021149325074, 13441959779061156291, 10801557030657187731}, + {5488228865522937525, 10042916063344664944, 16628991126352116102, 13399733271269739520, 7919096844168308660, 12224871956968387142}, + }, + { + {9406504212815497730, 6315084170282838751, 1538052392585176449, 3287788394884246045, 11684015502339439334, 774607932742351547}, + {13523687029812911694, 8970259436187285903, 516344689739437046, 8879385705799553570, 15472954217075584115, 17165612419994903190}, + }, + { + {6153906285028789904, 4881581827835548877, 9088581243877761387, 8673828452274153145, 3729691157199039232, 14763971970770720159}, + {11125946843031387253, 16893034180060177406, 11028878025260215404, 13414446456552306577, 15673952559920934625, 8227747155230402213}, + }, + { + {4019194246965870655, 15651844969361453739, 14943903262285431608, 16531569415823118894, 12811244602177600058, 13239818034282515750}, + {5449698701210370930, 10791866857788139766, 5646650868879525525, 13293667095645494023, 12241262662724597658, 13853472368070253083}, + }, + { + {4116627791673898568, 5326753363832360760, 11600148105162668652, 16022425070120634880, 12379564163937803418, 18403278989519500037}, + {3838756056494870539, 9746510470453080454, 15196381880087604041, 1324266274153753608, 1934910704818180248, 16192237923261768598}, + }, + { + {5766511464995673783, 8244831189622490542, 8170343088439188103, 6232835306175447562, 5263728916489688559, 11717533286834875}, + {12241226361813518908, 13563045206906982275, 6620157279318203022, 5949784687776791647, 2638510331637305823, 8202404349400972534}, + }, + { + {17137086209956005801, 204428026461370733, 3234178205969960017, 1143006718786815780, 7294365920988646447, 3430748893910901229}, + {15644744495324135074, 6526193849034702994, 15311692696436479485, 100536624425234142, 2072137864950345134, 2838362248079960254}, + }, + { + {3864766173433820636, 1971303109201164903, 5674191275610292510, 1729560487462795155, 10192657450724834454, 13552365051012392948}, + {6029200215919341904, 15607499798945720199, 9235384391078164863, 13115797159041968899, 11473304030559673981, 6717143313334294198}, + }, + { + {16073198989296538507, 1260522085794207919, 2484833084695527559, 16663233906141730979, 16370173418105654173, 15941588275532048355}, + {15264482454100651294, 1530324904307833661, 5346522558909751820, 168718846601743143, 12733323453851106540, 15054596367649585566}, + }, + { + {8779244963536382258, 14774177152181331880, 4385874624061025062, 1164231020920773885, 18441595039555055892, 10628161864427821209}, + {314776300789919008, 15953928246882392341, 11239013102079015593, 12105564780074077722, 14167815415915669462, 1359490032240618238}, + }, + }, + { + { + {17495831655399754328, 5174414647671185898, 11318938235462267547, 10600238109237010238, 3808662780947456733, 9982761271652922419}, + {9825065447185105695, 17201221608158777066, 8386702419239390647, 6669452484318451541, 9948181677775458542, 10854356442296663251}, + }, + { + {9814807791324751977, 12296930083946621987, 10307437404349332723, 9109385710605983143, 14812805821653280276, 9073050103164402930}, + {13867323253290964163, 4560904001274587374, 8320427990736234822, 16081927245724423233, 5738004521721590874, 6293359268685952360}, + }, + { + {1102440177859885328, 6433584039832869723, 5220624537358960047, 13680706619037828486, 8111463461178477715, 8222960733395115842}, + {17599283693164557341, 15090346558134489779, 4538679599583135375, 15042688490235051776, 13835441515025117083, 16073809881077304026}, + }, + { + {10047787296578964584, 2965381022962740423, 16294614689730458159, 9190282415235004744, 2690723303600845570, 2433913875956636400}, + {314860987985756378, 17256734903814295206, 15934782378906162714, 430963730343504134, 11136098731840913906, 17571316264889158941}, + }, + { + {13751698910353501324, 13510591610088790493, 7296230476386677951, 15771194764882310216, 7071348632181406726, 4016223392586971068}, + {5697427461676860171, 8233597763060359382, 11010267185618729313, 3415981542645755022, 5457294468077244468, 225392490383371832}, + }, + { + {15646693844663402255, 3326571016557891145, 11654470234122088961, 15157961803112063987, 2993882145665175656, 8636467418941461771}, + {6779513489978476950, 5971261203840109208, 12247590628659552873, 17305918993021939273, 16119245356860371088, 1321130712911895728}, + }, + { + {11483973417069062031, 6037224851072625784, 15557951376706404252, 2470679358159540669, 12238331311548942969, 8726725576681513552}, + {9571412658072452963, 13081411829441971381, 11182177874732199472, 4596163123987649855, 2508633440203353096, 13386883764628321276}, + }, + { + {13238425823862395570, 9364555424927625812, 13036757456625831933, 17258175170914518289, 10977661896195155237, 2108108449570745277}, + {9531888381573748695, 871050091524626285, 5415169211299494043, 12856340691567607896, 13004810147483829082, 16238406080182275763}, + }, + { + {15371919503521995592, 1023245974044194281, 7465441369206311123, 1659176121116069520, 14352885355523706915, 12313186690485283196}, + {16829625273347829325, 14329982894690398353, 13430769608769996200, 14433580840835616212, 1575399656250103267, 5631450320997959585}, + }, + { + {1308927832832721864, 7645300720509257753, 394821027033666361, 1405179974140973893, 9998561471841590974, 740549317055684310}, + {9206896584584034779, 14330288277576019540, 5482705534907018177, 1134228745870193564, 14319406255178735919, 6723548280696025825}, + }, + { + {7488031393132578836, 4827301471138388705, 13879957958516433613, 8914235600795497221, 9625930790436045227, 14346277439968844011}, + {8799754665963613196, 17445816559731029471, 1345966680255046785, 2291437085360476682, 17887362986581489890, 11089873753828852787}, + }, + { + {2786087897073892568, 3104846214576331224, 16466749382591438860, 18025871964671977774, 11073207410569350939, 15738740251530786465}, + {13634745416070217585, 5695916567870375377, 3278890813204002656, 436738283047315052, 7668575393144640681, 4923414004094995102}, + }, + { + {14851753411270223421, 2820295503131879793, 17134510985746317750, 6635507126737913572, 2826933808807957093, 14392615754844885363}, + {2507906658398669588, 10780876428782550273, 10380620345441284945, 7886790170905380501, 10231944265771711398, 16476655346301721654}, + }, + { + {13070800538562112677, 9974973058199179811, 17174935952981795715, 11396839698540407513, 6936502055882250851, 14166262455025754064}, + {8364117452854843552, 6706032581969460855, 18006192088730697620, 14578422357554768654, 8987670312607011721, 12637025718236942994}, + }, + { + {3558937619125289797, 5542434901402954033, 5561316942068979218, 3053265417595846608, 17622647805733278772, 13078656474266295183}, + {4792933921067825163, 12438312561223885381, 4069107248810180056, 14562883583229266197, 15526204878824637024, 13971448521721856329}, + }, + }, + { + { + {13881233885713608853, 18310267182505878203, 9666283410481579841, 7622892083109029242, 7627364883537502737, 7711280318302167400}, + {2653916418723521679, 2132538432068103232, 7384809380579857215, 3976377314823384782, 6302545514324279629, 4766374634552375286}, + }, + { + {14275770317741623555, 13472206961963184891, 14882629621446810331, 4745461955502981496, 13430642232042183996, 18385303470562194476}, + {3828360326258537309, 5628323622401545900, 10617176218500988509, 3376138133187194596, 1896232731466588191, 4015792813110298739}, + }, + { + {17520011058000060892, 13282870058194119308, 2970088605549251468, 559824469192815928, 13074959133117617173, 13965335622649006598}, + {14278086476506718074, 15679496005431490447, 7405358540117832269, 11499896947138894959, 6967445910717609773, 2473509465854660680}, + }, + { + {14218645527427232303, 16094073974715081351, 14550346839806249740, 17359042213091334869, 8243736883827664451, 19411709369106904}, + {17360637257722902309, 13524203219993551359, 17248055348998851403, 818508604090109170, 17862494632117412800, 7597397595500206950}, + }, + { + {355637953695091928, 13365105901469090585, 11160916490622410120, 2871346391173754292, 6750400526492046394, 211127482213137910}, + {549443043401466743, 11744212739472559234, 4600076762405256377, 12166210043154281415, 11432931513593152138, 17057353378977209047}, + }, + { + {11045556636417587304, 15797122882916606544, 9857941873608458027, 15587445337518508161, 16747134094270843369, 1942895756873835958}, + {16926974666046519651, 17530543788685554725, 1482855329287158678, 4473134732938867843, 16205916098480860897, 14394504722885977211}, + }, + { + {11278672676047883003, 3127364840791393317, 14661695642506572763, 11327535520461364742, 16295126143649156464, 9195965710616161195}, + {2883629345650458713, 1172057357528370502, 3611546183472157852, 13774548359392334165, 13259339647748906816, 629600286834219016}, + }, + { + {7869123316056211366, 8912948800190134731, 7048222560394935760, 5384815822636674013, 8276041929283508860, 10387125700457001021}, + {5152418287465476363, 10375890927386960077, 17017201689085708686, 17352090541805918837, 12744013506722056115, 16512473688480987896}, + }, + { + {13274024037452373469, 13088421719716579977, 6488831580186260168, 12167840477765829729, 4048926237756853262, 10042315437016580210}, + {16990037843046932062, 11650375436582455716, 336515426783093448, 5621387034989961497, 16227625293517574482, 1675664794019173789}, + }, + { + {8998700262199537435, 3948126232667015745, 6110307257346779364, 1830671386111562275, 17929406846170452655, 6510115356319508860}, + {11701924621820907518, 624276597106916110, 7769841773667732717, 12604366378926560515, 8005398115052195134, 293463208231752797}, + }, + { + {3901247269240974390, 8083958895346723402, 13047079326090925018, 10022566546990307546, 16068843007491877327, 10422873494559390104}, + {6431582432115208832, 7003752929540397423, 751812828597354449, 13448257234944313700, 17160453016917581253, 224281597487448015}, + }, + { + {15505836579778927831, 12536765066489116061, 7911004464200661773, 4589459948731631618, 1352286392773861838, 6489162408280759760}, + {6654011263605559897, 8851080956163569570, 14795264073060462823, 14859036427142293159, 7090935575643363067, 15615386349502020600}, + }, + { + {13497550669973445610, 776655080972150030, 3491366472103751840, 16846118274841047081, 13565352443717216734, 16762453283994907024}, + {12654927015632301198, 15345461380888405279, 4403814052111981055, 17852880245807884583, 14115340613623856930, 4860085117378061039}, + }, + { + {6433917609890801577, 10685400209354089382, 10418542423521959747, 3946310041240688418, 9635492151118952286, 9917954643840099262}, + {15291273590135926152, 4720885519447161005, 17166594277722852696, 3334399947768089986, 17999815131740278301, 8130038528325353891}, + }, + { + {6629307447971988422, 5335548022504527311, 12146427842799104389, 8972801394900876948, 14555534637545481678, 1004424158638645771}, + {6032457518228329693, 15568108340121417066, 8949689274415917695, 4542026629771725374, 7740306014723477514, 16661552339503449836}, + }, + }, + { + { + {9224203646647229025, 12662711716512669786, 12163889523034683189, 2867493967382851716, 8230710800753936196, 207192902851491327}, + {9006096280315984413, 10727939396825569390, 7414333640665166734, 8831661749780045475, 10577657048648935168, 7340987637726578721}, + }, + { + {16819901085357815109, 1200308257500709808, 17900351623796430109, 421922693020621282, 4799108745080418673, 2867647093297445986}, + {4820563775913927012, 5975941317603369967, 14072742165336817571, 2287502568922658853, 9587001235227187358, 4290334145148904430}, + }, + { + {3832022561932601686, 7513971564898549429, 7265952414186567449, 5571401045684531851, 5917838096882845075, 9020054854027355230}, + {17666670175994672478, 14849859059336890140, 16575133114891581747, 18181109587632733552, 9353137766555932790, 14224517063829047201}, + }, + { + {11379736539869871663, 14064395773240508269, 15376587550927055762, 12366734842807406024, 7399730532330594511, 16291653033248048665}, + {17533123140589700114, 16874629705534527689, 2772413922918237986, 17100246637189895662, 12295986277440111980, 9880401782043035390}, + }, + { + {4600239529793568865, 13314440057685353765, 5513099208751614902, 10672101316916498735, 7845480375626361331, 13210044038654501689}, + {9289518081528298195, 11080913979513349207, 17396978866245763032, 6250395789173560880, 16771707236585087336, 2590734212198297899}, + }, + { + {930462897994518978, 9217181672387315942, 17307812439812166569, 3609084933939549829, 16131501236725989478, 8757759376648884060}, + {16339503747609931114, 17221587404154414579, 7488052216073421601, 4518526255668709375, 16947062963375159993, 18380636145787033322}, + }, + { + {3629310135461852726, 14261574859150072195, 12180309193984885578, 10259672401517896031, 6494810599317794988, 17046762876694577034}, + {12098574628862673469, 10378154311416559487, 12750606156573867456, 8663374335352934709, 4693992916394743961, 357493171015036757}, + }, + { + {11833317211185183313, 10488624928285281625, 3077329497649896790, 8470872799795652062, 18163548998316849229, 7886285029156450668}, + {18270578357826845759, 15548792140868659315, 193286806456843076, 16001981975120132135, 5119039709260849665, 9668247383740756817}, + }, + { + {9031752377320763641, 242818397681257852, 18241906657254956110, 13839428244885956520, 9537688327632448482, 2680760180422680034}, + {1140834959571490287, 9218649627789651517, 5215286326434684525, 9085211375997438966, 14681078397199707995, 6543087453410959651}, + }, + { + {12771546520335765761, 8608812848025739593, 11046738517958961200, 2102753437152423641, 14544186608765681553, 17802705546689279874}, + {16807367192212923198, 5264409545529952952, 18278421807570260973, 5724995243518092238, 1214809321092318114, 10853502413658374973}, + }, + { + {16212300912408911066, 1517529852090653420, 4886194125638679873, 1212252738684378336, 11831701727622714538, 7716816927665980895}, + {17295498200608277293, 13425634643770440583, 15749163629045239603, 7303838501526289106, 14498496375761955339, 6454509847858940644}, + }, + { + {18202283120945286395, 2039362142522516476, 18347665142857106533, 17305114143802821185, 11943785292295778029, 2743738074951986737}, + {4994513738578570266, 6348689099302941658, 15173738691317246698, 11558529557606048315, 4106465899018522358, 8424813643021743657}, + }, + { + {10424551593037483425, 17413812589282410500, 705854651896543614, 6898508513214864618, 145837834970548303, 2863236542933854914}, + {12835826729643090586, 1958115997725533394, 280738023943547097, 6087206023074646703, 4265323126954195996, 8619647725472919222}, + }, + { + {5732596994419719701, 9319740642492016182, 8478607680989525873, 17406976540323360541, 14044433736883338890, 5843487408713771306}, + {17866336923428882759, 6507956087423256715, 9144061297371615776, 3240732467142651847, 5257579294906270467, 13872281309975586392}, + }, + { + {12720761491485366396, 6776966272901501581, 11463518450782265334, 17251569553757868971, 6624504318270596406, 11185165932902536570}, + {12227483127918029728, 6324632225240663892, 9478714313429082812, 12835053263906838560, 6450777494445586817, 5700121989629794103}, + }, + }, + { + { + {15147392016261929612, 2592171191975946442, 7902428577086443761, 18094018070971638928, 17125131301575142676, 10403369618039505987}, + {7782580376688466610, 4703006815182908293, 5606766158256046999, 9775555907755921362, 18306579346372695468, 18162177355143222738}, + }, + { + {12724835834640470632, 9147221313705790092, 7170406708748588612, 4886504410000298099, 17202448621988755776, 13271672497061292325}, + {17599074313590505725, 3164548778567106464, 14831945487181112151, 10047709902632560980, 80312838214623996, 4488377331349129562}, + }, + { + {16935158672435590850, 3414074563213825020, 14976003461413697269, 16596700862409772375, 1410879114739726020, 1257343276542464557}, + {12595581628483328246, 18321480388540739538, 16111335550040023466, 18371700889666820459, 5114856790954063486, 12702332139456970834}, + }, + { + {9865043235042057824, 6029147174750169487, 4293853667229843866, 9112439374197776924, 14635415243831213657, 16684692725807653987}, + {6007944397888869536, 10548392254307770404, 7913056855243428884, 6568756587625967278, 595480320951638110, 15988239687909198680}, + }, + { + {6682713213932946292, 7716189363132191471, 6386782149539319850, 9799679847346926198, 12768758919818342081, 12149412740097346866}, + {15963729003660447748, 9187947812534491537, 15358865564388966319, 17453292715073688659, 6185316189136789449, 12625900424403229246}, + }, + { + {1176014715697049427, 10940632468289921525, 1316897139158742923, 4659486690798028078, 6789215229361554544, 6689879531142462158}, + {9044301377244887283, 3631078536826367378, 7428358043384314342, 1014081592875127196, 9053433738331035978, 8688971663426964781}, + }, + { + {13620164954367910528, 9966976914653058965, 4659720763711269903, 6933780758465588457, 8151676732205446269, 8752412244536117943}, + {2214917853338768919, 12945088371494225060, 4601901579622551791, 15942583889923574471, 7281044701092345103, 17030848736008966572}, + }, + { + {7835462182282043081, 6752736874837396136, 1692977477997399163, 6932537288585414532, 14477842662688910095, 15049850015849067234}, + {6173531860463995642, 15846342177339735029, 1597137878407950850, 5502938210031734458, 7415040766859401533, 1338338807883996623}, + }, + { + {140753466411001702, 2297914471247852879, 1028738292103309951, 17823758766646087018, 15769363817186087193, 4910055743319677712}, + {15419773815255457739, 12240682779047476716, 18282251230655960630, 16713544303549254380, 13083613671678892706, 3210908138315425474}, + }, + { + {3793265829253063392, 417218602524327002, 4908064786314635338, 1898100452518531755, 2568510715793833230, 14120149645664052105}, + {18146362507954308672, 2545351352320443286, 5008353042150968046, 10916578200202739329, 13715068559100727645, 17156509812140536028}, + }, + { + {9838244599212892470, 12509523685653687922, 10577600670943532011, 15106554186241242699, 12631690473512788728, 9169152683892800174}, + {729650498691277361, 12159677075966957800, 1876936289057209821, 253712351947999722, 194325639412533985, 9244721047496417443}, + }, + { + {2482116316041585169, 2104186195194786493, 7202193418181832678, 15057368806550291031, 8766969826300985526, 14582594738267145235}, + {16362045180297581158, 14472742906561159645, 14204095959602911743, 12991159482136232910, 5359117497638310078, 17218381012207861896}, + }, + { + {1272816448120968979, 9359442561097893921, 3623593162723332560, 8905232475783332533, 5169888391258441059, 8811080810485397684}, + {653572848361898632, 16110636390338543963, 13671121912701413366, 4560998650645223117, 10962017893531637465, 12770222065189975065}, + }, + { + {3116586205508178734, 2050508606805777592, 675566623125517728, 5812215637185565400, 16747763503048114993, 979095159683344417}, + {4422968182455831938, 2371155931114840425, 4264880153383139392, 2245458832441390704, 4962056465731516764, 13785630336035383669}, + }, + { + {11608620191053318010, 3148547465913113704, 4334059326127053351, 3242751952971024244, 15779619493269214681, 16028659557022656525}, + {10258993644149710167, 6956689905416847195, 1219361474591302664, 15358800427564853076, 18412522508913131917, 11320199778311670341}, + }, + }, + { + { + {1763123866941591327, 16900027656783472578, 11315458126277126494, 14678873114899664069, 16385889875309589997, 9608350753469446028}, + {8365156417390395208, 9518773903920392233, 15517769310656023055, 15557612401839384612, 6818638793384298196, 4689490629614769647}, + }, + { + {7029169502144566380, 15357026717875887823, 10958228541568110205, 12991311448110316375, 18163413024255486907, 4423132467880086538}, + {14329574318939096952, 15986250779104246749, 5149023581841912567, 857692231877427831, 6766579494828030413, 13297528373249043274}, + }, + { + {8833286985133922820, 1422352152750949632, 17916971651207587120, 9852959168575954132, 720074577693725724, 16992164406778833274}, + {13658912852753184715, 15995732835663412588, 109169432375935263, 7153134127152350339, 1740708231718983481, 10096352175613178615}, + }, + { + {8898444536197899229, 7363197234870550392, 13859502656863853529, 16353929722932824154, 3563926877908575789, 7083332022656946846}, + {1192602583272042541, 11691701210306654678, 17768977285493519026, 1325595029028298323, 6083154463528028942, 9420136318321879646}, + }, + { + {9357643633468667166, 9777626262221569724, 13091931063589755125, 7867107412773768943, 15020623651884666147, 12089257806028258277}, + {10848050713527447877, 5954793401847436243, 11016251893792937739, 3094692726578056666, 13335998362365960105, 4456549853200134134}, + }, + { + {6615550875184532162, 17802299024252154693, 9829209431047041336, 12066910166505767332, 9658085204117106784, 628187108833105552}, + {4704248642052554113, 6397156614024370344, 11345180222991965460, 6233845157183108927, 9777374421972523308, 5874678333002996612}, + }, + { + {7822288722540972332, 7952138195439261347, 11169290659098881849, 3042519944988229158, 5405508523428790131, 17939670977762776799}, + {2939158258373740623, 12697341633646165676, 13062397760872702525, 17176707327834230530, 15615175546165608557, 8494997402872669401}, + }, + { + {15755839765779794871, 4360301701503507242, 18156570609668386254, 5119543763469609383, 16128603506838286124, 8332918297114938687}, + {2581195955267651639, 4444333459878089434, 14369377281187161259, 8296332340199089840, 16659639448818898530, 18345037457345897147}, + }, + { + {4758277028832022225, 11683847788382241419, 515925726413885095, 3693914633629232851, 1334049558186740102, 9903363943316486178}, + {6186305948183309326, 9076841023132049489, 2269793805693240470, 5838292741631995685, 15624692348115370947, 5174016497034202999}, + }, + { + {13050258405219282279, 16752510433331299519, 16577830848329560188, 14788323970814757487, 3531220681642194883, 10450279241367329525}, + {2241246527454921768, 5961237379972381806, 17018546346619625080, 4693825024640504146, 1766972201817885924, 12382031514930570953}, + }, + { + {14186663977554217418, 15921452897246352532, 1670746882987574783, 10569214187154214751, 8735916617091829853, 4778008137059793493}, + {12230336867909671050, 4713018484448365389, 17202143122302469643, 709747344404349977, 11975499930396914498, 17122512072780824252}, + }, + { + {18302357690866390301, 7110969485339785348, 13942032347351245328, 5693499076189202693, 12668677863581132895, 12259773033298583409}, + {9466495933006422543, 11511978512020081294, 2926450004721272470, 13153116633565406229, 11631506386728977206, 16476012745611483528}, + }, + { + {3807014191641283110, 18120911889946646293, 6904037019088813739, 8534576748083079369, 7162583560481993923, 8819640486580967436}, + {440118242100524191, 6463206891372223528, 547302312933082159, 16377841440620731411, 13653804506016223223, 11521845620308131867}, + }, + { + {5885835281685587260, 14732488327182469839, 9123122330185964050, 7188708702276480952, 11527895050614825468, 16851231088680010599}, + {16816057606689618333, 11155368217836023835, 12624177727172231086, 16592926329340617105, 15223575869568336594, 7273522873166632571}, + }, + { + {5641683582398435967, 4216323241605386457, 3341345023369259125, 5445036994137252291, 5739257813022814747, 14500775521438222305}, + {11851051397499831538, 8952633600654017343, 16150283802430207733, 14278765209911766161, 10318996485999417200, 17994297809574684578}, + }, + }, + { + { + {12250833825141170631, 8405485792690252918, 12864232748520003516, 10788258468673581522, 11856270866800692413, 17612133403939424877}, + {6699634647130975491, 3731182997054981008, 3644858741145969783, 15278087383684100287, 12254545970866866689, 15919262562293099205}, + }, + { + {8514722413728667145, 18324970319650698111, 1140876005394585162, 14935735778864688897, 13574593964511010162, 5249313883818330346}, + {7116828599638239878, 15508924984182297327, 4202376624751087766, 17328701599850278205, 3030575546715635832, 10545614704608166749}, + }, + { + {1712884901460314968, 9844020979159339847, 6421369648072212416, 15296006715190099259, 14597799127028308590, 14859929927669149364}, + {6921131700509172807, 2364609551036929704, 6856710389833844455, 12969257838905572572, 15852094516432192950, 18132001333910704096}, + }, + { + {17180792802575253493, 12600911473819356885, 3979738952931545371, 897682737326728136, 3061890262390512969, 15521523824750041606}, + {332654518124076169, 10307766275571297144, 15915817537662916802, 8907165492937349795, 7857497823831313277, 691902339344201455}, + }, + { + {18398586274195528059, 15773719058798786758, 12837048689216171565, 11953182511721889201, 5401493090861388884, 18440361993747252486}, + {5508661908202617743, 12788348494283175173, 12802197537676893221, 13389178143916130308, 538230151218415613, 16302560609031790145}, + }, + { + {8617925644825956245, 4355127854548976134, 14887476132899231451, 18298212220260618556, 373812720990200546, 18003600147222108981}, + {9609711738554496849, 14532030487725870587, 7449281719849717093, 8469200687346562573, 10559473347725150336, 12054655914827657608}, + }, + { + {3996011418975128202, 6210410771156724227, 16016243241151657273, 17559838693774705198, 18254204752477848622, 5017013903626038628}, + {11728280652213039591, 18003698909909675482, 5616545407832730442, 3102086566055618083, 5927895418024958106, 18268521772846570919}, + }, + { + {4353949603957647042, 9085101501655849465, 12908896052138981424, 17855767860621714692, 9492202381046329533, 6493982940855119418}, + {920636089493927515, 7492445422033208514, 15300073048779302285, 14892838342609729650, 7806275110911940261, 18060719008911082625}, + }, + { + {11178478997628375018, 2538869944843427535, 1225616675740174641, 262785678366031569, 7237556322327894647, 9013462934359109785}, + {13984952488792193847, 11393155007624702919, 7707447211005168284, 9473882403030139097, 3744543934645693007, 552942797664059813}, + }, + { + {8830021259611276202, 14238468777507748310, 8084636387556533453, 16267493202640556542, 11525587568835060457, 10481188297824139279}, + {1115271124367336174, 311879893672637356, 9462111876944106068, 13040825816840411547, 2701770737309674052, 1508687001335391359}, + }, + { + {18280457447310560954, 1268638543685594562, 17105501920321557826, 8343192844895939858, 10103219901911409344, 5772380144868336032}, + {3999072919154635477, 16332682335690661625, 17160109792742439915, 5532275933255506759, 11912464980270406151, 15340700818574378247}, + }, + { + {7968741417565336095, 4204348514802527406, 10647577904042939816, 18088419244287416759, 17463728543868140844, 8457835342186140450}, + {8996396783317142351, 11593744928362394165, 1118739296758409498, 14422226999371433227, 12625902505025381474, 3115381790871861597}, + }, + { + {13500267717482823695, 12826999588757664414, 9339382239162750836, 8128243301916864690, 12056736855957358028, 8196723657625083381}, + {13279394920737824036, 2958586812346659937, 17330699213847682717, 16087607133092967162, 16401864758434998681, 10039877192861155006}, + }, + { + {671802191804153328, 4139782484917432247, 2458696726707986631, 13509154007102964993, 17371423440074958223, 1797826281916833787}, + {11733261849393823747, 4590492414496687225, 11885892654308987107, 10686151607542826668, 1505341691600550175, 14056863349008723570}, + }, + { + {15792482088894033762, 5480086515083249209, 11855064859109876087, 17787767953015637343, 12667533478417710162, 7387754975679279919}, + {1207308571340156947, 16667444176920164891, 15975281376773688805, 12572215559198527609, 14287924549904848354, 15022984237456793014}, + }, + }, + { + { + {44405927858177408, 5350377411887964085, 14455423006632940030, 5051888284479827915, 18289264027550181045, 8742179469806049698}, + {1965293239814067675, 6296618101654059964, 3622639221300896262, 13683273513375487727, 4967193303260329462, 11081296004911608832}, + }, + { + {9099612492305855642, 13667366445618114651, 2368345502115408891, 355808025346965495, 6486699240755468623, 17662463045646732595}, + {13873320631421175736, 5934257143872775779, 5746672378903457427, 3704713689249420299, 12753304704606405263, 3217678872185309915}, + }, + { + {16414774628626628182, 32433971592372646, 4545225813507032103, 6836784835149171090, 5605550610705879937, 5548109210523028334}, + {15540467984433628639, 2461569588551261176, 7976753374299459545, 7581883501804398076, 4495381352011398463, 14281052217405746417}, + }, + { + {11076024185715957092, 3756765523882542942, 16665914572503891748, 14424567262466352621, 3717953767462280879, 16707839638391689758}, + {16892433804273414193, 8340332951294898930, 16313859462232353177, 13057798224010923708, 2523399837778976306, 12671960932364471005}, + }, + { + {17680998608405488653, 16454370296773597713, 13745267107063112083, 17812400946273208067, 6537239167722644731, 18154061302206627196}, + {14732093356815809073, 5178617476103754703, 13809803262147327548, 8824415336739118563, 17720661792494399232, 332116945344768606}, + }, + { + {5904671783816032987, 12111663325909606562, 6880618626717651658, 15875709066691863243, 11314665215817792920, 17321877266325783037}, + {15530273438553475601, 13979895649836346625, 9161871406971555955, 8903894066085514940, 6153387203496648040, 12571794686069326995}, + }, + { + {13016093613163620702, 11300489640845417680, 12781125362901831503, 801538149314788550, 2606593691508046519, 3163799746260716745}, + {7990809893160984636, 14408985047470077797, 347123455262478363, 13992131173035179306, 11786974102048305024, 11698441235974567349}, + }, + { + {11403599927368253583, 3279567955763272667, 7486403755075843180, 14522524358510212243, 14041846160447403772, 6435799871106467417}, + {14030691594486470451, 7790983720309604281, 6582028046670807563, 2822694964154013291, 16463582068215434850, 15072905663834443911}, + }, + { + {3407741673335114913, 11737534300849159723, 6401636175760439089, 12664954507386771017, 9946081910621171804, 5351127802521315559}, + {3173915260803124860, 10290055371665382209, 1714775078878069738, 10809651193197592847, 7937909731024783757, 10117809777580180877}, + }, + { + {16234864712073389023, 5314806349780370870, 4543488410858487687, 16873514203217580096, 10926710397504298767, 9299654171185615615}, + {15666939264737647752, 631855467695092014, 12193734327123054559, 17500404761181864020, 5421672177931299996, 3181351099583887620}, + }, + { + {9865914660144246756, 679604583562241462, 12921501903321601694, 13643679714879784509, 9802439286503205145, 3566349991748818559}, + {3712245593303086298, 13460846416004687749, 9489981526591301543, 3123337991328400667, 4486301121585605289, 8667920552833478113}, + }, + { + {11007825084924597849, 3874134660444866478, 7483283914474628520, 2947665680662261000, 18206338370303112208, 6893224180612988447}, + {15534747185067764117, 14985089178434671491, 3753309356845273643, 15570826499824234809, 4279214973488175555, 9593222558729075908}, + }, + { + {8602395341968076463, 15871701026135700965, 3712441164876432259, 7899892413623964244, 2712639600130105811, 12974295924845123944}, + {12399828322355686123, 18332014219357823799, 16863123510502888446, 771187562270410330, 8994686144476825705, 8686520534353888933}, + }, + { + {5941138557129179410, 16597018407758618077, 11490599640002981607, 3438708541253264112, 2003804289091704123, 16058751440908460062}, + {12804590885840718391, 1477090995170106511, 6149788628468626331, 1665866219994921367, 674399758826895796, 3022438717214642932}, + }, + { + {12649661972779445664, 4013263712261539431, 14554669017811351896, 13226091073296320692, 15697669929212159615, 10884886018241841834}, + {7538090638724339870, 17307058199744561660, 10160210242875571595, 18329720837322489027, 6424491245976098107, 11439659459774047524}, + }, + }, + { + { + {7518960189446694562, 6993197482502760102, 3624948335487031629, 3298603013801970257, 4557303586291885385, 513965581431450258}, + {15631936952275006776, 17646865581595831452, 356541621832294767, 13550122502020347389, 14318884666702203958, 10960356269253451077}, + }, + { + {18088774058581706331, 13144474494348168686, 7944684987556043669, 14803417489453188919, 9523674128757303753, 11078534252464233827}, + {12388996124243602932, 7847055437820113788, 8655700446678160057, 8000087902999810104, 6845432560166828222, 12293660227730163310}, + }, + { + {4121836826461176490, 6993311364897236225, 5980001915532870045, 9191387104629167574, 610736785956912723, 16369608744481332444}, + {8192853368245745564, 7830351299822135372, 7708271704384679284, 8692236521179851966, 4729288028381163761, 15087261038869840952}, + }, + { + {12359675760240320823, 5017343929380605284, 13074869016670236859, 15189571864632066092, 16437432446366423946, 10450373967097078613}, + {6473521102572105839, 10479204864703445101, 9531740430353536824, 16747435491821370083, 13590492053866597783, 13972781732492559558}, + }, + { + {13526124267573528663, 8270416783887521310, 12350520572663083733, 8457342880502864923, 9576612715781561966, 15585819794980473675}, + {12920791615644428441, 14682599939111671380, 4336061001815369200, 12825352708863745934, 13689910154205327554, 1285753843825672638}, + }, + { + {16260954862601212942, 15141701739798325327, 3469367818986501585, 12433553164601433194, 13397654412997304037, 9513462516209648688}, + {8806424456394813714, 3283666376713533561, 12560245143465260449, 17855428090864138328, 9493604162795122493, 12112034994090758518}, + }, + { + {7529184601583900565, 11129864964563043004, 7211397676801058227, 1363637554105090981, 17895272493932277282, 3646615785541938193}, + {5125329656455924528, 4567149614941497190, 11074336456476606030, 15476194487447194466, 7180704409380789299, 13835694922459390849}, + }, + { + {6367771991991911192, 8601334531593085019, 4312076039860441887, 3349991553201651706, 9823362064268535912, 13889910441974079325}, + {15204812249791097149, 6041265790239125946, 12691543265160543238, 10306665514263435988, 14767325902815340861, 10379404251573981879}, + }, + { + {5287451048506707013, 4348959316051807494, 2195731310084877410, 10147908105969953285, 6603704322303743751, 945595692043651424}, + {8176294556983740459, 3760024494015990869, 1596032494450454490, 9532812003368449590, 11266525576652515928, 17675618372058806611}, + }, + { + {13713835993913486801, 7766578236545921171, 14534805690298336184, 5666909695385346186, 8839507885361423259, 4694981751780603071}, + {17723407317459630378, 4443283331360111884, 15519272406098385785, 17520713768065915126, 5696872215251363099, 17703348601524604831}, + }, + { + {2164215638320833038, 17121084597475879972, 953559170830523874, 9824463983667276307, 14122056531227172478, 17378911366973403187}, + {11224042629539202120, 9891688504526640813, 17195883541507550243, 6329564008856258694, 10930601382660244797, 7336662048169067742}, + }, + { + {995921546101717569, 5828224904318233156, 8250787968679150139, 18216596344319934990, 11999487189021985197, 12415115477515701118}, + {15186145702255030700, 2113607545324837959, 15288422804320951323, 6325938775505173826, 10420910094419414217, 1927106976056222556}, + }, + { + {168373835175327962, 5954547085671796454, 17463611069868415386, 225394552152764446, 2307768634143069290, 8042600063379354713}, + {8117902579268801666, 10832127345976105061, 13664993000566573485, 16355061628853536029, 11258951867911128064, 13533986249738933070}, + }, + { + {2256466623088827889, 11490136642947524148, 10955178908605173832, 370819964681409304, 10493984649757869556, 5132627896758472655}, + {6336091067505438921, 10780074837814789259, 16645850939014586085, 8079913953781307235, 4062116077218792165, 9366190569985953070}, + }, + { + {7040462669310098393, 5297122089825027264, 17836763057295674752, 8661859425168585511, 4207236964581867607, 16977003945502762190}, + {13639729604193903699, 3075230971516641826, 12603679116623626959, 17929390171247529438, 4340045624055496198, 12958507460470817783}, + }, + }, + { + { + {13603267959306598193, 8693043305222262466, 8385036129731204785, 17301749092100773230, 17293119319290412054, 7997938435970033452}, + {17626685223448488356, 12525034788314564340, 14661668164222586257, 3322104272345643135, 1609592810955141849, 2549513802617457284}, + }, + { + {8798435167269930640, 13070514712052083568, 4736461614042760363, 14206975230185412328, 133298083050190689, 3881702371340834770}, + {9708307132029784886, 1190148038752103456, 6413103290824094803, 13481632314215227255, 13825269422873963023, 10412305108920689107}, + }, + { + {15788775674106557193, 2647031410423879993, 11824234196304518021, 16508012954631132049, 2851858215553102032, 9031676847819265350}, + {17056269066330629533, 16578781453141932588, 12149327146251727097, 5603735625820741662, 6198349307184960758, 15317416179414320750}, + }, + { + {12101899190913284916, 9608769495503265584, 15201140684891239564, 6542484635045229965, 2916993459978592676, 4802334108209352673}, + {1973336680768349386, 12679196129410828967, 13463385388413200455, 9654153036115837558, 16342609945030294957, 13480152702062555703}, + }, + { + {2899711161363462805, 13301605990446182752, 13405176039316030122, 12694240906495353636, 6028874869507943666, 17436011221762298446}, + {3799912876591532513, 3287947124836704136, 5920239729516121972, 4658851572162401105, 16206677545960268727, 11754748256988512736}, + }, + { + {14829746466477852272, 8785495584277675921, 6423194551544767939, 692454830006456519, 231353646984097766, 10478691929706490052}, + {13187510740839857109, 6329453754316993892, 16082691749983710504, 9140500440454110398, 1359919744529707405, 5867635887532143880}, + }, + { + {8283409025155305021, 8326153006408425638, 8192125950875031557, 12491925510388767602, 15318184472466947145, 17174845401039236071}, + {4024628118229282985, 15541859898701908579, 14997151867577432677, 2742910007129941237, 11281936698759777841, 4053513648766184443}, + }, + { + {17504540629335028708, 10934158903032446529, 10440102841886099171, 14945242719790343095, 9216441307898357664, 9638980805394197765}, + {17980359344968817157, 7448102317851383292, 6074361339806645900, 13629660188149307441, 13004652602731784581, 11547813582289855464}, + }, + { + {5835495230485007597, 14350772393378726062, 8747233229858209651, 3317935002292804215, 1073070181947964939, 7460355407911594663}, + {13395345232316724375, 10346078775799124075, 13798478435639795560, 1629058324627559163, 14747763100431935680, 15299073526901740916}, + }, + { + {15651423385292143727, 4846110050285526280, 8366261324209130800, 18348748562705004572, 1191482937147378439, 14318163684990419654}, + {5828426112534678889, 15752453922521080195, 788797916869961805, 1050155050965406592, 16245505178409635417, 4624404334332384586}, + }, + { + {9519649412281579636, 15518026566172043316, 8230071711608174064, 15501328228846578396, 15538051064956598926, 8638696845481203911}, + {6545591773917305375, 5939294308617001483, 5916517198820221821, 2183353220433638210, 6608710467805325002, 6375674496051123629}, + }, + { + {14599741493080584733, 265043095998502009, 15590157843765788733, 16283462652920133690, 127450980034769700, 8101994233918053876}, + {4354404904705327864, 10527772165440476297, 3472213175562207788, 14083669454947716927, 13275423539077686885, 5338095862941712423}, + }, + { + {1235012355674231855, 2090134554838509585, 11863415298782072711, 18023496095060787824, 8410498900143253177, 10594109983238360693}, + {17550081202781797913, 2173651076708559007, 1186671825722566228, 15233030551314777921, 9888771203060958359, 15468843840302879988}, + }, + { + {11461190636282409817, 14308116091595492374, 15509337886967718014, 3305520874657987597, 7626903910031076977, 3082923764612175270}, + {14811303431165168732, 8838542203092895295, 16984937260064502824, 11714999386942378861, 4897363879848520603, 1001099817032265897}, + }, + { + {3637674483014131572, 3117885916559390287, 13017322864107767485, 11567467141438885182, 4996993546175421383, 1767669170792783157}, + {6426400534208188423, 18081501770343787332, 6628088911946069490, 15549150917856099952, 14206743374618728130, 14181348296669151521}, + }, + }, + { + { + {7989198143366045630, 7010829800355578048, 8546053455940578601, 6881887443026808498, 15042102422681491309, 5420645403520488369}, + {10849333199099746435, 12113569487191320877, 3246658105605143184, 6336537385102402345, 4597429228667676601, 5272271520244435977}, + }, + { + {14306638724632781511, 5757106316922152519, 17125373792178988648, 1583100757864258958, 17360083944987639843, 3920600288799646538}, + {3331960036348075865, 16584227479356001542, 17306396376373940447, 14759099067984370905, 5812518892646247762, 15782678322655568927}, + }, + { + {5413193268301814099, 10713883248352187164, 13410675108716405078, 3585734128190446197, 2777085511140743921, 1755162931158100151}, + {14101275991297185856, 1707557804525078570, 1967729659696736336, 4823950423327664451, 862801022254850239, 12435639820717247064}, + }, + { + {306679465712635984, 12152848986799385191, 6883719236152567513, 12305822533289967588, 18402162608409722972, 11108631399674712772}, + {2571321336657345725, 5282906424085283199, 14072199601206037589, 6326969628422378510, 7257345697465293614, 15327414546710657910}, + }, + { + {12201144960808694291, 2266284960898988252, 8424553153700131642, 9167059607375209949, 7355136040026239658, 2541478780035614622}, + {16506463005253913043, 6582690723164939915, 6599951765449856592, 2404559737777750863, 8780347760287852096, 17846128204113467575}, + }, + { + {14860969561074928871, 4809849983665237968, 12242711789150271258, 13843481869678455226, 14175051524655250463, 14334810640036579932}, + {11575444057028938068, 1682341910648266103, 10938858063273491391, 4341242396287801217, 7613196676950010801, 2500752005513253600}, + }, + { + {12440061027889587972, 13927371198268500445, 16154935051556123915, 18096961537601388555, 8424464497516729675, 2313786208528450307}, + {6509771027110309267, 3390162382665127855, 14587068644788920599, 1328169351793106371, 10509868205576387317, 2765759870517196435}, + }, + { + {2900406544253496059, 7303698760912649984, 8691265875763036027, 9197553224083694706, 18352617242438717063, 14750961326114925844}, + {2499601025675361076, 8368427257901887897, 18132146080106643208, 1110936544903604055, 16261680704811161606, 15090938849013897133}, + }, + { + {5870727586880606917, 3817524309119245910, 10695436097727319065, 16784573325267031769, 168386867463964139, 18415971011491165889}, + {13492479568749674699, 15834291406704295009, 15705574100744201096, 2398014061321015822, 12468258805517123137, 13991053711847966585}, + }, + { + {4169557306961711707, 4015219248181969243, 12214392270444620774, 16050078587473704262, 2784750252993704422, 17395896913298686268}, + {12843958296305025565, 369831555843170916, 11677678398942896027, 6641755134933316997, 9109097098896451407, 4781721487698386903}, + }, + { + {1392099397992149225, 6653317869794434155, 8261302057061700743, 17076785984088590530, 12214500026419464516, 8183114113550743923}, + {7219173278975390146, 13854678885102808519, 52819572796104662, 14959508682837821268, 4666245422256363222, 526398188884660107}, + }, + { + {146377064121748072, 11117625842528721265, 16508297934345517505, 13963807611317318780, 15513104757270430459, 9486443679271300608}, + {8499000076286979115, 6314693643347125094, 15660966474005923460, 4849442041573028425, 4417660487771261375, 13534789771025100765}, + }, + { + {14165452728554216170, 13694105377023575661, 12112553140758207627, 13499340770701043478, 10416006904191195926, 3543462727896098709}, + {4066244216336615064, 6569278217794074558, 387967286518318157, 270108989062251217, 16349063922035707389, 12438514695154831396}, + }, + { + {587040577811041823, 6936770533105343364, 16776134995012734224, 10277362302644779257, 14649614714574251627, 15051066325824432588}, + {8291129711414316681, 9551002213274431576, 6676196382269508743, 6874374105452669031, 14751197759974741889, 9029571467065764667}, + }, + { + {14428258617344372219, 9908056332586719435, 3405976719581642508, 11387547871499772614, 2994350212903836640, 16490884790412572450}, + {11355150127282843741, 753093375853717498, 3493937923504423687, 8754398622695613018, 10230143170990690589, 8594587862090207256}, + }, + }, + { + { + {12025065147930696764, 16395321909258498666, 17254275975074883492, 8698446818264119462, 13921708813901601023, 11317527677055938762}, + {8372735897264020153, 3995509821790542114, 17844440857746011127, 7150508535332996970, 7856356095447891107, 18425881274930431587}, + }, + { + {3868179882159761840, 2264438469296879600, 14040732472308090308, 6176899669975159097, 7687708097392128226, 15700212396478219258}, + {14432188665158358139, 14093430104632320380, 6658435239629637912, 16817255952598430533, 4042186219830704930, 5581603010754890001}, + }, + { + {4194420838030196541, 1333911740513429952, 18216514596089176140, 5522562721578975413, 14019454638832409935, 16180950399634304052}, + {7874407470843020638, 16700170713448853543, 13238545221113708433, 17341343942946679971, 2492905945545894244, 6150964092835885281}, + }, + { + {9160207688035903546, 10421934692844981887, 12973343349121023222, 4588457373452478724, 8930230292368920615, 8764471311578947963}, + {2287273259416958217, 7105649602824330442, 18442962768087545765, 6705276737238885061, 577380682084602753, 596787676998246106}, + }, + { + {663478452777260243, 16283602145029174982, 11124685403360893629, 4781563535459832423, 9323851769832103844, 18097969442952761286}, + {7837190984970827968, 6643489635464035580, 17874774866954327612, 16430201046158097201, 12045640219457858446, 6223326808284158866}, + }, + { + {1657492744835373106, 14305521459309102400, 3869067393311496051, 10037235265268002078, 795960391565742762, 15570341341842321230}, + {1416215615272420305, 3844160609182024535, 5420451137511849586, 1949162974936638642, 8451435764323596076, 8788000062158561339}, + }, + { + {13928009376574601896, 7291171400028186761, 16473025605005992076, 16638477947212814985, 12047811767976047467, 6878298473296735831}, + {14902080744924353595, 11030229314796494659, 12098457778174714596, 9424760405850702049, 1497914805837158259, 3249894799792534256}, + }, + { + {3590247938838498240, 8806692635119047359, 1698761057036684647, 6343574101558802001, 3746591523512207350, 16046850941587493893}, + {9375703075091035250, 11484732524515574701, 10605373578002057385, 1718556460448813872, 228246291976542303, 10311368155034743860}, + }, + { + {13497031464860502366, 9397761439599875485, 1318541732049664766, 15374121346380046672, 17717429548790284664, 5159388673283835821}, + {13355298244502234884, 9645381144552778188, 15577838213165745473, 17224721347234155862, 440552977874015809, 3485586753351733297}, + }, + { + {3516261141390918044, 4335927420212454420, 9153235025059865419, 17728981115683781993, 5407851417900531604, 15034043952911725703}, + {8360898999522732095, 14154807375320553311, 12720119837506596047, 17979696399481662488, 1503715168515766653, 5169207090054716326}, + }, + { + {12162980084934091895, 4233957881103578519, 17170356997174783866, 4243094926092018555, 16613894431916307329, 6606193115702532471}, + {11789634164556738593, 996991792386448418, 6962245779712200787, 4974442952401074444, 10897550856395547118, 10995646432875528213}, + }, + { + {17102632525353385033, 4726908628368929907, 4247885372815903947, 1788394963141125417, 15102348628480678182, 15128367306207476457}, + {3972599649912410141, 3921603030106002483, 161288956218192081, 7338348096295758314, 7143236202635983396, 8624888890090620099}, + }, + { + {6331943491044463866, 14228029352154794719, 2947037856011623469, 11772679753184455432, 7465692292318631028, 14289953244793202905}, + {5134250825128073664, 17656488618598423937, 16854119307556681012, 2421796355445999202, 15424387029136720472, 7987182987578392406}, + }, + { + {2608951835161989111, 14588356830133736122, 787581713316032185, 9896238476586952494, 4431066364605451791, 2903280281635265356}, + {8247495622914418748, 11683109383984515972, 11561088616384052872, 1149723125258168883, 14529556212737756877, 8912094569277399627}, + }, + { + {12789135954360228010, 6780075827365568571, 8810224435698828502, 13446476233477343302, 7214376817335187762, 14458570598448093615}, + {15615130062596991276, 17246585199766548683, 6890348740309790991, 2462037107533762815, 14348419451565630896, 5342642686877329738}, + }, + }, + { + { + {2905464083126352106, 15382523776645615659, 4208326436876253066, 18269526693635159971, 5790854390728730522, 10746880826459375258}, + {8662248081050622522, 13826611872785505390, 16436929138283976510, 6326154269244482967, 2880171501306902421, 6678386436918333169}, + }, + { + {4081558640315641247, 1910870639571469881, 6877171221443835842, 14157529767685404063, 7740037116920621887, 14764919955763458331}, + {10267569861886921827, 2529844482184019983, 3259055836051436011, 12721359948163822535, 9659485045930382444, 2682511237837334805}, + }, + { + {6257278162168451228, 14804471928370352903, 17266243102614466221, 1834384770768531640, 1291836003048662370, 6034253395610136614}, + {8743066898222911631, 10312528166509794599, 15491664890314077124, 9459311605542100872, 18188244670802339459, 11837284714306023066}, + }, + { + {7384073074546884058, 13342536901934035362, 1796642291707654196, 14924003300567702780, 17696513874113839739, 2170126944979395945}, + {15655425421070558346, 9046927642313144782, 2539141704545898189, 2313651783662755544, 10988582385563170062, 10708895281446879013}, + }, + { + {8049823402121284107, 1015261354744953141, 11001601026371351857, 5188408555842360927, 238307893716713840, 9306355674483778871}, + {4882696385991861541, 10855316230146219920, 7297309210275934874, 2129929538911047623, 6105877736586220144, 16540174430975243109}, + }, + { + {3846553462991609521, 18287444857448547300, 4860654016674888150, 12102465094571524845, 9665319422122056880, 7341976002114379270}, + {11450690261526312033, 14359620265055539834, 2129613678351742251, 4154310935547659871, 17819794191738178105, 12470777076380361738}, + }, + { + {1820231603330482333, 8197912473886688932, 17564410961062418802, 5547060850511847496, 14784446920715373986, 6744079834192692285}, + {8045763461421446101, 10946745933502697155, 3334195578263537309, 4155813158460651681, 16304254047867190720, 9129755894729457353}, + }, + { + {5858270368901180686, 5650671310031369526, 17358036986724164367, 12272486751450316321, 8118942123504245440, 7605341247988122771}, + {6460053483168551327, 13974980628946427300, 15265461046774765196, 1434115779622874584, 18256968071394468929, 162814016140883808}, + }, + { + {2332162608871511375, 1868148336815015635, 10688622518437469162, 4535570520634779462, 5558414024910369005, 12846608910105978921}, + {10182583164281883737, 10225962215828780864, 6647302228613027609, 13926246345815428275, 16444874778110264906, 12426728125906820495}, + }, + { + {7319356743643981758, 17290801891240533282, 13680538635395325509, 9431898857998460284, 9654052594732493588, 11216128628361019165}, + {5480652586120031716, 12264251589473554648, 629460023613249876, 13888625092415164277, 5982727213326537179, 4575309381338208673}, + }, + { + {9318690217895942273, 3885888063527830607, 9646742812304452818, 18262479706556902502, 3620133047155459299, 18388160719790129736}, + {1914761448944519470, 9758008627466255788, 18418420068679038400, 12896122466120836747, 10890035278343231294, 3646620616965601722}, + }, + { + {7320055252736060853, 1303381685630079106, 1389396534790493913, 2784451395900022634, 12504771187503822515, 4227927385881340861}, + {12071605771892533802, 2754948426319968897, 11085204177816817620, 182697453064193454, 9227505917134720328, 10621984715679088732}, + }, + { + {6220826937720121878, 13229947210201087101, 16420906931171635230, 4228069687275537145, 10649909068460962812, 14974797380841429985}, + {2099387861104913886, 17576472277696906704, 11384913496578412357, 6794363617398915145, 4335808821084623592, 9733284623560895058}, + }, + { + {1755145516295475548, 15247893042361836531, 5738179788894433569, 11279068420917658317, 4290389521159722087, 14365410757465934654}, + {7291605289247002500, 11812770986542211322, 48289046067440439, 1233419001099601995, 13182799439408327769, 3066909062077171440}, + }, + { + {9251396949650789431, 10964669964980210420, 18441875565843264347, 10766527953487419221, 2053504370587058697, 1120548999764652480}, + {13156388621520434359, 9488348829267331096, 471226560476910099, 16729073468825516463, 6843824047113762587, 932518740561235009}, + }, + }, + { + { + {8005022716490156292, 172470276668278570, 12027061491585017361, 12668206184074529368, 2383566891938055597, 15146733507906754355}, + {7778895097740687136, 14251829674046124789, 12738613561581015447, 12051618485845136097, 9897878846738638320, 7907234926402663579}, + }, + { + {10065252555514097915, 6386861198439688962, 2775722427207394938, 17952746237366567827, 16390357373389037601, 13972513434252720715}, + {14700210881752165375, 15185652113659869954, 1923970725644198719, 12211789976130827254, 2585886428464543151, 5288489885799434816}, + }, + { + {10567691911424697649, 16971243382477786521, 10251841113143443125, 1687737920922643646, 3746145726913279586, 4786791138611857452}, + {8476041976560261273, 15570593593290952605, 17648077308436960175, 5839063770228102907, 9706501119134890748, 6475897123160711932}, + }, + { + {16272681470773409672, 18157143820860266346, 6874350001337166182, 13501252460259511743, 17259688624947069488, 17317925810681384843}, + {17458673210103455399, 8293651101654188440, 4287591827563518608, 17477963865483680843, 927677871568183454, 4257762449075391782}, + }, + { + {8076033399227106890, 16533143032280607906, 13521927650080284497, 11510742235496409044, 773074617642472847, 5480268378661415914}, + {10560774877949781007, 1551950937282276704, 699681785268341449, 139399977164437031, 6186795762861491620, 10490971431428917955}, + }, + { + {9190090661907342314, 10353817139393866538, 13722719350565763089, 8086989101739556304, 11831125735426804282, 6527360398769008658}, + {15661687200097987699, 17883372000534567314, 18228449294037686953, 16276062303086046777, 11067473153184484205, 5270793026007762758}, + }, + { + {4644322026860926003, 13840860549436432899, 773219189435319969, 4214545261061108721, 7349178605060789384, 14108663996709041985}, + {15086368808776131018, 5873313287260733157, 10958955294835479142, 1029190239709350397, 16575148148212140239, 548824197340738121}, + }, + { + {10538023507650655080, 6405097420742099168, 3772328850901597675, 13431850381701237922, 17301482879787833065, 10960182504575418989}, + {3458141607490423836, 15983729892825441020, 6674827306666597406, 6998631059837206710, 10452310379665360233, 12442577005422810090}, + }, + { + {6357449289782518654, 5562676255948928403, 4267773668505879348, 17042466998439942315, 15445173922414204273, 5045693191253100284}, + {10888452729312376066, 7286005702779769520, 6310396517254538489, 17973884204765258948, 8552375160420880806, 9676186921102873385}, + }, + { + {5132936755125381856, 13632397944410194731, 1195217251618711717, 14192521157173466766, 7136777102122506464, 4992685048206006386}, + {12758444670751645174, 14211008273195363585, 15176937626622599827, 17548458272828201751, 5057260891126473883, 9952036262648196850}, + }, + { + {16078498188091009803, 1162033447512069931, 10059309132406299500, 8829937177340388978, 14448159399458657941, 374069359661101813}, + {13367213118297441109, 5274140197674632268, 16907854435294080281, 10813040207319437761, 17981016036466195869, 7390729432234187734}, + }, + { + {927041625307275433, 8960709029455529859, 10831922670190955819, 18290821865497267571, 15356340336167722251, 1277117312667074566}, + {11345332917031878869, 14333153309564749909, 4757616462511080414, 15371264136186622670, 16048790410218032652, 6253972033361590906}, + }, + { + {13515732918257273776, 13723630809424897822, 1256040724895856748, 741241381320040022, 4179658714379202158, 7700440732059923700}, + {12620782566472061643, 8647092247759141584, 14556418162370042196, 10398569400923172183, 2942763850561441253, 13510474539740910285}, + }, + { + {9284152513908444951, 13364815009916075834, 4919960874500389956, 11846737451875562809, 6206281447342218811, 16898214858205632546}, + {4777300224767696450, 16738332457351222374, 2425414676554916356, 10738169294712527458, 8592315599382595498, 779347662452931693}, + }, + { + {12657704884116037495, 16629278614392996531, 16644595643705514648, 13083603858484073418, 5531378660228117371, 1072715305930583874}, + {16281698922290258814, 17101495949789370442, 697325071236988515, 6834733894203542328, 16874883980138472052, 13765652846823513818}, + }, + }, + { + { + {1443983809817335050, 5159436179287288748, 8718823893455992642, 13859422481759839054, 16821370532543822004, 11312232963165366867}, + {16799784256686916142, 11063086467296440173, 5409640362054745615, 1744861157419261406, 9159074957446964246, 14640106507936810200}, + }, + { + {2855230597739850155, 13620723665924576268, 15633539828476547165, 12790587404740345825, 14929382470136573230, 11024875668098768390}, + {9757666174600838731, 2232369412498935956, 5843374372613155338, 15919240107279516647, 16925041227711211671, 10150031711225457751}, + }, + { + {167838721727610261, 7541800216831159956, 18111323457358615697, 1375214001809563574, 12793193868391341616, 18288999141676090200}, + {13741005234449322878, 11213622750935649716, 1522802528596667168, 15269019072730025083, 10719991413129377137, 15521380803604598551}, + }, + { + {718529776434363422, 12683359777452057212, 2804554777590895595, 13664120639095226495, 13598640112814221798, 15241444675921322490}, + {8810840946828957504, 7811396362330849266, 9645885245397761208, 679907887946404609, 13039332546165252336, 8209508558765517234}, + }, + { + {4626158970998280523, 17779366207669178780, 14066716967377837836, 5541345249351270224, 71760835438433145, 1781108686838293059}, + {11015261109851457791, 16129646178084531488, 10669691012640045245, 18184224459278962224, 668895765928111620, 18347537117071351865}, + }, + { + {5383950189451203046, 10844133140951324068, 2374979840933487414, 18242105404652163653, 2153887761192573295, 3314974606006034191}, + {13575532204571281217, 2247071187256305144, 448195274692108969, 2053979169079271594, 13812860435287696334, 1732389448089431296}, + }, + { + {4284546519240384782, 18250416328676695864, 6075393821764526355, 6803234443690359332, 2308015705795216965, 14282768041402275649}, + {14692234199015945763, 10982825331872323691, 16257836708673068915, 9290937795903983017, 13215156669957704998, 13581066011281717289}, + }, + { + {726662160657361021, 12794593883926219472, 7861799432245846591, 14620923059626590643, 13564033114045541206, 12056825063290520144}, + {9319654440973526666, 13306574040007137554, 12383704628262510604, 16837061611201648320, 5148924680488916382, 757589831530246899}, + }, + { + {11260142852359901856, 2910994799586619654, 8190175402543023708, 10282746214391918351, 6197128196041568622, 12103744805432714925}, + {2754925794608765953, 7213719752583096226, 12149382823057292581, 6622803011412572659, 1043029140538289242, 2160363121257772533}, + }, + { + {3959688648190130918, 8473581564018232725, 8102575542433283254, 17478136759519300612, 10782499745742339984, 15960018897339834420}, + {16254514834142148732, 7808901449511931787, 18330166307905077063, 10432644456391460073, 12246398526421152951, 16631198455707802675}, + }, + { + {3447922898029507114, 16051230154621670189, 16072905312851388355, 15031563884401549512, 14706198388315798396, 7847298879472932181}, + {14334929624882962482, 4207755459965567091, 2727607546440637589, 11028268195413273994, 65681139350480862, 10388523824998445409}, + }, + { + {13621028160954218188, 9189281248079816548, 6559689192872320191, 12511220059980672697, 15021931978161570527, 14942251476194345708}, + {8032030039336040011, 15968186657808771957, 9377328317206799246, 11373269023340235305, 14864609151221526904, 12259184676083236409}, + }, + { + {4993001240436128010, 14622033823485440043, 1269131542761241152, 3340746980531933825, 7474601841448992000, 6720228020507007935}, + {7637406401737657019, 7627450969186809480, 16514017994864839608, 4814188734303098279, 2484761716517021839, 8799093000399717716}, + }, + { + {12269127574265060145, 9724465093155898416, 15873065313448764429, 8761869776521026054, 13485847957822391857, 2439524426319009706}, + {2196722629873916930, 16606975023104026874, 14395842146577003711, 8980633514374222856, 14337391476390507239, 3245539094489483683}, + }, + { + {4586284023246783172, 2578135446952921534, 16829066520710412866, 703408518185354273, 1484970151848468921, 4187259876483048418}, + {16026918465565392877, 12845800470973132882, 3563015620264375279, 16242852718263860671, 13711297870624837478, 10327260052313469500}, + }, + }, + { + { + {11907264597133981686, 5345484317343243432, 3526298189589605651, 14941494503371346641, 4390348405627321537, 3075441678856402034}, + {9143920156043167932, 1663991502233570797, 11411151526779617123, 6295062208334296723, 11167953874910400669, 2847239470361941655}, + }, + { + {12048307220520866404, 10548739433510366959, 5828937682586289028, 8259138483713638196, 1664521593180101667, 15076565371876670808}, + {9031856040208856894, 7347877633160823775, 2684001693679752997, 1187394758632407893, 2023471202170921576, 11368770613720851227}, + }, + { + {17683555864724676435, 13968533138851757949, 1943437173787895091, 15827749049763045012, 6987423277000309812, 4926724831615296075}, + {17103731276906243966, 10968826448844601259, 16352070254497671124, 16551824619482611318, 10381849412124093967, 9436665416229949512}, + }, + { + {7048379827497088065, 7443977613807482377, 15322620479477551149, 5013135385875340566, 5747364795223736553, 7862606879963470164}, + {12609816404493593258, 88582923555110046, 9264042141620870961, 12622483743145618453, 36832241874005927, 11846454950663675962}, + }, + { + {10498869048482452833, 10139776276152664444, 15056732056726485889, 15099480040493702355, 5399073333783908255, 18182172735172720788}, + {13323470181256898728, 7293540973022589120, 1981283917056275351, 1683846209255518469, 10681059793003383268, 16940960671858675128}, + }, + { + {11079616827562091047, 6298929519625833683, 467167558554168186, 4358762903022032877, 3416306995690695388, 14393771751405339556}, + {8542268838893846242, 13985040364793095543, 15595485032978442778, 13710848327370489861, 12647895656520219232, 18141386123053510590}, + }, + { + {7421011150990207232, 11463423897464684083, 11777398400930295903, 12887147976139911049, 13452389883052007052, 4276539450334756600}, + {17003232901404646154, 5648172435840152002, 9060551298958599769, 9865768386391095478, 2380928329972073322, 16806909077051674163}, + }, + { + {6879794746887651427, 15191659499793488108, 15434300527081888859, 7856295689590209271, 6774603981548851786, 14620245528126721402}, + {17675423419823628072, 5010454868432987998, 9315026554545892356, 15171741100035630176, 13503881861133354654, 13836586572609238772}, + }, + { + {2081093758072482234, 2160302331720847475, 1771001500045437109, 524929417164114132, 948139338327583506, 13116239640907621525}, + {2067558540785058447, 16015346840737264408, 8998465241460291405, 3205597488226039915, 13132850068494171809, 12550638131827261524}, + }, + { + {11487678613186732166, 12226538283374456197, 386046383678908710, 261136384486182248, 6073820936063889754, 338089910147739013}, + {2204520790471760666, 13225443348522804886, 5533826822105659739, 8067241596100405272, 17056747808692642524, 7928554988750665570}, + }, + { + {6926667811451225445, 11361726998764751598, 11858255027279547942, 12874828932074051770, 13844212609147206062, 9229674123496154728}, + {2157148641194346791, 7533189974437599411, 3818533723919763688, 17102113454166535674, 11957918589822377676, 199286897588186765}, + }, + { + {18098297521262853561, 2549150080497419905, 1920476418432176737, 12406241507983538977, 9994324328270480744, 6865216726931218199}, + {10882517499218691272, 3878271624739672851, 2651991057058067418, 8041121093439073066, 2863398953389074916, 14090287437597767123}, + }, + { + {15691539065269187690, 15926915037487623140, 10414347487737173015, 4830265708288246683, 11328595530368816451, 4903535768556567628}, + {12008565653438033332, 1571218720864129835, 1840887482550755461, 6912046034772469524, 3644063824758321256, 2126322707583833546}, + }, + { + {12169143892540109486, 6002799381834121764, 9166177939527749537, 2717071050858554, 14132387690398409212, 9461668085670424152}, + {4615175463679096657, 2777593348175259115, 1086524210167200873, 3727975968832889444, 259602294277541227, 3220284105548094890}, + }, + { + {7567574313834290099, 8145437034220375349, 10888802157352801074, 15444274935766241808, 7033566652389697721, 15084515844524348642}, + {15010111241306351000, 14537704976709260010, 13901878997182787975, 11697236875339079364, 16516786017890903855, 1661580686211855443}, + }, + }, + { + { + {15463648276913935878, 4382144021532630330, 5071136388542935899, 898357497003506891, 6306262877201485580, 7503267895380498351}, + {12209894407081504812, 13537298049306094654, 684729356387257364, 7075405619352396484, 15714299178550944331, 15696888615882072580}, + }, + { + {7477407170849995021, 13555863987096416386, 8646006234528633039, 10219427423139282479, 16098841852404237961, 8497637134921782372}, + {5309688570092265610, 3976413109977205320, 14825158186275338256, 18330027746161861298, 8379597551709481692, 7776375825952465168}, + }, + { + {17368205043853313911, 11366480305058719483, 3986491568217663545, 17776307296855398379, 18166640678790561016, 12400054106979718042}, + {14701884885297130131, 11997630432923609339, 2316884967752005589, 899451448914269587, 12320093108807155483, 13224130717820204708}, + }, + { + {2301120181151250930, 7134427926629173419, 13652391877351066163, 14358476347223217001, 7720954555948039363, 16079187223864015439}, + {16130714394389204488, 15060521357793404892, 6157723303371622460, 388433905262539304, 6397942210441116350, 15870010555361278310}, + }, + { + {8386588512253237744, 12398600073071431889, 15704645810442703641, 13918516392916317159, 4048204874387041555, 14789502552726712590}, + {10953546364075891631, 307391290824075890, 4085950680975341402, 8528936851895154413, 16191803140891684852, 694681636582541066}, + }, + { + {4052072016637665509, 10815871552988988571, 8015406219413895615, 1996664536108251392, 15055672969658133547, 11345388978032390658}, + {3833741327008156172, 8078127745144700769, 18219007769895676040, 12373542083253387973, 10749960526614124693, 5297937097120834946}, + }, + { + {6473608164798697997, 1704324113009551078, 313510886399003784, 7482485442761088384, 3630467062499177474, 17889206319568130728}, + {17813422549220613506, 13365489546100356563, 3642293795923051505, 13366391632389811062, 9309608098424960759, 15583860066261322393}, + }, + { + {3920285757492003115, 969197763731201452, 16178147428848039825, 6611676964264587135, 4670040846705473526, 9965087165592606467}, + {9385067634888736531, 17301457722800757500, 6213258855206728473, 8445301014191943446, 8142518927165972910, 16360532488199989251}, + }, + { + {5265906353635046495, 4989115549924370545, 7716029377102384472, 581999053178428771, 1927216309428257662, 16726029285829946215}, + {13608385105784378405, 16390741907364333262, 2050639151388485496, 11880595111878011177, 11418095767233061977, 6193391483702304675}, + }, + { + {983944277502152387, 17618013366706679742, 13527856424316363938, 17809004578576556920, 16807595463159644124, 12659014490378234561}, + {16660215596018323668, 1845548200977670934, 14981347628825634975, 3292665052105349975, 1255560706381478700, 16841318968187590600}, + }, + { + {2665344548535488753, 10749679950323224770, 14480048826753464948, 8103744201764603054, 4292621633536097205, 17368247036505307539}, + {8629653144199349731, 15713695068648974367, 1391688109689860259, 17209900783908384199, 16396814162862442509, 5977962909365766241}, + }, + { + {1765723133486333001, 13553591410290383834, 17120307789275811780, 5867585200918539797, 10340378507202539704, 10417992971032525897}, + {5521483192544399925, 13339071700237022049, 619482636797119427, 3159013689121603910, 5024096637477394285, 398928734167456668}, + }, + { + {13703486582158429978, 4835870969542931590, 13849753374989811859, 1366566739320000236, 17404228716488772409, 5130516311326930222}, + {6137130478942191139, 17716584582497907230, 16134870936885120581, 12112071202840308227, 7545387975022640244, 13816774847829473152}, + }, + { + {971030984593369643, 3220347373596070794, 13959149202405537534, 15516864884375555266, 12029622495808712626, 6647055389116471320}, + {11132585267709726879, 9838206173776721087, 1787590871969783091, 4539972049341594577, 6034675663835419496, 17293055497219064814}, + }, + { + {17570642940564731459, 8213552062444081653, 15593226808110603739, 3879030828893359677, 13433601001024396878, 4211122738890174635}, + {17934189169765241763, 10790041884906581465, 4207951857220635543, 12628418922625498827, 3341984002885074575, 6259488712494116991}, + }, + }, + { + { + {13403761680618042221, 16536343759299396957, 17972613761828085938, 13333143634871897494, 8217080844173300090, 8327319758336938056}, + {11266549251857186424, 5632462193213183426, 12437134888406006072, 18063700593397823279, 18150635335174302985, 8092211028476756137}, + }, + { + {1207108350681107077, 6429062998832911556, 8673250477723521447, 18170583393512312328, 3550801055781941700, 11719672827257672268}, + {9655111182266878395, 3132327691752397108, 14419687084811747991, 13073348421646940420, 5049344006922558667, 14000517852372127517}, + }, + { + {9716991597801328457, 9345079756027796093, 11200045987212678732, 8772280601358427821, 8639259441726405566, 12571033841874242820}, + {17715089933168590527, 11095491120411888771, 13347464584416454324, 485046159821099087, 571976757247075453, 10200902628607063580}, + }, + { + {8660499117188074779, 14226599538335222514, 8340352780522593400, 1946310520997776236, 6787355814568168885, 5153689776891688054}, + {5667308841323258461, 11049803545816366962, 5483549481076210859, 2650281183298359631, 10767231237699743035, 9742809143935952370}, + }, + { + {9986140370114486237, 7466209585105907907, 1754679179647126464, 17945009041507108637, 12527902125314539776, 6140813986326054524}, + {16393207997039569607, 17870467338953320569, 11842665547915567264, 13006120953816441470, 3548078985168965983, 16007487616892315454}, + }, + { + {988676199292814316, 13795038563960075881, 16898044307644951136, 1804989563201918949, 2415690271309649768, 1403951095677177318}, + {6559788013277581301, 4206972693543414726, 18371258651929788196, 16216427380122603337, 17635684431775122262, 9400941069599463959}, + }, + { + {34276850896178184, 9065645945697227102, 13317573345776592985, 601525926235193053, 9217981927592209636, 12309969749608407478}, + {10546130936371370328, 8868787171248972574, 10889253363563606858, 6066708084552745229, 7944441856950188066, 5353076020090917453}, + }, + { + {14598544504315957518, 7432571723098985759, 10858597307591799424, 10923605445845404997, 13436652897726474200, 13271716260984755076}, + {11746484360997594567, 18260883576159652569, 16536705360207159365, 11555128771579375669, 12265809109975236207, 8710014081931635373}, + }, + { + {9533947271063157362, 3972341891231849936, 9209964459552097719, 7267309578223077779, 13770805495144557607, 14101871822520603545}, + {12718640989104832837, 8947514731845143756, 14070551777157757491, 536892280925814178, 15747030266203480092, 18200278268968621690}, + }, + { + {7077130438749295216, 6779238826822620474, 10474903966971522019, 6820278386136128934, 7255072249237041, 12514067474090301555}, + {7241461786197226059, 6467732564131199867, 3747183394163351948, 16770929168264693834, 17085066469289276480, 9143407880258729982}, + }, + { + {290347547239938735, 15468258237582113955, 660408138412436868, 1302684185031722990, 16641837582246495972, 13735740180315027614}, + {6557401589512433778, 17846464164436659617, 9246161196630668218, 6890950256970483725, 6402204265992443022, 10338073060862145258}, + }, + { + {15430861178767026114, 6156963833198612703, 18365332210313898228, 3325534901104799446, 10271591932915681474, 18275367409906466678}, + {2067293804126060977, 15233366967537526098, 5396097640022364444, 1000014498192944822, 2327452880062984343, 12841411739269464963}, + }, + { + {3385350950958430684, 606441855443472767, 13033776423762098262, 2439357857147383084, 18252952076577877678, 16120810045031173460}, + {15157581942921822634, 4215996528362266156, 6476897491406537975, 5275043577903261598, 17454296124704487863, 17027978976524912289}, + }, + { + {8644752755484142871, 7520506767179250566, 9386137872506045147, 9782131010687153158, 4578495700127020092, 4136883695294906150}, + {11998149667575356581, 11059056827970704042, 12270233192667197003, 2455222920699340298, 9618999184986094275, 6116998915343032425}, + }, + { + {3193697934884363730, 10140335243666665118, 4870491066049398271, 637453714006877933, 14709075847235147331, 13193262757253144996}, + {17938884861655126589, 15835455202328116116, 16378047501426682850, 13063459063154887816, 8093827040207265175, 14470652935631573504}, + }, + }, + { + { + {16034112998441587883, 63845002635443002, 4593001182702153658, 8670578084218703882, 15774651180914872398, 13011991283112025000}, + {15423226930432745692, 4127345328586917270, 1602656434526331459, 3487999218598710668, 1255208198000959867, 10109403147260388638}, + }, + { + {10562160444642241972, 4693105869372484085, 17703834603739267248, 9021680918874890901, 15481929100325334120, 6845602054990892604}, + {16898382896248806202, 5343640296806331476, 6915303502069874700, 12691955589654230714, 13119484603892573302, 444753398747923872}, + }, + { + {17283295680731918382, 10382975592516681859, 10060598265400044655, 1313342669690321024, 15676629915621228473, 14015433292309842706}, + {3722541864418588142, 14316642109988396582, 9534209643602653706, 13980670620545874771, 7954420611695152174, 9814225047068930652}, + }, + { + {248374788036866218, 17964913720605794071, 16982718660501411011, 16539334441772479951, 5999220954131990982, 4565255831754507469}, + {15763389274228509815, 6793638010832842884, 17795140448628569794, 4610627011608977927, 13484317218426525831, 2384269128785251439}, + }, + { + {2064700530864965515, 10923886096271221890, 3965781226482780927, 1349539335778141934, 12283277140753198011, 14288291926557028409}, + {4755291516376942338, 14961944343518391105, 14986331171481011377, 2502562775678124281, 16690683782834868128, 18249446433878083968}, + }, + { + {10500343217363396563, 14604642486751688903, 14821582350585533209, 4360682754333123179, 17373258282956363535, 6560652026876217517}, + {5925790258489013411, 12382625725858582375, 8191985561612267659, 8311548657817207535, 3006895680396725527, 3424975657919705430}, + }, + { + {786181852668121822, 3801037947411321795, 2585057011854260354, 12788225394892184473, 12121545804172165809, 11694085950174284847}, + {1454296081340454152, 12662133117530554350, 15386954396026382518, 12188364006311053755, 14067469636462237943, 6286019250473603394}, + }, + { + {4641661046536668968, 15004063183056394436, 15294276007335774446, 8657963759909427419, 8639015101221632772, 17792395880030705551}, + {11362725454724497258, 14875854967673364453, 16443994946864117237, 16738074345499328534, 11771999957157378351, 14373743150670458553}, + }, + { + {7451471218366369279, 684245731125347196, 15398340817834830921, 11295766022223517867, 13796419334827571161, 2612443196993735753}, + {7266302045333075703, 17867476614955463252, 5444704239473117280, 357656867535988264, 15166074865462198557, 3395143793729939538}, + }, + { + {9509682271313714077, 9145094498501491985, 13014758147649818691, 4392894942493592724, 11373886379849938565, 16136200415791294662}, + {15645599976658644512, 14840712622512041213, 3362514637218698312, 15450726990483884945, 3596435004543257072, 4415992810307073795}, + }, + { + {436726982121698239, 13056502432887055088, 15945046688454709231, 6523495243194823485, 9810653958526702955, 9848069844181259583}, + {16826626473951948582, 231037515307333908, 16194400318485741693, 3341139243875410050, 7198330632933430971, 7499173440340466946}, + }, + { + {7368601478194798007, 12230035070325836486, 3516680325632927852, 3369692206924057126, 3839719055081332823, 12595556495411997471}, + {8654493585319068452, 12397958396131600158, 6963511070567779898, 12454283910184705082, 15562030337854730099, 15142592400258359045}, + }, + { + {8837809708004032486, 13277037412298218780, 16996196458911291717, 15020576394594692202, 7172043530412198673, 8471665740380245865}, + {11048001909658695452, 1722104415157885624, 16816688571596127304, 326278451259665665, 16226792594575388803, 11568977043541034616}, + }, + { + {8456421891774413106, 16587861652105824697, 14920803257030657404, 12140658454692956011, 2890921724026031732, 12248872106995059646}, + {592841531535126012, 9580494709626759695, 6803986786165840954, 3665682418447597915, 8504060701005800264, 12144369197475287665}, + }, + { + {5922269777496758330, 14836479545831353112, 8253590747960613367, 7431627931206560621, 7537389025408568437, 6545197178800609703}, + {4783858952421044028, 8590095805578721626, 1536842665057149294, 8541415499733223192, 314926954266960247, 2029622086554107518}, + }, + }, + { + { + {4552857008992046677, 7742982176237677764, 12614777762761021709, 17623070834843911177, 7352134649339042116, 6424241685372912961}, + {18284550672507410602, 4854060557681920993, 10258397549646077684, 3584018295573283683, 17668477552040944899, 13192004216363332229}, + }, + { + {17395497660961887899, 16009800729326461553, 3265273913749573846, 9525956475609557354, 8008893070464926044, 3999458899476097125}, + {5718380022945515412, 17235833906403176472, 13454747352995042112, 7452239822974730986, 4102392695939993093, 2803000540861803936}, + }, + { + {16618737600557794728, 2033973305346022392, 13031336632325068307, 7832039322814057742, 12529462370460373850, 15738577000088471938}, + {277987228557519899, 2457326519366423538, 4962659838606449004, 6462045821947637749, 14278115896296845634, 5493465508681078002}, + }, + { + {11771918065257941348, 15959999845581824982, 8970191473775898411, 11027278633783758541, 9400158449323034551, 947901598666525928}, + {16512757415387632108, 12706593809124338887, 6988242886781123197, 16531083476591412578, 12943906174817632915, 7656648959205801931}, + }, + { + {9950095340907991327, 18323483036824977356, 8826742511566055218, 17289678119472024221, 16533507249962244789, 15598631885516380765}, + {11278387603777833774, 15536595680256820784, 15785905710436386503, 906326985858832835, 17435036139151677190, 6061369501778984272}, + }, + { + {9936222309360295519, 612751096165259792, 6985140021370817962, 1577482019780095971, 18261512140175647300, 2268925111829825997}, + {8997280151950305277, 15099942588201541647, 11975082702124791135, 10350894913803197836, 3939026946439666522, 15071423278799975648}, + }, + { + {11100833451065161224, 6687431061458662316, 13938739712482703228, 9097524113006971645, 11310108789698970481, 7263803389930912069}, + {7579732541402969223, 4427494314869998923, 17444201060244136886, 16922365472232600409, 4405012916660752532, 12070687041452080974}, + }, + { + {15647519617270108164, 117991711471445854, 6393176877020591891, 12580017776760024469, 5697272146318734492, 6061004989930742460}, + {2473756929649050129, 6642185257675347189, 11657278544254761788, 7595244572280804026, 16987026974396265658, 7603680608840671838}, + }, + { + {4641817200788130074, 11411582570279978213, 14271172827338073307, 983033021155616654, 8960364147838313835, 1083015732588609826}, + {1497200903677486726, 10353458850981831261, 2374066392391409216, 14420375504998989822, 2686838733391603031, 8314093359533890676}, + }, + { + {17496508456763250145, 3725851402903874990, 5215356232054038476, 8626178798561231122, 7346081438096983294, 5668902882044010550}, + {12691479253178408400, 11602632369474788625, 15888416067375784848, 5084998651123071836, 17687638434614023978, 4748093935259778032}, + }, + { + {7012591365105857634, 2874880375540929348, 3220174710965004795, 3059517961108662801, 782775158531417858, 5458085543118651718}, + {1041626186007335450, 1540954764582416518, 9157012689553456216, 6955405647089997424, 5200809672173570153, 11421235046137546582}, + }, + { + {4523124602653947973, 5836966919029851883, 15986368381641127657, 15621634437004074460, 10729890475855047355, 15294257247680785512}, + {11285439807747745101, 11111809578467323610, 14892047086560953694, 11048499802178473817, 2516056791328163076, 16852268565013832233}, + }, + { + {16471199282876861755, 13210632438290224271, 7489191141275166803, 1018062459034819295, 10390278673880097194, 8531679383922148028}, + {10429530876679392022, 16263107527863893420, 16501163786286139551, 13280134735187206873, 1020285771945898492, 9886235265786298880}, + }, + { + {3953361034531375110, 7386122381239091719, 14255034285668453820, 15785522167361485422, 515961023718038653, 15929890586479205538}, + {6439493683049357704, 8056685472536938535, 15913828424728076669, 7849931732449815279, 8828673947015448236, 17381185117791234015}, + }, + { + {6935262837758552669, 7238290685472994963, 12638530517079483671, 1598710569731665524, 980245562699768920, 877454677177454227}, + {13771635882215066620, 16040753974649338826, 7896323269797579290, 788789760541962817, 1510803060770395652, 1869615403943907757}, + }, + }, + { + { + {5531580499851611686, 13083938152796080580, 8093925535259937316, 17200389625360018863, 14842037215178251796, 11988119859109137475}, + {12263909710787132014, 13130916007869632497, 10441881769690738090, 16476642241864490775, 13984242664609457262, 14845292102137925557}, + }, + { + {12517076146320333530, 10291406855889954894, 12064707867419687573, 1502641198165310419, 5109759070771650866, 10320287993169153654}, + {8399783621045104794, 4798114569651528165, 13755067856098540412, 16302764698541317278, 1003238627835525562, 12928911232568933328}, + }, + { + {16493640364904216538, 16952576493628188735, 8338786068864117560, 8893685516440999887, 11383847562341498629, 5266455800998421009}, + {11752729420077323639, 3693269312053900188, 2099384749139572854, 18271582031918815784, 4429897358715577578, 3927504374421523062}, + }, + { + {8698070787678755125, 15703050641810248638, 18420332370057065886, 6522943156759230092, 8207665535041398772, 18112327861657685869}, + {2673396578153201579, 4785641887391457008, 3201343168686834345, 10594426270740968521, 6137975018005068614, 8967572499474389126}, + }, + { + {16980781357310728815, 9400368845185156373, 10978677447297186946, 9679748460996475145, 12732154117709762699, 11885892661392904979}, + {13639001668971925003, 8287641087844004413, 9636673197644968413, 11135961857199331499, 1593345137419156162, 6112607232727638903}, + }, + { + {1618121961524149483, 7125019653217610280, 4135046824878421576, 5280859186376679590, 5657048372118791602, 2933466611636648975}, + {5805664612181580903, 1205209836997769509, 6806945599172222398, 15385614052211122330, 5146598126955318559, 8075018016062999662}, + }, + { + {7764055997887316625, 3096247021063747628, 3855058303686011896, 8368825559451644110, 8834573136185883032, 11962274012645814108}, + {3892254476562240873, 17250665319194659862, 8912259066218683223, 165112253005842692, 7958059294996660528, 2841248137703216850}, + }, + { + {3680472053937419225, 15818262971662536925, 13906534632021415373, 10388162304643816807, 15630768198665438636, 15299740983304379113}, + {15444479968420088661, 4725578511733068322, 6592797451123590955, 12644252808393788891, 3368737811520598812, 2557827868369225502}, + }, + { + {8738552487289663521, 12798020703054253540, 16285176121985392361, 8515295685945774862, 13775150004805130289, 5480066442593566352}, + {1832062561221016724, 11474440365914311748, 12840477284251180526, 9418012590905495131, 10980357385153192796, 11175435945147283367}, + }, + { + {12031563579597435632, 9205196637096882542, 11184135606984465931, 1401305294056001956, 4011048655023979025, 6048353554978805897}, + {9981078758998137503, 2677269315040497841, 8661895209193888174, 2176295311480160014, 1399949325842755013, 1287167020178538381}, + }, + { + {14989416317733195928, 5215645857684328926, 7743823977182561807, 16035950733196346339, 17265966818360956995, 8141738386272537518}, + {15308740448260040102, 4819506016918069818, 10426746682594017119, 792592082078639440, 9734028579320469106, 4168164141775623240}, + }, + { + {15110332316914443547, 2454995031938088056, 8681564356238928114, 8347098831687234549, 7523258191196591151, 3959358611912316605}, + {9351830676079593795, 7428833308286598266, 1416453949629038883, 13547349981311301086, 10428277550264282650, 3606337116602082651}, + }, + { + {5899820503488869883, 11958490906970962079, 16075475723156804884, 9886958163106570293, 2336860573252008348, 13927573664175717710}, + {16197429394630719701, 3637410335075415017, 11999182092087635021, 1303728926256486256, 11862646426072718672, 12350194941729076911}, + }, + { + {11908703473110352895, 2298157340739520546, 12948782415344060130, 3891804988944198780, 11457024627994711505, 9170264692053088570}, + {13049916205169787428, 1232888971483236977, 408187673144451089, 9362353849122321485, 2376369338115959747, 14275353516415817459}, + }, + { + {13799005322110561814, 3601529694367639643, 11106772392590283339, 14056629906511810342, 13572576527799392856, 3487092026537252918}, + {8004945340194339537, 12604327154304882576, 9170501006502176061, 7882459238319530612, 10231971368325328570, 12291029816500597144}, + }, + }, + { + { + {12016493313669998017, 12933290028169404494, 7574629307155081194, 11064769132776585661, 14341813749429263738, 15283735852995564728}, + {5619619958275981377, 4050556776362198952, 3177576231622277940, 8943006541554009372, 7305626035911810624, 2218764583069172594}, + }, + { + {9566598936438275016, 1524065942898634278, 6538402437371981825, 7619146568983786789, 4056320053847575406, 12732024686662415782}, + {17127152314608074825, 15674977896298098134, 17387546565573344457, 5579093677326322780, 12742505204554944005, 9270656236439021505}, + }, + { + {9662754095902029984, 11052177687755266491, 6564855675021815294, 3737820401397024623, 9158763078587705755, 18065064980820239052}, + {1653796274043149373, 8013850902639245573, 10214534956928427486, 9886536041863638379, 436480483045091770, 11299718318113762234}, + }, + { + {967339059085129682, 13104166305190785688, 4270323337549419783, 5748057697199097523, 8577924642091241283, 3581915858994574733}, + {16286952775270696590, 10080909121150901764, 14969905990810770951, 16982777697014839521, 10781115824630384652, 10066879780630943259}, + }, + { + {92896671827781235, 2887243649264806545, 15833385588487728320, 123691791239786979, 11763384358781563166, 2158831843887588802}, + {8596741012506330566, 13826523457635717537, 6540594903680582753, 13793962889582160991, 5269794365508943505, 12066409262788357582}, + }, + { + {14160395515480751096, 4804393992065108318, 5865339760971292592, 16944867750437583884, 12346156586123862268, 13893983071198461568}, + {8669655392775136330, 16391668238375635128, 15081288913073483485, 14651450622111663417, 10940438561578281261, 1459769045883260702}, + }, + { + {4763396496514922336, 11162734181090584219, 6254038965156999258, 7654502220362726613, 2599074756235434712, 4175520862838218020}, + {5532712110222397779, 6663653809301337170, 11279470997460625805, 18326970986868768181, 9974042098100537539, 13917964898357259770}, + }, + { + {15546191471293518390, 2963849438433690733, 1598685141972719458, 8898856010516215467, 8627198789811864809, 18213029019475870781}, + {14333200464642291702, 11308787646021527497, 18050331911988613311, 6162173240162706538, 5132865581846192726, 12525247456279358053}, + }, + { + {11888520648547343281, 494917248976844922, 18138185753471197483, 12035073496965460264, 1674990322514407384, 5436485227695752804}, + {5110912561716495333, 3540271208711945312, 16423892434973715102, 12964671785499501176, 9148547701868918153, 8452102921910430935}, + }, + { + {10550849065095437067, 10753053363341312814, 1074211954227515445, 10020702799800602789, 12864406763293784387, 2698115192684535328}, + {2660806710140858085, 6972138123836745017, 15756537040022601667, 3441297371570217231, 15992662632802735446, 14962954137941778116}, + }, + { + {4348443051639929958, 635118108731535045, 2015655861614690138, 7353522871311274501, 7204918312248323903, 16297291314051374567}, + {819730982198770845, 12608785952359657870, 8576080532289806827, 3009710480834492730, 16107946955600658269, 6618414758853382272}, + }, + { + {3553937582483580592, 748557765063505988, 13881146308285141838, 1352625613370615861, 9547466942139744787, 2062114793498335002}, + {14124993439348982791, 16102858923929790336, 11804652514462156585, 5732609751578720530, 714375047010554356, 6431147290667166077}, + }, + { + {16907430455802407338, 651092243779400541, 5558490953571514703, 421524543072162879, 9495583213289666453, 13989694091243449064}, + {12986952796935468504, 16698463546003412945, 8012703590208385816, 7886765190319975434, 10751493468002030133, 6515081698151754556}, + }, + { + {6087474257130132004, 4181631832640612201, 6923834817653851052, 13172825904549355364, 11686731712296308893, 8288122396407189675}, + {12024088251429940990, 3651003894223587872, 1019304847301994100, 9991022902762889112, 16582922336964107294, 16110644774675481098}, + }, + { + {5498126896868064142, 4836747456186980397, 14439451922445606120, 2540627828887613339, 14545261008261773051, 11467969799607449102}, + {6475133878892579834, 11091521615198288188, 2782411639442406711, 5318254024968417786, 5859257904336594124, 2341590642428951702}, + }, + }, + { + { + {14518481408695687669, 2095771038881695915, 15826157616849474498, 7631060871632259188, 7943802148536381101, 9960658929149574973}, + {14220929306479180052, 6691269956130908121, 11961714924677727754, 9368323637302814513, 7291095832678254036, 1472432228204364122}, + }, + { + {296235288120767705, 15980896506163657127, 9062593919771909466, 16125661299672370182, 9635461578488266018, 1155136620315591386}, + {15542837136824990624, 12143968280527693151, 11763598774950389381, 6763568060848908383, 9078265856423831300, 11111306292226892543}, + }, + { + {3439881221278078059, 14900693561020779474, 5254088415616219888, 6252474065701086141, 9557647970998076314, 16557080478909731651}, + {17984691969139760073, 6920275699694311708, 11586093772939554855, 10567368687255256163, 5080233168822419117, 4328516116216989313}, + }, + { + {4596402599231671431, 18270370190796421118, 2306869450531067189, 14899242618385405087, 5573077655838651504, 14786962047597110553}, + {8824292366761823595, 4280831893742429953, 15856753721134043278, 6520053395038611912, 18021729931870278099, 6369767037287702722}, + }, + { + {2092756234911620351, 12191998366985012384, 7450107522245627844, 13887131358456374402, 8075627236568549243, 2080029865308854734}, + {14564437191532160823, 1248159409055904140, 11241915899684752873, 374881929831255064, 13433377109261039811, 4864742963124465747}, + }, + { + {16241148550837149451, 7822351548402593379, 8309026501457287155, 5103819580434410766, 9108794158669260903, 16488989256917731421}, + {654044319854628751, 4653846517548435917, 17199712750191435016, 4845695359451199828, 8117219445563926224, 12507860620472651305}, + }, + { + {7653070797102301348, 5941550290626705984, 17158569969337658821, 9643823508741141673, 1522997131282064389, 14961110431686131034}, + {11802659136406721500, 12306955104612554951, 9514149419806882461, 14375242488313250733, 5052075298187092512, 7410174133191576572}, + }, + { + {4358758092801908863, 7341423105081917858, 10291109018391718430, 16808750129865208976, 8165688726053843552, 6688211068991597475}, + {17960382836450267765, 4303165753492267405, 7660091042153170442, 3855051391425497455, 10928187542174197484, 13179854521947504240}, + }, + { + {11914960295850256028, 736894971573607460, 12038994816721001602, 15765970801138452754, 4004778617735408471, 13131827739122379797}, + {17423943862970446994, 11783909998933696219, 8224961911959792292, 16132329169568881376, 2487867689899583885, 15018657522918867674}, + }, + { + {8657571447411467172, 14465724378300467677, 7456925156021131657, 10099394822944333635, 1108995305500533003, 14670621046876829893}, + {13859265344673965228, 12642756285805199588, 10618371399223472359, 10368789075142392456, 17024775460445275303, 4836741220623357252}, + }, + { + {13978074604430806636, 18407681732775924476, 8539556435113599518, 12436983718097546564, 12305195225429220776, 14562179379065953930}, + {6423549542556077018, 5040755781466160241, 17482453842942123143, 16447448498858010488, 11479552475069053178, 1277752221540085617}, + }, + { + {920233764095776718, 3319139992705676642, 10862716399636326975, 9064714243076616640, 14300958971895109720, 9740515883782303421}, + {6704838650099908790, 13781706302104941529, 2159164314515365763, 2657942042243527314, 8728543051894613622, 2325932806770059428}, + }, + { + {1967422502593875213, 7041760415173107577, 9050221304247474093, 6387184238732181908, 5042857585504795697, 8540152121523996010}, + {12903368152967462170, 12590063752208819611, 1933648838835739903, 14309714702251501120, 3968656691162699954, 7006655092536063292}, + }, + { + {4234961586345538709, 4555151906871493852, 3232985920750903052, 4244526539796687845, 9377328776465632031, 7060246266590210233}, + {2853784874472922126, 12423531525688330431, 5274221307163072241, 8471968438469831965, 5168569868577424241, 13738202276372145637}, + }, + { + {11027740333858210397, 14805109795564990231, 18001404758531034531, 8113634300017707290, 7136773249584072726, 6460937237419466983}, + {11113010926555478983, 8211408909041649548, 12479292053761376428, 4353008690987758386, 8859777315867880266, 15451653478486520306}, + }, + }, + { + { + {13818182961147912906, 16111231902964497105, 5753266394530009372, 17616272516546069710, 7303352128999517861, 5933646202109354624}, + {5921806076173096907, 13896009253778745778, 11309023928924737855, 4469463255182812436, 11037920326247304138, 1421676035563246889}, + }, + { + {9963872303672903223, 10215244336266366950, 15328675269518615753, 122600537279116424, 7616143723151064557, 10569183306278169313}, + {7031003844724741558, 14407986305911385591, 11788159030526689129, 3609241791309434129, 13905596487394238209, 17665966721516237541}, + }, + { + {2594699758954057096, 11341478545067279123, 17990597733287642429, 15246802590252455327, 8353870017669333748, 12614437615817297240}, + {6394781505133818163, 7425571888170698179, 10395654478962895608, 28575799984957524, 2682124171246326926, 3197867099218106953}, + }, + { + {11244734218150742610, 10723159354785424855, 7484860387130692692, 2467563150354920554, 17551980904639200483, 18441274508899025558}, + {3676988885705600635, 1865990625010728131, 10102149234595216040, 1252552252382716358, 684792256577566866, 6943047702176820428}, + }, + { + {12653542557867698652, 1142433072335098633, 3314552015716235100, 12422430364987401619, 15277043111900184721, 15734019630472200325}, + {15919711988870913647, 10725565601222767370, 11290906213530487192, 4662157581039009933, 11015350972696669275, 8208086286380460938}, + }, + { + {8149565212922680035, 9567944225255802618, 12487131892260634436, 7443172048029929426, 4305538689986215677, 4430546250909191430}, + {10741221950240759364, 16545153560365439267, 6755029137094727228, 81110724808247078, 5717471797282522877, 1486218088878517808}, + }, + { + {9544854622790528047, 10769761497113177908, 1502686769356489564, 11081322603706834961, 13364711539216168883, 5094854373914013146}, + {16200855071998899478, 11725976297239923532, 3061711654331076059, 2493583541459486142, 16389197377130664032, 1243320213701794262}, + }, + { + {8357050367418458359, 5525355159387149167, 17747090324964588952, 15694673113104643586, 7307621991317580676, 1289366645950419281}, + {528742783924328467, 12856892207404403478, 7148581103958210921, 1069895320583652302, 8428983332864385655, 12605554700259997922}, + }, + { + {2487016972575222431, 707675339208452706, 13435953217565346444, 10759388806374516776, 11194720901200530938, 7026549091209652010}, + {9613174021959686236, 4467223759668079541, 1818968857637375440, 13722755860101057871, 7447888855543394914, 11546251567136013168}, + }, + { + {2457098738888001184, 13436425175767521555, 2765094396909275573, 13944016834209830039, 11092919542763411502, 1754742216756443900}, + {3000476756681394440, 9364034762555019549, 6876992788712194394, 3585709061747683458, 14106253519316541506, 5279212076903345269}, + }, + { + {10813235272482429086, 731216775886127646, 15234319760355729449, 9466303362664776229, 13159285075818128580, 5734182119311122400}, + {5552097949831952705, 8072700375309437721, 16694077426905656662, 6836436096351296392, 11231592576240564431, 18047071890971042931}, + }, + { + {1022254770374886277, 9469459507582571128, 2689087779341478977, 10040558278837523393, 83202215085697759, 11389135963216852624}, + {43806665444650760, 10286022177325133470, 12773072940237016578, 10992425690329167747, 4947183945666379415, 13675981203969163591}, + }, + { + {13477598317485536079, 10040066752150433290, 7405123541490280851, 9274383932346246150, 14309192723531202554, 2524700381746668787}, + {3616389453203314756, 13581678150808337225, 14540726193639627397, 3234008850825878308, 15341468248221057383, 3830563877031748372}, + }, + { + {10853619680499782048, 17362724233771660267, 10116273108750733202, 8385992189881504730, 17855585710140315498, 8470682662587365724}, + {8287837611861659551, 10994242426397343384, 7964721658577081933, 4070529224299771220, 9413822451565658120, 12865616140969909319}, + }, + { + {4909175585319342946, 10921727442298570876, 10167667568640009770, 6338375152080033018, 3059470611612240919, 5445884441031512847}, + {2080017510988083324, 994134584813785821, 11859009130969323612, 4838588735676167501, 7193860141357257635, 14012081064531795045}, + }, + }, + { + { + {18027264009080180273, 2475688335442217172, 11495630589568554783, 2044610447313340819, 16211574958831636691, 18082923260238685029}, + {15706469362280984389, 10175042474371958564, 1978937508224725826, 8517309419909857419, 14117179981307010083, 16117021543255946075}, + }, + { + {1511347881429709117, 14331553269818546726, 3174494305719383998, 11632902270807950107, 173546718771105251, 8459530881951500056}, + {9768245664684322698, 16561286001450401034, 8971518231697912000, 10976747460480974856, 5720643303151017754, 10819571526556570257}, + }, + { + {9576152676005768185, 10006989422531598194, 16187127654089665852, 10942929199410456340, 12406093935974963980, 9789646989960898506}, + {1787070800558790010, 15321395745534743079, 10957766159164936872, 8270293817925324519, 6611548955360388519, 811894490473141865}, + }, + { + {1177812967446514471, 1517957963298502615, 11830891177576473426, 13778978023558357649, 5108224327305754122, 14001515739949397207}, + {8456370711154495527, 9224707985240991577, 11975300863666543456, 11628484027954011676, 4106175737255204293, 141089986476922703}, + }, + { + {9131678980253850574, 4479975833350928208, 10129015129452566706, 14596103361459462005, 6870275426489406730, 9740372621433972730}, + {14372377876881420680, 5948925994235262952, 14844830411071630096, 5061939034624460495, 13713851364090957723, 15171884222064254954}, + }, + { + {11883295856694360955, 10292514093729377837, 1018241106247366045, 5734998220934568611, 604293790623280200, 6610275829270273887}, + {12366129529412267868, 18331188876567635410, 5216829119638902498, 8912427667935396786, 9501870605862624528, 12344298042089151792}, + }, + { + {8163932230030769123, 9636016199609023759, 9161423603597683840, 6654511074475296823, 17793619545653824539, 4124609248372213291}, + {11230396913985033299, 16604770927162297627, 15127151935380606658, 17824607882620004762, 10373865240573715539, 16654854491247214292}, + }, + { + {14818683899450679836, 14357841858587947614, 5205003223993289617, 9070636802111036582, 5470773669151086737, 16750045699953367638}, + {14277479053033448070, 16287996706847536112, 15752386157739826785, 17892417758463210493, 15541841791609187377, 4029170486772069449}, + }, + { + {590558285614616488, 10384571122104306912, 5382287961959199743, 1207676815187815333, 13011773384862224953, 532436966815548636}, + {3019650690602626765, 7314252074457497416, 1838949562628498144, 10537471043392597480, 3070353104978729913, 15624376645604971077}, + }, + { + {17115127186232346178, 10621035233663393896, 18371958430819337089, 1193295512905013155, 16614017806526374903, 10388183900788590144}, + {12609314943764198670, 11179941239127206128, 12182679129557646733, 8965475646212860502, 13633585572850681632, 3426380476575326349}, + }, + { + {8276623546443212404, 9482903315384710760, 15538896085254227434, 15790143076571948507, 13143573532148067747, 3184541945442546624}, + {4972549455963732427, 18394646794778833511, 9055568163078599201, 11111002929065765438, 17363710725009368186, 15039897105379313802}, + }, + { + {1298806571453657723, 1042114212262366662, 5680532184394488579, 8926718412388834594, 17803123059561224046, 8663230263216788351}, + {1629533050023872010, 16027578301664521945, 10229699200823727147, 7773663415615911623, 14047718958480228325, 9551563011362116236}, + }, + { + {5989309147210387183, 17849299546447616600, 13296929709722338577, 12659773706196250035, 9857145876253632711, 11836080982965367426}, + {13554494825619368750, 17266926296470690286, 18031413991494048783, 16082997100696095698, 7954101307530025972, 17805255183453764631}, + }, + { + {11764175621326135951, 1791939567018465213, 13029241477144523291, 10840557939557580560, 8381031918646881664, 15423611692748071864}, + {867816783445809673, 6030296688691172286, 5561502310603617073, 15534923164629599800, 1208665840373127315, 12554641657645359528}, + }, + { + {3209670898909179942, 3098303062665745356, 14606274486451097890, 5959844521554290710, 2464075942028132860, 4072466165408271129}, + {4803469398150112461, 13680850164034057508, 11856265931978933824, 13240671495015013351, 15372029486600936548, 16702375458830177711}, + }, + }, + { + { + {18354847664660713402, 9400129736098519180, 1693064830516242847, 8562602303494815916, 13461534639537583386, 12859295804198471696}, + {17914958195244970799, 14970948874889495984, 16335291403269479707, 10631004823344361203, 17176847807154743365, 7714732495833925335}, + }, + { + {14957716628768963046, 17714101461064775895, 14988284950839047625, 16071167094351699344, 13890128763447277457, 4634560608180312269}, + {15209983968927413233, 13604763079237964821, 10947506257796639042, 16898823699351743161, 13294221703899555280, 15072745049022926507}, + }, + { + {3852056161889022327, 2473180673803482388, 3734174223964831443, 18372076238287597117, 12199161160370991577, 5666481007872478146}, + {14306064415346698520, 10330919921159881314, 8823577501055193872, 1854546884403147535, 8350718724062793691, 6987169359640195828}, + }, + { + {6350728622830713728, 5701874018092832478, 1307420847228487387, 12162151629784986353, 9986023597556720981, 7652258640582743122}, + {2186001021201828888, 3639063210548593758, 17939576646917089186, 7727612437620888084, 7790541002958463900, 16125720901743858869}, + }, + { + {7987758804483759886, 15261177063236862551, 14141837944496855895, 12436175571389993349, 8274042047049891014, 17152451709054820788}, + {8637518459734046525, 14044145421979578672, 7087188747750571441, 6313728565256547988, 11986656046293683375, 4860648976415357838}, + }, + { + {9009539789648791006, 17968770175863968085, 7552239675047114070, 2857176040809917182, 17447219567921940196, 7265407823518294105}, + {17146273377976250579, 6793545786177262831, 14702522055640190270, 4115098237661381737, 2503118300874563585, 1557013629291304762}, + }, + { + {11378438312695848589, 6538246237007438137, 17401630259167972224, 3718158584776484875, 4653786582172050367, 8204345231064757942}, + {14333075355191893658, 17490753073467497501, 882454733741447284, 13137676416912827511, 12367922995099391170, 11659416979788208350}, + }, + { + {6506114746421938896, 15057654379054626074, 15301323392829790768, 4198974549026211659, 17765210741443108016, 7132509492152477030}, + {13814681355173788286, 18227429366563277742, 5706529263838269680, 3305860129954779061, 6258038612413033234, 5553019991310521590}, + }, + { + {2740541731000766119, 8596175174200043370, 15268406586850192141, 4422842783758936070, 16124815896970518429, 16832763608196271685}, + {15434766743141189819, 7524954445211264826, 10235492655871568031, 8982274848184708554, 61280556653488570, 2365856772460075321}, + }, + { + {13157569055430348176, 15120480921106359700, 8907221703681745856, 9744220876937878792, 12735259395540542647, 9934004250126983654}, + {16718615067756416460, 410404144349530529, 6127062667806307811, 13658502470838162746, 14801118008320529094, 16148996127797465924}, + }, + { + {15802530345131809115, 17755831194964343760, 17769515049688374693, 7857718956073628784, 210191518703714850, 1746393941813293182}, + {9588189846482137991, 16335835178827943095, 13379307055600165683, 13189771146869278015, 15165452058189091322, 16119082358562095187}, + }, + { + {14291300888450540580, 12179403608989848787, 1574081386467411267, 17634301459964659121, 8878112303286796059, 17677799131162737575}, + {15596184219007084082, 6187497693225343219, 3798717948418717856, 4726638163830739524, 5752064164618039868, 12151699975292370996}, + }, + { + {2566281592983211586, 7556513094797110610, 2450166108042699822, 5117635899811819452, 9378838926483608725, 6536766093196310265}, + {7844966478885204208, 17742733133746826278, 14738531168438873782, 12821429720867364479, 17548355350637387437, 10379676596614787905}, + }, + { + {9312968557225948243, 12012357331777111837, 15378903016229100083, 12000905387706281859, 17061047818694588137, 9595998526695275691}, + {11468745480135275611, 15336669098149774847, 1341152435528764937, 15838536921908481248, 11418408147933255250, 5931142050180490224}, + }, + { + {4126355864148604636, 13615307424696038095, 610122995599041643, 7310843591875371159, 9562945189555198546, 5139192984197086614}, + {16434764370823678107, 8879626425844710867, 10870500519197212704, 10351639341497698657, 2684669702506554173, 12776278319330754082}, + }, + }, + { + { + {2976080374040978112, 15463477607266400944, 18021857121116180535, 12769842468896246932, 3127871016491855528, 16064631537662018368}, + {14779669176601385973, 3776668856093058683, 14901222703045028630, 3232341387704264788, 11524644522032323784, 2840977857469413331}, + }, + { + {5288000162182207268, 6882039810247587375, 8670725030786145343, 5145183205378561959, 5837273482862705559, 12796134768505888809}, + {4538314407891574892, 9060622484855928248, 10762409677748173572, 3978391277049014537, 17437084673881602774, 9597445123068848506}, + }, + { + {9647243303471030171, 14403945224496984264, 13886934807685357620, 17412670052512822239, 5167671672373181761, 11309623208884894891}, + {16223393003006029431, 1419420326439656825, 2369169453814801856, 13061716774043471194, 14634525798681795534, 4751674434384485255}, + }, + { + {4551832817507521552, 2313908657037532903, 5993995178973949921, 12447883782437853955, 2555223230220912865, 15167076377045730267}, + {2005335384595372774, 8714558357337187482, 14553513576888660757, 9344637821077197511, 11470542328000845120, 8444785364767260640}, + }, + { + {4138889373221767098, 12141056423117115293, 14874649331180645388, 1705049756225833969, 7848874201060248948, 5156845906941397672}, + {4861831505262375336, 4347196895421922491, 13681671418165655661, 10985831839263041306, 12731646375130791986, 13097670606652769270}, + }, + { + {13662345490304024129, 2974839373795112820, 12056507699680569779, 11760177245091509243, 1304067584530226034, 5993077591223164847}, + {2387375708577719238, 9626459487654222268, 1955587799597889262, 13097747078399605477, 17202959331606801221, 2329556196948809962}, + }, + { + {17812987452373376709, 93922986227836615, 6326230905711504623, 16126249753219785660, 2455759288569847701, 5953549367496130585}, + {330019371493755212, 3787738706597361027, 6252621554557272655, 725518130284881658, 976894057381550612, 3762034607037675717}, + }, + { + {15030213828999353996, 7537307216693595568, 10906817211901741334, 12978201161486570836, 13688879460912198344, 16875104360403708899}, + {2236812266517027774, 8283440131031015303, 2503310362171705003, 14140140152955857646, 9324835099807979519, 14222655865872085142}, + }, + { + {3744645064193324992, 11767671095853168147, 1146189435518138409, 5628986181810339417, 918940426876816812, 15936037265796453016}, + {6613161822954084270, 11628888581784661943, 10812400261220740733, 18166624472577344261, 5876006248392439801, 16310306694834328246}, + }, + { + {14125633931334589394, 14751339378917740218, 5150510528739010610, 14276625313476908582, 428670252922191956, 2631125662043419149}, + {1617981761951911336, 11583305636829657910, 5101252848640834978, 16667317030245715710, 15236201878077258476, 10871787548070323489}, + }, + { + {7447893961295274471, 232689431551823296, 13869806697620401084, 5330160866804784025, 14865575443350752261, 1679832461395111529}, + {13432840916023326626, 5655812378144376418, 17569608518110186458, 12501129428357124126, 12870492098064776642, 2977413908822477380}, + }, + { + {16051075988752124526, 387294815279188176, 3113985811668805632, 1973998868188061597, 3007935075189940834, 1096206135454331889}, + {5718521169091374159, 14981024399127745789, 12740192428843246945, 16002483798782724245, 646320423819307823, 3798677800777828461}, + }, + { + {3175319352668641931, 16660628462131386552, 6009313219444175330, 7678412375003613097, 9306411708347736279, 9935327299823143180}, + {11559141188091897348, 16810520437389758501, 17490645749839025712, 17259327961568124278, 15274735373631914960, 8983416743854404564}, + }, + { + {11963348162499020986, 5141506614889163229, 17433303046800477704, 8199586499645960554, 11047244048987602943, 6043499675044562520}, + {3566164965696214407, 7496224733250850598, 18368140720280229179, 1567369354656910484, 5448980629729479630, 7863641419129732206}, + }, + { + {2725337558589481703, 2497570082780513054, 8145569365382441623, 16909216290827518100, 2055218062540628228, 2415304909498436767}, + {9493217182909039176, 16224541192418752121, 7654146956830687353, 15910281318968056771, 7566577530597601060, 392195615790859862}, + }, + }, + { + { + {16389181503826270360, 12110241482308603158, 18288412366208628916, 6215500050936591061, 6014488852457703712, 15271085167906108065}, + {14292078858945118972, 14481422217835125511, 7781324865065249448, 1680769593324888263, 10152646427558791174, 11660961480686650731}, + }, + { + {12596615897631832150, 8821755551627965643, 9377179163931081776, 39054669779258365, 16376149550862611797, 14563278930531491140}, + {16172472663040388770, 5190287148139844803, 9110064025691300865, 15647288432646291523, 11591045834006760644, 844689883380316992}, + }, + { + {13548776749212678702, 17662168188358040525, 12032615038574171326, 6080133567086225201, 16938431180779549179, 3443895457286094158}, + {6436317213424755334, 9475881081120747064, 8925950328230980837, 1431876965977827621, 2014835158760914736, 12987015014298314305}, + }, + { + {6414994335254419743, 13126391477045983044, 7334301732865328995, 17814900833709399507, 4626754175182728225, 15638724462213933799}, + {4525732141028097375, 8291242304314061980, 7906228613924545091, 15172916208217647131, 12973611124608613858, 14415032784796747468}, + }, + { + {2941763674782308367, 8542334074892503502, 6518009639926774875, 8175768187727642229, 6810163642801138717, 13000888070357934506}, + {6742587576626772316, 6185408768536176876, 6199936764943605186, 14449234849358571084, 15099106384716206744, 424689763956421079}, + }, + { + {11352046731905647368, 13199556803131515747, 5716134925316732088, 5648788594959551026, 3705999902843684565, 560536953153999361}, + {11871652593424132117, 9835410362049088550, 1151003289591121644, 6319035178000560268, 14320824175339506736, 9395144506212799342}, + }, + { + {15455730684964191688, 10234835525295487673, 13182207266101117103, 6524185547415883508, 3326725631592873861, 15008535546194382452}, + {14902727792883529480, 15934241170433009830, 9499368143445027089, 7932650776206057878, 7397463728482754856, 15064673712954012572}, + }, + { + {10466244619397673266, 15399629207270328335, 17269983148989232532, 11915757566815614941, 10527914924508876394, 14191866475212875708}, + {1195709843044148654, 13844920180243298721, 1913057717019589478, 2076654993296600487, 5771535096432721647, 5276006344600556560}, + }, + { + {11597571737530846199, 15087369689361537037, 1943002093062010773, 14166422307764789509, 9566693410200051474, 5715847907279017779}, + {10365566668051221446, 15849087890611260377, 17862304002596752565, 13346541298411131391, 17741431867034125269, 5459305016755278252}, + }, + { + {11716528930963372212, 5531007692335820969, 16480109661368747208, 4989131671065416736, 1321744169687329693, 14777911526361771830}, + {16382233147918448360, 8261406114108376025, 14558557421269437229, 14834971601402563213, 15317501415447267445, 6664947553397092024}, + }, + { + {5785339725163835826, 6971210823493195704, 16124144681939339987, 3475104212436227942, 6049658499241715622, 16458315540661701699}, + {13323859344989042773, 6912561797063467249, 16800874344261680852, 8282162771440569212, 16369106286531876819, 1170526359132776853}, + }, + { + {9782081741251904701, 157951607661604103, 16926146768919338915, 7973413355284153573, 8362125879537081326, 9862990051212466177}, + {5184297884162915665, 10244746657009000097, 17343337497982107750, 10499903102065327375, 4012731889022182801, 7003219507037376215}, + }, + { + {12814653486444031879, 695131493401594940, 5677983402953066279, 12084690974215027335, 10420441289745630608, 14692497896969958685}, + {10769477264375836410, 17164147105428372995, 2619906011157181849, 1415661898003451303, 9866791318849538593, 11584829697149423292}, + }, + { + {14473501522542709727, 10749304489595316230, 2934355198146439368, 11017927560935119595, 5915324032076206144, 6354575443760924114}, + {8112720200285039304, 3582240290765355039, 4273023256712648103, 18427552816472655644, 12422787084653101783, 1105225281604355429}, + }, + { + {17128222588782702290, 13487368180342466954, 18017424846076363710, 8988322008818510817, 4708906557988367239, 7838727005553267159}, + {9398500148632613444, 2222389518787551320, 9441001728156177075, 11730541176540093429, 2854531586000055239, 9731840308469777308}, + }, + }, + { + { + {12818200022021032544, 18304962199648570900, 13782454312217074924, 15136749185545329918, 6562515245419546737, 15005045681562431971}, + {698694633971573994, 4013566334015448244, 14911595848732456117, 18305955879156015222, 6117212666624617460, 18143980466289027383}, + }, + { + {3502426890414957587, 12060773399876551675, 9782583782804195660, 2856421043271709331, 9172760811796379412, 287598491992287381}, + {3574882806715667454, 1471467928527282465, 18213296168373130112, 14471573043027880442, 9733220931679498558, 18238876809557846346}, + }, + { + {1186541863308497492, 9046950340101487212, 2745706024936898790, 4989009340224862161, 12823642979701239217, 17942139398687727132}, + {285479679301825536, 15862959466038586171, 9521459034208492274, 5591094499772746735, 11556872820220759870, 859478641511045607}, + }, + { + {15238342970318237289, 12057224731033370287, 3456414471220945721, 10398678431367169082, 16329262524936091613, 9810430130271885572}, + {507823287632145607, 13852199732643342659, 6599758124440658421, 6281020241660422787, 7196547321920663751, 10793248012346291609}, + }, + { + {16383444525677044377, 2278315169443859734, 10660119552937534602, 11864735405260308934, 8495438467432993830, 17346877704286895877}, + {3849319409996272322, 15807271853256513609, 1281702280418940250, 2373472013096372228, 13886255586271670807, 9001471337887209400}, + }, + { + {126909537204579598, 9749804666000980109, 16255800152061704810, 16609135318627234518, 17961723534307687333, 11140782709978313514}, + {4136643585846766549, 13601295896682468661, 13257346841610635045, 13497111085366129373, 4536183896151771989, 2489943574182543991}, + }, + { + {17280995436445609182, 7102456830521880903, 11461813376456526486, 9119286224190937602, 1677507200155630395, 6530478943017087729}, + {14611227007048719177, 251469378654353230, 4648274799629731126, 18315451912783545607, 16748007467838496641, 8627030552960679348}, + }, + { + {3196164040344762946, 13715698755805511585, 12458229346805024551, 3656509940452321691, 14877033093641476326, 11337317622750049895}, + {13942131585783347058, 18149827011545790191, 14895656048349000943, 16669534928350175969, 12531447672595399983, 13192103245474624236}, + }, + { + {14145917324940179268, 1801646073880966091, 15389460022241189228, 12374720625988164902, 12743858920585304074, 17607177891983515301}, + {15207272938242753632, 10413323271560975478, 12343096097117660807, 8269383012599149690, 15406849301603489917, 5134788699979908779}, + }, + { + {15888200229957314506, 14831411534621040361, 17970009204612188323, 2343767984014726431, 17841302528539551395, 17397648858980735628}, + {5368978612132943636, 4213367444878083717, 2033768727106228984, 14322131493744692794, 1236700335920101663, 9898949435294220253}, + }, + { + {24758834352404155, 5091013253272577242, 2028941475205281304, 15518967929666839380, 18004005068930730609, 1086684650652446553}, + {3503524165121762927, 16631444510755073447, 11468393061269997145, 11182831309911774750, 14403549322101529071, 13276637040909393512}, + }, + { + {16631857123721916775, 12096833102612622585, 17555483922966042784, 6723532965693736694, 5206953889265807064, 5257296707684647125}, + {9873856732725887735, 2019034753037317738, 12416543296251547862, 11111904680478030156, 7089558964960452193, 18166289056279109058}, + }, + { + {10481925795166053003, 6733183822951411784, 2336616077761967501, 16214291345655367389, 1553615587408951311, 17704541651779617310}, + {15809632617388566423, 7040680416264460118, 13227773672965345020, 5249395959455852855, 3700955432488167579, 5695246660982315902}, + }, + { + {1322177735500321843, 9036238380817454036, 7985514519046855063, 12745778131660207555, 7517032570151312640, 9543215009508727185}, + {15511746435670372720, 1582199859560802198, 16232964063663491032, 18413513284071022892, 878561573889774723, 17999994568313632469}, + }, + { + {51610547936916636, 449080743773055520, 11895942441668539651, 11528163466753867928, 5327778117936222113, 8054693531038673087}, + {2883116022051785418, 10880071210182937273, 16424612420341096868, 12563975202447499768, 17898191392637488032, 4341166004500306028}, + }, + }, + { + { + {13532417727291518966, 15621487234118278211, 11434135490251796442, 12174621814582402377, 11920309846702883069, 2376809786088257319}, + {13790218081512629675, 11886070728329073138, 14026033143551470492, 1787100914236464953, 304006454051884466, 2756779920933373985}, + }, + { + {14557765107140528328, 12355977617261039918, 4747772470536185104, 18066963986056971247, 2652951795222371597, 10786073208769016103}, + {11296024438266601030, 10656113304080611004, 8026365448356501999, 2223277656070704256, 11257682407574091370, 7238909102714165030}, + }, + { + {2791395962931366632, 1203894038483281930, 15578449492227701100, 2119859552714176601, 5772832886191005383, 2752141942254219689}, + {10053647313488524348, 5086479179724027856, 17277990771954143064, 15685827892771379266, 7735502714666745260, 9034852030753288603}, + }, + { + {9516343685613462106, 5255139143590615572, 12557738960870331208, 6702052925707924899, 9793008294868108308, 1711520204119625593}, + {13236841202015067107, 11129785963068370784, 1317992927785313925, 17479451244447802402, 13036816126933313535, 12502011338757112622}, + }, + { + {5480168288956527943, 11042549818448342343, 5915412500172865058, 12999251329017129768, 5808021534739634680, 15104939226808360257}, + {16234634328969043664, 3758395717098249756, 1015491288991804400, 5068251056783778816, 16324558660491861300, 1738698513676655878}, + }, + { + {15946881038575547502, 11116762950959791543, 1297081076272427975, 18245256277091707800, 15100977783223461884, 6017885634508292069}, + {16886823282698854680, 2072463130596047656, 6569088142237167338, 1681498520362575025, 5901004614588673498, 17871763470160973506}, + }, + { + {5104558086478114328, 8971286270876655577, 16470947836284805745, 9037729831080471007, 1965555872583588977, 15433240281955214704}, + {15775227419098203047, 9665258145206729468, 6253192577851256595, 14270940816171443030, 16612589103033695708, 15637879580008007829}, + }, + { + {17904034783907348399, 2626038317331972399, 1873258435072511230, 10005975240297222027, 7533652174638142552, 8419273188570922972}, + {1990391844410141613, 7373216149717011445, 12388874252879150470, 16614842721902772761, 2061105669992609107, 9570836984475646549}, + }, + { + {8491665721135698298, 1799890999791860692, 2389734471340627870, 6270039658247138318, 2463312350149470933, 2217609086834055191}, + {2540364179975154870, 13284898623265362260, 15339373729732261072, 4514279700129226946, 9114575154956391114, 2305724692490304627}, + }, + { + {16530141398463115553, 14748291394528377795, 12303798781899702708, 12438876515281985755, 3858890397627964933, 13323517596969431732}, + {9818536194104432590, 16122491291064677498, 484427543635671756, 14180970696306090632, 9883282120273913918, 1968662552094340067}, + }, + { + {10479341768131470504, 2190791104965238551, 2211152119507925575, 2517772887931981229, 4163883984830586116, 7101754214377757388}, + {1318955625560086134, 10530268190194110, 15248667065937080538, 7939869955605316809, 14313273335008385545, 13762768542953544187}, + }, + { + {690011461657587646, 10912073132311140135, 3674573373985417129, 1597723780107325694, 3549368082234927465, 5785289767244769610}, + {10814725183340498172, 1844706750982331307, 3626691260264165038, 5983040194600768762, 14282060651990538968, 3649897431950147558}, + }, + { + {2301048926250107017, 14317366235953485757, 11632712123230515281, 15595916662388747577, 15711429699151908381, 1305749118231488029}, + {10723669266169674926, 5797826425608678920, 17405218711301982393, 21871232298874801, 15013562554137035037, 9701498342635018022}, + }, + { + {8248839050962163686, 188360563145520954, 16729953975463785867, 3169981816175024043, 7187517706576344210, 9124675384823574083}, + {10262932309387547064, 2404363551953852313, 13372721599356368606, 2531242226775172773, 14257983105055729397, 2642170875421515959}, + }, + { + {13319873663433996292, 13089646428714940315, 10556137876882685421, 11656950941183630010, 12276319669931009991, 9463441716524353939}, + {3370727689367607500, 16018376472071193381, 3301478033055661161, 13190011310690675390, 3229558123256164376, 1583255490085522802}, + }, + }, + { + { + {11928390292426988518, 12638952790538679939, 2608009033823001125, 1242834957664439029, 17797992506731473096, 10340201033905982118}, + {10278753530600088172, 14116327152473508099, 5415842384660027374, 8566401179276240818, 4672386168367646978, 7541801451638385534}, + }, + { + {8566538196049418515, 3197654215985957962, 6355192582145549922, 2489061264757130927, 10197194261710918732, 3715293456694744633}, + {1991945499394841082, 3380660455057193206, 9083458464137174418, 3254176369798763840, 9684490403170591220, 10473571146597457026}, + }, + { + {6457826063520179285, 16268949646546946980, 3097451422505225454, 16453171385247691361, 17481519375542182315, 8112355562842761847}, + {18025352535213545210, 3750835203252893359, 10768297909412467901, 17629461198543052222, 10843179524144693103, 5226721924620138404}, + }, + { + {11631805870497408523, 18340134794831315912, 13311913312275168872, 2845528461275777300, 13173530356238926504, 14929218971024971026}, + {2411139026399661115, 17215217074808016346, 18228531498431262439, 6710245408258710904, 10307545091592698852, 15144971226257950491}, + }, + { + {11109750770824264074, 1088007372340209252, 10263956230079210784, 13896899727089451859, 4559138529870539846, 7777534303712666029}, + {15041017330059266135, 14622601734133247399, 7108706896655204385, 7934590922797237644, 7575713521896250968, 3332437975700014380}, + }, + { + {13801266825487496316, 15263809516575468264, 15419536487874300835, 9072780772100611698, 5969380434932396755, 11198543363610134500}, + {4171408162113015715, 10202388527823988708, 4311928890627114703, 11816249602018388228, 16313146221834083742, 16629955175557153355}, + }, + { + {11660286662603189685, 1207956299008625786, 11363359882526736892, 12477550434520668425, 17179867938403281938, 5655901105940295926}, + {136910678421418920, 2416064355587887290, 4502724777522615718, 17912124462718346700, 1361328791937120561, 12111897685488154046}, + }, + { + {8096344270340363443, 2517756701774451654, 9304005451085866903, 5715847369594509871, 9745892404944266254, 6051292773703160279}, + {15884195349114695334, 9517199133306271549, 1066058705882005165, 8365496980814928779, 7686746440596632791, 13176504626066527022}, + }, + { + {5447100387998907411, 15776278570078464376, 15224157255965180681, 16441839948680600381, 8813248177057271462, 10796641304027905046}, + {15358728422211379791, 6653135625270840458, 18255855576461478753, 9625920573335344034, 6295553526678577130, 12814858875321523185}, + }, + { + {17422403916567477760, 6238259464169695174, 11407009829093777631, 14718862258997290816, 14501697263370095522, 18221436165995139407}, + {6055444735226512775, 6768775017420314875, 7196971579967975624, 16790550980878240131, 16309548149795408433, 13384461631727488380}, + }, + { + {14079161021446380314, 7955905127227850069, 6465999511395878315, 7788108352019910331, 6222197449376487017, 4871252710770322572}, + {16673373722646856051, 13544022498694656238, 7378084945975549635, 6707761833586330039, 12377553912462035692, 17347971251371560420}, + }, + { + {14395815921984889730, 16242663560670555551, 10933265444645517596, 5914394225264036695, 16421696853010989602, 5685552142879689368}, + {12020206507361369768, 11602855627342652015, 5200080540337794980, 15877202861979761300, 16623062677785575198, 4399280632997370270}, + }, + { + {1019528443634077636, 6201939062294227465, 2193674349270074093, 17838059521213356953, 17494214752031608293, 1870623058299198966}, + {11485380789709140498, 6901145761334773250, 9249667932906723287, 9945518497873500003, 2287783742604500536, 15642905768346824183}, + }, + { + {6482332546440863608, 7760091220023803488, 3238194504321395476, 11017818554400598448, 15989612191997623737, 17176177776749389800}, + {9233800304624853063, 15940633772893955963, 1055365280899111788, 17832351193102257533, 3728875607894595859, 11458906737664282937}, + }, + { + {8155436981174747409, 4245212880996209373, 7397768860981266872, 12376011921970823763, 6727814153288120097, 4925255243200109984}, + {12956382084478097801, 7578047214327095169, 14028361267843039054, 12893429039763352989, 15016902170609700113, 3952485452273593863}, + }, + }, + { + { + {10212113970351356092, 7523429041914331341, 7486406457607204412, 3324890123572559980, 3609678540132843360, 2779647883674003080}, + {10785490009290216694, 5512178091962365081, 15405389773555373879, 17119053545814414444, 4550915783680335364, 5243325139730264225}, + }, + { + {15514067016142951342, 6798704670058921365, 15788722941232068928, 11593726264526847078, 2286988197169413876, 14828646074338136439}, + {2215588591344044651, 11994073923064762522, 3627301481345142037, 17167985271749886895, 14022445437114653662, 7923678237890136587}, + }, + { + {6611156704115509785, 18035620512627347750, 12381083171658118986, 270239073191874966, 1473931467604861674, 16752630206679926972}, + {13564215097326132206, 4074525343054815713, 177585984812302656, 10624670211816340622, 10109313618255604651, 14687069652115498251}, + }, + { + {16146132531590710538, 12624070149355925261, 3371340830834921143, 3637666900208692421, 12578993021430103850, 8399914141968916590}, + {701294690134606357, 18348654154222046066, 16080787544185533713, 13729499035821774112, 101002779873624994, 6415359183199533087}, + }, + { + {893065980645567055, 9780512522735000137, 14013587606638438320, 2042146894211661930, 4926876227730145005, 17705997753590203223}, + {403180381605128100, 2168255912491056834, 2400870712237917082, 7361183795795049574, 9566809726615509364, 6303637469757763886}, + }, + { + {17460362964014562908, 15586968786742110252, 8494757460457574325, 15624700433298528101, 17318575918908746254, 12652072085873395255}, + {9835587478950302112, 15548301433729187970, 4835168265500394400, 4967939877357046781, 12172794064315424711, 13503969662963117963}, + }, + { + {10829288067385404126, 18368582702063329154, 7495898914356102398, 6638691277000448994, 12421305448095328104, 12913821326734578178}, + {8084574956986873667, 5701547954903136324, 9827732902307175096, 9844605815961285215, 12681790933515557867, 11120448073083314536}, + }, + { + {16068344822778820192, 8689936877594040165, 8315547524451662260, 3879243152723994807, 4538257327824274009, 14758576181122195171}, + {8434922169634574674, 5728614983829345478, 1650023042553620956, 11308715920844572662, 12984057269003477315, 3325170259493507497}, + }, + { + {2598915533513585113, 14183744977018914294, 181474781586722719, 14637209114370560238, 18213257975009888133, 16601151640440493077}, + {11667415477497099667, 14085199965267867494, 16721473494118951513, 14499309470908758904, 12850701150110062639, 2986900412652523759}, + }, + { + {3221589256444770394, 11214409482440895328, 2728454368684972041, 11241800590680666601, 4667060631816223587, 4054750084181257934}, + {16826694011900430102, 11268855356189298229, 17144797540779468702, 8125742309270210655, 3796632567822982708, 8322624158258003342}, + }, + { + {17852794608451085917, 15586644236280880670, 2638796224141730299, 6571369537216725099, 17238484134695994919, 6584002309074770367}, + {332176389297000027, 13368981597643817994, 9475905376702633, 887026676346074182, 2659944342595076192, 9716495411301164463}, + }, + { + {8760436800248748645, 16559589424441408742, 17728067511446087541, 15979039360791931099, 1186131304518732359, 544669493272271576}, + {11512458030364033194, 4234660342823911330, 13269362908985131848, 6620254276755952341, 2472637252854054812, 2804760878774068057}, + }, + { + {15928091392978072069, 1045418146814199706, 7425379098630386963, 16455708007612906306, 5515953762090790798, 4146738699702553135}, + {5126640753769911542, 15649236295646849030, 8100061362821164710, 5931546784464607243, 10980236595948879217, 6825063281664784010}, + }, + { + {8543951044930873896, 6542715458284226112, 2761529550697027755, 10608334059217377785, 5013963483795824785, 12907134297467450098}, + {980382309389436255, 7808952507916033869, 15275563855873621709, 5310054094388396360, 8349155105071860026, 11043771142323384823}, + }, + { + {10152873500779880984, 8921920392860909449, 14073008766417442634, 7574006587459435649, 8742698680973393947, 3634151658166442700}, + {16215510897853847342, 6313231586526240160, 15374028344552157486, 16025015223144590637, 4962437968942642052, 2389997079243177935}, + }, + }, + { + { + {14281041519735018975, 12922311381137007214, 10232502343768314657, 1134871332686858449, 2406027671397524741, 8211135280367851709}, + {17686015482034995045, 13964987788145667419, 7719837707443653733, 11241849337066564058, 6107424228088781549, 6557866097251668304}, + }, + { + {44745771075211169, 12978700281287734965, 12341083357048397205, 1797820217645587144, 16645470871308398952, 5574272877734914713}, + {17391736056610728361, 16032339083920183657, 3446991150741449782, 10033643099742979783, 14851902199569135753, 1830235897561763723}, + }, + { + {8645411699894411605, 1426585791906124213, 3579550076805920171, 9083173147160007694, 11631776499533913846, 8510913582608227570}, + {1541698565399230466, 17192733751495667997, 1610633544366852348, 14882834591025699164, 3805773893383467941, 18227555101610282617}, + }, + { + {7654469169679738716, 17884541881059058957, 1658182501566786879, 2647862499567454261, 3575230054065121063, 5196577140526681418}, + {12604411569045121957, 13620316591036967083, 18197402841216136733, 16577144861751835196, 1856064252812727669, 18261694871001689672}, + }, + { + {4917344388382226976, 6330884756405843776, 17908872738552769229, 5244919991308831166, 8697595492991011433, 4947226470683672404}, + {8425523832699364501, 7754795213298783206, 8063207615592653394, 3563540304379150938, 15696361418241150720, 6209953025795422024}, + }, + { + {10542961880027073714, 14819776903900712189, 10788823732453390406, 3505823457495732649, 7370161041256253297, 7602319824210592069}, + {15683925906988243629, 4273670365516442517, 3693480665904390884, 16506632164939082014, 15344251801076915117, 9664860330838560631}, + }, + { + {13453231080122146905, 6512465127883837379, 7629388504183246683, 4217401442467660418, 13133301451058498685, 10166079809976017824}, + {7398318211270177803, 8363389463704327290, 10324465568426256419, 4965710503345352609, 2089060017802990689, 13427246861509147536}, + }, + { + {3328996401163396997, 14795923992923049777, 2850129498190588037, 2818567789790091571, 2452485851215886435, 10898789027092665189}, + {14647661412525870291, 3599306402736479964, 3756515659636605976, 12815169094441383661, 15786213320252390618, 6231903730571064302}, + }, + { + {10711642105210749960, 3964832036350312570, 2594869633154010768, 7504273439683990593, 6171834057422616095, 12806635729425016087}, + {6242042828168471440, 11746641890873718074, 16615154546579032279, 95454097875132020, 6393615725707696241, 7618061211687978664}, + }, + { + {9930957720367733639, 1077368814711136367, 2417053219800485985, 10848530230418354055, 7260326287853856173, 14141227535390115151}, + {7830749040726146784, 9016206039825747868, 11290344305602325972, 14750454853595294291, 14714683920601490123, 1432121990527736048}, + }, + { + {17441977106390458994, 8730805915901635226, 5819567079469848168, 6321912429222256985, 837082610639548473, 15410302798534400718}, + {16852273756502231397, 8917666851023000894, 14301029351076598242, 15350040486231497808, 1621413004527249197, 13889481477114808738}, + }, + { + {8916394881822438043, 1646293865051273262, 16633458954488857984, 1971089263341201042, 14055873993496913092, 13954758750729316517}, + {12992583064239709509, 1952701756447682135, 5933085826608622333, 3590325588620993260, 18107021064040771922, 5262440036415899013}, + }, + { + {8672666323143994986, 3432698976158862459, 7932092920769909604, 9350507304052696520, 9950195840741471235, 3384863162662803302}, + {11269793069739340493, 6207863446301189912, 12329276380474262269, 10965144619249951761, 97704029241884757, 10457642244982072945}, + }, + { + {12371754360290866894, 1591074855650384155, 8325409655366518323, 11442314427085611305, 10875405650221560131, 7491900189345980515}, + {17244250783259713081, 9507080483851292003, 9417267023896977595, 4243988893984453349, 11064476576986125131, 17158304321030000154}, + }, + { + {5517940657612757396, 4123868648127756780, 943948557181189068, 6078511197957700447, 13220388742767098964, 3184112381859294304}, + {12392153938824408522, 3168610752876052364, 350018255493345977, 2813965382812065687, 11093319528930675311, 6598131031733576701}, + }, + }, + { + { + {17846260309109160862, 1306797101136445625, 11647460062050134126, 4280254741069645613, 13550506007057592994, 18283679445420746708}, + {14822459580299409390, 16348337099471471523, 14343139876287082865, 16111294748648165111, 6270862100768665567, 5789912213367358682}, + }, + { + {200047379930668220, 3107506412723209866, 12635605344473049868, 6454603385777743125, 3634997813341433192, 7438775972421422847}, + {13638641130311201683, 11030479200470016288, 4711568272785668705, 3373744634232082099, 12735396517885935812, 1666767200715548592}, + }, + { + {1661699022230626915, 7732150026917057818, 6874108361236320794, 1159587009959479866, 7007379701174607195, 9952444100833302939}, + {5965322983127194050, 4366859071433931272, 3231323670368819730, 18362879607830583246, 5646154626466164812, 16999943723339328275}, + }, + { + {18089243736135451887, 15837467602480156595, 4979955351269012725, 12695524654989516016, 15309527870169710145, 9923199650873375699}, + {477633266795650405, 6218407297793375468, 13972928132308654086, 6804584457444043116, 11304504344726657230, 16511473903383869711}, + }, + { + {18035621934283433559, 17683775718600141872, 1200977174684534015, 5313684562476274913, 16332322452774063686, 2145323195208686943}, + {1572586157017613665, 6541397378767315724, 4667619245659807579, 6374201727420350952, 18032000221066592915, 2059105043707958084}, + }, + { + {12166351370380034203, 7102163135877977227, 13332299513090850017, 16122777051352557935, 1102940088487877845, 5212887364114727166}, + {6687171729958891220, 1664933694283032903, 14897359728576714580, 5549891844111603232, 4137590082941305255, 10264069531127198424}, + }, + { + {272620083016298055, 17189778207291663400, 15639379971966818574, 3447379160890980726, 10696794611439970864, 16890999064760725295}, + {9003356812390325490, 166360430953008789, 6721503120622592701, 16752071907266696152, 10459887288559544412, 16460372927471671270}, + }, + { + {15720666782902086695, 2243636647767906075, 14348999864993654614, 16530847832477493511, 13572226349455897926, 10485166353342867630}, + {1701375111884628062, 2188828106789127558, 12645689658478144853, 8016727425888546008, 12431997919751623083, 7136689765653286632}, + }, + { + {3054654888507663517, 3901732615579060999, 11618712726777764967, 10400033150633623763, 11673620844004038101, 5065261890057318586}, + {14496601939391821092, 11531645523028139605, 14474922880926708005, 7706650634046982502, 6570274599504352046, 7642596377689896565}, + }, + { + {7699868198387215867, 13465612880023018168, 6802825825452629152, 17947085319706590740, 399098071367693766, 2227253631387109201}, + {7913744672279207864, 5711722633374904101, 16654422138819448366, 1591238867781947932, 13785062295639206639, 5681650681074277757}, + }, + { + {14302942159889415158, 2510726813191413600, 13501150440879192520, 14000061751928804479, 6039954540724187037, 7505529269867033702}, + {18250665573771576073, 5127325503233443708, 14065731457493758594, 11160674673771208971, 15693171419798520829, 17233795126257791284}, + }, + { + {15622130931527103601, 16901855276484525272, 18102024747919573302, 7726517490109845107, 14147913176577212424, 12842015409583521397}, + {8781643538636513691, 12123988514306098157, 16318265076922410388, 17085813739519115894, 11427890478685706148, 13711950220864410601}, + }, + { + {6680912247635161790, 17580838069043296523, 16777963020027530302, 5469775206057287185, 16990549936692332421, 16432218618617031088}, + {16382011306148463125, 16249390935258095721, 789229423855427321, 5584503286135036603, 14761218594144073940, 14540866621986964431}, + }, + { + {9496858985145256777, 6425875918734527060, 12207380394759736422, 7438079918113743538, 696640929848616795, 4155405326832419357}, + {10690817436861400384, 1479037799171245484, 13853435209996737946, 772955156615502406, 16556804502651134724, 13405497439711762710}, + }, + { + {12180390271623191338, 2554198210777409989, 15828648806466804950, 13386302369804389308, 17877328148870959009, 17063001337418714450}, + {14566511491060416421, 5205063642854029012, 15266492670006985909, 10920630473589926436, 6854610609610056970, 4823212255031433832}, + }, + }, + { + { + {11555239510565564423, 102493428844323960, 11265440475505070062, 6954957201906837447, 11578828270036850246, 5363571767815413948}, + {10687688618938071305, 17560569863417444168, 1763490681657096693, 10285148253700502778, 228169834671249043, 3817223026964299801}, + }, + { + {11869614854023374983, 12616170826516189176, 1249571328192797152, 1152755290640443365, 17679907775602849695, 11345355428207169384}, + {92124442948271692, 15136392605896368971, 7174298541623418149, 3977850961259601135, 15260799075573749863, 419190360224954337}, + }, + { + {12941138664806365009, 78537568941164918, 4499564597238696841, 9259817189360690299, 3875404300171494106, 18031393974005709390}, + {14230220635083072083, 8633088687256087821, 9439675871539484936, 10592074684996303446, 5207584782270069594, 16579180203133498559}, + }, + { + {15911051168603653765, 12912915675404184524, 16445705037168890851, 16740563878098656388, 5961314645410792024, 7476305351043019972}, + {11904755216174892471, 4508187020781349730, 1122261304753504973, 6085882050766589531, 8389757320097382309, 13048473480684052162}, + }, + { + {17680809686224888166, 2880007448785334434, 17671705111659901281, 5357941687184787676, 6416428659886206805, 2539295694241036705}, + {15493556906347117063, 15184359621150444926, 15623522089297218213, 11422112823115234443, 10761632026600704373, 10659378440527931495}, + }, + { + {3820135739709169880, 7261377824800497120, 7489769782834815216, 13165627835187312122, 13110045944249714025, 1304982596015592431}, + {10409327089880860262, 8119523470638259517, 3634401951306540946, 1979100535727127060, 7288813164350284510, 8247925357758448450}, + }, + { + {12278090077201324890, 16864061172993697783, 5587071207462858732, 14536122420710742668, 13859058519726422179, 10645667192932212843}, + {15670105262718068703, 15430134228548786966, 1251089591865195285, 2149683357007094264, 1836398382617121265, 16062290149085488761}, + }, + { + {6401472755905860665, 18251568613645282796, 4758943616732471246, 6655672671851225203, 102549765979647744, 6901551898032346073}, + {10154259747808913943, 13030720662056447919, 2754179948730913899, 214967400224523605, 9208467612937514595, 16909326990814546062}, + }, + { + {6054271246698272853, 14544060829566630707, 8136820029398201235, 953136503654279040, 84568208454785546, 14305961879546400571}, + {1732011551860061479, 11399625830128770326, 10400513758237997842, 3165162339732221581, 9416667999137637971, 17092345029934304618}, + }, + { + {9400098298185420887, 5556041148968335564, 6912036430365340369, 2944702321639771461, 13167226429156120766, 18187144612223747373}, + {7959639088001081413, 4236408582243967575, 14543785681099574184, 11098877575745565163, 14302577285379639548, 10484088530600671912}, + }, + { + {9373483053259607268, 3543313042332813439, 17074705243236711793, 7450654168557338084, 16833050907477987107, 16070783762419210385}, + {540551482092433485, 896422619371514104, 138542949191418634, 18265302404419375371, 16792245401695248275, 12353390887345526565}, + }, + { + {3539472665850408941, 9973857813280052924, 12971804241703503646, 7407990072499301360, 9559955945280406647, 14424568234166047002}, + {11096806861225971603, 6816003284380469282, 1147913720130733539, 13720120058704725060, 1399756058361164073, 983212633898190589}, + }, + { + {10664997543956449171, 454517167775805631, 15856261682659737800, 4154393874169146738, 12268872310704088235, 11262767255104080967}, + {1686376439172079011, 12012369940855624242, 6114883187951156869, 778196593644747678, 2384399524034132671, 15059515630710187014}, + }, + { + {16693905404142293085, 4325377301783117143, 2580347499530969883, 1407527347166788600, 17454091049478095854, 17446410903937548513}, + {12048478360023053515, 756323182854419638, 18183393958679661690, 2276830709283047969, 15484089378884863933, 11532985185158241406}, + }, + { + {962670163839534853, 8108389445709454545, 10885345009931744728, 1709075883125195127, 12639892596513679369, 7994345234505196064}, + {3957358292438775986, 15177501453635460453, 5749874344089288877, 13980629880591955685, 11290207695256566671, 6266738518930986595}, + }, + }, + { + { + {2112471176772812653, 5992610445858141042, 3359824065683384802, 14910744199028914975, 3540279332055051816, 7481318687562895300}, + {3778660497841133917, 7665160960416784403, 18344176739282807989, 6652353946044311969, 10335050395834175287, 829161198718552289}, + }, + { + {987187890721916756, 1180893057043299417, 7997694989088471290, 13943477209509617880, 5789135275803442933, 15003053876978578152}, + {11491981179365890542, 9783628750553484845, 78941951872642943, 413130106196007898, 5965786292528401894, 962843809509488765}, + }, + { + {8077344451961036015, 12071091132773222174, 3465673301214104928, 16928369631937685883, 5355222520769513898, 13361191077839573619}, + {10372078388188800788, 16137701973564428727, 16378364657125535444, 14147781750402923873, 16760187636270495320, 7550201579272756957}, + }, + { + {14084923669266627263, 7553568273380849735, 15691370880642541716, 1999581770825966126, 4575194939013031822, 12495949140700950136}, + {7538580687408334777, 17053011349491117810, 1716759308796398676, 16611187257146498231, 8469759805465235212, 12974300428352030494}, + }, + { + {859955691188282569, 13352606119576189973, 3180693414073792430, 5959867301005659300, 13835947303818547540, 162851927886880075}, + {16769940376654738256, 9939117735531953429, 13149699086290415664, 3305357061162836785, 9009939707511121271, 13981210403713247609}, + }, + { + {15280492422823355766, 15236897741281284068, 16375251899685919662, 2375999612321238009, 6002020302005330277, 4867913810970375080}, + {11372869170822493237, 14166186567360268594, 4761141133604528346, 10183261926525426109, 9349125973207534361, 8199961450165628412}, + }, + { + {11291117276267195299, 14973998728699422778, 16425655270225982283, 15329324944689574083, 7979576976920559153, 14994530807417641960}, + {16703738914238983421, 2834957708878859809, 10020001258433278091, 3066018529077593047, 7903800555273951661, 13033393171964190854}, + }, + { + {1653789232981578275, 952371650849832179, 10927445400776044968, 12157933816885775189, 9290507541884583865, 12826421106361126902}, + {551558165798937217, 1729101615745031644, 4791663141996814522, 16904640700879459114, 12874781959897756061, 3513760684524485070}, + }, + { + {8207357056686195321, 11137222442007015668, 15645132451218915478, 3105709674939731826, 10607257435983024941, 16912916807528355764}, + {6323399773421218599, 2748551999608353527, 8626149829332963214, 3316199943098194703, 6716681752170794378, 2936787212120932946}, + }, + { + {15440834838198080689, 931869522652835594, 7592851540253747298, 5478596926880972349, 6652810167530776258, 4577181343372966932}, + {13801964408907248297, 13739037151947376992, 8697064982745685286, 12401883107738713638, 2448777686813372733, 4016677910779410184}, + }, + { + {930435436459751529, 7291335211208166106, 8662147097774800941, 1754832412907874485, 11716049188393912454, 6088054938180223267}, + {14767636360685531193, 16761369108402789416, 3774240452651006015, 8812730740575156268, 2441588704916651547, 6532572576667981720}, + }, + { + {14520642821078702231, 9152978367661523282, 6377069713671652085, 12296007202473970904, 17767917081512566521, 9137555524675129570}, + {339729066832634027, 13577486648345315707, 8784435346186982538, 11788746341130221385, 17389275735918464762, 1499091028328348784}, + }, + { + {6895056287740805821, 15551414767986485684, 18245567068949911079, 11780461279934853858, 17514165768801962395, 4604945067503181622}, + {17970049594076464754, 5131328972180637912, 14013492191391630748, 13860986326135334440, 17262237096531626622, 15447317764876697344}, + }, + { + {9241932972904406753, 10136261935647290984, 2240671992235812692, 17354651007012787836, 3225243242586300908, 3556466132564431774}, + {15035753318658290895, 17220643029876180698, 5318335111039228183, 4424502322878902841, 2675895669690622325, 1884586557676234029}, + }, + { + {5250110106303814488, 1975207799636297674, 13532036578394208591, 3969043079520697544, 5728723625100363223, 7158702673653973988}, + {16195684125677252996, 4149751094169622529, 11846551373222263809, 13787057146822598191, 16962390587607642862, 7670754904406853980}, + }, + }, + { + { + {158721254439694626, 14016472328785146057, 3215742685919437659, 4283116501421190228, 14416945229571419453, 3260361759779720928}, + {11569905182149055942, 13365945824267994176, 9560316005976549600, 8014152880174667326, 8983248355930398915, 6003107822914970018}, + }, + { + {11769244887375954354, 16734798255146218250, 7450660885486578621, 13241415025693890385, 7585701487764431710, 7068349087572048763}, + {11673574025706412973, 12054573315442038381, 3465595090934871151, 14116150045410515995, 16747453732925727391, 2053788472539252039}, + }, + { + {8254128435175778191, 17961721281775180333, 3465171206067904370, 17786859311178538748, 5750765123994852536, 5373889982583891369}, + {5947994461711601875, 4264969794290341217, 5733140740964071824, 566813084550213227, 3008438020483790267, 9393523034553376074}, + }, + { + {3488992165971683960, 5408858964234561845, 3943860838659448298, 10606370049279338924, 1497444843416374478, 5655792335049791924}, + {991809778400186594, 15331432498205269189, 14409135173658903226, 4844024566576229783, 8437358490135848140, 15238255612948837438}, + }, + { + {3981945260589053255, 5238428271891653292, 17666609270668276737, 5136761226420502964, 8998438003563725182, 2026122825528004680}, + {14800276493572942057, 12172612348684122426, 8309771000688236057, 1565694914599287285, 14726316506042877882, 9150853180590412510}, + }, + { + {17340721586269964714, 217529583853973911, 8591243800256753437, 13887006532271166813, 16938831598502428118, 5372377227102637491}, + {451250041397357076, 4989306166373412675, 13630414847684491708, 3996969106514180362, 2275313485002180685, 2301296218808044149}, + }, + { + {4291242465719312676, 10844339224270608311, 2121832093979610215, 16773046612047697523, 10995952484439012381, 12237539089984856911}, + {11585863874855568916, 13849634900022210805, 12285224492680055214, 5525310790718599719, 4273270766854007820, 14699310461571394996}, + }, + { + {13339800343403240396, 7709432974418657015, 5301385839232292107, 2969538953397180786, 3800860603349698317, 2508772359731689564}, + {14378517458066378354, 8882708296441449226, 8558667663066577082, 17076224488360060086, 16842404219922924015, 17095860696531681717}, + }, + { + {6709186302039351677, 8451434297354584619, 4758927276311396271, 12322849161987713036, 3702550498120081225, 16306272953980522166}, + {1037682183893893480, 14663627147661191968, 11571949542375472706, 5714568058845181963, 15981901038671696988, 11976708367028629004}, + }, + { + {11207839561296012338, 4875894249269467127, 5107711364762712689, 8192718242078932005, 5352423725257079410, 3571810293108102994}, + {5515509758059991725, 7457615682786317799, 4860181546702428200, 8930731253012747041, 5659928076906420302, 7496101079865843064}, + }, + { + {12022229726853822462, 14706436872065443302, 3389725333074082852, 1604903701561777472, 8950817588405763739, 13190244158376540107}, + {14016236309633488294, 8475371081917274175, 9944826967483171109, 18053549564499967546, 7930723406558155263, 4626913441465521473}, + }, + { + {2715165459263721907, 9674001561320555387, 12396221282651500645, 3973238506618524626, 7278954243806937758, 9176131567068265043}, + {2372457887719386534, 5022496686095517029, 16913411979107538659, 11089957791594060315, 3232871551299762533, 10181928965032453240}, + }, + { + {13077103522673276166, 13953006147353067459, 13937321564029460312, 11775289180731898757, 9005718366158380378, 13645760323002406046}, + {10332481686150199318, 5314709245555453273, 14740068464959386027, 39846363329861329, 6936258174745205094, 15346255345000921785}, + }, + { + {11902235556304614325, 9716523013532558935, 6408642420452662970, 10910145013733353424, 10487750635963941672, 3263923993556113887}, + {3979263897601764948, 11489365827974628507, 5295637109315505928, 6972999611880974771, 1108442977000346725, 669149380592427324}, + }, + { + {1157132430713125844, 9939423443740928614, 7186655438202963643, 14372268141018236868, 12646427359638789024, 7392025192496396479}, + {11172990535174193001, 1182082134585836558, 2511299207918210769, 2172910944443379020, 9484470871043901670, 1230325285277248870}, + }, + }, + { + { + {9665579348258363865, 2087918080557695122, 135537599087992531, 15215723868160805464, 278908927488187941, 17503720082240216915}, + {5744927809331053213, 13798298316314029615, 9696283778270547989, 4870358740201919966, 3439882118475813321, 4143783440792496951}, + }, + { + {7769489242957847290, 16684864626270304081, 2879249682816493383, 6265076094334458119, 6886499504502814482, 14195770023097875547}, + {2631387143433279288, 16031347118135873637, 2311344129842860939, 12572114332759228948, 7732595900970909006, 14311355333002206999}, + }, + { + {11228237540890978828, 1079293124827979304, 7487220471408651681, 13548174215752533194, 13320332840506137434, 14014587572505105518}, + {10308451336179922295, 1971803029831470018, 3369232812295268792, 4471651358093175556, 12478347644279240383, 16248645353907765158}, + }, + { + {881896658963638416, 2026615415208131225, 1975014851600144074, 6268313587596276173, 15189049743474081851, 14141869123482614039}, + {4695467916519996154, 12465708679157180870, 11422608049605393187, 16598608052494558909, 3756011221236491774, 8063000249101262382}, + }, + { + {5494197245461486331, 15364625217797987691, 1134233848906038918, 7726911346031918100, 15503554540833122104, 9953446955839429175}, + {719175439330210354, 11993546280891538825, 12098356945782186267, 14761662828882868605, 4054521887535828822, 568836477239613961}, + }, + { + {4895604554173507232, 12377758172579626987, 15401866685509290286, 9150363264406780287, 6123727635885171426, 2013086363637951538}, + {1499537875756117851, 10260341551071830418, 15012297749974575104, 11295782034836939405, 14699384490428880947, 4058564242175274162}, + }, + { + {5697099271842625185, 11897498065292086007, 165253007275908673, 8683995743377403005, 12085865296553972670, 5953667974147175744}, + {824129719356249097, 17390674672020315024, 14600835594781296921, 14157907740151210460, 14620516163389564217, 6402637035301660148}, + }, + { + {6814805391879506821, 13733360575773203028, 14964423068624665929, 2845857522246553444, 4737277078061891938, 14974979150537406091}, + {10199845472834911755, 12457032282300718325, 12509382395143476419, 12723831063072297351, 9804751755261218393, 9738618498716380065}, + }, + { + {12971320806846916743, 6373340119401674163, 14940450957165318789, 6054294310918381610, 16262716106286726308, 11738163287805791020}, + {6651936162381007336, 272251828638977954, 16782812253935098255, 157477203834421822, 9758166039167226447, 3757098019902685001}, + }, + { + {2797914620292272718, 6824445594276636543, 7612944636508242479, 12310914090409404192, 5900414063625470828, 1578574444575760813}, + {1746963247281383230, 8358183515669196030, 114807234762833252, 3434169954702426697, 10754906727586255973, 13248437026834498974}, + }, + { + {10367883878888843605, 13209011820972196415, 4546179109832588353, 10048885285637082041, 13740390940277885181, 3897350217203120410}, + {4420913340021562814, 4575173797445180389, 9128196763097374162, 1507217548372129726, 11871635706539357657, 731457449257913541}, + }, + { + {12327596966828336878, 12044047960030865903, 12590450765463213560, 10493254635328920048, 8651077485178084369, 6371936575607168909}, + {5090312744055455793, 17685482889085467956, 9393295431338315435, 15080146787113774018, 8385657726957576620, 3383348226554775383}, + }, + { + {14588590004163196212, 18274572275841358391, 7651897004994035620, 7427055507937608536, 7778320234184341217, 16916348689537901989}, + {2419944192928809758, 8857445667038434995, 11459028014322971295, 8519876766524924471, 8951414995530421895, 11510037251020037555}, + }, + { + {15790971709064914690, 17551616639212949181, 17685426066530430956, 8470300602731078412, 7440168085597529492, 7627174044502506272}, + {1710862283221741969, 13964871482694027643, 617332758617265162, 3711135961102404485, 4655924078995340065, 2113569679148694735}, + }, + { + {2154983266339619301, 11861362304971063147, 4258182409238841621, 6253453232321750157, 15909672604786711366, 1482606699963487564}, + {10258975978079697240, 4952492506950453020, 5749995703462780308, 9651071132904525497, 14977376759992362124, 14011541847161628118}, + }, + }, + { + { + {11998317121553500299, 2582325766599936510, 10226444194055732720, 6578918458494290458, 16856344663543484552, 8023206593552703223}, + {10896969734623517030, 8965286626042649860, 15869898932136510986, 188758287853374907, 3043553330642597875, 4825743274601412340}, + }, + { + {14811264716270138923, 9172209925012047033, 16222958531492700587, 11130963356286229429, 12646613143129669873, 15325043128670486670}, + {11347507763721459405, 12900058314528881450, 5171017319841793302, 4651322121729076016, 10307557446743606869, 6055886709749279778}, + }, + { + {8183782069332642864, 4400608719297868437, 9887680839598123793, 16997602958862657609, 6307175890874383417, 14450424872255242386}, + {6872546037892456974, 8399143418250687787, 9134623456632335969, 13760709404346799708, 12989741448870036879, 2909960824443156805}, + }, + { + {5430907109181030283, 16527229751480129461, 4626559521361924187, 9923786072582407723, 3599523730508604347, 7403949125284615057}, + {4562148631066323166, 5805336986933520185, 8257255431523708381, 4507203543461357226, 5619824380968497684, 11986819821861980903}, + }, + { + {5319261111797206279, 4857131879138244426, 10148248807556188825, 11267161186123495115, 1870130028222872285, 2706665384656124928}, + {17899120971855949667, 3796430035357845496, 12931652797283355998, 8202504218162242839, 4247443200870022359, 11773865795553695256}, + }, + { + {6197233327569567984, 11863568501944321119, 10309410692812279373, 18064151364176098605, 651644022956656301, 10015612095276572238}, + {3712079372837513925, 12629021524719225747, 14243639867450874095, 17310848059794411658, 5934269651842912614, 7281399930842709350}, + }, + { + {2511581009523899341, 15219471439294737719, 7319331989694981973, 5501409405436918279, 16976076438864148161, 6162909726068177573}, + {16008540889386100268, 4274652746244818627, 12394070200068488667, 263293445411113815, 16742410837666591362, 13337130885835734358}, + }, + { + {3564999479898740369, 187214543496040556, 5760327611422130945, 15928347702080842921, 5118946570680674960, 13188149096923612709}, + {18076374160986186344, 1142074025295083811, 300437958095382782, 16478562199461788278, 15937231598514871133, 6966938597435454129}, + }, + { + {13530583958756622194, 16230919531879218650, 7960208013515434222, 8928487179767185338, 4297154246225352437, 18083693613832338785}, + {9858555096056225549, 10553430097471230871, 12398865197153772201, 2169073753193400460, 15971418942371450367, 1091129085077207635}, + }, + { + {9681282287508526911, 4228346943866017698, 10211475224895899114, 1698892461040930260, 17803383979093774988, 10310416508095123236}, + {14111993390309359036, 2601950955716363720, 6730639879397050736, 916578826304680783, 3894845782969558019, 14122184451458658420}, + }, + { + {311655445282733128, 2366794277731754693, 8447159453573507161, 12862724207019311852, 10879028081424972165, 3930832077575481179}, + {14584836693230155370, 3726981236135324025, 817259866591722463, 134655665446114637, 16268648157415006878, 355268316254117109}, + }, + { + {4860532288606162276, 11004314106081710488, 13906897172384614977, 17082455640344885157, 9775380650399905532, 4859705013148787294}, + {4027669077440695384, 4484628209953599288, 13138896518548468962, 18071971245715712413, 11010957284943999098, 3796309351538330539}, + }, + { + {13949338558872623983, 13999822274187176958, 4733168546809278902, 1627926466897635936, 17007149557493659471, 13788534126928728612}, + {6675844921694720089, 9637011121617213286, 15573984252403764668, 2898513089190539810, 10606052222462092213, 18300597426015463926}, + }, + { + {9020738854941186688, 1697516889381119272, 10894637951430404070, 15457129124942948177, 16383433189144661467, 18047431570429355124}, + {6107850723361208829, 17243425140244995421, 13395554308381924491, 1364807545420052892, 16213716354723238556, 17690236310907832398}, + }, + { + {2522091960819005086, 3742779915092319093, 16499486839317582864, 12740630314665543268, 1980734899856062565, 12849686842043469074}, + {12935833425771077826, 83225990269841200, 15699446177561037505, 11225486016581978415, 2649847060493723129, 911854890207243944}, + }, + }, + { + { + {12424795815234096738, 11929854285805518958, 1614907582435615152, 3243608722624509713, 11618089050999655243, 16450991037761706190}, + {14791827265740380694, 16253295635917069809, 12967661044055669288, 8950779205008902591, 8504639429942410457, 17167078365929060886}, + }, + { + {1313046233449071650, 12998265777408570719, 4977133893460974672, 2561165906571264315, 2564935401972071022, 10644027015828213948}, + {10686048288050006911, 9039002669587247392, 7778186232262317846, 15418338195770720773, 12395635872224741505, 11648627441950590376}, + }, + { + {14681037105441419090, 11154412906553738939, 16558423151175496356, 6285030627926492227, 10290832285247957235, 16522750161805300815}, + {4436228920200714418, 2409858423294994518, 617155725363325676, 14011524653303053004, 5177797359236803245, 8290899194960599185}, + }, + { + {12435263296022000489, 14513062589041133148, 3001590359688622693, 1093106399238867375, 8390630854825882223, 5298071266967498440}, + {9716703994510762833, 139163142171401861, 10954439330188883947, 3997722728391005309, 15245271690519046411, 2686187644733347867}, + }, + { + {11528745980014882011, 6182430424023761381, 3475082923360625607, 3076073459063455076, 10378442361972777951, 1928653322025847242}, + {11275859159200702717, 17732962924665430019, 18439987823449214394, 7064944630179873720, 3304719418024411692, 2153772832250412099}, + }, + { + {243789443148875657, 14348824346423476228, 9830514620004209466, 15033617551094748322, 13287145353793822594, 5879970292069402674}, + {12214538079058326601, 16847679853452995547, 18169365757890727021, 16879879400199284117, 7800932071917017135, 12460054258572695815}, + }, + { + {10090114058748492201, 7363290374561050715, 7843838338279350344, 7920870311130336096, 10170914017871367100, 9865561470166537637}, + {9334256772527683640, 8581897812539458667, 8599471352803027994, 8796183458658268985, 12659201731590700622, 4970311472744086260}, + }, + { + {11601996913454808056, 2966774980339442523, 8806491719792949791, 10028525763203412255, 17850477211982122081, 13173986239201796652}, + {4294659508144450490, 274180317020745003, 4247201611788433227, 5939975532167416714, 7655114550003254785, 18074517862019706540}, + }, + { + {11681890644329677881, 2335615570183618708, 12700694827537854982, 6177201878022338797, 10745204280522885060, 5447698501831385650}, + {13944548355133223332, 13427954271655744372, 1758846050835724655, 4081176162908411954, 143138826110337136, 1333853703322284874}, + }, + { + {2393802334236414897, 13598149804179976864, 3558363201881498809, 10555101826553612932, 4227704841951906537, 100142050362332829}, + {12474424570957807697, 1991825797392445989, 17078870348149694209, 1571893036435136749, 11842302574300496814, 17791109433102614838}, + }, + { + {8550811044062711868, 13733211819722662864, 17711131098892634177, 1540706468250987542, 3800475869236690840, 16871019571035580709}, + {6156757348293294843, 16929121828562583242, 18390632985111796241, 11618787844989532555, 10141372211456532826, 10522160836096579564}, + }, + { + {8165081209334278958, 4318582065069784775, 8081574069194739336, 8837613972613683181, 8266196792698516362, 3864857654878740737}, + {6803499104632318962, 10355487208936010141, 8739779104813710437, 12797187628326760113, 12836259478886858533, 7668861972296903573}, + }, + { + {8680747440971223366, 9209090258749385791, 982535240747476893, 4968038987235564059, 16403151423719561525, 11948841256741010288}, + {12550112619626029423, 12104110998874624802, 7496321954500925035, 17315621249735120555, 15846515502273544800, 12285193498005904194}, + }, + { + {4458184136234141447, 13912288647211446586, 7117356884920961264, 5467268310638154588, 15245220777673729712, 1674280713480622742}, + {11266978702654960956, 8634408824232294194, 14563437357018599132, 12842855704844405513, 1838111782288095759, 6169326332823577777}, + }, + { + {15630121427809305107, 1264840490697624404, 701327106091044566, 4687859862481244801, 4265389202393581678, 5961642557976590205}, + {6203324135029419236, 7455513180678088141, 6200001572379546985, 13701878844691679107, 177549874223488145, 685737752624899694}, + }, + }, + { + { + {17917652049280870568, 15058137289936578634, 13285085763522663208, 9845541049437644680, 11548676527161727192, 1593118089521595216}, + {10864003938379607147, 6682934333876753207, 8053350681795059753, 551995444074003321, 3834039616241196288, 13845962738460690774}, + }, + { + {17541102291453342324, 16435134367897898459, 3939250297619897100, 12831289266484462644, 2672302121940744249, 7983602741649631751}, + {9523831687169710855, 17856472103343426230, 10843947846323217757, 14788689810244029330, 16504581624723904320, 11424882804767220488}, + }, + { + {2900014861634585510, 11023132652887767105, 2781680546817585197, 2476750077618814416, 319701938011681702, 16893912712850804803}, + {17902073833702688977, 7222956556801351179, 17573562467147835250, 12198424156050387872, 7580627929306217147, 13998202371779366768}, + }, + { + {1943983450904780125, 7408346268399740105, 575213954926041679, 1462915584543848271, 2793007152100116392, 14469842559338475936}, + {3871734769136634846, 6700443490968311306, 6647535974540130541, 16864861301170855711, 10601116194391087412, 3578030254148841428}, + }, + { + {17076168913451726474, 12485001555750504145, 14937987845634560457, 16395528327395759722, 5249566901251131187, 14663685647372164951}, + {10098944853248455296, 13972698641100795994, 1737447218715933176, 2714092024085619006, 11856165348735870270, 6799485136302256186}, + }, + { + {5871871142109447713, 3293520181912634558, 7939325551904631466, 10798118573813278311, 13730791012248413123, 10321504720930821065}, + {17809680245543286190, 6650716579366069822, 10928266693125200322, 1399611361785322991, 5452474480776063976, 11884595003144475719}, + }, + { + {1276101160526991692, 1768819204291469464, 6678258399213622671, 10371513950625536782, 13597732847202290270, 16825083293383279230}, + {14168055895026590584, 2774764008800741021, 2309957760746875777, 6610907305570878050, 9706314202777059385, 16449252911102591674}, + }, + { + {14813060919741573474, 7098612088410986625, 966349190955014421, 5030549973018435870, 16698536462268084234, 604473235996320648}, + {10311165654586245785, 6873675636522594928, 14584273072844681489, 14316320659212458696, 1005079606220503069, 15954821355200367890}, + }, + { + {11183652692239073486, 8884116362394548598, 16492077002226140882, 16441016482531564528, 7470807081036429707, 9739141751658800808}, + {10370008242233770052, 680077688048593942, 7591564246708190689, 3645206790017203395, 2343053669027771998, 12572086616810161300}, + }, + { + {7519219331676774985, 3636740765491217067, 5116697285820822168, 13451090039382057704, 1896663396212964754, 5095592986735787153}, + {8207963783074146802, 6043379100202585906, 7652091558617243287, 7757654959377578673, 6081998859385971492, 2348786168616402284}, + }, + { + {7133122685181885176, 18155906669418812507, 8358116164721036434, 1130164626051647366, 2252530757558141869, 53649050676747504}, + {6768458751052378608, 10192709252783071229, 12663625005887863612, 9834336599446253001, 2038072719748979950, 13671585969003086743}, + }, + { + {4173851761541023368, 11613248765669161044, 12438237453144940177, 14553457703654741901, 12124876439154757010, 12300911432501569717}, + {9801691717672785463, 15951088982856589802, 13753872259817625075, 8949450803632947356, 12300776088138489008, 840080730448769108}, + }, + { + {5858476980082527952, 3415994521904095408, 16728629317865207261, 7095110407248715536, 9601602711454432831, 13502772203209999571}, + {8615007365984796321, 6504095591339955518, 5137600816385143072, 13062434456967887391, 4631991737746920809, 14058443721136417450}, + }, + { + {1656883461929285686, 17999602600826473063, 1799632323068877945, 7732508045647761265, 10873882997372651873, 3506525810685866503}, + {15989411289191292639, 16479471154067566511, 2001393974257662209, 843909327062680514, 3242569658964181728, 8478074943121574788}, + }, + { + {8836486505210648494, 10426577898344062793, 15007011756836364324, 313253543022452733, 11238239898276565663, 9629338715516113114}, + {993560883855492779, 15607551791478573230, 15193357750834803730, 13987812869592549277, 8887672059344069418, 5889521823488896936}, + }, + }, + { + { + {3145983761589624622, 17611056211316241576, 7512834765800752414, 18184573603751780835, 242382926403786594, 4397520716964975958}, + {4247119304022133294, 8685419354613982051, 9278503793637334290, 16772431670903233717, 16405977360280723789, 18340424413449720973}, + }, + { + {7278488351594086657, 13741799650370721053, 7077234897085578231, 18054749312950890784, 18263305810183755751, 17993843681498715672}, + {931117702416785030, 5163042803543400584, 7302612788872058407, 3506972565756252769, 13474801549451642960, 12996402258486911171}, + }, + { + {12722582186246792962, 8320877050791714570, 8335877567392598374, 13905858286751392828, 9736409409986876840, 11481277047355207753}, + {10562168749192737373, 14796357906073824644, 5143880557235132223, 1571641856571928949, 2271316785876440591, 3660167720441454348}, + }, + { + {18049602908503252792, 11214422395908641790, 11430824735860140075, 2019476279635404969, 6289777936286416617, 13753051460215424762}, + {11815459366199608802, 12257585796234971843, 8445139535123038318, 18054472803182783544, 7741484337923311202, 8173824012406015686}, + }, + { + {12256197267402510387, 13981324545434438090, 8854870249521577116, 1322567737371616078, 206839117288725323, 7997975760757403170}, + {10936017633135714664, 7366988068807007130, 8063896872358704385, 2137626719657327928, 3857424773492212377, 2719356304578840102}, + }, + { + {301934102174571642, 17806324394288773834, 16260123717658024207, 2047056936294915604, 7772436465589087916, 10948745767775306521}, + {9748882939263142737, 15303318171412953528, 951366600399039153, 11773285376383557606, 973693395285409021, 17741704800677625463}, + }, + { + {17924453454819492958, 11063986742596412626, 3141255180896459304, 6613007634173851965, 8230425337359415489, 9592328879812768331}, + {2074105989750243852, 8292968072994968539, 1989007282115330477, 9773026020534605403, 575143206156426338, 15794135741551054909}, + }, + { + {8693419915948057531, 1857557492170437980, 3828328131632721806, 16028252623001538746, 18359326643571678076, 6797739150028305116}, + {5767011240779324391, 1596344978223521735, 17443341853132737437, 10141092192444507922, 2880787045172334942, 2732830950861490359}, + }, + { + {3720564070329831762, 1116290302908559499, 8937540830788665972, 9131941124777117589, 17948366512937030527, 14685135061941669573}, + {18087232427084058704, 16817803762356804259, 1008977742792474413, 9381957960616185727, 11019890287218060046, 3802083666870379154}, + }, + { + {4862605723300674513, 9575672576917996640, 7558492797250409763, 105451604303370500, 16038157294412882498, 8761291945534568660}, + {3569807536094118073, 12152660506168626366, 15524077973685866450, 12984443099952829222, 14525324946986225232, 846797246005295625}, + }, + { + {16118471591100195500, 15075676621793721135, 16827468519303942764, 15179554880581807399, 17607860075908872130, 4006056291125828527}, + {13532541668080502449, 6554388530128575875, 11492311210085820804, 17407862345050568276, 3079559812598152049, 1961041605272859295}, + }, + { + {11643823884368608148, 13692078871457260347, 12760667246660146798, 14632954658001918449, 8493526038677331601, 11799308386431974644}, + {14675672791238509138, 1711971116872200846, 14683263505637045451, 9945937059533842597, 2533449755114148002, 182889653926968389}, + }, + { + {12117719403043995995, 2911986408429249777, 1810092692597231347, 18376367531841849458, 6595121441567685408, 12086792012295038031}, + {18169524376531427837, 7290300957931658086, 1193279940028308124, 133756179824057793, 3153937764794889756, 949814549860399421}, + }, + { + {484820520924399903, 4326328160527123330, 960211674708882727, 8917024768858500619, 6654526459358471452, 13449950526572072120}, + {9962763721058274024, 15699755065403197794, 16510141891401774591, 4621297269285137763, 9994000521116731271, 18052048126792112397}, + }, + { + {13533215919022444391, 9410324278985615744, 9852634656100194208, 1155971444710515203, 2911320463483837737, 231084108675667411}, + {5261097282088390531, 14003855699351521178, 17744595804999607148, 12877326770237543851, 2381016402869931196, 9246060959671779703}, + }, + }, + { + { + {1480509573599822036, 5087695994006556261, 17552775024242623509, 4908461990210297503, 7162610856648884601, 4093820247209466993}, + {2797950306474546244, 5001803039722689495, 6874955169311742070, 16748306778408052918, 4663084007893308007, 14696281298177607450}, + }, + { + {11992083281415385424, 15003924313644360188, 16060749513147241488, 15017414158265602339, 592682985276747063, 10327384700468822392}, + {12963019048030648384, 9853215583316433375, 5853002447766629843, 3573502149365840495, 7038518580360953609, 6673767391281747746}, + }, + { + {9298643174512728477, 13990767093997540279, 4393323960646334288, 4483648226430512282, 8076224304421767616, 6102759767515536930}, + {3652706241006741637, 3186805786206752554, 13272394214313265857, 8224305150459867349, 741190616027468712, 63238693198034713}, + }, + { + {2449597540862217259, 12351778639332774926, 262991594157788783, 2680188811965411501, 615952274938618918, 11101057916879795178}, + {15843704445146482504, 15768003479919439006, 16910795055422658817, 8210619241519359236, 13238407118245991998, 16212017713818083131}, + }, + { + {14806494457242751533, 3449804849483160156, 16962452567092059192, 9141394773020099337, 8870354660703521024, 3891566159386999852}, + {6146187894824960028, 11953410583785840196, 4404488807426703410, 6773066909874546524, 13716047320419439079, 4345501551123937401}, + }, + { + {11770160881016297977, 912473005790610286, 2745675273862880545, 15571792568792967285, 10677789776282348899, 295569599270057816}, + {6996654843946379963, 3996640705568842675, 12385530671849869858, 7412246026156424081, 8603296241680544804, 642377289008783440}, + }, + { + {11971881963673402517, 5439855382586921512, 16727103775229765963, 919596519199508651, 17937823088055377422, 17176167766106996798}, + {3663817202726401586, 5233288534404927566, 12262379145132434982, 12524678428958655570, 15158879251407581617, 18113402803324294467}, + }, + { + {5911831825147712996, 11728153653307965512, 9638203731413711221, 7948268717672672186, 7633819740372611413, 7035796435141898619}, + {6174193923587781027, 5408370123448680957, 4626366961562317252, 2309742647852990490, 16455916524028211003, 4504573468719265476}, + }, + { + {9058031745280178311, 690568667783443719, 5828783220548918226, 16050974080522553564, 13601922218850425804, 8808996512886455105}, + {5092307204676037523, 2947766400331304188, 7168571072799599807, 18029292030846640494, 15149715177238445188, 7857041415140644235}, + }, + { + {11743616397824348491, 11497771481919230308, 7158569983910845263, 13603604323915554008, 3337542887194115557, 14157633378937758586}, + {370281458279622519, 17762634864406198956, 11337855845757706931, 2929878283715844237, 13865396000587203957, 7059037007931834351}, + }, + { + {6973772658311339209, 791613060143613947, 207740421140774752, 15112398720810035573, 9603899779905889177, 5467205843920466750}, + {14380982275701503993, 12490114314596206995, 6782837922057127896, 8380489751197838412, 8510299632595261617, 4701772950345167165}, + }, + { + {17694086330481919631, 11636328947060876015, 1995706737774084856, 1925297315118813321, 3075862652270344957, 6399044835008845126}, + {3179065217616615921, 1550261549062697917, 6277396572721355536, 17738387466266963038, 8634038426968132537, 10728928687683354197}, + }, + { + {13587993255682028939, 3093746275081235678, 18152806066111947732, 14870862873010104695, 6947641398927171301, 6167792530140134466}, + {15651443704630473260, 6642812576181662272, 17064834710938919444, 7375543199807976966, 14845457653197598647, 11635197020740053176}, + }, + { + {4049527531120095178, 4601134559076758743, 9749942598880804868, 3990727773964515788, 7976713942185951445, 3046031092694896893}, + {15903097778987665452, 9044411259806049413, 1100762861888218692, 9340935249673778045, 13483058690067148645, 1545265903606923858}, + }, + { + {2035047113284776118, 14270860440293482779, 8925762303886288983, 14305197949489621718, 10202635115093639414, 10612436012257691297}, + {4441413877178186113, 5982857664255490920, 2491752418622962596, 9740828623410492538, 16822026648654939159, 13367270937584463190}, + }, + }, + { + { + {753467293193578188, 14319628483702379607, 9902332266754012588, 10961250711959848420, 14561592831116999990, 5289034957582773903}, + {16878255390347501753, 6614600699964682579, 15224133068199077460, 8845898800353928686, 13501508557386903079, 12790515894544276936}, + }, + { + {11011452278678065531, 11497839782101232733, 7285443384376562651, 3269734604421310040, 13431092833461803889, 3947360924216217744}, + {3251034893487035800, 12202372175578593549, 1928365734042402305, 13907315815562159932, 4942146767537177575, 9208365212678422011}, + }, + { + {12195725836685438469, 858993920875325442, 13838230858435487279, 3353504415316812969, 7929957941866392419, 14225218649971283983}, + {18163292212490608521, 5208475779203961411, 18277468513758427896, 5137327622216988361, 14819617095799940577, 16354307604702819275}, + }, + { + {16781294408245827650, 10125764934688471810, 17386045350799928761, 7875599535676923213, 11646654052414081972, 13301057675984901743}, + {12871815118558604397, 730917248827024292, 9514315608146867033, 513190696593073824, 15098974280120040377, 16196294686650511719}, + }, + { + {16909596444779110671, 10723968674526571591, 10996553782910854129, 16341969708695486761, 8635318916065362596, 6184764740785536711}, + {4510923062913139004, 2099379644008359301, 12406019366618763142, 11660159720716101851, 9002817464305502564, 15689479522617312827}, + }, + { + {9012015558077211452, 12527300838564203164, 5537302239069624297, 4367370042010266898, 15289441745247695580, 4593879093246181819}, + {7147970286091237416, 7287559954909509597, 4624960348890895434, 4403301422292173682, 7585442950983589875, 7325469891518486313}, + }, + { + {11624314814028789299, 4829320234443117094, 10699140943317911265, 14108042008131265164, 14865288068464758045, 10370004463666457157}, + {5805719613941872131, 5896198105631611038, 1844096097102433842, 1338882622497873479, 2882306796959123998, 15679394935542538300}, + }, + { + {11839803958974077427, 12283042318798607896, 14631718929239598705, 3167303738550719650, 8387688327413311466, 16263982689936295493}, + {4641171021165489505, 15063549369667052490, 4114993861532264470, 17514729201584918440, 11567986488283330737, 11751214862996904663}, + }, + { + {7533651708740465644, 3241255842488644864, 6743080020393835585, 9662587303565932915, 14065041846648071011, 12865213763613806318}, + {3077902115599738788, 3561402121178551657, 14611443992052777610, 8057658460840092305, 3326179385599463412, 10159717164443540788}, + }, + { + {700570683660150445, 16431145398710913934, 14168612051358907826, 13260960614387819370, 12988684119093007748, 1867024934246155048}, + {6311188673107170040, 3547825519151270185, 7128858853100723527, 4250551126633259556, 32233820825017096, 544635653753539727}, + }, + { + {8186226847711890094, 120861651635567506, 15214391831057401822, 9554237535615944181, 10075996254396042981, 14008290848782906398}, + {16525833259001997344, 10952578407797544068, 9567631957420742761, 4694819969357735839, 7767798136118541848, 18127622189992993176}, + }, + { + {7372375356062107488, 14109154833185040894, 4602775210887940742, 13468454637087016746, 5719482738764538175, 4919648522641500969}, + {14001774924525738221, 1330372407151555180, 3428768277669749657, 2816692670087351763, 9277450502900005529, 13715847643179616093}, + }, + { + {6794725365200966305, 9338913627946190988, 6477518264556505079, 5413655651412570539, 3966748832123982834, 17431753968516942256}, + {2369756878476639122, 3529105775992784064, 8846093841954577079, 16453616771411600591, 4485347503114816232, 6730810021701621332}, + }, + { + {1450226730593401111, 2904272681147253326, 11091003663793942841, 12036368148456428561, 11936601964184969530, 16312603396316459043}, + {4136271589497610048, 14294570804106047765, 15555359403853426727, 10264827714357589573, 9810665706497301464, 1311018743132753054}, + }, + { + {18271820402515351558, 8762537564155822450, 6068223146661937849, 5461403608011964107, 4988573958931158097, 10363771067980560783}, + {1663617762306194365, 15095271556849436192, 3047795323021630415, 15887201493595197850, 7868923572436975277, 14683359131088610248}, + }, + }, + { + { + {3584219355111975656, 16371250505380188607, 1783498323461654093, 994193781588257676, 9344084148092131914, 15250514640734155003}, + {5059260913356645611, 15865386190442670448, 17548757651739284710, 8085895309926420946, 4682964998668660167, 5020215203959826643}, + }, + { + {14253762630740826994, 3822111194856117434, 9311588183436895562, 14738024658650371287, 10441316960341346644, 14194770708525922705}, + {10501198799087781964, 6776195770649012397, 2069471581290353759, 16296715215024806431, 4534980656861543696, 6047881007434832794}, + }, + { + {2576612335437377594, 1899682712651141430, 11887300270792449021, 11804472993069758206, 10830999119719313280, 1741753179884488861}, + {16286699122731099873, 3643516247376722163, 3682273255591068565, 6392728837720629214, 11901348706175159921, 16143485051395996208}, + }, + { + {16501275346405437273, 14761564517561445391, 4638515002973003639, 17077550066034272812, 3698823236196638906, 124739081757270004}, + {15651979540537047037, 4985552038876265035, 13897675410836153797, 6701001687129639509, 16001679255576062512, 15935676633572097252}, + }, + { + {6152665130156855097, 9705469503204567708, 13951924545067113356, 2434138635056070528, 16591230788773292318, 4426260001178290949}, + {6390121195308333473, 8700572060668754242, 4812036275221797020, 13956720073248299438, 1902555843966298265, 5202141163826482301}, + }, + { + {2205395724283622824, 14105060019721358203, 15333631923716583964, 15403277868996709611, 16053651221022177038, 4784915253302323097}, + {971368063439244399, 827094312859966805, 1289222939864657176, 6606646522754926560, 17884747739152229998, 2668818780560918135}, + }, + { + {8525645166886970196, 3134143460247871741, 15116115167560752933, 3078800960701409856, 13059504075862532550, 9108153517754978547}, + {8250610785324912755, 9363672325956190127, 1495074847941437905, 10404043508726832050, 3904454763323616406, 12813791572599100929}, + }, + { + {16231508947971999600, 13363198726931461200, 5108997208952476742, 313182511761731319, 13219320773345255384, 17738895122530321495}, + {13811613026355251284, 8104379475524665186, 11192626091005940452, 12269372147510686296, 14390816163307043004, 12548485382177679293}, + }, + { + {8324780214689809449, 12924270761990727384, 15667753985117360698, 2943366707006427041, 10732039278085105434, 187369508428043393}, + {13244759855456178980, 13648213682810990274, 2660837912365849198, 11976770768362504658, 9693934687975961239, 13497908482787476774}, + }, + { + {14274386677405027725, 5124210746189478907, 13406608799629323494, 6405757996539000551, 14833312365952984384, 17785392529319073280}, + {7012330673098190805, 4918207845691492471, 14569574826272718621, 14168881522510616264, 14543438332068119070, 4326878510849999806}, + }, + { + {3341517100128815958, 2243420303688401610, 7153321666640309374, 10525543547452580816, 15776339624494341946, 7695076598671462598}, + {17732536140683547636, 3592810100391824473, 8413963613597435501, 6287395742336969309, 17465824153452860115, 6235174426722257030}, + }, + { + {5115445260875459050, 16200730294025276633, 6547940770886449207, 14513875339087588525, 2198135911102420364, 5169696006198573197}, + {11212158904251814892, 12437547968034770636, 11358243474088174481, 15452137528587726940, 4669136461455404974, 16320538143089060251}, + }, + { + {535242441654234443, 17036092933883802967, 11600759291125000719, 8050420965161709260, 17428526452419188659, 16458791281477337579}, + {6849931777343444339, 8512792140518036559, 7343733992893241199, 600235943839786928, 12840987592523793156, 9723169304965060621}, + }, + { + {16910417058622635394, 13917679375324377616, 17959562963138340920, 13359247597962361445, 636821169073744083, 11256621821635909669}, + {7096901051607551014, 2253054364079345329, 10215298864674526475, 8119225351234426800, 6541463265042612592, 12031138687814031665}, + }, + { + {5533765953345363299, 3666831701473191637, 14428123488067625678, 10208783684904868326, 4235254303243099550, 1152270923153823119}, + {7789988973198825144, 6281293996379084253, 11378132145663703106, 3044105183226657672, 15306186828154649523, 15118610766364934343}, + }, + }, + { + { + {16935319226801225402, 17479248115784925404, 11638874181787898404, 10204689344548103047, 5117503946912602321, 12798676317624404688}, + {9505799912502843544, 8138377038334669868, 12720954262725413506, 15335292261188744188, 15038060543229285980, 8787225712640151227}, + }, + { + {15287318513745980942, 15744943637312052287, 7712210611206194812, 2217808902952441036, 2880866790953980192, 7667233076242231085}, + {13340980843800511721, 1457443910895561494, 5659029865434015148, 9961325920271003974, 15801510722608035636, 12796727676398023612}, + }, + { + {15122689851130277466, 2795800145719527903, 13568032512724822791, 11462146579021072831, 4492622156197866593, 2389375563422758140}, + {12865430000561425758, 6876703980342191229, 6462758017056646394, 8138171318212409116, 4936990990444974691, 5220248005727829595}, + }, + { + {8222368087744136131, 12347516717036849679, 11297745347969103984, 8698144848560622671, 15235738417459308488, 11458307232141527973}, + {3156981165764697119, 3057909217286827485, 12707579681957851551, 14845444651771540740, 80043930456510931, 1427289826580350896}, + }, + { + {7271145335703081483, 8550379746366065405, 13222245170616935372, 1540183103607345547, 2206602728696862159, 2058073362893523092}, + {5459388607478785206, 13539611642074024292, 14402323904633266753, 11367015657725980988, 17537636140146252991, 14350125041234662967}, + }, + { + {15616429048255216098, 9646593367959435050, 10000076172445964456, 6887507833360734784, 9214691284865468772, 13407989755707318537}, + {23319057005728778, 5445755128474749921, 13782721823710291190, 4306629918002434911, 15715349716986824199, 6251943698106742954}, + }, + { + {198559125451872098, 8385427235747237692, 4233027135118542510, 12503554726860108589, 11105115177544924331, 10775185446004113820}, + {18212911447748408345, 13178565926755254085, 11114640510577499, 13843735599818615925, 18381258674287597192, 4756672869046810150}, + }, + { + {17538496477622964185, 1433183888673756786, 9984974491682898090, 4517808169349623741, 11986465564270089848, 8951472393424828879}, + {18196670723256299192, 535472157380722178, 693981884244746078, 15216522065428143733, 17726679260273203578, 9642969849409448024}, + }, + { + {5160114191168942061, 16463297770925271772, 10584792713261988719, 171850540846180989, 11579918515133959672, 10396694913224588816}, + {1922695067497914227, 3714397082557422085, 14915689713324864917, 3021901216294169148, 8451082446819513089, 2760044106111795702}, + }, + { + {2097173236089378814, 1814647054859784608, 10170299954366323333, 15955393059406664485, 4430370743633462938, 14617134597845327698}, + {6936197719765052068, 2035967928833128806, 10470936468275213989, 4552370931749195957, 7631626755294792165, 6995299789974072943}, + }, + { + {12192685447194213477, 16243788027426389138, 3307221830229366704, 4572373691827105584, 1147991015406820584, 7590972120066359889}, + {734169818930149130, 13046977851131733697, 18326449449602619156, 6629039284529698715, 7271937928914886253, 6619823517983792967}, + }, + { + {3491881131560177144, 7135322509001495847, 7718439954155088601, 939390052225540969, 10510098057025374009, 1036897112091468594}, + {16801210479572678348, 15364620159660153125, 9689801136876260321, 8466379544537007598, 4580285922100315708, 14754066353072462775}, + }, + { + {14236937969687093384, 11875131250768543855, 9199326778448473576, 17010296519672747261, 1432191715295448820, 7240396672478525409}, + {9282856696818793150, 8929298554101654038, 11691758527810395698, 13529214720842330904, 11364130274429289404, 16330417304431446315}, + }, + { + {15048936394544601723, 9976495942367902744, 5091911528724055948, 11917276080086885230, 18264141168509742890, 8988005100166523392}, + {13433041019916296924, 81537940451447058, 7905632599843138323, 7403634956612254316, 9471327080643618410, 14680725036927871901}, + }, + { + {2480592968060069230, 10676679272536823217, 15243200241275199686, 4240286848559333728, 12603956967014393016, 7473015364599570554}, + {2693765916823593525, 17572693658548274653, 13118888526718862906, 7144820876393735119, 17370196132870621301, 15051190136387242039}, + }, + }, + { + { + {15739670027855719825, 11036910205333787352, 4021544392863474986, 3565553387347367423, 3964961332364428282, 11603690097938709153}, + {11178322814781082150, 16935748921430175757, 10468742523886846223, 12912873445700591944, 5891559088297154919, 7322207037498008851}, + }, + { + {12503447801634120868, 970610322114574805, 1771807998727008733, 13441366741769313415, 4222236502986444720, 6760646999389453689}, + {1245452496533201083, 11777722003914828797, 8588751099069529352, 5461466601148872630, 8337331853046009840, 14200040474835462559}, + }, + { + {4381862158218819279, 3257946724717759531, 5715153718741221113, 4670267951691935548, 7126319499291794377, 7414184252515644416}, + {4409132192672707346, 5008109015870660081, 6646364227378002309, 2739818052318307018, 5254205492507002412, 2818763676677612931}, + }, + { + {17099575116390052440, 10771651599651215927, 16162078968288139277, 11747949268467955645, 18198632468383550806, 5718826843079118428}, + {12831818154622136923, 1139908981801729025, 18325634788038344414, 7897003381227512409, 4530946171065941992, 9839081555707087441}, + }, + { + {1822027882663919965, 2586692059104727545, 5262003340562216457, 15937894742226805212, 2377491755233029350, 2199279221179036230}, + {54627843603070570, 11018477725217416055, 13581326215347987485, 2599428256427468431, 13357876536889150180, 5983800947159377657}, + }, + { + {15875913836362316711, 10364504788586479828, 17159094454348286198, 2800760017120758514, 14648701318118632258, 10084646760313097110}, + {7413441597539522638, 5800112976104553529, 9603144930153129200, 18001343598967203147, 14907060105560621240, 12851016504514458788}, + }, + { + {3323767885881860783, 945816439403988314, 3122694203407892777, 18097120801908111115, 9507940132379519570, 13017216324377796046}, + {12112635426215062124, 1632305052635647076, 4503287615961131543, 5133655488959366792, 13376146870575309121, 17882590448286769229}, + }, + { + {16466564999101809423, 1103282883706681354, 13897339472612964740, 17515405571613479317, 231560140111353554, 11990302689318760970}, + {7461824051127758032, 2488635053784032130, 6738969321229436836, 12690895278364961387, 2762939532146449635, 2566430231249792091}, + }, + { + {7209658814720595696, 6910205524542965175, 16895432611633764341, 1110904616599822555, 768894652460082360, 5179276470661463666}, + {15046305975780485616, 12488826026249142249, 8883750914202815334, 7813886526674522093, 17626611286752587237, 14173740877250861014}, + }, + { + {9184078983275066527, 171829382296912269, 1767211109057348846, 3838810139883956938, 2892177352325525577, 587540104068323612}, + {16438018710111896232, 13071494062615911086, 9382254240153787479, 17837390153984245022, 9337352294335969384, 18306549772652293379}, + }, + { + {14206472070300656666, 15149876885322007535, 3058976565256742606, 7554155984973508676, 848860206737153803, 17384966138802851783}, + {6071585659381516479, 14599727484496636530, 14181631841630691241, 13597791031715947870, 787248750081521448, 8147947928967221166}, + }, + { + {7004817083098459682, 16726689782184453232, 3213280543725383668, 14046342544758604883, 16080740219683260927, 6076899979239474997}, + {14309002016238865418, 10488447184497156801, 10347316099979186191, 11941243369619909359, 11458632538231428835, 16102685462015086321}, + }, + { + {5487055055828671823, 4943171312842343470, 2928579838198416229, 11795723672039180426, 15618595864800120544, 11464055884874039484}, + {13454571326567663312, 12358687232096370990, 7938409714147002954, 8608381810067054636, 372913087078823561, 864501330934225576}, + }, + { + {635797081607123489, 1104369599182677226, 12483036179234706450, 17056128228042647500, 10009312675611681732, 12059669643105161762}, + {11477626132980303816, 5618063553013787498, 166943516871328425, 14701206874730673486, 9058640949987144681, 14563869860860339278}, + }, + { + {5395965497092106349, 3612539035634205771, 17681237127506582399, 3439193647142441652, 13780614753565633276, 235023041725887347}, + {3033179449351627440, 2044311760483059251, 2065568607574809846, 17974731450209330886, 14177489327434055447, 3961147821444060613}, + }, + }, + } + + @(private,rodata) + Gen_Multiply_Table_p384r1_lo := [48][15]Affine_Point_p384r1 { + { + { + {16703670340392818579, 1286760518886852636, 11248394403413918835, 4151901610420793306, 7970266049123896154, 17445779790134370107}, + {4329645970348976719, 16042142634338562513, 4537215703931505808, 6697447871083152280, 5793772036565999466, 5422118019001268159}, + }, + { + {14433915249620809430, 14971215887698628099, 14827104772163660010, 11634958463871186927, 828474226872480842, 5684743366783276110}, + {1331356080952535699, 5841511589364898644, 16990208903097464526, 13569226881169318218, 14248664498875166094, 17077506676755919754}, + }, + { + {5595676609776115867, 14618789080398559922, 2201134414120099102, 470895016097834742, 4102274241195483625, 2844568561456831518}, + {9494102924637200590, 7204580187252836546, 7742575358791209801, 5793245187166312694, 7454323588778133219, 7806095107071672157}, + }, + { + {18441227226710925557, 4630553211990364563, 3567153708366150805, 3858385788220258018, 2078907395053339838, 13453284031779612583}, + {16169419783227686582, 17856966316888004876, 9896590068038479498, 14513417153433374062, 5670844902446917335, 9309033883650068756}, + }, + { + {8174394611136832104, 13491946505368383532, 12716018224795668623, 15943834453938385647, 3311092385060995418, 10887239960276233526}, + {15318725704412058702, 13116557402644158788, 14528201448082359539, 9228826301082322952, 17581754887086264468, 4047041475027063331}, + }, + { + {18438599215442843313, 4015537097131987576, 1561321091994153296, 9662659929380603540, 5578281112816876342, 3480911564464745823}, + {858348351556501620, 17689640268312640141, 6959330516163154977, 6424518012595766799, 9187284181582831648, 6293794091600054382}, + }, + { + {13045229387657188208, 13690085938659083295, 9600974199166858024, 526884655886879619, 9290237641803195661, 7044646765166233376}, + {16602070129307025076, 15849288967186609035, 9092091796131291387, 10381155581334810487, 4911799803962481643, 914336345096302600}, + }, + { + {13490991706206957717, 8927032385078017633, 7775090801253487746, 17974570142754513596, 464854089971106110, 13646019468240342346}, + {13801477758808282478, 13267721605400745615, 8832595569781960770, 9823421671556846000, 11348861522513112089, 6704673626616438154}, + }, + { + {8798162395637210450, 2683284686000899615, 4296198105208970139, 7947505075124182900, 13030877569967081055, 7202635434125543310}, + {13802611418940267507, 17744356624256633959, 8515974827567262278, 16069780865789899366, 10235134369297564617, 15382730249140051729}, + }, + { + {10693928681786088231, 1868325427202955038, 2891972363284809610, 6677373020746038340, 14105047344690585066, 17441979056936361876}, + {2686563440401097160, 8335702271416969845, 3158278451667439105, 5195564280130047356, 13312870524821286691, 15037483265391344728}, + }, + { + {3961559481920028500, 898644078007715818, 14752617534552494351, 10654851227350209338, 6258212134755923496, 17327451745924835018}, + {5507497779295982340, 843987163524714857, 14881898850445300947, 16441634412065732426, 11312619178008978797, 3479463508901782856}, + }, + { + {17561502496821949095, 17726839616498802252, 13796139019518438084, 17300206272420033420, 10454206928587256948, 15885557324996538691}, + {16041928347765771195, 2239441821804334412, 6135738566013018613, 4043665170586576566, 10115109045930619727, 6594457533842211310}, + }, + { + {14756924596072248000, 4565075227644918341, 9793935188935462586, 9388712027596954480, 8006957541468583297, 8242831277630235578}, + {15798273981155867752, 6668583424992018829, 16434344268720351774, 3606110602406722084, 15561842144076827952, 2349656254358783019}, + }, + { + {3253443540806261442, 12555698908805436602, 6007490220897601617, 5307008481266272767, 13393830130502009899, 8899654776078387782}, + {4245028374464324749, 15297078807106399119, 16491046288077512347, 4048243407351607495, 13370129289324274804, 9876476920885673812}, + }, + { + {5390721684048918729, 16937659987125372309, 7680342595364868670, 12142253496635306986, 14233066834308424598, 671988498495879468}, + {2704194713182753691, 8912885238785332267, 15078054313953845804, 4795992794995133067, 11649755685481317418, 11930012365952944103}, + }, + }, + { + { + {8103759701478546490, 6028420157132162257, 3067900158853996905, 11583772150650265, 13094984669461418774, 6924985893407600465}, + {54958071128185219, 5021622351003191237, 11654157968548247126, 16247401174679100696, 16385802195540251172, 1031107974518303989}, + }, + { + {6428454722497658491, 10574271313549116822, 6743635881957160769, 16913635330376244749, 9681507818909145851, 4876529861171491293}, + {1814394652136903734, 4968086053144023329, 8920542953983370742, 210240699625540355, 8955586987380900266, 2164268895419701767}, + }, + { + {5608034336248364138, 5067877992472687888, 1933286244725713046, 13242405536880737213, 17263293185510756261, 1983344179233384988}, + {4237886563426459300, 9362799971325551733, 6786753397135169332, 5328115443562703638, 13654670013742588183, 3496580653988254115}, + }, + { + {16071914267185072355, 1315031918944783309, 16012293156990256785, 873056734499530638, 182560274640457158, 7405766622048342074}, + {16511661555914077662, 16795211140914816975, 1916902833101131312, 1130623122713241497, 3989275369171052712, 8501563225308840504}, + }, + { + {13149817102019880631, 10613889292284716178, 14010209428095701112, 1069882031932704860, 2775529095131230131, 9347998569909840066}, + {4409541671614199253, 17197365123077983458, 15652322139676023536, 7678148401641840335, 6034482384901310542, 9413989696720117446}, + }, + { + {11107110071047359159, 16288145590887699966, 2478598181863120847, 15571111403485190543, 10919164510183037186, 14098221725957317118}, + {3061511168275528853, 11371457453448805883, 8189313039485832750, 6940285322230600293, 14956213158219260245, 10799498050375169041}, + }, + { + {5031907698608444539, 18023991803445814565, 8556321431341137752, 8726888316311726846, 15478462387049033552, 10223636290028566398}, + {1905780687053743980, 6821165281886008665, 7646114077486165623, 3026148831014052877, 5536359622022292613, 18100746543211803131}, + }, + { + {11288497443759020267, 4363091778301392226, 8219453406085589946, 10369445991132585411, 5649747494026709400, 18114667371941410725}, + {5194421950530684100, 4023001639787678110, 13257830134828579022, 11041975949961923389, 15908375997592753284, 6836247357428864861}, + }, + { + {8547337202213930412, 6990159258245634878, 17883445208299166982, 4330231136088960102, 6472431629071074290, 8131668855043775727}, + {1615633974804093366, 17702421785830517013, 9040817873428455213, 7253431082049880663, 2580856565062595255, 957305604392189103}, + }, + { + {12550147352209098659, 16706353701874781568, 700985739649075400, 4991698549871850585, 14639605956467764796, 3990548737524847695}, + {2159031565346056390, 14297287012776021245, 4068789221096394891, 11837860404566828450, 1306127140860623184, 8582603028558393539}, + }, + { + {8572221175486824716, 7382610452565148879, 3798240777531515882, 7720424940498032163, 7955672733623916913, 10400992857478606514}, + {12536704118238452711, 1197472667002221920, 7958112946414946287, 7516882332626933011, 6786534214144691859, 10528818884598336300}, + }, + { + {4533011924393772581, 16478214876471299994, 2870575348476289509, 8319688882646555414, 7938557478377595810, 17061203640304685056}, + {6044136899841184844, 17176981934203875292, 14440091607628557291, 9556569541816694726, 12283955757179373500, 1728837458486823533}, + }, + { + {5856710237476933835, 18180055770541353170, 13666756016638015302, 9964122442248888293, 10568196656880286198, 10795529097021501365}, + {10291893071934944227, 1707329095509852784, 10774246437350578760, 8243808578767563702, 9842723530450682815, 10188532762574071159}, + }, + { + {12927366458992235142, 12160026958988547745, 16049652135447450561, 11154205822470049879, 2553582547365345640, 1479077593723189613}, + {6276822011775852642, 1807019718136820449, 5338003307650859330, 13548512004292529114, 274283195318475252, 4262254754558484551}, + }, + { + {2472529054687466938, 17137589090954053016, 13215293749622035568, 14627962367947576303, 10928297195163569905, 7813265877078949706}, + {13456308939723513800, 13108147281933977161, 5072676724153339749, 13630316084050530379, 10412807778936469738, 15061325193703102493}, + }, + }, + { + { + {14062262138187338878, 14826409911427014159, 3147169237468764230, 5040482455529903325, 15961102847332276086, 13076348733721508834}, + {15710048825425827881, 4711284320020833684, 5495111936001513123, 3975264090403135121, 18277552338555821101, 4982873089438865894}, + }, + { + {5881757900577935727, 3082203099603789340, 10587626589676775022, 9790887005834760478, 9753637089164583050, 17530540992010733452}, + {5906674355300253726, 14153899797650168477, 3203393482568874434, 7159946211415711208, 7770493192583170243, 6644035929201092924}, + }, + { + {7565543376250635378, 4894026024316289281, 1064629363627018549, 2229266393711567405, 13431836127556156122, 12345166870816475249}, + {5683094813130145113, 14460568816529669593, 16208596146346015783, 2251060002020925256, 6312100574995421868, 14142863082990548960}, + }, + { + {1701333505386754372, 18113825521491950532, 15971836848310645636, 10666804696553863930, 13339073901359549963, 9016082484725164613}, + {524595420371030344, 15193894147408008715, 11249116561046537456, 1416362693818654170, 8646200124849404878, 14789125286420214299}, + }, + { + {4448219040529062825, 16518108651741681163, 3867577730929059843, 12855944907169975887, 16383070643186103984, 3819970029429236068}, + {12270348593365308353, 3228624969622433424, 17746128033189004516, 15514466691444838563, 16922017859272304090, 10873928830553796343}, + }, + { + {6961979079470599534, 16442399973939705101, 5377070573932785756, 17366295333623521118, 1494760113702996405, 429566900985508037}, + {14596353036230607150, 18306968147291386069, 1956159373957339528, 13362661793127394768, 11047915751588023609, 15562772745602654490}, + }, + { + {12121783799905148744, 3210361347813891304, 15601117831098401384, 11374300947166969030, 14495343294857431451, 16887049363902653749}, + {2806824323484143617, 5891762208520246921, 10519788632722533851, 12406881532231465105, 12476596345610166775, 2929326634009750346}, + }, + { + {11619033824779825453, 6336011282085668010, 66441947656791796, 12634397924162340700, 16056962418493926156, 11181515142520561407}, + {228191213136585541, 10830330953744400264, 2487877016763970308, 943175580952184167, 46830635233029711, 6767691008612241467}, + }, + { + {10533215390069074161, 4240175145555423422, 927926585809726275, 5478507036975461437, 7372848586643865635, 9188187990850719132}, + {8456896957742765, 13507092707706845733, 4249106212594536568, 9711299350266342220, 13631286176123080117, 4243238077447546989}, + }, + { + {18238242856411579816, 7012871932937161633, 5224050476172253536, 12408721251948601788, 10429115795365006677, 3477371341824366834}, + {15692232122888670788, 7069484297055312625, 1511660220915668033, 13645274720004713009, 11371041276648404641, 3227460690876065865}, + }, + { + {9499451334789564187, 9807725712319466421, 17195273970347031491, 6512007407498606377, 825966736514514068, 7114432455006537628}, + {10929611578313393309, 3516227960140039809, 12431877805751955166, 4016269285378947058, 8308345904367589503, 479384259777781962}, + }, + { + {14823174488388431791, 10564122197066740052, 6359884666645689361, 3305490714663935161, 6956926106723106036, 1757044025346810681}, + {9218490684456903330, 17894538754746428292, 3686852509050441380, 11911436761000976094, 11281044983406290132, 4794870267149123419}, + }, + { + {6169315169310965043, 5050462902740654046, 4420119860349968507, 5900509286663583281, 6291948542666637974, 3502179279509591327}, + {13414573911064604645, 8561174987712176835, 15147203171479718083, 8916929729860280634, 465692852423696059, 3241796192189938737}, + }, + { + {4805037083483896463, 15749560291366181979, 3006668833558996338, 12746633991383561533, 2093748724448476449, 9143995667421057397}, + {862280791886494713, 158031676650943923, 9973152260325767561, 5540147634920097817, 18166813436129848595, 8728770860976175253}, + }, + { + {4780823618183778549, 14061468507515826456, 7924000550603741539, 16510436260807392542, 17111673152849580261, 1234594638075874309}, + {16418687934646105232, 3635175728906499987, 17864341637460241578, 49761007765188774, 5595562975249122128, 5917189370132161288}, + }, + }, + { + { + {2891150813386726224, 13575952774970790164, 16329951209698470872, 18208247565458407151, 795211506291706468, 3446245218498235605}, + {14887832502310695652, 7581320984927408991, 15304466638902159963, 12725650577835381689, 2109861799774686052, 14818469767057813718}, + }, + { + {8520307348850101682, 7147166939641194797, 7109795853315555561, 442556286123685640, 16703274587824683126, 11297170023439632439}, + {10777125051934595230, 8742602774458406457, 4568334189916483142, 9580614388736516768, 2144947800046381092, 11233838117038064428}, + }, + { + {14724535093102438262, 1097342397055114606, 9684252469138587855, 10770495648038995593, 4782115196813486405, 13108894563021474936}, + {6186407145212796523, 13044986185014550590, 14287812581901877630, 2228056593434999714, 2377539634072584064, 11484070981184438199}, + }, + { + {2372261882030647536, 17006732445240006818, 102465582613597482, 2306438222867094987, 7030387201499219717, 5620507683182655462}, + {7426675944447602092, 17517494666366669692, 1813907813072832665, 1664846168154029277, 8169354358603845783, 1009146886505697517}, + }, + { + {5359889361557595171, 18332881320680903217, 12992372967564983467, 3235336283246928496, 1918122366598530872, 9672910778717714037}, + {10998109349782570051, 13802180944593323119, 9243457800738211841, 14095366958484090980, 16875322389911718389, 11796767024296942452}, + }, + { + {4154159147515201722, 1273058311504047038, 14930295376923149691, 3541538910606543693, 14677828445112984159, 5652606725362693691}, + {12587781688969918075, 5762437720521018878, 8791631222951065564, 18036051705319852103, 6505939774259762064, 7898749725936014100}, + }, + { + {6073232427180312380, 2682532781858699359, 12899347092203445153, 3460025242522313749, 4187053964557337310, 14007867821755778993}, + {18308269875959593333, 17332777355331823582, 7827095597708416078, 17863450250717363140, 18143218844291088501, 10900355318411639865}, + }, + { + {15193822661262360443, 5913328606143520006, 4932960895618406335, 15675963329264670252, 786659723967404702, 15232212664900441010}, + {15668180363894430003, 10607216776267006109, 5301637052223037456, 6083790571087095778, 10053342033687645838, 11423643886760792179}, + }, + { + {13508339220661185864, 7911953729259324588, 18173014631200309538, 270516748480480779, 674907878659291397, 3314126255600287460}, + {11240909876624153823, 14246305828355338213, 16826984562886383731, 13091972868382905056, 16310998494569268055, 13182051848225269981}, + }, + { + {14790615268961369640, 10646825950331407644, 10001662541750174959, 4485562084633894157, 4694132461615297692, 12672440127863843193}, + {14852450733356045921, 12752269371731614662, 1290625671287973161, 2039070529850743039, 8986721707197477570, 7630558459824216971}, + }, + { + {3913192058752964309, 374802346376725418, 7620720531723602129, 7342095966104858310, 10538685091773236584, 16209362234668385483}, + {12484799568540253613, 12923921033391389174, 5685298310721897238, 8993584320789077055, 6359972113055748935, 3898751772482394271}, + }, + { + {1075126414131149860, 16702551730100501572, 16055620698555862254, 12278885216348953795, 3548642758697723931, 15071720148450568818}, + {12280024271646974211, 4447996993562488799, 14555333424853785642, 1510116618615803509, 3964481213568291913, 4155814256055970508}, + }, + { + {10647300335660095520, 18204591302040110305, 16964359131090101117, 11243541948462109820, 8583754773070458282, 5855117432513754745}, + {12473603800066854136, 10368688750745799978, 6023393792530123639, 12684166823166670856, 5507715439369687446, 1938961554823093885}, + }, + { + {13853144112993896041, 13666138769156330420, 3081504300584253886, 10998940258778477483, 2715364081362496022, 5105801355297802600}, + {10251345083070754091, 5637878810016321791, 2328631003481310687, 8881649909555714117, 16947069603315339244, 7416533920645212782}, + }, + { + {8283704072516909927, 12371773270912112344, 3092081269786213287, 16680017677990020370, 689642403329869517, 1983474266047873258}, + {3309976929403283249, 12532343087642554741, 13903549971839166752, 10358144884777122985, 5685607956768455269, 15212858975393784996}, + }, + }, + { + { + {1974541103187663850, 14419503307385213572, 1910357063271577544, 9405849388295731825, 8846714195441265126, 1825348137739350109}, + {8946791593625047664, 7707902765438605609, 16743886742959612839, 10498180759536919434, 17561637045610857774, 6591991118449510560}, + }, + { + {5396387893935102068, 9492930398296567082, 13435301371127725418, 15386190233236435468, 7248487611273180305, 10016334808351425905}, + {11988208056926197509, 10137338921708783421, 2716545254572709847, 14606914623397840325, 2555748042271077974, 4613981232528869724}, + }, + { + {1157528445712671795, 7268820473896949348, 1310099106886122503, 4262348507724938662, 8917553728509651151, 17005257183552454953}, + {10059173412034340597, 577994398230440258, 7002708654309095293, 10286301441424331105, 16384815498995719862, 112791320905797865}, + }, + { + {12313672925235387459, 625188478309360787, 3630661012849554290, 6134464256048521087, 17936871466010965416, 17564699109077082040}, + {6761309657688544628, 17284240846518446876, 3570047841144108922, 15668537842491950089, 17083391336599335387, 9282566732138308423}, + }, + { + {14888961160828833873, 1864596543262469754, 17784154409948684103, 3052077954154793867, 7607056789868369456, 3894203281376040408}, + {17710090260347574598, 2210004113826562961, 5671161332907863757, 6625158587348516953, 577771095520713590, 16394908675016020276}, + }, + { + {6603729010820482722, 310501835036252193, 13954871388003056741, 14251448811909808675, 5233636024407453469, 12245878228209898903}, + {11486231149562966694, 2835585577048418114, 6551484302395633982, 1147669539433231355, 16475838258018071696, 12247646139693000214}, + }, + { + {8095718986263574912, 10516714254110691975, 10870802407417590732, 12874599804285329736, 16364633263585191132, 8865300776110950252}, + {3563236263281283648, 6644962740435178657, 13092866580083075501, 16578846863092146456, 10069414745327895789, 9434194139304387489}, + }, + { + {3556391957256886772, 2045016845106055936, 16226354733380887667, 17466044866167164875, 5174514841894426254, 1878394346602870901}, + {6716526457444196714, 7250663133803025807, 6718545916437832659, 13969599547915135008, 9325220973174112271, 1581163301870356679}, + }, + { + {17874459379059293830, 17502662865497015769, 1413180880150211940, 15088446747480281041, 8470145037392166085, 15096281883892228601}, + {16563437908222832225, 440803266862528997, 17031080291135092609, 11406614303171495232, 3723108198050621166, 4347405779711045020}, + }, + { + {14923234998584905456, 10067479898750534001, 16939842266743060751, 17700070519960195683, 5683478503944407120, 11025361952743521652}, + {4209605377271021882, 1469922120365400988, 11514012988142017467, 7856087734177419136, 4097954809069446909, 12489390616599495992}, + }, + { + {17122478311949624172, 2606406176820258447, 10067594371237100910, 15451154690481864146, 12038146827921735864, 15614369208187755152}, + {6824524079696297568, 2015807129229573570, 8194028607199100376, 6009223747668470820, 7772398281249621704, 762894964403298890}, + }, + { + {7815360071000367774, 17901565192138878313, 10434394026011307506, 17374730254587070753, 520674668586498531, 9514841979847171014}, + {8950553127025783937, 14895127801975478381, 12425287594242504013, 4645132844100203397, 5976766478892526023, 7370660544571859011}, + }, + { + {17533325387355455402, 12119607747199535982, 9073368446213478432, 2599055833895753629, 2355979442709556838, 16659690147892928501}, + {6238157733277724851, 1384135036242951943, 2192811311355019409, 10465103238457430542, 13159060180143520417, 10257462144135243277}, + }, + { + {15864053898474748885, 3221238804944627, 6003608638035281159, 13653735634664806453, 8230891808319557046, 6613649981851363837}, + {5893628415615729604, 9710922278586234190, 10395125337377360528, 3931451882481143085, 15979557321922502583, 16029662329812025753}, + }, + { + {2992392235075872590, 6059858128867517556, 15617366226623071384, 4111806970940100258, 2815759757037139466, 11575444833660170455}, + {12346698926973835666, 7263128764813325306, 15235588485234058492, 7572978345825547287, 4333826640601921394, 1322529269991380909}, + }, + }, + { + { + {9784032244755280441, 10040637167065316270, 13599824657669619733, 10375431024260591386, 11026488569773701752, 148008158803836909}, + {14567290934774912661, 16110515707287744352, 7491732171320356409, 940936830894493669, 14287255966622464286, 5426456074085300916}, + }, + { + {14969046289595378522, 2961608585839402462, 8313047147741327249, 15157159053809069603, 7193489948575262630, 14433197008239894898}, + {14199648694191979725, 3269958096730932465, 7497592897262475128, 2728526358559655944, 4744743661876038842, 2743084008632367240}, + }, + { + {12708234784965893093, 3307842163098541971, 17303873939057534192, 13260319540233926124, 9019484163029605371, 9900024564598332822}, + {9160913700210863226, 14428342536017851587, 603459719728403776, 18236218541634735507, 4474730692000472054, 13244873297017787236}, + }, + { + {1470084386249125812, 13287518884856486050, 2962960042040907088, 2151437856455287500, 2905195302281113959, 16356195231949614105}, + {10979007359054784823, 17866133863009475011, 4170501321215960549, 4594340427813823261, 16023065223081480373, 12495390124432989208}, + }, + { + {3972369974785239897, 2263460443502958971, 271463035813818108, 4070768510424378794, 18183758750525376366, 9693239897287717465}, + {1475136609401905372, 5379591160737925092, 8153537820525801184, 1865515692994364877, 11166184186139353884, 7175559837327764278}, + }, + { + {15851820172704931949, 12655143336395232851, 14730294842561239904, 12459362250042251879, 8382688064372334901, 5889068791548184842}, + {8985568054046695170, 3001288673081076633, 749616385212969715, 2646834045811835619, 4782194008578140982, 10854034154938442923}, + }, + { + {3566983516939841616, 16390187007609797937, 8741971305711964717, 10988398606335852160, 7867588372988852672, 14538400485602331946}, + {8104114227557982732, 14039413126798418158, 5102330106089863488, 5619388808486733299, 2378045731360365970, 7775897872465058879}, + }, + { + {8285639907960685452, 6907081304694029245, 3932091882248482870, 7739498675000172490, 10103249503689721665, 15185105419572705287}, + {6218795015578490321, 6781880938546434941, 5905078566070212755, 299457794212684954, 2165089807353723840, 8480540247598037310}, + }, + { + {14784673784599919989, 2082260535205922993, 8168045341288037020, 11903543474273736259, 11981001928254322331, 9522037239934847936}, + {14472653912826320219, 11309503817936052299, 13738425228648904701, 8042010790362339419, 14117271511958285496, 790309299276090992}, + }, + { + {1732476059839006505, 17018699420444452651, 12153180531366356108, 11316536740921479323, 10078354046704171747, 10800231856927927233}, + {9504117955400644407, 12280517700591263912, 1062093141564177828, 7578015021890571031, 11569246388902651024, 17406496106428159878}, + }, + { + {2347276268330916160, 3811437762946151257, 13719307347921295013, 3930073025002065810, 6454531622431144143, 7482466867004373254}, + {4716770925419565679, 5110702795209658366, 15071426966139561730, 12738769369895983368, 9464508449545437568, 14677026754609888388}, + }, + { + {15527739528861052501, 8795354980099030148, 17061268663297745190, 13090961285447854468, 15698285934641221614, 12271672067594065876}, + {12952447277463416183, 17845959850709540103, 15366734867247877735, 13405705559578435369, 13317381544359441361, 9727437258673830028}, + }, + { + {11430653818134040708, 13972160408058655396, 7084064239516383189, 5779466131231952465, 13956916356587340454, 15097328365167500151}, + {11851587197086244848, 5814948700376813477, 12470797735177958521, 289525451793692048, 15282352302269881904, 15273112883324865707}, + }, + { + {2162599553469592657, 4663793700503951742, 16049802300031157625, 14926606091765253431, 8356290077455847249, 4143079345240852597}, + {13247139040866943853, 14022573155642926251, 207855347034742811, 4720924427150657828, 15071740430405402718, 6051774750243840661}, + }, + { + {7719115525766766580, 15211733959779219234, 9890856375298480641, 2106523170188804656, 11116661084796200293, 7362312025325548799}, + {3717785929351377088, 13315020865788643418, 18113403510273317893, 14815931788618774540, 14634966516940592950, 2034948857717155805}, + }, + }, + { + { + {14244174369224556546, 5342392209233508928, 7438713248457968580, 10614297495547921248, 9202135001584851596, 3342234996026879127}, + {13691335804923598208, 15140348432227922719, 8428540434060562744, 12043754816218808261, 10858831840083451813, 4598155351159579828}, + }, + { + {4498695262421386143, 9265193209482259657, 17498675555682479110, 24163428822819825, 16737629178311549749, 11187404778246278772}, + {10767729479345778777, 17391117902918412174, 6880253873200674120, 15284410651868444657, 12792198194450228219, 2395904758303124696}, + }, + { + {8158446918957702678, 7546107368870022629, 11717312886106537153, 6923216345857736395, 11003539876942772744, 1153070042831623474}, + {633963820936975157, 11353131760056430258, 7976658868901878513, 8020939041587681581, 8591633705762983526, 1696346219311964099}, + }, + { + {16508671692567979884, 7478096400789445774, 14273613261641667275, 16142155569890490590, 17190642547002219793, 1935098112081588531}, + {4595462997311059955, 15750249483900207872, 5924388750545229489, 5293390377249847029, 4749762219313386172, 13693994083245523550}, + }, + { + {16380431445715687892, 106230990604580903, 18014344013591313889, 1033379254497495760, 12516742637402838545, 13779274142940005848}, + {9785610002952463038, 9797590851340545635, 2035999898130400225, 7132629806216558751, 9169445448696845522, 12182932187779129821}, + }, + { + {501907073775093791, 17308901417650437752, 14252322144012009433, 14212853038379844496, 9157666821207522685, 14098967321770430754}, + {693358881197934327, 14629222976781047974, 2813134959990207271, 11343356266664072637, 6987651623587825922, 10281965377549280543}, + }, + { + {2764452604422336440, 300997096301046019, 14094398322842717733, 8058134187047147246, 15215625261188908838, 4382907902287523761}, + {8492851920809087726, 5937579395094221111, 7477845800356457342, 10689515189034436722, 12617667903878138436, 3774778193535313798}, + }, + { + {9960007214821980729, 4069548394854294195, 8627747251011093233, 8210112892681901809, 7088798910112129600, 2053428079297196270}, + {3702967442659062216, 2310906403335544760, 7567753294056516949, 1948580970688562476, 13536454877958536205, 6639944374963599628}, + }, + { + {15295696372734148976, 3579596265901281843, 9574081162895456810, 4923374886486176154, 3219363399904390571, 5015637093415491888}, + {4593899936599160002, 3908598443341109958, 957285171332479030, 15321912334716832124, 7810866701395908986, 1221281858922781688}, + }, + { + {13874958592881679723, 6638033067173937719, 12963324999336699337, 14597466910971525853, 5238085686240872501, 18280593805011112769}, + {1903676504579977735, 6574951020929533498, 13950840705690778416, 1696682485827935789, 8423274085423453740, 14078931046981905240}, + }, + { + {3517518319454019911, 10814049823525725669, 18276808946264820784, 13619936204927961226, 229197000889315492, 16087612506648744856}, + {13359110821899203348, 18273672153546569067, 15448342392556280774, 12827254463788206440, 16731815387033480424, 14776988595871001826}, + }, + { + {15270415391437565596, 2028683490070884787, 11702183509282950225, 8688196922408363831, 9849893844753628582, 9968552033497457092}, + {8940282168698946885, 11937029660413868974, 11118271464781804264, 11568483938414775956, 5728644286601384752, 3703969168279877107}, + }, + { + {11652044326376748259, 17908439335707899388, 17421220331644622730, 9490161168331495839, 12156528627204515202, 7912628748081518108}, + {12398934214500264906, 15275646021381992403, 4419692862258023354, 16421180417058441595, 2454832921933908163, 17393752904451977236}, + }, + { + {17844918621715720543, 3502040829859328267, 12871353770728226564, 3472339707328644724, 12451097532318425848, 71861369639778964}, + {17295347875481859563, 3690461964037187899, 18360181465850037021, 3712583869172705797, 12197237321535716543, 4729929162220746067}, + }, + { + {8731053926361454382, 7287398925224999230, 18086826009699036346, 8335574098738039638, 7591410546978300407, 8794647666674147762}, + {3125018303771223725, 4278864892990223517, 16568066644140435565, 4494257938435512782, 12764272586590492568, 15409898743615904621}, + }, + }, + { + { + {13983598851114853863, 529849755045537891, 1350161153312991881, 5942999622371373086, 13586823003297946505, 12570856107373756476}, + {11045595872248151877, 13409716803560067967, 7556599145425958335, 12242191131006857685, 13579932482365250112, 18381666009358571885}, + }, + { + {17762884470933745605, 13091628412956520, 11848002318246680260, 11007732397942638623, 6536960302098188074, 815221834698284970}, + {9236334332791328041, 1308454297106192382, 13073132817539534118, 10187597698470053764, 1224340772341594193, 17492375944897582958}, + }, + { + {8342214479854782437, 12753724076994494301, 15158115729208345118, 10675749973467471208, 13779951729398402660, 9124105394386876597}, + {16701027235021659665, 17012019762848269150, 9335333600380004220, 4905542903515934494, 4679911467761810541, 18087992689526637879}, + }, + { + {15671008364960232950, 7860658171410702100, 14227259085597804568, 5601891579416133188, 13347153814200955463, 16322888887317605171}, + {6781550399618311953, 3002152930532217896, 16651539803074113759, 12688880914945537327, 8458859171342351565, 6912445599896725323}, + }, + { + {5223854540563296107, 6918357952454360661, 9207094772512963084, 14426924911853158195, 5755518699259636294, 9387283789461380977}, + {3503930759476121643, 9159964934165741367, 15206356441822401499, 1480953354201474586, 16143427034936870480, 14366839330630373342}, + }, + { + {15025229139882835362, 6569314276317895034, 2647355676900663405, 15940408348923221874, 9319872831842193999, 2441065085739546990}, + {10915383241419292088, 9125679006919517116, 16537773929817775472, 16520361616767483661, 177268947296049279, 5845623806684850619}, + }, + { + {1715144640521397840, 9713182207991148222, 9099904704212771890, 18362082653791274277, 5942292809119944225, 9769586133554284694}, + {11519768289953656760, 11743868714787315094, 6721165095180661980, 10279267157246395337, 15375558993376490987, 14492867532550448130}, + }, + { + {12103512047683613691, 4278073385410902126, 14292291658628531517, 9854045601464761923, 16032579696315420438, 7195268416745968767}, + {612006809983855445, 11060333399844039545, 10009253468204157639, 12689475911984215777, 4543371362129747434, 16168227213690204032}, + }, + { + {11770921065158854893, 107067300718291927, 6216709271265794600, 6933524040251286410, 1452606278006972167, 6352326468906969436}, + {14670895904694727522, 3137275022800628766, 14281654070417022408, 17577495604202186311, 16841827195439601162, 422964381244324663}, + }, + { + {2173637395644840283, 9666438537552030781, 2621516439523045149, 16194421987699911464, 1151524228457474221, 2401703450418989544}, + {17462142435831844356, 15163851247483784831, 1841486106108653340, 7822858850019771468, 4249485329140599845, 1821072017377180323}, + }, + { + {15298268041084334151, 1531237843026640514, 15841013071716322151, 9410793877088000637, 5108136920376770765, 14198994672804406233}, + {12867076639631558569, 17777512969934768577, 4278122367966949505, 1107145346780540130, 15722269527707226912, 966176458294482319}, + }, + { + {3539257888383275199, 17944547213827679412, 9759251359067155556, 7261158630405432972, 15290149052332111161, 4170309286957220483}, + {7708910151755850904, 3634500268466769566, 5837736360460882054, 18200381407287071659, 3169144765352868301, 203115232477137729}, + }, + { + {6840468866856259700, 7758204996514135607, 17976257971060442776, 14304394653760424496, 8378305391704268529, 15501414806030165669}, + {11373547512176927055, 7169306605754795400, 4819206690827867025, 938930549801608666, 15550126629632404977, 16998450850862106862}, + }, + { + {15700328879061755831, 3194744149035659602, 12913379952862607162, 10843238782556582006, 10727228193111430396, 1268507586473183326}, + {13242157096784103517, 9764148610613513484, 13432136698405924597, 17207758635006490092, 5669195169308257419, 9700784012686509553}, + }, + { + {13323401950222069126, 7143389192525342566, 2753977793903748710, 14752970139128156351, 11560905576527598704, 7772265590772671469}, + {15339277736310777779, 11892168454138922804, 17815983037800870820, 15149987747549949858, 11149095484837869946, 3146330589620022603}, + }, + }, + { + { + {2176496575786881341, 11137175552988470328, 18165371128924571066, 14493665018797210129, 9027832134416315155, 17831122727374654343}, + {13941117776210453432, 3262628315315934865, 6955607093154218866, 9315601893566251415, 5081138766383608342, 9449507684235557713}, + }, + { + {3015183280845351853, 8567302742230480780, 12270847108839625213, 11246873507912728870, 1058839101090450289, 15063533146116054837}, + {15816951661145602122, 17835613250576961263, 377336345548517249, 16952055578532303378, 10643126612569896087, 15589909904400117121}, + }, + { + {5917530861159333215, 16376811621868701260, 12468667157041084287, 6060910297573454847, 5999643954660792761, 10374199955429433218}, + {15354447643953389125, 17866869079904367209, 8929885267107625215, 9764565262519350782, 12345751593966204455, 9590062130519338399}, + }, + { + {5932736646654537524, 11111625974290371458, 15669816313412657243, 18348488897895796471, 17719589740702908170, 13074575404328778262}, + {13337220567014765893, 3183217332202609863, 13737875422290924678, 5053183954635209364, 7253181521673343044, 16432970095551512913}, + }, + { + {14090926673589572542, 17530443530454432055, 12384368526139233597, 13369819312395505251, 7198182961160804423, 794076975275841051}, + {2760884514203992257, 14661425019208431637, 13933494052308237687, 13461782301434087101, 15552200892959134758, 17074320298955503096}, + }, + { + {6895102306183172231, 17913949034057542002, 8793858421550093100, 16831072178043970751, 13776552101358985318, 1188816091752039796}, + {17433095774009548776, 1361051895268056816, 1584454468837935219, 9000587494960507617, 9150046460469003449, 6677236369751497162}, + }, + { + {10073416357027898043, 11049353932450326412, 5686074628312392124, 8667039569779248174, 7027692055059522005, 7268282275319392236}, + {8629306706584271868, 4544414308773698323, 15825173458798511659, 3783245463927499985, 3277602994961352368, 16594668318001131253}, + }, + { + {17194222042243013514, 9755907999220542865, 15203045510993220352, 16670494240308716815, 5468356552637101934, 2209927657220556130}, + {4080551261822064698, 9410102261896788927, 1729749535853106305, 12865714430736655885, 16788188297672046823, 4739114570896754270}, + }, + { + {14031233216260426655, 13894451532350910002, 14721305842339563831, 2571399673735228739, 17136925918547685412, 12486318545760378351}, + {14945904247785918924, 4332191017784273191, 3577416897748122497, 10770672964471969794, 13859172261775533936, 1323080729872112496}, + }, + { + {4806132367170729030, 3012780210920457375, 3465902493839868696, 8367717133643917430, 7541627860300058604, 15166837387405701033}, + {8755188577678123832, 15440550960246952705, 6821177912455354424, 13580899156034649200, 13889507678691571539, 8622094254907884271}, + }, + { + {8944073100303306076, 6542151642656830118, 4104527697818383341, 956456087501600204, 1355338812157776915, 1576264571133590433}, + {14576384464935893161, 12976993851388633360, 8882463173850021133, 6146594088987122341, 4213885861865358420, 5730501125228024803}, + }, + { + {7734895557992270496, 13773292779533050725, 11791360189416713892, 3844762521853578365, 1284645752772663495, 9812572158308316394}, + {7423486593749131086, 9063179868650496218, 15664453574296549152, 12189904173100887627, 15565268483602424319, 3276085766266736963}, + }, + { + {13663977661665765595, 12869596706690969469, 11622894659269832036, 8626701230474747130, 10051999084490524702, 1254507355148706860}, + {3738417688632628979, 10128963025153309524, 10379579774762834621, 16085982828578912188, 999630916899084620, 5890496890318826833}, + }, + { + {5464691878810358086, 16779490499259550831, 16167618561212471093, 1500388924177938877, 12758820778786031069, 8726936634855616738}, + {17023037108698278190, 3926165730727012559, 2857709494954513428, 3375996756516865105, 7319015008396427730, 5981183379963579669}, + }, + { + {9453101235061934254, 8471689648697407064, 6756160836097095590, 4538217394377244150, 3501535205004454648, 11902347949869551885}, + {698830528006196076, 8321354741552964610, 2475663594321703580, 13966220326496163916, 1495087475066029926, 9248489243263297804}, + }, + }, + { + { + {340762250586370878, 15885853259854490950, 14170016703992127752, 13413185133968590757, 9132295233250564044, 9955913638095083109}, + {11442204168742219584, 18030844452885851851, 4172771706246866818, 8415318956258968622, 10025498907972372942, 9168803391366195663}, + }, + { + {8511258912015600714, 16401285336019435955, 11567231709606604746, 10909146042530314890, 5175867930620067690, 1758264796269950390}, + {1311893356838490889, 2075003657340819455, 4150679767398135680, 9944985572047220304, 11726442185374948983, 9515564709417907692}, + }, + { + {947814274602777664, 16977093960389365711, 17182772961477092323, 7950550504137754878, 12164286910738269376, 2396865457216588451}, + {7712672988612544289, 2256404627520187318, 8042169559407463337, 4322215616044918854, 7896874306873269018, 8861341680456564805}, + }, + { + {1573021064477563490, 12385142738510496803, 5846352022563838737, 7179392922412551607, 16770926861117259109, 4748524474277694353}, + {627992288971210988, 5079973027627716026, 12148275790420566931, 2974507608681532690, 4977283032988448426, 12122543170457868729}, + }, + { + {14982315046876125397, 10694656698025592471, 69978513957895432, 10720522802782817933, 674072974690397016, 18202488981264823240}, + {2763268093414423208, 16627509676996448791, 7905391784431874217, 15969282761758331738, 4087266599186541195, 6705534661083402155}, + }, + { + {4260928749573083864, 14414653187745491590, 17669562882664725861, 5539725367798503840, 9892464532031311709, 8646224288734922726}, + {14636838328767388157, 272416839100440696, 9027818199363669781, 13152959597440376914, 9885545384154705441, 4531971612013043371}, + }, + { + {3054144515900924393, 12231678983485064511, 5344887254723067065, 16260784250181309348, 13554495123766829763, 16541428532159722510}, + {16971418268239157688, 6561565182987963636, 11849488276654035036, 5626075694176069835, 5950685614385695889, 659455020499241038}, + }, + { + {4016750444584361935, 10934103594664060658, 1610640179181480423, 2687152927501620139, 4356423113034416292, 1508042570353658648}, + {12444493154493623021, 7858990549536828280, 2620376282128316119, 3094221996681006634, 2197436117225946497, 13627448762660605994}, + }, + { + {11319267592865004792, 5771783128259971891, 18183444021717726622, 14584551296093059489, 8197314068068346944, 1496665335270628278}, + {7533930075545786161, 17913476997028566696, 10110826559280511221, 12595790705256942207, 8383527098300125989, 10468103262027643123}, + }, + { + {1297397412658178639, 17891290189040928260, 11494441724074567854, 4008680981284786655, 3752678751199473490, 2327749996539228182}, + {14427514318988472029, 3553111765024203036, 9339018535932944476, 5033337384514825308, 4461712737595757481, 1042763231946705190}, + }, + { + {5282595958571557801, 213593101601136936, 5851288338443284810, 7230384975686448098, 5076726665241242579, 15657565414881533309}, + {2806053347798036217, 13325810292191155888, 11207865985035518040, 16753610899485159157, 11780444340160414775, 117213508700926531}, + }, + { + {12301002695840234190, 5825957247323734322, 7540088495914446527, 16042651929295067210, 10094620945045619814, 10110065362760208923}, + {13445281647852023130, 14273322378142608479, 3078794690211711993, 3432436226120118989, 5328806020363596991, 6994513974763316732}, + }, + { + {12003038273625258094, 10383425068383640359, 15520194992621832802, 377777956418164695, 14943016921304093418, 11013649826256127439}, + {7230967483902155369, 10825313619847326325, 7037825115392195402, 8972357023328446193, 1253857384837096935, 6266649133505623519}, + }, + { + {10589482155172539950, 12297389734324327538, 4069221173445026474, 16016744041800779341, 18417752858659154550, 5634264208757126073}, + {15473968400152854338, 2809792092226097652, 7273042078361794560, 2614557813052600661, 11360021509152649943, 16733025469392257248}, + }, + { + {14029153203244842151, 8283401980696181560, 11095661564207243200, 17088874757598325946, 17546567502506221871, 5640913915552816107}, + {7075972272517500150, 2257279655826038849, 5696746906369339622, 2316175253051029175, 17712158778401896374, 364112814656520215}, + }, + }, + { + { + {14679924527974280886, 15947635289512277104, 15351404070450195459, 4727979236151915703, 16350474002987521743, 3821044743014808256}, + {9479595861519884974, 8516666617350278746, 11503226012034686940, 3623032435206572941, 13809630545510991358, 15014347175818555977}, + }, + { + {11057592299455225148, 11418500207601195379, 10015659838321279434, 3277591360102749557, 13870089373464432053, 11899764543560815680}, + {10598708899627490235, 5204860756179583225, 5704026074815499757, 3961740021052616841, 8083325146143482469, 9703502648801234299}, + }, + { + {5296723995152596286, 12702366508473375573, 3560342141598167052, 1229852828708405148, 987112422309132678, 9050289325451932333}, + {8377778558476358877, 18299004077752380767, 8205821641610714688, 415872980483417712, 9637058392436615799, 16488239169772178994}, + }, + { + {14131815066626142041, 11540556304194578314, 17720164231008490194, 8647469527673297080, 13717080072986283066, 16364407850305375121}, + {9812923705693309894, 15252855277120316678, 4251079378183712824, 16287850228852183968, 16981432229628540775, 7288137070535318945}, + }, + { + {8134759848840978213, 133995483652992421, 12594363638483218087, 9394943745697767530, 3292684192987421047, 5641109531274744017}, + {18340625042234832363, 11659678257409646710, 7834895451987153240, 15013848757483954741, 6923004623931848431, 10731117231772923396}, + }, + { + {710182862970832652, 7186938586352280975, 843940566536207033, 18222882275783810673, 9033108566167385693, 5062146455700166349}, + {8983560327851192528, 9593314042056721839, 13080593353438570596, 8499297145526220981, 12018300556898041742, 5590813964218970674}, + }, + { + {560148900890697500, 3872724270688497231, 12155226431747164567, 12069399862495208716, 7800323474020451504, 17842129873781067995}, + {10386941694229256988, 12627593178570682056, 13595572751629997365, 8796981607722448553, 16749808188347360672, 7845278385143284636}, + }, + { + {5771329137650242669, 14398580224071912888, 2684433028961805130, 5472793673559551896, 4139791942141311772, 10242427010920223149}, + {3435557043383543647, 16439074182964580066, 1897097733009851383, 7790954287877138337, 4094797857151328545, 17636387648829877391}, + }, + { + {11084338203592089978, 7046536437278056828, 15270162581532936685, 14872594521711089230, 1065044340676136516, 12215363914120183972}, + {8807558094930205455, 6192530442586873261, 7580836915562456588, 14608662449758709959, 15699254439480728117, 7514868894683313347}, + }, + { + {6725908589474685098, 17990909432805680896, 10064707122671181170, 16351089498679067398, 6987057004328973058, 1476297822394021518}, + {16905817105678067782, 15956790087223100464, 11919441400720484520, 6472307250416206582, 8105558973519980497, 6060069727850515408}, + }, + { + {4394995949664289457, 6428291279342645254, 14868971543072031986, 7469984888154793685, 4535882282594416153, 14087727563932343498}, + {13764853652994987377, 3726460811537607063, 9231152303364152091, 7795121740553029976, 3567427738439652965, 828395371245164136}, + }, + { + {3588112622259521330, 14318995036651536017, 15152996261895537910, 13117193981606719833, 10869520400973032500, 1535537291014629366}, + {3953371315021198156, 386530500873665491, 3508849322379756897, 4055089442250030357, 12628113724743989767, 4186397566457919545}, + }, + { + {3443066389826097469, 5916450488257370663, 14335878619740602917, 10811180552560485498, 10078378655405541627, 10331041864412397191}, + {7918530238023081306, 10187646187565606947, 10643817701072622350, 14671988813510778565, 17264570610690688746, 5035607629406476407}, + }, + { + {3532200476336731719, 5678111310353191224, 11922638866398303913, 7540915859698370345, 7422783730002635298, 12884745215638918079}, + {11258694614182796345, 589030835645795838, 2262193094720294286, 13773904298325886739, 13573020426752625101, 1682880838844955766}, + }, + { + {3667751664279524715, 11424246261326489986, 11184700745029985834, 6642084736925658394, 16833380705883602850, 7641656710490994742}, + {3519566587420847235, 12380249650455369211, 14234084881378137812, 11403307110698732867, 10605766497849541425, 10861452779244197005}, + }, + }, + { + { + {508120474314030324, 2355066544885544183, 2781810294408129833, 15987954833749728730, 11640488433383588320, 273718689405132586}, + {2640929119024127447, 6627781401094026707, 8341197168509731890, 3918225740211580144, 12693567636985320532, 12010813241293331917}, + }, + { + {1067643586933482569, 15789537218210505592, 11772390798352937810, 8551678486344942630, 18134749517345567483, 8018480309623112915}, + {13721763421328053376, 3248048408533182382, 14403298468089883307, 18344377936005924503, 8145236551628572080, 18246715613208739706}, + }, + { + {7517918011338920649, 10924417706771677823, 17726681281676783216, 18231267965570514089, 9942149863736880790, 2495324098584754616}, + {7703134802415701672, 6763631388551517046, 4129117670208724623, 15972974109259347702, 7281041685266079849, 4033286739838961760}, + }, + { + {18167431682574255272, 16875991970663412008, 17295095002088005373, 8493357273501291495, 15937618870319643038, 11833224465563102215}, + {5034304464808785416, 4940901108264101769, 4572127150938139448, 4375798149940068108, 15502449895994354606, 11063825957880913338}, + }, + { + {12106998444454782089, 478129254096369622, 3583445821883510974, 3783525850583222929, 12700800678744232856, 8398918095020677450}, + {10572000908134195556, 2591572375203033135, 7440424324108251337, 5098405712381411786, 16645670879854917662, 1340903336183382664}, + }, + { + {7662402429691938227, 12301560877341388372, 854014491934252472, 13252962285002044539, 14950007384282365768, 9322453517274020995}, + {3037202449373284699, 10134277839370356135, 7874405825451119639, 6074763175687974962, 12425801537362983169, 18441996758138525244}, + }, + { + {6377198952519496340, 10452019513637841848, 17999702029925940943, 7474985002644580736, 16710285089220886173, 8795286825426459720}, + {9274877579709547055, 11658383846072744560, 15190956902413353547, 5248750851994650598, 2300395682072506542, 2755645297874985482}, + }, + { + {17741788053056918633, 14066143977624056531, 9188940017443802353, 8808532662781054683, 3364478519071964886, 3169335378890645771}, + {17112675492175952719, 14236192466751475311, 5603662455233963823, 12286659362580784043, 491873052068930659, 15049849551374735889}, + }, + { + {2576424316119212598, 12775551962911576966, 15259699755977921424, 11651942542046543115, 1402783857204478837, 18324652864132536670}, + {1707338149370542188, 3298420157097588817, 7521797060095862577, 11460596774399479099, 2575910799608490644, 12312525139228130635}, + }, + { + {392896831764612871, 17176033439239962097, 4721807216245185554, 16182155038868684552, 5761252087564225471, 15052621263295120129}, + {12346920066003727294, 6129012491021115289, 9977552588222578097, 6652331187558815009, 14909718540327055008, 968144566139233934}, + }, + { + {13293883802715635807, 2653176068873560866, 709377591048241427, 8121623725564414915, 16119489273759831559, 17342448566209464262}, + {1211174416757974427, 14015417764234041664, 14462722521216925477, 14082661984659007681, 1695477692957516417, 10365750554717767074}, + }, + { + {4884022083833567724, 7559598399602191657, 198426261319140977, 12353123114206461318, 7871074382107198052, 15544439452501146366}, + {10764302824973303475, 18236640700905160595, 4118397287860275206, 8469775327273188212, 6943100138927210185, 7678646557360620170}, + }, + { + {9047129816186912754, 686205745533008290, 17091874804035707852, 13829610192011685605, 8445841882472685584, 12683587236818333381}, + {15248187852218806490, 9143067576807462149, 13130422498538192412, 1987394184930393469, 17234091013976042376, 5309021133366567407}, + }, + { + {11153014502206421469, 15119688811090307722, 11900512007334729116, 12033534775335022157, 14206136005718288725, 11758356920610289524}, + {1170674544739813802, 1735805534869368410, 14265461327530260009, 454122264224446315, 1196955246858854577, 13496891451537487585}, + }, + { + {1963635747876520766, 8037994677047475948, 9778925841589003509, 18373179051584417655, 17774160058627740027, 11457632676580645202}, + {10746767866979893471, 6679657251517714598, 11924693891957720076, 15059776164765359320, 17106029443182107067, 2977050945907214605}, + }, + }, + { + { + {11428714276400700816, 9684363906879720073, 2326880593732199571, 8761076367298171397, 896913682478838017, 17538745710015774502}, + {16011943008419601378, 5975733755904344526, 18015284849904033774, 12671514003052240271, 17740261525233420473, 8887483872226550753}, + }, + { + {4149943974880712918, 10350790058854190497, 8196369947058715735, 4949794127529191723, 14693007776575755250, 799869184787085670}, + {13583602297228816985, 9731922590252326563, 11783888221311533059, 11272596661461028723, 10650424498639591856, 6814307635900293619}, + }, + { + {5187662544727433604, 6610818388649597184, 13217214483925463411, 11225358343307261041, 3979262110455362044, 17023319482473508776}, + {13540734409372034129, 10873366545113221391, 6574497676007990697, 16695089176775352098, 1800106753424785549, 10409365476253724591}, + }, + { + {7201953056257784053, 7550552970976446148, 6715285792546737720, 1597813460246962944, 5934044807465023074, 5362427500790106824}, + {10951441180547054651, 18111344793262344961, 11925095468088301604, 9885237597177799430, 17378911605611802956, 6344832877661407429}, + }, + { + {2193141511878184296, 8475396127202322472, 3917381969650598296, 16265248388470690809, 6186852221346093846, 11846013739636446977}, + {5487357187469375202, 13711750528133438663, 1849109594291933227, 15949224025529501096, 15221000652947043364, 2391723465441720967}, + }, + { + {7536562994359807923, 8905565631504805860, 16506171098935768123, 4130408208541979441, 9322288628868118772, 3079300424148444967}, + {16936259574260547615, 18438783821712938661, 10324525933994673862, 8397550184634189831, 17434676747885185144, 13637497700498785239}, + }, + { + {8483145192795413196, 3847913378476383052, 4337984637797992463, 7010629707438332975, 11953181174909111039, 12014680632165513786}, + {12276869096120751141, 12577833746497947189, 11723523233456261682, 14093651901317012131, 12375742220834231759, 12908141375852234811}, + }, + { + {3461865703771860361, 797298537903379949, 1718621620291046004, 9179319574938112016, 15506643513481237125, 17129849380198117652}, + {7110323273563692976, 2203663670190111617, 9853530541246034651, 12592752863363999293, 5433719754579498668, 224022543784731840}, + }, + { + {326532432663732788, 4070991663847076038, 1470607885232799605, 6211408722804468886, 15716355503743027945, 5590361253785299677}, + {7812181315317979243, 11828059863468531398, 12778009786378056601, 7800732687373876279, 4224156601900994011, 16057020107391082099}, + }, + { + {7782487925572685932, 1724391588041133300, 17972041778362775708, 11333825676811621865, 4537746153362835585, 4171052629714822431}, + {12770750867191330688, 634694503287104037, 10540092664171311636, 1350757360469465298, 16229194085829187695, 11033889142205249636}, + }, + { + {1500626805655044948, 1474262357314620997, 11484027637627776587, 8585564162226987518, 4361776374583212023, 14496468422187250418}, + {17741545623455229310, 12747090277885336885, 18323745182075670270, 2038556268554236114, 7015814683852162475, 2248939812176116415}, + }, + { + {4335040403419509309, 4616570637565163389, 17011251234033239541, 879860923453038495, 6819883123403800219, 1722220926773986334}, + {4709656270455345524, 16636162851412473237, 7348864482366322076, 14270025125795014424, 6328218483059680686, 13214052880713025067}, + }, + { + {11977022734060949713, 5628060629783977587, 103670064741031623, 8484869049261498542, 4939759321638626982, 16432117890868549963}, + {7629267303968775517, 16619962589721111422, 17463764779224102539, 10685322297759502900, 8807902043402042351, 17462711850802416480}, + }, + { + {15295264908526444823, 13335307760080513805, 4604414283483994449, 5316311055438475989, 9106484611277661419, 13606509782370139031}, + {4442177947438604155, 5803819775434638136, 4655697769853187972, 9432210737074556266, 1181431965380933231, 17230321351582564170}, + }, + { + {16450007145062463968, 4085694834533625610, 10068111071916006395, 7262607959861442044, 16002455059452793805, 14195715414553647245}, + {11695905535525197488, 17972632274451872946, 1579756808173779650, 9867832289808138729, 7742524395848721653, 2581276165337478448}, + }, + }, + { + { + {12418897939030198809, 15206661827925660880, 3670234668273509673, 629739459084205561, 12432881678413324698, 14794818295399912598}, + {8304013048279127199, 8979239574719663301, 7898287937622516136, 18064217129523036783, 15422375485556825691, 3491105078158712969}, + }, + { + {12712561841049401285, 13926510503703002969, 2612279756031831730, 9493430901786542794, 13291879522996024106, 5809241029170276658}, + {13691694507969220766, 18143668557798275313, 9138492995891623951, 688189100127541854, 15640560704872541163, 715816703484468594}, + }, + { + {9922254315993542377, 3698353835142433482, 2152397153019100388, 12317485668320147862, 7630803741744990206, 14043844136716370060}, + {8779442871712769558, 9907756658115628584, 14458334256944611273, 16860549487530785456, 6324109159626157948, 4731255892134100106}, + }, + { + {8002922251516613060, 978443873609457407, 3195553158279317543, 5854976976295928246, 10958159112329303460, 3970083282599810189}, + {5557639662225343558, 15971994949723322072, 11989908821085930999, 8821364574039081706, 16665145761534571014, 4658625544288657356}, + }, + { + {6340510664543185199, 17018415579031156332, 5848132202484941289, 1936333141268823482, 12812324366507433640, 6731572340563570418}, + {16857078034411292476, 15068277976532276123, 11722116475437972189, 1964509865396978581, 18238872631873981400, 7991345170212629670}, + }, + { + {4399729739127562657, 11272928375680253530, 11946741552547688174, 14049301799414882766, 15181782087994325146, 10089988859449254233}, + {6518268185564876927, 6536487350448659481, 9828361032623653320, 1339336992832075931, 500012115828942236, 14824212847841613777}, + }, + { + {171920790242842166, 5492071276632784703, 7283720254645560138, 5078044100187809965, 10385647514177990351, 4643536432707194364}, + {14989909821879706494, 8756233713883588748, 12449984475333613170, 12585959722117915734, 1005739684596759274, 11155909844346489416}, + }, + { + {11688324725241825062, 15138461392078796204, 12325266391227455113, 1340485671902994619, 282500164578345499, 7467882813685092227}, + {74331176722111354, 8867394635845954934, 10408699117489665536, 15725442571211452985, 2590111940561580876, 122458286127547889}, + }, + { + {15892645628302923294, 5856468311490081970, 6874561504197875933, 18019303355409739795, 6082937058931523996, 215426188952156771}, + {1268422509930086836, 14213194550854690836, 11126293425133380142, 9865185168089540488, 11632286407552253140, 15174468604920668601}, + }, + { + {10936413110689795487, 15010995742767473191, 4568817801913429420, 4205444133627513879, 6395122355763512349, 8918743386740702009}, + {16692774758406989332, 17955372475145034386, 15048470334846953021, 3736761708891032300, 2111259224340263959, 15614397697732925529}, + }, + { + {8738432084134066654, 3426263179552640084, 719712812862575782, 10981970426674636690, 9230912351159198043, 10854126184000364805}, + {1961455377595115519, 11451312678111642174, 7688356239558056833, 5143561757570891633, 9215608498872789998, 7917478891815725904}, + }, + { + {13905441237538948064, 12480816058500448930, 9351950531208974987, 17868240518152709336, 16456831118221743401, 14827343335622163069}, + {5502543494126784481, 389131188595713234, 13066540568193379266, 13328625471332746991, 5244571811269709341, 6606962250802166084}, + }, + { + {8488561190820155258, 5704568936155861609, 14891109450025140507, 14985917965027582458, 8150697647605526155, 13242121807143276147}, + {3762467964945321810, 6385131138942825064, 11791602379712639353, 8213332910240399371, 995112454035913025, 8530416099523440086}, + }, + { + {13640325735363574879, 9838259707028418406, 13090326969619576773, 13639005985461657607, 2136356356058124836, 13990780887246135133}, + {5609755522352639162, 17659567235866466759, 16259320408797139425, 5409555833771708415, 9408620568269064004, 6504340943038131334}, + }, + { + {5831978049482033791, 13004433680416851426, 13573449569471990176, 7730273069509750576, 11703396887458680397, 13713882189606773514}, + {15136688631097887611, 6655871600738369661, 10582530699775137958, 2242461969176695317, 607007649724149634, 12963349946916344106}, + }, + }, + { + { + {1245849788995478406, 15927065038482738007, 14167031681717622750, 6558184416262903003, 12026552713606964001, 13141157765235910782}, + {13953548913050124814, 10512136906136752951, 17603704039609623324, 145717304147461215, 325471403460036622, 13128236733581623507}, + }, + { + {16674741188506215062, 9760284329368026164, 6227912018538320358, 6062313431245706681, 11530767050864043247, 4050743335749600291}, + {5438096629683113243, 4619575833741800840, 3125333116803012851, 3488990215372938922, 10001296793595923533, 10533821010269665140}, + }, + { + {16525932200239811820, 11277725255119639967, 13380457983594150580, 11345091161981432621, 16404711622698975165, 2413157060343610687}, + {6861888264192898716, 4349048715057257879, 17588098592479288977, 17308040295861018844, 10945075256382032297, 6591571232106737441}, + }, + { + {3312100944805375360, 17751669833244855959, 11421167323527761031, 2790564601954208965, 2677089945270728547, 14912524259578856947}, + {5283996146017069939, 10959370318137784011, 9095576254518931495, 1311273597919359627, 14918615616693191386, 926115797902848153}, + }, + { + {13690563848743893725, 12308308054894561959, 15395087439588112783, 2472586724818805576, 8533710141094669405, 7942802424878184185}, + {5420945215657024810, 16122859608174405004, 3053741733492700862, 12221133467396472029, 15851472746153652052, 1947565546705152863}, + }, + { + {15897054605211154249, 15279739731289823093, 2336561653796295997, 12705889529297020171, 5961825895197974169, 2720481772301941412}, + {18443277954611435845, 594427728188203259, 12303839396678154633, 5358688406862385350, 13000467893527182939, 14952128333381655033}, + }, + { + {6619004200098886597, 3521645713977761698, 12344376102408265251, 12402516760501056887, 16667318326769571309, 12874140072685141335}, + {9621314969493341823, 5207967593480486550, 2826521035705699793, 16265445537996266956, 5066340697704330848, 14633460704255879322}, + }, + { + {4697083591690261853, 16801765456421135763, 18151421584540787936, 16835495532227054337, 7795860894099083043, 1328764521238600097}, + {8297620491750460337, 11793447721298138387, 10295382270817397671, 12786024121368826653, 7279518368534718792, 318434652860893917}, + }, + { + {17026077028448645577, 565529336479994071, 9535502575346171761, 6007100762400155323, 5678897757750626782, 9959925017754425050}, + {16242528163060496516, 4576911095161823236, 4403607854299656167, 12912517930864843821, 4739470393271194311, 1151478280656415262}, + }, + { + {16048476540489898494, 6783117499823714007, 6415336927764029960, 15673195924318961740, 6247136051556578121, 13084657697232162709}, + {13162992357344402018, 16464326350960129807, 839616770160173579, 4740726662754602535, 3152479265198829295, 6404513982945014328}, + }, + { + {3092232113376296196, 15331813846360575326, 18290474234869335723, 8231838642205234980, 7400082193016179605, 8410763375241570875}, + {9128762227989687509, 3794598237625234172, 4286873165056892559, 15334567321376368149, 14794216692099838599, 6895373348463126576}, + }, + { + {2724979383179813062, 14777475620842655294, 8495183486057249617, 13049191530970000171, 1463143549362168712, 7716595605180919892}, + {4514675039144392038, 3975933817505069894, 12970184659307405583, 4177319338659410908, 6165857585915235970, 17620162379352558438}, + }, + { + {1745353185162679063, 3792943368267263896, 5392169106673425858, 12818767881496565683, 12092569230529535449, 2578847804476911357}, + {2780126809449397009, 5405540052572325879, 15285827524500880746, 2941675021271411795, 9447355824276841918, 4559807377485007719}, + }, + { + {7610007746883416737, 10147509530120995196, 10888385397255137878, 14772040059195211280, 10560108669991599276, 2620459706274870386}, + {4887132538582860164, 2596493858310366442, 13580111877897930049, 13035579030058060026, 10732634358057493593, 13596263836781091773}, + }, + { + {16502308326832314698, 6813655593085792854, 865540522694200977, 18406777409114169497, 70237201416715116, 5540630135583650201}, + {11043265419464844764, 75803127346564744, 3544127781510566665, 8608672751361961179, 5292089330226488152, 1998221520759237189}, + }, + }, + { + { + {15843747259285912280, 11051757736519314133, 15850618202671354967, 11414438518663550807, 8901822655665788460, 4938308746649520510}, + {777341510519627412, 11562816405392154916, 767515422569196951, 16316638273329970696, 8108021482044013490, 11530472289475307950}, + }, + { + {17325850825538431065, 37125221006850315, 9538255856396155842, 1677341822293077462, 8890165136267025298, 15244650613952369517}, + {4845598674027029924, 276084057002262337, 16096273565408425115, 5476011667390370895, 13774404766368645238, 1693789135306442102}, + }, + { + {14853893681504474636, 7246777094738611755, 14348468490599768069, 1584676862820702751, 4055902816558872583, 14691624686566000273}, + {8463792358840766097, 3916260300604218254, 7138823842751636444, 12063405069309472256, 9666094494441286118, 227223526050825967}, + }, + { + {11439448267446980509, 10876971879546473859, 12463594188698329361, 4867143769403125573, 12497774131673245064, 3293027647115301082}, + {17269845420219875716, 7999343694417279981, 11042866033136034598, 15364989427615166682, 10865140228718307051, 15023792553833632785}, + }, + { + {3313587089867634043, 12345206552722066323, 2085484537482749047, 8672528099921546193, 13019543378492473719, 16014000899261448682}, + {8688247996955695393, 13880086369349074733, 13685898059232129585, 9745238149905695566, 12860398562206147371, 17318310740773319426}, + }, + { + {4831067862161961952, 1700016751300913085, 120879261664102718, 10126392277187226937, 12334968545166906646, 2424236269343093373}, + {5064451542294364369, 18179376425888307033, 18011599774285802620, 5403509623689485964, 6314622790688034216, 11605915467730303384}, + }, + { + {2247133619710642624, 14577616964025781087, 2368018907158808843, 16498726243986409168, 1407790037339558890, 1268560497020660735}, + {9801656500494901417, 2349861632952537447, 9517882931966374505, 17010759715257218806, 15435798766523589684, 17726795183758368944}, + }, + { + {18311374045587866554, 14447020620922821410, 11083360170030115832, 9113415708727437834, 14541956290558262142, 13961285592123282152}, + {828114605405992045, 12150002910767606346, 7206389356124187542, 17860503209876058312, 11798129788760460490, 17127855426259911149}, + }, + { + {6199176795763629395, 7044922086316649293, 13997864205295119697, 276986585995515541, 18048058974579713616, 16490720274644998299}, + {8536596227155890833, 3914547013952713733, 16510694033833622662, 3939667794619888075, 3178595810875111442, 12482691560580240458}, + }, + { + {6817856411751563437, 5442319161374364825, 2600227314552885688, 885644663444831557, 11700451742910873418, 12995396601628275569}, + {12803389344446349365, 17830292246277698677, 9309532553762179652, 6680640295615786576, 16662072345574199545, 5503555633912973406}, + }, + { + {9023109435328558547, 15291865436110219430, 13383262037362169985, 17595017389171456916, 9112975926620102374, 6959372004949197556}, + {5079998641977253062, 6532421761731762580, 3807095942977659963, 8160554533119900022, 6829392063047646882, 9484387938580835773}, + }, + { + {10226973915924968410, 8694011647938489632, 4300203054946897035, 12117316368104547695, 13852935341469006648, 16325279905079591603}, + {3279907632975731352, 17658867899191622273, 6430488073563164502, 11102370118583390470, 1351653460592165074, 1155328654798844033}, + }, + { + {17696616168038539128, 14705634818800389635, 13086381626647796878, 8160829291664474794, 12380871402708163904, 86292804711961768}, + {18387045944833009681, 366768093235351805, 6342784007092933055, 10213820317755221687, 2637460351332260222, 14273547543620959978}, + }, + { + {17055410858120919085, 5117864209362229433, 7752728474235998778, 5718238531312883549, 11379901830549393718, 6167331998180922513}, + {2139807429787460156, 15318820080504273410, 4676863271077360086, 11038500994511396240, 10091980097419465773, 14332586624137472063}, + }, + { + {10283737372978878771, 12574954996091932368, 15672686541053306208, 12565297310940420187, 16116977738821195704, 13549410483910339391}, + {7927005432441035757, 13175590081759395358, 1211258742602602684, 15884670892710680064, 3650720270567732720, 12671425442920594205}, + }, + }, + { + { + {16945326091077782209, 16464694010613758543, 15031894690983835272, 4230984078465338834, 15876751555985865416, 13853851790773712608}, + {10629669182284449427, 7123507341691517943, 1604779450978617269, 12335442368004615918, 15831231179039969998, 5721219491336463048}, + }, + { + {8779923605369004874, 11015027029723172570, 13053683587822215278, 14371924836322803667, 6175910444240484015, 7444596092153062599}, + {16538104473324970868, 17940085998297689696, 8904671253507597276, 10735167732778346892, 10719411100540081001, 11825864791636217846}, + }, + { + {10513874959070541808, 141726534094196367, 8961670049397339577, 17110620828714912466, 9276156314861939407, 5283989756429336401}, + {10830576007717201253, 10019682216548180288, 14732709404946097825, 11154000097553876933, 7279438743640661651, 11741828296965158287}, + }, + { + {13710602247235634585, 5794283881286256131, 7189333897035442825, 11474888458737436516, 9536387759009059378, 37447282054824480}, + {13831688592995763204, 15514310505960816464, 5617377358519582781, 5382874924721720664, 12826347177360954774, 16487830138240466133}, + }, + { + {10136021926566126263, 11928523244042660673, 620080950963362813, 8625626899007622861, 13450521127313958418, 12173913767817931256}, + {12782398870117899816, 18284930545209739688, 8340732005841122414, 7667253783573485052, 1170918830797979709, 2726644985398233748}, + }, + { + {5868319710548462775, 4614538984539777268, 3606513902357509689, 5842687629722217460, 655661300379058806, 5750034184391579904}, + {6706948898263875391, 1861998499115841763, 17416124038131320471, 3088573942691514912, 10862822225918958565, 10723788336215927712}, + }, + { + {3469954697000879474, 9886078825125536983, 16639512902206423417, 949458984263591079, 4713065388685405969, 6485681870763151394}, + {17550597369256616144, 8492358132474734258, 1973243959933916082, 11845479291839734419, 10373742178422412864, 12917185093797127077}, + }, + { + {10148520876393042933, 17008996819208361065, 11244838413238054187, 7578025140351179165, 11819693939772377780, 11922206691683897452}, + {5193678850892441703, 11269576636085412111, 14586018532679524926, 2160103807216749946, 2883270595579022419, 8933957426785365011}, + }, + { + {7701278840381406043, 813864330332921165, 15346578798485581339, 4630804650809464614, 16185031359787444003, 17826776112141610425}, + {8401323936341934197, 9592171776430509912, 7758005530392712135, 14454554148729439336, 7956273653179990376, 7839320390573561917}, + }, + { + {9250363391170832193, 11006035015261134401, 14458550514807354785, 9325016894298710330, 4144596754841442017, 15054746156170374381}, + {11456640279410058145, 16275606744085683852, 17831878718437221277, 1528529578606146868, 10275813860685205403, 15479223083860040951}, + }, + { + {14596302840734253179, 14900690077811267578, 16140097010885461623, 12772352415462534488, 8614394783748304718, 6766902863888446020}, + {3301138793577892410, 172863568565472035, 5251004015700101269, 3165424378709792613, 4958340403792084944, 12619148531858668210}, + }, + { + {3284553122109620274, 5270759104970263988, 8347616712857016748, 10393685591838506061, 7030247929091757107, 11570651577508724004}, + {303593432212184598, 10870347165523269046, 5858810139852537379, 1529168183268214217, 15332143584615473398, 15102908354736105773}, + }, + { + {9574340152153043928, 1662915623607662881, 1811398080012362182, 14878205415613515919, 13936394534036516069, 2337960597242570130}, + {4877776368265943702, 405103566243555934, 14225276821637443863, 15556532615883469807, 13552306515137288805, 13115529663394516774}, + }, + { + {8161989794903954412, 11660052284711833602, 181947658370696753, 12989304799327482750, 4066413204451462606, 1942221685308503206}, + {12484888137941485851, 4649383641303460090, 8371451456723263654, 18441597518505156777, 2352723388962482606, 13975888702704352920}, + }, + { + {3847700141255053024, 16406472982872848520, 12468984591385771739, 14942334423186830995, 9933763195617481489, 1409101159701707313}, + {3573772803237348824, 11730844867315771254, 7243658460515938367, 2166169203511142802, 6248287935705475203, 8265081108739245827}, + }, + }, + { + { + {13853753564171363451, 13820378722717422408, 3590234094500056381, 6866298275188000567, 9895869565406539361, 14927210698587219451}, + {18236367046121661763, 4730509858602802480, 16337561945026136271, 14109799857833288312, 11587799424253933816, 18285301586729898647}, + }, + { + {5697628194755082385, 10473326214136017445, 14513883747346413480, 15341298111275585222, 17117376470859521237, 11176286297628034124}, + {13634599286238815170, 17382552533170299294, 9094266669583253997, 239734418257835070, 3591794414849763173, 3133034763403569336}, + }, + { + {479206554903518820, 14658665690734737994, 17152906210790105810, 5958667172720220276, 18361725589118886101, 6185981515380453548}, + {3944672359066359091, 13732151285655721173, 13939827029587789643, 4302296200033682886, 10240802189705837857, 17865142655928189798}, + }, + { + {8306168305072060501, 14751131852602843064, 8096080752206544475, 4680206077732390021, 4419645889416275973, 1519820218356079506}, + {5861554578628119723, 17661801171279693964, 13496831092349512650, 3841281188034367706, 9158790543647317313, 10612203699190989969}, + }, + { + {17037898389052207682, 17860849396131636095, 4349951673886175152, 16094377250964498544, 8476986837295463150, 13680887785001025305}, + {9336507099265066829, 5947089043768571535, 16585602400938566700, 12581267016799867259, 5245484406207830441, 15258801158753041634}, + }, + { + {17548721630682880044, 2012629971546646455, 800602602193080743, 17396222438338198463, 15386698858603827900, 4460480856545157616}, + {8525314085294734845, 6802480695964082562, 3816316223911984005, 2464494579218714722, 16070919992014947059, 12434854377052757812}, + }, + { + {10772836789272530628, 17088691547289098969, 6718631187086570471, 420298886229605471, 14226789851958972081, 17291643744773087097}, + {12356365831670845340, 13630822714405907791, 16223114371865091666, 15934941425414639409, 17030594846596638635, 8894066301960174157}, + }, + { + {4310605480085901679, 5471288425725661823, 6576140643955467936, 3714340113776184365, 15078838872712774233, 18067422699917639715}, + {12245168645156565325, 15389216374359086860, 18243910314816324743, 13468377185671333723, 11841166299472831071, 11909676588719569514}, + }, + { + {3039346662401409366, 11575031947853028231, 14291487837746157982, 282111250317099825, 4887181073166372566, 14047452768090024474}, + {2283232607704977993, 4156222868336602759, 2441521584735661714, 13573229353517305526, 9684005436985156440, 16922485212222584386}, + }, + { + {1553039617197624241, 16514547904183858426, 17367571479943820700, 6825408557936662849, 2149227651964819356, 12858662242348855034}, + {16445523343296776096, 15421752631325482241, 9264183421788584112, 10262669298529989004, 3891304426791575665, 7854962043530510807}, + }, + { + {7161328094115041425, 14768718294470741983, 1078847568267874018, 6322480815278149199, 18188544274188331587, 16963805236223110899}, + {6569325721741554692, 3602100460502266263, 6206643867130260259, 3995469255074245935, 4504503583988431466, 13467328567518375341}, + }, + { + {63226333202683911, 14671906635501883344, 4335660486805420293, 11275217723178135465, 6969760830613945548, 5475843160816775058}, + {5191859885839573328, 11668101171119622286, 9518940388019884438, 14714241947617194877, 632307311715190469, 10690578858328770477}, + }, + { + {14884997433355015941, 156621939301515107, 2445891763674288403, 6687931105529654257, 8038932454300528136, 17697513852216155615}, + {10697408303393919012, 1270195498851099805, 8775588255042571995, 1242116603145454630, 9905730533240215250, 11108714318383369270}, + }, + { + {11500726014983094694, 4893160514903146014, 6828604209587544129, 6694479643978756339, 10165551838331433795, 8922014005219839474}, + {3229903124718463251, 14809704320533033299, 16708685770407035451, 5156200782696113140, 8700282174866114406, 7662703141074882120}, + }, + { + {5701014331899997770, 4977516111362250117, 10386130146580034690, 5907362069264702911, 5301877636154186197, 397392370575027293}, + {1263487057932284919, 11711479762453857997, 16042267091696606042, 15652910858049110642, 10197526967041956937, 9889216320967166622}, + }, + }, + { + { + {2278932254609762845, 3068437509226158452, 15744868666981586003, 8677007854964299754, 14625754507006402628, 7482852446653641224}, + {15206963697756253732, 7484355521899064206, 6303098706947551318, 2787820459819783710, 10505036182664953766, 16812578278348872057}, + }, + { + {5328402213024840932, 2831229329708260259, 9906671250991291328, 7195378896450113384, 8137962574541487106, 15483420743942942895}, + {10185763153215621718, 14520317539607894634, 16021622969265412233, 249210915963234415, 17409430098951304156, 3459897863682731842}, + }, + { + {4578309973503497569, 5447834563002642123, 15020655062803172906, 9784029918330815189, 2259183585428823851, 16276654784273178554}, + {16974315692938443293, 10322189489795986428, 18095043949242233690, 15529824169672291114, 1043280182503641486, 14396190389419318386}, + }, + { + {13791916129725914380, 13541507063515942618, 9276345046434203244, 6943275844315018043, 16854690413809965818, 2726487241024832361}, + {3900450032896335120, 5969156219373170750, 17268291021193518751, 11250600592358444059, 7565688406177070545, 15380048155812318403}, + }, + { + {2159715218114046205, 301696308536518990, 11911287610460594499, 11610729258797804364, 1589214470697930255, 1570320627315083551}, + {9260920251773296769, 7918633900008866828, 7386692371354490728, 7126854243096368735, 15222007907649556112, 11290458721857786222}, + }, + { + {17312369275830596578, 5182973081822417591, 5758577204554952034, 295579627010058982, 2247918074145955246, 8367663961370585320}, + {3503412556908913188, 5007246298285139323, 8914116616437113026, 1817837618482256490, 3888281808755203703, 3596198455140072332}, + }, + { + {4204733050884801398, 1015148026108767645, 4474014702901614014, 7893591904251967078, 4629334549496872963, 15544715130284192268}, + {11515169364144564012, 11336358832640243779, 10261616753173485797, 10330995131826947610, 12790048324162427726, 3954964425838098297}, + }, + { + {15466718315096778468, 8207059140145815039, 10673629467808554944, 886708118721286191, 10960160354467637448, 9642682828370620599}, + {17438921783439498819, 14206610474459128199, 11283947246870324451, 12050660127565107275, 13394619346776634282, 17491132232695062376}, + }, + { + {10457517951627566681, 7814805982659785572, 4650803108692583382, 4440130354090651090, 7336812384548660642, 13822285076682517424}, + {11611474337378208231, 10509443664430110860, 10916114862115943164, 12170669850354153477, 1352553062166066021, 11347589626152349860}, + }, + { + {7366949076040585274, 9972276751640303927, 16423512277534811183, 7530907908504052262, 14015798648185098200, 8802667423497257421}, + {228792414850368243, 10508703706507014037, 15514995919049710800, 9118562110950567762, 10221889965935090890, 16185466175233862997}, + }, + { + {16803723690699933675, 8487548998297552291, 5803011050307689648, 8460712827018550942, 16456152075823939447, 156300814418469424}, + {17276908626721299576, 10528203526298520812, 16491173177262003297, 11906011972808274164, 6723396315092456133, 15740670211031988239}, + }, + { + {15373669199500708772, 1418986186617967125, 14646929309039869466, 10499548009936132679, 5225957845760868950, 4939303423191000552}, + {2490287739273437898, 16292383701614685255, 1045010937850952943, 12708627850998017142, 10150876621237058060, 3374704772596624527}, + }, + { + {6486481503809124917, 11162331521576557500, 10016688945665150046, 10440833383589084422, 14434962491136116288, 13795058186240622619}, + {7202909919242169987, 7084906191002088475, 2670999100224514475, 11205165509896785683, 9153315609780748370, 5520519463950164065}, + }, + { + {351071170739877570, 13322560781273060052, 1701785565365847432, 9955777089526659386, 7009753490594385600, 829657910123534028}, + {9606276748652074643, 4015732708367370031, 11721876633733031363, 1595979662340466299, 3599656218219669185, 6412814251963052600}, + }, + { + {322868295872168097, 10779671223207907160, 17146021042584030369, 7744919563204743978, 18009926370684955932, 44255721611034122}, + {7075518626826263580, 12948066299893087092, 7907043165345290748, 13326944701483639264, 4900286334119935957, 4216867816480695349}, + }, + }, + { + { + {11422675888913080491, 5395798484379963549, 17893801226572621158, 3834831668463767880, 18370393837527875887, 17800133101197187390}, + {7029247643873698097, 17334943497121462468, 2660202885167189413, 329065954663218375, 6698129215665562567, 13717605916501910272}, + }, + { + {8639178386474167317, 866299449001193597, 3615027842912577064, 3248451241352944854, 15229370169242039655, 14022996697023959990}, + {18261603954599110401, 277984183194636545, 7122474136492127151, 17268552229454245560, 8360275028065354990, 12658058275321946659}, + }, + { + {7568749213445711158, 11322886283898751316, 1514838974790282409, 16480451187055352472, 3521826310939475982, 13331538149045598985}, + {16615732436977239999, 2388796933096443142, 12226612954948297380, 10822339804892299866, 11505338527635209905, 13965903403607753974}, + }, + { + {17992684961837313681, 6896408298290524868, 8544072807657571566, 6748791036415412590, 14025071172791740982, 9009141746159193034}, + {13586218153614538887, 7799628080484457452, 10266486360990114058, 10957603090701342492, 17913488373740611379, 3678764260563976289}, + }, + { + {7850028067287088329, 12999005266298055869, 177742117066576348, 4187563636181037744, 18227464305249346823, 3944943827343100145}, + {693604820039552598, 11582121744559616851, 8219537047451291189, 12011868187157813437, 4720619866818053644, 4330189064262098264}, + }, + { + {5651722935351245741, 16211924818358123384, 11885056608369234243, 4201983212017634359, 544526908348909642, 18119044215050860139}, + {1629340396439724022, 4959173500186337859, 4507705775156637972, 8833696014848286450, 779478998504818906, 7902380186120673057}, + }, + { + {18293852260825634987, 11802124232706822019, 1644849027510672867, 2812476574328933804, 15557250672802932860, 16508981297686648154}, + {3465734358950613242, 526649456539607490, 1919417099895547055, 17331494709758577824, 5162227762764949865, 6242065099954684976}, + }, + { + {14405288903984360898, 3180009282630369461, 7764333772077120386, 14416489610146878273, 6877362386602494384, 8785041971848387380}, + {16205552197332611855, 1946014005873611974, 7425906351428289382, 14466564319882318102, 17948246265185418576, 2220383241683179866}, + }, + { + {14872241004765885673, 3636107144878936670, 11410176190546783355, 12181463760260857326, 10438330742190191570, 8102662675316985666}, + {6176126135590814635, 15938212979141106430, 6930351408968184663, 8991851982195757076, 5444235666245388183, 9160086367185317170}, + }, + { + {15340964667452830754, 14317488092981700975, 510238063968897076, 6837249889367286466, 525386960344698653, 13363589982130767126}, + {17072735759253073196, 3498833952641874877, 18362568207671943201, 8995020072357799227, 7719631523143820724, 1085622312019426779}, + }, + { + {13037971076711969658, 7591102587937139905, 16112103964232511295, 6658071900440103886, 3506958499519852800, 11206278262730072649}, + {874512935619455066, 14023431168230615564, 7818120766602709739, 8832031439666609419, 5585964366092107082, 11504555017740100069}, + }, + { + {15350102097560218059, 17960930933998802379, 5819537312713605133, 16574725790066529972, 5613973488460835436, 1634532828922318920}, + {6054735558644874316, 6779535286618214798, 12125632371272029575, 14822061593509407829, 9915577628769350648, 3262340591497022728}, + }, + { + {8571949731132956833, 17851489671172976600, 16122671592171467294, 17953595451749771955, 7101774572418004893, 444927268485192911}, + {12898124468306022144, 4543591108002290851, 16651517581025086108, 16702288951395475761, 9009172261902505944, 17794186523942672480}, + }, + { + {15874281727524415422, 6572132168538751333, 2488717046038925837, 7528462563702651155, 15177291123321120421, 14276075288284279593}, + {7287442030153170731, 8621411913466239822, 2230532822823360290, 17882655262254713908, 10820729357094734590, 17116812739217748569}, + }, + { + {3521891825683807648, 1428294732738224966, 4467541612632144795, 10743380230531306175, 11596549629085266496, 12996854075027646298}, + {7286872326554604613, 4747621740227512796, 5892707014992033323, 4322214473714022904, 15745271974603396672, 7332629562375692095}, + }, + }, + { + { + {11178967054056195663, 5059057946657071041, 15846370838494899705, 4058997021862163911, 2593984691649122230, 6254605580411388786}, + {4176062086390468245, 16189011794825339160, 3064989397845883132, 13286588576296135872, 535125068036700463, 10408854172492123217}, + }, + { + {13415824456928728537, 9031989784978508164, 17964218247364329886, 10744745034242750397, 11043008786756317850, 7568533431395324401}, + {7507011205371347198, 2388282443864154121, 13696995679089020165, 12583409078815059304, 13898075392069488590, 3664734608506976906}, + }, + { + {16544958402351236901, 14337484652764170641, 9770866337239118974, 17810777202725060237, 2097808205286057289, 10362289157561627722}, + {2685761484429320421, 2462399891877992298, 6512262486201450596, 10981880327208688077, 6617301996979402163, 2835239075992528291}, + }, + { + {7991173582500478757, 8893625338111976660, 14169111919230117155, 12356393203568432042, 6624804336968870156, 4373502195159979453}, + {5525831087690451674, 11667968375332638977, 11672899591207027148, 16453647862989440606, 11804399513913845371, 7628460269199181450}, + }, + { + {14630566089474246013, 12500213971114656059, 830106031407073402, 6911967831791350423, 5540576114989833332, 5622942981234358149}, + {9345206395676904366, 629433153585557678, 12592664746177863352, 7117895689488311014, 6126264353083621009, 8672251668710377501}, + }, + { + {15343270797031359599, 11669913580639087574, 5479735138674518875, 8134395341091815991, 3472212905841111046, 1943386847444310169}, + {4802323257275851562, 13041393404614837895, 300696023871229709, 8124939534882080453, 7037259695740405607, 15666477288369374120}, + }, + { + {16929655147930952127, 8700678224807582342, 6899508338063907541, 14124820011808216974, 6685131911353931949, 11392136278714910024}, + {16320977876025241931, 1873285772151321892, 3864985292509805330, 9209816330063069102, 14360660501914452161, 13765026774665638630}, + }, + { + {892554047301358165, 8208545275404753447, 8552497586050955747, 5886745868526813090, 11422451069439740114, 14454702771432318255}, + {13473748178404916790, 15675215165690108087, 5664345539094868232, 987897124768858568, 15329698597492189645, 13301936956751718708}, + }, + { + {11819868530282842855, 6710224194746120191, 748201410135027328, 11307022666945855023, 17212649811821554251, 13423110040809399786}, + {9934050328022487645, 12074357593722511625, 6630946082142899698, 17056161405408381398, 8571006633367538659, 3796784189746526746}, + }, + { + {2305785560014348207, 9531795736757421484, 9618934670188570881, 14780074586441306089, 6200104801707088881, 5386351446699164262}, + {3002942961830406638, 148274483233190080, 12735679168321756134, 14693507680316309726, 14232858087052761737, 13985992269476016693}, + }, + { + {13842387890174377681, 15419080605999723375, 16681571383346636493, 9653218004391250805, 1748476375644147649, 16081919636049288692}, + {16200057164189696404, 16659975838973439415, 16148363345960831424, 1128253701358674568, 11627719509137069576, 4062100673790478823}, + }, + { + {9445528033084918138, 3236780574278685899, 9682773997054520194, 3980365165990825614, 10958694477307693178, 10839810148743664524}, + {6650282121724231548, 7894922159420004756, 5624389477223934865, 18151956206730252126, 3735677846659494424, 7111781989342355242}, + }, + { + {10926693111959793122, 3929513560799028061, 13083700370081498912, 7606788298622011804, 1499929199041655117, 2537708677997890346}, + {16163615921094614869, 12490168710448316035, 4173408469387936546, 9680453490885130745, 6897387665823483412, 1803882466154055696}, + }, + { + {12928382421675599167, 8246098434142042032, 7828289919035992593, 12704490623615851803, 11049427248294980078, 13839977807550225944}, + {8790158444480790055, 14691519147850982325, 3571740556626361440, 2025494493460599521, 3901915857099204524, 9232848549491285301}, + }, + { + {17205250580750313739, 15838972152830244406, 5212027996849957464, 16696646218907655391, 13718292263491425643, 17806855155656742837}, + {11988041571551593283, 12853752025657189673, 13524920127388710455, 10671352188986408025, 17279385799981015698, 4758202966923836309}, + }, + }, + { + { + {3974313353418109687, 5720345224825286858, 6801835843798312295, 6372634484952764872, 3310006789326513240, 2726055308497026029}, + {3843770043613727251, 7900599654720541372, 632972795419277904, 5983319127366592262, 3077785537568329842, 11218370678822489750}, + }, + { + {8928421106978139244, 16345148895360341144, 13492011400134727288, 1731289337634521374, 12525842512649542947, 4207120388067304407}, + {2345046098001310699, 330997644936357897, 13635040363459393506, 15230878178212376507, 13652277951430850918, 7237296141945425478}, + }, + { + {4557723407539085034, 14471756909246230823, 12448850285779367089, 7851797223627122363, 5151430975338428030, 2954895927776921398}, + {5279712016090746131, 10809813162354586237, 9242053890074456174, 9668653512111950665, 10135306740731568651, 3351464240228973156}, + }, + { + {1627053608069570695, 11376938021692164730, 9622466798286684763, 5827728193917331600, 975693545877321955, 17470494739932363034}, + {2436171715026125366, 7848361070155121218, 14061221750869732481, 4888283785453330436, 5036741489113467755, 18084794423259936778}, + }, + { + {3552955380513038861, 6493678664778873794, 649357577150179579, 10545862185632419419, 16350124503975893898, 17724367842084936677}, + {8896453178391269512, 4710703558251776246, 8492419126400496150, 12768468520236451572, 9192761450614257478, 7438647446930613021}, + }, + { + {12369531841339403158, 12996664064774054476, 16155473999921375261, 6644207479370307599, 15208474964382806744, 633958492471874768}, + {15790482482394397377, 11673958026072739923, 2075775971265990014, 1102830502989644674, 14328138387706433231, 13602359449553119289}, + }, + { + {12143092119248055873, 14188915263690936719, 7408425876028150433, 3779414505485695820, 1780029671596030155, 12865710926564478965}, + {11680590440944425259, 6090714137241796515, 17343249885314900203, 16644769067866316590, 7256952446206185353, 12961945084971064727}, + }, + { + {11134447122165152593, 12122722588466177555, 13031738851579131777, 775360620960643964, 14535630049172421527, 15517365877497081698}, + {6749416834835986329, 111798195283805063, 9427922671178152846, 5583634039175768131, 18026394909638384188, 9381210933213377107}, + }, + { + {10334265748604755240, 14313974363914896934, 906523409788490776, 18014259526343590726, 2489497295341492694, 15497769074229220560}, + {16667753502962144886, 13343473574324449479, 10922772232061902038, 17638948975896960836, 6206546855196209053, 701379544767660020}, + }, + { + {7323167804561066698, 11606373977379537829, 7740797211952786009, 6774632772002662447, 4137066669379889537, 16448062068535134384}, + {2263388950950990004, 13986419062957738814, 12736780551361126087, 2151837813422636155, 1478109418633068180, 13196418687650255350}, + }, + { + {4763801360917190189, 8413965106647468101, 4459652012857109043, 9905026392952537025, 7732441075598956516, 5321607056947218327}, + {18121980170092748441, 3481588764335216251, 10446782825632997719, 7693360199940913038, 17104571571510845330, 9855412900039516293}, + }, + { + {9385835129240491860, 4824589714590984336, 2196446888524873714, 14983326779959559720, 3813990482140930799, 7930070026494865435}, + {10845320348409053590, 11702362686639252435, 15805206625312010834, 8614879420112692657, 9694429543708544128, 10989853026030014509}, + }, + { + {4594816827257062041, 2562345560258457605, 15050193570974712932, 17246403151526033694, 16146699389908107161, 3086841042515638998}, + {1177843674463060692, 12536747725401551571, 13206715304133223188, 8671490102358535635, 12212794350549092683, 20556749311088582}, + }, + { + {10565304604241425748, 5627103307724972881, 2705248188066943448, 11105071139145988281, 16803969759084451954, 14319542282813740942}, + {9198217579227787191, 10953486347952736044, 4560368619486330585, 757042920267352831, 9594548960853813804, 16693022163678979226}, + }, + { + {16489742344230153188, 6539412415140498039, 5165832543217723569, 13003478072329918265, 10047084890632029191, 4694331753623574371}, + {10703728784580237099, 15556245530594099306, 17588951018132280983, 3935002524499547861, 17702492742125323184, 8520257892664878061}, + }, + }, + { + { + {6560439988460907757, 5477297489685795935, 8263272205317190744, 2155221279069076320, 11867925124460267529, 8571196738200600952}, + {6380793266523402469, 15145030817477249320, 17647327914659401104, 13319573822063298508, 5205094261198279328, 9191043393335719432}, + }, + { + {12034745616655220445, 1806587157936901864, 7601847606478345239, 4533004298191165610, 3124085236761665559, 17389156053407331651}, + {2864989624008200953, 5136009810031599899, 10582433036693217288, 14931735150274274801, 10439401220326631886, 12677134576293396474}, + }, + { + {14650755191841474854, 16300166795758970811, 10649037273588294054, 7104270209860104788, 7967261075606297822, 7279561497784730946}, + {11697616288471532112, 1052366164901768766, 2912238129374155198, 9701834771332452417, 5442175782826775844, 2299045115469613839}, + }, + { + {1287332463662400432, 3513212364154390112, 15346209202263562543, 10855689071781783808, 1452088722357536954, 18071443086358423492}, + {868440689883949449, 1816852863222370485, 5199615657293991859, 9449935448458274470, 177207136542962287, 18245562675978917823}, + }, + { + {17651410429892341588, 2994246517539724152, 17728394019247321391, 15386586165465459648, 3241419904742758835, 8030267348237056794}, + {8435074151094093690, 524712275897055450, 6804195566995782773, 7679712373149113143, 7995287808064276131, 8927279975652841496}, + }, + { + {10778050409776497212, 9536627676531662024, 7658414011223352564, 12327599912454605669, 10735492819935528307, 2807151273987894916}, + {16239030609792653613, 10332717478474239620, 17257364018983708944, 3381279635307716914, 6577585621142376520, 13802487288606991045}, + }, + { + {17954497611593459666, 3664315036641118415, 16509024076253684643, 17283250569741859362, 14982375386085505669, 7689080851173975344}, + {6539602342283003922, 14623322619256010467, 2886392582253254823, 11318353402632029623, 1048960849463114154, 6823726223520193527}, + }, + { + {4530098428200707620, 12839096969967251554, 6198816293838808699, 14497410916805455082, 5464738801928006246, 2590420136286143409}, + {11539859348742386287, 6448283683032046535, 5190841120404297714, 12682630274691496068, 3502978196473226835, 12528396777891929349}, + }, + { + {3746596285568179795, 4244746780559722754, 14192133631604917518, 7971972442736154200, 12850431088842970183, 12924848893782277960}, + {6210043026683817121, 16093936346760077654, 12896762480304091787, 37796835925086671, 3297320202618582783, 16993735692589610973}, + }, + { + {16449417965222475184, 7693932127514324007, 365506606826317804, 11357852591741708092, 13089599889026601450, 16903400737548641302}, + {16984170724371326225, 10391779522684702015, 3067870164038615636, 14252841648119381798, 16218707853229586386, 7836241961586971830}, + }, + { + {15192483994066769425, 4516676767104334066, 3298548929696008355, 14149842818379505147, 7754159985358226567, 18074898548922930513}, + {6787600702315314002, 17427509000681768725, 454039934719798915, 6687725764533626315, 650049015881932447, 8174481017589685550}, + }, + { + {1190766049258248701, 16712766508257076609, 16011267443004798709, 4304976661940244179, 17401735122754430323, 17805491770899188624}, + {12819712409221279306, 6012470734633531883, 13202842728516275075, 6714649673431658519, 14766728086190011567, 12025005326013128366}, + }, + { + {2550442130803597746, 4388182498378820973, 11877916159578114240, 2491232568553766269, 3061633366263606868, 8930196601588700949}, + {8351158090909235917, 17643196865264803997, 15136059012100053669, 10435163437422615040, 14669662828147957267, 1927075496220718405}, + }, + { + {8522264882073051051, 1620578049778200332, 8273686191210510914, 15161466784984992681, 8880636972606501019, 5137083413106892985}, + {7453074636338505180, 12738938384123169905, 14134926144460829976, 13289026532736437285, 9961457855205231232, 16868281080316857896}, + }, + { + {7869220388851879053, 9243594331185701304, 4578820859414588545, 6726500389404417900, 17828060266225175185, 2805995484906762914}, + {8127865232957840490, 1119209698667346666, 1543121112626802223, 11635665147697604228, 8700384215304758069, 15110956032330707009}, + }, + }, + { + { + {3999765870898298471, 14172770317997608516, 15838808511345459441, 17483331932540195875, 11537545446428919358, 18161106008778308362}, + {10832208579815022485, 11144226171709861172, 17832358814667390783, 8104027490956075374, 7738001035752373711, 9976303985994712521}, + }, + { + {3053316092196908301, 14599294197004415859, 11376968891216184065, 2166021074759834008, 15176324388121041813, 1177183645238737592}, + {8872756236922047177, 12695199395087628448, 43719476960233138, 9968538827589652609, 18292294231863534866, 15247938318298852535}, + }, + { + {12542532240058205361, 7268582068935965299, 13539169522639613195, 6415306438194106780, 752732255800848126, 6467156824109874302}, + {8919765688158995394, 10376805730213749427, 3560797874989249371, 13765505640431451465, 5413502209131873679, 5479930898819906026}, + }, + { + {1620953412301746638, 1834494332682380488, 1221287231603861044, 7143200653970910387, 2142887614724373742, 515369627860172237}, + {668312192947122200, 14495573370059274601, 19053408511875346, 11573007294798838371, 5996919291690021344, 10963600343891369281}, + }, + { + {3772056564995867704, 8936213084537725440, 14741295503761475310, 10169482512429303117, 7395158688725827440, 10625709550842394718}, + {14145698620161177178, 2138174424797012712, 6382911437211835009, 9621628449746421183, 15318114188233644891, 9127092351657370481}, + }, + { + {7569439361788924386, 5358743744068588919, 2472617216924555430, 14446025836401453832, 15206339952764265454, 7985026553542652918}, + {2885368393308729366, 7662239829932173449, 16902869606779080248, 173909372728520956, 4745825384290840252, 18238389235634593837}, + }, + { + {17278763089415978011, 14648999284612290464, 14549644405624342751, 5242220935080712551, 1281695041546515602, 15620247700383069753}, + {6061717613096359788, 16094895295267398297, 10954605165474093325, 17036094738837097294, 17315827424817840310, 4006783343088127765}, + }, + { + {3347760495316022590, 18353910874341978035, 6043778301036432970, 13355724919784404041, 13015796096139756391, 12036177583658955420}, + {6518471179080804014, 17158842633921763658, 14405522311746951243, 6973400651137011042, 4746890325642485958, 6736547103097705136}, + }, + { + {10669366973839367672, 2385569531879845310, 5688157778456360570, 5432194657022107321, 12671178471488614588, 7761060866335594839}, + {8978451158519567422, 8492352982229672202, 16643425269116819050, 14671179713658552694, 4363789067899164540, 9370620302779212621}, + }, + { + {13310909055019013380, 9596076897475568893, 6086247547890141325, 6615089564251394108, 7111916614455620574, 11675908774987320387}, + {15925711704010954904, 1550153309190557596, 18423416479089687440, 2237807451710845475, 18354395799746145454, 5438928742395904784}, + }, + { + {4608572069409268399, 15073585230746724421, 5850493471469990136, 17178910933214514567, 9197442918599759710, 1507943865355025659}, + {10368207473957700231, 2360337372791198513, 5963074125901124077, 4250878605574616141, 16077767359709901643, 4855088307376525666}, + }, + { + {2203675397636717516, 10128211604548624427, 4835587188573085370, 7287969591049025649, 18068255218779265239, 17327995020974268765}, + {5719882824311508910, 6709568563671378548, 5291703009398100222, 10788191138630994747, 10408053012947876069, 17443305409665545835}, + }, + { + {3342016462643355321, 16679489257601825281, 12043384844586211843, 2115834496701139743, 7212063995634259653, 9441913556375417406}, + {7879272060659630672, 1322154690117373473, 1520558149537399921, 10259915503278516179, 3368650106971654575, 4144693617269779944}, + }, + { + {123661428923518452, 17329242377861899194, 2113549760254636588, 847106394960135909, 9954070461361301937, 15563438708607816744}, + {1040702637047883211, 10189161753028718742, 4009789976573376701, 1936488692781097326, 8873733742849194027, 12009079112311092681}, + }, + { + {17741068926415815996, 2460265563474934139, 1072480528377351648, 11885568366174373122, 275536108394716793, 4505994571681041972}, + {4997815718062610307, 7966342590073259297, 12194728418927987790, 7653673951695752977, 14783821829300070265, 12992716489185017892}, + }, + }, + { + { + {11640101960998639313, 15953805101075159736, 3493841973394909037, 12961869929990749200, 13933610253398336212, 12682152790147939130}, + {11399471237860797020, 9683858492545796215, 1548460573545589546, 7173998343795107028, 11677696610449743857, 8398835533776273489}, + }, + { + {18347627398589476579, 10477209504919905991, 11985004040168566638, 14212280469459055980, 17155809208164808508, 232842756626748023}, + {17663176896634111834, 11266862009271054832, 2801433370426448852, 5656158823188135309, 12410354059238919535, 2244879375847000921}, + }, + { + {3190520016779022051, 13246407962418081856, 6668351451725762413, 7768576717338627844, 2262028295584292801, 14381567562481981200}, + {15520621358714576108, 15362331656590194956, 13091576850573016550, 5790621552805149408, 11085966456081752022, 7995145398979072602}, + }, + { + {13623592007492989552, 5695669685400021686, 11103834195452561281, 3924874736262277070, 14749945062025337942, 4117578579179786869}, + {4942010861531575831, 1697597687729901180, 8378286745350822869, 1042755497644966445, 4609634700670610222, 1595371322671204226}, + }, + { + {7356907816961926000, 1600282058170066082, 10425052022355846482, 13802483414078059083, 6527010123231557260, 17014236698247006256}, + {18079966107052649494, 18199473573195697305, 12045755339859992655, 9377227322475274712, 4707316309742615490, 9453719605925386277}, + }, + { + {18077338856333540591, 10940855750925578638, 14676427357499773843, 7077022433649111811, 16481763083992802494, 7834705448306735746}, + {10145419701640226394, 16562141330625721365, 16626213781430570449, 17015973614586109901, 12442022173385031947, 9087600251713065715}, + }, + { + {14206474989889371590, 15241997516043179936, 10046960511573015546, 4012668500672179053, 6302607210097986007, 14073285009414845523}, + {10393845740118669710, 9303896053454113349, 318938169015454180, 16356683611313694376, 4951073049233679376, 8961912152048041842}, + }, + { + {8028335957857989427, 10757251699849982309, 4827184158706600421, 1972803202369040744, 10894855692237667943, 4915699847075993000}, + {2764904044867252832, 3759515232559764976, 16791991319742688688, 15982469402311953688, 4451160053970330710, 10836878114068503963}, + }, + { + {1898218734300846462, 1890052160621754096, 17802491502548108823, 6190373917215274157, 803001649590263174, 3115437408056727221}, + {17784493560265139286, 4722713594994619444, 7211558284311348923, 12566601502228621014, 13213147693274689277, 6593798376447442065}, + }, + { + {14162633535901746112, 13888434174969429930, 3406707891053136625, 14343716935895842484, 624836619325620495, 16396608622030250358}, + {11243183545197281900, 13435578064685298093, 8553550930687221160, 11901710173536269070, 11201351899495201574, 6707939517125993234}, + }, + { + {9276193773801045700, 5450558417706905067, 9450904291105895205, 9833917887246857818, 7285500844025425965, 14754203014686269594}, + {810778446780024575, 2913316233752324212, 5099291060376680008, 5738827727953191083, 9464181523940859483, 5936468513591129863}, + }, + { + {4878961831520826954, 14509215665191898446, 6708977457709037859, 12634291587039233323, 14051107097299387218, 1257131711299495146}, + {2944921399309621693, 930008782908430501, 1144887774944683814, 12070375620973983173, 8562905952672576547, 6655131226711101957}, + }, + { + {2899574573379169897, 1484714325759426788, 13026584324463930570, 7354422735718365143, 15271320868736293087, 16264371063992305811}, + {16407322345111310891, 8408499977463544416, 15290440212843619800, 17056597194115740595, 1666861996182883636, 13197583661824364865}, + }, + { + {6358774672677922630, 821442820597003176, 3813988636387892061, 6549290188660731594, 3924164508423783399, 10897312938877431610}, + {10853174774402828944, 11140723571860242940, 13060695462912345962, 14956978874467708930, 3205778154938349955, 4857627122623530951}, + }, + { + {11135246107897067582, 12930931433283727075, 16046715789896369411, 15407716337362202421, 13785191090068112, 14267330907406142872}, + {9630464474491738918, 15849686165796549334, 6769531647489555179, 14133844287397398953, 14941312803089108859, 2539509877677478606}, + }, + }, + { + { + {4519426578252664019, 12498635300136211504, 6321021405218202857, 726318959046945666, 13882007167200891438, 2395319726326567532}, + {14574068852065085528, 10190204462571587840, 3147469108386280925, 10820985172387594951, 6286320751972150388, 11262911446209261547}, + }, + { + {14681940503030753559, 845444804754325384, 17738750192032703554, 16488507045196756482, 11910847346995920258, 8626355026937911802}, + {18017945832199185475, 11050392025640445707, 10242360224530664755, 1617332161128003926, 14748788017604482554, 10938197837639769317}, + }, + { + {16523024021068053599, 14153734702399414874, 8975814599494295874, 13479798347939192877, 11858323547050135962, 16835135870848796279}, + {18442770255404680133, 6432227429946434052, 14626833122688941937, 15380321854072410541, 8513682513482878540, 17341688292014129030}, + }, + { + {9982750773031032188, 8982169985591678537, 5249265836220267338, 745482432716420646, 15780419841302462097, 15584095070673766359}, + {7735573468252400802, 3795411598689442193, 10306326103347347341, 14546148414040805838, 12297870683806673875, 10180646444691724781}, + }, + { + {12710315976002578004, 18013486904999737909, 15071959480643480686, 11232436041458243738, 11242505152758575624, 8836015187488468465}, + {7163797004587484021, 6976175793895240071, 17645939623644273967, 15778152496214427324, 11329126604565270312, 13110466004937401027}, + }, + { + {7062286409431630812, 2728146973991795543, 9706360251287090173, 17163823676653858159, 10108371106182915478, 15145658691257940197}, + {10397214263743326838, 16577575568682665639, 12639970963217473417, 17440990594269730118, 14950277950848187668, 17431952877316305268}, + }, + { + {6480066766050317343, 3568668077668658088, 13783844110647363350, 3962057444946379264, 10510088723077169182, 7170700020292960967}, + {18344863488775695783, 8824084188613580257, 6513472792662119798, 8283498389636157255, 2472052284746094828, 4520476222306731358}, + }, + { + {4812653469852902630, 7740257893595917350, 933590915187574091, 5367604661371230699, 11524926856934229507, 1547803982974742036}, + {7173249707714144699, 3782455439068354757, 3436775349109564743, 2186512130420632639, 13544740200729805403, 16975429410143506788}, + }, + { + {15877732835883777356, 5756653960126645671, 2937501458743429054, 3189115871611189466, 1436979939858552352, 14064609826654033973}, + {6211184029252028368, 14949803431947181926, 13070266838064658248, 12061247352423941993, 10971542374730440659, 3480209766469344160}, + }, + { + {14525709786341885047, 8039674455841380225, 12237612161305828783, 3099183041004087991, 6867967360204688651, 4823608220141329719}, + {2084876862441787600, 12090014665548950766, 3746144123408878153, 3923168966734460049, 9736629444481310223, 2220438547349139262}, + }, + { + {12036615988734629195, 16475002855996060653, 4484972141187264922, 5765002039288394851, 17063350421202862246, 13141299915467681366}, + {18175008310626520279, 16161757370162131471, 10768451552383046438, 17776643199179949221, 10598298165332627044, 15321920779815178261}, + }, + { + {11362509937560115945, 10576153459965418079, 1262608791982484244, 8810089598173523841, 12316042044260285948, 2268907115684739741}, + {11678522433578723279, 13370587091821540471, 9764685266488488043, 16120963353852178901, 6374843544537806852, 9069656632944802220}, + }, + { + {2566151116175682705, 18419852245029475374, 8482627328365732076, 85390825415125292, 15919801360472688229, 5270660089582520119}, + {9546653662379271343, 15939549011572950268, 14048762686232196880, 16243975286260758268, 11298686963723559385, 16417368127514338489}, + }, + { + {17555499161685523827, 4589562335151500279, 4172801013578954247, 4538649193559819086, 14507716041867679317, 15478474910313981001}, + {6017839036160861908, 4246101108460983771, 13629753094704860997, 5513007954781513788, 3904348220984245516, 9061778934720872085}, + }, + { + {15748938882069408756, 14277135008861981773, 18217921952747007161, 13344713176347262386, 17886228199837380528, 1540401873780123937}, + {3324086529084340824, 16272343370371044813, 742477341260013957, 3350915636385358992, 6792514656381585078, 8878152636708404891}, + }, + }, + { + { + {606092015174216516, 5918356105766628823, 3171854402026042629, 5083410488709721579, 3403581311288428367, 17676510467286289614}, + {2967008223055154986, 4440513410884574177, 16523045544893119274, 3217655037837401371, 13054487720522321142, 10034418456224208190}, + }, + { + {7347573045686808521, 8524339315025279874, 16314398830774990578, 7148576901562720613, 17397796952544351613, 12574968465368627587}, + {17127750532495035623, 7031729130299604572, 8389747942949500517, 6996080963912626814, 13495784988274569257, 1168514218006331799}, + }, + { + {3096433627791070893, 1860156442548924013, 15384249936468274478, 6818491582204214579, 16342638307737468887, 4369943414960054850}, + {17533478036417612037, 15025947594061943030, 18236676236976149572, 7039406316466350694, 15869565193009626370, 3852675700088288543}, + }, + { + {18309824205914080602, 6894088905116897314, 10591623158526430812, 2528539630082230699, 12042495883122935729, 5844044239001656400}, + {17005697103726708846, 7925252746001041067, 10999152033548088863, 9154176622465162277, 15084949920970423534, 5578598380515797128}, + }, + { + {6917179209198910574, 3886697537844862434, 18150496386873591051, 4972646778348909437, 4969661664166180669, 2872836128490559084}, + {2704398887171405709, 13639654495080115785, 11425684371658593338, 232369335821630324, 218748759902514707, 6158205593118649580}, + }, + { + {16496178860935794046, 15119575313167393886, 15571136778187380808, 15718174980588554218, 8407222631419874046, 3994751679816363176}, + {16137943000116730838, 649686844284716838, 8196756005862490544, 6988085908898901263, 8051931904212610802, 996284375053598207}, + }, + { + {11202012828915629624, 16434906580972492259, 5073784107975608951, 4555011077667954368, 15056393774484220435, 7153650342547995309}, + {17034230510077633808, 9529331632480295071, 17805365034946979115, 1306070794871122132, 11283252790245181700, 14195024093610616158}, + }, + { + {17062804313340314021, 12487559988166578822, 15223533012653521266, 4215428489484541930, 16150265079986093045, 5813481978377140106}, + {16065565784667247990, 11555499440070100600, 12227692665725509655, 174038838204068309, 6944904892485822829, 8209387774354117162}, + }, + { + {7097764295443365680, 7845963410214653920, 5797125233317311504, 17926005715153747711, 4229684472586339799, 17705398018071993192}, + {11024978540019744970, 7926106855153668317, 3165689713040846858, 1324462571872837789, 4092065205041218276, 4114073167420719940}, + }, + { + {14832234719124735027, 17720736763724642037, 7569347324614805545, 2422203898133075744, 8407080162538697312, 4638392288322278865}, + {14250957996942719144, 1268388636046597839, 5742106579831765479, 7403762642777718888, 10608168393433486378, 5148201736835738471}, + }, + { + {12017738182708598078, 15496109165938912856, 16276087896775269508, 14348251368567035394, 15495719802443424398, 2886769213483924492}, + {13088574881807814182, 6175259348987407998, 10240343649650858024, 2445547966947917305, 4412093101877027279, 11575806026599033878}, + }, + { + {1978949153914018361, 9333756199061121765, 2483677446328516905, 4947844288118935595, 8796341380385369544, 13376588153739423951}, + {15189671345805877067, 7857386656423263866, 12087267128677715980, 3124246805898824272, 8155860863800786429, 10855265042165217616}, + }, + { + {10968540393441817286, 4229948088947631485, 8845677625419290462, 3176865215857370108, 7460329129753473479, 16979518947567294508}, + {2509227000662036147, 6062006495041137172, 10067170914885555116, 17887270821175830326, 11296565130650766701, 7373311159946922401}, + }, + { + {8850120526955796736, 11314469582193677783, 1068054995241090552, 7318394094178466418, 7619360585150493559, 1453572552029566577}, + {17996868603041808639, 17518159987665308986, 12081491143590269787, 16972562088952683938, 9389093909820463685, 4548563124413215604}, + }, + { + {17046249548250582064, 7914728399210345507, 4240928990714296695, 14486835470503581294, 372290144157579880, 16839406978927405392}, + {1016866348257954267, 15113309936348826018, 6432209476523479319, 10269747907106890252, 941691948152294603, 14287414307327182997}, + }, + }, + { + { + {1272546058761547252, 13578575248362383071, 7500958990496300674, 3099202960982751824, 6362531162831059087, 2019233083206809658}, + {2754115770602762476, 17265393813973046355, 1460109499264827148, 8566701200794847730, 7001275408840316981, 8133565635966870191}, + }, + { + {4530800567522751634, 172100420111867893, 10423105592359647894, 5854403877381514842, 8749270627115121145, 3573817859696661904}, + {10641876612315799701, 13310097519809820175, 2575058335739178127, 1763270043880050, 13175676291469077040, 16171136871688122050}, + }, + { + {18354147526894604667, 13484255054412392853, 2800700506464137914, 11110366580313920102, 5646064147441879882, 2795616433118016579}, + {2129899893763421818, 4807666508003926776, 16472812490021449281, 7681490117554722919, 3438671827454179974, 13557284264475208066}, + }, + { + {5975319400755341093, 1124738826642685970, 16753728698306033686, 16494353205423996145, 18061430851006650946, 12807029835851374145}, + {14925084576890361984, 2612771955533652816, 8242017343741157450, 7403436780273402474, 14211525852367133182, 18439046101355433515}, + }, + { + {12522140250931309228, 2650365165363684707, 17266707117780681001, 17646854366183132476, 8242359948852550575, 4320679156333325465}, + {15229476123325427164, 422299931396282295, 12793864739684453285, 14299923645240128941, 9978405170065329096, 832960934203122298}, + }, + { + {518871060412814841, 15562218878203565824, 8980911201550345823, 11524613147177454714, 8894386144833336880, 8282385053468266803}, + {11036310375799843604, 11631323855952279243, 9204542676358250227, 9017637584223443028, 3369721496038149573, 15595900417339550003}, + }, + { + {4591440636846949512, 6036488867281859201, 16533349215338691556, 3133742230803728901, 2571899330106231363, 1631909183838142939}, + {8989734436763331330, 5978410296483257172, 2006955146568177692, 7522769147634649601, 10220842932346919807, 15597809501020248076}, + }, + { + {13439894621213745503, 9146006640549707854, 5648702331867490349, 11405536749919113563, 12230345710914827865, 10071652654740622079}, + {12555953518900584840, 14800100043573333557, 9904134836732167291, 7181207832363950334, 12514588099534090508, 15307927244603231548}, + }, + { + {13605621509983689364, 10781859117898335879, 13538880269705946725, 8371044748813843478, 3462400909078782886, 890871523695605067}, + {16499951906767373988, 10661436183202627477, 10666398637960730939, 12471664467090838807, 1750972772377056241, 7518131157858325250}, + }, + { + {10247949599901648714, 14190196306159090329, 11216722499720804306, 3590282982469992444, 4633227070625809035, 9190116695797697665}, + {15939242820763354667, 16077413183961690083, 6355653157022204783, 8580010924979501748, 7153725479094108372, 1357680516578643501}, + }, + { + {66627260421700178, 981976094061062611, 14088629719356601159, 18087879346236428983, 2519331146402108878, 14689662575392662258}, + {12195986880010891308, 68431921015150749, 3127083875017010141, 3161714979740429833, 12839293036406001550, 7341433216159877049}, + }, + { + {1065953584516863039, 15096288182389718648, 4172454286491200670, 18026295242507833531, 5078063585310882257, 7268157657978060289}, + {7875776889204835546, 10627478238674063372, 8099037147030128002, 3027823377924903270, 14915487051934001991, 15228458635498084487}, + }, + { + {18435525997497788188, 2784122541135616216, 9899619044143187449, 10187065183348144288, 14659596985883743461, 15442370538955392962}, + {17895314255123528958, 5201907198851189607, 3321003244006213256, 12358309570578006578, 16348924419530434982, 11908899161823776291}, + }, + { + {2996337363285490304, 5920778534715228229, 6118912118872553172, 15730295041050666050, 4957216697404822003, 5536648704019369663}, + {17046266803691791611, 2824215581505967575, 8261255744418562057, 9146405379237138408, 14347950681302095310, 16755353354313831572}, + }, + { + {2023775850404636364, 10364798591267796992, 16581829103891111877, 4554451792573593634, 725404179839321971, 11768827269800328280}, + {3438461944423664753, 5207909560991353292, 4151502141621601136, 9129240992387993021, 10289852383205392490, 4419823091950629536}, + }, + }, + { + { + {12192276596816111129, 11439584366963014783, 2713946508948792470, 12156092371372338197, 5082916671545533837, 9910663863905945351}, + {2895173316336063022, 8340424674337499647, 11728516556339912814, 7593958655663885127, 14349406256224440438, 10167298094102276396}, + }, + { + {9604776696424199962, 3890505023889250408, 17042346157821590641, 9813252657656690957, 3258804089827867072, 9204267042383472101}, + {7747649746653076093, 14320851129876639286, 3963186726043119688, 8387428722722708424, 10944959183156131923, 12376934458606855405}, + }, + { + {6374660930662569399, 12346634963964714147, 9701085914647913938, 10287390907227015944, 13392157278046428293, 12147807827670963406}, + {7192397644093650214, 11565761799483254133, 8650181311221997306, 17210098121268283770, 13830241999240110878, 5113645900809384231}, + }, + { + {15158945955863226945, 8229963785033500122, 807836554855297163, 1605387028888366737, 7953194974476541404, 9367206363171169167}, + {189311819502508835, 8213700212546178990, 6170317059714889580, 2177468661830227636, 15110619070491538357, 5283152492368065731}, + }, + { + {16607045468719296517, 2927802433169566022, 8424681719366218084, 17419326047422606150, 5999905625970770911, 6190744183228192436}, + {12634495609470650905, 7990399520412760153, 351497963881822847, 9308418808757913317, 15411526673945299267, 12287423269457077297}, + }, + { + {13180158784974106865, 9942520119447471544, 5134405864152878608, 4720032172529013059, 15879568571954680415, 12977824023383269741}, + {13377925830416234380, 6393639184729793137, 5830766798694674856, 18039280938728751023, 12060628440735138632, 7991124073272328857}, + }, + { + {2644049280934582490, 10000276111558865661, 304722485028140043, 11735908257972102216, 2166515612050129815, 13377192353750901582}, + {14726585142314469382, 16602322022612937022, 4257344852211444460, 18080317473257477535, 2135517644863233373, 17513835768414110554}, + }, + { + {8724634927100459054, 8808563927836495504, 7987949369395724856, 16530109834509215943, 3846892622369353218, 5202324697033273279}, + {6850156471545519811, 15616657543406258924, 5319309874170900032, 16821994765034133697, 11207249294481864848, 9072369915476840210}, + }, + { + {4789875659742294869, 2967870937886378114, 5039716748733970466, 13024655282622758546, 13532935784717493836, 9347203783138386205}, + {8437277641527033147, 7455819464204777750, 3981495148880689532, 17282508695124259106, 13046846599571196113, 911227421359412761}, + }, + { + {14260224171888129031, 18038330451640326075, 15187295489695980501, 6762914031777041371, 6164418084043959767, 2811459417788208737}, + {17735002493861412727, 14516376847997846647, 9469431640063725785, 13958475411167704800, 14313946757521744683, 820863393193999746}, + }, + { + {4594187992219349224, 10516014328076789329, 9634144629372521799, 12811929681753256189, 1612050195000098012, 10578937287722203100}, + {10753937463348294286, 3603138206444261394, 9977000596369528886, 12918098041632842426, 7822977537561576313, 9364821144993035825}, + }, + { + {18090855139103467087, 5666769360330456887, 11220391310171813836, 5925748024381680440, 4640306010653470273, 18420049688662192498}, + {1059075524163100205, 9669195064815845119, 15313725541560391108, 5852840239013352895, 13002771717222269682, 4779511585836627626}, + }, + { + {241470604732582689, 8576671504524153099, 225652023678227074, 12435872718858072551, 13214352155330021296, 13114666440706969044}, + {16229486748212187548, 17546920563101641584, 2680822621869368005, 9315236640170012245, 14213661658286924384, 16853567802071195844}, + }, + { + {9323859950832044295, 15243140817228794442, 16338128914658363502, 12809819155289324786, 11997169044878679089, 9354840640666247977}, + {8822752410054480907, 1693710795906789185, 3728007655785421863, 5709205642332505842, 12656439228195873274, 12902472130882922605}, + }, + { + {14607278468875625959, 7672085385893969446, 11489053104399436980, 9874730896233758251, 8525538217421482215, 13557027426716988643}, + {11011646714046465719, 5278340269600204139, 1189175061902172835, 15246577042271755274, 5610476507823471218, 643296281309723962}, + }, + }, + { + { + {6162274162111650349, 9370977122090552413, 4694677321413743677, 15950549144746715137, 9635784431169384220, 6961808095841628377}, + {2163304554817059286, 8135281500465815472, 15429903319242318055, 11931312695286905498, 8894858811936530766, 995355997076750921}, + }, + { + {12678890939214435529, 17417003843916143348, 13742839322904008361, 10152726179915321290, 734923888530823747, 1110609374259636082}, + {13691542854487986519, 14664730400527454719, 8718834560598843193, 7133813452251675747, 16781599914305742325, 8788103601345715167}, + }, + { + {17797423961269151165, 15688097913738577129, 7587009064470741374, 9652300434517855281, 10128814085960764645, 13054349291137249827}, + {13667863971566990101, 10673432944181115990, 5827094206620143396, 6099167371319575207, 14812954584184361536, 9860618325640310042}, + }, + { + {589591245000469796, 8979433141915604381, 9021800314668643791, 3750105644114233003, 15670991254808140563, 9806671408565926028}, + {2465691143012527725, 4510267491638521072, 7232653231694705753, 14855984652990117558, 12634578316903510172, 1228039410348310529}, + }, + { + {9068020286559576826, 12618713895631873814, 11722393205397692351, 1086070536693193852, 17324321200170762004, 611028187223175838}, + {11651577700459617322, 11901409630642456359, 2085390425394188987, 490403321567849835, 14654293622476130790, 1298964209197946604}, + }, + { + {11322550018095596102, 3527572794553440421, 6339011792028948225, 5151642471735201045, 2959990528935484190, 9272589623358955444}, + {1016320821529073770, 16888052482282045242, 17688112620024597894, 3719928857894020285, 10396159054756858238, 3233119903385274118}, + }, + { + {15749902098907230753, 17763545669244090771, 9755900373517498480, 4320948179558902844, 10566924725356292516, 6116336473010794202}, + {15545737137436862310, 17240371706149670924, 11955643308605230982, 5932841340555536241, 15279500761826801442, 4179996491012197595}, + }, + { + {1552613943182547753, 10840747323421940067, 17328467336775183521, 6802521766845552195, 8626607143686909840, 540795511127208201}, + {15256703109378673438, 5812944466862532241, 6124501523506740441, 513175402986879460, 17434632082742815254, 16069187481501759225}, + }, + { + {8244487053073823419, 3868641351473260462, 2153712666785000554, 6957836165836180397, 500618765615109373, 1238832243704171799}, + {9603490361093858122, 246830756783484378, 2787086006655910133, 3907320948968255488, 14281263422468298103, 939723834433893649}, + }, + { + {6284765599251061063, 16534676857694838737, 3061690289969396130, 9626162384711348108, 1365881874432943624, 14727198041537453743}, + {8889264123676562961, 9777083175236297205, 13215028356698003407, 6986347484245421817, 11678122634649892302, 2435055587926500790}, + }, + { + {10396608653122814276, 17008484250005639146, 6318409447149262851, 7802099541170520164, 5574615603329953919, 16385780123891961969}, + {11134920568042011673, 12640687912091679512, 1146490453403655245, 3102249330058753539, 4095988337115400384, 17335158718433609549}, + }, + { + {12864499821393802475, 11788119049228790088, 977799416909835541, 15499421488379367188, 163390536177699522, 6804786504683418696}, + {3095872826752058595, 7223570057465222827, 1387121623948247335, 15122489364022134171, 10885423363329551545, 6434450333953245952}, + }, + { + {6653769292986613967, 9168736013794357965, 2104630911670700434, 8244457909216763431, 13703714178493743166, 8218306853052367309}, + {7189028979195471657, 5692750993768367394, 6844269123871604359, 17538650433906843042, 2579405218304322009, 2297663885759252861}, + }, + { + {12692054479125812992, 4320705081611888724, 14008964009638233826, 5334393314224233638, 2696459947028270454, 8328775412419649518}, + {5889525878366957250, 11336536538831724301, 12024875252935715642, 3494686190602179160, 9253138142565030267, 3528435954014636439}, + }, + { + {12648684265556130294, 2074783917548245950, 8308495191421783004, 15790318216073206594, 387051048726917672, 10990928722025444053}, + {15969688555016198304, 13762652978883154272, 12850841387412245400, 4825302074606748639, 2432583894467418376, 9326934178392716656}, + }, + }, + { + { + {18031089708973353209, 2245200960251079511, 480259352579296652, 5296730028561240923, 13672097544022918942, 12074013283516969918}, + {695570325720907777, 12417118176840300328, 11125216762475259777, 7694756262905475485, 6389856663806076935, 2023651462558938155}, + }, + { + {3716913865293623832, 9519939044782302522, 1190311626040433621, 4122386088785812252, 9998628051763276281, 6762269968937642429}, + {9861199249890354064, 1243120329240608977, 12074892082479307233, 11448174216179350137, 16878357486848010894, 14263124486707469927}, + }, + { + {4032144724607143660, 17323710612966320098, 4113668299203613008, 17685219225377287708, 13802533048264874636, 2291580023602316722}, + {5991918412653581128, 9413531453038680232, 12039010584036849554, 12779724028748234268, 9334132880061582927, 854018423284649885}, + }, + { + {4279036817315949205, 10908936013777057682, 5459140224800461056, 5336329855941119274, 13817174543987505002, 5803329503585048266}, + {3098013773573646382, 794466548882446711, 10937734087173941890, 10649767122328016589, 672512432710857443, 4439506334562330966}, + }, + { + {6150189972540442038, 17499024099306121191, 973920649937779980, 10819201450198182582, 14435306386254208142, 15898445937302462823}, + {17016479119212840445, 1987134867235671218, 3749994341137487979, 15521454315121012289, 12198185585065236535, 11161746347726704041}, + }, + { + {4108277248035082323, 4763145889189955538, 4083190563033592079, 13055163363599987027, 5746298306966204683, 895046093136418450}, + {4049236010637090060, 13099192881343834296, 8562023198967118756, 13994928855290033576, 12876191625337022672, 15993047528545202523}, + }, + { + {9330745605186235732, 4222579288142143178, 15252637539981899624, 7567380934463081549, 12741264148440889833, 15828019440897091920}, + {12723327006361657486, 4018078838231227180, 2560766106207278510, 13929068044020554063, 4759749660422617144, 1918410964088436476}, + }, + { + {1401229371513852474, 3725211280317699620, 15262967864528722679, 8998318469575212442, 14884830350906617811, 1500695608507126549}, + {629292347007891015, 4795086203008477332, 14482270326941440934, 17180742059572498031, 14991047340345822048, 7320414524005582285}, + }, + { + {3761423041074020566, 9183947159053999516, 17327960252130032123, 17936746435648093112, 4957874135698491906, 18381419405600408140}, + {2021552462092061162, 18293561973713757720, 807095291604235614, 10694367035762253443, 12210621028072312159, 14157551998029009312}, + }, + { + {8253770234288769934, 1748567047436239326, 15113806840556405352, 9849305728745472726, 9352106351313265444, 12676746928135649012}, + {15910355313240486455, 18316120463051771221, 15406553262270712153, 14120304384949032181, 10235649054584170863, 9663403668634321464}, + }, + { + {17566890036357409279, 8153035355283482148, 13497394635071743235, 9324980713264281675, 1855752933438317130, 17353271655839803714}, + {16210618120406652642, 1994646251130732955, 5626798068584404507, 5598549692563786678, 13865783001414878683, 14643387061407936303}, + }, + { + {6501357512501439891, 12176708815869008686, 11994352389570659317, 16086293893515238232, 6781571500932791296, 7749985836495590529}, + {7267769773480576098, 10519122498445425561, 12426530300337493483, 16904464207183051533, 9655317422890141240, 9006359300493534956}, + }, + { + {2379896081555791674, 7529087855981939465, 17515505484370387645, 11992060160533269066, 9874426908749159085, 9612679919749306188}, + {8727002423244992491, 11651910302226593854, 14317531382092040616, 7148921073820945054, 11509981879876620492, 241425876025527115}, + }, + { + {3957931629992459039, 14626193761179440029, 8968065435170182499, 18306857838363825356, 15388760608247994094, 7556220454574081940}, + {2830354800601290284, 6007093254955226710, 5776847166084925815, 17411399255750975735, 12948871637122999099, 10619688187202777033}, + }, + { + {18019620613881262245, 8668018235864297559, 5360445581416845868, 541567173296101055, 17792105755090691444, 11386151880811930327}, + {14234180784132089596, 11582267640018556498, 13014702559444465145, 3629111073015327967, 14739462952187775393, 10310644470035819364}, + }, + }, + { + { + {17403833916326762122, 9740094979480827357, 14548670989847645635, 15707508983563938391, 17654070414772907819, 7410646283891180823}, + {12088151802847404486, 13751887120986972745, 7133572866312957805, 6984144881486426141, 11478362218013196569, 397100930473218000}, + }, + { + {3572843614659695767, 13917566193783723224, 10106991008395751890, 14776064316406512486, 3973284575540205963, 1393548331195253411}, + {17728418700244338613, 3569943135321046585, 15310934114440659327, 7534966422523126315, 6695235484066733707, 10654160843179249647}, + }, + { + {3916524477947621683, 11443354393618774115, 11759119305556384367, 5213174624675660124, 7949463549546931828, 12092151641941435863}, + {62263562580411942, 12003780754220372116, 17593048334196024065, 1486928429974104945, 2382231722092886579, 2435498065565847060}, + }, + { + {12823154059116108213, 7988070353263431872, 5238951896699939370, 8132043978344570215, 9775088878106588256, 1118856390259997431}, + {18065172735230934036, 16325872707906562424, 13000039721574339202, 4312637592102231069, 4902470028754124204, 4272784360331042739}, + }, + { + {6433126302697049134, 14546898608004289942, 5143458349243895500, 2287546739351655153, 15996486027454642710, 8035174736863426329}, + {18381568106804023303, 503934132851985517, 5955511571426124170, 11588909349656865672, 2539783010592793715, 2517368635804605002}, + }, + { + {9688220347159635445, 3779168584047736134, 3386170765747188013, 10056695776861610791, 4230378171552673912, 13380959223891516403}, + {6821607274732022337, 8369692960524296435, 17556137452703259897, 9913246146396765840, 18385056826905781741, 595789229862790596}, + }, + { + {3376198520685928255, 11401697177155390480, 3837907196036866447, 7783605697094735953, 6911185458281008352, 16661582556490022446}, + {8898449499666876128, 12720029146151254358, 9180900453839682688, 16904557421585200609, 3231736335575648393, 13582984509377915948}, + }, + { + {6335991962752687896, 13799946527490837369, 12932853903574384992, 15301891419692833364, 7117580415677557079, 1638243357400401907}, + {12691541233696549250, 13069535028987414972, 1561175855442316177, 15953947983175737946, 17433282081462277288, 17805588449174971002}, + }, + { + {14830787803333713689, 11568262452331360318, 15414418121287856547, 291893575140657361, 8537715289723658891, 895041535012667546}, + {8735575073330490257, 7904711333758081192, 7705478766063086839, 14966128571780877610, 510498342305674002, 5375842717792934507}, + }, + { + {14017553865950425970, 3203585385790093320, 5960504993013900991, 14499792127339543400, 1042520134310564369, 9007730864681746336}, + {8155955287049316865, 1168268403444813838, 8223462980864298646, 7046058388874344827, 3806799754540117714, 14310126916845550569}, + }, + { + {18101015319769141333, 10981175585883985115, 11076843211911188635, 1865376526114106685, 7691555534771124483, 12825758162850881889}, + {12705759021631065468, 13425295730593551151, 2454066834990145158, 7398456861539482216, 17965437387228755239, 4549246519638273011}, + }, + { + {3564216727206350471, 11502367821276581491, 10888792934596534614, 3218935969765398418, 12592775041500777408, 11647588572015935744}, + {2922640897322707689, 8613211193560218045, 2230968453901036138, 14376635144218060540, 16773708514752577950, 17553690068355938998}, + }, + { + {12898296153065645455, 16720692735856066113, 327172655540413761, 13227218237345565511, 8519416956666328535, 9006180558080542517}, + {1264713729050345984, 9103896317460059276, 10413898570640954633, 3676401446977680326, 2935706012419574846, 9423939538748482172}, + }, + { + {2350781039643192469, 1693506343823609927, 11077706501162430667, 16417164483905858926, 13333764386693653370, 12097153330368571478}, + {10940849199388401790, 10597622934633620124, 4717517384091986088, 2104650762579463668, 9840374844871408095, 3483317510992532499}, + }, + { + {4767861261398259198, 15300499894768898507, 8688456959068450491, 16604170046623753993, 38066602101631568, 8293371963850926780}, + {17963446985501477796, 18444654321008564037, 11760177315245860872, 1435879756649854235, 12050871655191687758, 17344630493039043282}, + }, + }, + { + { + {3096485884016777148, 12376984002139145052, 5480443619638874966, 10095208486451434692, 3492940022953765146, 15299835252568625902}, + {6007593829256808804, 9692621867284256874, 13254638193058937432, 11707277530365540634, 16923342671634580125, 10732664863951753047}, + }, + { + {13872582197972895881, 17193014938795396512, 15971767134700759136, 131681455406226309, 15729877667343662624, 15250608391374424092}, + {6602138623471383700, 7643740135412054049, 17664951607321499035, 14599694205978771523, 8340737952520919285, 10584728957567182276}, + }, + { + {4029925504600209836, 9230486924650579139, 12709630435517017856, 16752856913747515048, 16091176512252055807, 5654615991864890349}, + {16213912518103095615, 17398694063688948608, 6470301373189861265, 12049558432878948403, 15731102283993311220, 1974808235304593120}, + }, + { + {4216082854210318654, 13783625863031842952, 14228148352427104722, 798223135284158372, 17371302655925227458, 3868945640945033607}, + {14496156719528803963, 835017877332649412, 15738356549194558199, 11268806386543436865, 1609600006680937174, 15189642421218057250}, + }, + { + {2100911419510810891, 11709730967811792326, 11070968852465741080, 15167667469791505342, 6990446430502772064, 2979739266982579384}, + {9729924531656485522, 14538459181363709770, 8953107760739874488, 15399265283602391297, 2640851218253403446, 397493120169971392}, + }, + { + {15302726863134446614, 13492823216891695902, 1527459733416593466, 3780183339959616960, 646805679119326182, 3572065085993834296}, + {2086050242579936958, 16097128196674610398, 11110917184928300297, 15215051174675736281, 8638996858467536364, 17498051884481561986}, + }, + { + {7442054194398722761, 5899037616301380264, 3602141627092495462, 12455087214158437405, 3316146807961356474, 1301937084617765443}, + {10089073892535620144, 14190065028184329721, 1808236899842351791, 4533062878686621914, 9993862131126637828, 2297009856133766352}, + }, + { + {16801618217516611581, 12059439895460656350, 8598727314831164546, 9586649536512297470, 10941296402181826520, 18191582771052788270}, + {500755738669776861, 12757213489859603192, 5140871938904556861, 9617812594256568652, 14076395917678039824, 9994140370794675736}, + }, + { + {5850038450443732235, 6375066279442420119, 15818683872880571739, 723472722199022174, 9333015052679795537, 16719493839402031559}, + {10024247267249865137, 5868800923297915890, 8041157937570474814, 7928686841256858707, 3370105934450681139, 17883122805284898817}, + }, + { + {5382144947237128088, 1043006451545558226, 1681467077957939654, 9517495454378300520, 7036177533948513894, 13161967355521737889}, + {12219093509482945494, 7442193295382785217, 277712888488640722, 13947546222291113300, 12611485840092686485, 9710833655025677113}, + }, + { + {12502549552167234190, 8232125533311903390, 839854118279680892, 9485775732822833984, 17663390734822952749, 9394764657882708830}, + {9000572432647298775, 6908017511163909222, 6513180860770299323, 1139498172110369417, 14568474154258358741, 5050171222169492187}, + }, + { + {3993332219625203427, 16865359864205374644, 18194512585980505134, 9613014347311695262, 16860790576951889934, 15221161996871384983}, + {15637827171909035878, 12174768900796615919, 10654832940369855667, 2582700277462133737, 6776356767890276075, 15022166989559684534}, + }, + { + {10674226674222713381, 6640126227278302401, 5685415511245921812, 18111307322717025760, 17086035813631913574, 15847356748945327676}, + {15174476977121907079, 17856987969624827110, 16167616169413150302, 1944283930257068430, 2453038170129818707, 1469204933482392249}, + }, + { + {18275102898719666599, 12983079761412852970, 8388106129782060896, 10209355387576245223, 14538158393256278017, 7560687135426084382}, + {10553905131472339745, 11398173317153206213, 13617408055623208259, 11532011743299529667, 11538247191420015587, 5623160693645531170}, + }, + { + {8940662681574827513, 18164959107927468123, 18046552638532109884, 14155453048592004567, 5584625548584318353, 4723581324777545689}, + {11184722677308218083, 3999406699031629777, 4988145712425592916, 12203913929517294737, 9784288473101397226, 128198380995960707}, + }, + }, + { + { + {3863173275874957588, 7607368433346418538, 3446917342117543093, 3102805528911016504, 5796298790620582886, 4845029410873700374}, + {3364570708230969314, 4211843997911050357, 955735840518088540, 4382952718350579495, 11151776336025623039, 3248067064518007812}, + }, + { + {10979154959051140455, 17057489977844809380, 4636877136932368853, 13173423356700842378, 6427295314745268682, 16166484199425823600}, + {13947498680098198587, 9565058221523432140, 6724059640029046123, 2606510272316346451, 14817173045790080526, 17921662463284944192}, + }, + { + {8834547168849238776, 12415387183251468175, 1535769784386765604, 1355498814697642747, 11825072756645717040, 10331067826681906891}, + {8890584623925299707, 550918406340532812, 7338316217644779781, 17543638401057055929, 4365113997542215090, 2411169740153090294}, + }, + { + {10112129279069371496, 11405549101446425766, 12461696963021780427, 1134289511017689360, 9417819820453596293, 7597522379563535727}, + {2074398209324320962, 961715655667925180, 5962000230359126827, 8547804373478236252, 13432658671807283680, 9718385789307084154}, + }, + { + {16080785183875764467, 4017135721666879597, 8974124072605099690, 6665445735103434589, 14756638402029436542, 4331542523722303717}, + {1702503223444440164, 14189603650236390274, 971810312712682183, 8049986845378060800, 7330150922533173899, 16296166314284869572}, + }, + { + {9526769721404560092, 11775998161420767448, 16356632323651128085, 8008696501724706815, 6341629823262057063, 8523528728189280635}, + {18166074208498206728, 2229400479403638901, 5403004557542136690, 8487804674759640484, 3159160659687043477, 5700251865341103945}, + }, + { + {16822522037639219170, 3266418131057286997, 16472577174486956897, 15819423733871391528, 17594326634646650876, 4931927040440301796}, + {999336285551238701, 3401843156036868997, 11496979962939320412, 15550337525570953734, 15845745790852081340, 3342897350949791243}, + }, + { + {5808162251213383712, 18156856773531164983, 1937517322940695286, 11625411969327328360, 9824825636580723903, 12658592751635829899}, + {10492457110340784150, 15080267389153378243, 2728353556631119200, 14320292562386508753, 13490107143925758180, 6274827431709058227}, + }, + { + {14860895913867154489, 10080650032026459432, 12807414385133112117, 847324989654678215, 13613905648479118356, 12400016944146011293}, + {8776013302541032016, 9925887754260000908, 10894174981766535805, 15297900474855663929, 7442689517452234839, 171834335047382038}, + }, + { + {9117588627465418641, 11168331531349603535, 6924358652074850811, 10618700262994212668, 4103627941911888613, 15694811739383802290}, + {9844066545684783246, 18166608448724723735, 15930623463970128522, 16725459693529035690, 2783599048829322892, 441632469097465516}, + }, + { + {499123733301815599, 16274441320546608446, 8669188578438459973, 14214738178860124031, 12485272536092776327, 6746102886227516887}, + {3968023548712012438, 9154853401879925537, 13974983377028591333, 10516947431089663290, 933442150807932151, 1500788281533481018}, + }, + { + {4586047615512747332, 2505846476262500922, 3826876063100299053, 15762019359435942125, 11799323381173767446, 3568265576213353380}, + {12738065238480311575, 4804303397040398585, 6942032723664133680, 14301007503455957988, 184861059208060790, 2126913780868224063}, + }, + { + {1985910238562893230, 14542760065878644523, 16833470122497892859, 6947656477689970299, 16592512648364063018, 6357361689814456051}, + {13200391207691971905, 2310116023035377028, 5508896705935951006, 10187259410896817897, 3059013399060322780, 5209073312162680293}, + }, + { + {2550642766496181772, 11278535109027313473, 3879516477095166631, 5651059749761693924, 6360530625026542850, 8678055154702639383}, + {9895197927639380575, 10283962157020530930, 15939637088764924497, 8554801996782490495, 7371475446643610469, 3583344374097517208}, + }, + { + {17371412619585132655, 4718601666750293258, 15975408209741840969, 7108377055663708997, 17338928230506045982, 14627100588346057122}, + {13528723931279394499, 12515391311856549312, 14781282577544396450, 7264023353215685261, 3375932768360087636, 13881393850792083407}, + }, + }, + { + { + {1721448973177947457, 17542277325179447353, 17937558459976980552, 11205040461324106686, 51740205411633326, 17489989809778293662}, + {15829483165674242202, 2621026715167601087, 12151982072969161717, 14118259735069082779, 16359059099859035748, 2645875010407964904}, + }, + { + {13044315376543176345, 3791987176391770853, 7257315148468660254, 7615181808332653921, 34885173241256032, 13076418563936506107}, + {2024041865836120065, 343217496537691538, 6758070881563975561, 12527712552092021226, 9130227670558521871, 15869156873791479522}, + }, + { + {16624820076559004073, 3290961180687832086, 1505111348777534793, 15451932960818385994, 4885700112405367154, 502473235663078197}, + {9023344755595914819, 1119495374695090045, 13125353132125365621, 4582328460786968359, 13153243053399805058, 7243196921351431637}, + }, + { + {16660609005075089706, 11456541224374281812, 13813535856291553219, 14877518040804369021, 15861475260704681751, 3089740386917625556}, + {5892458763715639755, 15267181778302530854, 3988849050539397794, 10518710330883699493, 17431760984824214042, 12598607198625858948}, + }, + { + {7886366245642682083, 10962884476823348220, 6709711326774074595, 4572918043062220701, 12755952895112236674, 4061495514143300363}, + {7306556391215449886, 9599795224615892204, 459890930081394149, 13715832153540946078, 14440301411429777271, 16495857007705672763}, + }, + { + {265852797146271341, 11386341344328950606, 2823304281998980676, 3128543525090347743, 9711211560804927151, 11699179803002767366}, + {913811348561539832, 4079387039854771378, 5786553996132212662, 4783085098376699354, 11850032584026193104, 2507234732008509693}, + }, + { + {1681054977850769931, 14671156085086914970, 16232677545813708023, 10037013912612964578, 12655886518994362601, 17930493853619313277}, + {4261930640340402336, 16291971428751843912, 14124714297167598319, 7116061430830749554, 5140259185669271312, 9521500824814628533}, + }, + { + {2133204265371102168, 7738424860559779443, 9132973083464203079, 3624293757540177213, 16855385106148764582, 2981904660819867362}, + {2221031423918751149, 12840489442672309770, 12668245131095936710, 2439831201753391314, 19103421409345804, 5682831538477921588}, + }, + { + {2740210992007145962, 10621702461750253547, 10508827636006320761, 8248704461968714321, 6168928611394207164, 14048196011297482761}, + {11562029679319191839, 10199382699007278950, 3360092486992146320, 1463128897560010163, 6976632107921480266, 2129873557666907110}, + }, + { + {1100325675403567262, 673625074442631877, 8514591637299607269, 2345202943752109744, 7167639158345336267, 17342690971659777406}, + {4862595967217912581, 156590070960043410, 1115171684358334313, 6101500075575877531, 4062560666972498140, 5927929705820198011}, + }, + { + {364176692174332883, 7738711573998977497, 3727117924922648734, 17488404453005608305, 8507877372628529188, 7821485339424482447}, + {3407079555113142839, 2821844621824294453, 7117735201903766861, 2746395978318799182, 16096929564195692367, 443983083263483317}, + }, + { + {9618959095759532752, 5009109919584887941, 13273663751866897132, 10020142088235002186, 8463814795688208512, 5854890718933975039}, + {549447413377699602, 13361664826453471360, 4381643613995465702, 11048937580044016933, 356464625333949552, 10426821157046820998}, + }, + { + {18186037674911124153, 9266904366881705693, 1746212978216662911, 16297025199546965112, 12372897714118201342, 8586503557066603618}, + {10659723169179230020, 8331742669536916843, 17458121139259655844, 3918785045029490546, 10947551116738566182, 9999088208920405141}, + }, + { + {8354650412119672244, 17175305374472306433, 2829972105586097490, 10426050169628830453, 17159563166759848715, 58591768570097984}, + {18406299714417692335, 12546352398212878156, 2495694500244923448, 12073608360379166377, 6610894508561660367, 11682997196017168294}, + }, + { + {3210207744299112648, 13875413666800710915, 11640078075030694173, 10454397255148356013, 17880871075693128223, 7359039635726487892}, + {4853115095464004720, 7976333879782734047, 7694722857965415540, 6036769361724001263, 14076311434771587877, 7283323370969754879}, + }, + }, + { + { + {2614353155557682937, 14058591604861440576, 8309144349698829255, 10106897547146685772, 183429285024450792, 7660674933291714098}, + {17722010084076500734, 2099112471522046187, 3527281458003781480, 14209273751181102104, 17230024122478409574, 10483334506136982748}, + }, + { + {6047132184189720819, 4426654828692160218, 4329633098905519796, 14236543825083707690, 14077477151979085718, 1291177900283865316}, + {12977722282683448473, 17497194838527230928, 5763750732808676924, 9844068727688186332, 650882686296875205, 16353023628194028517}, + }, + { + {3571331741751811067, 18233407145253967397, 2182689380490249825, 9862956875499357585, 4101378667203447553, 2434938326871008100}, + {4975383754309760613, 3934729624717234976, 18322513804399478400, 4995364561535811634, 4754224073033422626, 18130942841051642409}, + }, + { + {13897652105647445247, 15549865991927044469, 17587166399757083359, 645157568514571702, 756205085560500677, 14733833165754071077}, + {913239358738001609, 2071269782500914614, 17073597609159000389, 944355324501816969, 4767516640133819639, 7180502768526971577}, + }, + { + {11871454882320947778, 4076335602405372571, 4747500308730376335, 18397169244778911221, 7987453080975894942, 6950688158372586713}, + {17368720469534992117, 11740301568583332137, 15177273953729130117, 18421847781159349697, 505562344182069757, 3704550989049269178}, + }, + { + {11672240582589566888, 1108540908548515402, 3338717371374145046, 10460877846984614452, 9211584971186313940, 11952076760337213457}, + {7672641505116403277, 13764930264603220483, 3744578737514393421, 15724456999421097869, 13506821640767565708, 13538891648668593334}, + }, + { + {1050281222231361612, 8994982763868301024, 12355411974171252835, 11306931529620801092, 5865750322856587361, 15613850005955819172}, + {14398943333497272142, 15112832726445460775, 9983052759258731406, 16935356055040242837, 14203640081769534446, 9130644307291338833}, + }, + { + {4953908352693126534, 5062976277743240918, 16505639315575105155, 14534500310766348303, 17944736498552318640, 4792459954642443738}, + {18252334781095086320, 13063263503472794652, 13198172387261578292, 1616650596611064703, 15181924039569157445, 5150232158682339336}, + }, + { + {5624679813550782251, 2451770210293674414, 13240746159856752674, 903265396767255440, 11078214582152861563, 7261508578820008638}, + {9752563467317727618, 7386516386070528758, 14793037822648488271, 5090452706673272192, 15308894744012067286, 8130767753744452857}, + }, + { + {6918549675326654825, 8356548187098615599, 18110842889094676823, 3963339850475613373, 6987554242330845710, 2982471659740542895}, + {12669841747723635164, 12626688679931160789, 9018528450701894905, 9726597985776847011, 11318736602457760788, 14025138192598645150}, + }, + { + {17505324765173267460, 7096407019104498095, 15924951709972151945, 16257204011042132345, 4971672139719859625, 2321621670487320814}, + {17594404375116307560, 4647612677109579503, 3901300263702871151, 16326292626815115333, 6831256398102532757, 627750677080250535}, + }, + { + {18076088553817290385, 17349449293663683793, 11642446393364288036, 10122513438385611555, 16537537641493131433, 14156371894700831240}, + {10743408581678488725, 8483948758453680699, 12243160245743380209, 1500764398487579885, 13614004849488464930, 5994785415308094372}, + }, + { + {6122565183919808230, 1008209506550806598, 15249625726527344206, 5096898832984665512, 10958457055229538950, 14428643543814058899}, + {17024506398778167044, 1989641393139458938, 3538068469415906392, 7351031458262333307, 18232141335489091166, 101299571031811981}, + }, + { + {12540548462618170712, 208754347981855850, 5755714353878203428, 13810850252670464562, 2144696743162115760, 15602160948740024567}, + {18186995987441524090, 17284490982574717647, 6768470157308652643, 9315159601737265015, 15486248506383436092, 4135862452814063276}, + }, + { + {7062558030802288283, 4151046583133123194, 17296845417413488570, 2939642080257680057, 10681059010204949305, 5154176607283576645}, + {4961584994822815984, 6524971500046141586, 9968235534650293072, 14236553626523573525, 11581675440714217403, 10779043421926068031}, + }, + }, + { + { + {5704148093399535513, 1982201820910068915, 2015300701102890863, 4938678016782651685, 4225735698935095441, 380627551509963002}, + {12290756922107972790, 14689334170111259003, 17081591129898655804, 12725711463684644427, 14355859294197921899, 4833292303349912353}, + }, + { + {1199430367393420777, 7844876978855113240, 8362429417006246806, 18405301817567609597, 2010437614964189103, 15790163337826190044}, + {13172944002680008407, 7545247538771827356, 8799495964430321755, 1636508240176095806, 3688223623562214043, 5001180399862075810}, + }, + { + {9236682024243624347, 1097419180975135931, 16930071776861614326, 9425037863420681425, 1897777030645415141, 14923573308348753100}, + {9048832771935393542, 16495423457575818894, 14651297528469675829, 14681410364817210043, 6270262408162655998, 3202527036040014714}, + }, + { + {12148128553462546338, 14272886082678845161, 1998189262058231244, 3290638835546848685, 10974691513020291898, 11300741189288469923}, + {12102666221723151731, 15168969616238080084, 7571411875816772674, 6708095321534436923, 13842254475238776074, 11645310689961969980}, + }, + { + {15206355933923800488, 1526822957768928677, 18444342976893277734, 18290836660807940588, 14597401039689350006, 2191517853826363150}, + {6631276040465224272, 9608830307927194622, 13173894809175192722, 3447459865798044953, 7473450899969070648, 17538173612935114726}, + }, + { + {2545753328201935179, 1541411216554356934, 12430899315303981226, 16873953755863768968, 16122659417628515478, 11719197339014743998}, + {15840812009819945279, 5620933673682798071, 11726809338101868835, 10020394952939578101, 6417033277605415646, 1193962146484927818}, + }, + { + {12699385012539356648, 1074729856826138284, 11360834127412011973, 11614291784573969284, 4629063743007127923, 6826004983002907114}, + {5533842397602974776, 5380622214800401295, 8077909061924689270, 9153034190848608609, 6198536077171060590, 10840145921066532009}, + }, + { + {16250603474235152690, 753654051241256788, 2265085864511952533, 7827038858733068367, 4327850715387046187, 11399515242612634708}, + {10497059724291403883, 4688252136426618327, 18024770225850104963, 15437873549837467773, 8363336228498661948, 7727493073571533637}, + }, + { + {12358979317647022406, 2405166324543341567, 1131516171615394739, 5450907798304034460, 6666818116269349649, 5855256214551082397}, + {10663129043987590669, 4887396919880469663, 2298289197437656441, 5676069638451158212, 11906248580355770142, 9562940725527931031}, + }, + { + {14844739915543480162, 13246961953132764518, 15443922107017863339, 17591911221252177558, 14809121152752475646, 14938006221572424065}, + {18293125953571441775, 3365272595752907779, 17552372285854513998, 17235054008682833997, 8690722712832570147, 13050282119073535772}, + }, + { + {15776540266747032014, 14852977882697304855, 12442551787887075800, 16222199462276877546, 1348770173344153190, 18330160582494566789}, + {4685257266073614758, 17629760902250811736, 1099686978395867610, 5720148750089389598, 8752939799218942652, 12653117413452417188}, + }, + { + {1928524914772854786, 8132034417591551586, 7951059682269625334, 2812108933072612507, 1596610641421367938, 3496321797212562056}, + {9864359450003079695, 13827098275898780935, 7851275574239236550, 148489084772098078, 14414610826237061088, 6221005392878728474}, + }, + { + {10231841021413400882, 6416526412762119350, 428961125681723016, 5443671154306564465, 6515481304725718135, 7472109697629360236}, + {4053824519380499109, 9856627631912166862, 8808287978132340097, 3494734447997642012, 13122490218403354627, 1586718502175528539}, + }, + { + {6260407175309061893, 14850337727743664854, 15585408845772003227, 7077264422349275731, 8392418541009408758, 443622451095627013}, + {11824794477049100598, 12322457178558060770, 7174368023614892223, 18169994008863893305, 1353822949072228703, 10638226122523854578}, + }, + { + {4765938320248439052, 8363686885434148155, 11304264598901869535, 14452099896297485497, 14813989444275511579, 11997113422384802221}, + {6448271325447843219, 636006309719920128, 9686816723717740028, 9631232081121088634, 8102244673875044160, 3189426959171768223}, + }, + }, + { + { + {2463818565041698203, 8022820688029070207, 4888356879458026368, 11629790905165524278, 16555714206595898330, 13627886481857856688}, + {16335710071193906987, 6321854959216334024, 13113326664056241925, 11554351464078489040, 794805091959363175, 12545188758454015719}, + }, + { + {156113733862257116, 12812294601068672576, 3563267346091688314, 3001452181277921772, 15607483360571672694, 17299258115284201469}, + {981410215374975479, 10842895849914354733, 4019626280262303535, 3964525883133678208, 11449335357635141837, 7447803780571143247}, + }, + { + {3449274165036362414, 4918853138124055081, 1547983020534099669, 8313761980678241388, 12236549001847065606, 8919544181940646346}, + {7959615711717924349, 1998441664630865730, 15662251542753222396, 878616613737147225, 10921558209848383451, 14643587960617282503}, + }, + { + {10030195466513813736, 7264007409425871486, 13572379319575545436, 5989173427119562900, 9714898089014614002, 16719526588489259967}, + {14134732214629887880, 12965589590960717029, 12056814709100630613, 13827802528787563910, 2927559054475015091, 12475732844535894680}, + }, + { + {14808325747134274433, 8057826914079617564, 5525954727355605916, 5290214223388727378, 1085748056393626543, 12252253028550111114}, + {5922977969674250041, 2448526450681685329, 2926522479362225384, 13034339434060413522, 14285788618705740240, 14224616444852968120}, + }, + { + {14468289541178842512, 12201944999920129159, 12698876919717580942, 6936204399773360929, 8336457280891506998, 14054191262205054108}, + {7985103068695070111, 11634744794544986495, 3492551865016082791, 12866518520735982455, 12992402881058061256, 5203085761453373334}, + }, + { + {2744232347627720169, 13383652591074198984, 11038998560267305871, 13459807200627641401, 4723235801697844775, 6052210961441690931}, + {8015232138170246714, 12079252961549472414, 13192819517464270060, 14584389580251977550, 17833236661373150481, 3761490117360962633}, + }, + { + {10639242284018919836, 15769134811853365977, 2764713995390457156, 2939983068560561484, 7744415034623844491, 9862924824634167441}, + {5812124348561302205, 16914325820321413839, 4446235265737737774, 5136338484784530512, 467458589733891477, 2630304324972701607}, + }, + { + {6832719395023449163, 2033508612951663629, 3511592613860178255, 981472589675863291, 12626082291731102761, 966591436305020179}, + {13733382109710953302, 1434291421752039220, 17971214388752092375, 7561304859414785821, 17294534194238094519, 6834714320288858574}, + }, + { + {2420226340788279821, 12053022832331502898, 15086319486305540754, 14384436305396163060, 7162949585624069622, 2339283057144054658}, + {16555809395586932014, 16575909670975005732, 12006449181862665382, 10896691971361895576, 3873458976101713782, 4179351799128456450}, + }, + { + {4772589731323745937, 17591537228186096278, 7733169684400774683, 7943142157971243776, 2600580496982037708, 12240688438179106242}, + {1682995002150080423, 8105112813163255258, 14679869015350748762, 10615354182892733709, 1101044368915518409, 5335546289827620815}, + }, + { + {2820596099556415173, 2594358308517525622, 3833328115443141899, 1838617013547370473, 10703662474010707679, 6132526521387027976}, + {2504146752328209083, 10365161708998346132, 18378027908391206958, 5944023165464852345, 17106626712229962048, 8325422024401372832}, + }, + { + {11789842430665850017, 6421202279499314143, 11573596254910462066, 4537895385523862063, 4377931158374724860, 12552031527611086863}, + {15504318552571625652, 3707368681645487345, 15001785752614913702, 11705782900778611709, 11949053603484681481, 18195922704834165941}, + }, + { + {15421742936087622130, 10159987354101918308, 5370406297439414101, 18048469588184356347, 15077974257262174351, 4171587624627671421}, + {14084050992809485269, 6539059918771085671, 1374789379818515594, 3838078018577862594, 17679614135822761449, 15474878493731691411}, + }, + { + {12693451959622797980, 13290565128275588854, 7361758586005248557, 16075093967835316398, 7087112768596951545, 11543822053453504948}, + {5902482308820286139, 7353185101342606440, 4571190498315407690, 7730145317036018296, 3643250411451134315, 10481041494035321174}, + }, + }, + { + { + {11379922315523310195, 6620262071143097557, 10733110307157784360, 2455420994718286142, 4941160012966559203, 12036389373766931776}, + {2004451758092625142, 4014199760272071819, 15292911034143935666, 17687179513796035433, 1569516718335592017, 12444236748783362218}, + }, + { + {1200397030012372876, 6457491138111915023, 11531993623745349026, 17899861472742612738, 14124733664835562044, 10645792077218180283}, + {13099261645024141037, 10440696952297433984, 1918236772154249849, 9506923430535157418, 17499444799293611002, 1509670397443280998}, + }, + { + {4465757364835631722, 10965936787556583155, 14540946401148103030, 4584421538084028348, 13594362137297692686, 8844279558284617491}, + {5111359204171112465, 12790060720198863411, 4014742787506192452, 6614930013636115085, 11730197034873324635, 8776100629808369100}, + }, + { + {3790258798970833100, 15996801276739271696, 3464398440425134039, 15326814870706418920, 14448492169636125498, 3231159483392005876}, + {3705423779579747953, 11372348237300277088, 8069222225331107027, 2700528497189769719, 13555552327194442702, 410730686168183967}, + }, + { + {6826832086550914049, 17351671830508265713, 10661972945889099645, 12894337943034505815, 9813078142757356629, 782908000516993322}, + {12769245099971286736, 4882620828121265763, 9488137564983431475, 12539028776281802034, 14846786398874564444, 9073776363026222135}, + }, + { + {11362886301924370650, 6443575479653887522, 351000858570459150, 915347620832419895, 12517886863027987115, 12886465789602176705}, + {13102667374276139057, 6893636638757694468, 4158135635197259073, 17014006099419646155, 2886247550772729453, 14342905125501493077}, + }, + { + {3750785743865695174, 16184496891679274640, 4508484768462328620, 12569830003082072446, 4338678566828661049, 15769546354414324906}, + {3809488443136531987, 3433818606509958865, 2864343169319087118, 3035827594190654155, 4283767959137064887, 1597329211670760111}, + }, + { + {6735976130349257678, 16303412525749538849, 16400428130291037330, 3771855351047356253, 8461011934077951901, 9862709568546362072}, + {6948691434839126085, 15094238067058818238, 11970945255041716883, 8357516122660935053, 11312726144884161679, 13888868066934144152}, + }, + { + {8552971979382238094, 14893844762756755755, 15247853217772454969, 7990879378400788049, 1337495408598927433, 4927592820371154426}, + {11318355400818989979, 14034508604918932131, 850449205422148972, 8707631597140933770, 9005290700503315458, 11206135773816655778}, + }, + { + {11717560420962665146, 16036488489927426530, 1073385780093662141, 5605091585524991500, 11567805488139392367, 6960929895827554242}, + {3185029102977538829, 2880896879639691851, 3758583862703327606, 2607528607094689740, 6140415866307855875, 12833322601936456641}, + }, + { + {2487173712779352607, 4163293746622453413, 15225064953453124837, 4745691426593935280, 15916414889134198240, 1934042257062059048}, + {6574682739913942887, 13440408571236322143, 18076013925783648472, 6693474681185919321, 6987178681680099301, 8824321410010451056}, + }, + { + {663297042995494661, 14801753841371941556, 8727539546491979133, 232708169718659428, 1190547424093432076, 10001731533557757135}, + {10564965587834524294, 10882077754824824235, 18044231443793420173, 16047844267187742404, 15237359807179541598, 12335098732141186268}, + }, + { + {4522044229514984187, 12692311112090809521, 5174544620399081630, 15624956610993361290, 17499804740829372070, 14159780115181988400}, + {6980473429664507297, 16919669078262269987, 2419328464610134620, 7279187746594254030, 12270975978407595756, 12652404087215952443}, + }, + { + {3097250801852684058, 7529383389734329429, 8943150468940937789, 8684872219957364714, 1510282680805138697, 1736664582387906156}, + {8559488977052206069, 5218002957160199868, 16129363866527754916, 3419381639187625321, 7406388656339306496, 733912006552345760}, + }, + { + {5051832488018112348, 2845773093799720531, 4269756063941307164, 11932175332287301151, 15864531947553285757, 6880993309378786007}, + {17221326993540037993, 7339003944245759506, 1709954257215636952, 3058564762936670215, 1381289108584710274, 10818101921467782182}, + }, + }, + { + { + {11909603028098105071, 1433304974993906210, 8596793362628962403, 17840341647275356595, 17335910880809706217, 14496938254816120063}, + {9718444168237729680, 97136308719864699, 385208539784578137, 3982687391919868715, 16704940770194925306, 549720452261507487}, + }, + { + {2694843761758977903, 18124804948268586954, 3810124062407334761, 815390255307793990, 14032033031902943311, 4699208123402406172}, + {12100023268807134280, 12092656330344745210, 13856900984407365162, 10791000625265461807, 10537408988523295901, 1213148431505044944}, + }, + { + {5564129609030186650, 661399315027471445, 6227812982018710887, 12211259814675657270, 12640363533246661095, 4250662369482871640}, + {13995602364293455479, 12559572490607005689, 4555992709769317618, 10656755099067169486, 5466266601354190684, 18303706146826818496}, + }, + { + {15368142834518355591, 387732588739217687, 17906815839192787578, 2458368923948318521, 1213186515140052771, 18119735955342268000}, + {1464255699774805313, 15706302797823747047, 11515240128938376809, 3345743489851301863, 4182988989553146063, 5822101833208111449}, + }, + { + {16987042022725647034, 319232815210787283, 4458381292742179195, 17988503646508966180, 11158143875082860346, 11504863432259964894}, + {1973834314893704871, 17030914264131630067, 4911299812763134293, 5430690367398180217, 2557726880455581905, 12434521041073812213}, + }, + { + {545462916220339990, 3584698686781184519, 5328421879230100723, 366775970831948805, 4024338021516994343, 1533516434617926006}, + {15759296396039088968, 1165424695035321437, 4856582709870659258, 12896943835426779442, 14754955776815298193, 410556923033083573}, + }, + { + {4186087526910663586, 6165136419336713660, 12136818299454961122, 3405693470185967536, 3648773103438697505, 6515981208652058927}, + {3752988438485155801, 16815658448321902855, 2796662867929732032, 5824574038203643621, 9332750850995495618, 14417469253846871647}, + }, + { + {5370314366938532279, 9877969370138171231, 13966511470431609240, 15877758322148217369, 773982613756465354, 2790333076733361805}, + {15260338585394597865, 6297024182872652719, 12048909513493364581, 12444492358042311467, 4022686688297847278, 17410241858326791474}, + }, + { + {3482292231700676468, 8908690623157180028, 16288460904525269506, 5959395600638297217, 360588989624002344, 4420646335976102398}, + {15326491091968545497, 9102573345895719113, 11981331366781021439, 11438298421566869030, 11986315544156148772, 9586987921414184090}, + }, + { + {12658775917959337138, 7321726641436322889, 8904085691599899669, 6181173455344381785, 16990799257112339793, 6589370949402051563}, + {152076730697639797, 6292489939246750855, 2631558763335345129, 2400788177969090289, 3082489011322585694, 5460755211051411481}, + }, + { + {16026468164120587616, 3890624441511373656, 13608676030619425331, 10074131329717815957, 10336173319596529425, 15010101088827254127}, + {16066548767291218138, 346765727064293714, 3034008750782532770, 10634970483280908770, 11696186401772501910, 992070167768548909}, + }, + { + {16700357690267037996, 2280486417700678036, 12292705505251502979, 17433319339816222360, 3180311752818744080, 12556842763675232270}, + {7431081179990995973, 11626745676061745617, 925792030195302151, 7573296302591880847, 7111534405851948348, 7418370979279348359}, + }, + { + {16126038235581718523, 4590472232521394945, 15667737325175661395, 3234185470951996453, 6433453928669282028, 15899702540931522631}, + {4961512606010997533, 7075023696164954837, 1926349877304076748, 15847449820251106944, 12103289522218620655, 11755646081940303532}, + }, + { + {2815793807577222685, 3974873120030374430, 14070231706868366483, 14914212937861260775, 11217571411566683403, 13488284407258074738}, + {2447044301855977709, 1991486381221843561, 10306272153518153979, 13012982641746076783, 7500759912363127296, 9368569895638129462}, + }, + { + {16633917127904484128, 766128895880122918, 12296015683476921956, 12780904198992336027, 1747119835730230715, 11648694124739687510}, + {6931300612490207931, 11673373686239852450, 18176687859595005370, 16590940298368519075, 10350216104129322491, 4313019598947936772}, + }, + }, + { + { + {18436559208253217538, 10052692439679361295, 13914661242043605922, 5303216763167780904, 10320619132458662262, 764916138455538204}, + {9742933872987685981, 10626539639975944361, 8938199719602528282, 3118400879731019025, 17486614403295685962, 8194019942137487488}, + }, + { + {16848715567479381646, 3965484758491433728, 17553116401134175918, 266130778949555493, 15612913147808127901, 2452271039599659592}, + {12112647027603191858, 9836632132933298138, 7150220004740389636, 6080952109208447401, 12794151692277391601, 11339774216918951773}, + }, + { + {15370271492241639789, 13865842581349159076, 14645993961035890521, 8096824553138062253, 17815019169532343171, 12197261930135611113}, + {13843017114364404011, 5010421400581829489, 17814230270064460774, 687861654752340118, 17009006702144007774, 10314843449915140883}, + }, + { + {2744318910620647716, 5603184151316605771, 11257624090959454283, 13185449267405233716, 13751271304022947910, 357227629545275976}, + {6629711137100856610, 2708216448052728946, 13226058796854087226, 1788986271084080906, 9168817775042008469, 11922427675226424552}, + }, + { + {14454843566511544351, 12858454059009483825, 6952579439068010126, 7733931976949613017, 2531905974818570751, 2340234299628817285}, + {4064406969820346920, 11776091497743820272, 8329625521872996607, 17793038299121088064, 8268289814329664881, 6179727598715947755}, + }, + { + {13248035145811273019, 7752115389537037710, 3783507151237115160, 7998022990884122769, 16933952266389620556, 9525578126304597588}, + {17660710021706978693, 7887275263336665238, 1823257268190340929, 16929028893372651088, 5606633925842000055, 17725594627635071001}, + }, + { + {10717942541841401668, 5062492223707666521, 2874099965260778327, 2111658619166071126, 11668640869427564697, 129797271043653095}, + {9692221446048485432, 1712242857382255473, 4838248139231811400, 4970058966083233108, 16360347161442205136, 3339445137046433520}, + }, + { + {11766141551615199913, 8685320933099257575, 12025130600585049936, 11062435310323182587, 10065203967214956664, 17179026247686360724}, + {973705476571001605, 12336450041607754348, 874536885921370264, 3620964755713794319, 3600247557571996978, 3539695373337548386}, + }, + { + {6671466056512719629, 16184392602500878537, 13956944166874842510, 3115630032774258951, 1843095648852176408, 8229461234479287588}, + {9459156799383170558, 575562900712226104, 1461784124210182226, 9743344326188849649, 8264467109834156287, 14855166366987863706}, + }, + { + {14443662408692449290, 7664862287740722890, 17649339370312940977, 2156776012545551339, 15768456150480100232, 14346672920916515716}, + {8113778989714113681, 15635297215600657635, 3026622243462570848, 9983527114455639519, 495493109210132335, 1825135321586189570}, + }, + { + {3948205964039691358, 9147407127214526584, 7561468478346924639, 10897363606469824992, 703934561704031911, 11244219452628483166}, + {9517458047229537628, 17195327556556691064, 15691063270835772767, 9438705527839014294, 9695368154409603795, 3649704513354366568}, + }, + { + {8298214822826346584, 16160788589831391317, 17819994725843440833, 1024306577659159521, 1852010738280183503, 16583513376689890736}, + {3373755007779392878, 15683692594403040997, 13166508057783939533, 11523709082285599828, 5437988652322971796, 18109256413139496795}, + }, + { + {12923777389997376805, 9977718769355025596, 13018161749708349740, 14360291996204235159, 9575337711644144758, 9974219793575670651}, + {10424562739975667006, 3563632038522075692, 3672552713411869989, 13884443527418224724, 6155373509257036382, 3207888628018922232}, + }, + { + {11930174348010923271, 1348949055337526798, 726415247102229584, 5055400198081198789, 11015209320490555612, 9833582750989675305}, + {9700597556714543589, 2992217892752165914, 13783701793319444227, 11374474240057387342, 10199414602968931098, 17127353744132587534}, + }, + { + {9563065141641954290, 14665066342222635705, 9884992491626869089, 5974715562776845322, 573036282426832215, 11499375779477883827}, + {3206285674430939161, 12354004793799927731, 5478655966737394286, 7263281183196607046, 8288729282303345591, 18029234498520921275}, + }, + }, + { + { + {2992157424964359003, 10438615318402196118, 255815347996375468, 4465802505310361450, 1438013292054608859, 2462444921683526793}, + {6885574398590377060, 1301114469257389079, 2687344453450416312, 14090513069242834662, 17764663004285116999, 8889109452874431564}, + }, + { + {3947928161712886286, 6283937438203374232, 1924037281168554481, 16154924465225066172, 1172742291383405274, 4266561696255722724}, + {7000612604942850536, 7659188878730526073, 17637356804126820843, 16975720578569227612, 4896458553166174167, 2686308470754372836}, + }, + { + {9432182594949608034, 7182179915820505304, 7710800442508848674, 13288492478214648407, 12461818323948657464, 5572387091938177662}, + {277315655080978560, 8486149812061624297, 17273407137514060442, 15942854874670749371, 11686164309797544370, 5909985884404360345}, + }, + { + {16367186110059925561, 346226761199691539, 11243569651429838414, 15633495530019237469, 16343973985917329298, 10134611081598971563}, + {15093301170509003037, 1008194724710082237, 3218608412640277159, 7159496834485052730, 10712235151472906025, 4198145441405858657}, + }, + { + {5131609251652718207, 86776758092331267, 11360734888319180911, 3469913385423048534, 18100684383471212679, 325475210458359248}, + {3689757001346201628, 1730954327037278569, 3788507424874318707, 10512008196941777061, 11932764492105480931, 8036637367681551485}, + }, + { + {16591185232690243721, 6455242289394723746, 6695217017042848759, 4941824958829892109, 10112600357660465319, 18308711553066796539}, + {8438656634392593423, 4958573399768303703, 11140056576272524422, 1895853887747460679, 7283324369187624339, 16195252249773926894}, + }, + { + {823375075601828122, 17327350242456001950, 1349893857168950396, 8412958507213802615, 948019923217166776, 7456308766971274642}, + {17370437399496312157, 8520389823586348238, 15411367408205754799, 13174837180834440525, 9274060964565734577, 14571182742247634669}, + }, + { + {1082395577808637743, 8147865335545732038, 1404461702912200930, 4993236329065838796, 17484910947541357459, 6852232223602019945}, + {8965634425630211893, 4255349305144782529, 5448760775922504263, 708413774782466570, 11280134104493101923, 6100170211777061175}, + }, + { + {625515264652475732, 3039989026588849470, 417945613321369841, 17093374707175198551, 13237189962567875668, 2311750606403861433}, + {8005856008273673581, 6479389764331986131, 14555228340786648758, 7247893743936400741, 1374541774474051599, 11227441366009495338}, + }, + { + {4181002734489236543, 470999966911862785, 15476804201865281857, 9087684620614573993, 18304567027803637491, 15731747090499402793}, + {2010012731370719240, 2998664217104214076, 1961508652389190300, 6950362691421142338, 15681741907839112240, 17447712985298987779}, + }, + { + {11768357416958608825, 7645918167071842001, 16228882427244007654, 1745696721312212486, 11721695430734972091, 7273899982161219731}, + {8266026594340198219, 15717218685429720821, 14112476118090358572, 17888013578946462203, 13290175546249368751, 17734414485500127553}, + }, + { + {5326868799317243470, 16458483939729073751, 14887970960607081992, 5039987544340497966, 14821797247198942090, 3950630707728288537}, + {17597412384190391301, 5520789045820740828, 8226360244407437775, 16657311355689665307, 5224094771449505848, 16756747441122548551}, + }, + { + {598869525170933512, 6677154916771020677, 12401580674393252457, 9920987208485925499, 13800670572914405529, 9707555292166940171}, + {3223483868032463832, 3631710847850758369, 11358667894316546298, 3754511562356210854, 1701568866431315786, 5919933616663414779}, + }, + { + {11490856134015076232, 5025125213251421660, 17087480468251353943, 3675626333374651640, 15669324372624095816, 5288578761594490376}, + {13849647572526881715, 390378562422129603, 5286372605531545224, 634678992498468192, 16814060184007219837, 16839035721991946110}, + }, + { + {5403383155926395805, 125221686724158846, 16200173587003585891, 1190332142773424609, 15217396669374393068, 2578745759049575066}, + {13475383798014306998, 6424876294380300114, 14191098580567931628, 5890095616593589345, 2936173359172605332, 17487060099266163274}, + }, + }, + { + { + {12719214741013613290, 5114617959251923035, 10751915446782581763, 2484828566956964312, 14343803650946049216, 14801299356022205455}, + {3016813884715770290, 17891349667893557724, 15777676062783188811, 1712819799097224132, 12168613974393954998, 13986990585905126288}, + }, + { + {8023010081509653349, 5335670617918622683, 1846902627262622829, 11994486113849390341, 6538926236372175318, 4814731736716894207}, + {16304448710578682702, 9349072176363267816, 9186691613158664419, 17103823355609391752, 3916770392270698134, 9012943127536839823}, + }, + { + {5275622406326687551, 6112584237967786501, 265405289314185926, 1412958831727264346, 7651126186628822932, 5834995389479500713}, + {13122792515707256985, 2550947875326289463, 7066444771311187962, 4421293422025492021, 10767771791627962866, 14226728638256751184}, + }, + { + {11448691464520706664, 15675985285202273608, 3655079521218996928, 15936388576359819252, 13208918369662918590, 9516984219307854927}, + {11597611792829772123, 7713221738127008948, 7961786708858212519, 16353817233799898756, 14783345852732475068, 10250761950603958774}, + }, + { + {2625594970679028763, 2169078556432423136, 13021097165593667190, 10791106227007710714, 2690189788129576822, 5484825642511489488}, + {16273557857984121953, 12145090445512587769, 16101739928864380638, 2643908061410998004, 12729107251027632439, 7695556167491532786}, + }, + { + {11157440928684545360, 3046840632242460591, 11426877095892198900, 8918480588279063509, 8787952932779849223, 9027816580501160769}, + {9128814207932650961, 7203341616721124638, 8182325905700299211, 13427506527593902897, 18140725933956453022, 5063665298842103866}, + }, + { + {13658301013561762689, 2849842635737133681, 9794505509330850697, 4574981021203185846, 8209746334820554465, 5056236831081348743}, + {16624206083233762319, 2806783205419280334, 4722899220782250386, 6951333432373876775, 16586996273337609315, 4087561966128175843}, + }, + { + {3878852889783645167, 5400481924475044908, 13648745681887805278, 16385969341835471642, 8474668593315413480, 17072114360268111657}, + {15909524935314055264, 12962656664337915873, 16045825205726727428, 17668445836324789204, 9582515111403822925, 8311229418367164498}, + }, + { + {16750713536855692337, 12158883093332386860, 869753891367085490, 15605303972493341694, 12313210121941258747, 13916691409490803616}, + {11444860648717627512, 2835105424184438282, 10913132759099776850, 1412948777401255586, 769776732776506316, 1165176872145242057}, + }, + { + {3136155720816959363, 176782515877232633, 15898658221137319414, 5945945464575269676, 9144428244947354059, 15406556014273518710}, + {9716246750324542500, 1672303908580126879, 11063634686713475813, 5077145573933036029, 9745467858439955753, 6968865545502175550}, + }, + { + {2495713660630230645, 1185980555358051965, 14406641941666869071, 13418195026575315332, 5357639127530659925, 1493186117020140399}, + {15828121188984359229, 8349485267934650396, 7613912943850760152, 18030871967540857146, 8018837622665199635, 15135626352960024679}, + }, + { + {17168709744073976774, 17815617756406029920, 7562176203824291435, 12623565445431123456, 18154939934834134345, 7536657795057385488}, + {1403539525163296919, 18383425392072061037, 3301314769729806667, 6468401011400515937, 17613786701601511597, 14867910979962040781}, + }, + { + {5676915880842387064, 10055846762720957031, 11806698128040651823, 5264306477430907541, 8384892015115220698, 78358395066300931}, + {1150314427301408206, 5063901896663115767, 638613414256407118, 8689364962315350092, 16590905670553712162, 18128165591184340257}, + }, + { + {7752905958520447175, 14603722115727539325, 9781506285327318406, 13087529078766636510, 14023569057475503528, 6019746498716519160}, + {1031759345651315039, 13964338843948005473, 6689558506286989216, 14220086196735492654, 8688284060108936168, 11830821814034764828}, + }, + { + {13480780456478148129, 17091116390541906595, 5942938816814828424, 476503073112423896, 17958436423709724523, 12898659138199048553}, + {2131038254379659612, 12525642025600402532, 3081067260990044234, 2822022238840761302, 7062264661943515613, 5905091641833394361}, + }, + }, + { + { + {13440622283766006421, 9484751676577363406, 9905947788244365184, 9616606862630155221, 9253691280381130230, 310805699197692105}, + {15857119177216089006, 10322980288919041083, 18373416554700920525, 6657775287925290320, 3666256939083168698, 439429372311506210}, + }, + { + {1597897383029505429, 10525228828887910120, 4933923276776716663, 10152243689983019623, 15301370315971850890, 4214213542732825860}, + {897349283246619198, 5660938796941340389, 3717921090959741165, 5280841632073610594, 17979019565907796206, 11519275321457511404}, + }, + { + {3291527771490538711, 12694342940653469057, 13203683462309390985, 1193899784465090270, 659621542292721066, 1071462121865719293}, + {9590655863442234173, 337930243762610616, 6432199645357122456, 10260314756660590323, 14326008875664555298, 3522995246882448014}, + }, + { + {4644598969538718139, 12193860868892577984, 12250306904140467019, 5407962404963080644, 4485091644169226191, 16089382217006835007}, + {920589308924763406, 7142202226709964624, 11524080200370440713, 8450954286780755403, 4635718750704941162, 1486085287263603581}, + }, + { + {14187921230404535350, 11346105716295753707, 18142765952006405051, 4300086759963317261, 1825347314279603037, 4246997353784727565}, + {10550338330776677777, 11915257613511762166, 465865811699731787, 14525465801670139106, 4190035864475007181, 15697268699718129928}, + }, + { + {16520532307875617691, 6478110846501161864, 12009144890567102539, 6639996996037161221, 10346745057146969014, 545026149668689158}, + {12347224953633676077, 13721884389953920858, 16613557823182647213, 8719051450883594518, 1657296232801227258, 9195723469582730377}, + }, + { + {10672379303837372508, 1178915066578644658, 7318232521602719432, 4586807728983065460, 9645130800550409989, 10469349993209561384}, + {6164577485020507700, 14774782349604625747, 1175325949885081731, 7503981034527378970, 6665905526100319746, 14115807008378187235}, + }, + { + {10537591092984195751, 14902777188358201211, 1609682826674157693, 1415112203205414973, 2121292735488271251, 9730644628099641048}, + {1561907835543757283, 17295199465882003505, 6244864773422006269, 14104758566372328508, 5172569374976915040, 10911149041876998445}, + }, + { + {4142743472397546820, 3389473658987681872, 10678200230732012359, 11202709549973179279, 9306523242271834336, 12282962716364438596}, + {9003120795952620535, 14330038165744890298, 10145599770735328847, 16631175899061725823, 6362275304129962702, 314787489785924267}, + }, + { + {11721097912057176600, 465843171488534090, 3822319191955558577, 15208224590212643113, 11095623855521247100, 6466436977520978591}, + {10032477427078550098, 14389677632018329866, 7463855252587484514, 9538679795516955542, 2432362658144624282, 3283104727441149351}, + }, + { + {12785913170846555661, 16504696481298824206, 18387430512449781784, 11501522553203007302, 17453226662032435648, 72841124322579339}, + {10340092917595603421, 18425536899827803529, 3390279596984649469, 104139025934621284, 14389540744379448736, 13185495434887927728}, + }, + { + {13047319551312062583, 13069113474868968778, 14400534570791996729, 2940176026787857058, 3476131159454733686, 4052732675176402643}, + {3639915650884140037, 3373696894468266675, 5954677702497869028, 12219029297141994717, 14767012055233408577, 4804879819244591749}, + }, + { + {5743319169894187724, 3403171851694334648, 4433580132084214877, 13890862639937427160, 10419362266230633172, 2859349082979398226}, + {8742566305870816529, 13813314196081988405, 13904410987635691727, 16614452833957126689, 13707357634780610178, 1642839273094370920}, + }, + { + {14027248214112167925, 1719835930921678207, 18418332983139545900, 3720933284960441366, 602535342330473807, 561868717519919310}, + {12719483106586196278, 10935152826803494465, 1856788292694114055, 11401362997997198554, 16655766755327767076, 16749664986736295564}, + }, + { + {4746163886620296056, 16195921656868907520, 8331686623103669412, 560576196003183117, 12094183225971951844, 16935771085543970093}, + {9464520802091612215, 10072288040788029476, 13937774116306076245, 4650247287489763753, 7901567587026209939, 5944125224832984247}, + }, + }, + { + { + {9018413310491937545, 7479211580165592007, 4723343534675309263, 13895454120971208439, 13937115985645404601, 11554040025799661497}, + {5480952972697767947, 2914963179369015982, 10162636262303291625, 11296982831055708826, 17035403260442020132, 11311386309034106855}, + }, + { + {10287403934820058638, 140061018296065973, 4609836502448609974, 12833794578281306273, 7013376274017941064, 3171002103636180619}, + {17411865245980625367, 17830137832122912415, 9926615308142487378, 10170594699632265376, 9289903336520035955, 295986264357752633}, + }, + { + {2353717779065485542, 7849736054356737745, 16353139566092721807, 12477191479637934527, 611225681162111976, 2348028862004420825}, + {9785747690717484735, 17418090343401958851, 12038755953887168101, 16958893033340106984, 13647755196440313762, 12405018904475572776}, + }, + { + {5298494778929819598, 3924508621232171971, 8749972845037533540, 1931716910689763937, 11971817937790329025, 8597404460835479112}, + {14699754936537593409, 3124307020702767627, 15973366477384098168, 12480586491719897520, 7671564839409689125, 13926805082785871387}, + }, + { + {15204999194234914607, 8349634193664955592, 6009098602331648241, 6924706367035510132, 11252627761006599356, 18041169172716666620}, + {17789359299204781079, 5727817029324871017, 8859671792757355400, 522069605866675301, 11189207261261388877, 11232767462102509610}, + }, + { + {16139497738710238126, 4157146187414349131, 5487114022641721563, 1063383115530797038, 2906599717299719710, 5276015474524600486}, + {9269825514681515477, 16775312150546041513, 14582957882487299154, 15170954478995084883, 2499812420501884408, 10945713424572036595}, + }, + { + {5089807051541807662, 7157200325468149470, 2937849588731584444, 9354845172055266578, 5631696405995964524, 2214323534299283665}, + {9722628493150662989, 17918792662316048829, 3417043373414897775, 17679083211095336242, 16808346554886232447, 13289844996223351707}, + }, + { + {11269874526592562906, 16500978216603335212, 10118738127249413871, 3659452648579232998, 5141018253691260035, 16117724868471222014}, + {11347815034616287201, 7709514744105498479, 14118984237650181458, 12026134955404838277, 9335436582353087685, 369430838816330654}, + }, + { + {1585139051234805814, 404691396436142113, 11444293817557480245, 5830770104023383537, 12277306276048209251, 10642326551634509497}, + {13792665542662432081, 6208000577113784638, 15717378408394080413, 7820469524198781038, 14389089922028942421, 8582404818280480446}, + }, + { + {70981166460121239, 5563408652468244620, 614683176526977757, 2781152952815547101, 12029155884278293318, 17760250353211832620}, + {3187755494407378069, 17888395113661363276, 13412285944510495080, 11584741820870126887, 15965393589757423852, 18040989847530826793}, + }, + { + {5405473909442890818, 14666994240588619109, 12458304673324386647, 11008174367296119903, 14582036957337795851, 17282661739787817063}, + {14222078674054535548, 11008919174943325660, 11819167351245959209, 18134905895138035484, 13162976610859867356, 7513570547713034700}, + }, + { + {14503898932310678540, 10872534209513960811, 10769539085938900258, 950968100788102293, 2593957957211394429, 9325054429337127538}, + {8794306083750832982, 1021791833181379560, 9826075936615091843, 3550496685357100718, 10181274077023686988, 1708403758287646690}, + }, + { + {2114324794753920008, 9126128083829835556, 16280212870402563277, 13283686190256525376, 3251349600931694719, 14483424206972436627}, + {10572754008401154275, 8633764455629405737, 6588424944597437957, 1571954989152470825, 8516883611989669014, 11640306975729561230}, + }, + { + {4109007533450828692, 2356386509806748446, 9041152461761446992, 16218546554098405589, 14154709222330366952, 9392453621407519648}, + {17770577554690365656, 10932372374411174377, 12600690631485435764, 7948622706571305677, 8660221260057720358, 4747684946643246411}, + }, + { + {8540558873947276350, 3622540825228765451, 16650849354810540513, 11226397583292742086, 4705379347219803579, 12325233166887290731}, + {15619140333232072725, 8608337299420394261, 2163342765639233276, 15744964703433685214, 5280747802181153134, 17233894809548258880}, + }, + }, + { + { + {13115213709675436794, 10299123692547567131, 9429245948262081969, 13047795122467758935, 13812575189117105527, 2948332115489926339}, + {2744672569127744094, 4815622797427999112, 859178603639156086, 11576446289001159839, 9958253466657519480, 16703064241036892748}, + }, + { + {9659930467403989932, 17321718087937017122, 3615409075768522018, 6398728174042229488, 8382474392298007936, 16868018560156882295}, + {15394153985344325633, 18233056749369336201, 2786261003208561400, 14117307321540249886, 9686181390715937042, 8956691786907318249}, + }, + { + {12469663383430832235, 13312156986621640537, 11912360761178303017, 11804219970133303678, 18138791436343161493, 2154714404896772973}, + {8464860256859883443, 14324425897255227015, 11075246616197014103, 11084846688464899884, 14026644252332359919, 6402389694082745611}, + }, + { + {1664247920632234678, 10050469124529404545, 13550912777105883578, 5684389909240961711, 18262622312373628010, 5992040147885225610}, + {3886052343944693110, 7794548519566311969, 5328743476861022198, 3557155954099235264, 3684795529791949842, 17691405542438413688}, + }, + { + {9667044915797468497, 5187341894386544411, 9007932748072503962, 8968805127439822005, 4693907985120651307, 1280923431871955632}, + {6721231714391543602, 12198545097663757759, 4397005010009650381, 1422329781944115833, 125099025124551420, 12942840780107155582}, + }, + { + {9559600762660458657, 2654878193132084429, 6142683421157333426, 8600628541895281085, 2720194395607941256, 11800628992463553487}, + {4425191657353376240, 6088099402960722641, 115029919295524541, 12646988404583673832, 13384863624367861501, 18364682859012250550}, + }, + { + {4532078693830769620, 718394906501818236, 3877201007259789143, 760257150764070663, 16650468445415199734, 14938394407466859533}, + {13647198668172065265, 8150502240122876834, 14693081828320862132, 7303871211541846858, 9083743247615337146, 14627695013907233453}, + }, + { + {15736758467123642408, 9706701086221383807, 2559832927730153795, 7692171838583389170, 10835849209926253466, 2290935724211630501}, + {7110948153091501836, 12491488884744421116, 17194507769433100343, 12871741772449719665, 13293932181017940663, 15615371283128275924}, + }, + { + {10561525560550219871, 8873205184226519024, 7699063686607517061, 13635014797737384505, 14667176363819822811, 3925937510121565786}, + {10228456892890207582, 14846438160606646653, 5315480697106497650, 5122456725957472423, 6204140834106767339, 673047575978292150}, + }, + { + {13827793037997042902, 2372112433190900987, 4942678787760432958, 17946455618542608613, 15396054321262292130, 11511518053778317681}, + {11160017347470886464, 13664803594602056362, 8669936965482088617, 17765994223101087455, 14455539200673473573, 7079780915049059206}, + }, + { + {8033984515178450060, 16378670770570801979, 1548095437408110789, 11401360828210390234, 8750170757194679057, 4561487363432466918}, + {9995552829545286346, 4476962116767664929, 5764765679815373569, 15487395691041270870, 2323841776203994300, 2856618876814473844}, + }, + { + {11531868239432263786, 5277805717080096397, 11682853637330501925, 5733978770749385591, 17364192273085890197, 7500286843970580511}, + {86794299821863973, 4596156132784169023, 4785356555999800565, 10872734824615120105, 3047769721102166199, 10829425068529251522}, + }, + { + {16664987869819734811, 12973908345922045971, 4703076108718901177, 14075270048770461650, 104815219486926864, 892782843371503265}, + {10458459649338308428, 10668999312407153052, 13704561636334771166, 4635417240676718572, 5106553366947462575, 3703456388087747221}, + }, + { + {2751721731474885326, 16084898094744997319, 12429196417254737907, 6088459822127419367, 6900842023460552142, 12211266007254795824}, + {7744071277950462535, 2084549072065931478, 9120649345176753774, 4812104275201077076, 657496594162312754, 3182353075430185403}, + }, + { + {8755422501308001479, 10142307435936727265, 11064770721673029308, 18425843187034865157, 13347285302222173760, 3708437028689637787}, + {14876728210989151093, 7705511398925586068, 14248821016296346136, 17806364092565886021, 5124212170718863197, 16198455889993493512}, + }, + }, + { + { + {11131309769818983841, 14973020341004185634, 8446856854308327009, 89059453523509986, 9172267203688134801, 11760494578717306152}, + {5073673248942080292, 1012148470051943223, 11336947344365930468, 9256490203060408704, 15345366488712852356, 4777703526474964085}, + }, + { + {6785992801663327967, 18012758086365480538, 11715768358595862309, 15278468386670997865, 7557494802091764967, 3226512940013553265}, + {10651059331535692113, 11605693566797492518, 7683257465728908366, 1028223626866438466, 16313431221531990341, 6758261315736790700}, + }, + { + {11449545682029299204, 6596199629139963480, 963551988680601724, 698978766831128675, 17425132333529601498, 13413146748170623416}, + {1714656874981820009, 4296884965902036208, 2990962557113972989, 10577651126385226151, 14576461165238503913, 6650017187571610816}, + }, + { + {6245777462138705770, 602174165006002688, 9651995753732157494, 6180859913470161771, 12820839311740267213, 10236566947582409415}, + {11884174684151318817, 15241119462662846032, 6907037784685500586, 8001533132847243248, 3670287336361099984, 3392433665095714529}, + }, + { + {13912308898779395548, 3788232904773170505, 13510110594291767173, 8520990689262136399, 5635271140287576080, 7032476081565599191}, + {3050147342057890882, 5226316271430966932, 11412499390577871486, 11913706106456146646, 4829447444602840419, 14235552292854028654}, + }, + { + {17312195306081130163, 12680842068822272296, 11528293990644984223, 14726421452780975383, 11447257867816650567, 762807127447733227}, + {11172211697797188525, 8517884001168098535, 18342273006866963779, 17586041278289316668, 4779448404822225420, 9813346493235742371}, + }, + { + {9286929404285814938, 8816346852883562511, 7466996584964541958, 5933279471984750642, 1644469041072153982, 11834454051429614839}, + {11689018037377144292, 9302324005187580531, 5409758949060136366, 4109111569593553253, 16829865226968878273, 6434426298631595957}, + }, + { + {16596404332021807148, 11395037243930999642, 6230660960102828038, 14208272099018002212, 8705581668959309002, 7133705014266607355}, + {14252633600291674542, 17382067068187300207, 18138192466898743511, 6530204006214324897, 18284169711456293177, 4900989821334366705}, + }, + { + {5965502925766151340, 3801830478050084251, 6152884788276000974, 10584299273681935132, 2524731521663531672, 15776417203522871638}, + {6285082299497166915, 15290822150488384424, 5578747051433926469, 5845296506012538407, 4823217512374723890, 7213090796321328136}, + }, + { + {1838054042722947491, 18012783215465657741, 1258715365050436512, 7913577973454740911, 7384511648712781941, 4158912753329944154}, + {14299503727251690236, 8238664371507527991, 5075150254794639881, 11556112057563955850, 9196908777829742547, 1421651284198415569}, + }, + { + {7653294651845234281, 297639109833143896, 4336984993054011825, 16447737956972905656, 1714050270655945931, 15452230596345454363}, + {15076547011376710685, 7524806307535928719, 7795256374139730227, 10089448010239318836, 7023465550055784134, 6968423688937605957}, + }, + { + {13092365251897461865, 18278882827386367428, 14555338542207092484, 6910907828139278038, 4543230946116571027, 5044543664197618202}, + {6650151637454194021, 6834808965400326944, 16365723935359292167, 14827804062568090126, 13707520293209424632, 6325303435642990801}, + }, + { + {343357558658755796, 6940253811840342433, 12914150358606642695, 17231336963809853008, 11079943205463705734, 12473223889867436019}, + {15215091930162368566, 11521732813165590119, 4432843582148093137, 2750024527657999932, 9405241261008362249, 10288224084277755975}, + }, + { + {10358507458667546506, 4836195114970556281, 4009596827146315911, 11256224974885245252, 5176303767964952564, 111134394063583597}, + {6393513946378868409, 17037805604945819779, 10171688558016965768, 7858522891516850377, 1914205856134346186, 16973629294504183772}, + }, + { + {10256813334907479264, 17555541259591449755, 10506400127843286281, 3802242808788493442, 16997535067306771110, 8902379766095587425}, + {1036044043924340639, 17424237503082033211, 12387965860513794582, 2930816639468217614, 10629728210657646483, 15009855708899356359}, + }, + }, + { + { + {4454189113653900584, 2369870743683386936, 9771750146904378734, 7229551204834152191, 9308930686126579243, 5564951339003155731}, + {2523209505731486974, 11655219901025790380, 10064955099576512592, 14322381509056856025, 15960759442596276288, 3132442392059561449}, + }, + { + {14421263046720478865, 10262735078638179312, 3820432306672060577, 15745169881456738128, 11281698473866736902, 15822191634431631555}, + {4821811912616493018, 16782915424867765464, 1577651352486052440, 716633372221422297, 508136038908094084, 16377700646398062786}, + }, + { + {424706049021067379, 14217487990368728988, 7719227939353578736, 4199843265846733886, 16388456301404529776, 15169247696432251820}, + {9090595157644861783, 10581077201944372077, 1379900013445280838, 7494321123029536948, 17787926264007537465, 5067787616258265775}, + }, + { + {769698236917518124, 3483900225503109603, 3336909192235363398, 541374049706836141, 18104741290431601017, 14983166848044339752}, + {6121492399965995954, 16666617093809949054, 10249737155929975505, 1473067211573216915, 16575421339110736253, 5806380672117240601}, + }, + { + {13499925512737386719, 13944763802764915814, 9159954083757191227, 6979221481184822758, 14300821660040225990, 16265637021317828603}, + {3128114568639019553, 2504404013570803046, 9274630379913042841, 5414311569178493969, 16628860202352780141, 5598477736550720675}, + }, + { + {9130425033956973272, 14637917817606979898, 17028834835152328690, 3041045091819937813, 5696889246846210875, 14160128160963955776}, + {4567408060924985859, 8330188839918063054, 10075889358467904432, 10649295639077482245, 6371906135676507546, 14525834287139954362}, + }, + { + {16074395804418777643, 5541188270073279665, 8295310521928755861, 6864072771162821613, 17911901316631945045, 10605026599429014107}, + {690935445353571870, 1392537891789610105, 7325904616956299332, 1149398686564874112, 17689896955892401926, 15639337629880458046}, + }, + { + {2591269655907388346, 11399575915049212026, 2043559396265943823, 2133276679198333751, 2052339475550725155, 6752287291455887793}, + {949413463927904836, 9470431435117911687, 8077017638133728996, 16830570160974576546, 8072941217145343758, 4326954112402321249}, + }, + { + {3412919337711024431, 16383399630678254841, 2740801234954712157, 15867621577894919999, 2797972073741634922, 6677462884297174122}, + {17474301298337562800, 3996912168590289455, 2877907669270439874, 12028178698733277400, 9048903683242829652, 16676938495979746758}, + }, + { + {9535591367797480450, 3032516458384811911, 16858722241492443043, 6099583463893158590, 14048493063580960236, 12185142455189643566}, + {13517307410699214798, 262669939477440604, 6425159725529082877, 9337681168995712285, 4468475772573169834, 7978572861495407848}, + }, + { + {14371139353492294781, 4986055967754386106, 994283350302316111, 124059366184412674, 17931249617405877625, 11248278814950278199}, + {8524946062048541221, 6940016701900868483, 4388778906010249088, 3316636379456104494, 4720367297793042554, 11143646688813775128}, + }, + { + {4447383188862483936, 15286779289485640736, 264847228943597281, 17761832039421017475, 5925682522537768028, 7096337516750811757}, + {18071896252632882904, 9283619734214567194, 10122267390711497388, 4667499764407784879, 227971306242715406, 895727107492327229}, + }, + { + {11203525951412289019, 12852755217270479509, 9978444356559295662, 15803698066139233622, 15160649502708391831, 13050401346945170580}, + {17641607277129335085, 15629899850899448002, 8690304923168739299, 13258223666573053280, 9366850728951877315, 5050696512039385569}, + }, + { + {6369749042849981516, 14997591469096472735, 14585781473609538602, 4957906834847789414, 9248310387962593481, 5103185051386294714}, + {13712135472859015397, 6056087516321847761, 2219295526440778687, 8233797578211440273, 7240984299223714420, 4911601582698376693}, + }, + { + {4929990821929415849, 3130583257788034008, 9497231337826843444, 6435653863924772981, 1134942105434085779, 18114272026645693035}, + {2524774042677381563, 7016780555346498950, 5414403864902656268, 15986697199444096112, 9742407776110139287, 6514675658717406998}, + }, + }, + } +} diff --git a/core/crypto/_weierstrass/tools/ecc_gen_tables.odin b/core/crypto/_weierstrass/tools/ecc_gen_tables.odin new file mode 100644 index 000000000..3211c65f3 --- /dev/null +++ b/core/crypto/_weierstrass/tools/ecc_gen_tables.odin @@ -0,0 +1,134 @@ +package weierstrass_tools + +import secec "core:crypto/_weierstrass" +import "core:fmt" +import path "core:path/filepath" +import "core:os" +import "core:strings" + +// Yes this leaks memory, fite me IRL. + +GENERATED :: `/* + ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ +*/` + +main :: proc() { + gen_tables("p256r1") + gen_tables("p384r1") +} + +gen_tables :: proc($CURVE: string) { + when CURVE == "p256r1" { + Affine_Point_p256r1 :: struct { + x: secec.Field_Element_p256r1, + y: secec.Field_Element_p256r1, + } + + Multiply_Table_hi: [32][15]Affine_Point_p256r1 + Multiply_Table_lo: [32][15]Affine_Point_p256r1 + + SC_LEN :: 32 + + g, p: secec.Point_p256r1 + } else when CURVE == "p384r1" { + Affine_Point_p384r1 :: struct { + x: secec.Field_Element_p384r1, + y: secec.Field_Element_p384r1, + } + Multiply_Table_hi: [48][15]Affine_Point_p384r1 + Multiply_Table_lo: [48][15]Affine_Point_p384r1 + + SC_LEN :: 48 + + g, p: secec.Point_p384r1 + } else { + #panic("weistrass/tools: invalid curve") + } + + secec.pt_generator(&g) + + // Precompute ([1,15] << n) * G multiples of G, MSB->LSB + for i in 0.. bool { } if crypto.compare_constant_time(tag, derived_tag) != 1 { - mem.zero_explicit(raw_data(derived_tag), len(derived_tag)) - mem.zero_explicit(raw_data(dst), ct_len) + crypto.zero_explicit(raw_data(derived_tag), len(derived_tag)) + crypto.zero_explicit(raw_data(dst), ct_len) return false } @@ -208,7 +207,7 @@ open :: proc(ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool { // reset sanitizes the Context. The Context must be // re-initialized to be used again. reset :: proc "contextless" (ctx: ^Context) { - mem.zero_explicit(&ctx._key, len(ctx._key)) + crypto.zero_explicit(&ctx._key, len(ctx._key)) ctx._key_len = 0 ctx._is_initialized = false -} +} \ No newline at end of file diff --git a/core/crypto/aegis/aegis_impl_ct64.odin b/core/crypto/aegis/aegis_impl_ct64.odin index 4813b37ec..15a9b4b3d 100644 --- a/core/crypto/aegis/aegis_impl_ct64.odin +++ b/core/crypto/aegis/aegis_impl_ct64.odin @@ -1,8 +1,8 @@ package aegis +import "core:crypto" import aes "core:crypto/_aes/ct64" import "core:encoding/endian" -import "core:mem" // This uses the bitlsiced 64-bit general purpose register SWAR AES // round function. The intermediate state is stored in interleaved @@ -324,7 +324,7 @@ dec_sw_256 :: #force_inline proc "contextless" (st: ^State_SW, xi, ci: []byte) # @(private = "file") dec_partial_sw_128l :: proc "contextless" (st: ^State_SW, xn, cn: []byte) #no_bounds_check { tmp: [_RATE_128L]byte - defer mem.zero_explicit(&tmp, size_of(tmp)) + defer crypto.zero_explicit(&tmp, size_of(tmp)) z0_0, z0_1, z1_0, z1_1 := z_sw_128l(st) copy(tmp[:], cn) @@ -349,7 +349,7 @@ dec_partial_sw_128l :: proc "contextless" (st: ^State_SW, xn, cn: []byte) #no_bo @(private = "file") dec_partial_sw_256 :: proc "contextless" (st: ^State_SW, xn, cn: []byte) #no_bounds_check { tmp: [_RATE_256]byte - defer mem.zero_explicit(&tmp, size_of(tmp)) + defer crypto.zero_explicit(&tmp, size_of(tmp)) z_0, z_1 := z_sw_256(st) copy(tmp[:], cn) @@ -448,5 +448,5 @@ finalize_sw :: proc "contextless" (st: ^State_SW, tag: []byte, ad_len, msg_len: @(private) reset_state_sw :: proc "contextless" (st: ^State_SW) { - mem.zero_explicit(st, size_of(st^)) + crypto.zero_explicit(st, size_of(st^)) } diff --git a/core/crypto/aegis/aegis_impl_hw.odin b/core/crypto/aegis/aegis_impl_hw.odin new file mode 100644 index 000000000..4a39b341c --- /dev/null +++ b/core/crypto/aegis/aegis_impl_hw.odin @@ -0,0 +1,397 @@ +#+build amd64,arm64,arm32 +package aegis + +import "base:intrinsics" +import "core:crypto" +import aes_hw "core:crypto/_aes/hw" +import "core:encoding/endian" +import "core:simd" + +@(private) +State_HW :: struct { + s0: simd.u8x16, + s1: simd.u8x16, + s2: simd.u8x16, + s3: simd.u8x16, + s4: simd.u8x16, + s5: simd.u8x16, + s6: simd.u8x16, + s7: simd.u8x16, + rate: int, +} + +when ODIN_ARCH == .amd64 { + @(private="file") + TARGET_FEATURES :: "sse2,aes" +} else when ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32 { + @(private="file") + TARGET_FEATURES :: "neon,aes" +} + +// is_hardware_accelerated returns true if and only if (⟺) hardware +// accelerated AEGIS is supported. +is_hardware_accelerated :: proc "contextless" () -> bool { + return aes_hw.is_supported() +} + +@(private, enable_target_feature = TARGET_FEATURES) +init_hw :: proc "contextless" (ctx: ^Context, st: ^State_HW, iv: []byte) { + switch ctx._key_len { + case KEY_SIZE_128L: + key := intrinsics.unaligned_load((^simd.u8x16)(&ctx._key[0])) + iv := intrinsics.unaligned_load((^simd.u8x16)(raw_data(iv))) + + st.s0 = simd.bit_xor(key, iv) + st.s1 = intrinsics.unaligned_load((^simd.u8x16)(&_C1[0])) + st.s2 = intrinsics.unaligned_load((^simd.u8x16)(&_C0[0])) + st.s3 = st.s1 + st.s4 = st.s0 + st.s5 = simd.bit_xor(key, st.s2) // key ^ C0 + st.s6 = simd.bit_xor(key, st.s1) // key ^ C1 + st.s7 = st.s5 + st.rate = _RATE_128L + + for _ in 0 ..< 10 { + update_hw_128l(st, iv, key) + } + case KEY_SIZE_256: + k0 := intrinsics.unaligned_load((^simd.u8x16)(&ctx._key[0])) + k1 := intrinsics.unaligned_load((^simd.u8x16)(&ctx._key[16])) + n0 := intrinsics.unaligned_load((^simd.u8x16)(&iv[0])) + n1 := intrinsics.unaligned_load((^simd.u8x16)(&iv[16])) + + st.s0 = simd.bit_xor(k0, n0) + st.s1 = simd.bit_xor(k1, n1) + st.s2 = intrinsics.unaligned_load((^simd.u8x16)(&_C1[0])) + st.s3 = intrinsics.unaligned_load((^simd.u8x16)(&_C0[0])) + st.s4 = simd.bit_xor(k0, st.s3) // k0 ^ C0 + st.s5 = simd.bit_xor(k1, st.s2) // k1 ^ C1 + st.rate = _RATE_256 + + u0, u1 := st.s0, st.s1 + for _ in 0 ..< 4 { + update_hw_256(st, k0) + update_hw_256(st, k1) + update_hw_256(st, u0) + update_hw_256(st, u1) + } + } +} + +@(private = "file", enable_target_feature = TARGET_FEATURES) +update_hw_128l :: #force_inline proc "contextless" (st: ^State_HW, m0, m1: simd.u8x16) { + s0_ := aes_hw.aesenc(st.s7, simd.bit_xor(st.s0, m0)) + s1_ := aes_hw.aesenc(st.s0, st.s1) + s2_ := aes_hw.aesenc(st.s1, st.s2) + s3_ := aes_hw.aesenc(st.s2, st.s3) + s4_ := aes_hw.aesenc(st.s3, simd.bit_xor(st.s4, m1)) + s5_ := aes_hw.aesenc(st.s4, st.s5) + s6_ := aes_hw.aesenc(st.s5, st.s6) + s7_ := aes_hw.aesenc(st.s6, st.s7) + st.s0, st.s1, st.s2, st.s3, st.s4, st.s5, st.s6, st.s7 = s0_, s1_, s2_, s3_, s4_, s5_, s6_, s7_ +} + +@(private = "file", enable_target_feature = TARGET_FEATURES) +update_hw_256 :: #force_inline proc "contextless" (st: ^State_HW, m: simd.u8x16) { + s0_ := aes_hw.aesenc(st.s5, simd.bit_xor(st.s0, m)) + s1_ := aes_hw.aesenc(st.s0, st.s1) + s2_ := aes_hw.aesenc(st.s1, st.s2) + s3_ := aes_hw.aesenc(st.s2, st.s3) + s4_ := aes_hw.aesenc(st.s3, st.s4) + s5_ := aes_hw.aesenc(st.s4, st.s5) + st.s0, st.s1, st.s2, st.s3, st.s4, st.s5 = s0_, s1_, s2_, s3_, s4_, s5_ +} + +@(private = "file", enable_target_feature = TARGET_FEATURES) +absorb_hw_128l :: #force_inline proc "contextless" (st: ^State_HW, ai: []byte) { + t0 := intrinsics.unaligned_load((^simd.u8x16)(&ai[0])) + t1 := intrinsics.unaligned_load((^simd.u8x16)(&ai[16])) + update_hw_128l(st, t0, t1) +} + +@(private = "file", enable_target_feature = TARGET_FEATURES) +absorb_hw_256 :: #force_inline proc "contextless" (st: ^State_HW, ai: []byte) { + m := intrinsics.unaligned_load((^simd.u8x16)(&ai[0])) + update_hw_256(st, m) +} + +@(private, enable_target_feature = TARGET_FEATURES) +absorb_hw :: proc "contextless" (st: ^State_HW, aad: []byte) #no_bounds_check { + ai, l := aad, len(aad) + + switch st.rate { + case _RATE_128L: + for l >= _RATE_128L { + absorb_hw_128l(st, ai) + ai = ai[_RATE_128L:] + l -= _RATE_128L + } + case _RATE_256: + for l >= _RATE_256 { + absorb_hw_256(st, ai) + + ai = ai[_RATE_256:] + l -= _RATE_256 + } + } + + // Pad out the remainder with `0`s till it is rate sized. + if l > 0 { + tmp: [_RATE_MAX]byte // AAD is not confidential. + copy(tmp[:], ai) + switch st.rate { + case _RATE_128L: + absorb_hw_128l(st, tmp[:]) + case _RATE_256: + absorb_hw_256(st, tmp[:]) + } + } +} + +@(private = "file", enable_target_feature = TARGET_FEATURES, require_results) +z_hw_128l :: #force_inline proc "contextless" (st: ^State_HW) -> (simd.u8x16, simd.u8x16) { + z0 := simd.bit_xor( + st.s6, + simd.bit_xor( + st.s1, + simd.bit_and(st.s2, st.s3), + ), + ) + z1 := simd.bit_xor( + st.s2, + simd.bit_xor( + st.s5, + simd.bit_and(st.s6, st.s7), + ), + ) + return z0, z1 +} + +@(private = "file", enable_target_feature = TARGET_FEATURES, require_results) +z_hw_256 :: #force_inline proc "contextless" (st: ^State_HW) -> simd.u8x16 { + return simd.bit_xor( + st.s1, + simd.bit_xor( + st.s4, + simd.bit_xor( + st.s5, + simd.bit_and(st.s2, st.s3), + ), + ), + ) +} + +@(private = "file", enable_target_feature = TARGET_FEATURES) +enc_hw_128l :: #force_inline proc "contextless" (st: ^State_HW, ci, xi: []byte) #no_bounds_check { + z0, z1 := z_hw_128l(st) + + t0 := intrinsics.unaligned_load((^simd.u8x16)(&xi[0])) + t1 := intrinsics.unaligned_load((^simd.u8x16)(&xi[16])) + update_hw_128l(st, t0, t1) + + out0 := simd.bit_xor(t0, z0) + out1 := simd.bit_xor(t1, z1) + intrinsics.unaligned_store((^simd.u8x16)(&ci[0]), out0) + intrinsics.unaligned_store((^simd.u8x16)(&ci[16]), out1) +} + +@(private = "file", enable_target_feature = TARGET_FEATURES) +enc_hw_256 :: #force_inline proc "contextless" (st: ^State_HW, ci, xi: []byte) #no_bounds_check { + z := z_hw_256(st) + + xi_ := intrinsics.unaligned_load((^simd.u8x16)(raw_data(xi))) + update_hw_256(st, xi_) + + ci_ := simd.bit_xor(xi_, z) + intrinsics.unaligned_store((^simd.u8x16)(raw_data(ci)), ci_) +} + +@(private, enable_target_feature = TARGET_FEATURES) +enc_hw :: proc "contextless" (st: ^State_HW, dst, src: []byte) #no_bounds_check { + ci, xi, l := dst, src, len(src) + + switch st.rate { + case _RATE_128L: + for l >= _RATE_128L { + enc_hw_128l(st, ci, xi) + ci = ci[_RATE_128L:] + xi = xi[_RATE_128L:] + l -= _RATE_128L + } + case _RATE_256: + for l >= _RATE_256 { + enc_hw_256(st, ci, xi) + ci = ci[_RATE_256:] + xi = xi[_RATE_256:] + l -= _RATE_256 + } + } + + // Pad out the remainder with `0`s till it is rate sized. + if l > 0 { + tmp: [_RATE_MAX]byte // Ciphertext is not confidential. + copy(tmp[:], xi) + switch st.rate { + case _RATE_128L: + enc_hw_128l(st, tmp[:], tmp[:]) + case _RATE_256: + enc_hw_256(st, tmp[:], tmp[:]) + } + copy(ci, tmp[:l]) + } +} + +@(private = "file", enable_target_feature = TARGET_FEATURES) +dec_hw_128l :: #force_inline proc "contextless" (st: ^State_HW, xi, ci: []byte) #no_bounds_check { + z0, z1 := z_hw_128l(st) + + t0 := intrinsics.unaligned_load((^simd.u8x16)(&ci[0])) + t1 := intrinsics.unaligned_load((^simd.u8x16)(&ci[16])) + out0 := simd.bit_xor(t0, z0) + out1 := simd.bit_xor(t1, z1) + + update_hw_128l(st, out0, out1) + intrinsics.unaligned_store((^simd.u8x16)(&xi[0]), out0) + intrinsics.unaligned_store((^simd.u8x16)(&xi[16]), out1) +} + +@(private = "file", enable_target_feature = TARGET_FEATURES) +dec_hw_256 :: #force_inline proc "contextless" (st: ^State_HW, xi, ci: []byte) #no_bounds_check { + z := z_hw_256(st) + + ci_ := intrinsics.unaligned_load((^simd.u8x16)(raw_data(ci))) + xi_ := simd.bit_xor(ci_, z) + + update_hw_256(st, xi_) + intrinsics.unaligned_store((^simd.u8x16)(raw_data(xi)), xi_) +} + +@(private = "file", enable_target_feature = TARGET_FEATURES) +dec_partial_hw_128l :: #force_inline proc "contextless" (st: ^State_HW, xn, cn: []byte) #no_bounds_check { + tmp: [_RATE_128L]byte + defer crypto.zero_explicit(&tmp, size_of(tmp)) + + z0, z1 := z_hw_128l(st) + copy(tmp[:], cn) + + t0 := intrinsics.unaligned_load((^simd.u8x16)(&tmp[0])) + t1 := intrinsics.unaligned_load((^simd.u8x16)(&tmp[16])) + out0 := simd.bit_xor(t0, z0) + out1 := simd.bit_xor(t1, z1) + + intrinsics.unaligned_store((^simd.u8x16)(&tmp[0]), out0) + intrinsics.unaligned_store((^simd.u8x16)(&tmp[16]), out1) + copy(xn, tmp[:]) + + for off := len(xn); off < _RATE_128L; off += 1 { + tmp[off] = 0 + } + out0 = intrinsics.unaligned_load((^simd.u8x16)(&tmp[0])) // v0 + out1 = intrinsics.unaligned_load((^simd.u8x16)(&tmp[16])) // v1 + update_hw_128l(st, out0, out1) +} + +@(private = "file", enable_target_feature = TARGET_FEATURES) +dec_partial_hw_256 :: #force_inline proc "contextless" (st: ^State_HW, xn, cn: []byte) #no_bounds_check { + tmp: [_RATE_256]byte + defer crypto.zero_explicit(&tmp, size_of(tmp)) + + z := z_hw_256(st) + copy(tmp[:], cn) + + cn_ := intrinsics.unaligned_load((^simd.u8x16)(&tmp[0])) + xn_ := simd.bit_xor(cn_, z) + + intrinsics.unaligned_store((^simd.u8x16)(&tmp[0]), xn_) + copy(xn, tmp[:]) + + for off := len(xn); off < _RATE_256; off += 1 { + tmp[off] = 0 + } + xn_ = intrinsics.unaligned_load((^simd.u8x16)(&tmp[0])) + update_hw_256(st, xn_) +} + +@(private, enable_target_feature = TARGET_FEATURES) +dec_hw :: proc "contextless" (st: ^State_HW, dst, src: []byte) #no_bounds_check { + xi, ci, l := dst, src, len(src) + + switch st.rate { + case _RATE_128L: + for l >= _RATE_128L { + dec_hw_128l(st, xi, ci) + xi = xi[_RATE_128L:] + ci = ci[_RATE_128L:] + l -= _RATE_128L + } + case _RATE_256: + for l >= _RATE_256 { + dec_hw_256(st, xi, ci) + xi = xi[_RATE_256:] + ci = ci[_RATE_256:] + l -= _RATE_256 + } + } + + // Process the remainder. + if l > 0 { + switch st.rate { + case _RATE_128L: + dec_partial_hw_128l(st, xi, ci) + case _RATE_256: + dec_partial_hw_256(st, xi, ci) + } + } +} + +@(private, enable_target_feature = TARGET_FEATURES) +finalize_hw :: proc "contextless" (st: ^State_HW, tag: []byte, ad_len, msg_len: int) { + tmp: [16]byte + endian.unchecked_put_u64le(tmp[0:], u64(ad_len) * 8) + endian.unchecked_put_u64le(tmp[8:], u64(msg_len) * 8) + + t := intrinsics.unaligned_load((^simd.u8x16)(&tmp[0])) + + t0, t1: simd.u8x16 = ---, --- + switch st.rate { + case _RATE_128L: + t = simd.bit_xor(st.s2, t) + for _ in 0 ..< 7 { + update_hw_128l(st, t, t) + } + + t0 = simd.bit_xor(st.s0, st.s1) + t0 = simd.bit_xor(t0, st.s2) + t0 = simd.bit_xor(t0, st.s3) + + t1 = simd.bit_xor(st.s4, st.s5) + t1 = simd.bit_xor(t1, st.s6) + if len(tag) == TAG_SIZE_256 { + t1 = simd.bit_xor(t1, st.s7) + } + case _RATE_256: + t = simd.bit_xor(st.s3, t) + for _ in 0 ..< 7 { + update_hw_256(st, t) + } + + t0 = simd.bit_xor(st.s0, st.s1) + t0 = simd.bit_xor(t0, st.s2) + + t1 = simd.bit_xor(st.s3, st.s4) + t1 = simd.bit_xor(t1, st.s5) + } + switch len(tag) { + case TAG_SIZE_128: + t0 = simd.bit_xor(t0, t1) + intrinsics.unaligned_store((^simd.u8x16)(&tag[0]), t0) + case TAG_SIZE_256: + intrinsics.unaligned_store((^simd.u8x16)(&tag[0]), t0) + intrinsics.unaligned_store((^simd.u8x16)(&tag[16]), t1) + } +} + +@(private) +reset_state_hw :: proc "contextless" (st: ^State_HW) { + crypto.zero_explicit(st, size_of(st^)) +} diff --git a/core/crypto/aegis/aegis_impl_hw_gen.odin b/core/crypto/aegis/aegis_impl_hw_gen.odin index 5ec2f3d6e..8f8b4c5da 100644 --- a/core/crypto/aegis/aegis_impl_hw_gen.odin +++ b/core/crypto/aegis/aegis_impl_hw_gen.odin @@ -1,4 +1,6 @@ #+build !amd64 +#+build !arm64 +#+build !arm32 package aegis @(private = "file") @@ -7,7 +9,7 @@ ERR_HW_NOT_SUPPORTED :: "crypto/aegis: hardware implementation unsupported" @(private) State_HW :: struct {} -// is_hardware_accelerated returns true iff hardware accelerated AEGIS +// is_hardware_accelerated returns true if and only if (⟺) hardware accelerated AEGIS // is supported. is_hardware_accelerated :: proc "contextless" () -> bool { return false diff --git a/core/crypto/aegis/aegis_impl_hw_intel.odin b/core/crypto/aegis/aegis_impl_hw_intel.odin deleted file mode 100644 index 5334f3258..000000000 --- a/core/crypto/aegis/aegis_impl_hw_intel.odin +++ /dev/null @@ -1,389 +0,0 @@ -#+build amd64 -package aegis - -import "base:intrinsics" -import "core:crypto/aes" -import "core:encoding/endian" -import "core:mem" -import "core:simd/x86" - -@(private) -State_HW :: struct { - s0: x86.__m128i, - s1: x86.__m128i, - s2: x86.__m128i, - s3: x86.__m128i, - s4: x86.__m128i, - s5: x86.__m128i, - s6: x86.__m128i, - s7: x86.__m128i, - rate: int, -} - -// is_hardware_accelerated returns true iff hardware accelerated AEGIS -// is supported. -is_hardware_accelerated :: proc "contextless" () -> bool { - return aes.is_hardware_accelerated() -} - -@(private, enable_target_feature = "sse2,aes") -init_hw :: proc "contextless" (ctx: ^Context, st: ^State_HW, iv: []byte) { - switch ctx._key_len { - case KEY_SIZE_128L: - key := intrinsics.unaligned_load((^x86.__m128i)(&ctx._key[0])) - iv := intrinsics.unaligned_load((^x86.__m128i)(raw_data(iv))) - - st.s0 = x86._mm_xor_si128(key, iv) - st.s1 = intrinsics.unaligned_load((^x86.__m128i)(&_C1[0])) - st.s2 = intrinsics.unaligned_load((^x86.__m128i)(&_C0[0])) - st.s3 = st.s1 - st.s4 = st.s0 - st.s5 = x86._mm_xor_si128(key, st.s2) // key ^ C0 - st.s6 = x86._mm_xor_si128(key, st.s1) // key ^ C1 - st.s7 = st.s5 - st.rate = _RATE_128L - - for _ in 0 ..< 10 { - update_hw_128l(st, iv, key) - } - case KEY_SIZE_256: - k0 := intrinsics.unaligned_load((^x86.__m128i)(&ctx._key[0])) - k1 := intrinsics.unaligned_load((^x86.__m128i)(&ctx._key[16])) - n0 := intrinsics.unaligned_load((^x86.__m128i)(&iv[0])) - n1 := intrinsics.unaligned_load((^x86.__m128i)(&iv[16])) - - st.s0 = x86._mm_xor_si128(k0, n0) - st.s1 = x86._mm_xor_si128(k1, n1) - st.s2 = intrinsics.unaligned_load((^x86.__m128i)(&_C1[0])) - st.s3 = intrinsics.unaligned_load((^x86.__m128i)(&_C0[0])) - st.s4 = x86._mm_xor_si128(k0, st.s3) // k0 ^ C0 - st.s5 = x86._mm_xor_si128(k1, st.s2) // k1 ^ C1 - st.rate = _RATE_256 - - u0, u1 := st.s0, st.s1 - for _ in 0 ..< 4 { - update_hw_256(st, k0) - update_hw_256(st, k1) - update_hw_256(st, u0) - update_hw_256(st, u1) - } - } -} - -@(private = "file", enable_target_feature = "sse2,aes") -update_hw_128l :: #force_inline proc "contextless" (st: ^State_HW, m0, m1: x86.__m128i) { - s0_ := x86._mm_aesenc_si128(st.s7, x86._mm_xor_si128(st.s0, m0)) - s1_ := x86._mm_aesenc_si128(st.s0, st.s1) - s2_ := x86._mm_aesenc_si128(st.s1, st.s2) - s3_ := x86._mm_aesenc_si128(st.s2, st.s3) - s4_ := x86._mm_aesenc_si128(st.s3, x86._mm_xor_si128(st.s4, m1)) - s5_ := x86._mm_aesenc_si128(st.s4, st.s5) - s6_ := x86._mm_aesenc_si128(st.s5, st.s6) - s7_ := x86._mm_aesenc_si128(st.s6, st.s7) - st.s0, st.s1, st.s2, st.s3, st.s4, st.s5, st.s6, st.s7 = s0_, s1_, s2_, s3_, s4_, s5_, s6_, s7_ -} - -@(private = "file", enable_target_feature = "sse2,aes") -update_hw_256 :: #force_inline proc "contextless" (st: ^State_HW, m: x86.__m128i) { - s0_ := x86._mm_aesenc_si128(st.s5, x86._mm_xor_si128(st.s0, m)) - s1_ := x86._mm_aesenc_si128(st.s0, st.s1) - s2_ := x86._mm_aesenc_si128(st.s1, st.s2) - s3_ := x86._mm_aesenc_si128(st.s2, st.s3) - s4_ := x86._mm_aesenc_si128(st.s3, st.s4) - s5_ := x86._mm_aesenc_si128(st.s4, st.s5) - st.s0, st.s1, st.s2, st.s3, st.s4, st.s5 = s0_, s1_, s2_, s3_, s4_, s5_ -} - -@(private = "file", enable_target_feature = "sse2,aes") -absorb_hw_128l :: #force_inline proc "contextless" (st: ^State_HW, ai: []byte) { - t0 := intrinsics.unaligned_load((^x86.__m128i)(&ai[0])) - t1 := intrinsics.unaligned_load((^x86.__m128i)(&ai[16])) - update_hw_128l(st, t0, t1) -} - -@(private = "file", enable_target_feature = "sse2,aes") -absorb_hw_256 :: #force_inline proc "contextless" (st: ^State_HW, ai: []byte) { - m := intrinsics.unaligned_load((^x86.__m128i)(&ai[0])) - update_hw_256(st, m) -} - -@(private, enable_target_feature = "sse2,aes") -absorb_hw :: proc "contextless" (st: ^State_HW, aad: []byte) #no_bounds_check { - ai, l := aad, len(aad) - - switch st.rate { - case _RATE_128L: - for l >= _RATE_128L { - absorb_hw_128l(st, ai) - ai = ai[_RATE_128L:] - l -= _RATE_128L - } - case _RATE_256: - for l >= _RATE_256 { - absorb_hw_256(st, ai) - - ai = ai[_RATE_256:] - l -= _RATE_256 - } - } - - // Pad out the remainder with `0`s till it is rate sized. - if l > 0 { - tmp: [_RATE_MAX]byte // AAD is not confidential. - copy(tmp[:], ai) - switch st.rate { - case _RATE_128L: - absorb_hw_128l(st, tmp[:]) - case _RATE_256: - absorb_hw_256(st, tmp[:]) - } - } -} - -@(private = "file", enable_target_feature = "sse2", require_results) -z_hw_128l :: #force_inline proc "contextless" (st: ^State_HW) -> (x86.__m128i, x86.__m128i) { - z0 := x86._mm_xor_si128( - st.s6, - x86._mm_xor_si128( - st.s1, - x86._mm_and_si128(st.s2, st.s3), - ), - ) - z1 := x86._mm_xor_si128( - st.s2, - x86._mm_xor_si128( - st.s5, - x86._mm_and_si128(st.s6, st.s7), - ), - ) - return z0, z1 -} - -@(private = "file", enable_target_feature = "sse2", require_results) -z_hw_256 :: #force_inline proc "contextless" (st: ^State_HW) -> x86.__m128i { - return x86._mm_xor_si128( - st.s1, - x86._mm_xor_si128( - st.s4, - x86._mm_xor_si128( - st.s5, - x86._mm_and_si128(st.s2, st.s3), - ), - ), - ) -} - -@(private = "file", enable_target_feature = "sse2,aes") -enc_hw_128l :: #force_inline proc "contextless" (st: ^State_HW, ci, xi: []byte) #no_bounds_check { - z0, z1 := z_hw_128l(st) - - t0 := intrinsics.unaligned_load((^x86.__m128i)(&xi[0])) - t1 := intrinsics.unaligned_load((^x86.__m128i)(&xi[16])) - update_hw_128l(st, t0, t1) - - out0 := x86._mm_xor_si128(t0, z0) - out1 := x86._mm_xor_si128(t1, z1) - intrinsics.unaligned_store((^x86.__m128i)(&ci[0]), out0) - intrinsics.unaligned_store((^x86.__m128i)(&ci[16]), out1) -} - -@(private = "file", enable_target_feature = "sse2,aes") -enc_hw_256 :: #force_inline proc "contextless" (st: ^State_HW, ci, xi: []byte) #no_bounds_check { - z := z_hw_256(st) - - xi_ := intrinsics.unaligned_load((^x86.__m128i)(raw_data(xi))) - update_hw_256(st, xi_) - - ci_ := x86._mm_xor_si128(xi_, z) - intrinsics.unaligned_store((^x86.__m128i)(raw_data(ci)), ci_) -} - -@(private, enable_target_feature = "sse2,aes") -enc_hw :: proc "contextless" (st: ^State_HW, dst, src: []byte) #no_bounds_check { - ci, xi, l := dst, src, len(src) - - switch st.rate { - case _RATE_128L: - for l >= _RATE_128L { - enc_hw_128l(st, ci, xi) - ci = ci[_RATE_128L:] - xi = xi[_RATE_128L:] - l -= _RATE_128L - } - case _RATE_256: - for l >= _RATE_256 { - enc_hw_256(st, ci, xi) - ci = ci[_RATE_256:] - xi = xi[_RATE_256:] - l -= _RATE_256 - } - } - - // Pad out the remainder with `0`s till it is rate sized. - if l > 0 { - tmp: [_RATE_MAX]byte // Ciphertext is not confidential. - copy(tmp[:], xi) - switch st.rate { - case _RATE_128L: - enc_hw_128l(st, tmp[:], tmp[:]) - case _RATE_256: - enc_hw_256(st, tmp[:], tmp[:]) - } - copy(ci, tmp[:l]) - } -} - -@(private = "file", enable_target_feature = "sse2,aes") -dec_hw_128l :: #force_inline proc "contextless" (st: ^State_HW, xi, ci: []byte) #no_bounds_check { - z0, z1 := z_hw_128l(st) - - t0 := intrinsics.unaligned_load((^x86.__m128i)(&ci[0])) - t1 := intrinsics.unaligned_load((^x86.__m128i)(&ci[16])) - out0 := x86._mm_xor_si128(t0, z0) - out1 := x86._mm_xor_si128(t1, z1) - - update_hw_128l(st, out0, out1) - intrinsics.unaligned_store((^x86.__m128i)(&xi[0]), out0) - intrinsics.unaligned_store((^x86.__m128i)(&xi[16]), out1) -} - -@(private = "file", enable_target_feature = "sse2,aes") -dec_hw_256 :: #force_inline proc "contextless" (st: ^State_HW, xi, ci: []byte) #no_bounds_check { - z := z_hw_256(st) - - ci_ := intrinsics.unaligned_load((^x86.__m128i)(raw_data(ci))) - xi_ := x86._mm_xor_si128(ci_, z) - - update_hw_256(st, xi_) - intrinsics.unaligned_store((^x86.__m128i)(raw_data(xi)), xi_) -} - -@(private = "file", enable_target_feature = "sse2,aes") -dec_partial_hw_128l :: #force_inline proc "contextless" (st: ^State_HW, xn, cn: []byte) #no_bounds_check { - tmp: [_RATE_128L]byte - defer mem.zero_explicit(&tmp, size_of(tmp)) - - z0, z1 := z_hw_128l(st) - copy(tmp[:], cn) - - t0 := intrinsics.unaligned_load((^x86.__m128i)(&tmp[0])) - t1 := intrinsics.unaligned_load((^x86.__m128i)(&tmp[16])) - out0 := x86._mm_xor_si128(t0, z0) - out1 := x86._mm_xor_si128(t1, z1) - - intrinsics.unaligned_store((^x86.__m128i)(&tmp[0]), out0) - intrinsics.unaligned_store((^x86.__m128i)(&tmp[16]), out1) - copy(xn, tmp[:]) - - for off := len(xn); off < _RATE_128L; off += 1 { - tmp[off] = 0 - } - out0 = intrinsics.unaligned_load((^x86.__m128i)(&tmp[0])) // v0 - out1 = intrinsics.unaligned_load((^x86.__m128i)(&tmp[16])) // v1 - update_hw_128l(st, out0, out1) -} - -@(private = "file", enable_target_feature = "sse2,aes") -dec_partial_hw_256 :: #force_inline proc "contextless" (st: ^State_HW, xn, cn: []byte) #no_bounds_check { - tmp: [_RATE_256]byte - defer mem.zero_explicit(&tmp, size_of(tmp)) - - z := z_hw_256(st) - copy(tmp[:], cn) - - cn_ := intrinsics.unaligned_load((^x86.__m128i)(&tmp[0])) - xn_ := x86._mm_xor_si128(cn_, z) - - intrinsics.unaligned_store((^x86.__m128i)(&tmp[0]), xn_) - copy(xn, tmp[:]) - - for off := len(xn); off < _RATE_256; off += 1 { - tmp[off] = 0 - } - xn_ = intrinsics.unaligned_load((^x86.__m128i)(&tmp[0])) - update_hw_256(st, xn_) -} - -@(private, enable_target_feature = "sse2,aes") -dec_hw :: proc "contextless" (st: ^State_HW, dst, src: []byte) #no_bounds_check { - xi, ci, l := dst, src, len(src) - - switch st.rate { - case _RATE_128L: - for l >= _RATE_128L { - dec_hw_128l(st, xi, ci) - xi = xi[_RATE_128L:] - ci = ci[_RATE_128L:] - l -= _RATE_128L - } - case _RATE_256: - for l >= _RATE_256 { - dec_hw_256(st, xi, ci) - xi = xi[_RATE_256:] - ci = ci[_RATE_256:] - l -= _RATE_256 - } - } - - // Process the remainder. - if l > 0 { - switch st.rate { - case _RATE_128L: - dec_partial_hw_128l(st, xi, ci) - case _RATE_256: - dec_partial_hw_256(st, xi, ci) - } - } -} - -@(private, enable_target_feature = "sse2,aes") -finalize_hw :: proc "contextless" (st: ^State_HW, tag: []byte, ad_len, msg_len: int) { - tmp: [16]byte - endian.unchecked_put_u64le(tmp[0:], u64(ad_len) * 8) - endian.unchecked_put_u64le(tmp[8:], u64(msg_len) * 8) - - t := intrinsics.unaligned_load((^x86.__m128i)(&tmp[0])) - - t0, t1: x86.__m128i = ---, --- - switch st.rate { - case _RATE_128L: - t = x86._mm_xor_si128(st.s2, t) - for _ in 0 ..< 7 { - update_hw_128l(st, t, t) - } - - t0 = x86._mm_xor_si128(st.s0, st.s1) - t0 = x86._mm_xor_si128(t0, st.s2) - t0 = x86._mm_xor_si128(t0, st.s3) - - t1 = x86._mm_xor_si128(st.s4, st.s5) - t1 = x86._mm_xor_si128(t1, st.s6) - if len(tag) == TAG_SIZE_256 { - t1 = x86._mm_xor_si128(t1, st.s7) - } - case _RATE_256: - t = x86._mm_xor_si128(st.s3, t) - for _ in 0 ..< 7 { - update_hw_256(st, t) - } - - t0 = x86._mm_xor_si128(st.s0, st.s1) - t0 = x86._mm_xor_si128(t0, st.s2) - - t1 = x86._mm_xor_si128(st.s3, st.s4) - t1 = x86._mm_xor_si128(t1, st.s5) - } - switch len(tag) { - case TAG_SIZE_128: - t0 = x86._mm_xor_si128(t0, t1) - intrinsics.unaligned_store((^x86.__m128i)(&tag[0]), t0) - case TAG_SIZE_256: - intrinsics.unaligned_store((^x86.__m128i)(&tag[0]), t0) - intrinsics.unaligned_store((^x86.__m128i)(&tag[16]), t1) - } -} - -@(private) -reset_state_hw :: proc "contextless" (st: ^State_HW) { - mem.zero_explicit(st, size_of(st^)) -} diff --git a/core/crypto/aes/aes_ctr.odin b/core/crypto/aes/aes_ctr.odin index a74133235..9d7a0b80b 100644 --- a/core/crypto/aes/aes_ctr.odin +++ b/core/crypto/aes/aes_ctr.odin @@ -4,7 +4,6 @@ import "core:bytes" import "core:crypto/_aes/ct64" import "core:encoding/endian" import "core:math/bits" -import "core:mem" // CTR_IV_SIZE is the size of the CTR mode IV in bytes. CTR_IV_SIZE :: 16 @@ -117,7 +116,7 @@ reset_ctr :: proc "contextless" (ctx: ^Context_CTR) { ctx._off = 0 ctx._ctr_hi = 0 ctx._ctr_lo = 0 - mem.zero_explicit(&ctx._buffer, size_of(ctx._buffer)) + zero_explicit(&ctx._buffer, size_of(ctx._buffer)) ctx._is_initialized = false } @@ -172,7 +171,7 @@ ctr_blocks :: proc(ctx: ^Context_CTR, dst, src: []byte, nr_blocks: int) #no_boun // Write back the counter. ctx._ctr_hi, ctx._ctr_lo = ctr_hi, ctr_lo - mem.zero_explicit(&tmp, size_of(tmp)) + zero_explicit(&tmp, size_of(tmp)) } @(private) diff --git a/core/crypto/aes/aes_ctr_hw_intel.odin b/core/crypto/aes/aes_ctr_hw.odin similarity index 60% rename from core/crypto/aes/aes_ctr_hw_intel.odin rename to core/crypto/aes/aes_ctr_hw.odin index 415758b24..859b63a40 100644 --- a/core/crypto/aes/aes_ctr_hw_intel.odin +++ b/core/crypto/aes/aes_ctr_hw.odin @@ -1,31 +1,32 @@ -#+build amd64 +#+build amd64,arm64,arm32 package aes import "base:intrinsics" import "core:crypto/_aes" +import aes_hw "core:crypto/_aes/hw" +import "core:encoding/endian" import "core:math/bits" -import "core:mem" -import "core:simd/x86" +import "core:simd" @(private) CTR_STRIDE_HW :: 4 @(private) CTR_STRIDE_BYTES_HW :: CTR_STRIDE_HW * BLOCK_SIZE -@(private, enable_target_feature = "sse2,aes") +@(private, enable_target_feature = aes_hw.TARGET_FEATURES) ctr_blocks_hw :: proc(ctx: ^Context_CTR, dst, src: []byte, nr_blocks: int) #no_bounds_check { hw_ctx := ctx._impl.(Context_Impl_Hardware) - sks: [15]x86.__m128i = --- + sks: [15]simd.u8x16 = --- for i in 0 ..= hw_ctx._num_rounds { - sks[i] = intrinsics.unaligned_load((^x86.__m128i)(&hw_ctx._sk_exp_enc[i])) + sks[i] = intrinsics.unaligned_load((^simd.u8x16)(&hw_ctx._sk_exp_enc[i])) } - hw_inc_ctr := #force_inline proc "contextless" (hi, lo: u64) -> (x86.__m128i, u64, u64) { - ret := x86.__m128i{ - i64(intrinsics.byte_swap(hi)), - i64(intrinsics.byte_swap(lo)), - } + hw_inc_ctr := #force_inline proc "contextless" (hi, lo: u64) -> (simd.u8x16, u64, u64) { + buf: [BLOCK_SIZE]byte = --- + endian.unchecked_put_u64be(buf[0:], hi) + endian.unchecked_put_u64be(buf[8:], lo) + ret := intrinsics.unaligned_load((^simd.u8x16)(&buf)) hi, lo := hi, lo carry: u64 @@ -47,42 +48,42 @@ ctr_blocks_hw :: proc(ctx: ^Context_CTR, dst, src: []byte, nr_blocks: int) #no_b nr_blocks := nr_blocks ctr_hi, ctr_lo := ctx._ctr_hi, ctx._ctr_lo - blks: [CTR_STRIDE_HW]x86.__m128i = --- + blks: [CTR_STRIDE_HW]simd.u8x16 = --- for nr_blocks >= CTR_STRIDE_HW { #unroll for i in 0..< CTR_STRIDE_HW { blks[i], ctr_hi, ctr_lo = hw_inc_ctr(ctr_hi, ctr_lo) } #unroll for i in 0 ..< CTR_STRIDE_HW { - blks[i] = x86._mm_xor_si128(blks[i], sks[0]) + blks[i] = simd.bit_xor(blks[i], sks[0]) } #unroll for i in 1 ..= 9 { #unroll for j in 0 ..< CTR_STRIDE_HW { - blks[j] = x86._mm_aesenc_si128(blks[j], sks[i]) + blks[j] = aes_hw.aesenc(blks[j], sks[i]) } } switch hw_ctx._num_rounds { case _aes.ROUNDS_128: #unroll for i in 0 ..< CTR_STRIDE_HW { - blks[i] = x86._mm_aesenclast_si128(blks[i], sks[10]) + blks[i] = aes_hw.aesenclast(blks[i], sks[10]) } case _aes.ROUNDS_192: #unroll for i in 10 ..= 11 { #unroll for j in 0 ..< CTR_STRIDE_HW { - blks[j] = x86._mm_aesenc_si128(blks[j], sks[i]) + blks[j] = aes_hw.aesenc(blks[j], sks[i]) } } #unroll for i in 0 ..< CTR_STRIDE_HW { - blks[i] = x86._mm_aesenclast_si128(blks[i], sks[12]) + blks[i] = aes_hw.aesenclast(blks[i], sks[12]) } case _aes.ROUNDS_256: #unroll for i in 10 ..= 13 { #unroll for j in 0 ..< CTR_STRIDE_HW { - blks[j] = x86._mm_aesenc_si128(blks[j], sks[i]) + blks[j] = aes_hw.aesenc(blks[j], sks[i]) } } #unroll for i in 0 ..< CTR_STRIDE_HW { - blks[i] = x86._mm_aesenclast_si128(blks[i], sks[14]) + blks[i] = aes_hw.aesenclast(blks[i], sks[14]) } } @@ -99,23 +100,23 @@ ctr_blocks_hw :: proc(ctx: ^Context_CTR, dst, src: []byte, nr_blocks: int) #no_b for nr_blocks > 0 { blks[0], ctr_hi, ctr_lo = hw_inc_ctr(ctr_hi, ctr_lo) - blks[0] = x86._mm_xor_si128(blks[0], sks[0]) + blks[0] = simd.bit_xor(blks[0], sks[0]) #unroll for i in 1 ..= 9 { - blks[0] = x86._mm_aesenc_si128(blks[0], sks[i]) + blks[0] = aes_hw.aesenc(blks[0], sks[i]) } switch hw_ctx._num_rounds { case _aes.ROUNDS_128: - blks[0] = x86._mm_aesenclast_si128(blks[0], sks[10]) + blks[0] = aes_hw.aesenclast(blks[0], sks[10]) case _aes.ROUNDS_192: #unroll for i in 10 ..= 11 { - blks[0] = x86._mm_aesenc_si128(blks[0], sks[i]) + blks[0] = aes_hw.aesenc(blks[0], sks[i]) } - blks[0] = x86._mm_aesenclast_si128(blks[0], sks[12]) + blks[0] = aes_hw.aesenclast(blks[0], sks[12]) case _aes.ROUNDS_256: #unroll for i in 10 ..= 13 { - blks[0] = x86._mm_aesenc_si128(blks[0], sks[i]) + blks[0] = aes_hw.aesenc(blks[0], sks[i]) } - blks[0] = x86._mm_aesenclast_si128(blks[0], sks[14]) + blks[0] = aes_hw.aesenclast(blks[0], sks[14]) } xor_blocks_hw(dst, src, blks[:1]) @@ -130,22 +131,22 @@ ctr_blocks_hw :: proc(ctx: ^Context_CTR, dst, src: []byte, nr_blocks: int) #no_b // Write back the counter. ctx._ctr_hi, ctx._ctr_lo = ctr_hi, ctr_lo - mem.zero_explicit(&blks, size_of(blks)) - mem.zero_explicit(&sks, size_of(sks)) + zero_explicit(&blks, size_of(blks)) + zero_explicit(&sks, size_of(sks)) } -@(private, enable_target_feature = "sse2") -xor_blocks_hw :: proc(dst, src: []byte, blocks: []x86.__m128i) { +@(private, enable_target_feature = aes_hw.TARGET_FEATURES) +xor_blocks_hw :: proc(dst, src: []byte, blocks: []simd.u8x16) { #no_bounds_check { if src != nil { for i in 0 ..< len(blocks) { off := i * BLOCK_SIZE - tmp := intrinsics.unaligned_load((^x86.__m128i)(raw_data(src[off:]))) - blocks[i] = x86._mm_xor_si128(blocks[i], tmp) + tmp := intrinsics.unaligned_load((^simd.u8x16)(raw_data(src[off:]))) + blocks[i] = simd.bit_xor(blocks[i], tmp) } } for i in 0 ..< len(blocks) { - intrinsics.unaligned_store((^x86.__m128i)(raw_data(dst[i * BLOCK_SIZE:])), blocks[i]) + intrinsics.unaligned_store((^simd.u8x16)(raw_data(dst[i * BLOCK_SIZE:])), blocks[i]) } } } diff --git a/core/crypto/aes/aes_ecb_hw.odin b/core/crypto/aes/aes_ecb_hw.odin new file mode 100644 index 000000000..87a006d9b --- /dev/null +++ b/core/crypto/aes/aes_ecb_hw.odin @@ -0,0 +1,59 @@ +#+build amd64,arm64,arm32 +package aes + +import "base:intrinsics" +import "core:crypto/_aes" +import aes_hw "core:crypto/_aes/hw" +import "core:simd" + +@(private, enable_target_feature = aes_hw.TARGET_FEATURES) +encrypt_block_hw :: proc(ctx: ^Context_Impl_Hardware, dst, src: []byte) { + blk := intrinsics.unaligned_load((^simd.u8x16)(raw_data(src))) + + blk = simd.bit_xor(blk, intrinsics.unaligned_load((^simd.u8x16)(&ctx._sk_exp_enc[0]))) + #unroll for i in 1 ..= 9 { + blk = aes_hw.aesenc(blk, intrinsics.unaligned_load((^simd.u8x16)(&ctx._sk_exp_enc[i]))) + } + switch ctx._num_rounds { + case _aes.ROUNDS_128: + blk = aes_hw.aesenclast(blk, intrinsics.unaligned_load((^simd.u8x16)(&ctx._sk_exp_enc[10]))) + case _aes.ROUNDS_192: + #unroll for i in 10 ..= 11 { + blk = aes_hw.aesenc(blk, intrinsics.unaligned_load((^simd.u8x16)(&ctx._sk_exp_enc[i]))) + } + blk = aes_hw.aesenclast(blk, intrinsics.unaligned_load((^simd.u8x16)(&ctx._sk_exp_enc[12]))) + case _aes.ROUNDS_256: + #unroll for i in 10 ..= 13 { + blk = aes_hw.aesenc(blk, intrinsics.unaligned_load((^simd.u8x16)(&ctx._sk_exp_enc[i]))) + } + blk = aes_hw.aesenclast(blk, intrinsics.unaligned_load((^simd.u8x16)(&ctx._sk_exp_enc[14]))) + } + + intrinsics.unaligned_store((^simd.u8x16)(raw_data(dst)), blk) +} + +@(private, enable_target_feature = aes_hw.TARGET_FEATURES) +decrypt_block_hw :: proc(ctx: ^Context_Impl_Hardware, dst, src: []byte) { + blk := intrinsics.unaligned_load((^simd.u8x16)(raw_data(src))) + + blk = simd.bit_xor(blk, intrinsics.unaligned_load((^simd.u8x16)(&ctx._sk_exp_dec[0]))) + #unroll for i in 1 ..= 9 { + blk = aes_hw.aesdec(blk, intrinsics.unaligned_load((^simd.u8x16)(&ctx._sk_exp_dec[i]))) + } + switch ctx._num_rounds { + case _aes.ROUNDS_128: + blk = aes_hw.aesdeclast(blk, intrinsics.unaligned_load((^simd.u8x16)(&ctx._sk_exp_dec[10]))) + case _aes.ROUNDS_192: + #unroll for i in 10 ..= 11 { + blk = aes_hw.aesdec(blk, intrinsics.unaligned_load((^simd.u8x16)(&ctx._sk_exp_dec[i]))) + } + blk = aes_hw.aesdeclast(blk, intrinsics.unaligned_load((^simd.u8x16)(&ctx._sk_exp_dec[12]))) + case _aes.ROUNDS_256: + #unroll for i in 10 ..= 13 { + blk = aes_hw.aesdec(blk, intrinsics.unaligned_load((^simd.u8x16)(&ctx._sk_exp_dec[i]))) + } + blk = aes_hw.aesdeclast(blk, intrinsics.unaligned_load((^simd.u8x16)(&ctx._sk_exp_dec[14]))) + } + + intrinsics.unaligned_store((^simd.u8x16)(raw_data(dst)), blk) +} diff --git a/core/crypto/aes/aes_ecb_hw_intel.odin b/core/crypto/aes/aes_ecb_hw_intel.odin deleted file mode 100644 index f1d44a25f..000000000 --- a/core/crypto/aes/aes_ecb_hw_intel.odin +++ /dev/null @@ -1,58 +0,0 @@ -#+build amd64 -package aes - -import "base:intrinsics" -import "core:crypto/_aes" -import "core:simd/x86" - -@(private, enable_target_feature = "sse2,aes") -encrypt_block_hw :: proc(ctx: ^Context_Impl_Hardware, dst, src: []byte) { - blk := intrinsics.unaligned_load((^x86.__m128i)(raw_data(src))) - - blk = x86._mm_xor_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_enc[0]))) - #unroll for i in 1 ..= 9 { - blk = x86._mm_aesenc_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_enc[i]))) - } - switch ctx._num_rounds { - case _aes.ROUNDS_128: - blk = x86._mm_aesenclast_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_enc[10]))) - case _aes.ROUNDS_192: - #unroll for i in 10 ..= 11 { - blk = x86._mm_aesenc_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_enc[i]))) - } - blk = x86._mm_aesenclast_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_enc[12]))) - case _aes.ROUNDS_256: - #unroll for i in 10 ..= 13 { - blk = x86._mm_aesenc_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_enc[i]))) - } - blk = x86._mm_aesenclast_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_enc[14]))) - } - - intrinsics.unaligned_store((^x86.__m128i)(raw_data(dst)), blk) -} - -@(private, enable_target_feature = "sse2,aes") -decrypt_block_hw :: proc(ctx: ^Context_Impl_Hardware, dst, src: []byte) { - blk := intrinsics.unaligned_load((^x86.__m128i)(raw_data(src))) - - blk = x86._mm_xor_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_dec[0]))) - #unroll for i in 1 ..= 9 { - blk = x86._mm_aesdec_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_dec[i]))) - } - switch ctx._num_rounds { - case _aes.ROUNDS_128: - blk = x86._mm_aesdeclast_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_dec[10]))) - case _aes.ROUNDS_192: - #unroll for i in 10 ..= 11 { - blk = x86._mm_aesdec_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_dec[i]))) - } - blk = x86._mm_aesdeclast_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_dec[12]))) - case _aes.ROUNDS_256: - #unroll for i in 10 ..= 13 { - blk = x86._mm_aesdec_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_dec[i]))) - } - blk = x86._mm_aesdeclast_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_dec[14]))) - } - - intrinsics.unaligned_store((^x86.__m128i)(raw_data(dst)), blk) -} diff --git a/core/crypto/aes/aes_gcm.odin b/core/crypto/aes/aes_gcm.odin index d349aa353..531844a32 100644 --- a/core/crypto/aes/aes_gcm.odin +++ b/core/crypto/aes/aes_gcm.odin @@ -4,8 +4,8 @@ import "core:bytes" import "core:crypto" import "core:crypto/_aes" import "core:crypto/_aes/ct64" +import aes_hw "core:crypto/_aes/hw" import "core:encoding/endian" -import "core:mem" // GCM_IV_SIZE is the default size of the GCM IV in bytes. GCM_IV_SIZE :: 12 @@ -27,6 +27,10 @@ Context_GCM :: struct { // init_gcm initializes a Context_GCM with the provided key. init_gcm :: proc(ctx: ^Context_GCM, key: []byte, impl := DEFAULT_IMPLEMENTATION) { + when aes_hw.HAS_GHASH { + impl := aes_hw.is_ghash_supported() ? impl : .Portable + + } init_impl(&ctx._impl, key, impl) ctx._is_initialized = true } @@ -59,14 +63,14 @@ seal_gcm :: proc(ctx: ^Context_GCM, dst, tag, iv, aad, plaintext: []byte) { final_ghash_ct64(&s, &h, &j0_enc, len(aad), len(plaintext)) copy(tag, s[:]) - mem.zero_explicit(&h, len(h)) - mem.zero_explicit(&j0, len(j0)) - mem.zero_explicit(&j0_enc, len(j0_enc)) + zero_explicit(&h, len(h)) + zero_explicit(&j0, len(j0)) + zero_explicit(&j0_enc, len(j0_enc)) } // open_gcm authenticates the aad and ciphertext, and decrypts the ciphertext, // with the provided Context_GCM, iv, and tag, and stores the output in dst, -// returning true iff the authentication was successful. If authentication +// returning true if and only if (⟺) the authentication was successful. If authentication // fails, the destination buffer will be zeroed. // // dst and plaintext MUST alias exactly or not at all. @@ -94,13 +98,13 @@ open_gcm :: proc(ctx: ^Context_GCM, dst, iv, aad, ciphertext, tag: []byte) -> bo ok := crypto.compare_constant_time(s[:], tag) == 1 if !ok { - mem.zero_explicit(raw_data(dst), len(dst)) + zero_explicit(raw_data(dst), len(dst)) } - mem.zero_explicit(&h, len(h)) - mem.zero_explicit(&j0, len(j0)) - mem.zero_explicit(&j0_enc, len(j0_enc)) - mem.zero_explicit(&s, len(s)) + zero_explicit(&h, len(h)) + zero_explicit(&j0, len(j0)) + zero_explicit(&j0_enc, len(j0_enc)) + zero_explicit(&s, len(s)) return ok } @@ -249,6 +253,6 @@ gctr_ct64 :: proc( } } - mem.zero_explicit(&tmp, size_of(tmp)) - mem.zero_explicit(&tmp2, size_of(tmp2)) + zero_explicit(&tmp, size_of(tmp)) + zero_explicit(&tmp2, size_of(tmp2)) } diff --git a/core/crypto/aes/aes_gcm_hw_intel.odin b/core/crypto/aes/aes_gcm_hw.odin similarity index 59% rename from core/crypto/aes/aes_gcm_hw_intel.odin rename to core/crypto/aes/aes_gcm_hw.odin index 3982d1452..13c035a20 100644 --- a/core/crypto/aes/aes_gcm_hw_intel.odin +++ b/core/crypto/aes/aes_gcm_hw.odin @@ -1,13 +1,13 @@ -#+build amd64 +#+build amd64,arm64,arm32 package aes import "base:intrinsics" import "core:crypto" import "core:crypto/_aes" -import "core:crypto/_aes/hw_intel" +@(require) import "core:crypto/_aes/ct64" +import aes_hw "core:crypto/_aes/hw" import "core:encoding/endian" -import "core:mem" -import "core:simd/x86" +import "core:simd" @(private) gcm_seal_hw :: proc(ctx: ^Context_Impl_Hardware, dst, tag, iv, aad, plaintext: []byte) { @@ -18,14 +18,18 @@ gcm_seal_hw :: proc(ctx: ^Context_Impl_Hardware, dst, tag, iv, aad, plaintext: [ init_ghash_hw(ctx, &h, &j0, &j0_enc, iv) // Note: Our GHASH implementation handles appending padding. - hw_intel.ghash(s[:], h[:], aad) + when aes_hw.HAS_GHASH { + aes_hw.ghash(s[:], h[:], aad) + } else { + ct64.ghash(s[:], h[:], aad) + } gctr_hw(ctx, dst, &s, plaintext, &h, &j0, true) final_ghash_hw(&s, &h, &j0_enc, len(aad), len(plaintext)) copy(tag, s[:]) - mem.zero_explicit(&h, len(h)) - mem.zero_explicit(&j0, len(j0)) - mem.zero_explicit(&j0_enc, len(j0_enc)) + zero_explicit(&h, len(h)) + zero_explicit(&j0, len(j0)) + zero_explicit(&j0_enc, len(j0_enc)) } @(private) @@ -36,19 +40,23 @@ gcm_open_hw :: proc(ctx: ^Context_Impl_Hardware, dst, iv, aad, ciphertext, tag: s: [_aes.GHASH_TAG_SIZE]byte init_ghash_hw(ctx, &h, &j0, &j0_enc, iv) - hw_intel.ghash(s[:], h[:], aad) + when aes_hw.HAS_GHASH { + aes_hw.ghash(s[:], h[:], aad) + } else { + ct64.ghash(s[:], h[:], aad) + } gctr_hw(ctx, dst, &s, ciphertext, &h, &j0, false) final_ghash_hw(&s, &h, &j0_enc, len(aad), len(ciphertext)) ok := crypto.compare_constant_time(s[:], tag) == 1 if !ok { - mem.zero_explicit(raw_data(dst), len(dst)) + zero_explicit(raw_data(dst), len(dst)) } - mem.zero_explicit(&h, len(h)) - mem.zero_explicit(&j0, len(j0)) - mem.zero_explicit(&j0_enc, len(j0_enc)) - mem.zero_explicit(&s, len(s)) + zero_explicit(&h, len(h)) + zero_explicit(&j0, len(j0)) + zero_explicit(&j0_enc, len(j0_enc)) + zero_explicit(&s, len(s)) return ok } @@ -72,18 +80,26 @@ init_ghash_hw :: proc( } else { // If len(IV) != 96, then let s = 128 ceil(len(IV)/128) - len(IV), // and let J0 = GHASHH(IV || 0^(s+64) || ceil(len(IV))^64). - hw_intel.ghash(j0[:], h[:], iv) + when aes_hw.HAS_GHASH { + aes_hw.ghash(j0[:], h[:], iv) + } else { + ct64.ghash(j0[:], h[:], iv) + } tmp: [_aes.GHASH_BLOCK_SIZE]byte endian.unchecked_put_u64be(tmp[8:], u64(l) * 8) - hw_intel.ghash(j0[:], h[:], tmp[:]) + when aes_hw.HAS_GHASH { + aes_hw.ghash(j0[:], h[:], tmp[:]) + } else { + ct64.ghash(j0[:], h[:], tmp[:]) + } } // ECB encrypt j0, so that we can just XOR with the tag. encrypt_block_hw(ctx, j0_enc[:], j0[:]) } -@(private = "file", enable_target_feature = "sse2") +@(private = "file", enable_target_feature = aes_hw.TARGET_FEATURES) final_ghash_hw :: proc( s: ^[_aes.GHASH_BLOCK_SIZE]byte, h: ^[_aes.GHASH_KEY_SIZE]byte, @@ -95,14 +111,18 @@ final_ghash_hw :: proc( endian.unchecked_put_u64be(blk[0:], u64(a_len) * 8) endian.unchecked_put_u64be(blk[8:], u64(t_len) * 8) - hw_intel.ghash(s[:], h[:], blk[:]) - j0_vec := intrinsics.unaligned_load((^x86.__m128i)(j0)) - s_vec := intrinsics.unaligned_load((^x86.__m128i)(s)) - s_vec = x86._mm_xor_si128(s_vec, j0_vec) - intrinsics.unaligned_store((^x86.__m128i)(s), s_vec) + when aes_hw.HAS_GHASH { + aes_hw.ghash(s[:], h[:], blk[:]) + } else { + ct64.ghash(s[:], h[:], blk[:]) + } + j0_vec := intrinsics.unaligned_load((^simd.u8x16)(j0)) + s_vec := intrinsics.unaligned_load((^simd.u8x16)(s)) + s_vec = simd.bit_xor(s_vec, j0_vec) + intrinsics.unaligned_store((^simd.u8x16)(s), s_vec) } -@(private = "file", enable_target_feature = "sse2,sse4.1,aes") +@(private = "file", enable_target_feature = aes_hw.TARGET_FEATURES) gctr_hw :: proc( ctx: ^Context_Impl_Hardware, dst: []byte, @@ -112,13 +132,13 @@ gctr_hw :: proc( iv: ^[_aes.GHASH_BLOCK_SIZE]byte, is_seal: bool, ) #no_bounds_check { - sks: [15]x86.__m128i = --- + sks: [15]simd.u8x16 = --- for i in 0 ..= ctx._num_rounds { - sks[i] = intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_enc[i])) + sks[i] = intrinsics.unaligned_load((^simd.u8x16)(&ctx._sk_exp_enc[i])) } // Setup the counter block - ctr_blk := intrinsics.unaligned_load((^x86.__m128i)(iv)) + ctr_blk := intrinsics.unaligned_load((^simd.u8x16)(iv)) ctr := endian.unchecked_get_u32be(iv[GCM_IV_SIZE:]) + 1 src, dst := src, dst @@ -128,11 +148,15 @@ gctr_hw :: proc( // This results in an unreadable mess, so we opt for simplicity // as performance is adequate. - blks: [CTR_STRIDE_HW]x86.__m128i = --- + blks: [CTR_STRIDE_HW]simd.u8x16 = --- nr_blocks := len(src) / BLOCK_SIZE for nr_blocks >= CTR_STRIDE_HW { if !is_seal { - hw_intel.ghash(s[:], h[:], src[:CTR_STRIDE_BYTES_HW]) + when aes_hw.HAS_GHASH { + aes_hw.ghash(s[:], h[:], src[:CTR_STRIDE_BYTES_HW]) + } else { + ct64.ghash(s[:], h[:], src[:CTR_STRIDE_BYTES_HW]) + } } #unroll for i in 0 ..< CTR_STRIDE_HW { @@ -140,42 +164,46 @@ gctr_hw :: proc( } #unroll for i in 0 ..< CTR_STRIDE_HW { - blks[i] = x86._mm_xor_si128(blks[i], sks[0]) + blks[i] = simd.bit_xor(blks[i], sks[0]) } #unroll for i in 1 ..= 9 { #unroll for j in 0 ..< CTR_STRIDE_HW { - blks[j] = x86._mm_aesenc_si128(blks[j], sks[i]) + blks[j] = aes_hw.aesenc(blks[j], sks[i]) } } switch ctx._num_rounds { case _aes.ROUNDS_128: #unroll for i in 0 ..< CTR_STRIDE_HW { - blks[i] = x86._mm_aesenclast_si128(blks[i], sks[10]) + blks[i] = aes_hw.aesenclast(blks[i], sks[10]) } case _aes.ROUNDS_192: #unroll for i in 10 ..= 11 { #unroll for j in 0 ..< CTR_STRIDE_HW { - blks[j] = x86._mm_aesenc_si128(blks[j], sks[i]) + blks[j] = aes_hw.aesenc(blks[j], sks[i]) } } #unroll for i in 0 ..< CTR_STRIDE_HW { - blks[i] = x86._mm_aesenclast_si128(blks[i], sks[12]) + blks[i] = aes_hw.aesenclast(blks[i], sks[12]) } case _aes.ROUNDS_256: #unroll for i in 10 ..= 13 { #unroll for j in 0 ..< CTR_STRIDE_HW { - blks[j] = x86._mm_aesenc_si128(blks[j], sks[i]) + blks[j] = aes_hw.aesenc(blks[j], sks[i]) } } #unroll for i in 0 ..< CTR_STRIDE_HW { - blks[i] = x86._mm_aesenclast_si128(blks[i], sks[14]) + blks[i] = aes_hw.aesenclast(blks[i], sks[14]) } } xor_blocks_hw(dst, src, blks[:]) if is_seal { - hw_intel.ghash(s[:], h[:], dst[:CTR_STRIDE_BYTES_HW]) + when aes_hw.HAS_GHASH { + aes_hw.ghash(s[:], h[:], dst[:CTR_STRIDE_BYTES_HW]) + } else { + ct64.ghash(s[:], h[:], dst[:CTR_STRIDE_BYTES_HW]) + } } src = src[CTR_STRIDE_BYTES_HW:] @@ -187,28 +215,32 @@ gctr_hw :: proc( for n := len(src); n > 0; { l := min(n, BLOCK_SIZE) if !is_seal { - hw_intel.ghash(s[:], h[:], src[:l]) + when aes_hw.HAS_GHASH { + aes_hw.ghash(s[:], h[:], src[:l]) + } else { + ct64.ghash(s[:], h[:], src[:l]) + } } blks[0], ctr = hw_inc_ctr32(&ctr_blk, ctr) - blks[0] = x86._mm_xor_si128(blks[0], sks[0]) + blks[0] = simd.bit_xor(blks[0], sks[0]) #unroll for i in 1 ..= 9 { - blks[0] = x86._mm_aesenc_si128(blks[0], sks[i]) + blks[0] = aes_hw.aesenc(blks[0], sks[i]) } switch ctx._num_rounds { case _aes.ROUNDS_128: - blks[0] = x86._mm_aesenclast_si128(blks[0], sks[10]) + blks[0] = aes_hw.aesenclast(blks[0], sks[10]) case _aes.ROUNDS_192: #unroll for i in 10 ..= 11 { - blks[0] = x86._mm_aesenc_si128(blks[0], sks[i]) + blks[0] = aes_hw.aesenc(blks[0], sks[i]) } - blks[0] = x86._mm_aesenclast_si128(blks[0], sks[12]) + blks[0] = aes_hw.aesenclast(blks[0], sks[12]) case _aes.ROUNDS_256: #unroll for i in 10 ..= 13 { - blks[0] = x86._mm_aesenc_si128(blks[0], sks[i]) + blks[0] = aes_hw.aesenc(blks[0], sks[i]) } - blks[0] = x86._mm_aesenclast_si128(blks[0], sks[14]) + blks[0] = aes_hw.aesenclast(blks[0], sks[14]) } if l == BLOCK_SIZE { @@ -220,7 +252,11 @@ gctr_hw :: proc( copy(dst, blk[:l]) } if is_seal { - hw_intel.ghash(s[:], h[:], dst[:l]) + when aes_hw.HAS_GHASH { + aes_hw.ghash(s[:], h[:], dst[:l]) + } else { + ct64.ghash(s[:], h[:], dst[:l]) + } } dst = dst[l:] @@ -228,16 +264,25 @@ gctr_hw :: proc( n -= l } - mem.zero_explicit(&blks, size_of(blks)) - mem.zero_explicit(&sks, size_of(sks)) + zero_explicit(&blks, size_of(blks)) + zero_explicit(&sks, size_of(sks)) } // BUG: Sticking this in gctr_hw (like the other implementations) crashes // the compiler. // // src/check_expr.cpp(8104): Assertion Failure: `c->curr_proc_decl->entity` -@(private = "file", enable_target_feature = "sse4.1") -hw_inc_ctr32 :: #force_inline proc "contextless" (src: ^x86.__m128i, ctr: u32) -> (x86.__m128i, u32) { - ret := x86._mm_insert_epi32(src^, i32(intrinsics.byte_swap(ctr)), 3) +@(private = "file", enable_target_feature = aes_hw.TARGET_FEATURES) +hw_inc_ctr32 :: #force_inline proc "contextless" (src: ^simd.u8x16, ctr: u32) -> (simd.u8x16, u32) { + when ODIN_ENDIAN == .Little { + ctr_be := intrinsics.byte_swap(ctr) + } else { + ctr_be := ctr + } + + ret := transmute(simd.u8x16)( + simd.replace(transmute(simd.u32x4)(src^), 3, ctr_be) + ) + return ret, ctr + 1 } diff --git a/core/crypto/aes/aes_impl.odin b/core/crypto/aes/aes_impl.odin index f26874809..b95abfaf0 100644 --- a/core/crypto/aes/aes_impl.odin +++ b/core/crypto/aes/aes_impl.odin @@ -1,9 +1,11 @@ package aes +import "core:crypto" import "core:crypto/_aes/ct64" -import "core:mem" import "core:reflect" +zero_explicit :: crypto.zero_explicit + @(private) Context_Impl :: union { ct64.Context, @@ -41,5 +43,5 @@ init_impl :: proc(ctx: ^Context_Impl, key: []byte, impl: Implementation) { @(private) reset_impl :: proc "contextless" (ctx: ^Context_Impl) { - mem.zero_explicit(ctx, size_of(Context_Impl)) -} + zero_explicit(ctx, size_of(Context_Impl)) +} \ No newline at end of file diff --git a/core/crypto/aes/aes_impl_hw.odin b/core/crypto/aes/aes_impl_hw.odin new file mode 100644 index 000000000..fe93966f8 --- /dev/null +++ b/core/crypto/aes/aes_impl_hw.odin @@ -0,0 +1,18 @@ +#+build amd64,arm64,arm32 +package aes + +import aes_hw "core:crypto/_aes/hw" + +// is_hardware_accelerated returns true if and only if (⟺) hardware accelerated AES +// is supported. +is_hardware_accelerated :: proc "contextless" () -> bool { + return aes_hw.is_supported() +} + +@(private) +Context_Impl_Hardware :: aes_hw.Context + +@(private, enable_target_feature = aes_hw.TARGET_FEATURES) +init_impl_hw :: proc(ctx: ^Context_Impl_Hardware, key: []byte) { + aes_hw.init(ctx, key) +} diff --git a/core/crypto/aes/aes_impl_hw_gen.odin b/core/crypto/aes/aes_impl_hw_gen.odin index 0c9ec6edc..10b08b7b5 100644 --- a/core/crypto/aes/aes_impl_hw_gen.odin +++ b/core/crypto/aes/aes_impl_hw_gen.odin @@ -1,10 +1,12 @@ #+build !amd64 +#+build !arm64 +#+build !arm32 package aes @(private = "file") ERR_HW_NOT_SUPPORTED :: "crypto/aes: hardware implementation unsupported" -// is_hardware_accelerated returns true iff hardware accelerated AES +// is_hardware_accelerated returns true if and only if (⟺) hardware accelerated AES // is supported. is_hardware_accelerated :: proc "contextless" () -> bool { return false diff --git a/core/crypto/aes/aes_impl_hw_intel.odin b/core/crypto/aes/aes_impl_hw_intel.odin deleted file mode 100644 index 0f1fa6143..000000000 --- a/core/crypto/aes/aes_impl_hw_intel.odin +++ /dev/null @@ -1,18 +0,0 @@ -#+build amd64 -package aes - -import "core:crypto/_aes/hw_intel" - -// is_hardware_accelerated returns true iff hardware accelerated AES -// is supported. -is_hardware_accelerated :: proc "contextless" () -> bool { - return hw_intel.is_supported() -} - -@(private) -Context_Impl_Hardware :: hw_intel.Context - -@(private, enable_target_feature = "sse2,aes") -init_impl_hw :: proc(ctx: ^Context_Impl_Hardware, key: []byte) { - hw_intel.init(ctx, key) -} diff --git a/core/crypto/argon2id/argon2id.odin b/core/crypto/argon2id/argon2id.odin new file mode 100644 index 000000000..3bff5a3a9 --- /dev/null +++ b/core/crypto/argon2id/argon2id.odin @@ -0,0 +1,622 @@ +/* +package argon2id implements the Argon2id password hashing algorithm. + +See: [[ https://datatracker.ietf.org/doc/rfc9106/ ]] +*/ +package argon2id + +import "core:crypto/blake2b" +import "core:encoding/endian" +import "core:math/bits" +import "core:mem" + +// Implementation based on the RFC, Monocypher (CC0-1.0), and the reference +// code (CC0-1.0). + +// MAX_INPUT_SIZE is the mamximum size of the various inputs (password, +// salt, secret, ad) in bytes. +MAX_INPUT_SIZE :: (1 << 32) - 1 + +// MIN_PARALLELISM is the minimum allowed parallelism. +MIN_PARALLELISM :: 1 +// MAX_PARALLELISM is the maximum allowed parallelism. +MAX_PARALLELISM :: (1 << 24) - 1 + +// MIN_TAG_SIZE is the minimum digest size in bytes. +MIN_TAG_SIZE :: 4 +// MAX_TAG_SIZE is the maximum digest size in bytes. +MAX_TAG_SIZE :: (1 << 32) - 1 + +// RECOMMENDED_TAG_SIZE is the recommended tag size in bytes. +RECOMMENTED_TAG_SIZE :: 32 // 256-bits +// RECOMMENDNED_SALT_SIZE is the recommended salt size in bytes. +RECOMMENDED_SALT_SIZE :: 16 // 128-bits + +@(private) +V_RFC9106 :: 0x13 +@(private) +Y_ID :: 0x02 +@(private) +BLOCK_SIZE_BYTES :: 1024 +@(private) +BLOCK_SIZE_U64 :: 128 + +// PARAMS_RFC9106 is the first recommended "uniformly safe" parameter set +// per RFC 9106. +@(rodata) +PARAMS_RFC9106 := Parameters{ + memory_size = 2 * 1024 * 1024, // 2 GiB + passes = 1, + parallelism = 4, +} + +// PARAMS_RFC9106_SMALL is the second recommended "uniformly safe" parameter +// set per RFC 9106 tailored for memory constrained environments. +@(rodata) +PARAMS_RFC9106_SMALL := Parameters{ + memory_size = 64 * 1024, // 64 MiB + passes = 3, + parallelism = 4, +} + +// PARAMS_OWASP is one of the recommended parameter set from the OWASP +// Password Storage Cheat Sheet (as of 2026/02). The cheat sheet contains +// additional variations to this parameter set with various trade-offs +// between `memory_size` and `passes` that are intended to provide +// equivalent security. +// +// See: [[ https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html ]] +@(rodata) +PARAMS_OWASP := Parameters{ + memory_size = 19 * 1024, // 19 MiB + passes = 2, + parallelism = 1, +} + +// PARAMS_OWASP_SMALL is equivalent in strength to PARAMS_OWASP, but +// trades off less memory use for more CPU usage. +@(rodata) +PARAMS_OWASP_SMALL := Parameters{ + memory_size = 7 * 1024, // 7 MiB + passes = 5, + parallelism = 1, +} + +// Parameters is an Argon2id parameter set. +Parameters :: struct { + memory_size: u32, // m (KiB) + passes: u32, // t + parallelism: u32, // p +} + +@(private) +Block :: [BLOCK_SIZE_U64]u64 + +// derive invokes Argon2id with the specified parameter set and inputs, +// and outputs the derived key to dst. +@(require_results) +derive :: proc( + parameters: ^Parameters, + password: []byte, // P + salt: []byte, // S + dst: []byte, + secret: []byte = nil, // K (aka `pepper`) + ad: []byte = nil, // X + sanitize := true, + allocator := context.allocator, // Not temp as this can be large. +) -> mem.Allocator_Error #no_bounds_check { + if u64(len(password)) > MAX_INPUT_SIZE { + panic("crypto/argon2id: invalid password size") + } + if u64(len(salt)) > MAX_INPUT_SIZE { + panic("crypto/argon2id: invalid salt size") + } + if u64(len(secret)) > MAX_INPUT_SIZE { + panic("crypto/argon2id: invalid secret size") + } + if u64(len(ad)) > MAX_INPUT_SIZE { + panic("crypto/argon2id: invalid ad size") + } + if l := u64(len(dst)); l > MAX_TAG_SIZE || l < MIN_TAG_SIZE { + panic("crypto/argon2id: invalid dst size") + } + + p, t, m := parameters.parallelism, parameters.passes, u64(parameters.memory_size) + if p < MIN_PARALLELISM || p > MAX_PARALLELISM { + panic("crypto/argon2id: invalid parallelism") + } + if t < 1 { + panic("crypto/argon2id: invalid passes") + } + if m < 8 * u64(p) { + panic("crypto/argon2id: insufficient memory size") + } + if m * BLOCK_SIZE_BYTES > u64(max(int)) { + panic("crypto/argon2id: excessive memory size") + } + + // Allocate the memory as m' 1024-byte blocks, where m' is derived as: + // m' = 4 * p * floor (m / 4p) + // + // For p lanes, the memory is organized in a matrix B[i][j] of + // blocks with p rows (lanes) and q = m' / p columns. + m_ := 4 * u64(p) * (m / u64(4 * p)) + b := mem.alloc_bytes_non_zeroed( + int(m_) * BLOCK_SIZE_BYTES, + alignment = mem.DEFAULT_PAGE_SIZE, + allocator = allocator, + ) or_return + defer delete(b, allocator) + + block_buf: [BLOCK_SIZE_BYTES]byte = --- + + blocks := ([^]Block)(raw_data(b))[:m_] + segment_size := u32(m_ / u64(p) / 4) + lane_size := segment_size * 4 + + // Establish H_0 as the 64-byte value as shown below. If K, X, or S + // has zero length, it is just absent, but its length field remains. + // + // H_0 = H^(64)(LE32(p) || LE32(T) || LE32(m) || LE32(t) || + // LE32(v) || LE32(y) || LE32(length(P)) || P || + // LE32(length(S)) || S || LE32(length(K)) || K || + // LE32(length(X)) || X) + { + ctx: blake2b.Context + blake2b.init(&ctx) + + blake2b_update_u32le(&ctx, u32(p)) + blake2b_update_u32le(&ctx, u32(len(dst))) + blake2b_update_u32le(&ctx, parameters.memory_size) + blake2b_update_u32le(&ctx, t) + blake2b_update_u32le(&ctx, V_RFC9106) + blake2b_update_u32le(&ctx, Y_ID) + blake2b_update_u32le(&ctx, u32(len(password))) + blake2b.update(&ctx, password) + blake2b_update_u32le(&ctx, u32(len(salt))) + blake2b.update(&ctx, salt) + blake2b_update_u32le(&ctx, u32(len(secret))) + blake2b.update(&ctx, secret) + blake2b_update_u32le(&ctx, u32(len(ad))) + blake2b.update(&ctx, ad) + + h_0: [blake2b.DIGEST_SIZE+8]byte + blake2b.final(&ctx, h_0[:blake2b.DIGEST_SIZE]) + + // Compute B[i][0] for all i ranging from (and including) 0 to (not + // including) p. + // + // B[i][0] = H'^(1024)(H_0 || LE32(0) || LE32(i)) + // + // Compute B[i][1] for all i ranging from (and including) 0 to (not + // including) p. + // + // B[i][1] = H'^(1024)(H_0 || LE32(1) || LE32(i)) + for l in u32(0) ..< p { + for i in u32(0) ..< 2 { + endian.unchecked_put_u32le(h_0[blake2b.DIGEST_SIZE:], i) // LE32({0,1}) + endian.unchecked_put_u32le(h_0[blake2b.DIGEST_SIZE+4:], l) // LE32(i) + h_prime(block_buf[:], h_0[:]) + blk := &blocks[l * lane_size + i] + for j in 0 ..< BLOCK_SIZE_U64 { + blk[j] = endian.unchecked_get_u64le(block_buf[j*8:]) + } + } + } + + mem.zero_explicit(&h_0, size_of(h_0)) // No longer needed. + } + + // Compute B[i][j] for all i ranging from (and including) 0 to (not + // including) p and for all j ranging from (and including) 2 to (not + // including) q. The computation MUST proceed slicewise + // (Section 3.4): first, blocks from slice 0 are computed for all + // lanes (in an arbitrary order of lanes), then blocks from slice 1 + // are computed, etc. The block indices l and z are determined for + // each i, j differently for Argon2d, Argon2i, and Argon2id. + // + // B[i][j] = G(B[i][j-1], B[l][z]) + // + // If the number of passes t is larger than 1, we repeat step 5. We + // compute B[i][0] and B[i][j] for all i raging from (and including) + // 0 to (not including) p and for all j ranging from (and including) + // 1 to (not including) q. However, blocks are computed differently + // as the old value is XORed with the new one: + // + // B[i][0] = G(B[i][q-1], B[l][z]) XOR B[i][0]; + // B[i][j] = G(B[i][j-1], B[l][z]) XOR B[i][j]. + constant_time := true // Start with constant time indexing. + tmp, index_block: Block = ---, --- + for pass in u32(0) ..< t { + for slice in u32(0) ..< 4 { + // The first slice of the first pass has blocks 0 and 1 + // pre-filled. + pass_offset: u32 = pass == 0 && slice == 0 ? 2 : 0 + slice_offset := slice * segment_size + + // 3.4.1.3. Argon2id + // + // If the pass number is 0 and the slice number is 0 or 1, then compute + // J_1 and J_2 as for Argon2i, else compute J_1 and J_2 as for Argon2d. + if slice == 2 { + constant_time = false + } + + // Each segment can be processed in parallel, as long as + // each iteration of the loop completes before proceeding + // to the next. For simplicity we do this in serial + // instead of using threads. + for segment in u32(0) ..< u32(p) { + index_ctr: u64 = 1 + for block in pass_offset ..< segment_size { + // Current and previous blocks (indexes, not pointers) + lane_offset := segment * lane_size + segment_start := lane_offset + slice_offset + current := segment_start + block + previous := segment_start - 1 + switch { + case block == 0 && slice_offset == 0: + previous += lane_size + case: + previous += block + } + + index_seed: u64 + if constant_time { + // 3.4.1.2. Argon2i + // + // For each segment, we do the following. First, we compute the value Z + // as: + // + // Z= ( LE64(r) || LE64(l) || LE64(sl) || LE64(m') || + // LE64(t) || LE64(y) ) + // + // Figure 11: Input to Compute J1,J2 in Argon2i + // + // where + // + // r: the pass number + // l: the lane number + // sl: the slice number + // m': the total number of memory blocks + // t: the total number of passes + // y: the Argon2 type (0 for Argon2d, 1 for Argon2i, 2 for Argon2id) + // + // Then we compute: + // + // q/(128*SL) 1024-byte values + // G(ZERO(1024),G(ZERO(1024), + // Z || LE64(1) || ZERO(968) )), + // G(ZERO(1024),G(ZERO(1024), + // Z || LE64(2) || ZERO(968) )),... , + // G(ZERO(1024),G(ZERO(1024), + // Z || LE64(q/(128*SL)) || ZERO(968) )), + // + // which are partitioned into q/(SL) 8-byte values X, which are viewed + // as X1||X2 and converted to J_1=int32(X1) and J_2=int32(X2). + // + // The values r, l, sl, m', t, y, and i are represented as 8 bytes in + // little endian. + if block == pass_offset || (block % 128) == 0 { + mem.zero(&index_block, size_of(index_block)) + index_block[0] = u64(pass) + index_block[1] = u64(segment) + index_block[2] = u64(slice) + index_block[3] = u64(lane_size * p) + index_block[4] = u64(t) // passes + index_block[5] = Y_ID + index_block[6] = index_ctr + index_ctr += 1 + + copy(tmp[:], index_block[:]) + g_rounds(&index_block) + xor_block(&index_block, &tmp) + copy(tmp[:], index_block[:]) + g_rounds(&index_block) + xor_block(&index_block, &tmp) + } + index_seed = index_block[block % 128] + } else { + // 3.4.1.1. Argon2d + // + // J_1 is given by the first 32 bits of block B[i][j-1], while J_2 is + // given by the next 32 bits of block B[i][j-1]: + // + // J_1 = int32(extract(B[i][j-1], 0)) + // J_2 = int32(extract(B[i][j-1], 1)) + // + // Figure 10: Deriving J1,J2 in Argon2d + index_seed = blocks[previous][0] + } + + // 3.4.2. Mapping J_1 and J_2 to Reference Block Index [l][z] + // + // The value of l = J_2 mod p gives the index of the lane from which the + // block will be taken. For the first pass (r=0) and the first slice + // (sl=0), the block is taken from the current lane. + // + // The set W contains the indices that are referenced according to the + // following rules: + // + // 1. If l is the current lane, then W includes the indices of all + // blocks in the last SL - 1 = 3 segments computed and finished, as + // well as the blocks computed in the current segment in the current + // pass excluding B[i][j-1]. + // + // 2. If l is not the current lane, then W includes the indices of all + // blocks in the last SL - 1 = 3 segments computed and finished in + // lane l. If B[i][j] is the first block of a segment, then the + // very last index from W is excluded. + // + // Then take a block from W with a nonuniform distribution over [0, |W|) + // using the following mapping: + // + // J_1 -> |W|(1 - J_1^2 / 2^(64)) + // + // Figure 12: Computing J1 + // + // To avoid floating point computation, the following approximation is + // used: + // + // x = J_1^2 / 2^(32) + // y = (|W| * x) / 2^(32) + // zz = |W| - 1 - y + // + // Figure 13: Computing J1, Part 2 + // + // Then take the zz-th index from W; it will be the z value for the + // reference block index [l][z]. + next_slice: u32 = ((slice + 1) % 4) * segment_size + window_start, nb_segments: u32 + lane := u32(index_seed >> 32) % p + switch { + case pass == 0: + nb_segments = slice + if slice == 0 { + lane = segment + } + case: + window_start = next_slice + nb_segments = 3 + } + window_size := nb_segments * segment_size + if lane == segment { + window_size += block - 1 + } else if block == 0 { + window_size += ~u32(0) + } + + j1 := index_seed & 0xffffffff + x := (j1 * j1) >> 32 + y := (u64(window_size) * x) >> 32 + z := (u64(window_size) - 1) - y + ref := u32((u64(window_start) + z) % u64(lane_size)) + reference: u32 = lane * lane_size + ref + + copy(tmp[:], blocks[previous][:]) + xor_block(&tmp, &blocks[reference]) + if pass == 0 { + copy(blocks[current][:], tmp[:]) + } else { + xor_block(&blocks[current], &tmp) + } + g_rounds(&tmp) + xor_block(&blocks[current], &tmp) + } + } + } + } + mem.zero_explicit(&tmp, size_of(tmp)) + mem.zero_explicit(&index_block, size_of(index_block)) + + // After t steps have been iterated, the final block C is computed + // as the XOR of the last column: + // + // C = B[0][q-1] XOR B[1][q-1] XOR ... XOR B[p-1][q-1] + idx := lane_size - 1 + last_block := &blocks[idx] + for _ in 1 ..< p { + idx += lane_size + next_block := &blocks[idx] + xor_block(next_block, last_block) + last_block = next_block + } + + for v, i in last_block { + endian.unchecked_put_u64le(block_buf[i*8:], v) + } + + // The output tag is computed as H'^T(C). + h_prime(dst, block_buf[:]) + mem.zero_explicit(&block_buf, size_of(block_buf)) + + // Sanitize the working memory. While the RFC implies that this is + // optional ("enable the memory-wiping option in the library call"), + // the reference code defaults to enabling it. + // + // An opt-out is provided, as this can get somewhat expensive when + // m gets large. + if sanitize { + mem.zero_explicit(raw_data(b), len(b)) + } + + return nil +} + +@(private) +xor_block :: #force_inline proc(dst, src: ^Block) { + for v, i in src { + dst[i] ~= v + } +} + +@(private) +blake2b_update_u32le :: #force_inline proc(ctx: ^blake2b.Context, i: u32) { + tmp: [4]byte = --- + endian.unchecked_put_u32le(tmp[:], i) + blake2b.update(ctx, tmp[:]) + mem.zero_explicit(&tmp, size_of(tmp)) // Probably overkill. +} + +// 3.3. Variable-Length Hash Function H' +// +// Let V_i be a 64-byte block and W_i be its first 32 bytes. Then we +// define function H' as follows: +// +// if T <= 64 +// H'^T(A) = H^T(LE32(T)||A) +// else +// r = ceil(T/32)-2 +// V_1 = H^(64)(LE32(T)||A) +// V_2 = H^(64)(V_1) +// ... +// V_r = H^(64)(V_{r-1}) +// V_{r+1} = H^(T-32*r)(V_{r}) +// H'^T(X) = W_1 || W_2 || ... || W_r || V_{r+1} +// +// Figure 8: Function H' for Tag and Initial Block Computations +@(private) +h_prime :: proc(dst, src: []byte) { + t := len(dst) + ctx: blake2b.Context + blake2b.init(&ctx, min(t, blake2b.DIGEST_SIZE)) + blake2b_update_u32le(&ctx, u32(t)) + blake2b.update(&ctx, src) + blake2b.final(&ctx, dst) + + if t > 64 { + r := u32((u64(t) + 31) >> 5) - 2 + i: u32 = 1 + off_in := 0 + off_out := 32 + for i < r { + blake2b.init(&ctx, blake2b.DIGEST_SIZE) + blake2b.update(&ctx, dst[off_in:off_in+64]) + blake2b.final(&ctx, dst[off_out:]) + i += 1 + off_in += 32 + off_out += 32 + } + blake2b.init(&ctx, t - int(32 * r)) + blake2b.update(&ctx, dst[off_in:off_in+64]) + blake2b.final(&ctx, dst[off_out:]) + } +} + +// GB(a, b, c, d) is defined as follows: +// +// a = (a + b + 2 * trunc(a) * trunc(b)) mod 2^(64) +// d = (d XOR a) >>> 32 +// c = (c + d + 2 * trunc(c) * trunc(d)) mod 2^(64) +// b = (b XOR c) >>> 24 +// +// a = (a + b + 2 * trunc(a) * trunc(b)) mod 2^(64) +// d = (d XOR a) >>> 16 +// c = (c + d + 2 * trunc(c) * trunc(d)) mod 2^(64) +// b = (b XOR c) >>> 63 +// +// Figure 19: Details of GB +// +// The modular additions in GB are combined with 64-bit multiplications. +// Multiplications are the only difference from the original BLAKE2b +// design. This choice is done to increase the circuit depth and thus +// the running time of ASIC implementations, while having roughly the +// same running time on CPUs thanks to parallelism and pipelining. +@(private,require_results) +gb :: #force_inline proc(a, b, c, d: u64) -> (u64, u64, u64, u64) { + a, b, c, d := a, b, c, d + + trunc := #force_inline proc(v: u64) -> u64 { + return u64(u32(v)) + } + + a += b + ((trunc(a) * trunc(b)) << 1) + d = bits.rotate_left64(d ~ a, 32) // >>> 32 + c += d + ((trunc(c) * trunc(d)) << 1) + b = bits.rotate_left64((b ~ c), 40) // >>> 24 + + a += b + ((trunc(a) * trunc(b)) << 1) + d = bits.rotate_left64(d ~ a, 48) // >>> 16 + c += d + ((trunc(c) * trunc(d)) << 1) + b = bits.rotate_left64((b ~ c), 1) // >>> 63 + + return a, b, c, d +} + +// 3.6. Permutation P +// +// Permutation P is based on the round function of BLAKE2b. The eight +// 16-byte inputs S_0, S_1, ... , S_7 are viewed as a 4x4 matrix of +// 64-bit words, where S_i = (v_{2*i+1} || v_{2*i}): +// +// v_0 v_1 v_2 v_3 +// v_4 v_5 v_6 v_7 +// v_8 v_9 v_10 v_11 +// v_12 v_13 v_14 v_15 +// +// Figure 17: Matrix Element Labeling +// +// It works as follows: +// +// GB(v_0, v_4, v_8, v_12) +// GB(v_1, v_5, v_9, v_13) +// GB(v_2, v_6, v_10, v_14) +// GB(v_3, v_7, v_11, v_15) +// +// GB(v_0, v_5, v_10, v_15) +// GB(v_1, v_6, v_11, v_12) +// GB(v_2, v_7, v_8, v_13) +// GB(v_3, v_4, v_9, v_14) +// +// Figure 18: Feeding Matrix Elements to GB +@(private,require_results) +perm_p :: #force_inline proc(v_0, v_1, v_2, v_3, v_4, v_5, v_6, v_7, v_8, v_9, v_10, v_11, v_12, v_13, v_14, v_15: u64) -> (u64, u64, u64, u64, u64, u64, u64, u64, u64, u64, u64, u64, u64, u64, u64, u64) { + v_0, v_1, v_2, v_3, v_4, v_5, v_6, v_7, v_8, v_9, v_10, v_11, v_12, v_13, v_14, v_15 := v_0, v_1, v_2, v_3, v_4, v_5, v_6, v_7, v_8, v_9, v_10, v_11, v_12, v_13, v_14, v_15 + + v_0, v_4, v_8, v_12 = gb(v_0, v_4, v_8, v_12) + v_1, v_5, v_9, v_13 = gb(v_1, v_5, v_9, v_13) + v_2, v_6, v_10, v_14 = gb(v_2, v_6, v_10, v_14) + v_3, v_7, v_11, v_15 = gb(v_3, v_7, v_11, v_15) + + v_0, v_5, v_10, v_15 = gb(v_0, v_5, v_10, v_15) + v_1, v_6, v_11, v_12 = gb(v_1, v_6, v_11, v_12) + v_2, v_7, v_8, v_13 = gb(v_2, v_7, v_8, v_13) + v_3, v_4, v_9, v_14 = gb(v_3, v_4, v_9, v_14) + + return v_0, v_1, v_2, v_3, v_4, v_5, v_6, v_7, v_8, v_9, v_10, v_11, v_12, v_13, v_14, v_15 +} + +// 3.5. Compression Function G +// +// The compression function G is built upon the BLAKE2b-based +// transformation P. P operates on the 128-byte input, which can be +// viewed as eight 16-byte registers: +// +// P(A_0, A_1, ... ,A_7) = (B_0, B_1, ... ,B_7) +// +// Figure 14: Blake Round Function P +// +// The compression function G(X, Y) operates on two 1024-byte blocks X +// and Y. It first computes R = X XOR Y. Then R is viewed as an 8x8 +// matrix of 16-byte registers R_0, R_1, ... , R_63. Then P is first +// applied to each row, and then to each column to get Z: +// +// ( Q_0, Q_1, Q_2, ... , Q_7) <- P( R_0, R_1, R_2, ... , R_7) +// ( Q_8, Q_9, Q_10, ... , Q_15) <- P( R_8, R_9, R_10, ... , R_15) +// ... +// (Q_56, Q_57, Q_58, ... , Q_63) <- P(R_56, R_57, R_58, ... , R_63) +// ( Z_0, Z_8, Z_16, ... , Z_56) <- P( Q_0, Q_8, Q_16, ... , Q_56) +// ( Z_1, Z_9, Z_17, ... , Z_57) <- P( Q_1, Q_9, Q_17, ... , Q_57) +// ... +// ( Z_7, Z_15, Z 23, ... , Z_63) <- P( Q_7, Q_15, Q_23, ... , Q_63) +// +// Figure 15: Core of Compression Function G +@(private) +g_rounds :: proc(b: ^Block) { + for i := 0; i < 128; i += 16 { + b[i], b[i+1], b[i+2], b[i+3], b[i+4], b[i+5], b[i+6], b[i+7], b[i+8], b[i+9], b[i+10], b[i+11], b[i+12], b[i+13], b[i+14], b[i+15] = perm_p(b[i], b[i+1], b[i+2], b[i+3], b[i+4], b[i+5], b[i+6], b[i+7], b[i+8], b[i+9], b[i+10], b[i+11], b[i+12], b[i+13], b[i+14], b[i+15]) + } + for i := 0; i < 16; i += 2 { + b[i], b[i+1], b[i+16], b[i+17], b[i+32], b[i+33], b[i+48], b[i+49], b[i+64], b[i+65], b[i+80], b[i+81], b[i+96], b[i+97], b[i+112], b[i+113] = perm_p(b[i], b[i+1], b[i+16], b[i+17], b[i+32], b[i+33], b[i+48], b[i+49], b[i+64], b[i+65], b[i+80], b[i+81], b[i+96], b[i+97], b[i+112], b[i+113]) + } +} diff --git a/core/crypto/blake2b/blake2b.odin b/core/crypto/blake2b/blake2b.odin index 4590ca40e..8cce6dac8 100644 --- a/core/crypto/blake2b/blake2b.odin +++ b/core/crypto/blake2b/blake2b.odin @@ -28,13 +28,24 @@ Context :: _blake2.Blake2b_Context // init initializes a Context with the default BLAKE2b config. init :: proc(ctx: ^Context, digest_size := DIGEST_SIZE) { - ensure(digest_size <= _blake2.MAX_SIZE, "crypto/blake2b: invalid digest size") + ensure(digest_size <= DIGEST_SIZE, "crypto/blake2b: invalid digest size") cfg: _blake2.Blake2_Config cfg.size = u8(digest_size) _blake2.init(ctx, &cfg) } +// init_mac initializes a Context with a user provided key. +init_mac :: proc(ctx: ^Context, key: []byte, digest_size := DIGEST_SIZE) { + ensure(digest_size <= DIGEST_SIZE, "crypto/blake2b: invalid digest size") + ensure(len(key) <= DIGEST_SIZE, "crypto/blake2b: invalid key size") + + cfg: _blake2.Blake2_Config + cfg.size = u8(digest_size) + cfg.key = key + _blake2.init(ctx, &cfg) +} + // update adds more data to the Context. update :: proc(ctx: ^Context, data: []byte) { _blake2.update(ctx, data) @@ -43,7 +54,7 @@ update :: proc(ctx: ^Context, data: []byte) { // final finalizes the Context, writes the digest to hash, and calls // reset on the Context. // -// Iff finalize_clone is set, final will work on a copy of the Context, +// If and only if (⟺) finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { _blake2.final(ctx, hash, finalize_clone) diff --git a/core/crypto/blake2s/blake2s.odin b/core/crypto/blake2s/blake2s.odin index 37da53360..35e278f72 100644 --- a/core/crypto/blake2s/blake2s.odin +++ b/core/crypto/blake2s/blake2s.odin @@ -28,13 +28,24 @@ Context :: _blake2.Blake2s_Context // init initializes a Context with the default BLAKE2s config. init :: proc(ctx: ^Context, digest_size := DIGEST_SIZE) { - ensure(digest_size <= _blake2.MAX_SIZE, "crypto/blake2s: invalid digest size") + ensure(digest_size <= DIGEST_SIZE, "crypto/blake2s: invalid digest size") cfg: _blake2.Blake2_Config cfg.size = u8(digest_size) _blake2.init(ctx, &cfg) } +// init_mac initializes a Context with a user provided key. +init_mac :: proc(ctx: ^Context, key: []byte, digest_size := DIGEST_SIZE) { + ensure(digest_size <= DIGEST_SIZE, "crypto/blake2s: invalid digest size") + ensure(len(key) <= DIGEST_SIZE, "crypto/blake2s: invalid key size") + + cfg: _blake2.Blake2_Config + cfg.size = u8(digest_size) + cfg.key = key + _blake2.init(ctx, &cfg) +} + // update adds more data to the Context. update :: proc(ctx: ^Context, data: []byte) { _blake2.update(ctx, data) @@ -43,7 +54,7 @@ update :: proc(ctx: ^Context, data: []byte) { // final finalizes the Context, writes the digest to hash, and calls // reset on the Context. // -// Iff finalize_clone is set, final will work on a copy of the Context, +// If and only if (⟺) finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { _blake2.final(ctx, hash, finalize_clone) diff --git a/core/crypto/chacha20/chacha20.odin b/core/crypto/chacha20/chacha20.odin index a91c6a24a..91f22f744 100644 --- a/core/crypto/chacha20/chacha20.odin +++ b/core/crypto/chacha20/chacha20.odin @@ -8,8 +8,8 @@ See: package chacha20 import "core:bytes" +import "core:crypto" import "core:crypto/_chacha20" -import "core:mem" // KEY_SIZE is the (X)ChaCha20 key size in bytes. KEY_SIZE :: _chacha20.KEY_SIZE @@ -50,7 +50,7 @@ init :: proc(ctx: ^Context, key, iv: []byte, impl := DEFAULT_IMPLEMENTATION) { // The sub-key is stored in the keystream buffer. While // this will be overwritten in most circumstances, explicitly // clear it out early. - mem.zero_explicit(&ctx._state._buffer, KEY_SIZE) + crypto.zero_explicit(&ctx._state._buffer, KEY_SIZE) } } diff --git a/core/crypto/chacha20poly1305/chacha20poly1305.odin b/core/crypto/chacha20poly1305/chacha20poly1305.odin index 9840d357e..c405a2736 100644 --- a/core/crypto/chacha20poly1305/chacha20poly1305.odin +++ b/core/crypto/chacha20poly1305/chacha20poly1305.odin @@ -13,7 +13,6 @@ import "core:crypto" import "core:crypto/chacha20" import "core:crypto/poly1305" import "core:encoding/endian" -import "core:mem" // KEY_SIZE is the chacha20poly1305 key size in bytes. KEY_SIZE :: chacha20.KEY_SIZE @@ -103,7 +102,7 @@ seal :: proc(ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) { chacha20.keystream_bytes(&stream_ctx, otk[:]) mac_ctx: poly1305.Context = --- poly1305.init(&mac_ctx, otk[:]) - mem.zero_explicit(&otk, size_of(otk)) + crypto.zero_explicit(&otk, size_of(otk)) aad_len, ciphertext_len := len(aad), len(ciphertext) @@ -137,7 +136,7 @@ seal :: proc(ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) { // open authenticates the aad and ciphertext, and decrypts the ciphertext, // with the provided Context, iv, and tag, and stores the output in dst, -// returning true iff the authentication was successful. If authentication +// returning true if and only if (⟺) the authentication was successful. If authentication // fails, the destination buffer will be zeroed. // // dst and plaintext MUST alias exactly or not at all. @@ -164,7 +163,7 @@ open :: proc(ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool { mac_ctx: poly1305.Context = --- poly1305.init(&mac_ctx, otk[:]) - defer mem.zero_explicit(&otk, size_of(otk)) + defer crypto.zero_explicit(&otk, size_of(otk)) aad_len, ciphertext_len := len(aad), len(ciphertext) @@ -188,7 +187,7 @@ open :: proc(ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool { // Validate the tag in constant time. if crypto.compare_constant_time(tag, derived_tag) != 1 { // Zero out the plaintext, as a defense in depth measure. - mem.zero_explicit(raw_data(plaintext), ciphertext_len) + crypto.zero_explicit(raw_data(plaintext), ciphertext_len) return false } @@ -202,7 +201,7 @@ open :: proc(ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool { // reset sanitizes the Context. The Context must be // re-initialized to be used again. reset :: proc "contextless" (ctx: ^Context) { - mem.zero_explicit(&ctx._key, len(ctx._key)) + crypto.zero_explicit(&ctx._key, len(ctx._key)) ctx._is_xchacha = false ctx._is_initialized = false } diff --git a/core/crypto/crypto.odin b/core/crypto/crypto.odin index 7ccf126e6..f4ddbfbe7 100644 --- a/core/crypto/crypto.odin +++ b/core/crypto/crypto.odin @@ -1,18 +1,22 @@ // A selection of cryptography algorithms and useful helper routines. package crypto +import "base:intrinsics" import "base:runtime" -import "core:mem" +import subtle "core:crypto/_subtle" -// HAS_RAND_BYTES is true iff the runtime provides a cryptographic +// Omit large precomputed tables, trading off performance for size. +COMPACT_IMPLS: bool : #config(ODIN_CRYPTO_COMPACT, false) + +// HAS_RAND_BYTES is true if and only if (⟺) the runtime provides a cryptographic // entropy source. HAS_RAND_BYTES :: runtime.HAS_RAND_BYTES -// compare_constant_time returns 1 iff a and b are equal, 0 otherwise. +// compare_constant_time returns 1 if and only if (⟺) a and b are equal, 0 otherwise. // // The execution time of this routine is constant regardless of the contents // of the slices being compared, as long as the length of the slices is equal. -// If the length of the two slices is different, it will early-return 0. +// If the length of the two slices is dif and only if (⟺)erent, it will early-return 0. compare_constant_time :: proc "contextless" (a, b: []byte) -> int { // If the length of the slices is different, early return. // @@ -27,24 +31,69 @@ compare_constant_time :: proc "contextless" (a, b: []byte) -> int { return compare_byte_ptrs_constant_time(raw_data(a), raw_data(b), n) } -// compare_byte_ptrs_constant_time returns 1 iff the bytes pointed to by +// compare_byte_ptrs_constant_time returns 1 if and only if (⟺) the bytes pointed to by // a and b are equal, 0 otherwise. // // The execution time of this routine is constant regardless of the // contents of the memory being compared. @(optimization_mode="none") compare_byte_ptrs_constant_time :: proc "contextless" (a, b: ^byte, n: int) -> int { - x := mem.slice_ptr(a, n) - y := mem.slice_ptr(b, n) + x := ([^]byte)(a)[:n] + y := ([^]byte)(b)[:n] v: byte for i in 0..> 31) + // After the loop, v == 0 if and only if (⟺) a == b. The subtraction will underflow + // if and only if (⟺) v == 0, setting the sign-bit, which gets returned. + return subtle.eq(0, v) +} + +// is_zero_constant_time returns 1 if and only if (⟺) b is all 0s, 0 otherwise. +is_zero_constant_time :: proc "contextless" (b: []byte) -> int { + v: byte + for b_ in b { + v |= b_ + } + + return subtle.byte_eq(0, v) +} + +/* +Set each byte of a memory range to zero. + +This procedure copies the value `0` into the `len` bytes of a memory range, +starting at address `data`. + +This procedure returns the pointer to `data`. + +Unlike the `zero()` procedure, which can be optimized away or reordered by the +compiler under certain circumstances, `zero_explicit()` procedure can not be +optimized away or reordered with other memory access operations, and the +compiler assumes volatile semantics of the memory. +*/ +zero_explicit :: proc "contextless" (data: rawptr, len: int) -> rawptr { + // This routine tries to avoid the compiler optimizing away the call, + // so that it is always executed. It is intended to provide + // equivalent semantics to those provided by the C11 Annex K 3.7.4.1 + // memset_s call. + intrinsics.mem_zero_volatile(data, len) // Use the volatile mem_zero + intrinsics.atomic_thread_fence(.Seq_Cst) // Prevent reordering + return data +} + +/* +Set each byte of a memory range to a specific value. + +This procedure copies value specified by the `value` parameter into each of the +`len` bytes of a memory range, located at address `data`. + +This procedure returns the pointer to `data`. +*/ +set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr { + return runtime.memset(data, i32(value), len) } // rand_bytes fills the dst buffer with cryptographic entropy taken from @@ -56,7 +105,7 @@ compare_byte_ptrs_constant_time :: proc "contextless" (a, b: ^byte, n: int) -> i // `HAS_RAND_BYTES` boolean constant. rand_bytes :: proc (dst: []byte) { // zero-fill the buffer first - mem.zero_explicit(raw_data(dst), len(dst)) + zero_explicit(raw_data(dst), len(dst)) runtime.rand_bytes(dst) } diff --git a/core/crypto/deoxysii/deoxysii.odin b/core/crypto/deoxysii/deoxysii.odin index 3ebcfea30..ffe9b4b32 100644 --- a/core/crypto/deoxysii/deoxysii.odin +++ b/core/crypto/deoxysii/deoxysii.odin @@ -8,8 +8,8 @@ package deoxysii import "base:intrinsics" import "core:bytes" +import "core:crypto" import "core:crypto/aes" -import "core:mem" import "core:simd" // KEY_SIZE is the Deoxys-II-256 key size in bytes. @@ -122,7 +122,7 @@ seal :: proc(ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) { // open authenticates the aad and ciphertext, and decrypts the ciphertext, // with the provided Context, iv, and tag, and stores the output in dst, -// returning true iff the authentication was successful. If authentication +// returning true if and only if (⟺) the authentication was successful. If authentication // fails, the destination buffer will be zeroed. // // dst and plaintext MUST alias exactly or not at all. @@ -142,7 +142,7 @@ open :: proc(ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool { ok = d_ref(ctx, dst, iv, aad, ciphertext, tag) } if !ok { - mem.zero_explicit(raw_data(dst), len(ciphertext)) + crypto.zero_explicit(raw_data(dst), len(ciphertext)) } return ok @@ -151,7 +151,7 @@ open :: proc(ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool { // reset sanitizes the Context. The Context must be // re-initialized to be used again. reset :: proc "contextless" (ctx: ^Context) { - mem.zero_explicit(&ctx._subkeys, len(ctx._subkeys)) + crypto.zero_explicit(&ctx._subkeys, len(ctx._subkeys)) ctx._is_initialized = false } diff --git a/core/crypto/deoxysii/deoxysii_impl_ct64.odin b/core/crypto/deoxysii/deoxysii_impl_ct64.odin index c4d0edb03..e95eaa678 100644 --- a/core/crypto/deoxysii/deoxysii_impl_ct64.odin +++ b/core/crypto/deoxysii/deoxysii_impl_ct64.odin @@ -4,7 +4,6 @@ import "base:intrinsics" import "core:crypto" import aes "core:crypto/_aes/ct64" import "core:encoding/endian" -import "core:mem" import "core:simd" // This uses the bitlsiced 64-bit general purpose register SWAR AES @@ -149,8 +148,8 @@ bc_absorb :: proc "contextless" ( intrinsics.unaligned_store((^simd.u8x16)(raw_data(dst)), dst_) - mem.zero_explicit(&tweaks, size_of(tweaks)) - mem.zero_explicit(&tmp, size_of(tmp)) + crypto.zero_explicit(&tweaks, size_of(tweaks)) + crypto.zero_explicit(&tmp, size_of(tmp)) return stk_block_nr } @@ -214,8 +213,8 @@ bc_encrypt :: proc "contextless" ( nr_blocks -= n } - mem.zero_explicit(&tweaks, size_of(tweaks)) - mem.zero_explicit(&tmp, size_of(tmp)) + crypto.zero_explicit(&tweaks, size_of(tweaks)) + crypto.zero_explicit(&tmp, size_of(tmp)) return stk_block_nr } @@ -295,13 +294,13 @@ e_ref :: proc "contextless" (ctx: ^Context, dst, tag, iv, aad, plaintext: []byte copy(dst[n*BLOCK_SIZE:], m_star[:]) - mem.zero_explicit(&m_star, size_of(m_star)) + crypto.zero_explicit(&m_star, size_of(m_star)) } copy(tag, auth[:]) - mem.zero_explicit(&st.q_stk, size_of(st.q_stk)) - mem.zero_explicit(&st.q_b, size_of(st.q_b)) + crypto.zero_explicit(&st.q_stk, size_of(st.q_stk)) + crypto.zero_explicit(&st.q_b, size_of(st.q_b)) } @(private, require_results) @@ -336,7 +335,7 @@ d_ref :: proc "contextless" (ctx: ^Context, dst, iv, aad, ciphertext, tag: []byt copy(dst[n*BLOCK_SIZE:], m_star[:]) - mem.zero_explicit(&m_star, size_of(m_star)) + crypto.zero_explicit(&m_star, size_of(m_star)) } // Associated data @@ -382,7 +381,7 @@ d_ref :: proc "contextless" (ctx: ^Context, dst, iv, aad, ciphertext, tag: []byt _ = bc_absorb(&st, auth[:], m_star[:], PREFIX_MSG_FINAL, n) - mem.zero_explicit(&m_star, size_of(m_star)) + crypto.zero_explicit(&m_star, size_of(m_star)) } bc_final(&st, auth[:], iv) @@ -391,9 +390,9 @@ d_ref :: proc "contextless" (ctx: ^Context, dst, iv, aad, ciphertext, tag: []byt // else return false ok := crypto.compare_constant_time(auth[:], tag) == 1 - mem.zero_explicit(&auth, size_of(auth)) - mem.zero_explicit(&st.q_stk, size_of(st.q_stk)) - mem.zero_explicit(&st.q_b, size_of(st.q_b)) + crypto.zero_explicit(&auth, size_of(auth)) + crypto.zero_explicit(&st.q_stk, size_of(st.q_stk)) + crypto.zero_explicit(&st.q_b, size_of(st.q_b)) return ok -} +} \ No newline at end of file diff --git a/core/crypto/deoxysii/deoxysii_impl_hw_intel.odin b/core/crypto/deoxysii/deoxysii_impl_hw.odin similarity index 57% rename from core/crypto/deoxysii/deoxysii_impl_hw_intel.odin rename to core/crypto/deoxysii/deoxysii_impl_hw.odin index d268009a2..47f9ab55f 100644 --- a/core/crypto/deoxysii/deoxysii_impl_hw_intel.odin +++ b/core/crypto/deoxysii/deoxysii_impl_hw.odin @@ -1,153 +1,183 @@ -#+build amd64 +#+build amd64,arm64,arm32 package deoxysii import "base:intrinsics" import "core:crypto" -import "core:crypto/aes" -import "core:mem" +import aes_hw "core:crypto/_aes/hw" import "core:simd" -import "core:simd/x86" // This processes a maximum of 4 blocks at a time, as that is suitable // for most current hardware that doesn't say "Xeon". +// +// TODO/perf: ARM should be able to do 8 at a time. + +when ODIN_ARCH == .amd64 { + @(private="file") + TARGET_FEATURES :: "sse2,ssse3,aes" +} else when ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32 { + @(private="file") + TARGET_FEATURES :: "neon,aes" +} @(private = "file") -_BIT_ENC :: x86.__m128i{0x80, 0} +_BIT_ENC :: simd.u8x16{0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} @(private = "file") -_PREFIX_AD_BLOCK :: x86.__m128i{PREFIX_AD_BLOCK << PREFIX_SHIFT, 0} +_PREFIX_AD_BLOCK :: simd.u8x16{ + PREFIX_AD_BLOCK << PREFIX_SHIFT, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +} @(private = "file") -_PREFIX_AD_FINAL :: x86.__m128i{PREFIX_AD_FINAL << PREFIX_SHIFT, 0} +_PREFIX_AD_FINAL :: simd.u8x16{ + PREFIX_AD_FINAL << PREFIX_SHIFT, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +} @(private = "file") -_PREFIX_MSG_BLOCK :: x86.__m128i{PREFIX_MSG_BLOCK << PREFIX_SHIFT, 0} +_PREFIX_MSG_BLOCK :: simd.u8x16{ + PREFIX_MSG_BLOCK << PREFIX_SHIFT, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +} @(private = "file") -_PREFIX_MSG_FINAL :: x86.__m128i{PREFIX_MSG_FINAL << PREFIX_SHIFT, 0} +_PREFIX_MSG_FINAL :: simd.u8x16{ + PREFIX_MSG_FINAL << PREFIX_SHIFT, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +} -// is_hardware_accelerated returns true iff hardware accelerated Deoxys-II +// is_hardware_accelerated returns true if and only if (⟺) hardware accelerated Deoxys-II // is supported. is_hardware_accelerated :: proc "contextless" () -> bool { - return aes.is_hardware_accelerated() + return aes_hw.is_supported() } -@(private = "file", enable_target_feature = "sse4.1", require_results) +@(private = "file", enable_target_feature = TARGET_FEATURES, require_results) auth_tweak :: #force_inline proc "contextless" ( - prefix: x86.__m128i, + prefix: simd.u8x16, block_nr: int, -) -> x86.__m128i { - return x86._mm_insert_epi64(prefix, i64(intrinsics.byte_swap(u64(block_nr))), 1) -} +) -> simd.u8x16 { + when ODIN_ENDIAN == .Little { + block_nr_u64 := intrinsics.byte_swap(u64(block_nr)) + } else { + block_nr_u64 := u64(block_nr) + } -@(private = "file", enable_target_feature = "sse2", require_results) -enc_tweak :: #force_inline proc "contextless" ( - tag: x86.__m128i, - block_nr: int, -) -> x86.__m128i { - return x86._mm_xor_si128( - x86._mm_or_si128(tag, _BIT_ENC), - x86.__m128i{0, i64(intrinsics.byte_swap(u64(block_nr)))}, + return simd.bit_or( + prefix, + transmute(simd.u8x16)(simd.u64x2{0, block_nr_u64}), ) } -@(private = "file", enable_target_feature = "ssse3", require_results) -h_ :: #force_inline proc "contextless" (tk1: x86.__m128i) -> x86.__m128i { - return transmute(x86.__m128i)h(transmute(simd.u8x16)tk1) +@(private = "file", enable_target_feature = TARGET_FEATURES, require_results) +enc_tweak :: #force_inline proc "contextless" ( + tag: simd.u8x16, + block_nr: int, +) -> simd.u8x16 { + when ODIN_ENDIAN == .Little { + block_nr_u64 := intrinsics.byte_swap(u64(block_nr)) + } else { + block_nr_u64 := u64(block_nr) + } + + return simd.bit_xor( + simd.bit_or(tag, _BIT_ENC), + transmute(simd.u8x16)(simd.u64x2{0, block_nr_u64}), + ) } -@(private = "file", enable_target_feature = "sse2,ssse3,aes", require_results) +@(private = "file", enable_target_feature = TARGET_FEATURES, require_results) bc_x4 :: #force_inline proc "contextless" ( ctx: ^Context, - s_0, s_1, s_2, s_3: x86.__m128i, - tweak_0, tweak_1, tweak_2, tweak_3: x86.__m128i, -) -> (x86.__m128i, x86.__m128i, x86.__m128i, x86.__m128i) #no_bounds_check { + s_0, s_1, s_2, s_3: simd.u8x16, + tweak_0, tweak_1, tweak_2, tweak_3: simd.u8x16, +) -> (simd.u8x16, simd.u8x16, simd.u8x16, simd.u8x16) #no_bounds_check { s_0, s_1, s_2, s_3 := s_0, s_1, s_2, s_3 tk1_0, tk1_1, tk1_2, tk1_3 := tweak_0, tweak_1, tweak_2, tweak_3 - sk := intrinsics.unaligned_load((^x86.__m128i)(&ctx._subkeys[0])) - stk_0 := x86._mm_xor_si128(tk1_0, sk) - stk_1 := x86._mm_xor_si128(tk1_1, sk) - stk_2 := x86._mm_xor_si128(tk1_2, sk) - stk_3 := x86._mm_xor_si128(tk1_3, sk) + sk := intrinsics.unaligned_load((^simd.u8x16)(&ctx._subkeys[0])) + stk_0 := simd.bit_xor(tk1_0, sk) + stk_1 := simd.bit_xor(tk1_1, sk) + stk_2 := simd.bit_xor(tk1_2, sk) + stk_3 := simd.bit_xor(tk1_3, sk) - s_0 = x86._mm_xor_si128(s_0, stk_0) - s_1 = x86._mm_xor_si128(s_1, stk_1) - s_2 = x86._mm_xor_si128(s_2, stk_2) - s_3 = x86._mm_xor_si128(s_3, stk_3) + s_0 = simd.bit_xor(s_0, stk_0) + s_1 = simd.bit_xor(s_1, stk_1) + s_2 = simd.bit_xor(s_2, stk_2) + s_3 = simd.bit_xor(s_3, stk_3) for i in 1 ..= BC_ROUNDS { - sk = intrinsics.unaligned_load((^x86.__m128i)(&ctx._subkeys[i])) + sk = intrinsics.unaligned_load((^simd.u8x16)(&ctx._subkeys[i])) - tk1_0 = h_(tk1_0) - tk1_1 = h_(tk1_1) - tk1_2 = h_(tk1_2) - tk1_3 = h_(tk1_3) + tk1_0 = h(tk1_0) + tk1_1 = h(tk1_1) + tk1_2 = h(tk1_2) + tk1_3 = h(tk1_3) - stk_0 = x86._mm_xor_si128(tk1_0, sk) - stk_1 = x86._mm_xor_si128(tk1_1, sk) - stk_2 = x86._mm_xor_si128(tk1_2, sk) - stk_3 = x86._mm_xor_si128(tk1_3, sk) + stk_0 = simd.bit_xor(tk1_0, sk) + stk_1 = simd.bit_xor(tk1_1, sk) + stk_2 = simd.bit_xor(tk1_2, sk) + stk_3 = simd.bit_xor(tk1_3, sk) - s_0 = x86._mm_aesenc_si128(s_0, stk_0) - s_1 = x86._mm_aesenc_si128(s_1, stk_1) - s_2 = x86._mm_aesenc_si128(s_2, stk_2) - s_3 = x86._mm_aesenc_si128(s_3, stk_3) + s_0 = aes_hw.aesenc(s_0, stk_0) + s_1 = aes_hw.aesenc(s_1, stk_1) + s_2 = aes_hw.aesenc(s_2, stk_2) + s_3 = aes_hw.aesenc(s_3, stk_3) } return s_0, s_1, s_2, s_3 } -@(private = "file", enable_target_feature = "sse2,ssse3,aes", require_results) +@(private = "file", enable_target_feature = TARGET_FEATURES, require_results) bc_x1 :: #force_inline proc "contextless" ( ctx: ^Context, - s: x86.__m128i, - tweak: x86.__m128i, -) -> x86.__m128i #no_bounds_check { + s: simd.u8x16, + tweak: simd.u8x16, +) -> simd.u8x16 #no_bounds_check { s, tk1 := s, tweak - sk := intrinsics.unaligned_load((^x86.__m128i)(&ctx._subkeys[0])) - stk := x86._mm_xor_si128(tk1, sk) + sk := intrinsics.unaligned_load((^simd.u8x16)(&ctx._subkeys[0])) + stk := simd.bit_xor(tk1, sk) - s = x86._mm_xor_si128(s, stk) + s = simd.bit_xor(s, stk) for i in 1 ..= BC_ROUNDS { - sk = intrinsics.unaligned_load((^x86.__m128i)(&ctx._subkeys[i])) + sk = intrinsics.unaligned_load((^simd.u8x16)(&ctx._subkeys[i])) - tk1 = h_(tk1) + tk1 = h(tk1) - stk = x86._mm_xor_si128(tk1, sk) + stk = simd.bit_xor(tk1, sk) - s = x86._mm_aesenc_si128(s, stk) + s = aes_hw.aesenc(s, stk) } return s } -@(private = "file", enable_target_feature = "sse2,ssse3,sse4.1,aes", require_results) +@(private = "file", enable_target_feature = TARGET_FEATURES, require_results) bc_absorb :: proc "contextless" ( ctx: ^Context, - tag: x86.__m128i, + tag: simd.u8x16, src: []byte, - tweak_prefix: x86.__m128i, + tweak_prefix: simd.u8x16, stk_block_nr: int, -) -> (x86.__m128i, int) #no_bounds_check { +) -> (simd.u8x16, int) #no_bounds_check { src, stk_block_nr, tag := src, stk_block_nr, tag nr_blocks := len(src) / BLOCK_SIZE for nr_blocks >= 4 { d_0, d_1, d_2, d_3 := bc_x4( ctx, - intrinsics.unaligned_load((^x86.__m128i)(raw_data(src))), - intrinsics.unaligned_load((^x86.__m128i)(raw_data(src[BLOCK_SIZE:]))), - intrinsics.unaligned_load((^x86.__m128i)(raw_data(src[2*BLOCK_SIZE:]))), - intrinsics.unaligned_load((^x86.__m128i)(raw_data(src[3*BLOCK_SIZE:]))), + intrinsics.unaligned_load((^simd.u8x16)(raw_data(src))), + intrinsics.unaligned_load((^simd.u8x16)(raw_data(src[BLOCK_SIZE:]))), + intrinsics.unaligned_load((^simd.u8x16)(raw_data(src[2*BLOCK_SIZE:]))), + intrinsics.unaligned_load((^simd.u8x16)(raw_data(src[3*BLOCK_SIZE:]))), auth_tweak(tweak_prefix, stk_block_nr), auth_tweak(tweak_prefix, stk_block_nr + 1), auth_tweak(tweak_prefix, stk_block_nr + 2), auth_tweak(tweak_prefix, stk_block_nr + 3), ) - tag = x86._mm_xor_si128(tag, d_0) - tag = x86._mm_xor_si128(tag, d_1) - tag = x86._mm_xor_si128(tag, d_2) - tag = x86._mm_xor_si128(tag, d_3) + tag = simd.bit_xor(tag, d_0) + tag = simd.bit_xor(tag, d_1) + tag = simd.bit_xor(tag, d_2) + tag = simd.bit_xor(tag, d_3) src = src[4*BLOCK_SIZE:] stk_block_nr += 4 @@ -157,11 +187,11 @@ bc_absorb :: proc "contextless" ( for nr_blocks > 0 { d := bc_x1( ctx, - intrinsics.unaligned_load((^x86.__m128i)(raw_data(src))), + intrinsics.unaligned_load((^simd.u8x16)(raw_data(src))), auth_tweak(tweak_prefix, stk_block_nr), ) - tag = x86._mm_xor_si128(tag, d) + tag = simd.bit_xor(tag, d) src = src[BLOCK_SIZE:] stk_block_nr += 1 @@ -171,29 +201,29 @@ bc_absorb :: proc "contextless" ( return tag, stk_block_nr } -@(private = "file", enable_target_feature = "sse2,ssse3,aes", require_results) +@(private = "file", enable_target_feature = TARGET_FEATURES, require_results) bc_final :: proc "contextless" ( ctx: ^Context, - tag: x86.__m128i, + tag: simd.u8x16, iv: []byte, -) -> x86.__m128i { +) -> simd.u8x16 { tmp: [BLOCK_SIZE]byte tmp[0] = PREFIX_TAG << PREFIX_SHIFT copy(tmp[1:], iv) - tweak := intrinsics.unaligned_load((^x86.__m128i)(&tmp)) + tweak := intrinsics.unaligned_load((^simd.u8x16)(&tmp)) return bc_x1(ctx, tag, tweak) } -@(private = "file", enable_target_feature = "sse2,ssse3,aes", require_results) +@(private = "file", enable_target_feature = TARGET_FEATURES, require_results) bc_encrypt :: proc "contextless" ( ctx: ^Context, dst: []byte, src: []byte, - iv: x86.__m128i, - tweak_tag: x86.__m128i, + iv: simd.u8x16, + tweak_tag: simd.u8x16, stk_block_nr: int, ) -> int { dst, src, stk_block_nr := dst, src, stk_block_nr @@ -210,31 +240,31 @@ bc_encrypt :: proc "contextless" ( ) intrinsics.unaligned_store( - (^x86.__m128i)(raw_data(dst)), - x86._mm_xor_si128( + (^simd.u8x16)(raw_data(dst)), + simd.bit_xor( d_0, - intrinsics.unaligned_load((^x86.__m128i)(raw_data(src))), + intrinsics.unaligned_load((^simd.u8x16)(raw_data(src))), ), ) intrinsics.unaligned_store( - (^x86.__m128i)(raw_data(dst[BLOCK_SIZE:])), - x86._mm_xor_si128( + (^simd.u8x16)(raw_data(dst[BLOCK_SIZE:])), + simd.bit_xor( d_1, - intrinsics.unaligned_load((^x86.__m128i)(raw_data(src[BLOCK_SIZE:]))), + intrinsics.unaligned_load((^simd.u8x16)(raw_data(src[BLOCK_SIZE:]))), ), ) intrinsics.unaligned_store( - (^x86.__m128i)(raw_data(dst[2*BLOCK_SIZE:])), - x86._mm_xor_si128( + (^simd.u8x16)(raw_data(dst[2*BLOCK_SIZE:])), + simd.bit_xor( d_2, - intrinsics.unaligned_load((^x86.__m128i)(raw_data(src[2*BLOCK_SIZE:]))), + intrinsics.unaligned_load((^simd.u8x16)(raw_data(src[2*BLOCK_SIZE:]))), ), ) intrinsics.unaligned_store( - (^x86.__m128i)(raw_data(dst[3*BLOCK_SIZE:])), - x86._mm_xor_si128( + (^simd.u8x16)(raw_data(dst[3*BLOCK_SIZE:])), + simd.bit_xor( d_3, - intrinsics.unaligned_load((^x86.__m128i)(raw_data(src[3*BLOCK_SIZE:]))), + intrinsics.unaligned_load((^simd.u8x16)(raw_data(src[3*BLOCK_SIZE:]))), ), ) @@ -251,10 +281,10 @@ bc_encrypt :: proc "contextless" ( ) intrinsics.unaligned_store( - (^x86.__m128i)(raw_data(dst)), - x86._mm_xor_si128( + (^simd.u8x16)(raw_data(dst)), + simd.bit_xor( d, - intrinsics.unaligned_load((^x86.__m128i)(raw_data(src))), + intrinsics.unaligned_load((^simd.u8x16)(raw_data(src))), ), ) @@ -270,7 +300,7 @@ bc_encrypt :: proc "contextless" ( e_hw :: proc "contextless" (ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) #no_bounds_check { tmp: [BLOCK_SIZE]byte copy(tmp[1:], iv) - iv_ := intrinsics.unaligned_load((^x86.__m128i)(raw_data(&tmp))) + iv_ := intrinsics.unaligned_load((^simd.u8x16)(raw_data(&tmp))) // Algorithm 3 // @@ -283,7 +313,7 @@ e_hw :: proc "contextless" (ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) // if A_∗ != nil then // Auth <- Auth ^ EK(0110 || la, pad10∗(A_∗)) // end - auth: x86.__m128i + auth: simd.u8x16 n: int aad := aad @@ -342,14 +372,14 @@ e_hw :: proc "contextless" (ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) copy(dst[n*BLOCK_SIZE:], m_star[:]) } - intrinsics.unaligned_store((^x86.__m128i)(raw_data(tag)), auth) + intrinsics.unaligned_store((^simd.u8x16)(raw_data(tag)), auth) } @(private, require_results) d_hw :: proc "contextless" (ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool { tmp: [BLOCK_SIZE]byte copy(tmp[1:], iv) - iv_ := intrinsics.unaligned_load((^x86.__m128i)(raw_data(&tmp))) + iv_ := intrinsics.unaligned_load((^simd.u8x16)(raw_data(&tmp))) // Algorithm 4 // @@ -361,7 +391,7 @@ d_hw :: proc "contextless" (ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte // if C_∗ != nil then // M_∗ <- C_∗ ^ EK(1 || tag ^ l, 0^8 || N) // end - auth := intrinsics.unaligned_load((^x86.__m128i)(raw_data(tag))) + auth := intrinsics.unaligned_load((^simd.u8x16)(raw_data(tag))) m := ciphertext n := bc_encrypt(ctx, dst, m, iv_, auth, 0) @@ -374,7 +404,7 @@ d_hw :: proc "contextless" (ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte copy(dst[n*BLOCK_SIZE:], m_star[:]) - mem.zero_explicit(&m_star, size_of(m_star)) + crypto.zero_explicit(&m_star, size_of(m_star)) } // Associated data @@ -386,7 +416,7 @@ d_hw :: proc "contextless" (ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte // if A∗ != nil then // Auth <- Auth ^ EK(0110| | l_a, pad10∗(A_∗)) // end - auth = x86.__m128i{0, 0} + auth = simd.u8x16{} aad := aad auth, n = bc_absorb(ctx, auth, aad, _PREFIX_AD_BLOCK, 0) aad = aad[BLOCK_SIZE*n:] @@ -425,10 +455,10 @@ d_hw :: proc "contextless" (ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte // Tag verification // if tag0 = tag then return (M_1 || ... || M_l || M_∗) // else return false - intrinsics.unaligned_store((^x86.__m128i)(raw_data(&tmp)), auth) + intrinsics.unaligned_store((^simd.u8x16)(raw_data(&tmp)), auth) ok := crypto.compare_constant_time(tmp[:], tag) == 1 - mem.zero_explicit(&tmp, size_of(tmp)) + crypto.zero_explicit(&tmp, size_of(tmp)) return ok } diff --git a/core/crypto/deoxysii/deoxysii_impl_hw_gen.odin b/core/crypto/deoxysii/deoxysii_impl_hw_gen.odin index b0705ca62..7f5444535 100644 --- a/core/crypto/deoxysii/deoxysii_impl_hw_gen.odin +++ b/core/crypto/deoxysii/deoxysii_impl_hw_gen.odin @@ -1,10 +1,12 @@ #+build !amd64 +#+build !arm64 +#+build !arm32 package deoxysii @(private = "file") ERR_HW_NOT_SUPPORTED :: "crypto/deoxysii: hardware implementation unsupported" -// is_hardware_accelerated returns true iff hardware accelerated Deoxys-II +// is_hardware_accelerated returns true if and only if (⟺) hardware accelerated Deoxys-II // is supported. is_hardware_accelerated :: proc "contextless" () -> bool { return false diff --git a/core/crypto/ecdh/doc.odin b/core/crypto/ecdh/doc.odin new file mode 100644 index 000000000..e34f255f2 --- /dev/null +++ b/core/crypto/ecdh/doc.odin @@ -0,0 +1,4 @@ +/* +A generic interface to Elliptic Curve Diffie-Hellman key exchange. +*/ +package ecdh diff --git a/core/crypto/ecdh/ecdh.odin b/core/crypto/ecdh/ecdh.odin new file mode 100644 index 000000000..6a8f6e466 --- /dev/null +++ b/core/crypto/ecdh/ecdh.odin @@ -0,0 +1,455 @@ +package ecdh + +import "core:crypto" +import secec "core:crypto/_weierstrass" +import "core:crypto/x25519" +import "core:crypto/x448" +import "core:reflect" + +// Note: For these primitives scalar size = point size +@(private="file") +X25519_Buf :: [x25519.SCALAR_SIZE]byte +@(private="file") +X448_Buf :: [x448.SCALAR_SIZE]byte + +// Curve the curve identifier associated with a given Private_Key +// or Public_Key +Curve :: enum { + Invalid, + SECP256R1, + SECP384R1, + X25519, + X448, +} + +// CURVE_NAMES is the Curve to curve name string. +CURVE_NAMES := [Curve]string { + .Invalid = "Invalid", + .SECP256R1 = "secp256r1", + .SECP384R1 = "secp384r1", + .X25519 = "X25519", + .X448 = "X448", +} + +// PRIVATE_KEY_SIZES is the Curve to private key size in bytes. +PRIVATE_KEY_SIZES := [Curve]int { + .Invalid = 0, + .SECP256R1 = secec.SC_SIZE_P256R1, + .SECP384R1 = secec.SC_SIZE_P384R1, + .X25519 = x25519.SCALAR_SIZE, + .X448 = x448.SCALAR_SIZE, +} + +// PUBLIC_KEY_SIZES is the Curve to public key size in bytes. +PUBLIC_KEY_SIZES := [Curve]int { + .Invalid = 0, + .SECP256R1 = 1 + 2 * secec.FE_SIZE_P256R1, + .SECP384R1 = 1 + 2 * secec.FE_SIZE_P384R1, + .X25519 = x25519.POINT_SIZE, + .X448 = x448.POINT_SIZE, +} + +// SHARED_SECRET_SIZES is the Curve to shared secret size in bytes. +SHARED_SECRET_SIZES := [Curve]int { + .Invalid = 0, + .SECP256R1 = secec.FE_SIZE_P256R1, + .SECP384R1 = secec.FE_SIZE_P384R1, + .X25519 = x25519.POINT_SIZE, + .X448 = x448.POINT_SIZE, +} + +@(private="file") +_PRIV_IMPL_IDS := [Curve]typeid { + .Invalid = nil, + .SECP256R1 = typeid_of(secec.Scalar_p256r1), + .SECP384R1 = typeid_of(secec.Scalar_p384r1), + .X25519 = typeid_of(X25519_Buf), + .X448 = typeid_of(X448_Buf), +} + +@(private="file") +_PUB_IMPL_IDS := [Curve]typeid { + .Invalid = nil, + .SECP256R1 = typeid_of(secec.Point_p256r1), + .SECP384R1 = typeid_of(secec.Point_p384r1), + .X25519 = typeid_of(X25519_Buf), + .X448 = typeid_of(X448_Buf), +} + +// Private_Key is an ECDH private key. +Private_Key :: struct { + // WARNING: All of the members are to be treated as internal (ie: + // the Private_Key structure is intended to be opaque). + _curve: Curve, + _impl: union { + secec.Scalar_p256r1, + secec.Scalar_p384r1, + X25519_Buf, + X448_Buf, + }, + _pub_key: Public_Key, +} + +// Public_Key is an ECDH public key. +Public_Key :: struct { + // WARNING: All of the members are to be treated as internal (ie: + // the Public_Key structure is intended to be opaque). + _curve: Curve, + _impl: union { + secec.Point_p256r1, + secec.Point_p384r1, + X25519_Buf, + X448_Buf, + }, +} + +// private_key_generate uses the system entropy source to generate a new +// Private_Key. This will only fail if and only if (⟺) the system entropy source is +// missing or broken. +private_key_generate :: proc(priv_key: ^Private_Key, curve: Curve) -> bool { + private_key_clear(priv_key) + + if !crypto.HAS_RAND_BYTES { + return false + } + + reflect.set_union_variant_typeid( + priv_key._impl, + _PRIV_IMPL_IDS[curve], + ) + + #partial switch curve { + case .SECP256R1: + sc := &priv_key._impl.(secec.Scalar_p256r1) + secec.sc_set_random(sc) + case .SECP384R1: + sc := &priv_key._impl.(secec.Scalar_p384r1) + secec.sc_set_random(sc) + case .X25519: + sc := &priv_key._impl.(X25519_Buf) + crypto.rand_bytes(sc[:]) + case .X448: + sc := &priv_key._impl.(X448_Buf) + crypto.rand_bytes(sc[:]) + case: + panic("crypto/ecdh: invalid curve") + } + + priv_key._curve = curve + private_key_generate_public(priv_key) + + return true +} + +// private_key_set_bytes decodes a byte-encoded private key, and returns +// true if and only if (⟺) the operation was successful. +private_key_set_bytes :: proc(priv_key: ^Private_Key, curve: Curve, b: []byte) -> bool { + private_key_clear(priv_key) + + if len(b) != PRIVATE_KEY_SIZES[curve] { + return false + } + + reflect.set_union_variant_typeid( + priv_key._impl, + _PRIV_IMPL_IDS[curve], + ) + + #partial switch curve { + case .SECP256R1: + sc := &priv_key._impl.(secec.Scalar_p256r1) + did_reduce := secec.sc_set_bytes(sc, b) + is_zero := secec.sc_is_zero(sc) == 1 + + // Reject `0` and scalars that are not less than the + // curve order. + if did_reduce || is_zero { + private_key_clear(priv_key) + return false + } + case .SECP384R1: + sc := &priv_key._impl.(secec.Scalar_p384r1) + did_reduce := secec.sc_set_bytes(sc, b) + is_zero := secec.sc_is_zero(sc) == 1 + + // Reject `0` and scalars that are not less than the + // curve order. + if did_reduce || is_zero { + private_key_clear(priv_key) + return false + } + case .X25519: + sc := &priv_key._impl.(X25519_Buf) + copy(sc[:], b) + case .X448: + sc := &priv_key._impl.(X448_Buf) + copy(sc[:], b) + case: + panic("crypto/ecdh: invalid curve") + } + + priv_key._curve = curve + private_key_generate_public(priv_key) + + return true +} + +@(private="file") +private_key_generate_public :: proc(priv_key: ^Private_Key) { + switch &sc in priv_key._impl { + case secec.Scalar_p256r1: + pub_key: secec.Point_p256r1 = --- + secec.pt_scalar_mul_generator(&pub_key, &sc) + secec.pt_rescale(&pub_key, &pub_key) + priv_key._pub_key._impl = pub_key + case secec.Scalar_p384r1: + pub_key: secec.Point_p384r1 = --- + secec.pt_scalar_mul_generator(&pub_key, &sc) + secec.pt_rescale(&pub_key, &pub_key) + priv_key._pub_key._impl = pub_key + case X25519_Buf: + pub_key: X25519_Buf = --- + x25519.scalarmult_basepoint(pub_key[:], sc[:]) + priv_key._pub_key._impl = pub_key + case X448_Buf: + pub_key: X448_Buf = --- + x448.scalarmult_basepoint(pub_key[:], sc[:]) + priv_key._pub_key._impl = pub_key + case: + panic("crypto/ecdh: invalid curve") + } + + priv_key._pub_key._curve = priv_key._curve +} + +// private_key_bytes sets dst to byte-encoding of priv_key. +private_key_bytes :: proc(priv_key: ^Private_Key, dst: []byte) { + ensure(priv_key._curve != .Invalid, "crypto/ecdh: uninitialized private key") + ensure(len(dst) == PRIVATE_KEY_SIZES[priv_key._curve], "crypto/ecdh: invalid destination size") + + #partial switch priv_key._curve { + case .SECP256R1: + sc := &priv_key._impl.(secec.Scalar_p256r1) + secec.sc_bytes(dst, sc) + case .SECP384R1: + sc := &priv_key._impl.(secec.Scalar_p384r1) + secec.sc_bytes(dst, sc) + case .X25519: + sc := &priv_key._impl.(X25519_Buf) + copy(dst, sc[:]) + case .X448: + sc := &priv_key._impl.(X448_Buf) + copy(dst, sc[:]) + case: + panic("crypto/ecdh: invalid curve") + } +} + +// private_key_equal returns true if and only if (⟺) the private keys are equal, +// in constant time. +private_key_equal :: proc(p, q: ^Private_Key) -> bool { + if p._curve != q._curve { + return false + } + + #partial switch p._curve { + case .SECP256R1: + sc_p, sc_q := &p._impl.(secec.Scalar_p256r1), &q._impl.(secec.Scalar_p256r1) + return secec.sc_equal(sc_p, sc_q) == 1 + case .SECP384R1: + sc_p, sc_q := &p._impl.(secec.Scalar_p384r1), &q._impl.(secec.Scalar_p384r1) + return secec.sc_equal(sc_p, sc_q) == 1 + case .X25519: + b_p, b_q := &p._impl.(X25519_Buf), &q._impl.(X25519_Buf) + return crypto.compare_constant_time(b_p[:], b_q[:]) == 1 + case .X448: + b_p, b_q := &p._impl.(X448_Buf), &q._impl.(X448_Buf) + return crypto.compare_constant_time(b_p[:], b_q[:]) == 1 + case: + return false + } +} + +// private_key_clear clears priv_key to the uninitialized state. +private_key_clear :: proc "contextless" (priv_key: ^Private_Key) { + crypto.zero_explicit(priv_key, size_of(Private_Key)) +} + +// public_key_set_bytes decodes a byte-encoded public key, and returns +// true if and only if (⟺) the operation was successful. +public_key_set_bytes :: proc(pub_key: ^Public_Key, curve: Curve, b: []byte) -> bool { + public_key_clear(pub_key) + + if len(b) != PUBLIC_KEY_SIZES[curve] { + return false + } + + reflect.set_union_variant_typeid( + pub_key._impl, + _PUB_IMPL_IDS[curve], + ) + + #partial switch curve { + case .SECP256R1: + if b[0] != secec.SEC_PREFIX_UNCOMPRESSED { + return false + } + + pt := &pub_key._impl.(secec.Point_p256r1) + ok := secec.pt_set_sec_bytes(pt, b) + if !ok || secec.pt_is_identity(pt) == 1 { + return false + } + case .SECP384R1: + if b[0] != secec.SEC_PREFIX_UNCOMPRESSED { + return false + } + + pt := &pub_key._impl.(secec.Point_p384r1) + ok := secec.pt_set_sec_bytes(pt, b) + if !ok || secec.pt_is_identity(pt) == 1 { + return false + } + case .X25519: + pt := &pub_key._impl.(X25519_Buf) + copy(pt[:], b) + case .X448: + pt := &pub_key._impl.(X448_Buf) + copy(pt[:], b) + case: + panic("crypto/ecdh: invalid curve") + } + + pub_key._curve = curve + + return true +} + +// public_key_set_priv sets pub_key to the public component of priv_key. +public_key_set_priv :: proc(pub_key: ^Public_Key, priv_key: ^Private_Key) { + ensure(priv_key._curve != .Invalid, "crypto/ecdh: uninitialized private key") + public_key_clear(pub_key) + pub_key^ = priv_key._pub_key +} + +// public_key_bytes sets dst to byte-encoding of pub_key. +public_key_bytes :: proc(pub_key: ^Public_Key, dst: []byte) { + ensure(pub_key._curve != .Invalid, "crypto/ecdh: uninitialized public key") + ensure(len(dst) == PUBLIC_KEY_SIZES[pub_key._curve], "crypto/ecdh: invalid destination size") + + #partial switch pub_key._curve { + case .SECP256R1: + // Invariant: Unless the caller is manually building pub_key + // `Z = 1`, so we can skip the rescale. + pt := &pub_key._impl.(secec.Point_p256r1) + + dst[0] = secec.SEC_PREFIX_UNCOMPRESSED + secec.fe_bytes(dst[1:1+secec.FE_SIZE_P256R1], &pt.x) + secec.fe_bytes(dst[1+secec.FE_SIZE_P256R1:], &pt.y) + case .SECP384R1: + // Invariant: Unless the caller is manually building pub_key + // `Z = 1`, so we can skip the rescale. + pt := &pub_key._impl.(secec.Point_p384r1) + + dst[0] = secec.SEC_PREFIX_UNCOMPRESSED + secec.fe_bytes(dst[1:1+secec.FE_SIZE_P384R1], &pt.x) + secec.fe_bytes(dst[1+secec.FE_SIZE_P384R1:], &pt.y) + case .X25519: + pt := &pub_key._impl.(X25519_Buf) + copy(dst, pt[:]) + case .X448: + pt := &pub_key._impl.(X448_Buf) + copy(dst, pt[:]) + case: + panic("crypto/ecdh: invalid curve") + } +} + +// public_key_equal returns true if and only if (⟺) the public keys are equal, +// in constant time. +public_key_equal :: proc(p, q: ^Public_Key) -> bool { + if p._curve != q._curve { + return false + } + + #partial switch p._curve { + case .SECP256R1: + pt_p, pt_q := &p._impl.(secec.Point_p256r1), &q._impl.(secec.Point_p256r1) + return secec.pt_equal(pt_p, pt_q) == 1 + case .SECP384R1: + pt_p, pt_q := &p._impl.(secec.Point_p384r1), &q._impl.(secec.Point_p384r1) + return secec.pt_equal(pt_p, pt_q) == 1 + case .X25519: + b_p, b_q := &p._impl.(X25519_Buf), &q._impl.(X25519_Buf) + return crypto.compare_constant_time(b_p[:], b_q[:]) == 1 + case .X448: + b_p, b_q := &p._impl.(X448_Buf), &q._impl.(X448_Buf) + return crypto.compare_constant_time(b_p[:], b_q[:]) == 1 + case: + panic("crypto/ecdh: invalid curve") + } +} + +// public_key_clear clears pub_key to the uninitialized state. +public_key_clear :: proc "contextless" (pub_key: ^Public_Key) { + crypto.zero_explicit(pub_key, size_of(Public_Key)) +} + +// ecdh performs an Elliptic Curve Diffie-Hellman key exchange betwween +// the Private_Key and Public_Key, writing the shared secret to dst. +// +// The neutral element is rejected as an error. +@(require_results) +ecdh :: proc(priv_key: ^Private_Key, pub_key: ^Public_Key, dst: []byte) -> bool { + ensure(priv_key._curve == pub_key._curve, "crypto/ecdh: curve mismatch") + ensure(pub_key._curve != .Invalid, "crypto/ecdh: uninitialized public key") + ensure(len(dst) == SHARED_SECRET_SIZES[priv_key._curve], "crypto/ecdh: invalid shared secret size") + + #partial switch priv_key._curve { + case .SECP256R1: + sc, pt := &priv_key._impl.(secec.Scalar_p256r1), &pub_key._impl.(secec.Point_p256r1) + ss: secec.Point_p256r1 + defer secec.pt_clear(&ss) + + secec.pt_scalar_mul(&ss, pt, sc) + return secec.pt_bytes(dst, nil, &ss) + case .SECP384R1: + sc, pt := &priv_key._impl.(secec.Scalar_p384r1), &pub_key._impl.(secec.Point_p384r1) + ss: secec.Point_p384r1 + defer secec.pt_clear(&ss) + + secec.pt_scalar_mul(&ss, pt, sc) + return secec.pt_bytes(dst, nil, &ss) + case .X25519: + sc, pt := &priv_key._impl.(X25519_Buf), &pub_key._impl.(X25519_Buf) + x25519.scalarmult(dst, sc[:], pt[:]) + case .X448: + sc, pt := &priv_key._impl.(X448_Buf), &pub_key._impl.(X448_Buf) + x448.scalarmult(dst, sc[:], pt[:]) + case: + panic("crypto/ecdh: invalid curve") + } + + // X25519/X448 check for all zero digest. + return crypto.is_zero_constant_time(dst) == 0 +} + +// curve returns the Curve used by a Private_Key or Public_Key instance. +curve :: proc(k: ^$T) -> Curve where(T == Private_Key || T == Public_Key) { + return k._curve +} + +// key_size returns the key size of a Private_Key or Public_Key in bytes. +key_size :: proc(k: ^$T) -> int where(T == Private_Key || T == Public_Key) { + when T == Private_Key { + return PRIVATE_KEY_SIZES[k._curve] + } else { + return PUBLIC_KEY_SIZES[k._curve] + } +} + +// shared_secret_size returns the shared secret size of a key exchange +// in bytes. +shared_secret_size :: proc(k: ^$T) -> int where(T == Private_Key || T == Public_Key) { + return SHARED_SECRET_SIZES[k._curve] +} diff --git a/core/crypto/ecdsa/doc.odin b/core/crypto/ecdsa/doc.odin new file mode 100644 index 000000000..8d60f3c52 --- /dev/null +++ b/core/crypto/ecdsa/doc.odin @@ -0,0 +1,7 @@ +/* +Elliptic Curve Digital Signature Algorithm per SEC 2.0 section 4.1. + +See: +- [[ https://secg.org/sec1-v2.pdf ]] +*/ +package ecdsa diff --git a/core/crypto/ecdsa/ecdsa.odin b/core/crypto/ecdsa/ecdsa.odin new file mode 100644 index 000000000..6c71feef7 --- /dev/null +++ b/core/crypto/ecdsa/ecdsa.odin @@ -0,0 +1,321 @@ +package ecdsa + +import "core:crypto" +import secec "core:crypto/_weierstrass" +import "core:mem" +import "core:reflect" + +// Curve the curve identifier associated with a given Private_Key +// or Public_Key +Curve :: enum { + Invalid, + SECP256R1, + SECP384R1, +} + +// CURVE_NAMES is the Curve to curve name string. +CURVE_NAMES := [Curve]string { + .Invalid = "Invalid", + .SECP256R1 = "secp256r1", + .SECP384R1 = "secp384r1", +} + +// PRIVATE_KEY_SIZES is the Curve to private key size in bytes. +PRIVATE_KEY_SIZES := [Curve]int { + .Invalid = 0, + .SECP256R1 = secec.SC_SIZE_P256R1, + .SECP384R1 = secec.SC_SIZE_P384R1, +} + +// PUBLIC_KEY_SIZES is the Curve to public key size in bytes. +PUBLIC_KEY_SIZES := [Curve]int { + .Invalid = 0, + .SECP256R1 = 1 + 2 * secec.FE_SIZE_P256R1, + .SECP384R1 = 1 + 2 * secec.FE_SIZE_P384R1, +} + +// RAW_SIGNATURE_SIZES is the Curve to "raw" signature size in bytes. +RAW_SIGNATURE_SIZES := [Curve]int { + .Invalid = 0, + .SECP256R1 = 2 * secec.SC_SIZE_P256R1, + .SECP384R1 = 2 * secec.SC_SIZE_P384R1, +} + +@(private="file") +_PRIV_IMPL_IDS := [Curve]typeid { + .Invalid = nil, + .SECP256R1 = typeid_of(secec.Scalar_p256r1), + .SECP384R1 = typeid_of(secec.Scalar_p384r1), +} + +@(private="file") +_PUB_IMPL_IDS := [Curve]typeid { + .Invalid = nil, + .SECP256R1 = typeid_of(secec.Point_p256r1), + .SECP384R1 = typeid_of(secec.Point_p384r1), +} + +// Private_Key is an ECDSA private key. +Private_Key :: struct { + // WARNING: All of the members are to be treated as internal (ie: + // the Private_Key structure is intended to be opaque). + _curve: Curve, + _impl: union { + secec.Scalar_p256r1, + secec.Scalar_p384r1, + }, + _pub_key: Public_Key, +} + +// Public_Key is an ECDSA public key. +Public_Key :: struct { + // WARNING: All of the members are to be treated as internal (ie: + // the Public_Key structure is intended to be opaque). + _curve: Curve, + _impl: union { + secec.Point_p256r1, + secec.Point_p384r1, + }, +} + +// private_key_generate uses the system entropy source to generate a new +// Private_Key. This will only fail if and only if (⟺) the system entropy source is +// missing or broken. +private_key_generate :: proc(priv_key: ^Private_Key, curve: Curve) -> bool { + private_key_clear(priv_key) + + if !crypto.HAS_RAND_BYTES { + return false + } + + reflect.set_union_variant_typeid( + priv_key._impl, + _PRIV_IMPL_IDS[curve], + ) + + #partial switch curve { + case .SECP256R1: + sc := &priv_key._impl.(secec.Scalar_p256r1) + secec.sc_set_random(sc) + case .SECP384R1: + sc := &priv_key._impl.(secec.Scalar_p384r1) + secec.sc_set_random(sc) + case: + panic("crypto/ecdsa: invalid curve") + } + + priv_key._curve = curve + private_key_generate_public(priv_key) + + return true +} + +// private_key_set_bytes decodes a byte-encoded private key, and returns +// true if and only if (⟺) the operation was successful. +private_key_set_bytes :: proc(priv_key: ^Private_Key, curve: Curve, b: []byte) -> bool { + private_key_clear(priv_key) + + if len(b) != PRIVATE_KEY_SIZES[curve] { + return false + } + + reflect.set_union_variant_typeid( + priv_key._impl, + _PRIV_IMPL_IDS[curve], + ) + + #partial switch curve { + case .SECP256R1: + sc := &priv_key._impl.(secec.Scalar_p256r1) + did_reduce := secec.sc_set_bytes(sc, b) + is_zero := secec.sc_is_zero(sc) == 1 + + // Reject `0` and scalars that are not less than the + // curve order. + if did_reduce || is_zero { + private_key_clear(priv_key) + return false + } + case .SECP384R1: + sc := &priv_key._impl.(secec.Scalar_p384r1) + did_reduce := secec.sc_set_bytes(sc, b) + is_zero := secec.sc_is_zero(sc) == 1 + + // Reject `0` and scalars that are not less than the + // curve order. + if did_reduce || is_zero { + private_key_clear(priv_key) + return false + } + case: + panic("crypto/esa: invalid curve") + } + + priv_key._curve = curve + private_key_generate_public(priv_key) + + return true +} + +@(private="file") +private_key_generate_public :: proc(priv_key: ^Private_Key) { + switch &sc in priv_key._impl { + case secec.Scalar_p256r1: + pub_key: secec.Point_p256r1 = --- + secec.pt_scalar_mul_generator(&pub_key, &sc) + secec.pt_rescale(&pub_key, &pub_key) + priv_key._pub_key._impl = pub_key + case secec.Scalar_p384r1: + pub_key: secec.Point_p384r1 = --- + secec.pt_scalar_mul_generator(&pub_key, &sc) + secec.pt_rescale(&pub_key, &pub_key) + priv_key._pub_key._impl = pub_key + case: + panic("crypto/ecdsa: invalid curve") + } + + priv_key._pub_key._curve = priv_key._curve +} + +// private_key_bytes sets dst to byte-encoding of priv_key. +private_key_bytes :: proc(priv_key: ^Private_Key, dst: []byte) { + ensure(priv_key._curve != .Invalid, "crypto/ecdsa: uninitialized private key") + ensure(len(dst) == PRIVATE_KEY_SIZES[priv_key._curve], "crypto/ecdsa: invalid destination size") + + #partial switch priv_key._curve { + case .SECP256R1: + sc := &priv_key._impl.(secec.Scalar_p256r1) + secec.sc_bytes(dst, sc) + case .SECP384R1: + sc := &priv_key._impl.(secec.Scalar_p384r1) + secec.sc_bytes(dst, sc) + case: + panic("crypto/ecdsa: invalid curve") + } +} + +// private_key_equal returns true if and only if (⟺) the private keys are equal, +// in constant time. +private_key_equal :: proc(p, q: ^Private_Key) -> bool { + if p._curve != q._curve { + return false + } + + #partial switch p._curve { + case .SECP256R1: + sc_p, sc_q := &p._impl.(secec.Scalar_p256r1), &q._impl.(secec.Scalar_p256r1) + return secec.sc_equal(sc_p, sc_q) == 1 + case .SECP384R1: + sc_p, sc_q := &p._impl.(secec.Scalar_p384r1), &q._impl.(secec.Scalar_p384r1) + return secec.sc_equal(sc_p, sc_q) == 1 + case: + return false + } +} + +// private_key_clear clears priv_key to the uninitialized state. +private_key_clear :: proc "contextless" (priv_key: ^Private_Key) { + mem.zero_explicit(priv_key, size_of(Private_Key)) +} + +// public_key_set_bytes decodes a byte-encoded public key, and returns +// true if and only if (⟺) the operation was successful. +public_key_set_bytes :: proc(pub_key: ^Public_Key, curve: Curve, b: []byte) -> bool { + public_key_clear(pub_key) + + if len(b) != PUBLIC_KEY_SIZES[curve] { + return false + } + + reflect.set_union_variant_typeid( + pub_key._impl, + _PUB_IMPL_IDS[curve], + ) + + #partial switch curve { + case .SECP256R1: + if b[0] != secec.SEC_PREFIX_UNCOMPRESSED { + return false + } + + pt := &pub_key._impl.(secec.Point_p256r1) + ok := secec.pt_set_sec_bytes(pt, b) + if !ok || secec.pt_is_identity(pt) == 1 { + return false + } + case .SECP384R1: + if b[0] != secec.SEC_PREFIX_UNCOMPRESSED { + return false + } + + pt := &pub_key._impl.(secec.Point_p384r1) + ok := secec.pt_set_sec_bytes(pt, b) + if !ok || secec.pt_is_identity(pt) == 1 { + return false + } + case: + panic("crypto/ecdsa: invalid curve") + } + + pub_key._curve = curve + + return true +} + +// public_key_set_priv sets pub_key to the public component of priv_key. +public_key_set_priv :: proc(pub_key: ^Public_Key, priv_key: ^Private_Key) { + ensure(priv_key._curve != .Invalid, "crypto/ecdsa: uninitialized private key") + public_key_clear(pub_key) + pub_key^ = priv_key._pub_key +} + +// public_key_bytes sets dst to byte-encoding of pub_key. +public_key_bytes :: proc(pub_key: ^Public_Key, dst: []byte) { + ensure(pub_key._curve != .Invalid, "crypto/ecdsa: uninitialized public key") + ensure(len(dst) == PUBLIC_KEY_SIZES[pub_key._curve], "crypto/ecdsa: invalid destination size") + + #partial switch pub_key._curve { + case .SECP256R1: + // Invariant: Unless the caller is manually building pub_key + // `Z = 1`, so we can skip the rescale. + pt := &pub_key._impl.(secec.Point_p256r1) + + dst[0] = secec.SEC_PREFIX_UNCOMPRESSED + secec.fe_bytes(dst[1:1+secec.FE_SIZE_P256R1], &pt.x) + secec.fe_bytes(dst[1+secec.FE_SIZE_P256R1:], &pt.y) + case .SECP384R1: + // Invariant: Unless the caller is manually building pub_key + // `Z = 1`, so we can skip the rescale. + pt := &pub_key._impl.(secec.Point_p384r1) + + dst[0] = secec.SEC_PREFIX_UNCOMPRESSED + secec.fe_bytes(dst[1:1+secec.FE_SIZE_P384R1], &pt.x) + secec.fe_bytes(dst[1+secec.FE_SIZE_P384R1:], &pt.y) + case: + panic("crypto/ecdsa: invalid curve") + } +} + +// public_key_equal returns true if and only if (⟺) the public keys are equal, +// in constant time. +public_key_equal :: proc(p, q: ^Public_Key) -> bool { + if p._curve != q._curve { + return false + } + + #partial switch p._curve { + case .SECP256R1: + pt_p, pt_q := &p._impl.(secec.Point_p256r1), &q._impl.(secec.Point_p256r1) + return secec.pt_equal(pt_p, pt_q) == 1 + case .SECP384R1: + pt_p, pt_q := &p._impl.(secec.Point_p384r1), &q._impl.(secec.Point_p384r1) + return secec.pt_equal(pt_p, pt_q) == 1 + case: + panic("crypto/ecdsa: invalid curve") + } +} + +// public_key_clear clears pub_key to the uninitialized state. +public_key_clear :: proc "contextless" (pub_key: ^Public_Key) { + mem.zero_explicit(pub_key, size_of(Public_Key)) +} diff --git a/core/crypto/ecdsa/ecdsa_asn1.odin b/core/crypto/ecdsa/ecdsa_asn1.odin new file mode 100644 index 000000000..74c9d65e6 --- /dev/null +++ b/core/crypto/ecdsa/ecdsa_asn1.odin @@ -0,0 +1,183 @@ +package ecdsa + +import secec "core:crypto/_weierstrass" + +// ASN.1 format ECDSA signatures are`SEQUENCE { r INTEGER, s INTEGER }` +// this implements enough to generate/parse signatures. Eventually when +// we have a full ASN.1 DER library, these routines will be removed. + +@(private="file") +TAG_SEQUENCE :: 0x30 +@(private="file") +TAG_INTEGER :: 0x02 + +@(private,require_results) +generate_asn1_sig :: proc(r, s: ^$T, allocator := context.allocator) -> []byte { + when T == secec.Scalar_p256r1 { + SC_SZ :: secec.SC_SIZE_P256R1 + } else when T == secec.Scalar_p384r1 { + SC_SZ :: secec.SC_SIZE_P384R1 + } else { + #panic("crypto/ecdsa: invalid curve") + } + + INT_TLP :: 3 // tag, tength, (optional) leading zero-byte + encode_uint :: proc(b: []byte) -> []byte { + b := b + + // DER requires minimal encoding. + off := INT_TLP + for v in b[off:] { + if v != 0 { + break + } + off += 1 + } + // If the sign big is set, add a leading zero. + if b[off] & 0x80 == 0x80 { + off -= 1 + b[off] = 0 + } + + // Encode the length (up to 127 octets, adequate for ECDSA). + l := len(b[off:]) + off -= 1 + b[off] = byte(l) + + // Encode the tag + off -= 1 + b[off] = TAG_INTEGER + + return b[off:] + } + + r_buf, s_buf: [INT_TLP+SC_SZ]byte = ---, --- + secec.sc_bytes(r_buf[INT_TLP:], r) + secec.sc_bytes(s_buf[INT_TLP:], s) + + r_bytes, s_bytes := encode_uint(r_buf[:]), encode_uint(s_buf[:]) + seq_len := len(r_bytes) + len(s_bytes) + + // WARNING: If secp521r1 support is added, this needs to support + // long-form length encoding. + ensure(seq_len <= 127, "BUG: crypto/ecdsa: signature length too large") + b := make([]byte, seq_len + 2, allocator) + b[0] = TAG_SEQUENCE + b[1] = byte(seq_len) + copy(b[2:], r_bytes) + copy(b[2+len(r_bytes):], s_bytes) + + return b +} + +@(private,require_results) +parse_asn1_sig :: proc(sig: []byte) -> (r, s: []byte, ok: bool) { + read_seq :: proc(b: []byte) -> (v: []byte, rest: []byte, ok: bool) { + b_len := len(b) + if b_len < 3 { + return nil, nil, false + } + if b[0] != TAG_SEQUENCE { + return nil, nil, false + } + seq_len, off: int + if b[1] & 0x80 == 0x80 { + if b[1] != 0x81 || b_len < 4 { // 2-length octets is sufficient for ecdsa. + return nil, nil, false + } + if b[2] & 0x80 == 0x80 || b[3] & 0x80 == 80 { + return nil, nil, false + } + seq_len = int(b[2]) * 127 + int(b[3]) + off = 4 + } else { + seq_len = int(b[1]) + off = 2 + } + if b_len - off < seq_len { + return nil, nil, false + } + return b[off:off+seq_len], b[off+seq_len:], true + } + + read_int :: proc(b: []byte) -> (v: []byte, rest: []byte, ok: bool) { + b_len := len(b) + if b_len < 3 { + return nil, nil, false + } + if b[0] != TAG_INTEGER { + return nil, nil, false + } + v_len := int(b[1]) + if v_len > 0x80 || b_len - 2 < v_len { // 127-bytes max. + return nil, nil, false + } + + return b[2:2+v_len], b[2+v_len:], true + } + + // SEQUENCE + seq_bytes, rest: []byte + seq_bytes, rest, ok = read_seq(sig) + if !ok { + return nil, nil, false + } + if len(rest) != 0 { + return nil, nil, false + } + + // INTEGER (r) + r, rest, ok = read_int(seq_bytes) + if !ok { + return nil, nil, false + } + + // INTEGER (s) + s, rest, ok = read_int(rest) + if !ok { + return nil, nil, false + } + if len(rest) != 0 { + return nil, nil, false + } + + // DER requires a leading 0 if and only if (⟺) the sign bit of the leading byte + // is set to distinguish between positive and negative integers, + // and the minimal length representation. `r` and `s` are always + // going to be unsigned, so we validate malformed DER and strip + // the leading 0 as needed. + fixup_der_uint :: proc(b: []byte) -> ([]byte, bool) { + switch len(b) { + case 0: + // 0 length is invalid + return nil, false + case 1: + // Missing leading zero + if b[0] & 0x80 == 0x80 { + return nil, false + } + case: + if b[0] == 0 { + // Sign bit not set + if b[1] & 0x80 != 0x80 { + return nil, false + } + return b[1:], true + } else if b[0] & 0x80 == 0x80 { + // Missing leading zero + return nil, false + } + } + + return b, true + } + + if r, ok = fixup_der_uint(r); !ok { + return nil, nil, false + } + if s, ok = fixup_der_uint(s); !ok { + return nil, nil, false + } + + return r, s, true +} diff --git a/core/crypto/ecdsa/ecdsa_k_rfc6979.odin b/core/crypto/ecdsa/ecdsa_k_rfc6979.odin new file mode 100644 index 000000000..01d2bb911 --- /dev/null +++ b/core/crypto/ecdsa/ecdsa_k_rfc6979.odin @@ -0,0 +1,98 @@ +package ecdsa + +import "core:crypto" +import "core:crypto/hash" +import "core:crypto/hmac" +import secec "core:crypto/_weierstrass" + +@(private) +Drbg_RFC6979 :: struct { + v: [hash.MAX_DIGEST_SIZE]byte, + k: [hash.MAX_DIGEST_SIZE]byte, + + algorithm: hash.Algorithm, + sz: int, + need_update: bool, +} + +@(private) +init_drbg_rfc6979 :: proc(rng: ^Drbg_RFC6979, algorithm: hash.Algorithm, x_bytes, e_bytes: []byte, deterministic: bool) { + rng.algorithm = algorithm + rng.sz = hash.DIGEST_SIZES[algorithm] + rng.need_update = false + for i in 0.. bool { + // Extremely unlikely, so avoid unless the rejection + // sampling triggers. + if rng.need_update { + drbg_update_k(rng) + drbg_update_v(rng) + } + + drbg_update_v(rng) + rng.need_update = true + + return secec.sc_set_bytes(sc, rng.v[:secec.sc_size(sc)]) +} + +@(private) +drbg_clear_rfc6979 :: proc(rng: ^Drbg_RFC6979) { + crypto.zero_explicit(rng, size_of(Drbg_RFC6979)) +} + +@(private="file") +drbg_update_v :: proc(rng: ^Drbg_RFC6979) { + // V = HMAC_K(V) + k, v := rng.k[:rng.sz], rng.v[:rng.sz] + hmac.sum(rng.algorithm, v, v, k) +} + +@(private="file") +drbg_update_k :: proc(rng: ^Drbg_RFC6979) { + // K = HMAC_K(V || 0x00) + k, v := rng.k[:rng.sz], rng.v[:rng.sz] + + ctx: hmac.Context + hmac.init(&ctx, rng.algorithm, k) + hmac.update(&ctx, v) + hmac.update(&ctx, []byte{0x00}) + hmac.final(&ctx, k) +} + +@(private="file") +drbg_init_update_k :: proc(rng: ^Drbg_RFC6979, i2o_b, b2o_h1: []byte, internal_octet: byte, additional_input: []byte) { + k, v := rng.k[:rng.sz], rng.v[:rng.sz] + + ctx: hmac.Context + hmac.init(&ctx, rng.algorithm, k) + hmac.update(&ctx, v) + hmac.update(&ctx, []byte{internal_octet}) + hmac.update(&ctx, i2o_b) + hmac.update(&ctx, b2o_h1) + if additional_input != nil { + hmac.update(&ctx, additional_input) + } + hmac.final(&ctx, k) +} diff --git a/core/crypto/ecdsa/ecdsa_sign.odin b/core/crypto/ecdsa/ecdsa_sign.odin new file mode 100644 index 000000000..c6fec56dc --- /dev/null +++ b/core/crypto/ecdsa/ecdsa_sign.odin @@ -0,0 +1,201 @@ +package ecdsa + +import "base:runtime" +import "core:crypto" +import "core:crypto/hash" +import secec "core:crypto/_weierstrass" + +// sign_asn1 returns the signature by priv_key over msg hased using hash_algo +// using the signing procedure as specified in SEC 1, Version 2.0, Section +// 4.1.3. ASN.1 DER requires minimal encoding, and the format is clunky +// and variable-length so for simplicity we allocate the signature. +// +// The signature format is ASN1. `SEQUECE `{ r INTEGER, s INTEGER }`. +@(require_results) +sign_asn1 :: proc(priv_key: ^Private_Key, hash_algo: hash.Algorithm, msg: []byte, allocator: runtime.Allocator, deterministic := !crypto.HAS_RAND_BYTES) -> ([]byte, bool) { + ensure(hash_algo != .Invalid, "crypto/edsa: invalid hash algorithm") + ensure(priv_key._curve != .Invalid, "crypto/edsa: invalid curve") + + if !deterministic && !crypto.HAS_RAND_BYTES { + return nil, false + } + + #partial switch priv_key._curve { + case .SECP256R1: + SC_SZ :: secec.SC_SIZE_P256R1 + RAW_SIG_SZ :: 2 * SC_SZ + r, s: secec.Scalar_p256r1 = ---, --- + sk := &priv_key._impl.(secec.Scalar_p256r1) + sign_internal(sk, &r, &s, hash_algo, msg, deterministic) + + return generate_asn1_sig(&r, &s, allocator), true + case .SECP384R1: + SC_SZ :: secec.SC_SIZE_P384R1 + RAW_SIG_SZ :: 2 * SC_SZ + r, s: secec.Scalar_p384r1 = ---, --- + sk := &priv_key._impl.(secec.Scalar_p384r1) + sign_internal(sk, &r, &s, hash_algo, msg, deterministic) + + return generate_asn1_sig(&r, &s, allocator), true + } + + return nil, false +} + +// sign_raw writes the signature by priv_key over msg hased using hash_algo +// to sig, using the signing procedure as specified in SEC 1, Version 2.0, +// Section 4.1.3. +// +// The signature format is `r | s`. +@(require_results) +sign_raw :: proc(priv_key: ^Private_Key, hash_algo: hash.Algorithm, msg, sig: []byte, deterministic := !crypto.HAS_RAND_BYTES) -> bool { + ensure(hash_algo != .Invalid, "crypto/edsa: invalid hash algorithm") + ensure(priv_key._curve != .Invalid, "crypto/edsa: invalid curve") + ensure(len(sig) == RAW_SIGNATURE_SIZES[priv_key._curve], "crypto/ecdsa: invalid destination size") + + if !deterministic && !crypto.HAS_RAND_BYTES { + return false + } + + #partial switch priv_key._curve { + case .SECP256R1: + SC_SZ :: secec.SC_SIZE_P256R1 + r, s: secec.Scalar_p256r1 = ---, --- + sk := &priv_key._impl.(secec.Scalar_p256r1) + sign_internal(sk, &r, &s, hash_algo, msg, deterministic) + + r_bytes, s_bytes := sig[:SC_SZ], sig[SC_SZ:] + secec.sc_bytes(r_bytes, &r) + secec.sc_bytes(s_bytes, &s) + case .SECP384R1: + SC_SZ :: secec.SC_SIZE_P384R1 + r, s: secec.Scalar_p384r1 = ---, --- + sk := &priv_key._impl.(secec.Scalar_p384r1) + sign_internal(sk, &r, &s, hash_algo, msg, deterministic) + + r_bytes, s_bytes := sig[:SC_SZ], sig[SC_SZ:] + secec.sc_bytes(r_bytes, &r) + secec.sc_bytes(s_bytes, &s) + case: + panic("crypto/ecdsa: invalid curve") + } + + return true +} + +@(private) +sign_internal :: proc(priv_key, sig_r, sig_s: ^$T, hash_algo: hash.Algorithm, msg: []byte, deterministic: bool) { + when T == secec.Scalar_p256r1 { + SC_SZ :: secec.SC_SIZE_P256R1 + FE_SZ :: secec.FE_SIZE_P256R1 + MIN_DRBG_HASH :: hash.Algorithm.SHA256 + r_pt: secec.Point_p256r1 = --- + } else when T == secec.Scalar_p384r1 { + SC_SZ :: secec.SC_SIZE_P384R1 + FE_SZ :: secec.FE_SIZE_P384R1 + MIN_DRBG_HASH :: hash.Algorithm.SHA384 + r_pt: secec.Point_p384r1 = --- + } else { + #panic("crypto/ecdsa: invalid curve") + } + + // Note: `e` (derived from `hash`) in steps 4 and 5, is + // unchanged throughout the process even if a different `k` + // needs to be selected, thus, the value is derived first + // before the rejection sampling loop. + + // 4. Use the hash function selected during the setup procedure + // to compute the hash value: + // H = Hash(M) + // of length hashlen octets as specified in Section 3.5. If the + // hash function outputs “invalid”, output “invalid” and stop. + + // 5. Derive an integer e from H as follows: + // 5.1. Convert the octet string H to a bit string H using the + // conversion routine specified in Section 2.3.2. + // 5.2. Set E = H if ceil(log2(n)) >= 8(hashlen), and set E equal + // to the leftmost ceil(log2(n)) bits of H if ceil(log2(n)) < + // 8(hashlen). + // 5.3. Convert the bit string E to an octet string E using the + // conversion routine specified in Section 2.3.1. + // 5.4. Convert the octet string E to an integer e using the + // conversion routine specified in Section 2.3.8. + + e: T = --- + h_bytes: [hash.MAX_DIGEST_SIZE]byte = --- + e_bytes := hash.hash_bytes_to_buffer(hash_algo, msg, h_bytes[:]) + if len(e_bytes) > SC_SZ { + e_bytes = e_bytes[:SC_SZ] + } + if did_reduce := secec.sc_set_bytes(&e, e_bytes); did_reduce { + // RFC 6979 wants the reduced value + secec.sc_bytes(e_bytes, &e) + } + + x_bytes: [SC_SZ]byte = --- + defer crypto.zero_explicit(&x_bytes, size_of(x_bytes)) + secec.sc_bytes(x_bytes[:], priv_key) + + // While I normally will be content to let idiots compromise + // their signing keys, past precident (eg: Sony Computer + // Entertainment America, Inc v. Hotz) shows that "idiots" + // are also litigatious asshats. By default we use the hedged + // ("with additional input") variant of RFC 6979, with the option + // to disable the added entropy for RFC 6979 compatible deterministic + // signatures. + // + // For implementation simplicity, we will use a hash function that + // has a digest size that is greater than or equal to that of the + // curve order. Using a separate hash is allowed per section 3.6 + // of the RFC, and we only ever use a more secure hash. + + rng: Drbg_RFC6979 = --- + drbg_hash := hash_algo + if hash.DIGEST_SIZES[hash_algo] < SC_SZ { + drbg_hash = MIN_DRBG_HASH + } + init_drbg_rfc6979(&rng, drbg_hash, x_bytes[:], e_bytes, deterministic) + + k: T = --- + defer secec.sc_clear(&k) + for { + // 1. Select an ephemeral elliptic curve key pair (k, R) with + // R = (xR, yR) associated with the elliptic curve domain parameters + // T established during the setup procedure using the key pair + // generation primitive specified in Section 3.2.1. + + if did_reduce := drbg_read_rfc6979(&rng, &k); did_reduce || secec.sc_is_zero(&k) == 1 { + continue + } + secec.pt_scalar_mul_generator(&r_pt, &k) + + // 2. Convert the field element xR to an integer xR using the + // conversion routine specified in Section 2.3.9. + + rx_bytes: [FE_SZ]byte = --- + _ = secec.pt_bytes(rx_bytes[:], nil, &r_pt) + + // 3. Set r = xR mod n. If r = 0, or optionally r fails to meet + // other publicly verifiable criteria (see below), return to Step 1. + + _ = secec.sc_set_bytes(sig_r, rx_bytes[:]) + if secec.sc_is_zero(sig_r) == 1 { + // This is essentially totally untestable since the odds + // of generating `r = 0` is astronomically unlikely. + continue + } + + // (Steps 4/5 done prior to loop.) + + // 6. Compute: s = k^−1 (e + r * dU) mod n. + // If s = 0, return to Step 1. + + secec.sc_inv(&k, &k) + secec.sc_mul(sig_s, sig_r, priv_key) + secec.sc_add(sig_s, sig_s, &e) + secec.sc_mul(sig_s, sig_s, &k) + if secec.sc_is_zero(sig_s) == 0 { + return + } + } +} diff --git a/core/crypto/ecdsa/ecdsa_verify.odin b/core/crypto/ecdsa/ecdsa_verify.odin new file mode 100644 index 000000000..bd973a8df --- /dev/null +++ b/core/crypto/ecdsa/ecdsa_verify.odin @@ -0,0 +1,148 @@ +package ecdsa + +import "core:crypto/hash" +import secec "core:crypto/_weierstrass" + +// verify_raw returns true if and only if (⟺) sig is a valid signature by pub_key over +// msg, hased using hash_algo, per the verification procedure specifed +// in SEC 1, Version 2.0, Section 4.1.4. +// +// The signature format is `r | s`. +@(require_results) +verify_raw :: proc(pub_key: ^Public_Key, hash_algo: hash.Algorithm, msg, sig: []byte) -> bool { + ensure(hash_algo != .Invalid, "crypto/edsa: invalid hash algorithm") + ensure(pub_key._curve != .Invalid, "crypto/edsa: invalid curve") + + if len(sig) != RAW_SIGNATURE_SIZES[pub_key._curve] { + return false + } + + #partial switch pub_key._curve { + case .SECP256R1: + SC_SZ :: secec.SC_SIZE_P256R1 + r_bytes, s_bytes := sig[:SC_SZ], sig[SC_SZ:] + pk := &pub_key._impl.(secec.Point_p256r1) + return verify_internal(pk, hash_algo, r_bytes, s_bytes, msg) + case .SECP384R1: + SC_SZ :: secec.SC_SIZE_P384R1 + r_bytes, s_bytes := sig[:SC_SZ], sig[SC_SZ:] + pk := &pub_key._impl.(secec.Point_p384r1) + return verify_internal(pk, hash_algo, r_bytes, s_bytes, msg) + } + + panic("crypto/ecdsa: invalid curve") +} + +// verify_asn1 returns true if and only if (⟺) sig is a valid signature by pub_key over +// msg, hased using hash_algo, per the verification procedure specifed +// in SEC 1, Version 2.0, Section 4.1.4. +// +// The signature format is ASN.1 `SEQUENCE { r INTEGER, s INTEGER }`. +@(require_results) +verify_asn1 :: proc(pub_key: ^Public_Key, hash_algo: hash.Algorithm, msg, sig: []byte) -> bool { + ensure(hash_algo != .Invalid, "crypto/edsa: invalid hash algorithm") + ensure(pub_key._curve != .Invalid, "crypto/edsa: invalid curve") + + r_bytes, s_bytes, ok := parse_asn1_sig(sig) + if !ok { + return false + } + + #partial switch pub_key._curve { + case .SECP256R1: + pk := &pub_key._impl.(secec.Point_p256r1) + return verify_internal(pk, hash_algo, r_bytes, s_bytes, msg) + case .SECP384R1: + pk := &pub_key._impl.(secec.Point_p384r1) + return verify_internal(pk, hash_algo, r_bytes, s_bytes, msg) + } + + panic("crypto/ecdsa: invalid curve") +} + +@(private,require_results) +verify_internal :: proc(pub_key: ^$T, hash_algo: hash.Algorithm, sig_r, sig_s, msg: []byte) -> bool { + when T == secec.Point_p256r1 { + r, s, e, v: secec.Scalar_p256r1 = ---, ---, ---, --- + u1, u2, s_inv: secec.Scalar_p256r1 = ---, ---, --- + SC_SZ :: secec.SC_SIZE_P256R1 + } else when T == secec.Point_p384r1 { + r, s, e, v: secec.Scalar_p384r1 = ---, ---, ---, --- + u1, u2, s_inv: secec.Scalar_p384r1 = ---, ---, --- + SC_SZ :: secec.SC_SIZE_P384R1 + } else { + #panic("crypto/ecdsa: invalid curve") + } + + if len(sig_r) > SC_SZ || len(sig_s) > SC_SZ { + return false + } + + // 1. If r and s are not both integers in the interval [1, n − 1], + // output “invalid” and stop. + + if did_reduce := secec.sc_set_bytes(&r, sig_r); did_reduce { + return false + } + if did_reduce := secec.sc_set_bytes(&s, sig_s); did_reduce { + return false + } + if secec.sc_is_zero(&r) == 1 || secec.sc_is_zero(&s) == 1 { + return false + } + + // 2. Use the hash function established during the setup procedure + // to compute the hash value: + // H = Hash(M) + // of length hashlen octets as specified in Section 3.5. If the + // hash function outputs “invalid”, output “invalid” and stop. + + // 3. Derive an integer e from H as follows: + // 3.1. Convert the octet string H to a bit string H using the + // conversion routine specified in Section 2.3.2. + // 3.2. Set E = H if ceil(log2(n)) >= 8(hashlen), and set E equal + // to the leftmost ceil(log2(n)) bits of H if ceil(log2(n)) < + // 8(hashlen). + // 3.3. Convert the bit string E to an octet string E using the + // conversion routine specified in Section 2.3.1. + // 3.4. Convert the octet string E to an integer e using the + // conversion routine specified in Section 2.3.8. + + h_bytes: [hash.MAX_DIGEST_SIZE]byte = --- + e_bytes := hash.hash_bytes_to_buffer(hash_algo, msg, h_bytes[:]) + if len(e_bytes) > SC_SZ { + e_bytes = e_bytes[:SC_SZ] + } + _ = secec.sc_set_bytes(&e, e_bytes) + + // 4. Compute: u1 = e(s^−1) mod n and u2 = r(s^-1) mod n. + + secec.sc_inv(&s_inv, &s) + secec.sc_mul(&u1, &e, &s_inv) + secec.sc_mul(&u2, &r, &s_inv) + + // 5. Compute: R = (xR, yR) = u1 * G + u2 * QU. + + r_pt: T = --- + secec.pt_double_scalar_mul_generator_vartime(&r_pt, pub_key, &u1, &u2) + + // If R = O, output “invalid” and stop. + + if secec.pt_is_identity(&r_pt) == 1 { + return false + } + + // 6. Convert the field element xR to an integer xR using the + // conversion routine specified in Section 2.3.9. + // + // 7. Set v = xR mod n. + + r_x: [SC_SZ]byte = --- + _ = secec.pt_bytes(r_x[:], nil, &r_pt) + _ = secec.sc_set_bytes(&v, r_x[:]) + + // 8. Compare v and r — if v = r, output “valid”, and if + // v != r, output “invalid”. + + return secec.sc_equal(&r, &v) == 1 +} diff --git a/core/crypto/ed25519/ed25519.odin b/core/crypto/ed25519/ed25519.odin index 0382a6739..2020c0633 100644 --- a/core/crypto/ed25519/ed25519.odin +++ b/core/crypto/ed25519/ed25519.odin @@ -11,7 +11,6 @@ package ed25519 import "core:crypto" import grp "core:crypto/_edwards25519" import "core:crypto/sha2" -import "core:mem" // PRIVATE_KEY_SIZE is the byte-encoded private key size. PRIVATE_KEY_SIZE :: 32 @@ -48,8 +47,27 @@ Public_Key :: struct { _is_initialized: bool, } +// private_key_generate uses the system entropy source to generate a new +// Private_Key. This will only fail if and only if (⟺) the system entropy source is +// missing or broken. +private_key_generate :: proc(priv_key: ^Private_Key) -> bool { + private_key_clear(priv_key) + + if !crypto.HAS_RAND_BYTES { + return false + } + + b: [PRIVATE_KEY_SIZE]byte + defer crypto.zero_explicit(&b, size_of(b)) + + crypto.rand_bytes(b[:]) + private_key_set_bytes(priv_key, b[:]) + + return true +} + // private_key_set_bytes decodes a byte-encoded private key, and returns -// true iff the operation was successful. +// true if and only if (⟺) the operation was successful. private_key_set_bytes :: proc(priv_key: ^Private_Key, b: []byte) -> bool { if len(b) != PRIVATE_KEY_SIZE { return false @@ -89,7 +107,7 @@ private_key_bytes :: proc(priv_key: ^Private_Key, dst: []byte) { // private_key_clear clears priv_key to the uninitialized state. private_key_clear :: proc "contextless" (priv_key: ^Private_Key) { - mem.zero_explicit(priv_key, size_of(Private_Key)) + crypto.zero_explicit(priv_key, size_of(Private_Key)) } // sign writes the signature by priv_key over msg to sig. @@ -149,7 +167,7 @@ sign :: proc(priv_key: ^Private_Key, msg, sig: []byte) { } // public_key_set_bytes decodes a byte-encoded public key, and returns -// true iff the operation was successful. +// true if and only if (⟺) the operation was successful. public_key_set_bytes :: proc "contextless" (pub_key: ^Public_Key, b: []byte) -> bool { if len(b) != PUBLIC_KEY_SIZE { return false @@ -170,7 +188,7 @@ public_key_set_bytes :: proc "contextless" (pub_key: ^Public_Key, b: []byte) -> // public_key_set_priv sets pub_key to the public component of priv_key. public_key_set_priv :: proc(pub_key: ^Public_Key, priv_key: ^Private_Key) { - ensure(priv_key._is_initialized, "crypto/ed25519: uninitialized public key") + ensure(priv_key._is_initialized, "crypto/ed25519: uninitialized private key") src := &priv_key._pub_key copy(pub_key._b[:], src._b[:]) @@ -187,14 +205,14 @@ public_key_bytes :: proc(pub_key: ^Public_Key, dst: []byte) { copy(dst, pub_key._b[:]) } -// public_key_equal returns true iff pub_key is equal to other. +// public_key_equal returns true if and only if (⟺) pub_key is equal to other. public_key_equal :: proc(pub_key, other: ^Public_Key) -> bool { ensure(pub_key._is_initialized && other._is_initialized, "crypto/ed25519: uninitialized public key") return crypto.compare_constant_time(pub_key._b[:], other._b[:]) == 1 } -// verify returns true iff sig is a valid signature by pub_key over msg. +// verify returns true if and only if (⟺) sig is a valid signature by pub_key over msg. // // The optional `allow_small_order_A` parameter will make this // implementation strictly compatible with FIPS 186-5, at the expense of diff --git a/core/crypto/hash/hash.odin b/core/crypto/hash/hash.odin index ecb33b9d0..31f07ac72 100644 --- a/core/crypto/hash/hash.odin +++ b/core/crypto/hash/hash.odin @@ -8,8 +8,8 @@ package crypto_hash zhibog, dotbmp: Initial implementation. */ +import "core:crypto" import "core:io" -import "core:mem" // hash_bytes will hash the given input and return the computed digest // in a newly allocated slice. @@ -61,7 +61,7 @@ hash_stream :: proc( ctx: Context buf: [MAX_BLOCK_SIZE * 4]byte - defer mem.zero_explicit(&buf, size_of(buf)) + defer crypto.zero_explicit(&buf, size_of(buf)) init(&ctx, algorithm) diff --git a/core/crypto/hash/hash_js.odin b/core/crypto/hash/hash_js.odin new file mode 100644 index 000000000..99309b944 --- /dev/null +++ b/core/crypto/hash/hash_js.odin @@ -0,0 +1,10 @@ +#+build js +package crypto_hash + +hash :: proc { + hash_stream, + hash_bytes, + hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, +} diff --git a/core/crypto/hash/hash_os.odin b/core/crypto/hash/hash_os.odin index d54e657ad..49c1a0ff8 100644 --- a/core/crypto/hash/hash_os.odin +++ b/core/crypto/hash/hash_os.odin @@ -1,26 +1,27 @@ #+build !freestanding +#+build !js package crypto_hash import "core:io" import "core:os" -// hash_file will read the file provided by the given handle and return the +// `hash_file` will read the file provided by the given handle and return the // computed digest in a newly allocated slice. -hash_file :: proc( - algorithm: Algorithm, - hd: os.Handle, +hash_file_by_handle :: proc( + algorithm: Algorithm, + handle: ^os.File, load_at_once := false, - allocator := context.allocator, + allocator := context.allocator, ) -> ( []byte, io.Error, ) { if !load_at_once { - return hash_stream(algorithm, os.stream_from_handle(hd), allocator) + return hash_stream(algorithm, os.to_stream(handle), allocator) } - buf, ok := os.read_entire_file(hd, allocator) - if !ok { + buf, err := os.read_entire_file(handle, allocator) + if err != nil { return nil, io.Error.Unknown } defer delete(buf, allocator) @@ -28,11 +29,30 @@ hash_file :: proc( return hash_bytes(algorithm, buf, allocator), io.Error.None } +hash_file_by_name :: proc( + algorithm: Algorithm, + filename: string, + load_at_once := false, + allocator := context.allocator, +) -> ( + []byte, + io.Error, +) { + handle, err := os.open(filename) + defer os.close(handle) + + if err != nil { + return {}, io.Error.Unknown + } + return hash_file_by_handle(algorithm, handle, load_at_once, allocator) +} + + hash :: proc { hash_stream, - hash_file, + hash_file_by_handle, hash_bytes, hash_string, hash_bytes_to_buffer, hash_string_to_buffer, -} +} \ No newline at end of file diff --git a/core/crypto/hash/low_level.odin b/core/crypto/hash/low_level.odin index 242eadd5f..44b2a8100 100644 --- a/core/crypto/hash/low_level.odin +++ b/core/crypto/hash/low_level.odin @@ -235,7 +235,7 @@ update :: proc(ctx: ^Context, data: []byte) { // final finalizes the Context, writes the digest to hash, and calls // reset on the Context. // -// Iff finalize_clone is set, final will work on a copy of the Context, +// If and only if (⟺) finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { switch &impl in ctx._impl { diff --git a/core/crypto/hkdf/hkdf.odin b/core/crypto/hkdf/hkdf.odin index b3a6bf303..b2b515676 100644 --- a/core/crypto/hkdf/hkdf.odin +++ b/core/crypto/hkdf/hkdf.odin @@ -5,9 +5,9 @@ See: [[ https://www.rfc-editor.org/rfc/rfc5869 ]] */ package hkdf +import "core:crypto" import "core:crypto/hash" import "core:crypto/hmac" -import "core:mem" // extract_and_expand derives output keying material (OKM) via the // HKDF-Extract and HKDF-Expand algorithms, with the specified has @@ -18,7 +18,7 @@ extract_and_expand :: proc(algorithm: hash.Algorithm, salt, ikm, info, dst: []by tmp: [hash.MAX_DIGEST_SIZE]byte prk := tmp[:h_len] - defer mem.zero_explicit(raw_data(prk), h_len) + defer crypto.zero_explicit(raw_data(prk), h_len) extract(algorithm, salt, ikm, prk) expand(algorithm, prk, info, dst) @@ -83,7 +83,7 @@ expand :: proc(algorithm: hash.Algorithm, prk, info, dst: []byte) { if r > 0 { tmp: [hash.MAX_DIGEST_SIZE]byte blk := tmp[:h_len] - defer mem.zero_explicit(raw_data(blk), h_len) + defer crypto.zero_explicit(raw_data(blk), h_len) _F(&base, prev, info, n + 1, blk) copy(dst_blk, blk) diff --git a/core/crypto/hmac/hmac.odin b/core/crypto/hmac/hmac.odin index 1427baf34..56decc0ef 100644 --- a/core/crypto/hmac/hmac.odin +++ b/core/crypto/hmac/hmac.odin @@ -8,7 +8,6 @@ package hmac import "core:crypto" import "core:crypto/hash" -import "core:mem" // sum will compute the HMAC with the specified algorithm and key // over msg, and write the computed tag to dst. It requires that @@ -22,7 +21,7 @@ sum :: proc(algorithm: hash.Algorithm, dst, msg, key: []byte) { } // verify will verify the HMAC tag computed with the specified algorithm -// and key over msg and return true iff the tag is valid. It requires +// and key over msg and return true if and only if (⟺) the tag is valid. It requires // that the tag is correctly sized. verify :: proc(algorithm: hash.Algorithm, tag, msg, key: []byte) -> bool { tag_buf: [hash.MAX_DIGEST_SIZE]byte @@ -126,7 +125,7 @@ _init_hashes :: proc(ctx: ^Context, algorithm: hash.Algorithm, key: []byte) { kLen := len(key) B := hash.BLOCK_SIZES[algorithm] K0 := K0_buf[:B] - defer mem.zero_explicit(raw_data(K0), B) + defer crypto.zero_explicit(raw_data(K0), B) switch { case kLen == B, kLen < B: @@ -157,7 +156,7 @@ _init_hashes :: proc(ctx: ^Context, algorithm: hash.Algorithm, key: []byte) { hash.init(&ctx._i_hash, algorithm) kPad := kPad_buf[:B] - defer mem.zero_explicit(raw_data(kPad), B) + defer crypto.zero_explicit(raw_data(kPad), B) for v, i in K0 { kPad[i] = v ~ _I_PAD diff --git a/core/crypto/kmac/kmac.odin b/core/crypto/kmac/kmac.odin index 4ecff4f12..f0c27739a 100644 --- a/core/crypto/kmac/kmac.odin +++ b/core/crypto/kmac/kmac.odin @@ -32,7 +32,7 @@ sum :: proc(sec_strength: int, dst, msg, key, domain_sep: []byte) { } // verify will verify the KMAC tag computed with the specified security -// strength, key and domain separator over msg and return true iff the +// strength, key and domain separator over msg and return true if and only if (⟺) the // tag is valid. verify :: proc(sec_strength: int, tag, msg, key, domain_sep: []byte, allocator := context.temp_allocator) -> bool { derived_tag := make([]byte, len(tag), allocator) diff --git a/core/crypto/legacy/keccak/keccak.odin b/core/crypto/legacy/keccak/keccak.odin index ec6af2565..ffca1c95c 100644 --- a/core/crypto/legacy/keccak/keccak.odin +++ b/core/crypto/legacy/keccak/keccak.odin @@ -77,7 +77,7 @@ update :: proc "contextless" (ctx: ^Context, data: []byte) { // final finalizes the Context, writes the digest to hash, and calls // reset on the Context. // -// Iff finalize_clone is set, final will work on a copy of the Context, +// If and only if (⟺) finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc "contextless" (ctx: ^Context, hash: []byte, finalize_clone: bool = false) { _sha3.final((^_sha3.Context)(ctx), hash, finalize_clone) diff --git a/core/crypto/legacy/md5/md5.odin b/core/crypto/legacy/md5/md5.odin index d9d74d498..4bbc5d32a 100644 --- a/core/crypto/legacy/md5/md5.odin +++ b/core/crypto/legacy/md5/md5.odin @@ -18,9 +18,9 @@ package md5 zhibog, dotbmp: Initial implementation. */ +import "core:crypto" import "core:encoding/endian" import "core:math/bits" -import "core:mem" // DIGEST_SIZE is the MD5 digest size in bytes. DIGEST_SIZE :: 16 @@ -69,7 +69,7 @@ update :: proc(ctx: ^Context, data: []byte) { // final finalizes the Context, writes the digest to hash, and calls // reset on the Context. // -// Iff finalize_clone is set, final will work on a copy of the Context, +// If and only if (⟺) finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { ensure(ctx.is_initialized) @@ -100,7 +100,7 @@ final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { i += 1 } transform(ctx, ctx.data[:]) - mem.set(&ctx.data, 0, 56) + crypto.set(&ctx.data, 0, 56) } ctx.bitlen += u64(ctx.datalen * 8) @@ -124,7 +124,7 @@ reset :: proc(ctx: ^$T) { return } - mem.zero_explicit(ctx, size_of(ctx^)) + crypto.zero_explicit(ctx, size_of(ctx^)) } /* diff --git a/core/crypto/legacy/sha1/sha1.odin b/core/crypto/legacy/sha1/sha1.odin index 35b228f69..892f893a6 100644 --- a/core/crypto/legacy/sha1/sha1.odin +++ b/core/crypto/legacy/sha1/sha1.odin @@ -19,9 +19,9 @@ package sha1 zhibog, dotbmp: Initial implementation. */ +import "core:crypto" import "core:encoding/endian" import "core:math/bits" -import "core:mem" // DIGEST_SIZE is the SHA1 digest size in bytes. DIGEST_SIZE :: 20 @@ -76,7 +76,7 @@ update :: proc(ctx: ^Context, data: []byte) { // final finalizes the Context, writes the digest to hash, and calls // reset on the Context. // -// Iff finalize_clone is set, final will work on a copy of the Context, +// If and only if (⟺) finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { ensure(ctx.is_initialized) @@ -107,7 +107,7 @@ final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { i += 1 } transform(ctx, ctx.data[:]) - mem.set(&ctx.data, 0, 56) + crypto.set(&ctx.data, 0, 56) } ctx.bitlen += u64(ctx.datalen * 8) @@ -131,7 +131,7 @@ reset :: proc(ctx: ^$T) { return } - mem.zero_explicit(ctx, size_of(ctx^)) + crypto.zero_explicit(ctx, size_of(ctx^)) } /* diff --git a/core/crypto/pbkdf2/pbkdf2.odin b/core/crypto/pbkdf2/pbkdf2.odin index c96855b9c..c27ec4aa2 100644 --- a/core/crypto/pbkdf2/pbkdf2.odin +++ b/core/crypto/pbkdf2/pbkdf2.odin @@ -5,10 +5,10 @@ See: [[ https://www.rfc-editor.org/rfc/rfc2898 ]] */ package pbkdf2 +import "core:crypto" import "core:crypto/hash" import "core:crypto/hmac" import "core:encoding/endian" -import "core:mem" // derive invokes PBKDF2-HMAC with the specified hash algorithm, password, // salt, iteration count, and outputs the derived key to dst. @@ -66,12 +66,12 @@ derive :: proc( dst_blk = dst_blk[h_len:] } - // Instead of rounding l up, just proceass the one extra block iff + // Instead of rounding l up, just proceass the one extra block if and only if (⟺) // r != 0. if r > 0 { tmp: [hash.MAX_DIGEST_SIZE]byte blk := tmp[:h_len] - defer mem.zero_explicit(raw_data(blk), h_len) + defer crypto.zero_explicit(raw_data(blk), h_len) _F(&base, salt, iterations, u32(l + 1), blk) copy(dst_blk, blk) @@ -84,7 +84,7 @@ _F :: proc(base: ^hmac.Context, salt: []byte, c: u32, i: u32, dst_blk: []byte) { tmp: [hash.MAX_DIGEST_SIZE]byte u := tmp[:h_len] - defer mem.zero_explicit(raw_data(u), h_len) + defer crypto.zero_explicit(raw_data(u), h_len) // F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c // diff --git a/core/crypto/poly1305/poly1305.odin b/core/crypto/poly1305/poly1305.odin index d90f2ad54..ed2bec82d 100644 --- a/core/crypto/poly1305/poly1305.odin +++ b/core/crypto/poly1305/poly1305.odin @@ -10,7 +10,6 @@ import "core:crypto" import field "core:crypto/_fiat/field_poly1305" import "core:encoding/endian" import "core:math/bits" -import "core:mem" // KEY_SIZE is the Poly1305 key size in bytes. KEY_SIZE :: 32 @@ -34,7 +33,7 @@ sum :: proc(dst, msg, key: []byte) { } // verify will verify the Poly1305 tag computed with the key over msg and -// return true iff the tag is valid. It requires that the tag is correctly +// return true if and only if (⟺) the tag is valid. It requires that the tag is correctly // sized. verify :: proc(tag, msg, key: []byte) -> bool { ctx: Context = --- @@ -155,10 +154,10 @@ final :: proc(ctx: ^Context, dst: []byte) { // reset sanitizes the Context. The Context must be re-initialized to // be used again. reset :: proc(ctx: ^Context) { - mem.zero_explicit(&ctx._r, size_of(ctx._r)) - mem.zero_explicit(&ctx._a, size_of(ctx._a)) - mem.zero_explicit(&ctx._s, size_of(ctx._s)) - mem.zero_explicit(&ctx._buffer, size_of(ctx._buffer)) + crypto.zero_explicit(&ctx._r, size_of(ctx._r)) + crypto.zero_explicit(&ctx._a, size_of(ctx._a)) + crypto.zero_explicit(&ctx._s, size_of(ctx._s)) + crypto.zero_explicit(&ctx._buffer, size_of(ctx._buffer)) ctx._is_initialized = false } diff --git a/core/crypto/ristretto255/ristretto255.odin b/core/crypto/ristretto255/ristretto255.odin index 78bf45c28..ef899d1da 100644 --- a/core/crypto/ristretto255/ristretto255.odin +++ b/core/crypto/ristretto255/ristretto255.odin @@ -6,9 +6,9 @@ See: */ package ristretto255 +import "core:crypto" import grp "core:crypto/_edwards25519" import field "core:crypto/_fiat/field_curve25519" -import "core:mem" // ELEMENT_SIZE is the size of a byte-encoded ristretto255 group element. ELEMENT_SIZE :: 32 @@ -71,7 +71,7 @@ Group_Element :: struct { // ge_clear clears ge to the uninitialized state. ge_clear :: proc "contextless" (ge: ^Group_Element) { - mem.zero_explicit(ge, size_of(Group_Element)) + crypto.zero_explicit(ge, size_of(Group_Element)) } // ge_set sets `ge = a`. @@ -360,7 +360,7 @@ ge_double_scalarmult_generator_vartime :: proc( ge._is_initialized = true } -// ge_cond_negate sets `ge = a` iff `ctrl == 0` and `ge = -a` iff `ctrl == 1`. +// ge_cond_negate sets `ge = a` if and only if (⟺) `ctrl == 0` and `ge = -a` if and only if (⟺) `ctrl == 1`. // Behavior for all other values of ctrl are undefined, ge_cond_negate :: proc(ge, a: ^Group_Element, ctrl: int) { _ge_ensure_initialized([]^Group_Element{a}) @@ -369,7 +369,7 @@ ge_cond_negate :: proc(ge, a: ^Group_Element, ctrl: int) { ge._is_initialized = true } -// ge_cond_assign sets `ge = ge` iff `ctrl == 0` and `ge = a` iff `ctrl == 1`. +// ge_cond_assign sets `ge = ge` if and only if (⟺) `ctrl == 0` and `ge = a` if and only if (⟺) `ctrl == 1`. // Behavior for all other values of ctrl are undefined, ge_cond_assign :: proc(ge, a: ^Group_Element, ctrl: int) { _ge_ensure_initialized([]^Group_Element{ge, a}) @@ -377,7 +377,7 @@ ge_cond_assign :: proc(ge, a: ^Group_Element, ctrl: int) { grp.ge_cond_assign(&ge._p, &a._p, ctrl) } -// ge_cond_select sets `ge = a` iff `ctrl == 0` and `ge = b` iff `ctrl == 1`. +// ge_cond_select sets `ge = a` if and only if (⟺) `ctrl == 0` and `ge = b` if and only if (⟺) `ctrl == 1`. // Behavior for all other values of ctrl are undefined, ge_cond_select :: proc(ge, a, b: ^Group_Element, ctrl: int) { _ge_ensure_initialized([]^Group_Element{a, b}) @@ -386,7 +386,7 @@ ge_cond_select :: proc(ge, a, b: ^Group_Element, ctrl: int) { ge._is_initialized = true } -// ge_equal returns 1 iff `a == b`, and 0 otherwise. +// ge_equal returns 1 if and only if (⟺) `a == b`, and 0 otherwise. @(require_results) ge_equal :: proc(a, b: ^Group_Element) -> int { _ge_ensure_initialized([]^Group_Element{a, b}) @@ -405,7 +405,7 @@ ge_equal :: proc(a, b: ^Group_Element) -> int { return ret } -// ge_is_identity returns 1 iff `ge` is the identity element, and 0 otherwise. +// ge_is_identity returns 1 if and only if (⟺) `ge` is the identity element, and 0 otherwise. @(require_results) ge_is_identity :: proc(ge: ^Group_Element) -> int { return ge_equal(ge, &GE_IDENTITY) diff --git a/core/crypto/ristretto255/ristretto255_scalar.odin b/core/crypto/ristretto255/ristretto255_scalar.odin index 75844b3f4..743e02ef3 100644 --- a/core/crypto/ristretto255/ristretto255_scalar.odin +++ b/core/crypto/ristretto255/ristretto255_scalar.odin @@ -80,13 +80,13 @@ sc_square :: proc "contextless" (sc, a: ^Scalar) { grp.sc_square(sc, a) } -// sc_cond_assign sets `sc = sc` iff `ctrl == 0` and `sc = a` iff `ctrl == 1`. +// sc_cond_assign sets `sc = sc` if and only if (⟺) `ctrl == 0` and `sc = a` if and only if (⟺) `ctrl == 1`. // Behavior for all other values of ctrl are undefined, sc_cond_assign :: proc(sc, a: ^Scalar, ctrl: int) { grp.sc_cond_assign(sc, a, ctrl) } -// sc_equal returns 1 iff `a == b`, and 0 otherwise. +// sc_equal returns 1 if and only if (⟺) `a == b`, and 0 otherwise. @(require_results) sc_equal :: proc(a, b: ^Scalar) -> int { return grp.sc_equal(a, b) diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin index 0b34cd6a1..2eac9240b 100644 --- a/core/crypto/sha2/sha2.odin +++ b/core/crypto/sha2/sha2.odin @@ -15,9 +15,9 @@ package sha2 zhibog, dotbmp: Initial implementation. */ +@(require) import "core:crypto" @(require) import "core:encoding/endian" import "core:math/bits" -@(require) import "core:mem" // DIGEST_SIZE_224 is the SHA-224 digest size in bytes. DIGEST_SIZE_224 :: 28 @@ -44,7 +44,8 @@ Context_256 :: struct { length: u64, md_bits: int, - is_initialized: bool, + is_hw_accelerated: bool, + is_initialized: bool, } // Context_512 is a SHA-384, SHA-512 or SHA-512/256 instance. @@ -55,7 +56,8 @@ Context_512 :: struct { length: u64, md_bits: int, - is_initialized: bool, + is_hw_accelerated: bool, + is_initialized: bool, } // init_224 initializes a Context_256 for SHA-224. @@ -88,6 +90,9 @@ init_512_256 :: proc(ctx: ^Context_512) { _init(ctx) } +@(private) +ERR_HW_NOT_SUPPORTED :: "crypto/sha2: hardware implementation unsupported" + @(private) _init :: proc(ctx: ^$T) { when T == Context_256 { @@ -113,6 +118,8 @@ _init :: proc(ctx: ^$T) { case: panic("crypto/sha2: invalid digest output length") } + + ctx.is_hw_accelerated = is_hardware_accelerated_256() } else when T == Context_512 { switch ctx.md_bits { case 256: @@ -148,6 +155,8 @@ _init :: proc(ctx: ^$T) { case: panic("crypto/sha2: invalid digest output length") } + + ctx.is_hw_accelerated = is_hardware_accelerated_512() } ctx.length = 0 @@ -191,7 +200,7 @@ update :: proc(ctx: ^$T, data: []byte) { // final finalizes the Context, writes the digest to hash, and calls // reset on the Context. // -// Iff finalize_clone is set, final will work on a copy of the Context, +// If and only if (⟺) finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^$T, hash: []byte, finalize_clone: bool = false) { ensure(ctx.is_initialized) @@ -260,14 +269,14 @@ reset :: proc(ctx: ^$T) { return } - mem.zero_explicit(ctx, size_of(ctx^)) + crypto.zero_explicit(ctx, size_of(ctx^)) } /* SHA2 implementation */ -@(private, rodata) +@(private = "file", rodata) SHA256_K := [64]u32 { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, @@ -287,7 +296,7 @@ SHA256_K := [64]u32 { 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, } -@(private, rodata) +@(private = "file", rodata) SHA512_K := [80]u64 { 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, @@ -336,70 +345,70 @@ SHA256_ROUNDS :: 64 @(private) SHA512_ROUNDS :: 80 -@(private) +@(private = "file") SHA256_CH :: #force_inline proc "contextless" (x, y, z: u32) -> u32 { return (x & y) ~ (~x & z) } -@(private) +@(private = "file") SHA256_MAJ :: #force_inline proc "contextless" (x, y, z: u32) -> u32 { return (x & y) ~ (x & z) ~ (y & z) } -@(private) +@(private = "file") SHA512_CH :: #force_inline proc "contextless" (x, y, z: u64) -> u64 { return (x & y) ~ (~x & z) } -@(private) +@(private = "file") SHA512_MAJ :: #force_inline proc "contextless" (x, y, z: u64) -> u64 { return (x & y) ~ (x & z) ~ (y & z) } -@(private) +@(private = "file") SHA256_F1 :: #force_inline proc "contextless" (x: u32) -> u32 { return bits.rotate_left32(x, 30) ~ bits.rotate_left32(x, 19) ~ bits.rotate_left32(x, 10) } -@(private) +@(private = "file") SHA256_F2 :: #force_inline proc "contextless" (x: u32) -> u32 { return bits.rotate_left32(x, 26) ~ bits.rotate_left32(x, 21) ~ bits.rotate_left32(x, 7) } -@(private) +@(private = "file") SHA256_F3 :: #force_inline proc "contextless" (x: u32) -> u32 { return bits.rotate_left32(x, 25) ~ bits.rotate_left32(x, 14) ~ (x >> 3) } -@(private) +@(private = "file") SHA256_F4 :: #force_inline proc "contextless" (x: u32) -> u32 { return bits.rotate_left32(x, 15) ~ bits.rotate_left32(x, 13) ~ (x >> 10) } -@(private) +@(private = "file") SHA512_F1 :: #force_inline proc "contextless" (x: u64) -> u64 { return bits.rotate_left64(x, 36) ~ bits.rotate_left64(x, 30) ~ bits.rotate_left64(x, 25) } -@(private) +@(private = "file") SHA512_F2 :: #force_inline proc "contextless" (x: u64) -> u64 { return bits.rotate_left64(x, 50) ~ bits.rotate_left64(x, 46) ~ bits.rotate_left64(x, 23) } -@(private) +@(private = "file") SHA512_F3 :: #force_inline proc "contextless" (x: u64) -> u64 { return bits.rotate_left64(x, 63) ~ bits.rotate_left64(x, 56) ~ (x >> 7) } -@(private) +@(private = "file") SHA512_F4 :: #force_inline proc "contextless" (x: u64) -> u64 { return bits.rotate_left64(x, 45) ~ bits.rotate_left64(x, 3) ~ (x >> 6) } -@(private) +@(private = "file") sha2_transf :: proc "contextless" (ctx: ^$T, data: []byte) #no_bounds_check { when T == Context_256 { - if is_hardware_accelerated_256() { + if ctx.is_hw_accelerated { sha256_transf_hw(ctx, data) return } @@ -410,6 +419,11 @@ sha2_transf :: proc "contextless" (ctx: ^$T, data: []byte) #no_bounds_check { CURR_BLOCK_SIZE :: BLOCK_SIZE_256 } else when T == Context_512 { + if ctx.is_hw_accelerated { + sha512_transf_hw(ctx, data) + return + } + w: [SHA512_ROUNDS]u64 wv: [8]u64 t1, t2: u64 diff --git a/core/crypto/sha2/sha256_impl_hw_arm.odin b/core/crypto/sha2/sha256_impl_hw_arm.odin new file mode 100644 index 000000000..618cc6fff --- /dev/null +++ b/core/crypto/sha2/sha256_impl_hw_arm.odin @@ -0,0 +1,224 @@ +#+build arm64,arm32 +package sha2 + +// Based on the public domain code by Jeffrey Walton, though +// realistically, there only is one sensible way to write this. +// +// See: https://github.com/noloader/SHA-Intrinsics + +import "base:intrinsics" +import "core:simd" +import "core:simd/arm" +import "core:sys/info" + +// is_hardware_accelerated_256 returns true if and only if (⟺) hardware +// accelerated SHA-224/SHA-256 is supported. +is_hardware_accelerated_256 :: proc "contextless" () -> bool { + req_features :: info.CPU_Features{ + .asimd, + .sha256, + } + return info.cpu_features() >= req_features +} + +@(private = "file") +K_0 :: simd.u32x4{0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5} +@(private = "file") +K_1 :: simd.u32x4{0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5} +@(private = "file") +K_2 :: simd.u32x4{0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3} +@(private = "file") +K_3 :: simd.u32x4{0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174} +@(private = "file") +K_4 :: simd.u32x4{0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC} +@(private = "file") +K_5 :: simd.u32x4{0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA} +@(private = "file") +K_6 :: simd.u32x4{0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7} +@(private = "file") +K_7 :: simd.u32x4{0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967} +@(private = "file") +K_8 :: simd.u32x4{0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13} +@(private = "file") +K_9 :: simd.u32x4{0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85} +@(private = "file") +K_10 :: simd.u32x4{0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3} +@(private = "file") +K_11 :: simd.u32x4{0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070} +@(private = "file") +K_12 :: simd.u32x4{0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5} +@(private = "file") +K_13 :: simd.u32x4{0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3} +@(private = "file") +K_14 :: simd.u32x4{0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208} +@(private = "file") +K_15 :: simd.u32x4{0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2} + +@(private, enable_target_feature = "neon,sha2") +sha256_transf_hw :: proc "contextless" (ctx: ^Context_256, data: []byte) #no_bounds_check { + state_0 := intrinsics.unaligned_load((^simd.u32x4)(&ctx.h[0])) + state_1 := intrinsics.unaligned_load((^simd.u32x4)(&ctx.h[4])) + + data := data + for len(data) >= BLOCK_SIZE_256 { + // Save state + abef_save, cdgh_save := state_0, state_1 + + // Load message + msg_0 := intrinsics.unaligned_load((^simd.u32x4)(raw_data(data))) + msg_1 := intrinsics.unaligned_load((^simd.u32x4)(raw_data(data[16:]))) + msg_2 := intrinsics.unaligned_load((^simd.u32x4)(raw_data(data[32:]))) + msg_3 := intrinsics.unaligned_load((^simd.u32x4)(raw_data(data[48:]))) + + // Reverse for little endian + when ODIN_ENDIAN == .Little { + msg_0 = byteswap_u32x4(msg_0) + msg_1 = byteswap_u32x4(msg_1) + msg_2 = byteswap_u32x4(msg_2) + msg_3 = byteswap_u32x4(msg_3) + } + + tmp_0 := simd.add(msg_0, K_0) + + // Rounds 0-3 + msg_0 = arm.vsha256su0q_u32(msg_0, msg_1) + tmp_2 := state_0 + tmp_1 := simd.add(msg_1, K_1) + state_0 = arm.vsha256hq_u32(state_0, state_1, tmp_0) + state_1 = arm.vsha256h2q_u32(state_1, tmp_2, tmp_0) + msg_0 = arm.vsha256su1q_u32(msg_0, msg_2, msg_3) + + // Rounds 4-7 + msg_1 = arm.vsha256su0q_u32(msg_1, msg_2) + tmp_2 = state_0 + tmp_0 = simd.add(msg_2, K_2) + state_0 = arm.vsha256hq_u32(state_0, state_1, tmp_1) + state_1 = arm.vsha256h2q_u32(state_1, tmp_2, tmp_1) + msg_1 = arm.vsha256su1q_u32(msg_1, msg_3, msg_0) + + // Rounds 8-11 + msg_2 = arm.vsha256su0q_u32(msg_2, msg_3) + tmp_2 = state_0 + tmp_1 = simd.add(msg_3, K_3) + state_0 = arm.vsha256hq_u32(state_0, state_1, tmp_0) + state_1 = arm.vsha256h2q_u32(state_1, tmp_2, tmp_0) + msg_2 = arm.vsha256su1q_u32(msg_2, msg_0, msg_1) + + // Rounds 12-15 + msg_3 = arm.vsha256su0q_u32(msg_3, msg_0) + tmp_2 = state_0 + tmp_0 = simd.add(msg_0, K_4) + state_0 = arm.vsha256hq_u32(state_0, state_1, tmp_1) + state_1 = arm.vsha256h2q_u32(state_1, tmp_2, tmp_1) + msg_3 = arm.vsha256su1q_u32(msg_3, msg_1, msg_2) + + // Rounds 16-19 + msg_0 = arm.vsha256su0q_u32(msg_0, msg_1) + tmp_2 = state_0 + tmp_1 = simd.add(msg_1, K_5) + state_0 = arm.vsha256hq_u32(state_0, state_1, tmp_0) + state_1 = arm.vsha256h2q_u32(state_1, tmp_2, tmp_0) + msg_0 = arm.vsha256su1q_u32(msg_0, msg_2, msg_3) + + // Rounds 20-23 + msg_1 = arm.vsha256su0q_u32(msg_1, msg_2) + tmp_2 = state_0 + tmp_0 = simd.add(msg_2, K_6) + state_0 = arm.vsha256hq_u32(state_0, state_1, tmp_1) + state_1 = arm.vsha256h2q_u32(state_1, tmp_2, tmp_1) + msg_1 = arm.vsha256su1q_u32(msg_1, msg_3, msg_0) + + // Rounds 24-27 + msg_2 = arm.vsha256su0q_u32(msg_2, msg_3) + tmp_2 = state_0 + tmp_1 = simd.add(msg_3, K_7) + state_0 = arm.vsha256hq_u32(state_0, state_1, tmp_0) + state_1 = arm.vsha256h2q_u32(state_1, tmp_2, tmp_0) + msg_2 = arm.vsha256su1q_u32(msg_2, msg_0, msg_1) + + // Rounds 28-31 + msg_3 = arm.vsha256su0q_u32(msg_3, msg_0) + tmp_2 = state_0 + tmp_0 = simd.add(msg_0, K_8) + state_0 = arm.vsha256hq_u32(state_0, state_1, tmp_1) + state_1 = arm.vsha256h2q_u32(state_1, tmp_2, tmp_1) + msg_3 = arm.vsha256su1q_u32(msg_3, msg_1, msg_2) + + // Rounds 32-35 + msg_0 = arm.vsha256su0q_u32(msg_0, msg_1) + tmp_2 = state_0 + tmp_1 = simd.add(msg_1, K_9) + state_0 = arm.vsha256hq_u32(state_0, state_1, tmp_0) + state_1 = arm.vsha256h2q_u32(state_1, tmp_2, tmp_0) + msg_0 = arm.vsha256su1q_u32(msg_0, msg_2, msg_3) + + // Rounds 36-39 + msg_1 = arm.vsha256su0q_u32(msg_1, msg_2) + tmp_2 = state_0 + tmp_0 = simd.add(msg_2, K_10) + state_0 = arm.vsha256hq_u32(state_0, state_1, tmp_1) + state_1 = arm.vsha256h2q_u32(state_1, tmp_2, tmp_1) + msg_1 = arm.vsha256su1q_u32(msg_1, msg_3, msg_0) + + // Rounds 40-43 + msg_2 = arm.vsha256su0q_u32(msg_2, msg_3) + tmp_2 = state_0 + tmp_1 = simd.add(msg_3, K_11) + state_0 = arm.vsha256hq_u32(state_0, state_1, tmp_0) + state_1 = arm.vsha256h2q_u32(state_1, tmp_2, tmp_0) + msg_2 = arm.vsha256su1q_u32(msg_2, msg_0, msg_1) + + // Rounds 44-47 + msg_3 = arm.vsha256su0q_u32(msg_3, msg_0) + tmp_2 = state_0 + tmp_0 = simd.add(msg_0, K_12) + state_0 = arm.vsha256hq_u32(state_0, state_1, tmp_1) + state_1 = arm.vsha256h2q_u32(state_1, tmp_2, tmp_1) + msg_3 = arm.vsha256su1q_u32(msg_3, msg_1, msg_2) + + // Rounds 48-51 + tmp_2 = state_0 + tmp_1 = simd.add(msg_1, K_13) + state_0 = arm.vsha256hq_u32(state_0, state_1, tmp_0) + state_1 = arm.vsha256h2q_u32(state_1, tmp_2, tmp_0) + + // Rounds 52-55 + tmp_2 = state_0 + tmp_0 = simd.add(msg_2, K_14) + state_0 = arm.vsha256hq_u32(state_0, state_1, tmp_1) + state_1 = arm.vsha256h2q_u32(state_1, tmp_2, tmp_1) + + // Rounds 56-59 + tmp_2 = state_0 + tmp_1 = simd.add(msg_3, K_15) + state_0 = arm.vsha256hq_u32(state_0, state_1, tmp_0) + state_1 = arm.vsha256h2q_u32(state_1, tmp_2, tmp_0) + + // Rounds 60-63 + tmp_2 = state_0 + state_0 = arm.vsha256hq_u32(state_0, state_1, tmp_1) + state_1 = arm.vsha256h2q_u32(state_1, tmp_2, tmp_1) + + // Combine state + state_0 = simd.add(state_0, abef_save) + state_1 = simd.add(state_1, cdgh_save) + + data = data[BLOCK_SIZE_256:] + } + + intrinsics.unaligned_store((^simd.u32x4)(&ctx.h[0]), state_0) + intrinsics.unaligned_store((^simd.u32x4)(&ctx.h[4]), state_1) +} + +when ODIN_ENDIAN == .Little { + @(private = "file", enable_target_feature = "neon") + byteswap_u32x4 :: #force_inline proc "contextless" (a: simd.u32x4) -> simd.u32x4 { + return transmute(simd.u32x4)( + simd.shuffle( + transmute(simd.u8x16)(a), + transmute(simd.u8x16)(a), + 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12, + ) + ) + } +} \ No newline at end of file diff --git a/core/crypto/sha2/sha2_impl_hw_gen.odin b/core/crypto/sha2/sha256_impl_hw_gen.odin similarity index 53% rename from core/crypto/sha2/sha2_impl_hw_gen.odin rename to core/crypto/sha2/sha256_impl_hw_gen.odin index 85c7f8b28..ad384caaa 100644 --- a/core/crypto/sha2/sha2_impl_hw_gen.odin +++ b/core/crypto/sha2/sha256_impl_hw_gen.odin @@ -1,15 +1,15 @@ #+build !amd64 +#+build !arm64 +#+build !arm32 package sha2 -@(private = "file") -ERR_HW_NOT_SUPPORTED :: "crypto/sha2: hardware implementation unsupported" - -// is_hardware_accelerated_256 returns true iff hardware accelerated -// SHA-224/SHA-256 is supported. +// is_hardware_accelerated_256 returns true if and only if (⟺) hardware +// accelerated SHA-224/SHA-256 is supported. is_hardware_accelerated_256 :: proc "contextless" () -> bool { return false } +@(private) sha256_transf_hw :: proc "contextless" (ctx: ^Context_256, data: []byte) { panic_contextless(ERR_HW_NOT_SUPPORTED) } diff --git a/core/crypto/sha2/sha2_impl_hw_intel.odin b/core/crypto/sha2/sha256_impl_hw_intel.odin similarity index 93% rename from core/crypto/sha2/sha2_impl_hw_intel.odin rename to core/crypto/sha2/sha256_impl_hw_intel.odin index cb29a3a20..fcec80a3c 100644 --- a/core/crypto/sha2/sha2_impl_hw_intel.odin +++ b/core/crypto/sha2/sha256_impl_hw_intel.odin @@ -49,21 +49,16 @@ K_14 :: simd.u64x2{0x78a5636f748f82ee, 0x8cc7020884c87814} K_15 :: simd.u64x2{0xa4506ceb90befffa, 0xc67178f2bef9a3f7} -// is_hardware_accelerated_256 returns true iff hardware accelerated +// is_hardware_accelerated_256 returns true if and only if (⟺) hardware accelerated // SHA-224/SHA-256 is supported. is_hardware_accelerated_256 :: proc "contextless" () -> bool { - features, ok := info.cpu.features.? - if !ok { - return false - } - req_features :: info.CPU_Features{ .sse2, .ssse3, .sse41, .sha, } - return features >= req_features + return info.cpu_features() >= req_features } @(private, enable_target_feature="sse2,ssse3,sse4.1,sha") @@ -75,8 +70,7 @@ sha256_transf_hw :: proc "contextless" (ctx: ^Context_256, data: []byte) #no_bou tmp = x86._mm_shuffle_epi32(tmp, 0xb1) // CDAB state_1 = x86._mm_shuffle_epi32(state_1, 0x1b) // EFGH state_0 := x86._mm_alignr_epi8(tmp, state_1, 8) // ABEF - // state_1 = x86._mm_blend_epi16(state_1, tmp, 0xf0) // CDGH - state_1 = kludge_mm_blend_epi16_0xf0(state_1, tmp) + state_1 = x86._mm_blend_epi16(state_1, tmp, 0xf0) // CDGH data := data for len(data) >= BLOCK_SIZE_256 { @@ -243,18 +237,9 @@ sha256_transf_hw :: proc "contextless" (ctx: ^Context_256, data: []byte) #no_bou // Write back the updated state tmp = x86._mm_shuffle_epi32(state_0, 0x1b) // FEBA state_1 = x86._mm_shuffle_epi32(state_1, 0xb1) // DCHG - // state_0 = x86._mm_blend_epi16(tmp, state_1, 0xf0) // DCBA - state_0 = kludge_mm_blend_epi16_0xf0(tmp, state_1) + state_0 = x86._mm_blend_epi16(tmp, state_1, 0xf0) // DCBA state_1 = x86._mm_alignr_epi8(state_1, tmp, 8) // ABEF intrinsics.unaligned_store((^x86.__m128i)(&ctx.h[0]), state_0) intrinsics.unaligned_store((^x86.__m128i)(&ctx.h[4]), state_1) } - -@(private = "file") -kludge_mm_blend_epi16_0xf0 :: #force_inline proc "contextless"(a, b: x86.__m128i) -> x86.__m128i { - // HACK HACK HACK: LLVM got rid of `llvm.x86.sse41.pblendw`. - a_ := simd.to_array(a) - b_ := simd.to_array(b) - return x86.__m128i{a_[0], b_[1]} -} diff --git a/core/crypto/sha2/sha512_impl_hw_arm.odin b/core/crypto/sha2/sha512_impl_hw_arm.odin new file mode 100644 index 000000000..27ef83f5a --- /dev/null +++ b/core/crypto/sha2/sha512_impl_hw_arm.odin @@ -0,0 +1,498 @@ +// The round function's intrinsic calls are based on: +// https://github.com/LostInCompilation/HashMe/blob/main/src/SHA512_Hardware.cpp +// +// The zlib License +// +// Copyright (C) 2024 Marc Schöndorf +// +// This software is provided 'as-is', without any express or implied warranty. In +// no event will the authors be held liable for any damages arising from the use of +// this software. +// +// Permission is granted to anyone to use this software for any purpose, including +// commercial applications, and to alter it and redistribute it freely, subject to +// the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not claim +// that you wrote the original software. If you use this software in a product, +// an acknowledgment in the product documentation would be appreciated but is +// not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. + +#+build arm64 +package sha2 + +import "base:intrinsics" +import "core:simd" +import "core:simd/arm" +import "core:sys/info" + +// is_hardware_accelerated_512 returns true if and only if (⟺) hardware +// accelerated SHA-384, SHA-512, and SHA-512/256 are supported. +is_hardware_accelerated_512 :: proc "contextless" () -> bool { + req_features :: info.CPU_Features{ + .asimd, + .sha512, + .sha3, // XXX: LLVM groups these under `sha3`. + } + return info.cpu_features() >= req_features +} + +@(private = "file") +K_0 :: simd.u64x2{0x428a2f98d728ae22, 0x7137449123ef65cd} +@(private = "file") +K_1 :: simd.u64x2{0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc} +@(private = "file") +K_2 :: simd.u64x2{0x3956c25bf348b538, 0x59f111f1b605d019} +@(private = "file") +K_3 :: simd.u64x2{0x923f82a4af194f9b, 0xab1c5ed5da6d8118} +@(private = "file") +K_4 :: simd.u64x2{0xd807aa98a3030242, 0x12835b0145706fbe} +@(private = "file") +K_5 :: simd.u64x2{0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2} +@(private = "file") +K_6 :: simd.u64x2{0x72be5d74f27b896f, 0x80deb1fe3b1696b1} +@(private = "file") +K_7 :: simd.u64x2{0x9bdc06a725c71235, 0xc19bf174cf692694} +@(private = "file") +K_8 :: simd.u64x2{0xe49b69c19ef14ad2, 0xefbe4786384f25e3} +@(private = "file") +K_9 :: simd.u64x2{0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65} +@(private = "file") +K_10 :: simd.u64x2{0x2de92c6f592b0275, 0x4a7484aa6ea6e483} +@(private = "file") +K_11 :: simd.u64x2{0x5cb0a9dcbd41fbd4, 0x76f988da831153b5} +@(private = "file") +K_12 :: simd.u64x2{0x983e5152ee66dfab, 0xa831c66d2db43210} +@(private = "file") +K_13 :: simd.u64x2{0xb00327c898fb213f, 0xbf597fc7beef0ee4} +@(private = "file") +K_14 :: simd.u64x2{0xc6e00bf33da88fc2, 0xd5a79147930aa725} +@(private = "file") +K_15 :: simd.u64x2{0x06ca6351e003826f, 0x142929670a0e6e70} +@(private = "file") +K_16 :: simd.u64x2{0x27b70a8546d22ffc, 0x2e1b21385c26c926} +@(private = "file") +K_17 :: simd.u64x2{0x4d2c6dfc5ac42aed, 0x53380d139d95b3df} +@(private = "file") +K_18 :: simd.u64x2{0x650a73548baf63de, 0x766a0abb3c77b2a8} +@(private = "file") +K_19 :: simd.u64x2{0x81c2c92e47edaee6, 0x92722c851482353b} +@(private = "file") +K_20 :: simd.u64x2{0xa2bfe8a14cf10364, 0xa81a664bbc423001} +@(private = "file") +K_21 :: simd.u64x2{0xc24b8b70d0f89791, 0xc76c51a30654be30} +@(private = "file") +K_22 :: simd.u64x2{0xd192e819d6ef5218, 0xd69906245565a910} +@(private = "file") +K_23 :: simd.u64x2{0xf40e35855771202a, 0x106aa07032bbd1b8} +@(private = "file") +K_24 :: simd.u64x2{0x19a4c116b8d2d0c8, 0x1e376c085141ab53} +@(private = "file") +K_25 :: simd.u64x2{0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8} +@(private = "file") +K_26 :: simd.u64x2{0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb} +@(private = "file") +K_27 :: simd.u64x2{0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3} +@(private = "file") +K_28 :: simd.u64x2{0x748f82ee5defb2fc, 0x78a5636f43172f60} +@(private = "file") +K_29 :: simd.u64x2{0x84c87814a1f0ab72, 0x8cc702081a6439ec} +@(private = "file") +K_30 :: simd.u64x2{0x90befffa23631e28, 0xa4506cebde82bde9} +@(private = "file") +K_31 :: simd.u64x2{0xbef9a3f7b2c67915, 0xc67178f2e372532b} +@(private = "file") +K_32 :: simd.u64x2{0xca273eceea26619c, 0xd186b8c721c0c207} +@(private = "file") +K_33 :: simd.u64x2{0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178} +@(private = "file") +K_34 :: simd.u64x2{0x06f067aa72176fba, 0x0a637dc5a2c898a6} +@(private = "file") +K_35 :: simd.u64x2{0x113f9804bef90dae, 0x1b710b35131c471b} +@(private = "file") +K_36 :: simd.u64x2{0x28db77f523047d84, 0x32caab7b40c72493} +@(private = "file") +K_37 :: simd.u64x2{0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c} +@(private = "file") +K_38 :: simd.u64x2{0x4cc5d4becb3e42b6, 0x597f299cfc657e2a} +@(private = "file") +K_39 :: simd.u64x2{0x5fcb6fab3ad6faec, 0x6c44198c4a475817} + +@(private, enable_target_feature = "neon,sha3") +sha512_transf_hw :: proc "contextless" (ctx: ^Context_512, data: []byte) #no_bounds_check { + state_0 := intrinsics.unaligned_load((^simd.u64x2)(&ctx.h[0])) + state_1 := intrinsics.unaligned_load((^simd.u64x2)(&ctx.h[2])) + state_2 := intrinsics.unaligned_load((^simd.u64x2)(&ctx.h[4])) + state_3 := intrinsics.unaligned_load((^simd.u64x2)(&ctx.h[6])) + + data := data + for len(data) >= BLOCK_SIZE_512 { + ab_save, cd_save, ef_save, gh_save := state_0, state_1, state_2, state_3 + + // Load message + msg_0 := intrinsics.unaligned_load((^simd.u64x2)(raw_data(data))) + msg_1 := intrinsics.unaligned_load((^simd.u64x2)(raw_data(data[16:]))) + msg_2 := intrinsics.unaligned_load((^simd.u64x2)(raw_data(data[32:]))) + msg_3 := intrinsics.unaligned_load((^simd.u64x2)(raw_data(data[48:]))) + msg_4 := intrinsics.unaligned_load((^simd.u64x2)(raw_data(data[64:]))) + msg_5 := intrinsics.unaligned_load((^simd.u64x2)(raw_data(data[80:]))) + msg_6 := intrinsics.unaligned_load((^simd.u64x2)(raw_data(data[96:]))) + msg_7 := intrinsics.unaligned_load((^simd.u64x2)(raw_data(data[112:]))) + + // Reverse for little endian + when ODIN_ENDIAN == .Little { + msg_0 = byteswap_u64x2(msg_0) + msg_1 = byteswap_u64x2(msg_1) + msg_2 = byteswap_u64x2(msg_2) + msg_3 = byteswap_u64x2(msg_3) + msg_4 = byteswap_u64x2(msg_4) + msg_5 = byteswap_u64x2(msg_5) + msg_6 = byteswap_u64x2(msg_6) + msg_7 = byteswap_u64x2(msg_7) + } + + // Rounds 0-1 + msg_k := simd.add(msg_0, K_0) + tmp_0 := simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_3) + tmp_1 := arm.vsha512hq_u64(tmp_0, simd.shuffle(state_2, state_3, 1, 2), simd.shuffle(state_1, state_2, 1, 2)) + state_3 = arm.vsha512h2q_u64(tmp_1, state_1, state_0) + state_1 = simd.add(state_1, tmp_1) + msg_0 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_0, msg_1), msg_7, simd.shuffle(msg_4, msg_5, 1, 2)) + + // Rounds 2-3 + msg_k = simd.add(msg_1, K_1) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_2) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_1, state_2, 1, 2), simd.shuffle(state_0, state_1, 1, 2)) + state_2 = arm.vsha512h2q_u64(tmp_1, state_0, state_3) + state_0 = simd.add(state_0, tmp_1) + msg_1 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_1, msg_2), msg_0, simd.shuffle(msg_5, msg_6, 1, 2)) + + // Rounds 4-5 + msg_k = simd.add(msg_2, K_2) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_1) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_0, state_1, 1, 2), simd.shuffle(state_3, state_0, 1, 2)) + state_1 = arm.vsha512h2q_u64(tmp_1, state_3, state_2) + state_3 = simd.add(state_3, tmp_1) + msg_2 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_2, msg_3), msg_1, simd.shuffle(msg_6, msg_7, 1, 2)) + + // Rounds 6-7 + msg_k = simd.add(msg_3, K_3) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_0) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_3, state_0, 1, 2), simd.shuffle(state_2, state_3, 1, 2)) + state_0 = arm.vsha512h2q_u64(tmp_1, state_2, state_1) + state_2 = simd.add(state_2, tmp_1) + msg_3 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_3, msg_4), msg_2, simd.shuffle(msg_7, msg_0, 1, 2)) + + // Rounds 8-9 + msg_k = simd.add(msg_4, K_4) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_3) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_2, state_3, 1, 2), simd.shuffle(state_1, state_2, 1, 2)) + state_3 = arm.vsha512h2q_u64(tmp_1, state_1, state_0) + state_1 = simd.add(state_1, tmp_1) + msg_4 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_4, msg_5), msg_3, simd.shuffle(msg_0, msg_1, 1, 2)) + + // Rounds 10-11 + msg_k = simd.add(msg_5, K_5) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_2) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_1, state_2, 1, 2), simd.shuffle(state_0, state_1, 1, 2)) + state_2 = arm.vsha512h2q_u64(tmp_1, state_0, state_3) + state_0 = simd.add(state_0, tmp_1) + msg_5 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_5, msg_6), msg_4, simd.shuffle(msg_1, msg_2, 1, 2)) + + // Rounds 12-13 + msg_k = simd.add(msg_6, K_6) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_1) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_0, state_1, 1, 2), simd.shuffle(state_3, state_0, 1, 2)) + state_1 = arm.vsha512h2q_u64(tmp_1, state_3, state_2) + state_3 = simd.add(state_3, tmp_1) + msg_6 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_6, msg_7), msg_5, simd.shuffle(msg_2, msg_3, 1, 2)) + + // Rounds 14-15 + msg_k = simd.add(msg_7, K_7) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_0) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_3, state_0, 1, 2), simd.shuffle(state_2, state_3, 1, 2)) + state_0 = arm.vsha512h2q_u64(tmp_1, state_2, state_1) + state_2 = simd.add(state_2, tmp_1) + msg_7 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_7, msg_0), msg_6, simd.shuffle(msg_3, msg_4, 1, 2)) + + // Rounds 16-17 + msg_k = simd.add(msg_0, K_8) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_3) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_2, state_3, 1, 2), simd.shuffle(state_1, state_2, 1, 2)) + state_3 = arm.vsha512h2q_u64(tmp_1, state_1, state_0) + state_1 = simd.add(state_1, tmp_1) + msg_0 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_0, msg_1), msg_7, simd.shuffle(msg_4, msg_5, 1, 2)) + + // Rounds 18-19 + msg_k = simd.add(msg_1, K_9) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_2) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_1, state_2, 1, 2), simd.shuffle(state_0, state_1, 1, 2)) + state_2 = arm.vsha512h2q_u64(tmp_1, state_0, state_3) + state_0 = simd.add(state_0, tmp_1) + msg_1 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_1, msg_2), msg_0, simd.shuffle(msg_5, msg_6, 1, 2)) + + // Rounds 20-21 + msg_k = simd.add(msg_2, K_10) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_1) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_0, state_1, 1, 2), simd.shuffle(state_3, state_0, 1, 2)) + state_1 = arm.vsha512h2q_u64(tmp_1, state_3, state_2) + state_3 = simd.add(state_3, tmp_1) + msg_2 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_2, msg_3), msg_1, simd.shuffle(msg_6, msg_7, 1, 2)) + + // Rounds 22-23 + msg_k = simd.add(msg_3, K_11) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_0) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_3, state_0, 1, 2), simd.shuffle(state_2, state_3, 1, 2)) + state_0 = arm.vsha512h2q_u64(tmp_1, state_2, state_1) + state_2 = simd.add(state_2, tmp_1) + msg_3 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_3, msg_4), msg_2, simd.shuffle(msg_7, msg_0, 1, 2)) + + // Rounds 24-25 + msg_k = simd.add(msg_4, K_12) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_3) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_2, state_3, 1, 2), simd.shuffle(state_1, state_2, 1, 2)) + state_3 = arm.vsha512h2q_u64(tmp_1, state_1, state_0) + state_1 = simd.add(state_1, tmp_1) + msg_4 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_4, msg_5), msg_3, simd.shuffle(msg_0, msg_1, 1, 2)) + + // Rounds 26-27 + msg_k = simd.add(msg_5, K_13) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_2) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_1, state_2, 1, 2), simd.shuffle(state_0, state_1, 1, 2)) + state_2 = arm.vsha512h2q_u64(tmp_1, state_0, state_3) + state_0 = simd.add(state_0, tmp_1) + msg_5 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_5, msg_6), msg_4, simd.shuffle(msg_1, msg_2, 1, 2)) + + // Rounds 28-29 + msg_k = simd.add(msg_6, K_14) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_1) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_0, state_1, 1, 2), simd.shuffle(state_3, state_0, 1, 2)) + state_1 = arm.vsha512h2q_u64(tmp_1, state_3, state_2) + state_3 = simd.add(state_3, tmp_1) + msg_6 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_6, msg_7), msg_5, simd.shuffle(msg_2, msg_3, 1, 2)) + + // Rounds 30-31 + msg_k = simd.add(msg_7, K_15) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_0) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_3, state_0, 1, 2), simd.shuffle(state_2, state_3, 1, 2)) + state_0 = arm.vsha512h2q_u64(tmp_1, state_2, state_1) + state_2 = simd.add(state_2, tmp_1) + msg_7 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_7, msg_0), msg_6, simd.shuffle(msg_3, msg_4, 1, 2)) + + // Rounds 32-33 + msg_k = simd.add(msg_0, K_16) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_3) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_2, state_3, 1, 2), simd.shuffle(state_1, state_2, 1, 2)) + state_3 = arm.vsha512h2q_u64(tmp_1, state_1, state_0) + state_1 = simd.add(state_1, tmp_1) + msg_0 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_0, msg_1), msg_7, simd.shuffle(msg_4, msg_5, 1, 2)) + + // Rounds 34-35 + msg_k = simd.add(msg_1, K_17) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_2) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_1, state_2, 1, 2), simd.shuffle(state_0, state_1, 1, 2)) + state_2 = arm.vsha512h2q_u64(tmp_1, state_0, state_3) + state_0 = simd.add(state_0, tmp_1) + msg_1 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_1, msg_2), msg_0, simd.shuffle(msg_5, msg_6, 1, 2)) + + // Rounds 36-37 + msg_k = simd.add(msg_2, K_18) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_1) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_0, state_1, 1, 2), simd.shuffle(state_3, state_0, 1, 2)) + state_1 = arm.vsha512h2q_u64(tmp_1, state_3, state_2) + state_3 = simd.add(state_3, tmp_1) + msg_2 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_2, msg_3), msg_1, simd.shuffle(msg_6, msg_7, 1, 2)) + + // Rounds 38-39 + msg_k = simd.add(msg_3, K_19) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_0) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_3, state_0, 1, 2), simd.shuffle(state_2, state_3, 1, 2)) + state_0 = arm.vsha512h2q_u64(tmp_1, state_2, state_1) + state_2 = simd.add(state_2, tmp_1) + msg_3 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_3, msg_4), msg_2, simd.shuffle(msg_7, msg_0, 1, 2)) + + // Rounds 40-41 + msg_k = simd.add(msg_4, K_20) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_3) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_2, state_3, 1, 2), simd.shuffle(state_1, state_2, 1, 2)) + state_3 = arm.vsha512h2q_u64(tmp_1, state_1, state_0) + state_1 = simd.add(state_1, tmp_1) + msg_4 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_4, msg_5), msg_3, simd.shuffle(msg_0, msg_1, 1, 2)) + + // Rounds 42-43 + msg_k = simd.add(msg_5, K_21) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_2) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_1, state_2, 1, 2), simd.shuffle(state_0, state_1, 1, 2)) + state_2 = arm.vsha512h2q_u64(tmp_1, state_0, state_3) + state_0 = simd.add(state_0, tmp_1) + msg_5 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_5, msg_6), msg_4, simd.shuffle(msg_1, msg_2, 1, 2)) + + // Rounds 44-45 + msg_k = simd.add(msg_6, K_22) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_1) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_0, state_1, 1, 2), simd.shuffle(state_3, state_0, 1, 2)) + state_1 = arm.vsha512h2q_u64(tmp_1, state_3, state_2) + state_3 = simd.add(state_3, tmp_1) + msg_6 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_6, msg_7), msg_5, simd.shuffle(msg_2, msg_3, 1, 2)) + + // Rounds 46-47 + msg_k = simd.add(msg_7, K_23) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_0) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_3, state_0, 1, 2), simd.shuffle(state_2, state_3, 1, 2)) + state_0 = arm.vsha512h2q_u64(tmp_1, state_2, state_1) + state_2 = simd.add(state_2, tmp_1) + msg_7 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_7, msg_0), msg_6, simd.shuffle(msg_3, msg_4, 1, 2)) + + // Rounds 48-49 + msg_k = simd.add(msg_0, K_24) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_3) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_2, state_3, 1, 2), simd.shuffle(state_1, state_2, 1, 2)) + state_3 = arm.vsha512h2q_u64(tmp_1, state_1, state_0) + state_1 = simd.add(state_1, tmp_1) + msg_0 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_0, msg_1), msg_7, simd.shuffle(msg_4, msg_5, 1, 2)) + + // Rounds 50-51 + msg_k = simd.add(msg_1, K_25) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_2) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_1, state_2, 1, 2), simd.shuffle(state_0, state_1, 1, 2)) + state_2 = arm.vsha512h2q_u64(tmp_1, state_0, state_3) + state_0 = simd.add(state_0, tmp_1) + msg_1 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_1, msg_2), msg_0, simd.shuffle(msg_5, msg_6, 1, 2)) + + // Rounds 52-53 + msg_k = simd.add(msg_2, K_26) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_1) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_0, state_1, 1, 2), simd.shuffle(state_3, state_0, 1, 2)) + state_1 = arm.vsha512h2q_u64(tmp_1, state_3, state_2) + state_3 = simd.add(state_3, tmp_1) + msg_2 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_2, msg_3), msg_1, simd.shuffle(msg_6, msg_7, 1, 2)) + + // Rounds 54-55 + msg_k = simd.add(msg_3, K_27) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_0) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_3, state_0, 1, 2), simd.shuffle(state_2, state_3, 1, 2)) + state_0 = arm.vsha512h2q_u64(tmp_1, state_2, state_1) + state_2 = simd.add(state_2, tmp_1) + msg_3 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_3, msg_4), msg_2, simd.shuffle(msg_7, msg_0, 1, 2)) + + // Rounds 56-57 + msg_k = simd.add(msg_4, K_28) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_3) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_2, state_3, 1, 2), simd.shuffle(state_1, state_2, 1, 2)) + state_3 = arm.vsha512h2q_u64(tmp_1, state_1, state_0) + state_1 = simd.add(state_1, tmp_1) + msg_4 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_4, msg_5), msg_3, simd.shuffle(msg_0, msg_1, 1, 2)) + + // Rounds 58-59 + msg_k = simd.add(msg_5, K_29) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_2) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_1, state_2, 1, 2), simd.shuffle(state_0, state_1, 1, 2)) + state_2 = arm.vsha512h2q_u64(tmp_1, state_0, state_3) + state_0 = simd.add(state_0, tmp_1) + msg_5 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_5, msg_6), msg_4, simd.shuffle(msg_1, msg_2, 1, 2)) + + // Rounds 60-61 + msg_k = simd.add(msg_6, K_30) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_1) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_0, state_1, 1, 2), simd.shuffle(state_3, state_0, 1, 2)) + state_1 = arm.vsha512h2q_u64(tmp_1, state_3, state_2) + state_3 = simd.add(state_3, tmp_1) + msg_6 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_6, msg_7), msg_5, simd.shuffle(msg_2, msg_3, 1, 2)) + + // Rounds 62-63 + msg_k = simd.add(msg_7, K_31) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_0) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_3, state_0, 1, 2), simd.shuffle(state_2, state_3, 1, 2)) + state_0 = arm.vsha512h2q_u64(tmp_1, state_2, state_1) + state_2 = simd.add(state_2, tmp_1) + msg_7 = arm.vsha512su1q_u64(arm.vsha512su0q_u64(msg_7, msg_0), msg_6, simd.shuffle(msg_3, msg_4, 1, 2)) + + // Rounds 64-65 + msg_k = simd.add(msg_0, K_32) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_3) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_2, state_3, 1, 2), simd.shuffle(state_1, state_2, 1, 2)) + state_3 = arm.vsha512h2q_u64(tmp_1, state_1, state_0) + state_1 = simd.add(state_1, tmp_1) + + // Rounds 66-67 + msg_k = simd.add(msg_1, K_33) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_2) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_1, state_2, 1, 2), simd.shuffle(state_0, state_1, 1, 2)) + state_2 = arm.vsha512h2q_u64(tmp_1, state_0, state_3) + state_0 = simd.add(state_0, tmp_1) + + // Rounds 68-69 + msg_k = simd.add(msg_2, K_34) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_1) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_0, state_1, 1, 2), simd.shuffle(state_3, state_0, 1, 2)) + state_1 = arm.vsha512h2q_u64(tmp_1, state_3, state_2) + state_3 = simd.add(state_3, tmp_1) + + // Rounds 70-71 + msg_k = simd.add(msg_3, K_35) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_0) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_3, state_0, 1, 2), simd.shuffle(state_2, state_3, 1, 2)) + state_0 = arm.vsha512h2q_u64(tmp_1, state_2, state_1) + state_2 = simd.add(state_2, tmp_1) + + // Rounds 72-73 + msg_k = simd.add(msg_4, K_36) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_3) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_2, state_3, 1, 2), simd.shuffle(state_1, state_2, 1, 2)) + state_3 = arm.vsha512h2q_u64(tmp_1, state_1, state_0) + state_1 = simd.add(state_1, tmp_1) + + // Rounds 74-75 + msg_k = simd.add(msg_5, K_37) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_2) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_1, state_2, 1, 2), simd.shuffle(state_0, state_1, 1, 2)) + state_2 = arm.vsha512h2q_u64(tmp_1, state_0, state_3) + state_0 = simd.add(state_0, tmp_1) + + // Rounds 76-77 + msg_k = simd.add(msg_6, K_38) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_1) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_0, state_1, 1, 2), simd.shuffle(state_3, state_0, 1, 2)) + state_1 = arm.vsha512h2q_u64(tmp_1, state_3, state_2) + state_3 = simd.add(state_3, tmp_1) + + // Rounds 78-79 + msg_k = simd.add(msg_7, K_39) + tmp_0 = simd.add(simd.shuffle(msg_k, msg_k, 1, 2), state_0) + tmp_1 = arm.vsha512hq_u64(tmp_0, simd.shuffle(state_3, state_0, 1, 2), simd.shuffle(state_2, state_3, 1, 2)) + state_0 = arm.vsha512h2q_u64(tmp_1, state_2, state_1) + state_2 = simd.add(state_2, tmp_1) + + // Combine state + state_0 = simd.add(state_0, ab_save) + state_1 = simd.add(state_1, cd_save) + state_2 = simd.add(state_2, ef_save) + state_3 = simd.add(state_3, gh_save) + + data = data[BLOCK_SIZE_512:] + } + + intrinsics.unaligned_store((^simd.u64x2)(&ctx.h[0]), state_0) + intrinsics.unaligned_store((^simd.u64x2)(&ctx.h[2]), state_1) + intrinsics.unaligned_store((^simd.u64x2)(&ctx.h[4]), state_2) + intrinsics.unaligned_store((^simd.u64x2)(&ctx.h[6]), state_3) +} + +when ODIN_ENDIAN == .Little { + @(private = "file", enable_target_feature = "neon") + byteswap_u64x2 :: #force_inline proc "contextless" (a: simd.u64x2) -> simd.u64x2 { + return transmute(simd.u64x2)( + simd.shuffle( + transmute(simd.u8x16)(a), + transmute(simd.u8x16)(a), + 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, + ) + ) + } +} diff --git a/core/crypto/sha2/sha512_impl_hw_gen.odin b/core/crypto/sha2/sha512_impl_hw_gen.odin new file mode 100644 index 000000000..701f82709 --- /dev/null +++ b/core/crypto/sha2/sha512_impl_hw_gen.odin @@ -0,0 +1,13 @@ +#+build !arm64 +package sha2 + +// is_hardware_accelerated_512 returns true if and only if (⟺) hardware +// accelerated SHA-384, SHA-512, and SHA-512/256 are supported. +is_hardware_accelerated_512 :: proc "contextless" () -> bool { + return false +} + +@(private) +sha512_transf_hw :: proc "contextless" (ctx: ^Context_512, data: []byte) { + panic_contextless(ERR_HW_NOT_SUPPORTED) +} diff --git a/core/crypto/sha3/sha3.odin b/core/crypto/sha3/sha3.odin index 2ca70963a..2f8d95092 100644 --- a/core/crypto/sha3/sha3.odin +++ b/core/crypto/sha3/sha3.odin @@ -79,7 +79,7 @@ update :: proc(ctx: ^Context, data: []byte) { // final finalizes the Context, writes the digest to hash, and calls // reset on the Context. // -// Iff finalize_clone is set, final will work on a copy of the Context, +// If and only if (⟺) finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { _sha3.final((^_sha3.Context)(ctx), hash, finalize_clone) diff --git a/core/crypto/sm3/sm3.odin b/core/crypto/sm3/sm3.odin index 186331d92..6f1d788e0 100644 --- a/core/crypto/sm3/sm3.odin +++ b/core/crypto/sm3/sm3.odin @@ -14,9 +14,9 @@ package sm3 zhibog, dotbmp: Initial implementation. */ +import "core:crypto" import "core:encoding/endian" import "core:math/bits" -import "core:mem" // DIGEST_SIZE is the SM3 digest size in bytes. DIGEST_SIZE :: 32 @@ -80,7 +80,7 @@ update :: proc(ctx: ^Context, data: []byte) { // final finalizes the Context, writes the digest to hash, and calls // reset on the Context. // -// Iff finalize_clone is set, final will work on a copy of the Context, +// If and only if (⟺) finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { ensure(ctx.is_initialized) @@ -126,7 +126,7 @@ reset :: proc(ctx: ^Context) { return } - mem.zero_explicit(ctx, size_of(ctx^)) + crypto.zero_explicit(ctx, size_of(ctx^)) } /* diff --git a/core/crypto/tuplehash/tuplehash.odin b/core/crypto/tuplehash/tuplehash.odin index 5c8d8e39b..a45c1b120 100644 --- a/core/crypto/tuplehash/tuplehash.odin +++ b/core/crypto/tuplehash/tuplehash.odin @@ -31,7 +31,7 @@ write_element :: proc(ctx: ^Context, data: []byte) { // final finalizes the Context, writes the digest to hash, and calls // reset on the Context. // -// Iff finalize_clone is set, final will work on a copy of the Context, +// If and only if (⟺) finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { _sha3.final_cshake((^_sha3.Context)(ctx), hash, finalize_clone) diff --git a/core/crypto/x25519/x25519.odin b/core/crypto/x25519/x25519.odin index e25d1831f..6268a882d 100644 --- a/core/crypto/x25519/x25519.odin +++ b/core/crypto/x25519/x25519.odin @@ -6,16 +6,19 @@ See: */ package x25519 +import "core:crypto" +import ed "core:crypto/_edwards25519" import field "core:crypto/_fiat/field_curve25519" -import "core:mem" // SCALAR_SIZE is the size of a X25519 scalar (private key) in bytes. SCALAR_SIZE :: 32 // POINT_SIZE is the size of a X25519 point (public key/shared secret) in bytes. POINT_SIZE :: 32 -@(private, rodata) -_BASE_POINT: [32]byte = {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +when crypto.COMPACT_IMPLS == true { + @(private,rodata) + _BASE_POINT: [32]byte = {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +} @(private) _scalar_bit :: #force_inline proc "contextless" (s: ^[32]byte, i: int) -> u8 { @@ -111,19 +114,44 @@ scalarmult :: proc(dst, scalar, point: []byte) { e[31] &= 127 e[31] |= 64 - p: [32]byte = --- - copy_slice(p[:], point) + p := (^[32]byte)(raw_data(point)) + d := (^[32]byte)(raw_data(dst)) + _scalarmult(d, &e, p) - d: [32]byte = --- - _scalarmult(&d, &e, &p) - copy_slice(dst, d[:]) - - mem.zero_explicit(&e, size_of(e)) - mem.zero_explicit(&d, size_of(d)) + crypto.zero_explicit(&e, size_of(e)) } // scalarmult_basepoint "multiplies" the provided scalar with the X25519 // base point and writes the resulting point to dst. scalarmult_basepoint :: proc(dst, scalar: []byte) { - scalarmult(dst, scalar, _BASE_POINT[:]) + when crypto.COMPACT_IMPLS == true { + scalarmult(dst, scalar, _BASE_POINT[:]) + } else { + ensure(len(scalar) == SCALAR_SIZE, "crypto/x25519: invalid scalar size") + ensure(len(dst) == POINT_SIZE, "crypto/x25519: invalid destination point size") + + sc: ed.Scalar = --- + ed.sc_set_bytes_rfc8032(&sc, scalar) + + ge: ed.Group_Element = --- + ed.ge_scalarmult_basepoint(&ge, &sc) + + // u = (y + z)/(z - y) + y_plus_z: field.Loose_Field_Element = --- + z_minus_y: field.Loose_Field_Element = --- + u: field.Tight_Field_Element = --- + + field.fe_add(&y_plus_z, &ge.y, &ge.z) + field.fe_sub(&z_minus_y, &ge.z, &ge.y) + field.fe_carry_inv(&u, &z_minus_y) + field.fe_carry_mul(&u, &y_plus_z, field.fe_relax_cast(&u)) + + dst_ := (^[32]byte)(raw_data(dst)) + field.fe_to_bytes(dst_, &u) + + field.fe_clear_vec([]^field.Loose_Field_Element{&y_plus_z, &z_minus_y}) + field.fe_clear(&u) + ed.sc_clear(&sc) + ed.ge_clear(&ge) + } } diff --git a/core/crypto/x448/x448.odin b/core/crypto/x448/x448.odin index 75693e055..f2cbaadec 100644 --- a/core/crypto/x448/x448.odin +++ b/core/crypto/x448/x448.odin @@ -6,8 +6,8 @@ See: */ package x448 +import "core:crypto" import field "core:crypto/_fiat/field_curve448" -import "core:mem" // SCALAR_SIZE is the size of a X448 scalar (private key) in bytes. SCALAR_SIZE :: 56 @@ -143,8 +143,8 @@ scalarmult :: proc(dst, scalar, point: []byte) { _scalarmult(&d, &e, &p) copy_slice(dst, d[:]) - mem.zero_explicit(&e, size_of(e)) - mem.zero_explicit(&d, size_of(d)) + crypto.zero_explicit(&e, size_of(e)) + crypto.zero_explicit(&d, size_of(d)) } // scalarmult_basepoint "multiplies" the provided scalar with the X448 diff --git a/core/debug/trace/doc.odin b/core/debug/trace/doc.odin index e5fd3f7c2..f9bb82fb5 100644 --- a/core/debug/trace/doc.odin +++ b/core/debug/trace/doc.odin @@ -19,7 +19,7 @@ Example: } runtime.print_byte('\n') - ctx := &trace_ctx + ctx := &global_trace_ctx if !trace.in_resolve(ctx) { buf: [64]trace.Frame runtime.print_string("Debug Trace:\n") @@ -48,4 +48,4 @@ Example: } */ -package debug_trace \ No newline at end of file +package debug_trace diff --git a/core/debug/trace/trace.odin b/core/debug/trace/trace.odin index 134609b05..6a9ba9dab 100644 --- a/core/debug/trace/trace.odin +++ b/core/debug/trace/trace.odin @@ -44,4 +44,34 @@ resolve :: proc(ctx: ^Context, frame: Frame, allocator: runtime.Allocator) -> (r @(require_results) in_resolve :: proc "contextless" (ctx: ^Context) -> bool { return intrinsics.atomic_load(&ctx.in_resolve) -} \ No newline at end of file +} + +_format_hex :: proc(buf: []byte, val: uintptr, allocator: runtime.Allocator) -> int { + _digits := "0123456789abcdef" + + shift := (size_of(uintptr) * 8) - 4 + offs := 0 + + for shift >= 0 { + d := (val >> uint(shift)) & 0xf + buf[offs] = _digits[d] + shift -= 4 + offs += 1 + } + + return offs +} + +_format_missing_proc :: proc(addr: uintptr, allocator: runtime.Allocator) -> string { + PREFIX :: "proc:0x" + buf, buf_err := make([]byte, len(PREFIX) + 16, allocator) + copy(buf, PREFIX) + + if buf_err != nil { + return "OUT_OF_MEMORY" + } + + offs := len(PREFIX) + offs += _format_hex(buf[offs:], uintptr(addr), allocator) + return string(buf[:offs]) +} diff --git a/core/debug/trace/trace_cpp.odin b/core/debug/trace/trace_cpp.odin index 8ef377cef..1a96ee112 100644 --- a/core/debug/trace/trace_cpp.odin +++ b/core/debug/trace/trace_cpp.odin @@ -5,7 +5,6 @@ package debug_trace import "base:intrinsics" import "base:runtime" import "core:strings" -import "core:fmt" import "core:c" // NOTE: Relies on C++23 which adds and becomes ABI and that can be used @@ -164,7 +163,7 @@ _resolve :: proc(ctx: ^Context, frame: Frame, allocator: runtime.Allocator) -> F } else if info: Dl_info; dladdr(rawptr(address), &info) != 0 && info.dli_sname != "" { frame.procedure = strings.clone_from_cstring(info.dli_sname, btc.allocator) } else { - frame.procedure = fmt.aprintf("(procedure: 0x%x)", allocator=btc.allocator) + frame.procedure = _format_missing_proc(address, btc.allocator) } frame.line = i32(line) return 0 diff --git a/core/debug/trace/trace_windows.odin b/core/debug/trace/trace_windows.odin index 04e92f125..b27b0ee29 100644 --- a/core/debug/trace/trace_windows.odin +++ b/core/debug/trace/trace_windows.odin @@ -6,7 +6,6 @@ import "base:intrinsics" import "base:runtime" import win32 "core:sys/windows" -import "core:fmt" _Context :: struct { hProcess: win32.HANDLE, @@ -56,7 +55,7 @@ _resolve :: proc(ctx: ^Context, frame: Frame, allocator: runtime.Allocator) -> ( if win32.SymFromAddrW(ctx.impl.hProcess, win32.DWORD64(frame), &{}, symbol) { fl.procedure, _ = win32.wstring_to_utf8(cstring16(&symbol.Name[0]), -1, allocator) } else { - fl.procedure = fmt.aprintf("(procedure: 0x%x)", frame, allocator=allocator) + fl.procedure = _format_missing_proc(uintptr(frame), allocator) } line: win32.IMAGEHLP_LINE64 diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index 34de2ff53..d272b32b8 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -153,15 +153,15 @@ decode :: proc( padding_count += 1 } + // Verify no padding in the middle + for i := 0; i < data_len - padding_count; i += 1 { + if data[i] == byte(PADDING) { + return nil, .Malformed_Input + } + } + // Check for proper padding and length combinations if padding_count > 0 { - // Verify no padding in the middle - for i := 0; i < data_len - padding_count; i += 1 { - if data[i] == byte(PADDING) { - return nil, .Malformed_Input - } - } - content_len := data_len - padding_count mod8 := content_len % 8 required_padding: int diff --git a/core/encoding/base64/base64.odin b/core/encoding/base64/base64.odin index 032716bde..1488e2201 100644 --- a/core/encoding/base64/base64.odin +++ b/core/encoding/base64/base64.odin @@ -9,8 +9,8 @@ truncate it from the encoded output. */ package encoding_base64 +import "base:runtime" import "core:io" -import "core:mem" import "core:strings" ENC_TABLE := [64]byte { @@ -24,6 +24,18 @@ ENC_TABLE := [64]byte { '4', '5', '6', '7', '8', '9', '+', '/', } +// Encoding table for Base64url variant +ENC_URL_TABLE := [64]byte { + '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', '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', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '-', '_', +} + PADDING :: '=' DEC_TABLE := [256]u8 { @@ -61,7 +73,44 @@ DEC_TABLE := [256]u8 { 0, 0, 0, 0, 0, 0, 0, 0, } -encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> (encoded: string, err: mem.Allocator_Error) #optional_allocator_error { +// Decoding table for Base64url variant +DEC_URL_TABLE := [256]u8 { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 62, 0, 0, + 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 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, 0, 0, 0, 0, 63, + 0, 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, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +} + + +encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> (encoded: string, err: runtime.Allocator_Error) #optional_allocator_error { out_length := encoded_len(data) if out_length == 0 { return @@ -112,7 +161,7 @@ encoded_len :: proc(data: []byte) -> int { return ((4 * length / 3) + 3) &~ 3 } -decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> (decoded: []byte, err: mem.Allocator_Error) #optional_allocator_error { +decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> (decoded: []byte, err: runtime.Allocator_Error) #optional_allocator_error { out_length := decoded_len(data) out := strings.builder_make(0, out_length, allocator) or_return diff --git a/core/encoding/cbor/marshal.odin b/core/encoding/cbor/marshal.odin index b23087c90..b9333bf2b 100644 --- a/core/encoding/cbor/marshal.odin +++ b/core/encoding/cbor/marshal.odin @@ -285,6 +285,32 @@ _marshal_into_encoder :: proc(e: Encoder, v: any, ti: ^runtime.Type_Info) -> (er } return + + case runtime.Type_Info_Fixed_Capacity_Dynamic_Array: + array_data := uintptr(v.data) + array_len := (^int)(array_data + info.len_offset)^ + if info.elem.id == byte { + raw := runtime.Raw_Slice{v.data, array_len} + return err_conv(_encode_bytes(e, transmute([]byte)raw)) + } + + err_conv(_encode_u64(e, u64(array_len), .Array)) or_return + + if impl, ok := _tag_implementations_type[info.elem.id]; ok { + for i in 0..marshal(e, any{rawptr(data), info.elem.id}) or_return + } + return + } + + elem_ti := runtime.type_info_core(type_info_of(info.elem.id)) + for i in 0.. t.capacity { return _unsupported(v, hdr) } + + // Copy into array type, delete original. + slice := ([^]byte)(v.data)[:len(bytes)] + n := copy(slice, bytes) + assert(n == len(bytes)) + (^int)(uintptr(v.data) + t.len_offset)^ = n + return } return _unsupported(v, hdr) @@ -553,6 +570,21 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header if out_of_space { return _unsupported(v, hdr) } return + case reflect.Type_Info_Fixed_Capacity_Dynamic_Array: + length, _ := err_conv(_decode_len_container(d, add)) or_return + if length > t.capacity { + return _unsupported(v, hdr) + } + + da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, allocator } + + out_of_space := assign_array(d, &da, t.elem, length, growable=false) or_return + if out_of_space { return _unsupported(v, hdr) } + + (^int)(uintptr(v.data) + t.len_offset)^ = length + + return + case reflect.Type_Info_Complex: length, _ := err_conv(_decode_len_container(d, add)) or_return if length > 2 { @@ -661,8 +693,7 @@ _unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, unknown := length == -1 fields := reflect.struct_fields_zipped(ti.id) - idx := 0 - for ; idx < len(fields) && (unknown || idx < length); idx += 1 { + for idx := 0; unknown || idx < length; idx += 1 { // Decode key, keys can only be strings. key: string if keyv, kerr := decode_key(d, v, context.temp_allocator); unknown && kerr == .Break { @@ -710,16 +741,6 @@ _unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, _unmarshal_value(d, fany, _decode_header(r) or_return) or_return } - // If there are fields left in the map that did not get decoded into the struct, decode and discard them. - if !unknown { - for _ in idx.. (err: Error) { } } -xml_decode_entity :: proc(entity: string) -> (decoded: rune, ok: bool) { +xml_decode_entity :: proc(entity: string) -> (decoded: [2]rune, rune_count: int, ok: bool) { entity := entity - if len(entity) == 0 { return -1, false } + if len(entity) == 0 { return } - switch entity[0] { - case '#': + if entity[0] == '#' { base := 10 val := 0 entity = entity[1:] - if len(entity) == 0 { return -1, false } + if len(entity) == 0 { return } if entity[0] == 'x' || entity[0] == 'X' { base = 16 @@ -237,30 +239,275 @@ xml_decode_entity :: proc(entity: string) -> (decoded: rune, ok: bool) { val += int(r - '0') case 'a'..='f': - if base == 10 { return -1, false } + if base == 10 { return } val *= base val += int(r - 'a' + 10) case 'A'..='F': - if base == 10 { return -1, false } + if base == 10 { return } val *= base val += int(r - 'A' + 10) case: - return -1, false + return } - if val > MAX_RUNE_CODEPOINT { return -1, false } + if val > MAX_RUNE_CODEPOINT { return } entity = entity[1:] } - return rune(val), true - - case: - // Named entity. - return named_xml_entity_to_rune(entity) + return rune(val), 1, true } + // Named entity. + return named_xml_entity_to_rune(entity) } + +// escape_html escapes special characters like '&' to become '&'. +// It escapes only 5 different characters: & ' < > and " +@(require_results) +escape_html :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (output: string, was_allocation: bool) { + /* + & -> & + ' -> ' // ' is shorter than ' (NOTE: ' was not available until HTML 5) + < -> < + > -> > + " -> " // " is shorter than " + */ + + b := transmute([]byte)s + + extra_bytes_needed := 0 + + for c in b { + switch c { + case '&': extra_bytes_needed += 4 + case '\'': extra_bytes_needed += 4 + case '<': extra_bytes_needed += 3 + case '>': extra_bytes_needed += 3 + case '"': extra_bytes_needed += 4 + } + } + + if extra_bytes_needed == 0 { + return s, false + } + + t, err := make([]byte, len(s) + extra_bytes_needed, allocator, loc) + if err != nil { + return + } + was_allocation = true + + w := 0 + for c in b { + x := "" + switch c { + case '&': x = "&" + case '\'': x = "'" + case '<': x = "<" + case '>': x = ">" + case '"': x = """ + } + if x != "" { + copy(t[w:], x) + w += len(x) + } else { + t[w] = c + w += 1 + } + } + output = string(t[0:w]) + return +} + + +@(require_results) +unescape_html :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (output: string, was_allocation: bool, err: runtime.Allocator_Error) { + @(require_results) + do_append :: proc(s: string, amp_idx: int, buf: ^[dynamic]byte) -> (n: int) { + s, amp_idx := s, amp_idx + + n += len(s[:amp_idx]) + if buf != nil { append(buf, s[:amp_idx]) } + s = s[amp_idx:] + for len(s) > 0 { + b, w, j := unescape_entity(s) + n += w + if buf != nil { append(buf, ..b[:w]) } + + s = s[j:] + + amp_idx = strings.index_byte(s, '&') + if amp_idx < 0 { + n += len(s) + if buf != nil { append(buf, s) } + break + } + n += amp_idx + if buf != nil { append(buf, s[:amp_idx]) } + s = s[amp_idx:] + } + + return + } + + s := s + amp_idx := strings.index_byte(s, '&') + if amp_idx < 0 { + return s, false, nil + } + + // NOTE(bill): this does a two pass in order to minimize the allocations required + bytes_required := do_append(s, amp_idx, nil) + + buf := make([dynamic]byte, 0, bytes_required, allocator, loc) or_return + was_allocation = true + + _ = do_append(s, amp_idx, &buf) + + assert(len(buf) == cap(buf)) + output = string(buf[:]) + + return +} + +// Returns an unescaped string of an encoded XML/HTML entity. +@(require_results) +unescape_entity :: proc(s: string) -> (b: [8]byte, w: int, j: int) { + s := s + if len(s) < 2 { + return + } + if s[0] != '&' { + return + } + j = 1 + + if s[j] == '#' { // scan numbers + j += 1 + if len(s) <= 3 { // remove `&#.` + return + } + c := s[j] + hex := false + if c == 'x' || c == 'X' { + hex = true + j += 1 + } + + x := rune(0) + scan_number: for j < len(s) { + c = s[j] + j += 1 + if hex { + switch c { + case '0'..='9': x = 16*x + rune(c) - '0'; continue scan_number + case 'a'..='f': x = 16*x + rune(c) - 'a' + 10; continue scan_number + case 'A'..='F': x = 16*x + rune(c) - 'A' + 10; continue scan_number + } + } else { + switch c { + case '0'..='9': x = 10*x + rune(c) - '0'; continue scan_number + } + } + + // Keep the ';' to check for cases which require it and cases which might not + if c != ';' { + j -= 1 + } + break scan_number + } + + + if j <= 3 { // no replacement characters found + return + } + + @(static, rodata) + windows_1252_replacement_table := [0xa0 - 0x80]rune{ // Windows-1252 -> UTF-8 + '\u20ac', '\u0081', '\u201a', '\u0192', + '\u201e', '\u2026', '\u2020', '\u2021', + '\u02c6', '\u2030', '\u0160', '\u2039', + '\u0152', '\u008d', '\u017d', '\u008f', + '\u0090', '\u2018', '\u2019', '\u201c', + '\u201d', '\u2022', '\u2013', '\u2014', + '\u02dc', '\u2122', '\u0161', '\u203a', + '\u0153', '\u009d', '\u017e', '\u0178', + } + + switch x { + case 0x80..<0xa0: + x = windows_1252_replacement_table[x-0x80] + case 0, 0xd800..=0xdfff: + x = utf8.RUNE_ERROR + case: + if x > 0x10ffff { + x = utf8.RUNE_ERROR + } + + } + + b1, w1 := utf8.encode_rune(x) + w += copy(b[:], b1[:w1]) + return + } + + // Lookup by entity names + + scan_ident: for j < len(s) { // scan over letters and digits + c := s[j] + j += 1 + + switch c { + case 'a'..='z', 'A'..='Z', '0'..='9': + continue scan_ident + } + // Keep the ';' to check for cases which require it and cases which might not + if c != ';' { + j -= 1 + } + break scan_ident + } + + entity_name := s[1:j] + if len(entity_name) == 0 { + return + } + + if entity_name[len(entity_name)-1] == ';' { + entity_name = entity_name[:len(entity_name)-1] + } + + if r2, _, ok := named_xml_entity_to_rune(entity_name); ok { + b1, w1 := utf8.encode_rune(r2[0]) + w += copy(b[w:], b1[:w1]) + if r2[1] != 0 { + b2, w2 := utf8.encode_rune(r2[1]) + w += copy(b[w:], b2[:w2]) + } + return + } + + // The longest entities that do not end with a semicolon are <=6 bytes long + LONGEST_ENTITY_WITHOUT_SEMICOLON :: 6 + + n := min(len(entity_name)-1, LONGEST_ENTITY_WITHOUT_SEMICOLON) + for i := n; i > 1; i -= 1 { + if r2, _, ok := named_xml_entity_to_rune(entity_name[:i]); ok { + b1, w1 := utf8.encode_rune(r2[0]) + w += copy(b[w:], b1[:w1]) + if r2[1] != 0 { + b2, w2 := utf8.encode_rune(r2[1]) + w += copy(b[w:], b2[:w2]) + } + return + } + } + + return +} + + // Private XML helper to extract `&;` entity. @(private="file") _extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) { diff --git a/core/encoding/entity/generated.odin b/core/encoding/entity/generated.odin index 52027ae03..fda8e5c2a 100644 --- a/core/encoding/entity/generated.odin +++ b/core/encoding/entity/generated.odin @@ -6,14 +6,14 @@ package encoding_unicode_entity /* This file is generated from "https://github.com/w3c/xml-entities/blob/gh-pages/unicode.xml". - + UPDATE: - - Ensure the XML file was downloaded using "tests\core\download_assets.py". + - Ensure the XML file was downloaded using "tests\core\download_assets.py", given the path to the "tests\assets" directory. - Run "core/unicode/tools/generate_entity_table.odin" Odin unicode generated tables: https://github.com/odin-lang/Odin/tree/master/core/encoding/entity - Copyright David Carlisle 1999-2023 + Copyright David Carlisle 1999-2025 Use and distribution of this code are permitted under the terms of the W3C Software Notice and License. @@ -43,5047 +43,5047 @@ XML_NAME_TO_RUNE_MAX_LENGTH :: 31 entity_name - a string, like "copy" that describes a user-encoded Unicode entity as used in XML. Returns: - "decoded" - The decoded rune if found by name, or -1 otherwise. - "ok" - true if found, false if not. + "decoded" - The decoded runes if found by name, or all zero otherwise. + "rune_count" - The number of decoded runes + "ok" - true if found, false if not. IMPORTANT: XML processors (including browsers) treat these names as case-sensitive. So do we. */ -named_xml_entity_to_rune :: proc(name: string) -> (decoded: rune, ok: bool) { +named_xml_entity_to_rune :: proc(name: string) -> (decoded: [2]rune, rune_count: int, ok: bool) { /* Early out if the name is too short or too long. min as a precaution in case the generated table has a bogus value. */ if len(name) < min(1, XML_NAME_TO_RUNE_MIN_LENGTH) || len(name) > XML_NAME_TO_RUNE_MAX_LENGTH { - return -1, false + return } switch rune(name[0]) { - case 'A': switch name { case "AElig": // LATIN CAPITAL LETTER AE - return rune(0xc6), true + return {'Æ', 0}, 1, true case "AMP": // AMPERSAND - return rune(0x26), true + return {'&', 0}, 1, true case "Aacgr": // GREEK CAPITAL LETTER ALPHA WITH TONOS - return rune(0x0386), true + return {'\u0386', 0}, 1, true case "Aacute": // LATIN CAPITAL LETTER A WITH ACUTE - return rune(0xc1), true + return {'Á', 0}, 1, true case "Abreve": // LATIN CAPITAL LETTER A WITH BREVE - return rune(0x0102), true + return {'\u0102', 0}, 1, true case "Acirc": // LATIN CAPITAL LETTER A WITH CIRCUMFLEX - return rune(0xc2), true + return {'Â', 0}, 1, true case "Acy": // CYRILLIC CAPITAL LETTER A - return rune(0x0410), true + return {'\u0410', 0}, 1, true case "Afr": // MATHEMATICAL FRAKTUR CAPITAL A - return rune(0x01d504), true + return {'\U0001d504', 0}, 1, true case "Agr": // GREEK CAPITAL LETTER ALPHA - return rune(0x0391), true + return {'\u0391', 0}, 1, true case "Agrave": // LATIN CAPITAL LETTER A WITH GRAVE - return rune(0xc0), true + return {'À', 0}, 1, true case "Alpha": // GREEK CAPITAL LETTER ALPHA - return rune(0x0391), true + return {'\u0391', 0}, 1, true case "Amacr": // LATIN CAPITAL LETTER A WITH MACRON - return rune(0x0100), true + return {'\u0100', 0}, 1, true case "And": // DOUBLE LOGICAL AND - return rune(0x2a53), true + return {'\u2a53', 0}, 1, true case "Aogon": // LATIN CAPITAL LETTER A WITH OGONEK - return rune(0x0104), true + return {'\u0104', 0}, 1, true case "Aopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL A - return rune(0x01d538), true + return {'\U0001d538', 0}, 1, true case "ApplyFunction": // FUNCTION APPLICATION - return rune(0x2061), true + return {'\u2061', 0}, 1, true case "Aring": // LATIN CAPITAL LETTER A WITH RING ABOVE - return rune(0xc5), true + return {'Å', 0}, 1, true case "Ascr": // MATHEMATICAL SCRIPT CAPITAL A - return rune(0x01d49c), true + return {'\U0001d49c', 0}, 1, true case "Assign": // COLON EQUALS - return rune(0x2254), true + return {'\u2254', 0}, 1, true case "Ast": // TWO ASTERISKS ALIGNED VERTICALLY - return rune(0x2051), true + return {'\u2051', 0}, 1, true case "Atilde": // LATIN CAPITAL LETTER A WITH TILDE - return rune(0xc3), true + return {'Ã', 0}, 1, true case "Auml": // LATIN CAPITAL LETTER A WITH DIAERESIS - return rune(0xc4), true + return {'Ä', 0}, 1, true } case 'B': switch name { case "Backslash": // SET MINUS - return rune(0x2216), true + return {'\u2216', 0}, 1, true case "Barint": // INTEGRAL WITH DOUBLE STROKE - return rune(0x2a0e), true + return {'\u2a0e', 0}, 1, true case "Barv": // SHORT DOWN TACK WITH OVERBAR - return rune(0x2ae7), true + return {'\u2ae7', 0}, 1, true case "Barwed": // PERSPECTIVE - return rune(0x2306), true + return {'\u2306', 0}, 1, true case "Barwedl": // LOGICAL AND WITH DOUBLE OVERBAR - return rune(0x2a5e), true + return {'\u2a5e', 0}, 1, true case "Bcy": // CYRILLIC CAPITAL LETTER BE - return rune(0x0411), true + return {'\u0411', 0}, 1, true case "Because": // BECAUSE - return rune(0x2235), true + return {'\u2235', 0}, 1, true case "Bernoullis": // SCRIPT CAPITAL B - return rune(0x212c), true + return {'\u212c', 0}, 1, true case "Beta": // GREEK CAPITAL LETTER BETA - return rune(0x0392), true + return {'\u0392', 0}, 1, true case "Bfr": // MATHEMATICAL FRAKTUR CAPITAL B - return rune(0x01d505), true + return {'\U0001d505', 0}, 1, true case "Bgr": // GREEK CAPITAL LETTER BETA - return rune(0x0392), true + return {'\u0392', 0}, 1, true case "Bopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL B - return rune(0x01d539), true + return {'\U0001d539', 0}, 1, true case "Breve": // BREVE - return rune(0x02d8), true + return {'\u02d8', 0}, 1, true case "Bscr": // SCRIPT CAPITAL B - return rune(0x212c), true + return {'\u212c', 0}, 1, true case "Bumpeq": // GEOMETRICALLY EQUIVALENT TO - return rune(0x224e), true + return {'\u224e', 0}, 1, true case "Bvert": // BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL - return rune(0x2506), true + return {'\u2506', 0}, 1, true } case 'C': switch name { case "CHcy": // CYRILLIC CAPITAL LETTER CHE - return rune(0x0427), true + return {'\u0427', 0}, 1, true case "COPY": // COPYRIGHT SIGN - return rune(0xa9), true + return {'©', 0}, 1, true case "Cacute": // LATIN CAPITAL LETTER C WITH ACUTE - return rune(0x0106), true + return {'\u0106', 0}, 1, true case "Cap": // DOUBLE INTERSECTION - return rune(0x22d2), true + return {'\u22d2', 0}, 1, true case "CapitalDifferentialD": // DOUBLE-STRUCK ITALIC CAPITAL D - return rune(0x2145), true + return {'\u2145', 0}, 1, true case "Cayleys": // BLACK-LETTER CAPITAL C - return rune(0x212d), true + return {'\u212d', 0}, 1, true case "Ccaron": // LATIN CAPITAL LETTER C WITH CARON - return rune(0x010c), true + return {'\u010c', 0}, 1, true case "Ccedil": // LATIN CAPITAL LETTER C WITH CEDILLA - return rune(0xc7), true + return {'Ç', 0}, 1, true case "Ccirc": // LATIN CAPITAL LETTER C WITH CIRCUMFLEX - return rune(0x0108), true + return {'\u0108', 0}, 1, true case "Cconint": // VOLUME INTEGRAL - return rune(0x2230), true + return {'\u2230', 0}, 1, true case "Cdot": // LATIN CAPITAL LETTER C WITH DOT ABOVE - return rune(0x010a), true + return {'\u010a', 0}, 1, true case "Cedilla": // CEDILLA - return rune(0xb8), true + return {'¸', 0}, 1, true case "CenterDot": // MIDDLE DOT - return rune(0xb7), true + return {'·', 0}, 1, true case "Cfr": // BLACK-LETTER CAPITAL C - return rune(0x212d), true + return {'\u212d', 0}, 1, true case "Chi": // GREEK CAPITAL LETTER CHI - return rune(0x03a7), true + return {'\u03a7', 0}, 1, true case "CircleDot": // CIRCLED DOT OPERATOR - return rune(0x2299), true + return {'\u2299', 0}, 1, true case "CircleMinus": // CIRCLED MINUS - return rune(0x2296), true + return {'\u2296', 0}, 1, true case "CirclePlus": // CIRCLED PLUS - return rune(0x2295), true + return {'\u2295', 0}, 1, true case "CircleTimes": // CIRCLED TIMES - return rune(0x2297), true + return {'\u2297', 0}, 1, true case "ClockwiseContourIntegral": // CLOCKWISE CONTOUR INTEGRAL - return rune(0x2232), true + return {'\u2232', 0}, 1, true case "CloseCurlyDoubleQuote": // RIGHT DOUBLE QUOTATION MARK - return rune(0x201d), true + return {'\u201d', 0}, 1, true case "CloseCurlyQuote": // RIGHT SINGLE QUOTATION MARK - return rune(0x2019), true + return {'\u2019', 0}, 1, true case "Colon": // PROPORTION - return rune(0x2237), true + return {'\u2237', 0}, 1, true case "Colone": // DOUBLE COLON EQUAL - return rune(0x2a74), true + return {'\u2a74', 0}, 1, true case "Congruent": // IDENTICAL TO - return rune(0x2261), true + return {'\u2261', 0}, 1, true case "Conint": // SURFACE INTEGRAL - return rune(0x222f), true + return {'\u222f', 0}, 1, true case "ContourIntegral": // CONTOUR INTEGRAL - return rune(0x222e), true + return {'\u222e', 0}, 1, true case "Copf": // DOUBLE-STRUCK CAPITAL C - return rune(0x2102), true + return {'\u2102', 0}, 1, true case "Coproduct": // N-ARY COPRODUCT - return rune(0x2210), true + return {'\u2210', 0}, 1, true case "CounterClockwiseContourIntegral": // ANTICLOCKWISE CONTOUR INTEGRAL - return rune(0x2233), true + return {'\u2233', 0}, 1, true case "Cross": // VECTOR OR CROSS PRODUCT - return rune(0x2a2f), true + return {'\u2a2f', 0}, 1, true case "Cscr": // MATHEMATICAL SCRIPT CAPITAL C - return rune(0x01d49e), true + return {'\U0001d49e', 0}, 1, true case "Cup": // DOUBLE UNION - return rune(0x22d3), true + return {'\u22d3', 0}, 1, true case "CupCap": // EQUIVALENT TO - return rune(0x224d), true + return {'\u224d', 0}, 1, true } case 'D': switch name { case "DD": // DOUBLE-STRUCK ITALIC CAPITAL D - return rune(0x2145), true + return {'\u2145', 0}, 1, true case "DDotrahd": // RIGHTWARDS ARROW WITH DOTTED STEM - return rune(0x2911), true + return {'\u2911', 0}, 1, true case "DJcy": // CYRILLIC CAPITAL LETTER DJE - return rune(0x0402), true + return {'\u0402', 0}, 1, true case "DScy": // CYRILLIC CAPITAL LETTER DZE - return rune(0x0405), true + return {'\u0405', 0}, 1, true case "DZcy": // CYRILLIC CAPITAL LETTER DZHE - return rune(0x040f), true + return {'\u040f', 0}, 1, true case "Dagger": // DOUBLE DAGGER - return rune(0x2021), true + return {'\u2021', 0}, 1, true case "Darr": // DOWNWARDS TWO HEADED ARROW - return rune(0x21a1), true + return {'\u21a1', 0}, 1, true case "Dashv": // VERTICAL BAR DOUBLE LEFT TURNSTILE - return rune(0x2ae4), true + return {'\u2ae4', 0}, 1, true case "Dcaron": // LATIN CAPITAL LETTER D WITH CARON - return rune(0x010e), true + return {'\u010e', 0}, 1, true case "Dcy": // CYRILLIC CAPITAL LETTER DE - return rune(0x0414), true + return {'\u0414', 0}, 1, true case "Del": // NABLA - return rune(0x2207), true + return {'\u2207', 0}, 1, true case "Delta": // GREEK CAPITAL LETTER DELTA - return rune(0x0394), true + return {'\u0394', 0}, 1, true case "Dfr": // MATHEMATICAL FRAKTUR CAPITAL D - return rune(0x01d507), true + return {'\U0001d507', 0}, 1, true case "Dgr": // GREEK CAPITAL LETTER DELTA - return rune(0x0394), true + return {'\u0394', 0}, 1, true case "DiacriticalAcute": // ACUTE ACCENT - return rune(0xb4), true + return {'´', 0}, 1, true case "DiacriticalDot": // DOT ABOVE - return rune(0x02d9), true + return {'\u02d9', 0}, 1, true case "DiacriticalDoubleAcute": // DOUBLE ACUTE ACCENT - return rune(0x02dd), true + return {'\u02dd', 0}, 1, true case "DiacriticalGrave": // GRAVE ACCENT - return rune(0x60), true + return {'`', 0}, 1, true case "DiacriticalTilde": // SMALL TILDE - return rune(0x02dc), true + return {'\u02dc', 0}, 1, true case "Diamond": // DIAMOND OPERATOR - return rune(0x22c4), true + return {'\u22c4', 0}, 1, true case "DifferentialD": // DOUBLE-STRUCK ITALIC SMALL D - return rune(0x2146), true + return {'\u2146', 0}, 1, true case "Dopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL D - return rune(0x01d53b), true + return {'\U0001d53b', 0}, 1, true case "Dot": // DIAERESIS - return rune(0xa8), true + return {'¨', 0}, 1, true case "DotDot": // COMBINING FOUR DOTS ABOVE - return rune(0x20dc), true + return {'\u20dc', 0}, 1, true case "DotEqual": // APPROACHES THE LIMIT - return rune(0x2250), true + return {'\u2250', 0}, 1, true case "DoubleContourIntegral": // SURFACE INTEGRAL - return rune(0x222f), true + return {'\u222f', 0}, 1, true case "DoubleDot": // DIAERESIS - return rune(0xa8), true + return {'¨', 0}, 1, true case "DoubleDownArrow": // DOWNWARDS DOUBLE ARROW - return rune(0x21d3), true + return {'\u21d3', 0}, 1, true case "DoubleLeftArrow": // LEFTWARDS DOUBLE ARROW - return rune(0x21d0), true + return {'\u21d0', 0}, 1, true case "DoubleLeftRightArrow": // LEFT RIGHT DOUBLE ARROW - return rune(0x21d4), true + return {'\u21d4', 0}, 1, true case "DoubleLeftTee": // VERTICAL BAR DOUBLE LEFT TURNSTILE - return rune(0x2ae4), true + return {'\u2ae4', 0}, 1, true case "DoubleLongLeftArrow": // LONG LEFTWARDS DOUBLE ARROW - return rune(0x27f8), true + return {'\u27f8', 0}, 1, true case "DoubleLongLeftRightArrow": // LONG LEFT RIGHT DOUBLE ARROW - return rune(0x27fa), true + return {'\u27fa', 0}, 1, true case "DoubleLongRightArrow": // LONG RIGHTWARDS DOUBLE ARROW - return rune(0x27f9), true + return {'\u27f9', 0}, 1, true case "DoubleRightArrow": // RIGHTWARDS DOUBLE ARROW - return rune(0x21d2), true + return {'\u21d2', 0}, 1, true case "DoubleRightTee": // TRUE - return rune(0x22a8), true + return {'\u22a8', 0}, 1, true case "DoubleUpArrow": // UPWARDS DOUBLE ARROW - return rune(0x21d1), true + return {'\u21d1', 0}, 1, true case "DoubleUpDownArrow": // UP DOWN DOUBLE ARROW - return rune(0x21d5), true + return {'\u21d5', 0}, 1, true case "DoubleVerticalBar": // PARALLEL TO - return rune(0x2225), true + return {'\u2225', 0}, 1, true case "DownArrow": // DOWNWARDS ARROW - return rune(0x2193), true + return {'\u2193', 0}, 1, true case "DownArrowBar": // DOWNWARDS ARROW TO BAR - return rune(0x2913), true + return {'\u2913', 0}, 1, true case "DownArrowUpArrow": // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW - return rune(0x21f5), true + return {'\u21f5', 0}, 1, true case "DownBreve": // COMBINING INVERTED BREVE - return rune(0x0311), true + return {'\u0311', 0}, 1, true case "DownLeftRightVector": // LEFT BARB DOWN RIGHT BARB DOWN HARPOON - return rune(0x2950), true + return {'\u2950', 0}, 1, true case "DownLeftTeeVector": // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR - return rune(0x295e), true + return {'\u295e', 0}, 1, true case "DownLeftVector": // LEFTWARDS HARPOON WITH BARB DOWNWARDS - return rune(0x21bd), true + return {'\u21bd', 0}, 1, true case "DownLeftVectorBar": // LEFTWARDS HARPOON WITH BARB DOWN TO BAR - return rune(0x2956), true + return {'\u2956', 0}, 1, true case "DownRightTeeVector": // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR - return rune(0x295f), true + return {'\u295f', 0}, 1, true case "DownRightVector": // RIGHTWARDS HARPOON WITH BARB DOWNWARDS - return rune(0x21c1), true + return {'\u21c1', 0}, 1, true case "DownRightVectorBar": // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR - return rune(0x2957), true + return {'\u2957', 0}, 1, true case "DownTee": // DOWN TACK - return rune(0x22a4), true + return {'\u22a4', 0}, 1, true case "DownTeeArrow": // DOWNWARDS ARROW FROM BAR - return rune(0x21a7), true + return {'\u21a7', 0}, 1, true case "Downarrow": // DOWNWARDS DOUBLE ARROW - return rune(0x21d3), true + return {'\u21d3', 0}, 1, true case "Dscr": // MATHEMATICAL SCRIPT CAPITAL D - return rune(0x01d49f), true + return {'\U0001d49f', 0}, 1, true case "Dstrok": // LATIN CAPITAL LETTER D WITH STROKE - return rune(0x0110), true + return {'\u0110', 0}, 1, true } case 'E': switch name { case "EEacgr": // GREEK CAPITAL LETTER ETA WITH TONOS - return rune(0x0389), true + return {'\u0389', 0}, 1, true case "EEgr": // GREEK CAPITAL LETTER ETA - return rune(0x0397), true + return {'\u0397', 0}, 1, true case "ENG": // LATIN CAPITAL LETTER ENG - return rune(0x014a), true + return {'\u014a', 0}, 1, true case "ETH": // LATIN CAPITAL LETTER ETH - return rune(0xd0), true + return {'Ð', 0}, 1, true case "Eacgr": // GREEK CAPITAL LETTER EPSILON WITH TONOS - return rune(0x0388), true + return {'\u0388', 0}, 1, true case "Eacute": // LATIN CAPITAL LETTER E WITH ACUTE - return rune(0xc9), true + return {'É', 0}, 1, true case "Ecaron": // LATIN CAPITAL LETTER E WITH CARON - return rune(0x011a), true + return {'\u011a', 0}, 1, true case "Ecirc": // LATIN CAPITAL LETTER E WITH CIRCUMFLEX - return rune(0xca), true + return {'Ê', 0}, 1, true case "Ecy": // CYRILLIC CAPITAL LETTER E - return rune(0x042d), true + return {'\u042d', 0}, 1, true case "Edot": // LATIN CAPITAL LETTER E WITH DOT ABOVE - return rune(0x0116), true + return {'\u0116', 0}, 1, true case "Efr": // MATHEMATICAL FRAKTUR CAPITAL E - return rune(0x01d508), true + return {'\U0001d508', 0}, 1, true case "Egr": // GREEK CAPITAL LETTER EPSILON - return rune(0x0395), true + return {'\u0395', 0}, 1, true case "Egrave": // LATIN CAPITAL LETTER E WITH GRAVE - return rune(0xc8), true + return {'È', 0}, 1, true case "Element": // ELEMENT OF - return rune(0x2208), true + return {'\u2208', 0}, 1, true case "Emacr": // LATIN CAPITAL LETTER E WITH MACRON - return rune(0x0112), true + return {'\u0112', 0}, 1, true case "EmptySmallSquare": // WHITE MEDIUM SQUARE - return rune(0x25fb), true + return {'\u25fb', 0}, 1, true case "EmptyVerySmallSquare": // WHITE SMALL SQUARE - return rune(0x25ab), true + return {'\u25ab', 0}, 1, true case "Eogon": // LATIN CAPITAL LETTER E WITH OGONEK - return rune(0x0118), true + return {'\u0118', 0}, 1, true case "Eopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL E - return rune(0x01d53c), true + return {'\U0001d53c', 0}, 1, true case "Epsilon": // GREEK CAPITAL LETTER EPSILON - return rune(0x0395), true + return {'\u0395', 0}, 1, true case "Equal": // TWO CONSECUTIVE EQUALS SIGNS - return rune(0x2a75), true + return {'\u2a75', 0}, 1, true case "EqualTilde": // MINUS TILDE - return rune(0x2242), true + return {'\u2242', 0}, 1, true case "Equilibrium": // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON - return rune(0x21cc), true + return {'\u21cc', 0}, 1, true case "Escr": // SCRIPT CAPITAL E - return rune(0x2130), true + return {'\u2130', 0}, 1, true case "Esim": // EQUALS SIGN ABOVE TILDE OPERATOR - return rune(0x2a73), true + return {'\u2a73', 0}, 1, true case "Eta": // GREEK CAPITAL LETTER ETA - return rune(0x0397), true + return {'\u0397', 0}, 1, true case "Euml": // LATIN CAPITAL LETTER E WITH DIAERESIS - return rune(0xcb), true + return {'Ë', 0}, 1, true case "Exists": // THERE EXISTS - return rune(0x2203), true + return {'\u2203', 0}, 1, true case "ExponentialE": // DOUBLE-STRUCK ITALIC SMALL E - return rune(0x2147), true + return {'\u2147', 0}, 1, true } case 'F': switch name { case "Fcy": // CYRILLIC CAPITAL LETTER EF - return rune(0x0424), true + return {'\u0424', 0}, 1, true case "Ffr": // MATHEMATICAL FRAKTUR CAPITAL F - return rune(0x01d509), true + return {'\U0001d509', 0}, 1, true case "FilledSmallSquare": // BLACK MEDIUM SQUARE - return rune(0x25fc), true + return {'\u25fc', 0}, 1, true case "FilledVerySmallSquare": // BLACK SMALL SQUARE - return rune(0x25aa), true + return {'\u25aa', 0}, 1, true case "Fopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL F - return rune(0x01d53d), true + return {'\U0001d53d', 0}, 1, true case "ForAll": // FOR ALL - return rune(0x2200), true + return {'\u2200', 0}, 1, true case "Fouriertrf": // SCRIPT CAPITAL F - return rune(0x2131), true + return {'\u2131', 0}, 1, true case "Fscr": // SCRIPT CAPITAL F - return rune(0x2131), true + return {'\u2131', 0}, 1, true } case 'G': switch name { case "GJcy": // CYRILLIC CAPITAL LETTER GJE - return rune(0x0403), true + return {'\u0403', 0}, 1, true case "GT": // GREATER-THAN SIGN - return rune(0x3e), true + return {'>', 0}, 1, true case "Game": // TURNED SANS-SERIF CAPITAL G - return rune(0x2141), true + return {'\u2141', 0}, 1, true case "Gamma": // GREEK CAPITAL LETTER GAMMA - return rune(0x0393), true + return {'\u0393', 0}, 1, true case "Gammad": // GREEK LETTER DIGAMMA - return rune(0x03dc), true + return {'\u03dc', 0}, 1, true case "Gbreve": // LATIN CAPITAL LETTER G WITH BREVE - return rune(0x011e), true + return {'\u011e', 0}, 1, true case "Gcedil": // LATIN CAPITAL LETTER G WITH CEDILLA - return rune(0x0122), true + return {'\u0122', 0}, 1, true case "Gcirc": // LATIN CAPITAL LETTER G WITH CIRCUMFLEX - return rune(0x011c), true + return {'\u011c', 0}, 1, true case "Gcy": // CYRILLIC CAPITAL LETTER GHE - return rune(0x0413), true + return {'\u0413', 0}, 1, true case "Gdot": // LATIN CAPITAL LETTER G WITH DOT ABOVE - return rune(0x0120), true + return {'\u0120', 0}, 1, true case "Gfr": // MATHEMATICAL FRAKTUR CAPITAL G - return rune(0x01d50a), true + return {'\U0001d50a', 0}, 1, true case "Gg": // VERY MUCH GREATER-THAN - return rune(0x22d9), true + return {'\u22d9', 0}, 1, true case "Ggr": // GREEK CAPITAL LETTER GAMMA - return rune(0x0393), true + return {'\u0393', 0}, 1, true case "Gopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL G - return rune(0x01d53e), true + return {'\U0001d53e', 0}, 1, true case "GreaterEqual": // GREATER-THAN OR EQUAL TO - return rune(0x2265), true + return {'\u2265', 0}, 1, true case "GreaterEqualLess": // GREATER-THAN EQUAL TO OR LESS-THAN - return rune(0x22db), true + return {'\u22db', 0}, 1, true case "GreaterFullEqual": // GREATER-THAN OVER EQUAL TO - return rune(0x2267), true + return {'\u2267', 0}, 1, true case "GreaterGreater": // DOUBLE NESTED GREATER-THAN - return rune(0x2aa2), true + return {'\u2aa2', 0}, 1, true case "GreaterLess": // GREATER-THAN OR LESS-THAN - return rune(0x2277), true + return {'\u2277', 0}, 1, true case "GreaterSlantEqual": // GREATER-THAN OR SLANTED EQUAL TO - return rune(0x2a7e), true + return {'\u2a7e', 0}, 1, true case "GreaterTilde": // GREATER-THAN OR EQUIVALENT TO - return rune(0x2273), true + return {'\u2273', 0}, 1, true case "Gscr": // MATHEMATICAL SCRIPT CAPITAL G - return rune(0x01d4a2), true + return {'\U0001d4a2', 0}, 1, true case "Gt": // MUCH GREATER-THAN - return rune(0x226b), true + return {'\u226b', 0}, 1, true } case 'H': switch name { case "HARDcy": // CYRILLIC CAPITAL LETTER HARD SIGN - return rune(0x042a), true + return {'\u042a', 0}, 1, true case "Hacek": // CARON - return rune(0x02c7), true + return {'\u02c7', 0}, 1, true case "Hat": // CIRCUMFLEX ACCENT - return rune(0x5e), true + return {'^', 0}, 1, true case "Hcirc": // LATIN CAPITAL LETTER H WITH CIRCUMFLEX - return rune(0x0124), true + return {'\u0124', 0}, 1, true case "Hfr": // BLACK-LETTER CAPITAL H - return rune(0x210c), true + return {'\u210c', 0}, 1, true case "HilbertSpace": // SCRIPT CAPITAL H - return rune(0x210b), true + return {'\u210b', 0}, 1, true case "Hopf": // DOUBLE-STRUCK CAPITAL H - return rune(0x210d), true + return {'\u210d', 0}, 1, true case "HorizontalLine": // BOX DRAWINGS LIGHT HORIZONTAL - return rune(0x2500), true + return {'\u2500', 0}, 1, true case "Hscr": // SCRIPT CAPITAL H - return rune(0x210b), true + return {'\u210b', 0}, 1, true case "Hstrok": // LATIN CAPITAL LETTER H WITH STROKE - return rune(0x0126), true + return {'\u0126', 0}, 1, true case "HumpDownHump": // GEOMETRICALLY EQUIVALENT TO - return rune(0x224e), true + return {'\u224e', 0}, 1, true case "HumpEqual": // DIFFERENCE BETWEEN - return rune(0x224f), true + return {'\u224f', 0}, 1, true } case 'I': switch name { case "IEcy": // CYRILLIC CAPITAL LETTER IE - return rune(0x0415), true + return {'\u0415', 0}, 1, true case "IJlig": // LATIN CAPITAL LIGATURE IJ - return rune(0x0132), true + return {'\u0132', 0}, 1, true case "IOcy": // CYRILLIC CAPITAL LETTER IO - return rune(0x0401), true + return {'\u0401', 0}, 1, true case "Iacgr": // GREEK CAPITAL LETTER IOTA WITH TONOS - return rune(0x038a), true + return {'\u038a', 0}, 1, true case "Iacute": // LATIN CAPITAL LETTER I WITH ACUTE - return rune(0xcd), true + return {'Í', 0}, 1, true case "Icirc": // LATIN CAPITAL LETTER I WITH CIRCUMFLEX - return rune(0xce), true + return {'Î', 0}, 1, true case "Icy": // CYRILLIC CAPITAL LETTER I - return rune(0x0418), true + return {'\u0418', 0}, 1, true case "Idigr": // GREEK CAPITAL LETTER IOTA WITH DIALYTIKA - return rune(0x03aa), true + return {'\u03aa', 0}, 1, true case "Idot": // LATIN CAPITAL LETTER I WITH DOT ABOVE - return rune(0x0130), true + return {'\u0130', 0}, 1, true case "Ifr": // BLACK-LETTER CAPITAL I - return rune(0x2111), true + return {'\u2111', 0}, 1, true case "Igr": // GREEK CAPITAL LETTER IOTA - return rune(0x0399), true + return {'\u0399', 0}, 1, true case "Igrave": // LATIN CAPITAL LETTER I WITH GRAVE - return rune(0xcc), true + return {'Ì', 0}, 1, true case "Im": // BLACK-LETTER CAPITAL I - return rune(0x2111), true + return {'\u2111', 0}, 1, true case "Imacr": // LATIN CAPITAL LETTER I WITH MACRON - return rune(0x012a), true + return {'\u012a', 0}, 1, true case "ImaginaryI": // DOUBLE-STRUCK ITALIC SMALL I - return rune(0x2148), true + return {'\u2148', 0}, 1, true case "Implies": // RIGHTWARDS DOUBLE ARROW - return rune(0x21d2), true + return {'\u21d2', 0}, 1, true case "Int": // DOUBLE INTEGRAL - return rune(0x222c), true + return {'\u222c', 0}, 1, true case "Integral": // INTEGRAL - return rune(0x222b), true + return {'\u222b', 0}, 1, true case "Intersection": // N-ARY INTERSECTION - return rune(0x22c2), true + return {'\u22c2', 0}, 1, true case "InvisibleComma": // INVISIBLE SEPARATOR - return rune(0x2063), true + return {'\u2063', 0}, 1, true case "InvisibleTimes": // INVISIBLE TIMES - return rune(0x2062), true + return {'\u2062', 0}, 1, true case "Iogon": // LATIN CAPITAL LETTER I WITH OGONEK - return rune(0x012e), true + return {'\u012e', 0}, 1, true case "Iopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL I - return rune(0x01d540), true + return {'\U0001d540', 0}, 1, true case "Iota": // GREEK CAPITAL LETTER IOTA - return rune(0x0399), true + return {'\u0399', 0}, 1, true case "Iscr": // SCRIPT CAPITAL I - return rune(0x2110), true + return {'\u2110', 0}, 1, true case "Itilde": // LATIN CAPITAL LETTER I WITH TILDE - return rune(0x0128), true + return {'\u0128', 0}, 1, true case "Iukcy": // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I - return rune(0x0406), true + return {'\u0406', 0}, 1, true case "Iuml": // LATIN CAPITAL LETTER I WITH DIAERESIS - return rune(0xcf), true + return {'Ï', 0}, 1, true } case 'J': switch name { case "Jcirc": // LATIN CAPITAL LETTER J WITH CIRCUMFLEX - return rune(0x0134), true + return {'\u0134', 0}, 1, true case "Jcy": // CYRILLIC CAPITAL LETTER SHORT I - return rune(0x0419), true + return {'\u0419', 0}, 1, true case "Jfr": // MATHEMATICAL FRAKTUR CAPITAL J - return rune(0x01d50d), true + return {'\U0001d50d', 0}, 1, true case "Jopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL J - return rune(0x01d541), true + return {'\U0001d541', 0}, 1, true case "Jscr": // MATHEMATICAL SCRIPT CAPITAL J - return rune(0x01d4a5), true + return {'\U0001d4a5', 0}, 1, true case "Jsercy": // CYRILLIC CAPITAL LETTER JE - return rune(0x0408), true + return {'\u0408', 0}, 1, true case "Jukcy": // CYRILLIC CAPITAL LETTER UKRAINIAN IE - return rune(0x0404), true + return {'\u0404', 0}, 1, true } case 'K': switch name { case "KHcy": // CYRILLIC CAPITAL LETTER HA - return rune(0x0425), true + return {'\u0425', 0}, 1, true case "KHgr": // GREEK CAPITAL LETTER CHI - return rune(0x03a7), true + return {'\u03a7', 0}, 1, true case "KJcy": // CYRILLIC CAPITAL LETTER KJE - return rune(0x040c), true + return {'\u040c', 0}, 1, true case "Kappa": // GREEK CAPITAL LETTER KAPPA - return rune(0x039a), true + return {'\u039a', 0}, 1, true case "Kcedil": // LATIN CAPITAL LETTER K WITH CEDILLA - return rune(0x0136), true + return {'\u0136', 0}, 1, true case "Kcy": // CYRILLIC CAPITAL LETTER KA - return rune(0x041a), true + return {'\u041a', 0}, 1, true case "Kfr": // MATHEMATICAL FRAKTUR CAPITAL K - return rune(0x01d50e), true + return {'\U0001d50e', 0}, 1, true case "Kgr": // GREEK CAPITAL LETTER KAPPA - return rune(0x039a), true + return {'\u039a', 0}, 1, true case "Kopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL K - return rune(0x01d542), true + return {'\U0001d542', 0}, 1, true case "Kscr": // MATHEMATICAL SCRIPT CAPITAL K - return rune(0x01d4a6), true + return {'\U0001d4a6', 0}, 1, true } case 'L': switch name { case "LJcy": // CYRILLIC CAPITAL LETTER LJE - return rune(0x0409), true + return {'\u0409', 0}, 1, true case "LT": // LESS-THAN SIGN - return rune(0x3c), true + return {'<', 0}, 1, true case "Lacute": // LATIN CAPITAL LETTER L WITH ACUTE - return rune(0x0139), true + return {'\u0139', 0}, 1, true case "Lambda": // GREEK CAPITAL LETTER LAMDA - return rune(0x039b), true + return {'\u039b', 0}, 1, true case "Lang": // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET - return rune(0x27ea), true + return {'\u27ea', 0}, 1, true case "Laplacetrf": // SCRIPT CAPITAL L - return rune(0x2112), true + return {'\u2112', 0}, 1, true case "Larr": // LEFTWARDS TWO HEADED ARROW - return rune(0x219e), true + return {'\u219e', 0}, 1, true case "Lcaron": // LATIN CAPITAL LETTER L WITH CARON - return rune(0x013d), true + return {'\u013d', 0}, 1, true case "Lcedil": // LATIN CAPITAL LETTER L WITH CEDILLA - return rune(0x013b), true + return {'\u013b', 0}, 1, true case "Lcy": // CYRILLIC CAPITAL LETTER EL - return rune(0x041b), true + return {'\u041b', 0}, 1, true case "LeftAngleBracket": // MATHEMATICAL LEFT ANGLE BRACKET - return rune(0x27e8), true + return {'\u27e8', 0}, 1, true case "LeftArrow": // LEFTWARDS ARROW - return rune(0x2190), true + return {'\u2190', 0}, 1, true case "LeftArrowBar": // LEFTWARDS ARROW TO BAR - return rune(0x21e4), true + return {'\u21e4', 0}, 1, true case "LeftArrowRightArrow": // LEFTWARDS ARROW OVER RIGHTWARDS ARROW - return rune(0x21c6), true + return {'\u21c6', 0}, 1, true case "LeftCeiling": // LEFT CEILING - return rune(0x2308), true + return {'\u2308', 0}, 1, true case "LeftDoubleBracket": // MATHEMATICAL LEFT WHITE SQUARE BRACKET - return rune(0x27e6), true + return {'\u27e6', 0}, 1, true case "LeftDownTeeVector": // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR - return rune(0x2961), true + return {'\u2961', 0}, 1, true case "LeftDownVector": // DOWNWARDS HARPOON WITH BARB LEFTWARDS - return rune(0x21c3), true + return {'\u21c3', 0}, 1, true case "LeftDownVectorBar": // DOWNWARDS HARPOON WITH BARB LEFT TO BAR - return rune(0x2959), true + return {'\u2959', 0}, 1, true case "LeftFloor": // LEFT FLOOR - return rune(0x230a), true + return {'\u230a', 0}, 1, true case "LeftRightArrow": // LEFT RIGHT ARROW - return rune(0x2194), true + return {'\u2194', 0}, 1, true case "LeftRightVector": // LEFT BARB UP RIGHT BARB UP HARPOON - return rune(0x294e), true + return {'\u294e', 0}, 1, true case "LeftTee": // LEFT TACK - return rune(0x22a3), true + return {'\u22a3', 0}, 1, true case "LeftTeeArrow": // LEFTWARDS ARROW FROM BAR - return rune(0x21a4), true + return {'\u21a4', 0}, 1, true case "LeftTeeVector": // LEFTWARDS HARPOON WITH BARB UP FROM BAR - return rune(0x295a), true + return {'\u295a', 0}, 1, true case "LeftTriangle": // NORMAL SUBGROUP OF - return rune(0x22b2), true + return {'\u22b2', 0}, 1, true case "LeftTriangleBar": // LEFT TRIANGLE BESIDE VERTICAL BAR - return rune(0x29cf), true + return {'\u29cf', 0}, 1, true case "LeftTriangleEqual": // NORMAL SUBGROUP OF OR EQUAL TO - return rune(0x22b4), true + return {'\u22b4', 0}, 1, true case "LeftUpDownVector": // UP BARB LEFT DOWN BARB LEFT HARPOON - return rune(0x2951), true + return {'\u2951', 0}, 1, true case "LeftUpTeeVector": // UPWARDS HARPOON WITH BARB LEFT FROM BAR - return rune(0x2960), true + return {'\u2960', 0}, 1, true case "LeftUpVector": // UPWARDS HARPOON WITH BARB LEFTWARDS - return rune(0x21bf), true + return {'\u21bf', 0}, 1, true case "LeftUpVectorBar": // UPWARDS HARPOON WITH BARB LEFT TO BAR - return rune(0x2958), true + return {'\u2958', 0}, 1, true case "LeftVector": // LEFTWARDS HARPOON WITH BARB UPWARDS - return rune(0x21bc), true + return {'\u21bc', 0}, 1, true case "LeftVectorBar": // LEFTWARDS HARPOON WITH BARB UP TO BAR - return rune(0x2952), true + return {'\u2952', 0}, 1, true case "Leftarrow": // LEFTWARDS DOUBLE ARROW - return rune(0x21d0), true + return {'\u21d0', 0}, 1, true case "Leftrightarrow": // LEFT RIGHT DOUBLE ARROW - return rune(0x21d4), true + return {'\u21d4', 0}, 1, true case "LessEqualGreater": // LESS-THAN EQUAL TO OR GREATER-THAN - return rune(0x22da), true + return {'\u22da', 0}, 1, true case "LessFullEqual": // LESS-THAN OVER EQUAL TO - return rune(0x2266), true + return {'\u2266', 0}, 1, true case "LessGreater": // LESS-THAN OR GREATER-THAN - return rune(0x2276), true + return {'\u2276', 0}, 1, true case "LessLess": // DOUBLE NESTED LESS-THAN - return rune(0x2aa1), true + return {'\u2aa1', 0}, 1, true case "LessSlantEqual": // LESS-THAN OR SLANTED EQUAL TO - return rune(0x2a7d), true + return {'\u2a7d', 0}, 1, true case "LessTilde": // LESS-THAN OR EQUIVALENT TO - return rune(0x2272), true + return {'\u2272', 0}, 1, true case "Lfr": // MATHEMATICAL FRAKTUR CAPITAL L - return rune(0x01d50f), true + return {'\U0001d50f', 0}, 1, true case "Lgr": // GREEK CAPITAL LETTER LAMDA - return rune(0x039b), true + return {'\u039b', 0}, 1, true case "Ll": // VERY MUCH LESS-THAN - return rune(0x22d8), true + return {'\u22d8', 0}, 1, true case "Lleftarrow": // LEFTWARDS TRIPLE ARROW - return rune(0x21da), true + return {'\u21da', 0}, 1, true case "Lmidot": // LATIN CAPITAL LETTER L WITH MIDDLE DOT - return rune(0x013f), true + return {'\u013f', 0}, 1, true case "LongLeftArrow": // LONG LEFTWARDS ARROW - return rune(0x27f5), true + return {'\u27f5', 0}, 1, true case "LongLeftRightArrow": // LONG LEFT RIGHT ARROW - return rune(0x27f7), true + return {'\u27f7', 0}, 1, true case "LongRightArrow": // LONG RIGHTWARDS ARROW - return rune(0x27f6), true + return {'\u27f6', 0}, 1, true case "Longleftarrow": // LONG LEFTWARDS DOUBLE ARROW - return rune(0x27f8), true + return {'\u27f8', 0}, 1, true case "Longleftrightarrow": // LONG LEFT RIGHT DOUBLE ARROW - return rune(0x27fa), true + return {'\u27fa', 0}, 1, true case "Longrightarrow": // LONG RIGHTWARDS DOUBLE ARROW - return rune(0x27f9), true + return {'\u27f9', 0}, 1, true case "Lopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL L - return rune(0x01d543), true + return {'\U0001d543', 0}, 1, true case "LowerLeftArrow": // SOUTH WEST ARROW - return rune(0x2199), true + return {'\u2199', 0}, 1, true case "LowerRightArrow": // SOUTH EAST ARROW - return rune(0x2198), true + return {'\u2198', 0}, 1, true case "Lscr": // SCRIPT CAPITAL L - return rune(0x2112), true + return {'\u2112', 0}, 1, true case "Lsh": // UPWARDS ARROW WITH TIP LEFTWARDS - return rune(0x21b0), true + return {'\u21b0', 0}, 1, true case "Lstrok": // LATIN CAPITAL LETTER L WITH STROKE - return rune(0x0141), true + return {'\u0141', 0}, 1, true case "Lt": // MUCH LESS-THAN - return rune(0x226a), true + return {'\u226a', 0}, 1, true case "Ltbar": // DOUBLE NESTED LESS-THAN WITH UNDERBAR - return rune(0x2aa3), true + return {'\u2aa3', 0}, 1, true } case 'M': switch name { case "Map": // RIGHTWARDS TWO-HEADED ARROW FROM BAR - return rune(0x2905), true + return {'\u2905', 0}, 1, true case "Mapfrom": // LEFTWARDS DOUBLE ARROW FROM BAR - return rune(0x2906), true + return {'\u2906', 0}, 1, true case "Mapto": // RIGHTWARDS DOUBLE ARROW FROM BAR - return rune(0x2907), true + return {'\u2907', 0}, 1, true case "Mcy": // CYRILLIC CAPITAL LETTER EM - return rune(0x041c), true + return {'\u041c', 0}, 1, true case "MediumSpace": // MEDIUM MATHEMATICAL SPACE - return rune(0x205f), true + return {'\u205f', 0}, 1, true case "Mellintrf": // SCRIPT CAPITAL M - return rune(0x2133), true + return {'\u2133', 0}, 1, true case "Mfr": // MATHEMATICAL FRAKTUR CAPITAL M - return rune(0x01d510), true + return {'\U0001d510', 0}, 1, true case "Mgr": // GREEK CAPITAL LETTER MU - return rune(0x039c), true + return {'\u039c', 0}, 1, true case "MinusPlus": // MINUS-OR-PLUS SIGN - return rune(0x2213), true + return {'\u2213', 0}, 1, true case "Mopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL M - return rune(0x01d544), true + return {'\U0001d544', 0}, 1, true case "Mscr": // SCRIPT CAPITAL M - return rune(0x2133), true + return {'\u2133', 0}, 1, true case "Mu": // GREEK CAPITAL LETTER MU - return rune(0x039c), true + return {'\u039c', 0}, 1, true } case 'N': switch name { case "NJcy": // CYRILLIC CAPITAL LETTER NJE - return rune(0x040a), true + return {'\u040a', 0}, 1, true case "Nacute": // LATIN CAPITAL LETTER N WITH ACUTE - return rune(0x0143), true + return {'\u0143', 0}, 1, true case "Ncaron": // LATIN CAPITAL LETTER N WITH CARON - return rune(0x0147), true + return {'\u0147', 0}, 1, true case "Ncedil": // LATIN CAPITAL LETTER N WITH CEDILLA - return rune(0x0145), true + return {'\u0145', 0}, 1, true case "Ncy": // CYRILLIC CAPITAL LETTER EN - return rune(0x041d), true + return {'\u041d', 0}, 1, true case "NegativeMediumSpace": // ZERO WIDTH SPACE - return rune(0x200b), true + return {'\u200b', 0}, 1, true case "NegativeThickSpace": // ZERO WIDTH SPACE - return rune(0x200b), true + return {'\u200b', 0}, 1, true case "NegativeThinSpace": // ZERO WIDTH SPACE - return rune(0x200b), true + return {'\u200b', 0}, 1, true case "NegativeVeryThinSpace": // ZERO WIDTH SPACE - return rune(0x200b), true + return {'\u200b', 0}, 1, true case "NestedGreaterGreater": // MUCH GREATER-THAN - return rune(0x226b), true + return {'\u226b', 0}, 1, true case "NestedLessLess": // MUCH LESS-THAN - return rune(0x226a), true + return {'\u226a', 0}, 1, true case "NewLine": // LINE FEED (LF) - return rune(0x0a), true + return {'\n', 0}, 1, true case "Nfr": // MATHEMATICAL FRAKTUR CAPITAL N - return rune(0x01d511), true + return {'\U0001d511', 0}, 1, true case "Ngr": // GREEK CAPITAL LETTER NU - return rune(0x039d), true + return {'\u039d', 0}, 1, true case "NoBreak": // WORD JOINER - return rune(0x2060), true + return {'\u2060', 0}, 1, true case "NonBreakingSpace": // NO-BREAK SPACE - return rune(0xa0), true + return {'\u00a0', 0}, 1, true case "Nopf": // DOUBLE-STRUCK CAPITAL N - return rune(0x2115), true + return {'\u2115', 0}, 1, true case "Not": // DOUBLE STROKE NOT SIGN - return rune(0x2aec), true + return {'\u2aec', 0}, 1, true case "NotCongruent": // NOT IDENTICAL TO - return rune(0x2262), true + return {'\u2262', 0}, 1, true case "NotCupCap": // NOT EQUIVALENT TO - return rune(0x226d), true + return {'\u226d', 0}, 1, true case "NotDoubleVerticalBar": // NOT PARALLEL TO - return rune(0x2226), true + return {'\u2226', 0}, 1, true case "NotElement": // NOT AN ELEMENT OF - return rune(0x2209), true + return {'\u2209', 0}, 1, true case "NotEqual": // NOT EQUAL TO - return rune(0x2260), true + return {'\u2260', 0}, 1, true case "NotEqualTilde": // MINUS TILDE with slash - return rune(0x2242), true + return {'\u2242', '\u0338'}, 2, true case "NotExists": // THERE DOES NOT EXIST - return rune(0x2204), true + return {'\u2204', 0}, 1, true case "NotGreater": // NOT GREATER-THAN - return rune(0x226f), true + return {'\u226f', 0}, 1, true case "NotGreaterEqual": // NEITHER GREATER-THAN NOR EQUAL TO - return rune(0x2271), true + return {'\u2271', 0}, 1, true case "NotGreaterFullEqual": // GREATER-THAN OVER EQUAL TO with slash - return rune(0x2267), true + return {'\u2267', '\u0338'}, 2, true case "NotGreaterGreater": // MUCH GREATER THAN with slash - return rune(0x226b), true + return {'\u226b', '\u0338'}, 2, true case "NotGreaterLess": // NEITHER GREATER-THAN NOR LESS-THAN - return rune(0x2279), true + return {'\u2279', 0}, 1, true case "NotGreaterSlantEqual": // GREATER-THAN OR SLANTED EQUAL TO with slash - return rune(0x2a7e), true + return {'\u2a7e', '\u0338'}, 2, true case "NotGreaterTilde": // NEITHER GREATER-THAN NOR EQUIVALENT TO - return rune(0x2275), true + return {'\u2275', 0}, 1, true case "NotHumpDownHump": // GEOMETRICALLY EQUIVALENT TO with slash - return rune(0x224e), true + return {'\u224e', '\u0338'}, 2, true case "NotHumpEqual": // DIFFERENCE BETWEEN with slash - return rune(0x224f), true + return {'\u224f', '\u0338'}, 2, true case "NotLeftTriangle": // NOT NORMAL SUBGROUP OF - return rune(0x22ea), true + return {'\u22ea', 0}, 1, true case "NotLeftTriangleBar": // LEFT TRIANGLE BESIDE VERTICAL BAR with slash - return rune(0x29cf), true + return {'\u29cf', '\u0338'}, 2, true case "NotLeftTriangleEqual": // NOT NORMAL SUBGROUP OF OR EQUAL TO - return rune(0x22ec), true + return {'\u22ec', 0}, 1, true case "NotLess": // NOT LESS-THAN - return rune(0x226e), true + return {'\u226e', 0}, 1, true case "NotLessEqual": // NEITHER LESS-THAN NOR EQUAL TO - return rune(0x2270), true + return {'\u2270', 0}, 1, true case "NotLessGreater": // NEITHER LESS-THAN NOR GREATER-THAN - return rune(0x2278), true + return {'\u2278', 0}, 1, true case "NotLessLess": // MUCH LESS THAN with slash - return rune(0x226a), true + return {'\u226a', '\u0338'}, 2, true case "NotLessSlantEqual": // LESS-THAN OR SLANTED EQUAL TO with slash - return rune(0x2a7d), true + return {'\u2a7d', '\u0338'}, 2, true case "NotLessTilde": // NEITHER LESS-THAN NOR EQUIVALENT TO - return rune(0x2274), true + return {'\u2274', 0}, 1, true case "NotNestedGreaterGreater": // DOUBLE NESTED GREATER-THAN with slash - return rune(0x2aa2), true + return {'\u2aa2', '\u0338'}, 2, true case "NotNestedLessLess": // DOUBLE NESTED LESS-THAN with slash - return rune(0x2aa1), true + return {'\u2aa1', '\u0338'}, 2, true case "NotPrecedes": // DOES NOT PRECEDE - return rune(0x2280), true + return {'\u2280', 0}, 1, true case "NotPrecedesEqual": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash - return rune(0x2aaf), true + return {'\u2aaf', '\u0338'}, 2, true case "NotPrecedesSlantEqual": // DOES NOT PRECEDE OR EQUAL - return rune(0x22e0), true + return {'\u22e0', 0}, 1, true case "NotReverseElement": // DOES NOT CONTAIN AS MEMBER - return rune(0x220c), true + return {'\u220c', 0}, 1, true case "NotRightTriangle": // DOES NOT CONTAIN AS NORMAL SUBGROUP - return rune(0x22eb), true + return {'\u22eb', 0}, 1, true case "NotRightTriangleBar": // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash - return rune(0x29d0), true + return {'\u29d0', '\u0338'}, 2, true case "NotRightTriangleEqual": // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL - return rune(0x22ed), true + return {'\u22ed', 0}, 1, true case "NotSquareSubset": // SQUARE IMAGE OF with slash - return rune(0x228f), true + return {'\u228f', '\u0338'}, 2, true case "NotSquareSubsetEqual": // NOT SQUARE IMAGE OF OR EQUAL TO - return rune(0x22e2), true + return {'\u22e2', 0}, 1, true case "NotSquareSuperset": // SQUARE ORIGINAL OF with slash - return rune(0x2290), true + return {'\u2290', '\u0338'}, 2, true case "NotSquareSupersetEqual": // NOT SQUARE ORIGINAL OF OR EQUAL TO - return rune(0x22e3), true + return {'\u22e3', 0}, 1, true case "NotSubset": // SUBSET OF with vertical line - return rune(0x2282), true + return {'\u2282', '\u20d2'}, 2, true case "NotSubsetEqual": // NEITHER A SUBSET OF NOR EQUAL TO - return rune(0x2288), true + return {'\u2288', 0}, 1, true case "NotSucceeds": // DOES NOT SUCCEED - return rune(0x2281), true + return {'\u2281', 0}, 1, true case "NotSucceedsEqual": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash - return rune(0x2ab0), true + return {'\u2ab0', '\u0338'}, 2, true case "NotSucceedsSlantEqual": // DOES NOT SUCCEED OR EQUAL - return rune(0x22e1), true + return {'\u22e1', 0}, 1, true case "NotSucceedsTilde": // SUCCEEDS OR EQUIVALENT TO with slash - return rune(0x227f), true + return {'\u227f', '\u0338'}, 2, true case "NotSuperset": // SUPERSET OF with vertical line - return rune(0x2283), true + return {'\u2283', '\u20d2'}, 2, true case "NotSupersetEqual": // NEITHER A SUPERSET OF NOR EQUAL TO - return rune(0x2289), true + return {'\u2289', 0}, 1, true case "NotTilde": // NOT TILDE - return rune(0x2241), true + return {'\u2241', 0}, 1, true case "NotTildeEqual": // NOT ASYMPTOTICALLY EQUAL TO - return rune(0x2244), true + return {'\u2244', 0}, 1, true case "NotTildeFullEqual": // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO - return rune(0x2247), true + return {'\u2247', 0}, 1, true case "NotTildeTilde": // NOT ALMOST EQUAL TO - return rune(0x2249), true + return {'\u2249', 0}, 1, true case "NotVerticalBar": // DOES NOT DIVIDE - return rune(0x2224), true + return {'\u2224', 0}, 1, true case "Nscr": // MATHEMATICAL SCRIPT CAPITAL N - return rune(0x01d4a9), true + return {'\U0001d4a9', 0}, 1, true case "Ntilde": // LATIN CAPITAL LETTER N WITH TILDE - return rune(0xd1), true + return {'Ñ', 0}, 1, true case "Nu": // GREEK CAPITAL LETTER NU - return rune(0x039d), true + return {'\u039d', 0}, 1, true } case 'O': switch name { case "OElig": // LATIN CAPITAL LIGATURE OE - return rune(0x0152), true + return {'\u0152', 0}, 1, true case "OHacgr": // GREEK CAPITAL LETTER OMEGA WITH TONOS - return rune(0x038f), true + return {'\u038f', 0}, 1, true case "OHgr": // GREEK CAPITAL LETTER OMEGA - return rune(0x03a9), true + return {'\u03a9', 0}, 1, true case "Oacgr": // GREEK CAPITAL LETTER OMICRON WITH TONOS - return rune(0x038c), true + return {'\u038c', 0}, 1, true case "Oacute": // LATIN CAPITAL LETTER O WITH ACUTE - return rune(0xd3), true + return {'Ó', 0}, 1, true case "Ocirc": // LATIN CAPITAL LETTER O WITH CIRCUMFLEX - return rune(0xd4), true + return {'Ô', 0}, 1, true case "Ocy": // CYRILLIC CAPITAL LETTER O - return rune(0x041e), true + return {'\u041e', 0}, 1, true case "Odblac": // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE - return rune(0x0150), true + return {'\u0150', 0}, 1, true case "Ofr": // MATHEMATICAL FRAKTUR CAPITAL O - return rune(0x01d512), true + return {'\U0001d512', 0}, 1, true case "Ogr": // GREEK CAPITAL LETTER OMICRON - return rune(0x039f), true + return {'\u039f', 0}, 1, true case "Ograve": // LATIN CAPITAL LETTER O WITH GRAVE - return rune(0xd2), true + return {'Ò', 0}, 1, true case "Omacr": // LATIN CAPITAL LETTER O WITH MACRON - return rune(0x014c), true + return {'\u014c', 0}, 1, true case "Omega": // GREEK CAPITAL LETTER OMEGA - return rune(0x03a9), true + return {'\u03a9', 0}, 1, true case "Omicron": // GREEK CAPITAL LETTER OMICRON - return rune(0x039f), true + return {'\u039f', 0}, 1, true case "Oopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL O - return rune(0x01d546), true + return {'\U0001d546', 0}, 1, true case "OpenCurlyDoubleQuote": // LEFT DOUBLE QUOTATION MARK - return rune(0x201c), true + return {'\u201c', 0}, 1, true case "OpenCurlyQuote": // LEFT SINGLE QUOTATION MARK - return rune(0x2018), true + return {'\u2018', 0}, 1, true case "Or": // DOUBLE LOGICAL OR - return rune(0x2a54), true + return {'\u2a54', 0}, 1, true case "Oscr": // MATHEMATICAL SCRIPT CAPITAL O - return rune(0x01d4aa), true + return {'\U0001d4aa', 0}, 1, true case "Oslash": // LATIN CAPITAL LETTER O WITH STROKE - return rune(0xd8), true + return {'Ø', 0}, 1, true case "Otilde": // LATIN CAPITAL LETTER O WITH TILDE - return rune(0xd5), true + return {'Õ', 0}, 1, true case "Otimes": // MULTIPLICATION SIGN IN DOUBLE CIRCLE - return rune(0x2a37), true + return {'\u2a37', 0}, 1, true case "Ouml": // LATIN CAPITAL LETTER O WITH DIAERESIS - return rune(0xd6), true + return {'Ö', 0}, 1, true case "OverBar": // OVERLINE - return rune(0x203e), true + return {'\u203e', 0}, 1, true case "OverBrace": // TOP CURLY BRACKET - return rune(0x23de), true + return {'\u23de', 0}, 1, true case "OverBracket": // TOP SQUARE BRACKET - return rune(0x23b4), true + return {'\u23b4', 0}, 1, true case "OverParenthesis": // TOP PARENTHESIS - return rune(0x23dc), true + return {'\u23dc', 0}, 1, true } case 'P': switch name { case "PHgr": // GREEK CAPITAL LETTER PHI - return rune(0x03a6), true + return {'\u03a6', 0}, 1, true case "PSgr": // GREEK CAPITAL LETTER PSI - return rune(0x03a8), true + return {'\u03a8', 0}, 1, true case "PartialD": // PARTIAL DIFFERENTIAL - return rune(0x2202), true + return {'\u2202', 0}, 1, true case "Pcy": // CYRILLIC CAPITAL LETTER PE - return rune(0x041f), true + return {'\u041f', 0}, 1, true case "Pfr": // MATHEMATICAL FRAKTUR CAPITAL P - return rune(0x01d513), true + return {'\U0001d513', 0}, 1, true case "Pgr": // GREEK CAPITAL LETTER PI - return rune(0x03a0), true + return {'\u03a0', 0}, 1, true case "Phi": // GREEK CAPITAL LETTER PHI - return rune(0x03a6), true + return {'\u03a6', 0}, 1, true case "Pi": // GREEK CAPITAL LETTER PI - return rune(0x03a0), true + return {'\u03a0', 0}, 1, true case "PlusMinus": // PLUS-MINUS SIGN - return rune(0xb1), true + return {'±', 0}, 1, true case "Poincareplane": // BLACK-LETTER CAPITAL H - return rune(0x210c), true + return {'\u210c', 0}, 1, true case "Popf": // DOUBLE-STRUCK CAPITAL P - return rune(0x2119), true + return {'\u2119', 0}, 1, true case "Pr": // DOUBLE PRECEDES - return rune(0x2abb), true + return {'\u2abb', 0}, 1, true case "Precedes": // PRECEDES - return rune(0x227a), true + return {'\u227a', 0}, 1, true case "PrecedesEqual": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN - return rune(0x2aaf), true + return {'\u2aaf', 0}, 1, true case "PrecedesSlantEqual": // PRECEDES OR EQUAL TO - return rune(0x227c), true + return {'\u227c', 0}, 1, true case "PrecedesTilde": // PRECEDES OR EQUIVALENT TO - return rune(0x227e), true + return {'\u227e', 0}, 1, true case "Prime": // DOUBLE PRIME - return rune(0x2033), true + return {'\u2033', 0}, 1, true case "Product": // N-ARY PRODUCT - return rune(0x220f), true + return {'\u220f', 0}, 1, true case "Proportion": // PROPORTION - return rune(0x2237), true + return {'\u2237', 0}, 1, true case "Proportional": // PROPORTIONAL TO - return rune(0x221d), true + return {'\u221d', 0}, 1, true case "Pscr": // MATHEMATICAL SCRIPT CAPITAL P - return rune(0x01d4ab), true + return {'\U0001d4ab', 0}, 1, true case "Psi": // GREEK CAPITAL LETTER PSI - return rune(0x03a8), true + return {'\u03a8', 0}, 1, true } case 'Q': switch name { case "QUOT": // QUOTATION MARK - return rune(0x22), true + return {'"', 0}, 1, true case "Qfr": // MATHEMATICAL FRAKTUR CAPITAL Q - return rune(0x01d514), true + return {'\U0001d514', 0}, 1, true case "Qopf": // DOUBLE-STRUCK CAPITAL Q - return rune(0x211a), true + return {'\u211a', 0}, 1, true case "Qscr": // MATHEMATICAL SCRIPT CAPITAL Q - return rune(0x01d4ac), true + return {'\U0001d4ac', 0}, 1, true } case 'R': switch name { case "RBarr": // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW - return rune(0x2910), true + return {'\u2910', 0}, 1, true case "REG": // REGISTERED SIGN - return rune(0xae), true + return {'®', 0}, 1, true case "Racute": // LATIN CAPITAL LETTER R WITH ACUTE - return rune(0x0154), true + return {'\u0154', 0}, 1, true case "Rang": // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET - return rune(0x27eb), true + return {'\u27eb', 0}, 1, true case "Rarr": // RIGHTWARDS TWO HEADED ARROW - return rune(0x21a0), true + return {'\u21a0', 0}, 1, true case "Rarrtl": // RIGHTWARDS TWO-HEADED ARROW WITH TAIL - return rune(0x2916), true + return {'\u2916', 0}, 1, true case "Rcaron": // LATIN CAPITAL LETTER R WITH CARON - return rune(0x0158), true + return {'\u0158', 0}, 1, true case "Rcedil": // LATIN CAPITAL LETTER R WITH CEDILLA - return rune(0x0156), true + return {'\u0156', 0}, 1, true case "Rcy": // CYRILLIC CAPITAL LETTER ER - return rune(0x0420), true + return {'\u0420', 0}, 1, true case "Re": // BLACK-LETTER CAPITAL R - return rune(0x211c), true + return {'\u211c', 0}, 1, true case "ReverseElement": // CONTAINS AS MEMBER - return rune(0x220b), true + return {'\u220b', 0}, 1, true case "ReverseEquilibrium": // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON - return rune(0x21cb), true + return {'\u21cb', 0}, 1, true case "ReverseUpEquilibrium": // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT - return rune(0x296f), true + return {'\u296f', 0}, 1, true case "Rfr": // BLACK-LETTER CAPITAL R - return rune(0x211c), true + return {'\u211c', 0}, 1, true case "Rgr": // GREEK CAPITAL LETTER RHO - return rune(0x03a1), true + return {'\u03a1', 0}, 1, true case "Rho": // GREEK CAPITAL LETTER RHO - return rune(0x03a1), true + return {'\u03a1', 0}, 1, true case "RightAngleBracket": // MATHEMATICAL RIGHT ANGLE BRACKET - return rune(0x27e9), true + return {'\u27e9', 0}, 1, true case "RightArrow": // RIGHTWARDS ARROW - return rune(0x2192), true + return {'\u2192', 0}, 1, true case "RightArrowBar": // RIGHTWARDS ARROW TO BAR - return rune(0x21e5), true + return {'\u21e5', 0}, 1, true case "RightArrowLeftArrow": // RIGHTWARDS ARROW OVER LEFTWARDS ARROW - return rune(0x21c4), true + return {'\u21c4', 0}, 1, true case "RightCeiling": // RIGHT CEILING - return rune(0x2309), true + return {'\u2309', 0}, 1, true case "RightDoubleBracket": // MATHEMATICAL RIGHT WHITE SQUARE BRACKET - return rune(0x27e7), true + return {'\u27e7', 0}, 1, true case "RightDownTeeVector": // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR - return rune(0x295d), true + return {'\u295d', 0}, 1, true case "RightDownVector": // DOWNWARDS HARPOON WITH BARB RIGHTWARDS - return rune(0x21c2), true + return {'\u21c2', 0}, 1, true case "RightDownVectorBar": // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR - return rune(0x2955), true + return {'\u2955', 0}, 1, true case "RightFloor": // RIGHT FLOOR - return rune(0x230b), true + return {'\u230b', 0}, 1, true case "RightTee": // RIGHT TACK - return rune(0x22a2), true + return {'\u22a2', 0}, 1, true case "RightTeeArrow": // RIGHTWARDS ARROW FROM BAR - return rune(0x21a6), true + return {'\u21a6', 0}, 1, true case "RightTeeVector": // RIGHTWARDS HARPOON WITH BARB UP FROM BAR - return rune(0x295b), true + return {'\u295b', 0}, 1, true case "RightTriangle": // CONTAINS AS NORMAL SUBGROUP - return rune(0x22b3), true + return {'\u22b3', 0}, 1, true case "RightTriangleBar": // VERTICAL BAR BESIDE RIGHT TRIANGLE - return rune(0x29d0), true + return {'\u29d0', 0}, 1, true case "RightTriangleEqual": // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO - return rune(0x22b5), true + return {'\u22b5', 0}, 1, true case "RightUpDownVector": // UP BARB RIGHT DOWN BARB RIGHT HARPOON - return rune(0x294f), true + return {'\u294f', 0}, 1, true case "RightUpTeeVector": // UPWARDS HARPOON WITH BARB RIGHT FROM BAR - return rune(0x295c), true + return {'\u295c', 0}, 1, true case "RightUpVector": // UPWARDS HARPOON WITH BARB RIGHTWARDS - return rune(0x21be), true + return {'\u21be', 0}, 1, true case "RightUpVectorBar": // UPWARDS HARPOON WITH BARB RIGHT TO BAR - return rune(0x2954), true + return {'\u2954', 0}, 1, true case "RightVector": // RIGHTWARDS HARPOON WITH BARB UPWARDS - return rune(0x21c0), true + return {'\u21c0', 0}, 1, true case "RightVectorBar": // RIGHTWARDS HARPOON WITH BARB UP TO BAR - return rune(0x2953), true + return {'\u2953', 0}, 1, true case "Rightarrow": // RIGHTWARDS DOUBLE ARROW - return rune(0x21d2), true + return {'\u21d2', 0}, 1, true case "Ropf": // DOUBLE-STRUCK CAPITAL R - return rune(0x211d), true + return {'\u211d', 0}, 1, true case "RoundImplies": // RIGHT DOUBLE ARROW WITH ROUNDED HEAD - return rune(0x2970), true + return {'\u2970', 0}, 1, true case "Rrightarrow": // RIGHTWARDS TRIPLE ARROW - return rune(0x21db), true + return {'\u21db', 0}, 1, true case "Rscr": // SCRIPT CAPITAL R - return rune(0x211b), true + return {'\u211b', 0}, 1, true case "Rsh": // UPWARDS ARROW WITH TIP RIGHTWARDS - return rune(0x21b1), true + return {'\u21b1', 0}, 1, true case "RuleDelayed": // RULE-DELAYED - return rune(0x29f4), true + return {'\u29f4', 0}, 1, true } case 'S': switch name { case "SHCHcy": // CYRILLIC CAPITAL LETTER SHCHA - return rune(0x0429), true + return {'\u0429', 0}, 1, true case "SHcy": // CYRILLIC CAPITAL LETTER SHA - return rune(0x0428), true + return {'\u0428', 0}, 1, true case "SOFTcy": // CYRILLIC CAPITAL LETTER SOFT SIGN - return rune(0x042c), true + return {'\u042c', 0}, 1, true case "Sacute": // LATIN CAPITAL LETTER S WITH ACUTE - return rune(0x015a), true + return {'\u015a', 0}, 1, true case "Sc": // DOUBLE SUCCEEDS - return rune(0x2abc), true + return {'\u2abc', 0}, 1, true case "Scaron": // LATIN CAPITAL LETTER S WITH CARON - return rune(0x0160), true + return {'\u0160', 0}, 1, true case "Scedil": // LATIN CAPITAL LETTER S WITH CEDILLA - return rune(0x015e), true + return {'\u015e', 0}, 1, true case "Scirc": // LATIN CAPITAL LETTER S WITH CIRCUMFLEX - return rune(0x015c), true + return {'\u015c', 0}, 1, true case "Scy": // CYRILLIC CAPITAL LETTER ES - return rune(0x0421), true + return {'\u0421', 0}, 1, true case "Sfr": // MATHEMATICAL FRAKTUR CAPITAL S - return rune(0x01d516), true + return {'\U0001d516', 0}, 1, true case "Sgr": // GREEK CAPITAL LETTER SIGMA - return rune(0x03a3), true + return {'\u03a3', 0}, 1, true case "ShortDownArrow": // DOWNWARDS ARROW - return rune(0x2193), true + return {'\u2193', 0}, 1, true case "ShortLeftArrow": // LEFTWARDS ARROW - return rune(0x2190), true + return {'\u2190', 0}, 1, true case "ShortRightArrow": // RIGHTWARDS ARROW - return rune(0x2192), true + return {'\u2192', 0}, 1, true case "ShortUpArrow": // UPWARDS ARROW - return rune(0x2191), true + return {'\u2191', 0}, 1, true case "Sigma": // GREEK CAPITAL LETTER SIGMA - return rune(0x03a3), true + return {'\u03a3', 0}, 1, true case "SmallCircle": // RING OPERATOR - return rune(0x2218), true + return {'\u2218', 0}, 1, true case "Sopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL S - return rune(0x01d54a), true + return {'\U0001d54a', 0}, 1, true case "Sqrt": // SQUARE ROOT - return rune(0x221a), true + return {'\u221a', 0}, 1, true case "Square": // WHITE SQUARE - return rune(0x25a1), true + return {'\u25a1', 0}, 1, true case "SquareIntersection": // SQUARE CAP - return rune(0x2293), true + return {'\u2293', 0}, 1, true case "SquareSubset": // SQUARE IMAGE OF - return rune(0x228f), true + return {'\u228f', 0}, 1, true case "SquareSubsetEqual": // SQUARE IMAGE OF OR EQUAL TO - return rune(0x2291), true + return {'\u2291', 0}, 1, true case "SquareSuperset": // SQUARE ORIGINAL OF - return rune(0x2290), true + return {'\u2290', 0}, 1, true case "SquareSupersetEqual": // SQUARE ORIGINAL OF OR EQUAL TO - return rune(0x2292), true + return {'\u2292', 0}, 1, true case "SquareUnion": // SQUARE CUP - return rune(0x2294), true + return {'\u2294', 0}, 1, true case "Sscr": // MATHEMATICAL SCRIPT CAPITAL S - return rune(0x01d4ae), true + return {'\U0001d4ae', 0}, 1, true case "Star": // STAR OPERATOR - return rune(0x22c6), true + return {'\u22c6', 0}, 1, true case "Sub": // DOUBLE SUBSET - return rune(0x22d0), true + return {'\u22d0', 0}, 1, true case "Subset": // DOUBLE SUBSET - return rune(0x22d0), true + return {'\u22d0', 0}, 1, true case "SubsetEqual": // SUBSET OF OR EQUAL TO - return rune(0x2286), true + return {'\u2286', 0}, 1, true case "Succeeds": // SUCCEEDS - return rune(0x227b), true + return {'\u227b', 0}, 1, true case "SucceedsEqual": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN - return rune(0x2ab0), true + return {'\u2ab0', 0}, 1, true case "SucceedsSlantEqual": // SUCCEEDS OR EQUAL TO - return rune(0x227d), true + return {'\u227d', 0}, 1, true case "SucceedsTilde": // SUCCEEDS OR EQUIVALENT TO - return rune(0x227f), true + return {'\u227f', 0}, 1, true case "SuchThat": // CONTAINS AS MEMBER - return rune(0x220b), true + return {'\u220b', 0}, 1, true case "Sum": // N-ARY SUMMATION - return rune(0x2211), true + return {'\u2211', 0}, 1, true case "Sup": // DOUBLE SUPERSET - return rune(0x22d1), true + return {'\u22d1', 0}, 1, true case "Superset": // SUPERSET OF - return rune(0x2283), true + return {'\u2283', 0}, 1, true case "SupersetEqual": // SUPERSET OF OR EQUAL TO - return rune(0x2287), true + return {'\u2287', 0}, 1, true case "Supset": // DOUBLE SUPERSET - return rune(0x22d1), true + return {'\u22d1', 0}, 1, true } case 'T': switch name { case "THORN": // LATIN CAPITAL LETTER THORN - return rune(0xde), true + return {'Þ', 0}, 1, true case "THgr": // GREEK CAPITAL LETTER THETA - return rune(0x0398), true + return {'\u0398', 0}, 1, true case "TRADE": // TRADE MARK SIGN - return rune(0x2122), true + return {'\u2122', 0}, 1, true case "TSHcy": // CYRILLIC CAPITAL LETTER TSHE - return rune(0x040b), true + return {'\u040b', 0}, 1, true case "TScy": // CYRILLIC CAPITAL LETTER TSE - return rune(0x0426), true + return {'\u0426', 0}, 1, true case "Tab": // CHARACTER TABULATION - return rune(0x09), true + return {'\t', 0}, 1, true case "Tau": // GREEK CAPITAL LETTER TAU - return rune(0x03a4), true + return {'\u03a4', 0}, 1, true case "Tcaron": // LATIN CAPITAL LETTER T WITH CARON - return rune(0x0164), true + return {'\u0164', 0}, 1, true case "Tcedil": // LATIN CAPITAL LETTER T WITH CEDILLA - return rune(0x0162), true + return {'\u0162', 0}, 1, true case "Tcy": // CYRILLIC CAPITAL LETTER TE - return rune(0x0422), true + return {'\u0422', 0}, 1, true case "Tfr": // MATHEMATICAL FRAKTUR CAPITAL T - return rune(0x01d517), true + return {'\U0001d517', 0}, 1, true case "Tgr": // GREEK CAPITAL LETTER TAU - return rune(0x03a4), true + return {'\u03a4', 0}, 1, true case "Therefore": // THEREFORE - return rune(0x2234), true + return {'\u2234', 0}, 1, true case "Theta": // GREEK CAPITAL LETTER THETA - return rune(0x0398), true + return {'\u0398', 0}, 1, true case "Thetav": // GREEK CAPITAL THETA SYMBOL - return rune(0x03f4), true + return {'\u03f4', 0}, 1, true case "ThickSpace": // space of width 5/18 em - return rune(0x205f), true + return {'\u205f', '\u200a'}, 2, true case "ThinSpace": // THIN SPACE - return rune(0x2009), true + return {'\u2009', 0}, 1, true case "Tilde": // TILDE OPERATOR - return rune(0x223c), true + return {'\u223c', 0}, 1, true case "TildeEqual": // ASYMPTOTICALLY EQUAL TO - return rune(0x2243), true + return {'\u2243', 0}, 1, true case "TildeFullEqual": // APPROXIMATELY EQUAL TO - return rune(0x2245), true + return {'\u2245', 0}, 1, true case "TildeTilde": // ALMOST EQUAL TO - return rune(0x2248), true + return {'\u2248', 0}, 1, true case "Topf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL T - return rune(0x01d54b), true + return {'\U0001d54b', 0}, 1, true case "TripleDot": // COMBINING THREE DOTS ABOVE - return rune(0x20db), true + return {'\u20db', 0}, 1, true case "Tscr": // MATHEMATICAL SCRIPT CAPITAL T - return rune(0x01d4af), true + return {'\U0001d4af', 0}, 1, true case "Tstrok": // LATIN CAPITAL LETTER T WITH STROKE - return rune(0x0166), true + return {'\u0166', 0}, 1, true } case 'U': switch name { case "Uacgr": // GREEK CAPITAL LETTER UPSILON WITH TONOS - return rune(0x038e), true + return {'\u038e', 0}, 1, true case "Uacute": // LATIN CAPITAL LETTER U WITH ACUTE - return rune(0xda), true + return {'Ú', 0}, 1, true case "Uarr": // UPWARDS TWO HEADED ARROW - return rune(0x219f), true + return {'\u219f', 0}, 1, true case "Uarrocir": // UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE - return rune(0x2949), true + return {'\u2949', 0}, 1, true case "Ubrcy": // CYRILLIC CAPITAL LETTER SHORT U - return rune(0x040e), true + return {'\u040e', 0}, 1, true case "Ubreve": // LATIN CAPITAL LETTER U WITH BREVE - return rune(0x016c), true + return {'\u016c', 0}, 1, true case "Ucirc": // LATIN CAPITAL LETTER U WITH CIRCUMFLEX - return rune(0xdb), true + return {'Û', 0}, 1, true case "Ucy": // CYRILLIC CAPITAL LETTER U - return rune(0x0423), true + return {'\u0423', 0}, 1, true case "Udblac": // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE - return rune(0x0170), true + return {'\u0170', 0}, 1, true case "Udigr": // GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA - return rune(0x03ab), true + return {'\u03ab', 0}, 1, true case "Ufr": // MATHEMATICAL FRAKTUR CAPITAL U - return rune(0x01d518), true + return {'\U0001d518', 0}, 1, true case "Ugr": // GREEK CAPITAL LETTER UPSILON - return rune(0x03a5), true + return {'\u03a5', 0}, 1, true case "Ugrave": // LATIN CAPITAL LETTER U WITH GRAVE - return rune(0xd9), true + return {'Ù', 0}, 1, true case "Umacr": // LATIN CAPITAL LETTER U WITH MACRON - return rune(0x016a), true + return {'\u016a', 0}, 1, true case "UnderBar": // LOW LINE - return rune(0x5f), true + return {'_', 0}, 1, true case "UnderBrace": // BOTTOM CURLY BRACKET - return rune(0x23df), true + return {'\u23df', 0}, 1, true case "UnderBracket": // BOTTOM SQUARE BRACKET - return rune(0x23b5), true + return {'\u23b5', 0}, 1, true case "UnderParenthesis": // BOTTOM PARENTHESIS - return rune(0x23dd), true + return {'\u23dd', 0}, 1, true case "Union": // N-ARY UNION - return rune(0x22c3), true + return {'\u22c3', 0}, 1, true case "UnionPlus": // MULTISET UNION - return rune(0x228e), true + return {'\u228e', 0}, 1, true case "Uogon": // LATIN CAPITAL LETTER U WITH OGONEK - return rune(0x0172), true + return {'\u0172', 0}, 1, true case "Uopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL U - return rune(0x01d54c), true + return {'\U0001d54c', 0}, 1, true case "UpArrow": // UPWARDS ARROW - return rune(0x2191), true + return {'\u2191', 0}, 1, true case "UpArrowBar": // UPWARDS ARROW TO BAR - return rune(0x2912), true + return {'\u2912', 0}, 1, true case "UpArrowDownArrow": // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW - return rune(0x21c5), true + return {'\u21c5', 0}, 1, true case "UpDownArrow": // UP DOWN ARROW - return rune(0x2195), true + return {'\u2195', 0}, 1, true case "UpEquilibrium": // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT - return rune(0x296e), true + return {'\u296e', 0}, 1, true case "UpTee": // UP TACK - return rune(0x22a5), true + return {'\u22a5', 0}, 1, true case "UpTeeArrow": // UPWARDS ARROW FROM BAR - return rune(0x21a5), true + return {'\u21a5', 0}, 1, true case "Uparrow": // UPWARDS DOUBLE ARROW - return rune(0x21d1), true + return {'\u21d1', 0}, 1, true case "Updownarrow": // UP DOWN DOUBLE ARROW - return rune(0x21d5), true + return {'\u21d5', 0}, 1, true case "UpperLeftArrow": // NORTH WEST ARROW - return rune(0x2196), true + return {'\u2196', 0}, 1, true case "UpperRightArrow": // NORTH EAST ARROW - return rune(0x2197), true + return {'\u2197', 0}, 1, true case "Upsi": // GREEK UPSILON WITH HOOK SYMBOL - return rune(0x03d2), true + return {'\u03d2', 0}, 1, true case "Upsilon": // GREEK CAPITAL LETTER UPSILON - return rune(0x03a5), true + return {'\u03a5', 0}, 1, true case "Uring": // LATIN CAPITAL LETTER U WITH RING ABOVE - return rune(0x016e), true + return {'\u016e', 0}, 1, true case "Uscr": // MATHEMATICAL SCRIPT CAPITAL U - return rune(0x01d4b0), true + return {'\U0001d4b0', 0}, 1, true case "Utilde": // LATIN CAPITAL LETTER U WITH TILDE - return rune(0x0168), true + return {'\u0168', 0}, 1, true case "Uuml": // LATIN CAPITAL LETTER U WITH DIAERESIS - return rune(0xdc), true + return {'Ü', 0}, 1, true } case 'V': switch name { case "VDash": // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE - return rune(0x22ab), true + return {'\u22ab', 0}, 1, true case "Vbar": // DOUBLE UP TACK - return rune(0x2aeb), true + return {'\u2aeb', 0}, 1, true case "Vcy": // CYRILLIC CAPITAL LETTER VE - return rune(0x0412), true + return {'\u0412', 0}, 1, true case "Vdash": // FORCES - return rune(0x22a9), true + return {'\u22a9', 0}, 1, true case "Vdashl": // LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL - return rune(0x2ae6), true + return {'\u2ae6', 0}, 1, true case "Vee": // N-ARY LOGICAL OR - return rune(0x22c1), true + return {'\u22c1', 0}, 1, true case "Verbar": // DOUBLE VERTICAL LINE - return rune(0x2016), true + return {'\u2016', 0}, 1, true case "Vert": // DOUBLE VERTICAL LINE - return rune(0x2016), true + return {'\u2016', 0}, 1, true case "VerticalBar": // DIVIDES - return rune(0x2223), true + return {'\u2223', 0}, 1, true case "VerticalLine": // VERTICAL LINE - return rune(0x7c), true + return {'|', 0}, 1, true case "VerticalSeparator": // LIGHT VERTICAL BAR - return rune(0x2758), true + return {'\u2758', 0}, 1, true case "VerticalTilde": // WREATH PRODUCT - return rune(0x2240), true + return {'\u2240', 0}, 1, true case "VeryThinSpace": // HAIR SPACE - return rune(0x200a), true + return {'\u200a', 0}, 1, true case "Vfr": // MATHEMATICAL FRAKTUR CAPITAL V - return rune(0x01d519), true + return {'\U0001d519', 0}, 1, true case "Vopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL V - return rune(0x01d54d), true + return {'\U0001d54d', 0}, 1, true case "Vscr": // MATHEMATICAL SCRIPT CAPITAL V - return rune(0x01d4b1), true + return {'\U0001d4b1', 0}, 1, true case "Vvdash": // TRIPLE VERTICAL BAR RIGHT TURNSTILE - return rune(0x22aa), true + return {'\u22aa', 0}, 1, true } case 'W': switch name { case "Wcirc": // LATIN CAPITAL LETTER W WITH CIRCUMFLEX - return rune(0x0174), true + return {'\u0174', 0}, 1, true case "Wedge": // N-ARY LOGICAL AND - return rune(0x22c0), true + return {'\u22c0', 0}, 1, true case "Wfr": // MATHEMATICAL FRAKTUR CAPITAL W - return rune(0x01d51a), true + return {'\U0001d51a', 0}, 1, true case "Wopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL W - return rune(0x01d54e), true + return {'\U0001d54e', 0}, 1, true case "Wscr": // MATHEMATICAL SCRIPT CAPITAL W - return rune(0x01d4b2), true + return {'\U0001d4b2', 0}, 1, true } case 'X': switch name { case "Xfr": // MATHEMATICAL FRAKTUR CAPITAL X - return rune(0x01d51b), true + return {'\U0001d51b', 0}, 1, true case "Xgr": // GREEK CAPITAL LETTER XI - return rune(0x039e), true + return {'\u039e', 0}, 1, true case "Xi": // GREEK CAPITAL LETTER XI - return rune(0x039e), true + return {'\u039e', 0}, 1, true case "Xopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL X - return rune(0x01d54f), true + return {'\U0001d54f', 0}, 1, true case "Xscr": // MATHEMATICAL SCRIPT CAPITAL X - return rune(0x01d4b3), true + return {'\U0001d4b3', 0}, 1, true } case 'Y': switch name { case "YAcy": // CYRILLIC CAPITAL LETTER YA - return rune(0x042f), true + return {'\u042f', 0}, 1, true case "YIcy": // CYRILLIC CAPITAL LETTER YI - return rune(0x0407), true + return {'\u0407', 0}, 1, true case "YUcy": // CYRILLIC CAPITAL LETTER YU - return rune(0x042e), true + return {'\u042e', 0}, 1, true case "Yacute": // LATIN CAPITAL LETTER Y WITH ACUTE - return rune(0xdd), true + return {'Ý', 0}, 1, true case "Ycirc": // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX - return rune(0x0176), true + return {'\u0176', 0}, 1, true case "Ycy": // CYRILLIC CAPITAL LETTER YERU - return rune(0x042b), true + return {'\u042b', 0}, 1, true case "Yfr": // MATHEMATICAL FRAKTUR CAPITAL Y - return rune(0x01d51c), true + return {'\U0001d51c', 0}, 1, true case "Yopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL Y - return rune(0x01d550), true + return {'\U0001d550', 0}, 1, true case "Yscr": // MATHEMATICAL SCRIPT CAPITAL Y - return rune(0x01d4b4), true + return {'\U0001d4b4', 0}, 1, true case "Yuml": // LATIN CAPITAL LETTER Y WITH DIAERESIS - return rune(0x0178), true + return {'\u0178', 0}, 1, true } case 'Z': switch name { case "ZHcy": // CYRILLIC CAPITAL LETTER ZHE - return rune(0x0416), true + return {'\u0416', 0}, 1, true case "Zacute": // LATIN CAPITAL LETTER Z WITH ACUTE - return rune(0x0179), true + return {'\u0179', 0}, 1, true case "Zcaron": // LATIN CAPITAL LETTER Z WITH CARON - return rune(0x017d), true + return {'\u017d', 0}, 1, true case "Zcy": // CYRILLIC CAPITAL LETTER ZE - return rune(0x0417), true + return {'\u0417', 0}, 1, true case "Zdot": // LATIN CAPITAL LETTER Z WITH DOT ABOVE - return rune(0x017b), true + return {'\u017b', 0}, 1, true case "ZeroWidthSpace": // ZERO WIDTH SPACE - return rune(0x200b), true + return {'\u200b', 0}, 1, true case "Zeta": // GREEK CAPITAL LETTER ZETA - return rune(0x0396), true + return {'\u0396', 0}, 1, true case "Zfr": // BLACK-LETTER CAPITAL Z - return rune(0x2128), true + return {'\u2128', 0}, 1, true case "Zgr": // GREEK CAPITAL LETTER ZETA - return rune(0x0396), true + return {'\u0396', 0}, 1, true case "Zopf": // DOUBLE-STRUCK CAPITAL Z - return rune(0x2124), true + return {'\u2124', 0}, 1, true case "Zscr": // MATHEMATICAL SCRIPT CAPITAL Z - return rune(0x01d4b5), true + return {'\U0001d4b5', 0}, 1, true } case 'a': switch name { case "aacgr": // GREEK SMALL LETTER ALPHA WITH TONOS - return rune(0x03ac), true + return {'\u03ac', 0}, 1, true case "aacute": // LATIN SMALL LETTER A WITH ACUTE - return rune(0xe1), true + return {'á', 0}, 1, true case "abreve": // LATIN SMALL LETTER A WITH BREVE - return rune(0x0103), true + return {'\u0103', 0}, 1, true case "ac": // INVERTED LAZY S - return rune(0x223e), true + return {'\u223e', 0}, 1, true case "acE": // INVERTED LAZY S with double underline - return rune(0x223e), true + return {'\u223e', '\u0333'}, 2, true case "acd": // SINE WAVE - return rune(0x223f), true + return {'\u223f', 0}, 1, true case "acirc": // LATIN SMALL LETTER A WITH CIRCUMFLEX - return rune(0xe2), true + return {'â', 0}, 1, true case "actuary": // COMBINING ANNUITY SYMBOL - return rune(0x20e7), true + return {'\u20e7', 0}, 1, true case "acute": // ACUTE ACCENT - return rune(0xb4), true + return {'´', 0}, 1, true case "acy": // CYRILLIC SMALL LETTER A - return rune(0x0430), true + return {'\u0430', 0}, 1, true case "aelig": // LATIN SMALL LETTER AE - return rune(0xe6), true + return {'æ', 0}, 1, true case "af": // FUNCTION APPLICATION - return rune(0x2061), true + return {'\u2061', 0}, 1, true case "afr": // MATHEMATICAL FRAKTUR SMALL A - return rune(0x01d51e), true + return {'\U0001d51e', 0}, 1, true case "agr": // GREEK SMALL LETTER ALPHA - return rune(0x03b1), true + return {'\u03b1', 0}, 1, true case "agrave": // LATIN SMALL LETTER A WITH GRAVE - return rune(0xe0), true + return {'à', 0}, 1, true case "alefsym": // ALEF SYMBOL - return rune(0x2135), true + return {'\u2135', 0}, 1, true case "aleph": // ALEF SYMBOL - return rune(0x2135), true + return {'\u2135', 0}, 1, true case "alpha": // GREEK SMALL LETTER ALPHA - return rune(0x03b1), true + return {'\u03b1', 0}, 1, true case "amacr": // LATIN SMALL LETTER A WITH MACRON - return rune(0x0101), true + return {'\u0101', 0}, 1, true case "amalg": // AMALGAMATION OR COPRODUCT - return rune(0x2a3f), true + return {'\u2a3f', 0}, 1, true case "amp": // AMPERSAND - return rune(0x26), true + return {'&', 0}, 1, true case "and": // LOGICAL AND - return rune(0x2227), true + return {'\u2227', 0}, 1, true case "andand": // TWO INTERSECTING LOGICAL AND - return rune(0x2a55), true + return {'\u2a55', 0}, 1, true case "andd": // LOGICAL AND WITH HORIZONTAL DASH - return rune(0x2a5c), true + return {'\u2a5c', 0}, 1, true case "andslope": // SLOPING LARGE AND - return rune(0x2a58), true + return {'\u2a58', 0}, 1, true case "andv": // LOGICAL AND WITH MIDDLE STEM - return rune(0x2a5a), true + return {'\u2a5a', 0}, 1, true case "ang": // ANGLE - return rune(0x2220), true + return {'\u2220', 0}, 1, true case "ang90": // RIGHT ANGLE - return rune(0x221f), true + return {'\u221f', 0}, 1, true case "angdnl": // TURNED ANGLE - return rune(0x29a2), true + return {'\u29a2', 0}, 1, true case "angdnr": // ACUTE ANGLE - return rune(0x299f), true + return {'\u299f', 0}, 1, true case "ange": // ANGLE WITH UNDERBAR - return rune(0x29a4), true + return {'\u29a4', 0}, 1, true case "angle": // ANGLE - return rune(0x2220), true + return {'\u2220', 0}, 1, true case "angles": // ANGLE WITH S INSIDE - return rune(0x299e), true + return {'\u299e', 0}, 1, true case "angmsd": // MEASURED ANGLE - return rune(0x2221), true + return {'\u2221', 0}, 1, true case "angmsdaa": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT - return rune(0x29a8), true + return {'\u29a8', 0}, 1, true case "angmsdab": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT - return rune(0x29a9), true + return {'\u29a9', 0}, 1, true case "angmsdac": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT - return rune(0x29aa), true + return {'\u29aa', 0}, 1, true case "angmsdad": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT - return rune(0x29ab), true + return {'\u29ab', 0}, 1, true case "angmsdae": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP - return rune(0x29ac), true + return {'\u29ac', 0}, 1, true case "angmsdaf": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP - return rune(0x29ad), true + return {'\u29ad', 0}, 1, true case "angmsdag": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN - return rune(0x29ae), true + return {'\u29ae', 0}, 1, true case "angmsdah": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN - return rune(0x29af), true + return {'\u29af', 0}, 1, true case "angrt": // RIGHT ANGLE - return rune(0x221f), true + return {'\u221f', 0}, 1, true case "angrtvb": // RIGHT ANGLE WITH ARC - return rune(0x22be), true + return {'\u22be', 0}, 1, true case "angrtvbd": // MEASURED RIGHT ANGLE WITH DOT - return rune(0x299d), true + return {'\u299d', 0}, 1, true case "angsph": // SPHERICAL ANGLE - return rune(0x2222), true + return {'\u2222', 0}, 1, true case "angst": // LATIN CAPITAL LETTER A WITH RING ABOVE - return rune(0xc5), true + return {'Å', 0}, 1, true case "angupl": // REVERSED ANGLE - return rune(0x29a3), true + return {'\u29a3', 0}, 1, true case "angzarr": // RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW - return rune(0x237c), true + return {'\u237c', 0}, 1, true case "aogon": // LATIN SMALL LETTER A WITH OGONEK - return rune(0x0105), true + return {'\u0105', 0}, 1, true case "aopf": // MATHEMATICAL DOUBLE-STRUCK SMALL A - return rune(0x01d552), true + return {'\U0001d552', 0}, 1, true case "ap": // ALMOST EQUAL TO - return rune(0x2248), true + return {'\u2248', 0}, 1, true case "apE": // APPROXIMATELY EQUAL OR EQUAL TO - return rune(0x2a70), true + return {'\u2a70', 0}, 1, true case "apacir": // ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT - return rune(0x2a6f), true + return {'\u2a6f', 0}, 1, true case "ape": // ALMOST EQUAL OR EQUAL TO - return rune(0x224a), true + return {'\u224a', 0}, 1, true case "apid": // TRIPLE TILDE - return rune(0x224b), true + return {'\u224b', 0}, 1, true case "apos": // APOSTROPHE - return rune(0x27), true + return {'\'', 0}, 1, true case "approx": // ALMOST EQUAL TO - return rune(0x2248), true + return {'\u2248', 0}, 1, true case "approxeq": // ALMOST EQUAL OR EQUAL TO - return rune(0x224a), true + return {'\u224a', 0}, 1, true case "aring": // LATIN SMALL LETTER A WITH RING ABOVE - return rune(0xe5), true + return {'å', 0}, 1, true case "arrllsr": // LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW - return rune(0x2943), true + return {'\u2943', 0}, 1, true case "arrlrsl": // RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW - return rune(0x2942), true + return {'\u2942', 0}, 1, true case "arrsrll": // SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW - return rune(0x2944), true + return {'\u2944', 0}, 1, true case "ascr": // MATHEMATICAL SCRIPT SMALL A - return rune(0x01d4b6), true + return {'\U0001d4b6', 0}, 1, true case "ast": // ASTERISK - return rune(0x2a), true + return {'*', 0}, 1, true case "astb": // SQUARED ASTERISK - return rune(0x29c6), true + return {'\u29c6', 0}, 1, true case "asymp": // ALMOST EQUAL TO - return rune(0x2248), true + return {'\u2248', 0}, 1, true case "asympeq": // EQUIVALENT TO - return rune(0x224d), true + return {'\u224d', 0}, 1, true case "atilde": // LATIN SMALL LETTER A WITH TILDE - return rune(0xe3), true + return {'ã', 0}, 1, true case "auml": // LATIN SMALL LETTER A WITH DIAERESIS - return rune(0xe4), true + return {'ä', 0}, 1, true case "awconint": // ANTICLOCKWISE CONTOUR INTEGRAL - return rune(0x2233), true + return {'\u2233', 0}, 1, true case "awint": // ANTICLOCKWISE INTEGRATION - return rune(0x2a11), true + return {'\u2a11', 0}, 1, true } case 'b': switch name { case "b.Delta": // MATHEMATICAL BOLD CAPITAL DELTA - return rune(0x01d6ab), true + return {'\U0001d6ab', 0}, 1, true case "b.Gamma": // MATHEMATICAL BOLD CAPITAL GAMMA - return rune(0x01d6aa), true + return {'\U0001d6aa', 0}, 1, true case "b.Gammad": // MATHEMATICAL BOLD CAPITAL DIGAMMA - return rune(0x01d7ca), true + return {'\U0001d7ca', 0}, 1, true case "b.Lambda": // MATHEMATICAL BOLD CAPITAL LAMDA - return rune(0x01d6b2), true + return {'\U0001d6b2', 0}, 1, true case "b.Omega": // MATHEMATICAL BOLD CAPITAL OMEGA - return rune(0x01d6c0), true + return {'\U0001d6c0', 0}, 1, true case "b.Phi": // MATHEMATICAL BOLD CAPITAL PHI - return rune(0x01d6bd), true + return {'\U0001d6bd', 0}, 1, true case "b.Pi": // MATHEMATICAL BOLD CAPITAL PI - return rune(0x01d6b7), true + return {'\U0001d6b7', 0}, 1, true case "b.Psi": // MATHEMATICAL BOLD CAPITAL PSI - return rune(0x01d6bf), true + return {'\U0001d6bf', 0}, 1, true case "b.Sigma": // MATHEMATICAL BOLD CAPITAL SIGMA - return rune(0x01d6ba), true + return {'\U0001d6ba', 0}, 1, true case "b.Theta": // MATHEMATICAL BOLD CAPITAL THETA - return rune(0x01d6af), true + return {'\U0001d6af', 0}, 1, true case "b.Upsi": // MATHEMATICAL BOLD CAPITAL UPSILON - return rune(0x01d6bc), true + return {'\U0001d6bc', 0}, 1, true case "b.Xi": // MATHEMATICAL BOLD CAPITAL XI - return rune(0x01d6b5), true + return {'\U0001d6b5', 0}, 1, true case "b.alpha": // MATHEMATICAL BOLD SMALL ALPHA - return rune(0x01d6c2), true + return {'\U0001d6c2', 0}, 1, true case "b.beta": // MATHEMATICAL BOLD SMALL BETA - return rune(0x01d6c3), true + return {'\U0001d6c3', 0}, 1, true case "b.chi": // MATHEMATICAL BOLD SMALL CHI - return rune(0x01d6d8), true + return {'\U0001d6d8', 0}, 1, true case "b.delta": // MATHEMATICAL BOLD SMALL DELTA - return rune(0x01d6c5), true + return {'\U0001d6c5', 0}, 1, true case "b.epsi": // MATHEMATICAL BOLD SMALL EPSILON - return rune(0x01d6c6), true + return {'\U0001d6c6', 0}, 1, true case "b.epsiv": // MATHEMATICAL BOLD EPSILON SYMBOL - return rune(0x01d6dc), true + return {'\U0001d6dc', 0}, 1, true case "b.eta": // MATHEMATICAL BOLD SMALL ETA - return rune(0x01d6c8), true + return {'\U0001d6c8', 0}, 1, true case "b.gamma": // MATHEMATICAL BOLD SMALL GAMMA - return rune(0x01d6c4), true + return {'\U0001d6c4', 0}, 1, true case "b.gammad": // MATHEMATICAL BOLD SMALL DIGAMMA - return rune(0x01d7cb), true + return {'\U0001d7cb', 0}, 1, true case "b.iota": // MATHEMATICAL BOLD SMALL IOTA - return rune(0x01d6ca), true + return {'\U0001d6ca', 0}, 1, true case "b.kappa": // MATHEMATICAL BOLD SMALL KAPPA - return rune(0x01d6cb), true + return {'\U0001d6cb', 0}, 1, true case "b.kappav": // MATHEMATICAL BOLD KAPPA SYMBOL - return rune(0x01d6de), true + return {'\U0001d6de', 0}, 1, true case "b.lambda": // MATHEMATICAL BOLD SMALL LAMDA - return rune(0x01d6cc), true + return {'\U0001d6cc', 0}, 1, true case "b.mu": // MATHEMATICAL BOLD SMALL MU - return rune(0x01d6cd), true + return {'\U0001d6cd', 0}, 1, true case "b.nu": // MATHEMATICAL BOLD SMALL NU - return rune(0x01d6ce), true + return {'\U0001d6ce', 0}, 1, true case "b.omega": // MATHEMATICAL BOLD SMALL OMEGA - return rune(0x01d6da), true + return {'\U0001d6da', 0}, 1, true case "b.phi": // MATHEMATICAL BOLD SMALL PHI - return rune(0x01d6d7), true + return {'\U0001d6d7', 0}, 1, true case "b.phiv": // MATHEMATICAL BOLD PHI SYMBOL - return rune(0x01d6df), true + return {'\U0001d6df', 0}, 1, true case "b.pi": // MATHEMATICAL BOLD SMALL PI - return rune(0x01d6d1), true + return {'\U0001d6d1', 0}, 1, true case "b.piv": // MATHEMATICAL BOLD PI SYMBOL - return rune(0x01d6e1), true + return {'\U0001d6e1', 0}, 1, true case "b.psi": // MATHEMATICAL BOLD SMALL PSI - return rune(0x01d6d9), true + return {'\U0001d6d9', 0}, 1, true case "b.rho": // MATHEMATICAL BOLD SMALL RHO - return rune(0x01d6d2), true + return {'\U0001d6d2', 0}, 1, true case "b.rhov": // MATHEMATICAL BOLD RHO SYMBOL - return rune(0x01d6e0), true + return {'\U0001d6e0', 0}, 1, true case "b.sigma": // MATHEMATICAL BOLD SMALL SIGMA - return rune(0x01d6d4), true + return {'\U0001d6d4', 0}, 1, true case "b.sigmav": // MATHEMATICAL BOLD SMALL FINAL SIGMA - return rune(0x01d6d3), true + return {'\U0001d6d3', 0}, 1, true case "b.tau": // MATHEMATICAL BOLD SMALL TAU - return rune(0x01d6d5), true + return {'\U0001d6d5', 0}, 1, true case "b.thetas": // MATHEMATICAL BOLD SMALL THETA - return rune(0x01d6c9), true + return {'\U0001d6c9', 0}, 1, true case "b.thetav": // MATHEMATICAL BOLD THETA SYMBOL - return rune(0x01d6dd), true + return {'\U0001d6dd', 0}, 1, true case "b.upsi": // MATHEMATICAL BOLD SMALL UPSILON - return rune(0x01d6d6), true + return {'\U0001d6d6', 0}, 1, true case "b.xi": // MATHEMATICAL BOLD SMALL XI - return rune(0x01d6cf), true + return {'\U0001d6cf', 0}, 1, true case "b.zeta": // MATHEMATICAL BOLD SMALL ZETA - return rune(0x01d6c7), true + return {'\U0001d6c7', 0}, 1, true case "bNot": // REVERSED DOUBLE STROKE NOT SIGN - return rune(0x2aed), true + return {'\u2aed', 0}, 1, true case "backcong": // ALL EQUAL TO - return rune(0x224c), true + return {'\u224c', 0}, 1, true case "backepsilon": // GREEK REVERSED LUNATE EPSILON SYMBOL - return rune(0x03f6), true + return {'\u03f6', 0}, 1, true case "backprime": // REVERSED PRIME - return rune(0x2035), true + return {'\u2035', 0}, 1, true case "backsim": // REVERSED TILDE - return rune(0x223d), true + return {'\u223d', 0}, 1, true case "backsimeq": // REVERSED TILDE EQUALS - return rune(0x22cd), true + return {'\u22cd', 0}, 1, true case "barV": // DOUBLE DOWN TACK - return rune(0x2aea), true + return {'\u2aea', 0}, 1, true case "barvee": // NOR - return rune(0x22bd), true + return {'\u22bd', 0}, 1, true case "barwed": // PROJECTIVE - return rune(0x2305), true + return {'\u2305', 0}, 1, true case "barwedge": // PROJECTIVE - return rune(0x2305), true + return {'\u2305', 0}, 1, true case "bbrk": // BOTTOM SQUARE BRACKET - return rune(0x23b5), true + return {'\u23b5', 0}, 1, true case "bbrktbrk": // BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET - return rune(0x23b6), true + return {'\u23b6', 0}, 1, true case "bcong": // ALL EQUAL TO - return rune(0x224c), true + return {'\u224c', 0}, 1, true case "bcy": // CYRILLIC SMALL LETTER BE - return rune(0x0431), true + return {'\u0431', 0}, 1, true case "bdlhar": // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR - return rune(0x2961), true + return {'\u2961', 0}, 1, true case "bdquo": // DOUBLE LOW-9 QUOTATION MARK - return rune(0x201e), true + return {'\u201e', 0}, 1, true case "bdrhar": // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR - return rune(0x295d), true + return {'\u295d', 0}, 1, true case "becaus": // BECAUSE - return rune(0x2235), true + return {'\u2235', 0}, 1, true case "because": // BECAUSE - return rune(0x2235), true + return {'\u2235', 0}, 1, true case "bemptyv": // REVERSED EMPTY SET - return rune(0x29b0), true + return {'\u29b0', 0}, 1, true case "bepsi": // GREEK REVERSED LUNATE EPSILON SYMBOL - return rune(0x03f6), true + return {'\u03f6', 0}, 1, true case "bernou": // SCRIPT CAPITAL B - return rune(0x212c), true + return {'\u212c', 0}, 1, true case "beta": // GREEK SMALL LETTER BETA - return rune(0x03b2), true + return {'\u03b2', 0}, 1, true case "beth": // BET SYMBOL - return rune(0x2136), true + return {'\u2136', 0}, 1, true case "between": // BETWEEN - return rune(0x226c), true + return {'\u226c', 0}, 1, true case "bfr": // MATHEMATICAL FRAKTUR SMALL B - return rune(0x01d51f), true + return {'\U0001d51f', 0}, 1, true case "bgr": // GREEK SMALL LETTER BETA - return rune(0x03b2), true + return {'\u03b2', 0}, 1, true case "bigcap": // N-ARY INTERSECTION - return rune(0x22c2), true + return {'\u22c2', 0}, 1, true case "bigcirc": // LARGE CIRCLE - return rune(0x25ef), true + return {'\u25ef', 0}, 1, true case "bigcup": // N-ARY UNION - return rune(0x22c3), true + return {'\u22c3', 0}, 1, true case "bigodot": // N-ARY CIRCLED DOT OPERATOR - return rune(0x2a00), true + return {'\u2a00', 0}, 1, true case "bigoplus": // N-ARY CIRCLED PLUS OPERATOR - return rune(0x2a01), true + return {'\u2a01', 0}, 1, true case "bigotimes": // N-ARY CIRCLED TIMES OPERATOR - return rune(0x2a02), true + return {'\u2a02', 0}, 1, true case "bigsqcup": // N-ARY SQUARE UNION OPERATOR - return rune(0x2a06), true + return {'\u2a06', 0}, 1, true case "bigstar": // BLACK STAR - return rune(0x2605), true + return {'\u2605', 0}, 1, true case "bigtriangledown": // WHITE DOWN-POINTING TRIANGLE - return rune(0x25bd), true + return {'\u25bd', 0}, 1, true case "bigtriangleup": // WHITE UP-POINTING TRIANGLE - return rune(0x25b3), true + return {'\u25b3', 0}, 1, true case "biguplus": // N-ARY UNION OPERATOR WITH PLUS - return rune(0x2a04), true + return {'\u2a04', 0}, 1, true case "bigvee": // N-ARY LOGICAL OR - return rune(0x22c1), true + return {'\u22c1', 0}, 1, true case "bigwedge": // N-ARY LOGICAL AND - return rune(0x22c0), true + return {'\u22c0', 0}, 1, true case "bkarow": // RIGHTWARDS DOUBLE DASH ARROW - return rune(0x290d), true + return {'\u290d', 0}, 1, true case "blacklozenge": // BLACK LOZENGE - return rune(0x29eb), true + return {'\u29eb', 0}, 1, true case "blacksquare": // BLACK SMALL SQUARE - return rune(0x25aa), true + return {'\u25aa', 0}, 1, true case "blacktriangle": // BLACK UP-POINTING SMALL TRIANGLE - return rune(0x25b4), true + return {'\u25b4', 0}, 1, true case "blacktriangledown": // BLACK DOWN-POINTING SMALL TRIANGLE - return rune(0x25be), true + return {'\u25be', 0}, 1, true case "blacktriangleleft": // BLACK LEFT-POINTING SMALL TRIANGLE - return rune(0x25c2), true + return {'\u25c2', 0}, 1, true case "blacktriangleright": // BLACK RIGHT-POINTING SMALL TRIANGLE - return rune(0x25b8), true + return {'\u25b8', 0}, 1, true case "blank": // BLANK SYMBOL - return rune(0x2422), true + return {'\u2422', 0}, 1, true case "bldhar": // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR - return rune(0x295e), true + return {'\u295e', 0}, 1, true case "blk12": // MEDIUM SHADE - return rune(0x2592), true + return {'\u2592', 0}, 1, true case "blk14": // LIGHT SHADE - return rune(0x2591), true + return {'\u2591', 0}, 1, true case "blk34": // DARK SHADE - return rune(0x2593), true + return {'\u2593', 0}, 1, true case "block": // FULL BLOCK - return rune(0x2588), true + return {'\u2588', 0}, 1, true case "bluhar": // LEFTWARDS HARPOON WITH BARB UP FROM BAR - return rune(0x295a), true + return {'\u295a', 0}, 1, true case "bne": // EQUALS SIGN with reverse slash - return rune(0x3d), true + return {'=', '\u20e5'}, 2, true case "bnequiv": // IDENTICAL TO with reverse slash - return rune(0x2261), true + return {'\u2261', '\u20e5'}, 2, true case "bnot": // REVERSED NOT SIGN - return rune(0x2310), true + return {'\u2310', 0}, 1, true case "bopf": // MATHEMATICAL DOUBLE-STRUCK SMALL B - return rune(0x01d553), true + return {'\U0001d553', 0}, 1, true case "bot": // UP TACK - return rune(0x22a5), true + return {'\u22a5', 0}, 1, true case "bottom": // UP TACK - return rune(0x22a5), true + return {'\u22a5', 0}, 1, true case "bowtie": // BOWTIE - return rune(0x22c8), true + return {'\u22c8', 0}, 1, true case "boxDL": // BOX DRAWINGS DOUBLE DOWN AND LEFT - return rune(0x2557), true + return {'\u2557', 0}, 1, true case "boxDR": // BOX DRAWINGS DOUBLE DOWN AND RIGHT - return rune(0x2554), true + return {'\u2554', 0}, 1, true case "boxDl": // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE - return rune(0x2556), true + return {'\u2556', 0}, 1, true case "boxDr": // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE - return rune(0x2553), true + return {'\u2553', 0}, 1, true case "boxH": // BOX DRAWINGS DOUBLE HORIZONTAL - return rune(0x2550), true + return {'\u2550', 0}, 1, true case "boxHD": // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL - return rune(0x2566), true + return {'\u2566', 0}, 1, true case "boxHU": // BOX DRAWINGS DOUBLE UP AND HORIZONTAL - return rune(0x2569), true + return {'\u2569', 0}, 1, true case "boxHd": // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE - return rune(0x2564), true + return {'\u2564', 0}, 1, true case "boxHu": // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE - return rune(0x2567), true + return {'\u2567', 0}, 1, true case "boxUL": // BOX DRAWINGS DOUBLE UP AND LEFT - return rune(0x255d), true + return {'\u255d', 0}, 1, true case "boxUR": // BOX DRAWINGS DOUBLE UP AND RIGHT - return rune(0x255a), true + return {'\u255a', 0}, 1, true case "boxUl": // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE - return rune(0x255c), true + return {'\u255c', 0}, 1, true case "boxUr": // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE - return rune(0x2559), true + return {'\u2559', 0}, 1, true case "boxV": // BOX DRAWINGS DOUBLE VERTICAL - return rune(0x2551), true + return {'\u2551', 0}, 1, true case "boxVH": // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL - return rune(0x256c), true + return {'\u256c', 0}, 1, true case "boxVL": // BOX DRAWINGS DOUBLE VERTICAL AND LEFT - return rune(0x2563), true + return {'\u2563', 0}, 1, true case "boxVR": // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT - return rune(0x2560), true + return {'\u2560', 0}, 1, true case "boxVh": // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE - return rune(0x256b), true + return {'\u256b', 0}, 1, true case "boxVl": // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE - return rune(0x2562), true + return {'\u2562', 0}, 1, true case "boxVr": // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE - return rune(0x255f), true + return {'\u255f', 0}, 1, true case "boxbox": // TWO JOINED SQUARES - return rune(0x29c9), true + return {'\u29c9', 0}, 1, true case "boxdL": // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE - return rune(0x2555), true + return {'\u2555', 0}, 1, true case "boxdR": // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE - return rune(0x2552), true + return {'\u2552', 0}, 1, true case "boxdl": // BOX DRAWINGS LIGHT DOWN AND LEFT - return rune(0x2510), true + return {'\u2510', 0}, 1, true case "boxdr": // BOX DRAWINGS LIGHT DOWN AND RIGHT - return rune(0x250c), true + return {'\u250c', 0}, 1, true case "boxh": // BOX DRAWINGS LIGHT HORIZONTAL - return rune(0x2500), true + return {'\u2500', 0}, 1, true case "boxhD": // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE - return rune(0x2565), true + return {'\u2565', 0}, 1, true case "boxhU": // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE - return rune(0x2568), true + return {'\u2568', 0}, 1, true case "boxhd": // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL - return rune(0x252c), true + return {'\u252c', 0}, 1, true case "boxhu": // BOX DRAWINGS LIGHT UP AND HORIZONTAL - return rune(0x2534), true + return {'\u2534', 0}, 1, true case "boxminus": // SQUARED MINUS - return rune(0x229f), true + return {'\u229f', 0}, 1, true case "boxplus": // SQUARED PLUS - return rune(0x229e), true + return {'\u229e', 0}, 1, true case "boxtimes": // SQUARED TIMES - return rune(0x22a0), true + return {'\u22a0', 0}, 1, true case "boxuL": // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE - return rune(0x255b), true + return {'\u255b', 0}, 1, true case "boxuR": // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE - return rune(0x2558), true + return {'\u2558', 0}, 1, true case "boxul": // BOX DRAWINGS LIGHT UP AND LEFT - return rune(0x2518), true + return {'\u2518', 0}, 1, true case "boxur": // BOX DRAWINGS LIGHT UP AND RIGHT - return rune(0x2514), true + return {'\u2514', 0}, 1, true case "boxv": // BOX DRAWINGS LIGHT VERTICAL - return rune(0x2502), true + return {'\u2502', 0}, 1, true case "boxvH": // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE - return rune(0x256a), true + return {'\u256a', 0}, 1, true case "boxvL": // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE - return rune(0x2561), true + return {'\u2561', 0}, 1, true case "boxvR": // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE - return rune(0x255e), true + return {'\u255e', 0}, 1, true case "boxvh": // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL - return rune(0x253c), true + return {'\u253c', 0}, 1, true case "boxvl": // BOX DRAWINGS LIGHT VERTICAL AND LEFT - return rune(0x2524), true + return {'\u2524', 0}, 1, true case "boxvr": // BOX DRAWINGS LIGHT VERTICAL AND RIGHT - return rune(0x251c), true + return {'\u251c', 0}, 1, true case "bprime": // REVERSED PRIME - return rune(0x2035), true + return {'\u2035', 0}, 1, true case "brdhar": // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR - return rune(0x295f), true + return {'\u295f', 0}, 1, true case "breve": // BREVE - return rune(0x02d8), true + return {'\u02d8', 0}, 1, true case "bruhar": // RIGHTWARDS HARPOON WITH BARB UP FROM BAR - return rune(0x295b), true + return {'\u295b', 0}, 1, true case "brvbar": // BROKEN BAR - return rune(0xa6), true + return {'¦', 0}, 1, true case "bscr": // MATHEMATICAL SCRIPT SMALL B - return rune(0x01d4b7), true + return {'\U0001d4b7', 0}, 1, true case "bsemi": // REVERSED SEMICOLON - return rune(0x204f), true + return {'\u204f', 0}, 1, true case "bsim": // REVERSED TILDE - return rune(0x223d), true + return {'\u223d', 0}, 1, true case "bsime": // REVERSED TILDE EQUALS - return rune(0x22cd), true + return {'\u22cd', 0}, 1, true case "bsol": // REVERSE SOLIDUS - return rune(0x5c), true + return {'\\', 0}, 1, true case "bsolb": // SQUARED FALLING DIAGONAL SLASH - return rune(0x29c5), true + return {'\u29c5', 0}, 1, true case "bsolhsub": // REVERSE SOLIDUS PRECEDING SUBSET - return rune(0x27c8), true + return {'\u27c8', 0}, 1, true case "btimes": // SEMIDIRECT PRODUCT WITH BOTTOM CLOSED - return rune(0x2a32), true + return {'\u2a32', 0}, 1, true case "bulhar": // UPWARDS HARPOON WITH BARB LEFT FROM BAR - return rune(0x2960), true + return {'\u2960', 0}, 1, true case "bull": // BULLET - return rune(0x2022), true + return {'\u2022', 0}, 1, true case "bullet": // BULLET - return rune(0x2022), true + return {'\u2022', 0}, 1, true case "bump": // GEOMETRICALLY EQUIVALENT TO - return rune(0x224e), true + return {'\u224e', 0}, 1, true case "bumpE": // EQUALS SIGN WITH BUMPY ABOVE - return rune(0x2aae), true + return {'\u2aae', 0}, 1, true case "bumpe": // DIFFERENCE BETWEEN - return rune(0x224f), true + return {'\u224f', 0}, 1, true case "bumpeq": // DIFFERENCE BETWEEN - return rune(0x224f), true + return {'\u224f', 0}, 1, true case "burhar": // UPWARDS HARPOON WITH BARB RIGHT FROM BAR - return rune(0x295c), true + return {'\u295c', 0}, 1, true } case 'c': switch name { case "cacute": // LATIN SMALL LETTER C WITH ACUTE - return rune(0x0107), true + return {'\u0107', 0}, 1, true case "cap": // INTERSECTION - return rune(0x2229), true + return {'\u2229', 0}, 1, true case "capand": // INTERSECTION WITH LOGICAL AND - return rune(0x2a44), true + return {'\u2a44', 0}, 1, true case "capbrcup": // INTERSECTION ABOVE BAR ABOVE UNION - return rune(0x2a49), true + return {'\u2a49', 0}, 1, true case "capcap": // INTERSECTION BESIDE AND JOINED WITH INTERSECTION - return rune(0x2a4b), true + return {'\u2a4b', 0}, 1, true case "capcup": // INTERSECTION ABOVE UNION - return rune(0x2a47), true + return {'\u2a47', 0}, 1, true case "capdot": // INTERSECTION WITH DOT - return rune(0x2a40), true + return {'\u2a40', 0}, 1, true case "capint": // INTEGRAL WITH INTERSECTION - return rune(0x2a19), true + return {'\u2a19', 0}, 1, true case "caps": // INTERSECTION with serifs - return rune(0x2229), true + return {'\u2229', '\ufe00'}, 2, true case "caret": // CARET INSERTION POINT - return rune(0x2041), true + return {'\u2041', 0}, 1, true case "caron": // CARON - return rune(0x02c7), true + return {'\u02c7', 0}, 1, true case "ccaps": // CLOSED INTERSECTION WITH SERIFS - return rune(0x2a4d), true + return {'\u2a4d', 0}, 1, true case "ccaron": // LATIN SMALL LETTER C WITH CARON - return rune(0x010d), true + return {'\u010d', 0}, 1, true case "ccedil": // LATIN SMALL LETTER C WITH CEDILLA - return rune(0xe7), true + return {'ç', 0}, 1, true case "ccirc": // LATIN SMALL LETTER C WITH CIRCUMFLEX - return rune(0x0109), true + return {'\u0109', 0}, 1, true case "ccups": // CLOSED UNION WITH SERIFS - return rune(0x2a4c), true + return {'\u2a4c', 0}, 1, true case "ccupssm": // CLOSED UNION WITH SERIFS AND SMASH PRODUCT - return rune(0x2a50), true + return {'\u2a50', 0}, 1, true case "cdot": // LATIN SMALL LETTER C WITH DOT ABOVE - return rune(0x010b), true + return {'\u010b', 0}, 1, true case "cedil": // CEDILLA - return rune(0xb8), true + return {'¸', 0}, 1, true case "cemptyv": // EMPTY SET WITH SMALL CIRCLE ABOVE - return rune(0x29b2), true + return {'\u29b2', 0}, 1, true case "cent": // CENT SIGN - return rune(0xa2), true + return {'¢', 0}, 1, true case "centerdot": // MIDDLE DOT - return rune(0xb7), true + return {'·', 0}, 1, true case "cfr": // MATHEMATICAL FRAKTUR SMALL C - return rune(0x01d520), true + return {'\U0001d520', 0}, 1, true case "chcy": // CYRILLIC SMALL LETTER CHE - return rune(0x0447), true + return {'\u0447', 0}, 1, true case "check": // CHECK MARK - return rune(0x2713), true + return {'\u2713', 0}, 1, true case "checkmark": // CHECK MARK - return rune(0x2713), true + return {'\u2713', 0}, 1, true case "chi": // GREEK SMALL LETTER CHI - return rune(0x03c7), true + return {'\u03c7', 0}, 1, true case "cir": // WHITE CIRCLE - return rune(0x25cb), true + return {'\u25cb', 0}, 1, true case "cirE": // CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT - return rune(0x29c3), true + return {'\u29c3', 0}, 1, true case "cirb": // SQUARED SMALL CIRCLE - return rune(0x29c7), true + return {'\u29c7', 0}, 1, true case "circ": // MODIFIER LETTER CIRCUMFLEX ACCENT - return rune(0x02c6), true + return {'\u02c6', 0}, 1, true case "circeq": // RING EQUAL TO - return rune(0x2257), true + return {'\u2257', 0}, 1, true case "circlearrowleft": // ANTICLOCKWISE OPEN CIRCLE ARROW - return rune(0x21ba), true + return {'\u21ba', 0}, 1, true case "circlearrowright": // CLOCKWISE OPEN CIRCLE ARROW - return rune(0x21bb), true + return {'\u21bb', 0}, 1, true case "circledR": // REGISTERED SIGN - return rune(0xae), true + return {'®', 0}, 1, true case "circledS": // CIRCLED LATIN CAPITAL LETTER S - return rune(0x24c8), true + return {'\u24c8', 0}, 1, true case "circledast": // CIRCLED ASTERISK OPERATOR - return rune(0x229b), true + return {'\u229b', 0}, 1, true case "circledcirc": // CIRCLED RING OPERATOR - return rune(0x229a), true + return {'\u229a', 0}, 1, true case "circleddash": // CIRCLED DASH - return rune(0x229d), true + return {'\u229d', 0}, 1, true case "cirdarr": // WHITE CIRCLE WITH DOWN ARROW - return rune(0x29ec), true + return {'\u29ec', 0}, 1, true case "cire": // RING EQUAL TO - return rune(0x2257), true + return {'\u2257', 0}, 1, true case "cirerr": // ERROR-BARRED WHITE CIRCLE - return rune(0x29f2), true + return {'\u29f2', 0}, 1, true case "cirfdarr": // BLACK CIRCLE WITH DOWN ARROW - return rune(0x29ed), true + return {'\u29ed', 0}, 1, true case "cirferr": // ERROR-BARRED BLACK CIRCLE - return rune(0x29f3), true + return {'\u29f3', 0}, 1, true case "cirfnint": // CIRCULATION FUNCTION - return rune(0x2a10), true + return {'\u2a10', 0}, 1, true case "cirmid": // VERTICAL LINE WITH CIRCLE ABOVE - return rune(0x2aef), true + return {'\u2aef', 0}, 1, true case "cirscir": // CIRCLE WITH SMALL CIRCLE TO THE RIGHT - return rune(0x29c2), true + return {'\u29c2', 0}, 1, true case "closur": // CLOSE UP - return rune(0x2050), true + return {'\u2050', 0}, 1, true case "clubs": // BLACK CLUB SUIT - return rune(0x2663), true + return {'\u2663', 0}, 1, true case "clubsuit": // BLACK CLUB SUIT - return rune(0x2663), true + return {'\u2663', 0}, 1, true case "colon": // COLON - return rune(0x3a), true + return {':', 0}, 1, true case "colone": // COLON EQUALS - return rune(0x2254), true + return {'\u2254', 0}, 1, true case "coloneq": // COLON EQUALS - return rune(0x2254), true + return {'\u2254', 0}, 1, true case "comma": // COMMA - return rune(0x2c), true + return {',', 0}, 1, true case "commat": // COMMERCIAL AT - return rune(0x40), true + return {'@', 0}, 1, true case "comp": // COMPLEMENT - return rune(0x2201), true + return {'\u2201', 0}, 1, true case "compfn": // RING OPERATOR - return rune(0x2218), true + return {'\u2218', 0}, 1, true case "complement": // COMPLEMENT - return rune(0x2201), true + return {'\u2201', 0}, 1, true case "complexes": // DOUBLE-STRUCK CAPITAL C - return rune(0x2102), true + return {'\u2102', 0}, 1, true case "cong": // APPROXIMATELY EQUAL TO - return rune(0x2245), true + return {'\u2245', 0}, 1, true case "congdot": // CONGRUENT WITH DOT ABOVE - return rune(0x2a6d), true + return {'\u2a6d', 0}, 1, true case "conint": // CONTOUR INTEGRAL - return rune(0x222e), true + return {'\u222e', 0}, 1, true case "copf": // MATHEMATICAL DOUBLE-STRUCK SMALL C - return rune(0x01d554), true + return {'\U0001d554', 0}, 1, true case "coprod": // N-ARY COPRODUCT - return rune(0x2210), true + return {'\u2210', 0}, 1, true case "copy": // COPYRIGHT SIGN - return rune(0xa9), true + return {'©', 0}, 1, true case "copysr": // SOUND RECORDING COPYRIGHT - return rune(0x2117), true + return {'\u2117', 0}, 1, true case "crarr": // DOWNWARDS ARROW WITH CORNER LEFTWARDS - return rune(0x21b5), true + return {'\u21b5', 0}, 1, true case "cross": // BALLOT X - return rune(0x2717), true + return {'\u2717', 0}, 1, true case "cscr": // MATHEMATICAL SCRIPT SMALL C - return rune(0x01d4b8), true + return {'\U0001d4b8', 0}, 1, true case "csub": // CLOSED SUBSET - return rune(0x2acf), true + return {'\u2acf', 0}, 1, true case "csube": // CLOSED SUBSET OR EQUAL TO - return rune(0x2ad1), true + return {'\u2ad1', 0}, 1, true case "csup": // CLOSED SUPERSET - return rune(0x2ad0), true + return {'\u2ad0', 0}, 1, true case "csupe": // CLOSED SUPERSET OR EQUAL TO - return rune(0x2ad2), true + return {'\u2ad2', 0}, 1, true case "ctdot": // MIDLINE HORIZONTAL ELLIPSIS - return rune(0x22ef), true + return {'\u22ef', 0}, 1, true case "cudarrl": // RIGHT-SIDE ARC CLOCKWISE ARROW - return rune(0x2938), true + return {'\u2938', 0}, 1, true case "cudarrr": // ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS - return rune(0x2935), true + return {'\u2935', 0}, 1, true case "cuepr": // EQUAL TO OR PRECEDES - return rune(0x22de), true + return {'\u22de', 0}, 1, true case "cuesc": // EQUAL TO OR SUCCEEDS - return rune(0x22df), true + return {'\u22df', 0}, 1, true case "cularr": // ANTICLOCKWISE TOP SEMICIRCLE ARROW - return rune(0x21b6), true + return {'\u21b6', 0}, 1, true case "cularrp": // TOP ARC ANTICLOCKWISE ARROW WITH PLUS - return rune(0x293d), true + return {'\u293d', 0}, 1, true case "cup": // UNION - return rune(0x222a), true + return {'\u222a', 0}, 1, true case "cupbrcap": // UNION ABOVE BAR ABOVE INTERSECTION - return rune(0x2a48), true + return {'\u2a48', 0}, 1, true case "cupcap": // UNION ABOVE INTERSECTION - return rune(0x2a46), true + return {'\u2a46', 0}, 1, true case "cupcup": // UNION BESIDE AND JOINED WITH UNION - return rune(0x2a4a), true + return {'\u2a4a', 0}, 1, true case "cupdot": // MULTISET MULTIPLICATION - return rune(0x228d), true + return {'\u228d', 0}, 1, true case "cupint": // INTEGRAL WITH UNION - return rune(0x2a1a), true + return {'\u2a1a', 0}, 1, true case "cupor": // UNION WITH LOGICAL OR - return rune(0x2a45), true + return {'\u2a45', 0}, 1, true case "cupre": // PRECEDES OR EQUAL TO - return rune(0x227c), true + return {'\u227c', 0}, 1, true case "cups": // UNION with serifs - return rune(0x222a), true + return {'\u222a', '\ufe00'}, 2, true case "curarr": // CLOCKWISE TOP SEMICIRCLE ARROW - return rune(0x21b7), true + return {'\u21b7', 0}, 1, true case "curarrm": // TOP ARC CLOCKWISE ARROW WITH MINUS - return rune(0x293c), true + return {'\u293c', 0}, 1, true case "curlyeqprec": // EQUAL TO OR PRECEDES - return rune(0x22de), true + return {'\u22de', 0}, 1, true case "curlyeqsucc": // EQUAL TO OR SUCCEEDS - return rune(0x22df), true + return {'\u22df', 0}, 1, true case "curlyvee": // CURLY LOGICAL OR - return rune(0x22ce), true + return {'\u22ce', 0}, 1, true case "curlywedge": // CURLY LOGICAL AND - return rune(0x22cf), true + return {'\u22cf', 0}, 1, true case "curren": // CURRENCY SIGN - return rune(0xa4), true + return {'¤', 0}, 1, true case "curvearrowleft": // ANTICLOCKWISE TOP SEMICIRCLE ARROW - return rune(0x21b6), true + return {'\u21b6', 0}, 1, true case "curvearrowright": // CLOCKWISE TOP SEMICIRCLE ARROW - return rune(0x21b7), true + return {'\u21b7', 0}, 1, true case "cuvee": // CURLY LOGICAL OR - return rune(0x22ce), true + return {'\u22ce', 0}, 1, true case "cuwed": // CURLY LOGICAL AND - return rune(0x22cf), true + return {'\u22cf', 0}, 1, true case "cwconint": // CLOCKWISE CONTOUR INTEGRAL - return rune(0x2232), true + return {'\u2232', 0}, 1, true case "cwint": // CLOCKWISE INTEGRAL - return rune(0x2231), true + return {'\u2231', 0}, 1, true case "cylcty": // CYLINDRICITY - return rune(0x232d), true + return {'\u232d', 0}, 1, true } case 'd': switch name { case "dAarr": // DOWNWARDS TRIPLE ARROW - return rune(0x290b), true + return {'\u290b', 0}, 1, true case "dArr": // DOWNWARDS DOUBLE ARROW - return rune(0x21d3), true + return {'\u21d3', 0}, 1, true case "dHar": // DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT - return rune(0x2965), true + return {'\u2965', 0}, 1, true case "dagger": // DAGGER - return rune(0x2020), true + return {'\u2020', 0}, 1, true case "dalembrt": // SQUARE WITH CONTOURED OUTLINE - return rune(0x29e0), true + return {'\u29e0', 0}, 1, true case "daleth": // DALET SYMBOL - return rune(0x2138), true + return {'\u2138', 0}, 1, true case "darr": // DOWNWARDS ARROW - return rune(0x2193), true + return {'\u2193', 0}, 1, true case "darr2": // DOWNWARDS PAIRED ARROWS - return rune(0x21ca), true + return {'\u21ca', 0}, 1, true case "darrb": // DOWNWARDS ARROW TO BAR - return rune(0x2913), true + return {'\u2913', 0}, 1, true case "darrln": // DOWNWARDS ARROW WITH HORIZONTAL STROKE - return rune(0x2908), true + return {'\u2908', 0}, 1, true case "dash": // HYPHEN - return rune(0x2010), true + return {'\u2010', 0}, 1, true case "dashV": // DOUBLE VERTICAL BAR LEFT TURNSTILE - return rune(0x2ae3), true + return {'\u2ae3', 0}, 1, true case "dashv": // LEFT TACK - return rune(0x22a3), true + return {'\u22a3', 0}, 1, true case "dbkarow": // RIGHTWARDS TRIPLE DASH ARROW - return rune(0x290f), true + return {'\u290f', 0}, 1, true case "dblac": // DOUBLE ACUTE ACCENT - return rune(0x02dd), true + return {'\u02dd', 0}, 1, true case "dcaron": // LATIN SMALL LETTER D WITH CARON - return rune(0x010f), true + return {'\u010f', 0}, 1, true case "dcy": // CYRILLIC SMALL LETTER DE - return rune(0x0434), true + return {'\u0434', 0}, 1, true case "dd": // DOUBLE-STRUCK ITALIC SMALL D - return rune(0x2146), true + return {'\u2146', 0}, 1, true case "ddagger": // DOUBLE DAGGER - return rune(0x2021), true + return {'\u2021', 0}, 1, true case "ddarr": // DOWNWARDS PAIRED ARROWS - return rune(0x21ca), true + return {'\u21ca', 0}, 1, true case "ddotseq": // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW - return rune(0x2a77), true + return {'\u2a77', 0}, 1, true case "deg": // DEGREE SIGN - return rune(0xb0), true + return {'°', 0}, 1, true case "delta": // GREEK SMALL LETTER DELTA - return rune(0x03b4), true + return {'\u03b4', 0}, 1, true case "demptyv": // EMPTY SET WITH OVERBAR - return rune(0x29b1), true + return {'\u29b1', 0}, 1, true case "dfisht": // DOWN FISH TAIL - return rune(0x297f), true + return {'\u297f', 0}, 1, true case "dfr": // MATHEMATICAL FRAKTUR SMALL D - return rune(0x01d521), true + return {'\U0001d521', 0}, 1, true case "dgr": // GREEK SMALL LETTER DELTA - return rune(0x03b4), true + return {'\u03b4', 0}, 1, true case "dharl": // DOWNWARDS HARPOON WITH BARB LEFTWARDS - return rune(0x21c3), true + return {'\u21c3', 0}, 1, true case "dharr": // DOWNWARDS HARPOON WITH BARB RIGHTWARDS - return rune(0x21c2), true + return {'\u21c2', 0}, 1, true case "diam": // DIAMOND OPERATOR - return rune(0x22c4), true + return {'\u22c4', 0}, 1, true case "diamdarr": // BLACK DIAMOND WITH DOWN ARROW - return rune(0x29ea), true + return {'\u29ea', 0}, 1, true case "diamerr": // ERROR-BARRED WHITE DIAMOND - return rune(0x29f0), true + return {'\u29f0', 0}, 1, true case "diamerrf": // ERROR-BARRED BLACK DIAMOND - return rune(0x29f1), true + return {'\u29f1', 0}, 1, true case "diamond": // DIAMOND OPERATOR - return rune(0x22c4), true + return {'\u22c4', 0}, 1, true case "diamondsuit": // BLACK DIAMOND SUIT - return rune(0x2666), true + return {'\u2666', 0}, 1, true case "diams": // BLACK DIAMOND SUIT - return rune(0x2666), true + return {'\u2666', 0}, 1, true case "die": // DIAERESIS - return rune(0xa8), true + return {'¨', 0}, 1, true case "digamma": // GREEK SMALL LETTER DIGAMMA - return rune(0x03dd), true + return {'\u03dd', 0}, 1, true case "disin": // ELEMENT OF WITH LONG HORIZONTAL STROKE - return rune(0x22f2), true + return {'\u22f2', 0}, 1, true case "div": // DIVISION SIGN - return rune(0xf7), true + return {'÷', 0}, 1, true case "divide": // DIVISION SIGN - return rune(0xf7), true + return {'÷', 0}, 1, true case "divideontimes": // DIVISION TIMES - return rune(0x22c7), true + return {'\u22c7', 0}, 1, true case "divonx": // DIVISION TIMES - return rune(0x22c7), true + return {'\u22c7', 0}, 1, true case "djcy": // CYRILLIC SMALL LETTER DJE - return rune(0x0452), true + return {'\u0452', 0}, 1, true case "dlarr": // SOUTH WEST ARROW - return rune(0x2199), true + return {'\u2199', 0}, 1, true case "dlcorn": // BOTTOM LEFT CORNER - return rune(0x231e), true + return {'\u231e', 0}, 1, true case "dlcrop": // BOTTOM LEFT CROP - return rune(0x230d), true + return {'\u230d', 0}, 1, true case "dlharb": // DOWNWARDS HARPOON WITH BARB LEFT TO BAR - return rune(0x2959), true + return {'\u2959', 0}, 1, true case "dollar": // DOLLAR SIGN - return rune(0x24), true + return {'$', 0}, 1, true case "dopf": // MATHEMATICAL DOUBLE-STRUCK SMALL D - return rune(0x01d555), true + return {'\U0001d555', 0}, 1, true case "dot": // DOT ABOVE - return rune(0x02d9), true + return {'\u02d9', 0}, 1, true case "doteq": // APPROACHES THE LIMIT - return rune(0x2250), true + return {'\u2250', 0}, 1, true case "doteqdot": // GEOMETRICALLY EQUAL TO - return rune(0x2251), true + return {'\u2251', 0}, 1, true case "dotminus": // DOT MINUS - return rune(0x2238), true + return {'\u2238', 0}, 1, true case "dotplus": // DOT PLUS - return rune(0x2214), true + return {'\u2214', 0}, 1, true case "dotsquare": // SQUARED DOT OPERATOR - return rune(0x22a1), true + return {'\u22a1', 0}, 1, true case "doublebarwedge": // PERSPECTIVE - return rune(0x2306), true + return {'\u2306', 0}, 1, true case "downarrow": // DOWNWARDS ARROW - return rune(0x2193), true + return {'\u2193', 0}, 1, true case "downdownarrows": // DOWNWARDS PAIRED ARROWS - return rune(0x21ca), true + return {'\u21ca', 0}, 1, true case "downharpoonleft": // DOWNWARDS HARPOON WITH BARB LEFTWARDS - return rune(0x21c3), true + return {'\u21c3', 0}, 1, true case "downharpoonright": // DOWNWARDS HARPOON WITH BARB RIGHTWARDS - return rune(0x21c2), true + return {'\u21c2', 0}, 1, true case "drarr": // SOUTH EAST ARROW - return rune(0x2198), true + return {'\u2198', 0}, 1, true case "drbkarow": // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW - return rune(0x2910), true + return {'\u2910', 0}, 1, true case "drcorn": // BOTTOM RIGHT CORNER - return rune(0x231f), true + return {'\u231f', 0}, 1, true case "drcrop": // BOTTOM RIGHT CROP - return rune(0x230c), true + return {'\u230c', 0}, 1, true case "drharb": // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR - return rune(0x2955), true + return {'\u2955', 0}, 1, true case "dscr": // MATHEMATICAL SCRIPT SMALL D - return rune(0x01d4b9), true + return {'\U0001d4b9', 0}, 1, true case "dscy": // CYRILLIC SMALL LETTER DZE - return rune(0x0455), true + return {'\u0455', 0}, 1, true case "dsol": // SOLIDUS WITH OVERBAR - return rune(0x29f6), true + return {'\u29f6', 0}, 1, true case "dstrok": // LATIN SMALL LETTER D WITH STROKE - return rune(0x0111), true + return {'\u0111', 0}, 1, true case "dtdot": // DOWN RIGHT DIAGONAL ELLIPSIS - return rune(0x22f1), true + return {'\u22f1', 0}, 1, true case "dtri": // WHITE DOWN-POINTING SMALL TRIANGLE - return rune(0x25bf), true + return {'\u25bf', 0}, 1, true case "dtrif": // BLACK DOWN-POINTING SMALL TRIANGLE - return rune(0x25be), true + return {'\u25be', 0}, 1, true case "dtrilf": // DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK - return rune(0x29e8), true + return {'\u29e8', 0}, 1, true case "dtrirf": // DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK - return rune(0x29e9), true + return {'\u29e9', 0}, 1, true case "duarr": // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW - return rune(0x21f5), true + return {'\u21f5', 0}, 1, true case "duhar": // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT - return rune(0x296f), true + return {'\u296f', 0}, 1, true case "dumap": // DOUBLE-ENDED MULTIMAP - return rune(0x29df), true + return {'\u29df', 0}, 1, true case "dwangle": // OBLIQUE ANGLE OPENING UP - return rune(0x29a6), true + return {'\u29a6', 0}, 1, true case "dzcy": // CYRILLIC SMALL LETTER DZHE - return rune(0x045f), true + return {'\u045f', 0}, 1, true case "dzigrarr": // LONG RIGHTWARDS SQUIGGLE ARROW - return rune(0x27ff), true + return {'\u27ff', 0}, 1, true } case 'e': switch name { case "eDDot": // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW - return rune(0x2a77), true + return {'\u2a77', 0}, 1, true case "eDot": // GEOMETRICALLY EQUAL TO - return rune(0x2251), true + return {'\u2251', 0}, 1, true case "eacgr": // GREEK SMALL LETTER EPSILON WITH TONOS - return rune(0x03ad), true + return {'\u03ad', 0}, 1, true case "eacute": // LATIN SMALL LETTER E WITH ACUTE - return rune(0xe9), true + return {'é', 0}, 1, true case "easter": // EQUALS WITH ASTERISK - return rune(0x2a6e), true + return {'\u2a6e', 0}, 1, true case "ecaron": // LATIN SMALL LETTER E WITH CARON - return rune(0x011b), true + return {'\u011b', 0}, 1, true case "ecir": // RING IN EQUAL TO - return rune(0x2256), true + return {'\u2256', 0}, 1, true case "ecirc": // LATIN SMALL LETTER E WITH CIRCUMFLEX - return rune(0xea), true + return {'ê', 0}, 1, true case "ecolon": // EQUALS COLON - return rune(0x2255), true + return {'\u2255', 0}, 1, true case "ecy": // CYRILLIC SMALL LETTER E - return rune(0x044d), true + return {'\u044d', 0}, 1, true case "edot": // LATIN SMALL LETTER E WITH DOT ABOVE - return rune(0x0117), true + return {'\u0117', 0}, 1, true case "ee": // DOUBLE-STRUCK ITALIC SMALL E - return rune(0x2147), true + return {'\u2147', 0}, 1, true case "eeacgr": // GREEK SMALL LETTER ETA WITH TONOS - return rune(0x03ae), true + return {'\u03ae', 0}, 1, true case "eegr": // GREEK SMALL LETTER ETA - return rune(0x03b7), true + return {'\u03b7', 0}, 1, true case "efDot": // APPROXIMATELY EQUAL TO OR THE IMAGE OF - return rune(0x2252), true + return {'\u2252', 0}, 1, true case "efr": // MATHEMATICAL FRAKTUR SMALL E - return rune(0x01d522), true + return {'\U0001d522', 0}, 1, true case "eg": // DOUBLE-LINE EQUAL TO OR GREATER-THAN - return rune(0x2a9a), true + return {'\u2a9a', 0}, 1, true case "egr": // GREEK SMALL LETTER EPSILON - return rune(0x03b5), true + return {'\u03b5', 0}, 1, true case "egrave": // LATIN SMALL LETTER E WITH GRAVE - return rune(0xe8), true + return {'è', 0}, 1, true case "egs": // SLANTED EQUAL TO OR GREATER-THAN - return rune(0x2a96), true + return {'\u2a96', 0}, 1, true case "egsdot": // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE - return rune(0x2a98), true + return {'\u2a98', 0}, 1, true case "el": // DOUBLE-LINE EQUAL TO OR LESS-THAN - return rune(0x2a99), true + return {'\u2a99', 0}, 1, true case "elinters": // ELECTRICAL INTERSECTION - return rune(0x23e7), true + return {'\u23e7', 0}, 1, true case "ell": // SCRIPT SMALL L - return rune(0x2113), true + return {'\u2113', 0}, 1, true case "els": // SLANTED EQUAL TO OR LESS-THAN - return rune(0x2a95), true + return {'\u2a95', 0}, 1, true case "elsdot": // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE - return rune(0x2a97), true + return {'\u2a97', 0}, 1, true case "emacr": // LATIN SMALL LETTER E WITH MACRON - return rune(0x0113), true + return {'\u0113', 0}, 1, true case "empty": // EMPTY SET - return rune(0x2205), true + return {'\u2205', 0}, 1, true case "emptyset": // EMPTY SET - return rune(0x2205), true + return {'\u2205', 0}, 1, true case "emptyv": // EMPTY SET - return rune(0x2205), true + return {'\u2205', 0}, 1, true case "emsp": // EM SPACE - return rune(0x2003), true + return {'\u2003', 0}, 1, true case "emsp13": // THREE-PER-EM SPACE - return rune(0x2004), true + return {'\u2004', 0}, 1, true case "emsp14": // FOUR-PER-EM SPACE - return rune(0x2005), true + return {'\u2005', 0}, 1, true case "eng": // LATIN SMALL LETTER ENG - return rune(0x014b), true + return {'\u014b', 0}, 1, true case "ensp": // EN SPACE - return rune(0x2002), true + return {'\u2002', 0}, 1, true case "eogon": // LATIN SMALL LETTER E WITH OGONEK - return rune(0x0119), true + return {'\u0119', 0}, 1, true case "eopf": // MATHEMATICAL DOUBLE-STRUCK SMALL E - return rune(0x01d556), true + return {'\U0001d556', 0}, 1, true case "epar": // EQUAL AND PARALLEL TO - return rune(0x22d5), true + return {'\u22d5', 0}, 1, true case "eparsl": // EQUALS SIGN AND SLANTED PARALLEL - return rune(0x29e3), true + return {'\u29e3', 0}, 1, true case "eplus": // EQUALS SIGN ABOVE PLUS SIGN - return rune(0x2a71), true + return {'\u2a71', 0}, 1, true case "epsi": // GREEK SMALL LETTER EPSILON - return rune(0x03b5), true + return {'\u03b5', 0}, 1, true case "epsilon": // GREEK SMALL LETTER EPSILON - return rune(0x03b5), true + return {'\u03b5', 0}, 1, true case "epsis": // GREEK LUNATE EPSILON SYMBOL - return rune(0x03f5), true + return {'\u03f5', 0}, 1, true case "epsiv": // GREEK LUNATE EPSILON SYMBOL - return rune(0x03f5), true + return {'\u03f5', 0}, 1, true case "eqcirc": // RING IN EQUAL TO - return rune(0x2256), true + return {'\u2256', 0}, 1, true case "eqcolon": // EQUALS COLON - return rune(0x2255), true + return {'\u2255', 0}, 1, true case "eqeq": // TWO CONSECUTIVE EQUALS SIGNS - return rune(0x2a75), true + return {'\u2a75', 0}, 1, true case "eqsim": // MINUS TILDE - return rune(0x2242), true + return {'\u2242', 0}, 1, true case "eqslantgtr": // SLANTED EQUAL TO OR GREATER-THAN - return rune(0x2a96), true + return {'\u2a96', 0}, 1, true case "eqslantless": // SLANTED EQUAL TO OR LESS-THAN - return rune(0x2a95), true + return {'\u2a95', 0}, 1, true case "equals": // EQUALS SIGN - return rune(0x3d), true + return {'=', 0}, 1, true case "equest": // QUESTIONED EQUAL TO - return rune(0x225f), true + return {'\u225f', 0}, 1, true case "equiv": // IDENTICAL TO - return rune(0x2261), true + return {'\u2261', 0}, 1, true case "equivDD": // EQUIVALENT WITH FOUR DOTS ABOVE - return rune(0x2a78), true + return {'\u2a78', 0}, 1, true case "eqvparsl": // IDENTICAL TO AND SLANTED PARALLEL - return rune(0x29e5), true + return {'\u29e5', 0}, 1, true case "erDot": // IMAGE OF OR APPROXIMATELY EQUAL TO - return rune(0x2253), true + return {'\u2253', 0}, 1, true case "erarr": // EQUALS SIGN ABOVE RIGHTWARDS ARROW - return rune(0x2971), true + return {'\u2971', 0}, 1, true case "escr": // SCRIPT SMALL E - return rune(0x212f), true + return {'\u212f', 0}, 1, true case "esdot": // APPROACHES THE LIMIT - return rune(0x2250), true + return {'\u2250', 0}, 1, true case "esim": // MINUS TILDE - return rune(0x2242), true + return {'\u2242', 0}, 1, true case "eta": // GREEK SMALL LETTER ETA - return rune(0x03b7), true + return {'\u03b7', 0}, 1, true case "eth": // LATIN SMALL LETTER ETH - return rune(0xf0), true + return {'ð', 0}, 1, true case "euml": // LATIN SMALL LETTER E WITH DIAERESIS - return rune(0xeb), true + return {'ë', 0}, 1, true case "euro": // EURO SIGN - return rune(0x20ac), true + return {'\u20ac', 0}, 1, true case "excl": // EXCLAMATION MARK - return rune(0x21), true + return {'!', 0}, 1, true case "exist": // THERE EXISTS - return rune(0x2203), true + return {'\u2203', 0}, 1, true case "expectation": // SCRIPT CAPITAL E - return rune(0x2130), true + return {'\u2130', 0}, 1, true case "exponentiale": // DOUBLE-STRUCK ITALIC SMALL E - return rune(0x2147), true + return {'\u2147', 0}, 1, true } case 'f': switch name { case "fallingdotseq": // APPROXIMATELY EQUAL TO OR THE IMAGE OF - return rune(0x2252), true + return {'\u2252', 0}, 1, true case "fbowtie": // BLACK BOWTIE - return rune(0x29d3), true + return {'\u29d3', 0}, 1, true case "fcy": // CYRILLIC SMALL LETTER EF - return rune(0x0444), true + return {'\u0444', 0}, 1, true case "fdiag": // BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT - return rune(0x2572), true + return {'\u2572', 0}, 1, true case "fdiordi": // FALLING DIAGONAL CROSSING RISING DIAGONAL - return rune(0x292c), true + return {'\u292c', 0}, 1, true case "fdonearr": // FALLING DIAGONAL CROSSING NORTH EAST ARROW - return rune(0x292f), true + return {'\u292f', 0}, 1, true case "female": // FEMALE SIGN - return rune(0x2640), true + return {'\u2640', 0}, 1, true case "ffilig": // LATIN SMALL LIGATURE FFI - return rune(0xfb03), true + return {'\ufb03', 0}, 1, true case "fflig": // LATIN SMALL LIGATURE FF - return rune(0xfb00), true + return {'\ufb00', 0}, 1, true case "ffllig": // LATIN SMALL LIGATURE FFL - return rune(0xfb04), true + return {'\ufb04', 0}, 1, true case "ffr": // MATHEMATICAL FRAKTUR SMALL F - return rune(0x01d523), true + return {'\U0001d523', 0}, 1, true case "fhrglass": // BLACK HOURGLASS - return rune(0x29d7), true + return {'\u29d7', 0}, 1, true case "filig": // LATIN SMALL LIGATURE FI - return rune(0xfb01), true + return {'\ufb01', 0}, 1, true case "fjlig": // fj ligature - return rune(0x66), true + return {'f', 'j'}, 2, true case "flat": // MUSIC FLAT SIGN - return rune(0x266d), true + return {'\u266d', 0}, 1, true case "fllig": // LATIN SMALL LIGATURE FL - return rune(0xfb02), true + return {'\ufb02', 0}, 1, true case "fltns": // WHITE PARALLELOGRAM - return rune(0x25b1), true + return {'\u25b1', 0}, 1, true case "fnof": // LATIN SMALL LETTER F WITH HOOK - return rune(0x0192), true + return {'\u0192', 0}, 1, true case "fopf": // MATHEMATICAL DOUBLE-STRUCK SMALL F - return rune(0x01d557), true + return {'\U0001d557', 0}, 1, true case "forall": // FOR ALL - return rune(0x2200), true + return {'\u2200', 0}, 1, true case "fork": // PITCHFORK - return rune(0x22d4), true + return {'\u22d4', 0}, 1, true case "forkv": // ELEMENT OF OPENING DOWNWARDS - return rune(0x2ad9), true + return {'\u2ad9', 0}, 1, true case "fpartint": // FINITE PART INTEGRAL - return rune(0x2a0d), true + return {'\u2a0d', 0}, 1, true case "frac12": // VULGAR FRACTION ONE HALF - return rune(0xbd), true + return {'½', 0}, 1, true case "frac13": // VULGAR FRACTION ONE THIRD - return rune(0x2153), true + return {'\u2153', 0}, 1, true case "frac14": // VULGAR FRACTION ONE QUARTER - return rune(0xbc), true + return {'¼', 0}, 1, true case "frac15": // VULGAR FRACTION ONE FIFTH - return rune(0x2155), true + return {'\u2155', 0}, 1, true case "frac16": // VULGAR FRACTION ONE SIXTH - return rune(0x2159), true + return {'\u2159', 0}, 1, true case "frac18": // VULGAR FRACTION ONE EIGHTH - return rune(0x215b), true + return {'\u215b', 0}, 1, true case "frac23": // VULGAR FRACTION TWO THIRDS - return rune(0x2154), true + return {'\u2154', 0}, 1, true case "frac25": // VULGAR FRACTION TWO FIFTHS - return rune(0x2156), true + return {'\u2156', 0}, 1, true case "frac34": // VULGAR FRACTION THREE QUARTERS - return rune(0xbe), true + return {'¾', 0}, 1, true case "frac35": // VULGAR FRACTION THREE FIFTHS - return rune(0x2157), true + return {'\u2157', 0}, 1, true case "frac38": // VULGAR FRACTION THREE EIGHTHS - return rune(0x215c), true + return {'\u215c', 0}, 1, true case "frac45": // VULGAR FRACTION FOUR FIFTHS - return rune(0x2158), true + return {'\u2158', 0}, 1, true case "frac56": // VULGAR FRACTION FIVE SIXTHS - return rune(0x215a), true + return {'\u215a', 0}, 1, true case "frac58": // VULGAR FRACTION FIVE EIGHTHS - return rune(0x215d), true + return {'\u215d', 0}, 1, true case "frac78": // VULGAR FRACTION SEVEN EIGHTHS - return rune(0x215e), true + return {'\u215e', 0}, 1, true case "frasl": // FRACTION SLASH - return rune(0x2044), true + return {'\u2044', 0}, 1, true case "frown": // FROWN - return rune(0x2322), true + return {'\u2322', 0}, 1, true case "fscr": // MATHEMATICAL SCRIPT SMALL F - return rune(0x01d4bb), true + return {'\U0001d4bb', 0}, 1, true } case 'g': switch name { case "gE": // GREATER-THAN OVER EQUAL TO - return rune(0x2267), true + return {'\u2267', 0}, 1, true case "gEl": // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN - return rune(0x2a8c), true + return {'\u2a8c', 0}, 1, true case "gacute": // LATIN SMALL LETTER G WITH ACUTE - return rune(0x01f5), true + return {'\u01f5', 0}, 1, true case "gamma": // GREEK SMALL LETTER GAMMA - return rune(0x03b3), true + return {'\u03b3', 0}, 1, true case "gammad": // GREEK SMALL LETTER DIGAMMA - return rune(0x03dd), true + return {'\u03dd', 0}, 1, true case "gap": // GREATER-THAN OR APPROXIMATE - return rune(0x2a86), true + return {'\u2a86', 0}, 1, true case "gbreve": // LATIN SMALL LETTER G WITH BREVE - return rune(0x011f), true + return {'\u011f', 0}, 1, true case "gcedil": // LATIN SMALL LETTER G WITH CEDILLA - return rune(0x0123), true + return {'\u0123', 0}, 1, true case "gcirc": // LATIN SMALL LETTER G WITH CIRCUMFLEX - return rune(0x011d), true + return {'\u011d', 0}, 1, true case "gcy": // CYRILLIC SMALL LETTER GHE - return rune(0x0433), true + return {'\u0433', 0}, 1, true case "gdot": // LATIN SMALL LETTER G WITH DOT ABOVE - return rune(0x0121), true + return {'\u0121', 0}, 1, true case "ge": // GREATER-THAN OR EQUAL TO - return rune(0x2265), true + return {'\u2265', 0}, 1, true case "gel": // GREATER-THAN EQUAL TO OR LESS-THAN - return rune(0x22db), true + return {'\u22db', 0}, 1, true case "geq": // GREATER-THAN OR EQUAL TO - return rune(0x2265), true + return {'\u2265', 0}, 1, true case "geqq": // GREATER-THAN OVER EQUAL TO - return rune(0x2267), true + return {'\u2267', 0}, 1, true case "geqslant": // GREATER-THAN OR SLANTED EQUAL TO - return rune(0x2a7e), true + return {'\u2a7e', 0}, 1, true case "ges": // GREATER-THAN OR SLANTED EQUAL TO - return rune(0x2a7e), true + return {'\u2a7e', 0}, 1, true case "gescc": // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL - return rune(0x2aa9), true + return {'\u2aa9', 0}, 1, true case "gesdot": // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE - return rune(0x2a80), true + return {'\u2a80', 0}, 1, true case "gesdoto": // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE - return rune(0x2a82), true + return {'\u2a82', 0}, 1, true case "gesdotol": // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT - return rune(0x2a84), true + return {'\u2a84', 0}, 1, true case "gesl": // GREATER-THAN slanted EQUAL TO OR LESS-THAN - return rune(0x22db), true + return {'\u22db', '\ufe00'}, 2, true case "gesles": // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL - return rune(0x2a94), true + return {'\u2a94', 0}, 1, true case "gfr": // MATHEMATICAL FRAKTUR SMALL G - return rune(0x01d524), true + return {'\U0001d524', 0}, 1, true case "gg": // MUCH GREATER-THAN - return rune(0x226b), true + return {'\u226b', 0}, 1, true case "ggg": // VERY MUCH GREATER-THAN - return rune(0x22d9), true + return {'\u22d9', 0}, 1, true case "ggr": // GREEK SMALL LETTER GAMMA - return rune(0x03b3), true + return {'\u03b3', 0}, 1, true case "gimel": // GIMEL SYMBOL - return rune(0x2137), true + return {'\u2137', 0}, 1, true case "gjcy": // CYRILLIC SMALL LETTER GJE - return rune(0x0453), true + return {'\u0453', 0}, 1, true case "gl": // GREATER-THAN OR LESS-THAN - return rune(0x2277), true + return {'\u2277', 0}, 1, true case "glE": // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL - return rune(0x2a92), true + return {'\u2a92', 0}, 1, true case "gla": // GREATER-THAN BESIDE LESS-THAN - return rune(0x2aa5), true + return {'\u2aa5', 0}, 1, true case "glj": // GREATER-THAN OVERLAPPING LESS-THAN - return rune(0x2aa4), true + return {'\u2aa4', 0}, 1, true case "gnE": // GREATER-THAN BUT NOT EQUAL TO - return rune(0x2269), true + return {'\u2269', 0}, 1, true case "gnap": // GREATER-THAN AND NOT APPROXIMATE - return rune(0x2a8a), true + return {'\u2a8a', 0}, 1, true case "gnapprox": // GREATER-THAN AND NOT APPROXIMATE - return rune(0x2a8a), true + return {'\u2a8a', 0}, 1, true case "gne": // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO - return rune(0x2a88), true + return {'\u2a88', 0}, 1, true case "gneq": // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO - return rune(0x2a88), true + return {'\u2a88', 0}, 1, true case "gneqq": // GREATER-THAN BUT NOT EQUAL TO - return rune(0x2269), true + return {'\u2269', 0}, 1, true case "gnsim": // GREATER-THAN BUT NOT EQUIVALENT TO - return rune(0x22e7), true + return {'\u22e7', 0}, 1, true case "gopf": // MATHEMATICAL DOUBLE-STRUCK SMALL G - return rune(0x01d558), true + return {'\U0001d558', 0}, 1, true case "grave": // GRAVE ACCENT - return rune(0x60), true + return {'`', 0}, 1, true case "gscr": // SCRIPT SMALL G - return rune(0x210a), true + return {'\u210a', 0}, 1, true case "gsdot": // GREATER-THAN WITH DOT - return rune(0x22d7), true + return {'\u22d7', 0}, 1, true case "gsim": // GREATER-THAN OR EQUIVALENT TO - return rune(0x2273), true + return {'\u2273', 0}, 1, true case "gsime": // GREATER-THAN ABOVE SIMILAR OR EQUAL - return rune(0x2a8e), true + return {'\u2a8e', 0}, 1, true case "gsiml": // GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN - return rune(0x2a90), true + return {'\u2a90', 0}, 1, true case "gt": // GREATER-THAN SIGN - return rune(0x3e), true + return {'>', 0}, 1, true case "gtcc": // GREATER-THAN CLOSED BY CURVE - return rune(0x2aa7), true + return {'\u2aa7', 0}, 1, true case "gtcir": // GREATER-THAN WITH CIRCLE INSIDE - return rune(0x2a7a), true + return {'\u2a7a', 0}, 1, true case "gtdot": // GREATER-THAN WITH DOT - return rune(0x22d7), true + return {'\u22d7', 0}, 1, true case "gtlPar": // DOUBLE LEFT ARC GREATER-THAN BRACKET - return rune(0x2995), true + return {'\u2995', 0}, 1, true case "gtquest": // GREATER-THAN WITH QUESTION MARK ABOVE - return rune(0x2a7c), true + return {'\u2a7c', 0}, 1, true case "gtrapprox": // GREATER-THAN OR APPROXIMATE - return rune(0x2a86), true + return {'\u2a86', 0}, 1, true case "gtrarr": // GREATER-THAN ABOVE RIGHTWARDS ARROW - return rune(0x2978), true + return {'\u2978', 0}, 1, true case "gtrdot": // GREATER-THAN WITH DOT - return rune(0x22d7), true + return {'\u22d7', 0}, 1, true case "gtreqless": // GREATER-THAN EQUAL TO OR LESS-THAN - return rune(0x22db), true + return {'\u22db', 0}, 1, true case "gtreqqless": // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN - return rune(0x2a8c), true + return {'\u2a8c', 0}, 1, true case "gtrless": // GREATER-THAN OR LESS-THAN - return rune(0x2277), true + return {'\u2277', 0}, 1, true case "gtrpar": // SPHERICAL ANGLE OPENING LEFT - return rune(0x29a0), true + return {'\u29a0', 0}, 1, true case "gtrsim": // GREATER-THAN OR EQUIVALENT TO - return rune(0x2273), true + return {'\u2273', 0}, 1, true case "gvertneqq": // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke - return rune(0x2269), true + return {'\u2269', '\ufe00'}, 2, true case "gvnE": // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke - return rune(0x2269), true + return {'\u2269', '\ufe00'}, 2, true } case 'h': switch name { case "hArr": // LEFT RIGHT DOUBLE ARROW - return rune(0x21d4), true + return {'\u21d4', 0}, 1, true case "hairsp": // HAIR SPACE - return rune(0x200a), true + return {'\u200a', 0}, 1, true case "half": // VULGAR FRACTION ONE HALF - return rune(0xbd), true + return {'½', 0}, 1, true case "hamilt": // SCRIPT CAPITAL H - return rune(0x210b), true + return {'\u210b', 0}, 1, true case "hardcy": // CYRILLIC SMALL LETTER HARD SIGN - return rune(0x044a), true + return {'\u044a', 0}, 1, true case "harr": // LEFT RIGHT ARROW - return rune(0x2194), true + return {'\u2194', 0}, 1, true case "harrcir": // LEFT RIGHT ARROW THROUGH SMALL CIRCLE - return rune(0x2948), true + return {'\u2948', 0}, 1, true case "harrw": // LEFT RIGHT WAVE ARROW - return rune(0x21ad), true + return {'\u21ad', 0}, 1, true case "hbar": // PLANCK CONSTANT OVER TWO PI - return rune(0x210f), true + return {'\u210f', 0}, 1, true case "hcirc": // LATIN SMALL LETTER H WITH CIRCUMFLEX - return rune(0x0125), true + return {'\u0125', 0}, 1, true case "hearts": // BLACK HEART SUIT - return rune(0x2665), true + return {'\u2665', 0}, 1, true case "heartsuit": // BLACK HEART SUIT - return rune(0x2665), true + return {'\u2665', 0}, 1, true case "hellip": // HORIZONTAL ELLIPSIS - return rune(0x2026), true + return {'\u2026', 0}, 1, true case "hercon": // HERMITIAN CONJUGATE MATRIX - return rune(0x22b9), true + return {'\u22b9', 0}, 1, true case "hfr": // MATHEMATICAL FRAKTUR SMALL H - return rune(0x01d525), true + return {'\U0001d525', 0}, 1, true case "hksearow": // SOUTH EAST ARROW WITH HOOK - return rune(0x2925), true + return {'\u2925', 0}, 1, true case "hkswarow": // SOUTH WEST ARROW WITH HOOK - return rune(0x2926), true + return {'\u2926', 0}, 1, true case "hoarr": // LEFT RIGHT OPEN-HEADED ARROW - return rune(0x21ff), true + return {'\u21ff', 0}, 1, true case "homtht": // HOMOTHETIC - return rune(0x223b), true + return {'\u223b', 0}, 1, true case "hookleftarrow": // LEFTWARDS ARROW WITH HOOK - return rune(0x21a9), true + return {'\u21a9', 0}, 1, true case "hookrightarrow": // RIGHTWARDS ARROW WITH HOOK - return rune(0x21aa), true + return {'\u21aa', 0}, 1, true case "hopf": // MATHEMATICAL DOUBLE-STRUCK SMALL H - return rune(0x01d559), true + return {'\U0001d559', 0}, 1, true case "horbar": // HORIZONTAL BAR - return rune(0x2015), true + return {'\u2015', 0}, 1, true case "hrglass": // WHITE HOURGLASS - return rune(0x29d6), true + return {'\u29d6', 0}, 1, true case "hscr": // MATHEMATICAL SCRIPT SMALL H - return rune(0x01d4bd), true + return {'\U0001d4bd', 0}, 1, true case "hslash": // PLANCK CONSTANT OVER TWO PI - return rune(0x210f), true + return {'\u210f', 0}, 1, true case "hstrok": // LATIN SMALL LETTER H WITH STROKE - return rune(0x0127), true + return {'\u0127', 0}, 1, true case "htimes": // VECTOR OR CROSS PRODUCT - return rune(0x2a2f), true + return {'\u2a2f', 0}, 1, true case "hybull": // HYPHEN BULLET - return rune(0x2043), true + return {'\u2043', 0}, 1, true case "hyphen": // HYPHEN - return rune(0x2010), true + return {'\u2010', 0}, 1, true } case 'i': switch name { case "iacgr": // GREEK SMALL LETTER IOTA WITH TONOS - return rune(0x03af), true + return {'\u03af', 0}, 1, true case "iacute": // LATIN SMALL LETTER I WITH ACUTE - return rune(0xed), true + return {'í', 0}, 1, true case "ic": // INVISIBLE SEPARATOR - return rune(0x2063), true + return {'\u2063', 0}, 1, true case "icirc": // LATIN SMALL LETTER I WITH CIRCUMFLEX - return rune(0xee), true + return {'î', 0}, 1, true case "icy": // CYRILLIC SMALL LETTER I - return rune(0x0438), true + return {'\u0438', 0}, 1, true case "idiagr": // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS - return rune(0x0390), true + return {'\u0390', 0}, 1, true case "idigr": // GREEK SMALL LETTER IOTA WITH DIALYTIKA - return rune(0x03ca), true + return {'\u03ca', 0}, 1, true case "iecy": // CYRILLIC SMALL LETTER IE - return rune(0x0435), true + return {'\u0435', 0}, 1, true case "iexcl": // INVERTED EXCLAMATION MARK - return rune(0xa1), true + return {'¡', 0}, 1, true case "iff": // LEFT RIGHT DOUBLE ARROW - return rune(0x21d4), true + return {'\u21d4', 0}, 1, true case "ifr": // MATHEMATICAL FRAKTUR SMALL I - return rune(0x01d526), true + return {'\U0001d526', 0}, 1, true case "igr": // GREEK SMALL LETTER IOTA - return rune(0x03b9), true + return {'\u03b9', 0}, 1, true case "igrave": // LATIN SMALL LETTER I WITH GRAVE - return rune(0xec), true + return {'ì', 0}, 1, true case "ii": // DOUBLE-STRUCK ITALIC SMALL I - return rune(0x2148), true + return {'\u2148', 0}, 1, true case "iiiint": // QUADRUPLE INTEGRAL OPERATOR - return rune(0x2a0c), true + return {'\u2a0c', 0}, 1, true case "iiint": // TRIPLE INTEGRAL - return rune(0x222d), true + return {'\u222d', 0}, 1, true case "iinfin": // INCOMPLETE INFINITY - return rune(0x29dc), true + return {'\u29dc', 0}, 1, true case "iiota": // TURNED GREEK SMALL LETTER IOTA - return rune(0x2129), true + return {'\u2129', 0}, 1, true case "ijlig": // LATIN SMALL LIGATURE IJ - return rune(0x0133), true + return {'\u0133', 0}, 1, true case "imacr": // LATIN SMALL LETTER I WITH MACRON - return rune(0x012b), true + return {'\u012b', 0}, 1, true case "image": // BLACK-LETTER CAPITAL I - return rune(0x2111), true + return {'\u2111', 0}, 1, true case "imagline": // SCRIPT CAPITAL I - return rune(0x2110), true + return {'\u2110', 0}, 1, true case "imagpart": // BLACK-LETTER CAPITAL I - return rune(0x2111), true + return {'\u2111', 0}, 1, true case "imath": // LATIN SMALL LETTER DOTLESS I - return rune(0x0131), true + return {'\u0131', 0}, 1, true case "imof": // IMAGE OF - return rune(0x22b7), true + return {'\u22b7', 0}, 1, true case "imped": // LATIN CAPITAL LETTER Z WITH STROKE - return rune(0x01b5), true + return {'\u01b5', 0}, 1, true case "in": // ELEMENT OF - return rune(0x2208), true + return {'\u2208', 0}, 1, true case "incare": // CARE OF - return rune(0x2105), true + return {'\u2105', 0}, 1, true case "infin": // INFINITY - return rune(0x221e), true + return {'\u221e', 0}, 1, true case "infintie": // TIE OVER INFINITY - return rune(0x29dd), true + return {'\u29dd', 0}, 1, true case "inodot": // LATIN SMALL LETTER DOTLESS I - return rune(0x0131), true + return {'\u0131', 0}, 1, true case "int": // INTEGRAL - return rune(0x222b), true + return {'\u222b', 0}, 1, true case "intcal": // INTERCALATE - return rune(0x22ba), true + return {'\u22ba', 0}, 1, true case "integers": // DOUBLE-STRUCK CAPITAL Z - return rune(0x2124), true + return {'\u2124', 0}, 1, true case "intercal": // INTERCALATE - return rune(0x22ba), true + return {'\u22ba', 0}, 1, true case "intlarhk": // INTEGRAL WITH LEFTWARDS ARROW WITH HOOK - return rune(0x2a17), true + return {'\u2a17', 0}, 1, true case "intprod": // INTERIOR PRODUCT - return rune(0x2a3c), true + return {'\u2a3c', 0}, 1, true case "iocy": // CYRILLIC SMALL LETTER IO - return rune(0x0451), true + return {'\u0451', 0}, 1, true case "iogon": // LATIN SMALL LETTER I WITH OGONEK - return rune(0x012f), true + return {'\u012f', 0}, 1, true case "iopf": // MATHEMATICAL DOUBLE-STRUCK SMALL I - return rune(0x01d55a), true + return {'\U0001d55a', 0}, 1, true case "iota": // GREEK SMALL LETTER IOTA - return rune(0x03b9), true + return {'\u03b9', 0}, 1, true case "iprod": // INTERIOR PRODUCT - return rune(0x2a3c), true + return {'\u2a3c', 0}, 1, true case "iprodr": // RIGHTHAND INTERIOR PRODUCT - return rune(0x2a3d), true + return {'\u2a3d', 0}, 1, true case "iquest": // INVERTED QUESTION MARK - return rune(0xbf), true + return {'¿', 0}, 1, true case "iscr": // MATHEMATICAL SCRIPT SMALL I - return rune(0x01d4be), true + return {'\U0001d4be', 0}, 1, true case "isin": // ELEMENT OF - return rune(0x2208), true + return {'\u2208', 0}, 1, true case "isinE": // ELEMENT OF WITH TWO HORIZONTAL STROKES - return rune(0x22f9), true + return {'\u22f9', 0}, 1, true case "isindot": // ELEMENT OF WITH DOT ABOVE - return rune(0x22f5), true + return {'\u22f5', 0}, 1, true case "isins": // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE - return rune(0x22f4), true + return {'\u22f4', 0}, 1, true case "isinsv": // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE - return rune(0x22f3), true + return {'\u22f3', 0}, 1, true case "isinv": // ELEMENT OF - return rune(0x2208), true + return {'\u2208', 0}, 1, true case "isinvb": // ELEMENT OF WITH UNDERBAR - return rune(0x22f8), true + return {'\u22f8', 0}, 1, true case "it": // INVISIBLE TIMES - return rune(0x2062), true + return {'\u2062', 0}, 1, true case "itilde": // LATIN SMALL LETTER I WITH TILDE - return rune(0x0129), true + return {'\u0129', 0}, 1, true case "iukcy": // CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I - return rune(0x0456), true + return {'\u0456', 0}, 1, true case "iuml": // LATIN SMALL LETTER I WITH DIAERESIS - return rune(0xef), true + return {'ï', 0}, 1, true } case 'j': switch name { case "jcirc": // LATIN SMALL LETTER J WITH CIRCUMFLEX - return rune(0x0135), true + return {'\u0135', 0}, 1, true case "jcy": // CYRILLIC SMALL LETTER SHORT I - return rune(0x0439), true + return {'\u0439', 0}, 1, true case "jfr": // MATHEMATICAL FRAKTUR SMALL J - return rune(0x01d527), true + return {'\U0001d527', 0}, 1, true case "jmath": // LATIN SMALL LETTER DOTLESS J - return rune(0x0237), true + return {'\u0237', 0}, 1, true case "jnodot": // LATIN SMALL LETTER DOTLESS J - return rune(0x0237), true + return {'\u0237', 0}, 1, true case "jopf": // MATHEMATICAL DOUBLE-STRUCK SMALL J - return rune(0x01d55b), true + return {'\U0001d55b', 0}, 1, true case "jscr": // MATHEMATICAL SCRIPT SMALL J - return rune(0x01d4bf), true + return {'\U0001d4bf', 0}, 1, true case "jsercy": // CYRILLIC SMALL LETTER JE - return rune(0x0458), true + return {'\u0458', 0}, 1, true case "jukcy": // CYRILLIC SMALL LETTER UKRAINIAN IE - return rune(0x0454), true + return {'\u0454', 0}, 1, true } case 'k': switch name { case "kappa": // GREEK SMALL LETTER KAPPA - return rune(0x03ba), true + return {'\u03ba', 0}, 1, true case "kappav": // GREEK KAPPA SYMBOL - return rune(0x03f0), true + return {'\u03f0', 0}, 1, true case "kcedil": // LATIN SMALL LETTER K WITH CEDILLA - return rune(0x0137), true + return {'\u0137', 0}, 1, true case "kcy": // CYRILLIC SMALL LETTER KA - return rune(0x043a), true + return {'\u043a', 0}, 1, true case "kfr": // MATHEMATICAL FRAKTUR SMALL K - return rune(0x01d528), true + return {'\U0001d528', 0}, 1, true case "kgr": // GREEK SMALL LETTER KAPPA - return rune(0x03ba), true + return {'\u03ba', 0}, 1, true case "kgreen": // LATIN SMALL LETTER KRA - return rune(0x0138), true + return {'\u0138', 0}, 1, true case "khcy": // CYRILLIC SMALL LETTER HA - return rune(0x0445), true + return {'\u0445', 0}, 1, true case "khgr": // GREEK SMALL LETTER CHI - return rune(0x03c7), true + return {'\u03c7', 0}, 1, true case "kjcy": // CYRILLIC SMALL LETTER KJE - return rune(0x045c), true + return {'\u045c', 0}, 1, true case "kopf": // MATHEMATICAL DOUBLE-STRUCK SMALL K - return rune(0x01d55c), true + return {'\U0001d55c', 0}, 1, true case "koppa": // GREEK LETTER KOPPA - return rune(0x03de), true + return {'\u03de', 0}, 1, true case "kscr": // MATHEMATICAL SCRIPT SMALL K - return rune(0x01d4c0), true + return {'\U0001d4c0', 0}, 1, true } case 'l': switch name { case "lAarr": // LEFTWARDS TRIPLE ARROW - return rune(0x21da), true + return {'\u21da', 0}, 1, true case "lArr": // LEFTWARDS DOUBLE ARROW - return rune(0x21d0), true + return {'\u21d0', 0}, 1, true case "lAtail": // LEFTWARDS DOUBLE ARROW-TAIL - return rune(0x291b), true + return {'\u291b', 0}, 1, true case "lBarr": // LEFTWARDS TRIPLE DASH ARROW - return rune(0x290e), true + return {'\u290e', 0}, 1, true case "lE": // LESS-THAN OVER EQUAL TO - return rune(0x2266), true + return {'\u2266', 0}, 1, true case "lEg": // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN - return rune(0x2a8b), true + return {'\u2a8b', 0}, 1, true case "lHar": // LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN - return rune(0x2962), true + return {'\u2962', 0}, 1, true case "lacute": // LATIN SMALL LETTER L WITH ACUTE - return rune(0x013a), true + return {'\u013a', 0}, 1, true case "laemptyv": // EMPTY SET WITH LEFT ARROW ABOVE - return rune(0x29b4), true + return {'\u29b4', 0}, 1, true case "lagran": // SCRIPT CAPITAL L - return rune(0x2112), true + return {'\u2112', 0}, 1, true case "lambda": // GREEK SMALL LETTER LAMDA - return rune(0x03bb), true + return {'\u03bb', 0}, 1, true case "lang": // MATHEMATICAL LEFT ANGLE BRACKET - return rune(0x27e8), true + return {'\u27e8', 0}, 1, true case "langd": // LEFT ANGLE BRACKET WITH DOT - return rune(0x2991), true + return {'\u2991', 0}, 1, true case "langle": // MATHEMATICAL LEFT ANGLE BRACKET - return rune(0x27e8), true + return {'\u27e8', 0}, 1, true case "lap": // LESS-THAN OR APPROXIMATE - return rune(0x2a85), true + return {'\u2a85', 0}, 1, true case "laquo": // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - return rune(0xab), true + return {'«', 0}, 1, true case "larr": // LEFTWARDS ARROW - return rune(0x2190), true + return {'\u2190', 0}, 1, true case "larr2": // LEFTWARDS PAIRED ARROWS - return rune(0x21c7), true + return {'\u21c7', 0}, 1, true case "larrb": // LEFTWARDS ARROW TO BAR - return rune(0x21e4), true + return {'\u21e4', 0}, 1, true case "larrbfs": // LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND - return rune(0x291f), true + return {'\u291f', 0}, 1, true case "larrfs": // LEFTWARDS ARROW TO BLACK DIAMOND - return rune(0x291d), true + return {'\u291d', 0}, 1, true case "larrhk": // LEFTWARDS ARROW WITH HOOK - return rune(0x21a9), true + return {'\u21a9', 0}, 1, true case "larrlp": // LEFTWARDS ARROW WITH LOOP - return rune(0x21ab), true + return {'\u21ab', 0}, 1, true case "larrpl": // LEFT-SIDE ARC ANTICLOCKWISE ARROW - return rune(0x2939), true + return {'\u2939', 0}, 1, true case "larrsim": // LEFTWARDS ARROW ABOVE TILDE OPERATOR - return rune(0x2973), true + return {'\u2973', 0}, 1, true case "larrtl": // LEFTWARDS ARROW WITH TAIL - return rune(0x21a2), true + return {'\u21a2', 0}, 1, true case "lat": // LARGER THAN - return rune(0x2aab), true + return {'\u2aab', 0}, 1, true case "latail": // LEFTWARDS ARROW-TAIL - return rune(0x2919), true + return {'\u2919', 0}, 1, true case "late": // LARGER THAN OR EQUAL TO - return rune(0x2aad), true + return {'\u2aad', 0}, 1, true case "lates": // LARGER THAN OR slanted EQUAL - return rune(0x2aad), true + return {'\u2aad', '\ufe00'}, 2, true case "lbarr": // LEFTWARDS DOUBLE DASH ARROW - return rune(0x290c), true + return {'\u290c', 0}, 1, true case "lbbrk": // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT - return rune(0x2772), true + return {'\u2772', 0}, 1, true case "lbrace": // LEFT CURLY BRACKET - return rune(0x7b), true + return {'{', 0}, 1, true case "lbrack": // LEFT SQUARE BRACKET - return rune(0x5b), true + return {'[', 0}, 1, true case "lbrke": // LEFT SQUARE BRACKET WITH UNDERBAR - return rune(0x298b), true + return {'\u298b', 0}, 1, true case "lbrksld": // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER - return rune(0x298f), true + return {'\u298f', 0}, 1, true case "lbrkslu": // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER - return rune(0x298d), true + return {'\u298d', 0}, 1, true case "lcaron": // LATIN SMALL LETTER L WITH CARON - return rune(0x013e), true + return {'\u013e', 0}, 1, true case "lcedil": // LATIN SMALL LETTER L WITH CEDILLA - return rune(0x013c), true + return {'\u013c', 0}, 1, true case "lceil": // LEFT CEILING - return rune(0x2308), true + return {'\u2308', 0}, 1, true case "lcub": // LEFT CURLY BRACKET - return rune(0x7b), true + return {'{', 0}, 1, true case "lcy": // CYRILLIC SMALL LETTER EL - return rune(0x043b), true + return {'\u043b', 0}, 1, true case "ldca": // ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS - return rune(0x2936), true + return {'\u2936', 0}, 1, true case "ldharb": // LEFTWARDS HARPOON WITH BARB DOWN TO BAR - return rune(0x2956), true + return {'\u2956', 0}, 1, true case "ldot": // LESS-THAN WITH DOT - return rune(0x22d6), true + return {'\u22d6', 0}, 1, true case "ldquo": // LEFT DOUBLE QUOTATION MARK - return rune(0x201c), true + return {'\u201c', 0}, 1, true case "ldquor": // DOUBLE LOW-9 QUOTATION MARK - return rune(0x201e), true + return {'\u201e', 0}, 1, true case "ldrdhar": // LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN - return rune(0x2967), true + return {'\u2967', 0}, 1, true case "ldrdshar": // LEFT BARB DOWN RIGHT BARB DOWN HARPOON - return rune(0x2950), true + return {'\u2950', 0}, 1, true case "ldrushar": // LEFT BARB DOWN RIGHT BARB UP HARPOON - return rune(0x294b), true + return {'\u294b', 0}, 1, true case "ldsh": // DOWNWARDS ARROW WITH TIP LEFTWARDS - return rune(0x21b2), true + return {'\u21b2', 0}, 1, true case "le": // LESS-THAN OR EQUAL TO - return rune(0x2264), true + return {'\u2264', 0}, 1, true case "leftarrow": // LEFTWARDS ARROW - return rune(0x2190), true + return {'\u2190', 0}, 1, true case "leftarrowtail": // LEFTWARDS ARROW WITH TAIL - return rune(0x21a2), true + return {'\u21a2', 0}, 1, true case "leftharpoondown": // LEFTWARDS HARPOON WITH BARB DOWNWARDS - return rune(0x21bd), true + return {'\u21bd', 0}, 1, true case "leftharpoonup": // LEFTWARDS HARPOON WITH BARB UPWARDS - return rune(0x21bc), true + return {'\u21bc', 0}, 1, true case "leftleftarrows": // LEFTWARDS PAIRED ARROWS - return rune(0x21c7), true + return {'\u21c7', 0}, 1, true case "leftrightarrow": // LEFT RIGHT ARROW - return rune(0x2194), true + return {'\u2194', 0}, 1, true case "leftrightarrows": // LEFTWARDS ARROW OVER RIGHTWARDS ARROW - return rune(0x21c6), true + return {'\u21c6', 0}, 1, true case "leftrightharpoons": // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON - return rune(0x21cb), true + return {'\u21cb', 0}, 1, true case "leftrightsquigarrow": // LEFT RIGHT WAVE ARROW - return rune(0x21ad), true + return {'\u21ad', 0}, 1, true case "leftthreetimes": // LEFT SEMIDIRECT PRODUCT - return rune(0x22cb), true + return {'\u22cb', 0}, 1, true case "leg": // LESS-THAN EQUAL TO OR GREATER-THAN - return rune(0x22da), true + return {'\u22da', 0}, 1, true case "leq": // LESS-THAN OR EQUAL TO - return rune(0x2264), true + return {'\u2264', 0}, 1, true case "leqq": // LESS-THAN OVER EQUAL TO - return rune(0x2266), true + return {'\u2266', 0}, 1, true case "leqslant": // LESS-THAN OR SLANTED EQUAL TO - return rune(0x2a7d), true + return {'\u2a7d', 0}, 1, true case "les": // LESS-THAN OR SLANTED EQUAL TO - return rune(0x2a7d), true + return {'\u2a7d', 0}, 1, true case "lescc": // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL - return rune(0x2aa8), true + return {'\u2aa8', 0}, 1, true case "lesdot": // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE - return rune(0x2a7f), true + return {'\u2a7f', 0}, 1, true case "lesdoto": // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE - return rune(0x2a81), true + return {'\u2a81', 0}, 1, true case "lesdotor": // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT - return rune(0x2a83), true + return {'\u2a83', 0}, 1, true case "lesg": // LESS-THAN slanted EQUAL TO OR GREATER-THAN - return rune(0x22da), true + return {'\u22da', '\ufe00'}, 2, true case "lesges": // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL - return rune(0x2a93), true + return {'\u2a93', 0}, 1, true case "lessapprox": // LESS-THAN OR APPROXIMATE - return rune(0x2a85), true + return {'\u2a85', 0}, 1, true case "lessdot": // LESS-THAN WITH DOT - return rune(0x22d6), true + return {'\u22d6', 0}, 1, true case "lesseqgtr": // LESS-THAN EQUAL TO OR GREATER-THAN - return rune(0x22da), true + return {'\u22da', 0}, 1, true case "lesseqqgtr": // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN - return rune(0x2a8b), true + return {'\u2a8b', 0}, 1, true case "lessgtr": // LESS-THAN OR GREATER-THAN - return rune(0x2276), true + return {'\u2276', 0}, 1, true case "lesssim": // LESS-THAN OR EQUIVALENT TO - return rune(0x2272), true + return {'\u2272', 0}, 1, true case "lfbowtie": // BOWTIE WITH LEFT HALF BLACK - return rune(0x29d1), true + return {'\u29d1', 0}, 1, true case "lfisht": // LEFT FISH TAIL - return rune(0x297c), true + return {'\u297c', 0}, 1, true case "lfloor": // LEFT FLOOR - return rune(0x230a), true + return {'\u230a', 0}, 1, true case "lfr": // MATHEMATICAL FRAKTUR SMALL L - return rune(0x01d529), true + return {'\U0001d529', 0}, 1, true case "lftimes": // TIMES WITH LEFT HALF BLACK - return rune(0x29d4), true + return {'\u29d4', 0}, 1, true case "lg": // LESS-THAN OR GREATER-THAN - return rune(0x2276), true + return {'\u2276', 0}, 1, true case "lgE": // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL - return rune(0x2a91), true + return {'\u2a91', 0}, 1, true case "lgr": // GREEK SMALL LETTER LAMDA - return rune(0x03bb), true + return {'\u03bb', 0}, 1, true case "lhard": // LEFTWARDS HARPOON WITH BARB DOWNWARDS - return rune(0x21bd), true + return {'\u21bd', 0}, 1, true case "lharu": // LEFTWARDS HARPOON WITH BARB UPWARDS - return rune(0x21bc), true + return {'\u21bc', 0}, 1, true case "lharul": // LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH - return rune(0x296a), true + return {'\u296a', 0}, 1, true case "lhblk": // LOWER HALF BLOCK - return rune(0x2584), true + return {'\u2584', 0}, 1, true case "ljcy": // CYRILLIC SMALL LETTER LJE - return rune(0x0459), true + return {'\u0459', 0}, 1, true case "ll": // MUCH LESS-THAN - return rune(0x226a), true + return {'\u226a', 0}, 1, true case "llarr": // LEFTWARDS PAIRED ARROWS - return rune(0x21c7), true + return {'\u21c7', 0}, 1, true case "llcorner": // BOTTOM LEFT CORNER - return rune(0x231e), true + return {'\u231e', 0}, 1, true case "llhard": // LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH - return rune(0x296b), true + return {'\u296b', 0}, 1, true case "lltri": // LOWER LEFT TRIANGLE - return rune(0x25fa), true + return {'\u25fa', 0}, 1, true case "lltrif": // BLACK LOWER LEFT TRIANGLE - return rune(0x25e3), true + return {'\u25e3', 0}, 1, true case "lmidot": // LATIN SMALL LETTER L WITH MIDDLE DOT - return rune(0x0140), true + return {'\u0140', 0}, 1, true case "lmoust": // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION - return rune(0x23b0), true + return {'\u23b0', 0}, 1, true case "lmoustache": // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION - return rune(0x23b0), true + return {'\u23b0', 0}, 1, true case "lnE": // LESS-THAN BUT NOT EQUAL TO - return rune(0x2268), true + return {'\u2268', 0}, 1, true case "lnap": // LESS-THAN AND NOT APPROXIMATE - return rune(0x2a89), true + return {'\u2a89', 0}, 1, true case "lnapprox": // LESS-THAN AND NOT APPROXIMATE - return rune(0x2a89), true + return {'\u2a89', 0}, 1, true case "lne": // LESS-THAN AND SINGLE-LINE NOT EQUAL TO - return rune(0x2a87), true + return {'\u2a87', 0}, 1, true case "lneq": // LESS-THAN AND SINGLE-LINE NOT EQUAL TO - return rune(0x2a87), true + return {'\u2a87', 0}, 1, true case "lneqq": // LESS-THAN BUT NOT EQUAL TO - return rune(0x2268), true + return {'\u2268', 0}, 1, true case "lnsim": // LESS-THAN BUT NOT EQUIVALENT TO - return rune(0x22e6), true + return {'\u22e6', 0}, 1, true case "loang": // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET - return rune(0x27ec), true + return {'\u27ec', 0}, 1, true case "loarr": // LEFTWARDS OPEN-HEADED ARROW - return rune(0x21fd), true + return {'\u21fd', 0}, 1, true case "lobrk": // MATHEMATICAL LEFT WHITE SQUARE BRACKET - return rune(0x27e6), true + return {'\u27e6', 0}, 1, true case "locub": // LEFT WHITE CURLY BRACKET - return rune(0x2983), true + return {'\u2983', 0}, 1, true case "longleftarrow": // LONG LEFTWARDS ARROW - return rune(0x27f5), true + return {'\u27f5', 0}, 1, true case "longleftrightarrow": // LONG LEFT RIGHT ARROW - return rune(0x27f7), true + return {'\u27f7', 0}, 1, true case "longmapsto": // LONG RIGHTWARDS ARROW FROM BAR - return rune(0x27fc), true + return {'\u27fc', 0}, 1, true case "longrightarrow": // LONG RIGHTWARDS ARROW - return rune(0x27f6), true + return {'\u27f6', 0}, 1, true case "looparrowleft": // LEFTWARDS ARROW WITH LOOP - return rune(0x21ab), true + return {'\u21ab', 0}, 1, true case "looparrowright": // RIGHTWARDS ARROW WITH LOOP - return rune(0x21ac), true + return {'\u21ac', 0}, 1, true case "lopar": // LEFT WHITE PARENTHESIS - return rune(0x2985), true + return {'\u2985', 0}, 1, true case "lopf": // MATHEMATICAL DOUBLE-STRUCK SMALL L - return rune(0x01d55d), true + return {'\U0001d55d', 0}, 1, true case "loplus": // PLUS SIGN IN LEFT HALF CIRCLE - return rune(0x2a2d), true + return {'\u2a2d', 0}, 1, true case "lotimes": // MULTIPLICATION SIGN IN LEFT HALF CIRCLE - return rune(0x2a34), true + return {'\u2a34', 0}, 1, true case "lowast": // LOW ASTERISK - return rune(0x204e), true + return {'\u204e', 0}, 1, true case "lowbar": // LOW LINE - return rune(0x5f), true + return {'_', 0}, 1, true case "lowint": // INTEGRAL WITH UNDERBAR - return rune(0x2a1c), true + return {'\u2a1c', 0}, 1, true case "loz": // LOZENGE - return rune(0x25ca), true + return {'\u25ca', 0}, 1, true case "lozenge": // LOZENGE - return rune(0x25ca), true + return {'\u25ca', 0}, 1, true case "lozf": // BLACK LOZENGE - return rune(0x29eb), true + return {'\u29eb', 0}, 1, true case "lpar": // LEFT PARENTHESIS - return rune(0x28), true + return {'(', 0}, 1, true case "lpargt": // SPHERICAL ANGLE OPENING LEFT - return rune(0x29a0), true + return {'\u29a0', 0}, 1, true case "lparlt": // LEFT ARC LESS-THAN BRACKET - return rune(0x2993), true + return {'\u2993', 0}, 1, true case "lrarr": // LEFTWARDS ARROW OVER RIGHTWARDS ARROW - return rune(0x21c6), true + return {'\u21c6', 0}, 1, true case "lrarr2": // LEFTWARDS ARROW OVER RIGHTWARDS ARROW - return rune(0x21c6), true + return {'\u21c6', 0}, 1, true case "lrcorner": // BOTTOM RIGHT CORNER - return rune(0x231f), true + return {'\u231f', 0}, 1, true case "lrhar": // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON - return rune(0x21cb), true + return {'\u21cb', 0}, 1, true case "lrhar2": // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON - return rune(0x21cb), true + return {'\u21cb', 0}, 1, true case "lrhard": // RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH - return rune(0x296d), true + return {'\u296d', 0}, 1, true case "lrm": // LEFT-TO-RIGHT MARK - return rune(0x200e), true + return {'\u200e', 0}, 1, true case "lrtri": // RIGHT TRIANGLE - return rune(0x22bf), true + return {'\u22bf', 0}, 1, true case "lsaquo": // SINGLE LEFT-POINTING ANGLE QUOTATION MARK - return rune(0x2039), true + return {'\u2039', 0}, 1, true case "lscr": // MATHEMATICAL SCRIPT SMALL L - return rune(0x01d4c1), true + return {'\U0001d4c1', 0}, 1, true case "lsh": // UPWARDS ARROW WITH TIP LEFTWARDS - return rune(0x21b0), true + return {'\u21b0', 0}, 1, true case "lsim": // LESS-THAN OR EQUIVALENT TO - return rune(0x2272), true + return {'\u2272', 0}, 1, true case "lsime": // LESS-THAN ABOVE SIMILAR OR EQUAL - return rune(0x2a8d), true + return {'\u2a8d', 0}, 1, true case "lsimg": // LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN - return rune(0x2a8f), true + return {'\u2a8f', 0}, 1, true case "lsqb": // LEFT SQUARE BRACKET - return rune(0x5b), true + return {'[', 0}, 1, true case "lsquo": // LEFT SINGLE QUOTATION MARK - return rune(0x2018), true + return {'\u2018', 0}, 1, true case "lsquor": // SINGLE LOW-9 QUOTATION MARK - return rune(0x201a), true + return {'\u201a', 0}, 1, true case "lstrok": // LATIN SMALL LETTER L WITH STROKE - return rune(0x0142), true + return {'\u0142', 0}, 1, true case "lt": // LESS-THAN SIGN - return rune(0x3c), true + return {'<', 0}, 1, true case "ltcc": // LESS-THAN CLOSED BY CURVE - return rune(0x2aa6), true + return {'\u2aa6', 0}, 1, true case "ltcir": // LESS-THAN WITH CIRCLE INSIDE - return rune(0x2a79), true + return {'\u2a79', 0}, 1, true case "ltdot": // LESS-THAN WITH DOT - return rune(0x22d6), true + return {'\u22d6', 0}, 1, true case "lthree": // LEFT SEMIDIRECT PRODUCT - return rune(0x22cb), true + return {'\u22cb', 0}, 1, true case "ltimes": // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT - return rune(0x22c9), true + return {'\u22c9', 0}, 1, true case "ltlarr": // LESS-THAN ABOVE LEFTWARDS ARROW - return rune(0x2976), true + return {'\u2976', 0}, 1, true case "ltquest": // LESS-THAN WITH QUESTION MARK ABOVE - return rune(0x2a7b), true + return {'\u2a7b', 0}, 1, true case "ltrPar": // DOUBLE RIGHT ARC LESS-THAN BRACKET - return rune(0x2996), true + return {'\u2996', 0}, 1, true case "ltri": // WHITE LEFT-POINTING SMALL TRIANGLE - return rune(0x25c3), true + return {'\u25c3', 0}, 1, true case "ltrie": // NORMAL SUBGROUP OF OR EQUAL TO - return rune(0x22b4), true + return {'\u22b4', 0}, 1, true case "ltrif": // BLACK LEFT-POINTING SMALL TRIANGLE - return rune(0x25c2), true + return {'\u25c2', 0}, 1, true case "ltrivb": // LEFT TRIANGLE BESIDE VERTICAL BAR - return rune(0x29cf), true + return {'\u29cf', 0}, 1, true case "luharb": // LEFTWARDS HARPOON WITH BARB UP TO BAR - return rune(0x2952), true + return {'\u2952', 0}, 1, true case "lurdshar": // LEFT BARB UP RIGHT BARB DOWN HARPOON - return rune(0x294a), true + return {'\u294a', 0}, 1, true case "luruhar": // LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP - return rune(0x2966), true + return {'\u2966', 0}, 1, true case "lurushar": // LEFT BARB UP RIGHT BARB UP HARPOON - return rune(0x294e), true + return {'\u294e', 0}, 1, true case "lvertneqq": // LESS-THAN BUT NOT EQUAL TO - with vertical stroke - return rune(0x2268), true + return {'\u2268', '\ufe00'}, 2, true case "lvnE": // LESS-THAN BUT NOT EQUAL TO - with vertical stroke - return rune(0x2268), true + return {'\u2268', '\ufe00'}, 2, true } case 'm': switch name { case "mDDot": // GEOMETRIC PROPORTION - return rune(0x223a), true + return {'\u223a', 0}, 1, true case "macr": // MACRON - return rune(0xaf), true + return {'¯', 0}, 1, true case "male": // MALE SIGN - return rune(0x2642), true + return {'\u2642', 0}, 1, true case "malt": // MALTESE CROSS - return rune(0x2720), true + return {'\u2720', 0}, 1, true case "maltese": // MALTESE CROSS - return rune(0x2720), true + return {'\u2720', 0}, 1, true case "map": // RIGHTWARDS ARROW FROM BAR - return rune(0x21a6), true + return {'\u21a6', 0}, 1, true case "mapsto": // RIGHTWARDS ARROW FROM BAR - return rune(0x21a6), true + return {'\u21a6', 0}, 1, true case "mapstodown": // DOWNWARDS ARROW FROM BAR - return rune(0x21a7), true + return {'\u21a7', 0}, 1, true case "mapstoleft": // LEFTWARDS ARROW FROM BAR - return rune(0x21a4), true + return {'\u21a4', 0}, 1, true case "mapstoup": // UPWARDS ARROW FROM BAR - return rune(0x21a5), true + return {'\u21a5', 0}, 1, true case "marker": // BLACK VERTICAL RECTANGLE - return rune(0x25ae), true + return {'\u25ae', 0}, 1, true case "mcomma": // MINUS SIGN WITH COMMA ABOVE - return rune(0x2a29), true + return {'\u2a29', 0}, 1, true case "mcy": // CYRILLIC SMALL LETTER EM - return rune(0x043c), true + return {'\u043c', 0}, 1, true case "mdash": // EM DASH - return rune(0x2014), true + return {'\u2014', 0}, 1, true case "measuredangle": // MEASURED ANGLE - return rune(0x2221), true + return {'\u2221', 0}, 1, true case "mfr": // MATHEMATICAL FRAKTUR SMALL M - return rune(0x01d52a), true + return {'\U0001d52a', 0}, 1, true case "mgr": // GREEK SMALL LETTER MU - return rune(0x03bc), true + return {'\u03bc', 0}, 1, true case "mho": // INVERTED OHM SIGN - return rune(0x2127), true + return {'\u2127', 0}, 1, true case "micro": // MICRO SIGN - return rune(0xb5), true + return {'µ', 0}, 1, true case "mid": // DIVIDES - return rune(0x2223), true + return {'\u2223', 0}, 1, true case "midast": // ASTERISK - return rune(0x2a), true + return {'*', 0}, 1, true case "midcir": // VERTICAL LINE WITH CIRCLE BELOW - return rune(0x2af0), true + return {'\u2af0', 0}, 1, true case "middot": // MIDDLE DOT - return rune(0xb7), true + return {'·', 0}, 1, true case "minus": // MINUS SIGN - return rune(0x2212), true + return {'\u2212', 0}, 1, true case "minusb": // SQUARED MINUS - return rune(0x229f), true + return {'\u229f', 0}, 1, true case "minusd": // DOT MINUS - return rune(0x2238), true + return {'\u2238', 0}, 1, true case "minusdu": // MINUS SIGN WITH DOT BELOW - return rune(0x2a2a), true + return {'\u2a2a', 0}, 1, true case "mlcp": // TRANSVERSAL INTERSECTION - return rune(0x2adb), true + return {'\u2adb', 0}, 1, true case "mldr": // HORIZONTAL ELLIPSIS - return rune(0x2026), true + return {'\u2026', 0}, 1, true case "mnplus": // MINUS-OR-PLUS SIGN - return rune(0x2213), true + return {'\u2213', 0}, 1, true case "models": // MODELS - return rune(0x22a7), true + return {'\u22a7', 0}, 1, true case "mopf": // MATHEMATICAL DOUBLE-STRUCK SMALL M - return rune(0x01d55e), true + return {'\U0001d55e', 0}, 1, true case "mp": // MINUS-OR-PLUS SIGN - return rune(0x2213), true + return {'\u2213', 0}, 1, true case "mscr": // MATHEMATICAL SCRIPT SMALL M - return rune(0x01d4c2), true + return {'\U0001d4c2', 0}, 1, true case "mstpos": // INVERTED LAZY S - return rune(0x223e), true + return {'\u223e', 0}, 1, true case "mu": // GREEK SMALL LETTER MU - return rune(0x03bc), true + return {'\u03bc', 0}, 1, true case "multimap": // MULTIMAP - return rune(0x22b8), true + return {'\u22b8', 0}, 1, true case "mumap": // MULTIMAP - return rune(0x22b8), true + return {'\u22b8', 0}, 1, true } case 'n': switch name { case "nGg": // VERY MUCH GREATER-THAN with slash - return rune(0x22d9), true + return {'\u22d9', '\u0338'}, 2, true case "nGt": // MUCH GREATER THAN with vertical line - return rune(0x226b), true + return {'\u226b', '\u20d2'}, 2, true case "nGtv": // MUCH GREATER THAN with slash - return rune(0x226b), true + return {'\u226b', '\u0338'}, 2, true case "nLeftarrow": // LEFTWARDS DOUBLE ARROW WITH STROKE - return rune(0x21cd), true + return {'\u21cd', 0}, 1, true case "nLeftrightarrow": // LEFT RIGHT DOUBLE ARROW WITH STROKE - return rune(0x21ce), true + return {'\u21ce', 0}, 1, true case "nLl": // VERY MUCH LESS-THAN with slash - return rune(0x22d8), true + return {'\u22d8', '\u0338'}, 2, true case "nLt": // MUCH LESS THAN with vertical line - return rune(0x226a), true + return {'\u226a', '\u20d2'}, 2, true case "nLtv": // MUCH LESS THAN with slash - return rune(0x226a), true + return {'\u226a', '\u0338'}, 2, true case "nRightarrow": // RIGHTWARDS DOUBLE ARROW WITH STROKE - return rune(0x21cf), true + return {'\u21cf', 0}, 1, true case "nVDash": // NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE - return rune(0x22af), true + return {'\u22af', 0}, 1, true case "nVdash": // DOES NOT FORCE - return rune(0x22ae), true + return {'\u22ae', 0}, 1, true case "nabla": // NABLA - return rune(0x2207), true + return {'\u2207', 0}, 1, true case "nacute": // LATIN SMALL LETTER N WITH ACUTE - return rune(0x0144), true + return {'\u0144', 0}, 1, true case "nang": // ANGLE with vertical line - return rune(0x2220), true + return {'\u2220', '\u20d2'}, 2, true case "nap": // NOT ALMOST EQUAL TO - return rune(0x2249), true + return {'\u2249', 0}, 1, true case "napE": // APPROXIMATELY EQUAL OR EQUAL TO with slash - return rune(0x2a70), true + return {'\u2a70', '\u0338'}, 2, true case "napid": // TRIPLE TILDE with slash - return rune(0x224b), true + return {'\u224b', '\u0338'}, 2, true case "napos": // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE - return rune(0x0149), true + return {'\u0149', 0}, 1, true case "napprox": // NOT ALMOST EQUAL TO - return rune(0x2249), true + return {'\u2249', 0}, 1, true case "natur": // MUSIC NATURAL SIGN - return rune(0x266e), true + return {'\u266e', 0}, 1, true case "natural": // MUSIC NATURAL SIGN - return rune(0x266e), true + return {'\u266e', 0}, 1, true case "naturals": // DOUBLE-STRUCK CAPITAL N - return rune(0x2115), true + return {'\u2115', 0}, 1, true case "nbsp": // NO-BREAK SPACE - return rune(0xa0), true + return {'\u00a0', 0}, 1, true case "nbump": // GEOMETRICALLY EQUIVALENT TO with slash - return rune(0x224e), true + return {'\u224e', '\u0338'}, 2, true case "nbumpe": // DIFFERENCE BETWEEN with slash - return rune(0x224f), true + return {'\u224f', '\u0338'}, 2, true case "ncap": // INTERSECTION WITH OVERBAR - return rune(0x2a43), true + return {'\u2a43', 0}, 1, true case "ncaron": // LATIN SMALL LETTER N WITH CARON - return rune(0x0148), true + return {'\u0148', 0}, 1, true case "ncedil": // LATIN SMALL LETTER N WITH CEDILLA - return rune(0x0146), true + return {'\u0146', 0}, 1, true case "ncong": // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO - return rune(0x2247), true + return {'\u2247', 0}, 1, true case "ncongdot": // CONGRUENT WITH DOT ABOVE with slash - return rune(0x2a6d), true + return {'\u2a6d', '\u0338'}, 2, true case "ncup": // UNION WITH OVERBAR - return rune(0x2a42), true + return {'\u2a42', 0}, 1, true case "ncy": // CYRILLIC SMALL LETTER EN - return rune(0x043d), true + return {'\u043d', 0}, 1, true case "ndash": // EN DASH - return rune(0x2013), true + return {'\u2013', 0}, 1, true case "ne": // NOT EQUAL TO - return rune(0x2260), true + return {'\u2260', 0}, 1, true case "neArr": // NORTH EAST DOUBLE ARROW - return rune(0x21d7), true + return {'\u21d7', 0}, 1, true case "nearhk": // NORTH EAST ARROW WITH HOOK - return rune(0x2924), true + return {'\u2924', 0}, 1, true case "nearr": // NORTH EAST ARROW - return rune(0x2197), true + return {'\u2197', 0}, 1, true case "nearrow": // NORTH EAST ARROW - return rune(0x2197), true + return {'\u2197', 0}, 1, true case "nedot": // APPROACHES THE LIMIT with slash - return rune(0x2250), true + return {'\u2250', '\u0338'}, 2, true case "neonwarr": // NORTH EAST ARROW CROSSING NORTH WEST ARROW - return rune(0x2931), true + return {'\u2931', 0}, 1, true case "neosearr": // NORTH EAST ARROW CROSSING SOUTH EAST ARROW - return rune(0x292e), true + return {'\u292e', 0}, 1, true case "nequiv": // NOT IDENTICAL TO - return rune(0x2262), true + return {'\u2262', 0}, 1, true case "nesear": // NORTH EAST ARROW AND SOUTH EAST ARROW - return rune(0x2928), true + return {'\u2928', 0}, 1, true case "nesim": // MINUS TILDE with slash - return rune(0x2242), true + return {'\u2242', '\u0338'}, 2, true case "neswsarr": // NORTH EAST AND SOUTH WEST ARROW - return rune(0x2922), true + return {'\u2922', 0}, 1, true case "nexist": // THERE DOES NOT EXIST - return rune(0x2204), true + return {'\u2204', 0}, 1, true case "nexists": // THERE DOES NOT EXIST - return rune(0x2204), true + return {'\u2204', 0}, 1, true case "nfr": // MATHEMATICAL FRAKTUR SMALL N - return rune(0x01d52b), true + return {'\U0001d52b', 0}, 1, true case "ngE": // GREATER-THAN OVER EQUAL TO with slash - return rune(0x2267), true + return {'\u2267', '\u0338'}, 2, true case "nge": // NEITHER GREATER-THAN NOR EQUAL TO - return rune(0x2271), true + return {'\u2271', 0}, 1, true case "ngeq": // NEITHER GREATER-THAN NOR EQUAL TO - return rune(0x2271), true + return {'\u2271', 0}, 1, true case "ngeqq": // GREATER-THAN OVER EQUAL TO with slash - return rune(0x2267), true + return {'\u2267', '\u0338'}, 2, true case "ngeqslant": // GREATER-THAN OR SLANTED EQUAL TO with slash - return rune(0x2a7e), true + return {'\u2a7e', '\u0338'}, 2, true case "nges": // GREATER-THAN OR SLANTED EQUAL TO with slash - return rune(0x2a7e), true + return {'\u2a7e', '\u0338'}, 2, true case "ngr": // GREEK SMALL LETTER NU - return rune(0x03bd), true + return {'\u03bd', 0}, 1, true case "ngsim": // NEITHER GREATER-THAN NOR EQUIVALENT TO - return rune(0x2275), true + return {'\u2275', 0}, 1, true case "ngt": // NOT GREATER-THAN - return rune(0x226f), true + return {'\u226f', 0}, 1, true case "ngtr": // NOT GREATER-THAN - return rune(0x226f), true + return {'\u226f', 0}, 1, true case "nhArr": // LEFT RIGHT DOUBLE ARROW WITH STROKE - return rune(0x21ce), true + return {'\u21ce', 0}, 1, true case "nharr": // LEFT RIGHT ARROW WITH STROKE - return rune(0x21ae), true + return {'\u21ae', 0}, 1, true case "nhpar": // PARALLEL WITH HORIZONTAL STROKE - return rune(0x2af2), true + return {'\u2af2', 0}, 1, true case "ni": // CONTAINS AS MEMBER - return rune(0x220b), true + return {'\u220b', 0}, 1, true case "nis": // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE - return rune(0x22fc), true + return {'\u22fc', 0}, 1, true case "nisd": // CONTAINS WITH LONG HORIZONTAL STROKE - return rune(0x22fa), true + return {'\u22fa', 0}, 1, true case "niv": // CONTAINS AS MEMBER - return rune(0x220b), true + return {'\u220b', 0}, 1, true case "njcy": // CYRILLIC SMALL LETTER NJE - return rune(0x045a), true + return {'\u045a', 0}, 1, true case "nlArr": // LEFTWARDS DOUBLE ARROW WITH STROKE - return rune(0x21cd), true + return {'\u21cd', 0}, 1, true case "nlE": // LESS-THAN OVER EQUAL TO with slash - return rune(0x2266), true + return {'\u2266', '\u0338'}, 2, true case "nlarr": // LEFTWARDS ARROW WITH STROKE - return rune(0x219a), true + return {'\u219a', 0}, 1, true case "nldr": // TWO DOT LEADER - return rune(0x2025), true + return {'\u2025', 0}, 1, true case "nle": // NEITHER LESS-THAN NOR EQUAL TO - return rune(0x2270), true + return {'\u2270', 0}, 1, true case "nleftarrow": // LEFTWARDS ARROW WITH STROKE - return rune(0x219a), true + return {'\u219a', 0}, 1, true case "nleftrightarrow": // LEFT RIGHT ARROW WITH STROKE - return rune(0x21ae), true + return {'\u21ae', 0}, 1, true case "nleq": // NEITHER LESS-THAN NOR EQUAL TO - return rune(0x2270), true + return {'\u2270', 0}, 1, true case "nleqq": // LESS-THAN OVER EQUAL TO with slash - return rune(0x2266), true + return {'\u2266', '\u0338'}, 2, true case "nleqslant": // LESS-THAN OR SLANTED EQUAL TO with slash - return rune(0x2a7d), true + return {'\u2a7d', '\u0338'}, 2, true case "nles": // LESS-THAN OR SLANTED EQUAL TO with slash - return rune(0x2a7d), true + return {'\u2a7d', '\u0338'}, 2, true case "nless": // NOT LESS-THAN - return rune(0x226e), true + return {'\u226e', 0}, 1, true case "nlsim": // NEITHER LESS-THAN NOR EQUIVALENT TO - return rune(0x2274), true + return {'\u2274', 0}, 1, true case "nlt": // NOT LESS-THAN - return rune(0x226e), true + return {'\u226e', 0}, 1, true case "nltri": // NOT NORMAL SUBGROUP OF - return rune(0x22ea), true + return {'\u22ea', 0}, 1, true case "nltrie": // NOT NORMAL SUBGROUP OF OR EQUAL TO - return rune(0x22ec), true + return {'\u22ec', 0}, 1, true case "nltrivb": // LEFT TRIANGLE BESIDE VERTICAL BAR with slash - return rune(0x29cf), true + return {'\u29cf', '\u0338'}, 2, true case "nmid": // DOES NOT DIVIDE - return rune(0x2224), true + return {'\u2224', 0}, 1, true case "nopf": // MATHEMATICAL DOUBLE-STRUCK SMALL N - return rune(0x01d55f), true + return {'\U0001d55f', 0}, 1, true case "not": // NOT SIGN - return rune(0xac), true + return {'¬', 0}, 1, true case "notin": // NOT AN ELEMENT OF - return rune(0x2209), true + return {'\u2209', 0}, 1, true case "notinE": // ELEMENT OF WITH TWO HORIZONTAL STROKES with slash - return rune(0x22f9), true + return {'\u22f9', '\u0338'}, 2, true case "notindot": // ELEMENT OF WITH DOT ABOVE with slash - return rune(0x22f5), true + return {'\u22f5', '\u0338'}, 2, true case "notinva": // NOT AN ELEMENT OF - return rune(0x2209), true + return {'\u2209', 0}, 1, true case "notinvb": // SMALL ELEMENT OF WITH OVERBAR - return rune(0x22f7), true + return {'\u22f7', 0}, 1, true case "notinvc": // ELEMENT OF WITH OVERBAR - return rune(0x22f6), true + return {'\u22f6', 0}, 1, true case "notni": // DOES NOT CONTAIN AS MEMBER - return rune(0x220c), true + return {'\u220c', 0}, 1, true case "notniva": // DOES NOT CONTAIN AS MEMBER - return rune(0x220c), true + return {'\u220c', 0}, 1, true case "notnivb": // SMALL CONTAINS WITH OVERBAR - return rune(0x22fe), true + return {'\u22fe', 0}, 1, true case "notnivc": // CONTAINS WITH OVERBAR - return rune(0x22fd), true + return {'\u22fd', 0}, 1, true case "npar": // NOT PARALLEL TO - return rune(0x2226), true + return {'\u2226', 0}, 1, true case "nparallel": // NOT PARALLEL TO - return rune(0x2226), true + return {'\u2226', 0}, 1, true case "nparsl": // DOUBLE SOLIDUS OPERATOR with reverse slash - return rune(0x2afd), true + return {'\u2afd', '\u20e5'}, 2, true case "npart": // PARTIAL DIFFERENTIAL with slash - return rune(0x2202), true + return {'\u2202', '\u0338'}, 2, true case "npolint": // LINE INTEGRATION NOT INCLUDING THE POLE - return rune(0x2a14), true + return {'\u2a14', 0}, 1, true case "npr": // DOES NOT PRECEDE - return rune(0x2280), true + return {'\u2280', 0}, 1, true case "nprcue": // DOES NOT PRECEDE OR EQUAL - return rune(0x22e0), true + return {'\u22e0', 0}, 1, true case "npre": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash - return rune(0x2aaf), true + return {'\u2aaf', '\u0338'}, 2, true case "nprec": // DOES NOT PRECEDE - return rune(0x2280), true + return {'\u2280', 0}, 1, true case "npreceq": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash - return rune(0x2aaf), true + return {'\u2aaf', '\u0338'}, 2, true case "nprsim": // PRECEDES OR EQUIVALENT TO with slash - return rune(0x227e), true + return {'\u227e', '\u0338'}, 2, true case "nrArr": // RIGHTWARDS DOUBLE ARROW WITH STROKE - return rune(0x21cf), true + return {'\u21cf', 0}, 1, true case "nrarr": // RIGHTWARDS ARROW WITH STROKE - return rune(0x219b), true + return {'\u219b', 0}, 1, true case "nrarrc": // WAVE ARROW POINTING DIRECTLY RIGHT with slash - return rune(0x2933), true + return {'\u2933', '\u0338'}, 2, true case "nrarrw": // RIGHTWARDS WAVE ARROW with slash - return rune(0x219d), true + return {'\u219d', '\u0338'}, 2, true case "nrightarrow": // RIGHTWARDS ARROW WITH STROKE - return rune(0x219b), true + return {'\u219b', 0}, 1, true case "nrtri": // DOES NOT CONTAIN AS NORMAL SUBGROUP - return rune(0x22eb), true + return {'\u22eb', 0}, 1, true case "nrtrie": // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL - return rune(0x22ed), true + return {'\u22ed', 0}, 1, true case "nsGt": // DOUBLE NESTED GREATER-THAN with slash - return rune(0x2aa2), true + return {'\u2aa2', '\u0338'}, 2, true case "nsLt": // DOUBLE NESTED LESS-THAN with slash - return rune(0x2aa1), true + return {'\u2aa1', '\u0338'}, 2, true case "nsc": // DOES NOT SUCCEED - return rune(0x2281), true + return {'\u2281', 0}, 1, true case "nsccue": // DOES NOT SUCCEED OR EQUAL - return rune(0x22e1), true + return {'\u22e1', 0}, 1, true case "nsce": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash - return rune(0x2ab0), true + return {'\u2ab0', '\u0338'}, 2, true case "nscr": // MATHEMATICAL SCRIPT SMALL N - return rune(0x01d4c3), true + return {'\U0001d4c3', 0}, 1, true case "nscsim": // SUCCEEDS OR EQUIVALENT TO with slash - return rune(0x227f), true + return {'\u227f', '\u0338'}, 2, true case "nshortmid": // DOES NOT DIVIDE - return rune(0x2224), true + return {'\u2224', 0}, 1, true case "nshortparallel": // NOT PARALLEL TO - return rune(0x2226), true + return {'\u2226', 0}, 1, true case "nsim": // NOT TILDE - return rune(0x2241), true + return {'\u2241', 0}, 1, true case "nsime": // NOT ASYMPTOTICALLY EQUAL TO - return rune(0x2244), true + return {'\u2244', 0}, 1, true case "nsimeq": // NOT ASYMPTOTICALLY EQUAL TO - return rune(0x2244), true + return {'\u2244', 0}, 1, true case "nsmid": // DOES NOT DIVIDE - return rune(0x2224), true + return {'\u2224', 0}, 1, true case "nspar": // NOT PARALLEL TO - return rune(0x2226), true + return {'\u2226', 0}, 1, true case "nsqsub": // SQUARE IMAGE OF with slash - return rune(0x228f), true + return {'\u228f', '\u0338'}, 2, true case "nsqsube": // NOT SQUARE IMAGE OF OR EQUAL TO - return rune(0x22e2), true + return {'\u22e2', 0}, 1, true case "nsqsup": // SQUARE ORIGINAL OF with slash - return rune(0x2290), true + return {'\u2290', '\u0338'}, 2, true case "nsqsupe": // NOT SQUARE ORIGINAL OF OR EQUAL TO - return rune(0x22e3), true + return {'\u22e3', 0}, 1, true case "nsub": // NOT A SUBSET OF - return rune(0x2284), true + return {'\u2284', 0}, 1, true case "nsubE": // SUBSET OF ABOVE EQUALS SIGN with slash - return rune(0x2ac5), true + return {'\u2ac5', '\u0338'}, 2, true case "nsube": // NEITHER A SUBSET OF NOR EQUAL TO - return rune(0x2288), true + return {'\u2288', 0}, 1, true case "nsubset": // SUBSET OF with vertical line - return rune(0x2282), true + return {'\u2282', '\u20d2'}, 2, true case "nsubseteq": // NEITHER A SUBSET OF NOR EQUAL TO - return rune(0x2288), true + return {'\u2288', 0}, 1, true case "nsubseteqq": // SUBSET OF ABOVE EQUALS SIGN with slash - return rune(0x2ac5), true + return {'\u2ac5', '\u0338'}, 2, true case "nsucc": // DOES NOT SUCCEED - return rune(0x2281), true + return {'\u2281', 0}, 1, true case "nsucceq": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash - return rune(0x2ab0), true + return {'\u2ab0', '\u0338'}, 2, true case "nsup": // NOT A SUPERSET OF - return rune(0x2285), true + return {'\u2285', 0}, 1, true case "nsupE": // SUPERSET OF ABOVE EQUALS SIGN with slash - return rune(0x2ac6), true + return {'\u2ac6', '\u0338'}, 2, true case "nsupe": // NEITHER A SUPERSET OF NOR EQUAL TO - return rune(0x2289), true + return {'\u2289', 0}, 1, true case "nsupset": // SUPERSET OF with vertical line - return rune(0x2283), true + return {'\u2283', '\u20d2'}, 2, true case "nsupseteq": // NEITHER A SUPERSET OF NOR EQUAL TO - return rune(0x2289), true + return {'\u2289', 0}, 1, true case "nsupseteqq": // SUPERSET OF ABOVE EQUALS SIGN with slash - return rune(0x2ac6), true + return {'\u2ac6', '\u0338'}, 2, true case "ntgl": // NEITHER GREATER-THAN NOR LESS-THAN - return rune(0x2279), true + return {'\u2279', 0}, 1, true case "ntilde": // LATIN SMALL LETTER N WITH TILDE - return rune(0xf1), true + return {'ñ', 0}, 1, true case "ntlg": // NEITHER LESS-THAN NOR GREATER-THAN - return rune(0x2278), true + return {'\u2278', 0}, 1, true case "ntriangleleft": // NOT NORMAL SUBGROUP OF - return rune(0x22ea), true + return {'\u22ea', 0}, 1, true case "ntrianglelefteq": // NOT NORMAL SUBGROUP OF OR EQUAL TO - return rune(0x22ec), true + return {'\u22ec', 0}, 1, true case "ntriangleright": // DOES NOT CONTAIN AS NORMAL SUBGROUP - return rune(0x22eb), true + return {'\u22eb', 0}, 1, true case "ntrianglerighteq": // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL - return rune(0x22ed), true + return {'\u22ed', 0}, 1, true case "nu": // GREEK SMALL LETTER NU - return rune(0x03bd), true + return {'\u03bd', 0}, 1, true case "num": // NUMBER SIGN - return rune(0x23), true + return {'#', 0}, 1, true case "numero": // NUMERO SIGN - return rune(0x2116), true + return {'\u2116', 0}, 1, true case "numsp": // FIGURE SPACE - return rune(0x2007), true + return {'\u2007', 0}, 1, true case "nvDash": // NOT TRUE - return rune(0x22ad), true + return {'\u22ad', 0}, 1, true case "nvHarr": // LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE - return rune(0x2904), true + return {'\u2904', 0}, 1, true case "nvap": // EQUIVALENT TO with vertical line - return rune(0x224d), true + return {'\u224d', '\u20d2'}, 2, true case "nvbrtri": // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash - return rune(0x29d0), true + return {'\u29d0', '\u0338'}, 2, true case "nvdash": // DOES NOT PROVE - return rune(0x22ac), true + return {'\u22ac', 0}, 1, true case "nvge": // GREATER-THAN OR EQUAL TO with vertical line - return rune(0x2265), true + return {'\u2265', '\u20d2'}, 2, true case "nvgt": // GREATER-THAN SIGN with vertical line - return rune(0x3e), true + return {'>', '\u20d2'}, 2, true case "nvinfin": // INFINITY NEGATED WITH VERTICAL BAR - return rune(0x29de), true + return {'\u29de', 0}, 1, true case "nvlArr": // LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE - return rune(0x2902), true + return {'\u2902', 0}, 1, true case "nvle": // LESS-THAN OR EQUAL TO with vertical line - return rune(0x2264), true + return {'\u2264', '\u20d2'}, 2, true case "nvlt": // LESS-THAN SIGN with vertical line - return rune(0x3c), true + return {'<', '\u20d2'}, 2, true case "nvltrie": // NORMAL SUBGROUP OF OR EQUAL TO with vertical line - return rune(0x22b4), true + return {'\u22b4', '\u20d2'}, 2, true case "nvrArr": // RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE - return rune(0x2903), true + return {'\u2903', 0}, 1, true case "nvrtrie": // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO with vertical line - return rune(0x22b5), true + return {'\u22b5', '\u20d2'}, 2, true case "nvsim": // TILDE OPERATOR with vertical line - return rune(0x223c), true + return {'\u223c', '\u20d2'}, 2, true case "nwArr": // NORTH WEST DOUBLE ARROW - return rune(0x21d6), true + return {'\u21d6', 0}, 1, true case "nwarhk": // NORTH WEST ARROW WITH HOOK - return rune(0x2923), true + return {'\u2923', 0}, 1, true case "nwarr": // NORTH WEST ARROW - return rune(0x2196), true + return {'\u2196', 0}, 1, true case "nwarrow": // NORTH WEST ARROW - return rune(0x2196), true + return {'\u2196', 0}, 1, true case "nwnear": // NORTH WEST ARROW AND NORTH EAST ARROW - return rune(0x2927), true + return {'\u2927', 0}, 1, true case "nwonearr": // NORTH WEST ARROW CROSSING NORTH EAST ARROW - return rune(0x2932), true + return {'\u2932', 0}, 1, true case "nwsesarr": // NORTH WEST AND SOUTH EAST ARROW - return rune(0x2921), true + return {'\u2921', 0}, 1, true } case 'o': switch name { case "oS": // CIRCLED LATIN CAPITAL LETTER S - return rune(0x24c8), true + return {'\u24c8', 0}, 1, true case "oacgr": // GREEK SMALL LETTER OMICRON WITH TONOS - return rune(0x03cc), true + return {'\u03cc', 0}, 1, true case "oacute": // LATIN SMALL LETTER O WITH ACUTE - return rune(0xf3), true + return {'ó', 0}, 1, true case "oast": // CIRCLED ASTERISK OPERATOR - return rune(0x229b), true + return {'\u229b', 0}, 1, true case "obsol": // CIRCLED REVERSE SOLIDUS - return rune(0x29b8), true + return {'\u29b8', 0}, 1, true case "ocir": // CIRCLED RING OPERATOR - return rune(0x229a), true + return {'\u229a', 0}, 1, true case "ocirc": // LATIN SMALL LETTER O WITH CIRCUMFLEX - return rune(0xf4), true + return {'ô', 0}, 1, true case "ocy": // CYRILLIC SMALL LETTER O - return rune(0x043e), true + return {'\u043e', 0}, 1, true case "odash": // CIRCLED DASH - return rune(0x229d), true + return {'\u229d', 0}, 1, true case "odblac": // LATIN SMALL LETTER O WITH DOUBLE ACUTE - return rune(0x0151), true + return {'\u0151', 0}, 1, true case "odiv": // CIRCLED DIVISION SIGN - return rune(0x2a38), true + return {'\u2a38', 0}, 1, true case "odot": // CIRCLED DOT OPERATOR - return rune(0x2299), true + return {'\u2299', 0}, 1, true case "odsold": // CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN - return rune(0x29bc), true + return {'\u29bc', 0}, 1, true case "oelig": // LATIN SMALL LIGATURE OE - return rune(0x0153), true + return {'\u0153', 0}, 1, true case "ofcir": // CIRCLED BULLET - return rune(0x29bf), true + return {'\u29bf', 0}, 1, true case "ofr": // MATHEMATICAL FRAKTUR SMALL O - return rune(0x01d52c), true + return {'\U0001d52c', 0}, 1, true case "ogon": // OGONEK - return rune(0x02db), true + return {'\u02db', 0}, 1, true case "ogr": // GREEK SMALL LETTER OMICRON - return rune(0x03bf), true + return {'\u03bf', 0}, 1, true case "ograve": // LATIN SMALL LETTER O WITH GRAVE - return rune(0xf2), true + return {'ò', 0}, 1, true case "ogt": // CIRCLED GREATER-THAN - return rune(0x29c1), true + return {'\u29c1', 0}, 1, true case "ohacgr": // GREEK SMALL LETTER OMEGA WITH TONOS - return rune(0x03ce), true + return {'\u03ce', 0}, 1, true case "ohbar": // CIRCLE WITH HORIZONTAL BAR - return rune(0x29b5), true + return {'\u29b5', 0}, 1, true case "ohgr": // GREEK SMALL LETTER OMEGA - return rune(0x03c9), true + return {'\u03c9', 0}, 1, true case "ohm": // GREEK CAPITAL LETTER OMEGA - return rune(0x03a9), true + return {'\u03a9', 0}, 1, true case "oint": // CONTOUR INTEGRAL - return rune(0x222e), true + return {'\u222e', 0}, 1, true case "olarr": // ANTICLOCKWISE OPEN CIRCLE ARROW - return rune(0x21ba), true + return {'\u21ba', 0}, 1, true case "olcir": // CIRCLED WHITE BULLET - return rune(0x29be), true + return {'\u29be', 0}, 1, true case "olcross": // CIRCLE WITH SUPERIMPOSED X - return rune(0x29bb), true + return {'\u29bb', 0}, 1, true case "oline": // OVERLINE - return rune(0x203e), true + return {'\u203e', 0}, 1, true case "olt": // CIRCLED LESS-THAN - return rune(0x29c0), true + return {'\u29c0', 0}, 1, true case "omacr": // LATIN SMALL LETTER O WITH MACRON - return rune(0x014d), true + return {'\u014d', 0}, 1, true case "omega": // GREEK SMALL LETTER OMEGA - return rune(0x03c9), true + return {'\u03c9', 0}, 1, true case "omicron": // GREEK SMALL LETTER OMICRON - return rune(0x03bf), true + return {'\u03bf', 0}, 1, true case "omid": // CIRCLED VERTICAL BAR - return rune(0x29b6), true + return {'\u29b6', 0}, 1, true case "ominus": // CIRCLED MINUS - return rune(0x2296), true + return {'\u2296', 0}, 1, true case "oopf": // MATHEMATICAL DOUBLE-STRUCK SMALL O - return rune(0x01d560), true + return {'\U0001d560', 0}, 1, true case "opar": // CIRCLED PARALLEL - return rune(0x29b7), true + return {'\u29b7', 0}, 1, true case "operp": // CIRCLED PERPENDICULAR - return rune(0x29b9), true + return {'\u29b9', 0}, 1, true case "opfgamma": // DOUBLE-STRUCK SMALL GAMMA - return rune(0x213d), true + return {'\u213d', 0}, 1, true case "opfpi": // DOUBLE-STRUCK CAPITAL PI - return rune(0x213f), true + return {'\u213f', 0}, 1, true case "opfsum": // DOUBLE-STRUCK N-ARY SUMMATION - return rune(0x2140), true + return {'\u2140', 0}, 1, true case "oplus": // CIRCLED PLUS - return rune(0x2295), true + return {'\u2295', 0}, 1, true case "or": // LOGICAL OR - return rune(0x2228), true + return {'\u2228', 0}, 1, true case "orarr": // CLOCKWISE OPEN CIRCLE ARROW - return rune(0x21bb), true + return {'\u21bb', 0}, 1, true case "ord": // LOGICAL OR WITH HORIZONTAL DASH - return rune(0x2a5d), true + return {'\u2a5d', 0}, 1, true case "order": // SCRIPT SMALL O - return rune(0x2134), true + return {'\u2134', 0}, 1, true case "orderof": // SCRIPT SMALL O - return rune(0x2134), true + return {'\u2134', 0}, 1, true case "ordf": // FEMININE ORDINAL INDICATOR - return rune(0xaa), true + return {'ª', 0}, 1, true case "ordm": // MASCULINE ORDINAL INDICATOR - return rune(0xba), true + return {'º', 0}, 1, true case "origof": // ORIGINAL OF - return rune(0x22b6), true + return {'\u22b6', 0}, 1, true case "oror": // TWO INTERSECTING LOGICAL OR - return rune(0x2a56), true + return {'\u2a56', 0}, 1, true case "orslope": // SLOPING LARGE OR - return rune(0x2a57), true + return {'\u2a57', 0}, 1, true case "orv": // LOGICAL OR WITH MIDDLE STEM - return rune(0x2a5b), true + return {'\u2a5b', 0}, 1, true case "oscr": // SCRIPT SMALL O - return rune(0x2134), true + return {'\u2134', 0}, 1, true case "oslash": // LATIN SMALL LETTER O WITH STROKE - return rune(0xf8), true + return {'ø', 0}, 1, true case "osol": // CIRCLED DIVISION SLASH - return rune(0x2298), true + return {'\u2298', 0}, 1, true case "otilde": // LATIN SMALL LETTER O WITH TILDE - return rune(0xf5), true + return {'õ', 0}, 1, true case "otimes": // CIRCLED TIMES - return rune(0x2297), true + return {'\u2297', 0}, 1, true case "otimesas": // CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT - return rune(0x2a36), true + return {'\u2a36', 0}, 1, true case "ouml": // LATIN SMALL LETTER O WITH DIAERESIS - return rune(0xf6), true + return {'ö', 0}, 1, true case "ovbar": // APL FUNCTIONAL SYMBOL CIRCLE STILE - return rune(0x233d), true + return {'\u233d', 0}, 1, true case "ovrbrk": // TOP SQUARE BRACKET - return rune(0x23b4), true + return {'\u23b4', 0}, 1, true case "ovrcub": // TOP CURLY BRACKET - return rune(0x23de), true + return {'\u23de', 0}, 1, true case "ovrpar": // TOP PARENTHESIS - return rune(0x23dc), true + return {'\u23dc', 0}, 1, true case "oxuarr": // UP ARROW THROUGH CIRCLE - return rune(0x29bd), true + return {'\u29bd', 0}, 1, true } case 'p': switch name { case "par": // PARALLEL TO - return rune(0x2225), true + return {'\u2225', 0}, 1, true case "para": // PILCROW SIGN - return rune(0xb6), true + return {'¶', 0}, 1, true case "parallel": // PARALLEL TO - return rune(0x2225), true + return {'\u2225', 0}, 1, true case "parsim": // PARALLEL WITH TILDE OPERATOR - return rune(0x2af3), true + return {'\u2af3', 0}, 1, true case "parsl": // DOUBLE SOLIDUS OPERATOR - return rune(0x2afd), true + return {'\u2afd', 0}, 1, true case "part": // PARTIAL DIFFERENTIAL - return rune(0x2202), true + return {'\u2202', 0}, 1, true case "pcy": // CYRILLIC SMALL LETTER PE - return rune(0x043f), true + return {'\u043f', 0}, 1, true case "percnt": // PERCENT SIGN - return rune(0x25), true + return {'%', 0}, 1, true case "period": // FULL STOP - return rune(0x2e), true + return {'.', 0}, 1, true case "permil": // PER MILLE SIGN - return rune(0x2030), true + return {'\u2030', 0}, 1, true case "perp": // UP TACK - return rune(0x22a5), true + return {'\u22a5', 0}, 1, true case "pertenk": // PER TEN THOUSAND SIGN - return rune(0x2031), true + return {'\u2031', 0}, 1, true case "pfr": // MATHEMATICAL FRAKTUR SMALL P - return rune(0x01d52d), true + return {'\U0001d52d', 0}, 1, true case "pgr": // GREEK SMALL LETTER PI - return rune(0x03c0), true + return {'\u03c0', 0}, 1, true case "phgr": // GREEK SMALL LETTER PHI - return rune(0x03c6), true + return {'\u03c6', 0}, 1, true case "phi": // GREEK SMALL LETTER PHI - return rune(0x03c6), true + return {'\u03c6', 0}, 1, true case "phis": // GREEK PHI SYMBOL - return rune(0x03d5), true + return {'\u03d5', 0}, 1, true case "phiv": // GREEK PHI SYMBOL - return rune(0x03d5), true + return {'\u03d5', 0}, 1, true case "phmmat": // SCRIPT CAPITAL M - return rune(0x2133), true + return {'\u2133', 0}, 1, true case "phone": // BLACK TELEPHONE - return rune(0x260e), true + return {'\u260e', 0}, 1, true case "pi": // GREEK SMALL LETTER PI - return rune(0x03c0), true + return {'\u03c0', 0}, 1, true case "pitchfork": // PITCHFORK - return rune(0x22d4), true + return {'\u22d4', 0}, 1, true case "piv": // GREEK PI SYMBOL - return rune(0x03d6), true + return {'\u03d6', 0}, 1, true case "planck": // PLANCK CONSTANT OVER TWO PI - return rune(0x210f), true + return {'\u210f', 0}, 1, true case "planckh": // PLANCK CONSTANT - return rune(0x210e), true + return {'\u210e', 0}, 1, true case "plankv": // PLANCK CONSTANT OVER TWO PI - return rune(0x210f), true + return {'\u210f', 0}, 1, true case "plus": // PLUS SIGN - return rune(0x2b), true + return {'+', 0}, 1, true case "plusacir": // PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE - return rune(0x2a23), true + return {'\u2a23', 0}, 1, true case "plusb": // SQUARED PLUS - return rune(0x229e), true + return {'\u229e', 0}, 1, true case "pluscir": // PLUS SIGN WITH SMALL CIRCLE ABOVE - return rune(0x2a22), true + return {'\u2a22', 0}, 1, true case "plusdo": // DOT PLUS - return rune(0x2214), true + return {'\u2214', 0}, 1, true case "plusdu": // PLUS SIGN WITH DOT BELOW - return rune(0x2a25), true + return {'\u2a25', 0}, 1, true case "pluse": // PLUS SIGN ABOVE EQUALS SIGN - return rune(0x2a72), true + return {'\u2a72', 0}, 1, true case "plusmn": // PLUS-MINUS SIGN - return rune(0xb1), true + return {'±', 0}, 1, true case "plussim": // PLUS SIGN WITH TILDE BELOW - return rune(0x2a26), true + return {'\u2a26', 0}, 1, true case "plustrif": // PLUS SIGN WITH BLACK TRIANGLE - return rune(0x2a28), true + return {'\u2a28', 0}, 1, true case "plustwo": // PLUS SIGN WITH SUBSCRIPT TWO - return rune(0x2a27), true + return {'\u2a27', 0}, 1, true case "pm": // PLUS-MINUS SIGN - return rune(0xb1), true + return {'±', 0}, 1, true case "pointint": // INTEGRAL AROUND A POINT OPERATOR - return rune(0x2a15), true + return {'\u2a15', 0}, 1, true case "popf": // MATHEMATICAL DOUBLE-STRUCK SMALL P - return rune(0x01d561), true + return {'\U0001d561', 0}, 1, true case "pound": // POUND SIGN - return rune(0xa3), true + return {'£', 0}, 1, true case "pr": // PRECEDES - return rune(0x227a), true + return {'\u227a', 0}, 1, true case "prE": // PRECEDES ABOVE EQUALS SIGN - return rune(0x2ab3), true + return {'\u2ab3', 0}, 1, true case "prap": // PRECEDES ABOVE ALMOST EQUAL TO - return rune(0x2ab7), true + return {'\u2ab7', 0}, 1, true case "prcue": // PRECEDES OR EQUAL TO - return rune(0x227c), true + return {'\u227c', 0}, 1, true case "pre": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN - return rune(0x2aaf), true + return {'\u2aaf', 0}, 1, true case "prec": // PRECEDES - return rune(0x227a), true + return {'\u227a', 0}, 1, true case "precapprox": // PRECEDES ABOVE ALMOST EQUAL TO - return rune(0x2ab7), true + return {'\u2ab7', 0}, 1, true case "preccurlyeq": // PRECEDES OR EQUAL TO - return rune(0x227c), true + return {'\u227c', 0}, 1, true case "preceq": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN - return rune(0x2aaf), true + return {'\u2aaf', 0}, 1, true case "precnapprox": // PRECEDES ABOVE NOT ALMOST EQUAL TO - return rune(0x2ab9), true + return {'\u2ab9', 0}, 1, true case "precneqq": // PRECEDES ABOVE NOT EQUAL TO - return rune(0x2ab5), true + return {'\u2ab5', 0}, 1, true case "precnsim": // PRECEDES BUT NOT EQUIVALENT TO - return rune(0x22e8), true + return {'\u22e8', 0}, 1, true case "precsim": // PRECEDES OR EQUIVALENT TO - return rune(0x227e), true + return {'\u227e', 0}, 1, true case "prime": // PRIME - return rune(0x2032), true + return {'\u2032', 0}, 1, true case "primes": // DOUBLE-STRUCK CAPITAL P - return rune(0x2119), true + return {'\u2119', 0}, 1, true case "prnE": // PRECEDES ABOVE NOT EQUAL TO - return rune(0x2ab5), true + return {'\u2ab5', 0}, 1, true case "prnap": // PRECEDES ABOVE NOT ALMOST EQUAL TO - return rune(0x2ab9), true + return {'\u2ab9', 0}, 1, true case "prnsim": // PRECEDES BUT NOT EQUIVALENT TO - return rune(0x22e8), true + return {'\u22e8', 0}, 1, true case "prod": // N-ARY PRODUCT - return rune(0x220f), true + return {'\u220f', 0}, 1, true case "profalar": // ALL AROUND-PROFILE - return rune(0x232e), true + return {'\u232e', 0}, 1, true case "profline": // ARC - return rune(0x2312), true + return {'\u2312', 0}, 1, true case "profsurf": // SEGMENT - return rune(0x2313), true + return {'\u2313', 0}, 1, true case "prop": // PROPORTIONAL TO - return rune(0x221d), true + return {'\u221d', 0}, 1, true case "propto": // PROPORTIONAL TO - return rune(0x221d), true + return {'\u221d', 0}, 1, true case "prsim": // PRECEDES OR EQUIVALENT TO - return rune(0x227e), true + return {'\u227e', 0}, 1, true case "prurel": // PRECEDES UNDER RELATION - return rune(0x22b0), true + return {'\u22b0', 0}, 1, true case "pscr": // MATHEMATICAL SCRIPT SMALL P - return rune(0x01d4c5), true + return {'\U0001d4c5', 0}, 1, true case "psgr": // GREEK SMALL LETTER PSI - return rune(0x03c8), true + return {'\u03c8', 0}, 1, true case "psi": // GREEK SMALL LETTER PSI - return rune(0x03c8), true + return {'\u03c8', 0}, 1, true case "puncsp": // PUNCTUATION SPACE - return rune(0x2008), true + return {'\u2008', 0}, 1, true } case 'q': switch name { case "qfr": // MATHEMATICAL FRAKTUR SMALL Q - return rune(0x01d52e), true + return {'\U0001d52e', 0}, 1, true case "qint": // QUADRUPLE INTEGRAL OPERATOR - return rune(0x2a0c), true + return {'\u2a0c', 0}, 1, true case "qopf": // MATHEMATICAL DOUBLE-STRUCK SMALL Q - return rune(0x01d562), true + return {'\U0001d562', 0}, 1, true case "qprime": // QUADRUPLE PRIME - return rune(0x2057), true + return {'\u2057', 0}, 1, true case "qscr": // MATHEMATICAL SCRIPT SMALL Q - return rune(0x01d4c6), true + return {'\U0001d4c6', 0}, 1, true case "quaternions": // DOUBLE-STRUCK CAPITAL H - return rune(0x210d), true + return {'\u210d', 0}, 1, true case "quatint": // QUATERNION INTEGRAL OPERATOR - return rune(0x2a16), true + return {'\u2a16', 0}, 1, true case "quest": // QUESTION MARK - return rune(0x3f), true + return {'?', 0}, 1, true case "questeq": // QUESTIONED EQUAL TO - return rune(0x225f), true + return {'\u225f', 0}, 1, true case "quot": // QUOTATION MARK - return rune(0x22), true + return {'"', 0}, 1, true } case 'r': switch name { case "rAarr": // RIGHTWARDS TRIPLE ARROW - return rune(0x21db), true + return {'\u21db', 0}, 1, true case "rArr": // RIGHTWARDS DOUBLE ARROW - return rune(0x21d2), true + return {'\u21d2', 0}, 1, true case "rAtail": // RIGHTWARDS DOUBLE ARROW-TAIL - return rune(0x291c), true + return {'\u291c', 0}, 1, true case "rBarr": // RIGHTWARDS TRIPLE DASH ARROW - return rune(0x290f), true + return {'\u290f', 0}, 1, true case "rHar": // RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN - return rune(0x2964), true + return {'\u2964', 0}, 1, true case "race": // REVERSED TILDE with underline - return rune(0x223d), true + return {'\u223d', '\u0331'}, 2, true case "racute": // LATIN SMALL LETTER R WITH ACUTE - return rune(0x0155), true + return {'\u0155', 0}, 1, true case "radic": // SQUARE ROOT - return rune(0x221a), true + return {'\u221a', 0}, 1, true case "raemptyv": // EMPTY SET WITH RIGHT ARROW ABOVE - return rune(0x29b3), true + return {'\u29b3', 0}, 1, true case "rang": // MATHEMATICAL RIGHT ANGLE BRACKET - return rune(0x27e9), true + return {'\u27e9', 0}, 1, true case "rangd": // RIGHT ANGLE BRACKET WITH DOT - return rune(0x2992), true + return {'\u2992', 0}, 1, true case "range": // REVERSED ANGLE WITH UNDERBAR - return rune(0x29a5), true + return {'\u29a5', 0}, 1, true case "rangle": // MATHEMATICAL RIGHT ANGLE BRACKET - return rune(0x27e9), true + return {'\u27e9', 0}, 1, true case "raquo": // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - return rune(0xbb), true + return {'»', 0}, 1, true case "rarr": // RIGHTWARDS ARROW - return rune(0x2192), true + return {'\u2192', 0}, 1, true case "rarr2": // RIGHTWARDS PAIRED ARROWS - return rune(0x21c9), true + return {'\u21c9', 0}, 1, true case "rarr3": // THREE RIGHTWARDS ARROWS - return rune(0x21f6), true + return {'\u21f6', 0}, 1, true case "rarrap": // RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO - return rune(0x2975), true + return {'\u2975', 0}, 1, true case "rarrb": // RIGHTWARDS ARROW TO BAR - return rune(0x21e5), true + return {'\u21e5', 0}, 1, true case "rarrbfs": // RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND - return rune(0x2920), true + return {'\u2920', 0}, 1, true case "rarrc": // WAVE ARROW POINTING DIRECTLY RIGHT - return rune(0x2933), true + return {'\u2933', 0}, 1, true case "rarrfs": // RIGHTWARDS ARROW TO BLACK DIAMOND - return rune(0x291e), true + return {'\u291e', 0}, 1, true case "rarrhk": // RIGHTWARDS ARROW WITH HOOK - return rune(0x21aa), true + return {'\u21aa', 0}, 1, true case "rarrlp": // RIGHTWARDS ARROW WITH LOOP - return rune(0x21ac), true + return {'\u21ac', 0}, 1, true case "rarrpl": // RIGHTWARDS ARROW WITH PLUS BELOW - return rune(0x2945), true + return {'\u2945', 0}, 1, true case "rarrsim": // RIGHTWARDS ARROW ABOVE TILDE OPERATOR - return rune(0x2974), true + return {'\u2974', 0}, 1, true case "rarrtl": // RIGHTWARDS ARROW WITH TAIL - return rune(0x21a3), true + return {'\u21a3', 0}, 1, true case "rarrw": // RIGHTWARDS WAVE ARROW - return rune(0x219d), true + return {'\u219d', 0}, 1, true case "rarrx": // RIGHTWARDS ARROW THROUGH X - return rune(0x2947), true + return {'\u2947', 0}, 1, true case "ratail": // RIGHTWARDS ARROW-TAIL - return rune(0x291a), true + return {'\u291a', 0}, 1, true case "ratio": // RATIO - return rune(0x2236), true + return {'\u2236', 0}, 1, true case "rationals": // DOUBLE-STRUCK CAPITAL Q - return rune(0x211a), true + return {'\u211a', 0}, 1, true case "rbarr": // RIGHTWARDS DOUBLE DASH ARROW - return rune(0x290d), true + return {'\u290d', 0}, 1, true case "rbbrk": // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT - return rune(0x2773), true + return {'\u2773', 0}, 1, true case "rbrace": // RIGHT CURLY BRACKET - return rune(0x7d), true + return {'}', 0}, 1, true case "rbrack": // RIGHT SQUARE BRACKET - return rune(0x5d), true + return {']', 0}, 1, true case "rbrke": // RIGHT SQUARE BRACKET WITH UNDERBAR - return rune(0x298c), true + return {'\u298c', 0}, 1, true case "rbrksld": // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER - return rune(0x298e), true + return {'\u298e', 0}, 1, true case "rbrkslu": // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER - return rune(0x2990), true + return {'\u2990', 0}, 1, true case "rcaron": // LATIN SMALL LETTER R WITH CARON - return rune(0x0159), true + return {'\u0159', 0}, 1, true case "rcedil": // LATIN SMALL LETTER R WITH CEDILLA - return rune(0x0157), true + return {'\u0157', 0}, 1, true case "rceil": // RIGHT CEILING - return rune(0x2309), true + return {'\u2309', 0}, 1, true case "rcub": // RIGHT CURLY BRACKET - return rune(0x7d), true + return {'}', 0}, 1, true case "rcy": // CYRILLIC SMALL LETTER ER - return rune(0x0440), true + return {'\u0440', 0}, 1, true case "rdca": // ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS - return rune(0x2937), true + return {'\u2937', 0}, 1, true case "rdharb": // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR - return rune(0x2957), true + return {'\u2957', 0}, 1, true case "rdiag": // BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT - return rune(0x2571), true + return {'\u2571', 0}, 1, true case "rdiofdi": // RISING DIAGONAL CROSSING FALLING DIAGONAL - return rune(0x292b), true + return {'\u292b', 0}, 1, true case "rdldhar": // RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN - return rune(0x2969), true + return {'\u2969', 0}, 1, true case "rdosearr": // RISING DIAGONAL CROSSING SOUTH EAST ARROW - return rune(0x2930), true + return {'\u2930', 0}, 1, true case "rdquo": // RIGHT DOUBLE QUOTATION MARK - return rune(0x201d), true + return {'\u201d', 0}, 1, true case "rdquor": // RIGHT DOUBLE QUOTATION MARK - return rune(0x201d), true + return {'\u201d', 0}, 1, true case "rdsh": // DOWNWARDS ARROW WITH TIP RIGHTWARDS - return rune(0x21b3), true + return {'\u21b3', 0}, 1, true case "real": // BLACK-LETTER CAPITAL R - return rune(0x211c), true + return {'\u211c', 0}, 1, true case "realine": // SCRIPT CAPITAL R - return rune(0x211b), true + return {'\u211b', 0}, 1, true case "realpart": // BLACK-LETTER CAPITAL R - return rune(0x211c), true + return {'\u211c', 0}, 1, true case "reals": // DOUBLE-STRUCK CAPITAL R - return rune(0x211d), true + return {'\u211d', 0}, 1, true case "rect": // WHITE RECTANGLE - return rune(0x25ad), true + return {'\u25ad', 0}, 1, true case "reg": // REGISTERED SIGN - return rune(0xae), true + return {'®', 0}, 1, true case "rfbowtie": // BOWTIE WITH RIGHT HALF BLACK - return rune(0x29d2), true + return {'\u29d2', 0}, 1, true case "rfisht": // RIGHT FISH TAIL - return rune(0x297d), true + return {'\u297d', 0}, 1, true case "rfloor": // RIGHT FLOOR - return rune(0x230b), true + return {'\u230b', 0}, 1, true case "rfr": // MATHEMATICAL FRAKTUR SMALL R - return rune(0x01d52f), true + return {'\U0001d52f', 0}, 1, true case "rftimes": // TIMES WITH RIGHT HALF BLACK - return rune(0x29d5), true + return {'\u29d5', 0}, 1, true case "rgr": // GREEK SMALL LETTER RHO - return rune(0x03c1), true + return {'\u03c1', 0}, 1, true case "rhard": // RIGHTWARDS HARPOON WITH BARB DOWNWARDS - return rune(0x21c1), true + return {'\u21c1', 0}, 1, true case "rharu": // RIGHTWARDS HARPOON WITH BARB UPWARDS - return rune(0x21c0), true + return {'\u21c0', 0}, 1, true case "rharul": // RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH - return rune(0x296c), true + return {'\u296c', 0}, 1, true case "rho": // GREEK SMALL LETTER RHO - return rune(0x03c1), true + return {'\u03c1', 0}, 1, true case "rhov": // GREEK RHO SYMBOL - return rune(0x03f1), true + return {'\u03f1', 0}, 1, true case "rightarrow": // RIGHTWARDS ARROW - return rune(0x2192), true + return {'\u2192', 0}, 1, true case "rightarrowtail": // RIGHTWARDS ARROW WITH TAIL - return rune(0x21a3), true + return {'\u21a3', 0}, 1, true case "rightharpoondown": // RIGHTWARDS HARPOON WITH BARB DOWNWARDS - return rune(0x21c1), true + return {'\u21c1', 0}, 1, true case "rightharpoonup": // RIGHTWARDS HARPOON WITH BARB UPWARDS - return rune(0x21c0), true + return {'\u21c0', 0}, 1, true case "rightleftarrows": // RIGHTWARDS ARROW OVER LEFTWARDS ARROW - return rune(0x21c4), true + return {'\u21c4', 0}, 1, true case "rightleftharpoons": // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON - return rune(0x21cc), true + return {'\u21cc', 0}, 1, true case "rightrightarrows": // RIGHTWARDS PAIRED ARROWS - return rune(0x21c9), true + return {'\u21c9', 0}, 1, true case "rightsquigarrow": // RIGHTWARDS WAVE ARROW - return rune(0x219d), true + return {'\u219d', 0}, 1, true case "rightthreetimes": // RIGHT SEMIDIRECT PRODUCT - return rune(0x22cc), true + return {'\u22cc', 0}, 1, true case "rimply": // RIGHT DOUBLE ARROW WITH ROUNDED HEAD - return rune(0x2970), true + return {'\u2970', 0}, 1, true case "ring": // RING ABOVE - return rune(0x02da), true + return {'\u02da', 0}, 1, true case "risingdotseq": // IMAGE OF OR APPROXIMATELY EQUAL TO - return rune(0x2253), true + return {'\u2253', 0}, 1, true case "rlarr": // RIGHTWARDS ARROW OVER LEFTWARDS ARROW - return rune(0x21c4), true + return {'\u21c4', 0}, 1, true case "rlarr2": // RIGHTWARDS ARROW OVER LEFTWARDS ARROW - return rune(0x21c4), true + return {'\u21c4', 0}, 1, true case "rlhar": // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON - return rune(0x21cc), true + return {'\u21cc', 0}, 1, true case "rlhar2": // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON - return rune(0x21cc), true + return {'\u21cc', 0}, 1, true case "rlm": // RIGHT-TO-LEFT MARK - return rune(0x200f), true + return {'\u200f', 0}, 1, true case "rmoust": // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION - return rune(0x23b1), true + return {'\u23b1', 0}, 1, true case "rmoustache": // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION - return rune(0x23b1), true + return {'\u23b1', 0}, 1, true case "rnmid": // DOES NOT DIVIDE WITH REVERSED NEGATION SLASH - return rune(0x2aee), true + return {'\u2aee', 0}, 1, true case "roang": // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET - return rune(0x27ed), true + return {'\u27ed', 0}, 1, true case "roarr": // RIGHTWARDS OPEN-HEADED ARROW - return rune(0x21fe), true + return {'\u21fe', 0}, 1, true case "robrk": // MATHEMATICAL RIGHT WHITE SQUARE BRACKET - return rune(0x27e7), true + return {'\u27e7', 0}, 1, true case "rocub": // RIGHT WHITE CURLY BRACKET - return rune(0x2984), true + return {'\u2984', 0}, 1, true case "ropar": // RIGHT WHITE PARENTHESIS - return rune(0x2986), true + return {'\u2986', 0}, 1, true case "ropf": // MATHEMATICAL DOUBLE-STRUCK SMALL R - return rune(0x01d563), true + return {'\U0001d563', 0}, 1, true case "roplus": // PLUS SIGN IN RIGHT HALF CIRCLE - return rune(0x2a2e), true + return {'\u2a2e', 0}, 1, true case "rotimes": // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE - return rune(0x2a35), true + return {'\u2a35', 0}, 1, true case "rpar": // RIGHT PARENTHESIS - return rune(0x29), true + return {')', 0}, 1, true case "rpargt": // RIGHT ARC GREATER-THAN BRACKET - return rune(0x2994), true + return {'\u2994', 0}, 1, true case "rppolint": // LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE - return rune(0x2a12), true + return {'\u2a12', 0}, 1, true case "rrarr": // RIGHTWARDS PAIRED ARROWS - return rune(0x21c9), true + return {'\u21c9', 0}, 1, true case "rsaquo": // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - return rune(0x203a), true + return {'\u203a', 0}, 1, true case "rscr": // MATHEMATICAL SCRIPT SMALL R - return rune(0x01d4c7), true + return {'\U0001d4c7', 0}, 1, true case "rsh": // UPWARDS ARROW WITH TIP RIGHTWARDS - return rune(0x21b1), true + return {'\u21b1', 0}, 1, true case "rsolbar": // REVERSE SOLIDUS WITH HORIZONTAL STROKE - return rune(0x29f7), true + return {'\u29f7', 0}, 1, true case "rsqb": // RIGHT SQUARE BRACKET - return rune(0x5d), true + return {']', 0}, 1, true case "rsquo": // RIGHT SINGLE QUOTATION MARK - return rune(0x2019), true + return {'\u2019', 0}, 1, true case "rsquor": // RIGHT SINGLE QUOTATION MARK - return rune(0x2019), true + return {'\u2019', 0}, 1, true case "rthree": // RIGHT SEMIDIRECT PRODUCT - return rune(0x22cc), true + return {'\u22cc', 0}, 1, true case "rtimes": // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT - return rune(0x22ca), true + return {'\u22ca', 0}, 1, true case "rtri": // WHITE RIGHT-POINTING SMALL TRIANGLE - return rune(0x25b9), true + return {'\u25b9', 0}, 1, true case "rtrie": // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO - return rune(0x22b5), true + return {'\u22b5', 0}, 1, true case "rtrif": // BLACK RIGHT-POINTING SMALL TRIANGLE - return rune(0x25b8), true + return {'\u25b8', 0}, 1, true case "rtriltri": // RIGHT TRIANGLE ABOVE LEFT TRIANGLE - return rune(0x29ce), true + return {'\u29ce', 0}, 1, true case "ruharb": // RIGHTWARDS HARPOON WITH BARB UP TO BAR - return rune(0x2953), true + return {'\u2953', 0}, 1, true case "ruluhar": // RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP - return rune(0x2968), true + return {'\u2968', 0}, 1, true case "rx": // PRESCRIPTION TAKE - return rune(0x211e), true + return {'\u211e', 0}, 1, true } case 's': switch name { case "sacute": // LATIN SMALL LETTER S WITH ACUTE - return rune(0x015b), true + return {'\u015b', 0}, 1, true case "samalg": // N-ARY COPRODUCT - return rune(0x2210), true + return {'\u2210', 0}, 1, true case "sampi": // GREEK LETTER SAMPI - return rune(0x03e0), true + return {'\u03e0', 0}, 1, true case "sbquo": // SINGLE LOW-9 QUOTATION MARK - return rune(0x201a), true + return {'\u201a', 0}, 1, true case "sbsol": // SMALL REVERSE SOLIDUS - return rune(0xfe68), true + return {'\ufe68', 0}, 1, true case "sc": // SUCCEEDS - return rune(0x227b), true + return {'\u227b', 0}, 1, true case "scE": // SUCCEEDS ABOVE EQUALS SIGN - return rune(0x2ab4), true + return {'\u2ab4', 0}, 1, true case "scap": // SUCCEEDS ABOVE ALMOST EQUAL TO - return rune(0x2ab8), true + return {'\u2ab8', 0}, 1, true case "scaron": // LATIN SMALL LETTER S WITH CARON - return rune(0x0161), true + return {'\u0161', 0}, 1, true case "sccue": // SUCCEEDS OR EQUAL TO - return rune(0x227d), true + return {'\u227d', 0}, 1, true case "sce": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN - return rune(0x2ab0), true + return {'\u2ab0', 0}, 1, true case "scedil": // LATIN SMALL LETTER S WITH CEDILLA - return rune(0x015f), true + return {'\u015f', 0}, 1, true case "scirc": // LATIN SMALL LETTER S WITH CIRCUMFLEX - return rune(0x015d), true + return {'\u015d', 0}, 1, true case "scnE": // SUCCEEDS ABOVE NOT EQUAL TO - return rune(0x2ab6), true + return {'\u2ab6', 0}, 1, true case "scnap": // SUCCEEDS ABOVE NOT ALMOST EQUAL TO - return rune(0x2aba), true + return {'\u2aba', 0}, 1, true case "scnsim": // SUCCEEDS BUT NOT EQUIVALENT TO - return rune(0x22e9), true + return {'\u22e9', 0}, 1, true case "scpolint": // LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE - return rune(0x2a13), true + return {'\u2a13', 0}, 1, true case "scsim": // SUCCEEDS OR EQUIVALENT TO - return rune(0x227f), true + return {'\u227f', 0}, 1, true case "scy": // CYRILLIC SMALL LETTER ES - return rune(0x0441), true + return {'\u0441', 0}, 1, true case "sdot": // DOT OPERATOR - return rune(0x22c5), true + return {'\u22c5', 0}, 1, true case "sdotb": // SQUARED DOT OPERATOR - return rune(0x22a1), true + return {'\u22a1', 0}, 1, true case "sdote": // EQUALS SIGN WITH DOT BELOW - return rune(0x2a66), true + return {'\u2a66', 0}, 1, true case "seArr": // SOUTH EAST DOUBLE ARROW - return rune(0x21d8), true + return {'\u21d8', 0}, 1, true case "searhk": // SOUTH EAST ARROW WITH HOOK - return rune(0x2925), true + return {'\u2925', 0}, 1, true case "searr": // SOUTH EAST ARROW - return rune(0x2198), true + return {'\u2198', 0}, 1, true case "searrow": // SOUTH EAST ARROW - return rune(0x2198), true + return {'\u2198', 0}, 1, true case "sect": // SECTION SIGN - return rune(0xa7), true + return {'§', 0}, 1, true case "semi": // SEMICOLON - return rune(0x3b), true + return {';', 0}, 1, true case "seonearr": // SOUTH EAST ARROW CROSSING NORTH EAST ARROW - return rune(0x292d), true + return {'\u292d', 0}, 1, true case "seswar": // SOUTH EAST ARROW AND SOUTH WEST ARROW - return rune(0x2929), true + return {'\u2929', 0}, 1, true case "setminus": // SET MINUS - return rune(0x2216), true + return {'\u2216', 0}, 1, true case "setmn": // SET MINUS - return rune(0x2216), true + return {'\u2216', 0}, 1, true case "sext": // SIX POINTED BLACK STAR - return rune(0x2736), true + return {'\u2736', 0}, 1, true case "sfgr": // GREEK SMALL LETTER FINAL SIGMA - return rune(0x03c2), true + return {'\u03c2', 0}, 1, true case "sfr": // MATHEMATICAL FRAKTUR SMALL S - return rune(0x01d530), true + return {'\U0001d530', 0}, 1, true case "sfrown": // FROWN - return rune(0x2322), true + return {'\u2322', 0}, 1, true case "sgr": // GREEK SMALL LETTER SIGMA - return rune(0x03c3), true + return {'\u03c3', 0}, 1, true case "sharp": // MUSIC SHARP SIGN - return rune(0x266f), true + return {'\u266f', 0}, 1, true case "shchcy": // CYRILLIC SMALL LETTER SHCHA - return rune(0x0449), true + return {'\u0449', 0}, 1, true case "shcy": // CYRILLIC SMALL LETTER SHA - return rune(0x0448), true + return {'\u0448', 0}, 1, true case "shortmid": // DIVIDES - return rune(0x2223), true + return {'\u2223', 0}, 1, true case "shortparallel": // PARALLEL TO - return rune(0x2225), true + return {'\u2225', 0}, 1, true case "shuffle": // SHUFFLE PRODUCT - return rune(0x29e2), true + return {'\u29e2', 0}, 1, true case "shy": // SOFT HYPHEN - return rune(0xad), true + return {'\u00ad', 0}, 1, true case "sigma": // GREEK SMALL LETTER SIGMA - return rune(0x03c3), true + return {'\u03c3', 0}, 1, true case "sigmaf": // GREEK SMALL LETTER FINAL SIGMA - return rune(0x03c2), true + return {'\u03c2', 0}, 1, true case "sigmav": // GREEK SMALL LETTER FINAL SIGMA - return rune(0x03c2), true + return {'\u03c2', 0}, 1, true case "sim": // TILDE OPERATOR - return rune(0x223c), true + return {'\u223c', 0}, 1, true case "simdot": // TILDE OPERATOR WITH DOT ABOVE - return rune(0x2a6a), true + return {'\u2a6a', 0}, 1, true case "sime": // ASYMPTOTICALLY EQUAL TO - return rune(0x2243), true + return {'\u2243', 0}, 1, true case "simeq": // ASYMPTOTICALLY EQUAL TO - return rune(0x2243), true + return {'\u2243', 0}, 1, true case "simg": // SIMILAR OR GREATER-THAN - return rune(0x2a9e), true + return {'\u2a9e', 0}, 1, true case "simgE": // SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN - return rune(0x2aa0), true + return {'\u2aa0', 0}, 1, true case "siml": // SIMILAR OR LESS-THAN - return rune(0x2a9d), true + return {'\u2a9d', 0}, 1, true case "simlE": // SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN - return rune(0x2a9f), true + return {'\u2a9f', 0}, 1, true case "simne": // APPROXIMATELY BUT NOT ACTUALLY EQUAL TO - return rune(0x2246), true + return {'\u2246', 0}, 1, true case "simplus": // PLUS SIGN WITH TILDE ABOVE - return rune(0x2a24), true + return {'\u2a24', 0}, 1, true case "simrarr": // TILDE OPERATOR ABOVE RIGHTWARDS ARROW - return rune(0x2972), true + return {'\u2972', 0}, 1, true case "slarr": // LEFTWARDS ARROW - return rune(0x2190), true + return {'\u2190', 0}, 1, true case "slint": // INTEGRAL AVERAGE WITH SLASH - return rune(0x2a0f), true + return {'\u2a0f', 0}, 1, true case "smallsetminus": // SET MINUS - return rune(0x2216), true + return {'\u2216', 0}, 1, true case "smashp": // SMASH PRODUCT - return rune(0x2a33), true + return {'\u2a33', 0}, 1, true case "smeparsl": // EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE - return rune(0x29e4), true + return {'\u29e4', 0}, 1, true case "smid": // DIVIDES - return rune(0x2223), true + return {'\u2223', 0}, 1, true case "smile": // SMILE - return rune(0x2323), true + return {'\u2323', 0}, 1, true case "smt": // SMALLER THAN - return rune(0x2aaa), true + return {'\u2aaa', 0}, 1, true case "smte": // SMALLER THAN OR EQUAL TO - return rune(0x2aac), true + return {'\u2aac', 0}, 1, true case "smtes": // SMALLER THAN OR slanted EQUAL - return rune(0x2aac), true + return {'\u2aac', '\ufe00'}, 2, true case "softcy": // CYRILLIC SMALL LETTER SOFT SIGN - return rune(0x044c), true + return {'\u044c', 0}, 1, true case "sol": // SOLIDUS - return rune(0x2f), true + return {'/', 0}, 1, true case "solb": // SQUARED RISING DIAGONAL SLASH - return rune(0x29c4), true + return {'\u29c4', 0}, 1, true case "solbar": // APL FUNCTIONAL SYMBOL SLASH BAR - return rune(0x233f), true + return {'\u233f', 0}, 1, true case "sopf": // MATHEMATICAL DOUBLE-STRUCK SMALL S - return rune(0x01d564), true + return {'\U0001d564', 0}, 1, true case "spades": // BLACK SPADE SUIT - return rune(0x2660), true + return {'\u2660', 0}, 1, true case "spadesuit": // BLACK SPADE SUIT - return rune(0x2660), true + return {'\u2660', 0}, 1, true case "spar": // PARALLEL TO - return rune(0x2225), true + return {'\u2225', 0}, 1, true case "sqcap": // SQUARE CAP - return rune(0x2293), true + return {'\u2293', 0}, 1, true case "sqcaps": // SQUARE CAP with serifs - return rune(0x2293), true + return {'\u2293', '\ufe00'}, 2, true case "sqcup": // SQUARE CUP - return rune(0x2294), true + return {'\u2294', 0}, 1, true case "sqcups": // SQUARE CUP with serifs - return rune(0x2294), true + return {'\u2294', '\ufe00'}, 2, true case "sqsub": // SQUARE IMAGE OF - return rune(0x228f), true + return {'\u228f', 0}, 1, true case "sqsube": // SQUARE IMAGE OF OR EQUAL TO - return rune(0x2291), true + return {'\u2291', 0}, 1, true case "sqsubset": // SQUARE IMAGE OF - return rune(0x228f), true + return {'\u228f', 0}, 1, true case "sqsubseteq": // SQUARE IMAGE OF OR EQUAL TO - return rune(0x2291), true + return {'\u2291', 0}, 1, true case "sqsup": // SQUARE ORIGINAL OF - return rune(0x2290), true + return {'\u2290', 0}, 1, true case "sqsupe": // SQUARE ORIGINAL OF OR EQUAL TO - return rune(0x2292), true + return {'\u2292', 0}, 1, true case "sqsupset": // SQUARE ORIGINAL OF - return rune(0x2290), true + return {'\u2290', 0}, 1, true case "sqsupseteq": // SQUARE ORIGINAL OF OR EQUAL TO - return rune(0x2292), true + return {'\u2292', 0}, 1, true case "squ": // WHITE SQUARE - return rune(0x25a1), true + return {'\u25a1', 0}, 1, true case "square": // WHITE SQUARE - return rune(0x25a1), true + return {'\u25a1', 0}, 1, true case "squarf": // BLACK SMALL SQUARE - return rune(0x25aa), true + return {'\u25aa', 0}, 1, true case "squb": // SQUARED SQUARE - return rune(0x29c8), true + return {'\u29c8', 0}, 1, true case "squerr": // ERROR-BARRED WHITE SQUARE - return rune(0x29ee), true + return {'\u29ee', 0}, 1, true case "squf": // BLACK SMALL SQUARE - return rune(0x25aa), true + return {'\u25aa', 0}, 1, true case "squferr": // ERROR-BARRED BLACK SQUARE - return rune(0x29ef), true + return {'\u29ef', 0}, 1, true case "srarr": // RIGHTWARDS ARROW - return rune(0x2192), true + return {'\u2192', 0}, 1, true case "sscr": // MATHEMATICAL SCRIPT SMALL S - return rune(0x01d4c8), true + return {'\U0001d4c8', 0}, 1, true case "ssetmn": // SET MINUS - return rune(0x2216), true + return {'\u2216', 0}, 1, true case "ssmile": // SMILE - return rune(0x2323), true + return {'\u2323', 0}, 1, true case "sstarf": // STAR OPERATOR - return rune(0x22c6), true + return {'\u22c6', 0}, 1, true case "star": // WHITE STAR - return rune(0x2606), true + return {'\u2606', 0}, 1, true case "starf": // BLACK STAR - return rune(0x2605), true + return {'\u2605', 0}, 1, true case "stigma": // GREEK LETTER STIGMA - return rune(0x03da), true + return {'\u03da', 0}, 1, true case "straightepsilon": // GREEK LUNATE EPSILON SYMBOL - return rune(0x03f5), true + return {'\u03f5', 0}, 1, true case "straightphi": // GREEK PHI SYMBOL - return rune(0x03d5), true + return {'\u03d5', 0}, 1, true case "strns": // MACRON - return rune(0xaf), true + return {'¯', 0}, 1, true case "sub": // SUBSET OF - return rune(0x2282), true + return {'\u2282', 0}, 1, true case "subE": // SUBSET OF ABOVE EQUALS SIGN - return rune(0x2ac5), true + return {'\u2ac5', 0}, 1, true case "subdot": // SUBSET WITH DOT - return rune(0x2abd), true + return {'\u2abd', 0}, 1, true case "sube": // SUBSET OF OR EQUAL TO - return rune(0x2286), true + return {'\u2286', 0}, 1, true case "subedot": // SUBSET OF OR EQUAL TO WITH DOT ABOVE - return rune(0x2ac3), true + return {'\u2ac3', 0}, 1, true case "submult": // SUBSET WITH MULTIPLICATION SIGN BELOW - return rune(0x2ac1), true + return {'\u2ac1', 0}, 1, true case "subnE": // SUBSET OF ABOVE NOT EQUAL TO - return rune(0x2acb), true + return {'\u2acb', 0}, 1, true case "subne": // SUBSET OF WITH NOT EQUAL TO - return rune(0x228a), true + return {'\u228a', 0}, 1, true case "subplus": // SUBSET WITH PLUS SIGN BELOW - return rune(0x2abf), true + return {'\u2abf', 0}, 1, true case "subrarr": // SUBSET ABOVE RIGHTWARDS ARROW - return rune(0x2979), true + return {'\u2979', 0}, 1, true case "subset": // SUBSET OF - return rune(0x2282), true + return {'\u2282', 0}, 1, true case "subseteq": // SUBSET OF OR EQUAL TO - return rune(0x2286), true + return {'\u2286', 0}, 1, true case "subseteqq": // SUBSET OF ABOVE EQUALS SIGN - return rune(0x2ac5), true + return {'\u2ac5', 0}, 1, true case "subsetneq": // SUBSET OF WITH NOT EQUAL TO - return rune(0x228a), true + return {'\u228a', 0}, 1, true case "subsetneqq": // SUBSET OF ABOVE NOT EQUAL TO - return rune(0x2acb), true + return {'\u2acb', 0}, 1, true case "subsim": // SUBSET OF ABOVE TILDE OPERATOR - return rune(0x2ac7), true + return {'\u2ac7', 0}, 1, true case "subsub": // SUBSET ABOVE SUBSET - return rune(0x2ad5), true + return {'\u2ad5', 0}, 1, true case "subsup": // SUBSET ABOVE SUPERSET - return rune(0x2ad3), true + return {'\u2ad3', 0}, 1, true case "succ": // SUCCEEDS - return rune(0x227b), true + return {'\u227b', 0}, 1, true case "succapprox": // SUCCEEDS ABOVE ALMOST EQUAL TO - return rune(0x2ab8), true + return {'\u2ab8', 0}, 1, true case "succcurlyeq": // SUCCEEDS OR EQUAL TO - return rune(0x227d), true + return {'\u227d', 0}, 1, true case "succeq": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN - return rune(0x2ab0), true + return {'\u2ab0', 0}, 1, true case "succnapprox": // SUCCEEDS ABOVE NOT ALMOST EQUAL TO - return rune(0x2aba), true + return {'\u2aba', 0}, 1, true case "succneqq": // SUCCEEDS ABOVE NOT EQUAL TO - return rune(0x2ab6), true + return {'\u2ab6', 0}, 1, true case "succnsim": // SUCCEEDS BUT NOT EQUIVALENT TO - return rune(0x22e9), true + return {'\u22e9', 0}, 1, true case "succsim": // SUCCEEDS OR EQUIVALENT TO - return rune(0x227f), true + return {'\u227f', 0}, 1, true case "sum": // N-ARY SUMMATION - return rune(0x2211), true + return {'\u2211', 0}, 1, true case "sumint": // SUMMATION WITH INTEGRAL - return rune(0x2a0b), true + return {'\u2a0b', 0}, 1, true case "sung": // EIGHTH NOTE - return rune(0x266a), true + return {'\u266a', 0}, 1, true case "sup": // SUPERSET OF - return rune(0x2283), true + return {'\u2283', 0}, 1, true case "sup1": // SUPERSCRIPT ONE - return rune(0xb9), true + return {'¹', 0}, 1, true case "sup2": // SUPERSCRIPT TWO - return rune(0xb2), true + return {'²', 0}, 1, true case "sup3": // SUPERSCRIPT THREE - return rune(0xb3), true + return {'³', 0}, 1, true case "supE": // SUPERSET OF ABOVE EQUALS SIGN - return rune(0x2ac6), true + return {'\u2ac6', 0}, 1, true case "supdot": // SUPERSET WITH DOT - return rune(0x2abe), true + return {'\u2abe', 0}, 1, true case "supdsub": // SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET - return rune(0x2ad8), true + return {'\u2ad8', 0}, 1, true case "supe": // SUPERSET OF OR EQUAL TO - return rune(0x2287), true + return {'\u2287', 0}, 1, true case "supedot": // SUPERSET OF OR EQUAL TO WITH DOT ABOVE - return rune(0x2ac4), true + return {'\u2ac4', 0}, 1, true case "suphsol": // SUPERSET PRECEDING SOLIDUS - return rune(0x27c9), true + return {'\u27c9', 0}, 1, true case "suphsub": // SUPERSET BESIDE SUBSET - return rune(0x2ad7), true + return {'\u2ad7', 0}, 1, true case "suplarr": // SUPERSET ABOVE LEFTWARDS ARROW - return rune(0x297b), true + return {'\u297b', 0}, 1, true case "supmult": // SUPERSET WITH MULTIPLICATION SIGN BELOW - return rune(0x2ac2), true + return {'\u2ac2', 0}, 1, true case "supnE": // SUPERSET OF ABOVE NOT EQUAL TO - return rune(0x2acc), true + return {'\u2acc', 0}, 1, true case "supne": // SUPERSET OF WITH NOT EQUAL TO - return rune(0x228b), true + return {'\u228b', 0}, 1, true case "supplus": // SUPERSET WITH PLUS SIGN BELOW - return rune(0x2ac0), true + return {'\u2ac0', 0}, 1, true case "supset": // SUPERSET OF - return rune(0x2283), true + return {'\u2283', 0}, 1, true case "supseteq": // SUPERSET OF OR EQUAL TO - return rune(0x2287), true + return {'\u2287', 0}, 1, true case "supseteqq": // SUPERSET OF ABOVE EQUALS SIGN - return rune(0x2ac6), true + return {'\u2ac6', 0}, 1, true case "supsetneq": // SUPERSET OF WITH NOT EQUAL TO - return rune(0x228b), true + return {'\u228b', 0}, 1, true case "supsetneqq": // SUPERSET OF ABOVE NOT EQUAL TO - return rune(0x2acc), true + return {'\u2acc', 0}, 1, true case "supsim": // SUPERSET OF ABOVE TILDE OPERATOR - return rune(0x2ac8), true + return {'\u2ac8', 0}, 1, true case "supsub": // SUPERSET ABOVE SUBSET - return rune(0x2ad4), true + return {'\u2ad4', 0}, 1, true case "supsup": // SUPERSET ABOVE SUPERSET - return rune(0x2ad6), true + return {'\u2ad6', 0}, 1, true case "swArr": // SOUTH WEST DOUBLE ARROW - return rune(0x21d9), true + return {'\u21d9', 0}, 1, true case "swarhk": // SOUTH WEST ARROW WITH HOOK - return rune(0x2926), true + return {'\u2926', 0}, 1, true case "swarr": // SOUTH WEST ARROW - return rune(0x2199), true + return {'\u2199', 0}, 1, true case "swarrow": // SOUTH WEST ARROW - return rune(0x2199), true + return {'\u2199', 0}, 1, true case "swnwar": // SOUTH WEST ARROW AND NORTH WEST ARROW - return rune(0x292a), true + return {'\u292a', 0}, 1, true case "szlig": // LATIN SMALL LETTER SHARP S - return rune(0xdf), true + return {'ß', 0}, 1, true } case 't': switch name { case "target": // POSITION INDICATOR - return rune(0x2316), true + return {'\u2316', 0}, 1, true case "tau": // GREEK SMALL LETTER TAU - return rune(0x03c4), true + return {'\u03c4', 0}, 1, true case "tbrk": // TOP SQUARE BRACKET - return rune(0x23b4), true + return {'\u23b4', 0}, 1, true case "tcaron": // LATIN SMALL LETTER T WITH CARON - return rune(0x0165), true + return {'\u0165', 0}, 1, true case "tcedil": // LATIN SMALL LETTER T WITH CEDILLA - return rune(0x0163), true + return {'\u0163', 0}, 1, true case "tcy": // CYRILLIC SMALL LETTER TE - return rune(0x0442), true + return {'\u0442', 0}, 1, true case "tdot": // COMBINING THREE DOTS ABOVE - return rune(0x20db), true + return {'\u20db', 0}, 1, true case "telrec": // TELEPHONE RECORDER - return rune(0x2315), true + return {'\u2315', 0}, 1, true case "tfr": // MATHEMATICAL FRAKTUR SMALL T - return rune(0x01d531), true + return {'\U0001d531', 0}, 1, true case "tgr": // GREEK SMALL LETTER TAU - return rune(0x03c4), true + return {'\u03c4', 0}, 1, true case "there4": // THEREFORE - return rune(0x2234), true + return {'\u2234', 0}, 1, true case "therefore": // THEREFORE - return rune(0x2234), true + return {'\u2234', 0}, 1, true case "thermod": // THERMODYNAMIC - return rune(0x29e7), true + return {'\u29e7', 0}, 1, true case "theta": // GREEK SMALL LETTER THETA - return rune(0x03b8), true + return {'\u03b8', 0}, 1, true case "thetas": // GREEK SMALL LETTER THETA - return rune(0x03b8), true + return {'\u03b8', 0}, 1, true case "thetasym": // GREEK THETA SYMBOL - return rune(0x03d1), true + return {'\u03d1', 0}, 1, true case "thetav": // GREEK THETA SYMBOL - return rune(0x03d1), true + return {'\u03d1', 0}, 1, true case "thgr": // GREEK SMALL LETTER THETA - return rune(0x03b8), true + return {'\u03b8', 0}, 1, true case "thickapprox": // ALMOST EQUAL TO - return rune(0x2248), true + return {'\u2248', 0}, 1, true case "thicksim": // TILDE OPERATOR - return rune(0x223c), true + return {'\u223c', 0}, 1, true case "thinsp": // THIN SPACE - return rune(0x2009), true + return {'\u2009', 0}, 1, true case "thkap": // ALMOST EQUAL TO - return rune(0x2248), true + return {'\u2248', 0}, 1, true case "thksim": // TILDE OPERATOR - return rune(0x223c), true + return {'\u223c', 0}, 1, true case "thorn": // LATIN SMALL LETTER THORN - return rune(0xfe), true + return {'þ', 0}, 1, true case "tilde": // SMALL TILDE - return rune(0x02dc), true + return {'\u02dc', 0}, 1, true case "timeint": // INTEGRAL WITH TIMES SIGN - return rune(0x2a18), true + return {'\u2a18', 0}, 1, true case "times": // MULTIPLICATION SIGN - return rune(0xd7), true + return {'×', 0}, 1, true case "timesb": // SQUARED TIMES - return rune(0x22a0), true + return {'\u22a0', 0}, 1, true case "timesbar": // MULTIPLICATION SIGN WITH UNDERBAR - return rune(0x2a31), true + return {'\u2a31', 0}, 1, true case "timesd": // MULTIPLICATION SIGN WITH DOT ABOVE - return rune(0x2a30), true + return {'\u2a30', 0}, 1, true case "tint": // TRIPLE INTEGRAL - return rune(0x222d), true + return {'\u222d', 0}, 1, true case "toea": // NORTH EAST ARROW AND SOUTH EAST ARROW - return rune(0x2928), true + return {'\u2928', 0}, 1, true case "top": // DOWN TACK - return rune(0x22a4), true + return {'\u22a4', 0}, 1, true case "topbot": // APL FUNCTIONAL SYMBOL I-BEAM - return rune(0x2336), true + return {'\u2336', 0}, 1, true case "topcir": // DOWN TACK WITH CIRCLE BELOW - return rune(0x2af1), true + return {'\u2af1', 0}, 1, true case "topf": // MATHEMATICAL DOUBLE-STRUCK SMALL T - return rune(0x01d565), true + return {'\U0001d565', 0}, 1, true case "topfork": // PITCHFORK WITH TEE TOP - return rune(0x2ada), true + return {'\u2ada', 0}, 1, true case "tosa": // SOUTH EAST ARROW AND SOUTH WEST ARROW - return rune(0x2929), true + return {'\u2929', 0}, 1, true case "tprime": // TRIPLE PRIME - return rune(0x2034), true + return {'\u2034', 0}, 1, true case "trade": // TRADE MARK SIGN - return rune(0x2122), true + return {'\u2122', 0}, 1, true case "triS": // S IN TRIANGLE - return rune(0x29cc), true + return {'\u29cc', 0}, 1, true case "triangle": // WHITE UP-POINTING SMALL TRIANGLE - return rune(0x25b5), true + return {'\u25b5', 0}, 1, true case "triangledown": // WHITE DOWN-POINTING SMALL TRIANGLE - return rune(0x25bf), true + return {'\u25bf', 0}, 1, true case "triangleleft": // WHITE LEFT-POINTING SMALL TRIANGLE - return rune(0x25c3), true + return {'\u25c3', 0}, 1, true case "trianglelefteq": // NORMAL SUBGROUP OF OR EQUAL TO - return rune(0x22b4), true + return {'\u22b4', 0}, 1, true case "triangleq": // DELTA EQUAL TO - return rune(0x225c), true + return {'\u225c', 0}, 1, true case "triangleright": // WHITE RIGHT-POINTING SMALL TRIANGLE - return rune(0x25b9), true + return {'\u25b9', 0}, 1, true case "trianglerighteq": // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO - return rune(0x22b5), true + return {'\u22b5', 0}, 1, true case "tribar": // TRIANGLE WITH UNDERBAR - return rune(0x29cb), true + return {'\u29cb', 0}, 1, true case "tridot": // WHITE UP-POINTING TRIANGLE WITH DOT - return rune(0x25ec), true + return {'\u25ec', 0}, 1, true case "tridoto": // TRIANGLE WITH DOT ABOVE - return rune(0x29ca), true + return {'\u29ca', 0}, 1, true case "trie": // DELTA EQUAL TO - return rune(0x225c), true + return {'\u225c', 0}, 1, true case "triminus": // MINUS SIGN IN TRIANGLE - return rune(0x2a3a), true + return {'\u2a3a', 0}, 1, true case "triplus": // PLUS SIGN IN TRIANGLE - return rune(0x2a39), true + return {'\u2a39', 0}, 1, true case "trisb": // TRIANGLE WITH SERIFS AT BOTTOM - return rune(0x29cd), true + return {'\u29cd', 0}, 1, true case "tritime": // MULTIPLICATION SIGN IN TRIANGLE - return rune(0x2a3b), true + return {'\u2a3b', 0}, 1, true case "trpezium": // WHITE TRAPEZIUM - return rune(0x23e2), true + return {'\u23e2', 0}, 1, true case "tscr": // MATHEMATICAL SCRIPT SMALL T - return rune(0x01d4c9), true + return {'\U0001d4c9', 0}, 1, true case "tscy": // CYRILLIC SMALL LETTER TSE - return rune(0x0446), true + return {'\u0446', 0}, 1, true case "tshcy": // CYRILLIC SMALL LETTER TSHE - return rune(0x045b), true + return {'\u045b', 0}, 1, true case "tstrok": // LATIN SMALL LETTER T WITH STROKE - return rune(0x0167), true + return {'\u0167', 0}, 1, true case "tverbar": // TRIPLE VERTICAL BAR DELIMITER - return rune(0x2980), true + return {'\u2980', 0}, 1, true case "twixt": // BETWEEN - return rune(0x226c), true + return {'\u226c', 0}, 1, true case "twoheadleftarrow": // LEFTWARDS TWO HEADED ARROW - return rune(0x219e), true + return {'\u219e', 0}, 1, true case "twoheadrightarrow": // RIGHTWARDS TWO HEADED ARROW - return rune(0x21a0), true + return {'\u21a0', 0}, 1, true } case 'u': switch name { case "uAarr": // UPWARDS TRIPLE ARROW - return rune(0x290a), true + return {'\u290a', 0}, 1, true case "uArr": // UPWARDS DOUBLE ARROW - return rune(0x21d1), true + return {'\u21d1', 0}, 1, true case "uHar": // UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT - return rune(0x2963), true + return {'\u2963', 0}, 1, true case "uacgr": // GREEK SMALL LETTER UPSILON WITH TONOS - return rune(0x03cd), true + return {'\u03cd', 0}, 1, true case "uacute": // LATIN SMALL LETTER U WITH ACUTE - return rune(0xfa), true + return {'ú', 0}, 1, true case "uarr": // UPWARDS ARROW - return rune(0x2191), true + return {'\u2191', 0}, 1, true case "uarr2": // UPWARDS PAIRED ARROWS - return rune(0x21c8), true + return {'\u21c8', 0}, 1, true case "uarrb": // UPWARDS ARROW TO BAR - return rune(0x2912), true + return {'\u2912', 0}, 1, true case "uarrln": // UPWARDS ARROW WITH HORIZONTAL STROKE - return rune(0x2909), true + return {'\u2909', 0}, 1, true case "ubrcy": // CYRILLIC SMALL LETTER SHORT U - return rune(0x045e), true + return {'\u045e', 0}, 1, true case "ubreve": // LATIN SMALL LETTER U WITH BREVE - return rune(0x016d), true + return {'\u016d', 0}, 1, true case "ucirc": // LATIN SMALL LETTER U WITH CIRCUMFLEX - return rune(0xfb), true + return {'û', 0}, 1, true case "ucy": // CYRILLIC SMALL LETTER U - return rune(0x0443), true + return {'\u0443', 0}, 1, true case "udarr": // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW - return rune(0x21c5), true + return {'\u21c5', 0}, 1, true case "udblac": // LATIN SMALL LETTER U WITH DOUBLE ACUTE - return rune(0x0171), true + return {'\u0171', 0}, 1, true case "udhar": // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT - return rune(0x296e), true + return {'\u296e', 0}, 1, true case "udiagr": // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS - return rune(0x03b0), true + return {'\u03b0', 0}, 1, true case "udigr": // GREEK SMALL LETTER UPSILON WITH DIALYTIKA - return rune(0x03cb), true + return {'\u03cb', 0}, 1, true case "udrbrk": // BOTTOM SQUARE BRACKET - return rune(0x23b5), true + return {'\u23b5', 0}, 1, true case "udrcub": // BOTTOM CURLY BRACKET - return rune(0x23df), true + return {'\u23df', 0}, 1, true case "udrpar": // BOTTOM PARENTHESIS - return rune(0x23dd), true + return {'\u23dd', 0}, 1, true case "ufisht": // UP FISH TAIL - return rune(0x297e), true + return {'\u297e', 0}, 1, true case "ufr": // MATHEMATICAL FRAKTUR SMALL U - return rune(0x01d532), true + return {'\U0001d532', 0}, 1, true case "ugr": // GREEK SMALL LETTER UPSILON - return rune(0x03c5), true + return {'\u03c5', 0}, 1, true case "ugrave": // LATIN SMALL LETTER U WITH GRAVE - return rune(0xf9), true + return {'ù', 0}, 1, true case "uharl": // UPWARDS HARPOON WITH BARB LEFTWARDS - return rune(0x21bf), true + return {'\u21bf', 0}, 1, true case "uharr": // UPWARDS HARPOON WITH BARB RIGHTWARDS - return rune(0x21be), true + return {'\u21be', 0}, 1, true case "uhblk": // UPPER HALF BLOCK - return rune(0x2580), true + return {'\u2580', 0}, 1, true case "ulcorn": // TOP LEFT CORNER - return rune(0x231c), true + return {'\u231c', 0}, 1, true case "ulcorner": // TOP LEFT CORNER - return rune(0x231c), true + return {'\u231c', 0}, 1, true case "ulcrop": // TOP LEFT CROP - return rune(0x230f), true + return {'\u230f', 0}, 1, true case "uldlshar": // UP BARB LEFT DOWN BARB LEFT HARPOON - return rune(0x2951), true + return {'\u2951', 0}, 1, true case "ulharb": // UPWARDS HARPOON WITH BARB LEFT TO BAR - return rune(0x2958), true + return {'\u2958', 0}, 1, true case "ultri": // UPPER LEFT TRIANGLE - return rune(0x25f8), true + return {'\u25f8', 0}, 1, true case "umacr": // LATIN SMALL LETTER U WITH MACRON - return rune(0x016b), true + return {'\u016b', 0}, 1, true case "uml": // DIAERESIS - return rune(0xa8), true + return {'¨', 0}, 1, true case "uogon": // LATIN SMALL LETTER U WITH OGONEK - return rune(0x0173), true + return {'\u0173', 0}, 1, true case "uopf": // MATHEMATICAL DOUBLE-STRUCK SMALL U - return rune(0x01d566), true + return {'\U0001d566', 0}, 1, true case "uparrow": // UPWARDS ARROW - return rune(0x2191), true + return {'\u2191', 0}, 1, true case "updownarrow": // UP DOWN ARROW - return rune(0x2195), true + return {'\u2195', 0}, 1, true case "upharpoonleft": // UPWARDS HARPOON WITH BARB LEFTWARDS - return rune(0x21bf), true + return {'\u21bf', 0}, 1, true case "upharpoonright": // UPWARDS HARPOON WITH BARB RIGHTWARDS - return rune(0x21be), true + return {'\u21be', 0}, 1, true case "upint": // INTEGRAL WITH OVERBAR - return rune(0x2a1b), true + return {'\u2a1b', 0}, 1, true case "uplus": // MULTISET UNION - return rune(0x228e), true + return {'\u228e', 0}, 1, true case "upsi": // GREEK SMALL LETTER UPSILON - return rune(0x03c5), true + return {'\u03c5', 0}, 1, true case "upsih": // GREEK UPSILON WITH HOOK SYMBOL - return rune(0x03d2), true + return {'\u03d2', 0}, 1, true case "upsilon": // GREEK SMALL LETTER UPSILON - return rune(0x03c5), true + return {'\u03c5', 0}, 1, true case "upuparrows": // UPWARDS PAIRED ARROWS - return rune(0x21c8), true + return {'\u21c8', 0}, 1, true case "urcorn": // TOP RIGHT CORNER - return rune(0x231d), true + return {'\u231d', 0}, 1, true case "urcorner": // TOP RIGHT CORNER - return rune(0x231d), true + return {'\u231d', 0}, 1, true case "urcrop": // TOP RIGHT CROP - return rune(0x230e), true + return {'\u230e', 0}, 1, true case "urdrshar": // UP BARB RIGHT DOWN BARB RIGHT HARPOON - return rune(0x294f), true + return {'\u294f', 0}, 1, true case "urharb": // UPWARDS HARPOON WITH BARB RIGHT TO BAR - return rune(0x2954), true + return {'\u2954', 0}, 1, true case "uring": // LATIN SMALL LETTER U WITH RING ABOVE - return rune(0x016f), true + return {'\u016f', 0}, 1, true case "urtri": // UPPER RIGHT TRIANGLE - return rune(0x25f9), true + return {'\u25f9', 0}, 1, true case "urtrif": // BLACK UPPER RIGHT TRIANGLE - return rune(0x25e5), true + return {'\u25e5', 0}, 1, true case "uscr": // MATHEMATICAL SCRIPT SMALL U - return rune(0x01d4ca), true + return {'\U0001d4ca', 0}, 1, true case "utdot": // UP RIGHT DIAGONAL ELLIPSIS - return rune(0x22f0), true + return {'\u22f0', 0}, 1, true case "utilde": // LATIN SMALL LETTER U WITH TILDE - return rune(0x0169), true + return {'\u0169', 0}, 1, true case "utri": // WHITE UP-POINTING SMALL TRIANGLE - return rune(0x25b5), true + return {'\u25b5', 0}, 1, true case "utrif": // BLACK UP-POINTING SMALL TRIANGLE - return rune(0x25b4), true + return {'\u25b4', 0}, 1, true case "uuarr": // UPWARDS PAIRED ARROWS - return rune(0x21c8), true + return {'\u21c8', 0}, 1, true case "uuml": // LATIN SMALL LETTER U WITH DIAERESIS - return rune(0xfc), true + return {'ü', 0}, 1, true case "uwangle": // OBLIQUE ANGLE OPENING DOWN - return rune(0x29a7), true + return {'\u29a7', 0}, 1, true } case 'v': switch name { case "vArr": // UP DOWN DOUBLE ARROW - return rune(0x21d5), true + return {'\u21d5', 0}, 1, true case "vBar": // SHORT UP TACK WITH UNDERBAR - return rune(0x2ae8), true + return {'\u2ae8', 0}, 1, true case "vBarv": // SHORT UP TACK ABOVE SHORT DOWN TACK - return rune(0x2ae9), true + return {'\u2ae9', 0}, 1, true case "vDash": // TRUE - return rune(0x22a8), true + return {'\u22a8', 0}, 1, true case "vDdash": // VERTICAL BAR TRIPLE RIGHT TURNSTILE - return rune(0x2ae2), true + return {'\u2ae2', 0}, 1, true case "vangrt": // RIGHT ANGLE VARIANT WITH SQUARE - return rune(0x299c), true + return {'\u299c', 0}, 1, true case "varepsilon": // GREEK LUNATE EPSILON SYMBOL - return rune(0x03f5), true + return {'\u03f5', 0}, 1, true case "varkappa": // GREEK KAPPA SYMBOL - return rune(0x03f0), true + return {'\u03f0', 0}, 1, true case "varnothing": // EMPTY SET - return rune(0x2205), true + return {'\u2205', 0}, 1, true case "varphi": // GREEK PHI SYMBOL - return rune(0x03d5), true + return {'\u03d5', 0}, 1, true case "varpi": // GREEK PI SYMBOL - return rune(0x03d6), true + return {'\u03d6', 0}, 1, true case "varpropto": // PROPORTIONAL TO - return rune(0x221d), true + return {'\u221d', 0}, 1, true case "varr": // UP DOWN ARROW - return rune(0x2195), true + return {'\u2195', 0}, 1, true case "varrho": // GREEK RHO SYMBOL - return rune(0x03f1), true + return {'\u03f1', 0}, 1, true case "varsigma": // GREEK SMALL LETTER FINAL SIGMA - return rune(0x03c2), true + return {'\u03c2', 0}, 1, true case "varsubsetneq": // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members - return rune(0x228a), true + return {'\u228a', '\ufe00'}, 2, true case "varsubsetneqq": // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members - return rune(0x2acb), true + return {'\u2acb', '\ufe00'}, 2, true case "varsupsetneq": // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members - return rune(0x228b), true + return {'\u228b', '\ufe00'}, 2, true case "varsupsetneqq": // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members - return rune(0x2acc), true + return {'\u2acc', '\ufe00'}, 2, true case "vartheta": // GREEK THETA SYMBOL - return rune(0x03d1), true + return {'\u03d1', 0}, 1, true case "vartriangleleft": // NORMAL SUBGROUP OF - return rune(0x22b2), true + return {'\u22b2', 0}, 1, true case "vartriangleright": // CONTAINS AS NORMAL SUBGROUP - return rune(0x22b3), true + return {'\u22b3', 0}, 1, true case "vbrtri": // VERTICAL BAR BESIDE RIGHT TRIANGLE - return rune(0x29d0), true + return {'\u29d0', 0}, 1, true case "vcy": // CYRILLIC SMALL LETTER VE - return rune(0x0432), true + return {'\u0432', 0}, 1, true case "vdash": // RIGHT TACK - return rune(0x22a2), true + return {'\u22a2', 0}, 1, true case "vee": // LOGICAL OR - return rune(0x2228), true + return {'\u2228', 0}, 1, true case "veeBar": // LOGICAL OR WITH DOUBLE UNDERBAR - return rune(0x2a63), true + return {'\u2a63', 0}, 1, true case "veebar": // XOR - return rune(0x22bb), true + return {'\u22bb', 0}, 1, true case "veeeq": // EQUIANGULAR TO - return rune(0x225a), true + return {'\u225a', 0}, 1, true case "vellip": // VERTICAL ELLIPSIS - return rune(0x22ee), true + return {'\u22ee', 0}, 1, true case "vellip4": // DOTTED FENCE - return rune(0x2999), true + return {'\u2999', 0}, 1, true case "vellipv": // TRIPLE COLON OPERATOR - return rune(0x2af6), true + return {'\u2af6', 0}, 1, true case "verbar": // VERTICAL LINE - return rune(0x7c), true + return {'|', 0}, 1, true case "vert": // VERTICAL LINE - return rune(0x7c), true + return {'|', 0}, 1, true case "vert3": // TRIPLE VERTICAL BAR BINARY RELATION - return rune(0x2af4), true + return {'\u2af4', 0}, 1, true case "vfr": // MATHEMATICAL FRAKTUR SMALL V - return rune(0x01d533), true + return {'\U0001d533', 0}, 1, true case "vldash": // LEFT SQUARE BRACKET LOWER CORNER - return rune(0x23a3), true + return {'\u23a3', 0}, 1, true case "vltri": // NORMAL SUBGROUP OF - return rune(0x22b2), true + return {'\u22b2', 0}, 1, true case "vnsub": // SUBSET OF with vertical line - return rune(0x2282), true + return {'\u2282', '\u20d2'}, 2, true case "vnsup": // SUPERSET OF with vertical line - return rune(0x2283), true + return {'\u2283', '\u20d2'}, 2, true case "vopf": // MATHEMATICAL DOUBLE-STRUCK SMALL V - return rune(0x01d567), true + return {'\U0001d567', 0}, 1, true case "vprime": // PRIME - return rune(0x2032), true + return {'\u2032', 0}, 1, true case "vprop": // PROPORTIONAL TO - return rune(0x221d), true + return {'\u221d', 0}, 1, true case "vrtri": // CONTAINS AS NORMAL SUBGROUP - return rune(0x22b3), true + return {'\u22b3', 0}, 1, true case "vscr": // MATHEMATICAL SCRIPT SMALL V - return rune(0x01d4cb), true + return {'\U0001d4cb', 0}, 1, true case "vsubnE": // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members - return rune(0x2acb), true + return {'\u2acb', '\ufe00'}, 2, true case "vsubne": // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members - return rune(0x228a), true + return {'\u228a', '\ufe00'}, 2, true case "vsupnE": // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members - return rune(0x2acc), true + return {'\u2acc', '\ufe00'}, 2, true case "vsupne": // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members - return rune(0x228b), true + return {'\u228b', '\ufe00'}, 2, true case "vzigzag": // VERTICAL ZIGZAG LINE - return rune(0x299a), true + return {'\u299a', 0}, 1, true } case 'w': switch name { case "wcirc": // LATIN SMALL LETTER W WITH CIRCUMFLEX - return rune(0x0175), true + return {'\u0175', 0}, 1, true case "wedbar": // LOGICAL AND WITH UNDERBAR - return rune(0x2a5f), true + return {'\u2a5f', 0}, 1, true case "wedge": // LOGICAL AND - return rune(0x2227), true + return {'\u2227', 0}, 1, true case "wedgeq": // ESTIMATES - return rune(0x2259), true + return {'\u2259', 0}, 1, true case "weierp": // SCRIPT CAPITAL P - return rune(0x2118), true + return {'\u2118', 0}, 1, true case "wfr": // MATHEMATICAL FRAKTUR SMALL W - return rune(0x01d534), true + return {'\U0001d534', 0}, 1, true case "wopf": // MATHEMATICAL DOUBLE-STRUCK SMALL W - return rune(0x01d568), true + return {'\U0001d568', 0}, 1, true case "wp": // SCRIPT CAPITAL P - return rune(0x2118), true + return {'\u2118', 0}, 1, true case "wr": // WREATH PRODUCT - return rune(0x2240), true + return {'\u2240', 0}, 1, true case "wreath": // WREATH PRODUCT - return rune(0x2240), true + return {'\u2240', 0}, 1, true case "wscr": // MATHEMATICAL SCRIPT SMALL W - return rune(0x01d4cc), true + return {'\U0001d4cc', 0}, 1, true } case 'x': switch name { case "xandand": // TWO LOGICAL AND OPERATOR - return rune(0x2a07), true + return {'\u2a07', 0}, 1, true case "xbsol": // BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT - return rune(0x2571), true + return {'\u2571', 0}, 1, true case "xcap": // N-ARY INTERSECTION - return rune(0x22c2), true + return {'\u22c2', 0}, 1, true case "xcirc": // LARGE CIRCLE - return rune(0x25ef), true + return {'\u25ef', 0}, 1, true case "xcup": // N-ARY UNION - return rune(0x22c3), true + return {'\u22c3', 0}, 1, true case "xcupdot": // N-ARY UNION OPERATOR WITH DOT - return rune(0x2a03), true + return {'\u2a03', 0}, 1, true case "xdtri": // WHITE DOWN-POINTING TRIANGLE - return rune(0x25bd), true + return {'\u25bd', 0}, 1, true case "xfr": // MATHEMATICAL FRAKTUR SMALL X - return rune(0x01d535), true + return {'\U0001d535', 0}, 1, true case "xgr": // GREEK SMALL LETTER XI - return rune(0x03be), true + return {'\u03be', 0}, 1, true case "xhArr": // LONG LEFT RIGHT DOUBLE ARROW - return rune(0x27fa), true + return {'\u27fa', 0}, 1, true case "xharr": // LONG LEFT RIGHT ARROW - return rune(0x27f7), true + return {'\u27f7', 0}, 1, true case "xi": // GREEK SMALL LETTER XI - return rune(0x03be), true + return {'\u03be', 0}, 1, true case "xlArr": // LONG LEFTWARDS DOUBLE ARROW - return rune(0x27f8), true + return {'\u27f8', 0}, 1, true case "xlarr": // LONG LEFTWARDS ARROW - return rune(0x27f5), true + return {'\u27f5', 0}, 1, true case "xmap": // LONG RIGHTWARDS ARROW FROM BAR - return rune(0x27fc), true + return {'\u27fc', 0}, 1, true case "xnis": // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE - return rune(0x22fb), true + return {'\u22fb', 0}, 1, true case "xodot": // N-ARY CIRCLED DOT OPERATOR - return rune(0x2a00), true + return {'\u2a00', 0}, 1, true case "xopf": // MATHEMATICAL DOUBLE-STRUCK SMALL X - return rune(0x01d569), true + return {'\U0001d569', 0}, 1, true case "xoplus": // N-ARY CIRCLED PLUS OPERATOR - return rune(0x2a01), true + return {'\u2a01', 0}, 1, true case "xoror": // TWO LOGICAL OR OPERATOR - return rune(0x2a08), true + return {'\u2a08', 0}, 1, true case "xotime": // N-ARY CIRCLED TIMES OPERATOR - return rune(0x2a02), true + return {'\u2a02', 0}, 1, true case "xrArr": // LONG RIGHTWARDS DOUBLE ARROW - return rune(0x27f9), true + return {'\u27f9', 0}, 1, true case "xrarr": // LONG RIGHTWARDS ARROW - return rune(0x27f6), true + return {'\u27f6', 0}, 1, true case "xscr": // MATHEMATICAL SCRIPT SMALL X - return rune(0x01d4cd), true + return {'\U0001d4cd', 0}, 1, true case "xsol": // BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT - return rune(0x2572), true + return {'\u2572', 0}, 1, true case "xsqcap": // N-ARY SQUARE INTERSECTION OPERATOR - return rune(0x2a05), true + return {'\u2a05', 0}, 1, true case "xsqcup": // N-ARY SQUARE UNION OPERATOR - return rune(0x2a06), true + return {'\u2a06', 0}, 1, true case "xsqu": // WHITE MEDIUM SQUARE - return rune(0x25fb), true + return {'\u25fb', 0}, 1, true case "xsquf": // BLACK MEDIUM SQUARE - return rune(0x25fc), true + return {'\u25fc', 0}, 1, true case "xtimes": // N-ARY TIMES OPERATOR - return rune(0x2a09), true + return {'\u2a09', 0}, 1, true case "xuplus": // N-ARY UNION OPERATOR WITH PLUS - return rune(0x2a04), true + return {'\u2a04', 0}, 1, true case "xutri": // WHITE UP-POINTING TRIANGLE - return rune(0x25b3), true + return {'\u25b3', 0}, 1, true case "xvee": // N-ARY LOGICAL OR - return rune(0x22c1), true + return {'\u22c1', 0}, 1, true case "xwedge": // N-ARY LOGICAL AND - return rune(0x22c0), true + return {'\u22c0', 0}, 1, true } case 'y': switch name { case "yacute": // LATIN SMALL LETTER Y WITH ACUTE - return rune(0xfd), true + return {'ý', 0}, 1, true case "yacy": // CYRILLIC SMALL LETTER YA - return rune(0x044f), true + return {'\u044f', 0}, 1, true case "ycirc": // LATIN SMALL LETTER Y WITH CIRCUMFLEX - return rune(0x0177), true + return {'\u0177', 0}, 1, true case "ycy": // CYRILLIC SMALL LETTER YERU - return rune(0x044b), true + return {'\u044b', 0}, 1, true case "yen": // YEN SIGN - return rune(0xa5), true + return {'¥', 0}, 1, true case "yfr": // MATHEMATICAL FRAKTUR SMALL Y - return rune(0x01d536), true + return {'\U0001d536', 0}, 1, true case "yicy": // CYRILLIC SMALL LETTER YI - return rune(0x0457), true + return {'\u0457', 0}, 1, true case "yopf": // MATHEMATICAL DOUBLE-STRUCK SMALL Y - return rune(0x01d56a), true + return {'\U0001d56a', 0}, 1, true case "yscr": // MATHEMATICAL SCRIPT SMALL Y - return rune(0x01d4ce), true + return {'\U0001d4ce', 0}, 1, true case "yucy": // CYRILLIC SMALL LETTER YU - return rune(0x044e), true + return {'\u044e', 0}, 1, true case "yuml": // LATIN SMALL LETTER Y WITH DIAERESIS - return rune(0xff), true + return {'ÿ', 0}, 1, true } case 'z': switch name { case "zacute": // LATIN SMALL LETTER Z WITH ACUTE - return rune(0x017a), true + return {'\u017a', 0}, 1, true case "zcaron": // LATIN SMALL LETTER Z WITH CARON - return rune(0x017e), true + return {'\u017e', 0}, 1, true case "zcy": // CYRILLIC SMALL LETTER ZE - return rune(0x0437), true + return {'\u0437', 0}, 1, true case "zdot": // LATIN SMALL LETTER Z WITH DOT ABOVE - return rune(0x017c), true + return {'\u017c', 0}, 1, true case "zeetrf": // BLACK-LETTER CAPITAL Z - return rune(0x2128), true + return {'\u2128', 0}, 1, true case "zeta": // GREEK SMALL LETTER ZETA - return rune(0x03b6), true + return {'\u03b6', 0}, 1, true case "zfr": // MATHEMATICAL FRAKTUR SMALL Z - return rune(0x01d537), true + return {'\U0001d537', 0}, 1, true case "zgr": // GREEK SMALL LETTER ZETA - return rune(0x03b6), true + return {'\u03b6', 0}, 1, true case "zhcy": // CYRILLIC SMALL LETTER ZHE - return rune(0x0436), true + return {'\u0436', 0}, 1, true case "zigrarr": // RIGHTWARDS SQUIGGLE ARROW - return rune(0x21dd), true + return {'\u21dd', 0}, 1, true case "zopf": // MATHEMATICAL DOUBLE-STRUCK SMALL Z - return rune(0x01d56b), true + return {'\U0001d56b', 0}, 1, true case "zscr": // MATHEMATICAL SCRIPT SMALL Z - return rune(0x01d4cf), true + return {'\U0001d4cf', 0}, 1, true case "zwj": // ZERO WIDTH JOINER - return rune(0x200d), true + return {'\u200d', 0}, 1, true case "zwnj": // ZERO WIDTH NON-JOINER - return rune(0x200c), true + return {'\u200c', 0}, 1, true } } - return -1, false + return } /* diff --git a/core/encoding/hex/hex.odin b/core/encoding/hex/hex.odin index 318e52ace..c4726d9e9 100644 --- a/core/encoding/hex/hex.odin +++ b/core/encoding/hex/hex.odin @@ -1,35 +1,115 @@ // Encoding and decoding of hex-encoded binary, e.g. `0x23` -> `#`. package encoding_hex +import "base:runtime" import "core:io" import "core:strings" -encode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> []byte #no_bounds_check { - dst := make([]byte, len(src) * 2, allocator, loc) - for i, j := 0, 0; i < len(src); i += 1 { +/* +Encodes a byte slice into a lowercase hex sequence + +*Allocates Using Provided Allocator* + +Inputs: +- src: The `[]byte` to be hex-encoded +- allocator: (default: context.allocator) +- loc: The caller location for debugging purposes (default: #caller_location) + +Returns: +- res: The hex-encoded result +- err: An optional allocator error if one occured, `.None` otherwise +*/ +encode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> (res: []byte, err: runtime.Allocator_Error) #optional_allocator_error { + res, err = make([]byte, len(src) * 2, allocator, loc) + #no_bounds_check for i, j := 0, 0; i < len(src); i += 1 { v := src[i] - dst[j] = HEXTABLE[v>>4] - dst[j+1] = HEXTABLE[v&0x0f] + res[j] = LOWER[v>>4] + res[j+1] = LOWER[v&0x0f] j += 2 } - - return dst + return } -encode_into_writer :: proc(dst: io.Writer, src: []byte) -> io.Error { +/* +Encodes a byte slice as a lowercase hex sequence into an `io.Writer` + +Inputs: +- dst: The `io.Writer` to encode into +- src: The `[]byte` to be hex-encoded + +Returns: +- err: An `io.Error` if one occured, `.None` otherwise +*/ +encode_into_writer :: proc(dst: io.Writer, src: []byte) -> (err: io.Error) { for v in src { - io.write(dst, {HEXTABLE[v>>4], HEXTABLE[v&0x0f]}) or_return + io.write(dst, {LOWER[v>>4], LOWER[v&0x0f]}) or_return } - return nil + return } -decode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> (dst: []byte, ok: bool) #no_bounds_check { +/* +Encodes a byte slice into an uppercase hex sequence + +*Allocates Using Provided Allocator* + +Inputs: +- src: The `[]byte` to be hex-encoded +- allocator: (default: context.allocator) +- loc: The caller location for debugging purposes (default: #caller_location) + +Returns: +- res: The hex-encoded result +- err: An optional allocator error if one occured, `.None` otherwise +*/ +encode_upper :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> (res: []byte, err: runtime.Allocator_Error) #optional_allocator_error { + res, err = make([]byte, len(src) * 2, allocator, loc) + #no_bounds_check for i, j := 0, 0; i < len(src); i += 1 { + v := src[i] + res[j] = UPPER[v>>4] + res[j+1] = UPPER[v&0x0f] + j += 2 + } + return +} + +/* +Encodes a byte slice as an uppercase hex sequence into an `io.Writer` + +Inputs: +- dst: The `io.Writer` to encode into +- src: The `[]byte` to be hex-encoded + +Returns: +- err: An `io.Error` if one occured, `.None` otherwise +*/ +encode_upper_into_writer :: proc(dst: io.Writer, src: []byte) -> (err: io.Error) { + for v in src { + io.write(dst, {UPPER[v>>4], UPPER[v&0x0f]}) or_return + } + return +} + +/* +Decodes a hex sequence into a byte slice + +*Allocates Using Provided Allocator* + +Inputs: +- dst: The hex sequence decoded into bytes +- src: The `[]byte` to be hex-decoded +- allocator: (default: context.allocator) +- loc: The caller location for debugging purposes (default: #caller_location) + +Returns: +- ok: A bool, `true` if decoding succeeded, `false` otherwise +*/ +decode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> (dst: []byte, ok: bool) { if len(src) % 2 == 1 { return } dst = make([]byte, len(src) / 2, allocator, loc) - for i, j := 0, 1; j < len(src); j += 2 { + #no_bounds_check for i, j := 0, 1; j < len(src); j += 2 { p := src[j-1] q := src[j] @@ -43,8 +123,16 @@ decode :: proc(src: []byte, allocator := context.allocator, loc := #caller_locat return dst, true } -// Decodes the given sequence into one byte. -// Should be called with one byte worth of the source, eg: 0x23 -> '#'. +/* +Decodes the first byte in a hex sequence to a byte + +Inputs: +- str: A hex-encoded `string`, e.g. `"0x23"` + +Returns: +- res: The decoded byte, e.g. `'#'` +- ok: A bool, `true` if decoding succeeded, `false` otherwise +*/ decode_sequence :: proc(str: string) -> (res: byte, ok: bool) { str := str if strings.has_prefix(str, "0x") || strings.has_prefix(str, "0X") { @@ -62,13 +150,21 @@ decode_sequence :: proc(str: string) -> (res: byte, ok: bool) { } @(private) -HEXTABLE := [16]byte { +LOWER := [16]byte { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', } +@(private) +UPPER := [16]byte { + '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'A', 'B', + 'C', 'D', 'E', 'F', +} + @(private) hex_digit :: proc(char: byte) -> (u8, bool) { switch char { diff --git a/core/encoding/hxa/hxa.odin b/core/encoding/hxa/hxa.odin index 9d0c58196..4ed2001d9 100644 --- a/core/encoding/hxa/hxa.odin +++ b/core/encoding/hxa/hxa.odin @@ -1,6 +1,6 @@ package encoding_hxa -import "core:mem" +import "base:runtime" LATEST_VERSION :: 3 VERSION_API :: "0.3" @@ -16,7 +16,7 @@ Header :: struct #packed { File :: struct { using header: Header, backing: []byte, - allocator: mem.Allocator, + allocator: runtime.Allocator, nodes: []Node, } diff --git a/core/encoding/hxa/hxa_os.odin b/core/encoding/hxa/hxa_os.odin new file mode 100644 index 000000000..17ad94819 --- /dev/null +++ b/core/encoding/hxa/hxa_os.odin @@ -0,0 +1,34 @@ +#+build !freestanding +#+build !js +package encoding_hxa + +import "core:os" + +read_from_file :: proc(filename: string, print_error := false, allocator := context.allocator, loc := #caller_location) -> (file: File, err: Read_Error) { + context.allocator = allocator + + data, data_err := os.read_entire_file(filename, allocator, loc) + if data_err != nil { + err = .Unable_To_Read_File + delete(data, allocator) + return + } + file, err = read(data, filename, print_error, allocator) + file.backing = data + return +} + +write_to_file :: proc(filepath: string, file: File) -> (err: Write_Error) { + required := required_write_size(file) + buf, alloc_err := make([]byte, required) + if alloc_err == .Out_Of_Memory { + return .Failed_File_Write + } + defer delete(buf) + + write_internal(&Writer{data = buf}, file) + if os.write_entire_file(filepath, buf) != nil { + err =.Failed_File_Write + } + return +} diff --git a/core/encoding/hxa/read.odin b/core/encoding/hxa/read.odin index 6dde16848..29d57838c 100644 --- a/core/encoding/hxa/read.odin +++ b/core/encoding/hxa/read.odin @@ -1,8 +1,6 @@ package encoding_hxa import "core:fmt" -import "core:os" -import "core:mem" Read_Error :: enum { None, @@ -11,20 +9,6 @@ Read_Error :: enum { Unable_To_Read_File, } -read_from_file :: proc(filename: string, print_error := false, allocator := context.allocator, loc := #caller_location) -> (file: File, err: Read_Error) { - context.allocator = allocator - - data, ok := os.read_entire_file(filename, allocator, loc) - if !ok { - err = .Unable_To_Read_File - delete(data, allocator, loc) - return - } - file, err = read(data, filename, print_error, allocator, loc) - file.backing = data - return -} - read :: proc(data: []byte, filename := "", print_error := false, allocator := context.allocator, loc := #caller_location) -> (file: File, err: Read_Error) { Reader :: struct { filename: string, @@ -60,7 +44,7 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato } ptr := raw_data(r.data[r.offset:]) - value = mem.slice_ptr((^T)(ptr), count) + value = ([^]T)(ptr)[:count] r.offset += size_of(T)*count return } diff --git a/core/encoding/hxa/write.odin b/core/encoding/hxa/write.odin index 5bb950e81..0716131f5 100644 --- a/core/encoding/hxa/write.odin +++ b/core/encoding/hxa/write.odin @@ -1,29 +1,11 @@ package encoding_hxa -import "core:os" -import "core:mem" - Write_Error :: enum { None, Buffer_Too_Small, Failed_File_Write, } -write_to_file :: proc(filepath: string, file: File) -> (err: Write_Error) { - required := required_write_size(file) - buf, alloc_err := make([]byte, required) - if alloc_err == .Out_Of_Memory { - return .Failed_File_Write - } - defer delete(buf) - - write_internal(&Writer{data = buf}, file) - if !os.write_entire_file(filepath, buf) { - err =.Failed_File_Write - } - return -} - write :: proc(buf: []byte, file: File) -> (n: int, err: Write_Error) { required := required_write_size(file) if len(buf) < required { @@ -66,7 +48,7 @@ write_internal :: proc(w: ^Writer, file: File) { remaining := len(w.data) - w.offset assert(size_of(T)*len(array) <= remaining) ptr := raw_data(w.data[w.offset:]) - dst := mem.slice_ptr((^T)(ptr), len(array)) + dst := ([^]T)(ptr)[:len(array)] copy(dst, array) } w.offset += size_of(T)*len(array) @@ -76,7 +58,7 @@ write_internal :: proc(w: ^Writer, file: File) { remaining := len(w.data) - w.offset assert(size_of(byte)*len(str) <= remaining) ptr := raw_data(w.data[w.offset:]) - dst := mem.slice_ptr((^byte)(ptr), len(str)) + dst := ([^]byte)(ptr)[:len(str)] copy(dst, str) } w.offset += size_of(byte)*len(str) diff --git a/core/encoding/ini/ini.odin b/core/encoding/ini/ini.odin index a119b0f2e..8bf6c6c9a 100644 --- a/core/encoding/ini/ini.odin +++ b/core/encoding/ini/ini.odin @@ -1,13 +1,12 @@ // Reader and writer for a variant of the `.ini` file format with `key = value` entries in `[sections]`. package encoding_ini -import "base:runtime" -import "base:intrinsics" -import "core:strings" -import "core:strconv" -import "core:io" -import "core:os" -import "core:fmt" +import "base:runtime" +import "base:intrinsics" +import "core:strings" +import "core:strconv" +import "core:io" +import "core:fmt" _ :: fmt Options :: struct { @@ -120,17 +119,6 @@ load_map_from_string :: proc(src: string, allocator: runtime.Allocator, options return } -load_map_from_path :: proc(path: string, allocator: runtime.Allocator, options := DEFAULT_OPTIONS) -> (m: Map, err: runtime.Allocator_Error, ok: bool) { - data := os.read_entire_file(path, allocator) or_return - defer delete(data, allocator) - m, err = load_map_from_string(string(data), allocator, options) - ok = err == nil - defer if !ok { - delete_map(m) - } - return -} - save_map_to_string :: proc(m: Map, allocator: runtime.Allocator) -> (data: string) { b := strings.builder_make(allocator) _, _ = write_map(strings.to_writer(&b), m) @@ -191,4 +179,4 @@ write_map :: proc(w: io.Writer, m: Map) -> (n: int, err: io.Error) { section_index += 1 } return -} +} \ No newline at end of file diff --git a/core/encoding/ini/ini_os.odin b/core/encoding/ini/ini_os.odin new file mode 100644 index 000000000..22c6bf7b3 --- /dev/null +++ b/core/encoding/ini/ini_os.odin @@ -0,0 +1,20 @@ +#+build !freestanding +#+build !js +package encoding_ini + +import "base:runtime" +import "core:os" + +load_map_from_path :: proc(path: string, allocator: runtime.Allocator, options := DEFAULT_OPTIONS) -> (m: Map, err: runtime.Allocator_Error, ok: bool) { + data, data_err := os.read_entire_file(path, allocator) + defer delete(data, allocator) + if data_err != nil { + return + } + m, err = load_map_from_string(string(data), allocator, options) + ok = err == nil + defer if !ok { + delete_map(m) + } + return +} diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index e563c326a..a38c6b6d9 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -62,6 +62,78 @@ Marshal_Options :: struct { mjson_skipped_first_braces_end: bool, } +User_Marshaler :: #type proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> Marshal_Error + +Register_User_Marshaler_Error :: enum { + None, + No_User_Marshaler, + Marshaler_Previously_Found, +} + +// Example User Marshaler: +// Custom Marshaler for `int` +// Some_Marshaler :: proc(w: io.Writer, v: any, opt: ^json.Marshal_Options) -> json.Marshal_Error { +// io.write_string(w, fmt.tprintf("%b", v)) +// return json.Marshal_Data_Error.None +// } +// +// main :: proc() { +// // Ensure the json._user_marshaler map is initialized +// json.set_user_marshalers(new(map[typeid]json.User_Marshaler)) +// reg_err := json.register_user_marshaler(type_info_of(int).id, Some_Marshaler) +// assert(reg_err == .None) +// +// +// // Use the custom marshaler +// SomeType :: struct { +// value: int, +// } +// +// x := SomeType{42} +// data, marshal_err := json.marshal(x) +// assert(marshal_err == nil) +// defer delete(data) +// +// fmt.println("Custom output:", string(data)) // Custom output: {"value":101010} +// } + +// NOTE(Jeroen): This is a pointer to prevent accidental additions +// it is prefixed with `_` rather than marked with a private attribute so that users can access it if necessary +_user_marshalers: ^map[typeid]User_Marshaler + +// Sets user-defined marshalers for custom json marshaling of specific types +// +// Inputs: +// - m: A pointer to a map of typeids to User_Marshaler procs. +// +// NOTE: Must be called before using register_user_marshaler. +// +set_user_marshalers :: proc(m: ^map[typeid]User_Marshaler) { + assert(_user_marshalers == nil, "set_user_marshalers must not be called more than once.") + _user_marshalers = m +} + +// Registers a user-defined marshaler for a specific typeid +// +// Inputs: +// - id: The typeid of the custom type. +// - formatter: The User_Marshaler function for the custom type. +// +// Returns: A Register_User_Marshaler_Error value indicating the success or failure of the operation. +// +// WARNING: set_user_marshalers must be called before using this procedure. +// +register_user_marshaler :: proc(id: typeid, marshaler: User_Marshaler) -> Register_User_Marshaler_Error { + if _user_marshalers == nil { + return .No_User_Marshaler + } + if prev, found := _user_marshalers[id]; found && prev != nil { + return .Marshaler_Previously_Found + } + _user_marshalers[id] = marshaler + return .None +} + marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Marshal_Error) { b := strings.builder_make(allocator, loc) defer if err != nil { @@ -91,6 +163,13 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: return } + if _user_marshalers != nil { + marshaler := _user_marshalers[v.id] + if marshaler != nil { + return marshaler(w, v, opt) + } + } + ti := runtime.type_info_base(type_info_of(v.id)) a := any{v.data, ti.id} @@ -122,9 +201,9 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: case runtime.Type_Info_Rune: r := a.(rune) - io.write_byte(w, '"') or_return - io.write_escaped_rune(w, r, '"', true) or_return - io.write_byte(w, '"') or_return + io.write_byte(w, '"') or_return + io.write_escaped_rune(w, r, '"', for_json = true) or_return + io.write_byte(w, '"') or_return case runtime.Type_Info_Float: switch f in a { @@ -241,6 +320,16 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: } opt_write_end(w, opt, ']') or_return + case runtime.Type_Info_Fixed_Capacity_Dynamic_Array: + opt_write_start(w, opt, '[') or_return + len := (^int)(uintptr(v.data) + info.len_offset)^ + for i in 0.. (err: opt_write_iteration(w, opt, first_iteration) or_return first_iteration = false + + if opt.pretty { + comment := reflect.struct_tag_get(reflect.Struct_Tag(info.tags[i]), "jsoncomment") + opt_write_comment(w, opt, &comment) or_return + } + if json_name != "" { opt_write_key(w, opt, json_name) or_return } else { @@ -533,6 +628,26 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: return } +// Newlines are split into multiple comment lines +opt_write_comment :: proc(w: io.Writer, opt: ^Marshal_Options, comment: ^string) -> (err: io.Error) { + if comment^ == "" { + return nil + } + + switch opt.spec { + case .JSON5, .MJSON: + for line in strings.split_iterator(comment, "\n") { + io.write_string(w, "// ") or_return + io.write_string(w, line) or_return + io.write_rune(w, '\n') or_return + opt_write_indentation(w, opt) or_return + } + case .JSON: return nil + } + + return nil +} + // write key as quoted string or with optional quotes in mjson opt_write_key :: proc(w: io.Writer, opt: ^Marshal_Options, name: string) -> (err: io.Error) { switch opt.spec { diff --git a/core/encoding/json/parser.odin b/core/encoding/json/parser.odin index d6c3df7c6..cd6518955 100644 --- a/core/encoding/json/parser.odin +++ b/core/encoding/json/parser.odin @@ -38,7 +38,7 @@ parse_string :: proc(data: string, spec := DEFAULT_SPECIFICATION, parse_integers switch p.spec { case .JSON: - return parse_object(&p, loc) + return parse_value(&p, loc) case .JSON5: return parse_value(&p, loc) case .SJSON: @@ -84,7 +84,7 @@ expect_token :: proc(p: ^Parser, kind: Token_Kind) -> Error { parse_colon :: proc(p: ^Parser) -> (err: Error) { - colon_err := expect_token(p, .Colon) + colon_err := expect_token(p, .Colon) if colon_err == nil { return nil } @@ -133,13 +133,13 @@ parse_value :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err: f, _ := strconv.parse_f64(token.text) value = Float(f) return - + case .Ident: if p.spec == .MJSON { advance_token(p) return clone_string(token.text, p.allocator, loc) } - + case .String: advance_token(p) return unquote_string(token, p.spec, p.allocator, loc) @@ -192,7 +192,7 @@ parse_array :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err: for p.curr_token.kind != .Close_Bracket { elem := parse_value(p, loc) or_return append(&array, elem, loc) - + if parse_comma(p) { break } @@ -278,7 +278,7 @@ parse_object_body :: proc(p: ^Parser, end_token: Token_Kind, loc := #caller_loca if parse_comma(p) { break } - } + } return obj, .None } @@ -481,4 +481,4 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a } return string(b[:w]), nil -} \ No newline at end of file +} diff --git a/core/encoding/json/types.odin b/core/encoding/json/types.odin index 1da17a0db..77cc7db85 100644 --- a/core/encoding/json/types.odin +++ b/core/encoding/json/types.odin @@ -76,6 +76,7 @@ Error :: enum { Invalid_Number, String_Not_Terminated, Invalid_String, + Invalid_Rune, // Parsing Errors diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index 3cdc6429d..2aa3c0913 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -26,6 +26,80 @@ Unmarshal_Error :: union { Unsupported_Type_Error, } +User_Unmarshaler :: #type proc(p: ^Parser, v: any) -> Unmarshal_Error + +Register_User_Unmarshaler_Error :: enum { + None, + No_User_Unmarshaler, + Unmarshaler_Previously_Found, +} + +// Example User Unmarshaler: +// Custom Unmarshaler for `int` +// Some_Unmarshaler :: proc(p: ^json.Parser, v: any) -> json.Unmarshal_Error { +// token := p.curr_token.text +// i, ok := strconv.parse_i64_of_base(token, 2) +// if !ok { +// return .Invalid_Data +// +// } +// (^int)(v.data)^ = int(i) +// return .None +// } +// +// _main :: proc() { +// // Ensure the json._user_unmarshaler map is initialized +// json.set_user_unmarshalers(new(map[typeid]json.User_Unmarshaler)) +// reg_err := json.register_user_unmarshaler(type_info_of(int).id, Some_Unmarshaler) +// assert(reg_err == .None) +// +// data := `{"value":101010}` +// SomeType :: struct { +// value: int, +// } +// y: SomeType +// +// unmarshal_err := json.unmarshal(transmute([]byte)data, &y) +// fmt.println(y, unmarshal_err) +// } + +// NOTE(Jeroen): This is a pointer to prevent accidental additions +// it is prefixed with `_` rather than marked with a private attribute so that users can access it if necessary +_user_unmarshalers: ^map[typeid]User_Unmarshaler + +// Sets user-defined unmarshalers for custom json unmarshaling of specific types +// +// Inputs: +// - m: A pointer to a map of typeids to User_Unmarshaler procs. +// +// NOTE: Must be called before using register_user_unmarshaler. +// +set_user_unmarshalers :: proc(m: ^map[typeid]User_Unmarshaler) { + assert(_user_unmarshalers == nil, "set_user_unmarshalers must not be called more than once.") + _user_unmarshalers = m +} + +// Registers a user-defined unmarshaler for a specific typeid +// +// Inputs: +// - id: The typeid of the custom type. +// - unmarshaler: The User_Unmarshaler function for the custom type. +// +// Returns: A Register_User_Unmarshaler_Error value indicating the success or failure of the operation. +// +// WARNING: set_user_unmarshalers must be called before using this procedure. +// +register_user_unmarshaler :: proc(id: typeid, unmarshaler: User_Unmarshaler) -> Register_User_Unmarshaler_Error { + if _user_unmarshalers == nil { + return .No_User_Unmarshaler + } + if prev, found := _user_unmarshalers[id]; found && prev != nil { + return .Unmarshaler_Previously_Found + } + _user_unmarshalers[id] = unmarshaler + return .None +} + unmarshal_any :: proc(data: []byte, v: any, spec := DEFAULT_SPECIFICATION, allocator := context.allocator) -> Unmarshal_Error { v := v if v == nil || v.id == nil { @@ -37,8 +111,10 @@ unmarshal_any :: proc(data: []byte, v: any, spec := DEFAULT_SPECIFICATION, alloc return .Non_Pointer_Parameter } PARSE_INTEGERS :: true - - if !is_valid(data, spec, PARSE_INTEGERS) { + + // If we have custom unmarshalers, we skip validation in case the custom data is not quite up to spec. + have_custom := _user_unmarshalers != nil && len(_user_unmarshalers) > 0 + if !have_custom && !is_valid(data, spec, PARSE_INTEGERS) { return .Invalid_Data } p := make_parser(data, spec, PARSE_INTEGERS, allocator) @@ -225,6 +301,15 @@ unmarshal_string_token :: proc(p: ^Parser, val: any, token: Token, ti: ^reflect. } ok = true return + case rune: + for rne, i in str { + if i > 0 { + dst = {} + return false, .Invalid_Rune + } + dst = rne + } + return true, nil } #partial switch variant in ti.variant { @@ -265,12 +350,18 @@ unmarshal_string_token :: proc(p: ^Parser, val: any, token: Token, ti: ^reflect. return false, nil } - @(private) unmarshal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) { UNSUPPORTED_TYPE := Unsupported_Type_Error{v.id, p.curr_token} token := p.curr_token + if _user_unmarshalers != nil { + unmarshaler := _user_unmarshalers[v.id] + if unmarshaler != nil { + return unmarshaler(p, v) + } + } + v := v ti := reflect.type_info_base(type_info_of(v.id)) if u, ok := ti.variant.(reflect.Type_Info_Union); ok && token.kind != .Null { diff --git a/core/encoding/json/validator.odin b/core/encoding/json/validator.odin index a6873319d..e90270335 100644 --- a/core/encoding/json/validator.odin +++ b/core/encoding/json/validator.odin @@ -5,10 +5,10 @@ import "core:mem" // NOTE(bill): is_valid will not check for duplicate keys is_valid :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false) -> bool { p := make_parser(data, spec, parse_integers, mem.nil_allocator()) - + switch p.spec { case .JSON: - return validate_object(&p) + return validate_value(&p) case .JSON5: return validate_value(&p) case .MJSON: @@ -52,7 +52,7 @@ validate_object :: proc(p: ^Parser) -> bool { if err := expect_token(p, .Open_Brace); err != .None { return false } - + validate_object_body(p, .Close_Brace) or_return if err := expect_token(p, .Close_Brace); err != .None { @@ -102,7 +102,7 @@ validate_value :: proc(p: ^Parser) -> bool { case .Open_Bracket: return validate_array(p) - + case .Ident: if p.spec == .MJSON { advance_token(p) diff --git a/core/encoding/xml/example/xml_example.odin b/core/encoding/xml/example/xml_example.odin index 9648143db..5ea689069 100644 --- a/core/encoding/xml/example/xml_example.odin +++ b/core/encoding/xml/example/xml_example.odin @@ -10,8 +10,6 @@ import "core:hash" N :: 1 example :: proc() { - using fmt - docs: [N]^xml.Document errs: [N]xml.Error times: [N]time.Duration @@ -59,23 +57,23 @@ example :: proc() { fmt.printf("[Average]: %v bytes in %.2f ms (%.2f MiB/s).\n", len(input), average_ms, average_speed) if errs[0] != .None { - printf("Load/Parse error: %v\n", errs[0]) + fmt.eprintf("Load/Parse error: %v\n", errs[0]) if errs[0] == .File_Error { - println("\"unicode.xml\" not found. Did you run \"tests\\download_assets.py\"?") + fmt.eprintln("\"unicode.xml\" not found. Did you run \"tests\\download_assets.py\"?") } return } charlist, charlist_ok := xml.find_child_by_ident(docs[0], 0, "charlist") if !charlist_ok { - eprintln("Could not locate top-level `` tag.") - return + fmt.eprintln("Could not locate top-level `` tag.") + return } - printf("Found `` with %v children, %v elements total\n", len(docs[0].elements[charlist].value), docs[0].element_count) + fmt.printf("Found `` with %v children, %v elements total\n", len(docs[0].elements[charlist].value), docs[0].element_count) crc32 := doc_hash(docs[0], false) - printf("[%v] CRC32: 0x%08x\n", "🎉" if crc32 == 0x420dbac5 else "🤬", crc32) + fmt.printf("[%v] CRC32: 0x%08x\n", "🎉" if crc32 == 0x420dbac5 else "🤬", crc32) for round in 0.. (crc32: u32) { } main :: proc() { - using fmt - track: mem.Tracking_Allocator mem.tracking_allocator_init(&track, context.allocator) context.allocator = mem.tracking_allocator(&track) @@ -103,10 +99,10 @@ main :: proc() { example() if len(track.allocation_map) > 0 { - println() + fmt.println() for _, v in track.allocation_map { - printf("%v Leaked %v bytes.\n", v.location, v.size) + fmt.printf("%v Leaked %v bytes.\n", v.location, v.size) } } - println("Done and cleaned up!") + fmt.println("Done and cleaned up!") } diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index 71fa0bdf5..d07f41580 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -264,7 +264,7 @@ scan_comment :: proc(t: ^Tokenizer) -> (comment: string, err: Error) { expect(t, .Dash) expect(t, .Gt) - return string(t.src[offset : t.offset - 1]), .None + return string(t.src[offset : t.offset - 3]), .None } // Skip CDATA diff --git a/core/encoding/xml/xml_os.odin b/core/encoding/xml/xml_os.odin new file mode 100644 index 000000000..1e94572c6 --- /dev/null +++ b/core/encoding/xml/xml_os.odin @@ -0,0 +1,18 @@ +#+build !freestanding +#+build !js +package encoding_xml + +import "core:os" + +// Load an XML file +load_from_file :: proc(filename: string, options := DEFAULT_OPTIONS, error_handler := default_error_handler, allocator := context.allocator) -> (doc: ^Document, err: Error) { + context.allocator = allocator + options := options + + data, data_err := os.read_entire_file(filename, allocator) + if data_err != nil { return {}, .File_Error } + + options.flags += { .Input_May_Be_Modified } + + return parse_bytes(data, options, filename, error_handler, allocator) +} diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 0e773fd8a..6d068466b 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -9,13 +9,12 @@ package encoding_xml - Jeroen van Rijn: Initial implementation. */ -import "core:bytes" -import "core:encoding/entity" -import "base:intrinsics" -import "core:mem" -import "core:os" -import "core:strings" -import "base:runtime" +import "base:runtime" +import "core:bytes" +import "core:encoding/entity" +import "base:intrinsics" +import "core:mem" +import "core:strings" likely :: intrinsics.expect @@ -294,7 +293,7 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha comment := scan_comment(t) or_return if .Intern_Comments in opts.flags { - if len(doc.elements) == 0 { + if doc.element_count == 0 { append(&doc.comments, comment) } else { el := new_element(doc) @@ -308,6 +307,7 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha case .Open_Bracket: // This could be a CDATA tag part of a tag's body. Unread the ` (doc: ^Document, err: Error) { +destroy :: proc(doc: ^Document, allocator := context.allocator) { context.allocator = allocator - options := options - - data, data_ok := os.read_entire_file(filename) - if !data_ok { return {}, .File_Error } - - options.flags += { .Input_May_Be_Modified } - - return parse_bytes(data, options, filename, error_handler, allocator) -} - -destroy :: proc(doc: ^Document) { if doc == nil { return } for el in doc.elements { @@ -625,4 +613,4 @@ new_element :: proc(doc: ^Document) -> (id: Element_ID) { cur := doc.element_count doc.element_count += 1 return cur -} \ No newline at end of file +} diff --git a/core/flags/constants.odin b/core/flags/constants.odin index dc2663e2a..154ed3cec 100644 --- a/core/flags/constants.odin +++ b/core/flags/constants.odin @@ -11,8 +11,7 @@ NO_CORE_NAMED_TYPES :: #config(ODIN_CORE_FLAGS_NO_CORE_NAMED_TYPES, false) IMPORTING_TIME :: #config(ODIN_CORE_FLAGS_USE_TIME, time.IS_SUPPORTED) // Override support for parsing `net` types. -// TODO: Update this when the BSDs are supported. -IMPORTING_NET :: #config(ODIN_CORE_FLAGS_USE_NET, ODIN_OS == .Windows || ODIN_OS == .Linux || ODIN_OS == .Darwin || ODIN_OS == .FreeBSD) +IMPORTING_NET :: #config(ODIN_CORE_FLAGS_USE_NET, ODIN_OS == .Windows || ODIN_OS == .Linux || ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD) TAG_ARGS :: "args" SUBTAG_NAME :: "name" diff --git a/core/flags/errors.odin b/core/flags/errors.odin index 3d34a95d3..efe4cb6c4 100644 --- a/core/flags/errors.odin +++ b/core/flags/errors.odin @@ -1,5 +1,7 @@ package flags +import "base:runtime" +import "core:net" import "core:os" Parse_Error_Reason :: enum { @@ -24,13 +26,19 @@ Parse_Error :: struct { message: string, } +Unified_Parse_Error_Reason :: union #shared_nil { + Parse_Error_Reason, + runtime.Allocator_Error, + net.Parse_Endpoint_Error, +} + // Raised during parsing. // Provides more granular information than what just a string could hold. Open_File_Error :: struct { filename: string, errno: os.Error, - mode: int, - perms: int, + flags: os.File_Flags, + perms: os.Permissions, } // Raised during parsing. diff --git a/core/flags/errors_bsd.odin b/core/flags/errors_bsd.odin deleted file mode 100644 index 4d98d2ee4..000000000 --- a/core/flags/errors_bsd.odin +++ /dev/null @@ -1,9 +0,0 @@ -#+build netbsd, openbsd -package flags - -import "base:runtime" - -Unified_Parse_Error_Reason :: union #shared_nil { - Parse_Error_Reason, - runtime.Allocator_Error, -} diff --git a/core/flags/errors_nonbsd.odin b/core/flags/errors_nonbsd.odin deleted file mode 100644 index 28912b57f..000000000 --- a/core/flags/errors_nonbsd.odin +++ /dev/null @@ -1,12 +0,0 @@ -#+build !netbsd -#+build !openbsd -package flags - -import "base:runtime" -import "core:net" - -Unified_Parse_Error_Reason :: union #shared_nil { - Parse_Error_Reason, - runtime.Allocator_Error, - net.Parse_Endpoint_Error, -} diff --git a/core/flags/example/example.odin b/core/flags/example/example.odin index a3af44790..6ace3d852 100644 --- a/core/flags/example/example.odin +++ b/core/flags/example/example.odin @@ -76,8 +76,8 @@ Distinct_Int :: distinct int main :: proc() { Options :: struct { - file: os.Handle `args:"pos=0,required,file=r" usage:"Input file."`, - output: os.Handle `args:"pos=1,file=cw" usage:"Output file."`, + file: ^os.File `args:"pos=0,required,file=r" usage:"Input file."`, + output: ^os.File `args:"pos=1,file=cw" usage:"Output file."`, hub: net.Host_Or_Endpoint `usage:"Internet address to contact for updates."`, schedule: datetime.DateTime `usage:"Launch tasks at this time."`, @@ -126,7 +126,7 @@ main :: proc() { fmt.printfln("%#v", opt) - if opt.output != 0 { + if opt.output != nil { os.write_string(opt.output, "Hellope!\n") } } diff --git a/core/flags/internal_rtti.odin b/core/flags/internal_rtti.odin index a1b050597..1d86f4bce 100644 --- a/core/flags/internal_rtti.odin +++ b/core/flags/internal_rtti.odin @@ -1,17 +1,18 @@ #+private package flags -import "base:intrinsics" -import "base:runtime" -import "core:fmt" -import "core:mem" -import "core:os" -import "core:reflect" -import "core:strconv" -import "core:strings" -@require import "core:time" -@require import "core:time/datetime" -import "core:unicode/utf8" +import "base:intrinsics" +import "base:runtime" +import "core:fmt" +import "core:mem" +import "core:net" +@(require) import "core:os" +import "core:reflect" +import "core:strconv" +import "core:strings" +@(require) import "core:time" +@(require) import "core:time/datetime" +import "core:unicode/utf8" @(optimization_mode="favor_size") parse_and_set_pointer_by_base_type :: proc(ptr: rawptr, str: string, type_info: ^runtime.Type_Info) -> bool { @@ -208,7 +209,7 @@ parse_and_set_pointer_by_base_type :: proc(ptr: rawptr, str: string, type_info: parse_and_set_pointer_by_named_type :: proc(ptr: rawptr, str: string, data_type: typeid, arg_tag: string, out_error: ^Error) { // Core types currently supported: // - // - os.Handle + // - ^os.File // - time.Time // - datetime.DateTime // - net.Host_Or_Endpoint @@ -216,64 +217,61 @@ parse_and_set_pointer_by_named_type :: proc(ptr: rawptr, str: string, data_type: GENERIC_RFC_3339_ERROR :: "Invalid RFC 3339 string. Try this format: `yyyy-mm-ddThh:mm:ssZ`, for example `2024-02-29T16:30:00Z`." out_error^ = nil - - if data_type == os.Handle { + if data_type == ^os.File { // NOTE: `os` is hopefully available everywhere, even if it might panic on some calls. - wants_read := false - wants_write := false - mode: int + flags: os.File_Flags if file, ok := get_struct_subtag(arg_tag, SUBTAG_FILE); ok { for i in 0..= {.Read, .Write} { + octal_perms |= 0o200 + } else if .Write in flags { + octal_perms |= 0o200 } else { - mode |= os.O_RDONLY + flags |= {.Read} } if permstr, ok := get_struct_subtag(arg_tag, SUBTAG_PERMS); ok { if value, parse_ok := strconv.parse_u64_of_base(permstr, 8); parse_ok { - perms = int(value) + octal_perms = int(value) } } - handle, errno := os.open(str, mode, perms) - if errno != nil { + perms := os.perm(octal_perms) + + f, error := os.open(str, flags, perms) + if error != nil { // NOTE(Feoramund): os.Error is system-dependent, and there's // currently no good way to translate them all into strings. // - // The upcoming `os2` package will hopefully solve this. + // The upcoming `core:os` package will hopefully solve this. // // We can at least provide the number for now, so the user can look // it up. out_error^ = Open_File_Error { str, - errno, - mode, + error, + flags, perms, } return } - (^os.Handle)(ptr)^ = handle + (^^os.File)(ptr)^ = f return } @@ -310,7 +308,18 @@ parse_and_set_pointer_by_named_type :: proc(ptr: rawptr, str: string, data_type: } when IMPORTING_NET { - if try_net_parse_workaround(data_type, str, ptr, out_error) { + if data_type == net.Host_Or_Endpoint { + addr, net_error := net.parse_hostname_or_endpoint(str) + if net_error != nil { + // We pass along `net.Error` here. + out_error^ = Parse_Error { + net_error, + "Invalid Host/Endpoint.", + } + return + } + + (cast(^net.Host_Or_Endpoint)ptr)^ = addr return } } @@ -463,6 +472,11 @@ parse_and_set_pointer_by_type :: proc(ptr: rawptr, str: string, type_info: ^runt } case: + if type_info.id == ^os.File { + parse_and_set_pointer_by_named_type(ptr, str, type_info.id, arg_tag, &error) + return + } + if !parse_and_set_pointer_by_base_type(ptr, str, type_info) { return Parse_Error { // The caller will add more details. diff --git a/core/flags/internal_rtti_nonbsd.odin b/core/flags/internal_rtti_nonbsd.odin deleted file mode 100644 index e1286186b..000000000 --- a/core/flags/internal_rtti_nonbsd.odin +++ /dev/null @@ -1,32 +0,0 @@ -#+private -#+build !netbsd -#+build !openbsd -package flags - -import "core:net" - -// This proc exists purely as a workaround for import restrictions. -// Returns true if caller should return early. -try_net_parse_workaround :: #force_inline proc ( - data_type: typeid, - str: string, - ptr: rawptr, - out_error: ^Error, -) -> bool { - if data_type == net.Host_Or_Endpoint { - addr, net_error := net.parse_hostname_or_endpoint(str) - if net_error != nil { - // We pass along `net.Error` here. - out_error^ = Parse_Error { - net_error, - "Invalid Host/Endpoint.", - } - return true - } - - (cast(^net.Host_Or_Endpoint)ptr)^ = addr - return true - } - - return false -} diff --git a/core/flags/internal_validation.odin b/core/flags/internal_validation.odin index cd903c3e5..6f9016a21 100644 --- a/core/flags/internal_validation.odin +++ b/core/flags/internal_validation.odin @@ -138,20 +138,20 @@ validate_structure :: proc(model_type: $T, style: Parsing_Style, loc := #caller_ allowed_to_define_file_perms: bool = --- #partial switch specific_type_info in field.type.variant { case runtime.Type_Info_Map: - allowed_to_define_file_perms = specific_type_info.value.id == os.Handle + allowed_to_define_file_perms = specific_type_info.value.id == ^os.File case runtime.Type_Info_Dynamic_Array: - allowed_to_define_file_perms = specific_type_info.elem.id == os.Handle + allowed_to_define_file_perms = specific_type_info.elem.id == ^os.File case: - allowed_to_define_file_perms = field.type.id == os.Handle + allowed_to_define_file_perms = field.type.id == ^os.File } if _, has_file := get_struct_subtag(args_tag, SUBTAG_FILE); has_file { - fmt.assertf(allowed_to_define_file_perms, "%T.%s has `%s` defined, but it is not nor does it contain an `os.Handle` type.", + fmt.assertf(allowed_to_define_file_perms, "%T.%s has `%s` defined, but it is not nor does it contain an `^os.File` type.", model_type, field.name, SUBTAG_FILE, loc = loc) } if _, has_perms := get_struct_subtag(args_tag, SUBTAG_PERMS); has_perms { - fmt.assertf(allowed_to_define_file_perms, "%T.%s has `%s` defined, but it is not nor does it contain an `os.Handle` type.", + fmt.assertf(allowed_to_define_file_perms, "%T.%s has `%s` defined, but it is not nor does it contain an `^os.File` type.", model_type, field.name, SUBTAG_PERMS, loc = loc) } diff --git a/core/flags/util.odin b/core/flags/util.odin index ce7e2e36c..b5e557cf6 100644 --- a/core/flags/util.odin +++ b/core/flags/util.odin @@ -1,9 +1,9 @@ package flags -import "core:fmt" +import "core:fmt" @require import "core:os" @require import "core:path/filepath" -import "core:strings" +import "core:strings" /* Parse any arguments into an annotated struct or exit if there was an error. @@ -38,7 +38,7 @@ parse_or_exit :: proc( error := parse(model, args, style, true, true, allocator, loc) if error != nil { - stderr := os.stream_from_handle(os.stderr) + stderr := os.to_stream(os.stderr) if len(args) == 0 { // No arguments entered, and there was an error; show the usage, @@ -65,19 +65,44 @@ Inputs: */ @(optimization_mode="favor_size") print_errors :: proc(data_type: typeid, error: Error, program: string, style: Parsing_Style = .Odin) { - stderr := os.stream_from_handle(os.stderr) - stdout := os.stream_from_handle(os.stdout) + stderr := os.to_stream(os.stderr) + stdout := os.to_stream(os.stdout) switch specific_error in error { case Parse_Error: fmt.wprintfln(stderr, "[%T.%v] %s", specific_error, specific_error.reason, specific_error.message) case Open_File_Error: - fmt.wprintfln(stderr, "[%T#%i] Unable to open file with perms 0o%o in mode 0x%x: %s", - specific_error, - specific_error.errno, - specific_error.perms, - specific_error.mode, - specific_error.filename) + if os.exists(specific_error.filename) { + flags: string + if specific_error.flags == {.Read} { + flags = "read-only" + } else if specific_error.flags == {.Write} { + flags = "write-only" + } else if specific_error.flags == {.Read, .Write} { + flags = "read/write" + } + + if flags != "" { + fmt.wprintfln(stderr, "[%T#%i] Unable to open %q with perms 0o%o as %s", + specific_error, + specific_error.errno, + specific_error.filename, + u16(transmute(u32)specific_error.perms), + flags) + } else { + fmt.wprintfln(stderr, "[%T#%i] Unable to open %q with perms 0o%o and flags %v", + specific_error, + specific_error.errno, + specific_error.filename, + u16(transmute(u32)specific_error.perms), + specific_error.flags) + } + } else { + fmt.wprintfln(stderr, "[%T#%i] Unable to open %q. File not found", + specific_error, + specific_error.errno, + specific_error.filename) + } case Validation_Error: fmt.wprintfln(stderr, "[%T] %s", specific_error, specific_error.message) case Help_Request: diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 7ec3062e1..4ecb19c21 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -42,6 +42,8 @@ Info_State :: struct { width: int, prec: int, indent: int, + + parent_struct: any, } @@ -1084,7 +1086,7 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d case 12: io.write_byte(fi.writer, '0', &fi.n) - io.write_byte(fi.writer, 'o', &fi.n) + io.write_byte(fi.writer, 'z', &fi.n) start = 2 case 16: @@ -1098,10 +1100,7 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d if fi.prec_set { prec = fi.prec if prec == 0 && u == 0 { - prev_zero := fi.zero - fi.zero = false fmt_write_padding(fi, fi.width) - fi.zero = prev_zero return } } else if fi.zero && fi.width_set { @@ -1169,7 +1168,7 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i case 12: io.write_byte(fi.writer, '0', &fi.n) - io.write_byte(fi.writer, 'o', &fi.n) + io.write_byte(fi.writer, 'z', &fi.n) start = 2 case 16: @@ -1183,10 +1182,7 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i if fi.prec_set { prec = fi.prec if prec == 0 && u == 0 { - prev_zero := fi.zero - fi.zero = false fmt_write_padding(fi, fi.width) - fi.zero = prev_zero return } } else if fi.zero && fi.width_set { @@ -1229,8 +1225,8 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i _pad(fi, s) } // Units of measurements: -__MEMORY_LOWER := " b kib mib gib tib pib eib" -__MEMORY_UPPER := " B KiB MiB GiB TiB PiB EiB" +@(rodata) __MEMORY_LOWER := " b kib mib gib tib pib eib" +@(rodata) __MEMORY_UPPER := " B KiB MiB GiB TiB PiB EiB" // Formats an integer value as bytes with the best representation. // // Inputs: @@ -1288,8 +1284,8 @@ _fmt_memory :: proc(fi: ^Info, u: u64, is_signed: bool, bit_size: int, units: st _pad(fi, str) } // Hex Values: -__DIGITS_LOWER := "0123456789abcdefx" -__DIGITS_UPPER := "0123456789ABCDEFX" +@(rodata) __DIGITS_LOWER := "0123456789abcdefx" +@(rodata) __DIGITS_UPPER := "0123456789ABCDEFX" // Formats a rune value according to the specified formatting verb. // // Inputs: @@ -2071,6 +2067,235 @@ handle_tag :: proc(state: ^Info_State, data: rawptr, info: reflect.Type_Info_Str } return } + + +__handle_raw_union_tag :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_Struct, type_name: string) -> (ok: bool) { + ut := type_info_of(v.id) + + if !reflect.is_raw_union(ut) { + return false + } + + tag_name: string + for tag in info.tags[:info.field_count] { + rut := reflect.struct_tag_lookup(reflect.Struct_Tag(tag), "raw_union_tag") or_continue + head_tag, match, _ := strings.partition(string(rut), "=") + if match != "=" { + continue + } + if tag_name == "" { + tag_name = head_tag + } else if tag_name != head_tag { + return false + } + } + if tag_name == "" { + return false + } + + tag := reflect.struct_field_value_by_name(fi.state.parent_struct, tag_name, true) + if tag == nil { + // try the current type just in case the tag is also stored here + tag = reflect.struct_field_value_by_name(v, tag_name, false) + } + if tag == nil { + return false + } + + + tag_info := reflect.type_info_base(type_info_of(tag.id)) + #partial switch ti in tag_info.variant { + case reflect.Type_Info_Enum: + tag_string := reflect.enum_string(tag) + + for tag, index in info.tags[:info.field_count] { + rut_list := reflect.struct_tag_lookup(reflect.Struct_Tag(tag), "raw_union_tag") or_continue + + for rut in strings.split_iterator(&rut_list, ",") { + head_tag, match, tail_name := strings.partition(string(rut), "=") + if head_tag != tag_name || match != "=" { + continue + } + + // just ignore the `A.` prefix for `A.B` stuff entirely + if _, _, try_tail_name := strings.partition(string(rut), "."); try_tail_name != "" { + tail_name = try_tail_name + } + + if tail_name == tag_string { + io.write_string(fi.writer, "#raw_union(.", &fi.n) + io.write_string(fi.writer, tag_string, &fi.n) + io.write_string(fi.writer, ") ", &fi.n) + fmt_arg(fi, any{v.data, info.types[index].id}, the_verb) + return true + } + } + } + case reflect.Type_Info_Integer: + tag_value := reflect.as_i64(tag) or_break + + for tag, index in info.tags[:info.field_count] { + rut_list := reflect.struct_tag_lookup(reflect.Struct_Tag(tag), "raw_union_tag") or_continue + + for rut in strings.split_iterator(&rut_list, ",") { + head_tag, match, tail_name := strings.partition(string(rut), "=") + if head_tag != tag_name || match != "=" { + continue + } + + // just ignore the `A.` prefix for `A.B` stuff entirely + if _, _, try_tail_name := strings.partition(string(rut), "."); try_tail_name != "" { + tail_name = try_tail_name + } + + tail_value := strconv.parse_i64(tail_name) or_continue + + if tail_value == tag_value { + io.write_string(fi.writer, "#raw_union(.", &fi.n) + io.write_i64(fi.writer, tag_value, 10, &fi.n) + io.write_string(fi.writer, ") ", &fi.n) + fmt_arg(fi, any{v.data, info.types[index].id}, the_verb) + return true + } + } + } + + case reflect.Type_Info_Boolean: + tag_value := reflect.as_bool(tag) or_break + + for tag, index in info.tags[:info.field_count] { + rut_list := reflect.struct_tag_lookup(reflect.Struct_Tag(tag), "raw_union_tag") or_continue + + for rut in strings.split_iterator(&rut_list, ",") { + head_tag, match, tail_name := strings.partition(string(rut), "=") + if head_tag != tag_name || match != "=" { + continue + } + + // just ignore the `A.` prefix for `A.B` stuff entirely + if _, _, try_tail_name := strings.partition(string(rut), "."); try_tail_name != "" { + tail_name = try_tail_name + } + + tail_value := strconv.parse_bool(tail_name) or_continue + + if tail_value == tag_value { + io.write_string(fi.writer, "#raw_union(.", &fi.n) + io.write_string(fi.writer, "true" if tag_value else "false", &fi.n) + io.write_string(fi.writer, ") ", &fi.n) + fmt_arg(fi, any{v.data, info.types[index].id}, the_verb) + return true + } + } + } + } + + return false +} + +@(private) +fmt_soa_struct_internal :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_Struct, type_name: string, hash: bool, indent: int) { + is_empty := info.field_count == 0 + + fi.indent += 1 + defer fi.indent -= 1 + + base_type_name: string + if v, ok := info.soa_base_type.variant.(runtime.Type_Info_Named); ok { + base_type_name = v.name + } + + actual_field_count := info.field_count + + n := uintptr(info.soa_len) + + if info.soa_kind == .Slice { + actual_field_count = info.field_count-1 // len + + n = uintptr((^int)(uintptr(v.data) + info.offsets[actual_field_count])^) + + } else if info.soa_kind == .Dynamic { + actual_field_count = info.field_count-3 // len, cap, allocator + + n = uintptr((^int)(uintptr(v.data) + info.offsets[actual_field_count])^) + } + + if hash && n > 0 { + io.write_byte(fi.writer, '\n', &fi.n) + } + + for index in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } + + field_count := -1 + + if !hash && field_count > 0 { io.write_string(fi.writer, ", ", &fi.n) } + + if hash { + fi.indent -= 1 + fmt_write_indent(fi) + fi.indent += 1 + } + io.write_string(fi.writer, base_type_name, &fi.n) + io.write_byte(fi.writer, '{', &fi.n) + if hash && !is_empty { io.write_byte(fi.writer, '\n', &fi.n) } + defer { + if hash && !is_empty { + fi.indent -= 1 + fmt_write_indent(fi) + fi.indent += 1 + } + io.write_byte(fi.writer, '}', &fi.n) + if hash { io.write_string(fi.writer, ",\n", &fi.n) } + } + fi.record_level += 1 + defer fi.record_level -= 1 + + for i in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } + if hash { + fmt_write_indent(fi) + } + + io.write_string(fi.writer, name, &fi.n) + io.write_string(fi.writer, " = ", &fi.n) + + if info.soa_kind == .Fixed { + t := info.types[i].variant.(runtime.Type_Info_Array).elem + t_size := uintptr(t.size) + if reflect.is_any(t) { + io.write_string(fi.writer, "any{}", &fi.n) + } else { + data := rawptr(uintptr(v.data) + info.offsets[i] + index*t_size) + fmt_arg(fi, any{data, t.id}, verb) + } + } else { + t := info.types[i].variant.(runtime.Type_Info_Multi_Pointer).elem + t_size := uintptr(t.size) + if reflect.is_any(t) { + io.write_string(fi.writer, "any{}", &fi.n) + } else { + field_ptr := (^^byte)(uintptr(v.data) + info.offsets[i])^ + data := rawptr(uintptr(field_ptr) + index*t_size) + fmt_arg(fi, any{data, t.id}, verb) + } + } + + if hash { io.write_string(fi.writer, ",\n", &fi.n) } + } + } + + if hash && n > 0 { + for _ in 0.. 0 { - io.write_byte(fi.writer, '\n', &fi.n) - } - - for index in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - - field_count := -1 - - if !hash && field_count > 0 { io.write_string(fi.writer, ", ", &fi.n) } - - if hash { - fi.indent -= 1 - fmt_write_indent(fi) - fi.indent += 1 - } - io.write_string(fi.writer, base_type_name, &fi.n) - io.write_byte(fi.writer, '{', &fi.n) - if hash && !is_empty { io.write_byte(fi.writer, '\n', &fi.n) } - defer { - if hash && !is_empty { - fi.indent -= 1 - fmt_write_indent(fi) - fi.indent += 1 - } - io.write_byte(fi.writer, '}', &fi.n) - if hash { io.write_string(fi.writer, ",\n", &fi.n) } - } - fi.record_level += 1 - defer fi.record_level -= 1 - - for i in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - if hash { - fmt_write_indent(fi) - } - - io.write_string(fi.writer, name, &fi.n) - io.write_string(fi.writer, " = ", &fi.n) - - if info.soa_kind == .Fixed { - t := info.types[i].variant.(runtime.Type_Info_Array).elem - t_size := uintptr(t.size) - if reflect.is_any(t) { - io.write_string(fi.writer, "any{}", &fi.n) - } else { - data := rawptr(uintptr(v.data) + info.offsets[i] + index*t_size) - fmt_arg(fi, any{data, t.id}, verb) - } - } else { - t := info.types[i].variant.(runtime.Type_Info_Multi_Pointer).elem - t_size := uintptr(t.size) - if reflect.is_any(t) { - io.write_string(fi.writer, "any{}", &fi.n) - } else { - field_ptr := (^^byte)(uintptr(v.data) + info.offsets[i])^ - data := rawptr(uintptr(field_ptr) + index*t_size) - fmt_arg(fi, any{data, t.id}, verb) - } - } - - if hash { io.write_string(fi.writer, ",\n", &fi.n) } - } - } - - if hash && n > 0 { - for _ in 0.. bool { + switch a in v { + case runtime.Source_Code_Location: + io.write_string(fi.writer, a.file_path, &fi.n) + + when ODIN_ERROR_POS_STYLE == .Default { + io.write_byte(fi.writer, '(', &fi.n) + io.write_int(fi.writer, int(a.line), 10, &fi.n) + if a.column != 0 { + io.write_byte(fi.writer, ':', &fi.n) + io.write_int(fi.writer, int(a.column), 10, &fi.n) + } + io.write_byte(fi.writer, ')', &fi.n) + } else when ODIN_ERROR_POS_STYLE == .Unix { + io.write_byte(fi.writer, ':', &fi.n) + io.write_int(fi.writer, int(a.line), 10, &fi.n) + if a.column != 0 { + io.write_byte(fi.writer, ':', &fi.n) + io.write_int(fi.writer, int(a.column), 10, &fi.n) + } + io.write_byte(fi.writer, ':', &fi.n) + } else { + #panic("Unhandled ODIN_ERROR_POS_STYLE") + } + return true + + case time.Duration: + ffrac :: proc(buf: []byte, v: u64, prec: int) -> (nw: int, nv: u64) { + v := v + w := len(buf) + print := false + for _ in 0.. int { + v := v + w := len(buf) + if v == 0 { + w -= 1 + buf[w] = '0' + } else { + for v > 0 { + w -= 1 + buf[w] = byte(v%10) + '0' + v /= 10 + } + } + return w + } + + buf: [32]byte + w := len(buf) + u := u64(a) + neg := a < 0 + if neg { + u = -u + } + + if u < u64(time.Second) { + prec: int + w -= 1 + buf[w] = 's' + w -= 1 + switch { + case u == 0: + io.write_string(fi.writer, "0s", &fi.n) + return true + case u < u64(time.Microsecond): + prec = 0 + buf[w] = 'n' + case u < u64(time.Millisecond): + prec = 3 + // U+00B5 'µ' micro sign == 0xC2 0xB5 + w -= 1 // Need room for two bytes + copy(buf[w:], "µ") + case: + prec = 6 + buf[w] = 'm' + } + if fi.space { + w -= 1 + buf[w] = ' ' + } + w, u = ffrac(buf[:w], u, prec) + w = fint(buf[:w], u) + } else { + w -= 1 + buf[w] = 's' + if fi.space { + w -= 1 + buf[w] = ' ' + } + w, u = ffrac(buf[:w], u, 9) + w = fint(buf[:w], u%60) + u /= 60 + if u > 0 { + w -= 1 + buf[w] = 'm' + w = fint(buf[:w], u%60) + u /= 60 + if u > 0 { + w -= 1 + buf[w] = 'h' + w = fint(buf[:w], u) + } + } + } + + if neg { + w -= 1 + buf[w] = '-' + } + io.write_string(fi.writer, string(buf[w:]), &fi.n) + return true + + case time.Time: + write_padded_number :: proc(fi: ^Info, i: i64, width: int) { + n := width-1 + for x := i; x >= 10; x /= 10 { + n -= 1 + } + for _ in 0..= 10; x /= 10 { - n -= 1 - } - for _ in 0.. (nw: int, nv: u64) { - v := v - w := len(buf) - print := false - for _ in 0.. int { - v := v - w := len(buf) - if v == 0 { - w -= 1 - buf[w] = '0' - } else { - for v > 0 { - w -= 1 - buf[w] = byte(v%10) + '0' - v /= 10 - } - } - return w - } - - buf: [32]byte - w := len(buf) - u := u64(a) - neg := a < 0 - if neg { - u = -u - } - - if u < u64(time.Second) { - prec: int - w -= 1 - buf[w] = 's' - w -= 1 - switch { - case u == 0: - io.write_string(fi.writer, "0s", &fi.n) - return - case u < u64(time.Microsecond): - prec = 0 - buf[w] = 'n' - case u < u64(time.Millisecond): - prec = 3 - // U+00B5 'µ' micro sign == 0xC2 0xB5 - w -= 1 // Need room for two bytes - copy(buf[w:], "µ") - case: - prec = 6 - buf[w] = 'm' - } - w, u = ffrac(buf[:w], u, prec) - w = fint(buf[:w], u) - } else { - w -= 1 - buf[w] = 's' - w, u = ffrac(buf[:w], u, 9) - w = fint(buf[:w], u%60) - u /= 60 - if u > 0 { - w -= 1 - buf[w] = 'm' - w = fint(buf[:w], u%60) - u /= 60 - if u > 0 { - w -= 1 - buf[w] = 'h' - w = fint(buf[:w], u) - } - } - } - - if neg { - w -= 1 - buf[w] = '-' - } - io.write_string(fi.writer, string(buf[w:]), &fi.n) - return - - case time.Time: - t := a - y, mon, d := time.date(t) - h, min, s := time.clock(t) - ns := (t._nsec - (t._nsec/1e9 + time.UNIX_TO_ABSOLUTE)*1e9) % 1e9 - write_padded_number(fi, i64(y), 4) - io.write_byte(fi.writer, '-', &fi.n) - write_padded_number(fi, i64(mon), 2) - io.write_byte(fi.writer, '-', &fi.n) - write_padded_number(fi, i64(d), 2) - io.write_byte(fi.writer, ' ', &fi.n) - - write_padded_number(fi, i64(h), 2) - io.write_byte(fi.writer, ':', &fi.n) - write_padded_number(fi, i64(min), 2) - io.write_byte(fi.writer, ':', &fi.n) - write_padded_number(fi, i64(s), 2) - io.write_byte(fi.writer, '.', &fi.n) - write_padded_number(fi, (ns), 9) - io.write_string(fi.writer, " +0000 UTC", &fi.n) - return - } + if verb != 'w' && fmt_named_buitlin_custom_formatters(fi, v, verb, info) { + return } #partial switch &b in info.base.variant { @@ -2765,6 +2919,232 @@ fmt_bit_field :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Bit } +@(private) +fmt_pointer_from_value :: proc(fi: ^Info, v: any, info: runtime.Type_Info_Pointer, verb: rune) { + if v.id == typeid_of(^runtime.Type_Info) { + reflect.write_type(fi.writer, (^^runtime.Type_Info)(v.data)^, &fi.n) + } else { + ptr := (^rawptr)(v.data)^ + if verb != 'p' && info.elem != nil { + a := any{ptr, info.elem.id} + + elem := runtime.type_info_base(info.elem) + if elem != nil { + #partial switch &e in elem.variant { + case runtime.Type_Info_Array, + runtime.Type_Info_Slice, + runtime.Type_Info_Dynamic_Array, + runtime.Type_Info_Map: + if ptr == nil { + io.write_string(fi.writer, "", &fi.n) + return + } + if fi.indirection_level < 1 { + fi.indirection_level += 1 + defer fi.indirection_level -= 1 + io.write_byte(fi.writer, '&') + fmt_value(fi, a, verb) + return + } + + case runtime.Type_Info_Struct, + runtime.Type_Info_Union, + runtime.Type_Info_Bit_Field: + if ptr == nil { + io.write_string(fi.writer, "", &fi.n) + return + } + if fi.indirection_level < 1 { + fi.indirection_level += 1 + defer fi.indirection_level -= 1 + io.write_byte(fi.writer, '&', &fi.n) + fmt_value(fi, a, verb) + return + } + } + } + } + fmt_pointer(fi, ptr, verb) + } +} + +@(private) +fmt_multi_pointer :: proc(fi: ^Info, v: any, info: runtime.Type_Info_Multi_Pointer, verb: rune) { + ptr := (^rawptr)(v.data)^ + if ptr == nil { + io.write_string(fi.writer, "", &fi.n) + return + } + if verb != 'p' && info.elem != nil { + a := any{ptr, info.elem.id} + + elem := runtime.type_info_base(info.elem) + if elem != nil { + if n, ok := fi.optional_len.?; ok { + fi.optional_len = nil + fmt_array(fi, ptr, n, elem.size, elem, verb) + return + } else if fi.use_nul_termination { + fi.use_nul_termination = false + fmt_array_nul_terminated(fi, ptr, -1, elem.size, elem, verb) + return + } + + #partial switch &e in elem.variant { + case runtime.Type_Info_Integer: + switch verb { + case 's', 'q': + switch elem.id { + case u8: + fmt_cstring(fi, cstring(ptr), verb) + return + case u16, u32, rune: + n := search_nul_termination(ptr, elem.size, -1) + fmt_array(fi, ptr, n, elem.size, elem, verb) + return + } + } + + case runtime.Type_Info_Array, + runtime.Type_Info_Slice, + runtime.Type_Info_Dynamic_Array, + runtime.Type_Info_Map: + if fi.indirection_level < 1 { + fi.indirection_level += 1 + defer fi.indirection_level -= 1 + io.write_byte(fi.writer, '&', &fi.n) + fmt_value(fi, a, verb) + return + } + + case runtime.Type_Info_Struct, + runtime.Type_Info_Union: + if fi.indirection_level < 1 { + fi.indirection_level += 1 + defer fi.indirection_level -= 1 + io.write_byte(fi.writer, '&', &fi.n) + fmt_value(fi, a, verb) + return + } + } + } + } + fmt_pointer(fi, ptr, verb) +} + +fmt_enumerated_array :: proc(fi: ^Info, v: any, info: runtime.Type_Info_Enumerated_Array, verb: rune) { + fi.record_level += 1 + defer fi.record_level -= 1 + + if fi.hash { + io.write_byte(fi.writer, '[' if verb != 'w' else '{', &fi.n) + io.write_byte(fi.writer, '\n', &fi.n) + defer { + fmt_write_indent(fi) + io.write_byte(fi.writer, ']' if verb != 'w' else '}', &fi.n) + } + indent := fi.indent + fi.indent += 1 + defer fi.indent = indent + + for i in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } + + idx, ok := stored_enum_value_to_string(info.index, info.min_value, i) + if ok { + io.write_byte(fi.writer, '.', &fi.n) + io.write_string(fi.writer, idx, &fi.n) + } else { + io.write_i64(fi.writer, i64(info.min_value)+i64(i), 10, &fi.n) + } + io.write_string(fi.writer, " = ", &fi.n) + + data := uintptr(v.data) + uintptr(i*info.elem_size) + fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) + } + } +} + +fmt_map :: proc(fi: ^Info, v: any, info: runtime.Type_Info_Map, verb: rune) { + switch verb { + case: + fmt_bad_verb(fi, verb) + case 'v', 'w': + if verb == 'v' { + io.write_string(fi.writer, "map", &fi.n) + } + io.write_byte(fi.writer, '[' if verb != 'w' else '{', &fi.n) + defer io.write_byte(fi.writer, ']' if verb != 'w' else '}', &fi.n) + + + hash := fi.hash; defer fi.hash = hash + indent := fi.indent; defer fi.indent -= 1 + do_trailing_comma := hash + + fi.indent += 1 + if hash { + io.write_byte(fi.writer, '\n', &fi.n) + } + defer { + if hash { + for _ in 0.. 0 { io.write_string(fi.writer, ", ") } + if hash { + fmt_write_indent(fi) + } + j += 1 + + key := runtime.map_cell_index_dynamic(ks, info.map_info.ks, bucket_index) + value := runtime.map_cell_index_dynamic(vs, info.map_info.vs, bucket_index) + + fmt_arg(&Info{writer = fi.writer}, any{rawptr(key), info.key.id}, verb) + if hash { + io.write_string(fi.writer, " = ", &fi.n) + } else { + io.write_string(fi.writer, "=", &fi.n) + } + fmt_arg(fi, any{rawptr(value), info.value.id}, verb) + + if do_trailing_comma { io.write_string(fi.writer, ",\n", &fi.n) } + } + } + } + +} // Formats a value based on its type and formatting verb // @@ -2795,184 +3175,35 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { type_info := type_info_of(v.id) switch &info in type_info.variant { - case runtime.Type_Info_Any: // Ignore - case runtime.Type_Info_Parameters: // Ignore + case runtime.Type_Info_Any: + // Ignore + case runtime.Type_Info_Parameters: + // Ignore case runtime.Type_Info_Named: fmt_named(fi, v, verb, info) - case runtime.Type_Info_Boolean: fmt_arg(fi, v, verb) - case runtime.Type_Info_Integer: fmt_arg(fi, v, verb) - case runtime.Type_Info_Rune: fmt_arg(fi, v, verb) - case runtime.Type_Info_Float: fmt_arg(fi, v, verb) - case runtime.Type_Info_Complex: fmt_arg(fi, v, verb) - case runtime.Type_Info_Quaternion: fmt_arg(fi, v, verb) - case runtime.Type_Info_String: fmt_arg(fi, v, verb) + case runtime.Type_Info_Boolean, + runtime.Type_Info_Integer, + runtime.Type_Info_Rune, + runtime.Type_Info_Float, + runtime.Type_Info_Complex, + runtime.Type_Info_Quaternion, + runtime.Type_Info_String: + fmt_arg(fi, v, verb) case runtime.Type_Info_Pointer: - if v.id == typeid_of(^runtime.Type_Info) { - reflect.write_type(fi.writer, (^^runtime.Type_Info)(v.data)^, &fi.n) - } else { - ptr := (^rawptr)(v.data)^ - if verb != 'p' && info.elem != nil { - a := any{ptr, info.elem.id} - - elem := runtime.type_info_base(info.elem) - if elem != nil { - #partial switch &e in elem.variant { - case runtime.Type_Info_Array, - runtime.Type_Info_Slice, - runtime.Type_Info_Dynamic_Array, - runtime.Type_Info_Map: - if ptr == nil { - io.write_string(fi.writer, "", &fi.n) - return - } - if fi.indirection_level < 1 { - fi.indirection_level += 1 - defer fi.indirection_level -= 1 - io.write_byte(fi.writer, '&') - fmt_value(fi, a, verb) - return - } - - case runtime.Type_Info_Struct, - runtime.Type_Info_Union, - runtime.Type_Info_Bit_Field: - if ptr == nil { - io.write_string(fi.writer, "", &fi.n) - return - } - if fi.indirection_level < 1 { - fi.indirection_level += 1 - defer fi.indirection_level -= 1 - io.write_byte(fi.writer, '&', &fi.n) - fmt_value(fi, a, verb) - return - } - } - } - } - fmt_pointer(fi, ptr, verb) - } + fmt_pointer_from_value(fi, v, info, verb) case runtime.Type_Info_Soa_Pointer: ptr := (^runtime.Raw_Soa_Pointer)(v.data)^ fmt_soa_pointer(fi, ptr, verb) case runtime.Type_Info_Multi_Pointer: - ptr := (^rawptr)(v.data)^ - if ptr == nil { - io.write_string(fi.writer, "", &fi.n) - return - } - if verb != 'p' && info.elem != nil { - a := any{ptr, info.elem.id} - - elem := runtime.type_info_base(info.elem) - if elem != nil { - if n, ok := fi.optional_len.?; ok { - fi.optional_len = nil - fmt_array(fi, ptr, n, elem.size, elem, verb) - return - } else if fi.use_nul_termination { - fi.use_nul_termination = false - fmt_array_nul_terminated(fi, ptr, -1, elem.size, elem, verb) - return - } - - #partial switch &e in elem.variant { - case runtime.Type_Info_Integer: - switch verb { - case 's', 'q': - switch elem.id { - case u8: - fmt_cstring(fi, cstring(ptr), verb) - return - case u16, u32, rune: - n := search_nul_termination(ptr, elem.size, -1) - fmt_array(fi, ptr, n, elem.size, elem, verb) - return - } - } - - case runtime.Type_Info_Array, - runtime.Type_Info_Slice, - runtime.Type_Info_Dynamic_Array, - runtime.Type_Info_Map: - if fi.indirection_level < 1 { - fi.indirection_level += 1 - defer fi.indirection_level -= 1 - io.write_byte(fi.writer, '&', &fi.n) - fmt_value(fi, a, verb) - return - } - - case runtime.Type_Info_Struct, - runtime.Type_Info_Union: - if fi.indirection_level < 1 { - fi.indirection_level += 1 - defer fi.indirection_level -= 1 - io.write_byte(fi.writer, '&', &fi.n) - fmt_value(fi, a, verb) - return - } - } - } - } - fmt_pointer(fi, ptr, verb) + fmt_multi_pointer(fi, v, info, verb) case runtime.Type_Info_Enumerated_Array: - fi.record_level += 1 - defer fi.record_level -= 1 - - if fi.hash { - io.write_byte(fi.writer, '[' if verb != 'w' else '{', &fi.n) - io.write_byte(fi.writer, '\n', &fi.n) - defer { - fmt_write_indent(fi) - io.write_byte(fi.writer, ']' if verb != 'w' else '}', &fi.n) - } - indent := fi.indent - fi.indent += 1 - defer fi.indent = indent - - for i in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - - idx, ok := stored_enum_value_to_string(info.index, info.min_value, i) - if ok { - io.write_byte(fi.writer, '.', &fi.n) - io.write_string(fi.writer, idx, &fi.n) - } else { - io.write_i64(fi.writer, i64(info.min_value)+i64(i), 10, &fi.n) - } - io.write_string(fi.writer, " = ", &fi.n) - - data := uintptr(v.data) + uintptr(i*info.elem_size) - fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) - } - } + fmt_enumerated_array(fi, v, info, verb) case runtime.Type_Info_Array: n := info.count @@ -3015,6 +3246,21 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { } fmt_array(fi, ptr, n, info.elem_size, info.elem, verb) + + case runtime.Type_Info_Fixed_Capacity_Dynamic_Array: + n := (^int)(uintptr(v.data) + info.len_offset)^ + + ptr := v.data // data is stored at the start + if ol, ok := fi.optional_len.?; ok { + fi.optional_len = nil + n = min(n, ol) + } else if fi.use_nul_termination { + fi.use_nul_termination = false + fmt_array_nul_terminated(fi, ptr, n, info.elem_size, info.elem, verb) + return + } + fmt_array(fi, ptr, n, info.elem_size, info.elem, verb) + case runtime.Type_Info_Simd_Vector: io.write_byte(fi.writer, '<', &fi.n) defer io.write_byte(fi.writer, '>', &fi.n) @@ -3027,63 +3273,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Map: - switch verb { - case: - fmt_bad_verb(fi, verb) - case 'v', 'w': - if verb == 'v' { - io.write_string(fi.writer, "map", &fi.n) - } - io.write_byte(fi.writer, '[' if verb != 'w' else '{', &fi.n) - defer io.write_byte(fi.writer, ']' if verb != 'w' else '}', &fi.n) - - - hash := fi.hash; defer fi.hash = hash - indent := fi.indent; defer fi.indent -= 1 - do_trailing_comma := hash - - fi.indent += 1 - if hash { - io.write_byte(fi.writer, '\n', &fi.n) - } - defer { - if hash { - for _ in 0.. 0 { io.write_string(fi.writer, ", ") } - if hash { - fmt_write_indent(fi) - } - j += 1 - - key := runtime.map_cell_index_dynamic(ks, info.map_info.ks, bucket_index) - value := runtime.map_cell_index_dynamic(vs, info.map_info.vs, bucket_index) - - fmt_arg(&Info{writer = fi.writer}, any{rawptr(key), info.key.id}, verb) - if hash { - io.write_string(fi.writer, " = ", &fi.n) - } else { - io.write_string(fi.writer, "=", &fi.n) - } - fmt_arg(fi, any{rawptr(value), info.value.id}, verb) - - if do_trailing_comma { io.write_string(fi.writer, ",\n", &fi.n) } - } - } - } + fmt_map(fi, v, info, verb) case runtime.Type_Info_Struct: fmt_struct(fi, v, verb, info, "") diff --git a/core/fmt/fmt_js.odin b/core/fmt/fmt_js.odin index 4ec6bd9a8..ccab15220 100644 --- a/core/fmt/fmt_js.odin +++ b/core/fmt/fmt_js.odin @@ -1,10 +1,6 @@ #+build js package fmt -import "core:bufio" -import "core:io" -import "core:os" - foreign import "odin_env" @(private="file") @@ -12,90 +8,77 @@ foreign odin_env { write :: proc "contextless" (fd: u32, p: []byte) --- } -@(private="file") -write_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { - if mode == .Write { - fd := u32(uintptr(stream_data)) - write(fd, p) - return i64(len(p)), nil - } - return 0, .Unsupported -} +stdout :: u32(1) +stderr :: u32(2) @(private="file") -stdout := io.Writer{ - procedure = write_stream_proc, - data = rawptr(uintptr(1)), -} -@(private="file") -stderr := io.Writer{ - procedure = write_stream_proc, - data = rawptr(uintptr(2)), -} +BUF_SIZE :: 1024 @(private="file") -fd_to_writer :: proc(fd: os.Handle, loc := #caller_location) -> io.Writer { - switch fd { - case 1: return stdout - case 2: return stderr - case: panic("`fmt.fprint` variant called with invalid file descriptor for JS, only 1 (stdout) and 2 (stderr) are supported", loc) +// TODO: Find a way to grow this if necessary +buf: [BUF_SIZE]byte + +@(private="file") +get_fd :: proc(f: any, loc := #caller_location) -> (fd: u32) { + if _fd, _ok := f.(u32); _ok { + fd = _fd } + if fd != 1 && fd != 2 { + panic("`fmt.fprint` variant called with invalid file descriptor for JS, only 1 (stdout) and 2 (stderr) are supported", loc) + } + return fd } // fprint formats using the default print settings and writes to fd -fprint :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true, loc := #caller_location) -> int { - buf: [1024]byte - b: bufio.Writer - defer bufio.writer_flush(&b) - - bufio.writer_init_with_buf(&b, fd_to_writer(fd, loc), buf[:]) - w := bufio.writer_to_writer(&b) - return wprint(w, ..args, sep=sep, flush=flush) +// flush is ignored +fprint :: proc(f: any, args: ..any, sep := " ", flush := true, loc := #caller_location) -> (n: int) { + fd := get_fd(f) + s := bprint(buf[:], ..args, sep=sep) + n = len(s) + write(fd, transmute([]byte)s) + return n } -// fprintln formats using the default print settings and writes to fd -fprintln :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true, loc := #caller_location) -> int { - buf: [1024]byte - b: bufio.Writer - defer bufio.writer_flush(&b) - - bufio.writer_init_with_buf(&b, fd_to_writer(fd, loc), buf[:]) - - w := bufio.writer_to_writer(&b) - return wprintln(w, ..args, sep=sep, flush=flush) +// fprintln formats using the default print settings and writes to fd, followed by a newline +// flush is ignored +fprintln :: proc(f: any, args: ..any, sep := " ", flush := true, loc := #caller_location) -> (n: int) { + fd := get_fd(f) + s := bprintln(buf[:], ..args, sep=sep) + n = len(s) + write(fd, transmute([]byte)s) + return n } // fprintf formats according to the specified format string and writes to fd -fprintf :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, newline := false, loc := #caller_location) -> int { - buf: [1024]byte - b: bufio.Writer - defer bufio.writer_flush(&b) - - bufio.writer_init_with_buf(&b, fd_to_writer(fd, loc), buf[:]) - - w := bufio.writer_to_writer(&b) - return wprintf(w, fmt, ..args, flush=flush, newline=newline) +// flush is ignored +fprintf :: proc(f: any, fmt: string, args: ..any, flush := true, newline := false, loc := #caller_location) -> (n: int) { + fd := get_fd(f) + s := bprintf(buf[:], fmt, ..args, newline=newline) + n = len(s) + write(fd, transmute([]byte)s) + return n } // fprintfln formats according to the specified format string and writes to fd, followed by a newline. -fprintfln :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, loc := #caller_location) -> int { - return fprintf(fd, fmt, ..args, flush=flush, newline=true, loc=loc) +// flush is ignored +fprintfln :: proc(f: any, fmt: string, args: ..any, flush := true, loc := #caller_location) -> int { + return fprintf(f, fmt, ..args, flush=flush, newline=true, loc=loc) } // print formats using the default print settings and writes to stdout -print :: proc(args: ..any, sep := " ", flush := true) -> int { return wprint(w=stdout, args=args, sep=sep, flush=flush) } +print :: proc(args: ..any, sep := " ", flush := true) -> int { return fprint(stdout, ..args, sep=sep, flush=flush) } // println formats using the default print settings and writes to stdout -println :: proc(args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stdout, args=args, sep=sep, flush=flush) } +println :: proc(args: ..any, sep := " ", flush := true) -> int { return fprintln(stdout, ..args, sep=sep, flush=flush) } // printf formats according to the specififed format string and writes to stdout -printf :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush) } +printf :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(stdout, fmt, ..args, flush=flush) } // printfln formats according to the specified format string and writes to stdout, followed by a newline. -printfln :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush, newline=true) } +printfln :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(stdout, fmt, ..args, flush=flush, newline=true) } // eprint formats using the default print settings and writes to stderr -eprint :: proc(args: ..any, sep := " ", flush := true) -> int { return wprint(w=stderr, args=args, sep=sep, flush=flush) } +eprint :: proc(args: ..any, sep := " ", flush := true) -> int { return fprint(stderr, ..args, sep=sep, flush=flush) } // eprintln formats using the default print settings and writes to stderr -eprintln :: proc(args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stderr, args=args, sep=sep, flush=flush) } +eprintln :: proc(args: ..any, sep := " ", flush := true) -> int { return fprintln(stderr, ..args, sep=sep, flush=flush) } // eprintf formats according to the specififed format string and writes to stderr -eprintf :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stderr, fmt, ..args, flush=flush) } +eprintf :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(stderr, fmt, ..args, flush=flush) } // eprintfln formats according to the specified format string and writes to stderr, followed by a newline. -eprintfln :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush, newline=true) } +eprintfln :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(stderr, fmt, ..args, flush=flush, newline=true) } \ No newline at end of file diff --git a/core/fmt/fmt_os.odin b/core/fmt/fmt_os.odin index a481061f1..0305b5bac 100644 --- a/core/fmt/fmt_os.odin +++ b/core/fmt/fmt_os.odin @@ -8,59 +8,61 @@ import "core:os" import "core:io" import "core:bufio" +// NOTE(Jeroen): The other option is to deprecate `fprint*` and make it an alias for `wprint*`, using File.stream directly. + // fprint formats using the default print settings and writes to fd -fprint :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int { +fprint :: proc(f: ^os.File, args: ..any, sep := " ", flush := true) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) - bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:]) + bufio.writer_init_with_buf(&b, os.to_stream(f), buf[:]) w := bufio.writer_to_writer(&b) return wprint(w, ..args, sep=sep, flush=flush) } // fprintln formats using the default print settings and writes to fd -fprintln :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int { +fprintln :: proc(f: ^os.File, args: ..any, sep := " ", flush := true) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) - bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:]) + bufio.writer_init_with_buf(&b, os.to_stream(f), buf[:]) w := bufio.writer_to_writer(&b) return wprintln(w, ..args, sep=sep, flush=flush) } // fprintf formats according to the specified format string and writes to fd -fprintf :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, newline := false) -> int { +fprintf :: proc(f: ^os.File, fmt: string, args: ..any, flush := true, newline := false) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) - bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:]) + bufio.writer_init_with_buf(&b, os.to_stream(f), buf[:]) w := bufio.writer_to_writer(&b) return wprintf(w, fmt, ..args, flush=flush, newline=newline) } // fprintfln formats according to the specified format string and writes to fd, followed by a newline. -fprintfln :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true) -> int { - return fprintf(fd, fmt, ..args, flush=flush, newline=true) +fprintfln :: proc(f: ^os.File, fmt: string, args: ..any, flush := true) -> int { + return fprintf(f, fmt, ..args, flush=flush, newline=true) } -fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info, flush := true) -> (n: int, err: io.Error) { +fprint_type :: proc(f: ^os.File, info: ^runtime.Type_Info, flush := true) -> (n: int, err: io.Error) { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) - bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:]) + bufio.writer_init_with_buf(&b, os.to_stream(f), buf[:]) w := bufio.writer_to_writer(&b) return wprint_type(w, info, flush=flush) } -fprint_typeid :: proc(fd: os.Handle, id: typeid, flush := true) -> (n: int, err: io.Error) { +fprint_typeid :: proc(f: ^os.File, id: typeid, flush := true) -> (n: int, err: io.Error) { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) - bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:]) + bufio.writer_init_with_buf(&b, os.to_stream(f), buf[:]) w := bufio.writer_to_writer(&b) return wprint_typeid(w, id, flush=flush) diff --git a/core/hash/crc32.odin b/core/hash/crc32.odin index 0a4617f6d..777209bed 100644 --- a/core/hash/crc32.odin +++ b/core/hash/crc32.odin @@ -1,7 +1,5 @@ package hash -import "base:intrinsics" - @(optimization_mode="favor_size") crc32 :: proc "contextless" (data: []byte, seed := u32(0)) -> u32 #no_bounds_check { crc := ~seed diff --git a/core/hash/hash.odin b/core/hash/hash.odin index 6c048c05b..b495fd30d 100644 --- a/core/hash/hash.odin +++ b/core/hash/hash.odin @@ -1,7 +1,6 @@ package hash import "core:mem" -import "base:intrinsics" @(optimization_mode="favor_size") adler32 :: proc "contextless" (data: []byte, seed := u32(1)) -> u32 #no_bounds_check { @@ -57,14 +56,14 @@ djb2 :: proc "contextless" (data: []byte, seed := u32(5381)) -> u32 { djbx33a :: proc "contextless" (data: []byte, seed := u32(5381)) -> (result: [16]byte) #no_bounds_check { state := [4]u32{seed, seed, seed, seed} - + s: u32 = 0 for p in data { state[s] = (state[s] << 5) + state[s] + u32(p) // hash * 33 + u32(b) s = (s + 1) & 3 } - - + + (^u32le)(&result[0])^ = u32le(state[0]) (^u32le)(&result[4])^ = u32le(state[1]) (^u32le)(&result[8])^ = u32le(state[2]) @@ -160,7 +159,7 @@ murmur32 :: proc "contextless" (data: []byte, seed := u32(0x9747b28c)) -> u32 { case 1: k1 ~= u32(tail[0]) k1 *= c1_32 - k1 = (k1 << 15) | (k1 >> 17) + k1 = (k1 << 15) | (k1 >> 17) k1 *= c2_32 h1 ~= k1 } diff --git a/core/hash/xxhash/streaming.odin b/core/hash/xxhash/streaming.odin index d34206fdb..22d99be1d 100644 --- a/core/hash/xxhash/streaming.odin +++ b/core/hash/xxhash/streaming.odin @@ -10,7 +10,7 @@ package xxhash Jeroen van Rijn: Initial implementation. */ -import "core:mem" +import "base:runtime" import "base:intrinsics" /* @@ -121,7 +121,7 @@ XXH3_init_state :: proc(state: ^XXH3_state) { } XXH3_create_state :: proc(allocator := context.allocator) -> (res: ^XXH3_state, err: Error) { - state, mem_error := mem.new_aligned(XXH3_state, 64, allocator) + state, mem_error := runtime.new_aligned(XXH3_state, 64, allocator) err = nil if mem_error == nil else .Error XXH3_init_state(state) diff --git a/core/image/bmp/bmp_os.odin b/core/image/bmp/bmp_os.odin index 70a85a784..1aa1d63de 100644 --- a/core/image/bmp/bmp_os.odin +++ b/core/image/bmp/bmp_os.odin @@ -9,10 +9,10 @@ load :: proc{load_from_file, load_from_bytes, load_from_context} load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) { context.allocator = allocator - data, ok := os.read_entire_file(filename) - defer delete(data) + data, data_err := os.read_entire_file(filename, allocator) + defer delete(data, allocator) - if ok { + if data_err == nil { return load_from_bytes(data, options) } else { return nil, .Unable_To_Read_File @@ -28,7 +28,7 @@ save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocato defer bytes.buffer_destroy(out) save_to_buffer(out, img, options) or_return - write_ok := os.write_entire_file(output, out.buf[:]) + write_err := os.write_entire_file(output, out.buf[:]) - return nil if write_ok else .Unable_To_Write_File + return nil if write_err == nil else .Unable_To_Write_File } \ No newline at end of file diff --git a/core/image/general.odin b/core/image/general.odin index 1662cf14e..779f5d0b1 100644 --- a/core/image/general.odin +++ b/core/image/general.odin @@ -86,7 +86,7 @@ which_bytes :: proc(data: []byte) -> Which_File_Type { return v } get16le :: #force_inline proc(s: ^string) -> u16 { - v := u16(s[0]) | u16(s[1])<<16 + v := u16(s[0]) | u16(s[1])<<8 s^ = s[2:] return v } diff --git a/core/image/general_os.odin b/core/image/general_os.odin index 98eb5bdbe..63d7c8d43 100644 --- a/core/image/general_os.odin +++ b/core/image/general_os.odin @@ -8,18 +8,16 @@ load :: proc{ load_from_file, } - load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) { - data, ok := os.read_entire_file(filename, allocator) + data, data_err := os.read_entire_file(filename, allocator) defer delete(data, allocator) - if ok { + if data_err == nil { return load_from_bytes(data, options, allocator) } else { return nil, .Unable_To_Read_File } } - which :: proc{ which_bytes, which_file, diff --git a/core/image/jpeg/jpeg.odin b/core/image/jpeg/jpeg.odin index 241066273..7261e5dd5 100644 --- a/core/image/jpeg/jpeg.odin +++ b/core/image/jpeg/jpeg.odin @@ -648,27 +648,17 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a color_components[id].v_sampling_factor = cast(int)vertical_sampling color_components[id].h_sampling_factor = cast(int)horizontal_sampling } - case .SOF2: // Progressive DCT - fallthrough - case .SOF3: // Lossless (sequential) - fallthrough - case .SOF5: // Differential sequential DCT - fallthrough - case .SOF6: // Differential progressive DCT - fallthrough - case .SOF7: // Differential lossless (sequential) - fallthrough - case .SOF9: // Extended sequential DCT, Arithmetic coding - fallthrough - case .SOF10: // Progressive DCT, Arithmetic coding - fallthrough - case .SOF11: // Lossless (sequential), Arithmetic coding - fallthrough - case .SOF13: // Differential sequential DCT, Arithmetic coding - fallthrough - case .SOF14: // Differential progressive DCT, Arithmetic coding - fallthrough - case .SOF15: // Differential lossless (sequential), Arithmetic coding + case .SOF2, // Progressive DCT + .SOF3, // Lossless (sequential) + .SOF5, // Differential sequential DCT + .SOF6, // Differential progressive DCT + .SOF7, // Differential lossless (sequential) + .SOF9, // Extended sequential DCT, Arithmetic coding + .SOF10, // Progressive DCT, Arithmetic coding + .SOF11, // Lossless (sequential), Arithmetic coding + .SOF13, // Differential sequential DCT, Arithmetic coding + .SOF14, // Differential progressive DCT, Arithmetic coding + .SOF15: // Differential lossless (sequential), Arithmetic coding if img.metadata != nil { info := img.metadata.(^image.JPEG_Info) info.frame_type = marker diff --git a/core/image/jpeg/jpeg_os.odin b/core/image/jpeg/jpeg_os.odin index 92c0bb447..6ba301d80 100644 --- a/core/image/jpeg/jpeg_os.odin +++ b/core/image/jpeg/jpeg_os.odin @@ -8,10 +8,10 @@ load :: proc{load_from_file, load_from_bytes, load_from_context} load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) { context.allocator = allocator - data, ok := os.read_entire_file(filename) - defer delete(data) + data, data_err := os.read_entire_file(filename, allocator) + defer delete(data, allocator) - if ok { + if data_err == nil { return load_from_bytes(data, options) } else { return nil, .Unable_To_Read_File diff --git a/core/image/netpbm/netpbm.odin b/core/image/netpbm/netpbm.odin index 25e0228b5..6a30d135a 100644 --- a/core/image/netpbm/netpbm.odin +++ b/core/image/netpbm/netpbm.odin @@ -1,4 +1,3 @@ -#+vet !using-stmt package netpbm import "core:bytes" @@ -73,8 +72,7 @@ save_to_buffer :: proc(img: ^Image, custom_info: Info = {}, allocator := context } } - // using info so we can just talk about the header - using info + header := &info.header // validation if header.format in (PBM + PGM + Formats{.Pf}) && img.channels != 1 \ @@ -664,14 +662,14 @@ autoselect_pbm_format_from_image :: proc(img: ^Image, prefer_binary := true, for ASCII :: Formats{.P1, .P2, .P3} */ - using res.header + h := &res.header - width = img.width - height = img.height - channels = img.channels - depth = img.depth - maxval = 255 if img.depth == 8 else 65535 - little_endian = true if ODIN_ENDIAN == .Little else false + h.width = img.width + h.height = img.height + h.channels = img.channels + h.depth = img.depth + h.maxval = 255 if img.depth == 8 else 65535 + h.little_endian = ODIN_ENDIAN == .Little // Assume we'll find a suitable format ok = true @@ -680,37 +678,37 @@ autoselect_pbm_format_from_image :: proc(img: ^Image, prefer_binary := true, for case 1: // Must be Portable Float Map if img.depth == 32 { - format = .Pf + h.format = .Pf return } if force_black_and_white { // Portable Bit Map - format = .P4 if prefer_binary else .P1 - maxval = 1 + h.format = .P4 if prefer_binary else .P1 + h.maxval = 1 return } else { // Portable Gray Map - format = .P5 if prefer_binary else .P2 + h.format = .P5 if prefer_binary else .P2 return } case 3: // Must be Portable Float Map if img.depth == 32 { - format = .PF + h.format = .PF return } // Portable Pixel Map - format = .P6 if prefer_binary else .P3 + h.format = .P6 if prefer_binary else .P3 return case: // Portable Arbitrary Map if img.depth == 8 || img.depth == 16 { - format = .P7 - scale = pfm_scale + h.format = .P7 + h.scale = pfm_scale return } } diff --git a/core/image/netpbm/netpbm_os.odin b/core/image/netpbm/netpbm_os.odin index 2cf2439ac..ae9029b54 100644 --- a/core/image/netpbm/netpbm_os.odin +++ b/core/image/netpbm/netpbm_os.odin @@ -8,20 +8,18 @@ load :: proc { load_from_bytes, } - load_from_file :: proc(filename: string, allocator := context.allocator) -> (img: ^Image, err: Error) { context.allocator = allocator - data, ok := os.read_entire_file(filename); defer delete(data) - if !ok { + data, data_err := os.read_entire_file(filename, allocator); defer delete(data) + if data_err == nil { + return load_from_bytes(data) + } else { err = .Unable_To_Read_File return } - - return load_from_bytes(data) } - save :: proc { save_to_file, save_to_buffer, @@ -33,7 +31,7 @@ save_to_file :: proc(filename: string, img: ^Image, custom_info: Info = {}, allo data: []byte; defer delete(data) data = save_to_buffer(img, custom_info) or_return - if ok := os.write_entire_file(filename, data); !ok { + if save_err := os.write_entire_file(filename, data); save_err != nil { return .Unable_To_Write_File } diff --git a/core/image/png/doc.odin b/core/image/png/doc.odin deleted file mode 100644 index 034a6775f..000000000 --- a/core/image/png/doc.odin +++ /dev/null @@ -1,348 +0,0 @@ -/* -Reader for `PNG` images. - -The PNG specification is at [[ https://www.w3.org/TR/PNG/ ]]. - -Example: - package main - - import "core:image" - // import "core:image/png" - import "core:bytes" - import "core:fmt" - - // For PPM writer - import "core:mem" - import "core:os" - - main :: proc() { - track := mem.Tracking_Allocator{} - mem.tracking_allocator_init(&track, context.allocator) - - context.allocator = mem.tracking_allocator(&track) - - demo() - - if len(track.allocation_map) > 0 { - fmt.println("Leaks:") - for _, v in track.allocation_map { - fmt.printf("\t%v\n\n", v) - } - } - } - - demo :: proc() { - file: string - - options := image.Options{.return_metadata} - err: image.Error - img: ^image.Image - - file = "../../../misc/logo-slim.png" - - img, err = load(file, options) - defer destroy(img) - - if err != nil { - fmt.printf("Trying to read PNG file %v returned %v\n", file, err) - } else { - fmt.printf("Image: %vx%vx%v, %v-bit.\n", img.width, img.height, img.channels, img.depth) - - if v, ok := img.metadata.(^image.PNG_Info); ok { - // Handle ancillary chunks as you wish. - // We provide helper functions for a few types. - for c in v.chunks { - #partial switch c.header.type { - case .tIME: - if t, t_ok := core_time(c); t_ok { - fmt.printf("[tIME]: %v\n", t) - } - case .gAMA: - if gama, gama_ok := gamma(c); gama_ok { - fmt.printf("[gAMA]: %v\n", gama) - } - case .pHYs: - if phys, phys_ok := phys(c); phys_ok { - if phys.unit == .Meter { - xm := f32(img.width) / f32(phys.ppu_x) - ym := f32(img.height) / f32(phys.ppu_y) - dpi_x, dpi_y := phys_to_dpi(phys) - fmt.printf("[pHYs] Image resolution is %v x %v pixels per meter.\n", phys.ppu_x, phys.ppu_y) - fmt.printf("[pHYs] Image resolution is %v x %v DPI.\n", dpi_x, dpi_y) - fmt.printf("[pHYs] Image dimensions are %v x %v meters.\n", xm, ym) - } else { - fmt.printf("[pHYs] x: %v, y: %v pixels per unknown unit.\n", phys.ppu_x, phys.ppu_y) - } - } - case .iTXt, .zTXt, .tEXt: - res, ok_text := text(c) - if ok_text { - if c.header.type == .iTXt { - fmt.printf("[iTXt] %v (%v:%v): %v\n", res.keyword, res.language, res.keyword_localized, res.text) - } else { - fmt.printf("[tEXt/zTXt] %v: %v\n", res.keyword, res.text) - } - } - defer text_destroy(res) - case .bKGD: - fmt.printf("[bKGD] %v\n", img.background) - case .eXIf: - if res, ok_exif := exif(c); ok_exif { - /* - Other than checking the signature and byte order, we don't handle Exif data. - If you wish to interpret it, pass it to an Exif parser. - */ - fmt.printf("[eXIf] %v\n", res) - } - case .PLTE: - if plte, plte_ok := plte(c); plte_ok { - fmt.printf("[PLTE] %v\n", plte) - } else { - fmt.printf("[PLTE] Error\n") - } - case .hIST: - if res, ok_hist := hist(c); ok_hist { - fmt.printf("[hIST] %v\n", res) - } - case .cHRM: - if res, ok_chrm := chrm(c); ok_chrm { - fmt.printf("[cHRM] %v\n", res) - } - case .sPLT: - res, ok_splt := splt(c) - if ok_splt { - fmt.printf("[sPLT] %v\n", res) - } - splt_destroy(res) - case .sBIT: - if res, ok_sbit := sbit(c); ok_sbit { - fmt.printf("[sBIT] %v\n", res) - } - case .iCCP: - res, ok_iccp := iccp(c) - if ok_iccp { - fmt.printf("[iCCP] %v\n", res) - } - iccp_destroy(res) - case .sRGB: - if res, ok_srgb := srgb(c); ok_srgb { - fmt.printf("[sRGB] Rendering intent: %v\n", res) - } - case: - type := c.header.type - name := chunk_type_to_name(&type) - fmt.printf("[%v]: %v\n", name, c.data) - } - } - } - } - - fmt.printf("Done parsing metadata.\n") - - if err == nil && .do_not_decompress_image not_in options && .info not_in options { - if ok := write_image_as_ppm("out.ppm", img); ok { - fmt.println("Saved decoded image.") - } else { - fmt.println("Error saving out.ppm.") - fmt.println(img) - } - } - } - - // Crappy PPM writer used during testing. Don't use in production. - write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: bool) { - - _bg :: proc(bg: Maybe([3]u16), x, y: int, high := true) -> (res: [3]u16) { - if v, ok := bg.?; ok { - res = v - } else { - if high { - l := u16(30 * 256 + 30) - - if (x & 4 == 0) ~ (y & 4 == 0) { - res = [3]u16{l, 0, l} - } else { - res = [3]u16{l >> 1, 0, l >> 1} - } - } else { - if (x & 4 == 0) ~ (y & 4 == 0) { - res = [3]u16{30, 30, 30} - } else { - res = [3]u16{15, 15, 15} - } - } - } - return - } - - // profiler.timed_proc(); - using image - using os - - flags: int = O_WRONLY|O_CREATE|O_TRUNC - - img := image - - // PBM 16-bit images are big endian - when ODIN_ENDIAN == .Little { - if img.depth == 16 { - // The pixel components are in Big Endian. Let's byteswap back. - input := mem.slice_data_cast([]u16, img.pixels.buf[:]) - output := mem.slice_data_cast([]u16be, img.pixels.buf[:]) - #no_bounds_check for v, i in input { - output[i] = u16be(v) - } - } - } - - pix := bytes.buffer_to_bytes(&img.pixels) - - if len(pix) == 0 || len(pix) < image.width * image.height * int(image.channels) { - return false - } - - mode: int = 0 - when ODIN_OS == .Linux || ODIN_OS == .Darwin { - // NOTE(justasd): 644 (owner read, write; group read; others read) - mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH - } - - fd, err := open(filename, flags, mode) - if err != nil { - return false - } - defer close(fd) - - write_string(fd, - fmt.tprintf("P6\n%v %v\n%v\n", width, height, uint(1 << uint(depth) - 1)), - ) - - if channels == 3 { - // We don't handle transparency here... - write_ptr(fd, raw_data(pix), len(pix)) - } else { - bpp := depth == 16 ? 2 : 1 - bytes_needed := width * height * 3 * bpp - - op := bytes.Buffer{} - bytes.buffer_init_allocator(&op, bytes_needed, bytes_needed) - defer bytes.buffer_destroy(&op) - - if channels == 1 { - if depth == 16 { - assert(len(pix) == width * height * 2) - p16 := mem.slice_data_cast([]u16, pix) - o16 := mem.slice_data_cast([]u16, op.buf[:]) - #no_bounds_check for len(p16) != 0 { - r := u16(p16[0]) - o16[0] = r - o16[1] = r - o16[2] = r - p16 = p16[1:] - o16 = o16[3:] - } - } else { - o := 0 - for i := 0; i < len(pix); i += 1 { - r := pix[i] - op.buf[o ] = r - op.buf[o+1] = r - op.buf[o+2] = r - o += 3 - } - } - write_ptr(fd, raw_data(op.buf), len(op.buf)) - } else if channels == 2 { - if depth == 16 { - p16 := mem.slice_data_cast([]u16, pix) - o16 := mem.slice_data_cast([]u16, op.buf[:]) - - bgcol := img.background - - #no_bounds_check for len(p16) != 0 { - r := f64(u16(p16[0])) - bg: f64 - if bgcol != nil { - v := bgcol.([3]u16)[0] - bg = f64(v) - } - a := f64(u16(p16[1])) / 65535.0 - l := (a * r) + (1 - a) * bg - - o16[0] = u16(l) - o16[1] = u16(l) - o16[2] = u16(l) - - p16 = p16[2:] - o16 = o16[3:] - } - } else { - o := 0 - for i := 0; i < len(pix); i += 2 { - r := pix[i]; a := pix[i+1]; a1 := f32(a) / 255.0 - c := u8(f32(r) * a1) - op.buf[o ] = c - op.buf[o+1] = c - op.buf[o+2] = c - o += 3 - } - } - write_ptr(fd, raw_data(op.buf), len(op.buf)) - } else if channels == 4 { - if depth == 16 { - p16 := mem.slice_data_cast([]u16be, pix) - o16 := mem.slice_data_cast([]u16be, op.buf[:]) - - #no_bounds_check for len(p16) != 0 { - - bg := _bg(img.background, 0, 0) - r := f32(p16[0]) - g := f32(p16[1]) - b := f32(p16[2]) - a := f32(p16[3]) / 65535.0 - - lr := (a * r) + (1 - a) * f32(bg[0]) - lg := (a * g) + (1 - a) * f32(bg[1]) - lb := (a * b) + (1 - a) * f32(bg[2]) - - o16[0] = u16be(lr) - o16[1] = u16be(lg) - o16[2] = u16be(lb) - - p16 = p16[4:] - o16 = o16[3:] - } - } else { - o := 0 - - for i := 0; i < len(pix); i += 4 { - - x := (i / 4) % width - y := i / width / 4 - - _b := _bg(img.background, x, y, false) - bgcol := [3]u8{u8(_b[0]), u8(_b[1]), u8(_b[2])} - - r := f32(pix[i]) - g := f32(pix[i+1]) - b := f32(pix[i+2]) - a := f32(pix[i+3]) / 255.0 - - lr := u8(f32(r) * a + (1 - a) * f32(bgcol[0])) - lg := u8(f32(g) * a + (1 - a) * f32(bgcol[1])) - lb := u8(f32(b) * a + (1 - a) * f32(bgcol[2])) - op.buf[o ] = lr - op.buf[o+1] = lg - op.buf[o+2] = lb - o += 3 - } - } - write_ptr(fd, raw_data(op.buf), len(op.buf)) - } else { - return false - } - } - return true - } -*/ -package png diff --git a/core/image/png/example.odin b/core/image/png/example.odin new file mode 100644 index 000000000..cab6e4de1 --- /dev/null +++ b/core/image/png/example.odin @@ -0,0 +1,136 @@ +#+build ignore +package png_example + +import "core:image" +import "core:image/png" +import "core:image/tga" +import "core:fmt" +import "core:mem" + +demo :: proc() { + options := image.Options{.return_metadata} + err: image.Error + img: ^image.Image + + PNG_FILE :: ODIN_ROOT + "misc/logo-slim.png" + + img, err = png.load(PNG_FILE, options) + defer png.destroy(img) + + if err != nil { + fmt.eprintfln("Trying to read PNG file %v returned %v.", PNG_FILE, err) + } else { + fmt.printfln("Image: %vx%vx%v, %v-bit.", img.width, img.height, img.channels, img.depth) + + if v, ok := img.metadata.(^image.PNG_Info); ok { + // Handle ancillary chunks as you wish. + // We provide helper functions for a few types. + for c in v.chunks { + #partial switch c.header.type { + case .tIME: + if t, t_ok := png.core_time(c); t_ok { + fmt.printfln("[tIME]: %v", t) + } + case .gAMA: + if gama, gama_ok := png.gamma(c); gama_ok { + fmt.printfln("[gAMA]: %v", gama) + } + case .pHYs: + if phys, phys_ok := png.phys(c); phys_ok { + if phys.unit == .Meter { + xm := f32(img.width) / f32(phys.ppu_x) + ym := f32(img.height) / f32(phys.ppu_y) + dpi_x, dpi_y := png.phys_to_dpi(phys) + fmt.printfln("[pHYs] Image resolution is %v x %v pixels per meter.", phys.ppu_x, phys.ppu_y) + fmt.printfln("[pHYs] Image resolution is %v x %v DPI.", dpi_x, dpi_y) + fmt.printfln("[pHYs] Image dimensions are %v x %v meters.", xm, ym) + } else { + fmt.printfln("[pHYs] x: %v, y: %v pixels per unknown unit.", phys.ppu_x, phys.ppu_y) + } + } + case .iTXt, .zTXt, .tEXt: + res, ok_text := png.text(c) + if ok_text { + if c.header.type == .iTXt { + fmt.printfln("[iTXt] %v (%v:%v): %v", res.keyword, res.language, res.keyword_localized, res.text) + } else { + fmt.printfln("[tEXt/zTXt] %v: %v", res.keyword, res.text) + } + } + defer png.text_destroy(res) + case .bKGD: + fmt.printfln("[bKGD] %v", img.background) + case .eXIf: + if res, ok_exif := png.exif(c); ok_exif { + /* + Other than checking the signature and byte order, we don't handle Exif data. + If you wish to interpret it, pass it to an Exif parser. + */ + fmt.printfln("[eXIf] %v", res) + } + case .PLTE: + if plte, plte_ok := png.plte(c); plte_ok { + fmt.printfln("[PLTE] %v", plte) + } else { + fmt.printfln("[PLTE] Error") + } + case .hIST: + if res, ok_hist := png.hist(c); ok_hist { + fmt.printfln("[hIST] %v", res) + } + case .cHRM: + if res, ok_chrm := png.chrm(c); ok_chrm { + fmt.printfln("[cHRM] %v", res) + } + case .sPLT: + res, ok_splt := png.splt(c) + if ok_splt { + fmt.printfln("[sPLT] %v", res) + } + png.splt_destroy(res) + case .sBIT: + if res, ok_sbit := png.sbit(c); ok_sbit { + fmt.printfln("[sBIT] %v", res) + } + case .iCCP: + res, ok_iccp := png.iccp(c) + if ok_iccp { + fmt.printfln("[iCCP] %v", res) + } + png.iccp_destroy(res) + case .sRGB: + if res, ok_srgb := png.srgb(c); ok_srgb { + fmt.printfln("[sRGB] Rendering intent: %v", res) + } + case: + type := c.header.type + name := png.chunk_type_to_name(&type) + fmt.printfln("[%v]: %v", name, c.data) + } + } + } + } + + fmt.printfln("Done parsing metadata.") + + if err == nil && .do_not_decompress_image not_in options && .info not_in options { + if err = tga.save("out.tga", img); err == nil { + fmt.println("Saved decoded image.") + } else { + fmt.eprintfln("Error %v saving out.ppm.", err) + } + } +} + +main :: proc() { + track: mem.Tracking_Allocator + mem.tracking_allocator_init(&track, context.allocator) + defer mem.tracking_allocator_destroy(&track) + context.allocator = mem.tracking_allocator(&track) + + demo() + + for _, leak in track.allocation_map { + fmt.printf("%v leaked %m", leak.location, leak.size) + } +} \ No newline at end of file diff --git a/core/image/png/png.odin b/core/image/png/png.odin index 1a7240bad..5a0913cff 100644 --- a/core/image/png/png.odin +++ b/core/image/png/png.odin @@ -1,4 +1,6 @@ -#+vet !using-stmt +#+feature using-stmt +// Reader for `PNG` images. +// The PNG specification is at [[ https://www.w3.org/TR/PNG/ ]]. package png /* diff --git a/core/image/png/png_os.odin b/core/image/png/png_os.odin index 8e0706206..5fc10cec4 100644 --- a/core/image/png/png_os.odin +++ b/core/image/png/png_os.odin @@ -8,12 +8,12 @@ load :: proc{load_from_file, load_from_bytes, load_from_context} load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) { context.allocator = allocator - data, ok := os.read_entire_file(filename) - defer delete(data) + data, data_err := os.read_entire_file(filename, allocator) + defer delete(data, allocator) - if ok { + if data_err == nil { return load_from_bytes(data, options) } else { return nil, .Unable_To_Read_File } -} +} \ No newline at end of file diff --git a/core/image/qoi/qoi_os.odin b/core/image/qoi/qoi_os.odin index c85fdd839..f2bf83cfc 100644 --- a/core/image/qoi/qoi_os.odin +++ b/core/image/qoi/qoi_os.odin @@ -4,8 +4,22 @@ package qoi import "core:os" import "core:bytes" -save :: proc{save_to_buffer, save_to_file} +load :: proc{load_from_file, load_from_bytes, load_from_context} +load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) { + context.allocator = allocator + + data, data_err := os.read_entire_file(filename, allocator) + defer delete(data, allocator) + + if data_err == nil { + return load_from_bytes(data, options) + } else { + return nil, .Unable_To_Read_File + } +} + +save :: proc{save_to_buffer, save_to_file} save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocator := context.allocator) -> (err: Error) { context.allocator = allocator @@ -14,24 +28,7 @@ save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocato defer bytes.buffer_destroy(out) save_to_buffer(out, img, options) or_return - write_ok := os.write_entire_file(output, out.buf[:]) + write_err := os.write_entire_file(output, out.buf[:]) - return nil if write_ok else .Unable_To_Write_File -} - - -load :: proc{load_from_file, load_from_bytes, load_from_context} - - -load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) { - context.allocator = allocator - - data, ok := os.read_entire_file(filename) - defer delete(data) - - if ok { - return load_from_bytes(data, options) - } else { - return nil, .Unable_To_Read_File - } + return nil if write_err == nil else .Unable_To_Write_File } \ No newline at end of file diff --git a/core/image/tga/tga.odin b/core/image/tga/tga.odin index 260720bb4..1941b53f9 100644 --- a/core/image/tga/tga.odin +++ b/core/image/tga/tga.odin @@ -152,7 +152,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a // Intentionally blank case .Uncompressed_Black_White: black_white = true - dest_depth = 24 + dest_depth = 8 if .do_not_expand_grayscale in options else 24 case .Uncompressed_Color_Mapped: color_mapped = true case .Compressed_Color_Mapped: @@ -161,7 +161,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a case .Compressed_Black_White: black_white = true rle_encoding = true - dest_depth = 24 + dest_depth = 8 if .do_not_expand_grayscale in options else 24 case: return nil, .Unsupported_Format @@ -180,6 +180,9 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a } switch dest_depth { + case 8: // R8 + src_channels = 1 + dest_channels = 1 case 15: // B5G5R5 src_channels = 2 dest_channels = 3 diff --git a/core/image/tga/tga_os.odin b/core/image/tga/tga_os.odin index a78998105..ba50439de 100644 --- a/core/image/tga/tga_os.odin +++ b/core/image/tga/tga_os.odin @@ -4,6 +4,21 @@ package tga import "core:os" import "core:bytes" +load :: proc{load_from_file, load_from_bytes, load_from_context} + +load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) { + context.allocator = allocator + + data, data_err := os.read_entire_file(filename, allocator) + defer delete(data) + + if data_err == nil { + return load_from_bytes(data, options) + } else { + return nil, .Unable_To_Read_File + } +} + save :: proc{save_to_buffer, save_to_file} save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocator := context.allocator) -> (err: Error) { @@ -13,22 +28,7 @@ save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocato defer bytes.buffer_destroy(out) save_to_buffer(out, img, options) or_return - write_ok := os.write_entire_file(output, out.buf[:]) + write_err := os.write_entire_file(output, out.buf[:]) - return nil if write_ok else .Unable_To_Write_File -} - -load :: proc{load_from_file, load_from_bytes, load_from_context} - -load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) { - context.allocator = allocator - - data, ok := os.read_entire_file(filename) - defer delete(data) - - if ok { - return load_from_bytes(data, options) - } else { - return nil, .Unable_To_Read_File - } + return nil if write_err == nil else .Unable_To_Write_File } \ No newline at end of file diff --git a/core/io/io.odin b/core/io/io.odin index 9fae30946..631a232aa 100644 --- a/core/io/io.odin +++ b/core/io/io.odin @@ -436,7 +436,7 @@ copy_buffer :: proc(dst: Writer, src: Reader, buf: []byte) -> (written: i64, err // copy_n copies n bytes (or till an error) from src to dst. // It returns the number of bytes copied and the first error that occurred whilst copying, if any. -// On return, written == n IFF err == nil +// On return, written == n if and only if (⟺) err == nil copy_n :: proc(dst: Writer, src: Reader, n: i64) -> (written: i64, err: Error) { nsrc := limited_reader_init(&Limited_Reader{}, src, n) written, err = copy(dst, nsrc) diff --git a/core/io/util.odin b/core/io/util.odin index 86a89cfb1..c6ad8f525 100644 --- a/core/io/util.odin +++ b/core/io/util.odin @@ -8,6 +8,11 @@ read_ptr :: proc(r: Reader, p: rawptr, byte_size: int, n_read: ^int = nil) -> (n return read(r, ([^]byte)(p)[:byte_size], n_read) } +read_slice :: proc(r: Reader, slice: $S/[]$T, n_read: ^int = nil) -> (n: int, err: Error) { + size := len(slice)*size_of(T) + return read_ptr(w, raw_data(slice), size, n_read) +} + write_ptr :: proc(w: Writer, p: rawptr, byte_size: int, n_written: ^int = nil) -> (n: int, err: Error) { return write(w, ([^]byte)(p)[:byte_size], n_written) } @@ -20,13 +25,19 @@ write_ptr_at :: proc(w: Writer_At, p: rawptr, byte_size: int, offset: i64, n_wri return write_at(w, ([^]byte)(p)[:byte_size], offset, n_written) } +write_slice :: proc(w: Writer, slice: $S/[]$T, n_written: ^int = nil) -> (n: int, err: Error) { + size := len(slice)*size_of(T) + return write_ptr(w, raw_data(slice), size, n_written) +} + + write_u64 :: proc(w: Writer, i: u64, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { - buf: [32]byte + buf: [64]byte s := strconv.write_bits(buf[:], i, base, false, 64, strconv.digits, nil) return write_string(w, s, n_written) } write_i64 :: proc(w: Writer, i: i64, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { - buf: [32]byte + buf: [65]byte s := strconv.write_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil) return write_string(w, s, n_written) } @@ -39,12 +50,12 @@ write_int :: proc(w: Writer, i: int, base: int = 10, n_written: ^int = nil) -> ( } write_u128 :: proc(w: Writer, i: u128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { - buf: [39]byte + buf: [128]byte s := strconv.write_bits_128(buf[:], i, base, false, 128, strconv.digits, nil) return write_string(w, s, n_written) } write_i128 :: proc(w: Writer, i: i128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { - buf: [40]byte + buf: [129]byte s := strconv.write_bits_128(buf[:], u128(i), base, true, 128, strconv.digits, nil) return write_string(w, s, n_written) } diff --git a/core/log/console_logger_js.odin b/core/log/console_logger_js.odin new file mode 100644 index 000000000..1e07b6cdc --- /dev/null +++ b/core/log/console_logger_js.odin @@ -0,0 +1,119 @@ +#+build js +package log + +import "core:fmt" +import "core:strings" +import "core:time" + +Level_Headers := [?]string{ + 0..<10 = "[DEBUG] --- ", + 10..<20 = "[INFO ] --- ", + 20..<30 = "[WARN ] --- ", + 30..<40 = "[ERROR] --- ", + 40..<50 = "[FATAL] --- ", +} + +Default_Console_Logger_Opts :: Options{ + .Level, + .Short_File_Path, + .Line, + .Procedure, +} | Full_Timestamp_Opts + +Console_Logger_Data :: struct { + ident: string, +} + +create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logger_Opts, ident := "", allocator := context.allocator) -> Logger { + data := new(Console_Logger_Data, allocator) + data.ident = strings.clone(ident) + return Logger{console_logger_proc, data, lowest, opt} +} + +destroy_console_logger :: proc(log: Logger, allocator := context.allocator) { + data := cast(^Console_Logger_Data)log.data + delete(data.ident) + free(log.data, allocator) +} + +console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) { + options := options + data := cast(^Console_Logger_Data)logger_data + + backing: [1024]byte //NOTE(Hoej): 1024 might be too much for a header backing, unless somebody has really long paths. + buf := strings.builder_from_bytes(backing[:]) + + if .Level in options { + fmt.sbprint(&buf, Level_Headers[level]) + } + + when time.IS_SUPPORTED { + do_time_header(options, &buf, time.now()) + } + + do_location_header(options, &buf, location) + + if data.ident != "" { + fmt.sbprintf(&buf, "[%s] ", data.ident) + } + + h := fmt.stderr if level >= .Error else fmt.stdout + + //TODO(Hoej): When we have better atomics and such, make this thread-safe + fmt.fprintf(h, "%s%s\n", strings.to_string(buf), text) +} + +do_time_header :: proc(opts: Options, buf: ^strings.Builder, t: time.Time) { + when time.IS_SUPPORTED { + if Full_Timestamp_Opts & opts != nil { + fmt.sbprint(buf, "[") + y, m, d := time.date(t) + h, min, s := time.clock(t) + if .Date in opts { + fmt.sbprintf(buf, "%d-%02d-%02d", y, m, d) + if .Time in opts { + fmt.sbprint(buf, " ") + } + } + if .Time in opts { fmt.sbprintf(buf, "%02d:%02d:%02d", h, min, s) } + fmt.sbprint(buf, "] ") + } + } +} + +do_location_header :: proc(opts: Options, buf: ^strings.Builder, location := #caller_location) { + if Location_Header_Opts & opts == nil { + return + } + fmt.sbprint(buf, "[") + + file := location.file_path + if .Short_File_Path in opts { + last := 0 + for r, i in location.file_path { + if r == '/' { + last = i+1 + } + } + file = location.file_path[last:] + } + + if Location_File_Opts & opts != nil { + fmt.sbprint(buf, file) + } + if .Line in opts { + if Location_File_Opts & opts != nil { + fmt.sbprint(buf, ":") + } + fmt.sbprint(buf, location.line) + } + + if .Procedure in opts { + if (Location_File_Opts | {.Line}) & opts != nil { + fmt.sbprint(buf, ":") + } + fmt.sbprintf(buf, "%s()", location.procedure) + } + + fmt.sbprint(buf, "] ") +} \ No newline at end of file diff --git a/core/log/file_console_logger.odin b/core/log/file_console_logger.odin index f0acc8a22..47174719f 100644 --- a/core/log/file_console_logger.odin +++ b/core/log/file_console_logger.odin @@ -1,5 +1,6 @@ #+build !freestanding #+build !orca +#+build !js package log import "base:runtime" @@ -35,7 +36,7 @@ Default_File_Logger_Opts :: Options{ File_Console_Logger_Data :: struct { - file_handle: os.Handle, + file_handle: ^os.File, ident: string, } @@ -66,16 +67,16 @@ init_standard_stream_status :: proc "contextless" () { } } -create_file_logger :: proc(h: os.Handle, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "", allocator := context.allocator) -> Logger { +create_file_logger :: proc(f: ^os.File, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "", allocator := context.allocator) -> Logger { data := new(File_Console_Logger_Data, allocator) - data.file_handle = h + data.file_handle = f data.ident = ident return Logger{file_logger_proc, data, lowest, opt} } destroy_file_logger :: proc(log: Logger, allocator := context.allocator) { data := cast(^File_Console_Logger_Data)log.data - if data.file_handle != os.INVALID_HANDLE { + if data.file_handle != nil { os.close(data.file_handle) } free(data, allocator) @@ -83,7 +84,7 @@ destroy_file_logger :: proc(log: Logger, allocator := context.allocator) { create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logger_Opts, ident := "", allocator := context.allocator) -> Logger { data := new(File_Console_Logger_Data, allocator) - data.file_handle = os.INVALID_HANDLE + data.file_handle = nil data.ident = ident return Logger{console_logger_proc, data, lowest, opt} } @@ -93,7 +94,7 @@ destroy_console_logger :: proc(log: Logger, allocator := context.allocator) { } @(private) -_file_console_logger_proc :: proc(h: os.Handle, ident: string, level: Level, text: string, options: Options, location: runtime.Source_Code_Location) { +_file_console_logger_proc :: proc(h: ^os.File, ident: string, level: Level, text: string, options: Options, location: runtime.Source_Code_Location) { backing: [1024]byte //NOTE(Hoej): 1024 might be too much for a header backing, unless somebody has really long paths. buf := strings.builder_from_bytes(backing[:]) @@ -106,9 +107,7 @@ _file_console_logger_proc :: proc(h: os.Handle, ident: string, level: Level, tex do_location_header(options, &buf, location) if .Thread_Id in options { - // NOTE(Oskar): not using context.thread_id here since that could be - // incorrect when replacing context for a thread. - fmt.sbprintf(&buf, "[{}] ", os.current_thread_id()) + fmt.sbprintf(&buf, "[{}] ", os.get_current_thread_id()) } if ident != "" { @@ -126,7 +125,7 @@ file_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, option console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) { options := options data := cast(^File_Console_Logger_Data)logger_data - h: os.Handle = --- + h: ^os.File = nil if level < Level.Error { h = os.stdout options -= global_subtract_stdout_options @@ -216,4 +215,4 @@ do_location_header :: proc(opts: Options, buf: ^strings.Builder, location := #ca } fmt.sbprint(buf, "] ") -} +} \ No newline at end of file diff --git a/core/math/big/common.odin b/core/math/big/common.odin index 944d1cfa1..acf32749e 100644 --- a/core/math/big/common.odin +++ b/core/math/big/common.odin @@ -14,21 +14,10 @@ import "base:runtime" This allows to benchmark and/or setting optimized values for a certain CPU without recompiling. */ -/* - There is a bug with DLL globals. They don't get set. - To allow tests to run we add `-define:MATH_BIG_EXE=false` to hardcode the cutoffs for now. -*/ -when #config(MATH_BIG_EXE, true) { - MUL_KARATSUBA_CUTOFF := _DEFAULT_MUL_KARATSUBA_CUTOFF - SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF - MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF - SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF -} else { - MUL_KARATSUBA_CUTOFF := _DEFAULT_MUL_KARATSUBA_CUTOFF - SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF - MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF - SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF -} +MUL_KARATSUBA_CUTOFF := _DEFAULT_MUL_KARATSUBA_CUTOFF +SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF +MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF +SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF /* These defaults were tuned on an AMD A8-6600K (64-bit) using libTomMath's `make tune`. @@ -38,9 +27,6 @@ when #config(MATH_BIG_EXE, true) { It would also be cool if we collected some data across various processor families. This would let uss set reasonable defaults at runtime as this library initializes itself by using `cpuid` or the ARM equivalent. - - IMPORTANT: The 32_BIT path has largely gone untested. It needs to be tested and - debugged where necessary. */ _DEFAULT_MUL_KARATSUBA_CUTOFF :: #config(MATH_BIG_MUL_KARATSUBA_CUTOFF, 80) @@ -54,7 +40,7 @@ MAX_ITERATIONS_ROOT_N := 500 /* Largest `N` for which we'll compute `N!` */ -FACTORIAL_MAX_N := 1_000_000 +FACTORIAL_MAX_N := 1_000_000 /* Cutoff to switch to int_factorial_binary_split, and its max recursion level. @@ -86,22 +72,10 @@ MAX_ITERATIONS_RANDOM_PRIME := 1_000_000 */ @thread_local RANDOM_PRIME_ITERATIONS_USED: int -/* - We don't allow these to be switched at runtime for two reasons: - - 1) 32-bit and 64-bit versions of procedures use different types for their storage, - so we'd have to double the number of procedures, and they couldn't interact. - - 2) Optimizations thanks to precomputed masks wouldn't work. -*/ -MATH_BIG_FORCE_64_BIT :: #config(MATH_BIG_FORCE_64_BIT, false) -MATH_BIG_FORCE_32_BIT :: #config(MATH_BIG_FORCE_32_BIT, false) -when (MATH_BIG_FORCE_32_BIT && MATH_BIG_FORCE_64_BIT) { #panic("Cannot force 32-bit and 64-bit big backend simultaneously.") } - /* Trade a smaller memory footprint for more processing overhead? */ -_LOW_MEMORY :: #config(MATH_BIG_SMALL_MEMORY, false) +_LOW_MEMORY :: #config(MATH_BIG_SMALL_MEMORY, false) when _LOW_MEMORY { _DEFAULT_DIGIT_COUNT :: 8 _TAB_SIZE :: 32 @@ -217,28 +191,19 @@ _MIN_DIGIT_COUNT :: max(3, ((size_of(u128) + _DIGIT_BITS) - 1) / _DIGIT_BITS) _MAX_BIT_COUNT :: (max(int) - 2) _MAX_DIGIT_COUNT :: _MAX_BIT_COUNT / _DIGIT_BITS -when MATH_BIG_FORCE_64_BIT || (!MATH_BIG_FORCE_32_BIT && size_of(rawptr) == 8) { - /* - We can use u128 as an intermediary. - */ - DIGIT :: distinct u64 - _WORD :: distinct u128 - // Base 10 extraction constants - ITOA_DIVISOR :: DIGIT(1_000_000_000_000_000_000) - ITOA_COUNT :: 18 -} else { - DIGIT :: distinct u32 - _WORD :: distinct u64 - // Base 10 extraction constants - ITOA_DIVISOR :: DIGIT(100_000_000) - ITOA_COUNT :: 8 -} +// We use u128 as an intermediary. +DIGIT :: distinct u64 +_WORD :: distinct u128 + +// Base 10 extraction constants +ITOA_DIVISOR :: DIGIT(1_000_000_000_000_000_000) +ITOA_COUNT :: 18 #assert(size_of(_WORD) == 2 * size_of(DIGIT)) _DIGIT_TYPE_BITS :: 8 * size_of(DIGIT) _WORD_TYPE_BITS :: 8 * size_of(_WORD) -_DIGIT_NAILS :: 4 +_DIGIT_NAILS :: 1 _DIGIT_BITS :: _DIGIT_TYPE_BITS - _DIGIT_NAILS _WORD_BITS :: 2 * _DIGIT_BITS diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index b922881b4..21a5bdc35 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -7,7 +7,6 @@ package math_big import "base:intrinsics" import "base:runtime" -import rnd "core:math/rand" /* TODO: Int.flags and Constants like ONE, NAN, etc, are not yet properly handled everywhere. @@ -362,17 +361,7 @@ platform_count_lsb :: #force_inline proc(a: $T) -> (count: int) count_lsb :: proc { int_count_lsb, platform_count_lsb, } -int_random_digit :: proc() -> (res: DIGIT) { - when _DIGIT_BITS == 60 { // DIGIT = u64 - return DIGIT(rnd.uint64()) & _MASK - } else when _DIGIT_BITS == 28 { // DIGIT = u32 - return DIGIT(rnd.uint32()) & _MASK - } else { - panic("Unsupported DIGIT size.") - } - - return 0 // We shouldn't get here. -} +int_random_digit :: internal_int_random_digit int_random :: proc(dest: ^Int, bits: int, allocator := context.allocator) -> (err: Error) { /* diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index 333fee3ad..e2bfa8f50 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -29,8 +29,8 @@ package math_big import "base:builtin" import "base:intrinsics" -import "core:mem" -import rnd "core:math/rand" +import "base:runtime" +@(require) import rnd "core:math/rand" /* Low-level addition, unsigned. Handbook of Applied Cryptography, algorithm 14.7. @@ -989,7 +989,8 @@ internal_int_mod_bits :: proc(remainder, numerator: ^Int, bits: int, allocator : Zero remainder. Special case, can't use `internal_zero_unused`. */ if zero_count > 0 { - mem.zero_slice(remainder.digit[zero_count:]) + data := remainder.digit[zero_count:] + _zero(data) } /* @@ -1015,7 +1016,7 @@ internal_int_mod_bits :: proc(remainder, numerator: ^Int, bits: int, allocator : Assumes `a` not to be `nil`. */ internal_int_allocated_cap :: #force_inline proc(a: ^Int) -> (cap: int) { - raw := transmute(mem.Raw_Dynamic_Array)a.digit + raw := transmute(runtime.Raw_Dynamic_Array)a.digit return raw.cap } @@ -1177,6 +1178,8 @@ internal_cmp_digit :: internal_compare_digit */ internal_int_compare_magnitude :: #force_inline proc(a, b: ^Int) -> (comparison: int) { assert_if_nil(a, b) + internal_clamp(a) + internal_clamp(b) // Compare based on used digits. if a.used != b.used { @@ -1449,6 +1452,7 @@ internal_int_log :: proc(a: ^Int, base: DIGIT) -> (res: int, err: Error) { /* Fast path for `Int`s that fit within a single `DIGIT`. */ + internal_clamp(a) if a.used == 1 { return internal_log(a.digit[0], DIGIT(base)) } return _private_int_log(a, base) @@ -1684,7 +1688,7 @@ internal_int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.alloca */ if n == 2 { return #force_inline internal_sqrt(dest, src) } - if n < 0 || n > int(_DIGIT_MAX) { return .Invalid_Argument } + if n < 0 || _WORD(n) > _WORD(_DIGIT_MAX) { return .Invalid_Argument } if n & 1 == 0 && #force_inline internal_is_negative(src) { return .Invalid_Argument } @@ -1845,7 +1849,7 @@ internal_int_destroy :: proc(integers: ..^Int) { for &a in integers { if internal_int_allocated_cap(a) > 0 { - mem.zero_slice(a.digit[:]) + _zero(a.digit[:]) free(&a.digit[0]) } a = &Int{} @@ -2177,7 +2181,7 @@ internal_int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator If not yet initialized, initialize the `digit` backing with the allocator we were passed. */ if cap == 0 { - mem_err: mem.Allocator_Error + mem_err: runtime.Allocator_Error a.digit, mem_err = make([dynamic]DIGIT, needed, allocator) if mem_err != nil { return cast(Error)mem_err @@ -2208,9 +2212,9 @@ internal_grow :: proc { internal_int_grow, } Assumes `a` not to be `nil`. */ internal_int_clear :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) { - raw := transmute(mem.Raw_Dynamic_Array)a.digit + raw := transmute(runtime.Raw_Dynamic_Array)a.digit if raw.cap != 0 { - mem.zero_slice(a.digit[:a.used]) + _zero(a.digit[:a.used]) } a.sign = .Zero_or_Positive a.used = 0 @@ -2273,7 +2277,7 @@ internal_int_power_of_two :: proc(a: ^Int, power: int, allocator := context.allo /* Zero the entirety. */ - mem.zero_slice(a.digit[:]) + _zero(a.digit[:]) /* Set the bit. @@ -2819,9 +2823,9 @@ internal_platform_count_lsb :: #force_inline proc(a: $T) -> (count: int) internal_count_lsb :: proc { internal_int_count_lsb, internal_platform_count_lsb, } internal_int_random_digit :: proc() -> (res: DIGIT) { - when _DIGIT_BITS == 60 { // DIGIT = u64 + when _DIGIT_TYPE_BITS == 64 { // DIGIT = u64 return DIGIT(rnd.uint64()) & _MASK - } else when _DIGIT_BITS == 28 { // DIGIT = u32 + } else when _DIGIT_TYPE_BITS == 32 { // DIGIT = u32 return DIGIT(rnd.uint32()) & _MASK } else { panic("Unsupported DIGIT size.") @@ -2944,11 +2948,15 @@ internal_int_zero_unused :: #force_inline proc(dest: ^Int, old_used := -1) { Zero remainder. */ if zero_count > 0 && dest.used < len(dest.digit) { - mem.zero_slice(dest.digit[dest.used:][:zero_count]) + _zero(dest.digit[dest.used:][:zero_count]) } } internal_zero_unused :: proc { internal_int_zero_unused, } +_zero :: proc(data: []DIGIT) { + intrinsics.mem_zero(raw_data(data), size_of(DIGIT)*len(data)) +} + /* ========================== End of low-level routines ========================== */ diff --git a/core/math/big/prime.odin b/core/math/big/prime.odin index 1c772143b..7fa6d8e4a 100644 --- a/core/math/big/prime.odin +++ b/core/math/big/prime.odin @@ -101,7 +101,7 @@ internal_int_power_modulo :: proc(res, G, X, P: ^Int, allocator := context.alloc If the modulus is odd or dr != 0 use the montgomery method. */ if internal_int_is_odd(P) || dr != 0 { - return _private_int_exponent_mod(res, G, X, P, dr) + return _private_int_exponent_mod_fast(res, G, X, P, dr) } /* diff --git a/core/math/big/private.odin b/core/math/big/private.odin index caed8c8b9..1ca706c6d 100644 --- a/core/math/big/private.odin +++ b/core/math/big/private.odin @@ -19,7 +19,6 @@ package math_big */ import "base:intrinsics" -import "core:mem" /* Multiplies |a| * |b| and only computes upto digs digits of result. @@ -440,8 +439,14 @@ _private_int_mul_high :: proc(dest, a, b: ^Int, digits: int, allocator := contex return _private_int_mul_high_comba(dest, a, b, digits) } - internal_grow(dest, a.used + b.used + 1) or_return - dest.used = a.used + b.used + 1 + /* + Set up temporary output `Int`, which we'll swap for `dest` when done. + */ + + t := &Int{} + + internal_grow(t, a.used + b.used + 1) or_return + t.used = a.used + b.used + 1 pa := a.used pb := b.used @@ -452,20 +457,23 @@ _private_int_mul_high :: proc(dest, a, b: ^Int, digits: int, allocator := contex /* Calculate the double precision result. */ - r := _WORD(dest.digit[ix + iy]) + _WORD(a.digit[ix]) * _WORD(b.digit[iy]) + _WORD(carry) + r := _WORD(t.digit[ix + iy]) + _WORD(a.digit[ix]) * _WORD(b.digit[iy]) + _WORD(carry) /* Get the lower part. */ - dest.digit[ix + iy] = DIGIT(r & _WORD(_MASK)) + t.digit[ix + iy] = DIGIT(r & _WORD(_MASK)) /* Carry the carry. */ carry = DIGIT(r >> _WORD(_DIGIT_BITS)) } - dest.digit[ix + pb] = carry + t.digit[ix + pb] = carry } + + internal_swap(dest, t) + internal_destroy(t) return internal_clamp(dest) } @@ -817,7 +825,7 @@ _private_int_sqr_karatsuba :: proc(dest, src: ^Int, allocator := context.allocat x1.used = src.used - B #force_inline internal_copy_digits(x0, src, x0.used) - #force_inline mem.copy_non_overlapping(&x1.digit[0], &src.digit[B], size_of(DIGIT) * x1.used) + intrinsics.mem_copy_non_overlapping(&x1.digit[0], &src.digit[B], size_of(DIGIT) * x1.used) #force_inline internal_clamp(x0) /* @@ -882,9 +890,9 @@ _private_int_sqr_toom :: proc(dest, src: ^Int, allocator := context.allocator) - a1.used = B a2.used = src.used - 2 * B - #force_inline mem.copy_non_overlapping(&a0.digit[0], &src.digit[ 0], size_of(DIGIT) * a0.used) - #force_inline mem.copy_non_overlapping(&a1.digit[0], &src.digit[ B], size_of(DIGIT) * a1.used) - #force_inline mem.copy_non_overlapping(&a2.digit[0], &src.digit[2 * B], size_of(DIGIT) * a2.used) + intrinsics.mem_copy_non_overlapping(&a0.digit[0], &src.digit[ 0], size_of(DIGIT) * a0.used) + intrinsics.mem_copy_non_overlapping(&a1.digit[0], &src.digit[ B], size_of(DIGIT) * a1.used) + intrinsics.mem_copy_non_overlapping(&a2.digit[0], &src.digit[2 * B], size_of(DIGIT) * a2.used) internal_clamp(a0) internal_clamp(a1) @@ -2340,7 +2348,7 @@ _private_int_dr_reduce :: proc(x, n: ^Int, k: DIGIT, allocator := context.alloca /* Zero words above m. */ - mem.zero_slice(x.digit[m + 1:][:x.used - m]) + _zero(x.digit[m + 1:][:x.used - m]) /* Clamp, sub and return. @@ -3137,7 +3145,7 @@ _private_copy_digits :: proc(dest, src: ^Int, digits: int, offset := int(0)) -> } digits = min(digits, len(src.digit), len(dest.digit)) - mem.copy_non_overlapping(&dest.digit[0], &src.digit[offset], size_of(DIGIT) * digits) + intrinsics.mem_copy_non_overlapping(&dest.digit[0], &src.digit[offset], size_of(DIGIT) * digits) return nil } @@ -3175,7 +3183,7 @@ _private_int_shl_leg :: proc(quotient: ^Int, digits: int, allocator := context.a } quotient.used += digits - mem.zero_slice(quotient.digit[:digits]) + _zero(quotient.digit[:digits]) return nil } @@ -3283,9 +3291,8 @@ _private_prime_table := [_PRIME_TAB_SIZE]DIGIT{ } #assert(_PRIME_TAB_SIZE * size_of(DIGIT) == size_of(_private_prime_table)) -when MATH_BIG_FORCE_64_BIT || (!MATH_BIG_FORCE_32_BIT && size_of(rawptr) == 8) { - @(rodata) - _factorial_table := [35]_WORD{ +@(rodata) +_factorial_table := [35]_WORD{ /* f(00): */ 1, /* f(01): */ 1, /* f(02): */ 2, @@ -3321,34 +3328,9 @@ when MATH_BIG_FORCE_64_BIT || (!MATH_BIG_FORCE_32_BIT && size_of(rawptr) == 8) { /* f(32): */ 263_130_836_933_693_530_167_218_012_160_000_000, /* f(33): */ 8_683_317_618_811_886_495_518_194_401_280_000_000, /* f(34): */ 295_232_799_039_604_140_847_618_609_643_520_000_000, - } -} else { - @(rodata) - _factorial_table := [21]_WORD{ -/* f(00): */ 1, -/* f(01): */ 1, -/* f(02): */ 2, -/* f(03): */ 6, -/* f(04): */ 24, -/* f(05): */ 120, -/* f(06): */ 720, -/* f(07): */ 5_040, -/* f(08): */ 40_320, -/* f(09): */ 362_880, -/* f(10): */ 3_628_800, -/* f(11): */ 39_916_800, -/* f(12): */ 479_001_600, -/* f(13): */ 6_227_020_800, -/* f(14): */ 87_178_291_200, -/* f(15): */ 1_307_674_368_000, -/* f(16): */ 20_922_789_888_000, -/* f(17): */ 355_687_428_096_000, -/* f(18): */ 6_402_373_705_728_000, -/* f(19): */ 121_645_100_408_832_000, -/* f(20): */ 2_432_902_008_176_640_000, - } } + /* ========================= End of private tables ======================== */ \ No newline at end of file diff --git a/core/math/big/radix.odin b/core/math/big/radix.odin index 9c87440fc..1a80fdf88 100644 --- a/core/math/big/radix.odin +++ b/core/math/big/radix.odin @@ -16,8 +16,6 @@ package math_big */ import "base:intrinsics" -import "core:mem" -import "core:os" /* This version of `itoa` allocates on behalf of the caller. The caller must free the string. @@ -144,7 +142,7 @@ int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_ter written = len(buffer) - available if written < size { diff := size - written - mem.copy(&buffer[0], &buffer[diff], written) + intrinsics.mem_copy(&buffer[0], &buffer[diff], written) } return written, nil } @@ -177,7 +175,7 @@ int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_ter written = len(buffer) - available if written < size { diff := size - written - mem.copy(&buffer[0], &buffer[diff], written) + intrinsics.mem_copy(&buffer[0], &buffer[diff], written) } return written, nil } @@ -218,7 +216,7 @@ int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_ter written = len(buffer) - available if written < size { diff := size - written - mem.copy(&buffer[0], &buffer[diff], written) + intrinsics.mem_copy(&buffer[0], &buffer[diff], written) } return written, nil } @@ -228,7 +226,7 @@ int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_ter // If we optimize `itoa` further, this needs to be evaluated. itoa_method := _itoa_raw_full - when !MATH_BIG_FORCE_32_BIT && ODIN_OPTIMIZATION_MODE >= .Size { + when ODIN_OPTIMIZATION_MODE >= .Size { if count >= 32768 { itoa_method = _itoa_raw_old } @@ -386,64 +384,7 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false, allocator := con return size, nil } -/* - We might add functions to read and write byte-encoded Ints from/to files, using `int_to_bytes_*` functions. - LibTomMath allows exporting/importing to/from a file in ASCII, but it doesn't support a much more compact representation in binary, even though it has several pack functions int_to_bytes_* (which I expanded upon and wrote Python interoperable versions of as well), and (un)pack, which is GMP compatible. - Someone could implement their own read/write binary int procedures, of course. - - Could be worthwhile to add a canonical binary file representation with an optional small header that says it's an Odin big.Int, big.Rat or Big.Float, byte count for each component that follows, flag for big/little endian and a flag that says a checksum exists at the end of the file. - For big.Rat and big.Float the header couldn't be optional, because we'd have no way to distinguish where the components end. -*/ - -/* - Read an Int from an ASCII file. -*/ -internal_int_read_from_ascii_file :: proc(a: ^Int, filename: string, radix := i8(10), allocator := context.allocator) -> (err: Error) { - context.allocator = allocator - - /* - We can either read the entire file at once, or read a bunch at a time and keep multiplying by the radix. - For now, we'll read the entire file. Eventually we'll replace this with a copy that duplicates the logic - of `atoi` so we don't need to read the entire file. - */ - - res, ok := os.read_entire_file(filename, allocator) - defer delete(res, allocator) - - if !ok { - return .Cannot_Read_File - } - - as := string(res) - return atoi(a, as, radix) -} - -/* - Write an Int to an ASCII file. -*/ -internal_int_write_to_ascii_file :: proc(a: ^Int, filename: string, radix := i8(10), allocator := context.allocator) -> (err: Error) { - context.allocator = allocator - - /* - For now we'll convert the Int using itoa and writing the result in one go. - If we want to preserve memory we could duplicate the itoa logic and write backwards. - */ - - as := itoa(a, radix) or_return - defer delete(as) - - l := len(as) - assert(l > 0) - - data := transmute([]u8)mem.Raw_Slice{ - data = raw_data(as), - len = l, - } - - ok := os.write_entire_file(filename, data, truncate=true) - return nil if ok else .Cannot_Write_File -} /* Calculate the size needed for `internal_int_pack`. @@ -698,7 +639,7 @@ _itoa_raw_full :: proc(a: ^Int, radix: i8, buffer: []u8, zero_terminate := false written = len(buffer) - available if written < len(buffer) { diff := len(buffer) - written - mem.copy(&buffer[0], &buffer[diff], written) + intrinsics.mem_copy(&buffer[0], &buffer[diff], written) } return written, nil } @@ -746,7 +687,7 @@ _itoa_raw_old :: proc(a: ^Int, radix: i8, buffer: []u8, zero_terminate := false, written = len(buffer) - available if written < len(buffer) { diff := len(buffer) - written - mem.copy(&buffer[0], &buffer[diff], written) + intrinsics.mem_copy(&buffer[0], &buffer[diff], written) } return written, nil } \ No newline at end of file diff --git a/core/math/big/radix_os.odin b/core/math/big/radix_os.odin new file mode 100644 index 000000000..793a6c88a --- /dev/null +++ b/core/math/big/radix_os.odin @@ -0,0 +1,79 @@ +#+build !freestanding +#+build !js +package math_big + +/* + Copyright 2021 Jeroen van Rijn . + Made available under Odin's license. + + An arbitrary precision mathematics implementation in Odin. + For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. + The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. + + This file contains radix conversions, `string_to_int` (atoi) and `int_to_string` (itoa). + + TODO: + - Use Barrett reduction for non-powers-of-two. + - Also look at extracting and splatting several digits at once. +*/ + +import "base:runtime" +import "core:os" + +/* + We might add functions to read and write byte-encoded Ints from/to files, using `int_to_bytes_*` functions. + + LibTomMath allows exporting/importing to/from a file in ASCII, but it doesn't support a much more compact representation in binary, even though it has several pack functions int_to_bytes_* (which I expanded upon and wrote Python interoperable versions of as well), and (un)pack, which is GMP compatible. + Someone could implement their own read/write binary int procedures, of course. + + Could be worthwhile to add a canonical binary file representation with an optional small header that says it's an Odin big.Int, big.Rat or Big.Float, byte count for each component that follows, flag for big/little endian and a flag that says a checksum exists at the end of the file. + For big.Rat and big.Float the header couldn't be optional, because we'd have no way to distinguish where the components end. +*/ + +/* + Read an Int from an ASCII file. +*/ +internal_int_read_from_ascii_file :: proc(a: ^Int, filename: string, radix := i8(10), allocator := context.allocator) -> (err: Error) { + context.allocator = allocator + + /* + We can either read the entire file at once, or read a bunch at a time and keep multiplying by the radix. + For now, we'll read the entire file. Eventually we'll replace this with a copy that duplicates the logic + of `atoi` so we don't need to read the entire file. + */ + res, res_err := os.read_entire_file(filename, allocator) + defer delete(res, allocator) + + if res_err != nil { + return .Cannot_Read_File + } + + as := string(res) + return atoi(a, as, radix) +} + +/* + Write an Int to an ASCII file. +*/ +internal_int_write_to_ascii_file :: proc(a: ^Int, filename: string, radix := i8(10), allocator := context.allocator) -> (err: Error) { + context.allocator = allocator + + /* + For now we'll convert the Int using itoa and writing the result in one go. + If we want to preserve memory we could duplicate the itoa logic and write backwards. + */ + + as := itoa(a, radix) or_return + defer delete(as) + + l := len(as) + assert(l > 0) + + data := transmute([]u8)runtime.Raw_Slice{ + data = raw_data(as), + len = l, + } + + write_err := os.write_entire_file(filename, data, truncate=true) + return nil if write_err == nil else .Cannot_Write_File +} \ No newline at end of file diff --git a/core/math/linalg/general.odin b/core/math/linalg/general.odin index 4a0150972..ea3a4e84a 100644 --- a/core/math/linalg/general.odin +++ b/core/math/linalg/general.odin @@ -376,6 +376,7 @@ matrix_cast :: proc "contextless" (v: $A/matrix[$M, $N]$T, $Elem_Type: typeid) - return } +@(require_results) to_f16 :: #force_inline proc(v: $A/[$N]$T) -> [N]f16 { return array_cast(v, f16) } @(require_results) to_f32 :: #force_inline proc(v: $A/[$N]$T) -> [N]f32 { return array_cast(v, f32) } @(require_results) to_f64 :: #force_inline proc(v: $A/[$N]$T) -> [N]f64 { return array_cast(v, f64) } diff --git a/core/math/math.odin b/core/math/math.odin index 7afb32db6..1ecb1da00 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -418,7 +418,7 @@ remap_clamped :: proc "contextless" (old_value, old_min, old_max, new_min, new_m } @(require_results) -wrap :: proc "contextless" (x, y: $T) -> T where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) { +wrap :: proc "contextless" (x, y: $T) -> T where intrinsics.type_is_numeric(T), intrinsics.type_is_float(T), !intrinsics.type_is_array(T) { tmp := mod(x, y) return y + tmp if tmp < 0 else tmp } diff --git a/core/math/math_sincos.odin b/core/math/math_sincos.odin index 9b4d3de40..a17f39fe5 100644 --- a/core/math/math_sincos.odin +++ b/core/math/math_sincos.odin @@ -1,6 +1,6 @@ package math -import "core:math/bits" +import "base:intrinsics" // The original C code, the long comment, and the constants // below were from http://netlib.sandia.gov/cephes/cmath/sin.c, @@ -280,16 +280,16 @@ _trig_reduce_f64 :: proc "contextless" (x: f64) -> (j: u64, z: f64) #no_bounds_c z1 := (bd_pi4[digit+1] << bitshift) | (bd_pi4[digit+2] >> (64 - bitshift)) z2 := (bd_pi4[digit+2] << bitshift) | (bd_pi4[digit+3] >> (64 - bitshift)) // Multiply mantissa by the digits and extract the upper two digits (hi, lo). - z2hi, _ := bits.mul(z2, ix) - z1hi, z1lo := bits.mul(z1, ix) + z2hi, _ := mul_u64(z2, ix) + z1hi, z1lo := mul_u64(z1, ix) z0lo := z0 * ix - lo, c := bits.add(z1lo, z2hi, 0) - hi, _ := bits.add(z0lo, z1hi, c) + lo, c := add_u64(z1lo, z2hi, 0) + hi, _ := add_u64(z0lo, z1hi, c) // The top 3 bits are j. j = hi >> 61 // Extract the fraction and find its magnitude. hi = hi<<3 | lo>>61 - lz := uint(bits.leading_zeros(hi)) + lz := uint(intrinsics.count_leading_zeros(hi)) e := u64(BIAS - (lz + 1)) // Clear implicit mantissa bit and shift into place. hi = (hi << (lz + 1)) | (lo >> (64 - (lz + 1))) @@ -305,4 +305,20 @@ _trig_reduce_f64 :: proc "contextless" (x: f64) -> (j: u64, z: f64) #no_bounds_c } // Multiply the fractional part by pi/4. return j, z * PI4 + + @(require_results) + add_u64 :: proc "contextless" (x, y, carry: u64) -> (sum, carry_out: u64) { + tmp_carry, tmp_carry2: bool + sum, tmp_carry = intrinsics.overflow_add(x, y) + sum, tmp_carry2 = intrinsics.overflow_add(sum, carry) + carry_out = u64(tmp_carry | tmp_carry2) + return + } + + @(require_results) + mul_u64 :: proc "contextless" (x, y: u64) -> (hi, lo: u64) { + prod_wide := u128(x) * u128(y) + hi, lo = u64(prod_wide>>64), u64(prod_wide) + return + } } diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index 41b066255..738de07e5 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -4,7 +4,6 @@ package rand import "base:intrinsics" import "base:runtime" import "core:math" -import "core:mem" Generator :: runtime.Random_Generator @@ -260,7 +259,7 @@ Example: Possible Output: 6 - 500 + 13 */ @(require_results) @@ -301,7 +300,7 @@ Example: Possible Output: 6 - 500 + 13 */ @(require_results) @@ -342,7 +341,7 @@ Example: Possible Output: 6 - 500 + 13 */ @(require_results) @@ -1031,11 +1030,11 @@ Returns: - err: An allocator error if one occured, `nil` otherwise Example: + import "base:runtime" import "core:math/rand" - import "core:mem" import "core:fmt" - perm_example :: proc() -> (err: mem.Allocator_Error) { + perm_example :: proc() -> (err: runtime.Allocator_Error) { data := rand.perm(4) or_return fmt.println(data) defer delete(data, context.allocator) @@ -1050,7 +1049,7 @@ Possible Output: */ @(require_results) -perm :: proc(n: int, allocator := context.allocator, gen := context.random_generator) -> (res: []int, err: mem.Allocator_Error) #optional_allocator_error { +perm :: proc(n: int, allocator := context.allocator, gen := context.random_generator) -> (res: []int, err: runtime.Allocator_Error) #optional_allocator_error { m := make([]int, n, allocator) or_return for i := 0; i < n; i += 1 { j := int_max(i+1, gen) diff --git a/core/math/rand/rand_pcg.odin b/core/math/rand/rand_pcg.odin index 009e139be..79c18acbb 100644 --- a/core/math/rand/rand_pcg.odin +++ b/core/math/rand/rand_pcg.odin @@ -55,16 +55,20 @@ pcg_random_generator_proc :: proc(data: rawptr, mode: runtime.Random_Generator_M intrinsics.unaligned_store((^u64)(raw_data(p)), read_u64(r)) case: // All other cases. - pos := i8(0) - val := u64(0) - for &v in p { - if pos == 0 { - val = read_u64(r) - pos = 8 + n := len(p) / size_of(u64) + buff := ([^]u64)(raw_data(p))[:n] + for &e in buff { + intrinsics.unaligned_store(&e, read_u64(r)) + } + // Handle remaining bytes + rem := len(p) % size_of(u64) + if rem > 0 { + val := read_u64(r) + tail := p[len(p) - rem:] + for &b in tail { + b = byte(val) + val >>= 8 } - v = byte(val) - val >>= 8 - pos -= 1 } } diff --git a/core/math/rand/rand_xoshiro256.odin b/core/math/rand/rand_xoshiro256.odin index 54dd02130..3771d2beb 100644 --- a/core/math/rand/rand_xoshiro256.odin +++ b/core/math/rand/rand_xoshiro256.odin @@ -3,7 +3,17 @@ package rand import "base:intrinsics" import "base:runtime" -import "core:math/bits" +when ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 { + // LLVM thinks that using SIMD for read_u64 is good, + // when it causes a ~3x performance regression. As + // far as I can tell, this behavior is limited to + // Intel. + @(private = "file") + TARGET_FEATURES :: "-sse,-avx,-avx2" +} else { + @(private = "file") + TARGET_FEATURES :: "" +} /* The state for a xoshiro256** pseudorandom generator. @@ -12,12 +22,13 @@ Xoshiro256_Random_State :: struct { s: [4]u64, } +@(enable_target_feature = TARGET_FEATURES) xoshiro256_random_generator_proc :: proc(data: rawptr, mode: runtime.Random_Generator_Mode, p: []byte) { - @(require_results) + @(require_results, enable_target_feature = TARGET_FEATURES) read_u64 :: proc "contextless" (r: ^Xoshiro256_Random_State) -> u64 { // xoshiro256** output function and state transition - result := bits.rotate_left64(r.s[1] * 5, 7) * 9 + result := rotate_left64(r.s[1] * 5, 7) * 9 t := r.s[1] << 17 r.s[2] = r.s[2] ~ r.s[0] @@ -25,9 +36,15 @@ xoshiro256_random_generator_proc :: proc(data: rawptr, mode: runtime.Random_Gene r.s[1] = r.s[1] ~ r.s[2] r.s[0] = r.s[0] ~ r.s[3] r.s[2] = r.s[2] ~ t - r.s[3] = bits.rotate_left64(r.s[3], 45) + r.s[3] = rotate_left64(r.s[3], 45) return result + + rotate_left64 :: #force_inline proc "contextless" (x: u64, k: int) -> u64 { + n :: 64 + s := uint(k) & (n-1) + return x << s | x >> (n-s) + } } @(thread_local) @@ -74,16 +91,20 @@ xoshiro256_random_generator_proc :: proc(data: rawptr, mode: runtime.Random_Gene intrinsics.unaligned_store((^u64)(raw_data(p)), read_u64(r)) case: // All other cases. - pos := i8(0) - val := u64(0) - for &v in p { - if pos == 0 { - val = read_u64(r) - pos = 8 + n := len(p) / size_of(u64) + buff := ([^]u64)(raw_data(p))[:n] + for &e in buff { + intrinsics.unaligned_store(&e, read_u64(r)) + } + // Handle remaining bytes + rem := len(p) % size_of(u64) + if rem > 0 { + val := read_u64(r) + tail := p[len(p) - rem:] + for &b in tail { + b = byte(val) + val >>= 8 } - v = byte(val) - val >>= 8 - pos -= 1 } } diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index b515aa3cf..bcf3ee702 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -141,9 +141,9 @@ arena_alloc_unguarded :: proc(arena: ^Arena, size: uint, alignment: uint, loc := needed := mem.align_forward_uint(size, alignment) needed = max(needed, arena.default_commit_size) - block_size := max(needed, arena.minimum_block_size) + block_size := max(needed, arena.minimum_block_size) + alignment - new_block := memory_block_alloc(needed, block_size, alignment, {}) or_return + new_block := memory_block_alloc(needed, block_size) or_return new_block.prev = arena.curr_block arena.curr_block = new_block arena.total_reserved += new_block.reserved diff --git a/core/mem/virtual/common.odin b/core/mem/virtual/common.odin new file mode 100644 index 000000000..ad8505c89 --- /dev/null +++ b/core/mem/virtual/common.odin @@ -0,0 +1,16 @@ +package mem_virtual + +Map_File_Error :: enum { + None, + Open_Failure, + Stat_Failure, + Negative_Size, + Too_Large_Size, + Map_Failure, +} + +Map_File_Flag :: enum u32 { + Read, + Write, +} +Map_File_Flags :: distinct bit_set[Map_File_Flag; u32] \ No newline at end of file diff --git a/core/mem/virtual/doc.odin b/core/mem/virtual/doc.odin index 614e290c3..b5f0944c7 100644 --- a/core/mem/virtual/doc.odin +++ b/core/mem/virtual/doc.odin @@ -1,7 +1,6 @@ /* A platform agnostic way to reserve/commit/decommit virtual memory. - virtual.Arena usage Example: @@ -27,14 +26,14 @@ Example: // See arena_init_buffer for an arena that does not use virtual memory, // instead it relies on you feeding it a buffer. - f1, f1_ok := os.read_entire_file("file1.txt", arena_alloc) - ensure(f1_ok) + f1, f1_err := os.read_entire_file("file1.txt", arena_alloc) + ensure(f1_err == nil) - f2, f2_ok := os.read_entire_file("file2.txt", arena_alloc) - ensure(f2_ok) + f2, f2_err := os.read_entire_file("file2.txt", arena_alloc) + ensure(f2_err == nil) - f3, f3_ok := os.read_entire_file("file3.txt", arena_alloc) - ensure(f3_ok) + f3, f3_err := os.read_entire_file("file3.txt", arena_alloc) + ensure(f3_err == nil) res := make([]string, 3, arena_alloc) res[0] = string(f1) @@ -56,7 +55,21 @@ Example: vmem.arena_destroy(&arena) } +virtual.map_file usage +Example: + // Source: https://github.com/odin-lang/examples/blob/master/arena_allocator/arena_allocator.odin + import "core:fmt" + + // virtual package implements cross-platform file memory mapping + import vmem "core:mem/virtual" + + main :: proc() { + data, err := virtual.map_file_from_path(#file, {.Read}) + defer virtual.unmap_file(data) + fmt.printfln("Error: %v", err) + fmt.printfln("Data: %s", data) + } */ package mem_virtual diff --git a/core/mem/virtual/file.odin b/core/mem/virtual/file.odin index 2f852b40c..af0449e66 100644 --- a/core/mem/virtual/file.odin +++ b/core/mem/virtual/file.odin @@ -1,39 +1,32 @@ +#+build !freestanding +#+build !js package mem_virtual import "core:os" -Map_File_Error :: enum { - None, - Open_Failure, - Stat_Failure, - Negative_Size, - Too_Large_Size, - Map_Failure, -} - -Map_File_Flag :: enum u32 { - Read, - Write, -} -Map_File_Flags :: distinct bit_set[Map_File_Flag; u32] - map_file :: proc{ map_file_from_path, - map_file_from_file_descriptor, + map_file_from_file, } map_file_from_path :: proc(filename: string, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) { - fd, err := os.open(filename, os.O_RDWR) + open_flags : os.File_Flags + if .Read in flags { + open_flags += {.Read} + } + if .Write in flags { + open_flags += {.Write} + } + f, err := os.open(filename, open_flags) if err != nil { return nil, .Open_Failure } - defer os.close(fd) - - return map_file_from_file_descriptor(uintptr(fd), flags) + defer os.close(f) + return map_file_from_file(f, flags) } -map_file_from_file_descriptor :: proc(fd: uintptr, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) { - size, os_err := os.file_size(os.Handle(fd)) +map_file_from_file :: proc(f: ^os.File, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) { + size, os_err := os.file_size(f) if os_err != nil { return nil, .Stat_Failure } @@ -43,5 +36,12 @@ map_file_from_file_descriptor :: proc(fd: uintptr, flags: Map_File_Flags) -> (da if size != i64(int(size)) { return nil, .Too_Large_Size } + fd := os.fd(f) return _map_file(fd, size, flags) } + +unmap_file :: proc(data: []byte) { + if raw_data(data) != nil { + _unmap_file(data) + } +} diff --git a/core/mem/virtual/virtual.odin b/core/mem/virtual/virtual.odin index 3f388acf3..d37c61267 100644 --- a/core/mem/virtual/virtual.odin +++ b/core/mem/virtual/virtual.odin @@ -154,7 +154,7 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint, pmblock.committed = platform_total_commit block.committed = pmblock.committed - base_offset - + assert(block.committed <= block.reserved) } return } @@ -174,7 +174,7 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint, err = .Out_Of_Memory return } - assert(block.committed <= block.reserved) + do_commit_if_necessary(block, size, default_commit_size) or_return data = block.base[block.used+alignment_offset:][:min_size] diff --git a/core/mem/virtual/virtual_linux.odin b/core/mem/virtual/virtual_linux.odin index f819fbf86..144a8dc59 100644 --- a/core/mem/virtual/virtual_linux.odin +++ b/core/mem/virtual/virtual_linux.odin @@ -49,7 +49,6 @@ _platform_memory_init :: proc "contextless" () { assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) } - _map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) { prot: linux.Mem_Protection if .Read in flags { @@ -66,3 +65,7 @@ _map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) } return ([^]byte)(addr)[:size], nil } + +_unmap_file :: proc "contextless" (data: []byte) { + _release(raw_data(data), uint(len(data))) +} \ No newline at end of file diff --git a/core/mem/virtual/virtual_other.odin b/core/mem/virtual/virtual_other.odin index c6386e842..8a2e1a61d 100644 --- a/core/mem/virtual/virtual_other.odin +++ b/core/mem/virtual/virtual_other.odin @@ -26,8 +26,13 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) } _platform_memory_init :: proc "contextless" () { + } -_map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) { +_map_file :: proc "contextless" (f: any, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) { return nil, .Map_Failure } + +_unmap_file :: proc "contextless" (data: []byte) { + +} \ No newline at end of file diff --git a/core/mem/virtual/virtual_posix.odin b/core/mem/virtual/virtual_posix.odin index 4bb161770..6f257c385 100644 --- a/core/mem/virtual/virtual_posix.odin +++ b/core/mem/virtual/virtual_posix.odin @@ -47,3 +47,7 @@ _map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) } return ([^]byte)(addr)[:size], nil } + +_unmap_file :: proc "contextless" (data: []byte) { + _release(raw_data(data), uint(len(data))) +} \ No newline at end of file diff --git a/core/mem/virtual/virtual_windows.odin b/core/mem/virtual/virtual_windows.odin index 1d777af17..0866ebfa1 100644 --- a/core/mem/virtual/virtual_windows.odin +++ b/core/mem/virtual/virtual_windows.odin @@ -82,6 +82,8 @@ foreign Kernel32 { dwFileOffsetLow: u32, dwNumberOfBytesToMap: uint, ) -> rawptr --- + + UnmapViewOfFile :: proc(lpBaseAddress: rawptr) -> b32 --- } @(no_sanitize_address) @@ -185,3 +187,8 @@ _map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) file_data := MapViewOfFile(handle, desired_access, 0, 0, uint(size)) return ([^]byte)(file_data)[:size], nil } + +@(no_sanitize_address) +_unmap_file :: proc "contextless" (data: []byte) { + UnmapViewOfFile(raw_data(data)) +} \ No newline at end of file diff --git a/core/nbio/doc.odin b/core/nbio/doc.odin new file mode 100644 index 000000000..706d9d42f --- /dev/null +++ b/core/nbio/doc.odin @@ -0,0 +1,213 @@ +/* +package nbio implements a non-blocking I/O and event loop abstraction layer +over several platform-specific asynchronous I/O APIs. + +More examples can be found in Odin's examples repository +at [[ examples/nbio ; https://github.com/odin-lang/examples/tree/master/nbio ]]. + +**Event Loop**: + +Each thread may have at most one event loop associated with it. +This is enforced by the package, as running multiple event loops on a single +thread does not make sense. + +Event loops are reference counted and managed by the package. + +`acquire_thread_event_loop` and `release_thread_event_loop` can be used +to acquire and release a reference. Acquiring must be done before any operation +is done. + +The event loop progresses in ticks. A tick checks if any work is to be done, +and based on the given timeout may block waiting for work. + +Ticks are typically done using the `tick`, `run`, and `run_until` procedures. + +Example: + package main + + import "core:nbio" + import "core:time" + import "core:fmt" + + main :: proc() { + err := nbio.acquire_thread_event_loop() + assert(err == nil) + defer nbio.release_thread_event_loop() + + nbio.timeout(time.Second, proc(_: ^nbio.Operation) { + fmt.println("Hellope after 1 second!") + }) + + err = nbio.run() + assert(err == nil) + } + + +**Time and timeouts**: + +Timeouts are intentionally *slightly inaccurate* by design. + +A timeout is not checked continuously, instead, it is evaluated only when +a tick occurs. This means if a tick took a long time, your timeout may be ready +for a bit of time already before the callback is called. + +The function `now` returns the current time as perceived by the event +loop. This value is cached at least once per tick so it is fast to retrieve. + +Most operations also take an optional timeout when executed. +If the timeout completes before the operation, the operation is cancelled and +called back with a `.Timeout` error. + + +**Threading**: + +The package has a concept of I/O threads (threads that are ticking) and worker +threads (any other thread). + +An I/O thread is mostly self contained, operations are executed on it, and +callbacks run on it. + +If you try to execute an operation on a thread that has no running event loop +a panic will be executed. Instead a worker thread can execute operations onto +a running event loop by taking it's reference and executing operations with +that reference. + +In this case: +- The operation is enqueued from the worker thread +- The I/O thread is optionally woken up from blocking for work with `wake_up` +- The next tick, the operation is executed by the I/O thread +- The callback is invoked on the I/O thread + +Example: + package main + + import "core:nbio" + import "core:net" + import "core:thread" + import "core:time" + + Connection :: struct { + loop: ^nbio.Event_Loop, + socket: net.TCP_Socket, + } + + main :: proc() { + workers: thread.Pool + thread.pool_init(&workers, context.allocator, 2) + thread.pool_start(&workers) + + err := nbio.acquire_thread_event_loop() + defer nbio.release_thread_event_loop() + assert(err == nil) + + server, listen_err := nbio.listen_tcp({nbio.IP4_Any, 1234}) + assert(listen_err == nil) + nbio.accept_poly(server, &workers, on_accept) + + err = nbio.run() + assert(err == nil) + + on_accept :: proc(op: ^nbio.Operation, workers: ^thread.Pool) { + assert(op.accept.err == nil) + + nbio.accept_poly(op.accept.socket, workers, on_accept) + + thread.pool_add_task(workers, context.allocator, do_work, new_clone(Connection{ + loop = op.l, + socket = op.accept.client, + })) + } + + do_work :: proc(t: thread.Task) { + connection := (^Connection)(t.data) + + // Imagine CPU intensive work that's been ofloaded to a worker thread. + time.sleep(time.Second * 1) + + nbio.send_poly(connection.socket, {transmute([]byte)string("Hellope!\n")}, connection, on_sent, l=connection.loop) + } + + on_sent :: proc(op: ^nbio.Operation, connection: ^Connection) { + assert(op.send.err == nil) + // Client got our message, clean up. + nbio.close(connection.socket) + free(connection) + } + } + + +**Handle and socket association**: + +Most platforms require handles (files, sockets, etc.) to be explicitly +associated with an event loop or configured for non-blocking/asynchronous +operation. + +On some platforms (notably Windows), this requires a specific flag at open +time (`.Non_Blocking` for `core:os`) and association may fail if the handle was +not created correctly. + +For this reason, prefer `open` and `create_socket` from this package instead. + +`associate_handle`, `associate_file`, and `associate_socket` can be used for +externally opened files/sockets. + + +**Offsets and positional I/O**: + +Operations do not implicitly use or modify a handle’s internal file +offset. + +Instead, operations such as `read` and `write` are *positional* and require +an explicit offset. + +This avoids ambiguity and subtle bugs when multiple asynchronous operations +are issued concurrently against the same handle. + + +**Contexts and callbacks**: + +The `context` inside a callback is *not* the context that submitted the +operation. + +Instead, the callback receives the context that was active when the event +loop function (`tick`, `run`, etc.) was called. + +This is because otherwise the context would have to be copied and held onto for +each operation. + +If the submitting context is required inside the callback, it must be copied +into the operation’s user data explicitly. + +Example: + nbio.timeout_poly(time.Second, new_clone(context), proc(_: ^Operation, ctx: ^runtime.Context) { + context = ctx^ + free(ctx) + }) + + +**Callback scheduling guarantees**: + +Callbacks are guaranteed to be invoked in a later tick, never synchronously. +This means that the operation returned from a procedure is at least valid till +the end of the current tick, because an operation is freed after it's callback +is called. Thus you can set user data after an execution is queued, or call +`remove`, removing subtle "race" conditions and simplifying control flow. + +**Why does the design of this package use callbacks?** + +Callbacks are the simplest interface an event loop can reasonably expose: "Run +this when the operation completes". This means the loop itself doesn’t need to +know how the result is consumed (You could give control of the entire loop to +the user, but that comes with all the problems in that). + +Other mechanisms can be built on top of this, such as coroutines or even a queue +you comsume at your own time. + +The choice of one `Operation` type and one callback type for all the operations +is partly so it is easy to bind into Lua-like or native coroutines. + +Callbacks also allow multiple independent users to share the same event loop. +A package can register its own operations, and application code can register +others, without either seeing or handling the other’s completions. +*/ +package nbio diff --git a/core/nbio/errors.odin b/core/nbio/errors.odin new file mode 100644 index 000000000..f3bd381d5 --- /dev/null +++ b/core/nbio/errors.odin @@ -0,0 +1,84 @@ +package nbio + +import "base:intrinsics" + +import "core:reflect" + +Error :: intrinsics.type_merge( + Network_Error, + union #shared_nil { + General_Error, + FS_Error, + }, +) +#assert(size_of(Error) == 8) + +// Errors regarding general usage of the event loop. +General_Error :: enum i32 { + None, + + Allocation_Failed = i32(PLATFORM_ERR_ALLOCATION_FAILED), + Unsupported = i32(PLATFORM_ERR_UNSUPPORTED), +} + +// Errors gotten from file system operations. +FS_Error :: enum i32 { + None, + Unsupported = i32(PLATFORM_ERR_UNSUPPORTED), + Allocation_Failed = i32(PLATFORM_ERR_ALLOCATION_FAILED), + Timeout = i32(PLATFORM_ERR_TIMEOUT), + Invalid_Argument = i32(PLATFORM_ERR_INVALID_ARGUMENT), + Permission_Denied = i32(PLATFORM_ERR_PERMISSION_DENIED), + EOF = i32(PLATFORM_ERR_EOF), + Exists = i32(PLATFORM_ERR_EXISTS), + Not_Found = i32(PLATFORM_ERR_NOT_FOUND), +} + +Platform_Error :: _Platform_Error + +error_string :: proc(err: Error) -> string { + err := err + variant := any{ + id = reflect.union_variant_typeid(err), + data = &err, + } + str := reflect.enum_string(variant) + + if str == "" { + #partial switch uerr in err { + case FS_Error: + str, _ = reflect.enum_name_from_value(Platform_Error(uerr)) + case General_Error: + str, _ = reflect.enum_name_from_value(Platform_Error(uerr)) + } + } + if str == "" { + str = "Unknown" + } + + return str +} + +error_string_recv :: proc(recv_err: Recv_Error) -> string { + switch err in recv_err { + case TCP_Recv_Error: return error_string(err) + case UDP_Recv_Error: return error_string(err) + case: return "Unknown" + } +} + +error_string_send :: proc(send_err: Send_Error) -> string { + switch err in send_err { + case TCP_Send_Error: return error_string(err) + case UDP_Send_Error: return error_string(err) + case: return "Unknown" + } +} + +error_string_sendfile :: proc(send_err: Send_File_Error) -> string { + switch err in send_err { + case TCP_Send_Error: return error_string(err) + case FS_Error: return error_string(err) + case: return "Unknown" + } +} diff --git a/core/nbio/errors_linux.odin b/core/nbio/errors_linux.odin new file mode 100644 index 000000000..5c3472500 --- /dev/null +++ b/core/nbio/errors_linux.odin @@ -0,0 +1,16 @@ +#+private +package nbio + +import "core:sys/linux" + +PLATFORM_ERR_UNSUPPORTED :: linux.Errno.ENOSYS +PLATFORM_ERR_ALLOCATION_FAILED :: linux.Errno.ENOMEM +PLATFORM_ERR_TIMEOUT :: linux.Errno.ECANCELED +PLATFORM_ERR_INVALID_ARGUMENT :: linux.Errno.EINVAL +PLATFORM_ERR_OVERFLOW :: linux.Errno.E2BIG +PLATFORM_ERR_NOT_FOUND :: linux.Errno.ENOENT +PLATFORM_ERR_EXISTS :: linux.Errno.EEXIST +PLATFORM_ERR_PERMISSION_DENIED :: linux.Errno.EPERM +PLATFORM_ERR_EOF :: -100 // There is no EOF errno, we use negative for our own error codes. + +_Platform_Error :: linux.Errno diff --git a/core/nbio/errors_others.odin b/core/nbio/errors_others.odin new file mode 100644 index 000000000..f27c91178 --- /dev/null +++ b/core/nbio/errors_others.odin @@ -0,0 +1,20 @@ +#+build !darwin +#+build !freebsd +#+build !openbsd +#+build !netbsd +#+build !linux +#+build !windows +#+private +package nbio + +PLATFORM_ERR_UNSUPPORTED :: 1 +PLATFORM_ERR_ALLOCATION_FAILED :: 2 +PLATFORM_ERR_TIMEOUT :: 3 +PLATFORM_ERR_INVALID_ARGUMENT :: 4 +PLATFORM_ERR_OVERFLOW :: 5 +PLATFORM_ERR_NOT_FOUND :: 6 +PLATFORM_ERR_EXISTS :: 7 +PLATFORM_ERR_PERMISSION_DENIED :: 8 +PLATFORM_ERR_EOF :: 9 + +_Platform_Error :: enum i32 {} diff --git a/core/nbio/errors_posix.odin b/core/nbio/errors_posix.odin new file mode 100644 index 000000000..3dd8f781d --- /dev/null +++ b/core/nbio/errors_posix.odin @@ -0,0 +1,17 @@ +#+build darwin, freebsd, netbsd, openbsd +#+private +package nbio + +import "core:sys/posix" + +PLATFORM_ERR_UNSUPPORTED :: posix.Errno.ENOSYS +PLATFORM_ERR_ALLOCATION_FAILED :: posix.Errno.ENOMEM +PLATFORM_ERR_TIMEOUT :: posix.Errno.ECANCELED +PLATFORM_ERR_INVALID_ARGUMENT :: posix.Errno.EINVAL +PLATFORM_ERR_OVERFLOW :: posix.Errno.E2BIG +PLATFORM_ERR_NOT_FOUND :: posix.Errno.ENOENT +PLATFORM_ERR_EXISTS :: posix.Errno.EEXIST +PLATFORM_ERR_PERMISSION_DENIED :: posix.Errno.EPERM +PLATFORM_ERR_EOF :: -100 // There is no EOF errno, we use negative for our own error codes. + +_Platform_Error :: posix.Errno diff --git a/core/nbio/errors_windows.odin b/core/nbio/errors_windows.odin new file mode 100644 index 000000000..d9b3b7e4d --- /dev/null +++ b/core/nbio/errors_windows.odin @@ -0,0 +1,17 @@ +#+private +package nbio + +import win "core:sys/windows" + +PLATFORM_ERR_UNSUPPORTED :: win.System_Error.NOT_SUPPORTED + +PLATFORM_ERR_ALLOCATION_FAILED :: win.System_Error.OUTOFMEMORY +PLATFORM_ERR_TIMEOUT :: win.System_Error.WAIT_TIMEOUT +PLATFORM_ERR_INVALID_ARGUMENT :: win.System_Error.BAD_ARGUMENTS +PLATFORM_ERR_OVERFLOW :: win.System_Error.BUFFER_OVERFLOW +PLATFORM_ERR_NOT_FOUND :: win.System_Error.FILE_NOT_FOUND +PLATFORM_ERR_EXISTS :: win.System_Error.FILE_EXISTS +PLATFORM_ERR_PERMISSION_DENIED :: win.System_Error.ACCESS_DENIED +PLATFORM_ERR_EOF :: win.System_Error.HANDLE_EOF + +_Platform_Error :: win.System_Error diff --git a/core/nbio/impl.odin b/core/nbio/impl.odin new file mode 100644 index 000000000..18bb7cfa9 --- /dev/null +++ b/core/nbio/impl.odin @@ -0,0 +1,318 @@ +#+private +package nbio + +import "base:runtime" +import "base:intrinsics" + +import "core:container/pool" +import "core:net" +import "core:reflect" +import "core:slice" +import "core:strings" +import "core:time" + +@(init, private) +init_thread_local_cleaner :: proc "contextless" () { + runtime.add_thread_local_cleaner(proc() { + l := &_tls_event_loop + if l.refs > 0 { + l.refs = 1 + _release_thread_event_loop() + } + }) +} + +@(thread_local) +_tls_event_loop: Event_Loop + +_acquire_thread_event_loop :: proc() -> General_Error { + l := &_tls_event_loop + if l.err == nil && l.refs == 0 { + when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 && ODIN_OS != .Orca { + allocator := runtime.default_wasm_allocator() + } else { + allocator := runtime.heap_allocator() + } + + l.allocator = allocator + + if alloc_err := mpsc_init(&l.queue, 128, l.allocator); alloc_err != nil { + l.err = .Allocation_Failed + return l.err + } + defer if l.err != nil { mpsc_destroy(&l.queue, l.allocator) } + + if pool_err := pool.init(&l.operation_pool, "_pool_link"); pool_err != nil { + l.err = .Allocation_Failed + return l.err + } + defer if l.err != nil { pool.destroy(&l.operation_pool) } + + l.err = _init(l, allocator) + l.now = time.now() + } + + if l.err != nil { + return l.err + } + + l.refs += 1 + return nil +} + +_release_thread_event_loop :: proc() { + l := &_tls_event_loop + if l.err != nil { + assert(l.refs == 0) + return + } + + if l.refs > 0 { + l.refs -= 1 + if l.refs == 0 { + mpsc_destroy(&l.queue, l.allocator) + pool.destroy(&l.operation_pool) + _destroy(l) + l^ = {} + } + } +} + +_current_thread_event_loop :: #force_inline proc(loc := #caller_location) -> (^Event_Loop) { + l := &_tls_event_loop + + if intrinsics.expect(l.refs == 0, false) { + return nil + } + + return l +} + +_tick :: proc(l: ^Event_Loop, timeout: time.Duration) -> (err: General_Error) { + // Receive operations queued from other threads first. + for { + op := (^Operation)(mpsc_dequeue(&l.queue)) + if op == nil { break } + _exec(op) + } + + return __tick(l, timeout) +} + +_listen_tcp :: proc( + l: ^Event_Loop, + endpoint: Endpoint, + backlog := 1000, + loc := #caller_location, +) -> ( + socket: TCP_Socket, + err: Network_Error, +) { + family := family_from_endpoint(endpoint) + socket = create_tcp_socket(family, l, loc) or_return + defer if err != nil { close(socket, l=l) } + + net.set_option(socket, .Reuse_Address, true) + + bind(socket, endpoint) or_return + + _listen(socket, backlog) or_return + return +} + +_read_entire_file :: proc(l: ^Event_Loop, path: string, user_data: rawptr, cb: Read_Entire_File_Callback, allocator := context.allocator, dir := CWD) { + open_poly3(path, user_data, cb, allocator, on_open, dir=dir, l=l) + + on_open :: proc(op: ^Operation, user_data: rawptr, cb: Read_Entire_File_Callback, allocator: runtime.Allocator) { + if op.open.err != nil { + cb(user_data, nil, {.Open, op.open.err}) + return + } + + stat_poly3(op.open.handle, user_data, cb, allocator, on_stat) + } + + on_stat :: proc(op: ^Operation, user_data: rawptr, cb: Read_Entire_File_Callback, allocator: runtime.Allocator) { + if op.stat.err != nil { + close(op.stat.handle) + cb(user_data, nil, {.Stat, op.stat.err}) + return + } + + if op.stat.type != .Regular { + close(op.stat.handle) + cb(user_data, nil, {.Stat, .Unsupported}) + return + } + + buf, err := make([]byte, op.stat.size, allocator) + if err != nil { + close(op.stat.handle) + cb(user_data, nil, {.Read, .Allocation_Failed}) + return + } + + read_poly3(op.stat.handle, 0, buf, user_data, cb, allocator, on_read, all=true) + } + + on_read :: proc(op: ^Operation, user_data: rawptr, cb: Read_Entire_File_Callback, allocator: runtime.Allocator) { + close(op.read.handle) + + if op.read.err != nil { + delete(op.read.buf, allocator) + cb(user_data, nil, {.Read, op.read.err}) + return + } + + assert(op.read.read == len(op.read.buf)) + cb(user_data, op.read.buf, {}) + } +} + +NBIO_DEBUG :: #config(NBIO_DEBUG, false) + +Debuggable :: union { + Operation_Type, + string, + int, + time.Time, + time.Duration, +} + +@(disabled=!NBIO_DEBUG) +debug :: proc(contents: ..Debuggable, location := #caller_location) { + if context.logger.procedure == nil || .Debug < context.logger.lowest_level { + return + } + + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + + b: strings.Builder + b.buf.allocator = context.temp_allocator + + strings.write_string(&b, "[nbio] ") + + for content, i in contents { + switch val in content { + case Operation_Type: + name, _ := reflect.enum_name_from_value(val) + strings.write_string(&b, name) + case string: + strings.write_string(&b, val) + case int: + strings.write_int(&b, val) + case time.Duration: + ms := time.duration_milliseconds(val) + strings.write_f64(&b, ms, 'f') + strings.write_string(&b, "ms") + + case time.Time: + buf: [time.MIN_HMS_LEN+1]byte + h, m, s, ns := time.precise_clock_from_time(val) + buf[8] = '.' + buf[7] = '0' + u8(s % 10); s /= 10 + buf[6] = '0' + u8(s) + buf[5] = ':' + buf[4] = '0' + u8(m % 10); m /= 10 + buf[3] = '0' + u8(m) + buf[2] = ':' + buf[1] = '0' + u8(h % 10); h /= 10 + buf[0] = '0' + u8(h) + + strings.write_string(&b, string(buf[:])) + strings.write_int(&b, ns) + } + + if i < len(contents)-1 { + strings.write_byte(&b, ' ') + } + } + + context.logger.procedure(context.logger.data, .Debug, strings.to_string(b), context.logger.options, location) +} + +warn :: proc(text: string, location := #caller_location) { + if context.logger.procedure == nil || .Warning < context.logger.lowest_level { + return + } + + context.logger.procedure(context.logger.data, .Warning, text, context.logger.options, location) +} + +/* +In order to: +1. Not require the caller to allocate their buffers (`op.send.bufs` and `op.recv.bufs` can be stack allocated) +2. Have `op.send.bufs` and `op.recv.bufs` be valid and the same content in the callback as when called +3. Be able to facilitate the `all` option, which requires mutating the slices (advancing them) +4. Constraint single send/recv syscalls to MAX_RW bytes + +We need to copy the input buffers twice, once for a stable copy returned to the user, +and one for the working copy that we mutate with `all` set. +*/ + +Bufs :: struct { + backing: [1][]byte, + working: struct #raw_union { + small: [1][]byte, + big: [][]byte, + }, +} + +bufs_init :: proc(bufs: ^Bufs, orig: ^[][]byte, allocator: runtime.Allocator) -> runtime.Allocator_Error { + if len(orig) > 1 { + backing := make([][]byte, len(orig)*2, allocator) or_return + bufs.working.big = backing[len(orig):] + copy(bufs.working.big, orig^) + copy(backing, orig^) + orig^ = backing[:len(orig)] + return nil + } + + bufs.backing = {orig[0]} + orig^ = bufs.backing[:] + return nil +} + +bufs_delete :: proc(bufs: ^Bufs, orig: [][]byte, allocator: runtime.Allocator) { + if len(orig) > 1 { + backing := raw_data(orig)[:len(orig)*2] + delete(backing, allocator) + } +} + +@(require_results) +bufs_to_process :: proc(bufs: ^Bufs, orig: [][]byte, processed: int) -> (working: [][]byte, total: int) { + if len(orig) > 1 { + // Reset to length and contents of backing, so a previous modification is removed. + (^runtime.Raw_Slice)(&bufs.working.big).len = len(orig) + copy(bufs.working.big, orig) + working = bufs.working.big + } else { + bufs.working.small = {orig[0]} + working = bufs.working.small[:] + } + + working = slice.advance_slices(working, processed) + working, total = constraint_bufs_to_max_rw(working) + return +} + +@(require_results) +constraint_bufs_to_max_rw :: proc(bufs: [][]byte) -> (constrained: [][]byte, total: int) { + for buf in bufs { + total += len(buf) + } + + constrained = bufs + for n := total; n > MAX_RW; { + last := &constrained[len(constrained)-1] + take := min(len(last), n-MAX_RW) + last^ = last[:take] + if len(last) == 0 { + constrained = constrained[:len(constrained)-1] + } + n -= take + } + + return +} diff --git a/core/nbio/impl_linux.odin b/core/nbio/impl_linux.odin new file mode 100644 index 000000000..f4b200830 --- /dev/null +++ b/core/nbio/impl_linux.odin @@ -0,0 +1,1465 @@ +#+private file +package nbio + +import "base:intrinsics" + +import "core:container/pool" +import "core:container/queue" +import "core:mem" +import "core:net" +import "core:strings" +import "core:sys/linux" +import "core:sys/linux/uring" +import "core:time" + +@(private="package") +_FULLY_SUPPORTED :: true + +@(private="package") +_Event_Loop :: struct { + ring: uring.Ring, + // Ready to be submitted to kernel, if kernel is full. + unqueued: queue.Queue(^Operation), + // Ready to run callbacks, mainly next tick, some other ops that error outside the kernel. + completed: queue.Queue(^Operation), + wake: ^Operation, +} + +@(private="package") +_Handle :: linux.Fd + +@(private="package") +_CWD :: linux.AT_FDCWD + +@(private="package") +MAX_RW :: mem.Gigabyte + +@(private="package") +_Operation :: struct { + removal: ^Operation, + sqe: ^linux.IO_Uring_SQE, + expires: linux.Time_Spec, +} + +@(private="package") +_Accept :: struct { + sockaddr: linux.Sock_Addr_Any, + sockaddr_len: i32, +} + +@(private="package") +_Close :: struct {} + +@(private="package") +_Dial :: struct { + sockaddr: linux.Sock_Addr_Any, +} + +@(private="package") +_Read :: struct {} + +@(private="package") +_Write :: struct {} + +Sock_Addr_Ip :: struct #raw_union { + using _: struct { + family: linux.Address_Family, + port: u16be, + }, + using ipv4: linux.Sock_Addr_In, + using ipv6: linux.Sock_Addr_In6, +} + +@(private="package") +_Send :: struct { + endpoint: Sock_Addr_Ip, + msghdr: linux.Msg_Hdr, + bufs: Bufs, +} + +@(private="package") +_Recv :: struct { + addr_out: Sock_Addr_Ip, + msghdr: linux.Msg_Hdr, + bufs: Bufs, +} + +@(private="package") +_Timeout :: struct { + expires: linux.Time_Spec, +} + +@(private="package") +_Poll :: struct {} + +@(private="package") +_Remove :: struct { + target: ^Operation, +} + +@(private="package") +_Link_Timeout :: struct { + target: ^Operation, + expires: linux.Time_Spec, +} + +@(private="package") +_Send_File :: struct { + len: int, + pipe: Handle, + + splice: ^Operation, +} + +@(private="package") +_Splice :: struct { + off: int, + len: int, + file: Handle, + pipe: Handle, + + written: int, + + sendfile: ^Operation, +} + +@(private="package") +_Open :: struct { + cpath: cstring, +} + +@(private="package") +_Stat :: struct { + buf: linux.Statx, +} + +@(private="package") +_init :: proc(l: ^Event_Loop, alloc: mem.Allocator) -> (err: General_Error) { + params := uring.DEFAULT_PARAMS + params.flags += {.SUBMIT_ALL, .COOP_TASKRUN, .SINGLE_ISSUER} + + uerr := uring.init(&l.ring, ¶ms, QUEUE_SIZE) + if uerr != nil { + err = General_Error(uerr) + return + } + defer if err != nil { uring.destroy(&l.ring) } + + if perr := queue.init(&l.unqueued, allocator = alloc); perr != nil { + err = .Allocation_Failed + return + } + defer if err != nil { queue.destroy(&l.unqueued) } + + if perr := queue.init(&l.completed, allocator = alloc); perr != nil { + err = .Allocation_Failed + return + } + defer if err != nil { queue.destroy(&l.completed) } + + set_up_wake_up(l) or_return + + return + + set_up_wake_up :: proc(l: ^Event_Loop) -> General_Error { + wakefd, wakefd_err := linux.eventfd(0, {.SEMAPHORE, .CLOEXEC, .NONBLOCK}) + if wakefd_err != nil { + return General_Error(wakefd_err) + } + + op, alloc_err := new(Operation, l.allocator) + if alloc_err != nil { + linux.close(wakefd) + return .Allocation_Failed + } + + l.wake = op + l.wake.detached = true + l.wake.l = l + l.wake.type = .Read + l.wake.cb = wake_up_callback + l.wake.read.handle = wakefd + l.wake.read.buf = ([^]byte)(&l.wake.user_data)[:8] + _exec(l.wake) + + return nil + } + + wake_up_callback :: proc(op: ^Operation) { + assert(op.type == .Read) + assert(op == op.l.wake) + assert(op.read.err == nil) + assert(op.read.read == 8) + value := intrinsics.unaligned_load((^u64)(&op.user_data)) + assert(value > 0) + debug(int(value), "wake_up calls handled") + + op.read.read = 0 + op.user_data = {} + _exec(op) + } +} + +@(private="package") +_destroy :: proc(l: ^Event_Loop) { + linux.close(l.wake.read.handle) + free(l.wake, l.allocator) + + queue.destroy(&l.unqueued) + queue.destroy(&l.completed) + uring.destroy(&l.ring) +} + +@(private="package") +__tick :: proc(l: ^Event_Loop, timeout: time.Duration) -> General_Error { + debug("tick") + + // Execute completed operations, mostly next tick ops, also some other ops that may error before + // adding it to the Uring. + n := queue.len(l.completed) + if n > 0 { + l.now = time.now() + for _ in 0 ..< n { + completed := queue.pop_front(&l.completed) + if completed._impl.removal == nil { + completed.cb(completed) + } else if completed._impl.removal != (^Operation)(REMOVED) { + completed._impl.removal._remove.target = nil + } + if !completed.detached { + pool.put(&l.operation_pool, completed) + } + } + } + + err := _flush_submissions(l, timeout) + if err != nil { return General_Error(err) } + + l.now = time.now() + + err = _flush_completions(l, false) + if err != nil { return General_Error(err) } + + return nil + + _flush_completions :: proc(l: ^Event_Loop, wait: bool) -> linux.Errno { + wait := wait + cqes: [128]linux.IO_Uring_CQE = --- + for { + completed, err := uring.copy_cqes(&l.ring, cqes[:], 1 if wait else 0) + if err == .EINTR { + continue + } else if err != nil { + return err + } + + _flush_unqueued(l) + + if completed > 0 { + debug(int(completed), "operations returned from uring") + } + + for cqe in cqes[:completed] { + assert(cqe.user_data != 0) + op, is_timeout := unpack_operation(cqe.user_data) + if is_timeout { + link_timeout_callback(op, cqe.res) + } else { + handle_completed(op, cqe.res) + } + } + + if completed < len(cqes) { break } + + debug("more events ready than our results buffer handles, getting more") + wait = false + } + + return nil + } + + _flush_submissions :: proc(l: ^Event_Loop, timeout: time.Duration) -> linux.Errno { + for { + ts: linux.Time_Spec + ts.time_nsec = uint(timeout) + _, err := uring.submit(&l.ring, 0 if timeout == 0 else 1, nil if timeout < 0 else &ts) + #partial switch err { + case .NONE, .ETIME: + case .EINTR: + warn("uring interrupted") + continue + case .ENOMEM: + // It's full, wait for at least one operation to complete and try again. + warn("could not flush submissions, ENOMEM, waiting for operations to complete before continuing") + ferr := _flush_completions(l, true) + if ferr != nil { return ferr } + continue + case: + return err + } + + break + } + + return nil + } + + _flush_unqueued :: proc(l: ^Event_Loop) { + n := queue.len(l.unqueued) + for _ in 0.. (handle: Handle, err: FS_Error) { + if path == "" { + err = .Invalid_Argument + return + } + + cpath, cerr := strings.clone_to_cstring(path, l.allocator) + if cerr != nil { + err = .Allocation_Failed + return + } + defer delete(cpath, l.allocator) + + sys_flags := linux.Open_Flags{.NOCTTY, .CLOEXEC, .NONBLOCK} + + if .Write in mode { + if .Read in mode { + sys_flags += {.RDWR} + } else { + sys_flags += {.WRONLY} + } + } + + if .Append in mode { sys_flags += {.APPEND} } + if .Create in mode { sys_flags += {.CREAT} } + if .Excl in mode { sys_flags += {.EXCL} } + if .Sync in mode { sys_flags += {.DSYNC} } + if .Trunc in mode { sys_flags += {.TRUNC} } + // if .Inheritable in mode { sys_flags -= {.CLOEXEC} } + + errno: linux.Errno + handle, errno = linux.openat(dir, cpath, sys_flags, transmute(linux.Mode)perm) + if errno != nil { + err = FS_Error(errno) + } + + return +} + +@(private="package") +_create_socket :: proc( + _: ^Event_Loop, + family: Address_Family, + protocol: Socket_Protocol, +) -> ( + socket: Any_Socket, + err: Create_Socket_Error, +) { + socket = net.create_socket(family, protocol) or_return + // NOTE: this doesn't seem needed with io uring. + // defer if err != nil { net.close(socket) } + // net.set_blocking(socket, false) or_return + return +} + +@(private="package") +_listen :: proc(socket: TCP_Socket, backlog := 1000) -> Listen_Error { + err := linux.listen(linux.Fd(socket), i32(backlog)) + if err != nil { + return net._listen_error(err) + } + return nil +} + +@(private="package") +_remove :: proc(target: ^Operation) { + target := target + assert(target != nil) + + if target._impl.removal != nil { + return + } + + op := _prep(target.l, proc(_: ^Operation) {}, ._Remove) + op._remove.target = target + + target._impl.removal = op + + enqueue(op, uring.async_cancel( + &op.l.ring, + u64(uintptr(target)), + u64(uintptr(op)), + )) +} + +@(private="package") +_associate_handle :: proc(handle: uintptr, l: ^Event_Loop) -> (Handle, Association_Error) { + // Works by default. + return Handle(handle), nil +} + +@(private="package") +_associate_socket :: proc(socket: Any_Socket, l: ^Event_Loop) -> Association_Error { + // Works by default. + return nil +} + +@(private="package") +_wake_up :: proc(l: ^Event_Loop) { + assert(l != &_tls_event_loop) + one: u64 = 1 + // Called from another thread, in which we can't use the uring. + n, err := linux.write(l.wake.read.handle, ([^]byte)(&one)[:size_of(one)]) + // Shouldn't fail. + assert(err == nil) + assert(n == 8) +} + +@(private="package") +_yield :: proc() { + linux.sched_yield() +} + +// Start file private. + +// The size of the IO Uring queues. +QUEUE_SIZE :: #config(ODIN_NBIO_QUEUE_SIZE, 2048) +#assert(QUEUE_SIZE <= uring.MAX_ENTRIES) + +#assert(size_of(Operation) <= 384) // Just so we see when we make it bigger. +#assert(size_of(Specifics) <= 288) // Just so we see when we make it bigger. + +REMOVED :: rawptr(max(uintptr)-1) + +handle_completed :: proc(op: ^Operation, res: i32) { + debug("handling", op.type, "result", int(res)) + + switch op.type { + case .Accept: + accept_callback(op, res) + case .Dial: + dial_callback(op, res) + case .Timeout: + timeout_callback(op, res) + case .Write: + if !write_callback(op, res) { return } + case .Read: + if !read_callback(op, res) { return } + case .Close: + close_callback(op, res) + case .Poll: + poll_callback(op, res) + case .Send: + if !send_callback(op, res) { return } + maybe_callback(op) + bufs_delete(&op.send._impl.bufs, op.send.bufs, op.l.allocator) + cleanup(op) + return + case .Recv: + if !recv_callback(op, res) { return } + maybe_callback(op) + bufs_delete(&op.recv._impl.bufs, op.recv.bufs, op.l.allocator) + cleanup(op) + return + case .Open: + open_callback(op, res) + case .Stat: + stat_callback(op, res) + case .Send_File: + if !sendfile_callback(op, res) { return } + case ._Splice: + if !splice_callback(op, res) { return } + case ._Remove: + if !remove_callback(op, res) { return } + case ._Link_Timeout: + unreachable() + case .None: + fallthrough + case: + panic("corrupted operation") + } + + maybe_callback(op) + cleanup(op) + + maybe_callback :: proc(op: ^Operation) { + if op._impl.removal == nil { + debug("done, calling back", op.type) + op.cb(op) + } else if op._impl.removal == (^Operation)(REMOVED) { + debug("done but was cancelled by remove", op.type) + } else { + debug("done but has removal pending", op.type) + // If the remove callback sees their target is nil, they know it is done already. + op._impl.removal._remove.target = nil + } + } + + cleanup :: proc(op: ^Operation) { + if !op.detached { + pool.put(&op.l.operation_pool, op) + } + } +} + +enqueue :: proc(op: ^Operation, sqe: ^linux.IO_Uring_SQE, ok: bool) { + assert(uintptr(op) & LINK_TIMEOUT_MASK == 0) + debug("enqueue", op.type) + if !ok { + warn("queueing for next tick because the ring is full, queue size may need increasing") + pok, _ := queue.push_back(&op.l.unqueued, op) + ensure(pok, "unqueued queue allocation failure") + return + } + + op._impl.sqe = sqe +} + +LINK_TIMEOUT_MASK :: 1 + +link_timeout :: proc(target: ^Operation, expires: time.Time) { + if expires == {} { + return + } + + // If the last op was queued because kernel is full, return. + if target._impl.sqe == nil { + assert(queue.len(target.l.unqueued) > 0 && queue.back_ptr(&target.l.unqueued)^ == target) + return + } + + target._impl.sqe.flags += {.IO_LINK} + target._impl.expires = ns_to_time_spec(expires._nsec) + + // Tag the pointer as a timeout. + p := uintptr(target) + assert(p & LINK_TIMEOUT_MASK == 0) + p |= LINK_TIMEOUT_MASK + + _, ok := uring.link_timeout( + &target.l.ring, + u64(p), + &target._impl.expires, + {.ABS, .REALTIME}, + ) + // If the target wasn't queued, the link timeout should not need to be queued, because uring + // leaves one spot specifically for a link. + assert(ok) +} + +link_timeout_callback :: proc(op: ^Operation, res: i32) { + err := linux.Errno(-res) + if err != nil && err != .ETIME && err != .ECANCELED { + panic("unexpected nbio.link_timeout() error") + } +} + +unpack_operation :: #force_inline proc(user_data: u64) -> (op: ^Operation, timed_out: bool) { + p := uintptr(user_data) + return (^Operation)(p &~ LINK_TIMEOUT_MASK), bool(p & LINK_TIMEOUT_MASK) +} + +@(require_results) +remove_callback :: proc(op: ^Operation, res: i32) -> bool { + assert(op.type == ._Remove) + err := linux.Errno(-res) + + target := op._remove.target + if target == nil { + debug("remove target nil, already handled") + return true + } + + assert(target.type != .None) + assert(target._impl.removal == op) + + if err == .ENOENT { + debug("remove ENOENT, trying again") + + enqueue(op, uring.async_cancel( + &op.l.ring, + u64(uintptr(target)), + u64(uintptr(op)), + )) + + return false + } else if err == .EALREADY { + debug("remove is accepted and will be tried") + } else if err != nil { + assert(false, "unexpected nbio.remove() error") + } + + // Set to sentinel so nothing references the operation that will be reused. + target._impl.removal = (^Operation)(REMOVED) + return true +} + +accept_exec :: proc(op: ^Operation) { + assert(op.type == .Accept) + op.accept._impl.sockaddr_len = size_of(op.accept._impl.sockaddr) + enqueue(op, uring.accept( + &op.l.ring, + u64(uintptr(op)), + linux.Fd(op.accept.socket), + &op.accept._impl.sockaddr, + &op.accept._impl.sockaddr_len, + {}, + )) + link_timeout(op, op.accept.expires) +} + +accept_callback :: proc(op: ^Operation, res: i32) { + assert(op.type == .Accept) + if res < 0 { + errno := linux.Errno(-res) + #partial switch errno { + case .ECANCELED: + op.accept.err = .Timeout + case: + op.accept.err = net._accept_error(errno) + } + + return + } + + op.accept.client = TCP_Socket(res) + // net.set_blocking(net.TCP_Socket(op.accept.client), false) + op.accept.client_endpoint = sockaddr_storage_to_endpoint_any(&op.accept._impl.sockaddr) +} + +dial_exec :: proc(op: ^Operation) { + assert(op.type == .Dial) + if op.dial.socket == {} { + if op.dial.endpoint.port == 0 { + op.dial.err = .Port_Required + queue.push_back(&op.l.completed, op) + return + } + + sock, err := create_socket(net.family_from_endpoint(op.dial.endpoint), .TCP) + if err != nil { + op.dial.err = err + queue.push_back(&op.l.completed, op) + return + } + + op.dial.socket = sock.(TCP_Socket) + op.dial._impl.sockaddr = endpoint_to_sockaddr_any(op.dial.endpoint) + } + + enqueue(op, uring.connect( + &op.l.ring, + u64(uintptr(op)), + linux.Fd(op.dial.socket), + &op.dial._impl.sockaddr, + )) + link_timeout(op, op.dial.expires) +} + +dial_callback :: proc(op: ^Operation, res: i32) { + assert(op.type == .Dial) + errno := linux.Errno(-res) + if errno != nil { + #partial switch errno { + case .ECANCELED: + op.dial.err = Dial_Error.Timeout + case: + op.dial.err = net._dial_error(errno) + } + close(op.dial.socket) + } +} + +timeout_exec :: proc(op: ^Operation) { + assert(op.type == .Timeout) + if op.timeout.duration <= 0 { + queue.push_back(&op.l.completed, op) + return + } + + expires := time.time_add(op.l.now, op.timeout.duration) + op.timeout._impl.expires = ns_to_time_spec(expires._nsec) + + enqueue(op, uring.timeout( + &op.l.ring, + u64(uintptr(op)), + &op.timeout._impl.expires, + 0, + {.ABS, .REALTIME}, + )) +} + +timeout_callback :: proc(op: ^Operation, res: i32) { + if res < 0 { + errno := linux.Errno(-res) + #partial switch errno { + case .ETIME, .ECANCELED: // OK. + case: + debug("unexpected timeout error:", int(errno)) + panic("unexpected timeout error") + } + } +} + +close_exec :: proc(op: ^Operation) { + assert(op.type == .Close) + + fd: linux.Fd + switch closable in op.close.subject { + case Handle: fd = linux.Fd(closable) + case TCP_Socket: fd = linux.Fd(closable) + case UDP_Socket: fd = linux.Fd(closable) + case: op.close.err = .Invalid_Argument; return + } + + enqueue(op, uring.close( + &op.l.ring, + u64(uintptr(op)), + fd, + )) +} + +close_callback :: proc(op: ^Operation, res: i32) { + assert(op.type == .Close) + op.close.err = FS_Error(linux.Errno(-res)) +} + +recv_exec :: proc(op: ^Operation) { + assert(op.type == .Recv) + + if op.recv.err != nil { + queue.push_back(&op.l.completed, op) + return + } + + bufs, _ := bufs_to_process(&op.recv._impl.bufs, op.recv.bufs, op.recv.received) + op.recv._impl.msghdr.iov = transmute([]linux.IO_Vec)bufs + + sock: linux.Fd + switch socket in op.recv.socket { + case TCP_Socket: + sock = linux.Fd(socket) + case UDP_Socket: + sock = linux.Fd(socket) + op.recv._impl.msghdr.name = &op.recv._impl.addr_out + op.recv._impl.msghdr.namelen = size_of(op.recv._impl.addr_out) + } + + enqueue(op, uring.recvmsg( + &op.l.ring, + u64(uintptr(op)), + linux.Fd(sock), + &op.recv._impl.msghdr, + {.NOSIGNAL}, + )) + link_timeout(op, op.recv.expires) +} + +@(require_results) +recv_callback :: proc(op: ^Operation, res: i32) -> bool { + assert(op.type == .Recv) + + if res < 0 { + errno := linux.Errno(-res) + switch sock in op.recv.socket { + case TCP_Socket: + #partial switch errno { + case .ECANCELED: + op.recv.err = TCP_Recv_Error.Timeout + case: + op.recv.err = net._tcp_recv_error(errno) + } + case UDP_Socket: + #partial switch errno { + case .ECANCELED: + op.recv.err = UDP_Recv_Error.Timeout + case: + op.recv.err = net._udp_recv_error(errno) + } + } + + return true + } + + op.recv.received += int(res) + + switch sock in op.recv.socket { + case TCP_Socket: + if res == 0 { + // Connection closed. + return true + } + + if op.recv.all { + total: int + for buf in op.recv.bufs { + total += len(buf) + } + + if op.recv.received < total { + recv_exec(op) + return false + } + } + + case UDP_Socket: + op.recv.source = sockaddr_storage_to_endpoint_ip(&op.recv._impl.addr_out) + } + + return true +} + +send_exec :: proc(op: ^Operation) { + assert(op.type == .Send) + + if op.send.err != nil { + queue.push_back(&op.l.completed, op) + return + } + + bufs, _ := bufs_to_process(&op.send._impl.bufs, op.send.bufs, op.send.sent) + op.send._impl.msghdr.iov = transmute([]linux.IO_Vec)bufs + + sock: linux.Fd + switch socket in op.send.socket { + case TCP_Socket: + sock = linux.Fd(socket) + case UDP_Socket: + sock = linux.Fd(socket) + op.send._impl.endpoint = endpoint_to_sockaddr_ip(op.send.endpoint) + op.send._impl.msghdr.name = &op.send._impl.endpoint + op.send._impl.msghdr.namelen = size_of(op.send._impl.endpoint) + } + + enqueue(op, uring.sendmsg( + &op.l.ring, + u64(uintptr(op)), + sock, + &op.send._impl.msghdr, + {.NOSIGNAL}, + )) + link_timeout(op, op.send.expires) +} + +@(require_results) +send_callback :: proc(op: ^Operation, res: i32) -> bool { + assert(op.type == .Send) + if res < 0 { + errno := linux.Errno(-res) + switch sock in op.send.socket { + case TCP_Socket: + #partial switch errno { + case .ECANCELED: + op.send.err = TCP_Send_Error.Timeout + case: + op.send.err = net._tcp_send_error(errno) + } + case UDP_Socket: + #partial switch errno { + case .ECANCELED: + op.send.err = UDP_Send_Error.Timeout + case: + op.send.err = net._udp_send_error(errno) + } + case: panic("corrupted socket") + } + + return true + } + + op.send.sent += int(res) + + if op.send.all { + total: int + for buf in op.send.bufs { + total += len(buf) + } + + if op.send.sent < total { + assert(res > 0) + send_exec(op) + return false + } + } + + return true +} + +write_exec :: proc(op: ^Operation) { + assert(op.type == .Write) + + buf := op.write.buf[op.write.written:] + buf = buf[:min(MAX_RW, len(buf))] + + enqueue(op, uring.write( + &op.l.ring, + u64(uintptr(op)), + op.write.handle, + buf, + u64(op.write.offset) + u64(op.write.written), + )) + link_timeout(op, op.write.expires) +} + +@(require_results) +write_callback :: proc(op: ^Operation, res: i32) -> bool { + if res < 0 { + errno := linux.Errno(-res) + op.write.err = FS_Error(errno) + return true + } + + op.write.written += int(res) + + if op.write.all && op.write.written < len(op.write.buf) { + write_exec(op) + return false + } + + return true +} + +read_exec :: proc(op: ^Operation) { + assert(op.type == .Read) + + buf := op.read.buf[op.read.read:] + buf = buf[:min(MAX_RW, len(buf))] + + enqueue(op, uring.read( + &op.l.ring, + u64(uintptr(op)), + op.read.handle, + buf, + u64(op.read.offset) + u64(op.read.read), + )) + link_timeout(op, op.read.expires) +} + +@(require_results) +read_callback :: proc(op: ^Operation, res: i32) -> bool { + if res < 0 { + errno := linux.Errno(-res) + op.read.err = FS_Error(errno) + return true + } else if res == 0 { + if op.read.read == 0 { + op.read.err = .EOF + } + return true + } + + op.read.read += int(res) + + if op.read.all && op.read.read < len(op.read.buf) { + read_exec(op) + return false + } + + return true +} + +poll_exec :: proc(op: ^Operation) { + assert(op.type == .Poll) + + events: linux.Fd_Poll_Events + switch op.poll.event { + case .Receive: events = { .IN } + case .Send: events = { .OUT } + } + + fd: linux.Fd + switch sock in op.poll.socket { + case TCP_Socket: fd = linux.Fd(sock) + case UDP_Socket: fd = linux.Fd(sock) + } + + enqueue(op, uring.poll_add( + &op.l.ring, + u64(uintptr(op)), + fd, + events, + {}, + )) + link_timeout(op, op.poll.expires) +} + +poll_callback :: proc(op: ^Operation, res: i32) { + if res < 0 { + errno := linux.Errno(-res) + #partial switch errno { + case .NONE: // no-op + case .ECANCELED: + op.poll.result = .Timeout + case .EINVAL, .EFAULT, .EBADF: + op.poll.result = .Invalid_Argument + case: + op.poll.result = .Error + } + + return + } + + op.poll.result = .Ready +} + +/* +`sendfile` is implemented with 2 splices over a pipe. + +Splice A: from file to pipe +Splice B: from pipe to socket (optionally linked to a timeout) + +The splices are hard-linked which means A completes before B. +B could get an `EWOULDBLOCK`, which is when the remote end has not read enough of the socket data yet. +In that case we enqueue a poll on the socket and continue when that completes. +A shouldn't get `EWOULDBLOCK`, but as a cautionary measure we handle it. + +The timeout is either linked to the splice B op, or the poll op, either of these is also always in progress in the kernel. +*/ +sendfile_exec :: proc(op: ^Operation, splice := true) { + assert(op.type == .Send_File) + + splice_done := !splice + if splice_op := op.sendfile._impl.splice; splice && splice_op != nil { + splice_done = splice_op._splice.written == splice_op._splice.len + } + + debug("sendfile_exec") + + if op.sendfile._impl.splice == nil { + // First stat for the file size. + if op.sendfile.nbytes == SEND_ENTIRE_FILE { + debug("sendfile SEND_ENTIRE_FILE, doing stat") + + stat_poly(op.sendfile.file, op, proc(stat_op: ^Operation, sendfile_op: ^Operation) { + if stat_op.stat.err != nil { + sendfile_op.sendfile.err = stat_op.stat.err + } else if stat_op.stat.type != .Regular { + sendfile_op.sendfile.err = FS_Error.Invalid_Argument + } else { + sendfile_op.sendfile.nbytes = int(i64(stat_op.stat.size) - i64(sendfile_op.sendfile.offset)) + if sendfile_op.sendfile.nbytes <= 0 { + sendfile_op.sendfile.err = FS_Error.Invalid_Argument + } + } + + if sendfile_op.sendfile.err != nil { + handle_completed(sendfile_op, 0) + return + } + + sendfile_exec(sendfile_op) + }) + return + } + + debug("sendfile setting up") + + rw: [2]linux.Fd + err := linux.pipe2(&rw, {.NONBLOCK, .CLOEXEC}) + if err != nil { + op.sendfile.err = FS_Error(err) + queue.push_back(&op.l.completed, op) + return + } + + splice_op := _prep(op.l, proc(_: ^Operation) { debug("sendfile splice helper callback") }, ._Splice) + splice_op._splice.sendfile = op + splice_op._splice.file = op.sendfile.file + splice_op._splice.pipe = rw[1] + splice_op._splice.off = op.sendfile.offset + splice_op._splice.len = op.sendfile.nbytes + + op.sendfile._impl.splice = splice_op + op.sendfile._impl.pipe = rw[0] + op.sendfile._impl.len = op.sendfile.nbytes + } + + splice_op: ^Operation + if !splice_done { + splice_op = op.sendfile._impl.splice + enqueue(splice_op, uring.splice( + &splice_op.l.ring, + u64(uintptr(splice_op)), + splice_op._splice.file, + i64(splice_op._splice.off) + i64(splice_op._splice.written), + splice_op._splice.pipe, + -1, + u32(min(splice_op._splice.len - splice_op._splice.written, MAX_RW)), + {.NONBLOCK}, + )) + } + + b, b_added := uring.splice( + &op.l.ring, + u64(uintptr(op)), + op.sendfile._impl.pipe, + -1, + linux.Fd(op.sendfile.socket), + -1, + u32(min(op.sendfile._impl.len - op.sendfile.sent, MAX_RW)), + {.NONBLOCK}, + ) + if !splice_done && b_added { + assert(splice_op._impl.sqe != nil) // if b was added successfully, a should've been too. + // Makes sure splice A (file to pipe) completes before splice B (pipe to socket). + splice_op._impl.sqe.flags += {.IO_HARDLINK} + } + enqueue(op, b, b_added) + + link_timeout(op, op.sendfile.expires) +} + +@(require_results) +splice_callback :: proc(op: ^Operation, res: i32) -> bool { + assert(op.type == ._Splice) + + if res < 0 { + errno := linux.Errno(-res) + #partial switch errno { + case .EAGAIN: + // Splice A (from file to pipe) would block, this means the buffer is full and it first needs + // to be sent over the socket by splice B (from pipe to socket). + // So we don't do anything here, once a splice B completes a new splice A will be created. + + case: + // Splice A (from file to pipe) error, we need to close the pipes, cancel the pending splice B, + // and call the callback with the error. + + debug("sendfile helper splice error, closing pipe") + + close(op._splice.pipe) + + // This is nil if this is a cancel originating from the sendfile. + // This is not nil if it is an actual error that happened on this splice. + sendfile_op := op._splice.sendfile + if sendfile_op != nil { + debug("sendfile helper splice error, cancelling main sendfile") + assert(sendfile_op.type == .Send_File) + + sendfile_op.sendfile._impl.splice = nil + sendfile_op.sendfile.err = FS_Error(errno) + } + } + + return true + } + + op._splice.written += int(res) + + sendfile_op := op._splice.sendfile + if sendfile_op != nil { + if op._splice.written < sendfile_op.sendfile.nbytes { + return false + } + + sendfile_op.sendfile._impl.splice = nil + } + + assert(op._splice.pipe > 0) + close(op._splice.pipe) + + debug("sendfile helper splice completely done") + return true +} + +@(require_results) +sendfile_callback :: proc(op: ^Operation, res: i32) -> bool { + assert(op.type == .Send_File) + + if op.sendfile.err == nil && res < 0 { + errno := linux.Errno(-res) + #partial switch errno { + case .EAGAIN: + // Splice B (from pipe to socket) would block. We are waiting on the remote to read more + // of our buffer before we can send more to it. + // We use a poll to find out when this is. + + debug("sendfile needs to poll") + + poll_op := poll_poly(op.sendfile.socket, .Send, op, proc(poll_op: ^Operation, sendfile_op: ^Operation) { + #partial switch poll_op.poll.result { + case .Ready: + // Do not enqueue a splice right away, we know there is at least one splice call worth of data in the kernel buffer. + sendfile_exec(sendfile_op, splice=false) + return + + case .Timeout: + sendfile_op.sendfile.err = TCP_Send_Error.Timeout + case: + sendfile_op.sendfile.err = TCP_Send_Error.Unknown + } + + debug("sendfile poll error") + handle_completed(sendfile_op, 0) + }) + + link_timeout(poll_op, op.sendfile.expires) + return false + + case .ECANCELED: + op.sendfile.err = TCP_Send_Error.Timeout + case: + op.sendfile.err = net._tcp_send_error(errno) + } + } + + if op.sendfile.err != nil { + debug("sendfile error") + + if op.sendfile._impl.pipe > 0 { + close(op.sendfile._impl.pipe) + } + + splice_op := op.sendfile._impl.splice + if splice_op != nil { + assert(splice_op.type == ._Splice) + splice_op._splice.sendfile = nil + _remove(splice_op) + } + + return true + } + + op.sendfile.sent += int(res) + if op.sendfile.sent < op.sendfile._impl.len { + debug("sendfile not completely done yet") + sendfile_exec(op) + if op.sendfile.progress_updates { op.cb(op) } + return false + } + + debug("sendfile completely done") + return true +} + +open_exec :: proc(op: ^Operation) { + assert(op.type == .Open) + + sys_flags := linux.Open_Flags{.NOCTTY, .CLOEXEC, .NONBLOCK} + + if .Write in op.open.mode { + if .Read in op.open.mode { + sys_flags += {.RDWR} + } else { + sys_flags += {.WRONLY} + } + } + + if .Append in op.open.mode { sys_flags += {.APPEND} } + if .Create in op.open.mode { sys_flags += {.CREAT} } + if .Excl in op.open.mode { sys_flags += {.EXCL} } + if .Sync in op.open.mode { sys_flags += {.DSYNC} } + if .Trunc in op.open.mode { sys_flags += {.TRUNC} } + // if .Inheritable in op.open.mode { sys_flags -= {.CLOEXEC} } + + cpath, err := strings.clone_to_cstring(op.open.path, op.l.allocator) + if err != nil { + op.open.err = .Allocation_Failed + queue.push_back(&op.l.completed, op) + return + } + op.open._impl.cpath = cpath + + enqueue(op, uring.openat( + &op.l.ring, + u64(uintptr(op)), + linux.Fd(op.open.dir), + op.open._impl.cpath, + transmute(linux.Mode)op.open.perm, + sys_flags, + )) +} + +open_callback :: proc(op: ^Operation, res: i32) { + assert(op.type == .Open) + + delete(op.open._impl.cpath, op.l.allocator) + + if res < 0 { + errno := linux.Errno(-res) + op.open.err = FS_Error(errno) + return + } + + op.open.handle = Handle(res) +} + +stat_exec :: proc(op: ^Operation) { + assert(op.type == .Stat) + + enqueue(op, uring.statx( + &op.l.ring, + u64(uintptr(op)), + op.stat.handle, + "", + {.EMPTY_PATH}, + {.TYPE, .SIZE}, + &op.stat._impl.buf, + )) +} + +stat_callback :: proc(op: ^Operation, res: i32) { + assert(op.type == .Stat) + + if res < 0 { + errno := linux.Errno(-res) + op.stat.err = FS_Error(errno) + return + } + + type := File_Type.Regular + switch op.stat._impl.buf.mode & linux.S_IFMT { + case linux.S_IFBLK, linux.S_IFCHR: type = .Device + case linux.S_IFDIR: type = .Directory + case linux.S_IFIFO: type = .Pipe_Or_Socket + case linux.S_IFLNK: type = .Symlink + case linux.S_IFREG: type = .Regular + case linux.S_IFSOCK: type = .Pipe_Or_Socket + } + + op.stat.type = type + op.stat.size = i64(op.stat._impl.buf.size) +} + +@(require_results) +sockaddr_storage_to_endpoint_ip :: proc(addr: ^Sock_Addr_Ip) -> (ep: Endpoint) { + #partial switch addr.family { + case .INET: + return Endpoint { + address = IP4_Address(addr.sin_addr), + port = int(addr.sin_port), + } + case .INET6: + return Endpoint { + address = IP6_Address(transmute([8]u16be)addr.sin6_addr), + port = int(addr.sin6_port), + } + case: + return {} + } +} + +@(require_results) +sockaddr_storage_to_endpoint_any :: proc(addr: ^linux.Sock_Addr_Any) -> (ep: Endpoint) { + #partial switch addr.family { + case .INET: + return Endpoint { + address = IP4_Address(addr.sin_addr), + port = int(addr.sin_port), + } + case .INET6: + return Endpoint { + address = IP6_Address(transmute([8]u16be)addr.sin6_addr), + port = int(addr.sin6_port), + } + case: + return {} + } +} + +@(require_results) +endpoint_to_sockaddr_ip :: proc(ep: Endpoint) -> (sockaddr: Sock_Addr_Ip) { + switch a in ep.address { + case IP4_Address: + sockaddr.sin_family = .INET + sockaddr.sin_port = u16be(ep.port) + sockaddr.sin_addr = cast([4]u8)a + return + case IP6_Address: + sockaddr.sin6_family = .INET6 + sockaddr.sin6_port = u16be(ep.port) + sockaddr.sin6_addr = transmute([16]u8)a + return + } + + unreachable() +} + +@(require_results) +endpoint_to_sockaddr_any :: proc(ep: Endpoint) -> (sockaddr: linux.Sock_Addr_Any) { + switch a in ep.address { + case IP4_Address: + sockaddr.sin_family = .INET + sockaddr.sin_port = u16be(ep.port) + sockaddr.sin_addr = cast([4]u8)a + return + case IP6_Address: + sockaddr.sin6_family = .INET6 + sockaddr.sin6_port = u16be(ep.port) + sockaddr.sin6_addr = transmute([16]u8)a + return + } + + unreachable() +} + +@(require_results) +ns_to_time_spec :: proc(nsec: i64) -> linux.Time_Spec { + NANOSECONDS_PER_SECOND :: 1e9 + return { + time_sec = uint(nsec / NANOSECONDS_PER_SECOND), + time_nsec = uint(nsec % NANOSECONDS_PER_SECOND), + } +} diff --git a/core/nbio/impl_others.odin b/core/nbio/impl_others.odin new file mode 100644 index 000000000..0a4564454 --- /dev/null +++ b/core/nbio/impl_others.odin @@ -0,0 +1,218 @@ +#+build !darwin +#+build !freebsd +#+build !openbsd +#+build !netbsd +#+build !linux +#+build !windows +#+private +package nbio + +import "core:container/avl" +import "core:container/pool" +import "core:container/queue" +import "core:mem" +import "core:slice" +import "core:time" + +_FULLY_SUPPORTED :: false + +_Event_Loop :: struct { + completed: queue.Queue(^Operation), + timeouts: avl.Tree(^Operation), +} + +_Handle :: uintptr + +_CWD :: Handle(-100) + +MAX_RW :: mem.Gigabyte + +_Operation :: struct { + removed: bool, +} + +_Accept :: struct {} + +_Close :: struct {} + +_Dial :: struct {} + +_Recv :: struct { + small_bufs: [1][]byte, +} + +_Send :: struct { + small_bufs: [1][]byte, +} + +_Read :: struct {} + +_Write :: struct {} + +_Timeout :: struct { + expires: time.Time, +} + +_Poll :: struct {} + +_Send_File :: struct {} + +_Open :: struct {} + +_Stat :: struct {} + +_Splice :: struct {} + +_Remove :: struct {} + +_Link_Timeout :: struct {} + +_init :: proc(l: ^Event_Loop, allocator: mem.Allocator) -> (rerr: General_Error) { + l.completed.data.allocator = allocator + + avl.init_cmp(&l.timeouts, timeouts_cmp, allocator) + + return nil + + timeouts_cmp :: #force_inline proc(a, b: ^Operation) -> slice.Ordering { + switch { + case a.timeout._impl.expires._nsec < b.timeout._impl.expires._nsec: + return .Less + case a.timeout._impl.expires._nsec > b.timeout._impl.expires._nsec: + return .Greater + case uintptr(a) < uintptr(b): + return .Less + case uintptr(a) > uintptr(b): + return .Greater + case: + assert(a == b) + return .Equal + } + } +} + +_destroy :: proc(l: ^Event_Loop) { + queue.destroy(&l.completed) + avl.destroy(&l.timeouts, false) +} + +__tick :: proc(l: ^Event_Loop, timeout: time.Duration) -> General_Error { + l.now = time.now() + + for op in queue.pop_front_safe(&l.completed) { + if !op._impl.removed { + op.cb(op) + } + if !op.detached { + pool.put(&l.operation_pool, op) + } + } + + iter := avl.iterator(&l.timeouts, .Forward) + for node in avl.iterator_next(&iter) { + op := node.value + cexpires := time.diff(l.now, op.timeout._impl.expires) + + done := cexpires <= 0 + if done { + op.cb(op) + avl.remove_node(&l.timeouts, node) + if !op.detached { + pool.put(&l.operation_pool, op) + } + continue + } + + break + } + + return nil +} + +_create_socket :: proc(l: ^Event_Loop, family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Create_Socket_Error) { + return nil, .Network_Unreachable +} + +_listen :: proc(socket: TCP_Socket, backlog := 1000) -> Listen_Error { + return .Network_Unreachable +} + +_exec :: proc(op: ^Operation) { + switch op.type { + case .Timeout: + _, _, err := avl.find_or_insert(&op.l.timeouts, op) + if err != nil { + panic("nbio: allocation failure") + } + return + case .Accept: + op.accept.err = .Network_Unreachable + case .Close: + op.close.err = .Unsupported + case .Dial: + op.dial.err = Dial_Error.Network_Unreachable + case .Recv: + switch _ in op.recv.socket { + case TCP_Socket: op.recv.err = TCP_Recv_Error.Network_Unreachable + case UDP_Socket: op.recv.err = UDP_Recv_Error.Network_Unreachable + case: op.recv.err = TCP_Recv_Error.Network_Unreachable + } + case .Send: + switch _ in op.send.socket { + case TCP_Socket: op.send.err = TCP_Send_Error.Network_Unreachable + case UDP_Socket: op.send.err = UDP_Send_Error.Network_Unreachable + case: op.send.err = TCP_Send_Error.Network_Unreachable + } + case .Send_File: + op.sendfile.err = .Network_Unreachable + case .Read: + op.read.err = .Unsupported + case .Write: + op.write.err = .Unsupported + case .Poll: + op.poll.result = .Error + case .Open: + op.open.err = .Unsupported + case .Stat: + op.stat.err = .Unsupported + case .None, ._Link_Timeout, ._Remove, ._Splice: + fallthrough + case: + unreachable() + } + + _, err := queue.push_back(&op.l.completed, op) + if err != nil { + panic("nbio: allocation failure") + } +} + +_remove :: proc(target: ^Operation) { + #partial switch target.type { + case .Timeout: + avl.remove_value(&target.l.timeouts, target) + if !target.detached { + pool.put(&target.l.operation_pool, target) + } + case: + target._impl.removed = true + } +} + +_open_sync :: proc(l: ^Event_Loop, path: string, dir: Handle, mode: File_Flags, perm: Permissions) -> (handle: Handle, err: FS_Error) { + return 0, FS_Error.Unsupported +} + +_associate_handle :: proc(handle: uintptr, l: ^Event_Loop) -> (Handle, Association_Error) { + return Handle(handle), nil +} + +_associate_socket :: proc(socket: Any_Socket, l: ^Event_Loop) -> Association_Error { + return nil +} + +_wake_up :: proc(l: ^Event_Loop) { +} + +_yield :: proc() { +} diff --git a/core/nbio/impl_posix.odin b/core/nbio/impl_posix.odin new file mode 100644 index 000000000..0d3f57e9c --- /dev/null +++ b/core/nbio/impl_posix.odin @@ -0,0 +1,1407 @@ +#+build darwin, freebsd, openbsd, netbsd +#+private file +package nbio + +import "core:c" +import "core:container/pool" +import "core:container/queue" +import "core:mem" +import "core:net" +import "core:strings" +import "core:sys/posix" +import "core:time" +import kq "core:sys/kqueue" + +@(private="package") +_FULLY_SUPPORTED :: true + +@(private="package") +_Event_Loop :: struct { + // kqueue does not permit multiple {ident, filter} pairs in the kqueue. + // We have to keep record of what we currently have in the kqueue, and if we get an operation + // that would be the same (ident, filter) pair we need to bundle the operations under one kevent. + submitted: map[Queue_Identifier]^Operation, + // Holds all events we want to flush. Flushing is done each tick at which point this is emptied. + pending: [dynamic; QUEUE_SIZE]kq.KEvent, + // Holds what should be in `pending` but didn't fit. + // When `pending`is flushed these are moved to `pending`. + overflow: queue.Queue(kq.KEvent), + // Contains all operations that were immediately completed in `exec`. + // These ops did not block so can call back next tick. + completed: queue.Queue(^Operation), + kqueue: kq.KQ, +} + +@(private="package") +_Handle :: posix.FD + +@(private="package") +_CWD :: posix.AT_FDCWD + +@(private="package") +MAX_RW :: mem.Gigabyte + +@(private="package") +_Operation :: struct { + // Linked list of operations that are bundled (same {ident, filter} pair) with this one. + next: ^Operation, + prev: ^Operation, + + flags: Operation_Flags, + result: i64, +} + +@(private="package") +_Accept :: struct {} + +@(private="package") +_Close :: struct {} + +@(private="package") +_Dial :: struct {} + +@(private="package") +_Recv :: struct { + bufs: Bufs, +} + +@(private="package") +_Send :: struct { + bufs: Bufs, +} + +@(private="package") +_Read :: struct {} + +@(private="package") +_Write :: struct {} + +@(private="package") +_Timeout :: struct {} + +@(private="package") +_Poll :: struct {} + +@(private="package") +_Send_File :: struct { + mapping: []byte, // `mmap`'d buffer (if native `sendfile` is not supported). +} + +@(private="package") +_Open :: struct {} + +@(private="package") +_Stat :: struct {} + +@(private="package") +_Splice :: struct {} + +@(private="package") +_Remove :: struct {} + +@(private="package") +_Link_Timeout :: struct {} + +@(private="package") +_init :: proc(l: ^Event_Loop, allocator: mem.Allocator) -> (rerr: General_Error) { + l.submitted.allocator = allocator + l.overflow.data.allocator = allocator + l.completed.data.allocator = allocator + + kqueue, err := kq.kqueue() + if err != nil { + return General_Error(posix.errno()) + } + + l.kqueue = kqueue + + append(&l.pending, kq.KEvent{ + ident = IDENT_WAKE_UP, + filter = .User, + flags = {.Add, .Enable, .Clear}, + }) + + return nil +} + +@(private="package") +_destroy :: proc(l: ^Event_Loop) { + delete(l.submitted) + queue.destroy(&l.overflow) + queue.destroy(&l.completed) + posix.close(l.kqueue) +} + +@(private="package") +__tick :: proc(l: ^Event_Loop, timeout: time.Duration) -> General_Error { + debug("tick") + + if n := queue.len(l.completed); n > 0 { + l.now = time.now() + debug("processing", n, "already completed") + + for _ in 0 ..< n { + op := queue.pop_front(&l.completed) + handle_completed(op) + } + + if pool.num_outstanding(&l.operation_pool) == 0 { return nil } + } + + if NBIO_DEBUG { + npending := len(l.pending) + if npending > 0 { + debug("queueing", npending, "new events, there are", int(len(l.submitted)), "events pending") + } else { + debug("there are", int(len(l.submitted)), "events pending") + } + } + + ts_backing: posix.timespec + ts_pointer: ^posix.timespec // nil means forever. + if queue.len(l.completed) == 0 && len(l.submitted) > 0 { + if timeout >= 0 { + debug("timeout", timeout) + ts_backing = {tv_sec=posix.time_t(timeout/time.Second), tv_nsec=c.long(timeout%time.Second)} + ts_pointer = &ts_backing + } else { + debug("timeout forever") + } + } else { + debug("timeout 0, there is completed work pending") + ts_pointer = &ts_backing + } + + for { + results_buf: [128]kq.KEvent + results := kevent(l, results_buf[:], ts_pointer) or_return + + clear(&l.pending) + for overflow in queue.pop_front_safe(&l.overflow) { + (append(&l.pending, overflow) != 0) or_break + } + + l.now = time.now() + + handle_results(l, results) + + if len(results) < len(results_buf) { + break + } + + debug("more events ready than our results buffer handles, getting more") + + // No timeout for the next call. + ts_backing = {} + ts_pointer = &ts_backing + } + + + return nil + + kevent :: proc(l: ^Event_Loop, buf: []kq.KEvent, ts: ^posix.timespec) -> ([]kq.KEvent, General_Error) { + for { + new_events, err := kq.kevent(l.kqueue, l.pending[:], buf, ts) + #partial switch err { + case nil: + assert(new_events >= 0) + return buf[:new_events], nil + case .EINTR: + warn("kevent interrupted") + case: + warn("kevent error") + warn(string(posix.strerror(err))) + return nil, General_Error(err) + } + } + } + + is_internal_timeout :: proc(filter: kq.Filter, op: ^Operation) -> bool { + // A `.Timeout` that `.Has_Timeout` is a `remove()`'d timeout. + return filter == .Timer && (op.type != .Timeout || .Has_Timeout in op._impl.flags) + } + + handle_results :: proc(l: ^Event_Loop, results: []kq.KEvent) { + if len(results) > 0 { + debug(len(results), "events completed") + } + + // Mark all operations that have an event returned as not `.For_Kernel`. + // We have to do this right away, or we may process an operation as if we think the kernel is responsible. + for &event in results { + if ODIN_OS != .Darwin { + // On the BSDs, a `.Delete` that results in an `.Error` does not keep the `.Delete` flag in the result. + // We only have `udata == nil` when we do a delete, so we can add it back here to keep consistent. + if .Error in event.flags && event.udata == nil { + event.flags += {.Delete} + } + } + + if .Delete in event.flags { + continue + } + + if event.filter == .User && event.ident == IDENT_WAKE_UP { + continue + } + + op := cast(^Operation)event.udata + assert(op != nil) + assert(op.type != .None) + + if is_internal_timeout(event.filter, op) { + continue + } + + _, del := delete_key(&l.submitted, Queue_Identifier{ ident = event.ident, filter = event.filter }) + assert(del != nil) + + for next := op; next != nil; next = next._impl.next { + assert(.For_Kernel in next._impl.flags) + next._impl.flags -= {.For_Kernel} + } + } + + // If we get a timeout and an actual result, ignore the timeout. + // We have to do this after the previous loop so we know if the target op of a timeout was also completed. + // We have to do this before the next loop so we handle timeouts before their target ops. Otherwise the target could already be done. + for &event in results { + if .Delete in event.flags { + continue + } + + if event.filter == .User && event.ident == IDENT_WAKE_UP { + continue + } + + op := cast(^Operation)event.udata + if is_internal_timeout(event.filter, op) { + // If the actual event has also been returned this tick, we need to ignore the timeout to not get a uaf. + if .For_Kernel not_in op._impl.flags { + assert(.Has_Timeout in op._impl.flags) + op._impl.flags -= {.Has_Timeout} + + event.filter = kq.Filter(FILTER_IGNORE) + debug(op.type, "timed out but was also completed this tick, ignoring timeout") + } + + } + } + + for event in results { + if event.filter == kq.Filter(FILTER_IGNORE) { + // Previous loop told us to ignore. + continue + } + + if event.filter == .User && event.ident == IDENT_WAKE_UP { + debug("woken up") + continue + } + + if .Delete in event.flags { + assert(.Error in event.flags) + // Seems to happen when you delete at the same time or just after a close. + debug("delete error", int(event.data)) + if err := posix.Errno(event.data); err != .ENOENT && err != .EBADF { + warn("unexpected delete error") + warn(string(posix.strerror(err))) + } + continue + } + + op := cast(^Operation)event.udata + assert(op != nil) + assert(op.type != .None) + + // Timeout result that is a non-timeout op, meaning the operation timed out. + // Because of the previous loop we are sure that the target op is not also in this tick's results. + if is_internal_timeout(event.filter, op) { + debug("got timeout for", op.type) + + assert(.Error not_in event.flags) + + assert(.Has_Timeout in op._impl.flags) + op._impl.flags -= {.Has_Timeout} + + // Remove the actual operation. + timeout_and_delete(op) + handle_completed(op) + continue + } + + // Weird loop, but we need to get the next ptr before handle_completed(curr), curr is freed in handle_completed. + for curr, next := op, op._impl.next; curr != nil; curr, next = next, next == nil ? nil : next._impl.next { + if .Error in event.flags { curr._impl.flags += {.Error} } + if .EOF in event.flags { curr._impl.flags += {.EOF} } + curr._impl.result = event.data + + // Remove refs to the list in case the operation would still block and `add_pending` + // is executed on it again. + curr._impl.prev = nil + curr._impl.next = nil + + handle_completed(curr) + } + } + } +} + +@(private="package") +_create_socket :: proc(l: ^Event_Loop, family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Create_Socket_Error) { + socket = net.create_socket(family, protocol) or_return + + berr := net.set_blocking(socket, false) + // This shouldn't be able to fail. + assert(berr == nil) + + return +} + +@(private="package") +_listen :: proc(socket: TCP_Socket, backlog := 1000) -> Listen_Error { + if res := posix.listen(posix.FD(socket), i32(backlog)); res != .OK { + return posix_listen_error() + } + return nil +} + +@(private="package") +_exec :: proc(op: ^Operation) { + assert(op.l == &_tls_event_loop) + + debug("exec", op.type) + + result: Op_Result + switch op.type { + case .Accept: + result = accept_exec(op) + case .Close: + // no-op + case .Timeout: + result = timeout_exec(op) + case .Dial: + result = dial_exec(op) + case .Recv: + result = recv_exec(op) + case .Send: + result = send_exec(op) + case .Send_File: + result = sendfile_exec(op) + case .Read: + result = read_exec(op) + case .Write: + result = write_exec(op) + case .Poll: + result = poll_exec(op) + assert(result == .Pending) + case .Open: + open_exec(op) + case .Stat: + stat_exec(op) + case .None, ._Link_Timeout, ._Remove, ._Splice: + fallthrough + case: + unreachable() + } + + switch result { + case .Pending: + // no-op, in kernel. + debug(op.type, "pending") + case .Done: + debug(op.type, "done immediately") + op._impl.flags += {.Done} + _, err := queue.push_back(&op.l.completed, op) // Got result, handle it next tick. + ensure(err == nil, "allocation failure") + } +} + +@(private="package") +_remove :: proc(target: ^Operation) { + assert(target != nil) + + debug("remove", target.type) + + if .Removed in target._impl.flags { + debug("already removed") + return + } + + target._impl.flags += {.Removed, .Has_Timeout} + link_timeout(target, target.l.now) +} + +@(private="package") +_open_sync :: proc(l: ^Event_Loop, path: string, dir: Handle, mode: File_Flags, perm: Permissions) -> (handle: Handle, err: FS_Error) { + if path == "" { + err = .Invalid_Argument + return + } + + cpath, cerr := strings.clone_to_cstring(path, l.allocator) + if cerr != nil { + err = .Allocation_Failed + return + } + defer delete(cpath, l.allocator) + + sys_flags := posix.O_Flags{.NOCTTY, .CLOEXEC, .NONBLOCK} + + if .Write in mode { + if .Read in mode { + sys_flags += {.RDWR} + } else { + sys_flags += {.WRONLY} + } + } + + if .Append in mode { sys_flags += {.APPEND} } + if .Create in mode { sys_flags += {.CREAT} } + if .Excl in mode { sys_flags += {.EXCL} } + if .Sync in mode { sys_flags += {.DSYNC} } + if .Trunc in mode { sys_flags += {.TRUNC} } + + handle = posix.openat(dir, cpath, sys_flags, transmute(posix.mode_t)posix._mode_t(transmute(u32)perm)) + if handle < 0 { + err = FS_Error(posix.errno()) + } + + return +} + +@(private="package") +_associate_handle :: proc(handle: uintptr, l: ^Event_Loop) -> (Handle, Association_Error) { + flags_ := posix.fcntl(posix.FD(handle), .GETFL) + if flags_ < 0 { + #partial switch errno := posix.errno(); errno { + case .EBADF: return -1, .Invalid_Handle + case: return -1, Association_Error(errno) + } + } + flags := transmute(posix.O_Flags)(flags_) + + if .NONBLOCK in flags { + return Handle(handle), nil + } + + if posix.fcntl(posix.FD(handle), .SETFL, flags) < 0 { + #partial switch errno := posix.errno(); errno { + case .EBADF: return -1, .Invalid_Handle + case: return -1, Association_Error(errno) + } + } + + return Handle(handle), nil +} + +@(private="package") +_associate_socket :: proc(socket: Any_Socket, l: ^Event_Loop) -> Association_Error { + if err := net.set_blocking(socket, false); err != nil { + switch err { + case .None: unreachable() + case .Network_Unreachable: return .Network_Unreachable + case .Invalid_Argument: return .Invalid_Handle + case .Unknown: fallthrough + case: return Association_Error(net.last_platform_error()) + } + } + + return nil +} + +@(private="package") +_wake_up :: proc(l: ^Event_Loop) { + // TODO: only if we are sleeping (like Windows). + ev := [1]kq.KEvent{ + { + ident = IDENT_WAKE_UP, + filter = .User, + flags = {}, + fflags = { + user = {.Trigger}, + }, + }, + } + t: posix.timespec + n, err := kq.kevent(l.kqueue, ev[:], nil, &t) + assert(err == nil) + assert(n == 0) +} + +@(private="package") +_yield :: proc() { + posix.sched_yield() +} + +// Start file private. + +// Max operations that can be enqueued per tick. +QUEUE_SIZE :: #config(ODIN_NBIO_QUEUE_SIZE, 256) + +FILTER_IGNORE :: kq.Filter(max(kq._Filter_Backing)) + +IDENT_WAKE_UP :: 69 + +Op_Result :: enum { + Done, + Pending, +} + +Operation_Flag :: enum { + Done, + Removed, + Has_Timeout, + For_Kernel, + EOF, + Error, +} +Operation_Flags :: bit_set[Operation_Flag] + +// Operations in the kqueue are uniquely identified using these 2 fields. You may not have more +// than one operation with the same identity submitted. +// So we need to keep track of the operations we have submitted, and if we add another, link it to a previously +// added operation. +Queue_Identifier :: struct { + filter: kq.Filter, + ident: uintptr, +} + +handle_completed :: proc(op: ^Operation) { + debug("handling", op.type) + + result: Op_Result + #partial switch op.type { + case .Accept: + result = accept_exec(op) + case .Dial: + result = dial_exec(op) + case .Send: + if send_exec(op) == .Done { + maybe_callback(op) + bufs_delete(&op.send._impl.bufs, op.send.bufs, op.l.allocator) + cleanup(op) + } + return + case .Recv: + if recv_exec(op) == .Done { + maybe_callback(op) + bufs_delete(&op.recv._impl.bufs, op.recv.bufs, op.l.allocator) + cleanup(op) + } + return + case .Send_File: + result = sendfile_exec(op) + case .Read: + result = read_exec(op) + case .Write: + result = write_exec(op) + case .Poll: + result = poll_exec(op) + case .Open: + open_exec(op) + case .Close: + close_exec(op) + case .Timeout, .Stat: + // no-op + case: + unimplemented() + } + + if result == .Done { + maybe_callback(op) + cleanup(op) + } + + maybe_callback :: proc(op: ^Operation) { + if .Removed not_in op._impl.flags { + debug("done", op.type, "calling back") + op.cb(op) + } else { + debug("done but removed", op.type) + } + } + + bufs_destroy :: proc(bufs: [][]byte, allocator: mem.Allocator) { + if len(bufs) > 1 { + delete(bufs, allocator) + } + } + + cleanup :: proc(op: ^Operation) { + if .Has_Timeout in op._impl.flags { + remove_link_timeout(op) + } + if !op.detached { + pool.put(&op.l.operation_pool, op) + } + } +} + +@(require_results) +accept_exec :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Accept) + + defer if op.accept.err != nil && op.accept.client > 0 { + posix.close(posix.FD(op.accept.client)) + } + + if op.accept.err != nil || .Done in op._impl.flags { + return .Done + } + + op.accept.client, op.accept.client_endpoint, op.accept.err = net.accept_tcp(op.accept.socket) + if op.accept.err != nil { + if op.accept.err == .Would_Block { + op.accept.err = nil + add_pending(op, .Read, uintptr(op.accept.socket)) + link_timeout(op, op.accept.expires) + return .Pending + } + + return .Done + } + + if err := net.set_blocking(op.accept.client, false); err != nil { + op.accept.err = posix_accept_error() + } + + return .Done +} + +@(require_results) +dial_exec :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Dial) + + defer if op.dial.err != nil && op.dial.socket > 0 { + posix.close(posix.FD(op.dial.socket)) + } + + if op.dial.err != nil || .Done in op._impl.flags { + return .Done + } + + if op.dial.socket > 0 { + // We have already called connect, retrieve potential error number only. + err: posix.Errno + size := posix.socklen_t(size_of(err)) + posix.getsockopt(posix.FD(op.dial.socket), posix.SOL_SOCKET, .ERROR, &err, &size) + if err != nil { + posix.errno(err) + op.dial.err = posix_dial_error() + } + return .Done + } + + if op.dial.endpoint.port == 0 { + op.dial.err = .Port_Required + return .Done + } + + family := family_from_endpoint(op.dial.endpoint) + osocket, socket_err := _create_socket(op.l, family, .TCP) + if socket_err != nil { + op.dial.err = socket_err + return .Done + } + + op.dial.socket = osocket.(TCP_Socket) + + sockaddr := endpoint_to_sockaddr(op.dial.endpoint) + if posix.connect(posix.FD(op.dial.socket), (^posix.sockaddr)(&sockaddr), posix.socklen_t(sockaddr.ss_len)) != .OK { + if posix.errno() == .EINPROGRESS { + add_pending(op, .Write, uintptr(op.dial.socket)) + link_timeout(op, op.dial.expires) + return .Pending + } + + op.dial.err = posix_dial_error() + return .Done + } + + return .Done +} + +@(require_results) +poll_exec :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Poll) + + if .Error in op._impl.flags { + #partial switch posix.Errno(op._impl.result) { + case .EBADF: op.poll.result = .Invalid_Argument + case: op.poll.result = .Error + } + return .Done + } + + if op._impl.result != 0 { + op.poll.result = .Ready + return .Done + } + + if op.poll.result != .Ready { + return .Done + } + + filter: kq.Filter + switch op.poll.event { + case .Receive: filter = .Read + case .Send: filter = .Write + } + + add_pending(op, filter, uintptr(net.any_socket_to_socket(op.poll.socket))) + link_timeout(op, op.poll.expires) + return .Pending +} + +close_exec :: proc(op: ^Operation) { + assert(op.type == .Close) + + if op.close.err != nil || op.close.subject == nil { + return + } + + fd: posix.FD + switch subject in op.close.subject { + case TCP_Socket: fd = posix.FD(subject) + case UDP_Socket: fd = posix.FD(subject) + case Handle: fd = posix.FD(subject) + case: op.close.err = .Invalid_Argument; return + } + + if posix.close(fd) != .OK { + op.close.err = FS_Error(posix.errno()) + } +} + +@(require_results) +send_exec :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Send) + + if op.send.err != nil || .Done in op._impl.flags { + return .Done + } + + bufs, total := bufs_to_process(&op.send._impl.bufs, op.send.bufs, op.send.sent) + sock, n := sendv(op.send.socket, bufs, op.send.endpoint) + if n < 0 { + if posix.errno() == .EWOULDBLOCK { + if !op.send.all && op.send.sent > 0 { + return .Done + } + + add_pending(op, .Write, uintptr(sock)) + link_timeout(op, op.send.expires) + return .Pending + } + + switch _ in op.send.socket { + case TCP_Socket: op.send.err = posix_tcp_send_error() + case UDP_Socket: op.send.err = posix_udp_send_error() + } + return .Done + } + + op.send.sent += n + + if n < total { + return send_exec(op) + } + + return .Done + + sendv :: proc(socket: Any_Socket, bufs: [][]byte, to: net.Endpoint) -> (posix.FD, int) { + assert(len(bufs) < int(max(i32))) + + msg: posix.msghdr + msg.msg_iov = cast([^]posix.iovec)raw_data(bufs) + msg.msg_iovlen = i32(len(bufs)) + + toaddr: posix.sockaddr_storage + fd: posix.FD + switch sock in socket { + case TCP_Socket: + fd = posix.FD(sock) + case UDP_Socket: + fd = posix.FD(sock) + toaddr = endpoint_to_sockaddr(to) + msg.msg_name = &toaddr + msg.msg_namelen = posix.socklen_t(toaddr.ss_len) + } + + return fd, posix.sendmsg(fd, &msg, {.NOSIGNAL}) + } +} + +@(require_results) +recv_exec :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Recv) + + if op.recv.err != nil || .Done in op._impl.flags { + return .Done + } + + bufs, total := bufs_to_process(&op.recv._impl.bufs, op.recv.bufs, op.recv.received) + _, is_tcp := op.recv.socket.(net.TCP_Socket) + + sock, n := recvv(op.recv.socket, bufs, &op.recv.source) + if n < 0 { + if posix.errno() == .EWOULDBLOCK { + if is_tcp && !op.recv.all && op.recv.received > 0 { + return .Done + } + + add_pending(op, .Read, uintptr(sock)) + link_timeout(op, op.recv.expires) + return .Pending + } + + if is_tcp { + op.recv.err = posix_tcp_recv_error() + } else { + op.recv.err = posix_udp_recv_error() + } + + return .Done + } + + assert(is_tcp || op.recv.received == 0) + op.recv.received += n + + if is_tcp && n != 0 && n < total { + return recv_exec(op) + } + + return .Done + + recvv :: proc(socket: Any_Socket, bufs: [][]byte, from: ^Endpoint) -> (fd: posix.FD, n: int) { + assert(len(bufs) < int(max(i32))) + + msg: posix.msghdr + msg.msg_iov = cast([^]posix.iovec)raw_data(bufs) + msg.msg_iovlen = i32(len(bufs)) + + udp: bool + fromaddr: posix.sockaddr_storage + switch sock in socket { + case TCP_Socket: + fd = posix.FD(sock) + case UDP_Socket: + fd = posix.FD(sock) + udp = true + msg.msg_name = &fromaddr + msg.msg_namelen = posix.socklen_t(size_of(fromaddr)) + } + + n = posix.recvmsg(fd, &msg, {.NOSIGNAL}) + if n >= 0 && udp { + from^ = sockaddr_to_endpoint(&fromaddr) + } + + return + } +} + +@(require_results) +sendfile_exec :: proc(op: ^Operation) -> (result: Op_Result) { + assert(op.type == .Send_File) + + defer if result == .Done && op.sendfile._impl.mapping != nil { + posix.munmap(raw_data(op.sendfile._impl.mapping), len(op.sendfile._impl.mapping)) + } + + if op.sendfile.err != nil || .Done in op._impl.flags { + return .Done + } + + when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + // Doesn't have `sendfile`, emulate it with `mmap` + normal `send`. + return sendfile_exec_emulated(op) + } else { + return sendfile_exec_native(op) + + @(require_results) + sendfile_exec_native :: proc(op: ^Operation) -> Op_Result { + nbytes := op.sendfile.nbytes + assert(nbytes != 0) + if nbytes == SEND_ENTIRE_FILE { + nbytes = 0 // special value for entire file. + + // If we want progress updates we need nbytes to be the actual size, or the user + // won't be able to check `sent < nbytes` to know if it's the final callback. + if op.sendfile.progress_updates { + stat: posix.stat_t + if posix.fstat(op.sendfile.file, &stat) != .OK { + op.sendfile.err = FS_Error(posix.errno()) + return .Done + } + op.sendfile.nbytes = int(stat.st_size - posix.off_t(op.sendfile.offset)) + } + } else { + nbytes -= op.sendfile.sent + } + + n, ok := posix_sendfile(op.sendfile.file, op.sendfile.socket, op.sendfile.offset + op.sendfile.sent, nbytes) + + assert(n >= 0) + op.sendfile.sent += n + + if !ok { + op.sendfile.err = posix_tcp_send_error() + if op.sendfile.err == .Would_Block { + op.sendfile.err = nil + if op.sendfile.progress_updates { op.cb(op) } + add_pending(op, .Write, uintptr(op.sendfile.socket)) + link_timeout(op, op.sendfile.expires) + return .Pending + } + + return .Done + } + + assert(op.sendfile.nbytes == SEND_ENTIRE_FILE || op.sendfile.sent == op.sendfile.nbytes) + return .Done + } + } + + @(require_results) + sendfile_exec_emulated :: proc(op: ^Operation) -> Op_Result { + if op.sendfile.nbytes == SEND_ENTIRE_FILE { + stat: posix.stat_t + if posix.fstat(op.sendfile.file, &stat) != .OK { + op.sendfile.err = FS_Error(posix.errno()) + return .Done + } + op.sendfile.nbytes = int(stat.st_size - posix.off_t(op.sendfile.offset)) + } + + if op.sendfile._impl.mapping == nil { + addr := posix.mmap(nil, uint(op.sendfile.nbytes), {.READ}, {}, op.sendfile.file, posix.off_t(op.sendfile.offset)) + if addr == posix.MAP_FAILED { + op.sendfile.err = FS_Error(posix.errno()) + return .Done + } + op.sendfile._impl.mapping = ([^]byte)(addr)[:op.sendfile.nbytes] + } + + n := posix.send( + posix.FD(op.sendfile.socket), + raw_data(op.sendfile._impl.mapping)[op.sendfile.sent:], + uint(min(MAX_RW, op.sendfile.nbytes - op.sendfile.sent)), + {.NOSIGNAL}, + ) + if n < 0 { + op.sendfile.err = posix_tcp_send_error() + if op.sendfile.err == .Would_Block { + op.sendfile.err = nil + add_pending(op, .Write, uintptr(op.sendfile.socket)) + link_timeout(op, op.sendfile.expires) + return .Pending + } + + return .Done + } + + op.sendfile.sent += n + + if op.sendfile.sent < op.sendfile.nbytes { + if op.sendfile.progress_updates { op.cb(op) } + return sendfile_exec_emulated(op) + } + + return .Done + } +} + +@(require_results) +read_exec :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Read) + + if op.read.err != nil || .Done in op._impl.flags { + return .Done + } + + to_read := op.read.buf[op.read.read:] + to_read = to_read[:min(MAX_RW, len(to_read))] + + res := posix.pread(op.read.handle, raw_data(to_read), len(to_read), posix.off_t(op.read.offset) + posix.off_t(op.read.read)) + if res < 0 { + errno := posix.errno() + if errno == .EWOULDBLOCK { + if !op.read.all && op.read.read > 0 { + return .Done + } + + add_pending(op, .Read, uintptr(op.read.handle)) + link_timeout(op, op.read.expires) + return .Pending + } + + op.read.err = FS_Error(errno) + return .Done + } else if res == 0 { + if op.read.read == 0 { + op.read.err = .EOF + } + return .Done + } + + op.read.read += res + + if op.read.read < len(op.read.buf) { + return read_exec(op) + } + + return .Done +} + +@(require_results) +write_exec :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Write) + + if op.write.err != nil || .Done in op._impl.flags { + return .Done + } + + to_write := op.write.buf[op.write.written:] + to_write = to_write[:min(MAX_RW, len(to_write))] + + res := posix.pwrite(op.write.handle, raw_data(to_write), len(to_write), posix.off_t(op.write.offset) + posix.off_t(op.write.written)) + if res < 0 { + errno := posix.errno() + if errno == .EWOULDBLOCK { + if !op.write.all && op.write.written > 0 { + return .Done + } + + add_pending(op, .Write, uintptr(op.write.handle)) + link_timeout(op, op.write.expires) + return .Pending + } + + op.write.err = FS_Error(errno) + return .Done + } + + op.write.written += res + + if op.write.written < len(op.write.buf) { + return write_exec(op) + } + + return .Done +} + +timeout_exec :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Timeout) + + if op.timeout.duration <= 0 { + return .Done + } + + op.l.submitted[Queue_Identifier{ ident = uintptr(op), filter = .Timer }] = op + + op._impl.flags += {.For_Kernel} + + append_pending(op.l, kq.KEvent { + ident = uintptr(op), + filter = .Timer, + flags = {.Add, .Enable, .One_Shot}, + fflags = { + timer = kq.TIMER_FLAGS_NSECONDS + {.Absolute}, + }, + data = op.l.now._nsec + i64(op.timeout.duration), + udata = op, + }) + return .Pending +} + +open_exec :: proc(op: ^Operation) { + assert(op.type == .Open) + + if op.open.err != nil && op.open.handle > 0 { + posix.close(op.open.handle) + return + } + + if .Done in op._impl.flags { + return + } + + op.open.handle, op.open.err = _open_sync(op.l, op.open.path, op.open.dir, op.open.mode, op.open.perm) +} + +stat_exec :: proc(op: ^Operation) { + assert(op.type == .Stat) + + stat: posix.stat_t + if posix.fstat(op.stat.handle, &stat) != .OK { + op.stat.err = FS_Error(posix.errno()) + return + } + + op.stat.type = .Undetermined + switch { + case posix.S_ISBLK(stat.st_mode) || posix.S_ISCHR(stat.st_mode): + op.stat.type = .Device + case posix.S_ISDIR(stat.st_mode): + op.stat.type = .Directory + case posix.S_ISFIFO(stat.st_mode) || posix.S_ISSOCK(stat.st_mode): + op.stat.type = .Pipe_Or_Socket + case posix.S_ISLNK(stat.st_mode): + op.stat.type = .Symlink + case posix.S_ISREG(stat.st_mode): + op.stat.type = .Regular + } + + op.stat.size = i64(stat.st_size) +} + +add_pending :: proc(op: ^Operation, filter: kq.Filter, ident: uintptr) { + debug("adding pending", op.type) + assert(op._impl.next == nil) + assert(op._impl.prev == nil) + op._impl.flags += {.For_Kernel} + + _, val, just_inserted, err := map_entry(&op.l.submitted, Queue_Identifier{ ident = ident, filter = filter }) + ensure(err == nil, "allocation failure") + if just_inserted { + val^ = op + + append_pending(op.l, kq.KEvent { + filter = filter, + ident = ident, + flags = {.Add, .Enable, .One_Shot}, + udata = op, + }) + } else { + debug("already have this operation on the kqueue, bundling it") + + last := val^ + for last._impl.next != nil { + last = last._impl.next + } + last._impl.next = op + op._impl.prev = last + } +} + +append_pending :: #force_inline proc(l: ^Event_Loop, ev: kq.KEvent) { + if append(&l.pending, ev) == 0 { + warn("queue is full, adding to overflow, should QUEUE_SIZE be increased?") + _, err := queue.append(&l.overflow, ev) + ensure(err == nil, "allocation failure") + } +} + +link_timeout :: proc(op: ^Operation, expires: time.Time) { + if expires == {} { + return + } + + debug(op.type, "times out at", expires) + + op._impl.flags += {.Has_Timeout} + + append_pending(op.l, kq.KEvent { + ident = uintptr(op), + filter = .Timer, + flags = {.Add, .Enable, .One_Shot}, + fflags = { + timer = kq.TIMER_FLAGS_NSECONDS + {.Absolute}, + }, + data = expires._nsec, + udata = op, + }) +} + +remove_link_timeout :: proc(op: ^Operation) { + debug("removing timeout of", op.type) + assert(.Has_Timeout in op._impl.flags) + + append_pending(op.l, kq.KEvent { + ident = uintptr(op), + filter = .Timer, + flags = {.Delete, .Disable, .One_Shot}, + }) +} + +timeout_and_delete :: proc(target: ^Operation) { + filter: kq.Filter + ident: uintptr + switch target.type { + case .Accept: + target.accept.err = .Timeout + filter = .Read + ident = uintptr(target.accept.socket) + case .Dial: + target.dial.err = Dial_Error.Timeout + filter = .Write + ident = uintptr(target.dial.socket) + case .Read: + target.read.err = .Timeout + filter = .Read + ident = uintptr(target.read.handle) + case .Write: + target.write.err = .Timeout + filter = .Write + ident = uintptr(target.write.handle) + case .Recv: + switch sock in target.recv.socket { + case TCP_Socket: + target.recv.err = TCP_Recv_Error.Timeout + ident = uintptr(sock) + case UDP_Socket: + target.recv.err = UDP_Recv_Error.Timeout + ident = uintptr(sock) + } + filter = .Read + case .Send: + switch sock in target.send.socket { + case TCP_Socket: + target.send.err = TCP_Send_Error.Timeout + ident = uintptr(sock) + case UDP_Socket: + target.send.err = UDP_Send_Error.Timeout + ident = uintptr(sock) + } + filter = .Write + case .Send_File: + target.send.err = TCP_Send_Error.Timeout + filter = .Write + ident = uintptr(target.sendfile.socket) + case .Poll: + target.poll.result = .Timeout + ident = uintptr(net.any_socket_to_socket(target.poll.socket)) + + switch target.poll.event { + case .Receive: filter = .Read + case .Send: filter = .Write + } + + case .Timeout: + ident = uintptr(target) + filter = .Timer + + case .Close: + target.close.err = .Timeout + return + + case .Open: + target.open.err = .Timeout + return + + case .Stat: + target.stat.err = .Timeout + return + + case .None, ._Link_Timeout, ._Remove, ._Splice: + return + } + + // If there are other ops linked to this kevent, don't remove it. + if target._impl.next != nil || target._impl.prev != nil { + debug("removing target by pulling it out of the linked list, other ops depend on the kevent") + assert(filter != .Timer) + + if target._impl.next != nil { + target._impl.next._impl.prev = target._impl.prev + } + + if target._impl.prev != nil { + target._impl.prev._impl.next = target._impl.next + } else { + debug("target was the head of the list, updating map to point at new head") + + _, vp, _, err := map_entry(&target.l.submitted, Queue_Identifier{ ident = ident, filter = filter }) + ensure(err == nil, "allocation failure") + assert(vp^ == target) + vp^ = target._impl.next + + ev := kq.KEvent{ + filter = filter, + ident = ident, + flags = {.Add, .Enable, .One_Shot}, + udata = target._impl.next, + } + if append(&target.l.pending, ev) == 0 { + warn("just removed the head operation of a list of multiple, and the queue is full, have to force this update through inefficiently") + // This has to happen the next time we submit or we could have udata pointing wrong. + // Very inefficient but probably never hit. + + // Makes kevent return a receipt for our addition, so we don't take any new events from it. + // This forces .Error to be added and data being 0 means it's added. + ev.flags += {.Receipt} + + timeout: posix.timespec + n, err := kq.kevent(target.l.kqueue, ([^]kq.KEvent)(&ev)[:1], ([^]kq.KEvent)(&ev)[:1], &timeout) + assert(n == 1) + assert(err == nil) + + // The receipt flag makes this occur on the event. + assert(.Error in ev.flags) + assert(ev.data == 0) + } + } + + } else if .For_Kernel in target._impl.flags { + debug("adding delete event") + + _, dval := delete_key(&target.l.submitted, Queue_Identifier{ ident = ident, filter = filter }) + assert(dval != nil) + + append_pending(target.l, kq.KEvent{ + ident = ident, + filter = filter, + flags = {.Delete, .Disable, .One_Shot}, + }) + } else { + debug("remove without delete event, because target is not in kernel") + } +} + +@(require_results) +endpoint_to_sockaddr :: proc(ep: Endpoint) -> (sockaddr: posix.sockaddr_storage) { + switch a in ep.address { + case IP4_Address: + (^posix.sockaddr_in)(&sockaddr)^ = posix.sockaddr_in { + sin_port = u16be(ep.port), + sin_addr = transmute(posix.in_addr)a, + sin_family = .INET, + sin_len = size_of(posix.sockaddr_in), + } + return + case IP6_Address: + (^posix.sockaddr_in6)(&sockaddr)^ = posix.sockaddr_in6 { + sin6_port = u16be(ep.port), + sin6_addr = transmute(posix.in6_addr)a, + sin6_family = .INET6, + sin6_len = size_of(posix.sockaddr_in6), + } + return + } + unreachable() +} + +@(require_results) +sockaddr_to_endpoint :: proc(native_addr: ^posix.sockaddr_storage) -> (ep: Endpoint) { + #partial switch native_addr.ss_family { + case .INET: + addr := cast(^posix.sockaddr_in)native_addr + port := int(addr.sin_port) + ep = Endpoint { + address = IP4_Address(transmute([4]byte)addr.sin_addr), + port = port, + } + case .INET6: + addr := cast(^posix.sockaddr_in6)native_addr + port := int(addr.sin6_port) + ep = Endpoint { + address = IP6_Address(transmute([8]u16be)addr.sin6_addr), + port = port, + } + case: + panic("native_addr is neither IP4 or IP6 address") + } + return +} diff --git a/core/nbio/impl_posix_darwin.odin b/core/nbio/impl_posix_darwin.odin new file mode 100644 index 000000000..7ec64c2df --- /dev/null +++ b/core/nbio/impl_posix_darwin.odin @@ -0,0 +1,29 @@ +#+private +package nbio + +import "core:net" +import "core:sys/posix" + +foreign import lib "system:System" + +posix_sendfile :: proc(fd: Handle, s: TCP_Socket, offset, nbytes: int) -> (sent: int, ok := true) { + foreign lib { + @(link_name="sendfile") + _posix_sendfile :: proc (fd, s: posix.FD, offset: posix.off_t, len: ^posix.off_t, hdtr: rawptr, flags: i32) -> posix.result --- + } + + len := posix.off_t(nbytes) + if _posix_sendfile(posix.FD(fd), posix.FD(s), posix.off_t(offset), &len, nil, 0) != .OK { + ok = false + } + sent = int(len) + return +} + +posix_listen_error :: net._listen_error +posix_accept_error :: net._accept_error +posix_dial_error :: net._dial_error +posix_tcp_send_error :: net._tcp_send_error +posix_udp_send_error :: net._udp_send_error +posix_tcp_recv_error :: net._tcp_recv_error +posix_udp_recv_error :: net._udp_recv_error diff --git a/core/nbio/impl_posix_freebsd.odin b/core/nbio/impl_posix_freebsd.odin new file mode 100644 index 000000000..50089510b --- /dev/null +++ b/core/nbio/impl_posix_freebsd.odin @@ -0,0 +1,52 @@ +#+private +package nbio + +import "core:net" +import "core:sys/posix" +import "core:sys/freebsd" + +foreign import lib "system:c" + +// TODO: rewrite freebsd implementation to use `sys/freebsd` instead of `sys/posix`. + +posix_sendfile :: proc(fd: Handle, s: TCP_Socket, offset, nbytes: int) -> (sent: int, ok := true) { + foreign lib { + @(link_name="sendfile") + _posix_sendfile :: proc (fd, s: posix.FD, offset: posix.off_t, nbytes: uint, hdtr: rawptr, sbytes: ^posix.off_t, flags: i32) -> posix.result --- + } + + len: posix.off_t + if _posix_sendfile(posix.FD(fd), posix.FD(s), posix.off_t(offset), uint(nbytes), nil, &len, 0) != .OK { + ok = false + } + sent = int(len) + return +} + +posix_listen_error :: proc() -> Listen_Error { + return net._listen_error(freebsd.Errno(posix.errno())) +} + +posix_accept_error :: proc() -> Accept_Error { + return net._accept_error(freebsd.Errno(posix.errno())) +} + +posix_dial_error :: proc() -> Dial_Error { + return net._dial_error(freebsd.Errno(posix.errno())) +} + +posix_tcp_send_error :: proc() -> TCP_Send_Error { + return net._tcp_send_error(freebsd.Errno(posix.errno())) +} + +posix_udp_send_error :: proc() -> UDP_Send_Error { + return net._udp_send_error(freebsd.Errno(posix.errno())) +} + +posix_tcp_recv_error :: proc() -> TCP_Recv_Error { + return net._tcp_recv_error(freebsd.Errno(posix.errno())) +} + +posix_udp_recv_error :: proc() -> UDP_Recv_Error { + return net._udp_recv_error(freebsd.Errno(posix.errno())) +} diff --git a/core/nbio/impl_posix_netbsd.odin b/core/nbio/impl_posix_netbsd.odin new file mode 100644 index 000000000..a0e2652f4 --- /dev/null +++ b/core/nbio/impl_posix_netbsd.odin @@ -0,0 +1,12 @@ +#+private +package nbio + +import "core:net" + +posix_listen_error :: net._listen_error +posix_accept_error :: net._accept_error +posix_dial_error :: net._dial_error +posix_tcp_send_error :: net._tcp_send_error +posix_udp_send_error :: net._udp_send_error +posix_tcp_recv_error :: net._tcp_recv_error +posix_udp_recv_error :: net._udp_recv_error diff --git a/core/nbio/impl_posix_openbsd.odin b/core/nbio/impl_posix_openbsd.odin new file mode 100644 index 000000000..a0e2652f4 --- /dev/null +++ b/core/nbio/impl_posix_openbsd.odin @@ -0,0 +1,12 @@ +#+private +package nbio + +import "core:net" + +posix_listen_error :: net._listen_error +posix_accept_error :: net._accept_error +posix_dial_error :: net._dial_error +posix_tcp_send_error :: net._tcp_send_error +posix_udp_send_error :: net._udp_send_error +posix_tcp_recv_error :: net._tcp_recv_error +posix_udp_recv_error :: net._udp_recv_error diff --git a/core/nbio/impl_windows.odin b/core/nbio/impl_windows.odin new file mode 100644 index 000000000..adf2d5351 --- /dev/null +++ b/core/nbio/impl_windows.odin @@ -0,0 +1,1848 @@ +#+private file +package nbio + +import "base:intrinsics" + +import "core:container/avl" +import "core:container/pool" +import "core:container/queue" +import "core:mem" +import "core:net" +import "core:path/filepath" +import "core:slice" +import "core:strings" +import "core:sync" +import "core:time" + +import win "core:sys/windows" + +@(private="package") +_FULLY_SUPPORTED :: true + +@(private="package") +_Event_Loop :: struct { + timeouts: avl.Tree(^Operation), + thread: win.HANDLE, + completed: queue.Queue(^Operation), + completed_oob: Multi_Producer_Single_Consumer, + state: enum { + Working, + Waking, + Sleeping, + }, +} + +@(private="package") +_Handle :: distinct uintptr + +@(private="package") +_CWD :: ~_Handle(99) + +@(private="package") +MAX_RW :: mem.Gigabyte + +@(private="package") +_Operation :: struct { + over: win.OVERLAPPED, + timeout: ^Operation, +} + +@(private="package") +_Accept :: struct { + // Space that gets the local and remote address written into it. + addrs: [(size_of(win.sockaddr_in6)+16)*2]byte, +} + +@(private="package") +_Close :: struct {} + +@(private="package") +_Dial :: struct { + addr: win.SOCKADDR_STORAGE_LH, +} + +@(private="package") +_Read :: struct {} + +@(private="package") +_Write :: struct {} + +@(private="package") +_Send :: struct { + bufs: Bufs, +} + +@(private="package") +_Recv :: struct { + source: win.SOCKADDR_STORAGE_LH, + source_len: win.INT, + flags: win.DWORD, + bufs: Bufs, +} + +@(private="package") +_Timeout :: struct { + expires: time.Time, + target: ^Operation, +} + +@(private="package") +_Poll :: struct { + wait_handle: win.HANDLE, +} + +@(private="package") +_Send_File :: struct {} + +@(private="package") +_Remove :: struct {} + +@(private="package") +_Link_Timeout :: struct {} + +@(private="package") +_Splice :: struct {} + +@(private="package") +_Open :: struct {} + +@(private="package") +_Stat :: struct {} + +@(private="package") +_init :: proc(l: ^Event_Loop, alloc: mem.Allocator) -> (err: General_Error) { + l.allocator = alloc + + l.completed.data.allocator = l.allocator + + avl.init(&l.timeouts, timeouts_cmp, alloc) + + mpsc_init(&l.completed_oob, QUEUE_SIZE, l.allocator) + defer if err != nil { mpsc_destroy(&l.completed_oob, l.allocator) } + + dup_ok := win.DuplicateHandle( + win.GetCurrentProcess(), win.GetCurrentThread(), + win.GetCurrentProcess(), &l.thread, + 0, false, win.DUPLICATE_SAME_ACCESS, + ) + ensure(dup_ok == true) + defer if err != nil { win.CloseHandle(l.thread) } + + err = g_ref() + return +} + +@(private="package") +_destroy :: proc(l: ^Event_Loop) { + avl.destroy(&l.timeouts) + queue.destroy(&l.completed) + mpsc_destroy(&l.completed_oob, l.allocator) + win.CloseHandle(l.thread) + g_unref() +} + +@(private="package") +__tick :: proc(l: ^Event_Loop, timeout: time.Duration) -> (err: General_Error) { + debug("tick") + + l.now = time.now() + next_timeout := check_timeouts(l) + + // Prevent infinite loop when callback adds to completed by storing length. + n := queue.len(l.completed) + if n > 0 { + for _ in 0 ..< n { + op := queue.pop_front(&l.completed) + handle_completed(op) + } + } + + for { + op := (^Operation)(mpsc_dequeue(&l.completed_oob)) + if op == nil { break } + handle_completed(op) + } + + if pool.num_outstanding(&l.operation_pool) == 0 { return nil } + + actual_timeout := win.INFINITE + if queue.len(l.completed) > 0 || mpsc_count(&l.completed_oob) > 0 { + actual_timeout = 0 + } else if timeout >= 0 { + actual_timeout = win.DWORD(timeout / time.Millisecond) + } + if nt, ok := next_timeout.?; ok { + actual_timeout = min(actual_timeout, win.DWORD(nt / time.Millisecond)) + } + + if actual_timeout > 0 { + sync.atomic_store_explicit(&l.state, .Sleeping, .Release) + + // There could be a race condition where we go sleeping at the same time as things get queued + // and a wakeup isn't done because the state is not .Sleeping yet. + // So after sleeping we first check our queues. + + for { + op := (^Operation)(mpsc_dequeue(&l.queue)) + if op == nil { break } + _exec(op) + } + + for { + op := (^Operation)(mpsc_dequeue(&l.completed_oob)) + if op == nil { break } + handle_completed(op) + } + } + + for { + events: [256]win.OVERLAPPED_ENTRY + entries_removed: win.ULONG + if !win.GetQueuedCompletionStatusEx(g.iocp, &events[0], len(events), &entries_removed, actual_timeout, true) { + winerr := win.GetLastError() + switch winerr { + case win.WAIT_TIMEOUT, win.WAIT_IO_COMPLETION: + entries_removed = 0 + case: + err = General_Error(winerr) + return + } + } + + sync.atomic_store_explicit(&l.state, .Working, .Relaxed) + + if actual_timeout > 0 { + // We may have just waited some time, lets update the current time. + l.now = time.now() + } + + if entries_removed > 0 { + debug(int(entries_removed), "operations were completed") + } + + for event in events[:entries_removed] { + assert(event.lpOverlapped != nil) + op := container_of(container_of(event.lpOverlapped, _Operation, "over"), Operation, "_impl") + + if op.l == l { + handle_completed(op) + } else { + op_l := op.l + for !mpsc_enqueue(&op.l.completed_oob, op) { + warn("oob queue filled up, QUEUE_SIZE may need increasing") + _wake_up(op_l) + win.SwitchToThread() + } + _wake_up(op_l) + } + } + + if entries_removed < len(events) { + break + } + + // `events` was filled up, get more. + debug("GetQueuedCompletionStatusEx filled entire events buffer, getting more") + actual_timeout = 0 + } + + return nil + + check_timeouts :: proc(l: ^Event_Loop) -> (expires: Maybe(time.Duration)) { + curr := l.now + + if avl.len(&l.timeouts) == 0 { + return + } + + debug(avl.len(&l.timeouts), "timeouts", "threshold", curr) + + iter := avl.iterator(&l.timeouts, .Forward) + for node in avl.iterator_next(&iter) { + op := node.value + cexpires := time.diff(curr, op.timeout._impl.expires) + + debug("expires after", cexpires) + + removed := op._impl.timeout == (^Operation)(REMOVED) + done := cexpires <= 0 + if removed { + debug("timeout removed!") + } else if done { + debug("timeout done!") + handle_completed(op) + } + if removed || done { + avl.remove_node(&l.timeouts, node) + continue + } + + break + } + + // Don't merge this with the previous iteration because the `handle_completed` in that one might queue + // more timeouts which we want to detect here. + // For example: `timeout(time.Second, proc(_: ^Operation) { timeout(time.Second, ...) })` + + first := avl.first(&l.timeouts) + if first != nil { + op := first.value + cexpires := time.diff(curr, op.timeout._impl.expires) + debug("first timeout in the future is at", op.timeout._impl.expires, "after", cexpires) + expires = cexpires + } + return + } + + handle_completed :: proc(op: ^Operation) { + debug("handling", op.type) + + if op._impl.timeout == (^Operation)(REMOVED) { + debug(op.type, "was removed") + + // Set an error, and call the internal callback. + // This way resources are cleaned up properly, for example the result socket for dial. + // If we just do nothing it will be leaked. + + if op._impl.over.Internal == nil { + // There is no error from the kernel, set one ourselves. + // This needs to be an NTSTATUS code, not a win32 error number. + STATUS_REQUEST_ABORTED :: 0xC023000C + op._impl.over.Internal = (^win.c_ulong)(uintptr(STATUS_REQUEST_ABORTED)) + } + } + + result := Op_Result.Done + switch op.type { + case .Read: + result = read_callback(op) + case .Recv: + result = recv_callback(op) + if result == .Done { + maybe_callback(op) + bufs_delete(&op.recv._impl.bufs, op.recv.bufs, op.l.allocator) + cleanup(op) + return + } + case .Write: + result = write_callback(op) + case .Send: + result = send_callback(op) + if result == .Done { + maybe_callback(op) + bufs_delete(&op.send._impl.bufs, op.send.bufs, op.l.allocator) + cleanup(op) + return + } + case .Send_File: + result = sendfile_callback(op) + case .Accept: + accept_callback(op) + case .Dial: + dial_callback(op) + case .Poll: + poll_callback(op) + case .Timeout, .Open, .Stat, .Close: + // no-op. + case .None, ._Link_Timeout, ._Remove, ._Splice: + fallthrough + case: + unreachable() + } + + if result == .Pending { + assert(op._impl.timeout != (^Operation)(REMOVED)) + debug(op.type, "pending") + return + } + + maybe_callback(op) + cleanup(op) + + maybe_callback :: proc(op: ^Operation) { + if op._impl.timeout == (^Operation)(REMOVED) { + debug(op.type, "done but removed") + } else { + debug(op.type, "done") + op.cb(op) + + if op._impl.timeout != nil { + debug("cancelling timeout of", op.type) + op._impl.timeout.timeout._impl.target = nil + _remove(op._impl.timeout) + } + } + } + + cleanup :: proc(op: ^Operation) { + if !op.detached { + pool.put(&op.l.operation_pool, op) + } + } + } + +} + +@(private="package") +_exec :: proc(op: ^Operation) { + assert(op.l == &_tls_event_loop) + + result: Op_Result + switch op.type { + case .Accept: result = accept_exec(op) + case .Close: close_exec(op); result = .Done + case .Dial: result = dial_exec(op) + case .Recv: result = recv_exec(op) + case .Send: result = send_exec(op) + case .Send_File: result = sendfile_exec(op) + case .Read: result = read_exec(op) + case .Write: result = write_exec(op) + case .Timeout: result = timeout_exec(op) + case .Poll: result = poll_exec(op) + case .Open: open_exec(op); result = .Done + case .Stat: stat_exec(op); result = .Done + case .None, ._Link_Timeout, ._Remove, ._Splice: + unreachable() + } + + switch result { + case .Pending: + // no-op, in kernel. + debug("exec", op.type, "pending") + case .Done: + debug("exec", op.type, "done immediately") + _, err := queue.append(&op.l.completed, op) // Got result, handle it next tick. + ensure(err == nil, "allocation failure") + } +} + +@(private="package") +_open_sync :: proc(l: ^Event_Loop, name: string, dir: Handle, mode: File_Flags, perm: Permissions) -> (handle: Handle, err: FS_Error) { + if len(name) == 0 { + err = .Invalid_Argument + return + } + + dir := dir + + is_abs := filepath.is_abs(name) + is_cwd: bool + cwd_path: win.wstring + if !is_abs && dir == CWD { + is_cwd = true + + cwd_len := win.GetCurrentDirectoryW(0, nil) + assert(cwd_len > 0) + cwd_buf, cwd_err := make([]u16, cwd_len, l.allocator) + if cwd_err != nil { return INVALID_HANDLE, .Allocation_Failed } + cwd_len = win.GetCurrentDirectoryW(cwd_len, raw_data(cwd_buf)) + assert(int(cwd_len) == len(cwd_buf)-1) + cwd_path = win.wstring(raw_data(cwd_buf)) + + dir = Handle(win.CreateFileW( + cwd_path, + win.GENERIC_READ, + win.FILE_SHARE_READ|win.FILE_SHARE_WRITE, + nil, + win.OPEN_EXISTING, + win.FILE_FLAG_BACKUP_SEMANTICS, + nil, + )) + if dir == INVALID_HANDLE { + err = FS_Error(win.GetLastError()) + return + } + } + defer if is_cwd { + delete(cwd_path, l.allocator) + win.CloseHandle(win.HANDLE(dir)) + } + + path, was_alloc := _normalize_path(name, l.allocator) + defer if was_alloc { delete(path, l.allocator) } + + wpath := win.utf8_to_utf16(path, l.allocator) + defer delete(wpath, l.allocator) + + if path == "" || wpath == nil { + return INVALID_HANDLE, .Allocation_Failed + } + + path_len := len(wpath) * 2 + if path_len > int(max(u16)) { + err = .Invalid_Argument + return + } + + access: u32 + switch mode & {.Read, .Write} { + case {.Read}: access = win.FILE_GENERIC_READ + case {.Write}: access = win.FILE_GENERIC_WRITE + case {.Read, .Write}: access = win.FILE_GENERIC_READ | win.FILE_GENERIC_WRITE + } + + if .Create in mode { + access |= win.FILE_GENERIC_WRITE + } + if .Append in mode { + access &~= win.FILE_GENERIC_WRITE + access |= win.FILE_APPEND_DATA + } + share_mode := u32(win.FILE_SHARE_READ | win.FILE_SHARE_WRITE) + + create_mode: u32 = win.FILE_OPEN + switch { + case mode & {.Create, .Excl} == {.Create, .Excl}: + create_mode = win.FILE_CREATE + case mode & {.Create, .Trunc} == {.Create, .Trunc}: + create_mode = win.FILE_OVERWRITE_IF + case mode & {.Create} == {.Create}: + create_mode = win.FILE_OPEN_IF + case mode & {.Trunc} == {.Trunc}: + create_mode = win.FILE_OVERWRITE + } + + attrs: u32 = win.FILE_ATTRIBUTE_NORMAL + + if .Write_User not_in perm { + attrs = win.FILE_ATTRIBUTE_READONLY + if create_mode == win.FILE_OVERWRITE_IF { + // NOTE(bill): Open has just asked to create a file in read-only mode. + // If the file already exists, to make it akin to a *nix open call, + // the call preserves the existing permissions. + + h: win.HANDLE + io_status: win.IO_STATUS_BLOCK + status := win.NtCreateFile( + &h, + access, + &{ + Length = size_of(win.OBJECT_ATTRIBUTES), + RootDirectory = is_abs ? nil : win.HANDLE(dir), + ObjectName = &{ + Length = u16(path_len), + MaximumLength = u16(path_len), + Buffer = raw_data(wpath), + }, + }, + &io_status, + nil, + win.FILE_ATTRIBUTE_NORMAL, + share_mode, + win.FILE_OVERWRITE, + 0, + nil, + 0, + ) + syserr := win.System_Error(win.RtlNtStatusToDosError(status)) + #partial switch syserr { + case .FILE_NOT_FOUND, .BAD_NETPATH, .PATH_NOT_FOUND: + // File does not exists, create the file + case .SUCCESS: + association_err: Association_Error + handle, association_err = _associate_handle(uintptr(h), l) + // This shouldn't fail, we just created this file, with correct flags. + assert(association_err != nil) + return + case: + err = FS_Error(syserr) + return + } + } + } + + h: win.HANDLE + io_status: win.IO_STATUS_BLOCK + status := win.NtCreateFile( + &h, + access, + &{ + Length = size_of(win.OBJECT_ATTRIBUTES), + RootDirectory = is_abs ? nil : win.HANDLE(dir), + ObjectName = &{ + Length = u16(path_len), + MaximumLength = u16(path_len), + Buffer = raw_data(wpath), + }, + }, + &io_status, + nil, + attrs, + share_mode, + create_mode, + 0, + nil, + 0, + ) + syserr := win.System_Error(win.RtlNtStatusToDosError(status)) + #partial switch syserr { + case .SUCCESS: + association_err: Association_Error + handle, association_err = _associate_handle(uintptr(h), l) + // This shouldn't fail, we just created this file, with correct flags. + assert(association_err == nil) + return + case: + err = FS_Error(syserr) + return + } + + @(require_results) + _normalize_path :: proc(path: string, allocator := context.allocator) -> (fixed: string, allocated: bool) { + // An UNC path or relative, just replace slashes. + if strings.has_prefix(path, `\\`) || !filepath.is_abs(path) { + return strings.replace_all(path, `/`, `\`) + } + + path_buf, err := make([]byte, len(PREFIX)+len(path)+1, allocator) + if err != nil { return } + defer if !allocated { delete(path_buf, allocator) } + + PREFIX :: `\??` + copy(path_buf, PREFIX) + n := len(path) + r, w := 0, len(PREFIX) + for r < n { + switch { + case filepath.is_separator(path[r]): + r += 1 + case path[r] == '.' && (r+1 == n || filepath.is_separator(path[r+1])): + // \.\ + r += 1 + case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || filepath.is_separator(path[r+2])): + // Skip \..\ paths + return path, false + case: + path_buf[w] = '\\' + w += 1 + for r < n && !filepath.is_separator(path[r]) { + path_buf[w] = path[r] + r += 1 + w += 1 + } + } + } + + // Root directories require a trailing \ + if w == len(`\\?\c:`) { + path_buf[w] = '\\' + w += 1 + } + + allocated = true + fixed = string(path_buf[:w]) + return + } +} + +@(private="package") +_listen :: proc(socket: TCP_Socket, backlog := 1000) -> (err: Listen_Error) { + if res := win.listen(win.SOCKET(socket), i32(backlog)); res == win.SOCKET_ERROR { + err = net._listen_error() + } + return +} + +@(private="package") +_create_socket :: proc( + l: ^Event_Loop, + family: Address_Family, + protocol: Socket_Protocol, +) -> ( + socket: Any_Socket, + err: Create_Socket_Error, +) { + socket = net.create_socket(family, protocol) or_return + + association_err := _associate_socket(socket, l) + // Network unreachable would've happened on creation too. + // Not possible to associate or invalid handle can't happen because we controlled creation. + assert(association_err == nil) + + return +} + +@(private="package") +_remove :: proc(target: ^Operation) { + debug("remove", target.type) + + if target._impl.timeout == (^Operation)(REMOVED) { + return + } + + if target._impl.timeout != nil { + _remove(target._impl.timeout) + } + + target._impl.timeout = (^Operation)(REMOVED) + + switch target.type { + case .Poll: + win.UnregisterWaitEx(target.poll._impl.wait_handle, nil) + target.poll._impl.wait_handle = nil + + ok := win.PostQueuedCompletionStatus( + g.iocp, + 0, + 0, + &target._impl.over, + ) + ensure(ok == true, "unexpected PostQueuedCompletionStatus error") + return + + case .Timeout: + if avl.remove_value(&target.l.timeouts, target) { + debug("removed timeout directly") + if !target.detached { + pool.put(&target.l.operation_pool, target) + } + } else { + debug("timeout is in completed queue, will be picked up there") + } + return + + case .Close, .Open, .Stat: + // Synchronous ops, picked up in handler. + return + + case .Accept, .Dial, .Read, .Recv, .Send, .Write, .Send_File: + if is_pending(target._impl.over) { + handle := operation_handle(target) + assert(handle != win.INVALID_HANDLE) + ok := win.CancelIoEx(handle, &target._impl.over) + if !ok { + err := win.System_Error(win.GetLastError()) + #partial switch err { + case .NOT_FOUND: + debug("Remove: Cancel", target.type, "NOT_FOUND") + case .INVALID_HANDLE: + debug("Remove: Cancel", target.type, "INVALID_HANDLE") // Likely closed already. + case: + assert(false, "unexpected CancelIoEx error") + } + } + } + + case ._Remove: + panic("can't remove a removal") + + case .None, ._Splice, ._Link_Timeout: + fallthrough + case: + unreachable() + } +} + +@(private="package") +_associate_handle :: proc(handle: uintptr, l: ^Event_Loop) -> (Handle, Association_Error) { + handle_iocp := win.CreateIoCompletionPort(win.HANDLE(handle), g.iocp, 0, 0) + if handle_iocp != g.iocp { + return INVALID_HANDLE, .Not_Possible_To_Associate + } + + cmode: byte + cmode |= win.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS + cmode |= win.FILE_SKIP_SET_EVENT_ON_HANDLE + ok := win.SetFileCompletionNotificationModes(win.HANDLE(handle), cmode) + + // This is an assertion because I don't believe this can happen when we just successfully + // called `CreateIoCompletionPort`. + assert(ok == true, "unexpected SetFileCompletionNotificationModes error") + + return Handle(handle), nil +} + +@(private="package") +_associate_socket :: proc(socket: Any_Socket, l: ^Event_Loop) -> Association_Error { + if err := net.set_blocking(socket, false); err != nil { + switch err { + case .None: unreachable() + case .Network_Unreachable: return .Network_Unreachable + case .Invalid_Argument: return .Invalid_Handle + case .Unknown: fallthrough + case: return Association_Error(net.last_platform_error()) + } + } + + _, err := _associate_handle(uintptr(net.any_socket_to_socket(socket)), l) + return err +} + +@(private="package") +_wake_up :: proc(l: ^Event_Loop) { + _, exchanged := sync.atomic_compare_exchange_strong(&l.state, .Sleeping, .Waking) + if exchanged { + win.QueueUserAPC(proc "system" (Parameter: win.ULONG_PTR) {}, l.thread, 0) + } +} + +@(private="package") +_yield :: proc() { + win.SwitchToThread() +} + +// Start file private. + +QUEUE_SIZE :: 128 + +REMOVED :: rawptr(max(uintptr)-1) + +INVALID_HANDLE :: Handle(win.INVALID_HANDLE) + +Op_Result :: enum { + Done, + Pending, +} + +/* +IOCP is designed to be used from multiple threads. +For best performance we need to adhere to that and have one single IOCP for the event loops to share. +*/ +g: struct{ + mu: sync.Mutex, + refs: int, + iocp: win.HANDLE, + err: General_Error, +} + +g_ref :: proc() -> General_Error { + sync.guard(&g.mu) + + if g.refs == 0 { + win.ensure_winsock_initialized() + + // NOTE: setting NumberOfConcurrentThreads to 0 which makes Windows use the amount of processors as a default. + // We may want to make this configurable somehow? + g.iocp = win.CreateIoCompletionPort(win.INVALID_HANDLE_VALUE, nil, 0, 0) + if g.iocp == nil { + g.err = General_Error(win.GetLastError()) + } + } + + sync.atomic_add(&g.refs, 1) + + return sync.atomic_load(&g.err) +} + +g_unref :: proc() { + sync.guard(&g.mu) + + if sync.atomic_sub(&g.refs, 1) == 1 { + win.CloseHandle(g.iocp) + g.err = nil + } +} + +operation_handle :: proc(op: ^Operation) -> win.HANDLE { + switch op.type { + case .Accept: return win.HANDLE(uintptr(op.accept.socket)) + case .Close: + switch fd in op.close.subject { + case TCP_Socket: return win.HANDLE(uintptr(fd)) + case UDP_Socket: return win.HANDLE(uintptr(fd)) + case Handle: return win.HANDLE(uintptr(fd)) + case: + unreachable() + } + case .Dial: return win.HANDLE(uintptr(op.dial.socket)) + case .Read: return win.HANDLE(op.read.handle) + case .Write: return win.HANDLE(op.write.handle) + case .Recv: return win.HANDLE(uintptr(net.any_socket_to_socket(op.recv.socket))) + case .Send: return win.HANDLE(uintptr(net.any_socket_to_socket(op.send.socket))) + case .Send_File: return win.HANDLE(uintptr(net.any_socket_to_socket(op.sendfile.socket))) + case .Poll: return win.HANDLE(uintptr(net.any_socket_to_socket(op.poll.socket))) + case .Stat: return win.HANDLE(uintptr(op.stat.handle)) + + case .Timeout, .Open, ._Splice, ._Link_Timeout, ._Remove, .None: + return win.INVALID_HANDLE + case: + unreachable() + } +} + +close_exec :: proc(op: ^Operation) { + assert(op.type == .Close) + + switch h in op.close.subject { + case Handle: + if !win.CloseHandle(win.HANDLE(h)) { + op.close.err = FS_Error(win.GetLastError()) + } + case TCP_Socket: + if win.closesocket(win.SOCKET(h)) != win.NO_ERROR { + op.close.err = FS_Error(win.WSAGetLastError()) + } + case UDP_Socket: + if win.closesocket(win.SOCKET(h)) != win.NO_ERROR { + op.close.err = FS_Error(win.WSAGetLastError()) + } + case: + op.close.err = .Invalid_Argument + return + } +} + +@(require_results) +accept_exec :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Accept) + assert(is_fresh(op._impl.over)) + + family := Address_Family.IP4 + { + ep, err := bound_endpoint(op.accept.socket) + if err != nil { + op.accept.err = net._accept_error() + return .Done + } + + if _, is_ip6 := ep.address.(IP6_Address); is_ip6 { + family = .IP6 + } + } + + client, err := _create_socket(op.l, family, .TCP) + if err != nil { + op.accept.err = net._accept_error() + return .Done + } + + + op.accept.client = client.(TCP_Socket) + + received: win.DWORD + if !win.AcceptEx( + win.SOCKET(op.accept.socket), + win.SOCKET(op.accept.client), + &op.accept._impl.addrs, + 0, + size_of(win.sockaddr_in6) + 16, + size_of(win.sockaddr_in6) + 16, + &received, + &op._impl.over, + ) { + if is_pending(op._impl.over) || (op._impl.over.Internal == nil && is_incomplete(win.System_Error(win.GetLastError()))) { + link_timeout(op, op.accept.expires) + return .Pending + } else if op._impl.over.Internal == nil { + op.accept.err = net._accept_error() + } + } + + return .Done +} + +accept_callback :: proc(op: ^Operation) { + assert(op.type == .Accept) + + defer if op.accept.err != nil { + win.closesocket(win.SOCKET(op.accept.client)) + } + + if op.accept.err != nil { + return + } + + _, err := wsa_get_result(win.SOCKET(op.accept.socket), op._impl.over) + #partial switch err { + case .SUCCESS: + local_addr: ^win.sockaddr + local_addr_len: win.INT + remote_addr: ^win.sockaddr + remote_addr_len: win.INT + win.GetAcceptExSockaddrs( + &op.accept._impl.addrs, + 0, + size_of(win.sockaddr_in6) + 16, + size_of(win.sockaddr_in6) + 16, + &local_addr, + &local_addr_len, + &remote_addr, + &remote_addr_len, + ) + + assert(remote_addr_len <= size_of(win.SOCKADDR_STORAGE_LH)) + op.accept.client_endpoint = sockaddr_to_endpoint((^win.SOCKADDR_STORAGE_LH)(remote_addr)) + + // enables getsockopt, setsockopt, getsockname, getpeername, etc. + win.setsockopt(win.SOCKET(op.accept.client), win.SOL_SOCKET, win.SO_UPDATE_ACCEPT_CONTEXT, nil, 0) + + case .OPERATION_ABORTED: + // This error could also happen when the user calls close on the socket. + if check_timed_out(op, op.accept.expires) { + op.accept.err = Accept_Error.Timeout + return + } + fallthrough + + case: + op.accept.err = net._accept_error() + } +} + +@(require_results) +dial_exec :: proc(op: ^Operation) -> (result: Op_Result) { + assert(op.type == .Dial) + assert(is_fresh(op._impl.over)) + + if op.dial.endpoint.port == 0 { + op.dial.err = .Port_Required + return .Done + } + + family := family_from_endpoint(op.dial.endpoint) + osocket, socket_err := _create_socket(op.l, family, .TCP) + if socket_err != nil { + op.dial.err = socket_err + return .Done + } + + op.dial.socket = osocket.(TCP_Socket) + + sockaddr := endpoint_to_sockaddr({IP6_Any if family == .IP6 else net.IP4_Any, 0}) + res := win.bind(win.SOCKET(op.dial.socket), &sockaddr, size_of(sockaddr)) + if res < 0 { + op.dial.err = net._bind_error() + win.closesocket(win.SOCKET(op.dial.socket)) + return .Done + } + + op.dial._impl.addr = endpoint_to_sockaddr(op.dial.endpoint) + + connect_ex: win.LPFN_CONNECTEX + load_socket_fn(win.SOCKET(op.dial.socket), win.WSAID_CONNECTEX, &connect_ex) + + transferred: win.DWORD + if !connect_ex( + win.SOCKET(op.dial.socket), + &op.dial._impl.addr, + size_of(op.dial._impl.addr), + nil, + 0, + &transferred, + &op._impl.over, + ) { + if is_pending(op._impl.over) || (op._impl.over.Internal == nil && is_incomplete(win.System_Error(win.GetLastError()))) { + link_timeout(op, op.dial.expires) + return .Pending + } else if op._impl.over.Internal == nil { + op.dial.err = net._dial_error() + } + } + + return .Done +} + +dial_callback :: proc(op: ^Operation) { + assert(op.type == .Dial) + + defer if op.dial.err != nil { + win.closesocket(win.SOCKET(op.dial.socket)) + } + + if op.dial.err != nil { + return + } + + _, err := wsa_get_result(win.SOCKET(op.dial.socket), op._impl.over) + #partial switch err { + case .SUCCESS: + // enables getsockopt, setsockopt, getsockname, getpeername, etc. + win.setsockopt(win.SOCKET(op.dial.socket), win.SOL_SOCKET, win.SO_UPDATE_CONNECT_CONTEXT, nil, 0) + + case .OPERATION_ABORTED: + op.dial.err = Dial_Error.Timeout + + case: + op.dial.err = net._dial_error() + } +} + +@(require_results) +read_exec :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Read) + op._impl.over = {} // Can be called multiple times. + + op._impl.over.OffsetFull = u64(op.read.offset) + u64(op.read.read) + + to_read := op.read.buf[op.read.read:] + + read: win.DWORD + if !win.ReadFile( + win.HANDLE(op.read.handle), + raw_data(to_read), + win.DWORD(min(len(to_read), MAX_RW)), + &read, + &op._impl.over, + ) { + assert(read == 0) + if is_pending(op._impl.over) { + link_timeout(op, op.read.expires) + return .Pending + } else if op._impl.over.Internal == nil { + err := win.GetLastError() + if is_incomplete(win.System_Error(err)) { + link_timeout(op, op.read.expires) + return .Pending + } + op.read.err = FS_Error(err) + } + } + + assert(uintptr(read) == uintptr(op._impl.over.InternalHigh)) + return .Done +} + +@(require_results) +read_callback :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Read) + + if op.read.err != nil { + return .Done + } + + n, err := get_result(op._impl.over) + #partial switch err { + case .SUCCESS: + case .OPERATION_ABORTED: + // This error could also happen when the user calls close on the handle. + if check_timed_out(op, op.read.expires) { + op.read.err = .Timeout + return .Done + } + fallthrough + case .HANDLE_EOF: + if op.read.read == 0 { + op.read.err = .EOF + return .Done + } + case: + op.read.err = FS_Error(err) + return .Done + } + + op.read.read += n + if op.read.all && op.read.read < len(op.read.buf) { + switch read_exec(op) { + case .Done: return read_callback(op) + case .Pending: return .Pending + } + } + + return .Done +} + +@(require_results) +write_exec :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Write) + op._impl.over = {} // Can be called multiple times. + + op._impl.over.OffsetFull = u64(op.write.offset) + u64(op.write.written) + + to_write := op.write.buf[op.write.written:] + + written: win.DWORD + if !win.WriteFile( + win.HANDLE(op.write.handle), + raw_data(to_write), + win.DWORD(min(len(to_write), MAX_RW)), + &written, + &op._impl.over, + ) { + assert(written == 0) + if is_pending(op._impl.over) { + link_timeout(op, op.write.expires) + return .Pending + } else if op._impl.over.Internal == nil { + err := win.GetLastError() + if is_incomplete(win.System_Error(err)) { + link_timeout(op, op.write.expires) + return .Pending + } + op.write.err = FS_Error(err) + } + } + + assert(uintptr(written) == uintptr(op._impl.over.InternalHigh)) + return .Done +} + +@(require_results) +write_callback :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Write) + + if op.write.err != nil { + return .Done + } + + n, err := get_result(op._impl.over) + #partial switch err { + case .SUCCESS: + case .OPERATION_ABORTED: + // This error could also happen when the user calls close on the handle. + if check_timed_out(op, op.write.expires) { + op.write.err = .Timeout + return .Done + } + fallthrough + case: + op.write.err = FS_Error(err) + return .Done + } + + op.write.written += n + if op.write.all && op.write.written < len(op.write.buf) { + switch write_exec(op) { + case .Done: return write_callback(op) + case .Pending: return .Pending + } + } + + return .Done +} + +@(require_results) +recv_exec :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Recv) + op._impl.over = {} // Can be called multiple times. + + if op.recv.err != nil { + return .Done + } + + bufs, _ := bufs_to_process(&op.recv._impl.bufs, op.recv.bufs, op.recv.received) + win_bufs := ([^]win.WSABUF)(intrinsics.alloca(size_of(win.WSABUF) * len(bufs), align_of(win.WSABUF))) + for buf, i in bufs { + assert(i64(len(buf)) < i64(max(u32))) + win_bufs[i] = {len=u32(len(buf)), buf=raw_data(buf)} + } + + status: win.c_int + switch sock in op.recv.socket { + case TCP_Socket: + status = win.WSARecv( + win.SOCKET(sock), + win_bufs, + u32(len(bufs)), + nil, + &op.recv._impl.flags, + win.LPWSAOVERLAPPED(&op._impl.over), + nil, + ) + case UDP_Socket: + op.recv._impl.source_len = size_of(op.recv._impl.source) + status = win.WSARecvFrom( + win.SOCKET(sock), + win_bufs, + u32(len(bufs)), + nil, + &op.recv._impl.flags, + (^win.sockaddr)(&op.recv._impl.source), + &op.recv._impl.source_len, + win.LPWSAOVERLAPPED(&op._impl.over), + nil, + ) + } + + if status == win.SOCKET_ERROR { + if is_pending(op._impl.over) || (op._impl.over.Internal == nil && is_incomplete(win.System_Error(win.GetLastError()))) { + link_timeout(op, op.recv.expires) + return .Pending + } else if op._impl.over.Internal == nil { + switch _ in op.recv.socket { + case TCP_Socket: op.recv.err = net._tcp_recv_error() + case UDP_Socket: op.recv.err = net._udp_recv_error() + } + } + } + + return .Done +} + +@(require_results) +recv_callback :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Recv) + + if op.recv.err != nil { + return .Done + } + + n, err := wsa_get_result(win.SOCKET((^net.Socket)(&op.recv.socket)^), op._impl.over) + #partial switch err { + case .SUCCESS: + case .OPERATION_ABORTED: + // This error could also happen when the user calls close on the socket. + if check_timed_out(op, op.recv.expires) { + switch _ in op.recv.socket { + case TCP_Socket: op.recv.err = net.TCP_Recv_Error.Timeout + case UDP_Socket: op.recv.err = net.UDP_Recv_Error.Timeout + } + return .Done + } + fallthrough + case: + switch _ in op.recv.socket { + case TCP_Socket: op.recv.err = net._tcp_recv_error() + case UDP_Socket: op.recv.err = net._udp_recv_error() + } + return .Done + } + + op.recv.received += n + + switch sock in op.recv.socket { + case TCP_Socket: + if n == 0 { + // Connection closed. + return .Done + } + + if op.recv.all { + total: int + for buf in op.recv.bufs { + total += len(buf) + } + + if op.recv.received < total { + switch recv_exec(op) { + case .Done: return recv_callback(op) + case .Pending: return .Pending + } + } + } + + case UDP_Socket: + assert(op.recv._impl.source_len > 0) + op.recv.source = sockaddr_to_endpoint(&op.recv._impl.source) + } + + return .Done +} + +@(require_results) +send_exec :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Send) + op._impl.over = {} // Can be called multiple times. + + if op.send.err != nil { + return .Done + } + + bufs, _ := bufs_to_process(&op.send._impl.bufs, op.send.bufs, op.send.sent) + win_bufs := ([^]win.WSABUF)(intrinsics.alloca(size_of(win.WSABUF) * len(bufs), align_of(win.WSABUF))) + for buf, i in bufs { + assert(i64(len(buf)) < i64(max(u32))) + win_bufs[i] = {len=u32(len(buf)), buf=raw_data(buf)} + } + + status: win.c_int + switch sock in op.send.socket { + case TCP_Socket: + status = win.WSASend( + win.SOCKET(sock), + win_bufs, + u32(len(bufs)), + nil, + 0, + win.LPWSAOVERLAPPED(&op._impl.over), + nil, + ) + case UDP_Socket: + addr := endpoint_to_sockaddr(op.send.endpoint) + status = win.WSASendTo( + win.SOCKET(sock), + win_bufs, + u32(len(bufs)), + nil, + 0, + (^win.sockaddr)(&addr), + size_of(addr), + win.LPWSAOVERLAPPED(&op._impl.over), + nil, + ) + } + + if status == win.SOCKET_ERROR { + if is_pending(op._impl.over) || (op._impl.over.Internal == nil && is_incomplete(win.System_Error(win.GetLastError()))) { + link_timeout(op, op.send.expires) + return .Pending + } else if op._impl.over.Internal == nil { + switch _ in op.send.socket { + case TCP_Socket: op.send.err = net._tcp_send_error() + case UDP_Socket: op.send.err = net._udp_send_error() + } + } + } + + return .Done +} + +@(require_results) +send_callback :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Send) + + if op.send.err != nil { + return .Done + } + + n, err := wsa_get_result(win.SOCKET((^net.Socket)(&op.send.socket)^), op._impl.over) + #partial switch err { + case .SUCCESS: + case .OPERATION_ABORTED: + // This error could also happen when the user calls close on the socket. + if check_timed_out(op, op.send.expires) { + switch _ in op.send.socket { + case TCP_Socket: op.send.err = net.TCP_Send_Error.Timeout + case UDP_Socket: op.send.err = net.UDP_Send_Error.Timeout + } + return .Done + } + fallthrough + case: + switch _ in op.send.socket { + case TCP_Socket: op.send.err = net._tcp_send_error() + case UDP_Socket: op.send.err = net._udp_send_error() + } + return .Done + } + + op.send.sent += n + + if op.send.all { + total: int + for buf in op.send.bufs { + total += len(buf) + } + + if op.send.sent < total { + switch send_exec(op) { + case .Done: return send_callback(op) + case .Pending: return .Pending + } + } + } + + return .Done +} + +@(require_results) +sendfile_exec :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Send_File) + op._impl.over = {} // Can be called multiple times. + + if op.sendfile.nbytes == SEND_ENTIRE_FILE { + type, size, stat_err := stat(op.sendfile.file) + if stat_err != nil { + op.sendfile.err = stat_err + return .Done + } + + op.sendfile.nbytes = int(size - i64(op.sendfile.offset)) + if type != .Regular || op.sendfile.nbytes <= 0 { + op.sendfile.err = FS_Error.Invalid_Argument + return .Done + } + } + + op._impl.over.OffsetFull = u64(op.sendfile.offset) + u64(op.sendfile.sent) + + if !win.TransmitFile( + win.SOCKET(op.sendfile.socket), + win.HANDLE(op.sendfile.file), + u32(min(op.sendfile.nbytes - op.sendfile.sent, MAX_RW)), + 0, + &op._impl.over, + nil, + 0, + ) { + if is_pending(op._impl.over) || (op._impl.over.Internal == nil && is_incomplete(win.System_Error(win.GetLastError()))) { + link_timeout(op, op.sendfile.expires) + return .Pending + } else if op._impl.over.Internal == nil { + op.sendfile.err = net._tcp_send_error() + } + } + + return .Done +} + +@(require_results) +sendfile_callback :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Send_File) + + if op.sendfile.err != nil { + return .Done + } + + n, err := wsa_get_result(win.SOCKET(op.sendfile.socket), op._impl.over) + #partial switch err { + case .SUCCESS: + case .OPERATION_ABORTED: + // This error could also happen when the user calls close on the socket. + if check_timed_out(op, op.sendfile.expires) { + op.sendfile.err = TCP_Send_Error.Timeout + return .Done + } + fallthrough + case: + op.sendfile.err = net._tcp_send_error() + return .Done + } + + op.sendfile.sent += n + if op.sendfile.sent < op.sendfile.nbytes { + switch sendfile_exec(op) { + case .Done: + return sendfile_callback(op) + case .Pending: + if op.sendfile.progress_updates { op.cb(op) } + return .Pending + } + } + + return .Done +} + +@(require_results) +poll_exec :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Poll) + + events: i32 = win.FD_CLOSE + switch op.poll.event { + case .Send: events |= win.FD_WRITE|win.FD_CONNECT + case .Receive: events |= win.FD_READ|win.FD_ACCEPT + case: + op.poll.result = .Invalid_Argument + return .Done + } + + op._impl.over.hEvent = win.WSACreateEvent() + if win.WSAEventSelect( + win.SOCKET(net.any_socket_to_socket(op.poll.socket)), + op._impl.over.hEvent, + events, + ) != 0 { + #partial switch win.System_Error(win.GetLastError()) { + case .WSAEINVAL, .WSAENOTSOCK: op.poll.result = .Invalid_Argument + case: op.poll.result = .Error + } + return .Done + } + + timeout := win.INFINITE + if op.poll.expires != {} { + diff := max(0, time.diff(op.l.now, op.poll.expires)) + timeout = win.DWORD(diff / time.Millisecond) + } + + ok := win.RegisterWaitForSingleObject( + &op.poll._impl.wait_handle, + op._impl.over.hEvent, + wait_callback, + op, + timeout, + win.WT_EXECUTEINWAITTHREAD|win.WT_EXECUTEONLYONCE, + ) + ensure(ok == true, "unexpected RegisterWaitForSingleObject error") + + return .Pending + + wait_callback :: proc "system" (lpParameter: win.PVOID, TimerOrWaitFired: win.BOOLEAN) { + op := (^Operation)(lpParameter) + assert_contextless(op.type == .Poll) + + if TimerOrWaitFired { + op.poll.result = .Timeout + } + + ok := win.PostQueuedCompletionStatus( + g.iocp, + 0, + 0, + &op._impl.over, + ) + ensure_contextless(ok == true, "unexpected PostQueuedCompletionStatus error") + } +} + +poll_callback :: proc(op: ^Operation) { + assert(op.type == .Poll) + + if op._impl.over.hEvent != nil { + win.WSACloseEvent(op._impl.over.hEvent) + } + + if op.poll._impl.wait_handle != nil { + win.UnregisterWaitEx(op.poll._impl.wait_handle, nil) + } + + if op.poll.result != nil { + return + } + + _, err := get_result(op._impl.over) + #partial switch err { + case .SUCCESS: + case: + op.poll.result = .Error + } +} + +open_exec :: proc(op: ^Operation) { + assert(op.type == .Open) + // No async way of doing this. + op.open.handle, op.open.err = _open_sync(op.l, op.open.path, op.open.dir, op.open.mode, op.open.perm) +} + +stat_exec :: proc(op: ^Operation) { + assert(op.type == .Stat) + // No async way of doing this. + op.stat.type, op.stat.size, op.stat.err = stat(op.stat.handle) +} + +@(require_results) +timeout_exec :: proc(op: ^Operation) -> Op_Result { + assert(op.type == .Timeout) + + if op.timeout.duration <= 0 { + return .Done + } else { + op.timeout._impl.expires = time.time_add(now(), op.timeout.duration) + node, inserted, alloc_err := avl.find_or_insert(&op.l.timeouts, op) + assert(alloc_err == nil) + assert(inserted) + assert(node != nil) + return .Pending + } +} + +link_timeout :: proc(op: ^Operation, expires: time.Time) { + if expires == {} { + return + } + + timeout_op := _prep(op.l, internal_timeout_callback, .Timeout) + timeout_op.timeout._impl.expires = expires + timeout_op.timeout._impl.target = op + op._impl.timeout = timeout_op + + node, inserted, alloc_err := avl.find_or_insert(&op.l.timeouts, timeout_op) + assert(alloc_err == nil) + assert(inserted) + assert(node != nil) +} + +internal_timeout_callback :: proc(op: ^Operation) { + assert(op.type == .Timeout) + + target := op.timeout._impl.target + assert(target != nil) + assert(target._impl.timeout == op) + target._impl.timeout = nil + + #partial switch target.type { + case .Poll: + target.poll.result = .Timeout + target.cb(target) + _remove(target) + return + } + + if is_pending(target._impl.over) { + handle := operation_handle(target) + assert(handle != win.INVALID_HANDLE) + ok := win.CancelIoEx(handle, &target._impl.over) + if !ok { + err := win.System_Error(win.GetLastError()) + #partial switch err { + case .NOT_FOUND: + debug("Timeout: Cancel", target.type, "NOT_FOUND") + case .INVALID_HANDLE: + debug("Timeout: Cancel", target.type, "INVALID_HANDLE") + case: + assert(false, "unexpected CancelIoEx error") + } + } + } +} + +stat :: proc(handle: Handle) -> (type: File_Type, size: i64, err: FS_Error) { + info: win.FILE_STANDARD_INFO + if !win.GetFileInformationByHandleEx(win.HANDLE(handle), .FileStandardInfo, &info, size_of(info)) { + err = FS_Error(win.GetLastError()) + return + } + + size = i64(info.EndOfFile) + + if info.Directory { + type = .Directory + return + } + + switch win.GetFileType(win.HANDLE(handle)) { + case win.FILE_TYPE_PIPE: + type = .Pipe_Or_Socket + return + case win.FILE_TYPE_CHAR: + type = .Device + return + case win.FILE_TYPE_DISK: + type = .Regular + // Don't return, might be a symlink. + case: + type = .Undetermined + return + } + + + tag_info: win.FILE_ATTRIBUTE_TAG_INFO + if !win.GetFileInformationByHandleEx(win.HANDLE(handle), .FileAttributeTagInfo, &tag_info, size_of(tag_info)) { + return + } + + if ( + (tag_info.FileAttributes & win.FILE_ATTRIBUTE_REPARSE_POINT != 0) && + ( + (tag_info.ReparseTag == win.IO_REPARSE_TAG_SYMLINK) || + (tag_info.ReparseTag == win.IO_REPARSE_TAG_MOUNT_POINT) + ) + ) { + type = .Symlink + } + + return +} + +STATUS_PENDING :: rawptr(uintptr(0x103)) + +is_pending :: proc(over: win.OVERLAPPED) -> bool { + return over.Internal == STATUS_PENDING +} + +is_fresh :: proc(over: win.OVERLAPPED) -> bool { + return over.Internal == nil && over.InternalHigh == nil +} + +get_result :: proc(over: win.OVERLAPPED) -> (n: int, err: win.System_Error) { + assert(!is_pending(over)) + + n = int(uintptr(over.InternalHigh)) + + if over.Internal != nil { + err = win.System_Error(win.RtlNtStatusToDosError(win.NTSTATUS(uintptr(over.Internal)))) + assert(!is_incomplete(err)) + } + return +} + +// `get_result` above translates NT status codes to errors through RtlNtStatsToDosError, +// this is context free and can cause weird mappings, thus for sockets we want to call `WSAGetOverlappedResult` +// which does context based mapping of error codes. +// See https://stackoverflow.com/questions/28925003/calling-wsagetlasterror-from-an-iocp-thread-return-incorrect-result +wsa_get_result :: proc(socket: win.SOCKET, over: win.OVERLAPPED) -> (n: int, err: win.System_Error) { + over := over + assert(!is_pending(over)) + + if over.Internal != nil { + flags: win.DWORD + _n: win.DWORD + res := win.WSAGetOverlappedResult(socket, &over, &_n, false, &flags) + assert(!res) + n = int(_n) // NOTE: It is possible that an amount of bytes is present when the operation was cancelled. + err = win.System_Error(win.WSAGetLastError()) + } + + n = int(uintptr(over.InternalHigh)) + return +} + +is_incomplete :: proc(err: win.System_Error) -> bool { + #partial switch err { + case .WSAEWOULDBLOCK, .IO_PENDING, .IO_INCOMPLETE, .WSAEALREADY: return true + case: return false + } +} + +endpoint_to_sockaddr :: proc(ep: Endpoint) -> (sockaddr: win.SOCKADDR_STORAGE_LH) { + switch a in ep.address { + case IP4_Address: + (^win.sockaddr_in)(&sockaddr)^ = win.sockaddr_in { + sin_port = u16be(win.USHORT(ep.port)), + sin_addr = transmute(win.in_addr)a, + sin_family = u16(win.AF_INET), + } + return + case IP6_Address: + (^win.sockaddr_in6)(&sockaddr)^ = win.sockaddr_in6 { + sin6_port = u16be(win.USHORT(ep.port)), + sin6_addr = transmute(win.in6_addr)a, + sin6_family = u16(win.AF_INET6), + } + return + } + unreachable() +} + +sockaddr_to_endpoint :: proc(native_addr: ^win.SOCKADDR_STORAGE_LH) -> (ep: Endpoint) { + switch native_addr.ss_family { + case u16(win.AF_INET): + addr := cast(^win.sockaddr_in)native_addr + port := int(addr.sin_port) + ep = Endpoint { + address = IP4_Address(transmute([4]byte)addr.sin_addr), + port = port, + } + case u16(win.AF_INET6): + addr := cast(^win.sockaddr_in6)native_addr + port := int(addr.sin6_port) + ep = Endpoint { + address = IP6_Address(transmute([8]u16be)addr.sin6_addr), + port = port, + } + case: + panic("native_addr is neither IP4 or IP6 address") + } + return +} + +load_socket_fn :: proc(subject: win.SOCKET, guid: win.GUID, fn: ^$T) { + over: win.OVERLAPPED + + guid := guid + bytes: u32 + rc := win.WSAIoctl( + subject, + win.SIO_GET_EXTENSION_FUNCTION_POINTER, + &guid, + size_of(guid), + fn, + size_of(fn), + &bytes, + // NOTE: I don't think loading a socket fn ever blocks, + // but I would like to hit an assert if it does, so we do pass it. + &over, + nil, + ) + assert(rc != win.SOCKET_ERROR) + assert(bytes == size_of(fn^)) +} + +check_timed_out :: proc(op: ^Operation, expires: time.Time) -> bool { + return expires != {} && time.diff(op.l.now, expires) <= 0 +} + +timeouts_cmp :: #force_inline proc(a, b: ^Operation) -> slice.Ordering { + switch { + case a.timeout._impl.expires._nsec < b.timeout._impl.expires._nsec: + return .Less + case a.timeout._impl.expires._nsec > b.timeout._impl.expires._nsec: + return .Greater + case uintptr(a) < uintptr(b): + return .Less + case uintptr(a) > uintptr(b): + return .Greater + case: + assert(a == b) + return .Equal + } +} diff --git a/core/nbio/mpsc.odin b/core/nbio/mpsc.odin new file mode 100644 index 000000000..7f88829b4 --- /dev/null +++ b/core/nbio/mpsc.odin @@ -0,0 +1,63 @@ +#+private +package nbio + +import "base:runtime" + +import "core:sync" + +Multi_Producer_Single_Consumer :: struct { + count: int, + head: int, + tail: int, + buffer: []rawptr, + mask: int, +} + +mpsc_init :: proc(mpscq: ^Multi_Producer_Single_Consumer, cap: int, allocator: runtime.Allocator) -> runtime.Allocator_Error { + assert(runtime.is_power_of_two_int(cap), "cap must be a power of 2") + mpscq.buffer = make([]rawptr, cap, allocator) or_return + mpscq.mask = cap-1 + sync.atomic_thread_fence(.Release) + return nil +} + +mpsc_destroy :: proc(mpscq: ^Multi_Producer_Single_Consumer, allocator: runtime.Allocator) { + delete(mpscq.buffer, allocator) +} + +mpsc_enqueue :: proc(mpscq: ^Multi_Producer_Single_Consumer, obj: rawptr) -> bool { + count := sync.atomic_add_explicit(&mpscq.count, 1, .Acquire) + if count >= len(mpscq.buffer) { + sync.atomic_sub_explicit(&mpscq.count, 1, .Release) + return false + } + + head := sync.atomic_add_explicit(&mpscq.head, 1, .Acquire) + assert(mpscq.buffer[head & mpscq.mask] == nil) + rv := sync.atomic_exchange_explicit(&mpscq.buffer[head & mpscq.mask], obj, .Release) + assert(rv == nil) + return true +} + +mpsc_dequeue :: proc(mpscq: ^Multi_Producer_Single_Consumer) -> rawptr { + ret := sync.atomic_exchange_explicit(&mpscq.buffer[mpscq.tail], nil, .Acquire) + if ret == nil { + return nil + } + + mpscq.tail += 1 + if mpscq.tail >= len(mpscq.buffer) { + mpscq.tail = 0 + } + r := sync.atomic_sub_explicit(&mpscq.count, 1, .Release) + assert(r > 0) + return ret +} + +mpsc_count :: proc(mpscq: ^Multi_Producer_Single_Consumer) -> int { + return sync.atomic_load_explicit(&mpscq.count, .Relaxed) +} + +mpsc_cap :: proc(mpscq: ^Multi_Producer_Single_Consumer) -> int { + return len(mpscq.buffer) +} \ No newline at end of file diff --git a/core/nbio/nbio.odin b/core/nbio/nbio.odin new file mode 100644 index 000000000..703a2b4d7 --- /dev/null +++ b/core/nbio/nbio.odin @@ -0,0 +1,431 @@ +package nbio + +import "base:intrinsics" +import "base:runtime" + +import "core:container/pool" +import "core:net" +import "core:time" + +/* +If the package is fully supported on the current target. If it is not it will compile but work +in a matter where things are unimplemented. + +Additionally if it is `FULLY_SUPPORTED` it may still return `.Unsupported` in `acquire_thread_event_loop` +If the target does not support the needed syscalls for operating the package. +*/ +FULLY_SUPPORTED :: _FULLY_SUPPORTED + +/* +An event loop, one per thread, consider the fields private. +Do not copy. +*/ +Event_Loop :: struct /* #no_copy */ { + using impl: _Event_Loop, + allocator: runtime.Allocator, + err: General_Error, + refs: int, + now: time.Time, + + // Queue that is used to queue operations from another thread to be executed on this thread. + queue: Multi_Producer_Single_Consumer, + + operation_pool: pool.Pool(Operation), +} + +Handle :: _Handle + +// The maximum size of user arguments for an operation, can be increased at the cost of more RAM. +MAX_USER_ARGUMENTS :: #config(NBIO_MAX_USER_ARGUMENTS, 4) +#assert(MAX_USER_ARGUMENTS >= 4) + +Operation :: struct { + cb: Callback, + user_data: [MAX_USER_ARGUMENTS + 1]rawptr, + detached: bool, + type: Operation_Type, + using specifics: Specifics, + + _impl: _Operation `fmt:"-"`, + using _: struct #raw_union { + _pool_link: ^Operation, + l: ^Event_Loop, + }, +} + +Specifics :: struct #raw_union { + accept: Accept `raw_union_tag:"type=.Accept"`, + close: Close `raw_union_tag:"type=.Close"`, + dial: Dial `raw_union_tag:"type=.Dial"`, + read: Read `raw_union_tag:"type=.Read"`, + recv: Recv `raw_union_tag:"type=.Recv"`, + send: Send `raw_union_tag:"type=.Send"`, + write: Write `raw_union_tag:"type=.Write"`, + timeout: Timeout `raw_union_tag:"type=.Timeout"`, + poll: Poll `raw_union_tag:"type=.Poll"`, + sendfile: Send_File `raw_union_tag:"type=.Send_File"`, + open: Open `raw_union_tag:"type=.Open"`, + stat: Stat `raw_union_tag:"type=.Stat"`, + + _remove: _Remove `raw_union_tag:"type=._Remove"`, + _link_timeout: _Link_Timeout `raw_union_tag:"type=._Link_Timeout"`, + _splice: _Splice `raw_union_tag:"type=._Splice"`, +} + +Operation_Type :: enum i32 { + None, + Accept, + Close, + Dial, + Read, + Recv, + Send, + Write, + Timeout, + Poll, + Send_File, + Open, + Stat, + + _Link_Timeout, + _Remove, + _Splice, +} + +Callback :: #type proc(op: ^Operation) + +/* +Initialize or increment the reference counted event loop for the current thread. +*/ +acquire_thread_event_loop :: proc() -> General_Error { + return _acquire_thread_event_loop() +} + +/* +Destroy or decrease the reference counted event loop for the current thread. +*/ +release_thread_event_loop :: proc() { + _release_thread_event_loop() +} + +current_thread_event_loop :: proc(loc := #caller_location) -> ^Event_Loop { + return _current_thread_event_loop(loc) +} + +/* +Each time you call this the implementation checks its state +and calls any callbacks which are ready. You would typically call this in a loop. + +Blocks for up-to timeout waiting for events if there is nothing to do. +*/ +tick :: proc(timeout: time.Duration = NO_TIMEOUT) -> General_Error { + l := &_tls_event_loop + if l.refs == 0 { return nil } + return _tick(l, timeout) +} + +/* +Runs the event loop by ticking in a loop until there is no more work to be done. +*/ +run :: proc() -> General_Error { + l := &_tls_event_loop + if l.refs == 0 { return nil } + + acquire_thread_event_loop() + defer release_thread_event_loop() + + for num_waiting() > 0 { + if errno := _tick(l, NO_TIMEOUT); errno != nil { + return errno + } + } + return nil +} + +/* +Runs the event loop by ticking in a loop until there is no more work to be done, or the flag `done` is `true`. +*/ +run_until :: proc(done: ^bool) -> General_Error { + l := &_tls_event_loop + if l.refs == 0 { return nil } + + acquire_thread_event_loop() + defer release_thread_event_loop() + + for num_waiting() > 0 && !intrinsics.volatile_load(done) { + if errno := _tick(l, NO_TIMEOUT); errno != nil { + return errno + } + } + return nil +} + +/* +Returns the number of in-progress operations to be completed on the event loop. +*/ +num_waiting :: proc(l: Maybe(^Event_Loop) = nil) -> int { + l_ := l.? or_else &_tls_event_loop + if l_.refs == 0 { return 0 } + return pool.num_outstanding(&l_.operation_pool) +} + +/* +Returns the current time (cached at most at the beginning of the current tick). +*/ +now :: proc() -> time.Time { + if _tls_event_loop.now == {} { + return time.now() + } + return _tls_event_loop.now +} + +/* +Remove the given operation from the event loop. The callback of it won't be called and resources are freed. + +Calling `remove`: +- Cancels the operation if it has not yet completed +- Prevents the callback from being called + +Cancellation via `remove` is *final* and silent: +- The callback will never be invoked +- No error is delivered +- The operation must be considered dead after removal + +WARN: the operation could have already been (partially or completely) completed. + A send with `all` set to true could have sent a portion already. + But also, a send that could be completed without blocking could have been completed. + You just won't get a callback. + +WARN: once an operation's callback is called it can not be removed anymore (use after free). + +WARN: needs to be called from the thread of the event loop the target belongs to. + +Common use would be to cancel a timeout, remove a polling, or remove an `accept` before calling `close` on it's socket. +*/ +remove :: proc(target: ^Operation) { + if target == nil { + return + } + + assert(target.type != .None) + + if target.l != &_tls_event_loop { + panic("nbio.remove called on different thread") + } + + _remove(target) +} + +/* +Creates a socket for use in `nbio` and relates it to the given event loop. + +Inputs: +- family: Should this be an IP4 or IP6 socket +- protocol: The type of socket (TCP or UDP) +- l: The event loop to associate it with, defaults to the current thread's loop + +Returns: +- socket: The created socket, consider `create_{udp|tcp}_socket` for a typed socket instead of the union +- err: A network error (`Create_Socket_Error`, or `Set_Blocking_Error`) which happened while opening +*/ +create_socket :: proc( + family: Address_Family, + protocol: Socket_Protocol, + l: ^Event_Loop = nil, + loc := #caller_location, +) -> ( + socket: Any_Socket, + err: Create_Socket_Error, +) { + return _create_socket(l if l != nil else _current_thread_event_loop(loc), family, protocol) +} + +/* +Creates a UDP socket for use in `nbio` and relates it to the given event loop. + +Inputs: +- family: Should this be an IP4 or IP6 socket +- l: The event loop to associate it with, defaults to the current thread's loop + +Returns: +- socket: The created UDP socket +- err: A network error (`Create_Socket_Error`, or `Set_Blocking_Error`) which happened while opening +*/ +create_udp_socket :: proc(family: Address_Family, l: ^Event_Loop = nil, loc := #caller_location) -> (net.UDP_Socket, Create_Socket_Error) { + socket, err := create_socket(family, .UDP, l, loc) + if err != nil { + return -1, err + } + + return socket.(UDP_Socket), nil +} + +/* +Creates a TCP socket for use in `nbio` and relates it to the given event loop. + +Inputs: +- family: Should this be an IP4 or IP6 socket +- l: The event loop to associate it with, defaults to the current thread's loop + +Returns: +- socket: The created TCP socket +- err: A network error (`Create_Socket_Error`, or `Set_Blocking_Error`) which happened while opening +*/ +create_tcp_socket :: proc(family: Address_Family, l: ^Event_Loop = nil, loc := #caller_location) -> (net.TCP_Socket, Create_Socket_Error) { + socket, err := create_socket(family, .TCP, l, loc) + if err != nil { + return -1, err + } + + return socket.(TCP_Socket), nil +} + +/* +Creates a socket, sets non blocking mode, relates it to the given IO, binds the socket to the given endpoint and starts listening. + +Inputs: +- endpoint: Where to bind the socket to +- backlog: The maximum length to which the queue of pending connections may grow, before refusing connections +- l: The event loop to associate the socket with, defaults to the current thread's loop + +Returns: +- socket: The opened, bound and listening socket +- err: A network error (`Create_Socket_Error`, `Bind_Error`, or `Listen_Error`) that has happened +*/ +listen_tcp :: proc(endpoint: Endpoint, backlog := 1000, l: ^Event_Loop = nil, loc := #caller_location) -> (socket: TCP_Socket, err: net.Network_Error) { + assert(backlog > 0 && backlog < int(max(i32))) + return _listen_tcp(l if l != nil else _current_thread_event_loop(loc), endpoint, backlog) +} + +/* +Opens a file and associates it with the event loop. + +Inputs: +- path: path to the file, if not absolute: relative from `dir` +- dir: directory that `path` is relative from (if it is relative), defaults to the current working directory +- mode: open mode, defaults to read-only +- perm: permissions to use when creating a file, defaults to read+write for everybody +- l: event loop to associate the file with, defaults to the current thread's + +Returns: +- handle: The file handle +- err: An error if it occurred +*/ +open_sync :: proc(path: string, dir: Handle = CWD, mode: File_Flags = {.Read}, perm := Permissions_Default_File, l: ^Event_Loop = nil, loc := #caller_location) -> (handle: Handle, err: FS_Error) { + return _open_sync(l if l != nil else _current_thread_event_loop(loc), path, dir, mode, perm) +} + +Association_Error :: enum { + None, + // The given file/handle/socket was not opened in a mode that it can be made non-blocking afterwards. + // + // On Windows, this can happen when a file is not opened with the `FILE_FLAG_OVERLAPPED` flag. + // If using `core:os`, that is set when you specify the `O_NONBLOCK` flag. + // There is no way to add that after the fact. + Not_Possible_To_Associate, + // The given handle is not a valid handle. + Invalid_Handle, + // No network connection, or the network stack is not initialized. + Network_Unreachable, +} + +/* +Associate the given OS handle, not opened through this package, with the event loop. + +Consider using this package's `open` or `open_sync` directly instead. + +The handle returned is for convenience, it is actually still the same handle as given. +Thus you should not close the given handle. + +On Windows, this can error when a file is not opened with the `FILE_FLAG_OVERLAPPED` flag. +If using `core:os`, that is set when you specify the `O_NONBLOCK` flag. +There is no way to add that after the fact. +*/ +associate_handle :: proc(handle: uintptr, l: ^Event_Loop = nil, loc := #caller_location) -> (Handle, Association_Error) { + return _associate_handle(handle, l if l != nil else _current_thread_event_loop(loc)) +} + +/* +Associate the given socket, not created through this package, with the event loop. + +Consider using this package's `create_socket` directly instead. +*/ +associate_socket :: proc(socket: Any_Socket, l: ^Event_Loop = nil, loc := #caller_location) -> Association_Error { + return _associate_socket(socket, l if l != nil else _current_thread_event_loop(loc)) +} + +Read_Entire_File_Error :: struct { + operation: Operation_Type, + value: FS_Error, +} + +Read_Entire_File_Callback :: #type proc(user_data: rawptr, data: []byte, err: Read_Entire_File_Error) + +/* +Combines multiple operations (open, stat, read, close) into one that reads an entire regular file. + +The error contains the `operation` that the error happened on. + +Inputs: +- path: path to the file, if not absolute: relative from `dir` +- user_data: a pointer passed through into the callback +- cb: the callback to call once completed, called with the user data, file data, and an optional error +- allocator: the allocator to allocate the file's contents onto +- dir: directory that `path` is relative from (if it is relative), defaults to the current working directory +- l: event loop to execute the operation on +*/ +read_entire_file :: proc(path: string, user_data: rawptr, cb: Read_Entire_File_Callback, allocator := context.allocator, dir := CWD, l: ^Event_Loop = nil, loc := #caller_location) { + _read_entire_file(l if l != nil else _current_thread_event_loop(loc), path, user_data, cb, allocator, dir) +} + +/* +Detach an operation from the package's lifetime management. + +By default the operation's lifetime is managed by the package and freed after a callback is called. +Calling this function detaches the operation from this lifetime. +You are expected to call `reattach` to give the package back this operation. +*/ +detach :: proc(op: ^Operation) { + op.detached = true +} + +/* +Reattach an operation to the package's lifetime management. +*/ +reattach :: proc(op: ^Operation) { + pool.put(&op.l.operation_pool, op) +} + +/* +Execute an operation. + +If the operation is attached to another thread's event loop, it is queued to be executed on that event loop, +optionally waking that loop up (from a blocking `tick`) with `trigger_wake_up`. +*/ +exec :: proc(op: ^Operation, trigger_wake_up := true) { + if op.l == &_tls_event_loop { + _exec(op) + } else { + for !mpsc_enqueue(&op.l.queue, op) { + warn("operation queue on event loop filled up") + wake_up(op.l) + _yield() + } + if trigger_wake_up { + wake_up(op.l) + } + } +} + +/* +Wake up an event loop on another thread which may be blocking for completed operations. + +Commonly used with `exec` from a worker thread to have the event loop pick up that work. +Note that by default `exec` already calls this procedure. +*/ +wake_up :: proc(l: ^Event_Loop) { + if l == &_tls_event_loop { + return + } + _wake_up(l) +} diff --git a/core/nbio/net.odin b/core/nbio/net.odin new file mode 100644 index 000000000..d584639a7 --- /dev/null +++ b/core/nbio/net.odin @@ -0,0 +1,39 @@ +package nbio + +import "core:net" + +Network_Error :: net.Network_Error +Accept_Error :: net.Accept_Error +Dial_Error :: net.Dial_Error +Send_Error :: net.Send_Error +TCP_Send_Error :: net.TCP_Send_Error +UDP_Send_Error :: net.UDP_Send_Error +Recv_Error :: net.Recv_Error +TCP_Recv_Error :: net.TCP_Recv_Error +UDP_Recv_Error :: net.UDP_Recv_Error +Listen_Error :: net.Listen_Error +Create_Socket_Error :: net.Create_Socket_Error + +Address_Family :: net.Address_Family +Socket_Protocol :: net.Socket_Protocol + +Address :: net.Address +IP4_Address :: net.IP4_Address +IP6_Address :: net.IP6_Address + +Endpoint :: net.Endpoint + +TCP_Socket :: net.TCP_Socket +UDP_Socket :: net.UDP_Socket +Any_Socket :: net.Any_Socket + +IP4_Any :: net.IP4_Any +IP6_Any :: net.IP6_Any +IP4_Loopback :: net.IP4_Loopback +IP6_Loopback :: net.IP6_Loopback + +family_from_endpoint :: net.family_from_endpoint +bind :: net.bind +bound_endpoint :: net.bound_endpoint +parse_endpoint :: net.parse_endpoint +endpoint_to_string :: net.endpoint_to_string diff --git a/core/nbio/ops.odin b/core/nbio/ops.odin new file mode 100644 index 000000000..382dca747 --- /dev/null +++ b/core/nbio/ops.odin @@ -0,0 +1,2461 @@ +package nbio + +import "base:intrinsics" + +import "core:container/pool" +import "core:time" +import "core:slice" + +NO_TIMEOUT: time.Duration: -1 + +Accept :: struct { + // Socket to accept an incoming connection on. + socket: TCP_Socket, + // When this operation expires and should be timed out. + expires: time.Time, + + // The connection that was accepted. + client: TCP_Socket, + // The connection's remote origin. + client_endpoint: Endpoint, + // An error, if it occurred. + err: Accept_Error, + + // Implementation specifics, private. + _impl: _Accept `fmt:"-"`, +} + +/* +Retrieves and preps an operation to do an accept without executing it. + +Executing can then be done with the `exec` procedure. + +The timeout is calculated from the time when this procedure was called, not from when it's executed. + +Any user data can be set on the returned operation's `user_data` field. + +Inputs: +- socket: A bound and listening socket *associated with the event loop* +- cb: The callback to be called when the operation finishes, `Operation.accept` will contain results +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +prep_accept :: #force_inline proc( + socket: TCP_Socket, + cb: Callback, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation { + op := _prep(l, cb, .Accept) + op.accept.socket = socket + if timeout > 0 { + op.accept.expires = time.time_add(now(), timeout) + } + return op +} + +/* +Using the given socket, accepts the next incoming connection, calling the callback when that happens. + +Any user data can be set on the returned operation's `user_data` field. +Polymorphic variants for type safe user data are available under `accept_poly`, `accept_poly2`, and `accept_poly3`. + +Inputs: +- socket: A bound and listening socket *associated with the event loop* +- cb: The callback to be called when the operation finishes, `Operation.accept` will contain results +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +accept :: #force_inline proc( + socket: TCP_Socket, + cb: Callback, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation { + res := prep_accept(socket, cb, timeout, l) + exec(res) + return res +} + +/* +Using the given socket, accepts the next incoming connection, calling the callback when that happens. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- socket: A bound and listening socket *associated with the event loop* +- p: User data, the callback will receive this as it's second argument +- cb: The callback to be called when the operation finishes, `Operation.accept` will contain results +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +accept_poly :: #force_inline proc( + socket: TCP_Socket, + p: $T, + cb: $C/proc(op: ^Operation, p: T), + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil +) -> ^Operation where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_accept(socket, _poly_cb(C, T), timeout, l) + _put_user_data(op, cb, p) + exec(op) + return op +} + +/* +Using the given socket, accepts the next incoming connection, calling the callback when that happens. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- socket: A bound and listening socket *associated with the event loop* +- p: User data, the callback will receive this as it's second argument +- p2: User data, the callback will receive this as it's third argument +- cb: The callback to be called when the operation finishes, `Operation.accept` will contain results +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +accept_poly2 :: #force_inline proc( + socket: TCP_Socket, + p: $T, p2: $T2, + cb: $C/proc(op: ^Operation, p: T, p2: T2), + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_accept(socket, _poly_cb2(C, T, T2), timeout, l) + _put_user_data2(op, cb, p, p2) + exec(op) + return op +} + +/* +Using the given socket, accepts the next incoming connection, calling the callback when that happens. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- socket: A bound and listening socket *associated with the event loop* +- p: User data, the callback will receive this as it's second argument +- p2: User data, the callback will receive this as it's third argument +- p3: User data, the callback will receive this as it's fourth argument +- cb: The callback to be called when the operation finishes, `Operation.accept` will contain results +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +accept_poly3 :: #force_inline proc( + socket: TCP_Socket, + p: $T, p2: $T2, p3: $T3, + cb: $C/proc(op: ^Operation, p: T, p2: T2, p3: T3), + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_accept(socket, _poly_cb3(C, T, T2, T3), timeout, l) + _put_user_data3(op, cb, p, p2, p3) + exec(op) + return op +} + +/* +A union of closable types that can be passed to `close`. +*/ +Closable :: union { + TCP_Socket, + UDP_Socket, + Handle, +} + +Close :: struct { + // The subject to close. + subject: Closable, + + // An error, if it occurred. + err: FS_Error, + + // Implementation specifics, private. + _impl: _Close `fmt:"-"`, +} + +@(private) +empty_callback :: proc(_: ^Operation) {} + +/* +Retrieves and preps an operation to do a close without executing it. + +Executing can then be done with the `exec` procedure. + +Closing something that has IO in progress may or may not cancel it, and may or may not call the callback. +For consistent behavior first call `remove` on in progress IO. + +Any user data can be set on the returned operation's `user_data` field. + +Inputs: +- subject: The subject (socket or file) to close +- cb: The optional callback to be called when the operation finishes, `Operation.close` will contain results +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +prep_close :: #force_inline proc(subject: Closable, cb: Callback = empty_callback, l: ^Event_Loop = nil) -> ^Operation { + op := _prep(l, cb, .Close) + op.close.subject = subject + return op +} + +/* +Closes the given subject (file or socket). + +Closing something that has IO in progress may or may not cancel it, and may or may not call the callback. +For consistent behavior first call `remove` on in progress IO. + +Any user data can be set on the returned operation's `user_data` field. +Polymorphic variants for type safe user data are available under `close_poly`, `close_poly2`, and `close_poly3`. + +Inputs: +- subject: The subject (socket or file) to close +- cb: The optional callback to be called when the operation finishes, `Operation.close` will contain results +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +close :: #force_inline proc(subject: Closable, cb: Callback = empty_callback, l: ^Event_Loop = nil) -> ^Operation { + op := prep_close(subject, cb, l) + exec(op) + return op +} + +/* +Closes the given subject (file or socket). + +Closing something that has IO in progress may or may not cancel it, and may or may not call the callback. +For consistent behavior first call `remove` on in progress IO. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- subject: The subject (socket or file) to close +- p: User data, the callback will receive this as it's second argument +- cb: The optional callback to be called when the operation finishes, `Operation.close` will contain results +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +close_poly :: #force_inline proc(subject: Closable, p: $T, cb: $C/proc(op: ^Operation, p: T), l: ^Event_Loop = nil) -> ^Operation +where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_close(subject, _poly_cb(C, T), l) + _put_user_data(op, cb, p) + exec(op) + return op +} + +/* +Closes the given subject (file or socket). + +Closing something that has IO in progress may or may not cancel it, and may or may not call the callback. +For consistent behavior first call `remove` on in progress IO. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- subject: The subject (socket or file) to close +- p: User data, the callback will receive this as it's second argument +- p2: User data, the callback will receive this as it's third argument +- cb: The optional callback to be called when the operation finishes, `Operation.close` will contain results +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +close_poly2 :: #force_inline proc(subject: Closable, p: $T, p2: $T2, cb: $C/proc(op: ^Operation, p: T, p2: T2), l: ^Event_Loop = nil) -> ^Operation +where size_of(T) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_close(subject, _poly_cb2(C, T, T2), l) + _put_user_data2(op, cb, p, p2) + exec(op) + return op +} + +/* +Closes the given subject (file or socket). + +Closing something that has IO in progress may or may not cancel it, and may or may not call the callback. +For consistent behavior first call `remove` on in progress IO. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- subject: The subject (socket or file) to close +- p: User data, the callback will receive this as it's second argument +- p2: User data, the callback will receive this as it's third argument +- p3: User data, the callback will receive this as it's fourth argument +- cb: The optional callback to be called when the operation finishes, `Operation.close` will contain results +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +close_poly3 :: #force_inline proc(subject: Closable, p: $T, p2: $T2, p3: $T3, cb: $C/proc(op: ^Operation, p: T, p2: T2, p3: T3), l: ^Event_Loop = nil) -> ^Operation +where size_of(T) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_close(subject, _poly_cb3(C, T, T2, T3), l) + _put_user_data3(op, cb, p, p2, p3) + exec(op) + return op +} + +Dial :: struct { + // The endpoint to connect to. + endpoint: Endpoint, + // When this operation expires and should be timed out. + expires: time.Time, + + // Errors that can be returned: `Create_Socket_Error`, or `Dial_Error`. + err: Network_Error, + // The socket to communicate with the connected server. + socket: TCP_Socket, + + // Implementation specifics, private. + _impl: _Dial `fmt:"-"`, +} + +/* +Retrieves and preps an operation to do a dial operation without executing it. + +Executing can then be done with the `exec` procedure. + +The timeout is calculated from the time when this procedure was called, not from when it's executed. + +Any user data can be set on the returned operation's `user_data` field. + +Inputs: +- endpoint: The endpoint to connect to +- cb: The callback to be called when the operation finishes, `Operation.dial` will contain results +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +prep_dial :: #force_inline proc( + endpoint: Endpoint, + cb: Callback, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation { + op := _prep(l, cb, .Dial) + if timeout > 0 { + op.dial.expires = time.time_add(now(), timeout) + } + op.dial.endpoint = endpoint + return op +} + +/* +Dials the given endpoint. + +Any user data can be set on the returned operation's `user_data` field. +Polymorphic variants for type safe user data are available under `dial_poly`, `dial_poly2`, and `dial_poly3`. + +Inputs: +- endpoint: The endpoint to connect to +- cb: The callback to be called when the operation finishes, `Operation.dial` will contain results +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +dial :: #force_inline proc( + endpoint: Endpoint, + cb: Callback, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation { + res := prep_dial(endpoint, cb, timeout, l) + exec(res) + return res +} + +/* +Dials the given endpoint. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- endpoint: The endpoint to connect to +- p: User data, the callback will receive this as it's second argument +- cb: The callback to be called when the operation finishes, `Operation.dial` will contain results +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +dial_poly :: #force_inline proc( + endpoint: Endpoint, + p: $T, + cb: $C/proc(op: ^Operation, p: T), + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_dial(endpoint, _poly_cb(C, T), timeout, l) + _put_user_data(op, cb, p) + exec(op) + + return op +} + +/* +Dials the given endpoint. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- endpoint: The endpoint to connect to +- p: User data, the callback will receive this as it's second argument +- p2: User data, the callback will receive this as it's third argument +- cb: The callback to be called when the operation finishes, `Operation.dial` will contain results +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +dial_poly2 :: #force_inline proc( + endpoint: Endpoint, + p: $T, p2: $T2, + cb: $C/proc(op: ^Operation, p: T, p2: T2), + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_dial(endpoint, _poly_cb2(C, T, T2), timeout, l) + _put_user_data2(op, cb, p, p2) + exec(op) + + return op +} + +/* +Dials the given endpoint. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- endpoint: The endpoint to connect to +- p: User data, the callback will receive this as it's second argument +- p2: User data, the callback will receive this as it's third argument +- p3: User data, the callback will receive this as it's fourth argument +- cb: The callback to be called when the operation finishes, `Operation.dial` will contain results +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +dial_poly3 :: #force_inline proc( + endpoint: Endpoint, + p: $T, p2: $T2, p3: $T3, + cb: $C/proc(op: ^Operation, p: T, p2: T2, p3: T3), + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_dial(endpoint, _poly_cb3(C, T, T2, T3), timeout, l) + _put_user_data3(op, cb, p, p2, p3) + exec(op) + + return op +} + +Recv :: struct { + // The socket to receive from. + socket: Any_Socket, + // The buffers to receive data into. + // The outer slice is copied internally, but the backing data must remain alive. + // It is safe to access `bufs` during the callback. + bufs: [][]byte, + // If true, the operation waits until all buffers are filled (TCP only). + all: bool, + // When this operation expires and should be timed out. + expires: time.Time, + + // The source endpoint data was received from (UDP only). + source: Endpoint, + + // An error, if it occurred. + // If `received == 0` and `err == nil`, the connection was closed by the peer. + err: Recv_Error, + // The number of bytes received. + received: int, + + // Implementation specifics, private. + _impl: _Recv `fmt:"-"`, +} + +/* +Retrieves and preps an operation to do a receive without executing it. + +Executing can then be done with the `exec` procedure. + +To avoid ambiguity between a closed connection and a 0-byte read, the provided buffers must have a total capacity greater than 0. + +The `bufs` slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired. + +The timeout is calculated from the time when this procedure was called, not from when it's executed. + +Any user data can be set on the returned operation's `user_data` field. + +Inputs: +- socket: The socket to receive from +- bufs: Buffers to fill with received data +- cb: The callback to be called when the operation finishes, `Operation.recv` will contain results +- all: If true, waits until all buffers are full before completing (TCP only, ignored for UDP) +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +prep_recv :: #force_inline proc( + socket: Any_Socket, + bufs: [][]byte, + cb: Callback, + all := false, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation { + assert(socket != nil) + + // If we accepted `bufs` that total 0 it would be ambiguous if the result of `received == 0 && err == nil` means connection closed or received 0 bytes. + assert(len(bufs) > 0) + assert(slice.any_of_proc(bufs, proc(buf: []byte) -> bool { return len(buf) > 0 })) + + op := _prep(l, cb, .Recv) + op.recv.socket = socket + op.recv.bufs = bufs + op.recv.all = all + if timeout > 0 { + op.recv.expires = time.time_add(now(), timeout) + } + + if err := bufs_init(&op.recv._impl.bufs, &op.recv.bufs, op.l.allocator); err != nil { + switch _ in op.recv.socket { + case TCP_Socket: op.recv.err = TCP_Recv_Error.Insufficient_Resources + case UDP_Socket: op.recv.err = UDP_Recv_Error.Insufficient_Resources + case: unreachable() + } + } + + return op +} + +/* +Receives data from the socket. + +If the operation completes with 0 bytes received and no error, it indicates the connection was closed by the peer. + +The `bufs` slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired. + +Any user data can be set on the returned operation's `user_data` field. +Polymorphic variants for type safe user data are available under `recv_poly`, `recv_poly2`, and `recv_poly3`. + +Inputs: +- socket: The socket to receive from +- bufs: Buffers to fill with received data +- cb: The callback to be called when the operation finishes, `Operation.recv` will contain results +- all: If true, waits until all buffers are full before completing (TCP only, ignored for UDP) +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +recv :: #force_inline proc( + socket: Any_Socket, + bufs: [][]byte, + cb: Callback, + all := false, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil +) -> ^Operation { + op := prep_recv(socket, bufs, cb, all, timeout, l) + exec(op) + return op +} + +/* +Receives data from the socket. + +If the operation completes with 0 bytes received and no error, it indicates the connection was closed by the peer. + +The `bufs` slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- socket: The socket to receive from +- bufs: Buffers to fill with received data +- p: User data, the callback will receive this as it's second argument +- cb: The callback to be called when the operation finishes, `Operation.recv` will contain results +- all: If true, waits until all buffers are full before completing (TCP only, ignored for UDP) +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +recv_poly :: #force_inline proc( + socket: Any_Socket, + bufs: [][]byte, + p: $T, + cb: $C/proc(op: ^Operation, p: T), + all := false, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_recv(socket, bufs, _poly_cb(C, T), all, timeout, l) + _put_user_data(op, cb, p) + exec(op) + + return op +} + +/* +Receives data from the socket. + +If the operation completes with 0 bytes received and no error, it indicates the connection was closed by the peer. + +The `bufs` slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- socket: The socket to receive from +- bufs: Buffers to fill with received data +- p: User data, the callback will receive this as it's second argument +- p2: User data, the callback will receive this as it's third argument +- cb: The callback to be called when the operation finishes, `Operation.recv` will contain results +- all: If true, waits until all buffers are full before completing (TCP only, ignored for UDP) +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +recv_poly2 :: #force_inline proc( + socket: Any_Socket, + bufs: [][]byte, + p: $T, p2: $T2, + cb: $C/proc(op: ^Operation, p: T, p2: T2), + all := false, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_recv(socket, bufs, _poly_cb2(C, T, T2), all, timeout, l) + _put_user_data2(op, cb, p, p2) + exec(op) + + return op +} + +/* +Receives data from the socket. + +If the operation completes with 0 bytes received and no error, it indicates the connection was closed by the peer. + +The `bufs` slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- socket: The socket to receive from +- bufs: Buffers to fill with received data +- p: User data, the callback will receive this as it's second argument +- p2: User data, the callback will receive this as it's third argument +- p3: User data, the callback will receive this as it's fourth argument +- cb: The callback to be called when the operation finishes, `Operation.recv` will contain results +- all: If true, waits until all buffers are full before completing (TCP only, ignored for UDP) +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +recv_poly3 :: #force_inline proc( + socket: Any_Socket, + bufs: [][]byte, + p: $T, p2: $T2, p3: $T3, + cb: $C/proc(op: ^Operation, p: T, p2: T2, p3: T3), + all := false, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_recv(socket, bufs, _poly_cb3(C, T, T2, T3), all, timeout, l) + _put_user_data3(op, cb, p, p2, p3) + exec(op) + + return op +} + +Send :: struct { + // The socket to send to. + socket: Any_Socket, + // The buffers to send. + // The outer slice is copied internally, but the backing data must remain alive. + // It is safe to access `bufs` during the callback. + bufs: [][]byte `fmt:"-"`, + // The destination endpoint to send to (UDP only). + endpoint: Endpoint, + // If true, the operation ensures all data is sent before completing. + all: bool, + // When this operation expires and should be timed out. + expires: time.Time, + + // An error, if it occurred. + err: Send_Error, + // The number of bytes sent. + sent: int, + + // Implementation specifics, private. + _impl: _Send `fmt:"-"`, +} + +/* +Retrieves and preps an operation to do a send without executing it. + +Executing can then be done with the `exec` procedure. + +The `bufs` slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired. + +The timeout is calculated from the time when this procedure was called, not from when it's executed. + +Any user data can be set on the returned operation's `user_data` field. + +Inputs: +- socket: The socket to send to +- bufs: Buffers containing the data to send +- cb: The callback to be called when the operation finishes, `Operation.send` will contain results +- endpoint: The destination endpoint (UDP only, ignored for TCP) +- all: If true, the operation ensures all data is sent before completing +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +prep_send :: proc( + socket: Any_Socket, + bufs: [][]byte, + cb: Callback, + endpoint: Endpoint = {}, + all := true, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation { + assert(socket != nil) + op := _prep(l, cb, .Send) + op.send.socket = socket + op.send.bufs = bufs + op.send.endpoint = endpoint + op.send.all = all + if timeout > 0 { + op.send.expires = time.time_add(now(), timeout) + } + + if err := bufs_init(&op.send._impl.bufs, &op.send.bufs, op.l.allocator); err != nil { + switch _ in op.send.socket { + case TCP_Socket: op.send.err = TCP_Send_Error.Insufficient_Resources + case UDP_Socket: op.send.err = UDP_Send_Error.Insufficient_Resources + case: unreachable() + } + } + + return op +} + +/* +Sends data to the socket. + +The `bufs` slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired. + +Any user data can be set on the returned operation's `user_data` field. +Polymorphic variants for type safe user data are available under `send_poly`, `send_poly2`, and `send_poly3`. + +Inputs: +- socket: The socket to send to +- bufs: Buffers containing the data to send +- cb: The callback to be called when the operation finishes, `Operation.send` will contain results +- endpoint: The destination endpoint (UDP only, ignored for TCP) +- all: If true, the operation ensures all data is sent before completing +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +send :: #force_inline proc( + socket: Any_Socket, + bufs: [][]byte, + cb: Callback, + endpoint: Endpoint = {}, + all := true, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation { + op := prep_send(socket, bufs, cb, endpoint, all, timeout, l) + exec(op) + return op +} + +/* +Sends data to the socket. + +The `bufs` slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- socket: The socket to send to +- bufs: Buffers containing the data to send +- p: User data, the callback will receive this as it's second argument +- cb: The callback to be called when the operation finishes, `Operation.send` will contain results +- endpoint: The destination endpoint (UDP only, ignored for TCP) +- all: If true, the operation ensures all data is sent before completing +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +send_poly :: #force_inline proc( + socket: Any_Socket, + bufs: [][]byte, + p: $T, + cb: $C/proc(op: ^Operation, p: T), + endpoint: Endpoint = {}, + all := true, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_send(socket, bufs, _poly_cb(C, T), endpoint, all, timeout, l) + _put_user_data(op, cb, p) + exec(op) + + return op +} + +/* +Sends data to the socket. + +The `bufs` slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- socket: The socket to send to +- bufs: Buffers containing the data to send +- p: User data, the callback will receive this as it's second argument +- p2: User data, the callback will receive this as it's third argument +- cb: The callback to be called when the operation finishes, `Operation.send` will contain results +- endpoint: The destination endpoint (UDP only, ignored for TCP) +- all: If true, the operation ensures all data is sent before completing +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +send_poly2 :: #force_inline proc( + socket: Any_Socket, + bufs: [][]byte, + p: $T, p2: $T2, + cb: $C/proc(op: ^Operation, p: T, p2: T2), + endpoint: Endpoint = {}, + all := true, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_send(socket, bufs, _poly_cb2(C, T, T2), endpoint, all, timeout, l) + _put_user_data2(op, cb, p, p2) + exec(op) + + return op +} + +/* +Sends data to the socket. + +The `bufs` slice itself is copied into the operation, so it can be temporary (e.g. on the stack), but the underlying memory of the buffers must remain valid until the callback is fired. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- socket: The socket to send to +- bufs: Buffers containing the data to send +- p: User data, the callback will receive this as it's second argument +- p2: User data, the callback will receive this as it's third argument +- p3: User data, the callback will receive this as it's fourth argument +- cb: The callback to be called when the operation finishes, `Operation.send` will contain results +- endpoint: The destination endpoint (UDP only, ignored for TCP) +- all: If true, the operation ensures all data is sent before completing +- timeout: Optional timeout for the operation, the callback will get a `.Timeout` error after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +send_poly3 :: #force_inline proc( + socket: Any_Socket, + bufs: [][]byte, + p: $T, p2: $T2, p3: $T3, + cb: $C/proc(op: ^Operation, p: T, p2: T2, p3: T3), + endpoint: Endpoint = {}, + all := true, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_send(socket, bufs, _poly_cb3(C, T, T2, T3), endpoint, all, timeout, l) + _put_user_data3(op, cb, p, p2, p3) + exec(op) + + return op +} + +Read :: struct { + // Handle to read from. + handle: Handle, + // Buffer to read data into. + buf: []byte `fmt:"v,read"`, + // Offset to read from. + offset: int, + // Whether to read until the buffer is full or an error occurs. + all: bool, + // When this operation expires and should be timed out. + expires: time.Time, + + // Error, if it occurred. + err: FS_Error, + // Number of bytes read. + read: int, + + // Implementation specifics, private. + _impl: _Read `fmt:"-"`, +} + +/* +Retrieves and preps a positional read operation without executing it. + +This is a pread-style operation: the read starts at the given offset and does +not modify the handle's current file position. + +Executing can then be done with the `exec` procedure. + +The timeout is calculated from the time when this procedure was called, +not from when it's executed. + +Any user data can be set on the returned operation's `user_data` field. + +Inputs: +- handle: Handle to read from +- offset: Offset to read from +- buf: Buffer to read data into (must not be empty) +- cb: The callback to be called when the operation finishes, `Operation.read` will contain results +- all: Whether to read until the buffer is full or an error occurs +- timeout: Optional timeout for the operation +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +prep_read :: #force_inline proc( + handle: Handle, + offset: int, + buf: []byte, + cb: Callback, + all := false, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation { + assert(len(buf) > 0) + op := _prep(l, cb, .Read) + op.read.handle = handle + op.read.buf = buf + op.read.offset = offset + op.read.all = all + if timeout > 0 { + op.read.expires = time.time_add(now(), timeout) + } + return op +} + +/* +Reads data from a handle at a specific offset. + +This is a pread-style operation: the read starts at the given offset and does +not modify the handle's current file position. + +Any user data can be set on the returned operation's `user_data` field. +Polymorphic variants for type safe user data are available under `read_poly`, `read_poly2`, and `read_poly3`. + +Inputs: +- handle: Handle to read from +- offset: Offset to read from +- buf: Buffer to read data into (must not be empty) +- cb: The callback to be called when the operation finishes, `Operation.read` will contain results +- all: Whether to read until the buffer is full or an error occurs +- timeout: Optional timeout for the operation +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +read :: #force_inline proc( + handle: Handle, + offset: int, + buf: []byte, + cb: Callback, + all := false, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation { + op := prep_read(handle, offset, buf, cb, all, timeout, l) + exec(op) + return op +} + +/* +Reads data from a handle at a specific offset. + +This is a pread-style operation: the read starts at the given offset and does +not modify the handle's current file position. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- handle: Handle to read from +- offset: Offset to read from +- buf: Buffer to read data into (must not be empty) +- p: User data, the callback will receive this as its second argument +- cb: The callback to be called when the operation finishes, `Operation.read` will contain results +- all: Whether to read until the buffer is full or an error occurs +- timeout: Optional timeout for the operation +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +read_poly :: #force_inline proc( + handle: Handle, + offset: int, + buf: []byte, + p: $T, + cb: $C/proc(op: ^Operation, p: T), + all := false, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil +) -> ^Operation where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_read(handle, offset, buf, _poly_cb(C, T), all=all, timeout=timeout, l=l) + _put_user_data(op, cb, p) + exec(op) + + return op +} + +/* +Reads data from a handle at a specific offset. + +This is a pread-style operation: the read starts at the given offset and does +not modify the handle's current file position. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- handle: Handle to read from +- offset: Offset to read from +- buf: Buffer to read data into (must not be empty) +- p: User data, the callback will receive this as its second argument +- p2: User data, the callback will receive this as its third argument +- cb: The callback to be called when the operation finishes, `Operation.read` will contain results +- all: Whether to read until the buffer is full or an error occurs +- timeout: Optional timeout for the operation +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +read_poly2 :: #force_inline proc( + handle: Handle, + offset: int, + buf: []byte, + p: $T, p2: $T2, + cb: $C/proc(op: ^Operation, p: T, p2: T2), + all := false, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil +) -> ^Operation where size_of(T) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_read(handle, offset, buf, _poly_cb2(C, T, T2), all, timeout, l) + _put_user_data2(op, cb, p, p2) + exec(op) + + return op +} + +/* +Reads data from a handle at a specific offset. + +This is a pread-style operation: the read starts at the given offset and does +not modify the handle's current file position. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- handle: Handle to read from +- offset: Offset to read from +- buf: Buffer to read data into (must not be empty) +- p: User data, the callback will receive this as its second argument +- p2: User data, the callback will receive this as its third argument +- p3: User data, the callback will receive this as its fourth argument +- cb: The callback to be called when the operation finishes, `Operation.read` will contain results +- all: Whether to read until the buffer is full or an error occurs +- timeout: Optional timeout for the operation +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +read_poly3 :: #force_inline proc( + handle: Handle, + offset: int, + buf: []byte, + p: $T, p2: $T2, p3: $T3, + cb: $C/proc(op: ^Operation, p: T, p2: T2, p3: T3), + all := false, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil +) -> ^Operation where size_of(T) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_read(handle, offset, buf, _poly_cb3(C, T, T2, T3), all, timeout, l) + _put_user_data3(op, cb, p, p2, p3) + exec(op) + + return op +} + +Write :: struct { + // Handle to write to. + handle: Handle, + // Buffer containing data to write. + buf: []byte, + // Offset to write to. + offset: int, + // Whether to write until the buffer is fully written or an error occurs. + all: bool, + // When this operation expires and should be timed out. + expires: time.Time, + + // Error, if it occurred. + err: FS_Error, + // Number of bytes written. + written: int, + + // Implementation specifics, private. + _impl: _Write `fmt:"-"`, +} + +/* +Retrieves and preps a positional write operation without executing it. + +This is a pwrite-style operation: the write starts at the given offset and does +not modify the handle's current file position. + +Executing can then be done with the `exec` procedure. + +The timeout is calculated from the time when this procedure was called, +not from when it's executed. + +Any user data can be set on the returned operation's `user_data` field. + +Inputs: +- handle: Handle to write to +- offset: Offset to write to +- buf: Buffer containing data to write (must not be empty) +- cb: The callback to be called when the operation finishes, `Operation.write` will contain results +- all: Whether to write until the entire buffer is written or an error occurs +- timeout: Optional timeout for the operation +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +prep_write :: #force_inline proc( + handle: Handle, + offset: int, + buf: []byte, + cb: Callback, + all := true, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation { + assert(len(buf) > 0) + op := _prep(l, cb, .Write) + op.write.handle = handle + op.write.buf = buf + op.write.offset = offset + op.write.all = all + if timeout > 0 { + op.write.expires = time.time_add(now(), timeout) + } + return op +} + +/* +Writes data to a handle at a specific offset. + +This is a pwrite-style operation: the write starts at the given offset and does +not modify the handle's current file position. + +Any user data can be set on the returned operation's `user_data` field. +Polymorphic variants for type safe user data are available under `write_poly`, `write_poly2`, and `write_poly3`. + +Inputs: +- handle: Handle to write to +- offset: Offset to write to +- buf: Buffer containing data to write (must not be empty) +- cb: The callback to be called when the operation finishes, `Operation.write` will contain results +- all: Whether to write until the entire buffer is written or an error occurs +- timeout: Optional timeout for the operation +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +write :: #force_inline proc( + handle: Handle, + offset: int, + buf: []byte, + cb: Callback, + all := true, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation { + op := prep_write(handle, offset, buf, cb, all, timeout, l) + exec(op) + return op +} + +/* +Writes data to a handle at a specific offset. + +This is a pwrite-style operation: the write starts at the given offset and does +not modify the handle's current file position. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- handle: Handle to write to +- offset: Offset to write to +- buf: Buffer containing data to write (must not be empty) +- p: User data, the callback will receive this as its second argument +- cb: The callback to be called when the operation finishes, `Operation.write` will contain results +- all: Whether to write until the entire buffer is written or an error occurs +- timeout: Optional timeout for the operation +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +write_poly :: #force_inline proc( + handle: Handle, + offset: int, + buf: []byte, + p: $T, + cb: $C/proc(op: ^Operation, p: T), + all := true, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil +) -> ^Operation where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_write(handle, offset, buf, _poly_cb(C, T), all=all, timeout=timeout, l=l) + _put_user_data(op, cb, p) + exec(op) + + return op +} + +/* +Writes data to a handle at a specific offset. + +This is a pwrite-style operation: the write starts at the given offset and does +not modify the handle's current file position. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- handle: Handle to write to +- offset: Offset to write to +- buf: Buffer containing data to write (must not be empty) +- p: User data, the callback will receive this as its second argument +- p2: User data, the callback will receive this as its third argument +- cb: The callback to be called when the operation finishes, `Operation.write` will contain results +- all: Whether to write until the entire buffer is written or an error occurs +- timeout: Optional timeout for the operation +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +write_poly2 :: #force_inline proc( + handle: Handle, + offset: int, + buf: []byte, + p: $T, p2: $T2, + cb: $C/proc(op: ^Operation, p: T, p2: T2), + all := true, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil +) -> ^Operation where size_of(T) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_write(handle, offset, buf, _poly_cb2(C, T, T2), all, timeout, l) + _put_user_data2(op, cb, p, p2) + exec(op) + + return op +} + +/* +Writes data to a handle at a specific offset. + +This is a pwrite-style operation: the write starts at the given offset and does +not modify the handle's current file position. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- handle: Handle to write to +- offset: Offset to write to +- buf: Buffer containing data to write (must not be empty) +- p: User data, the callback will receive this as its second argument +- p2: User data, the callback will receive this as its third argument +- p3: User data, the callback will receive this as its fourth argument +- cb: The callback to be called when the operation finishes, `Operation.write` will contain results +- all: Whether to write until the entire buffer is written or an error occurs +- timeout: Optional timeout for the operation +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +write_poly3 :: #force_inline proc( + handle: Handle, + offset: int, + buf: []byte, + p: $T, p2: $T2, p3: $T3, + cb: $C/proc(op: ^Operation, p: T, p2: T2, p3: T3), + all := true, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil +) -> ^Operation where size_of(T) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_write(handle, offset, buf, _poly_cb3(C, T, T2, T3), all, timeout, l) + _put_user_data3(op, cb, p, p2, p3) + exec(op) + + return op +} + +Timeout :: struct { + // Duration after which the timeout expires. + duration: time.Duration, + + // Implementation specifics, private. + _impl: _Timeout `fmt:"-"`, +} + +/* +Retrieves and preps a timeout operation without executing it. + +Executing can then be done with the `exec` procedure. + +Any user data can be set on the returned operation's `user_data` field. + +Inputs: +- duration: Duration to wait before the operation completes +- cb: The callback to be called when the operation finishes +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +prep_timeout :: #force_inline proc( + duration: time.Duration, + cb: Callback, + l: ^Event_Loop = nil, +) -> ^Operation { + op := _prep(l, cb, .Timeout) + op.timeout.duration = duration + return op +} + +/* +Schedules a timeout that completes after the given duration. + +Any user data can be set on the returned operation's `user_data` field. +Polymorphic variants for type safe user data are available under `timeout_poly`, `timeout_poly2`, and `timeout_poly3`. + +Inputs: +- duration: Duration to wait before the operation completes +- cb: The callback to be called when the operation finishes +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +timeout :: #force_inline proc( + duration: time.Duration, + cb: Callback, + l: ^Event_Loop = nil, +) -> ^Operation { + op := prep_timeout(duration, cb, l) + exec(op) + return op +} + +/* +Schedules a timeout that completes after the given duration. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- dur: Duration to wait before the operation completes +- p: User data, the callback will receive this as its second argument +- cb: The callback to be called when the operation finishes +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +timeout_poly :: #force_inline proc( + dur: time.Duration, + p: $T, + cb: $C/proc(op: ^Operation, p: T), + l: ^Event_Loop = nil, +) -> ^Operation + where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_timeout(dur, _poly_cb(C, T), l) + _put_user_data(op, cb, p) + exec(op) + + return op +} + +/* +Schedules a timeout that completes after the given duration. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- dur: Duration to wait before the operation completes +- p: User data, the callback will receive this as its second argument +- p2: User data, the callback will receive this as its third argument +- cb: The callback to be called when the operation finishes +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +timeout_poly2 :: #force_inline proc( + dur: time.Duration, + p: $T, p2: $T2, + cb: $C/proc(op: ^Operation, p: T, p2: T2), + l: ^Event_Loop = nil, +) -> ^Operation + where size_of(T) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_timeout(dur, _poly_cb2(C, T, T2), l) + _put_user_data2(op, cb, p, p2) + exec(op) + + return op +} + +/* +Schedules a timeout that completes after the given duration. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- dur: Duration to wait before the operation completes +- p: User data, the callback will receive this as its second argument +- p2: User data, the callback will receive this as its third argument +- p3: User data, the callback will receive this as its fourth argument +- cb: The callback to be called when the operation finishes +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +timeout_poly3 :: #force_inline proc( + dur: time.Duration, + p: $T, p2: $T2, p3: $T3, + cb: $C/proc(op: ^Operation, p: T, p2: T2, p3: T3), + l: ^Event_Loop = nil, +) -> ^Operation + where size_of(T) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_timeout(dur, _poly_cb3(C, T, T2, T3), l) + _put_user_data3(op, cb, p, p2, p3) + exec(op) + + return op +} + +/* +Retrieves and preps an operation that completes on the next event loop tick. + +This is equivalent to `prep_timeout(0, ...)`. +*/ +prep_next_tick :: #force_inline proc(cb: Callback, l: ^Event_Loop = nil) -> ^Operation { + return prep_timeout(0, cb, l) +} + +/* +Schedules an operation that completes on the next event loop tick. + +This is equivalent to `timeout(0, ...)`. +*/ +next_tick :: #force_inline proc(cb: Callback, l: ^Event_Loop = nil) -> ^Operation { + return timeout(0, cb, l) +} + +/* +Schedules an operation that completes on the next event loop tick. + +This is equivalent to `timeout_poly(0, ...)`. +*/ +next_tick_poly :: #force_inline proc(p: $T, cb: $C/proc(op: ^Operation, p: T), l: ^Event_Loop = nil) -> ^Operation + where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + return timeout_poly(0, p, cb, l) +} + +/* +Schedules an operation that completes on the next event loop tick. + +This is equivalent to `timeout_poly2(0, ...)`. +*/ +next_tick_poly2 :: #force_inline proc(p: $T, p2: $T2, cb: $C/proc(op: ^Operation, p: T, p2: T2), l: ^Event_Loop = nil) -> ^Operation + where size_of(T) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + return timeout_poly2(0, p, p2, cb, l) +} + +/* +Schedules an operation that completes on the next event loop tick. + +This is equivalent to `timeout_poly3(0, ...)`. +*/ +next_tick_poly3 :: #force_inline proc(p: $T, p2: $T2, p3: $T3, cb: $C/proc(op: ^Operation, p: T, p2: T2, p3: T3), l: ^Event_Loop = nil) -> ^Operation + where size_of(T) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + return timeout_poly3(0, p, p2, p3, cb, l) +} + +Poll_Result :: enum i32 { + // The requested event is ready. + Ready, + // The operation timed out before the event became ready. + Timeout, + // The socket was invalid. + Invalid_Argument, + // An unspecified error occurred. + Error, +} + +Poll_Event :: enum { + // The subject is ready to be received from. + Receive, + // The subject is ready to be sent to. + Send, +} + +Poll :: struct { + // Socket to poll. + socket: Any_Socket, + // Event to poll for. + event: Poll_Event, + // When this operation expires and should be timed out. + expires: time.Time, + + // Result of the poll. + result: Poll_Result, + + // Implementation specifics, private. + _impl: _Poll `fmt:"-"`, +} + +/* +Retrieves and preps an operation to poll a socket without executing it. + +Executing can then be done with the `exec` procedure. + +The timeout is calculated from the time when this procedure was called, +not from when it's executed. + +Any user data can be set on the returned operation's `user_data` field. + +Inputs: +- socket: Socket to poll that is *associated with the event loop* +- event: Event to poll for +- cb: The callback to be called when the operation finishes, `Operation.poll` will contain results +- timeout: Optional timeout for the operation, the callback will receive a `.Timeout` result after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +prep_poll :: #force_inline proc( + socket: Any_Socket, + event: Poll_Event, + cb: Callback, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation { + op := _prep(l, cb, .Poll) + op.poll.socket = socket + op.poll.event = event + if timeout > 0 { + op.poll.expires = time.time_add(now(), timeout) + } + return op +} + +/* +Poll a socket for readiness. + +NOTE: this is provided to help with "legacy" APIs that require polling behavior. +If you can avoid it and use the other procs in this package, do so. + +Any user data can be set on the returned operation's `user_data` field. +Polymorphic variants for type safe user data are available under `poll_poly`, `poll_poly2`, and `poll_poly3`. + +Inputs: +- socket: Socket to poll that is *associated with the event loop* +- event: Event to poll for +- cb: The callback to be called when the operation finishes, `Operation.poll` will contain results +- timeout: Optional timeout for the operation, the callback will receive a `.Timeout` result after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +poll :: #force_inline proc( + socket: Any_Socket, + event: Poll_Event, + cb: Callback, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation { + op := prep_poll(socket, event, cb, timeout, l) + exec(op) + return op +} + +/* +Poll a socket for readiness. + +NOTE: this is provided to help with "legacy" APIs that require polling behavior. +If you can avoid it and use the other procs in this package, do so. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- socket: Socket to poll that is *associated with the event loop* +- event: Event to poll for +- p: User data, the callback will receive this as its second argument +- cb: The callback to be called when the operation finishes, `Operation.poll` will contain results +- timeout: Optional timeout for the operation, the callback will receive a `.Timeout` result after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +poll_poly :: #force_inline proc( + socket: Any_Socket, + event: Poll_Event, + p: $T, + cb: $C/proc(op: ^Operation, p: T), + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_poll(socket, event, _poly_cb(C, T), timeout, l) + _put_user_data(op, cb, p) + exec(op) + + return op +} + +/* +Poll a socket for readiness. + +NOTE: this is provided to help with "legacy" APIs that require polling behavior. +If you can avoid it and use the other procs in this package, do so. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- socket: Socket to poll that is *associated with the event loop* +- event: Event to poll for +- p: User data, the callback will receive this as its second argument +- p2: User data, the callback will receive this as its third argument +- cb: The callback to be called when the operation finishes, `Operation.poll` will contain results +- timeout: Optional timeout for the operation, the callback will receive a `.Timeout` result after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +poll_poly2 :: #force_inline proc( + socket: Any_Socket, + event: Poll_Event, + p: $T, p2: $T2, + cb: $C/proc(op: ^Operation, p: T, p2: T2), + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_poll(socket, event, _poly_cb2(C, T, T2), timeout, l) + _put_user_data2(op, cb, p, p2) + exec(op) + + return op +} + +/* +Poll a socket for readiness. + +NOTE: this is provided to help with "legacy" APIs that require polling behavior. +If you can avoid it and use the other procs in this package, do so. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- socket: Socket to poll that is *associated with the event loop* +- event: Event to poll for +- p: User data, the callback will receive this as its second argument +- p2: User data, the callback will receive this as its third argument +- p3: User data, the callback will receive this as its fourth argument +- cb: The callback to be called when the operation finishes, `Operation.poll` will contain results +- timeout: Optional timeout for the operation, the callback will receive a `.Timeout` result after that duration +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +poll_poly3 :: #force_inline proc( + socket: Any_Socket, + event: Poll_Event, + p: $T, p2: $T2, p3: $T3, + cb: $C/proc(op: ^Operation, p: T, p2: T2, p3: T3), + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_poll(socket, event, _poly_cb3(C, T, T2, T3), timeout, l) + _put_user_data3(op, cb, p, p2, p3) + exec(op) + + return op +} + +SEND_ENTIRE_FILE :: -1 + +Send_File_Error :: union #shared_nil { + FS_Error, + TCP_Send_Error, +} + +Send_File :: struct { + // The TCP socket to send the file over. + socket: TCP_Socket, + // The handle of the regular file to send. + file: Handle, + // When this operation expires and should be timed out. + expires: time.Time, + // The starting offset within the file. + offset: int, + // Number of bytes to send. If set to SEND_ENTIRE_FILE, the file size is retrieved + // automatically and this field is updated to reflect the full size. + nbytes: int, + // If true, the callback is triggered periodically as data is sent. + // The callback will continue to be called until `sent == nbytes` or an error occurs. + progress_updates: bool, + + // Total number of bytes (so far if `progress_updates` is true). + sent: int, + // An error, if it occurred. Can be a filesystem or networking error. + err: Send_File_Error, + + // Implementation specifics, private. + _impl: _Send_File `fmt:"-"`, +} + +/* +Retrieves and preps an operation to send a file over a socket without executing it. + +Executing can then be done with the `exec` procedure. + +This uses high-performance zero-copy system calls where available. +Note: This is emulated on NetBSD and OpenBSD (stat -> mmap -> send) as they lack a native sendfile implementation. + +Any user data can be set on the returned operation's `user_data` field. + +Inputs: +- socket: The destination TCP socket +- file: The source file handle +- cb: The callback to be called when data is sent (if `progress_updates` is true) or the operation completes +- offset: Byte offset to start reading from the file +- nbytes: Total bytes to send (use SEND_ENTIRE_FILE for the whole file) +- progress_updates: If true, the callback fires multiple times to report progress, `sent == nbytes` means te operation completed +- timeout: Optional timeout for the operation +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the final callback is called +*/ +prep_sendfile :: #force_inline proc( + socket: TCP_Socket, + file: Handle, + cb: Callback, + offset: int = 0, + nbytes: int = SEND_ENTIRE_FILE, + progress_updates := false, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation { + assert(offset >= 0) + assert(nbytes == SEND_ENTIRE_FILE || nbytes > 0) + op := _prep(l, cb, .Send_File) + op.sendfile.socket = socket + op.sendfile.file = file + if timeout > 0 { + op.sendfile.expires = time.time_add(now(), timeout) + } + op.sendfile.offset = offset + op.sendfile.nbytes = nbytes + op.sendfile.progress_updates = progress_updates + return op +} + +/* +Sends a file over a TCP socket. + +This uses high-performance zero-copy system calls where available. +Note: This is emulated on NetBSD and OpenBSD (stat -> mmap -> send) as they lack a native sendfile implementation. + +Any user data can be set on the returned operation's `user_data` field. +Polymorphic variants for type safe user data are available under `sendfile_poly`, `sendfile_poly2`, and `sendfile_poly3`. + +Inputs: +- socket: The destination TCP socket +- file: The source file handle +- cb: The callback to be called when data is sent (if `progress_updates` is true) or the operation completes +- offset: Byte offset to start reading from the file +- nbytes: Total bytes to send (use SEND_ENTIRE_FILE for the whole file) +- progress_updates: If true, the callback fires multiple times to report progress, `sent == nbytes` means te operation completed +- timeout: Optional timeout for the operation +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the final callback is called +*/ +sendfile :: #force_inline proc( + socket: TCP_Socket, + file: Handle, + cb: Callback, + offset: int = 0, + nbytes: int = SEND_ENTIRE_FILE, + progress_updates := false, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation { + op := prep_sendfile(socket, file, cb, offset, nbytes, progress_updates, timeout, l) + exec(op) + return op +} + +/* +Sends a file over a TCP socket. + +This uses high-performance zero-copy system calls where available. +Note: This is emulated on NetBSD and OpenBSD (stat -> mmap -> send) as they lack a native sendfile implementation. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- socket: The destination TCP socket +- file: The source file handle +- p: User data, the callback will receive this as it's second argument +- cb: The callback to be called when data is sent (if `progress_updates` is true) or the operation completes +- offset: Byte offset to start reading from the file +- nbytes: Total bytes to send (use SEND_ENTIRE_FILE for the whole file) +- progress_updates: If true, the callback fires multiple times to report progress, `sent == nbytes` means te operation completed +- timeout: Optional timeout for the operation +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the final callback is called +*/ +sendfile_poly :: #force_inline proc( + socket: TCP_Socket, + file: Handle, + p: $T, + cb: $C/proc(op: ^Operation, p: T), + offset: int = 0, + nbytes: int = SEND_ENTIRE_FILE, + progress_updates := false, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_sendfile(socket, file, _poly_cb(C, T), offset, nbytes, progress_updates, timeout, l) + _put_user_data(op, cb, p) + exec(op) + + return op +} + +/* +Sends a file over a TCP socket. + +This uses high-performance zero-copy system calls where available. +Note: This is emulated on NetBSD and OpenBSD (stat -> mmap -> send) as they lack a native sendfile implementation. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- socket: The destination TCP socket +- file: The source file handle +- p: User data, the callback will receive this as it's second argument +- p2: User data, the callback will receive this as it's third argument +- cb: The callback to be called when data is sent (if `progress_updates` is true) or the operation completes +- offset: Byte offset to start reading from the file +- nbytes: Total bytes to send (use SEND_ENTIRE_FILE for the whole file) +- progress_updates: If true, the callback fires multiple times to report progress, `sent == nbytes` means te operation completed +- timeout: Optional timeout for the operation +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the final callback is called +*/ +sendfile_poly2 :: #force_inline proc( + socket: TCP_Socket, + file: Handle, + p: $T, p2: $T2, + cb: $C/proc(op: ^Operation, p: T, p2: T2), + offset: int = 0, + nbytes: int = SEND_ENTIRE_FILE, + progress_updates := false, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_sendfile(socket, file, _poly_cb2(C, T, T2), offset, nbytes, progress_updates, timeout, l) + _put_user_data2(op, cb, p, p2) + exec(op) + + return op +} + +/* +Sends a file over a TCP socket. + +This uses high-performance zero-copy system calls where available. +Note: This is emulated on NetBSD and OpenBSD (stat -> mmap -> send) as they lack a native sendfile implementation. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- socket: The destination TCP socket +- file: The source file handle +- p: User data, the callback will receive this as it's second argument +- p2: User data, the callback will receive this as it's third argument +- p3: User data, the callback will receive this as it's fourth argument +- cb: The callback to be called when data is sent (if `progress_updates` is true) or the operation completes +- offset: Byte offset to start reading from the file +- nbytes: Total bytes to send (use SEND_ENTIRE_FILE for the whole file) +- progress_updates: If true, the callback fires multiple times to report progress, `sent == nbytes` means te operation completed +- timeout: Optional timeout for the operation +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the final callback is called +*/ +sendfile_poly3 :: #force_inline proc( + socket: TCP_Socket, + file: Handle, + p: $T, p2: $T2, p3: $T3, + cb: $C/proc(op: ^Operation, p: T, p2: T2, p3: T3), + offset: int = 0, + nbytes: int = SEND_ENTIRE_FILE, + progress_updates := false, + timeout: time.Duration = NO_TIMEOUT, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_sendfile(socket, file, _poly_cb3(C, T, T2, T3), offset, nbytes, progress_updates, timeout, l) + _put_user_data3(op, cb, p, p2, p3) + exec(op) + + return op +} + +/* +File permission bit-set. + +This type represents POSIX-style file permissions, split into user, group, +and other categories, each with read, write, and execute flags. +*/ +Permissions :: distinct bit_set[Permission_Flag; u32] + +Permission_Flag :: enum u32 { + Execute_Other = 0, + Write_Other = 1, + Read_Other = 2, + + Execute_Group = 3, + Write_Group = 4, + Read_Group = 5, + + Execute_User = 6, + Write_User = 7, + Read_User = 8, +} + +// Convenience permission sets. +Permissions_Execute_All :: Permissions{.Execute_User, .Execute_Group, .Execute_Other} +Permissions_Write_All :: Permissions{.Write_User, .Write_Group, .Write_Other} +Permissions_Read_All :: Permissions{.Read_User, .Read_Group, .Read_Other} + +// Read and write permissions for user, group, and others. +Permissions_Read_Write_All :: Permissions_Read_All + Permissions_Write_All + +// Read, write, and execute permissions for user, group, and others. +Permissions_All :: Permissions_Read_All + Permissions_Write_All + Permissions_Execute_All + +// Default permissions used when creating a file (read and write for everyone). +Permissions_Default_File :: Permissions_Read_All + Permissions_Write_All + +// Default permissions used when creating a directory (read, write, and execute for everyone). +Permissions_Default_Directory :: Permissions_Read_All + Permissions_Write_All + Permissions_Execute_All + +File_Flags :: bit_set[File_Flag; int] + +File_Flag :: enum { + // Open for reading. + Read, + // Open for writing. + Write, + // Append writes to the end of the file. + Append, + // Create the file if it does not exist. + Create, + // Fail if the file already exists (used with Create). + Excl, + Sync, + // Truncate the file on open. + Trunc, +} + +Open :: struct { + // Base directory the path is relative to. + dir: Handle, + // Path to the file. + path: string, + // File open mode flags. + mode: File_Flags, + // Permissions used if the file is created. + perm: Permissions, + + // The opened file handle. + handle: Handle, + // An error, if it occurred. + err: FS_Error, + + // Implementation specifics, private. + _impl: _Open `fmt:"-"`, +} + +// Sentinel handle representing the current/present working directory. +CWD :: _CWD + +/* +Retrieves and preps an operation to open a file without executing it. + +Executing can then be done with the `exec` procedure. + +Any user data can be set on the returned operation's `user_data` field. + +Inputs: +- path: Path to the file, if not absolute: relative from `dir` +- cb: The callback to be called when the operation finishes, `Operation.open` will contain results +- mode: File open mode flags, defaults to read-only +- perm: Permissions to use when creating a file, defaults to read+write for everybody +- dir: Directory that `path` is relative from (if it is relative), defaults to the current working directory +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +prep_open :: #force_inline proc( + path: string, + cb: Callback, + mode: File_Flags = {.Read}, + perm: Permissions = Permissions_Default_File, + dir: Handle = CWD, + l: ^Event_Loop = nil, +) -> ^Operation { + op := _prep(l, cb, .Open) + op.open.path = path + op.open.mode = mode + op.open.perm = perm + op.open.dir = dir + return op +} + +/* +Opens a file and associates it with the event loop. + +Any user data can be set on the returned operation's `user_data` field. +Polymorphic variants for type safe user data are available under `open_poly`, `open_poly2`, and `open_poly3`. + +Inputs: +- path: Path to the file, if not absolute: relative from `dir` +- cb: The callback to be called when the operation finishes, `Operation.open` will contain results +- mode: File open mode flags, defaults to read-only +- perm: Permissions to use when creating a file, defaults to read+write for everybody +- dir: Directory that `path` is relative from (if it is relative), defaults to the current working directory +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +open :: #force_inline proc( + path: string, + cb: Callback, + mode: File_Flags = {.Read}, + perm: Permissions = Permissions_Default_File, + dir: Handle = CWD, + l: ^Event_Loop = nil, +) -> ^Operation { + op := prep_open(path, cb, mode, perm, dir, l) + exec(op) + return op +} + +/* +Opens a file and associates it with the event loop. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- path: Path to the file, if not absolute: relative from `dir` +- p: User data, the callback will receive this as its second argument +- cb: The callback to be called when the operation finishes, `Operation.open` will contain results +- mode: File open mode flags, defaults to read-only +- perm: Permissions to use when creating a file, defaults to read+write for everybody +- dir: Directory that `path` is relative from (if it is relative), defaults to the current working directory +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +open_poly :: #force_inline proc( + path: string, + p: $T, + cb: $C/proc(op: ^Operation, p: T), + mode: File_Flags = {.Read}, + perm: Permissions = Permissions_Default_File, + dir: Handle = CWD, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_open(path, _poly_cb(C, T), mode, perm, dir, l) + _put_user_data(op, cb, p) + exec(op) + + return op +} + +/* +Opens a file and associates it with the event loop. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- path: Path to the file, if not absolute: relative from `dir` +- p: User data, the callback will receive this as its second argument +- p2: User data, the callback will receive this as its third argument +- cb: The callback to be called when the operation finishes, `Operation.open` will contain results +- mode: File open mode flags, defaults to read-only +- perm: Permissions to use when creating a file, defaults to read+write for everybody +- dir: Directory that `path` is relative from (if it is relative), defaults to the current working directory +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +open_poly2 :: #force_inline proc( + path: string, + p: $T, p2: $T2, + cb: $C/proc(op: ^Operation, p: T, p2: T2), + mode: File_Flags = {.Read}, + perm: Permissions = Permissions_Default_File, + dir: Handle = CWD, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_open(path, _poly_cb2(C, T, T2), mode, perm, dir, l) + _put_user_data2(op, cb, p, p2) + exec(op) + + return op +} + +/* +Asynchronously opens a file and associates it with the event loop. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- path: Path to the file, if not absolute: relative from `dir` +- p: User data, the callback will receive this as its second argument +- p2: User data, the callback will receive this as its third argument +- p3: User data, the callback will receive this as its fourth argument +- cb: The callback to be called when the operation finishes, `Operation.open` will contain results +- mode: File open mode flags, defaults to read-only +- perm: Permissions to use when creating a file, defaults to read+write for everybody +- dir: Directory that `path` is relative from (if it is relative), defaults to the current working directory +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +open_poly3 :: #force_inline proc( + path: string, + p: $T, p2: $T2, p3: $T3, + cb: $C/proc(op: ^Operation, p: T, p2: T2, p3: T3), + mode: File_Flags = {.Read}, + perm: Permissions = Permissions_Default_File, + dir: Handle = CWD, + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_open(path, _poly_cb3(C, T, T2, T3), mode, perm, dir, l) + _put_user_data3(op, cb, p, p2, p3) + exec(op) + + return op +} + +File_Type :: enum { + // File type could not be determined. + Undetermined, + // Regular file. + Regular, + // Directory. + Directory, + // Symbolic link. + Symlink, + // Pipe or socket. + Pipe_Or_Socket, + // Character or block device. + Device, +} + +Stat :: struct { + // Handle to stat. + handle: Handle, + + // The type of the file. + type: File_Type, + // Size of the file in bytes. + size: i64 `fmt:"M"`, + + // An error, if it occurred. + err: FS_Error, + + // Implementation specifics, private. + _impl: _Stat `fmt:"-"`, +} + +/* +Retrieves and preps an operation to stat a handle without executing it. + +Executing can then be done with the `exec` procedure. + +Any user data can be set on the returned operation's `user_data` field. + +Inputs: +- handle: Handle to retrieve stat +- cb: The callback to be called when the operation finishes, `Operation.stat` will contain results +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +prep_stat :: #force_inline proc( + handle: Handle, + cb: Callback, + l: ^Event_Loop = nil, +) -> ^Operation { + op := _prep(l, cb, .Stat) + op.stat.handle = handle + return op +} + +/* +Stats a handle. + +Any user data can be set on the returned operation's `user_data` field. +Polymorphic variants for type safe user data are available under `stat_poly`, `stat_poly2`, and `stat_poly3`. + +Inputs: +- handle: Handle to retrieve status information for +- cb: The callback to be called when the operation finishes, `Operation.stat` will contain results +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +stat :: #force_inline proc( + handle: Handle, + cb: Callback, + l: ^Event_Loop = nil, +) -> ^Operation { + op := prep_stat(handle, cb, l) + exec(op) + return op +} + +/* +Stats a handle. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- handle: Handle to retrieve status information for +- p: User data, the callback will receive this as its second argument +- cb: The callback to be called when the operation finishes, `Operation.stat` will contain results +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +stat_poly :: #force_inline proc( + handle: Handle, + p: $T, + cb: $C/proc(op: ^Operation, p: T), + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_stat(handle, _poly_cb(C, T), l) + _put_user_data(op, cb, p) + exec(op) + + return op +} + +/* +Stats a handle. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- handle: Handle to retrieve status information for +- p: User data, the callback will receive this as its second argument +- p2: User data, the callback will receive this as its third argument +- cb: The callback to be called when the operation finishes, `Operation.stat` will contain results +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +stat_poly2 :: #force_inline proc( + handle: Handle, + p: $T, p2: $T2, + cb: $C/proc(op: ^Operation, p: T, p2: T2), + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_stat(handle, _poly_cb2(C, T, T2), l) + _put_user_data2(op, cb, p, p2) + exec(op) + + return op +} + +/* +Stats a handle. + +This procedure uses polymorphism for type safe user data up to a certain size. + +Inputs: +- handle: Handle to retrieve status information for +- p: User data, the callback will receive this as its second argument +- p2: User data, the callback will receive this as its third argument +- p3: User data, the callback will receive this as its fourth argument +- cb: The callback to be called when the operation finishes, `Operation.stat` will contain results +- l: Event loop to associate the operation with, defaults to the current thread's loop + +Returns: A non-nil pointer to the operation, alive until the callback is called +*/ +stat_poly3 :: #force_inline proc( + handle: Handle, + p: $T, p2: $T2, p3: $T3, + cb: $C/proc(op: ^Operation, p: T, p2: T2, p3: T3), + l: ^Event_Loop = nil, +) -> ^Operation where size_of(T) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { + + op := prep_stat(handle, _poly_cb3(C, T, T2, T3), l) + _put_user_data3(op, cb, p, p2, p3) + exec(op) + + return op +} + +_prep :: proc(l: ^Event_Loop, cb: Callback, type: Operation_Type) -> ^Operation { + assert(cb != nil) + assert(type != .None) + l := l + if l == nil { l = _current_thread_event_loop() } + operation := pool.get(&l.operation_pool) + operation.l = l + operation.type = type + operation.cb = cb + return operation +} + +_poly_cb :: #force_inline proc($C: typeid, $T: typeid) -> proc(^Operation) { + return proc(op: ^Operation) { + ptr := uintptr(&op.user_data) + cb := intrinsics.unaligned_load((^C)(rawptr(ptr))) + p := intrinsics.unaligned_load((^T)(rawptr(ptr + size_of(C)))) + cb(op, p) + } +} + +_poly_cb2 :: #force_inline proc($C: typeid, $T: typeid, $T2: typeid) -> proc(^Operation) { + return proc(op: ^Operation) { + ptr := uintptr(&op.user_data) + cb := intrinsics.unaligned_load((^C) (rawptr(ptr))) + p := intrinsics.unaligned_load((^T) (rawptr(ptr + size_of(C)))) + p2 := intrinsics.unaligned_load((^T2)(rawptr(ptr + size_of(C) + size_of(T)))) + cb(op, p, p2) + } +} + +_poly_cb3 :: #force_inline proc($C: typeid, $T: typeid, $T2: typeid, $T3: typeid) -> proc(^Operation) { + return proc(op: ^Operation) { + ptr := uintptr(&op.user_data) + cb := intrinsics.unaligned_load((^C) (rawptr(ptr))) + p := intrinsics.unaligned_load((^T) (rawptr(ptr + size_of(C)))) + p2 := intrinsics.unaligned_load((^T2)(rawptr(ptr + size_of(C) + size_of(T)))) + p3 := intrinsics.unaligned_load((^T3)(rawptr(ptr + size_of(C) + size_of(T) + size_of(T2)))) + cb(op, p, p2, p3) + } +} + +_put_user_data :: #force_inline proc(op: ^Operation, cb: $C, p: $T) { + ptr := uintptr(&op.user_data) + intrinsics.unaligned_store((^C)(rawptr(ptr)), cb) + intrinsics.unaligned_store((^T)(rawptr(ptr + size_of(cb))), p) +} + +_put_user_data2 :: #force_inline proc(op: ^Operation, cb: $C, p: $T, p2: $T2) { + ptr := uintptr(&op.user_data) + intrinsics.unaligned_store((^C) (rawptr(ptr)), cb) + intrinsics.unaligned_store((^T) (rawptr(ptr + size_of(cb))), p) + intrinsics.unaligned_store((^T2)(rawptr(ptr + size_of(cb) + size_of(p))), p2) +} + +_put_user_data3 :: #force_inline proc(op: ^Operation, cb: $C, p: $T, p2: $T2, p3: $T3) { + ptr := uintptr(&op.user_data) + intrinsics.unaligned_store((^C) (rawptr(ptr)), cb) + intrinsics.unaligned_store((^T) (rawptr(ptr + size_of(cb))), p) + intrinsics.unaligned_store((^T2)(rawptr(ptr + size_of(cb) + size_of(p))), p2) + intrinsics.unaligned_store((^T3)(rawptr(ptr + size_of(cb) + size_of(p) + size_of(p2))), p3) +} diff --git a/core/net/addr.odin b/core/net/addr.odin index fad0eddc4..888744841 100644 --- a/core/net/addr.odin +++ b/core/net/addr.odin @@ -1,4 +1,3 @@ -#+build windows, linux, darwin, freebsd package net /* @@ -22,7 +21,6 @@ package net import "core:strconv" import "core:strings" -import "core:fmt" /* Expects an IPv4 address with no leading or trailing whitespace: @@ -461,31 +459,63 @@ split_port :: proc(endpoint_str: string) -> (addr_or_host: string, port: int, ok return } -// Joins an address or hostname with a port. -join_port :: proc(address_or_host: string, port: int, allocator := context.allocator) -> string { +// Joins an address or hostname with a port, allocated using an Allocator. +join_port_allocator :: proc(address_or_host: string, port: int, allocator := context.allocator) -> string { addr_or_host, _, ok := split_port(address_or_host) if !ok { return addr_or_host } b := strings.builder_make(allocator) + addr := parse_address(addr_or_host) + if addr == nil { + // hostname + strings.write_string(&b, addr_or_host) + strings.write_string(&b, ":") + strings.write_int(&b, port) + return strings.to_string(b) + } else { + return _join_port_internal(addr, port, &b) + } +} + +// Joins an address or hostname with a port, allocated using a `strings.Builder`. +join_port_builder :: proc(address_or_host: string, port: int, b: ^strings.Builder) -> string { + addr_or_host, _, ok := split_port(address_or_host) + if !ok { + return addr_or_host + } addr := parse_address(addr_or_host) if addr == nil { // hostname - fmt.sbprintf(&b, "%v:%v", addr_or_host, port) + strings.write_string(b, addr_or_host) + strings.write_string(b, ":") + strings.write_int(b, port) + return strings.to_string(b^) } else { - switch _ in addr { - case IP4_Address: - fmt.sbprintf(&b, "%v:%v", address_to_string(addr), port) - case IP6_Address: - fmt.sbprintf(&b, "[%v]:%v", address_to_string(addr), port) - } + return _join_port_internal(addr, port, b) } - return strings.to_string(b) } +join_port :: proc{join_port_allocator, join_port_builder} +// Also used in `endpoint_to_string_builder`. +@(private) +_join_port_internal :: proc(addr: Address, port: int, b: ^strings.Builder) -> string { + switch a in addr { + case IP4_Address: + address_to_string_builder(addr, b) + strings.write_string(b, ":") + strings.write_int(b, port) + case IP6_Address: + strings.write_string(b, "[") + address_to_string_builder(addr, b) + strings.write_string(b, "]:") + strings.write_int(b, port) + } + return strings.to_string(b^) +} // TODO(tetra): Do we need this? map_to_ip6 :: proc(addr: Address) -> Address { @@ -495,8 +525,8 @@ map_to_ip6 :: proc(addr: Address) -> Address { addr4 := addr.(IP4_Address) addr4_u16 := transmute([2]u16be) addr4 addr6: IP6_Address - addr6[4] = 0xffff - copy(addr6[5:], addr4_u16[:]) + addr6[5] = 0xffff + copy(addr6[6:], addr4_u16[:]) return addr6 } @@ -505,11 +535,26 @@ map_to_ip6 :: proc(addr: Address) -> Address { See RFC 5952 section 4 for IPv6 representation recommendations. */ -address_to_string :: proc(addr: Address, allocator := context.temp_allocator) -> string { +address_to_string_allocator :: proc(addr: Address, allocator := context.temp_allocator) -> string { b := strings.builder_make(allocator) + return address_to_string_builder(addr, &b) +} + +/* + Returns a string representation of the address using a `strings.Builder`. + + See RFC 5952 section 4 for IPv6 representation recommendations. +*/ +address_to_string_builder :: proc(addr: Address, b: ^strings.Builder) -> string { switch v in addr { case IP4_Address: - fmt.sbprintf(&b, "%v.%v.%v.%v", v[0], v[1], v[2], v[3]) + strings.write_uint(b, uint(v[0])) + strings.write_byte(b, '.') + strings.write_uint(b, uint(v[1])) + strings.write_byte(b, '.') + strings.write_uint(b, uint(v[2])) + strings.write_byte(b, '.') + strings.write_uint(b, uint(v[3])) case IP6_Address: // First find the longest run of zeroes. Zero_Run :: struct { @@ -563,50 +608,61 @@ address_to_string :: proc(addr: Address, allocator := context.temp_allocator) -> for val, i in v { if best.start == i || best.end == i { // For the left and right side of the best zero run, print a `:`. - fmt.sbprint(&b, ":") + strings.write_string(b, ":") } else if i < best.start { /* If we haven't made it to the best run yet, print the digit. Make sure we only print a `:` after the digit if it's not immediately followed by the run's own leftmost `:`. */ - fmt.sbprintf(&b, "%x", val) + + buf: [32]byte + str := strconv.write_bits(buf[:], u64(val), 16, false, size_of(val), strconv.digits, {}) + strings.write_string(b, str) + if i < best.start - 1 { - fmt.sbprintf(&b, ":") + strings.write_string(b, ":") } } else if i > best.end { /* If there are any digits after the zero run, print them. But don't print the `:` at the end of the IP number. */ - fmt.sbprintf(&b, "%x", val) + + buf: [32]byte + str := strconv.write_bits(buf[:], u64(val), 16, false, size_of(val), strconv.digits, {}) + strings.write_string(b, str) + if i != 7 { - fmt.sbprintf(&b, ":") + strings.write_string(b, ":") } } } } - return strings.to_string(b) + return strings.to_string(b^) } +address_to_string :: proc{address_to_string_allocator, address_to_string_builder} // Returns a temporarily-allocated string representation of the endpoint. // If there's a port, uses the `ip4address:port` or `[ip6address]:port` format, respectively. -endpoint_to_string :: proc(ep: Endpoint, allocator := context.temp_allocator) -> string { +endpoint_to_string_allocator :: proc(ep: Endpoint, allocator := context.temp_allocator) -> string { + b := strings.builder_make(allocator) + return endpoint_to_string_builder(ep, &b) +} + +// Returns a string representation of the endpoint using a `strings.Builder`. +// If there's a port, uses the `ip4address:port` or `[ip6address]:port` format, respectively. +endpoint_to_string_builder :: proc(ep: Endpoint, b: ^strings.Builder) -> string { if ep.port == 0 { - return address_to_string(ep.address, allocator) + return address_to_string(ep.address, b) } else { - s := address_to_string(ep.address, context.temp_allocator) - b := strings.builder_make(allocator) - switch a in ep.address { - case IP4_Address: fmt.sbprintf(&b, "%v:%v", s, ep.port) - case IP6_Address: fmt.sbprintf(&b, "[%v]:%v", s, ep.port) - } - return strings.to_string(b) + return _join_port_internal(ep.address, ep.port, b) } } -to_string :: proc{address_to_string, endpoint_to_string} +endpoint_to_string :: proc{endpoint_to_string_allocator, endpoint_to_string_builder} +to_string :: proc{address_to_string_allocator, address_to_string_builder, endpoint_to_string_allocator, endpoint_to_string_builder} family_from_address :: proc(addr: Address) -> Address_Family { switch _ in addr { diff --git a/core/net/common.odin b/core/net/common.odin index 70523050f..2758a7359 100644 --- a/core/net/common.odin +++ b/core/net/common.odin @@ -1,4 +1,3 @@ -#+build windows, linux, darwin, freebsd package net /* @@ -91,6 +90,7 @@ Parse_Endpoint_Error :: enum u32 { Resolve_Error :: enum u32 { None = 0, Unable_To_Resolve = 1, + Allocation_Failure, } DNS_Error :: enum u32 { @@ -144,11 +144,11 @@ Address :: union {IP4_Address, IP6_Address} IP4_Loopback :: IP4_Address{127, 0, 0, 1} IP6_Loopback :: IP6_Address{0, 0, 0, 0, 0, 0, 0, 1} -IP4_Any := IP4_Address{} -IP6_Any := IP6_Address{} +IP4_Any :: IP4_Address{} +IP6_Any :: IP6_Address{} -IP4_mDNS_Broadcast := Endpoint{address=IP4_Address{224, 0, 0, 251}, port=5353} -IP6_mDNS_Broadcast := Endpoint{address=IP6_Address{65282, 0, 0, 0, 0, 0, 0, 251}, port = 5353} +IP4_mDNS_Broadcast :: Endpoint{address=IP4_Address{224, 0, 0, 251}, port=5353} +IP6_mDNS_Broadcast :: Endpoint{address=IP6_Address{65282, 0, 0, 0, 0, 0, 0, 251}, port = 5353} Endpoint :: struct { address: Address, diff --git a/core/net/dns.odin b/core/net/dns.odin index 540991fe7..54cc57c38 100644 --- a/core/net/dns.odin +++ b/core/net/dns.odin @@ -1,4 +1,3 @@ -#+build windows, linux, darwin, freebsd package net /* @@ -22,13 +21,16 @@ package net Haesbaert: Security fixes */ -@(require) import "base:runtime" +@(require) +import "base:runtime" +import "core:bufio" +import "core:io" import "core:mem" import "core:strings" import "core:time" -import "core:os" -import "core:math/rand" -@(require) import "core:sync" + +@(require) +import "core:sync" dns_config_initialized: sync.Once when ODIN_OS == .Windows { @@ -42,20 +44,12 @@ when ODIN_OS == .Windows { hosts_file = "/etc/hosts", } } else { - #panic("Please add a configuration for this OS.") + DEFAULT_DNS_CONFIGURATION :: DNS_Configuration{} } -/* - Replaces environment placeholders in `dns_configuration`. Only necessary on Windows. - Is automatically called, once, by `get_dns_records_*`. -*/ -@(private) init_dns_configuration :: proc() { when ODIN_OS == .Windows { - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - val := os.replace_environment_placeholders(dns_configuration.hosts_file, context.temp_allocator) - copy(dns_configuration.hosts_file_buf[:], val) - dns_configuration.hosts_file = string(dns_configuration.hosts_file_buf[:len(val)]) + _init_dns_configuration() } } @@ -178,9 +172,7 @@ resolve_ip6 :: proc(hostname_and_maybe_port: string) -> (ep6: Endpoint, err: Net See `destroy_records`. */ get_dns_records_from_os :: proc(hostname: string, type: DNS_Record_Type, allocator := context.allocator) -> (records: []DNS_Record, err: DNS_Error) { - when ODIN_OS == .Windows { - sync.once_do(&dns_config_initialized, init_dns_configuration) - } + init_dns_configuration() return _get_dns_records_os(hostname, type, allocator) } @@ -196,51 +188,17 @@ get_dns_records_from_os :: proc(hostname: string, type: DNS_Record_Type, allocat See `destroy_records`. */ get_dns_records_from_nameservers :: proc(hostname: string, type: DNS_Record_Type, name_servers: []Endpoint, host_overrides: []DNS_Record, allocator := context.allocator) -> (records: []DNS_Record, err: DNS_Error) { - when ODIN_OS == .Windows { - sync.once_do(&dns_config_initialized, init_dns_configuration) - } + init_dns_configuration() context.allocator = allocator - if type != .SRV { - // NOTE(tetra): 'hostname' can contain underscores when querying SRV records - ok := validate_hostname(hostname) - if !ok { - return nil, .Invalid_Hostname_Error - } - } + id: u16be + rand_ok := runtime.random_generator_read_ptr(context.random_generator, &id, size_of(id)) + assert(rand_ok, "uninitialized gen/context.random_generator") - hdr := DNS_Header{ - id = u16be(rand.uint32()), - is_response = false, - opcode = 0, - is_authoritative = false, - is_truncated = false, - is_recursion_desired = true, - is_recursion_available = false, - response_code = DNS_Response_Code.No_Error, - } + dns_packet_buf: [DNS_PACKET_MIN_LEN]byte = --- + dns_packet := make_dns_packet(dns_packet_buf[:], id, hostname, type) or_return - id, bits := pack_dns_header(hdr) - dns_hdr := [6]u16be{} - dns_hdr[0] = id - dns_hdr[1] = bits - dns_hdr[2] = 1 - - dns_query := [2]u16be{ u16be(type), 1 } - - output := [(size_of(u16be) * 6) + NAME_MAX + (size_of(u16be) * 2)]u8{} - b := strings.builder_from_slice(output[:]) - - strings.write_bytes(&b, mem.slice_data_cast([]u8, dns_hdr[:])) - ok := encode_hostname(&b, hostname) - if !ok { - return nil, .Invalid_Hostname_Error - } - strings.write_bytes(&b, mem.slice_data_cast([]u8, dns_query[:])) - - dns_packet := output[:strings.builder_len(b)] - - dns_response_buf := [4096]u8{} + dns_response_buf: [4096]u8 = --- dns_response: []u8 for name_server in name_servers { conn, sock_err := make_unbound_udp_socket(family_from_endpoint(name_server)) @@ -283,6 +241,42 @@ get_dns_records_from_nameservers :: proc(hostname: string, type: DNS_Record_Type return } +DNS_PACKET_MIN_LEN :: (size_of(u16be) * 6) + NAME_MAX + (size_of(u16be) * 2) + +make_dns_packet :: proc(buf: []byte, id: u16be, hostname: string, type: DNS_Record_Type) -> (packet: []byte, err: DNS_Error) { + assert(len(buf) >= DNS_PACKET_MIN_LEN) + + hdr := DNS_Header{ + id = id, + is_response = false, + opcode = 0, + is_authoritative = false, + is_truncated = false, + is_recursion_desired = true, + is_recursion_available = false, + response_code = DNS_Response_Code.No_Error, + } + + _, bits := pack_dns_header(hdr) + dns_hdr := [6]u16be{} + dns_hdr[0] = id + dns_hdr[1] = bits + dns_hdr[2] = 1 + + dns_query := [2]u16be{ u16be(type), 1 } + + b := strings.builder_from_slice(buf[:]) + + strings.write_bytes(&b, mem.slice_data_cast([]u8, dns_hdr[:])) + ok := encode_hostname(&b, hostname) + if !ok { + return nil, .Invalid_Hostname_Error + } + strings.write_bytes(&b, mem.slice_data_cast([]u8, dns_query[:])) + + return buf[:strings.builder_len(b)], nil +} + // `records` slice is also destroyed. destroy_dns_records :: proc(records: []DNS_Record, allocator := context.allocator) { context.allocator = allocator @@ -364,13 +358,8 @@ unpack_dns_header :: proc(id: u16be, bits: u16be) -> (hdr: DNS_Header) { return hdr } -load_resolv_conf :: proc(resolv_conf_path: string, allocator := context.allocator) -> (name_servers: []Endpoint, ok: bool) { - context.allocator = allocator - - res := os.read_entire_file_from_filename(resolv_conf_path) or_return - defer delete(res) - resolv_str := string(res) - +parse_resolv_conf :: proc(resolv_str: string, allocator := context.allocator) -> (name_servers: []Endpoint) { + resolv_str := resolv_str id_str := "nameserver" id_len := len(id_str) @@ -401,41 +390,51 @@ load_resolv_conf :: proc(resolv_conf_path: string, allocator := context.allocato append(&_name_servers, endpoint) } - return _name_servers[:], true + return _name_servers[:] } -load_hosts :: proc(hosts_file_path: string, allocator := context.allocator) -> (hosts: []DNS_Host_Entry, ok: bool) { - context.allocator = allocator +parse_hosts :: proc(stream: io.Stream, allocator := context.allocator) -> (hosts: []DNS_Host_Entry, ok: bool) { + s := bufio.scanner_init(&{}, stream, allocator) + defer bufio.scanner_destroy(s) - res := os.read_entire_file_from_filename(hosts_file_path, allocator) or_return - defer delete(res) + resize(&s.buf, 256) - _hosts := make([dynamic]DNS_Host_Entry, 0, allocator) - hosts_str := string(res) - for line in strings.split_lines_iterator(&hosts_str) { - if len(line) == 0 || line[0] == '#' { - continue + _hosts: [dynamic]DNS_Host_Entry + _hosts.allocator = allocator + defer if !ok { + for host in _hosts { + delete(host.name, allocator) } + delete(_hosts) + } - splits := strings.fields(line) - defer delete(splits) + for bufio.scanner_scan(s) { + line := bufio.scanner_text(s) - (len(splits) >= 2) or_continue + line, _, _ = strings.partition(line, "#") + (len(line) > 0) or_continue + + ip_str := strings.fields_iterator(&line) or_continue - ip_str := splits[0] addr := parse_address(ip_str) - if addr == nil { - continue - } + (addr != nil) or_continue - for hostname in splits[1:] { - if len(hostname) != 0 { - append(&_hosts, DNS_Host_Entry{hostname, addr}) - } + for hostname in strings.fields_iterator(&line) { + (len(hostname) > 0) or_continue + + clone, alloc_err := strings.clone(hostname, allocator) + if alloc_err != nil { return } + + _, alloc_err = append(&_hosts, DNS_Host_Entry{clone, addr}) + if alloc_err != nil { return } } } - return _hosts[:], true + if bufio.scanner_error(s) != nil { return } + + hosts = _hosts[:] + ok = true + return } // www.google.com -> 3www6google3com0 @@ -594,7 +593,7 @@ decode_hostname :: proc(packet: []u8, start_idx: int, allocator := context.alloc // Uses RFC 952 & RFC 1123 validate_hostname :: proc(hostname: string) -> (ok: bool) { - if len(hostname) > 255 || len(hostname) == 0 { + if len(hostname) > NAME_MAX || len(hostname) == 0 { return } @@ -604,7 +603,7 @@ validate_hostname :: proc(hostname: string) -> (ok: bool) { _hostname := hostname for label in strings.split_iterator(&_hostname, ".") { - if len(label) > 63 || len(label) == 0 { + if len(label) > LABEL_MAX || len(label) == 0 { return } @@ -868,4 +867,4 @@ parse_response :: proc(response: []u8, filter: DNS_Record_Type = nil, allocator xid = hdr.id return _records[:], xid, true -} \ No newline at end of file +} diff --git a/core/net/dns_os.odin b/core/net/dns_os.odin new file mode 100644 index 000000000..ad9724d37 --- /dev/null +++ b/core/net/dns_os.odin @@ -0,0 +1,24 @@ +#+build darwin, freebsd, openbsd, netbsd, linux, windows, wasi +#+private +package net + +import "core:os" + +load_resolv_conf :: proc(resolv_conf_path: string, allocator := context.allocator) -> (name_servers: []Endpoint, ok: bool) { + context.allocator = allocator + + res, err := os.read_entire_file(resolv_conf_path, allocator) + if err != nil { return } + defer delete(res) + resolv_str := string(res) + + return parse_resolv_conf(resolv_str), true +} + +load_hosts :: proc(hosts_file_path: string, allocator := context.allocator) -> (hosts: []DNS_Host_Entry, ok: bool) { + handle, err := os.open(hosts_file_path) + if err != nil { return } + defer os.close(handle) + + return parse_hosts(os.to_stream(handle), allocator) +} \ No newline at end of file diff --git a/core/net/dns_others.odin b/core/net/dns_others.odin new file mode 100644 index 000000000..842e833aa --- /dev/null +++ b/core/net/dns_others.odin @@ -0,0 +1,12 @@ +#+build !windows +#+build !linux +#+build !darwin +#+build !freebsd +#+build !netbsd +#+build !openbsd +package net + +@(private) +_get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator := context.allocator) -> (records: []DNS_Record, err: DNS_Error) { + return +} diff --git a/core/net/dns_unix.odin b/core/net/dns_unix.odin index fbc1909cd..be95b8341 100644 --- a/core/net/dns_unix.odin +++ b/core/net/dns_unix.odin @@ -1,4 +1,4 @@ -#+build linux, darwin, freebsd +#+build linux, darwin, freebsd, openbsd, netbsd package net /* Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures. @@ -42,14 +42,19 @@ _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator : } hosts, hosts_ok := load_hosts(dns_configuration.hosts_file) - defer delete(hosts) if !hosts_ok { return nil, .Invalid_Hosts_Config_Error } + defer { + for h in hosts { + delete(h.name) + } + delete(hosts) + } host_overrides := make([dynamic]DNS_Record) for host in hosts { - if strings.compare(host.name, hostname) != 0 { + if host.name != hostname { continue } @@ -79,4 +84,4 @@ _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator : } return get_dns_records_from_nameservers(hostname, type, name_servers, host_overrides[:]) -} \ No newline at end of file +} diff --git a/core/net/dns_windows.odin b/core/net/dns_windows.odin index b1e7da97d..393df5fa7 100644 --- a/core/net/dns_windows.odin +++ b/core/net/dns_windows.odin @@ -20,11 +20,29 @@ package net Feoramund: FreeBSD platform code */ -import "core:strings" +import "base:runtime" + import "core:mem" +import "core:os" +import "core:strings" +import "core:sync" import win "core:sys/windows" +/* + Replaces environment placeholders in `dns_configuration`. Only necessary on Windows. + Is automatically called, once, by `get_dns_records_*`. +*/ +@(private) +_init_dns_configuration :: proc() { + sync.once_do(&dns_config_initialized, proc() { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + val := os.replace_environment_placeholders(dns_configuration.hosts_file, context.temp_allocator) + copy(dns_configuration.hosts_file_buf[:], val) + dns_configuration.hosts_file = string(dns_configuration.hosts_file_buf[:len(val)]) + }) +} + @(private) _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator := context.allocator) -> (records: []DNS_Record, err: DNS_Error) { context.allocator = allocator @@ -171,4 +189,4 @@ _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator : records = recs[:] return -} \ No newline at end of file +} diff --git a/core/net/errors.odin b/core/net/errors.odin index 4853327b0..28153375c 100644 --- a/core/net/errors.odin +++ b/core/net/errors.odin @@ -139,6 +139,11 @@ Accept_Error :: enum i32 { Unknown, } +Recv_Error :: union #shared_nil { + TCP_Recv_Error, + UDP_Recv_Error, +} + TCP_Recv_Error :: enum i32 { None, // No network connection, or the network stack is not initialized. @@ -149,7 +154,8 @@ TCP_Recv_Error :: enum i32 { Invalid_Argument, // The socket is not connected. Not_Connected, - // Connection was closed/broken/shutdown while receiving data. + // Connection was closed due to an error or shutdown. + // NOTE: a graceful close is indicated by a `0, nil` (0 bytes received and no error) return. Connection_Closed, // Timed out before being able to receive any data. Timeout, @@ -170,7 +176,8 @@ UDP_Recv_Error :: enum i32 { Insufficient_Resources, // Invalid socket or buffer given. Invalid_Argument, - // "Connection" was refused by remote, or closed/broken/shutdown while receiving data. + // "Connection" was refused, or closed due to an error. + // NOTE: a graceful close is indicated by a `0, nil` (0 bytes received and no error) return. Connection_Refused, // Timed out before being able to receive any data. Timeout, @@ -185,6 +192,11 @@ UDP_Recv_Error :: enum i32 { Unknown, } +Send_Error :: union #shared_nil { + TCP_Send_Error, + UDP_Send_Error, +} + TCP_Send_Error :: enum i32 { None, // No network connection, or the network stack is not initialized. @@ -193,7 +205,7 @@ TCP_Send_Error :: enum i32 { Insufficient_Resources, // Invalid socket or buffer given. Invalid_Argument, - // Connection was closed/broken/shutdown while receiving data. + // Connection was closed/broken/shutdown while sending data. Connection_Closed, // The socket is not connected. Not_Connected, diff --git a/core/net/errors_others.odin b/core/net/errors_others.odin index b80ead79c..3a752d58e 100644 --- a/core/net/errors_others.odin +++ b/core/net/errors_others.odin @@ -2,6 +2,8 @@ #+build !linux #+build !freebsd #+build !windows +#+build !netbsd +#+build !openbsd package net @(private="file", thread_local) @@ -18,10 +20,3 @@ _last_platform_error_string :: proc() -> string { _set_last_platform_error :: proc(err: i32) { _last_error = err } - -Parse_Endpoint_Error :: enum u32 { - None = 0, - Bad_Port = 1, - Bad_Address, - Bad_Hostname, -} \ No newline at end of file diff --git a/core/net/errors_darwin.odin b/core/net/errors_posix.odin similarity index 99% rename from core/net/errors_darwin.odin rename to core/net/errors_posix.odin index a35e96bc0..b59cbc30b 100644 --- a/core/net/errors_darwin.odin +++ b/core/net/errors_posix.odin @@ -1,4 +1,4 @@ -#+build darwin +#+build darwin, netbsd, openbsd package net /* diff --git a/core/net/errors_windows.odin b/core/net/errors_windows.odin index 83c45ee7f..6d3724c82 100644 --- a/core/net/errors_windows.odin +++ b/core/net/errors_windows.odin @@ -63,7 +63,7 @@ _dial_error :: proc() -> Dial_Error { return .Already_Connecting case .WSAEADDRNOTAVAIL, .WSAEAFNOSUPPORT, .WSAEFAULT, .WSAENOTSOCK, .WSAEINPROGRESS, .WSAEINVAL: return .Invalid_Argument - case .WSAECONNREFUSED: + case .WSAECONNREFUSED, .CONNECTION_REFUSED: return .Refused case .WSAEISCONN: return .Already_Connected @@ -122,7 +122,7 @@ _accept_error :: proc() -> Accept_Error { return .Aborted case .WSAEFAULT, .WSAEINPROGRESS, .WSAENOTSOCK: return .Invalid_Argument - case .WSAEINTR: + case .WSAEINTR, .OPERATION_ABORTED: return .Interrupted case .WSAEINVAL: return .Not_Listening diff --git a/core/net/interface_others.odin b/core/net/interface_others.odin new file mode 100644 index 000000000..9a8a141df --- /dev/null +++ b/core/net/interface_others.odin @@ -0,0 +1,11 @@ +#+build !darwin +#+build !linux +#+build !freebsd +#+build !windows +#+build !netbsd +#+build !openbsd +package net + +_enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Interfaces_Error) { + return +} diff --git a/core/net/interface_darwin.odin b/core/net/interface_posix.odin similarity index 79% rename from core/net/interface_darwin.odin rename to core/net/interface_posix.odin index f18cff995..202951b29 100644 --- a/core/net/interface_darwin.odin +++ b/core/net/interface_posix.odin @@ -1,4 +1,4 @@ -#+build darwin +#+build darwin, openbsd, netbsd package net /* @@ -117,32 +117,47 @@ IF_Flag :: enum u32 { BROADCAST, DEBUG, LOOPBACK, - POINTTOPOINT, - NOTRAILERS, - RUNNING, - NOARP, - PROMISC, - ALLMULTI, - OACTIVE, - SIMPLEX, - LINK0, - LINK1, - LINK2, - MULTICAST, + // NOTE: different order on other BSDs but we don't even need these. + // POINTTOPOINT, + // NOTRAILERS, + // RUNNING, + // NOARP, + // PROMISC, + // ALLMULTI, + // OACTIVE, + // SIMPLEX, + // LINK0, + // LINK1, + // LINK2, + // MULTICAST, } @(private) IF_Flags :: bit_set[IF_Flag; u32] -@(private) -ifaddrs :: struct { - next: ^ifaddrs, - name: cstring, - flags: IF_Flags, - addr: ^posix.sockaddr, - netmask: ^posix.sockaddr, - dstaddr: ^posix.sockaddr, - data: rawptr, +when ODIN_OS == .Darwin || ODIN_OS == .OpenBSD { + @(private) + ifaddrs :: struct { + next: ^ifaddrs, + name: cstring, + flags: IF_Flags, + addr: ^posix.sockaddr, + netmask: ^posix.sockaddr, + dstaddr: ^posix.sockaddr, + data: rawptr, + } +} else when ODIN_OS == .NetBSD { + @(private) + ifaddrs :: struct { + next: ^ifaddrs, + name: cstring, + flags: IF_Flags, + addr: ^posix.sockaddr, + netmask: ^posix.sockaddr, + dstaddr: ^posix.sockaddr, + data: rawptr, + addrflags: u32, + } } @(private) diff --git a/core/net/socket.odin b/core/net/socket.odin index 7e96ba2b2..e2f96e2f3 100644 --- a/core/net/socket.odin +++ b/core/net/socket.odin @@ -1,4 +1,3 @@ -#+build windows, linux, darwin, freebsd package net /* @@ -20,6 +19,35 @@ package net Feoramund: FreeBSD platform code */ +Socket_Option :: enum i32 { + Broadcast = i32(_SOCKET_OPTION_BROADCAST), + Reuse_Address = i32(_SOCKET_OPTION_REUSE_ADDRESS), + Keep_Alive = i32(_SOCKET_OPTION_KEEP_ALIVE), + Out_Of_Bounds_Data_Inline = i32(_SOCKET_OPTION_OUT_OF_BOUNDS_DATA_INLINE), + Linger = i32(_SOCKET_OPTION_LINGER), + Receive_Buffer_Size = i32(_SOCKET_OPTION_RECEIVE_BUFFER_SIZE), + Send_Buffer_Size = i32(_SOCKET_OPTION_SEND_BUFFER_SIZE), + Receive_Timeout = i32(_SOCKET_OPTION_RECEIVE_TIMEOUT), + Send_Timeout = i32(_SOCKET_OPTION_SEND_TIMEOUT), + + TCP_Nodelay = i32(_SOCKET_OPTION_TCP_NODELAY), + + Use_Loopback = i32(_SOCKET_OPTION_USE_LOOPBACK), + Reuse_Port = i32(_SOCKET_OPTION_REUSE_PORT), + No_SIGPIPE_From_EPIPE = i32(_SOCKET_OPTION_NO_SIGPIPE_FROM_EPIPE), + Reuse_Port_Load_Balancing = i32(_SOCKET_OPTION_REUSE_PORT_LOAD_BALANCING), + + Exclusive_Addr_Use = i32(_SOCKET_OPTION_EXCLUSIVE_ADDR_USE), + Conditional_Accept = i32(_SOCKET_OPTION_CONDITIONAL_ACCEPT), + Dont_Linger = i32(_SOCKET_OPTION_DONT_LINGER), +} + +Shutdown_Manner :: enum i32 { + Receive = i32(_SHUTDOWN_MANNER_RECEIVE), + Send = i32(_SHUTDOWN_MANNER_SEND), + Both = i32(_SHUTDOWN_MANNER_BOTH), +} + any_socket_to_socket :: proc "contextless" (socket: Any_Socket) -> Socket { switch s in socket { case TCP_Socket: return Socket(s) @@ -193,21 +221,36 @@ close :: proc(socket: Any_Socket) { _close(socket) } +/* + Receive data into a buffer from a TCP socket. + + If no error occurs, `recv_tcp` returns the number of bytes received and `buf` will contain this data received. + If the connection has been gracefully closed, the return value is `0, nil` (0 bytes read and no error). +*/ recv_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_read: int, err: TCP_Recv_Error) { return _recv_tcp(socket, buf) } +/* + Receive data into a buffer from a UDP socket. + + If no error occurs, `recv_udp` returns the number of bytes received and `buf` will contain this data received. + If the "connection" has been gracefully closed, the return value is `0, nil` (0 bytes read and no error). +*/ recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endpoint: Endpoint, err: UDP_Recv_Error) { return _recv_udp(socket, buf) } /* - Receive data from into a buffer from any socket. + Receive data into a buffer from any socket. Note: `remote_endpoint` parameter is non-nil only if the socket type is UDP. On TCP sockets it will always return `nil`. - Errors that can be returned: `TCP_Recv_Error`, or `UDP_Recv_Error` + Errors that can be returned: `TCP_Recv_Error`, or `UDP_Recv_Error`. + + If no error occurs, `recv_any` returns the number of bytes received and `buf` will contain this data received. + If the connection has been gracefully closed, the return value is `0, nil, nil` (0 bytes read and no error). */ recv_any :: proc(socket: Any_Socket, buf: []byte) -> ( bytes_read: int, diff --git a/core/net/socket_freebsd.odin b/core/net/socket_freebsd.odin index 504229e73..bd600fd99 100644 --- a/core/net/socket_freebsd.odin +++ b/core/net/socket_freebsd.odin @@ -20,45 +20,35 @@ package net Feoramund: FreeBSD platform code */ -import "core:c" import "core:sys/freebsd" import "core:time" Fd :: freebsd.Fd -Socket_Option :: enum c.int { - // TODO: Test and implement more socket options. - // DEBUG - Reuse_Address = cast(c.int)freebsd.Socket_Option.REUSEADDR, - Keep_Alive = cast(c.int)freebsd.Socket_Option.KEEPALIVE, - // DONTROUTE - Broadcast = cast(c.int)freebsd.Socket_Option.BROADCAST, - Use_Loopback = cast(c.int)freebsd.Socket_Option.USELOOPBACK, - Linger = cast(c.int)freebsd.Socket_Option.LINGER, - Out_Of_Bounds_Data_Inline = cast(c.int)freebsd.Socket_Option.OOBINLINE, - Reuse_Port = cast(c.int)freebsd.Socket_Option.REUSEPORT, - // TIMESTAMP - No_SIGPIPE_From_EPIPE = cast(c.int)freebsd.Socket_Option.NOSIGPIPE, - // ACCEPTFILTER - // BINTIME - // NO_OFFLOAD - // NO_DDP - Reuse_Port_Load_Balancing = cast(c.int)freebsd.Socket_Option.REUSEPORT_LB, - // RERROR +_SOCKET_OPTION_BROADCAST :: freebsd.Socket_Option.BROADCAST +_SOCKET_OPTION_REUSE_ADDRESS :: freebsd.Socket_Option.REUSEADDR +_SOCKET_OPTION_KEEP_ALIVE :: freebsd.Socket_Option.KEEPALIVE +_SOCKET_OPTION_OUT_OF_BOUNDS_DATA_INLINE :: freebsd.Socket_Option.OOBINLINE +_SOCKET_OPTION_LINGER :: freebsd.Socket_Option.LINGER +_SOCKET_OPTION_RECEIVE_BUFFER_SIZE :: freebsd.Socket_Option.RCVBUF +_SOCKET_OPTION_SEND_BUFFER_SIZE :: freebsd.Socket_Option.SNDBUF +_SOCKET_OPTION_RECEIVE_TIMEOUT :: freebsd.Socket_Option.RCVTIMEO +_SOCKET_OPTION_SEND_TIMEOUT :: freebsd.Socket_Option.SNDTIMEO - Send_Buffer_Size = cast(c.int)freebsd.Socket_Option.SNDBUF, - Receive_Buffer_Size = cast(c.int)freebsd.Socket_Option.RCVBUF, - // SNDLOWAT - // RCVLOWAT - Send_Timeout = cast(c.int)freebsd.Socket_Option.SNDTIMEO, - Receive_Timeout = cast(c.int)freebsd.Socket_Option.RCVTIMEO, -} +_SOCKET_OPTION_TCP_NODELAY :: -1 -Shutdown_Manner :: enum c.int { - Receive = cast(c.int)freebsd.Shutdown_Method.RD, - Send = cast(c.int)freebsd.Shutdown_Method.WR, - Both = cast(c.int)freebsd.Shutdown_Method.RDWR, -} +_SOCKET_OPTION_USE_LOOPBACK :: freebsd.Socket_Option.USELOOPBACK +_SOCKET_OPTION_REUSE_PORT :: freebsd.Socket_Option.REUSEPORT +_SOCKET_OPTION_NO_SIGPIPE_FROM_EPIPE :: freebsd.Socket_Option.NOSIGPIPE +_SOCKET_OPTION_REUSE_PORT_LOAD_BALANCING :: freebsd.Socket_Option.REUSEPORT_LB + +_SOCKET_OPTION_EXCLUSIVE_ADDR_USE :: -1 +_SOCKET_OPTION_CONDITIONAL_ACCEPT :: -1 +_SOCKET_OPTION_DONT_LINGER :: -1 + +_SHUTDOWN_MANNER_RECEIVE :: freebsd.Shutdown_Method.RD +_SHUTDOWN_MANNER_SEND :: freebsd.Shutdown_Method.WR +_SHUTDOWN_MANNER_BOTH :: freebsd.Shutdown_Method.RDWR @(private) _create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Create_Socket_Error) { @@ -272,7 +262,7 @@ _set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc : ptr: rawptr len: freebsd.socklen_t - switch option { + #partial switch option { case .Reuse_Address, .Keep_Alive, @@ -344,7 +334,7 @@ _set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc : ptr = &int_value len = size_of(int_value) case: - unimplemented("set_option() option not yet implemented", loc) + return .Invalid_Option } real_socket := any_socket_to_socket(socket) @@ -391,7 +381,7 @@ _endpoint_to_sockaddr :: proc(ep: Endpoint) -> (sockaddr: freebsd.Socket_Address } case IP6_Address: (cast(^freebsd.Socket_Address_Internet6)(&sockaddr))^ = { - len = size_of(freebsd.Socket_Address_Internet), + len = size_of(freebsd.Socket_Address_Internet6), family = .INET6, port = cast(freebsd.in_port_t)ep.port, addr = transmute(freebsd.IP6_Address)addr, diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin index 9719ff61b..8348ce114 100644 --- a/core/net/socket_linux.odin +++ b/core/net/socket_linux.odin @@ -21,28 +21,33 @@ package net Feoramund: FreeBSD platform code */ -import "core:c" import "core:time" import "core:sys/linux" -Socket_Option :: enum c.int { - Reuse_Address = c.int(linux.Socket_Option.REUSEADDR), - Keep_Alive = c.int(linux.Socket_Option.KEEPALIVE), - Out_Of_Bounds_Data_Inline = c.int(linux.Socket_Option.OOBINLINE), - TCP_Nodelay = c.int(linux.Socket_TCP_Option.NODELAY), - Linger = c.int(linux.Socket_Option.LINGER), - Receive_Buffer_Size = c.int(linux.Socket_Option.RCVBUF), - Send_Buffer_Size = c.int(linux.Socket_Option.SNDBUF), - Receive_Timeout = c.int(linux.Socket_Option.RCVTIMEO), - Send_Timeout = c.int(linux.Socket_Option.SNDTIMEO), - Broadcast = c.int(linux.Socket_Option.BROADCAST), -} +_SOCKET_OPTION_BROADCAST :: linux.Socket_Option.BROADCAST +_SOCKET_OPTION_REUSE_ADDRESS :: linux.Socket_Option.REUSEADDR +_SOCKET_OPTION_KEEP_ALIVE :: linux.Socket_Option.KEEPALIVE +_SOCKET_OPTION_OUT_OF_BOUNDS_DATA_INLINE :: linux.Socket_Option.OOBINLINE +_SOCKET_OPTION_LINGER :: linux.Socket_Option.LINGER +_SOCKET_OPTION_RECEIVE_BUFFER_SIZE :: linux.Socket_Option.RCVBUF +_SOCKET_OPTION_SEND_BUFFER_SIZE :: linux.Socket_Option.SNDBUF +_SOCKET_OPTION_RECEIVE_TIMEOUT :: linux.Socket_Option.RCVTIMEO +_SOCKET_OPTION_SEND_TIMEOUT :: linux.Socket_Option.SNDTIMEO -Shutdown_Manner :: enum c.int { - Receive = c.int(linux.Shutdown_How.RD), - Send = c.int(linux.Shutdown_How.WR), - Both = c.int(linux.Shutdown_How.RDWR), -} +_SOCKET_OPTION_TCP_NODELAY :: linux.Socket_TCP_Option.NODELAY + +_SOCKET_OPTION_USE_LOOPBACK :: -1 +_SOCKET_OPTION_REUSE_PORT :: -1 +_SOCKET_OPTION_NO_SIGPIPE_FROM_EPIPE :: -1 +_SOCKET_OPTION_REUSE_PORT_LOAD_BALANCING :: -1 + +_SOCKET_OPTION_EXCLUSIVE_ADDR_USE :: -1 +_SOCKET_OPTION_CONDITIONAL_ACCEPT :: -1 +_SOCKET_OPTION_DONT_LINGER :: -1 + +_SHUTDOWN_MANNER_RECEIVE :: linux.Shutdown_How.RD +_SHUTDOWN_MANNER_SEND :: linux.Shutdown_How.WR +_SHUTDOWN_MANNER_BOTH :: linux.Shutdown_How.RDWR // Wrappers and unwrappers for system-native types @@ -347,7 +352,7 @@ _set_option :: proc(sock: Any_Socket, option: Socket_Option, value: any, loc := int_value: i32 timeval_value: linux.Time_Val errno: linux.Errno - switch option { + #partial switch option { case .Reuse_Address, .Keep_Alive, @@ -400,10 +405,14 @@ _set_option :: proc(sock: Any_Socket, option: Socket_Option, value: any, loc := panic("set_option() value must be an integer here", loc) } errno = linux.setsockopt(os_sock, level, int(option), &int_value) + case: + return .Invalid_Socket } + if errno != .NONE { return _socket_option_error(errno) } + return nil } diff --git a/core/net/socket_others.odin b/core/net/socket_others.odin new file mode 100644 index 000000000..61cf7240e --- /dev/null +++ b/core/net/socket_others.odin @@ -0,0 +1,105 @@ +#+build !darwin +#+build !linux +#+build !freebsd +#+build !windows +#+build !netbsd +#+build !openbsd +#+private +package net + +_SOCKET_OPTION_BROADCAST :: -1 +_SOCKET_OPTION_REUSE_ADDRESS :: -1 +_SOCKET_OPTION_KEEP_ALIVE :: -1 +_SOCKET_OPTION_OUT_OF_BOUNDS_DATA_INLINE :: -1 +_SOCKET_OPTION_LINGER :: -1 +_SOCKET_OPTION_RECEIVE_BUFFER_SIZE :: -1 +_SOCKET_OPTION_SEND_BUFFER_SIZE :: -1 +_SOCKET_OPTION_RECEIVE_TIMEOUT :: -1 +_SOCKET_OPTION_SEND_TIMEOUT :: -1 + +_SOCKET_OPTION_TCP_NODELAY :: -1 + +_SOCKET_OPTION_USE_LOOPBACK :: -1 +_SOCKET_OPTION_REUSE_PORT :: -1 +_SOCKET_OPTION_NO_SIGPIPE_FROM_EPIPE :: -1 +_SOCKET_OPTION_REUSE_PORT_LOAD_BALANCING :: -1 + +_SOCKET_OPTION_EXCLUSIVE_ADDR_USE :: -1 +_SOCKET_OPTION_CONDITIONAL_ACCEPT :: -1 +_SOCKET_OPTION_DONT_LINGER :: -1 + +_SHUTDOWN_MANNER_RECEIVE :: -1 +_SHUTDOWN_MANNER_SEND :: -1 +_SHUTDOWN_MANNER_BOTH :: -1 + +_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := DEFAULT_TCP_OPTIONS) -> (sock: TCP_Socket, err: Network_Error) { + err = Create_Socket_Error.Network_Unreachable + return +} + +_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (sock: Any_Socket, err: Create_Socket_Error) { + err = .Network_Unreachable + return +} + +_bind :: proc(skt: Any_Socket, ep: Endpoint) -> (err: Bind_Error) { + err = .Network_Unreachable + return +} + +_listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (skt: TCP_Socket, err: Network_Error) { + err = Create_Socket_Error.Network_Unreachable + return +} + +_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) { + err = .Network_Unreachable + return +} + +_peer_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) { + err = .Network_Unreachable + return +} + +_accept_tcp :: proc(sock: TCP_Socket, options := DEFAULT_TCP_OPTIONS) -> (client: TCP_Socket, source: Endpoint, err: Accept_Error) { + err = .Network_Unreachable + return +} + +_close :: proc(skt: Any_Socket) { +} + +_recv_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_read: int, err: TCP_Recv_Error) { + err = .Network_Unreachable + return +} + +_recv_udp :: proc(skt: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endpoint: Endpoint, err: UDP_Recv_Error) { + err = .Network_Unreachable + return +} + +_send_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_written: int, err: TCP_Send_Error) { + err = .Network_Unreachable + return +} + +_send_udp :: proc(skt: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: int, err: UDP_Send_Error) { + err = .Network_Unreachable + return +} + +_shutdown :: proc(skt: Any_Socket, manner: Shutdown_Manner) -> (err: Shutdown_Error) { + err = .Network_Unreachable + return +} + +_set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Socket_Option_Error { + return .Network_Unreachable +} + +_set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Set_Blocking_Error) { + err = .Network_Unreachable + return +} diff --git a/core/net/socket_darwin.odin b/core/net/socket_posix.odin similarity index 90% rename from core/net/socket_darwin.odin rename to core/net/socket_posix.odin index 8e01eb4a8..243b2e06f 100644 --- a/core/net/socket_darwin.odin +++ b/core/net/socket_posix.odin @@ -1,4 +1,4 @@ -#+build darwin +#+build darwin, netbsd, openbsd package net /* @@ -20,28 +20,33 @@ package net Feoramund: FreeBSD platform code */ -import "core:c" import "core:sys/posix" import "core:time" -Socket_Option :: enum c.int { - Broadcast = c.int(posix.Sock_Option.BROADCAST), - Reuse_Address = c.int(posix.Sock_Option.REUSEADDR), - Keep_Alive = c.int(posix.Sock_Option.KEEPALIVE), - Out_Of_Bounds_Data_Inline = c.int(posix.Sock_Option.OOBINLINE), - TCP_Nodelay = c.int(posix.TCP_NODELAY), - Linger = c.int(posix.Sock_Option.LINGER), - Receive_Buffer_Size = c.int(posix.Sock_Option.RCVBUF), - Send_Buffer_Size = c.int(posix.Sock_Option.SNDBUF), - Receive_Timeout = c.int(posix.Sock_Option.RCVTIMEO), - Send_Timeout = c.int(posix.Sock_Option.SNDTIMEO), -} +_SOCKET_OPTION_BROADCAST :: posix.Sock_Option.BROADCAST +_SOCKET_OPTION_REUSE_ADDRESS :: posix.Sock_Option.REUSEADDR +_SOCKET_OPTION_KEEP_ALIVE :: posix.Sock_Option.KEEPALIVE +_SOCKET_OPTION_OUT_OF_BOUNDS_DATA_INLINE :: posix.Sock_Option.OOBINLINE +_SOCKET_OPTION_LINGER :: posix.Sock_Option.LINGER +_SOCKET_OPTION_RECEIVE_BUFFER_SIZE :: posix.Sock_Option.RCVBUF +_SOCKET_OPTION_SEND_BUFFER_SIZE :: posix.Sock_Option.SNDBUF +_SOCKET_OPTION_RECEIVE_TIMEOUT :: posix.Sock_Option.RCVTIMEO +_SOCKET_OPTION_SEND_TIMEOUT :: posix.Sock_Option.SNDTIMEO -Shutdown_Manner :: enum c.int { - Receive = c.int(posix.SHUT_RD), - Send = c.int(posix.SHUT_WR), - Both = c.int(posix.SHUT_RDWR), -} +_SOCKET_OPTION_TCP_NODELAY :: posix.TCP_NODELAY + +_SOCKET_OPTION_USE_LOOPBACK :: -1 +_SOCKET_OPTION_REUSE_PORT :: -1 +_SOCKET_OPTION_NO_SIGPIPE_FROM_EPIPE :: -1 +_SOCKET_OPTION_REUSE_PORT_LOAD_BALANCING :: -1 + +_SOCKET_OPTION_EXCLUSIVE_ADDR_USE :: -1 +_SOCKET_OPTION_CONDITIONAL_ACCEPT :: -1 +_SOCKET_OPTION_DONT_LINGER :: -1 + +_SHUTDOWN_MANNER_RECEIVE :: posix.SHUT_RD +_SHUTDOWN_MANNER_SEND :: posix.SHUT_WR +_SHUTDOWN_MANNER_BOTH :: posix.SHUT_RDWR @(private) _create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Create_Socket_Error) { @@ -273,7 +278,7 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca ptr: rawptr len: posix.socklen_t - switch option { + #partial switch option { case .Broadcast, .Reuse_Address, @@ -327,6 +332,8 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca } ptr = &int_value len = size_of(int_value) + case: + return .Invalid_Option } skt := any_socket_to_socket(s) diff --git a/core/net/socket_windows.odin b/core/net/socket_windows.odin index 6dd2f0458..4eea0ea65 100644 --- a/core/net/socket_windows.odin +++ b/core/net/socket_windows.odin @@ -24,59 +24,30 @@ import "core:c" import win "core:sys/windows" import "core:time" -Socket_Option :: enum c.int { - // bool: Whether the address that this socket is bound to can be reused by other sockets. - // This allows you to bypass the cooldown period if a program dies while the socket is bound. - Reuse_Address = win.SO_REUSEADDR, +_SOCKET_OPTION_BROADCAST :: win.SO_BROADCAST +_SOCKET_OPTION_REUSE_ADDRESS :: win.SO_REUSEADDR +_SOCKET_OPTION_KEEP_ALIVE :: win.SO_KEEPALIVE +_SOCKET_OPTION_OUT_OF_BOUNDS_DATA_INLINE :: win.SO_OOBINLINE +_SOCKET_OPTION_LINGER :: win.SO_LINGER +_SOCKET_OPTION_RECEIVE_BUFFER_SIZE :: win.SO_RCVBUF +_SOCKET_OPTION_SEND_BUFFER_SIZE :: win.SO_SNDBUF +_SOCKET_OPTION_RECEIVE_TIMEOUT :: win.SO_RCVTIMEO +_SOCKET_OPTION_SEND_TIMEOUT :: win.SO_SNDTIMEO - // bool: Whether other programs will be inhibited from binding the same endpoint as this socket. - Exclusive_Addr_Use = win.SO_EXCLUSIVEADDRUSE, +_SOCKET_OPTION_TCP_NODELAY :: win.TCP_NODELAY - // bool: When true, keepalive packets will be automatically be sent for this connection. TODO: verify this understanding - Keep_Alive = win.SO_KEEPALIVE, +_SOCKET_OPTION_USE_LOOPBACK :: -1 +_SOCKET_OPTION_REUSE_PORT :: -1 +_SOCKET_OPTION_NO_SIGPIPE_FROM_EPIPE :: -1 +_SOCKET_OPTION_REUSE_PORT_LOAD_BALANCING :: -1 - // bool: When true, client connections will immediately be sent a TCP/IP RST response, rather than being accepted. - Conditional_Accept = win.SO_CONDITIONAL_ACCEPT, +_SOCKET_OPTION_EXCLUSIVE_ADDR_USE :: win.SO_EXCLUSIVEADDRUSE +_SOCKET_OPTION_CONDITIONAL_ACCEPT :: win.SO_CONDITIONAL_ACCEPT +_SOCKET_OPTION_DONT_LINGER :: win.SO_DONTLINGER - // bool: If true, when the socket is closed, but data is still waiting to be sent, discard that data. - Dont_Linger = win.SO_DONTLINGER, - - // bool: When true, 'out-of-band' data sent over the socket will be read by a normal net.recv() call, the same as normal 'in-band' data. - Out_Of_Bounds_Data_Inline = win.SO_OOBINLINE, - - // bool: When true, disables send-coalescing, therefore reducing latency. - TCP_Nodelay = win.TCP_NODELAY, - - // win.LINGER: Customizes how long (if at all) the socket will remain open when there - // is some remaining data waiting to be sent, and net.close() is called. - Linger = win.SO_LINGER, - - // win.DWORD: The size, in bytes, of the OS-managed receive-buffer for this socket. - Receive_Buffer_Size = win.SO_RCVBUF, - - // win.DWORD: The size, in bytes, of the OS-managed send-buffer for this socket. - Send_Buffer_Size = win.SO_SNDBUF, - - // win.DWORD: For blocking sockets, the time in milliseconds to wait for incoming data to be received, before giving up and returning .Timeout. - // For non-blocking sockets, ignored. - // Use a value of zero to potentially wait forever. - Receive_Timeout = win.SO_RCVTIMEO, - - // win.DWORD: For blocking sockets, the time in milliseconds to wait for outgoing data to be sent, before giving up and returning .Timeout. - // For non-blocking sockets, ignored. - // Use a value of zero to potentially wait forever. - Send_Timeout = win.SO_SNDTIMEO, - - // bool: Allow sending to, receiving from, and binding to, a broadcast address. - Broadcast = win.SO_BROADCAST, -} - - -Shutdown_Manner :: enum c.int { - Receive = win.SD_RECEIVE, - Send = win.SD_SEND, - Both = win.SD_BOTH, -} +_SHUTDOWN_MANNER_RECEIVE :: win.SD_RECEIVE +_SHUTDOWN_MANNER_SEND :: win.SD_SEND +_SHUTDOWN_MANNER_BOTH :: win.SD_BOTH @(init, private) ensure_winsock_initialized :: proc "contextless" () { @@ -322,7 +293,7 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca ptr: rawptr len: c.int - switch option { + #partial switch option { case .Reuse_Address, .Exclusive_Addr_Use, @@ -383,6 +354,8 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca } ptr = &int_value len = size_of(int_value) + case: + return .Invalid_Option } socket := any_socket_to_socket(s) diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index a8c198476..22139d7f9 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -17,6 +17,11 @@ Proc_Inlining :: enum u32 { No_Inline = 2, } +Proc_Tailing :: enum u32 { + None = 0, + Must_Tail = 1, +} + Proc_Calling_Convention_Extra :: enum i32 { Foreign_Block_Default, } @@ -147,6 +152,7 @@ Proc_Lit :: struct { body: ^Stmt, // nil when it represents a foreign procedure tags: Proc_Tags, inlining: Proc_Inlining, + tailing: Proc_Tailing, where_token: tokenizer.Token, where_clauses: []^Expr, } @@ -243,6 +249,7 @@ Matrix_Index_Expr :: struct { Call_Expr :: struct { using node: Expr, inlining: Proc_Inlining, + tailing: Proc_Tailing, expr: ^Expr, open: tokenizer.Pos, args: []^Expr, @@ -425,6 +432,7 @@ For_Stmt :: struct { Range_Stmt :: struct { using node: Stmt, label: ^Expr, // possibly nil + init: ^Stmt, for_pos: tokenizer.Pos, vals: []^Expr, in_pos: tokenizer.Pos, @@ -778,6 +786,16 @@ Dynamic_Array_Type :: struct { elem: ^Expr, } +Fixed_Capacity_Dynamic_Array_Type :: struct { + using node: Expr, + tag: ^Expr, // possibly nil + open: tokenizer.Pos, + dynamic_pos: tokenizer.Pos, + capacity: ^Expr, + close: tokenizer.Pos, + elem: ^Expr, +} + Struct_Type :: struct { using node: Expr, tok_pos: tokenizer.Pos, @@ -791,6 +809,7 @@ Struct_Type :: struct { is_raw_union: bool, is_no_copy: bool, is_all_or_none: bool, + is_simple: bool, fields: ^Field_List, name_count: int, } @@ -922,6 +941,7 @@ Any_Node :: union { ^Multi_Pointer_Type, ^Array_Type, ^Dynamic_Array_Type, + ^Fixed_Capacity_Dynamic_Array_Type, ^Struct_Type, ^Union_Type, ^Enum_Type, @@ -1008,6 +1028,7 @@ Any_Expr :: union { ^Multi_Pointer_Type, ^Array_Type, ^Dynamic_Array_Type, + ^Fixed_Capacity_Dynamic_Array_Type, ^Struct_Type, ^Union_Type, ^Enum_Type, diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index b7501e6ca..163485840 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -239,6 +239,7 @@ clone_node :: proc(node: ^Node) -> ^Node { r.body = clone(r.body) case ^Range_Stmt: r.label = clone(r.label) + r.init = clone(r.init) r.vals = clone(r.vals) r.expr = clone(r.expr) r.body = clone(r.body) @@ -310,10 +311,16 @@ clone_node :: proc(node: ^Node) -> ^Node { case ^Multi_Pointer_Type: r.elem = clone(r.elem) case ^Array_Type: + r.tag = clone(r.tag) r.len = clone(r.len) r.elem = clone(r.elem) case ^Dynamic_Array_Type: + r.tag = clone(r.tag) r.elem = clone(r.elem) + case ^Fixed_Capacity_Dynamic_Array_Type: + r.tag = clone(r.tag) + r.capacity = clone(r.capacity) + r.elem = clone(r.elem) case ^Struct_Type: r.poly_params = auto_cast clone(r.poly_params) r.align = clone(r.align) diff --git a/core/odin/ast/walk.odin b/core/odin/ast/walk.odin index cba040875..d3824c213 100644 --- a/core/odin/ast/walk.odin +++ b/core/odin/ast/walk.odin @@ -222,6 +222,9 @@ walk :: proc(v: ^Visitor, node: ^Node) { if n.label != nil { walk(v, n.label) } + if n.init != nil { + walk(v, n.init) + } for val in n.vals { if val != nil { walk(v, val) @@ -377,6 +380,12 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk(v, n.tag) } walk(v, n.elem) + case ^Fixed_Capacity_Dynamic_Array_Type: + if n.tag != nil { + walk(v, n.tag) + } + walk(v, n.capacity) + walk(v, n.elem) case ^Struct_Type: if n.poly_params != nil { walk(v, n.poly_params) @@ -402,9 +411,7 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk_expr_list(v, n.fields) case ^Bit_Set_Type: walk(v, n.elem) - if n.underlying != nil { - walk(v, n.underlying) - } + walk(v, n.underlying) case ^Map_Type: walk(v, n.key) walk(v, n.value) diff --git a/core/odin/doc-format/doc_format.odin b/core/odin/doc-format/doc_format.odin index df36c1b55..28552b346 100644 --- a/core/odin/doc-format/doc_format.odin +++ b/core/odin/doc-format/doc_format.odin @@ -12,7 +12,7 @@ String :: distinct Array(byte) Version_Type_Major :: 0 Version_Type_Minor :: 3 -Version_Type_Patch :: 1 +Version_Type_Patch :: 2 Version_Type :: struct { major, minor, patch: u8, @@ -168,32 +168,33 @@ Attribute :: struct { } Type_Kind :: enum u32le { - Invalid = 0, - Basic = 1, - Named = 2, - Generic = 3, - Pointer = 4, - Array = 5, - Enumerated_Array = 6, - Slice = 7, - Dynamic_Array = 8, - Map = 9, - Struct = 10, - Union = 11, - Enum = 12, - Parameters = 13, - Proc = 14, - Bit_Set = 15, - Simd_Vector = 16, - SOA_Struct_Fixed = 17, - SOA_Struct_Slice = 18, - SOA_Struct_Dynamic = 19, - Relative_Pointer = 20, - Relative_Multi_Pointer = 21, - Multi_Pointer = 22, - Matrix = 23, - Soa_Pointer = 24, - Bit_Field = 25, + Invalid = 0, + Basic = 1, + Named = 2, + Generic = 3, + Pointer = 4, + Array = 5, + Enumerated_Array = 6, + Slice = 7, + Dynamic_Array = 8, + Map = 9, + Struct = 10, + Union = 11, + Enum = 12, + Parameters = 13, + Proc = 14, + Bit_Set = 15, + Simd_Vector = 16, + SOA_Struct_Fixed = 17, + SOA_Struct_Slice = 18, + SOA_Struct_Dynamic = 19, + Relative_Pointer = 20, + Relative_Multi_Pointer = 21, + Multi_Pointer = 22, + Matrix = 23, + Soa_Pointer = 24, + Bit_Field = 25, + Fixed_Capacity_Dynamic_Array = 26, } Type_Elems_Cap :: 4 @@ -219,13 +220,14 @@ Type :: struct { custom_align: String, // Used by: - // .Array - 1 count: 0=len - // .Enumerated_Array - 1 count: 0=len - // .SOA_Struct_Fixed - 1 count: 0=len - // .Bit_Set - 2 count: 0=lower, 1=upper - // .Simd_Vector - 1 count: 0=len - // .Matrix - 2 count: 0=row_count, 1=column_count - // .Struct - <=2 count: 0=min_field_align, 1=max_field_align + // .Array - 1 count: 0=len + // .Enumerated_Array - 1 count: 0=len + // .SOA_Struct_Fixed - 1 count: 0=len + // .Bit_Set - 2 count: 0=lower, 1=upper + // .Simd_Vector - 1 count: 0=len + // .Matrix - 2 count: 0=row_count, 1=column_count + // .Struct - <=2 count: 0=min_field_align, 1=max_field_align + // .Fixed_Capacity_Dynamic_Array - 1 count: 0=cap elem_count_len: u32le, elem_counts: [Type_Elems_Cap]i64le, @@ -234,27 +236,28 @@ Type :: struct { calling_convention: String, // Used by: - // .Named - 1 type: 0=base type - // .Generic - <1 type: 0=specialization - // .Pointer - 1 type: 0=element - // .Array - 1 type: 0=element - // .Enumerated_Array - 2 types: 0=index and 1=element - // .Slice - 1 type: 0=element - // .Dynamic_Array - 1 type: 0=element - // .Map - 2 types: 0=key, 1=value - // .SOA_Struct_Fixed - 1 type: underlying SOA struct element - // .SOA_Struct_Slice - 1 type: underlying SOA struct element - // .SOA_Struct_Dynamic - 1 type: underlying SOA struct element - // .Union - 0+ types: variants - // .Enum - <1 type: 0=base type - // .Proc - 2 types: 0=parameters, 1=results - // .Bit_Set - <=2 types: 0=element type, 1=underlying type (Underlying_Type flag will be set) - // .Simd_Vector - 1 type: 0=element - // .Relative_Pointer - 2 types: 0=pointer type, 1=base integer - // .Multi_Pointer - 1 type: 0=element - // .Matrix - 1 type: 0=element - // .Soa_Pointer - 1 type: 0=element - // .Bit_Field - 1 type: 0=backing type + // .Named - 1 type: 0=base type + // .Generic - <1 type: 0=specialization + // .Pointer - 1 type: 0=element + // .Array - 1 type: 0=element (and 1=generic index (if exists)) + // .Enumerated_Array - 2 types: 0=index and 1=element + // .Slice - 1 type: 0=element + // .Dynamic_Array - 1 type: 0=element + // .Map - 2 types: 0=key, 1=value + // .SOA_Struct_Fixed - 1 type: underlying SOA struct element + // .SOA_Struct_Slice - 1 type: underlying SOA struct element + // .SOA_Struct_Dynamic - 1 type: underlying SOA struct element + // .Union - 0+ types: variants + // .Enum - <1 type: 0=base type + // .Proc - 2 types: 0=parameters, 1=results + // .Bit_Set - <=2 types: 0=element type, 1=underlying type (Underlying_Type flag will be set) + // .Simd_Vector - 1 type: 0=element + // .Relative_Pointer - 2 types: 0=pointer type, 1=base integer + // .Multi_Pointer - 1 type: 0=element + // .Matrix - 1 type: 0=element + // .Soa_Pointer - 1 type: 0=element + // .Bit_Field - 1 type: 0=backing type + // .Fixed_Capacity_Dynamic_Array - 1 type: 0=element (and 1=generic index (if exists)) types: Array(Type_Index), // Used by: diff --git a/core/odin/parser/file_tags.odin b/core/odin/parser/file_tags.odin index 24aea3b9e..669fa5263 100644 --- a/core/odin/parser/file_tags.odin +++ b/core/odin/parser/file_tags.odin @@ -65,12 +65,6 @@ get_build_arch_from_string :: proc(str: string) -> runtime.Odin_Arch_Type { @require_results parse_file_tags :: proc(file: ast.File, allocator := context.allocator) -> (tags: File_Tags) { - context.allocator = allocator - - if file.docs == nil && file.tags == nil { - return - } - next_char :: proc(src: string, i: ^int) -> (ch: u8) { if i^ < len(src) { ch = src[i^] @@ -102,15 +96,6 @@ parse_file_tags :: proc(file: ast.File, allocator := context.allocator) -> (tags } } - build_kinds: [dynamic]Build_Kind - defer shrink(&build_kinds) - - build_project_name_strings: [dynamic]string - defer shrink(&build_project_name_strings) - - build_project_names: [dynamic][]string - defer shrink(&build_project_names) - parse_tag :: proc(text: string, tags: ^File_Tags, build_kinds: ^[dynamic]Build_Kind, build_project_name_strings: ^[dynamic]string, build_project_names: ^[dynamic][]string) { @@ -143,7 +128,7 @@ parse_file_tags :: proc(file: ast.File, allocator := context.allocator) -> (tags for { skip_whitespace(text, &i) name_start := i - + switch next_char(text, &i) { case 0, '\r', '\n': i -= 1 @@ -155,7 +140,7 @@ parse_file_tags :: proc(file: ast.File, allocator := context.allocator) -> (tags case: i -= 1 } - + scan_value(text, &i) append(build_project_name_strings, text[name_start:i]) } @@ -220,6 +205,18 @@ parse_file_tags :: proc(file: ast.File, allocator := context.allocator) -> (tags } } + context.allocator = allocator + + if file.docs == nil && file.tags == nil { + return + } + + build_kinds: [dynamic]Build_Kind + build_project_names: [dynamic][]string + + build_project_name_strings: [dynamic]string + + if file.docs != nil { for comment in file.docs.list { if len(comment.text) < 3 || comment.text[:2] != "//" { @@ -241,6 +238,10 @@ parse_file_tags :: proc(file: ast.File, allocator := context.allocator) -> (tags parse_tag(text, &tags, &build_kinds, &build_project_name_strings, &build_project_names) } + shrink(&build_kinds) + shrink(&build_project_names) + delete(build_project_name_strings) + tags.build = build_kinds[:] tags.build_project_name = build_project_names[:] diff --git a/core/odin/parser/parse_files.odin b/core/odin/parser/parse_files.odin index d4e532ec7..2ea47ca89 100644 --- a/core/odin/parser/parse_files.odin +++ b/core/odin/parser/parse_files.odin @@ -11,8 +11,8 @@ import "core:strings" collect_package :: proc(path: string) -> (pkg: ^ast.Package, success: bool) { NO_POS :: tokenizer.Pos{} - pkg_path, pkg_path_ok := filepath.abs(path) - if !pkg_path_ok { + pkg_path, pkg_path_err := os.get_absolute_path(path, context.allocator) + if pkg_path_err != nil { return } @@ -28,14 +28,13 @@ collect_package :: proc(path: string) -> (pkg: ^ast.Package, success: bool) { pkg.fullpath = pkg_path for match in matches { - src: []byte - fullpath, ok := filepath.abs(match) - if !ok { + fullpath, fullpath_err := os.get_absolute_path(match, context.allocator) + if fullpath_err != nil { return } - src, ok = os.read_entire_file(fullpath) - if !ok { + src, src_err := os.read_entire_file(fullpath, context.allocator) + if src_err != nil { delete(fullpath) return } diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index f4beddcbb..0f3ac78b2 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -881,7 +881,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt { body: ^ast.Stmt is_range := false - if p.curr_tok.kind != .Open_Brace && p.curr_tok.kind != .Do { + general_conds: if p.curr_tok.kind != .Open_Brace && p.curr_tok.kind != .Do { prev_level := p.expr_level defer p.expr_level = prev_level p.expr_level = -1 @@ -929,6 +929,17 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt { error(p, p.curr_tok.pos, "Expected ';', followed by a condition expression and post statement, got %s", tokenizer.tokens[p.curr_tok.kind]) } else { if p.curr_tok.kind != .Semicolon { + if p.curr_tok.kind == .Ident { + next_token := peek_token(p) + if next_token.kind == .In || next_token.kind == .Comma { + cond = parse_simple_stmt(p, {.In}) + as := cond.derived_stmt.(^ast.Assign_Stmt) + assert(as.op.kind == .In) + is_range = true + break general_conds + } + } + cond = parse_simple_stmt(p, nil) } @@ -967,6 +978,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt { range_stmt := ast.new(ast.Range_Stmt, tok.pos, body) range_stmt.for_pos = tok.pos + range_stmt.init = init range_stmt.vals = vals range_stmt.in_pos = assign_stmt.op.pos range_stmt.expr = rhs @@ -1528,8 +1540,8 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { es.expr = ce return es - case "force_inline", "force_no_inline": - expr := parse_inlining_operand(p, true, tag) + case "force_inline", "force_no_inline", "must_tail": + expr := parse_inlining_or_tailing_operand(p, true, tag) es := ast.new(ast.Expr_Stmt, expr.pos, expr) es.expr = expr return es @@ -2235,10 +2247,11 @@ parse_proc_type :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Proc_Type { return pt } -parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^ast.Expr { +parse_inlining_or_tailing_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^ast.Expr { expr := parse_unary_expr(p, lhs) pi := ast.Proc_Inlining.None + pt := ast.Proc_Tailing.None #partial switch tok.kind { case .Inline: pi = .Inline @@ -2250,6 +2263,8 @@ parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^ pi = .Inline case "force_no_inline": pi = .No_Inline + case "must_tail": + pt = .Must_Tail } } @@ -2259,13 +2274,19 @@ parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^ if e.inlining != .None && e.inlining != pi { error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure literal") } + if pt != .None { + error(p, expr.pos, "'#must_tail' can only be applied to a procedure call, not the procedure literal") + } + e.inlining = pi + e.tailing = pt return expr case ^ast.Call_Expr: if e.inlining != .None && e.inlining != pi { error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure call") } e.inlining = pi + e.tailing = pt return expr } } @@ -2368,6 +2389,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { case ^ast.Array_Type: t.tag = bd case ^ast.Dynamic_Array_Type: t.tag = bd case ^ast.Pointer_Type: t.tag = bd + case ^ast.Fixed_Capacity_Dynamic_Array_Type: t.tag = bd case: error(p, original_type.pos, "expected an array or pointer type after #%s", name.text) } @@ -2451,7 +2473,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { return rt case "force_inline", "force_no_inline": - return parse_inlining_operand(p, lhs, name) + return parse_inlining_or_tailing_operand(p, lhs, name) case: expr := parse_expr(p, lhs) end := expr.pos if expr != nil else end_pos(tok) @@ -2464,7 +2486,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { case .Inline, .No_Inline: tok := advance_token(p) - return parse_inlining_operand(p, lhs, tok) + return parse_inlining_or_tailing_operand(p, lhs, tok) case .Proc: tok := expect_token(p, .Proc) @@ -2605,6 +2627,20 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { return t case .Dynamic: tok := expect_token(p, .Dynamic) + if allow_token(p, .Semicolon) { + capacity := parse_expr(p, false) + close := expect_token(p, .Close_Bracket) + elem := parse_type(p) + + da := ast.new(ast.Fixed_Capacity_Dynamic_Array_Type, open.pos, elem) + da.open = open.pos + da.dynamic_pos = tok.pos + da.capacity = capacity + da.close = close.pos + da.elem = elem + return da + } + close := expect_token(p, .Close_Bracket) elem := parse_type(p) da := ast.new(ast.Dynamic_Array_Type, open.pos, elem) @@ -2658,6 +2694,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { is_raw_union: bool is_no_copy: bool is_all_or_none: bool + is_simple: bool fields: ^ast.Field_List name_count: int @@ -2686,6 +2723,11 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { error(p, tag.pos, "duplicate struct tag '#%s'", tag.text) } is_all_or_none = true + case "simple": + if is_simple { + error(p, tag.pos, "duplicate struct tag '#%s'", tag.text) + } + is_simple = true case "align": if align != nil { error(p, tag.pos, "duplicate struct tag '#%s'", tag.text) @@ -2760,6 +2802,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { st.is_raw_union = is_raw_union st.is_no_copy = is_no_copy st.is_all_or_none = is_all_or_none + st.is_simple = is_simple st.fields = fields st.name_count = name_count st.where_token = where_token @@ -3079,6 +3122,7 @@ is_literal_type :: proc(expr: ^ast.Expr) -> bool { ^ast.Union_Type, ^ast.Enum_Type, ^ast.Dynamic_Array_Type, + ^ast.Fixed_Capacity_Dynamic_Array_Type, ^ast.Map_Type, ^ast.Bit_Set_Type, ^ast.Matrix_Type, diff --git a/core/odin/tokenizer/tokenizer.odin b/core/odin/tokenizer/tokenizer.odin index 9f46f2ed6..f4d50b36c 100644 --- a/core/odin/tokenizer/tokenizer.odin +++ b/core/odin/tokenizer/tokenizer.odin @@ -1,6 +1,7 @@ // The tokenizer (lexer) for `Odin` files, used to create tooling. package odin_tokenizer +import "base:intrinsics" import "core:fmt" import "core:unicode" import "core:unicode/utf8" @@ -32,6 +33,68 @@ Tokenizer :: struct { error_count: int, } + +Keyword_Hash_Entry :: struct { + hash: u32, + kind: Token_Kind, + name: string, +} + +KEYWORD_LUT_LEN :: 1<<9 +KEYWORD_LUT_MASK :: KEYWORD_LUT_LEN-1 +Keyword_LUT :: [KEYWORD_LUT_LEN]Keyword_Hash_Entry + +global_keyword_lut: Keyword_LUT // protected by `_global_keyword_lut_spinlock` +_global_keyword_lut_initialized: bool // atomic +_global_keyword_lut_spinlock: bool // atomic + +_global_keyword_spin_lock :: proc() { + for intrinsics.atomic_exchange_explicit(&_global_keyword_lut_spinlock, true, .Acquire) { + intrinsics.cpu_relax() + } +} + +_global_keyword_spin_unlock :: proc() { + intrinsics.atomic_store_explicit(&_global_keyword_lut_spinlock, false, .Release) +} + +@(require_results) +keyword_hash :: proc(text: string) -> u32 #no_bounds_check { + h := u32(0x811c9dc5) + for i in 0.. bool { + if lut == nil { + return false + } + + max_keyword_size := 0 + + for kind in (Token_Kind.B_Keyword_Begin+Token_Kind(1)).. 1) + assert(max_keyword_size < 16) + + return true +} + + init :: proc(t: ^Tokenizer, src: string, path: string, err: Error_Handler = default_error_handler) { t.src = src t.err = err @@ -44,6 +107,13 @@ init :: proc(t: ^Tokenizer, src: string, path: string, err: Error_Handler = defa t.error_count = 0 t.path = path + if !intrinsics.atomic_load(&_global_keyword_lut_initialized) { + _global_keyword_spin_lock() + ok := keyword_lut_init(&global_keyword_lut) + intrinsics.atomic_store(&_global_keyword_lut_initialized, ok) + _global_keyword_spin_unlock() + } + advance_rune(t) if t.ch == utf8.RUNE_BOM { advance_rune(t) @@ -502,13 +572,20 @@ scan :: proc(t: ^Tokenizer) -> Token { case is_letter(ch): lit = scan_identifier(t) kind = .Ident - check_keyword: if len(lit) > 1 { - // TODO(bill): Maybe have a hash table lookup rather than this linear search - for i in Token_Kind.B_Keyword_Begin ..= Token_Kind.B_Keyword_End { - if lit == tokens[i] { - kind = Token_Kind(i) + check_keyword: if 1 < len(lit) && len(lit) < 16 { + if intrinsics.atomic_load(&_global_keyword_lut_initialized) { + entry := &global_keyword_lut[keyword_hash(lit) & KEYWORD_LUT_MASK] + if entry.kind != .Invalid && entry.name == lit { + kind = entry.kind break check_keyword } + } else { + for i in Token_Kind.B_Keyword_Begin ..= Token_Kind.B_Keyword_End { + if lit == tokens[i] { + kind = Token_Kind(i) + break check_keyword + } + } } for keyword, i in custom_keyword_tokens { if lit == keyword { @@ -516,7 +593,6 @@ scan :: proc(t: ^Tokenizer) -> Token { break check_keyword } } - break check_keyword } case '0' <= ch && ch <= '9': kind, lit = scan_number(t, false) diff --git a/core/os/os2/allocators.odin b/core/os/allocators.odin similarity index 99% rename from core/os/os2/allocators.odin rename to core/os/allocators.odin index 36a7d72be..e49d416e1 100644 --- a/core/os/os2/allocators.odin +++ b/core/os/allocators.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" diff --git a/core/os/os2/dir.odin b/core/os/dir.odin similarity index 96% rename from core/os/os2/dir.odin rename to core/os/dir.odin index f63754273..02dcb87af 100644 --- a/core/os/os2/dir.odin +++ b/core/os/dir.odin @@ -1,4 +1,4 @@ -package os2 +package os import "base:runtime" import "core:slice" @@ -160,8 +160,8 @@ extend its lifetime. Example: package main - import "core:fmt" - import os "core:os/os2" + import "core:fmt" + import "core:os" main :: proc() { f, oerr := os.open("core") @@ -195,7 +195,6 @@ Example: } } */ -@(require_results) read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info, index: int, ok: bool) { if it.f == nil { return @@ -209,7 +208,7 @@ read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info, } // Recursively copies a directory to `dst` from `src` -copy_directory_all :: proc(dst, src: string, dst_perm := 0o755) -> Error { +copy_directory_all :: proc(dst, src: string, dst_perm := Permissions_Default) -> Error { when #defined(_copy_directory_all_native) { return _copy_directory_all_native(dst, src, dst_perm) } else { @@ -218,7 +217,7 @@ copy_directory_all :: proc(dst, src: string, dst_perm := 0o755) -> Error { } @(private) -_copy_directory_all :: proc(dst, src: string, dst_perm := 0o755) -> Error { +_copy_directory_all :: proc(dst, src: string, dst_perm := Permissions_Default) -> Error { err := make_directory(dst, dst_perm) if err != nil && err != .Exist { return err diff --git a/core/os/dir_js.odin b/core/os/dir_js.odin new file mode 100644 index 000000000..cd6227507 --- /dev/null +++ b/core/os/dir_js.odin @@ -0,0 +1,28 @@ +#+build js wasm32, js wasm64p32 +#+private +package os + +// None of this does anything on js/wasm. +// It's only here so importing `core:os` on wasm panics cleanly, +// without spamming about all sorts of missing procs and types. + +import "base:intrinsics" + +Read_Directory_Iterator_Impl :: struct { + fullpath: [dynamic]byte, + buf: []byte, + off: int, +} + +@(require_results) +_read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info, index: int, ok: bool) { + return {}, -1, false +} + +_read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) { + +} + +_read_directory_iterator_destroy :: proc(it: ^Read_Directory_Iterator) { + +} \ No newline at end of file diff --git a/core/os/os2/dir_linux.odin b/core/os/dir_linux.odin similarity index 99% rename from core/os/os2/dir_linux.odin rename to core/os/dir_linux.odin index 34346c02f..1ca2ef9b4 100644 --- a/core/os/os2/dir_linux.odin +++ b/core/os/dir_linux.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "core:sys/linux" diff --git a/core/os/os2/dir_posix.odin b/core/os/dir_posix.odin similarity index 99% rename from core/os/os2/dir_posix.odin rename to core/os/dir_posix.odin index d9fa16f8d..c67a37430 100644 --- a/core/os/os2/dir_posix.odin +++ b/core/os/dir_posix.odin @@ -1,6 +1,6 @@ #+private #+build darwin, netbsd, freebsd, openbsd -package os2 +package os import "core:sys/posix" diff --git a/core/os/os2/dir_posix_darwin.odin b/core/os/dir_posix_darwin.odin similarity index 88% rename from core/os/os2/dir_posix_darwin.odin rename to core/os/dir_posix_darwin.odin index 3cae50d25..ddd25c1fc 100644 --- a/core/os/os2/dir_posix_darwin.odin +++ b/core/os/dir_posix_darwin.odin @@ -1,9 +1,9 @@ #+private -package os2 +package os import "core:sys/darwin" -_copy_directory_all_native :: proc(dst, src: string, dst_perm := 0o755) -> (err: Error) { +_copy_directory_all_native :: proc(dst, src: string, dst_perm := Permissions_Default) -> (err: Error) { temp_allocator := TEMP_ALLOCATOR_GUARD({}) csrc := clone_to_cstring(src, temp_allocator) or_return diff --git a/core/os/os2/dir_walker.odin b/core/os/dir_walker.odin similarity index 98% rename from core/os/os2/dir_walker.odin rename to core/os/dir_walker.odin index 0af751f31..b510b7a2a 100644 --- a/core/os/os2/dir_walker.odin +++ b/core/os/dir_walker.odin @@ -1,4 +1,4 @@ -package os2 +package os import "core:container/queue" @@ -136,9 +136,9 @@ If an error occurred opening a directory, you may get zero'd info struct and Example: package main - import "core:fmt" - import "core:strings" - import os "core:os/os2" + import "core:fmt" + import "core:strings" + import "core:os" main :: proc() { w := os.walker_create("core") @@ -227,4 +227,4 @@ walker_walk :: proc(w: ^Walker) -> (fi: File_Info, ok: bool) { } return info, iter_ok -} +} \ No newline at end of file diff --git a/core/os/os2/dir_wasi.odin b/core/os/dir_wasi.odin similarity index 98% rename from core/os/os2/dir_wasi.odin rename to core/os/dir_wasi.odin index 61c005674..05d74be31 100644 --- a/core/os/os2/dir_wasi.odin +++ b/core/os/dir_wasi.odin @@ -1,7 +1,6 @@ #+private -package os2 +package os -import "base:runtime" import "core:slice" import "base:intrinsics" import "core:sys/wasm/wasi" diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin index 40f4b9e9b..1168fe18b 100644 --- a/core/os/dir_windows.odin +++ b/core/os/dir_windows.odin @@ -1,114 +1,144 @@ +#+private package os -import win32 "core:sys/windows" -import "core:strings" import "base:runtime" +import "core:time" +import win32 "core:sys/windows" + +@(private="file") +find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) { + // Ignore "." and ".." + if d.cFileName[0] == '.' && d.cFileName[1] == 0 { + return + } + if d.cFileName[0] == '.' && d.cFileName[1] == '.' && d.cFileName[2] == 0 { + return + } + + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + path := concatenate({base_path, `\`, win32_wstring_to_utf8(cstring16(raw_data(d.cFileName[:])), temp_allocator) or_else ""}, allocator) or_return + + handle := win32.HANDLE(_open_internal(path, {.Read}, Permissions_Read_Write_All) or_else 0) + defer win32.CloseHandle(handle) + + fi.fullpath = path + fi.name = basename(path) + fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) + + fi.type, fi.mode = _file_type_mode_from_file_attributes(d.dwFileAttributes, handle, d.dwReserved0) + + fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime)) + fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime)) + fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime)) + + if file_id_info: win32.FILE_ID_INFO; handle != nil && win32.GetFileInformationByHandleEx(handle, .FileIdInfo, &file_id_info, size_of(file_id_info)) { + #assert(size_of(fi.inode) == size_of(file_id_info.FileId)) + #assert(size_of(fi.inode) == 16) + runtime.mem_copy_non_overlapping(&fi.inode, &file_id_info.FileId, 16) + } + + return +} + +Read_Directory_Iterator_Impl :: struct { + find_data: win32.WIN32_FIND_DATAW, + find_handle: win32.HANDLE, + path: string, + prev_fi: File_Info, + no_more_files: bool, +} + @(require_results) -read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Error) { - @(require_results) - find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW) -> (fi: File_Info) { - // Ignore "." and ".." - if d.cFileName[0] == '.' && d.cFileName[1] == 0 { +_read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info, index: int, ok: bool) { + for !it.impl.no_more_files { + err: Error + file_info_delete(it.impl.prev_fi, file_allocator()) + it.impl.prev_fi = {} + + fi, err = find_data_to_file_info(it.impl.path, &it.impl.find_data, file_allocator()) + if err != nil { + read_directory_iterator_set_error(it, it.impl.path, err) return } - if d.cFileName[0] == '.' && d.cFileName[1] == '.' && d.cFileName[2] == 0 { - return - } - path := strings.concatenate({base_path, `\`, win32.utf16_to_utf8(d.cFileName[:]) or_else ""}) - fi.fullpath = path - fi.name = basename(path) - fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) - if d.dwFileAttributes & win32.FILE_ATTRIBUTE_READONLY != 0 { - fi.mode |= 0o444 - } else { - fi.mode |= 0o666 + if fi.name != "" { + it.impl.prev_fi = fi + ok = true + index = it.index + it.index += 1 } - is_sym := false - if d.dwFileAttributes & win32.FILE_ATTRIBUTE_REPARSE_Point == 0 { - is_sym = false - } else { - is_sym = d.dwReserved0 == win32.IO_REPARSE_TAG_SYMLINK || d.dwReserved0 == win32.IO_REPARSE_TAG_MOUNT_POINT - } - - if is_sym { - fi.mode |= File_Mode_Sym_Link - } else { - if d.dwFileAttributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 { - fi.mode |= 0o111 | File_Mode_Dir + if !win32.FindNextFileW(it.impl.find_handle, &it.impl.find_data) { + e := _get_platform_error() + if pe, _ := is_platform_error(e); pe != i32(win32.ERROR_NO_MORE_FILES) { + read_directory_iterator_set_error(it, it.impl.path, e) } - - // fi.mode |= file_type_mode(h); + it.impl.no_more_files = true } + if ok { + return + } + } + return +} - windows_set_file_info_times(&fi, d) +_read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) { + it.impl.no_more_files = false - fi.is_dir = fi.mode & File_Mode_Dir != 0 + if f == nil || f.impl == nil { + read_directory_iterator_set_error(it, "", .Invalid_File) return } - if fd == 0 { - return nil, ERROR_INVALID_HANDLE + it.f = f + impl := (^File_Impl)(f.impl) + + // NOTE: Allow calling `init` to target a new directory with the same iterator - reset idx. + if it.impl.find_handle != nil { + win32.FindClose(it.impl.find_handle) + } + if it.impl.path != "" { + delete(it.impl.path, file_allocator()) } - context.allocator = allocator - - h := win32.HANDLE(fd) - - dir_fi, _ := file_info_from_get_file_information_by_handle("", h) - if !dir_fi.is_dir { - return nil, .Not_Dir - } - - n := n - size := n - if n <= 0 { - n = -1 - size = 100 - } - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) - - wpath := cleanpath_from_handle_u16(fd, context.temp_allocator) or_return - if len(wpath) == 0 { + if !is_directory(impl.name) { + read_directory_iterator_set_error(it, impl.name, .Invalid_Dir) return } - dfi := make([dynamic]File_Info, 0, size) or_return + wpath := string16(impl.wname) + temp_allocator := TEMP_ALLOCATOR_GUARD({}) - wpath_search := make([]u16, len(wpath)+3, context.temp_allocator) or_return + wpath_search := make([]u16, len(wpath)+3, temp_allocator) copy(wpath_search, wpath) wpath_search[len(wpath)+0] = '\\' wpath_search[len(wpath)+1] = '*' wpath_search[len(wpath)+2] = 0 - path := cleanpath_from_buf(wpath) - defer delete(path) - - find_data := &win32.WIN32_FIND_DATAW{} - find_handle := win32.FindFirstFileW(cstring16(raw_data(wpath_search)), find_data) - if find_handle == win32.INVALID_HANDLE_VALUE { - err = get_last_error() - return dfi[:], err + it.impl.find_handle = win32.FindFirstFileW(cstring16(raw_data(wpath_search)), &it.impl.find_data) + if it.impl.find_handle == win32.INVALID_HANDLE_VALUE { + read_directory_iterator_set_error(it, impl.name, _get_platform_error()) + return } - defer win32.FindClose(find_handle) - for n != 0 { - fi: File_Info - fi = find_data_to_file_info(path, find_data) - if fi.name != "" { - append(&dfi, fi) - n -= 1 - } - - if !win32.FindNextFileW(find_handle, find_data) { - e := get_last_error() - if e == ERROR_NO_MORE_FILES { - break - } - return dfi[:], e - } + defer if it.err.err != nil { + win32.FindClose(it.impl.find_handle) } - return dfi[:], nil + err: Error + it.impl.path, err = _cleanpath_from_buf(wpath, file_allocator()) + if err != nil { + read_directory_iterator_set_error(it, impl.name, err) + } + + return +} + +_read_directory_iterator_destroy :: proc(it: ^Read_Directory_Iterator) { + if it.f == nil { + return + } + file_info_delete(it.impl.prev_fi, file_allocator()) + delete(it.impl.path, file_allocator()) + win32.FindClose(it.impl.find_handle) } diff --git a/core/os/doc.odin b/core/os/doc.odin new file mode 100644 index 000000000..10087a5e1 --- /dev/null +++ b/core/os/doc.odin @@ -0,0 +1,3 @@ +// A cross-platform API for things like `I/O`, intended to be uniform across all operating systems. +// Features not generally available appear in the system-specific packages under `core:sys`. +package os diff --git a/core/os/os2/env.odin b/core/os/env.odin similarity index 99% rename from core/os/os2/env.odin rename to core/os/env.odin index 310d45af1..0b8138e6b 100644 --- a/core/os/os2/env.odin +++ b/core/os/env.odin @@ -1,4 +1,4 @@ -package os2 +package os import "base:runtime" import "core:strings" diff --git a/core/os/env_js.odin b/core/os/env_js.odin new file mode 100644 index 000000000..55ffce593 --- /dev/null +++ b/core/os/env_js.odin @@ -0,0 +1,42 @@ +#+build js wasm32, js wasm64p32 +#+private +package os + +// None of this does anything on js/wasm. +// It's only here so importing `core:os` on wasm panics cleanly, +// without spamming about all sorts of missing procs and types. + +import "base:runtime" + +build_env :: proc() -> (err: Error) { + return +} + +@(require_results) +_lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { + return +} + +_lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, error: Error) { + return "", .Unsupported +} +_lookup_env :: proc{_lookup_env_alloc, _lookup_env_buf} + +@(require_results) +_set_env :: proc(key, value: string) -> (err: Error) { + return .Unsupported +} + +@(require_results) +_unset_env :: proc(key: string) -> bool { + return true +} + +_clear_env :: proc() { + +} + +@(require_results) +_environ :: proc(allocator: runtime.Allocator) -> (environ: []string, err: Error) { + return {}, .Unsupported +} \ No newline at end of file diff --git a/core/os/os2/env_linux.odin b/core/os/env_linux.odin similarity index 99% rename from core/os/os2/env_linux.odin rename to core/os/env_linux.odin index faee5c5ab..e55c59293 100644 --- a/core/os/os2/env_linux.odin +++ b/core/os/env_linux.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" import "base:intrinsics" @@ -282,6 +282,7 @@ when ODIN_NO_CRT { return "", .Buffer_Full } else { copy(buf, key) + buf[len(key)] = 0 } cval := posix.getenv(cstring(raw_data(buf))) diff --git a/core/os/os2/env_posix.odin b/core/os/env_posix.odin similarity index 98% rename from core/os/os2/env_posix.odin rename to core/os/env_posix.odin index 8b5f2082e..5d46cf7fc 100644 --- a/core/os/os2/env_posix.odin +++ b/core/os/env_posix.odin @@ -1,6 +1,6 @@ #+private #+build darwin, netbsd, freebsd, openbsd -package os2 +package os import "base:runtime" @@ -35,6 +35,7 @@ _lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, error: Error) return "", .Buffer_Full } else { copy(buf, key) + buf[len(key)] = 0 } cval := posix.getenv(cstring(raw_data(buf))) diff --git a/core/os/os2/env_wasi.odin b/core/os/env_wasi.odin similarity index 99% rename from core/os/os2/env_wasi.odin rename to core/os/env_wasi.odin index b126d014e..03a56421d 100644 --- a/core/os/os2/env_wasi.odin +++ b/core/os/env_wasi.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" @@ -88,6 +88,7 @@ _lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, error: Error) return "", .Buffer_Full } else { copy(buf, key) + buf[len(key)] = 0 } sync.shared_guard(&g_env_mutex) diff --git a/core/os/env_windows.odin b/core/os/env_windows.odin index ef658b0a1..dfbc5c454 100644 --- a/core/os/env_windows.odin +++ b/core/os/env_windows.odin @@ -1,30 +1,37 @@ +#+private package os import win32 "core:sys/windows" import "base:runtime" -// lookup_env gets the value of the environment variable named by the key -// If the variable is found in the environment the value (which can be empty) is returned and the boolean is true -// Otherwise the returned value will be empty and the boolean will be false -// NOTE: the value will be allocated with the supplied allocator -@(require_results) -lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { +_lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { if key == "" { return } - wkey := win32.utf8_to_wstring(key) - n := win32.GetEnvironmentVariableW(wkey, nil, 0) - if n == 0 && get_last_error() == ERROR_ENVVAR_NOT_FOUND { - return "", false - } - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + wkey, _ := win32_utf8_to_wstring(key, temp_allocator) + + n := win32.GetEnvironmentVariableW(wkey, nil, 0) + if n == 0 { + err := win32.GetLastError() + if err == win32.ERROR_ENVVAR_NOT_FOUND { + return "", false + } + return "", true + } + + b := make([]u16, n+1, temp_allocator) - b, _ := make([dynamic]u16, n, context.temp_allocator) n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b))) - if n == 0 && get_last_error() == ERROR_ENVVAR_NOT_FOUND { + if n == 0 { + err := win32.GetLastError() + if err == win32.ERROR_ENVVAR_NOT_FOUND { + return "", false + } return "", false } - value, _ = win32.utf16_to_utf8(b[:n], allocator) + + value = win32_utf16_to_utf8(string16(b[:n]), allocator) or_else "" found = true return } @@ -33,7 +40,7 @@ lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: // Note that it is limited to environment names and values of 512 utf-16 values each // due to the necessary utf-8 <> utf-16 conversion. @(require_results) -lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) { +_lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, err: Error) { key_buf: [513]u16 wkey := win32.utf8_to_wstring(key_buf[:], key) if wkey == nil { @@ -57,78 +64,28 @@ lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) return value, nil } -lookup_env :: proc{lookup_env_alloc, lookup_env_buffer} +_lookup_env :: proc{_lookup_env_alloc, _lookup_env_buf} -// get_env retrieves the value of the environment variable named by the key -// It returns the value, which will be empty if the variable is not present -// To distinguish between an empty value and an unset value, use lookup_env -// NOTE: the value will be allocated with the supplied allocator -@(require_results) -get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) { - value, _ = lookup_env(key, allocator) - return -} - -@(require_results) -get_env_buf :: proc(buf: []u8, key: string) -> (value: string) { - value, _ = lookup_env(buf, key) - return -} -get_env :: proc{get_env_alloc, get_env_buf} - - -// set_env sets the value of the environment variable named by the key -set_env :: proc(key, value: string) -> Error { - k := win32.utf8_to_wstring(key) - v := win32.utf8_to_wstring(value) +_set_env :: proc(key, value: string) -> Error { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + k := win32_utf8_to_wstring(key, temp_allocator) or_return + v := win32_utf8_to_wstring(value, temp_allocator) or_return if !win32.SetEnvironmentVariableW(k, v) { - return get_last_error() + return _get_platform_error() } return nil } -// unset_env unsets a single environment variable -unset_env :: proc(key: string) -> Error { - k := win32.utf8_to_wstring(key) - if !win32.SetEnvironmentVariableW(k, nil) { - return get_last_error() - } - return nil +_unset_env :: proc(key: string) -> bool { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + k, _ := win32_utf8_to_wstring(key, temp_allocator) + return bool(win32.SetEnvironmentVariableW(k, nil)) } -// environ returns a copy of strings representing the environment, in the form "key=value" -// NOTE: the slice of strings and the strings with be allocated using the supplied allocator -@(require_results) -environ :: proc(allocator := context.allocator) -> []string { - envs := ([^]win32.WCHAR)(win32.GetEnvironmentStringsW()) - if envs == nil { - return nil - } - defer win32.FreeEnvironmentStringsW(envs) - - r, err := make([dynamic]string, 0, 50, allocator) - if err != nil { - return nil - } - for from, i := 0, 0; true; i += 1 { - if c := envs[i]; c == 0 { - if i <= from { - break - } - append(&r, win32.utf16_to_utf8(envs[from:i], allocator) or_else "") - from = i + 1 - } - } - - return r[:] -} - - -// clear_env deletes all environment variables -clear_env :: proc() { - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - envs := environ(context.temp_allocator) +_clear_env :: proc() { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + envs, _ := environ(temp_allocator) for env in envs { for j in 1.. string where intrinsics.type_is_enum(Platform_Error) { - if e == nil { - return "" - } - when ODIN_OS == .Darwin { - if s := string(_darwin_string_error(i32(e))); s != "" { - return s - } - } - - when ODIN_OS != .Linux { - @(require_results) - binary_search :: proc "contextless" (array: $A/[]$T, key: T) -> (index: int, found: bool) #no_bounds_check { - n := len(array) - left, right := 0, n - for left < right { - mid := int(uint(left+right) >> 1) - if array[mid] < key { - left = mid+1 - } else { - // equal or greater - right = mid - } - } - return left, left < n && array[left] == key - } - - err := runtime.Type_Info_Enum_Value(e) - - ti := &runtime.type_info_base(type_info_of(Platform_Error)).variant.(runtime.Type_Info_Enum) - if idx, ok := binary_search(ti.values, err); ok { - return ti.names[idx] - } - } else { - @(rodata, static) - pe_strings := [Platform_Error]string{ - .NONE = "", - .EPERM = "Operation not permitted", - .ENOENT = "No such file or directory", - .ESRCH = "No such process", - .EINTR = "Interrupted system call", - .EIO = "Input/output error", - .ENXIO = "No such device or address", - .E2BIG = "Argument list too long", - .ENOEXEC = "Exec format error", - .EBADF = "Bad file descriptor", - .ECHILD = "No child processes", - .EAGAIN = "Resource temporarily unavailable", - .ENOMEM = "Cannot allocate memory", - .EACCES = "Permission denied", - .EFAULT = "Bad address", - .ENOTBLK = "Block device required", - .EBUSY = "Device or resource busy", - .EEXIST = "File exists", - .EXDEV = "Invalid cross-device link", - .ENODEV = "No such device", - .ENOTDIR = "Not a directory", - .EISDIR = "Is a directory", - .EINVAL = "Invalid argument", - .ENFILE = "Too many open files in system", - .EMFILE = "Too many open files", - .ENOTTY = "Inappropriate ioctl for device", - .ETXTBSY = "Text file busy", - .EFBIG = "File too large", - .ENOSPC = "No space left on device", - .ESPIPE = "Illegal seek", - .EROFS = "Read-only file system", - .EMLINK = "Too many links", - .EPIPE = "Broken pipe", - .EDOM = "Numerical argument out of domain", - .ERANGE = "Numerical result out of range", - .EDEADLK = "Resource deadlock avoided", - .ENAMETOOLONG = "File name too long", - .ENOLCK = "No locks available", - .ENOSYS = "Function not implemented", - .ENOTEMPTY = "Directory not empty", - .ELOOP = "Too many levels of symbolic links", - .EUNKNOWN_41 = "Unknown Error (41)", - .ENOMSG = "No message of desired type", - .EIDRM = "Identifier removed", - .ECHRNG = "Channel number out of range", - .EL2NSYNC = "Level 2 not synchronized", - .EL3HLT = "Level 3 halted", - .EL3RST = "Level 3 reset", - .ELNRNG = "Link number out of range", - .EUNATCH = "Protocol driver not attached", - .ENOCSI = "No CSI structure available", - .EL2HLT = "Level 2 halted", - .EBADE = "Invalid exchange", - .EBADR = "Invalid request descriptor", - .EXFULL = "Exchange full", - .ENOANO = "No anode", - .EBADRQC = "Invalid request code", - .EBADSLT = "Invalid slot", - .EUNKNOWN_58 = "Unknown Error (58)", - .EBFONT = "Bad font file format", - .ENOSTR = "Device not a stream", - .ENODATA = "No data available", - .ETIME = "Timer expired", - .ENOSR = "Out of streams resources", - .ENONET = "Machine is not on the network", - .ENOPKG = "Package not installed", - .EREMOTE = "Object is remote", - .ENOLINK = "Link has been severed", - .EADV = "Advertise error", - .ESRMNT = "Srmount error", - .ECOMM = "Communication error on send", - .EPROTO = "Protocol error", - .EMULTIHOP = "Multihop attempted", - .EDOTDOT = "RFS specific error", - .EBADMSG = "Bad message", - .EOVERFLOW = "Value too large for defined data type", - .ENOTUNIQ = "Name not unique on network", - .EBADFD = "File descriptor in bad state", - .EREMCHG = "Remote address changed", - .ELIBACC = "Can not access a needed shared library", - .ELIBBAD = "Accessing a corrupted shared library", - .ELIBSCN = ".lib section in a.out corrupted", - .ELIBMAX = "Attempting to link in too many shared libraries", - .ELIBEXEC = "Cannot exec a shared library directly", - .EILSEQ = "Invalid or incomplete multibyte or wide character", - .ERESTART = "Interrupted system call should be restarted", - .ESTRPIPE = "Streams pipe error", - .EUSERS = "Too many users", - .ENOTSOCK = "Socket operation on non-socket", - .EDESTADDRREQ = "Destination address required", - .EMSGSIZE = "Message too long", - .EPROTOTYPE = "Protocol wrong type for socket", - .ENOPROTOOPT = "Protocol not available", - .EPROTONOSUPPORT = "Protocol not supported", - .ESOCKTNOSUPPORT = "Socket type not supported", - .EOPNOTSUPP = "Operation not supported", - .EPFNOSUPPORT = "Protocol family not supported", - .EAFNOSUPPORT = "Address family not supported by protocol", - .EADDRINUSE = "Address already in use", - .EADDRNOTAVAIL = "Cannot assign requested address", - .ENETDOWN = "Network is down", - .ENETUNREACH = "Network is unreachable", - .ENETRESET = "Network dropped connection on reset", - .ECONNABORTED = "Software caused connection abort", - .ECONNRESET = "Connection reset by peer", - .ENOBUFS = "No buffer space available", - .EISCONN = "Transport endpoint is already connected", - .ENOTCONN = "Transport endpoint is not connected", - .ESHUTDOWN = "Cannot send after transport endpoint shutdown", - .ETOOMANYREFS = "Too many references: cannot splice", - .ETIMEDOUT = "Connection timed out", - .ECONNREFUSED = "Connection refused", - .EHOSTDOWN = "Host is down", - .EHOSTUNREACH = "No route to host", - .EALREADY = "Operation already in progress", - .EINPROGRESS = "Operation now in progress", - .ESTALE = "Stale file handle", - .EUCLEAN = "Structure needs cleaning", - .ENOTNAM = "Not a XENIX named type file", - .ENAVAIL = "No XENIX semaphores available", - .EISNAM = "Is a named type file", - .EREMOTEIO = "Remote I/O error", - .EDQUOT = "Disk quota exceeded", - .ENOMEDIUM = "No medium found", - .EMEDIUMTYPE = "Wrong medium type", - .ECANCELED = "Operation canceled", - .ENOKEY = "Required key not available", - .EKEYEXPIRED = "Key has expired", - .EKEYREVOKED = "Key has been revoked", - .EKEYREJECTED = "Key was rejected by service", - .EOWNERDEAD = "Owner died", - .ENOTRECOVERABLE = "State not recoverable", - .ERFKILL = "Operation not possible due to RF-kill", - .EHWPOISON = "Memory page has hardware error", - } - if Platform_Error.NONE <= e && e <= max(Platform_Error) { - return pe_strings[e] - } - } - return "" -} - -@(private, require_results) +// Attempts to convert an `Error` `ferr` into an `io.Error` +@(private) error_to_io_error :: proc(ferr: Error) -> io.Error { if ferr == nil { return .None diff --git a/core/os/errors_js.odin b/core/os/errors_js.odin new file mode 100644 index 000000000..368b94d68 --- /dev/null +++ b/core/os/errors_js.odin @@ -0,0 +1,17 @@ +#+build js wasm32, js wasm64p32 +#+private +package os + +// None of this does anything on js/wasm. +// It's only here so importing `core:os` on wasm panics cleanly, +// without spamming about all sorts of missing procs and types. + +_Platform_Error :: enum i32 {} + +_error_string :: proc(errno: i32) -> string { + return "" +} + +_get_platform_error :: proc(errno: _Platform_Error) -> Error { + return Platform_Error(errno) +} \ No newline at end of file diff --git a/core/os/os2/errors_linux.odin b/core/os/errors_linux.odin similarity index 99% rename from core/os/os2/errors_linux.odin rename to core/os/errors_linux.odin index a7556c306..713c03359 100644 --- a/core/os/os2/errors_linux.odin +++ b/core/os/errors_linux.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "core:sys/linux" @@ -148,7 +148,7 @@ _get_platform_error :: proc(errno: linux.Errno) -> Error { #partial switch errno { case .NONE: return nil - case .EPERM: + case .EPERM, .EACCES: return .Permission_Denied case .EEXIST: return .Exist diff --git a/core/os/os2/errors_posix.odin b/core/os/errors_posix.odin similarity index 96% rename from core/os/os2/errors_posix.odin rename to core/os/errors_posix.odin index 8a9ca07df..45bac931f 100644 --- a/core/os/os2/errors_posix.odin +++ b/core/os/errors_posix.odin @@ -1,6 +1,6 @@ #+private #+build darwin, netbsd, freebsd, openbsd -package os2 +package os import "core:sys/posix" @@ -16,7 +16,7 @@ _get_platform_error_from_errno :: proc() -> Error { _get_platform_error_existing :: proc(errno: posix.Errno) -> Error { #partial switch errno { - case .EPERM: + case .EPERM, .EACCES: return .Permission_Denied case .EEXIST: return .Exist diff --git a/core/os/os2/errors_wasi.odin b/core/os/errors_wasi.odin similarity index 98% rename from core/os/os2/errors_wasi.odin rename to core/os/errors_wasi.odin index b88e5b81e..a0377ce96 100644 --- a/core/os/os2/errors_wasi.odin +++ b/core/os/errors_wasi.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" diff --git a/core/os/os2/errors_windows.odin b/core/os/errors_windows.odin similarity index 99% rename from core/os/os2/errors_windows.odin rename to core/os/errors_windows.odin index 404560f98..639780337 100644 --- a/core/os/os2/errors_windows.odin +++ b/core/os/errors_windows.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" import "core:slice" diff --git a/core/os/os2/file.odin b/core/os/file.odin similarity index 99% rename from core/os/os2/file.odin rename to core/os/file.odin index 9e7788c31..61582c528 100644 --- a/core/os/os2/file.odin +++ b/core/os/file.odin @@ -1,4 +1,4 @@ -package os2 +package os import "core:io" import "core:time" @@ -67,7 +67,7 @@ File_Flag :: enum { Trunc, Sparse, Inheritable, - + Non_Blocking, Unbuffered_IO, } @@ -538,6 +538,11 @@ is_directory :: proc(path: string) -> bool { /* `copy_file` copies a file from `src_path` to `dst_path` and returns an error if any was encountered. */ +@(require_results) +is_tty :: proc "contextless" (f: ^File) -> bool { + return _is_tty(f) +} + copy_file :: proc(dst_path, src_path: string) -> Error { when #defined(_copy_file_native) { return _copy_file_native(dst_path, src_path) @@ -562,4 +567,4 @@ _copy_file :: proc(dst_path, src_path: string) -> Error { _, err := io.copy(to_writer(dst), to_reader(src)) return err -} +} \ No newline at end of file diff --git a/core/os/file_js.odin b/core/os/file_js.odin new file mode 100644 index 000000000..aef811c11 --- /dev/null +++ b/core/os/file_js.odin @@ -0,0 +1,115 @@ +#+build js wasm32, js wasm64p32 +#+private +package os + +// None of this does anything on js/wasm. +// It's only here so importing `core:os` on wasm panics cleanly, +// without spamming about all sorts of missing procs and types. + +import "base:runtime" +import "core:io" +import "core:time" + +File_Impl :: struct { + file: File, +} + +_open :: proc(name: string, flags: File_Flags, perm: Permissions) -> (f: ^File, err: Error) { + return nil, .Unsupported +} + +_new_file :: proc(handle: uintptr, name: string, allocator: runtime.Allocator) -> (f: ^File, err: Error) { + return nil, .Unsupported +} + +_clone :: proc(f: ^File) -> (clone: ^File, err: Error) { + return nil, .Unsupported +} + +_close :: proc(f: ^File_Impl) -> (err: Error) { + return .Unsupported +} + +_fd :: proc(f: ^File) -> uintptr { + return 0 +} + +_is_tty :: proc "contextless" (f: ^File) -> bool { + return true +} + +_name :: proc(f: ^File) -> string { + return "" +} + +_sync :: proc(f: ^File) -> Error { + return .Unsupported +} + +_truncate :: proc(f: ^File, size: i64) -> Error { + return .Unsupported +} + +_remove :: proc(name: string) -> Error { + return .Unsupported +} + +_rename :: proc(old_path, new_path: string) -> Error { + return .Unsupported +} + +_link :: proc(old_name, new_name: string) -> Error { + return .Unsupported +} + +_symlink :: proc(old_name, new_name: string) -> Error { + return .Unsupported +} + +_read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, err: Error) { + return "", .Unsupported +} + +_chdir :: proc(name: string) -> Error { + return .Unsupported +} + +_fchdir :: proc(f: ^File) -> Error { + return .Unsupported +} + +_fchmod :: proc(f: ^File, mode: Permissions) -> Error { + return .Unsupported +} + +_chmod :: proc(name: string, mode: Permissions) -> Error { + return .Unsupported +} + +_fchown :: proc(f: ^File, uid, gid: int) -> Error { + return .Unsupported +} + +_chown :: proc(name: string, uid, gid: int) -> Error { + return .Unsupported +} + +_lchown :: proc(name: string, uid, gid: int) -> Error { + return .Unsupported +} + +_chtimes :: proc(name: string, atime, mtime: time.Time) -> Error { + return .Unsupported +} + +_fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error { + return .Unsupported +} + +_exists :: proc(path: string) -> bool { + return false +} + +_file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { + return 0, .Empty +} \ No newline at end of file diff --git a/core/os/os2/file_linux.odin b/core/os/file_linux.odin similarity index 97% rename from core/os/os2/file_linux.odin rename to core/os/file_linux.odin index fb25ca411..d4223ba5d 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/file_linux.odin @@ -1,11 +1,12 @@ #+private -package os2 +package os import "base:runtime" import "core:io" import "core:time" import "core:sync" import "core:sys/linux" +import "core:sys/posix" // Most implementations will EINVAL at some point when doing big writes. // In practice a read/write call would probably never read/write these big buffers all at once, @@ -82,6 +83,7 @@ _open :: proc(name: string, flags: File_Flags, perm: Permissions) -> (f: ^File, if .Excl in flags { sys_flags += {.EXCL} } if .Sync in flags { sys_flags += {.DSYNC} } if .Trunc in flags { sys_flags += {.TRUNC} } + if .Non_Blocking in flags { sys_flags += {.NONBLOCK} } if .Inheritable in flags { sys_flags -= {.CLOEXEC} } fd, errno := linux.open(name_cstr, sys_flags, transmute(linux.Mode)transmute(u32)perm) @@ -173,6 +175,17 @@ _fd :: proc(f: ^File) -> uintptr { return uintptr(impl.fd) } +_is_tty :: proc "contextless" (f: ^File) -> bool { + if f == nil || f.impl == nil { + return false + } + impl := (^File_Impl)(f.impl) + + // TODO: Replace `posix.isatty` with `tcgetattr(fd, &termios) == 0` + is_tty := posix.isatty(posix.FD(impl.fd)) + return bool(is_tty) +} + _name :: proc(f: ^File) -> string { return (^File_Impl)(f.impl).name if f != nil && f.impl != nil else "" } diff --git a/core/os/os2/file_posix.odin b/core/os/file_posix.odin similarity index 95% rename from core/os/os2/file_posix.odin rename to core/os/file_posix.odin index 874ec7c7d..006f25e11 100644 --- a/core/os/os2/file_posix.odin +++ b/core/os/file_posix.odin @@ -1,6 +1,6 @@ #+private #+build darwin, netbsd, freebsd, openbsd -package os2 +package os import "base:runtime" @@ -61,12 +61,13 @@ _open :: proc(name: string, flags: File_Flags, perm: Permissions) -> (f: ^File, } } - if .Append in flags { sys_flags += {.APPEND} } - if .Create in flags { sys_flags += {.CREAT} } - if .Excl in flags { sys_flags += {.EXCL} } - if .Sync in flags { sys_flags += {.DSYNC} } - if .Trunc in flags { sys_flags += {.TRUNC} } - if .Inheritable in flags { sys_flags -= {.CLOEXEC} } + if .Append in flags { sys_flags += {.APPEND} } + if .Create in flags { sys_flags += {.CREAT} } + if .Excl in flags { sys_flags += {.EXCL} } + if .Sync in flags { sys_flags += {.DSYNC} } + if .Trunc in flags { sys_flags += {.TRUNC} } + if .Non_Blocking in flags { sys_flags += {.NONBLOCK} } + if .Inheritable in flags { sys_flags -= {.CLOEXEC} } temp_allocator := TEMP_ALLOCATOR_GUARD({}) cname := clone_to_cstring(name, temp_allocator) or_return @@ -160,6 +161,13 @@ __fd :: proc(f: ^File) -> posix.FD { return -1 } +_is_tty :: proc "contextless" (f: ^File) -> bool { + context = runtime.default_context() + fd := _fd(f) + is_tty := posix.isatty(posix.FD(fd)) + return bool(is_tty) +} + _name :: proc(f: ^File) -> string { if f != nil && f.impl != nil { return (^File_Impl)(f.impl).name diff --git a/core/os/os2/file_posix_darwin.odin b/core/os/file_posix_darwin.odin similarity index 98% rename from core/os/os2/file_posix_darwin.odin rename to core/os/file_posix_darwin.odin index aed3e56f5..5522124ae 100644 --- a/core/os/os2/file_posix_darwin.odin +++ b/core/os/file_posix_darwin.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" @@ -43,4 +43,4 @@ _copy_file_native :: proc(dst_path, src_path: string) -> (err: Error) { } return -} +} \ No newline at end of file diff --git a/core/os/os2/file_posix_freebsd.odin b/core/os/file_posix_freebsd.odin similarity index 99% rename from core/os/os2/file_posix_freebsd.odin rename to core/os/file_posix_freebsd.odin index 05d031930..4ed9ecc1e 100644 --- a/core/os/os2/file_posix_freebsd.odin +++ b/core/os/file_posix_freebsd.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" diff --git a/core/os/os2/file_posix_netbsd.odin b/core/os/file_posix_netbsd.odin similarity index 97% rename from core/os/os2/file_posix_netbsd.odin rename to core/os/file_posix_netbsd.odin index f96c227ba..791836c00 100644 --- a/core/os/os2/file_posix_netbsd.odin +++ b/core/os/file_posix_netbsd.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" diff --git a/core/os/os2/file_posix_other.odin b/core/os/file_posix_other.odin similarity index 97% rename from core/os/os2/file_posix_other.odin rename to core/os/file_posix_other.odin index 8871a0062..6430c9fb6 100644 --- a/core/os/os2/file_posix_other.odin +++ b/core/os/file_posix_other.odin @@ -1,6 +1,6 @@ #+private #+build openbsd -package os2 +package os import "base:runtime" diff --git a/core/os/os2/file_stream.odin b/core/os/file_stream.odin similarity index 99% rename from core/os/os2/file_stream.odin rename to core/os/file_stream.odin index af6e50921..cee1bef47 100644 --- a/core/os/os2/file_stream.odin +++ b/core/os/file_stream.odin @@ -1,4 +1,4 @@ -package os2 +package os import "base:intrinsics" import "base:runtime" diff --git a/core/os/os2/file_util.odin b/core/os/file_util.odin similarity index 89% rename from core/os/os2/file_util.odin rename to core/os/file_util.odin index c2cf7c121..854977b01 100644 --- a/core/os/os2/file_util.odin +++ b/core/os/file_util.odin @@ -1,4 +1,4 @@ -package os2 +package os import "base:runtime" import "core:strconv" @@ -111,6 +111,25 @@ read_ptr :: proc(f: ^File, data: rawptr, len: int) -> (n: int, err: Error) { } +/* + `write_slice` is a utility procedure that writes the bytes points at `slice`. + + It is equivalent to: `write(f, ([^]byte)(raw_data(slice))[:len(slice)*size_of(slice[0])])` +*/ +write_slice :: proc(f: ^File, slice: $S/[]$T) -> (n: int, err: Error) { + return write(f, ([^]byte)(raw_data(slice))[:len(slice)*size_of(slice[0])]) +} + +/* + `read_slice` is a utility procedure that writes the bytes points at `slice`. + + It is equivalent to: `read(f, ([^]byte)(raw_data(slice))[:len(slice)*size_of(slice[0])])` +*/ +read_slice :: proc(f: ^File, slice: $S/[]$T) -> (n: int, err: Error) { + return read(f, ([^]byte)(raw_data(slice))[:len(slice)*size_of(slice[0])]) +} + + /* `read_at_least` reads from `f` into `buf` until it has read at least `min` bytes. @@ -156,9 +175,12 @@ read_entire_file :: proc{ */ @(require_results) read_entire_file_from_path :: proc(name: string, allocator: runtime.Allocator, loc := #caller_location) -> (data: []byte, err: Error) { - f := open(name) or_return + f, ferr := open(name) + if ferr != nil { + return nil, ferr + } defer close(f) - return read_entire_file_from_file(f, allocator, loc) + return read_entire_file_from_file(f=f, allocator=allocator, loc=loc) } /* diff --git a/core/os/os2/file_wasi.odin b/core/os/file_wasi.odin similarity index 95% rename from core/os/os2/file_wasi.odin rename to core/os/file_wasi.odin index b60cce4be..116c237d6 100644 --- a/core/os/os2/file_wasi.odin +++ b/core/os/file_wasi.odin @@ -1,5 +1,6 @@ +#+feature global-context #+private -package os2 +package os import "base:runtime" @@ -40,7 +41,6 @@ init_std_files :: proc "contextless" () { data = impl, procedure = _file_stream_proc, } - impl.file.fstat = _fstat return &impl.file } @@ -185,8 +185,9 @@ _open :: proc(name: string, flags: File_Flags, perm: Permissions) -> (f: ^File, if .Trunc in flags { oflags += {.TRUNC} } fdflags: wasi.fdflags_t - if .Append in flags { fdflags += {.APPEND} } - if .Sync in flags { fdflags += {.SYNC} } + if .Append in flags { fdflags += {.APPEND} } + if .Sync in flags { fdflags += {.SYNC} } + if .Non_Blocking in flags { fdflags += {.NONBLOCK} } // NOTE: rights are adjusted to what this package's functions might want to call. rights: wasi.rights_t @@ -220,7 +221,6 @@ _new_file :: proc(handle: uintptr, name: string, allocator: runtime.Allocator) - data = impl, procedure = _file_stream_proc, } - impl.file.fstat = _fstat return &impl.file, nil } @@ -272,6 +272,10 @@ __fd :: proc(f: ^File) -> wasi.fd_t { return -1 } +_is_tty :: proc "contextless" (f: ^File) -> bool { + return false +} + _name :: proc(f: ^File) -> string { if f != nil && f.impl != nil { return (^File_Impl)(f.impl).name @@ -428,7 +432,7 @@ _exists :: proc(path: string) -> bool { return true } -_file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { +_file_stream_proc :: proc(stream_data: rawptr, mode: File_Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From, allocator: runtime.Allocator) -> (n: i64, err: Error) { f := (^File_Impl)(stream_data) fd := f.fd @@ -556,6 +560,10 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, case .Query: return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Destroy, .Query}) + case .Fstat: + err = file_stream_fstat_utility(f, p, allocator) + return + case: return 0, .Unsupported } diff --git a/core/os/os2/file_windows.odin b/core/os/file_windows.odin similarity index 95% rename from core/os/os2/file_windows.odin rename to core/os/file_windows.odin index 0d2f28642..3a9e90fed 100644 --- a/core/os/os2/file_windows.odin +++ b/core/os/file_windows.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" @@ -126,7 +126,11 @@ _open_internal :: proc(name: string, flags: File_Flags, perm: Permissions) -> (h // NOTE(bill): Open has just asked to create a file in read-only mode. // If the file already exists, to make it akin to a *nix open call, // the call preserves the existing permissions. - h := win32.CreateFileW(path, access, share_mode, &sa, win32.TRUNCATE_EXISTING, win32.FILE_ATTRIBUTE_NORMAL, nil) + nix_attrs := win32.FILE_ATTRIBUTE_NORMAL + if .Non_Blocking in flags { + nix_attrs |= win32.FILE_FLAG_OVERLAPPED + } + h := win32.CreateFileW(path, access, share_mode, &sa, win32.TRUNCATE_EXISTING, nix_attrs, nil) if h == win32.INVALID_HANDLE { switch e := win32.GetLastError(); e { case win32.ERROR_FILE_NOT_FOUND, _ERROR_BAD_NETPATH, win32.ERROR_PATH_NOT_FOUND: @@ -140,6 +144,10 @@ _open_internal :: proc(name: string, flags: File_Flags, perm: Permissions) -> (h } } + if .Non_Blocking in flags { + attrs |= win32.FILE_FLAG_OVERLAPPED + } + h := win32.CreateFileW(path, access, share_mode, &sa, create_mode, attrs, nil) if h == win32.INVALID_HANDLE { return 0, _get_platform_error() @@ -238,6 +246,11 @@ _fd :: proc "contextless" (f: ^File) -> uintptr { return uintptr((^File_Impl)(f.impl).fd) } +_is_tty :: proc "contextless" (f: ^File) -> bool { + fd := _fd(f) + return win32.GetFileType(win32.HANDLE(fd)) == win32.FILE_TYPE_CHAR +} + _destroy :: proc(f: ^File_Impl) -> Error { if f == nil { return nil @@ -364,33 +377,33 @@ _read_internal :: proc(f: ^File_Impl, p: []byte) -> (n: i64, err: Error) { handle := _handle(&f.file) - single_read_length: win32.DWORD total_read: int sync.shared_guard(&f.rw_mutex) // multiple readers if sync.guard(&f.p_mutex) { - to_read := min(win32.DWORD(length), MAX_RW) - ok: win32.BOOL - if f.kind == .Console { - n, cerr := read_console(handle, p[total_read:][:to_read]) - total_read += n - if cerr != nil { - return i64(total_read), cerr + to_read := win32.DWORD(min(length, MAX_RW)) + switch f.kind { + case .Console: + // NOTE(laytan): at least for now, just use ReadFile, it seems to work fine, + // but, there may be issues with certain situations that we need to get reproductions for. + // total_read, err = read_console(handle, p[total_read:][:to_read]) + fallthrough + case .Pipe, .File: + single_read_length: win32.DWORD + ok := win32.ReadFile(handle, &p[total_read], to_read, &single_read_length, nil) + if ok { + total_read += int(single_read_length) + } else { + err = _get_platform_error() } - } else { - ok = win32.ReadFile(handle, &p[total_read], to_read, &single_read_length, nil) } + } - if single_read_length > 0 && ok { - total_read += int(single_read_length) - } else if single_read_length == 0 && ok { - // ok and 0 bytes means EOF: - // https://learn.microsoft.com/en-us/windows/win32/fileio/testing-for-the-end-of-a-file - err = .EOF - } else { - err = _get_platform_error() - } + if total_read == 0 && err == nil { + // ok and 0 bytes means EOF: + // https://learn.microsoft.com/en-us/windows/win32/fileio/testing-for-the-end-of-a-file + err = .EOF } return i64(total_read), err diff --git a/core/os/os2/heap.odin b/core/os/heap.odin similarity index 98% rename from core/os/os2/heap.odin rename to core/os/heap.odin index b1db54dc7..356e60b4d 100644 --- a/core/os/os2/heap.odin +++ b/core/os/heap.odin @@ -1,4 +1,4 @@ -package os2 +package os import "base:runtime" diff --git a/core/os/heap_js.odin b/core/os/heap_js.odin new file mode 100644 index 000000000..ebc8f902d --- /dev/null +++ b/core/os/heap_js.odin @@ -0,0 +1,11 @@ +#+build js wasm32, js wasm64p32 +#+private +package os + +// None of this does anything on js/wasm. +// It's only here so importing `core:os` on wasm panics cleanly, +// without spamming about all sorts of missing procs and types. + +import "base:runtime" + +_heap_allocator_proc :: runtime.wasm_allocator_proc \ No newline at end of file diff --git a/core/os/os2/heap_linux.odin b/core/os/heap_linux.odin similarity index 87% rename from core/os/os2/heap_linux.odin rename to core/os/heap_linux.odin index 1d1f12726..69c2b6edf 100644 --- a/core/os/os2/heap_linux.odin +++ b/core/os/heap_linux.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" diff --git a/core/os/os2/heap_posix.odin b/core/os/heap_posix.odin similarity index 91% rename from core/os/os2/heap_posix.odin rename to core/os/heap_posix.odin index 1b52aed75..5bff96de6 100644 --- a/core/os/os2/heap_posix.odin +++ b/core/os/heap_posix.odin @@ -1,6 +1,6 @@ #+private #+build darwin, netbsd, freebsd, openbsd -package os2 +package os import "base:runtime" diff --git a/core/os/os2/heap_wasi.odin b/core/os/heap_wasi.odin similarity index 87% rename from core/os/os2/heap_wasi.odin rename to core/os/heap_wasi.odin index 7da3c4845..066a43f85 100644 --- a/core/os/os2/heap_wasi.odin +++ b/core/os/heap_wasi.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" diff --git a/core/os/os2/heap_windows.odin b/core/os/heap_windows.odin similarity index 99% rename from core/os/os2/heap_windows.odin rename to core/os/heap_windows.odin index 7fd4529a0..e0e62a91f 100644 --- a/core/os/os2/heap_windows.odin +++ b/core/os/heap_windows.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "core:mem" import win32 "core:sys/windows" diff --git a/core/os/os2/internal_util.odin b/core/os/internal_util.odin similarity index 99% rename from core/os/os2/internal_util.odin rename to core/os/internal_util.odin index 9616af8b0..a279e9bee 100644 --- a/core/os/os2/internal_util.odin +++ b/core/os/internal_util.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:intrinsics" import "base:runtime" diff --git a/core/os/dir_unix.odin b/core/os/old/dir_unix.odin similarity index 98% rename from core/os/dir_unix.odin rename to core/os/old/dir_unix.odin index c3dd844ef..95cc887d6 100644 --- a/core/os/dir_unix.odin +++ b/core/os/old/dir_unix.odin @@ -1,5 +1,5 @@ #+build darwin, linux, netbsd, freebsd, openbsd, haiku -package os +package os_old import "core:strings" diff --git a/core/os/old/dir_windows.odin b/core/os/old/dir_windows.odin new file mode 100644 index 000000000..b81787872 --- /dev/null +++ b/core/os/old/dir_windows.odin @@ -0,0 +1,114 @@ +package os_old + +import win32 "core:sys/windows" +import "core:strings" +import "base:runtime" + +@(require_results) +read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Error) { + @(require_results) + find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW) -> (fi: File_Info) { + // Ignore "." and ".." + if d.cFileName[0] == '.' && d.cFileName[1] == 0 { + return + } + if d.cFileName[0] == '.' && d.cFileName[1] == '.' && d.cFileName[2] == 0 { + return + } + path := strings.concatenate({base_path, `\`, win32.utf16_to_utf8(d.cFileName[:]) or_else ""}) + fi.fullpath = path + fi.name = basename(path) + fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) + + if d.dwFileAttributes & win32.FILE_ATTRIBUTE_READONLY != 0 { + fi.mode |= 0o444 + } else { + fi.mode |= 0o666 + } + + is_sym := false + if d.dwFileAttributes & win32.FILE_ATTRIBUTE_REPARSE_Point == 0 { + is_sym = false + } else { + is_sym = d.dwReserved0 == win32.IO_REPARSE_TAG_SYMLINK || d.dwReserved0 == win32.IO_REPARSE_TAG_MOUNT_POINT + } + + if is_sym { + fi.mode |= File_Mode_Sym_Link + } else { + if d.dwFileAttributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 { + fi.mode |= 0o111 | File_Mode_Dir + } + + // fi.mode |= file_type_mode(h); + } + + windows_set_file_info_times(&fi, d) + + fi.is_dir = fi.mode & File_Mode_Dir != 0 + return + } + + if fd == 0 { + return nil, ERROR_INVALID_HANDLE + } + + context.allocator = allocator + + h := win32.HANDLE(fd) + + dir_fi, _ := file_info_from_get_file_information_by_handle("", h) + if !dir_fi.is_dir { + return nil, .Not_Dir + } + + n := n + size := n + if n <= 0 { + n = -1 + size = 100 + } + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) + + wpath := cleanpath_from_handle_u16(fd, context.temp_allocator) or_return + if len(wpath) == 0 { + return + } + + dfi := make([dynamic]File_Info, 0, size) or_return + + wpath_search := make([]u16, len(wpath)+3, context.temp_allocator) or_return + copy(wpath_search, wpath) + wpath_search[len(wpath)+0] = '\\' + wpath_search[len(wpath)+1] = '*' + wpath_search[len(wpath)+2] = 0 + + path := cleanpath_from_buf(wpath) + defer delete(path) + + find_data := &win32.WIN32_FIND_DATAW{} + find_handle := win32.FindFirstFileW(cstring16(raw_data(wpath_search)), find_data) + if find_handle == win32.INVALID_HANDLE_VALUE { + err = get_last_error() + return dfi[:], err + } + defer win32.FindClose(find_handle) + for n != 0 { + fi: File_Info + fi = find_data_to_file_info(path, find_data) + if fi.name != "" { + append(&dfi, fi) + n -= 1 + } + + if !win32.FindNextFileW(find_handle, find_data) { + e := get_last_error() + if e == ERROR_NO_MORE_FILES { + break + } + return dfi[:], e + } + } + + return dfi[:], nil +} diff --git a/core/os/old/doc.odin b/core/os/old/doc.odin new file mode 100644 index 000000000..525c0b96d --- /dev/null +++ b/core/os/old/doc.odin @@ -0,0 +1,2 @@ +// The original implementation of `core:os`, to be removed in Q2 2026. +package os_old \ No newline at end of file diff --git a/core/os/old/env_windows.odin b/core/os/old/env_windows.odin new file mode 100644 index 000000000..f9480340c --- /dev/null +++ b/core/os/old/env_windows.odin @@ -0,0 +1,140 @@ +package os_old + +import win32 "core:sys/windows" +import "base:runtime" + +// lookup_env gets the value of the environment variable named by the key +// If the variable is found in the environment the value (which can be empty) is returned and the boolean is true +// Otherwise the returned value will be empty and the boolean will be false +// NOTE: the value will be allocated with the supplied allocator +@(require_results) +lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { + if key == "" { + return + } + wkey := win32.utf8_to_wstring(key) + n := win32.GetEnvironmentVariableW(wkey, nil, 0) + if n == 0 && get_last_error() == ERROR_ENVVAR_NOT_FOUND { + return "", false + } + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) + + b, _ := make([dynamic]u16, n, context.temp_allocator) + n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b))) + if n == 0 && get_last_error() == ERROR_ENVVAR_NOT_FOUND { + return "", false + } + value, _ = win32.utf16_to_utf8(b[:n], allocator) + found = true + return +} + +// This version of `lookup_env` doesn't allocate and instead requires the user to provide a buffer. +// Note that it is limited to environment names and values of 512 utf-16 values each +// due to the necessary utf-8 <> utf-16 conversion. +@(require_results) +lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) { + key_buf: [513]u16 + wkey := win32.utf8_to_wstring(key_buf[:], key) + if wkey == nil { + return "", .Buffer_Full + } + + n2 := win32.GetEnvironmentVariableW(wkey, nil, 0) + if n2 == 0 { + return "", .Env_Var_Not_Found + } + + val_buf: [513]u16 + n2 = win32.GetEnvironmentVariableW(wkey, raw_data(val_buf[:]), u32(len(val_buf[:]))) + if n2 == 0 { + return "", .Env_Var_Not_Found + } else if int(n2) > len(buf) { + return "", .Buffer_Full + } + + value = win32.utf16_to_utf8(buf, val_buf[:n2]) + + return value, nil +} +lookup_env :: proc{lookup_env_alloc, lookup_env_buffer} + +// get_env retrieves the value of the environment variable named by the key +// It returns the value, which will be empty if the variable is not present +// To distinguish between an empty value and an unset value, use lookup_env +// NOTE: the value will be allocated with the supplied allocator +@(require_results) +get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) { + value, _ = lookup_env(key, allocator) + return +} + +@(require_results) +get_env_buf :: proc(buf: []u8, key: string) -> (value: string) { + value, _ = lookup_env(buf, key) + return +} +get_env :: proc{get_env_alloc, get_env_buf} + + +// set_env sets the value of the environment variable named by the key +set_env :: proc(key, value: string) -> Error { + k := win32.utf8_to_wstring(key) + v := win32.utf8_to_wstring(value) + + if !win32.SetEnvironmentVariableW(k, v) { + return get_last_error() + } + return nil +} + +// unset_env unsets a single environment variable +unset_env :: proc(key: string) -> Error { + k := win32.utf8_to_wstring(key) + if !win32.SetEnvironmentVariableW(k, nil) { + return get_last_error() + } + return nil +} + +// environ returns a copy of strings representing the environment, in the form "key=value" +// NOTE: the slice of strings and the strings with be allocated using the supplied allocator +@(require_results) +environ :: proc(allocator := context.allocator) -> []string { + envs := ([^]win32.WCHAR)(win32.GetEnvironmentStringsW()) + if envs == nil { + return nil + } + defer win32.FreeEnvironmentStringsW(envs) + + r, err := make([dynamic]string, 0, 50, allocator) + if err != nil { + return nil + } + for from, i := 0, 0; true; i += 1 { + if c := envs[i]; c == 0 { + if i <= from { + break + } + append(&r, win32.utf16_to_utf8(envs[from:i], allocator) or_else "") + from = i + 1 + } + } + + return r[:] +} + + +// clear_env deletes all environment variables +clear_env :: proc() { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + envs := environ(context.temp_allocator) + for env in envs { + for j in 1.. string where intrinsics.type_is_enum(Platform_Error) { + if e == nil { + return "" + } + + when ODIN_OS == .Darwin { + if s := string(_darwin_string_error(i32(e))); s != "" { + return s + } + } + + when ODIN_OS != .Linux { + @(require_results) + binary_search :: proc "contextless" (array: $A/[]$T, key: T) -> (index: int, found: bool) #no_bounds_check { + n := len(array) + left, right := 0, n + for left < right { + mid := int(uint(left+right) >> 1) + if array[mid] < key { + left = mid+1 + } else { + // equal or greater + right = mid + } + } + return left, left < n && array[left] == key + } + + err := runtime.Type_Info_Enum_Value(e) + + ti := &runtime.type_info_base(type_info_of(Platform_Error)).variant.(runtime.Type_Info_Enum) + if idx, ok := binary_search(ti.values, err); ok { + return ti.names[idx] + } + } else { + @(rodata, static) + pe_strings := [Platform_Error]string{ + .NONE = "", + .EPERM = "Operation not permitted", + .ENOENT = "No such file or directory", + .ESRCH = "No such process", + .EINTR = "Interrupted system call", + .EIO = "Input/output error", + .ENXIO = "No such device or address", + .E2BIG = "Argument list too long", + .ENOEXEC = "Exec format error", + .EBADF = "Bad file descriptor", + .ECHILD = "No child processes", + .EAGAIN = "Resource temporarily unavailable", + .ENOMEM = "Cannot allocate memory", + .EACCES = "Permission denied", + .EFAULT = "Bad address", + .ENOTBLK = "Block device required", + .EBUSY = "Device or resource busy", + .EEXIST = "File exists", + .EXDEV = "Invalid cross-device link", + .ENODEV = "No such device", + .ENOTDIR = "Not a directory", + .EISDIR = "Is a directory", + .EINVAL = "Invalid argument", + .ENFILE = "Too many open files in system", + .EMFILE = "Too many open files", + .ENOTTY = "Inappropriate ioctl for device", + .ETXTBSY = "Text file busy", + .EFBIG = "File too large", + .ENOSPC = "No space left on device", + .ESPIPE = "Illegal seek", + .EROFS = "Read-only file system", + .EMLINK = "Too many links", + .EPIPE = "Broken pipe", + .EDOM = "Numerical argument out of domain", + .ERANGE = "Numerical result out of range", + .EDEADLK = "Resource deadlock avoided", + .ENAMETOOLONG = "File name too long", + .ENOLCK = "No locks available", + .ENOSYS = "Function not implemented", + .ENOTEMPTY = "Directory not empty", + .ELOOP = "Too many levels of symbolic links", + .EUNKNOWN_41 = "Unknown Error (41)", + .ENOMSG = "No message of desired type", + .EIDRM = "Identifier removed", + .ECHRNG = "Channel number out of range", + .EL2NSYNC = "Level 2 not synchronized", + .EL3HLT = "Level 3 halted", + .EL3RST = "Level 3 reset", + .ELNRNG = "Link number out of range", + .EUNATCH = "Protocol driver not attached", + .ENOCSI = "No CSI structure available", + .EL2HLT = "Level 2 halted", + .EBADE = "Invalid exchange", + .EBADR = "Invalid request descriptor", + .EXFULL = "Exchange full", + .ENOANO = "No anode", + .EBADRQC = "Invalid request code", + .EBADSLT = "Invalid slot", + .EUNKNOWN_58 = "Unknown Error (58)", + .EBFONT = "Bad font file format", + .ENOSTR = "Device not a stream", + .ENODATA = "No data available", + .ETIME = "Timer expired", + .ENOSR = "Out of streams resources", + .ENONET = "Machine is not on the network", + .ENOPKG = "Package not installed", + .EREMOTE = "Object is remote", + .ENOLINK = "Link has been severed", + .EADV = "Advertise error", + .ESRMNT = "Srmount error", + .ECOMM = "Communication error on send", + .EPROTO = "Protocol error", + .EMULTIHOP = "Multihop attempted", + .EDOTDOT = "RFS specific error", + .EBADMSG = "Bad message", + .EOVERFLOW = "Value too large for defined data type", + .ENOTUNIQ = "Name not unique on network", + .EBADFD = "File descriptor in bad state", + .EREMCHG = "Remote address changed", + .ELIBACC = "Can not access a needed shared library", + .ELIBBAD = "Accessing a corrupted shared library", + .ELIBSCN = ".lib section in a.out corrupted", + .ELIBMAX = "Attempting to link in too many shared libraries", + .ELIBEXEC = "Cannot exec a shared library directly", + .EILSEQ = "Invalid or incomplete multibyte or wide character", + .ERESTART = "Interrupted system call should be restarted", + .ESTRPIPE = "Streams pipe error", + .EUSERS = "Too many users", + .ENOTSOCK = "Socket operation on non-socket", + .EDESTADDRREQ = "Destination address required", + .EMSGSIZE = "Message too long", + .EPROTOTYPE = "Protocol wrong type for socket", + .ENOPROTOOPT = "Protocol not available", + .EPROTONOSUPPORT = "Protocol not supported", + .ESOCKTNOSUPPORT = "Socket type not supported", + .EOPNOTSUPP = "Operation not supported", + .EPFNOSUPPORT = "Protocol family not supported", + .EAFNOSUPPORT = "Address family not supported by protocol", + .EADDRINUSE = "Address already in use", + .EADDRNOTAVAIL = "Cannot assign requested address", + .ENETDOWN = "Network is down", + .ENETUNREACH = "Network is unreachable", + .ENETRESET = "Network dropped connection on reset", + .ECONNABORTED = "Software caused connection abort", + .ECONNRESET = "Connection reset by peer", + .ENOBUFS = "No buffer space available", + .EISCONN = "Transport endpoint is already connected", + .ENOTCONN = "Transport endpoint is not connected", + .ESHUTDOWN = "Cannot send after transport endpoint shutdown", + .ETOOMANYREFS = "Too many references: cannot splice", + .ETIMEDOUT = "Connection timed out", + .ECONNREFUSED = "Connection refused", + .EHOSTDOWN = "Host is down", + .EHOSTUNREACH = "No route to host", + .EALREADY = "Operation already in progress", + .EINPROGRESS = "Operation now in progress", + .ESTALE = "Stale file handle", + .EUCLEAN = "Structure needs cleaning", + .ENOTNAM = "Not a XENIX named type file", + .ENAVAIL = "No XENIX semaphores available", + .EISNAM = "Is a named type file", + .EREMOTEIO = "Remote I/O error", + .EDQUOT = "Disk quota exceeded", + .ENOMEDIUM = "No medium found", + .EMEDIUMTYPE = "Wrong medium type", + .ECANCELED = "Operation canceled", + .ENOKEY = "Required key not available", + .EKEYEXPIRED = "Key has expired", + .EKEYREVOKED = "Key has been revoked", + .EKEYREJECTED = "Key was rejected by service", + .EOWNERDEAD = "Owner died", + .ENOTRECOVERABLE = "State not recoverable", + .ERFKILL = "Operation not possible due to RF-kill", + .EHWPOISON = "Memory page has hardware error", + } + if Platform_Error.NONE <= e && e <= max(Platform_Error) { + return pe_strings[e] + } + } + return "" +} + +@(private, require_results) +error_to_io_error :: proc(ferr: Error) -> io.Error { + if ferr == nil { + return .None + } + return ferr.(io.Error) or_else .Unknown +} diff --git a/core/os/os.odin b/core/os/old/os.odin similarity index 99% rename from core/os/os.odin rename to core/os/old/os.odin index da7b0c151..01e93126d 100644 --- a/core/os/os.odin +++ b/core/os/old/os.odin @@ -1,5 +1,5 @@ // Cross-platform `OS` interactions like file `I/O`. -package os +package os_old import "base:intrinsics" import "base:runtime" diff --git a/core/os/os_darwin.odin b/core/os/old/os_darwin.odin similarity index 99% rename from core/os/os_darwin.odin rename to core/os/old/os_darwin.odin index 77b5825dd..6a6efe4e2 100644 --- a/core/os/os_darwin.odin +++ b/core/os/old/os_darwin.odin @@ -1,4 +1,4 @@ -package os +package os_old foreign import dl "system:dl" foreign import libc "system:System" @@ -598,7 +598,7 @@ foreign libc { @(link_name="fstat64") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int --- @(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t --- @(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int --- - @(link_name="fsync") _unix_fsync :: proc(handle: Handle) -> c.int --- + @(link_name="fsync") _unix_fsync :: proc(handle: Handle) -> c.int --- @(link_name="dup") _unix_dup :: proc(handle: Handle) -> Handle --- @(link_name="fdopendir$INODE64") _unix_fdopendir_amd64 :: proc(fd: Handle) -> Dir --- @@ -1072,6 +1072,7 @@ lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) return "", .Buffer_Full } else { copy(buf, key) + buf[len(key)] = 0 } if value = string(_unix_getenv(cstring(raw_data(buf)))); value == "" { diff --git a/core/os/os_essence.odin b/core/os/old/os_essence.odin similarity index 98% rename from core/os/os_essence.odin rename to core/os/old/os_essence.odin index 75c4c1156..8156bb496 100644 --- a/core/os/os_essence.odin +++ b/core/os/old/os_essence.odin @@ -1,4 +1,4 @@ -package os +package os_old import "core:sys/es" diff --git a/core/os/os_freebsd.odin b/core/os/old/os_freebsd.odin similarity index 99% rename from core/os/os_freebsd.odin rename to core/os/old/os_freebsd.odin index 0542e10dc..a1ecf2aff 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/old/os_freebsd.odin @@ -1,4 +1,4 @@ -package os +package os_old foreign import dl "system:dl" foreign import libc "system:c" @@ -844,6 +844,7 @@ lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) return "", .Buffer_Full } else { copy(buf, key) + buf[len(key)] = 0 } if value = string(_unix_getenv(cstring(raw_data(buf)))); value == "" { diff --git a/core/os/old/os_freestanding.odin b/core/os/old/os_freestanding.odin new file mode 100644 index 000000000..def000aae --- /dev/null +++ b/core/os/old/os_freestanding.odin @@ -0,0 +1,4 @@ +#+build freestanding +package os_old + +#panic("package os_old does not support a freestanding target") diff --git a/core/os/os_haiku.odin b/core/os/old/os_haiku.odin similarity index 99% rename from core/os/os_haiku.odin rename to core/os/old/os_haiku.odin index e7c71338b..a85f2d5c1 100644 --- a/core/os/os_haiku.odin +++ b/core/os/old/os_haiku.odin @@ -1,4 +1,4 @@ -package os +package os_old foreign import lib "system:c" @@ -487,6 +487,7 @@ lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) return "", .Buffer_Full } else { copy(buf, key) + buf[len(key)] = 0 } if value = string(_unix_getenv(cstring(raw_data(buf)))); value == "" { diff --git a/core/os/os_js.odin b/core/os/old/os_js.odin similarity index 99% rename from core/os/os_js.odin rename to core/os/old/os_js.odin index 1870218d3..cefabbf4d 100644 --- a/core/os/os_js.odin +++ b/core/os/old/os_js.odin @@ -1,5 +1,5 @@ #+build js -package os +package os_old foreign import "odin_env" diff --git a/core/os/os_linux.odin b/core/os/old/os_linux.odin similarity index 98% rename from core/os/os_linux.odin rename to core/os/old/os_linux.odin index f0f9b401c..504f6f5b3 100644 --- a/core/os/os_linux.odin +++ b/core/os/old/os_linux.odin @@ -1,4 +1,4 @@ -package os +package os_old foreign import dl "system:dl" foreign import libc "system:c" @@ -7,19 +7,8 @@ import "base:runtime" import "core:strings" import "core:c" import "core:strconv" - -// NOTE(flysand): For compatibility we'll make core:os package -// depend on the old (scheduled for removal) linux package. -// Seeing that there are plans for os2, I'm imagining that *that* -// package should inherit the new sys functionality. -// The reasons for these are as follows: -// 1. It's very hard to update this package without breaking *a lot* of code. -// 2. os2 is not stable anyways, so we can break compatibility all we want -// It might be weird to bring up compatibility when Odin in it's nature isn't -// all that about compatibility. But we don't want to push experimental changes -// and have people's code break while it's still work in progress. -import unix "core:sys/unix" -import linux "core:sys/linux" +import "core:sys/unix" +import "core:sys/linux" Handle :: distinct i32 Pid :: distinct i32 @@ -963,6 +952,7 @@ lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) return "", .Buffer_Full } else { copy(buf, key) + buf[len(key)] = 0 } if value = string(_unix_getenv(cstring(raw_data(buf)))); value == "" { diff --git a/core/os/os_netbsd.odin b/core/os/old/os_netbsd.odin similarity index 99% rename from core/os/os_netbsd.odin rename to core/os/old/os_netbsd.odin index 30511012f..601e42199 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/old/os_netbsd.odin @@ -1,4 +1,4 @@ -package os +package os_old foreign import dl "system:dl" foreign import libc "system:c" @@ -891,6 +891,7 @@ lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) return "", .Buffer_Full } else { copy(buf, key) + buf[len(key)] = 0 } if value = string(_unix_getenv(cstring(raw_data(buf)))); value == "" { diff --git a/core/os/os_openbsd.odin b/core/os/old/os_openbsd.odin similarity index 99% rename from core/os/os_openbsd.odin rename to core/os/old/os_openbsd.odin index 50ee37dff..95d431134 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/old/os_openbsd.odin @@ -1,4 +1,4 @@ -package os +package os_old foreign import libc "system:c" @@ -804,6 +804,7 @@ lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) return "", .Buffer_Full } else { copy(buf, key) + buf[len(key)] = 0 } if value = string(_unix_getenv(cstring(raw_data(buf)))); value == "" { diff --git a/core/os/os_wasi.odin b/core/os/old/os_wasi.odin similarity index 99% rename from core/os/os_wasi.odin rename to core/os/old/os_wasi.odin index fe0a1fb3e..287034957 100644 --- a/core/os/os_wasi.odin +++ b/core/os/old/os_wasi.odin @@ -1,4 +1,4 @@ -package os +package os_old import "core:sys/wasm/wasi" import "base:runtime" diff --git a/core/os/os_windows.odin b/core/os/old/os_windows.odin similarity index 99% rename from core/os/os_windows.odin rename to core/os/old/os_windows.odin index 03c194596..8081d9726 100644 --- a/core/os/os_windows.odin +++ b/core/os/old/os_windows.odin @@ -1,5 +1,5 @@ #+build windows -package os +package os_old import win32 "core:sys/windows" import "base:runtime" @@ -333,8 +333,14 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Erro case: create_mode = win32.OPEN_EXISTING } + + attrs := win32.FILE_ATTRIBUTE_NORMAL|win32.FILE_FLAG_BACKUP_SEMANTICS + if mode & (O_NONBLOCK) == O_NONBLOCK { + attrs |= win32.FILE_FLAG_OVERLAPPED + } + wide_path := win32.utf8_to_wstring(path) - handle := Handle(win32.CreateFileW(wide_path, access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL|win32.FILE_FLAG_BACKUP_SEMANTICS, nil)) + handle := Handle(win32.CreateFileW(wide_path, access, share_mode, sa, create_mode, attrs, nil)) if handle != INVALID_HANDLE { return handle, nil } @@ -862,4 +868,4 @@ pipe :: proc() -> (r, w: Handle, err: Error) { err = get_last_error() } return -} \ No newline at end of file +} diff --git a/core/os/old/stat.odin b/core/os/old/stat.odin new file mode 100644 index 000000000..fad8ff755 --- /dev/null +++ b/core/os/old/stat.odin @@ -0,0 +1,33 @@ +package os_old + +import "core:time" + +File_Info :: struct { + fullpath: string, // allocated + name: string, // uses `fullpath` as underlying data + size: i64, + mode: File_Mode, + is_dir: bool, + creation_time: time.Time, + modification_time: time.Time, + access_time: time.Time, +} + +file_info_slice_delete :: proc(infos: []File_Info, allocator := context.allocator) { + for i := len(infos)-1; i >= 0; i -= 1 { + file_info_delete(infos[i], allocator) + } + delete(infos, allocator) +} + +file_info_delete :: proc(fi: File_Info, allocator := context.allocator) { + delete(fi.fullpath, allocator) +} + +File_Mode :: distinct u32 + +File_Mode_Dir :: File_Mode(1<<16) +File_Mode_Named_Pipe :: File_Mode(1<<17) +File_Mode_Device :: File_Mode(1<<18) +File_Mode_Char_Device :: File_Mode(1<<19) +File_Mode_Sym_Link :: File_Mode(1<<20) diff --git a/core/os/stat_unix.odin b/core/os/old/stat_unix.odin similarity index 99% rename from core/os/stat_unix.odin rename to core/os/old/stat_unix.odin index 648987a07..0f7be62e2 100644 --- a/core/os/stat_unix.odin +++ b/core/os/old/stat_unix.odin @@ -1,5 +1,5 @@ #+build linux, darwin, freebsd, openbsd, netbsd, haiku -package os +package os_old import "core:time" diff --git a/core/os/old/stat_windows.odin b/core/os/old/stat_windows.odin new file mode 100644 index 000000000..34e5e1695 --- /dev/null +++ b/core/os/old/stat_windows.odin @@ -0,0 +1,303 @@ +package os_old + +import "core:time" +import "base:runtime" +import win32 "core:sys/windows" + +@(private, require_results) +full_path_from_name :: proc(name: string, allocator := context.allocator) -> (path: string, err: Errno) { + context.allocator = allocator + + name := name + if name == "" { + name = "." + } + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) + p := win32.utf8_to_utf16(name, context.temp_allocator) + buf := make([dynamic]u16, 100) + defer delete(buf) + for { + n := win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil) + if n == 0 { + return "", get_last_error() + } + if n <= u32(len(buf)) { + return win32.utf16_to_utf8(buf[:n], allocator) or_else "", nil + } + resize(&buf, len(buf)*2) + } + + return +} + +@(private, require_results) +_stat :: proc(name: string, create_file_attributes: u32, allocator := context.allocator) -> (fi: File_Info, e: Errno) { + if len(name) == 0 { + return {}, ERROR_PATH_NOT_FOUND + } + + context.allocator = allocator + + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) + + wname := win32.utf8_to_wstring(fix_long_path(name), context.temp_allocator) + fa: win32.WIN32_FILE_ATTRIBUTE_DATA + ok := win32.GetFileAttributesExW(wname, win32.GetFileExInfoStandard, &fa) + if ok && fa.dwFileAttributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 { + // Not a symlink + return file_info_from_win32_file_attribute_data(&fa, name) + } + + err := 0 if ok else win32.GetLastError() + + if err == win32.ERROR_SHARING_VIOLATION { + fd: win32.WIN32_FIND_DATAW + sh := win32.FindFirstFileW(wname, &fd) + if sh == win32.INVALID_HANDLE_VALUE { + e = get_last_error() + return + } + win32.FindClose(sh) + + return file_info_from_win32_find_data(&fd, name) + } + + h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil) + if h == win32.INVALID_HANDLE_VALUE { + e = get_last_error() + return + } + defer win32.CloseHandle(h) + return file_info_from_get_file_information_by_handle(name, h) +} + + +@(require_results) +lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Errno) { + attrs := win32.FILE_FLAG_BACKUP_SEMANTICS + attrs |= win32.FILE_FLAG_OPEN_REPARSE_POINT + return _stat(name, attrs, allocator) +} + +@(require_results) +stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Errno) { + attrs := win32.FILE_FLAG_BACKUP_SEMANTICS + return _stat(name, attrs, allocator) +} + +@(require_results) +fstat :: proc(fd: Handle, allocator := context.allocator) -> (fi: File_Info, err: Errno) { + if fd == 0 { + err = ERROR_INVALID_HANDLE + } + context.allocator = allocator + + path := cleanpath_from_handle(fd) or_return + defer if err != nil { + delete(path) + } + + h := win32.HANDLE(fd) + switch win32.GetFileType(h) { + case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR: + fi.name = basename(path) + fi.mode |= file_type_mode(h) + err = nil + case: + fi = file_info_from_get_file_information_by_handle(path, h) or_return + } + fi.fullpath = path + return +} + + +@(private, require_results) +cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 { + buf := buf + N := 0 + for c, i in buf { + if c == 0 { break } + N = i+1 + } + buf = buf[:N] + + if len(buf) >= 4 && buf[0] == '\\' && buf[1] == '\\' && buf[2] == '?' && buf[3] == '\\' { + buf = buf[4:] + + /* + NOTE(Jeroen): Properly handle UNC paths. + We need to turn `\\?\UNC\synology.local` into `\\synology.local`. + */ + if len(buf) >= 3 && buf[0] == 'U' && buf[1] == 'N' && buf[2] == 'C' { + buf = buf[2:] + buf[0] = '\\' + } + } + return buf +} + +@(private, require_results) +cleanpath_from_handle :: proc(fd: Handle) -> (s: string, err: Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) + buf := cleanpath_from_handle_u16(fd, context.temp_allocator) or_return + return win32.utf16_to_utf8(buf, context.allocator) +} +@(private, require_results) +cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> ([]u16, Errno) { + if fd == 0 { + return nil, ERROR_INVALID_HANDLE + } + h := win32.HANDLE(fd) + + n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0) + if n == 0 { + return nil, get_last_error() + } + buf := make([]u16, max(n, win32.DWORD(260))+1, allocator) + buf_len := win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), n, 0) + return buf[:buf_len], nil +} +@(private, require_results) +cleanpath_from_buf :: proc(buf: []u16) -> string { + buf := buf + buf = cleanpath_strip_prefix(buf) + return win32.utf16_to_utf8(buf, context.allocator) or_else "" +} + +@(private, require_results) +basename :: proc(name: string) -> (base: string) { + name := name + if len(name) > 3 && name[:3] == `\\?` { + name = name[3:] + } + + if len(name) == 2 && name[1] == ':' { + return "." + } else if len(name) > 2 && name[1] == ':' { + name = name[2:] + } + i := len(name)-1 + + for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i -= 1 { + name = name[:i] + } + for i -= 1; i >= 0; i -= 1 { + if name[i] == '/' || name[i] == '\\' { + name = name[i+1:] + break + } + } + return name +} + +@(private, require_results) +file_type_mode :: proc(h: win32.HANDLE) -> File_Mode { + switch win32.GetFileType(h) { + case win32.FILE_TYPE_PIPE: + return File_Mode_Named_Pipe + case win32.FILE_TYPE_CHAR: + return File_Mode_Device | File_Mode_Char_Device + } + return 0 +} + + +@(private, require_results) +file_mode_from_file_attributes :: proc(FileAttributes: win32.DWORD, h: win32.HANDLE, ReparseTag: win32.DWORD) -> (mode: File_Mode) { + if FileAttributes & win32.FILE_ATTRIBUTE_READONLY != 0 { + mode |= 0o444 + } else { + mode |= 0o666 + } + + is_sym := false + if FileAttributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 { + is_sym = false + } else { + is_sym = ReparseTag == win32.IO_REPARSE_TAG_SYMLINK || ReparseTag == win32.IO_REPARSE_TAG_MOUNT_POINT + } + + if is_sym { + mode |= File_Mode_Sym_Link + } else { + if FileAttributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 { + mode |= 0o111 | File_Mode_Dir + } + + if h != nil { + mode |= file_type_mode(h) + } + } + + return +} + +@(private) +windows_set_file_info_times :: proc(fi: ^File_Info, d: ^$T) { + fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime)) + fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime)) + fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime)) +} + +@(private, require_results) +file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string) -> (fi: File_Info, e: Errno) { + fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) + + fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0) + fi.is_dir = fi.mode & File_Mode_Dir != 0 + + windows_set_file_info_times(&fi, d) + + fi.fullpath, e = full_path_from_name(name) + fi.name = basename(fi.fullpath) + + return +} + +@(private, require_results) +file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string) -> (fi: File_Info, e: Errno) { + fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) + + fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0) + fi.is_dir = fi.mode & File_Mode_Dir != 0 + + windows_set_file_info_times(&fi, d) + + fi.fullpath, e = full_path_from_name(name) + fi.name = basename(fi.fullpath) + + return +} + +@(private, require_results) +file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE) -> (File_Info, Errno) { + d: win32.BY_HANDLE_FILE_INFORMATION + if !win32.GetFileInformationByHandle(h, &d) { + err := get_last_error() + return {}, err + + } + + ti: win32.FILE_ATTRIBUTE_TAG_INFO + if !win32.GetFileInformationByHandleEx(h, .FileAttributeTagInfo, &ti, size_of(ti)) { + err := get_last_error() + if err != ERROR_INVALID_PARAMETER { + return {}, err + } + // Indicate this is a symlink on FAT file systems + ti.ReparseTag = 0 + } + + fi: File_Info + + fi.fullpath = path + fi.name = basename(path) + fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) + + fi.mode |= file_mode_from_file_attributes(ti.FileAttributes, h, ti.ReparseTag) + fi.is_dir = fi.mode & File_Mode_Dir != 0 + + windows_set_file_info_times(&fi, &d) + + return fi, nil +} diff --git a/core/os/stream.odin b/core/os/old/stream.odin similarity index 98% rename from core/os/stream.odin rename to core/os/old/stream.odin index f4e9bcdde..d94505505 100644 --- a/core/os/stream.odin +++ b/core/os/old/stream.odin @@ -1,4 +1,4 @@ -package os +package os_old import "core:io" diff --git a/core/os/os2/dir_windows.odin b/core/os/os2/dir_windows.odin deleted file mode 100644 index a4dadca75..000000000 --- a/core/os/os2/dir_windows.odin +++ /dev/null @@ -1,144 +0,0 @@ -#+private -package os2 - -import "base:runtime" -import "core:time" -import win32 "core:sys/windows" - -@(private="file") -find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) { - // Ignore "." and ".." - if d.cFileName[0] == '.' && d.cFileName[1] == 0 { - return - } - if d.cFileName[0] == '.' && d.cFileName[1] == '.' && d.cFileName[2] == 0 { - return - } - - temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - path := concatenate({base_path, `\`, win32_wstring_to_utf8(cstring16(raw_data(d.cFileName[:])), temp_allocator) or_else ""}, allocator) or_return - - handle := win32.HANDLE(_open_internal(path, {.Read}, Permissions_Read_Write_All) or_else 0) - defer win32.CloseHandle(handle) - - fi.fullpath = path - fi.name = basename(path) - fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) - - fi.type, fi.mode = _file_type_mode_from_file_attributes(d.dwFileAttributes, handle, d.dwReserved0) - - fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime)) - fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime)) - fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime)) - - if file_id_info: win32.FILE_ID_INFO; handle != nil && win32.GetFileInformationByHandleEx(handle, .FileIdInfo, &file_id_info, size_of(file_id_info)) { - #assert(size_of(fi.inode) == size_of(file_id_info.FileId)) - #assert(size_of(fi.inode) == 16) - runtime.mem_copy_non_overlapping(&fi.inode, &file_id_info.FileId, 16) - } - - return -} - -Read_Directory_Iterator_Impl :: struct { - find_data: win32.WIN32_FIND_DATAW, - find_handle: win32.HANDLE, - path: string, - prev_fi: File_Info, - no_more_files: bool, -} - - -@(require_results) -_read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info, index: int, ok: bool) { - for !it.impl.no_more_files { - err: Error - file_info_delete(it.impl.prev_fi, file_allocator()) - it.impl.prev_fi = {} - - fi, err = find_data_to_file_info(it.impl.path, &it.impl.find_data, file_allocator()) - if err != nil { - read_directory_iterator_set_error(it, it.impl.path, err) - return - } - - if fi.name != "" { - it.impl.prev_fi = fi - ok = true - index = it.index - it.index += 1 - } - - if !win32.FindNextFileW(it.impl.find_handle, &it.impl.find_data) { - e := _get_platform_error() - if pe, _ := is_platform_error(e); pe != i32(win32.ERROR_NO_MORE_FILES) { - read_directory_iterator_set_error(it, it.impl.path, e) - } - it.impl.no_more_files = true - } - if ok { - return - } - } - return -} - -_read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) { - it.impl.no_more_files = false - - if f == nil || f.impl == nil { - read_directory_iterator_set_error(it, "", .Invalid_File) - return - } - - it.f = f - impl := (^File_Impl)(f.impl) - - // NOTE: Allow calling `init` to target a new directory with the same iterator - reset idx. - if it.impl.find_handle != nil { - win32.FindClose(it.impl.find_handle) - } - if it.impl.path != "" { - delete(it.impl.path, file_allocator()) - } - - if !is_directory(impl.name) { - read_directory_iterator_set_error(it, impl.name, .Invalid_Dir) - return - } - - wpath := string16(impl.wname) - temp_allocator := TEMP_ALLOCATOR_GUARD({}) - - wpath_search := make([]u16, len(wpath)+3, temp_allocator) - copy(wpath_search, wpath) - wpath_search[len(wpath)+0] = '\\' - wpath_search[len(wpath)+1] = '*' - wpath_search[len(wpath)+2] = 0 - - it.impl.find_handle = win32.FindFirstFileW(cstring16(raw_data(wpath_search)), &it.impl.find_data) - if it.impl.find_handle == win32.INVALID_HANDLE_VALUE { - read_directory_iterator_set_error(it, impl.name, _get_platform_error()) - return - } - defer if it.err.err != nil { - win32.FindClose(it.impl.find_handle) - } - - err: Error - it.impl.path, err = _cleanpath_from_buf(wpath, file_allocator()) - if err != nil { - read_directory_iterator_set_error(it, impl.name, err) - } - - return -} - -_read_directory_iterator_destroy :: proc(it: ^Read_Directory_Iterator) { - if it.f == nil { - return - } - file_info_delete(it.impl.prev_fi, file_allocator()) - delete(it.impl.path, file_allocator()) - win32.FindClose(it.impl.find_handle) -} diff --git a/core/os/os2/doc.odin b/core/os/os2/doc.odin deleted file mode 100644 index 86dcbc452..000000000 --- a/core/os/os2/doc.odin +++ /dev/null @@ -1,11 +0,0 @@ -// Package os provides a platform-independent interface to operating system functionality. -// The design is UNIX-like but with Odin-like error handling. Failing calls return values with a specific error type rather than error number. -// -// The package os interface is intended to be uniform across all operating systems. -// Features not generally available appear in the system-specific packages under core:sys/*. -// -// -// IMPORTANT NOTE from Bill: This package is not fully complete yet but should give designers a better idea of the general -// interface and how to write things. This entire interface is subject to change, but mostly working still. -// When things are finalized, this message will be removed. -package os2 diff --git a/core/os/os2/env_windows.odin b/core/os/os2/env_windows.odin deleted file mode 100644 index d389f8860..000000000 --- a/core/os/os2/env_windows.odin +++ /dev/null @@ -1,142 +0,0 @@ -#+private -package os2 - -import win32 "core:sys/windows" -import "base:runtime" - -_lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { - if key == "" { - return - } - temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - wkey, _ := win32_utf8_to_wstring(key, temp_allocator) - - n := win32.GetEnvironmentVariableW(wkey, nil, 0) - if n == 0 { - err := win32.GetLastError() - if err == win32.ERROR_ENVVAR_NOT_FOUND { - return "", false - } - return "", true - } - - b := make([]u16, n+1, temp_allocator) - - n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b))) - if n == 0 { - err := win32.GetLastError() - if err == win32.ERROR_ENVVAR_NOT_FOUND { - return "", false - } - return "", false - } - - value = win32_utf16_to_utf8(string16(b[:n]), allocator) or_else "" - found = true - return -} - -// This version of `lookup_env` doesn't allocate and instead requires the user to provide a buffer. -// Note that it is limited to environment names and values of 512 utf-16 values each -// due to the necessary utf-8 <> utf-16 conversion. -@(require_results) -_lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, err: Error) { - key_buf: [513]u16 - wkey := win32.utf8_to_wstring(key_buf[:], key) - if wkey == nil { - return "", .Buffer_Full - } - - n2 := win32.GetEnvironmentVariableW(wkey, nil, 0) - if n2 == 0 { - return "", .Env_Var_Not_Found - } - - val_buf: [513]u16 - n2 = win32.GetEnvironmentVariableW(wkey, raw_data(val_buf[:]), u32(len(val_buf[:]))) - if n2 == 0 { - return "", .Env_Var_Not_Found - } else if int(n2) > len(buf) { - return "", .Buffer_Full - } - - value = win32.utf16_to_utf8(buf, val_buf[:n2]) - - return value, nil -} -_lookup_env :: proc{_lookup_env_alloc, _lookup_env_buf} - -_set_env :: proc(key, value: string) -> Error { - temp_allocator := TEMP_ALLOCATOR_GUARD({}) - k := win32_utf8_to_wstring(key, temp_allocator) or_return - v := win32_utf8_to_wstring(value, temp_allocator) or_return - - if !win32.SetEnvironmentVariableW(k, v) { - return _get_platform_error() - } - return nil -} - -_unset_env :: proc(key: string) -> bool { - temp_allocator := TEMP_ALLOCATOR_GUARD({}) - k, _ := win32_utf8_to_wstring(key, temp_allocator) - return bool(win32.SetEnvironmentVariableW(k, nil)) -} - -_clear_env :: proc() { - temp_allocator := TEMP_ALLOCATOR_GUARD({}) - envs, _ := environ(temp_allocator) - for env in envs { - for j in 1.. io.Error { - if ferr == nil { - return .None - } - return ferr.(io.Error) or_else .Unknown -} diff --git a/core/os/os2/stat.odin b/core/os/os2/stat.odin deleted file mode 100644 index 58df45754..000000000 --- a/core/os/os2/stat.odin +++ /dev/null @@ -1,113 +0,0 @@ -package os2 - -import "base:runtime" -import "core:strings" -import "core:time" - -Fstat_Callback :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error) - -/* - `File_Info` describes a file and is returned from `stat`, `fstat`, and `lstat`. -*/ -File_Info :: struct { - fullpath: string, // fullpath of the file - name: string, // base name of the file - - inode: u128, // might be zero if cannot be determined - size: i64 `fmt:"M"`, // length in bytes for regular files; system-dependent for other file types - mode: Permissions, // file permission flags - type: File_Type, - - creation_time: time.Time, - modification_time: time.Time, - access_time: time.Time, -} - -@(require_results) -file_info_clone :: proc(fi: File_Info, allocator: runtime.Allocator) -> (cloned: File_Info, err: runtime.Allocator_Error) { - cloned = fi - cloned.fullpath = strings.clone(fi.fullpath, allocator) or_return - _, cloned.name = split_path(cloned.fullpath) - return -} - -file_info_slice_delete :: proc(infos: []File_Info, allocator: runtime.Allocator) { - #reverse for info in infos { - file_info_delete(info, allocator) - } - delete(infos, allocator) -} - -file_info_delete :: proc(fi: File_Info, allocator: runtime.Allocator) { - delete(fi.fullpath, allocator) -} - -@(require_results) -fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error) { - if f == nil { - return {}, nil - } else if f.stream.procedure != nil { - fi: File_Info - data := ([^]byte)(&fi)[:size_of(fi)] - _, err := f.stream.procedure(f, .Fstat, data, 0, nil, allocator) - return fi, err - } - return {}, .Invalid_Callback -} - -/* - `stat` returns a `File_Info` describing the named file from the file system. - The resulting `File_Info` must be deleted with `file_info_delete`. -*/ -@(require_results) -stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) { - return _stat(name, allocator) -} - -lstat :: stat_do_not_follow_links - -/* - Returns a `File_Info` describing the named file from the file system. - If the file is a symbolic link, the `File_Info` returns describes the symbolic link, - rather than following the link. - The resulting `File_Info` must be deleted with `file_info_delete`. -*/ -@(require_results) -stat_do_not_follow_links :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) { - return _lstat(name, allocator) -} - - -/* - Returns true if two `File_Info`s are equivalent. -*/ -@(require_results) -same_file :: proc(fi1, fi2: File_Info) -> bool { - return _same_file(fi1, fi2) -} - - -last_write_time :: modification_time -last_write_time_by_name :: modification_time_by_path - -/* - Returns the modification time of the file `f`. - The resolution of the timestamp is system-dependent. -*/ -@(require_results) -modification_time :: proc(f: ^File) -> (time.Time, Error) { - temp_allocator := TEMP_ALLOCATOR_GUARD({}) - fi, err := fstat(f, temp_allocator) - return fi.modification_time, err -} - -/* - Returns the modification time of the named file `path`. - The resolution of the timestamp is system-dependent. -*/ -@(require_results) -modification_time_by_path :: proc(path: string) -> (time.Time, Error) { - temp_allocator := TEMP_ALLOCATOR_GUARD({}) - fi, err := stat(path, temp_allocator) - return fi.modification_time, err -} diff --git a/core/os/os2/stat_windows.odin b/core/os/os2/stat_windows.odin deleted file mode 100644 index 651029ac3..000000000 --- a/core/os/os2/stat_windows.odin +++ /dev/null @@ -1,393 +0,0 @@ -#+private -package os2 - -import "base:runtime" -import "core:time" -import "core:strings" -import win32 "core:sys/windows" - -_fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) { - if f == nil || (^File_Impl)(f.impl).fd == nil { - return - } - - path := _cleanpath_from_handle(f, allocator) or_return - - h := _handle(f) - switch win32.GetFileType(h) { - case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR: - fi = File_Info { - fullpath = path, - name = basename(path), - type = file_type(h), - } - return - } - - return _file_info_from_get_file_information_by_handle(path, h, allocator) -} - -_stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) { - return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS, allocator) -} - -_lstat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) { - return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS|win32.FILE_FLAG_OPEN_REPARSE_POINT, allocator) -} - -_same_file :: proc(fi1, fi2: File_Info) -> bool { - return fi1.fullpath == fi2.fullpath -} - -full_path_from_name :: proc(name: string, allocator: runtime.Allocator) -> (path: string, err: Error) { - name := name - if name == "" { - name = "." - } - - temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - - p := win32_utf8_to_utf16(name, temp_allocator) or_return - - n := win32.GetFullPathNameW(cstring16(raw_data(p)), 0, nil, nil) - if n == 0 { - return "", _get_platform_error() - } - buf := make([]u16, n+1, temp_allocator) - n = win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil) - if n == 0 { - return "", _get_platform_error() - } - return win32_utf16_to_utf8(buf[:n], allocator) -} - -internal_stat :: proc(name: string, create_file_attributes: u32, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) { - if len(name) == 0 { - return {}, .Not_Exist - } - temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - - wname := _fix_long_path(name, temp_allocator) or_return - fa: win32.WIN32_FILE_ATTRIBUTE_DATA - ok := win32.GetFileAttributesExW(wname, win32.GetFileExInfoStandard, &fa) - if ok && fa.dwFileAttributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 { - // Not a symlink - fi = _file_info_from_win32_file_attribute_data(&fa, name, allocator) or_return - if fi.type == .Undetermined { - fi.type = _file_type_from_create_file(wname, create_file_attributes) - } - return - } - - err := 0 if ok else win32.GetLastError() - - if err == win32.ERROR_SHARING_VIOLATION { - fd: win32.WIN32_FIND_DATAW - sh := win32.FindFirstFileW(wname, &fd) - if sh == win32.INVALID_HANDLE_VALUE { - e = _get_platform_error() - return - } - win32.FindClose(sh) - - fi = _file_info_from_win32_find_data(&fd, name, allocator) or_return - if fi.type == .Undetermined { - fi.type = _file_type_from_create_file(wname, create_file_attributes) - } - return - } - - h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil) - if h == win32.INVALID_HANDLE_VALUE { - e = _get_platform_error() - return - } - defer win32.CloseHandle(h) - return _file_info_from_get_file_information_by_handle(name, h, allocator) -} - -_cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 { - buf := buf - N := 0 - for c, i in buf { - if c == 0 { break } - N = i+1 - } - buf = buf[:N] - - if len(buf) >= 4 { - if buf[0] == '\\' && - buf[1] == '\\' && - buf[2] == '?' && - buf[3] == '\\' { - buf = buf[4:] - } - } - return buf -} - -_cleanpath_from_handle :: proc(f: ^File, allocator: runtime.Allocator) -> (string, Error) { - if f == nil { - return "", nil - } - h := _handle(f) - - n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0) - if n == 0 { - return "", _get_platform_error() - } - - temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - - buf := make([]u16, max(n, 260)+1, temp_allocator) - n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0) - return _cleanpath_from_buf(string16(buf[:n]), allocator) -} - -_cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) { - if f == nil { - return nil, nil - } - h := _handle(f) - - n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0) - if n == 0 { - return nil, _get_platform_error() - } - - temp_allocator := TEMP_ALLOCATOR_GUARD({}) - - buf := make([]u16, max(n, 260)+1, temp_allocator) - n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0) - return _cleanpath_strip_prefix(buf[:n]), nil -} - -_cleanpath_from_buf :: proc(buf: string16, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { - buf := transmute([]u16)buf - buf = _cleanpath_strip_prefix(buf) - return win32_utf16_to_utf8(buf, allocator) -} - -basename :: proc(name: string) -> (base: string) { - name := name - if len(name) > 3 && name[:3] == `\\?` { - name = name[3:] - } - - if len(name) == 2 && name[1] == ':' { - return "." - } else if len(name) > 2 && name[1] == ':' { - name = name[2:] - } - i := len(name)-1 - - for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i -= 1 { - name = name[:i] - } - for i -= 1; i >= 0; i -= 1 { - if name[i] == '/' || name[i] == '\\' { - name = name[i+1:] - break - } - } - return name -} - -file_type :: proc(h: win32.HANDLE) -> File_Type { - switch win32.GetFileType(h) { - case win32.FILE_TYPE_PIPE: return .Named_Pipe - case win32.FILE_TYPE_CHAR: return .Character_Device - case win32.FILE_TYPE_DISK: return .Regular - } - return .Undetermined -} - -_file_type_from_create_file :: proc(wname: win32.wstring, create_file_attributes: u32) -> File_Type { - h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil) - if h == win32.INVALID_HANDLE_VALUE { - return .Undetermined - } - defer win32.CloseHandle(h) - return file_type(h) -} - -_file_type_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: win32.HANDLE, ReparseTag: win32.DWORD) -> (type: File_Type, mode: Permissions) { - if file_attributes & win32.FILE_ATTRIBUTE_READONLY != 0 { - mode += Permissions_Write_All - } else { - mode += Permissions_Read_Write_All - } - - is_sym := false - if file_attributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 { - is_sym = false - } else { - is_sym = ReparseTag == win32.IO_REPARSE_TAG_SYMLINK || ReparseTag == win32.IO_REPARSE_TAG_MOUNT_POINT - } - - if is_sym { - type = .Symlink - } else if file_attributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 { - type = .Directory - mode += Permissions_Execute_All - } else if h != nil { - type = file_type(h) - } - return -} - -// a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC) -time_as_filetime :: #force_inline proc(t: time.Time) -> (ft: win32.LARGE_INTEGER) { - win := u64(t._nsec / 100) + 116444736000000000 - return win32.LARGE_INTEGER(win) -} - -filetime_as_time_li :: #force_inline proc(ft: win32.LARGE_INTEGER) -> (t: time.Time) { - return {_nsec=(i64(ft) - 116444736000000000) * 100} -} - -filetime_as_time_ft :: #force_inline proc(ft: win32.FILETIME) -> (t: time.Time) { - return filetime_as_time_li(win32.LARGE_INTEGER(ft.dwLowDateTime) + win32.LARGE_INTEGER(ft.dwHighDateTime) << 32) -} - -filetime_as_time :: proc{filetime_as_time_ft, filetime_as_time_li} - -_file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) { - fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) - type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0) - fi.type = type - fi.mode |= mode - fi.creation_time = filetime_as_time(d.ftCreationTime) - fi.modification_time = filetime_as_time(d.ftLastWriteTime) - fi.access_time = filetime_as_time(d.ftLastAccessTime) - fi.fullpath, e = full_path_from_name(name, allocator) - fi.name = basename(fi.fullpath) - return -} - -_file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) { - fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) - type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0) - fi.type = type - fi.mode |= mode - fi.creation_time = filetime_as_time(d.ftCreationTime) - fi.modification_time = filetime_as_time(d.ftLastWriteTime) - fi.access_time = filetime_as_time(d.ftLastAccessTime) - fi.fullpath, e = full_path_from_name(name, allocator) - fi.name = basename(fi.fullpath) - return -} - -_file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE, allocator: runtime.Allocator) -> (File_Info, Error) { - d: win32.BY_HANDLE_FILE_INFORMATION - if !win32.GetFileInformationByHandle(h, &d) { - return {}, _get_platform_error() - - } - - ti: win32.FILE_ATTRIBUTE_TAG_INFO - if !win32.GetFileInformationByHandleEx(h, .FileAttributeTagInfo, &ti, size_of(ti)) { - err := _get_platform_error() - if perr, ok := is_platform_error(err); ok && perr != i32(win32.ERROR_INVALID_PARAMETER) { - return {}, err - } - // Indicate this is a symlink on FAT file systems - ti.ReparseTag = 0 - } - fi: File_Info - fi.fullpath = path - fi.name = basename(path) - fi.inode = u128(u64(d.nFileIndexHigh)<<32 + u64(d.nFileIndexLow)) - fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) - type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, h, 0) - fi.type = type - fi.mode |= mode - fi.creation_time = filetime_as_time(d.ftCreationTime) - fi.modification_time = filetime_as_time(d.ftLastWriteTime) - fi.access_time = filetime_as_time(d.ftLastAccessTime) - return fi, nil -} - -reserved_names := [?]string{ - "CON", "PRN", "AUX", "NUL", - "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", - "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", -} - -_is_reserved_name :: proc(path: string) -> bool { - if len(path) == 0 { - return false - } - for reserved in reserved_names { - if strings.equal_fold(path, reserved) { - return true - } - } - return false -} - -_volume_name_len :: proc(path: string) -> (length: int) { - if len(path) < 2 { - return 0 - } - - if path[1] == ':' { - switch path[0] { - case 'a'..='z', 'A'..='Z': - return 2 - } - } - - /* - See: URL: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx - Further allowed paths can be of the form of: - - \\server\share or \\server\share\more\path - - \\?\C:\... - - \\.\PhysicalDriveX - */ - // Any remaining kind of path has to start with two slashes. - if !_is_path_separator(path[0]) || !_is_path_separator(path[1]) { - return 0 - } - - // Device path. The volume name is the whole string - if len(path) >= 5 && path[2] == '.' && _is_path_separator(path[3]) { - return len(path) - } - - // We're a UNC share `\\host\share`, file namespace `\\?\C:` or UNC in file namespace `\\?\\host\share` - prefix := 2 - - // File namespace. - if len(path) >= 5 && path[2] == '?' && _is_path_separator(path[3]) { - if _is_path_separator(path[4]) { - // `\\?\\` UNC path in file namespace - prefix = 5 - } - - if len(path) >= 6 && path[5] == ':' { - switch path[4] { - case 'a'..='z', 'A'..='Z': - return 6 - case: - return 0 - } - } - } - - // UNC path, minimum version of the volume is `\\h\s` for host, share. - // Can also contain an IP address in the host position. - slash_count := 0 - for i in prefix.. 0 { - slash_count += 1 - - if slash_count == 2 { - return i - } - } - } - - return len(path) -} \ No newline at end of file diff --git a/core/os/os_freestanding.odin b/core/os/os_freestanding.odin deleted file mode 100644 index c22a6d7d5..000000000 --- a/core/os/os_freestanding.odin +++ /dev/null @@ -1,4 +0,0 @@ -#+build freestanding -package os - -#panic("package os does not support a freestanding target") diff --git a/core/os/os2/path.odin b/core/os/path.odin similarity index 50% rename from core/os/os2/path.odin rename to core/os/path.odin index e12aa3c9c..766adcaa9 100644 --- a/core/os/os2/path.odin +++ b/core/os/path.odin @@ -1,11 +1,14 @@ -package os2 +package os import "base:runtime" - +import "core:slice" import "core:strings" +import "core:unicode/utf8" + Path_Separator :: _Path_Separator // OS-Specific Path_Separator_String :: _Path_Separator_String // OS-Specific +Path_Separator_Chars :: `/\` Path_List_Separator :: _Path_List_Separator // OS-Specific #assert(_Path_Separator <= rune(0x7F), "The system-specific path separator rune is expected to be within the 7-bit ASCII character set.") @@ -19,6 +22,51 @@ is_path_separator :: proc(c: byte) -> bool { return _is_path_separator(c) } +/* +Returns the result of replacing each path separator character in the path +with the `new_sep` rune. + +*Allocates Using Provided Allocator* +*/ +replace_path_separators :: proc(path: string, new_sep: rune, allocator: runtime.Allocator) -> (new_path: string, err: Error) { + length := len(path) + rep_b, rep_w := utf8.encode_rune(new_sep) + + byte_oriented := rep_w == 1 + + for r in path { + if r == '/' || r == '\\' { + length += rep_w - 1 + } + if r > rune(0x7f) { + byte_oriented = false + } + } + + buf := make([]u8, length, allocator) or_return + + if byte_oriented { + // Neither replacement rune or any other rune in the path takes up more than 1 byte + str := transmute([]byte)path + #no_bounds_check for b, i in str { + buf[i] = u8(new_sep) if b == '/' || b == '\\' else b + } + } else { + i: int + for r in path { + if r == '/' || r == '\\' { + copy(buf[i:], rep_b[:rep_w]) + i += rep_w + } else { + r_b, r_w := utf8.encode_rune(r) + copy(buf[i:], r_b[:r_w]) + i += r_w + } + } + } + return string(buf), nil +} + mkdir :: make_directory /* @@ -26,7 +74,7 @@ Make a new directory. If `path` is relative, it will be relative to the process's current working directory. */ -make_directory :: proc(name: string, perm: int = 0o755) -> Error { +make_directory :: proc(name: string, perm := Permissions_Default_Directory) -> Error { return _mkdir(name, perm) } @@ -37,7 +85,7 @@ Make a new directory, creating new intervening directories when needed. If `path` is relative, it will be relative to the process's current working directory. */ -make_directory_all :: proc(path: string, perm: int = 0o755) -> Error { +make_directory_all :: proc(path: string, perm := Permissions_Default_Directory) -> Error { return _mkdir_all(path, perm) } @@ -114,7 +162,7 @@ This will remove duplicate separators and unneeded references to the current or parent directory. */ @(require_results) -clean_path :: proc(path: string, allocator: runtime.Allocator) -> (cleaned: string, err: Error) { +clean_path :: proc(path: string, allocator: runtime.Allocator) -> (cleaned: string, err: runtime.Allocator_Error) { if path == "" || path == "." { return strings.clone(".", allocator) } @@ -315,6 +363,139 @@ split_path :: proc(path: string) -> (dir, filename: string) { return _split_path(path) } + +/* +Gets the file name and extension from a path. + +e.g. + 'path/to/name.tar.gz' -> 'name.tar.gz' + 'path/to/name.txt' -> 'name.txt' + 'path/to/name' -> 'name' + +Returns "." if the path is an empty string. +*/ +base :: proc(path: string) -> string { + if path == "" { + return "." + } + + _, file := split_path(path) + return file +} + +/* +Gets the name of a file from a path. + +The stem of a file is such that `stem(path)` + `ext(path)` = `base(path)`. + +Only the last dot is considered when splitting the file extension. +See `short_stem`. + +e.g. + 'name.tar.gz' -> 'name.tar' + 'name.txt' -> 'name' + +Returns an empty string if there is no stem. e.g: '.gitignore'. +Returns an empty string if there's a trailing path separator. +*/ +stem :: proc(path: string) -> string { + // If the last character is a path separator, there is no file. + if is_path_separator(path[len(path) - 1]) { + return "" + } + + // Get the base path. + p := base(path) + if i := strings.last_index_any(p, Path_Separator_Chars); i != -1 { + p = p[i+1:] + } + + if i := strings.last_index_byte(p, '.'); i != -1 { + return p[:i] + } + return p +} + +/* +Gets the name of a file from a path. + +The short stem is such that `short_stem(path)` + `long_ext(path)` = `base(path)`, +where `long_ext` is the extension returned by `split_filename_all`. + +The first dot is used to split off the file extension, unlike `stem` which uses the last dot. + +e.g. + 'name.tar.gz' -> 'name' + 'name.txt' -> 'name' + +Returns an empty string if there is no stem. e.g: '.gitignore'. +Returns an empty string if there's a trailing path separator. +*/ +short_stem :: proc(path: string) -> string { + s := stem(path) + if i := strings.index_byte(s, '.'); i != -1 { + return s[:i] + } + return s +} + +/* +Gets the file extension from a path, including the dot. + +The file extension is such that `stem_path(path)` + `ext(path)` = `base(path)`. + +Only the last dot is considered when splitting the file extension. +See `long_ext`. + +e.g. + 'name.tar.gz' -> '.gz' + 'name.txt' -> '.txt' + +Returns an empty string if there is no dot. +Returns an empty string if there is a trailing path separator. +*/ +ext :: proc(path: string) -> string { + for i := len(path)-1; i >= 0 && !is_path_separator(path[i]); i -= 1 { + if path[i] == '.' { + return path[i:] + } + } + return "" +} + +/* +Gets the file extension from a path, including the dot. + +The long file extension is such that `short_stem(path)` + `long_ext(path)` = `base(path)`. + +The first dot is used to split off the file extension, unlike `ext` which uses the last dot. + +e.g. + 'name.tar.gz' -> '.tar.gz' + 'name.txt' -> '.txt' + +Returns an empty string if there is no dot. +Returns an empty string if there is a trailing path separator. +*/ +long_ext :: proc(path: string) -> string { + if len(path) > 0 && is_path_separator(path[len(path) - 1]) { + // NOTE(tetra): Trailing separator + return "" + } + + // NOTE(tetra): Get the basename + path := path + if i := strings.last_index_any(path, Path_Separator_Chars); i != -1 { + path = path[i+1:] + } + + if i := strings.index_byte(path, '.'); i != -1 { + return path[i:] + } + + return "" +} + /* Join all `elems` with the system's path separator and normalize the result. @@ -323,7 +504,7 @@ Join all `elems` with the system's path separator and normalize the result. For example, `join_path({"/home", "foo", "bar.txt"})` will result in `"/home/foo/bar.txt"`. */ @(require_results) -join_path :: proc(elems: []string, allocator: runtime.Allocator) -> (joined: string, err: Error) { +join_path :: proc(elems: []string, allocator: runtime.Allocator) -> (joined: string, err: runtime.Allocator_Error) { for e, i in elems { if e != "" { temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) @@ -460,3 +641,353 @@ split_path_list :: proc(path: string, allocator: runtime.Allocator) -> (list: [] return list, nil } + +/* +`match` states whether "name" matches the shell pattern + +Pattern syntax is: + pattern: + {term} + term: + '*' matches any sequence of non-/ characters + '?' matches any single non-/ character + '[' ['^'] { character-range } ']' + character classification (cannot be empty) + c matches character c (c != '*', '?', '\\', '[') + '\\' c matches character c + + character-range + c matches character c (c != '\\', '-', ']') + '\\' c matches character c + lo '-' hi matches character c for lo <= c <= hi + +`match` requires that the pattern matches the entirety of the name, not just a substring. +The only possible error returned is `.Syntax_Error` or an allocation error. + +NOTE(bill): This is effectively the shell pattern matching system found +*/ +match :: proc(pattern, name: string) -> (matched: bool, err: Error) { + pattern, name := pattern, name + pattern_loop: for len(pattern) > 0 { + star: bool + chunk: string + star, chunk, pattern = scan_chunk(pattern) + if star && chunk == "" { + return !strings.contains(name, _Path_Separator_String), nil + } + + t, ok := match_chunk(chunk, name) or_return + + if ok && (len(t) == 0 || len(pattern) > 0) { + name = t + continue + } + + if star { + for i := 0; i < len(name) && name[i] != _Path_Separator; i += 1 { + t, ok = match_chunk(chunk, name[i+1:]) or_return + if ok { + if len(pattern) == 0 && len(t) > 0 { + continue + } + name = t + continue pattern_loop + } + } + } + + return false, nil + } + + return len(name) == 0, nil +} + +// glob returns the names of all files matching pattern or nil if there are no matching files +// The syntax of patterns is the same as "match". +// The pattern may describe hierarchical names such as /usr/*/bin (assuming '/' is a separator) +// +// glob ignores file system errors +// +glob :: proc(pattern: string, allocator := context.allocator) -> (matches: []string, err: Error) { + _split :: proc(path: string) -> (dir, file: string) { + vol := volume_name(path) + i := len(path) - 1 + for i >= len(vol) && !is_path_separator(path[i]) { + i -= 1 + } + return path[:i+1], path[i+1:] + } + + context.allocator = allocator + + if !has_meta(pattern) { + // TODO(bill): os.lstat on here to check for error + m := make([]string, 1) + m[0] = pattern + return m[:], nil + } + + // NOTE(Jeroen): For `glob`, we need this version of `split`, which leaves the trailing `/` on `dir`. + dir, file := _split(pattern) + + temp_buf: [8]byte + vol_len: int + vol_len, dir = clean_glob_path(dir, temp_buf[:]) + + if !has_meta(dir[vol_len:]) { + m, e := _glob(dir, file, nil) + return m[:], e + } + + m := glob(dir) or_return + defer { + for s in m { + delete(s) + } + delete(m) + } + + dmatches := make([dynamic]string, 0, 0) + for d in m { + dmatches, err = _glob(d, file, &dmatches) + if err != nil { + break + } + } + if len(dmatches) > 0 { + matches = dmatches[:] + } + return +} + +/* + Returns leading volume name. + + e.g. + "C:\foo\bar\baz" will return "C:" on Windows. + Everything else will be "". +*/ +volume_name :: proc(path: string) -> string { + when ODIN_OS == .Windows { + return path[:_volume_name_len(path)] + } else { + return "" + } +} + +@(private="file") +scan_chunk :: proc(pattern: string) -> (star: bool, chunk, rest: string) { + pattern := pattern + for len(pattern) > 0 && pattern[0] == '*' { + pattern = pattern[1:] + star = true + } + + in_range, i := false, 0 + + scan_loop: for i = 0; i < len(pattern); i += 1 { + switch pattern[i] { + case '\\': + when ODIN_OS != .Windows { + if i+1 < len(pattern) { + i += 1 + } + } + case '[': + in_range = true + case ']': + in_range = false + case '*': + in_range or_break scan_loop + + } + } + return star, pattern[:i], pattern[i:] +} + +@(private="file") +match_chunk :: proc(chunk, s: string) -> (rest: string, ok: bool, err: Error) { + slash_equal :: proc(a, b: u8) -> bool { + switch a { + case '/': return b == '/' || b == '\\' + case '\\': return b == '/' || b == '\\' + case: return a == b + } + } + + chunk, s := chunk, s + for len(chunk) > 0 { + if len(s) == 0 { + return + } + switch chunk[0] { + case '[': + r, w := utf8.decode_rune_in_string(s) + s = s[w:] + chunk = chunk[1:] + is_negated := false + if len(chunk) > 0 && chunk[0] == '^' { + is_negated = true + chunk = chunk[1:] + } + match := false + range_count := 0 + for { + if len(chunk) > 0 && chunk[0] == ']' && range_count > 0 { + chunk = chunk[1:] + break + } + lo, hi: rune + if lo, chunk, err = get_escape(chunk); err != nil { + return + } + hi = lo + if chunk[0] == '-' { + if hi, chunk, err = get_escape(chunk[1:]); err != nil { + return + } + } + + if lo <= r && r <= hi { + match = true + } + range_count += 1 + } + if match == is_negated { + return + } + + case '?': + if s[0] == _Path_Separator { + return + } + _, w := utf8.decode_rune_in_string(s) + s = s[w:] + chunk = chunk[1:] + + case '\\': + when ODIN_OS != .Windows { + chunk = chunk[1:] + if len(chunk) == 0 { + err = .Pattern_Syntax_Error + return + } + } + fallthrough + case: + if !slash_equal(chunk[0], s[0]) { + return + } + s = s[1:] + chunk = chunk[1:] + + } + } + return s, true, nil +} + +@(private="file") +get_escape :: proc(chunk: string) -> (r: rune, next_chunk: string, err: Error) { + if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' { + err = .Pattern_Syntax_Error + return + } + chunk := chunk + if chunk[0] == '\\' && ODIN_OS != .Windows { + chunk = chunk[1:] + if len(chunk) == 0 { + err = .Pattern_Syntax_Error + return + } + } + + w: int + r, w = utf8.decode_rune_in_string(chunk) + if r == utf8.RUNE_ERROR && w == 1 { + err = .Pattern_Syntax_Error + } + + next_chunk = chunk[w:] + if len(next_chunk) == 0 { + err = .Pattern_Syntax_Error + } + + return +} + +// Internal implementation of `glob`, not meant to be used by the user. Prefer `glob`. +_glob :: proc(dir, pattern: string, matches: ^[dynamic]string, allocator := context.allocator) -> (m: [dynamic]string, e: Error) { + context.allocator = allocator + + if matches != nil { + m = matches^ + } else { + m = make([dynamic]string, 0, 0) + } + + + d := open(dir, O_RDONLY) or_return + defer close(d) + + file_info := fstat(d, allocator) or_return + defer file_info_delete(file_info, allocator) + + if file_info.type != .Directory { + return + } + + fis, _ := read_dir(d, -1, allocator) + slice.sort_by(fis, proc(a, b: File_Info) -> bool { + return a.name < b.name + }) + defer file_info_slice_delete(fis, allocator) + + for fi in fis { + matched := match(pattern, fi.name) or_return + if matched { + matched_path := join_path({dir, fi.name}, allocator) or_return + append(&m, matched_path) + } + } + return +} + +@(private) +has_meta :: proc(path: string) -> bool { + when ODIN_OS == .Windows { + CHARS :: `*?[` + } else { + CHARS :: `*?[\` + } + return strings.contains_any(path, CHARS) +} + +@(private) +clean_glob_path :: proc(path: string, temp_buf: []byte) -> (int, string) { + when ODIN_OS == .Windows { + vol_len := _volume_name_len(path) + switch { + case path == "": + return 0, "." + case vol_len+1 == len(path) && is_path_separator(path[len(path)-1]): // /, \, C:\, C:/ + return vol_len+1, path + case vol_len == len(path) && len(path) == 2: // C: + copy(temp_buf[:], path) + temp_buf[2] = '.' + return vol_len, string(temp_buf[:3]) + } + + if vol_len >= len(path) { + vol_len = len(path) -1 + } + return vol_len, path[:len(path)-1] + } else { + switch path { + case "": + return 0, "." + case Path_Separator_String: + return 0, path + } + return 0, path[:len(path)-1] + } +} \ No newline at end of file diff --git a/core/os/os2/path_darwin.odin b/core/os/path_darwin.odin similarity index 97% rename from core/os/os2/path_darwin.odin rename to core/os/path_darwin.odin index 65aaf1e95..dbfdb584b 100644 --- a/core/os/os2/path_darwin.odin +++ b/core/os/path_darwin.odin @@ -1,4 +1,4 @@ -package os2 +package os import "base:runtime" diff --git a/core/os/os2/path_freebsd.odin b/core/os/path_freebsd.odin similarity index 98% rename from core/os/os2/path_freebsd.odin rename to core/os/path_freebsd.odin index e7e4f63c9..5ec43466e 100644 --- a/core/os/os2/path_freebsd.odin +++ b/core/os/path_freebsd.odin @@ -1,4 +1,4 @@ -package os2 +package os import "base:runtime" diff --git a/core/os/path_js.odin b/core/os/path_js.odin new file mode 100644 index 000000000..556d93b16 --- /dev/null +++ b/core/os/path_js.odin @@ -0,0 +1,89 @@ +#+build js wasm32, js wasm64p32 +#+private +package os + +// None of this does anything on js/wasm. +// It's only here so importing `core:os` on wasm panics cleanly, +// without spamming about all sorts of missing procs and types. + +import "base:runtime" + +_Path_Separator :: '/' +_Path_Separator_String :: "/" +_Path_List_Separator :: ':' + +_is_path_separator :: proc(c: byte) -> (ok: bool) { + return c == _Path_Separator +} + +_mkdir :: proc(name: string, perm: Permissions) -> (err: Error) { + return .Unsupported +} + +_mkdir_all :: proc(path: string, perm: Permissions) -> (err: Error) { + return .Unsupported +} + +_remove_all :: proc(path: string) -> (err: Error) { + return .Unsupported +} + +_get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + return "", .Unsupported +} + +_set_working_directory :: proc(dir: string) -> (err: Error) { + return .Unsupported +} + +_get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) { + return "", .Unsupported +} + +_are_paths_identical :: proc(a, b: string) -> bool { + return false +} + +_clean_path_handle_start :: proc(path: string, buffer: []u8) -> (rooted: bool, start: int) { + return +} + +_is_absolute_path :: proc(path: string) -> bool { + return false +} + +_get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absolute_path: string, err: Error) { + return "", .Unsupported +} + +_get_relative_path_handle_start :: proc(base, target: string) -> bool { + return false +} + +_get_common_path_len :: proc(base, target: string) -> int { + i := 0 + end := min(len(base), len(target)) + for j in 0..=end { + if j == end || _is_path_separator(base[j]) { + if base[i:j] == target[i:j] { + i = j + } else { + break + } + } + } + return i +} + +_split_path :: proc(path: string) -> (dir, file: string) { + i := len(path) - 1 + for i >= 0 && !_is_path_separator(path[i]) { + i -= 1 + } + if i == 0 { + return path[:i+1], path[i+1:] + } else if i > 0 { + return path[:i], path[i+1:] + } + return "", path +} \ No newline at end of file diff --git a/core/os/os2/path_linux.odin b/core/os/path_linux.odin similarity index 92% rename from core/os/os2/path_linux.odin rename to core/os/path_linux.odin index 1c9927843..8911e6986 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/path_linux.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" @@ -17,14 +17,14 @@ _is_path_separator :: proc(c: byte) -> bool { return c == _Path_Separator } -_mkdir :: proc(path: string, perm: int) -> Error { +_mkdir :: proc(path: string, perm: Permissions) -> Error { temp_allocator := TEMP_ALLOCATOR_GUARD({}) path_cstr := clone_to_cstring(path, temp_allocator) or_return - return _get_platform_error(linux.mkdir(path_cstr, transmute(linux.Mode)u32(perm))) + return _get_platform_error(linux.mkdir(path_cstr, transmute(linux.Mode)transmute(u32)perm)) } -_mkdir_all :: proc(path: string, perm: int) -> Error { - mkdirat :: proc(dfd: linux.Fd, path: []u8, perm: int, has_created: ^bool) -> Error { +_mkdir_all :: proc(path: string, perm: Permissions) -> Error { + mkdirat :: proc(dfd: linux.Fd, path: []u8, perm: Permissions, has_created: ^bool) -> Error { i: int for ; i < len(path) - 1 && path[i] != '/'; i += 1 {} if i == 0 { @@ -34,7 +34,7 @@ _mkdir_all :: proc(path: string, perm: int) -> Error { new_dfd, errno := linux.openat(dfd, cstring(&path[0]), _OPENDIR_FLAGS) #partial switch errno { case .ENOENT: - if errno = linux.mkdirat(dfd, cstring(&path[0]), transmute(linux.Mode)u32(perm)); errno != .NONE { + if errno = linux.mkdirat(dfd, cstring(&path[0]), transmute(linux.Mode)transmute(u32)perm); errno != .NONE { return _get_platform_error(errno) } has_created^ = true @@ -71,7 +71,7 @@ _mkdir_all :: proc(path: string, perm: int) -> Error { if errno != .NONE { return _get_platform_error(errno) } - + has_created: bool mkdirat(dfd, path_bytes, perm, &has_created) or_return return nil if has_created else .Exist @@ -147,13 +147,13 @@ _remove_all :: proc(path: string) -> Error { return _get_platform_error(linux.rmdir(path_cstr)) } -_get_working_directory :: proc(allocator: runtime.Allocator) -> (string, Error) { +_get_working_directory :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) { // NOTE(tetra): I would use PATH_MAX here, but I was not able to find // an authoritative value for it across all systems. // The largest value I could find was 4096, so might as well use the page size. // NOTE(jason): Avoiding libc, so just use 4096 directly PATH_MAX :: 4096 - buf := make([dynamic]u8, PATH_MAX, allocator) + buf := make([dynamic]u8, PATH_MAX, allocator) or_return for { #no_bounds_check n, errno := linux.getcwd(buf[:]) if errno == .NONE { @@ -162,7 +162,7 @@ _get_working_directory :: proc(allocator: runtime.Allocator) -> (string, Error) if errno != .ERANGE { return "", _get_platform_error(errno) } - resize(&buf, len(buf)+PATH_MAX) + resize(&buf, len(buf)+PATH_MAX) or_return } unreachable() } diff --git a/core/os/os2/path_netbsd.odin b/core/os/path_netbsd.odin similarity index 97% rename from core/os/os2/path_netbsd.odin rename to core/os/path_netbsd.odin index 815102dea..a9ceb13df 100644 --- a/core/os/os2/path_netbsd.odin +++ b/core/os/path_netbsd.odin @@ -1,4 +1,4 @@ -package os2 +package os import "base:runtime" diff --git a/core/os/os2/path_openbsd.odin b/core/os/path_openbsd.odin similarity index 99% rename from core/os/os2/path_openbsd.odin rename to core/os/path_openbsd.odin index cbc0346d4..55b6b7d1f 100644 --- a/core/os/os2/path_openbsd.odin +++ b/core/os/path_openbsd.odin @@ -1,4 +1,4 @@ -package os2 +package os import "base:runtime" diff --git a/core/os/os2/path_posix.odin b/core/os/path_posix.odin similarity index 91% rename from core/os/os2/path_posix.odin rename to core/os/path_posix.odin index 173cb6b6d..6f383903a 100644 --- a/core/os/os2/path_posix.odin +++ b/core/os/path_posix.odin @@ -1,6 +1,6 @@ #+private #+build darwin, netbsd, freebsd, openbsd -package os2 +package os import "base:runtime" @@ -14,16 +14,16 @@ _is_path_separator :: proc(c: byte) -> bool { return c == _Path_Separator } -_mkdir :: proc(name: string, perm: int) -> (err: Error) { +_mkdir :: proc(name: string, perm: Permissions) -> (err: Error) { temp_allocator := TEMP_ALLOCATOR_GUARD({}) cname := clone_to_cstring(name, temp_allocator) or_return - if posix.mkdir(cname, transmute(posix.mode_t)posix._mode_t(perm)) != .OK { + if posix.mkdir(cname, transmute(posix.mode_t)posix._mode_t(transmute(u32)perm)) != .OK { return _get_platform_error() } return nil } -_mkdir_all :: proc(path: string, perm: int) -> Error { +_mkdir_all :: proc(path: string, perm: Permissions) -> Error { if path == "" { return .Invalid_Path } @@ -37,7 +37,7 @@ _mkdir_all :: proc(path: string, perm: int) -> Error { clean_path := clean_path(path, temp_allocator) or_return return internal_mkdir_all(clean_path, perm) - internal_mkdir_all :: proc(path: string, perm: int) -> Error { + internal_mkdir_all :: proc(path: string, perm: Permissions) -> Error { dir, file := split_path(path) if file != path && dir != "/" { if len(dir) > 1 && dir[len(dir) - 1] == '/' { diff --git a/core/os/os2/path_posixfs.odin b/core/os/path_posixfs.odin similarity index 99% rename from core/os/os2/path_posixfs.odin rename to core/os/path_posixfs.odin index 0736e73d1..aea89c60a 100644 --- a/core/os/os2/path_posixfs.odin +++ b/core/os/path_posixfs.odin @@ -1,6 +1,6 @@ #+private #+build linux, darwin, netbsd, freebsd, openbsd, wasi -package os2 +package os // This implementation is for all systems that have POSIX-compliant filesystem paths. diff --git a/core/os/os2/path_wasi.odin b/core/os/path_wasi.odin similarity index 93% rename from core/os/os2/path_wasi.odin rename to core/os/path_wasi.odin index f26e16158..e7c003001 100644 --- a/core/os/os2/path_wasi.odin +++ b/core/os/path_wasi.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" @@ -14,7 +14,7 @@ _is_path_separator :: proc(c: byte) -> bool { return c == _Path_Separator } -_mkdir :: proc(name: string, perm: int) -> Error { +_mkdir :: proc(name: string, perm: Permissions) -> Error { dir_fd, relative, ok := match_preopen(name) if !ok { return .Invalid_Path @@ -23,7 +23,7 @@ _mkdir :: proc(name: string, perm: int) -> Error { return _get_platform_error(wasi.path_create_directory(dir_fd, relative)) } -_mkdir_all :: proc(path: string, perm: int) -> Error { +_mkdir_all :: proc(path: string, perm: Permissions) -> Error { if path == "" { return .Invalid_Path } @@ -46,7 +46,7 @@ _mkdir_all :: proc(path: string, perm: int) -> Error { internal_mkdir_all(dir) or_return } - err := _mkdir(path, 0) + err := _mkdir(path, Permissions_Default) if err == .Exist { err = nil } return err } diff --git a/core/os/os2/path_windows.odin b/core/os/path_windows.odin similarity index 89% rename from core/os/os2/path_windows.odin rename to core/os/path_windows.odin index 1225ab2ce..b471ab0b0 100644 --- a/core/os/os2/path_windows.odin +++ b/core/os/path_windows.odin @@ -1,6 +1,7 @@ #+private -package os2 +package os +import "base:intrinsics" import "base:runtime" import "core:strings" import win32 "core:sys/windows" @@ -13,7 +14,7 @@ _is_path_separator :: proc(c: byte) -> bool { return c == '\\' || c == '/' } -_mkdir :: proc(name: string, perm: int) -> Error { +_mkdir :: proc(name: string, perm: Permissions) -> Error { temp_allocator := TEMP_ALLOCATOR_GUARD({}) if !win32.CreateDirectoryW(_fix_long_path(name, temp_allocator) or_return, nil) { return _get_platform_error() @@ -21,7 +22,7 @@ _mkdir :: proc(name: string, perm: int) -> Error { return nil } -_mkdir_all :: proc(path: string, perm: int) -> Error { +_mkdir_all :: proc(path: string, perm: Permissions) -> Error { fix_root_directory :: proc(p: string) -> (s: string, allocated: bool, err: runtime.Allocator_Error) { if len(p) == len(`\\?\c:`) { if is_path_separator(p[0]) && is_path_separator(p[1]) && p[2] == '?' && is_path_separator(p[3]) && p[5] == ':' { @@ -157,17 +158,30 @@ _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err } } -can_use_long_paths: bool -@(init) -init_long_path_support :: proc "contextless" () { +@(require_results) +has_long_path_support :: proc "contextless" () -> bool { + @(static) + can_use_long_paths_lock: win32.SRWLOCK + @(static) + can_use_long_paths_checked: bool // atomic + @(static) + can_use_long_paths: bool + + if intrinsics.atomic_load_explicit(&can_use_long_paths_checked, .Acquire) == true { + return can_use_long_paths + } + win32.AcquireSRWLockExclusive(&can_use_long_paths_lock) + defer win32.ReleaseSRWLockExclusive(&can_use_long_paths_lock) + defer intrinsics.atomic_store_explicit(&can_use_long_paths_checked, true, .Release) + can_use_long_paths = false key: win32.HKEY res := win32.RegOpenKeyExW(win32.HKEY_LOCAL_MACHINE, win32.L(`SYSTEM\CurrentControlSet\Control\FileSystem`), 0, win32.KEY_READ, &key) defer win32.RegCloseKey(key) if res != 0 { - return + return can_use_long_paths } value: u32 @@ -182,11 +196,13 @@ init_long_path_support :: proc "contextless" () { &size, ) if res != 0 { - return + return can_use_long_paths } if value == 1 { can_use_long_paths = true } + + return can_use_long_paths } @(require_results) @@ -201,10 +217,11 @@ _fix_long_path :: proc(path: string, allocator: runtime.Allocator) -> (win32.wst @(require_results) _fix_long_path_internal :: proc(path: string) -> string { - if can_use_long_paths { + if has_long_path_support() { return path } + // When using win32 to create a directory, the path // cannot be too long that you cannot append an 8.3 // file name, because MAX_PATH is 260, 260-12 = 248 @@ -283,6 +300,10 @@ _is_absolute_path :: proc(path: string) -> bool { if _is_reserved_name(path) { return true } + if len(path) > 0 && _is_path_separator(path[0]) { + return true + } + l := _volume_name_len(path) if l == 0 { return false @@ -351,4 +372,4 @@ _split_path :: proc(path: string) -> (dir, file: string) { return path[:i], path[i+1:] } return "", path -} +} \ No newline at end of file diff --git a/core/os/os2/pipe.odin b/core/os/pipe.odin similarity index 94% rename from core/os/os2/pipe.odin rename to core/os/pipe.odin index 5d3e8368e..5254f9469 100644 --- a/core/os/os2/pipe.odin +++ b/core/os/pipe.odin @@ -1,4 +1,4 @@ -package os2 +package os /* Create an anonymous pipe. @@ -15,7 +15,7 @@ process, that end of the pipe needs to be closed by the parent, before any data is attempted to be read. Although pipes look like files and is compatible with most file APIs in package -os2, the way it's meant to be read is different. Due to asynchronous nature of +os, the way it's meant to be read is different. Due to asynchronous nature of the communication channel, the data may not be present at the time of a read request. The other scenario is when a pipe has no data because the other end of the pipe was closed by the child process. diff --git a/core/os/pipe_js.odin b/core/os/pipe_js.odin new file mode 100644 index 000000000..5e724ea00 --- /dev/null +++ b/core/os/pipe_js.odin @@ -0,0 +1,18 @@ +#+build js wasm32, js wasm64p32 +#+private +package os + +// None of this does anything on js/wasm. +// It's only here so importing `core:os` on wasm panics cleanly, +// without spamming about all sorts of missing procs and types. + +_pipe :: proc() -> (r, w: ^File, err: Error) { + err = .Unsupported + return +} + +@(require_results) +_pipe_has_data :: proc(r: ^File) -> (ok: bool, err: Error) { + err = .Unsupported + return +} \ No newline at end of file diff --git a/core/os/os2/pipe_linux.odin b/core/os/pipe_linux.odin similarity index 98% rename from core/os/os2/pipe_linux.odin rename to core/os/pipe_linux.odin index bb4456e1c..561f82f80 100644 --- a/core/os/os2/pipe_linux.odin +++ b/core/os/pipe_linux.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "core:sys/linux" diff --git a/core/os/os2/pipe_posix.odin b/core/os/pipe_posix.odin similarity index 99% rename from core/os/os2/pipe_posix.odin rename to core/os/pipe_posix.odin index 7c07bc068..e811e306f 100644 --- a/core/os/os2/pipe_posix.odin +++ b/core/os/pipe_posix.odin @@ -1,6 +1,6 @@ #+private #+build darwin, netbsd, freebsd, openbsd -package os2 +package os import "core:sys/posix" import "core:strings" diff --git a/core/os/os2/pipe_wasi.odin b/core/os/pipe_wasi.odin similarity index 94% rename from core/os/os2/pipe_wasi.odin rename to core/os/pipe_wasi.odin index 19c11b51d..e27c9419e 100644 --- a/core/os/os2/pipe_wasi.odin +++ b/core/os/pipe_wasi.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os _pipe :: proc() -> (r, w: ^File, err: Error) { err = .Unsupported diff --git a/core/os/os2/pipe_windows.odin b/core/os/pipe_windows.odin similarity index 98% rename from core/os/os2/pipe_windows.odin rename to core/os/pipe_windows.odin index d6dc47c9c..4e627e26a 100644 --- a/core/os/os2/pipe_windows.odin +++ b/core/os/pipe_windows.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import win32 "core:sys/windows" diff --git a/core/os/os2/process.odin b/core/os/process.odin similarity index 92% rename from core/os/os2/process.odin rename to core/os/process.odin index def561e28..9a720af87 100644 --- a/core/os/os2/process.odin +++ b/core/os/process.odin @@ -1,4 +1,4 @@ -package os2 +package os import "base:runtime" @@ -15,6 +15,9 @@ Arguments to the current process. */ args := get_args() +@(private="file") +internal_args_to_free: []string + @(private="file") get_args :: proc "contextless" () -> []string { context = runtime.default_context() @@ -22,13 +25,16 @@ get_args :: proc "contextless" () -> []string { for rt_arg, i in runtime.args__ { result[i] = string(rt_arg) } + internal_args_to_free = result return result } @(fini, private="file") delete_args :: proc "contextless" () { - context = runtime.default_context() - delete(args, heap_allocator()) + if internal_args_to_free != nil { + context = runtime.default_context() + delete(internal_args_to_free, heap_allocator()) + } } /* @@ -114,6 +120,21 @@ get_ppid :: proc() -> int { return _get_ppid() } +/* +Obtain the current thread id +*/ +@(require_results) +get_current_thread_id :: proc "contextless" () -> int { + return _get_current_thread_id() +} + +/* +Return the number of cores +*/ +get_processor_core_count :: proc() -> int { + return _get_processor_core_count() +} + /* Obtain ID's of all processes running in the system. */ @@ -290,7 +311,8 @@ This procedure obtains a process handle of a process specified by `pid`. This procedure can be subject to race conditions. See the description of `Process`. -Use `process_close()` function to close the process handle. +Use the `process_wait()` procedure (optionally prefaced with a `process_kill()`) +to close and free the process handle. */ @(require_results) process_open :: proc(pid: int, flags := Process_Open_Flags {}) -> (Process, Error) { @@ -339,10 +361,8 @@ be created. It contains information such as the command line, the environment of the process, the starting directory and many other options. Most of the fields in the struct can be set to `nil` or an empty value. -Use `process_close` to close the handle to the process. Note, that this -is not the same as terminating the process. One can terminate the process -and not close the handle, in which case the handle would be leaked. In case -the function returns an error, an invalid handle is returned. +Use the `process_wait()` procedure (optionally prefaced with a `process_kill()`) +to close and free the process handle. This procedure is not thread-safe. It may alter the inheritance properties of file handles in an unpredictable manner. In case multiple threads change @@ -474,7 +494,7 @@ Process_State :: struct { // Will also store the number of the exception or signal that has crashed the // process. exit_code: int, - // Specifies whether the termination of the process was successfull or not, + // Specifies whether the termination of the process was successful or not, // i.e. whether it has crashed or not. // **Note(windows)**: On windows `true` is always returned, as there is no // reliable way to obtain information about whether the process has crashed. @@ -490,7 +510,9 @@ Wait for a process event. This procedure blocks the execution until the process has exited or the timeout (if specified) has reached zero. If the timeout is `TIMEOUT_INFINITE`, -no timeout restriction is imposed and the procedure can block indefinately. +no timeout restriction is imposed and the procedure can block indefinitely. + +If the timeout is 0, no blocking will be done and the current state is returned. If the timeout has expired, the `General_Error.Timeout` is returned as the error. @@ -504,24 +526,25 @@ process_wait :: proc(process: Process, timeout := TIMEOUT_INFINITE) -> (Process_ } /* -Close the handle to a process. +Kill a process. -This procedure closes the handle associated with a process. It **does not** -terminate a process, in case it was running. In case a termination is -desired, kill the process first, wait for the process to finish, -then close the handle. +This procedure kills a process, specified by it's handle, `process`. + +The process is forced to exit and can't ignore the request. */ @(require_results) -process_close :: proc(process: Process) -> (Error) { - return _process_close(process) +process_kill :: proc(process: Process) -> (Error) { + return _process_kill(process) } /* Terminate a process. This procedure terminates a process, specified by it's handle, `process`. + +The process is requested to exit and can ignore the request. */ @(require_results) -process_kill :: proc(process: Process) -> (Error) { - return _process_kill(process) +process_terminate :: proc(process: Process) -> (Error) { + return _process_terminate(process) } diff --git a/core/os/process_freebsd.odin b/core/os/process_freebsd.odin new file mode 100644 index 000000000..794991ae5 --- /dev/null +++ b/core/os/process_freebsd.odin @@ -0,0 +1,34 @@ +#+private +#+build freebsd +package os + +foreign import libc "system:c" +foreign import dl "system:dl" + +foreign libc { + @(link_name="sysctlbyname") + _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> i32 --- +} + +foreign dl { + @(link_name="pthread_getthreadid_np") + pthread_getthreadid_np :: proc() -> i32 --- +} + +@(require_results) +_get_current_thread_id :: proc "contextless" () -> int { + return int(pthread_getthreadid_np()) +} + +@(require_results) +_get_processor_core_count :: proc() -> int { + count : int = 0 + count_size := size_of(count) + if _sysctlbyname("hw.ncpu", &count, &count_size, nil, 0) == 0 { + if count > 0 { + return count + } + } + + return 1 +} diff --git a/core/os/process_js.odin b/core/os/process_js.odin new file mode 100644 index 000000000..7aa6bb1b8 --- /dev/null +++ b/core/os/process_js.odin @@ -0,0 +1,99 @@ +#+build js wasm32, js wasm64p32 +#+private +package os + +// None of this does anything on js/wasm. +// It's only here so importing `core:os` on wasm panics cleanly, +// without spamming about all sorts of missing procs and types. + +import "base:runtime" +import "core:time" + + +_exit :: proc "contextless" (code: int) -> ! { + runtime.panic_contextless("exit") +} + +_get_uid :: proc() -> int { + return 0 +} + +_get_euid :: proc() -> int { + return 0 +} + +_get_gid :: proc() -> int { + return 0 +} + +_get_egid :: proc() -> int { + return 0 +} + +_get_pid :: proc() -> int { + return 0 +} + +_get_ppid :: proc() -> int { + return 0 +} + +_get_current_thread_id :: proc "contextless" () -> int { + return 0 +} + +_get_processor_core_count :: proc() -> int { + return 1 +} + +_process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) { + err = .Unsupported + return +} + +_current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) { + err = .Unsupported + return +} + +_process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { + err = .Unsupported + return +} + +_process_wait :: proc(process: Process, timeout: time.Duration) -> (process_state: Process_State, err: Error) { + err = .Unsupported + return +} + +_process_kill :: proc(process: Process) -> (err: Error) { + return .Unsupported +} + +_process_terminate :: proc(process: Process) -> (err: Error) { + return .Unsupported +} + +_process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) { + err = .Unsupported + return +} + +_process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error) { + err = .Unsupported + return +} + +_process_open :: proc(pid: int, flags: Process_Open_Flags) -> (process: Process, err: Error) { + process.pid = pid + err = .Unsupported + return +} + +_process_handle_still_valid :: proc(p: Process) -> Error { + return nil +} + +_process_state_update_times :: proc(p: Process, state: ^Process_State) { + return +} diff --git a/core/os/os2/process_linux.odin b/core/os/process_linux.odin similarity index 96% rename from core/os/os2/process_linux.odin rename to core/os/process_linux.odin index 197693dc3..5e6eff335 100644 --- a/core/os/os2/process_linux.odin +++ b/core/os/process_linux.odin @@ -1,6 +1,6 @@ #+build linux #+private file -package os2 +package os import "base:runtime" import "base:intrinsics" @@ -43,6 +43,22 @@ _get_ppid :: proc() -> int { return int(linux.getppid()) } +@(private="package") +_get_current_thread_id :: proc "contextless" () -> int { + return int(linux.gettid()) +} + +@(private="package") +_get_processor_core_count :: proc() -> (core_count: int) { + cpu_set: [128]u64 + if n, err := linux.sched_getaffinity(0, size_of(cpu_set), &cpu_set); err == nil { + for set in cpu_set[:n / 8] { + core_count += int(intrinsics.count_ones(set)) + } + } + return +} + @(private="package") _process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error) { temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) @@ -658,6 +674,8 @@ _reap_terminated :: proc(process: Process) -> (state: Process_State, err: Error) state.exit_code = int(info.status) state.success = false } + + _process_close(process) return } @@ -699,6 +717,8 @@ _timed_wait_on_handle :: proc(process: Process, timeout: time.Duration) -> (proc start_tick = time.tick_now() continue } + + _process_close(process) return process_state, _get_platform_error(errno) } @@ -709,6 +729,7 @@ _timed_wait_on_handle :: proc(process: Process, timeout: time.Duration) -> (proc } if errno = linux.waitid(.PIDFD, linux.Id(process.handle), &info, {.WEXITED, .WNOHANG, .WNOWAIT}, nil); errno != .NONE { + _process_close(process) return process_state, _get_platform_error(errno) } @@ -743,6 +764,8 @@ _timed_wait_on_handle :: proc(process: Process, timeout: time.Duration) -> (proc process_state.success = false } } + + _process_close(process) return } @@ -759,6 +782,7 @@ _timed_wait_on_pid :: proc(process: Process, timeout: time.Duration) -> (process org_sigset: linux.Sig_Set errno := linux.rt_sigprocmask(.SIG_BLOCK, &sigchld_set, &org_sigset) if errno != .NONE { + _process_close(process) return process_state, _get_platform_error(errno) } defer linux.rt_sigprocmask(.SIG_SETMASK, &org_sigset, nil) @@ -790,6 +814,7 @@ _timed_wait_on_pid :: proc(process: Process, timeout: time.Duration) -> (process timeout -= time.tick_since(start_tick) start_tick = time.tick_now() case .EINVAL: + _process_close(process) return process_state, _get_platform_error(errno) } } @@ -828,13 +853,13 @@ _process_wait :: proc(process: Process, timeout: time.Duration) -> (Process_Stat return process_state, .Timeout } if errno != .NONE { + _process_close(process) return process_state, _get_platform_error(errno) } return _reap_terminated(process) } -@(private="package") _process_close :: proc(process: Process) -> Error { if process.handle == 0 || process.handle == PIDFD_UNASSIGNED { return nil @@ -848,3 +873,7 @@ _process_kill :: proc(process: Process) -> Error { return _get_platform_error(linux.kill(linux.Pid(process.pid), .SIGKILL)) } +@(private="package") +_process_terminate :: proc(process: Process) -> Error { + return _get_platform_error(linux.kill(linux.Pid(process.pid), .SIGTERM)) +} diff --git a/core/os/process_netbsd.odin b/core/os/process_netbsd.odin new file mode 100644 index 000000000..af65e1371 --- /dev/null +++ b/core/os/process_netbsd.odin @@ -0,0 +1,30 @@ +#+private +#+build netbsd +package os + +foreign import libc "system:c" + +@(private) +foreign libc { + _lwp_self :: proc() -> i32 --- + + @(link_name="sysctlbyname") + _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> i32 --- +} + +@(require_results) +_get_current_thread_id :: proc "contextless" () -> int { + return int(_lwp_self()) +} + +_get_processor_core_count :: proc() -> int { + count : int = 0 + count_size := size_of(count) + if _sysctlbyname("hw.ncpu", &count, &count_size, nil, 0) == 0 { + if count > 0 { + return count + } + } + + return 1 +} diff --git a/core/os/process_openbsd.odin b/core/os/process_openbsd.odin new file mode 100644 index 000000000..cab562aaf --- /dev/null +++ b/core/os/process_openbsd.odin @@ -0,0 +1,25 @@ +#+private +#+build openbsd +package os + +import "core:c" + +foreign import libc "system:c" + +@(default_calling_convention="c") +foreign libc { + @(link_name="getthrid") _unix_getthrid :: proc() -> int --- + @(link_name="sysconf") _sysconf :: proc(name: c.int) -> c.long --- +} + +@(require_results) +_get_current_thread_id :: proc "contextless" () -> int { + return _unix_getthrid() +} + +_SC_NPROCESSORS_ONLN :: 503 + +@(private, require_results) +_get_processor_core_count :: proc() -> int { + return int(_sysconf(_SC_NPROCESSORS_ONLN)) +} diff --git a/core/os/os2/process_posix.odin b/core/os/process_posix.odin similarity index 97% rename from core/os/os2/process_posix.odin rename to core/os/process_posix.odin index a48e44900..f41779290 100644 --- a/core/os/os2/process_posix.odin +++ b/core/os/process_posix.odin @@ -1,6 +1,6 @@ #+private #+build darwin, netbsd, freebsd, openbsd -package os2 +package os import "base:runtime" @@ -329,10 +329,6 @@ _process_wait :: proc(process: Process, timeout: time.Duration) -> (process_stat return } -_process_close :: proc(process: Process) -> Error { - return nil -} - _process_kill :: proc(process: Process) -> (err: Error) { _process_handle_still_valid(process) or_return @@ -342,3 +338,13 @@ _process_kill :: proc(process: Process) -> (err: Error) { return } + +_process_terminate :: proc(process: Process) -> (err: Error) { + _process_handle_still_valid(process) or_return + + if posix.kill(posix.pid_t(process.pid), .SIGTERM) != .OK { + err = _get_platform_error() + } + + return +} diff --git a/core/os/os2/process_posix_darwin.odin b/core/os/process_posix_darwin.odin similarity index 91% rename from core/os/os2/process_posix_darwin.odin rename to core/os/process_posix_darwin.odin index f655d42a9..ea621eea8 100644 --- a/core/os/os2/process_posix_darwin.odin +++ b/core/os/process_posix_darwin.odin @@ -1,8 +1,7 @@ #+private -package os2 +package os import "base:runtime" -import "base:intrinsics" import "core:bytes" import "core:sys/darwin" @@ -10,14 +9,40 @@ import "core:sys/posix" import "core:sys/unix" import "core:time" -foreign import lib "system:System" +foreign import libsystem "system:System" -foreign lib { +foreign libsystem { sysctl :: proc "c" ( name: [^]i32, namelen: u32, oldp: rawptr, oldlenp: ^uint, newp: rawptr, newlen: uint, ) -> posix.result --- + + @(link_name="sysctlbyname") + _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> posix.result --- + + // NOTE(Oskar): available from OSX 10.6 and iOS 3.2. + // For older versions there is `syscall(SYS_thread_selfid)`, but not really + // the same thing apparently. + pthread_threadid_np :: proc "c" (rawptr, ^u64) -> i32 --- +} + +_get_current_thread_id :: proc "contextless" () -> int { + tid: u64 + pthread_threadid_np(nil, &tid) + return int(tid) +} + +_get_processor_core_count :: proc() -> int { + count: int = 0 + count_size := size_of(count) + if _sysctlbyname("hw.logicalcpu", &count, &count_size, nil, 0) == .OK { + if count > 0 { + return count + } + } + + return 1 } _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) { diff --git a/core/os/os2/process_posix_other.odin b/core/os/process_posix_other.odin similarity index 98% rename from core/os/os2/process_posix_other.odin rename to core/os/process_posix_other.odin index 65da3e9e2..85ed6cdd8 100644 --- a/core/os/os2/process_posix_other.odin +++ b/core/os/process_posix_other.odin @@ -1,6 +1,6 @@ #+private #+build netbsd, openbsd, freebsd -package os2 +package os import "base:runtime" diff --git a/core/os/os2/process_wasi.odin b/core/os/process_wasi.odin similarity index 88% rename from core/os/os2/process_wasi.odin rename to core/os/process_wasi.odin index 52fdb1680..09c12a600 100644 --- a/core/os/os2/process_wasi.odin +++ b/core/os/process_wasi.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" @@ -30,6 +30,14 @@ _get_ppid :: proc() -> int { return 0 } +_get_current_thread_id :: proc "contextless" () -> int { + return 0 +} + +_get_processor_core_count :: proc() -> int { + return 1 +} + _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) { err = .Unsupported return @@ -50,11 +58,11 @@ _process_wait :: proc(process: Process, timeout: time.Duration) -> (process_stat return } -_process_close :: proc(process: Process) -> Error { +_process_kill :: proc(process: Process) -> (err: Error) { return .Unsupported } -_process_kill :: proc(process: Process) -> (err: Error) { +_process_terminate :: proc(process: Process) -> (err: Error) { return .Unsupported } diff --git a/core/os/os2/process_windows.odin b/core/os/process_windows.odin similarity index 92% rename from core/os/os2/process_windows.odin rename to core/os/process_windows.odin index 05ac9da93..e1ed4f3c0 100644 --- a/core/os/os2/process_windows.odin +++ b/core/os/process_windows.odin @@ -1,6 +1,7 @@ #+private file -package os2 +package os +import "base:intrinsics" import "base:runtime" import "core:strings" @@ -50,6 +51,35 @@ _get_ppid :: proc() -> int { return -1 } +@(private="package") +_get_current_thread_id :: proc "contextless" () -> int { + return int(win32.GetCurrentThreadId()) +} + +@(private="package") +_get_processor_core_count :: proc() -> int { + length : win32.DWORD = 0 + result := win32.GetLogicalProcessorInformation(nil, &length) + + thread_count := 0 + if !result && win32.GetLastError() == 122 && length > 0 { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + processors := make([]win32.SYSTEM_LOGICAL_PROCESSOR_INFORMATION, length, context.temp_allocator) + + result = win32.GetLogicalProcessorInformation(&processors[0], &length) + if result { + for processor in processors { + if processor.Relationship == .RelationProcessorCore { + thread := intrinsics.count_ones(processor.ProcessorMask) + thread_count += int(thread) + } + } + } + } + + return thread_count +} + @(private="package") _process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error) { snap := win32.CreateToolhelp32Snapshot(win32.TH32CS_SNAPPROCESS, 0) @@ -509,6 +539,7 @@ _process_wait :: proc(process: Process, timeout: time.Duration) -> (process_stat exit_code: u32 if !win32.GetExitCodeProcess(handle, &exit_code) { err =_get_platform_error() + _process_close(process) return } time_created: win32.FILETIME @@ -517,6 +548,7 @@ _process_wait :: proc(process: Process, timeout: time.Duration) -> (process_stat time_user: win32.FILETIME if !win32.GetProcessTimes(handle, &time_created, &time_exited, &time_kernel, &time_user) { err = _get_platform_error() + _process_close(process) return } process_state = { @@ -527,17 +559,18 @@ _process_wait :: proc(process: Process, timeout: time.Duration) -> (process_stat system_time = _filetime_to_duration(time_kernel), user_time = _filetime_to_duration(time_user), } + _process_close(process) return case win32.WAIT_TIMEOUT: err = General_Error.Timeout return case: err = _get_platform_error() + _process_close(process) return } } -@(private="package") _process_close :: proc(process: Process) -> Error { if !win32.CloseHandle(win32.HANDLE(process.handle)) { return _get_platform_error() @@ -557,6 +590,49 @@ _process_kill :: proc(process: Process) -> Error { return nil } +@(private="package") +_process_terminate :: proc(process: Process) -> Error { + Enum_Windows_State :: struct { + has_windows: bool, + pid: int, + } + state: Enum_Windows_State + state.pid = process.pid + ok := win32.EnumWindows( + proc "system" (hwnd: win32.HWND, lParam: win32.LPARAM) -> win32.BOOL { + #assert(size_of(win32.LPARAM) == size_of(^Enum_Windows_State)) + state := (^Enum_Windows_State)(rawptr(uintptr(lParam))) + + dwPid: win32.DWORD + win32.GetWindowThreadProcessId(hwnd, &dwPid) + if (dwPid == win32.DWORD(state.pid)) { + state.has_windows = true + win32.PostMessageW(hwnd, win32.WM_CLOSE, 0, 0) + } + + return true + }, + win32.LPARAM(uintptr(&state)), + ) + if state.has_windows { + if ok { + return nil + } + + err := _get_platform_error() + kill_err := _process_kill(process) + return kill_err == nil ? nil : err + } + + if !win32.GenerateConsoleCtrlEvent(win32.CTRL_C_EVENT, win32.DWORD(process.pid)) { + err := _get_platform_error() + kill_err := _process_kill(process) + return kill_err == nil ? nil : err + } + + return nil +} + _filetime_to_duration :: proc(filetime: win32.FILETIME) -> time.Duration { ticks := u64(filetime.dwHighDateTime)<<32 | u64(filetime.dwLowDateTime) return time.Duration(ticks * 100) diff --git a/core/os/stat.odin b/core/os/stat.odin index 21a4961d1..fa92e8a8e 100644 --- a/core/os/stat.odin +++ b/core/os/stat.odin @@ -1,33 +1,117 @@ package os +import "base:runtime" +import "core:strings" import "core:time" +Fstat_Callback :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error) + +/* + `File_Info` describes a file and is returned from `stat`, `fstat`, and `lstat`. +*/ File_Info :: struct { - fullpath: string, // allocated - name: string, // uses `fullpath` as underlying data - size: i64, - mode: File_Mode, - is_dir: bool, + fullpath: string, // fullpath of the file + name: string, // base name of the file + + inode: u128, // might be zero if cannot be determined + size: i64 `fmt:"M"`, // length in bytes for regular files; system-dependent for other file types + mode: Permissions, // file permission flags + type: File_Type, + creation_time: time.Time, modification_time: time.Time, access_time: time.Time, } -file_info_slice_delete :: proc(infos: []File_Info, allocator := context.allocator) { - for i := len(infos)-1; i >= 0; i -= 1 { - file_info_delete(infos[i], allocator) +@(require_results) +file_info_clone :: proc(fi: File_Info, allocator: runtime.Allocator) -> (cloned: File_Info, err: runtime.Allocator_Error) { + cloned = fi + cloned.fullpath = strings.clone(fi.fullpath, allocator) or_return + _, cloned.name = split_path(cloned.fullpath) + return +} + +file_info_slice_delete :: proc(infos: []File_Info, allocator: runtime.Allocator) { + #reverse for info in infos { + file_info_delete(info, allocator) } delete(infos, allocator) } -file_info_delete :: proc(fi: File_Info, allocator := context.allocator) { +file_info_delete :: proc(fi: File_Info, allocator: runtime.Allocator) { delete(fi.fullpath, allocator) } -File_Mode :: distinct u32 +@(require_results) +fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error) { + if f == nil { + return {}, nil + } else if f.stream.procedure != nil { + fi: File_Info + data := ([^]byte)(&fi)[:size_of(fi)] + _, err := f.stream.procedure(f, .Fstat, data, 0, nil, allocator) + return fi, err + } + return {}, .Invalid_Callback +} -File_Mode_Dir :: File_Mode(1<<16) -File_Mode_Named_Pipe :: File_Mode(1<<17) -File_Mode_Device :: File_Mode(1<<18) -File_Mode_Char_Device :: File_Mode(1<<19) -File_Mode_Sym_Link :: File_Mode(1<<20) +/* + `stat` returns a `File_Info` describing the named file from the file system. + The resulting `File_Info` must be deleted with `file_info_delete`. +*/ +@(require_results) +stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) { + return _stat(name, allocator) +} + +lstat :: stat_do_not_follow_links + +/* + Returns a `File_Info` describing the named file from the file system. + If the file is a symbolic link, the `File_Info` returns describes the symbolic link, + rather than following the link. + The resulting `File_Info` must be deleted with `file_info_delete`. +*/ +@(require_results) +stat_do_not_follow_links :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) { + return _lstat(name, allocator) +} + + +/* + Returns true if two `File_Info`s are equivalent. +*/ +@(require_results) +same_file :: proc(fi1, fi2: File_Info) -> bool { + return _same_file(fi1, fi2) +} + + +last_write_time :: modification_time +last_write_time_by_name :: modification_time_by_path + +/* + Returns the modification time of the file `f`. + The resolution of the timestamp is system-dependent. +*/ +@(require_results) +modification_time :: proc(f: ^File) -> (time.Time, Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + fi, err := fstat(f, temp_allocator) + return fi.modification_time, err +} + +/* + Returns the modification time of the named file `path`. + The resolution of the timestamp is system-dependent. +*/ +@(require_results) +modification_time_by_path :: proc(path: string) -> (time.Time, Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + fi, err := stat(path, temp_allocator) + return fi.modification_time, err +} + +is_reserved_name :: proc(path: string) -> bool { + return _is_reserved_name(path) +} \ No newline at end of file diff --git a/core/os/stat_js.odin b/core/os/stat_js.odin new file mode 100644 index 000000000..a304435d9 --- /dev/null +++ b/core/os/stat_js.odin @@ -0,0 +1,29 @@ +#+build js wasm32, js wasm64p32 +#+private +package os + +// None of this does anything on js/wasm. +// It's only here so importing `core:os` on wasm panics cleanly, +// without spamming about all sorts of missing procs and types. + +import "base:runtime" + +_fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) { + return {}, .Unsupported +} + +_stat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) { + return {}, .Unsupported +} + +_lstat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) { + return {}, .Unsupported +} + +_same_file :: proc(fi1, fi2: File_Info) -> bool { + return fi1.fullpath == fi2.fullpath +} + +_is_reserved_name :: proc(path: string) -> bool { + return false +} \ No newline at end of file diff --git a/core/os/os2/stat_linux.odin b/core/os/stat_linux.odin similarity index 97% rename from core/os/os2/stat_linux.odin rename to core/os/stat_linux.odin index 6185252cf..082279e8d 100644 --- a/core/os/os2/stat_linux.odin +++ b/core/os/stat_linux.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "core:time" import "base:runtime" @@ -73,3 +73,7 @@ _lstat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, er _same_file :: proc(fi1, fi2: File_Info) -> bool { return fi1.fullpath == fi2.fullpath } + +_is_reserved_name :: proc(path: string) -> bool { + return false +} \ No newline at end of file diff --git a/core/os/os2/stat_posix.odin b/core/os/stat_posix.odin similarity index 97% rename from core/os/os2/stat_posix.odin rename to core/os/stat_posix.odin index 4ed96b389..924860744 100644 --- a/core/os/os2/stat_posix.odin +++ b/core/os/stat_posix.odin @@ -1,6 +1,6 @@ #+private #+build darwin, netbsd, freebsd, openbsd -package os2 +package os import "base:runtime" @@ -135,3 +135,7 @@ _lstat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, er _same_file :: proc(fi1, fi2: File_Info) -> bool { return fi1.fullpath == fi2.fullpath } + +_is_reserved_name :: proc(path: string) -> bool { + return false +} \ No newline at end of file diff --git a/core/os/os2/stat_wasi.odin b/core/os/stat_wasi.odin similarity index 96% rename from core/os/os2/stat_wasi.odin rename to core/os/stat_wasi.odin index bf18d8273..5f5e6fe45 100644 --- a/core/os/os2/stat_wasi.odin +++ b/core/os/stat_wasi.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" @@ -98,3 +98,7 @@ _lstat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, er _same_file :: proc(fi1, fi2: File_Info) -> bool { return fi1.fullpath == fi2.fullpath } + +_is_reserved_name :: proc(path: string) -> bool { + return false +} \ No newline at end of file diff --git a/core/os/stat_windows.odin b/core/os/stat_windows.odin index 662c9f9e6..51bd57d5b 100644 --- a/core/os/stat_windows.odin +++ b/core/os/stat_windows.odin @@ -1,51 +1,82 @@ +#+private package os -import "core:time" import "base:runtime" +import "core:time" +import "core:strings" import win32 "core:sys/windows" -@(private, require_results) -full_path_from_name :: proc(name: string, allocator := context.allocator) -> (path: string, err: Errno) { - context.allocator = allocator - +_fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) { + if f == nil || (^File_Impl)(f.impl).fd == nil { + return + } + + path := _cleanpath_from_handle(f, allocator) or_return + + h := _handle(f) + switch win32.GetFileType(h) { + case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR: + fi = File_Info { + fullpath = path, + name = basename(path), + type = file_type(h), + } + return + } + + return _file_info_from_get_file_information_by_handle(path, h, allocator) +} + +_stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) { + return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS, allocator) +} + +_lstat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) { + return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS|win32.FILE_FLAG_OPEN_REPARSE_POINT, allocator) +} + +_same_file :: proc(fi1, fi2: File_Info) -> bool { + return fi1.fullpath == fi2.fullpath +} + +full_path_from_name :: proc(name: string, allocator: runtime.Allocator) -> (path: string, err: Error) { name := name if name == "" { name = "." } - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) - p := win32.utf8_to_utf16(name, context.temp_allocator) - buf := make([dynamic]u16, 100) - defer delete(buf) - for { - n := win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil) - if n == 0 { - return "", get_last_error() - } - if n <= u32(len(buf)) { - return win32.utf16_to_utf8(buf[:n], allocator) or_else "", nil - } - resize(&buf, len(buf)*2) - } - return + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + + p := win32_utf8_to_utf16(name, temp_allocator) or_return + + n := win32.GetFullPathNameW(cstring16(raw_data(p)), 0, nil, nil) + if n == 0 { + return "", _get_platform_error() + } + buf := make([]u16, n+1, temp_allocator) + n = win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil) + if n == 0 { + return "", _get_platform_error() + } + return win32_utf16_to_utf8(buf[:n], allocator) } -@(private, require_results) -_stat :: proc(name: string, create_file_attributes: u32, allocator := context.allocator) -> (fi: File_Info, e: Errno) { +internal_stat :: proc(name: string, create_file_attributes: u32, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) { if len(name) == 0 { - return {}, ERROR_PATH_NOT_FOUND + return {}, .Not_Exist } + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - context.allocator = allocator - - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) - - wname := win32.utf8_to_wstring(fix_long_path(name), context.temp_allocator) + wname := _fix_long_path(name, temp_allocator) or_return fa: win32.WIN32_FILE_ATTRIBUTE_DATA ok := win32.GetFileAttributesExW(wname, win32.GetFileExInfoStandard, &fa) if ok && fa.dwFileAttributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 { // Not a symlink - return file_info_from_win32_file_attribute_data(&fa, name) + fi = _file_info_from_win32_file_attribute_data(&fa, name, allocator) or_return + if fi.type == .Undetermined { + fi.type = _file_type_from_create_file(wname, create_file_attributes) + } + return } err := 0 if ok else win32.GetLastError() @@ -54,65 +85,28 @@ _stat :: proc(name: string, create_file_attributes: u32, allocator := context.al fd: win32.WIN32_FIND_DATAW sh := win32.FindFirstFileW(wname, &fd) if sh == win32.INVALID_HANDLE_VALUE { - e = get_last_error() + e = _get_platform_error() return } win32.FindClose(sh) - return file_info_from_win32_find_data(&fd, name) + fi = _file_info_from_win32_find_data(&fd, name, allocator) or_return + if fi.type == .Undetermined { + fi.type = _file_type_from_create_file(wname, create_file_attributes) + } + return } h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil) if h == win32.INVALID_HANDLE_VALUE { - e = get_last_error() + e = _get_platform_error() return } defer win32.CloseHandle(h) - return file_info_from_get_file_information_by_handle(name, h) + return _file_info_from_get_file_information_by_handle(name, h, allocator) } - -@(require_results) -lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Errno) { - attrs := win32.FILE_FLAG_BACKUP_SEMANTICS - attrs |= win32.FILE_FLAG_OPEN_REPARSE_POINT - return _stat(name, attrs, allocator) -} - -@(require_results) -stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Errno) { - attrs := win32.FILE_FLAG_BACKUP_SEMANTICS - return _stat(name, attrs, allocator) -} - -@(require_results) -fstat :: proc(fd: Handle, allocator := context.allocator) -> (fi: File_Info, err: Errno) { - if fd == 0 { - err = ERROR_INVALID_HANDLE - } - context.allocator = allocator - - path := cleanpath_from_handle(fd) or_return - defer if err != nil { - delete(path) - } - - h := win32.HANDLE(fd) - switch win32.GetFileType(h) { - case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR: - fi.name = basename(path) - fi.mode |= file_type_mode(h) - err = nil - case: - fi = file_info_from_get_file_information_by_handle(path, h) or_return - } - fi.fullpath = path - return -} - - -@(private, require_results) -cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 { +_cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 { buf := buf N := 0 for c, i in buf { @@ -121,50 +115,59 @@ cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 { } buf = buf[:N] - if len(buf) >= 4 && buf[0] == '\\' && buf[1] == '\\' && buf[2] == '?' && buf[3] == '\\' { - buf = buf[4:] - - /* - NOTE(Jeroen): Properly handle UNC paths. - We need to turn `\\?\UNC\synology.local` into `\\synology.local`. - */ - if len(buf) >= 3 && buf[0] == 'U' && buf[1] == 'N' && buf[2] == 'C' { - buf = buf[2:] - buf[0] = '\\' + if len(buf) >= 4 { + if buf[0] == '\\' && + buf[1] == '\\' && + buf[2] == '?' && + buf[3] == '\\' { + buf = buf[4:] } } return buf } -@(private, require_results) -cleanpath_from_handle :: proc(fd: Handle) -> (s: string, err: Errno) { - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) - buf := cleanpath_from_handle_u16(fd, context.temp_allocator) or_return - return win32.utf16_to_utf8(buf, context.allocator) -} -@(private, require_results) -cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> ([]u16, Errno) { - if fd == 0 { - return nil, ERROR_INVALID_HANDLE +_cleanpath_from_handle :: proc(f: ^File, allocator: runtime.Allocator) -> (string, Error) { + if f == nil { + return "", nil } - h := win32.HANDLE(fd) + h := _handle(f) n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0) if n == 0 { - return nil, get_last_error() + return "", _get_platform_error() } - buf := make([]u16, max(n, win32.DWORD(260))+1, allocator) - buf_len := win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), n, 0) - return buf[:buf_len], nil -} -@(private, require_results) -cleanpath_from_buf :: proc(buf: []u16) -> string { - buf := buf - buf = cleanpath_strip_prefix(buf) - return win32.utf16_to_utf8(buf, context.allocator) or_else "" + + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + + buf := make([]u16, max(n, 260)+1, temp_allocator) + n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0) + return _cleanpath_from_buf(string16(buf[:n]), allocator) +} + +_cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) { + if f == nil { + return nil, nil + } + h := _handle(f) + + n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0) + if n == 0 { + return nil, _get_platform_error() + } + + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + + buf := make([]u16, max(n, 260)+1, temp_allocator) + n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0) + return _cleanpath_strip_prefix(buf[:n]), nil +} + +_cleanpath_from_buf :: proc(buf: string16, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { + buf := transmute([]u16)buf + buf = _cleanpath_strip_prefix(buf) + return win32_utf16_to_utf8(buf, allocator) } -@(private, require_results) basename :: proc(name: string) -> (base: string) { name := name if len(name) > 3 && name[:3] == `\\?` { @@ -190,114 +193,201 @@ basename :: proc(name: string) -> (base: string) { return name } -@(private, require_results) -file_type_mode :: proc(h: win32.HANDLE) -> File_Mode { +file_type :: proc(h: win32.HANDLE) -> File_Type { switch win32.GetFileType(h) { - case win32.FILE_TYPE_PIPE: - return File_Mode_Named_Pipe - case win32.FILE_TYPE_CHAR: - return File_Mode_Device | File_Mode_Char_Device + case win32.FILE_TYPE_PIPE: return .Named_Pipe + case win32.FILE_TYPE_CHAR: return .Character_Device + case win32.FILE_TYPE_DISK: return .Regular } - return 0 + return .Undetermined } +_file_type_from_create_file :: proc(wname: win32.wstring, create_file_attributes: u32) -> File_Type { + h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil) + if h == win32.INVALID_HANDLE_VALUE { + return .Undetermined + } + defer win32.CloseHandle(h) + return file_type(h) +} -@(private, require_results) -file_mode_from_file_attributes :: proc(FileAttributes: win32.DWORD, h: win32.HANDLE, ReparseTag: win32.DWORD) -> (mode: File_Mode) { - if FileAttributes & win32.FILE_ATTRIBUTE_READONLY != 0 { - mode |= 0o444 +_file_type_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: win32.HANDLE, ReparseTag: win32.DWORD) -> (type: File_Type, mode: Permissions) { + if file_attributes & win32.FILE_ATTRIBUTE_READONLY != 0 { + mode += Permissions_Write_All } else { - mode |= 0o666 + mode += Permissions_Read_Write_All } is_sym := false - if FileAttributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 { + if file_attributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 { is_sym = false } else { is_sym = ReparseTag == win32.IO_REPARSE_TAG_SYMLINK || ReparseTag == win32.IO_REPARSE_TAG_MOUNT_POINT } if is_sym { - mode |= File_Mode_Sym_Link - } else { - if FileAttributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 { - mode |= 0o111 | File_Mode_Dir - } - - if h != nil { - mode |= file_type_mode(h) - } + type = .Symlink + } else if file_attributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 { + type = .Directory + mode += Permissions_Execute_All + } else if h != nil { + type = file_type(h) } - return } -@(private) -windows_set_file_info_times :: proc(fi: ^File_Info, d: ^$T) { - fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime)) - fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime)) - fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime)) +// a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC) +time_as_filetime :: #force_inline proc(t: time.Time) -> (ft: win32.LARGE_INTEGER) { + win := u64(t._nsec / 100) + 116444736000000000 + return win32.LARGE_INTEGER(win) } -@(private, require_results) -file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string) -> (fi: File_Info, e: Errno) { +filetime_as_time_li :: #force_inline proc(ft: win32.LARGE_INTEGER) -> (t: time.Time) { + return {_nsec=(i64(ft) - 116444736000000000) * 100} +} + +filetime_as_time_ft :: #force_inline proc(ft: win32.FILETIME) -> (t: time.Time) { + return filetime_as_time_li(win32.LARGE_INTEGER(ft.dwLowDateTime) + win32.LARGE_INTEGER(ft.dwHighDateTime) << 32) +} + +filetime_as_time :: proc{filetime_as_time_ft, filetime_as_time_li} + +_file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) { fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) - - fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0) - fi.is_dir = fi.mode & File_Mode_Dir != 0 - - windows_set_file_info_times(&fi, d) - - fi.fullpath, e = full_path_from_name(name) + type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0) + fi.type = type + fi.mode |= mode + fi.creation_time = filetime_as_time(d.ftCreationTime) + fi.modification_time = filetime_as_time(d.ftLastWriteTime) + fi.access_time = filetime_as_time(d.ftLastAccessTime) + fi.fullpath, e = full_path_from_name(name, allocator) fi.name = basename(fi.fullpath) - return } -@(private, require_results) -file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string) -> (fi: File_Info, e: Errno) { +_file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) { fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) - - fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0) - fi.is_dir = fi.mode & File_Mode_Dir != 0 - - windows_set_file_info_times(&fi, d) - - fi.fullpath, e = full_path_from_name(name) + type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0) + fi.type = type + fi.mode |= mode + fi.creation_time = filetime_as_time(d.ftCreationTime) + fi.modification_time = filetime_as_time(d.ftLastWriteTime) + fi.access_time = filetime_as_time(d.ftLastAccessTime) + fi.fullpath, e = full_path_from_name(name, allocator) fi.name = basename(fi.fullpath) - return } -@(private, require_results) -file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE) -> (File_Info, Errno) { +_file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE, allocator: runtime.Allocator) -> (File_Info, Error) { d: win32.BY_HANDLE_FILE_INFORMATION if !win32.GetFileInformationByHandle(h, &d) { - err := get_last_error() - return {}, err + return {}, _get_platform_error() } ti: win32.FILE_ATTRIBUTE_TAG_INFO if !win32.GetFileInformationByHandleEx(h, .FileAttributeTagInfo, &ti, size_of(ti)) { - err := get_last_error() - if err != ERROR_INVALID_PARAMETER { + err := _get_platform_error() + if perr, ok := is_platform_error(err); ok && perr != i32(win32.ERROR_INVALID_PARAMETER) { return {}, err } // Indicate this is a symlink on FAT file systems ti.ReparseTag = 0 } - fi: File_Info - fi.fullpath = path fi.name = basename(path) - fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) - - fi.mode |= file_mode_from_file_attributes(ti.FileAttributes, h, ti.ReparseTag) - fi.is_dir = fi.mode & File_Mode_Dir != 0 - - windows_set_file_info_times(&fi, &d) - + fi.inode = u128(u64(d.nFileIndexHigh)<<32 + u64(d.nFileIndexLow)) + fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) + type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, h, 0) + fi.type = type + fi.mode |= mode + fi.creation_time = filetime_as_time(d.ftCreationTime) + fi.modification_time = filetime_as_time(d.ftLastWriteTime) + fi.access_time = filetime_as_time(d.ftLastAccessTime) return fi, nil } + +reserved_names := [?]string{ + "CON", "PRN", "AUX", "NUL", + "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", + "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", +} + +_is_reserved_name :: proc(path: string) -> bool { + if len(path) == 0 { + return false + } + for reserved in reserved_names { + if strings.equal_fold(path, reserved) { + return true + } + } + return false +} + +_volume_name_len :: proc(path: string) -> (length: int) { + if len(path) < 2 { + return 0 + } + + if path[1] == ':' { + switch path[0] { + case 'a'..='z', 'A'..='Z': + return 2 + } + } + + /* + See: URL: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx + Further allowed paths can be of the form of: + - \\server\share or \\server\share\more\path + - \\?\C:\... + - \\.\PhysicalDriveX + */ + // Any remaining kind of path has to start with two slashes. + if !_is_path_separator(path[0]) || !_is_path_separator(path[1]) { + return 0 + } + + // Device path. The volume name is the whole string + if len(path) >= 5 && path[2] == '.' && _is_path_separator(path[3]) { + return len(path) + } + + // We're a UNC share `\\host\share`, file namespace `\\?\C:` or UNC in file namespace `\\?\\host\share` + prefix := 2 + + // File namespace. + if len(path) >= 5 && path[2] == '?' && _is_path_separator(path[3]) { + if _is_path_separator(path[4]) { + // `\\?\\` UNC path in file namespace + prefix = 5 + } + + if len(path) >= 6 && path[5] == ':' { + switch path[4] { + case 'a'..='z', 'A'..='Z': + return 6 + case: + return 0 + } + } + } + + // UNC path, minimum version of the volume is `\\h\s` for host, share. + // Can also contain an IP address in the host position. + slash_count := 0 + for i in prefix.. 0 { + slash_count += 1 + + if slash_count == 2 { + return i + } + } + } + + return len(path) +} \ No newline at end of file diff --git a/core/os/os2/temp_file.odin b/core/os/temp_file.odin similarity index 93% rename from core/os/os2/temp_file.odin rename to core/os/temp_file.odin index f0bc3788e..9068b6590 100644 --- a/core/os/os2/temp_file.odin +++ b/core/os/temp_file.odin @@ -1,4 +1,4 @@ -package os2 +package os import "base:runtime" @@ -14,7 +14,7 @@ MAX_ATTEMPTS :: 1<<13 // Should be enough for everyone, right? // // The caller must `close` the file once finished with. @(require_results) -create_temp_file :: proc(dir, pattern: string) -> (f: ^File, err: Error) { +create_temp_file :: proc(dir, pattern: string, additional_flags: File_Flags = {}) -> (f: ^File, err: Error) { temp_allocator := TEMP_ALLOCATOR_GUARD({}) dir := dir if dir != "" else temp_directory(temp_allocator) or_return prefix, suffix := _prefix_and_suffix(pattern) or_return @@ -26,7 +26,7 @@ create_temp_file :: proc(dir, pattern: string) -> (f: ^File, err: Error) { attempts := 0 for { name := concatenate_strings_from_buffer(name_buf[:], prefix, random_string(rand_buf[:]), suffix) - f, err = open(name, {.Read, .Write, .Create, .Excl}, Permissions_Read_Write_All) + f, err = open(name, {.Read, .Write, .Create, .Excl} + additional_flags, Permissions_Read_Write_All) if err == .Exist { close(f) attempts += 1 @@ -58,7 +58,7 @@ make_directory_temp :: proc(dir, pattern: string, allocator: runtime.Allocator) attempts := 0 for { name := concatenate_strings_from_buffer(name_buf[:], prefix, random_string(rand_buf[:]), suffix) - err = make_directory(name, 0o700) + err = make_directory(name) if err == nil { return clone_string(name, allocator) } diff --git a/core/os/temp_file_js.odin b/core/os/temp_file_js.odin new file mode 100644 index 000000000..53158d843 --- /dev/null +++ b/core/os/temp_file_js.odin @@ -0,0 +1,13 @@ +#+build js wasm32, js wasm64p32 +#+private +package os + +// None of this does anything on js/wasm. +// It's only here so importing `core:os` on wasm panics cleanly, +// without spamming about all sorts of missing procs and types. + +import "base:runtime" + +_temp_dir :: proc(allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { + return "", .Mode_Not_Implemented +} \ No newline at end of file diff --git a/core/os/os2/temp_file_linux.odin b/core/os/temp_file_linux.odin similarity index 96% rename from core/os/os2/temp_file_linux.odin rename to core/os/temp_file_linux.odin index 310720cbe..30f2169ad 100644 --- a/core/os/os2/temp_file_linux.odin +++ b/core/os/temp_file_linux.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" diff --git a/core/os/os2/temp_file_posix.odin b/core/os/temp_file_posix.odin similarity index 97% rename from core/os/os2/temp_file_posix.odin rename to core/os/temp_file_posix.odin index b44ea13a7..a72dc2fab 100644 --- a/core/os/os2/temp_file_posix.odin +++ b/core/os/temp_file_posix.odin @@ -1,6 +1,6 @@ #+private #+build darwin, netbsd, freebsd, openbsd -package os2 +package os import "base:runtime" diff --git a/core/os/os2/temp_file_wasi.odin b/core/os/temp_file_wasi.odin similarity index 95% rename from core/os/os2/temp_file_wasi.odin rename to core/os/temp_file_wasi.odin index d5628d300..d3fa941f7 100644 --- a/core/os/os2/temp_file_wasi.odin +++ b/core/os/temp_file_wasi.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" diff --git a/core/os/os2/temp_file_windows.odin b/core/os/temp_file_windows.odin similarity index 97% rename from core/os/os2/temp_file_windows.odin rename to core/os/temp_file_windows.odin index 91ea284a1..4c927134d 100644 --- a/core/os/os2/temp_file_windows.odin +++ b/core/os/temp_file_windows.odin @@ -1,5 +1,5 @@ #+private -package os2 +package os import "base:runtime" import win32 "core:sys/windows" diff --git a/core/os/os2/user.odin b/core/os/user.odin similarity index 99% rename from core/os/os2/user.odin rename to core/os/user.odin index e2a4ec4d0..8e952477d 100644 --- a/core/os/os2/user.odin +++ b/core/os/user.odin @@ -1,4 +1,4 @@ -package os2 +package os import "base:runtime" diff --git a/core/os/os2/user_posix.odin b/core/os/user_posix.odin similarity index 99% rename from core/os/os2/user_posix.odin rename to core/os/user_posix.odin index 09134d847..355a2e3cd 100644 --- a/core/os/os2/user_posix.odin +++ b/core/os/user_posix.odin @@ -1,6 +1,7 @@ #+build !windows -package os2 +package os +import "base:intrinsics" import "base:runtime" import "core:strings" diff --git a/core/os/os2/user_windows.odin b/core/os/user_windows.odin similarity index 99% rename from core/os/os2/user_windows.odin rename to core/os/user_windows.odin index 75d0ba6ac..6f7b74d6d 100644 --- a/core/os/os2/user_windows.odin +++ b/core/os/user_windows.odin @@ -1,4 +1,4 @@ -package os2 +package os import "base:runtime" @(require) import win32 "core:sys/windows" diff --git a/core/os/wasm.odin b/core/os/wasm.odin new file mode 100644 index 000000000..79c00f694 --- /dev/null +++ b/core/os/wasm.odin @@ -0,0 +1,4 @@ +#+build js wasm32, js wasm64p32 +package os + +#panic("core:os is unsupported on js/wasm") \ No newline at end of file diff --git a/core/path/filepath/match.odin b/core/path/filepath/match.odin index 3eaa7c6fe..178d5f986 100644 --- a/core/path/filepath/match.odin +++ b/core/path/filepath/match.odin @@ -3,14 +3,6 @@ package filepath import "core:os" -import "core:slice" -import "core:strings" -import "core:unicode/utf8" - -Match_Error :: enum { - None, - Syntax_Error, -} // match states whether "name" matches the shell pattern // Pattern syntax is: @@ -34,183 +26,7 @@ Match_Error :: enum { // // NOTE(bill): This is effectively the shell pattern matching system found // -match :: proc(pattern, name: string) -> (matched: bool, err: Match_Error) { - pattern, name := pattern, name - pattern_loop: for len(pattern) > 0 { - star: bool - chunk: string - star, chunk, pattern = scan_chunk(pattern) - if star && chunk == "" { - return !strings.contains(name, SEPARATOR_STRING), .None - } - - t: string - ok: bool - t, ok, err = match_chunk(chunk, name) - - if ok && (len(t) == 0 || len(pattern) > 0) { - name = t - continue - } - if err != .None { - return - } - if star { - for i := 0; i < len(name) && name[i] != SEPARATOR; i += 1 { - t, ok, err = match_chunk(chunk, name[i+1:]) - if ok { - if len(pattern) == 0 && len(t) > 0 { - continue - } - name = t - continue pattern_loop - } - if err != .None { - return - } - } - } - - return false, .None - } - - return len(name) == 0, .None -} - - -@(private="file") -scan_chunk :: proc(pattern: string) -> (star: bool, chunk, rest: string) { - pattern := pattern - for len(pattern) > 0 && pattern[0] == '*' { - pattern = pattern[1:] - star = true - } - - in_range, i := false, 0 - - scan_loop: for i = 0; i < len(pattern); i += 1 { - switch pattern[i] { - case '\\': - when ODIN_OS != .Windows { - if i+1 < len(pattern) { - i += 1 - } - } - case '[': - in_range = true - case ']': - in_range = false - case '*': - in_range or_break scan_loop - - } - } - return star, pattern[:i], pattern[i:] -} - -@(private="file") -match_chunk :: proc(chunk, s: string) -> (rest: string, ok: bool, err: Match_Error) { - chunk, s := chunk, s - for len(chunk) > 0 { - if len(s) == 0 { - return - } - switch chunk[0] { - case '[': - r, w := utf8.decode_rune_in_string(s) - s = s[w:] - chunk = chunk[1:] - is_negated := false - if len(chunk) > 0 && chunk[0] == '^' { - is_negated = true - chunk = chunk[1:] - } - match := false - range_count := 0 - for { - if len(chunk) > 0 && chunk[0] == ']' && range_count > 0 { - chunk = chunk[1:] - break - } - lo, hi: rune - if lo, chunk, err = get_escape(chunk); err != .None { - return - } - hi = lo - if chunk[0] == '-' { - if hi, chunk, err = get_escape(chunk[1:]); err != .None { - return - } - } - - if lo <= r && r <= hi { - match = true - } - range_count += 1 - } - if match == is_negated { - return - } - - case '?': - if s[0] == SEPARATOR { - return - } - _, w := utf8.decode_rune_in_string(s) - s = s[w:] - chunk = chunk[1:] - - case '\\': - when ODIN_OS != .Windows { - chunk = chunk[1:] - if len(chunk) == 0 { - err = .Syntax_Error - return - } - } - fallthrough - case: - if chunk[0] != s[0] { - return - } - s = s[1:] - chunk = chunk[1:] - - } - } - return s, true, .None -} - -@(private="file") -get_escape :: proc(chunk: string) -> (r: rune, next_chunk: string, err: Match_Error) { - if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' { - err = .Syntax_Error - return - } - chunk := chunk - if chunk[0] == '\\' && ODIN_OS != .Windows { - chunk = chunk[1:] - if len(chunk) == 0 { - err = .Syntax_Error - return - } - } - - w: int - r, w = utf8.decode_rune_in_string(chunk) - if r == utf8.RUNE_ERROR && w == 1 { - err = .Syntax_Error - } - - next_chunk = chunk[w:] - if len(next_chunk) == 0 { - err = .Syntax_Error - } - - return -} - - +match :: os.match // glob returns the names of all files matching pattern or nil if there are no matching files // The syntax of patterns is the same as "match". @@ -218,145 +34,4 @@ get_escape :: proc(chunk: string) -> (r: rune, next_chunk: string, err: Match_Er // // glob ignores file system errors // -glob :: proc(pattern: string, allocator := context.allocator) -> (matches: []string, err: Match_Error) { - context.allocator = allocator - - if !has_meta(pattern) { - // TODO(bill): os.lstat on here to check for error - m := make([]string, 1) - m[0] = pattern - return m[:], .None - } - - dir, file := split(pattern) - volume_len := 0 - when ODIN_OS == .Windows { - temp_buf: [8]byte - volume_len, dir = clean_glob_path_windows(dir, temp_buf[:]) - - } else { - dir = clean_glob_path(dir) - } - - if !has_meta(dir[volume_len:]) { - m, e := _glob(dir, file, nil) - return m[:], e - } - - m: []string - m, err = glob(dir) - if err != .None { - return - } - defer { - for s in m { - delete(s) - } - delete(m) - } - - dmatches := make([dynamic]string, 0, 0) - for d in m { - dmatches, err = _glob(d, file, &dmatches) - if err != .None { - break - } - } - if len(dmatches) > 0 { - matches = dmatches[:] - } - return -} - -// Internal implementation of `glob`, not meant to be used by the user. Prefer `glob`. -_glob :: proc(dir, pattern: string, matches: ^[dynamic]string, allocator := context.allocator) -> (m: [dynamic]string, e: Match_Error) { - context.allocator = allocator - - if matches != nil { - m = matches^ - } else { - m = make([dynamic]string, 0, 0) - } - - - d, derr := os.open(dir, os.O_RDONLY) - if derr != nil { - return - } - defer os.close(d) - - { - file_info, ferr := os.fstat(d) - defer os.file_info_delete(file_info) - - if ferr != nil { - return - } - if !file_info.is_dir { - return - } - } - - - fis, _ := os.read_dir(d, -1) - slice.sort_by(fis, proc(a, b: os.File_Info) -> bool { - return a.name < b.name - }) - defer { - for fi in fis { - os.file_info_delete(fi) - } - delete(fis) - } - - for fi in fis { - n := fi.name - matched := match(pattern, n) or_return - if matched { - append(&m, join({dir, n})) - } - } - return -} - -@(private) -has_meta :: proc(path: string) -> bool { - when ODIN_OS == .Windows { - CHARS :: `*?[` - } else { - CHARS :: `*?[\` - } - return strings.contains_any(path, CHARS) -} - -@(private) -clean_glob_path :: proc(path: string) -> string { - switch path { - case "": - return "." - case SEPARATOR_STRING: - return path - } - return path[:len(path)-1] -} - - -@(private) -clean_glob_path_windows :: proc(path: string, temp_buf: []byte) -> (prefix_len: int, cleaned: string) { - vol_len := volume_name_len(path) - switch { - case path == "": - return 0, "." - case vol_len+1 == len(path) && is_separator(path[len(path)-1]): // /, \, C:\, C:/ - return vol_len+1, path - case vol_len == len(path) && len(path) == 2: // C: - copy(temp_buf[:], path) - temp_buf[2] = '.' - return vol_len, string(temp_buf[:3]) - } - - if vol_len >= len(path) { - vol_len = len(path) -1 - } - return vol_len, path[:len(path)-1] -} +glob :: os.glob \ No newline at end of file diff --git a/core/path/filepath/path.odin b/core/path/filepath/path.odin index 14a9181c3..e383e756c 100644 --- a/core/path/filepath/path.odin +++ b/core/path/filepath/path.odin @@ -2,35 +2,37 @@ // To process paths such as URLs that depend on forward slashes regardless of the OS, use the slashpath package. package filepath -import "base:runtime" +import "core:os" import "core:strings" SEPARATOR_CHARS :: `/\` // is_separator checks whether the byte is a valid separator character -is_separator :: proc(c: byte) -> bool { - switch c { - case '/': return true - case '\\': return ODIN_OS == .Windows - } - return false -} +is_separator :: os.is_path_separator -@(private) -is_slash :: proc(c: byte) -> bool { - return c == '\\' || c == '/' -} +/* + In Windows, returns `true` if `path` is one of the following: + "CON", "PRN", "AUX", "NUL", + "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", + "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", + + On other platforms, returns `false`. +*/ +is_reserved_name :: os.is_reserved_name // Splits path immediate following the last separator; separating the path into a directory and file. // If no separator is found, `dir` will be empty and `path` set to `path`. -split :: proc(path: string) -> (dir, file: string) { - vol := volume_name(path) - i := len(path) - 1 - for i >= len(vol) && !is_separator(path[i]) { - i -= 1 - } - return path[:i+1], path[i+1:] -} +split :: os.split_path + + +/* +Join all `elems` with the system's path separator and normalize the result. + +*Allocates Using Provided Allocator* + +For example, `join_path({"/home", "foo", "bar.txt"})` will result in `"/home/foo/bar.txt"`. +*/ +join :: os.join_path /* Returns leading volume name. @@ -39,48 +41,7 @@ split :: proc(path: string) -> (dir, file: string) { "C:\foo\bar\baz" will return "C:" on Windows. Everything else will be "". */ -volume_name :: proc(path: string) -> string { - return path[:volume_name_len(path)] -} - -// Returns the length of the volume name in bytes. -volume_name_len :: proc(path: string) -> int { - if ODIN_OS == .Windows { - if len(path) < 2 { - return 0 - } - c := path[0] - if path[1] == ':' { - switch c { - case 'a'..='z', 'A'..='Z': - return 2 - } - } - - // URL: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx - if l := len(path); l >= 5 && is_slash(path[0]) && is_slash(path[1]) && - !is_slash(path[2]) && path[2] != '.' { - for n := 3; n < l-1; n += 1 { - if is_slash(path[n]) { - n += 1 - if !is_slash(path[n]) { - if path[n] == '.' { - break - } - } - for ; n < l; n += 1 { - if is_slash(path[n]) { - break - } - } - return n - } - break - } - } - } - return 0 -} +volume_name :: os.volume_name /* Gets the file name and extension from a path. @@ -92,30 +53,7 @@ volume_name_len :: proc(path: string) -> int { Returns "." if the path is an empty string. */ -base :: proc(path: string) -> string { - if path == "" { - return "." - } - - path := path - for len(path) > 0 && is_separator(path[len(path)-1]) { - path = path[:len(path)-1] - } - - path = path[volume_name_len(path):] - - i := len(path)-1 - for i >= 0 && !is_separator(path[i]) { - i -= 1 - } - if i >= 0 { - path = path[i+1:] - } - if path == "" { - return SEPARATOR_STRING - } - return path -} +base :: os.base /* Gets the name of a file from a path. @@ -132,24 +70,7 @@ base :: proc(path: string) -> string { Returns an empty string if there is no stem. e.g: '.gitignore'. Returns an empty string if there's a trailing path separator. */ -stem :: proc(path: string) -> string { - if len(path) > 0 && is_separator(path[len(path) - 1]) { - // NOTE(tetra): Trailing separator - return "" - } - - // NOTE(tetra): Get the basename - path := path - if i := strings.last_index_any(path, SEPARATOR_CHARS); i != -1 { - path = path[i+1:] - } - - if i := strings.last_index_byte(path, '.'); i != -1 { - return path[:i] - } - - return path -} +stem :: os.stem /* Gets the name of a file from a path. @@ -165,13 +86,7 @@ stem :: proc(path: string) -> string { Returns an empty string if there is no stem. e.g: '.gitignore'. Returns an empty string if there's a trailing path separator. */ -short_stem :: proc(path: string) -> string { - s := stem(path) - if i := strings.index_byte(s, '.'); i != -1 { - return s[:i] - } - return s -} +short_stem :: os.short_stem /* Gets the file extension from a path, including the dot. @@ -188,14 +103,7 @@ short_stem :: proc(path: string) -> string { Returns an empty string if there is no dot. Returns an empty string if there is a trailing path separator. */ -ext :: proc(path: string) -> string { - for i := len(path)-1; i >= 0 && !is_separator(path[i]); i -= 1 { - if path[i] == '.' { - return path[i:] - } - } - return "" -} +ext :: os.ext /* Gets the file extension from a path, including the dot. @@ -211,24 +119,7 @@ ext :: proc(path: string) -> string { Returns an empty string if there is no dot. Returns an empty string if there is a trailing path separator. */ -long_ext :: proc(path: string) -> string { - if len(path) > 0 && is_separator(path[len(path) - 1]) { - // NOTE(tetra): Trailing separator - return "" - } - - // NOTE(tetra): Get the basename - path := path - if i := strings.last_index_any(path, SEPARATOR_CHARS); i != -1 { - path = path[i+1:] - } - - if i := strings.index_byte(path, '.'); i != -1 { - return path[i:] - } - - return "" -} +long_ext :: os.long_ext /* Returns the shortest path name equivalent to `path` through solely lexical processing. @@ -245,108 +136,30 @@ long_ext :: proc(path: string) -> string { If the result of the path is an empty string, the returned path with be `"."`. */ -clean :: proc(path: string, allocator := context.allocator) -> (cleaned: string, err: runtime.Allocator_Error) #optional_allocator_error { - context.allocator = allocator +clean :: os.clean_path - path := path - original_path := path - vol_len := volume_name_len(path) - path = path[vol_len:] +/* +Returns the result of replacing each path separator character in the path +with the specific character `new_sep`. - if path == "" { - if vol_len > 1 && original_path[1] != ':' { - s, ok := from_slash(original_path) - if !ok { - s = strings.clone(s) or_return - } - return s, nil - } - return strings.concatenate({original_path, "."}) - } +*Allocates Using Provided Allocator* +*/ +replace_path_separators := os.replace_path_separators - rooted := is_separator(path[0]) +/* +Return true if `path` is an absolute path as opposed to a relative one. +*/ +is_abs :: os.is_absolute_path - n := len(path) - out := &Lazy_Buffer{ - s = path, - vol_and_path = original_path, - vol_len = vol_len, - } - defer lazy_buffer_destroy(out) - - r, dot_dot := 0, 0 - if rooted { - lazy_buffer_append(out, SEPARATOR) or_return - r, dot_dot = 1, 1 - } - - for r < n { - switch { - case is_separator(path[r]): - r += 1 - case path[r] == '.' && (r+1 == n || is_separator(path[r+1])): - r += 1 - case path[r] == '.' && path[r+1] == '.' && (r+2 == n || is_separator(path[r+2])): - r += 2 - switch { - case out.w > dot_dot: - out.w -= 1 - for out.w > dot_dot && !is_separator(lazy_buffer_index(out, out.w)) { - out.w -= 1 - } - case !rooted: - if out.w > 0 { - lazy_buffer_append(out, SEPARATOR) or_return - } - lazy_buffer_append(out, '.') or_return - lazy_buffer_append(out, '.') or_return - dot_dot = out.w - } - case: - if rooted && out.w != 1 || !rooted && out.w != 0 { - lazy_buffer_append(out, SEPARATOR) or_return - } - for ; r < n && !is_separator(path[r]); r += 1 { - lazy_buffer_append(out, path[r]) or_return - } - - } - } - - if out.w == 0 { - lazy_buffer_append(out, '.') or_return - } - - s := lazy_buffer_string(out) or_return - - new_allocation: bool - cleaned, new_allocation = from_slash(s) - if new_allocation { - delete(s) - } - return -} - -// Returns the result of replacing each forward slash `/` character in the path with the separate OS specific character. -from_slash :: proc(path: string, allocator := context.allocator) -> (new_path: string, new_allocation: bool) { - if SEPARATOR == '/' { - return path, false - } - return strings.replace_all(path, "/", SEPARATOR_STRING, allocator) -} - -// Returns the result of replacing each OS specific separator with a forward slash `/` character. -to_slash :: proc(path: string, allocator := context.allocator) -> (new_path: string, new_allocation: bool) { - if SEPARATOR == '/' { - return path, false - } - return strings.replace_all(path, SEPARATOR_STRING, "/", allocator) -} +/* +Get the absolute path to `path` with respect to the process's current directory. +*Allocates Using Provided Allocator* +*/ +abs :: os.get_absolute_path Relative_Error :: enum { None, - Cannot_Relate, } @@ -359,8 +172,10 @@ Relative_Error :: enum { */ rel :: proc(base_path, target_path: string, allocator := context.allocator) -> (string, Relative_Error) { context.allocator = allocator - base_clean := clean(base_path, allocator) - target_clean := clean(target_path, allocator) + base_clean, base_err := clean(base_path, allocator) + if base_err != nil { return "", .Cannot_Relate} + target_clean, target_err := clean(target_path, allocator) + if target_err != nil { return "", .Cannot_Relate} defer delete(base_clean, allocator) defer delete(target_clean, allocator) @@ -368,8 +183,8 @@ rel :: proc(base_path, target_path: string, allocator := context.allocator) -> ( return strings.clone(".", allocator), .None } - base_vol := volume_name(base_path) - target_vol := volume_name(target_path) + base_vol := volume_name(base_clean) + target_vol := volume_name(target_clean) base := base_clean [len(base_vol):] target := target_clean[len(target_vol):] if base == "." { @@ -435,18 +250,14 @@ rel :: proc(base_path, target_path: string, allocator := context.allocator) -> ( then `"."` is returned. */ dir :: proc(path: string, allocator := context.allocator) -> string { - context.allocator = allocator - vol := volume_name(path) i := len(path) - 1 - for i >= len(vol) && !is_separator(path[i]) { + for i > 0 && !is_separator(path[i]) { i -= 1 } - dir := clean(path[len(vol) : i+1]) - defer delete(dir) - if dir == "." && len(vol) > 2 { - return strings.clone(vol) - } - return strings.concatenate({vol, dir}) + res, dir_err := clean(path[:i], allocator) + + if dir_err != nil { return "" } + return res } @@ -456,108 +267,4 @@ dir :: proc(path: string, allocator := context.allocator) -> string { // An empty string returns nil. A non-empty string with no separators returns a 1-element array. // Any empty components will be included, e.g. `a::b` will return a 3-element array, as will `::`. // Separators within pairs of double-quotes will be ignored and stripped, e.g. `"a:b"c:d` will return []{`a:bc`, `d`}. -split_list :: proc(path: string, allocator := context.allocator) -> (list: []string, err: runtime.Allocator_Error) #optional_allocator_error { - if path == "" { - return nil, nil - } - - start: int - quote: bool - - start, quote = 0, false - count := 0 - - for i := 0; i < len(path); i += 1 { - c := path[i] - switch { - case c == '"': - quote = !quote - case c == LIST_SEPARATOR && !quote: - count += 1 - } - } - - start, quote = 0, false - list = make([]string, count + 1, allocator) or_return - index := 0 - for i := 0; i < len(path); i += 1 { - c := path[i] - switch { - case c == '"': - quote = !quote - case c == LIST_SEPARATOR && !quote: - list[index] = path[start:i] - index += 1 - start = i + 1 - } - } - assert(index == count) - list[index] = path[start:] - - for s0, i in list { - s, new := strings.replace_all(s0, `"`, ``, allocator) - if !new { - s = strings.clone(s, allocator) or_return - } - list[i] = s - } - - return list, nil -} - - - - -/* - Lazy_Buffer is a lazily made path buffer - When it does allocate, it uses the context.allocator - */ -@(private) -Lazy_Buffer :: struct { - s: string, - b: []byte, - w: int, // write index - vol_and_path: string, - vol_len: int, -} - -@(private) -lazy_buffer_index :: proc(lb: ^Lazy_Buffer, i: int) -> byte { - if lb.b != nil { - return lb.b[i] - } - return lb.s[i] -} -@(private) -lazy_buffer_append :: proc(lb: ^Lazy_Buffer, c: byte) -> (err: runtime.Allocator_Error) { - if lb.b == nil { - if lb.w < len(lb.s) && lb.s[lb.w] == c { - lb.w += 1 - return - } - lb.b = make([]byte, len(lb.s)) or_return - copy(lb.b, lb.s[:lb.w]) - } - lb.b[lb.w] = c - lb.w += 1 - return -} -@(private) -lazy_buffer_string :: proc(lb: ^Lazy_Buffer) -> (s: string, err: runtime.Allocator_Error) { - if lb.b == nil { - return strings.clone(lb.vol_and_path[:lb.vol_len+lb.w]) - } - - x := lb.vol_and_path[:lb.vol_len] - y := string(lb.b[:lb.w]) - z := make([]byte, len(x)+len(y)) or_return - copy(z, x) - copy(z[len(x):], y) - return string(z), nil -} -@(private) -lazy_buffer_destroy :: proc(lb: ^Lazy_Buffer) -> runtime.Allocator_Error { - err := delete(lb.b) - lb^ = {} - return err -} +split_list :: os.split_path_list \ No newline at end of file diff --git a/core/path/filepath/path_js.odin b/core/path/filepath/path_js.odin index 3b5ac04f5..e2657cb3e 100644 --- a/core/path/filepath/path_js.odin +++ b/core/path/filepath/path_js.odin @@ -1,36 +1,5 @@ package filepath -import "base:runtime" - -import "core:strings" - SEPARATOR :: '/' SEPARATOR_STRING :: `/` -LIST_SEPARATOR :: ':' - -is_reserved_name :: proc(path: string) -> bool { - return false -} - -is_abs :: proc(path: string) -> bool { - return strings.has_prefix(path, "/") -} - -abs :: proc(path: string, allocator := context.allocator) -> (string, bool) { - if is_abs(path) { - return strings.clone(string(path), allocator), true - } - - return path, false -} - -join :: proc(elems: []string, allocator := context.allocator) -> (joined: string, err: runtime.Allocator_Error) #optional_allocator_error { - for e, i in elems { - if e != "" { - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) - p := strings.join(elems[i:], SEPARATOR_STRING, context.temp_allocator) or_return - return clean(p, allocator) - } - } - return "", nil -} \ No newline at end of file +LIST_SEPARATOR :: ':' \ No newline at end of file diff --git a/core/path/filepath/path_unix.odin b/core/path/filepath/path_unix.odin index 8bf412599..2e1b1419e 100644 --- a/core/path/filepath/path_unix.odin +++ b/core/path/filepath/path_unix.odin @@ -1,46 +1,6 @@ #+build linux, darwin, freebsd, openbsd, netbsd, haiku package filepath -import "base:runtime" - -import "core:strings" -import "core:sys/posix" - SEPARATOR :: '/' SEPARATOR_STRING :: `/` -LIST_SEPARATOR :: ':' - -is_reserved_name :: proc(path: string) -> bool { - return false -} - -is_abs :: proc(path: string) -> bool { - return strings.has_prefix(path, "/") -} - -abs :: proc(path: string, allocator := context.allocator) -> (string, bool) { - rel := path - if rel == "" { - rel = "." - } - rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator) - path_ptr := posix.realpath(rel_cstr, nil) - if path_ptr == nil { - return "", posix.errno() == nil - } - defer posix.free(path_ptr) - - path_str := strings.clone(string(path_ptr), allocator) - return path_str, true -} - -join :: proc(elems: []string, allocator := context.allocator) -> (joined: string, err: runtime.Allocator_Error) #optional_allocator_error { - for e, i in elems { - if e != "" { - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) - p := strings.join(elems[i:], SEPARATOR_STRING, context.temp_allocator) or_return - return clean(p, allocator) - } - } - return "", nil -} +LIST_SEPARATOR :: ':' \ No newline at end of file diff --git a/core/path/filepath/path_wasi.odin b/core/path/filepath/path_wasi.odin index 74cc6ca1e..e2657cb3e 100644 --- a/core/path/filepath/path_wasi.odin +++ b/core/path/filepath/path_wasi.odin @@ -1,36 +1,5 @@ package filepath -import "base:runtime" - -import "core:strings" - SEPARATOR :: '/' SEPARATOR_STRING :: `/` -LIST_SEPARATOR :: ':' - -is_reserved_name :: proc(path: string) -> bool { - return false -} - -is_abs :: proc(path: string) -> bool { - return strings.has_prefix(path, "/") -} - -abs :: proc(path: string, allocator := context.allocator) -> (string, bool) { - if is_abs(path) { - return strings.clone(string(path), allocator), true - } - - return path, false -} - -join :: proc(elems: []string, allocator := context.allocator) -> (joined: string, err: runtime.Allocator_Error) #optional_allocator_error { - for e, i in elems { - if e != "" { - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) - p := strings.join(elems[i:], SEPARATOR_STRING, context.temp_allocator) or_return - return clean(p, allocator) - } - } - return "", nil -} +LIST_SEPARATOR :: ':' \ No newline at end of file diff --git a/core/path/filepath/path_windows.odin b/core/path/filepath/path_windows.odin index b3f4eee9e..9b8e92bbd 100644 --- a/core/path/filepath/path_windows.odin +++ b/core/path/filepath/path_windows.odin @@ -1,132 +1,9 @@ package filepath -import "core:strings" -import "base:runtime" -import "core:os" -import win32 "core:sys/windows" - SEPARATOR :: '\\' SEPARATOR_STRING :: `\` LIST_SEPARATOR :: ';' -@(private) -reserved_names := [?]string{ - "CON", "PRN", "AUX", "NUL", - "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", - "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", -} - -is_reserved_name :: proc(path: string) -> bool { - if len(path) == 0 { - return false - } - for reserved in reserved_names { - if strings.equal_fold(path, reserved) { - return true - } - } - return false -} - is_UNC :: proc(path: string) -> bool { - return volume_name_len(path) > 2 -} - -is_abs :: proc(path: string) -> bool { - if is_reserved_name(path) { - return true - } - l := volume_name_len(path) - if l == 0 { - return false - } - - path := path - path = path[l:] - if path == "" { - return false - } - return is_slash(path[0]) -} - -@(private) -temp_full_path :: proc(name: string) -> (path: string, err: os.Error) { - ta := context.temp_allocator - - name := name - if name == "" { - name = "." - } - - p := win32.utf8_to_utf16(name, ta) - n := win32.GetFullPathNameW(cstring16(raw_data(p)), 0, nil, nil) - if n == 0 { - return "", os.get_last_error() - } - - buf := make([]u16, n, ta) - n = win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil) - if n == 0 { - delete(buf) - return "", os.get_last_error() - } - - return win32.utf16_to_utf8(buf[:n], ta) -} - -abs :: proc(path: string, allocator := context.allocator) -> (string, bool) { - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator) - full_path, err := temp_full_path(path) - if err != nil { - return "", false - } - p := clean(full_path, allocator) - return p, true -} - -join :: proc(elems: []string, allocator := context.allocator) -> (string, runtime.Allocator_Error) #optional_allocator_error { - for e, i in elems { - if e != "" { - return join_non_empty(elems[i:], allocator) - } - } - return "", nil -} - -join_non_empty :: proc(elems: []string, allocator := context.allocator) -> (joined: string, err: runtime.Allocator_Error) { - context.allocator = allocator - - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator) - - if len(elems[0]) == 2 && elems[0][1] == ':' { - i := 1 - for ; i < len(elems); i += 1 { - if elems[i] != "" { - break - } - } - s := strings.join(elems[i:], SEPARATOR_STRING, context.temp_allocator) or_return - s = strings.concatenate({elems[0], s}, context.temp_allocator) or_return - return clean(s) - } - - p := strings.join(elems, SEPARATOR_STRING, context.temp_allocator) or_return - p = clean(p) or_return - if !is_UNC(p) { - return p, nil - } - - head := clean(elems[0], context.temp_allocator) or_return - if is_UNC(head) { - return p, nil - } - delete(p) // It is not needed now - - tail := strings.join(elems[1:], SEPARATOR_STRING, context.temp_allocator) or_return - tail = clean(tail, context.temp_allocator) or_return - if head[len(head)-1] == SEPARATOR { - return strings.concatenate({head, tail}) - } - - return strings.concatenate({head, SEPARATOR_STRING, tail}) -} + return len(volume_name(path)) > 2 +} \ No newline at end of file diff --git a/core/path/filepath/walk.odin b/core/path/filepath/walk.odin index 05d67daf0..2e2a4ff54 100644 --- a/core/path/filepath/walk.odin +++ b/core/path/filepath/walk.odin @@ -3,81 +3,103 @@ package filepath import "core:os" -import "core:slice" -// Walk_Proc is the type of the procedure called for each file or directory visited by 'walk' -// The 'path' parameter contains the parameter to walk as a prefix (this is the same as info.fullpath except on 'root') -// The 'info' parameter is the os.File_Info for the named path -// -// If there was a problem walking to the file or directory named by path, the incoming error will describe the problem -// and the procedure can decide how to handle that error (and walk will not descend into that directory) -// In the case of an error, the info argument will be 0 -// If an error is returned, processing stops -// The sole exception is if 'skip_dir' is returned as true: -// when 'skip_dir' is invoked on a directory. 'walk' skips directory contents -// when 'skip_dir' is invoked on a non-directory. 'walk' skips the remaining files in the containing directory -Walk_Proc :: #type proc(info: os.File_Info, in_err: os.Error, user_data: rawptr) -> (err: os.Error, skip_dir: bool) +Walker :: os.Walker -// walk walks the file tree rooted at 'root', calling 'walk_proc' for each file or directory in the tree, including 'root' -// All errors that happen visiting files and directories are filtered by walk_proc -// The files are walked in lexical order to make the output deterministic -// NOTE: Walking large directories can be inefficient due to the lexical sort -// NOTE: walk does not follow symbolic links -// NOTE: os.File_Info uses the 'context.temp_allocator' to allocate, and will delete when it is done -walk :: proc(root: string, walk_proc: Walk_Proc, user_data: rawptr) -> os.Error { - info, err := os.lstat(root, context.temp_allocator) - defer os.file_info_delete(info, context.temp_allocator) +/* +Initializes a walker, either using a path or a file pointer to a directory the walker will start at. - skip_dir: bool - if err != nil { - err, skip_dir = walk_proc(info, err, user_data) - } else { - err, skip_dir = _walk(info, walk_proc, user_data) - } - return nil if skip_dir else err -} +You are allowed to repeatedly call this to reuse it for later walks. +For an example on how to use the walker, see `walker_walk`. +*/ +walker_init :: os.walker_init -@(private) -_walk :: proc(info: os.File_Info, walk_proc: Walk_Proc, user_data: rawptr) -> (err: os.Error, skip_dir: bool) { - if !info.is_dir { - if info.fullpath == "" && info.name == "" { - // ignore empty things - return - } - return walk_proc(info, nil, user_data) - } +/* +Creates a walker, either using a path or a file pointer to a directory the walker will start at. - fis: []os.File_Info - err1: os.Error - fis, err = read_dir(info.fullpath, context.temp_allocator) - defer os.file_info_slice_delete(fis, context.temp_allocator) +For an example on how to use the walker, see `walker_walk`. +*/ +walker_create :: os.walker_create - err1, skip_dir = walk_proc(info, err, user_data) - if err != nil || err1 != nil || skip_dir { - err = err1 - return - } +/* +Returns the last error that occurred during the walker's operations. - for fi in fis { - err, skip_dir = _walk(fi, walk_proc, user_data) - if err != nil || skip_dir { - if !fi.is_dir || !skip_dir { - return +Can be called while iterating, or only at the end to check if anything failed. +*/ +walker_error :: os.walker_error + +walker_destroy :: os.walker_destroy + +// Marks the current directory to be skipped (not entered into). +walker_skip_dir :: os.walker_skip_dir + +/* +Returns the next file info in the iterator, files are iterated in breadth-first order. + +If an error occurred opening a directory, you may get zero'd info struct and +`walker_error` will return the error. + +Example: + package main + + import "core:fmt" + import "core:strings" + import "core:os" + + main :: proc() { + w := os.walker_create("core") + defer os.walker_destroy(&w) + + for info in os.walker_walk(&w) { + // Optionally break on the first error: + // _ = walker_error(&w) or_break + + // Or, handle error as we go: + if path, err := os.walker_error(&w); err != nil { + fmt.eprintfln("failed walking %s: %s", path, err) + continue } + + // Or, do not handle errors during iteration, and just check the error at the end. + + + + // Skip a directory: + if strings.has_suffix(info.fullpath, ".git") { + os.walker_skip_dir(&w) + continue + } + + fmt.printfln("%#v", info) + } + + // Handle error if one happened during iteration at the end: + if path, err := os.walker_error(&w); err != nil { + fmt.eprintfln("failed walking %s: %v", path, err) } } +*/ +walker_walk :: os.walker_walk - return -} +/* + Reads the file `f` (assuming it is a directory) and returns the unsorted directory entries. + This returns up to `n` entries OR all of them if `n <= 0`. +*/ +read_directory :: os.read_directory -@(private) -read_dir :: proc(dir_name: string, allocator := context.temp_allocator) -> (fis: []os.File_Info, err: os.Error) { - f := os.open(dir_name, os.O_RDONLY) or_return - defer os.close(f) - fis = os.read_dir(f, -1, allocator) or_return - slice.sort_by(fis, proc(a, b: os.File_Info) -> bool { - return a.name < b.name - }) - return -} +/* + Reads the file `f` (assuming it is a directory) and returns all of the unsorted directory entries. +*/ +read_all_directory :: os.read_all_directory + +/* + Reads the named directory by path (assuming it is a directory) and returns the unsorted directory entries. + This returns up to `n` entries OR all of them if `n <= 0`. +*/ +read_directory_by_path :: os.read_directory_by_path + +/* + Reads the named directory by path (assuming it is a directory) and returns all of the unsorted directory entries. +*/ +read_all_directory_by_path :: os.read_all_directory_by_path \ No newline at end of file diff --git a/core/prof/spall/spall.odin b/core/prof/spall/spall.odin index dc53dc3dc..281eaa82d 100644 --- a/core/prof/spall/spall.odin +++ b/core/prof/spall/spall.odin @@ -1,8 +1,9 @@ package spall +import "base:intrinsics" + import "core:os" import "core:time" -import "base:intrinsics" // File Format @@ -64,7 +65,9 @@ NAME_EVENT_MAX :: size_of(Name_Event) + 255 Context :: struct { precise_time: bool, timestamp_scale: f64, - fd: os.Handle, + + file: ^os.File, + fd: uintptr, } Buffer :: struct { @@ -79,18 +82,20 @@ BUFFER_DEFAULT_SIZE :: 0x10_0000 context_create_with_scale :: proc(filename: string, precise_time: bool, timestamp_scale: f64) -> (ctx: Context, ok: bool) #optional_ok { - fd, err := os.open(filename, os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_TRUNC, 0o600) + file, err := os.open(filename, {.Write, .Append, .Create, .Trunc}, {.Read_User, .Write_User}) if err != nil { return } - ctx.fd = fd + ctx.file = file + ctx.fd = os.fd(file) + ctx.precise_time = precise_time ctx.timestamp_scale = timestamp_scale temp := [size_of(Manual_Stream_Header)]u8{} _build_stream_header(temp[:], ctx.timestamp_scale) - os.write(ctx.fd, temp[:]) + write(ctx.fd, temp[:]) ok = true return } @@ -109,7 +114,7 @@ context_destroy :: proc(ctx: ^Context) { return } - os.close(ctx.fd) + os.close(ctx.file) ctx^ = Context{} } @@ -288,12 +293,12 @@ _buffer_name_process :: proc "contextless" (ctx: ^Context, buffer: ^Buffer, name buffer.head += _build_name_event(buffer.data[buffer.head:], name, .Name_Process) } -@(no_instrumentation) -write :: proc "contextless" (fd: os.Handle, buf: []byte) -> (n: int, err: os.Error) { - return _write(fd, buf) +@(no_instrumentation, private="package") +write :: proc "contextless" (fd: uintptr, buf: []byte) { + _write(fd, buf) } -@(no_instrumentation) +@(no_instrumentation, private="package") tick_now :: proc "contextless" () -> (ns: i64) { return _tick_now() } diff --git a/core/prof/spall/spall_linux.odin b/core/prof/spall/spall_linux.odin index 8060af448..207bd8471 100644 --- a/core/prof/spall/spall_linux.odin +++ b/core/prof/spall/spall_linux.odin @@ -1,19 +1,17 @@ #+private package spall -// Only for types and constants. -import "core:os" - // Package is `#+no-instrumentation`, safe to use. import "core:sys/linux" MAX_RW :: 0x7fffffff @(no_instrumentation) -_write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.Error) #no_bounds_check /* bounds check would segfault instrumentation */ { +_write :: proc "contextless" (fd: uintptr, data: []byte) #no_bounds_check /* bounds check would segfault instrumentation */ { + n: int for n < len(data) { chunk := data[:min(len(data), MAX_RW)] - n += linux.write(linux.Fd(fd), chunk) or_return + n += linux.write(linux.Fd(fd), chunk) or_break } return } diff --git a/core/prof/spall/spall_unix.odin b/core/prof/spall/spall_unix.odin index 455245aad..2f1e356ee 100644 --- a/core/prof/spall/spall_unix.odin +++ b/core/prof/spall/spall_unix.odin @@ -2,29 +2,23 @@ #+build darwin, freebsd, openbsd, netbsd package spall -// Only for types. -import "core:os" - import "core:sys/posix" MAX_RW :: 0x7fffffff @(no_instrumentation) -_write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.Error) #no_bounds_check /* bounds check would segfault instrumentation */ { - if len(data) == 0 { - return 0, nil - } - +_write :: proc "contextless" (fd: uintptr, data: []byte) #no_bounds_check /* bounds check would segfault instrumentation */ { + n: int for n < len(data) { chunk := data[:min(len(data), MAX_RW)] written := posix.write(posix.FD(fd), raw_data(chunk), len(chunk)) if written < 0 { - return n, os.get_last_error() + return } n += written } - return n, nil + return } // NOTE(tetra): "RAW" means: Not adjusted by NTP. diff --git a/core/prof/spall/spall_windows.odin b/core/prof/spall/spall_windows.odin index 11e216b63..2d059dc4d 100644 --- a/core/prof/spall/spall_windows.odin +++ b/core/prof/spall/spall_windows.odin @@ -1,20 +1,13 @@ #+private package spall -// Only for types. -import "core:os" - // Package is `#+no-instrumentation`, safe to use. import win32 "core:sys/windows" MAX_RW :: 1<<30 @(no_instrumentation) -_write :: proc "contextless" (fd: os.Handle, data: []byte) -> (int, os.Error) #no_bounds_check /* bounds check would segfault instrumentation */ { - if len(data) == 0 { - return 0, nil - } - +_write :: proc "contextless" (fd: uintptr, data: []byte) #no_bounds_check /* bounds check would segfault instrumentation */ { single_write_length: win32.DWORD total_write: i64 length := i64(len(data)) @@ -25,11 +18,12 @@ _write :: proc "contextless" (fd: os.Handle, data: []byte) -> (int, os.Error) #n e := win32.WriteFile(win32.HANDLE(fd), &data[total_write], to_write, &single_write_length, nil) if single_write_length <= 0 || !e { - return int(total_write), os.get_last_error() + return } total_write += i64(single_write_length) } - return int(total_write), nil + + return } @(no_instrumentation) diff --git a/core/reflect/iterator.odin b/core/reflect/iterator.odin index e96019f68..d283f190f 100644 --- a/core/reflect/iterator.odin +++ b/core/reflect/iterator.odin @@ -44,6 +44,15 @@ iterate_array :: proc(val: any, it: ^int) -> (elem: any, index: int, ok: bool) { index = it^ it^ += 1 } + case Type_Info_Fixed_Capacity_Dynamic_Array: + count := (^int)(uintptr(val.data) + info.len_offset)^ + if it^ < count { + elem.data = rawptr(uintptr(val.data) + uintptr(it^ * info.elem_size)) + elem.id = info.elem.id + ok = true + index = it^ + it^ += 1 + } } return diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 5fbff08c2..e7115fc96 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -6,33 +6,34 @@ _ :: intrinsics Type_Info :: runtime.Type_Info -Type_Info_Named :: runtime.Type_Info_Named -Type_Info_Integer :: runtime.Type_Info_Integer -Type_Info_Rune :: runtime.Type_Info_Rune -Type_Info_Float :: runtime.Type_Info_Float -Type_Info_Complex :: runtime.Type_Info_Complex -Type_Info_Quaternion :: runtime.Type_Info_Quaternion -Type_Info_String :: runtime.Type_Info_String -Type_Info_Boolean :: runtime.Type_Info_Boolean -Type_Info_Any :: runtime.Type_Info_Any -Type_Info_Type_Id :: runtime.Type_Info_Type_Id -Type_Info_Pointer :: runtime.Type_Info_Pointer -Type_Info_Multi_Pointer :: runtime.Type_Info_Multi_Pointer -Type_Info_Procedure :: runtime.Type_Info_Procedure -Type_Info_Array :: runtime.Type_Info_Array -Type_Info_Enumerated_Array :: runtime.Type_Info_Enumerated_Array -Type_Info_Dynamic_Array :: runtime.Type_Info_Dynamic_Array -Type_Info_Slice :: runtime.Type_Info_Slice -Type_Info_Parameters :: runtime.Type_Info_Parameters -Type_Info_Struct :: runtime.Type_Info_Struct -Type_Info_Union :: runtime.Type_Info_Union -Type_Info_Enum :: runtime.Type_Info_Enum -Type_Info_Map :: runtime.Type_Info_Map -Type_Info_Bit_Set :: runtime.Type_Info_Bit_Set -Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector -Type_Info_Matrix :: runtime.Type_Info_Matrix -Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer -Type_Info_Bit_Field :: runtime.Type_Info_Bit_Field +Type_Info_Named :: runtime.Type_Info_Named +Type_Info_Integer :: runtime.Type_Info_Integer +Type_Info_Rune :: runtime.Type_Info_Rune +Type_Info_Float :: runtime.Type_Info_Float +Type_Info_Complex :: runtime.Type_Info_Complex +Type_Info_Quaternion :: runtime.Type_Info_Quaternion +Type_Info_String :: runtime.Type_Info_String +Type_Info_Boolean :: runtime.Type_Info_Boolean +Type_Info_Any :: runtime.Type_Info_Any +Type_Info_Type_Id :: runtime.Type_Info_Type_Id +Type_Info_Pointer :: runtime.Type_Info_Pointer +Type_Info_Multi_Pointer :: runtime.Type_Info_Multi_Pointer +Type_Info_Procedure :: runtime.Type_Info_Procedure +Type_Info_Array :: runtime.Type_Info_Array +Type_Info_Enumerated_Array :: runtime.Type_Info_Enumerated_Array +Type_Info_Dynamic_Array :: runtime.Type_Info_Dynamic_Array +Type_Info_Slice :: runtime.Type_Info_Slice +Type_Info_Parameters :: runtime.Type_Info_Parameters +Type_Info_Struct :: runtime.Type_Info_Struct +Type_Info_Union :: runtime.Type_Info_Union +Type_Info_Enum :: runtime.Type_Info_Enum +Type_Info_Map :: runtime.Type_Info_Map +Type_Info_Bit_Set :: runtime.Type_Info_Bit_Set +Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector +Type_Info_Matrix :: runtime.Type_Info_Matrix +Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer +Type_Info_Bit_Field :: runtime.Type_Info_Bit_Field +Type_Info_Fixed_Capacity_Dynamic_Array :: runtime.Type_Info_Fixed_Capacity_Dynamic_Array Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value @@ -67,6 +68,7 @@ Type_Kind :: enum { Matrix, Soa_Pointer, Bit_Field, + Fixed_Capacity_Dynamic_Array, } @@ -76,33 +78,34 @@ type_kind :: proc(T: typeid) -> Type_Kind { ti := type_info_of(T) if ti != nil { switch _ in ti.variant { - case Type_Info_Named: return .Named - case Type_Info_Integer: return .Integer - case Type_Info_Rune: return .Rune - case Type_Info_Float: return .Float - case Type_Info_Complex: return .Complex - case Type_Info_Quaternion: return .Quaternion - case Type_Info_String: return .String - case Type_Info_Boolean: return .Boolean - case Type_Info_Any: return .Any - case Type_Info_Type_Id: return .Type_Id - case Type_Info_Pointer: return .Pointer - case Type_Info_Multi_Pointer: return .Multi_Pointer - case Type_Info_Procedure: return .Procedure - case Type_Info_Array: return .Array - case Type_Info_Enumerated_Array: return .Enumerated_Array - case Type_Info_Dynamic_Array: return .Dynamic_Array - case Type_Info_Slice: return .Slice - case Type_Info_Parameters: return .Parameters - case Type_Info_Struct: return .Struct - case Type_Info_Union: return .Union - case Type_Info_Enum: return .Enum - case Type_Info_Map: return .Map - case Type_Info_Bit_Set: return .Bit_Set - case Type_Info_Simd_Vector: return .Simd_Vector - case Type_Info_Matrix: return .Matrix - case Type_Info_Soa_Pointer: return .Soa_Pointer - case Type_Info_Bit_Field: return .Bit_Field + case Type_Info_Named: return .Named + case Type_Info_Integer: return .Integer + case Type_Info_Rune: return .Rune + case Type_Info_Float: return .Float + case Type_Info_Complex: return .Complex + case Type_Info_Quaternion: return .Quaternion + case Type_Info_String: return .String + case Type_Info_Boolean: return .Boolean + case Type_Info_Any: return .Any + case Type_Info_Type_Id: return .Type_Id + case Type_Info_Pointer: return .Pointer + case Type_Info_Multi_Pointer: return .Multi_Pointer + case Type_Info_Procedure: return .Procedure + case Type_Info_Array: return .Array + case Type_Info_Enumerated_Array: return .Enumerated_Array + case Type_Info_Dynamic_Array: return .Dynamic_Array + case Type_Info_Slice: return .Slice + case Type_Info_Parameters: return .Parameters + case Type_Info_Struct: return .Struct + case Type_Info_Union: return .Union + case Type_Info_Enum: return .Enum + case Type_Info_Map: return .Map + case Type_Info_Bit_Set: return .Bit_Set + case Type_Info_Simd_Vector: return .Simd_Vector + case Type_Info_Matrix: return .Matrix + case Type_Info_Soa_Pointer: return .Soa_Pointer + case Type_Info_Bit_Field: return .Bit_Field + case Type_Info_Fixed_Capacity_Dynamic_Array: return .Fixed_Capacity_Dynamic_Array } } @@ -215,6 +218,7 @@ typeid_elem :: proc(id: typeid) -> typeid { case Type_Info_Slice: return v.elem.id case Type_Info_Dynamic_Array: return v.elem.id case Type_Info_Simd_Vector: return v.elem.id + case Type_Info_Fixed_Capacity_Dynamic_Array: return v.elem.id } return id } @@ -305,6 +309,9 @@ length :: proc(val: any) -> int { case Type_Info_Dynamic_Array: return (^runtime.Raw_Dynamic_Array)(val.data).len + case Type_Info_Fixed_Capacity_Dynamic_Array: + return (^int)(uintptr(val.data) + a.len_offset)^ + case Type_Info_Map: return runtime.map_len((^runtime.Raw_Map)(val.data)^) @@ -357,6 +364,9 @@ capacity :: proc(val: any) -> int { case Type_Info_Dynamic_Array: return (^runtime.Raw_Dynamic_Array)(val.data).cap + case Type_Info_Fixed_Capacity_Dynamic_Array: + return a.capacity + case Type_Info_Map: return runtime.map_cap((^runtime.Raw_Map)(val.data)^) @@ -417,6 +427,13 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any { data := rawptr(uintptr(raw.data) + offset) return any{data, a.elem.id} + case Type_Info_Fixed_Capacity_Dynamic_Array: + count := (^int)(uintptr(val.data) + a.len_offset)^ + runtime.bounds_check_error_loc(loc, i, count) + offset := uintptr(a.elem.size * i) + data := rawptr(uintptr(val.data) + offset) + return any{data, a.elem.id} + case Type_Info_String: if a.is_cstring { return nil } @@ -1773,6 +1790,10 @@ as_raw_data :: proc(a: any) -> (value: rawptr, valid: bool) { valid = true value = (^runtime.Raw_Slice)(a.data).data + case Type_Info_Fixed_Capacity_Dynamic_Array: + valid = true + value = a.data + case Type_Info_Dynamic_Array: valid = true value = (^runtime.Raw_Dynamic_Array)(a.data).data @@ -1919,6 +1940,23 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_ } } return true + case Type_Info_Fixed_Capacity_Dynamic_Array: + a_count := (^int)(uintptr(a.data) + v.len_offset)^ + b_count := (^int)(uintptr(b.data) + v.len_offset)^ + if a_count != b_count { + return false + } + + for i in 0.. uintptr where intrinsics.type_is_comparable(T) { + assert(ptr != nil) + info := intrinsics.type_map_info(map[T]struct{}) + + h := u64(seed) + runtime.INITIAL_HASH_SEED + actual_seed := uintptr(h) | uintptr(uintptr(h) == 0) + + return info.key_hasher(ptr, actual_seed) } \ No newline at end of file diff --git a/core/reflect/types.odin b/core/reflect/types.odin index d6d7011d1..fa40c1d1b 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -32,36 +32,36 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { return x.signed == y.signed && x.endianness == y.endianness case Type_Info_Rune: - _, ok := b.variant.(Type_Info_Rune) - return ok + _ = b.variant.(Type_Info_Rune) or_return + return true case Type_Info_Float: - _, ok := b.variant.(Type_Info_Float) - return ok + y := b.variant.(Type_Info_Float) or_return + return x.endianness == y.endianness case Type_Info_Complex: - _, ok := b.variant.(Type_Info_Complex) - return ok + _ = b.variant.(Type_Info_Complex) or_return + return true case Type_Info_Quaternion: - _, ok := b.variant.(Type_Info_Quaternion) - return ok + _ = b.variant.(Type_Info_Quaternion) or_return + return true case Type_Info_Type_Id: - _, ok := b.variant.(Type_Info_Type_Id) - return ok + _ = b.variant.(Type_Info_Type_Id) or_return + return true case Type_Info_String: - _, ok := b.variant.(Type_Info_String) - return ok + y := b.variant.(Type_Info_String) or_return + return x.is_cstring == y.is_cstring && x.encoding == y.encoding case Type_Info_Boolean: - _, ok := b.variant.(Type_Info_Boolean) - return ok + _ = b.variant.(Type_Info_Boolean) or_return + return true case Type_Info_Any: - _, ok := b.variant.(Type_Info_Any) - return ok + _ = b.variant.(Type_Info_Any) or_return + return true case Type_Info_Pointer: y := b.variant.(Type_Info_Pointer) or_return @@ -78,22 +78,19 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { case Type_Info_Procedure: y := b.variant.(Type_Info_Procedure) or_return - switch { - case x.variadic != y.variadic, - x.convention != y.convention: - return false - } + (x.variadic == y.variadic) or_return + (x.convention == y.convention) or_return return are_types_identical(x.params, y.params) && are_types_identical(x.results, y.results) case Type_Info_Array: y := b.variant.(Type_Info_Array) or_return - if x.count != y.count { return false } + (x.count == y.count) or_return return are_types_identical(x.elem, y.elem) case Type_Info_Enumerated_Array: y := b.variant.(Type_Info_Enumerated_Array) or_return - if x.count != y.count { return false } + (x.count == y.count) or_return return are_types_identical(x.index, y.index) && are_types_identical(x.elem, y.elem) @@ -105,14 +102,17 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { y := b.variant.(Type_Info_Slice) or_return return are_types_identical(x.elem, y.elem) + case Type_Info_Fixed_Capacity_Dynamic_Array: + y := b.variant.(Type_Info_Fixed_Capacity_Dynamic_Array) or_return + (x.capacity == y.capacity) or_return + return are_types_identical(x.elem, y.elem) + case Type_Info_Parameters: y := b.variant.(Type_Info_Parameters) or_return - if len(x.types) != len(y.types) { return false } + (len(x.types) == len(y.types)) or_return for _, i in x.types { xt, yt := x.types[i], y.types[i] - if !are_types_identical(xt, yt) { - return false - } + are_types_identical(xt, yt) or_return } return true @@ -131,59 +131,64 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { xt, yt := x.types[i], y.types[i] xl, yl := x.tags[i], y.tags[i] - if xn != yn { return false } - if !are_types_identical(xt, yt) { return false } - if xl != yl { return false } + (xn == yn) or_return + are_types_identical(xt, yt) or_return + (xl == yl) or_return } return true case Type_Info_Union: - y := b.variant.(Type_Info_Union) or_return - if len(x.variants) != len(y.variants) { return false } + y := b.variant.(Type_Info_Union) or_return + (len(x.variants) == len(y.variants)) or_return for _, i in x.variants { xv, yv := x.variants[i], y.variants[i] - if !are_types_identical(xv, yv) { return false } + are_types_identical(xv, yv) or_return } return true case Type_Info_Enum: - // NOTE(bill): Should be handled above - return false + y := b.variant.(Type_Info_Enum) or_return + are_types_identical(x.base, y.base) or_return + (len(x.names) == len(y.names)) or_return + + for _, i in x.names { + (x.names[i] == y.names[i]) or_return + (x.values[i] == y.values[i]) or_return + } + return true case Type_Info_Map: y := b.variant.(Type_Info_Map) or_return return are_types_identical(x.key, y.key) && are_types_identical(x.value, y.value) case Type_Info_Bit_Set: - y := b.variant.(Type_Info_Bit_Set) or_return - return x.elem == y.elem && x.lower == y.lower && x.upper == y.upper + y := b.variant.(Type_Info_Bit_Set) or_return + are_types_identical(x.underlying, y.underlying) or_return + are_types_identical(x.elem, y.elem) or_return + + return x.lower == y.lower && x.upper == y.upper case Type_Info_Simd_Vector: y := b.variant.(Type_Info_Simd_Vector) or_return return x.count == y.count && x.elem == y.elem case Type_Info_Matrix: - y := b.variant.(Type_Info_Matrix) or_return - if x.row_count != y.row_count { return false } - if x.column_count != y.column_count { return false } - if x.layout != y.layout { return false } + y := b.variant.(Type_Info_Matrix) or_return + (x.row_count == y.row_count) or_return + (x.column_count == y.column_count) or_return + (x.layout == y.layout) or_return return are_types_identical(x.elem, y.elem) case Type_Info_Bit_Field: - y := b.variant.(Type_Info_Bit_Field) or_return - if !are_types_identical(x.backing_type, y.backing_type) { return false } - if x.field_count != y.field_count { return false } + y := b.variant.(Type_Info_Bit_Field) or_return + are_types_identical(x.backing_type, y.backing_type) or_return + (x.field_count == y.field_count) or_return + for _, i in x.names[:x.field_count] { - if x.names[i] != y.names[i] { - return false - } - if !are_types_identical(x.types[i], y.types[i]) { - return false - } - if x.bit_sizes[i] != y.bit_sizes[i] { - return false - } + (x.names[i] == y.names[i]) or_return + are_types_identical(x.types[i], y.types[i]) or_return + (x.bit_sizes[i] == y.bit_sizes[i]) or_return } return true } @@ -329,7 +334,8 @@ is_soa_pointer :: proc(info: ^Type_Info) -> bool { is_pointer_internally :: proc(info: ^Type_Info) -> bool { if info == nil { return false } #partial switch v in type_info_base(info).variant { - case Type_Info_Pointer, Type_Info_Multi_Pointer, + case Type_Info_Pointer, + Type_Info_Multi_Pointer, Type_Info_Procedure: return true case Type_Info_String: @@ -428,6 +434,13 @@ is_simd_vector :: proc(info: ^Type_Info) -> bool { _, ok := type_info_base(info).variant.(Type_Info_Simd_Vector) return ok } +// Returns true when the type is a fixed-capacity dynamic-array type ([dynamic; N]T), false otherwise. +@(require_results) +is_fixed_capacity_dynamic_array :: proc(info: ^Type_Info) -> bool { + if info == nil { return false } + _, ok := type_info_base(info).variant.(Type_Info_Fixed_Capacity_Dynamic_Array) + return ok +} // Returns true when the core-type is represented with a platform-native endian type, and returns false otherwise. @@ -441,11 +454,10 @@ is_endian_platform :: proc(info: ^Type_Info) -> bool { #partial switch v in info.variant { case Type_Info_Integer: return v.endianness == .Platform + case Type_Info_Float: + return v.endianness == .Platform case Type_Info_Bit_Set: - if v.underlying != nil { - return is_endian_platform(v.underlying) - } - return true + return is_endian_platform(v.underlying) case Type_Info_Pointer: return true } @@ -466,11 +478,13 @@ is_endian_little :: proc(info: ^Type_Info) -> bool { return ODIN_ENDIAN == .Little } return v.endianness == .Little - case Type_Info_Bit_Set: - if v.underlying != nil { - return is_endian_platform(v.underlying) + case Type_Info_Float: + if v.endianness == .Platform { + return ODIN_ENDIAN == .Little } - return ODIN_ENDIAN == .Little + return v.endianness == .Little + case Type_Info_Bit_Set: + return is_endian_little(v.underlying) case Type_Info_Pointer: return ODIN_ENDIAN == .Little } @@ -491,11 +505,13 @@ is_endian_big :: proc(info: ^Type_Info) -> bool { return ODIN_ENDIAN == .Big } return v.endianness == .Big - case Type_Info_Bit_Set: - if v.underlying != nil { - return is_endian_platform(v.underlying) + case Type_Info_Float: + if v.endianness == .Platform { + return ODIN_ENDIAN == .Big } - return ODIN_ENDIAN == .Big + return v.endianness == .Big + case Type_Info_Bit_Set: + return is_endian_big(v.underlying) case Type_Info_Pointer: return ODIN_ENDIAN == .Big } @@ -670,6 +686,12 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt io.write_string(w, "[]", &n) or_return write_type(w, info.elem, &n) or_return + case Type_Info_Fixed_Capacity_Dynamic_Array: + io.write_string(w, "[dynamic; ", &n) or_return + io.write_i64(w, i64(info.capacity), 10, &n) or_return + io.write_string(w, "]", &n) or_return + write_type(w, info.elem, &n) or_return + case Type_Info_Map: io.write_string(w, "map[", &n) or_return write_type(w, info.key, &n) or_return @@ -696,9 +718,10 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt } io.write_string(w, "struct ", &n) or_return - if .packed in info.flags { io.write_string(w, "#packed ", &n) or_return } - if .raw_union in info.flags { io.write_string(w, "#raw_union ", &n) or_return } + if .packed in info.flags { io.write_string(w, "#packed ", &n) or_return } + if .raw_union in info.flags { io.write_string(w, "#raw_union ", &n) or_return } if .all_or_none in info.flags { io.write_string(w, "#all_or_none ", &n) or_return } + if .simple in info.flags { io.write_string(w, "#simple ", &n) or_return } if .align in info.flags { io.write_string(w, "#align(", &n) or_return io.write_i64(w, i64(ti.align), 10, &n) or_return @@ -753,7 +776,7 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt io.write_string(w, "..=", &n) or_return io.write_i64(w, info.upper, 10, &n) or_return } - if info.underlying != nil { + if info.explicit_underlying { io.write_string(w, "; ", &n) or_return write_type(w, info.underlying, &n) or_return } @@ -837,6 +860,8 @@ has_no_indirections :: proc(ti: ^Type_Info) -> bool { return has_no_indirections(info.elem) case Type_Info_Enumerated_Array: return has_no_indirections(info.elem) + case Type_Info_Fixed_Capacity_Dynamic_Array: + return has_no_indirections(info.elem) case Type_Info_Simd_Vector: return true diff --git a/core/simd/arm/aes.odin b/core/simd/arm/aes.odin new file mode 100644 index 000000000..b1f44e52c --- /dev/null +++ b/core/simd/arm/aes.odin @@ -0,0 +1,34 @@ +#+build arm64,arm32 +package simd_arm + +@(require_results, enable_target_feature = "aes") +vaeseq_u8 :: #force_inline proc "c" (data, key: uint8x16_t) -> uint8x16_t { + return _vaeseq_u8(data, key) +} + +@(require_results, enable_target_feature = "aes") +vaesdq_u8 :: #force_inline proc "c" (data, key: uint8x16_t) -> uint8x16_t { + return _vaesdq_u8(data, key) +} + +@(require_results, enable_target_feature = "aes") +vaesmcq_u8 :: #force_inline proc "c" (data: uint8x16_t) -> uint8x16_t { + return _vaesmcq_u8(data) +} + +@(require_results,enable_target_feature = "aes") +vaesimcq_u8 :: #force_inline proc "c" (data: uint8x16_t) -> uint8x16_t { + return _vaesimcq_u8(data) +} + +@(private, default_calling_convention = "none") +foreign _ { + @(link_name = "llvm.aarch64.crypto.aese" when ODIN_ARCH == .arm64 else "llvm.arm.neon.aese") + _vaeseq_u8 :: proc(data, key: uint8x16_t) -> uint8x16_t --- + @(link_name = "llvm.aarch64.crypto.aesd" when ODIN_ARCH == .arm64 else "llvm.arm.neon.aesd") + _vaesdq_u8 :: proc(data, key: uint8x16_t) -> uint8x16_t --- + @(link_name = "llvm.aarch64.crypto.aesmc" when ODIN_ARCH == .arm64 else "llvm.arm.neon.aesmc") + _vaesmcq_u8 :: proc(data: uint8x16_t) -> uint8x16_t --- + @(link_name = "llvm.aarch64.crypto.aesimc" when ODIN_ARCH == .arm64 else "llvm.arm.neon.aesimc") + _vaesimcq_u8 :: proc(data: uint8x16_t) -> uint8x16_t --- +} diff --git a/core/simd/arm/doc.odin b/core/simd/arm/doc.odin new file mode 100644 index 000000000..ecedc7bac --- /dev/null +++ b/core/simd/arm/doc.odin @@ -0,0 +1,2 @@ +// `SIMD` intrinsics specific to ARMv8 `arm32` and `arm64` architectures. +package simd_arm \ No newline at end of file diff --git a/core/simd/arm/sha.odin b/core/simd/arm/sha.odin new file mode 100644 index 000000000..ca87c9795 --- /dev/null +++ b/core/simd/arm/sha.odin @@ -0,0 +1,108 @@ +#+build arm64,arm32 +package simd_arm + +@(require_results, enable_target_feature = "sha2") +vsha1cq_u32 :: #force_inline proc "c" (hash_abcd: uint32x4_t, e: uint32_t, wk: uint32x4_t) -> uint32x4_t { + return _vsha1cq_u32(hash_abcd, e, wk) +} + +@(require_results, enable_target_feature = "sha2") +vsha1pq_u32 :: #force_inline proc "c" (hash_abcd: uint32x4_t, e: uint32_t, wk: uint32x4_t) -> uint32x4_t { + return _vsha1pq_u32(hash_abcd, e, wk) +} + +@(require_results, enable_target_feature = "sha2") +vsha1mq_u32 :: #force_inline proc "c" (hash_abcd: uint32x4_t, e: uint32_t, wk: uint32x4_t) -> uint32x4_t { + return _vsha1mq_u32(hash_abcd, e, wk) +} + +@(require_results, enable_target_feature = "sha2") +vsha1h_u32 :: #force_inline proc "c" (e: uint32_t) -> uint32_t { + return _vsha1h_u32(e) +} + +@(require_results, enable_target_feature = "sha2") +vsha1su0q_u32 :: #force_inline proc "c" (w0_3, w4_7, w8_11: uint32x4_t) -> uint32x4_t { + return _vsha1su0q_u32(w0_3, w4_7, w8_11) +} + +@(require_results, enable_target_feature = "sha2") +vsha1su1q_u32 :: #force_inline proc "c" (tw0_3, w12_15: uint32x4_t) -> uint32x4_t { + return _vsha1su1q_u32(tw0_3, w12_15) +} + +@(require_results, enable_target_feature = "sha2") +vsha256hq_u32 :: #force_inline proc "c" (hash_abcd, hash_efgh, wk: uint32x4_t) -> uint32x4_t { + return _vsha256hq_u32(hash_abcd, hash_efgh, wk) +} + +@(require_results, enable_target_feature = "sha2") +vsha256h2q_u32 :: #force_inline proc "c" (hash_efgh, hash_abcd, wk: uint32x4_t) -> uint32x4_t { + return _vsha256h2q_u32(hash_efgh, hash_abcd, wk) +} + +@(require_results, enable_target_feature = "sha2") +vsha256su0q_u32 :: #force_inline proc "c" (w0_3, w4_7: uint32x4_t) -> uint32x4_t { + return _vsha256su0q_u32(w0_3, w4_7) +} + +@(require_results, enable_target_feature = "sha2") +vsha256su1q_u32 :: #force_inline proc "c" (tw0_3, w8_11, w12_15: uint32x4_t) -> uint32x4_t { + return _vsha256su1q_u32(tw0_3, w8_11, w12_15) +} + +// Note: The SHA512 instructions are part of the `sha3` feature set. + +@(require_results, enable_target_feature = "sha3") +vsha512hq_u64 :: #force_inline proc "c" (hash_ed, hash_gf, kwh_kwh2: uint64x2_t) -> uint64x2_t { + return _vsha512hq_u64(hash_ed, hash_gf, kwh_kwh2) +} + +@(require_results, enable_target_feature = "sha3") +vsha512h2q_u64 :: #force_inline proc "c" (sum_ab, hash_c_, hash_ab: uint64x2_t) -> uint64x2_t { + return _vsha512h2q_u64(sum_ab, hash_c_, hash_ab) +} + +@(require_results, enable_target_feature = "sha3") +vsha512su0q_u64 :: #force_inline proc "c" (w0_1, w2_: uint64x2_t) -> uint64x2_t { + return _vsha512su0q_u64(w0_1, w2_) +} + +@(require_results, enable_target_feature = "sha3") +vsha512su1q_u64 :: #force_inline proc "c" (s01_s02, w14_15, w9_10: uint64x2_t) -> uint64x2_t { + return _vsha512su1q_u64(s01_s02, w14_15, w9_10) +} + +@(private, default_calling_convention = "none") +foreign _ { + @(link_name = "llvm.aarch64.crypto.sha1c" when ODIN_ARCH == .arm64 else "llvm.arm.neon.sha1c") + _vsha1cq_u32 :: proc(hash_abcd: uint32x4_t, e: uint32_t, wk: uint32x4_t) -> uint32x4_t --- + @(link_name = "llvm.aarch64.crypto.sha1p" when ODIN_ARCH == .arm64 else "llvm.arm.neon.sha1p") + _vsha1pq_u32 :: proc(hash_abcd: uint32x4_t, e: uint32_t, wk: uint32x4_t) -> uint32x4_t --- + @(link_name = "llvm.aarch64.crypto.sha1m" when ODIN_ARCH == .arm64 else "llvm.arm.neon.sha1m") + _vsha1mq_u32 :: proc(hash_abcd: uint32x4_t, e: uint32_t, wk: uint32x4_t) -> uint32x4_t --- + @(link_name = "llvm.aarch64.crypto.sha1h" when ODIN_ARCH == .arm64 else "llvm.arm.neon.sha1h") + _vsha1h_u32 :: proc(e: uint32_t) -> uint32_t --- + @(link_name = "llvm.aarch64.crypto.sha1su0" when ODIN_ARCH == .arm64 else "llvm.arm.neon.sha1su0") + _vsha1su0q_u32 :: proc(w0_3, w4_7, w8_11: uint32x4_t) -> uint32x4_t --- + @(link_name = "llvm.aarch64.crypto.sha1su1" when ODIN_ARCH == .arm64 else "llvm.arm.neon.sha1su1") + _vsha1su1q_u32 :: proc(tw0_3, w12_15: uint32x4_t) -> uint32x4_t --- + + @(link_name = "llvm.aarch64.crypto.sha256h" when ODIN_ARCH == .arm64 else "llvm.arm.neon.sha256h") + _vsha256hq_u32 :: proc(hash_abcd, hash_efgh, wk: uint32x4_t) -> uint32x4_t --- + @(link_name = "llvm.aarch64.crypto.sha256h2" when ODIN_ARCH == .arm64 else "llvm.arm.neon.sha256h2") + _vsha256h2q_u32 :: proc(hash_efgh, hash_abcd, wk: uint32x4_t) -> uint32x4_t --- + @(link_name = "llvm.aarch64.crypto.sha256su0" when ODIN_ARCH == .arm64 else "llvm.arm.neon.sha256su0") + _vsha256su0q_u32 :: proc(w0_3, w4_7: uint32x4_t) -> uint32x4_t --- + @(link_name = "llvm.aarch64.crypto.sha256su1" when ODIN_ARCH == .arm64 else "llvm.arm.neon.sha256su1") + _vsha256su1q_u32 :: proc(tw0_3, w8_11, w12_15: uint32x4_t) -> uint32x4_t --- + + @(link_name = "llvm.aarch64.crypto.sha512h" when ODIN_ARCH == .arm64 else "llvm.arm.neon.sha512h") + _vsha512hq_u64 :: proc(hash_ed, hash_gf, kwh_kwh2: uint64x2_t) -> uint64x2_t --- + @(link_name = "llvm.aarch64.crypto.sha512h2" when ODIN_ARCH == .arm64 else "llvm.arm.neon.sha512h2") + _vsha512h2q_u64 :: proc(sum_ab, hash_c_, hash_ab: uint64x2_t) -> uint64x2_t --- + @(link_name = "llvm.aarch64.crypto.sha512su0" when ODIN_ARCH == .arm64 else "llvm.arm.neon.sha512su0") + _vsha512su0q_u64 :: proc(w0_1, w2_: uint64x2_t) -> uint64x2_t --- + @(link_name = "llvm.aarch64.crypto.sha512su1" when ODIN_ARCH == .arm64 else "llvm.arm.neon.sha512su1") + _vsha512su1q_u64 :: proc(s01_s02, w14_15, w9_10: uint64x2_t) -> uint64x2_t --- +} diff --git a/core/simd/arm/types.odin b/core/simd/arm/types.odin new file mode 100644 index 000000000..05e3540b6 --- /dev/null +++ b/core/simd/arm/types.odin @@ -0,0 +1,9 @@ +#+build arm64,arm32 +package simd_arm + +// Type aliases to match `arm_neon.h`. +uint32_t :: u32 + +uint8x16_t :: #simd[16]u8 +uint32x4_t :: #simd[4]u32 +uint64x2_t :: #simd[2]u64 diff --git a/core/simd/simd.odin b/core/simd/simd.odin index 14bf03f43..52c97cc45 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -493,7 +493,7 @@ Example: +-------+-------+-------+-------+ res: +-------+-------+-------+--------+ - | 0x04 | 0x2a | 0 | 0xff | + | 0x04 | 0x2a | 0 | 0x7f | +-------+-------+-------+--------+ */ shr :: intrinsics.simd_shr @@ -581,7 +581,7 @@ Example: +-------+-------+-------+-------+ res: +-------+-------+-------+--------+ - | 0x04 | 0x2a | 0x01 | 0xff | + | 0x04 | 0x2a | 0x01 | 0x7f | +-------+-------+-------+--------+ */ shr_masked :: intrinsics.simd_shr_masked @@ -2207,7 +2207,7 @@ swizzle :: builtin.swizzle /* Extract the set of most-significant bits of a SIMD vector. -This procedure checks the the most-significant bit (MSB) for each lane of vector +This procedure checks the most-significant bit (MSB) for each lane of vector and returns the numbers of lanes with the most-significant bit set. This procedure can be used in conjuction with `lanes_eq` (and other similar procedures) to count the number of matched lanes by computing the cardinality of the resulting @@ -2253,7 +2253,7 @@ extract_msbs :: intrinsics.simd_extract_msbs /* Extract the set of least-significant bits of a SIMD vector. -This procedure checks the the least-significant bit (LSB) for each lane of vector +This procedure checks the least-significant bit (LSB) for each lane of vector and returns the numbers of lanes with the least-significant bit set. This procedure can be used in conjuction with `lanes_eq` (and other similar procedures) to count the number of matched lanes by computing the cardinality of the resulting diff --git a/core/simd/x86/sse41.odin b/core/simd/x86/sse41.odin index 81089ed63..510f5d8e9 100644 --- a/core/simd/x86/sse41.odin +++ b/core/simd/x86/sse41.odin @@ -26,7 +26,18 @@ _mm_blendv_epi8 :: #force_inline proc "c" (a, b, mask: __m128i) -> __m128i { } @(require_results, enable_target_feature="sse4.1") _mm_blend_epi16 :: #force_inline proc "c" (a, b: __m128i, $IMM8: u8) -> __m128i { - return transmute(__m128i)pblendw(transmute(i16x8)a, transmute(i16x8)b, IMM8) + return transmute(__m128i)simd.shuffle( + transmute(i16x8)b, + transmute(i16x8)a, + 0 when (IMM8 >> 0) & 1 == 1 else 8, + 1 when (IMM8 >> 1) & 1 == 1 else 9, + 2 when (IMM8 >> 2) & 1 == 1 else 10, + 3 when (IMM8 >> 3) & 1 == 1 else 11, + 4 when (IMM8 >> 4) & 1 == 1 else 12, + 5 when (IMM8 >> 5) & 1 == 1 else 13, + 6 when (IMM8 >> 6) & 1 == 1 else 14, + 7 when (IMM8 >> 7) & 1 == 1 else 15, + ) } @(require_results, enable_target_feature="sse4.1") _mm_blendv_pd :: #force_inline proc "c" (a, b, mask: __m128d) -> __m128d { @@ -303,8 +314,6 @@ foreign _ { blendpd :: proc(a, b: __m128d, #const imm2: u8) -> __m128d --- @(link_name = "llvm.x86.sse41.blendps") blendps :: proc(a, b: __m128, #const imm4: u8) -> __m128 --- - @(link_name = "llvm.x86.sse41.pblendw") - pblendw :: proc(a: i16x8, b: i16x8, #const imm8: u8) -> i16x8 --- @(link_name = "llvm.x86.sse41.insertps") insertps :: proc(a, b: __m128, #const imm8: u8) -> __m128 --- @(link_name = "llvm.x86.sse41.pmaxsb") diff --git a/core/simd/x86/types.odin b/core/simd/x86/types.odin index ea0eff534..1b52f22f1 100644 --- a/core/simd/x86/types.odin +++ b/core/simd/x86/types.odin @@ -22,25 +22,25 @@ __m256bh :: #simd[16]bf16 __m512bh :: #simd[32]bf16 -/// The `__mmask64` type used in AVX-512 intrinsics, a 64-bit integer +// The `__mmask64` type used in AVX-512 intrinsics, a 64-bit integer __mmask64 :: u64 -/// The `__mmask32` type used in AVX-512 intrinsics, a 32-bit integer +// The `__mmask32` type used in AVX-512 intrinsics, a 32-bit integer __mmask32 :: u32 -/// The `__mmask16` type used in AVX-512 intrinsics, a 16-bit integer +// The `__mmask16` type used in AVX-512 intrinsics, a 16-bit integer __mmask16 :: u16 -/// The `__mmask8` type used in AVX-512 intrinsics, a 8-bit integer +// The `__mmask8` type used in AVX-512 intrinsics, a 8-bit integer __mmask8 :: u8 -/// The `_MM_CMPINT_ENUM` type used to specify comparison operations in AVX-512 intrinsics. +// The `_MM_CMPINT_ENUM` type used to specify comparison operations in AVX-512 intrinsics. _MM_CMPINT_ENUM :: i32 -/// The `MM_MANTISSA_NORM_ENUM` type used to specify mantissa normalized operations in AVX-512 intrinsics. +// The `MM_MANTISSA_NORM_ENUM` type used to specify mantissa normalized operations in AVX-512 intrinsics. _MM_MANTISSA_NORM_ENUM :: i32 -/// The `MM_MANTISSA_SIGN_ENUM` type used to specify mantissa signed operations in AVX-512 intrinsics. +// The `MM_MANTISSA_SIGN_ENUM` type used to specify mantissa signed operations in AVX-512 intrinsics. _MM_MANTISSA_SIGN_ENUM :: i32 _MM_PERM_ENUM :: i32 diff --git a/core/slice/map.odin b/core/slice/map.odin index c68488d26..fafbb55ee 100644 --- a/core/slice/map.odin +++ b/core/slice/map.odin @@ -6,8 +6,8 @@ import "base:runtime" _ :: intrinsics _ :: runtime -map_keys :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (keys: []K, err: runtime.Allocator_Error) { - keys = make(type_of(keys), len(m), allocator) or_return +map_keys :: proc(m: $M/map[$K]$V, allocator := context.allocator, loc := #caller_location) -> (keys: []K, err: runtime.Allocator_Error) { + keys = make(type_of(keys), len(m), allocator, loc) or_return i := 0 for key in m { keys[i] = key @@ -15,8 +15,8 @@ map_keys :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (keys: []K, } return } -map_values :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (values: []V, err: runtime.Allocator_Error) { - values = make(type_of(values), len(m), allocator) or_return +map_values :: proc(m: $M/map[$K]$V, allocator := context.allocator, loc := #caller_location) -> (values: []V, err: runtime.Allocator_Error) { + values = make(type_of(values), len(m), allocator, loc) or_return i := 0 for _, value in m { values[i] = value @@ -37,8 +37,8 @@ Map_Entry_Info :: struct($Key, $Value: typeid) { } -map_entries :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (entries: []Map_Entry(K, V), err: runtime.Allocator_Error) { - entries = make(type_of(entries), len(m), allocator) or_return +map_entries :: proc(m: $M/map[$K]$V, allocator := context.allocator, loc := #caller_location) -> (entries: []Map_Entry(K, V), err: runtime.Allocator_Error) { + entries = make(type_of(entries), len(m), allocator, loc) or_return i := 0 for key, value in m { entries[i].key = key @@ -48,13 +48,13 @@ map_entries :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (entries return } -map_entry_infos :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (entries: []Map_Entry_Info(K, V), err: runtime.Allocator_Error) #no_bounds_check { +map_entry_infos :: proc(m: $M/map[$K]$V, allocator := context.allocator, loc := #caller_location) -> (entries: []Map_Entry_Info(K, V), err: runtime.Allocator_Error) #no_bounds_check { m := m rm := (^runtime.Raw_Map)(&m) info := runtime.type_info_base(type_info_of(M)).variant.(runtime.Type_Info_Map) if info.map_info != nil { - entries = make(type_of(entries), len(m), allocator) or_return + entries = make(type_of(entries), len(m), allocator, loc) or_return map_cap := uintptr(cap(m)) ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(rm^, info.map_info) diff --git a/core/slice/permute.odin b/core/slice/permute.odin index 42b6d4129..280989e47 100644 --- a/core/slice/permute.odin +++ b/core/slice/permute.odin @@ -29,12 +29,13 @@ Returns: make_permutation_iterator :: proc( slice: []$T, allocator := context.allocator, + loc := #caller_location, ) -> ( iter: Permutation_Iterator(T), error: runtime.Allocator_Error, ) #optional_allocator_error { iter.slice = slice - iter.counters = make([]int, len(iter.slice), allocator) or_return + iter.counters = make([]int, len(iter.slice), allocator, loc) or_return return } diff --git a/core/slice/slice.odin b/core/slice/slice.odin index 0d0cadefa..0df55320b 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -3,12 +3,10 @@ package slice import "base:intrinsics" import "base:builtin" -import "core:math/bits" import "base:runtime" _ :: intrinsics _ :: builtin -_ :: bits _ :: runtime /* @@ -41,7 +39,7 @@ to_bytes :: proc "contextless" (s: []$T) -> []byte { Turns a byte slice into a type. */ @(require_results) -to_type :: proc(buf: []u8, $T: typeid) -> (T, bool) #optional_ok { +to_type :: proc "contextless" (buf: []u8, $T: typeid) -> (T, bool) #optional_ok { if len(buf) < size_of(T) { return {}, false } @@ -105,7 +103,7 @@ swap :: proc(array: $T/[]$E, a, b: int) { } } -swap_between :: proc(a, b: $T/[]$E) { +swap_between :: proc "contextless" (a, b: $T/[]$E) #no_bounds_check { n := builtin.min(len(a), len(b)) if n >= 0 { ptr_swap_overlapping(&a[0], &b[0], size_of(E)*n) @@ -122,7 +120,7 @@ reverse :: proc(array: $T/[]$E) { @(require_results) -contains :: proc(array: $T/[]$E, value: E) -> bool where intrinsics.type_is_comparable(E) { +contains :: proc "contextless" (array: $T/[]$E, value: E) -> bool where intrinsics.type_is_comparable(E) { _, found := linear_search(array, value) return found } @@ -156,7 +154,7 @@ Example: assert(index == 1 && found == true) */ @(require_results) -linear_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool) +linear_search :: proc "contextless" (array: $A/[]$T, key: T) -> (index: int, found: bool) where intrinsics.type_is_comparable(T) { for x, i in array { if x == key { @@ -219,7 +217,7 @@ Example: assert(index == 1 && found == true) */ @(require_results) -linear_search_reverse :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool) +linear_search_reverse :: proc "contextless" (array: $A/[]$T, key: T) -> (index: int, found: bool) where intrinsics.type_is_comparable(T) { #reverse for x, i in array { if x == key { @@ -327,7 +325,7 @@ binary_search_by :: proc(array: $A/[]$T, key: $K, f: proc(T, K) -> Ordering) -> } @(require_results) -equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) #no_bounds_check { +equal :: proc "contextless" (a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) #no_bounds_check { if len(a) != len(b) { return false } @@ -355,7 +353,7 @@ equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) #no_ } @(require_results) -simple_equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_simple_compare(E) { +simple_equal :: proc "contextless" (a, b: $T/[]$E) -> bool where intrinsics.type_is_simple_compare(E) { if len(a) != len(b) { return false } @@ -370,7 +368,7 @@ simple_equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_simple_comp slice.prefix_length([]u8{1, 2, 3, 4}, []u8{2, 3, 4}) -> 0 */ @(require_results) -prefix_length :: proc(a, b: $T/[]$E) -> (n: int) where intrinsics.type_is_comparable(E) { +prefix_length :: proc "contextless" (a, b: $T/[]$E) -> (n: int) where intrinsics.type_is_comparable(E) { _len := builtin.min(len(a), len(b)) #no_bounds_check for n < _len && a[n] == b[n] { @@ -380,7 +378,7 @@ prefix_length :: proc(a, b: $T/[]$E) -> (n: int) where intrinsics.type_is_compar } @(require_results) -has_prefix :: proc(array: $T/[]$E, needle: T) -> bool where intrinsics.type_is_comparable(E) { +has_prefix :: proc "contextless" (array: $T/[]$E, needle: T) -> bool where intrinsics.type_is_comparable(E) { n := len(needle) if len(array) >= n { return equal(array[:n], needle) @@ -398,7 +396,7 @@ has_prefix :: proc(array: $T/[]$E, needle: T) -> bool where intrinsics.type_is_c slice.suffix_length([]u8{3, 4, 5}, []u8{3, 5}) -> 1 */ @(require_results) -suffix_length :: proc(a, b: $T/[]$E) -> (n: int) where intrinsics.type_is_comparable(E) { +suffix_length :: proc "contextless" (a, b: $T/[]$E) -> (n: int) where intrinsics.type_is_comparable(E) { len_a, len_b := len(a), len(b) _len := builtin.min(len_a, len_b) @@ -409,7 +407,7 @@ suffix_length :: proc(a, b: $T/[]$E) -> (n: int) where intrinsics.type_is_compar } @(require_results) -has_suffix :: proc(array: $T/[]$E, needle: T) -> bool where intrinsics.type_is_comparable(E) { +has_suffix :: proc "contextless" (array: $T/[]$E, needle: T) -> bool where intrinsics.type_is_comparable(E) { array := array m, n := len(array), len(needle) if m >= n { @@ -418,13 +416,13 @@ has_suffix :: proc(array: $T/[]$E, needle: T) -> bool where intrinsics.type_is_c return false } -zero :: proc(array: $T/[]$E) #no_bounds_check { +zero :: proc "contextless" (array: $T/[]$E) #no_bounds_check { if len(array) > 0 { intrinsics.mem_zero(raw_data(array), size_of(E)*len(array)) } } -fill :: proc(array: $T/[]$E, value: E) #no_bounds_check { +fill :: proc "contextless" (array: $T/[]$E, value: E) #no_bounds_check { if len(array) <= 0 { return } @@ -434,7 +432,7 @@ fill :: proc(array: $T/[]$E, value: E) #no_bounds_check { } } -rotate_left :: proc(array: $T/[]$E, mid: int) { +rotate_left :: proc "contextless" (array: $T/[]$E, mid: int) { n := len(array) m := mid %% n k := n - m @@ -443,7 +441,7 @@ rotate_left :: proc(array: $T/[]$E, mid: int) { p := cast(^E)raw_data(array) ptr_rotate(m, ptr_add(p, m), k) } -rotate_right :: proc(array: $T/[]$E, k: int) { +rotate_right :: proc "contextless" (array: $T/[]$E, k: int) { rotate_left(array, -k) } @@ -454,7 +452,7 @@ swap_with_slice :: proc(a, b: $T/[]$E, loc := #caller_location) { } @(require_results) -concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T, err: runtime.Allocator_Error) #optional_allocator_error { +concatenate :: proc(a: []$T/[]$E, allocator := context.allocator, loc := #caller_location) -> (res: T, err: runtime.Allocator_Error) #optional_allocator_error { if len(a) == 0 { return } @@ -462,7 +460,7 @@ concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T, er for s in a { n += len(s) } - res = make(T, n, allocator) or_return + res = make(T, n, allocator, loc) or_return i := 0 for s in a { i += copy(res[i:], s) @@ -480,6 +478,7 @@ clone :: proc(a: $T/[]$E, allocator := context.allocator, loc := #caller_locatio // copies slice into a new dynamic array +@(require_results) clone_to_dynamic :: proc(a: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> ([dynamic]E, runtime.Allocator_Error) #optional_allocator_error { d, err := make([dynamic]E, len(a), allocator, loc) copy(d[:], a) @@ -502,11 +501,11 @@ into_dynamic :: proc(a: $T/[]$E) -> [dynamic]E { @(require_results) -length :: proc(a: $T/[]$E) -> int { +length :: proc "contextless" (a: $T/[]$E) -> int { return len(a) } @(require_results) -is_empty :: proc(a: $T/[]$E) -> bool { +is_empty :: proc "contextless" (a: $T/[]$E) -> bool { return len(a) == 0 } @@ -560,16 +559,16 @@ last_ptr :: proc(array: $T/[]$E) -> ^E { } @(require_results) -get :: proc(array: $T/[]$E, index: int) -> (value: E, ok: bool) { - if uint(index) < len(array) { +get :: proc "contextless" (array: $T/[]$E, index: int) -> (value: E, ok: bool) { + #bounds_check if uint(index) < len(array) { value = array[index] ok = true } return } @(require_results) -get_ptr :: proc(array: $T/[]$E, index: int) -> (value: ^E, ok: bool) { - if uint(index) < len(array) { +get_ptr :: proc "contextless" (array: $T/[]$E, index: int) -> (value: ^E, ok: bool) { + #no_bounds_check if uint(index) < len(array) { value = &array[index] ok = true } @@ -577,14 +576,14 @@ get_ptr :: proc(array: $T/[]$E, index: int) -> (value: ^E, ok: bool) { } @(require_results) -as_ptr :: proc(array: $T/[]$E) -> [^]E { +as_ptr :: proc "contextless" (array: $T/[]$E) -> [^]E { return raw_data(array) } @(require_results) -mapper :: proc(s: $S/[]$U, f: proc(U) -> $V, allocator := context.allocator) -> (r: []V, err: runtime.Allocator_Error) #optional_allocator_error { - r = make([]V, len(s), allocator) or_return +mapper :: proc(s: $S/[]$U, f: proc(U) -> $V, allocator := context.allocator, loc := #caller_location) -> (r: []V, err: runtime.Allocator_Error) #optional_allocator_error { + r = make([]V, len(s), allocator, loc) or_return for v, i in s { r[i] = f(v) } @@ -610,33 +609,33 @@ reduce_reverse :: proc(s: $S/[]$U, initializer: $V, f: proc(V, U) -> V) -> V { } @(require_results) -filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) -> (res: S, err: runtime.Allocator_Error) #optional_allocator_error { - r := make([dynamic]U, 0, 0, allocator) or_return +filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator, loc := #caller_location) -> (res: S, err: runtime.Allocator_Error) #optional_allocator_error { + r := make([dynamic]U, 0, 0, allocator, loc) or_return for v in s { if f(v) { - append(&r, v) + append(&r, v, loc) } } return r[:], nil } @(require_results) -filter_reverse :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) -> (res: S, err: runtime.Allocator_Error) #optional_allocator_error { - r := make([dynamic]U, 0, 0, allocator) or_return +filter_reverse :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator, loc := #caller_location) -> (res: S, err: runtime.Allocator_Error) #optional_allocator_error { + r := make([dynamic]U, 0, 0, allocator, loc) or_return for i := len(s)-1; i >= 0; i -= 1 { #no_bounds_check v := s[i] if f(v) { - append(&r, v) + append(&r, v, loc) } } return r[:], nil } @(require_results) -scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := context.allocator) -> (res: []V, err: runtime.Allocator_Error) #optional_allocator_error { +scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := context.allocator, loc := #caller_location) -> (res: []V, err: runtime.Allocator_Error) #optional_allocator_error { if len(s) == 0 { return } - res = make([]V, len(s), allocator) or_return + res = make([]V, len(s), allocator, loc) or_return p := as_ptr(s) q := as_ptr(res) r := initializer @@ -653,14 +652,14 @@ scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := c @(require_results) -repeat :: proc(s: $S/[]$U, count: int, allocator := context.allocator) -> (b: S, err: runtime.Allocator_Error) #optional_allocator_error { +repeat :: proc(s: $S/[]$U, count: int, allocator := context.allocator, loc := #caller_location) -> (b: S, err: runtime.Allocator_Error) #optional_allocator_error { if count < 0 { panic("slice: negative repeat count") } else if count > 0 && (len(s)*count)/count != len(s) { panic("slice: repeat count will cause an overflow") } - b = make(S, len(s)*count, allocator) or_return + b = make(S, len(s)*count, allocator, loc) or_return i := copy(b, s) for i < len(b) { // 2^N trick to reduce the need to copy copy(b[i:], b[:i]) @@ -672,7 +671,7 @@ repeat :: proc(s: $S/[]$U, count: int, allocator := context.allocator) -> (b: S, // 'unique' replaces consecutive runs of equal elements with a single copy. // The procedures modifies the slice in-place and returns the modified slice. @(require_results) -unique :: proc(s: $S/[]$T) -> S where intrinsics.type_is_comparable(T) #no_bounds_check { +unique :: proc "contextless" (s: $S/[]$T) -> S where intrinsics.type_is_comparable(T) #no_bounds_check { if len(s) < 2 { return s } @@ -711,7 +710,7 @@ unique_proc :: proc(s: $S/[]$T, eq: proc(T, T) -> bool) -> S #no_bounds_check { @(require_results) -min :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok { +min :: proc "contextless" (s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok { if len(s) != 0 { res = s[0] ok = true @@ -722,7 +721,7 @@ min :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T return } @(require_results) -max :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok { +max :: proc "contextless" (s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok { if len(s) != 0 { res = s[0] ok = true @@ -734,7 +733,7 @@ max :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T } @(require_results) -min_max :: proc(s: $S/[]$T) -> (min, max: T, ok: bool) where intrinsics.type_is_ordered(T) { +min_max :: proc "contextless" (s: $S/[]$T) -> (min, max: T, ok: bool) where intrinsics.type_is_ordered(T) { if len(s) != 0 { min, max = s[0], s[0] ok = true @@ -748,7 +747,7 @@ min_max :: proc(s: $S/[]$T) -> (min, max: T, ok: bool) where intrinsics.type_is_ // Find the index of the (first) minimum element in a slice. @(require_results) -min_index :: proc(s: $S/[]$T) -> (min_index: int, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok { +min_index :: proc "contextless" (s: $S/[]$T) -> (min_index: int, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok { if len(s) == 0 { return -1, false } @@ -765,7 +764,7 @@ min_index :: proc(s: $S/[]$T) -> (min_index: int, ok: bool) where intrinsics.typ // Find the index of the (first) maximum element in a slice. @(require_results) -max_index :: proc(s: $S/[]$T) -> (max_index: int, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok { +max_index :: proc "contextless" (s: $S/[]$T) -> (max_index: int, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok { if len(s) == 0 { return -1, false } @@ -781,7 +780,7 @@ max_index :: proc(s: $S/[]$T) -> (max_index: int, ok: bool) where intrinsics.typ } @(require_results) -any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) { +any_of :: proc "contextless" (s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) { for v in s { if v == value { return true @@ -791,7 +790,7 @@ any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable } @(require_results) -none_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) { +none_of :: proc "contextless" (s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) { for v in s { if v == value { return false @@ -801,7 +800,7 @@ none_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparabl } @(require_results) -all_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) { +all_of :: proc "contextless" (s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) { if len(s) == 0 { return false } @@ -849,7 +848,7 @@ all_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool { @(require_results) -count :: proc(s: $S/[]$T, value: T) -> (n: int) where intrinsics.type_is_comparable(T) { +count :: proc "contextless" (s: $S/[]$T, value: T) -> (n: int) where intrinsics.type_is_comparable(T) { for v in s { if v == value { n += 1 @@ -870,7 +869,7 @@ count_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> (n: int) { @(require_results) -dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool) +dot_product :: proc "contextless" (a, b: $S/[]$T) -> (r: T, ok: bool) where intrinsics.type_is_numeric(T) { if len(a) != len(b) { return @@ -884,7 +883,7 @@ dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool) // Convert a pointer to an enumerated array to a slice of the element type @(require_results) -enumerated_array :: proc(ptr: ^$T) -> []intrinsics.type_elem_type(T) +enumerated_array :: proc "contextless" (ptr: ^$T) -> []intrinsics.type_elem_type(T) where intrinsics.type_is_enumerated_array(T) { return ([^]intrinsics.type_elem_type(T))(ptr)[:len(T)] } @@ -893,7 +892,7 @@ enumerated_array :: proc(ptr: ^$T) -> []intrinsics.type_elem_type(T) // e.g.: // bs := slice.enum_slice_to_bitset(my_flag_slice, rl.ConfigFlags) @(require_results) -enum_slice_to_bitset :: proc(enums: []$E, $T: typeid/bit_set[E]) -> (bits: T) where intrinsics.type_is_enum(E), intrinsics.type_bit_set_elem_type(T) == E { +enum_slice_to_bitset :: proc "contextless" (enums: []$E, $T: typeid/bit_set[E]) -> (bits: T) where intrinsics.type_is_enum(E), intrinsics.type_bit_set_elem_type(T) == E { for v in enums { bits += {v} } @@ -917,9 +916,45 @@ bitset_to_enum_slice_with_buffer :: proc(buf: []$E, bs: $T) -> (slice: []E) wher // e.g.: // sl := slice.bitset_to_enum_slice(bs) @(require_results) -bitset_to_enum_slice_with_make :: proc(bs: $T, $E: typeid, allocator := context.allocator) -> (slice: []E) where intrinsics.type_is_enum(E), intrinsics.type_bit_set_elem_type(T) == E { - buf := make([]E, card(bs), allocator) +bitset_to_enum_slice_with_make :: proc(bs: $T, $E: typeid, allocator := context.allocator, loc := #caller_location) -> (slice: []E) where intrinsics.type_is_enum(E), intrinsics.type_bit_set_elem_type(T) == E { + buf := make([]E, card(bs), allocator, loc) return bitset_to_enum_slice(buf, bs) } bitset_to_enum_slice :: proc{bitset_to_enum_slice_with_make, bitset_to_enum_slice_with_buffer} + +/* +Removes the first n elements (`elems`) from a slice of slices, spanning inner slices and dropping empty ones. + +If `elems` is out of bounds (more than the total) this will trigger a bounds check. + +Example: + import "core:fmt" + import "core:slice" + + advance_slices_example :: proc() { + slices := [][]byte { + {1, 2, 3, 4}, + {5, 6, 7}, + } + + fmt.println(slice.advance_slices(slices, 4)) + } + +Output: + [[5, 6, 7]] +*/ +advance_slices :: proc(slices: $S/[][]$T, elems: int) -> S { + slices, elems := slices, elems + for elems > 0 { + slice := &slices[0] + take := builtin.min(elems, len(slice)) + slice^ = slice[take:] + if len(slice) == 0 { + slices = slices[1:] + } + elems -= take + } + + return slices +} diff --git a/core/slice/sort.odin b/core/slice/sort.odin index a9f8c1067..ed9d1f315 100644 --- a/core/slice/sort.odin +++ b/core/slice/sort.odin @@ -54,9 +54,9 @@ sort :: proc(data: $T/[]$E) where ORD(E) { sort_by_indices :: proc{ sort_by_indices_allocate, _sort_by_indices} -sort_by_indices_allocate :: proc(data: $T/[]$E, indices: []int, allocator := context.allocator) -> (sorted: T) { +sort_by_indices_allocate :: proc(data: $T/[]$E, indices: []int, allocator := context.allocator, loc := #caller_location) -> (sorted: T) { assert(len(data) == len(indices)) - sorted = make(T, len(data), allocator) + sorted = make(T, len(data), allocator, loc) for v, i in indices { sorted[i] = data[v] } @@ -100,8 +100,8 @@ sort_from_permutation_indices :: proc(data: $T/[]$E, indices: []int) { // sort sorts a slice and returns a slice of the original indices // This sort is not guaranteed to be stable -sort_with_indices :: proc(data: $T/[]$E, allocator := context.allocator) -> (indices: []int) where ORD(E) { - indices = make([]int, len(data), allocator) +sort_with_indices :: proc(data: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> (indices: []int) where ORD(E) { + indices = make([]int, len(data), allocator, loc) when size_of(E) != 0 { if n := len(data); n > 1 { for _, idx in indices { @@ -173,8 +173,8 @@ sort_by_with_data :: proc(data: $T/[]$E, less: proc(i, j: E, user_data: rawptr) // sort_by sorts a slice with a given procedure to test whether two values are ordered "i < j" // This sort is not guaranteed to be stable -sort_by_with_indices :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool, allocator := context.allocator) -> (indices : []int) { - indices = make([]int, len(data), allocator) +sort_by_with_indices :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool, allocator := context.allocator, loc := #caller_location) -> (indices : []int) { + indices = make([]int, len(data), allocator, loc) when size_of(E) != 0 { if n := len(data); n > 1 { for _, idx in indices { @@ -205,8 +205,8 @@ sort_by_with_indices :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool, allocat return indices } -sort_by_with_indices_with_data :: proc(data: $T/[]$E, less: proc(i, j: E, user_data: rawptr) -> bool, user_data: rawptr, allocator := context.allocator) -> (indices : []int) { - indices = make([]int, len(data), allocator) +sort_by_with_indices_with_data :: proc(data: $T/[]$E, less: proc(i, j: E, user_data: rawptr) -> bool, user_data: rawptr, allocator := context.allocator, loc := #caller_location) -> (indices : []int) { + indices = make([]int, len(data), allocator, loc) when size_of(E) != 0 { if n := len(data); n > 1 { for _, idx in indices { @@ -300,7 +300,9 @@ Example: import "core:slice" import "core:fmt" - main :: proc() { + stable_sort_by_example :: proc() { + Example :: struct { n: int, s: string } + arr := []Example { {2, "name"}, {3, "Bill"}, @@ -312,10 +314,9 @@ Example: }) for e in arr do fmt.printf("%s ", e.s) + fmt.println() } - Example :: struct { n: int, s: string } - Output: My name is Bill */ @@ -335,7 +336,9 @@ Example: import "core:slice" import "core:fmt" - main :: proc() { + stable_sort_by_cmp_example :: proc() { + Example :: struct { n: int, s: string } + arr := []Example { {2, "name"}, {3, "Bill"}, @@ -347,9 +350,9 @@ Example: }) for e in arr do fmt.printf("%s ", e.s) + fmt.println() } - Example :: struct { n: int, s: string } Output: My name is Bill */ @@ -413,7 +416,7 @@ reverse_sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) { sort_by_cmp_with_data(data, proc(i, j: E, user_data: rawptr) -> Ordering { k := (proc(i, j: E) -> Ordering)(user_data) return k(j, i) - }, rawptr(data)) + }, rawptr(cmp)) } diff --git a/core/sort/sort.odin b/core/sort/sort.odin index 63cb50490..30abc5336 100644 --- a/core/sort/sort.odin +++ b/core/sort/sort.odin @@ -2,11 +2,9 @@ package sort import "core:mem" -import _slice "core:slice" import "base:intrinsics" _ :: intrinsics -_ :: _slice ORD :: intrinsics.type_is_ordered Interface :: struct { @@ -639,7 +637,7 @@ compare_f64s :: proc(a, b: f64) -> int { compare_strings :: proc(a, b: string) -> int { x := transmute(mem.Raw_String)a y := transmute(mem.Raw_String)b - + ret := mem.compare_byte_ptrs(x.data, y.data, min(x.len, y.len)) if ret == 0 && x.len != y.len { return -1 if x.len < y.len else +1 diff --git a/core/strings/builder.odin b/core/strings/builder.odin index a6d0b24b3..79ba6108f 100644 --- a/core/strings/builder.odin +++ b/core/strings/builder.odin @@ -3,7 +3,6 @@ package strings import "base:runtime" import "core:unicode/utf8" import "core:strconv" -import "core:mem" import "core:io" /* Type definition for a procedure that flushes a Builder @@ -35,7 +34,7 @@ Returns: - res: The new Builder - err: An optional allocator error if one occured, `nil` otherwise */ -builder_make_none :: proc(allocator := context.allocator, loc := #caller_location) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error { +builder_make_none :: proc(allocator := context.allocator, loc := #caller_location) -> (res: Builder, err: runtime.Allocator_Error) #optional_allocator_error { return Builder{buf=make([dynamic]byte, allocator, loc) or_return }, nil } /* @@ -51,7 +50,7 @@ Returns: - res: The new Builder - err: An optional allocator error if one occured, `nil` otherwise */ -builder_make_len :: proc(len: int, allocator := context.allocator, loc := #caller_location) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error { +builder_make_len :: proc(len: int, allocator := context.allocator, loc := #caller_location) -> (res: Builder, err: runtime.Allocator_Error) #optional_allocator_error { return Builder{buf=make([dynamic]byte, len, allocator, loc) or_return }, nil } /* @@ -68,7 +67,7 @@ Returns: - res: The new Builder - err: An optional allocator error if one occured, `nil` otherwise */ -builder_make_len_cap :: proc(len, cap: int, allocator := context.allocator, loc := #caller_location) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error { +builder_make_len_cap :: proc(len, cap: int, allocator := context.allocator, loc := #caller_location) -> (res: Builder, err: runtime.Allocator_Error) #optional_allocator_error { return Builder{buf=make([dynamic]byte, len, cap, allocator, loc) or_return }, nil } /* @@ -116,7 +115,7 @@ Returns: - res: A pointer to the initialized Builder - err: An optional allocator error if one occured, `nil` otherwise */ -builder_init_none :: proc(b: ^Builder, allocator := context.allocator, loc := #caller_location) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error { +builder_init_none :: proc(b: ^Builder, allocator := context.allocator, loc := #caller_location) -> (res: ^Builder, err: runtime.Allocator_Error) #optional_allocator_error { b.buf = make([dynamic]byte, allocator, loc) or_return return b, nil } @@ -135,7 +134,7 @@ Returns: - res: A pointer to the initialized Builder - err: An optional allocator error if one occured, `nil` otherwise */ -builder_init_len :: proc(b: ^Builder, len: int, allocator := context.allocator, loc := #caller_location) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error { +builder_init_len :: proc(b: ^Builder, len: int, allocator := context.allocator, loc := #caller_location) -> (res: ^Builder, err: runtime.Allocator_Error) #optional_allocator_error { b.buf = make([dynamic]byte, len, allocator, loc) or_return return b, nil } @@ -153,7 +152,7 @@ Returns: - res: A pointer to the initialized Builder - err: An optional allocator error if one occured, `nil` otherwise */ -builder_init_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator, loc := #caller_location) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error { +builder_init_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator, loc := #caller_location) -> (res: ^Builder, err: runtime.Allocator_Error) #optional_allocator_error { b.buf = make([dynamic]byte, len, cap, allocator, loc) or_return return b, nil } @@ -269,8 +268,19 @@ Output: */ builder_from_bytes :: proc(backing: []byte) -> (res: Builder) { - return Builder{ buf = mem.buffer_from_slice(backing) } + return Builder{ + buf = transmute([dynamic]byte)runtime.Raw_Dynamic_Array{ + data = raw_data(backing), + len = 0, + cap = len(backing), + allocator = runtime.Allocator{ + procedure = runtime.nil_allocator_proc, + data = nil, + }, + }, + } } + // Alias to `builder_from_bytes` builder_from_slice :: builder_from_bytes /* @@ -311,7 +321,7 @@ Returns: - res: A cstring of the Builder's buffer upon success - err: An optional allocator error if one occured, `nil` otherwise */ -to_cstring :: proc(b: ^Builder, loc := #caller_location) -> (res: cstring, err: mem.Allocator_Error) #optional_allocator_error { +to_cstring :: proc(b: ^Builder, loc := #caller_location) -> (res: cstring, err: runtime.Allocator_Error) #optional_allocator_error { n := append(&b.buf, 0, loc) or_return if n != 1 { return nil, .Out_Of_Memory @@ -835,3 +845,125 @@ Returns: write_int :: proc(b: ^Builder, i: int, base: int = 10) -> (n: int) { return write_i64(b, i64(i), base) } + + +/* +Replaces all instances of `old` in the string in a Builder `b` with the `new` string + +*Allocates Using The Allocator On The Builder* + +Inputs: +- b: The input `Builder` +- old: The substring to be replaced +- new: The replacement string + +Returns: +- replaced: The number of replacements +- err: if any allocation errors occurred +*/ +builder_replace_all :: proc(b: ^Builder, old, new: string) -> (replaced: int, err: runtime.Allocator_Error) { + return builder_replace(b, old, new, -1) +} + +/* +Replaces n instances of `old` in the string in a Builder `b` with the `new` string + +*Allocates Using The Allocator On The Builder* + +Inputs: +- b: The input `Builder` +- old: The substring to be replaced +- new: The replacement string +- n: The number of instances to replace (if `n < 0`, no limit on the number of replacements) + +Returns: +- replaced: The number of replacements +- err: if any allocation errors occurred +*/ +builder_replace :: proc(b: ^Builder, old, new: string, n: int, loc := #caller_location) -> (replaced: int, err: runtime.Allocator_Error) { + if old == new || n == 0 { + return + } + + if m := count(to_string(b^), old); m == 0 { + return + } + + if len(old) == 0 { + // NOTE(bill): reserve the necessary memory + found := 0 + for i := 0; i <= len(b.buf); i += len(new)+1 { + if n > 0 && found == n { + break + } + found += 1 + } + if found == 0 { + return + } + reserve(&b.buf, len(b.buf) + len(new)*found) or_return + + + for i := 0; i <= len(b.buf); i += len(new)+1 { + if n > 0 && replaced == n { + break + } + + resize(&b.buf, len(b.buf)+len(new), loc) or_return + copy(b.buf[i+len(new):], b.buf[i:]) + copy(b.buf[i:], new) + replaced += 1 + } + } else { + if len(new) > len(old) { + // NOTE(bill): reserve the necessary memory + found := 0 + for i := 0; i < len(b.buf); /**/ { + if n > 0 && found == n { + break + } + + j := index(string(b.buf[i:]), old) + if j < 0 { + break + } + i += j+len(old) + found += 1 + } + if found == 0 { + return + } + reserve(&b.buf, len(b.buf) + (len(new)-len(old))*found) or_return + } + + for i := 0; i < len(b.buf); /**/ { + if n > 0 && replaced == n { + break + } + + j := index(string(b.buf[i:]), old) + if j < 0 { + break + } + + if len(new) > len(old) { + resize(&b.buf, len(b.buf) + len(new)-len(old)) or_return + } + + cur := b.buf[i+j:] + src := cur[len(old):] + dst := cur[len(new):] + copy(dst, src) + copy(cur, new) + + i += j+len(new) + + replaced += 1 + + if len(new) < len(old) { + resize(&b.buf, len(b.buf) + len(new)-len(old)) or_return + } + } + } + return +} \ No newline at end of file diff --git a/core/strings/conversion.odin b/core/strings/conversion.odin index 2e82fff58..2e6bee573 100644 --- a/core/strings/conversion.odin +++ b/core/strings/conversion.odin @@ -1,7 +1,7 @@ package strings +import "base:runtime" import "core:io" -import "core:mem" import "core:unicode" import "core:unicode/utf8" @@ -21,7 +21,7 @@ Returns: - res: A valid UTF-8 string with invalid sequences replaced by `replacement`. - err: An optional allocator error if one occured, `nil` otherwise */ -to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { if len(s) == 0 { return "", nil } @@ -101,7 +101,7 @@ Output: test */ -to_lower :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +to_lower :: proc(s: string, allocator := context.allocator) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { b: Builder builder_init(&b, 0, len(s), allocator) or_return for r in s { @@ -136,7 +136,7 @@ Output: TEST */ -to_upper :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +to_upper :: proc(s: string, allocator := context.allocator) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { b: Builder builder_init(&b, 0, len(s), allocator) or_return for r in s { @@ -260,7 +260,7 @@ Returns: - res: The converted string - err: An optional allocator error if one occured, `nil` otherwise */ -to_camel_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +to_camel_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { s := s s = trim_space(s) b: Builder @@ -296,7 +296,7 @@ Returns: - res: The converted string - err: An optional allocator error if one occured, `nil` otherwise */ -to_pascal_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +to_pascal_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { s := s s = trim_space(s) b: Builder @@ -355,7 +355,7 @@ to_delimiter_case :: proc( delimiter: rune, all_upper_case: bool, allocator := context.allocator, -) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { s := s s = trim_space(s) b: Builder @@ -422,7 +422,7 @@ Output: hello_world */ -to_snake_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +to_snake_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { return to_delimiter_case(s, '_', false, allocator) } // Alias for `to_upper_snake_case` @@ -454,7 +454,7 @@ Output: HELLO_WORLD */ -to_upper_snake_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +to_upper_snake_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { return to_delimiter_case(s, '_', true, allocator) } /* @@ -484,7 +484,7 @@ Output: hello-world */ -to_kebab_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +to_kebab_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { return to_delimiter_case(s, '-', false, allocator) } /* @@ -514,7 +514,7 @@ Output: HELLO-WORLD */ -to_upper_kebab_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +to_upper_kebab_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { return to_delimiter_case(s, '-', true, allocator) } /* @@ -544,7 +544,7 @@ Output: Hello_World */ -to_ada_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +to_ada_case :: proc(s: string, allocator := context.allocator) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { s := s s = trim_space(s) b: Builder diff --git a/core/strings/intern.odin b/core/strings/intern.odin index 0b8ed173e..9b816ff8d 100644 --- a/core/strings/intern.odin +++ b/core/strings/intern.odin @@ -1,7 +1,6 @@ package strings import "base:runtime" -import "core:mem" // Custom string entry struct Intern_Entry :: struct { @@ -30,11 +29,12 @@ Inputs: - m: A pointer to the Intern struct to be initialized - allocator: The allocator for the Intern_Entry strings (Default: context.allocator) - map_allocator: The allocator for the map of entries (Default: context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - err: An allocator error if one occured, `nil` otherwise */ -intern_init :: proc(m: ^Intern, allocator := context.allocator, map_allocator := context.allocator, loc := #caller_location) -> (err: mem.Allocator_Error) { +intern_init :: proc(m: ^Intern, allocator := context.allocator, map_allocator := context.allocator, loc := #caller_location) -> (err: runtime.Allocator_Error) { m.allocator = allocator m.entries = make(map[string]^Intern_Entry, 16, map_allocator, loc) or_return return nil @@ -78,6 +78,7 @@ Returns an interned copy of the given text as a cstring, adding it to the map if Inputs: - m: A pointer to the Intern struct - text: The string to be interned +- loc: The caller location for debugging purposes (default: `#caller_location`) NOTE: The returned cstring lives as long as the map entry lives @@ -85,8 +86,8 @@ Returns: - str: The interned cstring - err: An allocator error if one occured, `nil` otherwise */ -intern_get_cstring :: proc(m: ^Intern, text: string) -> (str: cstring, err: runtime.Allocator_Error) { - entry := _intern_get_entry(m, text) or_return +intern_get_cstring :: proc(m: ^Intern, text: string, loc := #caller_location) -> (str: cstring, err: runtime.Allocator_Error) { + entry := _intern_get_entry(m, text, loc) or_return return cstring(&entry.str[0]), nil } @@ -99,12 +100,13 @@ Sets and allocates the entry if it wasn't set yet Inputs: - m: A pointer to the Intern struct - text: The string to be looked up or interned +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - new_entry: The interned cstring - err: An allocator error if one occured, `nil` otherwise */ -_intern_get_entry :: proc(m: ^Intern, text: string) -> (new_entry: ^Intern_Entry, err: runtime.Allocator_Error) #no_bounds_check { +_intern_get_entry :: proc(m: ^Intern, text: string, loc := #caller_location) -> (new_entry: ^Intern_Entry, err: runtime.Allocator_Error) #no_bounds_check { if m.allocator.procedure == nil { m.allocator = context.allocator } @@ -115,7 +117,7 @@ _intern_get_entry :: proc(m: ^Intern, text: string) -> (new_entry: ^Intern_Entry } entry_size := int(offset_of(Intern_Entry, str)) + len(text) + 1 - bytes := runtime.mem_alloc(entry_size, align_of(Intern_Entry), m.allocator) or_return + bytes := runtime.mem_alloc(entry_size, align_of(Intern_Entry), m.allocator, loc) or_return new_entry = (^Intern_Entry)(raw_data(bytes)) new_entry.len = len(text) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index beaa8bda1..40dc11e75 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -5,7 +5,6 @@ import "base:intrinsics" import "base:runtime" import "core:bytes" import "core:io" -import "core:mem" import "core:unicode" import "core:unicode/utf8" @@ -23,7 +22,7 @@ Returns: - res: The cloned string - err: An optional allocator error if one occured, `nil` otherwise */ -clone :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +clone :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { c := make([]byte, len(s), allocator, loc) or_return copy(c, s) return string(c), nil @@ -43,7 +42,7 @@ Returns: - res: A cloned cstring with an appended null-byte - err: An optional allocator error if one occured, `nil` otherwise */ -clone_to_cstring :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: cstring, err: mem.Allocator_Error) #optional_allocator_error { +clone_to_cstring :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: cstring, err: runtime.Allocator_Error) #optional_allocator_error { c := make([]byte, len(s)+1, allocator, loc) or_return copy(c, s) c[len(s)] = 0 @@ -63,7 +62,7 @@ Returns: - res: A string created from the byte pointer and length */ string_from_ptr :: proc(ptr: ^byte, len: int) -> (res: string) { - return transmute(string)mem.Raw_String{ptr, len} + return transmute(string)runtime.Raw_String{ptr, len} } /* @@ -97,7 +96,7 @@ Returns: - res: The converted cstring */ unsafe_string_to_cstring :: proc(str: string) -> (res: cstring) { - d := transmute(mem.Raw_String)str + d := transmute(runtime.Raw_String)str return cstring(d.data) } @@ -113,7 +112,7 @@ NOTE: Failure to find the byte results in returning the entire string. Returns: - res: The truncated string */ -truncate_to_byte :: proc "contextless" (str: string, b: byte) -> (res: string) { +truncate_to_byte :: proc "contextless" (str: string, b: byte) -> (res: string) #no_bounds_check { n := index_byte(str, b) if n < 0 { n = len(str) @@ -131,7 +130,7 @@ Inputs: Returns: - res: The truncated string */ -truncate_to_rune :: proc(str: string, r: rune) -> (res: string) { +truncate_to_rune :: proc(str: string, r: rune) -> (res: string) #no_bounds_check { n := index_rune(str, r) if n < 0 { n = len(str) @@ -153,7 +152,7 @@ Returns: - res: The cloned string from the byte array with a null-byte - err: An optional allocator error if one occured, `nil` otherwise */ -clone_from_bytes :: proc(s: []byte, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +clone_from_bytes :: proc(s: []byte, allocator := context.allocator, loc := #caller_location) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error #no_bounds_check { c := make([]byte, len(s)+1, allocator, loc) or_return copy(c, s) c[len(s)] = 0 @@ -174,7 +173,7 @@ Returns: - res: The cloned string from the cstring - err: An optional allocator error if one occured, `nil` otherwise */ -clone_from_cstring :: proc(s: cstring, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +clone_from_cstring :: proc(s: cstring, allocator := context.allocator, loc := #caller_location) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { return clone(string(s), allocator, loc) } @@ -195,7 +194,7 @@ Returns: - res: The cloned string from the byte pointer and length - err: An optional allocator error if one occured, `nil` otherwise */ -clone_from_ptr :: proc(ptr: ^byte, len: int, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +clone_from_ptr :: proc(ptr: ^byte, len: int, allocator := context.allocator, loc := #caller_location) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { s := string_from_ptr(ptr, len) return clone(s, allocator, loc) } @@ -225,7 +224,7 @@ Returns: - res: The cloned string from the null-terminated cstring and byte length - err: An optional allocator error if one occured, `nil` otherwise */ -clone_from_cstring_bounded :: proc(ptr: cstring, len: int, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +clone_from_cstring_bounded :: proc(ptr: cstring, len: int, allocator := context.allocator, loc := #caller_location) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { s := string_from_ptr((^u8)(ptr), len) s = truncate_to_byte(s, 0) return clone(s, allocator, loc) @@ -242,9 +241,7 @@ Inputs: Returns: - result: `-1` if `lhs` comes first, `1` if `rhs` comes first, or `0` if they are equal */ -compare :: proc "contextless" (lhs, rhs: string) -> (result: int) { - return mem.compare(transmute([]byte)lhs, transmute([]byte)rhs) -} +compare :: runtime.string_cmp /* Checks if rune `r` in the string `s` @@ -401,7 +398,7 @@ Output: false */ -equal_fold :: proc(u, v: string) -> (res: bool) { +equal_fold :: proc(u, v: string) -> (res: bool) #no_bounds_check { s, t := u, v loop: for s != "" && t != "" { sr, tr: rune @@ -438,7 +435,7 @@ equal_fold :: proc(u, v: string) -> (res: bool) { r := unicode.simple_fold(sr) for r != sr && r < tr { - r = unicode.simple_fold(sr) + r = unicode.simple_fold(r) } if r == tr { continue loop @@ -486,7 +483,7 @@ prefix_length :: proc "contextless" (a, b: string) -> (n: int) { n = runtime.memory_prefix_length(raw_data(a), raw_data(b), min(len(a), len(b))) lim := max(n - UTF_MAX + 1, 0) - for l := n; l > lim; l -= 1 { + #no_bounds_check for l := n; l > lim; l -= 1 { r, _ := runtime.string_decode_rune(a[l - 1:]) if r != RUNE_ERROR { if l > 0 && (a[l - 1] & 0xc0 == 0xc0) { @@ -595,7 +592,7 @@ Output: true */ -has_suffix :: proc(s, suffix: string) -> (result: bool) { +has_suffix :: proc(s, suffix: string) -> (result: bool) #no_bounds_check { return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix } @@ -634,7 +631,7 @@ Output: a...b...c */ -join :: proc(a: []string, sep: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +join :: proc(a: []string, sep: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error #no_bounds_check { if len(a) == 0 { return "", nil } @@ -681,7 +678,7 @@ Output: abc */ -concatenate :: proc(a: []string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +concatenate :: proc(a: []string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error #no_bounds_check { if len(a) == 0 { return "", nil } @@ -764,6 +761,7 @@ Inputs: - rune_offset: The starting rune index (default is 0). In runes, not bytes. - rune_length: The number of runes to include in the substring (default is 0, which returns the remainder of the string). In runes, not bytes. - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: The substring @@ -787,7 +785,7 @@ Output: example */ -cut_clone :: proc(s: string, rune_offset := int(0), rune_length := int(0), allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +cut_clone :: proc(s: string, rune_offset := int(0), rune_length := int(0), allocator := context.allocator, loc := #caller_location) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { res = cut(s, rune_offset, rune_length) return clone(res, allocator, loc) } @@ -805,6 +803,7 @@ Inputs: - sep_save: A flag determining if the separator should be saved in the resulting substrings - n: The maximum number of substrings to return, returns `nil` without alloc when `n=0` - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) NOTE: Allocation occurs for the array, the splits are all views of the original string. @@ -813,7 +812,7 @@ Returns: - err: An optional allocator error if one occured, `nil` otherwise */ @private -_split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: mem.Allocator_Error) { +_split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: runtime.Allocator_Error) #no_bounds_check { s, n := s_, n_ if n == 0 { @@ -869,6 +868,7 @@ Inputs: - s: The string to split. - sep: The separator string used to split the input string. - allocator: (default is context.allocator). +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: The slice of strings, each representing a part of the split string. @@ -892,8 +892,8 @@ Output: ["aaa", "bbb", "ccc", "ddd", "eee"] */ -split :: proc(s, sep: string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { - return _split(s, sep, 0, -1, allocator) +split :: proc(s, sep: string, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: runtime.Allocator_Error) #optional_allocator_error { + return _split(s, sep, 0, -1, allocator, loc) } /* @@ -906,6 +906,7 @@ Inputs: - sep: The separator string used to split the input string. - n: The maximum amount of parts to split the string into. - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: The slice of strings, each representing a part of the split string. @@ -929,8 +930,8 @@ Output: ["aaa", "bbb", "ccc.ddd.eee"] */ -split_n :: proc(s, sep: string, n: int, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { - return _split(s, sep, 0, n, allocator) +split_n :: proc(s, sep: string, n: int, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: runtime.Allocator_Error) #optional_allocator_error { + return _split(s, sep, 0, n, allocator, loc) } /* @@ -942,6 +943,7 @@ Inputs: - s: The string to split. - sep: The separator string used to split the input string. - allocator: (default is context.allocator). +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: The slice of strings, each representing a part of the split string after the separator @@ -965,8 +967,8 @@ Output: ["aaa.", "bbb.", "ccc.", "ddd.", "eee"] */ -split_after :: proc(s, sep: string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { - return _split(s, sep, len(sep), -1, allocator) +split_after :: proc(s, sep: string, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: runtime.Allocator_Error) #optional_allocator_error { + return _split(s, sep, len(sep), -1, allocator, loc) } /* @@ -979,6 +981,7 @@ Inputs: - sep: The separator string used to split the input string. - n: The maximum number of parts to split the string into. - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: The slice of strings with `n` parts or fewer if there weren't @@ -1002,8 +1005,8 @@ Output: ["aaa.", "bbb.", "ccc.ddd.eee"] */ -split_after_n :: proc(s, sep: string, n: int, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { - return _split(s, sep, len(sep), n, allocator) +split_after_n :: proc(s, sep: string, n: int, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: runtime.Allocator_Error) #optional_allocator_error { + return _split(s, sep, len(sep), n, allocator, loc) } /* @@ -1034,7 +1037,7 @@ _split_iterator :: proc(s: ^string, sep: string, sep_save: int) -> (res: string, } else { m = index(s^, sep) } - if m < 0 { + #no_bounds_check if m < 0 { // not found res = s[:] ok = res != "" @@ -1081,7 +1084,7 @@ Output: */ split_by_byte_iterator :: proc(s: ^string, sep: u8) -> (res: string, ok: bool) { m := index_byte(s^, sep) - if m < 0 { + #no_bounds_check if m < 0 { // not found res = s[:] ok = res != "" @@ -1178,7 +1181,7 @@ Returns: - res: The trimmed string as a slice of the original. */ @(private) -_trim_cr :: proc(s: string) -> (res: string) { +_trim_cr :: proc(s: string) -> (res: string) #no_bounds_check { n := len(s) if n > 0 { if s[n-1] == '\r' { @@ -1196,6 +1199,7 @@ Splits the input string at every line break `\n`. Inputs: - s: The input string to split. - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: The slice (allocated) of the split string (slices into original string) @@ -1217,9 +1221,9 @@ Output: ["a", "b", "c", "d", "e"] */ -split_lines :: proc(s: string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { +split_lines :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: runtime.Allocator_Error) #optional_allocator_error { sep :: "\n" - lines := _split(s, sep, 0, -1, allocator) or_return + lines := _split(s, sep, 0, -1, allocator, loc) or_return for &line in lines { line = _trim_cr(line) } @@ -1235,6 +1239,7 @@ Inputs: - s: The input string to split. - n: The number of parts to split into. - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: The slice (allocated) of the split string (slices into original string) @@ -1258,9 +1263,9 @@ Output: ["a", "b", "c\nd\ne"] */ -split_lines_n :: proc(s: string, n: int, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { +split_lines_n :: proc(s: string, n: int, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: runtime.Allocator_Error) #optional_allocator_error { sep :: "\n" - lines := _split(s, sep, 0, n, allocator) or_return + lines := _split(s, sep, 0, n, allocator, loc) or_return for &line in lines { line = _trim_cr(line) } @@ -1275,6 +1280,7 @@ Splits the input string at every line break `\n` leaving the `\n` in the resulti Inputs: - s: The input string to split. - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: The slice (allocated) of the split string (slices into original string), with `\n` included @@ -1298,9 +1304,9 @@ Output: ["a\n", "b\n", "c\n", "d\n", "e"] */ -split_lines_after :: proc(s: string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { +split_lines_after :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: runtime.Allocator_Error) #optional_allocator_error { sep :: "\n" - lines := _split(s, sep, len(sep), -1, allocator) or_return + lines := _split(s, sep, len(sep), -1, allocator, loc) or_return for &line in lines { line = _trim_cr(line) } @@ -1317,6 +1323,7 @@ Inputs: - s: The input string to split. - n: The number of parts to split into. - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: The slice (allocated) of the split string (slices into original string), with `\n` included @@ -1340,9 +1347,9 @@ Output: ["a\n", "b\n", "c\nd\ne"] */ -split_lines_after_n :: proc(s: string, n: int, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { +split_lines_after_n :: proc(s: string, n: int, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: runtime.Allocator_Error) #optional_allocator_error { sep :: "\n" - lines := _split(s, sep, len(sep), n, allocator) or_return + lines := _split(s, sep, len(sep), n, allocator, loc) or_return for &line in lines { line = _trim_cr(line) } @@ -1584,8 +1591,8 @@ Output: -1 */ -index :: proc "contextless" (s, substr: string) -> (res: int) { - hash_str_rabin_karp :: proc "contextless" (s: string) -> (hash: u32 = 0, pow: u32 = 1) { +index :: proc "contextless" (s, substr: string) -> (res: int) #no_bounds_check { + hash_str_rabin_karp :: proc "contextless" (s: string) -> (hash: u32 = 0, pow: u32 = 1) #no_bounds_check { for i := 0; i < len(s); i += 1 { hash = hash*PRIME_RABIN_KARP + u32(s[i]) } @@ -1664,8 +1671,8 @@ Output: -1 */ -last_index :: proc(s, substr: string) -> (res: int) { - hash_str_rabin_karp_reverse :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) { +last_index :: proc(s, substr: string) -> (res: int) #no_bounds_check { + hash_str_rabin_karp_reverse :: proc "contextless" (s: string) -> (hash: u32 = 0, pow: u32 = 1) #no_bounds_check { for i := len(s) - 1; i >= 0; i -= 1 { hash = hash*PRIME_RABIN_KARP + u32(s[i]) } @@ -1744,7 +1751,7 @@ Output: -1 */ -index_any :: proc(s, chars: string) -> (res: int) { +index_any :: proc(s, chars: string) -> (res: int) #no_bounds_check { if chars == "" { return -1 } @@ -1808,7 +1815,7 @@ Output: -1 */ -last_index_any :: proc(s, chars: string) -> (res: int) { +last_index_any :: proc(s, chars: string) -> (res: int) #no_bounds_check { if chars == "" { return -1 } @@ -1869,7 +1876,7 @@ Returns: - idx: the index of the first matching substring - width: the length of the found substring */ -index_multi :: proc(s: string, substrs: []string) -> (idx: int, width: int) { +index_multi :: proc(s: string, substrs: []string) -> (idx: int, width: int) #no_bounds_check { idx = -1 if s == "" || len(substrs) <= 0 { return @@ -1932,7 +1939,7 @@ Output: 0 */ -count :: proc(s, substr: string) -> (res: int) { +count :: proc(s, substr: string) -> (res: int) #no_bounds_check { if len(substr) == 0 { // special case return rune_count(s) + 1 } @@ -1976,6 +1983,7 @@ Inputs: - s: The string to repeat - count: The number of times to repeat `s` - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: The concatenated repeated string @@ -1997,7 +2005,7 @@ Output: abcabc */ -repeat :: proc(s: string, count: int, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +repeat :: proc(s: string, count: int, allocator := context.allocator, loc := #caller_location) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { if count < 0 { panic("strings: negative repeat count") } else if count > 0 && (len(s)*count)/count != len(s) { @@ -2006,7 +2014,7 @@ repeat :: proc(s: string, count: int, allocator := context.allocator, loc := #ca b := make([]byte, len(s)*count, allocator, loc) or_return i := copy(b, s) - for i < len(b) { // 2^N trick to reduce the need to copy + #no_bounds_check for i < len(b) { // 2^N trick to reduce the need to copy copy(b[i:], b[:i]) i *= 2 } @@ -2023,6 +2031,7 @@ Inputs: - old: The substring to replace - new: The substring to replace `old` with - allocator: The allocator to use for the new string (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - output: The modified string @@ -2047,8 +2056,8 @@ Output: */ -replace_all :: proc(s, old, new: string, allocator := context.allocator) -> (output: string, was_allocation: bool) { - return replace(s, old, new, -1, allocator) +replace_all :: proc(s, old, new: string, allocator := context.allocator, loc := #caller_location) -> (output: string, was_allocation: bool) { + return replace(s, old, new, -1, allocator, loc) } /* @@ -2062,6 +2071,7 @@ Inputs: - new: The replacement string - n: The number of instances to replace (if `n < 0`, no limit on the number of replacements) - allocator: (default: context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - output: The modified string @@ -2111,7 +2121,7 @@ replace :: proc(s, old, new: string, n: int, allocator := context.allocator, loc w := 0 start := 0 - for i := 0; i < byte_count; i += 1 { + #no_bounds_check for i := 0; i < byte_count; i += 1 { j := start if len(old) == 0 { if i > 0 { @@ -2140,6 +2150,7 @@ Inputs: - key: The substring to be removed - n: The number of instances to remove (if `n < 0`, no limit on the number of removes) - allocator: (default: context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - output: The modified string @@ -2165,8 +2176,8 @@ Output: abcabc false */ -remove :: proc(s, key: string, n: int, allocator := context.allocator) -> (output: string, was_allocation: bool) { - return replace(s, key, "", n, allocator) +remove :: proc(s, key: string, n: int, allocator := context.allocator, loc := #caller_location) -> (output: string, was_allocation: bool) { + return replace(s, key, "", n, allocator, loc) } /* @@ -2178,6 +2189,7 @@ Inputs: - s: The input string - key: The substring to be removed - allocator: (default: context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - output: The modified string @@ -2201,8 +2213,8 @@ Output: abcabc false */ -remove_all :: proc(s, key: string, allocator := context.allocator) -> (output: string, was_allocation: bool) { - return remove(s, key, -1, allocator) +remove_all :: proc(s, key: string, allocator := context.allocator, loc := #caller_location) -> (output: string, was_allocation: bool) { + return remove(s, key, -1, allocator, loc) } // Returns true if is an ASCII space character ('\t', '\n', '\v', '\f', '\r', ' ') @@ -2426,7 +2438,7 @@ Output: test */ -trim_right_proc :: proc(s: string, p: proc(rune) -> bool) -> (res: string) { +trim_right_proc :: proc(s: string, p: proc(rune) -> bool) -> (res: string) #no_bounds_check { i := last_index_proc(s, p, false) if i >= 0 && s[i] >= utf8.RUNE_SELF { _, w := utf8.decode_rune_in_string(s[i:]) @@ -2448,7 +2460,7 @@ Inputs: Returns: - res: The trimmed string as a slice of the original, empty when no match */ -trim_right_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr) -> (res: string) { +trim_right_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr) -> (res: string) #no_bounds_check { i := last_index_proc_with_state(s, p, state, false) if i >= 0 && s[i] >= utf8.RUNE_SELF { _, w := utf8.decode_rune_in_string(s[i:]) @@ -2623,7 +2635,7 @@ Output: testing */ -trim_prefix :: proc(s, prefix: string) -> (res: string) { +trim_prefix :: proc(s, prefix: string) -> (res: string) #no_bounds_check { if has_prefix(s, prefix) { return s[len(prefix):] } @@ -2656,7 +2668,7 @@ Output: todo.doc */ -trim_suffix :: proc(s, suffix: string) -> (res: string) { +trim_suffix :: proc(s, suffix: string) -> (res: string) #no_bounds_check { if has_suffix(s, suffix) { return s[:len(s)-len(suffix)] } @@ -2672,6 +2684,7 @@ Inputs: - s: The input string - substrs: An array of substrings used for splitting - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: An array of strings, or nil on empty substring or no matches @@ -2695,7 +2708,7 @@ Output: ["testing", "this", "out", "nice", "done", "last"] */ -split_multi :: proc(s: string, substrs: []string, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error #no_bounds_check { +split_multi :: proc(s: string, substrs: []string, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: runtime.Allocator_Error) #optional_allocator_error #no_bounds_check { if s == "" || len(substrs) <= 0 { return nil, nil } @@ -2805,6 +2818,7 @@ Inputs: - s: The input string - replacement: The string used to replace invalid UTF-8 characters - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: A new string with invalid UTF-8 characters replaced @@ -2825,16 +2839,16 @@ Output: Hello? */ -scrub :: proc(s: string, replacement: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +scrub :: proc(s: string, replacement: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { str := s b: Builder - builder_init(&b, 0, len(s), allocator) or_return + builder_init(&b, 0, len(s), allocator, loc) or_return has_error := false cursor := 0 origin := str - for len(str) > 0 { + #no_bounds_check for len(str) > 0 { r, w := utf8.decode_rune_in_string(str) if r == utf8.RUNE_ERROR { @@ -2865,6 +2879,7 @@ Reverses the input string `s` Inputs: - s: The input string - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: A reversed version of the input string @@ -2886,13 +2901,13 @@ Output: abcxyz zyxcba */ -reverse :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +reverse :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { str := s n := len(str) buf := make([]byte, n, allocator, loc) or_return i := n - for len(str) > 0 { + #no_bounds_check for len(str) > 0 { _, w := utf8.decode_rune_in_string(str) i -= w copy(buf[i:], str[:w]) @@ -2910,6 +2925,7 @@ Inputs: - s: The input string - tab_size: The number of spaces to use for each tab character - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: A new string with tab characters expanded to the specified tab size @@ -2932,7 +2948,7 @@ Output: abc1 abc2 abc3 */ -expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator, loc := #caller_location) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { if tab_size <= 0 { panic("tab size must be positive") } @@ -2942,12 +2958,12 @@ expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) -> } b: Builder - builder_init(&b, allocator) or_return + builder_init(&b, allocator, loc) or_return writer := to_writer(&b) str := s column: int - for len(str) > 0 { + #no_bounds_check for len(str) > 0 { r, w := utf8.decode_rune_in_string(str) if r == '\t' { @@ -3012,7 +3028,7 @@ Output: true */ -partition :: proc(str, sep: string) -> (head, match, tail: string) { +partition :: proc(str, sep: string) -> (head, match, tail: string) #no_bounds_check { i := index(str, sep) if i == -1 { head = str @@ -3038,22 +3054,23 @@ Inputs: - length: The desired length of the centered string, in runes - pad: The string used for padding on both sides - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: A new string centered within a field of the specified length - err: An optional allocator error if one occured, `nil` otherwise */ -centre_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +centre_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { n := rune_count(str) if n >= length || pad == "" { - return clone(str, allocator) + return clone(str, allocator, loc) } remains := length-n pad_len := rune_count(pad) b: Builder - builder_init(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator) or_return + builder_init(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator, loc) or_return w := to_writer(&b) @@ -3074,22 +3091,23 @@ Inputs: - length: The desired length of the left-justified string - pad: The string used for padding on the right side - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: A new string left-justified within a field of the specified length - err: An optional allocator error if one occured, `nil` otherwise */ -left_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +left_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { n := rune_count(str) if n >= length || pad == "" { - return clone(str, allocator) + return clone(str, allocator, loc) } remains := length-n pad_len := rune_count(pad) b: Builder - builder_init(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator) or_return + builder_init(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator, loc) or_return w := to_writer(&b) @@ -3109,22 +3127,23 @@ Inputs: - length: The desired length of the right-justified string - pad: The string used for padding on the left side - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: A new string right-justified within a field of the specified length - err: An optional allocator error if one occured, `nil` otherwise */ -right_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { +right_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: runtime.Allocator_Error) #optional_allocator_error { n := rune_count(str) if n >= length || pad == "" { - return clone(str, allocator) + return clone(str, allocator, loc) } remains := length-n pad_len := rune_count(pad) b: Builder - builder_init(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator) or_return + builder_init(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator, loc) or_return w := to_writer(&b) @@ -3147,14 +3166,14 @@ Inputs: write_pad_string :: proc(w: io.Writer, pad: string, pad_len, remains: int) { repeats := remains / pad_len - for i := 0; i < repeats; i += 1 { + for _ in 0.. (res: []string, err: mem.Allocator_Error) #optional_allocator_error #no_bounds_check { +fields :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: runtime.Allocator_Error) #optional_allocator_error #no_bounds_check { n := 0 was_space := 1 set_bits := u8(0) @@ -3232,6 +3252,7 @@ Inputs: - s: The input string - f: A predicate function to determine the split points - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) NOTE: fields_proc makes no guarantee about the order in which it calls `f(r)`, it assumes that `f` always returns the same value for a given `r` @@ -3239,7 +3260,7 @@ Returns: - res: A slice of substrings of the input string, or an empty slice if all code points in the input string satisfy the predicate or if the input string is empty - err: An optional allocator error if one occured, `nil` otherwise */ -fields_proc :: proc(s: string, f: proc(rune) -> bool, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error #no_bounds_check { +fields_proc :: proc(s: string, f: proc(rune) -> bool, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: runtime.Allocator_Error) #optional_allocator_error #no_bounds_check { substrings := make([dynamic]string, 0, 32, allocator, loc) or_return start, end := -1, -1 @@ -3276,7 +3297,7 @@ Returns: - field: The first non-space substring found - ok: A boolean indicating if a non-space substring was found */ -fields_iterator :: proc(s: ^string) -> (field: string, ok: bool) { +fields_iterator :: proc(s: ^string) -> (field: string, ok: bool) #no_bounds_check { start, end := -1, -1 for r, offset in s { end = offset @@ -3315,6 +3336,7 @@ NOTE: Does not perform internal allocation if length of string `b`, in runes, is Inputs: - a, b: The two strings to compare - allocator: (default is context.allocator) +- loc: The caller location for debugging purposes (default: `#caller_location`) Returns: - res: The Levenshtein edit distance between the two strings @@ -3322,7 +3344,7 @@ Returns: NOTE: This implementation is a single-row-version of the Wagner–Fischer algorithm, based on C code by Martin Ettl. */ -levenshtein_distance :: proc(a, b: string, allocator := context.allocator, loc := #caller_location) -> (res: int, err: mem.Allocator_Error) #optional_allocator_error { +levenshtein_distance :: proc(a, b: string, allocator := context.allocator, loc := #caller_location) -> (res: int, err: runtime.Allocator_Error) #optional_allocator_error { LEVENSHTEIN_DEFAULT_COSTS: []int : { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, @@ -3382,7 +3404,7 @@ levenshtein_distance :: proc(a, b: string, allocator := context.allocator, loc : } @(private) -internal_substring :: proc(s: string, rune_start: int, rune_end: int) -> (sub: string, ok: bool) { +internal_substring :: proc(s: string, rune_start: int, rune_end: int) -> (sub: string, ok: bool) #no_bounds_check { sub = s ok = true @@ -3398,7 +3420,9 @@ internal_substring :: proc(s: string, rune_start: int, rune_end: int) -> (sub: s } rune_i += 1 } - if !ok { return } + if !ok { + sub = sub[rune_i:] + } } if rune_end >= rune_start { diff --git a/core/sync/atomic.odin b/core/sync/atomic.odin index 7e514a6b4..f680c7aa3 100644 --- a/core/sync/atomic.odin +++ b/core/sync/atomic.odin @@ -27,7 +27,7 @@ multiple memory locations between two cores. Which is why CPU's allow for stronger memory ordering guarantees if certain instructions or instruction variants are used. -In Odin there are 5 different memory ordering guaranties that can be provided +In Odin there are 5 different memory ordering guarantees that can be provided to an atomic operation: - `Relaxed`: The memory access (load or store) is unordered with respect to @@ -450,4 +450,4 @@ the load operation, if the comparison fails. The memory ordering for these operations is as specified by the `success` and `failure` parameters respectively. */ -atomic_compare_exchange_weak_explicit :: intrinsics.atomic_compare_exchange_weak_explicit \ No newline at end of file +atomic_compare_exchange_weak_explicit :: intrinsics.atomic_compare_exchange_weak_explicit diff --git a/core/sync/chan/chan.odin b/core/sync/chan/chan.odin index 05312e5a2..5daabe2eb 100644 --- a/core/sync/chan/chan.odin +++ b/core/sync/chan/chan.odin @@ -3,7 +3,6 @@ package sync_chan import "base:builtin" import "base:intrinsics" import "base:runtime" -import "core:mem" import "core:sync" import "core:math/rand" @@ -255,20 +254,20 @@ Example: } */ @(require_results) -create_raw_unbuffered :: proc(#any_int msg_size, msg_alignment: int, allocator: runtime.Allocator) -> (c: ^Raw_Chan, err: runtime.Allocator_Error) { +create_raw_unbuffered :: proc(#any_int msg_size, msg_alignment: int, allocator: runtime.Allocator, loc := #caller_location) -> (c: ^Raw_Chan, err: runtime.Allocator_Error) { assert(msg_size <= int(max(u16))) align := max(align_of(Raw_Chan), msg_alignment) - size := mem.align_forward_int(size_of(Raw_Chan), align) + size := runtime.align_forward_int(size_of(Raw_Chan), align) offset := size size += msg_size - size = mem.align_forward_int(size, align) + size = runtime.align_forward_int(size, align) - ptr := mem.alloc(size, align, allocator) or_return - c = (^Raw_Chan)(ptr) + data := runtime.mem_alloc(size, align, allocator, loc) or_return + c = (^Raw_Chan)(raw_data(data)) c.allocator = allocator c.allocation_size = size - c.unbuffered_data = ([^]byte)(ptr)[offset:] + c.unbuffered_data = raw_data(data[offset:]) c.msg_size = u16(msg_size) return } @@ -300,7 +299,7 @@ Example: } */ @(require_results) -create_raw_buffered :: proc(#any_int msg_size, msg_alignment: int, #any_int cap: int, allocator: runtime.Allocator) -> (c: ^Raw_Chan, err: runtime.Allocator_Error) { +create_raw_buffered :: proc(#any_int msg_size, msg_alignment: int, #any_int cap: int, allocator: runtime.Allocator, loc := #caller_location) -> (c: ^Raw_Chan, err: runtime.Allocator_Error) { assert(msg_size <= int(max(u16))) if cap <= 0 { return create_raw_unbuffered(msg_size, msg_alignment, allocator) @@ -308,15 +307,16 @@ create_raw_buffered :: proc(#any_int msg_size, msg_alignment: int, #any_int cap: align := max(align_of(Raw_Chan), msg_alignment, align_of(Raw_Queue)) - size := mem.align_forward_int(size_of(Raw_Chan), align) + size := runtime.align_forward_int(size_of(Raw_Chan), align) q_offset := size - size = mem.align_forward_int(q_offset + size_of(Raw_Queue), msg_alignment) + size = runtime.align_forward_int(q_offset + size_of(Raw_Queue), msg_alignment) offset := size size += msg_size * cap - size = mem.align_forward_int(size, align) + size = runtime.align_forward_int(size, align) - ptr := mem.alloc(size, align, allocator) or_return - c = (^Raw_Chan)(ptr) + data := runtime.mem_alloc(size, align, allocator, loc) or_return + ptr := raw_data(data) + c = (^Raw_Chan)(raw_data(data)) c.allocator = allocator c.allocation_size = size @@ -339,10 +339,10 @@ Destroys the Channel. **Returns**: - An `Allocator_Error` */ -destroy :: proc(c: ^Raw_Chan) -> (err: runtime.Allocator_Error) { +destroy :: proc(c: ^Raw_Chan, loc := #caller_location) -> (err: runtime.Allocator_Error) { if c != nil { allocator := c.allocator - err = mem.free_with_size(c, c.allocation_size, allocator) + err = runtime.mem_free_with_size(c, c.allocation_size, allocator, loc) } return } @@ -633,7 +633,7 @@ send_raw :: proc "contextless" (c: ^Raw_Chan, msg_in: rawptr) -> (ok: bool) { c.did_read = false defer c.did_read = false - mem.copy(c.unbuffered_data, msg_in, int(c.msg_size)) + intrinsics.mem_copy(c.unbuffered_data, msg_in, int(c.msg_size)) c.w_waiting += 1 @@ -711,7 +711,7 @@ recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> (ok: bool) { msg := raw_queue_pop(c.queue) if msg != nil { - mem.copy(msg_out, msg, int(c.msg_size)) + intrinsics.mem_copy(msg_out, msg, int(c.msg_size)) } if c.w_waiting > 0 { @@ -731,7 +731,7 @@ recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> (ok: bool) { return } - mem.copy(msg_out, c.unbuffered_data, int(c.msg_size)) + intrinsics.mem_copy(msg_out, c.unbuffered_data, int(c.msg_size)) c.w_waiting -= 1 c.did_read = true @@ -798,7 +798,7 @@ try_send_raw :: proc "contextless" (c: ^Raw_Chan, msg_in: rawptr) -> (ok: bool) return false } - mem.copy(c.unbuffered_data, msg_in, int(c.msg_size)) + intrinsics.mem_copy(c.unbuffered_data, msg_in, int(c.msg_size)) c.w_waiting += 1 if c.r_waiting > 0 { sync.signal(&c.r_cond) @@ -848,7 +848,7 @@ try_recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> bool { msg := raw_queue_pop(c.queue) if msg != nil { - mem.copy(msg_out, msg, int(c.msg_size)) + intrinsics.mem_copy(msg_out, msg, int(c.msg_size)) } if c.w_waiting > 0 { @@ -862,7 +862,7 @@ try_recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> bool { return false } - mem.copy(msg_out, c.unbuffered_data, int(c.msg_size)) + intrinsics.mem_copy(msg_out, c.unbuffered_data, int(c.msg_size)) c.w_waiting -= 1 sync.signal(&c.w_cond) @@ -1166,7 +1166,7 @@ Example: import "core:sync/chan" import "core:fmt" - select_raw_example :: proc() { + try_select_raw_example :: proc() { c, err := chan.create(chan.Chan(int), 1, context.allocator) assert(err == .None) defer chan.destroy(c) @@ -1198,11 +1198,11 @@ Example: Output: - SELECT: 0 true + SELECT: 0 Send RECEIVED VALUE 0 - SELECT: 0 true + SELECT: 0 Recv RECEIVED VALUE 1 - SELECT: 0 false + SELECT: -1 None */ @(require_results) @@ -1219,7 +1219,7 @@ try_select_raw :: proc "odin" (recvs: []^Raw_Chan, sends: []^Raw_Chan, send_msgs count := 0 for c, i in recvs { - if can_recv(c) { + if !c.closed && can_recv(c) { candidates[count] = { is_recv = true, idx = i, @@ -1232,7 +1232,7 @@ try_select_raw :: proc "odin" (recvs: []^Raw_Chan, sends: []^Raw_Chan, send_msgs if i > builtin.len(send_msgs)-1 || send_msgs[i] == nil { continue } - if can_send(c) { + if !c.closed && can_send(c) { candidates[count] = { is_recv = false, idx = i, @@ -1359,7 +1359,7 @@ raw_queue_push :: proc "contextless" (q: ^Raw_Queue, data: rawptr) -> bool { } val_ptr := q.data[pos*q.size:] - mem.copy(val_ptr, data, q.size) + intrinsics.mem_copy(val_ptr, data, q.size) q.len += 1 return true } diff --git a/core/sync/extended.odin b/core/sync/extended.odin index 8566eccc8..58344b740 100644 --- a/core/sync/extended.odin +++ b/core/sync/extended.odin @@ -222,9 +222,10 @@ thread. */ auto_reset_event_signal :: proc "contextless" (e: ^Auto_Reset_Event) { old_status := atomic_load_explicit(&e.status, .Relaxed) - new_status := old_status + 1 if old_status < 1 else 1 for { - if _, ok := atomic_compare_exchange_weak_explicit(&e.status, old_status, new_status, .Release, .Relaxed); ok { + new_status := old_status + 1 if old_status < 1 else 1 + ok: bool + if old_status, ok = atomic_compare_exchange_weak_explicit(&e.status, old_status, new_status, .Release, .Relaxed); ok { break } cpu_relax() diff --git a/core/sys/darwin/CoreFoundation/CFCGTypes.odin b/core/sys/darwin/CoreFoundation/CFCGTypes.odin new file mode 100644 index 000000000..ccfdf177a --- /dev/null +++ b/core/sys/darwin/CoreFoundation/CFCGTypes.odin @@ -0,0 +1,18 @@ +package CoreFoundation + +CGFloat :: distinct (f32 when size_of(uint) == 4 else f64) + +CGPoint :: struct { + x: CGFloat, + y: CGFloat, +} + +CGRect :: struct { + using origin: CGPoint, + using size: CGSize, +} + +CGSize :: struct { + width: CGFloat, + height: CGFloat, +} diff --git a/core/sys/darwin/CoreGraphics/CoreGraphics.odin b/core/sys/darwin/CoreGraphics/CoreGraphics.odin new file mode 100644 index 000000000..e2ba5fe3c --- /dev/null +++ b/core/sys/darwin/CoreGraphics/CoreGraphics.odin @@ -0,0 +1,57 @@ +package CoreGraphics + +import "core:c" +import CF "core:sys/darwin/CoreFoundation" + +@(require) +foreign import "system:CoreGraphics.framework" + +@(link_prefix="CG", default_calling_convention="c") +foreign CoreGraphics { + AssociateMouseAndMouseCursorPosition :: proc(connected: b32) -> Error --- + DisplayIDToOpenGLDisplayMask :: proc(display: DirectDisplayID) -> OpenGLDisplayMask --- + DisplayMoveCursorToPoint :: proc(display: DirectDisplayID, point: Point) -> Error --- + EventSourceKeyState :: proc(stateID: EventSourceStateID, key: KeyCode) -> bool --- + GetActiveDisplayList :: proc(maxDisplays: c.uint32_t, activeDisplays: [^]DirectDisplayID, displayCount: ^c.uint32_t) -> Error --- + GetDisplaysWithOpenGLDisplayMask :: proc(mask: OpenGLDisplayMask, maxDisplays: c.uint32_t, displays: [^]DirectDisplayID, matchingDisplayCount: ^c.uint32_t) -> Error --- + GetDisplaysWithPoint :: proc(point: Point, maxDisplays: c.uint32_t, displays: [^]DirectDisplayID, matchingDisplayCount: ^c.uint32_t) -> Error --- + GetDisplaysWithRect :: proc(rect: Rect, maxDisplays: c.uint32_t, displays: [^]DirectDisplayID, matchingDisplayCount: ^c.uint32_t) -> Error --- + GetOnlineDisplayList :: proc(maxDisplays: c.uint32_t, onlineDisplays: [^]DirectDisplayID, displayCount: ^c.uint32_t) -> Error --- + MainDisplayID :: proc() -> DirectDisplayID --- + OpenGLDisplayMaskToDisplayID :: proc(mask: OpenGLDisplayMask) -> DirectDisplayID --- + WarpMouseCursorPosition :: proc(newCursorPosition: Point) -> Error --- +} + +DirectDisplayID :: c.uint32_t + +Error :: enum c.int32_t { + Success = 0, + Failure = 1000, + IllegalArgument = 1001, + InvalidConnection = 1002, + InvalidContext = 1003, + CannotComplete = 1004, + NotImplemented = 1006, + RangeCheck = 1007, + TypeCheck = 1008, + InvalidOperation = 1010, + NoneAvailable = 1011, +} + +EventSourceStateID :: enum c.int32_t { + Private = -1, + CombinedSessionState = 0, + HIDSystemState = 1, +} + +Float :: CF.CGFloat + +KeyCode :: c.uint16_t + +OpenGLDisplayMask :: c.uint32_t + +Point :: CF.CGPoint + +Rect :: CF.CGRect + +Size :: CF.CGSize diff --git a/core/sys/darwin/Foundation/NSApplication.odin b/core/sys/darwin/Foundation/NSApplication.odin index 6cb3df979..cdda7b3e4 100644 --- a/core/sys/darwin/Foundation/NSApplication.odin +++ b/core/sys/darwin/Foundation/NSApplication.odin @@ -1,21 +1,9 @@ package objc_Foundation -foreign import "system:Foundation.framework" - import "base:intrinsics" import "base:runtime" import "core:strings" -RunLoopMode :: ^String - -@(link_prefix="NS") -foreign Foundation { - RunLoopCommonModes: RunLoopMode - DefaultRunLoopMode: RunLoopMode - EventTrackingRunLoopMode: RunLoopMode - ModalPanelRunLoopMode: RunLoopMode -} - ActivationPolicy :: enum UInteger { Regular = 0, Accessory = 1, @@ -92,6 +80,11 @@ Application_activate :: proc "c" (self: ^Application) { msgSend(nil, self, "activate") } +@(objc_type=Application, objc_name="active") +Application_active :: proc "c" (self: ^Application) -> BOOL { + return msgSend(BOOL, self, "isActive") +} + @(objc_type=Application, objc_name="setTitle") Application_setTitle :: proc "c" (self: ^Application, title: ^String) { msgSend(nil, self, "setTitle", title) @@ -107,6 +100,35 @@ Application_setMainMenu :: proc "c" (self: ^Application, menu: ^Menu) { msgSend(nil, self, "setMainMenu:", menu) } +// This property is actually not exposed in AppKit's public API. +// But there is basically no other way to configure the apple menu without using NIB files. +// Therefore, an Odin binding for this non-public API was created. +// Note: SDL also calls this non-public method. +@(objc_type=Application, objc_name="setAppleMenu") +Application_setAppleMenu :: proc "c" (self: ^Application, menu: ^Menu) { + msgSend(nil, self, "setAppleMenu:", menu) +} + +@(objc_type=Application, objc_name="servicesMenu") +Application_servicesMenu :: proc "c" (self: ^Application) -> ^Menu { + return msgSend(^Menu, self, "servicesMenu") +} + +@(objc_type=Application, objc_name="setServicesMenu") +Application_setServicesMenu :: proc "c" (self: ^Application, menu: ^Menu) { + msgSend(nil, self, "setServicesMenu:", menu) +} + +@(objc_type=Application, objc_name="windowsMenu") +Application_windowsMenu :: proc "c" (self: ^Application) -> ^Menu { + return msgSend(^Menu, self, "windowsMenu") +} + +@(objc_type=Application, objc_name="setWindowsMenu") +Application_setWindowsMenu :: proc "c" (self: ^Application, menu: ^Menu) { + msgSend(nil, self, "setWindowsMenu:", menu) +} + @(objc_type=Application, objc_name="mainWindow") Application_mainWindow :: proc "c" (self: ^Application) -> ^Window { return msgSend(^Window, self, "mainWindow") @@ -172,6 +194,13 @@ Application_updateWindows :: proc "c" (self: ^Application) { msgSend(nil, self, "updateWindows") } +@(objc_type=Application, objc_name="sendAction") +Application_sendAction :: proc "c" (self: ^Application, action: SEL, to: id, from: id) { + msgSend(nil, self, "sendAction:to:from:", action, to, from) +} + + + @(objc_class="NSRunningApplication") RunningApplication :: struct {using _: Object} diff --git a/core/sys/darwin/Foundation/NSBitmapImageRep.odin b/core/sys/darwin/Foundation/NSBitmapImageRep.odin index 059a75e43..d10043d7a 100644 --- a/core/sys/darwin/Foundation/NSBitmapImageRep.odin +++ b/core/sys/darwin/Foundation/NSBitmapImageRep.odin @@ -1,42 +1,72 @@ package objc_Foundation -import "base:intrinsics" - @(objc_class="NSBitmapImageRep") BitmapImageRep :: struct { using _: Object } +BitmapInteger :: distinct UInteger +BitmapFormatFlag :: enum BitmapInteger { + AlphaFirst = 0, + AlphaNonpremultiplied = 1, + FloatingPointSamples = 2, + SixteenBitLittleEndian = 8, + ThirtyTwoBitLittleEndian = 9, + SixteenBitBigEndian = 10, + ThirtyTwoBitBigEndian = 11, +} +BitmapFormatFlags :: bit_set[BitmapFormatFlag; BitmapInteger] + @(objc_type=BitmapImageRep, objc_name="alloc", objc_is_class_method=true) BitmapImageRep_alloc :: proc "c" () -> ^BitmapImageRep { return msgSend(^BitmapImageRep, BitmapImageRep, "alloc") } -@(objc_type=BitmapImageRep, objc_name="initWithBitmapDataPlanes") -BitmapImageRep_initWithBitmapDataPlanes :: proc "c" ( - self: ^BitmapImageRep, +BitmapImageRep_initWithBitmapDataPlanes_legacy :: proc "c" ( + self: ^BitmapImageRep, bitmapDataPlanes: ^^u8, - pixelsWide: Integer, - pixelsHigh: Integer, - bitsPerSample: Integer, + pixelsWide: Integer, + pixelsHigh: Integer, + bitsPerSample: Integer, samplesPerPixel: Integer, - hasAlpha: bool, - isPlanar: bool, - colorSpaceName: ^String, - bytesPerRow: Integer, - bitsPerPixel: Integer) -> ^BitmapImageRep { - - return msgSend(^BitmapImageRep, - self, + hasAlpha: bool, + isPlanar: bool, + colorSpaceName: ^String, + bytesPerRow: Integer, + bitsPerPixel: Integer, +) -> ^BitmapImageRep { + return msgSend( + ^BitmapImageRep, self, "initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bytesPerRow:bitsPerPixel:", - bitmapDataPlanes, - pixelsWide, - pixelsHigh, - bitsPerSample, - samplesPerPixel, - hasAlpha, - isPlanar, - colorSpaceName, - bytesPerRow, - bitsPerPixel) + bitmapDataPlanes, pixelsWide, pixelsHigh, bitsPerSample, samplesPerPixel, + hasAlpha, isPlanar, colorSpaceName, bytesPerRow, bitsPerPixel, + ) +} + +BitmapImageRep_initWithBitmapDataPlanes_bitmapFormat :: proc "c" ( + self: ^BitmapImageRep, + bitmapDataPlanes: ^^u8, + pixelsWide: Integer, + pixelsHigh: Integer, + bitsPerSample: Integer, + samplesPerPixel: Integer, + hasAlpha: bool, + isPlanar: bool, + colorSpaceName: ^String, + bitmapFormat: BitmapFormatFlags, + bytesPerRow: Integer, + bitsPerPixel: Integer, +) -> ^BitmapImageRep { + return msgSend( + ^BitmapImageRep, self, + "initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:", + bitmapDataPlanes, pixelsWide, pixelsHigh, bitsPerSample, samplesPerPixel, + hasAlpha, isPlanar, colorSpaceName, bitmapFormat, bytesPerRow, bitsPerPixel, + ) +} + +@(objc_type=BitmapImageRep, objc_name="initWithBitmapDataPlanes") +BitmapImageRep_initWithBitmapDataPlanes :: proc{ + BitmapImageRep_initWithBitmapDataPlanes_legacy, + BitmapImageRep_initWithBitmapDataPlanes_bitmapFormat, } @(objc_type=BitmapImageRep, objc_name="bitmapData") diff --git a/core/sys/darwin/Foundation/NSBlock.odin b/core/sys/darwin/Foundation/NSBlock.odin index 8e65391f4..a5b99abc5 100644 --- a/core/sys/darwin/Foundation/NSBlock.odin +++ b/core/sys/darwin/Foundation/NSBlock.odin @@ -2,13 +2,13 @@ package objc_Foundation import "base:intrinsics" import "base:builtin" -import "core:mem" +import "base:runtime" @(objc_class="NSBlock") Block :: struct {using _: Object} @(objc_type=Block, objc_name="createGlobal", objc_is_class_method=true) -Block_createGlobal :: proc (user_data: rawptr, user_proc: proc "c" (user_data: rawptr), allocator := context.allocator) -> (^Block, mem.Allocator_Error) #optional_allocator_error { +Block_createGlobal :: proc (user_data: rawptr, user_proc: proc "c" (user_data: rawptr), allocator := context.allocator) -> (^Block, runtime.Allocator_Error) #optional_allocator_error { return Block_createInternal(true, user_data, user_proc, allocator) } @(objc_type=Block, objc_name="createLocal", objc_is_class_method=true) @@ -17,7 +17,7 @@ Block_createLocal :: proc (user_data: rawptr, user_proc: proc "c" (user_data: ra return b } @(objc_type=Block, objc_name="createGlobalWithParam", objc_is_class_method=true) -Block_createGlobalWithParam :: proc (user_data: rawptr, user_proc: proc "c" (user_data: rawptr, t: $T), allocator := context.allocator) -> (^Block, mem.Allocator_Error) #optional_allocator_error { +Block_createGlobalWithParam :: proc (user_data: rawptr, user_proc: proc "c" (user_data: rawptr, t: $T), allocator := context.allocator) -> (^Block, runtime.Allocator_Error) #optional_allocator_error { return Block_createInternalWithParam(true, user_data, user_proc, allocator) } @(objc_type=Block, objc_name="createLocalWithParam", objc_is_class_method=true) @@ -69,7 +69,7 @@ foreign libSystem { } @(private="file") -internal_block_literal_make :: proc (is_global: bool, user_data: rawptr, user_proc: rawptr, invoke: rawptr, allocator: mem.Allocator) -> (b: ^Block, err: mem.Allocator_Error) { +internal_block_literal_make :: proc (is_global: bool, user_data: rawptr, user_proc: rawptr, invoke: rawptr, allocator: runtime.Allocator) -> (b: ^Block, err: runtime.Allocator_Error) { _init :: proc(bl: ^Internal_Block_Literal, is_global: bool, user_data: rawptr, user_proc: rawptr, invoke: rawptr) { // Set to true on blocks that have captures (and thus are not true // global blocks) but are known not to escape for various other @@ -82,7 +82,7 @@ internal_block_literal_make :: proc (is_global: bool, user_data: rawptr, user_pr BLOCK_HAS_COPY_DISPOSE :: 1 << 25 BLOCK_HAS_CTOR :: 1 << 26 // helpers have C++ code BLOCK_IS_GLOBAL :: 1 << 28 - BLOCK_HAS_STRET :: 1 << 29 // IFF BLOCK_HAS_SIGNATURE + BLOCK_HAS_STRET :: 1 << 29 // if and only if (⟺) BLOCK_HAS_SIGNATURE BLOCK_HAS_SIGNATURE :: 1 << 30 bl.isa = is_global ? &_NSConcreteGlobalBlock : &_NSConcreteStackBlock @@ -105,7 +105,7 @@ internal_block_literal_make :: proc (is_global: bool, user_data: rawptr, user_pr } @(private="file") -Block_createInternal :: proc (is_global: bool, user_data: rawptr, user_proc: proc "c" (user_data: rawptr), allocator: mem.Allocator) -> (b: ^Block, err: mem.Allocator_Error) { +Block_createInternal :: proc (is_global: bool, user_data: rawptr, user_proc: proc "c" (user_data: rawptr), allocator: runtime.Allocator) -> (b: ^Block, err: runtime.Allocator_Error) { invoke :: proc "c" (bl: ^Internal_Block_Literal) { user_proc := (proc "c" (rawptr))(bl.user_proc) user_proc(bl.user_data) @@ -114,7 +114,7 @@ Block_createInternal :: proc (is_global: bool, user_data: rawptr, user_proc: pro } @(private="file") -Block_createInternalWithParam :: proc (is_global: bool, user_data: rawptr, user_proc: proc "c" (user_data: rawptr, t: $T), allocator: mem.Allocator) -> (b: ^Block, err: mem.Allocator_Error) { +Block_createInternalWithParam :: proc (is_global: bool, user_data: rawptr, user_proc: proc "c" (user_data: rawptr, t: $T), allocator: runtime.Allocator) -> (b: ^Block, err: runtime.Allocator_Error) { invoke :: proc "c" (bl: ^Internal_Block_Literal, t: T) { user_proc := (proc "c" (rawptr, T))(bl.user_proc) user_proc(bl.user_data, t) diff --git a/core/sys/darwin/Foundation/NSColor.odin b/core/sys/darwin/Foundation/NSColor.odin index 453b33144..b50e08af1 100644 --- a/core/sys/darwin/Foundation/NSColor.odin +++ b/core/sys/darwin/Foundation/NSColor.odin @@ -1,5 +1,7 @@ package objc_Foundation +foreign import "system:Foundation.framework" + @(objc_class="NSColorSpace") ColorSpace :: struct {using _: Object} @@ -146,4 +148,9 @@ Color_numberOfComponents :: proc "c" (self: ^Color) -> Integer { @(objc_type=Color, objc_name="getComponents") Color_getComponents :: proc "c" (self: ^Color, components: [^]Float) { msgSend(nil, self, "getComponents:", components) -} \ No newline at end of file +} + +@(link_prefix="NS", default_calling_convention="c") +foreign Foundation { + DeviceRGBColorSpace: ^String +} diff --git a/core/sys/darwin/Foundation/NSCursor.odin b/core/sys/darwin/Foundation/NSCursor.odin new file mode 100644 index 000000000..5c43e1353 --- /dev/null +++ b/core/sys/darwin/Foundation/NSCursor.odin @@ -0,0 +1,47 @@ +package objc_Foundation + +@(objc_class="NSCursor") +Cursor :: struct {using _: Object} + +@(objc_type=Cursor, objc_name="alloc", objc_is_class_method=true) +Cursor_alloc :: proc "c" () -> ^Cursor { + return msgSend(^Cursor, Cursor, "alloc") +} +@(objc_type=Cursor, objc_name="initWithImage") +Cursor_initWithImage :: proc "c" (self: ^Cursor, image: ^Image, hotSpot: Point) -> ^Cursor { + return msgSend(^Cursor, self, "initWithImage:hotSpot:", image, hotSpot) +} +@(objc_type=Cursor, objc_name="hide", objc_is_class_method=true) +Cursor_hide :: proc() { + msgSend(nil, Cursor, "hide") +} +@(objc_type=Cursor, objc_name="unhide", objc_is_class_method=true) +Cursor_unhide :: proc() { + msgSend(nil, Cursor, "unhide") +} +@(objc_type=Cursor, objc_name="setHiddenUntilMouseMoves", objc_is_class_method=true) +Cursor_setHiddenUntilMouseMoves :: proc(flag: BOOL) { + msgSend(nil, Cursor, "setHiddenUntilMouseMoves:", flag) +} + +@(objc_type=Cursor, objc_name="set") +Cursor_set :: proc(self: ^Cursor) { + msgSend(EventType, self, "set") +} +@(objc_type=Cursor, objc_name="currentCursor", objc_is_class_method=true) +Cursor_currentCursor :: proc "c" () -> ^Cursor { + return msgSend(^Cursor, Cursor, "currentCursor") +} +@(objc_type=Cursor, objc_name="IBeamCursor", objc_is_class_method=true) +Cursor_IBeamCursor :: proc "c" () -> ^Cursor { + return msgSend(^Cursor, Cursor, "IBeamCursor") +} +@(objc_type=Cursor, objc_name="arrowCursor", objc_is_class_method=true) +Cursor_arrowCursor :: proc "c" () -> ^Cursor { + return msgSend(^Cursor, Cursor, "arrowCursor") +} +@(objc_type=Cursor, objc_name="pointingHandCursor", objc_is_class_method=true) +Cursor_pointingHandCursor :: proc "c" () -> ^Cursor { + return msgSend(^Cursor, Cursor, "pointingHandCursor") +} + diff --git a/core/sys/darwin/Foundation/NSEvent.odin b/core/sys/darwin/Foundation/NSEvent.odin index 3bd0c1879..952a1726c 100644 --- a/core/sys/darwin/Foundation/NSEvent.odin +++ b/core/sys/darwin/Foundation/NSEvent.odin @@ -334,6 +334,11 @@ Event_locationInWindow :: proc "c" (self: ^Event) -> Point { return msgSend(Point, self, "locationInWindow") } +@(objc_type=Event, objc_name="mouseLocation", objc_is_class_method=true) +Event_mouseLocation :: proc "c" () -> Point { + return msgSend(Point, Event, "mouseLocation") +} + @(objc_type=Event, objc_name="deltaX") Event_deltaX :: proc "c" (self: ^Event) -> Float { diff --git a/core/sys/darwin/Foundation/NSImage.odin b/core/sys/darwin/Foundation/NSImage.odin new file mode 100644 index 000000000..33aae6c50 --- /dev/null +++ b/core/sys/darwin/Foundation/NSImage.odin @@ -0,0 +1,19 @@ +package objc_Foundation + +@(objc_class="NSImage") +Image :: struct { using _: Object } + +@(objc_type=Image, objc_name="alloc", objc_is_class_method=true) +Image_alloc :: proc "c" () -> ^Image { + return msgSend(^Image, Image, "alloc") +} + +@(objc_type=Image, objc_name="initWithSize") +Image_initWithSize :: proc "c" (self: ^Image, size: Size) -> ^Image { + return msgSend(^Image, self, "initWithSize:", size) +} + +@(objc_type=Image, objc_name="addRepresentation") +Image_addRepresentation :: proc(self: ^Image, rep: ^ImageRep) { + msgSend(nil, self, "addRepresentation:", rep) +} diff --git a/core/sys/darwin/Foundation/NSImageRep.odin b/core/sys/darwin/Foundation/NSImageRep.odin new file mode 100644 index 000000000..1e80cb336 --- /dev/null +++ b/core/sys/darwin/Foundation/NSImageRep.odin @@ -0,0 +1,4 @@ +package objc_Foundation + +@(objc_class="NSImageRep") +ImageRep :: struct { using _: Object } diff --git a/core/sys/darwin/Foundation/NSObject.odin b/core/sys/darwin/Foundation/NSObject.odin index 31ece47a1..7a423e757 100644 --- a/core/sys/darwin/Foundation/NSObject.odin +++ b/core/sys/darwin/Foundation/NSObject.odin @@ -81,6 +81,12 @@ debugDescription :: proc "c" (self: ^Object) -> ^String { return nil } + +@(objc_type=Object, objc_name="performSelectorOnMainThread") +performSelectorOnMainThread :: proc "c" (self: ^Object, aSelector: SEL, arg: id, wait: BOOL) { + msgSend(^String, self, "performSelectorOnMainThread:withObject:waitUntilDone:", aSelector, arg, wait) +} + bridgingCast :: proc "c" ($T: typeid, obj: ^Object) where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object) { return (T)(obj) } @@ -88,4 +94,4 @@ bridgingCast :: proc "c" ($T: typeid, obj: ^Object) where intrinsics.type_is_poi @(objc_class="NSCoder") Coder :: struct {using _: Object} -// TODO(bill): Implement all the methods for this massive type \ No newline at end of file +// TODO(bill): Implement all the methods for this massive type diff --git a/core/sys/darwin/Foundation/NSRunLoop.odin b/core/sys/darwin/Foundation/NSRunLoop.odin new file mode 100644 index 000000000..a9c47bd0e --- /dev/null +++ b/core/sys/darwin/Foundation/NSRunLoop.odin @@ -0,0 +1,27 @@ +package objc_Foundation + +foreign import "system:Foundation.framework" + +RunLoopMode :: ^String + +@(link_prefix="NS") +foreign Foundation { + RunLoopCommonModes: RunLoopMode + DefaultRunLoopMode: RunLoopMode + EventTrackingRunLoopMode: RunLoopMode + ModalPanelRunLoopMode: RunLoopMode +} + +@(objc_class="NSRunLoop") +RunLoop :: struct { using _: Object } + +@(objc_type=RunLoop, objc_name="mainRunLoop", objc_is_class_method=true) +RunLoop_mainRunLoop :: proc() -> ^RunLoop { + return msgSend(^RunLoop, RunLoop, "mainRunLoop") +} + +@(objc_type=RunLoop, objc_name="addTimerForMode") +RunLoop_addTimerForMode :: proc(self: ^RunLoop, timer: ^Timer, forMode: RunLoopMode) { + msgSend(nil, self, "addTimer:forMode:", timer, forMode) +} + diff --git a/core/sys/darwin/Foundation/NSScreen.odin b/core/sys/darwin/Foundation/NSScreen.odin index 79ab00fbe..8d52b9e1c 100644 --- a/core/sys/darwin/Foundation/NSScreen.odin +++ b/core/sys/darwin/Foundation/NSScreen.odin @@ -3,18 +3,22 @@ package objc_Foundation @(objc_class="NSScreen") Screen :: struct {using _: Object} -@(objc_type=Screen, objc_name="mainScreen") +@(objc_type=Screen, objc_name="mainScreen", objc_is_class_method=true) Screen_mainScreen :: proc "c" () -> ^Screen { return msgSend(^Screen, Screen, "mainScreen") } -@(objc_type=Screen, objc_name="deepestScreen") +@(objc_type=Screen, objc_name="deepestScreen", objc_is_class_method=true) Screen_deepestScreen :: proc "c" () -> ^Screen { return msgSend(^Screen, Screen, "deepestScreen") } -@(objc_type=Screen, objc_name="screens") +@(objc_type=Screen, objc_name="screens", objc_is_class_method=true) Screen_screens :: proc "c" () -> ^Array { return msgSend(^Array, Screen, "screens") } +@(objc_type=Screen, objc_name="screensHaveSeparateSpaces", objc_is_class_method=true) +Screen_screensHaveSeparateSpaces :: proc "c" () -> BOOL { + return msgSend(BOOL, Screen, "screensHaveSeparateSpaces") +} @(objc_type=Screen, objc_name="frame") Screen_frame :: proc "c" (self: ^Screen) -> Rect { return msgSend(Rect, self, "frame") diff --git a/core/sys/darwin/Foundation/NSTimer.odin b/core/sys/darwin/Foundation/NSTimer.odin new file mode 100644 index 000000000..7e10078ca --- /dev/null +++ b/core/sys/darwin/Foundation/NSTimer.odin @@ -0,0 +1,14 @@ +package objc_Foundation + +@(objc_class="NSTimer") +Timer :: struct { using _: Object } + +@(objc_type=Timer, objc_name="scheduledTimerWithTimeIntervalRepeatsBlock", objc_is_class_method=true) +Timer_scheduledTimerWithTimeIntervalRepeatsBlock :: proc(interval: TimeInterval, repeats: BOOL, block: ^Block) -> ^Timer { + return msgSend(^Timer, Timer, "scheduledTimerWithTimeInterval:repeats:block:", repeats, block) +} + +@(objc_type=Timer, objc_name="scheduledTimerWithTimeIntervalTargetSelectorUserInfoRepeat", objc_is_class_method=true) +Timer_scheduledTimerWithTimeIntervalTargetSelectorUserInfoRepeat :: proc(interval: TimeInterval, aTarget: id, aSelector: SEL, userInfo: id, repeats: BOOL) -> ^Timer { + return msgSend(^Timer, Timer, "scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:", interval, aTarget, aSelector, userInfo, repeats) +} diff --git a/core/sys/darwin/Foundation/NSTypes.odin b/core/sys/darwin/Foundation/NSTypes.odin index 822a07ab1..7c379cf99 100644 --- a/core/sys/darwin/Foundation/NSTypes.odin +++ b/core/sys/darwin/Foundation/NSTypes.odin @@ -1,6 +1,7 @@ package objc_Foundation import "base:intrinsics" +import CF "core:sys/darwin/CoreFoundation" @(private) msgSend :: intrinsics.objc_send @@ -34,17 +35,11 @@ ComparisonResult :: enum Integer { NotFound :: IntegerMax -Float :: distinct (f32 when size_of(uint) == 4 else f64) +Float :: CF.CGFloat -Point :: struct { - x: Float, - y: Float, -} +Point :: CF.CGPoint -Size :: struct { - width: Float, - height: Float, -} +Size :: CF.CGSize when size_of(UInteger) == 8 { _UINTEGER_ENCODING :: "Q" diff --git a/core/sys/darwin/Foundation/NSWindow.odin b/core/sys/darwin/Foundation/NSWindow.odin index 244d25001..fcf35546e 100644 --- a/core/sys/darwin/Foundation/NSWindow.odin +++ b/core/sys/darwin/Foundation/NSWindow.odin @@ -1,12 +1,28 @@ package objc_Foundation import "core:strings" +import CF "core:sys/darwin/CoreFoundation" import "base:runtime" import "base:intrinsics" -Rect :: struct { - using origin: Point, - using size: Size, +Rect :: CF.CGRect +MaxX :: proc(aRect: Rect) -> Float { + return aRect.origin.x + aRect.size.width +} +MaxY :: proc(aRect: Rect) -> Float { + return aRect.origin.y + aRect.size.height +} +MidX :: proc(aRect: Rect) -> Float { + return aRect.origin.x + aRect.size.width*0.5 +} +MidY :: proc(aRect: Rect) -> Float { + return aRect.origin.y + aRect.size.height*0.5 +} +MinX :: proc(aRect: Rect) -> Float { + return aRect.origin.x +} +MinY :: proc(aRect: Rect) -> Float { + return aRect.origin.y } Depth :: enum UInteger { @@ -643,6 +659,14 @@ Layer_setContentsScale :: proc "c" (self: ^Layer, scale: Float) { Layer_frame :: proc "c" (self: ^Layer) -> Rect { return msgSend(Rect, self, "frame") } +@(objc_type=Layer, objc_name="position") +Layer_position :: proc "c" (self: ^Layer) -> Point { + return msgSend(Point, self, "position") +} +@(objc_type=Layer, objc_name="setPosition") +Layer_setPosition :: proc "c" (self: ^Layer, position: Point) { + msgSend(nil, self, "setPosition:", position) +} @(objc_type=Layer, objc_name="addSublayer") Layer_addSublayer :: proc "c" (self: ^Layer, layer: ^Layer) { msgSend(nil, self, "addSublayer:", layer) @@ -691,6 +715,14 @@ View_convertPointFromView :: proc "c" (self: ^View, point: Point, view: ^View) - View_addSubview :: proc "c" (self: ^View, view: ^View) { msgSend(nil, self, "addSubview:", view) } +@(objc_type=View, objc_name="isFlipped") +View_isFlipped :: proc "c" (self: ^View) -> BOOL { + return msgSend(BOOL, self, "isFlipped") +} +@(objc_type=View, objc_name="setIsFlipped") +View_setIsFlipped :: proc "c" (self: ^View, flipped: BOOL) { + msgSend(nil, self, "setIsFlipped:", flipped) +} @(objc_class="NSWindow") Window :: struct {using _: Responder} @@ -784,6 +816,10 @@ Window_setAcceptsMouseMovedEvents :: proc "c" (self: ^Window, ok: BOOL) { Window_setStyleMask :: proc "c" (self: ^Window, style_mask: WindowStyleMask) { msgSend(nil, self, "setStyleMask:", style_mask) } +@(objc_type=Window, objc_name="performClose") +Window_performClose :: proc "c" (self: ^Window, sender: id) { + msgSend(nil, self, "performClose:", sender) +} @(objc_type=Window, objc_name="close") Window_close :: proc "c" (self: ^Window) { msgSend(nil, self, "close") @@ -916,6 +952,18 @@ Window_collectionBehavior :: proc "c" (self: ^Window) -> WindowCollectionBehavio Window_setLevel :: proc "c" (self: ^Window, level: WindowLevel) { msgSend(nil, self, "setLevel:", level) } +@(objc_type = Window, objc_name = "keyWindow") +Window_keyWindow :: proc "c" (self: ^Window) -> BOOL { + return msgSend(BOOL, self, "isKeyWindow") +} +@(objc_type = Window, objc_name = "mainWindow") +Window_mainWindow :: proc "c" (self: ^Window) -> BOOL { + return msgSend(BOOL, self, "isMainWindow") +} +@(objc_type = Window, objc_name = "parentWindow") +Window_parentWindow :: proc "c" (self: ^Window) -> ^Window { + return msgSend(^Window, self, "parentWindow") +} @(objc_type = Window, objc_name = "setReleasedWhenClosed") Window_setReleasedWhenClosed :: proc "c" (self: ^Window, flag: BOOL) { msgSend(nil, self, "setReleasedWhenClosed:", flag) @@ -936,3 +984,27 @@ Window_setTabbingMode :: proc "c" (self: ^Window, mode: WindowTabbingMode) { Window_toggleFullScreen :: proc "c" (self: ^Window, sender: id) { msgSend(nil, self, "toggleFullScreen:", sender) } +@(objc_type = Window, objc_name = "contentRectForFrameRect", objc_is_class_method=true) +Window_contentRectForFrameRectType :: proc "c" (frameRect: Rect, styleMask: WindowStyleMask) -> Rect { + return msgSend(Rect, Window, "contentRectForFrameRect:styleMask:", frameRect, styleMask) +} +@(objc_type = Window, objc_name = "frameRectForContentRect", objc_is_class_method=true) +Window_frameRectForContentRectType :: proc "c" (contentRect: Rect, styleMask: WindowStyleMask) -> Rect { + return msgSend(Rect, Window, "frameRectForContentRect:styleMask:", contentRect, styleMask) +} +@(objc_type = Window, objc_name = "minFrameWidthWithTitle", objc_is_class_method=true) +Window_minFrameWidthWithTitle :: proc "c" (title: ^String, styleMask: WindowStyleMask) -> Float { + return msgSend(Float, Window, "minFrameWidthWithTitle:styleMask:", title, styleMask) +} +@(objc_type = Window, objc_name = "contentRectForFrameRect") +Window_contentRectForFrameRectInstance :: proc "c" (self: ^Window, frameRect: Rect) -> Rect { + return msgSend(Rect, self, "contentRectForFrameRect:", frameRect) +} +@(objc_type = Window, objc_name = "frameRectForContentRect") +Window_frameRectForContentRectInstance :: proc "c" (self: ^Window, contentRect: Rect) -> Rect { + return msgSend(Rect, self, "frameRectForContentRect:", contentRect) +} +@(objc_type = Window, objc_name = "screen") +Window_screen :: proc "c" (self: ^Window) -> ^Screen { + return msgSend(^Screen, self, "screen") +} diff --git a/core/sys/es/api.odin b/core/sys/es/api.odin index ae1a1a8bb..42fadff1a 100644 --- a/core/sys/es/api.odin +++ b/core/sys/es/api.odin @@ -566,7 +566,7 @@ ECHO_REQUEST_MAX_LENGTH :: (48) CONNECTION_OPEN_WAIT :: (1 << 0) FILE_CONTROL_NOTIFY_MONITORS :: (1 << 0) FILE_CONTROL_FLUSH :: (1 << 1) -using StandardIcon :: enum i32 { +StandardIcon :: enum i32 { ICON_NONE, ICON_ACTION_UNAVAILABLE_SYMBOLIC, ICON_ADDRESS_BOOK_NEW, @@ -1632,7 +1632,7 @@ using StandardIcon :: enum i32 { ICON_WEATHER_STORM_TORNADO_SYMBOLIC, ICON_WEATHER_WINDY_SYMBOLIC, } -using FatalError :: enum i32 { +FatalError :: enum i32 { FATAL_ERROR_INVALID_BUFFER, FATAL_ERROR_UNKNOWN_SYSCALL, FATAL_ERROR_INVALID_MEMORY_REGION, @@ -1657,7 +1657,7 @@ using FatalError :: enum i32 { FATAL_ERROR_ABORT, FATAL_ERROR_COUNT, } -using SyscallType :: enum i32 { +SyscallType :: enum i32 { SYSCALL_ALLOCATE, SYSCALL_FREE, SYSCALL_SHARE_MEMORY, @@ -1768,7 +1768,7 @@ using SyscallType :: enum i32 { SYSCALL_DEBUG_COMMAND, SYSCALL_COUNT, } -using MessageType :: enum i32 { +MessageType :: enum i32 { MSG_WM_START = 0x1000, MSG_MOUSE_MOVED = 0x1001, MSG_WINDOW_ACTIVATED = 0x1002, @@ -1880,18 +1880,18 @@ using MessageType :: enum i32 { MSG_USER_START = 0x8000, MSG_USER_END = 0xBFFF, } -using DrawMode :: enum i32 { +DrawMode :: enum i32 { DRAW_MODE_REPEAT_FIRST = 1 , DRAW_MODE_STRECH, DRAW_MODE_REPEAT, DRAW_MODE_NONE, } -using ClipboardFormat :: enum i32 { +ClipboardFormat :: enum i32 { CLIPBOARD_FORMAT_EMPTY, CLIPBOARD_FORMAT_TEXT, CLIPBOARD_FORMAT_FILE_LIST, } -using CursorStyle :: enum i32 { +CursorStyle :: enum i32 { CURSOR_NORMAL, CURSOR_TEXT, CURSOR_RESIZE_VERTICAL, @@ -1923,30 +1923,30 @@ using CursorStyle :: enum i32 { CURSOR_BLANK, CURSOR_COUNT, } -using WindowStyle :: enum i32 { +WindowStyle :: enum i32 { WINDOW_NORMAL, WINDOW_CONTAINER, WINDOW_MENU, WINDOW_TIP, WINDOW_PLAIN, } -using FormatValueType :: enum i32 { +FormatValueType :: enum i32 { FORMAT_VALUE_INVALID, FORMAT_VALUE_STRING, FORMAT_VALUE_NUMBER, FORMAT_VALUE_TIME, } -using CheckState :: enum i32 { +CheckState :: enum i32 { CHECK_UNCHECKED = 0, CHECK_CHECKED = 1, CHECK_INDETERMINATE = 2, } -using DocumentState :: enum i32 { +DocumentState :: enum i32 { DOCUMENT_STATE_EMPTY, DOCUMENT_STATE_UNSAVED, DOCUMENT_STATE_FILE, } -using TransitionType :: enum i32 { +TransitionType :: enum i32 { TRANSITION_NONE, TRANSITION_SLIDE_UP, TRANSITION_SLIDE_DOWN, @@ -1963,7 +1963,7 @@ using TransitionType :: enum i32 { TRANSITION_FADE_IN, TRANSITION_FADE_OUT, } -using MemoryProtection :: enum i32 { +MemoryProtection :: enum i32 { MEMORY_PROTECTION_READ_ONLY, MEMORY_PROTECTION_READ_WRITE, MEMORY_PROTECTION_EXECUTABLE, @@ -2675,7 +2675,7 @@ MemoryDecommit :: #force_inline proc "c" (pointer_ : rawptr, bytes_ : int MemoryFill :: #force_inline proc "c" (from_ : rawptr, to_ : rawptr, byte_ : u8 ){ addr := 0x1000 + 86 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, rawptr, u8 )) (fp))(from_, to_, byte_)} MemoryMove :: #force_inline proc "c" (_start_ : rawptr, _end_ : rawptr, amount_ : int , zeroEmptySpace_ : bool){ addr := 0x1000 + 88 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, rawptr, int , bool)) (fp))(_start_, _end_, amount_, zeroEmptySpace_)} MemoryOpen :: #force_inline proc "c" (size_ : int , name_ : string, flags_ : u32 ) -> Handle{ addr := 0x1000 + 89 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int , ^u8, int, u32 ) -> Handle) (fp))(size_, raw_data(name_), len(name_), flags_)} -MemoryReserve :: #force_inline proc "c" (size_ : int , protection_ : MemoryProtection = MEMORY_PROTECTION_READ_WRITE, commitAll_ : bool = true) -> rawptr{ addr := 0x1000 + 25 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int , MemoryProtection, bool) -> rawptr) (fp))(size_, protection_, commitAll_)} +MemoryReserve :: #force_inline proc "c" (size_ : int , protection_ : MemoryProtection = .MEMORY_PROTECTION_READ_WRITE, commitAll_ : bool = true) -> rawptr{ addr := 0x1000 + 25 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int , MemoryProtection, bool) -> rawptr) (fp))(size_, protection_, commitAll_)} MemoryShare :: #force_inline proc "c" (sharedMemoryRegion_ : Handle, targetProcess_ : Handle, readOnly_ : bool) -> Handle{ addr := 0x1000 + 90 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, Handle, bool) -> Handle) (fp))(sharedMemoryRegion_, targetProcess_, readOnly_)} MemorySumBytes :: #force_inline proc "c" (data_ : ^u8 , bytes_ : int ) -> u8 { addr := 0x1000 + 91 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^u8 , int ) -> u8 ) (fp))(data_, bytes_)} MemoryUnreserve :: #force_inline proc "c" (pointer_ : rawptr, size_ : int = 0){ addr := 0x1000 + 319 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, int )) (fp))(pointer_, size_)} @@ -2858,7 +2858,7 @@ WindowSetIcon :: #force_inline proc "c" (window_ : ^Window, iconID_ : u32 WindowSetTitle :: #force_inline proc "c" (window_ : ^Window, title_ : string = ""){ addr := 0x1000 + 268 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Window, ^u8, int)) (fp))(window_, raw_data(title_), len(title_))} MenuGetSource :: #force_inline proc "c" (menu_ : ^Menu) -> ^Element{ addr := 0x1000 + 269 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Menu) -> ^Element) (fp))(menu_)} ButtonSetIcon :: #force_inline proc "c" (button_ : ^Button, iconID_ : u32 ){ addr := 0x1000 + 270 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Button, u32 )) (fp))(button_, iconID_)} -ButtonSetCheck :: #force_inline proc "c" (button_ : ^Button, checkState_ : CheckState = CHECK_CHECKED, sendUpdatedMessage_ : bool = true){ addr := 0x1000 + 271 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Button, CheckState, bool)) (fp))(button_, checkState_, sendUpdatedMessage_)} +ButtonSetCheck :: #force_inline proc "c" (button_ : ^Button, checkState_ : CheckState = .CHECK_CHECKED, sendUpdatedMessage_ : bool = true){ addr := 0x1000 + 271 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Button, CheckState, bool)) (fp))(button_, checkState_, sendUpdatedMessage_)} ButtonGetCheck :: #force_inline proc "c" (button_ : ^Button) -> CheckState{ addr := 0x1000 + 272 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Button) -> CheckState) (fp))(button_)} ButtonOnCommand :: #force_inline proc "c" (button_ : ^Button, callback_ : CommandCallbackFunction, command_ : ^Command = nil){ addr := 0x1000 + 273 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Button, CommandCallbackFunction, ^Command)) (fp))(button_, callback_, command_)} ButtonSetCheckBuddy :: #force_inline proc "c" (button_ : ^Button, checkBuddy_ : ^Element){ addr := 0x1000 + 274 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Button, ^Element)) (fp))(button_, checkBuddy_)} diff --git a/core/sys/freebsd/syscalls.odin b/core/sys/freebsd/syscalls.odin index 452914eea..3d62a975e 100644 --- a/core/sys/freebsd/syscalls.odin +++ b/core/sys/freebsd/syscalls.odin @@ -62,7 +62,7 @@ read :: proc "contextless" (fd: Fd, buf: []u8) -> (int, Errno) { // // The write() function appeared in Version 1 AT&T UNIX. write :: proc "contextless" (fd: Fd, buf: []u8) -> (int, Errno) { - result, ok := intrinsics.syscall_bsd(SYS_pwrite, + result, ok := intrinsics.syscall_bsd(SYS_write, cast(uintptr)fd, cast(uintptr)raw_data(buf), cast(uintptr)len(buf)) diff --git a/core/sys/info/cpu_arm.odin b/core/sys/info/cpu_arm.odin index 8f5143394..439007e24 100644 --- a/core/sys/info/cpu_arm.odin +++ b/core/sys/info/cpu_arm.odin @@ -40,35 +40,33 @@ CPU_Feature :: enum u64 { } CPU_Features :: distinct bit_set[CPU_Feature; u64] -CPU :: struct { - name: Maybe(string), - features: Maybe(CPU_Features), - physical_cores: int, - logical_cores: int, -} -cpu: CPU + +// Retrieving CPU features on ARM is even more expensive than on Intel, so we're doing this lookup only once, before `main()` +@(private) _features: CPU_Features + + +@(private) _name_buf: [256]u8 +@(private) _name: string @(private) -cpu_name_buf: [128]byte +_cpu_name :: proc() -> (name: string) { + return _name +} @(init, private) -init_cpu_name :: proc "contextless" () { - generic := true - +_init_cpu_name :: proc "contextless" () { when ODIN_OS == .Darwin { - if unix.sysctlbyname("machdep.cpu.brand_string", &cpu_name_buf) { - cpu.name = string(cstring(rawptr(&cpu_name_buf))) - generic = false + if unix.sysctlbyname("machdep.cpu.brand_string", &_name_buf) { + _name = string(cstring(rawptr(&_name_buf))) + return } } - if generic { - when ODIN_ARCH == .arm64 { - copy(cpu_name_buf[:], "ARM64") - cpu.name = string(cpu_name_buf[:len("ARM64")]) - } else { - copy(cpu_name_buf[:], "ARM") - cpu.name = string(cpu_name_buf[:len("ARM")]) - } + when ODIN_ARCH == .arm64 { + copy(_name_buf[:], "ARM64") + _name = string(_name_buf[:len("ARM64")]) + } else { + copy(_name_buf[:], "ARM") + _name = string(_name_buf[:len("ARM")]) } -} +} \ No newline at end of file diff --git a/core/sys/info/cpu_darwin.odin b/core/sys/info/cpu_darwin.odin index c4a209f6d..06a44227c 100644 --- a/core/sys/info/cpu_darwin.odin +++ b/core/sys/info/cpu_darwin.odin @@ -2,11 +2,11 @@ package sysinfo import "core:sys/unix" -@(init, private) -init_cpu_core_count :: proc "contextless" () { - physical, logical: i64 - unix.sysctlbyname("hw.physicalcpu", &physical) - unix.sysctlbyname("hw.logicalcpu", &logical) - cpu.physical_cores = int(physical) - cpu.logical_cores = int(logical) -} +@(private) +_cpu_core_count :: proc "contextless" () -> (physical: int, logical: int, ok: bool) { + _physical, _logical: i64 + unix.sysctlbyname("hw.physicalcpu", &_physical) + unix.sysctlbyname("hw.logicalcpu", &_logical) + + return int(_physical), int(_logical), true +} \ No newline at end of file diff --git a/core/sys/info/cpu_darwin_arm64.odin b/core/sys/info/cpu_darwin_arm64.odin index aaeef9ad9..7f4c7dda2 100644 --- a/core/sys/info/cpu_darwin_arm64.odin +++ b/core/sys/info/cpu_darwin_arm64.odin @@ -2,15 +2,17 @@ package sysinfo import "core:sys/unix" -@(init, private) -init_cpu_features :: proc "contextless" () { - @(static) features: CPU_Features - defer cpu.features = features +@(private) +_cpu_features :: proc "contextless" () -> (features: CPU_Features) { + return _features +} - try_set :: proc "contextless" (name: cstring, feature: CPU_Feature) -> (ok: bool) { +@(init, private) +_init_cpu_features :: proc "contextless" () -> () { + try_set :: proc "contextless" (features: ^CPU_Features, name: cstring, feature: CPU_Feature) -> (ok: bool) { support: b32 if ok = unix.sysctlbyname(name, &support); ok && support { - features += { feature } + features^ += { feature } } return } @@ -20,79 +22,79 @@ init_cpu_features :: proc "contextless" () { // Advanced SIMD & floating-point capabilities: { - if !try_set("hw.optional.AdvSIMD", .asimd) { - try_set("hw.optional.neon", .asimd) + if !try_set(&_features, "hw.optional.AdvSIMD", .asimd) { + try_set(&_features, "hw.optional.neon", .asimd) } - try_set("hw.optional.floatingpoint", .floatingpoint) + try_set(&_features, "hw.optional.floatingpoint", .floatingpoint) - if !try_set("hw.optional.AdvSIMD_HPFPCvt", .asimdhp) { - try_set("hw.optional.neon_hpfp", .asimdhp) + if !try_set(&_features, "hw.optional.AdvSIMD_HPFPCvt", .asimdhp) { + try_set(&_features, "hw.optional.neon_hpfp", .asimdhp) } - try_set("hw.optional.arm.FEAT_BF16", .bf16) - // try_set("hw.optional.arm.FEAT_DotProd", .dotprod) + try_set(&_features, "hw.optional.arm.FEAT_BF16", .bf16) + // try_set(&_features, "hw.optional.arm.FEAT_DotProd", .dotprod) - if !try_set("hw.optional.arm.FEAT_FCMA", .fcma) { - try_set("hw.optional.armv8_3_compnum", .fcma) + if !try_set(&_features, "hw.optional.arm.FEAT_FCMA", .fcma) { + try_set(&_features, "hw.optional.armv8_3_compnum", .fcma) } - if !try_set("hw.optional.arm.FEAT_FHM", .fhm) { - try_set("hw.optional.armv8_2_fhm", .fhm) + if !try_set(&_features, "hw.optional.arm.FEAT_FHM", .fhm) { + try_set(&_features, "hw.optional.armv8_2_fhm", .fhm) } - if !try_set("hw.optional.arm.FEAT_FP16", .fp16) { - try_set("hw.optional.neon_fp16", .fp16) + if !try_set(&_features, "hw.optional.arm.FEAT_FP16", .fp16) { + try_set(&_features, "hw.optional.neon_fp16", .fp16) } - try_set("hw.optional.arm.FEAT_FRINTTS", .frint) - try_set("hw.optional.arm.FEAT_I8MM", .i8mm) - try_set("hw.optional.arm.FEAT_JSCVT", .jscvt) - try_set("hw.optional.arm.FEAT_RDM", .rdm) + try_set(&_features, "hw.optional.arm.FEAT_FRINTTS", .frint) + try_set(&_features, "hw.optional.arm.FEAT_I8MM", .i8mm) + try_set(&_features, "hw.optional.arm.FEAT_JSCVT", .jscvt) + try_set(&_features, "hw.optional.arm.FEAT_RDM", .rdm) } // Integer capabilities: { - try_set("hw.optional.arm.FEAT_FlagM", .flagm) - try_set("hw.optional.arm.FEAT_FlagM2", .flagm2) - try_set("hw.optional.armv8_crc32", .crc32) + try_set(&_features, "hw.optional.arm.FEAT_FlagM", .flagm) + try_set(&_features, "hw.optional.arm.FEAT_FlagM2", .flagm2) + try_set(&_features, "hw.optional.armv8_crc32", .crc32) } // Atomic and memory ordering instruction capabilities: { - try_set("hw.optional.arm.FEAT_LRCPC", .lrcpc) - try_set("hw.optional.arm.FEAT_LRCPC2", .lrcpc2) + try_set(&_features, "hw.optional.arm.FEAT_LRCPC", .lrcpc) + try_set(&_features, "hw.optional.arm.FEAT_LRCPC2", .lrcpc2) - if !try_set("hw.optional.arm.FEAT_LSE", .lse) { - try_set("hw.optional.armv8_1_atomics", .lse) + if !try_set(&_features, "hw.optional.arm.FEAT_LSE", .lse) { + try_set(&_features, "hw.optional.armv8_1_atomics", .lse) } - // try_set("hw.optional.arm.FEAT_LSE2", .lse2) + // try_set(&_features, "hw.optional.arm.FEAT_LSE2", .lse2) } // Encryption capabilities: { - try_set("hw.optional.arm.FEAT_AES", .aes) - try_set("hw.optional.arm.FEAT_PMULL", .pmull) - try_set("hw.optional.arm.FEAT_SHA1", .sha1) - try_set("hw.optional.arm.FEAT_SHA256", .sha256) + try_set(&_features, "hw.optional.arm.FEAT_AES", .aes) + try_set(&_features, "hw.optional.arm.FEAT_PMULL", .pmull) + try_set(&_features, "hw.optional.arm.FEAT_SHA1", .sha1) + try_set(&_features, "hw.optional.arm.FEAT_SHA256", .sha256) - if !try_set("hw.optional.arm.FEAT_SHA512", .sha512) { - try_set("hw.optional.armv8_2_sha512", .sha512) + if !try_set(&_features, "hw.optional.arm.FEAT_SHA512", .sha512) { + try_set(&_features, "hw.optional.armv8_2_sha512", .sha512) } - if !try_set("hw.optional.arm.FEAT_SHA3", .sha3) { - try_set("hw.optional.armv8_2_sha3", .sha3) + if !try_set(&_features, "hw.optional.arm.FEAT_SHA3", .sha3) { + try_set(&_features, "hw.optional.armv8_2_sha3", .sha3) } } // General capabilities: { - // try_set("hw.optional.arm.FEAT_BTI", .bti) - // try_set("hw.optional.arm.FEAT_DPB", .dpb) - // try_set("hw.optional.arm.FEAT_DPB2", .dpb2) - // try_set("hw.optional.arm.FEAT_ECV", .ecv) - try_set("hw.optional.arm.FEAT_SB", .sb) - try_set("hw.optional.arm.FEAT_SSBS", .ssbs) + // try_set(&_features, "hw.optional.arm.FEAT_BTI", .bti) + // try_set(&_features, "hw.optional.arm.FEAT_DPB", .dpb) + // try_set(&_features, "hw.optional.arm.FEAT_DPB2", .dpb2) + // try_set(&_features, "hw.optional.arm.FEAT_ECV", .ecv) + try_set(&_features, "hw.optional.arm.FEAT_SB", .sb) + try_set(&_features, "hw.optional.arm.FEAT_SSBS", .ssbs) } -} +} \ No newline at end of file diff --git a/core/sys/info/cpu_intel.odin b/core/sys/info/cpu_intel.odin index e8f07c732..0a75e2475 100644 --- a/core/sys/info/cpu_intel.odin +++ b/core/sys/info/cpu_intel.odin @@ -3,6 +3,12 @@ package sysinfo import "base:intrinsics" +// cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) --- +cpuid :: intrinsics.x86_cpuid + +// xgetbv :: proc(cx: u32) -> (eax, edx: u32) --- +xgetbv :: intrinsics.x86_xgetbv + CPU_Feature :: enum u64 { aes, // AES hardware implementation (AES NI) adx, // Multi-precision add-carry instruction extensions @@ -43,16 +49,13 @@ CPU_Feature :: enum u64 { } CPU_Features :: distinct bit_set[CPU_Feature; u64] -CPU :: struct { - name: Maybe(string), - features: Maybe(CPU_Features), - physical_cores: int, // Initialized by cpu_.odin - logical_cores: int, // Initialized by cpu_.odin -} -cpu: CPU + +// `cpuid` is a barrier so we try not performing this query this more than necessary. +// `atomic_load_explicit` is also a barrier, so we're doing this lookup only once, before `main()` +@(private) _features: CPU_Features @(init, private) -init_cpu_features :: proc "contextless" () { +_init_cpu_features :: proc "contextless" () { is_set :: #force_inline proc "c" (bit: u32, value: u32) -> bool { return (value>>bit) & 0x1 != 0 } @@ -64,29 +67,27 @@ init_cpu_features :: proc "contextless" () { max_id, _, _, _ := cpuid(0, 0) if max_id < 1 { + _features = {} return } - set: CPU_Features - _, _, ecx1, edx1 := cpuid(1, 0) - try_set(&set, .sse2, 26, edx1) - try_set(&set, .sse3, 0, ecx1) - try_set(&set, .pclmulqdq, 1, ecx1) - try_set(&set, .ssse3, 9, ecx1) - try_set(&set, .fma, 12, ecx1) - try_set(&set, .sse41, 19, ecx1) - try_set(&set, .sse42, 20, ecx1) - try_set(&set, .popcnt, 23, ecx1) - try_set(&set, .aes, 25, ecx1) - try_set(&set, .os_xsave, 27, ecx1) - try_set(&set, .rdrand, 30, ecx1) + try_set(&_features, .sse2, 26, edx1) + try_set(&_features, .sse3, 0, ecx1) + try_set(&_features, .pclmulqdq, 1, ecx1) + try_set(&_features, .ssse3, 9, ecx1) + try_set(&_features, .fma, 12, ecx1) + try_set(&_features, .sse41, 19, ecx1) + try_set(&_features, .sse42, 20, ecx1) + try_set(&_features, .popcnt, 23, ecx1) + try_set(&_features, .aes, 25, ecx1) + try_set(&_features, .os_xsave, 27, ecx1) + try_set(&_features, .rdrand, 30, ecx1) when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD { // xgetbv is an illegal instruction under FreeBSD 13, OpenBSD 7.1 and NetBSD 10 // return before probing further - cpu.features = set return } @@ -97,15 +98,15 @@ init_cpu_features :: proc "contextless" () { // after they started checking both OSXSAVE and XSAVE. // // See: crbug.com/375968 - os_supports_avx := false + os_supports_avx := false os_supports_avx512 := false - if .os_xsave in set && is_set(26, ecx1) { + if .os_xsave in _features && is_set(26, ecx1) { eax, _ := xgetbv(0) - os_supports_avx = is_set(1, eax) && is_set(2, eax) + os_supports_avx = is_set(1, eax) && is_set(2, eax) os_supports_avx512 = is_set(5, eax) && is_set(6, eax) && is_set(7, eax) } if os_supports_avx { - try_set(&set, .avx, 28, ecx1) + try_set(&_features, .avx, 28, ecx1) } if max_id < 7 { @@ -113,56 +114,61 @@ init_cpu_features :: proc "contextless" () { } _, ebx7, ecx7, edx7 := cpuid(7, 0) - try_set(&set, .bmi1, 3, ebx7) - try_set(&set, .sha, 29, ebx7) + try_set(&_features, .bmi1, 3, ebx7) + try_set(&_features, .sha, 29, ebx7) if os_supports_avx { - try_set(&set, .avx2, 5, ebx7) + try_set(&_features, .avx2, 5, ebx7) } if os_supports_avx512 { - try_set(&set, .avx512f, 16, ebx7) - try_set(&set, .avx512dq, 17, ebx7) - try_set(&set, .avx512ifma, 21, ebx7) - try_set(&set, .avx512pf, 26, ebx7) - try_set(&set, .avx512er, 27, ebx7) - try_set(&set, .avx512cd, 28, ebx7) - try_set(&set, .avx512bw, 30, ebx7) + try_set(&_features, .avx512f, 16, ebx7) + try_set(&_features, .avx512dq, 17, ebx7) + try_set(&_features, .avx512ifma, 21, ebx7) + try_set(&_features, .avx512pf, 26, ebx7) + try_set(&_features, .avx512er, 27, ebx7) + try_set(&_features, .avx512cd, 28, ebx7) + try_set(&_features, .avx512bw, 30, ebx7) // XMM/YMM are also required for 128/256-bit instructions if os_supports_avx { - try_set(&set, .avx512vl, 31, ebx7) + try_set(&_features, .avx512vl, 31, ebx7) } - try_set(&set, .avx512vbmi, 1, ecx7) - try_set(&set, .avx512vbmi2, 6, ecx7) - try_set(&set, .avx512vnni, 11, ecx7) - try_set(&set, .avx512bitalg, 12, ecx7) - try_set(&set, .avx512vpopcntdq, 14, ecx7) + try_set(&_features, .avx512vbmi, 1, ecx7) + try_set(&_features, .avx512vbmi2, 6, ecx7) + try_set(&_features, .avx512vnni, 11, ecx7) + try_set(&_features, .avx512bitalg, 12, ecx7) + try_set(&_features, .avx512vpopcntdq, 14, ecx7) - try_set(&set, .avx512vp2intersect, 8, edx7) - try_set(&set, .avx512fp16, 23, edx7) + try_set(&_features, .avx512vp2intersect, 8, edx7) + try_set(&_features, .avx512fp16, 23, edx7) eax7_1, _, _, _ := cpuid(7, 1) - try_set(&set, .avx512bf16, 5, eax7_1) + try_set(&_features, .avx512bf16, 5, eax7_1) } - try_set(&set, .bmi2, 8, ebx7) - try_set(&set, .erms, 9, ebx7) - try_set(&set, .rdseed, 18, ebx7) - try_set(&set, .adx, 19, ebx7) - - cpu.features = set + try_set(&_features, .bmi2, 8, ebx7) + try_set(&_features, .erms, 9, ebx7) + try_set(&_features, .rdseed, 18, ebx7) + try_set(&_features, .adx, 19, ebx7) } @(private) -_cpu_name_buf: [72]u8 +_cpu_features :: proc "contextless" () -> (features: CPU_Features) { + return _features +} + +// `cpuid` is a barrier so we try not performing this query this more than necessary. +// `atomic_load_explicit` is also a barrier, so we're doing this lookup only once, before `main()` +@(private) _name_buf: [72]u8 +@(private) _name: string @(init, private) -init_cpu_name :: proc "contextless" () { +_init_cpu_name :: proc "contextless" () { number_of_extended_ids, _, _, _ := cpuid(0x8000_0000, 0) if number_of_extended_ids < 0x8000_0004 { return } - _buf := (^[0x12]u32)(&_cpu_name_buf) + _buf := (^[0x12]u32)(&_name_buf) _buf[ 0], _buf[ 1], _buf[ 2], _buf[ 3] = cpuid(0x8000_0002, 0) _buf[ 4], _buf[ 5], _buf[ 6], _buf[ 7] = cpuid(0x8000_0003, 0) _buf[ 8], _buf[ 9], _buf[10], _buf[11] = cpuid(0x8000_0004, 0) @@ -170,18 +176,16 @@ init_cpu_name :: proc "contextless" () { // Some CPUs like may include leading or trailing spaces. Trim them. // e.g. ` Intel(R) Xeon(R) CPU E5-1650 v2 @ 3.50GHz` - brand := string(_cpu_name_buf[:]) - for len(brand) > 0 && brand[0] == 0 || brand[0] == ' ' { - brand = brand[1:] + _name = string(_name_buf[:]) + for len(_name) > 0 && _name[0] == 0 || _name[0] == ' ' { + _name = _name[1:] } - for len(brand) > 0 && brand[len(brand) - 1] == 0 || brand[len(brand) - 1] == ' ' { - brand = brand[:len(brand) - 1] + for len(_name) > 0 && _name[len(_name) - 1] == 0 || _name[len(_name) - 1] == ' ' { + _name = _name[:len(_name) - 1] } - cpu.name = brand } -// cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) --- -cpuid :: intrinsics.x86_cpuid - -// xgetbv :: proc(cx: u32) -> (eax, edx: u32) --- -xgetbv :: intrinsics.x86_xgetbv \ No newline at end of file +@(private) +_cpu_name :: proc "contextless" () -> (name: string) { + return _name +} \ No newline at end of file diff --git a/core/sys/info/cpu_linux_arm.odin b/core/sys/info/cpu_linux_arm.odin index 6e8b1a634..492b51c8b 100644 --- a/core/sys/info/cpu_linux_arm.odin +++ b/core/sys/info/cpu_linux_arm.odin @@ -4,10 +4,16 @@ package sysinfo import "base:runtime" import "core:sys/linux" +import "core:strconv" import "core:strings" +@(private) +_cpu_features :: proc "contextless" () -> (features: CPU_Features) { + return _features +} + @(init, private) -init_cpu_features :: proc "contextless" () { +_init_cpu_features :: proc "contextless" () { context = runtime.default_context() fd, err := linux.open("/proc/cpuinfo", {}) if err != .NONE { return } @@ -18,9 +24,6 @@ init_cpu_features :: proc "contextless" () { n, rerr := linux.read(fd, buf[:]) if rerr != .NONE || n == 0 { return } - features: CPU_Features - defer cpu.features = features - str := string(buf[:n]) for line in strings.split_lines_iterator(&str) { key, _, value := strings.partition(line, ":") @@ -31,37 +34,68 @@ init_cpu_features :: proc "contextless" () { for feature in strings.split_by_byte_iterator(&value, ' ') { switch feature { - case "asimd", "neon": features += { .asimd } - case "fp": features += { .floatingpoint } - case "asimdhp": features += { .asimdhp } - case "asimdbf16": features += { .bf16 } - case "fcma": features += { .fcma } - case "asimdfhm": features += { .fhm } - case "fphp", "half": features += { .fp16 } - case "frint": features += { .frint } - case "i8mm": features += { .i8mm } - case "jscvt": features += { .jscvt } - case "asimdrdm": features += { .rdm } + case "asimd", "neon": _features += { .asimd } + case "fp": _features += { .floatingpoint } + case "asimdhp": _features += { .asimdhp } + case "asimdbf16": _features += { .bf16 } + case "fcma": _features += { .fcma } + case "asimdfhm": _features += { .fhm } + case "fphp", "half": _features += { .fp16 } + case "frint": _features += { .frint } + case "i8mm": _features += { .i8mm } + case "jscvt": _features += { .jscvt } + case "asimdrdm": _features += { .rdm } - case "flagm": features += { .flagm } - case "flagm2": features += { .flagm2 } - case "crc32": features += { .crc32 } + case "flagm": _features += { .flagm } + case "flagm2": _features += { .flagm2 } + case "crc32": _features += { .crc32 } - case "atomics": features += { .lse } - case "lrcpc": features += { .lrcpc } - case "ilrcpc": features += { .lrcpc2 } + case "atomics": _features += { .lse } + case "lrcpc": _features += { .lrcpc } + case "ilrcpc": _features += { .lrcpc2 } - case "aes": features += { .aes } - case "pmull": features += { .pmull } - case "sha1": features += { .sha1 } - case "sha2": features += { .sha256 } - case "sha3": features += { .sha3 } - case "sha512": features += { .sha512 } + case "aes": _features += { .aes } + case "pmull": _features += { .pmull } + case "sha1": _features += { .sha1 } + case "sha2": _features += { .sha256 } + case "sha3": _features += { .sha3 } + case "sha512": _features += { .sha512 } - case "sb": features += { .sb } - case "ssbs": features += { .ssbs } + case "sb": _features += { .sb } + case "ssbs": _features += { .ssbs } } } break } } + +@(private) +_cpu_core_count :: proc "contextless" () -> (physical: int, logical: int, ok: bool) { + context = runtime.default_context() + fd, err := linux.open("/proc/cpuinfo", {}) + if err != .NONE { return } + defer linux.close(fd) + + // This is probably enough right? + buf: [4096]byte + n, rerr := linux.read(fd, buf[:]) + if rerr != .NONE || n == 0 { return } + + physical_ok, logical_ok: bool + + str := string(buf[:n]) + for line in strings.split_lines_iterator(&str) { + key, _, value := strings.partition(line, ":") + key = strings.trim_space(key) + value = strings.trim_space(value) + + if key == "cpu cores" && !physical_ok{ + physical, physical_ok = strconv.parse_int(value) + } + + if key == "siblings" && !logical_ok{ + logical, logical_ok = strconv.parse_int(value) + } + } + return physical, logical, physical_ok || logical_ok +} \ No newline at end of file diff --git a/core/sys/info/cpu_linux_intel.odin b/core/sys/info/cpu_linux_intel.odin index af76a75e4..1823678ee 100644 --- a/core/sys/info/cpu_linux_intel.odin +++ b/core/sys/info/cpu_linux_intel.odin @@ -7,10 +7,9 @@ import "core:sys/linux" import "core:strings" import "core:strconv" -@(init, private) -init_cpu_core_count :: proc "contextless" () { +@(private) +_cpu_core_count :: proc "contextless" () -> (physical: int, logical: int, ok: bool) { context = runtime.default_context() - fd, err := linux.open("/proc/cpuinfo", {}) if err != .NONE { return } defer linux.close(fd) @@ -20,22 +19,21 @@ init_cpu_core_count :: proc "contextless" () { n, rerr := linux.read(fd, buf[:]) if rerr != .NONE || n == 0 { return } + physical_ok, logical_ok: bool + str := string(buf[:n]) for line in strings.split_lines_iterator(&str) { key, _, value := strings.partition(line, ":") key = strings.trim_space(key) value = strings.trim_space(value) - if key == "cpu cores" { - if num_physical_cores, ok := strconv.parse_int(value); ok { - cpu.physical_cores = num_physical_cores - } + if key == "cpu cores" && !physical_ok{ + physical, physical_ok = strconv.parse_int(value) } - if key == "siblings" { - if num_logical_cores, ok := strconv.parse_int(value); ok { - cpu.logical_cores = num_logical_cores - } + if key == "siblings" && !logical_ok{ + logical, logical_ok = strconv.parse_int(value) } } + return physical, logical, physical_ok || logical_ok } \ No newline at end of file diff --git a/core/sys/info/cpu_linux_riscv64.odin b/core/sys/info/cpu_linux_riscv64.odin index e65e8a3d2..519c6b315 100644 --- a/core/sys/info/cpu_linux_riscv64.odin +++ b/core/sys/info/cpu_linux_riscv64.odin @@ -3,14 +3,13 @@ package sysinfo import "base:intrinsics" - +import "base:runtime" import "core:sys/linux" +import "core:strconv" +import "core:strings" @(init, private) -init_cpu_features :: proc "contextless" () { - _features: CPU_Features - defer cpu.features = _features - +_init_cpu_features :: proc "contextless" () { HWCAP_Bits :: enum u64 { I = 'I' - 'A', M = 'M' - 'A', @@ -107,7 +106,43 @@ init_cpu_features :: proc "contextless" () { } } -@(init, private) -init_cpu_name :: proc "contextless" () { - cpu.name = "RISCV64" +@(private) +_cpu_features :: proc "contextless" () -> (features: CPU_Features) { + return _features } + +@(private) +_cpu_name :: proc() -> (name: string) { + return "RISCV64" +} + +@(private) +_cpu_core_count :: proc "contextless" () -> (physical: int, logical: int, ok: bool) { + context = runtime.default_context() // No allocations, only needed because `core:strings` wants it. + fd, err := linux.open("/proc/cpuinfo", {}) + if err != .NONE { return } + defer linux.close(fd) + + // This is probably enough right? + buf: [4096]byte + n, rerr := linux.read(fd, buf[:]) + if rerr != .NONE || n == 0 { return } + + physical_ok, logical_ok: bool + + str := string(buf[:n]) + for line in strings.split_lines_iterator(&str) { + key, _, value := strings.partition(line, ":") + key = strings.trim_space(key) + value = strings.trim_space(value) + + if key == "cpu cores" && !physical_ok{ + physical, physical_ok = strconv.parse_int(value) + } + + if key == "siblings" && !logical_ok{ + logical, logical_ok = strconv.parse_int(value) + } + } + return physical, logical, physical_ok || logical_ok +} \ No newline at end of file diff --git a/core/sys/info/cpu_other.odin b/core/sys/info/cpu_other.odin new file mode 100644 index 000000000..cb190a3c4 --- /dev/null +++ b/core/sys/info/cpu_other.odin @@ -0,0 +1,14 @@ +#+build openbsd, freebsd, netbsd, essence, haiku +package sysinfo + +@(private) +_cpu_core_count :: proc "contextless" () -> (physical: int, logical: int, ok: bool) { + return 0, 0, false +} + +when ODIN_ARCH == .arm32 || ODIN_ARCH == .arm64 { + @(private) + _cpu_features :: proc "contextless" () -> (features: CPU_Features) { + return {} + } +} \ No newline at end of file diff --git a/core/sys/info/cpu_riscv64.odin b/core/sys/info/cpu_riscv64.odin index 64f2edfd3..9303e6e79 100644 --- a/core/sys/info/cpu_riscv64.odin +++ b/core/sys/info/cpu_riscv64.odin @@ -95,10 +95,7 @@ CPU_Feature :: enum u64 { } CPU_Features :: distinct bit_set[CPU_Feature; u64] -CPU :: struct { - name: Maybe(string), - features: Maybe(CPU_Features), - physical_cores: int, - logical_cores: int, -} -cpu: CPU \ No newline at end of file + +// Looking up CPU features is expensive on RISCV, and `atomic_load_explicit` +// is also a barrier, so we're doing this lookup only once, before `main()` +@(private) _features: CPU_Features \ No newline at end of file diff --git a/core/sys/info/cpu_wasm.odin b/core/sys/info/cpu_wasm.odin new file mode 100644 index 000000000..f33f7cbb4 --- /dev/null +++ b/core/sys/info/cpu_wasm.odin @@ -0,0 +1,20 @@ +#+build wasm32, wasm64p32 +package sysinfo + +@(private) +_cpu_core_count :: proc "contextless" () -> (physical: int, logical: int, ok: bool) { + return 0, 0, false +} + +CPU_Feature :: enum u64 {} +CPU_Features :: distinct bit_set[CPU_Feature; u64] + +@(private) +_cpu_features :: proc "contextless" () -> (features: CPU_Features) { + return {} +} + +@(private) +_cpu_name :: proc() -> (name: string) { + return "wasm32" when ODIN_ARCH == .wasm32 else "wasm64p32" +} \ No newline at end of file diff --git a/core/sys/info/cpu_windows.odin b/core/sys/info/cpu_windows.odin index 72d79f9a7..604ec3641 100644 --- a/core/sys/info/cpu_windows.odin +++ b/core/sys/info/cpu_windows.odin @@ -2,30 +2,34 @@ package sysinfo import sys "core:sys/windows" import "base:intrinsics" -import "base:runtime" -@(init, private) -init_cpu_core_count :: proc "contextless" () { - context = runtime.default_context() +@(private) +_cpu_core_count :: proc "contextless" () -> (physical: int, logical: int, ok: bool) { + // Reportedly, Windows Server supports a maximum of 256 logical cores. + // The most scratch memory we need therefore is 8192 bytes = 256 * size_of(sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION) + infos: [256]sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION - infos: []sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION - defer delete(infos) - - returned_length: sys.DWORD // Query for the required buffer size. - if ok := sys.GetLogicalProcessorInformation(raw_data(infos), &returned_length); !ok { - infos = make([]sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION, returned_length / size_of(sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION)) + returned_length: sys.DWORD + sys.GetLogicalProcessorInformation(nil, &returned_length) + + if int(returned_length) > size_of(infos) { + return 0, 0, false } + count := int(returned_length) / size_of(sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION) + // If it still doesn't work, return - if ok := sys.GetLogicalProcessorInformation(raw_data(infos), &returned_length); !ok { - return + if ok := sys.GetLogicalProcessorInformation(raw_data(infos[:]), &returned_length); !ok { + return 0, 0, false } - for info in infos { + for info in infos[:count] { #partial switch info.Relationship { - case .RelationProcessorCore: cpu.physical_cores += 1 - case .RelationNumaNode: cpu.logical_cores += int(intrinsics.count_ones(info.ProcessorMask)) + case .RelationProcessorCore: physical += 1 + case .RelationNumaNode: logical += int(intrinsics.count_ones(info.ProcessorMask)) } } + + return physical, logical, true } \ No newline at end of file diff --git a/core/sys/info/doc.odin b/core/sys/info/doc.odin index 10ad7a127..b235eb5f4 100644 --- a/core/sys/info/doc.odin +++ b/core/sys/info/doc.odin @@ -6,8 +6,8 @@ and CPU information. On Windows, GPUs will also be enumerated using the registry. -CPU feature flags can be tested against `cpu_features`, where applicable, e.g. -`if .aes in info.cpu_features.? { ... }` +CPU feature flags can be tested against `cpu_features`, where applicable, e.g.: +`if .aes in info.cpu_features() { ... }` Example: package main @@ -16,66 +16,93 @@ Example: import si "core:sys/info" main :: proc() { - fmt.printfln("Odin: %v", ODIN_VERSION) - fmt.printfln("OS: %v", si.os_version.as_string) - fmt.printfln("OS: %#v", si.os_version) - fmt.printfln("CPU: %v", si.cpu.name) - fmt.printfln("CPU cores: %vc/%vt", si.cpu.physical_cores, si.cpu.logical_cores) - fmt.printfln("RAM: %#.1M", si.ram.total_ram) + fmt.printfln("Odin: %v", ODIN_VERSION) + if version, version_ok := si.os_version(context.allocator); version_ok { + defer si.destroy_os_version(version, context.allocator) + fmt.printfln("OS (full): %v", version.full) + fmt.printfln("OS (rel): %v", version.release) + fmt.printfln("OS: %v", version.os) + fmt.printfln("Kernel: %v", version.kernel) + } + fmt.printfln("CPU: %v", si.cpu_name()) + fmt.printfln(" %v", si.cpu_features()) + if physical, logical, cores_ok := si.cpu_core_count(); cores_ok { + fmt.printfln("CPU cores: %vc/%vt", physical, logical) + } - fmt.println() - for gpu, i in si.gpus { - fmt.printfln("GPU #%v:", i) - fmt.printfln("\tVendor: %v", gpu.vendor_name) - fmt.printfln("\tModel: %v", gpu.model_name) - fmt.printfln("\tVRAM: %#.1M", gpu.total_ram) + if total_ram, free_ram, total_swap, free_swap, ram_ok := si.ram_stats(); ram_ok { + fmt.printfln("RAM: %#.1M/%#.1M", free_ram, total_ram) + fmt.printfln("SWAP: %#.1M/%#.1M", free_swap, total_swap) + } + + it: si.GPU_Iterator + for gpu, i in si.iterate_gpus(&it) { + fmt.printfln("%d:", i) + fmt.printfln("\tVendor: %v", gpu.vendor) + fmt.printfln("\tModel: %v", gpu.model) + fmt.printfln("\tVRAM: %#.1M", gpu.vram) + fmt.printfln("\tDriver: %v", gpu.driver) } } -- Example Windows output: + /* + Example Windows output: - Odin: dev-2025-10 - OS: Windows 10 Professional (version: 22H2), build: 19045.6396 - OS: OS_Version{ - platform = "Windows", - _ = Version{ - major = 10, - minor = 0, - patch = 0, - }, - build = [ - 19045, - 6396, - ], - version = "22H2", - as_string = "Windows 10 Professional (version: 22H2), build: 19045.6396", - } - CPU: AMD Ryzen 9 5950X 16-Core Processor - CPU cores: 16c/32t - RAM: 63.9 GiB + Odin: dev-2026-02 + OS (full): Windows 10 Professional (version: 22H2), build: 19045.6575 + OS (rel): 22H2 + OS: Version{major = 10, minor = 0, patch = 0} + Kernel: Version{major = 10, minor = 19045, patch = 6575} + CPU: AMD Ryzen 9 5950X 16-Core Processor + CPU_Features{aes, adx, avx, avx2, bmi1, bmi2, erms, fma, os_xsave, pclmulqdq, popcnt, rdrand, rdseed, sha, sse2, sse3, ssse3, sse41, sse42} + CPU cores: 16c/32t + RAM: 32.1 GiB/63.9 GiB + SWAP: 21.6 GiB/73.4 GiB - GPU #0: - Vendor: Advanced Micro Devices, Inc. - Model: AMD Radeon RX 9070 - VRAM: 15.9 GiB + GPU #0: + Vendor: Advanced Micro Devices, Inc. + Model: AMD Radeon RX 9070 + VRAM: 15.9 GiB + Driver: 32.0.22029.1019 -- Example macOS output: + Example Linux output: - ODIN: dev-2022-09 - OS: OS_Version{ - platform = "MacOS", - major = 21, - minor = 5, - patch = 0, - build = [ - 0, - 0, - ], - version = "21F79", - as_string = "macOS Monterey 12.4 (build 21F79, kernel 21.5.0)", - } - CPU: Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz - RAM: 8.0 GiB + Odin: dev-2026-02 + OS (full): Ubuntu 24.04.3 LTS, Linux 6.6.87.2-microsoft-standard-WSL2 + OS (rel): microsoft-standard-WSL2 + OS: Version{major = 24, minor = 4, patch = 3} + Kernel: Version{major = 6, minor = 6, patch = 87} + CPU: AMD Ryzen 9 5950X 16-Core Processor + CPU_Features{aes, adx, avx, avx2, bmi1, bmi2, erms, fma, os_xsave, pclmulqdq, popcnt, rdrand, rdseed, sha, sse2, sse3, ssse3, sse41, sse42} + CPU cores: 16c/32t + RAM: 29.2 GiB/31.3 GiB + SWAP: 8.0 GiB/8.0 GiB + + Example macOS output: + + Odin: dev-2026-02 + OS (full): macOS Tahoe 26.3.0 (build 25D125, kernel 25.3.0) + OS (rel): 25D125 + OS: Version{major = 26, minor = 3, patch = 0} + Kernel: Version{major = 25, minor = 3, patch = 0} + CPU: Apple M4 Pro + CPU_Features{asimd, floatingpoint, asimdhp, bf16, fcma, fhm, fp16, frint, i8mm, jscvt, rdm, flagm, flagm2, crc32, lse, lrcpc, lrcpc2, aes, pmull, sha1, sha256, sha512, sha3, sb} + CPU cores: 12c/12t + RAM: 0.0 B/24.0 GiB + SWAP: 0.0 B/0.0 B + + Example FreeBSD output: + + Odin: dev-2026-02 + OS (full): FreeBSD 15.0-RELEASE-p2 releng/15.0-n281005-5fb0f8e9e61d GENERIC, revision 199506 + OS (rel): + OS: Version{major = 15, minor = 0, patch = 199506} + Kernel: Version{major = 15, minor = 0, patch = 199506} + CPU: AMD Ryzen 9 5950X 16-Core Processor + CPU_Features{aes, fma, os_xsave, pclmulqdq, popcnt, rdrand, sse2, sse3, ssse3, sse41, sse42} + RAM: 7.6 GiB/7.9 GiB + SWAP: 0.0 B/0.0 B + */ */ package sysinfo diff --git a/core/sys/info/platform_bsd.odin b/core/sys/info/platform_bsd.odin index 2f8d7f5bb..431b48200 100644 --- a/core/sys/info/platform_bsd.odin +++ b/core/sys/info/platform_bsd.odin @@ -1,27 +1,20 @@ #+build openbsd, netbsd package sysinfo -import sys "core:sys/unix" -import "core:strings" -import "core:strconv" import "base:runtime" +import "core:strings" +import sys "core:sys/unix" -@(private) -version_string_buf: [1024]u8 - -@(init, private) -init_os_version :: proc "contextless" () { - context = runtime.default_context() - +_os_version :: proc (allocator: runtime.Allocator, loc := #caller_location) -> (res: OS_Version, ok: bool) { when ODIN_OS == .NetBSD { - os_version.platform = .NetBSD + res.platform = .NetBSD } else { - os_version.platform = .OpenBSD + res.platform = .OpenBSD } kernel_version_buf: [1024]u8 - b := strings.builder_from_bytes(version_string_buf[:]) + b := strings.builder_make_none(allocator = allocator, loc = loc) // Retrieve kernel info using `sysctl`, e.g. OpenBSD and NetBSD mib := []i32{sys.CTL_KERN, sys.KERN_OSTYPE} if !sys.sysctl(mib, &kernel_version_buf) { @@ -39,19 +32,8 @@ init_os_version :: proc "contextless" () { version := string(cstring(raw_data(kernel_version_buf[:]))) strings.write_string(&b, version) - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - // Parse kernel version - triplet := strings.split(version, ".", context.temp_allocator) - if len(triplet) == 2 { - major, major_ok := strconv.parse_int(triplet[0]) - minor, minor_ok := strconv.parse_int(triplet[1]) - - if major_ok && minor_ok { - os_version.major = major - os_version.minor = minor - } - } + res.kernel = _parse_version(version) // Retrieve kernel revision using `sysctl`, e.g. 199506 mib = []i32{sys.CTL_KERN, sys.KERN_OSREV} @@ -59,20 +41,27 @@ init_os_version :: proc "contextless" () { if !sys.sysctl(mib, &revision) { return } - os_version.patch = revision + res.kernel.patch = revision strings.write_string(&b, ", build ") strings.write_int(&b, revision) // Finalize pretty name. - os_version.as_string = strings.to_string(b) + res.full = strings.to_string(b) + + return res, true } -@(init, private) -init_ram :: proc "contextless" () { +@(private) +_ram_stats :: proc "contextless" () -> (total_ram, free_ram, total_swap, free_swap: i64, ok: bool) { // Retrieve RAM info using `sysctl` mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM64} - mem_size: u64 - if sys.sysctl(mib, &mem_size) { - ram.total_ram = int(mem_size) + if sys.sysctl(mib, &total_ram) { + ok = true } -} + + mib = []i32{sys.CTL_HW, sys.HW_USERMEM64} + if sys.sysctl(mib, &free_ram) { + ok = true + } + return +} \ No newline at end of file diff --git a/core/sys/info/platform_darwin.odin b/core/sys/info/platform_darwin.odin index 07c26ec28..fe0b5ab2b 100644 --- a/core/sys/info/platform_darwin.odin +++ b/core/sys/info/platform_darwin.odin @@ -1,22 +1,16 @@ package sysinfo -import "base:runtime" - -import "core:strconv" +import "base:runtime" import "core:strings" import "core:sys/unix" import NS "core:sys/darwin/Foundation" @(private) -version_string_buf: [1024]u8 - -@(init, private) -init_platform :: proc "contextless" () { - context = runtime.default_context() +_os_version :: proc (allocator: runtime.Allocator, loc := #caller_location) -> (res: OS_Version, ok: bool) { ws :: strings.write_string wi :: strings.write_int - b := strings.builder_from_bytes(version_string_buf[:]) + b := strings.builder_make_none(allocator = allocator, loc = loc) version: NS.OperatingSystemVersion { @@ -24,18 +18,15 @@ init_platform :: proc "contextless" () { info := NS.ProcessInfo.processInfo() version = info->operatingSystemVersion() - mem := info->physicalMemory() - - ram.total_ram = int(mem) } - macos_version = {int(version.majorVersion), int(version.minorVersion), int(version.patchVersion)} + res.os = {int(version.majorVersion), int(version.minorVersion), int(version.patchVersion)} when ODIN_PLATFORM_SUBTARGET_IOS { - os_version.platform = .iOS + res.platform = .iOS ws(&b, "iOS") } else { - os_version.platform = .MacOS + res.platform = .MacOS switch version.majorVersion { case 26: ws(&b, "macOS Tahoe") case 15: ws(&b, "macOS Sequoia") @@ -72,34 +63,37 @@ init_platform :: proc "contextless" () { { build_buf: [12]u8 mib := []i32{unix.CTL_KERN, unix.KERN_OSVERSION} - ok := unix.sysctl(mib, &build_buf) - build := string(cstring(raw_data(build_buf[:]))) if ok else "Unknown" - + build := "Unknown" + if unix.sysctl(mib, &build_buf) { + build = string(cstring(raw_data(build_buf[:]))) + } ws(&b, " (build ") - build_start := len(b.buf) ws(&b, build) - os_version.version = string(b.buf[build_start:][:len(build)]) + res.release = string(b.buf[build_start:][:len(build)]) } { // Match on XNU kernel version version_bits: [12]u8 // enough for 999.999.999\x00 mib := []i32{unix.CTL_KERN, unix.KERN_OSRELEASE} - ok := unix.sysctl(mib, &version_bits) - kernel := string(cstring(raw_data(version_bits[:]))) if ok else "Unknown" - - major, _, tail := strings.partition(kernel, ".") - minor, _, patch := strings.partition(tail, ".") - - os_version.major, _ = strconv.parse_int(major, 10) - os_version.minor, _ = strconv.parse_int(minor, 10) - os_version.patch, _ = strconv.parse_int(patch, 10) - + kernel := "Unknown" + if unix.sysctl(mib, &version_bits) { + kernel = string(cstring(raw_data(version_bits[:]))) + res.kernel = _parse_version(kernel) + } ws(&b, ", kernel ") ws(&b, kernel) ws(&b, ")") } - os_version.as_string = string(b.buf[:]) + res.full = strings.to_string(b) + return res, true } + +@(private) +_ram_stats :: proc "contextless" () -> (total_ram, free_ram, total_swap, free_swap: i64, ok: bool) { + NS.scoped_autoreleasepool() + info := NS.ProcessInfo.processInfo() + return i64(info->physicalMemory()), 0, 0, 0, true +} \ No newline at end of file diff --git a/core/sys/info/platform_freebsd.odin b/core/sys/info/platform_freebsd.odin index eb39769de..6f32d4232 100644 --- a/core/sys/info/platform_freebsd.odin +++ b/core/sys/info/platform_freebsd.odin @@ -2,21 +2,15 @@ package sysinfo import sys "core:sys/unix" import "core:strings" -import "core:strconv" import "base:runtime" @(private) -version_string_buf: [1024]u8 - -@(init, private) -init_os_version :: proc "contextless" () { - context = runtime.default_context() - - os_version.platform = .FreeBSD +_os_version :: proc (allocator: runtime.Allocator, loc := #caller_location) -> (res: OS_Version, ok: bool) { + res.platform = .FreeBSD kernel_version_buf: [1024]u8 - b := strings.builder_from_bytes(version_string_buf[:]) + b := strings.builder_make_none(allocator = allocator, loc = loc) // Retrieve kernel info using `sysctl`, e.g. FreeBSD 13.1-RELEASE-p2 GENERIC mib := []i32{sys.CTL_KERN, sys.KERN_VERSION} if !sys.sysctl(mib, &kernel_version_buf) { @@ -27,21 +21,18 @@ init_os_version :: proc "contextless" () { pretty_name = strings.trim(pretty_name, "\n") strings.write_string(&b, pretty_name) - // l := strings.builder_len(b) - // Retrieve kernel revision using `sysctl`, e.g. 199506 mib = []i32{sys.CTL_KERN, sys.KERN_OSREV} revision: int if !sys.sysctl(mib, &revision) { return } - os_version.patch = revision strings.write_string(&b, ", revision ") strings.write_int(&b, revision) // Finalize pretty name. - os_version.as_string = strings.to_string(b) + res.full = strings.to_string(b) // Retrieve kernel release using `sysctl`, e.g. 13.1-RELEASE-p2 mib = []i32{sys.CTL_KERN, sys.KERN_OSRELEASE} @@ -49,32 +40,28 @@ init_os_version :: proc "contextless" () { return } - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - // Parse kernel version release := string(cstring(raw_data(kernel_version_buf[:]))) - version_bits := strings.split_n(release, "-", 2, context.temp_allocator) - if len(version_bits) > 1 { - // Parse major, minor from KERN_OSRELEASE - triplet := strings.split(version_bits[0], ".", context.temp_allocator) - if len(triplet) == 2 { - major, major_ok := strconv.parse_int(triplet[0]) - minor, minor_ok := strconv.parse_int(triplet[1]) + version_bits, _, _ := strings.partition(release, "-") + res.kernel = _parse_version(version_bits) + res.kernel.patch = revision - if major_ok && minor_ok { - os_version.major = major - os_version.minor = minor - } - } - } + res.os = res.kernel + + return res, true } -@(init, private) -init_ram :: proc "contextless" () { +@(private) +_ram_stats :: proc "contextless" () -> (total_ram, free_ram, total_swap, free_swap: i64, ok: bool) { // Retrieve RAM info using `sysctl` mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM} - mem_size: u64 - if sys.sysctl(mib, &mem_size) { - ram.total_ram = int(mem_size) + if sys.sysctl(mib, &total_ram) { + ok = true } -} \ No newline at end of file + + mib = []i32{sys.CTL_HW, sys.HW_USERMEM} + if sys.sysctl(mib, &free_ram) { + ok = true + } + return +} diff --git a/core/sys/info/platform_linux.odin b/core/sys/info/platform_linux.odin index 43cd580c1..7886b6243 100644 --- a/core/sys/info/platform_linux.odin +++ b/core/sys/info/platform_linux.odin @@ -2,21 +2,14 @@ package sysinfo import "base:intrinsics" import "base:runtime" - -import "core:strconv" import "core:strings" import "core:sys/linux" @(private) -version_string_buf: [1024]u8 +_os_version :: proc (allocator: runtime.Allocator, loc := #caller_location) -> (res: OS_Version, ok: bool) { + res.platform = .Linux -@(init, private) -init_os_version :: proc "contextless" () { - context = runtime.default_context() - - os_version.platform = .Linux - - b := strings.builder_from_bytes(version_string_buf[:]) + b := strings.builder_make_none(allocator = allocator, loc = loc) // Try to parse `/etc/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS` pretty_parse: { @@ -26,10 +19,7 @@ init_os_version :: proc "contextless" () { break pretty_parse } - defer { - cerrno := linux.close(fd) - assert(cerrno == .NONE, "Failed to close the file descriptor") - } + defer linux.close(fd) os_release_buf: [2048]u8 n, read_errno := linux.read(fd, os_release_buf[:]) @@ -39,17 +29,27 @@ init_os_version :: proc "contextless" () { } release := string(os_release_buf[:n]) - // Search the line in the file until we find "PRETTY_NAME=" - NEEDLE :: "PRETTY_NAME=\"" - _, _, post := strings.partition(release, NEEDLE) - if len(post) > 0 { - end := strings.index_any(post, "\"\n") - if end > -1 && post[end] == '"' { - strings.write_string(&b, post[:end]) + { + // Search the line in the file until we find "PRETTY_NAME=" + _, _, post := strings.partition(release, `PRETTY_NAME="`) + if len(post) > 0 { + end := strings.index_any(post, "\"\n") + if end > -1 && post[end] == '"' { + strings.write_string(&b, post[:end]) + } + } + if strings.builder_len(b) == 0 { + strings.write_string(&b, "Unknown Linux Distro") } } - if strings.builder_len(b) == 0 { - strings.write_string(&b, "Unknown Linux Distro") + + { + // Search the line in the file until we find "VERSION=" + _, _, post := strings.partition(release, `VERSION="`) + if len(post) > 0 { + pre, _, _ := strings.partition(post, ` `) + res.os = _parse_version(pre) + } } } @@ -66,43 +66,30 @@ init_os_version :: proc "contextless" () { strings.write_string(&b, string(cstring(&uts.release[0]))) release_str := string(b.buf[release_i:]) - os_version.as_string = strings.to_string(b) + res.full = strings.to_string(b) // Parse the Linux version out of the release string version_loop: { version_num, _, version_suffix := strings.partition(release_str, "-") - os_version.version = version_suffix + res.release = version_suffix + res.kernel = _parse_version(version_num) - i: int - for part in strings.split_iterator(&version_num, ".") { - defer i += 1 - - dst: ^int - switch i { - case 0: dst = &os_version.major - case 1: dst = &os_version.minor - case 2: dst = &os_version.patch - case: break version_loop - } - - num, ok := strconv.parse_int(part) - if !ok { break version_loop } - - dst^ = num - } } + return res, true } -@(init, private) -init_ram :: proc "contextless" () { +@(private) +_ram_stats :: proc "contextless" () -> (total_ram, free_ram, total_swap, free_swap: i64, ok: bool) { // Retrieve RAM info using `sysinfo` sys_info: linux.Sys_Info errno := linux.sysinfo(&sys_info) assert_contextless(errno == .NONE, "Good luck to whoever's debugging this, something's seriously cucked up!") - ram = RAM{ - total_ram = int(sys_info.totalram) * int(sys_info.mem_unit), - free_ram = int(sys_info.freeram) * int(sys_info.mem_unit), - total_swap = int(sys_info.totalswap) * int(sys_info.mem_unit), - free_swap = int(sys_info.freeswap) * int(sys_info.mem_unit), - } -} + + total_ram = i64(sys_info.totalram) * i64(sys_info.mem_unit) + free_ram = i64(sys_info.freeram) * i64(sys_info.mem_unit) + total_swap = i64(sys_info.totalswap) * i64(sys_info.mem_unit) + free_swap = i64(sys_info.freeswap) * i64(sys_info.mem_unit) + ok = true + + return +} \ No newline at end of file diff --git a/core/sys/info/platform_other.odin b/core/sys/info/platform_other.odin new file mode 100644 index 000000000..86325ee72 --- /dev/null +++ b/core/sys/info/platform_other.odin @@ -0,0 +1,14 @@ +#+build essence, haiku +package sysinfo + +import "base:runtime" + +@(private) +_ram_stats :: proc "contextless" () -> (total_ram, free_ram, total_swap, free_swap: i64, ok: bool) { + return +} + +@(private) +_os_version :: proc(allocator: runtime.Allocator, loc := #caller_location) -> (res: OS_Version, ok: bool) { + return {}, false +} \ No newline at end of file diff --git a/core/sys/info/platform_wasm.odin b/core/sys/info/platform_wasm.odin new file mode 100644 index 000000000..2778862e9 --- /dev/null +++ b/core/sys/info/platform_wasm.odin @@ -0,0 +1,14 @@ +#+build wasm32, wasm64p32 +package sysinfo + +import "base:runtime" + +@(private) +_ram_stats :: proc "contextless" () -> (total_ram, free_ram, total_swap, free_swap: i64, ok: bool) { + return +} + +@(private) +_os_version :: proc(allocator: runtime.Allocator, loc := #caller_location) -> (res: OS_Version, ok: bool) { + return {}, false +} \ No newline at end of file diff --git a/core/sys/info/platform_windows.odin b/core/sys/info/platform_windows.odin index bad99f811..e7d3baa83 100644 --- a/core/sys/info/platform_windows.odin +++ b/core/sys/info/platform_windows.odin @@ -1,38 +1,27 @@ package sysinfo +import "base:intrinsics" +import "base:runtime" +import "core:strings" +import "core:unicode/utf16" import sys "core:sys/windows" -import "base:intrinsics" -import "core:strings" -import "core:strconv" -import "core:unicode/utf16" - -// import "core:fmt" -import "base:runtime" @(private) -version_string_buf: [1024]u8 - -@(init, private) -init_os_version :: proc "contextless" () { - context = runtime.default_context() - +_os_version :: proc (allocator: runtime.Allocator, loc := #caller_location) -> (res: OS_Version, ok: bool) { /* - NOTE(Jeroen): - `GetVersionEx` will return 6.2 for Windows 10 unless the program is manifested for Windows 10. - `RtlGetVersion` will return the true version. - - Rather than include the WinDDK, we ask the kernel directly. - `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion` is for the minor build version (Update Build Release) + NOTE(Jeroen): + `GetVersionEx` will return 6.2 for Windows 10 unless the program is manifested for Windows 10. + `RtlGetVersion` will return the true version. + Rather than include the WinDDK, we ask the kernel directly. + `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion` is for the minor build version (Update Build Release) */ - os_version.platform = .Windows + res.platform = .Windows osvi: sys.OSVERSIONINFOEXW osvi.dwOSVersionInfoSize = size_of(osvi) - status := sys.RtlGetVersion(&osvi) - - if status != 0 { - return + if status := sys.RtlGetVersion(&osvi); status != 0 { + return res, false } product_type: sys.Windows_Product_Type @@ -42,12 +31,13 @@ init_os_version :: proc "contextless" () { &product_type, ) - os_version.major = int(osvi.dwMajorVersion) - os_version.minor = int(osvi.dwMinorVersion) - os_version.build[0] = int(osvi.dwBuildNumber) + res.os.major = int(osvi.dwMajorVersion) + res.os.minor = int(osvi.dwMinorVersion) + res.kernel.major = int(osvi.dwMajorVersion) + res.kernel.minor = int(osvi.dwBuildNumber) + b := strings.builder_make_none(allocator = allocator, loc = loc) - b := strings.builder_from_bytes(version_string_buf[:]) strings.write_string(&b, "Windows ") switch osvi.dwMajorVersion { @@ -125,13 +115,13 @@ init_os_version :: proc "contextless" () { } // Grab DisplayVersion - os_version.version = format_display_version(&b) + res.release = format_display_version(&b) // Grab build number and UBR - os_version.build[1] = format_build_number(&b, int(osvi.dwBuildNumber)) + res.kernel.patch = format_build_number(&b, int(osvi.dwBuildNumber)) // Finish the string - os_version.as_string = strings.to_string(b) + res.full = strings.to_string(b) format_windows_product_type :: proc (b: ^strings.Builder, prod_type: sys.Windows_Product_Type) { #partial switch prod_type { @@ -226,14 +216,14 @@ init_os_version :: proc "contextless" () { // Grab Windows DisplayVersion (like 20H02) format_display_version :: proc (b: ^strings.Builder) -> (version: string) { - dv, ok := read_reg_string( + scratch: [512]u8 + + if dv, ok := read_reg_string( sys.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "DisplayVersion", - ) - defer delete(dv) // It'll be interned into `version_string_buf` - - if ok { + scratch[:], + ); ok { strings.write_string(b, " (version: ") l := strings.builder_len(b^) strings.write_string(b, dv) @@ -245,13 +235,11 @@ init_os_version :: proc "contextless" () { // Grab build number and UBR format_build_number :: proc (b: ^strings.Builder, major_build: int) -> (ubr: int) { - res, ok := read_reg_i32( + if res, ok := read_reg_i32( sys.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "UBR", - ) - - if ok { + ); ok { ubr = int(res) strings.write_string(b, ", build: ") strings.write_int(b, major_build) @@ -260,31 +248,32 @@ init_os_version :: proc "contextless" () { } return } + + return res, true } -@(init, private) -init_ram :: proc "contextless" () { +@(private) +_ram_stats :: proc "contextless" () -> (total_ram, free_ram, total_swap, free_swap: i64, ok: bool) { state: sys.MEMORYSTATUSEX state.dwLength = size_of(state) - ok := sys.GlobalMemoryStatusEx(&state) - if !ok { + if ok := sys.GlobalMemoryStatusEx(&state); !ok { return } - ram = RAM{ - total_ram = int(state.ullTotalPhys), - free_ram = int(state.ullAvailPhys), - total_swap = int(state.ullTotalPageFil), - free_swap = int(state.ullAvailPageFil), - } + + total_ram = i64(state.ullTotalPhys) + free_ram = i64(state.ullAvailPhys) + total_swap = i64(state.ullTotalPageFil) + free_swap = i64(state.ullAvailPageFil) + ok = true + + return } -@(init, private) -init_gpu_info :: proc "contextless" () { +_iterate_gpus :: proc(it: ^GPU_Iterator, minimum_vram := i64(256 * 1024 * 1024)) -> (gpu: GPU, index: int, ok: bool) { GPU_ROOT_KEY :: `SYSTEM\ControlSet001\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}` - context = runtime.default_context() - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + defer it.index += 1 gpu_key: sys.HKEY if status := sys.RegOpenKeyExW( @@ -294,83 +283,82 @@ init_gpu_info :: proc "contextless" () { sys.KEY_ENUMERATE_SUB_KEYS, &gpu_key, ); status != i32(sys.ERROR_SUCCESS) { - return + return {}, it.index, false } defer sys.RegCloseKey(gpu_key) - gpu_list: [dynamic]GPU - gpu: ^GPU + buf_wstring: [100]u16 + buf_len := u32(len(buf_wstring)) + buf_key: [4 * len(buf_wstring)]u8 + buf_leaf: [100]u8 + leaf: string - index := sys.DWORD(0) - for { - defer index += 1 - - buf_wstring: [100]u16 - buf_len := u32(len(buf_wstring)) - buf_utf8: [4 * len(buf_wstring)]u8 + gpu_loop: { + defer it._index += 1 if status := sys.RegEnumKeyW( gpu_key, - index, + auto_cast it._index, &buf_wstring[0], &buf_len, ); status != i32(sys.ERROR_SUCCESS) { - break + return {}, it.index, false } - utf16.decode_to_utf8(buf_utf8[:], buf_wstring[:]) - leaf := string(cstring(&buf_utf8[0])) + utf16.decode_to_utf8(buf_leaf[:], buf_wstring[:]) + leaf = string(cstring(&buf_leaf[0])) - // Skip leafs that are not of the form 000x - if _, is_integer := strconv.parse_int(leaf, 10); !is_integer { - continue - } - - key := strings.concatenate({GPU_ROOT_KEY, "\\", leaf}, context.temp_allocator) - - if vendor, ok := read_reg_string(sys.HKEY_LOCAL_MACHINE, key, "ProviderName"); ok { - idx := append(&gpu_list, GPU{vendor_name = vendor}) - gpu = &gpu_list[idx - 1] - } else { - continue - } - - if desc, ok := read_reg_string(sys.HKEY_LOCAL_MACHINE, key, "DriverDesc"); ok { - gpu.model_name = desc - } - - if vram, ok := read_reg_i64(sys.HKEY_LOCAL_MACHINE, key, "HardwareInformation.qwMemorySize"); ok { - gpu.total_ram = int(vram) + // Skip leaves that are not of the form 000x + if is_integer(leaf) { + break gpu_loop } } - gpus = gpu_list[:] + + n := copy(buf_key[:], GPU_ROOT_KEY) + buf_key[n] = '\\' + copy(buf_key[n+1:], leaf) + + key_len := len(GPU_ROOT_KEY) + len(leaf) + 1 + + utf16.encode_string(buf_wstring[:], string(buf_key[:key_len])) + key := cstring16(&buf_wstring[0]) + + // Determine if this is a real GPU, or perhaps a screen mirroring or RDP driver + // Real devices tend to have more than 256 MiB of VRAM + gpu.vram, _ = read_reg_i64 (sys.HKEY_LOCAL_MACHINE, key, "HardwareInformation.qwMemorySize") + if gpu.vram < minimum_vram { + return + } + + // Real devices tend to have a matching PCI device + matching, _ := read_reg_string(sys.HKEY_LOCAL_MACHINE, key, "MatchingDeviceId", it._buffer[:100]) + if !strings.has_prefix(matching, "PCI\\VEN") { + return + } + + gpu.vendor, _ = read_reg_string(sys.HKEY_LOCAL_MACHINE, key, "ProviderName", it._buffer[ 0:][:100]) + gpu.model, _ = read_reg_string(sys.HKEY_LOCAL_MACHINE, key, "DriverDesc", it._buffer[100:][:100]) + gpu.driver, _ = read_reg_string(sys.HKEY_LOCAL_MACHINE, key, "DriverVersion", it._buffer[200:][:100]) + + return gpu, it.index, true } @(private) -read_reg_string :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: string, ok: bool) { +read_reg_string :: proc "contextless" (hkey: sys.HKEY, subkey, val: cstring16, res_buf: []u8) -> (res: string, ok: bool) { if len(subkey) == 0 || len(val) == 0 { return } - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - - BUF_SIZE :: 1024 - key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator) - val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator) - - utf16.encode_string(key_name_wide, subkey) - utf16.encode_string(val_name_wide, val) - - result_wide := make([]u16, BUF_SIZE, context.temp_allocator) - result_size := sys.DWORD(BUF_SIZE * size_of(u16)) + buf_utf16: [1024]u16 + result_size := sys.DWORD(size_of(buf_utf16)) status := sys.RegGetValueW( hkey, - cstring16(&key_name_wide[0]), - cstring16(&val_name_wide[0]), + subkey, + val, sys.RRF_RT_REG_SZ, nil, - raw_data(result_wide[:]), + raw_data(buf_utf16[:]), &result_size, ) if status != 0 { @@ -378,31 +366,22 @@ read_reg_string :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: string, ok return } - // Result string will be allocated for the caller. - result_utf8 := make([]u8, BUF_SIZE * 4, context.temp_allocator) - utf16.decode_to_utf8(result_utf8, result_wide[:result_size]) - return strings.clone_from_cstring(cstring(raw_data(result_utf8))), true + utf16.decode_to_utf8(res_buf[:result_size], buf_utf16[:]) + res = string(cstring(&res_buf[0])) + return res, true } + @(private) -read_reg_i32 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i32, ok: bool) { +read_reg_i32 :: proc "contextless" (hkey: sys.HKEY, subkey, val: cstring16) -> (res: i32, ok: bool) { if len(subkey) == 0 || len(val) == 0 { return } - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - - BUF_SIZE :: 1024 - key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator) - val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator) - - utf16.encode_string(key_name_wide, subkey) - utf16.encode_string(val_name_wide, val) - result_size := sys.DWORD(size_of(i32)) status := sys.RegGetValueW( hkey, - cstring16(&key_name_wide[0]), - cstring16(&val_name_wide[0]), + subkey, + val, sys.RRF_RT_REG_DWORD, nil, &res, @@ -410,26 +389,18 @@ read_reg_i32 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i32, ok: bool ) return res, status == 0 } + @(private) -read_reg_i64 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i64, ok: bool) { +read_reg_i64 :: proc "contextless" (hkey: sys.HKEY, subkey, val: cstring16) -> (res: i64, ok: bool) { if len(subkey) == 0 || len(val) == 0 { return } - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - - BUF_SIZE :: 1024 - key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator) - val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator) - - utf16.encode_string(key_name_wide, subkey) - utf16.encode_string(val_name_wide, val) - result_size := sys.DWORD(size_of(i64)) status := sys.RegGetValueW( hkey, - cstring16(&key_name_wide[0]), - cstring16(&val_name_wide[0]), + subkey, + val, sys.RRF_RT_REG_QWORD, nil, &res, @@ -437,3 +408,20 @@ read_reg_i64 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i64, ok: bool ) return res, status == 0 } + +@(private) +is_integer :: proc "contextless" (s: string) -> (ok: bool) { + if s == "" { + return + } + + ok = true + + for r in s { + switch r { + case '0'..='9': continue + case: return false + } + } + return +} \ No newline at end of file diff --git a/core/sys/info/sysinfo.odin b/core/sys/info/sysinfo.odin index 75cc237c6..ad120b264 100644 --- a/core/sys/info/sysinfo.odin +++ b/core/sys/info/sysinfo.odin @@ -1,15 +1,109 @@ package sysinfo -when !(ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 || ODIN_ARCH == .arm32 || ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 || ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32) { - #assert(false, "This package is unsupported on this architecture.") +import "base:runtime" +import "core:strings" +import "core:strconv" + +#assert( + ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 || \ + ODIN_ARCH == .arm32 || ODIN_ARCH == .arm64 || \ + ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 || \ + ODIN_ARCH == .riscv64, + "This package is unsupported on this architecture.") + +/* +Retrieves the number of physical and logical CPU cores + +Returns: +- physical: The number of physical cores +- logical: The number of logical cores +- ok: `true` when we could retrieve the CPU information, `false` otherwise +*/ +cpu_core_count :: proc "contextless" () -> (physical: int, logical: int, ok: bool) { + return _cpu_core_count() } -os_version: OS_Version -ram: RAM -gpus: []GPU +/* +Returns CPU features where available -// Only on MacOS, contains the actual MacOS version, while the `os_version` contains the kernel version. -macos_version: Version +The results are looked up before `main` enters and cached + +Returns: +- features: An architecture-specific `bit_set`, empty if we couldn't retrieve them +*/ +cpu_features :: proc "contextless" () -> (features: CPU_Features) { + return _cpu_features() +} + +/* +Returns the CPU's name + +The results are looked up before `main` enters and cached + +Returns: +- name: A `string` containing the CPU model name, empty if the lookup failed +*/ +cpu_name :: proc() -> (name: string) { + return _cpu_name() +} + +/* +Retrieves RAM statistics + +Unavailable stats will be returned as `0` bytes + +Returns: +- total_ram: Total RAM reported by the operating system, in bytes +- free_ram: Free RAM reported by the operating system, in bytes +- total_swap: Total SWAP reported by the operating system, in bytes +- free_swap: Free SWAP reported by the operating system, in bytes +- ok: `true` when we could retrieve RAM statistics, `false` otherwise +*/ +ram_stats :: proc "contextless" () -> (total_ram, free_ram, total_swap, free_swap: i64, ok: bool) { + return _ram_stats() +} + +/* +Retrieves OS version information + +*Allocates Using Provided Allocator* + +You can use `destroy_os_version` to free the results + +Inputs: +- allocator: A `runtime.Allocator` on which the version strings will be allocated +- loc: The caller location + +Returns: +- res: An `OS_Version` struct +- ok: `true` when we could retrieve OS version information, `false` otherwise +*/ +os_version :: proc(allocator: runtime.Allocator, loc := #caller_location) -> (res: OS_Version, ok: bool) { + return _os_version(allocator = allocator, loc = loc) +} + +/* +Releases an `OS_Version`'s strings + +*Frees Using Provided Allocator* + +Inputs: +- version: An `OS_Version` struct +- allocator: A `runtime.Allocator` on which the version strings will be freed +*/ +destroy_os_version :: proc(version: OS_Version, allocator: runtime.Allocator) { + delete(version.full, allocator) + // `version.release` is part of `version.full` and does not need to be freed separately. +} + +OS_Version :: struct { + platform: OS_Version_Platform, // Windows, Linux, MacOS, iOS, etc. + full: string, // e.g. Windows 10 Professional (version: 22H2), build: 19045.6575 + release: string, // e.g. 22H2 + + os: Version, // e.g. {major = 10, minor = 10, patch = 0} + kernel: Version, // e.g. {major = 10, minor = 19045, patch = 6575} +} OS_Version_Platform :: enum { Unknown, @@ -26,25 +120,69 @@ Version :: struct { major, minor, patch: int, } -OS_Version :: struct { - platform: OS_Version_Platform, +/* +Iterates over GPU adapters - using _: Version, - build: [2]int, - version: string, +On Windows: Enumerates `Computer\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}` +Elsewhere: Unsupported at the moment, returns `{}, 0, false` - as_string: string, -} +Important: The `vendor` name, `model` name and `driver` version strings are backed by the `GPU_Iterator`. +Clone them if you want to these to persist. -RAM :: struct { - total_ram: int, - free_ram: int, - total_swap: int, - free_swap: int, +Inputs: +- it: A pointer to a `GPU_Iterator` +- minimum_vram: The number of bytes of VRAM an adapter has to have to be considered, default 256 MiB + (This excludes most screen mirroring / remote desktop drivers) + +Returns: + gpu: A `GPU` struct which contains `vendor` name, `model` name, `driver` version and `vram` in bytes + index: Loop index, optional + ok: `true` if this was a success and we should continue, `false` otherwise +*/ +iterate_gpus :: proc(it: ^GPU_Iterator, minimum_vram := i64(256 * 1024 * 1024)) -> (gpu: GPU, index: int, ok: bool) { + when ODIN_OS == .Windows { + return _iterate_gpus(it, minimum_vram) + } else { + // Not implemented on another OS, yet + return {}, 0, false + } } GPU :: struct { - vendor_name: string, - model_name: string, - total_ram: int, + vendor: string, + model: string, + driver: string, + vram: i64, } + +GPU_Iterator :: struct { + // Public iterator index + index: int, + + // Internal buffer + index + _buffer: [512]u8, + _index: int, +} + +@(private) +_parse_version :: proc (str: string) -> (res: Version) { + str := str + i: int + for part in strings.split_iterator(&str, ".") { + defer i += 1 + dst: ^int + switch i { + case 0: dst = &res.major + case 1: dst = &res.minor + case 2: dst = &res.patch + case: return + } + + if num, num_ok := strconv.parse_int(part); !num_ok { + return + } else { + dst^ = num + } + } + return +} \ No newline at end of file diff --git a/core/sys/kqueue/kqueue.odin b/core/sys/kqueue/kqueue.odin index 25ee9bdce..b51f3426f 100644 --- a/core/sys/kqueue/kqueue.odin +++ b/core/sys/kqueue/kqueue.odin @@ -32,6 +32,7 @@ kevent :: proc(kq: KQ, change_list: []KEvent, event_list: []KEvent, timeout: ^po timeout, ) if n_events == -1 { + n_events = 0 err = posix.errno() } return @@ -60,6 +61,7 @@ Filter :: enum _Filter_Backing { Proc = _FILTER_PROC, // Check for changes to the subject process. Signal = _FILTER_SIGNAL, // Check for signals delivered to the process. Timer = _FILTER_TIMER, // Timers. + User = _FILTER_USER, // User events. } RW_Flag :: enum u32 { @@ -82,18 +84,30 @@ Proc_Flag :: enum u32 { Exit = log2(0x80000000), // Process exited. Fork = log2(0x40000000), // Process forked. Exec = log2(0x20000000), // Process exec'd. - Signal = log2(0x08000000), // Shared with `Filter.Signal`. } Proc_Flags :: bit_set[Proc_Flag; u32] Timer_Flag :: enum u32 { Seconds = log2(0x00000001), // Data is seconds. - USeconds = log2(0x00000002), // Data is microseconds. - NSeconds = log2(_NOTE_NSECONDS), // Data is nanoseconds. + USeconds = log2(_NOTE_USECONDS), // Data is microseconds. Absolute = log2(_NOTE_ABSOLUTE), // Absolute timeout. } Timer_Flags :: bit_set[Timer_Flag; u32] +User_Flag :: enum u32 { + Trigger = log2(0x01000000), + FFAnd = log2(0x40000000), + FFOr = log2(0x80000000), +} +User_Flags :: bit_set[User_Flag; u32] + +USER_FLAGS_COPY :: User_Flags{.FFOr, .FFAnd} +USER_FLAGS_CONTROL_MASK :: transmute(User_Flags)u32(0xc0000000) +USER_FLAGS_MASK :: transmute(User_Flags)u32(0x00FFFFFF) + +// Data is nanoseconds. +TIMER_FLAGS_NSECONDS :: _TIMER_FLAGS_NSECONDS + when ODIN_OS == .Darwin { _Filter_Backing :: distinct i16 @@ -106,10 +120,14 @@ when ODIN_OS == .Darwin { _FILTER_PROC :: -5 _FILTER_SIGNAL :: -6 _FILTER_TIMER :: -7 + _FILTER_USER :: -10 + _NOTE_USECONDS :: 0x00000002 _NOTE_NSECONDS :: 0x00000004 _NOTE_ABSOLUTE :: 0x00000008 + _TIMER_FLAGS_NSECONDS :: Timer_Flags{Timer_Flag(log2(_NOTE_NSECONDS))} + KEvent :: struct #align(4) { // Value used to identify this event. The exact interpretation is determined by the attached filter. ident: uintptr, @@ -119,11 +137,12 @@ when ODIN_OS == .Darwin { flags: Flags, // Filter specific flags. fflags: struct #raw_union { - rw: RW_Flags, - vnode: VNode_Flags, - fproc: Proc_Flags, + rw: RW_Flags `raw_union_tag:"filter=.Read, filter=.Write"`, + vnode: VNode_Flags `raw_union_tag:"filter=.VNode"`, + fproc: Proc_Flags `raw_union_tag:"filter=.Proc"`, // vm: VM_Flags, - timer: Timer_Flags, + timer: Timer_Flags `raw_union_tag:"filter=.Timer"`, + user: User_Flags `raw_union_tag:"filter=.User"`, }, // Filter specific data. data: c.long /* intptr_t */, @@ -143,9 +162,13 @@ when ODIN_OS == .Darwin { _FILTER_PROC :: -5 _FILTER_SIGNAL :: -6 _FILTER_TIMER :: -7 + _FILTER_USER :: -11 - _NOTE_NSECONDS :: 0x00000004 - _NOTE_ABSOLUTE :: 0x00000008 + _NOTE_USECONDS :: 0x00000004 + _NOTE_NSECONDS :: 0x00000008 + _NOTE_ABSOLUTE :: 0x00000010 + + _TIMER_FLAGS_NSECONDS :: Timer_Flags{Timer_Flag(log2(_NOTE_NSECONDS))} KEvent :: struct { // Value used to identify this event. The exact interpretation is determined by the attached filter. @@ -156,11 +179,12 @@ when ODIN_OS == .Darwin { flags: Flags, // Filter specific flags. fflags: struct #raw_union { - rw: RW_Flags, - vnode: VNode_Flags, - fproc: Proc_Flags, + rw: RW_Flags `raw_union_tag:"filter=.Read, filter=.Write"`, + vnode: VNode_Flags `raw_union_tag:"filter=.VNode"`, + fproc: Proc_Flags `raw_union_tag:"filter=.Proc"`, // vm: VM_Flags, - timer: Timer_Flags, + timer: Timer_Flags `raw_union_tag:"filter=.Timer"`, + user: User_Flags `raw_union_tag:"filter=.User"`, }, // Filter specific data. data: i64, @@ -181,11 +205,14 @@ when ODIN_OS == .Darwin { _FILTER_PROC :: 4 _FILTER_SIGNAL :: 5 _FILTER_TIMER :: 6 + _FILTER_USER :: 8 - _NOTE_NSECONDS :: 0x00000003 + _NOTE_USECONDS :: 0x00000002 _NOTE_ABSOLUTE :: 0x00000010 - KEvent :: struct #align(4) { + _TIMER_FLAGS_NSECONDS :: Timer_Flags{.Seconds, .USeconds} + + KEvent :: struct { // Value used to identify this event. The exact interpretation is determined by the attached filter. ident: uintptr, // Filter for event. @@ -194,18 +221,17 @@ when ODIN_OS == .Darwin { flags: Flags, // Filter specific flags. fflags: struct #raw_union { - rw: RW_Flags, - vnode: VNode_Flags, - fproc: Proc_Flags, + rw: RW_Flags `raw_union_tag:"filter=.Read, filter=.Write"`, + vnode: VNode_Flags `raw_union_tag:"filter=.VNode"`, + fproc: Proc_Flags `raw_union_tag:"filter=.Proc"`, // vm: VM_Flags, - timer: Timer_Flags, + timer: Timer_Flags `raw_union_tag:"filter=.Timer"`, + user: User_Flags `raw_union_tag:"filter=.User"`, }, // Filter specific data. data: i64, // Opaque user data passed through the kernel unchanged. udata: rawptr, - // Extensions. - ext: [4]u64, } } else when ODIN_OS == .OpenBSD { @@ -219,10 +245,14 @@ when ODIN_OS == .Darwin { _FILTER_PROC :: -5 _FILTER_SIGNAL :: -6 _FILTER_TIMER :: -7 + _FILTER_USER :: -10 - _NOTE_NSECONDS :: 0x00000003 + _NOTE_USECONDS :: 0x00000002 + _NOTE_NSECONDS :: 0x00000004 _NOTE_ABSOLUTE :: 0x00000010 + _TIMER_FLAGS_NSECONDS :: Timer_Flags{Timer_Flag(log2(_NOTE_NSECONDS))} + KEvent :: struct #align(4) { // Value used to identify this event. The exact interpretation is determined by the attached filter. ident: uintptr, @@ -232,11 +262,12 @@ when ODIN_OS == .Darwin { flags: Flags, // Filter specific flags. fflags: struct #raw_union { - rw: RW_Flags, - vnode: VNode_Flags, - fproc: Proc_Flags, + rw: RW_Flags `raw_union_tag:"filter=.Read, filter=.Write"`, + vnode: VNode_Flags `raw_union_tag:"filter=.VNode"`, + fproc: Proc_Flags `raw_union_tag:"filter=.Proc"`, // vm: VM_Flags, - timer: Timer_Flags, + timer: Timer_Flags `raw_union_tag:"filter=.Timer"`, + user: User_Flags `raw_union_tag:"filter=.User"`, }, // Filter specific data. data: i64, @@ -245,12 +276,20 @@ when ODIN_OS == .Darwin { } } +when ODIN_OS == .NetBSD { + @(private) + LKEVENT :: "__kevent50" +} else { + @(private) + LKEVENT :: "kevent" +} + @(private) log2 :: intrinsics.constant_log2 foreign lib { @(link_name="kqueue") _kqueue :: proc() -> KQ --- - @(link_name="kevent") + @(link_name=LKEVENT) _kevent :: proc(kq: KQ, change_list: [^]KEvent, n_changes: c.int, event_list: [^]KEvent, n_events: c.int, timeout: ^posix.timespec) -> c.int --- } diff --git a/core/sys/linux/bits.odin b/core/sys/linux/bits.odin index 213d6c26f..9ce352bf6 100644 --- a/core/sys/linux/bits.odin +++ b/core/sys/linux/bits.odin @@ -449,7 +449,7 @@ FLock_Type :: enum i16 { /* Bits for FD_Notifications */ -FD_Notifications_Bits :: enum { +FD_Notifications_Bits :: enum i32 { ACCESS = 0, MODIFY = 1, CREATE = 2, @@ -1690,17 +1690,17 @@ IPC_Cmd :: enum i16 { /* File locking operation bits */ -FLock_Op_Bits :: enum { - SH = 1, - EX = 2, - NB = 4, - UN = 8, +FLock_Op_Bits :: enum i32 { + SH = 0, + EX = 1, + NB = 2, + UN = 3, } /* ptrace requests */ -PTrace_Request :: enum { +PTrace_Request :: enum i32 { TRACEME = 0, PEEKTEXT = 1, PEEKDATA = 2, @@ -1747,7 +1747,7 @@ PTrace_Request :: enum { /* ptrace options */ -PTrace_Options_Bits :: enum { +PTrace_Options_Bits :: enum i32 { TRACESYSGOOD = 0, TRACEFORK = 1, TRACEVFORK = 2, @@ -2269,3 +2269,40 @@ Swap_Flags_Bits :: enum { PREFER = log2(0x8000), DISCARD = log2(0x10000), } + +Eventfd_Flags_Bits :: enum { + SEMAPHORE, + CLOEXEC = auto_cast Open_Flags_Bits.CLOEXEC, + NONBLOCK = auto_cast Open_Flags_Bits.NONBLOCK, +} + +Sched_Policy :: enum u32 { + OTHER = 0, + BATCH = 3, + IDLE = 5, + FIFO = 1, + RR = 2, + DEADLINE = 6, +} + +Sched_Flag_Bits :: enum { + RESET_ON_FORK = log2(0x01), + RECLAIM = log2(0x02), + DL_OVERRUN = log2(0x04), + KEEP_POLICY = log2(0x08), + KEEP_PARAMS = log2(0x10), + UTIL_CLAMP_MIN = log2(0x20), + UTIL_CLAMP_MAX = log2(0x40), +} + +Sched_Attr_Flag_Bits :: enum {} + +/* + See `constants.odin` for `MFD_HUGE_16KB`, et al. +*/ +Memfd_Create_Flag_Bits :: enum { + CLOEXEC = log2(0x1), + ALLOW_SEALING = log2(0x2), + HUGETLB = log2(0x4), +} + diff --git a/core/sys/linux/constants.odin b/core/sys/linux/constants.odin index 71a16312e..4de57f40b 100644 --- a/core/sys/linux/constants.odin +++ b/core/sys/linux/constants.odin @@ -395,6 +395,20 @@ MAP_HUGE_1GB :: transmute(Map_Flags)(u32(30) << MAP_HUGE_SHIFT) MAP_HUGE_2GB :: transmute(Map_Flags)(u32(31) << MAP_HUGE_SHIFT) MAP_HUGE_16GB :: transmute(Map_Flags)(u32(34) << MAP_HUGE_SHIFT) +MFD_HUGE_16KB :: transmute(Memfd_Create_Flags)(u32(14) << MAP_HUGE_SHIFT) +MFD_HUGE_64KB :: transmute(Memfd_Create_Flags)(u32(16) << MAP_HUGE_SHIFT) +MFD_HUGE_512KB :: transmute(Memfd_Create_Flags)(u32(19) << MAP_HUGE_SHIFT) +MFD_HUGE_1MB :: transmute(Memfd_Create_Flags)(u32(20) << MAP_HUGE_SHIFT) +MFD_HUGE_2MB :: transmute(Memfd_Create_Flags)(u32(21) << MAP_HUGE_SHIFT) +MFD_HUGE_8MB :: transmute(Memfd_Create_Flags)(u32(23) << MAP_HUGE_SHIFT) +MFD_HUGE_16MB :: transmute(Memfd_Create_Flags)(u32(24) << MAP_HUGE_SHIFT) +MFD_HUGE_32MB :: transmute(Memfd_Create_Flags)(u32(25) << MAP_HUGE_SHIFT) +MFD_HUGE_256MB :: transmute(Memfd_Create_Flags)(u32(28) << MAP_HUGE_SHIFT) +MFD_HUGE_512MB :: transmute(Memfd_Create_Flags)(u32(29) << MAP_HUGE_SHIFT) +MFD_HUGE_1GB :: transmute(Memfd_Create_Flags)(u32(30) << MAP_HUGE_SHIFT) +MFD_HUGE_2GB :: transmute(Memfd_Create_Flags)(u32(31) << MAP_HUGE_SHIFT) +MFD_HUGE_16GB :: transmute(Memfd_Create_Flags)(u32(34) << MAP_HUGE_SHIFT) + /* Get window size */ TIOCGWINSZ :: 0x5413 diff --git a/core/sys/linux/sys.odin b/core/sys/linux/sys.odin index 04305ece1..6e9c8ab91 100644 --- a/core/sys/linux/sys.odin +++ b/core/sys/linux/sys.odin @@ -2043,22 +2043,71 @@ setpriority :: proc "contextless" (which: Priority_Which, who: i32, prio: i32) - return Errno(-ret) } -// TODO(flysand): sched_setparam - -// TODO(flysand): sched_getparam - -// TODO(flysand): sched_setscheduler - -// TODO(flysand): sched_getscheduler - -// TODO(flysand): sched_get_priority_max - -// TODO(flysand): sched_get_priority_min - -// TODO(flysand): sched_rr_get_interval +/* + Set scheduling parameters. + Available since Linux 2.0. +*/ +sched_setparam :: proc "contextless" (pid: Pid, param: ^Sched_Param) -> (Errno) { + ret := syscall(SYS_sched_setparam, pid, param) + return Errno(-ret) +} /* - Lock and memory. + Get scheduling parameters. + Available since Linux 2.0. +*/ +sched_getparam :: proc "contextless" (pid: Pid, param: ^Sched_Param) -> (Errno) { + ret := syscall(SYS_sched_getparam, pid, param) + return Errno(-ret) +} + +/* + Set scheduling policy/parameters. + Available since Linux 2.0. +*/ +sched_setscheduler :: proc "contextless" (pid: Pid, policy: i32, param: ^Sched_Param) -> (Errno) { + ret := syscall(SYS_sched_setscheduler, pid, policy, param) + return Errno(-ret) +} + +/* + Get scheduling policy/parameters. + Available since Linux 2.0. +*/ +sched_getscheduler :: proc "contextless" (pid: Pid, policy: i32, param: ^Sched_Param) -> (i32, Errno) { + ret := syscall(SYS_sched_getscheduler, pid) + return errno_unwrap(ret, i32) +} + +/* + Get static priority range. + Available since Linux 2.0. +*/ +sched_get_priority_max :: proc "contextless" (policy: i32) -> (i32, Errno) { + ret := syscall(SYS_sched_get_priority_max, policy) + return errno_unwrap(ret, i32) +} + +/* + Get static priority range. + Available since Linux 2.0. +*/ +sched_get_priority_min :: proc "contextless" (policy: i32) -> (i32, Errno) { + ret := syscall(SYS_sched_get_priority_min, policy) + return errno_unwrap(ret, i32) +} + +/* + get the SCHED_RR interval for the named process. + Available since Linux 2.0. +*/ +sched_rr_get_interval :: proc "contextless" (pid: Pid, tp: ^Time_Spec) -> (Errno) { + ret := syscall(SYS_sched_rr_get_interval, pid, tp) + return Errno(-ret) +} + +/* + Lock memory. Available since Linux 2.0. If flags specified, available since Linux 4.4. */ @@ -2560,9 +2609,29 @@ futex :: proc{ futex_wake_bitset, } -// TODO(flysand): sched_setaffinity +/* + Set a thread's CPU affinity mask. + Available since Linux 2.6. + + If you are running on a system with less than 128 cores you can use `linux.Cpu_Set` as the type for the mask argument. + Otherwise use an array of integers. +*/ +sched_setaffinity :: proc "contextless" (pid: Pid, cpusetsize: uint, mask: rawptr) -> (int, Errno) { + ret := syscall(SYS_sched_setaffinity, pid, cpusetsize, mask) + return errno_unwrap(ret, int) +} -// TODO(flysand): sched_getaffinity +/* + Get a thread's CPU affinity mask. + Available since Linux 2.6. + + If you are running on a system with less than 128 cores you can use `linux.Cpu_Set` as the type for the mask argument. + Otherwise use an array of integers. +*/ +sched_getaffinity :: proc "contextless" (pid: Pid, cpusetsize: uint, mask: rawptr) -> (int, Errno) { + ret := syscall(SYS_sched_getaffinity, pid, cpusetsize, mask) + return errno_unwrap(ret, int) +} // TODO(flysand): set_thread_area @@ -2992,15 +3061,39 @@ epoll_pwait :: proc(epfd: Fd, events: [^]EPoll_Event, count: i32, timeout: i32, // TODO(flysand): signalfd -// TODO(flysand): timerfd_create +/* + Create Linux file descriptor based timer. + Available since Linux 2.6.25 +*/ +timerfd_create :: proc "contextless" (clock_id: Clock_Id, flags: Open_Flags) -> (Fd, Errno) { + ret := syscall(SYS_timerfd_create, clock_id, transmute(u32)flags) + return errno_unwrap2(ret, Fd) +} -// TODO(flysand): eventfd +eventfd :: proc "contextless" (initval: u32, flags: Eventfd_Flags) -> (Fd, Errno) { + ret := syscall(SYS_eventfd2, initval, transmute(i32)flags) + return errno_unwrap2(ret, Fd) +} // TODO(flysand): fallocate -// TODO(flysand): timerfd_settime +/* + Arm/disarm the state of the Linux file descriptor based timer. + Available since Linux 2.6.25 +*/ +timerfd_settime :: proc "contextless" (fd: Fd, flags: ITimer_Flags, new_value: ^ITimer_Spec, old_value: ^ITimer_Spec) -> Errno { + ret := syscall(SYS_timerfd_settime, fd, transmute(u32)flags, new_value, old_value) + return Errno(-ret) +} -// TODO(flysand): timerfd_gettime +/* + Get the state of the Linux file descriptor based timer. + Available since Linux 2.6.25 +*/ +timerfd_gettime :: proc "contextless" (fd: Fd, curr_value: ^ITimer_Spec) -> Errno { + ret := syscall(SYS_timerfd_gettime, fd, curr_value) + return Errno(-ret) +} // TODO(flysand): accept4 @@ -3079,7 +3172,14 @@ sendmmsg :: proc "contextless" (sock: Fd, msg_vec: []MMsg_Hdr, flags: Socket_Msg // TODO(flysand): setns -// TODO(flysand): getcpu +/* + Determine CPU and NUMA node on which the calling thread is running. + Available since Linux 2.6.19. +*/ +getcpu :: proc "contextless" (cpu, node: ^u32) -> (Errno) { + ret := syscall(SYS_getcpu, cpu, node) + return Errno(-ret) +} // TODO(flysand): process_vm_readv @@ -3089,9 +3189,23 @@ sendmmsg :: proc "contextless" (sock: Fd, msg_vec: []MMsg_Hdr, flags: Socket_Msg // TODO(flysand): finit_module -// TODO(flysand): sched_setattr +/* + Set scheduling policy and attributes. + Available since Linux 3.14. +*/ +sched_setattr :: proc "contextless" (pid: Pid, attr: ^Sched_Attr, flags: Sched_Attr_Flags) -> (Errno) { + ret := syscall(SYS_sched_setattr, pid, attr, transmute(u32)flags) + return Errno(-ret) +} -// TODO(flysand): sched_getattr +/* + Get scheduling policy and attributes. + Available since Linux 3.14. +*/ +sched_getattr :: proc "contextless" (pid: Pid, attr: ^Sched_Attr, size: u32, flags: Sched_Attr_Flags) -> (Errno) { + ret := syscall(SYS_sched_getattr, pid, attr, transmute(u32)flags) + return Errno(-ret) +} /* Rename the file with names relative to the specified dirfd's with other options. @@ -3109,7 +3223,14 @@ getrandom :: proc "contextless" (buf: []u8, flags: Get_Random_Flags) -> (int, Er return errno_unwrap(ret, int) } -// TODO(flysand): memfd_create +/* + Create an anonymous file. + Available since Linux 3.17. +*/ +memfd_create :: proc "contextless" (name: cstring, flags: Memfd_Create_Flags) -> (Fd, Errno) { + ret := syscall(SYS_memfd_create, cast(rawptr)name, transmute(u32)flags) + return errno_unwrap(ret, Fd) +} // TODO(flysand): kexec_file_load diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin index 6a2f7cbca..c2334e5b6 100644 --- a/core/sys/linux/types.odin +++ b/core/sys/linux/types.odin @@ -932,7 +932,7 @@ RUsage :: struct { Struct used for IO operations */ IO_Vec :: struct { - base: rawptr, + base: [^]byte, len: uint, } @@ -1589,23 +1589,23 @@ IO_Uring_SQE :: struct { using __ioprio: struct #raw_union { ioprio: u16, sq_accept_flags: IO_Uring_Accept_Flags, - sq_send_recv_flags: IO_Uring_Send_Recv_Flags, + sq_send_recv_flags: IO_Uring_Send_Recv_Flags `raw_union_tag:"opcode=.SENDMSG, opcode=.RECVMSG, opcode=.SEND, opcode=.RECV"`, }, fd: Fd, using __offset: struct #raw_union { // Offset into file. - off: u64, - addr2: u64, + off: u64 `raw_union_tag:"opcode=.READV, opcode=.WRITEV, opcode=.SPLICE, opcode=.POLL_REMOVE, opcode=.EPOLL_CTL, opcode=.TIMEOUT, opcode=.ACCEPT, opcode=.CONNECT, opcode=.READ, opcode=.WRITE, opcode=.FILES_UPDATE, opcode=.SOCKET"`, + addr2: u64 `raw_union_tag:"opcode=.SEND, opcode=.BIND"`, using _: struct { cmd_op: u32, __pad1: u32, }, - statx: ^Statx, + statx: ^Statx `raw_union_tag:"opcode=.STATX"`, }, using __iovecs: struct #raw_union { // Pointer to buffer or iovecs. - addr: u64, - splice_off_in: u64, + addr: u64 `raw_union_tag:"opcode=.READV, opcode=.WRITEV, opcode=.POLL_REMOVE, opcode=.EPOLL_CTL, opcode=.SENDMSG, opcode=.RECVMSG, opcode=.SEND, opcode=.RECV, opcode=.TIMEOUT, opcode=.TIMEOUT_REMOVE, opcode=.ACCEPT, opcode=.ASYNC_CANCEL, opcode=.LINK_TIMEOUT, opcode=.CONNECT, opcode=.MADVISE, opcode=.OPENAT, opcode=.STATX, opcode=.READ, opcode=.WRITE, opcode=.FILES_UPDATE, opcode=.BIND, opcode=.LISTEN"`, + splice_off_in: u64 `raw_union_tag:"opcode=.SPLICE"`, using _: struct { level: u32, optname: u32, @@ -1613,28 +1613,28 @@ IO_Uring_SQE :: struct { }, using __len: struct #raw_union { // Buffer size or number of iovecs. - len: u32, - poll_flags: IO_Uring_Poll_Add_Flags, - statx_mask: Statx_Mask, - epoll_ctl_op: EPoll_Ctl_Opcode, - shutdown_how: Shutdown_How, + len: u32 `raw_union_tag:"opcode=.READV, opcode=.WRITEV, opcode=.SPLICE, opcode=.SEND, opcode=.RECV, opcode=.TIMEOUT, opcode=.LINK_TIMEOUT, opcode=.MADVISE, opcode=.OPENAT, opcode=.READ, opcode=.WRITE, opcode=.TEE, opcode=.FILES_UPDATE, opcode=.SOCKET"`, + poll_flags: IO_Uring_Poll_Add_Flags `raw_union_tag:"opcode=.POLL_ADD, opcode=.POLL_REMOVE"`, + statx_mask: Statx_Mask `raw_union_tag:"opcode=.STATX"`, + epoll_ctl_op: EPoll_Ctl_Opcode `raw_union_tag:"opcode=.EPOLL_CTL"`, + shutdown_how: Shutdown_How `raw_union_tag:"opcode=.SHUTDOWN"`, }, using __contents: struct #raw_union { - rw_flags: i32, - fsync_flags: IO_Uring_Fsync_Flags, + rw_flags: i32 `raw_union_tag:"opcode=.READV, opcode=.WRITEV, opcode=.SOCKET"`, + fsync_flags: IO_Uring_Fsync_Flags `raw_union_tag:"opcode=.FSYNC"`, // compatibility. - poll_events: Fd_Poll_Events, + poll_events: Fd_Poll_Events `raw_union_tag:"opcode=.POLL_ADD, opcode=.POLL_REMOVE"`, // word-reversed for BE. poll32_events: u32, sync_range_flags: u32, - msg_flags: Socket_Msg, - timeout_flags: IO_Uring_Timeout_Flags, - accept_flags: Socket_FD_Flags, + msg_flags: Socket_Msg `raw_union_tag:"opcode=.SENDMSG, opcode=.RECVMSG, opcode=.SEND, opcode=.RECV"`, + timeout_flags: IO_Uring_Timeout_Flags `raw_union_tag:"opcode=.TIMEOUT, opcode=.TIMEOUT_REMOVE, opcode=.LINK_TIMEOUT"`, + accept_flags: Socket_FD_Flags `raw_union_tag:"opcode=.ACCEPT"`, cancel_flags: u32, - open_flags: Open_Flags, - statx_flags: FD_Flags, - fadvise_advice: u32, - splice_flags: IO_Uring_Splice_Flags, + open_flags: Open_Flags `raw_union_tag:"opcode=.OPENAT"`, + statx_flags: FD_Flags `raw_union_tag:"opcode=.STATX"`, + fadvise_advice: u32 `raw_union_tag:"opcode=.MADVISE"`, + splice_flags: IO_Uring_Splice_Flags `raw_union_tag:"opcode=.SPLICE, opcode=.TEE"`, rename_flags: u32, unlink_flags: u32, hardlink_flags: u32, @@ -1653,10 +1653,10 @@ IO_Uring_SQE :: struct { // Personality to use, if used. personality: u16, using _: struct #raw_union { - splice_fd_in: Fd, - file_index: u32, + splice_fd_in: Fd `raw_union_tag:"opcode=.SPLICE, opcode=.TEE"`, + file_index: u32 `raw_union_tag:"opcode=.ACCEPT, opcode=.OPENAT, opcode=.CLOSE, opcode=.SOCKET"`, using _: struct { - addr_len: u16, + addr_len: u16 `raw_union_tag:"opcode=.SEND"`, __pad3: [1]u16, }, }, @@ -1748,3 +1748,35 @@ Mount_Flags :: bit_set[Mount_Flags_Bits; uint] Umount2_Flags :: bit_set[Umount2_Flags_Bits; u32] Swap_Flags :: bit_set[Swap_Flags_Bits; u32] + +Eventfd_Flags :: bit_set[Eventfd_Flags_Bits; i32] + +Cpu_Set :: bit_set[0 ..< 128] + +Sched_Param :: struct { + sched_priority: i32, +} + +Sched_Flags :: bit_set[Sched_Flag_Bits; u32] + +Sched_Attr :: struct { + size: u32, + + sched_policy: Sched_Policy, + sched_flags: Sched_Flags, + sched_nice: i32, + sched_priority: u32, + + /* For the DEADLINE policy */ + sched_runtime: u64, + sched_deadline: u64, + sched_period: u64, + + /* Utilization hints */ + sched_util_min: u32, + sched_util_max: u32, +} + +Sched_Attr_Flags :: bit_set[Sched_Attr_Flag_Bits; u32] + +Memfd_Create_Flags :: bit_set[Memfd_Create_Flag_Bits; u32] diff --git a/core/sys/linux/uring/doc.odin b/core/sys/linux/uring/doc.odin new file mode 100644 index 000000000..8b9ae5ee8 --- /dev/null +++ b/core/sys/linux/uring/doc.odin @@ -0,0 +1,88 @@ +/* +Wrapper/convenience package over the raw io_uring syscalls, providing help with setup, creation, and operating the ring. + +The following example shows a simple `cat` program implementation using the package. + +Example: + package main + + import "base:runtime" + + import "core:fmt" + import "core:os" + import "core:sys/linux" + import "core:sys/linux/uring" + + Request :: struct { + path: cstring, + buffer: []byte, + completion: linux.IO_Uring_CQE, + } + + main :: proc() { + if len(os.args) < 2 { + fmt.eprintfln("Usage: %s [file name] <[file name] ...>", os.args[0]) + os.exit(1) + } + + requests := make_soa(#soa []Request, len(os.args)-1) + defer delete(requests) + + ring: uring.Ring + params := uring.DEFAULT_PARAMS + err := uring.init(&ring, ¶ms) + fmt.assertf(err == nil, "uring.init: %v", err) + defer uring.destroy(&ring) + + for &request, i in requests { + request.path = runtime.args__[i+1] + // sets up a read requests and adds it to the ring buffer. + submit_read_request(request.path, &request.buffer, &ring) + } + + ulen := u32(len(requests)) + + // submit the requests and wait for them to complete right away. + n, serr := uring.submit(&ring, ulen) + fmt.assertf(serr == nil, "uring.submit: %v", serr) + assert(n == ulen) + + // copy the completed requests out of the ring buffer. + cn := uring.copy_cqes_ready(&ring, requests.completion[:ulen]) + assert(cn == ulen) + + for request in requests { + // check result of the requests. + fmt.assertf(request.completion.res >= 0, "read %q failed: %v", request.path, linux.Errno(-request.completion.res)) + // print out. + fmt.print(string(request.buffer)) + + delete(request.buffer) + } + } + + submit_read_request :: proc(path: cstring, buffer: ^[]byte, ring: ^uring.Ring) { + fd, err := linux.open(path, {}) + fmt.assertf(err == nil, "open(%q): %v", path, err) + + file_sz := get_file_size(fd) + + buffer^ = make([]byte, file_sz) + + _, ok := uring.read(ring, 0, fd, buffer^, 0) + assert(ok, "could not get read sqe") + } + + get_file_size :: proc(fd: linux.Fd) -> uint { + st: linux.Stat + err := linux.fstat(fd, &st) + fmt.assertf(err == nil, "fstat: %v", err) + + if linux.S_ISREG(st.mode) { + return uint(st.size) + } + + panic("not a regular file") + } +*/ +package uring diff --git a/core/sys/linux/uring/ops.odin b/core/sys/linux/uring/ops.odin new file mode 100644 index 000000000..7b3392e98 --- /dev/null +++ b/core/sys/linux/uring/ops.odin @@ -0,0 +1,847 @@ +package uring + +import "core:sys/linux" + +// Do not perform any I/O. This is useful for testing the performance of the uring implementation itself. +nop :: proc(ring: ^Ring, user_data: u64) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .NOP + sqe.user_data = user_data + + ok = true + return +} + +// Vectored read operation, see also readv(2). +readv :: proc(ring: ^Ring, user_data: u64, fd: linux.Fd, iovs: []linux.IO_Vec, off: u64) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .READV + sqe.fd = fd + sqe.addr = cast(u64)uintptr(raw_data(iovs)) + sqe.len = u32(len(iovs)) + sqe.off = off + sqe.user_data = user_data + + ok = true + return +} + +// Vectored write operation, see also writev(2). +writev :: proc(ring: ^Ring, user_data: u64, fd: linux.Fd, iovs: []linux.IO_Vec, off: u64) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .WRITEV + sqe.fd = fd + sqe.addr = cast(u64)uintptr(raw_data(iovs)) + sqe.len = u32(len(iovs)) + sqe.off = off + sqe.user_data = user_data + + ok = true + return +} + +read_fixed :: proc() { + unimplemented() +} + +write_fixed :: proc() { + unimplemented() +} + +/* +File sync. See also fsync(2). + +Optionally off and len can be used to specify a range within the file to be synced rather than syncing the entire file, which is the default behavior. + +Note that, while I/O is initiated in the order in which it appears in the submission queue, completions are unordered. +For example, an application which places a write I/O followed by an fsync in the submission queue cannot expect the fsync to apply to the write. +The two operations execute in parallel, so the fsync may complete before the write is issued to the storage. +The same is also true for previously issued writes that have not completed prior to the fsync. +To enforce ordering one may utilize linked SQEs, +IOSQE_IO_DRAIN or wait for the arrival of CQEs of requests which have to be ordered before a given request before submitting its SQE. +*/ +fsync :: proc(ring: ^Ring, user_data: u64, fd: linux.Fd, flags: linux.IO_Uring_Fsync_Flags) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .FSYNC + sqe.fsync_flags = flags + sqe.fd = fd + sqe.user_data = user_data + + ok = true + return +} + +/* +Poll the fd specified in the submission queue entry for the events specified in the poll_events field. + +Unlike poll or epoll without EPOLLONESHOT, by default this interface always works in one shot mode. +That is, once the poll operation is completed, it will have to be resubmitted. + +If IORING_POLL_ADD_MULTI is set in the SQE len field, then the poll will work in multi shot mode instead. +That means it'll repatedly trigger when the requested event becomes true, and hence multiple CQEs can be generated from this single SQE. +The CQE flags field will have IORING_CQE_F_MORE set on completion if the application should expect further CQE entries from the original request. +If this flag isn't set on completion, then the poll request has been terminated and no further events will be generated. +This mode is available since 5.13. + +This command works like an async poll(2) and the completion event result is the returned mask of events. + +Without IORING_POLL_ADD_MULTI and the initial poll operation with IORING_POLL_ADD_MULTI the operation is level triggered, +i.e. if there is data ready or events pending etc. +at the time of submission a corresponding CQE will be posted. +Potential further completions beyond the first caused by a IORING_POLL_ADD_MULTI are edge triggered. +*/ +poll_add :: proc(ring: ^Ring, user_data: u64, fd: linux.Fd, events: linux.Fd_Poll_Events, flags: linux.IO_Uring_Poll_Add_Flags) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .POLL_ADD + sqe.fd = fd + sqe.poll_events = events + sqe.poll_flags = flags + sqe.user_data = user_data + + ok = true + return +} + +/* +Remove an existing poll request. + +If found, the res field of the struct io_uring_cqe will contain 0. +If not found, res will contain -ENOENT, or -EALREADY if the poll request was in the process of completing already. +*/ +poll_remove :: proc(ring: ^Ring, user_data: u64, fd: linux.Fd, events: linux.Fd_Poll_Events) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .POLL_REMOVE + sqe.fd = fd + sqe.poll_events = events + sqe.user_data = user_data + + ok = true + return +} + +/* +Update the events of an existing poll request. + +The request will update an existing poll request with the mask of events passed in with this request. +The lookup is based on the user_data field of the original SQE submitted. + +Updating an existing poll is available since 5.13. +*/ +poll_update_events :: proc(ring: ^Ring, user_data: u64, orig_user_data: u64, fd: linux.Fd, events: linux.Fd_Poll_Events) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .POLL_REMOVE + sqe.fd = fd + sqe.addr = orig_user_data + sqe.poll_events = events + sqe.user_data = user_data + sqe.poll_flags = {.UPDATE_EVENTS} + + ok = true + return +} + +/* +Update the user data of an existing poll request. + +The request will update the user_data of an existing poll request based on the value passed. + +Updating an existing poll is available since 5.13. +*/ +poll_update_user_data :: proc(ring: ^Ring, user_data: u64, orig_user_data: u64, new_user_data: u64, fd: linux.Fd) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .POLL_REMOVE + sqe.fd = fd + sqe.off = orig_user_data + sqe.addr = new_user_data + sqe.user_data = user_data + sqe.poll_flags = {.UPDATE_USER_DATA} + + ok = true + return +} + +/* +Add, remove or modify entries in the interest list of epoll(7). + +See epoll_ctl(2) for details of the system call. + +Available since 5.6. +*/ +epoll_ctl :: proc(ring: ^Ring, user_data: u64, epfd: linux.Fd, op: linux.EPoll_Ctl_Opcode, fd: linux.Fd, event: ^linux.EPoll_Event) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .EPOLL_CTL + sqe.fd = epfd + sqe.off = u64(fd) + sqe.epoll_ctl_op = op + sqe.addr = cast(u64)uintptr(event) + sqe.user_data = user_data + + ok = true + return +} + +sync_file_range :: proc() { + unimplemented() +} + +/* +Issue the equivalent of a sendmsg(2) system call. + +See also sendmsg(2) for the general description of the related system call. + +poll_first: if set, uring will assume the socket is currently full and attempting to send data will be unsuccessful. +For this case, uring will arm internal poll and trigger a send of the data when there is enough space available. +This initial send attempt can be wasteful for the case where the socket is expected to be full, setting this flag will +bypass the initial send attempt and go straight to arming poll. +If poll does indicate that data can be sent, the operation will proceed. + +Available since 5.3. +*/ +sendmsg :: proc(ring: ^Ring, user_data: u64, fd: linux.Fd, msghdr: ^linux.Msg_Hdr, flags: linux.Socket_Msg, poll_first := false) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .SENDMSG + sqe.fd = fd + sqe.addr = cast(u64)uintptr(msghdr) + sqe.msg_flags = flags + sqe.user_data = user_data + sqe.sq_send_recv_flags = {.RECVSEND_POLL_FIRST} if poll_first else {} + + ok = true + return +} + +/* +Works just like sendmsg, but receives instead of sends. + +poll_first: If set, uring will assume the socket is currently empty and attempting to receive data will be unsuccessful. +For this case, uring will arm internal poll and trigger a receive of the data when the socket has data to be read. +This initial receive attempt can be wasteful for the case where the socket is expected to be empty, setting this flag will bypass the initial receive attempt and go straight to arming poll. +If poll does indicate that data is ready to be received, the operation will proceed. + +Available since 5.3. +*/ +recvmsg :: proc(ring: ^Ring, user_data: u64, fd: linux.Fd, msghdr: ^linux.Msg_Hdr, flags: linux.Socket_Msg, poll_first := false) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .RECVMSG + sqe.fd = fd + sqe.addr = cast(u64)uintptr(msghdr) + sqe.msg_flags = flags + sqe.user_data = user_data + sqe.sq_send_recv_flags = {.RECVSEND_POLL_FIRST} if poll_first else {} + + ok = true + return +} + +/* +Issue the equivalent of a send(2) system call. + +See also send(2) for the general description of the related system call. + +poll_first: If set, uring will assume the socket is currently full and attempting to send data will be unsuccessful. +For this case, uring will arm internal poll and trigger a send of the data when there is enough space available. +This initial send attempt can be wasteful for the case where the socket is expected to be full, setting this flag will bypass the initial send attempt and go straight to arming poll. +If poll does indicate that data can be sent, the operation will proceed. + +Available since 5.6. +*/ +send :: proc(ring: ^Ring, user_data: u64, sockfd: linux.Fd, buf: []byte, flags: linux.Socket_Msg, poll_first := false) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .SEND + sqe.fd = sockfd + sqe.addr = cast(u64)uintptr(raw_data(buf)) + sqe.len = u32(len(buf)) + sqe.msg_flags = flags + sqe.user_data = user_data + sqe.sq_send_recv_flags = {.RECVSEND_POLL_FIRST} if poll_first else {} + + ok = true + return +} + +sendto :: proc(ring: ^Ring, user_data: u64, sockfd: linux.Fd, buf: []byte, flags: linux.Socket_Msg, dest: ^$T, poll_first := false) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) + where T == linux.Sock_Addr_In || T == linux.Sock_Addr_In6 || T == linux.Sock_Addr_Un || T == linux.Sock_Addr_Any { + + sqe = send(ring, user_data, sockfd, buf, flags, poll_first) or_return + sqe.addr2 = u64(uintptr(dest)) + sqe.addr_len = u16(size_of(T)) + + ok = true + return +} + +/* +Works just like send, but receives instead of sends. + +poll_first: If set, uring will assume the socket is currently empty and attempting to receive data will be unsuccessful. +For this case, uring will arm internal poll and trigger a receive of the data when the socket has data to be read. +This initial receive attempt can be wasteful for the case where the socket is expected to be empty, setting this flag will bypass the initial receive attempt and go straight to arming poll. +If poll does indicate that data is ready to be received, the operation will proceed. + +Available since 5.6. +*/ +recv :: proc(ring: ^Ring, user_data: u64, sockfd: linux.Fd, buf: []byte, flags: linux.Socket_Msg, poll_first := false) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .RECV + sqe.fd = sockfd + sqe.addr = cast(u64)uintptr(raw_data(buf)) + sqe.len = cast(u32)uintptr(len(buf)) + sqe.msg_flags = flags + sqe.user_data = user_data + sqe.sq_send_recv_flags = {.RECVSEND_POLL_FIRST} if poll_first else {} + + ok = true + return +} + +/* +Register a timeout operation. + +The timeout will complete when either the timeout expires, or after the specified number of +events complete (if `count` is greater than `0`). + +`flags` may be `0` for a relative timeout, or `IORING_TIMEOUT_ABS` for an absolute timeout. + +The completion event result will be `-ETIME` if the timeout completed through expiration, +`0` if the timeout completed after the specified number of events, or `-ECANCELED` if the +timeout was removed before it expired. + +uring timeouts use the `CLOCK.MONOTONIC` clock source. +*/ +timeout :: proc(ring: ^Ring, user_data: u64, ts: ^linux.Time_Spec, count: u32, flags: linux.IO_Uring_Timeout_Flags) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .TIMEOUT + sqe.fd = -1 + sqe.addr = cast(u64)uintptr(ts) + sqe.len = 1 + sqe.off = u64(count) + sqe.timeout_flags = flags + sqe.user_data = user_data + + ok = true + return +} + +/* +Rmove an existing timeout operation. + +The timeout is identified by it's `user_data`. + +The completion event result will be `0` if the timeout was found and cancelled successfully, +`-EBUSY` if the timeout was found but expiration was already in progress, or +`-ENOENT` if the timeout was not found. +*/ +timeout_remove :: proc(ring: ^Ring, user_data: u64, timeout_user_data: u64, flags: linux.IO_Uring_Timeout_Flags) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .TIMEOUT_REMOVE + sqe.fd = -1 + sqe.addr = timeout_user_data + sqe.timeout_flags = flags + sqe.user_data = user_data + + ok = true + return +} + +/* +Issue the equivalent of an accept4(2) system call. + +See also accept4(2) for the general description of the related system call. + +If the file_index field is set to a positive number, the file won't be installed into the normal file table as usual +but will be placed into the fixed file table at index file_index - 1. +In this case, instead of returning a file descriptor, the result will contain either 0 on success or an error. +If the index points to a valid empty slot, the installation is guaranteed to not fail. +If there is already a file in the slot, it will be replaced, similar to IORING_OP_FILES_UPDATE. +Please note that only uring has access to such files and no other syscall can use them. See IOSQE_FIXED_FILE and IORING_REGISTER_FILES. + +Available since 5.5. +*/ +accept :: proc(ring: ^Ring, user_data: u64, sockfd: linux.Fd, addr: ^$T, addr_len: ^i32, flags: linux.Socket_FD_Flags, file_index: u32 = 0) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) +where T == linux.Sock_Addr_In || T == linux.Sock_Addr_In6 || T == linux.Sock_Addr_Un || T == linux.Sock_Addr_Any { + + sqe = get_sqe(ring) or_return + sqe.opcode = .ACCEPT + sqe.fd = sockfd + sqe.addr = cast(u64)uintptr(addr) + sqe.off = cast(u64)uintptr(addr_len) + sqe.accept_flags = flags + sqe.user_data = user_data + sqe.file_index = file_index + + ok = true + return +} + +/* +Attempt to cancel an already issued request. + +The request is identified by it's user data. + +The cancelation request will complete with one of the following results codes. + +If found, the res field of the cqe will contain 0. +If not found, res will contain -ENOENT. + +If found and attempted canceled, the res field will contain -EALREADY. +In this case, the request may or may not terminate. +In general, requests that are interruptible (like socket IO) will get canceled, while disk IO requests cannot be canceled if already started. + +Available since 5.5. +*/ +async_cancel :: proc(ring: ^Ring, orig_user_data: u64, user_data: u64) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .ASYNC_CANCEL + sqe.addr = orig_user_data + sqe.user_data = user_data + + ok = true + return +} + +/* +Adds a link timeout operation. + +You need to set linux.IOSQE_IO_LINK to flags of the target operation +and then call this method right after the target operation. +See https://lwn.net/Articles/803932/ for detail. + +If the dependent request finishes before the linked timeout, the timeout +is canceled. If the timeout finishes before the dependent request, the +dependent request will be canceled. + +The completion event result of the link_timeout will be +`-ETIME` if the timeout finishes before the dependent request +(in this case, the completion event result of the dependent request will +be `-ECANCELED`), or +`-EALREADY` if the dependent request finishes before the linked timeout. + +Available since 5.5. +*/ +link_timeout :: proc(ring: ^Ring, user_data: u64, ts: ^linux.Time_Spec, flags: linux.IO_Uring_Timeout_Flags) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring, 0) or_return + sqe.opcode = .LINK_TIMEOUT + sqe.fd = -1 + sqe.addr = cast(u64)uintptr(ts) + sqe.len = 1 + sqe.timeout_flags = flags + sqe.user_data = user_data + + ok = true + return +} + +/* +Issue the equivalent of a connect(2) system call. + +See also connect(2) for the general description of the related system call. + +Available since 5.5. +*/ +connect :: proc(ring: ^Ring, user_data: u64, sockfd: linux.Fd, addr: ^$T) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) +where T == linux.Sock_Addr_In || T == linux.Sock_Addr_In6 || T == linux.Sock_Addr_Un || T == linux.Sock_Addr_Any { + + sqe = get_sqe(ring) or_return + sqe.opcode = .CONNECT + sqe.fd = sockfd + sqe.addr = cast(u64)uintptr(addr) + sqe.off = size_of(T) + sqe.user_data = user_data + + ok = true + return +} + +fallocate :: proc() { + unimplemented() +} + +fadvise :: proc() { + unimplemented() +} + +/* +Issue the equivalent of a madvise(2) system call. + +See also madvise(2) for the general description of the related system call. + +Available since 5.6. +*/ +madvise :: proc(ring: ^Ring, user_data: u64, addr: rawptr, size: u32, advise: linux.MAdvice) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .MADVISE + sqe.addr = u64(uintptr(addr)) + sqe.len = size + sqe.fadvise_advice = cast(u32)transmute(int)advise + sqe.user_data = user_data + + ok = true + return +} + +/* +Issue the equivalent of a openat(2) system call. + +See also openat(2) for the general description of the related system call. + +Available since 5.6. + +If the file_index is set to a positive number, +the file won't be installed into the normal file table as usual but will be placed into the fixed file table at index file_index - 1. +In this case, instead of returning a file descriptor, the result will contain either 0 on success or an error. +If the index points to a valid empty slot, the installation is guaranteed to not fail. +If there is already a file in the slot, it will be replaced, similar to IORING_OP_FILES_UPDATE. +Please note that only uring has access to such files and no other syscall can use them. +See IOSQE_FIXED_FILE and IORING_REGISTER_FILES. + +Available since 5.15. +*/ +openat :: proc(ring: ^Ring, user_data: u64, dirfd: linux.Fd, path: cstring, mode: linux.Mode, flags: linux.Open_Flags, file_index: u32 = 0) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .OPENAT + sqe.fd = dirfd + sqe.addr = cast(u64)transmute(uintptr)path + sqe.len = transmute(u32)mode + sqe.open_flags = flags + sqe.user_data = user_data + sqe.file_index = file_index + + ok = true + return +} + +openat2 :: proc() { + unimplemented() +} + +/* +Issue the equivalent of a close(2) system call. + +See also close(2) for the general description of the related system call. + +Available since 5.6. + +If the file_index field is set to a positive number, this command can be used to close files that were +direct opened through IORING_OP_OPENAT, IORING_OP_OPENAT2, or IORING_OP_ACCEPT using the uring specific direct descriptors. +Note that only one of the descriptor fields may be set. +The direct close feature is available since the 5.15 kernel, where direct descriptors were introduced. +*/ +close :: proc(ring: ^Ring, user_data: u64, fd: linux.Fd, file_index: u32 = 0) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .CLOSE + sqe.fd = fd + sqe.user_data = user_data + sqe.file_index = file_index + + ok = true + return +} + +/* +Issue the equivalent of a statx(2) system call. + +See also statx(2) for the general description of the related system call. + +Available since 5.6. +*/ +statx :: proc(ring: ^Ring, user_data: u64, dirfd: linux.Fd, pathname: cstring, flags: linux.FD_Flags, mask: linux.Statx_Mask, buf: ^linux.Statx) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .STATX + sqe.fd = dirfd + sqe.addr = cast(u64)transmute(uintptr)pathname + sqe.statx_flags = flags + sqe.statx_mask = mask + sqe.statx = buf + sqe.user_data = user_data + + ok = true + return +} + +/* +Issue the equivalent of a pread(2) system call. + +If offset is set to -1 , the offset will use (and advance) the file position, like the read(2) system calls. +These are non-vectored versions of the IORING_OP_READV and IORING_OP_WRITEV opcodes. +See also read(2) for the general description of the related system call. + +Available since 5.6. +*/ +read :: proc(ring: ^Ring, user_data: u64, fd: linux.Fd, buf: []u8, offset: u64) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .READ + sqe.fd = fd + sqe.addr = cast(u64)uintptr(raw_data(buf)) + sqe.len = u32(len(buf)) + sqe.off = offset + sqe.user_data = user_data + + ok = true + return +} + +/* +Issue the equivalent of a pwrite(2) system call. + +If offset is set to -1 , the offset will use (and advance) the file position, like the read(2) system calls. +These are non-vectored versions of the IORING_OP_READV and IORING_OP_WRITEV opcodes. +See also write(2) for the general description of the related system call. + +Available since 5.6. +*/ +write :: proc(ring: ^Ring, user_data: u64, fd: linux.Fd, buf: []u8, offset: u64) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .WRITE + sqe.fd = fd + sqe.addr = cast(u64)uintptr(raw_data(buf)) + sqe.len = u32(len(buf)) + sqe.off = offset + sqe.user_data = user_data + + ok = true + return +} + +/* +Issue the equivalent of a splice(2) system call. + +A sentinel value of -1 is used to pass the equivalent of a NULL for the offsets to splice(2). + +Please note that one of the file descriptors must refer to a pipe. +See also splice(2) for the general description of the related system call. + +Available since 5.7. + +*/ +splice :: proc(ring: ^Ring, user_data: u64, fd_in: linux.Fd, off_in: i64, fd_out: linux.Fd, off_out: i64, len: u32, flags: linux.IO_Uring_Splice_Flags) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .SPLICE + sqe.splice_fd_in = fd_in + sqe.splice_off_in = cast(u64)off_in + sqe.fd = fd_out + sqe.off = cast(u64)off_out + sqe.len = len + sqe.splice_flags = flags + sqe.user_data = user_data + + ok = true + return +} + +/* +Issue the equivalent of a tee(2) system call. + +Please note that both of the file descriptors must refer to a pipe. +See also tee(2) for the general description of the related system call. + +Available since 5.8. +*/ +tee :: proc(ring: ^Ring, user_data: u64, fd_in: linux.Fd, fd_out: linux.Fd, len: u32, flags: linux.IO_Uring_Splice_Flags) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .TEE + sqe.splice_fd_in = fd_in + sqe.fd = fd_out + sqe.len = len + sqe.splice_flags = flags + sqe.user_data = user_data + + ok = true + return +} + +/* +This command is an alternative to using IORING_REGISTER_FILES_UPDATE which then works in an async fashion, like the rest of the uring commands. + +Note that the array of file descriptors pointed to in addr must remain valid until this operation has completed. + +Available since 5.6. +*/ +files_update :: proc(ring: ^Ring, user_data: u64, fds: []linux.Fd, off: u64) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .FILES_UPDATE + sqe.addr = cast(u64)uintptr(raw_data(fds)) + sqe.len = cast(u32)len(fds) + sqe.off = off + sqe.user_data = user_data + + ok = true + return +} + +provide_buffers :: proc() { + unimplemented() +} + +remove_buffers :: proc() { + unimplemented() +} + +/* +Issue the equivalent of a shutdown(2) system call. + +Available since 5.11. +*/ +shutdown :: proc(ring: ^Ring, user_data: u64, fd: linux.Fd, how: linux.Shutdown_How) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .SHUTDOWN + sqe.fd = fd + sqe.shutdown_how = how + sqe.user_data = user_data + + ok = true + return +} + +renameat :: proc() { + unimplemented() +} + +unlinkat :: proc() { + unimplemented() +} + +mkdirat :: proc() { + unimplemented() +} + +symlinkat :: proc() { + unimplemented() +} + +linkat :: proc() { + unimplemented() +} + +msg_ring :: proc() { + unimplemented() +} + +/* +Issue the equivalent of a socket(2) system call. + +See also socket(2) for the general description of the related system call. + +Available since 5.19. + +If the file_index field is set to a positive number, the file won't be installed into the normal file +table as usual but will be placed into the fixed file table at index file_index - 1. +In this case, instead of returning a file descriptor, the result will contain either 0 on success or an error. +If the index points to a valid empty slot, the installation is guaranteed to not fail. +If there is already a file in the slot, it will be replaced, similar to IORING_OP_FILES_UPDATE. +Please note that only uring has access to such files and no other syscall can use them. +See IOSQE_FIXED_FILE and IORING_REGISTER_FILES. +*/ +socket :: proc(ring: ^Ring, user_data: u64, domain: linux.Address_Family, socktype: linux.Socket_Type, protocol: linux.Protocol, file_index: u32 = 0) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .SOCKET + sqe.user_data = user_data + sqe.fd = cast(linux.Fd)domain + sqe.off = cast(u64)socktype + sqe.len = cast(u32)protocol + sqe.rw_flags = {} + sqe.file_index = file_index + + ok = true + return +} + +uring_cmd :: proc() { + unimplemented() +} + +send_zc :: proc() { + unimplemented() +} + +sendmsg_zc :: proc() { + unimplemented() +} + +waitid :: proc() { + unimplemented() +} + +setxattr :: proc() { + unimplemented() +} + +getxattr :: proc() { + unimplemented() +} + +fsetxattr :: proc() { + unimplemented() +} + +fgetxattr :: proc() { + unimplemented() +} + +/* +Issues the equivalent of the bind(2) system call. + +Available since 6.11. +*/ +bind :: proc(ring: ^Ring, user_data: u64, sock: linux.Fd, addr: ^$T) -> (sqe: linux.IO_Uring_SQE, ok: bool) + where + T == linux.Sock_Addr_In || + T == linux.Sock_Addr_In6 || + T == linux.Sock_Addr_Un || + T == linux.Sock_Addr_Any +{ + sqe = get_sqe(ring) or_return + sqe.opcode = .BIND + sqe.user_data = user_data + sqe.fd = sock + sqe.addr = cast(u64)uintptr(addr) + sqe.addr2 = size_of(T) + + ok = true + return +} + +/* +Issues the equivalent of the listen(2) system call. + +fd must contain the file descriptor of the socket and addr must contain the backlog parameter, i.e. the maximum amount of pending queued connections. + +Available since 6.11. +*/ +listen :: proc(ring: ^Ring, user_data: u64, fd: linux.Fd, backlog: u64) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sqe = get_sqe(ring) or_return + sqe.opcode = .LISTEN + sqe.user_data = user_data + sqe.fd = fd + sqe.addr = backlog + + ok = true + return +} + +ftruncate :: proc() { + unimplemented() +} + +read_multishot :: proc() { + unimplemented() +} + +futex_wait :: proc() { + unimplemented() +} + +futex_wake :: proc() { + unimplemented() +} + +futex_waitv :: proc() { + unimplemented() +} + +fixed_fd_install :: proc() { + unimplemented() +} + +fixed_file :: proc() { + unimplemented() +} diff --git a/core/sys/linux/uring/uring.odin b/core/sys/linux/uring/uring.odin new file mode 100644 index 000000000..8e4315e6a --- /dev/null +++ b/core/sys/linux/uring/uring.odin @@ -0,0 +1,294 @@ +package uring + +import "core:math" +import "core:sync" +import "core:sys/linux" + +DEFAULT_THREAD_IDLE_MS :: 1000 +DEFAULT_ENTRIES :: 32 +MAX_ENTRIES :: 4096 + +Ring :: struct { + fd: linux.Fd, + sq: Submission_Queue, + cq: Completion_Queue, + flags: linux.IO_Uring_Setup_Flags, + features: linux.IO_Uring_Features, +} + +DEFAULT_PARAMS :: linux.IO_Uring_Params { + sq_thread_idle = DEFAULT_THREAD_IDLE_MS, +} + +// Initialize and setup an uring, `entries` must be a power of 2 between 1 and 4096. +init :: proc(ring: ^Ring, params: ^linux.IO_Uring_Params, entries: u32 = DEFAULT_ENTRIES) -> (err: linux.Errno) { + assert(entries <= MAX_ENTRIES, "too many entries") + assert(entries != 0, "entries must be positive") + assert(math.is_power_of_two(int(entries)), "entries must be a power of two") + + fd := linux.io_uring_setup(entries, params) or_return + defer if err != nil { linux.close(fd) } + + if .SINGLE_MMAP not_in params.features { + // NOTE: Could support this, but currently isn't. + err = .ENOSYS + return + } + + assert(.CQE32 not_in params.flags, "unsupported flag") // NOTE: Could support this by making IO_Uring generic. + assert(.SQE128 not_in params.flags, "unsupported flag") // NOTE: Could support this by making IO_Uring generic. + + sq := submission_queue_make(fd, params) or_return + + ring.fd = fd + ring.sq = sq + ring.cq = completion_queue_make(fd, params, &sq) + ring.flags = params.flags + ring.features = params.features + + return +} + +destroy :: proc(ring: ^Ring) { + assert(ring.fd >= 0) + submission_queue_destroy(&ring.sq) + linux.close(ring.fd) + ring.fd = -1 +} + +// Returns a pointer to a vacant submission queue entry, or nil if the submission queue is full. +// NOTE: extra is so you can make sure there is space for related entries, defaults to 1 so +// a link timeout op can always be added after another. +get_sqe :: proc(ring: ^Ring, extra: int = 1) -> (sqe: ^linux.IO_Uring_SQE, ok: bool) { + sq := &ring.sq + head: u32 = sync.atomic_load_explicit(sq.head, .Acquire) + next := sq.sqe_tail + 1 + + if int(next - head) > len(sq.sqes)-extra { + sqe = nil + ok = false + return + } + + sqe = &sq.sqes[sq.sqe_tail & sq.mask] + sqe^ = {} + + sq.sqe_tail = next + ok = true + return +} + +free_space :: proc(ring: ^Ring) -> int { + sq := &ring.sq + head := sync.atomic_load_explicit(sq.head, .Acquire) + next := sq.sqe_tail + 1 + free := len(sq.sqes) - int(next - head) + assert(free >= 0) + return free +} + +// Sync internal state with kernel ring state on the submission queue side. +// Returns the number of all pending events in the submission queue. +// Rationale is to determine that an enter call is needed. +flush_sq :: proc(ring: ^Ring) -> (n_pending: u32) { + sq := &ring.sq + to_submit := sq.sqe_tail - sq.sqe_head + if to_submit != 0 { + tail := sq.tail^ + i: u32 = 0 + for ; i < to_submit; i += 1 { + sq.array[tail & sq.mask] = sq.sqe_head & sq.mask + tail += 1 + sq.sqe_head += 1 + } + sync.atomic_store_explicit(sq.tail, tail, .Release) + } + n_pending = sq_ready(ring) + return +} + +// Returns true if we are not using an SQ thread (thus nobody submits but us), +// or if IORING_SQ_NEED_WAKEUP is set and the SQ thread must be explicitly awakened. +// For the latter case, we set the SQ thread wakeup flag. +// Matches the implementation of sq_ring_needs_enter() in liburing. +sq_ring_needs_enter :: proc(ring: ^Ring, flags: ^linux.IO_Uring_Enter_Flags) -> bool { + assert(flags^ == {}) + if .SQPOLL not_in ring.flags { return true } + if .NEED_WAKEUP in sync.atomic_load_explicit(ring.sq.flags, .Relaxed) { + flags^ += {.SQ_WAKEUP} + return true + } + return false +} + + +// Submits the submission queue entries acquired via get_sqe(). +// Returns the number of entries submitted. +// Optionally wait for a number of events by setting `wait_nr`, and/or set a maximum wait time by setting `timeout`. +submit :: proc(ring: ^Ring, wait_nr: u32 = 0, timeout: ^linux.Time_Spec = nil) -> (n_submitted: u32, err: linux.Errno) { + n_submitted = flush_sq(ring) + flags: linux.IO_Uring_Enter_Flags + if sq_ring_needs_enter(ring, &flags) || wait_nr > 0 { + if wait_nr > 0 || .IOPOLL in ring.flags { + flags += {.GETEVENTS} + } + + flags += {.EXT_ARG} + ext: linux.IO_Uring_Getevents_Arg + ext.ts = timeout + + n_submitted_: int + n_submitted_, err = linux.io_uring_enter2(ring.fd, n_submitted, wait_nr, flags, &ext) + assert(n_submitted_ >= 0) + n_submitted = u32(n_submitted_) + } + return +} + +// Returns the number of submission queue entries in the submission queue. +sq_ready :: proc(ring: ^Ring) -> u32 { + // Always use the shared ring state (i.e. head and not sqe_head) to avoid going out of sync, + // see https://github.com/axboe/liburing/issues/92. + return ring.sq.sqe_tail - sync.atomic_load_explicit(ring.sq.head, .Acquire) +} + +// Returns the number of completion queue entries in the completion queue (yet to consume). +cq_ready :: proc(ring: ^Ring) -> (n_ready: u32) { + return sync.atomic_load_explicit(ring.cq.tail, .Acquire) - ring.cq.head^ +} + +// Copies as many CQEs as are ready, and that can fit into the destination `cqes` slice. +// If none are available, enters into the kernel to wait for at most `wait_nr` CQEs. +// Returns the number of CQEs copied, advancing the CQ ring. +// Provides all the wait/peek methods found in liburing, but with batching and a single method. +// TODO: allow for timeout. +copy_cqes :: proc(ring: ^Ring, cqes: []linux.IO_Uring_CQE, wait_nr: u32) -> (n_copied: u32, err: linux.Errno) { + n_copied = copy_cqes_ready(ring, cqes) + if n_copied > 0 { return } + if wait_nr > 0 || cq_ring_needs_flush(ring) { + _ = linux.io_uring_enter(ring.fd, 0, wait_nr, {.GETEVENTS}, nil) or_return + n_copied = copy_cqes_ready(ring, cqes) + } + return +} + +copy_cqes_ready :: proc(ring: ^Ring, cqes: []linux.IO_Uring_CQE) -> (n_copied: u32) { + n_ready := cq_ready(ring) + n_copied = min(u32(len(cqes)), n_ready) + head := ring.cq.head^ + tail := head + n_copied + shift := u32(.CQE32 in ring.flags) + + i := 0 + for head != tail { + cqes[i] = ring.cq.cqes[(head & ring.cq.mask) << shift] + head += 1 + i += 1 + } + cq_advance(ring, n_copied) + return +} + +cq_ring_needs_flush :: proc(ring: ^Ring) -> bool { + return .CQ_OVERFLOW in sync.atomic_load_explicit(ring.sq.flags, .Relaxed) +} + +// For advanced use cases only that implement custom completion queue methods. +// If you use copy_cqes() or copy_cqe() you must not call cqe_seen() or cq_advance(). +// Must be called exactly once after a zero-copy CQE has been processed by your application. +// Not idempotent, calling more than once will result in other CQEs being lost. +// Matches the implementation of cqe_seen() in liburing. +cqe_seen :: proc(ring: ^Ring) { + cq_advance(ring, 1) +} + +// For advanced use cases only that implement custom completion queue methods. +// Matches the implementation of cq_advance() in liburing. +cq_advance :: proc(ring: ^Ring, count: u32) { + if count == 0 { return } + sync.atomic_store_explicit(ring.cq.head, ring.cq.head^ + count, .Release) +} + +Submission_Queue :: struct { + head: ^u32, + tail: ^u32, + mask: u32, + flags: ^linux.IO_Uring_Submission_Queue_Flags, + dropped: ^u32, + array: []u32, + sqes: []linux.IO_Uring_SQE, + mmap: []u8, + mmap_sqes: []u8, + + // We use `sqe_head` and `sqe_tail` in the same way as liburing: + // We increment `sqe_tail` (but not `tail`) for each call to `get_sqe()`. + // We then set `tail` to `sqe_tail` once, only when these events are actually submitted. + // This allows us to amortize the cost of the @atomicStore to `tail` across multiple SQEs. + sqe_head: u32, + sqe_tail: u32, +} + +submission_queue_make :: proc(fd: linux.Fd, params: ^linux.IO_Uring_Params) -> (sq: Submission_Queue, err: linux.Errno) { + assert(fd >= 0, "uninitialized queue fd") + assert(.SINGLE_MMAP in params.features, "unsupported feature") // NOTE: Could support this, but currently isn't. + + sq_size := params.sq_off.array + params.sq_entries * size_of(u32) + cq_size := params.cq_off.cqes + params.cq_entries * size_of(linux.IO_Uring_CQE) + size := max(sq_size, cq_size) + + // PERF: .POPULATE commits all pages right away, is that desired? + + cqe_map := cast([^]byte)(linux.mmap(0, uint(size), {.READ, .WRITE}, {.SHARED, .POPULATE}, fd, linux.IORING_OFF_SQ_RING) or_return) + defer if err != nil { linux.munmap(cqe_map, uint(size)) } + + size_sqes := params.sq_entries * size_of(linux.IO_Uring_SQE) + sqe_map := cast([^]byte)(linux.mmap(0, uint(size_sqes), {.READ, .WRITE}, {.SHARED, .POPULATE}, fd, linux.IORING_OFF_SQES) or_return) + + array := cast([^]u32)cqe_map[params.sq_off.array:] + sqes := cast([^]linux.IO_Uring_SQE)sqe_map + + sq.head = cast(^u32)&cqe_map[params.sq_off.head] + sq.tail = cast(^u32)&cqe_map[params.sq_off.tail] + sq.mask = (cast(^u32)&cqe_map[params.sq_off.ring_mask])^ + sq.flags = cast(^linux.IO_Uring_Submission_Queue_Flags)&cqe_map[params.sq_off.flags] + sq.dropped = cast(^u32)&cqe_map[params.sq_off.dropped] + sq.array = array[:params.sq_entries] + sq.sqes = sqes[:params.sq_entries] + sq.mmap = cqe_map[:size] + sq.mmap_sqes = sqe_map[:size_sqes] + + return +} + +submission_queue_destroy :: proc(sq: ^Submission_Queue) -> (err: linux.Errno) { + err = linux.munmap(raw_data(sq.mmap), uint(len(sq.mmap))) + err2 := linux.munmap(raw_data(sq.mmap_sqes), uint(len(sq.mmap_sqes))) + if err == nil { err = err2 } + return +} + +Completion_Queue :: struct { + head: ^u32, + tail: ^u32, + mask: u32, + overflow: ^u32, + cqes: []linux.IO_Uring_CQE, +} + +completion_queue_make :: proc(fd: linux.Fd, params: ^linux.IO_Uring_Params, sq: ^Submission_Queue) -> Completion_Queue { + assert(fd >= 0, "uninitialized queue fd") + assert(.SINGLE_MMAP in params.features, "required feature SINGLE_MMAP not supported") + + mmap := sq.mmap + cqes := cast([^]linux.IO_Uring_CQE)&mmap[params.cq_off.cqes] + + return( + { + head = cast(^u32)&mmap[params.cq_off.head], + tail = cast(^u32)&mmap[params.cq_off.tail], + mask = (cast(^u32)&mmap[params.cq_off.ring_mask])^, + overflow = cast(^u32)&mmap[params.cq_off.overflow], + cqes = cqes[:params.cq_entries], + } \ + ) +} diff --git a/core/sys/orca/orca.odin b/core/sys/orca/orca.odin index a36c5fa2a..a0fe0a041 100644 --- a/core/sys/orca/orca.odin +++ b/core/sys/orca/orca.odin @@ -1,15 +1,13 @@ // Bindings for the Orca platform // // See: [[ https://orca-app.dev ]] + package orca import "core:c" char :: c.char -// currently missing in the api.json -window :: distinct u64 - // currently missing in the api.json pool :: struct { arena: arena, @@ -142,17 +140,6 @@ UNICODE_VARIATION_SELECTORS_SUPPLEMENT :: unicode_range { 0xe0100, 239 } UNICODE_SUPPLEMENTARY_PRIVATE_USE_AREA_A :: unicode_range { 0xf0000, 65533 } UNICODE_SUPPLEMENTARY_PRIVATE_USE_AREA_B :: unicode_range { 0x100000, 65533 } -clock_kind :: enum c.int { - MONOTONIC, - UPTIME, - DATE, -} - -@(default_calling_convention="c", link_prefix="oc_") -foreign { - clock_time :: proc(clock: clock_kind) -> f64 --- -} - file_write_slice :: proc(file: file, slice: []char) -> u64 { return file_write(file, u64(len(slice)), raw_data(slice)) } @@ -204,6 +191,26 @@ foreign { mat2x3_rotate :: proc(radians: f32) -> mat2x3 --- // Return a 2x3 matrix representing a translation. mat2x3_translate :: proc(x: f32, y: f32) -> mat2x3 --- + // Return a 2x3 matrix representing a scale. + mat2x3_scale :: proc(x: f32, y: f32) -> mat2x3 --- +} + +//////////////////////////////////////////////////////////////////////////////// +// API for sampling the system clock. +//////////////////////////////////////////////////////////////////////////////// + +clock_kind :: enum u32 { + // A clock incrementing monotonically. + MONOTONIC = 0, + // A clock incrementing monotonically during uptime. + UPTIME = 1, + // A clock driven by the platform time. + DATE = 2, +} + +@(default_calling_convention="c", link_prefix="oc_") +foreign { + clock_time :: proc(clock: clock_kind) -> f64 --- } //////////////////////////////////////////////////////////////////////////////// @@ -354,10 +361,14 @@ foreign { arena_init_with_options :: proc(arena: ^arena, options: ^arena_options) --- // Release all resources allocated to a memory arena. arena_cleanup :: proc(arena: ^arena) --- - // Allocate a block of memory from an arena. + // Allocate a zero initialized block of memory from an arena. arena_push :: proc(arena: ^arena, size: u64) -> rawptr --- - // Allocate an aligned block of memory from an arena. + // Allocate an aligned, zero initialized block of memory from an arena. arena_push_aligned :: proc(arena: ^arena, size: u64, alignment: u32) -> rawptr --- + // Allocate a block of memory from an arena. + arena_push_uninitialized :: proc(arena: ^arena, size: u64) -> rawptr --- + // Allocate an aligned block of memory from an arena. + arena_push_aligned_uninitialized :: proc(arena: ^arena, size: u64, alignment: u32) -> rawptr --- // Reset an arena. All memory that was previously allocated from this arena is released to the arena, and can be reallocated by later calls to `oc_arena_push` and similar functions. No memory is actually released _to the system_. arena_clear :: proc(arena: ^arena) --- // Begin a memory scope. This creates an `oc_arena_scope` object that stores the current offset of the arena. The arena can later be reset to that offset by calling `oc_arena_scope_end`, releasing all memory that was allocated within the scope to the arena. @@ -530,15 +541,15 @@ utf8_status :: enum u32 { // The operation unexpectedly encountered the end of the utf8 sequence. OUT_OF_BOUNDS = 1, // A continuation byte was encountered where a leading byte was expected. - UNEXPECTED_CONTINUATION_BYTE = 3, + UNEXPECTED_CONTINUATION_BYTE = 2, // A leading byte was encountered in the middle of the encoding of utf8 codepoint. - UNEXPECTED_LEADING_BYTE = 4, + UNEXPECTED_LEADING_BYTE = 3, // The utf8 sequence contains an invalid byte. - INVALID_BYTE = 5, + INVALID_BYTE = 4, // The operation encountered an invalid utf8 codepoint. - INVALID_CODEPOINT = 6, + INVALID_CODEPOINT = 5, // The utf8 sequence contains an overlong encoding of a utf8 codepoint. - OVERLONG_ENCODING = 7, + OVERLONG_ENCODING = 6, } // A type representing the result of decoding of utf8-encoded codepoint. @@ -1044,6 +1055,9 @@ file_dialog_result :: struct { selection: str8_list, } +// An opaque handle identifying a window. +window :: distinct u64 + @(default_calling_convention="c", link_prefix="oc_") foreign { // Set the title of the application's window. @@ -1054,8 +1068,93 @@ foreign { request_quit :: proc() --- // Convert a scancode to a keycode, according to current keyboard layout. scancode_to_keycode :: proc(scanCode: scan_code) -> key_code --- +} + +//////////////////////////////////////////////////////////////////////////////// +// Application user input. +//////////////////////////////////////////////////////////////////////////////// + +key_state :: struct { + lastUpdate: u64, + transitionCount: u32, + repeatCount: u32, + down: bool, + sysClicked: bool, + sysDoubleClicked: bool, + sysTripleClicked: bool, +} + +keyboard_state :: struct { + keys: [349]key_state, + mods: keymod_flags, +} + +mouse_state :: struct { + lastUpdate: u64, + posValid: bool, + pos: vec2, + delta: vec2, + wheel: vec2, + using _: struct #raw_union { + buttons: [5]key_state, + using _: struct { + left: key_state, + right: key_state, + middle: key_state, + ext1: key_state, + ext2: key_state, + }, + }, +} + +BACKING_SIZE :: 64 + +text_state :: struct { + lastUpdate: u64, + backing: [64]utf32, + codePoints: str32, +} + +clipboard_state :: struct { + lastUpdate: u64, + pastedText: str8, +} + +input_state :: struct { + frameCounter: u64, + keyboard: keyboard_state, + mouse: mouse_state, + text: text_state, + clipboard: clipboard_state, +} + +@(default_calling_convention="c", link_prefix="oc_") +foreign { + input_process_event :: proc(arena: ^arena, state: ^input_state, event: ^event) --- + input_next_frame :: proc(state: ^input_state) --- + key_down :: proc(state: ^input_state, key: key_code) -> bool --- + key_press_count :: proc(state: ^input_state, key: key_code) -> u8 --- + key_release_count :: proc(state: ^input_state, key: key_code) -> u8 --- + key_repeat_count :: proc(state: ^input_state, key: key_code) -> u8 --- + key_down_scancode :: proc(state: ^input_state, key: scan_code) -> bool --- + key_press_count_scancode :: proc(state: ^input_state, key: scan_code) -> u8 --- + key_release_count_scancode :: proc(state: ^input_state, key: scan_code) -> u8 --- + key_repeat_count_scancode :: proc(state: ^input_state, key: scan_code) -> u8 --- + mouse_down :: proc(state: ^input_state, button: mouse_button) -> bool --- + mouse_pressed :: proc(state: ^input_state, button: mouse_button) -> u8 --- + mouse_released :: proc(state: ^input_state, button: mouse_button) -> u8 --- + mouse_clicked :: proc(state: ^input_state, button: mouse_button) -> bool --- + mouse_double_clicked :: proc(state: ^input_state, button: mouse_button) -> bool --- + mouse_position :: proc(state: ^input_state) -> vec2 --- + mouse_delta :: proc(state: ^input_state) -> vec2 --- + mouse_wheel :: proc(state: ^input_state) -> vec2 --- + input_text_utf32 :: proc(arena: ^arena, state: ^input_state) -> str32 --- + input_text_utf8 :: proc(arena: ^arena, state: ^input_state) -> str8 --- // Put a string in the clipboard. clipboard_set_string :: proc(string: str8) --- + clipboard_pasted :: proc(state: ^input_state) -> bool --- + clipboard_pasted_text :: proc(state: ^input_state) -> str8 --- + key_mods :: proc(state: ^input_state) -> keymod_flags --- } //////////////////////////////////////////////////////////////////////////////// @@ -1073,7 +1172,7 @@ file :: distinct u64 // Flags for the `oc_file_open()` function. file_open_flag :: enum u16 { // Open the file in 'append' mode. All writes append data at the end of the file. - APPEND = 1, + APPEND = 0, // Truncate the file to 0 bytes when opening. TRUNCATE, // Create the file if it does not exist. @@ -1090,7 +1189,7 @@ file_open_flags :: bit_set[file_open_flag; u16] // This enum describes the access permissions of a file handle. file_access_flag :: enum u16 { // The file handle can be used for reading from the file. - READ = 1, + READ = 0, // The file handle can be used for writing to the file. WRITE, } @@ -1242,7 +1341,7 @@ file_type :: enum u32 { // A type describing file permissions. file_perm_flag :: enum u16 { - OTHER_EXEC = 1, + OTHER_EXEC = 0, OTHER_WRITE, OTHER_READ, GROUP_EXEC, @@ -1272,6 +1371,18 @@ file_status :: struct { modificationDate: datestamp, } +// An type describing a list of enumerated files in a given directory. +file_list :: struct { + list: list, + eltCount: u64, +} + +file_listdir_elt :: struct { + listElt: list_elt, + basename: str8, + type: file_type, +} + @(default_calling_convention="c", link_prefix="oc_") foreign { // Send a single I/O request and wait for its completion. @@ -1299,6 +1410,7 @@ foreign { file_get_status :: proc(file: file) -> file_status --- file_size :: proc(file: file) -> u64 --- file_open_with_request :: proc(path: str8, rights: file_access, flags: file_open_flags) -> file --- + file_listdir :: proc(arena: ^arena, directory: str8) -> file_list --- } //////////////////////////////////////////////////////////////////////////////// @@ -1703,87 +1815,6 @@ foreign { // Graphical User Interface API. //////////////////////////////////////////////////////////////////////////////// -key_state :: struct { - lastUpdate: u64, - transitionCount: u32, - repeatCount: u32, - down: bool, - sysClicked: bool, - sysDoubleClicked: bool, - sysTripleClicked: bool, -} - -keyboard_state :: struct { - keys: [349]key_state, - mods: keymod_flags, -} - -mouse_state :: struct { - lastUpdate: u64, - posValid: bool, - pos: vec2, - delta: vec2, - wheel: vec2, - using _: struct #raw_union { - buttons: [5]key_state, - using _: struct { - left: key_state, - right: key_state, - middle: key_state, - ext1: key_state, - ext2: key_state, - }, - }, -} - -BACKING_SIZE :: 64 - -text_state :: struct { - lastUpdate: u64, - backing: [64]utf32, - codePoints: str32, -} - -clipboard_state :: struct { - lastUpdate: u64, - pastedText: str8, -} - -input_state :: struct { - frameCounter: u64, - keyboard: keyboard_state, - mouse: mouse_state, - text: text_state, - clipboard: clipboard_state, -} - -@(default_calling_convention="c", link_prefix="oc_") -foreign { - input_process_event :: proc(arena: ^arena, state: ^input_state, event: ^event) --- - input_next_frame :: proc(state: ^input_state) --- - key_down :: proc(state: ^input_state, key: key_code) -> bool --- - key_press_count :: proc(state: ^input_state, key: key_code) -> u8 --- - key_release_count :: proc(state: ^input_state, key: key_code) -> u8 --- - key_repeat_count :: proc(state: ^input_state, key: key_code) -> u8 --- - key_down_scancode :: proc(state: ^input_state, key: scan_code) -> bool --- - key_press_count_scancode :: proc(state: ^input_state, key: scan_code) -> u8 --- - key_release_count_scancode :: proc(state: ^input_state, key: scan_code) -> u8 --- - key_repeat_count_scancode :: proc(state: ^input_state, key: scan_code) -> u8 --- - mouse_down :: proc(state: ^input_state, button: mouse_button) -> bool --- - mouse_pressed :: proc(state: ^input_state, button: mouse_button) -> u8 --- - mouse_released :: proc(state: ^input_state, button: mouse_button) -> u8 --- - mouse_clicked :: proc(state: ^input_state, button: mouse_button) -> bool --- - mouse_double_clicked :: proc(state: ^input_state, button: mouse_button) -> bool --- - mouse_position :: proc(state: ^input_state) -> vec2 --- - mouse_delta :: proc(state: ^input_state) -> vec2 --- - mouse_wheel :: proc(state: ^input_state) -> vec2 --- - input_text_utf32 :: proc(arena: ^arena, state: ^input_state) -> str32 --- - input_text_utf8 :: proc(arena: ^arena, state: ^input_state) -> str8 --- - clipboard_pasted :: proc(state: ^input_state) -> bool --- - clipboard_pasted_text :: proc(state: ^input_state) -> str8 --- - key_mods :: proc(state: ^input_state) -> keymod_flags --- -} - //////////////////////////////////////////////////////////////////////////////// // Graphical User Interface Core API. //////////////////////////////////////////////////////////////////////////////// @@ -1857,11 +1888,11 @@ ui_attribute_mask :: enum u32 { SIZE_WIDTH = 1, SIZE_HEIGHT = 2, LAYOUT_AXIS = 4, - LAYOUT_ALIGN_X = 64, - LAYOUT_ALIGN_Y = 128, - LAYOUT_SPACING = 32, LAYOUT_MARGIN_X = 8, LAYOUT_MARGIN_Y = 16, + LAYOUT_SPACING = 32, + LAYOUT_ALIGN_X = 64, + LAYOUT_ALIGN_Y = 128, FLOATING_X = 256, FLOATING_Y = 512, FLOAT_TARGET_X = 1024, @@ -1873,10 +1904,10 @@ ui_attribute_mask :: enum u32 { COLOR = 65536, BG_COLOR = 131072, BORDER_COLOR = 262144, - BORDER_SIZE = 2097152, - ROUNDNESS = 4194304, FONT = 524288, FONT_SIZE = 1048576, + BORDER_SIZE = 2097152, + ROUNDNESS = 4194304, DRAW_MASK = 8388608, ANIMATION_TIME = 16777216, ANIMATION_MASK = 33554432, @@ -1898,6 +1929,7 @@ ui_box_size :: [2]ui_size ui_box_floating :: [2]bool +// These bits *disable* the corresponding element when they're set. ui_draw_mask :: enum u32 { BACKGROUND = 1, BORDER = 2, diff --git a/core/sys/posix/fcntl.odin b/core/sys/posix/fcntl.odin index db095c418..52d97f528 100644 --- a/core/sys/posix/fcntl.odin +++ b/core/sys/posix/fcntl.odin @@ -70,7 +70,7 @@ foreign lib { [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html ]] */ - openat :: proc(fd: FD, path: cstring, flags: O_Flags, mode: mode_t = {}) -> FD --- + openat :: proc(fd: FD, path: cstring, flags: O_Flags, #c_vararg mode: ..mode_t) -> FD --- } FCNTL_Cmd :: enum c.int { diff --git a/core/sys/posix/poll.odin b/core/sys/posix/poll.odin index a9e582b51..bb400c5a9 100644 --- a/core/sys/posix/poll.odin +++ b/core/sys/posix/poll.odin @@ -25,7 +25,7 @@ foreign lib { poll :: proc(fds: [^]pollfd, nfds: nfds_t, timeout: c.int) -> c.int --- } -when ODIN_OS == .Haiku { +when ODIN_OS == .Haiku || ODIN_OS == .Linux { nfds_t :: c.ulong } else { nfds_t :: c.uint diff --git a/core/sys/unix/sysctl_openbsd.odin b/core/sys/unix/sysctl_openbsd.odin index e71b743f8..a18b334c5 100644 --- a/core/sys/unix/sysctl_openbsd.odin +++ b/core/sys/unix/sysctl_openbsd.odin @@ -46,4 +46,5 @@ CTL_HW :: 6 HW_VERSION :: 16 HW_SERIALNO :: 17 HW_UUID :: 18 - HW_PHYSMEM64 :: 19 \ No newline at end of file + HW_PHYSMEM64 :: 19 + HW_USERMEM64 :: 20 \ No newline at end of file diff --git a/core/sys/wasm/js/dom.odin b/core/sys/wasm/js/dom.odin index 902dfc941..6dd9dbf45 100644 --- a/core/sys/wasm/js/dom.odin +++ b/core/sys/wasm/js/dom.odin @@ -15,13 +15,15 @@ foreign dom_lib { get_element_value_string_length :: proc(id: string) -> int --- set_element_key_string :: proc(id: string, key: string, value: string) --- - get_element_key_string_length :: proc(id: string, key: string, ) -> int --- + get_element_key_string_length :: proc(id: string, key: string) -> int --- device_pixel_ratio :: proc() -> f64 --- window_set_scroll :: proc(x, y: f64) --- set_element_style :: proc(id: string, key: string, value: string) --- + + set_document_title :: proc(title: string) --- } get_element_value_string :: proc "contextless" (id: string, buf: []byte) -> string { diff --git a/core/sys/wasm/js/memory_all_targets.odin b/core/sys/wasm/js/memory_all_targets.odin index e80d13c0b..69a789145 100644 --- a/core/sys/wasm/js/memory_all_targets.odin +++ b/core/sys/wasm/js/memory_all_targets.odin @@ -1,14 +1,14 @@ #+build !js package wasm_js_interface -import "core:mem" +import "base:runtime" PAGE_SIZE :: 64 * 1024 -page_alloc :: proc(page_count: int) -> (data: []byte, err: mem.Allocator_Error) { +page_alloc :: proc(page_count: int) -> (data: []byte, err: runtime.Allocator_Error) { panic("vendor:wasm/js not supported on non-js targets") } -page_allocator :: proc() -> mem.Allocator { +page_allocator :: proc() -> runtime.Allocator { panic("vendor:wasm/js not supported on non-js targets") } diff --git a/core/sys/wasm/js/memory_js.odin b/core/sys/wasm/js/memory_js.odin index 8232cd0c9..df3191b29 100644 --- a/core/sys/wasm/js/memory_js.odin +++ b/core/sys/wasm/js/memory_js.odin @@ -1,11 +1,11 @@ #+build js wasm32, js wasm64p32 package wasm_js_interface -import "core:mem" +import "base:runtime" import "base:intrinsics" PAGE_SIZE :: 64 * 1024 -page_alloc :: proc(page_count: int) -> (data: []byte, err: mem.Allocator_Error) { +page_alloc :: proc(page_count: int) -> (data: []byte, err: runtime.Allocator_Error) { prev_page_count := intrinsics.wasm_memory_grow(0, uintptr(page_count)) if prev_page_count < 0 { return nil, .Out_Of_Memory @@ -15,11 +15,11 @@ page_alloc :: proc(page_count: int) -> (data: []byte, err: mem.Allocator_Error) return ptr[:page_count * PAGE_SIZE], nil } -page_allocator :: proc() -> mem.Allocator { - procedure :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, +page_allocator :: proc() -> runtime.Allocator { + procedure :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, - location := #caller_location) -> ([]byte, mem.Allocator_Error) { + location := #caller_location) -> ([]byte, runtime.Allocator_Error) { switch mode { case .Alloc, .Alloc_Non_Zeroed: assert(size % PAGE_SIZE == 0) @@ -27,7 +27,7 @@ page_allocator :: proc() -> mem.Allocator { case .Resize, .Free, .Free_All, .Query_Info, .Resize_Non_Zeroed: return nil, .Mode_Not_Implemented case .Query_Features: - set := (^mem.Allocator_Mode_Set)(old_memory) + set := (^runtime.Allocator_Mode_Set)(old_memory) if set != nil { set^ = {.Alloc, .Query_Features} } diff --git a/core/sys/wasm/js/odin.js b/core/sys/wasm/js/odin.js index 43a6b002a..4d19916bd 100644 --- a/core/sys/wasm/js/odin.js +++ b/core/sys/wasm/js/odin.js @@ -10,7 +10,7 @@ function getElement(name) { } function stripNewline(str) { - return str.replace(/\n/, ' ') + return str.replace(/\n/, ' ') } class WasmMemoryInterface { @@ -40,22 +40,14 @@ class WasmMemoryInterface { } - loadF32Array(addr, len) { - let array = new Float32Array(this.memory.buffer, addr, len); - return array; - } - loadF64Array(addr, len) { - let array = new Float64Array(this.memory.buffer, addr, len); - return array; - } - loadU32Array(addr, len) { - let array = new Uint32Array(this.memory.buffer, addr, len); - return array; - } - loadI32Array(addr, len) { - let array = new Int32Array(this.memory.buffer, addr, len); - return array; - } + loadF32Array(addr, len) { return new Float32Array(this.memory.buffer, addr, len); } + loadF64Array(addr, len) { return new Float64Array(this.memory.buffer, addr, len); } + loadU32Array(addr, len) { return new Uint32Array(this.memory.buffer, addr, len); } + loadI32Array(addr, len) { return new Int32Array(this.memory.buffer, addr, len); } + loadU16Array(addr, len) { return new Uint16Array(this.memory.buffer, addr, len); } + loadI16Array(addr, len) { return new Int16Array(this.memory.buffer, addr, len); } + loadU8Array(addr, len) { return new Uint8Array(this.memory.buffer, addr, len); } + loadI8Array(addr, len) { return new Int8Array(this.memory.buffer, addr, len); } loadU8(addr) { return this.mem.getUint8 (addr); } @@ -200,6 +192,7 @@ class WebGLInterface { this.transformFeedbacks = []; this.syncs = []; this.programInfos = {}; + this.extensions = []; } get mem() { @@ -225,6 +218,9 @@ class WebGLInterface { } else { this.ctxVersion = 1.0; } + + this.extensions = this.ctx.getSupportedExtensions(); + return true; } @@ -281,6 +277,30 @@ class WebGLInterface { return source; } + loadTypedArrayFromTexelType(type, size, data) { + switch (type) { + case this.ctx.SHORT: return this.mem.loadI16Array(data, size/2); + case this.ctx.UNSIGNED_SHORT_5_5_5_1: + case this.ctx.UNSIGNED_SHORT_5_6_5: + case this.ctx.UNSIGNED_SHORT_4_4_4_4: + case this.ctx.UNSIGNED_SHORT: + case this.ctx.HALF_FLOAT: return this.mem.loadU16Array(data, size/2); + case this.ctx.FLOAT: return this.mem.loadF32Array(data, size/4); + case this.ctx.INT: return this.mem.loadI32Array(data, size/4) + case this.ctx.UNSIGNED_INT_24_8: + case this.ctx.UNSIGNED_INT_5_9_9_9_REV: + case this.ctx.UNSIGNED_INT_10F_11F_11F_REV: + case this.ctx.UNSIGNED_INT_2_10_10_10_REV: + case this.ctx.UNSIGNED_INT: return this.mem.loadU32Array(data, size/4) + case this.ctx.BYTE: return this.mem.loadI8Array(data, size); + case this.ctx.UNSIGNED_BYTE: return this.mem.loadU8Array(data, size); + case this.ctx.FLOAT_32_UNSIGNED_INT_24_8_REV: + throw new Error("Source data of type FLOAT_32_UNSIGNED_INT_24_8_REV must be null"); + } + + throw new Error(`Unsupported texture data type: 0x${type.toString(16)}`); + } + getWebGL1Interface() { return { SetCurrentContextById: (name_ptr, name_len) => { @@ -327,10 +347,30 @@ class WebGLInterface { IsExtensionSupported: (name_ptr, name_len) => { let name = this.mem.loadString(name_ptr, name_len); - let extensions = this.ctx.getSupportedExtensions(); + let extensions = this.extensions; return extensions.indexOf(name) !== -1 }, + GetSupportedExtensionFromIndex: (index, buf_ptr, buf_len, length_ptr) => { + let extensions = this.extensions; + if (index < 0 || index >= extensions.length) { + return false; + } + + let ext = extensions[index]; + const n = Math.min(buf_len, ext.length); + ext = ext.substring(0, n); + this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(ext)); + + this.mem.storeInt(length_ptr, n); + + return true; + }, + + GetExtension: (name_ptr, name_len) => { + let name = this.mem.loadString(name_ptr, name_len); + this.ctx.getExtension(name); + }, GetError: () => { let err = this.lastError; @@ -616,6 +656,9 @@ class WebGLInterface { FramebufferTexture2D: (target, attachment, textarget, texture, level) => { this.ctx.framebufferTexture2D(target, attachment, textarget, this.textures[texture], level); }, + CheckFramebufferStatus: (target) => { + return this.ctx.checkFramebufferStatus(target) + }, FrontFace: (mode) => { this.ctx.frontFace(mode); }, @@ -625,6 +668,52 @@ class WebGLInterface { this.ctx.generateMipmap(target); }, + GetBufferParameter: (target, pname) => { + return this.ctx.getBufferParameter(target, pname); + }, + + + GetActiveAttrib: (program, index, size_ptr, type_ptr, name_buf_ptr, name_buf_len, name_len_ptr) => { + const info = this.ctx.getActiveAttrib(this.programs[program], index); + + if (size_ptr) { + this.mem.storeInt(size_ptr, info.size); + } + + if (type_ptr) { + this.mem.storeI32(type_ptr, info.type); + } + + if (name_buf_ptr && name_buf_len > 0) { + let n = Math.min(name_buf_len, info.name.length); + let name = info.name.substring(0, n); + this.mem.loadBytes(name_buf_ptr, name_buf_len).set(new TextEncoder().encode(name)); + this.mem.storeInt(name_len_ptr, n); + } else if (name_len_ptr) { + this.mem.storeInt(name_len_ptr, info.name.length); + } + }, + + GetActiveUniform: (program, index, size_ptr, type_ptr, name_buf_ptr, name_buf_len, name_len_ptr) => { + let info = this.ctx.getActiveUniform(this.programs[program], index); + + if (size_ptr) { + this.mem.storeInt(size_ptr, info.size); + } + + if (type_ptr) { + this.mem.storeI32(type_ptr, info.type); + } + + if (name_buf_ptr && name_buf_len > 0) { + let n = Math.min(name_buf_len, info.name.length); + let name = info.name.substring(0, n); + this.mem.loadBytes(name_buf_ptr, name_buf_len).set(new TextEncoder().encode(name)); + this.mem.storeInt(name_len_ptr, n); + } else if (name_len_ptr) { + this.mem.storeInt(name_len_ptr, info.name.length); + } + }, GetAttribLocation: (program, name_ptr, name_len) => { let name = this.mem.loadString(name_ptr, name_len); @@ -786,7 +875,8 @@ class WebGLInterface { TexImage2D: (target, level, internalformat, width, height, border, format, type, size, data) => { if (data) { - this.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, this.mem.loadBytes(data, size)); + const texelData = this.loadTypedArrayFromTexelType(type, size, data); + this.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, texelData); } else { this.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, null); } @@ -798,7 +888,8 @@ class WebGLInterface { this.ctx.texParameteri(target, pname, param); }, TexSubImage2D: (target, level, xoffset, yoffset, width, height, format, type, size, data) => { - this.ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, this.mem.loadBytes(data, size)); + const texelData = this.loadTypedArrayFromTexelType(type, size, data); + this.ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, texelData); }, @@ -932,7 +1023,10 @@ class WebGLInterface { }, /* Texture objects */ - + TexStorage2D: (target, levels, internalformat, width, height) => { + this.assertWebGL2(); + this.ctx.texStorage2D(target, levels, internalformat, width, height); + }, TexStorage3D: (target, levels, internalformat, width, height, depth) => { this.assertWebGL2(); this.ctx.texStorage3D(target, levels, internalformat, width, height, depth); @@ -940,14 +1034,16 @@ class WebGLInterface { TexImage3D: (target, level, internalformat, width, height, depth, border, format, type, size, data) => { this.assertWebGL2(); if (data) { - this.ctx.texImage3D(target, level, internalformat, width, height, depth, border, format, type, this.mem.loadBytes(data, size)); + const texelData = this.loadTypedArrayFromTexelType(type, size, data); + this.ctx.texImage3D(target, level, internalformat, width, height, depth, border, format, type, texelData); } else { this.ctx.texImage3D(target, level, internalformat, width, height, depth, border, format, type, null); } }, TexSubImage3D: (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, size, data) => { this.assertWebGL2(); - this.ctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, this.mem.loadBytes(data, size)); + const texelData = this.loadTypedArrayFromTexelType(type, size, data); + this.ctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texelData); }, CompressedTexImage3D: (target, level, internalformat, width, height, depth, border, imageSize, data) => { this.assertWebGL2(); @@ -1260,15 +1356,34 @@ class WebGLInterface { this.assertWebGL2(); return this.ctx.getUniformBlockIndex(this.programs[program], this.mem.loadString(uniformBlockName_ptr, uniformBlockName_len)); }, - // any getActiveUniformBlockParameter(WebGLProgram program, GLuint uniformBlockIndex, GLenum pname); - GetActiveUniformBlockName: (program, uniformBlockIndex, buf_ptr, buf_len, length_ptr) => { + GetActiveUniformBlockName: (program, uniformBlockIndex, name_buf_ptr, name_buf_len, name_length_ptr) => { this.assertWebGL2(); let name = this.ctx.getActiveUniformBlockName(this.programs[program], uniformBlockIndex); - let n = Math.min(buf_len, name.length); - name = name.substring(0, n); - this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(name)) - this.mem.storeInt(length_ptr, n); + if (name_buf_ptr && name_buf_len > 0) { + let n = Math.min(name_buf_len, name.length); + name = name.substring(0, n); + this.mem.loadBytes(name_buf_ptr, name_buf_len).set(new TextEncoder().encode(name)); + this.mem.storeInt(name_length_ptr, n); + } else if (name_length_ptr) { + this.mem.storeInt(name_length_ptr, name.length); + } + }, + GetActiveUniforms: (program, uniformIndices_ptr, uniformIndices_len, pname, res_ptr) => { + this.assertWebGL2(); + let indices = this.mem.loadU32Array(uniformIndices_ptr, uniformIndices_len); + this.ctx.getActiveUniforms(this.programs[program], indices, pname) + this.mem.loadI32Array(res_ptr, indices.length).set(indices) + }, + GetActiveUniformBlockParameter: (program, uniformBlockIndex, pname, params_ptr) => { + this.assertWebGL2(); + let res = this.ctx.getActiveUniformBlockParameter(this.programs[program], uniformBlockIndex, pname); + + if (res instanceof Uint32Array) { // for pname GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES + this.mem.loadU32Array(params_ptr, res.length).set(res) + } else { + this.mem.storeI32(params_ptr, res) + } }, UniformBlockBinding: (program, uniformBlockIndex, uniformBlockBinding) => { this.assertWebGL2(); @@ -1840,6 +1955,7 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { return false; }, + // Writes a struct of type `Gamepad_State`, see `core/sys/wasm/js/events.odin` get_gamepad_state: (gamepad_id, ep) => { let index = gamepad_id; let gps = navigator.getGamepads(); @@ -1986,6 +2102,11 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { } }, + set_document_title: (title_ptr, title_len) => { + let title = wasmMemoryInterface.loadString(title_ptr, title_len); + document.title = title; + }, + get_element_key_f64: (id_ptr, id_len, key_ptr, key_len) => { let id = wasmMemoryInterface.loadString(id_ptr, id_len); let key = wasmMemoryInterface.loadString(key_ptr, key_len); @@ -2107,7 +2228,7 @@ async function runWasm(wasmPath, consoleElement, extraForeignImports, wasmMemory if (exports.memory) { if (wasmMemoryInterface.memory) { - console.warn("WASM module exports memory, but `runWasm` was given an interface with existing memory too"); + console.warn('WASM module exports memory, but `runWasm` was given an interface with existing memory too. Did you mean to use `-extra-linker-flags:"--import-memory"` to tell the compiler not to export memory?'); } wasmMemoryInterface.setMemory(exports.memory); } diff --git a/core/sys/win32/removal.odin b/core/sys/win32/removal.odin deleted file mode 100644 index 09c16aa05..000000000 --- a/core/sys/win32/removal.odin +++ /dev/null @@ -1,3 +0,0 @@ -package sys_win32 - -#panic(`"core:sys/win32" has been removed. Please use "core:sys/windows"`) \ No newline at end of file diff --git a/core/sys/windows/advapi32.odin b/core/sys/windows/advapi32.odin index 22cb27863..d4b86b875 100644 --- a/core/sys/windows/advapi32.odin +++ b/core/sys/windows/advapi32.odin @@ -228,7 +228,7 @@ foreign advapi32 { } PTOKEN_INFORMATION_CLASS :: ^TOKEN_INFORMATION_CLASS -TOKEN_INFORMATION_CLASS :: enum i32 { +TOKEN_INFORMATION_CLASS :: enum c_int { TokenUser = 1, TokenGroups, TokenPrivileges, @@ -282,7 +282,7 @@ TOKEN_INFORMATION_CLASS :: enum i32 { } PSID_NAME_USE :: ^SID_NAME_USE -SID_NAME_USE :: enum i32 { +SID_NAME_USE :: enum c_int { SidTypeUser = 1, SidTypeGroup, SidTypeDomain, @@ -303,35 +303,35 @@ TOKEN_USER :: struct { PSID_AND_ATTRIBUTES :: ^SID_AND_ATTRIBUTES SID_AND_ATTRIBUTES :: struct { - Sid: rawptr, + Sid: rawptr, Attributes: ULONG, } PTOKEN_TYPE :: ^TOKEN_TYPE TOKEN_TYPE :: enum { - TokenPrimary = 1, + TokenPrimary = 1, TokenImpersonation = 2, } PTOKEN_STATISTICS :: ^TOKEN_STATISTICS TOKEN_STATISTICS :: struct { - TokenId: LUID, - AuthenticationId: LUID, - ExpirationTime: LARGE_INTEGER, - TokenType: TOKEN_TYPE, + TokenId: LUID, + AuthenticationId: LUID, + ExpirationTime: LARGE_INTEGER, + TokenType: TOKEN_TYPE, ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL, - DynamicCharged: DWORD, - DynamicAvailable: DWORD, - GroupCount: DWORD, - PrivilegeCount: DWORD, - ModifiedId: LUID, + DynamicCharged: DWORD, + DynamicAvailable: DWORD, + GroupCount: DWORD, + PrivilegeCount: DWORD, + ModifiedId: LUID, } TOKEN_SOURCE_LENGTH :: 8 PTOKEN_SOURCE :: ^TOKEN_SOURCE TOKEN_SOURCE :: struct { - SourceName: [TOKEN_SOURCE_LENGTH]CHAR, + SourceName: [TOKEN_SOURCE_LENGTH]CHAR, SourceIdentifier: LUID, } @@ -339,7 +339,7 @@ TOKEN_SOURCE :: struct { PTOKEN_PRIVILEGES :: ^TOKEN_PRIVILEGES TOKEN_PRIVILEGES :: struct { PrivilegeCount: DWORD, - Privileges: [0]LUID_AND_ATTRIBUTES, + Privileges: [0]LUID_AND_ATTRIBUTES, } PTOKEN_PRIMARY_GROUP :: ^TOKEN_PRIMARY_GROUP @@ -354,16 +354,16 @@ TOKEN_OWNER :: struct { PTOKEN_GROUPS_AND_PRIVILEGES :: ^TOKEN_GROUPS_AND_PRIVILEGES TOKEN_GROUPS_AND_PRIVILEGES :: struct { - SidCount: DWORD, - SidLength: DWORD, - Sids: PSID_AND_ATTRIBUTES, - RestrictedSidCount: DWORD, + SidCount: DWORD, + SidLength: DWORD, + Sids: PSID_AND_ATTRIBUTES, + RestrictedSidCount: DWORD, RestrictedSidLength: DWORD, - RestrictedSids: PSID_AND_ATTRIBUTES, - PrivilegeCount: DWORD, - PrivilegeLength: DWORD, - Privileges: PLUID_AND_ATTRIBUTES, - AuthenticationId: LUID, + RestrictedSids: PSID_AND_ATTRIBUTES, + PrivilegeCount: DWORD, + PrivilegeLength: DWORD, + Privileges: PLUID_AND_ATTRIBUTES, + AuthenticationId: LUID, } PTOKEN_DEFAULT_DACL :: ^TOKEN_DEFAULT_DACL @@ -374,8 +374,8 @@ TOKEN_DEFAULT_DACL :: struct { PACL :: ^ACL ACL :: struct { AclRevision: BYTE, - Sbz1: BYTE, - AclSize: WORD, - AceCount: WORD, - Sbz2: WORD, + Sbz1: BYTE, + AclSize: WORD, + AceCount: WORD, + Sbz2: WORD, } diff --git a/core/sys/windows/comctl32.odin b/core/sys/windows/comctl32.odin index c7a166634..28fab53be 100644 --- a/core/sys/windows/comctl32.odin +++ b/core/sys/windows/comctl32.odin @@ -5,9 +5,9 @@ foreign import "system:Comctl32.lib" @(default_calling_convention="system") foreign Comctl32 { - InitCommonControlsEx :: proc(picce: ^INITCOMMONCONTROLSEX) -> BOOL --- + InitCommonControlsEx :: proc(picce: ^INITCOMMONCONTROLSEX) -> BOOL --- LoadIconWithScaleDown :: proc(hinst: HINSTANCE, pszName: PCWSTR, cx: c_int, cy: c_int, phico: ^HICON) -> HRESULT --- - SetWindowSubclass :: proc(hwnd: HWND, pfnSubclass: SUBCLASSPROC, uIdSubclass: UINT_PTR, dwRefData: DWORD_PTR) --- + SetWindowSubclass :: proc(hwnd: HWND, pfnSubclass: SUBCLASSPROC, uIdSubclass: UINT_PTR, dwRefData: DWORD_PTR) --- } ICC_LISTVIEW_CLASSES :: 0x00000001 @@ -155,85 +155,85 @@ ILP_NORMAL :: 0 ILP_DOWNLEVEL :: 1 IMAGELISTDRAWPARAMS :: struct { - cbSize: DWORD, - himl: HIMAGELIST, - i: i32, - hdcDst: HDC, - x: i32, - y: i32, - cx: i32, - cy: i32, - xBitmap: i32, - yBitmap: i32, - rgbBk: COLORREF, - rgbFg: COLORREF, - fStyle: UINT, - dwRop: DWORD, - fState: DWORD, - Frame: DWORD, + cbSize: DWORD, + himl: HIMAGELIST, + i: c_int, + hdcDst: HDC, + x: c_int, + y: c_int, + cx: c_int, + cy: c_int, + xBitmap: c_int, + yBitmap: c_int, + rgbBk: COLORREF, + rgbFg: COLORREF, + fStyle: UINT, + dwRop: DWORD, + fState: DWORD, + Frame: DWORD, crEffect: COLORREF, } LPIMAGELISTDRAWPARAMS :: ^IMAGELISTDRAWPARAMS IMAGEINFO :: struct { hbmImage: HBITMAP, - hbmMask: HBITMAP, - Unused1: i32, - Unused2: i32, - rcImage: RECT, + hbmMask: HBITMAP, + Unused1: c_int, + Unused2: c_int, + rcImage: RECT, } LPIMAGEINFO :: ^IMAGEINFO @(default_calling_convention="system") foreign Comctl32 { - ImageList_Create :: proc(cx, cy: i32, flags: UINT, cInitial, cGrow: i32) -> HIMAGELIST --- - ImageList_Destroy :: proc(himl: HIMAGELIST) -> BOOL --- - ImageList_GetImageCount :: proc(himl: HIMAGELIST) -> i32 --- - ImageList_SetImageCount :: proc(himl: HIMAGELIST, uNewCount: UINT) -> BOOL --- - ImageList_Add :: proc(himl: HIMAGELIST, hbmImage, hbmMask: HBITMAP) -> i32 --- - ImageList_ReplaceIcon :: proc(himl: HIMAGELIST, i: i32, hicon: HICON) -> i32 --- - ImageList_SetBkColor :: proc(himl: HIMAGELIST, clrBk: COLORREF) -> COLORREF --- - ImageList_GetBkColor :: proc(himl: HIMAGELIST) -> COLORREF --- - ImageList_SetOverlayImage :: proc(himl: HIMAGELIST, iImage: i32, iOverlay: i32) -> BOOL --- - ImageList_Draw :: proc(himl: HIMAGELIST, i: i32, hdcDst: HDC, x, y: i32, fStyle: UINT) -> BOOL --- - ImageList_Replace :: proc(himl: HIMAGELIST, i: i32, hbmImage, hbmMask: HBITMAP) -> BOOL --- - ImageList_AddMasked :: proc(himl: HIMAGELIST, hbmImage: HBITMAP, crMask: COLORREF) -> i32 --- - ImageList_DrawEx :: proc(himl: HIMAGELIST, i: i32, hdcDst: HDC, x, y, dx, dy: i32, rgbBk, rgbFg: COLORREF, fStyle: UINT) -> BOOL --- - ImageList_DrawIndirect :: proc(pimldp: ^IMAGELISTDRAWPARAMS) -> BOOL --- - ImageList_Remove :: proc(himl: HIMAGELIST, i: i32) -> BOOL --- - ImageList_GetIcon :: proc(himl: HIMAGELIST, i: i32, flags: UINT) -> HICON --- - ImageList_LoadImageW :: proc(hi: HINSTANCE, lpbmp: LPCWSTR, cx, cgrow: i32, crMask: COLORREF, uType, uFlags: UINT) -> HIMAGELIST --- - ImageList_Copy :: proc(himlDst: HIMAGELIST, iDst: i32, himlSrc: HIMAGELIST, iSrc: i32, uFlags: UINT) -> BOOL --- - ImageList_BeginDrag :: proc(himlTrack: HIMAGELIST, iTrack, dxHotspot, dyHotspot: i32) -> BOOL --- - ImageList_EndDrag :: proc() --- - ImageList_DragEnter :: proc(hwndLock: HWND, x, y: i32) -> BOOL --- - ImageList_DragLeave :: proc(hwndLock: HWND) -> BOOL --- - ImageList_DragMove :: proc(x, y: i32) -> BOOL --- - ImageList_SetDragCursorImage :: proc(himlDrag: HIMAGELIST, iDrag, dxHotspot, dyHotspot: i32) -> BOOL --- - ImageList_DragShowNolock :: proc(fShow: BOOL) -> BOOL --- - ImageList_GetDragImage :: proc(ppt, pptHotspot: ^POINT) -> HIMAGELIST --- - ImageList_Read :: proc(pstm: ^IStream) -> HIMAGELIST --- - ImageList_Write :: proc(himl: HIMAGELIST, pstm: ^IStream) -> BOOL --- - ImageList_ReadEx :: proc(dwFlags: DWORD, pstm: ^IStream, riid: REFIID, ppv: PVOID) -> HRESULT --- - ImageList_WriteEx :: proc(himl: HIMAGELIST, dwFlags: DWORD, pstm: ^IStream) -> HRESULT --- - ImageList_GetIconSize :: proc(himl: HIMAGELIST, cx, cy: ^i32) -> BOOL --- - ImageList_SetIconSize :: proc(himl: HIMAGELIST, cx, cy: i32) -> BOOL --- - ImageList_GetImageInfo :: proc(himl: HIMAGELIST, i: i32, pImageInfo: ^IMAGEINFO) -> BOOL --- - ImageList_Merge :: proc(himl1: HIMAGELIST, i1: i32, himl2: HIMAGELIST, i2: i32, dx, dy: i32) -> HIMAGELIST --- - ImageList_Duplicate :: proc(himl: HIMAGELIST) -> HIMAGELIST --- - HIMAGELIST_QueryInterface :: proc(himl: HIMAGELIST, riid: REFIID, ppv: rawptr) -> HRESULT --- + ImageList_Create :: proc(cx, cy: c_int, flags: UINT, cInitial, cGrow: c_int) -> HIMAGELIST --- + ImageList_Destroy :: proc(himl: HIMAGELIST) -> BOOL --- + ImageList_GetImageCount :: proc(himl: HIMAGELIST) -> c_int --- + ImageList_SetImageCount :: proc(himl: HIMAGELIST, uNewCount: UINT) -> BOOL --- + ImageList_Add :: proc(himl: HIMAGELIST, hbmImage, hbmMask: HBITMAP) -> c_int --- + ImageList_ReplaceIcon :: proc(himl: HIMAGELIST, i: c_int, hicon: HICON) -> c_int --- + ImageList_SetBkColor :: proc(himl: HIMAGELIST, clrBk: COLORREF) -> COLORREF --- + ImageList_GetBkColor :: proc(himl: HIMAGELIST) -> COLORREF --- + ImageList_SetOverlayImage :: proc(himl: HIMAGELIST, iImage: c_int, iOverlay: c_int) -> BOOL --- + ImageList_Draw :: proc(himl: HIMAGELIST, i: c_int, hdcDst: HDC, x, y: c_int, fStyle: UINT) -> BOOL --- + ImageList_Replace :: proc(himl: HIMAGELIST, i: c_int, hbmImage, hbmMask: HBITMAP) -> BOOL --- + ImageList_AddMasked :: proc(himl: HIMAGELIST, hbmImage: HBITMAP, crMask: COLORREF) -> c_int --- + ImageList_DrawEx :: proc(himl: HIMAGELIST, i: c_int, hdcDst: HDC, x, y, dx, dy: c_int, rgbBk, rgbFg: COLORREF, fStyle: UINT) -> BOOL --- + ImageList_DrawIndirect :: proc(pimldp: ^IMAGELISTDRAWPARAMS) -> BOOL --- + ImageList_Remove :: proc(himl: HIMAGELIST, i: c_int) -> BOOL --- + ImageList_GetIcon :: proc(himl: HIMAGELIST, i: c_int, flags: UINT) -> HICON --- + ImageList_LoadImageW :: proc(hi: HINSTANCE, lpbmp: LPCWSTR, cx, cgrow: c_int, crMask: COLORREF, uType, uFlags: UINT) -> HIMAGELIST --- + ImageList_Copy :: proc(himlDst: HIMAGELIST, iDst: c_int, himlSrc: HIMAGELIST, iSrc: c_int, uFlags: UINT) -> BOOL --- + ImageList_BeginDrag :: proc(himlTrack: HIMAGELIST, iTrack, dxHotspot, dyHotspot: c_int) -> BOOL --- + ImageList_EndDrag :: proc() --- + ImageList_DragEnter :: proc(hwndLock: HWND, x, y: c_int) -> BOOL --- + ImageList_DragLeave :: proc(hwndLock: HWND) -> BOOL --- + ImageList_DragMove :: proc(x, y: c_int) -> BOOL --- + ImageList_SetDragCursorImage :: proc(himlDrag: HIMAGELIST, iDrag, dxHotspot, dyHotspot: c_int) -> BOOL --- + ImageList_DragShowNolock :: proc(fShow: BOOL) -> BOOL --- + ImageList_GetDragImage :: proc(ppt, pptHotspot: ^POINT) -> HIMAGELIST --- + ImageList_Read :: proc(pstm: ^IStream) -> HIMAGELIST --- + ImageList_Write :: proc(himl: HIMAGELIST, pstm: ^IStream) -> BOOL --- + ImageList_ReadEx :: proc(dwFlags: DWORD, pstm: ^IStream, riid: REFIID, ppv: PVOID) -> HRESULT --- + ImageList_WriteEx :: proc(himl: HIMAGELIST, dwFlags: DWORD, pstm: ^IStream) -> HRESULT --- + ImageList_GetIconSize :: proc(himl: HIMAGELIST, cx, cy: ^c_int) -> BOOL --- + ImageList_SetIconSize :: proc(himl: HIMAGELIST, cx, cy: c_int) -> BOOL --- + ImageList_GetImageInfo :: proc(himl: HIMAGELIST, i: c_int, pImageInfo: ^IMAGEINFO) -> BOOL --- + ImageList_Merge :: proc(himl1: HIMAGELIST, i1: c_int, himl2: HIMAGELIST, i2: c_int, dx, dy: c_int) -> HIMAGELIST --- + ImageList_Duplicate :: proc(himl: HIMAGELIST) -> HIMAGELIST --- + HIMAGELIST_QueryInterface :: proc(himl: HIMAGELIST, riid: REFIID, ppv: rawptr) -> HRESULT --- } -ImageList_AddIcon :: #force_inline proc "system" (himl: HIMAGELIST, hicon: HICON) -> i32 { +ImageList_AddIcon :: #force_inline proc "system" (himl: HIMAGELIST, hicon: HICON) -> c_int { return ImageList_ReplaceIcon(himl, -1, hicon) } ImageList_RemoveAll :: #force_inline proc "system" (himl: HIMAGELIST) -> BOOL { return ImageList_Remove(himl, -1) } -ImageList_ExtractIcon :: #force_inline proc "system" (hi: HINSTANCE, himl: HIMAGELIST, i: i32) -> HICON { +ImageList_ExtractIcon :: #force_inline proc "system" (hi: HINSTANCE, himl: HIMAGELIST, i: c_int) -> HICON { return ImageList_GetIcon(himl, i, 0) } -ImageList_LoadBitmap :: #force_inline proc "system" (hi: HINSTANCE, lpbmp: LPCWSTR, cx, cGrow: i32, crMask: COLORREF) -> HIMAGELIST { +ImageList_LoadBitmap :: #force_inline proc "system" (hi: HINSTANCE, lpbmp: LPCWSTR, cx, cGrow: c_int, crMask: COLORREF) -> HIMAGELIST { return ImageList_LoadImageW(hi, lpbmp, cx, cGrow, crMask, IMAGE_BITMAP, 0) } @@ -1609,9 +1609,9 @@ LPTV_ITEMEXW :: LPTVITEMEXW TVINSERTSTRUCTW :: struct { hParent: HTREEITEM, hInsertAfter: HTREEITEM, - _: struct #raw_union { - itemex: TVITEMEXW, - item: TV_ITEMW, + using _: struct #raw_union { + itemex: TVITEMEXW, + item: TV_ITEMW, }, } TV_INSERTSTRUCTW :: TVINSERTSTRUCTW @@ -1703,7 +1703,7 @@ TreeView_Expand :: #force_inline proc "system" (hwnd: HWND, hitem: HTREEITEM, co } TreeView_GetItemRect :: #force_inline proc "system" (hwnd: HWND, hitem: HTREEITEM, prc: ^RECT, code: UINT) -> BOOL { alias: struct #raw_union { - rc: ^RECT, + rc: ^RECT, hitem: ^HTREEITEM, } diff --git a/core/sys/windows/dbghelp.odin b/core/sys/windows/dbghelp.odin index e32b4c874..4904c5fb4 100644 --- a/core/sys/windows/dbghelp.odin +++ b/core/sys/windows/dbghelp.odin @@ -55,23 +55,54 @@ MINIDUMP_CALLBACK_INFORMATION :: struct { CallbackParam: PVOID, } +MINIDUMP_CALLBACK_TYPE :: enum ULONG { + ModuleCallback, + ThreadCallback, + ThreadExCallback, + IncludeThreadCallback, + IncludeModuleCallback, + MemoryCallback, + CancelCallback, + WriteKernelMinidumpCallback, + KernelMinidumpStatusCallback, + RemoveMemoryCallback, + IncludeVmRegionCallback, + IoStartCallback, + IoWriteAllCallback, + IoFinishCallback, + ReadMemoryFailureCallback, + SecondaryFlagsCallback, + IsProcessSnapshotCallback, + VmStartCallback, + VmQueryCallback, + VmPreReadCallback, + VmPostReadCallback, +} + +MINIDUMP_SECONDARY_FLAG :: enum ULONG { + WithoutPowerInfo = 0, +} +MINIDUMP_SECONDARY_FLAGS :: distinct bit_set[MINIDUMP_SECONDARY_FLAG; ULONG] +MiniSecondaryWithoutPowerInfo :: MINIDUMP_SECONDARY_FLAGS{.WithoutPowerInfo} +MiniSecondaryValidFlags :: MINIDUMP_SECONDARY_FLAGS{.WithoutPowerInfo} + MINIDUMP_CALLBACK_INPUT :: struct { ProcessId: ULONG, ProcessHandle: HANDLE, - CallbackType: ULONG, + CallbackType: MINIDUMP_CALLBACK_TYPE, using _: struct #raw_union { - Status: HRESULT, - Thread: MINIDUMP_THREAD_CALLBACK, - ThreadEx: MINIDUMP_THREAD_EX_CALLBACK, - Module: MINIDUMP_MODULE_CALLBACK, - IncludeThread: MINIDUMP_INCLUDE_THREAD_CALLBACK, - IncludeModule: MINIDUMP_INCLUDE_MODULE_CALLBACK, - Io: MINIDUMP_IO_CALLBACK, - ReadMemoryFailure: MINIDUMP_READ_MEMORY_FAILURE_CALLBACK, - SecondaryFlags: ULONG, - VmQuery: MINIDUMP_VM_QUERY_CALLBACK, - VmPreRead: MINIDUMP_VM_PRE_READ_CALLBACK, - VmPostRead: MINIDUMP_VM_POST_READ_CALLBACK, + Status: HRESULT `raw_union_tag:"KernelMinidumpStatusCallback"`, + Thread: MINIDUMP_THREAD_CALLBACK `raw_union_tag:"ThreadCallback"`, + ThreadEx: MINIDUMP_THREAD_EX_CALLBACK `raw_union_tag:"ThreadExCallback"`, + Module: MINIDUMP_MODULE_CALLBACK `raw_union_tag:"ModuleCallback"`, + IncludeThread: MINIDUMP_INCLUDE_THREAD_CALLBACK `raw_union_tag:"IncludeThreadCallback"`, + IncludeModule: MINIDUMP_INCLUDE_MODULE_CALLBACK `raw_union_tag:"IncludeModuleCallback"`, + Io: MINIDUMP_IO_CALLBACK `raw_union_tag:"IoStartCallback,IoWriteAllCallback,IoFinishCallback"`, + ReadMemoryFailure: MINIDUMP_READ_MEMORY_FAILURE_CALLBACK `raw_union_tag:"ReadMemoryFailureCallback"`, + SecondaryFlags: MINIDUMP_SECONDARY_FLAGS `raw_union_tag:"SecondaryFlagsCallback"`, + VmQuery: MINIDUMP_VM_QUERY_CALLBACK `raw_union_tag:"VmQueryCallback"`, + VmPreRead: MINIDUMP_VM_PRE_READ_CALLBACK `raw_union_tag:"VmPreReadCallback"`, + VmPostRead: MINIDUMP_VM_POST_READ_CALLBACK `raw_union_tag:"VmPostReadCallback"`, }, } diff --git a/core/sys/windows/dnsapi.odin b/core/sys/windows/dnsapi.odin index 728813696..73e565118 100644 --- a/core/sys/windows/dnsapi.odin +++ b/core/sys/windows/dnsapi.odin @@ -5,6 +5,6 @@ foreign import "system:Dnsapi.lib" @(default_calling_convention="system") foreign Dnsapi { - DnsQuery_UTF8 :: proc(name: cstring, type: u16, options: DNS_QUERY_OPTIONS, extra: PVOID, results: ^^DNS_RECORD, reserved: PVOID) -> DNS_STATUS --- - DnsRecordListFree :: proc(list: ^DNS_RECORD, options: DWORD) --- + DnsQuery_UTF8 :: proc(name: cstring, type: u16, options: DNS_QUERY_OPTIONS, extra: PVOID, results: ^^DNS_RECORD, reserved: PVOID) -> DNS_STATUS --- + DnsRecordListFree :: proc(list: ^DNS_RECORD, options: DWORD) --- } diff --git a/core/sys/windows/dwmapi.odin b/core/sys/windows/dwmapi.odin index e86730660..0980c2e94 100644 --- a/core/sys/windows/dwmapi.odin +++ b/core/sys/windows/dwmapi.odin @@ -47,9 +47,9 @@ DWM_WINDOW_CORNER_PREFERENCE :: enum c_int { @(default_calling_convention="system") foreign dwmapi { - DwmFlush :: proc() -> HRESULT --- - DwmIsCompositionEnabled :: proc(pfEnabled: ^BOOL) -> HRESULT --- + DwmFlush :: proc() -> HRESULT --- + DwmIsCompositionEnabled :: proc(pfEnabled: ^BOOL) -> HRESULT --- DwmExtendFrameIntoClientArea :: proc(hWnd: HWND, pMarInset: PMARGINS) -> HRESULT --- - DwmGetWindowAttribute :: proc(hWnd: HWND, dwAttribute: DWORD, pvAttribute: PVOID, cbAttribute: DWORD) -> HRESULT --- - DwmSetWindowAttribute :: proc(hWnd: HWND, dwAttribute: DWORD, pvAttribute: LPCVOID, cbAttribute: DWORD) -> HRESULT --- + DwmGetWindowAttribute :: proc(hWnd: HWND, dwAttribute: DWORD, pvAttribute: PVOID, cbAttribute: DWORD) -> HRESULT --- + DwmSetWindowAttribute :: proc(hWnd: HWND, dwAttribute: DWORD, pvAttribute: LPCVOID, cbAttribute: DWORD) -> HRESULT --- } diff --git a/core/sys/windows/gdi32.odin b/core/sys/windows/gdi32.odin index 141429483..2ff346c7e 100644 --- a/core/sys/windows/gdi32.odin +++ b/core/sys/windows/gdi32.odin @@ -1,96 +1,105 @@ #+build windows package sys_windows -import "core:math/fixed" - foreign import gdi32 "system:Gdi32.lib" @(default_calling_convention="system") foreign gdi32 { - GetDeviceCaps :: proc(hdc: HDC, index: INT) -> INT --- + GetDeviceCaps :: proc(hdc: HDC, index: INT) -> INT --- GetStockObject :: proc(i: INT) -> HGDIOBJ --- - SelectObject :: proc(hdc: HDC, h: HGDIOBJ) -> HGDIOBJ --- - DeleteObject :: proc(ho: HGDIOBJ) -> BOOL --- - SetBkColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF --- - SetBkMode :: proc(hdc: HDC, mode: BKMODE) -> INT --- + SelectObject :: proc(hdc: HDC, h: HGDIOBJ) -> HGDIOBJ --- + DeleteObject :: proc(ho: HGDIOBJ) -> BOOL --- + SetBkColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF --- + SetBkMode :: proc(hdc: HDC, mode: BKMODE) -> INT --- CreateCompatibleDC :: proc(hdc: HDC) -> HDC --- - DeleteDC :: proc(hdc: HDC) -> BOOL --- - CancelDC :: proc(hdc: HDC) -> BOOL --- - SaveDC :: proc(hdc: HDC) -> INT --- - RestoreDC :: proc(hdc: HDC, nSavedDC: INT) -> BOOL --- + DeleteDC :: proc(hdc: HDC) -> BOOL --- + CancelDC :: proc(hdc: HDC) -> BOOL --- + SaveDC :: proc(hdc: HDC) -> INT --- + RestoreDC :: proc(hdc: HDC, nSavedDC: INT) -> BOOL --- CreateDIBPatternBrush :: proc(h: HGLOBAL, iUsage: UINT) -> HBRUSH --- - CreateDIBitmap :: proc(hdc: HDC, pbmih: ^BITMAPINFOHEADER, flInit: DWORD, pjBits: VOID, pbmi: ^BITMAPINFO, iUsage: UINT) -> HBITMAP --- - CreateDIBSection :: proc(hdc: HDC, pbmi: ^BITMAPINFO, usage: UINT, ppvBits: ^^VOID, hSection: HANDLE, offset: DWORD) -> HBITMAP --- - StretchDIBits :: proc(hdc: HDC, xDest, yDest, DestWidth, DestHeight, xSrc, ySrc, SrcWidth, SrcHeight: INT, lpBits: VOID, lpbmi: ^BITMAPINFO, iUsage: UINT, rop: DWORD) -> INT --- - StretchBlt :: proc(hdcDest: HDC, xDest, yDest, wDest, hDest: INT, hdcSrc: HDC, xSrc, ySrc, wSrc, hSrc: INT, rop: DWORD) -> BOOL --- + CreateBitmap :: proc(nWidth: INT, nHeight: INT, nPlanes: UINT, nBitCount: UINT, lpBits: LPVOID) -> HBITMAP --- + CreateDIBitmap :: proc(hdc: HDC, pbmih: ^BITMAPINFOHEADER, flInit: DWORD, pjBits: PVOID, pbmi: ^BITMAPINFO, iUsage: UINT) -> HBITMAP --- + CreateDIBSection :: proc(hdc: HDC, pbmi: ^BITMAPINFO, usage: UINT, ppvBits: ^PVOID, hSection: HANDLE, offset: DWORD) -> HBITMAP --- + StretchDIBits :: proc(hdc: HDC, xDest, yDest, DestWidth, DestHeight, xSrc, ySrc, SrcWidth, SrcHeight: INT, lpBits: LPVOID, lpbmi: ^BITMAPINFO, iUsage: UINT, rop: DWORD) -> INT --- + StretchBlt :: proc(hdcDest: HDC, xDest, yDest, wDest, hDest: INT, hdcSrc: HDC, xSrc, ySrc, wSrc, hSrc: INT, rop: DWORD) -> BOOL --- - SetPixelFormat :: proc(hdc: HDC, format: INT, ppfd: ^PIXELFORMATDESCRIPTOR) -> BOOL --- - ChoosePixelFormat :: proc(hdc: HDC, ppfd: ^PIXELFORMATDESCRIPTOR) -> INT --- + SetPixelFormat :: proc(hdc: HDC, format: INT, ppfd: ^PIXELFORMATDESCRIPTOR) -> BOOL --- + ChoosePixelFormat :: proc(hdc: HDC, ppfd: ^PIXELFORMATDESCRIPTOR) -> INT --- DescribePixelFormat :: proc(hdc: HDC, iPixelFormat: INT, nBytes: UINT, ppfd: ^PIXELFORMATDESCRIPTOR) -> INT --- - SwapBuffers :: proc(hdc: HDC) -> BOOL --- + SwapBuffers :: proc(hdc: HDC) -> BOOL --- SetDCBrushColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF --- GetDCBrushColor :: proc(hdc: HDC) -> COLORREF --- - PatBlt :: proc(hdc: HDC, x, y, w, h: INT, rop: DWORD) -> BOOL --- - Rectangle :: proc(hdc: HDC, left, top, right, bottom: INT) -> BOOL --- + PatBlt :: proc(hdc: HDC, x, y, w, h: INT, rop: DWORD) -> BOOL --- - CreateFontW :: proc(cHeight, cWidth, cEscapement, cOrientation, cWeight: INT, bItalic, bUnderline, bStrikeOut, iCharSet, iOutPrecision: DWORD, iClipPrecision, iQuality, iPitchAndFamily: DWORD, pszFaceName: LPCWSTR) -> HFONT --- - CreateFontIndirectW :: proc(lplf: ^LOGFONTW) -> HFONT --- + CreateFontW :: proc(cHeight, cWidth, cEscapement, cOrientation, cWeight: INT, bItalic, bUnderline, bStrikeOut, iCharSet, iOutPrecision: DWORD, iClipPrecision, iQuality, iPitchAndFamily: DWORD, pszFaceName: LPCWSTR) -> HFONT --- + CreateFontIndirectW :: proc(lplf: ^LOGFONTW) -> HFONT --- CreateFontIndirectExW :: proc(unnamedParam1: ^ENUMLOGFONTEXDVW) -> HFONT --- - AddFontResourceW :: proc(unnamedParam1: LPCWSTR) -> INT --- - AddFontResourceExW :: proc(name: LPCWSTR, fl: DWORD, res: PVOID) -> INT --- - AddFontMemResourceEx :: proc(pFileView: PVOID, cjSize: DWORD, pvResrved: PVOID, pNumFonts: ^DWORD) -> HANDLE --- - EnumFontsW :: proc(hdc: HDC, lpLogfont: LPCWSTR, lpProc: FONTENUMPROCW, lParam: LPARAM) -> INT --- - EnumFontFamiliesW :: proc(hdc: HDC, lpLogfont: LPCWSTR, lpProc: FONTENUMPROCW, lParam: LPARAM) -> INT --- - EnumFontFamiliesExW :: proc(hdc: HDC, lpLogfont: LPLOGFONTW, lpProc: FONTENUMPROCW, lParam: LPARAM, dwFlags: DWORD) -> INT --- + AddFontResourceW :: proc(unnamedParam1: LPCWSTR) -> INT --- + AddFontResourceExW :: proc(name: LPCWSTR, fl: DWORD, res: PVOID) -> INT --- + AddFontMemResourceEx :: proc(pFileView: PVOID, cjSize: DWORD, pvResrved: PVOID, pNumFonts: ^DWORD) -> HANDLE --- + EnumFontsW :: proc(hdc: HDC, lpLogfont: LPCWSTR, lpProc: FONTENUMPROCW, lParam: LPARAM) -> INT --- + EnumFontFamiliesW :: proc(hdc: HDC, lpLogfont: LPCWSTR, lpProc: FONTENUMPROCW, lParam: LPARAM) -> INT --- + EnumFontFamiliesExW :: proc(hdc: HDC, lpLogfont: LPLOGFONTW, lpProc: FONTENUMPROCW, lParam: LPARAM, dwFlags: DWORD) -> INT --- - TextOutW :: proc(hdc: HDC, x, y: INT, lpString: LPCWSTR, c: INT) -> BOOL --- + TextOutW :: proc(hdc: HDC, x, y: INT, lpString: LPCWSTR, c: INT) -> BOOL --- GetTextExtentPoint32W :: proc(hdc: HDC, lpString: LPCWSTR, c: INT, psizl: LPSIZE) -> BOOL --- - GetTextMetricsW :: proc(hdc: HDC, lptm: LPTEXTMETRICW) -> BOOL --- + GetTextMetricsW :: proc(hdc: HDC, lptm: LPTEXTMETRICW) -> BOOL --- CreateSolidBrush :: proc(color: COLORREF) -> HBRUSH --- - GetObjectW :: proc(h: HANDLE, c: INT, pv: LPVOID) -> int --- + GetObjectW :: proc(h: HANDLE, c: INT, pv: LPVOID) -> c_int --- CreateCompatibleBitmap :: proc(hdc: HDC, cx, cy: INT) -> HBITMAP --- - BitBlt :: proc(hdc: HDC, x, y, cx, cy: INT, hdcSrc: HDC, x1, y1: INT, rop: DWORD) -> BOOL --- - GetDIBits :: proc(hdc: HDC, hbm: HBITMAP, start, cLines: UINT, lpvBits: LPVOID, lpbmi: ^BITMAPINFO, usage: UINT) -> INT --- - SetDIBits :: proc(hdc: HDC, hbm: HBITMAP, start: UINT, cLines: UINT, lpBits: VOID, lpbmi: ^BITMAPINFO, ColorUse: UINT) -> INT --- - SetDIBColorTable :: proc(hdc: HDC, iStart: UINT, cEntries: UINT, prgbq: ^RGBQUAD) -> UINT --- - GetDIBColorTable :: proc(hdc: HDC, iStart: UINT, cEntries: UINT, prgbq: ^RGBQUAD) -> UINT --- + BitBlt :: proc(hdc: HDC, x, y, cx, cy: INT, hdcSrc: HDC, x1, y1: INT, rop: DWORD) -> BOOL --- + GetDIBits :: proc(hdc: HDC, hbm: HBITMAP, start, cLines: UINT, lpvBits: LPVOID, lpbmi: ^BITMAPINFO, usage: UINT) -> INT --- + SetDIBits :: proc(hdc: HDC, hbm: HBITMAP, start: UINT, cLines: UINT, lpBits: PVOID, lpbmi: ^BITMAPINFO, ColorUse: UINT) -> INT --- + SetDIBColorTable :: proc(hdc: HDC, iStart: UINT, cEntries: UINT, prgbq: ^RGBQUAD) -> UINT --- + GetDIBColorTable :: proc(hdc: HDC, iStart: UINT, cEntries: UINT, prgbq: ^RGBQUAD) -> UINT --- - CreatePen :: proc(iStyle, cWidth: INT, color: COLORREF) -> HPEN --- - ExtCreatePen :: proc(iPenStyle, cWidth: DWORD, plbrush: ^LOGBRUSH, cStyle: DWORD, pstyle: ^DWORD) -> HPEN --- + CreatePen :: proc(iStyle, cWidth: INT, color: COLORREF) -> HPEN --- + ExtCreatePen :: proc(iPenStyle, cWidth: DWORD, plbrush: ^LOGBRUSH, cStyle: DWORD, pstyle: ^DWORD) -> HPEN --- SetDCPenColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF --- GetDCPenColor :: proc(hdc: HDC) -> COLORREF --- - CreatePalette :: proc(plpal: ^LOGPALETTE) -> HPALETTE --- - SelectPalette :: proc(hdc: HDC, hPal: HPALETTE, bForceBkgd: BOOL) -> HPALETTE --- + CreatePalette :: proc(plpal: ^LOGPALETTE) -> HPALETTE --- + SelectPalette :: proc(hdc: HDC, hPal: HPALETTE, bForceBkgd: BOOL) -> HPALETTE --- RealizePalette :: proc(hdc: HDC) -> UINT --- SetTextColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF --- - RoundRect :: proc(hdc: HDC, left: INT, top: INT, right: INT, bottom: INT, width: INT, height: INT) -> BOOL --- - SetPixel :: proc(hdc: HDC, x: INT, y: INT, color: COLORREF) -> COLORREF --- + SetPixel :: proc(hdc: HDC, x: INT, y: INT, color: COLORREF) -> COLORREF --- GdiTransparentBlt :: proc(hdcDest: HDC, xoriginDest, yoriginDest, wDest, hDest: INT, hdcSrc: HDC, xoriginSrc, yoriginSrc, wSrc, hSrc: INT, crTransparent: UINT) -> BOOL --- - GdiGradientFill :: proc(hdc: HDC, pVertex: PTRIVERTEX, nVertex: ULONG, pMesh: PVOID, nCount: ULONG, ulMode: ULONG) -> BOOL --- - GdiAlphaBlend :: proc(hdcDest: HDC, xoriginDest, yoriginDest, wDest, hDest: INT, hdcSrc: HDC, xoriginSrc, yoriginSrc, wSrc, hSrc: INT, ftn: BLENDFUNCTION) -> BOOL --- + GdiGradientFill :: proc(hdc: HDC, pVertex: PTRIVERTEX, nVertex: ULONG, pMesh: PVOID, nCount: ULONG, ulMode: ULONG) -> BOOL --- + GdiAlphaBlend :: proc(hdcDest: HDC, xoriginDest, yoriginDest, wDest, hDest: INT, hdcSrc: HDC, xoriginSrc, yoriginSrc, wSrc, hSrc: INT, ftn: BLENDFUNCTION) -> BOOL --- + + // Filled Shape Functions + Rectangle :: proc(hdc: HDC, left, top, right, bottom: c_int) -> BOOL --- + Ellipse :: proc(hdc: HDC, left, top, right, bottom: c_int) -> BOOL --- + RoundRect :: proc(hdc: HDC, left, top, right, bottom, width, height: c_int) -> BOOL --- + Pie :: proc(hdc: HDC, left, right, top, bottom, xr1, yr1, xr2, yr2: c_int) -> BOOL --- + Chord :: proc(hdc: HDC, x1, y1, x2, y2, x3, y3, x4, y4: c_int) -> BOOL --- + Polygon :: proc(hdc: HDC, apt: [^]POINT, cpt: c_int) -> BOOL --- + PolyPolygon :: proc(hdc: HDC, apt: [^]POINT, asz: [^]c_int, csz: c_int) -> BOOL --- } +@(require_results) RGB :: #force_inline proc "contextless" (#any_int r, g, b: int) -> COLORREF { return COLORREF(DWORD(BYTE(r)) | (DWORD(BYTE(g)) << 8) | (DWORD(BYTE(b)) << 16)) } +@(require_results) PALETTERGB :: #force_inline proc "contextless" (#any_int r, g, b: int) -> COLORREF { return 0x02000000 | RGB(r, g, b) } +@(require_results) PALETTEINDEX :: #force_inline proc "contextless" (#any_int i: int) -> COLORREF { return COLORREF(DWORD(0x01000000) | DWORD(WORD(i))) } -FXPT2DOT30 :: distinct fixed.Fixed(i32, 30) +FXPT2DOT30 :: distinct i32 // fixed.Fixed(i32, 30) CIEXYZ :: struct { ciexyzX, ciexyzY, ciexyzZ: FXPT2DOT30, @@ -143,6 +152,13 @@ BKMODE :: enum { OPAQUE = 2, } +ICONINFO :: struct { + fIcon: BOOL, + xHotspot, yHotspot: DWORD, + hbmMask, hbmColor: HBITMAP, +} +PICONINFO :: ^ICONINFO + ICONINFOEXW :: struct { cbSize: DWORD, fIcon: BOOL, @@ -154,17 +170,21 @@ ICONINFOEXW :: struct { } PICONINFOEXW :: ^ICONINFOEXW -AC_SRC_OVER :: 0x00 +AC_SRC_OVER :: 0x00 AC_SRC_ALPHA :: 0x01 TransparentBlt :: GdiTransparentBlt -GradientFill :: GdiGradientFill -AlphaBlend :: GdiAlphaBlend +GradientFill :: GdiGradientFill +AlphaBlend :: GdiAlphaBlend COLOR16 :: USHORT TRIVERTEX :: struct { - x, y: LONG, - Red, Green, Blue, Alpha: COLOR16, + x: LONG, + y: LONG, + Red: COLOR16, + Green: COLOR16, + Blue: COLOR16, + Alpha: COLOR16, } PTRIVERTEX :: ^TRIVERTEX @@ -179,7 +199,10 @@ GRADIENT_RECT :: struct { PGRADIENT_RECT :: ^GRADIENT_RECT BLENDFUNCTION :: struct { - BlendOp, BlendFlags, SourceConstantAlpha, AlphaFormat: BYTE, + BlendOp: BYTE, + BlendFlags: BYTE, + SourceConstantAlpha: BYTE, + AlphaFormat: BYTE, } GRADIENT_FILL_RECT_H : ULONG : 0x00000000 diff --git a/core/sys/windows/hidpi.odin b/core/sys/windows/hidpi.odin index 5e9787527..2cf2b2f34 100644 --- a/core/sys/windows/hidpi.odin +++ b/core/sys/windows/hidpi.odin @@ -1,213 +1,212 @@ #+build windows package sys_windows -import "core:c" HIDD_CONFIGURATION :: struct { - cookie: PVOID, - size: ULONG, + cookie: PVOID, + size: ULONG, RingBufferSize: ULONG, } PHIDD_CONFIGURATION :: ^HIDD_CONFIGURATION HIDD_ATTRIBUTES :: struct { - Size: ULONG, - VendorID: USHORT, - ProductID: USHORT, + Size: ULONG, + VendorID: USHORT, + ProductID: USHORT, VersionNumber: USHORT, } PHIDD_ATTRIBUTES :: ^HIDD_ATTRIBUTES HIDP_CAPS :: struct { - Usage: USAGE, - UsagePage: USAGE, - InputReportByteLength: USHORT, - OutputReportByteLength: USHORT, - FeatureReportByteLength: USHORT, - Reserved: [17]USHORT, + Usage: USAGE, + UsagePage: USAGE, + InputReportByteLength: USHORT, + OutputReportByteLength: USHORT, + FeatureReportByteLength: USHORT, + Reserved: [17]USHORT, NumberLinkCollectionNodes: USHORT, - NumberInputButtonCaps: USHORT, - NumberInputValueCaps: USHORT, - NumberInputDataIndices: USHORT, - NumberOutputButtonCaps: USHORT, - NumberOutputValueCaps: USHORT, - NumberOutputDataIndices: USHORT, - NumberFeatureButtonCaps: USHORT, - NumberFeatureValueCaps: USHORT, - NumberFeatureDataIndices: USHORT, + NumberInputButtonCaps: USHORT, + NumberInputValueCaps: USHORT, + NumberInputDataIndices: USHORT, + NumberOutputButtonCaps: USHORT, + NumberOutputValueCaps: USHORT, + NumberOutputDataIndices: USHORT, + NumberFeatureButtonCaps: USHORT, + NumberFeatureValueCaps: USHORT, + NumberFeatureDataIndices: USHORT, } PHIDP_CAPS :: ^HIDP_CAPS HIDP_BUTTON_CAPS :: struct { - UsagePage: USAGE, - ReportID: UCHAR, - IsAlias: BOOLEAN, - BitField: USHORT, - LinkCollection: USHORT, - LinkUsage: USAGE, - LinkUsagePage: USAGE, - IsRange: BOOLEAN, - IsStringRange: BOOLEAN, + UsagePage: USAGE, + ReportID: UCHAR, + IsAlias: BOOLEAN, + BitField: USHORT, + LinkCollection: USHORT, + LinkUsage: USAGE, + LinkUsagePage: USAGE, + IsRange: BOOLEAN, + IsStringRange: BOOLEAN, IsDesignatorRange: BOOLEAN, - IsAbsolute: BOOLEAN, - ReportCount: USHORT, - Reserved2: USHORT, - Reserved: [9]ULONG, + IsAbsolute: BOOLEAN, + ReportCount: USHORT, + Reserved2: USHORT, + Reserved: [9]ULONG, using _: struct #raw_union { Range: struct { - UsageMin: USAGE, - UsageMax: USAGE, - StringMin: USHORT, - StringMax: USHORT, + UsageMin: USAGE, + UsageMax: USAGE, + StringMin: USHORT, + StringMax: USHORT, DesignatorMin: USHORT, DesignatorMax: USHORT, - DataIndexMin: USHORT, - DataIndexMax: USHORT, - }, + DataIndexMin: USHORT, + DataIndexMax: USHORT, + } `raw_union_tag:"IsRange=true"`, NotRange: struct { - Usage: USAGE, - Reserved1: USAGE, - StringIndex: USHORT, - Reserved2: USHORT, + Usage: USAGE, + Reserved1: USAGE, + StringIndex: USHORT, + Reserved2: USHORT, DesignatorIndex: USHORT, - Reserved3: USHORT, - DataIndex: USHORT, - Reserved4: USHORT, - }, + Reserved3: USHORT, + DataIndex: USHORT, + Reserved4: USHORT, + } `raw_union_tag:"IsRange=false"`, }, } PHIDP_BUTTON_CAPS :: ^HIDP_BUTTON_CAPS HIDP_VALUE_CAPS :: struct { - UsagePage: USAGE, - ReportID: UCHAR, - IsAlias: BOOLEAN, - BitField: USHORT, - LinkCollection: USHORT, - LinkUsage: USAGE, - LinkUsagePage: USAGE, - IsRange: BOOLEAN, - IsStringRange: BOOLEAN, + UsagePage: USAGE, + ReportID: UCHAR, + IsAlias: BOOLEAN, + BitField: USHORT, + LinkCollection: USHORT, + LinkUsage: USAGE, + LinkUsagePage: USAGE, + IsRange: BOOLEAN, + IsStringRange: BOOLEAN, IsDesignatorRange: BOOLEAN, - IsAbsolute: BOOLEAN, - HasNull: BOOLEAN, - Reserved: UCHAR, - BitSize: USHORT, - ReportCount: USHORT, - Reserved2: [5]USHORT, - UnitsExp: ULONG, - Units: ULONG, - LogicalMin: LONG, - LogicalMax: LONG, - PhysicalMin: LONG, - PhysicalMax: LONG, + IsAbsolute: BOOLEAN, + HasNull: BOOLEAN, + Reserved: UCHAR, + BitSize: USHORT, + ReportCount: USHORT, + Reserved2: [5]USHORT, + UnitsExp: ULONG, + Units: ULONG, + LogicalMin: LONG, + LogicalMax: LONG, + PhysicalMin: LONG, + PhysicalMax: LONG, using _: struct #raw_union { Range: struct { - UsageMin: USAGE, - UsageMax: USAGE, - StringMin: USHORT, - StringMax: USHORT, + UsageMin: USAGE, + UsageMax: USAGE, + StringMin: USHORT, + StringMax: USHORT, DesignatorMin: USHORT, DesignatorMax: USHORT, - DataIndexMin: USHORT, - DataIndexMax: USHORT, - }, + DataIndexMin: USHORT, + DataIndexMax: USHORT, + } `raw_union_tag:"IsRange=true"`, NotRange: struct { - Usage: USAGE, - Reserved1: USAGE, - StringIndex: USHORT, - Reserved2: USHORT, + Usage: USAGE, + Reserved1: USAGE, + StringIndex: USHORT, + Reserved2: USHORT, DesignatorIndex: USHORT, - Reserved3: USHORT, - DataIndex: USHORT, - Reserved4: USHORT, - }, + Reserved3: USHORT, + DataIndex: USHORT, + Reserved4: USHORT, + } `raw_union_tag:"IsRange=false"`, }, } PHIDP_VALUE_CAPS :: ^HIDP_VALUE_CAPS HIDP_DATA :: struct { DataIndex: USHORT, - Reserved: USHORT, + Reserved: USHORT, using _ : struct #raw_union { RawValue: ULONG, - On: BOOLEAN, + On: BOOLEAN, }, } PHIDP_DATA :: ^HIDP_DATA HIDP_LINK_COLLECTION_NODE :: struct { - LinkUsage: USAGE, - LinkUsagePage: USAGE, - Parent: USHORT, + LinkUsage: USAGE, + LinkUsagePage: USAGE, + Parent: USHORT, NumberOfChildren: USHORT, - NextSibling: USHORT, - FirstChild: USHORT, - CollectionType: [8]ULONG, - IsAlias: [1]ULONG, - Reserved: [23]ULONG, - UserContext: PVOID, + NextSibling: USHORT, + FirstChild: USHORT, + CollectionType: [8]ULONG, + IsAlias: [1]ULONG, + Reserved: [23]ULONG, + UserContext: PVOID, } PHIDP_LINK_COLLECTION_NODE :: ^HIDP_LINK_COLLECTION_NODE HIDP_PREPARSED_DATA :: rawptr PHIDP_PREPARSED_DATA :: ^HIDP_PREPARSED_DATA -HIDP_REPORT_TYPE :: enum c.int { +HIDP_REPORT_TYPE :: enum c_int { Input, Output, Feature, } -HIDP_STATUS_SUCCESS : NTSTATUS : 0x110000 -HIDP_STATUS_NULL : NTSTATUS : -2146369535 //0x80110001 -HIDP_STATUS_INVALID_PREPARSED_DATA : NTSTATUS : -1072627711 //0xC0110001 -HIDP_STATUS_INVALID_REPORT_TYPE : NTSTATUS : -1072627710 //0xC0110002 -HIDP_STATUS_INVALID_REPORT_LENGTH : NTSTATUS : -1072627709 //0xC0110003 -HIDP_STATUS_USAGE_NOT_FOUND : NTSTATUS : -1072627708 //0xC0110004 -HIDP_STATUS_VALUE_OUT_OF_RANGE : NTSTATUS : -1072627707 //0xC0110005 -HIDP_STATUS_BAD_LOG_PHY_VALUES : NTSTATUS : -1072627706 //0xC0100006 -HIDP_STATUS_BUFFER_TOO_SMALL : NTSTATUS : -1072627705 //0xC0110007 -HIDP_STATUS_INTERNAL_ERROR : NTSTATUS : -1072627704 //0xC0110008 -HIDP_STATUS_I8042_TRANS_UNKNOWN : NTSTATUS : -1072627703 //0xC0110009 -HIDP_STATUS_INCOMPATIBLE_REPORT_ID : NTSTATUS : -1072627702 //0xC011000A -HIDP_STATUS_NOT_VALUE_ARRAY : NTSTATUS : -1072627701 //0xC011000B -HIDP_STATUS_IS_VALUE_ARRAY : NTSTATUS : -1072627700 //0xC011000C -HIDP_STATUS_DATA_INDEX_NOT_FOUND : NTSTATUS : -1072627699 //0xC011000D +HIDP_STATUS_SUCCESS : NTSTATUS : 0x110000 +HIDP_STATUS_NULL : NTSTATUS : -2146369535 //0x80110001 +HIDP_STATUS_INVALID_PREPARSED_DATA : NTSTATUS : -1072627711 //0xC0110001 +HIDP_STATUS_INVALID_REPORT_TYPE : NTSTATUS : -1072627710 //0xC0110002 +HIDP_STATUS_INVALID_REPORT_LENGTH : NTSTATUS : -1072627709 //0xC0110003 +HIDP_STATUS_USAGE_NOT_FOUND : NTSTATUS : -1072627708 //0xC0110004 +HIDP_STATUS_VALUE_OUT_OF_RANGE : NTSTATUS : -1072627707 //0xC0110005 +HIDP_STATUS_BAD_LOG_PHY_VALUES : NTSTATUS : -1072627706 //0xC0100006 +HIDP_STATUS_BUFFER_TOO_SMALL : NTSTATUS : -1072627705 //0xC0110007 +HIDP_STATUS_INTERNAL_ERROR : NTSTATUS : -1072627704 //0xC0110008 +HIDP_STATUS_I8042_TRANS_UNKNOWN : NTSTATUS : -1072627703 //0xC0110009 +HIDP_STATUS_INCOMPATIBLE_REPORT_ID : NTSTATUS : -1072627702 //0xC011000A +HIDP_STATUS_NOT_VALUE_ARRAY : NTSTATUS : -1072627701 //0xC011000B +HIDP_STATUS_IS_VALUE_ARRAY : NTSTATUS : -1072627700 //0xC011000C +HIDP_STATUS_DATA_INDEX_NOT_FOUND : NTSTATUS : -1072627699 //0xC011000D HIDP_STATUS_DATA_INDEX_OUT_OF_RANGE : NTSTATUS : -1072627698 //0xC011000E -HIDP_STATUS_BUTTON_NOT_PRESSED : NTSTATUS : -1072627697 //0xC011000F -HIDP_STATUS_REPORT_DOES_NOT_EXIST : NTSTATUS : -1072627696 //0xC0110010 -HIDP_STATUS_NOT_IMPLEMENTED : NTSTATUS : -1072627680 //0xC0110020 -HIDP_STATUS_NOT_BUTTON_ARRAY : NTSTATUS : -1072627679 //0xC0110021 +HIDP_STATUS_BUTTON_NOT_PRESSED : NTSTATUS : -1072627697 //0xC011000F +HIDP_STATUS_REPORT_DOES_NOT_EXIST : NTSTATUS : -1072627696 //0xC0110010 +HIDP_STATUS_NOT_IMPLEMENTED : NTSTATUS : -1072627680 //0xC0110020 +HIDP_STATUS_NOT_BUTTON_ARRAY : NTSTATUS : -1072627679 //0xC0110021 HIDP_STATUS_I8242_TRANS_UNKNOWN :: HIDP_STATUS_I8042_TRANS_UNKNOWN foreign import hid "system:hid.lib" @(default_calling_convention="system") foreign hid { - HidP_GetCaps :: proc(PreparsedData: PHIDP_PREPARSED_DATA, Capabilities: PHIDP_CAPS) -> NTSTATUS --- - HidP_GetButtonCaps :: proc(ReportType: HIDP_REPORT_TYPE, ButtonCaps: PHIDP_BUTTON_CAPS, ButtonCapsLength: PUSHORT, PreparsedData: PHIDP_PREPARSED_DATA) -> NTSTATUS --- - HidP_GetValueCaps :: proc(ReportType: HIDP_REPORT_TYPE, ValueCaps: PHIDP_VALUE_CAPS, ValueCapsLength: PUSHORT, PreparsedData: PHIDP_PREPARSED_DATA) -> NTSTATUS --- - HidP_GetUsages :: proc(ReportType: HIDP_REPORT_TYPE, UsagePage: USAGE, LinkCollection: USHORT, UsageList: PUSAGE, UsageLength: PULONG, PreparsedData: PHIDP_PREPARSED_DATA, Report: PCHAR, ReportLength: ULONG) -> NTSTATUS --- - HidP_GetUsageValue :: proc(ReportType: HIDP_REPORT_TYPE, UsagePage: USAGE, LinkCollection: USHORT, Usage: USAGE, UsageValue: PULONG, PreparsedData: PHIDP_PREPARSED_DATA, Report: PCHAR, ReportLength: ULONG) -> NTSTATUS --- - HidP_GetData :: proc(ReportType: HIDP_REPORT_TYPE, DataList: PHIDP_DATA, DataLength: PULONG, PreparsedData: PHIDP_PREPARSED_DATA, Report: PCHAR, ReportLength: ULONG) -> NTSTATUS --- + HidP_GetCaps :: proc(PreparsedData: PHIDP_PREPARSED_DATA, Capabilities: PHIDP_CAPS) -> NTSTATUS --- + HidP_GetButtonCaps :: proc(ReportType: HIDP_REPORT_TYPE, ButtonCaps: PHIDP_BUTTON_CAPS, ButtonCapsLength: PUSHORT, PreparsedData: PHIDP_PREPARSED_DATA) -> NTSTATUS --- + HidP_GetValueCaps :: proc(ReportType: HIDP_REPORT_TYPE, ValueCaps: PHIDP_VALUE_CAPS, ValueCapsLength: PUSHORT, PreparsedData: PHIDP_PREPARSED_DATA) -> NTSTATUS --- + HidP_GetUsages :: proc(ReportType: HIDP_REPORT_TYPE, UsagePage: USAGE, LinkCollection: USHORT, UsageList: PUSAGE, UsageLength: PULONG, PreparsedData: PHIDP_PREPARSED_DATA, Report: PCHAR, ReportLength: ULONG) -> NTSTATUS --- + HidP_GetUsageValue :: proc(ReportType: HIDP_REPORT_TYPE, UsagePage: USAGE, LinkCollection: USHORT, Usage: USAGE, UsageValue: PULONG, PreparsedData: PHIDP_PREPARSED_DATA, Report: PCHAR, ReportLength: ULONG) -> NTSTATUS --- + HidP_GetData :: proc(ReportType: HIDP_REPORT_TYPE, DataList: PHIDP_DATA, DataLength: PULONG, PreparsedData: PHIDP_PREPARSED_DATA, Report: PCHAR, ReportLength: ULONG) -> NTSTATUS --- HidP_GetLinkCollectionNodes :: proc(LinkCollectionNodes: PHIDP_LINK_COLLECTION_NODE, LinkCollectionNodesLength: PULONG, PreparsedData: PHIDP_PREPARSED_DATA) -> NTSTATUS --- - HidD_GetAttributes :: proc(HidDeviceObject: HANDLE, Attributes: PHIDD_ATTRIBUTES) -> BOOLEAN --- - HidD_GetHidGuid :: proc(HidGuid: LPGUID) --- - HidD_GetPreparsedData :: proc(HidDeviceObject: HANDLE, PreparsedData: ^PHIDP_PREPARSED_DATA) -> BOOLEAN --- - HidD_FreePreparsedData :: proc(PreparsedData: PHIDP_PREPARSED_DATA) -> BOOLEAN --- - HidD_FlushQueue :: proc(HidDeviceObject: HANDLE) -> BOOLEAN --- - HidD_GetConfiguration :: proc(HidDeviceObject: HANDLE, Configuration: PHIDD_CONFIGURATION, ConfigurationLength: ULONG) -> BOOLEAN --- - HidD_SetConfiguration :: proc(HidDeviceObject: HANDLE, Configuration: PHIDD_CONFIGURATION, ConfigurationLength: ULONG) -> BOOLEAN --- - HidD_GetFeature :: proc(HidDeviceObject: HANDLE, ReportBuffer: PVOID, ReportBufferLength: ULONG) -> BOOLEAN --- - HidD_SetFeature :: proc(HidDeviceObject: HANDLE, ReportBuffer: PVOID, ReportBufferLength: ULONG) -> BOOLEAN --- - HidD_GetInputReport :: proc(HidDeviceObject: HANDLE, ReportBuffer: PVOID, ReportBufferLength: ULONG) -> BOOLEAN --- - HidD_SetOutputReport :: proc(HidDeviceObject: HANDLE, ReportBuffer: PVOID, ReportBufferLength: ULONG) -> BOOLEAN --- - HidD_GetNumInputBuffers :: proc(HidDeviceObject: HANDLE, NumberBuffers: PULONG) -> BOOLEAN --- - HidD_SetNumInputBuffers :: proc(HidDeviceObject: HANDLE, NumberBuffers: ULONG) -> BOOLEAN --- + HidD_GetAttributes :: proc(HidDeviceObject: HANDLE, Attributes: PHIDD_ATTRIBUTES) -> BOOLEAN --- + HidD_GetHidGuid :: proc(HidGuid: LPGUID) --- + HidD_GetPreparsedData :: proc(HidDeviceObject: HANDLE, PreparsedData: ^PHIDP_PREPARSED_DATA) -> BOOLEAN --- + HidD_FreePreparsedData :: proc(PreparsedData: PHIDP_PREPARSED_DATA) -> BOOLEAN --- + HidD_FlushQueue :: proc(HidDeviceObject: HANDLE) -> BOOLEAN --- + HidD_GetConfiguration :: proc(HidDeviceObject: HANDLE, Configuration: PHIDD_CONFIGURATION, ConfigurationLength: ULONG) -> BOOLEAN --- + HidD_SetConfiguration :: proc(HidDeviceObject: HANDLE, Configuration: PHIDD_CONFIGURATION, ConfigurationLength: ULONG) -> BOOLEAN --- + HidD_GetFeature :: proc(HidDeviceObject: HANDLE, ReportBuffer: PVOID, ReportBufferLength: ULONG) -> BOOLEAN --- + HidD_SetFeature :: proc(HidDeviceObject: HANDLE, ReportBuffer: PVOID, ReportBufferLength: ULONG) -> BOOLEAN --- + HidD_GetInputReport :: proc(HidDeviceObject: HANDLE, ReportBuffer: PVOID, ReportBufferLength: ULONG) -> BOOLEAN --- + HidD_SetOutputReport :: proc(HidDeviceObject: HANDLE, ReportBuffer: PVOID, ReportBufferLength: ULONG) -> BOOLEAN --- + HidD_GetNumInputBuffers :: proc(HidDeviceObject: HANDLE, NumberBuffers: PULONG) -> BOOLEAN --- + HidD_SetNumInputBuffers :: proc(HidDeviceObject: HANDLE, NumberBuffers: ULONG) -> BOOLEAN --- HidD_GetPhysicalDescriptor :: proc(HidDeviceObject: HANDLE, Buffer: PVOID, BufferLength: ULONG) -> BOOLEAN --- HidD_GetManufacturerString :: proc(HidDeviceObject: HANDLE, Buffer: PVOID, BufferLength: ULONG) -> BOOLEAN --- - HidD_GetProductString :: proc(HidDeviceObject: HANDLE, Buffer: PVOID, BufferLength: ULONG) -> BOOLEAN --- - HidD_GetIndexedString :: proc(HidDeviceObject: HANDLE, StringIndex: ULONG, Buffer: PVOID, BufferLength: ULONG) -> BOOLEAN --- + HidD_GetProductString :: proc(HidDeviceObject: HANDLE, Buffer: PVOID, BufferLength: ULONG) -> BOOLEAN --- + HidD_GetIndexedString :: proc(HidDeviceObject: HANDLE, StringIndex: ULONG, Buffer: PVOID, BufferLength: ULONG) -> BOOLEAN --- HidD_GetSerialNumberString :: proc(HidDeviceObject: HANDLE, Buffer: PVOID, BufferLength: ULONG) -> BOOLEAN --- - HidD_GetMsGenreDescriptor :: proc(HidDeviceObject: HANDLE, Buffer: PVOID, BufferLength: ULONG) -> BOOLEAN --- + HidD_GetMsGenreDescriptor :: proc(HidDeviceObject: HANDLE, Buffer: PVOID, BufferLength: ULONG) -> BOOLEAN --- } diff --git a/core/sys/windows/hidusage.odin b/core/sys/windows/hidusage.odin index eb2a85f2e..5f87bea2d 100644 --- a/core/sys/windows/hidusage.odin +++ b/core/sys/windows/hidusage.odin @@ -4,260 +4,260 @@ package sys_windows USAGE :: distinct USHORT PUSAGE :: ^USAGE -HID_USAGE_PAGE_UNDEFINED :: 0x00 -HID_USAGE_PAGE_GENERIC :: 0x01 -HID_USAGE_PAGE_SIMULATION :: 0x02 -HID_USAGE_PAGE_VR :: 0x03 -HID_USAGE_PAGE_SPORT :: 0x04 -HID_USAGE_PAGE_GAME :: 0x05 -HID_USAGE_PAGE_GENERIC_DEVICE :: 0x06 -HID_USAGE_PAGE_KEYBOARD :: 0x07 -HID_USAGE_PAGE_LED :: 0x08 -HID_USAGE_PAGE_BUTTON :: 0x09 -HID_USAGE_PAGE_ORDINAL :: 0x0A -HID_USAGE_PAGE_TELEPHONY :: 0x0B -HID_USAGE_PAGE_CONSUMER :: 0x0C -HID_USAGE_PAGE_DIGITIZER :: 0x0D -HID_USAGE_PAGE_HAPTICS :: 0x0E -HID_USAGE_PAGE_PID :: 0x0F -HID_USAGE_PAGE_UNICODE :: 0x10 -HID_USAGE_PAGE_ALPHANUMERIC :: 0x14 -HID_USAGE_PAGE_SENSOR :: 0x20 -HID_USAGE_PAGE_LIGHTING_ILLUMINATION :: 0x59 -HID_USAGE_PAGE_BARCODE_SCANNER :: 0x8C -HID_USAGE_PAGE_WEIGHING_DEVICE :: 0x8D -HID_USAGE_PAGE_MAGNETIC_STRIPE_READER :: 0x8E -HID_USAGE_PAGE_CAMERA_CONTROL :: 0x90 -HID_USAGE_PAGE_ARCADE :: 0x91 +HID_USAGE_PAGE_UNDEFINED :: 0x00 +HID_USAGE_PAGE_GENERIC :: 0x01 +HID_USAGE_PAGE_SIMULATION :: 0x02 +HID_USAGE_PAGE_VR :: 0x03 +HID_USAGE_PAGE_SPORT :: 0x04 +HID_USAGE_PAGE_GAME :: 0x05 +HID_USAGE_PAGE_GENERIC_DEVICE :: 0x06 +HID_USAGE_PAGE_KEYBOARD :: 0x07 +HID_USAGE_PAGE_LED :: 0x08 +HID_USAGE_PAGE_BUTTON :: 0x09 +HID_USAGE_PAGE_ORDINAL :: 0x0A +HID_USAGE_PAGE_TELEPHONY :: 0x0B +HID_USAGE_PAGE_CONSUMER :: 0x0C +HID_USAGE_PAGE_DIGITIZER :: 0x0D +HID_USAGE_PAGE_HAPTICS :: 0x0E +HID_USAGE_PAGE_PID :: 0x0F +HID_USAGE_PAGE_UNICODE :: 0x10 +HID_USAGE_PAGE_ALPHANUMERIC :: 0x14 +HID_USAGE_PAGE_SENSOR :: 0x20 +HID_USAGE_PAGE_LIGHTING_ILLUMINATION :: 0x59 +HID_USAGE_PAGE_BARCODE_SCANNER :: 0x8C +HID_USAGE_PAGE_WEIGHING_DEVICE :: 0x8D +HID_USAGE_PAGE_MAGNETIC_STRIPE_READER :: 0x8E +HID_USAGE_PAGE_CAMERA_CONTROL :: 0x90 +HID_USAGE_PAGE_ARCADE :: 0x91 HID_USAGE_PAGE_MICROSOFT_BLUETOOTH_HANDSFREE :: 0xFFF3 -HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN :: 0xFF00 -HID_USAGE_PAGE_VENDOR_DEFINED_END :: 0xFFFF +HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN :: 0xFF00 +HID_USAGE_PAGE_VENDOR_DEFINED_END :: 0xFFFF -HID_USAGE_GENERIC_POINTER :: 0x01 -HID_USAGE_GENERIC_MOUSE :: 0x02 -HID_USAGE_GENERIC_JOYSTICK :: 0x04 -HID_USAGE_GENERIC_GAMEPAD :: 0x05 -HID_USAGE_GENERIC_KEYBOARD :: 0x06 -HID_USAGE_GENERIC_KEYPAD :: 0x07 -HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER :: 0x08 -HID_USAGE_GENERIC_TABLET_PC_SYSTEM_CTL :: 0x09 +HID_USAGE_GENERIC_POINTER :: 0x01 +HID_USAGE_GENERIC_MOUSE :: 0x02 +HID_USAGE_GENERIC_JOYSTICK :: 0x04 +HID_USAGE_GENERIC_GAMEPAD :: 0x05 +HID_USAGE_GENERIC_KEYBOARD :: 0x06 +HID_USAGE_GENERIC_KEYPAD :: 0x07 +HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER :: 0x08 +HID_USAGE_GENERIC_TABLET_PC_SYSTEM_CTL :: 0x09 HID_USAGE_GENERIC_PORTABLE_DEVICE_CONTROL :: 0x0D -HID_USAGE_GENERIC_INTERACTIVE_CONTROL :: 0x0E -HID_USAGE_GENERIC_SYSTEM_CTL :: 0x80 +HID_USAGE_GENERIC_INTERACTIVE_CONTROL :: 0x0E +HID_USAGE_GENERIC_SYSTEM_CTL :: 0x80 -HID_USAGE_GENERIC_X :: 0x30 -HID_USAGE_GENERIC_Y :: 0x31 -HID_USAGE_GENERIC_Z :: 0x32 -HID_USAGE_GENERIC_RX :: 0x33 -HID_USAGE_GENERIC_RY :: 0x34 -HID_USAGE_GENERIC_RZ :: 0x35 -HID_USAGE_GENERIC_SLIDER :: 0x36 -HID_USAGE_GENERIC_DIAL :: 0x37 -HID_USAGE_GENERIC_WHEEL :: 0x38 -HID_USAGE_GENERIC_HATSWITCH :: 0x39 -HID_USAGE_GENERIC_COUNTED_BUFFER :: 0x3A -HID_USAGE_GENERIC_BYTE_COUNT :: 0x3B -HID_USAGE_GENERIC_MOTION_WAKEUP :: 0x3C -HID_USAGE_GENERIC_START :: 0x3D -HID_USAGE_GENERIC_SELECT :: 0x3E -HID_USAGE_GENERIC_VX :: 0x40 -HID_USAGE_GENERIC_VY :: 0x41 -HID_USAGE_GENERIC_VZ :: 0x42 -HID_USAGE_GENERIC_VBRX :: 0x43 -HID_USAGE_GENERIC_VBRY :: 0x44 -HID_USAGE_GENERIC_VBRZ :: 0x45 -HID_USAGE_GENERIC_VNO :: 0x46 -HID_USAGE_GENERIC_FEATURE_NOTIFICATION :: 0x47 -HID_USAGE_GENERIC_RESOLUTION_MULTIPLIER :: 0x48 -HID_USAGE_GENERIC_SYSCTL_POWER :: 0x81 -HID_USAGE_GENERIC_SYSCTL_SLEEP :: 0x82 -HID_USAGE_GENERIC_SYSCTL_WAKE :: 0x83 -HID_USAGE_GENERIC_SYSCTL_CONTEXT_MENU :: 0x84 -HID_USAGE_GENERIC_SYSCTL_MAIN_MENU :: 0x85 -HID_USAGE_GENERIC_SYSCTL_APP_MENU :: 0x86 -HID_USAGE_GENERIC_SYSCTL_HELP_MENU :: 0x87 -HID_USAGE_GENERIC_SYSCTL_MENU_EXIT :: 0x88 -HID_USAGE_GENERIC_SYSCTL_MENU_SELECT :: 0x89 -HID_USAGE_GENERIC_SYSCTL_MENU_RIGHT :: 0x8A -HID_USAGE_GENERIC_SYSCTL_MENU_LEFT :: 0x8B -HID_USAGE_GENERIC_SYSCTL_MENU_UP :: 0x8C -HID_USAGE_GENERIC_SYSCTL_MENU_DOWN :: 0x8D -HID_USAGE_GENERIC_SYSCTL_COLD_RESTART :: 0x8E -HID_USAGE_GENERIC_SYSCTL_WARM_RESTART :: 0x8F -HID_USAGE_GENERIC_DPAD_UP :: 0x90 -HID_USAGE_GENERIC_DPAD_DOWN :: 0x91 -HID_USAGE_GENERIC_DPAD_RIGHT :: 0x92 -HID_USAGE_GENERIC_DPAD_LEFT :: 0x93 -HID_USAGE_GENERIC_SYSCTL_FN :: 0x97 -HID_USAGE_GENERIC_SYSCTL_FN_LOCK :: 0x98 -HID_USAGE_GENERIC_SYSCTL_FN_LOCK_INDICATOR :: 0x99 -HID_USAGE_GENERIC_SYSCTL_DISMISS_NOTIFICATION :: 0x9A -HID_USAGE_GENERIC_SYSCTL_DOCK :: 0xA0 -HID_USAGE_GENERIC_SYSCTL_UNDOCK :: 0xA1 -HID_USAGE_GENERIC_SYSCTL_SETUP :: 0xA2 -HID_USAGE_GENERIC_SYSCTL_SYS_BREAK :: 0xA3 -HID_USAGE_GENERIC_SYSCTL_SYS_DBG_BREAK :: 0xA4 -HID_USAGE_GENERIC_SYSCTL_APP_BREAK :: 0xA5 -HID_USAGE_GENERIC_SYSCTL_APP_DBG_BREAK :: 0xA6 -HID_USAGE_GENERIC_SYSCTL_MUTE :: 0xA7 -HID_USAGE_GENERIC_SYSCTL_HIBERNATE :: 0xA8 -HID_USAGE_GENERIC_SYSCTL_DISP_INVERT :: 0xB0 -HID_USAGE_GENERIC_SYSCTL_DISP_INTERNAL :: 0xB1 -HID_USAGE_GENERIC_SYSCTL_DISP_EXTERNAL :: 0xB2 -HID_USAGE_GENERIC_SYSCTL_DISP_BOTH :: 0xB3 -HID_USAGE_GENERIC_SYSCTL_DISP_DUAL :: 0xB4 -HID_USAGE_GENERIC_SYSCTL_DISP_TOGGLE :: 0xB5 -HID_USAGE_GENERIC_SYSCTL_DISP_SWAP :: 0xB6 -HID_USAGE_GENERIC_SYSCTL_DISP_AUTOSCALE :: 0xB7 -HID_USAGE_GENERIC_SYSTEM_DISPLAY_ROTATION_LOCK_BUTTON :: 0xC9 +HID_USAGE_GENERIC_X :: 0x30 +HID_USAGE_GENERIC_Y :: 0x31 +HID_USAGE_GENERIC_Z :: 0x32 +HID_USAGE_GENERIC_RX :: 0x33 +HID_USAGE_GENERIC_RY :: 0x34 +HID_USAGE_GENERIC_RZ :: 0x35 +HID_USAGE_GENERIC_SLIDER :: 0x36 +HID_USAGE_GENERIC_DIAL :: 0x37 +HID_USAGE_GENERIC_WHEEL :: 0x38 +HID_USAGE_GENERIC_HATSWITCH :: 0x39 +HID_USAGE_GENERIC_COUNTED_BUFFER :: 0x3A +HID_USAGE_GENERIC_BYTE_COUNT :: 0x3B +HID_USAGE_GENERIC_MOTION_WAKEUP :: 0x3C +HID_USAGE_GENERIC_START :: 0x3D +HID_USAGE_GENERIC_SELECT :: 0x3E +HID_USAGE_GENERIC_VX :: 0x40 +HID_USAGE_GENERIC_VY :: 0x41 +HID_USAGE_GENERIC_VZ :: 0x42 +HID_USAGE_GENERIC_VBRX :: 0x43 +HID_USAGE_GENERIC_VBRY :: 0x44 +HID_USAGE_GENERIC_VBRZ :: 0x45 +HID_USAGE_GENERIC_VNO :: 0x46 +HID_USAGE_GENERIC_FEATURE_NOTIFICATION :: 0x47 +HID_USAGE_GENERIC_RESOLUTION_MULTIPLIER :: 0x48 +HID_USAGE_GENERIC_SYSCTL_POWER :: 0x81 +HID_USAGE_GENERIC_SYSCTL_SLEEP :: 0x82 +HID_USAGE_GENERIC_SYSCTL_WAKE :: 0x83 +HID_USAGE_GENERIC_SYSCTL_CONTEXT_MENU :: 0x84 +HID_USAGE_GENERIC_SYSCTL_MAIN_MENU :: 0x85 +HID_USAGE_GENERIC_SYSCTL_APP_MENU :: 0x86 +HID_USAGE_GENERIC_SYSCTL_HELP_MENU :: 0x87 +HID_USAGE_GENERIC_SYSCTL_MENU_EXIT :: 0x88 +HID_USAGE_GENERIC_SYSCTL_MENU_SELECT :: 0x89 +HID_USAGE_GENERIC_SYSCTL_MENU_RIGHT :: 0x8A +HID_USAGE_GENERIC_SYSCTL_MENU_LEFT :: 0x8B +HID_USAGE_GENERIC_SYSCTL_MENU_UP :: 0x8C +HID_USAGE_GENERIC_SYSCTL_MENU_DOWN :: 0x8D +HID_USAGE_GENERIC_SYSCTL_COLD_RESTART :: 0x8E +HID_USAGE_GENERIC_SYSCTL_WARM_RESTART :: 0x8F +HID_USAGE_GENERIC_DPAD_UP :: 0x90 +HID_USAGE_GENERIC_DPAD_DOWN :: 0x91 +HID_USAGE_GENERIC_DPAD_RIGHT :: 0x92 +HID_USAGE_GENERIC_DPAD_LEFT :: 0x93 +HID_USAGE_GENERIC_SYSCTL_FN :: 0x97 +HID_USAGE_GENERIC_SYSCTL_FN_LOCK :: 0x98 +HID_USAGE_GENERIC_SYSCTL_FN_LOCK_INDICATOR :: 0x99 +HID_USAGE_GENERIC_SYSCTL_DISMISS_NOTIFICATION :: 0x9A +HID_USAGE_GENERIC_SYSCTL_DOCK :: 0xA0 +HID_USAGE_GENERIC_SYSCTL_UNDOCK :: 0xA1 +HID_USAGE_GENERIC_SYSCTL_SETUP :: 0xA2 +HID_USAGE_GENERIC_SYSCTL_SYS_BREAK :: 0xA3 +HID_USAGE_GENERIC_SYSCTL_SYS_DBG_BREAK :: 0xA4 +HID_USAGE_GENERIC_SYSCTL_APP_BREAK :: 0xA5 +HID_USAGE_GENERIC_SYSCTL_APP_DBG_BREAK :: 0xA6 +HID_USAGE_GENERIC_SYSCTL_MUTE :: 0xA7 +HID_USAGE_GENERIC_SYSCTL_HIBERNATE :: 0xA8 +HID_USAGE_GENERIC_SYSCTL_DISP_INVERT :: 0xB0 +HID_USAGE_GENERIC_SYSCTL_DISP_INTERNAL :: 0xB1 +HID_USAGE_GENERIC_SYSCTL_DISP_EXTERNAL :: 0xB2 +HID_USAGE_GENERIC_SYSCTL_DISP_BOTH :: 0xB3 +HID_USAGE_GENERIC_SYSCTL_DISP_DUAL :: 0xB4 +HID_USAGE_GENERIC_SYSCTL_DISP_TOGGLE :: 0xB5 +HID_USAGE_GENERIC_SYSCTL_DISP_SWAP :: 0xB6 +HID_USAGE_GENERIC_SYSCTL_DISP_AUTOSCALE :: 0xB7 +HID_USAGE_GENERIC_SYSTEM_DISPLAY_ROTATION_LOCK_BUTTON :: 0xC9 HID_USAGE_GENERIC_SYSTEM_DISPLAY_ROTATION_LOCK_SLIDER_SWITCH :: 0xCA -HID_USAGE_GENERIC_CONTROL_ENABLE :: 0xCB +HID_USAGE_GENERIC_CONTROL_ENABLE :: 0xCB -HID_USAGE_SIMULATION_FLIGHT_SIMULATION_DEVICE :: 0x01 -HID_USAGE_SIMULATION_AUTOMOBILE_SIMULATION_DEVICE :: 0x02 -HID_USAGE_SIMULATION_TANK_SIMULATION_DEVICE :: 0x03 -HID_USAGE_SIMULATION_SPACESHIP_SIMULATION_DEVICE :: 0x04 -HID_USAGE_SIMULATION_SUBMARINE_SIMULATION_DEVICE :: 0x05 -HID_USAGE_SIMULATION_SAILING_SIMULATION_DEVICE :: 0x06 -HID_USAGE_SIMULATION_MOTORCYCLE_SIMULATION_DEVICE :: 0x07 -HID_USAGE_SIMULATION_SPORTS_SIMULATION_DEVICE :: 0x08 -HID_USAGE_SIMULATION_AIRPLANE_SIMULATION_DEVICE :: 0x09 -HID_USAGE_SIMULATION_HELICOPTER_SIMULATION_DEVICE :: 0x0A +HID_USAGE_SIMULATION_FLIGHT_SIMULATION_DEVICE :: 0x01 +HID_USAGE_SIMULATION_AUTOMOBILE_SIMULATION_DEVICE :: 0x02 +HID_USAGE_SIMULATION_TANK_SIMULATION_DEVICE :: 0x03 +HID_USAGE_SIMULATION_SPACESHIP_SIMULATION_DEVICE :: 0x04 +HID_USAGE_SIMULATION_SUBMARINE_SIMULATION_DEVICE :: 0x05 +HID_USAGE_SIMULATION_SAILING_SIMULATION_DEVICE :: 0x06 +HID_USAGE_SIMULATION_MOTORCYCLE_SIMULATION_DEVICE :: 0x07 +HID_USAGE_SIMULATION_SPORTS_SIMULATION_DEVICE :: 0x08 +HID_USAGE_SIMULATION_AIRPLANE_SIMULATION_DEVICE :: 0x09 +HID_USAGE_SIMULATION_HELICOPTER_SIMULATION_DEVICE :: 0x0A HID_USAGE_SIMULATION_MAGIC_CARPET_SIMULATION_DEVICE :: 0x0B -HID_USAGE_SIMULATION_BICYCLE_SIMULATION_DEVICE :: 0x0C -HID_USAGE_SIMULATION_FLIGHT_CONTROL_STICK :: 0x20 -HID_USAGE_SIMULATION_FLIGHT_STICK :: 0x21 -HID_USAGE_SIMULATION_CYCLIC_CONTROL :: 0x22 -HID_USAGE_SIMULATION_CYCLIC_TRIM :: 0x23 -HID_USAGE_SIMULATION_FLIGHT_YOKE :: 0x24 -HID_USAGE_SIMULATION_TRACK_CONTROL :: 0x25 +HID_USAGE_SIMULATION_BICYCLE_SIMULATION_DEVICE :: 0x0C +HID_USAGE_SIMULATION_FLIGHT_CONTROL_STICK :: 0x20 +HID_USAGE_SIMULATION_FLIGHT_STICK :: 0x21 +HID_USAGE_SIMULATION_CYCLIC_CONTROL :: 0x22 +HID_USAGE_SIMULATION_CYCLIC_TRIM :: 0x23 +HID_USAGE_SIMULATION_FLIGHT_YOKE :: 0x24 +HID_USAGE_SIMULATION_TRACK_CONTROL :: 0x25 -HID_USAGE_SIMULATION_AILERON :: 0xB0 -HID_USAGE_SIMULATION_AILERON_TRIM :: 0xB1 -HID_USAGE_SIMULATION_ANTI_TORQUE_CONTROL :: 0xB2 -HID_USAGE_SIMULATION_AUTOPIOLOT_ENABLE :: 0xB3 -HID_USAGE_SIMULATION_CHAFF_RELEASE :: 0xB4 -HID_USAGE_SIMULATION_COLLECTIVE_CONTROL :: 0xB5 -HID_USAGE_SIMULATION_DIVE_BRAKE :: 0xB6 +HID_USAGE_SIMULATION_AILERON :: 0xB0 +HID_USAGE_SIMULATION_AILERON_TRIM :: 0xB1 +HID_USAGE_SIMULATION_ANTI_TORQUE_CONTROL :: 0xB2 +HID_USAGE_SIMULATION_AUTOPIOLOT_ENABLE :: 0xB3 +HID_USAGE_SIMULATION_CHAFF_RELEASE :: 0xB4 +HID_USAGE_SIMULATION_COLLECTIVE_CONTROL :: 0xB5 +HID_USAGE_SIMULATION_DIVE_BRAKE :: 0xB6 HID_USAGE_SIMULATION_ELECTRONIC_COUNTERMEASURES :: 0xB7 -HID_USAGE_SIMULATION_ELEVATOR :: 0xB8 -HID_USAGE_SIMULATION_ELEVATOR_TRIM :: 0xB9 -HID_USAGE_SIMULATION_RUDDER :: 0xBA -HID_USAGE_SIMULATION_THROTTLE :: 0xBB -HID_USAGE_SIMULATION_FLIGHT_COMMUNICATIONS :: 0xBC -HID_USAGE_SIMULATION_FLARE_RELEASE :: 0xBD -HID_USAGE_SIMULATION_LANDING_GEAR :: 0xBE -HID_USAGE_SIMULATION_TOE_BRAKE :: 0xBF -HID_USAGE_SIMULATION_TRIGGER :: 0xC0 -HID_USAGE_SIMULATION_WEAPONS_ARM :: 0xC1 -HID_USAGE_SIMULATION_WEAPONS_SELECT :: 0xC2 -HID_USAGE_SIMULATION_WING_FLAPS :: 0xC3 -HID_USAGE_SIMULATION_ACCELLERATOR :: 0xC4 -HID_USAGE_SIMULATION_BRAKE :: 0xC5 -HID_USAGE_SIMULATION_CLUTCH :: 0xC6 -HID_USAGE_SIMULATION_SHIFTER :: 0xC7 -HID_USAGE_SIMULATION_STEERING :: 0xC8 -HID_USAGE_SIMULATION_TURRET_DIRECTION :: 0xC9 -HID_USAGE_SIMULATION_BARREL_ELEVATION :: 0xCA -HID_USAGE_SIMULATION_DIVE_PLANE :: 0xCB -HID_USAGE_SIMULATION_BALLAST :: 0xCC -HID_USAGE_SIMULATION_BICYCLE_CRANK :: 0xCD -HID_USAGE_SIMULATION_HANDLE_BARS :: 0xCE -HID_USAGE_SIMULATION_FRONT_BRAKE :: 0xCF -HID_USAGE_SIMULATION_REAR_BRAKE :: 0xD0 +HID_USAGE_SIMULATION_ELEVATOR :: 0xB8 +HID_USAGE_SIMULATION_ELEVATOR_TRIM :: 0xB9 +HID_USAGE_SIMULATION_RUDDER :: 0xBA +HID_USAGE_SIMULATION_THROTTLE :: 0xBB +HID_USAGE_SIMULATION_FLIGHT_COMMUNICATIONS :: 0xBC +HID_USAGE_SIMULATION_FLARE_RELEASE :: 0xBD +HID_USAGE_SIMULATION_LANDING_GEAR :: 0xBE +HID_USAGE_SIMULATION_TOE_BRAKE :: 0xBF +HID_USAGE_SIMULATION_TRIGGER :: 0xC0 +HID_USAGE_SIMULATION_WEAPONS_ARM :: 0xC1 +HID_USAGE_SIMULATION_WEAPONS_SELECT :: 0xC2 +HID_USAGE_SIMULATION_WING_FLAPS :: 0xC3 +HID_USAGE_SIMULATION_ACCELLERATOR :: 0xC4 +HID_USAGE_SIMULATION_BRAKE :: 0xC5 +HID_USAGE_SIMULATION_CLUTCH :: 0xC6 +HID_USAGE_SIMULATION_SHIFTER :: 0xC7 +HID_USAGE_SIMULATION_STEERING :: 0xC8 +HID_USAGE_SIMULATION_TURRET_DIRECTION :: 0xC9 +HID_USAGE_SIMULATION_BARREL_ELEVATION :: 0xCA +HID_USAGE_SIMULATION_DIVE_PLANE :: 0xCB +HID_USAGE_SIMULATION_BALLAST :: 0xCC +HID_USAGE_SIMULATION_BICYCLE_CRANK :: 0xCD +HID_USAGE_SIMULATION_HANDLE_BARS :: 0xCE +HID_USAGE_SIMULATION_FRONT_BRAKE :: 0xCF +HID_USAGE_SIMULATION_REAR_BRAKE :: 0xD0 -HID_USAGE_VR_BELT :: 0x01 -HID_USAGE_VR_BODY_SUIT :: 0x02 -HID_USAGE_VR_FLEXOR :: 0x03 -HID_USAGE_VR_GLOVE :: 0x04 -HID_USAGE_VR_HEAD_TRACKER :: 0x05 +HID_USAGE_VR_BELT :: 0x01 +HID_USAGE_VR_BODY_SUIT :: 0x02 +HID_USAGE_VR_FLEXOR :: 0x03 +HID_USAGE_VR_GLOVE :: 0x04 +HID_USAGE_VR_HEAD_TRACKER :: 0x05 HID_USAGE_VR_HEAD_MOUNTED_DISPLAY :: 0x06 -HID_USAGE_VR_HAND_TRACKER :: 0x07 -HID_USAGE_VR_OCULOMETER :: 0x08 -HID_USAGE_VR_VEST :: 0x09 -HID_USAGE_VR_ANIMATRONIC_DEVICE :: 0x0A +HID_USAGE_VR_HAND_TRACKER :: 0x07 +HID_USAGE_VR_OCULOMETER :: 0x08 +HID_USAGE_VR_VEST :: 0x09 +HID_USAGE_VR_ANIMATRONIC_DEVICE :: 0x0A -HID_USAGE_VR_STEREO_ENABLE :: 0x20 +HID_USAGE_VR_STEREO_ENABLE :: 0x20 HID_USAGE_VR_DISPLAY_ENABLE :: 0x21 -HID_USAGE_SPORT_BASEBALL_BAT :: 0x01 -HID_USAGE_SPORT_GOLF_CLUB :: 0x02 +HID_USAGE_SPORT_BASEBALL_BAT :: 0x01 +HID_USAGE_SPORT_GOLF_CLUB :: 0x02 HID_USAGE_SPORT_ROWING_MACHINE :: 0x03 -HID_USAGE_SPORT_TREADMILL :: 0x04 -HID_USAGE_SPORT_STICK_TYPE :: 0x38 +HID_USAGE_SPORT_TREADMILL :: 0x04 +HID_USAGE_SPORT_STICK_TYPE :: 0x38 -HID_USAGE_SPORT_OAR :: 0x30 -HID_USAGE_SPORT_SLOPE :: 0x31 -HID_USAGE_SPORT_RATE :: 0x32 -HID_USAGE_SPORT_STICK_SPEED :: 0x33 +HID_USAGE_SPORT_OAR :: 0x30 +HID_USAGE_SPORT_SLOPE :: 0x31 +HID_USAGE_SPORT_RATE :: 0x32 +HID_USAGE_SPORT_STICK_SPEED :: 0x33 HID_USAGE_SPORT_STICK_FACE_ANGLE :: 0x34 -HID_USAGE_SPORT_HEEL_TOE :: 0x35 -HID_USAGE_SPORT_FOLLOW_THROUGH :: 0x36 -HID_USAGE_SPORT_TEMPO :: 0x37 -HID_USAGE_SPORT_HEIGHT :: 0x39 -HID_USAGE_SPORT_PUTTER :: 0x50 -HID_USAGE_SPORT_1_IRON :: 0x51 -HID_USAGE_SPORT_2_IRON :: 0x52 -HID_USAGE_SPORT_3_IRON :: 0x53 -HID_USAGE_SPORT_4_IRON :: 0x54 -HID_USAGE_SPORT_5_IRON :: 0x55 -HID_USAGE_SPORT_6_IRON :: 0x56 -HID_USAGE_SPORT_7_IRON :: 0x57 -HID_USAGE_SPORT_8_IRON :: 0x58 -HID_USAGE_SPORT_9_IRON :: 0x59 -HID_USAGE_SPORT_10_IRON :: 0x5A -HID_USAGE_SPORT_11_IRON :: 0x5B -HID_USAGE_SPORT_SAND_WEDGE :: 0x5C -HID_USAGE_SPORT_LOFT_WEDGE :: 0x5D -HID_USAGE_SPORT_POWER_WEDGE :: 0x5E -HID_USAGE_SPORT_1_WOOD :: 0x5F -HID_USAGE_SPORT_3_WOOD :: 0x60 -HID_USAGE_SPORT_5_WOOD :: 0x61 -HID_USAGE_SPORT_7_WOOD :: 0x62 -HID_USAGE_SPORT_9_WOOD :: 0x63 +HID_USAGE_SPORT_HEEL_TOE :: 0x35 +HID_USAGE_SPORT_FOLLOW_THROUGH :: 0x36 +HID_USAGE_SPORT_TEMPO :: 0x37 +HID_USAGE_SPORT_HEIGHT :: 0x39 +HID_USAGE_SPORT_PUTTER :: 0x50 +HID_USAGE_SPORT_1_IRON :: 0x51 +HID_USAGE_SPORT_2_IRON :: 0x52 +HID_USAGE_SPORT_3_IRON :: 0x53 +HID_USAGE_SPORT_4_IRON :: 0x54 +HID_USAGE_SPORT_5_IRON :: 0x55 +HID_USAGE_SPORT_6_IRON :: 0x56 +HID_USAGE_SPORT_7_IRON :: 0x57 +HID_USAGE_SPORT_8_IRON :: 0x58 +HID_USAGE_SPORT_9_IRON :: 0x59 +HID_USAGE_SPORT_10_IRON :: 0x5A +HID_USAGE_SPORT_11_IRON :: 0x5B +HID_USAGE_SPORT_SAND_WEDGE :: 0x5C +HID_USAGE_SPORT_LOFT_WEDGE :: 0x5D +HID_USAGE_SPORT_POWER_WEDGE :: 0x5E +HID_USAGE_SPORT_1_WOOD :: 0x5F +HID_USAGE_SPORT_3_WOOD :: 0x60 +HID_USAGE_SPORT_5_WOOD :: 0x61 +HID_USAGE_SPORT_7_WOOD :: 0x62 +HID_USAGE_SPORT_9_WOOD :: 0x63 HID_USAGE_GAME_3D_GAME_CONTROLLER :: 0x01 -HID_USAGE_GAME_PINBALL_DEVICE :: 0x02 -HID_USAGE_GAME_GUN_DEVICE :: 0x03 -HID_USAGE_GAME_POINT_OF_VIEW :: 0x20 -HID_USAGE_GAME_GUN_SELECTOR :: 0x32 -HID_USAGE_GAME_GAMEPAD_FIRE_JUMP :: 0x37 -HID_USAGE_GAME_GAMEPAD_TRIGGER :: 0x39 +HID_USAGE_GAME_PINBALL_DEVICE :: 0x02 +HID_USAGE_GAME_GUN_DEVICE :: 0x03 +HID_USAGE_GAME_POINT_OF_VIEW :: 0x20 +HID_USAGE_GAME_GUN_SELECTOR :: 0x32 +HID_USAGE_GAME_GAMEPAD_FIRE_JUMP :: 0x37 +HID_USAGE_GAME_GAMEPAD_TRIGGER :: 0x39 -HID_USAGE_GAME_TURN_RIGHT_LEFT :: 0x21 +HID_USAGE_GAME_TURN_RIGHT_LEFT :: 0x21 HID_USAGE_GAME_PITCH_FORWARD_BACK :: 0x22 -HID_USAGE_GAME_ROLL_RIGHT_LEFT :: 0x23 -HID_USAGE_GAME_MOVE_RIGHT_LEFT :: 0x24 -HID_USAGE_GAME_MOVE_FORWARD_BACK :: 0x25 -HID_USAGE_GAME_MOVE_UP_DOWN :: 0x26 -HID_USAGE_GAME_LEAN_RIGHT_LEFT :: 0x27 -HID_USAGE_GAME_LEAN_FORWARD_BACK :: 0x28 -HID_USAGE_GAME_POV_HEIGHT :: 0x29 -HID_USAGE_GAME_FLIPPER :: 0x2A -HID_USAGE_GAME_SECONDARY_FLIPPER :: 0x2B -HID_USAGE_GAME_BUMP :: 0x2C -HID_USAGE_GAME_NEW_GAME :: 0x2D -HID_USAGE_GAME_SHOOT_BALL :: 0x2E -HID_USAGE_GAME_PLAYER :: 0x2F -HID_USAGE_GAME_GUN_BOLT :: 0x30 -HID_USAGE_GAME_GUN_CLIP :: 0x31 -HID_USAGE_GAME_GUN_SINGLE_SHOT :: 0x33 -HID_USAGE_GAME_GUN_BURST :: 0x34 -HID_USAGE_GAME_GUN_AUTOMATIC :: 0x35 -HID_USAGE_GAME_GUN_SAFETY :: 0x36 +HID_USAGE_GAME_ROLL_RIGHT_LEFT :: 0x23 +HID_USAGE_GAME_MOVE_RIGHT_LEFT :: 0x24 +HID_USAGE_GAME_MOVE_FORWARD_BACK :: 0x25 +HID_USAGE_GAME_MOVE_UP_DOWN :: 0x26 +HID_USAGE_GAME_LEAN_RIGHT_LEFT :: 0x27 +HID_USAGE_GAME_LEAN_FORWARD_BACK :: 0x28 +HID_USAGE_GAME_POV_HEIGHT :: 0x29 +HID_USAGE_GAME_FLIPPER :: 0x2A +HID_USAGE_GAME_SECONDARY_FLIPPER :: 0x2B +HID_USAGE_GAME_BUMP :: 0x2C +HID_USAGE_GAME_NEW_GAME :: 0x2D +HID_USAGE_GAME_SHOOT_BALL :: 0x2E +HID_USAGE_GAME_PLAYER :: 0x2F +HID_USAGE_GAME_GUN_BOLT :: 0x30 +HID_USAGE_GAME_GUN_CLIP :: 0x31 +HID_USAGE_GAME_GUN_SINGLE_SHOT :: 0x33 +HID_USAGE_GAME_GUN_BURST :: 0x34 +HID_USAGE_GAME_GUN_AUTOMATIC :: 0x35 +HID_USAGE_GAME_GUN_SAFETY :: 0x36 -HID_USAGE_GENERIC_DEVICE_BATTERY_STRENGTH :: 0x20 -HID_USAGE_GENERIC_DEVICE_WIRELESS_CHANNEL :: 0x21 -HID_USAGE_GENERIC_DEVICE_WIRELESS_ID :: 0x22 -HID_USAGE_GENERIC_DEVICE_DISCOVER_WIRELESS_CONTROL :: 0x23 +HID_USAGE_GENERIC_DEVICE_BATTERY_STRENGTH :: 0x20 +HID_USAGE_GENERIC_DEVICE_WIRELESS_CHANNEL :: 0x21 +HID_USAGE_GENERIC_DEVICE_WIRELESS_ID :: 0x22 +HID_USAGE_GENERIC_DEVICE_DISCOVER_WIRELESS_CONTROL :: 0x23 HID_USAGE_GENERIC_DEVICE_SECURITY_CODE_CHAR_ENTERED :: 0x24 -HID_USAGE_GENERIC_DEVICE_SECURITY_CODE_CHAR_ERASED :: 0x25 -HID_USAGE_GENERIC_DEVICE_SECURITY_CODE_CLEARED :: 0x26 +HID_USAGE_GENERIC_DEVICE_SECURITY_CODE_CHAR_ERASED :: 0x25 +HID_USAGE_GENERIC_DEVICE_SECURITY_CODE_CLEARED :: 0x26 // Error "keys" -HID_USAGE_KEYBOARD_NOEVENT :: 0x00 -HID_USAGE_KEYBOARD_ROLLOVER :: 0x01 -HID_USAGE_KEYBOARD_POSTFAIL :: 0x02 +HID_USAGE_KEYBOARD_NOEVENT :: 0x00 +HID_USAGE_KEYBOARD_ROLLOVER :: 0x01 +HID_USAGE_KEYBOARD_POSTFAIL :: 0x02 HID_USAGE_KEYBOARD_UNDEFINED :: 0x03 // Letters @@ -265,32 +265,32 @@ HID_USAGE_KEYBOARD_aA :: 0x04 HID_USAGE_KEYBOARD_zZ :: 0x1D // Numbers -HID_USAGE_KEYBOARD_ONE :: 0x1E +HID_USAGE_KEYBOARD_ONE :: 0x1E HID_USAGE_KEYBOARD_ZERO :: 0x27 // Modifier Keys -HID_USAGE_KEYBOARD_LCTRL :: 0xE0 -HID_USAGE_KEYBOARD_LSHFT :: 0xE1 -HID_USAGE_KEYBOARD_LALT :: 0xE2 -HID_USAGE_KEYBOARD_LGUI :: 0xE3 -HID_USAGE_KEYBOARD_RCTRL :: 0xE4 -HID_USAGE_KEYBOARD_RSHFT :: 0xE5 -HID_USAGE_KEYBOARD_RALT :: 0xE6 -HID_USAGE_KEYBOARD_RGUI :: 0xE7 +HID_USAGE_KEYBOARD_LCTRL :: 0xE0 +HID_USAGE_KEYBOARD_LSHFT :: 0xE1 +HID_USAGE_KEYBOARD_LALT :: 0xE2 +HID_USAGE_KEYBOARD_LGUI :: 0xE3 +HID_USAGE_KEYBOARD_RCTRL :: 0xE4 +HID_USAGE_KEYBOARD_RSHFT :: 0xE5 +HID_USAGE_KEYBOARD_RALT :: 0xE6 +HID_USAGE_KEYBOARD_RGUI :: 0xE7 HID_USAGE_KEYBOARD_SCROLL_LOCK :: 0x47 -HID_USAGE_KEYBOARD_NUM_LOCK :: 0x53 -HID_USAGE_KEYBOARD_CAPS_LOCK :: 0x39 +HID_USAGE_KEYBOARD_NUM_LOCK :: 0x53 +HID_USAGE_KEYBOARD_CAPS_LOCK :: 0x39 // Function keys -HID_USAGE_KEYBOARD_F1 :: 0x3A -HID_USAGE_KEYBOARD_F2 :: 0x3B -HID_USAGE_KEYBOARD_F3 :: 0x3C -HID_USAGE_KEYBOARD_F4 :: 0x3D -HID_USAGE_KEYBOARD_F5 :: 0x3E -HID_USAGE_KEYBOARD_F6 :: 0x3F -HID_USAGE_KEYBOARD_F7 :: 0x40 -HID_USAGE_KEYBOARD_F8 :: 0x41 -HID_USAGE_KEYBOARD_F9 :: 0x42 +HID_USAGE_KEYBOARD_F1 :: 0x3A +HID_USAGE_KEYBOARD_F2 :: 0x3B +HID_USAGE_KEYBOARD_F3 :: 0x3C +HID_USAGE_KEYBOARD_F4 :: 0x3D +HID_USAGE_KEYBOARD_F5 :: 0x3E +HID_USAGE_KEYBOARD_F6 :: 0x3F +HID_USAGE_KEYBOARD_F7 :: 0x40 +HID_USAGE_KEYBOARD_F8 :: 0x41 +HID_USAGE_KEYBOARD_F9 :: 0x42 HID_USAGE_KEYBOARD_F10 :: 0x43 HID_USAGE_KEYBOARD_F11 :: 0x44 HID_USAGE_KEYBOARD_F12 :: 0x45 @@ -315,103 +315,103 @@ HID_USAGE_KEYBOARD_PRINT_SCREEN :: 0x46 HID_USAGE_KEYBOARD_DELETE_FORWARD :: 0x4C // Numeric Keypad -HID_USAGE_KEYBOARD_KEYPAD_1_AND_END :: 0x59 +HID_USAGE_KEYBOARD_KEYPAD_1_AND_END :: 0x59 HID_USAGE_KEYBOARD_KEYPAD_0_AND_INSERT :: 0x62 -HID_USAGE_LED_NUM_LOCK :: 0x01 -HID_USAGE_LED_CAPS_LOCK :: 0x02 -HID_USAGE_LED_SCROLL_LOCK :: 0x03 -HID_USAGE_LED_COMPOSE :: 0x04 -HID_USAGE_LED_KANA :: 0x05 -HID_USAGE_LED_POWER :: 0x06 -HID_USAGE_LED_SHIFT :: 0x07 -HID_USAGE_LED_DO_NOT_DISTURB :: 0x08 -HID_USAGE_LED_MUTE :: 0x09 -HID_USAGE_LED_TONE_ENABLE :: 0x0A -HID_USAGE_LED_HIGH_CUT_FILTER :: 0x0B -HID_USAGE_LED_LOW_CUT_FILTER :: 0x0C -HID_USAGE_LED_EQUALIZER_ENABLE :: 0x0D -HID_USAGE_LED_SOUND_FIELD_ON :: 0x0E -HID_USAGE_LED_SURROUND_FIELD_ON :: 0x0F -HID_USAGE_LED_REPEAT :: 0x10 -HID_USAGE_LED_STEREO :: 0x11 +HID_USAGE_LED_NUM_LOCK :: 0x01 +HID_USAGE_LED_CAPS_LOCK :: 0x02 +HID_USAGE_LED_SCROLL_LOCK :: 0x03 +HID_USAGE_LED_COMPOSE :: 0x04 +HID_USAGE_LED_KANA :: 0x05 +HID_USAGE_LED_POWER :: 0x06 +HID_USAGE_LED_SHIFT :: 0x07 +HID_USAGE_LED_DO_NOT_DISTURB :: 0x08 +HID_USAGE_LED_MUTE :: 0x09 +HID_USAGE_LED_TONE_ENABLE :: 0x0A +HID_USAGE_LED_HIGH_CUT_FILTER :: 0x0B +HID_USAGE_LED_LOW_CUT_FILTER :: 0x0C +HID_USAGE_LED_EQUALIZER_ENABLE :: 0x0D +HID_USAGE_LED_SOUND_FIELD_ON :: 0x0E +HID_USAGE_LED_SURROUND_FIELD_ON :: 0x0F +HID_USAGE_LED_REPEAT :: 0x10 +HID_USAGE_LED_STEREO :: 0x11 HID_USAGE_LED_SAMPLING_RATE_DETECT :: 0x12 -HID_USAGE_LED_SPINNING :: 0x13 -HID_USAGE_LED_CAV :: 0x14 -HID_USAGE_LED_CLV :: 0x15 +HID_USAGE_LED_SPINNING :: 0x13 +HID_USAGE_LED_CAV :: 0x14 +HID_USAGE_LED_CLV :: 0x15 HID_USAGE_LED_RECORDING_FORMAT_DET :: 0x16 -HID_USAGE_LED_OFF_HOOK :: 0x17 -HID_USAGE_LED_RING :: 0x18 -HID_USAGE_LED_MESSAGE_WAITING :: 0x19 -HID_USAGE_LED_DATA_MODE :: 0x1A -HID_USAGE_LED_BATTERY_OPERATION :: 0x1B -HID_USAGE_LED_BATTERY_OK :: 0x1C -HID_USAGE_LED_BATTERY_LOW :: 0x1D -HID_USAGE_LED_SPEAKER :: 0x1E -HID_USAGE_LED_HEAD_SET :: 0x1F -HID_USAGE_LED_HOLD :: 0x20 -HID_USAGE_LED_MICROPHONE :: 0x21 -HID_USAGE_LED_COVERAGE :: 0x22 -HID_USAGE_LED_NIGHT_MODE :: 0x23 -HID_USAGE_LED_SEND_CALLS :: 0x24 -HID_USAGE_LED_CALL_PICKUP :: 0x25 -HID_USAGE_LED_CONFERENCE :: 0x26 -HID_USAGE_LED_STAND_BY :: 0x27 -HID_USAGE_LED_CAMERA_ON :: 0x28 -HID_USAGE_LED_CAMERA_OFF :: 0x29 -HID_USAGE_LED_ON_LINE :: 0x2A -HID_USAGE_LED_OFF_LINE :: 0x2B -HID_USAGE_LED_BUSY :: 0x2C -HID_USAGE_LED_READY :: 0x2D -HID_USAGE_LED_PAPER_OUT :: 0x2E -HID_USAGE_LED_PAPER_JAM :: 0x2F -HID_USAGE_LED_REMOTE :: 0x30 -HID_USAGE_LED_FORWARD :: 0x31 -HID_USAGE_LED_REVERSE :: 0x32 -HID_USAGE_LED_STOP :: 0x33 -HID_USAGE_LED_REWIND :: 0x34 -HID_USAGE_LED_FAST_FORWARD :: 0x35 -HID_USAGE_LED_PLAY :: 0x36 -HID_USAGE_LED_PAUSE :: 0x37 -HID_USAGE_LED_RECORD :: 0x38 -HID_USAGE_LED_ERROR :: 0x39 -HID_USAGE_LED_SELECTED_INDICATOR :: 0x3A -HID_USAGE_LED_IN_USE_INDICATOR :: 0x3B +HID_USAGE_LED_OFF_HOOK :: 0x17 +HID_USAGE_LED_RING :: 0x18 +HID_USAGE_LED_MESSAGE_WAITING :: 0x19 +HID_USAGE_LED_DATA_MODE :: 0x1A +HID_USAGE_LED_BATTERY_OPERATION :: 0x1B +HID_USAGE_LED_BATTERY_OK :: 0x1C +HID_USAGE_LED_BATTERY_LOW :: 0x1D +HID_USAGE_LED_SPEAKER :: 0x1E +HID_USAGE_LED_HEAD_SET :: 0x1F +HID_USAGE_LED_HOLD :: 0x20 +HID_USAGE_LED_MICROPHONE :: 0x21 +HID_USAGE_LED_COVERAGE :: 0x22 +HID_USAGE_LED_NIGHT_MODE :: 0x23 +HID_USAGE_LED_SEND_CALLS :: 0x24 +HID_USAGE_LED_CALL_PICKUP :: 0x25 +HID_USAGE_LED_CONFERENCE :: 0x26 +HID_USAGE_LED_STAND_BY :: 0x27 +HID_USAGE_LED_CAMERA_ON :: 0x28 +HID_USAGE_LED_CAMERA_OFF :: 0x29 +HID_USAGE_LED_ON_LINE :: 0x2A +HID_USAGE_LED_OFF_LINE :: 0x2B +HID_USAGE_LED_BUSY :: 0x2C +HID_USAGE_LED_READY :: 0x2D +HID_USAGE_LED_PAPER_OUT :: 0x2E +HID_USAGE_LED_PAPER_JAM :: 0x2F +HID_USAGE_LED_REMOTE :: 0x30 +HID_USAGE_LED_FORWARD :: 0x31 +HID_USAGE_LED_REVERSE :: 0x32 +HID_USAGE_LED_STOP :: 0x33 +HID_USAGE_LED_REWIND :: 0x34 +HID_USAGE_LED_FAST_FORWARD :: 0x35 +HID_USAGE_LED_PLAY :: 0x36 +HID_USAGE_LED_PAUSE :: 0x37 +HID_USAGE_LED_RECORD :: 0x38 +HID_USAGE_LED_ERROR :: 0x39 +HID_USAGE_LED_SELECTED_INDICATOR :: 0x3A +HID_USAGE_LED_IN_USE_INDICATOR :: 0x3B HID_USAGE_LED_MULTI_MODE_INDICATOR :: 0x3C -HID_USAGE_LED_INDICATOR_ON :: 0x3D -HID_USAGE_LED_INDICATOR_FLASH :: 0x3E +HID_USAGE_LED_INDICATOR_ON :: 0x3D +HID_USAGE_LED_INDICATOR_FLASH :: 0x3E HID_USAGE_LED_INDICATOR_SLOW_BLINK :: 0x3F HID_USAGE_LED_INDICATOR_FAST_BLINK :: 0x40 -HID_USAGE_LED_INDICATOR_OFF :: 0x41 -HID_USAGE_LED_FLASH_ON_TIME :: 0x42 -HID_USAGE_LED_SLOW_BLINK_ON_TIME :: 0x43 -HID_USAGE_LED_SLOW_BLINK_OFF_TIME :: 0x44 -HID_USAGE_LED_FAST_BLINK_ON_TIME :: 0x45 -HID_USAGE_LED_FAST_BLINK_OFF_TIME :: 0x46 -HID_USAGE_LED_INDICATOR_COLOR :: 0x47 -HID_USAGE_LED_RED :: 0x48 -HID_USAGE_LED_GREEN :: 0x49 -HID_USAGE_LED_AMBER :: 0x4A -HID_USAGE_LED_GENERIC_INDICATOR :: 0x4B -HID_USAGE_LED_SYSTEM_SUSPEND :: 0x4C -HID_USAGE_LED_EXTERNAL_POWER :: 0x4D +HID_USAGE_LED_INDICATOR_OFF :: 0x41 +HID_USAGE_LED_FLASH_ON_TIME :: 0x42 +HID_USAGE_LED_SLOW_BLINK_ON_TIME :: 0x43 +HID_USAGE_LED_SLOW_BLINK_OFF_TIME :: 0x44 +HID_USAGE_LED_FAST_BLINK_ON_TIME :: 0x45 +HID_USAGE_LED_FAST_BLINK_OFF_TIME :: 0x46 +HID_USAGE_LED_INDICATOR_COLOR :: 0x47 +HID_USAGE_LED_RED :: 0x48 +HID_USAGE_LED_GREEN :: 0x49 +HID_USAGE_LED_AMBER :: 0x4A +HID_USAGE_LED_GENERIC_INDICATOR :: 0x4B +HID_USAGE_LED_SYSTEM_SUSPEND :: 0x4C +HID_USAGE_LED_EXTERNAL_POWER :: 0x4D -HID_USAGE_TELEPHONY_PHONE :: 0x01 -HID_USAGE_TELEPHONY_ANSWERING_MACHINE :: 0x02 -HID_USAGE_TELEPHONY_MESSAGE_CONTROLS :: 0x03 -HID_USAGE_TELEPHONY_HANDSET :: 0x04 -HID_USAGE_TELEPHONY_HEADSET :: 0x05 -HID_USAGE_TELEPHONY_KEYPAD :: 0x06 +HID_USAGE_TELEPHONY_PHONE :: 0x01 +HID_USAGE_TELEPHONY_ANSWERING_MACHINE :: 0x02 +HID_USAGE_TELEPHONY_MESSAGE_CONTROLS :: 0x03 +HID_USAGE_TELEPHONY_HANDSET :: 0x04 +HID_USAGE_TELEPHONY_HEADSET :: 0x05 +HID_USAGE_TELEPHONY_KEYPAD :: 0x06 HID_USAGE_TELEPHONY_PROGRAMMABLE_BUTTON :: 0x07 -HID_USAGE_TELEPHONY_REDIAL :: 0x24 -HID_USAGE_TELEPHONY_TRANSFER :: 0x25 -HID_USAGE_TELEPHONY_DROP :: 0x26 -HID_USAGE_TELEPHONY_LINE :: 0x2A -HID_USAGE_TELEPHONY_RING_ENABLE :: 0x2D -HID_USAGE_TELEPHONY_SEND :: 0x31 -HID_USAGE_TELEPHONY_KEYPAD_0 :: 0xB0 -HID_USAGE_TELEPHONY_KEYPAD_D :: 0xBF -HID_USAGE_TELEPHONY_HOST_AVAILABLE :: 0xF1 +HID_USAGE_TELEPHONY_REDIAL :: 0x24 +HID_USAGE_TELEPHONY_TRANSFER :: 0x25 +HID_USAGE_TELEPHONY_DROP :: 0x26 +HID_USAGE_TELEPHONY_LINE :: 0x2A +HID_USAGE_TELEPHONY_RING_ENABLE :: 0x2D +HID_USAGE_TELEPHONY_SEND :: 0x31 +HID_USAGE_TELEPHONY_KEYPAD_0 :: 0xB0 +HID_USAGE_TELEPHONY_KEYPAD_D :: 0xBF +HID_USAGE_TELEPHONY_HOST_AVAILABLE :: 0xF1 HID_USAGE_CONSUMERCTRL :: 0x01 @@ -420,271 +420,271 @@ HID_USAGE_CONSUMER_CHANNEL_INCREMENT :: 0x9C HID_USAGE_CONSUMER_CHANNEL_DECREMENT :: 0x9D // transport control -HID_USAGE_CONSUMER_PLAY :: 0xB0 -HID_USAGE_CONSUMER_PAUSE :: 0xB1 -HID_USAGE_CONSUMER_RECORD :: 0xB2 -HID_USAGE_CONSUMER_FAST_FORWARD :: 0xB3 -HID_USAGE_CONSUMER_REWIND :: 0xB4 +HID_USAGE_CONSUMER_PLAY :: 0xB0 +HID_USAGE_CONSUMER_PAUSE :: 0xB1 +HID_USAGE_CONSUMER_RECORD :: 0xB2 +HID_USAGE_CONSUMER_FAST_FORWARD :: 0xB3 +HID_USAGE_CONSUMER_REWIND :: 0xB4 HID_USAGE_CONSUMER_SCAN_NEXT_TRACK :: 0xB5 HID_USAGE_CONSUMER_SCAN_PREV_TRACK :: 0xB6 -HID_USAGE_CONSUMER_STOP :: 0xB7 -HID_USAGE_CONSUMER_PLAY_PAUSE :: 0xCD +HID_USAGE_CONSUMER_STOP :: 0xB7 +HID_USAGE_CONSUMER_PLAY_PAUSE :: 0xCD // GameDVR -HID_USAGE_CONSUMER_GAMEDVR_OPEN_GAMEBAR :: 0xD0 -HID_USAGE_CONSUMER_GAMEDVR_TOGGLE_RECORD :: 0xD1 -HID_USAGE_CONSUMER_GAMEDVR_RECORD_CLIP :: 0xD2 -HID_USAGE_CONSUMER_GAMEDVR_SCREENSHOT :: 0xD3 -HID_USAGE_CONSUMER_GAMEDVR_TOGGLE_INDICATOR :: 0xD4 +HID_USAGE_CONSUMER_GAMEDVR_OPEN_GAMEBAR :: 0xD0 +HID_USAGE_CONSUMER_GAMEDVR_TOGGLE_RECORD :: 0xD1 +HID_USAGE_CONSUMER_GAMEDVR_RECORD_CLIP :: 0xD2 +HID_USAGE_CONSUMER_GAMEDVR_SCREENSHOT :: 0xD3 +HID_USAGE_CONSUMER_GAMEDVR_TOGGLE_INDICATOR :: 0xD4 HID_USAGE_CONSUMER_GAMEDVR_TOGGLE_MICROPHONE :: 0xD5 -HID_USAGE_CONSUMER_GAMEDVR_TOGGLE_CAMERA :: 0xD6 -HID_USAGE_CONSUMER_GAMEDVR_TOGGLE_BROADCAST :: 0xD7 +HID_USAGE_CONSUMER_GAMEDVR_TOGGLE_CAMERA :: 0xD6 +HID_USAGE_CONSUMER_GAMEDVR_TOGGLE_BROADCAST :: 0xD7 // audio -HID_USAGE_CONSUMER_VOLUME :: 0xE0 -HID_USAGE_CONSUMER_BALANCE :: 0xE1 -HID_USAGE_CONSUMER_MUTE :: 0xE2 -HID_USAGE_CONSUMER_BASS :: 0xE3 -HID_USAGE_CONSUMER_TREBLE :: 0xE4 -HID_USAGE_CONSUMER_BASS_BOOST :: 0xE5 -HID_USAGE_CONSUMER_SURROUND_MODE :: 0xE6 -HID_USAGE_CONSUMER_LOUDNESS :: 0xE7 -HID_USAGE_CONSUMER_MPX :: 0xE8 +HID_USAGE_CONSUMER_VOLUME :: 0xE0 +HID_USAGE_CONSUMER_BALANCE :: 0xE1 +HID_USAGE_CONSUMER_MUTE :: 0xE2 +HID_USAGE_CONSUMER_BASS :: 0xE3 +HID_USAGE_CONSUMER_TREBLE :: 0xE4 +HID_USAGE_CONSUMER_BASS_BOOST :: 0xE5 +HID_USAGE_CONSUMER_SURROUND_MODE :: 0xE6 +HID_USAGE_CONSUMER_LOUDNESS :: 0xE7 +HID_USAGE_CONSUMER_MPX :: 0xE8 HID_USAGE_CONSUMER_VOLUME_INCREMENT :: 0xE9 HID_USAGE_CONSUMER_VOLUME_DECREMENT :: 0xEA // supplementary audio -HID_USAGE_CONSUMER_BASS_INCREMENT :: 0x152 -HID_USAGE_CONSUMER_BASS_DECREMENT :: 0x153 +HID_USAGE_CONSUMER_BASS_INCREMENT :: 0x152 +HID_USAGE_CONSUMER_BASS_DECREMENT :: 0x153 HID_USAGE_CONSUMER_TREBLE_INCREMENT :: 0x154 HID_USAGE_CONSUMER_TREBLE_DECREMENT :: 0x155 // Application Launch HID_USAGE_CONSUMER_AL_CONFIGURATION :: 0x183 -HID_USAGE_CONSUMER_AL_EMAIL :: 0x18A -HID_USAGE_CONSUMER_AL_CALCULATOR :: 0x192 -HID_USAGE_CONSUMER_AL_BROWSER :: 0x194 -HID_USAGE_CONSUMER_AL_SEARCH :: 0x1C6 +HID_USAGE_CONSUMER_AL_EMAIL :: 0x18A +HID_USAGE_CONSUMER_AL_CALCULATOR :: 0x192 +HID_USAGE_CONSUMER_AL_BROWSER :: 0x194 +HID_USAGE_CONSUMER_AL_SEARCH :: 0x1C6 // Application Control -HID_USAGE_CONSUMER_AC_SEARCH :: 0x221 -HID_USAGE_CONSUMER_AC_GOTO :: 0x222 -HID_USAGE_CONSUMER_AC_HOME :: 0x223 -HID_USAGE_CONSUMER_AC_BACK :: 0x224 -HID_USAGE_CONSUMER_AC_FORWARD :: 0x225 -HID_USAGE_CONSUMER_AC_STOP :: 0x226 -HID_USAGE_CONSUMER_AC_REFRESH :: 0x227 -HID_USAGE_CONSUMER_AC_PREVIOUS :: 0x228 -HID_USAGE_CONSUMER_AC_NEXT :: 0x229 +HID_USAGE_CONSUMER_AC_SEARCH :: 0x221 +HID_USAGE_CONSUMER_AC_GOTO :: 0x222 +HID_USAGE_CONSUMER_AC_HOME :: 0x223 +HID_USAGE_CONSUMER_AC_BACK :: 0x224 +HID_USAGE_CONSUMER_AC_FORWARD :: 0x225 +HID_USAGE_CONSUMER_AC_STOP :: 0x226 +HID_USAGE_CONSUMER_AC_REFRESH :: 0x227 +HID_USAGE_CONSUMER_AC_PREVIOUS :: 0x228 +HID_USAGE_CONSUMER_AC_NEXT :: 0x229 HID_USAGE_CONSUMER_AC_BOOKMARKS :: 0x22A -HID_USAGE_CONSUMER_AC_PAN :: 0x238 +HID_USAGE_CONSUMER_AC_PAN :: 0x238 // Keyboard Extended Attributes (defined on consumer page in HUTRR42) -HID_USAGE_CONSUMER_EXTENDED_KEYBOARD_ATTRIBUTES_COLLECTION :: 0x2C0 -HID_USAGE_CONSUMER_KEYBOARD_FORM_FACTOR :: 0x2C1 -HID_USAGE_CONSUMER_KEYBOARD_KEY_TYPE :: 0x2C2 -HID_USAGE_CONSUMER_KEYBOARD_PHYSICAL_LAYOUT :: 0x2C3 -HID_USAGE_CONSUMER_VENDOR_SPECIFIC_KEYBOARD_PHYSICAL_LAYOUT :: 0x2C4 -HID_USAGE_CONSUMER_KEYBOARD_IETF_LANGUAGE_TAG_INDEX :: 0x2C5 +HID_USAGE_CONSUMER_EXTENDED_KEYBOARD_ATTRIBUTES_COLLECTION :: 0x2C0 +HID_USAGE_CONSUMER_KEYBOARD_FORM_FACTOR :: 0x2C1 +HID_USAGE_CONSUMER_KEYBOARD_KEY_TYPE :: 0x2C2 +HID_USAGE_CONSUMER_KEYBOARD_PHYSICAL_LAYOUT :: 0x2C3 +HID_USAGE_CONSUMER_VENDOR_SPECIFIC_KEYBOARD_PHYSICAL_LAYOUT :: 0x2C4 +HID_USAGE_CONSUMER_KEYBOARD_IETF_LANGUAGE_TAG_INDEX :: 0x2C5 HID_USAGE_CONSUMER_IMPLEMENTED_KEYBOARD_INPUT_ASSIST_CONTROLS :: 0x2C6 -HID_USAGE_DIGITIZER_DIGITIZER :: 0x01 -HID_USAGE_DIGITIZER_PEN :: 0x02 -HID_USAGE_DIGITIZER_LIGHT_PEN :: 0x03 -HID_USAGE_DIGITIZER_TOUCH_SCREEN :: 0x04 -HID_USAGE_DIGITIZER_TOUCH_PAD :: 0x05 -HID_USAGE_DIGITIZER_WHITE_BOARD :: 0x06 -HID_USAGE_DIGITIZER_COORD_MEASURING :: 0x07 -HID_USAGE_DIGITIZER_3D_DIGITIZER :: 0x08 -HID_USAGE_DIGITIZER_STEREO_PLOTTER :: 0x09 -HID_USAGE_DIGITIZER_ARTICULATED_ARM :: 0x0A -HID_USAGE_DIGITIZER_ARMATURE :: 0x0B -HID_USAGE_DIGITIZER_MULTI_POINT :: 0x0C -HID_USAGE_DIGITIZER_FREE_SPACE_WAND :: 0x0D -HID_USAGE_DIGITIZER_HEAT_MAP :: 0x0F -HID_USAGE_DIGITIZER_STYLUS :: 0x20 -HID_USAGE_DIGITIZER_PUCK :: 0x21 -HID_USAGE_DIGITIZER_FINGER :: 0x22 +HID_USAGE_DIGITIZER_DIGITIZER :: 0x01 +HID_USAGE_DIGITIZER_PEN :: 0x02 +HID_USAGE_DIGITIZER_LIGHT_PEN :: 0x03 +HID_USAGE_DIGITIZER_TOUCH_SCREEN :: 0x04 +HID_USAGE_DIGITIZER_TOUCH_PAD :: 0x05 +HID_USAGE_DIGITIZER_WHITE_BOARD :: 0x06 +HID_USAGE_DIGITIZER_COORD_MEASURING :: 0x07 +HID_USAGE_DIGITIZER_3D_DIGITIZER :: 0x08 +HID_USAGE_DIGITIZER_STEREO_PLOTTER :: 0x09 +HID_USAGE_DIGITIZER_ARTICULATED_ARM :: 0x0A +HID_USAGE_DIGITIZER_ARMATURE :: 0x0B +HID_USAGE_DIGITIZER_MULTI_POINT :: 0x0C +HID_USAGE_DIGITIZER_FREE_SPACE_WAND :: 0x0D +HID_USAGE_DIGITIZER_HEAT_MAP :: 0x0F +HID_USAGE_DIGITIZER_STYLUS :: 0x20 +HID_USAGE_DIGITIZER_PUCK :: 0x21 +HID_USAGE_DIGITIZER_FINGER :: 0x22 HID_USAGE_DIGITIZER_TABLET_FUNC_KEYS :: 0x39 HID_USAGE_DIGITIZER_PROG_CHANGE_KEYS :: 0x3A -HID_USAGE_DIGITIZER_TIP_PRESSURE :: 0x30 -HID_USAGE_DIGITIZER_BARREL_PRESSURE :: 0x31 -HID_USAGE_DIGITIZER_IN_RANGE :: 0x32 -HID_USAGE_DIGITIZER_TOUCH :: 0x33 -HID_USAGE_DIGITIZER_UNTOUCH :: 0x34 -HID_USAGE_DIGITIZER_TAP :: 0x35 -HID_USAGE_DIGITIZER_QUALITY :: 0x36 -HID_USAGE_DIGITIZER_DATA_VALID :: 0x37 -HID_USAGE_DIGITIZER_TRANSDUCER_INDEX :: 0x38 -HID_USAGE_DIGITIZER_BATTERY_STRENGTH :: 0x3B -HID_USAGE_DIGITIZER_INVERT :: 0x3C -HID_USAGE_DIGITIZER_X_TILT :: 0x3D -HID_USAGE_DIGITIZER_Y_TILT :: 0x3E -HID_USAGE_DIGITIZER_AZIMUTH :: 0x3F -HID_USAGE_DIGITIZER_ALTITUDE :: 0x40 -HID_USAGE_DIGITIZER_TWIST :: 0x41 -HID_USAGE_DIGITIZER_TIP_SWITCH :: 0x42 -HID_USAGE_DIGITIZER_SECONDARY_TIP_SWITCH :: 0x43 -HID_USAGE_DIGITIZER_BARREL_SWITCH :: 0x44 -HID_USAGE_DIGITIZER_ERASER :: 0x45 -HID_USAGE_DIGITIZER_TABLET_PICK :: 0x46 -HID_USAGE_DIGITIZER_TRANSDUCER_SERIAL :: 0x5B +HID_USAGE_DIGITIZER_TIP_PRESSURE :: 0x30 +HID_USAGE_DIGITIZER_BARREL_PRESSURE :: 0x31 +HID_USAGE_DIGITIZER_IN_RANGE :: 0x32 +HID_USAGE_DIGITIZER_TOUCH :: 0x33 +HID_USAGE_DIGITIZER_UNTOUCH :: 0x34 +HID_USAGE_DIGITIZER_TAP :: 0x35 +HID_USAGE_DIGITIZER_QUALITY :: 0x36 +HID_USAGE_DIGITIZER_DATA_VALID :: 0x37 +HID_USAGE_DIGITIZER_TRANSDUCER_INDEX :: 0x38 +HID_USAGE_DIGITIZER_BATTERY_STRENGTH :: 0x3B +HID_USAGE_DIGITIZER_INVERT :: 0x3C +HID_USAGE_DIGITIZER_X_TILT :: 0x3D +HID_USAGE_DIGITIZER_Y_TILT :: 0x3E +HID_USAGE_DIGITIZER_AZIMUTH :: 0x3F +HID_USAGE_DIGITIZER_ALTITUDE :: 0x40 +HID_USAGE_DIGITIZER_TWIST :: 0x41 +HID_USAGE_DIGITIZER_TIP_SWITCH :: 0x42 +HID_USAGE_DIGITIZER_SECONDARY_TIP_SWITCH :: 0x43 +HID_USAGE_DIGITIZER_BARREL_SWITCH :: 0x44 +HID_USAGE_DIGITIZER_ERASER :: 0x45 +HID_USAGE_DIGITIZER_TABLET_PICK :: 0x46 +HID_USAGE_DIGITIZER_TRANSDUCER_SERIAL :: 0x5B HID_USAGE_DIGITIZER_HEAT_MAP_PROTOCOL_VENDOR_ID :: 0x6A -HID_USAGE_DIGITIZER_HEAT_MAP_PROTOCOL_VERSION :: 0x6B -HID_USAGE_DIGITIZER_HEAT_MAP_FRAME_DATA :: 0x6C -HID_USAGE_DIGITIZER_TRANSDUCER_SERIAL_PART2 :: 0x6E -HID_USAGE_DIGITIZER_TRANSDUCER_VENDOR :: 0x91 -HID_USAGE_DIGITIZER_TRANSDUCER_PRODUCT :: 0x92 -HID_USAGE_DIGITIZER_TRANSDUCER_CONNECTED :: 0xA2 +HID_USAGE_DIGITIZER_HEAT_MAP_PROTOCOL_VERSION :: 0x6B +HID_USAGE_DIGITIZER_HEAT_MAP_FRAME_DATA :: 0x6C +HID_USAGE_DIGITIZER_TRANSDUCER_SERIAL_PART2 :: 0x6E +HID_USAGE_DIGITIZER_TRANSDUCER_VENDOR :: 0x91 +HID_USAGE_DIGITIZER_TRANSDUCER_PRODUCT :: 0x92 +HID_USAGE_DIGITIZER_TRANSDUCER_CONNECTED :: 0xA2 HID_USAGE_HAPTICS_SIMPLE_CONTROLLER :: 0x01 HID_USAGE_HAPTICS_WAVEFORM_LIST :: 0x10 HID_USAGE_HAPTICS_DURATION_LIST :: 0x11 -HID_USAGE_HAPTICS_AUTO_TRIGGER :: 0x20 -HID_USAGE_HAPTICS_MANUAL_TRIGGER :: 0x21 +HID_USAGE_HAPTICS_AUTO_TRIGGER :: 0x20 +HID_USAGE_HAPTICS_MANUAL_TRIGGER :: 0x21 HID_USAGE_HAPTICS_AUTO_ASSOCIATED_CONTROL :: 0x22 -HID_USAGE_HAPTICS_INTENSITY :: 0x23 -HID_USAGE_HAPTICS_REPEAT_COUNT :: 0x24 -HID_USAGE_HAPTICS_RETRIGGER_PERIOD :: 0x25 -HID_USAGE_HAPTICS_WAVEFORM_VENDOR_PAGE :: 0x26 -HID_USAGE_HAPTICS_WAVEFORM_VENDOR_ID :: 0x27 -HID_USAGE_HAPTICS_WAVEFORM_CUTOFF_TIME :: 0x28 +HID_USAGE_HAPTICS_INTENSITY :: 0x23 +HID_USAGE_HAPTICS_REPEAT_COUNT :: 0x24 +HID_USAGE_HAPTICS_RETRIGGER_PERIOD :: 0x25 +HID_USAGE_HAPTICS_WAVEFORM_VENDOR_PAGE :: 0x26 +HID_USAGE_HAPTICS_WAVEFORM_VENDOR_ID :: 0x27 +HID_USAGE_HAPTICS_WAVEFORM_CUTOFF_TIME :: 0x28 // Waveform types -HID_USAGE_HAPTICS_WAVEFORM_BEGIN :: 0x1000 -HID_USAGE_HAPTICS_WAVEFORM_STOP :: 0x1001 -HID_USAGE_HAPTICS_WAVEFORM_NULL :: 0x1002 -HID_USAGE_HAPTICS_WAVEFORM_CLICK :: 0x1003 -HID_USAGE_HAPTICS_WAVEFORM_BUZZ :: 0x1004 -HID_USAGE_HAPTICS_WAVEFORM_RUMBLE :: 0x1005 -HID_USAGE_HAPTICS_WAVEFORM_PRESS :: 0x1006 +HID_USAGE_HAPTICS_WAVEFORM_BEGIN :: 0x1000 +HID_USAGE_HAPTICS_WAVEFORM_STOP :: 0x1001 +HID_USAGE_HAPTICS_WAVEFORM_NULL :: 0x1002 +HID_USAGE_HAPTICS_WAVEFORM_CLICK :: 0x1003 +HID_USAGE_HAPTICS_WAVEFORM_BUZZ :: 0x1004 +HID_USAGE_HAPTICS_WAVEFORM_RUMBLE :: 0x1005 +HID_USAGE_HAPTICS_WAVEFORM_PRESS :: 0x1006 HID_USAGE_HAPTICS_WAVEFORM_RELEASE :: 0x1007 -HID_USAGE_HAPTICS_WAVEFORM_END :: 0x1FFF +HID_USAGE_HAPTICS_WAVEFORM_END :: 0x1FFF HID_USAGE_HAPTICS_WAVEFORM_VENDOR_BEGIN :: 0x2000 -HID_USAGE_HAPTICS_WAVEFORM_VENDOR_END :: 0x2FFF +HID_USAGE_HAPTICS_WAVEFORM_VENDOR_END :: 0x2FFF -HID_USAGE_ALPHANUMERIC_ALPHANUMERIC_DISPLAY :: 0x01 -HID_USAGE_ALPHANUMERIC_BITMAPPED_DISPLAY :: 0x02 +HID_USAGE_ALPHANUMERIC_ALPHANUMERIC_DISPLAY :: 0x01 +HID_USAGE_ALPHANUMERIC_BITMAPPED_DISPLAY :: 0x02 HID_USAGE_ALPHANUMERIC_DISPLAY_ATTRIBUTES_REPORT :: 0x20 -HID_USAGE_ALPHANUMERIC_DISPLAY_CONTROL_REPORT :: 0x24 -HID_USAGE_ALPHANUMERIC_CHARACTER_REPORT :: 0x2B -HID_USAGE_ALPHANUMERIC_DISPLAY_STATUS :: 0x2D -HID_USAGE_ALPHANUMERIC_CURSOR_POSITION_REPORT :: 0x32 -HID_USAGE_ALPHANUMERIC_FONT_REPORT :: 0x3B -HID_USAGE_ALPHANUMERIC_FONT_DATA :: 0x3C -HID_USAGE_ALPHANUMERIC_CHARACTER_ATTRIBUTE :: 0x48 -HID_USAGE_ALPHANUMERIC_PALETTE_REPORT :: 0x85 -HID_USAGE_ALPHANUMERIC_PALETTE_DATA :: 0x88 -HID_USAGE_ALPHANUMERIC_BLIT_REPORT :: 0x8A -HID_USAGE_ALPHANUMERIC_BLIT_DATA :: 0x8F -HID_USAGE_ALPHANUMERIC_SOFT_BUTTON :: 0x90 +HID_USAGE_ALPHANUMERIC_DISPLAY_CONTROL_REPORT :: 0x24 +HID_USAGE_ALPHANUMERIC_CHARACTER_REPORT :: 0x2B +HID_USAGE_ALPHANUMERIC_DISPLAY_STATUS :: 0x2D +HID_USAGE_ALPHANUMERIC_CURSOR_POSITION_REPORT :: 0x32 +HID_USAGE_ALPHANUMERIC_FONT_REPORT :: 0x3B +HID_USAGE_ALPHANUMERIC_FONT_DATA :: 0x3C +HID_USAGE_ALPHANUMERIC_CHARACTER_ATTRIBUTE :: 0x48 +HID_USAGE_ALPHANUMERIC_PALETTE_REPORT :: 0x85 +HID_USAGE_ALPHANUMERIC_PALETTE_DATA :: 0x88 +HID_USAGE_ALPHANUMERIC_BLIT_REPORT :: 0x8A +HID_USAGE_ALPHANUMERIC_BLIT_DATA :: 0x8F +HID_USAGE_ALPHANUMERIC_SOFT_BUTTON :: 0x90 -HID_USAGE_ALPHANUMERIC_ASCII_CHARACTER_SET :: 0x21 -HID_USAGE_ALPHANUMERIC_DATA_READ_BACK :: 0x22 -HID_USAGE_ALPHANUMERIC_FONT_READ_BACK :: 0x23 -HID_USAGE_ALPHANUMERIC_CLEAR_DISPLAY :: 0x25 -HID_USAGE_ALPHANUMERIC_DISPLAY_ENABLE :: 0x26 -HID_USAGE_ALPHANUMERIC_SCREEN_SAVER_DELAY :: 0x27 -HID_USAGE_ALPHANUMERIC_SCREEN_SAVER_ENABLE :: 0x28 -HID_USAGE_ALPHANUMERIC_VERTICAL_SCROLL :: 0x29 -HID_USAGE_ALPHANUMERIC_HORIZONTAL_SCROLL :: 0x2A -HID_USAGE_ALPHANUMERIC_DISPLAY_DATA :: 0x2C -HID_USAGE_ALPHANUMERIC_STATUS_NOT_READY :: 0x2E -HID_USAGE_ALPHANUMERIC_STATUS_READY :: 0x2F +HID_USAGE_ALPHANUMERIC_ASCII_CHARACTER_SET :: 0x21 +HID_USAGE_ALPHANUMERIC_DATA_READ_BACK :: 0x22 +HID_USAGE_ALPHANUMERIC_FONT_READ_BACK :: 0x23 +HID_USAGE_ALPHANUMERIC_CLEAR_DISPLAY :: 0x25 +HID_USAGE_ALPHANUMERIC_DISPLAY_ENABLE :: 0x26 +HID_USAGE_ALPHANUMERIC_SCREEN_SAVER_DELAY :: 0x27 +HID_USAGE_ALPHANUMERIC_SCREEN_SAVER_ENABLE :: 0x28 +HID_USAGE_ALPHANUMERIC_VERTICAL_SCROLL :: 0x29 +HID_USAGE_ALPHANUMERIC_HORIZONTAL_SCROLL :: 0x2A +HID_USAGE_ALPHANUMERIC_DISPLAY_DATA :: 0x2C +HID_USAGE_ALPHANUMERIC_STATUS_NOT_READY :: 0x2E +HID_USAGE_ALPHANUMERIC_STATUS_READY :: 0x2F HID_USAGE_ALPHANUMERIC_ERR_NOT_A_LOADABLE_CHARACTER :: 0x30 HID_USAGE_ALPHANUMERIC_ERR_FONT_DATA_CANNOT_BE_READ :: 0x31 -HID_USAGE_ALPHANUMERIC_ROW :: 0x33 -HID_USAGE_ALPHANUMERIC_COLUMN :: 0x34 -HID_USAGE_ALPHANUMERIC_ROWS :: 0x35 -HID_USAGE_ALPHANUMERIC_COLUMNS :: 0x36 -HID_USAGE_ALPHANUMERIC_CURSOR_PIXEL_POSITIONING :: 0x37 -HID_USAGE_ALPHANUMERIC_CURSOR_MODE :: 0x38 -HID_USAGE_ALPHANUMERIC_CURSOR_ENABLE :: 0x39 -HID_USAGE_ALPHANUMERIC_CURSOR_BLINK :: 0x3A -HID_USAGE_ALPHANUMERIC_CHAR_WIDTH :: 0x3D -HID_USAGE_ALPHANUMERIC_CHAR_HEIGHT :: 0x3E -HID_USAGE_ALPHANUMERIC_CHAR_SPACING_HORIZONTAL :: 0x3F -HID_USAGE_ALPHANUMERIC_CHAR_SPACING_VERTICAL :: 0x40 -HID_USAGE_ALPHANUMERIC_UNICODE_CHAR_SET :: 0x41 -HID_USAGE_ALPHANUMERIC_FONT_7_SEGMENT :: 0x42 -HID_USAGE_ALPHANUMERIC_7_SEGMENT_DIRECT_MAP :: 0x43 -HID_USAGE_ALPHANUMERIC_FONT_14_SEGMENT :: 0x44 -HID_USAGE_ALPHANUMERIC_14_SEGMENT_DIRECT_MAP :: 0x45 -HID_USAGE_ALPHANUMERIC_DISPLAY_BRIGHTNESS :: 0x46 -HID_USAGE_ALPHANUMERIC_DISPLAY_CONTRAST :: 0x47 -HID_USAGE_ALPHANUMERIC_ATTRIBUTE_READBACK :: 0x49 -HID_USAGE_ALPHANUMERIC_ATTRIBUTE_DATA :: 0x4A -HID_USAGE_ALPHANUMERIC_CHAR_ATTR_ENHANCE :: 0x4B -HID_USAGE_ALPHANUMERIC_CHAR_ATTR_UNDERLINE :: 0x4C -HID_USAGE_ALPHANUMERIC_CHAR_ATTR_BLINK :: 0x4D -HID_USAGE_ALPHANUMERIC_BITMAP_SIZE_X :: 0x80 -HID_USAGE_ALPHANUMERIC_BITMAP_SIZE_Y :: 0x81 -HID_USAGE_ALPHANUMERIC_BIT_DEPTH_FORMAT :: 0x83 -HID_USAGE_ALPHANUMERIC_DISPLAY_ORIENTATION :: 0x84 -HID_USAGE_ALPHANUMERIC_PALETTE_DATA_SIZE :: 0x86 -HID_USAGE_ALPHANUMERIC_PALETTE_DATA_OFFSET :: 0x87 -HID_USAGE_ALPHANUMERIC_BLIT_RECTANGLE_X1 :: 0x8B -HID_USAGE_ALPHANUMERIC_BLIT_RECTANGLE_Y1 :: 0x8C -HID_USAGE_ALPHANUMERIC_BLIT_RECTANGLE_X2 :: 0x8D -HID_USAGE_ALPHANUMERIC_BLIT_RECTANGLE_Y2 :: 0x8E -HID_USAGE_ALPHANUMERIC_SOFT_BUTTON_ID :: 0x91 -HID_USAGE_ALPHANUMERIC_SOFT_BUTTON_SIDE :: 0x92 -HID_USAGE_ALPHANUMERIC_SOFT_BUTTON_OFFSET1 :: 0x93 -HID_USAGE_ALPHANUMERIC_SOFT_BUTTON_OFFSET2 :: 0x94 -HID_USAGE_ALPHANUMERIC_SOFT_BUTTON_REPORT :: 0x95 +HID_USAGE_ALPHANUMERIC_ROW :: 0x33 +HID_USAGE_ALPHANUMERIC_COLUMN :: 0x34 +HID_USAGE_ALPHANUMERIC_ROWS :: 0x35 +HID_USAGE_ALPHANUMERIC_COLUMNS :: 0x36 +HID_USAGE_ALPHANUMERIC_CURSOR_PIXEL_POSITIONING :: 0x37 +HID_USAGE_ALPHANUMERIC_CURSOR_MODE :: 0x38 +HID_USAGE_ALPHANUMERIC_CURSOR_ENABLE :: 0x39 +HID_USAGE_ALPHANUMERIC_CURSOR_BLINK :: 0x3A +HID_USAGE_ALPHANUMERIC_CHAR_WIDTH :: 0x3D +HID_USAGE_ALPHANUMERIC_CHAR_HEIGHT :: 0x3E +HID_USAGE_ALPHANUMERIC_CHAR_SPACING_HORIZONTAL :: 0x3F +HID_USAGE_ALPHANUMERIC_CHAR_SPACING_VERTICAL :: 0x40 +HID_USAGE_ALPHANUMERIC_UNICODE_CHAR_SET :: 0x41 +HID_USAGE_ALPHANUMERIC_FONT_7_SEGMENT :: 0x42 +HID_USAGE_ALPHANUMERIC_7_SEGMENT_DIRECT_MAP :: 0x43 +HID_USAGE_ALPHANUMERIC_FONT_14_SEGMENT :: 0x44 +HID_USAGE_ALPHANUMERIC_14_SEGMENT_DIRECT_MAP :: 0x45 +HID_USAGE_ALPHANUMERIC_DISPLAY_BRIGHTNESS :: 0x46 +HID_USAGE_ALPHANUMERIC_DISPLAY_CONTRAST :: 0x47 +HID_USAGE_ALPHANUMERIC_ATTRIBUTE_READBACK :: 0x49 +HID_USAGE_ALPHANUMERIC_ATTRIBUTE_DATA :: 0x4A +HID_USAGE_ALPHANUMERIC_CHAR_ATTR_ENHANCE :: 0x4B +HID_USAGE_ALPHANUMERIC_CHAR_ATTR_UNDERLINE :: 0x4C +HID_USAGE_ALPHANUMERIC_CHAR_ATTR_BLINK :: 0x4D +HID_USAGE_ALPHANUMERIC_BITMAP_SIZE_X :: 0x80 +HID_USAGE_ALPHANUMERIC_BITMAP_SIZE_Y :: 0x81 +HID_USAGE_ALPHANUMERIC_BIT_DEPTH_FORMAT :: 0x83 +HID_USAGE_ALPHANUMERIC_DISPLAY_ORIENTATION :: 0x84 +HID_USAGE_ALPHANUMERIC_PALETTE_DATA_SIZE :: 0x86 +HID_USAGE_ALPHANUMERIC_PALETTE_DATA_OFFSET :: 0x87 +HID_USAGE_ALPHANUMERIC_BLIT_RECTANGLE_X1 :: 0x8B +HID_USAGE_ALPHANUMERIC_BLIT_RECTANGLE_Y1 :: 0x8C +HID_USAGE_ALPHANUMERIC_BLIT_RECTANGLE_X2 :: 0x8D +HID_USAGE_ALPHANUMERIC_BLIT_RECTANGLE_Y2 :: 0x8E +HID_USAGE_ALPHANUMERIC_SOFT_BUTTON_ID :: 0x91 +HID_USAGE_ALPHANUMERIC_SOFT_BUTTON_SIDE :: 0x92 +HID_USAGE_ALPHANUMERIC_SOFT_BUTTON_OFFSET1 :: 0x93 +HID_USAGE_ALPHANUMERIC_SOFT_BUTTON_OFFSET2 :: 0x94 +HID_USAGE_ALPHANUMERIC_SOFT_BUTTON_REPORT :: 0x95 -HID_USAGE_LAMPARRAY :: 0x01 -HID_USAGE_LAMPARRAY_ATTRBIUTES_REPORT :: 0x02 -HID_USAGE_LAMPARRAY_LAMP_COUNT :: 0x03 -HID_USAGE_LAMPARRAY_BOUNDING_BOX_WIDTH_IN_MICROMETERS :: 0x04 -HID_USAGE_LAMPARRAY_BOUNDING_BOX_HEIGHT_IN_MICROMETERS :: 0x05 -HID_USAGE_LAMPARRAY_BOUNDING_BOX_DEPTH_IN_MICROMETERS :: 0x06 -HID_USAGE_LAMPARRAY_KIND :: 0x07 +HID_USAGE_LAMPARRAY :: 0x01 +HID_USAGE_LAMPARRAY_ATTRBIUTES_REPORT :: 0x02 +HID_USAGE_LAMPARRAY_LAMP_COUNT :: 0x03 +HID_USAGE_LAMPARRAY_BOUNDING_BOX_WIDTH_IN_MICROMETERS :: 0x04 +HID_USAGE_LAMPARRAY_BOUNDING_BOX_HEIGHT_IN_MICROMETERS :: 0x05 +HID_USAGE_LAMPARRAY_BOUNDING_BOX_DEPTH_IN_MICROMETERS :: 0x06 +HID_USAGE_LAMPARRAY_KIND :: 0x07 HID_USAGE_LAMPARRAY_MIN_UPDATE_INTERVAL_IN_MICROSECONDS :: 0x08 // 0x09 - 0x1F Reserved -HID_USAGE_LAMPARRAY_LAMP_ATTRIBUTES_REQUEST_REPORT :: 0x20 -HID_USAGE_LAMPARRAY_LAMP_ID :: 0x21 +HID_USAGE_LAMPARRAY_LAMP_ATTRIBUTES_REQUEST_REPORT :: 0x20 +HID_USAGE_LAMPARRAY_LAMP_ID :: 0x21 HID_USAGE_LAMPARRAY_LAMP_ATTRIBUTES_RESPONSE_REPORT :: 0x22 -HID_USAGE_LAMPARRAY_POSITION_X_IN_MICROMETERS :: 0x23 -HID_USAGE_LAMPARRAY_POSITION_Y_IN_MICROMETERS :: 0x24 -HID_USAGE_LAMPARRAY_POSITION_Z_IN_MICROMETERS :: 0x25 -HID_USAGE_LAMPARRAY_LAMP_PURPOSES :: 0x26 -HID_USAGE_LAMPARRAY_UPDATE_LATENCY_IN_MICROSECONDS :: 0x27 -HID_USAGE_LAMPARRAY_RED_LEVEL_COUNT :: 0x28 -HID_USAGE_LAMPARRAY_GREEN_LEVEL_COUNT :: 0x29 -HID_USAGE_LAMPARRAY_BLUE_LEVEL_COUNT :: 0x2A -HID_USAGE_LAMPARRAY_INTENSITY_LEVEL_COUNT :: 0x2B -HID_USAGE_LAMPARRAY_IS_PROGRAMMABLE :: 0x2C -HID_USAGE_LAMPARRAY_INPUT_BINDING :: 0x2D +HID_USAGE_LAMPARRAY_POSITION_X_IN_MICROMETERS :: 0x23 +HID_USAGE_LAMPARRAY_POSITION_Y_IN_MICROMETERS :: 0x24 +HID_USAGE_LAMPARRAY_POSITION_Z_IN_MICROMETERS :: 0x25 +HID_USAGE_LAMPARRAY_LAMP_PURPOSES :: 0x26 +HID_USAGE_LAMPARRAY_UPDATE_LATENCY_IN_MICROSECONDS :: 0x27 +HID_USAGE_LAMPARRAY_RED_LEVEL_COUNT :: 0x28 +HID_USAGE_LAMPARRAY_GREEN_LEVEL_COUNT :: 0x29 +HID_USAGE_LAMPARRAY_BLUE_LEVEL_COUNT :: 0x2A +HID_USAGE_LAMPARRAY_INTENSITY_LEVEL_COUNT :: 0x2B +HID_USAGE_LAMPARRAY_IS_PROGRAMMABLE :: 0x2C +HID_USAGE_LAMPARRAY_INPUT_BINDING :: 0x2D // 0x2E - 0x4F Reserved -HID_USAGE_LAMPARRAY_LAMP_MULTI_UPDATE_REPORT :: 0x50 -HID_USAGE_LAMPARRAY_LAMP_RED_UPDATE_CHANNEL :: 0x51 -HID_USAGE_LAMPARRAY_LAMP_GREEN_UPDATE_CHANNEL :: 0x52 -HID_USAGE_LAMPARRAY_LAMP_BLUE_UPDATE_CHANNEL :: 0x53 +HID_USAGE_LAMPARRAY_LAMP_MULTI_UPDATE_REPORT :: 0x50 +HID_USAGE_LAMPARRAY_LAMP_RED_UPDATE_CHANNEL :: 0x51 +HID_USAGE_LAMPARRAY_LAMP_GREEN_UPDATE_CHANNEL :: 0x52 +HID_USAGE_LAMPARRAY_LAMP_BLUE_UPDATE_CHANNEL :: 0x53 HID_USAGE_LAMPARRAY_LAMP_INTENSITY_UPDATE_CHANNEL :: 0x54 -HID_USAGE_LAMPARRAY_LAMP_UPDATE_FLAGS :: 0x55 +HID_USAGE_LAMPARRAY_LAMP_UPDATE_FLAGS :: 0x55 // 0x55 - 0x5F Reserved HID_USAGE_LAMPARRAY_LAMP_RANGE_UPDATE_REPORT :: 0x60 -HID_USAGE_LAMPARRAY_LAMP_ID_START :: 0x61 -HID_USAGE_LAMPARRAY_LAMP_ID_END :: 0x62 +HID_USAGE_LAMPARRAY_LAMP_ID_START :: 0x61 +HID_USAGE_LAMPARRAY_LAMP_ID_END :: 0x62 // 0x63 - 0x6F Reserved -HID_USAGE_LAMPARRAY_CONTROL_REPORT :: 0x70 +HID_USAGE_LAMPARRAY_CONTROL_REPORT :: 0x70 HID_USAGE_LAMPARRAY_AUTONOMOUS_MODE :: 0x71 HID_USAGE_CAMERA_AUTO_FOCUS :: 0x20 -HID_USAGE_CAMERA_SHUTTER :: 0x21 +HID_USAGE_CAMERA_SHUTTER :: 0x21 HID_USAGE_MS_BTH_HF_DIALNUMBER :: 0x21 HID_USAGE_MS_BTH_HF_DIALMEMORY :: 0x22 diff --git a/core/sys/windows/icu.odin b/core/sys/windows/icu.odin index 6ed8c9b40..7be9ce4c6 100644 --- a/core/sys/windows/icu.odin +++ b/core/sys/windows/icu.odin @@ -10,5 +10,8 @@ UError :: enum i32 { @(default_calling_convention="system") foreign icu { ucal_getWindowsTimeZoneID :: proc(id: wstring, len: i32, winid: wstring, winidCapacity: i32, status: ^UError) -> i32 --- - ucal_getDefaultTimeZone :: proc(result: wstring, cap: i32, status: ^UError) -> i32 --- + ucal_getDefaultTimeZone :: proc(result: wstring, cap: i32, status: ^UError) -> i32 --- } + + +// NOTE(bill): all of these types actually do use `i32` and not `c_int` diff --git a/core/sys/windows/ip_helper.odin b/core/sys/windows/ip_helper.odin index d2e75d531..74ffa95b9 100644 --- a/core/sys/windows/ip_helper.odin +++ b/core/sys/windows/ip_helper.odin @@ -141,7 +141,7 @@ IP_ADAPTER_DNS_SERVER_ADDRESS_XP :: struct { Address: SOCKET_ADDRESS, } -IF_OPER_STATUS :: enum i32 { +IF_OPER_STATUS :: enum c_int { Up = 1, Down = 2, Testing = 3, @@ -160,17 +160,17 @@ NET_LUID_LH :: struct #raw_union { SOCKET_ADDRESS :: struct { lpSockaddr: ^SOCKADDR, - iSockaddrLength: i32, + iSockaddrLength: INT, } -NET_IF_CONNECTION_TYPE :: enum i32 { +NET_IF_CONNECTION_TYPE :: enum c_int { NET_IF_CONNECTION_DEDICATED = 1, NET_IF_CONNECTION_PASSIVE = 2, NET_IF_CONNECTION_DEMAND = 3, NET_IF_CONNECTION_MAXIMUM = 4, } -TUNNEL_TYPE :: enum i32 { +TUNNEL_TYPE :: enum c_int { TUNNEL_TYPE_NONE = 0, TUNNEL_TYPE_OTHER = 1, TUNNEL_TYPE_DIRECT = 2, @@ -179,7 +179,7 @@ TUNNEL_TYPE :: enum i32 { TUNNEL_TYPE_TEREDO = 14, TUNNEL_TYPE_IPHTTPS = 15, } -NL_PREFIX_ORIGIN :: enum i32 { +NL_PREFIX_ORIGIN :: enum c_int { IpPrefixOriginOther = 0, IpPrefixOriginManual = 1, IpPrefixOriginWellKnown = 2, @@ -188,7 +188,7 @@ NL_PREFIX_ORIGIN :: enum i32 { IpPrefixOriginUnchanged = 16, } -NL_SUFFIX_ORIGIN :: enum i32 { +NL_SUFFIX_ORIGIN :: enum c_int { NlsoOther = 0, NlsoManual = 1, NlsoWellKnown = 2, @@ -204,7 +204,7 @@ NL_SUFFIX_ORIGIN :: enum i32 { IpSuffixOriginUnchanged = 16, } -NL_DAD_STATE :: enum i32 { +NL_DAD_STATE :: enum c_int { NldsInvalid = 0, NldsTentative = 1, NldsDuplicate = 2, @@ -223,7 +223,7 @@ foreign iphlpapi { The GetAdaptersAddresses function retrieves the addresses associated with the adapters on the local computer. See: https://docs.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersaddresses */ - @(link_name="GetAdaptersAddresses") get_adapters_addresses :: proc( + GetAdaptersAddresses :: proc( family: Address_Family, flags: GAA_Flags, _reserved: rawptr, @@ -232,3 +232,5 @@ foreign iphlpapi { ) -> ULONG --- } + +get_adapters_addresses :: GetAdaptersAddresses \ No newline at end of file diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index d6f60a08b..916afe0e6 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -30,6 +30,18 @@ EV_RXCHAR :: DWORD(0x0001) EV_RXFLAG :: DWORD(0x0002) EV_TXEMPTY :: DWORD(0x0004) +WAITORTIMERCALLBACK :: #type proc "system" (lpParameter: PVOID, TimerOrWaitFired: BOOLEAN) + +PAPCFUNC :: #type proc "system" (Parameter: ULONG_PTR) + +WT_EXECUTEDEFAULT :: 0x00000000 +WT_EXECUTEINIOTHREAD :: 0x00000001 +WT_EXECUTEINPERSISTENTTHREAD :: 0x00000080 +WT_EXECUTEINWAITTHREAD :: 0x00000004 +WT_EXECUTELONGFUNCTION :: 0x00000010 +WT_EXECUTEONLYONCE :: 0x00000008 +WT_TRANSFER_IMPERSONATION :: 0x00000100 + @(default_calling_convention="system") foreign kernel32 { OutputDebugStringA :: proc(lpOutputString: LPCSTR) --- // The only A thing that is allowed @@ -60,15 +72,15 @@ foreign kernel32 { // https://learn.microsoft.com/en-us/windows/console/getnumberofconsoleinputevents GetNumberOfConsoleInputEvents :: proc(hConsoleInput: HANDLE, lpcNumberOfEvents: LPDWORD) -> BOOL --- - GetConsoleMode :: proc(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL --- - SetConsoleMode :: proc(hConsoleHandle: HANDLE, dwMode: DWORD) -> BOOL --- + GetConsoleMode :: proc(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL --- + SetConsoleMode :: proc(hConsoleHandle: HANDLE, dwMode: DWORD) -> BOOL --- SetConsoleCursorPosition :: proc(hConsoleHandle: HANDLE, dwCursorPosition: COORD) -> BOOL --- - SetConsoleTextAttribute :: proc(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL --- - GetConsoleCP :: proc() -> CODEPAGE --- - SetConsoleCP :: proc(wCodePageID: CODEPAGE) -> BOOL --- - GetConsoleOutputCP :: proc() -> CODEPAGE --- - SetConsoleOutputCP :: proc(wCodePageID: CODEPAGE) -> BOOL --- - FlushConsoleInputBuffer :: proc(hConsoleInput: HANDLE) -> BOOL --- + SetConsoleTextAttribute :: proc(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL --- + GetConsoleCP :: proc() -> CODEPAGE --- + SetConsoleCP :: proc(wCodePageID: CODEPAGE) -> BOOL --- + GetConsoleOutputCP :: proc() -> CODEPAGE --- + SetConsoleOutputCP :: proc(wCodePageID: CODEPAGE) -> BOOL --- + FlushConsoleInputBuffer :: proc(hConsoleInput: HANDLE) -> BOOL --- GetFileInformationByHandle :: proc(hFile: HANDLE, lpFileInformation: LPBY_HANDLE_FILE_INFORMATION) -> BOOL --- @@ -82,11 +94,11 @@ foreign kernel32 { dwBufferSize: DWORD) -> BOOL --- - AddVectoredExceptionHandler :: proc(FirstHandler: ULONG, VectoredHandler: PVECTORED_EXCEPTION_HANDLER) -> LPVOID --- - AddVectoredContinueHandler :: proc(FirstHandler: ULONG, VectoredHandler: PVECTORED_EXCEPTION_HANDLER) -> LPVOID --- + AddVectoredExceptionHandler :: proc(FirstHandler: ULONG, VectoredHandler: PVECTORED_EXCEPTION_HANDLER) -> LPVOID --- + AddVectoredContinueHandler :: proc(FirstHandler: ULONG, VectoredHandler: PVECTORED_EXCEPTION_HANDLER) -> LPVOID --- RemoveVectoredExceptionHandler :: proc(Handle: LPVOID) -> DWORD --- - RemoveVectoredContinueHandler :: proc(Handle: LPVOID) -> DWORD --- - RaiseException :: proc(dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD, lpArguments: ^ULONG_PTR) -> ! --- + RemoveVectoredContinueHandler :: proc(Handle: LPVOID) -> DWORD --- + RaiseException :: proc(dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD, lpArguments: ^ULONG_PTR) -> ! --- SetUnhandledExceptionFilter :: proc(lpTopLevelExceptionFilter: LPTOP_LEVEL_EXCEPTION_FILTER) -> LPTOP_LEVEL_EXCEPTION_FILTER --- @@ -103,31 +115,31 @@ foreign kernel32 { lpFileInformation: LPVOID, dwBufferSize: DWORD) -> BOOL --- - InitializeCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) --- + InitializeCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) --- InitializeCriticalSectionAndSpinCount :: proc(CriticalSection: ^CRITICAL_SECTION, dwSpinCount: DWORD) -> BOOL --- - EnterCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) --- - TryEnterCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) -> BOOLEAN --- - LeaveCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) --- - DeleteCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) --- + EnterCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) --- + TryEnterCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) -> BOOLEAN --- + LeaveCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) --- + DeleteCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) --- - RemoveDirectoryW :: proc(lpPathName: LPCWSTR) -> BOOL --- - SetFileAttributesW :: proc(lpFileName: LPCWSTR, dwFileAttributes: DWORD) -> BOOL --- - SetLastError :: proc(dwErrCode: DWORD) --- - GetCommTimeouts :: proc(handle: HANDLE, timeouts: ^COMMTIMEOUTS) -> BOOL --- - SetCommTimeouts :: proc(handle: HANDLE, timeouts: ^COMMTIMEOUTS) -> BOOL --- - ClearCommError :: proc(hFile: HANDLE, lpErrors: ^Com_Error, lpStat: ^COMSTAT) -> BOOL --- - GetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- - SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- - SetCommMask :: proc(handle: HANDLE, dwEvtMap: DWORD) -> BOOL --- - GetCommMask :: proc(handle: HANDLE, lpEvtMask: LPDWORD) -> BOOL --- - WaitCommEvent :: proc(handle: HANDLE, lpEvtMask: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL --- - GetCommandLineW :: proc() -> LPCWSTR --- - GetTempPathW :: proc(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD --- - GetTempFileNameW :: proc(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: c_int, lpTempFileName: LPWSTR) -> c_uint --- - GetCurrentProcess :: proc() -> HANDLE --- + RemoveDirectoryW :: proc(lpPathName: LPCWSTR) -> BOOL --- + SetFileAttributesW :: proc(lpFileName: LPCWSTR, dwFileAttributes: DWORD) -> BOOL --- + SetLastError :: proc(dwErrCode: DWORD) --- + GetCommTimeouts :: proc(handle: HANDLE, timeouts: ^COMMTIMEOUTS) -> BOOL --- + SetCommTimeouts :: proc(handle: HANDLE, timeouts: ^COMMTIMEOUTS) -> BOOL --- + ClearCommError :: proc(hFile: HANDLE, lpErrors: ^Com_Error, lpStat: ^COMSTAT) -> BOOL --- + GetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- + SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- + SetCommMask :: proc(handle: HANDLE, dwEvtMap: DWORD) -> BOOL --- + GetCommMask :: proc(handle: HANDLE, lpEvtMask: LPDWORD) -> BOOL --- + WaitCommEvent :: proc(handle: HANDLE, lpEvtMask: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL --- + GetCommandLineW :: proc() -> LPCWSTR --- + GetTempPathW :: proc(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD --- + GetTempFileNameW :: proc(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: c_int, lpTempFileName: LPWSTR) -> c_uint --- + GetCurrentProcess :: proc() -> HANDLE --- GetCurrentProcessId :: proc() -> DWORD --- - GetCurrentThread :: proc() -> HANDLE --- - GetCurrentThreadId :: proc() -> DWORD --- + GetCurrentThread :: proc() -> HANDLE --- + GetCurrentThreadId :: proc() -> DWORD --- GetProcessTimes :: proc( hProcess: HANDLE, lpCreationTime: LPFILETIME, @@ -136,7 +148,7 @@ foreign kernel32 { lpUserTime: LPFILETIME, ) -> BOOL --- GetStdHandle :: proc(which: DWORD) -> HANDLE --- - ExitProcess :: proc(uExitCode: c_uint) -> ! --- + ExitProcess :: proc(uExitCode: c_uint) -> ! --- DeviceIoControl :: proc( hDevice: HANDLE, dwIoControlCode: DWORD, @@ -164,15 +176,15 @@ foreign kernel32 { dwCreationFlags: DWORD, lpThreadId: LPDWORD, ) -> HANDLE --- - SwitchToThread :: proc() -> BOOL --- - ResumeThread :: proc(thread: HANDLE) -> DWORD --- - GetThreadPriority :: proc(thread: HANDLE) -> c_int --- - SetThreadPriority :: proc(thread: HANDLE, priority: c_int) -> BOOL --- + SwitchToThread :: proc() -> BOOL --- + ResumeThread :: proc(thread: HANDLE) -> DWORD --- + GetThreadPriority :: proc(thread: HANDLE) -> c_int --- + SetThreadPriority :: proc(thread: HANDLE, priority: c_int) -> BOOL --- GetThreadDescription :: proc(hThread: HANDLE, ppszThreadDescription: ^PWSTR) -> HRESULT --- SetThreadDescription :: proc(hThread: HANDLE, lpThreadDescription: PCWSTR) -> HRESULT --- - GetExitCodeThread :: proc(thread: HANDLE, exit_code: ^DWORD) -> BOOL --- - TerminateThread :: proc(thread: HANDLE, exit_code: DWORD) -> BOOL --- - SuspendThread :: proc(hThread: HANDLE) -> DWORD --- + GetExitCodeThread :: proc(thread: HANDLE, exit_code: ^DWORD) -> BOOL --- + TerminateThread :: proc(thread: HANDLE, exit_code: DWORD) -> BOOL --- + SuspendThread :: proc(hThread: HANDLE) -> DWORD --- GetProcessAffinityMask :: proc( hProcess: HANDLE, @@ -213,6 +225,16 @@ foreign kernel32 { ) -> BOOL --- WaitForSingleObject :: proc(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD --- WaitForSingleObjectEx :: proc(hHandle: HANDLE, dwMilliseconds: DWORD, bAlterable: BOOL) -> DWORD --- + EnterSynchronizationBarrier :: proc( + lpBarrier: ^SYNCHRONIZATION_BARRIER, + dwFlags: SYNCHRONIZATION_BARRIER_FLAGS, + ) -> BOOL --- + InitializeSynchronizationBarrier :: proc( + lpBarrier: ^SYNCHRONIZATION_BARRIER, + lTotalThreads: LONG, + lSpinCount: LONG, + ) -> BOOL --- + DeleteSynchronizationBarrier :: proc(lpBarrier: ^SYNCHRONIZATION_BARRIER) -> BOOL --- Sleep :: proc(dwMilliseconds: DWORD) --- GetProcessId :: proc(handle: HANDLE) -> DWORD --- CopyFileW :: proc( @@ -237,17 +259,17 @@ foreign kernel32 { nsize: DWORD, args: rawptr, ) -> DWORD --- - TlsAlloc :: proc() -> DWORD --- - TlsFree :: proc(dwTlsIndex: DWORD) -> BOOL --- - TlsGetValue :: proc(dwTlsIndex: DWORD) -> LPVOID --- - TlsSetValue :: proc(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL --- - GetLastError :: proc() -> DWORD --- + TlsAlloc :: proc() -> DWORD --- + TlsFree :: proc(dwTlsIndex: DWORD) -> BOOL --- + TlsGetValue :: proc(dwTlsIndex: DWORD) -> LPVOID --- + TlsSetValue :: proc(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL --- + GetLastError :: proc() -> DWORD --- QueryPerformanceFrequency :: proc(lpFrequency: ^LARGE_INTEGER) -> BOOL --- - QueryPerformanceCounter :: proc(lpPerformanceCount: ^LARGE_INTEGER) -> BOOL --- - GetExitCodeProcess :: proc(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL --- - TerminateProcess :: proc(hProcess: HANDLE, uExitCode: UINT) -> BOOL --- - OpenProcess :: proc(dwDesiredAccess: DWORD, bInheritHandle: BOOL, dwProcessId: DWORD) -> HANDLE --- - OpenThread :: proc(dwDesiredAccess: DWORD, bInheritHandle: BOOL, dwThreadId: DWORD) -> HANDLE --- + QueryPerformanceCounter :: proc(lpPerformanceCount: ^LARGE_INTEGER) -> BOOL --- + GetExitCodeProcess :: proc(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL --- + TerminateProcess :: proc(hProcess: HANDLE, uExitCode: UINT) -> BOOL --- + OpenProcess :: proc(dwDesiredAccess: DWORD, bInheritHandle: BOOL, dwProcessId: DWORD) -> HANDLE --- + OpenThread :: proc(dwDesiredAccess: DWORD, bInheritHandle: BOOL, dwThreadId: DWORD) -> HANDLE --- GetThreadContext :: proc( hThread: HANDLE, lpContext: LPCONTEXT, @@ -366,14 +388,14 @@ foreign kernel32 { ) -> BOOL --- CompareFileTime :: proc(lpFileTime1: LPFILETIME, lpFileTime2: LPFILETIME) -> LONG --- - FindFirstFileW :: proc(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE --- - FindNextFileW :: proc(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL --- - FindClose :: proc(findFile: HANDLE) -> BOOL --- - GetModuleHandleW :: proc(lpModuleName: LPCWSTR) -> HMODULE --- - GetModuleHandleA :: proc(lpModuleName: LPCSTR) -> HMODULE --- - GetSystemTimeAsFileTime :: proc(lpSystemTimeAsFileTime: LPFILETIME) --- - GetSystemTimePreciseAsFileTime :: proc(lpSystemTimeAsFileTime: LPFILETIME) --- - FileTimeToSystemTime :: proc(lpFileTime: ^FILETIME, lpSystemTime: ^SYSTEMTIME) -> BOOL --- + FindFirstFileW :: proc(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE --- + FindNextFileW :: proc(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL --- + FindClose :: proc(findFile: HANDLE) -> BOOL --- + GetModuleHandleW :: proc(lpModuleName: LPCWSTR) -> HMODULE --- + GetModuleHandleA :: proc(lpModuleName: LPCSTR) -> HMODULE --- + GetSystemTimeAsFileTime :: proc(lpSystemTimeAsFileTime: LPFILETIME) --- + GetSystemTimePreciseAsFileTime :: proc(lpSystemTimeAsFileTime: LPFILETIME) --- + FileTimeToSystemTime :: proc(lpFileTime: ^FILETIME, lpSystemTime: ^SYSTEMTIME) -> BOOL --- SystemTimeToTzSpecificLocalTime :: proc( lpTimeZoneInformation: ^TIME_ZONE_INFORMATION, lpUniversalTime: ^SYSTEMTIME, @@ -428,7 +450,7 @@ foreign kernel32 { lpTotalBytesAvail: ^u32, lpBytesLeftThisMessage: ^u32, ) -> BOOL --- - CancelIo :: proc(handle: HANDLE) -> BOOL --- + CancelIo :: proc(handle: HANDLE) -> BOOL --- CancelIoEx :: proc(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) -> BOOL --- GetOverlappedResult :: proc( hFile: HANDLE, @@ -437,19 +459,20 @@ foreign kernel32 { bWait: BOOL, ) -> BOOL --- GetProcessHeap :: proc() -> HANDLE --- - HeapAlloc :: proc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID --- - HeapReAlloc :: proc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID --- - HeapFree :: proc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL --- + HeapAlloc :: proc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID --- + HeapReAlloc :: proc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID --- + HeapFree :: proc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL --- - LocalAlloc :: proc(flags: UINT, bytes: SIZE_T) -> LPVOID --- + LocalAlloc :: proc(flags: UINT, bytes: SIZE_T) -> LPVOID --- LocalReAlloc :: proc(mem: LPVOID, bytes: SIZE_T, flags: UINT) -> LPVOID --- - LocalFree :: proc(mem: LPVOID) -> LPVOID --- + LocalFree :: proc(mem: LPVOID) -> LPVOID --- - GlobalAlloc :: proc(flags: UINT, bytes: SIZE_T) -> LPVOID --- + GlobalAlloc :: proc(flags: UINT, bytes: SIZE_T) -> LPVOID --- GlobalReAlloc :: proc(mem: LPVOID, bytes: SIZE_T, flags: UINT) -> LPVOID --- - GlobalFree :: proc(mem: LPVOID) -> LPVOID --- + GlobalFree :: proc(mem: LPVOID) -> LPVOID --- + GlobalSize :: proc(Mem: LPVOID) -> SIZE_T --- - GlobalLock :: proc(hMem: HGLOBAL) -> LPVOID --- + GlobalLock :: proc(hMem: HGLOBAL) -> LPVOID --- GlobalUnlock :: proc(hMem: HGLOBAL) -> BOOL --- ReadDirectoryChangesW :: proc( @@ -462,21 +485,32 @@ foreign kernel32 { lpOverlapped: LPOVERLAPPED, lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE, ) -> BOOL --- + ReadDirectoryChangesExW :: proc( + hDirectory: HANDLE, + lpBuffer: LPVOID, + nBufferLength: DWORD, + bWatchSubtree: BOOL, + dwNotifyFilter: DWORD, + lpBytesReturned: LPDWORD, + lpOverlapped: LPOVERLAPPED, + lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE, + ReadDirectoryNotifyInformationClass: READ_DIRECTORY_NOTIFY_INFORMATION_CLASS, + ) -> BOOL --- FindFirstChangeNotificationW :: proc( lpPathName: LPWSTR, bWatchSubtree: BOOL, dwNotifyFilter: DWORD, ) -> HANDLE --- - FindNextChangeNotification :: proc(hChangeHandle: HANDLE) -> BOOL --- + FindNextChangeNotification :: proc(hChangeHandle: HANDLE) -> BOOL --- FindCloseChangeNotification :: proc(hChangeHandle: HANDLE) -> BOOL --- InitializeSRWLock :: proc(SRWLock: ^SRWLOCK) --- AcquireSRWLockExclusive :: proc(SRWLock: ^SRWLOCK) --- TryAcquireSRWLockExclusive :: proc(SRWLock: ^SRWLOCK) -> BOOLEAN --- ReleaseSRWLockExclusive :: proc(SRWLock: ^SRWLOCK) --- - AcquireSRWLockShared :: proc(SRWLock: ^SRWLOCK) --- - TryAcquireSRWLockShared :: proc(SRWLock: ^SRWLOCK) -> BOOLEAN --- - ReleaseSRWLockShared :: proc(SRWLock: ^SRWLOCK) --- + AcquireSRWLockShared :: proc(SRWLock: ^SRWLOCK) --- + TryAcquireSRWLockShared :: proc(SRWLock: ^SRWLOCK) -> BOOLEAN --- + ReleaseSRWLockShared :: proc(SRWLock: ^SRWLOCK) --- InitializeConditionVariable :: proc(ConditionVariable: ^CONDITION_VARIABLE) --- WakeConditionVariable :: proc(ConditionVariable: ^CONDITION_VARIABLE) --- @@ -485,42 +519,42 @@ foreign kernel32 { SleepConditionVariableSRW :: proc(ConditionVariable: ^CONDITION_VARIABLE, SRWLock: ^SRWLOCK, dwMilliseconds: DWORD, Flags: LONG) -> BOOL --- - GetFileType :: proc(file_handle: HANDLE) -> DWORD --- - SetFilePointer :: proc(file_handle: HANDLE, distance_to_move: LONG, distance_to_move_high: ^LONG, move_method: DWORD) -> DWORD --- - GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^LARGE_INTEGER) -> BOOL --- - GetFileAttributesW :: proc(lpFileName: LPCWSTR) -> DWORD --- - GetFileAttributesExW :: proc(lpFileName: LPCWSTR, fInfoLevelId: GET_FILEEX_INFO_LEVELS, lpFileInformation: LPVOID) -> BOOL --- - GetSystemInfo :: proc(system_info: ^SYSTEM_INFO) --- - GetVersionExW :: proc(osvi: ^OSVERSIONINFOEXW) --- - GetSystemDirectoryW :: proc(lpBuffer: LPWSTR, uSize: UINT) -> UINT --- - GetWindowsDirectoryW :: proc(lpBuffer: LPWSTR, uSize: UINT) -> UINT --- - GetSystemDefaultLangID :: proc() -> LANGID --- - GetSystemDefaultLCID :: proc() -> LCID --- + GetFileType :: proc(file_handle: HANDLE) -> DWORD --- + SetFilePointer :: proc(file_handle: HANDLE, distance_to_move: LONG, distance_to_move_high: ^LONG, move_method: DWORD) -> DWORD --- + GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^LARGE_INTEGER) -> BOOL --- + GetFileAttributesW :: proc(lpFileName: LPCWSTR) -> DWORD --- + GetFileAttributesExW :: proc(lpFileName: LPCWSTR, fInfoLevelId: GET_FILEEX_INFO_LEVELS, lpFileInformation: LPVOID) -> BOOL --- + GetSystemInfo :: proc(system_info: ^SYSTEM_INFO) --- + GetVersionExW :: proc(osvi: ^OSVERSIONINFOEXW) --- + GetSystemDirectoryW :: proc(lpBuffer: LPWSTR, uSize: UINT) -> UINT --- + GetWindowsDirectoryW :: proc(lpBuffer: LPWSTR, uSize: UINT) -> UINT --- + GetSystemDefaultLangID :: proc() -> LANGID --- + GetSystemDefaultLCID :: proc() -> LCID --- GetSystemDefaultLocaleName :: proc(lpLocaleName: LPWSTR, cchLocaleName: INT) -> INT --- - LCIDToLocaleName :: proc(Locale: LCID, lpName: LPWSTR, cchName: INT, dwFlags: DWORD) -> INT --- - LocaleNameToLCID :: proc(lpName: LPCWSTR, dwFlags: DWORD) -> LCID --- - SetDllDirectoryW :: proc(lpPathName: LPCWSTR) -> BOOL --- - AddDllDirectory :: proc(NewDirectory: PCWSTR) -> rawptr --- - RemoveDllDirectory :: proc(Cookie: rawptr) -> BOOL --- - LoadLibraryW :: proc(c_str: LPCWSTR) -> HMODULE --- - LoadLibraryExW :: proc(c_str: LPCWSTR, hFile: HANDLE, dwFlags: LoadLibraryEx_Flags) -> HMODULE --- - FreeLibrary :: proc(h: HMODULE) -> BOOL --- - FreeLibraryAndExitThread :: proc(hLibModule: HMODULE, dwExitCode: DWORD) -> VOID --- - GetProcAddress :: proc(h: HMODULE, c_str: LPCSTR) -> rawptr --- + LCIDToLocaleName :: proc(Locale: LCID, lpName: LPWSTR, cchName: INT, dwFlags: DWORD) -> INT --- + LocaleNameToLCID :: proc(lpName: LPCWSTR, dwFlags: DWORD) -> LCID --- + SetDllDirectoryW :: proc(lpPathName: LPCWSTR) -> BOOL --- + AddDllDirectory :: proc(NewDirectory: PCWSTR) -> rawptr --- + RemoveDllDirectory :: proc(Cookie: rawptr) -> BOOL --- + LoadLibraryW :: proc(c_str: LPCWSTR) -> HMODULE --- + LoadLibraryExW :: proc(c_str: LPCWSTR, hFile: HANDLE, dwFlags: LoadLibraryEx_Flags) -> HMODULE --- + FreeLibrary :: proc(h: HMODULE) -> BOOL --- + FreeLibraryAndExitThread :: proc(hLibModule: HMODULE, dwExitCode: DWORD) --- + GetProcAddress :: proc(h: HMODULE, c_str: LPCSTR) -> rawptr --- - LoadResource :: proc(hModule: HMODULE, hResInfo: HRSRC) -> HGLOBAL --- - FreeResource :: proc(hResData: HGLOBAL) -> BOOL --- - LockResource :: proc(hResData: HGLOBAL) -> LPVOID --- - SizeofResource :: proc(hModule: HMODULE, hResInfo: HRSRC) -> DWORD --- - FindResourceW :: proc(hModule: HMODULE, lpName: LPCWSTR, lpType: LPCWSTR) -> HRSRC --- - FindResourceExW :: proc(hModule: HMODULE, lpType: LPCWSTR, lpName: LPCWSTR, wLanguage: LANGID) -> HRSRC --- - EnumResourceNamesW :: proc(hModule: HMODULE, lpType: LPCWSTR, lpEnumFunc: ENUMRESNAMEPROCW, lParam: LONG_PTR) -> BOOL --- - EnumResourceNamesExW :: proc(hModule: HMODULE, lpType: LPCWSTR, lpEnumFunc: ENUMRESNAMEPROCW, lParam: LONG_PTR, dwFlags: DWORD, LangId: LANGID) -> BOOL --- - EnumResourceTypesExW :: proc(hModule: HMODULE, lpEnumFunc: ENUMRESTYPEPROCW, lParam: LONG_PTR, dwFlags: DWORD, LangId: LANGID) -> BOOL --- - EnumResourceLanguagesExW :: proc(hModule: HMODULE, lpType: LPCWSTR, lpName: LPCWSTR, lpEnumFunc: ENUMRESLANGPROCW, lParam: LONG_PTR, dwFlags: DWORD, LangId: LANGID) -> BOOL --- - LookupIconIdFromDirectory :: proc(presbits: PBYTE, fIcon: BOOL) -> INT --- + LoadResource :: proc(hModule: HMODULE, hResInfo: HRSRC) -> HGLOBAL --- + FreeResource :: proc(hResData: HGLOBAL) -> BOOL --- + LockResource :: proc(hResData: HGLOBAL) -> LPVOID --- + SizeofResource :: proc(hModule: HMODULE, hResInfo: HRSRC) -> DWORD --- + FindResourceW :: proc(hModule: HMODULE, lpName: LPCWSTR, lpType: LPCWSTR) -> HRSRC --- + FindResourceExW :: proc(hModule: HMODULE, lpType: LPCWSTR, lpName: LPCWSTR, wLanguage: LANGID) -> HRSRC --- + EnumResourceNamesW :: proc(hModule: HMODULE, lpType: LPCWSTR, lpEnumFunc: ENUMRESNAMEPROCW, lParam: LONG_PTR) -> BOOL --- + EnumResourceNamesExW :: proc(hModule: HMODULE, lpType: LPCWSTR, lpEnumFunc: ENUMRESNAMEPROCW, lParam: LONG_PTR, dwFlags: DWORD, LangId: LANGID) -> BOOL --- + EnumResourceTypesExW :: proc(hModule: HMODULE, lpEnumFunc: ENUMRESTYPEPROCW, lParam: LONG_PTR, dwFlags: DWORD, LangId: LANGID) -> BOOL --- + EnumResourceLanguagesExW :: proc(hModule: HMODULE, lpType: LPCWSTR, lpName: LPCWSTR, lpEnumFunc: ENUMRESLANGPROCW, lParam: LONG_PTR, dwFlags: DWORD, LangId: LANGID) -> BOOL --- + LookupIconIdFromDirectory :: proc(presbits: PBYTE, fIcon: BOOL) -> INT --- LookupIconIdFromDirectoryEx :: proc(presbits: PBYTE, fIcon: BOOL, cxDesired: INT, cyDesired: INT, Flags: UINT) -> INT --- - CreateIconFromResourceEx :: proc(presbits: PBYTE, dwResSize: DWORD, fIcon: BOOL, dwVer: DWORD, cxDesired: INT, cyDesired: INT, Flags: UINT) -> HICON --- + CreateIconFromResourceEx :: proc(presbits: PBYTE, dwResSize: DWORD, fIcon: BOOL, dwVer: DWORD, cxDesired: INT, cyDesired: INT, Flags: UINT) -> HICON --- GetFullPathNameW :: proc(filename: LPCWSTR, buffer_length: DWORD, buffer: LPCWSTR, file_part: ^LPCWSTR) -> DWORD --- GetLongPathNameW :: proc(short, long: LPCWSTR, len: DWORD) -> DWORD --- @@ -533,21 +567,21 @@ foreign kernel32 { CreatePipe :: proc(hReadPipe, hWritePipe: ^HANDLE, lpPipeAttributes: LPSECURITY_ATTRIBUTES, nSize: DWORD) -> BOOL --- - ConnectNamedPipe :: proc(hNamedPipe: HANDLE, lpOverlapped: LPOVERLAPPED) -> BOOL --- + ConnectNamedPipe :: proc(hNamedPipe: HANDLE, lpOverlapped: LPOVERLAPPED) -> BOOL --- DisconnectNamedPipe :: proc(hNamedPipe: HANDLE) -> BOOL --- - WaitNamedPipeW :: proc(lpNamedPipeName: LPCWSTR, nTimeOut: DWORD) -> BOOL --- + WaitNamedPipeW :: proc(lpNamedPipeName: LPCWSTR, nTimeOut: DWORD) -> BOOL --- - AllocConsole :: proc() -> BOOL --- - AttachConsole :: proc(dwProcessId: DWORD) -> BOOL --- - SetConsoleCtrlHandler :: proc(HandlerRoutine: PHANDLER_ROUTINE, Add: BOOL) -> BOOL --- - GenerateConsoleCtrlEvent :: proc(dwCtrlEvent: DWORD, dwProcessGroupId: DWORD) -> BOOL --- - FreeConsole :: proc() -> BOOL --- - GetConsoleWindow :: proc() -> HWND --- + AllocConsole :: proc() -> BOOL --- + AttachConsole :: proc(dwProcessId: DWORD) -> BOOL --- + SetConsoleCtrlHandler :: proc(HandlerRoutine: PHANDLER_ROUTINE, Add: BOOL) -> BOOL --- + GenerateConsoleCtrlEvent :: proc(dwCtrlEvent: DWORD, dwProcessGroupId: DWORD) -> BOOL --- + FreeConsole :: proc() -> BOOL --- + GetConsoleWindow :: proc() -> HWND --- GetConsoleScreenBufferInfo :: proc(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: PCONSOLE_SCREEN_BUFFER_INFO) -> BOOL --- SetConsoleScreenBufferSize :: proc(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL --- - SetConsoleWindowInfo :: proc(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: ^SMALL_RECT) -> BOOL --- - GetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL --- - SetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL --- + SetConsoleWindowInfo :: proc(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: ^SMALL_RECT) -> BOOL --- + GetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL --- + SetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL --- GetDiskFreeSpaceExW :: proc( lpDirectoryName: LPCWSTR, @@ -561,20 +595,33 @@ foreign kernel32 { // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setfilecompletionnotificationmodes) SetFileCompletionNotificationModes :: proc(FileHandle: HANDLE, Flags: u8) -> BOOL --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-createiocompletionport) - CreateIoCompletionPort :: proc(FileHandle: HANDLE, ExistingCompletionPort: HANDLE, CompletionKey: ULONG_PTR, NumberOfConcurrentThreads: DWORD) -> HANDLE --- + CreateIoCompletionPort :: proc(FileHandle: HANDLE, ExistingCompletionPort: HANDLE, CompletionKey: ULONG_PTR, NumberOfConcurrentThreads: DWORD) -> HANDLE --- //[MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-getqueuedcompletionstatus) - GetQueuedCompletionStatus :: proc(CompletionPort: HANDLE, lpNumberOfBytesTransferred: ^DWORD, lpCompletionKey: PULONG_PTR, lpOverlapped: ^^OVERLAPPED, dwMilliseconds: DWORD) -> BOOL --- + GetQueuedCompletionStatus :: proc(CompletionPort: HANDLE, lpNumberOfBytesTransferred: ^DWORD, lpCompletionKey: PULONG_PTR, lpOverlapped: ^^OVERLAPPED, dwMilliseconds: DWORD) -> BOOL --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-getqueuedcompletionstatusex) - GetQueuedCompletionStatusEx :: proc(CompletionPort: HANDLE, lpCompletionPortEntries: ^OVERLAPPED_ENTRY, ulCount: c_ulong, ulNumEntriesRemoved: ^c_ulong, dwMilliseconds: DWORD, fAlertable: BOOL) -> BOOL --- + GetQueuedCompletionStatusEx :: proc(CompletionPort: HANDLE, lpCompletionPortEntries: ^OVERLAPPED_ENTRY, ulCount: c_ulong, ulNumEntriesRemoved: ^c_ulong, dwMilliseconds: DWORD, fAlertable: BOOL) -> BOOL --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-postqueuedcompletionstatus) - PostQueuedCompletionStatus :: proc(CompletionPort: HANDLE, dwNumberOfBytesTransferred: DWORD, dwCompletionKey: c_ulong, lpOverlapped: ^OVERLAPPED) -> BOOL --- + PostQueuedCompletionStatus :: proc(CompletionPort: HANDLE, dwNumberOfBytesTransferred: DWORD, dwCompletionKey: ULONG_PTR, lpOverlapped: ^OVERLAPPED) -> BOOL --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation) - GetHandleInformation :: proc(hObject: HANDLE, lpdwFlags: ^DWORD) -> BOOL --- + GetHandleInformation :: proc(hObject: HANDLE, lpdwFlags: ^DWORD) -> BOOL --- RtlCaptureStackBackTrace :: proc(FramesToSkip: ULONG, FramesToCapture: ULONG, BackTrace: [^]PVOID, BackTraceHash: PULONG) -> USHORT --- RtlNtStatusToDosError :: proc(status: NTSTATUS) -> ULONG --- GetSystemPowerStatus :: proc(lpSystemPowerStatus: ^SYSTEM_POWER_STATUS) -> BOOL --- + + RegisterWaitForSingleObject :: proc( + phNewWaitObject: PHANDLE, + hObject: HANDLE, + Callback: WAITORTIMERCALLBACK, + Context: PVOID, + dwMilliseconds: ULONG, + dwFlags: ULONG, + ) -> BOOL --- + + UnregisterWaitEx :: proc(WaitHandle: HANDLE, CompletionEvent: HANDLE) -> BOOL --- + + QueueUserAPC :: proc(pfnAPC: PAPCFUNC, hThread: HANDLE, dwData: ULONG_PTR) -> DWORD --- } DEBUG_PROCESS :: 0x00000001 @@ -625,44 +672,44 @@ THREAD_PRIORITY_IDLE :: THREAD_BASE_PRIORITY_IDLE THREAD_MODE_BACKGROUND_BEGIN :: 0x00010000 THREAD_MODE_BACKGROUND_END :: 0x00020000 -PROCESS_ALL_ACCESS :: 0x000F0000 | SYNCHRONIZE | 0xFFFF -PROCESS_CREATE_PROCESS :: 0x0080 -PROCESS_CREATE_THREAD :: 0x0002 -PROCESS_DUP_HANDLE :: 0x0040 -PROCESS_QUERY_INFORMATION :: 0x0400 +PROCESS_ALL_ACCESS :: 0x000F0000 | SYNCHRONIZE | 0xFFFF +PROCESS_CREATE_PROCESS :: 0x0080 +PROCESS_CREATE_THREAD :: 0x0002 +PROCESS_DUP_HANDLE :: 0x0040 +PROCESS_QUERY_INFORMATION :: 0x0400 PROCESS_QUERY_LIMITED_INFORMATION :: 0x1000 -PROCESS_SET_INFORMATION :: 0x0200 -PROCESS_SET_QUOTA :: 0x0100 -PROCESS_SUSPEND_RESUME :: 0x0800 -PROCESS_TERMINATE :: 0x0001 -PROCESS_VM_OPERATION :: 0x0008 -PROCESS_VM_READ :: 0x0010 -PROCESS_VM_WRITE :: 0x0020 +PROCESS_SET_INFORMATION :: 0x0200 +PROCESS_SET_QUOTA :: 0x0100 +PROCESS_SUSPEND_RESUME :: 0x0800 +PROCESS_TERMINATE :: 0x0001 +PROCESS_VM_OPERATION :: 0x0008 +PROCESS_VM_READ :: 0x0010 +PROCESS_VM_WRITE :: 0x0020 THREAD_ALL_ACCESS :: \ - THREAD_DIRECT_IMPERSONATION | - THREAD_GET_CONTEXT | - THREAD_IMPERSONATE | - THREAD_QUERY_INFORMATION | + THREAD_DIRECT_IMPERSONATION | + THREAD_GET_CONTEXT | + THREAD_IMPERSONATE | + THREAD_QUERY_INFORMATION | THREAD_QUERY_LIMITED_INFORMATION | - THREAD_SET_CONTEXT | - THREAD_SET_INFORMATION | - THREAD_SET_LIMITED_INFORMATION | - THREAD_SET_THREAD_TOKEN | - THREAD_SUSPEND_RESUME | - THREAD_TERMINATE | + THREAD_SET_CONTEXT | + THREAD_SET_INFORMATION | + THREAD_SET_LIMITED_INFORMATION | + THREAD_SET_THREAD_TOKEN | + THREAD_SUSPEND_RESUME | + THREAD_TERMINATE | SYNCHRONIZE -THREAD_DIRECT_IMPERSONATION :: 0x0200 -THREAD_GET_CONTEXT :: 0x0008 -THREAD_IMPERSONATE :: 0x0100 -THREAD_QUERY_INFORMATION :: 0x0040 +THREAD_DIRECT_IMPERSONATION :: 0x0200 +THREAD_GET_CONTEXT :: 0x0008 +THREAD_IMPERSONATE :: 0x0100 +THREAD_QUERY_INFORMATION :: 0x0040 THREAD_QUERY_LIMITED_INFORMATION :: 0x0800 -THREAD_SET_CONTEXT :: 0x0010 -THREAD_SET_INFORMATION :: 0x0020 -THREAD_SET_LIMITED_INFORMATION :: 0x0400 -THREAD_SET_THREAD_TOKEN :: 0x0080 -THREAD_SUSPEND_RESUME :: 0x0002 -THREAD_TERMINATE :: 0x0001 +THREAD_SET_CONTEXT :: 0x0010 +THREAD_SET_INFORMATION :: 0x0020 +THREAD_SET_LIMITED_INFORMATION :: 0x0400 +THREAD_SET_THREAD_TOKEN :: 0x0080 +THREAD_SUSPEND_RESUME :: 0x0002 +THREAD_TERMINATE :: 0x0001 COPY_FILE_FAIL_IF_EXISTS :: 0x00000001 COPY_FILE_RESTARTABLE :: 0x00000002 @@ -701,7 +748,7 @@ FILE_MAP_TARGETS_INVALID :: DWORD(0x40000000) FILE_MAP_LARGE_PAGES :: DWORD(0x20000000) LOCKFILE_FAIL_IMMEDIATELY :: DWORD (0x00000001) -LOCKFILE_EXCLUSIVE_LOCK :: DWORD(0x00000002) +LOCKFILE_EXCLUSIVE_LOCK :: DWORD(0x00000002) // Flags for `SetFileCompletionNotificationModes`. FILE_SKIP_COMPLETION_PORT_ON_SUCCESS :: 0x1 @@ -720,16 +767,16 @@ PAGE_NOCACHE :: 0x200 PAGE_WRITECOMBINE :: 0x400 MEMORY_BASIC_INFORMATION :: struct { - BaseAddress: PVOID, - AllocationBase: PVOID, + BaseAddress: PVOID, + AllocationBase: PVOID, AllocationProtect: DWORD, - PartitionId: WORD, - RegionSize: SIZE_T, - State: DWORD, - Protect: DWORD, - Type: DWORD, + PartitionId: WORD, + RegionSize: SIZE_T, + State: DWORD, + Protect: DWORD, + Type: DWORD, } -PMEMORY_BASIC_INFORMATION :: ^MEMORY_BASIC_INFORMATION +PMEMORY_BASIC_INFORMATION :: ^MEMORY_BASIC_INFORMATION LPMEMORY_BASIC_INFORMATION :: ^MEMORY_BASIC_INFORMATION MEM_COMMIT :: 0x1000 @@ -747,97 +794,97 @@ MEM_4MB_PAGES :: 0x80000000 @(default_calling_convention="system") foreign kernel32 { VirtualAlloc :: proc( - lpAddress: LPVOID, - dwSize: SIZE_T, + lpAddress: LPVOID, + dwSize: SIZE_T, flAllocationType: DWORD, - flProtect: DWORD, + flProtect: DWORD, ) -> LPVOID --- VirtualProtect :: proc( - lpAddress: LPVOID, - dwSize: SIZE_T, - flNewProtect: DWORD, + lpAddress: LPVOID, + dwSize: SIZE_T, + flNewProtect: DWORD, lpflOldProtect: PDWORD, ) -> BOOL --- VirtualFree :: proc( - lpAddress: LPVOID, - dwSize: SIZE_T, + lpAddress: LPVOID, + dwSize: SIZE_T, dwFreeType: DWORD, ) -> BOOL --- VirtualQuery :: proc( lpAddress: LPCVOID, - lpBuffer: PMEMORY_BASIC_INFORMATION, - dwLength: SIZE_T, + lpBuffer: PMEMORY_BASIC_INFORMATION, + dwLength: SIZE_T, ) -> SIZE_T --- VirtualAllocEx :: proc( - hProcess: HANDLE, - lpAddress: LPVOID, - dwSize: SIZE_T, + hProcess: HANDLE, + lpAddress: LPVOID, + dwSize: SIZE_T, flAllocationType: DWORD, - flProtect: DWORD, + flProtect: DWORD, ) -> LPVOID --- VirtualFreeEx :: proc( - hProcess: HANDLE, - lpAddress: LPVOID, - dwSize: SIZE_T, + hProcess: HANDLE, + lpAddress: LPVOID, + dwSize: SIZE_T, dwFreeType: DWORD, ) -> BOOL --- VirtualProtectEx :: proc( - hProcess: HANDLE, - lpAddress: LPVOID, - dwSize: SIZE_T, - flNewProtect: DWORD, + hProcess: HANDLE, + lpAddress: LPVOID, + dwSize: SIZE_T, + flNewProtect: DWORD, lpflOldProtect: PDWORD, ) -> BOOL --- VirtualQueryEx :: proc( - hProcess: HANDLE, + hProcess: HANDLE, lpAddress: LPCVOID, - lpBuffer: PMEMORY_BASIC_INFORMATION, - dwLength: SIZE_T, + lpBuffer: PMEMORY_BASIC_INFORMATION, + dwLength: SIZE_T, ) -> SIZE_T --- ReadProcessMemory :: proc( - hProcess: HANDLE, - lpBaseAddress: LPCVOID, - lpBuffer: LPVOID, - nSize: SIZE_T, + hProcess: HANDLE, + lpBaseAddress: LPCVOID, + lpBuffer: LPVOID, + nSize: SIZE_T, lpNumberOfBytesRead: ^SIZE_T, ) -> BOOL --- WriteProcessMemory :: proc( - hProcess: HANDLE, - lpBaseAddress: LPVOID, - lpBuffer: LPCVOID, - nSize: SIZE_T, + hProcess: HANDLE, + lpBaseAddress: LPVOID, + lpBuffer: LPCVOID, + nSize: SIZE_T, lpNumberOfBytesWritten: ^SIZE_T, ) -> BOOL --- CreateFileMappingW :: proc( - hFile: HANDLE, + hFile: HANDLE, lpFileMappingAttributes: LPSECURITY_ATTRIBUTES, - flProtect: DWORD, - dwMaximumSizeHigh: DWORD, - dwMaximumSizeLow: DWORD, - lpName: LPCWSTR, + flProtect: DWORD, + dwMaximumSizeHigh: DWORD, + dwMaximumSizeLow: DWORD, + lpName: LPCWSTR, ) -> HANDLE --- OpenFileMappingW :: proc( dwDesiredAccess: DWORD, - bInheritHandle: BOOL, - lpName: LPCWSTR, + bInheritHandle: BOOL, + lpName: LPCWSTR, ) -> HANDLE --- MapViewOfFile :: proc( - hFileMappingObject: HANDLE, - dwDesiredAccess: DWORD, - dwFileOffsetHigh: DWORD, - dwFileOffsetLow: DWORD, + hFileMappingObject: HANDLE, + dwDesiredAccess: DWORD, + dwFileOffsetHigh: DWORD, + dwFileOffsetLow: DWORD, dwNumberOfBytesToMap: SIZE_T, ) -> LPVOID --- MapViewOfFileEx :: proc( - hFileMappingObject: HANDLE, - dwDesiredAccess: DWORD, - dwFileOffsetHigh: DWORD, - dwFileOffsetLow: DWORD, + hFileMappingObject: HANDLE, + dwDesiredAccess: DWORD, + dwFileOffsetHigh: DWORD, + dwFileOffsetLow: DWORD, dwNumberOfBytesToMap: SIZE_T, - lpBaseAddress: LPVOID, + lpBaseAddress: LPVOID, ) -> LPVOID --- FlushViewOfFile :: proc( - lpBaseAddress: LPCVOID, + lpBaseAddress: LPCVOID, dwNumberOfBytesToFlush: SIZE_T, ) -> BOOL --- UnmapViewOfFile :: proc( @@ -845,36 +892,36 @@ foreign kernel32 { ) -> BOOL --- GetLargePageMinimum :: proc() -> SIZE_T --- GetProcessWorkingSetSizeEx :: proc( - hProcess: HANDLE, + hProcess: HANDLE, lpMinimumWorkingSetSize: PSIZE_T, lpMaximumWorkingSetSize: PSIZE_T, - Flags: PDWORD, + Flags: PDWORD, ) -> BOOL --- SetProcessWorkingSetSizeEx :: proc( - hProcess: HANDLE, + hProcess: HANDLE, dwMinimumWorkingSetSize: SIZE_T, dwMaximumWorkingSetSize: SIZE_T, - Flags: DWORD, + Flags: DWORD, ) -> BOOL --- VirtualLock :: proc( lpAddress: LPVOID, - dwSize: SIZE_T, + dwSize: SIZE_T, ) -> BOOL --- VirtualUnlock :: proc( lpAddress: LPVOID, - dwSize: SIZE_T, + dwSize: SIZE_T, ) -> BOOL --- GetWriteWatch :: proc( - dwFlags: DWORD, - lpBaseAddress: PVOID, - dwRegionSize: SIZE_T, - lpAddresses: ^PVOID, - lpdwCount: ^ULONG_PTR, + dwFlags: DWORD, + lpBaseAddress: PVOID, + dwRegionSize: SIZE_T, + lpAddresses: ^PVOID, + lpdwCount: ^ULONG_PTR, lpdwGranularity: LPDWORD, ) -> UINT --- ResetWriteWatch :: proc( lpBaseAddress: LPVOID, - dwRegionSize: SIZE_T, + dwRegionSize: SIZE_T, ) -> UINT --- } @@ -907,27 +954,27 @@ foreign kernel32 { GetSystemFileCacheSize :: proc( lpMinimumFileCacheSize: PSIZE_T, lpMaximumFileCacheSize: PSIZE_T, - lpFlags: PDWORD, + lpFlags: PDWORD, ) -> BOOL --- SetSystemFileCacheSize :: proc( MinimumFileCacheSize: SIZE_T, MaximumFileCacheSize: SIZE_T, - Flags: DWORD, + Flags: DWORD, ) -> BOOL --- CreateFileMappingNumaW :: proc( - hFile: HANDLE, + hFile: HANDLE, lpFileMappingAttributes: LPSECURITY_ATTRIBUTES, - flProtect: DWORD, - dwMaximumSizeHigh: DWORD, - dwMaximumSizeLow: DWORD, - lpName: LPCWSTR, - nndPreferred: DWORD, + flProtect: DWORD, + dwMaximumSizeHigh: DWORD, + dwMaximumSizeLow: DWORD, + lpName: LPCWSTR, + nndPreferred: DWORD, ) -> HANDLE --- } WIN32_MEMORY_RANGE_ENTRY :: struct { VirtualAddress: PVOID, - NumberOfBytes: SIZE_T, + NumberOfBytes: SIZE_T, } PWIN32_MEMORY_RANGE_ENTRY :: ^WIN32_MEMORY_RANGE_ENTRY @@ -935,56 +982,56 @@ PWIN32_MEMORY_RANGE_ENTRY :: ^WIN32_MEMORY_RANGE_ENTRY @(default_calling_convention="system") foreign kernel32 { PrefetchVirtualMemory :: proc( - hProcess: HANDLE, - NumberOfEntries: ULONG_PTR, + hProcess: HANDLE, + NumberOfEntries: ULONG_PTR, VirtualAddresses: PWIN32_MEMORY_RANGE_ENTRY, - Flags: ULONG, + Flags: ULONG, ) -> BOOL --- CreateFileMappingFromApp :: proc( - hFile: HANDLE, + hFile: HANDLE, SecurityAttributes: PSECURITY_ATTRIBUTES, - PageProtection: ULONG, - MaximumSize: ULONG64, - Name: PCWSTR, + PageProtection: ULONG, + MaximumSize: ULONG64, + Name: PCWSTR, ) -> HANDLE --- MapViewOfFileFromApp :: proc( hFileMappingObject: HANDLE, - DesiredAccess: ULONG, - FileOffset: ULONG64, + DesiredAccess: ULONG, + FileOffset: ULONG64, NumberOfBytesToMap: SIZE_T, ) -> PVOID --- UnmapViewOfFileEx :: proc( BaseAddress: PVOID, - UnmapFlags: ULONG, + UnmapFlags: ULONG, ) -> BOOL --- AllocateUserPhysicalPages :: proc( - hProcess: HANDLE, + hProcess: HANDLE, NumberOfPages: PULONG_PTR, - PageArray: PULONG_PTR, + PageArray: PULONG_PTR, ) -> BOOL --- FreeUserPhysicalPages :: proc( - hProcess: HANDLE, + hProcess: HANDLE, NumberOfPages: PULONG_PTR, - PageArray: PULONG_PTR, + PageArray: PULONG_PTR, ) -> BOOL --- MapUserPhysicalPages :: proc( VirtualAddress: PVOID, - NumberOfPages: ULONG_PTR, - PageArray: PULONG_PTR, + NumberOfPages: ULONG_PTR, + PageArray: PULONG_PTR, ) -> BOOL --- AllocateUserPhysicalPagesNuma :: proc( - hProcess: HANDLE, + hProcess: HANDLE, NumberOfPages: PULONG_PTR, - PageArray: PULONG_PTR, - nndPreferred: DWORD, + PageArray: PULONG_PTR, + nndPreferred: DWORD, ) -> BOOL --- VirtualAllocExNuma :: proc( - hProcess: HANDLE, - lpAddress: LPVOID, - dwSize: SIZE_T, + hProcess: HANDLE, + lpAddress: LPVOID, + dwSize: SIZE_T, flAllocationType: DWORD, - flProtect: DWORD, - nndPreferred: DWORD, + flProtect: DWORD, + nndPreferred: DWORD, ) -> LPVOID --- } @@ -992,28 +1039,20 @@ MEHC_PATROL_SCRUBBER_PRESENT :: ULONG(0x1) @(default_calling_convention="system") foreign kernel32 { - GetMemoryErrorHandlingCapabilities :: proc( - Capabilities: PULONG, - ) -> BOOL --- + GetMemoryErrorHandlingCapabilities :: proc(Capabilities: PULONG) -> BOOL --- } @(default_calling_convention="system") foreign kernel32 { - GlobalMemoryStatusEx :: proc( - lpBuffer: ^MEMORYSTATUSEX, - ) -> BOOL --- + GlobalMemoryStatusEx :: proc(lpBuffer: ^MEMORYSTATUSEX) -> BOOL --- } PBAD_MEMORY_CALLBACK_ROUTINE :: #type proc "system" () @(default_calling_convention="system") foreign kernel32 { - RegisterBadMemoryNotification :: proc( - Callback: PBAD_MEMORY_CALLBACK_ROUTINE, - ) -> PVOID --- - UnregisterBadMemoryNotification :: proc( - RegistrationHandle: PVOID, - ) -> BOOL --- + RegisterBadMemoryNotification :: proc(Callback: PBAD_MEMORY_CALLBACK_ROUTINE) -> PVOID --- + UnregisterBadMemoryNotification :: proc(RegistrationHandle: PVOID) -> BOOL --- } OFFER_PRIORITY :: enum c_int { @@ -1031,33 +1070,33 @@ VmOfferPriorityNormal :: OFFER_PRIORITY.VmOfferPriorityNormal foreign kernel32 { OfferVirtualMemory :: proc( VirtualAddress: PVOID, - Size: SIZE_T, - Priority: OFFER_PRIORITY, + Size: SIZE_T, + Priority: OFFER_PRIORITY, ) -> DWORD --- ReclaimVirtualMemory :: proc( VirtualAddress: PVOID, - Size: SIZE_T, + Size: SIZE_T, ) -> DWORD --- DiscardVirtualMemory :: proc( VirtualAddress: PVOID, - Size: SIZE_T, + Size: SIZE_T, ) -> DWORD --- VirtualAllocFromApp :: proc( - BaseAddress: PVOID, - Size: SIZE_T, + BaseAddress: PVOID, + Size: SIZE_T, AllocationType: ULONG, - Protection: ULONG, + Protection: ULONG, ) -> PVOID --- VirtualProtectFromApp :: proc( - Address: PVOID, - Size: SIZE_T, + Address: PVOID, + Size: SIZE_T, NewProtection: ULONG, OldProtection: PULONG, ) -> BOOL --- OpenFileMappingFromApp :: proc( DesiredAccess: ULONG, InheritHandle: BOOL, - Name: PCWSTR, + Name: PCWSTR, ) -> HANDLE --- } @@ -1067,54 +1106,48 @@ WIN32_MEMORY_INFORMATION_CLASS :: enum c_int { MemoryRegionInfo :: WIN32_MEMORY_INFORMATION_CLASS.MemoryRegionInfo WIN32_MEMORY_REGION_INFORMATION :: struct { - AllocationBase: PVOID, + AllocationBase: PVOID, AllocationProtect: ULONG, - u: WIN32_MEMORY_REGION_INFORMATION_u, + using DUMMYUNIONNAME: struct #raw_union { + _: [1]u32, + Flags: ULONG, + using DUMMYSTRUCTNAME: bit_field ULONG { + Private: ULONG | 1, + MappedDataFile: ULONG | 1, + MappedImage: ULONG | 1, + MappedPageFile: ULONG | 1, + MappedPhysical: ULONG | 1, + DirectMapped: ULONG | 1, + Reserved: ULONG | 26, + }, + }, RegionSize: SIZE_T, CommitSize: SIZE_T, } -WIN32_MEMORY_REGION_INFORMATION_u :: struct #raw_union { - u: [1]u32, - Flags: ULONG, - s: WIN32_MEMORY_REGION_INFORMATION_u_s, -} -WIN32_MEMORY_REGION_INFORMATION_u_s :: struct { - Bitfield: ULONG, -} -WIN32_MEMORY_REGION_INFORMATION_u_s_Bitfield :: distinct ULONG -/*bit_field #align(align_of(ULONG)) { - Private : 1-0, - MappedDataFile : 2-1, - MappedImage : 3-2, - MappedPageFile : 4-3, - MappedPhysical : 5-4, - DirectMapped : 6-5, - Reserved : 32-6, -}*/ @(default_calling_convention="system") foreign one_core { QueryVirtualMemoryInformation :: proc( - Process: HANDLE, - VirtualAddress: PVOID, + Process: HANDLE, + VirtualAddress: PVOID, MemoryInformationClass: WIN32_MEMORY_INFORMATION_CLASS, - MemoryInformation: PVOID, - MemoryInformationSize: SIZE_T, - ReturnSize: PSIZE_T, + MemoryInformation: PVOID, + MemoryInformationSize: SIZE_T, + ReturnSize: PSIZE_T, ) -> BOOL --- MapViewOfFileNuma2 :: proc( FileMappingHandle: HANDLE, - ProcessHandle: HANDLE, - Offset: ULONG64, - BaseAddress: PVOID, - ViewSize: SIZE_T, - AllocationType: ULONG, - PageProtection: ULONG, - PreferredNode: ULONG, + ProcessHandle: HANDLE, + Offset: ULONG64, + BaseAddress: PVOID, + ViewSize: SIZE_T, + AllocationType: ULONG, + PageProtection: ULONG, + PreferredNode: ULONG, ) -> PVOID --- GetCommPorts :: proc( - lpPortNumbers: PULONG, - uPortNumbersCount: ULONG, + lpPortNumbers: PULONG, + uPortNumbersCount: ULONG, puPortNumbersFound: PULONG, ) -> ULONG --- } @@ -1124,12 +1157,12 @@ NUMA_NO_PREFERRED_NODE :: 0xffffffff MapViewOfFile2 :: #force_inline proc "system" ( FileMappingHandle: HANDLE, - ProcessHandle: HANDLE, - Offset: ULONG64, - BaseAddress: PVOID, - ViewSize: SIZE_T, - AllocationType: ULONG, - PageProtection: ULONG, + ProcessHandle: HANDLE, + Offset: ULONG64, + BaseAddress: PVOID, + ViewSize: SIZE_T, + AllocationType: ULONG, + PageProtection: ULONG, ) -> PVOID { return MapViewOfFileNuma2( FileMappingHandle, @@ -1147,8 +1180,8 @@ MapViewOfFile2 :: #force_inline proc "system" ( foreign kernel32 { UnmapViewOfFile2 :: proc( ProcessHandle: HANDLE, - BaseAddress: PVOID, - UnmapFlags: ULONG, + BaseAddress: PVOID, + UnmapFlags: ULONG, ) -> BOOL --- } @@ -1159,10 +1192,83 @@ foreign kernel32 { OSMinorVersion: DWORD, SpMajorVersion: DWORD, SpMinorVersion: DWORD, - product_type: ^Windows_Product_Type, + product_type: ^Windows_Product_Type, ) -> BOOL --- } + +MEM_REPLACE_PLACEHOLDER :: 0x00004000 +MEM_RESERVE_PLACEHOLDER :: 0x00040000 +MEM_PRESERVE_PLACEHOLDER :: 0x00000002 +MEM_RESET_UNDO :: 0x1000000 +MEM_64K_PAGES :: 0x20400000 +MEM_PHYSICAL :: 0x00400000 + +MEM_EXTENDED_PARAMETER_TYPE :: enum c_int { + MemExtendedParameterInvalidType = 0, + MemExtendedParameterAddressRequirements, + MemExtendedParameterNumaNode, + MemExtendedParameterPartitionHandle, + MemExtendedParameterUserPhysicalHandle, + MemExtendedParameterAttributeFlags, + MemExtendedParameterImageMachine, +} + +MEM_EXTENDED_PARAMETER_NONPAGED :: 0x02 +MEM_EXTENDED_PARAMETER_NONPAGED_LARGE :: 0x08 +MEM_EXTENDED_PARAMETER_NONPAGED_HUGE :: 0x10 +MEM_EXTENDED_PARAMETER_EC_CODE :: 0x40 + +MEM_ADDRESS_REQUIREMENTS :: struct { + LowestStartingAddress: PVOID, + HighestEndingAddress: PVOID, + Alignment: SIZE_T, +} +PMEM_ADDRESS_REQUIREMENTS :: ^MEM_ADDRESS_REQUIREMENTS + +MEM_EXTENDED_PARAMETER_TYPE_BITS :: 8 + +MEM_EXTENDED_PARAMETER :: struct { + using DUMMYSTRUCTNAME: bit_field DWORD64 { + Type: MEM_EXTENDED_PARAMETER_TYPE | MEM_EXTENDED_PARAMETER_TYPE_BITS, + Reserved: DWORD64 | 64 - MEM_EXTENDED_PARAMETER_TYPE_BITS, + }, + using DUMMYUNIONNAME: struct #raw_union { + ULong64: DWORD64, + Pointer: PVOID, + Size: SIZE_T, + Handle: HANDLE, + ULong: DWORD, + }, +} + + +@(default_calling_convention="system") +foreign one_core { + VirtualAlloc2 :: proc( + Process: HANDLE, + BaseAddress: LPVOID, + Size: SIZE_T, + AllocationType: ULONG, + PageProtection: ULONG, + ExtendedParameters: ^MEM_EXTENDED_PARAMETER, + ParameterCount: ULONG, + ) -> LPVOID --- + + MapViewOfFile3 :: proc( + FileMappingHandle: HANDLE, + ProcessHandle: HANDLE, + BaseAddress: PVOID, + Offset: ULONG64, + ViewSize: SIZE_T, + AllocationType: ULONG, + PageProtection: ULONG, + ExtendedParameters: ^MEM_EXTENDED_PARAMETER, + ParameterCount: ULONG, + ) -> PVOID --- +} + + HandlerRoutine :: proc "system" (dwCtrlType: DWORD) -> BOOL PHANDLER_ROUTINE :: HandlerRoutine @@ -1173,10 +1279,10 @@ LPFIBER_START_ROUTINE :: #type proc "system" (lpFiberParameter: LPVOID) @(default_calling_convention = "system") foreign kernel32 { - CreateFiber :: proc(dwStackSize: SIZE_T, lpStartAddress: LPFIBER_START_ROUTINE, lpParameter: LPVOID) -> LPVOID --- - DeleteFiber :: proc(lpFiber: LPVOID) --- + CreateFiber :: proc(dwStackSize: SIZE_T, lpStartAddress: LPFIBER_START_ROUTINE, lpParameter: LPVOID) -> LPVOID --- + DeleteFiber :: proc(lpFiber: LPVOID) --- ConvertThreadToFiber :: proc(lpParameter: LPVOID) -> LPVOID --- - SwitchToFiber :: proc(lpFiber: LPVOID) --- + SwitchToFiber :: proc(lpFiber: LPVOID) --- } LOGICAL_PROCESSOR_RELATIONSHIP :: enum c_int { @@ -1199,11 +1305,11 @@ PROCESSOR_CACHE_TYPE :: enum c_int { } CACHE_DESCRIPTOR :: struct { - Level: BYTE, + Level: BYTE, Associativity: BYTE, - LineSize: WORD, - Size: DWORD, - Type: PROCESSOR_CACHE_TYPE, + LineSize: WORD, + Size: DWORD, + Type: PROCESSOR_CACHE_TYPE, } ProcessorCore :: struct { @@ -1212,17 +1318,16 @@ ProcessorCore :: struct { NumaNode :: struct { NodeNumber: DWORD, } -DUMMYUNIONNAME_u :: struct #raw_union { - Core: ProcessorCore, - Node: NumaNode, - Cache: CACHE_DESCRIPTOR, - Reserved: [2]ULONGLONG, -} SYSTEM_LOGICAL_PROCESSOR_INFORMATION :: struct { ProcessorMask: ULONG_PTR, - Relationship: LOGICAL_PROCESSOR_RELATIONSHIP, - using DummyUnion: DUMMYUNIONNAME_u, + Relationship: LOGICAL_PROCESSOR_RELATIONSHIP, + using DUMMYUNIONNAME: struct #raw_union { + ProcessorCore: ProcessorCore `raw_union_tag:"Relationship=RelationProcessorCore"`, + NumaNode: NumaNode `raw_union_tag:"Relationship=RelationNumaNode"`, + Cache: CACHE_DESCRIPTOR `raw_union_tag:"Relationship=RelationCache"`, + Reserved: [2]ULONGLONG, + }, } SYSTEM_POWER_STATUS :: struct { @@ -1294,6 +1399,6 @@ ACTCTX_FLAG_HMODULE_VALID :: 0x080 @(default_calling_convention="system") foreign kernel32 { - CreateActCtxW :: proc(pActCtx: ^ACTCTXW) -> HANDLE --- + CreateActCtxW :: proc(pActCtx: ^ACTCTXW) -> HANDLE --- ActivateActCtx :: proc(hActCtx: HANDLE, lpCookie: ^ULONG_PTR) -> BOOL --- } diff --git a/core/sys/windows/key_codes.odin b/core/sys/windows/key_codes.odin index 0991ca4b3..a2910ecd1 100644 --- a/core/sys/windows/key_codes.odin +++ b/core/sys/windows/key_codes.odin @@ -3,11 +3,11 @@ package sys_windows // https://docs.microsoft.com/en-us/windows/win32/inputdev/about-keyboard-input KF_EXTENDED :: 0x0100 -KF_DLGMODE :: 0x0800 +KF_DLGMODE :: 0x0800 KF_MENUMODE :: 0x1000 -KF_ALTDOWN :: 0x2000 -KF_REPEAT :: 0x4000 -KF_UP :: 0x8000 +KF_ALTDOWN :: 0x2000 +KF_REPEAT :: 0x4000 +KF_UP :: 0x8000 // https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes // Virtual Keys, Standard Set diff --git a/core/sys/windows/mswsock.odin b/core/sys/windows/mswsock.odin new file mode 100644 index 000000000..9019fc821 --- /dev/null +++ b/core/sys/windows/mswsock.odin @@ -0,0 +1,40 @@ +#+build windows +package sys_windows + +foreign import mswsock "system:mswsock.lib" + +foreign mswsock { + TransmitFile :: proc( + hSocket: SOCKET, + hFile: HANDLE, + nNumberOfBytesToWrite: DWORD, + nNumberOfBytesPerSend: DWORD, + lpOverlapped: LPOVERLAPPED, + lpTransmitBuffers: rawptr, + dwReserved: DWORD, + ) -> BOOL --- + + AcceptEx :: proc( + sListenSocket: SOCKET, + sAcceptSocket: SOCKET, + lpOutputBuffer: PVOID, + dwReceiveDataLength: DWORD, + dwLocalAddressLength: DWORD, + dwRemoteAddressLength: DWORD, + lpdwBytesReceived: LPDWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL --- + + GetAcceptExSockaddrs :: proc( + lpOutputBuffer: PVOID, + dwReceiveDataLength: DWORD, + dwLocalAddressLength: DWORD, + dwRemoteAddressLength: DWORD, + LocalSockaddr: ^^sockaddr, + LocalSockaddrLength: LPINT, + RemoteSockaddr: ^^sockaddr, + RemoteSockaddrLength: LPINT, + ) --- +} + +SO_UPDATE_CONNECT_CONTEXT :: 0x7010 \ No newline at end of file diff --git a/core/sys/windows/netapi32.odin b/core/sys/windows/netapi32.odin index 9442193ca..759c5847a 100644 --- a/core/sys/windows/netapi32.odin +++ b/core/sys/windows/netapi32.odin @@ -7,32 +7,32 @@ foreign import netapi32 "system:Netapi32.lib" foreign netapi32 { NetUserAdd :: proc( servername: wstring, - level: DWORD, - user_info: ^USER_INFO_1, // Perhaps make this a #raw_union with USER_INFO1..4 when we need the other levels. - parm_err: ^DWORD, + level: DWORD, + user_info: ^USER_INFO_1, // Perhaps make this a #raw_union with USER_INFO1..4 when we need the other levels. + parm_err: ^DWORD, ) -> NET_API_STATUS --- NetUserDel :: proc( servername: wstring, - username: wstring, + username: wstring, ) -> NET_API_STATUS --- NetUserGetInfo :: proc( servername: wstring, - username: wstring, - level: DWORD, - user_info: ^USER_INFO_1, + username: wstring, + level: DWORD, + user_info: ^USER_INFO_1, ) -> NET_API_STATUS --- NetLocalGroupAddMembers :: proc( - servername: wstring, - groupname: wstring, - level: DWORD, + servername: wstring, + groupname: wstring, + level: DWORD, group_members_info: ^LOCALGROUP_MEMBERS_INFO_0, // Actually a variably sized array of these. - totalentries: DWORD, + totalentries: DWORD, ) -> NET_API_STATUS --- NetLocalGroupDelMembers :: proc( - servername: wstring, - groupname: wstring, - level: DWORD, + servername: wstring, + groupname: wstring, + level: DWORD, group_members_info: ^LOCALGROUP_MEMBERS_INFO_0, // Actually a variably sized array of these. - totalentries: DWORD, + totalentries: DWORD, ) -> NET_API_STATUS --- } \ No newline at end of file diff --git a/core/sys/windows/ntdll.odin b/core/sys/windows/ntdll.odin index 747130749..8362bb9df 100644 --- a/core/sys/windows/ntdll.odin +++ b/core/sys/windows/ntdll.odin @@ -36,6 +36,20 @@ foreign ntdll_lib { QueryFlags: ULONG, FileName : PUNICODE_STRING, ) -> NTSTATUS --- + + NtCreateFile :: proc( + FileHandle: PHANDLE, + DesiredAccess: ACCESS_MASK, + ObjectAttributes: POBJECT_ATTRIBUTES, + IoStatusBlock: PIO_STATUS_BLOCK, + AllocationSize: PLARGE_INTEGER, + FileAttributes: ULONG, + ShareAccess: ULONG, + CreateDisposition: ULONG, + CreateOptions: ULONG, + EaBuffer: PVOID, + EaLength: ULONG, + ) -> NTSTATUS --- } @@ -256,4 +270,13 @@ RTL_DRIVE_LETTER_CURDIR :: struct { LIST_ENTRY :: struct { Flink: ^LIST_ENTRY, Blink: ^LIST_ENTRY, -} \ No newline at end of file +} + +FILE_SUPERSEDE :: 0x00000000 +FILE_OPEN :: 0x00000001 +FILE_CREATE :: 0x00000002 +FILE_OPEN_IF :: 0x00000003 +FILE_OVERWRITE :: 0x00000004 +FILE_OVERWRITE_IF :: 0x00000005 + +FILE_NON_DIRECTORY_FILE :: 0x00000040 diff --git a/core/sys/windows/ole32.odin b/core/sys/windows/ole32.odin index 32cb6fd60..f93ecc820 100644 --- a/core/sys/windows/ole32.odin +++ b/core/sys/windows/ole32.odin @@ -1,6 +1,8 @@ package sys_windows -foreign import "system:Ole32.lib" +// Don't add a `#+build windows` guard to this file. It's used for `dxgi` on non-Windows platforms, for example. + +foreign import Ole32 "system:Ole32.lib" //objbase.h // Note(Dragos): https://learn.microsoft.com/en-us/windows/win32/api/objbase/ne-objbase-coinit makes you believe that MULTITHREADED == 3. That is wrong. See definition of objbase.h @@ -41,32 +43,32 @@ LPUNKNOWN :: ^IUnknown @(default_calling_convention="system") foreign Ole32 { - CoInitialize :: proc(reserved: rawptr = nil) -> HRESULT --- + CoInitialize :: proc(reserved: rawptr = nil) -> HRESULT --- CoInitializeEx :: proc(reserved: rawptr = nil, co_init: COINIT = .APARTMENTTHREADED) -> HRESULT --- CoUninitialize :: proc() --- CoCreateInstance :: proc( - rclsid: REFCLSID, - pUnkOuter: LPUNKNOWN, + rclsid: REFCLSID, + pUnkOuter: LPUNKNOWN, dwClsContext: DWORD, - riid: REFIID, - ppv: ^LPVOID, + riid: REFIID, + ppv: ^LPVOID, ) -> HRESULT --- - CoTaskMemAlloc :: proc(cb: SIZE_T) -> rawptr --- + CoTaskMemAlloc :: proc(cb: SIZE_T) -> rawptr --- CoTaskMemRealloc :: proc(pv: rawptr, cb: SIZE_T) -> rawptr --- - CoTaskMemFree :: proc(pv: rawptr) --- + CoTaskMemFree :: proc(pv: rawptr) --- - CLSIDFromProgID :: proc(lpszProgID: LPCOLESTR, lpclsid: LPCLSID) -> HRESULT --- + CLSIDFromProgID :: proc(lpszProgID: LPCOLESTR, lpclsid: LPCLSID) -> HRESULT --- CLSIDFromProgIDEx :: proc(lpszProgID: LPCOLESTR, lpclsid: LPCLSID) -> HRESULT --- - CLSIDFromString :: proc(lpsz: LPOLESTR, pclsid: LPCLSID) -> HRESULT --- - IIDFromString :: proc(lpsz: LPOLESTR, lpiid: LPIID) -> HRESULT --- - ProgIDFromCLSID :: proc(clsid: REFCLSID, lplpszProgID: ^LPOLESTR) -> HRESULT --- - StringFromCLSID :: proc(rclsid: REFCLSID, lplpsz: ^LPOLESTR) -> HRESULT --- - StringFromGUID2 :: proc(rclsid: REFCLSID, lplpsz: LPOLESTR, cchMax: INT) -> INT --- - StringFromIID :: proc(rclsid: REFIID, lplpsz: ^LPOLESTR) -> HRESULT --- + CLSIDFromString :: proc(lpsz: LPOLESTR, pclsid: LPCLSID) -> HRESULT --- + IIDFromString :: proc(lpsz: LPOLESTR, lpiid: LPIID) -> HRESULT --- + ProgIDFromCLSID :: proc(clsid: REFCLSID, lplpszProgID: ^LPOLESTR) -> HRESULT --- + StringFromCLSID :: proc(rclsid: REFCLSID, lplpsz: ^LPOLESTR) -> HRESULT --- + StringFromGUID2 :: proc(rclsid: REFCLSID, lplpsz: LPOLESTR, cchMax: INT) -> INT --- + StringFromIID :: proc(rclsid: REFIID, lplpsz: ^LPOLESTR) -> HRESULT --- - PropVariantClear :: proc(pvar: ^PROPVARIANT) -> HRESULT --- - PropVariantCopy :: proc(pvarDest: ^PROPVARIANT, pvarSrc: ^PROPVARIANT) -> HRESULT --- + PropVariantClear :: proc(pvar: ^PROPVARIANT) -> HRESULT --- + PropVariantCopy :: proc(pvarDest: ^PROPVARIANT, pvarSrc: ^PROPVARIANT) -> HRESULT --- FreePropVariantArray :: proc(cVariants: ULONG, rgvars: ^PROPVARIANT) -> HRESULT --- } diff --git a/core/sys/windows/shcore.odin b/core/sys/windows/shcore.odin index 08a76ebe6..c7d784fe8 100644 --- a/core/sys/windows/shcore.odin +++ b/core/sys/windows/shcore.odin @@ -8,18 +8,18 @@ foreign import shcore "system:Shcore.lib" foreign shcore { GetProcessDpiAwareness :: proc(hprocess: HANDLE, value: ^PROCESS_DPI_AWARENESS) -> HRESULT --- SetProcessDpiAwareness :: proc(value: PROCESS_DPI_AWARENESS) -> HRESULT --- - GetDpiForMonitor :: proc(hmonitor: HMONITOR, dpiType: MONITOR_DPI_TYPE, dpiX: ^UINT, dpiY: ^UINT) -> HRESULT --- + GetDpiForMonitor :: proc(hmonitor: HMONITOR, dpiType: MONITOR_DPI_TYPE, dpiX: ^UINT, dpiY: ^UINT) -> HRESULT --- } PROCESS_DPI_AWARENESS :: enum DWORD { - PROCESS_DPI_UNAWARE = 0, - PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2, } MONITOR_DPI_TYPE :: enum DWORD { MDT_EFFECTIVE_DPI = 0, - MDT_ANGULAR_DPI = 1, - MDT_RAW_DPI = 2, + MDT_ANGULAR_DPI = 1, + MDT_RAW_DPI = 2, MDT_DEFAULT, } diff --git a/core/sys/windows/shell32.odin b/core/sys/windows/shell32.odin index 54cee718c..1a0844b39 100644 --- a/core/sys/windows/shell32.odin +++ b/core/sys/windows/shell32.odin @@ -22,29 +22,31 @@ foreign shell32 { ) -> c_int --- SHFileOperationW :: proc(lpFileOp: LPSHFILEOPSTRUCTW) -> c_int --- SHGetFolderPathW :: proc(hwnd: HWND, csidl: c_int, hToken: HANDLE, dwFlags: DWORD, pszPath: LPWSTR) -> HRESULT --- - SHAppBarMessage :: proc(dwMessage: DWORD, pData: PAPPBARDATA) -> UINT_PTR --- + SHAppBarMessage :: proc(dwMessage: DWORD, pData: PAPPBARDATA) -> UINT_PTR --- Shell_NotifyIconW :: proc(dwMessage: DWORD, lpData: ^NOTIFYICONDATAW) -> BOOL --- - SHChangeNotify :: proc(wEventId: LONG, uFlags: UINT, dwItem1: LPCVOID, dwItem2: LPCVOID) --- + SHChangeNotify :: proc(wEventId: LONG, uFlags: UINT, dwItem1: LPCVOID, dwItem2: LPCVOID) --- SHGetKnownFolderIDList :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, ppidl: rawptr) -> HRESULT --- - SHSetKnownFolderPath :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, pszPath: PCWSTR ) -> HRESULT --- - SHGetKnownFolderPath :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, ppszPath: ^LPWSTR) -> HRESULT --- + SHSetKnownFolderPath :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, pszPath: PCWSTR ) -> HRESULT --- + SHGetKnownFolderPath :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, ppszPath: ^LPWSTR) -> HRESULT --- - ExtractIconExW :: proc(pszFile: LPCWSTR, nIconIndex: INT, phiconLarge: ^HICON, phiconSmall: ^HICON, nIcons: UINT) -> UINT --- + SHCreateItemFromParsingName :: proc(pszPath: PCWSTR, pbc: ^IBindCtx, riid: REFIID, ppv: ^rawptr) -> HRESULT --- + + ExtractIconExW :: proc(pszFile: LPCWSTR, nIconIndex: INT, phiconLarge: ^HICON, phiconSmall: ^HICON, nIcons: UINT) -> UINT --- DragAcceptFiles :: proc(hWnd: HWND, fAccept: BOOL) --- - DragQueryPoint :: proc(hDrop: HDROP, ppt: ^POINT) -> BOOL --- - DragQueryFileW :: proc(hDrop: HDROP, iFile: UINT, lpszFile: LPWSTR, cch: UINT) -> UINT --- - DragFinish :: proc(hDrop: HDROP) --- // @New + DragQueryPoint :: proc(hDrop: HDROP, ppt: ^POINT) -> BOOL --- + DragQueryFileW :: proc(hDrop: HDROP, iFile: UINT, lpszFile: LPWSTR, cch: UINT) -> UINT --- + DragFinish :: proc(hDrop: HDROP) --- // @New } APPBARDATA :: struct { - cbSize: DWORD, - hWnd: HWND, + cbSize: DWORD, + hWnd: HWND, uCallbackMessage: UINT, - uEdge: UINT, - rc: RECT, - lParam: LPARAM, + uEdge: UINT, + rc: RECT, + lParam: LPARAM, } PAPPBARDATA :: ^APPBARDATA diff --git a/core/sys/windows/tlhelp.odin b/core/sys/windows/tlhelp.odin index 006c9c330..b23b4b06a 100644 --- a/core/sys/windows/tlhelp.odin +++ b/core/sys/windows/tlhelp.odin @@ -5,22 +5,22 @@ foreign import kernel32 "system:Kernel32.lib" @(default_calling_convention="system") foreign kernel32 { - CreateToolhelp32Snapshot :: proc (dwFlags: DWORD, th32ProcessID: DWORD) -> HANDLE --- - Process32FirstW :: proc (hSnapshot: HANDLE, lppe: LPPROCESSENTRY32W) -> BOOL --- - Process32NextW :: proc (hSnapshot: HANDLE, lppe: LPPROCESSENTRY32W) -> BOOL --- - Thread32First :: proc (hSnapshot: HANDLE, lpte: LPTHREADENTRY32) -> BOOL --- - Thread32Next :: proc (hSnapshot: HANDLE, lpte: LPTHREADENTRY32) -> BOOL --- - Module32FirstW :: proc (hSnapshot: HANDLE, lpme: LPMODULEENTRY32W) -> BOOL --- - Module32NextW :: proc (hSnapshot: HANDLE, lpme: LPMODULEENTRY32W) -> BOOL --- - Heap32ListFirst :: proc (hSnapshot: HANDLE, lphl: LPHEAPLIST32) -> BOOL --- - Heap32ListNext :: proc (hSnapshot: HANDLE, lphl: LPHEAPLIST32) -> BOOL --- - Heap32First :: proc (lphe: LPHEAPENTRY32, th32ProcessID: DWORD, th32HeapID: ULONG_PTR) -> BOOL --- - Heap32Next :: proc (lphe: LPHEAPENTRY32) -> BOOL --- - Toolhelp32ReadProcessMemory :: proc ( - th32ProcessID: DWORD, - lpBaseAddress: LPCVOID, - lpBuffer: LPVOID, - cbRead: SIZE_T, + CreateToolhelp32Snapshot :: proc(dwFlags: DWORD, th32ProcessID: DWORD) -> HANDLE --- + Process32FirstW :: proc(hSnapshot: HANDLE, lppe: LPPROCESSENTRY32W) -> BOOL --- + Process32NextW :: proc(hSnapshot: HANDLE, lppe: LPPROCESSENTRY32W) -> BOOL --- + Thread32First :: proc(hSnapshot: HANDLE, lpte: LPTHREADENTRY32) -> BOOL --- + Thread32Next :: proc(hSnapshot: HANDLE, lpte: LPTHREADENTRY32) -> BOOL --- + Module32FirstW :: proc(hSnapshot: HANDLE, lpme: LPMODULEENTRY32W) -> BOOL --- + Module32NextW :: proc(hSnapshot: HANDLE, lpme: LPMODULEENTRY32W) -> BOOL --- + Heap32ListFirst :: proc(hSnapshot: HANDLE, lphl: LPHEAPLIST32) -> BOOL --- + Heap32ListNext :: proc(hSnapshot: HANDLE, lphl: LPHEAPLIST32) -> BOOL --- + Heap32First :: proc(lphe: LPHEAPENTRY32, th32ProcessID: DWORD, th32HeapID: ULONG_PTR) -> BOOL --- + Heap32Next :: proc(lphe: LPHEAPENTRY32) -> BOOL --- + Toolhelp32ReadProcessMemory :: proc( + th32ProcessID: DWORD, + lpBaseAddress: LPCVOID, + lpBuffer: LPVOID, + cbRead: SIZE_T, lpNumberOfBytesRead: ^SIZE_T, ) -> BOOL --- } @@ -36,66 +36,66 @@ TH32CS_SNAPMODULE32 :: 0x00000010 TH32CS_SNAPALL :: TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE PROCESSENTRY32W :: struct { - dwSize: DWORD, - cntUsage: DWORD, - th32ProcessID: DWORD, - th32DefaultHeapID: ULONG_PTR, - th32ModuleID: DWORD, - cntThreads: DWORD, + dwSize: DWORD, + cntUsage: DWORD, + th32ProcessID: DWORD, + th32DefaultHeapID: ULONG_PTR, + th32ModuleID: DWORD, + cntThreads: DWORD, th32ParentProcessID: DWORD, - pcPriClassBase: LONG, - dwFlags: DWORD, - szExeFile: [MAX_PATH]WCHAR, + pcPriClassBase: LONG, + dwFlags: DWORD, + szExeFile: [MAX_PATH]WCHAR, } LPPROCESSENTRY32W :: ^PROCESSENTRY32W THREADENTRY32 :: struct { - dwSize: DWORD, - cntUsage: DWORD, - th32ThreadID: DWORD, + dwSize: DWORD, + cntUsage: DWORD, + th32ThreadID: DWORD, th32OwnerProcessID: DWORD, - tpBasePri: LONG, - tpDeltaPri: LONG, - dwFlags: DWORD, + tpBasePri: LONG, + tpDeltaPri: LONG, + dwFlags: DWORD, } LPTHREADENTRY32 :: ^THREADENTRY32 MODULEENTRY32W :: struct { - dwSize: DWORD, - th32ModuleID: DWORD, + dwSize: DWORD, + th32ModuleID: DWORD, th32ProcessID: DWORD, - GlblcntUsage: DWORD, - ProccntUsage: DWORD, - modBaseAddr: ^BYTE, - modBaseSize: DWORD, - hModule: HMODULE, - szModule: [MAX_MODULE_NAME32 + 1]WCHAR, - szExePath: [MAX_PATH]WCHAR, + GlblcntUsage: DWORD, + ProccntUsage: DWORD, + modBaseAddr: ^BYTE, + modBaseSize: DWORD, + hModule: HMODULE, + szModule: [MAX_MODULE_NAME32 + 1]WCHAR, + szExePath: [MAX_PATH]WCHAR, } LPMODULEENTRY32W :: ^MODULEENTRY32W HEAPLIST32 :: struct { - dwSize: SIZE_T, + dwSize: SIZE_T, th32ProcessID: DWORD, - th32HeapID: ULONG_PTR, - dwFlags: DWORD, + th32HeapID: ULONG_PTR, + dwFlags: DWORD, } LPHEAPLIST32 :: ^HEAPLIST32 HEAPENTRY32 :: struct { - dwSize: SIZE_T, - hHandle: HANDLE, - dwAddress: ULONG_PTR, - dwBlockSize: SIZE_T, - dwFlags: DWORD, - dwLockCount: DWORD, - dwResvd: DWORD, + dwSize: SIZE_T, + hHandle: HANDLE, + dwAddress: ULONG_PTR, + dwBlockSize: SIZE_T, + dwFlags: DWORD, + dwLockCount: DWORD, + dwResvd: DWORD, th32ProcessID: DWORD, - th32HeapID: ULONG_PTR, + th32HeapID: ULONG_PTR, } LPHEAPENTRY32 :: ^HEAPENTRY32 diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 904970589..54ebd9481 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -1,5 +1,7 @@ package sys_windows +// Don't add a `#+build windows` guard to this file. It's used for `dxgi` on non-Windows platforms, for example. + import "core:c" c_char :: c.char @@ -15,75 +17,75 @@ c_ushort :: c.ushort size_t :: c.size_t wchar_t :: c.wchar_t -DWORD :: c_ulong -DWORDLONG :: c.ulonglong -QWORD :: c.ulonglong -HANDLE :: distinct LPVOID -PHANDLE :: ^HANDLE -HINSTANCE :: HANDLE -HMODULE :: distinct HINSTANCE -HRESULT :: distinct LONG -HWND :: distinct HANDLE -HDC :: distinct HANDLE -HMONITOR :: distinct HANDLE -HICON :: distinct HANDLE -HCURSOR :: distinct HANDLE -HMENU :: distinct HANDLE -HBRUSH :: distinct HANDLE -HPEN :: distinct HANDLE -HGDIOBJ :: distinct HANDLE -HBITMAP :: distinct HANDLE -HPALETTE :: distinct HANDLE -HGLOBAL :: distinct HANDLE -HHOOK :: distinct HANDLE -HWINEVENTHOOK :: distinct HANDLE -HKEY :: distinct HANDLE -HDESK :: distinct HANDLE -HFONT :: distinct HANDLE -HRGN :: distinct HANDLE -HRSRC :: distinct HANDLE -HWINSTA :: distinct HANDLE -HACCEL :: distinct HANDLE -BOOL :: distinct b32 -BYTE :: distinct u8 -BOOLEAN :: distinct b8 -GROUP :: distinct c_uint -LARGE_INTEGER :: distinct c_longlong -ULARGE_INTEGER :: distinct c_ulonglong +DWORD :: c_ulong +DWORDLONG :: c.ulonglong +QWORD :: c.ulonglong +HANDLE :: distinct LPVOID +PHANDLE :: ^HANDLE +HINSTANCE :: HANDLE +HMODULE :: distinct HINSTANCE +HRESULT :: distinct LONG +HWND :: distinct HANDLE +HDC :: distinct HANDLE +HMONITOR :: distinct HANDLE +HICON :: distinct HANDLE +HCURSOR :: distinct HANDLE +HMENU :: distinct HANDLE +HBRUSH :: distinct HANDLE +HPEN :: distinct HANDLE +HGDIOBJ :: distinct HANDLE +HBITMAP :: distinct HANDLE +HPALETTE :: distinct HANDLE +HGLOBAL :: distinct HANDLE +HHOOK :: distinct HANDLE +HWINEVENTHOOK :: distinct HANDLE +HKEY :: distinct HANDLE +HDESK :: distinct HANDLE +HFONT :: distinct HANDLE +HRGN :: distinct HANDLE +HRSRC :: distinct HANDLE +HWINSTA :: distinct HANDLE +HACCEL :: distinct HANDLE +BOOL :: distinct b32 +BYTE :: distinct u8 +BOOLEAN :: distinct b8 +GROUP :: distinct c_uint +LARGE_INTEGER :: distinct c_longlong +ULARGE_INTEGER :: distinct c_ulonglong PULARGE_INTEGER :: ^ULARGE_INTEGER -LONG :: c_long -UINT :: c_uint -INT :: c_int -SHORT :: c_short -USHORT :: c_ushort -WCHAR :: wchar_t -SIZE_T :: uint -PSIZE_T :: ^SIZE_T -WORD :: u16 -CHAR :: c_char -ULONG_PTR :: uint -PULONG_PTR :: ^ULONG_PTR -LPULONG_PTR :: ^ULONG_PTR -DWORD_PTR :: ULONG_PTR -LONG_PTR :: int -INT_PTR :: int -UINT_PTR :: uintptr -ULONG :: c_ulong -ULONGLONG :: c_ulonglong -LONGLONG :: c_longlong -UCHAR :: BYTE -NTSTATUS :: c.long -COLORREF :: DWORD -LPCOLORREF :: ^COLORREF -LPARAM :: LONG_PTR -WPARAM :: UINT_PTR -LRESULT :: LONG_PTR -LPRECT :: ^RECT -LPPOINT :: ^POINT -LSTATUS :: LONG -PHKEY :: ^HKEY -PUSHORT :: ^USHORT -PCHAR :: ^CHAR +LONG :: c_long +UINT :: c_uint +INT :: c_int +SHORT :: c_short +USHORT :: c_ushort +WCHAR :: wchar_t +SIZE_T :: uint +PSIZE_T :: ^SIZE_T +WORD :: u16 +CHAR :: c_char +ULONG_PTR :: uint +PULONG_PTR :: ^ULONG_PTR +LPULONG_PTR :: ^ULONG_PTR +DWORD_PTR :: ULONG_PTR +LONG_PTR :: int +INT_PTR :: int +UINT_PTR :: uintptr +ULONG :: c_ulong +ULONGLONG :: c_ulonglong +LONGLONG :: c_longlong +UCHAR :: BYTE +NTSTATUS :: c.long +COLORREF :: DWORD +LPCOLORREF :: ^COLORREF +LPARAM :: LONG_PTR +WPARAM :: UINT_PTR +LRESULT :: LONG_PTR +LPRECT :: ^RECT +LPPOINT :: ^POINT +LSTATUS :: LONG +PHKEY :: ^HKEY +PUSHORT :: ^USHORT +PCHAR :: ^CHAR UINT8 :: u8 UINT16 :: u16 @@ -101,68 +103,86 @@ LONG32 :: i32 ULONG64 :: u64 LONG64 :: i64 -DWORD64 :: u64 +DWORD64 :: u64 PDWORD64 :: ^DWORD64 PDWORD_PTR :: ^DWORD_PTR -ATOM :: distinct WORD +ATOM :: distinct WORD wstring :: cstring16 PWSTR :: cstring16 -PBYTE :: ^BYTE -LPBYTE :: ^BYTE -PBOOL :: ^BOOL -LPBOOL :: ^BOOL -LPCSTR :: cstring -LPCWSTR :: wstring -LPCTSTR :: wstring -LPDWORD :: ^DWORD -PCSTR :: cstring -PCWSTR :: wstring -PDWORD :: ^DWORD -LPHANDLE :: ^HANDLE -LPOVERLAPPED :: ^OVERLAPPED +PBYTE :: ^BYTE +LPBYTE :: ^BYTE +PBOOL :: ^BOOL +LPBOOL :: ^BOOL +LPCSTR :: cstring +LPCWSTR :: wstring +LPCTSTR :: wstring +LPDWORD :: ^DWORD +PCSTR :: cstring +PCWSTR :: wstring +PDWORD :: ^DWORD +LPHANDLE :: ^HANDLE +LPOVERLAPPED :: ^OVERLAPPED LPPROCESS_INFORMATION :: ^PROCESS_INFORMATION -PSECURITY_ATTRIBUTES :: ^SECURITY_ATTRIBUTES +PSECURITY_ATTRIBUTES :: ^SECURITY_ATTRIBUTES LPSECURITY_ATTRIBUTES :: ^SECURITY_ATTRIBUTES -LPSTARTUPINFOW :: ^STARTUPINFOW -LPTRACKMOUSEEVENT :: ^TRACKMOUSEEVENT -VOID :: rawptr -PVOID :: rawptr -LPVOID :: rawptr -PINT :: ^INT -LPINT :: ^INT -PUINT :: ^UINT -LPUINT :: ^UINT -LPWCH :: ^WCHAR -LPWORD :: ^WORD -PULONG :: ^ULONG -LPWIN32_FIND_DATAW :: ^WIN32_FIND_DATAW -LPWSADATA :: ^WSADATA -LPWSAPROTOCOL_INFO :: ^WSAPROTOCOL_INFO -LPSTR :: ^CHAR -LPWSTR :: ^WCHAR -OLECHAR :: WCHAR -BSTR :: ^OLECHAR -LPOLESTR :: cstring16 -LPCOLESTR :: LPCSTR -LPFILETIME :: ^FILETIME -LPWSABUF :: ^WSABUF -LPWSAOVERLAPPED :: distinct rawptr -LPWSAOVERLAPPED_COMPLETION_ROUTINE :: distinct rawptr -LPCVOID :: rawptr -SCODE :: LONG -PSCODE :: ^SCODE +LPSTARTUPINFOW :: ^STARTUPINFOW +LPTRACKMOUSEEVENT :: ^TRACKMOUSEEVENT +VOID :: rawptr +PVOID :: rawptr +LPVOID :: rawptr +PINT :: ^INT +LPINT :: ^INT +PUINT :: ^UINT +LPUINT :: ^UINT +LPWCH :: ^WCHAR +LPWORD :: ^WORD +PULONG :: ^ULONG +LPWIN32_FIND_DATAW :: ^WIN32_FIND_DATAW +LPWSADATA :: ^WSADATA +LPWSAPROTOCOL_INFO :: ^WSAPROTOCOL_INFO +LPSTR :: ^CHAR +LPWSTR :: ^WCHAR +OLECHAR :: WCHAR +BSTR :: ^OLECHAR -PACCESS_TOKEN :: PVOID +LPOLESTR :: cstring16 +LPCOLESTR :: LPCSTR +LPFILETIME :: ^FILETIME +LPWSABUF :: ^WSABUF + +WSAEVENT :: HANDLE + +WSAOVERLAPPED :: struct { + Internal: DWORD, + InternalHigh: DWORD, + Offset: DWORD, + OffsetHigh: DWORD, + hEvent: WSAEVENT, +} + +LPWSAOVERLAPPED :: ^WSAOVERLAPPED +LPWSAOVERLAPPED_COMPLETION_ROUTINE :: #type proc "system" ( + dwError: DWORD, + cbTransferred: DWORD, + lpOverlapped: LPWSAOVERLAPPED, + dwFlags: DWORD, +) + +LPCVOID :: rawptr +SCODE :: LONG +PSCODE :: ^SCODE + +PACCESS_TOKEN :: PVOID PSECURITY_DESCRIPTOR :: PVOID -PSID :: PVOID -PCLAIMS_BLOB :: PVOID +PSID :: PVOID +PCLAIMS_BLOB :: PVOID PCONDITION_VARIABLE :: ^CONDITION_VARIABLE -PLARGE_INTEGER :: ^LARGE_INTEGER -PSRWLOCK :: ^SRWLOCK +PLARGE_INTEGER :: ^LARGE_INTEGER +PSRWLOCK :: ^SRWLOCK CREATE_WAITABLE_TIMER_MANUAL_RESET :: 0x00000001 CREATE_WAITABLE_TIMER_HIGH_RESOLUTION :: 0x00000002 @@ -183,28 +203,28 @@ LPSIZE :: ^SIZE MAXLONG :: 0x7fffffff -FILE_ATTRIBUTE_READONLY: DWORD : 0x00000001 -FILE_ATTRIBUTE_HIDDEN: DWORD : 0x00000002 -FILE_ATTRIBUTE_SYSTEM: DWORD : 0x00000004 -FILE_ATTRIBUTE_DIRECTORY: DWORD : 0x00000010 -FILE_ATTRIBUTE_ARCHIVE: DWORD : 0x00000020 -FILE_ATTRIBUTE_DEVICE: DWORD : 0x00000040 -FILE_ATTRIBUTE_NORMAL: DWORD : 0x00000080 -FILE_ATTRIBUTE_TEMPORARY: DWORD : 0x00000100 -FILE_ATTRIBUTE_SPARSE_FILE: DWORD : 0x00000200 -FILE_ATTRIBUTE_REPARSE_Point: DWORD : 0x00000400 -FILE_ATTRIBUTE_REPARSE_POINT: DWORD : 0x00000400 -FILE_ATTRIBUTE_COMPRESSED: DWORD : 0x00000800 -FILE_ATTRIBUTE_OFFLINE: DWORD : 0x00001000 -FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: DWORD : 0x00002000 -FILE_ATTRIBUTE_ENCRYPTED: DWORD : 0x00004000 +FILE_ATTRIBUTE_READONLY : DWORD : 0x00000001 +FILE_ATTRIBUTE_HIDDEN : DWORD : 0x00000002 +FILE_ATTRIBUTE_SYSTEM : DWORD : 0x00000004 +FILE_ATTRIBUTE_DIRECTORY : DWORD : 0x00000010 +FILE_ATTRIBUTE_ARCHIVE : DWORD : 0x00000020 +FILE_ATTRIBUTE_DEVICE : DWORD : 0x00000040 +FILE_ATTRIBUTE_NORMAL : DWORD : 0x00000080 +FILE_ATTRIBUTE_TEMPORARY : DWORD : 0x00000100 +FILE_ATTRIBUTE_SPARSE_FILE : DWORD : 0x00000200 +FILE_ATTRIBUTE_REPARSE_Point : DWORD : 0x00000400 +FILE_ATTRIBUTE_REPARSE_POINT : DWORD : 0x00000400 +FILE_ATTRIBUTE_COMPRESSED : DWORD : 0x00000800 +FILE_ATTRIBUTE_OFFLINE : DWORD : 0x00001000 +FILE_ATTRIBUTE_NOT_CONTENT_INDEXED : DWORD : 0x00002000 +FILE_ATTRIBUTE_ENCRYPTED : DWORD : 0x00004000 -FILE_SHARE_READ: DWORD : 0x00000001 -FILE_SHARE_WRITE: DWORD : 0x00000002 -FILE_SHARE_DELETE: DWORD : 0x00000004 -FILE_GENERIC_ALL: DWORD : 0x10000000 -FILE_GENERIC_EXECUTE: DWORD : 0x20000000 -FILE_GENERIC_READ: DWORD : 0x80000000 +FILE_SHARE_READ : DWORD : 0x00000001 +FILE_SHARE_WRITE : DWORD : 0x00000002 +FILE_SHARE_DELETE : DWORD : 0x00000004 +FILE_GENERIC_ALL : DWORD : 0x10000000 +FILE_GENERIC_EXECUTE : DWORD : 0x20000000 +FILE_GENERIC_READ : DWORD : 0x80000000 FILE_ALL_ACCESS :: STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF FILE_ACTION_ADDED :: 0x00000001 @@ -222,11 +242,11 @@ FILE_NOTIFY_CHANGE_LAST_ACCESS :: 0x00000020 FILE_NOTIFY_CHANGE_CREATION :: 0x00000040 FILE_NOTIFY_CHANGE_SECURITY :: 0x00000100 -CREATE_NEW: DWORD : 1 -CREATE_ALWAYS: DWORD : 2 -OPEN_ALWAYS: DWORD : 4 -OPEN_EXISTING: DWORD : 3 -TRUNCATE_EXISTING: DWORD : 5 +CREATE_NEW : DWORD : 1 +CREATE_ALWAYS : DWORD : 2 +OPEN_ALWAYS : DWORD : 4 +OPEN_EXISTING : DWORD : 3 +TRUNCATE_EXISTING : DWORD : 5 FILE_READ_DATA : DWORD : 0x00000001 FILE_LIST_DIRECTORY : DWORD : 0x00000001 @@ -248,11 +268,12 @@ GENERIC_WRITE : DWORD : 0x40000000 GENERIC_EXECUTE : DWORD : 0x20000000 GENERIC_ALL : DWORD : 0x10000000 -FILE_GENERIC_WRITE: DWORD : STANDARD_RIGHTS_WRITE | - FILE_WRITE_DATA | +FILE_GENERIC_WRITE : DWORD : \ + STANDARD_RIGHTS_WRITE | + FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | - FILE_WRITE_EA | - FILE_APPEND_DATA | + FILE_WRITE_EA | + FILE_APPEND_DATA | SYNCHRONIZE SECURITY_SQOS_PRESENT: DWORD : 0x00100000 @@ -274,7 +295,7 @@ PROTECTED_SACL_SECURITY_INFORMATION :: 0x40000000 UNPROTECTED_DACL_SECURITY_INFORMATION :: 0x20000000 UNPROTECTED_SACL_SECURITY_INFORMATION :: 0x10000000 -GET_FILEEX_INFO_LEVELS :: distinct i32 +GET_FILEEX_INFO_LEVELS :: distinct c_int GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0 GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1 @@ -297,13 +318,13 @@ POWER_REQUEST_CONTEXT_DETAILED_STRING :: DIAGNOSTIC_REASON_DETAILED_STRING REASON_CONTEXT :: struct { Version: ULONG, - Flags: DWORD, + Flags: DWORD, Reason: struct #raw_union { Detailed: struct { LocalizedReasonModule: HMODULE, - LocalizedReasonId: ULONG, - ReasonStringCount: ULONG, - ReasonStrings: ^LPWSTR, + LocalizedReasonId: ULONG, + ReasonStringCount: ULONG, + ReasonStrings: [^]LPWSTR `fmt:"v,ReasonStringCount"`, }, SimpleReasonString: LPWSTR, }, @@ -324,9 +345,9 @@ RRF_RT_ANY :: 0x0000ffff RRF_NOEXPAND :: 0x10000000 RRF_ZEROONFAILURE :: 0x20000000 -ACCESS_MASK :: DWORD +ACCESS_MASK :: DWORD PACCESS_MASK :: ^ACCESS_MASK -REGSAM :: ACCESS_MASK +REGSAM :: ACCESS_MASK // Reserved Key Handles. HKEY_CLASSES_ROOT :: HKEY(uintptr(0x80000000)) @@ -368,12 +389,13 @@ KEY_WOW64_RES :: 0x0300 KEY_READ :: (STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & (~SYNCHRONIZE) KEY_WRITE :: (STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) & (~SYNCHRONIZE) KEY_EXECUTE :: (KEY_READ) & (~SYNCHRONIZE) -KEY_ALL_ACCESS :: (STANDARD_RIGHTS_ALL | - KEY_QUERY_VALUE | - KEY_SET_VALUE | - KEY_CREATE_SUB_KEY | +KEY_ALL_ACCESS :: ( + STANDARD_RIGHTS_ALL | + KEY_QUERY_VALUE | + KEY_SET_VALUE | + KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | - KEY_NOTIFY | + KEY_NOTIFY | KEY_CREATE_LINK) & (~SYNCHRONIZE) // Open/Create Options @@ -385,17 +407,19 @@ REG_OPTION_BACKUP_RESTORE :: 0x00000004 REG_OPTION_OPEN_LINK :: 0x00000008 REG_OPTION_DONT_VIRTUALIZE :: 0x00000010 -REG_LEGAL_OPTION :: REG_OPTION_RESERVED | - REG_OPTION_NON_VOLATILE | - REG_OPTION_VOLATILE | - REG_OPTION_CREATE_LINK | +REG_LEGAL_OPTION :: \ + REG_OPTION_RESERVED | + REG_OPTION_NON_VOLATILE | + REG_OPTION_VOLATILE | + REG_OPTION_CREATE_LINK | REG_OPTION_BACKUP_RESTORE | - REG_OPTION_OPEN_LINK | + REG_OPTION_OPEN_LINK | REG_OPTION_DONT_VIRTUALIZE -REG_OPEN_LEGAL_OPTION :: REG_OPTION_RESERVED | +REG_OPEN_LEGAL_OPTION :: \ + REG_OPTION_RESERVED | REG_OPTION_BACKUP_RESTORE | - REG_OPTION_OPEN_LINK | + REG_OPTION_OPEN_LINK | REG_OPTION_DONT_VIRTUALIZE // Key creation/open disposition @@ -437,10 +461,11 @@ REG_NOTIFY_CHANGE_LAST_SET :: 0x00000004 REG_NOTIFY_CHANGE_SECURITY :: 0x00000008 REG_NOTIFY_THREAD_AGNOSTIC :: 0x10000000 -REG_LEGAL_CHANGE_FILTER :: REG_NOTIFY_CHANGE_NAME | +REG_LEGAL_CHANGE_FILTER :: \ + REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES | - REG_NOTIFY_CHANGE_LAST_SET | - REG_NOTIFY_CHANGE_SECURITY | + REG_NOTIFY_CHANGE_LAST_SET | + REG_NOTIFY_CHANGE_SECURITY | REG_NOTIFY_THREAD_AGNOSTIC // Predefined Value Types. @@ -461,9 +486,9 @@ REG_QWORD_LITTLE_ENDIAN :: 11 BSMINFO :: struct { cbSize: UINT, - hdesk: HDESK, - hwnd: HWND, - luid: LUID, + hdesk: HDESK, + hwnd: HWND, + luid: LUID, } PBSMINFO :: ^BSMINFO @@ -545,37 +570,37 @@ COLOR_BTNHILIGHT :: COLOR_BTNHIGHLIGHT // Common Control Notification Code Ranges NM_FIRST :: 0 -NM_LAST :: ~DWORD(99 - 1) -LVN_FIRST :: ~DWORD(100 - 1) -LVN_LAST :: ~DWORD(199 - 1) -HDN_FIRST :: ~DWORD(300 - 1) -HDN_LAST :: ~DWORD(399 - 1) -TVN_FIRST :: ~DWORD(400 - 1) -TVN_LAST :: ~DWORD(499 - 1) -TTN_FIRST :: ~DWORD(520 - 1) -TTN_LAST :: ~DWORD(549 - 1) -TCN_FIRST :: ~DWORD(550 - 1) -TCN_LAST :: ~DWORD(580 - 1) -CDN_FIRST :: ~DWORD(601 - 1) -CDN_LAST :: ~DWORD(699 - 1) -TBN_FIRST :: ~DWORD(700 - 1) -TBN_LAST :: ~DWORD(720 - 1) -UDN_FIRST :: ~DWORD(721 - 1) -UDN_LAST :: ~DWORD(740 - 1) -MCN_FIRST :: ~DWORD(750 - 1) -MCN_LAST :: ~DWORD(759 - 1) -DTN_FIRST :: ~DWORD(760 - 1) -DTN_LAST :: ~DWORD(799 - 1) -CBEN_FIRST :: ~DWORD(800 - 1) -CBEN_LAST :: ~DWORD(830 - 1) -RBN_FIRST :: ~DWORD(831 - 1) -RBN_LAST :: ~DWORD(859 - 1) -IPN_FIRST :: ~DWORD(860 - 1) -IPN_LAST :: ~DWORD(879 - 1) -SBN_FIRST :: ~DWORD(880 - 1) -SBN_LAST :: ~DWORD(899 - 1) -PGN_FIRST :: ~DWORD(900 - 1) -PGN_LAST :: ~DWORD(950 - 1) +NM_LAST :: ~DWORD( 99 - 1) +LVN_FIRST :: ~DWORD( 100 - 1) +LVN_LAST :: ~DWORD( 199 - 1) +HDN_FIRST :: ~DWORD( 300 - 1) +HDN_LAST :: ~DWORD( 399 - 1) +TVN_FIRST :: ~DWORD( 400 - 1) +TVN_LAST :: ~DWORD( 499 - 1) +TTN_FIRST :: ~DWORD( 520 - 1) +TTN_LAST :: ~DWORD( 549 - 1) +TCN_FIRST :: ~DWORD( 550 - 1) +TCN_LAST :: ~DWORD( 580 - 1) +CDN_FIRST :: ~DWORD( 601 - 1) +CDN_LAST :: ~DWORD( 699 - 1) +TBN_FIRST :: ~DWORD( 700 - 1) +TBN_LAST :: ~DWORD( 720 - 1) +UDN_FIRST :: ~DWORD( 721 - 1) +UDN_LAST :: ~DWORD( 740 - 1) +MCN_FIRST :: ~DWORD( 750 - 1) +MCN_LAST :: ~DWORD( 759 - 1) +DTN_FIRST :: ~DWORD( 760 - 1) +DTN_LAST :: ~DWORD( 799 - 1) +CBEN_FIRST :: ~DWORD( 800 - 1) +CBEN_LAST :: ~DWORD( 830 - 1) +RBN_FIRST :: ~DWORD( 831 - 1) +RBN_LAST :: ~DWORD( 859 - 1) +IPN_FIRST :: ~DWORD( 860 - 1) +IPN_LAST :: ~DWORD( 879 - 1) +SBN_FIRST :: ~DWORD( 880 - 1) +SBN_LAST :: ~DWORD( 899 - 1) +PGN_FIRST :: ~DWORD( 900 - 1) +PGN_LAST :: ~DWORD( 950 - 1) WMN_FIRST :: ~DWORD(1000 - 1) WMN_LAST :: ~DWORD(1200 - 1) BCN_FIRST :: ~DWORD(1250 - 1) @@ -1255,61 +1280,61 @@ HOOKPROC :: #type proc "system" (code: c_int, wParam: WPARAM, lParam: LPARAM) -> WINEVENTPROC :: #type proc "system" ( hWinEventHook: HWINEVENTHOOK, - event: DWORD, - hwnd: HWND, - idObject, idChild: LONG, + event: DWORD, + hwnd: HWND, + idObject, idChild: LONG, idEventThread, dwmsEventTime: DWORD, ) CWPRETSTRUCT :: struct { lResult: LRESULT, - lParam: LPARAM, - wParam: WPARAM, + lParam: LPARAM, + wParam: WPARAM, message: UINT, - hwnd: HWND, + hwnd: HWND, } MSLLHOOKSTRUCT :: struct { - pt: POINT, - mouseData: DWORD, - flags: DWORD, - time: DWORD, + pt: POINT, + mouseData: DWORD, + flags: DWORD, + time: DWORD, dwExtraInfo: ULONG_PTR, } KBDLLHOOKSTRUCT :: struct { - vkCode: DWORD, - scanCode: DWORD, - flags: DWORD, - time: DWORD, + vkCode: DWORD, + scanCode: DWORD, + flags: DWORD, + time: DWORD, dwExtraInfo: ULONG_PTR, } MOUSEINPUT :: struct { - dx: LONG, - dy: LONG, - mouseData: DWORD, - dwFlags: DWORD, - time: DWORD, + dx: LONG, + dy: LONG, + mouseData: DWORD, + dwFlags: DWORD, + time: DWORD, dwExtraInfo: ULONG_PTR, } KEYBDINPUT :: struct { - wVk: WORD, - wScan: WORD, - dwFlags: DWORD, - time: DWORD, + wVk: WORD, + wScan: WORD, + dwFlags: DWORD, + time: DWORD, dwExtraInfo: ULONG_PTR, } HARDWAREINPUT :: struct { - uMsg: DWORD, + uMsg: DWORD, wParamL: WORD, wParamH: WORD, } INPUT_TYPE :: enum DWORD { - MOUSE = 0, + MOUSE = 0, KEYBOARD = 1, HARDWARE = 2, } @@ -1317,128 +1342,128 @@ INPUT_TYPE :: enum DWORD { INPUT :: struct { type: INPUT_TYPE, using _: struct #raw_union { - mi: MOUSEINPUT, - ki: KEYBDINPUT, - hi: HARDWAREINPUT, + mi: MOUSEINPUT `raw_union_tag:"type=MOUSE"`, + ki: KEYBDINPUT `raw_union_tag:"type=KEYBOARD"`, + hi: HARDWAREINPUT `raw_union_tag:"type=HARDWARE"`, }, } -MOUSEEVENTF_MOVE :: 0x0001 -MOUSEEVENTF_LEFTDOWN :: 0x0002 -MOUSEEVENTF_LEFTUP :: 0x0004 -MOUSEEVENTF_RIGHTDOWN :: 0x0008 -MOUSEEVENTF_RIGHTUP :: 0x0010 -MOUSEEVENTF_MIDDLEDOWN :: 0x0020 -MOUSEEVENTF_MIDDLEUP :: 0x0040 -MOUSEEVENTF_XDOWN :: 0x0080 -MOUSEEVENTF_XUP :: 0x0100 -MOUSEEVENTF_WHEEL :: 0x0800 -MOUSEEVENTF_HWHEEL :: 0x1000 +MOUSEEVENTF_MOVE :: 0x0001 +MOUSEEVENTF_LEFTDOWN :: 0x0002 +MOUSEEVENTF_LEFTUP :: 0x0004 +MOUSEEVENTF_RIGHTDOWN :: 0x0008 +MOUSEEVENTF_RIGHTUP :: 0x0010 +MOUSEEVENTF_MIDDLEDOWN :: 0x0020 +MOUSEEVENTF_MIDDLEUP :: 0x0040 +MOUSEEVENTF_XDOWN :: 0x0080 +MOUSEEVENTF_XUP :: 0x0100 +MOUSEEVENTF_WHEEL :: 0x0800 +MOUSEEVENTF_HWHEEL :: 0x1000 MOUSEEVENTF_MOVE_NOCOALESCE :: 0x2000 -MOUSEEVENTF_VIRTUALDESK :: 0x4000 -MOUSEEVENTF_ABSOLUTE :: 0x8000 +MOUSEEVENTF_VIRTUALDESK :: 0x4000 +MOUSEEVENTF_ABSOLUTE :: 0x8000 WNDCLASSA :: struct { - style: UINT, - lpfnWndProc: WNDPROC, - cbClsExtra: c_int, - cbWndExtra: c_int, - hInstance: HINSTANCE, - hIcon: HICON, - hCursor: HCURSOR, + style: UINT, + lpfnWndProc: WNDPROC, + cbClsExtra: c_int, + cbWndExtra: c_int, + hInstance: HINSTANCE, + hIcon: HICON, + hCursor: HCURSOR, hbrBackground: HBRUSH, - lpszMenuName: LPCSTR, + lpszMenuName: LPCSTR, lpszClassName: LPCSTR, } WNDCLASSW :: struct { - style: UINT, - lpfnWndProc: WNDPROC, - cbClsExtra: c_int, - cbWndExtra: c_int, - hInstance: HINSTANCE, - hIcon: HICON, - hCursor: HCURSOR, + style: UINT, + lpfnWndProc: WNDPROC, + cbClsExtra: c_int, + cbWndExtra: c_int, + hInstance: HINSTANCE, + hIcon: HICON, + hCursor: HCURSOR, hbrBackground: HBRUSH, - lpszMenuName: LPCWSTR, + lpszMenuName: LPCWSTR, lpszClassName: LPCWSTR, } WNDCLASSEXA :: struct { - cbSize: UINT, - style: UINT, - lpfnWndProc: WNDPROC, - cbClsExtra: c_int, - cbWndExtra: c_int, - hInstance: HINSTANCE, - hIcon: HICON, - hCursor: HCURSOR, + cbSize: UINT, + style: UINT, + lpfnWndProc: WNDPROC, + cbClsExtra: c_int, + cbWndExtra: c_int, + hInstance: HINSTANCE, + hIcon: HICON, + hCursor: HCURSOR, hbrBackground: HBRUSH, - lpszMenuName: LPCSTR, + lpszMenuName: LPCSTR, lpszClassName: LPCSTR, - hIconSm: HICON, + hIconSm: HICON, } WNDCLASSEXW :: struct { - cbSize: UINT, - style: UINT, - lpfnWndProc: WNDPROC, - cbClsExtra: c_int, - cbWndExtra: c_int, - hInstance: HINSTANCE, - hIcon: HICON, - hCursor: HCURSOR, + cbSize: UINT, + style: UINT, + lpfnWndProc: WNDPROC, + cbClsExtra: c_int, + cbWndExtra: c_int, + hInstance: HINSTANCE, + hIcon: HICON, + hCursor: HCURSOR, hbrBackground: HBRUSH, - lpszMenuName: LPCWSTR, + lpszMenuName: LPCWSTR, lpszClassName: LPCWSTR, - hIconSm: HICON, + hIconSm: HICON, } MSG :: struct { - hwnd: HWND, + hwnd: HWND, message: UINT, - wParam: WPARAM, - lParam: LPARAM, - time: DWORD, - pt: POINT, + wParam: WPARAM, + lParam: LPARAM, + time: DWORD, + pt: POINT, } LPMSG :: ^MSG NOTIFYICONDATAW :: struct { - cbSize: DWORD, - hWnd: HWND, - uID: UINT, - uFlags: UINT, + cbSize: DWORD, + hWnd: HWND, + uID: UINT, + uFlags: UINT, uCallbackMessage: UINT, - hIcon: HICON, - szTip: [128]WCHAR, - dwState: DWORD, - dwStateMask: DWORD, - szInfo: [256]WCHAR, + hIcon: HICON, + szTip: [128]WCHAR, + dwState: DWORD, + dwStateMask: DWORD, + szInfo: [256]WCHAR, using _: struct #raw_union { uTimeout: UINT, uVersion: UINT, }, - szInfoTitle: [64]WCHAR, - dwInfoFlags: DWORD, - guidItem: GUID, + szInfoTitle: [64]WCHAR, + dwInfoFlags: DWORD, + guidItem: GUID, hBalloonIcon: HICON, } -NIF_MESSAGE :: 0x00000001 -NIF_ICON :: 0x00000002 -NIF_TIP :: 0x00000004 -NIF_STATE :: 0x00000008 -NIF_INFO :: 0x00000010 -NIF_GUID :: 0x00000020 +NIF_MESSAGE :: 0x00000001 +NIF_ICON :: 0x00000002 +NIF_TIP :: 0x00000004 +NIF_STATE :: 0x00000008 +NIF_INFO :: 0x00000010 +NIF_GUID :: 0x00000020 NIF_REALTIME :: 0x00000040 -NIF_SHOWTIP :: 0x00000080 +NIF_SHOWTIP :: 0x00000080 -NIM_ADD :: 0x00000000 -NIM_MODIFY :: 0x00000001 -NIM_DELETE :: 0x00000002 -NIM_SETFOCUS :: 0x00000003 +NIM_ADD :: 0x00000000 +NIM_MODIFY :: 0x00000001 +NIM_DELETE :: 0x00000002 +NIM_SETFOCUS :: 0x00000003 NIM_SETVERSION :: 0x00000004 // Menu flags for Add/Check/EnableMenuItem() @@ -1448,37 +1473,37 @@ MF_APPEND :: 0x00000100 MF_DELETE :: 0x00000200 MF_REMOVE :: 0x00001000 -MF_BYCOMMAND :: 0x00000000 +MF_BYCOMMAND :: 0x00000000 MF_BYPOSITION :: 0x00000400 MF_SEPARATOR :: 0x00000800 -MF_ENABLED :: 0x00000000 -MF_GRAYED :: 0x00000001 +MF_ENABLED :: 0x00000000 +MF_GRAYED :: 0x00000001 MF_DISABLED :: 0x00000002 -MF_UNCHECKED :: 0x00000000 -MF_CHECKED :: 0x00000008 +MF_UNCHECKED :: 0x00000000 +MF_CHECKED :: 0x00000008 MF_USECHECKBITMAPS :: 0x00000200 -MF_STRING :: 0x00000000 -MF_BITMAP :: 0x00000004 +MF_STRING :: 0x00000000 +MF_BITMAP :: 0x00000004 MF_OWNERDRAW :: 0x00000100 -MF_POPUP :: 0x00000010 +MF_POPUP :: 0x00000010 MF_MENUBARBREAK :: 0x00000020 -MF_MENUBREAK :: 0x00000040 +MF_MENUBREAK :: 0x00000040 MF_UNHILITE :: 0x00000000 -MF_HILITE :: 0x00000080 +MF_HILITE :: 0x00000080 -MF_DEFAULT :: 0x00001000 -MF_SYSMENU :: 0x00002000 -MF_HELP :: 0x00004000 +MF_DEFAULT :: 0x00001000 +MF_SYSMENU :: 0x00002000 +MF_HELP :: 0x00004000 MF_RIGHTJUSTIFY :: 0x00004000 MF_MOUSESELECT :: 0x00008000 -MF_END :: 0x00000080 // Obsolete -- only used by old RES files +MF_END :: 0x00000080 // Obsolete -- only used by old RES files // Menu flags for Add/Check/EnableMenuItem() MFS_GRAYED :: 0x00000003 @@ -1491,27 +1516,27 @@ MFS_UNHILITE :: MF_UNHILITE MFS_DEFAULT :: MF_DEFAULT // Flags for TrackPopupMenu -TPM_LEFTBUTTON :: 0x0000 -TPM_RIGHTBUTTON :: 0x0002 -TPM_LEFTALIGN :: 0x0000 -TPM_CENTERALIGN :: 0x0004 -TPM_RIGHTALIGN :: 0x0008 -TPM_TOPALIGN :: 0x0000 +TPM_LEFTBUTTON :: 0x0000 +TPM_RIGHTBUTTON :: 0x0002 +TPM_LEFTALIGN :: 0x0000 +TPM_CENTERALIGN :: 0x0004 +TPM_RIGHTALIGN :: 0x0008 +TPM_TOPALIGN :: 0x0000 TPM_VCENTERALIGN :: 0x0010 -TPM_BOTTOMALIGN :: 0x0020 +TPM_BOTTOMALIGN :: 0x0020 -TPM_HORIZONTAL :: 0x0000 /* Horz alignment matters more */ -TPM_VERTICAL :: 0x0040 /* Vert alignment matters more */ -TPM_NONOTIFY :: 0x0080 /* Don't send any notification msgs */ -TPM_RETURNCMD :: 0x0100 -TPM_RECURSE :: 0x0001 +TPM_HORIZONTAL :: 0x0000 /* Horz alignment matters more */ +TPM_VERTICAL :: 0x0040 /* Vert alignment matters more */ +TPM_NONOTIFY :: 0x0080 /* Don't send any notification msgs */ +TPM_RETURNCMD :: 0x0100 +TPM_RECURSE :: 0x0001 TPM_HORPOSANIMATION :: 0x0400 TPM_HORNEGANIMATION :: 0x0800 TPM_VERPOSANIMATION :: 0x1000 TPM_VERNEGANIMATION :: 0x2000 -TPM_NOANIMATION :: 0x4000 -TPM_LAYOUTRTL :: 0x8000 -TPM_WORKAREA :: 0x10000 +TPM_NOANIMATION :: 0x4000 +TPM_LAYOUTRTL :: 0x8000 +TPM_WORKAREA :: 0x10000 // WM_NCHITTEST and MOUSEHOOKSTRUCT Mouse Position Codes HTERROR :: -2 @@ -1545,42 +1570,42 @@ HTCLOSE :: 20 HTHELP :: 21 TEXTMETRICW :: struct { - tmHeight: LONG, - tmAscent: LONG, - tmDescent: LONG, - tmInternalLeading: LONG, - tmExternalLeading: LONG, - tmAveCharWidth: LONG, - tmMaxCharWidth: LONG, - tmWeight: LONG, - tmOverhang: LONG, + tmHeight: LONG, + tmAscent: LONG, + tmDescent: LONG, + tmInternalLeading: LONG, + tmExternalLeading: LONG, + tmAveCharWidth: LONG, + tmMaxCharWidth: LONG, + tmWeight: LONG, + tmOverhang: LONG, tmDigitizedAspectX: LONG, tmDigitizedAspectY: LONG, - tmFirstChar: WCHAR, - tmLastChar: WCHAR, - tmDefaultChar: WCHAR, - tmBreakChar: WCHAR, - tmItalic: BYTE, - tmUnderlined: BYTE, - tmStruckOut: BYTE, - tmPitchAndFamily: BYTE, - tmCharSet: BYTE, + tmFirstChar: WCHAR, + tmLastChar: WCHAR, + tmDefaultChar: WCHAR, + tmBreakChar: WCHAR, + tmItalic: BYTE, + tmUnderlined: BYTE, + tmStruckOut: BYTE, + tmPitchAndFamily: BYTE, + tmCharSet: BYTE, } LPTEXTMETRICW :: ^TEXTMETRICW PAINTSTRUCT :: struct { - hdc: HDC, - fErase: BOOL, - rcPaint: RECT, - fRestore: BOOL, - fIncUpdate: BOOL, + hdc: HDC, + fErase: BOOL, + rcPaint: RECT, + fRestore: BOOL, + fIncUpdate: BOOL, rgbReserved: [32]BYTE, } TRACKMOUSEEVENT :: struct { - cbSize: DWORD, - dwFlags: DWORD, - hwndTrack: HWND, + cbSize: DWORD, + dwFlags: DWORD, + hwndTrack: HWND, dwHoverTime: DWORD, } @@ -1640,16 +1665,16 @@ MAX_LINKID_TEXT :: 48 L_MAX_URL_LENGTH :: 2048 + 32 + len("://") LITEM :: struct { - mask: UINT, - iLink: c_int, - state: UINT, + mask: UINT, + iLink: c_int, + state: UINT, stateMask: UINT, - szID: [MAX_LINKID_TEXT]WCHAR, - szUrl: [L_MAX_URL_LENGTH]WCHAR, + szID: [MAX_LINKID_TEXT]WCHAR, + szUrl: [L_MAX_URL_LENGTH]WCHAR, } NMLINK :: struct { - hdr: NMHDR, + hdr: NMHDR, item: LITEM, } @@ -1660,12 +1685,12 @@ NMHDR :: struct { } NMCUSTOMDRAW :: struct { - hdr: NMHDR, + hdr: NMHDR, dwDrawStage: DWORD, - hdc: HDC, - rc: RECT, - dwItemSpec: DWORD_PTR, - uItemState: UINT, + hdc: HDC, + rc: RECT, + dwItemSpec: DWORD_PTR, + uItemState: UINT, lItemlParam: LPARAM, } @@ -1701,14 +1726,14 @@ NM_TVSTATEIMAGECHANGING :: NM_OUTOFMEMORY-23 // uses NMTVSTATEIMAGECHANGING stru PCZZWSTR :: cstring16 SHFILEOPSTRUCTW :: struct { - hwnd: HWND, - wFunc: UINT, - pFrom: PCZZWSTR, - pTo: PCZZWSTR, - fFlags: FILEOP_FLAGS, + hwnd: HWND, + wFunc: UINT, + pFrom: PCZZWSTR, + pTo: PCZZWSTR, + fFlags: FILEOP_FLAGS, fAnyOperationsAborted: BOOL, - hNameMappings: LPVOID, - lpszProgressTitle: PCWSTR, // only used if FOF_SIMPLEPROGRESS + hNameMappings: LPVOID, + lpszProgressTitle: PCWSTR, // only used if FOF_SIMPLEPROGRESS } LPSHFILEOPSTRUCTW :: ^SHFILEOPSTRUCTW @@ -1741,7 +1766,7 @@ FOF_NO_UI :: (FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FILEOP_FLAGS :: WORD DEVMODEW :: struct { - dmDeviceName: [32]wchar_t, + dmDeviceName: [32]wchar_t, dmSpecVersion: WORD, dmDriverVersion: WORD, dmSize: WORD, @@ -1887,7 +1912,7 @@ WS_MINIMIZE : UINT : 0x2000_0000 WS_MINIMIZEBOX : UINT : 0x0002_0000 WS_OVERLAPPED : UINT : 0x0000_0000 WS_OVERLAPPEDWINDOW : UINT : WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX -WS_POPUP : UINT : 0x8000_0000 +WS_POPUP : UINT : 0x8000_0000 WS_POPUPWINDOW : UINT : WS_POPUP | WS_BORDER | WS_SYSMENU WS_SIZEBOX : UINT : 0x0004_0000 WS_SYSMENU : UINT : 0x0008_0000 @@ -2227,24 +2252,24 @@ SEE_MASK_FLAG_LOG_USAGE :: 0x04000000 SEE_MASK_FLAG_HINST_IS_SITE :: 0x08000000 SHELLEXECUTEINFOW :: struct { - cbSize: DWORD, // in, required, sizeof of this structure - fMask: ULONG, // in, SEE_MASK_XXX values - hwnd: HWND, // in, optional - lpVerb: LPCWSTR, // in, optional when unspecified the default verb is choosen - lpFile: LPCWSTR, // in, either this value or lpIDList must be specified - lpParameters: LPCWSTR, // in, optional - lpDirectory: LPCWSTR, // in, optional - nShow: c.int, // in, required - hInstApp: HINSTANCE, // out when SEE_MASK_NOCLOSEPROCESS is specified - lpIDList: rawptr, // in, valid when SEE_MASK_IDLIST is specified, PCIDLIST_ABSOLUTE, for use with SEE_MASK_IDLIST & SEE_MASK_INVOKEIDLIST - lpClass: LPCWSTR, // in, valid when SEE_MASK_CLASSNAME is specified - hkeyClass: HKEY, // in, valid when SEE_MASK_CLASSKEY is specified - dwHotKey: DWORD, // in, valid when SEE_MASK_HOTKEY is specified - DUMMYUNIONNAME: struct #raw_union { - hIcon: HANDLE, // not used - hMonitor: HANDLE, // in, valid when SEE_MASK_HMONITOR specified + cbSize: DWORD, // in, required, sizeof of this structure + fMask: ULONG, // in, SEE_MASK_XXX values + hwnd: HWND, // in, optional + lpVerb: LPCWSTR, // in, optional when unspecified the default verb is choosen + lpFile: LPCWSTR, // in, either this value or lpIDList must be specified + lpParameters: LPCWSTR, // in, optional + lpDirectory: LPCWSTR, // in, optional + nShow: c_int, // in, required + hInstApp: HINSTANCE, // out when SEE_MASK_NOCLOSEPROCESS is specified + lpIDList: rawptr, // in, valid when SEE_MASK_IDLIST is specified, PCIDLIST_ABSOLUTE, for use with SEE_MASK_IDLIST & SEE_MASK_INVOKEIDLIST + lpClass: LPCWSTR, // in, valid when SEE_MASK_CLASSNAME is specified + hkeyClass: HKEY, // in, valid when SEE_MASK_CLASSKEY is specified + dwHotKey: DWORD, // in, valid when SEE_MASK_HOTKEY is specified + using DUMMYUNIONNAME: struct #raw_union { + hIcon: HANDLE, // not used + hMonitor: HANDLE, // in, valid when SEE_MASK_HMONITOR specified }, - hProcess: HANDLE, // out, valid when SEE_MASK_NOCLOSEPROCESS specified + hProcess: HANDLE, // out, valid when SEE_MASK_NOCLOSEPROCESS specified } LPSHELLEXECUTEINFOW :: ^SHELLEXECUTEINFOW @@ -2291,9 +2316,9 @@ WA_CLICKACTIVE :: 2 // Struct pointed to by WM_GETMINMAXINFO lParam MINMAXINFO :: struct { - ptReserved: POINT, - ptMaxSize: POINT, - ptMaxPosition: POINT, + ptReserved: POINT, + ptMaxSize: POINT, + ptMaxPosition: POINT, ptMinTrackSize: POINT, ptMaxTrackSize: POINT, } @@ -2514,53 +2539,53 @@ STOCK_LAST :: 19 CLR_INVALID :: 0xFFFFFFFF RGBQUAD :: struct { - rgbBlue: BYTE, - rgbGreen: BYTE, - rgbRed: BYTE, + rgbBlue: BYTE, + rgbGreen: BYTE, + rgbRed: BYTE, rgbReserved: BYTE, } PIXELFORMATDESCRIPTOR :: struct { - nSize: WORD, - nVersion: WORD, - dwFlags: DWORD, - iPixelType: BYTE, - cColorBits: BYTE, - cRedBits: BYTE, - cRedShift: BYTE, - cGreenBits: BYTE, - cGreenShift: BYTE, - cBlueBits: BYTE, - cBlueShift: BYTE, - cAlphaBits: BYTE, - cAlphaShift: BYTE, - cAccumBits: BYTE, - cAccumRedBits: BYTE, + nSize: WORD, + nVersion: WORD, + dwFlags: DWORD, + iPixelType: BYTE, + cColorBits: BYTE, + cRedBits: BYTE, + cRedShift: BYTE, + cGreenBits: BYTE, + cGreenShift: BYTE, + cBlueBits: BYTE, + cBlueShift: BYTE, + cAlphaBits: BYTE, + cAlphaShift: BYTE, + cAccumBits: BYTE, + cAccumRedBits: BYTE, cAccumGreenBits: BYTE, - cAccumBlueBits: BYTE, + cAccumBlueBits: BYTE, cAccumAlphaBits: BYTE, - cDepthBits: BYTE, - cStencilBits: BYTE, - cAuxBuffers: BYTE, - iLayerType: BYTE, - bReserved: BYTE, - dwLayerMask: DWORD, - dwVisibleMask: DWORD, - dwDamageMask: DWORD, + cDepthBits: BYTE, + cStencilBits: BYTE, + cAuxBuffers: BYTE, + iLayerType: BYTE, + bReserved: BYTE, + dwLayerMask: DWORD, + dwVisibleMask: DWORD, + dwDamageMask: DWORD, } BITMAPINFOHEADER :: struct { - biSize: DWORD, - biWidth: LONG, - biHeight: LONG, - biPlanes: WORD, - biBitCount: WORD, - biCompression: DWORD, - biSizeImage: DWORD, + biSize: DWORD, + biWidth: LONG, + biHeight: LONG, + biPlanes: WORD, + biBitCount: WORD, + biCompression: DWORD, + biSizeImage: DWORD, biXPelsPerMeter: LONG, biYPelsPerMeter: LONG, - biClrUsed: DWORD, - biClrImportant: DWORD, + biClrUsed: DWORD, + biClrImportant: DWORD, } BITMAPINFO :: struct { @@ -2668,64 +2693,66 @@ CONDITION_VARIABLE_INIT :: CONDITION_VARIABLE{} SRWLOCK_INIT :: SRWLOCK{} // Flags in STARTUPINFOW.dwFlags. -STARTF_USESHOWWINDOW: DWORD : 0x00000001 -STARTF_USESIZE: DWORD : 0x00000002 -STARTF_USEPOSITION: DWORD : 0x00000004 -STARTF_USECOUNTCHARS: DWORD : 0x00000008 -STARTF_USEFILLATTRIBUTE: DWORD : 0x00000010 -STARTF_RUNFULLSCREEN: DWORD : 0x00000020 // ignored for non-x86 platforms -STARTF_FORCEONFEEDBACK: DWORD : 0x00000040 -STARTF_FORCEOFFFEEDBACK: DWORD : 0x00000080 -STARTF_USESTDHANDLES: DWORD : 0x00000100 +STARTF_USESHOWWINDOW : DWORD : 0x00000001 +STARTF_USESIZE : DWORD : 0x00000002 +STARTF_USEPOSITION : DWORD : 0x00000004 +STARTF_USECOUNTCHARS : DWORD : 0x00000008 +STARTF_USEFILLATTRIBUTE : DWORD : 0x00000010 +STARTF_RUNFULLSCREEN : DWORD : 0x00000020 // ignored for non-x86 platforms +STARTF_FORCEONFEEDBACK : DWORD : 0x00000040 +STARTF_FORCEOFFFEEDBACK : DWORD : 0x00000080 +STARTF_USESTDHANDLES : DWORD : 0x00000100 // WINVER >= 0x400 -STARTF_USEHOTKEY: DWORD : 0x00000200 -STARTF_TITLEISLINKNAME: DWORD : 0x00000800 -STARTF_TITLEISAPPID: DWORD : 0x00001000 -STARTF_PREVENTPINNING: DWORD : 0x00002000 +STARTF_USEHOTKEY : DWORD : 0x00000200 +STARTF_TITLEISLINKNAME : DWORD : 0x00000800 +STARTF_TITLEISAPPID : DWORD : 0x00001000 +STARTF_PREVENTPINNING : DWORD : 0x00002000 // WINVER >= 0x600 -STARTF_UNTRUSTEDSOURCE: DWORD : 0x00008000 +STARTF_UNTRUSTEDSOURCE : DWORD : 0x00008000 VOLUME_NAME_DOS: DWORD : 0x0 -MOVEFILE_COPY_ALLOWED: DWORD: 0x2 -MOVEFILE_CREATE_HARDLINK: DWORD: 0x10 -MOVEFILE_DELAY_UNTIL_REBOOT: DWORD: 0x4 -MOVEFILE_FAIL_IF_NOT_TRACKABLE: DWORD: 0x20 -MOVEFILE_REPLACE_EXISTING: DWORD : 0x1 -MOVEFILE_WRITE_THROUGH: DWORD: 0x8 +MOVEFILE_COPY_ALLOWED : DWORD : 0x2 +MOVEFILE_CREATE_HARDLINK : DWORD : 0x10 +MOVEFILE_DELAY_UNTIL_REBOOT : DWORD : 0x4 +MOVEFILE_FAIL_IF_NOT_TRACKABLE : DWORD : 0x20 +MOVEFILE_REPLACE_EXISTING : DWORD : 0x1 +MOVEFILE_WRITE_THROUGH : DWORD : 0x8 -FILE_BEGIN: DWORD : 0 -FILE_CURRENT: DWORD : 1 -FILE_END: DWORD : 2 +FILE_BEGIN : DWORD : 0 +FILE_CURRENT : DWORD : 1 +FILE_END : DWORD : 2 -WAIT_OBJECT_0: DWORD : 0x00000000 -WAIT_TIMEOUT: DWORD : 258 -WAIT_FAILED: DWORD : 0xFFFFFFFF +WAIT_OBJECT_0 : DWORD : 0x00000000 +WAIT_TIMEOUT : DWORD : 258 +WAIT_FAILED : DWORD : 0xFFFFFFFF -FILE_FLAG_WRITE_THROUGH: DWORD : 0x80000000 -FILE_FLAG_OVERLAPPED: DWORD : 0x40000000 -FILE_FLAG_NO_BUFFERING: DWORD : 0x20000000 -FILE_FLAG_RANDOM_ACCESS: DWORD : 0x10000000 -FILE_FLAG_SEQUENTIAL_SCAN: DWORD : 0x08000000 -FILE_FLAG_DELETE_ON_CLOSE: DWORD : 0x04000000 -FILE_FLAG_BACKUP_SEMANTICS: DWORD : 0x02000000 -FILE_FLAG_POSIX_SEMANTICS: DWORD : 0x01000000 -FILE_FLAG_SESSION_AWARE: DWORD : 0x00800000 -FILE_FLAG_OPEN_REPARSE_POINT: DWORD : 0x00200000 -FILE_FLAG_OPEN_NO_RECALL: DWORD : 0x00100000 -FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD : 0x00080000 +WAIT_IO_COMPLETION: DWORD : 0x000000C0 -PIPE_ACCESS_INBOUND: DWORD : 0x00000001 -PIPE_ACCESS_OUTBOUND: DWORD : 0x00000002 -PIPE_ACCESS_DUPLEX: DWORD : 0x00000003 -PIPE_WAIT: DWORD : 0x00000000 -PIPE_TYPE_BYTE: DWORD : 0x00000000 -PIPE_TYPE_MESSAGE: DWORD : 0x00000004 -PIPE_REJECT_REMOTE_CLIENTS: DWORD : 0x00000008 -PIPE_READMODE_BYTE: DWORD : 0x00000000 -PIPE_READMODE_MESSAGE: DWORD : 0x00000002 -PIPE_ACCEPT_REMOTE_CLIENTS: DWORD : 0x00000000 +FILE_FLAG_WRITE_THROUGH : DWORD : 0x80000000 +FILE_FLAG_OVERLAPPED : DWORD : 0x40000000 +FILE_FLAG_NO_BUFFERING : DWORD : 0x20000000 +FILE_FLAG_RANDOM_ACCESS : DWORD : 0x10000000 +FILE_FLAG_SEQUENTIAL_SCAN : DWORD : 0x08000000 +FILE_FLAG_DELETE_ON_CLOSE : DWORD : 0x04000000 +FILE_FLAG_BACKUP_SEMANTICS : DWORD : 0x02000000 +FILE_FLAG_POSIX_SEMANTICS : DWORD : 0x01000000 +FILE_FLAG_SESSION_AWARE : DWORD : 0x00800000 +FILE_FLAG_OPEN_REPARSE_POINT : DWORD : 0x00200000 +FILE_FLAG_OPEN_NO_RECALL : DWORD : 0x00100000 +FILE_FLAG_FIRST_PIPE_INSTANCE : DWORD : 0x00080000 + +PIPE_ACCESS_INBOUND : DWORD : 0x00000001 +PIPE_ACCESS_OUTBOUND : DWORD : 0x00000002 +PIPE_ACCESS_DUPLEX : DWORD : 0x00000003 +PIPE_WAIT : DWORD : 0x00000000 +PIPE_TYPE_BYTE : DWORD : 0x00000000 +PIPE_TYPE_MESSAGE : DWORD : 0x00000004 +PIPE_REJECT_REMOTE_CLIENTS : DWORD : 0x00000008 +PIPE_READMODE_BYTE : DWORD : 0x00000000 +PIPE_READMODE_MESSAGE : DWORD : 0x00000002 +PIPE_ACCEPT_REMOTE_CLIENTS : DWORD : 0x00000000 FD_SETSIZE :: 64 @@ -2739,10 +2766,10 @@ HANDLE_FLAG_INHERIT: DWORD : 0x00000001 HANDLE_FLAG_PROTECT_FROM_CLOSE :: 0x00000002 GENERIC_MAPPING :: struct { - GenericRead: ACCESS_MASK, - GenericWrite: ACCESS_MASK, + GenericRead: ACCESS_MASK, + GenericWrite: ACCESS_MASK, GenericExecute: ACCESS_MASK, - GenericAll: ACCESS_MASK, + GenericAll: ACCESS_MASK, } PGENERIC_MAPPING :: ^GENERIC_MAPPING @@ -2758,14 +2785,14 @@ ANYSIZE_ARRAY :: 1 PLUID_AND_ATTRIBUTES :: ^LUID_AND_ATTRIBUTES LUID_AND_ATTRIBUTES :: struct { - Luid: LUID, + Luid: LUID, Attributes: DWORD, } PRIVILEGE_SET :: struct { PrivilegeCount: DWORD, - Control: DWORD, - Privilege: [ANYSIZE_ARRAY]LUID_AND_ATTRIBUTES, + Control: DWORD, + Privilege: [ANYSIZE_ARRAY]LUID_AND_ATTRIBUTES `fmt:"v,PrivilegeCount"`, } PPRIVILEGE_SET :: ^PRIVILEGE_SET @@ -2780,7 +2807,8 @@ TOKEN_ADJUST_GROUPS :: 0x0040 TOKEN_ADJUST_DEFAULT :: 0x0080 TOKEN_ADJUST_SESSIONID :: 0x0100 -TOKEN_ALL_ACCESS_P :: STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY |\ +TOKEN_ALL_ACCESS_P :: \ + STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT TOKEN_ALL_ACCESS :: TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID @@ -2803,8 +2831,8 @@ CP_UTF8 :: 65001 // UTF-8 translation LCID :: DWORD LANGID :: WORD -LANG_NEUTRAL :: 0x00 -LANG_INVARIANT :: 0x7f +LANG_NEUTRAL :: 0x00 +LANG_INVARIANT :: 0x7f SUBLANG_NEUTRAL :: 0x00 // language neutral SUBLANG_DEFAULT :: 0x01 // user default @@ -2815,7 +2843,7 @@ WC_ERR_INVALID_CHARS :: 128 MAX_PATH :: 0x00000104 MAX_PATH_WIDE :: 0x8000 -INVALID_FILE_ATTRIBUTES :: DWORD(0xffff_ffff) +INVALID_FILE_ATTRIBUTES :: DWORD(0xffff_ffff) FILE_TYPE_DISK :: 0x0001 FILE_TYPE_CHAR :: 0x0002 @@ -2826,33 +2854,33 @@ POINT :: struct {x, y: LONG} PWINDOWPOS :: ^WINDOWPOS WINDOWPOS :: struct { - hwnd: HWND, + hwnd: HWND, hwndInsertAfter: HWND, - x: c_int, - y: c_int, - cx: c_int, - cy: c_int, + x: c_int, + y: c_int, + cx: c_int, + cy: c_int, flags: UINT, } when size_of(uintptr) == 4 { WSADATA :: struct { - wVersion: WORD, - wHighVersion: WORD, - szDescription: [WSADESCRIPTION_LEN + 1]u8, + wVersion: WORD, + wHighVersion: WORD, + szDescription: [WSADESCRIPTION_LEN + 1]u8, szSystemStatus: [WSASYS_STATUS_LEN + 1]u8, - iMaxSockets: u16, - iMaxUdpDg: u16, - lpVendorInfo: ^u8, + iMaxSockets: u16, + iMaxUdpDg: u16, + lpVendorInfo: [^]u8, } } else when size_of(uintptr) == 8 { WSADATA :: struct { - wVersion: WORD, - wHighVersion: WORD, - iMaxSockets: u16, - iMaxUdpDg: u16, - lpVendorInfo: ^u8, - szDescription: [WSADESCRIPTION_LEN + 1]u8, + wVersion: WORD, + wHighVersion: WORD, + iMaxSockets: u16, + iMaxUdpDg: u16, + lpVendorInfo: ^u8, + szDescription: [WSADESCRIPTION_LEN + 1]u8, szSystemStatus: [WSASYS_STATUS_LEN + 1]u8, } } else { @@ -2861,71 +2889,71 @@ when size_of(uintptr) == 4 { WSABUF :: struct { len: ULONG, - buf: ^CHAR, + buf: [^]CHAR `fmt"q,len"`, } WSAPROTOCOL_INFO :: struct { - dwServiceFlags1: DWORD, - dwServiceFlags2: DWORD, - dwServiceFlags3: DWORD, - dwServiceFlags4: DWORD, - dwProviderFlags: DWORD, - ProviderId: GUID, - dwCatalogEntryId: DWORD, - ProtocolChain: WSAPROTOCOLCHAIN, - iVersion: c_int, - iAddressFamily: c_int, - iMaxSockAddr: c_int, - iMinSockAddr: c_int, - iSocketType: c_int, - iProtocol: c_int, + dwServiceFlags1: DWORD, + dwServiceFlags2: DWORD, + dwServiceFlags3: DWORD, + dwServiceFlags4: DWORD, + dwProviderFlags: DWORD, + ProviderId: GUID, + dwCatalogEntryId: DWORD, + ProtocolChain: WSAPROTOCOLCHAIN, + iVersion: c_int, + iAddressFamily: c_int, + iMaxSockAddr: c_int, + iMinSockAddr: c_int, + iSocketType: c_int, + iProtocol: c_int, iProtocolMaxOffset: c_int, - iNetworkByteOrder: c_int, - iSecurityScheme: c_int, - dwMessageSize: DWORD, + iNetworkByteOrder: c_int, + iSecurityScheme: c_int, + dwMessageSize: DWORD, dwProviderReserved: DWORD, - szProtocol: [WSAPROTOCOL_LEN + 1]u16, + szProtocol: [WSAPROTOCOL_LEN + 1]u16, } WIN32_FILE_ATTRIBUTE_DATA :: struct { dwFileAttributes: DWORD, - ftCreationTime: FILETIME, + ftCreationTime: FILETIME, ftLastAccessTime: FILETIME, - ftLastWriteTime: FILETIME, - nFileSizeHigh: DWORD, - nFileSizeLow: DWORD, + ftLastWriteTime: FILETIME, + nFileSizeHigh: DWORD, + nFileSizeLow: DWORD, } FILE_INFO_BY_HANDLE_CLASS :: enum c_int { - FileBasicInfo = 0, - FileStandardInfo = 1, - FileNameInfo = 2, - FileRenameInfo = 3, - FileDispositionInfo = 4, - FileAllocationInfo = 5, - FileEndOfFileInfo = 6, - FileStreamInfo = 7, - FileCompressionInfo = 8, - FileAttributeTagInfo = 9, - FileIdBothDirectoryInfo = 10, // 0xA + FileBasicInfo = 0, + FileStandardInfo = 1, + FileNameInfo = 2, + FileRenameInfo = 3, + FileDispositionInfo = 4, + FileAllocationInfo = 5, + FileEndOfFileInfo = 6, + FileStreamInfo = 7, + FileCompressionInfo = 8, + FileAttributeTagInfo = 9, + FileIdBothDirectoryInfo = 10, // 0xA FileIdBothDirectoryRestartInfo = 11, // 0xB - FileIoPriorityHintInfo = 12, // 0xC - FileRemoteProtocolInfo = 13, // 0xD - FileFullDirectoryInfo = 14, // 0xE - FileFullDirectoryRestartInfo = 15, // 0xF - FileStorageInfo = 16, // 0x10 - FileAlignmentInfo = 17, // 0x11 - FileIdInfo = 18, // 0x12 - FileIdExtdDirectoryInfo = 19, // 0x13 + FileIoPriorityHintInfo = 12, // 0xC + FileRemoteProtocolInfo = 13, // 0xD + FileFullDirectoryInfo = 14, // 0xE + FileFullDirectoryRestartInfo = 15, // 0xF + FileStorageInfo = 16, // 0x10 + FileAlignmentInfo = 17, // 0x11 + FileIdInfo = 18, // 0x12 + FileIdExtdDirectoryInfo = 19, // 0x13 FileIdExtdDirectoryRestartInfo = 20, // 0x14 MaximumFileInfoByHandlesClass, } FILE_BASIC_INFO :: struct { - CreationTime: LARGE_INTEGER, + CreationTime: LARGE_INTEGER, LastAccessTime: LARGE_INTEGER, - LastWriteTime: LARGE_INTEGER, - ChangeTime: LARGE_INTEGER, + LastWriteTime: LARGE_INTEGER, + ChangeTime: LARGE_INTEGER, FileAttributes: DWORD, } @@ -2941,39 +2969,39 @@ FILE_NOTIFY_INFORMATION :: struct { } REPARSE_DATA_BUFFER :: struct { - ReparseTag: c_uint, + ReparseTag: c_uint, ReparseDataLength: c_ushort, - Reserved: c_ushort, - rest: [0]byte, + Reserved: c_ushort, + rest: [0]byte, } SYMBOLIC_LINK_REPARSE_BUFFER :: struct { SubstituteNameOffset: c_ushort, SubstituteNameLength: c_ushort, - PrintNameOffset: c_ushort, - PrintNameLength: c_ushort, - Flags: c_ulong, - PathBuffer: WCHAR, + PrintNameOffset: c_ushort, + PrintNameLength: c_ushort, + Flags: c_ulong, + PathBuffer: WCHAR, } MOUNT_POINT_REPARSE_BUFFER :: struct { SubstituteNameOffset: c_ushort, SubstituteNameLength: c_ushort, - PrintNameOffset: c_ushort, - PrintNameLength: c_ushort, - PathBuffer: WCHAR, + PrintNameOffset: c_ushort, + PrintNameLength: c_ushort, + PathBuffer: WCHAR, } LPPROGRESS_ROUTINE :: #type proc "system" ( - TotalFileSize: LARGE_INTEGER, - TotalBytesTransferred: LARGE_INTEGER, - StreamSize: LARGE_INTEGER, + TotalFileSize: LARGE_INTEGER, + TotalBytesTransferred: LARGE_INTEGER, + StreamSize: LARGE_INTEGER, StreamBytesTransferred: LARGE_INTEGER, - dwStreamNumber: DWORD, - dwCallbackReason: DWORD, - hSourceFile: HANDLE, - hDestinationFile: HANDLE, - lpData: LPVOID, + dwStreamNumber: DWORD, + dwCallbackReason: DWORD, + hSourceFile: HANDLE, + hDestinationFile: HANDLE, + lpData: LPVOID, ) -> DWORD CONDITION_VARIABLE :: struct { @@ -2984,21 +3012,36 @@ SRWLOCK :: struct { } CRITICAL_SECTION :: struct { CriticalSectionDebug: LPVOID, - LockCount: LONG, - RecursionCount: LONG, - OwningThread: HANDLE, - LockSemaphore: HANDLE, - SpinCount: ULONG_PTR, + LockCount: LONG, + RecursionCount: LONG, + OwningThread: HANDLE, + LockSemaphore: HANDLE, + SpinCount: ULONG_PTR, } +SYNCHRONIZATION_BARRIER :: struct { + Reserved1: DWORD, + Reserved2: DWORD, + Reserved3: [2]ULONG_PTR, + Reserved4: DWORD, + Reserved5: DWORD, +} + +SYNCHRONIZATION_BARRIER_FLAG :: enum { + SPIN_ONLY = 0, + BLOCK_ONLY = 1, + NO_DELETE = 2, +} +SYNCHRONIZATION_BARRIER_FLAGS :: distinct bit_set[SYNCHRONIZATION_BARRIER_FLAG; DWORD] + REPARSE_MOUNTPOINT_DATA_BUFFER :: struct { - ReparseTag: DWORD, - ReparseDataLength: DWORD, - Reserved: WORD, - ReparseTargetLength: WORD, + ReparseTag: DWORD, + ReparseDataLength: DWORD, + Reserved: WORD, + ReparseTargetLength: WORD, ReparseTargetMaximumLength: WORD, - Reserved1: WORD, - ReparseTarget: WCHAR, + Reserved1: WORD, + ReparseTarget: WCHAR, } GUID :: struct { @@ -3021,12 +3064,12 @@ LPGUID :: ^GUID LPCGUID :: ^GUID REFIID :: ^GUID -REFGUID :: GUID -IID :: GUID -LPIID :: ^IID -CLSID :: GUID +REFGUID :: GUID +IID :: GUID +LPIID :: ^IID +CLSID :: GUID REFCLSID :: ^CLSID -LPCLSID :: ^CLSID +LPCLSID :: ^CLSID CLSCTX_INPROC_SERVER :: 0x1 CLSCTX_INPROC_HANDLER :: 0x2 @@ -3059,46 +3102,46 @@ CLSCTX_PS_DLL :: 0x80000000 CLSCTX_ALL :: CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER WSAPROTOCOLCHAIN :: struct { - ChainLen: c_int, - ChainEntries: [MAX_PROTOCOL_CHAIN]DWORD, + ChainLen: c_int, + ChainEntries: [MAX_PROTOCOL_CHAIN]DWORD `fmt:"v,ChainLen"`, } SECURITY_ATTRIBUTES :: struct { - nLength: DWORD, + nLength: DWORD, lpSecurityDescriptor: LPVOID, - bInheritHandle: BOOL, + bInheritHandle: BOOL, } PROCESS_INFORMATION :: struct { - hProcess: HANDLE, - hThread: HANDLE, + hProcess: HANDLE, + hThread: HANDLE, dwProcessId: DWORD, - dwThreadId: DWORD, + dwThreadId: DWORD, } STARTUPINFOW :: struct { - cb: DWORD, - lpReserved: LPWSTR, - lpDesktop: LPWSTR, - lpTitle: LPWSTR, - dwX: DWORD, - dwY: DWORD, - dwXSize: DWORD, - dwYSize: DWORD, - dwXCountChars: DWORD, - dwYCountChars: DWORD, + cb: DWORD, + lpReserved: LPWSTR, + lpDesktop: LPWSTR, + lpTitle: LPWSTR, + dwX: DWORD, + dwY: DWORD, + dwXSize: DWORD, + dwYSize: DWORD, + dwXCountChars: DWORD, + dwYCountChars: DWORD, dwFillAttribute: DWORD, - dwFlags: DWORD, - wShowWindow: WORD, - cbReserved2: WORD, - lpReserved2: LPBYTE, - hStdInput: HANDLE, - hStdOutput: HANDLE, - hStdError: HANDLE, + dwFlags: DWORD, + wShowWindow: WORD, + cbReserved2: WORD, + lpReserved2: LPBYTE, + hStdInput: HANDLE, + hStdOutput: HANDLE, + hStdError: HANDLE, } FILETIME :: struct { - dwLowDateTime: DWORD, + dwLowDateTime: DWORD, dwHighDateTime: DWORD, } @@ -3115,6 +3158,7 @@ OBJECT_ATTRIBUTES :: struct { SecurityDescriptor: rawptr, SecurityQualityOfService: rawptr, } +POBJECT_ATTRIBUTES :: ^OBJECT_ATTRIBUTES PUNICODE_STRING :: ^UNICODE_STRING UNICODE_STRING :: struct { @@ -3124,10 +3168,15 @@ UNICODE_STRING :: struct { } OVERLAPPED :: struct { - Internal: ^c_ulong, + Internal: ^c_ulong, InternalHigh: ^c_ulong, - Offset: DWORD, - OffsetHigh: DWORD, + using _: struct #raw_union { + using _: struct { + Offset: DWORD, + OffsetHigh: DWORD, + }, + OffsetFull: u64, // Convenience field to set Offset and OffsetHigh with one value. + }, hEvent: HANDLE, } @@ -3139,11 +3188,18 @@ OVERLAPPED_ENTRY :: struct { } LPOVERLAPPED_COMPLETION_ROUTINE :: #type proc "system" ( - dwErrorCode: DWORD, + dwErrorCode: DWORD, dwNumberOfBytesTransfered: DWORD, - lpOverlapped: LPOVERLAPPED, + lpOverlapped: LPOVERLAPPED, ) +READ_DIRECTORY_NOTIFY_INFORMATION_CLASS :: enum c_int { + ReadDirectoryNotifyInformation = 1, + ReadDirectoryNotifyExtendedInformation, + ReadDirectoryNotifyFullInformation, + ReadDirectoryNotifyMaximumInformation, +} + ADDRESS_MODE :: enum c_int { AddrMode1616, AddrMode1632, @@ -3164,7 +3220,7 @@ fd_set :: struct { } timeval :: struct { - tv_sec: c_long, + tv_sec: c_long, tv_usec: c_long, } @@ -3199,145 +3255,145 @@ STATUS_PRIVILEGED_INSTRUCTION :: 0xC0000096 EXCEPTION_RECORD :: struct { - ExceptionCode: DWORD, - ExceptionFlags: DWORD, - ExceptionRecord: ^EXCEPTION_RECORD, - ExceptionAddress: LPVOID, - NumberParameters: DWORD, - ExceptionInformation: [EXCEPTION_MAXIMUM_PARAMETERS]LPVOID, + ExceptionCode: DWORD, + ExceptionFlags: DWORD, + ExceptionRecord: ^EXCEPTION_RECORD, + ExceptionAddress: LPVOID, + NumberParameters: DWORD, + ExceptionInformation: [EXCEPTION_MAXIMUM_PARAMETERS]LPVOID `fmt:"v,NumberParameters"`, } CONTEXT :: struct { - P1Home: DWORD64, - P2Home: DWORD64, - P3Home: DWORD64, - P4Home: DWORD64, - P5Home: DWORD64, - P6Home: DWORD64, + P1Home: DWORD64, + P2Home: DWORD64, + P3Home: DWORD64, + P4Home: DWORD64, + P5Home: DWORD64, + P6Home: DWORD64, ContextFlags: DWORD, - MxCsr: DWORD, - SegCs: WORD, - SegDs: WORD, - SegEs: WORD, - SegFs: WORD, - SegGs: WORD, - SegSs: WORD, - EFlags: DWORD, - Dr0: DWORD64, - Dr1: DWORD64, - Dr2: DWORD64, - Dr3: DWORD64, - Dr6: DWORD64, - Dr7: DWORD64, - Rax: DWORD64, - Rcx: DWORD64, - Rdx: DWORD64, - Rbx: DWORD64, - Rsp: DWORD64, - Rbp: DWORD64, - Rsi: DWORD64, - Rdi: DWORD64, - R8: DWORD64, - R9: DWORD64, - R10: DWORD64, - R11: DWORD64, - R12: DWORD64, - R13: DWORD64, - R14: DWORD64, - R15: DWORD64, - Rip: DWORD64, - _: struct #raw_union { + MxCsr: DWORD, + SegCs: WORD, + SegDs: WORD, + SegEs: WORD, + SegFs: WORD, + SegGs: WORD, + SegSs: WORD, + EFlags: DWORD, + Dr0: DWORD64, + Dr1: DWORD64, + Dr2: DWORD64, + Dr3: DWORD64, + Dr6: DWORD64, + Dr7: DWORD64, + Rax: DWORD64, + Rcx: DWORD64, + Rdx: DWORD64, + Rbx: DWORD64, + Rsp: DWORD64, + Rbp: DWORD64, + Rsi: DWORD64, + Rdi: DWORD64, + R8: DWORD64, + R9: DWORD64, + R10: DWORD64, + R11: DWORD64, + R12: DWORD64, + R13: DWORD64, + R14: DWORD64, + R15: DWORD64, + Rip: DWORD64, + using _: struct #raw_union { FltSave: XMM_SAVE_AREA32, - Q: [16]NEON128, - D: [32]ULONGLONG, - _: struct { + Q: [16]NEON128, + D: [32]ULONGLONG, + using _: struct { Header: [2]M128A, Legacy: [8]M128A, - Xmm0: M128A, - Xmm1: M128A, - Xmm2: M128A, - Xmm3: M128A, - Xmm4: M128A, - Xmm5: M128A, - Xmm6: M128A, - Xmm7: M128A, - Xmm8: M128A, - Xmm9: M128A, - Xmm10: M128A, - Xmm11: M128A, - Xmm12: M128A, - Xmm13: M128A, - Xmm14: M128A, - Xmm15: M128A, + Xmm0: M128A, + Xmm1: M128A, + Xmm2: M128A, + Xmm3: M128A, + Xmm4: M128A, + Xmm5: M128A, + Xmm6: M128A, + Xmm7: M128A, + Xmm8: M128A, + Xmm9: M128A, + Xmm10: M128A, + Xmm11: M128A, + Xmm12: M128A, + Xmm13: M128A, + Xmm14: M128A, + Xmm15: M128A, }, S: [32]DWORD, }, - VectorRegister: [26]M128A, - VectorControl: DWORD64, - DebugControl: DWORD64, - LastBranchToRip: DWORD64, - LastBranchFromRip: DWORD64, - LastExceptionToRip: DWORD64, + VectorRegister: [26]M128A, + VectorControl: DWORD64, + DebugControl: DWORD64, + LastBranchToRip: DWORD64, + LastBranchFromRip: DWORD64, + LastExceptionToRip: DWORD64, LastExceptionFromRip: DWORD64, } -PCONTEXT :: ^CONTEXT +PCONTEXT :: ^CONTEXT LPCONTEXT :: ^CONTEXT when size_of(uintptr) == 32 { XSAVE_FORMAT :: struct #align(16) { - ControlWord: WORD, - StatusWord: WORD, - TagWord: BYTE, - Reserved1: BYTE, - ErrorOpcode: WORD, - ErrorOffset: DWORD, - ErrorSelector: WORD, - Reserved2: WORD, - DataOffset: DWORD, - DataSelector: WORD, - Reserved3: WORD, - MxCsr: DWORD, - MxCsr_Mask: DWORD, + ControlWord: WORD, + StatusWord: WORD, + TagWord: BYTE, + Reserved1: BYTE, + ErrorOpcode: WORD, + ErrorOffset: DWORD, + ErrorSelector: WORD, + Reserved2: WORD, + DataOffset: DWORD, + DataSelector: WORD, + Reserved3: WORD, + MxCsr: DWORD, + MxCsr_Mask: DWORD, FloatRegisters: [8]M128A, // 32-bit specific - XmmRegisters: [8]M128A, - Reserved4: [192]BYTE, - StackControl: [7]DWORD, - Cr0NpxState: DWORD, + XmmRegisters: [8]M128A, + Reserved4: [192]BYTE, + StackControl: [7]DWORD, + Cr0NpxState: DWORD, } } else { XSAVE_FORMAT :: struct #align(16) { - ControlWord: WORD, - StatusWord: WORD, - TagWord: BYTE, - Reserved1: BYTE, - ErrorOpcode: WORD, - ErrorOffset: DWORD, - ErrorSelector: WORD, - Reserved2: WORD, - DataOffset: DWORD, - DataSelector: WORD, - Reserved3: WORD, - MxCsr: DWORD, - MxCsr_Mask: DWORD, + ControlWord: WORD, + StatusWord: WORD, + TagWord: BYTE, + Reserved1: BYTE, + ErrorOpcode: WORD, + ErrorOffset: DWORD, + ErrorSelector: WORD, + Reserved2: WORD, + DataOffset: DWORD, + DataSelector: WORD, + Reserved3: WORD, + MxCsr: DWORD, + MxCsr_Mask: DWORD, FloatRegisters: [8]M128A, // 64-bit specific - XmmRegisters: [16]M128A, - Reserved4: [96]BYTE, + XmmRegisters: [16]M128A, + Reserved4: [96]BYTE, } } XMM_SAVE_AREA32 :: XSAVE_FORMAT M128A :: struct { - Low: ULONGLONG, + Low: ULONGLONG, High: LONGLONG, } NEON128 :: struct { - Low: ULONGLONG, + Low: ULONGLONG, High: LONGLONG, } @@ -3386,17 +3442,17 @@ FILE_ATTRIBUTE_TAG_INFO :: struct { } // getaddrinfo flags https://learn.microsoft.com/en-us/windows/win32/api/ws2def/ns-ws2def-addrinfoa -AI_PASSIVE :: 0x01 -AI_CANONNAME :: 0x02 -AI_NUMERICHOST :: 0x04 -AI_ALL :: 0x0100 -AI_ADDRCONFIG :: 0x0400 -AI_V4MAPPED :: 0x0800 -AI_NON_AUTHORITATIVE :: 0x04000 -AI_SECURE :: 0x08000 +AI_PASSIVE :: 0x01 +AI_CANONNAME :: 0x02 +AI_NUMERICHOST :: 0x04 +AI_ALL :: 0x0100 +AI_ADDRCONFIG :: 0x0400 +AI_V4MAPPED :: 0x0800 +AI_NON_AUTHORITATIVE :: 0x04000 +AI_SECURE :: 0x08000 AI_RETURN_PREFERRED_NAMES :: 0x010000 -AI_FQDN :: 0x00020000 -AI_FILESERVER :: 0x00040000 +AI_FQDN :: 0x00020000 +AI_FILESERVER :: 0x00040000 PADDRINFOEXW :: ^ADDRINFOEXW LPADDRINFOEXW :: ^ADDRINFOEXW @@ -3415,9 +3471,9 @@ ADDRINFOEXW :: struct { } LPLOOKUPSERVICE_COMPLETION_ROUTINE :: #type proc "system" ( - dwErrorCode: DWORD, + dwErrorCode: DWORD, dwNumberOfBytesTransfered: DWORD, - lpOverlapped: LPOVERLAPPED, + lpOverlapped: LPOVERLAPPED, ) @@ -3427,18 +3483,18 @@ SYSTEM_INFO :: struct { dwOemID: DWORD, using _: struct #raw_union { wProcessorArchitecture: WORD, - wReserved: WORD, // reserved + wReserved: WORD, // reserved }, }, - dwPageSize: DWORD, + dwPageSize: DWORD, lpMinimumApplicationAddress: LPVOID, lpMaximumApplicationAddress: LPVOID, - dwActiveProcessorMask: DWORD_PTR, - dwNumberOfProcessors: DWORD, - dwProcessorType: DWORD, - dwAllocationGranularity: DWORD, - wProcessorLevel: WORD, - wProcessorRevision: WORD, + dwActiveProcessorMask: DWORD_PTR, + dwNumberOfProcessors: DWORD, + dwProcessorType: DWORD, + dwAllocationGranularity: DWORD, + wProcessorLevel: WORD, + wProcessorRevision: WORD, } // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw @@ -3475,12 +3531,12 @@ LoadLibraryEx_Flags :: distinct bit_set[LoadLibraryEx_Flag] // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-quota_limits // Used in LogonUserExW PQUOTA_LIMITS :: struct { - PagedPoolLimit: SIZE_T, - NonPagedPoolLimit: SIZE_T, + PagedPoolLimit: SIZE_T, + NonPagedPoolLimit: SIZE_T, MinimumWorkingSetSize: SIZE_T, MaximumWorkingSetSize: SIZE_T, - PagefileLimit: SIZE_T, - TimeLimit: LARGE_INTEGER, + PagefileLimit: SIZE_T, + TimeLimit: LARGE_INTEGER, } Logon32_Type :: enum DWORD { @@ -3505,14 +3561,14 @@ Logon32_Provider :: enum DWORD { // Used in LoadUserProfileW PROFILEINFOW :: struct { - dwSize: DWORD, - dwFlags: DWORD, - lpUserName: LPWSTR, + dwSize: DWORD, + dwFlags: DWORD, + lpUserName: LPWSTR, lpProfilePath: LPWSTR, lpDefaultPath: LPWSTR, - lpServerName: LPWSTR, - lpPolicyPath: LPWSTR, - hProfile: HANDLE, + lpServerName: LPWSTR, + lpPolicyPath: LPWSTR, + hProfile: HANDLE, } SECURITY_MAX_SID_SIZE :: 68 @@ -3569,14 +3625,14 @@ USER_INFO_FLAG :: enum DWORD { USER_INFO_FLAGS :: distinct bit_set[USER_INFO_FLAG] USER_INFO_1 :: struct #packed { - name: LPWSTR, - password: LPWSTR, // Max password length is defined in LM20_PWLEN. + name: LPWSTR, + password: LPWSTR, // Max password length is defined in LM20_PWLEN. password_age: DWORD, - priv: USER_PRIV, - home_dir: LPWSTR, - comment: LPWSTR, - flags: USER_INFO_FLAGS, - script_path: LPWSTR, + priv: USER_PRIV, + home_dir: LPWSTR, + comment: LPWSTR, + flags: USER_INFO_FLAGS, + script_path: LPWSTR, } // #assert(size_of(USER_INFO_1) == 50) @@ -3585,320 +3641,320 @@ LOCALGROUP_MEMBERS_INFO_0 :: struct #packed { } NET_API_STATUS :: enum DWORD { - Success = 0, - ERROR_ACCESS_DENIED = 5, - MemberInAlias = 1378, - NetNotStarted = 2102, - UnknownServer = 2103, - ShareMem = 2104, - NoNetworkResource = 2105, - RemoteOnly = 2106, - DevNotRedirected = 2107, - ServerNotStarted = 2114, - ItemNotFound = 2115, - UnknownDevDir = 2116, - RedirectedPath = 2117, - DuplicateShare = 2118, - NoRoom = 2119, - TooManyItems = 2121, - InvalidMaxUsers = 2122, - BufTooSmall = 2123, - RemoteErr = 2127, - LanmanIniError = 2131, - NetworkError = 2136, - WkstaInconsistentState = 2137, - WkstaNotStarted = 2138, - BrowserNotStarted = 2139, - InternalError = 2140, - BadTransactConfig = 2141, - InvalidAPI = 2142, - BadEventName = 2143, - DupNameReboot = 2144, - CfgCompNotFound = 2146, - CfgParamNotFound = 2147, - LineTooLong = 2149, - QNotFound = 2150, - JobNotFound = 2151, - DestNotFound = 2152, - DestExists = 2153, - QExists = 2154, - QNoRoom = 2155, - JobNoRoom = 2156, - DestNoRoom = 2157, - DestIdle = 2158, - DestInvalidOp = 2159, - ProcNoRespond = 2160, - SpoolerNotLoaded = 2161, - DestInvalidState = 2162, - QInvalidState = 2163, - JobInvalidState = 2164, - SpoolNoMemory = 2165, - DriverNotFound = 2166, - DataTypeInvalid = 2167, - ProcNotFound = 2168, - ServiceTableLocked = 2180, - ServiceTableFull = 2181, - ServiceInstalled = 2182, - ServiceEntryLocked = 2183, - ServiceNotInstalled = 2184, - BadServiceName = 2185, - ServiceCtlTimeout = 2186, - ServiceCtlBusy = 2187, - BadServiceProgName = 2188, - ServiceNotCtrl = 2189, - ServiceKillProc = 2190, - ServiceCtlNotValid = 2191, - NotInDispatchTbl = 2192, - BadControlRecv = 2193, - ServiceNotStarting = 2194, - AlreadyLoggedOn = 2200, - NotLoggedOn = 2201, - BadUsername = 2202, - BadPassword = 2203, - UnableToAddName_W = 2204, - UnableToAddName_F = 2205, - UnableToDelName_W = 2206, - UnableToDelName_F = 2207, - LogonsPaused = 2209, - LogonServerConflict = 2210, - LogonNoUserPath = 2211, - LogonScriptError = 2212, - StandaloneLogon = 2214, - LogonServerNotFound = 2215, - LogonDomainExists = 2216, - NonValidatedLogon = 2217, - ACFNotFound = 2219, - GroupNotFound = 2220, - UserNotFound = 2221, - ResourceNotFound = 2222, - GroupExists = 2223, - UserExists = 2224, - ResourceExists = 2225, - NotPrimary = 2226, - ACFNotLoaded = 2227, - ACFNoRoom = 2228, - ACFFileIOFail = 2229, - ACFTooManyLists = 2230, - UserLogon = 2231, - ACFNoParent = 2232, - CanNotGrowSegment = 2233, - SpeGroupOp = 2234, - NotInCache = 2235, - UserInGroup = 2236, - UserNotInGroup = 2237, - AccountUndefined = 2238, - AccountExpired = 2239, - InvalidWorkstation = 2240, - InvalidLogonHours = 2241, - PasswordExpired = 2242, - PasswordCantChange = 2243, - PasswordHistConflict = 2244, - PasswordTooShort = 2245, - PasswordTooRecent = 2246, - InvalidDatabase = 2247, - DatabaseUpToDate = 2248, - SyncRequired = 2249, - UseNotFound = 2250, - BadAsgType = 2251, - DeviceIsShared = 2252, - SameAsComputerName = 2253, - NoComputerName = 2270, - MsgAlreadyStarted = 2271, - MsgInitFailed = 2272, - NameNotFound = 2273, - AlreadyForwarded = 2274, - AddForwarded = 2275, - AlreadyExists = 2276, - TooManyNames = 2277, - DelComputerName = 2278, - LocalForward = 2279, - GrpMsgProcessor = 2280, - PausedRemote = 2281, - BadReceive = 2282, - NameInUse = 2283, - MsgNotStarted = 2284, - NotLocalName = 2285, - NoForwardName = 2286, - RemoteFull = 2287, - NameNotForwarded = 2288, - TruncatedBroadcast = 2289, - InvalidDevice = 2294, - WriteFault = 2295, - DuplicateName = 2297, - DeleteLater = 2298, - IncompleteDel = 2299, - MultipleNets = 2300, - NetNameNotFound = 2310, - DeviceNotShared = 2311, - ClientNameNotFound = 2312, - FileIdNotFound = 2314, - ExecFailure = 2315, - TmpFile = 2316, - TooMuchData = 2317, - DeviceShareConflict = 2318, - BrowserTableIncomplete = 2319, - NotLocalDomain = 2320, - IsDfsShare = 2321, - DevInvalidOpCode = 2331, - DevNotFound = 2332, - DevNotOpen = 2333, - BadQueueDevString = 2334, - BadQueuePriority = 2335, - NoCommDevs = 2337, - QueueNotFound = 2338, - BadDevString = 2340, - BadDev = 2341, - InUseBySpooler = 2342, - CommDevInUse = 2343, - InvalidComputer = 2351, - MaxLenExceeded = 2354, - BadComponent = 2356, - CantType = 2357, - TooManyEntries = 2362, - ProfileFileTooBig = 2370, - ProfileOffset = 2371, - ProfileCleanup = 2372, - ProfileUnknownCmd = 2373, - ProfileLoadErr = 2374, - ProfileSaveErr = 2375, - LogOverflow = 2377, - LogFileChanged = 2378, - LogFileCorrupt = 2379, - SourceIsDir = 2380, - BadSource = 2381, - BadDest = 2382, - DifferentServers = 2383, - RunSrvPaused = 2385, - ErrCommRunSrv = 2389, - ErrorExecingGhost = 2391, - ShareNotFound = 2392, - InvalidLana = 2400, - OpenFiles = 2401, - ActiveConns = 2402, - BadPasswordCore = 2403, - DevInUse = 2404, - LocalDrive = 2405, - AlertExists = 2430, - TooManyAlerts = 2431, - NoSuchAlert = 2432, - BadRecipient = 2433, - AcctLimitExceeded = 2434, - InvalidLogSeek = 2440, - BadUasConfig = 2450, - InvalidUASOp = 2451, - LastAdmin = 2452, - DCNotFound = 2453, - LogonTrackingError = 2454, - NetlogonNotStarted = 2455, - CanNotGrowUASFile = 2456, - TimeDiffAtDC = 2457, - PasswordMismatch = 2458, - NoSuchServer = 2460, - NoSuchSession = 2461, - NoSuchConnection = 2462, - TooManyServers = 2463, - TooManySessions = 2464, - TooManyConnections = 2465, - TooManyFiles = 2466, - NoAlternateServers = 2467, - TryDownLevel = 2470, - UPSDriverNotStarted = 2480, - UPSInvalidConfig = 2481, - UPSInvalidCommPort = 2482, - UPSSignalAsserted = 2483, - UPSShutdownFailed = 2484, - BadDosRetCode = 2500, - ProgNeedsExtraMem = 2501, - BadDosFunction = 2502, - RemoteBootFailed = 2503, - BadFileCheckSum = 2504, - NoRplBootSystem = 2505, - RplLoadrNetBiosErr = 2506, - RplLoadrDiskErr = 2507, - ImageParamErr = 2508, - TooManyImageParams = 2509, - NonDosFloppyUsed = 2510, - RplBootRestart = 2511, - RplSrvrCallFailed = 2512, - CantConnectRplSrvr = 2513, - CantOpenImageFile = 2514, - CallingRplSrvr = 2515, - StartingRplBoot = 2516, - RplBootServiceTerm = 2517, - RplBootStartFailed = 2518, - RPL_CONNECTED = 2519, - BrowserConfiguredToNotRun = 2550, - RplNoAdaptersStarted = 2610, - RplBadRegistry = 2611, - RplBadDatabase = 2612, - RplRplfilesShare = 2613, - RplNotRplServer = 2614, - RplCannotEnum = 2615, - RplWkstaInfoCorrupted = 2616, - RplWkstaNotFound = 2617, - RplWkstaNameUnavailable = 2618, - RplProfileInfoCorrupted = 2619, - RplProfileNotFound = 2620, - RplProfileNameUnavailable = 2621, - RplProfileNotEmpty = 2622, - RplConfigInfoCorrupted = 2623, - RplConfigNotFound = 2624, - RplAdapterInfoCorrupted = 2625, - RplInternal = 2626, - RplVendorInfoCorrupted = 2627, - RplBootInfoCorrupted = 2628, - RplWkstaNeedsUserAcct = 2629, - RplNeedsRPLUSERAcct = 2630, - RplBootNotFound = 2631, - RplIncompatibleProfile = 2632, - RplAdapterNameUnavailable = 2633, - RplConfigNotEmpty = 2634, - RplBootInUse = 2635, - RplBackupDatabase = 2636, - RplAdapterNotFound = 2637, - RplVendorNotFound = 2638, - RplVendorNameUnavailable = 2639, - RplBootNameUnavailable = 2640, - RplConfigNameUnavailable = 2641, - DfsInternalCorruption = 2660, - DfsVolumeDataCorrupt = 2661, - DfsNoSuchVolume = 2662, - DfsVolumeAlreadyExists = 2663, - DfsAlreadyShared = 2664, - DfsNoSuchShare = 2665, - DfsNotALeafVolume = 2666, - DfsLeafVolume = 2667, - DfsVolumeHasMultipleServers = 2668, - DfsCantCreateJunctionPoint = 2669, - DfsServerNotDfsAware = 2670, - DfsBadRenamePath = 2671, - DfsVolumeIsOffline = 2672, - DfsNoSuchServer = 2673, - DfsCyclicalName = 2674, - DfsNotSupportedInServerDfs = 2675, - DfsDuplicateService = 2676, + Success = 0, + ERROR_ACCESS_DENIED = 5, + MemberInAlias = 1378, + NetNotStarted = 2102, + UnknownServer = 2103, + ShareMem = 2104, + NoNetworkResource = 2105, + RemoteOnly = 2106, + DevNotRedirected = 2107, + ServerNotStarted = 2114, + ItemNotFound = 2115, + UnknownDevDir = 2116, + RedirectedPath = 2117, + DuplicateShare = 2118, + NoRoom = 2119, + TooManyItems = 2121, + InvalidMaxUsers = 2122, + BufTooSmall = 2123, + RemoteErr = 2127, + LanmanIniError = 2131, + NetworkError = 2136, + WkstaInconsistentState = 2137, + WkstaNotStarted = 2138, + BrowserNotStarted = 2139, + InternalError = 2140, + BadTransactConfig = 2141, + InvalidAPI = 2142, + BadEventName = 2143, + DupNameReboot = 2144, + CfgCompNotFound = 2146, + CfgParamNotFound = 2147, + LineTooLong = 2149, + QNotFound = 2150, + JobNotFound = 2151, + DestNotFound = 2152, + DestExists = 2153, + QExists = 2154, + QNoRoom = 2155, + JobNoRoom = 2156, + DestNoRoom = 2157, + DestIdle = 2158, + DestInvalidOp = 2159, + ProcNoRespond = 2160, + SpoolerNotLoaded = 2161, + DestInvalidState = 2162, + QInvalidState = 2163, + JobInvalidState = 2164, + SpoolNoMemory = 2165, + DriverNotFound = 2166, + DataTypeInvalid = 2167, + ProcNotFound = 2168, + ServiceTableLocked = 2180, + ServiceTableFull = 2181, + ServiceInstalled = 2182, + ServiceEntryLocked = 2183, + ServiceNotInstalled = 2184, + BadServiceName = 2185, + ServiceCtlTimeout = 2186, + ServiceCtlBusy = 2187, + BadServiceProgName = 2188, + ServiceNotCtrl = 2189, + ServiceKillProc = 2190, + ServiceCtlNotValid = 2191, + NotInDispatchTbl = 2192, + BadControlRecv = 2193, + ServiceNotStarting = 2194, + AlreadyLoggedOn = 2200, + NotLoggedOn = 2201, + BadUsername = 2202, + BadPassword = 2203, + UnableToAddName_W = 2204, + UnableToAddName_F = 2205, + UnableToDelName_W = 2206, + UnableToDelName_F = 2207, + LogonsPaused = 2209, + LogonServerConflict = 2210, + LogonNoUserPath = 2211, + LogonScriptError = 2212, + StandaloneLogon = 2214, + LogonServerNotFound = 2215, + LogonDomainExists = 2216, + NonValidatedLogon = 2217, + ACFNotFound = 2219, + GroupNotFound = 2220, + UserNotFound = 2221, + ResourceNotFound = 2222, + GroupExists = 2223, + UserExists = 2224, + ResourceExists = 2225, + NotPrimary = 2226, + ACFNotLoaded = 2227, + ACFNoRoom = 2228, + ACFFileIOFail = 2229, + ACFTooManyLists = 2230, + UserLogon = 2231, + ACFNoParent = 2232, + CanNotGrowSegment = 2233, + SpeGroupOp = 2234, + NotInCache = 2235, + UserInGroup = 2236, + UserNotInGroup = 2237, + AccountUndefined = 2238, + AccountExpired = 2239, + InvalidWorkstation = 2240, + InvalidLogonHours = 2241, + PasswordExpired = 2242, + PasswordCantChange = 2243, + PasswordHistConflict = 2244, + PasswordTooShort = 2245, + PasswordTooRecent = 2246, + InvalidDatabase = 2247, + DatabaseUpToDate = 2248, + SyncRequired = 2249, + UseNotFound = 2250, + BadAsgType = 2251, + DeviceIsShared = 2252, + SameAsComputerName = 2253, + NoComputerName = 2270, + MsgAlreadyStarted = 2271, + MsgInitFailed = 2272, + NameNotFound = 2273, + AlreadyForwarded = 2274, + AddForwarded = 2275, + AlreadyExists = 2276, + TooManyNames = 2277, + DelComputerName = 2278, + LocalForward = 2279, + GrpMsgProcessor = 2280, + PausedRemote = 2281, + BadReceive = 2282, + NameInUse = 2283, + MsgNotStarted = 2284, + NotLocalName = 2285, + NoForwardName = 2286, + RemoteFull = 2287, + NameNotForwarded = 2288, + TruncatedBroadcast = 2289, + InvalidDevice = 2294, + WriteFault = 2295, + DuplicateName = 2297, + DeleteLater = 2298, + IncompleteDel = 2299, + MultipleNets = 2300, + NetNameNotFound = 2310, + DeviceNotShared = 2311, + ClientNameNotFound = 2312, + FileIdNotFound = 2314, + ExecFailure = 2315, + TmpFile = 2316, + TooMuchData = 2317, + DeviceShareConflict = 2318, + BrowserTableIncomplete = 2319, + NotLocalDomain = 2320, + IsDfsShare = 2321, + DevInvalidOpCode = 2331, + DevNotFound = 2332, + DevNotOpen = 2333, + BadQueueDevString = 2334, + BadQueuePriority = 2335, + NoCommDevs = 2337, + QueueNotFound = 2338, + BadDevString = 2340, + BadDev = 2341, + InUseBySpooler = 2342, + CommDevInUse = 2343, + InvalidComputer = 2351, + MaxLenExceeded = 2354, + BadComponent = 2356, + CantType = 2357, + TooManyEntries = 2362, + ProfileFileTooBig = 2370, + ProfileOffset = 2371, + ProfileCleanup = 2372, + ProfileUnknownCmd = 2373, + ProfileLoadErr = 2374, + ProfileSaveErr = 2375, + LogOverflow = 2377, + LogFileChanged = 2378, + LogFileCorrupt = 2379, + SourceIsDir = 2380, + BadSource = 2381, + BadDest = 2382, + DifferentServers = 2383, + RunSrvPaused = 2385, + ErrCommRunSrv = 2389, + ErrorExecingGhost = 2391, + ShareNotFound = 2392, + InvalidLana = 2400, + OpenFiles = 2401, + ActiveConns = 2402, + BadPasswordCore = 2403, + DevInUse = 2404, + LocalDrive = 2405, + AlertExists = 2430, + TooManyAlerts = 2431, + NoSuchAlert = 2432, + BadRecipient = 2433, + AcctLimitExceeded = 2434, + InvalidLogSeek = 2440, + BadUasConfig = 2450, + InvalidUASOp = 2451, + LastAdmin = 2452, + DCNotFound = 2453, + LogonTrackingError = 2454, + NetlogonNotStarted = 2455, + CanNotGrowUASFile = 2456, + TimeDiffAtDC = 2457, + PasswordMismatch = 2458, + NoSuchServer = 2460, + NoSuchSession = 2461, + NoSuchConnection = 2462, + TooManyServers = 2463, + TooManySessions = 2464, + TooManyConnections = 2465, + TooManyFiles = 2466, + NoAlternateServers = 2467, + TryDownLevel = 2470, + UPSDriverNotStarted = 2480, + UPSInvalidConfig = 2481, + UPSInvalidCommPort = 2482, + UPSSignalAsserted = 2483, + UPSShutdownFailed = 2484, + BadDosRetCode = 2500, + ProgNeedsExtraMem = 2501, + BadDosFunction = 2502, + RemoteBootFailed = 2503, + BadFileCheckSum = 2504, + NoRplBootSystem = 2505, + RplLoadrNetBiosErr = 2506, + RplLoadrDiskErr = 2507, + ImageParamErr = 2508, + TooManyImageParams = 2509, + NonDosFloppyUsed = 2510, + RplBootRestart = 2511, + RplSrvrCallFailed = 2512, + CantConnectRplSrvr = 2513, + CantOpenImageFile = 2514, + CallingRplSrvr = 2515, + StartingRplBoot = 2516, + RplBootServiceTerm = 2517, + RplBootStartFailed = 2518, + RPL_CONNECTED = 2519, + BrowserConfiguredToNotRun = 2550, + RplNoAdaptersStarted = 2610, + RplBadRegistry = 2611, + RplBadDatabase = 2612, + RplRplfilesShare = 2613, + RplNotRplServer = 2614, + RplCannotEnum = 2615, + RplWkstaInfoCorrupted = 2616, + RplWkstaNotFound = 2617, + RplWkstaNameUnavailable = 2618, + RplProfileInfoCorrupted = 2619, + RplProfileNotFound = 2620, + RplProfileNameUnavailable = 2621, + RplProfileNotEmpty = 2622, + RplConfigInfoCorrupted = 2623, + RplConfigNotFound = 2624, + RplAdapterInfoCorrupted = 2625, + RplInternal = 2626, + RplVendorInfoCorrupted = 2627, + RplBootInfoCorrupted = 2628, + RplWkstaNeedsUserAcct = 2629, + RplNeedsRPLUSERAcct = 2630, + RplBootNotFound = 2631, + RplIncompatibleProfile = 2632, + RplAdapterNameUnavailable = 2633, + RplConfigNotEmpty = 2634, + RplBootInUse = 2635, + RplBackupDatabase = 2636, + RplAdapterNotFound = 2637, + RplVendorNotFound = 2638, + RplVendorNameUnavailable = 2639, + RplBootNameUnavailable = 2640, + RplConfigNameUnavailable = 2641, + DfsInternalCorruption = 2660, + DfsVolumeDataCorrupt = 2661, + DfsNoSuchVolume = 2662, + DfsVolumeAlreadyExists = 2663, + DfsAlreadyShared = 2664, + DfsNoSuchShare = 2665, + DfsNotALeafVolume = 2666, + DfsLeafVolume = 2667, + DfsVolumeHasMultipleServers = 2668, + DfsCantCreateJunctionPoint = 2669, + DfsServerNotDfsAware = 2670, + DfsBadRenamePath = 2671, + DfsVolumeIsOffline = 2672, + DfsNoSuchServer = 2673, + DfsCyclicalName = 2674, + DfsNotSupportedInServerDfs = 2675, + DfsDuplicateService = 2676, DfsCantRemoveLastServerShare = 2677, - DfsVolumeIsInterDfs = 2678, - DfsInconsistent = 2679, - DfsServerUpgraded = 2680, - DfsDataIsIdentical = 2681, - DfsCantRemoveDfsRoot = 2682, - DfsChildOrParentInDfs = 2683, - DfsInternalError = 2690, - SetupAlreadyJoined = 2691, - SetupNotJoined = 2692, - SetupDomainController = 2693, - DefaultJoinRequired = 2694, - InvalidWorkgroupName = 2695, + DfsVolumeIsInterDfs = 2678, + DfsInconsistent = 2679, + DfsServerUpgraded = 2680, + DfsDataIsIdentical = 2681, + DfsCantRemoveDfsRoot = 2682, + DfsChildOrParentInDfs = 2683, + DfsInternalError = 2690, + SetupAlreadyJoined = 2691, + SetupNotJoined = 2692, + SetupDomainController = 2693, + DefaultJoinRequired = 2694, + InvalidWorkgroupName = 2695, NameUsesIncompatibleCodePage = 2696, - ComputerAccountNotFound = 2697, - PersonalSku = 2698, - SetupCheckDNSConfig = 2699, - PasswordMustChange = 2701, - AccountLockedOut = 2702, - PasswordTooLong = 2703, - PasswordNotComplexEnough = 2704, - PasswordFilterError = 2705, + ComputerAccountNotFound = 2697, + PersonalSku = 2698, + SetupCheckDNSConfig = 2699, + PasswordMustChange = 2701, + AccountLockedOut = 2702, + PasswordTooLong = 2703, + PasswordNotComplexEnough = 2704, + PasswordFilterError = 2705, } @@ -4053,12 +4109,12 @@ IMAGE_DEBUG_DIRECTORY :: struct { IMAGE_DEBUG_TYPE_CODEVIEW :: 2 -SICHINTF :: DWORD -SHCONTF :: DWORD -SFGAOF :: ULONG +SICHINTF :: DWORD +SHCONTF :: DWORD +SFGAOF :: ULONG FILEOPENDIALOGOPTIONS :: DWORD -REFPROPERTYKEY :: ^PROPERTYKEY -REFPROPVARIANT :: ^PROPVARIANT +REFPROPERTYKEY :: ^PROPERTYKEY +REFPROPVARIANT :: ^PROPVARIANT SIGDN :: enum c_int { NORMALDISPLAY = 0, @@ -4083,57 +4139,57 @@ SIATTRIBFLAGS :: enum c_int { FDAP :: enum c_int { BOTTOM = 0, - TOP = 1, + TOP = 1, } FDE_SHAREVIOLATION_RESPONSE :: enum c_int { DEFAULT = 0, - ACCEPT = 1, - REFUSE = 2, + ACCEPT = 1, + REFUSE = 2, } GETPROPERTYSTOREFLAGS :: enum c_int { - DEFAULT = 0, - HANDLERPROPERTIESONLY = 0x1, - READWRITE = 0x2, - TEMPORARY = 0x4, - FASTPROPERTIESONLY = 0x8, - OPENSLOWITEM = 0x10, - DELAYCREATION = 0x20, - BESTEFFORT = 0x40, - NO_OPLOCK = 0x80, - PREFERQUERYPROPERTIES = 0x100, - EXTRINSICPROPERTIES = 0x200, - EXTRINSICPROPERTIESONLY = 0x400, - VOLATILEPROPERTIES = 0x800, - VOLATILEPROPERTIESONLY = 0x1000, - MASK_VALID = 0x1fff, + DEFAULT = 0, + HANDLERPROPERTIESONLY = 0x1, + READWRITE = 0x2, + TEMPORARY = 0x4, + FASTPROPERTIESONLY = 0x8, + OPENSLOWITEM = 0x10, + DELAYCREATION = 0x20, + BESTEFFORT = 0x40, + NO_OPLOCK = 0x80, + PREFERQUERYPROPERTIES = 0x100, + EXTRINSICPROPERTIES = 0x200, + EXTRINSICPROPERTIESONLY = 0x400, + VOLATILEPROPERTIES = 0x800, + VOLATILEPROPERTIESONLY = 0x1000, + MASK_VALID = 0x1fff, } PROPERTYKEY :: struct { fmtid: GUID, - pid: DWORD, + pid: DWORD, } BIND_OPTS :: struct { - cbStruct: DWORD, - grfFlags: DWORD, - grfMode: DWORD, + cbStruct: DWORD, + grfFlags: DWORD, + grfMode: DWORD, dwTickCountDeadline: DWORD, } STATSTG :: struct { - pwcsName: LPOLESTR, - type: DWORD, - cbSize: ULARGE_INTEGER, - mtime: FILETIME, - ctime: FILETIME, - atime: FILETIME, - grfMode: DWORD, + pwcsName: LPOLESTR, + type: DWORD, + cbSize: ULARGE_INTEGER, + mtime: FILETIME, + ctime: FILETIME, + atime: FILETIME, + grfMode: DWORD, grfLocksSupported: DWORD, - clsid: CLSID, - grfStateBits: DWORD, - reserved: DWORD, + clsid: CLSID, + grfStateBits: DWORD, + reserved: DWORD, } COMDLG_FILTERSPEC :: struct { @@ -4142,15 +4198,15 @@ COMDLG_FILTERSPEC :: struct { DECIMAL :: struct { wReserved: USHORT, - _: struct #raw_union { - _: struct { + using _: struct #raw_union { + using _: struct { scale, sign: BYTE, }, signscale: USHORT, }, Hi32: ULONG, - _: struct #raw_union { - _: struct { + using _: struct #raw_union { + using _: struct { Lo32, Mid32: ULONG, }, Lo64: ULONGLONG, @@ -4223,14 +4279,15 @@ LWSTDAPI :: HRESULT CLSID_FileOpenDialog := &GUID{0xDC1C5A9C, 0xE88A, 0x4DDE, {0xA5, 0xA1, 0x60, 0xF8, 0x2A, 0x20, 0xAE, 0xF7}} CLSID_FileSaveDialog := &GUID{0xC0B4E2F3, 0xBA21, 0x4773, {0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B}} -CLSID_TaskbarList := &GUID{0x56FDF344, 0xFD6D, 0x11d0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}} +CLSID_TaskbarList := &GUID{0x56FDF344, 0xFD6D, 0x11d0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}} -IID_IFileDialog := &GUID{0x42F85136, 0xDB7E, 0x439C, {0x85, 0xF1, 0xE4, 0x07, 0x5D, 0x13, 0x5F, 0xC8}} -IID_IFileSaveDialog := &GUID{0x84BCCD23, 0x5FDE, 0x4CDB, {0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB}} -IID_IFileOpenDialog := &GUID{0xD57C7288, 0xD4AD, 0x4768, {0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60}} -IID_ITaskbarList := &GUID{0x56FDF342, 0xFD6D, 0x11d0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}} -IID_ITaskbarList2 := &GUID{0x602D4995, 0xB13A, 0x429b, {0xA6, 0x6E, 0x19, 0x35, 0xE4, 0x4F, 0x43, 0x17}} -IID_ITaskbarList3 := &GUID{0xea1afb91, 0x9e28, 0x4b86, {0x90, 0xe9, 0x9e, 0x9f, 0x8a, 0x5e, 0xef, 0xaf}} +IID_IShellItem := &GUID{0x43826d1e, 0xe718, 0x42ee, {0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe}} +IID_IFileDialog := &GUID{0x42F85136, 0xDB7E, 0x439C, {0x85, 0xF1, 0xE4, 0x07, 0x5D, 0x13, 0x5F, 0xC8}} +IID_IFileSaveDialog := &GUID{0x84BCCD23, 0x5FDE, 0x4CDB, {0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB}} +IID_IFileOpenDialog := &GUID{0xD57C7288, 0xD4AD, 0x4768, {0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60}} +IID_ITaskbarList := &GUID{0x56FDF342, 0xFD6D, 0x11d0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}} +IID_ITaskbarList2 := &GUID{0x602D4995, 0xB13A, 0x429b, {0xA6, 0x6E, 0x19, 0x35, 0xE4, 0x4F, 0x43, 0x17}} +IID_ITaskbarList3 := &GUID{0xea1afb91, 0x9e28, 0x4b86, {0x90, 0xe9, 0x9e, 0x9f, 0x8a, 0x5e, 0xef, 0xaf}} IModalWindow :: struct #raw_union { #subtype IUnknown: IUnknown, @@ -4726,24 +4783,24 @@ Windows_Product_Type :: enum DWORD { WEB_SERVER_CORE = 0x0000001D, // Web Server (core installation) } -ENABLE_ECHO_INPUT : DWORD : 0x0004 -ENABLE_INSERT_MODE : DWORD : 0x0020 -ENABLE_LINE_INPUT : DWORD : 0x0002 -ENABLE_MOUSE_INPUT : DWORD : 0x0010 -ENABLE_PROCESSED_INPUT : DWORD : 0x0001 -ENABLE_QUICK_EDIT_MODE : DWORD : 0x0040 -ENABLE_WINDOW_INPUT : DWORD : 0x0008 -ENABLE_VIRTUAL_TERMINAL_INPUT : DWORD : 0x0200 -ENABLE_PROCESSED_OUTPUT : DWORD : 0x0001 -ENABLE_WRAP_AT_EOL_OUTPUT : DWORD : 0x0002 +ENABLE_ECHO_INPUT : DWORD : 0x0004 +ENABLE_INSERT_MODE : DWORD : 0x0020 +ENABLE_LINE_INPUT : DWORD : 0x0002 +ENABLE_MOUSE_INPUT : DWORD : 0x0010 +ENABLE_PROCESSED_INPUT : DWORD : 0x0001 +ENABLE_QUICK_EDIT_MODE : DWORD : 0x0040 +ENABLE_WINDOW_INPUT : DWORD : 0x0008 +ENABLE_VIRTUAL_TERMINAL_INPUT : DWORD : 0x0200 +ENABLE_PROCESSED_OUTPUT : DWORD : 0x0001 +ENABLE_WRAP_AT_EOL_OUTPUT : DWORD : 0x0002 ENABLE_VIRTUAL_TERMINAL_PROCESSING : DWORD : 0x0004 -DISABLE_NEWLINE_AUTO_RETURN : DWORD : 0x0008 -ENABLE_LVB_GRID_WORLDWIDE : DWORD : 0x0010 +DISABLE_NEWLINE_AUTO_RETURN : DWORD : 0x0008 +ENABLE_LVB_GRID_WORLDWIDE : DWORD : 0x0010 -CTRL_C_EVENT : DWORD : 0 -CTRL_BREAK_EVENT : DWORD : 1 -CTRL_CLOSE_EVENT : DWORD : 2 -CTRL_LOGOFF_EVENT : DWORD : 5 +CTRL_C_EVENT : DWORD : 0 +CTRL_BREAK_EVENT : DWORD : 1 +CTRL_CLOSE_EVENT : DWORD : 2 +CTRL_LOGOFF_EVENT : DWORD : 5 CTRL_SHUTDOWN_EVENT : DWORD : 6 COORD :: struct { @@ -4752,45 +4809,45 @@ COORD :: struct { } SMALL_RECT :: struct { - Left: SHORT, - Top: SHORT, - Right: SHORT, + Left: SHORT, + Top: SHORT, + Right: SHORT, Bottom: SHORT, } CONSOLE_SCREEN_BUFFER_INFO :: struct { - dwSize: COORD, - dwCursorPosition: COORD, - wAttributes: WORD, - srWindow: SMALL_RECT, + dwSize: COORD, + dwCursorPosition: COORD, + wAttributes: WORD, + srWindow: SMALL_RECT, dwMaximumWindowSize: COORD, } CONSOLE_CURSOR_INFO :: struct { - dwSize: DWORD, + dwSize: DWORD, bVisible: BOOL, } PCONSOLE_SCREEN_BUFFER_INFO :: ^CONSOLE_SCREEN_BUFFER_INFO -PCONSOLE_CURSOR_INFO :: ^CONSOLE_CURSOR_INFO +PCONSOLE_CURSOR_INFO :: ^CONSOLE_CURSOR_INFO Event_Type :: enum WORD { - KEY_EVENT = 0x0001, - MOUSE_EVENT = 0x0002, + KEY_EVENT = 0x0001, + MOUSE_EVENT = 0x0002, WINDOW_BUFFER_SIZE_EVENT = 0x0004, - MENU_EVENT = 0x0008, - FOCUS_EVENT = 0x0010, + MENU_EVENT = 0x0008, + FOCUS_EVENT = 0x0010, } INPUT_RECORD :: struct { EventType: Event_Type, Event: struct #raw_union { - KeyEvent: KEY_EVENT_RECORD, - MouseEvent: MOUSE_EVENT_RECORD, - WindowBufferSizeEvent: WINDOW_BUFFER_SIZE_RECORD, - MenuEvent: MENU_EVENT_RECORD, - FocusEvent: FOCUS_EVENT_RECORD, + KeyEvent: KEY_EVENT_RECORD `raw_union_tag:"EventType=KEY_EVENT"`, + MouseEvent: MOUSE_EVENT_RECORD `raw_union_tag:"EventType=MOUSE_EVENT"`, + WindowBufferSizeEvent: WINDOW_BUFFER_SIZE_RECORD `raw_union_tag:"EventType=WINDOW_BUFFER_SIZE_EVENT"`, + MenuEvent: MENU_EVENT_RECORD `raw_union_tag:"EventType=MENU_EVENT"`, + FocusEvent: FOCUS_EVENT_RECORD `raw_union_tag:"EventType=FOCUS_EVENT"`, }, } @@ -4820,10 +4877,10 @@ KEY_EVENT_RECORD :: struct { } MOUSE_EVENT_RECORD :: struct { - dwMousePosition: COORD, - dwButtonState: DWORD, + dwMousePosition: COORD, + dwButtonState: DWORD, dwControlKeyState: DWORD, - dwEventFlags: DWORD, + dwEventFlags: DWORD, } WINDOW_BUFFER_SIZE_RECORD :: struct { @@ -4949,16 +5006,16 @@ SO_SNDBUF : c_int : 0x1001 SO_ERROR : c_int : 0x1007 SO_BROADCAST : c_int : 0x0020 -TCP_NODELAY: c_int : 0x0001 -IP_TTL: c_int : 4 -IPV6_V6ONLY: c_int : 27 -IP_MULTICAST_LOOP: c_int : 11 -IPV6_MULTICAST_LOOP: c_int : 11 -IP_MULTICAST_TTL: c_int : 10 -IP_ADD_MEMBERSHIP: c_int : 12 +TCP_NODELAY : c_int : 0x0001 +IP_TTL : c_int : 4 +IPV6_V6ONLY : c_int : 27 +IP_MULTICAST_LOOP : c_int : 11 +IPV6_MULTICAST_LOOP : c_int : 11 +IP_MULTICAST_TTL : c_int : 10 +IP_ADD_MEMBERSHIP : c_int : 12 -IPV6_ADD_MEMBERSHIP: c_int : 12 -IPV6_DROP_MEMBERSHIP: c_int : 13 +IPV6_ADD_MEMBERSHIP : c_int : 12 +IPV6_DROP_MEMBERSHIP : c_int : 13 MAX_PROTOCOL_CHAIN: DWORD : 7 @@ -4972,8 +5029,8 @@ MSG_OOB : c_int : 1 // `send`/`recv` should process out-of-band data. MSG_PEEK : c_int : 2 // `recv` should not remove the data from the buffer. Only valid for non-overlapped operations. -SOCKET :: distinct uintptr // TODO -socklen_t :: c_int +SOCKET :: distinct uintptr // TODO +socklen_t :: c_int ADDRESS_FAMILY :: USHORT ip_mreq :: struct { @@ -4999,7 +5056,7 @@ ADDRINFOA :: struct { ai_socktype: c_int, ai_protocol: c_int, ai_addrlen: size_t, - ai_canonname: ^c_char, + ai_canonname: [^]c_char `fmt:"q,ai_addrlen"`, ai_addr: ^SOCKADDR, ai_next: ^ADDRINFOA, } @@ -5032,18 +5089,18 @@ in6_addr :: struct { } -DNS_STATUS :: distinct DWORD // zero is success -DNS_INFO_NO_RECORDS :: 9501 +DNS_STATUS :: distinct DWORD // zero is success +DNS_INFO_NO_RECORDS :: 9501 DNS_QUERY_NO_RECURSION :: 0x00000004 DNS_RECORD :: struct { // aka DNS_RECORDA - pNext: ^DNS_RECORD, - pName: cstring, - wType: WORD, + pNext: ^DNS_RECORD, + pName: cstring, + wType: WORD, wDataLength: USHORT, - Flags: DWORD, - dwTtl: DWORD, - _: DWORD, + Flags: DWORD, + dwTtl: DWORD, + _: DWORD, Data: struct #raw_union #align(4) { CNAME: DNS_PTR_DATAA, A: u32be, // Ipv4 Address @@ -5064,8 +5121,8 @@ DNS_PTR_DATAA :: cstring DNS_MX_DATAA :: struct { pNameExchange: cstring, // the hostname - wPreference: WORD, // lower values preferred - _: WORD, // padding. + wPreference: WORD, // lower values preferred + _: WORD, // padding. } DNS_SRV_DATAA :: struct { pNameTarget: cstring, @@ -5110,8 +5167,8 @@ ENUMRESTYPEPROCW :: #type proc (hModule: HMODULE, lpType: LPCWSTR, lParam: LONG_ ENUMRESLANGPROCW :: #type proc (hModule: HMODULE, lpType: LPCWSTR, lpName: LPWSTR, wIDLanguage: LANGID, lParam: LONG_PTR)-> BOOL DTR_Control :: enum byte { - Disable = 0, - Enable = 1, + Disable = 0, + Enable = 1, Handshake = 2, } RTS_Control :: enum byte { @@ -5128,9 +5185,9 @@ Parity :: enum byte { Space = 4, } Stop_Bits :: enum byte { - One = 0, + One = 0, One_And_A_Half = 1, - Two = 2, + Two = 2, } DCB :: struct { @@ -5166,34 +5223,34 @@ DCB :: struct { } COMMTIMEOUTS :: struct { - ReadIntervalTimeout: DWORD, - ReadTotalTimeoutMultiplier: DWORD, - ReadTotalTimeoutConstant: DWORD, + ReadIntervalTimeout: DWORD, + ReadTotalTimeoutMultiplier: DWORD, + ReadTotalTimeoutConstant: DWORD, WriteTotalTimeoutMultiplier: DWORD, - WriteTotalTimeoutConstant: DWORD, + WriteTotalTimeoutConstant: DWORD, } -Com_Stat_Bits :: enum { - fCtsHold, - fDsrHold, - fRlsdHold, - fXoffHold, - fXoffSent, - fEof, - fTxim, -} COMSTAT :: struct { - bits: bit_set[Com_Stat_Bits; DWORD], - cbInQue: DWORD, + using _: bit_field DWORD { + fCtsHold: BOOL | 1, + fDsrHold: BOOL | 1, + fRlsdHol: BOOL | 1, + fXoffHol: BOOL | 1, + fXoffSen: BOOL | 1, + fEof: BOOL | 1, + fTxim: BOOL | 1, + fReserved: DWORD | 25, + }, + cbInQue: DWORD, cbOutQue: DWORD, } -Com_Error_Bits :: enum { +Com_Error_Bits :: enum DWORD { RXOVER, OVERRUN, RXPARITY, FRAME, BREAK, } -Com_Error :: bit_set[Com_Error_Bits; DWORD] +Com_Error :: distinct bit_set[Com_Error_Bits; DWORD] diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 76826f80b..d2f54b127 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -2,12 +2,11 @@ package sys_windows import "base:intrinsics" -import "core:c" foreign import user32 "system:User32.lib" @(default_calling_convention="system") foreign user32 { - GetClassInfoW :: proc(hInstance: HINSTANCE, lpClassName: LPCWSTR, lpWndClass: ^WNDCLASSW) -> BOOL --- + GetClassInfoW :: proc(hInstance: HINSTANCE, lpClassName: LPCWSTR, lpWndClass: ^WNDCLASSW) -> BOOL --- GetClassInfoExW :: proc(hInstance: HINSTANCE, lpszClass: LPCWSTR, lpwcx: ^WNDCLASSEXW) -> BOOL --- GetClassLongW :: proc(hWnd: HWND, nIndex: INT) -> DWORD --- @@ -20,67 +19,70 @@ foreign user32 { GetParent :: proc(hWnd: HWND) -> HWND --- SetWinEventHook :: proc( - eventMin, eventMax: DWORD, - hmodWinEventProc: HMODULE, - pfnWinEvenProc: WINEVENTPROC, + eventMin, eventMax: DWORD, + hmodWinEventProc: HMODULE, + pfnWinEvenProc: WINEVENTPROC, idProcess, idThread: DWORD, - dwFlags: WinEventFlags, + dwFlags: WinEventFlags, ) -> HWINEVENTHOOK --- + UnhookWinEvent :: proc(winEventHook: HWINEVENTHOOK) -> BOOL --- IsChild :: proc(hWndParent, hWnd: HWND) -> BOOL --- - RegisterClassW :: proc(lpWndClass: ^WNDCLASSW) -> ATOM --- + RegisterClassW :: proc(lpWndClass: ^WNDCLASSW) -> ATOM --- RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM --- UnregisterClassW :: proc(lpClassName: LPCWSTR, hInstance: HINSTANCE) -> BOOL --- - RegisterHotKey :: proc(hnwd: HWND, id: c.int, fsModifiers: UINT, vk: UINT) -> BOOL --- + RegisterHotKey :: proc(hnwd: HWND, id: c_int, fsModifiers: UINT, vk: UINT) -> BOOL --- CreateWindowExW :: proc( - dwExStyle: DWORD, - lpClassName: LPCWSTR, - lpWindowName: LPCWSTR, - dwStyle: DWORD, + dwExStyle: DWORD, + lpClassName: LPCWSTR, + lpWindowName: LPCWSTR, + dwStyle: DWORD, X, Y, nWidth, nHeight: INT, - hWndParent: HWND, - hMenu: HMENU, - hInstance: HINSTANCE, - lpParam: LPVOID, + hWndParent: HWND, + hMenu: HMENU, + hInstance: HINSTANCE, + lpParam: LPVOID, ) -> HWND --- GetWindowThreadProcessId :: proc(hwnd: HWND, lpdwProcessId: LPDWORD) -> DWORD --- DestroyWindow :: proc(hWnd: HWND) -> BOOL --- - ShowWindow :: proc(hWnd: HWND, nCmdShow: INT) -> BOOL --- - IsWindow :: proc(hWnd: HWND) -> BOOL --- - IsWindowVisible :: proc(hwnd: HWND) -> BOOL --- - IsWindowEnabled :: proc(hwnd: HWND) -> BOOL --- - IsIconic :: proc(hwnd: HWND) -> BOOL --- - IsZoomed :: proc(hwnd: HWND) -> BOOL --- - BringWindowToTop :: proc(hWnd: HWND) -> BOOL --- - GetTopWindow :: proc(hWnd: HWND) -> HWND --- + ShowWindow :: proc(hWnd: HWND, nCmdShow: INT) -> BOOL --- + IsWindow :: proc(hWnd: HWND) -> BOOL --- + IsWindowVisible :: proc(hwnd: HWND) -> BOOL --- + IsWindowEnabled :: proc(hwnd: HWND) -> BOOL --- + IsIconic :: proc(hwnd: HWND) -> BOOL --- + IsZoomed :: proc(hwnd: HWND) -> BOOL --- + BringWindowToTop :: proc(hWnd: HWND) -> BOOL --- + GetTopWindow :: proc(hWnd: HWND) -> HWND --- + GetWindow :: proc(hwnd: HWND, uCmd: UINT) -> HWND --- SetForegroundWindow :: proc(hWnd: HWND) -> BOOL --- GetForegroundWindow :: proc() -> HWND --- - GetDesktopWindow :: proc() -> HWND --- - UpdateWindow :: proc(hWnd: HWND) -> BOOL --- - SetActiveWindow :: proc(hWnd: HWND) -> HWND --- - GetActiveWindow :: proc() -> HWND --- - SetFocus :: proc(hWnd: HWND) -> HWND --- - GetFocus :: proc() -> HWND --- - RedrawWindow :: proc(hwnd: HWND, lprcUpdate: LPRECT, hrgnUpdate: HRGN, flags: RedrawWindowFlags) -> BOOL --- - SetParent :: proc(hWndChild: HWND, hWndNewParent: HWND) -> HWND --- - SetPropW :: proc(hWnd: HWND, lpString: LPCWSTR, hData: HANDLE) -> BOOL --- - GetPropW :: proc(hWnd: HWND, lpString: LPCWSTR) -> HANDLE --- - RemovePropW :: proc(hWnd: HWND, lpString: LPCWSTR) -> HANDLE --- - EnumPropsW :: proc(hWnd: HWND, lpEnumFunc: PROPENUMPROCW) -> INT --- - EnumPropsExW :: proc(hWnd: HWND, lpEnumFunc: PROPENUMPROCW, lParam: LPARAM) -> INT --- - GetMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> INT --- + GetDesktopWindow :: proc() -> HWND --- + UpdateWindow :: proc(hWnd: HWND) -> BOOL --- + SetActiveWindow :: proc(hWnd: HWND) -> HWND --- + GetActiveWindow :: proc() -> HWND --- + SetFocus :: proc(hWnd: HWND) -> HWND --- + GetFocus :: proc() -> HWND --- + RedrawWindow :: proc(hwnd: HWND, lprcUpdate: LPRECT, hrgnUpdate: HRGN, flags: RedrawWindowFlags) -> BOOL --- + SetParent :: proc(hWndChild: HWND, hWndNewParent: HWND) -> HWND --- + SetPropW :: proc(hWnd: HWND, lpString: LPCWSTR, hData: HANDLE) -> BOOL --- + GetPropW :: proc(hWnd: HWND, lpString: LPCWSTR) -> HANDLE --- + RemovePropW :: proc(hWnd: HWND, lpString: LPCWSTR) -> HANDLE --- + EnumPropsW :: proc(hWnd: HWND, lpEnumFunc: PROPENUMPROCW) -> INT --- + EnumPropsExW :: proc(hWnd: HWND, lpEnumFunc: PROPENUMPROCW, lParam: LPARAM) -> INT --- + GetMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> INT --- + GetMessageExtraInfo :: proc() -> LPARAM --- TranslateMessage :: proc(lpMsg: ^MSG) -> BOOL --- DispatchMessageW :: proc(lpMsg: ^MSG) -> LRESULT --- - WaitMessage :: proc() -> BOOL --- - MsgWaitForMultipleObjects :: proc(nCount: DWORD, pHandles: ^HANDLE, fWaitAll: BOOL, dwMilliseconds: DWORD, dwWakeMask: DWORD) -> DWORD --- + WaitMessage :: proc() -> BOOL --- + MsgWaitForMultipleObjects :: proc(nCount: DWORD, pHandles: [^]HANDLE, fWaitAll: BOOL, dwMilliseconds: DWORD, dwWakeMask: DWORD) -> DWORD --- PeekMessageA :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL --- PeekMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL --- @@ -100,97 +102,98 @@ foreign user32 { DefWindowProcA :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- DefWindowProcW :: proc(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- - FindWindowA :: proc(lpClassName: LPCSTR, lpWindowName: LPCSTR) -> HWND --- - FindWindowW :: proc(lpClassName: LPCWSTR, lpWindowName: LPCWSTR) -> HWND --- + FindWindowA :: proc(lpClassName: LPCSTR, lpWindowName: LPCSTR) -> HWND --- + FindWindowW :: proc(lpClassName: LPCWSTR, lpWindowName: LPCWSTR) -> HWND --- FindWindowExA :: proc(hWndParent: HWND, hWndChildAfter: HWND, lpszClass: LPCSTR, lpszWindow: LPCSTR) -> HWND --- FindWindowExW :: proc(hWndParent: HWND, hWndChildAfter: HWND, lpszClass: LPCWSTR, lpszWindow: LPCWSTR) -> HWND --- - LoadIconA :: proc(hInstance: HINSTANCE, lpIconName: LPCSTR) -> HICON --- - LoadIconW :: proc(hInstance: HINSTANCE, lpIconName: LPCWSTR) -> HICON --- + LoadIconA :: proc(hInstance: HINSTANCE, lpIconName: LPCSTR) -> HICON --- + LoadIconW :: proc(hInstance: HINSTANCE, lpIconName: LPCWSTR) -> HICON --- GetIconInfoExW :: proc(hIcon: HICON, piconinfo: PICONINFOEXW) -> BOOL --- - LoadCursorA :: proc(hInstance: HINSTANCE, lpCursorName: LPCSTR) -> HCURSOR --- - LoadCursorW :: proc(hInstance: HINSTANCE, lpCursorName: LPCWSTR) -> HCURSOR --- - LoadImageW :: proc(hInst: HINSTANCE, name: LPCWSTR, type: UINT, cx, cy: INT, fuLoad: UINT) -> HANDLE --- + LoadCursorA :: proc(hInstance: HINSTANCE, lpCursorName: LPCSTR) -> HCURSOR --- + LoadCursorW :: proc(hInstance: HINSTANCE, lpCursorName: LPCWSTR) -> HCURSOR --- + LoadImageW :: proc(hInst: HINSTANCE, name: LPCWSTR, type: UINT, cx, cy: INT, fuLoad: UINT) -> HANDLE --- - CreateIcon :: proc(hInstance: HINSTANCE, nWidth, nHeight: INT, cPlanes: BYTE, cBitsPixel: BYTE, lpbANDbits: PBYTE, lpbXORbits: PBYTE) -> HICON --- + CreateIcon :: proc(hInstance: HINSTANCE, nWidth, nHeight: INT, cPlanes: BYTE, cBitsPixel: BYTE, lpbANDbits: PBYTE, lpbXORbits: PBYTE) -> HICON --- CreateIconFromResource :: proc(presbits: PBYTE, dwResSize: DWORD, fIcon: BOOL, dwVer: DWORD) -> HICON --- - DestroyIcon :: proc(hIcon: HICON) -> BOOL --- - DrawIcon :: proc(hDC: HDC, X, Y: INT, hIcon: HICON) -> BOOL --- + CreateIconIndirect :: proc(piconinfo: PICONINFO) -> HICON --- + DestroyIcon :: proc(hIcon: HICON) -> BOOL --- + DrawIcon :: proc(hDC: HDC, X, Y: INT, hIcon: HICON) -> BOOL --- - CreateCursor :: proc(hInst: HINSTANCE, xHotSpot, yHotSpot, nWidth, nHeight: INT, pvANDPlane: PVOID, pvXORPlane: PVOID) -> HCURSOR --- + CreateCursor :: proc(hInst: HINSTANCE, xHotSpot, yHotSpot, nWidth, nHeight: INT, pvANDPlane: PVOID, pvXORPlane: PVOID) -> HCURSOR --- DestroyCursor :: proc(hCursor: HCURSOR) -> BOOL --- - GetWindowRect :: proc(hWnd: HWND, lpRect: LPRECT) -> BOOL --- - GetClientRect :: proc(hWnd: HWND, lpRect: LPRECT) -> BOOL --- - ClientToScreen :: proc(hWnd: HWND, lpPoint: LPPOINT) -> BOOL --- - ScreenToClient :: proc(hWnd: HWND, lpPoint: LPPOINT) -> BOOL --- - SetWindowPos :: proc(hWnd: HWND, hWndInsertAfter: HWND, X, Y, cx, cy: INT, uFlags: UINT) -> BOOL --- - MoveWindow :: proc(hWnd: HWND, X, Y, hWidth, hHeight: INT, bRepaint: BOOL) -> BOOL --- - GetSystemMetrics :: proc(nIndex: INT) -> INT --- - AdjustWindowRect :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL) -> BOOL --- - AdjustWindowRectEx :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD) -> BOOL --- + GetWindowRect :: proc(hWnd: HWND, lpRect: LPRECT) -> BOOL --- + GetClientRect :: proc(hWnd: HWND, lpRect: LPRECT) -> BOOL --- + ClientToScreen :: proc(hWnd: HWND, lpPoint: LPPOINT) -> BOOL --- + ScreenToClient :: proc(hWnd: HWND, lpPoint: LPPOINT) -> BOOL --- + SetWindowPos :: proc(hWnd: HWND, hWndInsertAfter: HWND, X, Y, cx, cy: INT, uFlags: UINT) -> BOOL --- + MoveWindow :: proc(hWnd: HWND, X, Y, hWidth, hHeight: INT, bRepaint: BOOL) -> BOOL --- + GetSystemMetrics :: proc(nIndex: INT) -> INT --- + AdjustWindowRect :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL) -> BOOL --- + AdjustWindowRectEx :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD) -> BOOL --- AdjustWindowRectExForDpi :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD, dpi: UINT) -> BOOL --- SystemParametersInfoW :: proc(uiAction, uiParam: UINT, pvParam: PVOID, fWinIni: UINT) -> BOOL --- - GetMonitorInfoW :: proc(hMonitor: HMONITOR, lpmi: LPMONITORINFO) -> BOOL --- + GetMonitorInfoW :: proc(hMonitor: HMONITOR, lpmi: LPMONITORINFO) -> BOOL --- GetWindowDC :: proc(hWnd: HWND) -> HDC --- - GetDC :: proc(hWnd: HWND) -> HDC --- - GetDCEx :: proc(hWnd: HWND, hrgnClip: HRGN, flags: DWORD) -> HDC --- - ReleaseDC :: proc(hWnd: HWND, hDC: HDC) -> INT --- + GetDC :: proc(hWnd: HWND) -> HDC --- + GetDCEx :: proc(hWnd: HWND, hrgnClip: HRGN, flags: DWORD) -> HDC --- + ReleaseDC :: proc(hWnd: HWND, hDC: HDC) -> INT --- GetDlgCtrlID :: proc(hWnd: HWND) -> INT --- - GetDlgItem :: proc(hDlg: HWND, nIDDlgItem: INT) -> HWND --- + GetDlgItem :: proc(hDlg: HWND, nIDDlgItem: INT) -> HWND --- - CreateMenu :: proc() -> HMENU --- - CreatePopupMenu :: proc() -> HMENU --- - DeleteMenu :: proc(hMenu: HMENU, uPosition: UINT, uFlags: UINT) -> BOOL --- - DestroyMenu :: proc(hMenu: HMENU) -> BOOL --- - InsertMenuW :: proc(hMenu: HMENU, uPosition: UINT, uFlags: UINT, uIDNewItem: UINT_PTR, lpNewItem: LPCWSTR) -> BOOL --- - AppendMenuW :: proc(hMenu: HMENU, uFlags: UINT, uIDNewItem: UINT_PTR, lpNewItem: LPCWSTR) -> BOOL --- - GetMenu :: proc(hWnd: HWND) -> HMENU --- - SetMenu :: proc(hWnd: HWND, hMenu: HMENU) -> BOOL --- - TrackPopupMenu :: proc(hMenu: HMENU, uFlags: UINT, x, y: INT, nReserved: INT, hWnd: HWND, prcRect: ^RECT) -> INT --- + CreateMenu :: proc() -> HMENU --- + CreatePopupMenu :: proc() -> HMENU --- + DeleteMenu :: proc(hMenu: HMENU, uPosition: UINT, uFlags: UINT) -> BOOL --- + DestroyMenu :: proc(hMenu: HMENU) -> BOOL --- + InsertMenuW :: proc(hMenu: HMENU, uPosition: UINT, uFlags: UINT, uIDNewItem: UINT_PTR, lpNewItem: LPCWSTR) -> BOOL --- + AppendMenuW :: proc(hMenu: HMENU, uFlags: UINT, uIDNewItem: UINT_PTR, lpNewItem: LPCWSTR) -> BOOL --- + GetMenu :: proc(hWnd: HWND) -> HMENU --- + SetMenu :: proc(hWnd: HWND, hMenu: HMENU) -> BOOL --- + TrackPopupMenu :: proc(hMenu: HMENU, uFlags: UINT, x, y: INT, nReserved: INT, hWnd: HWND, prcRect: ^RECT) -> INT --- RegisterWindowMessageW :: proc(lpString: LPCWSTR) -> UINT --- CreateAcceleratorTableW :: proc(paccel: LPACCEL, cAccel: INT) -> HACCEL --- DestroyAcceleratorTable :: proc(hAccel: HACCEL) -> BOOL --- - LoadAcceleratorsW :: proc(hInstance: HINSTANCE, lpTableName: LPCWSTR) -> HACCEL --- - TranslateAcceleratorW :: proc(hWnd: HWND, hAccTable: HACCEL, lpMsg: LPMSG) -> INT --- - CopyAcceleratorTableW :: proc(hAccelSrc: HACCEL, lpAccelDst: LPACCEL, cAccelEntries: INT) -> INT --- + LoadAcceleratorsW :: proc(hInstance: HINSTANCE, lpTableName: LPCWSTR) -> HACCEL --- + TranslateAcceleratorW :: proc(hWnd: HWND, hAccTable: HACCEL, lpMsg: LPMSG) -> INT --- + CopyAcceleratorTableW :: proc(hAccelSrc: HACCEL, lpAccelDst: LPACCEL, cAccelEntries: INT) -> INT --- - InsertMenuItemW :: proc(hmenu: HMENU, item: UINT, fByPosition: BOOL, lpmi: LPMENUITEMINFOW) -> BOOL --- - GetMenuItemInfoW :: proc(hmenu: HMENU, item: UINT, fByPosition: BOOL, lpmii: LPMENUITEMINFOW) -> BOOL --- - SetMenuItemInfoW :: proc(hmenu: HMENU, item: UINT, fByPositon: BOOL, lpmii: LPMENUITEMINFOW) -> BOOL --- + InsertMenuItemW :: proc(hmenu: HMENU, item: UINT, fByPosition: BOOL, lpmi: LPMENUITEMINFOW) -> BOOL --- + GetMenuItemInfoW :: proc(hmenu: HMENU, item: UINT, fByPosition: BOOL, lpmii: LPMENUITEMINFOW) -> BOOL --- + SetMenuItemInfoW :: proc(hmenu: HMENU, item: UINT, fByPositon: BOOL, lpmii: LPMENUITEMINFOW) -> BOOL --- GetMenuDefaultItem :: proc(hMenu: HMENU, fByPos: UINT, gmdiFlags: UINT) -> UINT --- SetMenuDefaultItem :: proc(hMenu: HMENU, uItem: UINT, fByPos: UINT) -> BOOL --- - GetMenuItemRect :: proc(hWnd: HWND, hMenu: HMENU, uItem: UINT, lprcItem: LPRECT) -> c_int --- + GetMenuItemRect :: proc(hWnd: HWND, hMenu: HMENU, uItem: UINT, lprcItem: LPRECT) -> c_int --- - GetUpdateRect :: proc(hWnd: HWND, lpRect: LPRECT, bErase: BOOL) -> BOOL --- - ValidateRect :: proc(hWnd: HWND, lpRect: ^RECT) -> BOOL --- + GetUpdateRect :: proc(hWnd: HWND, lpRect: LPRECT, bErase: BOOL) -> BOOL --- + ValidateRect :: proc(hWnd: HWND, lpRect: ^RECT) -> BOOL --- InvalidateRect :: proc(hWnd: HWND, lpRect: ^RECT, bErase: BOOL) -> BOOL --- BeginPaint :: proc(hWnd: HWND, lpPaint: ^PAINTSTRUCT) -> HDC --- - EndPaint :: proc(hWnd: HWND, lpPaint: ^PAINTSTRUCT) -> BOOL --- + EndPaint :: proc(hWnd: HWND, lpPaint: ^PAINTSTRUCT) -> BOOL --- - GetCapture :: proc() -> HWND --- - SetCapture :: proc(hWnd: HWND) -> HWND --- - ReleaseCapture :: proc() -> BOOL --- + GetCapture :: proc() -> HWND --- + SetCapture :: proc(hWnd: HWND) -> HWND --- + ReleaseCapture :: proc() -> BOOL --- TrackMouseEvent :: proc(lpEventTrack: LPTRACKMOUSEEVENT) -> BOOL --- - GetKeyState :: proc(nVirtKey: INT) -> SHORT --- + GetKeyState :: proc(nVirtKey: INT) -> SHORT --- GetAsyncKeyState :: proc(vKey: INT) -> SHORT --- GetKeyboardState :: proc(lpKeyState: PBYTE) -> BOOL --- MapVirtualKeyW :: proc(uCode: UINT, uMapType: UINT) -> UINT --- - ToUnicode :: proc(nVirtKey: UINT, wScanCode: UINT, lpKeyState: ^BYTE, pwszBuff: LPWSTR, cchBuff: INT, wFlags: UINT) -> INT --- + ToUnicode :: proc(nVirtKey: UINT, wScanCode: UINT, lpKeyState: ^BYTE, pwszBuff: LPWSTR, cchBuff: INT, wFlags: UINT) -> INT --- - SetWindowsHookExW :: proc(idHook: INT, lpfn: HOOKPROC, hmod: HINSTANCE, dwThreadId: DWORD) -> HHOOK --- + SetWindowsHookExW :: proc(idHook: INT, lpfn: HOOKPROC, hmod: HINSTANCE, dwThreadId: DWORD) -> HHOOK --- UnhookWindowsHookEx :: proc(hhk: HHOOK) -> BOOL --- - CallNextHookEx :: proc(hhk: HHOOK, nCode: INT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- + CallNextHookEx :: proc(hhk: HHOOK, nCode: INT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- - SetTimer :: proc(hWnd: HWND, nIDEvent: UINT_PTR, uElapse: UINT, lpTimerFunc: TIMERPROC) -> UINT_PTR --- + SetTimer :: proc(hWnd: HWND, nIDEvent: UINT_PTR, uElapse: UINT, lpTimerFunc: TIMERPROC) -> UINT_PTR --- KillTimer :: proc(hWnd: HWND, uIDEvent: UINT_PTR) -> BOOL --- // MessageBoxA :: proc(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT) -> INT --- @@ -198,143 +201,165 @@ foreign user32 { // MessageBoxExA :: proc(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT, wLanguageId: WORD) -> INT --- MessageBoxExW :: proc(hWnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR, uType: UINT, wLanguageId: WORD) -> INT --- - ClipCursor :: proc(lpRect: LPRECT) -> BOOL --- + ClipCursor :: proc(lpRect: LPRECT) -> BOOL --- GetCursorPos :: proc(lpPoint: LPPOINT) -> BOOL --- SetCursorPos :: proc(X, Y: INT) -> BOOL --- - SetCursor :: proc(hCursor: HCURSOR) -> HCURSOR --- + SetCursor :: proc(hCursor: HCURSOR) -> HCURSOR --- when !intrinsics.is_package_imported("raylib") { ShowCursor :: proc(bShow: BOOL) -> INT --- } - EnumDisplayDevicesW :: proc (lpDevice: LPCWSTR, iDevNum: DWORD, lpDisplayDevice: PDISPLAY_DEVICEW, dwFlags: DWORD) -> BOOL --- + EnumDisplayDevicesW :: proc(lpDevice: LPCWSTR, iDevNum: DWORD, lpDisplayDevice: PDISPLAY_DEVICEW, dwFlags: DWORD) -> BOOL --- EnumDisplaySettingsW :: proc(lpszDeviceName: LPCWSTR, iModeNum: DWORD, lpDevMode: ^DEVMODEW) -> BOOL --- - MonitorFromPoint :: proc(pt: POINT, dwFlags: Monitor_From_Flags) -> HMONITOR --- - MonitorFromRect :: proc(lprc: LPRECT, dwFlags: Monitor_From_Flags) -> HMONITOR --- - MonitorFromWindow :: proc(hwnd: HWND, dwFlags: Monitor_From_Flags) -> HMONITOR --- + WindowFromPoint :: proc(pt: POINT) -> HWND --- + MonitorFromPoint :: proc(pt: POINT, dwFlags: Monitor_From_Flags) -> HMONITOR --- + MonitorFromRect :: proc(lprc: LPRECT, dwFlags: Monitor_From_Flags) -> HMONITOR --- + MonitorFromWindow :: proc(hwnd: HWND, dwFlags: Monitor_From_Flags) -> HMONITOR --- EnumDisplayMonitors :: proc(hdc: HDC, lprcClip: LPRECT, lpfnEnum: Monitor_Enum_Proc, dwData: LPARAM) -> BOOL --- - EnumWindows :: proc(lpEnumFunc: Window_Enum_Proc, lParam: LPARAM) -> BOOL --- + EnumWindows :: proc(lpEnumFunc: Window_Enum_Proc, lParam: LPARAM) -> BOOL --- EnumChildWindows :: proc(hWndParent: HWND, lpEnumFunc: Window_Enum_Proc, lParam: LPARAM) -> BOOL --- - IsProcessDPIAware :: proc() -> BOOL --- + IsProcessDPIAware :: proc() -> BOOL --- SetProcessDPIAware :: proc() -> BOOL --- - SetThreadDpiAwarenessContext :: proc(dpiContext: DPI_AWARENESS_CONTEXT) -> DPI_AWARENESS_CONTEXT --- - GetThreadDpiAwarenessContext :: proc() -> DPI_AWARENESS_CONTEXT --- - GetWindowDpiAwarenessContext :: proc(hwnd: HWND) -> DPI_AWARENESS_CONTEXT --- + SetThreadDpiAwarenessContext :: proc(dpiContext: DPI_AWARENESS_CONTEXT) -> DPI_AWARENESS_CONTEXT --- + GetThreadDpiAwarenessContext :: proc() -> DPI_AWARENESS_CONTEXT --- + GetWindowDpiAwarenessContext :: proc(hwnd: HWND) -> DPI_AWARENESS_CONTEXT --- GetDpiFromDpiAwarenessContext :: proc(value: DPI_AWARENESS_CONTEXT) -> UINT --- - GetDpiForWindow :: proc(hwnd: HWND) -> UINT --- + GetDpiForWindow :: proc(hwnd: HWND) -> UINT --- SetProcessDpiAwarenessContext :: proc(value: DPI_AWARENESS_CONTEXT) -> BOOL --- BroadcastSystemMessageW :: proc( - flags: DWORD, + flags: DWORD, lpInfo: LPDWORD, - Msg: UINT, + Msg: UINT, wParam: WPARAM, lParam: LPARAM, ) -> c_long --- BroadcastSystemMessageExW :: proc( - flags: DWORD, - lpInfo: LPDWORD, - Msg: UINT, - wParam: WPARAM, - lParam: LPARAM, + flags: DWORD, + lpInfo: LPDWORD, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, pbsmInfo: PBSMINFO, ) -> c_long --- SendMessageTimeoutW :: proc( - hWnd: HWND, - Msg: UINT, - wParam: WPARAM, - lParam: LPARAM, - fuFlags: UINT, - uTimeout: UINT, + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + fuFlags: UINT, + uTimeout: UINT, lpdwResult: PDWORD_PTR, ) -> LRESULT --- - GetSysColor :: proc(nIndex: INT) -> DWORD --- + GetSysColor :: proc(nIndex: INT) -> DWORD --- GetSysColorBrush :: proc(nIndex: INT) -> HBRUSH --- - SetSysColors :: proc(cElements: INT, lpaElements: ^INT, lpaRgbValues: ^COLORREF) -> BOOL --- - MessageBeep :: proc(uType: UINT) -> BOOL --- + SetSysColors :: proc(cElements: INT, lpaElements: [^]INT, lpaRgbValues: ^COLORREF) -> BOOL --- + MessageBeep :: proc(uType: UINT) -> BOOL --- - IsDialogMessageW :: proc(hDlg: HWND, lpMsg: LPMSG) -> BOOL --- + IsDialogMessageW :: proc(hDlg: HWND, lpMsg: LPMSG) -> BOOL --- GetWindowTextLengthW :: proc(hWnd: HWND) -> INT --- - GetWindowTextW :: proc(hWnd: HWND, lpString: LPWSTR, nMaxCount: INT) -> INT --- - SetWindowTextW :: proc(hWnd: HWND, lpString: LPCWSTR) -> BOOL --- - CallWindowProcW :: proc(lpPrevWndFunc: WNDPROC, hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- - EnableWindow :: proc(hWnd: HWND, bEnable: BOOL) -> BOOL --- + GetWindowTextW :: proc(hWnd: HWND, lpString: LPWSTR, nMaxCount: INT) -> INT --- + SetWindowTextW :: proc(hWnd: HWND, lpString: LPCWSTR) -> BOOL --- + CallWindowProcW :: proc(lpPrevWndFunc: WNDPROC, hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- + EnableWindow :: proc(hWnd: HWND, bEnable: BOOL) -> BOOL --- - DefRawInputProc :: proc(paRawInput: ^PRAWINPUT, nInput: INT, cbSizeHeader: UINT) -> LRESULT --- - GetRawInputBuffer :: proc(pRawInput: PRAWINPUT, pcbSize: PUINT, cbSizeHeader: UINT) -> UINT --- - GetRawInputData :: proc(hRawInput: HRAWINPUT, uiCommand: UINT, pData: LPVOID, pcbSize: PUINT, cbSizeHeader: UINT) -> UINT --- - GetRawInputDeviceInfoW :: proc(hDevice: HANDLE, uiCommand: UINT, pData: LPVOID, pcbSize: PUINT) -> UINT --- - GetRawInputDeviceList :: proc(pRawInputDeviceList: PRAWINPUTDEVICELIST, puiNumDevices: PUINT, cbSize: UINT) -> UINT --- + DefRawInputProc :: proc(paRawInput: ^PRAWINPUT, nInput: INT, cbSizeHeader: UINT) -> LRESULT --- + GetRawInputBuffer :: proc(pRawInput: PRAWINPUT, pcbSize: PUINT, cbSizeHeader: UINT) -> UINT --- + GetRawInputData :: proc(hRawInput: HRAWINPUT, uiCommand: UINT, pData: LPVOID, pcbSize: PUINT, cbSizeHeader: UINT) -> UINT --- + GetRawInputDeviceInfoW :: proc(hDevice: HANDLE, uiCommand: UINT, pData: LPVOID, pcbSize: PUINT) -> UINT --- + GetRawInputDeviceList :: proc(pRawInputDeviceList: PRAWINPUTDEVICELIST, puiNumDevices: PUINT, cbSize: UINT) -> UINT --- GetRegisteredRawInputDevices :: proc(pRawInputDevices: PRAWINPUTDEVICE, puiNumDevices: PUINT, cbSize: UINT) -> UINT --- - RegisterRawInputDevices :: proc(pRawInputDevices: PCRAWINPUTDEVICE, uiNumDevices: UINT, cbSize: UINT) -> BOOL --- + RegisterRawInputDevices :: proc(pRawInputDevices: PCRAWINPUTDEVICE, uiNumDevices: UINT, cbSize: UINT) -> BOOL --- SendInput :: proc(cInputs: UINT, pInputs: [^]INPUT, cbSize: INT) -> UINT --- SetLayeredWindowAttributes :: proc(hWnd: HWND, crKey: COLORREF, bAlpha: BYTE, dwFlags: DWORD) -> BOOL --- - FillRect :: proc(hDC: HDC, lprc: ^RECT, hbr: HBRUSH) -> int --- - EqualRect :: proc(lprc1, lprc2: ^RECT) -> BOOL --- - OffsetRect :: proc(lprc1: ^RECT, dx, dy: INT) -> BOOL --- - InflateRect :: proc(lprc1: ^RECT, dx, dy: INT) -> BOOL --- + FillRect :: proc(hDC: HDC, lprc: ^RECT, hbr: HBRUSH) -> c_int --- + FrameRect :: proc(hDC: HDC, lprc: ^RECT, hbr: HBRUSH) -> c_int --- + InvertRect :: proc(hDC: HDC, lprc: ^RECT) -> BOOL --- + EqualRect :: proc(lprc1, lprc2: ^RECT) -> BOOL --- + OffsetRect :: proc(lprc1: ^RECT, dx, dy: INT) -> BOOL --- + InflateRect :: proc(lprc1: ^RECT, dx, dy: INT) -> BOOL --- IntersectRect :: proc(lprcDst, lprcSrc1, lprcSrc2: ^RECT) -> BOOL --- - SubtractRect :: proc(lprcDst, lprcSrc1, lprcSrc2: ^RECT) -> BOOL --- - UnionRect :: proc(lprcDst, lprcSrc1, lprcSrc2: ^RECT) -> BOOL --- - IsRectEmpty :: proc(lprc: ^RECT) -> BOOL --- - SetRectEmpty :: proc(lprc: ^RECT) -> BOOL --- - CopyRect :: proc(lprcDst, lprcSrc: ^RECT) -> BOOL --- + SubtractRect :: proc(lprcDst, lprcSrc1, lprcSrc2: ^RECT) -> BOOL --- + UnionRect :: proc(lprcDst, lprcSrc1, lprcSrc2: ^RECT) -> BOOL --- + IsRectEmpty :: proc(lprc: ^RECT) -> BOOL --- + SetRectEmpty :: proc(lprc: ^RECT) -> BOOL --- + CopyRect :: proc(lprcDst, lprcSrc: ^RECT) -> BOOL --- - GetWindowInfo :: proc(hwnd: HWND, pwi: PWINDOWINFO) -> BOOL --- - GetWindowPlacement :: proc(hWnd: HWND, lpwndpl: ^WINDOWPLACEMENT) -> BOOL --- - SetWindowPlacement :: proc(hwnd: HWND, lpwndpl: ^WINDOWPLACEMENT) -> BOOL --- - SetWindowRgn :: proc(hWnd: HWND, hRgn: HRGN, bRedraw: BOOL) -> int --- - CreateRectRgnIndirect :: proc(lprect: ^RECT) -> HRGN --- - GetSystemMetricsForDpi :: proc(nIndex: int, dpi: UINT) -> int --- + GetWindowInfo :: proc(hwnd: HWND, pwi: PWINDOWINFO) -> BOOL --- + GetWindowPlacement :: proc(hWnd: HWND, lpwndpl: ^WINDOWPLACEMENT) -> BOOL --- + SetWindowPlacement :: proc(hwnd: HWND, lpwndpl: ^WINDOWPLACEMENT) -> BOOL --- + SetWindowRgn :: proc(hWnd: HWND, hRgn: HRGN, bRedraw: BOOL) -> c_int --- + CreateRectRgnIndirect :: proc(lprect: ^RECT) -> HRGN --- + GetSystemMetricsForDpi :: proc(nIndex: c_int, dpi: UINT) -> c_int --- GetCursorInfo :: proc(pci: PCURSORINFO) -> BOOL --- - GetSystemMenu :: proc(hWnd: HWND, bRevert: BOOL) -> HMENU --- - EnableMenuItem :: proc(hMenu: HMENU, uIDEnableItem: UINT, uEnable: UINT) -> BOOL --- + GetSystemMenu :: proc(hWnd: HWND, bRevert: BOOL) -> HMENU --- + EnableMenuItem :: proc(hMenu: HMENU, uIDEnableItem: UINT, uEnable: UINT) -> BOOL --- MenuItemFromPoint :: proc(hWnd: HWND, hMenu: HMENU, ptScreen: POINT) -> INT --- - DrawTextW :: proc(hdc: HDC, lpchText: LPCWSTR, cchText: INT, lprc: LPRECT, format: DrawTextFormat) -> INT --- + DrawTextW :: proc(hdc: HDC, lpchText: LPCWSTR, cchText: INT, lprc: LPRECT, format: DrawTextFormat) -> INT --- DrawTextExW :: proc(hdc: HDC, lpchText: LPCWSTR, cchText: INT, lprc: LPRECT, format: DrawTextFormat, lpdtp: PDRAWTEXTPARAMS) -> INT --- - GetLocaleInfoEx :: proc(lpLocaleName: LPCWSTR, LCType: LCTYPE, lpLCData: LPWSTR, cchData: INT) -> INT --- + GetLocaleInfoEx :: proc(lpLocaleName: LPCWSTR, LCType: LCTYPE, lpLCData: LPWSTR, cchData: INT) -> INT --- IsValidLocaleName :: proc(lpLocaleName: LPCWSTR) -> BOOL --- ResolveLocaleName :: proc(lpNameToResolve: LPCWSTR, lpLocaleName: LPWSTR, cchLocaleName: INT) -> INT --- - IsValidCodePage :: proc(CodePage: UINT) -> BOOL --- - GetACP :: proc() -> CODEPAGE --- - GetCPInfoExW :: proc(CodePage: CODEPAGE, dwFlags: DWORD, lpCPInfoEx: LPCPINFOEXW) -> BOOL --- + IsValidCodePage :: proc(CodePage: UINT) -> BOOL --- + GetACP :: proc() -> CODEPAGE --- + GetCPInfoExW :: proc(CodePage: CODEPAGE, dwFlags: DWORD, lpCPInfoEx: LPCPINFOEXW) -> BOOL --- - GetProcessWindowStation :: proc() -> HWINSTA --- + GetProcessWindowStation :: proc() -> HWINSTA --- GetUserObjectInformationW :: proc(hObj: HANDLE, nIndex: GetUserObjectInformationFlags, pvInfo: PVOID, nLength: DWORD, lpnLengthNeeded: LPDWORD) -> BOOL --- - OpenClipboard :: proc(hWndNewOwner: HWND) -> BOOL --- - CloseClipboard :: proc() -> BOOL --- - GetClipboardData :: proc(uFormat: UINT) -> HANDLE --- - SetClipboardData :: proc(uFormat: UINT, hMem: HANDLE) -> HANDLE --- - IsClipboardFormatAvailable :: proc(format: UINT) -> BOOL --- - EmptyClipboard :: proc() -> BOOL --- + OpenClipboard :: proc(hWndNewOwner: HWND) -> BOOL --- + CloseClipboard :: proc() -> BOOL --- + GetClipboardData :: proc(uFormat: UINT) -> HANDLE --- + SetClipboardData :: proc(uFormat: UINT, hMem: HANDLE) -> HANDLE --- + IsClipboardFormatAvailable :: proc(format: UINT) -> BOOL --- + EmptyClipboard :: proc() -> BOOL --- + AddClipboardFormatListener :: proc(hwnd: HWND) -> BOOL --- + ChangeClipboardChain :: proc(hWndRemove: HWND, hWndNewNext: HWND) -> BOOL --- + CountClipboardFormats :: proc() -> c_int --- + EnumClipboardFormats :: proc(format: UINT) -> UINT --- + GetClipboardFormatNameW :: proc(format: UINT, lpszFormatName: LPWSTR, cchMaxCount: c_int) -> c_int --- + GetClipboardOwner :: proc() -> HWND--- + GetClipboardSequenceNumber :: proc() -> DWORD --- + GetClipboardViewer :: proc() -> HWND --- + GetOpenClipboardWindow :: proc() -> HWND --- + GetPriorityClipboardFormat :: proc(paFormatPriorityList: ^UINT, cFormats: c_int) -> c_int --- + GetUpdatedClipboardFormats :: proc(lpuiFormats: ^UINT, cFormats: UINT, pcFormatsOut: ^UINT) -> BOOL --- + RegisterClipboardFormatW :: proc(lpszFormat: LPCWSTR ) -> UINT --- + RemoveClipboardFormatListener :: proc(hwnd: HWND) -> BOOL --- + SetClipboardViewer :: proc(hWndNewViewer: HWND) -> HWND --- + + SetScrollInfo :: proc(hwnd: HWND, nBar: c_int, lpsi: ^SCROLLINFO, redraw: BOOL) -> c_int --- + GetScrollInfo :: proc(hwnd: HWND, nBar: c_int, lpsi: ^SCROLLINFO) -> BOOL --- + ShowScrollBar :: proc(hwnd: HWND, nBar: c_int, bShow: BOOL) -> BOOL --- + EnableScrollBar :: proc(hwnd: HWND, wSBflags: UINT, wArrows: UINT) -> BOOL --- } CreateWindowW :: #force_inline proc "system" ( - lpClassName: LPCTSTR, + lpClassName: LPCTSTR, lpWindowName: LPCTSTR, - dwStyle: DWORD, - X: INT, - Y: INT, - nWidth: INT, - nHeight: INT, - hWndParent: HWND, - hMenu: HMENU, - hInstance: HINSTANCE, - lpParam: LPVOID, + dwStyle: DWORD, + X: INT, + Y: INT, + nWidth: INT, + nHeight: INT, + hWndParent: HWND, + hMenu: HMENU, + hInstance: HINSTANCE, + lpParam: LPVOID, ) -> HWND { return CreateWindowExW( 0, @@ -369,35 +394,52 @@ when ODIN_ARCH == .amd64 { SetWindowLongPtrW :: SetWindowLongW } +@(require_results) GET_SC_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> INT { return INT(wParam) & 0xFFF0 } +@(require_results) GET_WHEEL_DELTA_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> c_short { return cast(c_short)HIWORD(cast(DWORD)wParam) } +@(require_results) GET_KEYSTATE_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> WORD { return LOWORD(cast(DWORD)wParam) } +@(require_results) GET_NCHITTEST_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> c_short { return cast(c_short)LOWORD(cast(DWORD)wParam) } +@(require_results) GET_XBUTTON_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> WORD { return HIWORD(cast(DWORD)wParam) } // Retrieves the input code from wParam in WM_INPUT message. +@(require_results) GET_RAWINPUT_CODE_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> RAWINPUT_CODE { return RAWINPUT_CODE(wParam & 0xFF) } +@(require_results) MAKEINTRESOURCEW :: #force_inline proc "contextless" (#any_int i: int) -> LPWSTR { return cast(LPWSTR)uintptr(WORD(i)) } +@(require_results) +RAWINPUT_ALIGN :: proc "contextless" (x: uintptr) -> uintptr { + return (x + size_of(uintptr) - 1) & ~uintptr(size_of(uintptr) - 1) +} + +@(require_results) +NEXTRAWINPUTBLOCK :: proc "contextless" (ptr: ^RAWINPUT) -> ^RAWINPUT { + return cast(^RAWINPUT)RAWINPUT_ALIGN(uintptr(ptr) + uintptr(ptr.header.dwSize)) +} + Monitor_From_Flags :: enum DWORD { MONITOR_DEFAULTTONULL = 0x00000000, // Returns NULL MONITOR_DEFAULTTOPRIMARY = 0x00000001, // Returns a handle to the primary display monitor @@ -405,7 +447,7 @@ Monitor_From_Flags :: enum DWORD { } Monitor_Enum_Proc :: #type proc "system" (HMONITOR, HDC, LPRECT, LPARAM) -> BOOL -Window_Enum_Proc :: #type proc "system" (HWND, LPARAM) -> BOOL +Window_Enum_Proc :: #type proc "system" (HWND, LPARAM) -> BOOL USER_DEFAULT_SCREEN_DPI :: 96 DPI_AWARENESS_CONTEXT :: distinct HANDLE @@ -415,7 +457,7 @@ DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE :: DPI_AWARENESS_CONTEXT(~uintptr(2)) DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 :: DPI_AWARENESS_CONTEXT(~uintptr(3)) // -4 DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED :: DPI_AWARENESS_CONTEXT(~uintptr(4)) // -5 -RAWINPUT_CODE :: enum { +RAWINPUT_CODE :: enum DWORD { // The input is in the regular message flow, // the app is required to call DefWindowProc // so that the system can perform clean ups. @@ -426,16 +468,16 @@ RAWINPUT_CODE :: enum { } RAWINPUTHEADER :: struct { - dwType: DWORD, - dwSize: DWORD, + dwType: DWORD, + dwSize: DWORD, hDevice: HANDLE, - wParam: WPARAM, + wParam: WPARAM, } RAWHID :: struct { dwSizeHid: DWORD, - dwCount: DWORD, - bRawData: [1]BYTE, + dwCount: DWORD, + bRawData: [1]BYTE, } RAWMOUSE :: struct { @@ -447,27 +489,27 @@ RAWMOUSE :: struct { usButtonData: USHORT, }, }, - ulRawButtons: ULONG, - lLastX: LONG, - lLastY: LONG, + ulRawButtons: ULONG, + lLastX: LONG, + lLastY: LONG, ulExtraInformation: ULONG, } RAWKEYBOARD :: struct { - MakeCode: USHORT, - Flags: USHORT, - Rserved: USHORT, - VKey: USHORT, - Message: UINT, + MakeCode: USHORT, + Flags: USHORT, + Rserved: USHORT, + VKey: USHORT, + Message: UINT, ExtraInformation: ULONG, } RAWINPUT :: struct { header: RAWINPUTHEADER, data: struct #raw_union { - mouse: RAWMOUSE, + mouse: RAWMOUSE, keyboard: RAWKEYBOARD, - hid: RAWHID, + hid: RAWHID, }, } @@ -476,42 +518,42 @@ HRAWINPUT :: distinct LPARAM RAWINPUTDEVICE :: struct { usUsagePage: USHORT, - usUsage: USHORT, - dwFlags: DWORD, - hwndTarget: HWND, + usUsage: USHORT, + dwFlags: DWORD, + hwndTarget: HWND, } -PRAWINPUTDEVICE :: ^RAWINPUTDEVICE +PRAWINPUTDEVICE :: ^RAWINPUTDEVICE PCRAWINPUTDEVICE :: PRAWINPUTDEVICE RAWINPUTDEVICELIST :: struct { hDevice: HANDLE, - dwType: DWORD, + dwType: DWORD, } PRAWINPUTDEVICELIST :: ^RAWINPUTDEVICELIST RID_DEVICE_INFO_HID :: struct { - dwVendorId: DWORD, - dwProductId: DWORD, + dwVendorId: DWORD, + dwProductId: DWORD, dwVersionNumber: DWORD, - usUsagePage: USHORT, - usUsage: USHORT, + usUsagePage: USHORT, + usUsage: USHORT, } RID_DEVICE_INFO_KEYBOARD :: struct { - dwType: DWORD, - dwSubType: DWORD, - dwKeyboardMode: DWORD, + dwType: DWORD, + dwSubType: DWORD, + dwKeyboardMode: DWORD, dwNumberOfFunctionKeys: DWORD, - dwNumberOfIndicators: DWORD, - dwNumberOfKeysTotal: DWORD, + dwNumberOfIndicators: DWORD, + dwNumberOfKeysTotal: DWORD, } RID_DEVICE_INFO_MOUSE :: struct { - dwId: DWORD, - dwNumberOfButtons: DWORD, - dwSampleRate: DWORD, + dwId: DWORD, + dwNumberOfButtons: DWORD, + dwSampleRate: DWORD, fHasHorizontalWheel: BOOL, } @@ -519,103 +561,103 @@ RID_DEVICE_INFO :: struct { cbSize: DWORD, dwType: DWORD, using DUMMYUNIONNAME: struct #raw_union { - mouse: RID_DEVICE_INFO_MOUSE, - keyboard: RID_DEVICE_INFO_KEYBOARD, - hid: RID_DEVICE_INFO_HID, + mouse: RID_DEVICE_INFO_MOUSE `raw_union_tag:"dwType=0"`, + keyboard: RID_DEVICE_INFO_KEYBOARD `raw_union_tag:"dwType=1"`, + hid: RID_DEVICE_INFO_HID `raw_union_tag:"dwType=2"`, }, } -RIDEV_REMOVE :: 0x00000001 -RIDEV_EXCLUDE :: 0x00000010 -RIDEV_PAGEONLY :: 0x00000020 -RIDEV_NOLEGACY :: 0x00000030 -RIDEV_INPUTSINK :: 0x00000100 +RIDEV_REMOVE :: 0x00000001 +RIDEV_EXCLUDE :: 0x00000010 +RIDEV_PAGEONLY :: 0x00000020 +RIDEV_NOLEGACY :: 0x00000030 +RIDEV_INPUTSINK :: 0x00000100 RIDEV_CAPTUREMOUSE :: 0x00000200 -RIDEV_NOHOTKEYS :: 0x00000200 -RIDEV_APPKEYS :: 0x00000400 -RIDEV_EXINPUTSINK :: 0x00001000 -RIDEV_DEVNOTIFY :: 0x00002000 +RIDEV_NOHOTKEYS :: 0x00000200 +RIDEV_APPKEYS :: 0x00000400 +RIDEV_EXINPUTSINK :: 0x00001000 +RIDEV_DEVNOTIFY :: 0x00002000 RID_HEADER :: 0x10000005 -RID_INPUT :: 0x10000003 +RID_INPUT :: 0x10000003 RIDI_PREPARSEDDATA :: 0x20000005 -RIDI_DEVICENAME :: 0x20000007 -RIDI_DEVICEINFO :: 0x2000000b +RIDI_DEVICENAME :: 0x20000007 +RIDI_DEVICEINFO :: 0x2000000b -RIM_TYPEMOUSE :: 0 +RIM_TYPEMOUSE :: 0 RIM_TYPEKEYBOARD :: 1 -RIM_TYPEHID :: 2 +RIM_TYPEHID :: 2 -RI_KEY_MAKE :: 0 -RI_KEY_BREAK :: 1 -RI_KEY_E0 :: 2 -RI_KEY_E1 :: 4 +RI_KEY_MAKE :: 0 +RI_KEY_BREAK :: 1 +RI_KEY_E0 :: 2 +RI_KEY_E1 :: 4 RI_KEY_TERMSRV_SET_LED :: 8 -RI_KEY_TERMSRV_SHADOW :: 0x10 +RI_KEY_TERMSRV_SHADOW :: 0x10 -MOUSE_MOVE_RELATIVE :: 0x00 -MOUSE_MOVE_ABSOLUTE :: 0x01 -MOUSE_VIRTUAL_DESKTOP :: 0x02 +MOUSE_MOVE_RELATIVE :: 0x00 +MOUSE_MOVE_ABSOLUTE :: 0x01 +MOUSE_VIRTUAL_DESKTOP :: 0x02 MOUSE_ATTRIBUTES_CHANGED :: 0x04 -MOUSE_MOVE_NOCOALESCE :: 0x08 +MOUSE_MOVE_NOCOALESCE :: 0x08 -RI_MOUSE_BUTTON_1_DOWN :: 0x0001 -RI_MOUSE_LEFT_BUTTON_DOWN :: RI_MOUSE_BUTTON_1_DOWN -RI_MOUSE_BUTTON_1_UP :: 0x0002 -RI_MOUSE_LEFT_BUTTON_UP :: RI_MOUSE_BUTTON_1_UP -RI_MOUSE_BUTTON_2_DOWN :: 0x0004 -RI_MOUSE_RIGHT_BUTTON_DOWN :: RI_MOUSE_BUTTON_2_DOWN -RI_MOUSE_BUTTON_2_UP :: 0x0008 -RI_MOUSE_RIGHT_BUTTON_UP :: RI_MOUSE_BUTTON_2_UP -RI_MOUSE_BUTTON_3_DOWN :: 0x0010 +RI_MOUSE_BUTTON_1_DOWN :: 0x0001 +RI_MOUSE_LEFT_BUTTON_DOWN :: RI_MOUSE_BUTTON_1_DOWN +RI_MOUSE_BUTTON_1_UP :: 0x0002 +RI_MOUSE_LEFT_BUTTON_UP :: RI_MOUSE_BUTTON_1_UP +RI_MOUSE_BUTTON_2_DOWN :: 0x0004 +RI_MOUSE_RIGHT_BUTTON_DOWN :: RI_MOUSE_BUTTON_2_DOWN +RI_MOUSE_BUTTON_2_UP :: 0x0008 +RI_MOUSE_RIGHT_BUTTON_UP :: RI_MOUSE_BUTTON_2_UP +RI_MOUSE_BUTTON_3_DOWN :: 0x0010 RI_MOUSE_MIDDLE_BUTTON_DOWN :: RI_MOUSE_BUTTON_3_DOWN -RI_MOUSE_BUTTON_3_UP :: 0x0020 -RI_MOUSE_MIDDLE_BUTTON_UP :: RI_MOUSE_BUTTON_3_UP -RI_MOUSE_BUTTON_4_DOWN :: 0x0040 -RI_MOUSE_BUTTON_4_UP :: 0x0080 -RI_MOUSE_BUTTON_5_DOWN :: 0x0100 -RI_MOUSE_BUTTON_5_UP :: 0x0200 -RI_MOUSE_WHEEL :: 0x0400 -RI_MOUSE_HWHEEL :: 0x0800 +RI_MOUSE_BUTTON_3_UP :: 0x0020 +RI_MOUSE_MIDDLE_BUTTON_UP :: RI_MOUSE_BUTTON_3_UP +RI_MOUSE_BUTTON_4_DOWN :: 0x0040 +RI_MOUSE_BUTTON_4_UP :: 0x0080 +RI_MOUSE_BUTTON_5_DOWN :: 0x0100 +RI_MOUSE_BUTTON_5_UP :: 0x0200 +RI_MOUSE_WHEEL :: 0x0400 +RI_MOUSE_HWHEEL :: 0x0800 WINDOWPLACEMENT :: struct { - length: UINT, - flags: UINT, - showCmd: UINT, - ptMinPosition: POINT, - ptMaxPosition: POINT, + length: UINT, + flags: UINT, + showCmd: UINT, + ptMinPosition: POINT, + ptMaxPosition: POINT, rcNormalPosition: RECT, } WINDOWINFO :: struct { - cbSize: DWORD, - rcWindow: RECT, - rcClient: RECT, - dwStyle: DWORD, - dwExStyle: DWORD, - dwWindowStatus: DWORD, + cbSize: DWORD, + rcWindow: RECT, + rcClient: RECT, + dwStyle: DWORD, + dwExStyle: DWORD, + dwWindowStatus: DWORD, cxWindowBorders: UINT, cyWindowBorders: UINT, - atomWindowType: ATOM, + atomWindowType: ATOM, wCreatorVersion: WORD, } PWINDOWINFO :: ^WINDOWINFO CURSORINFO :: struct { - cbSize: DWORD, - flags: DWORD, - hCursor: HCURSOR, + cbSize: DWORD, + flags: DWORD, + hCursor: HCURSOR, ptScreenPos: POINT, } PCURSORINFO :: ^CURSORINFO DRAWTEXTPARAMS :: struct { - cbSize: UINT, - iTabLength: INT, - iLeftMargin: INT, - iRightMargin: INT, + cbSize: UINT, + iTabLength: INT, + iLeftMargin: INT, + iRightMargin: INT, uiLengthDrawn: UINT, } PDRAWTEXTPARAMS :: ^DRAWTEXTPARAMS @@ -673,12 +715,12 @@ GetUserObjectInformationFlags :: enum INT { } USEROBJECTFLAGS :: struct { - fInherit: BOOL, + fInherit: BOOL, fReserved: BOOL, - dwFlags: DWORD, + dwFlags: DWORD, } -PROPENUMPROCW :: #type proc(unnamedParam1: HWND, unnamedParam2: LPCWSTR, unnamedParam3: HANDLE) -> BOOL +PROPENUMPROCW :: #type proc(unnamedParam1: HWND, unnamedParam2: LPCWSTR, unnamedParam3: HANDLE) -> BOOL PROPENUMPROCEXW :: #type proc(unnamedParam1: HWND, unnamedParam2: LPCWSTR, unnamedParam3: HANDLE, unnamedParam4: ULONG_PTR) -> BOOL RT_CURSOR :: LPWSTR(uintptr(0x00000001)) @@ -713,8 +755,8 @@ MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID :: LPWSTR(uintptr(0x00000010) ACCEL :: struct { /* Also called the flags field */ fVirt: BYTE, - key: WORD, - cmd: WORD, + key: WORD, + cmd: WORD, } LPACCEL :: ^ACCEL @@ -730,32 +772,32 @@ MIIM_BITMAP :: 0x00000080 MIIM_FTYPE :: 0x00000100 MENUITEMINFOW :: struct { - cbSize: UINT, - fMask: UINT, - fType: UINT, // used if MIIM_TYPE (4.0) or MIIM_FTYPE (>4.0) - fState: UINT, // used if MIIM_STATE - wID: UINT, // used if MIIM_ID - hSubMenu: HMENU, // used if MIIM_SUBMENU - hbmpChecked: HBITMAP, // used if MIIM_CHECKMARKS + cbSize: UINT, + fMask: UINT, + fType: UINT, // used if MIIM_TYPE (4.0) or MIIM_FTYPE (>4.0) + fState: UINT, // used if MIIM_STATE + wID: UINT, // used if MIIM_ID + hSubMenu: HMENU, // used if MIIM_SUBMENU + hbmpChecked: HBITMAP, // used if MIIM_CHECKMARKS hbmpUnchecked: HBITMAP, // used if MIIM_CHECKMARKS - dwItemData: ULONG_PTR, // used if MIIM_DATA - dwTypeData: LPWSTR, // used if MIIM_TYPE (4.0) or MIIM_STRING (>4.0) - cch: UINT, // used if MIIM_TYPE (4.0) or MIIM_STRING (>4.0) - hbmpItem: HBITMAP, // used if MIIM_BITMAP + dwItemData: ULONG_PTR, // used if MIIM_DATA + dwTypeData: LPWSTR, // used if MIIM_TYPE (4.0) or MIIM_STRING (>4.0) + cch: UINT, // used if MIIM_TYPE (4.0) or MIIM_STRING (>4.0) + hbmpItem: HBITMAP, // used if MIIM_BITMAP } LPMENUITEMINFOW :: ^MENUITEMINFOW DISPLAY_DEVICEW :: struct { - cb: DWORD, - DeviceName: [32]WCHAR, + cb: DWORD, + DeviceName: [32]WCHAR, DeviceString: [128]WCHAR, - StateFlags: DWORD, - DeviceID: [128]WCHAR, - DeviceKey: [128]WCHAR, + StateFlags: DWORD, + DeviceID: [128]WCHAR, + DeviceKey: [128]WCHAR, } PDISPLAY_DEVICEW :: ^DISPLAY_DEVICEW // OUTOFCONTEXT is the zero value, use {} -WinEventFlags :: bit_set[WinEventFlag; DWORD] +WinEventFlags :: distinct bit_set[WinEventFlag; DWORD] WinEventFlag :: enum DWORD { SKIPOWNTHREAD = 0, @@ -792,7 +834,7 @@ CF_PRIVATEFIRST :: 0x0200 CF_PRIVATELAST :: 0x02FF STICKYKEYS :: struct { - cbSize: UINT, + cbSize: UINT, dwFlags: DWORD, } LPSTICKYKEYS :: ^STICKYKEYS @@ -822,7 +864,7 @@ SKF_LALTLATCHED :: 0x10000000 SKF_RALTLATCHED :: 0x20000000 TOGGLEKEYS :: struct { - cbSize: UINT, + cbSize: UINT, dwFlags: DWORD, } LPTOGGLEKEYS :: ^TOGGLEKEYS @@ -835,10 +877,10 @@ TKF_HOTKEYSOUND :: 0x10 TKF_INDICATOR :: 0x20 FILTERKEYS :: struct { - cbSize: UINT, - dwFlags: DWORD, - iWaitMSec: DWORD, - iDelayMSec: DWORD, + cbSize: UINT, + dwFlags: DWORD, + iWaitMSec: DWORD, + iDelayMSec: DWORD, iRepeatMSec: DWORD, iBounceMSec: DWORD, } @@ -853,24 +895,95 @@ FKF_INDICATOR :: 0x20 FKF_CLICKON :: 0x40 NONCLIENTMETRICSW :: struct { - cbSize: UINT, - iBorderWidth: i32, - iScrollWidth: i32, - iScrollHeight: i32, - iCaptionWidth: i32, - iCaptionHeight: i32, - lfCaptionFont: LOGFONTW, - iSmCaptionWidth: i32, - iSmCaptionHeight: i32, - lfSmCaptionFont: LOGFONTW, - iMenuWidth: i32, - iMenuHeight: i32, - lfMenuFont: LOGFONTW, - lfStatusFont: LOGFONTW, - lfMessageFont: LOGFONTW, - iPaddedBorderWidth: i32, + cbSize: UINT, + iBorderWidth: c_int, + iScrollWidth: c_int, + iScrollHeight: c_int, + iCaptionWidth: c_int, + iCaptionHeight: c_int, + lfCaptionFont: LOGFONTW, + iSmCaptionWidth: c_int, + iSmCaptionHeight: c_int, + lfSmCaptionFont: LOGFONTW, + iMenuWidth: c_int, + iMenuHeight: c_int, + lfMenuFont: LOGFONTW, + lfStatusFont: LOGFONTW, + lfMessageFont: LOGFONTW, + iPaddedBorderWidth: c_int, } LPNONCLIENTMETRICSW :: ^NONCLIENTMETRICSW LWA_COLORKEY :: 0x1 LWA_ALPHA :: 0x2 + +SCROLLINFO :: struct { + cbSize: UINT, + fMask: UINT, + nMin: c_int, + nMax: c_int, + nPage: UINT, + nPos: c_int, + nTrackPos: c_int, +} +LPSCROLLINFO :: ^SCROLLINFO + +// Scroll Bar Constants +SB_MIN :: 0 +SB_HORZ :: 0 +SB_VERT :: 1 +SB_CTL :: 2 +SB_BOTH :: 3 + +// Scroll Bar Commands +SB_LINEUP :: 0 +SB_LINELEFT :: 0 +SB_LINEDOWN :: 1 +SB_LINERIGHT :: 1 +SB_PAGEUP :: 2 +SB_PAGELEFT :: 2 +SB_PAGEDOWN :: 3 +SB_PAGERIGHT :: 3 +SB_THUMBPOSITION :: 4 +SB_THUMBTRACK :: 5 +SB_TOP :: 6 +SB_LEFT :: 6 +SB_BOTTOM :: 7 +SB_RIGHT :: 7 +SB_ENDSCROLL :: 8 + +// Constants for SCROLLINFO.fMask +SIF_RANGE :: 0x0001 +SIF_PAGE :: 0x0002 +SIF_POS :: 0x0004 +SIF_DISABLENOSCROLL :: 0x0008 +SIF_TRACKPOS :: 0x0010 +SIF_ALL :: (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS) + +// EnableScrollBar() flags +ESB_ENABLE_BOTH :: 0x0000 +ESB_DISABLE_BOTH :: 0x0003 +ESB_DISABLE_LEFT :: 0x0001 +ESB_DISABLE_RIGHT :: 0x0002 +ESB_DISABLE_UP :: 0x0001 +ESB_DISABLE_DOWN :: 0x0002 +ESB_DISABLE_LTUP :: ESB_DISABLE_LEFT +ESB_DISABLE_RTDN :: ESB_DISABLE_RIGHT + +// Command constants for GetWindow +GW_HWNDFIRST :: 0 +GW_HWNDLAST :: 1 +GW_HWNDNEXT :: 2 +GW_HWNDPREV :: 3 +GW_OWNER :: 4 +GW_CHILD :: 5 +GW_ENABLEDPOPUP :: 6 +GW_MAX :: 6 + +COPYDATASTRUCT :: struct { + dwData: ULONG_PTR, + cbData: DWORD, + lpData: PVOID, +} + +PCOPYDATASTRUCT :: ^COPYDATASTRUCT diff --git a/core/sys/windows/userenv.odin b/core/sys/windows/userenv.odin index 2a2209d2c..1ed731407 100644 --- a/core/sys/windows/userenv.odin +++ b/core/sys/windows/userenv.odin @@ -5,19 +5,22 @@ foreign import userenv "system:Userenv.lib" @(default_calling_convention="system") foreign userenv { - GetUserProfileDirectoryW :: proc(hToken: HANDLE, - lpProfileDir: LPWSTR, - lpcchSize: ^DWORD) -> BOOL --- + GetUserProfileDirectoryW :: proc( + hToken: HANDLE, + lpProfileDir: LPWSTR, + lpcchSize: ^DWORD, + ) -> BOOL --- + LoadUserProfileW :: proc( - hToken: HANDLE, + hToken: HANDLE, lpProfileInfo: ^PROFILEINFOW, ) -> BOOL --- // https://docs.microsoft.com/en-us/windows/win32/api/userenv/nf-userenv-createprofile // The caller must have administrator privileges to call this function. CreateProfile :: proc( - pszUserSid: LPCWSTR, - pszUserName: LPCWSTR, + pszUserSid: LPCWSTR, + pszUserName: LPCWSTR, pszProfilePath: wstring, cchProfilePath: DWORD, ) -> u32 --- @@ -25,15 +28,15 @@ foreign userenv { // https://docs.microsoft.com/en-us/windows/win32/api/userenv/nf-userenv-deleteprofilew // The caller must have administrative privileges to delete a user's profile. DeleteProfileW :: proc( - lpSidString: LPCWSTR, - lpProfilePath: LPCWSTR, + lpSidString: LPCWSTR, + lpProfilePath: LPCWSTR, lpComputerName: LPCWSTR, ) -> BOOL --- // https://docs.microsoft.com/en-us/windows/win32/api/sddl/nf-sddl-convertsidtostringsida // To turn a SID into a string SID to use with CreateProfile & DeleteProfileW. ConvertSidToStringSidW :: proc( - Sid: ^SID, + Sid: ^SID, StringSid: ^LPCWSTR, ) -> BOOL --- } diff --git a/core/sys/windows/util.odin b/core/sys/windows/util.odin index 125038ac4..542d2718e 100644 --- a/core/sys/windows/util.odin +++ b/core/sys/windows/util.odin @@ -7,135 +7,236 @@ import "base:intrinsics" L :: intrinsics.constant_utf16_cstring // https://learn.microsoft.com/en-us/windows/win32/winmsg/makeword +@(require_results) MAKEWORD :: #force_inline proc "contextless" (#any_int a, b: int) -> WORD { return WORD(BYTE(DWORD_PTR(a) & 0xff)) | (WORD(BYTE(DWORD_PTR(b) & 0xff)) << 8) } // https://learn.microsoft.com/en-us/windows/win32/winmsg/makelong +@(require_results) MAKELONG :: #force_inline proc "contextless" (#any_int a, b: int) -> LONG { return LONG(WORD(DWORD_PTR(a) & 0xffff)) | (LONG(WORD(DWORD_PTR(b) & 0xffff)) << 16) } // https://learn.microsoft.com/en-us/windows/win32/winmsg/loword +@(require_results) LOWORD :: #force_inline proc "contextless" (#any_int x: int) -> WORD { return WORD(x & 0xffff) } // https://learn.microsoft.com/en-us/windows/win32/winmsg/hiword +@(require_results) HIWORD :: #force_inline proc "contextless" (#any_int x: int) -> WORD { return WORD(x >> 16) } // https://learn.microsoft.com/en-us/windows/win32/winmsg/lobyte +@(require_results) LOBYTE :: #force_inline proc "contextless" (w: WORD) -> BYTE { return BYTE((DWORD_PTR(w)) & 0xff) } // https://learn.microsoft.com/en-us/windows/win32/winmsg/hibyte +@(require_results) HIBYTE :: #force_inline proc "contextless" (w: WORD) -> BYTE { return BYTE(((DWORD_PTR(w)) >> 8) & 0xff) } // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-makewparam +@(require_results) MAKEWPARAM :: #force_inline proc "contextless" (#any_int l, h: int) -> WPARAM { return WPARAM(MAKELONG(l, h)) } // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-makelparam +@(require_results) MAKELPARAM :: #force_inline proc "contextless" (#any_int l, h: int) -> LPARAM { return LPARAM(MAKELONG(l, h)) } // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-makelresult +@(require_results) MAKELRESULT :: #force_inline proc "contextless" (#any_int l, h: int) -> LRESULT { return LRESULT(MAKELONG(l, h)) } // https://learn.microsoft.com/en-us/windows/win32/api/windowsx/nf-windowsx-get_x_lparam +@(require_results) GET_X_LPARAM :: #force_inline proc "contextless" (lp: LPARAM) -> c_int { return cast(c_int)cast(c_short)LOWORD(cast(DWORD)lp) } // https://learn.microsoft.com/en-us/windows/win32/api/windowsx/nf-windowsx-get_y_lparam +@(require_results) GET_Y_LPARAM :: #force_inline proc "contextless" (lp: LPARAM) -> c_int { return cast(c_int)cast(c_short)HIWORD(cast(DWORD)lp) } // https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-makelcid +@(require_results) MAKELCID :: #force_inline proc "contextless" (lgid, srtid: WORD) -> LCID { return (DWORD(WORD(srtid)) << 16) | DWORD(WORD(lgid)) } // https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-makelangid +@(require_results) MAKELANGID :: #force_inline proc "contextless" (p, s: WORD) -> DWORD { return DWORD(WORD(s)) << 10 | DWORD(WORD(p)) } +@(require_results) LANGIDFROMLCID :: #force_inline proc "contextless" (lcid: LCID) -> LANGID { return LANGID(lcid) } +@(require_results) utf8_to_utf16_alloc :: proc(s: string, allocator := context.temp_allocator) -> []u16 { - if len(s) < 1 { + s_length := len(s) + if s_length < 1 { + return nil + } + if s_length > cast(int)max(c_int) { + // Unsupported (input string is excessively long). return nil } b := transmute([]byte)s cstr := raw_data(b) - n := MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, cstr, i32(len(s)), nil, 0) - if n == 0 { + n := MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, cstr, c_int(s_length), nil, 0) + if n <= 0 || cast(int)n >= max(int) { + // If n is equal to or greater than max(int), then we will not be able + // to create a big enough slice with the null terminator. + // NOTE: This only affects 32-bit systems and is purely pedantic because + // the system will never be able to allocate that much memory. return nil } - text := make([]u16, n+1, allocator) + text := make([]u16, cast(int)n + 1, allocator) + if text == nil { + return nil + } - n1 := MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, cstr, i32(len(s)), raw_data(text), n) - if n1 == 0 { + n1 := MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, cstr, c_int(s_length), raw_data(text), n) + if n1 <= 0 { delete(text, allocator) return nil } + // null-terminate the result here, even though the null element is not + // part of the slice. This is done to prevent callers which relied on + // this behavior, and is also expected by utf8_to_wstring_alloc. text[n] = 0 - for n >= 1 && text[n-1] == 0 { - n -= 1 - } return text[:n] } +@(require_results) utf8_to_utf16_buf :: proc(buf: []u16, s: string) -> []u16 { - n1 := MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, raw_data(s), i32(len(s)), nil, 0) - if n1 == 0 { + buf_length := len(buf) + if buf_length < 1 { return nil - } else if int(n1) > len(buf) { + } + s_length := len(s) + if s_length == 0 { + return nil + } + if s_length > cast(int)max(c_int) { + // Unsupported (input string is excessively long). + return nil + } + if buf_length > cast(int)max(c_int) { + buf_length = cast(int)max(c_int) + } + elements_written := MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, raw_data(s), c_int(s_length), raw_data(buf), cast(c_int)buf_length) + if elements_written <= 0 { + // Insufficient buffer size, empty input string, or invalid characters. Contents of the buffer may have been modified. return nil } - n1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, raw_data(s), i32(len(s)), raw_data(buf[:]), n1) - if n1 == 0 { - return nil - } else if int(n1) > len(buf) { + // To be consistent with utf8_to_utf16_alloc, the output string + // is null-terminated here in the buffer, even though the terminating null character + // is not part of the returned slice. + if buf_length <= cast(int)elements_written { + // The terminating null character does not fit. + // Need at least a length of (elements_written+1). return nil } - return buf[:n1] + buf[elements_written] = 0 + return buf[:elements_written] } + +// Converts a regular UTF-8 `string` to UTF-16. +// +// The conversion includes any null characters present in the input string. +// +// Returns `nil` on conversion failure. +// +// Conversion may fail due to an invalid byte sequence in the input string, +// or an insufficient buffer size (`utf8_to_utf16_buf` only), +// or allocation failure (`utf8_to_utf16_alloc` only). +// +// The result of converting an empty string is indistinguishable from conversion failure. utf8_to_utf16 :: proc{utf8_to_utf16_alloc, utf8_to_utf16_buf} +@(require_results) utf8_to_wstring_alloc :: proc(s: string, allocator := context.temp_allocator) -> wstring { - if res := utf8_to_utf16(s, allocator); len(res) > 0 { - return wstring(raw_data(res)) + if len(s) == 0 { + // Empty string. Needs special care because an empty string + // is different from conversion failure. + buf := make([]u16, 1, allocator) + if buf == nil { + return nil + } + buf[0] = 0 + return wstring(raw_data(buf)) + } + // utf8_to_utf16 null-terminates the result in the allocated memory block, + // however, the null character is not part of the returned slice (it is just beyond). + // The conversion to wstring will bypass this implicit overrun. + res := utf8_to_utf16(s, allocator) + if len(res) > 0 { + return wstring(raw_data(res)) + } else { + // Conversion failure. + return nil } - return nil } +@(require_results) utf8_to_wstring_buf :: proc(buf: []u16, s: string) -> wstring { - if res := utf8_to_utf16(buf, s); len(res) > 0 { - return wstring(raw_data(res)) + buf_length := len(buf) + if buf_length == 0 { + // Insufficient buffer size, even for an empty string. + return nil + } + if len(s) == 0 { + // Empty string. Needs special care because an empty string + // is different from conversion failure. + buf[0] = 0 + return wstring(raw_data(buf)) + } + // utf8_to_utf16 null-terminates the result in the buffer, + // however, the null character is not part of the returned slice (it is just beyond). + // The conversion to wstring will bypass this implicit overrun. + res := utf8_to_utf16(buf[:], s) + if len(res) > 0 { + return wstring(raw_data(res)) + } else { + // Conversion failure. + return nil } - return nil } +// Converts a regular UTF-8 `string` to UTF-16, and returns the result as a +// null-terminated `wstring`, or `nil` on conversion failure. +// +// Conversion may fail due to an invalid byte sequence in the input string, +// or an insufficient buffer size (`utf8_to_wstring_buf` only), +// or allocation failure (`utf8_to_wstring_alloc` only). +// +// An empty string is valid, and results in a value distinct from `nil`. utf8_to_wstring :: proc{utf8_to_wstring_alloc, utf8_to_wstring_buf} +@(require_results) wstring_to_utf8_alloc :: proc(s: wstring, N: int, allocator := context.temp_allocator) -> (res: string, err: runtime.Allocator_Error) { context.allocator = allocator @@ -143,7 +244,7 @@ wstring_to_utf8_alloc :: proc(s: wstring, N: int, allocator := context.temp_allo return } - n := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N) if N > 0 else -1, nil, 0, nil, nil) + n := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, c_int(N) if N > 0 else -1, nil, 0, nil, nil) if n == 0 { return } @@ -155,7 +256,7 @@ wstring_to_utf8_alloc :: proc(s: wstring, N: int, allocator := context.temp_allo // will not be null terminated. text := make([]byte, n) or_return - n1 := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), raw_data(text), n, nil, nil) + n1 := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, c_int(N), raw_data(text), n, nil, nil) if n1 == 0 { delete(text, allocator) return @@ -170,15 +271,16 @@ wstring_to_utf8_alloc :: proc(s: wstring, N: int, allocator := context.temp_allo return string(text[:n]), nil } +@(require_results) wstring_to_utf8_buf :: proc(buf: []u8, s: wstring, N := -1) -> (res: string) { - n := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), nil, 0, nil, nil) + n := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, c_int(N), nil, 0, nil, nil) if n == 0 { return } else if int(n) > len(buf) { return } - n2 := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), raw_data(buf), n, nil, nil) + n2 := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, c_int(N), raw_data(buf), n, nil, nil) if n2 == 0 { return } else if int(n2) > len(buf) { @@ -211,6 +313,7 @@ Returns: - res: A cloned and converted string - err: An optional allocator error if one occured, `nil` otherwise */ +@(require_results) utf16_to_utf8_alloc :: proc(s: []u16, allocator := context.temp_allocator) -> (res: string, err: runtime.Allocator_Error) { if len(s) == 0 { return "", nil @@ -232,6 +335,7 @@ Inputs: Returns: - res: A converted string, backed byu `buf` */ +@(require_results) utf16_to_utf8_buf :: proc(buf: []u8, s: []u16) -> (res: string) { if len(s) == 0 { return @@ -244,8 +348,9 @@ utf16_to_utf8 :: proc{utf16_to_utf8_alloc, utf16_to_utf8_buf} // AdvAPI32, NetAPI32 and UserENV helpers. -allowed_username :: proc(username: string) -> bool { - contains_any :: proc(s, chars: string) -> bool { +@(require_results) +allowed_username :: proc "contextless" (username: string) -> bool { + contains_any :: proc "contextless" (s, chars: string) -> bool { if chars == "" { return false } @@ -287,8 +392,8 @@ allowed_username :: proc(username: string) -> bool { } // Returns .Success on success. +@(require_results) _add_user :: proc(servername: string, username: string, password: string) -> (ok: NET_API_STATUS) { - servername_w: wstring username_w: []u16 password_w: []u16 @@ -339,8 +444,8 @@ _add_user :: proc(servername: string, username: string, password: string) -> (ok return } +@(require_results) get_computer_name_and_account_sid :: proc(username: string) -> (computer_name: string, sid := SID{}, ok: bool) { - username_w := utf8_to_utf16(username, context.temp_allocator) cbsid: DWORD computer_name_size: DWORD @@ -381,8 +486,8 @@ get_computer_name_and_account_sid :: proc(username: string) -> (computer_name: s return } +@(require_results) get_sid :: proc(username: string, sid: ^SID) -> (ok: bool) { - username_w := utf8_to_utf16(username, context.temp_allocator) cbsid: DWORD computer_name_size: DWORD @@ -451,6 +556,7 @@ add_del_from_group :: proc(sid: ^SID, group: string) -> (ok: NET_API_STATUS) { return } +@(require_results) add_user_profile :: proc(username: string) -> (ok: bool, profile_path: string) { username_w := utf8_to_utf16(username, context.temp_allocator) diff --git a/core/sys/windows/ux_theme.odin b/core/sys/windows/ux_theme.odin index 679d9998f..e19800246 100644 --- a/core/sys/windows/ux_theme.odin +++ b/core/sys/windows/ux_theme.odin @@ -3,11 +3,73 @@ package sys_windows foreign import uxtheme "system:UxTheme.lib" -MARGINS :: distinct [4]i32 +MARGINS :: struct { + cxLeftWidth: c_int, + cxRightWidth: c_int, + cyTopHeight: c_int, + cyBottomHeight: c_int, +} PMARGINS :: ^MARGINS @(default_calling_convention="system") foreign uxtheme { - IsThemeActive :: proc() -> BOOL --- - SetWindowTheme :: proc(hWnd: HWND, pszSubAppName, pszSubIdList: LPCWSTR) -> HRESULT --- + IsThemeActive :: proc() -> BOOL --- + GetWindowTheme :: proc(hwnd: HWND) -> HTHEME --- + SetWindowTheme :: proc(hWnd: HWND, pszSubAppName, pszSubIdList: LPCWSTR) -> HRESULT --- + + // Buffered painting and buffered animation + BufferedPaintInit :: proc() -> HRESULT --- + BufferedPaintUnInit :: proc() -> HRESULT --- + + BeginBufferedPaint :: proc(hdcTarget: HDC, prcTarget: ^RECT, dwFormat: BP_BUFFERFORMAT, pPaintParams: ^BP_PAINTPARAMS, phdc: ^HDC) -> HPAINTBUFFER --- + EndBufferedPaint :: proc(hBufferedPaint: HPAINTBUFFER, fUpdateTarget: BOOL) -> HRESULT --- + + GetBufferedPaintTargetRect :: proc(hBufferedPaint: HPAINTBUFFER, prc: ^RECT) -> HRESULT --- + GetBufferedPaintTargetDC :: proc(hBufferedPaint: HPAINTBUFFER) -> HDC --- + GetBufferedPaintDC :: proc(hBufferedPaint: HPAINTBUFFER) -> HDC --- + GetBufferedPaintBits :: proc(hBufferedPaint, ppbBuffer: ^[^]RGBQUAD, pcxRow: ^c_int) -> HRESULT --- + + BufferedPaintClear :: proc(hBufferedPaint: HPAINTBUFFER, prc: ^RECT) -> HRESULT --- + BufferedPaintSetAlpha :: proc(hBufferedPaint: HPAINTBUFFER, prc: ^RECT, alpha: BYTE) -> HRESULT --- + + BufferedPaintStopAllAnimations :: proc(hwnd: HWND) -> HRESULT --- + BeginBufferedAnimation :: proc(hwnd: HWND, hdcTarget: HDC, prcTarget: ^RECT, dwFormat: BP_BUFFERFORMAT, pPaintParams: ^BP_PAINTPARAMS, pAnimationParams: ^BP_ANIMATIONPARAMS, phdcFrom: ^HDC, phdcTo: ^HDC) -> HANIMATIONBUFFER --- + BufferedPaintRenderAnimation :: proc(hwnd: HWND, hdcTarget: HDC) -> BOOL --- +} + +HTHEME :: distinct HANDLE +HPAINTBUFFER :: distinct HANDLE +HANIMATIONBUFFER :: distinct HANDLE + +BP_BUFFERFORMAT :: enum c_int { + BPBF_COMPATIBLEBITMAP, + BPBF_DIB, + BPBF_TOPDOWNDIB, + BPBF_TOPDOWNMONODIB, +} + +BP_ANIMATIONSTYLE :: enum c_int { + BPAS_NONE, + BPAS_LINEAR, + BPAS_CUBIC, + BPAS_SINE, +} + +// Constants for BP_PAINTPARAMS.dwFlags +BPPF_ERASE :: 0x0001 +BPPF_NOCLIP :: 0x0002 +BPPF_NONCLIENT :: 0x0004 + +BP_ANIMATIONPARAMS :: struct { + cbSize: DWORD, + dwFlags: DWORD, + style: BP_ANIMATIONSTYLE, + dwDuration: DWORD, +} + +BP_PAINTPARAMS :: struct { + cbSize: DWORD, + dwFlags: DWORD, + prcExclude: ^RECT, + pBlendFunction: ^BLENDFUNCTION, } diff --git a/core/sys/windows/wgl.odin b/core/sys/windows/wgl.odin index f50f06939..532a987eb 100644 --- a/core/sys/windows/wgl.odin +++ b/core/sys/windows/wgl.odin @@ -1,8 +1,6 @@ #+build windows package sys_windows -import "core:c" - foreign import "system:Opengl32.lib" CONTEXT_MAJOR_VERSION_ARB :: 0x2091 @@ -54,9 +52,9 @@ GLYPHMETRICSFLOAT :: struct { gmfCellIncY: f32, } -CreateContextAttribsARBType :: #type proc "c" (hdc: HDC, hShareContext: rawptr, attribList: [^]c.int) -> HGLRC -ChoosePixelFormatARBType :: #type proc "c" (hdc: HDC, attribIList: [^]c.int, attribFList: [^]f32, maxFormats: DWORD, formats: [^]c.int, numFormats: [^]DWORD) -> BOOL -SwapIntervalEXTType :: #type proc "c" (interval: c.int) -> bool +CreateContextAttribsARBType :: #type proc "c" (hdc: HDC, hShareContext: rawptr, attribList: [^]c_int) -> HGLRC +ChoosePixelFormatARBType :: #type proc "c" (hdc: HDC, attribIList: [^]c_int, attribFList: [^]f32, maxFormats: DWORD, formats: [^]c_int, numFormats: [^]DWORD) -> BOOL +SwapIntervalEXTType :: #type proc "c" (interval: c_int) -> bool GetExtensionsStringARBType :: #type proc "c" (HDC) -> cstring // Procedures @@ -73,18 +71,18 @@ foreign Opengl32 { wglGetProcAddress :: proc(c_str: cstring) -> rawptr --- wglDeleteContext :: proc(HGLRC: HGLRC) -> BOOL --- wglCopyContext :: proc(src, dst: HGLRC, mask: UINT) -> BOOL --- - wglCreateLayerContext :: proc(hdc: HDC, layer_plane: c.int) -> HGLRC --- - wglDescribeLayerPlane :: proc(hdc: HDC, pixel_format, layer_plane: c.int, bytes: UINT, pd: LPLAYERPLANEDESCRIPTOR) -> BOOL --- + wglCreateLayerContext :: proc(hdc: HDC, layer_plane: c_int) -> HGLRC --- + wglDescribeLayerPlane :: proc(hdc: HDC, pixel_format, layer_plane: c_int, bytes: UINT, pd: LPLAYERPLANEDESCRIPTOR) -> BOOL --- wglGetCurrentContext :: proc() -> HGLRC --- wglGetCurrentDC :: proc() -> HDC --- - wglGetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: c.int, cr: ^COLORREF) -> c.int --- - wglRealizeLayerPalette :: proc(hdc: HDC, layer_plane: c.int, realize: BOOL) -> BOOL --- - wglSetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: c.int, cr: ^COLORREF) -> c.int --- + wglGetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: c_int, cr: ^COLORREF) -> c_int --- + wglRealizeLayerPalette :: proc(hdc: HDC, layer_plane: c_int, realize: BOOL) -> BOOL --- + wglSetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: c_int, cr: ^COLORREF) -> c_int --- wglShareLists :: proc(HGLRC1, HGLRC2: HGLRC) -> BOOL --- wglSwapLayerBuffers :: proc(hdc: HDC, planes: DWORD) -> BOOL --- wglUseFontBitmapsA :: proc(hdc: HDC, first, count, list_base: DWORD) -> BOOL --- wglUseFontBitmapsW :: proc(hdc: HDC, first, count, list_base: DWORD) -> BOOL --- - wglUseFontOutlines :: proc(hdc: HDC, first, count, list_base: DWORD, deviation, extrusion: f32, format: c.int, gmf: LPGLYPHMETRICSFLOAT) -> BOOL --- + wglUseFontOutlines :: proc(hdc: HDC, first, count, list_base: DWORD, deviation, extrusion: f32, format: c_int, gmf: LPGLYPHMETRICSFLOAT) -> BOOL --- } // Used by vendor:OpenGL @@ -93,7 +91,7 @@ gl_set_proc_address :: proc(p: rawptr, name: cstring) { func := wglGetProcAddress(name) switch uintptr(func) { case 0, 1, 2, 3, ~uintptr(0): - module := LoadLibraryW(L("opengl32.dll")) + module := LoadLibraryW("opengl32.dll") func = GetProcAddress(module, name) } (^rawptr)(p)^ = func diff --git a/core/sys/windows/winerror.odin b/core/sys/windows/winerror.odin index 23467761d..2807ca0f8 100644 --- a/core/sys/windows/winerror.odin +++ b/core/sys/windows/winerror.odin @@ -248,6 +248,13 @@ E_HANDLE :: 0x80070006 // Handle that is not valid E_OUTOFMEMORY :: 0x8007000E // Failed to allocate necessary memory E_INVALIDARG :: 0x80070057 // One or more arguments are not valid +SEC_E_INCOMPLETE_MESSAGE :: 0x80090318 + +SEC_I_INCOMPLETE_CREDENTIALS :: 0x00090320 +SEC_I_CONTINUE_NEEDED :: 0x00090312 +SEC_I_CONTEXT_EXPIRED :: 0x00090317 +SEC_I_RENEGOTIATE :: 0x00090321 + // Severity values SEVERITY :: enum DWORD { SUCCESS = 0, diff --git a/core/sys/windows/winmm.odin b/core/sys/windows/winmm.odin index b85548b85..d1848cb7b 100644 --- a/core/sys/windows/winmm.odin +++ b/core/sys/windows/winmm.odin @@ -12,28 +12,28 @@ foreign winmm { timeEndPeriod :: proc(uPeriod: UINT) -> MMRESULT --- timeGetTime :: proc() -> DWORD --- - waveOutGetNumDevs :: proc() -> UINT --- - waveOutGetDevCapsW :: proc(uDeviceID: UINT_PTR, pwoc: LPWAVEOUTCAPSW, cbwoc: UINT) -> MMRESULT --- - waveOutGetVolume :: proc(hwo: HWAVEOUT, pdwVolume: LPDWORD) -> MMRESULT --- - waveOutSetVolume :: proc(hwo: HWAVEOUT, dwVolume: DWORD) -> MMRESULT --- - waveOutGetErrorTextW :: proc(mmrError: MMRESULT, pszText: LPWSTR, cchText: UINT) -> MMRESULT --- - waveOutOpen :: proc(phwo: LPHWAVEOUT, uDeviceID: UINT, pwfx: LPCWAVEFORMATEX, dwCallback: DWORD_PTR, dwInstance: DWORD_PTR, fdwOpen: DWORD) -> MMRESULT --- - waveOutClose :: proc(hwo: HWAVEOUT) -> MMRESULT --- - waveOutPrepareHeader :: proc(hwo: HWAVEOUT, pwh: LPWAVEHDR, cbwh: UINT) -> MMRESULT --- + waveOutGetNumDevs :: proc() -> UINT --- + waveOutGetDevCapsW :: proc(uDeviceID: UINT_PTR, pwoc: LPWAVEOUTCAPSW, cbwoc: UINT) -> MMRESULT --- + waveOutGetVolume :: proc(hwo: HWAVEOUT, pdwVolume: LPDWORD) -> MMRESULT --- + waveOutSetVolume :: proc(hwo: HWAVEOUT, dwVolume: DWORD) -> MMRESULT --- + waveOutGetErrorTextW :: proc(mmrError: MMRESULT, pszText: LPWSTR, cchText: UINT) -> MMRESULT --- + waveOutOpen :: proc(phwo: LPHWAVEOUT, uDeviceID: UINT, pwfx: LPCWAVEFORMATEX, dwCallback: DWORD_PTR, dwInstance: DWORD_PTR, fdwOpen: DWORD) -> MMRESULT --- + waveOutClose :: proc(hwo: HWAVEOUT) -> MMRESULT --- + waveOutPrepareHeader :: proc(hwo: HWAVEOUT, pwh: LPWAVEHDR, cbwh: UINT) -> MMRESULT --- waveOutUnprepareHeader :: proc(hwo: HWAVEOUT, pwh: LPWAVEHDR, cbwh: UINT) -> MMRESULT --- - waveOutWrite :: proc(hwo: HWAVEOUT, pwh: LPWAVEHDR, cbwh: UINT) -> MMRESULT --- - waveOutPause :: proc(hwo: HWAVEOUT) -> MMRESULT --- - waveOutRestart :: proc(hwo: HWAVEOUT) -> MMRESULT --- - waveOutReset :: proc(hwo: HWAVEOUT) -> MMRESULT --- - waveOutBreakLoop :: proc(hwo: HWAVEOUT) -> MMRESULT --- - waveOutGetPosition :: proc(hwo: HWAVEOUT, pmmt: LPMMTIME, cbmmt: UINT) -> MMRESULT --- - waveOutGetPitch :: proc(hwo: HWAVEOUT, pdwPitch: LPDWORD) -> MMRESULT --- - waveOutSetPitch :: proc(hwo: HWAVEOUT, pdwPitch: DWORD) -> MMRESULT --- + waveOutWrite :: proc(hwo: HWAVEOUT, pwh: LPWAVEHDR, cbwh: UINT) -> MMRESULT --- + waveOutPause :: proc(hwo: HWAVEOUT) -> MMRESULT --- + waveOutRestart :: proc(hwo: HWAVEOUT) -> MMRESULT --- + waveOutReset :: proc(hwo: HWAVEOUT) -> MMRESULT --- + waveOutBreakLoop :: proc(hwo: HWAVEOUT) -> MMRESULT --- + waveOutGetPosition :: proc(hwo: HWAVEOUT, pmmt: LPMMTIME, cbmmt: UINT) -> MMRESULT --- + waveOutGetPitch :: proc(hwo: HWAVEOUT, pdwPitch: LPDWORD) -> MMRESULT --- + waveOutSetPitch :: proc(hwo: HWAVEOUT, pdwPitch: DWORD) -> MMRESULT --- waveOutGetPlaybackRate :: proc(hwo: HWAVEOUT, pdwRate: LPDWORD) -> MMRESULT --- waveOutSetPlaybackRate :: proc(hwo: HWAVEOUT, pdwRate: DWORD) -> MMRESULT --- - waveOutGetID :: proc(hwo: HWAVEOUT, puDeviceID: LPUINT) -> MMRESULT --- + waveOutGetID :: proc(hwo: HWAVEOUT, puDeviceID: LPUINT) -> MMRESULT --- - waveInGetNumDevs :: proc() -> UINT --- + waveInGetNumDevs :: proc() -> UINT --- waveInGetDevCapsW :: proc(uDeviceID: UINT_PTR, pwic: LPWAVEINCAPSW, cbwic: UINT) -> MMRESULT --- PlaySoundW :: proc(pszSound: LPCWSTR, hmod: HMODULE, fdwSound: DWORD) -> BOOL --- @@ -272,10 +272,10 @@ LPHWAVEOUT :: ^HWAVEOUT MMTIME :: struct { wType: MMTIME_TYPE, u: struct #raw_union { - ms: DWORD, - sample: DWORD, - cb: DWORD, - ticks: DWORD, + ms: DWORD `raw_union_tag:"wType=TIME_MS"`, + sample: DWORD `raw_union_tag:"wType=TIME_SAMPLES"`, + cb: DWORD `raw_union_tag:"wType=TIME_BYTES"`, + ticks: DWORD `raw_union_tag:"wType=TIME_TICKS"`, smpte: struct { hour: BYTE, min: BYTE, @@ -284,10 +284,10 @@ MMTIME :: struct { fps: BYTE, dummy: BYTE, pad: [2]BYTE, - }, + } `raw_union_tag:"wType=TIME_SMPTE"`, midi: struct { songptrpos: DWORD, - }, + } `raw_union_tag:"wType=TIME_MIDI"`, }, } LPMMTIME :: ^MMTIME @@ -307,12 +307,13 @@ MMTIME_TYPE :: enum UINT { TIME_TICKS = 0x0020, } -MAXPNAMELEN :: 32 +MAXPNAMELEN :: 32 MAXERRORLENGTH :: 256 -MMVERSION :: UINT +MMVERSION :: UINT // Input is four characters string // Output is little-endian u32 representation +@(require_results) MAKEFOURCC :: #force_inline proc "contextless" (s: [4]byte) -> DWORD { return (DWORD(s[0])) | (DWORD(s[1]) << 8) | (DWORD(s[2]) << 16) | (DWORD(s[3]) << 24 ) } diff --git a/core/sys/windows/winnls.odin b/core/sys/windows/winnls.odin index ffb2638d5..9c2c219ef 100644 --- a/core/sys/windows/winnls.odin +++ b/core/sys/windows/winnls.odin @@ -5,8 +5,8 @@ LCTYPE :: distinct DWORD LOCALE_NAME_MAX_LENGTH :: 85 LOCALE_NAME_USER_DEFAULT :: 0 -LOCALE_NAME_INVARIANT : wstring = L("") -LOCALE_NAME_SYSTEM_DEFAULT : wstring = L("!x-sys-default-locale") +LOCALE_NAME_INVARIANT : wstring = "" +LOCALE_NAME_SYSTEM_DEFAULT : wstring = "!x-sys-default-locale" // String Length Maximums. // 5 ranges, 2 bytes ea., 0 term. @@ -16,16 +16,16 @@ MAX_DEFAULTCHAR :: 2 CPINFOEXW :: struct{ // Maximum length, in bytes, of a character in the code page. - MaxCharSize: UINT, + MaxCharSize: UINT, // The default is usually the "?" character for the code page. - DefaultChar: [MAX_DEFAULTCHAR]BYTE, + DefaultChar: [MAX_DEFAULTCHAR]BYTE, // A fixed-length array of lead byte ranges, for which the number of lead byte ranges is variable. - LeadByte: [MAX_LEADBYTES]BYTE, + LeadByte: [MAX_LEADBYTES]BYTE, // The default is usually the "?" character or the katakana middle dot character. UnicodeDefaultChar: WCHAR, // Code page value. This value reflects the code page passed to the GetCPInfoEx function. - CodePage: CODEPAGE, + CodePage: CODEPAGE, // Full name of the code page. - CodePageName: [MAX_PATH]WCHAR, + CodePageName: [MAX_PATH]WCHAR, } LPCPINFOEXW :: ^CPINFOEXW diff --git a/core/sys/windows/winver.odin b/core/sys/windows/winver.odin index 47751dab7..878080102 100644 --- a/core/sys/windows/winver.odin +++ b/core/sys/windows/winver.odin @@ -5,14 +5,14 @@ foreign import version "system:version.lib" @(default_calling_convention = "system") foreign version { - GetFileVersionInfoSizeW :: proc(lpwstrFilename: LPCWSTR, lpdwHandle: LPDWORD) -> DWORD --- - GetFileVersionInfoW :: proc(lptstrFilename: LPCWSTR, dwHandle: DWORD, dwLen: DWORD, lpData: LPVOID) -> BOOL --- + GetFileVersionInfoSizeW :: proc(lpwstrFilename: LPCWSTR, lpdwHandle: LPDWORD) -> DWORD --- + GetFileVersionInfoW :: proc(lptstrFilename: LPCWSTR, dwHandle: DWORD, dwLen: DWORD, lpData: LPVOID) -> BOOL --- GetFileVersionInfoSizeExW :: proc(dwFlags: FILE_VER_GET_FLAGS, lpwstrFilename: LPCWSTR, lpdwHandle: LPDWORD) -> DWORD --- - GetFileVersionInfoExW :: proc(dwFlags: FILE_VER_GET_FLAGS, lpwstrFilename: LPCWSTR, dwHandle, dwLen: DWORD, lpData: LPVOID) -> DWORD --- + GetFileVersionInfoExW :: proc(dwFlags: FILE_VER_GET_FLAGS, lpwstrFilename: LPCWSTR, dwHandle, dwLen: DWORD, lpData: LPVOID) -> DWORD --- - VerLanguageNameW :: proc(wLang: DWORD, szLang: LPWSTR, cchLang: DWORD) -> DWORD --- - VerQueryValueW :: proc(pBlock: LPCVOID, lpSubBlock: LPCWSTR, lplpBuffer: ^LPVOID, puLen: PUINT) -> BOOL --- + VerLanguageNameW :: proc(wLang: DWORD, szLang: LPWSTR, cchLang: DWORD) -> DWORD --- + VerQueryValueW :: proc(pBlock: LPCVOID, lpSubBlock: LPCWSTR, lplpBuffer: ^LPVOID, puLen: PUINT) -> BOOL --- } FILE_VER_GET :: enum DWORD {LOCALISED, NEUTRAL, PREFETCHED} diff --git a/core/sys/windows/wow64_apiset.odin b/core/sys/windows/wow64_apiset.odin index 3d29b786e..cce0ab2cc 100644 --- a/core/sys/windows/wow64_apiset.odin +++ b/core/sys/windows/wow64_apiset.odin @@ -5,30 +5,30 @@ foreign import kernel32 "system:Kernel32.lib" @(default_calling_convention="system") foreign kernel32 { - GetSystemWow64Directory2W :: proc (lpBuffer: LPWSTR, uSize: UINT, ImageFileMachineTyp: WORD) -> UINT --- - GetSystemWow64DirectoryW :: proc (lpBuffer: LPWSTR, uSize: UINT) -> UINT --- - IsWow64GuestMachineSupported :: proc (WowGuestMachine: USHORT, MachineIsSupported: ^BOOL) -> HRESULT --- - IsWow64Process :: proc (hProcess: HANDLE, Wow64Process: PBOOL) -> BOOL --- - IsWow64Process2 :: proc (hProcess: HANDLE, pProcessMachine: ^USHORT, pNativeMachine: ^USHORT) -> BOOL --- - Wow64EnableWow64FsRedirection :: proc (Wow64FsEnableRedirection: BOOLEAN) -> BOOLEAN --- - Wow64DisableWow64FsRedirection :: proc (OldValue: ^PVOID) -> BOOL --- - Wow64RevertWow64FsRedirection :: proc (OlValue: PVOID) -> BOOL --- - Wow64GetThreadContext :: proc (hThread: HANDLE, lpContext: PWOW64_CONTEXT) -> BOOL --- - Wow64SetThreadContext :: proc(hThread: HANDLE, lpContext: ^WOW64_CONTEXT) -> BOOL --- + GetSystemWow64Directory2W :: proc(lpBuffer: LPWSTR, uSize: UINT, ImageFileMachineTyp: WORD) -> UINT --- + GetSystemWow64DirectoryW :: proc(lpBuffer: LPWSTR, uSize: UINT) -> UINT --- + IsWow64GuestMachineSupported :: proc(WowGuestMachine: USHORT, MachineIsSupported: ^BOOL) -> HRESULT --- + IsWow64Process :: proc(hProcess: HANDLE, Wow64Process: PBOOL) -> BOOL --- + IsWow64Process2 :: proc(hProcess: HANDLE, pProcessMachine: ^USHORT, pNativeMachine: ^USHORT) -> BOOL --- + Wow64EnableWow64FsRedirection :: proc(Wow64FsEnableRedirection: BOOLEAN) -> BOOLEAN --- + Wow64DisableWow64FsRedirection :: proc(OldValue: ^PVOID) -> BOOL --- + Wow64RevertWow64FsRedirection :: proc(OlValue: PVOID) -> BOOL --- + Wow64GetThreadContext :: proc(hThread: HANDLE, lpContext: PWOW64_CONTEXT) -> BOOL --- + Wow64SetThreadContext :: proc(hThread: HANDLE, lpContext: ^WOW64_CONTEXT) -> BOOL --- Wow64SetThreadDefaultGuestMachine :: proc(Machine: USHORT) -> USHORT --- - Wow64SuspendThread :: proc (hThread: HANDLE) -> DWORD --- + Wow64SuspendThread :: proc(hThread: HANDLE) -> DWORD --- } WOW64_CONTEXT_i386 :: 0x00010000 -WOW64_CONTEXT_CONTROL :: (WOW64_CONTEXT_i386 | 0x00000001) -WOW64_CONTEXT_INTEGER :: (WOW64_CONTEXT_i386 | 0x00000002) +WOW64_CONTEXT_CONTROL :: (WOW64_CONTEXT_i386 | 0x00000001) +WOW64_CONTEXT_INTEGER :: (WOW64_CONTEXT_i386 | 0x00000002) WOW64_CONTEXT_SEGMENTS :: (WOW64_CONTEXT_i386 | 0x00000004) -WOW64_CONTEXT_FLOATING_POINT :: (WOW64_CONTEXT_i386 | 0x00000008) -WOW64_CONTEXT_DEBUG_REGISTERS :: (WOW64_CONTEXT_i386 | 0x00000010) +WOW64_CONTEXT_FLOATING_POINT :: (WOW64_CONTEXT_i386 | 0x00000008) +WOW64_CONTEXT_DEBUG_REGISTERS :: (WOW64_CONTEXT_i386 | 0x00000010) WOW64_CONTEXT_EXTENDED_REGISTERS :: (WOW64_CONTEXT_i386 | 0x00000020) -WOW64_CONTEXT_FULL :: (WOW64_CONTEXT_CONTROL | WOW64_CONTEXT_INTEGER | WOW64_CONTEXT_SEGMENTS) +WOW64_CONTEXT_FULL :: (WOW64_CONTEXT_CONTROL | WOW64_CONTEXT_INTEGER | WOW64_CONTEXT_SEGMENTS) WOW64_CONTEXT_ALL :: ( WOW64_CONTEXT_CONTROL | WOW64_CONTEXT_INTEGER | @@ -41,45 +41,45 @@ WOW64_SIZE_OF_80387_REGISTERS :: 80 WOW64_MAXIMUM_SUPPORTED_EXTENSION :: 512 WOW64_CONTEXT :: struct { - ContextFlags: DWORD, - Dr0: DWORD, - Dr1: DWORD, - Dr2: DWORD, - Dr3: DWORD, - Dr6: DWORD, - Dr7: DWORD, - FloatSave: WOW64_FLOATING_SAVE_AREA, - SegGs: DWORD, - SegFs: DWORD, - SegEs: DWORD, - SegDs: DWORD, - Edi: DWORD, - Esi: DWORD, - Ebx: DWORD, - Edx: DWORD, - Ecx: DWORD, - Eax: DWORD, - Ebp: DWORD, - Eip: DWORD, - SegCs: DWORD, - EFlags: DWORD, - Esp: DWORD, - SegSs: DWORD, + ContextFlags: DWORD, + Dr0: DWORD, + Dr1: DWORD, + Dr2: DWORD, + Dr3: DWORD, + Dr6: DWORD, + Dr7: DWORD, + FloatSave: WOW64_FLOATING_SAVE_AREA, + SegGs: DWORD, + SegFs: DWORD, + SegEs: DWORD, + SegDs: DWORD, + Edi: DWORD, + Esi: DWORD, + Ebx: DWORD, + Edx: DWORD, + Ecx: DWORD, + Eax: DWORD, + Ebp: DWORD, + Eip: DWORD, + SegCs: DWORD, + EFlags: DWORD, + Esp: DWORD, + SegSs: DWORD, ExtendedRegisters: [WOW64_MAXIMUM_SUPPORTED_EXTENSION]BYTE, } PWOW64_CONTEXT :: ^WOW64_CONTEXT WOW64_FLOATING_SAVE_AREA :: struct { - ControlWord: DWORD, - StatusWord: DWORD, - TagWord: DWORD, - ErrorOffset: DWORD, + ControlWord: DWORD, + StatusWord: DWORD, + TagWord: DWORD, + ErrorOffset: DWORD, ErrorSelector: DWORD, - DataOffset: DWORD, - DataSelector: DWORD, - RegisterArea: [WOW64_SIZE_OF_80387_REGISTERS]BYTE, - Cr0NpxState: DWORD, + DataOffset: DWORD, + DataSelector: DWORD, + RegisterArea: [WOW64_SIZE_OF_80387_REGISTERS]BYTE, + Cr0NpxState: DWORD, } PWOW64_FLOATING_SAVE_AREA :: ^WOW64_FLOATING_SAVE_AREA \ No newline at end of file diff --git a/core/sys/windows/ws2_32.odin b/core/sys/windows/ws2_32.odin index ed2ad5e24..2221e37fa 100644 --- a/core/sys/windows/ws2_32.odin +++ b/core/sys/windows/ws2_32.odin @@ -35,11 +35,10 @@ WSANETWORKEVENTS :: struct { iErrorCode: [FD_MAX_EVENTS]c_int, } -WSAEVENT :: HANDLE WSAID_ACCEPTEX :: GUID{0xb5367df1, 0xcbac, 0x11cf, {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} WSAID_GETACCEPTEXSOCKADDRS :: GUID{0xb5367df2, 0xcbac, 0x11cf, {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} -WSAID_CONNECTX :: GUID{0x25a207b9, 0xddf3, 0x4660, {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}} +WSAID_CONNECTEX :: GUID{0x25a207b9, 0xddf3, 0x4660, {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}} SIO_GET_EXTENSION_FUNCTION_POINTER :: IOC_INOUT | IOC_WS2 | 6 SIO_UDP_CONNRESET :: IOC_IN | IOC_VENDOR | 12 @@ -109,62 +108,62 @@ foreign ws2_32 { WSAPoll :: proc(fdArray: ^WSA_POLLFD, fds: c_ulong, timeout: c_int) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaduplicatesocketw) WSADuplicateSocketW :: proc( - s: SOCKET, - dwProcessId: DWORD, + s: SOCKET, + dwProcessId: DWORD, lpProtocolInfo: LPWSAPROTOCOL_INFO, ) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasend) WSASend :: proc( - s: SOCKET, - lpBuffers: LPWSABUF, - dwBufferCount: DWORD, + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, lpNumberOfBytesSent: LPDWORD, - dwFlags: DWORD, - lpOverlapped: LPWSAOVERLAPPED, + dwFlags: DWORD, + lpOverlapped: LPWSAOVERLAPPED, lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, ) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasendto) WSASendTo :: proc( - s: SOCKET, - lpBuffers: LPWSABUF, - dwBufferCount: DWORD, + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, lpNumberOfBytesSent: LPDWORD, - dwFlags: DWORD, - lpTo: ^SOCKADDR_STORAGE_LH, - iToLen: c_int, - lpOverlapped: LPWSAOVERLAPPED, + dwFlags: DWORD, + lpTo: ^sockaddr, + iToLen: c_int, + lpOverlapped: LPWSAOVERLAPPED, lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, ) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsarecv) WSARecv :: proc( - s: SOCKET, - lpBuffers: LPWSABUF, - dwBufferCount: DWORD, + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, lpNumberOfBytesRecvd: LPDWORD, - lpFlags: LPDWORD, - lpOverlapped: LPWSAOVERLAPPED, - lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + lpFlags: LPDWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, ) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsarecvfrom) WSARecvFrom :: proc( - s: SOCKET, - lpBuffers: LPWSABUF, - dwBufferCount: DWORD, + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, lpNumberOfBytesRecvd: LPDWORD, - lpFlags: LPDWORD, - lpFrom: ^SOCKADDR_STORAGE_LH, - lpFromlen: ^c_int, - lpOverlapped: LPWSAOVERLAPPED, - lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + lpFlags: LPDWORD, + lpFrom: ^sockaddr, + lpFromlen: LPINT, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, ) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasocketw) WSASocketW :: proc( - af: c_int, - kind: c_int, - protocol: c_int, + af: c_int, + kind: c_int, + protocol: c_int, lpProtocolInfo: LPWSAPROTOCOL_INFO, - g: GROUP, - dwFlags: DWORD, + g: GROUP, + dwFlags: DWORD, ) -> SOCKET --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaioctl) WSAIoctl :: proc(s: SOCKET, dwIoControlCode: DWORD, lpvInBuffer: rawptr, cbInBuffer: DWORD, lpvOutBuffer: rawptr, cbOutBuffer: DWORD, lpcbBytesReturned: ^DWORD, lpOverlapped: ^OVERLAPPED, lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> c_int --- @@ -182,8 +181,8 @@ foreign ws2_32 { WSAGetOverlappedResult :: proc(s: SOCKET, lpOverlapped: ^OVERLAPPED, lpcbTransfer: ^DWORD, fWait: BOOL, lpdwFlags: ^DWORD) -> BOOL --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket) socket :: proc( - af: c_int, - type: c_int, + af: c_int, + type: c_int, protocol: c_int, ) -> SOCKET --- @@ -197,20 +196,20 @@ foreign ws2_32 { send :: proc(socket: SOCKET, buf: rawptr, len: c_int, flags: c_int) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-recvfrom) recvfrom :: proc( - socket: SOCKET, - buf: rawptr, - len: c_int, - flags: c_int, - addr: ^SOCKADDR_STORAGE_LH, + socket: SOCKET, + buf: rawptr, + len: c_int, + flags: c_int, + addr: ^SOCKADDR_STORAGE_LH, addrlen: ^c_int, ) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto) sendto :: proc( - socket: SOCKET, - buf: rawptr, - len: c_int, - flags: c_int, - addr: ^SOCKADDR_STORAGE_LH, + socket: SOCKET, + buf: rawptr, + len: c_int, + flags: c_int, + addr: ^SOCKADDR_STORAGE_LH, addrlen: c_int, ) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-shutdown) @@ -220,16 +219,18 @@ foreign ws2_32 { // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt) setsockopt :: proc( - s: SOCKET, - level: c_int, + s: SOCKET, + level: c_int, optname: c_int, - optval: rawptr, - optlen: c_int, + optval: rawptr, + optlen: c_int, ) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockname) getsockname :: proc(socket: SOCKET, address: ^SOCKADDR_STORAGE_LH, address_len: ^c_int) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getpeername) getpeername :: proc(socket: SOCKET, address: ^SOCKADDR_STORAGE_LH, address_len: ^c_int) -> c_int --- + // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-gethostname) + gethostname :: proc(name: [^]c_char, namelen: c_int) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-bind) bind :: proc(socket: SOCKET, address: ^SOCKADDR_STORAGE_LH, address_len: socklen_t) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-listen) @@ -238,10 +239,10 @@ foreign ws2_32 { connect :: proc(socket: SOCKET, address: ^SOCKADDR_STORAGE_LH, len: c_int) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo) getaddrinfo :: proc( - node: cstring, + node: cstring, service: cstring, - hints: ^ADDRINFOA, - res: ^^ADDRINFOA, + hints: ^ADDRINFOA, + res: ^^ADDRINFOA, ) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-freeaddrinfo) freeaddrinfo :: proc(res: ^ADDRINFOA) --- @@ -261,19 +262,19 @@ foreign ws2_32 { lpHandle: LPHANDLE) -> INT --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-select) select :: proc( - nfds: c_int, - readfds: ^fd_set, - writefds: ^fd_set, - exceptfds: ^fd_set, - timeout: ^timeval, + nfds: c_int, + readfds: [^]fd_set, + writefds: [^]fd_set, + exceptfds: [^]fd_set, + timeout: ^timeval, ) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt) getsockopt :: proc( - s: SOCKET, - level: c_int, + s: SOCKET, + level: c_int, optname: c_int, - optval: ^c_char, - optlen: ^c_int, + optval: [^]c_char, + optlen: ^c_int, ) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-ntohl) ntohl :: proc(netlong: c_ulong) -> c_ulong --- diff --git a/core/sys/windows/xinput.odin b/core/sys/windows/xinput.odin index 0089f88cb..f8fd45bc9 100644 --- a/core/sys/windows/xinput.odin +++ b/core/sys/windows/xinput.odin @@ -57,9 +57,9 @@ XINPUT_GAMEPAD_BUTTON_BIT :: enum WORD { XINPUT_GAMEPAD_BUTTON :: distinct bit_set[XINPUT_GAMEPAD_BUTTON_BIT;WORD] // Gamepad thresholds -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE: SHORT : 7849 -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE: SHORT : 8689 -XINPUT_GAMEPAD_TRIGGER_THRESHOLD: SHORT : 30 +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE : SHORT : 7849 +XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE : SHORT : 8689 +XINPUT_GAMEPAD_TRIGGER_THRESHOLD : SHORT : 30 // Flags to pass to XInputGetCapabilities // Corresponds to log2(XINPUT_FLAG_...) @@ -199,12 +199,12 @@ XINPUT_KEYSTROKE :: struct { // XInput APIs @(default_calling_convention = "system") foreign xinput { - XInputGetState :: proc(user: XUSER, pState: ^XINPUT_STATE) -> System_Error --- - XInputSetState :: proc(user: XUSER, pVibration: ^XINPUT_VIBRATION) -> System_Error --- - XInputGetCapabilities :: proc(user: XUSER, dwFlags: XINPUT_FLAG, pCapabilities: ^XINPUT_CAPABILITIES) -> System_Error --- - XInputEnable :: proc(enable: BOOL) --- - XInputGetAudioDeviceIds :: proc(user: XUSER, pRenderDeviceId: LPWSTR, pRenderCount: ^UINT, pCaptureDeviceId: LPWSTR, pCaptureCount: ^UINT) -> System_Error --- - XInputGetBatteryInformation :: proc(user: XUSER, devType: BATTERY_DEVTYPE, pBatteryInformation: ^XINPUT_BATTERY_INFORMATION) -> System_Error --- - XInputGetKeystroke :: proc(user: XUSER, dwReserved: DWORD, pKeystroke: ^XINPUT_KEYSTROKE) -> System_Error --- + XInputGetState :: proc(user: XUSER, pState: ^XINPUT_STATE) -> System_Error --- + XInputSetState :: proc(user: XUSER, pVibration: ^XINPUT_VIBRATION) -> System_Error --- + XInputGetCapabilities :: proc(user: XUSER, dwFlags: XINPUT_FLAG, pCapabilities: ^XINPUT_CAPABILITIES) -> System_Error --- + XInputEnable :: proc(enable: BOOL) --- + XInputGetAudioDeviceIds :: proc(user: XUSER, pRenderDeviceId: LPWSTR, pRenderCount: ^UINT, pCaptureDeviceId: LPWSTR, pCaptureCount: ^UINT) -> System_Error --- + XInputGetBatteryInformation :: proc(user: XUSER, devType: BATTERY_DEVTYPE, pBatteryInformation: ^XINPUT_BATTERY_INFORMATION) -> System_Error --- + XInputGetKeystroke :: proc(user: XUSER, dwReserved: DWORD, pKeystroke: ^XINPUT_KEYSTROKE) -> System_Error --- XInputGetDSoundAudioDeviceGuids :: proc(user: XUSER, pDSoundRenderGuid: ^GUID, pDSoundCaptureGuid: ^GUID) -> System_Error --- } diff --git a/core/terminal/internal.odin b/core/terminal/internal_os.odin similarity index 85% rename from core/terminal/internal.odin rename to core/terminal/internal_os.odin index 9404ff833..127cbae54 100644 --- a/core/terminal/internal.odin +++ b/core/terminal/internal_os.odin @@ -1,3 +1,5 @@ +#+build !freestanding +#+build !js #+private package terminal @@ -50,17 +52,8 @@ get_environment_color :: proc() -> Color_Depth { // // Only a small sampling of some common values are checked here. switch term { - case "ansi": fallthrough - case "konsole": fallthrough - case "putty": fallthrough - case "rxvt": fallthrough - case "rxvt-color": fallthrough - case "screen": fallthrough - case "st": fallthrough - case "tmux": fallthrough - case "vte": fallthrough - case "xterm": fallthrough - case "xterm-color": + case "ansi", "konsole", "putty", "rxvt", "rxvt-color", "screen", + "st", "tmux", "vte", "xterm", "xterm-color": return .Three_Bit } } @@ -86,4 +79,4 @@ init_terminal :: proc "contextless" () { @(fini) fini_terminal :: proc "contextless" () { _fini_terminal() -} +} \ No newline at end of file diff --git a/core/terminal/terminal.odin b/core/terminal/terminal.odin index 37fdaff36..86d928649 100644 --- a/core/terminal/terminal.odin +++ b/core/terminal/terminal.odin @@ -1,8 +1,6 @@ // Interaction with the command line interface (`CLI`) of the system. package terminal -import "core:os" - /* This describes the range of colors that a terminal is capable of supporting. */ @@ -15,14 +13,14 @@ Color_Depth :: enum { } /* -Returns true if the file `handle` is attached to a terminal. +Returns true if the `File` is attached to a terminal. This is normally true for `os.stdout` and `os.stderr` unless they are redirected to a file. */ @(require_results) -is_terminal :: proc(handle: os.Handle) -> bool { - return _is_terminal(handle) +is_terminal :: proc(f: $T) -> bool { + return _is_terminal(f) } /* diff --git a/core/terminal/terminal_js.odin b/core/terminal/terminal_js.odin index 4dcd4465e..78c6c240f 100644 --- a/core/terminal/terminal_js.odin +++ b/core/terminal/terminal_js.odin @@ -2,9 +2,7 @@ #+build js package terminal -import "core:os" - -_is_terminal :: proc "contextless" (handle: os.Handle) -> bool { +_is_terminal :: proc "contextless" (handle: any) -> bool { return true } diff --git a/core/terminal/terminal_posix.odin b/core/terminal/terminal_posix.odin index 8d96dd256..83e64c6d8 100644 --- a/core/terminal/terminal_posix.odin +++ b/core/terminal/terminal_posix.odin @@ -4,10 +4,9 @@ package terminal import "base:runtime" import "core:os" -import "core:sys/posix" -_is_terminal :: proc "contextless" (handle: os.Handle) -> bool { - return bool(posix.isatty(posix.FD(handle))) +_is_terminal :: proc "contextless" (f: ^os.File) -> bool { + return os.is_tty(f) } _init_terminal :: proc "contextless" () { diff --git a/core/terminal/terminal_windows.odin b/core/terminal/terminal_windows.odin index 6d5f98a1f..6c77330b5 100644 --- a/core/terminal/terminal_windows.odin +++ b/core/terminal/terminal_windows.odin @@ -5,9 +5,8 @@ import "base:runtime" import "core:os" import "core:sys/windows" -_is_terminal :: proc "contextless" (handle: os.Handle) -> bool { - is_tty := windows.GetFileType(windows.HANDLE(handle)) == windows.FILE_TYPE_CHAR - return is_tty +_is_terminal :: proc "contextless" (f: ^os.File) -> bool { + return os.is_tty(f) } old_modes: [2]struct{ diff --git a/core/testing/doc.odin b/core/testing/doc.odin new file mode 100644 index 000000000..85dc80cc3 --- /dev/null +++ b/core/testing/doc.odin @@ -0,0 +1,46 @@ +/* +The implementation of the `odin test` runner and procedures user tests can use for this purpose. + +Defineables through `#config`: + +```odin +// Specify how many threads to use when running tests. +TEST_THREADS : int : #config(ODIN_TEST_THREADS, 0) +// Track the memory used by each test. +TRACKING_MEMORY : bool : #config(ODIN_TEST_TRACK_MEMORY, true) +// Always report how much memory is used, even when there are no leaks or bad frees. +ALWAYS_REPORT_MEMORY : bool : #config(ODIN_TEST_ALWAYS_REPORT_MEMORY, false) +// Treat memory leaks and bad frees as errors. +FAIL_ON_BAD_MEMORY : bool : #config(ODIN_TEST_FAIL_ON_BAD_MEMORY, false) +// Specify how much memory each thread allocator starts with. +PER_THREAD_MEMORY : int : #config(ODIN_TEST_THREAD_MEMORY, mem. ROLLBACK_STACK_DEFAULT_BLOCK_SIZE) +// Select a specific set of tests to run by name. +// Each test is separated by a comma and may optionally include the package name. +// This may be useful when running tests on multiple packages with `-all-packages`. +// The format is: `package.test_name,test_name_only,...` +TEST_NAMES : string : #config(ODIN_TEST_NAMES, "") +// Show the fancy animated progress report. +// This requires terminal color support, as well as STDOUT to not be redirected to a file. +FANCY_OUTPUT : bool : #config(ODIN_TEST_FANCY, true) +// Copy failed tests to the clipboard when done. +USE_CLIPBOARD : bool : #config(ODIN_TEST_CLIPBOARD, false) +// How many test results to show at a time per package. +PROGRESS_WIDTH : int : #config(ODIN_TEST_PROGRESS_WIDTH, 24) +// This is the random seed that will be sent to each test. +// If it is unspecified, it will be set to the system cycle counter at startup. +SHARED_RANDOM_SEED : u64 : #config(ODIN_TEST_RANDOM_SEED, 0) +// Set the lowest log level for this test run. +LOG_LEVEL_DEFAULT : string : "debug" when ODIN_DEBUG else "info" +LOG_LEVEL : string : #config(ODIN_TEST_LOG_LEVEL, LOG_LEVEL_DEFAULT) +// Report a message at the info level when a test has changed its state. +LOG_STATE_CHANGES : bool : #config(ODIN_TEST_LOG_STATE_CHANGES, false) +// Show only the most necessary logging information. +USING_SHORT_LOGS : bool : #config(ODIN_TEST_SHORT_LOGS, false) +// Output a report of the tests to the given path. +JSON_REPORT : string : #config(ODIN_TEST_JSON_REPORT, "") +// Print the full file path for failed test cases on a new line +// in a way that's friendly to regex capture for an editor's "go to error". +GO_TO_ERROR : bool : #config(ODIN_TEST_GO_TO_ERROR, false) +``` +*/ +package testing \ No newline at end of file diff --git a/core/testing/runner.odin b/core/testing/runner.odin index e0a37c46d..9033d078e 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -10,62 +10,63 @@ package testing Feoramund: Total rewrite. */ -import "base:intrinsics" -import "base:runtime" -import "core:bytes" -@require import "core:encoding/base64" -@require import "core:encoding/json" -import "core:fmt" -import "core:io" -@require import "core:log" -import "core:math/rand" -import "core:mem" -import "core:os" -import "core:slice" -@require import "core:strings" -import "core:sync/chan" -import "core:terminal" -import "core:terminal/ansi" -import "core:thread" -import "core:time" +import "base:intrinsics" +import "base:runtime" +import "core:bytes" +@(require) import "core:encoding/base64" +@(require) import "core:encoding/json" +import "core:fmt" +import "core:io" +@(require) import "core:log" +import "core:math/rand" +import "core:mem" +import "core:os" +import "core:slice" +@(require) import "core:strings" +import "core:sync/chan" +import "core:terminal" +import "core:terminal/ansi" +import "core:thread" +import "core:time" +import "core:path/slashpath" // Specify how many threads to use when running tests. -TEST_THREADS : int : #config(ODIN_TEST_THREADS, 0) +TEST_THREADS : int : #config(ODIN_TEST_THREADS, 0) // Track the memory used by each test. -TRACKING_MEMORY : bool : #config(ODIN_TEST_TRACK_MEMORY, true) +TRACKING_MEMORY : bool : #config(ODIN_TEST_TRACK_MEMORY, true) // Always report how much memory is used, even when there are no leaks or bad frees. ALWAYS_REPORT_MEMORY : bool : #config(ODIN_TEST_ALWAYS_REPORT_MEMORY, false) // Treat memory leaks and bad frees as errors. -FAIL_ON_BAD_MEMORY : bool : #config(ODIN_TEST_FAIL_ON_BAD_MEMORY, false) +FAIL_ON_BAD_MEMORY : bool : #config(ODIN_TEST_FAIL_ON_BAD_MEMORY, false) // Specify how much memory each thread allocator starts with. PER_THREAD_MEMORY : int : #config(ODIN_TEST_THREAD_MEMORY, mem.ROLLBACK_STACK_DEFAULT_BLOCK_SIZE) // Select a specific set of tests to run by name. // Each test is separated by a comma and may optionally include the package name. // This may be useful when running tests on multiple packages with `-all-packages`. // The format is: `package.test_name,test_name_only,...` -TEST_NAMES : string : #config(ODIN_TEST_NAMES, "") +TEST_NAMES : string : #config(ODIN_TEST_NAMES, "") // Show the fancy animated progress report. // This requires terminal color support, as well as STDOUT to not be redirected to a file. -FANCY_OUTPUT : bool : #config(ODIN_TEST_FANCY, true) +FANCY_OUTPUT : bool : #config(ODIN_TEST_FANCY, true) // Copy failed tests to the clipboard when done. -USE_CLIPBOARD : bool : #config(ODIN_TEST_CLIPBOARD, false) +USE_CLIPBOARD : bool : #config(ODIN_TEST_CLIPBOARD, false) // How many test results to show at a time per package. -PROGRESS_WIDTH : int : #config(ODIN_TEST_PROGRESS_WIDTH, 24) +PROGRESS_WIDTH : int : #config(ODIN_TEST_PROGRESS_WIDTH, 24) // This is the random seed that will be sent to each test. // If it is unspecified, it will be set to the system cycle counter at startup. -SHARED_RANDOM_SEED : u64 : #config(ODIN_TEST_RANDOM_SEED, 0) +SHARED_RANDOM_SEED : u64 : #config(ODIN_TEST_RANDOM_SEED, 0) // Set the lowest log level for this test run. LOG_LEVEL_DEFAULT : string : "debug" when ODIN_DEBUG else "info" -LOG_LEVEL : string : #config(ODIN_TEST_LOG_LEVEL, LOG_LEVEL_DEFAULT) +LOG_LEVEL : string : #config(ODIN_TEST_LOG_LEVEL, LOG_LEVEL_DEFAULT) // Report a message at the info level when a test has changed its state. -LOG_STATE_CHANGES : bool : #config(ODIN_TEST_LOG_STATE_CHANGES, false) +LOG_STATE_CHANGES : bool : #config(ODIN_TEST_LOG_STATE_CHANGES, false) // Show only the most necessary logging information. -USING_SHORT_LOGS : bool : #config(ODIN_TEST_SHORT_LOGS, false) +USING_SHORT_LOGS : bool : #config(ODIN_TEST_SHORT_LOGS, false) // Output a report of the tests to the given path. -JSON_REPORT : string : #config(ODIN_TEST_JSON_REPORT, "") +JSON_REPORT : string : #config(ODIN_TEST_JSON_REPORT, "") // Print the full file path for failed test cases on a new line // in a way that's friendly to regex capture for an editor's "go to error". -GO_TO_ERROR : bool : #config(ODIN_TEST_GO_TO_ERROR, false) +GO_TO_ERROR : bool : #config(ODIN_TEST_GO_TO_ERROR, false) get_log_level :: #force_inline proc() -> runtime.Logger_Level { when LOG_LEVEL == "debug" { return .Debug } else @@ -196,6 +197,53 @@ run_test_task :: proc(task: thread.Task) { }) } +Options :: struct { + // Equivalent to the TEST_NAMES compile-time definition, but used dynamically at runtime. + test_names: string, +} + +parse_cli_options :: proc(argv: []string, opts: ^Options, stdout, stderr: io.Writer) { + test_names: strings.Builder + + for arg in argv { + if strings.starts_with(arg, "-tests:") { + _, _, tests := strings.partition(arg, ":") + if len(tests) < 1 { + fmt.wprintln(stderr, "No test names specified for '-tests:'") + os.exit(-1) + } + + if strings.builder_len(test_names) > 0 { + strings.write_byte(&test_names, ',') + } + strings.write_string(&test_names, tests) + } else if arg == "-help" { + exe_name := "test" + if path, err := os.get_executable_path(context.temp_allocator); err == nil { + exe_name = slashpath.base(path) + } + + fmt.wprintfln(stdout, "Usage: %v [OPTIONS]", exe_name) + fmt.wprintfln(stdout, "OPTIONS:") + fmt.wprintln(stdout, " -help:") + fmt.wprintln(stdout, " Display this help text and exit.") + fmt.wprintln(stdout) + fmt.wprintln(stdout, " -tests:") + fmt.wprintln(stdout, " Specify a specific set of tests to run by name.\n" + + " Each test is separated by a comma and may optionally include the package name.\n" + + " This may be useful when running tests on multiple packages with `-all-packages`.\n" + + " The format is: `package.test_name,test_name_only,...`") + fmt.wprintln(stdout) + os.exit(0) + } else { + fmt.wprintfln(stderr, "Unknown argument encountered '%v'", arg) + os.exit(-1) + } + } + + opts.test_names = strings.to_string(test_names) +} + runner :: proc(internal_tests: []Internal_Test) -> bool { BATCH_BUFFER_SIZE :: 32 * mem.Kilobyte POOL_BLOCK_SIZE :: 16 * mem.Kilobyte @@ -219,8 +267,14 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { } } - stdout := io.to_writer(os.stream_from_handle(os.stdout)) - stderr := io.to_writer(os.stream_from_handle(os.stderr)) + + // `-vet` needs parameters to be shadowed by themselves first as an + // explicit declaration, to allow the next line to work. + // NOTE(@harold): Moved out of scope below as it's no longer under a `when` block, but under `if`. + internal_tests := internal_tests + + stdout := os.to_stream(os.stdout) + stderr := os.to_stream(os.stderr) // The animations are only ever shown through STDOUT; // STDERR is used exclusively for logging regardless of error level. @@ -229,54 +283,58 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { should_show_animations := FANCY_OUTPUT && terminal.color_enabled && !global_ansi_disabled + // -- Parse CLI options + opts: Options + parse_cli_options(os.args[1:], &opts, stdout, stderr) + + test_names: string = TEST_NAMES + if len(opts.test_names) > 0 { + test_names = opts.test_names + } + // -- Prepare test data. alloc_error: mem.Allocator_Error - when TEST_NAMES != "" { - select_internal_tests: [dynamic]Internal_Test - defer delete(select_internal_tests) + select_internal_tests: [dynamic]Internal_Test + defer delete(select_internal_tests) - { - index_list := TEST_NAMES - for selector in strings.split_iterator(&index_list, ",") { - // Temp allocator is fine since we just need to identify which test it's referring to. - split_selector := strings.split(selector, ".", context.temp_allocator) + if test_names != "" { + index_list := test_names + for selector in strings.split_iterator(&index_list, ",") { + // Temp allocator is fine since we just need to identify which test it's referring to. + split_selector := strings.split(selector, ".", context.temp_allocator) - found := false - switch len(split_selector) { - case 1: - // Only the test name? - #no_bounds_check name := split_selector[0] - find_test_by_name: for it in internal_tests { - if it.name == name { - found = true - _, alloc_error = append(&select_internal_tests, it) - fmt.assertf(alloc_error == nil, "Error appending to select internal tests: %v", alloc_error) - break find_test_by_name - } - } - case 2: - #no_bounds_check pkg := split_selector[0] - #no_bounds_check name := split_selector[1] - find_test_by_pkg_and_name: for it in internal_tests { - if it.pkg == pkg && it.name == name { - found = true - _, alloc_error = append(&select_internal_tests, it) - fmt.assertf(alloc_error == nil, "Error appending to select internal tests: %v", alloc_error) - break find_test_by_pkg_and_name - } + found := false + switch len(split_selector) { + case 1: + // Only the test name? + #no_bounds_check name := split_selector[0] + find_test_by_name: for it in internal_tests { + if it.name == name { + found = true + _, alloc_error = append(&select_internal_tests, it) + fmt.assertf(alloc_error == nil, "Error appending to select internal tests: %v", alloc_error) + break find_test_by_name } } - if !found { - fmt.wprintfln(stderr, "No test found for the name: %q", selector) + case 2: + #no_bounds_check pkg := split_selector[0] + #no_bounds_check name := split_selector[1] + find_test_by_pkg_and_name: for it in internal_tests { + if it.pkg == pkg && it.name == name { + found = true + _, alloc_error = append(&select_internal_tests, it) + fmt.assertf(alloc_error == nil, "Error appending to select internal tests: %v", alloc_error) + break find_test_by_pkg_and_name + } } } + if !found { + fmt.wprintfln(stderr, "No test found for the name: %q", selector) + } } - // `-vet` needs parameters to be shadowed by themselves first as an - // explicit declaration, to allow the next line to work. - internal_tests := internal_tests // Intentional shadow with user-specified tests. internal_tests = select_internal_tests[:] } @@ -317,7 +375,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { // -- Set thread count. when TEST_THREADS == 0 { - thread_count := os.processor_core_count() + thread_count := os.get_processor_core_count() } else { thread_count := max(1, TEST_THREADS) } @@ -960,11 +1018,7 @@ To partly mitigate this, redirect STDERR to a file or use the -define:ODIN_TEST_ when JSON_REPORT != "" { json_report: JSON - mode: int - when ODIN_OS != .Windows { - mode = os.S_IRUSR|os.S_IWUSR|os.S_IRGRP|os.S_IROTH - } - json_fd, err := os.open(JSON_REPORT, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode) + json_fd, err := os.open(JSON_REPORT, {.Write, .Create, .Trunc}, {.Read_User, .Write_User, .Read_Group, .Read_Other}) fmt.assertf(err == nil, "unable to open file %q for writing of JSON report, error: %v", JSON_REPORT, err) defer os.close(json_fd) @@ -983,7 +1037,7 @@ To partly mitigate this, redirect STDERR to a file or use the -define:ODIN_TEST_ json_report.success = total_success_count json_report.duration = finished_in - json_err := json.marshal_to_writer(os.stream_from_handle(json_fd), json_report, &{ pretty = true }) + json_err := json.marshal_to_writer(os.to_stream(json_fd), json_report, &{ pretty = true }) fmt.assertf(json_err == nil, "Error writing JSON report: %v", json_err) } diff --git a/core/testing/signal_handler_libc.odin b/core/testing/signal_handler_libc.odin index a1441f29d..fb19a0115 100644 --- a/core/testing/signal_handler_libc.odin +++ b/core/testing/signal_handler_libc.odin @@ -1,5 +1,5 @@ #+private -#+build windows, linux, darwin, freebsd, openbsd, netbsd, haiku +#+build linux, darwin, freebsd, openbsd, netbsd, haiku package testing /* @@ -8,6 +8,7 @@ package testing List of contributors: Feoramund: Total rewrite. + blob1807: Windows Win32 API rewrite. */ import "base:intrinsics" @@ -24,18 +25,12 @@ import "core:terminal/ansi" @(private="file") stop_test_passed: libc.sig_atomic_t @(private="file") stop_test_alert: libc.sig_atomic_t -when ODIN_ARCH == .i386 && ODIN_OS == .Windows { - // Thread-local storage is problematic on Windows i386 - @(private="file") - local_test_index: libc.sig_atomic_t - @(private="file") - local_test_index_set: bool -} else { - @(private="file", thread_local) - local_test_index: libc.sig_atomic_t - @(private="file", thread_local) - local_test_index_set: bool -} + +@(private="file", thread_local) +local_test_index: libc.sig_atomic_t +@(private="file", thread_local) +local_test_index_set: bool + // Windows does not appear to have a SIGTRAP, so this is defined here, instead // of in the libc package, just so there's no confusion about it being @@ -96,7 +91,7 @@ stop_test_callback :: proc "c" (sig: libc.int) { advisory_a := ` The test runner's main thread has caught an unrecoverable error (signal ` advisory_b := `) and will now forcibly terminate. -This is a dire bug and should be reported to the Odin developers. +Unless you terminated the tests yourself, this could be a dire bug and should be reported to the Odin developers. ` libc.fwrite(raw_data(advisory_a), size_of(byte), len(advisory_a), libc.stderr) libc.fwrite(raw_data(sigstr), size_of(byte), len(sigstr), libc.stderr) diff --git a/core/testing/signal_handler_windows.odin b/core/testing/signal_handler_windows.odin index 74ebe2998..8843dde92 100644 --- a/core/testing/signal_handler_windows.odin +++ b/core/testing/signal_handler_windows.odin @@ -1,6 +1,211 @@ #+private +#+build windows package testing -__setup_signal_handler :: proc() {} +/* + (c) Copyright 2024 Feoramund . + Made available under Odin's license. + + List of contributors: + Feoramund: Total rewrite. + blob1807: Windows Win32 API rewrite. +*/ + +import "base:runtime" +import "base:intrinsics" + +import "core:os" +import "core:sync" +import "core:c/libc" +import "core:strconv" +import "core:terminal/ansi" + +import win32 "core:sys/windows" + + +@(private="file") stop_runner_flag: int + +@(private="file") stop_test_gate: sync.Mutex +@(private="file") stop_test_index: int +@(private="file") stop_test_signal: win32.DWORD +@(private="file") stop_test_passed: bool +@(private="file") stop_test_alert: int + + +when ODIN_ARCH == .i386 { + // Thread-local storage is problematic on Windows i386 + @(private="file") + local_test_index: int + @(private="file") + local_test_index_set: bool +} else { + @(private="file", thread_local) + local_test_index: int + @(private="file", thread_local) + local_test_index_set: bool +} + + +@(private="file") +stop_runner_callback :: proc "system" (ctrl_type: win32.DWORD) -> win32.BOOL { + if ctrl_type == win32.CTRL_C_EVENT { + prev := intrinsics.atomic_add(&stop_runner_flag, 1) + + // If the flag was already set (if this is the second signal sent for example), + // consider this a forced (not graceful) exit. + if prev > 0 { + os.exit(1) + } + // Say we've hanndled the signal. + return true + } + + // This will also get called for other events which we don't handle for. + // Instead we pass it on to the next handler. + return false +} + +@(private) +stop_test_callback :: proc "system" (info: ^win32.EXCEPTION_POINTERS) -> win32.LONG { + if !local_test_index_set { + // We're a thread created by a test thread. + // + // There's nothing we can do to inform the test runner about who + // signalled, so hopefully the test will handle their own sub-threads. + return win32.EXCEPTION_CONTINUE_SEARCH + } + + context = runtime.default_context() + code := info.ExceptionRecord.ExceptionCode + + if local_test_index == -1 { + // We're the test runner, and we ourselves have caught a signal from + // which there is no recovery. + // + // The most we can do now is make sure the user's cursor is visible, + // nuke the entire processs, and hope a useful core dump survives. + if !global_ansi_disabled { + show_cursor := ansi.CSI + ansi.DECTCEM_SHOW + os.write_string(os.stdout, show_cursor) + os.flush(os.stdout) + } + + expbuf: [8]byte + expstr := strconv.write_uint(expbuf[:], cast(u64)code, 16) + for &c in expbuf { + if 'a' <= c && c <= 'f' { + c -= 32 + } + } + + advisory_a := ` +The test runner's main thread has caught an unrecoverable error (exception 0x` + advisory_b := `) and will now forcibly terminate. +This is a dire bug and should be reported to the Odin developers. +` + os.write_string(os.stderr, advisory_a) + os.write_string(os.stderr, expstr) + os.write_string(os.stderr, advisory_b) + os.flush(os.stderr) + + win32.TerminateProcess(win32.GetCurrentProcess(), 1) + } + + if sync.mutex_guard(&stop_test_gate) { + intrinsics.atomic_store(&stop_test_index, local_test_index) + intrinsics.atomic_store(&stop_test_signal, code) + passed: bool + check_passing: { + if location := local_test_assertion_raised.location; location != {} { + for i in 0.. bool { + return intrinsics.atomic_load(&stop_runner_flag) == 1 +} + +@(private="file") +unlock_stop_test_gate :: proc(_: int, _: Stop_Reason, ok: bool) { + if ok { + sync.mutex_unlock(&stop_test_gate) + } +} + +@(deferred_out=unlock_stop_test_gate) +_should_stop_test :: proc() -> (test_index: int, reason: Stop_Reason, ok: bool) { + if intrinsics.atomic_load(&stop_test_alert) == 1 { + intrinsics.atomic_store(&stop_test_alert, 0) + + test_index = intrinsics.atomic_load(&stop_test_index) + if intrinsics.atomic_load(&stop_test_passed) { + reason = .Successful_Stop + } else { + switch intrinsics.atomic_load(&stop_test_signal) { + case win32.EXCEPTION_ILLEGAL_INSTRUCTION: reason = .Illegal_Instruction + case win32.EXCEPTION_ACCESS_VIOLATION: reason = .Segmentation_Fault + case win32.EXCEPTION_BREAKPOINT: reason = .Unhandled_Trap + case win32.EXCEPTION_SINGLE_STEP: reason = .Unhandled_Trap + + case win32.EXCEPTION_FLT_DENORMAL_OPERAND ..= win32.EXCEPTION_INT_OVERFLOW: + reason = .Arithmetic_Error + } + } + ok = true + } + + return +} -_test_thread_cancel :: proc "contextless" () {} diff --git a/core/testing/testing.odin b/core/testing/testing.odin index d6bf6ea33..7182f77f5 100644 --- a/core/testing/testing.odin +++ b/core/testing/testing.odin @@ -1,4 +1,3 @@ -// The implementation of the `odin test` runner and procedures user tests can use for this purpose. package testing /* diff --git a/core/text/edit/text_edit.odin b/core/text/edit/text_edit.odin index 8713f6eff..58e184309 100644 --- a/core/text/edit/text_edit.odin +++ b/core/text/edit/text_edit.odin @@ -24,6 +24,7 @@ State :: struct { up_index, down_index: int, // multi-lines + translate_by_grapheme: bool, // translates by codepoint by default // undo undo: [dynamic]^Undo_State, @@ -302,14 +303,32 @@ translate_position :: proc(s: ^State, t: Translation) -> int { case .End: pos = len(buf) case .Left: - pos -= 1 - for pos >= 0 && is_continuation_byte(buf[pos]) { + if s.translate_by_grapheme { + // TODO(bill): determine if there is a faster way to determine the last grapheme + // rather than iterate across the entire string (which may be very slow) + it := utf8.decode_grapheme_iterator_make(string(buf[:pos])) + g: utf8.Grapheme + for { + _, g = utf8.decode_grapheme_iterate(&it) or_break + } + pos -= max(g.width, 1) + } else { pos -= 1 + for pos >= 0 && is_continuation_byte(buf[pos]) { + pos -= 1 + } } case .Right: - pos += 1 - for pos < len(buf) && is_continuation_byte(buf[pos]) { + if s.translate_by_grapheme { + it := utf8.decode_grapheme_iterator_make(string(buf[pos:])) + + _, g, _ := utf8.decode_grapheme_iterate(&it) + pos += max(g.width, 1) + } else { pos += 1 + for pos < len(buf) && is_continuation_byte(buf[pos]) { + pos += 1 + } } case .Up: pos = s.up_index diff --git a/core/text/i18n/gettext.odin b/core/text/i18n/gettext.odin index a29fdc003..b0e3dae67 100644 --- a/core/text/i18n/gettext.odin +++ b/core/text/i18n/gettext.odin @@ -14,7 +14,6 @@ package i18n List of contributors: Jeroen van Rijn: Initial implementation. */ -import "core:os" import "core:strings" import "core:bytes" @@ -28,22 +27,17 @@ parse_mo_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTIONS, plur return {}, .MO_File_Invalid } - /* - Check magic. Should be 0x950412de in native Endianness. - */ + // Check magic. Should be 0x950412de in native Endianness. native := true magic := read_u32(data, native) or_return if magic != 0x950412de { native = false - magic = read_u32(data, native) or_return - + magic = read_u32(data, native) or_return if magic != 0x950412de { return {}, .MO_File_Invalid_Signature } } - /* - We can ignore version_minor at offset 6. - */ + // We can ignore version_minor at offset 6. version_major := read_u16(data[4:]) or_return if version_major > 1 { return {}, .MO_File_Unsupported_Version } @@ -53,17 +47,13 @@ parse_mo_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTIONS, plur if count == 0 { return {}, .Empty_Translation_Catalog } - /* - Initalize Translation, interner and optional pluralizer. - */ + // Initalize Translation, interner and optional pluralizer. translation = new(Translation) translation.pluralize = pluralizer strings.intern_init(&translation.intern, allocator, allocator) for n := u32(0); n < count; n += 1 { - /* - Grab string's original length and offset. - */ + // Grab string's original length and offset. offset := original_offset + 8 * n if len(data) < int(offset + 8) { return translation, .MO_File_Invalid } @@ -82,9 +72,7 @@ parse_mo_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTIONS, plur key_data := data[o_offset:][:o_length] val_data := data[t_offset:][:t_length] - /* - Could be a pluralized string. - */ + // Could be a pluralized string. zero := []byte{0} keys := bytes.split(key_data, zero); defer delete(keys) vals := bytes.split(val_data, zero); defer delete(vals) @@ -137,22 +125,7 @@ parse_mo_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTIONS, plur return } -parse_mo_file :: proc(filename: string, options := DEFAULT_PARSE_OPTIONS, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { - context.allocator = allocator - - data, data_ok := os.read_entire_file(filename) - defer delete(data) - - if !data_ok { return {}, .File_Error } - - return parse_mo_from_bytes(data, options, pluralizer, allocator) -} - -parse_mo :: proc { parse_mo_file, parse_mo_from_bytes } - -/* - Helpers. -*/ +@(private) read_u32 :: proc(data: []u8, native_endian := true) -> (res: u32, err: Error) { if len(data) < size_of(u32) { return 0, .Premature_EOF } @@ -169,6 +142,7 @@ read_u32 :: proc(data: []u8, native_endian := true) -> (res: u32, err: Error) { } } +@(private) read_u16 :: proc(data: []u8, native_endian := true) -> (res: u16, err: Error) { if len(data) < size_of(u16) { return 0, .Premature_EOF } diff --git a/core/text/i18n/i18_js.odin b/core/text/i18n/i18_js.odin new file mode 100644 index 000000000..73e8535a5 --- /dev/null +++ b/core/text/i18n/i18_js.odin @@ -0,0 +1,16 @@ +#+build freestanding +#+build js +package i18n +/* + Internationalization helpers. + + Copyright 2021-2022 Jeroen van Rijn . + Made available under Odin's license. + + List of contributors: + Jeroen van Rijn: Initial implementation. +*/ +@(private) +parse_qt :: proc { parse_qt_linguist_from_bytes } + +parse_mo :: proc { parse_mo_from_bytes } \ No newline at end of file diff --git a/core/text/i18n/i18n.odin b/core/text/i18n/i18n.odin index b978bffc4..148fe229f 100644 --- a/core/text/i18n/i18n.odin +++ b/core/text/i18n/i18n.odin @@ -8,7 +8,7 @@ package i18n List of contributors: Jeroen van Rijn: Initial implementation. */ -import "core:strings" +import "core:strings" // Currently active catalog. ACTIVE: ^Translation diff --git a/core/text/i18n/i18n_os.odin b/core/text/i18n/i18n_os.odin new file mode 100644 index 000000000..7a7995612 --- /dev/null +++ b/core/text/i18n/i18n_os.odin @@ -0,0 +1,38 @@ +#+build !freestanding +#+build !js +package i18n +/* + Internationalization helpers. + + Copyright 2021-2022 Jeroen van Rijn . + Made available under Odin's license. + + List of contributors: + Jeroen van Rijn: Initial implementation. +*/ +import "base:runtime" +import "core:os" + +@(private) +read_file :: proc(filename: string, allocator: runtime.Allocator) -> (data: []u8, err: Error) { + file_data, file_err := os.read_entire_file(filename, allocator) + if file_err != nil { + return {}, .File_Error + } + return file_data, nil +} + +parse_qt_linguist_file :: proc(filename: string, options := DEFAULT_PARSE_OPTIONS, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { + data := read_file(filename, allocator) or_return + return parse_qt_linguist_from_bytes(data, options, pluralizer, allocator) +} + +parse_qt :: proc { parse_qt_linguist_file, parse_qt_linguist_from_bytes } + +parse_mo_file :: proc(filename: string, options := DEFAULT_PARSE_OPTIONS, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { + data := read_file(filename, allocator) or_return + defer delete(data) + return parse_mo_from_bytes(data, options, pluralizer, allocator) +} + +parse_mo :: proc { parse_mo_file, parse_mo_from_bytes } \ No newline at end of file diff --git a/core/text/i18n/qt_linguist.odin b/core/text/i18n/qt_linguist.odin index 2fc5efe7b..9c5791b67 100644 --- a/core/text/i18n/qt_linguist.odin +++ b/core/text/i18n/qt_linguist.odin @@ -11,7 +11,6 @@ package i18n List of contributors: Jeroen van Rijn: Initial implementation. */ -import "core:os" import "core:encoding/xml" import "core:strings" @@ -56,9 +55,7 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI return nil, .TS_File_Parse_Error } - /* - Initalize Translation, interner and optional pluralizer. - */ + // Initalize Translation, interner and optional pluralizer. translation = new(Translation) translation.pluralize = pluralizer strings.intern_init(&translation.intern, allocator, allocator) @@ -69,7 +66,6 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI child_id := get_id(value) or_return // These should be s. - if ts.elements[child_id].ident != "context" { return translation, .TS_File_Expected_Context } @@ -158,13 +154,3 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI return } -parse_qt_linguist_file :: proc(filename: string, options := DEFAULT_PARSE_OPTIONS, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { - context.allocator = allocator - - data, data_ok := os.read_entire_file(filename) - if !data_ok { return {}, .File_Error } - - return parse_qt_linguist_from_bytes(data, options, pluralizer, allocator) -} - -parse_qt :: proc { parse_qt_linguist_file, parse_qt_linguist_from_bytes } \ No newline at end of file diff --git a/core/text/regex/common/common.odin b/core/text/regex/common/common.odin index 24b44833f..cfbbe53ba 100644 --- a/core/text/regex/common/common.odin +++ b/core/text/regex/common/common.odin @@ -14,6 +14,8 @@ MAX_CAPTURE_GROUPS :: max(#config(ODIN_REGEX_MAX_CAPTURE_GROUPS, 10), 10) MAX_PROGRAM_SIZE :: int(max(i16)) MAX_CLASSES :: int(max(u8)) +ODIN_DEBUG_REGEX :: #config(ODIN_DEBUG_REGEX, false) + Flag :: enum u8 { // Multiline: treat `^` and `$` as if they also match newlines. Multiline, diff --git a/core/text/regex/common/debugging.odin b/core/text/regex/common/debugging.odin index 1a241e136..055bbd20d 100644 --- a/core/text/regex/common/debugging.odin +++ b/core/text/regex/common/debugging.odin @@ -8,16 +8,9 @@ package regex_common Feoramund: Initial implementation. */ -@require import "core:os" import "core:io" import "core:strings" -ODIN_DEBUG_REGEX :: #config(ODIN_DEBUG_REGEX, false) - -when ODIN_DEBUG_REGEX { - debug_stream := os.stream_from_handle(os.stderr) -} - write_padded_hex :: proc(w: io.Writer, #any_int n, zeroes: int) { sb := strings.builder_make() defer strings.builder_destroy(&sb) diff --git a/core/text/regex/common/os.odin b/core/text/regex/common/os.odin new file mode 100644 index 000000000..75d84a5d3 --- /dev/null +++ b/core/text/regex/common/os.odin @@ -0,0 +1,25 @@ +#+build !freestanding +#+build !js +package regex_common + +/* + (c) Copyright 2024 Feoramund . + Made available under Odin's license. + + List of contributors: + Feoramund: Initial implementation. +*/ + +@(require) import "base:runtime" +@(require) import "core:io" +@(require) import "core:os" + +debug_stream: io.Stream + +when ODIN_DEBUG_REGEX { + @(init) + init_debug_stream :: proc "contextless" () { + context = runtime.default_context() + debug_stream = os.to_stream(os.stderr) + } +} \ No newline at end of file diff --git a/core/text/regex/regex.odin b/core/text/regex/regex.odin index c22371f3f..eae95b7e5 100644 --- a/core/text/regex/regex.odin +++ b/core/text/regex/regex.odin @@ -280,9 +280,9 @@ create_iterator :: proc( ) -> (result: Match_Iterator, err: Error) { result.regex = create(pattern, flags, permanent_allocator, temporary_allocator) or_return - result.capture = preallocate_capture() + result.capture = preallocate_capture(permanent_allocator) result.temp = temporary_allocator - result.vm = virtual_machine.create(result.regex.program, str) + result.vm = virtual_machine.create(result.regex.program, str, permanent_allocator) result.vm.class_data = result.regex.class_data result.threads = max(1, virtual_machine.opcode_count(result.vm.code) - 1) diff --git a/core/text/regex/virtual_machine/virtual_machine.odin b/core/text/regex/virtual_machine/virtual_machine.odin index 169d8132d..ab2e9515c 100644 --- a/core/text/regex/virtual_machine/virtual_machine.odin +++ b/core/text/regex/virtual_machine/virtual_machine.odin @@ -203,28 +203,24 @@ add_thread :: proc(vm: ^Machine, saved: ^[2 * common.MAX_CAPTURE_GROUPS]int, pc: } case .Assert_Word_Boundary: sp := vm.string_pointer+vm.current_rune_size - if sp == 0 || sp == len(vm.memory) { + + left_is_wc := sp > 0 && is_word_class(vm.current_rune) + right_is_wc := sp < len(vm.memory) && is_word_class(vm.next_rune) + + if left_is_wc != right_is_wc { pc += size_of(Opcode) continue - } else { - last_rune_is_wc := is_word_class(vm.current_rune) - this_rune_is_wc := is_word_class(vm.next_rune) - - if last_rune_is_wc && !this_rune_is_wc || !last_rune_is_wc && this_rune_is_wc { - pc += size_of(Opcode) - continue - } } + case .Assert_Non_Word_Boundary: sp := vm.string_pointer+vm.current_rune_size - if sp != 0 && sp != len(vm.memory) { - last_rune_is_wc := is_word_class(vm.current_rune) - this_rune_is_wc := is_word_class(vm.next_rune) - if last_rune_is_wc && this_rune_is_wc || !last_rune_is_wc && !this_rune_is_wc { - pc += size_of(Opcode) - continue - } + left_is_wc := sp > 0 && is_word_class(vm.current_rune) + right_is_wc := sp < len(vm.memory) && is_word_class(vm.next_rune) + + if left_is_wc == right_is_wc { + pc += size_of(Opcode) + continue } case .Wait_For_Byte: diff --git a/core/text/table/doc.odin b/core/text/table/doc.odin index 4b8d76893..d91763661 100644 --- a/core/text/table/doc.odin +++ b/core/text/table/doc.odin @@ -195,6 +195,7 @@ Example: scripts :: proc(w: io.Writer) { t: table.Table table.init(&t) + defer table.destroy(&t) table.caption(&t, "Tést Suite") table.padding(&t, 1, 3) table.header_of_aligned_values(&t, {{.Left, "Script"}, {.Center, "Sample"}}) @@ -224,9 +225,7 @@ Example: } main :: proc() { - stdout := os.stream_from_handle(os.stdout) - - scripts(stdout) + scripts(os.to_stream(os.stdout)) } Output: @@ -274,6 +273,7 @@ Example: box_drawing :: proc(w: io.Writer) { t: table.Table table.init(&t) + defer table.destroy(&t) table.caption(&t, "Box Drawing Example") table.padding(&t, 2, 2) table.header_of_aligned_values(&t, {{.Left, "Operating System"}, {.Center, "Year Introduced"}}) @@ -299,9 +299,7 @@ Example: } main :: proc() { - stdout := os.stream_from_handle(os.stdout) - - box_drawing(stdout) + box_drawing(os.to_stream(os.stdout)) } While the decorations support multi-codepoint Unicode graphemes, do note that diff --git a/core/text/table/utility.odin b/core/text/table/utility.odin index 0e56fd968..675fa6b10 100644 --- a/core/text/table/utility.odin +++ b/core/text/table/utility.odin @@ -1,3 +1,5 @@ +#+build !freestanding +#+build !js package text_table import "core:io" @@ -5,7 +7,7 @@ import "core:os" import "core:strings" stdio_writer :: proc() -> io.Writer { - return io.to_writer(os.stream_from_handle(os.stdout)) + return os.to_stream(os.stdout) } strings_builder_writer :: proc(b: ^strings.Builder) -> io.Writer { diff --git a/core/thread/thread.odin b/core/thread/thread.odin index 0030022c4..859b6597a 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -5,7 +5,10 @@ import "base:runtime" import "core:mem" import "base:intrinsics" -_ :: intrinsics +@(private) +unall :: intrinsics.unaligned_load +@(private) +unals :: intrinsics.unaligned_store /* Value, specifying whether `core:thread` functionality is available on the @@ -394,7 +397,9 @@ create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_contex thread_proc :: proc(t: ^Thread) { fn := cast(proc(T))t.data assert(t.user_index >= 1) - data := (^T)(&t.user_args[0])^ + + data := unall((^T)(&t.user_args)) + fn(data) } if t = create(thread_proc, priority, name); t == nil { @@ -403,9 +408,7 @@ create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_contex t.data = rawptr(fn) t.user_index = 1 - data := data - - mem.copy(&t.user_args[0], &data, size_of(T)) + unals((^T)(&t.user_args), data) if self_cleanup { intrinsics.atomic_or(&t.flags, {.Self_Cleanup}) @@ -443,9 +446,10 @@ create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), fn := cast(proc(T1, T2))t.data assert(t.user_index >= 2) - user_args := mem.slice_to_bytes(t.user_args[:]) - arg1 := (^T1)(raw_data(user_args))^ - arg2 := (^T2)(raw_data(user_args[size_of(T1):]))^ + ptr := uintptr(&t.user_args) + + arg1 := unall((^T1)(rawptr(ptr))) + arg2 := unall((^T2)(rawptr(ptr + size_of(T1)))) fn(arg1, arg2) } @@ -455,11 +459,10 @@ create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), t.data = rawptr(fn) t.user_index = 2 - arg1, arg2 := arg1, arg2 - user_args := mem.slice_to_bytes(t.user_args[:]) + ptr := uintptr(&t.user_args) - n := copy(user_args, mem.ptr_to_bytes(&arg1)) - _ = copy(user_args[n:], mem.ptr_to_bytes(&arg2)) + unals((^T1)(rawptr(ptr)), arg1) + unals((^T2)(rawptr(ptr + size_of(T1))), arg2) if self_cleanup { intrinsics.atomic_or(&t.flags, {.Self_Cleanup}) @@ -497,10 +500,11 @@ create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: pr fn := cast(proc(T1, T2, T3))t.data assert(t.user_index >= 3) - user_args := mem.slice_to_bytes(t.user_args[:]) - arg1 := (^T1)(raw_data(user_args))^ - arg2 := (^T2)(raw_data(user_args[size_of(T1):]))^ - arg3 := (^T3)(raw_data(user_args[size_of(T1) + size_of(T2):]))^ + ptr := uintptr(&t.user_args) + + arg1 := unall((^T1)(rawptr(ptr))) + arg2 := unall((^T2)(rawptr(ptr + size_of(T1)))) + arg3 := unall((^T3)(rawptr(ptr + size_of(T1) + size_of(T2)))) fn(arg1, arg2, arg3) } @@ -510,12 +514,11 @@ create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: pr t.data = rawptr(fn) t.user_index = 3 - arg1, arg2, arg3 := arg1, arg2, arg3 - user_args := mem.slice_to_bytes(t.user_args[:]) + ptr := uintptr(&t.user_args) - n := copy(user_args, mem.ptr_to_bytes(&arg1)) - n += copy(user_args[n:], mem.ptr_to_bytes(&arg2)) - _ = copy(user_args[n:], mem.ptr_to_bytes(&arg3)) + unals((^T1)(rawptr(ptr)), arg1) + unals((^T2)(rawptr(ptr + size_of(T1))), arg2) + unals((^T3)(rawptr(ptr + size_of(T1) + size_of(T2))), arg3) if self_cleanup { intrinsics.atomic_or(&t.flags, {.Self_Cleanup}) diff --git a/core/thread/thread_other.odin b/core/thread/thread_other.odin index 1bdc11a4e..aa310d41e 100644 --- a/core/thread/thread_other.odin +++ b/core/thread/thread_other.odin @@ -38,7 +38,7 @@ _destroy :: proc(thread: ^Thread) { unimplemented("core:thread procedure not supported on target") } -_terminate :: proc(using thread : ^Thread, exit_code: int) { +_terminate :: proc(thread : ^Thread, exit_code: int) { unimplemented("core:thread procedure not supported on target") } diff --git a/core/thread/thread_pool.odin b/core/thread/thread_pool.odin index d7a03d04c..10f1438d7 100644 --- a/core/thread/thread_pool.odin +++ b/core/thread/thread_pool.odin @@ -20,6 +20,9 @@ Task :: struct { allocator: mem.Allocator, } +Thread_Init_Proc :: #type proc(thread: ^Thread, user_data: rawptr) +Thread_Fini_Proc :: #type proc(thread: ^Thread, user_data: rawptr) + // Do not access the pool's members directly while the pool threads are running, // since they use different kinds of locking and mutual exclusion devices. // Careless access can and will lead to nasty bugs. Once initialized, the @@ -36,6 +39,13 @@ Pool :: struct { num_done: int, // end of atomics + // called once per thread at startup + thread_init_proc: Thread_Init_Proc, + thread_init_data: rawptr, + // called once per thread at shutdown + thread_fini_proc: Thread_Fini_Proc, + thread_fini_data: rawptr, + is_running: bool, threads: []^Thread, @@ -55,6 +65,10 @@ pool_thread_runner :: proc(t: ^Thread) { data := cast(^Pool_Thread_Data)t.data pool := data.pool + if pool.thread_init_proc != nil { + pool.thread_init_proc(t, pool.thread_init_data) + } + for intrinsics.atomic_load(&pool.is_running) { sync.wait(&pool.sem_available) @@ -66,6 +80,10 @@ pool_thread_runner :: proc(t: ^Thread) { } } + if pool.thread_fini_proc != nil { + pool.thread_fini_proc(t, pool.thread_fini_data) + } + sync.post(&pool.sem_available, 1) } @@ -73,13 +91,26 @@ pool_thread_runner :: proc(t: ^Thread) { // it is destroyed. // // The thread pool requires an allocator which it either owns, or which is thread safe. -pool_init :: proc(pool: ^Pool, allocator: mem.Allocator, thread_count: int) { +pool_init :: proc( + pool: ^Pool, + allocator: mem.Allocator, + thread_count: int, + init_proc: Thread_Init_Proc = nil, + init_data: rawptr = nil, + fini_proc: Thread_Init_Proc = nil, + fini_data: rawptr = nil, +){ context.allocator = allocator pool.allocator = allocator queue.init(&pool.tasks) pool.tasks_done = make([dynamic]Task) pool.threads = make([]^Thread, max(thread_count, 1)) + pool.thread_init_proc = init_proc + pool.thread_fini_proc = fini_proc + pool.thread_init_data = init_data + pool.thread_fini_data = fini_data + pool.is_running = true for _, i in pool.threads { diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index b4e65a4e4..8b08d8c19 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -112,7 +112,11 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority, name: Maybe(s high := posix.sched_get_priority_max(policy) switch priority { case .Normal: // Okay - case .Low: params.sched_priority = low + 1 + case .Low: + params.sched_priority = low + 1 + if params.sched_priority >= high { + params.sched_priority = low + } case .High: params.sched_priority = high } res = posix.pthread_attr_setschedparam(&attrs, ¶ms) diff --git a/core/time/perf.odin b/core/time/perf.odin index c2d3890ff..2db1f4034 100644 --- a/core/time/perf.odin +++ b/core/time/perf.odin @@ -194,6 +194,8 @@ Benchmark_Options :: struct { // `benchmark()` procedure will output the average number of megabytes // processed per second, using the `processed` field of this struct. megabytes_per_second: f64, + // For user specified data in the callbacks + user_data: rawptr, } /* diff --git a/core/time/time.odin b/core/time/time.odin index 542e4d242..438d74569 100644 --- a/core/time/time.odin +++ b/core/time/time.odin @@ -526,6 +526,9 @@ to_string_hms_12 :: proc(t: Time, buf: []u8, ampm: [2]string = {" am", " pm"}) - h, m, s := clock(t) _h := h % 12 + if _h == 0 { + _h = 12 + } buf[7] = '0' + u8(s % 10); s /= 10 buf[6] = '0' + u8(s) buf[5] = ':' @@ -535,7 +538,7 @@ to_string_hms_12 :: proc(t: Time, buf: []u8, ampm: [2]string = {" am", " pm"}) - buf[1] = '0' + u8(_h% 10); _h /= 10 buf[0] = '0' + u8(_h) - if h < 13 { + if h < 12 { copy(buf[8:], ampm[0]) return string(buf[:MIN_HMS_LEN+len(ampm[0])]) } else { diff --git a/core/time/timezone/tz_os.odin b/core/time/timezone/tz_os.odin new file mode 100644 index 000000000..fae4980c3 --- /dev/null +++ b/core/time/timezone/tz_os.odin @@ -0,0 +1,19 @@ +#+build !freestanding +#+build !js +package timezone + +import "core:os" +import "core:time/datetime" + +load_tzif_file :: proc(filename: string, region_name: string, allocator := context.allocator) -> (out: ^datetime.TZ_Region, ok: bool) { + tzif_data, tzif_err := os.read_entire_file(filename, allocator) + if tzif_err != nil { + return nil, false + } + defer delete(tzif_data, allocator) + return parse_tzif(tzif_data, region_name, allocator) +} + +region_load_from_file :: proc(file_path, reg: string, allocator := context.allocator) -> (out_reg: ^datetime.TZ_Region, ok: bool) { + return load_tzif_file(file_path, reg, allocator) +} \ No newline at end of file diff --git a/core/time/timezone/tz_unix.odin b/core/time/timezone/tz_unix.odin index 990e78d41..3939b3265 100644 --- a/core/time/timezone/tz_unix.odin +++ b/core/time/timezone/tz_unix.odin @@ -4,17 +4,17 @@ package timezone import "core:os" import "core:strings" -import "core:path/filepath" import "core:time/datetime" +import "core:path/filepath" local_tz_name :: proc(allocator := context.allocator) -> (name: string, success: bool) { local_str, ok := os.lookup_env("TZ", allocator) if !ok { orig_localtime_path := "/etc/localtime" - path, err := os.absolute_path_from_relative(orig_localtime_path, allocator) + path, err := os.get_absolute_path(orig_localtime_path, allocator) if err != nil { // If we can't find /etc/localtime, fallback to UTC - if err == .ENOENT { + if err == .Not_Exist { str, err2 := strings.clone("UTC", allocator) if err2 != nil { return } return str, true @@ -28,16 +28,20 @@ local_tz_name :: proc(allocator := context.allocator) -> (name: string, success: // This is a hackaround, because FreeBSD copies rather than softlinks their local timezone file, // *sometimes* and then stores the original name of the timezone in /var/db/zoneinfo instead if path == orig_localtime_path { - data := os.read_entire_file("/var/db/zoneinfo", allocator) or_return + data, data_err := os.read_entire_file("/var/db/zoneinfo", allocator) + if data_err != nil { + return "", false + } return strings.trim_right_space(string(data)), true } // Looking for tz path (ex fmt: "UTC", "Etc/UTC" or "America/Los_Angeles") - path_dir, path_file := filepath.split(path) + path_dir, path_file := os.split_path(path) + if path_dir == "" { return } - upper_path_dir, upper_path_chunk := filepath.split(path_dir[:len(path_dir)-1]) + upper_path_dir, upper_path_chunk := os.split_path(path_dir[:len(path_dir)]) if upper_path_dir == "" { return } @@ -47,8 +51,8 @@ local_tz_name :: proc(allocator := context.allocator) -> (name: string, success: if err != nil { return } return region_str, true } else { - region_str, err := filepath.join({upper_path_chunk, path_file}, allocator = allocator) - if err != nil { return } + region_str, region_str_err := os.join_path({upper_path_chunk, path_file}, allocator = allocator) + if region_str_err != nil { return } return region_str, true } } @@ -81,9 +85,29 @@ _region_load :: proc(_reg_str: string, allocator := context.allocator) -> (out_r } defer if _reg_str == "local" { delete(reg_str, allocator) } - db_path := "/usr/share/zoneinfo" - region_path := filepath.join({db_path, reg_str}, allocator) - defer delete(region_path, allocator) + tzdir_str, tzdir_ok := os.lookup_env("TZDIR", allocator) + defer if tzdir_ok { delete(tzdir_str, allocator) } - return load_tzif_file(region_path, reg_str, allocator) -} + if tzdir_ok { + region_path, err := filepath.join({tzdir_str, reg_str}, allocator) + if err != nil { return nil, false } + defer delete(region_path, allocator) + + if tz_reg, ok := load_tzif_file(region_path, reg_str, allocator); ok { + return tz_reg, true + } + } + + db_paths := []string{"/usr/share/zoneinfo", "/share/zoneinfo", "/etc/zoneinfo"} + for db_path in db_paths { + region_path, err := filepath.join({db_path, reg_str}, allocator) + if err != nil { return nil, false} + defer delete(region_path, allocator) + + if tz_reg, ok := load_tzif_file(region_path, reg_str, allocator); ok { + return tz_reg, true + } + } + + return nil, false +} \ No newline at end of file diff --git a/core/time/timezone/tzdate.odin b/core/time/timezone/tzdate.odin index f01553573..29e8ad25c 100644 --- a/core/time/timezone/tzdate.odin +++ b/core/time/timezone/tzdate.odin @@ -10,10 +10,6 @@ region_load :: proc(reg: string, allocator := context.allocator) -> (out_reg: ^ return _region_load(reg, allocator) } -region_load_from_file :: proc(file_path, reg: string, allocator := context.allocator) -> (out_reg: ^datetime.TZ_Region, ok: bool) { - return load_tzif_file(file_path, reg, allocator) -} - region_load_from_buffer :: proc(buffer: []u8, reg: string, allocator := context.allocator) -> (out_reg: ^datetime.TZ_Region, ok: bool) { return parse_tzif(buffer, reg, allocator) } diff --git a/core/time/timezone/tzif.odin b/core/time/timezone/tzif.odin index 804211ef4..3b92364ac 100644 --- a/core/time/timezone/tzif.odin +++ b/core/time/timezone/tzif.odin @@ -1,12 +1,10 @@ package timezone -import "base:intrinsics" - -import "core:slice" -import "core:strings" -import "core:os" -import "core:strconv" -import "core:time/datetime" +import "base:intrinsics" +import "core:slice" +import "core:strings" +import "core:strconv" +import "core:time/datetime" // Implementing RFC8536 [https://datatracker.ietf.org/doc/html/rfc8536] @@ -68,13 +66,6 @@ tzif_data_block_size :: proc(hdr: ^TZif_Header, version: TZif_Version) -> (block int(hdr.isutcnt), true } - -load_tzif_file :: proc(filename: string, region_name: string, allocator := context.allocator) -> (out: ^datetime.TZ_Region, ok: bool) { - tzif_data := os.read_entire_file_from_filename(filename, allocator) or_return - defer delete(tzif_data, allocator) - return parse_tzif(tzif_data, region_name, allocator) -} - @private is_alphabetic :: proc(ch: u8) -> bool { // ('A' -> 'Z') || ('a' -> 'z') diff --git a/core/unicode/generated.odin b/core/unicode/generated.odin new file mode 100644 index 000000000..bfea47a87 --- /dev/null +++ b/core/unicode/generated.odin @@ -0,0 +1,2335 @@ +package unicode + +/* + ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ +*/ + +/* + This file is generated from UnicodeData.txt and PropList.txt. These files + are part of the Unicode Database (UCD) and are covered by the license + listed further down. They may be downloaded from the following locations; + + https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt + https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt + https://www.unicode.org/license.txt + + ------------------------------------------------------------------------------ + UNICODE LICENSE V3 + + COPYRIGHT AND PERMISSION NOTICE + + Copyright © 1991-2026 Unicode, Inc. + + NOTICE TO USER: Carefully read the following legal agreement. BY + DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR + SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE + TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT + DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of data files and any associated documentation (the "Data Files") or + software and any associated documentation (the "Software") to deal in the + Data Files or Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, and/or sell + copies of the Data Files or Software, and to permit persons to whom the + Data Files or Software are furnished to do so, provided that either (a) + this copyright and permission notice appear with all copies of the Data + Files or Software, or (b) this copyright and permission notice appear in + associated Documentation. + + THE DATA FILES AND SOFTWARE ARE 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 OF + THIRD PARTY RIGHTS. + + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE + BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA + FILES OR SOFTWARE. + + Except as contained in this notice, the name of a copyright holder shall + not be used in advertising or otherwise to promote the sale, use or other + dealings in these Data Files or Software without prior written + authorization of the copyright holder. + +*/ + +Range :: struct { + single_16 : []u16, + ranges_16 : []u16, + single_32 : []i32, + ranges_32 : []i32, +} + +@(rodata) +ll_singles16 := [?]u16{ + 0x00B5, 0x0101, 0x0103, 0x0105, 0x0107, 0x0109, 0x010B, 0x010D, + 0x010F, 0x0111, 0x0113, 0x0115, 0x0117, 0x0119, 0x011B, 0x011D, + 0x011F, 0x0121, 0x0123, 0x0125, 0x0127, 0x0129, 0x012B, 0x012D, + 0x012F, 0x0131, 0x0133, 0x0135, 0x013A, 0x013C, 0x013E, 0x0140, + 0x0142, 0x0144, 0x0146, 0x014B, 0x014D, 0x014F, 0x0151, 0x0153, + 0x0155, 0x0157, 0x0159, 0x015B, 0x015D, 0x015F, 0x0161, 0x0163, + 0x0165, 0x0167, 0x0169, 0x016B, 0x016D, 0x016F, 0x0171, 0x0173, + 0x0175, 0x0177, 0x017A, 0x017C, 0x0183, 0x0185, 0x0188, 0x0192, + 0x0195, 0x019E, 0x01A1, 0x01A3, 0x01A5, 0x01A8, 0x01AD, 0x01B0, + 0x01B4, 0x01B6, 0x01C6, 0x01C9, 0x01CC, 0x01CE, 0x01D0, 0x01D2, + 0x01D4, 0x01D6, 0x01D8, 0x01DA, 0x01DF, 0x01E1, 0x01E3, 0x01E5, + 0x01E7, 0x01E9, 0x01EB, 0x01ED, 0x01F3, 0x01F5, 0x01F9, 0x01FB, + 0x01FD, 0x01FF, 0x0201, 0x0203, 0x0205, 0x0207, 0x0209, 0x020B, + 0x020D, 0x020F, 0x0211, 0x0213, 0x0215, 0x0217, 0x0219, 0x021B, + 0x021D, 0x021F, 0x0221, 0x0223, 0x0225, 0x0227, 0x0229, 0x022B, + 0x022D, 0x022F, 0x0231, 0x023C, 0x0242, 0x0247, 0x0249, 0x024B, + 0x024D, 0x0371, 0x0373, 0x0377, 0x0390, 0x03D9, 0x03DB, 0x03DD, + 0x03DF, 0x03E1, 0x03E3, 0x03E5, 0x03E7, 0x03E9, 0x03EB, 0x03ED, + 0x03F5, 0x03F8, 0x0461, 0x0463, 0x0465, 0x0467, 0x0469, 0x046B, + 0x046D, 0x046F, 0x0471, 0x0473, 0x0475, 0x0477, 0x0479, 0x047B, + 0x047D, 0x047F, 0x0481, 0x048B, 0x048D, 0x048F, 0x0491, 0x0493, + 0x0495, 0x0497, 0x0499, 0x049B, 0x049D, 0x049F, 0x04A1, 0x04A3, + 0x04A5, 0x04A7, 0x04A9, 0x04AB, 0x04AD, 0x04AF, 0x04B1, 0x04B3, + 0x04B5, 0x04B7, 0x04B9, 0x04BB, 0x04BD, 0x04BF, 0x04C2, 0x04C4, + 0x04C6, 0x04C8, 0x04CA, 0x04CC, 0x04D1, 0x04D3, 0x04D5, 0x04D7, + 0x04D9, 0x04DB, 0x04DD, 0x04DF, 0x04E1, 0x04E3, 0x04E5, 0x04E7, + 0x04E9, 0x04EB, 0x04ED, 0x04EF, 0x04F1, 0x04F3, 0x04F5, 0x04F7, + 0x04F9, 0x04FB, 0x04FD, 0x04FF, 0x0501, 0x0503, 0x0505, 0x0507, + 0x0509, 0x050B, 0x050D, 0x050F, 0x0511, 0x0513, 0x0515, 0x0517, + 0x0519, 0x051B, 0x051D, 0x051F, 0x0521, 0x0523, 0x0525, 0x0527, + 0x0529, 0x052B, 0x052D, 0x052F, 0x1C8A, 0x1E01, 0x1E03, 0x1E05, + 0x1E07, 0x1E09, 0x1E0B, 0x1E0D, 0x1E0F, 0x1E11, 0x1E13, 0x1E15, + 0x1E17, 0x1E19, 0x1E1B, 0x1E1D, 0x1E1F, 0x1E21, 0x1E23, 0x1E25, + 0x1E27, 0x1E29, 0x1E2B, 0x1E2D, 0x1E2F, 0x1E31, 0x1E33, 0x1E35, + 0x1E37, 0x1E39, 0x1E3B, 0x1E3D, 0x1E3F, 0x1E41, 0x1E43, 0x1E45, + 0x1E47, 0x1E49, 0x1E4B, 0x1E4D, 0x1E4F, 0x1E51, 0x1E53, 0x1E55, + 0x1E57, 0x1E59, 0x1E5B, 0x1E5D, 0x1E5F, 0x1E61, 0x1E63, 0x1E65, + 0x1E67, 0x1E69, 0x1E6B, 0x1E6D, 0x1E6F, 0x1E71, 0x1E73, 0x1E75, + 0x1E77, 0x1E79, 0x1E7B, 0x1E7D, 0x1E7F, 0x1E81, 0x1E83, 0x1E85, + 0x1E87, 0x1E89, 0x1E8B, 0x1E8D, 0x1E8F, 0x1E91, 0x1E93, 0x1E9F, + 0x1EA1, 0x1EA3, 0x1EA5, 0x1EA7, 0x1EA9, 0x1EAB, 0x1EAD, 0x1EAF, + 0x1EB1, 0x1EB3, 0x1EB5, 0x1EB7, 0x1EB9, 0x1EBB, 0x1EBD, 0x1EBF, + 0x1EC1, 0x1EC3, 0x1EC5, 0x1EC7, 0x1EC9, 0x1ECB, 0x1ECD, 0x1ECF, + 0x1ED1, 0x1ED3, 0x1ED5, 0x1ED7, 0x1ED9, 0x1EDB, 0x1EDD, 0x1EDF, + 0x1EE1, 0x1EE3, 0x1EE5, 0x1EE7, 0x1EE9, 0x1EEB, 0x1EED, 0x1EEF, + 0x1EF1, 0x1EF3, 0x1EF5, 0x1EF7, 0x1EF9, 0x1EFB, 0x1EFD, 0x1FBE, + 0x210A, 0x2113, 0x212F, 0x2134, 0x2139, 0x214E, 0x2184, 0x2C61, + 0x2C68, 0x2C6A, 0x2C6C, 0x2C71, 0x2C81, 0x2C83, 0x2C85, 0x2C87, + 0x2C89, 0x2C8B, 0x2C8D, 0x2C8F, 0x2C91, 0x2C93, 0x2C95, 0x2C97, + 0x2C99, 0x2C9B, 0x2C9D, 0x2C9F, 0x2CA1, 0x2CA3, 0x2CA5, 0x2CA7, + 0x2CA9, 0x2CAB, 0x2CAD, 0x2CAF, 0x2CB1, 0x2CB3, 0x2CB5, 0x2CB7, + 0x2CB9, 0x2CBB, 0x2CBD, 0x2CBF, 0x2CC1, 0x2CC3, 0x2CC5, 0x2CC7, + 0x2CC9, 0x2CCB, 0x2CCD, 0x2CCF, 0x2CD1, 0x2CD3, 0x2CD5, 0x2CD7, + 0x2CD9, 0x2CDB, 0x2CDD, 0x2CDF, 0x2CE1, 0x2CEC, 0x2CEE, 0x2CF3, + 0x2D27, 0x2D2D, 0xA641, 0xA643, 0xA645, 0xA647, 0xA649, 0xA64B, + 0xA64D, 0xA64F, 0xA651, 0xA653, 0xA655, 0xA657, 0xA659, 0xA65B, + 0xA65D, 0xA65F, 0xA661, 0xA663, 0xA665, 0xA667, 0xA669, 0xA66B, + 0xA66D, 0xA681, 0xA683, 0xA685, 0xA687, 0xA689, 0xA68B, 0xA68D, + 0xA68F, 0xA691, 0xA693, 0xA695, 0xA697, 0xA699, 0xA69B, 0xA723, + 0xA725, 0xA727, 0xA729, 0xA72B, 0xA72D, 0xA733, 0xA735, 0xA737, + 0xA739, 0xA73B, 0xA73D, 0xA73F, 0xA741, 0xA743, 0xA745, 0xA747, + 0xA749, 0xA74B, 0xA74D, 0xA74F, 0xA751, 0xA753, 0xA755, 0xA757, + 0xA759, 0xA75B, 0xA75D, 0xA75F, 0xA761, 0xA763, 0xA765, 0xA767, + 0xA769, 0xA76B, 0xA76D, 0xA76F, 0xA77A, 0xA77C, 0xA77F, 0xA781, + 0xA783, 0xA785, 0xA787, 0xA78C, 0xA78E, 0xA791, 0xA797, 0xA799, + 0xA79B, 0xA79D, 0xA79F, 0xA7A1, 0xA7A3, 0xA7A5, 0xA7A7, 0xA7A9, + 0xA7AF, 0xA7B5, 0xA7B7, 0xA7B9, 0xA7BB, 0xA7BD, 0xA7BF, 0xA7C1, + 0xA7C3, 0xA7C8, 0xA7CA, 0xA7CD, 0xA7CF, 0xA7D1, 0xA7D3, 0xA7D5, + 0xA7D7, 0xA7D9, 0xA7DB, 0xA7F6, 0xA7FA, +} + +@(rodata) +ll_ranges16 := [?]u16{ + 0x0061, 0x007A, + 0x00DF, 0x00F6, + 0x00F8, 0x00FF, + 0x0137, 0x0138, + 0x0148, 0x0149, + 0x017E, 0x0180, + 0x018C, 0x018D, + 0x0199, 0x019B, + 0x01AA, 0x01AB, + 0x01B9, 0x01BA, + 0x01BD, 0x01BF, + 0x01DC, 0x01DD, + 0x01EF, 0x01F0, + 0x0233, 0x0239, + 0x023F, 0x0240, + 0x024F, 0x0293, + 0x0296, 0x02AF, + 0x037B, 0x037D, + 0x03AC, 0x03CE, + 0x03D0, 0x03D1, + 0x03D5, 0x03D7, + 0x03EF, 0x03F3, + 0x03FB, 0x03FC, + 0x0430, 0x045F, + 0x04CE, 0x04CF, + 0x0560, 0x0588, + 0x10D0, 0x10FA, + 0x10FD, 0x10FF, + 0x13F8, 0x13FD, + 0x1C80, 0x1C88, + 0x1D00, 0x1D2B, + 0x1D6B, 0x1D77, + 0x1D79, 0x1D9A, + 0x1E95, 0x1E9D, + 0x1EFF, 0x1F07, + 0x1F10, 0x1F15, + 0x1F20, 0x1F27, + 0x1F30, 0x1F37, + 0x1F40, 0x1F45, + 0x1F50, 0x1F57, + 0x1F60, 0x1F67, + 0x1F70, 0x1F7D, + 0x1F80, 0x1F87, + 0x1F90, 0x1F97, + 0x1FA0, 0x1FA7, + 0x1FB0, 0x1FB4, + 0x1FB6, 0x1FB7, + 0x1FC2, 0x1FC4, + 0x1FC6, 0x1FC7, + 0x1FD0, 0x1FD3, + 0x1FD6, 0x1FD7, + 0x1FE0, 0x1FE7, + 0x1FF2, 0x1FF4, + 0x1FF6, 0x1FF7, + 0x210E, 0x210F, + 0x213C, 0x213D, + 0x2146, 0x2149, + 0x2C30, 0x2C5F, + 0x2C65, 0x2C66, + 0x2C73, 0x2C74, + 0x2C76, 0x2C7B, + 0x2CE3, 0x2CE4, + 0x2D00, 0x2D25, + 0xA72F, 0xA731, + 0xA771, 0xA778, + 0xA793, 0xA795, + 0xAB30, 0xAB5A, + 0xAB60, 0xAB68, + 0xAB70, 0xABBF, + 0xFB00, 0xFB06, + 0xFB13, 0xFB17, + 0xFF41, 0xFF5A, +} + +@(rodata) +ll_singles32 := [?]i32{ + 0x1D4BB, 0x1D7CB, +} + +@(rodata) +ll_ranges32 := [?]i32{ + 0x10428, 0x1044F, + 0x104D8, 0x104FB, + 0x10597, 0x105A1, + 0x105A3, 0x105B1, + 0x105B3, 0x105B9, + 0x105BB, 0x105BC, + 0x10CC0, 0x10CF2, + 0x10D70, 0x10D85, + 0x118C0, 0x118DF, + 0x16E60, 0x16E7F, + 0x16EBB, 0x16ED3, + 0x1D41A, 0x1D433, + 0x1D44E, 0x1D454, + 0x1D456, 0x1D467, + 0x1D482, 0x1D49B, + 0x1D4B6, 0x1D4B9, + 0x1D4BD, 0x1D4C3, + 0x1D4C5, 0x1D4CF, + 0x1D4EA, 0x1D503, + 0x1D51E, 0x1D537, + 0x1D552, 0x1D56B, + 0x1D586, 0x1D59F, + 0x1D5BA, 0x1D5D3, + 0x1D5EE, 0x1D607, + 0x1D622, 0x1D63B, + 0x1D656, 0x1D66F, + 0x1D68A, 0x1D6A5, + 0x1D6C2, 0x1D6DA, + 0x1D6DC, 0x1D6E1, + 0x1D6FC, 0x1D714, + 0x1D716, 0x1D71B, + 0x1D736, 0x1D74E, + 0x1D750, 0x1D755, + 0x1D770, 0x1D788, + 0x1D78A, 0x1D78F, + 0x1D7AA, 0x1D7C2, + 0x1D7C4, 0x1D7C9, + 0x1DF00, 0x1DF09, + 0x1DF0B, 0x1DF1E, + 0x1DF25, 0x1DF2A, + 0x1E922, 0x1E943, +} + +ll_ranges := Range{ + single_16 = ll_singles16[:], + ranges_16 = ll_ranges16[:], + single_32 = ll_singles32[:], + ranges_32 = ll_ranges32[:], +} + +@(rodata) +lm_singles16 := [?]u16{ + 0x02EC, 0x02EE, 0x0374, 0x037A, 0x0559, 0x0640, 0x07FA, 0x081A, + 0x0824, 0x0828, 0x08C9, 0x0971, 0x0E46, 0x0EC6, 0x10FC, 0x17D7, + 0x1843, 0x1AA7, 0x1D78, 0x2071, 0x207F, 0x2D6F, 0x2E2F, 0x3005, + 0x303B, 0xA015, 0xA60C, 0xA67F, 0xA770, 0xA788, 0xA9CF, 0xA9E6, + 0xAA70, 0xAADD, 0xAB69, 0xFF70, +} + +@(rodata) +lm_ranges16 := [?]u16{ + 0x02B0, 0x02C1, + 0x02C6, 0x02D1, + 0x02E0, 0x02E4, + 0x06E5, 0x06E6, + 0x07F4, 0x07F5, + 0x1C78, 0x1C7D, + 0x1D2C, 0x1D6A, + 0x1D9B, 0x1DBF, + 0x2090, 0x209C, + 0x2C7C, 0x2C7D, + 0x3031, 0x3035, + 0x309D, 0x309E, + 0x30FC, 0x30FE, + 0xA4F8, 0xA4FD, + 0xA69C, 0xA69D, + 0xA717, 0xA71F, + 0xA7F1, 0xA7F4, + 0xA7F8, 0xA7F9, + 0xAAF3, 0xAAF4, + 0xAB5C, 0xAB5F, + 0xFF9E, 0xFF9F, +} + +@(rodata) +lm_singles32 := [?]i32{ + 0x10D4E, 0x10D6F, 0x10EC5, 0x11DD9, 0x16FE3, 0x1E4EB, 0x1E6FF, 0x1E94B, +} + +@(rodata) +lm_ranges32 := [?]i32{ + 0x10780, 0x10785, + 0x10787, 0x107B0, + 0x107B2, 0x107BA, + 0x16B40, 0x16B43, + 0x16D40, 0x16D42, + 0x16D6B, 0x16D6C, + 0x16F93, 0x16F9F, + 0x16FE0, 0x16FE1, + 0x16FF2, 0x16FF3, + 0x1AFF0, 0x1AFF3, + 0x1AFF5, 0x1AFFB, + 0x1AFFD, 0x1AFFE, + 0x1E030, 0x1E06D, + 0x1E137, 0x1E13D, +} + +lm_ranges := Range{ + single_16 = lm_singles16[:], + ranges_16 = lm_ranges16[:], + single_32 = lm_singles32[:], + ranges_32 = lm_ranges32[:], +} + +@(rodata) +lo_singles16 := [?]u16{ + 0x00AA, 0x00BA, 0x01BB, 0x06D5, 0x06FF, 0x0710, 0x07B1, 0x093D, + 0x0950, 0x09B2, 0x09BD, 0x09CE, 0x09FC, 0x0A5E, 0x0ABD, 0x0AD0, + 0x0AF9, 0x0B3D, 0x0B71, 0x0B83, 0x0B9C, 0x0BD0, 0x0C3D, 0x0C80, + 0x0CBD, 0x0D3D, 0x0D4E, 0x0DBD, 0x0E84, 0x0EA5, 0x0EBD, 0x0F00, + 0x103F, 0x1061, 0x108E, 0x1258, 0x12C0, 0x17DC, 0x18AA, 0x1CFA, + 0x3006, 0x303C, 0x309F, 0x30FF, 0xA66E, 0xA78F, 0xA7F7, 0xA8FB, + 0xAA7A, 0xAAB1, 0xAAC0, 0xAAC2, 0xAAF2, 0xFB1D, 0xFB3E, +} + +@(rodata) +lo_ranges16 := [?]u16{ + 0x01C0, 0x01C3, + 0x0294, 0x0295, + 0x05D0, 0x05EA, + 0x05EF, 0x05F2, + 0x0620, 0x063F, + 0x0641, 0x064A, + 0x066E, 0x066F, + 0x0671, 0x06D3, + 0x06EE, 0x06EF, + 0x06FA, 0x06FC, + 0x0712, 0x072F, + 0x074D, 0x07A5, + 0x07CA, 0x07EA, + 0x0800, 0x0815, + 0x0840, 0x0858, + 0x0860, 0x086A, + 0x0870, 0x0887, + 0x0889, 0x088F, + 0x08A0, 0x08C8, + 0x0904, 0x0939, + 0x0958, 0x0961, + 0x0972, 0x0980, + 0x0985, 0x098C, + 0x098F, 0x0990, + 0x0993, 0x09A8, + 0x09AA, 0x09B0, + 0x09B6, 0x09B9, + 0x09DC, 0x09DD, + 0x09DF, 0x09E1, + 0x09F0, 0x09F1, + 0x0A05, 0x0A0A, + 0x0A0F, 0x0A10, + 0x0A13, 0x0A28, + 0x0A2A, 0x0A30, + 0x0A32, 0x0A33, + 0x0A35, 0x0A36, + 0x0A38, 0x0A39, + 0x0A59, 0x0A5C, + 0x0A72, 0x0A74, + 0x0A85, 0x0A8D, + 0x0A8F, 0x0A91, + 0x0A93, 0x0AA8, + 0x0AAA, 0x0AB0, + 0x0AB2, 0x0AB3, + 0x0AB5, 0x0AB9, + 0x0AE0, 0x0AE1, + 0x0B05, 0x0B0C, + 0x0B0F, 0x0B10, + 0x0B13, 0x0B28, + 0x0B2A, 0x0B30, + 0x0B32, 0x0B33, + 0x0B35, 0x0B39, + 0x0B5C, 0x0B5D, + 0x0B5F, 0x0B61, + 0x0B85, 0x0B8A, + 0x0B8E, 0x0B90, + 0x0B92, 0x0B95, + 0x0B99, 0x0B9A, + 0x0B9E, 0x0B9F, + 0x0BA3, 0x0BA4, + 0x0BA8, 0x0BAA, + 0x0BAE, 0x0BB9, + 0x0C05, 0x0C0C, + 0x0C0E, 0x0C10, + 0x0C12, 0x0C28, + 0x0C2A, 0x0C39, + 0x0C58, 0x0C5A, + 0x0C5C, 0x0C5D, + 0x0C60, 0x0C61, + 0x0C85, 0x0C8C, + 0x0C8E, 0x0C90, + 0x0C92, 0x0CA8, + 0x0CAA, 0x0CB3, + 0x0CB5, 0x0CB9, + 0x0CDC, 0x0CDE, + 0x0CE0, 0x0CE1, + 0x0CF1, 0x0CF2, + 0x0D04, 0x0D0C, + 0x0D0E, 0x0D10, + 0x0D12, 0x0D3A, + 0x0D54, 0x0D56, + 0x0D5F, 0x0D61, + 0x0D7A, 0x0D7F, + 0x0D85, 0x0D96, + 0x0D9A, 0x0DB1, + 0x0DB3, 0x0DBB, + 0x0DC0, 0x0DC6, + 0x0E01, 0x0E30, + 0x0E32, 0x0E33, + 0x0E40, 0x0E45, + 0x0E81, 0x0E82, + 0x0E86, 0x0E8A, + 0x0E8C, 0x0EA3, + 0x0EA7, 0x0EB0, + 0x0EB2, 0x0EB3, + 0x0EC0, 0x0EC4, + 0x0EDC, 0x0EDF, + 0x0F40, 0x0F47, + 0x0F49, 0x0F6C, + 0x0F88, 0x0F8C, + 0x1000, 0x102A, + 0x1050, 0x1055, + 0x105A, 0x105D, + 0x1065, 0x1066, + 0x106E, 0x1070, + 0x1075, 0x1081, + 0x1100, 0x1248, + 0x124A, 0x124D, + 0x1250, 0x1256, + 0x125A, 0x125D, + 0x1260, 0x1288, + 0x128A, 0x128D, + 0x1290, 0x12B0, + 0x12B2, 0x12B5, + 0x12B8, 0x12BE, + 0x12C2, 0x12C5, + 0x12C8, 0x12D6, + 0x12D8, 0x1310, + 0x1312, 0x1315, + 0x1318, 0x135A, + 0x1380, 0x138F, + 0x1401, 0x166C, + 0x166F, 0x167F, + 0x1681, 0x169A, + 0x16A0, 0x16EA, + 0x16F1, 0x16F8, + 0x1700, 0x1711, + 0x171F, 0x1731, + 0x1740, 0x1751, + 0x1760, 0x176C, + 0x176E, 0x1770, + 0x1780, 0x17B3, + 0x1820, 0x1842, + 0x1844, 0x1878, + 0x1880, 0x1884, + 0x1887, 0x18A8, + 0x18B0, 0x18F5, + 0x1900, 0x191E, + 0x1950, 0x196D, + 0x1970, 0x1974, + 0x1980, 0x19AB, + 0x19B0, 0x19C9, + 0x1A00, 0x1A16, + 0x1A20, 0x1A54, + 0x1B05, 0x1B33, + 0x1B45, 0x1B4C, + 0x1B83, 0x1BA0, + 0x1BAE, 0x1BAF, + 0x1BBA, 0x1BE5, + 0x1C00, 0x1C23, + 0x1C4D, 0x1C4F, + 0x1C5A, 0x1C77, + 0x1CE9, 0x1CEC, + 0x1CEE, 0x1CF3, + 0x1CF5, 0x1CF6, + 0x2135, 0x2138, + 0x2D30, 0x2D67, + 0x2D80, 0x2D96, + 0x2DA0, 0x2DA6, + 0x2DA8, 0x2DAE, + 0x2DB0, 0x2DB6, + 0x2DB8, 0x2DBE, + 0x2DC0, 0x2DC6, + 0x2DC8, 0x2DCE, + 0x2DD0, 0x2DD6, + 0x2DD8, 0x2DDE, + 0x3041, 0x3096, + 0x30A1, 0x30FA, + 0x3105, 0x312F, + 0x3131, 0x318E, + 0x31A0, 0x31BF, + 0x31F0, 0x31FF, + 0x3400, 0x4DBF, + 0x4E00, 0x9FFF, + 0xA000, 0xA014, + 0xA016, 0xA48C, + 0xA4D0, 0xA4F7, + 0xA500, 0xA60B, + 0xA610, 0xA61F, + 0xA62A, 0xA62B, + 0xA6A0, 0xA6E5, + 0xA7FB, 0xA801, + 0xA803, 0xA805, + 0xA807, 0xA80A, + 0xA80C, 0xA822, + 0xA840, 0xA873, + 0xA882, 0xA8B3, + 0xA8F2, 0xA8F7, + 0xA8FD, 0xA8FE, + 0xA90A, 0xA925, + 0xA930, 0xA946, + 0xA960, 0xA97C, + 0xA984, 0xA9B2, + 0xA9E0, 0xA9E4, + 0xA9E7, 0xA9EF, + 0xA9FA, 0xA9FE, + 0xAA00, 0xAA28, + 0xAA40, 0xAA42, + 0xAA44, 0xAA4B, + 0xAA60, 0xAA6F, + 0xAA71, 0xAA76, + 0xAA7E, 0xAAAF, + 0xAAB5, 0xAAB6, + 0xAAB9, 0xAABD, + 0xAADB, 0xAADC, + 0xAAE0, 0xAAEA, + 0xAB01, 0xAB06, + 0xAB09, 0xAB0E, + 0xAB11, 0xAB16, + 0xAB20, 0xAB26, + 0xAB28, 0xAB2E, + 0xABC0, 0xABE2, + 0xAC00, 0xD7A3, + 0xD7B0, 0xD7C6, + 0xD7CB, 0xD7FB, + 0xF900, 0xFA6D, + 0xFA70, 0xFAD9, + 0xFB1F, 0xFB28, + 0xFB2A, 0xFB36, + 0xFB38, 0xFB3C, + 0xFB40, 0xFB41, + 0xFB43, 0xFB44, + 0xFB46, 0xFBB1, + 0xFBD3, 0xFD3D, + 0xFD50, 0xFD8F, + 0xFD92, 0xFDC7, + 0xFDF0, 0xFDFB, + 0xFE70, 0xFE74, + 0xFE76, 0xFEFC, + 0xFF66, 0xFF6F, + 0xFF71, 0xFF9D, + 0xFFA0, 0xFFBE, + 0xFFC2, 0xFFC7, + 0xFFCA, 0xFFCF, + 0xFFD2, 0xFFD7, + 0xFFDA, 0xFFDC, +} + +@(rodata) +lo_singles32 := [?]i32{ + 0x10808, 0x1083C, 0x10A00, 0x10D4F, 0x10F27, 0x11075, 0x11144, 0x11147, + 0x11176, 0x111DA, 0x111DC, 0x11288, 0x1133D, 0x11350, 0x1138B, 0x1138E, + 0x113B7, 0x113D1, 0x113D3, 0x114C7, 0x11644, 0x116B8, 0x11909, 0x1193F, + 0x11941, 0x119E1, 0x119E3, 0x11A00, 0x11A3A, 0x11A50, 0x11A9D, 0x11C40, + 0x11D46, 0x11D98, 0x11F02, 0x11FB0, 0x16F50, 0x18CFF, 0x1B132, 0x1B155, + 0x1DF0A, 0x1E14E, 0x1E5F0, 0x1E6FE, 0x1EE24, 0x1EE27, 0x1EE39, 0x1EE3B, + 0x1EE42, 0x1EE47, 0x1EE49, 0x1EE4B, 0x1EE54, 0x1EE57, 0x1EE59, 0x1EE5B, + 0x1EE5D, 0x1EE5F, 0x1EE64, 0x1EE7E, +} + +@(rodata) +lo_ranges32 := [?]i32{ + 0x10000, 0x1000B, + 0x1000D, 0x10026, + 0x10028, 0x1003A, + 0x1003C, 0x1003D, + 0x1003F, 0x1004D, + 0x10050, 0x1005D, + 0x10080, 0x100FA, + 0x10280, 0x1029C, + 0x102A0, 0x102D0, + 0x10300, 0x1031F, + 0x1032D, 0x10340, + 0x10342, 0x10349, + 0x10350, 0x10375, + 0x10380, 0x1039D, + 0x103A0, 0x103C3, + 0x103C8, 0x103CF, + 0x10450, 0x1049D, + 0x10500, 0x10527, + 0x10530, 0x10563, + 0x105C0, 0x105F3, + 0x10600, 0x10736, + 0x10740, 0x10755, + 0x10760, 0x10767, + 0x10800, 0x10805, + 0x1080A, 0x10835, + 0x10837, 0x10838, + 0x1083F, 0x10855, + 0x10860, 0x10876, + 0x10880, 0x1089E, + 0x108E0, 0x108F2, + 0x108F4, 0x108F5, + 0x10900, 0x10915, + 0x10920, 0x10939, + 0x10940, 0x10959, + 0x10980, 0x109B7, + 0x109BE, 0x109BF, + 0x10A10, 0x10A13, + 0x10A15, 0x10A17, + 0x10A19, 0x10A35, + 0x10A60, 0x10A7C, + 0x10A80, 0x10A9C, + 0x10AC0, 0x10AC7, + 0x10AC9, 0x10AE4, + 0x10B00, 0x10B35, + 0x10B40, 0x10B55, + 0x10B60, 0x10B72, + 0x10B80, 0x10B91, + 0x10C00, 0x10C48, + 0x10D00, 0x10D23, + 0x10D4A, 0x10D4D, + 0x10E80, 0x10EA9, + 0x10EB0, 0x10EB1, + 0x10EC2, 0x10EC4, + 0x10EC6, 0x10EC7, + 0x10F00, 0x10F1C, + 0x10F30, 0x10F45, + 0x10F70, 0x10F81, + 0x10FB0, 0x10FC4, + 0x10FE0, 0x10FF6, + 0x11003, 0x11037, + 0x11071, 0x11072, + 0x11083, 0x110AF, + 0x110D0, 0x110E8, + 0x11103, 0x11126, + 0x11150, 0x11172, + 0x11183, 0x111B2, + 0x111C1, 0x111C4, + 0x11200, 0x11211, + 0x11213, 0x1122B, + 0x1123F, 0x11240, + 0x11280, 0x11286, + 0x1128A, 0x1128D, + 0x1128F, 0x1129D, + 0x1129F, 0x112A8, + 0x112B0, 0x112DE, + 0x11305, 0x1130C, + 0x1130F, 0x11310, + 0x11313, 0x11328, + 0x1132A, 0x11330, + 0x11332, 0x11333, + 0x11335, 0x11339, + 0x1135D, 0x11361, + 0x11380, 0x11389, + 0x11390, 0x113B5, + 0x11400, 0x11434, + 0x11447, 0x1144A, + 0x1145F, 0x11461, + 0x11480, 0x114AF, + 0x114C4, 0x114C5, + 0x11580, 0x115AE, + 0x115D8, 0x115DB, + 0x11600, 0x1162F, + 0x11680, 0x116AA, + 0x11700, 0x1171A, + 0x11740, 0x11746, + 0x11800, 0x1182B, + 0x118FF, 0x11906, + 0x1190C, 0x11913, + 0x11915, 0x11916, + 0x11918, 0x1192F, + 0x119A0, 0x119A7, + 0x119AA, 0x119D0, + 0x11A0B, 0x11A32, + 0x11A5C, 0x11A89, + 0x11AB0, 0x11AF8, + 0x11BC0, 0x11BE0, + 0x11C00, 0x11C08, + 0x11C0A, 0x11C2E, + 0x11C72, 0x11C8F, + 0x11D00, 0x11D06, + 0x11D08, 0x11D09, + 0x11D0B, 0x11D30, + 0x11D60, 0x11D65, + 0x11D67, 0x11D68, + 0x11D6A, 0x11D89, + 0x11DB0, 0x11DD8, + 0x11DDA, 0x11DDB, + 0x11EE0, 0x11EF2, + 0x11F04, 0x11F10, + 0x11F12, 0x11F33, + 0x12000, 0x12399, + 0x12480, 0x12543, + 0x12F90, 0x12FF0, + 0x13000, 0x1342F, + 0x13441, 0x13446, + 0x13460, 0x143FA, + 0x14400, 0x14646, + 0x16100, 0x1611D, + 0x16800, 0x16A38, + 0x16A40, 0x16A5E, + 0x16A70, 0x16ABE, + 0x16AD0, 0x16AED, + 0x16B00, 0x16B2F, + 0x16B63, 0x16B77, + 0x16B7D, 0x16B8F, + 0x16D43, 0x16D6A, + 0x16F00, 0x16F4A, + 0x17000, 0x187FF, + 0x18800, 0x18CD5, + 0x18D00, 0x18D1E, + 0x18D80, 0x18DF2, + 0x1B000, 0x1B122, + 0x1B150, 0x1B152, + 0x1B164, 0x1B167, + 0x1B170, 0x1B2FB, + 0x1BC00, 0x1BC6A, + 0x1BC70, 0x1BC7C, + 0x1BC80, 0x1BC88, + 0x1BC90, 0x1BC99, + 0x1E100, 0x1E12C, + 0x1E290, 0x1E2AD, + 0x1E2C0, 0x1E2EB, + 0x1E4D0, 0x1E4EA, + 0x1E5D0, 0x1E5ED, + 0x1E6C0, 0x1E6DE, + 0x1E6E0, 0x1E6E2, + 0x1E6E4, 0x1E6E5, + 0x1E6E7, 0x1E6ED, + 0x1E6F0, 0x1E6F4, + 0x1E7E0, 0x1E7E6, + 0x1E7E8, 0x1E7EB, + 0x1E7ED, 0x1E7EE, + 0x1E7F0, 0x1E7FE, + 0x1E800, 0x1E8C4, + 0x1EE00, 0x1EE03, + 0x1EE05, 0x1EE1F, + 0x1EE21, 0x1EE22, + 0x1EE29, 0x1EE32, + 0x1EE34, 0x1EE37, + 0x1EE4D, 0x1EE4F, + 0x1EE51, 0x1EE52, + 0x1EE61, 0x1EE62, + 0x1EE67, 0x1EE6A, + 0x1EE6C, 0x1EE72, + 0x1EE74, 0x1EE77, + 0x1EE79, 0x1EE7C, + 0x1EE80, 0x1EE89, + 0x1EE8B, 0x1EE9B, + 0x1EEA1, 0x1EEA3, + 0x1EEA5, 0x1EEA9, + 0x1EEAB, 0x1EEBB, + 0x20000, 0x2A6DF, + 0x2A700, 0x2B73F, + 0x2B740, 0x2B81D, + 0x2B820, 0x2CEAD, + 0x2CEB0, 0x2EBE0, + 0x2EBF0, 0x2EE5D, + 0x2F800, 0x2FA1D, + 0x30000, 0x3134A, + 0x31350, 0x323AF, + 0x323B0, 0x33479, +} + +lo_ranges := Range{ + single_16 = lo_singles16[:], + ranges_16 = lo_ranges16[:], + single_32 = lo_singles32[:], + ranges_32 = lo_ranges32[:], +} + +@(rodata) +lt_singles16 := [?]u16{ + 0x01C5, 0x01C8, 0x01CB, 0x01F2, 0x1FBC, 0x1FCC, 0x1FFC, +} + +@(rodata) +lt_ranges16 := [?]u16{ + 0x1F88, 0x1F8F, + 0x1F98, 0x1F9F, + 0x1FA8, 0x1FAF, +} + +lt_ranges := Range{ + single_16 = lt_singles16[:], + ranges_16 = lt_ranges16[:], +} + +@(rodata) +lu_singles16 := [?]u16{ + 0x0100, 0x0102, 0x0104, 0x0106, 0x0108, 0x010A, 0x010C, 0x010E, + 0x0110, 0x0112, 0x0114, 0x0116, 0x0118, 0x011A, 0x011C, 0x011E, + 0x0120, 0x0122, 0x0124, 0x0126, 0x0128, 0x012A, 0x012C, 0x012E, + 0x0130, 0x0132, 0x0134, 0x0136, 0x0139, 0x013B, 0x013D, 0x013F, + 0x0141, 0x0143, 0x0145, 0x0147, 0x014A, 0x014C, 0x014E, 0x0150, + 0x0152, 0x0154, 0x0156, 0x0158, 0x015A, 0x015C, 0x015E, 0x0160, + 0x0162, 0x0164, 0x0166, 0x0168, 0x016A, 0x016C, 0x016E, 0x0170, + 0x0172, 0x0174, 0x0176, 0x017B, 0x017D, 0x0184, 0x01A2, 0x01A4, + 0x01A9, 0x01AC, 0x01B5, 0x01BC, 0x01C4, 0x01C7, 0x01CA, 0x01CD, + 0x01CF, 0x01D1, 0x01D3, 0x01D5, 0x01D7, 0x01D9, 0x01DB, 0x01DE, + 0x01E0, 0x01E2, 0x01E4, 0x01E6, 0x01E8, 0x01EA, 0x01EC, 0x01EE, + 0x01F1, 0x01F4, 0x01FA, 0x01FC, 0x01FE, 0x0200, 0x0202, 0x0204, + 0x0206, 0x0208, 0x020A, 0x020C, 0x020E, 0x0210, 0x0212, 0x0214, + 0x0216, 0x0218, 0x021A, 0x021C, 0x021E, 0x0220, 0x0222, 0x0224, + 0x0226, 0x0228, 0x022A, 0x022C, 0x022E, 0x0230, 0x0232, 0x0241, + 0x0248, 0x024A, 0x024C, 0x024E, 0x0370, 0x0372, 0x0376, 0x037F, + 0x0386, 0x038C, 0x03CF, 0x03D8, 0x03DA, 0x03DC, 0x03DE, 0x03E0, + 0x03E2, 0x03E4, 0x03E6, 0x03E8, 0x03EA, 0x03EC, 0x03EE, 0x03F4, + 0x03F7, 0x0460, 0x0462, 0x0464, 0x0466, 0x0468, 0x046A, 0x046C, + 0x046E, 0x0470, 0x0472, 0x0474, 0x0476, 0x0478, 0x047A, 0x047C, + 0x047E, 0x0480, 0x048A, 0x048C, 0x048E, 0x0490, 0x0492, 0x0494, + 0x0496, 0x0498, 0x049A, 0x049C, 0x049E, 0x04A0, 0x04A2, 0x04A4, + 0x04A6, 0x04A8, 0x04AA, 0x04AC, 0x04AE, 0x04B0, 0x04B2, 0x04B4, + 0x04B6, 0x04B8, 0x04BA, 0x04BC, 0x04BE, 0x04C3, 0x04C5, 0x04C7, + 0x04C9, 0x04CB, 0x04CD, 0x04D0, 0x04D2, 0x04D4, 0x04D6, 0x04D8, + 0x04DA, 0x04DC, 0x04DE, 0x04E0, 0x04E2, 0x04E4, 0x04E6, 0x04E8, + 0x04EA, 0x04EC, 0x04EE, 0x04F0, 0x04F2, 0x04F4, 0x04F6, 0x04F8, + 0x04FA, 0x04FC, 0x04FE, 0x0500, 0x0502, 0x0504, 0x0506, 0x0508, + 0x050A, 0x050C, 0x050E, 0x0510, 0x0512, 0x0514, 0x0516, 0x0518, + 0x051A, 0x051C, 0x051E, 0x0520, 0x0522, 0x0524, 0x0526, 0x0528, + 0x052A, 0x052C, 0x052E, 0x10C7, 0x10CD, 0x1C89, 0x1E00, 0x1E02, + 0x1E04, 0x1E06, 0x1E08, 0x1E0A, 0x1E0C, 0x1E0E, 0x1E10, 0x1E12, + 0x1E14, 0x1E16, 0x1E18, 0x1E1A, 0x1E1C, 0x1E1E, 0x1E20, 0x1E22, + 0x1E24, 0x1E26, 0x1E28, 0x1E2A, 0x1E2C, 0x1E2E, 0x1E30, 0x1E32, + 0x1E34, 0x1E36, 0x1E38, 0x1E3A, 0x1E3C, 0x1E3E, 0x1E40, 0x1E42, + 0x1E44, 0x1E46, 0x1E48, 0x1E4A, 0x1E4C, 0x1E4E, 0x1E50, 0x1E52, + 0x1E54, 0x1E56, 0x1E58, 0x1E5A, 0x1E5C, 0x1E5E, 0x1E60, 0x1E62, + 0x1E64, 0x1E66, 0x1E68, 0x1E6A, 0x1E6C, 0x1E6E, 0x1E70, 0x1E72, + 0x1E74, 0x1E76, 0x1E78, 0x1E7A, 0x1E7C, 0x1E7E, 0x1E80, 0x1E82, + 0x1E84, 0x1E86, 0x1E88, 0x1E8A, 0x1E8C, 0x1E8E, 0x1E90, 0x1E92, + 0x1E94, 0x1E9E, 0x1EA0, 0x1EA2, 0x1EA4, 0x1EA6, 0x1EA8, 0x1EAA, + 0x1EAC, 0x1EAE, 0x1EB0, 0x1EB2, 0x1EB4, 0x1EB6, 0x1EB8, 0x1EBA, + 0x1EBC, 0x1EBE, 0x1EC0, 0x1EC2, 0x1EC4, 0x1EC6, 0x1EC8, 0x1ECA, + 0x1ECC, 0x1ECE, 0x1ED0, 0x1ED2, 0x1ED4, 0x1ED6, 0x1ED8, 0x1EDA, + 0x1EDC, 0x1EDE, 0x1EE0, 0x1EE2, 0x1EE4, 0x1EE6, 0x1EE8, 0x1EEA, + 0x1EEC, 0x1EEE, 0x1EF0, 0x1EF2, 0x1EF4, 0x1EF6, 0x1EF8, 0x1EFA, + 0x1EFC, 0x1EFE, 0x1F59, 0x1F5B, 0x1F5D, 0x1F5F, 0x2102, 0x2107, + 0x2115, 0x2124, 0x2126, 0x2128, 0x2145, 0x2183, 0x2C60, 0x2C67, + 0x2C69, 0x2C6B, 0x2C72, 0x2C75, 0x2C82, 0x2C84, 0x2C86, 0x2C88, + 0x2C8A, 0x2C8C, 0x2C8E, 0x2C90, 0x2C92, 0x2C94, 0x2C96, 0x2C98, + 0x2C9A, 0x2C9C, 0x2C9E, 0x2CA0, 0x2CA2, 0x2CA4, 0x2CA6, 0x2CA8, + 0x2CAA, 0x2CAC, 0x2CAE, 0x2CB0, 0x2CB2, 0x2CB4, 0x2CB6, 0x2CB8, + 0x2CBA, 0x2CBC, 0x2CBE, 0x2CC0, 0x2CC2, 0x2CC4, 0x2CC6, 0x2CC8, + 0x2CCA, 0x2CCC, 0x2CCE, 0x2CD0, 0x2CD2, 0x2CD4, 0x2CD6, 0x2CD8, + 0x2CDA, 0x2CDC, 0x2CDE, 0x2CE0, 0x2CE2, 0x2CEB, 0x2CED, 0x2CF2, + 0xA640, 0xA642, 0xA644, 0xA646, 0xA648, 0xA64A, 0xA64C, 0xA64E, + 0xA650, 0xA652, 0xA654, 0xA656, 0xA658, 0xA65A, 0xA65C, 0xA65E, + 0xA660, 0xA662, 0xA664, 0xA666, 0xA668, 0xA66A, 0xA66C, 0xA680, + 0xA682, 0xA684, 0xA686, 0xA688, 0xA68A, 0xA68C, 0xA68E, 0xA690, + 0xA692, 0xA694, 0xA696, 0xA698, 0xA69A, 0xA722, 0xA724, 0xA726, + 0xA728, 0xA72A, 0xA72C, 0xA72E, 0xA732, 0xA734, 0xA736, 0xA738, + 0xA73A, 0xA73C, 0xA73E, 0xA740, 0xA742, 0xA744, 0xA746, 0xA748, + 0xA74A, 0xA74C, 0xA74E, 0xA750, 0xA752, 0xA754, 0xA756, 0xA758, + 0xA75A, 0xA75C, 0xA75E, 0xA760, 0xA762, 0xA764, 0xA766, 0xA768, + 0xA76A, 0xA76C, 0xA76E, 0xA779, 0xA77B, 0xA780, 0xA782, 0xA784, + 0xA786, 0xA78B, 0xA78D, 0xA790, 0xA792, 0xA796, 0xA798, 0xA79A, + 0xA79C, 0xA79E, 0xA7A0, 0xA7A2, 0xA7A4, 0xA7A6, 0xA7A8, 0xA7B6, + 0xA7B8, 0xA7BA, 0xA7BC, 0xA7BE, 0xA7C0, 0xA7C2, 0xA7C9, 0xA7CE, + 0xA7D0, 0xA7D2, 0xA7D4, 0xA7D6, 0xA7D8, 0xA7DA, 0xA7DC, 0xA7F5, +} + +@(rodata) +lu_ranges16 := [?]u16{ + 0x0041, 0x005A, + 0x00C0, 0x00D6, + 0x00D8, 0x00DE, + 0x0178, 0x0179, + 0x0181, 0x0182, + 0x0186, 0x0187, + 0x0189, 0x018B, + 0x018E, 0x0191, + 0x0193, 0x0194, + 0x0196, 0x0198, + 0x019C, 0x019D, + 0x019F, 0x01A0, + 0x01A6, 0x01A7, + 0x01AE, 0x01AF, + 0x01B1, 0x01B3, + 0x01B7, 0x01B8, + 0x01F6, 0x01F8, + 0x023A, 0x023B, + 0x023D, 0x023E, + 0x0243, 0x0246, + 0x0388, 0x038A, + 0x038E, 0x038F, + 0x0391, 0x03A1, + 0x03A3, 0x03AB, + 0x03D2, 0x03D4, + 0x03F9, 0x03FA, + 0x03FD, 0x042F, + 0x04C0, 0x04C1, + 0x0531, 0x0556, + 0x10A0, 0x10C5, + 0x13A0, 0x13F5, + 0x1C90, 0x1CBA, + 0x1CBD, 0x1CBF, + 0x1F08, 0x1F0F, + 0x1F18, 0x1F1D, + 0x1F28, 0x1F2F, + 0x1F38, 0x1F3F, + 0x1F48, 0x1F4D, + 0x1F68, 0x1F6F, + 0x1FB8, 0x1FBB, + 0x1FC8, 0x1FCB, + 0x1FD8, 0x1FDB, + 0x1FE8, 0x1FEC, + 0x1FF8, 0x1FFB, + 0x210B, 0x210D, + 0x2110, 0x2112, + 0x2119, 0x211D, + 0x212A, 0x212D, + 0x2130, 0x2133, + 0x213E, 0x213F, + 0x2C00, 0x2C2F, + 0x2C62, 0x2C64, + 0x2C6D, 0x2C70, + 0x2C7E, 0x2C80, + 0xA77D, 0xA77E, + 0xA7AA, 0xA7AE, + 0xA7B0, 0xA7B4, + 0xA7C4, 0xA7C7, + 0xA7CB, 0xA7CC, + 0xFF21, 0xFF3A, +} + +@(rodata) +lu_singles32 := [?]i32{ + 0x1D49C, 0x1D4A2, 0x1D546, 0x1D7CA, +} + +@(rodata) +lu_ranges32 := [?]i32{ + 0x10400, 0x10427, + 0x104B0, 0x104D3, + 0x10570, 0x1057A, + 0x1057C, 0x1058A, + 0x1058C, 0x10592, + 0x10594, 0x10595, + 0x10C80, 0x10CB2, + 0x10D50, 0x10D65, + 0x118A0, 0x118BF, + 0x16E40, 0x16E5F, + 0x16EA0, 0x16EB8, + 0x1D400, 0x1D419, + 0x1D434, 0x1D44D, + 0x1D468, 0x1D481, + 0x1D49E, 0x1D49F, + 0x1D4A5, 0x1D4A6, + 0x1D4A9, 0x1D4AC, + 0x1D4AE, 0x1D4B5, + 0x1D4D0, 0x1D4E9, + 0x1D504, 0x1D505, + 0x1D507, 0x1D50A, + 0x1D50D, 0x1D514, + 0x1D516, 0x1D51C, + 0x1D538, 0x1D539, + 0x1D53B, 0x1D53E, + 0x1D540, 0x1D544, + 0x1D54A, 0x1D550, + 0x1D56C, 0x1D585, + 0x1D5A0, 0x1D5B9, + 0x1D5D4, 0x1D5ED, + 0x1D608, 0x1D621, + 0x1D63C, 0x1D655, + 0x1D670, 0x1D689, + 0x1D6A8, 0x1D6C0, + 0x1D6E2, 0x1D6FA, + 0x1D71C, 0x1D734, + 0x1D756, 0x1D76E, + 0x1D790, 0x1D7A8, + 0x1E900, 0x1E921, +} + +lu_ranges := Range{ + single_16 = lu_singles16[:], + ranges_16 = lu_ranges16[:], + single_32 = lu_singles32[:], + ranges_32 = lu_ranges32[:], +} + +@(rodata) +mc_singles16 := [?]u16{ + 0x0903, 0x093B, 0x09D7, 0x0A03, 0x0A83, 0x0AC9, 0x0B3E, 0x0B40, + 0x0B57, 0x0BD7, 0x0CBE, 0x0CF3, 0x0D57, 0x0F7F, 0x1031, 0x1038, + 0x108F, 0x1715, 0x1734, 0x17B6, 0x1A55, 0x1A57, 0x1A61, 0x1B04, + 0x1B35, 0x1B3B, 0x1B82, 0x1BA1, 0x1BAA, 0x1BE7, 0x1BEE, 0x1CE1, + 0x1CF7, 0xA827, 0xA983, 0xAA4D, 0xAA7B, 0xAA7D, 0xAAEB, 0xAAF5, + 0xABEC, +} + +@(rodata) +mc_ranges16 := [?]u16{ + 0x093E, 0x0940, + 0x0949, 0x094C, + 0x094E, 0x094F, + 0x0982, 0x0983, + 0x09BE, 0x09C0, + 0x09C7, 0x09C8, + 0x09CB, 0x09CC, + 0x0A3E, 0x0A40, + 0x0ABE, 0x0AC0, + 0x0ACB, 0x0ACC, + 0x0B02, 0x0B03, + 0x0B47, 0x0B48, + 0x0B4B, 0x0B4C, + 0x0BBE, 0x0BBF, + 0x0BC1, 0x0BC2, + 0x0BC6, 0x0BC8, + 0x0BCA, 0x0BCC, + 0x0C01, 0x0C03, + 0x0C41, 0x0C44, + 0x0C82, 0x0C83, + 0x0CC0, 0x0CC4, + 0x0CC7, 0x0CC8, + 0x0CCA, 0x0CCB, + 0x0CD5, 0x0CD6, + 0x0D02, 0x0D03, + 0x0D3E, 0x0D40, + 0x0D46, 0x0D48, + 0x0D4A, 0x0D4C, + 0x0D82, 0x0D83, + 0x0DCF, 0x0DD1, + 0x0DD8, 0x0DDF, + 0x0DF2, 0x0DF3, + 0x0F3E, 0x0F3F, + 0x102B, 0x102C, + 0x103B, 0x103C, + 0x1056, 0x1057, + 0x1062, 0x1064, + 0x1067, 0x106D, + 0x1083, 0x1084, + 0x1087, 0x108C, + 0x109A, 0x109C, + 0x17BE, 0x17C5, + 0x17C7, 0x17C8, + 0x1923, 0x1926, + 0x1929, 0x192B, + 0x1930, 0x1931, + 0x1933, 0x1938, + 0x1A19, 0x1A1A, + 0x1A63, 0x1A64, + 0x1A6D, 0x1A72, + 0x1B3D, 0x1B41, + 0x1B43, 0x1B44, + 0x1BA6, 0x1BA7, + 0x1BEA, 0x1BEC, + 0x1BF2, 0x1BF3, + 0x1C24, 0x1C2B, + 0x1C34, 0x1C35, + 0x302E, 0x302F, + 0xA823, 0xA824, + 0xA880, 0xA881, + 0xA8B4, 0xA8C3, + 0xA952, 0xA953, + 0xA9B4, 0xA9B5, + 0xA9BA, 0xA9BB, + 0xA9BE, 0xA9C0, + 0xAA2F, 0xAA30, + 0xAA33, 0xAA34, + 0xAAEE, 0xAAEF, + 0xABE3, 0xABE4, + 0xABE6, 0xABE7, + 0xABE9, 0xABEA, +} + +@(rodata) +mc_singles32 := [?]i32{ + 0x11000, 0x11002, 0x11082, 0x1112C, 0x11182, 0x111CE, 0x11235, 0x11357, + 0x113C2, 0x113C5, 0x113CF, 0x11445, 0x114B9, 0x114C1, 0x115BE, 0x1163E, + 0x116AC, 0x116B6, 0x1171E, 0x11726, 0x11838, 0x1193D, 0x11940, 0x11942, + 0x119E4, 0x11A39, 0x11A97, 0x11B61, 0x11B65, 0x11B67, 0x11C2F, 0x11C3E, + 0x11CA9, 0x11CB1, 0x11CB4, 0x11D96, 0x11F03, 0x11F41, +} + +@(rodata) +mc_ranges32 := [?]i32{ + 0x110B0, 0x110B2, + 0x110B7, 0x110B8, + 0x11145, 0x11146, + 0x111B3, 0x111B5, + 0x111BF, 0x111C0, + 0x1122C, 0x1122E, + 0x11232, 0x11233, + 0x112E0, 0x112E2, + 0x11302, 0x11303, + 0x1133E, 0x1133F, + 0x11341, 0x11344, + 0x11347, 0x11348, + 0x1134B, 0x1134D, + 0x11362, 0x11363, + 0x113B8, 0x113BA, + 0x113C7, 0x113CA, + 0x113CC, 0x113CD, + 0x11435, 0x11437, + 0x11440, 0x11441, + 0x114B0, 0x114B2, + 0x114BB, 0x114BE, + 0x115AF, 0x115B1, + 0x115B8, 0x115BB, + 0x11630, 0x11632, + 0x1163B, 0x1163C, + 0x116AE, 0x116AF, + 0x11720, 0x11721, + 0x1182C, 0x1182E, + 0x11930, 0x11935, + 0x11937, 0x11938, + 0x119D1, 0x119D3, + 0x119DC, 0x119DF, + 0x11A57, 0x11A58, + 0x11D8A, 0x11D8E, + 0x11D93, 0x11D94, + 0x11EF5, 0x11EF6, + 0x11F34, 0x11F35, + 0x11F3E, 0x11F3F, + 0x1612A, 0x1612C, + 0x16F51, 0x16F87, + 0x16FF0, 0x16FF1, + 0x1D165, 0x1D166, + 0x1D16D, 0x1D172, +} + +mc_ranges := Range{ + single_16 = mc_singles16[:], + ranges_16 = mc_ranges16[:], + single_32 = mc_singles32[:], + ranges_32 = mc_ranges32[:], +} + +@(rodata) +me_singles16 := [?]u16{ + 0x1ABE, +} + +@(rodata) +me_ranges16 := [?]u16{ + 0x0488, 0x0489, + 0x20DD, 0x20E0, + 0x20E2, 0x20E4, + 0xA670, 0xA672, +} + +me_ranges := Range{ + single_16 = me_singles16[:], + ranges_16 = me_ranges16[:], +} + +@(rodata) +mn_singles16 := [?]u16{ + 0x05BF, 0x05C7, 0x0670, 0x0711, 0x07FD, 0x093A, 0x093C, 0x094D, + 0x0981, 0x09BC, 0x09CD, 0x09FE, 0x0A3C, 0x0A51, 0x0A75, 0x0ABC, + 0x0ACD, 0x0B01, 0x0B3C, 0x0B3F, 0x0B4D, 0x0B82, 0x0BC0, 0x0BCD, + 0x0C00, 0x0C04, 0x0C3C, 0x0C81, 0x0CBC, 0x0CBF, 0x0CC6, 0x0D4D, + 0x0D81, 0x0DCA, 0x0DD6, 0x0E31, 0x0EB1, 0x0F35, 0x0F37, 0x0F39, + 0x0FC6, 0x1082, 0x108D, 0x109D, 0x17C6, 0x17DD, 0x180F, 0x18A9, + 0x1932, 0x1A1B, 0x1A56, 0x1A60, 0x1A62, 0x1A7F, 0x1B34, 0x1B3C, + 0x1B42, 0x1BE6, 0x1BED, 0x1CED, 0x1CF4, 0x20E1, 0x2D7F, 0xA66F, + 0xA802, 0xA806, 0xA80B, 0xA82C, 0xA8FF, 0xA9B3, 0xA9E5, 0xAA43, + 0xAA4C, 0xAA7C, 0xAAB0, 0xAAC1, 0xAAF6, 0xABE5, 0xABE8, 0xABED, + 0xFB1E, +} + +@(rodata) +mn_ranges16 := [?]u16{ + 0x0300, 0x036F, + 0x0483, 0x0487, + 0x0591, 0x05BD, + 0x05C1, 0x05C2, + 0x05C4, 0x05C5, + 0x0610, 0x061A, + 0x064B, 0x065F, + 0x06D6, 0x06DC, + 0x06DF, 0x06E4, + 0x06E7, 0x06E8, + 0x06EA, 0x06ED, + 0x0730, 0x074A, + 0x07A6, 0x07B0, + 0x07EB, 0x07F3, + 0x0816, 0x0819, + 0x081B, 0x0823, + 0x0825, 0x0827, + 0x0829, 0x082D, + 0x0859, 0x085B, + 0x0897, 0x089F, + 0x08CA, 0x08E1, + 0x08E3, 0x0902, + 0x0941, 0x0948, + 0x0951, 0x0957, + 0x0962, 0x0963, + 0x09C1, 0x09C4, + 0x09E2, 0x09E3, + 0x0A01, 0x0A02, + 0x0A41, 0x0A42, + 0x0A47, 0x0A48, + 0x0A4B, 0x0A4D, + 0x0A70, 0x0A71, + 0x0A81, 0x0A82, + 0x0AC1, 0x0AC5, + 0x0AC7, 0x0AC8, + 0x0AE2, 0x0AE3, + 0x0AFA, 0x0AFF, + 0x0B41, 0x0B44, + 0x0B55, 0x0B56, + 0x0B62, 0x0B63, + 0x0C3E, 0x0C40, + 0x0C46, 0x0C48, + 0x0C4A, 0x0C4D, + 0x0C55, 0x0C56, + 0x0C62, 0x0C63, + 0x0CCC, 0x0CCD, + 0x0CE2, 0x0CE3, + 0x0D00, 0x0D01, + 0x0D3B, 0x0D3C, + 0x0D41, 0x0D44, + 0x0D62, 0x0D63, + 0x0DD2, 0x0DD4, + 0x0E34, 0x0E3A, + 0x0E47, 0x0E4E, + 0x0EB4, 0x0EBC, + 0x0EC8, 0x0ECE, + 0x0F18, 0x0F19, + 0x0F71, 0x0F7E, + 0x0F80, 0x0F84, + 0x0F86, 0x0F87, + 0x0F8D, 0x0F97, + 0x0F99, 0x0FBC, + 0x102D, 0x1030, + 0x1032, 0x1037, + 0x1039, 0x103A, + 0x103D, 0x103E, + 0x1058, 0x1059, + 0x105E, 0x1060, + 0x1071, 0x1074, + 0x1085, 0x1086, + 0x135D, 0x135F, + 0x1712, 0x1714, + 0x1732, 0x1733, + 0x1752, 0x1753, + 0x1772, 0x1773, + 0x17B4, 0x17B5, + 0x17B7, 0x17BD, + 0x17C9, 0x17D3, + 0x180B, 0x180D, + 0x1885, 0x1886, + 0x1920, 0x1922, + 0x1927, 0x1928, + 0x1939, 0x193B, + 0x1A17, 0x1A18, + 0x1A58, 0x1A5E, + 0x1A65, 0x1A6C, + 0x1A73, 0x1A7C, + 0x1AB0, 0x1ABD, + 0x1ABF, 0x1ADD, + 0x1AE0, 0x1AEB, + 0x1B00, 0x1B03, + 0x1B36, 0x1B3A, + 0x1B6B, 0x1B73, + 0x1B80, 0x1B81, + 0x1BA2, 0x1BA5, + 0x1BA8, 0x1BA9, + 0x1BAB, 0x1BAD, + 0x1BE8, 0x1BE9, + 0x1BEF, 0x1BF1, + 0x1C2C, 0x1C33, + 0x1C36, 0x1C37, + 0x1CD0, 0x1CD2, + 0x1CD4, 0x1CE0, + 0x1CE2, 0x1CE8, + 0x1CF8, 0x1CF9, + 0x1DC0, 0x1DFF, + 0x20D0, 0x20DC, + 0x20E5, 0x20F0, + 0x2CEF, 0x2CF1, + 0x2DE0, 0x2DFF, + 0x302A, 0x302D, + 0x3099, 0x309A, + 0xA674, 0xA67D, + 0xA69E, 0xA69F, + 0xA6F0, 0xA6F1, + 0xA825, 0xA826, + 0xA8C4, 0xA8C5, + 0xA8E0, 0xA8F1, + 0xA926, 0xA92D, + 0xA947, 0xA951, + 0xA980, 0xA982, + 0xA9B6, 0xA9B9, + 0xA9BC, 0xA9BD, + 0xAA29, 0xAA2E, + 0xAA31, 0xAA32, + 0xAA35, 0xAA36, + 0xAAB2, 0xAAB4, + 0xAAB7, 0xAAB8, + 0xAABE, 0xAABF, + 0xAAEC, 0xAAED, + 0xFE00, 0xFE0F, + 0xFE20, 0xFE2F, +} + +@(rodata) +mn_singles32 := [?]i32{ + 0x101FD, 0x102E0, 0x10A3F, 0x11001, 0x11070, 0x110C2, 0x11173, 0x111CF, + 0x11234, 0x1123E, 0x11241, 0x112DF, 0x11340, 0x113CE, 0x113D0, 0x113D2, + 0x11446, 0x1145E, 0x114BA, 0x1163D, 0x116AB, 0x116AD, 0x116B7, 0x1171D, + 0x1171F, 0x1193E, 0x11943, 0x119E0, 0x11A47, 0x11B60, 0x11B66, 0x11C3F, + 0x11D3A, 0x11D47, 0x11D95, 0x11D97, 0x11F40, 0x11F42, 0x11F5A, 0x13440, + 0x16F4F, 0x16FE4, 0x1DA75, 0x1DA84, 0x1E08F, 0x1E2AE, 0x1E6E3, 0x1E6E6, + 0x1E6F5, +} + +@(rodata) +mn_ranges32 := [?]i32{ + 0x10376, 0x1037A, + 0x10A01, 0x10A03, + 0x10A05, 0x10A06, + 0x10A0C, 0x10A0F, + 0x10A38, 0x10A3A, + 0x10AE5, 0x10AE6, + 0x10D24, 0x10D27, + 0x10D69, 0x10D6D, + 0x10EAB, 0x10EAC, + 0x10EFA, 0x10EFF, + 0x10F46, 0x10F50, + 0x10F82, 0x10F85, + 0x11038, 0x11046, + 0x11073, 0x11074, + 0x1107F, 0x11081, + 0x110B3, 0x110B6, + 0x110B9, 0x110BA, + 0x11100, 0x11102, + 0x11127, 0x1112B, + 0x1112D, 0x11134, + 0x11180, 0x11181, + 0x111B6, 0x111BE, + 0x111C9, 0x111CC, + 0x1122F, 0x11231, + 0x11236, 0x11237, + 0x112E3, 0x112EA, + 0x11300, 0x11301, + 0x1133B, 0x1133C, + 0x11366, 0x1136C, + 0x11370, 0x11374, + 0x113BB, 0x113C0, + 0x113E1, 0x113E2, + 0x11438, 0x1143F, + 0x11442, 0x11444, + 0x114B3, 0x114B8, + 0x114BF, 0x114C0, + 0x114C2, 0x114C3, + 0x115B2, 0x115B5, + 0x115BC, 0x115BD, + 0x115BF, 0x115C0, + 0x115DC, 0x115DD, + 0x11633, 0x1163A, + 0x1163F, 0x11640, + 0x116B0, 0x116B5, + 0x11722, 0x11725, + 0x11727, 0x1172B, + 0x1182F, 0x11837, + 0x11839, 0x1183A, + 0x1193B, 0x1193C, + 0x119D4, 0x119D7, + 0x119DA, 0x119DB, + 0x11A01, 0x11A0A, + 0x11A33, 0x11A38, + 0x11A3B, 0x11A3E, + 0x11A51, 0x11A56, + 0x11A59, 0x11A5B, + 0x11A8A, 0x11A96, + 0x11A98, 0x11A99, + 0x11B62, 0x11B64, + 0x11C30, 0x11C36, + 0x11C38, 0x11C3D, + 0x11C92, 0x11CA7, + 0x11CAA, 0x11CB0, + 0x11CB2, 0x11CB3, + 0x11CB5, 0x11CB6, + 0x11D31, 0x11D36, + 0x11D3C, 0x11D3D, + 0x11D3F, 0x11D45, + 0x11D90, 0x11D91, + 0x11EF3, 0x11EF4, + 0x11F00, 0x11F01, + 0x11F36, 0x11F3A, + 0x13447, 0x13455, + 0x1611E, 0x16129, + 0x1612D, 0x1612F, + 0x16AF0, 0x16AF4, + 0x16B30, 0x16B36, + 0x16F8F, 0x16F92, + 0x1BC9D, 0x1BC9E, + 0x1CF00, 0x1CF2D, + 0x1CF30, 0x1CF46, + 0x1D167, 0x1D169, + 0x1D17B, 0x1D182, + 0x1D185, 0x1D18B, + 0x1D1AA, 0x1D1AD, + 0x1D242, 0x1D244, + 0x1DA00, 0x1DA36, + 0x1DA3B, 0x1DA6C, + 0x1DA9B, 0x1DA9F, + 0x1DAA1, 0x1DAAF, + 0x1E000, 0x1E006, + 0x1E008, 0x1E018, + 0x1E01B, 0x1E021, + 0x1E023, 0x1E024, + 0x1E026, 0x1E02A, + 0x1E130, 0x1E136, + 0x1E2EC, 0x1E2EF, + 0x1E4EC, 0x1E4EF, + 0x1E5EE, 0x1E5EF, + 0x1E6EE, 0x1E6EF, + 0x1E8D0, 0x1E8D6, + 0x1E944, 0x1E94A, + 0xE0100, 0xE01EF, +} + +mn_ranges := Range{ + single_16 = mn_singles16[:], + ranges_16 = mn_ranges16[:], + single_32 = mn_singles32[:], + ranges_32 = mn_ranges32[:], +} + +@(rodata) +nd_ranges16 := [?]u16{ + 0x0030, 0x0039, + 0x0660, 0x0669, + 0x06F0, 0x06F9, + 0x07C0, 0x07C9, + 0x0966, 0x096F, + 0x09E6, 0x09EF, + 0x0A66, 0x0A6F, + 0x0AE6, 0x0AEF, + 0x0B66, 0x0B6F, + 0x0BE6, 0x0BEF, + 0x0C66, 0x0C6F, + 0x0CE6, 0x0CEF, + 0x0D66, 0x0D6F, + 0x0DE6, 0x0DEF, + 0x0E50, 0x0E59, + 0x0ED0, 0x0ED9, + 0x0F20, 0x0F29, + 0x1040, 0x1049, + 0x1090, 0x1099, + 0x17E0, 0x17E9, + 0x1810, 0x1819, + 0x1946, 0x194F, + 0x19D0, 0x19D9, + 0x1A80, 0x1A89, + 0x1A90, 0x1A99, + 0x1B50, 0x1B59, + 0x1BB0, 0x1BB9, + 0x1C40, 0x1C49, + 0x1C50, 0x1C59, + 0xA620, 0xA629, + 0xA8D0, 0xA8D9, + 0xA900, 0xA909, + 0xA9D0, 0xA9D9, + 0xA9F0, 0xA9F9, + 0xAA50, 0xAA59, + 0xABF0, 0xABF9, + 0xFF10, 0xFF19, +} + +@(rodata) +nd_ranges32 := [?]i32{ + 0x104A0, 0x104A9, + 0x10D30, 0x10D39, + 0x10D40, 0x10D49, + 0x11066, 0x1106F, + 0x110F0, 0x110F9, + 0x11136, 0x1113F, + 0x111D0, 0x111D9, + 0x112F0, 0x112F9, + 0x11450, 0x11459, + 0x114D0, 0x114D9, + 0x11650, 0x11659, + 0x116C0, 0x116C9, + 0x116D0, 0x116E3, + 0x11730, 0x11739, + 0x118E0, 0x118E9, + 0x11950, 0x11959, + 0x11BF0, 0x11BF9, + 0x11C50, 0x11C59, + 0x11D50, 0x11D59, + 0x11DA0, 0x11DA9, + 0x11DE0, 0x11DE9, + 0x11F50, 0x11F59, + 0x16130, 0x16139, + 0x16A60, 0x16A69, + 0x16AC0, 0x16AC9, + 0x16B50, 0x16B59, + 0x16D70, 0x16D79, + 0x1CCF0, 0x1CCF9, + 0x1D7CE, 0x1D7FF, + 0x1E140, 0x1E149, + 0x1E2F0, 0x1E2F9, + 0x1E4F0, 0x1E4F9, + 0x1E5F1, 0x1E5FA, + 0x1E950, 0x1E959, + 0x1FBF0, 0x1FBF9, +} + +nd_ranges := Range{ + ranges_16 = nd_ranges16[:], + ranges_32 = nd_ranges32[:], +} + +@(rodata) +nl_singles16 := [?]u16{ + 0x3007, +} + +@(rodata) +nl_ranges16 := [?]u16{ + 0x16EE, 0x16F0, + 0x2160, 0x2182, + 0x2185, 0x2188, + 0x3021, 0x3029, + 0x3038, 0x303A, + 0xA6E6, 0xA6EF, +} + +@(rodata) +nl_singles32 := [?]i32{ + 0x10341, 0x1034A, +} + +@(rodata) +nl_ranges32 := [?]i32{ + 0x10140, 0x10174, + 0x103D1, 0x103D5, + 0x12400, 0x1246E, + 0x16FF4, 0x16FF6, +} + +nl_ranges := Range{ + single_16 = nl_singles16[:], + ranges_16 = nl_ranges16[:], + single_32 = nl_singles32[:], + ranges_32 = nl_ranges32[:], +} + +@(rodata) +no_singles16 := [?]u16{ + 0x00B9, 0x19DA, 0x2070, 0x2189, 0x2CFD, +} + +@(rodata) +no_ranges16 := [?]u16{ + 0x00B2, 0x00B3, + 0x00BC, 0x00BE, + 0x09F4, 0x09F9, + 0x0B72, 0x0B77, + 0x0BF0, 0x0BF2, + 0x0C78, 0x0C7E, + 0x0D58, 0x0D5E, + 0x0D70, 0x0D78, + 0x0F2A, 0x0F33, + 0x1369, 0x137C, + 0x17F0, 0x17F9, + 0x2074, 0x2079, + 0x2080, 0x2089, + 0x2150, 0x215F, + 0x2460, 0x249B, + 0x24EA, 0x24FF, + 0x2776, 0x2793, + 0x3192, 0x3195, + 0x3220, 0x3229, + 0x3248, 0x324F, + 0x3251, 0x325F, + 0x3280, 0x3289, + 0x32B1, 0x32BF, + 0xA830, 0xA835, +} + +@(rodata) +no_ranges32 := [?]i32{ + 0x10107, 0x10133, + 0x10175, 0x10178, + 0x1018A, 0x1018B, + 0x102E1, 0x102FB, + 0x10320, 0x10323, + 0x10858, 0x1085F, + 0x10879, 0x1087F, + 0x108A7, 0x108AF, + 0x108FB, 0x108FF, + 0x10916, 0x1091B, + 0x109BC, 0x109BD, + 0x109C0, 0x109CF, + 0x109D2, 0x109FF, + 0x10A40, 0x10A48, + 0x10A7D, 0x10A7E, + 0x10A9D, 0x10A9F, + 0x10AEB, 0x10AEF, + 0x10B58, 0x10B5F, + 0x10B78, 0x10B7F, + 0x10BA9, 0x10BAF, + 0x10CFA, 0x10CFF, + 0x10E60, 0x10E7E, + 0x10F1D, 0x10F26, + 0x10F51, 0x10F54, + 0x10FC5, 0x10FCB, + 0x11052, 0x11065, + 0x111E1, 0x111F4, + 0x1173A, 0x1173B, + 0x118EA, 0x118F2, + 0x11C5A, 0x11C6C, + 0x11FC0, 0x11FD4, + 0x16B5B, 0x16B61, + 0x16E80, 0x16E96, + 0x1D2C0, 0x1D2D3, + 0x1D2E0, 0x1D2F3, + 0x1D360, 0x1D378, + 0x1E8C7, 0x1E8CF, + 0x1EC71, 0x1ECAB, + 0x1ECAD, 0x1ECAF, + 0x1ECB1, 0x1ECB4, + 0x1ED01, 0x1ED2D, + 0x1ED2F, 0x1ED3D, + 0x1F100, 0x1F10C, +} + +no_ranges := Range{ + single_16 = no_singles16[:], + ranges_16 = no_ranges16[:], + ranges_32 = no_ranges32[:], +} + +@(rodata) +pc_singles16 := [?]u16{ + 0x005F, 0x2054, 0xFF3F, +} + +@(rodata) +pc_ranges16 := [?]u16{ + 0x203F, 0x2040, + 0xFE33, 0xFE34, + 0xFE4D, 0xFE4F, +} + +pc_ranges := Range{ + single_16 = pc_singles16[:], + ranges_16 = pc_ranges16[:], +} + +@(rodata) +pd_singles16 := [?]u16{ + 0x002D, 0x058A, 0x05BE, 0x1400, 0x1806, 0x2E17, 0x2E1A, 0x2E40, + 0x2E5D, 0x301C, 0x3030, 0x30A0, 0xFE58, 0xFE63, 0xFF0D, +} + +@(rodata) +pd_ranges16 := [?]u16{ + 0x2010, 0x2015, + 0x2E3A, 0x2E3B, + 0xFE31, 0xFE32, +} + +@(rodata) +pd_singles32 := [?]i32{ + 0x10D6E, 0x10EAD, +} + +pd_ranges := Range{ + single_16 = pd_singles16[:], + ranges_16 = pd_ranges16[:], + single_32 = pd_singles32[:], +} + +@(rodata) +pe_singles16 := [?]u16{ + 0x0029, 0x005D, 0x007D, 0x0F3B, 0x0F3D, 0x169C, 0x2046, 0x207E, + 0x208E, 0x2309, 0x230B, 0x232A, 0x2769, 0x276B, 0x276D, 0x276F, + 0x2771, 0x2773, 0x2775, 0x27C6, 0x27E7, 0x27E9, 0x27EB, 0x27ED, + 0x27EF, 0x2984, 0x2986, 0x2988, 0x298A, 0x298C, 0x298E, 0x2990, + 0x2992, 0x2994, 0x2996, 0x2998, 0x29D9, 0x29DB, 0x29FD, 0x2E23, + 0x2E25, 0x2E27, 0x2E29, 0x2E56, 0x2E58, 0x2E5A, 0x2E5C, 0x3009, + 0x300B, 0x300D, 0x300F, 0x3011, 0x3015, 0x3017, 0x3019, 0x301B, + 0xFD3E, 0xFE18, 0xFE36, 0xFE38, 0xFE3A, 0xFE3C, 0xFE3E, 0xFE40, + 0xFE42, 0xFE44, 0xFE48, 0xFE5A, 0xFE5C, 0xFE5E, 0xFF09, 0xFF3D, + 0xFF5D, 0xFF60, 0xFF63, +} + +@(rodata) +pe_ranges16 := [?]u16{ + 0x301E, 0x301F, +} + +pe_ranges := Range{ + single_16 = pe_singles16[:], + ranges_16 = pe_ranges16[:], +} + +@(rodata) +pf_singles16 := [?]u16{ + 0x00BB, 0x2019, 0x201D, 0x203A, 0x2E03, 0x2E05, 0x2E0A, 0x2E0D, + 0x2E1D, 0x2E21, +} + +pf_ranges := Range{ + single_16 = pf_singles16[:], +} + +@(rodata) +pi_singles16 := [?]u16{ + 0x00AB, 0x2018, 0x201F, 0x2039, 0x2E02, 0x2E04, 0x2E09, 0x2E0C, + 0x2E1C, 0x2E20, +} + +@(rodata) +pi_ranges16 := [?]u16{ + 0x201B, 0x201C, +} + +pi_ranges := Range{ + single_16 = pi_singles16[:], + ranges_16 = pi_ranges16[:], +} + +@(rodata) +po_singles16 := [?]u16{ + 0x002A, 0x002C, 0x005C, 0x00A1, 0x00A7, 0x00BF, 0x037E, 0x0387, + 0x0589, 0x05C0, 0x05C3, 0x05C6, 0x061B, 0x06D4, 0x085E, 0x0970, + 0x09FD, 0x0A76, 0x0AF0, 0x0C77, 0x0C84, 0x0DF4, 0x0E4F, 0x0F14, + 0x0F85, 0x10FB, 0x166E, 0x1CD3, 0x2053, 0x2D70, 0x2E0B, 0x2E1B, + 0x2E41, 0x303D, 0x30FB, 0xA673, 0xA67E, 0xA8FC, 0xA95F, 0xABEB, + 0xFE19, 0xFE30, 0xFE68, 0xFF0A, 0xFF0C, 0xFF3C, 0xFF61, +} + +@(rodata) +po_ranges16 := [?]u16{ + 0x0021, 0x0023, + 0x0025, 0x0027, + 0x002E, 0x002F, + 0x003A, 0x003B, + 0x003F, 0x0040, + 0x00B6, 0x00B7, + 0x055A, 0x055F, + 0x05F3, 0x05F4, + 0x0609, 0x060A, + 0x060C, 0x060D, + 0x061D, 0x061F, + 0x066A, 0x066D, + 0x0700, 0x070D, + 0x07F7, 0x07F9, + 0x0830, 0x083E, + 0x0964, 0x0965, + 0x0E5A, 0x0E5B, + 0x0F04, 0x0F12, + 0x0FD0, 0x0FD4, + 0x0FD9, 0x0FDA, + 0x104A, 0x104F, + 0x1360, 0x1368, + 0x16EB, 0x16ED, + 0x1735, 0x1736, + 0x17D4, 0x17D6, + 0x17D8, 0x17DA, + 0x1800, 0x1805, + 0x1807, 0x180A, + 0x1944, 0x1945, + 0x1A1E, 0x1A1F, + 0x1AA0, 0x1AA6, + 0x1AA8, 0x1AAD, + 0x1B4E, 0x1B4F, + 0x1B5A, 0x1B60, + 0x1B7D, 0x1B7F, + 0x1BFC, 0x1BFF, + 0x1C3B, 0x1C3F, + 0x1C7E, 0x1C7F, + 0x1CC0, 0x1CC7, + 0x2016, 0x2017, + 0x2020, 0x2027, + 0x2030, 0x2038, + 0x203B, 0x203E, + 0x2041, 0x2043, + 0x2047, 0x2051, + 0x2055, 0x205E, + 0x2CF9, 0x2CFC, + 0x2CFE, 0x2CFF, + 0x2E00, 0x2E01, + 0x2E06, 0x2E08, + 0x2E0E, 0x2E16, + 0x2E18, 0x2E19, + 0x2E1E, 0x2E1F, + 0x2E2A, 0x2E2E, + 0x2E30, 0x2E39, + 0x2E3C, 0x2E3F, + 0x2E43, 0x2E4F, + 0x2E52, 0x2E54, + 0x3001, 0x3003, + 0xA4FE, 0xA4FF, + 0xA60D, 0xA60F, + 0xA6F2, 0xA6F7, + 0xA874, 0xA877, + 0xA8CE, 0xA8CF, + 0xA8F8, 0xA8FA, + 0xA92E, 0xA92F, + 0xA9C1, 0xA9CD, + 0xA9DE, 0xA9DF, + 0xAA5C, 0xAA5F, + 0xAADE, 0xAADF, + 0xAAF0, 0xAAF1, + 0xFE10, 0xFE16, + 0xFE45, 0xFE46, + 0xFE49, 0xFE4C, + 0xFE50, 0xFE52, + 0xFE54, 0xFE57, + 0xFE5F, 0xFE61, + 0xFE6A, 0xFE6B, + 0xFF01, 0xFF03, + 0xFF05, 0xFF07, + 0xFF0E, 0xFF0F, + 0xFF1A, 0xFF1B, + 0xFF1F, 0xFF20, + 0xFF64, 0xFF65, +} + +@(rodata) +po_singles32 := [?]i32{ + 0x1039F, 0x103D0, 0x1056F, 0x10857, 0x1091F, 0x1093F, 0x10A7F, 0x10ED0, + 0x111CD, 0x111DB, 0x112A9, 0x1145D, 0x114C6, 0x116B9, 0x1183B, 0x119E2, + 0x11BE1, 0x11FFF, 0x16AF5, 0x16B44, 0x16FE2, 0x1BC9F, 0x1E5FF, +} + +@(rodata) +po_ranges32 := [?]i32{ + 0x10100, 0x10102, + 0x10A50, 0x10A58, + 0x10AF0, 0x10AF6, + 0x10B39, 0x10B3F, + 0x10B99, 0x10B9C, + 0x10F55, 0x10F59, + 0x10F86, 0x10F89, + 0x11047, 0x1104D, + 0x110BB, 0x110BC, + 0x110BE, 0x110C1, + 0x11140, 0x11143, + 0x11174, 0x11175, + 0x111C5, 0x111C8, + 0x111DD, 0x111DF, + 0x11238, 0x1123D, + 0x113D4, 0x113D5, + 0x113D7, 0x113D8, + 0x1144B, 0x1144F, + 0x1145A, 0x1145B, + 0x115C1, 0x115D7, + 0x11641, 0x11643, + 0x11660, 0x1166C, + 0x1173C, 0x1173E, + 0x11944, 0x11946, + 0x11A3F, 0x11A46, + 0x11A9A, 0x11A9C, + 0x11A9E, 0x11AA2, + 0x11B00, 0x11B09, + 0x11C41, 0x11C45, + 0x11C70, 0x11C71, + 0x11EF7, 0x11EF8, + 0x11F43, 0x11F4F, + 0x12470, 0x12474, + 0x12FF1, 0x12FF2, + 0x16A6E, 0x16A6F, + 0x16B37, 0x16B3B, + 0x16D6D, 0x16D6F, + 0x16E97, 0x16E9A, + 0x1DA87, 0x1DA8B, + 0x1E95E, 0x1E95F, +} + +po_ranges := Range{ + single_16 = po_singles16[:], + ranges_16 = po_ranges16[:], + single_32 = po_singles32[:], + ranges_32 = po_ranges32[:], +} + +@(rodata) +ps_singles16 := [?]u16{ + 0x0028, 0x005B, 0x007B, 0x0F3A, 0x0F3C, 0x169B, 0x201A, 0x201E, + 0x2045, 0x207D, 0x208D, 0x2308, 0x230A, 0x2329, 0x2768, 0x276A, + 0x276C, 0x276E, 0x2770, 0x2772, 0x2774, 0x27C5, 0x27E6, 0x27E8, + 0x27EA, 0x27EC, 0x27EE, 0x2983, 0x2985, 0x2987, 0x2989, 0x298B, + 0x298D, 0x298F, 0x2991, 0x2993, 0x2995, 0x2997, 0x29D8, 0x29DA, + 0x29FC, 0x2E22, 0x2E24, 0x2E26, 0x2E28, 0x2E42, 0x2E55, 0x2E57, + 0x2E59, 0x2E5B, 0x3008, 0x300A, 0x300C, 0x300E, 0x3010, 0x3014, + 0x3016, 0x3018, 0x301A, 0x301D, 0xFD3F, 0xFE17, 0xFE35, 0xFE37, + 0xFE39, 0xFE3B, 0xFE3D, 0xFE3F, 0xFE41, 0xFE43, 0xFE47, 0xFE59, + 0xFE5B, 0xFE5D, 0xFF08, 0xFF3B, 0xFF5B, 0xFF5F, 0xFF62, +} + +ps_ranges := Range{ + single_16 = ps_singles16[:], +} + +@(rodata) +sc_singles16 := [?]u16{ + 0x0024, 0x058F, 0x060B, 0x09FB, 0x0AF1, 0x0BF9, 0x0E3F, 0x17DB, + 0xA838, 0xFDFC, 0xFE69, 0xFF04, +} + +@(rodata) +sc_ranges16 := [?]u16{ + 0x00A2, 0x00A5, + 0x07FE, 0x07FF, + 0x09F2, 0x09F3, + 0x20A0, 0x20C1, + 0xFFE0, 0xFFE1, + 0xFFE5, 0xFFE6, +} + +@(rodata) +sc_singles32 := [?]i32{ + 0x1E2FF, 0x1ECB0, +} + +@(rodata) +sc_ranges32 := [?]i32{ + 0x11FDD, 0x11FE0, +} + +sc_ranges := Range{ + single_16 = sc_singles16[:], + ranges_16 = sc_ranges16[:], + single_32 = sc_singles32[:], + ranges_32 = sc_ranges32[:], +} + +@(rodata) +sk_singles16 := [?]u16{ + 0x005E, 0x0060, 0x00A8, 0x00AF, 0x00B4, 0x00B8, 0x02ED, 0x0375, + 0x0888, 0x1FBD, 0xAB5B, 0xFF3E, 0xFF40, 0xFFE3, +} + +@(rodata) +sk_ranges16 := [?]u16{ + 0x02C2, 0x02C5, + 0x02D2, 0x02DF, + 0x02E5, 0x02EB, + 0x02EF, 0x02FF, + 0x0384, 0x0385, + 0x1FBF, 0x1FC1, + 0x1FCD, 0x1FCF, + 0x1FDD, 0x1FDF, + 0x1FED, 0x1FEF, + 0x1FFD, 0x1FFE, + 0x309B, 0x309C, + 0xA700, 0xA716, + 0xA720, 0xA721, + 0xA789, 0xA78A, + 0xAB6A, 0xAB6B, + 0xFBB2, 0xFBC2, +} + +@(rodata) +sk_ranges32 := [?]i32{ + 0x1F3FB, 0x1F3FF, +} + +sk_ranges := Range{ + single_16 = sk_singles16[:], + ranges_16 = sk_ranges16[:], + ranges_32 = sk_ranges32[:], +} + +@(rodata) +sm_singles16 := [?]u16{ + 0x002B, 0x007C, 0x007E, 0x00AC, 0x00B1, 0x00D7, 0x00F7, 0x03F6, + 0x2044, 0x2052, 0x2118, 0x214B, 0x21A0, 0x21A3, 0x21A6, 0x21AE, + 0x21D2, 0x21D4, 0x237C, 0x25B7, 0x25C1, 0x266F, 0xFB29, 0xFE62, + 0xFF0B, 0xFF5C, 0xFF5E, 0xFFE2, +} + +@(rodata) +sm_ranges16 := [?]u16{ + 0x003C, 0x003E, + 0x0606, 0x0608, + 0x207A, 0x207C, + 0x208A, 0x208C, + 0x2140, 0x2144, + 0x2190, 0x2194, + 0x219A, 0x219B, + 0x21CE, 0x21CF, + 0x21F4, 0x22FF, + 0x2320, 0x2321, + 0x239B, 0x23B3, + 0x23DC, 0x23E1, + 0x25F8, 0x25FF, + 0x27C0, 0x27C4, + 0x27C7, 0x27E5, + 0x27F0, 0x27FF, + 0x2900, 0x2982, + 0x2999, 0x29D7, + 0x29DC, 0x29FB, + 0x29FE, 0x2AFF, + 0x2B30, 0x2B44, + 0x2B47, 0x2B4C, + 0xFE64, 0xFE66, + 0xFF1C, 0xFF1E, + 0xFFE9, 0xFFEC, +} + +@(rodata) +sm_singles32 := [?]i32{ + 0x1CEF0, 0x1D6C1, 0x1D6DB, 0x1D6FB, 0x1D715, 0x1D735, 0x1D74F, 0x1D76F, + 0x1D789, 0x1D7A9, 0x1D7C3, +} + +@(rodata) +sm_ranges32 := [?]i32{ + 0x10D8E, 0x10D8F, + 0x1EEF0, 0x1EEF1, + 0x1F8D0, 0x1F8D8, +} + +sm_ranges := Range{ + single_16 = sm_singles16[:], + ranges_16 = sm_ranges16[:], + single_32 = sm_singles32[:], + ranges_32 = sm_ranges32[:], +} + +@(rodata) +so_singles16 := [?]u16{ + 0x00A6, 0x00A9, 0x00AE, 0x00B0, 0x0482, 0x06DE, 0x06E9, 0x07F6, + 0x09FA, 0x0B70, 0x0BFA, 0x0C7F, 0x0D4F, 0x0D79, 0x0F13, 0x0F34, + 0x0F36, 0x0F38, 0x166D, 0x1940, 0x2114, 0x2125, 0x2127, 0x2129, + 0x212E, 0x214A, 0x214F, 0x21D3, 0x3004, 0x3020, 0x31EF, 0x3250, + 0xA839, 0xFFE4, 0xFFE8, +} + +@(rodata) +so_ranges16 := [?]u16{ + 0x058D, 0x058E, + 0x060E, 0x060F, + 0x06FD, 0x06FE, + 0x0BF3, 0x0BF8, + 0x0F01, 0x0F03, + 0x0F15, 0x0F17, + 0x0F1A, 0x0F1F, + 0x0FBE, 0x0FC5, + 0x0FC7, 0x0FCC, + 0x0FCE, 0x0FCF, + 0x0FD5, 0x0FD8, + 0x109E, 0x109F, + 0x1390, 0x1399, + 0x19DE, 0x19FF, + 0x1B61, 0x1B6A, + 0x1B74, 0x1B7C, + 0x2100, 0x2101, + 0x2103, 0x2106, + 0x2108, 0x2109, + 0x2116, 0x2117, + 0x211E, 0x2123, + 0x213A, 0x213B, + 0x214C, 0x214D, + 0x218A, 0x218B, + 0x2195, 0x2199, + 0x219C, 0x219F, + 0x21A1, 0x21A2, + 0x21A4, 0x21A5, + 0x21A7, 0x21AD, + 0x21AF, 0x21CD, + 0x21D0, 0x21D1, + 0x21D5, 0x21F3, + 0x2300, 0x2307, + 0x230C, 0x231F, + 0x2322, 0x2328, + 0x232B, 0x237B, + 0x237D, 0x239A, + 0x23B4, 0x23DB, + 0x23E2, 0x2429, + 0x2440, 0x244A, + 0x249C, 0x24E9, + 0x2500, 0x25B6, + 0x25B8, 0x25C0, + 0x25C2, 0x25F7, + 0x2600, 0x266E, + 0x2670, 0x2767, + 0x2794, 0x27BF, + 0x2800, 0x28FF, + 0x2B00, 0x2B2F, + 0x2B45, 0x2B46, + 0x2B4D, 0x2B73, + 0x2B76, 0x2BFF, + 0x2CE5, 0x2CEA, + 0x2E50, 0x2E51, + 0x2E80, 0x2E99, + 0x2E9B, 0x2EF3, + 0x2F00, 0x2FD5, + 0x2FF0, 0x2FFF, + 0x3012, 0x3013, + 0x3036, 0x3037, + 0x303E, 0x303F, + 0x3190, 0x3191, + 0x3196, 0x319F, + 0x31C0, 0x31E5, + 0x3200, 0x321E, + 0x322A, 0x3247, + 0x3260, 0x327F, + 0x328A, 0x32B0, + 0x32C0, 0x33FF, + 0x4DC0, 0x4DFF, + 0xA490, 0xA4C6, + 0xA828, 0xA82B, + 0xA836, 0xA837, + 0xAA77, 0xAA79, + 0xFBC3, 0xFBD2, + 0xFD40, 0xFD4F, + 0xFD90, 0xFD91, + 0xFDC8, 0xFDCF, + 0xFDFD, 0xFDFF, + 0xFFED, 0xFFEE, + 0xFFFC, 0xFFFD, +} + +@(rodata) +so_singles32 := [?]i32{ + 0x101A0, 0x10AC8, 0x1173F, 0x16B45, 0x1BC9C, 0x1D245, 0x1E14F, 0x1ECAC, + 0x1ED2E, 0x1F7F0, 0x1FAC8, 0x1FBFA, +} + +@(rodata) +so_ranges32 := [?]i32{ + 0x10137, 0x1013F, + 0x10179, 0x10189, + 0x1018C, 0x1018E, + 0x10190, 0x1019C, + 0x101D0, 0x101FC, + 0x10877, 0x10878, + 0x10ED1, 0x10ED8, + 0x11FD5, 0x11FDC, + 0x11FE1, 0x11FF1, + 0x16B3C, 0x16B3F, + 0x1CC00, 0x1CCEF, + 0x1CCFA, 0x1CCFC, + 0x1CD00, 0x1CEB3, + 0x1CEBA, 0x1CED0, + 0x1CEE0, 0x1CEEF, + 0x1CF50, 0x1CFC3, + 0x1D000, 0x1D0F5, + 0x1D100, 0x1D126, + 0x1D129, 0x1D164, + 0x1D16A, 0x1D16C, + 0x1D183, 0x1D184, + 0x1D18C, 0x1D1A9, + 0x1D1AE, 0x1D1EA, + 0x1D200, 0x1D241, + 0x1D300, 0x1D356, + 0x1D800, 0x1D9FF, + 0x1DA37, 0x1DA3A, + 0x1DA6D, 0x1DA74, + 0x1DA76, 0x1DA83, + 0x1DA85, 0x1DA86, + 0x1F000, 0x1F02B, + 0x1F030, 0x1F093, + 0x1F0A0, 0x1F0AE, + 0x1F0B1, 0x1F0BF, + 0x1F0C1, 0x1F0CF, + 0x1F0D1, 0x1F0F5, + 0x1F10D, 0x1F1AD, + 0x1F1E6, 0x1F202, + 0x1F210, 0x1F23B, + 0x1F240, 0x1F248, + 0x1F250, 0x1F251, + 0x1F260, 0x1F265, + 0x1F300, 0x1F3FA, + 0x1F400, 0x1F6D8, + 0x1F6DC, 0x1F6EC, + 0x1F6F0, 0x1F6FC, + 0x1F700, 0x1F7D9, + 0x1F7E0, 0x1F7EB, + 0x1F800, 0x1F80B, + 0x1F810, 0x1F847, + 0x1F850, 0x1F859, + 0x1F860, 0x1F887, + 0x1F890, 0x1F8AD, + 0x1F8B0, 0x1F8BB, + 0x1F8C0, 0x1F8C1, + 0x1F900, 0x1FA57, + 0x1FA60, 0x1FA6D, + 0x1FA70, 0x1FA7C, + 0x1FA80, 0x1FA8A, + 0x1FA8E, 0x1FAC6, + 0x1FACD, 0x1FADC, + 0x1FADF, 0x1FAEA, + 0x1FAEF, 0x1FAF8, + 0x1FB00, 0x1FB92, + 0x1FB94, 0x1FBEF, +} + +so_ranges := Range{ + single_16 = so_singles16[:], + ranges_16 = so_ranges16[:], + single_32 = so_singles32[:], + ranges_32 = so_ranges32[:], +} + +@(rodata) +zs_singles16 := [?]u16{ + 0x0020, 0x00A0, 0x1680, 0x202F, 0x205F, 0x3000, +} + +@(rodata) +zs_ranges16 := [?]u16{ + 0x2000, 0x200A, +} + +zs_ranges := Range{ + single_16 = zs_singles16[:], + ranges_16 = zs_ranges16[:], +} + +@(rodata) +extra_digits_singles16 := [?]u16{ + 0x00B9, 0x19DA, 0x2070, 0x24EA, 0x24FF, +} + +@(rodata) +extra_digits_ranges16 := [?]u16{ + 0x00B2, 0x00B3, + 0x1369, 0x1371, + 0x2074, 0x2079, + 0x2080, 0x2089, + 0x2460, 0x2468, + 0x2474, 0x247C, + 0x2488, 0x2490, + 0x24F5, 0x24FD, + 0x2776, 0x277E, + 0x2780, 0x2788, + 0x278A, 0x2792, +} + +@(rodata) +extra_digits_ranges32 := [?]i32{ + 0x10A40, 0x10A43, + 0x10E60, 0x10E68, + 0x11052, 0x1105A, + 0x1F100, 0x1F10A, +} + +extra_digits_ranges := Range{ + single_16 = extra_digits_singles16[:], + ranges_16 = extra_digits_ranges16[:], + ranges_32 = extra_digits_ranges32[:], +} + +@(rodata) +other_lowercase_singles16 := [?]u16{ + 0x00AA, 0x00BA, 0x0345, 0x037A, 0x10FC, 0x1D78, 0x2071, 0x207F, + 0xA770, 0xAB69, +} + +@(rodata) +other_lowercase_ranges16 := [?]u16{ + 0x02B0, 0x02B8, + 0x02C0, 0x02C1, + 0x02E0, 0x02E4, + 0x1D2C, 0x1D6A, + 0x1D9B, 0x1DBF, + 0x2090, 0x209C, + 0x2170, 0x217F, + 0x24D0, 0x24E9, + 0x2C7C, 0x2C7D, + 0xA69C, 0xA69D, + 0xA7F1, 0xA7F4, + 0xA7F8, 0xA7F9, + 0xAB5C, 0xAB5F, +} + +@(rodata) +other_lowercase_singles32 := [?]i32{ + 0x10780, +} + +@(rodata) +other_lowercase_ranges32 := [?]i32{ + 0x10783, 0x10785, + 0x10787, 0x107B0, + 0x107B2, 0x107BA, + 0x1E030, 0x1E06D, +} + +other_lowercase_ranges := Range{ + single_16 = other_lowercase_singles16[:], + ranges_16 = other_lowercase_ranges16[:], + single_32 = other_lowercase_singles32[:], + ranges_32 = other_lowercase_ranges32[:], +} + +@(rodata) +other_uppercase_ranges16 := [?]u16{ + 0x2160, 0x216F, + 0x24B6, 0x24CF, +} + +@(rodata) +other_uppercase_ranges32 := [?]i32{ + 0x1F130, 0x1F149, + 0x1F150, 0x1F169, + 0x1F170, 0x1F189, +} + +other_uppercase_ranges := Range{ + ranges_16 = other_uppercase_ranges16[:], + ranges_32 = other_uppercase_ranges32[:], +} + diff --git a/core/unicode/inrange.odin b/core/unicode/inrange.odin new file mode 100644 index 000000000..fa433a741 --- /dev/null +++ b/core/unicode/inrange.odin @@ -0,0 +1,45 @@ +package unicode + +/* +Check to see if the rune `r` is in `range` +*/ +in_range :: proc(r: rune, range: Range) -> bool { + + if r <= 0xFFFF { + r16 := cast(u16) r + + length := len(range.ranges_16) + index := binary_search(r16, range.ranges_16, length/2, 2) if length > 0 else -1 + if index >= 0 && range.ranges_16[index] <= r16 && range.ranges_16[index+1] >= r16 { + return true + } + + length = len(range.single_16) + index = binary_search(r16, range.single_16, length, 1) if length > 0 else -1 + if index >= 0 && range.single_16[index] == r16 { + return true + } + } + + r32 := cast(i32) r + + length := len(range.ranges_32) + index := binary_search(r32, range.ranges_32, length/2, 2) if length >0 else -1 + if index >= 0 && range.ranges_32[index] <= r32 && range.ranges_32[index+1] >= r32 { + return true + } + + length = len(range.single_32) + index = binary_search(r32, range.single_32, length, 1) if length > 0 else -1 + if index >= 0 && range.single_32[index] == r32 { + return true + } + + + return false +} + + + + + diff --git a/core/unicode/letter.odin b/core/unicode/letter.odin index a1024dd6c..92aee9a68 100644 --- a/core/unicode/letter.odin +++ b/core/unicode/letter.odin @@ -2,7 +2,7 @@ package unicode import "base:runtime" -MAX_RUNE :: '\U00010fff' // Maximum valid unicode code point +MAX_RUNE :: '\U0010ffff' // Maximum valid unicode code point REPLACEMENT_CHAR :: '\ufffd' // Represented an invalid code point MAX_ASCII :: '\u007f' // Maximum ASCII value MAX_LATIN1 :: '\u00ff' // Maximum Latin-1 value @@ -13,7 +13,7 @@ ZERO_WIDTH_JOINER :: '\u200D' WORD_JOINER :: '\u2060' @(require_results) -binary_search :: proc(c: i32, table: []i32, length, stride: int, loc := #caller_location) -> int #no_bounds_check { +binary_search :: proc(c: $T, table: []T, length, stride: int, loc := #caller_location) -> int #no_bounds_check { runtime.bounds_check_error_loc(loc, length*stride-1, len(table)) n := length t := 0 @@ -75,16 +75,7 @@ is_lower :: proc(r: rune) -> bool #no_bounds_check { if r <= MAX_ASCII { return u32(r)-'a' < 26 } - c := i32(r) - p := binary_search(c, to_upper_ranges[:], len(to_upper_ranges)/3, 3) - if p >= 0 && to_upper_ranges[p] <= c && c <= to_upper_ranges[p+1] { - return true - } - p = binary_search(c, to_upper_singlets[:], len(to_upper_singlets)/2, 2) - if p >= 0 && c == to_upper_singlets[p] { - return true - } - return false + return in_range(r, ll_ranges) || in_range(r, other_lowercase_ranges) } @(require_results) @@ -92,19 +83,22 @@ is_upper :: proc(r: rune) -> bool #no_bounds_check { if r <= MAX_ASCII { return u32(r)-'A' < 26 } - c := i32(r) - p := binary_search(c, to_lower_ranges[:], len(to_lower_ranges)/3, 3) - if p >= 0 && to_lower_ranges[p] <= c && c <= to_lower_ranges[p+1] { - return true - } - p = binary_search(c, to_lower_singlets[:], len(to_lower_singlets)/2, 2) - if p >= 0 && c == to_lower_singlets[p] { - return true - } - return false + return in_range(r, lu_ranges) || in_range(r, other_uppercase_ranges) } is_alpha :: is_letter + +/* +Return true if the rune `r` is a letter. Being a letter means that the rune has +the Unicode general category property of L. In practice, the character will have +a general category property of Ll, Lm, Lo, Lt, or Lu. + +Inputs: +- r: The rune which will be check for having the property of being a letter. + +Returns: +`true` when the rune `r` is a letter. `false` will be returned in all other cases. +*/ @(require_results) is_letter :: proc(r: rune) -> bool #no_bounds_check { if u32(r) <= MAX_LATIN1 { @@ -114,16 +108,9 @@ is_letter :: proc(r: rune) -> bool #no_bounds_check { return true } - c := i32(r) - p := binary_search(c, alpha_ranges[:], len(alpha_ranges)/2, 2) - if p >= 0 && alpha_ranges[p] <= c && c <= alpha_ranges[p+1] { - return true - } - p = binary_search(c, alpha_singlets[:], len(alpha_singlets), 1) - if p >= 0 && c == alpha_singlets[p] { - return true - } - return false + ll_lu := in_range(r, ll_ranges) || in_range(r, lu_ranges) + + return ll_lu || in_range(r, lo_ranges) || in_range(r, lt_ranges) || in_range(r, lm_ranges) } @(require_results) @@ -131,11 +118,45 @@ is_title :: proc(r: rune) -> bool { return is_upper(r) && is_lower(r) } +/* +Returns true if the rune `r` is in the General Category Nd + +Inputs: +- r: The run to check if it is in the general category Nd. + +Returns: +`true` if the rune is in the general category Nd and `false` otherwise + +*/ +is_decimal :: proc(r: rune) -> bool { + return in_range(r, nd_ranges) +} + +/* +This function determincs if a rune is a digit. To be a digit the +charage either has a Numeric_Type of Digit or Decimal. + +Inputs: +- r: The rune to check if it is a digit. + +Returns: +`true` if the rune `r` is a digit, `false` in all other cases + +*/ @(require_results) is_digit :: proc(r: rune) -> bool { if r <= MAX_LATIN1 { - return '0' <= r && r <= '9' + return ('0' <= r && r <= '9') || r == 0x00B9 || (r >= 0x00B2 && r <= 0x0B3) } + + if in_range(r, nd_ranges) { + return true + } + + if in_range(r, extra_digits_ranges) { + return true + } + return false } @@ -176,6 +197,15 @@ is_graphic :: proc(r: rune) -> bool { if u32(r) <= MAX_LATIN1 { return char_properties[u8(r)]&pg != 0 } + + if is_letter(r) || is_number(r) || is_punct(r) || is_symbol(r) || in_range(r, zs_ranges) { + return true + } + + if in_range(r, mc_ranges) || in_range(r, me_ranges) || in_range(r, mn_ranges) { + return true + } + return false } @@ -195,12 +225,25 @@ is_control :: proc(r: rune) -> bool #no_bounds_check { return false } +/* +Checks to see if the rune `r` is a number. This means the rune is a member +of the general category Nd, Nl, or No. + +Inputs: +r: The rune to check if it is number. + +Returns: +`true` if the ruen belongs to the general category Nd, Nl, or No. `false` +is return in all other cases. + +*/ @(require_results) is_number :: proc(r: rune) -> bool #no_bounds_check { if u32(r) <= MAX_LATIN1 { return char_properties[u8(r)]&pN != 0 } - return false + + return in_range(r, nd_ranges) || in_range(r, nl_ranges) || in_range(r, no_ranges) } @(require_results) @@ -208,7 +251,16 @@ is_punct :: proc(r: rune) -> bool #no_bounds_check { if u32(r) <= MAX_LATIN1 { return char_properties[u8(r)]&pP != 0 } - return false + + if in_range(r, pc_ranges) || in_range(r, pd_ranges) || in_range(r, pe_ranges) { + return true + } + + if in_range(r, pf_ranges) || in_range(r, pi_ranges) || in_range(r, po_ranges) { + return true + } + + return in_range(r, ps_ranges) } @(require_results) @@ -216,6 +268,13 @@ is_symbol :: proc(r: rune) -> bool #no_bounds_check { if u32(r) <= MAX_LATIN1 { return char_properties[u8(r)]&pS != 0 } + + s := in_range(r, sc_ranges) || in_range(r, sm_ranges) + + if s || in_range(r, so_ranges) || in_range(r, sk_ranges) { + return true + } + return false } diff --git a/core/unicode/tools/generate_entity_table.odin b/core/unicode/tools/generate_entity_table.odin index 020ef94e4..7d53e5497 100644 --- a/core/unicode/tools/generate_entity_table.odin +++ b/core/unicode/tools/generate_entity_table.odin @@ -1,233 +1,12 @@ -package xml_example +package xml_tools -import "core:encoding/xml" -import "core:os" +import "core:encoding/xml" +import "core:os" import path "core:path/filepath" -import "core:mem" -import "core:strings" -import "core:strconv" -import "core:slice" -import "core:fmt" - -/* - Silent error handler for the parser. -*/ -Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) {} - -OPTIONS :: xml.Options{ flags = { .Ignore_Unsupported, }, expected_doctype = "unicode", } - -Entity :: struct { - name: string, - codepoint: rune, - description: string, -} - -generate_encoding_entity_table :: proc() { - filename := path.join({ODIN_ROOT, "tests", "core", "assets", "XML", "unicode.xml"}) - defer delete(filename) - - generated_filename := path.join({ODIN_ROOT, "core", "encoding", "entity", "generated.odin"}) - defer delete(generated_filename) - - doc, err := xml.load_from_file(filename, OPTIONS, Error_Handler) - defer xml.destroy(doc) - - if err != .None { - fmt.printf("Load/Parse error: %v\n", err) - if err == .File_Error { - fmt.printf("\"%v\" not found. Did you run \"tests\\download_assets.py\"?", filename) - } - os.exit(1) - } - - fmt.printf("\"%v\" loaded and parsed.\n", filename) - - generated_buf: strings.Builder - defer strings.builder_destroy(&generated_buf) - w := strings.to_writer(&generated_buf) - - charlist_id, charlist_ok := xml.find_child_by_ident(doc, 0, "charlist") - if !charlist_ok { - fmt.eprintln("Could not locate top-level `` tag.") - os.exit(1) - } - - charlist := doc.elements[charlist_id] - - fmt.printf("Found `` with %v children.\n", len(charlist.value)) - - entity_map: map[string]Entity - names: [dynamic]string - - min_name_length := max(int) - max_name_length := min(int) - shortest_name: string - longest_name: string - - count := 0 - for char_id in charlist.value { - id := char_id.(xml.Element_ID) - char := doc.elements[id] - - if char.ident != "character" { - fmt.eprintf("Expected ``, got `<%v>`\n", char.ident) - os.exit(1) - } - - if codepoint_string, ok := xml.find_attribute_val_by_key(doc, id, "dec"); !ok { - fmt.eprintln("`` attribute not found.") - os.exit(1) - } else { - codepoint := strconv.atoi(codepoint_string) - - desc, desc_ok := xml.find_child_by_ident(doc, id, "description") - description := "" - if len(doc.elements[desc].value) == 1 { - description = doc.elements[desc].value[0].(string) - } - - /* - For us to be interested in this codepoint, it has to have at least one entity. - */ - - nth := 0 - for { - character_entity := xml.find_child_by_ident(doc, id, "entity", nth) or_break - nth += 1 - name := xml.find_attribute_val_by_key(doc, character_entity, "id") or_continue - if len(name) == 0 { - /* - Invalid name. Skip. - */ - continue - } - - if name == "\"\"" { - fmt.printf("%#v\n", char) - fmt.printf("%#v\n", character_entity) - } - - if len(name) > max_name_length { longest_name = name } - if len(name) < min_name_length { shortest_name = name } - - min_name_length = min(min_name_length, len(name)) - max_name_length = max(max_name_length, len(name)) - - e := Entity{ - name = name, - codepoint = rune(codepoint), - description = description, - } - - if name in entity_map { - continue - } - - entity_map[name] = e - append(&names, name) - count += 1 - } - } - } - - /* - Sort by name. - */ - slice.sort(names[:]) - - fmt.printf("Found %v unique `&name;` -> rune mappings.\n", count) - fmt.printf("Shortest name: %v (%v)\n", shortest_name, min_name_length) - fmt.printf("Longest name: %v (%v)\n", longest_name, max_name_length) - - /* - Generate table. - */ - fmt.wprintln(w, "package encoding_unicode_entity") - fmt.wprintln(w, "") - fmt.wprintln(w, GENERATED) - fmt.wprintln(w, "") - fmt.wprintf (w, TABLE_FILE_PROLOG) - fmt.wprintln(w, "") - - fmt.wprintf (w, "// `&%v;`\n", shortest_name) - fmt.wprintf (w, "XML_NAME_TO_RUNE_MIN_LENGTH :: %v\n", min_name_length) - fmt.wprintf (w, "// `&%v;`\n", longest_name) - fmt.wprintf (w, "XML_NAME_TO_RUNE_MAX_LENGTH :: %v\n", max_name_length) - fmt.wprintln(w, "") - - fmt.wprintln(w, -` -/* - Input: - entity_name - a string, like "copy" that describes a user-encoded Unicode entity as used in XML. - - Returns: - "decoded" - The decoded rune if found by name, or -1 otherwise. - "ok" - true if found, false if not. - - IMPORTANT: XML processors (including browsers) treat these names as case-sensitive. So do we. -*/ -named_xml_entity_to_rune :: proc(name: string) -> (decoded: rune, ok: bool) { - /* - Early out if the name is too short or too long. - min as a precaution in case the generated table has a bogus value. - */ - if len(name) < min(1, XML_NAME_TO_RUNE_MIN_LENGTH) || len(name) > XML_NAME_TO_RUNE_MAX_LENGTH { - return -1, false - } - - switch rune(name[0]) { -`) - - prefix := '?' - should_close := false - - for v in names { - if rune(v[0]) != prefix { - if should_close { - fmt.wprintln(w, "\t\t}\n") - } - - prefix = rune(v[0]) - fmt.wprintf (w, "\tcase '%v':\n", prefix) - fmt.wprintln(w, "\t\tswitch name {") - } - - e := entity_map[v] - - fmt.wprintf(w, "\t\tcase \"%v\":", e.name) - for i := len(e.name); i < max_name_length; i += 1 { - fmt.wprintf(w, " ") - } - fmt.wprintf(w, " // %v\n", e.description) - fmt.wprintf(w, "\t\t\treturn %v, true\n", rune_to_string(e.codepoint)) - - should_close = true - } - fmt.wprintln(w, "\t\t}") - fmt.wprintln(w, "\t}") - fmt.wprintln(w, "\treturn -1, false") - fmt.wprintln(w, "}\n") - fmt.wprintln(w, GENERATED) - - fmt.println() - fmt.println(strings.to_string(generated_buf)) - fmt.println() - - written := os.write_entire_file(generated_filename, transmute([]byte)strings.to_string(generated_buf)) - - if written { - fmt.printf("Successfully written generated \"%v\".\n", generated_filename) - } else { - fmt.printf("Failed to write generated \"%v\".\n", generated_filename) - } - - delete(entity_map) - delete(names) - for &name in names { - free(&name) - } -} +import "core:strings" +import "core:strconv" +import "core:slice" +import "core:fmt" GENERATED :: `/* ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ @@ -235,14 +14,14 @@ GENERATED :: `/* TABLE_FILE_PROLOG :: `/* This file is generated from "https://github.com/w3c/xml-entities/blob/gh-pages/unicode.xml". - + UPDATE: - - Ensure the XML file was downloaded using "tests\core\download_assets.py". + - Ensure the XML file was downloaded using "tests\core\download_assets.py", given the path to the "tests\assets" directory. - Run "core/unicode/tools/generate_entity_table.odin" Odin unicode generated tables: https://github.com/odin-lang/Odin/tree/master/core/encoding/entity - Copyright David Carlisle 1999-2023 + Copyright David Carlisle 1999-2025 Use and distribution of this code are permitted under the terms of the W3C Software Notice and License. @@ -262,33 +41,326 @@ TABLE_FILE_PROLOG :: `/* */ ` -rune_to_string :: proc(r: rune) -> (res: string) { - res = fmt.tprintf("%08x", int(r)) - for len(res) > 2 && res[:2] == "00" { - res = res[2:] - } - return fmt.tprintf("rune(0x%v)", res) +// Silent error handler for the parser. +Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) {} + +OPTIONS :: xml.Options{ flags = { .Ignore_Unsupported, }, expected_doctype = "unicode", } + +Entity :: struct { + codepoints: [2]rune, + name: string, // &name; + description: string, } -is_dotted_name :: proc(name: string) -> (dotted: bool) { - for r in name { - if r == '.' { return true} - } - return false +Character :: struct { + codepoint: rune, + category: string, + description: string, } main :: proc() { - track: mem.Tracking_Allocator - mem.tracking_allocator_init(&track, context.allocator) - context.allocator = mem.tracking_allocator(&track) + filename, err_xml := path.join({ODIN_ROOT, "tests", "core", "assets", "XML", "unicode.xml"}, context.allocator) + defer delete(filename) - generate_encoding_entity_table() + if err_xml != .None { + fmt.eprintfln("Join path error for unicode.xml: %v", err_xml) + os.exit(1) + } - if len(track.allocation_map) > 0 { - fmt.println() - for _, v in track.allocation_map { - fmt.printf("%v Leaked %v bytes.\n", v.location, v.size) + doc, err := xml.load_from_file(filename, OPTIONS, Error_Handler) + defer xml.destroy(doc) + + if err != .None { + fmt.eprintfln("Load/Parse error: %v", err) + if err == .File_Error { + fmt.eprintfln("%q not found. Did you run \"tests\\download_assets.py\"?", filename) + } + os.exit(1) + } + + fmt.printfln("%q loaded and parsed.", filename) + + charlist_id, charlist_ok := xml.find_child_by_ident(doc, 0, "charlist") + if !charlist_ok { + fmt.eprintln("Could not locate top-level `` tag.") + os.exit(1) + } + + charlist := doc.elements[charlist_id] + + fmt.printfln("Found `` with %v children.", len(charlist.value)) + + // These are for `core:encoding/entity`, and only keep track of codepoints which have + // one or more children pointing to it. + // + // This means that this array can have the same codepoint appear more than once, e.g. + // `Aring` and `angst` are both a capital A with a circle. The latter is the Angstrom symbol. + entities: [dynamic]Entity + defer delete(entities) + entity_map: map[string]Entity + defer delete(entity_map) + + min_name_length := max(int) + max_name_length := min(int) + shortest_name: string + longest_name: string + + // This is for `core:unicode`'s tables and has all children of `` + characters: [dynamic]Character + defer delete(characters) + + for char_id in charlist.value { + id := char_id.(xml.Element_ID) + char := doc.elements[id] + + if char.ident != "character" { + fmt.eprintfln("Expected `` child to be ``, got `<%v>`", char.ident) + os.exit(1) + } + + // `dec` is the codepoint, or codepoints separated by a `-`. + codepoint_string, ok := xml.find_attribute_val_by_key(doc, id, "dec") + if !ok { + fmt.eprintln("`` attribute not found.") + os.exit(1) + } + + r1, _, r2 := strings.partition(codepoint_string, "-") + + codepoint, codepoint2: int + codepoint, _ = strconv.parse_int(r1) + if r2 != "" { + codepoint2, _ = strconv.parse_int(r2) + } + + // This is the description we add to `core:encoding/entity`'s generated table + desc, desc_ok := xml.find_child_by_ident(doc, id, "description") + assert(desc_ok) + description := "" + if len(doc.elements[desc].value) == 1 { + description = doc.elements[desc].value[0].(string) + } + + // For us to be interested in a character for `core:unicode`, it has to have `` + // + // Not present for e.g. MULTIPLE CHARACTER OPERATOR: arccos + // and some maths characters without a character category + if unicodedata, unicodedata_ok := xml.find_child_by_ident(doc, id, "unicodedata"); unicodedata_ok { + // Not present for some math characters, e.g. codepoint: 10913-824, desc: "DOUBLE NESTED LESS-THAN with slash" + if category_string, category_ok := xml.find_attribute_val_by_key(doc, unicodedata, "category"); category_ok { + // These should only consist of a single rune. + assert(codepoint2 == 0) + append(&characters, Character{ + codepoint = rune(codepoint), + description = description, + category = category_string, + }) + } + } + + // For us to be interested in this codepoint for `core:encoding/entity`, it has to have at least one ``. + nth := 0 + for { + character_entity := xml.find_child_by_ident(doc, id, "entity", nth) or_break + nth += 1 + name := xml.find_attribute_val_by_key(doc, character_entity, "id") or_continue + if len(name) == 0 { + // Invalid name. Skip. + continue + } + + if len(name) > max_name_length { longest_name = name } + if len(name) < min_name_length { shortest_name = name } + + min_name_length = min(min_name_length, len(name)) + max_name_length = max(max_name_length, len(name)) + + if name in entity_map { + continue + } + + e := Entity{ + name = name, + codepoints = {rune(codepoint), rune(codepoint2)}, + description = description, + } + + entity_map[name] = e + append(&entities, e) } } - fmt.println("Done and cleaned up!") + + write_encoding_entitities_table(entities[:], shortest_name, longest_name, min_name_length, max_name_length) + fmt.println() + write_unicode_category_tables(characters[:]) + + // Not a library, no need to clean up. +} + +write_encoding_entitities_table :: proc(entities: []Entity, shortest_name, longest_name: string, min_name_length, max_name_length: int) { + fmt.printfln("Found %v unique `&name;` -> rune mappings.", len(entities)) + fmt.printfln("Shortest name: %v (%v)", shortest_name, min_name_length) + fmt.printfln("Longest name: %v (%v)", longest_name, max_name_length) + + generated_filename, err_generated := path.join({ODIN_ROOT, "core", "encoding", "entity", "generated.odin"}, context.allocator) + defer delete(generated_filename) + + if err_generated != .None { + fmt.eprintfln("Join path error for generated.odin: %v", err_generated) + os.exit(1) + } + + generated_buf: strings.Builder + defer strings.builder_destroy(&generated_buf) + w := strings.to_writer(&generated_buf) + + // Generate table. + fmt.wprintln(w, "package encoding_unicode_entity") + fmt.wprintln(w, "") + fmt.wprintln(w, GENERATED) + fmt.wprintln(w, "") + fmt.wprintf (w, TABLE_FILE_PROLOG) + fmt.wprintln(w, "") + + fmt.wprintfln(w, "// `&%v;`", shortest_name) + fmt.wprintfln(w, "XML_NAME_TO_RUNE_MIN_LENGTH :: %v", min_name_length) + fmt.wprintfln(w, "// `&%v;`", longest_name) + fmt.wprintfln(w, "XML_NAME_TO_RUNE_MAX_LENGTH :: %v", max_name_length) + fmt.wprintln(w, "") + + fmt.wprintln(w, +` +/* + Input: + entity_name - a string, like "copy" that describes a user-encoded Unicode entity as used in XML. + + Returns: + "decoded" - The decoded runes if found by name, or all zero otherwise. + "rune_count" - The number of decoded runes + "ok" - true if found, false if not. + + IMPORTANT: XML processors (including browsers) treat these names as case-sensitive. So do we. +*/ +named_xml_entity_to_rune :: proc(name: string) -> (decoded: [2]rune, rune_count: int, ok: bool) { + /* + Early out if the name is too short or too long. + min as a precaution in case the generated table has a bogus value. + */ + if len(name) < min(1, XML_NAME_TO_RUNE_MIN_LENGTH) || len(name) > XML_NAME_TO_RUNE_MAX_LENGTH { + return + } + + switch rune(name[0]) {`) + + prefix := '?' + should_close := false + + slice.sort_by(entities, proc(a, b: Entity) -> bool { + return a.name < b.name + }) + + for e in entities { + if rune(e.name[0]) != prefix { + if should_close { + fmt.wprintln(w, "\t\t}\n") + } + + prefix = rune(e.name[0]) + fmt.wprintfln(w, "\tcase '%v':", prefix) + fmt.wprintln(w, "\t\tswitch name {") + } + + fmt.wprintf(w, "\t\tcase \"%v\":", e.name) + for i := len(e.name); i < max_name_length; i += 1 { + fmt.wprintf(w, " ") + } + fmt.wprintf(w, " // %v\n", e.description) + if e.codepoints[1] != 0 { + fmt.wprintf(w, "\t\t\treturn {{%q, %q}}, 2, true\n", e.codepoints[0], e.codepoints[1]) + } else { + fmt.wprintf(w, "\t\t\treturn {{%q, 0}}, 1, true\n", e.codepoints[0]) + } + should_close = true + } + fmt.wprintln(w, "\t\t}") + fmt.wprintln(w, "\t}") + fmt.wprintln(w, "\treturn") + fmt.wprintln(w, "}\n") + fmt.wprintln(w, GENERATED) + + fmt.println() + when ODIN_DEBUG { + fmt.println(strings.to_string(generated_buf)) + fmt.println() + } + + written := os.write_entire_file(generated_filename, transmute([]byte)strings.to_string(generated_buf)) + + if written == nil { + fmt.printfln("Successfully written generated \"%v\".", generated_filename) + } else { + fmt.printfln("Failed to write generated \"%v\".", generated_filename) + } +} + +write_unicode_category_tables :: proc(characters: []Character) { + fmt.printfln("Found %v codepoints with a category.", len(characters)) + + // Sort by `category`, then `codepoints` + slice.sort_by(characters, proc(a, b: Character) -> bool { + return a.category < b.category && a.codepoint < b.codepoint + }) + + nd_range_start := rune(-1) + nd_range_end := rune(-1) + nd_last: rune + for c in characters { + // Find contiguous ranges for the `Nd` category + if c.category == "Nd" { + defer nd_last = c.codepoint + + // New range start + if c.codepoint != nd_last + 1 { + nd_range_end = nd_last + if nd_range_start != rune(-1) { + // Found a range + // fmt.printfln("%r (%d) - %r (%d) // %s", nd_range_start, nd_range_start, nd_range_end, nd_range_end, c.description) + } + nd_range_start = c.codepoint + } + } + } + + /* + Lu Letter, Uppercase + Ll Letter, Lowercase + Lt Letter, Titlecase + Lm Letter, Modifier + Lo Letter, Other + Mn Mark, Nonspacing + Mc Mark, Spacing Combining + Me Mark, Enclosing + Nd Number, Decimal Digit + Nl Number, Letter + No Number, Other + Pc Punctuation, Connector + Pd Punctuation, Dash + Ps Punctuation, Open + Pe Punctuation, Close + Pi Punctuation, Initial quote (may behave like Ps or Pe depending on usage) + Pf Punctuation, Final quote (may behave like Ps or Pe depending on usage) + Po Punctuation, Other + Sm Symbol, Math + Sc Symbol, Currency + Sk Symbol, Modifier + So Symbol, Other + Zs Separator, Space + Zl Separator, Line + Zp Separator, Paragraph + Cc Other, Control + Cf Other, Format + Cs Other, Surrogate + Co Other, Private Use + Cn Other, Not Assigned (no characters in the file have this property) + */ } \ No newline at end of file diff --git a/core/unicode/tools/ucd/generate_unicode.odin b/core/unicode/tools/ucd/generate_unicode.odin new file mode 100644 index 000000000..9494674a1 --- /dev/null +++ b/core/unicode/tools/ucd/generate_unicode.odin @@ -0,0 +1,287 @@ +package ucd + +import "core:fmt" +import "core:os" +import "core:strings" +import "core:mem" +import "core:io" +import "core:log" + +// Table 2-3. Types of Code Points +// Table 4-4. General_Category Values page 229 +// Reference https://www.unicode.org/reports/tr44/ + +/* +Formats a `Dynamic_Range` into a set of fixed length arrays and writes them to an `io.Writer`. +The value of the parameter `name` will be used as a prefix to the array names. + +If a dynamic array contained in the `range` is empty, no corresponding fixed length array will be written. + +Inputs: +- writer: The `io.Writer` to be written to. +- name: Prefix to add to any array that is written to `writer` +- range: `The Dynamic_Range` to format and write to writer. +*/ +write_range_arrays :: proc(writer: io.Writer, name: string, range: Dynamic_Range) { + if len(range.single_16) > 0 { + fmt.wprintln(writer, "@(rodata)") + fmt.wprintf(writer, "%s_singles16 := [?]u16{{", name) + for v, count in range.single_16 { + if count % 8 == 0 { + fmt.wprintf(writer, "\n\t0x%4X,", v) + continue + } else { + fmt.wprintf(writer, " 0x%4X,", v) + } + } + fmt.wprintln(writer, "\n}\n") + } + + if len(range.ranges_16) > 0 { + fmt.wprintln(writer, "@(rodata)") + fmt.wprintfln(writer, "%s_ranges16 := [?]u16{{", name) + for v in range.ranges_16 { + fmt.wprintfln(writer, "\t0x%4X, 0x%4X,", v.first, v.last) + } + fmt.wprintln(writer, "}\n") + } + + if len(range.single_32) > 0 { + fmt.wprintln(writer, "@(rodata)") + fmt.wprintf(writer, "%s_singles32 := [?]i32{{", name) + for v, count in range.single_32 { + if count % 8 == 0 { + fmt.wprintf(writer, "\n\t0x%4X,", v) + continue + } else { + fmt.wprintf(writer, " 0x%4X,", v) + } + } + fmt.wprintln(writer, "\n}\n") + } + + if len(range.ranges_32) > 0 { + fmt.wprintln(writer, "@(rodata)") + fmt.wprintfln(writer, "%s_ranges32 := [?]i32{{", name) + for v in range.ranges_32 { + fmt.wprintfln(writer, "\t0x%4X, 0x%4X,", v.first, v.last) + } + fmt.wprintln(writer, "}\n") + } + + return +} + +write_range :: proc(writer: io.Writer, name: union{string, General_Category}, range: Dynamic_Range) { + buffer: [128]byte + str: string + + switch n in name { + case string: + assert(len(n) <= len(buffer)) + copy(buffer[:], n) + str = string(buffer[:len(n)]) + + case General_Category: + str = fmt.bprintf(buffer[:], "%s", n) + } + + // lowercase table names + for &b in buffer[0:len(str)] { + if b >= 'A' && b <= 'Z' { + b += ('a' - 'A') + } + } + + write_range_arrays(writer, str, range) + + fmt.wprintfln(writer, "%s_ranges := Range{{", str) + if len(range.single_16) > 0 { + fmt.wprintfln(writer, "\tsingle_16 = %s_singles16[:],", str) + } + if len(range.ranges_16) > 0 { + fmt.wprintfln(writer, "\tranges_16 = %s_ranges16[:],", str) + } + if len(range.single_32) > 0 { + fmt.wprintfln(writer, "\tsingle_32 = %s_singles32[:],", str) + } + if len(range.ranges_32) > 0 { + fmt.wprintfln(writer, "\tranges_32 = %s_ranges32[:],", str) + } + fmt.wprintln(writer, "}\n") + + return +} + +GENERATED :: `/* + ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ +*/ +` + +MESSAGE :: `/* + This file is generated from UnicodeData.txt and PropList.txt. These files + are part of the Unicode Database (UCD) and are covered by the license + listed further down. They may be downloaded from the following locations; + + https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt + https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt + https://www.unicode.org/license.txt + + ------------------------------------------------------------------------------ + UNICODE LICENSE V3 + + COPYRIGHT AND PERMISSION NOTICE + + Copyright © 1991-2026 Unicode, Inc. + + NOTICE TO USER: Carefully read the following legal agreement. BY + DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR + SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE + TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT + DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of data files and any associated documentation (the "Data Files") or + software and any associated documentation (the "Software") to deal in the + Data Files or Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, and/or sell + copies of the Data Files or Software, and to permit persons to whom the + Data Files or Software are furnished to do so, provided that either (a) + this copyright and permission notice appear with all copies of the Data + Files or Software, or (b) this copyright and permission notice appear in + associated Documentation. + + THE DATA FILES AND SOFTWARE ARE 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 OF + THIRD PARTY RIGHTS. + + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE + BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA + FILES OR SOFTWARE. + + Except as contained in this notice, the name of a copyright holder shall + not be used in advertising or otherwise to promote the sale, use or other + dealings in these Data Files or Software without prior written + authorization of the copyright holder. + +*/ +` + +main :: proc() { + track: mem.Tracking_Allocator + + mem.tracking_allocator_init(&track, context.allocator) + defer { + if len(track.allocation_map) > 0 { + fmt.eprintf("=== %v allocations not freed: ===\n", len(track.allocation_map)) + for _, entry in track.allocation_map { + fmt.eprintf("- %v bytes @ %v\n", entry.size, entry.location) + } + } + mem.tracking_allocator_destroy(&track) + } + + context.allocator = mem.tracking_allocator(&track) + + context.logger = log.create_console_logger() + defer log.destroy_console_logger(context.logger) + + ucd_path := ODIN_ROOT + "tests/core/assets/UCD/UnicodeData.txt" + + unicode_data, ucd_err := load_unicode_data(ucd_path) + if ucd_err != nil { + log.errorf("Error loading Unicode data. %s", ucd_err) + } + defer destroy_unicode_data(unicode_data) + + general_category_ranges := gc_ranges(&unicode_data) + defer destroy_general_category_ranges(general_category_ranges) + + extra_digits := extra_digits(&unicode_data) + defer destroy_dynamic_range(extra_digits) + + + proplist_path := ODIN_ROOT + "tests/core/assets/UCD/PropList.txt" + proplist, proplist_err := load_property_list(proplist_path) + if proplist_err != nil { + log.errorf("Error loading PropList.txt. %s", proplist_err) + return + } + defer destroy_property_list(proplist) + + sb := strings.builder_make_len_cap(0, 1024*32) + defer strings.builder_destroy(&sb) + + writer := strings.to_writer(&sb) + + fmt.wprintfln(writer, "package unicode\n") + fmt.wprintln(writer, GENERATED) + fmt.wprintln(writer, MESSAGE) + + Range_Type :: "Range :: struct {\n" + + "\tsingle_16 : []u16,\n" + + "\tranges_16 : []u16,\n" + + "\tsingle_32 : []i32,\n" + + "\tranges_32 : []i32,\n" + + "}\n" + + fmt.wprintfln(writer, "%s", Range_Type) + + //List of the general categories to skip when generating the code for + //core/unicode/generated.txt. + to_exclude := [?]General_Category{ + .Cc, // Control, a C0 or C1 control code + .Cf, // Format, a format control character + .Cn, // Unassigned, a reserved unassigned code point or a noncharacter + .Co, // Private_Use, a private-use character + .Cs, // Surrogate, a surrogate code point + // .Ll, // Lowercase_Letter, a lowercase letter + // .Lm, // Modifier_Letter, a modifier letter + // .Lo, // Other_Letter, other letters, including syllables and ideographs + // .Lt, // Titlecase_Letter, a digraph encoded as a single character, with first part uppercase + // .Lu, // Uppercase_Letter, an uppercase letter + // .Mc, // Spacing_Mark, a spacing combining mark (positive advance width) + // .Me, // Enclosing_Mark, an enclosing combining mark + // .Mn, // Nonspacing_Mark, a nonspacing combining mark (zero advance width) + //.Nd, // Decimal_Number, a decimal digit + //.Nl, // Letter_Number, a letterlike numeric character + //.No, // Other_Number, a numeric character of other type + // .Pc, // Connector_Punctuation, a connecting punctuation mark, like a tie + // .Pd, // Dash_Punctuation, a dash or hyphen punctuation mark + // .Pe, // Close_Punctuation, a closing punctuation mark (of a pair) + // .Pf, // Final_Punctuation, a final quotation mark + // .Pi, // Initial_Punctuation, an initial quotation mark + // .Po, // Other_Punctuation, a punctuation mark of other type + // .Ps, // Open_Punctuation, an opening punctuation mark (of a pair) + // .Sc, // Currency_Symbol, a currency sign + // .Sk, // Modifier_Symbol, a non-letterlike modifier symbol + // .Sm, // Math_Symbol, a symbol of mathematical use + // .So, // Other_Symbol, a symbol of other type + .Zl, // Line_Separator, U+2028 LINE SEPARATOR only + .Zp, // Paragraph_Separator, U+2029 PARAGRAPH SEPARATOR only + //.Zs, // Space_Separator, a space character (of various non-zero widths) + } + + write_loop: for range, category in general_category_ranges { + for excluded in to_exclude { + if category == excluded { + continue write_loop + } + } + write_range(writer, category, range) + } + + write_range(writer, "extra_digits", extra_digits) + write_range(writer, "other_lowercase", proplist[.Other_Lowercase]) + write_range(writer, "other_uppercase", proplist[.Other_Uppercase]) + + file_name := ODIN_ROOT + "core/unicode/generated.odin" + + if write_error := os.write_entire_file_from_string(file_name, strings.to_string(sb)); write_error != nil { + log.errorf("Error %v writing %q", write_error, file_name) + } +} \ No newline at end of file diff --git a/core/unicode/tools/ucd/string_to.odin b/core/unicode/tools/ucd/string_to.odin new file mode 100644 index 000000000..873c162b7 --- /dev/null +++ b/core/unicode/tools/ucd/string_to.odin @@ -0,0 +1,163 @@ +package ucd + +string_to_general_category :: proc "contextless" (str: string) -> (gc: General_Category, err: Error) { + switch str { + case "Lu": gc = .Lu + case "Ll": gc = .Ll + case "Lt": gc = .Lt + case "Lm": gc = .Lm + case "Lo": gc = .Lo + case "Mn": gc = .Mn + case "Mc": gc = .Mc + case "Me": gc = .Me + case "Nd": gc = .Nd + case "Nl": gc = .Nl + case "No": gc = .No + case "Pc": gc = .Pc + case "Pd": gc = .Pd + case "Ps": gc = .Ps + case "Pe": gc = .Pe + case "Pi": gc = .Pi + case "Pf": gc = .Pf + case "Po": gc = .Po + case "Sm": gc = .Sm + case "Sc": gc = .Sc + case "Sk": gc = .Sk + case "So": gc = .So + case "Zs": gc = .Zs + case "Zl": gc = .Zl + case "Zp": gc = .Zp + case "Cc": gc = .Cc + case "Cf": gc = .Cf + case "Cs": gc = .Cs + case "Co": gc = .Co + case "Cn": gc = .Cn + case: err = .Invalid_General_Category + } + return +} + +string_to_proplist_property :: proc(str: string) -> (prop: Prop_List_Property, err: Error) { + switch str { + case "White_Space": prop = .White_Space + case "Bidi_Control": prop = .Bidi_Control + case "Join_Control": prop = .Join_Control + case "Dash": prop = .Dash + case "Hyphen": prop = .Hyphen + case "Quotation_Mark": prop = .Quotation_Mark + case "Terminal_Punctuation": prop = .Terminal_Punctuation + case "Other_Math": prop = .Other_Math + case "Hex_Digit": prop = .Hex_Digit + case "ASCII_Hex_Digit": prop = .ASCII_Hex_Digit + case "Other_Alphabetic": prop = .Other_Alphabetic + case "Ideographic": prop = .Ideographic + case "Diacritic": prop = .Diacritic + case "Extender": prop = .Extender + case "Other_Lowercase": prop = .Other_Lowercase + case "Other_Uppercase": prop = .Other_Uppercase + case "Noncharacter_Code_Point": prop = .Noncharacter_Code_Point + case "Other_Grapheme_Extend": prop = .Other_Grapheme_Extend + case "IDS_Binary_Operator": prop = .IDS_Binary_Operator + case "IDS_Trinary_Operator": prop = .IDS_Trinary_Operator + case "IDS_Unary_Operator": prop = .IDS_Unary_Operator + case "Radical": prop = .Radical + case "Unified_Ideograph": prop = .Unified_Ideograph + case "Other_Default_Ignorable_Code_Point": prop = .Other_Default_Ignorable_Code_Point + case "Deprecated": prop = .Deprecated + case "Soft_Dotted": prop = .Soft_Dotted + case "Logical_Order_Exception": prop = .Logical_Order_Exception + case "Other_ID_Start": prop = .Other_ID_Start + case "Other_ID_Continue": prop = .Other_ID_Continue + case "ID_Compat_Math_Continue": prop = .ID_Compat_Math_Continue + case "ID_Compat_Math_Start": prop = .ID_Compat_Math_Start + case "Sentence_Terminal": prop = .Sentence_Terminal + case "Variation_Selector": prop = .Variation_Selector + case "Pattern_White_Space": prop = .Pattern_White_Space + case "Pattern_Syntax": prop = .Pattern_Syntax + case "Prepended_Concatenation_Mark": prop = .Prepended_Concatenation_Mark + case "Regional_Indicator": prop = .Regional_Indicator + case "Modifier_Combining_Mark": prop = .Modifier_Combining_Mark + case: prop = .Unknown + err = UCD_Error.Unknown_Property + } + return +} + +@(deprecated="Unused?") +string_to_age :: proc "contextless" (str: string) -> (age: Age) { + switch str { + case "1.1": age = .Age_1_1 + case "2.0": age = .Age_2_0 + case "2.1": age = .Age_2_1 + case "3.0": age = .Age_3_0 + case "3.1": age = .Age_3_1 + case "3.2": age = .Age_3_2 + case "4.0": age = .Age_4_0 + case "4.1": age = .Age_4_1 + case "5.0": age = .Age_5_0 + case "5.1": age = .Age_5_1 + case "5.2": age = .Age_5_2 + case "6.0": age = .Age_6_0 + case "6.1": age = .Age_6_1 + case "6.2": age = .Age_6_2 + case "6.3": age = .Age_6_3 + case "7.0": age = .Age_7_0 + case "8.0": age = .Age_8_0 + case "9.0": age = .Age_9_0 + case "10.0": age = .Age_10_0 + case "11.0": age = .Age_11_0 + case "12.0": age = .Age_12_0 + case "12.1": age = .Age_12_1 + case "13.0": age = .Age_13_0 + case "14.0": age = .Age_14_0 + case "15.0": age = .Age_15_0 + case "15.1": age = .Age_15_1 + case "16.0": age = .Age_16_0 + case "17.0": age = .Age_17_0 + case "unassigned": age = .Age_Unassigned + case: age = .Age_Unknown + } + return +} + +@(deprecated="Unused?") +string_to_paired_bracket_type :: proc "contextless" (str: string) -> (pbt: Paired_Bracket_Type) { + switch str { + case "o": pbt = .Open + case "c": pbt = .Close + case "n": pbt = .None + case: pbt = .Unknown + } + return +} + +@(deprecated="Unused?") +string_to_bidi_class :: proc "contextless" (str: string) -> (class: Bidi_Class) { + switch str { + case "AL": class = .AL + case "AN": class = .AN + case "B": class = .B + case "BN": class = .BN + case "CS": class = .CS + case "EN": class = .EN + case "ES": class = .ES + case "ET": class = .ET + case "FSI": class = .FSI + case "L": class = .L + case "LRE": class = .LRE + case "LRI": class = .LRI + case "LRO": class = .LRO + case "NSM": class = .NSM + case "ON": class = .ON + case "PDF": class = .PDF + case "PDI": class = .PDI + case "R": class = .R + case "RLE": class = .RLE + case "RLI": class = .RLI + case "RLO": class = .RLO + case "S": class = .S + case "WS": class = .WS + case: class = .Unknown + } + return +} diff --git a/core/unicode/tools/ucd/types.odin b/core/unicode/tools/ucd/types.odin new file mode 100644 index 000000000..5b87f96f8 --- /dev/null +++ b/core/unicode/tools/ucd/types.odin @@ -0,0 +1,694 @@ +package ucd + +import "core:os" + +Age :: enum byte { + Age_Unknown = 0, + Age_1_1, + Age_2_0, + Age_2_1, + Age_3_0, + Age_3_1, + Age_3_2, + Age_4_0, + Age_4_1, + Age_5_0, + Age_5_1, + Age_5_2, + Age_6_0, + Age_6_1, + Age_6_2, + Age_6_3, + Age_7_0, + Age_8_0, + Age_9_0, + Age_10_0, + Age_11_0, + Age_12_0, + Age_12_1, + Age_13_0, + Age_14_0, + Age_15_0, + Age_15_1, + Age_16_0, + Age_17_0, + Age_Unassigned, +} + +General_Category :: enum { + Cc, // Control, a C0 or C1 control code + Cf, // Format, a format control character + Cn, // Unassigned, a reserved unassigned code point or a noncharacter + Co, // Private_Use, a private-use character + Cs, // Surrogate, a surrogate code point + Ll, // Lowercase_Letter, a lowercase letter + Lm, // Modifier_Letter, a modifier letter + Lo, // Other_Letter, other letters, including syllables and ideographs + Lt, // Titlecase_Letter, a digraph encoded as a single character, with first part uppercase + Lu, // Uppercase_Letter, an uppercase letter + Mc, // Spacing_Mark, a spacing combining mark (positive advance width) + Me, // Enclosing_Mark, an enclosing combining mark + Mn, // Nonspacing_Mark, a nonspacing combining mark (zero advance width) + Nd, // Decimal_Number, a decimal digit + Nl, // Letter_Number, a letterlike numeric character + No, // Other_Number, a numeric character of other type + Pc, // Connector_Punctuation, a connecting punctuation mark, like a tie + Pd, // Dash_Punctuation, a dash or hyphen punctuation mark + Pe, // Close_Punctuation, a closing punctuation mark (of a pair) + Pf, // Final_Punctuation, a final quotation mark + Pi, // Initial_Punctuation, an initial quotation mark + Po, // Other_Punctuation, a punctuation mark of other type + Ps, // Open_Punctuation, an opening punctuation mark (of a pair) + Sc, // Currency_Symbol, a currency sign + Sk, // Modifier_Symbol, a non-letterlike modifier symbol + Sm, // Math_Symbol, a symbol of mathematical use + So, // Other_Symbol, a symbol of other type + Zl, // Line_Separator, U+2028 LINE SEPARATOR only + Zp, // Paragraph_Separator, U+2029 PARAGRAPH SEPARATOR only + Zs, // Space_Separator, a space character (of various non-zero widths) +} + +Block :: enum { + Nil = 0, + Adlam, + Aegean_Numbers, + Ahom, + Alchemical, + Alphabetic_PF, + Anatolian_Hieroglyphs, + Ancient_Greek_Music, + Ancient_Greek_Numbers, + Ancient_Symbols, + Arabic, + Arabic_Ext_A, + Arabic_Ext_B, + Arabic_Ext_C, + Arabic_Math, + Arabic_PF_A, + Arabic_PF_B, + Arabic_Sup, + Armenian, + Arrows, + ASCII, + Avestan, + Balinese, + Bamum, + Bamum_Sup, + Bassa_Vah, + Batak, + Bengali, + Beria_Erfe, + Bhaiksuki, + Block_Elements, + Bopomofo, + Bopomofo_Ext, + Box_Drawing, + Brahmi, + Braille, + Buginese, + Buhid, + Byzantine_Music, + Carian, + Caucasian_Albanian, + Chakma, + Cham, + Cherokee, + Cherokee_Sup, + Chess_Symbols, + Chorasmian, + CJK, + CJK_Compat, + CJK_Compat_Forms, + CJK_Compat_Ideographs, + CJK_Compat_Ideographs_Sup, + CJK_Ext_A, + CJK_Ext_B, + CJK_Ext_C, + CJK_Ext_D, + CJK_Ext_E, + CJK_Ext_F, + CJK_Ext_G, + CJK_Ext_H, + CJK_Ext_I, + CJK_Ext_J, + CJK_Radicals_Sup, + CJK_Strokes, + CJK_Symbols, + Compat_Jamo, + Control_Pictures, + Coptic, + Coptic_Epact_Numbers, + Counting_Rod, + Cuneiform, + Cuneiform_Numbers, + Currency_Symbols, + Cypriot_Syllabary, + Cypro_Minoan, + Cyrillic, + Cyrillic_Ext_A, + Cyrillic_Ext_B, + Cyrillic_Ext_C, + Cyrillic_Ext_D, + Cyrillic_Sup, + Deseret, + Devanagari, + Devanagari_Ext, + Devanagari_Ext_A, + Diacriticals, + Diacriticals_Ext, + Diacriticals_For_Symbols, + Diacriticals_Sup, + Dingbats, + Dives_Akuru, + Dogra, + Domino, + Duployan, + Early_Dynastic_Cuneiform, + Egyptian_Hieroglyph_Format_Controls, + Egyptian_Hieroglyphs, + Egyptian_Hieroglyphs_Ext_A, + Elbasan, + Elymaic, + Emoticons, + Enclosed_Alphanum, + Enclosed_Alphanum_Sup, + Enclosed_CJK, + Enclosed_Ideographic_Sup, + Ethiopic, + Ethiopic_Ext, + Ethiopic_Ext_A, + Ethiopic_Ext_B, + Ethiopic_Sup, + Garay, + Geometric_Shapes, + Geometric_Shapes_Ext, + Georgian, + Georgian_Ext, + Georgian_Sup, + Glagolitic, + Glagolitic_Sup, + Gothic, + Grantha, + Greek, + Greek_Ext, + Gujarati, + Gunjala_Gondi, + Gurmukhi, + Gurung_Khema, + Half_And_Full_Forms, + Half_Marks, + Hangul, + Hanifi_Rohingya, + Hanunoo, + Hatran, + Hebrew, + High_PU_Surrogates, + High_Surrogates, + Hiragana, + IDC, + Ideographic_Symbols, + Imperial_Aramaic, + Indic_Number_Forms, + Indic_Siyaq_Numbers, + Inscriptional_Pahlavi, + Inscriptional_Parthian, + IPA_Ext, + Jamo, + Jamo_Ext_A, + Jamo_Ext_B, + Javanese, + Kaithi, + Kaktovik_Numerals, + Kana_Ext_A, + Kana_Ext_B, + Kana_Sup, + Kanbun, + Kangxi, + Kannada, + Katakana, + Katakana_Ext, + Kawi, + Kayah_Li, + Kharoshthi, + Khitan_Small_Script, + Khmer, + Khmer_Symbols, + Khojki, + Khudawadi, + Kirat_Rai, + Lao, + Latin_1_Sup, + Latin_Ext_A, + Latin_Ext_Additional, + Latin_Ext_B, + Latin_Ext_C, + Latin_Ext_D, + Latin_Ext_E, + Latin_Ext_F, + Latin_Ext_G, + Lepcha, + Letterlike_Symbols, + Limbu, + Linear_A, + Linear_B_Ideograms, + Linear_B_Syllabary, + Lisu, + Lisu_Sup, + Low_Surrogates, + Lycian, + Lydian, + Mahajani, + Mahjong, + Makasar, + Malayalam, + Mandaic, + Manichaean, + Marchen, + Masaram_Gondi, + Math_Alphanum, + Math_Operators, + Mayan_Numerals, + Medefaidrin, + Meetei_Mayek, + Meetei_Mayek_Ext, + Mende_Kikakui, + Meroitic_Cursive, + Meroitic_Hieroglyphs, + Miao, + Misc_Arrows, + Misc_Math_Symbols_A, + Misc_Math_Symbols_B, + Misc_Pictographs, + Misc_Symbols, + Misc_Symbols_Sup, + Misc_Technical, + Modi, + Modifier_Letters, + Modifier_Tone_Letters, + Mongolian, + Mongolian_Sup, + Mro, + Multani, + Music, + Myanmar, + Myanmar_Ext_A, + Myanmar_Ext_B, + Myanmar_Ext_C, + Nabataean, + Nag_Mundari, + Nandinagari, + NB, + New_Tai_Lue, + Newa, + NKo, + Number_Forms, + Nushu, + Nyiakeng_Puachue_Hmong, + OCR, + Ogham, + Ol_Chiki, + Ol_Onal, + Old_Hungarian, + Old_Italic, + Old_North_Arabian, + Old_Permic, + Old_Persian, + Old_Sogdian, + Old_South_Arabian, + Old_Turkic, + Old_Uyghur, + Oriya, + Ornamental_Dingbats, + Osage, + Osmanya, + Ottoman_Siyaq_Numbers, + Pahawh_Hmong, + Palmyrene, + Pau_Cin_Hau, + Phags_Pa, + Phaistos, + Phoenician, + Phonetic_Ext, + Phonetic_Ext_Sup, + Playing_Cards, + Psalter_Pahlavi, + PUA, + Punctuation, + Rejang, + Rumi, + Runic, + Samaritan, + Saurashtra, + Sharada, + Sharada_Sup, + Shavian, + Shorthand_Format_Controls, + Siddham, + Sidetic, + Sinhala, + Sinhala_Archaic_Numbers, + Small_Forms, + Small_Kana_Ext, + Sogdian, + Sora_Sompeng, + Soyombo, + Specials, + Sundanese, + Sundanese_Sup, + Sunuwar, + Sup_Arrows_A, + Sup_Arrows_B, + Sup_Arrows_C, + Sup_Math_Operators, + Sup_PUA_A, + Sup_PUA_B, + Sup_Punctuation, + Sup_Symbols_And_Pictographs, + Super_And_Sub, + Sutton_SignWriting, + Syloti_Nagri, + Symbols_And_Pictographs_Ext_A, + Symbols_For_Legacy_Computing, + Symbols_For_Legacy_Computing_Sup, + Syriac, + Syriac_Sup, + Tagalog, + Tagbanwa, + Tags, + Tai_Le, + Tai_Tham, + Tai_Viet, + Tai_Xuan_Jing, + Tai_Yo, + Takri, + Tamil, + Tamil_Sup, + Tangsa, + Tangut, + Tangut_Components, + Tangut_Components_Sup, + Tangut_Sup, + Telugu, + Thaana, + Thai, + Tibetan, + Tifinagh, + Tirhuta, + Todhri, + Tolong_Siki, + Toto, + Transport_And_Map, + Tulu_Tigalari, + UCAS, + UCAS_Ext, + UCAS_Ext_A, + Ugaritic, + Vai, + Vedic_Ext, + Vertical_Forms, + Vithkuqi, + VS, + VS_Sup, + Wancho, + Warang_Citi, + Yezidi, + Yi_Radicals, + Yi_Syllables, + Yijing, + Zanabazar_Square, + Znamenny_Music, +} + +Combining_Class :: distinct byte + +Paired_Bracket_Type :: enum { + Unknown, + Open, + Close, + None, +} + +Bidi_Class :: enum { + Unknown, // + L, // Left-to-Right LRM + R, // Right-to-Left RLM + AL, // Right-to-Left Arabic ALM + EN, // European Number + ES, // European Number Separator + ET, // European Number Terminator + AN, // Arabic Number + CS, // Common Number Separator + NSM, // Nonspacing Mark + BN, // Boundary Neutral + B, // Paragraph Separator + S, // Segment Separator + WS, // Whitespace + ON, // Other Neutrals + LRE, // Left-to-Right Embedding LRE + LRO, // Left-to-Right Override LRO + RLE, // Right-to-Left Embedding RLE + RLO, // Right-to-Left Override RLO + PDF, // Pop Directional Format PDF + LRI, // Left-to-Right Isolate LRI + RLI, // Right-to-Left Isolate RLI + FSI, // First Strong Isolate FSI + PDI, // Pop Directional Isolate PDI +} + +Bidi :: struct { + bc: Bidi_Class, + bmg: Maybe(rune), // mirrored glyph + m: bool, // Bidi mirrored + c: bool, // Bidi control property + pb: Paired_Bracket_Type, // bidi paired bracket type + bpb: rune, // bidi paired bracket properties +} + +Decomposition_Type :: enum { + Nil = 0, + can, + com, + enc, + fin, + font, + fra, + init, + iso, + med, + nar, + nb, + sml, + sqr, + sub, + sup, + vert, + wid, + none, +} + +Trinary_Bool :: enum { + Maybe = -1, + False = 0, + True = 1, +} + +Decomposition_Mapping :: distinct [dynamic]rune + +Decomposition :: struct { + dt: Decomposition_Type, // Decomposition type + dm: Decomposition_Mapping, // Decomposition Mapping + ce: bool, // Composition Exclusion + comp_ex: bool, // Full Composition Exclusion + nfc_quick_check: Trinary_Bool, + nfd_quick_check: bool, + nfkc_quick_check: Trinary_Bool, + nfkd_quick_check: bool, +} + +Numeric_Type :: enum { + None = 0, // None + Decimal, // De + Digit, // Di + Numeric, // Nu +} + +/* +Note: Value is NAN when numberator and denominator ar 0 +*/ +Numberic_Value :: struct { + numerator: int, + denominator: int, +} + +Char :: struct { + cp: rune, + name: string, + gc: General_Category, + ccc: Combining_Class, + bc: Bidi_Class, + dt: Decomposition_Type, + dm: Decomposition_Mapping, + nt: Numeric_Type, + nv: Numberic_Value, + bm: bool, + name1: string, + sum: string, // Simple uppercase mapping + slm: string, // Simple lowercase mapping + stm: string, // Simple titlecase_mapping +} + +Char_Range :: struct { + first_cp: rune, + last_cp: rune, + name: string, + gc: General_Category, + ccc: Combining_Class, + bc: Bidi_Class, + dt: Decomposition_Type, + dm: Decomposition_Mapping, + nt: Numeric_Type, + nv: Numberic_Value, + bm: bool, + name1: string, + sum: string, // Simple uppercase mapping + slm: string, // Simple lowercase mapping + stm: string, // Simple titlecase_mapping +} + +Chars :: union { + Char, + Char_Range, +} + +Unicode_Data :: distinct [dynamic]Chars + + +Prop_List_Property :: enum { + Unknown, + White_Space, + Bidi_Control, + Join_Control, + Dash, + Hyphen, + Quotation_Mark, + Terminal_Punctuation, + Other_Math, + Hex_Digit, + ASCII_Hex_Digit, + Other_Alphabetic, + Ideographic, + Diacritic, + Extender, + Other_Lowercase, + Other_Uppercase, + Noncharacter_Code_Point, + Other_Grapheme_Extend, + IDS_Binary_Operator, + IDS_Trinary_Operator, + IDS_Unary_Operator, + Radical, + Unified_Ideograph, + Other_Default_Ignorable_Code_Point, + Deprecated, + Soft_Dotted, + Logical_Order_Exception, + Other_ID_Start, + Other_ID_Continue, + ID_Compat_Math_Continue, + ID_Compat_Math_Start, + Sentence_Terminal, + Variation_Selector, + Pattern_White_Space, + Pattern_Syntax, + Prepended_Concatenation_Mark, + Regional_Indicator, + Modifier_Combining_Mark, +} + +UCD_Error :: enum { + XML_LOAD_ERROR, + XML_Not_UCD, + Nil_XML_Document, + Element_Not_Repertoire, + Extra_Fields, + Unknown_Property, + Unknown_Bidi_Class, + + NO_REPERTOIRE, + UNEXPECTED_STRING, + Invalid_Hex_Number, + Invalid_General_Category, + UnicodeData_6_Too_Long, + UnicodeData_6_Invalid, + UnicodeData_7_Too_Long, + UnicodeData_7_Invalid, +} + + +Error :: union #shared_nil { + UCD_Error, + os.Error, +} + +Range_u16 :: struct { + first: u16, + last: u16, +} + +Range_i32 :: struct { + first: i32, + last: i32, +} + +Range_Rune :: struct { + first: rune, + last: rune, +} + +Dynamic_Range :: struct { + single_16: [dynamic]u16, + ranges_16: [dynamic]Range_u16, + single_32: [dynamic]i32, + ranges_32: [dynamic]Range_i32, +} + +append_to_dynamic_range :: proc(dr: ^Dynamic_Range, range: Range_Rune, allocator := context.allocator) { + if range.first == range.last && range.first <= 0xFFFF { + if len(dr.single_16) == 0 { + dr.single_16 = make([dynamic]u16, 0, 512, allocator) + } + append(&dr.single_16, cast(u16)range.first) + } else if range.first == range.last { + if len(dr.single_32) == 0 { + dr.single_32 = make([dynamic]i32, 0, 512, allocator) + } + append(&dr.single_32, cast(i32)range.first) + + } else if range.first <= 0xFFFF && range.last <= 0xFFFF { + if len(dr.ranges_16) == 0 { + dr.ranges_16 = make([dynamic]Range_u16, 0, 128, allocator) + } + r := Range_u16{ cast(u16)range.first, cast(u16)range.last} + append(&dr.ranges_16, r) + + } else { + if len(dr.ranges_32) == 0 { + dr.ranges_32 = make([dynamic]Range_i32, 0, 128, allocator) + } + r := Range_i32{ cast(i32)range.first, cast(i32)range.last} + append(&dr.ranges_32, r) + } +} + +destroy_dynamic_range :: proc(dr: Dynamic_Range) { + delete(dr.ranges_16) + delete(dr.ranges_32) + delete(dr.single_16) + delete(dr.single_32) +} + +destroy_general_category_ranges :: proc(gcr: [General_Category]Dynamic_Range) { + for r in gcr { + destroy_dynamic_range(r) + } +} \ No newline at end of file diff --git a/core/unicode/tools/ucd/ucd.odin b/core/unicode/tools/ucd/ucd.odin new file mode 100644 index 000000000..165147bbd --- /dev/null +++ b/core/unicode/tools/ucd/ucd.odin @@ -0,0 +1,290 @@ +package ucd + +import "core:strings" +import "core:os" +import "core:strconv" + +decode_rune :: proc(str: string) -> (cp1, cp2: rune, err: Error) { + head, _, tail := strings.partition(str, "..") + + if _cp1, _ok := strconv.parse_int(head, 16); !_ok { + return 0, 0, .Invalid_Hex_Number + } else { + cp1 = rune(_cp1) + } + + if len(tail) == 0 { + return cp1, cp1, nil + } + + if _cp2, _ok := strconv.parse_int(tail, 16); !_ok { + return 0, 0, .Invalid_Hex_Number + } else { + cp2 = rune(_cp2) + } + return +} + +load_unicode_data :: proc(filename: string, allocator := context.allocator) -> (unicode_data: Unicode_Data, err: Error) { + data := os.read_entire_file(filename, context.temp_allocator) or_return + defer free_all(context.temp_allocator) + + first_cp: rune + + str := string(data) + line_loop: for _line in strings.split_lines_iterator(&str) { + // Ignore any comments + line, _, _ := strings.partition(_line, "#") + + // Skip empty lines + if len(line) == 0 { continue } + + is_range := false + cp: rune + name: string + gc: General_Category + num_6: string + num_7: string + nt := Numeric_Type.None + + field_num := 0 + for _field in strings.split_iterator(&line, ";") { + defer field_num += 1 + field := strings.trim_space(_field) + + switch field_num { + case 0: // Code point + cp, _ = decode_rune(field) or_return + + case 1: // Name + if len(field) > 9 && field[0] == '<' && strings.ends_with(field, ", First>") { + first_cp = cp + continue line_loop + } + + if len(field) > 9 && field[0] == '<' && strings.ends_with(field, ", Last>") { + name = strings.clone(field[1:len(field)-7], allocator) + is_range = true + } else { + name = strings.clone(field[:], allocator) + } + + case 2: // General_Category + // NOTE: This is currently igorning a possible error it should probably be fixed + gc, _ = string_to_general_category(field) + + case 3: // Canonical_Combining_Class + case 4: // Bidi Class + case 5: // Decomposition_Type and Decomposition_Mapping + // Numeric_Type and Numeric_Value + case 6: + num_6 = field + + case 7: + num_7 = field + + case 8: + switch { + case num_6 != "" && num_7 != "" && field != "" : + nt = .Decimal + + case num_6 == "" && num_7 != "" && field != "" : + nt = .Digit + + case num_6 == "" && num_7 == "" && field != "" : + nt = .Numeric + + case: + nt = .None + } + + case 9: // Bidi mirrored + case 10: // Unicode 1 Name (Obsolete as of 6.2.0) + case 11: // should be null + case 12: + case 13: + case 14: + case: + err = .Extra_Fields + return + } + } + + if is_range { + append(&unicode_data, Char_Range { + gc = gc, + first_cp = first_cp, + last_cp = cp, + name = name, + nt = nt, + }) + } else { + append(&unicode_data, Char{ + gc = gc, + cp = cp, + name = name, + nt = nt, + }) + } + } + return +} + +destroy_unicode_data :: proc(unicode_data: Unicode_Data) { + for point in unicode_data { + switch p in point { + case Char: + delete(p.name) + case Char_Range: + delete(p.name) + } + } + delete(unicode_data) +} + + +gc_ranges :: proc(ud: ^Unicode_Data, allocator := context.allocator) -> (lst: [General_Category]Dynamic_Range) { + range := Range_Rune{ + first = -1, + last = -1, + } + gc: General_Category + + for point in ud { + switch p in point { + case Char: + if range.first != -1 && (p.cp != range.last + 1 || p.gc != gc) { + append_to_dynamic_range(&lst[gc], range, allocator) + range.first = -1 + range.last = -1 + } + + range.first = rune(min(u32(range.first), u32(p.cp))) + gc = p.gc + range.last = p.cp + + case Char_Range: + if range.first != -1 { + append_to_dynamic_range(&lst[gc], range, allocator) + } + + range.first = p.first_cp + range.last = p.last_cp + append_to_dynamic_range(&lst[p.gc], range ,allocator) + range.first = -1 + range.last = -1 + } + } + + if range.first != -1 { + append_to_dynamic_range(&lst[gc], range, allocator) + } + + return +} + + +extra_digits :: proc(ud: ^Unicode_Data, allocator := context.allocator) -> (Dynamic_Range) { + range := Range_Rune { + first = -1, + last = -1, + } + + exd: Dynamic_Range + for point in ud { + switch p in point { + + case Char: + exd_type := p.gc != .Nd && (p.nt == .Decimal || p.nt == .Digit) + + if range.first != -1 && (p.cp != range.last + 1 || !exd_type) { + append_to_dynamic_range(&exd, range, allocator) + range.first = -1 + range.last = -1 + } + + if exd_type { + range.first = rune(min(u32(range.first), u32(p.cp))) + range.last = p.cp + } + + case Char_Range: + exd_type := p.gc != .Nd && (p.nt == .Decimal || p.nt == .Digit) + + if range.first != -1 { + append_to_dynamic_range(&exd, range, allocator) + } + + if exd_type { + range.first = p.first_cp + range.last = p.last_cp + append_to_dynamic_range(&exd, range ,allocator) + } + range.first = -1 + range.last = -1 + } + } + if range.first != -1 { + append_to_dynamic_range(&exd, range, allocator) + } + + return exd +} + +/* +Data contained in the Unicode fiel PropList.txt + +A `Prop_List` is the data contained in the Unicode Database (UCD) file `PropList.txt`. +It is created with the procedure `load_property_list` and destroyed with the procedure `destroy_property_list`. +*/ +Prop_List :: [Prop_List_Property]Dynamic_Range + +/* +This function destroys a `Prop_List` created by `load_property_list`. + +Inputs: +- props: The Prop_List to destroy +*/ +destroy_property_list :: proc(props: Prop_List) { + for r in props { + delete(r.ranges_16) + delete(r.ranges_32) + delete(r.single_16) + delete(r.single_32) + } +} + + + +load_property_list :: proc(filename: string, allocator := context.allocator) -> (props: Prop_List, err: Error) { + data := os.read_entire_file(filename, allocator) or_return + defer delete(data) + + str := string(data) + for _line in strings.split_lines_iterator(&str) { + line, _, _ := strings.partition(_line, "#") + if len(line) == 0 { + continue + } + + rr: Range_Rune + prop: Prop_List_Property + + i := 0 + for _field in strings.split_iterator(&line, ";") { + defer i += 1 + field := strings.trim_space(_field) + + switch i { + // Code point or code point range + case 0: rr.first, rr.last = decode_rune(field) or_return + case 1: prop = string_to_proplist_property(field) or_return + case: return {}, .Extra_Fields + } + } + + append_to_dynamic_range(&props[prop], rr, allocator) + } + + return +} diff --git a/core/unicode/utf16/utf16.odin b/core/unicode/utf16/utf16.odin index 990d5bafa..edd48e0f3 100644 --- a/core/unicode/utf16/utf16.odin +++ b/core/unicode/utf16/utf16.odin @@ -1,6 +1,7 @@ // Procedures and constants to support text-encoding in the `UTF-16` character encoding. package utf16 +@(require) import "base:runtime" import "core:unicode/utf8" REPLACEMENT_CHAR :: '\ufffd' @@ -12,11 +13,11 @@ _surr3 :: 0xe000 _surr_self :: 0x10000 -is_surrogate :: proc(r: rune) -> bool { +is_surrogate :: proc "contextless" (r: rune) -> bool { return _surr1 <= r && r < _surr3 } -decode_surrogate_pair :: proc(r1, r2: rune) -> rune { +decode_surrogate_pair :: proc "contextless" (r1, r2: rune) -> rune { if _surr1 <= r1 && r1 < _surr2 && _surr2 <= r2 && r2 < _surr3 { return (r1-_surr1)<<10 | (r2 - _surr2) + _surr_self } @@ -24,7 +25,7 @@ decode_surrogate_pair :: proc(r1, r2: rune) -> rune { } -encode_surrogate_pair :: proc(c: rune) -> (r1, r2: rune) { +encode_surrogate_pair :: proc "contextless" (c: rune) -> (r1, r2: rune) { r := c if r < _surr_self || r > MAX_RUNE { return REPLACEMENT_CHAR, REPLACEMENT_CHAR @@ -33,7 +34,7 @@ encode_surrogate_pair :: proc(c: rune) -> (r1, r2: rune) { return _surr1 + (r>>10)&0x3ff, _surr2 + r&0x3ff } -encode :: proc(d: []u16, s: []rune) -> int { +encode :: proc "contextless" (d: []u16, s: []rune) -> int { n, m := 0, len(d) loop: for r in s { switch r { @@ -59,7 +60,7 @@ encode :: proc(d: []u16, s: []rune) -> int { } -encode_string :: proc(d: []u16, s: string) -> int { +encode_string :: proc "contextless" (d: []u16, s: string) -> int { n, m := 0, len(d) loop: for r in s { switch r { @@ -84,7 +85,7 @@ encode_string :: proc(d: []u16, s: string) -> int { return n } -decode :: proc(d: []rune, s: []u16) -> (n: int) { +decode :: proc "contextless" (d: []rune, s: []u16) -> (n: int) { for i := 0; i < len(s); i += 1 { if n >= len(d) { return @@ -107,7 +108,7 @@ decode :: proc(d: []rune, s: []u16) -> (n: int) { return } -decode_rune_in_string :: proc(s: string16) -> (r: rune, width: int) { +decode_rune_in_string :: proc "contextless" (s: string16) -> (r: rune, width: int) { r = rune(REPLACEMENT_CHAR) n := len(s) if n < 1 { @@ -127,10 +128,10 @@ decode_rune_in_string :: proc(s: string16) -> (r: rune, width: int) { return } -string_to_runes :: proc "odin" (s: string16, allocator := context.allocator) -> (runes: []rune) { +string_to_runes :: proc "odin" (s: string16, allocator := context.allocator) -> (runes: []rune, err: runtime.Allocator_Error) #optional_allocator_error { n := rune_count(s) - runes = make([]rune, n, allocator) + runes = make([]rune, n, allocator) or_return i := 0 for r in s { runes[i] = r @@ -144,7 +145,7 @@ rune_count :: proc{ rune_count_in_string, rune_count_in_slice, } -rune_count_in_string :: proc(s: string16) -> (n: int) { +rune_count_in_string :: proc "contextless" (s: string16) -> (n: int) { for i := 0; i < len(s); i += 1 { c := s[i] if _surr1 <= c && c < _surr2 && i+1 < len(s) && @@ -157,7 +158,7 @@ rune_count_in_string :: proc(s: string16) -> (n: int) { } -rune_count_in_slice :: proc(s: []u16) -> (n: int) { +rune_count_in_slice :: proc "contextless" (s: []u16) -> (n: int) { for i := 0; i < len(s); i += 1 { c := s[i] if _surr1 <= c && c < _surr2 && i+1 < len(s) && @@ -170,7 +171,7 @@ rune_count_in_slice :: proc(s: []u16) -> (n: int) { } -decode_to_utf8 :: proc(d: []byte, s: []u16) -> (n: int) { +decode_to_utf8 :: proc "contextless" (d: []byte, s: []u16) -> (n: int) { for i := 0; i < len(s); i += 1 { if n >= len(d) { return @@ -190,4 +191,4 @@ decode_to_utf8 :: proc(d: []byte, s: []u16) -> (n: int) { n += copy(d[n:], b[:w]) } return -} +} \ No newline at end of file diff --git a/core/unicode/utf8/utf8.odin b/core/unicode/utf8/utf8.odin index 281e36f43..c53b2e3a4 100644 --- a/core/unicode/utf8/utf8.odin +++ b/core/unicode/utf8/utf8.odin @@ -1,6 +1,8 @@ // Procedures and constants to support text-encoding in the `UTF-8` character encoding. package utf8 +@(require) import "base:runtime" + RUNE_ERROR :: '\ufffd' RUNE_SELF :: 0x80 RUNE_BOM :: 0xfeff @@ -60,7 +62,8 @@ accept_sizes := [256]u8{ 0xf5..=0xff = 0xf1, // ascii, size 1 } -encode_rune :: proc "contextless" (c: rune) -> ([4]u8, int) { +@(require_results) +encode_rune :: proc "contextless" (c: rune) -> ([4]u8, int) #no_bounds_check { r := c buf: [4]u8 @@ -101,10 +104,12 @@ decode_rune :: proc{ decode_rune_in_string, decode_rune_in_bytes, } +@(require_results) decode_rune_in_string :: #force_inline proc "contextless" (s: string) -> (rune, int) { return decode_rune_in_bytes(transmute([]u8)s) } -decode_rune_in_bytes :: proc "contextless" (s: []u8) -> (rune, int) { +@(require_results) +decode_rune_in_bytes :: proc "contextless" (s: []u8) -> (rune, int) #no_bounds_check { n := len(s) if n < 1 { return RUNE_ERROR, 0 @@ -141,10 +146,11 @@ decode_rune_in_bytes :: proc "contextless" (s: []u8) -> (rune, int) { return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4 } -string_to_runes :: proc "odin" (s: string, allocator := context.allocator) -> (runes: []rune) { +@(require_results) +string_to_runes :: proc "odin" (s: string, allocator := context.allocator) -> (runes: []rune, err: runtime.Allocator_Error) #optional_allocator_error #no_bounds_check { n := rune_count_in_string(s) - runes = make([]rune, n, allocator) + runes = make([]rune, n, allocator) or_return i := 0 for r in s { runes[i] = r @@ -153,14 +159,15 @@ string_to_runes :: proc "odin" (s: string, allocator := context.allocator) -> (r return } -runes_to_string :: proc "odin" (runes: []rune, allocator := context.allocator) -> string { +@(require_results) +runes_to_string :: proc "odin" (runes: []rune, allocator := context.allocator) -> (s: string, err: runtime.Allocator_Error) #optional_allocator_error #no_bounds_check { byte_count := 0 for r in runes { _, w := encode_rune(r) byte_count += w } - bytes := make([]byte, byte_count, allocator) + bytes := make([]byte, byte_count, allocator) or_return offset := 0 for r in runes { b, w := encode_rune(r) @@ -168,7 +175,8 @@ runes_to_string :: proc "odin" (runes: []rune, allocator := context.allocator) - offset += w } - return string(bytes) + s = string(bytes) + return } @@ -177,10 +185,12 @@ decode_last_rune :: proc{ decode_last_rune_in_bytes, } +@(require_results) decode_last_rune_in_string :: #force_inline proc "contextless" (s: string) -> (rune, int) { return decode_last_rune_in_bytes(transmute([]u8)s) } -decode_last_rune_in_bytes :: proc "contextless" (s: []u8) -> (rune, int) { +@(require_results) +decode_last_rune_in_bytes :: proc "contextless" (s: []u8) -> (rune, int) #no_bounds_check { r: rune size: int start, end, limit: int @@ -212,6 +222,7 @@ decode_last_rune_in_bytes :: proc "contextless" (s: []u8) -> (rune, int) { return r, size } +@(require_results) rune_at_pos :: proc "contextless" (s: string, pos: int) -> rune { if pos < 0 { return RUNE_ERROR @@ -227,7 +238,8 @@ rune_at_pos :: proc "contextless" (s: string, pos: int) -> rune { return RUNE_ERROR } -rune_string_at_pos :: proc "contextless" (s: string, pos: int) -> string { +@(require_results) +rune_string_at_pos :: proc "contextless" (s: string, pos: int) -> string #no_bounds_check { if pos < 0 { return "" } @@ -243,13 +255,15 @@ rune_string_at_pos :: proc "contextless" (s: string, pos: int) -> string { return "" } -rune_at :: proc "contextless" (s: string, byte_index: int) -> rune { +@(require_results) +rune_at :: proc "contextless" (s: string, byte_index: int) -> rune #no_bounds_check { r, _ := decode_rune_in_string(s[byte_index:]) return r } // Returns the byte position of rune at position pos in s with an optional start byte position. // Returns -1 if it runs out of the string. +@(require_results) rune_offset :: proc "contextless" (s: string, pos: int, start: int = 0) -> int { if pos < 0 { return -1 @@ -265,6 +279,7 @@ rune_offset :: proc "contextless" (s: string, pos: int, start: int = 0) -> int { return -1 } +@(require_results) valid_rune :: proc "contextless" (r: rune) -> bool { if r < 0 { return false @@ -276,7 +291,8 @@ valid_rune :: proc "contextless" (r: rune) -> bool { return true } -valid_string :: proc "contextless" (s: string) -> bool { +@(require_results) +valid_string :: proc "contextless" (s: string) -> bool #no_bounds_check { n := len(s) for i := 0; i < n; { si := s[i] @@ -301,7 +317,7 @@ valid_string :: proc "contextless" (s: string) -> bool { return false } else if size == 3 { // Okay - } else if d := s[i+3]; b < 0x80 || 0xbf < d { + } else if d := s[i+3]; d < 0x80 || 0xbf < d { return false } i += size @@ -309,6 +325,7 @@ valid_string :: proc "contextless" (s: string) -> bool { return true } +@(require_results) rune_start :: #force_inline proc "contextless" (b: u8) -> bool { return b&0xc0 != 0x80 } @@ -318,10 +335,12 @@ rune_count :: proc{ rune_count_in_bytes, } +@(require_results) rune_count_in_string :: #force_inline proc(s: string) -> int { return rune_count_in_bytes(transmute([]u8)s) } -rune_count_in_bytes :: proc "contextless" (s: []u8) -> int { +@(require_results) +rune_count_in_bytes :: proc "contextless" (s: []u8) -> int #no_bounds_check { count := 0 n := len(s) @@ -360,6 +379,7 @@ rune_count_in_bytes :: proc "contextless" (s: []u8) -> int { } +@(require_results) rune_size :: proc "contextless" (r: rune) -> int { switch { case r < 0: return -1 @@ -381,7 +401,8 @@ full_rune :: proc{ // full_rune_in_bytes reports if the bytes in b begin with a full utf-8 encoding of a rune or not // An invalid encoding is considered a full rune since it will convert as an error rune of width 1 (RUNE_ERROR) -full_rune_in_bytes :: proc "contextless" (b: []byte) -> bool { +@(require_results) +full_rune_in_bytes :: proc "contextless" (b: []byte) -> bool #no_bounds_check { n := len(b) if n == 0 { return false @@ -401,6 +422,7 @@ full_rune_in_bytes :: proc "contextless" (b: []byte) -> bool { // full_rune_in_string reports if the bytes in s begin with a full utf-8 encoding of a rune or not // An invalid encoding is considered a full rune since it will convert as an error rune of width 1 (RUNE_ERROR) +@(require_results) full_rune_in_string :: proc "contextless" (s: string) -> bool { return full_rune_in_bytes(transmute([]byte)s) } diff --git a/examples/all/all_js.odin b/examples/all/all_js.odin index 28b85f537..3e45565e0 100644 --- a/examples/all/all_js.odin +++ b/examples/all/all_js.odin @@ -10,7 +10,7 @@ package all @(require) import "core:compress" @(require) import "core:compress/shoco" -@(require) import "core:compress/gzip" +// @(require) import "core:compress/gzip" @(require) import "core:compress/zlib" @(require) import "core:container/avl" @@ -27,12 +27,15 @@ package all @(require) import "core:crypto/aead" @(require) import "core:crypto/aegis" @(require) import "core:crypto/aes" +@(require) import "core:crypto/argon2id" @(require) import "core:crypto/blake2b" @(require) import "core:crypto/blake2s" @(require) import "core:crypto/chacha20" @(require) import "core:crypto/chacha20poly1305" @(require) import chash "core:crypto/hash" @(require) import "core:crypto/deoxysii" +@(require) import "core:crypto/ecdh" +@(require) import "core:crypto/ecdsa" @(require) import "core:crypto/ed25519" @(require) import "core:crypto/hkdf" @(require) import "core:crypto/hmac" @@ -98,13 +101,13 @@ package all @(require) import "core:mem" @(require) import "core:mem/tlsf" -@(require) import "core:mem/virtual" +// Not supported on JS +// @(require) import "core:mem/virtual" @(require) import "core:odin/ast" @(require) import doc_format "core:odin/doc-format" @(require) import "core:odin/tokenizer" -@(require) import "core:os" @(require) import "core:path/slashpath" @(require) import "core:relative" @@ -129,6 +132,7 @@ package all @(require) import "core:text/match" @(require) import "core:text/regex" @(require) import "core:text/scanner" +// Not supported on JS, uses `core:mem/virtual`. @(require) import "core:text/table" @(require) import "core:thread" @@ -139,10 +143,12 @@ package all @(require) import "core:sys/orca" @(require) import "core:sys/info" +@(require) import "core:sys/wasm/js" +@(require) import "core:sys/wasm/wasi" @(require) import "core:unicode" @(require) import "core:unicode/utf8" @(require) import "core:unicode/utf8/utf8string" @(require) import "core:unicode/utf16" -main :: proc() {} \ No newline at end of file +main :: proc() {} diff --git a/examples/all/all_linux.odin b/examples/all/all_linux.odin index 2b70fa1e1..d7d005ba0 100644 --- a/examples/all/all_linux.odin +++ b/examples/all/all_linux.odin @@ -2,4 +2,5 @@ package all @(require) import "core:sys/linux" -@(require) import "vendor:x11/xlib" \ No newline at end of file +@(require) import "core:sys/linux/uring" +@(require) import "vendor:x11/xlib" diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index cda04278e..65e4b917c 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -17,24 +17,30 @@ package all @(require) import "core:container/avl" @(require) import "core:container/bit_array" +@(require) import "core:container/handle_map" +@(require) import "core:container/intrusive/list" +@(require) import "core:container/lru" +@(require) import "core:container/pool" @(require) import "core:container/priority_queue" @(require) import "core:container/queue" -@(require) import "core:container/small_array" -@(require) import "core:container/lru" -@(require) import "core:container/intrusive/list" @(require) import "core:container/rbtree" +@(require) import "core:container/small_array" @(require) import "core:container/topological_sort" +@(require) import "core:container/xar" @(require) import "core:crypto" @(require) import "core:crypto/aead" @(require) import "core:crypto/aegis" @(require) import "core:crypto/aes" +@(require) import "core:crypto/argon2id" @(require) import "core:crypto/blake2b" @(require) import "core:crypto/blake2s" @(require) import "core:crypto/chacha20" @(require) import "core:crypto/chacha20poly1305" @(require) import chash "core:crypto/hash" @(require) import "core:crypto/deoxysii" +@(require) import "core:crypto/ecdh" +@(require) import "core:crypto/ecdsa" @(require) import "core:crypto/ed25519" @(require) import "core:crypto/hkdf" @(require) import "core:crypto/hmac" @@ -103,6 +109,8 @@ package all @(require) import "core:mem/tlsf" @(require) import "core:mem/virtual" +@(require) import "core:nbio" + @(require) import "core:odin/ast" @(require) import doc_format "core:odin/doc-format" @(require) import "core:odin/parser" @@ -111,7 +119,7 @@ package all @(require) import "core:prof/spall" @(require) import "core:os" -@(require) import "core:os/os2" +@(require) import "core:os/old" @(require) import "core:path/slashpath" @(require) import "core:path/filepath" @@ -155,4 +163,4 @@ package all @(require) import "core:unicode/utf8/utf8string" @(require) import "core:unicode/utf16" -main :: proc() {} \ No newline at end of file +main :: proc() {} diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin index 80f6c52bb..1605ea8a7 100644 --- a/examples/all/all_vendor.odin +++ b/examples/all/all_vendor.odin @@ -2,6 +2,7 @@ package all @(require) import "vendor:cgltf" +@(require) import "vendor:curl" @(require) import "vendor:ENet" @(require) import "vendor:OpenEXRCore" @(require) import "vendor:ggpo" @@ -30,6 +31,7 @@ package all // NOTE: needed for doc generator @(require) import "core:sys/darwin/Foundation" @(require) import "core:sys/darwin/CoreFoundation" +@(require) import "core:sys/darwin/CoreGraphics" @(require) import "core:sys/darwin/Security" @(require) import "vendor:darwin/CoreVideo" @(require) import "vendor:darwin/Metal" diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 1ea06d096..a12217548 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1,5 +1,5 @@ #+vet !using-stmt !using-param -#+feature dynamic-literals +#+feature dynamic-literals using-stmt package main import "core:fmt" @@ -751,6 +751,11 @@ union_type :: proc() { } using_statement :: proc() { + // IMPORTANT NOTE: `using` as a statement is an opt-in feature which can be abled + // by adding `#+feature using-stmt` to be beginning of the file + // + // `using` as a struct field modifier remains available always + fmt.println("\n# using statement") // using can used to bring entities declared in a scope/namespace // into the current scope. This can be applied to import names, struct @@ -1601,7 +1606,7 @@ where_clauses :: proc() { where intrinsics.type_is_numeric(E) { x := a.y*b.z - a.z*b.y y := a.z*b.x - a.x*b.z - z := a.x*b.y - a.y*b.z + z := a.x*b.y - a.y*b.x return T{x, y, z} } @@ -2242,7 +2247,7 @@ arbitrary_precision_mathematics :: proc() { cb := big.internal_count_bits(a) if print_name { - fmt.printf(name) + fmt.print(name) } if err != nil { fmt.printf(" (Error: %v) ", err) diff --git a/src/big_int.cpp b/src/big_int.cpp index 0b0a9a400..e2ebb5c76 100644 --- a/src/big_int.cpp +++ b/src/big_int.cpp @@ -16,14 +16,25 @@ void MP_FREE(void *mem, size_t size) { #else void *MP_MALLOC(size_t size) { - return gb_alloc(permanent_allocator(), cast(isize)size); + Arena *arena = get_arena(ThreadArena_Permanent); + return arena_alloc(arena, cast(isize)size, 16); } void *MP_REALLOC(void *mem, size_t oldsize, size_t newsize) { - return gb_resize(permanent_allocator(), mem, cast(isize)oldsize, cast(isize)newsize); + if (newsize < oldsize) { + return mem; + } + if (newsize == 0) { + return mem; + } + Arena *arena = get_arena(ThreadArena_Permanent); + void *new_mem = arena_alloc(arena, cast(isize)newsize, 16); + gb_memcopy(new_mem, mem, oldsize); + return new_mem; } void *MP_CALLOC(size_t nmemb, size_t size) { - size_t total = nmemb*size; - return gb_alloc(permanent_allocator(), cast(isize)total); + Arena *arena = get_arena(ThreadArena_Permanent); + isize total_size = cast(isize)(nmemb * size); + return arena_alloc(arena, total_size, 16); } void MP_FREE(void *mem, size_t size) { // DO NOTHING @@ -46,6 +57,8 @@ gb_internal void big_int_dealloc(BigInt *dst) { mp_clear(dst); } +gb_internal bool big_int_can_be_represented_in_64_bits(BigInt const *x); + gb_internal BigInt big_int_make(BigInt const *b, bool abs=false); gb_internal BigInt big_int_make_abs(BigInt const *b); gb_internal BigInt big_int_make_u64(u64 x); @@ -197,8 +210,13 @@ gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success BigInt b = {}; big_int_from_u64(&b, base); + defer (big_int_dealloc(&b)); + mp_zero(dst); + BigInt digit = {}; + defer (big_int_dealloc(&digit)); + isize i = 0; for (; i < len; i++) { Rune r = cast(Rune)text[i]; @@ -224,9 +242,10 @@ gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success } break; } - BigInt val = big_int_make_u64(v); + + big_int_from_u64(&digit, v); big_int_mul_eq(dst, &b); - big_int_add_eq(dst, &val); + big_int_add_eq(dst, &digit); } if (i < len && (text[i] == 'e' || text[i] == 'E')) { i += 1; @@ -235,6 +254,7 @@ gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success if (text[i] == '+') { i += 1; } + u64 exp = 0; for (; i < len; i++) { char r = cast(char)text[i]; @@ -251,8 +271,19 @@ gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success exp *= 10; exp += v; } + + // NOTE(Jeroen): A valid integer can never have an exponent larger than 308 (per `max(f64)`). + // As an integer, not even larger than `max(u128)` which has a base 10 exponent of 38. + // But we also use this path to parse float literals like those in `core:math.pow10_f64`, + // so we have to stick with 1e308. + if (exp > 308) { + *success = false; + return; + } + BigInt tmp = {}; mp_init(&tmp); + defer (big_int_dealloc(&tmp)); big_int_exp_u64(&tmp, &b, exp, success); big_int_mul_eq(dst, &tmp); } @@ -264,6 +295,11 @@ gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success +gb_internal bool big_int_can_be_represented_in_64_bits(BigInt const *x) { + int bits_used = (x->used-1) * MP_DIGIT_BIT; + return bits_used <= 64; +} + gb_internal u64 big_int_to_u64(BigInt const *x) { GB_ASSERT(x->sign == 0); return mp_get_u64(x); diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 757df95f7..9663d5db5 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -9,6 +9,7 @@ // #endif #define DEFAULT_MAX_ERROR_COLLECTOR_COUNT (36) +#define DEFAULT_DID_YOU_MEAN_LIMIT (10) enum TargetOsKind : u16 { TargetOs_Invalid, @@ -360,12 +361,13 @@ enum OptInFeatureFlags : u64 { OptInFeatureFlag_IntegerDivisionByZero_Self = 1u<<4, OptInFeatureFlag_IntegerDivisionByZero_AllBits = 1u<<5, - OptInFeatureFlag_IntegerDivisionByZero_ALL = OptInFeatureFlag_IntegerDivisionByZero_Trap| OptInFeatureFlag_IntegerDivisionByZero_Zero| OptInFeatureFlag_IntegerDivisionByZero_Self| OptInFeatureFlag_IntegerDivisionByZero_AllBits, + OptInFeatureFlag_ForceTypeAssert = 1u<<6, + OptInFeatureFlag_UsingStmt = 1u<<7, }; u64 get_feature_flag_from_name(String const &name) { @@ -384,6 +386,12 @@ u64 get_feature_flag_from_name(String const &name) { if (name == "integer-division-by-zero:all-bits") { return OptInFeatureFlag_IntegerDivisionByZero_AllBits; } + if (name == "using-stmt") { + return OptInFeatureFlag_UsingStmt; + } + if (name == "force-type-assert") { + return OptInFeatureFlag_ForceTypeAssert; + } if (name == "global-context") { @@ -413,6 +421,12 @@ struct BuildCacheData { }; +enum LTOKind : i32 { + LTO_None, + LTO_Thin, + LTO_Thin_Files, +}; + enum LinkerChoice : i32 { Linker_Invalid = -1, Linker_Default = 0, @@ -525,6 +539,7 @@ struct BuildContext { bool different_os; bool keep_object_files; bool disallow_do; + bool show_import_graph; IntegerDivisionByZeroKind integer_division_by_zero_behaviour; @@ -553,6 +568,7 @@ struct BuildContext { bool use_single_module; bool use_separate_modules; + LTOKind lto_kind; bool module_per_file; bool cached; BuildCacheData build_cache_data; @@ -561,11 +577,16 @@ struct BuildContext { bool internal_by_value; bool internal_weak_monomorphization; bool internal_ignore_llvm_verification; + bool internal_llvm_mem2reg; + + bool enable_rvo; bool no_threaded_checker; bool show_debug_messages; + int did_you_mean_limit; + bool copy_file_contents; bool no_rtti; @@ -582,6 +603,7 @@ struct BuildContext { RelocMode reloc_mode; bool disable_red_zone; + bool disable_unwind; isize max_error_count; @@ -835,10 +857,19 @@ gb_global TargetMetrics target_freestanding_amd64_win64 = { TargetOs_freestanding, TargetArch_amd64, 8, 8, AMD64_MAX_ALIGNMENT, 32, - str_lit("x86_64-pc-none-msvc"), + str_lit("x86_64-pc-windows-msvc"), TargetABI_Win64, }; +gb_global TargetMetrics target_freestanding_amd64_mingw = { + TargetOs_freestanding, + TargetArch_amd64, + 8, 8, AMD64_MAX_ALIGNMENT, 32, + str_lit("x86_64-pc-windows-gnu"), + TargetABI_Win64, +}; + + gb_global TargetMetrics target_freestanding_arm64 = { TargetOs_freestanding, TargetArch_arm64, @@ -901,6 +932,7 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv }, { str_lit("freestanding_amd64_win64"), &target_freestanding_amd64_win64 }, + { str_lit("freestanding_amd64_mingw"), &target_freestanding_amd64_mingw }, { str_lit("freestanding_arm64"), &target_freestanding_arm64 }, { str_lit("freestanding_arm32"), &target_freestanding_arm32 }, @@ -1654,7 +1686,20 @@ gb_internal void init_android_values(bool with_sdk) { gb_exit(1); } - bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB = concatenate_strings(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN, str_lit("sysroot/usr/lib/aarch64-linux-android/")); + switch (bc->metrics.arch) { + case TargetArch_arm64: + bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB = str_lit("aarch64-linux-android"); + break; + case TargetArch_arm32: + bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB = str_lit("arm-linux-androideabi"); + break; + case TargetArch_amd64: + bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB = str_lit("x86_64-linux-android"); + break; + case TargetArch_i386: + bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB = str_lit("i686-linux-android"); + break; + } char buf[32] = {}; gb_snprintf(buf, gb_size_of(buf), "%d/", bc->ODIN_ANDROID_API_LEVEL); @@ -1703,6 +1748,29 @@ gb_internal char *token_pos_to_string(TokenPos const &pos) { return s; } +gb_internal String normalize_minimum_os_version_string(String version) { + GB_ASSERT(version.len > 0); + + gbString normalized = gb_string_make(permanent_allocator(), ""); + + int granularity = 0; + String_Iterator it = {version, 0}; + for (;; granularity++) { + String str = string_split_iterator(&it, '.'); + if (str == "") break; + if (granularity > 0) { + normalized = gb_string_appendc(normalized, "."); + } + normalized = gb_string_append_length(normalized, str.text, str.len); + } + + for (; granularity < 3; granularity++) { + normalized = gb_string_appendc(normalized, ".0"); + } + + return make_string_c(normalized); +} + gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subtarget) { BuildContext *bc = &build_context; @@ -1836,7 +1904,7 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta if (bc->disable_red_zone) { if (is_arch_wasm() && bc->metrics.os == TargetOs_freestanding) { - gb_printf_err("-disable-red-zone is not support for this target"); + gb_printf_err("-disable-red-zone is not supported on this target"); gb_exit(1); } } @@ -1906,9 +1974,22 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta } else if (metrics->os == TargetOs_linux && subtarget == Subtarget_Android) { switch (metrics->arch) { case TargetArch_arm64: - bc->metrics.target_triplet = str_lit("aarch64-none-linux-android"); + bc->metrics.target_triplet = str_lit("aarch64-linux-android"); bc->reloc_mode = RelocMode_PIC; break; + case TargetArch_arm32: + bc->metrics.target_triplet = str_lit("armv7a-linux-androideabi"); + bc->reloc_mode = RelocMode_PIC; + break; + case TargetArch_amd64: + bc->metrics.target_triplet = str_lit("x86_64-linux-android"); + bc->reloc_mode = RelocMode_PIC; + break; + case TargetArch_i386: + bc->metrics.target_triplet = str_lit("i686-linux-android"); + bc->reloc_mode = RelocMode_PIC; + break; + default: GB_PANIC("Unknown architecture for -subtarget:android"); } @@ -1972,10 +2053,12 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta } else if (subtarget == Subtarget_iPhone || subtarget == Subtarget_iPhoneSimulator) { // NOTE(harold): We default to 17.4 on iOS because that's when os_sync_wait_on_address was added and // we'd like to avoid any potential App Store issues by using the private ulock_* there. - bc->minimum_os_version_string = str_lit("17.4"); + bc->minimum_os_version_string = str_lit("17.4.0"); } } + bc->minimum_os_version_string = normalize_minimum_os_version_string(bc->minimum_os_version_string); + if (subtarget == Subtarget_iPhoneSimulator) { // For the iPhoneSimulator subtarget, the version must be between 'ios' and '-simulator'. String suffix = str_lit("-simulator"); @@ -2012,6 +2095,29 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta bc->use_separate_modules = false; } + if (bc->lto_kind == LTO_Thin || bc->lto_kind == LTO_Thin_Files) { +#if LLVM_VERSION_MAJOR < 17 + gb_printf_err("-lto:thin requires LLVM 17 or later\n"); + gb_exit(1); +#endif + if (bc->build_mode == BuildMode_Assembly || bc->build_mode == BuildMode_LLVM_IR) { + gb_printf_err("-lto:thin is incompatible with -build-mode:asm and -build-mode:llvm-ir\n"); + gb_exit(1); + } +#if defined(GB_SYSTEM_WINDOWS) + if (bc->linker_choice != Linker_lld) { + gb_printf_err("-lto:thin on Windows requires -linker:lld\n"); + gb_exit(1); + } +#endif + if (bc->use_single_module) { + gb_printf_err("Warning: -lto:thin overrides -use-single-module; separate modules will be used\n"); + } + bc->use_separate_modules = true; + if (bc->lto_kind == LTO_Thin_Files) { + bc->module_per_file = true; + } + } bc->ODIN_VALGRIND_SUPPORT = false; if (build_context.metrics.os != TargetOs_windows) { @@ -2054,8 +2160,15 @@ gb_internal bool check_target_feature_is_valid(String const &feature, TargetArch String_Iterator it = {feature, 0}; for (;;) { String str = string_split_iterator(&it, ','); - if (str == "") break; - if (!check_single_target_feature_is_valid(feature_list, str)) { + String feature_str = str; + if (string_starts_with(feature_str, '+') || string_starts_with(feature_str, '-')) { + feature_str = substring(feature_str, 1, feature_str.len); + if (feature_str == "") { + return false; + } + } + if (feature_str == "") break; + if (!check_single_target_feature_is_valid(feature_list, feature_str)) { if (invalid) *invalid = str; return false; } @@ -2095,20 +2208,26 @@ gb_internal bool check_target_feature_is_enabled(String const &feature, String * String_Iterator it = {feature, 0}; for (;;) { String str = string_split_iterator(&it, ','); - if (str == "") break; + String feature_str = str; + bool want_enabled = true; + if (string_starts_with(feature_str, '+') || string_starts_with(feature_str, '-')) { + want_enabled = feature_str[0] == '+'; + feature_str = substring(feature_str, 1, feature_str.len); + } + if (feature_str == "") break; if (!string_set_exists(&build_context.target_features_set, str)) { - String plus_str = concatenate_strings(temporary_allocator(), make_string_c("+"), str); + String plus_str = concatenate_strings(temporary_allocator(), make_string_c("+"), feature_str); - if (!string_set_exists(&build_context.target_features_set, plus_str)) { + if (want_enabled && !string_set_exists(&build_context.target_features_set, plus_str)) { if (not_enabled) *not_enabled = str; return false; } } - String minus_str = concatenate_strings(temporary_allocator(), make_string_c("-"), str); + String minus_str = concatenate_strings(temporary_allocator(), make_string_c("-"), feature_str); - if (string_set_exists(&build_context.target_features_set, minus_str)) { + if (!want_enabled && !string_set_exists(&build_context.target_features_set, minus_str)) { if (not_enabled) *not_enabled = str; return false; } diff --git a/src/build_settings_microarch.cpp b/src/build_settings_microarch.cpp index 0755aa62d..d3010522d 100644 --- a/src/build_settings_microarch.cpp +++ b/src/build_settings_microarch.cpp @@ -2,7 +2,595 @@ #error "LLVM_VERSION_MAJOR is not defined!" #endif -#if LLVM_VERSION_MAJOR >= 21 + +#if LLVM_VERSION_MAJOR >= 22 +// Generated with the featuregen script in `misc/featuregen` +gb_global String target_microarch_list[TargetArch_COUNT] = { + // TargetArch_Invalid: + str_lit(""), + // TargetArch_amd64: + str_lit("alderlake,amdfam10,arrowlake,arrowlake-s,arrowlake_s,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,cannonlake,cascadelake,clearwaterforest,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,diamondrapids,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,gracemont,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,lunarlake,meteorlake,mic_avx512,nehalem,nocona,novalake,opteron,opteron-sse3,pantherlake,penryn,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,wildcatlake,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4,znver5"), + // TargetArch_i386: + str_lit("alderlake,amdfam10,arrowlake,arrowlake-s,arrowlake_s,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,cannonlake,cascadelake,clearwaterforest,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,diamondrapids,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,gracemont,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,lunarlake,meteorlake,mic_avx512,nehalem,nocona,novalake,opteron,opteron-sse3,pantherlake,penryn,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,wildcatlake,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4,znver5"), + // TargetArch_arm32: + str_lit("arm1020e,arm1020t,arm1022e,arm10e,arm10tdmi,arm1136j-s,arm1136jf-s,arm1156t2-s,arm1156t2f-s,arm1176jz-s,arm1176jzf-s,arm710t,arm720t,arm7tdmi,arm7tdmi-s,arm8,arm810,arm9,arm920,arm920t,arm922t,arm926ej-s,arm940t,arm946e-s,arm966e-s,arm968e-s,arm9e,arm9tdmi,cortex-a12,cortex-a15,cortex-a17,cortex-a32,cortex-a35,cortex-a5,cortex-a510,cortex-a53,cortex-a55,cortex-a57,cortex-a7,cortex-a710,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78ae,cortex-a78c,cortex-a8,cortex-a9,cortex-m0,cortex-m0plus,cortex-m1,cortex-m23,cortex-m3,cortex-m33,cortex-m35p,cortex-m4,cortex-m52,cortex-m55,cortex-m7,cortex-m85,cortex-r4,cortex-r4f,cortex-r5,cortex-r52,cortex-r52plus,cortex-r7,cortex-r8,cortex-x1,cortex-x1c,cyclone,ep9312,exynos-m3,exynos-m4,exynos-m5,generic,iwmmxt,krait,kryo,mpcore,mpcorenovfp,neoverse-n1,neoverse-n2,neoverse-v1,sc000,sc300,star-mc1,star-mc3,strongarm,strongarm110,strongarm1100,strongarm1110,swift,xscale"), + // TargetArch_arm64: + str_lit("a64fx,ampere1,ampere1a,ampere1b,ampere1c,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a17,apple-a18,apple-a19,apple-a7,apple-a8,apple-a9,apple-m1,apple-m2,apple-m3,apple-m4,apple-m5,apple-s10,apple-s4,apple-s5,apple-s6,apple-s7,apple-s8,apple-s9,c1-nano,c1-premium,c1-pro,c1-ultra,carmel,cobalt-100,cortex-a320,cortex-a34,cortex-a35,cortex-a510,cortex-a520,cortex-a520ae,cortex-a53,cortex-a55,cortex-a57,cortex-a65,cortex-a65ae,cortex-a710,cortex-a715,cortex-a72,cortex-a720,cortex-a720ae,cortex-a725,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78ae,cortex-a78c,cortex-r82,cortex-r82ae,cortex-x1,cortex-x1c,cortex-x2,cortex-x3,cortex-x4,cortex-x925,cyclone,exynos-m3,exynos-m4,exynos-m5,falkor,fujitsu-monaka,gb10,generic,grace,kryo,neoverse-512tvb,neoverse-e1,neoverse-n1,neoverse-n2,neoverse-n3,neoverse-v1,neoverse-v2,neoverse-v3,neoverse-v3ae,olympus,oryon-1,saphira,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tsv110"), + // TargetArch_wasm32: + str_lit("bleeding-edge,generic,lime1,mvp"), + // TargetArch_wasm64p32: + str_lit("bleeding-edge,generic,lime1,mvp"), + // TargetArch_riscv64: + str_lit("andes-45-series,andes-a25,andes-a45,andes-ax25,andes-ax45,andes-ax45mpv,andes-n45,andes-nx45,generic,generic-ooo,generic-rv32,generic-rv64,mips-p8700,rocket,rocket-rv32,rocket-rv64,rp2350-hazard3,sifive-7-series,sifive-e20,sifive-e21,sifive-e24,sifive-e31,sifive-e34,sifive-e76,sifive-p450,sifive-p470,sifive-p550,sifive-p670,sifive-p870,sifive-s21,sifive-s51,sifive-s54,sifive-s76,sifive-u54,sifive-u74,sifive-x280,sifive-x390,spacemit-x60,syntacore-scr1-base,syntacore-scr1-max,syntacore-scr3-rv32,syntacore-scr3-rv64,syntacore-scr4-rv32,syntacore-scr4-rv64,syntacore-scr5-rv32,syntacore-scr5-rv64,syntacore-scr7,tt-ascalon-d8,veyron-v1,xiangshan-kunminghu,xiangshan-nanhu"), +}; + +// Generated with the featuregen script in `misc/featuregen` +gb_global String target_features_list[TargetArch_COUNT] = { + // TargetArch_Invalid: + str_lit(""), + // TargetArch_amd64: + str_lit("16bit-mode,32bit-mode,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-avx512,amx-bf16,amx-complex,amx-fp16,amx-fp8,amx-int8,amx-movrs,amx-tf32,amx-tile,avx,avx10.1,avx10.1-512,avx10.2,avx10.2-512,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branch-hint,branchfusion,ccmp,cf,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-dpwssd,fast-gather,fast-hops,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,inline-asm-use-gpr32,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,mwaitx,ndd,nf,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,ppx,prefer-128-bit,prefer-256-bit,prefer-legacy-setcc,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prfchw,ptwrite,push2pop2,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-pmullq,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x32,x87,xop,xsave,xsavec,xsaveopt,xsaves,zu"), + // TargetArch_i386: + str_lit("16bit-mode,32bit-mode,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-avx512,amx-bf16,amx-complex,amx-fp16,amx-fp8,amx-int8,amx-movrs,amx-tf32,amx-tile,avx,avx10.1,avx10.1-512,avx10.2,avx10.2-512,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branch-hint,branchfusion,ccmp,cf,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-dpwssd,fast-gather,fast-hops,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,inline-asm-use-gpr32,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,mwaitx,ndd,nf,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,ppx,prefer-128-bit,prefer-256-bit,prefer-legacy-setcc,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prfchw,ptwrite,push2pop2,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-pmullq,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x32,x87,xop,xsave,xsavec,xsaveopt,xsaves,zu"), + // TargetArch_arm32: + str_lit("32bit,8msecext,a12,a15,a17,a32,a35,a5,a53,a55,a57,a7,a72,a73,a75,a76,a77,a78c,a8,a9,aapcs-frame-chain,aclass,acquire-release,aes,armv4,armv4t,armv5t,armv5te,armv5tej,armv6,armv6-m,armv6j,armv6k,armv6kz,armv6s-m,armv6t2,armv7-a,armv7-m,armv7-r,armv7e-m,armv7k,armv7s,armv7ve,armv8-a,armv8-m.base,armv8-m.main,armv8-r,armv8.1-a,armv8.1-m.main,armv8.2-a,armv8.3-a,armv8.4-a,armv8.5-a,armv8.6-a,armv8.7-a,armv8.8-a,armv8.9-a,armv9-a,armv9.1-a,armv9.2-a,armv9.3-a,armv9.4-a,armv9.5-a,armv9.6-a,armv9.7-a,atomics-32,avoid-movs-shop,avoid-muls,avoid-partial-cpsr,bf16,big-endian-instructions,branch-align-64,cde,cdecp0,cdecp1,cdecp2,cdecp3,cdecp4,cdecp5,cdecp6,cdecp7,cheap-predicable-cpsr,clrbhb,cortex-a510,cortex-a710,cortex-a78,cortex-a78ae,cortex-x1,cortex-x1c,crc,crypto,d32,db,dfb,disable-postra-scheduler,dont-widen-vmovs,dotprod,dsp,execute-only,expand-fp-mlx,exynos,fix-cmse-cve-2021-35465,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpao,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hwdiv,hwdiv-arm,i8mm,iwmmxt,iwmmxt2,krait,kryo,lob,long-calls,loop-align,m3,m55,m7,m85,mclass,mp,muxed-units,mve,mve.fp,mve1beat,mve2beat,mve4beat,neon,neon-fpmovs,neonfp,neoverse-v1,no-branch-predictor,no-bti-at-return-twice,no-movt,no-neg-immediates,noarm,nonpipelined-vfp,pacbti,perfmon,prefer-ishst,prefer-vmovsr,prof-unpr,r4,r5,r52,r52plus,r7,ras,rclass,read-tp-tpidrprw,read-tp-tpidruro,read-tp-tpidrurw,reserve-r9,ret-addr-stack,sb,sha2,slow-fp-brcc,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,soft-float,splat-vfp-neon,strict-align,swift,thumb-mode,thumb2,trustzone,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.1m.main,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8m,v8m.main,v9.1a,v9.2a,v9.3a,v9.4a,v9.5a,v9.6a,v9.7a,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align,vmlx-forwarding,vmlx-hazards,wide-stride-vfp,xscale,zcz"), + // TargetArch_arm64: + str_lit("CONTEXTIDREL2,a320,a35,a510,a520,a520ae,a53,a55,a57,a64fx,a65,a710,a715,a72,a720,a720ae,a73,a75,a76,a77,a78,a78ae,a78c,addr-lsl-slow-14,aes,aggressive-fma,aggressive-interleaving,all,alternate-sextload-cvt-f32-pattern,altnzcv,alu-lsl-fast,am,ampere1,ampere1a,ampere1b,ampere1c,amvs,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a17,apple-a7,apple-m4,apple-m5,arith-bcc-fusion,arith-cbz-fusion,ascend-store-address,avoid-ldapur,balance-fp-ops,bf16,brbe,bti,btie,c1-nano,c1-premium,c1-pro,c1-ultra,call-saved-x10,call-saved-x11,call-saved-x12,call-saved-x13,call-saved-x14,call-saved-x15,call-saved-x18,call-saved-x8,call-saved-x9,carmel,ccdp,ccidx,ccpp,chk,clrbhb,cmh,cmp-bcc-fusion,cmpbr,complxnum,cortex-a725,cortex-r82,cortex-r82ae,cortex-x1,cortex-x2,cortex-x3,cortex-x4,cortex-x925,cpa,crc,crypto,cssc,d128,disable-fast-inc-vl,disable-latency-sched-heuristic,disable-ldp,disable-maximize-scalable-bandwidth,disable-stp,disable-unpredicated-ld-st-lower,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,execute-only,exynos-cheap-as-move,exynosm3,exynosm4,f16f32dot,f16f32mm,f16mm,f32mm,f64mm,f8f16mm,f8f32mm,falkor,faminmax,fgt,fix-cortex-a53-835769,flagm,fmv,force-32bit-jump-tables,fp-armv8,fp16fml,fp8,fp8dot2,fp8dot4,fp8fma,fpac,fprcvt,fptoint,fujitsu-monaka,fullfp16,fuse-address,fuse-addsub-2reg-const1,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-cset,fuse-literals,gcie,gcs,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hbc,hcx,i8mm,ite,jsconv,kryo,ldp-aligned-only,lor,ls64,lscp,lse,lse128,lse2,lsfe,lsui,lut,max-interleave-factor-4,mec,mops,mops-go,mpam,mpamv2,mte,mtetc,neon,neoverse512tvb,neoversee1,neoversen1,neoversen2,neoversen3,neoversev1,neoversev2,neoversev3,neoversev3AE,nmi,no-bti-at-return-twice,no-neg-immediates,no-sve-fp-ld1r,no-zcz-fpr64,nv,occmo,olympus,oryon-1,outline-atomics,pan,pan-rwv,pauth,pauth-lr,pcdphint,perfmon,poe2,pops,predictable-select-expensive,predres,prfm-slc-target,rand,ras,rasv2,rcpc,rcpc-immo,rcpc3,rdm,reserve-lr-for-ra,reserve-x1,reserve-x10,reserve-x11,reserve-x12,reserve-x13,reserve-x14,reserve-x15,reserve-x18,reserve-x2,reserve-x20,reserve-x21,reserve-x22,reserve-x23,reserve-x24,reserve-x25,reserve-x26,reserve-x27,reserve-x28,reserve-x3,reserve-x4,reserve-x5,reserve-x6,reserve-x7,reserve-x9,rme,saphira,sb,sel2,sha2,sha3,slow-misaligned-128store,slow-paired-128,slow-strqro-store,sm4,sme,sme-b16b16,sme-f16f16,sme-f64f64,sme-f8f16,sme-f8f32,sme-fa64,sme-i16i64,sme-lutv2,sme-mop4,sme-tmop,sme2,sme2p1,sme2p2,sme2p3,spe,spe-eef,specres2,specrestrict,ssbs,ssve-aes,ssve-bitperm,ssve-fexpa,ssve-fp8dot2,ssve-fp8dot4,ssve-fp8fma,store-pair-suppress,stp-aligned-only,strict-align,sve,sve-aes,sve-aes2,sve-b16b16,sve-b16mm,sve-bfscale,sve-bitperm,sve-f16f32mm,sve-sha3,sve-sm4,sve2,sve2-aes,sve2-bitperm,sve2-sha3,sve2-sm4,sve2p1,sve2p2,sve2p3,tagged-globals,tev,the,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tlb-rmi,tlbid,tlbiw,tpidr-el1,tpidr-el2,tpidr-el3,tpidrro-el0,tracev8.4,trbe,tsv110,uaops,use-experimental-zeroing-pseudos,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,use-reciprocal-square-root,use-wzr-to-vec-move,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8a,v8r,v9.1a,v9.2a,v9.3a,v9.4a,v9.5a,v9.6a,v9.7a,v9a,vh,wfxt,xs,zcm-fpr128,zcm-fpr32,zcm-fpr64,zcm-gpr32,zcm-gpr64,zcz-fp-workaround,zcz-fpr128,zcz-gpr32,zcz-gpr64"), + // TargetArch_wasm32: + str_lit("atomics,bulk-memory,bulk-memory-opt,call-indirect-overlong,exception-handling,extended-const,fp16,gc,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call,wide-arithmetic"), + // TargetArch_wasm64p32: + str_lit("atomics,bulk-memory,bulk-memory-opt,call-indirect-overlong,exception-handling,extended-const,fp16,gc,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call,wide-arithmetic"), + // TargetArch_riscv64: + str_lit("32bit,64bit,a,add-load-fusion,addi-load-fusion,andes45,auipc-addi-fusion,auipc-load-fusion,b,bfext-fusion,c,conditional-cmv-fusion,d,disable-latency-sched-heuristic,disable-misched-load-clustering,disable-misched-store-clustering,disable-postmisched-load-clustering,disable-postmisched-store-clustering,dlen-factor-2,e,enable-vsetvli-sched-heuristic,exact-asm,experimental,experimental-p,experimental-rvm23u32,experimental-smpmpmt,experimental-svukte,experimental-xrivosvisni,experimental-xrivosvizip,experimental-xsfmclic,experimental-xsfsclic,experimental-zibi,experimental-zicfilp,experimental-zicfiss,experimental-zvbc32e,experimental-zvfbfa,experimental-zvfofp8min,experimental-zvkgs,experimental-zvqdotq,f,forced-atomics,h,i,ld-add-fusion,log-vrgather,lui-addi-fusion,lui-load-fusion,m,mips-p8700,no-default-unroll,no-sink-splat-operands,no-trailing-seq-cst-fence,optimized-nf2-segment-load-store,optimized-nf3-segment-load-store,optimized-nf4-segment-load-store,optimized-nf5-segment-load-store,optimized-nf6-segment-load-store,optimized-nf7-segment-load-store,optimized-nf8-segment-load-store,optimized-zero-stride-load,permissive-zalrsc,predictable-select-expensive,prefer-vsetvli-over-read-vlenb,prefer-w-inst,q,relax,reserve-x1,reserve-x10,reserve-x11,reserve-x12,reserve-x13,reserve-x14,reserve-x15,reserve-x16,reserve-x17,reserve-x18,reserve-x19,reserve-x2,reserve-x20,reserve-x21,reserve-x22,reserve-x23,reserve-x24,reserve-x25,reserve-x26,reserve-x27,reserve-x28,reserve-x29,reserve-x3,reserve-x30,reserve-x31,reserve-x4,reserve-x5,reserve-x6,reserve-x7,reserve-x8,reserve-x9,rva20s64,rva20u64,rva22s64,rva22u64,rva23s64,rva23u64,rvb23s64,rvb23u64,rvi20u32,rvi20u64,save-restore,sdext,sdtrig,sha,shcounterenw,shgatpa,shifted-zextw-fusion,shlcofideleg,short-forward-branch-ialu,short-forward-branch-iload,short-forward-branch-iminmax,short-forward-branch-imul,shtvala,shvsatpa,shvstvala,shvstvecd,shxadd-load-fusion,sifive7,single-element-vec-fp64,smaia,smcdeleg,smcntrpmf,smcsrind,smctr,smdbltrp,smepmp,smmpm,smnpm,smrnmi,smstateen,ssaia,ssccfg,ssccptr,sscofpmf,sscounterenw,sscsrind,ssctr,ssdbltrp,ssnpm,sspm,ssqosid,ssstateen,ssstrict,sstc,sstvala,sstvecd,ssu64xl,supm,svade,svadu,svbare,svinval,svnapot,svpbmt,svvptc,tagged-globals,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,ventana-veyron,vl-dependent-latency,vxrm-pipeline-flush,xandesbfhcvt,xandesperf,xandesvbfhcvt,xandesvdot,xandesvpackfph,xandesvsinth,xandesvsintload,xcvalu,xcvbi,xcvbitmanip,xcvelw,xcvmac,xcvmem,xcvsimd,xmipscbop,xmipscmov,xmipsexectl,xmipslsp,xqccmp,xqci,xqcia,xqciac,xqcibi,xqcibm,xqcicli,xqcicm,xqcics,xqcicsr,xqciint,xqciio,xqcilb,xqcili,xqcilia,xqcilo,xqcilsm,xqcisim,xqcisls,xqcisync,xsfcease,xsfmm128t,xsfmm16t,xsfmm32a16f,xsfmm32a32f,xsfmm32a8f,xsfmm32a8i,xsfmm32t,xsfmm64a64f,xsfmm64t,xsfmmbase,xsfvcp,xsfvfbfexp16e,xsfvfexp16e,xsfvfexp32e,xsfvfexpa,xsfvfexpa64e,xsfvfnrclipxfqf,xsfvfwmaccqqq,xsfvqmaccdod,xsfvqmaccqoq,xsifivecdiscarddlone,xsifivecflushdlone,xsmtvdot,xtheadba,xtheadbb,xtheadbs,xtheadcmo,xtheadcondmov,xtheadfmemidx,xtheadmac,xtheadmemidx,xtheadmempair,xtheadsync,xtheadvdot,xventanacondops,xwchc,za128rs,za64rs,zaamo,zabha,zacas,zalasr,zalrsc,zama16b,zawrs,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zca,zcb,zcd,zce,zcf,zclsd,zcmop,zcmp,zcmt,zdinx,zexth-fusion,zextw-fusion,zfa,zfbfmin,zfh,zfhmin,zfinx,zhinx,zhinxmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccamoc,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintntl,zihintpause,zihpm,zilsd,zilsd-4byte-align,zimop,zk,zkn,zknd,zkne,zknh,zkr,zks,zksed,zksh,zkt,zmmul,ztso,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvfbfmin,zvfbfwma,zvfh,zvfhmin,zvkb,zvkg,zvkn,zvknc,zvkned,zvkng,zvknha,zvknhb,zvks,zvksc,zvksed,zvksg,zvksh,zvkt,zvl1024b,zvl128b,zvl16384b,zvl2048b,zvl256b,zvl32768b,zvl32b,zvl4096b,zvl512b,zvl64b,zvl65536b,zvl8192b"), +}; + +// Generated with the featuregen script in `misc/featuregen` +gb_global int target_microarch_counts[TargetArch_COUNT] = { + // TargetArch_Invalid: + 0, + // TargetArch_amd64: + 131, + // TargetArch_i386: + 131, + // TargetArch_arm32: + 96, + // TargetArch_arm64: + 98, + // TargetArch_wasm32: + 4, + // TargetArch_wasm64p32: + 4, + // TargetArch_riscv64: + 51, +}; + +// Generated with the featuregen script in `misc/featuregen` +gb_global MicroarchFeatureList microarch_features_list[] = { + // TargetArch_amd64: + { str_lit("alderlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("amdfam10"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,idivq-to-divl,lzcnt,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("arrowlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("arrowlake-s"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,slow-pmullq,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("arrowlake_s"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,slow-pmullq,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("athlon"), str_lit("64bit-mode,cmov,cx8,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-fx"), str_lit("64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-mp"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-tbird"), str_lit("64bit-mode,cmov,cx8,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-xp"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon64"), str_lit("64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon64-sse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("atom"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-imm16,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("atom_sse4_2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("atom_sse4_2_movbe"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fsgsbase,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("barcelona"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,idivq-to-divl,lzcnt,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("bdver1"), str_lit("64bit,64bit-mode,aes,avx,branchfusion,cmov,crc32,cx16,cx8,fast-11bytenop,fast-scalar-shift-masks,fma4,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver2"), str_lit("64bit,64bit-mode,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver3"), str_lit("64bit,64bit-mode,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bdver4"), str_lit("64bit,64bit-mode,aes,avx,avx2,bmi,bmi2,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,idivq-to-divl,lwp,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bonnell"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-imm16,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("broadwell"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("btver1"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-15bytenop,fast-imm16,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,idivq-to-divl,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,ssse3,vzeroupper,x87") }, + { str_lit("btver2"), str_lit("64bit,64bit-mode,aes,avx,bmi,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-hops,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,x87,xsave,xsaveopt") }, + { str_lit("c3"), str_lit("64bit-mode,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("c3-2"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("cannonlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vl,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,sha,slow-3ops-lea,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cascadelake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("clearwaterforest"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,slow-pmullq,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cooperlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("core-avx-i"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core-avx2"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core2"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_sse4_1"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_ssse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2nd_gen_avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_3rd_gen_avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx_tsx"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx_tsx"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_aes_pclmulqdq"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("core_i7_sse4_2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7-avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("diamondrapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-avx512,amx-bf16,amx-complex,amx-fp16,amx-fp8,amx-int8,amx-movrs,amx-tf32,amx-tile,avx,avx10.1,avx10.2,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branch-hint,ccmp,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,ndd,nf,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,ppx,prefer-256-bit,prefetchi,prfchw,ptwrite,push2pop2,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-pmullq,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves,zu") }, + { str_lit("emeraldrapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("generic"), str_lit("64bit,64bit-mode,cx8,fast-15bytenop,fast-scalar-fsqrt,idivq-to-divl,macrofusion,slow-3ops-lea,sse,sse2,vzeroupper,x87") }, + { str_lit("geode"), str_lit("64bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("goldmont"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont-plus"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont_plus"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("gracemont"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxvnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("grandridge"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids-d"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids_d"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("haswell"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("i386"), str_lit("64bit-mode,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("i486"), str_lit("64bit-mode,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("i586"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("i686"), str_lit("64bit-mode,cmov,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("icelake-client"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake-server"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_client"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_server"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("ivybridge"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("k6"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k6-2"), str_lit("64bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k6-3"), str_lit("64bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k8"), str_lit("64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k8-sse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("knl"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512f,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("knm"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512f,avx512vpopcntdq,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("lakemont"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper") }, + { str_lit("lunarlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,slow-pmullq,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("meteorlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("mic_avx512"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512f,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("nehalem"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("nocona"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("novalake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx10.1,avx10.2,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,ccmp,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,ndd,nf,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,ppx,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,push2pop2,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,slow-pmullq,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,x87,xsave,xsavec,xsaveopt,xsaves,zu") }, + { str_lit("opteron"), str_lit("64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("opteron-sse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pantherlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,slow-pmullq,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("penryn"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("pentium"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium-m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium-mmx"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium2"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium3"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium3m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium4m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4_sse3"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pentium_ii"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_iii"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_iii_no_xmm_regs"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_mmx"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_pro"), str_lit("64bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentiumpro"), str_lit("64bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("prescott"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("raptorlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("rocketlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sandybridge"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("sapphirerapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sierraforest"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("silvermont"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("skx"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake-avx512"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake_avx512"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("slm"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("tigerlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,shstk,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("tremont"), str_lit("64bit,64bit-mode,aes,clflushopt,clwb,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,gfni,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("westmere"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("wildcatlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,slow-pmullq,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("winchip-c6"), str_lit("64bit-mode,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("winchip2"), str_lit("64bit-mode,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("x86-64"), str_lit("64bit,64bit-mode,cmov,cx8,fxsr,idivq-to-divl,macrofusion,mmx,nopl,slow-3ops-lea,slow-incdec,sse,sse2,vzeroupper,x87") }, + { str_lit("x86-64-v2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,nopl,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("x86-64-v3"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("x86-64-v4"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,prefer-256-bit,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("yonah"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("znver1"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver2"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver3"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver4"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-dpwssd,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver5"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxvnni,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-dpwssd,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,nopl,pclmul,pku,popcnt,prefetchi,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + // TargetArch_i386: + { str_lit("alderlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("amdfam10"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,idivq-to-divl,lzcnt,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("arrowlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("arrowlake-s"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,slow-pmullq,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("arrowlake_s"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,slow-pmullq,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("athlon"), str_lit("32bit-mode,cmov,cx8,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("athlon-4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("athlon-fx"), str_lit("32bit-mode,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-mp"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("athlon-tbird"), str_lit("32bit-mode,cmov,cx8,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("athlon-xp"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("athlon64"), str_lit("32bit-mode,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon64-sse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("atom"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-imm16,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("atom_sse4_2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("atom_sse4_2_movbe"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fsgsbase,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("barcelona"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,idivq-to-divl,lzcnt,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("bdver1"), str_lit("32bit-mode,64bit,aes,avx,branchfusion,cmov,crc32,cx16,cx8,fast-11bytenop,fast-scalar-shift-masks,fma4,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver2"), str_lit("32bit-mode,64bit,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver3"), str_lit("32bit-mode,64bit,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bdver4"), str_lit("32bit-mode,64bit,aes,avx,avx2,bmi,bmi2,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,idivq-to-divl,lwp,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bonnell"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-imm16,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("broadwell"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("btver1"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-15bytenop,fast-imm16,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,idivq-to-divl,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,ssse3,vzeroupper,x87") }, + { str_lit("btver2"), str_lit("32bit-mode,64bit,aes,avx,bmi,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-hops,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,x87,xsave,xsaveopt") }, + { str_lit("c3"), str_lit("32bit-mode,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("c3-2"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("cannonlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vl,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,sha,slow-3ops-lea,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cascadelake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("clearwaterforest"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,slow-pmullq,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cooperlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("core-avx-i"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core-avx2"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core2"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_sse4_1"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_ssse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2nd_gen_avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_3rd_gen_avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx_tsx"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx_tsx"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_aes_pclmulqdq"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("core_i7_sse4_2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7-avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("diamondrapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-avx512,amx-bf16,amx-complex,amx-fp16,amx-fp8,amx-int8,amx-movrs,amx-tf32,amx-tile,avx,avx10.1,avx10.2,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branch-hint,ccmp,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,ndd,nf,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,ppx,prefer-256-bit,prefetchi,prfchw,ptwrite,push2pop2,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-pmullq,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves,zu") }, + { str_lit("emeraldrapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("generic"), str_lit("32bit-mode,64bit,cx8,fast-15bytenop,fast-scalar-fsqrt,idivq-to-divl,macrofusion,slow-3ops-lea,vzeroupper,x87") }, + { str_lit("geode"), str_lit("32bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("goldmont"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont-plus"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont_plus"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("gracemont"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxvnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("grandridge"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids-d"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids_d"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("haswell"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("i386"), str_lit("32bit-mode,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("i486"), str_lit("32bit-mode,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("i586"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("i686"), str_lit("32bit-mode,cmov,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("icelake-client"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake-server"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_client"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_server"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("ivybridge"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("k6"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("k6-2"), str_lit("32bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("k6-3"), str_lit("32bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("k8"), str_lit("32bit-mode,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k8-sse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("knl"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512f,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("knm"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512f,avx512vpopcntdq,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("lakemont"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper") }, + { str_lit("lunarlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,slow-pmullq,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("meteorlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("mic_avx512"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512f,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("nehalem"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("nocona"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("novalake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx10.1,avx10.2,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,ccmp,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,ndd,nf,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,ppx,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,push2pop2,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,slow-pmullq,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,x87,xsave,xsavec,xsaveopt,xsaves,zu") }, + { str_lit("opteron"), str_lit("32bit-mode,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("opteron-sse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pantherlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,slow-pmullq,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("penryn"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("pentium"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium-m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium-mmx"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium2"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium3"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium3m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium4m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4_sse3"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pentium_ii"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium_iii"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium_iii_no_xmm_regs"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium_m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_mmx"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium_pro"), str_lit("32bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentiumpro"), str_lit("32bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("prescott"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("raptorlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("rocketlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sandybridge"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("sapphirerapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sierraforest"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("silvermont"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("skx"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake-avx512"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake_avx512"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("slm"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("tigerlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,shstk,slow-pmullq,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("tremont"), str_lit("32bit-mode,64bit,aes,clflushopt,clwb,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,gfni,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("westmere"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("wildcatlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,slow-pmullq,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("winchip-c6"), str_lit("32bit-mode,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("winchip2"), str_lit("32bit-mode,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("x86-64"), str_lit("32bit-mode,64bit,cmov,cx8,fxsr,idivq-to-divl,macrofusion,mmx,nopl,slow-3ops-lea,slow-incdec,sse,sse2,vzeroupper,x87") }, + { str_lit("x86-64-v2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,nopl,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("x86-64-v3"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("x86-64-v4"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,prefer-256-bit,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("yonah"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("znver1"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver2"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver3"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver4"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-dpwssd,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver5"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxvnni,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-dpwssd,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,nopl,pclmul,pku,popcnt,prefetchi,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + // TargetArch_arm32: + { str_lit("arm1020e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm1020t"), str_lit("armv5t,v4t,v5t") }, + { str_lit("arm1022e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm10e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm10tdmi"), str_lit("armv5t,v4t,v5t") }, + { str_lit("arm1136j-s"), str_lit("armv6,dsp,v4t,v5t,v5te,v6") }, + { str_lit("arm1136jf-s"), str_lit("armv6,dsp,fp64,fpregs,fpregs64,slowfpvmlx,v4t,v5t,v5te,v6,vfp2,vfp2sp") }, + { str_lit("arm1156t2-s"), str_lit("armv6t2,dsp,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v8m") }, + { str_lit("arm1156t2f-s"), str_lit("armv6t2,dsp,fp64,fpregs,fpregs64,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v8m,vfp2,vfp2sp") }, + { str_lit("arm1176jz-s"), str_lit("armv6kz,trustzone,v4t,v5t,v5te,v6,v6k") }, + { str_lit("arm1176jzf-s"), str_lit("armv6kz,fp64,fpregs,fpregs64,slowfpvmlx,trustzone,v4t,v5t,v5te,v6,v6k,vfp2,vfp2sp") }, + { str_lit("arm710t"), str_lit("armv4t,v4t") }, + { str_lit("arm720t"), str_lit("armv4t,v4t") }, + { str_lit("arm7tdmi"), str_lit("armv4t,v4t") }, + { str_lit("arm7tdmi-s"), str_lit("armv4t,v4t") }, + { str_lit("arm8"), str_lit("armv4") }, + { str_lit("arm810"), str_lit("armv4") }, + { str_lit("arm9"), str_lit("armv4t,v4t") }, + { str_lit("arm920"), str_lit("armv4t,v4t") }, + { str_lit("arm920t"), str_lit("armv4t,v4t") }, + { str_lit("arm922t"), str_lit("armv4t,v4t") }, + { str_lit("arm926ej-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm940t"), str_lit("armv4t,v4t") }, + { str_lit("arm946e-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm966e-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm968e-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm9e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm9tdmi"), str_lit("armv4t,v4t") }, + { str_lit("cortex-a12"), str_lit("a12,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") }, + { str_lit("cortex-a15"), str_lit("a15,aclass,armv7-a,avoid-partial-cpsr,d32,db,dont-widen-vmovs,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,muxed-units,neon,perfmon,ret-addr-stack,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align") }, + { str_lit("cortex-a17"), str_lit("a17,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") }, + { str_lit("cortex-a32"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a35"), str_lit("a35,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a5"), str_lit("a5,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,mp,neon,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-forwarding") }, + { str_lit("cortex-a510"), str_lit("aclass,acquire-release,armv9-a,bf16,cortex-a710,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a53"), str_lit("a53,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a55"), str_lit("a55,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a57"), str_lit("a57,aclass,acquire-release,aes,armv8-a,avoid-partial-cpsr,cheap-predicable-cpsr,crc,crypto,d32,db,dsp,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a7"), str_lit("a7,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-a710"), str_lit("aclass,acquire-release,armv9-a,bf16,cortex-a710,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a72"), str_lit("a72,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a73"), str_lit("a73,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a75"), str_lit("a75,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a76"), str_lit("a76,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a76ae"), str_lit("a76,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a77"), str_lit("a77,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a78"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-a78,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a78ae"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-a78ae,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a78c"), str_lit("a78c,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a8"), str_lit("a8,aclass,armv7-a,d32,db,dsp,fp64,fpregs,fpregs64,neon,nonpipelined-vfp,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-a9"), str_lit("a9,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,expand-fp-mlx,fp16,fp64,fpregs,fpregs64,mp,muxed-units,neon,neon-fpmovs,perfmon,prefer-vmovsr,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vldn-align,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-m0"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("cortex-m0plus"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("cortex-m1"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("cortex-m23"), str_lit("8msecext,acquire-release,armv8-m.base,db,hwdiv,mclass,no-branch-predictor,no-movt,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m,v7clrex,v8m") }, + { str_lit("cortex-m3"), str_lit("armv7-m,db,hwdiv,loop-align,m3,mclass,no-branch-predictor,noarm,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, + { str_lit("cortex-m33"), str_lit("8msecext,acquire-release,armv8-m.main,avoid-muls,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("cortex-m35p"), str_lit("8msecext,acquire-release,armv8-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("cortex-m4"), str_lit("armv7e-m,db,dsp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("cortex-m52"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,loop-align,mclass,mve,mve.fp,mve1beat,no-branch-predictor,noarm,pacbti,ras,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-m55"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,loop-align,m55,mclass,mve,mve.fp,no-branch-predictor,noarm,ras,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-m7"), str_lit("armv7e-m,branch-align-64,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs64,hwdiv,m7,mclass,noarm,thumb-mode,thumb2,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-m85"), str_lit("8msecext,acquire-release,armv8.1-m.main,branch-align-64,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,m85,mclass,mve,mve.fp,noarm,pacbti,ras,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-r4"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,hwdiv,perfmon,r4,rclass,ret-addr-stack,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, + { str_lit("cortex-r4f"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp64,fpregs,fpregs64,hwdiv,perfmon,r4,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-r5"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,perfmon,r5,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-r52"), str_lit("acquire-release,armv8-r,crc,d32,db,dfb,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,r52,rclass,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-r52plus"), str_lit("acquire-release,armv8-r,crc,d32,db,dfb,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,r52plus,rclass,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-r7"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,r7,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-r8"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-x1"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-x1,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-x1c"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-x1c,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cyclone"), str_lit("aclass,acquire-release,aes,armv8-a,avoid-movs-shop,avoid-partial-cpsr,crc,crypto,d32,db,disable-postra-scheduler,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,neonfp,perfmon,ret-addr-stack,sha2,slowfpvfmx,slowfpvmlx,swift,thumb2,trustzone,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,zcz") }, + { str_lit("ep9312"), str_lit("armv4t,v4t") }, + { str_lit("exynos-m3"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dont-widen-vmovs,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, + { str_lit("exynos-m4"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dont-widen-vmovs,dotprod,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ras,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, + { str_lit("exynos-m5"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dont-widen-vmovs,dotprod,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ras,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, + { str_lit("generic"), str_lit("") }, + { str_lit("iwmmxt"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("krait"), str_lit("aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,krait,muxed-units,neon,perfmon,ret-addr-stack,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vldn-align,vmlx-forwarding") }, + { str_lit("kryo"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,kryo,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("mpcore"), str_lit("armv6k,fp64,fpregs,fpregs64,slowfpvmlx,v4t,v5t,v5te,v6,v6k,vfp2,vfp2sp") }, + { str_lit("mpcorenovfp"), str_lit("armv6k,v4t,v5t,v5te,v6,v6k") }, + { str_lit("neoverse-n1"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("neoverse-n2"), str_lit("aclass,acquire-release,armv9-a,bf16,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("neoverse-v1"), str_lit("aclass,acquire-release,aes,armv8.4-a,bf16,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("sc000"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("sc300"), str_lit("armv7-m,db,hwdiv,m3,mclass,no-branch-predictor,noarm,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, + { str_lit("star-mc1"), str_lit("8msecext,acquire-release,armv8-m.main,avoid-muls,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("star-mc3"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,loop-align,mclass,mve,mve.fp,mve1beat,no-branch-predictor,noarm,pacbti,ras,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("strongarm"), str_lit("armv4") }, + { str_lit("strongarm110"), str_lit("armv4") }, + { str_lit("strongarm1100"), str_lit("armv4") }, + { str_lit("strongarm1110"), str_lit("armv4") }, + { str_lit("swift"), str_lit("aclass,armv7-a,avoid-movs-shop,avoid-partial-cpsr,d32,db,disable-postra-scheduler,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,neonfp,perfmon,prefer-ishst,prof-unpr,ret-addr-stack,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,swift,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-hazards,wide-stride-vfp") }, + { str_lit("xscale"), str_lit("armv5te,v4t,v5t,v5te") }, + // TargetArch_arm64: + { str_lit("a64fx"), str_lit("CONTEXTIDREL2,a64fx,aes,aggressive-fma,arith-bcc-fusion,ccpp,complxnum,crc,disable-unpredicated-ld-st-lower,el2vmsa,el3,fp-armv8,fullfp16,lor,lse,max-interleave-factor-4,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rdm,sha2,store-pair-suppress,sve,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("ampere1"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,max-interleave-factor-4,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, + { str_lit("ampere1a"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1a,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fptoint,fullfp16,fuse-address,fuse-addsub-2reg-const1,fuse-adrp-add,fuse-aes,fuse-literals,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,max-interleave-factor-4,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, + { str_lit("ampere1b"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1b,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,cssc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,fgt,flagm,fp-armv8,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,hcx,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,max-interleave-factor-4,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,vh,wfxt,xs") }, + { str_lit("ampere1c"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1c,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,cssc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,faminmax,fgt,flagm,fp-armv8,fp16fml,fp8,fp8fma,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,lut,max-interleave-factor-4,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,specrestrict,ssbs,store-pair-suppress,sve,sve-aes,sve-b16b16,sve-sha3,sve-sm4,sve2,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("apple-a10"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a10,arith-bcc-fusion,arith-cbz-fusion,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,lor,neon,no-zcz-fpr64,pan,perfmon,rdm,sha2,store-pair-suppress,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-a11"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a11,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,lor,lse,neon,no-zcz-fpr64,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-a12"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,no-zcz-fpr64,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-a13"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,am,apple-a13,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,lse2,mpam,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-a14"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,alternate-sextload-cvt-f32-pattern,altnzcv,am,apple-a14,arith-bcc-fusion,arith-cbz-fusion,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-a15"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a15,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,i8mm,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-a16"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-a17"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a17,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-a18"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-m4,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sme,sme-f64f64,sme-i16i64,sme2,specrestrict,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,vh,wfxt,xs,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-a19"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-m5,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,cssc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hbc,hcx,i8mm,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,mte,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sme,sme-b16b16,sme-f16f16,sme-f64f64,sme-i16i64,sme2,sme2p1,specres2,specrestrict,sve-b16b16,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,vh,wfxt,xs,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-a7"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,arith-bcc-fusion,arith-cbz-fusion,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,no-zcz-fpr64,perfmon,sha2,store-pair-suppress,v8a,zcm-fpr128,zcm-gpr64,zcz-fp-workaround,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-a8"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,arith-bcc-fusion,arith-cbz-fusion,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,no-zcz-fpr64,perfmon,sha2,store-pair-suppress,v8a,zcm-fpr128,zcm-gpr64,zcz-fp-workaround,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-a9"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,arith-bcc-fusion,arith-cbz-fusion,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,no-zcz-fpr64,perfmon,sha2,store-pair-suppress,v8a,zcm-fpr128,zcm-gpr64,zcz-fp-workaround,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-m1"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,alternate-sextload-cvt-f32-pattern,altnzcv,am,apple-a14,arith-bcc-fusion,arith-cbz-fusion,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-m2"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a15,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,i8mm,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-m3"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-m4"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-m4,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sme,sme-f64f64,sme-i16i64,sme2,specrestrict,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,vh,wfxt,xs,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-m5"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-m5,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,cssc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hbc,hcx,i8mm,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,mte,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sme,sme-b16b16,sme-f16f16,sme-f64f64,sme-i16i64,sme2,sme2p1,specres2,specrestrict,sve-b16b16,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,vh,wfxt,xs,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-s10"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-s4"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,no-zcz-fpr64,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-s5"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,no-zcz-fpr64,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-s6"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,am,apple-a13,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,lse2,mpam,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-s7"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,am,apple-a13,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,lse2,mpam,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-s8"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,am,apple-a13,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,lse2,mpam,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("apple-s9"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,neon,no-zcz-fpr64,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm-fpr128,zcm-gpr64,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("c1-nano"), str_lit("CONTEXTIDREL2,altnzcv,am,amvs,bf16,bti,c1-nano,ccdp,ccidx,ccpp,chk,clrbhb,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hbc,hcx,i8mm,jsconv,lor,lse,lse2,mops,mpam,mte,neon,nmi,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rcpc3,rdm,sb,sel2,sme,sme2,specres2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,use-wzr-to-vec-move,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8a,v9.1a,v9.2a,v9.3a,v9a,vh,wfxt,xs") }, + { str_lit("c1-premium"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,bti,c1-premium,ccdp,ccidx,ccpp,chk,clrbhb,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,hbc,hcx,i8mm,jsconv,lor,lse,lse2,mops,mpam,mte,neon,nmi,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rcpc3,rdm,sb,sel2,sme,sme2,spe,spe-eef,specres2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8a,v9.1a,v9.2a,v9.3a,v9a,vh,wfxt,xs") }, + { str_lit("c1-pro"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,c1-pro,ccdp,ccidx,ccpp,chk,clrbhb,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,hbc,hcx,i8mm,jsconv,lor,lse,lse2,mops,mpam,mte,neon,nmi,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rcpc3,rdm,sb,sel2,sme,sme2,spe,spe-eef,specres2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8a,v9.1a,v9.2a,v9.3a,v9a,vh,wfxt,xs") }, + { str_lit("c1-ultra"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,bti,c1-ultra,ccdp,ccidx,ccpp,chk,clrbhb,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,hbc,hcx,i8mm,jsconv,lor,lse,lse2,mops,mpam,mte,neon,nmi,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rcpc3,rdm,sb,sel2,sme,sme2,spe,spe-eef,specres2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8a,v9.1a,v9.2a,v9.3a,v9a,vh,wfxt,xs") }, + { str_lit("carmel"), str_lit("CONTEXTIDREL2,aes,carmel,ccpp,crc,el2vmsa,el3,fp-armv8,fullfp16,lor,lse,neon,pan,pan-rwv,ras,rdm,sha2,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cobalt-100"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,disable-maximize-scalable-bandwidth,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversen2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a320"), str_lit("CONTEXTIDREL2,a320,aggressive-interleaving,altnzcv,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,use-wzr-to-vec-move,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a34"), str_lit("a35,aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,sha2,v8a") }, + { str_lit("cortex-a35"), str_lit("a35,aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,sha2,v8a") }, + { str_lit("cortex-a510"), str_lit("CONTEXTIDREL2,a510,altnzcv,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,use-wzr-to-vec-move,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a520"), str_lit("CONTEXTIDREL2,a520,altnzcv,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,use-wzr-to-vec-move,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a520ae"), str_lit("CONTEXTIDREL2,a520ae,altnzcv,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-wzr-to-vec-move,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a53"), str_lit("a53,aes,balance-fp-ops,crc,el2vmsa,el3,fp-armv8,fuse-adrp-add,fuse-aes,neon,perfmon,sha2,use-postra-scheduler,use-wzr-to-vec-move,v8a") }, + { str_lit("cortex-a55"), str_lit("CONTEXTIDREL2,a55,aes,ccpp,crc,dotprod,el2vmsa,el3,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,ras,rcpc,rdm,sha2,uaops,use-postra-scheduler,use-wzr-to-vec-move,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a57"), str_lit("a57,addr-lsl-slow-14,aes,balance-fp-ops,crc,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,fuse-literals,max-interleave-factor-4,neon,perfmon,predictable-select-expensive,sha2,use-postra-scheduler,v8a") }, + { str_lit("cortex-a65"), str_lit("CONTEXTIDREL2,a65,aes,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a65ae"), str_lit("CONTEXTIDREL2,a65,aes,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a710"), str_lit("CONTEXTIDREL2,a710,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a715"), str_lit("CONTEXTIDREL2,a715,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a72"), str_lit("a72,addr-lsl-slow-14,aes,crc,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,v8a") }, + { str_lit("cortex-a720"), str_lit("CONTEXTIDREL2,a720,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a720ae"), str_lit("CONTEXTIDREL2,a720ae,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a725"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,cortex-a725,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a73"), str_lit("a73,addr-lsl-slow-14,aes,crc,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,neon,perfmon,predictable-select-expensive,sha2,v8a") }, + { str_lit("cortex-a75"), str_lit("CONTEXTIDREL2,a75,addr-lsl-slow-14,aes,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a76"), str_lit("CONTEXTIDREL2,a76,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a76ae"), str_lit("CONTEXTIDREL2,a76,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a77"), str_lit("CONTEXTIDREL2,a77,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a78"), str_lit("CONTEXTIDREL2,a78,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a78ae"), str_lit("CONTEXTIDREL2,a78ae,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a78c"), str_lit("CONTEXTIDREL2,a78c,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,lor,lse,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-r82"), str_lit("CONTEXTIDREL2,ccdp,ccpp,complxnum,cortex-r82,crc,dit,dotprod,flagm,fp-armv8,fp16fml,fpac,fullfp16,jsconv,lse,neon,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8r") }, + { str_lit("cortex-r82ae"), str_lit("CONTEXTIDREL2,ccdp,ccpp,complxnum,cortex-r82ae,crc,dit,dotprod,flagm,fp-armv8,fp16fml,fpac,fullfp16,jsconv,lse,neon,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8r") }, + { str_lit("cortex-x1"), str_lit("CONTEXTIDREL2,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,cortex-x1,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-x1c"), str_lit("CONTEXTIDREL2,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,cortex-x1,crc,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,lse2,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rcpc-immo,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-x2"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,cortex-x2,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-x3"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x3,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-x4"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x4,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-x925"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x925,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cyclone"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,arith-bcc-fusion,arith-cbz-fusion,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,no-zcz-fpr64,perfmon,sha2,store-pair-suppress,v8a,zcm-fpr128,zcm-gpr64,zcz-fp-workaround,zcz-fpr128,zcz-gpr32,zcz-gpr64") }, + { str_lit("exynos-m3"), str_lit("aes,alu-lsl-fast,crc,el2vmsa,el3,exynos-cheap-as-move,exynosm3,force-32bit-jump-tables,fp-armv8,fuse-address,fuse-adrp-add,fuse-aes,fuse-csel,fuse-literals,max-interleave-factor-4,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,use-postra-scheduler,v8a") }, + { str_lit("exynos-m4"), str_lit("CONTEXTIDREL2,aes,alu-lsl-fast,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,dotprod,el2vmsa,el3,exynos-cheap-as-move,exynosm4,force-32bit-jump-tables,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-csel,fuse-literals,lor,lse,max-interleave-factor-4,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh,zcz-gpr32,zcz-gpr64") }, + { str_lit("exynos-m5"), str_lit("CONTEXTIDREL2,aes,alu-lsl-fast,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,dotprod,el2vmsa,el3,exynos-cheap-as-move,exynosm4,force-32bit-jump-tables,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-csel,fuse-literals,lor,lse,max-interleave-factor-4,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh,zcz-gpr32,zcz-gpr64") }, + { str_lit("falkor"), str_lit("aes,alu-lsl-fast,crc,el2vmsa,el3,falkor,fp-armv8,max-interleave-factor-4,neon,perfmon,predictable-select-expensive,rdm,sha2,slow-strqro-store,store-pair-suppress,use-postra-scheduler,v8a,zcz-gpr32,zcz-gpr64") }, + { str_lit("fujitsu-monaka"), str_lit("CONTEXTIDREL2,aes,altnzcv,am,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,clrbhb,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,faminmax,fgt,flagm,fp-armv8,fp16fml,fp8,fp8dot2,fp8dot4,fp8fma,fpac,fptoint,fujitsu-monaka,fullfp16,hbc,hcx,i8mm,jsconv,lor,ls64,lse,lse2,lut,mec,mops,mpam,neon,nmi,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,sha2,sha3,sm4,specres2,specrestrict,ssbs,sve,sve-aes,sve-bitperm,sve-sha3,sve-sm4,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8a,v9.1a,v9.2a,v9.3a,v9a,vh,wfxt,xs") }, + { str_lit("gb10"), str_lit("CONTEXTIDREL2,aes,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x925,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,spe,spe-eef,specrestrict,ssbs,sve,sve-aes,sve-bitperm,sve-sha3,sve-sm4,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("generic"), str_lit("enable-select-opt,ete,fp-armv8,fuse-adrp-add,fuse-aes,neon,trbe,use-postra-scheduler") }, + { str_lit("grace"), str_lit("CONTEXTIDREL2,aes,altnzcv,alu-lsl-fast,am,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,i8mm,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,mte,neon,neoversev2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,spe,specrestrict,ssbs,sve,sve-aes,sve-bitperm,sve-sha3,sve-sm4,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("kryo"), str_lit("aes,alu-lsl-fast,crc,el2vmsa,el3,fp-armv8,kryo,max-interleave-factor-4,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,use-postra-scheduler,v8a,zcz-gpr32,zcz-gpr64") }, + { str_lit("neoverse-512tvb"), str_lit("CONTEXTIDREL2,aes,alu-lsl-fast,am,bf16,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fp16fml,fpac,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,neon,neoverse512tvb,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,rand,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,sm4,spe,ssbs,sve,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh") }, + { str_lit("neoverse-e1"), str_lit("CONTEXTIDREL2,aes,ccpp,crc,dotprod,el2vmsa,el3,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,neoversee1,pan,pan-rwv,perfmon,ras,rcpc,rdm,sha2,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("neoverse-n1"), str_lit("CONTEXTIDREL2,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,neoversen1,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("neoverse-n2"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,disable-maximize-scalable-bandwidth,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversen2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("neoverse-n3"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversen3,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("neoverse-v1"), str_lit("CONTEXTIDREL2,addr-lsl-slow-14,aes,alu-lsl-fast,am,bf16,ccdp,ccidx,ccpp,complxnum,crc,disable-maximize-scalable-bandwidth,dit,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fp16fml,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,i8mm,jsconv,lor,lse,lse2,mpam,neon,neoversev1,no-sve-fp-ld1r,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,rand,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,sm4,spe,ssbs,sve,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh") }, + { str_lit("neoverse-v2"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,i8mm,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,mte,neon,neoversev2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("neoverse-v3"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,brbe,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,hcx,i8mm,jsconv,lor,ls64,lse,lse2,max-interleave-factor-4,mpam,mte,neon,neoversev3,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("neoverse-v3ae"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,brbe,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,fuse-csel,fuse-cset,hcx,i8mm,jsconv,lor,ls64,lse,lse2,max-interleave-factor-4,mpam,mte,neon,neoversev3AE,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("olympus"), str_lit("CONTEXTIDREL2,aes,altnzcv,alu-lsl-fast,am,amvs,bf16,brbe,bti,ccdp,ccidx,ccpp,chk,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,faminmax,fgt,flagm,fp-armv8,fp16fml,fp8,fp8dot2,fp8dot4,fp8fma,fpac,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,ls64,lse,lse2,lut,max-interleave-factor-4,mec,mpam,mte,neon,nv,olympus,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,sha2,sha3,sm4,spe,spe-eef,specrestrict,ssbs,sve,sve-aes,sve-bitperm,sve-sha3,sve-sm4,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("oryon-1"), str_lit("CONTEXTIDREL2,aes,altnzcv,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-crypto-eor,i8mm,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,neon,nv,oryon-1,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,spe,specrestrict,ssbs,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, + { str_lit("saphira"), str_lit("CONTEXTIDREL2,aes,alu-lsl-fast,am,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,jsconv,lor,lse,lse2,max-interleave-factor-4,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rcpc-immo,rdm,saphira,sel2,sha2,spe,store-pair-suppress,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcz-gpr32,zcz-gpr64") }, + { str_lit("thunderx"), str_lit("aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderx,use-postra-scheduler,v8a") }, + { str_lit("thunderx2t99"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,arith-bcc-fusion,crc,el2vmsa,el3,fp-armv8,lor,lse,max-interleave-factor-4,neon,pan,predictable-select-expensive,rdm,sha2,store-pair-suppress,thunderx2t99,use-postra-scheduler,v8.1a,v8a,vh") }, + { str_lit("thunderx3t110"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,arith-bcc-fusion,balance-fp-ops,ccidx,ccpp,complxnum,crc,el2vmsa,el3,fp-armv8,jsconv,lor,lse,max-interleave-factor-4,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,store-pair-suppress,strict-align,thunderx3t110,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8a,vh") }, + { str_lit("thunderxt81"), str_lit("aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt81,use-postra-scheduler,v8a") }, + { str_lit("thunderxt83"), str_lit("aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt83,use-postra-scheduler,v8a") }, + { str_lit("thunderxt88"), str_lit("aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt88,use-postra-scheduler,v8a") }, + { str_lit("tsv110"), str_lit("CONTEXTIDREL2,aes,ccpp,complxnum,crc,dotprod,el2vmsa,el3,fp-armv8,fp16fml,fullfp16,fuse-aes,jsconv,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,spe,store-pair-suppress,tsv110,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + // TargetArch_wasm32: + { str_lit("bleeding-edge"), str_lit("atomics,bulk-memory,bulk-memory-opt,call-indirect-overlong,exception-handling,extended-const,fp16,gc,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call") }, + { str_lit("generic"), str_lit("bulk-memory,bulk-memory-opt,call-indirect-overlong,multivalue,mutable-globals,nontrapping-fptoint,reference-types,sign-ext") }, + { str_lit("lime1"), str_lit("bulk-memory-opt,call-indirect-overlong,extended-const,multivalue,mutable-globals,nontrapping-fptoint,sign-ext") }, + { str_lit("mvp"), str_lit("") }, + // TargetArch_wasm64p32: + { str_lit("bleeding-edge"), str_lit("atomics,bulk-memory,bulk-memory-opt,call-indirect-overlong,exception-handling,extended-const,fp16,gc,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call") }, + { str_lit("generic"), str_lit("bulk-memory,bulk-memory-opt,call-indirect-overlong,multivalue,mutable-globals,nontrapping-fptoint,reference-types,sign-ext") }, + { str_lit("lime1"), str_lit("bulk-memory-opt,call-indirect-overlong,extended-const,multivalue,mutable-globals,nontrapping-fptoint,sign-ext") }, + { str_lit("mvp"), str_lit("") }, + // TargetArch_riscv64: + { str_lit("andes-45-series"), str_lit("andes45,no-default-unroll,short-forward-branch-ialu,use-postra-scheduler") }, + { str_lit("andes-a25"), str_lit("32bit,a,c,d,f,i,m,xandesperf,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("andes-a45"), str_lit("32bit,a,andes45,c,d,f,i,m,no-default-unroll,short-forward-branch-ialu,use-postra-scheduler,xandesperf,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("andes-ax25"), str_lit("64bit,a,c,d,f,i,m,xandesperf,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("andes-ax45"), str_lit("64bit,a,andes45,c,d,f,i,m,no-default-unroll,short-forward-branch-ialu,use-postra-scheduler,xandesperf,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("andes-ax45mpv"), str_lit("64bit,a,andes45,c,d,f,i,m,no-default-unroll,short-forward-branch-ialu,use-postra-scheduler,v,xandesperf,zaamo,zalrsc,zca,zicsr,zifencei,zmmul,zve32f,zve32x,zve64d,zve64f,zve64x,zvl128b,zvl32b,zvl64b") }, + { str_lit("andes-n45"), str_lit("32bit,a,andes45,c,d,f,i,m,no-default-unroll,short-forward-branch-ialu,use-postra-scheduler,xandesperf,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("andes-nx45"), str_lit("64bit,a,andes45,c,d,f,i,m,no-default-unroll,short-forward-branch-ialu,use-postra-scheduler,xandesperf,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("generic"), str_lit("64bit,i,optimized-nf2-segment-load-store") }, + { str_lit("generic-ooo"), str_lit("") }, + { str_lit("generic-rv32"), str_lit("32bit,i,optimized-nf2-segment-load-store") }, + { str_lit("generic-rv64"), str_lit("64bit,i,optimized-nf2-segment-load-store") }, + { str_lit("mips-p8700"), str_lit("64bit,a,c,d,f,i,m,mips-p8700,xmipscbop,xmipscmov,xmipsexectl,xmipslsp,zaamo,zalrsc,zba,zbb,zca,zicsr,zifencei,zmmul") }, + { str_lit("rocket"), str_lit("") }, + { str_lit("rocket-rv32"), str_lit("32bit,i,zicsr,zifencei") }, + { str_lit("rocket-rv64"), str_lit("64bit,i,zicsr,zifencei") }, + { str_lit("rp2350-hazard3"), str_lit("32bit,a,c,i,m,zaamo,zalrsc,zba,zbb,zbkb,zbs,zca,zcb,zcmp,zicsr,zifencei,zmmul") }, + { str_lit("sifive-7-series"), str_lit("no-default-unroll,short-forward-branch-ialu,sifive7,use-postra-scheduler") }, + { str_lit("sifive-e20"), str_lit("32bit,c,i,m,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-e21"), str_lit("32bit,a,c,i,m,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-e24"), str_lit("32bit,a,c,f,i,m,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-e31"), str_lit("32bit,a,c,i,m,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-e34"), str_lit("32bit,a,c,f,i,m,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-e76"), str_lit("32bit,a,c,f,i,m,no-default-unroll,short-forward-branch-ialu,sifive7,use-postra-scheduler,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-p450"), str_lit("64bit,a,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,za64rs,zaamo,zalrsc,zba,zbb,zbs,zca,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicsr,zifencei,zihintntl,zihintpause,zihpm,zkt,zmmul") }, + { str_lit("sifive-p470"), str_lit("64bit,a,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,no-sink-splat-operands,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,vxrm-pipeline-flush,xsifivecdiscarddlone,xsifivecflushdlone,za64rs,zaamo,zalrsc,zba,zbb,zbs,zca,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicsr,zifencei,zihintntl,zihintpause,zihpm,zkt,zmmul,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvkb,zvkg,zvkn,zvknc,zvkned,zvkng,zvknhb,zvks,zvksc,zvksed,zvksg,zvksh,zvkt,zvl128b,zvl32b,zvl64b") }, + { str_lit("sifive-p550"), str_lit("64bit,a,auipc-addi-fusion,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zba,zbb,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-p670"), str_lit("64bit,a,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,no-sink-splat-operands,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,vxrm-pipeline-flush,za64rs,zaamo,zalrsc,zba,zbb,zbs,zca,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicsr,zifencei,zihintntl,zihintpause,zihpm,zkt,zmmul,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvkb,zvkg,zvkn,zvknc,zvkned,zvkng,zvknhb,zvks,zvksc,zvksed,zvksg,zvksh,zvkt,zvl128b,zvl32b,zvl64b") }, + { str_lit("sifive-p870"), str_lit("64bit,a,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,no-sink-splat-operands,supm,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,vxrm-pipeline-flush,za64rs,zaamo,zalrsc,zama16b,zawrs,zba,zbb,zbs,zca,zcb,zcmop,zfa,zfbfmin,zfh,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintntl,zihintpause,zihpm,zimop,zkr,zkt,zmmul,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvfbfmin,zvfbfwma,zvfh,zvfhmin,zvkb,zvkg,zvkn,zvknc,zvkned,zvkng,zvknhb,zvks,zvksc,zvksed,zvksg,zvksh,zvkt,zvl128b,zvl32b,zvl64b") }, + { str_lit("sifive-s21"), str_lit("64bit,a,c,i,m,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-s51"), str_lit("64bit,a,c,i,m,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-s54"), str_lit("64bit,a,c,d,f,i,m,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-s76"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,short-forward-branch-ialu,sifive7,use-postra-scheduler,zaamo,zalrsc,zca,zicsr,zifencei,zihintpause,zmmul") }, + { str_lit("sifive-u54"), str_lit("64bit,a,c,d,f,i,m,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-u74"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,short-forward-branch-ialu,sifive7,use-postra-scheduler,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("sifive-x280"), str_lit("64bit,a,c,d,dlen-factor-2,f,i,m,no-default-unroll,optimized-nf2-segment-load-store,optimized-zero-stride-load,short-forward-branch-ialu,sifive7,use-postra-scheduler,v,vl-dependent-latency,zaamo,zalrsc,zba,zbb,zca,zfh,zfhmin,zicsr,zifencei,zmmul,zve32f,zve32x,zve64d,zve64f,zve64x,zvfh,zvfhmin,zvl128b,zvl256b,zvl32b,zvl512b,zvl64b") }, + { str_lit("sifive-x390"), str_lit("64bit,a,b,c,d,dlen-factor-2,experimental-zicfilp,experimental-zicfiss,f,i,m,no-default-unroll,optimized-nf2-segment-load-store,optimized-zero-stride-load,short-forward-branch-ialu,sifive7,single-element-vec-fp64,use-postra-scheduler,v,vl-dependent-latency,xsifivecdiscarddlone,xsifivecflushdlone,za64rs,zaamo,zalrsc,zawrs,zba,zbb,zbs,zca,zcb,zcmop,zfa,zfbfmin,zfh,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,ziccrse,zicntr,zicond,zicsr,zifencei,zihintntl,zihintpause,zihpm,zimop,zkr,zkt,zmmul,zvbb,zve32f,zve32x,zve64d,zve64f,zve64x,zvfbfmin,zvfbfwma,zvfh,zvfhmin,zvkb,zvkt,zvl1024b,zvl128b,zvl256b,zvl32b,zvl512b,zvl64b") }, + { str_lit("spacemit-x60"), str_lit("64bit,a,b,c,d,dlen-factor-2,f,i,m,optimized-nf2-segment-load-store,optimized-nf3-segment-load-store,optimized-nf4-segment-load-store,ssccptr,sscofpmf,sscounterenw,sstc,sstvala,sstvecd,svade,svbare,svinval,svnapot,svpbmt,unaligned-scalar-mem,v,vxrm-pipeline-flush,xsmtvdot,za64rs,zaamo,zalrsc,zba,zbb,zbc,zbkc,zbs,zca,zfh,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintpause,zihpm,zkt,zmmul,zve32f,zve32x,zve64d,zve64f,zve64x,zvfh,zvfhmin,zvkt,zvl128b,zvl256b,zvl32b,zvl64b") }, + { str_lit("syntacore-scr1-base"), str_lit("32bit,c,i,no-default-unroll,zca,zicsr,zifencei") }, + { str_lit("syntacore-scr1-max"), str_lit("32bit,c,i,m,no-default-unroll,zca,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr3-rv32"), str_lit("32bit,c,i,m,no-default-unroll,use-postra-scheduler,zca,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr3-rv64"), str_lit("64bit,a,c,i,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr4-rv32"), str_lit("32bit,c,d,f,i,m,no-default-unroll,use-postra-scheduler,zca,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr4-rv64"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr5-rv32"), str_lit("32bit,a,c,d,f,i,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr5-rv64"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zca,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr7"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,use-postra-scheduler,v,zaamo,zalrsc,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zca,zicsr,zifencei,zkn,zknd,zkne,zknh,zmmul,zve32f,zve32x,zve64d,zve64f,zve64x,zvl128b,zvl32b,zvl64b") }, + { str_lit("tt-ascalon-d8"), str_lit("64bit,a,b,c,d,f,h,i,log-vrgather,m,no-default-unroll,optimized-nf2-segment-load-store,optimized-nf3-segment-load-store,optimized-nf4-segment-load-store,optimized-nf5-segment-load-store,optimized-nf6-segment-load-store,optimized-nf7-segment-load-store,optimized-nf8-segment-load-store,optimized-zero-stride-load,sha,shcounterenw,shgatpa,shtvala,shvsatpa,shvstvala,shvstvecd,smaia,ssaia,ssccptr,sscofpmf,sscounterenw,ssnpm,ssstateen,ssstrict,sstc,sstvala,sstvecd,ssu64xl,supm,svade,svbare,svinval,svnapot,svpbmt,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,za64rs,zaamo,zalrsc,zawrs,zba,zbb,zbs,zca,zcb,zcmop,zfa,zfbfmin,zfh,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintntl,zihintpause,zihpm,zimop,zkt,zmmul,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvfbfmin,zvfbfwma,zvfh,zvfhmin,zvkb,zvkg,zvkn,zvkned,zvkng,zvknhb,zvkt,zvl128b,zvl256b,zvl32b,zvl64b") }, + { str_lit("veyron-v1"), str_lit("64bit,a,add-load-fusion,auipc-addi-fusion,auipc-load-fusion,c,d,disable-misched-load-clustering,disable-postmisched-load-clustering,disable-postmisched-store-clustering,f,i,lui-addi-fusion,lui-load-fusion,m,shifted-zextw-fusion,ventana-veyron,xventanacondops,zaamo,zalrsc,zba,zbb,zbc,zbs,zca,zexth-fusion,zextw-fusion,zicbom,zicbop,zicboz,zicntr,zicsr,zifencei,zihintpause,zihpm,zmmul") }, + { str_lit("xiangshan-kunminghu"), str_lit("64bit,a,b,c,d,f,h,i,m,no-default-unroll,sha,shcounterenw,shgatpa,shifted-zextw-fusion,shtvala,shvsatpa,shvstvala,shvstvecd,smaia,smcsrind,smdbltrp,smmpm,smnpm,smrnmi,smstateen,ssaia,ssccptr,sscofpmf,sscounterenw,sscsrind,ssdbltrp,ssnpm,sspm,ssstateen,ssstrict,sstc,sstvala,sstvecd,ssu64xl,supm,svade,svbare,svinval,svnapot,svpbmt,v,za64rs,zaamo,zacas,zalrsc,zawrs,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zca,zcb,zcmop,zexth-fusion,zextw-fusion,zfa,zfh,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintntl,zihintpause,zihpm,zimop,zkn,zknd,zkne,zknh,zks,zksed,zksh,zkt,zmmul,zvbb,zve32f,zve32x,zve64d,zve64f,zve64x,zvfh,zvfhmin,zvkb,zvkt,zvl128b,zvl32b,zvl64b") }, + { str_lit("xiangshan-nanhu"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,shifted-zextw-fusion,svinval,zaamo,zalrsc,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zca,zexth-fusion,zextw-fusion,zicbom,zicboz,zicsr,zifencei,zkn,zknd,zkne,zknh,zksed,zksh,zmmul") }, +}; + +#elif LLVM_VERSION_MAJOR == 21 // Generated with the featuregen script in `misc/featuregen` gb_global String target_microarch_list[TargetArch_COUNT] = { // TargetArch_Invalid: diff --git a/src/bundle_command.cpp b/src/bundle_command.cpp index 7abd48104..c19f29220 100644 --- a/src/bundle_command.cpp +++ b/src/bundle_command.cpp @@ -186,7 +186,11 @@ i32 bundle_android(String original_init_directory) { gb_string_clear(cmd); cmd = gb_string_append_length(cmd, android_sdk_build_tools.text, android_sdk_build_tools.len); +#if defined(GB_SYSTEM_WINDOWS) + cmd = gb_string_appendc(cmd, "apksigner.bat"); +#else cmd = gb_string_appendc(cmd, "apksigner"); +#endif cmd = gb_string_appendc(cmd, " sign"); String keystore = normalize_path(temporary_allocator(), build_context.android_keystore, NIX_SEPARATOR_STRING); diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 1b3e6912c..4b3e8807e 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -58,6 +58,7 @@ gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_bool is_type_simd_vector, is_type_matrix, is_type_raw_union, + is_type_fixed_capacity_dynamic_array, is_type_polymorphic_record_specialized, is_type_polymorphic_record_unspecialized, @@ -534,12 +535,12 @@ gb_internal bool check_builtin_objc_procedure(CheckerContext *c, Operand *operan return false; } - if (ident.entity->kind != Entity_Procedure) { + if (ident.entity.load()->kind != Entity_Procedure) { gbString e = expr_to_string(handler_node); ERROR_BLOCK(); error(handler.expr, "'%.*s' expected a direct reference to a procedure", LIT(builtin_name)); - if(ident.entity->kind == Entity_Variable) { + if(ident.entity.load()->kind == Entity_Variable) { error_line("\tSuggestion: Variables referencing a procedure are not allowed, they are not a direct procedure reference."); } else { error_line("\tSuggestion: Ensure '%s' is not a runtime-evaluated expression.", e); // NOTE(harold): Is this case possible to hit? @@ -1706,7 +1707,7 @@ gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String } defer ({ if (cache == nullptr) { - LoadFileCache *new_cache = gb_alloc_item(permanent_allocator(), LoadFileCache); + LoadFileCache *new_cache = permanent_alloc_item(); new_cache->path = path; new_cache->data = data; new_cache->file_error = file_error; @@ -1744,7 +1745,7 @@ gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String case LoadFileTier_Contents: { isize file_size = cast(isize)gb_file_size(&f); if (file_size > 0) { - u8 *ptr = cast(u8 *)gb_alloc(permanent_allocator(), file_size+1); + u8 *ptr = permanent_alloc_array(file_size+1); gb_file_read_at(&f, ptr, file_size, 0); ptr[file_size] = '\0'; data.text = ptr; @@ -1949,7 +1950,7 @@ gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c } defer ({ if (cache == nullptr) { - LoadDirectoryCache *new_cache = gb_alloc_item(permanent_allocator(), LoadDirectoryCache); + LoadDirectoryCache *new_cache = permanent_alloc_item(); new_cache->path = path; new_cache->files = file_caches; new_cache->file_error = file_error; @@ -2412,13 +2413,14 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o } String name = arg->Ident.token.string; + auto interned = arg->Ident.interned; operand->type = def.type; operand->mode = def.mode; operand->value = def.value; - Entity *found = scope_lookup_current(config_pkg->scope, name); + Entity *found = scope_lookup_current(config_pkg->scope, interned); if (found != nullptr) { if (found->kind != Entity_Constant) { error(arg, "'#config' entity '%.*s' found but expected a constant", LIT(name)); @@ -2634,6 +2636,16 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As mode = Addressing_Constant; value = exact_value_i64(at->Array.count); type = t_untyped_integer; + } else if (is_type_fixed_capacity_dynamic_array(op_type)) { + Type *at = core_type(op_type); + if (id == BuiltinProc_cap) { + mode = Addressing_Constant; + value = exact_value_i64(at->FixedCapacityDynamicArray.capacity); + type = t_untyped_integer; + } else { + GB_ASSERT(id == BuiltinProc_len); + mode = Addressing_Value; + } } else if (is_type_enumerated_array(op_type) && id == BuiltinProc_len) { Type *at = core_type(op_type); mode = Addressing_Constant; @@ -2695,6 +2707,16 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_size_of: { // size_of :: proc(Type or expr) -> untyped int + if (ce->args[0]->kind == Ast_UnaryExpr) { + ast_node(arg, UnaryExpr, ce->args[0]); + if (arg->op.kind == Token_And) { + ERROR_BLOCK(); + + warning(ce->args[0], "'size_of(&x)' returns the size of a pointer, not the size of x"); + error_line("\tSuggestion: Use 'size_of(rawptr)' if you want the size of the pointer"); + } + } + Operand o = {}; check_expr_or_type(c, &o, ce->args[0]); if (o.mode == Addressing_Invalid) { @@ -2783,7 +2805,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } GB_ASSERT(type != nullptr); - String field_name = {}; + InternedString field_name = {}; if (field_arg == nullptr) { error(call, "Expected an identifier for field argument"); @@ -2791,9 +2813,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } if (field_arg->kind == Ast_Ident) { - field_name = field_arg->Ident.token.string; + field_name = field_arg->Ident.interned; } - if (field_name.len == 0) { + if (field_name.value == 0) { error(field_arg, "Expected an identifier for field argument"); return false; } @@ -2826,19 +2848,19 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As ERROR_BLOCK(); gbString type_str = type_to_string_shorthand(type); error(ce->args[0], - "'%s' has no field named '%.*s'", type_str, LIT(field_name)); + "'%s' has no field named '%s'", type_str, field_name.cstring()); gb_string_free(type_str); Type *bt = base_type(type); if (bt->kind == Type_Struct) { - check_did_you_mean_type(field_name, bt->Struct.fields); + check_did_you_mean_type(field_name.string(), bt->Struct.fields); } return false; } if (sel.indirect) { gbString type_str = type_to_string_shorthand(type); error(ce->args[0], - "Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name), type_str); + "Field '%s' is embedded via a pointer in '%s'", field_name.cstring(), type_str); gb_string_free(type_str); return false; } @@ -2870,7 +2892,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } GB_ASSERT(type != nullptr); - String field_name = {}; + InternedString field_name = {}; if (field_arg == nullptr) { error(call, "Expected a constant (not-empty) string for field argument"); @@ -2880,9 +2902,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Operand x = {}; check_expr(c, &x, field_arg); if (x.mode == Addressing_Constant && x.value.kind == ExactValue_String) { - field_name = x.value.value_string; + field_name = string_interner_insert(x.value.value_string); } - if (field_name.len == 0) { + if (field_name.value == 0) { error(field_arg, "Expected a constant (non-empty) string for field argument"); return false; } @@ -2900,19 +2922,19 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As ERROR_BLOCK(); gbString type_str = type_to_string_shorthand(type); error(ce->args[0], - "'%s' has no field named '%.*s'", type_str, LIT(field_name)); + "'%s' has no field named '%s'", type_str, field_name.cstring()); gb_string_free(type_str); Type *bt = base_type(type); if (bt->kind == Type_Struct) { - check_did_you_mean_type(field_name, bt->Struct.fields); + check_did_you_mean_type(field_name.string(), bt->Struct.fields); } return false; } if (sel.indirect) { gbString type_str = type_to_string_shorthand(type); error(ce->args[0], - "Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name), type_str); + "Field '%s' is embedded via a pointer in '%s'", field_name.string(), type_str); gb_string_free(type_str); return false; } @@ -3584,18 +3606,17 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As gb_string_free(type_str); return false; } - gbAllocator a = permanent_allocator(); Type *tuple = alloc_type_tuple(); if (is_type_struct(type)) { isize variable_count = type->Struct.fields.count; - slice_init(&tuple->Tuple.variables, a, variable_count); + tuple->Tuple.variables = permanent_slice_make(variable_count); // NOTE(bill): don't copy the entities, this should be good enough gb_memmove_array(tuple->Tuple.variables.data, type->Struct.fields.data, variable_count); } else if (is_type_array(type)) { isize variable_count = cast(isize)type->Array.count; - slice_init(&tuple->Tuple.variables, a, variable_count); + tuple->Tuple.variables = permanent_slice_make(variable_count); for (isize i = 0; i < variable_count; i++) { tuple->Tuple.variables[i] = alloc_entity_array_elem(nullptr, blank_token, type->Array.elem, cast(i32)i); } @@ -4416,7 +4437,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } if (!fail && first_is_field_value) { for_array(i, names) { - Selection sel = lookup_field(et, names[i], false); + Selection sel = lookup_field(et, string_interner_insert(names[i]), false); if (sel.entity == nullptr) { goto soa_zip_end; } @@ -5157,6 +5178,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case Type_Array: case Type_EnumeratedArray: case Type_SimdVector: + case Type_FixedCapacityDynamicArray: operand->type = alloc_type_multi_pointer(base_array_type(base)); break; case Type_Matrix: @@ -5194,6 +5216,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_count_zeros: case BuiltinProc_count_trailing_zeros: case BuiltinProc_count_leading_zeros: + case BuiltinProc_count_trailing_ones: + case BuiltinProc_count_leading_ones: case BuiltinProc_reverse_bits: { Operand x = {}; @@ -5291,6 +5315,27 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As v += 1; } break; + + case BuiltinProc_count_trailing_ones: + for (u64 i = 0; i < bit_size; i++) { + u8 b = cast(u8)(i & 7); + u8 j = cast(u8)(i >> 3); + if ((rop[j] & (1 << b)) == 0) { + break; + } + v += 1; + } + break; + case BuiltinProc_count_leading_ones: + for (u64 i = bit_size-1; i < bit_size; i--) { + u8 b = cast(u8)(i & 7); + u8 j = cast(u8)(i >> 3); + if ((rop[j] & (1 << b)) == 0) { + break; + } + v += 1; + } + break; } @@ -5373,6 +5418,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } } + if (!are_types_identical(x.type, y.type)) { + gbString xts = type_to_string(x.type); + gbString yts = type_to_string(y.type); + error(x.expr, "Mismatched types for '%.*s', got %s vs %s", LIT(builtin_name), xts, yts); + gb_string_free(yts); + gb_string_free(xts); + return false; + } operand->mode = Addressing_Value; operand->type = make_optional_ok_type(default_type(x.type)); @@ -5416,6 +5469,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } } + if (!are_types_identical(x.type, y.type)) { + gbString xts = type_to_string(x.type); + gbString yts = type_to_string(y.type); + error(x.expr, "Mismatched types for '%.*s', got %s vs %s", LIT(builtin_name), xts, yts); + gb_string_free(yts); + gb_string_free(xts); + return false; + } operand->mode = Addressing_Value; operand->type = default_type(x.type); @@ -6196,6 +6257,33 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = x.type; } break; + + case BuiltinProc_likely: + case BuiltinProc_unlikely: + { + Operand x = {}; + check_expr(c, &x, ce->args[0]); + if (x.mode == Addressing_Invalid) { + return false; + } + if (!is_type_boolean(x.type)) { + gbString xt = type_to_string(x.type); + error(x.expr, "Expected a boolean expression to '%.*s', got %s", LIT(builtin_name), xt); + gb_string_free(xt); + *operand = x; // minimize error propagation + return true; + } + + if (x.mode == Addressing_Constant) { + // NOTE(bill): just completely ignore this intrinsic entirely + *operand = x; + return true; + } + + operand->mode = Addressing_Value; + operand->type = x.type; + } + break; case BuiltinProc_prefetch_read_instruction: case BuiltinProc_prefetch_read_data: @@ -6698,7 +6786,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } - String field_name = x.value.value_string; + InternedString field_name = string_interner_insert(x.value.value_string); Selection sel = lookup_field(type, field_name, false); operand->mode = Addressing_Constant; @@ -6778,12 +6866,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } - String field_name = x.value.value_string; + InternedString field_name = string_interner_insert(x.value.value_string); Selection sel = lookup_field(type, field_name, false); if (sel.index.count == 0) { gbString t = type_to_string(type); - error(ce->args[1], "'%.*s' is not a field of type %s", LIT(field_name), t); + error(ce->args[1], "'%s' is not a field of type %s", field_name.cstring(), t); gb_string_free(t); return false; } @@ -7538,25 +7626,25 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } - String field_name = x.value.value_string; + InternedString field_name = string_interner_insert(x.value.value_string); Selection sel = lookup_field(type, field_name, false); if (sel.entity == nullptr) { ERROR_BLOCK(); gbString type_str = type_to_string(bt); error(ce->args[0], - "'%s' has no field named '%.*s'", type_str, LIT(field_name)); + "'%s' has no field named '%s'", type_str, field_name.cstring()); gb_string_free(type_str); if (bt->kind == Type_Struct) { - check_did_you_mean_type(field_name, bt->Struct.fields); + check_did_you_mean_type(field_name.string(), bt->Struct.fields); } return false; } if (sel.indirect) { gbString type_str = type_to_string(bt); error(ce->args[0], - "Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name), type_str); + "Field '%s' is embedded via a pointer in '%s'", field_name.cstring(), type_str); gb_string_free(type_str); return false; } @@ -7568,6 +7656,31 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; + case BuiltinProc_type_fixed_capacity_dynamic_array_len_offset: + { + Operand op = {}; + Type *bt = check_type(c, ce->args[0]); + Type *type = base_type(bt); + if (type == nullptr || type == t_invalid) { + error(ce->args[0], "Expected a fixed capacity dynamic array type for '%.*s'", LIT(builtin_name)); + return false; + } + if (!is_type_fixed_capacity_dynamic_array(type)) { + error(ce->args[0], "Expected a fixed capacity dynamic array type for '%.*s'", LIT(builtin_name)); + return false; + } + + i64 sz = type_size_of(type); + gb_unused(sz); + i64 offset = type_offset_of(type, 1); + + operand->mode = Addressing_Constant; + operand->value = exact_value_u64(cast(u64)offset); + operand->type = t_uintptr; + break; + } + break; + case BuiltinProc_type_bit_set_backing_type: { Operand op = {}; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 27babd255..4f224affa 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -156,9 +156,12 @@ gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_e // NOTE(bill): The original_entity's scope may not be same scope that it was inserted into // e.g. file entity inserted into its package scope String original_name = original_entity->token.string; + auto original_intern = entity_interned_name(original_entity); + u32 hash = original_entity->interned_name_hash.load(); + Scope *found_scope = nullptr; Entity *found_entity = nullptr; - scope_lookup_parent(original_entity->scope, original_name, &found_scope, &found_entity); + scope_lookup_parent(original_entity->scope, original_intern, &found_scope, &found_entity, hash); if (found_scope == nullptr) { return; } @@ -171,7 +174,7 @@ gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_e // has been "evaluated" and the variant data can be copied across rw_mutex_lock(&found_scope->mutex); - string_map_set(&found_scope->elements, original_name, new_entity); + scope_map_insert(&found_scope->elements, original_intern, hash, new_entity); rw_mutex_unlock(&found_scope->mutex); original_entity->flags |= EntityFlag_Overridden; @@ -518,6 +521,8 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, AttributeContext ac = {}; check_decl_attributes(ctx, decl->attributes, type_decl_attribute, &ac); + e->deprecated_message = ac.deprecated_message; + if (e->kind == Entity_TypeName && ac.objc_class != "") { e->TypeName.objc_class_name = ac.objc_class; @@ -990,7 +995,7 @@ gb_internal Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) error(ident, "foreign library names must be an identifier"); } else { String name = ident->Ident.token.string; - Entity *found = scope_lookup(ctx->scope, name, ident->Ident.hash); + Entity *found = scope_lookup(ctx->scope, ident->Ident.interned, ident->Ident.hash); if (found == nullptr) { if (is_blank_ident(name)) { @@ -1189,26 +1194,26 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon if (!ac.objc_is_class_method) { bool ok = true; for (TypeNameObjCMetadataEntry const &entry : md->value_entries) { - if (entry.name == ac.objc_name) { + if (entry.interned.string() == ac.objc_name) { error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name)); ok = false; break; } } if (ok) { - array_add(&md->value_entries, TypeNameObjCMetadataEntry{ac.objc_name, e}); + array_add(&md->value_entries, TypeNameObjCMetadataEntry{string_interner_insert(ac.objc_name), e}); } } else { bool ok = true; for (TypeNameObjCMetadataEntry const &entry : md->type_entries) { - if (entry.name == ac.objc_name) { + if (entry.interned.string() == ac.objc_name) { error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name)); ok = false; break; } } if (ok) { - array_add(&md->type_entries, TypeNameObjCMetadataEntry{ac.objc_name, e}); + array_add(&md->type_entries, TypeNameObjCMetadataEntry{string_interner_insert(ac.objc_name), e}); } } } @@ -1473,6 +1478,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { e->Procedure.no_sanitize_address = ac.no_sanitize_address; e->Procedure.no_sanitize_memory = ac.no_sanitize_memory; + e->Procedure.no_sanitize_thread = ac.no_sanitize_thread; e->deprecated_message = ac.deprecated_message; e->warning_message = ac.warning_message; @@ -2154,7 +2160,7 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de rw_mutex_unlock(&ctx->scope->mutex); - bool where_clause_ok = evaluate_where_clauses(ctx, nullptr, decl->scope, &decl->proc_lit->ProcLit.where_clauses, !decl->where_clauses_evaluated); + bool where_clause_ok = evaluate_where_clauses(ctx, nullptr, decl->scope, &decl->proc_lit->ProcLit.where_clauses, !decl->where_clauses_evaluated.load(std::memory_order_relaxed)); if (!where_clause_ok) { // NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed return false; @@ -2172,15 +2178,15 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de } GB_ASSERT(decl->proc_checked_state != ProcCheckedState_Checked); - if (decl->defer_use_checked) { + if (decl->defer_use_checked.load(std::memory_order_relaxed)) { GB_ASSERT(is_type_polymorphic(type, true)); error(token, "Defer Use Checked: %.*s", LIT(decl->entity.load()->token.string)); - GB_ASSERT(decl->defer_use_checked == false); + GB_ASSERT(decl->defer_use_checked.load(std::memory_order_relaxed) == false); } check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls); - decl->defer_use_checked = true; + decl->defer_use_checked.store(true, std::memory_order_relaxed); for (Ast *stmt : bs->stmts) { if (stmt->kind == Ast_ValueDecl) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 418fb5378..9044d8346 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -153,13 +153,19 @@ gb_internal bool is_load_directive_call(Ast *call) { gb_internal LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found); gb_internal void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") { + int limit = build_context.did_you_mean_limit; auto results = did_you_mean_results(d); + int count = 0; if (results.count != 0) { error_line("\tSuggestion: Did you mean?\n"); for (auto const &result : results) { String const &target = result.target; error_line("\t\t%s%.*s\n", prefix, LIT(target)); // error_line("\t\t%.*s %td\n", LIT(target), results[i].distance); + if (limit > 0 && ++count == limit) { + error_line("\t\t... and %td more ...", results.count - limit); + break; + } } } } @@ -177,11 +183,11 @@ gb_internal void populate_check_did_you_mean_objc_entity(StringSet *set, Entity if (is_type) { for (auto const &entry : objc_metadata->type_entries) { - string_set_add(set, entry.name); + string_set_add(set, entry.interned.string()); } } else { for (auto const &entry : objc_metadata->value_entries) { - string_set_add(set, entry.name); + string_set_add(set, entry.interned.string()); } } @@ -493,7 +499,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E rw_mutex_shared_unlock(&gen_procs->mutex); // @local-mutex } else { - gen_procs = gb_alloc_item(permanent_allocator(), GenProcsData); + gen_procs = permanent_alloc_item(); gen_procs->procs.allocator = heap_allocator(); base_entity->Procedure.gen_procs = gen_procs; mutex_unlock(&base_entity->Procedure.gen_procs_mutex); // @entity-mutex @@ -508,7 +514,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E // NOTE(bill): Reset scope from the failed procedure type scope->head_child.store(nullptr, std::memory_order_relaxed); - string_map_clear(&scope->elements); + scope_map_clear(&scope->elements); ptr_set_clear(&scope->imported); // LEAK NOTE(bill): Cloning this AST may be leaky but this is not really an issue due to arena-based allocation @@ -530,7 +536,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E DeclInfo *decl = other->decl_info; if (decl->proc_checked_state != ProcCheckedState_Checked) { - ProcInfo *proc_info = gb_alloc_item(permanent_allocator(), ProcInfo); + ProcInfo *proc_info = permanent_alloc_item(); proc_info->file = other->file; proc_info->token = other->token; proc_info->decl = decl; @@ -624,7 +630,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E array_add(&gen_procs->procs, entity); rw_mutex_unlock(&gen_procs->mutex); // @local-mutex - ProcInfo *proc_info = gb_alloc_item(permanent_allocator(), ProcInfo); + ProcInfo *proc_info = permanent_alloc_item(); proc_info->file = file; proc_info->token = token; proc_info->decl = d; @@ -1084,18 +1090,20 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ return; } - // Grab definite or indefinite article matching `context_name`, or "" if not found. - String article = error_article(context_name); if (is_type_untyped(operand->type)) { Type *target_type = type; if (type == nullptr || is_type_any(type)) { if (type == nullptr && is_type_untyped_uninit(operand->type)) { + String article = error_article(context_name); // Grab definite or indefinite article matching `context_name`, or "" if not found. + error(operand->expr, "Use of --- in %.*s%.*s", LIT(article), LIT(context_name)); operand->mode = Addressing_Invalid; return; } if (type == nullptr && is_type_untyped_nil(operand->type)) { + String article = error_article(context_name); // Grab definite or indefinite article matching `context_name`, or "" if not found. + error(operand->expr, "Use of untyped nil in %.*s%.*s", LIT(article), LIT(context_name)); operand->mode = Addressing_Invalid; return; @@ -1133,7 +1141,11 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ x.mode = Addressing_Value; x.type = t; if (check_is_assignable_to(c, &x, type)) { - add_entity_use(c, operand->expr, e); + if (operand->expr->kind == Ast_SelectorExpr) { + add_entity_use(c, operand->expr->SelectorExpr.selector, e); + } else { + add_entity_use(c, operand->expr, e); + } good = true; break; } @@ -1149,6 +1161,8 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ defer (gb_string_free(op_type_str)); defer (gb_string_free(expr_str)); + String article = error_article(context_name); // Grab definite or indefinite article matching `context_name`, or "" if not found. + // TODO(bill): is this a good enough error message? error(operand->expr, "Cannot assign overloaded procedure group '%s' to '%s' in %.*s%.*s", @@ -1177,6 +1191,8 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ defer (gb_string_free(op_type_str)); defer (gb_string_free(expr_str)); + String article = error_article(context_name); // Grab definite or indefinite article matching `context_name`, or "" if not found. + switch (operand->mode) { case Addressing_Builtin: error(operand->expr, @@ -1319,7 +1335,7 @@ gb_internal bool polymorphic_assign_index(Type **gt_, i64 *dst_count, i64 source Type *gt = *gt_; GB_ASSERT(gt->kind == Type_Generic); - Entity *e = scope_lookup(gt->Generic.scope, gt->Generic.name); + Entity *e = scope_lookup(gt->Generic.scope, gt->Generic.interned_name, 0); GB_ASSERT(e != nullptr); if (e->kind == Entity_TypeName) { *gt_ = nullptr; @@ -1420,7 +1436,7 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T if (poly->Array.generic_count != nullptr) { Type *gt = poly->Array.generic_count; GB_ASSERT(gt->kind == Type_Generic); - Entity *e = scope_lookup(gt->Generic.scope, gt->Generic.name); + Entity *e = scope_lookup(gt->Generic.scope, gt->Generic.interned_name, 0); GB_ASSERT(e != nullptr); if (e->kind == Entity_TypeName) { Type *index = source->EnumeratedArray.index; @@ -1480,6 +1496,22 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T return is_polymorphic_type_assignable(c, poly->DynamicArray.elem, source->DynamicArray.elem, true, modify_type); } return false; + + case Type_FixedCapacityDynamicArray: + if (source->kind == Type_FixedCapacityDynamicArray) { + if (poly->FixedCapacityDynamicArray.generic_capacity != nullptr) { + if (!polymorphic_assign_index(&poly->FixedCapacityDynamicArray.generic_capacity, + &poly->FixedCapacityDynamicArray.capacity, + source->FixedCapacityDynamicArray.capacity)) { + return false; + } + } + if (poly->FixedCapacityDynamicArray.capacity == source->FixedCapacityDynamicArray.capacity) { + return is_polymorphic_type_assignable(c, poly->FixedCapacityDynamicArray.elem, source->FixedCapacityDynamicArray.elem, true, modify_type); + } + } + return false; + case Type_Slice: if (source->kind == Type_Slice) { return is_polymorphic_type_assignable(c, poly->Slice.elem, source->Slice.elem, true, modify_type); @@ -1491,6 +1523,11 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T case Type_BitSet: if (source->kind == Type_BitSet) { + if (!is_type_polymorphic(poly->BitSet.elem)) { + if (poly->BitSet.upper != source->BitSet.upper || poly->BitSet.lower != source->BitSet.lower) { + return false; + } + } if (!is_polymorphic_type_assignable(c, poly->BitSet.elem, source->BitSet.elem, true, modify_type)) { return false; } @@ -1739,9 +1776,9 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam GB_ASSERT(n->kind == Ast_Ident); o->mode = Addressing_Invalid; o->expr = n; - String name = n->Ident.token.string; + auto name = n->Ident.token.string; - Entity *e = scope_lookup(c->scope, name, n->Ident.hash); + Entity *e = scope_lookup(c->scope, n->Ident.interned, n->Ident.hash); if (e == nullptr) { if (is_blank_ident(name)) { error(n, "'_' cannot be used as a value"); @@ -2116,9 +2153,6 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i } return in_value.kind == ExactValue_String; } else if (is_type_integer(type) || is_type_rune(type)) { - if (in_value.kind == ExactValue_Bool) { - return false; - } ExactValue v = exact_value_to_integer(in_value); if (v.kind != ExactValue_Integer) { return false; @@ -2133,9 +2167,13 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i BigInt i = v.value_integer; i64 byte_size = type_size_of(type); - BigInt umax = {}; - BigInt imin = {}; - BigInt imax = {}; + BigInt umax; + BigInt imin; + BigInt imax; + + u64 umax_64 = 0; + i64 imin_64 = 0; + i64 imax_64 = 0; if (c->bit_field_bit_size > 0) { i64 bit_size = gb_min(cast(i64)(8*byte_size), cast(i64)c->bit_field_bit_size); @@ -2158,10 +2196,10 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i big_int_shl_eq(&imax, &bi); mp_decr(&imax); } else { - if (byte_size < 16) { - big_int_from_u64(&umax, unsigned_integer_maxs[byte_size]); - big_int_from_i64(&imin, signed_integer_mins[byte_size]); - big_int_from_i64(&imax, signed_integer_maxs[byte_size]); + if (byte_size <= 8) { + umax_64 = unsigned_integer_maxs[byte_size]; + imin_64 = signed_integer_mins[byte_size]; + imax_64 = signed_integer_maxs[byte_size]; } else { big_int_from_u64(&umax, 1); big_int_from_i64(&imin, 1); @@ -2189,16 +2227,27 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i case Basic_i16: case Basic_i32: case Basic_i64: - case Basic_i128: case Basic_int: case Basic_i16le: case Basic_i32le: case Basic_i64le: - case Basic_i128le: case Basic_i16be: case Basic_i32be: case Basic_i64be: + if (c->bit_field_bit_size == 0) { + // return imin <= i && i <= imax; + if (!big_int_can_be_represented_in_64_bits(&i)) { + return false; + } + + i64 val64 = big_int_to_i64(&i); + + return imin_64 <= val64 && val64 <= imax_64; + } + /*fallthrough*/ + case Basic_i128le: + case Basic_i128: case Basic_i128be: { // return imin <= i && i <= imax; @@ -2211,17 +2260,30 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i case Basic_u16: case Basic_u32: case Basic_u64: - case Basic_u128: case Basic_uint: case Basic_uintptr: case Basic_u16le: case Basic_u32le: case Basic_u64le: - case Basic_u128le: case Basic_u16be: case Basic_u32be: case Basic_u64be: + if (c->bit_field_bit_size == 0) { + if (big_int_is_neg(&i)) { + return false; + } + if (!big_int_can_be_represented_in_64_bits(&i)) { + return false; + } + u64 val64 = big_int_to_u64(&i); + + return val64 <= umax_64; + + } + /*fallthrough*/ + case Basic_u128: + case Basic_u128le: case Basic_u128be: { // return 0ull <= i && i <= umax; @@ -2943,14 +3005,21 @@ gb_internal void check_comparison(CheckerContext *c, Ast *node, Operand *x, Oper if (check_is_assignable_to(c, x, y->type) || check_is_assignable_to(c, y, x->type)) { + if (x->type->failure || y->type->failure) { + // // skip any failures + x->mode = Addressing_Value; + x->type = t_untyped_bool; + return; + } + Type *err_type = x->type; bool defined = false; switch (op) { case Token_CmpEq: case Token_NotEq: - defined = (is_type_comparable(x->type) && is_type_comparable(y->type)) || - (is_operand_nil(*x) && type_has_nil(y->type)) || - (is_operand_nil(*y) && type_has_nil(x->type)); + defined = ((is_operand_nil(*x) && type_has_nil(y->type)) || + (is_operand_nil(*y) && type_has_nil(x->type)) || + is_type_comparable(x->type) && is_type_comparable(y->type)); break; case Token_Lt: case Token_Gt: @@ -3529,28 +3598,17 @@ gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) Type *elem = core_array_type(bt); if (core_type(bt)->kind == Type_Basic) { - if (check_representable_as_constant(c, x->value, type, &x->value)) { - return true; - } - goto check_castable; - } else if (!are_types_identical(elem, bt) && - elem->kind == Type_Basic && - check_representable_as_constant(c, x->value, elem, &x->value)) { - if (check_representable_as_constant(c, x->value, type, &x->value)) { - return true; - } - goto check_castable; + return check_representable_as_constant(c, x->value, type, &x->value) || + (is_type_pointer(type) && check_is_castable_to(c, x, type)); + } else if (!are_types_identical(elem, bt) && elem->kind == Type_Basic && x->type->kind == Type_Basic) { + return check_representable_as_constant(c, x->value, elem, &x->value) || + (is_type_pointer(elem) && check_is_castable_to(c, x, elem)); } else if (check_is_castable_to(c, x, type)) { x->value = {}; x->mode = Addressing_Value; return true; } - - return false; - } - -check_castable: - if (check_is_castable_to(c, x, type)) { + } else if (check_is_castable_to(c, x, type)) { if (x->mode != Addressing_Constant) { x->mode = Addressing_Value; } else if (is_type_slice(type) && is_type_string(x->type)) { @@ -3663,6 +3721,24 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type, bool forb } } + if (is_const_expr) { + Type *src = core_type(x->type); + Type *dst = core_type(type); + + if (is_type_string(src) && is_type_string(dst)) { + bool src_utf16 = is_type_string16(src) || is_type_cstring16(src); + bool dst_utf16 = is_type_string16(dst) || is_type_cstring16(dst); + + if (!src_utf16 && dst_utf16) { + x->value = exact_value_string16(string_to_string16(permanent_allocator(), x->value.value_string)); + } + + if (src_utf16 && !dst_utf16) { + x->value = exact_value_string(string16_to_string(permanent_allocator(), x->value.value_string16)); + } + } + } + x->type = type; } @@ -4135,15 +4211,19 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ i64 upper = yt->BitSet.upper; if (lower <= key && key <= upper) { - i64 bit = 1ll<mode = Addressing_Constant; x->type = t_untyped_bool; if (op.kind == Token_in) { - x->value = exact_value_bool((bit & bits) != 0); + x->value = exact_value_bool(!big_int_is_zero(&mask)); } else { - x->value = exact_value_bool((bit & bits) == 0); + x->value = exact_value_bool(big_int_is_zero(&mask)); } x->expr = node; return; @@ -4172,7 +4252,7 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ default: if (is_ise_expr(be->left)) { // Evalute the right before the left for an '.X' expression - check_expr_or_type(c, y, be->right, type_hint); + check_expr_or_type(c, y, be->right, token_is_comparison(op.kind) ? nullptr : type_hint); if (can_use_other_type_as_type_hint(use_lhs_as_type_hint, y->type)) { // RHS in this case check_expr_or_type(c, x, be->left, y->type); @@ -4184,7 +4264,7 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ if (can_use_other_type_as_type_hint(use_lhs_as_type_hint, x->type)) { check_expr_with_type_hint(c, y, be->right, x->type); } else { - check_expr_with_type_hint(c, y, be->right, type_hint); + check_expr_with_type_hint(c, y, be->right, token_is_comparison(op.kind) ? nullptr : type_hint); } } break; @@ -4437,9 +4517,9 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ truncated: r = a - b*trunc(a/b) floored: r = a - b*floor(a/b) - IFF a/0 == 0, then (a%0 == a) or (a%%0 == a) - IFF a/0 == a, then (a%0 == 0) or (a%%0 == 0) - IFF a/0 == 0b111..., then (a%0 == a) or (a%%0 == a) + If and only if (⟺) a/0 == 0, then (a%0 == a) or (a%%0 == a) + If and only if (⟺) a/0 == a, then (a%0 == 0) or (a%%0 == 0) + If and only if (⟺) a/0 == 0b111..., then (a%0 == a) or (a%%0 == a) */ switch (zero_behaviour) { @@ -4454,6 +4534,9 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ break; } } + } else if (is_type_array_like(x->type)) { + x->mode = Addressing_Value; + return; } else { x->value = exact_binary_operator_value(op.kind, a, b); } @@ -4707,12 +4790,14 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar switch (t->kind) { case Type_Basic: if (operand->mode == Addressing_Constant) { - check_is_expressible(c, operand, t); + check_is_expressible(c, operand, target_type); if (operand->mode == Addressing_Invalid) { return; } update_untyped_expr_value(c, operand->expr, operand->value); - } else { + } + + { switch (operand->type->Basic.kind) { case Basic_UntypedBool: if (!is_type_boolean(target_type)) { @@ -5141,7 +5226,7 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v continue; } ast_node(fv, FieldValue, elem); - String name = fv->field->Ident.token.string; + auto name = fv->field->Ident.interned; Selection sub_sel = lookup_field(node->tav.type, name, false); if (sub_sel.index.count > 0 && sub_sel.index[0] == index) { @@ -5195,6 +5280,11 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v } } else { TypeAndValue index_tav = fv->field->tav; + if (index_tav.mode != Addressing_Constant) { + if (success_) *success_ = false; + if (finish_) *finish_ = true; + return empty_exact_value; + } GB_ASSERT(index_tav.mode == Addressing_Constant); ExactValue index_value = index_tav.value; if (is_type_enumerated_array(node->tav.type)) { @@ -5402,8 +5492,12 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast * return e; } } else */if (node->kind == Ast_Ident) { + Entity *e = node->Ident.entity.load(); + if (e != nullptr) { + return e; + } String name = node->Ident.token.string; - return scope_lookup(c->scope, name, node->Ident.hash); + return scope_lookup(c->scope, node->Ident.interned, node->Ident.hash); } else if (!ident_only) if (node->kind == Ast_SelectorExpr) { ast_node(se, SelectorExpr, node); if (se->token.kind == Token_ArrowRight) { @@ -5425,7 +5519,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast * if (op_expr->kind == Ast_Ident) { String op_name = op_expr->Ident.token.string; - Entity *e = scope_lookup(c->scope, op_name, op_expr->Ident.hash); + Entity *e = scope_lookup(c->scope, op_expr->Ident.interned, op_expr->Ident.hash); if (e == nullptr) { return nullptr; } @@ -5438,7 +5532,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast * // If you can clean this up, please do but be really careful String import_name = op_name; Scope *import_scope = e->ImportName.scope; - String entity_name = selector->Ident.token.string; + auto entity_name = selector->Ident.interned; check_op_expr = false; entity = scope_lookup_current(import_scope, entity_name); @@ -5464,7 +5558,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast * } if (entity == nullptr && selector->kind == Ast_Ident) { - String field_name = selector->Ident.token.string; + auto field_name = selector->Ident.interned; if (is_type_dynamic_array(type_deref(operand.type))) { init_mem_allocator(c->checker); } @@ -5522,7 +5616,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod if (op_expr->kind == Ast_Ident) { String op_name = op_expr->Ident.token.string; - Entity *e = scope_lookup(c->scope, op_name, op_expr->Ident.hash); + Entity *e = scope_lookup(c->scope, op_expr->Ident.interned, op_expr->Ident.hash); add_entity_use(c, op_expr, e); expr_entity = e; @@ -5540,6 +5634,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod String import_name = op_name; Scope *import_scope = e->ImportName.scope; String entity_name = selector->Ident.token.string; + InternedString entity_name_interned = selector->Ident.interned; if (import_scope == nullptr) { ERROR_BLOCK(); @@ -5550,7 +5645,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod } check_op_expr = false; - entity = scope_lookup_current(import_scope, entity_name); + entity = scope_lookup_current(import_scope, entity_name_interned); bool allow_builtin = false; if (!is_entity_declared_for_selector(entity, import_scope, &allow_builtin)) { ERROR_BLOCK(); @@ -5598,7 +5693,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod } if (entity == nullptr && selector->kind == Ast_Ident) { - String field_name = selector->Ident.token.string; + auto field_name = selector->Ident.interned; Type *t = type_deref(operand->type); if (t == nullptr) { error(operand->expr, "Cannot use a selector expression on 0-value expression"); @@ -5937,15 +6032,14 @@ gb_internal bool is_type_valid_atomic_type(Type *elem) { gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = false, Scope **out_scope = nullptr) { switch (node->kind) { case_ast_node(i, Ident, node); - String name = i->token.string; if (nested) { - Entity *e = scope_lookup_current(s, name); + Entity *e = scope_lookup_current(s, i->interned, i->hash); if (e != nullptr) { if (out_scope) *out_scope = e->scope; return true; } } else { - Entity *e = scope_lookup(s, name, i->hash); + Entity *e = scope_lookup(s, i->interned, i->hash); if (e != nullptr) { if (out_scope) *out_scope = e->scope; return true; @@ -7245,18 +7339,45 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, } } + // auto print_argument_types = [&]() { + // error_line("\tGiven argument types: ("); + // isize i = 0; + // for (Operand const &o : positional_operands) { + // if (i++ > 0) error_line(", "); + // gbString type = type_to_string(o.type); + // defer (gb_string_free(type)); + // error_line("%s", type); + // } + // for (Operand const &o : named_operands) { + // if (i++ > 0) error_line(", "); + + // gbString type = type_to_string(o.type); + // defer (gb_string_free(type)); + + // if (i < ce->split_args->named.count) { + // Ast *named_field = ce->split_args->named[i]; + // ast_node(fv, FieldValue, named_field); + + // gbString field = expr_to_string(fv->field); + // defer (gb_string_free(field)); + + // error_line("%s = %s", field, type); + // } else { + // error_line("%s", type); + // } + // } + // error_line(")\n"); + // }; + auto print_argument_types = [&]() { - error_line("\tGiven argument types: ("); + error_line("\tGiven argument types:\n"); isize i = 0; for (Operand const &o : positional_operands) { - if (i++ > 0) error_line(", "); gbString type = type_to_string(o.type); defer (gb_string_free(type)); - error_line("%s", type); + error_line("\t • %s\n", type); } for (Operand const &o : named_operands) { - if (i++ > 0) error_line(", "); - gbString type = type_to_string(o.type); defer (gb_string_free(type)); @@ -7267,12 +7388,11 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, gbString field = expr_to_string(fv->field); defer (gb_string_free(field)); - error_line("%s = %s", field, type); + error_line("\t • %s = %s\n", field, type); } else { - error_line("%s", type); + error_line("\t • %s\n", type); } } - error_line(")\n"); }; if (valids.count == 0) { @@ -7288,9 +7408,6 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, if (procs.count == 0) { procs = proc_group_entities_cloned(c, *operand); } - if (procs.count > 0) { - error_line("Did you mean to use one of the following:\n"); - } // Try to reduce the list further for `$T: typeid` like parameters bool *possibly_ignore = temporary_alloc_array(procs.count); @@ -7387,6 +7504,82 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, } spaces[max_spaces] = 0; + { + // TODO(bill): This is absolutely awful code, that needs improving a lot + + bool try_addr = false; + isize try_addr_idx = -1; + + for_array(i, procs) { + if (possibly_ignore_set != 0 && possibly_ignore[i]) { + continue; + } + Entity *proc = procs[i]; + TokenPos pos = proc->token.pos; + Type *t = base_type(proc->type); + if (t == t_invalid) continue; + GB_ASSERT(t->kind == Type_Proc); + if (t->Proc.params && t->Proc.params->Tuple.variables.count > 0) { + isize n = gb_min(t->Proc.params->Tuple.variables.count, positional_operands.count); + for (isize i = 0; i < n; i++) { + Type *dst = t->Proc.params->Tuple.variables[i]->type; + Operand src = positional_operands[i]; + if (check_is_assignable_to(c, &src, dst)) { + // okay + } else if (check_is_assignable_to(c, &src, type_deref(dst))) { + try_addr = true; + if (try_addr_idx < 0) { + try_addr_idx = i; + } + } + } + } + } + + if (try_addr) { + error_line(" \n"); + error_line("\tSuggestion:\n"); + error_line("\t\t%s(", expr_name); + isize i = 0; + for (Operand const &o : positional_operands) { + if (i++ > 0) error_line(", "); + gbString expr = expr_to_string(o.expr); + defer (gb_string_free(expr)); + + if (i-1 == try_addr_idx) { + error_line("&"); + } + error_line("%s", expr); + } + for (Operand const &o : named_operands) { + if (i++ > 0) error_line(", "); + + gbString expr = expr_to_string(o.expr); + defer (gb_string_free(expr)); + + if (i < ce->split_args->named.count) { + Ast *named_field = ce->split_args->named[i]; + ast_node(fv, FieldValue, named_field); + + gbString field = expr_to_string(fv->field); + defer (gb_string_free(field)); + + error_line("%s = %s", field, expr); + } else { + error_line("%s", expr); + } + } + error_line(")\n"); + + error_line(" \n"); // extra spaces to prevent newlines being consumed by the error handling syste, + } + } + + + if (procs.count > 0) { + error_line("Did you mean one of the following overloads?\n"); + } + for_array(i, procs) { if (possibly_ignore_set != 0 && possibly_ignore[i]) { continue; @@ -7541,7 +7734,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op } named_args = slice(ce->args, positional_args.count, ce->args.count); - auto split_args = gb_alloc_item(permanent_allocator(), AstSplitArgs); + auto split_args = permanent_alloc_item(); split_args->positional = positional_args; split_args->named = named_args; ce->split_args = split_args; @@ -7661,11 +7854,14 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O { // NOTE(bill, 2019-10-26): Allow a cycle in the parameters but not in the fields themselves auto prev_type_path = c->type_path; + + c->type_path = new_checker_type_path(); + defer ({ + destroy_checker_type_path(c->type_path); + c->type_path = prev_type_path; + }); + TEMPORARY_ALLOCATOR_GUARD(); - - c->type_path = new_checker_type_path(temporary_allocator()); - defer (c->type_path = prev_type_path); - if (is_call_expr_field_value(ce)) { named_fields = true; operands = array_make(temporary_allocator(), ce->args.count); @@ -8148,6 +8344,7 @@ gb_internal ExprKind check_call_expr_as_type_cast(CheckerContext *c, Operand *op if (operand->mode != Addressing_Invalid) { update_untyped_expr_type(c, arg, t, false); + check_representable_as_constant(c, operand->value, t, &operand->value); } break; } @@ -8171,13 +8368,7 @@ gb_internal void check_objc_call_expr(CheckerContext *c, Operand *operand, Ast * Type *return_type = proc.result_count == 0 ? nullptr : proc.results->Tuple.variables[0]->type; bool is_return_instancetype = return_type != nullptr && return_type == t_objc_instancetype; - if (params.count == 0 || !is_type_objc_ptr_to_object(params[0]->type)) { - if (!proc_entity->Procedure.is_objc_class_method) { - // Not a class method, invalid call - error(call, "Invalid Objective-C call: The Objective-C method is not a class method but this first parameter is not an Objective-C object pointer."); - return; - } - + if (proc_entity->Procedure.is_objc_class_method) { if (is_return_instancetype) { if (ce->proc->kind == Ast_SelectorExpr) { ast_node(se, SelectorExpr, ce->proc); @@ -8193,7 +8384,8 @@ gb_internal void check_objc_call_expr(CheckerContext *c, Operand *operand, Ast * self_type = t_objc_Class; params_start = 0; - } else if (ce->args.count > 0) { + } else { + GB_ASSERT(ce->args.count > 0); GB_ASSERT(is_type_objc_ptr_to_object(params[0]->type)); if (ce->args[0]->tav.objc_super_target) { @@ -8225,7 +8417,7 @@ gb_internal void check_objc_call_expr(CheckerContext *c, Operand *operand, Ast * add_objc_proc_type(c, call, return_type, param_types); } -gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *proc, Slice const &args, ProcInlining inlining, Type *type_hint) { +gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *proc, Slice const &args, ProcInlining inlining, ProcTailing tailing, Type *type_hint) { if (proc != nullptr && proc->kind == Ast_BasicDirective) { ast_node(bd, BasicDirective, proc); @@ -8256,7 +8448,10 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c return Expr_Expr; } if (inlining != ProcInlining_none) { - error(call, "Inlining operators are not allowed on built-in procedures"); + error(call, "Inlining directives are not allowed on built-in procedures"); + } + if (tailing != ProcTailing_none) { + error(call, "Tailing directives are not allowed on built-in procedures"); } } else { if (proc != nullptr) { @@ -8398,6 +8593,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } bool is_call_inlined = false; + bool is_call_tailed = true; switch (inlining) { case ProcInlining_inline: @@ -8432,6 +8628,23 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } } + switch (tailing) { + case ProcTailing_none: + break; + case ProcTailing_must_tail: + is_call_tailed = true; + if (c->curr_proc_sig == nullptr || !are_types_identical(c->curr_proc_sig, pt)) { + ERROR_BLOCK(); + gbString a = type_to_string(pt); + gbString b = type_to_string(c->curr_proc_sig); + error(call, "Use of '#must_tail' of a procedure must have the same type as the procedure it was called within"); + error_line("\tCall type: %s, parent type: %s", a, b); + gb_string_free(b); + gb_string_free(a); + } + break; + } + { String invalid; if (pt->kind == Type_Proc && pt->Proc.require_target_feature.len != 0) { @@ -8612,6 +8825,14 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 o->mode = Addressing_Variable; } return true; + + case Type_FixedCapacityDynamicArray: + o->type = t->FixedCapacityDynamicArray.elem; + if (o->mode != Addressing_Constant) { + o->mode = Addressing_Variable; + } + return true; + case Type_Struct: if (t->Struct.soa_kind != StructSoa_None) { if (t->Struct.soa_kind == StructSoa_Fixed) { @@ -8758,6 +8979,14 @@ gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Opera if (is_operand_nil(*o)) { return true; } + if (is_type_any(field_type)) { + return false; + } + if (field_type != nullptr && is_type_typeid(field_type) && o->mode == Addressing_Type) { + add_type_info_type(c, o->type); + return true; + } + Ast *expr = unparen_expr(o->expr); if (expr != nullptr) { Entity *e = strip_entity_wrapping(entity_from_expr(expr)); @@ -8768,13 +8997,12 @@ gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Opera add_type_and_value(c, expr, Addressing_Constant, type_of_expr(expr), exact_value_procedure(expr)); return true; } - } - if (field_type != nullptr && is_type_typeid(field_type) && o->mode == Addressing_Type) { - add_type_info_type(c, o->type); - return true; - } - if (is_type_any(field_type)) { - return false; + + if (e != nullptr && e->kind == Entity_Variable && e->Variable.is_rodata) { + // DeclInfo *d = e->decl_info; + // TODO(bill): rodata inlining for non-indirect values + // e.g. **NOT** []T{...} + } } return o->mode == Addressing_Constant; } @@ -8785,7 +9013,7 @@ gb_internal bool attempt_implicit_selector_expr(CheckerContext *c, Operand *o, A Type *enum_type = base_type(th); GB_ASSERT(enum_type->kind == Type_Enum); - String name = ise->selector->Ident.token.string; + auto name = ise->selector->Ident.interned; Entity *e = scope_lookup_current(enum_type->Enum.scope, name); if (e == nullptr) { @@ -9720,8 +9948,9 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, SliceIdent.token.string; + auto interned = ident->Ident.interned; - Selection sel = lookup_field(type, name, o->mode == Addressing_Type); + Selection sel = lookup_field(type, interned, o->mode == Addressing_Type); bool is_unknown = sel.entity == nullptr; if (is_unknown) { error(ident, "Unknown field '%.*s' in structure literal", LIT(name)); @@ -10141,6 +10370,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * case Type_DynamicArray: case Type_SimdVector: case Type_Matrix: + case Type_FixedCapacityDynamicArray: { Type *elem_type = nullptr; String context_name = {}; @@ -10171,6 +10401,10 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * elem_type = t->DynamicArray.elem; context_name = str_lit("dynamic array literal"); is_constant = false; + } else if (t->kind == Type_FixedCapacityDynamicArray) { + elem_type = t->FixedCapacityDynamicArray.elem; + context_name = str_lit("fixed capacity dynamic array literal"); + max_type_count = t->FixedCapacityDynamicArray.capacity; } else if (t->kind == Type_SimdVector) { elem_type = t->SimdVector.elem; context_name = str_lit("simd vector literal"); @@ -10671,8 +10905,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * continue; } String name = fv->field->Ident.token.string; + auto interned = fv->field->Ident.interned; - Selection sel = lookup_field(type, name, o->mode == Addressing_Type); + Selection sel = lookup_field(type, interned, o->mode == Addressing_Type); if (sel.entity == nullptr) { error(elem, "Unknown field '%.*s' in 'any' literal", LIT(name)); continue; @@ -11043,8 +11278,20 @@ gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *no end:; if ((c->state_flags & StateFlag_no_type_assert) == 0) { - add_package_dependency(c, "runtime", "type_assertion_check"); - add_package_dependency(c, "runtime", "type_assertion_check2"); + bool has_context = true; + if (c->proc_name.len == 0 && c->curr_proc_sig == nullptr) { + has_context = false; + } else if ((c->scope->flags & ScopeFlag_ContextDefined) == 0) { + has_context = false; + } + + if (has_context) { + add_package_dependency(c, "runtime", "type_assertion_check_with_context"); + add_package_dependency(c, "runtime", "type_assertion_check2_with_context"); + } else { + add_package_dependency(c, "runtime", "type_assertion_check_contextless"); + add_package_dependency(c, "runtime", "type_assertion_check2_contextless"); + } } return kind; } @@ -11242,6 +11489,8 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node, // Okay } else if (is_type_enumerated_array(t)) { // Okay + } else if (is_type_fixed_capacity_dynamic_array(t)) { + // Okay } else if (is_type_string(t)) { // Okay } else if (is_type_matrix(t)) { @@ -11388,6 +11637,11 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, o->type = alloc_type_slice(t->DynamicArray.elem); break; + case Type_FixedCapacityDynamicArray: + valid = true; + o->type = alloc_type_slice(t->FixedCapacityDynamicArray.elem); + break; + case Type_Struct: if (is_type_soa_struct(t)) { valid = true; @@ -11569,6 +11823,15 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast return kind; case_end; + case_ast_node(ht, HelperType, node); + Type *type = check_type(c, ht->type); + if (type != nullptr && type != t_invalid) { + o->mode = Addressing_Type; + o->type = type; + } + return kind; + case_end; + case_ast_node(i, Implicit, node); switch (i->kind) { case Token_context: @@ -11789,6 +12052,17 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast if (o->mode != Addressing_Invalid) { check_unary_expr(c, o, ue->op, node); + } else { + ERROR_BLOCK(); + gbString s = expr_to_string(ue->expr); + defer (gb_string_free(s)); + + error(node, "Cannot address value '%s' as it has not got a determined type yet", s); + + Entity *e = entity_of_node(ue->expr); + if (e != nullptr && e->kind == Entity_Variable) { + error_line("\tSuggestion: Add an explicit type to the declaration of '%.*s' rather than relying on type inference", LIT(e->token.string)); + } } o->expr = node; return Expr_Expr; @@ -11831,7 +12105,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast case_end; case_ast_node(ce, CallExpr, node); - return check_call_expr(c, o, node, ce->proc, ce->args, ce->inlining, type_hint); + return check_call_expr(c, o, node, ce->proc, ce->args, ce->inlining, ce->tailing, type_hint); case_end; case_ast_node(de, DerefExpr, node); @@ -11933,6 +12207,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast case Ast_MultiPointerType: case Ast_ArrayType: case Ast_DynamicArrayType: + case Ast_FixedCapacityDynamicArrayType: case Ast_StructType: case Ast_UnionType: case Ast_EnumType: @@ -12102,6 +12377,25 @@ gb_internal bool is_exact_value_zero(ExactValue const &v) { +gb_internal bool compare_exact_values_compound_lit(TokenKind op, ExactValue x, ExactValue y) { + ast_node(x_cl, CompoundLit, x.value_compound); + ast_node(y_cl, CompoundLit, y.value_compound); + + if (x_cl->elems.count != y_cl->elems.count) { + return false; + } + + bool test = op == Token_CmpEq; + + for (isize i = 0; i < x_cl->elems.count; i++) { + Ast *lhs = x_cl->elems[i]; + Ast *rhs = y_cl->elems[i]; + if (compare_exact_values(op, lhs->tav.value, rhs->tav.value) != test) { + return !test; + } + } + return test; +} @@ -12553,6 +12847,12 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan case_end; case_ast_node(ce, CallExpr, node); + switch (ce->tailing) { + case ProcTailing_must_tail: + str = gb_string_appendc(str, "#must_tail "); + break; + } + switch (ce->inlining) { case ProcInlining_inline: str = gb_string_appendc(str, "#force_inline "); @@ -12620,8 +12920,10 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan str = write_expr_to_string(str, st->polymorphic_params, shorthand); str = gb_string_appendc(str, ") "); } - if (st->is_packed) str = gb_string_appendc(str, "#packed "); - if (st->is_raw_union) str = gb_string_appendc(str, "#raw_union "); + if (st->is_packed) str = gb_string_appendc(str, "#packed "); + if (st->is_raw_union) str = gb_string_appendc(str, "#raw_union "); + if (st->is_all_or_none) str = gb_string_appendc(str, "#all_or_none "); + if (st->is_simple) str = gb_string_appendc(str, "#simple "); if (st->align) { str = gb_string_appendc(str, "#align "); str = write_expr_to_string(str, st->align, shorthand); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 835f0162a..5d740c6d2 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -484,7 +484,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O } if (ident_node != nullptr) { ast_node(i, Ident, ident_node); - e = scope_lookup(ctx->scope, i->token.string, i->hash); + e = scope_lookup(ctx->scope, i->interned, i->hash); if (e != nullptr && e->kind == Entity_Variable) { used = (e->flags & EntityFlag_Used) != 0; // NOTE(bill): Make backup just in case } @@ -788,12 +788,19 @@ gb_internal bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, rw_mutex_lock(&scope->mutex); defer (rw_mutex_unlock(&scope->mutex)); - for (auto const &entry : scope->elements) { - String name = entry.key; - Entity *decl = entry.value; - if (!is_entity_exported(decl, true)) continue; + for (u32 i = 0; i < scope->elements.cap; i++) { + if (!scope->elements.slots[i].hash) { + continue; + } - Entity *found = scope_insert_with_name(ctx->scope, name, decl); + Entity *decl = scope->elements.slots[i].value; + if (!is_entity_exported(decl, true)) { + continue; + } + u32 hash = scope->elements.slots[i].hash; + auto interned = scope->elements.keys[i]; + + Entity *found = scope_insert_with_name(ctx->scope, interned, hash, decl); if (found != nullptr) { gbString expr_str = expr_to_string(expr); error(us->token, @@ -1018,16 +1025,31 @@ gb_internal void check_unroll_range_stmt(CheckerContext *ctx, Ast *node, u32 mod inline_for_depth = exact_value_i64(unroll_count); } break; + case Type_FixedCapacityDynamicArray: + if (unroll_count > 0) { + val0 = t->FixedCapacityDynamicArray.elem; + val1 = t_int; + inline_for_depth = exact_value_i64(unroll_count); + } + break; } } if (val0 == nullptr) { + ERROR_BLOCK(); gbString s = expr_to_string(operand.expr); gbString t = type_to_string(operand.type); + defer (gb_string_free(s)); + defer (gb_string_free(t)); error(operand.expr, "Cannot iterate over '%s' of type '%s' in an '#unroll for' statement", s, t); - gb_string_free(t); - gb_string_free(s); - } else if (operand.mode != Addressing_Constant && unroll_count <= 0) { + + if (is_type_slice(operand.type) || is_type_dynamic_array(operand.type) || is_type_fixed_capacity_dynamic_array(operand.type)) { + error_line("\tSuggestion: An unroll count `#unroll(N)` must be specified with an array of a runtime-known length\n"); + } + + } else if (operand.mode != Addressing_Constant && ( + unroll_count <= 0 && + compare_exact_values(Token_CmpEq, inline_for_depth, exact_value_i64(0)))) { error(operand.expr, "An '#unroll for' expression must be known at compile time"); } } @@ -1051,7 +1073,7 @@ gb_internal void check_unroll_range_stmt(CheckerContext *ctx, Ast *node, u32 mod Entity *found = nullptr; if (!is_blank_ident(str)) { - found = scope_lookup_current(ctx->scope, str); + found = scope_lookup_current(ctx->scope, name->Ident.interned, name->Ident.hash); } if (found == nullptr) { entity = alloc_entity_variable(ctx->scope, token, type, EntityState_Resolved); @@ -1703,11 +1725,17 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) TEMPORARY_ALLOCATOR_GUARD(); - u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed; check_open_scope(ctx, node); check_label(ctx, rs->label, node); + Operand init = {}; + if (rs->init != nullptr) { + check_stmt(ctx, rs->init, mod_flags); + } + + u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed; + auto vals = array_make(temporary_allocator(), 0, 2); auto entities = array_make(temporary_allocator(), 0, 2); bool is_map = false; @@ -1722,6 +1750,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) bool is_range = false; bool is_possibly_addressable = true; isize max_val_count = 2; + if (is_ast_range(expr)) { ast_node(ie, BinaryExpr, expr); Operand x = {}; @@ -1813,10 +1842,10 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) } if (rs->vals.count == 1 && rs->vals[0] && rs->vals[0]->kind == Ast_Ident) { AstIdent *ident = &rs->vals[0]->Ident; - String name = ident->token.string; - Entity *found = scope_lookup(ctx->scope, name, ident->hash); + Entity *found = scope_lookup(ctx->scope, ident->interned, ident->hash); if (found && are_types_identical(found->type, t->BitSet.elem)) { ERROR_BLOCK(); + String name = ident->token.string; gbString s = expr_to_string(expr); error(rs->vals[0], "'%.*s' shadows a previous declaration which might be ambiguous with 'for (%.*s in %s)'", LIT(name), LIT(name), s); error_line("\tSuggestion: Use a different identifier if iteration is wanted, or surround in parentheses if a normal for loop is wanted\n"); @@ -1837,6 +1866,12 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) array_add(&vals, t_int); break; + case Type_FixedCapacityDynamicArray: + is_possibly_addressable = operand.mode == Addressing_Variable || is_ptr; + array_add(&vals, t->FixedCapacityDynamicArray.elem); + array_add(&vals, t_int); + break; + case Type_DynamicArray: is_possibly_addressable = true; array_add(&vals, t->DynamicArray.elem); @@ -1859,10 +1894,10 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) } if (rs->vals.count == 1 && rs->vals[0] && rs->vals[0]->kind == Ast_Ident) { AstIdent *ident = &rs->vals[0]->Ident; - String name = ident->token.string; - Entity *found = scope_lookup(ctx->scope, name, ident->hash); + Entity *found = scope_lookup(ctx->scope, ident->interned, ident->hash); if (found && are_types_identical(found->type, t->Map.key)) { ERROR_BLOCK(); + String name = ident->token.string; gbString s = expr_to_string(expr); error(rs->vals[0], "'%.*s' shadows a previous declaration which might be ambiguous with 'for (%.*s in %s)'", LIT(name), LIT(name), s); error_line("\tSuggestion: Use a different identifier if iteration is wanted, or surround in parentheses if a normal for loop is wanted\n"); @@ -1882,7 +1917,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) error_line("\tMultiple return valued parameters in a range statement are limited to a minimum of 1 usable values with a trailing boolean for the conditional, got %td\n", count); break; } - enum : isize {MAXIMUM_COUNT = 100}; + enum : isize {MAXIMUM_COUNT = 20}; if (count > MAXIMUM_COUNT) { ERROR_BLOCK(); check_not_tuple(ctx, &operand); @@ -1898,7 +1933,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) break; } - max_val_count = count; + max_val_count = count-1; for (Entity *e : t->Tuple.variables) { array_add(&vals, e->type); @@ -1918,6 +1953,20 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) if (is_reverse) { error(node, "#reverse for is not supported for multiple return valued parameters"); } + + Ast *expr = unparen_expr(operand.expr); + if (expr->kind == Ast_CallExpr) { + Type *p = base_type(type_of_expr(expr->CallExpr.proc)); + if (p != nullptr && p->kind == Type_Proc) { + if (p->Proc.require_results) { + if (rs->vals.count < max_val_count) { + TokenPos start = ast_token(rs->vals[0]).pos; + TokenPos end = ast_end_pos(rs->vals[rs->vals.count-1]); + error_range(start, end, "Expected %td identifier%s, got %td", max_val_count, max_val_count == 1 ? "" : "s", rs->vals.count); + } + } + } + } } break; @@ -1989,7 +2038,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) Entity *found = nullptr; if (!is_blank_ident(str)) { - found = scope_lookup_current(ctx->scope, str); + found = scope_lookup_current(ctx->scope, name->Ident.interned, name->Ident.hash); } if (found == nullptr) { entity = alloc_entity_variable(ctx->scope, token, type, EntityState_Resolved); @@ -2083,7 +2132,7 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f Entity *found = nullptr; // NOTE(bill): Ignore assignments to '_' if (!is_blank_ident(str)) { - found = scope_lookup_current(ctx->scope, str); + found = scope_lookup_current(ctx->scope, name->Ident.interned, name->Ident.hash); new_name_count += 1; } if (found == nullptr) { @@ -2943,10 +2992,12 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) error(us->token, "Empty 'using' list"); return; } - if (check_vet_flags(node) & VetFlag_UsingStmt) { + + u64 feature_flags = check_feature_flags(ctx, node); + if ((feature_flags & OptInFeatureFlag_UsingStmt) == 0) { ERROR_BLOCK(); - error(node, "'using' as a statement is not allowed when '-vet' or '-vet-using' is applied"); - error_line("\t'using' is considered bad practice to use as a statement outside of immediate refactoring\n"); + error(node, "'using' has been disallowed as it is considered bad practice to use as a statement outside of immediate refactoring"); + error_line("\tIf you do require it for refactoring purposes or legacy code, it can be enabled on a per-file basis with '#+feature using-stmt'\n"); } for (Ast *expr : us->list) { diff --git a/src/check_type.cpp b/src/check_type.cpp index af07efd8f..b625fb3d0 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -5,7 +5,9 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para gb_internal void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field, Type *t, String name, i32 idx) { t = base_type(t); GB_ASSERT(t->kind == Type_Array); - Entity *e = scope_lookup_current(ctx->scope, name); + InternedString interned = string_interner_insert(name); + + Entity *e = scope_lookup_current(ctx->scope, interned); if (e != nullptr) { gbString str = nullptr; defer (gb_string_free(str)); @@ -37,22 +39,20 @@ gb_internal void populate_using_entity_scope(CheckerContext *ctx, Ast *node, Ast } Type *original_type = t; t = base_type(type_deref(t)); - gbString str = nullptr; - defer (gb_string_free(str)); - if (node != nullptr) { - str = expr_to_string(node); - } if (t->kind == Type_Struct) { for (Entity *f : t->Struct.fields) { GB_ASSERT(f->kind == Entity_Variable); String name = f->token.string; - Entity *e = scope_lookup_current(ctx->scope, name); + InternedString interned = entity_interned_name(f); + Entity *e = scope_lookup_current(ctx->scope, interned); if (e != nullptr && name != "_") { gbString ot = type_to_string(original_type); // TODO(bill): Better type error - if (str != nullptr) { + if (node != nullptr) { + gbString str = expr_to_string(node); error(e->token, "'%.*s' is already declared in '%s', through 'using' from '%s'", LIT(name), str, ot); + gb_string_free(str); } else { error(e->token, "'%.*s' is already declared, through 'using' from '%s'", LIT(name), ot); } @@ -102,9 +102,6 @@ gb_internal bool does_field_type_allow_using(Type *t) { gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slice *fields, String **tags, Slice const ¶ms, isize init_field_capacity, Type *struct_type, String context) { - auto fields_array = array_make(heap_allocator(), 0, init_field_capacity); - auto tags_array = array_make(heap_allocator(), 0, init_field_capacity); - GB_ASSERT(node->kind == Ast_StructType); GB_ASSERT(struct_type->kind == Type_Struct); @@ -117,6 +114,16 @@ gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slice(permanent_allocator(), 0, init_field_capacity); + auto tags_array = array_make(permanent_allocator(), 0, init_field_capacity); + + defer (GB_ASSERT(fields_array.count == init_field_capacity)); + + // Allocate all at once + Entity *entities_to_use = permanent_alloc_array(variable_count); + isize entities_to_use_index = 0; + i32 field_src_index = 0; i32 field_group_index = -1; for_array(i, params) { @@ -165,7 +172,17 @@ gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, SliceIdent.token; - Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index); + // Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index); + Entity *field = &entities_to_use[entities_to_use_index++]; + INTERNAL_ENTITY_INIT(field, Entity_Variable, ctx->scope, name_token, type); + + field->interned_name.store(name->Ident.interned); + field->interned_name_hash.store(name->Ident.hash); + + field->flags |= EntityFlag_Field; + if (is_using) field->flags |= EntityFlag_Using; + field->Variable.field_index = field_src_index; + add_entity(ctx, ctx->scope, name, field); field->Variable.field_group_index = field_group_index; if (is_subtype) { @@ -272,7 +289,7 @@ gb_internal GenTypesData *ensure_polymorphic_record_entity_has_gen_types(Checker GB_ASSERT(original_type->kind == Type_Named); mutex_lock(&original_type->Named.gen_types_data_mutex); if (original_type->Named.gen_types_data == nullptr) { - GenTypesData *gen_types = gb_alloc_item(permanent_allocator(), GenTypesData); + GenTypesData *gen_types = permanent_alloc_item(); gen_types->types = array_make(heap_allocator()); original_type->Named.gen_types_data = gen_types; } @@ -412,7 +429,7 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly Ast *s = type_expr->TypeidType.specialization; specialization = check_type(ctx, s); } - type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization); + type = alloc_type_generic(ctx->scope, 0, string_interner_insert(str_lit("")), specialization); } else { type = check_type(ctx, type_expr); if (is_type_polymorphic(type)) { @@ -636,7 +653,7 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast * isize min_field_count = 0; for_array(field_index, st->fields) { - Ast *field = st->fields[field_index]; + Ast *field = st->fields[field_index]; switch (field->kind) { case_ast_node(f, ValueDecl, field); min_field_count += f->names.count; @@ -679,6 +696,21 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast * gb_unused(where_clause_ok); } check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context); + + if (st->is_simple) { + bool success = true; + for (Entity *f : struct_type->Struct.fields) { + if (!is_type_nearly_simple_compare(f->type)) { + gbString s = type_to_string(f->type); + error(f->token, "'struct #simple' requires all fields to be at least 'nearly simple compare', got %s", s); + gb_string_free(s); + } + } + if (success) { + struct_type->Struct.is_simple = true; + } + } + wait_signal_set(&struct_type->Struct.fields_wait_signal); } @@ -872,6 +904,10 @@ gb_internal void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *nam scope_reserve(ctx->scope, et->fields.count); + // Allocate all at once + Entity *entities_to_use = permanent_alloc_array(et->fields.count); + isize entities_to_use_index = 0; + for_array(i, et->fields) { Ast *field = et->fields[i]; Ast *ident = nullptr; @@ -916,9 +952,6 @@ gb_internal void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *nam // NOTE(bill): Skip blank identifiers if (is_blank_ident(name)) { continue; - } else if (name == "names") { - error(field, "'names' is a reserved identifier for enumerations"); - continue; } if (min_value_set) { @@ -942,7 +975,15 @@ gb_internal void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *nam max_value_set = true; } - Entity *e = alloc_entity_constant(ctx->scope, ident->Ident.token, constant_type, iota); + // Entity *e = alloc_entity_constant(ctx->scope, ident->Ident.token, constant_type, iota); + Entity *e = &entities_to_use[entities_to_use_index++]; + Token token = ident->Ident.token; + INTERNAL_ENTITY_INIT(e, Entity_Constant, ctx->scope, token, constant_type); + + e->interned_name.store(ident->Ident.interned); + e->interned_name_hash.store(ident->Ident.hash); + + e->Constant.value = iota; e->identifier = ident; e->flags |= EntityFlag_Visited; e->state = EntityState_Resolved; @@ -950,7 +991,9 @@ gb_internal void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *nam e->Constant.docs = docs; e->Constant.comment = comment; - if (scope_lookup_current(ctx->scope, name) != nullptr) { + auto interned = entity_interned_name(e); + + if (scope_lookup_current(ctx->scope, interned) != nullptr) { error(ident, "'%.*s' is already declared in this enumeration", LIT(name)); } else { add_entity(ctx, ctx->scope, nullptr, e); @@ -1012,6 +1055,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, CommentGroup *comment = f->comment; String name = f->name->Ident.token.string; + InternedString interned = f->name->Ident.interned; if (f->type == nullptr) { error(field, "A bit_field's field must have a type"); @@ -1062,7 +1106,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, gb_string_free(s); } - if (scope_lookup_current(ctx->scope, name) != nullptr) { + if (scope_lookup_current(ctx->scope, interned) != nullptr) { error(f->name, "'%.*s' is already declared in this bit_field", LIT(name)); } else { i64 bit_size_i64 = exact_value_to_i64(bit_size); @@ -1214,6 +1258,7 @@ gb_internal void check_bit_set_type(CheckerContext *c, Type *type, Type *named_t ast_node(bs, BitSetType, node); GB_ASSERT(type->kind == Type_BitSet); type->BitSet.node = node; + type->BitSet.elem = t_invalid; /* i64 const DEFAULT_BITS = cast(i64)(8*build_context.word_size); */ i64 const MAX_BITS = 128; @@ -1481,7 +1526,7 @@ gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *special // NOTE(bill, 2018-12-14): This is needed to override polymorphic named constants in types if (st->kind == Type_Generic && t_e->kind == Entity_Constant) { - Entity *e = scope_lookup(st->Generic.scope, st->Generic.name); + Entity *e = scope_lookup(st->Generic.scope, st->Generic.interned_name, 0); GB_ASSERT(e != nullptr); if (modify_type) { e->kind = Entity_Constant; @@ -1534,7 +1579,7 @@ gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *special // NOTE(bill, 2018-12-14): This is needed to override polymorphic named constants in types if (st->kind == Type_Generic && t_e->kind == Entity_Constant) { - Entity *e = scope_lookup(st->Generic.scope, st->Generic.name); + Entity *e = scope_lookup(st->Generic.scope, st->Generic.interned_name, 0); GB_ASSERT(e != nullptr); if (modify_type) { e->kind = Entity_Constant; @@ -1812,6 +1857,11 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para bool is_c_vararg = false; auto variables = array_make(permanent_allocator(), 0, variable_count); i32 field_group_index = -1; + + + Entity *entities_to_use = permanent_alloc_array(variable_count); + isize entities_to_use_index = 0; + for_array(i, params) { Ast *param = params[i]; if (param->kind != Ast_Field) { @@ -1830,11 +1880,14 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para Type *specialization = nullptr; bool is_using = (p->flags&FieldFlag_using) != 0; - if ((check_vet_flags(param) & VetFlag_UsingParam) && is_using) { - ERROR_BLOCK(); - error(param, "'using' on a procedure parameter is not allowed when '-vet' or '-vet-using-param' is applied"); - error_line("\t'using' is considered bad practice to use as a statement/procedure parameter outside of immediate refactoring\n"); + + u64 feature_flags = check_feature_flags(ctx, param); + + if (is_using && (feature_flags & OptInFeatureFlag_UsingStmt) == 0) { + ERROR_BLOCK(); + error(param, "'using' has been disallowed as it is considered bad practice to use as a statement/procedure parameter outside of immediate refactoring"); + error_line("\tIf you do require it for refactoring purposes or legacy code, it can be enabled on a per-file basis with '#+feature using-stmt'\n"); } if (type_expr == nullptr) { @@ -1870,7 +1923,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para detemine_type_from_operand = true; type = t_invalid; } else { - type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization); + type = alloc_type_generic(ctx->scope, 0, string_interner_insert(str_lit("")), specialization); } } else { type = t_typeid; @@ -2048,7 +2101,12 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para p->flags &= ~FieldFlag_no_capture; } - param = alloc_entity_type_name(scope, name->Ident.token, type, EntityState_Resolved); + param = &entities_to_use[entities_to_use_index++]; + INTERNAL_ENTITY_INIT(param, Entity_TypeName, scope, name->Ident.token, type); + param->state = EntityState_Resolved; + param->interned_name.store(name->Ident.interned); + param->interned_name_hash.store(name->Ident.hash); + param->TypeName.is_type_alias = true; } else { ExactValue poly_const = {}; @@ -2202,10 +2260,36 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para // failed } - param = alloc_entity_const_param(scope, name->Ident.token, type, poly_const, is_type_polymorphic(type)); + // param = alloc_entity_const_param(scope, name->Ident.token, type, poly_const, is_type_polymorphic(type)); + + param = &entities_to_use[entities_to_use_index++]; + INTERNAL_ENTITY_INIT(param, Entity_Constant, scope, name->Ident.token, type); + + param->flags |= EntityFlag_Used|EntityFlag_Param; + if (is_type_polymorphic(type)) { + param->flags |= EntityFlag_PolyConst; + } + param->Constant.value = poly_const; + + param->interned_name.store(name->Ident.interned); + param->interned_name_hash.store(name->Ident.hash); + param->Constant.field_group_index = field_group_index; } else { - param = alloc_entity_param(scope, name->Ident.token, type, is_using, true); + // param = alloc_entity_param(scope, name->Ident.token, type, is_using, true); + + param = &entities_to_use[entities_to_use_index++]; + INTERNAL_ENTITY_INIT(param, Entity_Variable, scope, name->Ident.token, type); + + param->state = EntityState_Resolved; + param->flags |= EntityFlag_Used|EntityFlag_Param|EntityFlag_Value; + if (is_using) { + param->flags |= EntityFlag_Using; + } + + param->interned_name.store(name->Ident.interned); + param->interned_name_hash.store(name->Ident.hash); + param->Variable.param_value = param_value; param->Variable.field_group_index = field_group_index; param->Variable.type_expr = type_expr; @@ -2287,6 +2371,56 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para return tuple; } +// Check if an AST node references any polymorphic type parameters +// TODO(bill): is this even complete enough? +gb_internal bool ast_references_poly_params(Scope *scope, Ast *node) { + if (node == nullptr) { + return false; + } + switch (node->kind) { + case Ast_Ident: { + Entity *e = scope_lookup(scope, node->Ident.interned, node->Ident.hash); + if (e != nullptr && e->kind == Entity_TypeName && e->type != nullptr && e->type->kind == Type_Generic) { + return true; + } + return false; + } + case Ast_SelectorExpr: + return ast_references_poly_params(scope, node->SelectorExpr.expr); + case Ast_IndexExpr: + return ast_references_poly_params(scope, node->IndexExpr.expr); + case Ast_CallExpr: + for (Ast *arg : node->CallExpr.args) { + if (ast_references_poly_params(scope, arg)) { + return true; + } + } + return ast_references_poly_params(scope, node->CallExpr.proc); + case Ast_CompoundLit: + return ast_references_poly_params(scope, node->CompoundLit.type); + case Ast_UnaryExpr: + return ast_references_poly_params(scope, node->UnaryExpr.expr); + case Ast_ParenExpr: + return ast_references_poly_params(scope, node->ParenExpr.expr); + case Ast_DerefExpr: + return ast_references_poly_params(scope, node->DerefExpr.expr); + case Ast_PointerType: + return ast_references_poly_params(scope, node->PointerType.type); + case Ast_ArrayType: + return ast_references_poly_params(scope, node->ArrayType.elem) || + ast_references_poly_params(scope, node->ArrayType.count); + case Ast_FixedCapacityDynamicArrayType: + return ast_references_poly_params(scope, node->FixedCapacityDynamicArrayType.elem) || + ast_references_poly_params(scope, node->FixedCapacityDynamicArrayType.capacity); + case Ast_DynamicArrayType: + return ast_references_poly_params(scope, node->DynamicArrayType.elem); + case Ast_MapType: + return ast_references_poly_params(scope, node->MapType.key) || + ast_references_poly_params(scope, node->MapType.value); + } + return false; +} + gb_internal Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) { if (_results == nullptr) { return nullptr; @@ -2308,6 +2442,9 @@ gb_internal Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_res } } + Entity *entities_to_use = permanent_alloc_array(variable_count); + isize entities_to_use_index = 0; + auto variables = array_make(permanent_allocator(), 0, variable_count); i32 field_group_index = -1; for_array(i, results) { @@ -2321,7 +2458,12 @@ gb_internal Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_res if (field->type == nullptr) { param_value = handle_parameter_value(ctx, nullptr, &type, default_value, false); } else { - type = check_type(ctx, field->type); + if (ctx->allow_polymorphic_types && ast_references_poly_params(ctx->scope, field->type)) { + type = alloc_type_generic(ctx->scope, 0, string_interner_insert(str_lit("$deferred_return")), nullptr); + } else { + type = check_type(ctx, field->type); + } + if (default_value != nullptr) { param_value = handle_parameter_value(ctx, type, nullptr, default_value, false); @@ -2341,7 +2483,12 @@ gb_internal Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_res if (field->names.count == 0) { Token token = ast_token(field->type); token.string = str_lit(""); - Entity *param = alloc_entity_param(scope, token, type, false, false); + // Entity *param = alloc_entity_param(scope, token, type, false, false); + Entity *param = &entities_to_use[entities_to_use_index++]; + INTERNAL_ENTITY_INIT(param, Entity_Variable, scope, token, type); + param->state = EntityState_Resolved; + param->flags |= EntityFlag_Used|EntityFlag_Param|EntityFlag_Result; + param->Variable.param_value = param_value; param->Variable.field_group_index = -1; array_add(&variables, param); @@ -2364,8 +2511,17 @@ gb_internal Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_res error(name, "Result value cannot be a blank identifer `_`"); } - Entity *param = alloc_entity_param(scope, token, type, false, false); - param->flags |= EntityFlag_Result; + // Entity *param = alloc_entity_param(scope, token, type, false, false); + Entity *param = &entities_to_use[entities_to_use_index++]; + INTERNAL_ENTITY_INIT(param, Entity_Variable, scope, token, type); + param->state = EntityState_Resolved; + param->flags |= EntityFlag_Used|EntityFlag_Param|EntityFlag_Result; + + if (name->kind == Ast_Ident) { + param->interned_name.store(name->Ident.interned); + param->interned_name_hash.store(name->Ident.hash); + } + param->Variable.param_value = param_value; param->Variable.field_group_index = field_group_index; array_add(&variables, param); @@ -3130,7 +3286,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e soa_struct->Struct.fields = permanent_slice_make(field_count+extra_field_count); soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count); - string_map_init(&scope->elements, 8); + scope_map_init(&scope->elements); String params_xyzw[4] = { str_lit("x"), @@ -3228,7 +3384,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e add_type_info_type(ctx, soa_struct); wait_signal_set(&soa_struct->Struct.fields_wait_signal); } else { - SoaTypeWorkerData *wd = gb_alloc_item(permanent_allocator(), SoaTypeWorkerData); + SoaTypeWorkerData *wd = permanent_alloc_item(); wd->ctx = *ctx; wd->type = soa_struct; wd->wait_to_finish = true; @@ -3443,7 +3599,7 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T Ast *s = pt->specialization; specific = check_type(&c, s); } - Type *t = alloc_type_generic(ctx->scope, 0, token.string, specific); + Type *t = alloc_type_generic(ctx->scope, 0, ident->Ident.interned, specific); if (ctx->allow_polymorphic_types) { if (ctx->disallow_polymorphic_return_types) { error(ident, "Undeclared polymorphic parameter '%.*s' in return type", LIT(token.string)); @@ -3524,7 +3680,8 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T CheckerContext c = *ctx; TEMPORARY_ALLOCATOR_GUARD(); - c.type_path = new_checker_type_path(temporary_allocator()); + c.type_path = new_checker_type_path(); + defer (destroy_checker_type_path(c.type_path)); Type *elem = t_invalid; Operand o = {}; @@ -3623,6 +3780,31 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T return true; case_end; + case_ast_node(dat, FixedCapacityDynamicArrayType, e); + Operand o = {}; + i64 capacity = check_array_count(ctx, &o, dat->capacity); + Type *generic_type = nullptr; + if (o.mode == Addressing_Type && o.type->kind == Type_Generic) { + generic_type = o.type; + } + + if (capacity < 0) { + error(dat->capacity, "? can only be used in conjunction with compound literals of fixed-length arrays"); + capacity = 0; + } + + + Type *elem = check_type(ctx, dat->elem); + if (dat->tag != nullptr) { + GB_ASSERT(dat->tag->kind == Ast_BasicDirective); + String name = dat->tag->BasicDirective.name.string; + error(dat->tag, "Invalid tag applied to fixed capacity dynamic array, got #%.*s", LIT(name)); + } + *type = alloc_type_fixed_capacity_dynamic_array(elem, capacity, generic_type); + set_base_type(named_type, *type); + return true; + case_end; + case_ast_node(st, StructType, e); CheckerContext c = *ctx; c.in_polymorphic_specialization = false; @@ -3750,6 +3932,20 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T set_base_type(named_type, *type); return true; case_end; + + default: { + Operand o = {}; + check_expr_base(ctx, &o, e, nullptr); + + if (o.mode == Addressing_Constant && + o.value.kind == ExactValue_Typeid) { + Type *t = o.value.value_typeid; + if (t != nullptr && t != t_invalid) { + *type = t; + return true; + } + } + } } *type = t_invalid; @@ -3758,8 +3954,8 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T gb_internal Type *check_type(CheckerContext *ctx, Ast *e) { CheckerContext c = *ctx; - TEMPORARY_ALLOCATOR_GUARD(); - c.type_path = new_checker_type_path(temporary_allocator()); + c.type_path = new_checker_type_path(); + defer (destroy_checker_type_path(c.type_path)); return check_type_expr(&c, e, nullptr); } diff --git a/src/checker.cpp b/src/checker.cpp index 4d5482933..ce8042b41 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -55,7 +55,8 @@ gb_internal bool check_rtti_type_disallowed(Ast *expr, Type *type, char const *f gb_internal void scope_reserve(Scope *scope, isize count) { - string_map_reserve(&scope->elements, 2*count); + scope_map_reserve(&scope->elements, 2*count); + // string_map_reserve(&scope->elements, 2*count); } gb_internal void entity_graph_node_set_destroy(EntityGraphNodeSet *s) { @@ -123,7 +124,7 @@ gb_internal void import_graph_node_set_add(ImportGraphNodeSet *s, ImportGraphNod // } gb_internal ImportGraphNode *import_graph_node_create(gbAllocator a, AstPackage *pkg) { - ImportGraphNode *n = gb_alloc_item(a, ImportGraphNode); + ImportGraphNode *n = permanent_alloc_item(); n->pkg = pkg; n->scope = pkg->scope; return n; @@ -163,7 +164,6 @@ gb_internal void import_graph_node_swap(ImportGraphNode **data, isize i, isize j gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { - gb_zero_item(d); if (parent) { mutex_lock(&parent->next_mutex); d->next_sibling = parent->next_child; @@ -181,7 +181,7 @@ gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { } gb_internal DeclInfo *make_decl_info(Scope *scope, DeclInfo *parent) { - DeclInfo *d = gb_alloc_item(permanent_allocator(), DeclInfo); + DeclInfo *d = permanent_alloc_item(); init_decl_info(d, scope, parent); return d; } @@ -214,7 +214,8 @@ gb_internal DeclInfo *make_decl_info(Scope *scope, DeclInfo *parent) { gb_internal Scope *create_scope(CheckerInfo *info, Scope *parent) { - Scope *s = gb_alloc_item(permanent_allocator(), Scope); + Scope *s = permanent_alloc_item(); + scope_map_init(&s->elements); s->parent = parent; if (parent != nullptr && parent != builtin_pkg->scope) { @@ -238,8 +239,7 @@ gb_internal Scope *create_scope_from_file(CheckerInfo *info, AstFile *f) { isize init_elements_capacity = gb_max(DEFAULT_SCOPE_CAPACITY, 2*f->total_file_decl_count); Scope *s = create_scope(info, f->pkg->scope); - string_map_init(&s->elements, init_elements_capacity); - + scope_reserve(s, init_elements_capacity); s->flags |= ScopeFlag_File; s->file = f; @@ -256,9 +256,10 @@ gb_internal Scope *create_scope_from_package(CheckerContext *c, AstPackage *pkg) total_pkg_decl_count += file->total_file_decl_count; } - isize init_elements_capacity = gb_max(DEFAULT_SCOPE_CAPACITY, 2*total_pkg_decl_count); + // isize init_elements_capacity = gb_max(DEFAULT_SCOPE_CAPACITY, 2*total_pkg_decl_count); Scope *s = create_scope(c->info, builtin_pkg->scope); - string_map_init(&s->elements, init_elements_capacity); + scope_map_reserve(&s->elements, 2*total_pkg_decl_count); + // string_map_init(&s->elements, init_elements_capacity); s->flags |= ScopeFlag_Pkg; s->pkg = pkg; @@ -285,7 +286,7 @@ gb_internal void destroy_scope(Scope *scope) { destroy_scope(child); } - string_map_destroy(&scope->elements); + // string_map_destroy(&scope->elements); ptr_set_destroy(&scope->imported); // NOTE(bill): No need to free scope as it "should" be allocated in an arena (except for the global scope) @@ -371,10 +372,14 @@ gb_internal void check_close_scope(CheckerContext *c) { } -gb_internal Entity *scope_lookup_current(Scope *s, String const &name) { - Entity **found = string_map_get(&s->elements, name); +gb_internal Entity *scope_lookup_current(Scope *s, InternedString name, u32 hash) { + // Entity **found = string_map_get(&s->elements, name); + if (hash == 0) { + hash = name.hash(); + } + Entity *found = scope_map_get(&s->elements, name, hash); if (found) { - return *found; + return found; } return nullptr; } @@ -382,25 +387,21 @@ gb_internal Entity *scope_lookup_current(Scope *s, String const &name) { gb_global std::atomic in_single_threaded_checker_stage; -gb_internal void scope_lookup_parent(Scope *scope, String const &name, Scope **scope_, Entity **entity_, u32 hash) { +gb_internal void scope_lookup_parent(Scope *scope, InternedString name, Scope **scope_, Entity **entity_, u32 hash) { bool is_single_threaded = in_single_threaded_checker_stage.load(std::memory_order_relaxed); if (scope != nullptr) { bool gone_thru_proc = false; bool gone_thru_package = false; - StringHashKey key = {}; - if (hash) { - key.hash = hash; - key.string = name; - } else { - key = string_hash_string(name); + if (!hash) { + hash = name.hash(); } for (Scope *s = scope; s != nullptr; s = s->parent) { - Entity **found = nullptr; + Entity *found = nullptr; if (!is_single_threaded) rw_mutex_shared_lock(&s->mutex); - found = string_map_get(&s->elements, key); + found = scope_map_get(&s->elements, name, hash); if (!is_single_threaded) rw_mutex_shared_unlock(&s->mutex); if (found) { - Entity *e = *found; + Entity *e = found; if (gone_thru_proc) { if (e->kind == Entity_Label) { continue; @@ -433,41 +434,40 @@ gb_internal void scope_lookup_parent(Scope *scope, String const &name, Scope **s if (scope_) *scope_ = nullptr; } -gb_internal Entity *scope_lookup(Scope *s, String const &name, u32 hash) { +gb_internal Entity *scope_lookup(Scope *s, InternedString interned, u32 hash) { Entity *entity = nullptr; - scope_lookup_parent(s, name, nullptr, &entity, hash); + scope_lookup_parent(s, interned, nullptr, &entity, hash); return entity; } -gb_internal Entity *scope_insert_with_name_no_mutex(Scope *s, String const &name, Entity *entity) { - if (name == "") { +gb_internal Entity *scope_insert_with_name_no_mutex(Scope *s, InternedString name, u32 hash, Entity *entity) { + if (name.value == 0) { return nullptr; } - StringHashKey key = string_hash_string(name); - Entity **found = nullptr; + Entity *found = nullptr; Entity *result = nullptr; - found = string_map_get(&s->elements, key); + found = scope_map_get(&s->elements, name, hash); if (found) { - if (entity != *found) { - result = *found; + if (entity != found) { + result = found; } goto end; } if (s->parent != nullptr && (s->parent->flags & ScopeFlag_Proc) != 0) { - found = string_map_get(&s->parent->elements, key); + found = scope_map_get(&s->parent->elements, name, hash); if (found) { - if ((*found)->flags & EntityFlag_Result) { - if (entity != *found) { - result = *found; + if (found->flags & EntityFlag_Result) { + if (entity != found) { + result = found; } goto end; } } } - string_map_set(&s->elements, key, entity); + scope_map_insert(&s->elements, name, hash, entity); if (entity->scope == nullptr) { entity->scope = s; } @@ -476,37 +476,39 @@ end:; } -gb_internal Entity *scope_insert_with_name(Scope *s, String const &name, Entity *entity) { - if (name == "") { +gb_internal Entity *scope_insert_with_name(Scope *s, InternedString name, u32 hash, Entity *entity) { + if (name.value == 0) { return nullptr; } - StringHashKey key = string_hash_string(name); - Entity **found = nullptr; + Entity *found = nullptr; Entity *result = nullptr; rw_mutex_lock(&s->mutex); - found = string_map_get(&s->elements, key); + found = scope_map_get(&s->elements, name, hash); if (found) { - if (entity != *found) { - result = *found; + if (entity != found) { + result = found; } goto end; } if (s->parent != nullptr && (s->parent->flags & ScopeFlag_Proc) != 0) { - found = string_map_get(&s->parent->elements, key); + rw_mutex_shared_lock(&s->parent->mutex); + found = scope_map_get(&s->parent->elements, name, hash); if (found) { - if ((*found)->flags & EntityFlag_Result) { - if (entity != *found) { - result = *found; + if (found->flags & EntityFlag_Result) { + if (entity != found) { + result = found; } + rw_mutex_shared_unlock(&s->parent->mutex); goto end; } } + rw_mutex_shared_unlock(&s->parent->mutex); } - string_map_set(&s->elements, key, entity); + scope_map_insert(&s->elements, name, hash, entity); if (entity->scope == nullptr) { entity->scope = s; } @@ -517,17 +519,21 @@ end:; } gb_internal Entity *scope_insert(Scope *s, Entity *entity) { - String name = entity->token.string; + auto name = entity_interned_name(entity); + u32 hash = entity->interned_name_hash.load(std::memory_order_relaxed); + GB_ASSERT(hash != 0); if (in_single_threaded_checker_stage.load(std::memory_order_relaxed)) { - return scope_insert_with_name_no_mutex(s, name, entity); + return scope_insert_with_name_no_mutex(s, name, hash, entity); } else { - return scope_insert_with_name(s, name, entity); + return scope_insert_with_name(s, name, hash, entity); } } gb_internal Entity *scope_insert_no_mutex(Scope *s, Entity *entity) { - String name = entity->token.string; - return scope_insert_with_name_no_mutex(s, name, entity); + auto name = string_interner_insert(entity->token.string); + u32 hash = entity->interned_name_hash.load(std::memory_order_relaxed); + GB_ASSERT(hash != 0); + return scope_insert_with_name_no_mutex(s, name, hash, entity); } @@ -661,7 +667,8 @@ gb_internal bool check_vet_shadowing(Checker *c, Entity *e, VettedEntity *ve) { return false; } - Entity *shadowed = scope_lookup(parent, name); + auto interned = entity_interned_name(e); + Entity *shadowed = scope_lookup(parent, interned, e->interned_name_hash.load()); if (shadowed == nullptr) { return false; } @@ -943,8 +950,10 @@ gb_internal AstPackage *try_get_core_package(CheckerInfo *info, String name) { gb_internal void add_package_dependency(CheckerContext *c, char const *package_name, char const *name, bool required=false) { String n = make_string_c(name); + u32 hash = 0; + InternedString key = string_interner_insert(n, 0, &hash); AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name)); - Entity *e = scope_lookup(p->scope, n); + Entity *e = scope_lookup(p->scope, key, hash); GB_ASSERT_MSG(e != nullptr, "%s", name); GB_ASSERT(c->decl != nullptr); e->flags |= EntityFlag_Used; @@ -956,8 +965,10 @@ gb_internal void add_package_dependency(CheckerContext *c, char const *package_n gb_internal void try_to_add_package_dependency(CheckerContext *c, char const *package_name, char const *name) { String n = make_string_c(name); + u32 hash = 0; + InternedString key = string_interner_insert(n, 0, &hash); AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name)); - Entity *e = scope_lookup(p->scope, n); + Entity *e = scope_lookup(p->scope, key, hash); if (e == nullptr) { return; } @@ -1016,7 +1027,7 @@ gb_internal void add_global_type_entity(String name, Type *type) { gb_internal AstPackage *create_builtin_package(char const *name) { gbAllocator a = permanent_allocator(); - AstPackage *pkg = gb_alloc_item(a, AstPackage); + AstPackage *pkg = permanent_alloc_item(); pkg->name = make_string_c(name); pkg->kind = Package_Builtin; @@ -1355,6 +1366,9 @@ gb_internal void init_universal(void) { BuiltinProcId id = cast(BuiltinProcId)i; String name = builtin_procs[i].name; if (name != "") { + u32 hash = 0; + InternedString interned = string_interner_insert(name, 0, &hash); + Entity *entity = alloc_entity(Entity_Builtin, nullptr, make_token_ident(name), t_invalid); entity->Builtin.id = id; switch (builtin_procs[i].pkg) { @@ -1363,7 +1377,7 @@ gb_internal void init_universal(void) { break; case BuiltinProcPkg_intrinsics: add_global_entity(entity, intrinsics_pkg->scope); - GB_ASSERT(scope_lookup_current(intrinsics_pkg->scope, name) != nullptr); + GB_ASSERT(scope_lookup_current(intrinsics_pkg->scope, interned, hash) != nullptr); break; } } @@ -1530,19 +1544,18 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { map_destroy(&i->load_directory_map); } -gb_internal CheckerContext make_checker_context(Checker *c) { - CheckerContext ctx = {}; - ctx.checker = c; - ctx.info = &c->info; - ctx.scope = builtin_pkg->scope; - ctx.pkg = builtin_pkg; +gb_internal void init_checker_context(CheckerContext *ctx, Checker *c) { + ctx->checker = c; + ctx->info = &c->info; + ctx->scope = builtin_pkg->scope; + ctx->pkg = builtin_pkg; - ctx.type_path = new_checker_type_path(heap_allocator()); - ctx.type_level = 0; - return ctx; + ctx->type_path = new_checker_type_path(); + ctx->type_level = 0; } + gb_internal void destroy_checker_context(CheckerContext *ctx) { - destroy_checker_type_path(ctx->type_path, heap_allocator()); + destroy_checker_type_path(ctx->type_path); } gb_internal bool add_curr_ast_file(CheckerContext *ctx, AstFile *file) { @@ -1605,7 +1618,7 @@ gb_internal void init_checker(Checker *c) { mpsc_init(&c->global_untyped_queue, a); // , 1<<20); mpsc_init(&c->soa_types_to_complete, a); // , 1<<20); - c->builtin_ctx = make_checker_context(c); + init_checker_context(&c->builtin_ctx, c); } gb_internal void destroy_checker(Checker *c) { @@ -1793,7 +1806,22 @@ gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, check_set_expr_info(c, expr, mode, type, value); } -gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value, bool use_mutex) { +struct alignas(GB_CACHE_LINE_SIZE) TypeAndValueMutexStripes { + BlockingMutex mutex; + u8 padding[GB_CACHE_LINE_SIZE - gb_size_of(BlockingMutex)]; +}; + +enum { TypeAndValueMutexStripes_COUNT = 128 }; +gb_global TypeAndValueMutexStripes tav_mutex_stripes[TypeAndValueMutexStripes_COUNT]; + +gb_internal BlockingMutex *tav_mutex_for_node(Ast *node) { + GB_ASSERT(node != nullptr); + uintptr h = cast(uintptr)node; + h ^= h >> 6; + return &tav_mutex_stripes[h % TypeAndValueMutexStripes_COUNT].mutex; +} + +gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value) { if (expr == nullptr) { return; } @@ -1804,14 +1832,18 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo return; } - BlockingMutex *mutex = &ctx->info->type_and_value_mutex; - if (ctx->decl) { - mutex = &ctx->decl->type_and_value_mutex; - } else if (ctx->pkg) { - mutex = &ctx->pkg->type_and_value_mutex; - } + BlockingMutex *mutex = tav_mutex_for_node(expr); - if (use_mutex) mutex_lock(mutex); + /* Previous logic: + BlockingMutex *mutex = &ctx->info->type_and_value_mutex; + if (ctx->decl) { + mutex = &ctx->decl->type_and_value_mutex; + } else if (ctx->pkg) { + mutex = &ctx->pkg->type_and_value_mutex; + } + */ + + mutex_lock(mutex); Ast *prev_expr = nullptr; while (prev_expr != expr) { prev_expr = expr; @@ -1836,7 +1868,7 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo break; }; } - if (use_mutex) mutex_unlock(mutex); + mutex_unlock(mutex); } gb_internal void add_entity_definition(CheckerInfo *i, Ast *identifier, Entity *entity) { @@ -2220,7 +2252,7 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { case Type_BitSet: add_type_info_type_internal(c, bt->BitSet.elem); - add_type_info_type_internal(c, bt->BitSet.underlying); + add_type_info_type_internal(c, bit_set_to_int(bt)); break; case Type_Pointer: @@ -2256,6 +2288,11 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { add_type_info_type_internal(c, t_int); break; + case Type_FixedCapacityDynamicArray: + add_type_info_type_internal(c, bt->FixedCapacityDynamicArray.elem); + add_type_info_type_internal(c, t_int); + break; + case Type_Enum: add_type_info_type_internal(c, bt->Enum.base_type); break; @@ -2387,7 +2424,7 @@ gb_internal void check_procedure_later(Checker *c, ProcInfo *info) { } gb_internal void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *decl, Type *type, Ast *body, u64 tags) { - ProcInfo *info = gb_alloc_item(permanent_allocator(), ProcInfo); + ProcInfo *info = permanent_alloc_item(); info->file = file; info->token = token; info->decl = decl; @@ -2459,7 +2496,7 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { case Type_BitSet: add_min_dep_type_info(c, bt->BitSet.elem); - add_min_dep_type_info(c, bt->BitSet.underlying); + add_min_dep_type_info(c, bit_set_to_int(bt)); break; case Type_Pointer: @@ -2494,6 +2531,12 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { add_min_dep_type_info(c, t_int); break; + case Type_FixedCapacityDynamicArray: + add_min_dep_type_info(c, bt->FixedCapacityDynamicArray.elem); + add_min_dep_type_info(c, alloc_type_pointer(bt->FixedCapacityDynamicArray.elem)); + add_min_dep_type_info(c, alloc_type_array(bt->FixedCapacityDynamicArray.elem, bt->FixedCapacityDynamicArray.capacity)); + add_min_dep_type_info(c, t_int); + case Type_Enum: add_min_dep_type_info(c, bt->Enum.base_type); break; @@ -2716,7 +2759,9 @@ gb_internal void add_dependency_to_set_threaded(Checker *c, Entity *entity) { gb_internal void force_add_dependency_entity(Checker *c, Scope *scope, String const &name) { - Entity *e = scope_lookup(scope, name); + u32 hash = 0; + auto interned = string_interner_insert(name, 0, &hash); + Entity *e = scope_lookup(scope, interned, hash); if (e == nullptr) { return; } @@ -2728,7 +2773,9 @@ gb_internal void force_add_dependency_entity(Checker *c, Scope *scope, String co gb_internal void collect_testing_procedures_of_package(Checker *c, AstPackage *pkg) { AstPackage *testing_package = get_core_package(&c->info, str_lit("testing")); Scope *testing_scope = testing_package->scope; - Entity *test_signature = scope_lookup_current(testing_scope, str_lit("Test_Signature")); + u32 hash = 0; + InternedString interned = string_interner_insert(str_lit("Test_Signature"), 0, &hash); + Entity *test_signature = scope_lookup_current(testing_scope, interned, hash); Scope *s = pkg->scope; for (auto const &entry : s->elements) { @@ -3182,7 +3229,9 @@ gb_internal void check_single_global_entity(Checker *c, Entity *e, DeclInfo *d); gb_internal Entity *find_core_entity(Checker *c, String name) { - Entity *e = scope_lookup_current(c->info.runtime_package->scope, name); + u32 hash = 0; + InternedString interned = string_interner_insert(name, 0, &hash); + Entity *e = scope_lookup_current(c->info.runtime_package->scope, interned, hash); if (e == nullptr) { compiler_error("Could not find type declaration for '%.*s'\n" , LIT(name)); @@ -3192,7 +3241,9 @@ gb_internal Entity *find_core_entity(Checker *c, String name) { } gb_internal Type *find_core_type(Checker *c, String name) { - Entity *e = scope_lookup_current(c->info.runtime_package->scope, name); + u32 hash = 0; + InternedString interned = string_interner_insert(name, 0, &hash); + Entity *e = scope_lookup_current(c->info.runtime_package->scope, interned, hash); if (e == nullptr) { compiler_error("Could not find type declaration for '%.*s'\n" , LIT(name)); @@ -3207,8 +3258,10 @@ gb_internal Type *find_core_type(Checker *c, String name) { gb_internal Entity *find_entity_in_pkg(CheckerInfo *info, String const &pkg, String const &name) { + u32 hash = 0; + InternedString interned = string_interner_insert(name, 0, &hash); AstPackage *package = get_core_package(info, pkg); - Entity *e = scope_lookup_current(package->scope, name); + Entity *e = scope_lookup_current(package->scope, interned, hash); if (e == nullptr) { compiler_error("Could not find type declaration for '%.*s.%.*s'\n", LIT(pkg), LIT(name)); // NOTE(bill): This will exit the program as it's cannot continue without it! @@ -3217,8 +3270,10 @@ gb_internal Entity *find_entity_in_pkg(CheckerInfo *info, String const &pkg, Str } gb_internal Type *find_type_in_pkg(CheckerInfo *info, String const &pkg, String const &name) { + u32 hash = 0; + InternedString interned = string_interner_insert(name, 0, &hash); AstPackage *package = get_core_package(info, pkg); - Entity *e = scope_lookup_current(package->scope, name); + Entity *e = scope_lookup_current(package->scope, interned, hash); if (e == nullptr) { compiler_error("Could not find type declaration for '%.*s.%.*s'\n", LIT(pkg), LIT(name)); // NOTE(bill): This will exit the program as it's cannot continue without it! @@ -3227,15 +3282,24 @@ gb_internal Type *find_type_in_pkg(CheckerInfo *info, String const &pkg, String return e->type; } -gb_internal CheckerTypePath *new_checker_type_path(gbAllocator allocator) { - auto *tp = gb_alloc_item(allocator, CheckerTypePath); - array_init(tp, allocator, 0, 16); - return tp; +gb_internal gb_thread_local std::atomic *> checker_type_path_free_list; + +gb_internal CheckerTypePath *new_checker_type_path() { + // TODO(bill): Cache to reuse `CheckerTypePath + + auto *tp = atomic_freelist_get(checker_type_path_free_list); + if (tp == nullptr) { + tp = permanent_alloc_item >(); + array_init(&tp->value, permanent_allocator(), 0, 16); + } + return &tp->value; } -gb_internal void destroy_checker_type_path(CheckerTypePath *tp, gbAllocator allocator) { - array_free(tp); - gb_free(allocator, tp); +gb_internal void destroy_checker_type_path(CheckerTypePath *path) { + auto *tp = cast(AtomicFreelist *)path; + array_clear(&tp->value); + + atomic_freelist_put(checker_type_path_free_list, tp); } gb_internal void check_type_path_push(CheckerContext *c, Entity *e) { @@ -3330,6 +3394,7 @@ gb_internal void init_core_type_info(Checker *c) { t_type_info_matrix = find_core_type(c, str_lit("Type_Info_Matrix")); t_type_info_soa_pointer = find_core_type(c, str_lit("Type_Info_Soa_Pointer")); t_type_info_bit_field = find_core_type(c, str_lit("Type_Info_Bit_Field")); + t_type_info_fixed_capacity_dynamic_array = find_core_type(c, str_lit("Type_Info_Fixed_Capacity_Dynamic_Array")); t_type_info_named_ptr = alloc_type_pointer(t_type_info_named); t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer); @@ -3358,6 +3423,7 @@ gb_internal void init_core_type_info(Checker *c) { t_type_info_matrix_ptr = alloc_type_pointer(t_type_info_matrix); t_type_info_soa_pointer_ptr = alloc_type_pointer(t_type_info_soa_pointer); t_type_info_bit_field_ptr = alloc_type_pointer(t_type_info_bit_field); + t_type_info_fixed_capacity_dynamic_array_ptr = alloc_type_pointer(t_type_info_fixed_capacity_dynamic_array); } gb_internal void init_mem_allocator(Checker *c) { @@ -3581,7 +3647,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { return true; } else if (name == "test") { if (value != nullptr) { - error(value, "'%.*s' expects no parameter, or a string literal containing \"file\" or \"package\"", LIT(name)); + error(value, "Expected no value for '%.*s'", LIT(name)); } ac->test = true; return true; @@ -3629,13 +3695,13 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { return true; } else if (name == "init") { if (value != nullptr) { - error(value, "'%.*s' expects no parameter, or a string literal containing \"file\" or \"package\"", LIT(name)); + error(value, "Expected no value for '%.*s'", LIT(name)); } ac->init = true; return true; } else if (name == "fini") { if (value != nullptr) { - error(value, "'%.*s' expects no parameter, or a string literal containing \"file\" or \"package\"", LIT(name)); + error(value, "Expected no value for '%.*s'", LIT(name)); } ac->fini = true; return true; @@ -3991,6 +4057,12 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { } ac->no_sanitize_memory = true; return true; + } else if (name == "no_sanitize_thread") { + if (value != nullptr) { + error(value, "'%.*s' expects no parameter", LIT(name)); + } + ac->no_sanitize_thread = true; + return true; } return false; } @@ -4027,6 +4099,7 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) { } else if (ev.kind == ExactValue_String) { String model = ev.value_string; if (model == "default" || + model == "globaldynamic" || model == "localdynamic" || model == "initialexec" || model == "localexec") { @@ -4035,6 +4108,7 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) { ERROR_BLOCK(); error(elem, "Invalid thread local model '%.*s'. Valid models:", LIT(model)); error_line("\tdefault\n"); + error_line("\tglobaldynamic\n"); error_line("\tlocaldynamic\n"); error_line("\tinitialexec\n"); error_line("\tlocalexec\n"); @@ -4241,6 +4315,20 @@ gb_internal DECL_ATTRIBUTE_PROC(type_decl_attribute) { error(elem, "Expected a string or no value for '%.*s'", LIT(name)); } return true; + } else if (name == "deprecated") { + ExactValue ev = check_decl_attribute_value(c, value); + + if (ev.kind == ExactValue_String) { + String msg = ev.value_string; + if (msg.len == 0) { + error(elem, "Deprecation message cannot be an empty string"); + } else { + ac->deprecated_message = msg; + } + } else { + error(elem, "Expected a string value for '%.*s'", LIT(name)); + } + return true; } return false; } @@ -4486,7 +4574,9 @@ gb_internal void check_builtin_attributes(CheckerContext *ctx, Entity *e, Array< if (name == "builtin") { mutex_lock(&ctx->info->builtin_mutex); add_entity(ctx, builtin_pkg->scope, nullptr, e); - GB_ASSERT(scope_lookup(builtin_pkg->scope, e->token.string) != nullptr); + auto interned = entity_interned_name(e); + u32 hash = e->interned_name_hash.load(); + GB_ASSERT(scope_lookup(builtin_pkg->scope, interned, hash) != nullptr); if (value != nullptr) { error(value, "'builtin' cannot have a field value"); } @@ -4828,9 +4918,9 @@ gb_internal bool correct_single_type_alias(CheckerContext *c, Entity *e) { gb_internal bool correct_type_alias_in_scope_backwards(CheckerContext *c, Scope *s) { bool correction = false; for (u32 n = s->elements.count, i = n-1; i < n; i--) { - auto const &entry = s->elements.entries[i]; - Entity *e = entry.value; - if (entry.hash && e != nullptr) { + auto const &slot = s->elements.slots[i]; + Entity *e = slot.value; + if (slot.hash && e != nullptr) { correction |= correct_single_type_alias(c, e); } } @@ -4961,8 +5051,8 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice const &n } gb_internal CheckerContext *create_checker_context(Checker *c) { - CheckerContext *ctx = gb_alloc_item(permanent_allocator(), CheckerContext); - *ctx = make_checker_context(c); + CheckerContext *ctx = permanent_alloc_item(); + init_checker_context(ctx, c); return ctx; } @@ -5407,7 +5497,8 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) { } gb_internal void check_foreign_import_fullpaths(Checker *c) { - CheckerContext ctx = make_checker_context(c); + CheckerContext ctx = {}; + init_checker_context(&ctx, c); UntypedExprInfoMap untyped = {}; defer (map_destroy(&untyped)); @@ -5790,7 +5881,7 @@ gb_internal void check_collect_entities_all(Checker *c) { for (isize i = 0; i < thread_count; i++) { auto *wd = &collect_entity_worker_data[i]; wd->c = c; - wd->ctx = make_checker_context(c); + init_checker_context(&wd->ctx, c); map_init(&wd->untyped); } @@ -5831,7 +5922,7 @@ gb_internal void check_export_entities(Checker *c) { for (isize i = 0; i < thread_count; i++) { auto *wd = &collect_entity_worker_data[i]; map_clear(&wd->untyped); - wd->ctx = make_checker_context(c); + init_checker_context(&wd->ctx, c); } for (auto const &entry : c->info.packages) { @@ -5898,7 +5989,8 @@ gb_internal void check_import_entities(Checker *c) { } TIME_SECTION("check_import_entities - collect file decls"); - CheckerContext ctx = make_checker_context(c); + CheckerContext ctx = {}; + init_checker_context(&ctx, c); UntypedExprInfoMap untyped = {}; defer (map_destroy(&untyped)); @@ -6171,7 +6263,7 @@ gb_internal void check_procedure_later_from_entity(Checker *c, Entity *e, char c GB_ASSERT(e->decl_info != nullptr); - ProcInfo *pi = gb_alloc_item(permanent_allocator(), ProcInfo); + ProcInfo *pi = permanent_alloc_item(); pi->file = e->file; pi->token = e->token; pi->decl = e->decl_info; @@ -6247,7 +6339,8 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u } } - CheckerContext ctx = make_checker_context(c); + CheckerContext ctx = {}; + init_checker_context(&ctx, c); defer (destroy_checker_context(&ctx)); reset_checker_context(&ctx, pi->file, untyped); ctx.decl = pi->decl; @@ -7439,7 +7532,7 @@ gb_internal void check_parsed_files(Checker *c) { Scope *s = c->info.init_scope; GB_ASSERT(s != nullptr); GB_ASSERT(s->flags&ScopeFlag_Init); - Entity *e = scope_lookup_current(s, str_lit("main")); + Entity *e = scope_lookup_current(s, string_interner_insert(str_lit("main"))); if (e == nullptr) { Token token = {}; token.pos.file_id = 0; diff --git a/src/checker.hpp b/src/checker.hpp index bda7b2746..5e295dc84 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -141,6 +141,7 @@ struct AttributeContext { bool instrumentation_exit : 1; bool no_sanitize_address : 1; bool no_sanitize_memory : 1; + bool no_sanitize_thread : 1; bool rodata : 1; bool ignore_duplicates : 1; u32 optimization_mode; // ProcedureOptimizationMode @@ -220,14 +221,14 @@ struct DeclInfo { Entity * para_poly_original; - bool is_using; - bool where_clauses_evaluated; - bool foreign_require_results; + bool is_using; + bool foreign_require_results; + std::atomic where_clauses_evaluated; std::atomic proc_checked_state; - BlockingMutex proc_checked_mutex; - isize defer_used; - bool defer_use_checked; + BlockingMutex proc_checked_mutex; + isize defer_used; + std::atomic defer_use_checked; CommentGroup *comment; CommentGroup *docs; @@ -249,7 +250,7 @@ struct DeclInfo { i64 variadic_reuse_max_align; // NOTE(bill): this is to prevent a race condition since these procedure literals can be created anywhere at any time - struct lbModule *code_gen_module; + std::atomic code_gen_module; }; // ProcInfo stores the information needed for checking a procedure @@ -265,6 +266,264 @@ struct ProcInfo { }; +enum { DEFAULT_SCOPE_CAPACITY = 32 }; + + +struct ScopeMapSlot { + u32 hash; + u32 _pad; + Entity *value; +}; + +enum { SCOPE_MAP_INLINE_CAP = 16 }; + +struct ScopeMap { + InternedString inline_keys [SCOPE_MAP_INLINE_CAP]; + ScopeMapSlot inline_slots[SCOPE_MAP_INLINE_CAP]; + InternedString *keys; + ScopeMapSlot * slots; + u32 count; + u32 cap; +}; + +gb_internal gb_inline u32 scope_map_max_load(u32 cap) { + return cap - (cap>>2); // 75% +} + +gb_internal gb_inline void scope_map_init(ScopeMap *m) { + m->cap = SCOPE_MAP_INLINE_CAP; + m->slots = m->inline_slots; + m->keys = m->inline_keys; +} + + +gb_internal Entity *scope_map_insert_for_rehash( + InternedString *keys, ScopeMapSlot *slots, u32 mask, + InternedString key, u32 hash, Entity *value) { + u32 pos = hash & mask; + u32 dist = 0; + + for (;;) { + ScopeMapSlot *s = &slots[pos]; + + if (s->hash == 0) { + keys[pos] = key; + s->hash = hash; + s->value = value; + return nullptr; + } + + u32 existing_dist = (pos - s->hash) & mask; + + if (dist > existing_dist) { + auto tmp_key = keys[pos]; + u32 tmp_hash = s->hash; + Entity *tmp_value = s->value; + + keys[pos] = key; + s->hash = hash; + s->value = value; + + hash = tmp_hash; + value = tmp_value; + key = tmp_key; + dist = existing_dist; + } + + dist += 1; + pos = (pos+1) & mask; + } +} + +gb_internal gb_inline void scope_map_allocate_entries(u32 cap, InternedString **keys, ScopeMapSlot **slots) { + Arena *arena = get_arena(ThreadArena_Permanent); + isize size = (gb_size_of(InternedString) + gb_size_of(ScopeMapSlot)) * cap; + u8 *data = cast(u8 *)arena_alloc(arena, size, 8); + + *keys = cast(InternedString *)data; + *slots = cast(ScopeMapSlot *)(*keys + cap); + + // *keys = permanent_alloc_array(cap); + // *slots = permanent_alloc_array(cap); +} + + +gb_internal void scope_map_grow(ScopeMap *m) { + u32 new_cap = m->cap << 1; + u32 new_mask = new_cap - 1; + + InternedString *new_keys; + ScopeMapSlot * new_slots; + scope_map_allocate_entries(new_cap, &new_keys, &new_slots); + + if (m->count > 0) { + for (u32 i = 0; i < m->cap; i++) { + if (m->slots[i].hash) { + scope_map_insert_for_rehash(new_keys, new_slots, new_mask, + m->keys[i], m->slots[i].hash, m->slots[i].value); + } + } + } + + m->slots = new_slots; + m->keys = new_keys; + m->cap = new_cap; +} + +gb_internal void scope_map_reserve(ScopeMap *m, isize capacity) { + if (m->slots == nullptr) { + scope_map_init(m); + } + u32 new_cap = next_pow2_u32(cast(u32)capacity); + if (m->cap < new_cap && new_cap > SCOPE_MAP_INLINE_CAP) { + scope_map_allocate_entries(new_cap, &m->keys, &m->slots); + m->cap = new_cap; + } +} + + + +gb_internal Entity *scope_map_insert(ScopeMap *m, InternedString key, u32 hash, Entity *value) { + if (m->slots == nullptr) { + scope_map_init(m); + } + if (m->count >= scope_map_max_load(m->cap)) { + scope_map_grow(m); + } + + u32 mask = m->cap-1; + u32 pos = hash & mask; + u32 dist = 0; + + for (;;) { + ScopeMapSlot *s = &m->slots[pos]; + + if (s->hash == 0) { + m->keys[pos] = key; + s->hash = hash; + s->value = value; + m->count += 1; + return nullptr; + } + + if (s->hash == hash && m->keys[pos] == key) { + Entity *old = s->value; + s->value = value; + return old; + } + + u32 existing_dist = (pos - s->hash) & mask; + + if (dist > existing_dist) { + auto tmp_key = m->keys[pos]; + u32 tmp_hash = s->hash; + Entity *tmp_value = s->value; + + m->keys[pos] = key; + s->hash = hash; + s->value = value; + + key = tmp_key; + hash = tmp_hash; + value = tmp_value; + dist = existing_dist; + } + + dist += 1; + pos = (pos+1) & mask; + } +} + +gb_internal Entity *scope_map_get(ScopeMap *m, InternedString key, u32 hash) { + u32 mask = m->cap-1; + u32 pos = hash & mask; + u32 dist = 0; + for (;;) { + ScopeMapSlot *s = &m->slots[pos]; + u32 curr_hash = s->hash; + if (curr_hash == 0) { + return nullptr; + } + + u32 existing_dist = (pos - curr_hash) & mask; + if (dist > existing_dist) { + return nullptr; + } + if (curr_hash == hash && m->keys[pos] == key) { + return s->value; + } + + dist += 1; + pos = (pos + 1) & mask; + } +} + +gb_internal void scope_map_clear(ScopeMap *m) { + gb_memset(m->slots, 0, gb_size_of(*m->slots) * m->cap); + m->count = 0; +} + +struct ScopeMapIterator { + ScopeMap const *map; + u32 index; + + ScopeMapIterator &operator++() noexcept { + for (;;) { + ++index; + if (map->cap == index) { + return *this; + } + ScopeMapSlot *s = map->slots+index; + if (s->hash) { + return *this; + } + } + } + + bool operator==(ScopeMapIterator const &other) const noexcept { + return this->map == other.map && this->index == other.index; + } + + operator ScopeMapSlot *() const { + return map->slots+index; + } +}; + + +gb_internal ScopeMapIterator end(ScopeMap &m) noexcept { + return ScopeMapIterator{&m, m.cap}; +} +gb_internal ScopeMapIterator const end(ScopeMap const &m) noexcept { + return ScopeMapIterator{&m, m.cap}; +} +gb_internal ScopeMapIterator begin(ScopeMap &m) noexcept { + if (m.count == 0) { + return end(m); + } + + u32 index = 0; + while (index < m.cap) { + if (m.slots[index].hash) { + break; + } + index++; + } + return ScopeMapIterator{&m, index}; +} +gb_internal ScopeMapIterator const begin(ScopeMap const &m) noexcept { + if (m.count == 0) { + return end(m); + } + + u32 index = 0; + while (index < m.cap) { + if (m.slots[index].hash) { + break; + } + index++; + } + return ScopeMapIterator{&m, index}; +} enum ScopeFlag : i32 { ScopeFlag_Pkg = 1<<1, @@ -280,7 +539,6 @@ enum ScopeFlag : i32 { ScopeFlag_ContextDefined = 1<<16, }; -enum { DEFAULT_SCOPE_CAPACITY = 32 }; struct Scope { Ast * node; @@ -291,7 +549,7 @@ struct Scope { i32 index; // within a procedure RwMutex mutex; - StringMap elements; + ScopeMap elements; PtrSet imported; DeclInfo *decl_info; @@ -624,13 +882,13 @@ gb_internal isize type_info_index (CheckerInfo *info, TypeInfoPair gb_internal Entity *entity_of_node(Ast *expr); -gb_internal Entity *scope_lookup_current(Scope *s, String const &name); -gb_internal Entity *scope_lookup (Scope *s, String const &name, u32 hash=0); -gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_, u32 hash=0); +// gb_internal Entity *scope_lookup_current(Scope *s, String const &name, u32 hash=0); +gb_internal Entity *scope_lookup (Scope *s, InternedString interned, u32 hash); +gb_internal void scope_lookup_parent (Scope *s, InternedString name, Scope **scope_, Entity **entity_, u32 hash); gb_internal Entity *scope_insert (Scope *s, Entity *entity); -gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue const &value, bool use_mutex=true); +gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue const &value); gb_internal ExprInfo *check_get_expr_info (CheckerContext *c, Ast *expr); gb_internal void add_untyped (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue const &value); gb_internal void add_entity_use (CheckerContext *c, Ast *identifier, Entity *entity); @@ -651,8 +909,8 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice const &n gb_internal void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws); gb_internal void check_delayed_file_import_entity(CheckerContext *c, Ast *decl); -gb_internal CheckerTypePath *new_checker_type_path(gbAllocator allocator); -gb_internal void destroy_checker_type_path(CheckerTypePath *tp, gbAllocator allocator); +gb_internal CheckerTypePath *new_checker_type_path(); +gb_internal void destroy_checker_type_path(CheckerTypePath *tp); gb_internal void check_type_path_push(CheckerContext *c, Entity *e); gb_internal Entity *check_type_path_pop (CheckerContext *c); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 5b446cc1c..f73422932 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -74,6 +74,8 @@ enum BuiltinProcId { BuiltinProc_count_zeros, BuiltinProc_count_trailing_zeros, BuiltinProc_count_leading_zeros, + BuiltinProc_count_trailing_ones, + BuiltinProc_count_leading_ones, BuiltinProc_reverse_bits, BuiltinProc_byte_swap, @@ -142,6 +144,8 @@ BuiltinProc__atomic_end, BuiltinProc_fixed_point_div_sat, BuiltinProc_expect, + BuiltinProc_likely, + BuiltinProc_unlikely, BuiltinProc__simd_begin, BuiltinProc_simd_add, @@ -295,6 +299,7 @@ BuiltinProc__type_simple_boolean_begin, BuiltinProc_type_is_simd_vector, BuiltinProc_type_is_matrix, BuiltinProc_type_is_raw_union, + BuiltinProc_type_is_fixed_capacity_dynamic_array, BuiltinProc_type_is_specialized_polymorphic_record, @@ -340,6 +345,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_field_index_of, + BuiltinProc_type_fixed_capacity_dynamic_array_len_offset, + BuiltinProc_type_bit_set_backing_type, BuiltinProc_type_enum_is_contiguous, @@ -453,6 +460,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("count_zeros"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("count_trailing_zeros"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("count_leading_zeros"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("count_trailing_ones"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("count_leading_ones"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("reverse_bits"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("byte_swap"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -520,7 +529,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("fixed_point_mul_sat"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("fixed_point_div_sat"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("expect"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("expect"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("likely"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("unlikely"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -670,6 +681,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_simd_vector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_matrix"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_raw_union"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_fixed_capacity_dynamic_array"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_specialized_polymorphic_record"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_unspecialized_polymorphic_record"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -713,6 +725,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_field_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_fixed_capacity_dynamic_array_len_offset"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_bit_set_backing_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_enum_is_contiguous"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics }, diff --git a/src/common.cpp b/src/common.cpp index d5fc1df4b..86ebb0fa8 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -366,6 +366,7 @@ gb_global bool global_module_path_set = false; #include "string_set.cpp" #include "priority_queue.cpp" #include "thread_pool.cpp" +#include "string_interner.cpp" gb_internal String obfuscate_string(String const &s, char const *prefix) { @@ -388,48 +389,6 @@ gb_internal i32 obfuscate_i32(i32 i) { } - -struct StringIntern { - StringIntern *next; - isize len; - char str[1]; -}; - -PtrMap string_intern_map = {}; // Key: u64 -gb_global Arena string_intern_arena = {}; - -gb_internal char const *string_intern(char const *text, isize len) { - u64 hash = gb_fnv64a(text, len); - uintptr key = cast(uintptr)(hash ? hash : 1); - StringIntern **found = map_get(&string_intern_map, key); - if (found) { - for (StringIntern *it = *found; it != nullptr; it = it->next) { - if (it->len == len && gb_strncmp(it->str, (char *)text, len) == 0) { - return it->str; - } - } - } - - StringIntern *new_intern = cast(StringIntern *)arena_alloc(&string_intern_arena, gb_offset_of(StringIntern, str) + len + 1, gb_align_of(StringIntern)); - new_intern->len = len; - new_intern->next = found ? *found : nullptr; - gb_memmove(new_intern->str, text, len); - new_intern->str[len] = 0; - map_set(&string_intern_map, key, new_intern); - return new_intern->str; -} - -gb_internal char const *string_intern(String const &string) { - return string_intern(cast(char const *)string.text, string.len); -} - -gb_internal void init_string_interner(void) { - map_init(&string_intern_map); -} - - - - gb_internal i32 next_pow2(i32 n) { if (n <= 0) { return 0; diff --git a/src/common_memory.cpp b/src/common_memory.cpp index addd43687..1590aac65 100644 --- a/src/common_memory.cpp +++ b/src/common_memory.cpp @@ -40,6 +40,7 @@ struct MemoryBlock { u8 * base; isize size; isize used; + isize committed; }; struct Arena { @@ -48,13 +49,14 @@ struct Arena { // BlockingMutex mutex; isize temp_count; Thread * parent_thread; + bool custom_arena; }; enum { DEFAULT_MINIMUM_BLOCK_SIZE = 8ll*1024ll*1024ll }; gb_global isize DEFAULT_PAGE_SIZE = 4096; -gb_internal MemoryBlock *virtual_memory_alloc(isize size); +gb_internal MemoryBlock *virtual_memory_alloc(isize size, bool commit); gb_internal void virtual_memory_dealloc(MemoryBlock *block); gb_internal void *arena_alloc(Arena *arena, isize min_size, isize alignment); gb_internal void arena_free_all(Arena *arena); @@ -82,7 +84,7 @@ gb_internal void thread_init_arenas(Thread *t) { gb_internal void *arena_alloc(Arena *arena, isize min_size, isize alignment) { GB_ASSERT(gb_is_power_of_two(alignment)); - GB_ASSERT(arena->parent_thread == get_current_thread()); + GB_ASSERT(arena->custom_arena || arena->parent_thread == get_current_thread()); isize size = 0; if (arena->curr_block != nullptr) { @@ -95,7 +97,7 @@ gb_internal void *arena_alloc(Arena *arena, isize min_size, isize alignment) { isize block_size = gb_max(size, arena->minimum_block_size); - MemoryBlock *new_block = virtual_memory_alloc(block_size); + MemoryBlock *new_block = virtual_memory_alloc(block_size, true); new_block->prev = arena->curr_block; arena->curr_block = new_block; } @@ -113,6 +115,62 @@ gb_internal void *arena_alloc(Arena *arena, isize min_size, isize alignment) { return ptr; } +gb_internal void *platform_virtual_memory_alloc_internal(isize total_size, bool commit); +gb_internal bool platform_virtual_memory_commit_internal(void *data, isize commit_amount); + +struct StaticArena { + u8 * data; + isize used; + isize committed; + isize reserved; + isize commit_block_size; +}; + +enum {STATIC_ARENA_DEFAULT_COMMIT_BLOCK_SIZE = 8<<20}; + +gb_internal void static_arena_init(StaticArena *arena, isize reserve_size, isize commit_block_size) { + GB_ASSERT(gb_is_power_of_two(reserve_size)); + GB_ASSERT(gb_is_power_of_two(commit_block_size)); + GB_ASSERT(commit_block_size <= reserve_size); + arena->data = cast(u8 *)platform_virtual_memory_alloc_internal(reserve_size, false); + arena->reserved = reserve_size; + arena->commit_block_size = commit_block_size; +} + +gb_internal void static_arena_commit_memory(StaticArena *arena, isize amount) { + isize blocks = (amount + arena->commit_block_size-1)/arena->commit_block_size; + isize total_amount = blocks * arena->commit_block_size; + + if (total_amount > arena->reserved - arena->committed) { + total_amount = arena->reserved - arena->committed; + } + + platform_virtual_memory_commit_internal(arena->data + arena->committed, total_amount); + arena->committed += total_amount; +} + +gb_internal void *static_arena_alloc(StaticArena *arena, isize size, isize alignment) { + GB_ASSERT(gb_is_power_of_two(alignment)); + + size = align_formula_isize(size, alignment); + + u8 *curr = arena->data + arena->used; + curr = cast(u8 *)align_formula_ptr(curr, alignment); + + u8 *end = curr + size; + if (end-arena->data > arena->committed) { + isize needed = (end - arena->data) - arena->committed; + static_arena_commit_memory(arena, needed); + } + GB_ASSERT_MSG(end-arena->data <= arena->committed, "out of memory for the static arena"); + + arena->used = end - arena->data; + + return curr; +} + + + template gb_internal T *arena_alloc_item(Arena *arena) { @@ -138,10 +196,13 @@ struct PlatformMemoryBlock { gb_global std::atomic global_platform_memory_total_usage; gb_global PlatformMemoryBlock global_platform_memory_block_sentinel; -gb_internal PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size); +gb_internal PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size, bool commit); gb_internal void platform_virtual_memory_free(PlatformMemoryBlock *block); gb_internal void platform_virtual_memory_protect(void *memory, isize size); +gb_internal void *platform_virtual_memory_alloc_internal(isize total_size, bool commit); +gb_internal bool platform_virtual_memory_commit_internal(void *data, isize commit_amount); + #if defined(GB_SYSTEM_WINDOWS) gb_internal void platform_virtual_memory_init(void) { global_platform_memory_block_sentinel.prev = &global_platform_memory_block_sentinel; @@ -153,14 +214,20 @@ gb_internal void platform_virtual_memory_protect(void *memory, isize size); GB_ASSERT(gb_is_power_of_two(DEFAULT_PAGE_SIZE)); } - gb_internal PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size) { - PlatformMemoryBlock *pmblock = (PlatformMemoryBlock *)VirtualAlloc(0, total_size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); - if (pmblock == nullptr) { + gb_internal void *platform_virtual_memory_alloc_internal(isize total_size, bool commit) { + DWORD flags = commit ? MEM_RESERVE|MEM_COMMIT : MEM_RESERVE; + void *mem = VirtualAlloc(0, total_size, flags, PAGE_READWRITE); + if (mem == nullptr) { gb_printf_err("Out of Virtual memory, oh no...\n"); gb_printf_err("Requested: %lld bytes\n", cast(long long)total_size); gb_printf_err("Total Usage: %lld bytes\n", cast(long long)global_platform_memory_total_usage); - GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no..."); + GB_ASSERT_MSG(mem != nullptr, "Out of Virtual Memory, oh no..."); } + return mem; + } + + gb_internal PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size, bool commit) { + PlatformMemoryBlock *pmblock = cast(PlatformMemoryBlock *)platform_virtual_memory_alloc_internal(total_size, commit); global_platform_memory_total_usage.fetch_add(total_size); return pmblock; } @@ -173,6 +240,16 @@ gb_internal void platform_virtual_memory_protect(void *memory, isize size); BOOL is_protected = VirtualProtect(memory, size, PAGE_NOACCESS, &old_protect); GB_ASSERT(is_protected); } + + gb_internal bool platform_virtual_memory_commit_internal(void *data, isize commit_amount) { + void *res = VirtualAlloc(data, commit_amount, MEM_COMMIT, PAGE_READWRITE); + if (res == nullptr) { + GB_PANIC("Out of Virtual Memory, oh no...\n"); + GB_ASSERT_MSG(res != nullptr, "Out of Virtual Memory, oh no..."); + return false; + } + return true; + } #else #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) #define MAP_ANONYMOUS MAP_ANON @@ -185,9 +262,20 @@ gb_internal void platform_virtual_memory_protect(void *memory, isize size); DEFAULT_PAGE_SIZE = gb_max(DEFAULT_PAGE_SIZE, cast(isize)sysconf(_SC_PAGE_SIZE)); GB_ASSERT(gb_is_power_of_two(DEFAULT_PAGE_SIZE)); } + + gb_internal void *platform_virtual_memory_alloc_internal(isize total_size, bool commit) { + void *mem = mmap(nullptr, total_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (mem == nullptr) { + gb_printf_err("Out of Virtual memory, oh no...\n"); + gb_printf_err("Requested: %lld bytes\n", cast(long long)total_size); + gb_printf_err("Total Usage: %lld bytes\n", cast(long long)global_platform_memory_total_usage); + GB_ASSERT_MSG(mem != nullptr, "Out of Virtual Memory, oh no..."); + } + return mem; + } - gb_internal PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size) { - PlatformMemoryBlock *pmblock = (PlatformMemoryBlock *)mmap(nullptr, total_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + gb_internal PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size, bool commit) { + PlatformMemoryBlock *pmblock = cast(PlatformMemoryBlock *)platform_virtual_memory_alloc_internal(total_size, commit); if (pmblock == nullptr) { gb_printf_err("Out of Virtual memory, oh no...\n"); gb_printf_err("Requested: %lld bytes\n", cast(long long)total_size); @@ -197,6 +285,9 @@ gb_internal void platform_virtual_memory_protect(void *memory, isize size); global_platform_memory_total_usage.fetch_add(total_size); return pmblock; } + gb_internal PlatformMemoryBlock *platform_virtual_memory_alloc_uncommited(isize total_size) { + return platform_virtual_memory_alloc(total_size, false); + } gb_internal void platform_virtual_memory_free(PlatformMemoryBlock *block) { isize size = block->total_size; global_platform_memory_total_usage.fetch_sub(size); @@ -206,9 +297,19 @@ gb_internal void platform_virtual_memory_protect(void *memory, isize size); int err = mprotect(memory, size, PROT_NONE); GB_ASSERT(err == 0); } + + gb_internal bool platform_virtual_memory_commit_internal(void *data, isize commit_amount) { + int err = mprotect(data, commit_amount, PROT_READ | PROT_WRITE); + if (err != 0) { + GB_PANIC("Out of Virtual Memory, oh no...\n"); + GB_ASSERT_MSG(err == 0, "Out of Virtual Memory, oh no..."); + return false; + } + return true; + } #endif -gb_internal MemoryBlock *virtual_memory_alloc(isize size) { +gb_internal MemoryBlock *virtual_memory_alloc(isize size, bool commit) { isize const page_size = DEFAULT_PAGE_SIZE; isize total_size = size + gb_size_of(PlatformMemoryBlock); @@ -224,7 +325,7 @@ gb_internal MemoryBlock *virtual_memory_alloc(isize size) { do_protection = true; } - PlatformMemoryBlock *pmblock = platform_virtual_memory_alloc(total_size); + PlatformMemoryBlock *pmblock = platform_virtual_memory_alloc(total_size, commit); GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no..."); pmblock->block.base = cast(u8 *)pmblock + base_offset; diff --git a/src/docs_format.cpp b/src/docs_format.cpp index 2235789d5..30dcf40b9 100644 --- a/src/docs_format.cpp +++ b/src/docs_format.cpp @@ -15,7 +15,7 @@ struct OdinDocVersionType { #define OdinDocVersionType_Major 0 #define OdinDocVersionType_Minor 3 -#define OdinDocVersionType_Patch 1 +#define OdinDocVersionType_Patch 2 struct OdinDocHeaderBase { u8 magic[8]; @@ -59,31 +59,31 @@ struct OdinDocPosition { }; enum OdinDocTypeKind : u32 { - OdinDocType_Invalid = 0, - OdinDocType_Basic = 1, - OdinDocType_Named = 2, - OdinDocType_Generic = 3, - OdinDocType_Pointer = 4, - OdinDocType_Array = 5, - OdinDocType_EnumeratedArray = 6, - OdinDocType_Slice = 7, - OdinDocType_DynamicArray = 8, - OdinDocType_Map = 9, - OdinDocType_Struct = 10, - OdinDocType_Union = 11, - OdinDocType_Enum = 12, - OdinDocType_Tuple = 13, - OdinDocType_Proc = 14, - OdinDocType_BitSet = 15, - OdinDocType_SimdVector = 16, - OdinDocType_SOAStructFixed = 17, - OdinDocType_SOAStructSlice = 18, - OdinDocType_SOAStructDynamic = 19, - - OdinDocType_MultiPointer = 22, - OdinDocType_Matrix = 23, - OdinDocType_SoaPointer = 24, - OdinDocType_BitField = 25, + OdinDocType_Invalid = 0, + OdinDocType_Basic = 1, + OdinDocType_Named = 2, + OdinDocType_Generic = 3, + OdinDocType_Pointer = 4, + OdinDocType_Array = 5, + OdinDocType_EnumeratedArray = 6, + OdinDocType_Slice = 7, + OdinDocType_DynamicArray = 8, + OdinDocType_Map = 9, + OdinDocType_Struct = 10, + OdinDocType_Union = 11, + OdinDocType_Enum = 12, + OdinDocType_Tuple = 13, + OdinDocType_Proc = 14, + OdinDocType_BitSet = 15, + OdinDocType_SimdVector = 16, + OdinDocType_SOAStructFixed = 17, + OdinDocType_SOAStructSlice = 18, + OdinDocType_SOAStructDynamic = 19, + OdinDocType_MultiPointer = 22, + OdinDocType_Matrix = 23, + OdinDocType_SoaPointer = 24, + OdinDocType_BitField = 25, + OdinDocType_FixedCapacityDynamicArray = 26, }; enum OdinDocTypeFlag_Basic : u32 { @@ -144,13 +144,14 @@ struct OdinDocType { OdinDocString custom_align; // Used by: - // .Array - 1 count: 0=len - // .Enumerated_Array - 1 count: 0=len - // .SOA_Struct_Fixed - 1 count: 0=len - // .Bit_Set - 2 count: 0=lower, 1=upper - // .Simd_Vector - 1 count: 0=len - // .Matrix - 2 count: 0=row_count, 1=column_count - // .Struct - <=2 count: 0=min_field_align, 1=max_field_align + // .Array - 1 count: 0=len + // .Enumerated_Array - 1 count: 0=len + // .SOA_Struct_Fixed - 1 count: 0=len + // .Bit_Set - 2 count: 0=lower, 1=upper + // .Simd_Vector - 1 count: 0=len + // .Matrix - 2 count: 0=row_count, 1=column_count + // .Struct - <=2 count: 0=min_field_align, 1=max_field_align + // .Fixed_Capacity_Dynamic_Array - 1 count: 0=cap u32 elem_count_len; i64 elem_counts[OdinDocType_ElemsCap]; @@ -159,27 +160,28 @@ struct OdinDocType { OdinDocString calling_convention; // Used by: - // .Named - 1 type: 0=base type - // .Generic - <1 type: 0=specialization - // .Pointer - 1 type: 0=element - // .Array - 1 type: 0=element - // .Enumerated_Array - 2 types: 0=index and 1=element - // .Slice - 1 type: 0=element - // .Dynamic_Array - 1 type: 0=element - // .Map - 2 types: 0=key, 1=value - // .SOA_Struct_Fixed - 1 type: underlying SOA struct element - // .SOA_Struct_Slice - 1 type: underlying SOA struct element - // .SOA_Struct_Dynamic - 1 type: underlying SOA struct element - // .Union - 0+ types: variants - // .Enum - <1 type: 0=base type - // .Proc - 2 types: 0=parameters, 1=results - // .Bit_Set - <=2 types: 0=element type, 1=underlying type (Underlying_Type flag will be set) - // .Simd_Vector - 1 type: 0=element - // .Relative_Pointer - 2 types: 0=pointer type, 1=base integer - // .Multi_Pointer - 1 type: 0=element - // .Matrix - 1 type: 0=element - // .Soa_Pointer - 1 type: 0=element - // .Bit_Field - 1 type: 0=backing type + // .Named - 1 type: 0=base type + // .Generic - <1 type: 0=specialization + // .Pointer - 1 type: 0=element + // .Array - 1 type: 0=element (and 1=generic index (if exists)) + // .Enumerated_Array - 2 types: 0=index and 1=element + // .Slice - 1 type: 0=element + // .Dynamic_Array - 1 type: 0=element + // .Map - 2 types: 0=key, 1=value + // .SOA_Struct_Fixed - 1 type: underlying SOA struct element + // .SOA_Struct_Slice - 1 type: underlying SOA struct element + // .SOA_Struct_Dynamic - 1 type: underlying SOA struct element + // .Union - 0+ types: variants + // .Enum - <1 type: 0=base type + // .Proc - 2 types: 0=parameters, 1=results + // .Bit_Set - <=2 types: 0=element type, 1=underlying type (Underlying_Type flag will be set) + // .Simd_Vector - 1 type: 0=element + // .Relative_Pointer - 2 types: 0=pointer type, 1=base integer + // .Multi_Pointer - 1 type: 0=element + // .Matrix - 1 type: 0=element + // .Soa_Pointer - 1 type: 0=element + // .Bit_Field - 1 type: 0=backing type + // .Fixed_Capacity_Dynamic_Array - 1 type: 0=element (and 1=generic index (if exists)) OdinDocArray types; // Used by: diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 3edd7da9d..a9f3a3e15 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -555,7 +555,14 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type, bool ca doc_type.kind = OdinDocType_Array; doc_type.elem_count_len = 1; doc_type.elem_counts[0] = type->Array.count; - doc_type.types = odin_doc_type_as_slice(w, type->Array.elem); + if (type->Array.generic_count != nullptr) { + OdinDocTypeIndex types[2] = {}; + types[0] = odin_doc_type(w, type->Array.elem); + types[1] = odin_doc_type(w, type->Array.generic_count); + doc_type.types = odin_write_slice(w, types, gb_count_of(types)); + } else { + doc_type.types = odin_doc_type_as_slice(w, type->Array.elem); + } break; case Type_EnumeratedArray: doc_type.kind = OdinDocType_EnumeratedArray; @@ -576,6 +583,20 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type, bool ca doc_type.kind = OdinDocType_DynamicArray; doc_type.types = odin_doc_type_as_slice(w, type->DynamicArray.elem); break; + case Type_FixedCapacityDynamicArray: + doc_type.kind = OdinDocType_FixedCapacityDynamicArray; + doc_type.elem_count_len = 1; + doc_type.elem_counts[0] = type->FixedCapacityDynamicArray.capacity; + + if (type->FixedCapacityDynamicArray.generic_capacity != nullptr) { + OdinDocTypeIndex types[2] = {}; + types[0] = odin_doc_type(w, type->FixedCapacityDynamicArray.elem); + types[1] = odin_doc_type(w, type->FixedCapacityDynamicArray.generic_capacity); + doc_type.types = odin_write_slice(w, types, gb_count_of(types)); + } else { + doc_type.types = odin_doc_type_as_slice(w, type->FixedCapacityDynamicArray.elem); + } + break; case Type_Map: doc_type.kind = OdinDocType_Map; { @@ -1021,9 +1042,12 @@ gb_internal OdinDocArray odin_doc_add_pkg_entries(OdinDocWrit auto entries = array_make(heap_allocator(), 0, w->entity_cache.count); defer (array_free(&entries)); - for (auto const &element : pkg->scope->elements) { - String name = element.key; - Entity *e = element.value; + for (isize i = 0; i < pkg->scope->elements.cap; i++) { + if (!pkg->scope->elements.slots[i].hash) { + continue; + } + auto interned = pkg->scope->elements.keys[i]; + Entity *e = pkg->scope->elements.slots[i].value; switch (e->kind) { case Entity_Invalid: case Entity_Nil: @@ -1051,7 +1075,7 @@ gb_internal OdinDocArray odin_doc_add_pkg_entries(OdinDocWrit } OdinDocScopeEntry entry = {}; - entry.name = odin_doc_write_string(w, name); + entry.name = odin_doc_write_string(w, interned.string()); entry.entity = odin_doc_add_entity(w, e); array_add(&entries, entry); } diff --git a/src/entity.cpp b/src/entity.cpp index 2b21fdcac..5062599de 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -141,7 +141,7 @@ enum ProcedureOptimizationMode : u8 { BlockingMutex global_type_name_objc_metadata_mutex; struct TypeNameObjCMetadataEntry { - String name; + InternedString interned; Entity *entity; }; struct TypeNameObjCMetadata { @@ -151,8 +151,8 @@ struct TypeNameObjCMetadata { }; gb_internal TypeNameObjCMetadata *create_type_name_obj_c_metadata() { - TypeNameObjCMetadata *md = gb_alloc_item(permanent_allocator(), TypeNameObjCMetadata); - md->mutex = gb_alloc_item(permanent_allocator(), BlockingMutex); + TypeNameObjCMetadata *md = permanent_alloc_item(); + md->mutex = permanent_alloc_item(); array_init(&md->type_entries, heap_allocator()); array_init(&md->value_entries, heap_allocator()); return md; @@ -169,8 +169,12 @@ struct Entity { Scope * scope; Type * type; std::atomic identifier; // Can be nullptr + + std::atomic interned_name; + std::atomic interned_name_hash; + DeclInfo * decl_info; - DeclInfo * parent_proc_decl; // nullptr if in file/global scope + std::atomic parent_proc_decl; // nullptr if in file/global scope AstFile * file; AstPackage *pkg; @@ -181,11 +185,11 @@ struct Entity { Entity * aliased_of; union { - struct lbModule *code_gen_module; + std::atomic code_gen_module; struct cgModule *cg_module; }; union { - struct lbProcedure *code_gen_procedure; + std::atomic code_gen_procedure; struct cgProcedure *cg_procedure; }; @@ -268,6 +272,7 @@ struct Entity { bool is_anonymous : 1; bool no_sanitize_address : 1; bool no_sanitize_memory : 1; + bool no_sanitize_thread : 1; bool is_objc_impl_or_import : 1; bool is_objc_class_method : 1; } Procedure; @@ -299,6 +304,16 @@ struct Entity { }; }; +gb_internal InternedString entity_interned_name(Entity *entity) { + auto name = entity->interned_name.load(); + if (name.value == 0) { + name = string_interner_insert(entity->token.string); + entity->interned_name.store(name); + entity->interned_name_hash.store(name.hash()); + } + return name; +} + gb_internal bool is_entity_kind_exported(EntityKind kind, bool allow_builtin = false) { switch (kind) { case Entity_Builtin: @@ -343,18 +358,24 @@ gb_internal bool entity_has_deferred_procedure(Entity *e) { gb_global std::atomic global_entity_id; +// NOTE(bill): This exists to allow for bulk allocations of entities all at once to improve performance for type generation +#define INTERNAL_ENTITY_INIT(e_, kind_, scope_, token_, type_) do { \ + (e_)->kind = (kind_); \ + (e_)->state = EntityState_Unresolved; \ + (e_)->scope = (scope_); \ + (e_)->token = (token_); \ + (e_)->type = (type_); \ + (e_)->id = 1 + global_entity_id.fetch_add(1); \ + if ((token_).pos.file_id) { \ + e_->file = thread_unsafe_get_ast_file_from_id((token_).pos.file_id); \ + } \ +} while (0) + + gb_internal Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Type *type) { - gbAllocator a = permanent_allocator(); - Entity *entity = gb_alloc_item(a, Entity); - entity->kind = kind; - entity->state = EntityState_Unresolved; - entity->scope = scope; - entity->token = token; - entity->type = type; - entity->id = 1 + global_entity_id.fetch_add(1); - if (token.pos.file_id) { - entity->file = thread_unsafe_get_ast_file_from_id(token.pos.file_id); - } + Entity *entity = permanent_alloc_item(); + INTERNAL_ENTITY_INIT(entity, kind, scope, token, type); + entity_interned_name(entity); return entity; } @@ -369,7 +390,7 @@ gb_internal Entity *alloc_entity_using_variable(Entity *parent, Token token, Typ token.pos = parent->token.pos; Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type); entity->using_parent = parent; - entity->parent_proc_decl = parent->parent_proc_decl; + entity->parent_proc_decl.store(parent->parent_proc_decl, std::memory_order_relaxed); entity->using_expr = using_expr; entity->flags |= EntityFlag_Using; entity->flags |= EntityFlag_Used; @@ -391,10 +412,9 @@ gb_internal Entity *alloc_entity_type_name(Scope *scope, Token token, Type *type } gb_internal Entity *alloc_entity_param(Scope *scope, Token token, Type *type, bool is_using, bool is_value) { - Entity *entity = alloc_entity_variable(scope, token, type); + Entity *entity = alloc_entity_variable(scope, token, type, EntityState_Resolved); entity->flags |= EntityFlag_Used; entity->flags |= EntityFlag_Param; - entity->state = EntityState_Resolved; if (is_using) entity->flags |= EntityFlag_Using; if (is_value) entity->flags |= EntityFlag_Value; return entity; @@ -411,11 +431,10 @@ gb_internal Entity *alloc_entity_const_param(Scope *scope, Token token, Type *ty gb_internal Entity *alloc_entity_field(Scope *scope, Token token, Type *type, bool is_using, i32 field_index, EntityState state = EntityState_Unresolved) { - Entity *entity = alloc_entity_variable(scope, token, type); + Entity *entity = alloc_entity_variable(scope, token, type, state); entity->Variable.field_index = field_index; if (is_using) entity->flags |= EntityFlag_Using; entity->flags |= EntityFlag_Field; - entity->state = state; return entity; } diff --git a/src/exact_value.cpp b/src/exact_value.cpp index e7077bd5b..525b8cb91 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -1,8 +1,6 @@ #include #include -gb_global BlockingMutex hash_exact_value_mutex; - struct Ast; struct HashKey; struct Type; @@ -54,9 +52,6 @@ struct ExactValue { gb_global ExactValue const empty_exact_value = {}; gb_internal uintptr hash_exact_value(ExactValue v) { - mutex_lock(&hash_exact_value_mutex); - defer (mutex_unlock(&hash_exact_value_mutex)); - uintptr res = 0; switch (v.kind) { @@ -151,7 +146,7 @@ gb_internal ExactValue exact_value_float(f64 f) { gb_internal ExactValue exact_value_complex(f64 real, f64 imag) { ExactValue result = {ExactValue_Complex}; - result.value_complex = gb_alloc_item(permanent_allocator(), Complex128); + result.value_complex = permanent_alloc_item(); result.value_complex->real = real; result.value_complex->imag = imag; return result; @@ -159,7 +154,7 @@ gb_internal ExactValue exact_value_complex(f64 real, f64 imag) { gb_internal ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) { ExactValue result = {ExactValue_Quaternion}; - result.value_quaternion = gb_alloc_item(permanent_allocator(), Quaternion256); + result.value_quaternion = permanent_alloc_item(); result.value_quaternion->real = real; result.value_quaternion->imag = imag; result.value_quaternion->jmag = jmag; @@ -443,7 +438,7 @@ gb_internal ExactValue exact_value_to_complex(ExactValue v) { // return exact_value_complex(v.value_quaternion.real, v.value_quaternion.imag); } ExactValue r = {ExactValue_Invalid}; - v.value_complex = gb_alloc_item(permanent_allocator(), Complex128); + v.value_complex = permanent_alloc_item(); return r; } gb_internal ExactValue exact_value_to_quaternion(ExactValue v) { @@ -458,7 +453,7 @@ gb_internal ExactValue exact_value_to_quaternion(ExactValue v) { return v; } ExactValue r = {ExactValue_Invalid}; - v.value_quaternion = gb_alloc_item(permanent_allocator(), Quaternion256); + v.value_quaternion = permanent_alloc_item(); return r; } @@ -947,6 +942,8 @@ gb_internal gb_inline i32 cmp_f64(f64 a, f64 b) { return (a > b) - (a < b); } +gb_internal bool compare_exact_values_compound_lit(TokenKind op, ExactValue x, ExactValue y); + gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) { match_exact_values(&x, &y); @@ -1055,9 +1052,19 @@ gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) case Token_NotEq: return x.value_typeid != y.value_typeid; } break; + + case ExactValue_Compound: + if (op != Token_CmpEq && op != Token_NotEq) { + return false; + } + + if (x.kind != y.kind) { + return false; + } + return compare_exact_values_compound_lit(op, x, y); } - GB_PANIC("Invalid comparison"); + GB_PANIC("Invalid comparison: %d", x.kind); return false; } diff --git a/src/gb/gb.h b/src/gb/gb.h index c52f63cec..3c88ce6ed 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -2522,6 +2522,7 @@ void gb_assert_handler(char const *prefix, char const *condition, char const *fi va_end(va); } gb_printf_err("\n"); + gb_printf_err("This is a compiler error. Please report this.\n"); } b32 gb_is_power_of_two(isize x) { diff --git a/src/linker.cpp b/src/linker.cpp index c2a3ee928..02bfe1146 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -174,14 +174,14 @@ try_cross_linking:; switch (build_context.linker_choice) { case Linker_Default: break; case Linker_lld: section_name = str_lit("lld-link"); break; - #if defined(GB_SYSTEM_LINUX) + #if defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_NETBSD) case Linker_mold: section_name = str_lit("mold-link"); break; #endif #if defined(GB_SYSTEM_WINDOWS) case Linker_radlink: section_name = str_lit("rad-link"); break; #endif default: - gb_printf_err("'%.*s' linker is not support for this platform\n", LIT(linker_choices[build_context.linker_choice])); + gb_printf_err("'%.*s' linker is not supported on this platform\n", LIT(linker_choices[build_context.linker_choice])); return 1; } @@ -328,6 +328,12 @@ try_cross_linking:; String windows_sdk_bin_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Win_SDK_Bin_Path]); defer (gb_free(heap_allocator(), windows_sdk_bin_path.text)); + gbString lld_lto_flags = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(lld_lto_flags)); + if (build_context.lto_kind != LTO_None) { + lld_lto_flags = gb_string_append_fmt(lld_lto_flags, "/opt:lldltojobs=%d ", build_context.thread_count); + } + switch (build_context.linker_choice) { case Linker_lld: result = system_exec_command_line_app("msvc-lld-link", @@ -336,13 +342,15 @@ try_cross_linking:; "%.*s " "%.*s " "%s " + "%s " "", LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename), link_settings, LIT(windows_subsystem_names[build_context.ODIN_WINDOWS_SUBSYSTEM]), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags), - lib_str + lib_str, + lld_lto_flags ); if (result) { @@ -668,7 +676,7 @@ try_cross_linking:; defer (gb_string_free(glue)); glue = gb_string_append_fmt(glue, "bin/clang"); - glue = gb_string_append_fmt(glue, " --target=aarch64-linux-android%d ", ODIN_ANDROID_API_LEVEL); + glue = gb_string_append_fmt(glue, " --target=%.*s%d ", LIT(build_context.metrics.target_triplet), ODIN_ANDROID_API_LEVEL); glue = gb_string_appendc(glue, "-c \""); glue = gb_string_append_length(glue, ODIN_ANDROID_NDK.text, ODIN_ANDROID_NDK.len); glue = gb_string_appendc(glue, "sources/android/native_app_glue/android_native_app_glue.c"); @@ -689,8 +697,9 @@ try_cross_linking:; glue = gb_string_appendc(glue, "\"-I"); glue = gb_string_append_length(glue, ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len); - glue = gb_string_appendc(glue, "sysroot/usr/include/aarch64-linux-android/"); - glue = gb_string_appendc(glue, "\" "); + glue = gb_string_appendc(glue, "sysroot/usr/include/"); + glue = gb_string_append_length(glue, ODIN_ANDROID_NDK_TOOLCHAIN_LIB.text, ODIN_ANDROID_NDK_TOOLCHAIN_LIB.len); + glue = gb_string_appendc(glue, "/\" "); glue = gb_string_appendc(glue, "-Wno-macro-redefined "); @@ -722,12 +731,12 @@ try_cross_linking:; return result; } - object_files = gb_string_append_fmt(object_files, "\'%.*s\' ", LIT(android_glue_static_lib)); + object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(android_glue_static_lib)); } for (String object_path : gen->output_object_paths) { - object_files = gb_string_append_fmt(object_files, "\'%.*s\' ", LIT(object_path)); + object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); } gbString link_settings = gb_string_make_reserve(heap_allocator(), 32); @@ -737,7 +746,21 @@ try_cross_linking:; } if (build_context.build_mode == BuildMode_StaticLibrary) { - compiler_error("TODO(bill): -build-mode:static on non-windows targets"); + TIME_SECTION("Static Library Creation"); + + gbString ar_command = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(ar_command)); + + ar_command = gb_string_appendc(ar_command, "ar rcs "); + ar_command = gb_string_append_fmt(ar_command, "\"%.*s\" ", LIT(output_filename)); + ar_command = gb_string_appendc(ar_command, object_files); + + result = system_exec_command_line_app("ar", ar_command); + if (result) { + return result; + } + + return result; } // NOTE(dweiler): We use clang as a frontend for the linker as there are @@ -902,7 +925,10 @@ try_cross_linking:; GB_ASSERT(ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT.len != 0); platform_lib_str = gb_string_appendc(platform_lib_str, "\"-L"); - platform_lib_str = gb_string_append_length(platform_lib_str, ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL.text, ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL.len); + platform_lib_str = gb_string_append_length(platform_lib_str, ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT.text, ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT.len); + platform_lib_str = gb_string_appendc(platform_lib_str, "usr/lib/"); + platform_lib_str = gb_string_append_length(platform_lib_str, ODIN_ANDROID_NDK_TOOLCHAIN_LIB.text, ODIN_ANDROID_NDK_TOOLCHAIN_LIB.len); + platform_lib_str = gb_string_append_fmt(platform_lib_str, "/%d", ODIN_ANDROID_API_LEVEL); platform_lib_str = gb_string_appendc(platform_lib_str, "\" "); platform_lib_str = gb_string_appendc(platform_lib_str, "-landroid "); @@ -947,11 +973,25 @@ try_cross_linking:; gbString ndk_bin_directory = gb_string_make_length(temporary_allocator(), ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len); link_command_line = gb_string_appendc(link_command_line, ndk_bin_directory); link_command_line = gb_string_appendc(link_command_line, "bin/clang"); - link_command_line = gb_string_append_fmt(link_command_line, " --target=aarch64-linux-android%d ", ODIN_ANDROID_API_LEVEL); + link_command_line = gb_string_append_fmt(link_command_line, " --target=%.*s%d ", LIT(build_context.metrics.target_triplet), ODIN_ANDROID_API_LEVEL); } else { link_command_line = gb_string_appendc(link_command_line, clang_path); } link_command_line = gb_string_appendc(link_command_line, " -Wno-unused-command-line-argument "); + + if (build_context.lto_kind != LTO_None) { + link_command_line = gb_string_appendc(link_command_line, " -flto=thin"); + link_command_line = gb_string_append_fmt(link_command_line, " -flto-jobs=%d ", build_context.thread_count); + + if (build_context.ODIN_DEBUG) { + link_command_line = gb_string_appendc(link_command_line, " -g "); + } + + if (is_osx && !build_context.minimum_os_version_string_given) { + link_command_line = gb_string_appendc(link_command_line, " -Wno-override-module "); + } + } + link_command_line = gb_string_appendc(link_command_line, object_files); link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s\" ", LIT(output_filename)); link_command_line = gb_string_append_fmt(link_command_line, " %s ", platform_lib_str); diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index ec7c63b1a..6aabe456f 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -389,7 +389,7 @@ namespace lbAbi386 { gb_internal LB_ABI_INFO(abi_info) { LLVMContextRef c = m->ctx; - lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); + lbFunctionType *ft = permanent_alloc_item(); ft->ctx = c; ft->args = compute_arg_types(c, arg_types, arg_count); ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple); @@ -471,7 +471,7 @@ namespace lbAbiAmd64Win64 { gb_internal LB_ABI_INFO(abi_info) { LLVMContextRef c = m->ctx; - lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); + lbFunctionType *ft = permanent_alloc_item(); ft->ctx = c; ft->args = compute_arg_types(c, arg_types, arg_count); ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple); @@ -617,7 +617,7 @@ namespace lbAbiAmd64SysV { gb_internal LB_ABI_INFO(abi_info) { LLVMContextRef c = m->ctx; - lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); + lbFunctionType *ft = permanent_alloc_item(); ft->ctx = c; ft->calling_convention = calling_convention; @@ -1128,7 +1128,7 @@ namespace lbAbiArm64 { gb_internal LB_ABI_INFO(abi_info) { LLVMContextRef c = m->ctx; - lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); + lbFunctionType *ft = permanent_alloc_item(); ft->ctx = c; ft->args = compute_arg_types(c, arg_types, arg_count); ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple); @@ -1349,7 +1349,7 @@ namespace lbAbiWasm { gb_internal LB_ABI_INFO(abi_info) { LLVMContextRef c = m->ctx; - lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); + lbFunctionType *ft = permanent_alloc_item(); ft->ctx = c; ft->calling_convention = calling_convention; ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention, original_type); @@ -1558,7 +1558,7 @@ namespace lbAbiArm32 { gb_internal LB_ABI_INFO(abi_info) { LLVMContextRef c = m->ctx; - lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); + lbFunctionType *ft = permanent_alloc_item(); ft->ctx = c; ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention); ft->ret = compute_return_type(c, return_type, return_is_defined); @@ -1867,7 +1867,7 @@ namespace lbAbiRiscv64 { } gb_internal LB_ABI_INFO(abi_info) { - lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); + lbFunctionType *ft = permanent_alloc_item(); ft->ctx = m->ctx; ft->calling_convention = calling_convention; @@ -1889,7 +1889,7 @@ gb_internal LB_ABI_INFO(lb_get_abi_info_internal) { case ProcCC_None: case ProcCC_InlineAsm: { - lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); + lbFunctionType *ft = permanent_alloc_item(); ft->ctx = c; ft->args = array_make(lb_function_type_args_allocator(), arg_count); for (unsigned i = 0; i < arg_count; i++) { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 71bca42ab..b2246c90e 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -15,6 +15,8 @@ #define LLVM_WEAK_MONOMORPHIZATION (USE_SEPARATE_MODULES && build_context.internal_weak_monomorphization) #endif +#define LLVM_SET_INTERNAL_WEAK_LINKAGE(value) LLVMSetLinkage(value, USE_SEPARATE_MODULES ? LLVMWeakAnyLinkage : LLVMInternalLinkage); + #include "llvm_backend.hpp" #include "llvm_abi.cpp" @@ -64,6 +66,19 @@ gb_internal String get_final_microarchitecture() { gb_internal String get_default_features() { BuildContext *bc = &build_context; + if (bc->microarch == str_lit("native")) { + String features = make_string_c(LLVMGetHostCPUFeatures()); + + // Update the features string so LLVM uses it later. + if (bc->target_features_string.len > 0) { + bc->target_features_string = concatenate3_strings(permanent_allocator(), features, str_lit(","), bc->target_features_string); + } else { + bc->target_features_string = features; + } + + return features; + } + int off = 0; for (int i = 0; i < bc->metrics.arch; i += 1) { off += target_microarch_counts[i]; @@ -169,16 +184,16 @@ gb_internal void lb_correct_entity_linkage(lbGenerator *gen) { LLVMValueRef other_global = nullptr; if (ec.e->kind == Entity_Variable) { other_global = LLVMGetNamedGlobal(ec.other_module->mod, ec.cname); - if (other_global) { - LLVMSetLinkage(other_global, LLVMWeakAnyLinkage); + if (other_global && (LLVMGetInitializer(other_global) != nullptr || LLVMIsExternallyInitialized(other_global))) { + LLVM_SET_INTERNAL_WEAK_LINKAGE(other_global); if (!ec.e->Variable.is_export && !ec.e->Variable.is_foreign) { LLVMSetVisibility(other_global, LLVMHiddenVisibility); } } } else if (ec.e->kind == Entity_Procedure) { other_global = LLVMGetNamedFunction(ec.other_module->mod, ec.cname); - if (other_global) { - LLVMSetLinkage(other_global, LLVMWeakAnyLinkage); + if (other_global && LLVMCountBasicBlocks(other_global) != 0) { + LLVM_SET_INTERNAL_WEAK_LINKAGE(other_global); if (!ec.e->Procedure.is_export && !ec.e->Procedure.is_foreign) { LLVMSetVisibility(other_global, LLVMHiddenVisibility); } @@ -237,9 +252,9 @@ gb_internal lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx gb_internal String lb_internal_gen_name_from_type(char const *prefix, Type *type) { gbString str = gb_string_make(permanent_allocator(), prefix); - u64 hash = type_hash_canonical_type(type); - str = gb_string_appendc(str, "-"); - str = gb_string_append_fmt(str, "%llu", cast(unsigned long long)hash); + str = gb_string_appendc(str, "$$"); + gbString ct = temp_canonical_string(type); + str = gb_string_append_length(str, ct, gb_string_length(ct)); String proc_name = make_string(cast(u8 const *)str, gb_string_length(str)); return proc_name; } @@ -2043,6 +2058,11 @@ gb_internal bool lb_init_global_var(lbModule *m, lbProcedure *p, Entity *e, Ast lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr)); lb_emit_store(p, ti, lb_typeid(p->module, var_type)); } else { + i64 sz = type_size_of(e->type); + if (sz >= 4 * 1024) { + warning(init_expr, "[Possible Code Generation Issue] Non-constant initialization is large (%lld bytes), and might cause problems with LLVM", cast(long long)sz); + } + LLVMTypeRef vt = llvm_addr_type(p->module, var.var); lbValue src0 = lb_emit_conv(p, var.init, t); LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt); @@ -2083,7 +2103,7 @@ gb_internal void lb_create_startup_runtime_generate_body(lbModule *m, lbProcedur continue; } - if (type_size_of(e->type) > 8) { + if (false && type_size_of(e->type) > 8) { String ename = lb_get_entity_name(m, e); gbString name = gb_string_make(permanent_allocator(), ""); name = gb_string_appendc(name, "__$startup$"); @@ -2092,7 +2112,7 @@ gb_internal void lb_create_startup_runtime_generate_body(lbModule *m, lbProcedur lbProcedure *dummy = lb_create_dummy_procedure(m, make_string_c(name), dummy_type); dummy->is_startup = true; LLVMSetVisibility(dummy->value, LLVMHiddenVisibility); - LLVMSetLinkage(dummy->value, LLVMWeakAnyLinkage); + LLVM_SET_INTERNAL_WEAK_LINKAGE(p->value); lb_begin_procedure_body(dummy); lb_init_global_var(m, dummy, e, init_expr, var); @@ -2109,7 +2129,7 @@ gb_internal void lb_create_startup_runtime_generate_body(lbModule *m, lbProcedur for (Entity *e : info->init_procedures) { lbValue value = lb_find_procedure_value_from_entity(m, e); - lb_emit_call(p, value, {}, ProcInlining_none); + lb_emit_call(p, value, {}, ProcInlining_none, ProcTailing_none); } @@ -2127,7 +2147,7 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc // Make sure shared libraries call their own runtime startup on Linux. LLVMSetVisibility(p->value, LLVMHiddenVisibility); - LLVMSetLinkage(p->value, LLVMWeakAnyLinkage); + LLVM_SET_INTERNAL_WEAK_LINKAGE(p->value); p->global_variables = &global_variables; p->objc_names = objc_names; @@ -2147,7 +2167,7 @@ gb_internal lbProcedure *lb_create_cleanup_runtime(lbModule *main_module) { // C // Make sure shared libraries call their own runtime cleanup on Linux. LLVMSetVisibility(p->value, LLVMHiddenVisibility); - LLVMSetLinkage(p->value, LLVMWeakAnyLinkage); + LLVM_SET_INTERNAL_WEAK_LINKAGE(p->value); lb_begin_procedure_body(p); @@ -2155,7 +2175,7 @@ gb_internal lbProcedure *lb_create_cleanup_runtime(lbModule *main_module) { // C for (Entity *e : info->fini_procedures) { lbValue value = lb_find_procedure_value_from_entity(main_module, e); - lb_emit_call(p, value, {}, ProcInlining_none); + lb_emit_call(p, value, {}, ProcInlining_none, ProcTailing_none); } lb_end_procedure_body(p); @@ -2325,7 +2345,12 @@ gb_internal WORKER_TASK_PROC(lb_llvm_emit_worker_proc) { auto wd = cast(lbLLVMEmitWorker *)data; - if (LLVMTargetMachineEmitToFile(wd->target_machine, wd->m->mod, cast(char *)wd->filepath_obj.text, wd->code_gen_file_type, &llvm_error)) { + if (build_context.lto_kind != LTO_None) { + if (LLVMWriteBitcodeToFile(wd->m->mod, cast(char *)wd->filepath_obj.text)) { + gb_printf_err("Failed to write bitcode file: %.*s\n", LIT(wd->filepath_obj)); + exit_with_errors(); + } + } else if (LLVMTargetMachineEmitToFile(wd->target_machine, wd->m->mod, cast(char *)wd->filepath_obj.text, wd->code_gen_file_type, &llvm_error)) { gb_printf_err("LLVM Error: %s\n", llvm_error); exit_with_errors(); } @@ -2442,14 +2467,21 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) { // tsan - Linux, Darwin // ubsan - Linux, Darwin, Windows (NOT SUPPORTED WITH LLVM C-API) - if (build_context.sanitizer_flags & SanitizerFlag_Address) { - array_add(&passes, "asan"); - } - if (build_context.sanitizer_flags & SanitizerFlag_Memory) { - array_add(&passes, "msan"); - } - if (build_context.sanitizer_flags & SanitizerFlag_Thread) { - array_add(&passes, "tsan"); + // With LTO, sanitizer passes run at link time (via -fsanitize= linker flags) + // where the linker has whole-program visibility. Running them here too would + // double-instrument every module, producing "Redundant instrumentation" warnings. + // Per-function sanitize attributes in the bitcode are preserved and respected + // by the linker's sanitizer pass. + if (build_context.lto_kind == LTO_None) { + if (build_context.sanitizer_flags & SanitizerFlag_Address) { + array_add(&passes, "asan"); + } + if (build_context.sanitizer_flags & SanitizerFlag_Memory) { + array_add(&passes, "msan"); + } + if (build_context.sanitizer_flags & SanitizerFlag_Thread) { + array_add(&passes, "tsan"); + } } if (passes.count == 0) { @@ -2615,7 +2647,7 @@ gb_internal void lb_llvm_module_passes_and_verification(lbGenerator *gen, bool d if (do_threading) { for (auto const &entry : gen->modules) { lbModule *m = entry.value; - auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData); + auto wd = permanent_alloc_item(); wd->m = m; wd->target_machine = m->target_machine; wd->do_threading = true; @@ -2626,7 +2658,7 @@ gb_internal void lb_llvm_module_passes_and_verification(lbGenerator *gen, bool d } else { for (auto const &entry : gen->modules) { lbModule *m = entry.value; - auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData); + auto wd = permanent_alloc_item(); wd->m = m; wd->target_machine = m->target_machine; wd->do_threading = false; @@ -2694,7 +2726,9 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) { String ext = {}; - if (build_context.build_mode == BuildMode_Assembly) { + if (build_context.lto_kind != LTO_None) { + ext = STR_LIT("bc"); + } else if (build_context.build_mode == BuildMode_Assembly) { ext = STR_LIT("S"); } else if (build_context.build_mode == BuildMode_Object) { // Allow a user override for the object extension. @@ -2744,7 +2778,7 @@ gb_internal bool lb_llvm_object_generation(lbGenerator *gen, bool do_threading) array_add(&gen->output_object_paths, filepath_obj); array_add(&gen->output_temp_paths, filepath_ll); - auto *wd = gb_alloc_item(permanent_allocator(), lbLLVMEmitWorker); + auto *wd = permanent_alloc_item(); wd->target_machine = m->target_machine; wd->code_gen_file_type = code_gen_file_type; wd->filepath_obj = filepath_obj; @@ -2769,7 +2803,13 @@ gb_internal bool lb_llvm_object_generation(lbGenerator *gen, bool do_threading) TIME_SECTION_WITH_LEN(section_name, gb_string_length(section_name)); - if (LLVMTargetMachineEmitToFile(m->target_machine, m->mod, cast(char *)filepath_obj.text, code_gen_file_type, &llvm_error)) { + if (build_context.lto_kind != LTO_None) { + if (LLVMWriteBitcodeToFile(m->mod, cast(char *)filepath_obj.text)) { + gb_printf_err("Failed to write bitcode file: %.*s\n", LIT(filepath_obj)); + exit_with_errors(); + return false; + } + } else if (LLVMTargetMachineEmitToFile(m->target_machine, m->mod, cast(char *)filepath_obj.text, code_gen_file_type, &llvm_error)) { gb_printf_err("LLVM Error: %s\n", llvm_error); exit_with_errors(); return false; @@ -2848,7 +2888,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star } lbValue startup_runtime_value = {startup_runtime->value, startup_runtime->type}; - lb_emit_call(p, startup_runtime_value, {}, ProcInlining_none); + lb_emit_call(p, startup_runtime_value, {}, ProcInlining_none, ProcTailing_none); if (build_context.command_kind == Command_test) { Type *t_Internal_Test = find_type_in_pkg(m->info, str_lit("testing"), str_lit("Internal_Test")); @@ -2906,7 +2946,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star AstPackage *pkg = get_runtime_package(m->info); String name = str_lit("exit"); - Entity *e = scope_lookup_current(pkg->scope, name); + Entity *e = scope_lookup_current(pkg->scope, string_interner_insert(name)); if (e == nullptr) { compiler_error("Could not find type declaration for '%.*s.%.*s'\n", LIT(pkg->name), LIT(name)); } @@ -2915,16 +2955,16 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star auto exit_args = array_make(temporary_allocator(), 1); exit_args[0] = lb_emit_select(p, result, lb_const_int(m, t_int, 0), lb_const_int(m, t_int, 1)); - lb_emit_call(p, exit_runner, exit_args, ProcInlining_none); + lb_emit_call(p, exit_runner, exit_args, ProcInlining_none, ProcTailing_none); } else { if (m->info->entry_point != nullptr) { lbValue entry_point = lb_find_procedure_value_from_entity(m, m->info->entry_point); - lb_emit_call(p, entry_point, {}, ProcInlining_no_inline); + lb_emit_call(p, entry_point, {}, ProcInlining_no_inline, ProcTailing_none); } if (call_cleanup) { lbValue cleanup_runtime_value = {cleanup_runtime->value, cleanup_runtime->type}; - lb_emit_call(p, cleanup_runtime_value, {}, ProcInlining_none); + lb_emit_call(p, cleanup_runtime_value, {}, ProcInlining_none, ProcTailing_none); } if (is_dll_main) { @@ -3147,7 +3187,9 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { code_mode); lbModule *m = entry.value; m->target_machine = target_machine; - LLVMSetModuleDataLayout(m->mod, LLVMCreateTargetDataLayout(target_machine)); + LLVMTargetDataRef data_layout = LLVMCreateTargetDataLayout(target_machine); + LLVMSetModuleDataLayout(m->mod, data_layout); + LLVMDisposeTargetData(data_layout); #if LLVM_VERSION_MAJOR >= 18 if (build_context.fast_isel) { @@ -3418,7 +3460,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { LLVMSetLinkage(g.value, LLVMDLLExportLinkage); LLVMSetDLLStorageClass(g.value, LLVMDLLExportStorageClass); } else if (!is_foreign) { - LLVMSetLinkage(g.value, USE_SEPARATE_MODULES ? LLVMWeakAnyLinkage : LLVMInternalLinkage); + LLVM_SET_INTERNAL_WEAK_LINKAGE(g.value); } lb_set_linkage_from_entity_flags(m, g.value, e->flags); LLVMSetAlignment(g.value, cast(u32)type_align_of(e->type)); @@ -3556,6 +3598,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { lb_add_raddbg_string(m, "type_view: {type: \"[]?\", expr: \"array(data, len)\"}"); lb_add_raddbg_string(m, "type_view: {type: \"string\", expr: \"array(data, len)\"}"); lb_add_raddbg_string(m, "type_view: {type: \"[dynamic]?\", expr: \"rows($, array(data, len), len, cap, allocator)\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"[dynamic;?]?\", expr: \"rows($, array(data, len), len)\"}"); // column major matrices lb_add_raddbg_string(m, "type_view: {type: \"matrix[1, ?]?\", expr: \"columns($.data, $[0])\"}"); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index da5d91f2e..e4297300f 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -290,6 +290,7 @@ struct lbDefer { isize scope_index; isize context_stack_count; lbBlock * block; + TokenPos pos; union { Ast *stmt; struct { @@ -345,6 +346,7 @@ struct lbProcedure { Ast * body; u64 tags; ProcInlining inlining; + ProcTailing tailing; bool is_foreign; bool is_export; bool is_entry_point; @@ -357,6 +359,7 @@ struct lbProcedure { std::atomic is_done; lbAddr return_ptr; + Entity * sret_rvo_entity; // Local aliases of `return_ptr` Array defer_stmts; Array blocks; Array branch_blocks; @@ -484,7 +487,7 @@ gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlo gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node); gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t); gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right); -gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, ProcInlining inlining = ProcInlining_none); +gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, ProcInlining inlining = ProcInlining_none, ProcTailing tailing = ProcTailing_none, lbValue *sret_dst = nullptr); gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t); gb_internal lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x); @@ -492,11 +495,10 @@ gb_internal void lb_emit_jump(lbProcedure *p, lbBlock *target_block); gb_internal void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, lbBlock *false_block); gb_internal void lb_start_block(lbProcedure *p, lbBlock *b); -gb_internal lbValue lb_build_call_expr(lbProcedure *p, Ast *expr); +gb_internal lbValue lb_build_call_expr(lbProcedure *p, Ast *expr, lbValue *sret_dst = nullptr); gb_internal lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type); gb_internal void lb_begin_procedure_body(lbProcedure *p); gb_internal void lb_end_procedure_body(lbProcedure *p); -gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, ProcInlining inlining); gb_internal lbAddr lb_find_or_generate_context_ptr(lbProcedure *p); gb_internal lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx); @@ -531,6 +533,7 @@ gb_internal lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da); gb_internal lbValue lb_dynamic_array_len(lbProcedure *p, lbValue da); gb_internal lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da); gb_internal lbValue lb_dynamic_array_allocator(lbProcedure *p, lbValue da); +gb_internal lbValue lb_fixed_capacity_dynamic_array_len(lbProcedure *p, lbValue da); gb_internal lbValue lb_map_len(lbProcedure *p, lbValue value); gb_internal lbValue lb_map_cap(lbProcedure *p, lbValue value); gb_internal lbValue lb_soa_struct_len(lbProcedure *p, lbValue value); @@ -618,7 +621,12 @@ gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef p gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, usize len, unsigned alignment, bool is_volatile); gb_internal gb_inline i64 lb_max_zero_init_size(void) { - return cast(i64)(4*build_context.int_size); + if (build_context.metrics.os == TargetOs_darwin && build_context.metrics.arch == TargetArch_arm64) { + // https://github.com/odin-lang/Odin/issues/6347 + return cast(i64)(4*build_context.int_size); + } else { + return cast(i64)(8); + } } gb_internal LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type); @@ -640,6 +648,11 @@ gb_internal LLVMTypeRef llvm_array_type(LLVMTypeRef ElementType, uint64_t Elemen #endif } +gb_internal lbValue lb_emit_struct_iv(lbProcedure *p, lbValue agg, lbValue field, i32 index); +gb_internal lbValue lb_build_struct_value(lbProcedure *p, Type *type, lbValue *fields, isize count); +gb_internal lbValue lb_make_slice_value(lbProcedure *p, Type *slice_type, lbValue elem, lbValue len); +gb_internal lbValue lb_make_string_value(lbProcedure *p, Type *string_type, lbValue elem, lbValue len); + gb_internal String lb_internal_gen_name_from_type(char const *prefix, Type *type); @@ -670,6 +683,7 @@ enum lbCallingConventionKind : unsigned { lbCallingConvention_PreserveAll = 15, lbCallingConvention_Swift = 16, lbCallingConvention_CXX_FAST_TLS = 17, + lbCallingConvention_PreserveNone = 21, lbCallingConvention_FirstTargetCC = 64, lbCallingConvention_X86_StdCall = 64, lbCallingConvention_X86_FastCall = 65, @@ -723,6 +737,10 @@ lbCallingConventionKind const lb_calling_convention_map[ProcCC_MAX] = { lbCallingConvention_Win64, // ProcCC_Win64, lbCallingConvention_X86_64_SysV, // ProcCC_SysV, + lbCallingConvention_PreserveNone, // ProcCC_PreserveNone, + lbCallingConvention_PreserveMost, // ProcCC_PreserveMost, + lbCallingConvention_PreserveAll, // ProcCC_PreserveAll, + }; enum : LLVMDWARFTypeEncoding { diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 22e124792..762243ee3 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -498,6 +498,13 @@ gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, Bi if (big_int_is_zero(a)) { return LLVMConstNull(lb_type(m, original_type)); } + + BigInt val = {}; + big_int_init(&val, a); + + if (big_int_is_neg(&val)) { + mp_incr(&val); + } size_t sz = cast(size_t)type_size_of(original_type); u64 rop64[4] = {}; // 2 u64 is the maximum we will ever need, so doubling it will be fine :P @@ -509,7 +516,7 @@ gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, Bi size_t nails = 0; mp_endian endian = MP_LITTLE_ENDIAN; - max_count = mp_pack_count(a, nails, size); + max_count = mp_pack_count(&val, nails, size); if (sz < max_count) { debug_print_big_int(a); gb_printf_err("%s -> %tu\n", type_to_string(original_type), sz); @@ -520,7 +527,7 @@ gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, Bi mp_err err = mp_pack(rop, sz, &written, MP_LSB_FIRST, size, endian, nails, - a); + &val); GB_ASSERT(err == MP_OKAY); if (!is_type_endian_little(original_type)) { @@ -531,12 +538,18 @@ gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, Bi } } + if (big_int_is_neg(a)) { + // sizeof instead of sz for sign extend to work properly + for (size_t i = 0; i < sizeof rop64; i++) { + rop[i] = ~rop[i]; + } + } + + big_int_dealloc(&val); + GB_ASSERT(!is_type_array(original_type)); LLVMValueRef value = LLVMConstIntOfArbitraryPrecision(lb_type(m, original_type), cast(unsigned)((sz+7)/8), cast(u64 *)rop); - if (big_int_is_neg(a)) { - value = LLVMConstNeg(value); - } return value; } @@ -665,6 +678,44 @@ LLVMValueRef llvm_const_pad_to_size(lbModule *m, LLVMValueRef val, LLVMTypeRef d } #endif +gb_internal void lb_const_array_spread(lbModule *m, lbConstContext cc, Type *array, ExactValue value, lbValue *res) { + GB_ASSERT(array->kind == Type_Array); + + i64 count = array->Array.count; + Type *elem = array->Array.elem; + + lbValue single_elem = lb_const_value(m, elem, value, cc); + + LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, cast(isize)count); + for (i64 i = 0; i < count; i++) { + elems[i] = single_elem.value; + } + + res->value = llvm_const_array(m, lb_type(m, elem), elems, cast(unsigned)count); +} + +gb_internal LLVMValueRef lb_fill_fixed_capacity_dynamic_array(lbModule *m, i64 elem_count, Type *original_type, LLVMValueRef *values, lbConstContext cc) { + Type *bt = base_type(original_type); + GB_ASSERT(bt->kind == Type_FixedCapacityDynamicArray); + Type *elem_type = bt->FixedCapacityDynamicArray.elem; + i64 capacity = bt->FixedCapacityDynamicArray.capacity; + + Type *array_backing_type = alloc_type_array(elem_type, capacity); + LLVMValueRef array_backing = lb_build_constant_array_values(m, array_backing_type, elem_type, cast(isize)capacity, values, cc); + LLVMValueRef array_len = lb_const_int(m, t_int, elem_count).value; + + isize svalue_count = 0; + LLVMValueRef svalues[3] = {}; + svalues[svalue_count++] = array_backing; + i64 padding = bt->FixedCapacityDynamicArray.padding_needed; + if (padding > 0) { + svalues[svalue_count++] = LLVMConstNull(lb_type_padding_filler(m, padding, 1)); + } + svalues[svalue_count++] = array_len; + + return llvm_const_named_struct(m, original_type, svalues, svalue_count); +} + gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc, Type *value_type) { if (cc.allow_local) { cc.is_rodata = false; @@ -723,13 +774,14 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } LLVMValueRef tag = LLVMConstInt(LLVMStructGetTypeAtIndex(llvm_type, 1), tag_value, false); LLVMValueRef padding = nullptr; - LLVMValueRef values[3] = {cv.value, tag, padding}; isize value_count = 2; if (LLVMCountStructElementTypes(llvm_type) > 2) { value_count = 3; padding = LLVMConstNull(LLVMStructGetTypeAtIndex(llvm_type, 2)); } + + LLVMValueRef values[3] = {cv.value, tag, padding}; res.value = llvm_const_named_struct_internal(m, llvm_type, values, value_count); res.type = original_type; return res; @@ -784,7 +836,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb Type *tag_type = union_tag_type(bt); LLVMTypeRef llvm_tag_type = lb_type(m, tag_type); - i64 tag_index = union_variant_index(bt, variant_type); + i64 tag_index = union_variant_index_checked(bt, variant_type); GB_ASSERT(tag_index >= 0); values[value_count++] = LLVMConstInt(llvm_tag_type, tag_index, false); i64 used_size = block_size + type_size_of(tag_type); @@ -953,34 +1005,29 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } - } else if (is_type_array(type) && value.kind == ExactValue_String && !is_type_u8(core_array_type(type))) { - if (is_type_rune_array(type)) { - i64 count = type->Array.count; - Type *elem = type->Array.elem; - LLVMTypeRef et = lb_type(m, elem); + } else if (is_type_rune_array(type) && value.kind == ExactValue_String && !is_type_u8(core_array_type(type))) { + i64 count = type->Array.count; + Type *elem = type->Array.elem; + LLVMTypeRef et = lb_type(m, elem); - Rune rune; - isize offset = 0; - isize width = 1; - String s = value.value_string; + Rune rune; + isize offset = 0; + isize width = 1; + String s = value.value_string; - LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, cast(isize)count); + LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, cast(isize)count); - for (i64 i = 0; i < count && offset < s.len; i++) { - width = utf8_decode(s.text+offset, s.len-offset, &rune); - offset += width; + for (i64 i = 0; i < count && offset < s.len; i++) { + width = utf8_decode(s.text+offset, s.len-offset, &rune); + offset += width; - elems[i] = LLVMConstInt(et, rune, true); + elems[i] = LLVMConstInt(et, rune, true); - } - GB_ASSERT(offset == s.len); - - res.value = llvm_const_array(m, et, elems, cast(unsigned)count); - return res; } - // NOTE(bill, 2021-10-07): Allow for array programming value constants - Type *core_elem = core_array_type(type); - return lb_const_value(m, core_elem, value, cc); + GB_ASSERT(offset == s.len); + + res.value = llvm_const_array(m, et, elems, cast(unsigned)count); + return res; } else if (is_type_u8_array(type) && value.kind == ExactValue_String) { GB_ASSERT(type->Array.count == value.value_string.len); LLVMValueRef data = LLVMConstStringInContext(ctx, @@ -991,21 +1038,9 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb return res; } else if (is_type_array(type) && value.kind != ExactValue_Invalid && - value.kind != ExactValue_String && value.kind != ExactValue_Compound) { - - i64 count = type->Array.count; - Type *elem = type->Array.elem; - - - lbValue single_elem = lb_const_value(m, elem, value, cc); - - LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, cast(isize)count); - for (i64 i = 0; i < count; i++) { - elems[i] = single_elem.value; - } - - res.value = llvm_const_array(m, lb_type(m, elem), elems, cast(unsigned)count); + + lb_const_array_spread(m, cc, type, value, &res); return res; } else if (is_type_matrix(type) && value.kind != ExactValue_Invalid && @@ -1541,6 +1576,108 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, cc); return res; } + } else if (is_type_fixed_capacity_dynamic_array(type)) { + ast_node(cl, CompoundLit, value.value_compound); + Type *elem_type = type->FixedCapacityDynamicArray.elem; + i64 capacity = type->FixedCapacityDynamicArray.capacity; + isize elem_count = cl->elems.count; + if (elem_count == 0 || !elem_type_can_be_constant(elem_type)) { + return lb_const_nil(m, original_type); + } + if (cl->elems[0]->kind == Ast_FieldValue) { + // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)capacity); + + i64 max_index = -1; + isize value_index = 0; + for (i64 i = 0; i < capacity; i++) { + bool found = false; + + for (isize j = 0; j < elem_count; j++) { + Ast *elem = cl->elems[j]; + ast_node(fv, FieldValue, elem); + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op != Token_RangeHalf) { + hi += 1; + } + max_index = gb_max(max_index, hi-1); + + if (lo == i) { + TypeAndValue tav = fv->value->tav; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; + for (i64 k = lo; k < hi; k++) { + values[value_index++] = val; + } + + found = true; + i += (hi-lo-1); + break; + } + } else { + TypeAndValue index_tav = fv->field->tav; + GB_ASSERT(index_tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(index_tav.value); + + max_index = gb_max(max_index, index); + + if (index == i) { + TypeAndValue tav = fv->value->tav; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; + values[value_index++] = val; + found = true; + break; + } + } + } + + if (!found) { + values[value_index++] = LLVMConstNull(lb_type(m, elem_type)); + } + } + + i64 count = max_index+1; + GB_ASSERT(0 < count); + GB_ASSERT(count <= capacity); + + res.value = lb_fill_fixed_capacity_dynamic_array(m, count, original_type, values, cc); + return res; + } else if (are_types_identical(value.value_compound->tav.type, elem_type)) { + // Compound is of array item type; expand its value to all items in array. + LLVMValueRef* values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)capacity); + + for (isize i = 0; i < capacity; i++) { + values[i] = lb_const_value(m, elem_type, value, cc, elem_type).value; + } + + res.value = lb_fill_fixed_capacity_dynamic_array(m, capacity, original_type, values, cc); + return res; + } else { + // Assume that compound value is an array literal + GB_ASSERT_MSG(elem_count <= capacity, "%td <= %td", elem_count, capacity); + + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)capacity); + + for (isize i = 0; i < elem_count; i++) { + TypeAndValue tav = cl->elems[i]->tav; + GB_ASSERT(tav.mode != Addressing_Invalid); + values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; + } + for (isize i = elem_count; i < capacity; i++) { + values[i] = LLVMConstNull(lb_type(m, elem_type)); + } + + res.value = lb_fill_fixed_capacity_dynamic_array(m, elem_count, original_type, values, cc); + return res; + } } else if (is_type_simd_vector(type)) { ast_node(cl, CompoundLit, value.value_compound); @@ -1682,11 +1819,12 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb for (isize i = 0; i < elem_count; i++) { ast_node(fv, FieldValue, cl->elems[i]); String name = fv->field->Ident.token.string; + InternedString interned = fv->field->Ident.interned; TypeAndValue tav = fv->value->tav; GB_ASSERT(tav.mode != Addressing_Invalid); - Selection sel = lookup_field(type, name, false); + Selection sel = lookup_field(type, interned, false); GB_ASSERT(!sel.indirect); Entity *f = type->Struct.fields[sel.index[0]]; @@ -1995,4 +2133,3 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb return lb_const_nil(m, original_type); } - diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 187aebf7c..d3e63cbf7 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -409,6 +409,69 @@ gb_internal LLVMMetadataRef lb_debug_dynamic_array(lbModule *m, Type *type, Stri return final_decl; } +gb_internal LLVMMetadataRef lb_debug_fixed_capacity_dynamic_array(lbModule *m, Type *type, String name, LLVMMetadataRef scope, LLVMMetadataRef file, unsigned line) { + Type *bt = base_type(type); + GB_ASSERT(bt->kind == Type_FixedCapacityDynamicArray); + + unsigned const int_bits = cast(unsigned)(8*build_context.int_size); + + u64 size_in_bits = 8*type_size_of(bt); + u32 align_in_bits = 8*cast(u32)type_align_of(bt); + + LLVMMetadataRef temp_forward_decl = LLVMDIBuilderCreateReplaceableCompositeType( + m->debug_builder, DW_TAG_structure_type, + cast(char const *)name.text, cast(size_t)name.len, + scope, file, line, 0, size_in_bits, align_in_bits, LLVMDIFlagZero, "", 0 + ); + + lb_set_llvm_metadata(m, type, temp_forward_decl); + + unsigned element_count = 2; + LLVMMetadataRef elements[2]; + + // LLVMMetadataRef member_scope = lb_get_llvm_metadata(m, bt->DynamicArray.scope); + LLVMMetadataRef member_scope = nullptr; + + Type *elem_type = alloc_type_array(bt->FixedCapacityDynamicArray.elem, bt->FixedCapacityDynamicArray.capacity); + elements[0] = LLVMDIBuilderCreateMemberType( + m->debug_builder, member_scope, + "data", 4, + file, line, + 8*cast(u64)type_size_of(elem_type), 8*cast(u32)type_align_of(elem_type), + 0, + LLVMDIFlagZero, lb_debug_type(m, elem_type) + ); + + i64 len_offset_in_bits = 8*type_offset_of(bt, 1); + + elements[1] = LLVMDIBuilderCreateMemberType( + m->debug_builder, member_scope, + "len", 3, + file, line, + int_bits, int_bits, + len_offset_in_bits, + LLVMDIFlagZero, lb_debug_type(m, t_int) + ); + + LLVMMetadataRef final_decl = LLVMDIBuilderCreateStructType( + m->debug_builder, scope, + cast(char const *)name.text, cast(size_t)name.len, + file, line, + size_in_bits, align_in_bits, + LLVMDIFlagZero, + nullptr, + elements, element_count, + 0, + nullptr, + "", 0 + ); + + LLVMMetadataReplaceAllUsesWith(temp_forward_decl, final_decl); + lb_set_llvm_metadata(m, type, final_decl); + return final_decl; +} + + gb_internal LLVMMetadataRef lb_debug_union(lbModule *m, Type *type, String name, LLVMMetadataRef scope, LLVMMetadataRef file, unsigned line) { Type *bt = base_type(type); GB_ASSERT(bt->kind == Type_Union); @@ -729,22 +792,22 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { case Basic_i128be: return lb_debug_type_basic_type(m, str_lit("i128be"), 128, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagBigEndian); case Basic_u128be: return lb_debug_type_basic_type(m, str_lit("u128be"), 128, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagBigEndian); - case Basic_f16be: return lb_debug_type_basic_type(m, str_lit("f16be"), 16, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian); - case Basic_f32be: return lb_debug_type_basic_type(m, str_lit("f32be"), 32, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian); - case Basic_f64be: return lb_debug_type_basic_type(m, str_lit("f64be"), 64, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian); + case Basic_f16be: return lb_debug_type_basic_type(m, str_lit("f16be"), 16, LLVMDWARFTypeEncoding_Float, LLVMDIFlagBigEndian); + case Basic_f32be: return lb_debug_type_basic_type(m, str_lit("f32be"), 32, LLVMDWARFTypeEncoding_Float, LLVMDIFlagBigEndian); + case Basic_f64be: return lb_debug_type_basic_type(m, str_lit("f64be"), 64, LLVMDWARFTypeEncoding_Float, LLVMDIFlagBigEndian); case Basic_complex32: { LLVMMetadataRef elements[2] = {}; elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f16, 0*16); elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f16, 1*16); - return lb_debug_basic_struct(m, str_lit("complex32"), 64, 32, elements, gb_count_of(elements)); + return lb_debug_basic_struct(m, str_lit("complex32"), 32, 16, elements, gb_count_of(elements)); } case Basic_complex64: { LLVMMetadataRef elements[2] = {}; elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f32, 0*32); - elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f32, 2*32); + elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f32, 1*32); return lb_debug_basic_struct(m, str_lit("complex64"), 64, 32, elements, gb_count_of(elements)); } case Basic_complex128: @@ -762,7 +825,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f16, 1*16); elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f16, 2*16); elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f16, 3*16); - return lb_debug_basic_struct(m, str_lit("quaternion64"), 128, 32, elements, gb_count_of(elements)); + return lb_debug_basic_struct(m, str_lit("quaternion64"), 64, 16, elements, gb_count_of(elements)); } case Basic_quaternion128: { @@ -780,7 +843,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f64, 1*64); elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f64, 2*64); elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f64, 3*64); - return lb_debug_basic_struct(m, str_lit("quaternion256"), 256, 32, elements, gb_count_of(elements)); + return lb_debug_basic_struct(m, str_lit("quaternion256"), 256, 64, elements, gb_count_of(elements)); } @@ -792,6 +855,8 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { } case Basic_string: { + // NOTE(bill): size_of(^u8) <= size_of(int) + LLVMMetadataRef elements[2] = {}; elements[0] = lb_debug_struct_field(m, str_lit("data"), t_u8_ptr, 0); elements[1] = lb_debug_struct_field(m, str_lit("len"), t_int, int_bits); @@ -805,6 +870,8 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { case Basic_string16: { + // NOTE(bill): size_of(^u16) <= size_of(int) + LLVMMetadataRef elements[2] = {}; elements[0] = lb_debug_struct_field(m, str_lit("data"), t_u16_ptr, 0); elements[1] = lb_debug_struct_field(m, str_lit("len"), t_int, int_bits); @@ -820,7 +887,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { { LLVMMetadataRef elements[2] = {}; elements[0] = lb_debug_struct_field(m, str_lit("data"), t_rawptr, 0); - elements[1] = lb_debug_struct_field(m, str_lit("id"), t_typeid, 64); + elements[1] = lb_debug_struct_field(m, str_lit("id"), t_typeid, 64); // typeid is always 64 bits in size and 64 bits in alignment return lb_debug_basic_struct(m, str_lit("any"), 128, 64, elements, gb_count_of(elements)); } @@ -843,6 +910,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { GB_PANIC("Type_Named should be handled in lb_debug_type separately"); case Type_SoaPointer: + // TODO(bill): This is technically incorrect and needs fixing return LLVMDIBuilderCreatePointerType(m->debug_builder, lb_debug_type(m, type->SoaPointer.elem), int_bits, int_bits, 0, nullptr, 0); case Type_Pointer: return LLVMDIBuilderCreatePointerType(m->debug_builder, lb_debug_type(m, type->Pointer.elem), ptr_bits, ptr_bits, 0, nullptr, 0); @@ -894,6 +962,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { case Type_BitSet: return lb_debug_bitset( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0); case Type_Enum: return lb_debug_enum( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0); case Type_BitField: return lb_debug_bitfield( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0); + case Type_FixedCapacityDynamicArray: return lb_debug_fixed_capacity_dynamic_array(m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0); case Type_Tuple: if (type->Tuple.variables.count == 1) { diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index dba61df44..39cdcd54f 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1,4 +1,14 @@ gb_internal lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise); +gb_internal lbValue lb_build_slice_expr_value(lbProcedure *p, Ast *expr); + +gb_internal LLVMValueRef lb_const_low_bits_mask(LLVMTypeRef type, u64 bit_count) { + GB_ASSERT(bit_count <= 64); + if (bit_count == 0) { + return LLVMConstInt(type, 0, false); + } + u64 mask = bit_count == 64 ? ~0ull : (1ull<module; @@ -242,25 +252,18 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, LLVMValueRef v0 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 0, ""), ""); LLVMValueRef v1 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 1, ""), ""); - lbAddr addr = lb_add_local_generated(p, x.type, false); - LLVMTypeRef type = llvm_addr_type(p->module, addr.addr); - LLVMBuildStore(p->builder, v0, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 0, "")); - LLVMBuildStore(p->builder, v1, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 1, "")); - return lb_addr_load(p, addr); - + Type *et = base_complex_elem_type(x.type); + lbValue fields[2] = {{v0, et}, {v1, et}}; + return lb_build_struct_value(p, x.type, fields, gb_count_of(fields)); } else if (is_type_quaternion(x.type)) { LLVMValueRef v0 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 0, ""), ""); LLVMValueRef v1 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 1, ""), ""); LLVMValueRef v2 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 2, ""), ""); LLVMValueRef v3 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 3, ""), ""); - lbAddr addr = lb_add_local_generated(p, x.type, false); - LLVMTypeRef type = llvm_addr_type(p->module, addr.addr); - LLVMBuildStore(p->builder, v0, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 0, "")); - LLVMBuildStore(p->builder, v1, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 1, "")); - LLVMBuildStore(p->builder, v2, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 2, "")); - LLVMBuildStore(p->builder, v3, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 3, "")); - return lb_addr_load(p, addr); + Type *et = base_complex_elem_type(x.type); + lbValue fields[4] = {{v0, et}, {v1, et}, {v2, et}, {v3, et}}; + return lb_build_struct_value(p, x.type, fields, gb_count_of(fields)); } else if (is_type_simd_vector(x.type)) { Type *elem = base_array_type(x.type); if (is_type_float(elem)) { @@ -282,11 +285,16 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, return res; } - -gb_internal IntegerDivisionByZeroKind lb_check_for_integer_division_by_zero_behaviour(lbProcedure *p) { +gb_internal u64 lb_get_file_feature_flags(lbProcedure *p, Ast *expr = nullptr) { AstFile *file = nullptr; - if (p->body && p->body->file()) { + if (expr != nullptr) { + file = expr->file(); + } + + if (file != nullptr) { + // it is now set + } else if (p->body && p->body->file()) { file = p->body->file(); } else if (p->type_expr && p->type_expr->file()) { file = p->type_expr->file(); @@ -295,20 +303,29 @@ gb_internal IntegerDivisionByZeroKind lb_check_for_integer_division_by_zero_beha } if (file != nullptr && file->feature_flags_set) { - u64 flags = file->feature_flags; - if (flags & OptInFeatureFlag_IntegerDivisionByZero_Trap) { - return IntegerDivisionByZero_Trap; - } - if (flags & OptInFeatureFlag_IntegerDivisionByZero_Zero) { - return IntegerDivisionByZero_Zero; - } - if (flags & OptInFeatureFlag_IntegerDivisionByZero_Self) { - return IntegerDivisionByZero_Self; - } - if (flags & OptInFeatureFlag_IntegerDivisionByZero_AllBits) { - return IntegerDivisionByZero_AllBits; - } + return file->feature_flags; } + return 0; +} + + + +gb_internal IntegerDivisionByZeroKind lb_check_for_integer_division_by_zero_behaviour(lbProcedure *p) { + u64 flags = lb_get_file_feature_flags(p); + + if (flags & OptInFeatureFlag_IntegerDivisionByZero_Trap) { + return IntegerDivisionByZero_Trap; + } + if (flags & OptInFeatureFlag_IntegerDivisionByZero_Zero) { + return IntegerDivisionByZero_Zero; + } + if (flags & OptInFeatureFlag_IntegerDivisionByZero_Self) { + return IntegerDivisionByZero_Self; + } + if (flags & OptInFeatureFlag_IntegerDivisionByZero_AllBits) { + return IntegerDivisionByZero_AllBits; + } + return build_context.integer_division_by_zero_behaviour; } @@ -950,7 +967,7 @@ gb_internal lbValue lb_emit_matrix_mul_vector(lbProcedure *p, lbValue lhs, lbVal } for (unsigned row_index = 0; row_index < column_count; row_index++) { - LLVMValueRef value = lb_emit_struct_ev(p, rhs, row_index).value; + LLVMValueRef value = LLVMBuildExtractValue(p->builder, rhs.value, row_index, ""); LLVMValueRef row = llvm_vector_broadcast(p, value, row_count); v_rows[row_index] = row; } @@ -971,13 +988,19 @@ gb_internal lbValue lb_emit_matrix_mul_vector(lbProcedure *p, lbValue lhs, lbVal lbAddr res = lb_add_local_generated(p, type, true); + Type *vector_elem_type = base_array_type(rhs.type); + for (i64 i = 0; i < mt->Matrix.row_count; i++) { for (i64 j = 0; j < mt->Matrix.column_count; j++) { lbValue dst = lb_emit_matrix_epi(p, res.addr, i, 0); lbValue d0 = lb_emit_load(p, dst); lbValue a = lb_emit_matrix_ev(p, lhs, i, j); - lbValue b = lb_emit_struct_ev(p, rhs, cast(i32)j); + + + LLVMValueRef b_value = LLVMBuildExtractValue(p->builder, rhs.value, cast(unsigned)j, ""); + lbValue b = {b_value, vector_elem_type}; + lbValue c = lb_emit_mul_add(p, a, b, d0, elem); lb_emit_store(p, dst, c); } @@ -1026,7 +1049,7 @@ gb_internal lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbVal } for (unsigned column_index = 0; column_index < row_count; column_index++) { - LLVMValueRef value = lb_emit_struct_ev(p, lhs, column_index).value; + LLVMValueRef value = LLVMBuildExtractValue(p->builder, lhs.value, column_index, ""); LLVMValueRef row = llvm_vector_broadcast(p, value, column_count); v_rows[column_index] = row; } @@ -1055,12 +1078,16 @@ gb_internal lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbVal lbAddr res = lb_add_local_generated(p, type, true); + Type *vector_elem_type = base_array_type(rhs.type); + for (i64 j = 0; j < mt->Matrix.column_count; j++) { for (i64 k = 0; k < mt->Matrix.row_count; k++) { lbValue dst = lb_emit_matrix_epi(p, res.addr, 0, j); lbValue d0 = lb_emit_load(p, dst); - lbValue a = lb_emit_struct_ev(p, lhs, cast(i32)k); + LLVMValueRef a_value = LLVMBuildExtractValue(p->builder, lhs.value, cast(unsigned)k, ""); + lbValue a = {a_value, vector_elem_type}; + lbValue b = lb_emit_matrix_ev(p, rhs, k, j); lbValue c = lb_emit_mul_add(p, a, b, d0, elem); lb_emit_store(p, dst, c); @@ -1363,6 +1390,8 @@ gb_internal LLVMValueRef lb_integer_modulo(lbProcedure *p, LLVMValueRef lhs, LLV if (LLVMIsConstant(rhs)) { if (LLVMIsNull(rhs)) { switch (behaviour) { + case IntegerDivisionByZero_Trap: + break; case IntegerDivisionByZero_Self: return zero; case IntegerDivisionByZero_Zero: @@ -1399,8 +1428,8 @@ gb_internal LLVMValueRef lb_integer_modulo(lbProcedure *p, LLVMValueRef lhs, LLV truncated: r = a - b*trunc(a/b) floored: r = a - b*floor(a/b) - IFF a/0 == 0, then (a%0 == a) or (a%%0 == a) - IFF a/0 == a, then (a%0 == 0) or (a%%0 == 0) + If and only if (⟺) a/0 == 0, then (a%0 == a) or (a%%0 == a) + If and only if (⟺) a/0 == a, then (a%0 == 0) or (a%%0 == 0) */ switch (behaviour) { @@ -1469,7 +1498,6 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV } } - lbAddr res = lb_add_local_generated(p, type, false); // NOTE: initialized in full later lbValue a = lb_emit_struct_ev(p, lhs, 0); lbValue b = lb_emit_struct_ev(p, lhs, 1); lbValue c = lb_emit_struct_ev(p, rhs, 0); @@ -1507,10 +1535,9 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV } } - lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 0), real); - lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 1), imag); - return lb_addr_load(p, res); + lbValue fields[2] = {real, imag}; + return lb_build_struct_value(p, type, fields, gb_count_of(fields)); } else if (is_type_quaternion(type)) { lhs = lb_emit_conv(p, lhs, type); rhs = lb_emit_conv(p, rhs, type); @@ -1523,7 +1550,6 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV immediate_type = t_f32; } - lbAddr res = lb_add_local_generated(p, type, false); // NOTE: initialized in full later lbValue x0 = lb_emit_struct_ev(p, lhs, 0); lbValue x1 = lb_emit_struct_ev(p, lhs, 1); lbValue x2 = lb_emit_struct_ev(p, lhs, 2); @@ -1551,10 +1577,6 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV lbValue z2 = lb_emit_arith(p, op, x2, y2, immediate_type); lbValue z3 = lb_emit_arith(p, op, x3, y3, immediate_type); - lbValue d0 = lb_emit_struct_ep(p, res.addr, 0); - lbValue d1 = lb_emit_struct_ep(p, res.addr, 1); - lbValue d2 = lb_emit_struct_ep(p, res.addr, 2); - lbValue d3 = lb_emit_struct_ep(p, res.addr, 3); if (immediate_type != ft) { z0 = lb_emit_conv(p, z0, ft); @@ -1563,12 +1585,8 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV z3 = lb_emit_conv(p, z3, ft); } - lb_emit_store(p, d0, z0); - lb_emit_store(p, d1, z1); - lb_emit_store(p, d2, z2); - lb_emit_store(p, d3, z3); - - return lb_addr_load(p, res); + lbValue fields[4] = {z0, z1, z2, z3}; + return lb_build_struct_value(p, type, fields, gb_count_of(fields)); } else if (op == Token_Mul) { TEMPORARY_ALLOCATOR_GUARD(); @@ -2206,77 +2224,63 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { if (is_type_complex(src) && is_type_complex(dst)) { Type *ft = base_complex_elem_type(dst); - lbAddr gen = lb_add_local_generated(p, t, false); - lbValue gp = lb_addr_get_ptr(p, gen); lbValue real = lb_emit_conv(p, lb_emit_struct_ev(p, value, 0), ft); lbValue imag = lb_emit_conv(p, lb_emit_struct_ev(p, value, 1), ft); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), real); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 1), imag); - return lb_addr_load(p, gen); + + lbValue fields[2] = {real, imag}; + return lb_build_struct_value(p, t, fields, gb_count_of(fields)); } if (is_type_quaternion(src) && is_type_quaternion(dst)) { // @QuaternionLayout Type *ft = base_complex_elem_type(dst); - lbAddr gen = lb_add_local_generated(p, t, false); - lbValue gp = lb_addr_get_ptr(p, gen); lbValue q0 = lb_emit_conv(p, lb_emit_struct_ev(p, value, 0), ft); lbValue q1 = lb_emit_conv(p, lb_emit_struct_ev(p, value, 1), ft); lbValue q2 = lb_emit_conv(p, lb_emit_struct_ev(p, value, 2), ft); lbValue q3 = lb_emit_conv(p, lb_emit_struct_ev(p, value, 3), ft); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), q0); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 1), q1); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 2), q2); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 3), q3); - return lb_addr_load(p, gen); + + lbValue fields[4] = {q0, q1, q2, q3}; + return lb_build_struct_value(p, t, fields, gb_count_of(fields)); } if (is_type_integer(src) && is_type_complex(dst)) { Type *ft = base_complex_elem_type(dst); - lbAddr gen = lb_add_local_generated(p, t, true); - lbValue gp = lb_addr_get_ptr(p, gen); lbValue real = lb_emit_conv(p, value, ft); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), real); - return lb_addr_load(p, gen); + lbValue fields[2] = {real, lb_const_nil(m, ft)}; + return lb_build_struct_value(p, t, fields, gb_count_of(fields)); } if (is_type_float(src) && is_type_complex(dst)) { Type *ft = base_complex_elem_type(dst); - lbAddr gen = lb_add_local_generated(p, t, true); - lbValue gp = lb_addr_get_ptr(p, gen); lbValue real = lb_emit_conv(p, value, ft); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), real); - return lb_addr_load(p, gen); + lbValue fields[2] = {real, lb_const_nil(m, ft)}; + return lb_build_struct_value(p, t, fields, gb_count_of(fields)); } if (is_type_integer(src) && is_type_quaternion(dst)) { Type *ft = base_complex_elem_type(dst); - lbAddr gen = lb_add_local_generated(p, t, true); - lbValue gp = lb_addr_get_ptr(p, gen); lbValue real = lb_emit_conv(p, value, ft); + lbValue zero = lb_const_nil(m, ft); // @QuaternionLayout - lb_emit_store(p, lb_emit_struct_ep(p, gp, 3), real); - return lb_addr_load(p, gen); + lbValue fields[4] = {zero, zero, zero, real}; + return lb_build_struct_value(p, t, fields, gb_count_of(fields)); } if (is_type_float(src) && is_type_quaternion(dst)) { Type *ft = base_complex_elem_type(dst); - lbAddr gen = lb_add_local_generated(p, t, true); - lbValue gp = lb_addr_get_ptr(p, gen); lbValue real = lb_emit_conv(p, value, ft); + lbValue zero = lb_const_nil(m, ft); // @QuaternionLayout - lb_emit_store(p, lb_emit_struct_ep(p, gp, 3), real); - return lb_addr_load(p, gen); + lbValue fields[4] = {zero, zero, zero, real}; + return lb_build_struct_value(p, t, fields, gb_count_of(fields)); } if (is_type_complex(src) && is_type_quaternion(dst)) { Type *ft = base_complex_elem_type(dst); - lbAddr gen = lb_add_local_generated(p, t, true); - lbValue gp = lb_addr_get_ptr(p, gen); lbValue real = lb_emit_conv(p, lb_emit_struct_ev(p, value, 0), ft); lbValue imag = lb_emit_conv(p, lb_emit_struct_ev(p, value, 1), ft); + lbValue zero = lb_const_nil(m, ft); // @QuaternionLayout - lb_emit_store(p, lb_emit_struct_ep(p, gp, 3), real); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), imag); - return lb_addr_load(p, gen); + lbValue fields[4] = {imag, zero, zero, real}; + return lb_build_struct_value(p, t, fields, gb_count_of(fields)); } // float <-> integer @@ -2818,8 +2822,6 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { return lb_const_nil(p->module, t); } - lbAddr result = lb_add_local_generated(p, t, true); - Type *st = default_type(src_type); lbValue data = lb_address_from_load_or_generate_local(p, value); @@ -2828,13 +2830,8 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { data = lb_emit_conv(p, data, t_rawptr); lbValue id = lb_typeid(p->module, st); - lbValue any_data = lb_emit_struct_ep(p, result.addr, 0); - lbValue any_id = lb_emit_struct_ep(p, result.addr, 1); - - lb_emit_store(p, any_data, data); - lb_emit_store(p, any_id, id); - - return lb_addr_load(p, result); + lbValue fields[2] = {data, id}; + return lb_build_struct_value(p, t, fields, gb_count_of(fields)); } @@ -2901,10 +2898,13 @@ gb_internal lbValue lb_emit_c_vararg(lbProcedure *p, lbValue arg, Type *type) { gb_internal lbValue lb_compare_records(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right, Type *type) { GB_ASSERT((is_type_struct(type) || is_type_soa_pointer(type) || is_type_union(type)) && is_type_comparable(type)); + lbValue left_ptr = lb_address_from_load_or_generate_local(p, left); lbValue right_ptr = lb_address_from_load_or_generate_local(p, right); + i64 size = type_size_of(type); + lbValue res = {}; - if (type_size_of(type) == 0) { + if (size == 0) { switch (op_kind) { case Token_CmpEq: return lb_const_bool(p->module, t_bool, true); @@ -2913,8 +2913,23 @@ gb_internal lbValue lb_compare_records(lbProcedure *p, TokenKind op_kind, lbValu } GB_PANIC("invalid operator"); } + TEMPORARY_ALLOCATOR_GUARD(); + if (is_type_simple_compare(type)) { + // if (size <= 8) { + // LLVMTypeRef int_type = LLVMIntTypeInContext(p->module->ctx, cast(unsigned)(size*8)); + // LLVMValueRef l = OdinLLVMBuildLoad(p, int_type, LLVMBuildPointerCast(p->builder, left_ptr.value, LLVMPointerType(int_type, 0), "")); + // LLVMValueRef r = OdinLLVMBuildLoad(p, int_type, LLVMBuildPointerCast(p->builder, right_ptr.value, LLVMPointerType(int_type, 0), "")); + + // LLVMIntPredicate pred = (op_kind == Token_CmpEq) ? LLVMIntEQ : LLVMIntNE; + // LLVMValueRef cmp = LLVMBuildICmp(p->builder, pred, l, r, ""); + + // res.value = cmp; + // res.type = t_bool; + // return res; + // } + // TODO(bill): Test to see if this is actually faster!!!! auto args = array_make(temporary_allocator(), 3); args[0] = lb_emit_conv(p, left_ptr, t_rawptr); @@ -2928,6 +2943,7 @@ gb_internal lbValue lb_compare_records(lbProcedure *p, TokenKind op_kind, lbValu args[1] = lb_emit_conv(p, right_ptr, t_rawptr); res = lb_emit_call(p, value, args); } + if (op_kind == Token_NotEq) { res = lb_emit_unary_arith(p, Token_Not, res, res.type); } @@ -2955,6 +2971,7 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left return nil_check; } + if (are_types_identical(a, b)) { // NOTE(bill): No need for a conversion } else if ((lb_is_const(left) && !is_type_array(left.type)) || lb_is_const_nil(left)) { @@ -2967,15 +2984,20 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left if (internal_check_is_assignable_to(right.type, left.type)) { right = lb_emit_conv(p, right, left.type); } - return lb_emit_comp_against_nil(p, op_kind, right); + if (LLVMTypeOf(left.value) == LLVMTypeOf(right.value)) { + return lb_emit_comp_against_nil(p, op_kind, right); + } } left = lb_emit_conv(p, left, right.type); } else if ((lb_is_const(right) && !is_type_array(right.type)) || lb_is_const_nil(right)) { + if (lb_is_const_nil(right)) { if (internal_check_is_assignable_to(left.type, right.type)) { left = lb_emit_conv(p, left, right.type); } - return lb_emit_comp_against_nil(p, op_kind, left); + if (LLVMTypeOf(left.value) == LLVMTypeOf(right.value)) { + return lb_emit_comp_against_nil(p, op_kind, left); + } } right = lb_emit_conv(p, right, left.type); } else { @@ -3802,6 +3824,17 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { Type *type = type_of_expr(ue_expr); GB_ASSERT(!is_type_tuple(type)); + bool do_type_check = true; + if (build_context.no_type_assert) { + u64 feature_flags = lb_get_file_feature_flags(p, ue_expr); + if ((feature_flags & OptInFeatureFlag_ForceTypeAssert) == 0) { + do_type_check = false; + } + + } else if ((p->state_flags & StateFlag_no_type_assert) != 0) { + do_type_check = false; + } + lbValue e = lb_build_expr(p, ta->expr); Type *t = type_deref(e.type); if (is_type_union(t)) { @@ -3813,7 +3846,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { Type *dst_type = type; - if (!build_context.no_type_assert && (p->state_flags & StateFlag_no_type_assert) == 0) { + if (do_type_check) { lbValue src_tag = {}; lbValue dst_tag = {}; if (is_type_union_maybe_pointer(src_type)) { @@ -3840,7 +3873,12 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { args[4] = lb_typeid(p->module, src_type); args[5] = lb_typeid(p->module, dst_type); } - lb_emit_runtime_call(p, "type_assertion_check", args); + + char const *name = "type_assertion_check_contextless"; + if (p->context_stack.count > 0) { + name = "type_assertion_check_with_context"; + } + lb_emit_runtime_call(p, name, args); } lbValue data_ptr = v; @@ -3851,21 +3889,33 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { v = lb_emit_load(p, v); } lbValue data_ptr = lb_emit_struct_ev(p, v, 0); - if (!build_context.no_type_assert && (p->state_flags & StateFlag_no_type_assert) == 0) { + if (do_type_check) { GB_ASSERT(!build_context.no_rtti); lbValue any_id = lb_emit_struct_ev(p, v, 1); + isize arg_count = 6; + if (build_context.no_rtti) { + arg_count = 4; + } + lbValue id = lb_typeid(p->module, type); lbValue ok = lb_emit_comp(p, Token_CmpEq, any_id, id); - auto args = array_make(permanent_allocator(), 6); + auto args = array_make(permanent_allocator(), arg_count); args[0] = ok; lb_set_file_line_col(p, array_slice(args, 1, args.count), pos); - args[4] = any_id; - args[5] = id; - lb_emit_runtime_call(p, "type_assertion_check", args); + if (!build_context.no_rtti) { + args[4] = any_id; + args[5] = id; + } + + char const *name = "type_assertion_check_contextless"; + if (p->context_stack.count > 0) { + name = "type_assertion_check_with_context"; + } + lb_emit_runtime_call(p, name, args); } return lb_emit_conv(p, data_ptr, tv.type); @@ -4054,10 +4104,18 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { case_end; case_ast_node(te, TernaryIfExpr, expr); + GB_ASSERT(te->y != nullptr); + Type *type = default_type(type_of_expr(expr)); + if (lb_is_expr_trivial(te->x) && lb_is_expr_trivial(te->y)) { + lbValue cond = lb_build_expr(p, te->cond); + lbValue x = lb_emit_conv(p, lb_build_expr(p, te->x), type); + lbValue y = lb_emit_conv(p, lb_build_expr(p, te->y), type); + return lb_emit_select(p, cond, x, y); + } + LLVMValueRef incoming_values[2] = {}; LLVMBasicBlockRef incoming_blocks[2] = {}; - GB_ASSERT(te->y != nullptr); lbBlock *then = lb_create_block(p, "if.then"); lbBlock *done = lb_create_block(p, "if.done"); // NOTE(bill): Append later lbBlock *else_ = lb_create_block(p, "if.else"); @@ -4065,7 +4123,6 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { lb_build_cond(p, te->cond, then, else_); lb_start_block(p, then); - Type *type = default_type(type_of_expr(expr)); LLVMTypeRef llvm_type = lb_type(p->module, type); incoming_values[0] = lb_emit_conv(p, lb_build_expr(p, te->x), type).value; @@ -4232,6 +4289,24 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { return lb_build_expr(p, se->expr); } } + { + Type *src_type = base_type(type_of_expr(se->expr)); + if (is_type_pointer(src_type)) { + src_type = base_type(type_deref(src_type)); + } + + if (is_type_slice(src_type) || + is_type_dynamic_array(src_type) || + is_type_string(src_type) || + is_type_string16(src_type)) { + return lb_build_slice_expr_value(p, expr); + } + + if (is_type_multi_pointer(src_type) && se->high != nullptr) { + return lb_build_slice_expr_value(p, expr); + } + } + return lb_addr_load(p, lb_build_addr(p, expr)); case_end; @@ -4287,9 +4362,9 @@ gb_internal lbAddr lb_get_soa_variable_addr(lbProcedure *p, Entity *e) { } gb_internal lbValue lb_get_using_variable(lbProcedure *p, Entity *e) { GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Using); - String name = e->token.string; + InternedString interned = entity_interned_name(e); Entity *parent = e->using_parent; - Selection sel = lookup_field(parent->type, name, false); + Selection sel = lookup_field(parent->type, interned, false); GB_ASSERT(sel.entity != nullptr); lbValue *pv = map_get(&p->module->values, parent); @@ -4304,7 +4379,7 @@ gb_internal lbValue lb_get_using_variable(lbProcedure *p, Entity *e) { } else if (pv != nullptr) { v = *pv; } else { - GB_ASSERT_MSG(e->using_expr != nullptr, "%.*s", LIT(name)); + GB_ASSERT_MSG(e->using_expr != nullptr, "%.*s", LIT(e->token.string)); v = lb_build_addr_ptr(p, e->using_expr); } GB_ASSERT(v.value != nullptr); @@ -4436,6 +4511,7 @@ gb_internal void lb_build_addr_compound_lit_populate(lbProcedure *p, SliceDynamicArray.elem; break; case Type_SimdVector: et = bt->SimdVector.elem; break; case Type_Matrix: et = bt->Matrix.elem; break; + case Type_FixedCapacityDynamicArray: et = bt->FixedCapacityDynamicArray.elem; break; } GB_ASSERT(et != nullptr); @@ -4641,6 +4717,25 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) { return lb_addr(elem); } + case Type_FixedCapacityDynamicArray: { + lbValue array = {}; + array = lb_build_addr_ptr(p, ie->expr); + if (deref) { + array = lb_emit_load(p, array); + } + lbValue index = lb_build_expr(p, ie->index); + index = lb_emit_conv(p, index, t_int); + + lbValue array_ptr = lb_emit_struct_ep(p, array, 0); + lbValue elem = lb_emit_array_ep(p, array_ptr, index); + + auto index_tv = type_and_value_of_expr(ie->index); + lbValue len = lb_emit_struct_ep(p, array, 1); + len = lb_emit_load(p, len); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + return lb_addr(elem); + } + case Type_EnumeratedArray: { lbValue array = {}; array = lb_build_addr_ptr(p, ie->expr); @@ -4774,6 +4869,216 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) { } +gb_internal lbValue lb_build_slice_expr_value(lbProcedure *p, Ast *expr) { + ast_node(se, SliceExpr, expr); + + if (true) { + // NOTE(bill): Fused nested slice chain: src[a:b][c:d][e:f]... + // Walk a chain of nested SliceExprs down to the root source, then apply + // each slice's bounds check and offset on raw (ptr, len) SSA values, + // building a single aggregate at the end. + + + Ast *inner_ast = unparen_expr(se->expr); + if (inner_ast->kind == Ast_SliceExpr) { + enum {MAX_CHAIN = 8}; // this is more than enough in practice + + // Collect the chain: slices[0] is innermost, slices[n-1] is outer-most `se`. + Ast *chain[MAX_CHAIN] = {}; // bounded depth + isize chain_count = 0; + chain[chain_count++] = expr; // outer-most + + Ast *root = inner_ast; + while (root->kind == Ast_SliceExpr && chain_count < MAX_CHAIN) { + chain[chain_count++] = root; + root = unparen_expr(root->SliceExpr.expr); + } + + Type *root_type = base_type(type_of_expr(root)); + if (is_type_pointer(root_type)) { + root_type = base_type(type_deref(root_type)); + } + if (is_type_slice(root_type) || + is_type_dynamic_array(root_type) || + is_type_string(root_type) || + is_type_string16(root_type)) { + lbModule *m = p->module; + + // Evaluate the root source and extract raw (ptr, len). + lbValue src = lb_build_expr(p, root); + Type *src_type = base_type(src.type); + if (is_type_pointer(src_type)) { + src_type = base_type(type_deref(src_type)); + src = lb_emit_load(p, src); + } + + lbValue cur_ptr = {}; + lbValue cur_len = {}; + if (is_type_slice(src_type)) { + cur_ptr = lb_slice_elem(p, src); + cur_len = lb_slice_len(p, src); + } else if (is_type_dynamic_array(src_type)) { + cur_ptr = lb_dynamic_array_elem(p, src); + cur_len = lb_dynamic_array_len(p, src); + } else { + GB_ASSERT(is_type_string(src_type) || is_type_string16(src_type)); + cur_ptr = lb_string_elem(p, src); + cur_len = lb_string_len(p, src); + } + + // Apply each slice innermost-first (reverse of collection order). + for (isize i = chain_count - 1; i >= 0; i--) { + AstSliceExpr *s = &chain[i]->SliceExpr; + + lbValue lo = lb_const_int(m, t_int, 0); + lbValue hi = {}; + if (s->low != nullptr) { + lo = lb_correct_endianness(p, lb_build_expr(p, s->low)); + } + if (s->high != nullptr) { + hi = lb_correct_endianness(p, lb_build_expr(p, s->high)); + } + if (hi.value == nullptr) { + hi = cur_len; + } + + bool no_indices = s->low == nullptr && s->high == nullptr; + if (!no_indices) { + lb_emit_slice_bounds_check(p, s->open, lo, hi, cur_len, s->low != nullptr); + } + + cur_ptr = (s->low == nullptr) ? cur_ptr : lb_emit_ptr_offset(p, cur_ptr, lo); + cur_len = (s->low == nullptr) ? lb_emit_conv(p, hi, t_int) : lb_emit_arith(p, Token_Sub, hi, lo, t_int); + } + + // Single aggregate construction. + Type *result_type = type_of_expr(expr); + if (is_type_string(result_type)) { + return lb_make_string_value(p, result_type, cur_ptr, cur_len); + } + return lb_make_slice_value(p, result_type, cur_ptr, cur_len); + } + } + } + + lbValue base = lb_build_expr(p, se->expr); + Type *type = base_type(base.type); + + if (is_type_pointer(type)) { + type = base_type(type_deref(type)); + base = lb_emit_load(p, base); + } + + lbValue low = lb_const_int(p->module, t_int, 0); + lbValue high = {}; + + if (se->low != nullptr) { + low = lb_correct_endianness(p, lb_build_expr(p, se->low)); + } + if (se->high != nullptr) { + high = lb_correct_endianness(p, lb_build_expr(p, se->high)); + } + + bool no_indices = se->low == nullptr && se->high == nullptr; + + switch (type->kind) { + case Type_Slice: { + Type *slice_type = type; + lbValue len = lb_slice_len(p, base); + if (high.value == nullptr) high = len; + + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + + lbValue elem = lb_emit_ptr_offset(p, lb_slice_elem(p, base), low); + lbValue new_len = (se->low == nullptr) + ? lb_emit_conv(p, high, t_int) + : lb_emit_arith(p, Token_Sub, high, low, t_int); + + return lb_make_slice_value(p, slice_type, elem, new_len); + } + + case Type_DynamicArray: { + Type *elem_type = type->DynamicArray.elem; + Type *slice_type = alloc_type_slice(elem_type); + + lbValue len = lb_dynamic_array_len(p, base); + if (high.value == nullptr) high = len; + + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + + lbValue elem = lb_emit_ptr_offset(p, lb_dynamic_array_elem(p, base), low); + lbValue new_len = (se->low == nullptr) + ? lb_emit_conv(p, high, t_int) + : lb_emit_arith(p, Token_Sub, high, low, t_int); + + return lb_make_slice_value(p, slice_type, elem, new_len); + } + + case Type_Basic: { + if (is_type_string16(type)) { + GB_ASSERT_MSG(are_types_identical(type, t_string16), "got %s", type_to_string(type)); + lbValue len = lb_string_len(p, base); + if (high.value == nullptr) high = len; + + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + + lbValue elem = lb_emit_ptr_offset(p, lb_string_elem(p, base), low); + lbValue new_len = (se->low == nullptr) + ? lb_emit_conv(p, high, t_int) + : lb_emit_arith(p, Token_Sub, high, low, t_int); + + return lb_make_string_value(p, t_string16, elem, new_len); + } + GB_ASSERT_MSG(are_types_identical(type, t_string), "got %s", type_to_string(type)); + lbValue len = lb_string_len(p, base); + if (high.value == nullptr) high = len; + + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + + lbValue elem = lb_emit_ptr_offset(p, lb_string_elem(p, base), low); + lbValue new_len = (se->low == nullptr) + ? lb_emit_conv(p, high, t_int) + : lb_emit_arith(p, Token_Sub, high, low, t_int); + + return lb_make_string_value(p, t_string, elem, new_len); + } + + case Type_MultiPointer: { + GB_ASSERT(se->high != nullptr); + Type *elem_type = type->MultiPointer.elem; + Type *slice_type = alloc_type_slice(elem_type); + + low = lb_emit_conv(p, low, t_int); + high = lb_emit_conv(p, high, t_int); + + lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high); + + LLVMValueRef indices[1] = {low.value}; + lbValue ptr = {}; + ptr.value = LLVMBuildGEP2(p->builder, lb_type(p->module, elem_type), base.value, indices, 1, ""); + ptr.type = alloc_type_pointer(elem_type); + + lbValue new_len = (se->low == nullptr) + ? lb_emit_conv(p, high, t_int) + : lb_emit_arith(p, Token_Sub, high, low, t_int); + + return lb_make_slice_value(p, slice_type, ptr, new_len); + } + + default: + GB_PANIC("lb_build_slice_expr_value: unexpected type %s", type_to_string(base.type)); + return {}; + } +} + gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { ast_node(se, SliceExpr, expr); @@ -4884,6 +5189,31 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { return slice; } + case Type_FixedCapacityDynamicArray: { + Type *elem_type = type->FixedCapacityDynamicArray.elem; + Type *slice_type = alloc_type_slice(elem_type); + + lbValue len = lb_fixed_capacity_dynamic_array_len(p, base); + if (high.value == nullptr) high = len; + + bool low_const = type_and_value_of_expr(se->low).mode == Addressing_Constant; + bool high_const = type_and_value_of_expr(se->high).mode == Addressing_Constant; + + if (!low_const || !high_const) { + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + } + lbValue data_ptr = lb_addr_get_ptr(p, addr); + lbValue array_ptr = lb_emit_struct_ep(p, data_ptr, 0); + lbValue elem = lb_emit_ptr_offset(p, lb_array_elem(p, array_ptr), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + lbAddr slice = lb_add_local_generated(p, slice_type, false); + lb_fill_slice(p, slice, elem, new_len); + return slice; + } + case Type_Basic: { if (is_type_string16(type)) { GB_ASSERT_MSG(are_types_identical(type, t_string16), "got %s", type_to_string(type)); @@ -4999,12 +5329,13 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { Type *et = nullptr; switch (bt->kind) { - case Type_Array: et = bt->Array.elem; break; - case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break; - case Type_Slice: et = bt->Slice.elem; break; - case Type_BitSet: et = bt->BitSet.elem; break; - case Type_SimdVector: et = bt->SimdVector.elem; break; - case Type_Matrix: et = bt->Matrix.elem; break; + case Type_Array: et = bt->Array.elem; break; + case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break; + case Type_Slice: et = bt->Slice.elem; break; + case Type_BitSet: et = bt->BitSet.elem; break; + case Type_SimdVector: et = bt->SimdVector.elem; break; + case Type_Matrix: et = bt->Matrix.elem; break; + case Type_FixedCapacityDynamicArray: et = bt->FixedCapacityDynamicArray.elem; break; } String proc_name = {}; @@ -5031,8 +5362,8 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { for (Ast *elem : cl->elems) { ast_node(fv, FieldValue, elem); - String name = fv->field->Ident.token.string; - Selection sel = lookup_field(bt, name, false); + InternedString interned = fv->field->Ident.interned; + Selection sel = lookup_field(bt, interned, false); GB_ASSERT(sel.is_bit_field); GB_ASSERT(!sel.indirect); GB_ASSERT(sel.index.count == 1); @@ -5098,13 +5429,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { for (isize i = 0; i < fields.count; i++) { auto const &f = fields[i]; - LLVMValueRef mask = LLVMConstInt(lit, 1, false); - #if LLVM_VERSION_MAJOR >= 19 - mask = LLVMBuildShl(p->builder, mask, LLVMConstInt(lit, f.bit_size, false), ""); - #else - mask = LLVMConstShl(mask, LLVMConstInt(lit, f.bit_size, false)); - #endif - mask = LLVMConstSub(mask, LLVMConstInt(lit, 1, false)); + LLVMValueRef mask = lb_const_low_bits_mask(lit, f.bit_size); LLVMValueRef elem = values[i].value; if (lb_sizeof(lit) < lb_sizeof(LLVMTypeOf(elem))) { @@ -5150,13 +5475,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { GB_ASSERT(mask_width > 0); bits_to_set -= mask_width; - LLVMValueRef mask = LLVMConstInt(vt, 1, false); - #if LLVM_VERSION_MAJOR >= 19 - mask = LLVMBuildShl(p->builder, mask, LLVMConstInt(vt, mask_width, false), ""); - #else - mask = LLVMConstShl(mask, LLVMConstInt(vt, mask_width, false)); - #endif - mask = LLVMConstSub(mask, LLVMConstInt(vt, 1, false)); + LLVMValueRef mask = lb_const_low_bits_mask(vt, mask_width); LLVMValueRef to_set = LLVMBuildAnd(p->builder, val, mask, ""); @@ -5237,8 +5556,8 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (elem->kind == Ast_FieldValue) { ast_node(fv, FieldValue, elem); - String name = fv->field->Ident.token.string; - Selection sel = lookup_field(bt, name, false); + InternedString interned = fv->field->Ident.interned; + Selection sel = lookup_field(bt, interned, false); GB_ASSERT(!sel.indirect); elem = fv->value; @@ -5295,11 +5614,20 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { Type *fet = field_expr.type; GB_ASSERT(fet->kind != Type_Tuple); - // HACK TODO(bill): THIS IS A MASSIVE HACK!!!! if (is_type_union(ft) && !are_types_identical(fet, ft) && !is_type_untyped(fet)) { - GB_ASSERT_MSG(union_variant_index(ft, fet) >= 0, "%s", type_to_string(fet)); + if (union_is_variant_of(ft, fet)) { + // NOTE(bill, 2026-03-15): If it's a direct assignment for a variant to the + // direct union we can just assign it directly to minimize wasted code generation + // + // TODO(bill): Allow this for deeply nested unions too e.g. union{union{T}} + GB_ASSERT_MSG(union_variant_index_checked(ft, fet) >= 0, "%s", type_to_string(fet)); + GB_ASSERT(are_types_identical(type_deref(gep.type), ft)); - lb_emit_store_union_variant(p, gep, field_expr, fet); + lb_emit_store_union_variant(p, gep, field_expr, fet); + } else { + lbValue fv = lb_emit_conv(p, field_expr, ft); + lb_emit_store(p, gep, fv); + } } else { lbValue fv = lb_emit_conv(p, field_expr, ft); lb_emit_store(p, gep, fv); @@ -5398,6 +5726,25 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { break; } + case Type_FixedCapacityDynamicArray: { + if (cl->elems.count > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); + + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + + lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type); + + lbValue dst_ptr = lb_addr_get_ptr(p, v); + for_array(i, temp_data) { + i32 index = cast(i32)(temp_data[i].elem_index); + temp_data[i].gep = lb_emit_array_epi(p, dst_ptr, index); + } + + lb_build_addr_compound_lit_assign_array(p, temp_data); + } + break; + } + case Type_DynamicArray: { if (cl->elems.count == 0) { break; @@ -5464,12 +5811,12 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (elem->kind == Ast_FieldValue) { ast_node(fv, FieldValue, elem); - Selection sel = lookup_field(bt, fv->field->Ident.token.string, false); + Selection sel = lookup_field(bt, fv->field->Ident.interned, false); index = sel.index[0]; elem = fv->value; } else { TypeAndValue tav = type_and_value_of_expr(elem); - Selection sel = lookup_field(bt, field_names[field_index], false); + Selection sel = lookup_field(bt, string_interner_insert(field_names[field_index]), false); index = sel.index[0]; } @@ -5611,7 +5958,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { case_ast_node(se, SelectorExpr, expr); Ast *sel_node = unparen_expr(se->selector); if (sel_node->kind == Ast_Ident) { - String selector = sel_node->Ident.token.string; + InternedString selector = sel_node->Ident.interned; TypeAndValue tav = type_and_value_of_expr(se->expr); if (tav.mode == Addressing_Invalid) { @@ -5631,7 +5978,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { GB_ASSERT(e->kind == Entity_Procedure); return lb_addr(lb_find_value_from_entity(p->module, e)); } - GB_PANIC("Unreachable %.*s", LIT(selector)); + GB_PANIC("Unreachable %s", selector.cstring()); } if (se->swizzle_count > 0) { @@ -6026,4 +6373,3 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { return {}; } - diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 4ebb40d96..8feadf6a4 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -163,10 +163,10 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { map_init(&gen->modules_through_ctx, gen->info->packages.count*2); if (USE_SEPARATE_MODULES) { - bool module_per_file = build_context.module_per_file && build_context.optimization_level <= 0; + bool module_per_file = build_context.module_per_file && (build_context.optimization_level <= 0 || build_context.lto_kind != LTO_None); for (auto const &entry : gen->info->packages) { AstPackage *pkg = entry.value; - auto m = gb_alloc_item(permanent_allocator(), lbModule); + auto m = permanent_alloc_item(); m->pkg = pkg; m->gen = gen; m->checker = c; @@ -174,7 +174,7 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { lb_init_module(m, do_threading); if (LLVM_WEAK_MONOMORPHIZATION) { - auto pm = gb_alloc_item(permanent_allocator(), lbModule); + auto pm = permanent_alloc_item(); pm->pkg = pkg; pm->gen = gen; pm->checker = c; @@ -216,7 +216,7 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { } // NOTE(bill): Probably per file is not a good idea, so leave this for later for (AstFile *file : pkg->files) { - auto m = gb_alloc_item(permanent_allocator(), lbModule); + auto m = permanent_alloc_item(); m->file = file; m->pkg = pkg; m->gen = gen; @@ -226,7 +226,7 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { if (LLVM_WEAK_MONOMORPHIZATION) { - auto pm = gb_alloc_item(permanent_allocator(), lbModule); + auto pm = permanent_alloc_item(); pm->file = file; pm->pkg = pkg; pm->gen = gen; @@ -242,7 +242,7 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { } if (LLVM_WEAK_MONOMORPHIZATION) { - lbModule *m = gb_alloc_item(permanent_allocator(), lbModule); + lbModule *m = permanent_alloc_item(); gen->equal_module = m; m->gen = gen; m->checker = c; @@ -498,10 +498,11 @@ gb_internal lbModule *lb_module_of_expr(lbGenerator *gen, Ast *expr) { gb_internal lbModule *lb_module_of_entity_internal(lbGenerator *gen, Entity *e, lbModule *curr_module) { lbModule **found = nullptr; - if (e->kind == Entity_Procedure && - e->decl_info && - e->decl_info->code_gen_module) { - return e->decl_info->code_gen_module; + if (e->kind == Entity_Procedure && e->decl_info) { + lbModule *mod = e->decl_info->code_gen_module.load(std::memory_order_relaxed); + if (mod) { + return mod; + } } if (e->file) { found = map_get(&gen->modules, cast(void *)e->file); @@ -700,11 +701,45 @@ gb_internal void lb_set_file_line_col(lbProcedure *p, Array arr, TokenP arr[2] = lb_const_int(p->module, t_i32, col); } -gb_internal void lb_emit_bounds_check(lbProcedure *p, Token token, lbValue index, lbValue len) { +gb_internal bool lb_bounds_check_short_circuit(lbProcedure *p, lbValue index, lbValue len) { if (build_context.no_bounds_check) { - return; + return true; } if ((p->state_flags & StateFlag_no_bounds_check) != 0) { + return true; + } + + if (LLVMIsConstant(index.value) && LLVMIsConstant(len.value)) { + i64 i = LLVMConstIntGetSExtValue(index.value); + i64 n = LLVMConstIntGetSExtValue(len.value); + if (0 <= i && i < n) { + return true; + } + } + + if (LLVMIsAInstruction(index.value)) { + LLVMOpcode op = LLVMGetInstructionOpcode(index.value); + if (op == LLVMURem) { + LLVMValueRef divisor = LLVMGetOperand(index.value, 1); + if (divisor == len.value) { + return true; + } + } else if (op == LLVMAnd) { + LLVMValueRef mask = LLVMGetOperand(index.value, 1); + if (LLVMIsConstant(mask) && LLVMIsConstant(len.value)) { + i64 m = LLVMConstIntGetSExtValue(mask); + i64 l = LLVMConstIntGetSExtValue(len.value); + if (l > 0 && (l & (l-1)) == 0 && m == l-1) { + return true; + } + } + } + } + return false; +} + +gb_internal void lb_emit_bounds_check(lbProcedure *p, Token token, lbValue index, lbValue len) { + if (lb_bounds_check_short_circuit(p, index, len)) { return; } @@ -755,6 +790,15 @@ gb_internal void lb_emit_multi_pointer_slice_bounds_check(lbProcedure *p, Token return; } + if (LLVMIsConstant(low.value) && LLVMIsConstant(high.value)) { + i64 i = LLVMConstIntGetSExtValue(low.value); + i64 n = LLVMConstIntGetSExtValue(high.value); + if (i < n) { + return; + } + } + + low = lb_emit_conv(p, low, t_int); high = lb_emit_conv(p, high, t_int); @@ -767,12 +811,15 @@ gb_internal void lb_emit_multi_pointer_slice_bounds_check(lbProcedure *p, Token } gb_internal void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValue high, lbValue len, bool lower_value_used) { - if (build_context.no_bounds_check) { - return; - } - if ((p->state_flags & StateFlag_no_bounds_check) != 0) { + if (!lower_value_used && lb_bounds_check_short_circuit(p, high, len)) { return; } + // if (lower_value_used && + // lb_bounds_check_short_circuit(p, low, high) && + // lb_bounds_check_short_circuit(p, low, len) && + // lb_bounds_check_short_circuit(p, high, len)) { + // return; + // } high = lb_emit_conv(p, high, t_int); @@ -1497,7 +1544,7 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { } gb_internal lbValue lb_const_union_tag(lbModule *m, Type *u, Type *v) { - return lb_const_value(m, union_tag_type(u), exact_value_i64(union_variant_index(u, v))); + return lb_const_value(m, union_tag_type(u), exact_value_i64(union_variant_index_checked(u, v))); } gb_internal lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) { @@ -1540,13 +1587,17 @@ gb_internal void lb_emit_store_union_variant_tag(lbProcedure *p, lbValue parent, // No tag needed! } else { lbValue tag_ptr = lb_emit_union_tag_ptr(p, parent); - lb_emit_store(p, tag_ptr, lb_const_union_tag(p->module, t, variant_type)); + lbValue tag = lb_const_union_tag(p->module, t, variant_type); + lb_emit_store(p, tag_ptr, tag); } } gb_internal void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbValue variant, Type *variant_type) { Type *pt = base_type(type_deref(parent.type)); GB_ASSERT(pt->kind == Type_Union); + + GB_ASSERT_MSG(union_is_variant_of(pt, variant_type), "%s %s", type_to_string(pt), type_to_string(variant_type)); + if (pt->Union.kind == UnionType_shared_nil) { GB_ASSERT(type_size_of(variant_type)); @@ -1716,13 +1767,13 @@ gb_internal LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *t "\n\tArgTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", LLVMPrintTypeToString(arg.type), j, ft->args.count, - LLVMGetTypeContext(arg.type), ft->ctx, LLVMGetGlobalContext()); + LLVMGetTypeContext(arg.type), ft->ctx); } GB_ASSERT_MSG(LLVMGetTypeContext(ft->ret.type) == ft->ctx, "\n\t%s" "\n\tRetTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", LLVMPrintTypeToString(ft->ret.type), - LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext()); + LLVMGetTypeContext(ft->ret.type), ft->ctx); } for (unsigned i = 0; i < param_count; i++) { if (params_by_ptr[i]) { @@ -1740,7 +1791,7 @@ gb_internal LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *t GB_ASSERT_MSG(LLVMGetTypeContext(new_abi_fn_type) == m->ctx, "\n\tFuncTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", - LLVMGetTypeContext(new_abi_fn_type), m->ctx, LLVMGetGlobalContext()); + LLVMGetTypeContext(new_abi_fn_type), m->ctx); map_set(&m->func_raw_types, type, new_abi_fn_type); @@ -2234,6 +2285,26 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { } break; + case Type_FixedCapacityDynamicArray: + { + unsigned field_count = 0; + + LLVMTypeRef fields[3] = {}; + m->internal_type_level += 1; + fields[field_count++] = llvm_array_type(lb_type(m, type->FixedCapacityDynamicArray.elem), type->FixedCapacityDynamicArray.capacity); + m->internal_type_level -= 1; + + gb_unused(type_size_of(type)); + if (type->FixedCapacityDynamicArray.padding_needed > 0) { + fields[field_count++] = lb_type_padding_filler(m, type->FixedCapacityDynamicArray.padding_needed, 1); // padding + } + + fields[field_count++] = lb_type(m, t_int); // len + + return LLVMStructTypeInContext(ctx, fields, field_count, false); + } + break; + case Type_Map: init_map_internal_debug_types(type); GB_ASSERT(t_raw_map != nullptr); @@ -2628,6 +2699,8 @@ gb_internal bool lb_apply_thread_local_model(LLVMValueRef value, String model) { LLVMThreadLocalMode mode = LLVMGeneralDynamicTLSModel; if (model == "default") { mode = LLVMGeneralDynamicTLSModel; + } else if (model == "globaldynamic") { + mode = LLVMGeneralDynamicTLSModel; } else if (model == "localdynamic") { mode = LLVMLocalDynamicTLSModel; } else if (model == "initialexec") { @@ -2655,7 +2728,7 @@ gb_internal void lb_add_edge(lbBlock *from, lbBlock *to) { gb_internal lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append) { - lbBlock *b = gb_alloc_item(permanent_allocator(), lbBlock); + lbBlock *b = permanent_alloc_item(); b->block = LLVMCreateBasicBlockInContext(p->module->ctx, name); b->appended = false; if (append) { @@ -3333,7 +3406,7 @@ gb_internal lbAddr lb_add_global_generated_from_procedure(lbProcedure *p, Type * gb_internal lbValue lb_find_runtime_value(lbModule *m, String const &name) { AstPackage *p = m->info->runtime_package; - Entity *e = scope_lookup_current(p->scope, name); + Entity *e = scope_lookup_current(p->scope, string_interner_insert(name)); return lb_find_value_from_entity(m, e); } gb_internal lbValue lb_find_package_value(lbModule *m, String const &pkg, String const &name) { @@ -3540,7 +3613,30 @@ gb_internal lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero } gb_internal lbAddr lb_add_local_generated(lbProcedure *p, Type *type, bool zero_init) { +#if 0 return lb_add_local(p, type, nullptr, zero_init); +#else + LLVMTypeRef llvm_type = lb_type(p->module, type); + + unsigned alignment = cast(unsigned)gb_max(type_align_of(type), lb_alignof(llvm_type)); + if (is_type_matrix(type)) { + alignment *= 2; // NOTE(bill): Just in case + } + + // This positions in the entry block, emits alloca, then restores position. + LLVMValueRef ptr = llvm_alloca(p, llvm_type, alignment, ""); + + if (zero_init) { + // Emit the zero-init store at the current position (not entry block) + // so it respects control flow. But the alloca itself is in entry. + lb_mem_zero_ptr(p, ptr, type, alignment); + } + + lbValue val = {}; + val.value = ptr; + val.type = alloc_type_pointer(type); + return lb_addr(val); +#endif } gb_internal lbAddr lb_add_local_generated_temp(lbProcedure *p, Type *type, i64 min_alignment) { diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp index 4971b1f10..cb7fe1c75 100644 --- a/src/llvm_backend_opt.cpp +++ b/src/llvm_backend_opt.cpp @@ -309,7 +309,15 @@ gb_internal void lb_run_remove_dead_instruction_pass(lbProcedure *p) { // NOTE(bill): Explicit instructions are set here because some instructions could have side effects switch (LLVMGetInstructionOpcode(curr_instr)) { - // case LLVMAlloca: + case LLVMAlloca: + if (map_get(&p->tuple_fix_map, curr_instr) != nullptr) { + // NOTE(bill, 2025-12-27): Remove temporary tuple fix alloca instructions + // if they are never used + removal_count += 1; + LLVMInstructionEraseFromParent(curr_instr); + was_dead_instructions = true; + } + break; case LLVMLoad: if (LLVMGetVolatile(curr_instr)) { break; @@ -504,8 +512,9 @@ gb_internal void llvm_delete_function(LLVMValueRef func) { LLVMDeleteFunction(func); } -gb_internal void lb_append_to_compiler_used(lbModule *m, LLVMValueRef value) { - LLVMValueRef global = LLVMGetNamedGlobal(m->mod, "llvm.compiler.used"); +// Helper to append a value to an llvm metadata array global (llvm.used or llvm.compiler.used) +gb_internal void lb_append_to_llvm_used_list(lbModule *m, LLVMValueRef value, char const *list_name) { + LLVMValueRef global = LLVMGetNamedGlobal(m->mod, list_name); LLVMValueRef *constants; int operands = 1; @@ -535,33 +544,43 @@ gb_internal void lb_append_to_compiler_used(lbModule *m, LLVMValueRef value) { constants[operands - 1] = LLVMConstBitCast(value, Int8PtrTy); LLVMValueRef initializer = LLVMConstArray(Int8PtrTy, constants, operands); - global = LLVMAddGlobal(m->mod, ATy, "llvm.compiler.used"); + global = LLVMAddGlobal(m->mod, ATy, list_name); LLVMSetLinkage(global, LLVMAppendingLinkage); LLVMSetSection(global, "llvm.metadata"); LLVMSetInitializer(global, initializer); } +gb_internal void lb_append_to_compiler_used(lbModule *m, LLVMValueRef value) { + lb_append_to_llvm_used_list(m, value, "llvm.compiler.used"); +} + +// llvm.used survives LTO linker optimizations (unlike llvm.compiler.used) +gb_internal void lb_append_to_used(lbModule *m, LLVMValueRef value) { + lb_append_to_llvm_used_list(m, value, "llvm.used"); +} + gb_internal void lb_run_remove_unused_function_pass(lbModule *m) { isize removal_count = 0; isize pass_count = 0; isize const max_pass_count = 10; - // Custom remove dead function pass + + // Custom remove dead function pass (for internal linkage functions) for (; pass_count < max_pass_count; pass_count++) { - bool was_dead = false; + bool was_dead = false; for (LLVMValueRef func = LLVMGetFirstFunction(m->mod); func != nullptr; /**/ ) { LLVMValueRef curr_func = func; func = LLVMGetNextFunction(func); - + LLVMUseRef first_use = LLVMGetFirstUse(curr_func); if (first_use != nullptr) { continue; } String name = {}; name.text = cast(u8 *)LLVMGetValueName2(curr_func, cast(size_t *)&name.len); - + if (LLVMIsDeclaration(curr_func)) { // Ignore for the time being continue; @@ -570,7 +589,7 @@ gb_internal void lb_run_remove_unused_function_pass(lbModule *m) { if (linkage != LLVMInternalLinkage) { continue; } - + Entity **found = map_get(&m->procedure_values, curr_func); if (found && *found) { Entity *e = *found; @@ -580,7 +599,7 @@ gb_internal void lb_run_remove_unused_function_pass(lbModule *m) { continue; } } - + llvm_delete_function(curr_func); was_dead = true; removal_count += 1; diff --git a/src/llvm_backend_passes.cpp b/src/llvm_backend_passes.cpp index e9edbace7..5001e29b0 100644 --- a/src/llvm_backend_passes.cpp +++ b/src/llvm_backend_passes.cpp @@ -4,6 +4,9 @@ break; case 0: array_add(&passes, "always-inline"); + if (build_context.internal_llvm_mem2reg) { + array_add(&passes, "function(mem2reg)"); + } array_add(&passes, "function(annotation-remarks)"); break; case 1: @@ -263,7 +266,7 @@ function( ), verify )"); -#else // LLVM 20 & 21 (same config) +#elif LLVM_VERSION_MAJOR < 22 // LLVM 20 & 21 (same config) array_add(&passes, u8R"( annotation2metadata, forceattrs, @@ -395,6 +398,144 @@ function( verify )"); +#else // LLVM 22 +// Passes removed: coro, openmp + array_add(&passes, u8R"( +memprof-remove-attributes, +annotation2metadata, +forceattrs, +inferattrs, +function( + ee-instrument<>, + lower-expect, + simplifycfg, + sroa, + early-cse<> +), +ipsccp, +called-value-propagation, +globalopt, +function( + mem2reg, + instcombine, + simplifycfg +), +always-inline, +require, +function( + invalidate +), +require, +cgscc( + devirt<4>( + inline, + function-attrs, + function( + sroa, + early-cse, + speculative-execution, + jump-threading, + correlated-propagation, + simplifycfg, + instcombine, + aggressive-instcombine, + tailcallelim, + simplifycfg, + reassociate, + constraint-elimination, + loop-mssa( + loop-instsimplify, + loop-simplifycfg, + licm, + loop-rotate, + licm, + simple-loop-unswitch + ), + simplifycfg, + instcombine, + loop( + loop-idiom, + indvars, + extra-simple-loop-unswitch-passes, + loop-deletion, + loop-unroll-full + ), + sroa, + vector-combine, + mldst-motion, + gvn<>, + sccp, + bdce, + instcombine, + jump-threading, + correlated-propagation, + adce, + memcpyopt, + dse, + move-auto-init, + loop-mssa( + licm + ), + simplifycfg, + instcombine + ), + function-attrs, + function( + require + ) + ) +), +deadargelim, +globalopt, +globaldce, +elim-avail-extern, +rpo-function-attrs, +recompute-globalsaa, +function( + drop-unnecessary-assumes, + float2int, + lower-constant-intrinsics, + loop( + loop-rotate, + loop-deletion + ), + loop-distribute, + inject-tli-mappings, + loop-vectorize, + drop-unnecessary-assumes, + infer-alignment, + loop-load-elim, + instcombine, + simplifycfg, + slp-vectorizer, + vector-combine, + instcombine, + loop-unroll, + transform-warning, + sroa, + infer-alignment, + instcombine, + loop-mssa( + licm + ), + alignment-from-assumptions, + loop-sink, + instsimplify, + div-rem-pairs, + tailcallelim, + simplifycfg +), +alloc-token, +globaldce, +constmerge, +cg-profile, +rel-lookup-table-converter, +function( + annotation-remarks +), +verify +)"); + #endif break; // default @@ -656,7 +797,7 @@ function( ), verify )"); -#else // LLVM 20 & 21 (same config) +#elif LLVM_VERSION_MAJOR < 22 // LLVM 20 & 21 (same config) array_add(&passes, u8R"( annotation2metadata, forceattrs, @@ -789,6 +930,145 @@ function( ), verify )"); + +#else // LLVM 22 +// Passes removed: coro, openmp + array_add(&passes, u8R"( +memprof-remove-attributes, +annotation2metadata, +forceattrs, +inferattrs, +function( + ee-instrument<>, + lower-expect, + simplifycfg, + sroa, + early-cse<> +), +ipsccp, +called-value-propagation, +globalopt, +function( + mem2reg, + instcombine, + simplifycfg +), +always-inline, +require, +function( + invalidate +), +require, +cgscc( + devirt<4>( + inline, + function-attrs, + function( + sroa, + early-cse, + speculative-execution, + jump-threading, + correlated-propagation, + simplifycfg, + instcombine, + aggressive-instcombine, + libcalls-shrinkwrap, + tailcallelim, + simplifycfg, + reassociate, + constraint-elimination, + loop-mssa( + loop-instsimplify, + loop-simplifycfg, + licm, + loop-rotate, + licm, + simple-loop-unswitch + ), + simplifycfg, + instcombine, + loop( + loop-idiom, + indvars, + extra-simple-loop-unswitch-passes, + loop-deletion, + loop-unroll-full + ), + sroa, + vector-combine, + mldst-motion, + gvn<>, + sccp, + bdce, + instcombine, + jump-threading, + correlated-propagation, + adce, + memcpyopt, + dse, + move-auto-init, + loop-mssa( + licm + ), + simplifycfg, + instcombine + ), + function-attrs, + function( + require + ) + ) +), +deadargelim, +globalopt, +globaldce, +elim-avail-extern, +rpo-function-attrs, +recompute-globalsaa, +function( + drop-unnecessary-assumes, + float2int, + lower-constant-intrinsics, + loop( + loop-rotate, + loop-deletion + ), + loop-distribute, + inject-tli-mappings, + loop-vectorize, + drop-unnecessary-assumes, + infer-alignment, + loop-load-elim, + instcombine, + simplifycfg, + slp-vectorizer, + vector-combine, + instcombine, + loop-unroll, + transform-warning, + sroa, + infer-alignment, + instcombine, + loop-mssa( + licm + ), + alignment-from-assumptions, + loop-sink, + instsimplify, + div-rem-pairs, + tailcallelim, + simplifycfg +), +alloc-token, +globaldce, +constmerge, +cg-profile, +rel-lookup-table-converter, +function( + annotation-remarks +), +verify +)"); #endif break; @@ -1052,7 +1332,7 @@ function( ), verify )"); -#else // LLVM 20 & 21 (same config) +#elif LLVM_VERSION_MAJOR < 22 // LLVM 20 & 21 (same config) array_add(&passes, u8R"( annotation2metadata, forceattrs, @@ -1190,6 +1470,148 @@ verify )"); +#else // LLVM 22 +// Passes removed: coro, openmp + array_add(&passes, u8R"( +memprof-remove-attributes, +annotation2metadata, +forceattrs, +inferattrs, +function( + ee-instrument<>, + lower-expect, + simplifycfg, + sroa, + early-cse<>, + callsite-splitting +), +ipsccp, +called-value-propagation, +globalopt, +function( + mem2reg, + instcombine, + simplifycfg +), +always-inline, +require, +function( + invalidate +), +require, +cgscc( + devirt<4>( + inline, + function-attrs, + argpromotion, + function( + sroa, + early-cse, + speculative-execution, + jump-threading, + correlated-propagation, + simplifycfg, + instcombine, + aggressive-instcombine, + libcalls-shrinkwrap, + tailcallelim, + simplifycfg, + reassociate, + constraint-elimination, + loop-mssa( + loop-instsimplify, + loop-simplifycfg, + licm, + loop-rotate, + licm, + simple-loop-unswitch + ), + simplifycfg, + instcombine, + loop( + loop-idiom, + indvars, + extra-simple-loop-unswitch-passes, + loop-deletion, + loop-unroll-full + ), + sroa, + vector-combine, + mldst-motion, + gvn<>, + sccp, + bdce, + instcombine, + jump-threading, + correlated-propagation, + adce, + memcpyopt, + dse, + move-auto-init, + loop-mssa( + licm + ), + simplifycfg, + instcombine + ), + function-attrs, + function( + require + ) + ) +), +deadargelim, +globalopt, +globaldce, +elim-avail-extern, +rpo-function-attrs, +recompute-globalsaa, +function( + drop-unnecessary-assumes, + float2int, + lower-constant-intrinsics, + chr, + loop( + loop-rotate, + loop-deletion + ), + loop-distribute, + inject-tli-mappings, + loop-vectorize, + drop-unnecessary-assumes, + infer-alignment, + loop-load-elim, + instcombine, + simplifycfg, + slp-vectorizer, + vector-combine, + instcombine, + loop-unroll, + transform-warning, + sroa, + infer-alignment, + instcombine, + loop-mssa( + licm + ), + alignment-from-assumptions, + loop-sink, + instsimplify, + div-rem-pairs, + tailcallelim, + simplifycfg +), +alloc-token, +globaldce, +constmerge, +cg-profile, +rel-lookup-table-converter, +function( + annotation-remarks +), +verify +)"); + #endif break; } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 27167aefd..7d0379e9a 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -12,9 +12,9 @@ gb_internal void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue sr len = lb_emit_conv(p, len, t_int); char const *name = "llvm.memmove"; - if (LLVMIsConstant(len.value)) { + if (!p->is_startup && LLVMIsConstant(len.value)) { i64 const_len = cast(i64)LLVMConstIntGetSExtValue(len.value); - if (const_len <= 4*build_context.int_size) { + if (const_len <= lb_max_zero_init_size()) { name = "llvm.memmove.inline"; } } @@ -41,9 +41,9 @@ gb_internal void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValu len = lb_emit_conv(p, len, t_int); char const *name = "llvm.memcpy"; - if (LLVMIsConstant(len.value)) { + if (!p->is_startup && LLVMIsConstant(len.value)) { i64 const_len = cast(i64)LLVMConstIntGetSExtValue(len.value); - if (const_len <= 4*build_context.int_size) { + if (const_len <= lb_max_zero_init_size()) { name = "llvm.memcpy.inline"; } } @@ -99,7 +99,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i } } - lbProcedure *p = gb_alloc_item(permanent_allocator(), lbProcedure); + lbProcedure *p = permanent_alloc_item(); p->module = m; entity->code_gen_module = m; @@ -117,6 +117,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i p->type_expr = decl->type_expr; p->body = pl->body; p->inlining = pl->inlining; + p->tailing = pl->tailing; p->is_foreign = entity->Procedure.is_foreign; p->is_export = entity->Procedure.is_export; p->is_entry_point = false; @@ -152,6 +153,10 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i lb_ensure_abi_function_type(m, p); lb_add_function_type_attributes(p->value, p->abi_function_type, p->abi_function_type->calling_convention); + if (build_context.disable_unwind) { + lb_add_attribute_to_proc(m, p->value, "nounwind"); + } + if (pt->Proc.diverging) { lb_add_attribute_to_proc(m, p->value, "noreturn"); } @@ -196,12 +201,15 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i for (;;) { String str = string_split_iterator(&it, ','); if (str == "") break; + bool add_prefix = !(string_starts_with(str, '+') || string_starts_with(str, '-')); if (!first) { feature_str = gb_string_appendc(feature_str, ","); } first = false; - feature_str = gb_string_appendc(feature_str, "+"); + if (add_prefix) { + feature_str = gb_string_appendc(feature_str, "+"); + } feature_str = gb_string_append_length(feature_str, str.text, str.len); } @@ -284,6 +292,19 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i lb_set_linkage_from_entity_flags(p->module, p->value, entity->flags); + // With LTO on all platforms, required procedures with external linkage need to be added to + // llvm.used to survive linker-level dead code elimination. This is necessary because + // LLVM may generate implicit calls to runtime builtins (e.g., __extendhfsf2 for f16 + // conversions) during instruction lowering, after the IR is finalized. + if (build_context.lto_kind != LTO_None) { + if (entity->flags & EntityFlag_Require) { + LLVMLinkage linkage = LLVMGetLinkage(p->value); + if (linkage != LLVMInternalLinkage) { + lb_append_to_used(m, p->value); + } + } + } + if (m->debug_builder) { // Debug Information Type *bt = base_type(p->type); @@ -346,7 +367,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i if (build_context.sanitizer_flags & SanitizerFlag_Memory && !entity->Procedure.no_sanitize_memory) { lb_add_attribute_to_proc(m, p->value, "sanitize_memory"); } - if (build_context.sanitizer_flags & SanitizerFlag_Thread) { + if (build_context.sanitizer_flags & SanitizerFlag_Thread && !entity->Procedure.no_sanitize_thread) { lb_add_attribute_to_proc(m, p->value, "sanitize_thread"); } } @@ -377,7 +398,7 @@ gb_internal lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name GB_ASSERT_MSG(found == nullptr, "failed to create dummy procedure for: %.*s", LIT(link_name)); } - lbProcedure *p = gb_alloc_item(permanent_allocator(), lbProcedure); + lbProcedure *p = permanent_alloc_item(); p->module = m; p->name = link_name; @@ -387,6 +408,7 @@ gb_internal lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name p->body = nullptr; p->tags = 0; p->inlining = ProcInlining_none; + p->tailing = ProcTailing_none; p->is_foreign = false; p->is_export = false; p->is_entry_point = false; @@ -670,7 +692,7 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) { lbAddr res = {}; if (p->entity && p->entity->decl_info && - p->entity->decl_info->defer_use_checked && + p->entity->decl_info->defer_use_checked.load(std::memory_order_relaxed) && p->entity->decl_info->defer_used == 0) { // NOTE(bill): this is a bodge to get around the issue of the problem BELOW @@ -855,7 +877,7 @@ gb_internal Array lb_value_to_array(lbProcedure *p, gbAllocator const & -gb_internal lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, Array const &processed_args, Type *abi_rt, lbAddr context_ptr, ProcInlining inlining) { +gb_internal lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, Array const &processed_args, Type *abi_rt, lbAddr context_ptr, ProcInlining inlining, ProcTailing tailing) { GB_ASSERT(p->module->ctx == LLVMGetTypeContext(LLVMTypeOf(value.value))); unsigned arg_count = cast(unsigned)processed_args.count; @@ -972,6 +994,17 @@ gb_internal lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue break; } + switch (tailing) { + case ProcTailing_none: + break; + case ProcTailing_must_tail: + LLVMSetTailCall(ret, true); + #if LLVM_VERSION_MAJOR > 17 + LLVMSetTailCallKind(ret, LLVMTailCallKindMustTail); + #endif + break; + } + lbValue res = {}; res.value = ret; res.type = abi_rt; @@ -982,7 +1015,7 @@ gb_internal lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue gb_internal lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name) { AstPackage *pkg = m->info->runtime_package; - Entity *e = scope_lookup_current(pkg->scope, name); + Entity *e = scope_lookup_current(pkg->scope, string_interner_insert(name)); GB_ASSERT_MSG(e != nullptr, "Runtime procedure not found: %s", name); return lb_find_procedure_value_from_entity(m, e); } @@ -998,15 +1031,14 @@ gb_internal lbValue lb_emit_conjugate(lbProcedure *p, lbValue val, Type *type) { lbValue res = {}; Type *t = val.type; if (is_type_complex(t)) { - res = lb_addr_get_ptr(p, lb_add_local_generated(p, type, false)); lbValue real = lb_emit_struct_ev(p, val, 0); lbValue imag = lb_emit_struct_ev(p, val, 1); imag = lb_emit_unary_arith(p, Token_Sub, imag, imag.type); - lb_emit_store(p, lb_emit_struct_ep(p, res, 0), real); - lb_emit_store(p, lb_emit_struct_ep(p, res, 1), imag); + + lbValue fields[2] = {real, imag}; + return lb_build_struct_value(p, type, fields, gb_count_of(fields)); } else if (is_type_quaternion(t)) { // @QuaternionLayout - res = lb_addr_get_ptr(p, lb_add_local_generated(p, type, false)); lbValue real = lb_emit_struct_ev(p, val, 3); lbValue imag = lb_emit_struct_ev(p, val, 0); lbValue jmag = lb_emit_struct_ev(p, val, 1); @@ -1014,10 +1046,9 @@ gb_internal lbValue lb_emit_conjugate(lbProcedure *p, lbValue val, Type *type) { imag = lb_emit_unary_arith(p, Token_Sub, imag, imag.type); jmag = lb_emit_unary_arith(p, Token_Sub, jmag, jmag.type); kmag = lb_emit_unary_arith(p, Token_Sub, kmag, kmag.type); - lb_emit_store(p, lb_emit_struct_ep(p, res, 3), real); - lb_emit_store(p, lb_emit_struct_ep(p, res, 0), imag); - lb_emit_store(p, lb_emit_struct_ep(p, res, 1), jmag); - lb_emit_store(p, lb_emit_struct_ep(p, res, 2), kmag); + + lbValue fields[4] = {imag, jmag, kmag, real}; + return lb_build_struct_value(p, type, fields, gb_count_of(fields)); } else if (is_type_array_like(t)) { res = lb_addr_get_ptr(p, lb_add_local_generated(p, type, true)); Type *elem_type = base_array_type(t); @@ -1045,7 +1076,7 @@ gb_internal lbValue lb_emit_conjugate(lbProcedure *p, lbValue val, Type *type) { return lb_emit_load(p, res); } -gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, ProcInlining inlining) { +gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, ProcInlining inlining, ProcTailing tailing, lbValue *sret_dst) { lbModule *m = p->module; Type *pt = base_type(value.type); @@ -1167,11 +1198,16 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array c } if (return_by_pointer) { - lbValue return_ptr = lb_add_local_generated(p, rt, true).addr; - lb_emit_call_internal(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining); + lbValue return_ptr = {}; + if (sret_dst != nullptr) { + return_ptr = *sret_dst; + } else { + return_ptr = lb_add_local_generated(p, rt, true).addr; + } + lb_emit_call_internal(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining, tailing); result = lb_emit_load(p, return_ptr); } else if (rt != nullptr) { - result = lb_emit_call_internal(p, value, {}, processed_args, rt, context_ptr, inlining); + result = lb_emit_call_internal(p, value, {}, processed_args, rt, context_ptr, inlining, tailing); if (ft->ret.cast_type) { result.value = OdinLLVMBuildTransmute(p, result.value, ft->ret.cast_type); } @@ -1184,7 +1220,7 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array c result = lb_emit_conv(p, result, rt); } } else { - lb_emit_call_internal(p, value, {}, processed_args, nullptr, context_ptr, inlining); + lb_emit_call_internal(p, value, {}, processed_args, nullptr, context_ptr, inlining, tailing); } if (original_rt != rt) { @@ -1212,15 +1248,6 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array c } tuple_fix_values[ret_count-1] = result; - #if 0 - for (isize j = 0; j < ret_count; j++) { - tuple_geps[j] = lb_emit_struct_ep(p, result_ptr, cast(i32)j); - } - for (isize j = 0; j < ret_count; j++) { - lb_emit_store(p, tuple_geps[j], tuple_fix_values[j]); - } - #endif - result = lb_emit_load(p, result_ptr); lbTupleFix tf = {tuple_fix_values}; @@ -1282,7 +1309,7 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array c } } - lb_add_defer_proc(p, p->scope_index, deferred, result_as_args); + lb_add_defer_proc(p, p->scope_index, deferred, result_as_args, e->token.pos); } } @@ -2209,8 +2236,10 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu Entity *e = entity_of_node(ident); GB_ASSERT(e != nullptr); - if (e->parent_proc_decl != nullptr && e->parent_proc_decl->entity != nullptr) { - procedure = e->parent_proc_decl->entity.load()->token.string; + DeclInfo *parent_proc_decl = e->parent_proc_decl.load(std::memory_order_relaxed); + if (parent_proc_decl != nullptr && + parent_proc_decl->entity != nullptr) { + procedure = parent_proc_decl->entity.load()->token.string; } else { procedure = str_lit(""); } @@ -2300,6 +2329,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu return lb_slice_len(p, v); } else if (is_type_dynamic_array(t)) { return lb_dynamic_array_len(p, v); + } else if (is_type_fixed_capacity_dynamic_array(t)) { + return lb_fixed_capacity_dynamic_array_len(p, v); } else if (is_type_map(t)) { return lb_map_len(p, v); } else if (is_type_soa_struct(t)) { @@ -2321,6 +2352,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu GB_PANIC("Unreachable"); } else if (is_type_array(t)) { GB_PANIC("Array lengths are constant"); + } else if (is_type_fixed_capacity_dynamic_array(t)) { + GB_PANIC("Fixed capacity dynamic array capacities are constant"); } else if (is_type_slice(t)) { return lb_slice_len(p, v); } else if (is_type_dynamic_array(t)) { @@ -2840,6 +2873,12 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_count_leading_zeros: return lb_emit_count_leading_zeros(p, lb_build_expr(p, ce->args[0]), tv.type); + case BuiltinProc_count_trailing_ones: + return lb_emit_count_trailing_ones(p, lb_build_expr(p, ce->args[0]), tv.type); + case BuiltinProc_count_leading_ones: + return lb_emit_count_leading_ones(p, lb_build_expr(p, ce->args[0]), tv.type); + + case BuiltinProc_count_ones: return lb_emit_count_ones(p, lb_build_expr(p, ce->args[0]), tv.type); case BuiltinProc_count_zeros: @@ -3336,6 +3375,24 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu return lb_emit_conv(p, res, t); } + case BuiltinProc_likely: + case BuiltinProc_unlikely: + { + Type *t = default_type(tv.type); + lbValue x = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t); + lbValue y = lb_const_bool(p->module, t, id == BuiltinProc_likely); + + char const *name = "llvm.expect"; + + LLVMTypeRef types[1] = {lb_type(p->module, t)}; + lbValue res = {}; + LLVMValueRef args[2] = { x.value, y.value }; + + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); + res.type = t; + return lb_emit_conv(p, res, t); + } + case BuiltinProc_prefetch_read_instruction: case BuiltinProc_prefetch_read_data: case BuiltinProc_prefetch_write_instruction: @@ -4077,13 +4134,13 @@ gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, } -gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr); +gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr, lbValue *sret_dst = nullptr); -gb_internal lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) { +gb_internal lbValue lb_build_call_expr(lbProcedure *p, Ast *expr, lbValue *sret_dst) { expr = unparen_expr(expr); ast_node(ce, CallExpr, expr); - lbValue res = lb_build_call_expr_internal(p, expr); + lbValue res = lb_build_call_expr_internal(p, expr, sret_dst); if (ce->optional_ok_one) { GB_ASSERT(is_type_tuple(res.type)); @@ -4104,7 +4161,7 @@ gb_internal void lb_add_values_to_array(lbProcedure *p, Array *args, lb } } -gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { +gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr, lbValue *sret_dst) { lbModule *m = p->module; TypeAndValue tv = type_and_value_of_expr(expr); @@ -4411,6 +4468,25 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { return lb_handle_objc_auto_send(p, expr, slice(call_args, 0, call_args.count)); } - return lb_emit_call(p, value, call_args, ce->inlining); + + ProcInlining inlining = ce->inlining; + ProcTailing tailing = ce->tailing; + + if (tailing == ProcTailing_none && + proc_entity && proc_entity->kind == Entity_Procedure && + proc_entity->decl_info && + proc_entity->decl_info->proc_lit) { + ast_node(pl, ProcLit, proc_entity->decl_info->proc_lit); + + if (pl->inlining != ProcInlining_none) { + inlining = pl->inlining; + } + + if (pl->tailing != ProcTailing_none) { + tailing = pl->tailing; + } + } + + return lb_emit_call(p, value, call_args, inlining, tailing, sret_dst); } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 3dbcea4fb..fe09b26c8 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1,3 +1,128 @@ +#define LB_ENABLE_BASIC_RVO true +#define LB_ENABLE_ADVANCED_RVO build_context.enable_rvo + +// NOTE(bill): @RVO Check if a call expression returns by sret with a return type matching dst_type. +// Returns the callee's function type if eligible for copy elision, nullptr otherwise. +gb_internal lbFunctionType *lb_call_sret_eligible(lbProcedure *p, Ast *call_expr, Type *dst_type) { + GB_ASSERT(call_expr->kind == Ast_CallExpr); + Ast *proc_expr = unparen_expr(call_expr->CallExpr.proc); + TypeAndValue proc_tv = type_and_value_of_expr(proc_expr); + if (proc_tv.mode == Addressing_Type || proc_tv.mode == Addressing_Builtin) { + return nullptr; + } + Type *pt = base_type(proc_tv.type); + if (pt == nullptr || pt->kind != Type_Proc || pt->Proc.results == nullptr) { + return nullptr; + } + lbFunctionType *callee_ft = lb_get_function_type(p->module, pt); + if (callee_ft->ret.kind != lbArg_Indirect) { + return nullptr; + } + Type *callee_ret = reduce_tuple_to_single_type(pt->Proc.results); + if (callee_ret == nullptr || !are_types_identical(dst_type, callee_ret)) { + return nullptr; + } + return callee_ft; +} + +// NOTE(bill): @RVO `sret` scan for `x := call(); ...; return x` pattern. +// When matched, `x` alloca will be the sret pointer itself, eliminating +// the copy from `x` to the sret buffer on return. +gb_internal void lb_scan_for_sret_rvo(lbProcedure *p) { + if (p->body == nullptr || p->body->kind != Ast_BlockStmt) { + return; + } + Type *proc_type = p->type; + if (proc_type->Proc.result_count != 1 || proc_type->Proc.results == nullptr) { + return; + } + lbFunctionType *ft = lb_get_function_type(p->module, proc_type); + if (ft->ret.kind != lbArg_Indirect) { + return; + } + + Slice stmts = p->body->BlockStmt.stmts; + if (stmts.count < 2) { + return; + } + + // Last stmt must be `return x` where x is an identifier + Ast *last = stmts[stmts.count - 1]; + if (last->kind != Ast_ReturnStmt) { + return; + } + Slice results = last->ReturnStmt.results; + if (results.count != 1) { + return; + } + Ast *ret_expr = unparen_expr(results[0]); + if (ret_expr->kind != Ast_Ident) { + return; + } + Entity *ret_entity = entity_of_node(ret_expr); + if (ret_entity == nullptr || ret_entity->kind != Entity_Variable) { + return; + } + + Type *ret_type = reduce_tuple_to_single_type(proc_type->Proc.results); + if (ret_type == nullptr || !are_types_identical(ret_entity->type, ret_type)) { + return; + } + + // Walk backwards from the second-to-last stmt to find `x := call()` + // Everything between must be safe (no reassignment of x, no control flow) + i64 decl_index = -1; + for (i64 i = stmts.count - 2; i >= 0; i--) { + Ast *stmt = stmts[i]; + switch (stmt->kind) { + case Ast_ValueDecl: { + AstValueDecl *vd = &stmt->ValueDecl; + if (!vd->is_mutable) { + // constant decl — safe, keep scanning + continue; + } + if (vd->names.count == 1 && vd->values.count == 1) { + Entity *e = entity_of_node(vd->names[0]); + if (e == ret_entity) { + Ast *rhs = unparen_expr(vd->values[0]); + if (rhs->kind == Ast_CallExpr && lb_call_sret_eligible(p, rhs, e->type)) { + decl_index = i; + } + goto done_scanning; + } + } + // Some other mutable ValueDecl — safe as long as it doesn't involve ret_entity + for (Ast *name : vd->names) { + if (entity_of_node(name) == ret_entity) { + goto done_scanning; + } + } + continue; + } + case Ast_ExprStmt: + // Expression statements (reads, function calls) are safe + continue; + case Ast_AssignStmt: { + // Check if any lhs is our entity + for (Ast *lhs : stmt->AssignStmt.lhs) { + Ast *l = unparen_expr(lhs); + if (l->kind == Ast_Ident && entity_of_node(l) == ret_entity) { + goto done_scanning; + } + } + continue; + } + default: + // Control flow or anything else — bail + goto done_scanning; + } + } +done_scanning: + if (decl_index >= 0) { + p->sret_rvo_entity = ret_entity; + } +} + gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) { if (vd == nullptr || vd->is_mutable) { return; @@ -135,7 +260,7 @@ gb_internal lbBranchBlocks lb_lookup_branch_blocks(lbProcedure *p, Ast *ident) { } gb_internal lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, lbBlock *continue_, lbBlock *fallthrough_) { - lbTargetList *tl = gb_alloc_item(permanent_allocator(), lbTargetList); + lbTargetList *tl = permanent_alloc_item(); tl->prev = p->target_list; tl->break_ = break_; tl->continue_ = continue_; @@ -362,6 +487,14 @@ gb_internal void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_ } break; } + case Type_FixedCapacityDynamicArray: { + if (val_type != nullptr) { + lbValue data = lb_emit_struct_ep(p, expr, 0); + val = lb_emit_load(p, lb_emit_array_ep(p, data, idx)); + } + break; + } + case Type_Slice: { if (val_type != nullptr) { lbValue elem = lb_slice_elem(p, expr); @@ -756,6 +889,10 @@ gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node, lb_open_scope(p, scope); + if (rs->init != nullptr) { + lb_build_stmt(p, rs->init); + } + Ast *val0 = rs->vals.count > 0 ? lb_strip_and_prefix(rs->vals[0]) : nullptr; Ast *val1 = rs->vals.count > 1 ? lb_strip_and_prefix(rs->vals[1]) : nullptr; Type *val0_type = nullptr; @@ -847,6 +984,10 @@ gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node, lb_close_scope(p, lbDeferExit_Default, nullptr, node->left); lb_pop_target_list(p); + if (p->debug_info != nullptr) { + LLVMSetCurrentDebugLocation2(p->builder, lb_debug_end_location_from_ast(p, rs->body)); + } + if (check != nullptr) { lb_emit_jump(p, check); lb_start_block(p, check); @@ -944,6 +1085,10 @@ gb_internal void lb_build_range_tuple(lbProcedure *p, AstRangeStmt *rs, Scope *s lb_open_scope(p, scope); + if (rs->init != nullptr) { + lb_build_stmt(p, rs->init); + } + lbBlock *loop = lb_create_block(p, "for.tuple.loop"); lb_emit_jump(p, loop); lb_start_block(p, loop); @@ -979,6 +1124,9 @@ gb_internal void lb_build_range_tuple(lbProcedure *p, AstRangeStmt *rs, Scope *s lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); lb_pop_target_list(p); + if (p->debug_info != nullptr) { + LLVMSetCurrentDebugLocation2(p->builder, lb_debug_end_location_from_ast(p, rs->body)); + } lb_emit_jump(p, loop); lb_start_block(p, done); } @@ -995,6 +1143,9 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs lb_open_scope(p, scope); + if (rs->init != nullptr) { + lb_build_stmt(p, rs->init); + } Ast *val0 = rs->vals.count > 0 ? lb_strip_and_prefix(rs->vals[0]) : nullptr; Ast *val1 = rs->vals.count > 1 ? lb_strip_and_prefix(rs->vals[1]) : nullptr; @@ -1108,6 +1259,9 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); lb_pop_target_list(p); + if (p->debug_info != nullptr) { + LLVMSetCurrentDebugLocation2(p->builder, lb_debug_end_location_from_ast(p, rs->body)); + } lb_emit_jump(p, loop); lb_start_block(p, done); @@ -1143,6 +1297,10 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc lb_open_scope(p, scope); + if (rs->init != nullptr) { + lb_build_stmt(p, rs->init); + } + Ast *val0 = rs->vals.count > 0 ? lb_strip_and_prefix(rs->vals[0]) : nullptr; Ast *val1 = rs->vals.count > 1 ? lb_strip_and_prefix(rs->vals[1]) : nullptr; Type *val0_type = nullptr; @@ -1216,6 +1374,15 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse); break; } + case Type_FixedCapacityDynamicArray: { + lbValue array = lb_build_addr_ptr(p, expr); + if (is_type_pointer(type_deref(array.type))) { + array = lb_emit_load(p, array); + } + lbValue count_ptr = lb_emit_struct_ep(p, array, 1); + lb_build_range_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse); + break; + } case Type_DynamicArray: { lbValue count_ptr = {}; lbValue array = lb_build_addr_ptr(p, expr); @@ -1330,6 +1497,9 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); lb_pop_target_list(p); + if (p->debug_info != nullptr) { + LLVMSetCurrentDebugLocation2(p->builder, lb_debug_end_location_from_ast(p, rs->body)); + } lb_emit_jump(p, loop); lb_start_block(p, done); } @@ -1339,6 +1509,10 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt * lb_open_scope(p, scope); // Open scope here + if (rs->init != nullptr) { + lb_build_stmt(p, rs->init); + } + Ast *val0 = lb_strip_and_prefix(rs->val0); Ast *val1 = lb_strip_and_prefix(rs->val1); Type *val0_type = nullptr; @@ -1434,12 +1608,13 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt * if (unroll_count_ev.kind == ExactValue_Invalid) { - GB_ASSERT(expr->tav.mode == Addressing_Constant); Type *t = base_type(expr->tav.type); switch (t->kind) { case Type_Basic: + GB_ASSERT(expr->tav.mode == Addressing_Constant); + GB_ASSERT(is_type_string(t)); { ExactValue value = expr->tav.value; @@ -1532,6 +1707,19 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt * break; } + case Type_FixedCapacityDynamicArray: { + lbValue array = lb_build_expr(p, expr); + if (!is_type_pointer(array.type)) { + array = lb_address_from_load_or_generate_local(p, array); + } + GB_ASSERT(is_type_pointer(array.type)); + + count_ptr = lb_emit_struct_ep(p, array, 1); + + data_ptr = lb_emit_conv(p, array, alloc_type_pointer(t->FixedCapacityDynamicArray.elem)); + break; + } + case Type_Array: { lbValue array = lb_build_expr(p, expr); count_ptr = lb_add_local_generated(p, t_int, false).addr; @@ -1720,7 +1908,45 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * Ast *clause = body->stmts[i]; ast_node(cc, CaseClause, clause); - body_blocks[i] = lb_create_block(p, cc->list.count == 0 ? "switch.default.body" : "switch.case.body"); + char const *block_name = cc->list.count == 0 ? "switch.default.body" : "switch.case.body"; + + if (is_trivial && cc->list.count >= 1) { + gbString bn = gb_string_make(heap_allocator(), "switch.case."); + + Ast *first = cc->list[0]; + if (first->tav.mode == Addressing_Type) { + bn = gb_string_appendc(bn, "type."); + } else if (is_type_rune(first->tav.type)) { + bn = gb_string_appendc(bn, "rune."); + } else { + bn = gb_string_appendc(bn, "value."); + } + + for_array(i, cc->list) { + if (i > 0) { + bn = gb_string_appendc(bn, ".."); + } + + Ast *expr = cc->list[i]; + if (expr->tav.mode == Addressing_Type) { + bn = write_type_to_string(bn, expr->tav.type, false); + } else { + ExactValue value = expr->tav.value; + if (is_type_rune(expr->tav.type) && value.kind == ExactValue_Integer) { + Rune r = cast(Rune)exact_value_to_i64(value); + u8 rune_temp[6] = {}; + isize size = gb_utf8_encode_rune(rune_temp, r); + bn = gb_string_append_length(bn, rune_temp, size); + } else { + bn = write_exact_value_to_string(bn, value, 1024); + } + } + } + + block_name = cast(char const *)bn; + } + + body_blocks[i] = lb_create_block(p, block_name); if (cc->list.count == 0) { default_block = body_blocks[i]; } @@ -1768,6 +1994,10 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * } lbBlock *next_cond = nullptr; + if (p->debug_info != nullptr) { + LLVMSetCurrentDebugLocation2(p->builder, lb_debug_end_location_from_ast(p, clause)); + } + for (Ast *expr : cc->list) { expr = unparen_expr(expr); @@ -1962,7 +2192,7 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss num_cases += cc->list.count; if (cc->list.count == 0) { GB_ASSERT(default_block == nullptr); - default_block = lb_create_block(p, "typeswitch.default.body"); + default_block = lb_create_block(p, "typeswitch.case.default"); else_block = default_block; } } @@ -2042,7 +2272,16 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss continue; } - lbBlock *body = lb_create_block(p, "typeswitch.body"); + char const *body_name = "typeswitch.case"; + + if (!are_types_identical(case_entity->type, parent_base_type)) { + gbString canonical_name = temp_canonical_string(case_entity->type); + gbString bn = gb_string_make(heap_allocator(), "typeswitch.case."); + bn = gb_string_append_length(bn, canonical_name, gb_string_length(canonical_name)); + body_name = cast(char const *)bn; + } + + lbBlock *body = lb_create_block(p, body_name); if (p->debug_info != nullptr) { LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, clause)); } @@ -2053,7 +2292,13 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss lbValue on_val = {}; if (switch_kind == TypeSwitch_Union) { Type *ut = base_type(type_deref(parent.type)); - on_val = lb_const_union_tag(m, ut, case_type); + if (is_type_untyped_nil(case_type)) { + GB_ASSERT(type_has_nil(ut)); + saw_nil = true; + on_val = lb_const_int(m, union_tag_type(ut), 0); + } else { + on_val = lb_const_union_tag(m, ut, case_type); + } } else if (switch_kind == TypeSwitch_Any) { if (is_type_untyped_nil(case_type)) { @@ -2122,14 +2367,7 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) { for_array(i, vd->names) { lbValue value = {}; - if (vd->values.count > 0) { - GB_ASSERT(vd->names.count == vd->values.count); - Ast *ast_value = vd->values[i]; - GB_ASSERT(ast_value->tav.mode == Addressing_Constant || - ast_value->tav.mode == Addressing_Invalid); - value = lb_const_value(p->module, ast_value->tav.type, ast_value->tav.value, LB_CONST_CONTEXT_DEFAULT_NO_LOCAL); - } Ast *ident = vd->names[i]; GB_ASSERT(!is_blank_ident(ident)); @@ -2137,6 +2375,19 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) { GB_ASSERT(e->flags & EntityFlag_Static); String name = e->token.string; + if (vd->values.count > 0) { + GB_ASSERT(vd->names.count == vd->values.count); + Ast *ast_value = vd->values[i]; + GB_ASSERT(ast_value->tav.mode == Addressing_Constant || + ast_value->tav.mode == Addressing_Invalid); + + auto cc = LB_CONST_CONTEXT_DEFAULT_NO_LOCAL; + if (e->Variable.is_rodata) { + cc.is_rodata = true; + } + value = lb_const_value(p->module, ast_value->tav.type, ast_value->tav.value, cc); + } + String mangled_name = {}; { gbString str = gb_string_make_length(permanent_allocator(), p->name.text, p->name.len); @@ -2342,6 +2593,45 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return if (return_count == 1) { Entity *e = tuple->variables[0]; + + if (LB_ENABLE_BASIC_RVO && res_count == 1 && return_by_pointer) { + Ast *ret_expr = unparen_expr(return_results[0]); + + // NOTE(bill): @RVO for `return call()` in a procedure which uses `sret` and has no defers + // This forwards the sret pointer directly to the callee + if (p->defer_stmts.count == 0) { + if (ret_expr->kind == Ast_CallExpr && lb_call_sret_eligible(p, ret_expr, e->type)) { + lbValue sret_ptr = p->return_ptr.addr; + lb_build_call_expr(p, ret_expr, &sret_ptr); + if (p->type->Proc.has_named_results && e->token.string != "") { + res = lb_emit_load(p, p->return_ptr.addr); + rw_mutex_shared_lock(&p->module->values_mutex); + lbValue found = map_must_get(&p->module->values, e); + rw_mutex_shared_unlock(&p->module->values_mutex); + lb_emit_store(p, found, lb_emit_conv(p, res, e->type)); + } + LLVMBuildRetVoid(p->builder); + return; + } + } + + // NOTE(bill): @RVO for `x := call(); ...; return x` + if (p->sret_rvo_entity != nullptr) { + if (ret_expr->kind == Ast_Ident) { + Entity *ret_e = entity_of_node(ret_expr); + if (ret_e == p->sret_rvo_entity) { + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); + LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); + if (!lb_is_instr_terminating(instr)) { + LLVMBuildRetVoid(p->builder); + } + return; + } + } + } + } + + if (res_count == 0) { rw_mutex_shared_lock(&p->module->values_mutex); lbValue found = map_must_get(&p->module->values, e); @@ -2441,33 +2731,26 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return } else { Type *ret_type = p->type->Proc.results; - // NOTE(bill): Doesn't need to be zero because it will be initialized in the loops - if (return_by_pointer) { - res = p->return_ptr.addr; - } else { - res = lb_add_local_generated(p, ret_type, false).addr; - } - auto result_values = slice_make(temporary_allocator(), results.count); - auto result_eps = slice_make(temporary_allocator(), results.count); - for_array(i, results) { result_values[i] = lb_emit_conv(p, results[i], tuple->variables[i]->type); } - for_array(i, results) { - result_eps[i] = lb_emit_struct_ep(p, res, cast(i32)i); - } - for_array(i, result_eps) { - lb_emit_store(p, result_eps[i], result_values[i]); - } if (return_by_pointer) { + res = p->return_ptr.addr; + auto result_eps = slice_make(temporary_allocator(), results.count); + for_array(i, results) { + result_eps[i] = lb_emit_struct_ep(p, res, cast(i32)i); + } + for_array(i, result_eps) { + lb_emit_store(p, result_eps[i], result_values[i]); + } lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); LLVMBuildRetVoid(p->builder); return; } - res = lb_emit_load(p, res); + res = lb_build_struct_value(p, ret_type, result_values.data, result_values.count); } } lb_build_return_stmt_internal(p, res, pos); @@ -2776,6 +3059,23 @@ gb_internal void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr } gb_internal void lb_build_assign_stmt(lbProcedure *p, AstAssignStmt *as) { if (as->op.kind == Token_Eq) { + if (LB_ENABLE_ADVANCED_RVO) { + // @RVO for single assignments `x = call()` + if (as->lhs.count == 1 && as->rhs.count == 1 && !is_blank_ident(as->lhs[0])) { + Ast *rhs_expr = unparen_expr(as->rhs[0]); + if (rhs_expr->kind == Ast_CallExpr) { + lbAddr lval = lb_build_addr(p, as->lhs[0]); + if (LLVMIsAAllocaInst(lval.addr.value) && lval.kind == lbAddr_Default) { + if (lb_call_sret_eligible(p, rhs_expr, lb_addr_type(lval))) { + lbValue dst = lval.addr; + lb_build_call_expr(p, rhs_expr, &dst); + return; + } + } + } + } + } + auto lvals = array_make(permanent_allocator(), 0, as->lhs.count); for (Ast *lhs : as->lhs) { @@ -2961,6 +3261,27 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { } } } else { + if (LB_ENABLE_ADVANCED_RVO) { + // @RVO: for `x := call()` + if (vd->names.count == 1 && values.count == 1 && !is_blank_ident(vd->names[0])) { + Ast *rhs_expr = unparen_expr(values[0]); + Entity *e = entity_of_node(vd->names[0]); + if (rhs_expr->kind == Ast_CallExpr && e != nullptr && lb_call_sret_eligible(p, rhs_expr, e->type)) { + lbValue dst = {}; + if (e == p->sret_rvo_entity) { + dst = p->return_ptr.addr; + lb_add_entity(p->module, e, dst); + lb_add_debug_local_variable(p, dst.value, e->type, e->token); + } else { + lbAddr local = lb_add_local(p, e->type, e, true); + dst = local.addr; + } + lb_build_call_expr(p, rhs_expr, &dst); + break; + } + } + } + auto lvals_preused = slice_make(temporary_allocator(), vd->names.count); auto lvals = slice_make(temporary_allocator(), vd->names.count); auto inits = array_make(temporary_allocator(), 0, lvals.count); @@ -3110,6 +3431,9 @@ gb_internal void lb_build_defer_stmt(lbProcedure *p, lbDefer const &d) { if (d.kind == lbDefer_Node) { lb_build_stmt(p, d.stmt); } else if (d.kind == lbDefer_Proc) { + if (p->debug_info != nullptr && d.pos.line > 0) { + LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_token_pos(p, d.pos)); + } lb_emit_call(p, d.proc.deferred, d.proc.result_as_args); } } @@ -3186,10 +3510,11 @@ gb_internal void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) d->scope_index = scope_index; d->context_stack_count = p->context_stack.count; d->block = p->curr_block; - d->stmt = stmt; + d->pos = ast_token(stmt).pos; + d->stmt = stmt; } -gb_internal void lb_add_defer_proc(lbProcedure *p, isize scope_index, lbValue deferred, Array const &result_as_args) { +gb_internal void lb_add_defer_proc(lbProcedure *p, isize scope_index, lbValue deferred, Array const &result_as_args, TokenPos pos) { Type *pt = base_type(p->type); GB_ASSERT(pt->kind == Type_Proc); if (pt->Proc.calling_convention == ProcCC_Odin) { @@ -3200,6 +3525,7 @@ gb_internal void lb_add_defer_proc(lbProcedure *p, isize scope_index, lbValue de d->kind = lbDefer_Proc; d->scope_index = p->scope_index; d->block = p->curr_block; + d->pos = pos; d->context_stack_count = p->context_stack.count; d->proc.deferred = deferred; d->proc.result_as_args = result_as_args; diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 382304a4e..9b9d3e8eb 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -69,6 +69,7 @@ gb_internal u64 lb_typeid_kind(lbModule *m, Type *type, u64 id=0) { case Type_SimdVector: kind = Typeid_Simd_Vector; break; case Type_SoaPointer: kind = Typeid_SoaPointer; break; case Type_BitField: kind = Typeid_Bit_Field; break; + case Type_FixedCapacityDynamicArray: kind = Typeid_Fixed_Capacity_Dynamic_Array; break; } return kind; @@ -200,10 +201,10 @@ gb_internal LLVMTypeRef *lb_setup_modified_types_for_type_info(lbModule *m, isiz vtypes[0] = lb_type(m, t); vtypes[1] = padding; vtypes[2] = tag; - LLVMTypeRef variant_type = LLVMStructType(vtypes, gb_count_of(vtypes), true); + LLVMTypeRef variant_type = LLVMStructTypeInContext(m->ctx, vtypes, gb_count_of(vtypes), true); stypes[variant_index] = variant_type; - LLVMTypeRef modified_type = LLVMStructType(stypes, cast(unsigned)(variant_index+1), false); + LLVMTypeRef modified_type = LLVMStructTypeInContext(m->ctx, stypes, cast(unsigned)(variant_index+1), false); modified_types[i] = modified_type; } @@ -644,6 +645,21 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); break; } + case Type_FixedCapacityDynamicArray: { + tag_type = t_type_info_fixed_capacity_dynamic_array; + + i64 len_offset = type_offset_of(t, 1); + + LLVMValueRef vals[4] = { + get_type_info_ptr(m, t->FixedCapacityDynamicArray.elem), + lb_const_int(m, t_int, type_size_of(t->FixedCapacityDynamicArray.elem)).value, + lb_const_int(m, t_int, t->FixedCapacityDynamicArray.capacity).value, + lb_const_int(m, t_uintptr, len_offset).value, + }; + + variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); + break; + } case Type_Slice: { tag_type = t_type_info_slice; @@ -923,15 +939,25 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ GB_ASSERT(is_type_typed(t->BitSet.elem)); - LLVMValueRef vals[4] = { - get_type_info_ptr(m, t->BitSet.elem), - LLVMConstNull(lb_type(m, t_type_info_ptr)), - lb_const_int(m, t_i64, t->BitSet.lower).value, - lb_const_int(m, t_i64, t->BitSet.upper).value, + LLVMValueRef vals[5] = { + get_type_info_ptr(m, t->BitSet.elem), // ^Type_Info + nullptr, // ^Type_Info + nullptr, // bool + lb_const_int(m, t_i64, t->BitSet.lower).value, // i64 + lb_const_int(m, t_i64, t->BitSet.upper).value, // i64 }; + Type *underlying = nullptr; + bool explicit_underlying = false; if (t->BitSet.underlying != nullptr) { + underlying = t->BitSet.underlying; + explicit_underlying = true; vals[1] = get_type_info_ptr(m, t->BitSet.underlying); + vals[2] = lb_const_bool(m, t_bool, true).value; + } else { + underlying = bit_set_to_int(t); } + vals[1] = get_type_info_ptr(m, underlying); + vals[2] = lb_const_bool(m, t_bool, explicit_underlying).value; variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); } @@ -1038,7 +1064,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ i64 tag_index = 0; if (tag_type != nullptr) { - tag_index = union_variant_index(ut, tag_type); + tag_index = union_variant_index_checked(ut, tag_type); } GB_ASSERT(tag_index <= Typeid__COUNT); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 33ad2ee8d..3905adfcd 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -89,7 +89,7 @@ gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef p bool is_inlinable = false; i64 const_len = 0; - if (LLVMIsConstant(len)) { + if (!p->is_startup && LLVMIsConstant(len)) { const_len = cast(i64)LLVMConstIntGetSExtValue(len); // TODO(bill): Determine when it is better to do the `*.inline` versions if (const_len <= lb_max_zero_init_size()) { @@ -438,6 +438,50 @@ gb_internal lbValue lb_emit_try_has_value(lbProcedure *p, lbValue rhs) { return has_value; } +gb_internal bool lb_is_type_trivial(Type *type) { + Type *bt = base_type(type); + if (is_type_integer(bt) || is_type_float(bt) || is_type_boolean(bt) || + is_type_pointer(bt) || is_type_enum(bt) || is_type_rune(bt) || is_type_typeid((bt))) { + return true; + } + return false; +} + +gb_internal bool lb_is_expr_trivial(Ast *e) { + Type *type = default_type(type_of_expr(e)); + if (lb_is_type_trivial(type)) { + e = unparen_expr(e); + TypeAndValue tav = type_and_value_of_expr(e); + if (tav.mode == Addressing_Constant) { + return true; + } + if (e->kind == Ast_Ident) { + return true; + } + if (e->kind == Ast_SelectorExpr) { + Ast *operand = unparen_expr(e->SelectorExpr.expr); + if (operand && operand->kind == Ast_Ident) { + // If the operand is a pointer, thus deferences it, disallow it + Type *ot = type_of_expr(operand); + if (ot == nullptr || is_type_pointer(ot)) { + return false; + } + return true; + } + } + if (e->kind == Ast_UnaryExpr && e->UnaryExpr.op.kind != Token_And) { + Ast *operand = unparen_expr(e->UnaryExpr.expr); + TypeAndValue otav = type_and_value_of_expr(operand); + if (otav.mode == Addressing_Constant) { + return true; + } + if (operand->kind == Ast_Ident) { + return true; + } + } + } + return false; +} gb_internal lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue const &tv) { if (arg->state_flags & StateFlag_DirectiveWasFalse) { @@ -467,6 +511,13 @@ gb_internal lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, Ty lb_start_block(p, then); return lb_emit_conv(p, lhs, type); } else { + if (lb_is_type_trivial(type) && lb_is_expr_trivial(else_expr)) { + lbValue has_value = lb_emit_try_has_value(p, rhs); + lbValue then_val = lb_emit_conv(p, lhs, type); + lbValue else_val = lb_emit_conv(p, lb_build_expr(p, else_expr), type); + return lb_emit_select(p, has_value, then_val, else_val); + } + LLVMValueRef incoming_values[2] = {}; LLVMBasicBlockRef incoming_blocks[2] = {}; @@ -648,6 +699,18 @@ gb_internal lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type return res; } +gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type); + +gb_internal lbValue lb_emit_count_trailing_ones(lbProcedure *p, lbValue x, Type *type) { + lbValue z = lb_emit_unary_arith(p, Token_Xor, x, type); + return lb_emit_count_trailing_zeros(p, z, type); +} + +gb_internal lbValue lb_emit_count_leading_ones(lbProcedure *p, lbValue x, Type *type) { + lbValue z = lb_emit_unary_arith(p, Token_Xor, x, type); + return lb_emit_count_leading_zeros(p, z, type); +} + gb_internal lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type) { @@ -803,7 +866,12 @@ gb_internal lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type args[5] = lb_typeid(m, dst_type); args[6] = lb_emit_conv(p, value_, t_rawptr); } - lb_emit_runtime_call(p, "type_assertion_check2", args); + + char const *name = "type_assertion_check2_contextless"; + if (p->context_stack.count > 0) { + name = "type_assertion_check2_with_context"; + } + lb_emit_runtime_call(p, name, args); } return lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 0)); @@ -877,7 +945,11 @@ gb_internal lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *ty args[5] = dst_typeid; args[6] = lb_emit_struct_ev(p, value, 0); } - lb_emit_runtime_call(p, "type_assertion_check2", args); + char const *name = "type_assertion_check2_contextless"; + if (p->context_stack.count > 0) { + name = "type_assertion_check2_with_context"; + } + lb_emit_runtime_call(p, name, args); } return lb_addr(lb_emit_struct_ep(p, v.addr, 0)); @@ -1040,6 +1112,17 @@ gb_internal i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) { break; } } + if (t->kind == Type_FixedCapacityDynamicArray) { + switch (index) { + case 0: return 0; // data + case 1: + if (t->FixedCapacityDynamicArray.padding_needed > 0) { + return 2; + } + return 1; + } + } + return index; } @@ -1213,6 +1296,11 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { case 2: result_type = t_int; break; case 3: result_type = t_allocator; break; } + } else if (is_type_fixed_capacity_dynamic_array(t)) { + switch (index) { + case 0: result_type = alloc_type_array(t->FixedCapacityDynamicArray.elem, t->FixedCapacityDynamicArray.capacity); break; + case 1: result_type = t_int; break; + } } else if (is_type_map(t)) { init_map_internal_debug_types(t); Type *itp = alloc_type_pointer(t_raw_map); @@ -1378,6 +1466,12 @@ gb_internal lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) { } break; + case Type_FixedCapacityDynamicArray: + switch (index) { + case 0: result_type = alloc_type_array(t->FixedCapacityDynamicArray.elem, t->FixedCapacityDynamicArray.capacity); break; + case 1: result_type = t_int; break; + } + case Type_Map: { init_map_internal_debug_types(t); @@ -1541,16 +1635,27 @@ gb_internal lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) { Type *t = s.type; GB_ASSERT(is_type_pointer(t)); Type *st = base_type(type_deref(t)); - GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st)); + GB_ASSERT(0 <= index); + if (is_type_fixed_capacity_dynamic_array(st)) { + lbValue data = lb_emit_struct_ep(p, s, 0); + return lb_emit_epi(p, data, index); + } + + GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st)); return lb_emit_epi(p, s, index); } gb_internal lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index) { Type *t = s.type; GB_ASSERT(is_type_pointer(t)); Type *st = base_type(type_deref(t)); - GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st)); GB_ASSERT(0 <= index); + if (is_type_fixed_capacity_dynamic_array(st)) { + lbValue data = lb_emit_epi(m, s, 0); + return lb_emit_epi(m, data, index); + } + + GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st)); return lb_emit_epi(m, s, index); } @@ -1637,14 +1742,25 @@ gb_internal lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lb return res; } - gb_internal lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isize column) { - Type *st = base_type(s.type); - GB_ASSERT_MSG(is_type_matrix(st), "%s", type_to_string(st)); - - lbValue value = lb_address_from_load_or_generate_local(p, s); - lbValue ptr = lb_emit_matrix_epi(p, value, row, column); - return lb_emit_load(p, ptr); + Type *t = s.type; + Type *mt = base_type(t); + GB_ASSERT_MSG(is_type_matrix(mt), "%s", type_to_string(mt)); + + isize stride_elems = matrix_type_stride_in_elems(mt); + + isize index = -1; + + if (mt->Matrix.is_row_major) { + index = column + (row * stride_elems); + } else { + index = row + (column * stride_elems); + } + + lbValue res = {}; + res.value = LLVMBuildExtractValue(p->builder, s.value, cast(unsigned)index, ""); + res.type = base_array_type(mt); + return res; } gb_internal void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base_elem, lbValue len) { @@ -1670,6 +1786,40 @@ gb_internal void lb_fill_string(lbProcedure *p, lbAddr const &string, lbValue ba lb_emit_store(p, lb_emit_struct_ep(p, ptr, 1), len); } +gb_internal lbValue lb_emit_struct_iv(lbProcedure *p, lbValue agg, lbValue field, i32 index) { + Type *t = base_type(agg.type); + i32 mapped_index = lb_convert_struct_index(p->module, t, index); + lbValue res = {}; + res.value = LLVMBuildInsertValue(p->builder, agg.value, field.value, cast(unsigned)mapped_index, ""); + res.type = agg.type; + return res; +} + +gb_internal lbValue lb_build_struct_value(lbProcedure *p, Type *type, lbValue *fields, isize count) { + LLVMTypeRef llvm_type = lb_type(p->module, type); + lbValue agg = {}; + // agg.value = LLVMGetPoison(llvm_type); + agg.value = LLVMConstNull(llvm_type); + agg.type = type; + for (isize i = 0; i < count; i++) { + agg = lb_emit_struct_iv(p, agg, fields[i], cast(i32)i); + } + return agg; +} + +gb_internal lbValue lb_make_slice_value(lbProcedure *p, Type *slice_type, lbValue elem, lbValue len) { + GB_ASSERT(is_type_slice(slice_type)); + lbValue fields[2] = {elem, len}; + return lb_build_struct_value(p, slice_type, fields, 2); +} + +gb_internal lbValue lb_make_string_value(lbProcedure *p, Type *string_type, lbValue elem, lbValue len) { + GB_ASSERT(is_type_string(string_type)); + lbValue fields[2] = {elem, len}; + return lb_build_struct_value(p, string_type, fields, 2); +} + + gb_internal lbValue lb_string_elem(lbProcedure *p, lbValue string) { Type *t = base_type(string.type); if (t->kind == Type_Basic && t->Basic.kind == Basic_string16) { @@ -1728,6 +1878,11 @@ gb_internal lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da) { return lb_emit_struct_ev(p, da, 2); } +gb_internal lbValue lb_fixed_capacity_dynamic_array_len(lbProcedure *p, lbValue da) { + GB_ASSERT(is_type_fixed_capacity_dynamic_array(da.type)); + return lb_emit_struct_ev(p, da, 1); +} + gb_internal lbValue lb_map_len(lbProcedure *p, lbValue value) { GB_ASSERT_MSG(is_type_map(value.type) || are_types_identical(value.type, t_raw_map), "%s", type_to_string(value.type)); lbValue len = lb_emit_struct_ev(p, value, 1); @@ -2410,7 +2565,7 @@ gb_internal lbValue lb_handle_objc_block(lbProcedure *p, Ast *expr) { Ast *proc_lit = unparen_expr(ce->args[capture_arg_count]); if (proc_lit->kind == Ast_Ident) { - proc_lit = proc_lit->Ident.entity->decl_info->proc_lit; + proc_lit = proc_lit->Ident.entity.load()->decl_info->proc_lit; } GB_ASSERT(proc_lit->kind == Ast_ProcLit); @@ -2868,9 +3023,13 @@ gb_internal lbValue lb_handle_objc_auto_send(lbProcedure *p, Ast *expr, Sliceexpr->tav.mode == Addressing_Type && se->expr->tav.type->kind == Type_Named); objc_class = entity_from_expr(se->expr); - GB_ASSERT(objc_class); GB_ASSERT(objc_class->kind == Entity_TypeName); + + if (objc_class->TypeName.is_type_alias) { + objc_class = objc_class->type->Named.type_name; + } + GB_ASSERT(objc_class->TypeName.objc_class_name != ""); } diff --git a/src/main.cpp b/src/main.cpp index 9a5df8aea..4d68d3d73 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -302,6 +302,7 @@ enum BuildFlagKind { BuildFlag_ShowUnused, BuildFlag_ShowUnusedWithLocation, BuildFlag_ShowMoreTimings, + BuildFlag_ShowImportGraph, BuildFlag_ExportTimings, BuildFlag_ExportTimingsFile, BuildFlag_ExportDependencies, @@ -324,13 +325,12 @@ enum BuildFlagKind { BuildFlag_NoCRT, BuildFlag_NoRPath, BuildFlag_NoEntryPoint, - BuildFlag_UseLLD, - BuildFlag_UseRADLink, BuildFlag_Linker, BuildFlag_UseSeparateModules, BuildFlag_UseSingleModule, BuildFlag_NoThreadedChecker, BuildFlag_ShowDebugMessages, + BuildFlag_DidYouMeanLimit, BuildFlag_ShowDefineables, BuildFlag_ExportDefineables, @@ -363,6 +363,8 @@ enum BuildFlagKind { BuildFlag_RelocMode, BuildFlag_DisableRedZone, + BuildFlag_DisableUnwind, + BuildFlag_DisallowDo, BuildFlag_DefaultToNilAllocator, BuildFlag_DefaultToPanicAllocator, @@ -409,10 +411,13 @@ enum BuildFlagKind { BuildFlag_InternalByValue, BuildFlag_InternalWeakMonomorphization, BuildFlag_InternalLLVMVerification, + BuildFlag_InternalLLVMMem2Reg, + BuildFlag_InternalEnableRVO, BuildFlag_Tilde, BuildFlag_Sanitize, + BuildFlag_LTO, #if defined(GB_SYSTEM_WINDOWS) BuildFlag_IgnoreVsSearch, @@ -529,6 +534,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("o"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ShowMoreTimings, str_lit("show-more-timings"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_ShowImportGraph, str_lit("show-import-graph"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ExportTimings, str_lit("export-timings"), BuildFlagParam_String, Command__does_check); add_flag(&build_flags, BuildFlag_ExportTimingsFile, str_lit("export-timings-file"), BuildFlagParam_String, Command__does_check); add_flag(&build_flags, BuildFlag_ExportDependencies, str_lit("export-dependencies"), BuildFlagParam_String, Command__does_build); @@ -554,13 +560,12 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_NoRPath, str_lit("no-rpath"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test); - add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None, Command__does_build); - add_flag(&build_flags, BuildFlag_UseRADLink, str_lit("radlink"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_Linker, str_lit("linker"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_UseSingleModule, str_lit("use-single-module"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_NoThreadedChecker, str_lit("no-threaded-checker"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_DidYouMeanLimit, str_lit("did-you-mean-limit"), BuildFlagParam_Integer, Command__does_check); add_flag(&build_flags, BuildFlag_ShowDefineables, str_lit("show-defineables"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ExportDefineables, str_lit("export-defineables"), BuildFlagParam_String, Command__does_check); @@ -592,6 +597,8 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_RelocMode, str_lit("reloc-mode"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_DisableRedZone, str_lit("disable-red-zone"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_DisableUnwind, str_lit("disable-unwind"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_DisallowDo, str_lit("disallow-do"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_DefaultToNilAllocator, str_lit("default-to-nil-allocator"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_DefaultToPanicAllocator, str_lit("default-to-panic-allocator"),BuildFlagParam_None, Command__does_check); @@ -637,12 +644,15 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_InternalByValue, str_lit("internal-by-value"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalWeakMonomorphization, str_lit("internal-weak-monomorphization"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalLLVMVerification, str_lit("internal-ignore-llvm-verification"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_InternalLLVMMem2Reg, str_lit("internal-llvm-mem2reg"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_InternalEnableRVO, str_lit("internal-enable-rvo"), BuildFlagParam_None, Command_all); #if ALLOW_TILDE add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build); #endif add_flag(&build_flags, BuildFlag_Sanitize, str_lit("sanitize"), BuildFlagParam_String, Command__does_build, true); + add_flag(&build_flags, BuildFlag_LTO, str_lit("lto"), BuildFlagParam_String, Command__does_build); #if defined(GB_SYSTEM_WINDOWS) @@ -868,6 +878,10 @@ gb_internal bool parse_build_flags(Array args) { build_context.show_timings = true; build_context.show_more_timings = true; break; + case BuildFlag_ShowImportGraph: + GB_ASSERT(value.kind == ExactValue_Invalid); + build_context.show_import_graph = true; + break; case BuildFlag_ExportTimings: { GB_ASSERT(value.kind == ExactValue_String); /* @@ -1072,7 +1086,7 @@ gb_internal bool parse_build_flags(Array args) { break; } - char const *key = string_intern(name); + char const *key = string_intern_cstring(name); if (map_get(&build_context.defined_values, key) != nullptr) { gb_printf_err("Defined constant '%.*s' already exists\n", LIT(name)); @@ -1252,14 +1266,6 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_NoThreadLocal: build_context.no_thread_local = true; break; - case BuildFlag_UseLLD: - gb_printf_err("Warning: Use of -lld has been deprecated in favour of -linker:lld\n"); - build_context.linker_choice = Linker_lld; - break; - case BuildFlag_UseRADLink: - gb_printf_err("Warning: Use of -lld has been deprecated in favour of -linker:radlink\n"); - build_context.linker_choice = Linker_radlink; - break; case BuildFlag_Linker: { GB_ASSERT(value.kind == ExactValue_String); @@ -1305,6 +1311,20 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_ShowDebugMessages: build_context.show_debug_messages = true; break; + + case BuildFlag_DidYouMeanLimit: + { + GB_ASSERT(value.kind == ExactValue_Integer); + isize count = cast(isize)big_int_to_i64(&value.value_integer); + if (count <= 0) { + gb_printf_err("%.*s expected a positive non-zero number, got %.*s\n", LIT(name), LIT(param)); + build_context.did_you_mean_limit = DEFAULT_DID_YOU_MEAN_LIMIT; + } else { + build_context.did_you_mean_limit = (int)count; + } + } + break; + case BuildFlag_Vet: build_context.vet_flags |= VetFlag_All; break; @@ -1424,6 +1444,10 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_DisableRedZone: build_context.disable_red_zone = true; break; + case BuildFlag_DisableUnwind: + build_context.disable_unwind = true; + break; + case BuildFlag_DisallowDo: build_context.disallow_do = true; break; @@ -1614,6 +1638,13 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_InternalLLVMVerification: build_context.internal_ignore_llvm_verification = true; break; + case BuildFlag_InternalLLVMMem2Reg: + build_context.internal_llvm_mem2reg = true; + break; + case BuildFlag_InternalEnableRVO: + build_context.enable_rvo = true; + break; + case BuildFlag_Tilde: @@ -1640,6 +1671,38 @@ gb_internal bool parse_build_flags(Array args) { } break; + case BuildFlag_LTO: + GB_ASSERT(value.kind == ExactValue_String); + if (str_eq_ignore_case(value.value_string, str_lit("thin"))) { + build_context.lto_kind = LTO_Thin; + if (build_context.linker_choice == Linker_Invalid || build_context.linker_choice == Linker_Default) { + build_context.linker_choice = Linker_lld; + } + if (!build_context.use_separate_modules) { + build_context.use_separate_modules = true; + if (build_context.use_single_module) { + gb_printf_err("-linker: cannot be used with -use-single-module\n"); + bad_flags = true; + } + } + } else if (str_eq_ignore_case(value.value_string, str_lit("thin-files"))) { + build_context.lto_kind = LTO_Thin_Files; + if (build_context.linker_choice == Linker_Invalid) { + build_context.linker_choice = Linker_lld; + } + if (!build_context.use_separate_modules) { + build_context.use_separate_modules = true; + if (build_context.use_single_module) { + gb_printf_err("-linker: cannot be used with -use-single-module\n"); + bad_flags = true; + } + } + } else { + gb_printf_err("-lto: options are 'thin' and 'thin-files'\n"); + bad_flags = true; + } + break; + #if defined(GB_SYSTEM_WINDOWS) case BuildFlag_IgnoreVsSearch: { @@ -1817,6 +1880,8 @@ gb_internal bool parse_build_flags(Array args) { bad_flags = true; } + if (build_context.did_you_mean_limit == 0) build_context.did_you_mean_limit = DEFAULT_DID_YOU_MEAN_LIMIT; + return !bad_flags; } @@ -2041,6 +2106,72 @@ gb_internal void show_defineables(Checker *c) { } } +gb_internal void show_import_graph(Checker *c) { + Parser *p = c->parser; + + gb_printf("digraph odin_import_graph {\n\tnode [shape=box];\n"); + + int cluster_counter = 0; + for (LibraryCollections coll : library_collections) { + gb_printf("\tsubgraph cluster_%i {\n", cluster_counter); + gb_printf("\t\tlabel = \"%.*s\";\n", LIT(coll.name)); + gb_printf("\t\tnode [style=filled, fillcolor=white];\n"); + if (coll.name =="core") { + gb_printf("\t\tbgcolor = lightsalmon;\n"); + } else if (coll.name =="vendor") { + gb_printf("\t\tbgcolor = lightblue;\n"); + } else if (coll.name =="base") { + gb_printf("\t\tbgcolor = lightcoral;\n"); + gb_printf("\t\tintrinsics;\n"); + gb_printf("\t\tbuiltin;\n"); + } + for (AstPackage *pkg : p->packages) { + if (string_starts_with(pkg->fullpath, coll.path)) { + gb_printf("\t\t\"%.*s\";\n", LIT(pkg->fullpath)); + } + } + gb_printf("\t}\n"); + cluster_counter += 1; + } + + for (AstPackage *pkg : p->packages) { + for (int i = 0; i < pkg->files.count; i++) { + AstFile *file = pkg->files[i]; + for(Ast *imp : file->imports) { + GB_ASSERT(imp->kind == Ast_ImportDecl); + + bool exists = false; + for (int j = i + 1; j < pkg->files.count; j++) { + AstFile *other_file = pkg->files[j]; + for(Ast *other_imp : other_file->imports) { + GB_ASSERT(other_imp->kind == Ast_ImportDecl); + if (0 == string_compare(imp->ImportDecl.fullpath, other_imp->ImportDecl.fullpath)) { + exists = true; + break; + } + } + if (exists) { + break; + } + } + + if (exists) { + continue; + } + + String path = imp->ImportDecl.fullpath; + if (imp->ImportDecl.package != nullptr) { + path = imp->ImportDecl.package->fullpath; + } + + gb_printf("\t\"%.*s\" -> \"%.*s\";\n", LIT(pkg->fullpath), LIT(path)); + } + } + } + + gb_printf("}\n\n"); +} + gb_internal void show_timings(Checker *c, Timings *t) { Parser *p = c->parser; isize lines = p->total_line_count; @@ -2719,8 +2850,12 @@ gb_internal int print_show_help(String const arg0, String command, String option } } - if (print_flag("-lld")) { - print_usage_line(2, "Uses the LLD linker rather than the default."); + if (print_flag("-lto:")) { + print_usage_line(2, "States that the project is to be build with link-time optimizations."); + print_usage_line(2, "This also enables '-use-separate-modules' (if not already set) and `-linker:lld"); + print_usage_line(2, "Choices:"); + print_usage_line(3, "thin (one module per package)"); + print_usage_line(3, "thin-files (one module file)"); } } @@ -2730,6 +2865,12 @@ gb_internal int print_show_help(String const arg0, String command, String option print_usage_line(2, "Must be an integer >0."); print_usage_line(2, "If not set, the default max error count is %d.", DEFAULT_MAX_ERROR_COLLECTOR_COUNT); } + + if (print_flag("-did-you-mean-limit:")) { + print_usage_line(2, "Sets the maximum number of suggestions the compiler provides."); + print_usage_line(2, "Must be an integer >0."); + print_usage_line(2, "If not set, the default limit is %d.", DEFAULT_DID_YOU_MEAN_LIMIT); + } } if (run_or_build) { @@ -2848,10 +2989,6 @@ gb_internal int print_show_help(String const arg0, String command, String option } if (run_or_build) { - if (print_flag("-radlink")) { - print_usage_line(2, "Uses the RAD linker rather than the default."); - } - if (print_flag("-reloc-mode:")) { print_usage_line(2, "Specifies the reloc mode."); print_usage_line(2, "Available options:"); @@ -2898,6 +3035,10 @@ gb_internal int print_show_help(String const arg0, String command, String option print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler."); } + if (print_flag("-show-import-graph")) { + print_usage_line(2, "Shows dot graph text format of the import graph of a project."); + } + if (print_flag("-show-timings")) { print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds."); } @@ -2971,6 +3112,10 @@ gb_internal int print_show_help(String const arg0, String command, String option if (check) { if (print_flag("-target:")) { print_usage_line(2, "Sets the target for the executable to be built in."); + print_usage_line(2, "Examples:"); + print_usage_line(3, "-target:linux_amd64"); + print_usage_line(3, "-target:windows_amd64"); + print_usage_line(3, "-target:\"?\" for a list"); } if (print_flag("-terse-errors")) { @@ -3867,8 +4012,8 @@ int main(int arg_count, char const **arg_ptr) { init_universal(); // TODO(bill): prevent compiling without a linker - Parser *parser = gb_alloc_item(permanent_allocator(), Parser); - Checker *checker = gb_alloc_item(permanent_allocator(), Checker); + Parser * parser = permanent_alloc_item(); + Checker *checker = permanent_alloc_item(); bool failed_to_cache_parsing = false; MAIN_TIME_SECTION("parse files"); @@ -3942,6 +4087,9 @@ int main(int arg_count, char const **arg_ptr) { if (build_context.show_timings) { show_timings(checker, &global_timings); } + if (build_context.show_import_graph) { + show_import_graph(checker); + } return 0; } @@ -3953,6 +4101,9 @@ int main(int arg_count, char const **arg_ptr) { if (build_context.show_timings) { show_timings(checker, &global_timings); } + if (build_context.show_import_graph) { + show_import_graph(checker); + } if (global_error_collector.count != 0) { return 1; @@ -3986,6 +4137,9 @@ int main(int arg_count, char const **arg_ptr) { if (build_context.show_timings) { show_timings(checker, &global_timings); } + if (build_context.show_import_graph) { + show_import_graph(checker); + } if (build_context.export_dependencies_format != DependenciesExportUnspecified) { export_dependencies(checker); @@ -3997,7 +4151,7 @@ int main(int arg_count, char const **arg_ptr) { } else #endif { - lbGenerator *gen = gb_alloc_item(permanent_allocator(), lbGenerator); + lbGenerator *gen = permanent_alloc_item(); if (!lb_init_generator(gen, checker)) { return 1; } @@ -4017,6 +4171,9 @@ int main(int arg_count, char const **arg_ptr) { if (build_context.show_timings) { show_timings(checker, &global_timings); } + if (build_context.show_import_graph) { + show_import_graph(checker); + } if (build_context.export_dependencies_format != DependenciesExportUnspecified) { export_dependencies(checker); @@ -4034,6 +4191,14 @@ int main(int arg_count, char const **arg_ptr) { remove_temp_files(gen); } + if (any_errors()) { + print_all_errors(); + return 1; + } + if (any_warnings()) { + print_all_errors(); + } + end_of_code_gen:; if (build_context.export_dependencies_format != DependenciesExportUnspecified) { @@ -4054,6 +4219,9 @@ end_of_code_gen:; if (build_context.show_timings) { show_timings(checker, &global_timings); } + if (build_context.show_import_graph) { + show_import_graph(checker); + } if (run_output) { String exe_name = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]); diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index f1dccb182..1a4ca6439 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -559,8 +559,10 @@ gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e) { // no prefix return; } - if (e->parent_proc_decl) { - Entity *p = e->parent_proc_decl->entity; + InternedString interned = entity_interned_name(e); + + if (e->parent_proc_decl.load(std::memory_order_relaxed)) { + Entity *p = e->parent_proc_decl.load(std::memory_order_relaxed)->entity; write_canonical_parent_prefix(w, p); type_writer_append(w, p->token.string.text, p->token.string.len); if (is_type_polymorphic(p->type)) { @@ -569,7 +571,7 @@ gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e) { } type_writer_appendc(w, CANONICAL_NAME_SEPARATOR); - } else if (e->pkg && (scope_lookup_current(e->pkg->scope, e->token.string) == e)) { + } else if (e->pkg && (scope_lookup_current(e->pkg->scope, interned) == e)) { type_writer_append(w, e->pkg->name.text, e->pkg->name.len); if (e->pkg->name == "llvm") { type_writer_appendc(w, "$"); @@ -748,8 +750,8 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) { return; } - type = default_type(type); - GB_ASSERT(!is_type_untyped(type)); + // type = default_type(type); + // GB_ASSERT(!is_type_untyped(type)); switch (type->kind) { case Type_Basic: @@ -788,6 +790,10 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) { type_writer_appendc(w, "[dynamic]"); write_type_to_canonical_string(w, type->DynamicArray.elem); return; + case Type_FixedCapacityDynamicArray: + type_writer_append_fmt(w, "[dynamic;%lld]", cast(long long)type->FixedCapacityDynamicArray.capacity); + write_type_to_canonical_string(w, type->FixedCapacityDynamicArray.elem); + return; case Type_SimdVector: type_writer_append_fmt(w, "#simd[%lld]", cast(long long)type->SimdVector.count); write_type_to_canonical_string(w, type->SimdVector.elem); @@ -838,7 +844,8 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) { } else { type_writer_append_fmt(w, "%lld", type->BitSet.lower); type_writer_append_fmt(w, CANONICAL_RANGE_OPERATOR); - type_writer_append_fmt(w, "%lld", type->BitSet.upper); + write_type_to_canonical_string(w, type->BitSet.elem); + type_writer_append_fmt(w, "(%lld)", type->BitSet.upper); } if (type->BitSet.underlying != nullptr) { type_writer_appendc(w, ";"); diff --git a/src/parser.cpp b/src/parser.cpp index 06703d643..584979064 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -353,12 +353,14 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) { break; case Ast_RangeStmt: n->RangeStmt.label = clone_ast(n->RangeStmt.label, f); + n->RangeStmt.init = clone_ast(n->RangeStmt.init, f); n->RangeStmt.vals = clone_ast_array(n->RangeStmt.vals, f); n->RangeStmt.expr = clone_ast(n->RangeStmt.expr, f); n->RangeStmt.body = clone_ast(n->RangeStmt.body, f); break; case Ast_UnrollRangeStmt: n->UnrollRangeStmt.args = clone_ast_array(n->UnrollRangeStmt.args, f); + n->UnrollRangeStmt.init = clone_ast(n->UnrollRangeStmt.init, f); n->UnrollRangeStmt.val0 = clone_ast(n->UnrollRangeStmt.val0, f); n->UnrollRangeStmt.val1 = clone_ast(n->UnrollRangeStmt.val1, f); n->UnrollRangeStmt.expr = clone_ast(n->UnrollRangeStmt.expr, f); @@ -454,6 +456,12 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) { break; case Ast_DynamicArrayType: n->DynamicArrayType.elem = clone_ast(n->DynamicArrayType.elem, f); + n->DynamicArrayType.tag = clone_ast(n->DynamicArrayType.tag, f); + break; + case Ast_FixedCapacityDynamicArrayType: + n->FixedCapacityDynamicArrayType.elem = clone_ast(n->FixedCapacityDynamicArrayType.elem, f); + n->FixedCapacityDynamicArrayType.capacity = clone_ast(n->FixedCapacityDynamicArrayType.capacity, f); + n->FixedCapacityDynamicArrayType.tag = clone_ast(n->FixedCapacityDynamicArrayType.tag, f); break; case Ast_StructType: n->StructType.fields = clone_ast_array(n->StructType.fields, f); @@ -514,6 +522,22 @@ gb_internal void error(Ast *node, char const *fmt, ...) { } } +gb_internal void error_range(TokenPos start, TokenPos end, char const *fmt, ...) { + GB_ASSERT(start.file_id == end.file_id); + GB_ASSERT(start.line == end.line); + GB_ASSERT(start.column <= end.column); + GB_ASSERT(start.offset <= end.offset); + + va_list va; + va_start(va, fmt); + error_va(start, end, fmt, va); + va_end(va); + if (start.file_id != 0) { + AstFile *f = thread_safe_get_ast_file_from_id(start.file_id); + f->error_count += 1; + } +} + gb_internal void syntax_error_with_verbose(Ast *node, char const *fmt, ...) { Token token = {}; TokenPos end_pos = {}; @@ -749,8 +773,9 @@ gb_internal Ast *ast_matrix_index_expr(AstFile *f, Ast *expr, Token open, Token gb_internal Ast *ast_ident(AstFile *f, Token token) { Ast *result = alloc_ast_node(f, Ast_Ident); - result->Ident.token = token; - result->Ident.hash = string_hash(token.string); + result->Ident.token = token; + result->Ident.hash = string_hash(token.string); + result->Ident.interned = string_interner_insert(token.string); return result; } @@ -767,6 +792,7 @@ gb_internal Ast *ast_uninit(AstFile *f, Token token) { gb_internal ExactValue exact_value_from_token(AstFile *f, Token const &token) { String s = token.string; + string_interner_insert(s); switch (token.kind) { case Token_Rune: if (!unquote_string(ast_allocator(f), &s, 0)) { @@ -786,7 +812,12 @@ gb_internal ExactValue exact_value_from_token(AstFile *f, Token const &token) { syntax_error(token, "Invalid integer literal"); break; case Token_Float: - syntax_error(token, "Invalid float literal"); + // NOTE(Jeroen): Could be an integer, see `exact_value_float_from_string` + if (!string_contains_char(s, '.') && !string_contains_char(s, '-')) { + syntax_error(token, "Invalid integer literal"); + } else { + syntax_error(token, "Invalid float literal"); + } break; default: syntax_error(token, "Invalid token literal"); @@ -818,6 +849,7 @@ gb_internal Ast *ast_basic_directive(AstFile *f, Token token, Token name) { Ast *result = alloc_ast_node(f, Ast_BasicDirective); result->BasicDirective.token = token; result->BasicDirective.name = name; + string_interner_insert(name.string); if (string_starts_with(name.string, str_lit("load"))) { f->seen_load_directive_count++; } @@ -1039,9 +1071,10 @@ gb_internal Ast *ast_for_stmt(AstFile *f, Token token, Ast *init, Ast *cond, Ast return result; } -gb_internal Ast *ast_range_stmt(AstFile *f, Token token, Slice vals, Token in_token, Ast *expr, Ast *body) { +gb_internal Ast *ast_range_stmt(AstFile *f, Token token, Ast *init, Slice vals, Token in_token, Ast *expr, Ast *body) { Ast *result = alloc_ast_node(f, Ast_RangeStmt); result->RangeStmt.token = token; + result->RangeStmt.init = init; result->RangeStmt.vals = vals; result->RangeStmt.in_token = in_token; result->RangeStmt.expr = expr; @@ -1049,9 +1082,10 @@ gb_internal Ast *ast_range_stmt(AstFile *f, Token token, Slice vals, Toke return result; } -gb_internal Ast *ast_unroll_range_stmt(AstFile *f, Token unroll_token, Slice args, Token for_token, Ast *val0, Ast *val1, Token in_token, Ast *expr, Ast *body) { +gb_internal Ast *ast_unroll_range_stmt(AstFile *f, Token unroll_token, Ast *init, Slice args, Token for_token, Ast *val0, Ast *val1, Token in_token, Ast *expr, Ast *body) { Ast *result = alloc_ast_node(f, Ast_UnrollRangeStmt); result->UnrollRangeStmt.unroll_token = unroll_token; + result->UnrollRangeStmt.init = init; result->UnrollRangeStmt.args = args; result->UnrollRangeStmt.for_token = for_token; result->UnrollRangeStmt.val0 = val0; @@ -1229,8 +1263,16 @@ gb_internal Ast *ast_dynamic_array_type(AstFile *f, Token token, Ast *elem) { return result; } +gb_internal Ast *ast_fixed_capacity_dynamic_array_type(AstFile *f, Token token, Ast *capacity, Ast *elem) { + Ast *result = alloc_ast_node(f, Ast_FixedCapacityDynamicArrayType); + result->FixedCapacityDynamicArrayType.token = token; + result->FixedCapacityDynamicArrayType.capacity = capacity; + result->FixedCapacityDynamicArrayType.elem = elem; + return result; +} + gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice fields, isize field_count, - Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_all_or_none, + Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_all_or_none, bool is_simple, Ast *align, Ast *min_field_align, Ast *max_field_align, Token where_token, Array const &where_clauses) { Ast *result = alloc_ast_node(f, Ast_StructType); @@ -1241,6 +1283,7 @@ gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice fields, i result->StructType.is_packed = is_packed; result->StructType.is_raw_union = is_raw_union; result->StructType.is_all_or_none = is_all_or_none; + result->StructType.is_simple = is_simple; result->StructType.align = align; result->StructType.min_field_align = min_field_align; result->StructType.max_field_align = max_field_align; @@ -1413,9 +1456,6 @@ gb_internal Token consume_comment(AstFile *f, isize *end_line_) { if (end_line_) *end_line_ = end_line; next_token0(f); - if (f->curr_token.pos.line > tok.pos.line || tok.kind == Token_EOF) { - end_line++; - } return tok; } @@ -1439,7 +1479,7 @@ gb_internal CommentGroup *consume_comment_group(AstFile *f, isize n, isize *end_ CommentGroup *comments = nullptr; if (list.count > 0) { - comments = gb_alloc_item(permanent_allocator(), CommentGroup); + comments = permanent_alloc_item(); comments->list = slice_from_array(list); array_add(&f->comments, comments); } @@ -2176,38 +2216,50 @@ gb_internal bool ast_on_same_line(Token const &x, Ast *yp) { return x.pos.line == y.pos.line; } -gb_internal Ast *parse_force_inlining_operand(AstFile *f, Token token) { +gb_internal Ast *parse_inlining_or_tailing_operand(AstFile *f, Token token) { Ast *expr = parse_unary_expr(f, false); Ast *e = strip_or_return_expr(expr); if (e == nullptr) { return expr; } if (e->kind != Ast_ProcLit && e->kind != Ast_CallExpr) { - syntax_error(expr, "%.*s must be followed by a procedure literal or call, got %.*s", LIT(token.string), LIT(ast_strings[expr->kind])); + syntax_error(expr, "%.*s must be followed by a procedure literal or call, got %.*s", LIT(token.string), LIT(ast_strings[e->kind])); return ast_bad_expr(f, token, f->curr_token); } ProcInlining pi = ProcInlining_none; + ProcTailing pt = ProcTailing_none; if (token.kind == Token_Ident) { if (token.string == "force_inline") { pi = ProcInlining_inline; } else if (token.string == "force_no_inline") { pi = ProcInlining_no_inline; + } else if (token.string == "must_tail") { + pt = ProcTailing_must_tail; } } if (pi != ProcInlining_none) { if (e->kind == Ast_ProcLit) { - if (expr->ProcLit.inlining != ProcInlining_none && - expr->ProcLit.inlining != pi) { + if (e->ProcLit.inlining != ProcInlining_none && + e->ProcLit.inlining != pi) { syntax_error(expr, "Cannot apply both '#force_inline' and '#force_no_inline' to a procedure literal"); } - expr->ProcLit.inlining = pi; + e->ProcLit.inlining = pi; } else if (e->kind == Ast_CallExpr) { - if (expr->CallExpr.inlining != ProcInlining_none && - expr->CallExpr.inlining != pi) { + if (e->CallExpr.inlining != ProcInlining_none && + e->CallExpr.inlining != pi) { syntax_error(expr, "Cannot apply both '#force_inline' and '#force_no_inline' to a procedure call"); } - expr->CallExpr.inlining = pi; + e->CallExpr.inlining = pi; + } + } + + if (pt != ProcTailing_none) { + if (e->kind == Ast_ProcLit) { + syntax_error(expr, "'#must_call' can only be applied to a procedure call, not the procedure literal"); + e->ProcLit.tailing = pt; + } else if (e->kind == Ast_CallExpr) { + e->CallExpr.tailing = pt; } } @@ -2435,9 +2487,10 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { Ast *original_type = parse_type(f); Ast *type = unparen_expr(original_type); switch (type->kind) { - case Ast_ArrayType: type->ArrayType.tag = tag; break; - case Ast_DynamicArrayType: type->DynamicArrayType.tag = tag; break; - case Ast_PointerType: type->PointerType.tag = tag; break; + case Ast_ArrayType: type->ArrayType.tag = tag; break; + case Ast_DynamicArrayType: type->DynamicArrayType.tag = tag; break; + case Ast_PointerType: type->PointerType.tag = tag; break; + case Ast_FixedCapacityDynamicArrayType: type->FixedCapacityDynamicArrayType.tag = tag; break; default: syntax_error(type, "Expected an array or pointer type after #%.*s, got %.*s", LIT(name.string), LIT(ast_strings[type->kind])); break; @@ -2507,8 +2560,9 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { syntax_error(tag, "#relative types have now been removed in favour of \"core:relative\""); return ast_relative_type(f, tag, type); } else if (name.string == "force_inline" || - name.string == "force_no_inline") { - return parse_force_inlining_operand(f, name); + name.string == "force_no_inline" || + name.string == "must_tail") { + return parse_inlining_or_tailing_operand(f, name); } return ast_basic_directive(f, token, name); } @@ -2666,8 +2720,25 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { } else if (f->curr_token.kind == Token_Question) { count_expr = ast_unary_expr(f, expect_token(f, Token_Question), nullptr); } else if (allow_token(f, Token_dynamic)) { + Ast *capacity = nullptr; + if (f->curr_token.kind == Token_Semicolon && f->curr_token.string == ";") { + expect_token(f, Token_Semicolon); + capacity = parse_expr(f, false); + } else if (allow_token(f, Token_Comma) || allow_token(f, Token_Semicolon)) { + String p = token_to_string(f->prev_token); + syntax_error(token_end_of_line(f, f->prev_token), "Expected a semicolon, got a %.*s", LIT(p)); + + capacity = parse_expr(f, false); + } expect_token(f, Token_CloseBracket); - return ast_dynamic_array_type(f, token, parse_type(f)); + + Ast *elem = parse_type(f); + + if (capacity == nullptr) { + return ast_dynamic_array_type(f, token, elem); + } else { + return ast_fixed_capacity_dynamic_array_type(f, token, capacity, elem); + } } else if (f->curr_token.kind != Token_CloseBracket) { f->expr_level++; count_expr = parse_expr(f, false); @@ -2775,6 +2846,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { bool is_packed = false; bool is_all_or_none = false; bool is_raw_union = false; + bool is_simple = false; Ast *align = nullptr; Ast *min_field_align = nullptr; Ast *max_field_align = nullptr; @@ -2803,7 +2875,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { } is_packed = true; } else if (tag.string == "all_or_none") { - if (is_packed) { + if (is_all_or_none) { syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); } is_all_or_none = true; @@ -2856,11 +2928,16 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { error_line("\tSuggestion: #max_field_align(%s)", s); gb_string_free(s); } - }else if (tag.string == "raw_union") { + } else if (tag.string == "raw_union") { if (is_raw_union) { syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); } is_raw_union = true; + } else if (tag.string == "simple") { + if (is_simple) { + syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); + } + is_simple = true; } else { syntax_error(tag, "Invalid struct tag '#%.*s'", LIT(tag.string)); } @@ -2906,7 +2983,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { parser_check_polymorphic_record_parameters(f, polymorphic_params); return ast_struct_type(f, token, decls, name_count, - polymorphic_params, is_packed, is_raw_union, is_all_or_none, + polymorphic_params, is_packed, is_raw_union, is_all_or_none, is_simple, align, min_field_align, max_field_align, where_token, where_clauses); } break; @@ -3110,6 +3187,8 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { } else { dialect = InlineAsmDialect_Intel; } + } else { + syntax_error(token, "Invalid directive on inline asm expression: '#%.*s'", LIT(token.string)); } } else { syntax_error(f->curr_token, "Expected an identifier after hash"); @@ -3142,6 +3221,7 @@ gb_internal bool is_literal_type(Ast *node) { case Ast_StructType: case Ast_UnionType: case Ast_EnumType: + case Ast_FixedCapacityDynamicArrayType: case Ast_DynamicArrayType: case Ast_MapType: case Ast_BitSetType: @@ -3448,6 +3528,9 @@ gb_internal Ast *parse_unary_expr(AstFile *f, bool lhs) { case Token_Mul: // Used for error handling when people do C-like things { Token token = advance_token(f); + if (token.kind == Token_Not) { + skip_possible_newline(f); + } Ast *expr = parse_unary_expr(f, lhs); return ast_unary_expr(f, token, expr); } @@ -4008,6 +4091,10 @@ gb_internal ProcCallingConvention string_to_calling_convention(String const &s) if (s == "win64") return ProcCC_Win64; if (s == "sysv") return ProcCC_SysV; + if (s == "preserve/none") return ProcCC_PreserveNone; + if (s == "preserve/most") return ProcCC_PreserveMost; + if (s == "preserve/all") return ProcCC_PreserveAll; + if (s == "system") { if (build_context.metrics.os == TargetOs_windows) { return ProcCC_StdCall; @@ -4841,7 +4928,7 @@ gb_internal Ast *parse_for_stmt(AstFile *f) { body = parse_block_stmt(f, false); } - return ast_range_stmt(f, token, {}, in_token, rhs, body); + return ast_range_stmt(f, token, init, {}, in_token, rhs, body); } if (f->curr_token.kind != Token_Semicolon) { @@ -4856,9 +4943,20 @@ gb_internal Ast *parse_for_stmt(AstFile *f) { cond = nullptr; if (f->curr_token.kind == Token_OpenBrace || f->curr_token.kind == Token_do) { - syntax_error(f->curr_token, "Expected ';', followed by a condition expression and post statement, got %.*s", LIT(token_strings[f->curr_token.kind])); + syntax_error(f->curr_token, "Expected ';', followed by a condition expression and post statement, or 'x in y' style loop, got %.*s", LIT(token_strings[f->curr_token.kind])); } else { if (f->curr_token.kind != Token_Semicolon) { + if (f->curr_token.kind == Token_Ident) { + // for init; x in y { } + Token next_token = peek_token(f); + if (next_token.kind == Token_in || next_token.kind == Token_Comma) { + cond = parse_simple_stmt(f, StmtAllowFlag_In); + GB_ASSERT(cond->kind == Ast_AssignStmt && cond->AssignStmt.op.kind == Token_in); + is_range = true; + goto range_skip; + } + } + cond = parse_simple_stmt(f, StmtAllowFlag_None); } @@ -4876,6 +4974,7 @@ gb_internal Ast *parse_for_stmt(AstFile *f) { } } +range_skip:; if (allow_token(f, Token_do)) { body = parse_do_body(f, token, "the for statement"); @@ -4891,7 +4990,7 @@ gb_internal Ast *parse_for_stmt(AstFile *f) { if (cond->AssignStmt.rhs.count > 0) { rhs = cond->AssignStmt.rhs[0]; } - return ast_range_stmt(f, token, vals, in_token, rhs, body); + return ast_range_stmt(f, token, init, vals, in_token, rhs, body); } cond = convert_stmt_to_expr(f, cond, str_lit("boolean expression")); @@ -5054,6 +5153,10 @@ gb_internal Ast *parse_import_decl(AstFile *f, ImportDeclKind kind) { syntax_error(import_name, "'using import' is not allowed, please use the import name explicitly"); } + if (file_path.string == "\".\"") { + // syntax_error(import_name, "Cannot cyclicly import packages"); + } + expect_semicolon(f); return s; } @@ -5221,6 +5324,7 @@ gb_internal Ast *parse_unrolled_for_loop(AstFile *f, Token unroll_token) { } Token for_token = expect_token(f, Token_for); + Ast *init = nullptr; Ast *val0 = nullptr; Ast *val1 = nullptr; Token in_token = {}; @@ -5263,7 +5367,7 @@ gb_internal Ast *parse_unrolled_for_loop(AstFile *f, Token unroll_token) { if (bad_stmt) { return ast_bad_stmt(f, unroll_token, f->curr_token); } - return ast_unroll_range_stmt(f, unroll_token, slice_from_array(args), for_token, val0, val1, in_token, expr, body); + return ast_unroll_range_stmt(f, unroll_token, init, slice_from_array(args), for_token, val0, val1, in_token, expr, body); } gb_internal Ast *parse_stmt(AstFile *f) { @@ -5381,9 +5485,15 @@ gb_internal Ast *parse_stmt(AstFile *f) { s = parse_stmt(f); switch (s->kind) { case Ast_SwitchStmt: + if (s->SwitchStmt.partial) { + syntax_error(token, "#partial already applied to a switch statement"); + } s->SwitchStmt.partial = true; break; case Ast_TypeSwitchStmt: + if (s->TypeSwitchStmt.partial) { + syntax_error(token, "#partial already applied to a switch statement"); + } s->TypeSwitchStmt.partial = true; break; case Ast_EmptyStmt: @@ -5399,8 +5509,9 @@ gb_internal Ast *parse_stmt(AstFile *f) { expect_semicolon(f); return stmt; } else if (name.string == "force_inline" || - name.string == "force_no_inline") { - Ast *expr = parse_force_inlining_operand(f, name); + name.string == "force_no_inline" || + name.string == "must_tail") { + Ast *expr = parse_inlining_or_tailing_operand(f, name); Ast *stmt = ast_expr_stmt(f, expr); expect_semicolon(f); return stmt; @@ -5689,7 +5800,7 @@ gb_internal WORKER_TASK_PROC(parser_worker_proc) { ParserWorkerData *wd = cast(ParserWorkerData *)data; ParseFileError err = process_imported_file(wd->parser, wd->imported_file); if (err != ParseFile_None) { - auto *node = gb_alloc_item(permanent_allocator(), ParseFileErrorNode); + auto *node = permanent_alloc_item(); node->err = err; MUTEX_GUARD_BLOCK(&wd->parser->file_error_mutex) { @@ -5709,7 +5820,7 @@ gb_internal WORKER_TASK_PROC(parser_worker_proc) { gb_internal void parser_add_file_to_process(Parser *p, AstPackage *pkg, FileInfo fi, TokenPos pos) { ImportedFile f = {pkg, fi, pos, p->file_to_process_count++}; f.pos.file_id = cast(i32)(f.index+1); - auto wd = gb_alloc_item(permanent_allocator(), ParserWorkerData); + auto wd = permanent_alloc_item(); wd->parser = p; wd->imported_file = f; thread_pool_add_task(parser_worker_proc, wd); @@ -5746,7 +5857,7 @@ gb_internal void parser_add_foreign_file_to_process(Parser *p, AstPackage *pkg, // TODO(bill): Use a better allocator ImportedFile f = {pkg, fi, pos, p->file_to_process_count++}; f.pos.file_id = cast(i32)(f.index+1); - auto wd = gb_alloc_item(permanent_allocator(), ForeignFileWorkerData); + auto wd = permanent_alloc_item(); wd->parser = p; wd->imported_file = f; wd->foreign_kind = kind; @@ -5766,7 +5877,7 @@ gb_internal AstPackage *try_add_import_path(Parser *p, String path, String const path = copy_string(permanent_allocator(), path); - AstPackage *pkg = gb_alloc_item(permanent_allocator(), AstPackage); + AstPackage *pkg = permanent_alloc_item(); pkg->kind = kind; pkg->fullpath = path; array_init(&pkg->files, permanent_allocator()); @@ -5818,6 +5929,11 @@ gb_internal AstPackage *try_add_import_path(Parser *p, String path, String const return nullptr; } + if (string_ends_with(path, str_lit(".odin"))) { + error(pos, "'import' declarations cannot import directories with a .odin extension/suffix"); + return nullptr; + } + isize files_with_ext = 0; isize files_to_reserve = 1; // always reserve 1 for (FileInfo fi : list) { @@ -5996,6 +6112,12 @@ gb_internal bool determine_path_from_string(BlockingMutex *file_mutex, Ast *node has_windows_drive = true; } } + + for (isize i = 0; i < original_string.len; i++) { + if (original_string.text[i] == '\\') { + original_string.text[i] = '/'; + } + } } #endif @@ -6205,9 +6327,28 @@ gb_internal String build_tag_get_token(String s, String *out) { return s; } +// returns true on failure +gb_internal bool build_require_space_after(String s, String prefix) { + GB_ASSERT(string_starts_with(s, prefix)); + + if (s.len == prefix.len) { + return false; + } + String stripped = string_trim_whitespace(substring(s, prefix.len, s.len)); + + if (s[prefix.len] != ' ' && stripped.len != 0) { + return true; + } + return false; +} + gb_internal bool parse_build_tag(Token token_for_pos, String s) { String const prefix = str_lit("build"); GB_ASSERT(string_starts_with(s, prefix)); + if (build_require_space_after(s, prefix)) { + syntax_error(token_for_pos, "Expected a space after #+%.*s", LIT(prefix)); + return true; + } s = string_trim_whitespace(substring(s, prefix.len, s.len)); if (s.len == 0) { @@ -6331,19 +6472,21 @@ gb_internal String vet_tag_get_token(String s, String *out, bool allow_colon) { } -gb_internal u64 parse_vet_tag(Token token_for_pos, String s) { +gb_internal u64 parse_vet_tag(Token token_for_pos, String s, u64 base_vet_flags) { String const prefix = str_lit("vet"); GB_ASSERT(string_starts_with(s, prefix)); + if (build_require_space_after(s, prefix)) { + syntax_error(token_for_pos, "Expected a space after #+%.*s", LIT(prefix)); + return true; + } s = string_trim_whitespace(substring(s, prefix.len, s.len)); + u64 vet_flags = base_vet_flags; + if (s.len == 0) { - return VetFlag_All; + vet_flags |= VetFlag_All; } - - u64 vet_flags = 0; - u64 vet_not_flags = 0; - while (s.len > 0) { String p = string_trim_whitespace(vet_tag_get_token(s, &s, /*allow_colon*/false)); if (p.len == 0) { @@ -6356,16 +6499,16 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) { p = substring(p, 1, p.len); if (p.len == 0) { syntax_error(token_for_pos, "Expected a vet flag name after '!'"); - return build_context.vet_flags; + return vet_flags; } } u64 flag = get_vet_flag_from_name(p); if (flag != VetFlag_NONE) { if (is_notted) { - vet_not_flags |= flag; + vet_flags = vet_flags &~ flag; } else { - vet_flags |= flag; + vet_flags |= flag; } } else { ERROR_BLOCK(); @@ -6383,26 +6526,20 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) { error_line("\tcast\n"); error_line("\ttabs\n"); error_line("\texplicit-allocators\n"); - return build_context.vet_flags; + return vet_flags; } } - if (vet_flags == 0 && vet_not_flags == 0) { - return build_context.vet_flags; - } - if (vet_flags == 0 && vet_not_flags != 0) { - return build_context.vet_flags &~ vet_not_flags; - } - if (vet_flags != 0 && vet_not_flags == 0) { - return vet_flags; - } - GB_ASSERT(vet_flags != 0 && vet_not_flags != 0); - return vet_flags &~ vet_not_flags; + return vet_flags; } gb_internal u64 parse_feature_tag(Token token_for_pos, String s) { String const prefix = str_lit("feature"); GB_ASSERT(string_starts_with(s, prefix)); + if (build_require_space_after(s, prefix)) { + syntax_error(token_for_pos, "Expected a space after #+%.*s", LIT(prefix)); + return true; + } s = string_trim_whitespace(substring(s, prefix.len, s.len)); if (s.len == 0) { @@ -6449,6 +6586,8 @@ gb_internal u64 parse_feature_tag(Token token_for_pos, String s) { syntax_error(token_for_pos, "Invalid feature flag name: %.*s", LIT(p)); error_line("\tExpected one of the following\n"); error_line("\tdynamic-literals\n"); + error_line("\tglobal-context\n"); + error_line("\tusing-stmt\n"); error_line("\tinteger-division-by-zero:trap\n"); error_line("\tinteger-division-by-zero:zero\n"); error_line("\tinteger-division-by-zero:self\n"); @@ -6576,7 +6715,7 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) return false; } } else if (string_starts_with(lc, str_lit("vet"))) { - f->vet_flags = parse_vet_tag(tok, lc); + f->vet_flags = parse_vet_tag(tok, lc, ast_file_vet_flags(f)); f->vet_flags_set = true; } else if (string_starts_with(lc, str_lit("test"))) { if ((build_context.command_kind & Command_test) == 0) { @@ -6627,11 +6766,6 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { String filepath = f->tokenizer.fullpath; String base_dir = dir_from_path(filepath); - if (f->curr_token.kind == Token_Comment) { - consume_comment_groups(f, f->prev_token); - } - - CommentGroup *docs = f->lead_comment; Array tags = array_make(temporary_allocator()); bool first_invalid_token_set = false; @@ -6653,6 +6787,8 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { } } + CommentGroup *docs = f->lead_comment; + if (f->curr_token.kind != Token_package) { ERROR_BLOCK(); @@ -6692,37 +6828,12 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { } f->package_name = package_name.string; - { - if (docs != nullptr && docs->list.count > 0) { - for (Token const &tok : docs->list) { - GB_ASSERT(tok.kind == Token_Comment); - String str = tok.string; - - if (!string_starts_with(str, str_lit("//"))) { - continue; - } - - String lc = string_trim_whitespace(substring(str, 2, str.len)); - if (string_starts_with(lc, str_lit("+"))) { - syntax_warning(tok, "'//+' is deprecated: Use '#+' instead"); - String lt = substring(lc, 1, lc.len); - if (parse_file_tag(lt, tok, f) == false) { - return false; - } - } - } - } - - for (Token const &tok : tags) { - GB_ASSERT(tok.kind == Token_FileTag); - String str = tok.string; - - if (string_starts_with(str, str_lit("#+"))) { - String lt = string_trim_whitespace(substring(str, 2, str.len)); - if (parse_file_tag(lt, tok, f) == false) { - return false; - } - } + for (Token const &tok : tags) { + GB_ASSERT(tok.kind == Token_FileTag); + GB_ASSERT(string_starts_with(tok.string, str_lit("#+"))); + String lt = string_trim_whitespace(substring(tok.string, 2, tok.string.len)); + if (parse_file_tag(lt, tok, f) == false) { + return false; } } @@ -6772,7 +6883,7 @@ gb_internal ParseFileError process_imported_file(Parser *p, ImportedFile importe FileInfo fi = imported_file.fi; TokenPos pos = imported_file.pos; - AstFile *file = gb_alloc_item(permanent_allocator(), AstFile); + AstFile *file = permanent_alloc_item(); file->pkg = pkg; file->id = cast(i32)(imported_file.index+1); TokenPos err_pos = {0}; diff --git a/src/parser.hpp b/src/parser.hpp index 71b61d95f..149cf6330 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -263,12 +263,17 @@ struct ForeignFileWorkerData { -enum ProcInlining { - ProcInlining_none = 0, - ProcInlining_inline = 1, +enum ProcInlining : u8 { + ProcInlining_none = 0, + ProcInlining_inline = 1, ProcInlining_no_inline = 2, }; +enum ProcTailing : u8 { + ProcTailing_none = 0, + ProcTailing_must_tail = 1, +}; + enum ProcTag { ProcTag_bounds_check = 1<<0, ProcTag_no_bounds_check = 1<<1, @@ -296,6 +301,9 @@ enum ProcCallingConvention : i32 { ProcCC_Win64 = 9, ProcCC_SysV = 10, + ProcCC_PreserveNone = 11, + ProcCC_PreserveMost = 12, + ProcCC_PreserveAll = 13, ProcCC_MAX, @@ -315,6 +323,9 @@ gb_global char const *proc_calling_convention_strings[ProcCC_MAX] = { "inlineasm", "win64", "sysv", + "preserve/none", + "preserve/most", + "preserve/all", }; gb_internal ProcCallingConvention default_calling_convention(void) { @@ -413,9 +424,10 @@ struct AstSplitArgs { #define AST_KINDS \ AST_KIND(Ident, "identifier", struct { \ - Token token; \ - Entity *entity; \ - u32 hash; \ + Token token; \ + std::atomic entity; \ + u32 hash; \ + InternedString interned; \ }) \ AST_KIND(Implicit, "implicit", Token) \ AST_KIND(Uninit, "uninitialized value", Token) \ @@ -441,6 +453,7 @@ struct AstSplitArgs { Ast *body; \ u64 tags; \ ProcInlining inlining; \ + ProcTailing tailing; \ Token where_token; \ Slice where_clauses; \ DeclInfo *decl; \ @@ -486,6 +499,7 @@ AST_KIND(_ExprBegin, "", bool) \ Token close; \ Token ellipsis; \ ProcInlining inlining; \ + ProcTailing tailing; \ bool optional_ok_one; \ bool was_selector; \ AstSplitArgs *split_args; \ @@ -574,6 +588,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ Scope *scope; \ Token token; \ Ast *label; \ + Ast *init; \ Slice vals; \ Token in_token; \ Ast *expr; \ @@ -583,6 +598,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ AST_KIND(UnrollRangeStmt, "#unroll range statement", struct { \ Scope *scope; \ Token unroll_token; \ + Ast *init; \ Slice args; \ Token for_token; \ Ast *val0; \ @@ -749,8 +765,14 @@ AST_KIND(_TypeBegin, "", bool) \ }) \ AST_KIND(DynamicArrayType, "dynamic array type", struct { \ Token token; \ - Ast *elem; \ - Ast *tag; \ + Ast *elem; \ + Ast *tag; \ + }) \ + AST_KIND(FixedCapacityDynamicArrayType, "fixed capacity dynamic array type", struct { \ + Token token; \ + Ast *capacity; \ + Ast *elem; \ + Ast *tag; \ }) \ AST_KIND(StructType, "struct type", struct { \ Scope *scope; \ @@ -767,6 +789,7 @@ AST_KIND(_TypeBegin, "", bool) \ bool is_raw_union; \ bool is_no_copy; \ bool is_all_or_none; \ + bool is_simple; \ }) \ AST_KIND(UnionType, "union type", struct { \ Scope *scope; \ @@ -842,19 +865,19 @@ gb_global isize const ast_variant_sizes[] = { }; struct AstCommonStuff { - AstKind kind; // u16 - u8 state_flags; - u8 viral_state_flags; - i32 file_id; - TypeAndValue tav; // NOTE(bill): Making this a pointer is slower + AstKind kind; // u16 + u8 state_flags; + std::atomic viral_state_flags; + i32 file_id; + TypeAndValue tav; // NOTE(bill): Making this a pointer is slower }; struct Ast { - AstKind kind; // u16 - u8 state_flags; - u8 viral_state_flags; - i32 file_id; - TypeAndValue tav; // NOTE(bill): Making this a pointer is slower + AstKind kind; // u16 + u8 state_flags; + std::atomic viral_state_flags; + i32 file_id; + TypeAndValue tav; // NOTE(bill): Making this a pointer is slower // IMPORTANT NOTE(bill): This must be at the end since the AST is allocated to be size of the variant union { diff --git a/src/parser_pos.cpp b/src/parser_pos.cpp index 1ffd3a82f..1d2b5090a 100644 --- a/src/parser_pos.cpp +++ b/src/parser_pos.cpp @@ -107,6 +107,7 @@ gb_internal Token ast_token(Ast *node) { case Ast_MultiPointerType: return node->MultiPointerType.token; case Ast_ArrayType: return node->ArrayType.token; case Ast_DynamicArrayType: return node->DynamicArrayType.token; + case Ast_FixedCapacityDynamicArrayType: return node->FixedCapacityDynamicArrayType.token; case Ast_StructType: return node->StructType.token; case Ast_UnionType: return node->UnionType.token; case Ast_EnumType: return node->EnumType.token; @@ -342,6 +343,7 @@ Token ast_end_token(Ast *node) { case Ast_MultiPointerType: return ast_end_token(node->MultiPointerType.type); case Ast_ArrayType: return ast_end_token(node->ArrayType.elem); case Ast_DynamicArrayType: return ast_end_token(node->DynamicArrayType.elem); + case Ast_FixedCapacityDynamicArrayType: return ast_end_token(node->FixedCapacityDynamicArrayType.elem); case Ast_StructType: if (node->StructType.fields.count > 0) { return ast_end_token(node->StructType.fields[node->StructType.fields.count-1]); diff --git a/src/ptr_set.cpp b/src/ptr_set.cpp index 5b1d2cc19..3d30bb35e 100644 --- a/src/ptr_set.cpp +++ b/src/ptr_set.cpp @@ -1,11 +1,14 @@ +enum {PTR_SET_INLINE_CAP = 16}; + template struct PtrSet { static_assert(TypeIsPointer::value || TypeIsPtrSizedInteger::value, "PtrSet::T must be a pointer"); static constexpr uintptr TOMBSTONE = ~(uintptr)(0ull); - T * keys; - usize count; - usize capacity; + T * keys; + u32 count; + u32 capacity; + T inline_keys[PTR_SET_INLINE_CAP]; }; template gb_internal void ptr_set_init (PtrSet *s, isize capacity = 16); @@ -19,24 +22,31 @@ template gb_internal void ptr_set_clear (PtrSet *s); #define FOR_PTR_SET(element, set_) for (auto *it = &(set_).keys[0], element = it ? *it : nullptr; (set_).keys != nullptr && it < &(set_).keys[(set_).capacity]; it++) if (element = *it, (*it != nullptr && *it != cast(void *)~(uintptr)(0ull))) gb_internal gbAllocator ptr_set_allocator(void) { - return heap_allocator(); + // return heap_allocator(); + return permanent_allocator(); } template gb_internal void ptr_set_init(PtrSet *s, isize capacity) { GB_ASSERT(s->keys == nullptr); if (capacity != 0) { - capacity = next_pow2_isize(gb_max(16, capacity)); - s->keys = gb_alloc_array(ptr_set_allocator(), T, capacity); + capacity = next_pow2_isize(gb_max(PTR_SET_INLINE_CAP, capacity)); + if (capacity > PTR_SET_INLINE_CAP) { + s->keys = gb_alloc_array(ptr_set_allocator(), T, capacity); + } else { + s->keys = s->inline_keys; + } // This memory will be zeroed, no need to explicitly zero it } s->count = 0; - s->capacity = capacity; + s->capacity = cast(u32)capacity; } template gb_internal void ptr_set_destroy(PtrSet *s) { - gb_free(ptr_set_allocator(), s->keys); + if (s->keys != s->inline_keys) { + gb_free(ptr_set_allocator(), s->keys); + } s->keys = nullptr; s->count = 0; s->capacity = 0; @@ -46,16 +56,10 @@ template gb_internal isize ptr_set__find(PtrSet *s, T ptr) { GB_ASSERT(ptr != 0); if (s->count != 0) { - #if 0 - for (usize i = 0; i < s->capacity; i++) { - if (s->keys[i] == ptr) { - return i; - } - } - #else u32 hash = ptr_map_hash_key(ptr); usize mask = s->capacity-1; usize hash_index = cast(usize)hash & mask; + for (usize i = 0; i < s->capacity; i++) { T key = s->keys[hash_index]; if (key == ptr) { @@ -65,14 +69,14 @@ gb_internal isize ptr_set__find(PtrSet *s, T ptr) { } hash_index = (hash_index+1)&mask; } - #endif } return -1; } template gb_internal bool ptr_set__full(PtrSet *s) { - return 0.75f * s->capacity <= s->count; + usize grow_at = s->capacity - (s->capacity>>2); + return s->count >= grow_at; } template @@ -122,10 +126,11 @@ gb_internal bool ptr_set_update(PtrSet *s, T ptr) { // returns true if it pre usize hash_index = (cast(usize)hash) & mask; GB_ASSERT(hash_index < s->capacity); for (usize i = 0; i < s->capacity; i++) { - T *key = &s->keys[hash_index]; - GB_ASSERT(*key != ptr); - if (*key == (T)PtrSet::TOMBSTONE || *key == 0) { - *key = ptr; + T *key_ptr = &s->keys[hash_index]; + T key = *key_ptr; + GB_ASSERT(key != ptr); + if (key == (T)PtrSet::TOMBSTONE || key == 0) { + *key_ptr = ptr; s->count++; return false; } @@ -160,10 +165,11 @@ gb_internal bool ptr_set_update_with_mutex(PtrSet *s, T ptr, RWSpinLock *m) { usize hash_index = (cast(usize)hash) & mask; GB_ASSERT(hash_index < s->capacity); for (usize i = 0; i < s->capacity; i++) { - T *key = &s->keys[hash_index]; - GB_ASSERT(*key != ptr); - if (*key == (T)PtrSet::TOMBSTONE || *key == 0) { - *key = ptr; + T *key_ptr = &s->keys[hash_index]; + T key = *key_ptr; + GB_ASSERT(key != ptr); + if (key == (T)PtrSet::TOMBSTONE || key == 0) { + *key_ptr = ptr; s->count++; return false; } @@ -184,11 +190,36 @@ gb_internal T ptr_set_add(PtrSet *s, T ptr) { template gb_internal void ptr_set_remove(PtrSet *s, T ptr) { isize index = ptr_set__find(s, ptr); - if (index >= 0) { - GB_ASSERT(s->count > 0); - s->keys[index] = (T)PtrSet::TOMBSTONE; - s->count--; + if (index < 0) { + return; } + +#if 0 + u32 mask = s->capacity-1; + u32 i = cast(u32)index; + s->count -= 1; + + for (;;) { + u32 next = (i + 1) & mask; + T key = s->keys[next]; + if (key == 0) { + break; + } + + u32 natural = ptr_map_hash_key(key) & mask; + + if (((next - natural) & mask) == 0) { + break; + } + s->keys[i] = key; + i = next; + } + s->keys[i] = 0; +#else + GB_ASSERT(s->count > 0); + s->keys[index] = (T)PtrSet::TOMBSTONE; + s->count--; +#endif } template diff --git a/src/queue.cpp b/src/queue.cpp index 82f82f3e1..563fbe69e 100644 --- a/src/queue.cpp +++ b/src/queue.cpp @@ -37,7 +37,7 @@ gb_internal void mpsc_destroy(MPSCQueue *q) { template gb_internal MPSCNode *mpsc_alloc_node(MPSCQueue *q, T const &value) { // auto new_node = gb_alloc_item(heap_allocator(), MPSCNode); - auto new_node = gb_alloc_item(permanent_allocator(), MPSCNode); + auto new_node = permanent_alloc_item >(); new_node->value = value; return new_node; } diff --git a/src/string.cpp b/src/string.cpp index 9c08114a7..09bce205e 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -182,8 +182,9 @@ gb_internal isize string_index_byte(String const &s, u8 x) { } gb_internal gb_inline bool str_eq(String const &a, String const &b) { - if (a.len != b.len) return false; - if (a.len == 0) return true; + if (a.len != b.len) return false; + if (a.len == 0) return true; + if (a.text == b.text) return true; return memcmp(a.text, b.text, a.len) == 0; } gb_internal gb_inline bool str_ne(String const &a, String const &b) { return !str_eq(a, b); } @@ -635,26 +636,107 @@ gb_internal String normalize_path(gbAllocator a, String const &path, String cons #elif defined(GB_SYSTEM_UNIX) || defined(GB_SYSTEM_OSX) #include + gb_internal void utf16_encode_surrogate_pair(Rune r, u16 *r1, u16 *r2) { + static Rune const _surr_self = 0x10000; + static Rune const _surr1 = 0xd800; + static Rune const _surr2 = 0xdc00; + Rune r_ = r - _surr_self; + *r1 = _surr1 + ((r_ >> 10) & 0x3ff); + *r2 = _surr2 + (r_ & 0x3ff); + } + + gb_internal isize utf16_decode(u16 const *s, isize n, Rune *r) { + static Rune const _surr1 = 0xd800; + static Rune const _surr2 = 0xdc00; + static Rune const _surr3 = 0xe000; + static Rune const _surr_self = 0x10000; + if (n < 1) { + *r = GB_RUNE_INVALID; + return 0; + } + u16 c = s[0]; + if (c < 0xd800 || c > 0xdfff) { + *r = cast(Rune)c; + return 1; + } + if (c >= 0xdc00) { + *r = GB_RUNE_INVALID; + return 1; + } + if (n < 2) { + *r = GB_RUNE_INVALID; + return 1; + } + u16 c2 = s[1]; + if (c2 < 0xdc00 || c2 > 0xdfff) { + *r = GB_RUNE_INVALID; + return 1; + } + *r = (((c-_surr1)<<10) | (c2 - _surr2)) + _surr_self; + return 2; + } + gb_internal int convert_multibyte_to_widechar(char const *multibyte_input, usize input_length, wchar_t *output, usize output_size) { - String string = copy_string(heap_allocator(), make_string(cast(u8 const*)multibyte_input, input_length)); /* Guarantee NULL terminator */ - u8* input = string.text; + u16 *out = cast(u16 *)output; + String s = make_string(cast(u8 const *)multibyte_input, input_length); + isize i = 0; + isize output_len = 0; + while (i < s.len) { + Rune r = 0; + isize width = utf8_decode(s.text + i, s.len - i, &r); + if (r == GB_RUNE_INVALID) { + return -1; + } + i += width; + if (r < 0x10000) { + if (out) { + if (cast(usize)output_len+1 > output_size) { + return -1; + } + out[output_len] = cast(u16)r; + } + output_len += 1; + } else { + if (out) { + if (cast(usize)output_len+2 > output_size) { + return -1; + } + u16 r1, r2; + utf16_encode_surrogate_pair(r, &r1, &r2); + out[output_len+0] = r1; + out[output_len+1] = r2; + } + output_len += 2; + } + } - mbstate_t ps = { 0 }; - size_t result = mbsrtowcs(output, cast(const char**)&input, output_size, &ps); - - gb_free(heap_allocator(), string.text); - return (result == (size_t)-1) ? -1 : (int)result; + return cast(int)output_len; } gb_internal int convert_widechar_to_multibyte(wchar_t const *widechar_input, usize input_length, char* output, usize output_size) { - String string = copy_string(heap_allocator(), make_string(cast(u8 const*)widechar_input, input_length)); /* Guarantee NULL terminator */ - u8* input = string.text; + u16 const *in = cast(u16 const *)widechar_input; + isize i = 0; + isize output_len = 0; + while (i < input_length) { + Rune r; + isize width = utf16_decode(in + i, input_length - i, &r); + if (r == GB_RUNE_INVALID) { + return -1; + } + i += width; - mbstate_t ps = { 0 }; - size_t result = wcsrtombs(output, cast(const wchar_t**)&input, output_size, &ps); + u8 buf[4]; + isize char_len = gb_utf8_encode_rune(buf, r); - gb_free(heap_allocator(), string.text); - return (result == (size_t)-1) ? -1 : (int)result; + if(output) { + if (cast(usize)output_len+cast(usize)char_len > output_size) { + return -1; + } + gb_memmove(output + output_len, buf, char_len); + } + output_len += char_len; + } + return cast(int)output_len; } #else #error Implement system diff --git a/src/string_interner.cpp b/src/string_interner.cpp new file mode 100644 index 000000000..660dbc61d --- /dev/null +++ b/src/string_interner.cpp @@ -0,0 +1,231 @@ +#define STRING_INTERNER_CELL_WIDTH 8 +#define STRING_INTERNER_MUTEX_STRIPE_COUNT 1024 +#define STRING_INTERNER_MUTEX_STRIPE_MASK (STRING_INTERNER_MUTEX_STRIPE_COUNT - 1) +#define STRING_INTERNER_THREAD_LOCAL_SIZE (1024 * 1024 * 2) +#define STRING_INTERN_CACHE_LINE (2*GB_CACHE_LINE_SIZE) + +struct InternedString { + u32 value; + bool operator==(InternedString other) const { + return this->value == other.value; + } + + String string() const; + char const *cstring() const; + u32 hash() const; + + bool is_blank() const; +}; +struct alignas(STRING_INTERN_CACHE_LINE) StringInternCell { + std::atomic hashes [STRING_INTERNER_CELL_WIDTH]; + InternedString offsets[STRING_INTERNER_CELL_WIDTH]; + std::atomic next; +}; + +struct alignas(STRING_INTERN_CACHE_LINE) PaddedMutex { + BlockingMutex m; +}; + +struct alignas(STRING_INTERN_CACHE_LINE) PaddedI64 { + std::atomic value; +}; + +struct StringInterner { + StringInternCell *cells; + u64 cell_mask; + PaddedMutex mutexes[STRING_INTERNER_MUTEX_STRIPE_COUNT]; + StaticArena arena; + PaddedMutex arena_mutex; + bool track_count; + PaddedI64 count; +}; + +gb_internal StringInterner *string_interner_create(); +gb_internal InternedString string_interner_insert(String str, u32 hash=0, u32 *new_hash_=nullptr); +gb_internal String string_interner_load(InternedString interned); + +gb_global StringInterner *g_string_interner; +gb_global InternedString g_interned_blank_ident; + +struct StringInternerThreadLocalArena { + u8 *data; + u64 cursor; +}; +gb_thread_local gb_global StringInternerThreadLocalArena g_interner_arena; + +gb_internal void string_interner_thread_local_arena_init(StringInternerThreadLocalArena *tl_arena); +gb_internal void *string_interner_thread_local_arena_alloc(StringInternerThreadLocalArena *tl_arena, isize size, isize alignment); + +gb_internal void init_string_interner() { + StaticArena arena = {}; + static_arena_init(&arena, 1<<30, STATIC_ARENA_DEFAULT_COMMIT_BLOCK_SIZE); + + StringInterner *interner = cast(StringInterner *)static_arena_alloc(&arena, gb_size_of(StringInterner), STRING_INTERN_CACHE_LINE); + interner->arena = arena; + u64 cell_size = 1llu << 17llu; + u64 cell_mask = cell_size - 1; + interner->cell_mask = cell_mask; + interner->cells = cast(StringInternCell *)static_arena_alloc(&interner->arena, cell_size * gb_size_of(StringInternCell), STRING_INTERN_CACHE_LINE); + interner->track_count = false; + + g_string_interner = interner; + + g_interned_blank_ident = string_interner_insert(str_lit("_")); +} + +gb_internal String string_interner_load(InternedString interned) { + StringInterner* interner = g_string_interner; + if (interned.value == 0) { + return {}; + } + u8 *base = cast(u8 *)interner + interned.value; + u32 str_len = *cast(u32 *)base; + u8 *text = base + 4; + String str = { text, str_len }; + return str; +} + +gb_internal char const *string_interner_load_cstring(InternedString interned) { + StringInterner* interner = g_string_interner; + if (interned.value == 0) { + return ""; + } + u8 *base = cast(u8 *)interner + interned.value; + // u32 str_len = *cast(u32 *)base; + u8 *text = base + 4; + return cast(char const *)text; +} + +String InternedString::string() const { + return string_interner_load(*this); +} +char const *InternedString::cstring() const { + return string_interner_load_cstring(*this); +} +u32 InternedString::hash() const { + String s = string_interner_load(*this); + return string_hash(s); +} +bool InternedString::is_blank() const { + return this->value == g_interned_blank_ident.value; +} + +gb_internal InternedString string_interner_insert(String str, u32 hash, u32 *new_hash_) { + StringInterner* interner = g_string_interner; + if (str.len == 0) { + if (new_hash_) *new_hash_ = string_hash(String{}); + return {}; + } + + if (hash == 0) { + hash = string_hash(str); + } + if (new_hash_) *new_hash_ = hash; + + u64 cell_idx = hash & interner->cell_mask; + StringInternCell *cell = &interner->cells[cell_idx]; + while (true) { + StringInternCell *next = cell->next.load(std::memory_order_acquire); + + for (i32 i = 0; i < STRING_INTERNER_CELL_WIDTH; i += 1) { + if (cell->hashes[i].load(std::memory_order_acquire) == hash) { + String to_compare = string_interner_load(cell->offsets[i]); + if (to_compare == str) { + return cell->offsets[i]; + } + } + } + if (next == nullptr) { + break; + } + cell = next; + } + + u64 mutex_cell = cell_idx & STRING_INTERNER_MUTEX_STRIPE_MASK; + PaddedMutex* m = &interner->mutexes[mutex_cell]; + MUTEX_GUARD(&m->m); + + StringInternCell *load_cell = nullptr; + while (cell) { + for (i32 i = 0; i < STRING_INTERNER_CELL_WIDTH; i += 1) { + if (cell->hashes[i].load(std::memory_order_relaxed) == hash) { + // string check + String to_compare = string_interner_load(cell->offsets[i]); + if (to_compare == str) { + return cell->offsets[i]; + } + } + } + load_cell = cell; + cell = cell->next.load(std::memory_order_relaxed); + } + + u64 data_to_allocate = 4 + str.len + 1; + u8 *data = cast(u8 *)string_interner_thread_local_arena_alloc(&g_interner_arena, data_to_allocate, 8); + u32 str_len = cast(u32)str.len; + gb_memcopy(data, &str_len, 4); + gb_memcopy(&data[4], str.text, str_len); + data[4+str_len] = 0; + InternedString offset = { cast(u32)(cast(u8 *)data - cast(u8 *)interner) }; + + for (i32 i = 0; i < STRING_INTERNER_CELL_WIDTH; i += 1) { + if (load_cell->hashes[i].load(std::memory_order_relaxed) == 0) { + load_cell->offsets[i] = offset; + load_cell->hashes[i].store(hash, std::memory_order_release); + if (interner->track_count) { + interner->count.value.fetch_add(1, std::memory_order_relaxed); + } + return offset; + } + } + + StringInternCell *new_cell = cast(StringInternCell *)string_interner_thread_local_arena_alloc(&g_interner_arena, gb_size_of(StringInternCell), STRING_INTERN_CACHE_LINE); + new_cell->offsets[0] = offset; + new_cell->hashes[0].store(hash, std::memory_order_relaxed); + load_cell->next.store(new_cell, std::memory_order_release); + + if (interner->track_count) { + interner->count.value.fetch_add(1, std::memory_order_relaxed); + } + + return offset; +} + +gb_internal char const *string_intern_cstring(String str, u32 *hash_=nullptr) { + InternedString i = string_interner_insert(str, 0, hash_); + return string_interner_load_cstring(i); +} + + +gb_internal String string_intern_string(String str, u32 *hash_=nullptr) { + InternedString i = string_interner_insert(str, 0, hash_); + return string_interner_load(i); +} + + + + +gb_internal void string_interner_thread_local_arena_init(StringInternerThreadLocalArena *tl_arena) { + *tl_arena = { + nullptr, + STRING_INTERNER_THREAD_LOCAL_SIZE, + }; +} + +gb_internal void *string_interner_thread_local_arena_alloc(StringInternerThreadLocalArena *tl_arena, isize size, isize alignment) { + if (tl_arena->data == nullptr) { + tl_arena->cursor = STRING_INTERNER_THREAD_LOCAL_SIZE; + } + isize new_head = align_formula_isize(tl_arena->cursor, alignment); + isize cursor = new_head + size; + if (cursor > STRING_INTERNER_THREAD_LOCAL_SIZE) { + mutex_lock(&g_string_interner->arena_mutex.m); + tl_arena->data = cast(u8 *)static_arena_alloc(&g_string_interner->arena, STRING_INTERNER_THREAD_LOCAL_SIZE, 4096); + tl_arena->cursor = 0; + mutex_unlock(&g_string_interner->arena_mutex.m); + return string_interner_thread_local_arena_alloc(tl_arena, size, alignment); + } + u8 *return_head = tl_arena->data + new_head; + tl_arena->cursor = cursor; + return return_head; +} \ No newline at end of file diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index ca6483fd9..a0afbd269 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -1,5 +1,15 @@ // thread_pool.cpp +// TODO(bill): make work on MSVC +// #if defined(__SANITIZE_THREAD__) || (defined(__has_feature) && __has_feature(thread_sanitizer)) +// #include +// #define TSAN_RELEASE(addr) __tsan_release(addr) +// #define TSAN_ACQUIRE(addr) __tsan_acquire(addr) +// #else +#define TSAN_RELEASE(addr) +#define TSAN_ACQUIRE(addr) +// #endif + struct WorkerTask; struct ThreadPool; @@ -88,6 +98,7 @@ void thread_pool_queue_push(Thread *thread, WorkerTask task) { } cur_ring->buffer[bot % cur_ring->size] = task; + TSAN_RELEASE(cur_ring->buffer[bot % cur_ring->size]); std::atomic_thread_fence(std::memory_order_release); thread->queue.bottom.store(bot + 1, std::memory_order_relaxed); @@ -108,6 +119,7 @@ GrabState thread_pool_queue_take(Thread *thread, WorkerTask *task) { if (top <= bot) { // Queue is not empty + TSAN_ACQUIRE(cur_ring->buffer[bot % cur_ring->size]); *task = cur_ring->buffer[bot % cur_ring->size]; if (top == bot) { // Only one entry left in queue @@ -139,6 +151,8 @@ GrabState thread_pool_queue_steal(Thread *thread, WorkerTask *task) { if (top < bot) { // Queue is not empty TaskRingBuffer *cur_ring = thread->queue.ring.load(std::memory_order_consume); + + TSAN_ACQUIRE(&cur_ring->buffer[top % cur_ring->size]); *task = cur_ring->buffer[top % cur_ring->size]; if (!thread->queue.top.compare_exchange_strong(top, top + 1, std::memory_order_seq_cst, std::memory_order_relaxed)) { diff --git a/src/threading.cpp b/src/threading.cpp index 02e6de14b..5dff13d2e 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -375,8 +375,8 @@ gb_internal void semaphore_wait(Semaphore *s) { } gb_internal bool mutex_try_lock(BlockingMutex *m) { ANNOTATE_LOCK_PRE(m, 1); - i32 v = m->state().exchange(Internal_Mutex_State_Locked, std::memory_order_acquire); - if (v == Internal_Mutex_State_Unlocked) { + i32 expected = Internal_Mutex_State_Unlocked; + if (m->state().compare_exchange_strong(expected, Internal_Mutex_State_Locked, std::memory_order_acquire)) { ANNOTATE_LOCK_POST(m); return true; } @@ -1201,3 +1201,41 @@ void futex_wait(Futex *f, Footex val) { #if defined(GB_SYSTEM_WINDOWS) #pragma warning(pop) #endif + + + +template +struct AtomicFreelist { + T value; + std::atomic *> next; +}; + +template +AtomicFreelist *atomic_freelist_get(std::atomic *> &head) { + AtomicFreelist *elem = nullptr; + + for (;;) { + elem = head.load(std::memory_order_acquire); + if (elem == nullptr) { + return nullptr; + } + + if (head.compare_exchange_weak(elem, elem->next.load(std::memory_order_acquire), std::memory_order_acquire, std::memory_order_relaxed)) { + elem->next.store(nullptr, std::memory_order_relaxed); + return elem; + } + + } +} + +template +void atomic_freelist_put(std::atomic *> &head_list, AtomicFreelist *elem) { + for (;;) { + auto *head = head_list.load(std::memory_order_relaxed); + elem->next.store(head, std::memory_order_relaxed); + if (head_list.compare_exchange_weak(head, elem, std::memory_order_release, std::memory_order_relaxed)) { + return; + } + + } +} \ No newline at end of file diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index ffa53abb5..2bdd15a60 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -379,6 +379,7 @@ gb_internal void advance_to_next_rune(Tokenizer *t) { gb_internal void init_tokenizer_with_data(Tokenizer *t, String const &fullpath, void const *data, isize size) { t->fullpath = fullpath; + t->column_minus_one = -1; t->line_count = 1; t->start = cast(u8 *)data; @@ -1114,6 +1115,7 @@ semicolon_check:; /*fallthrough*/ case Token_Increment: case Token_Decrement: + case Token_Not: /*fallthrough*/ t->insert_semicolon = true; break; diff --git a/src/types.cpp b/src/types.cpp index eb20b8edf..f4b708e57 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -163,27 +163,28 @@ struct TypeStruct { bool is_packed : 1; bool is_raw_union : 1; bool is_all_or_none : 1; + bool is_simple : 1; bool is_poly_specialized : 1; std::atomic are_offsets_being_processed; }; struct TypeUnion { - Slice variants; + Slice variants; - Ast * node; - Scope * scope; + Ast * node; + Scope * scope; - i64 variant_block_size; - i64 custom_align; - Type * polymorphic_params; // Type_Tuple - Type * polymorphic_parent; - Wait_Signal polymorphic_wait_signal; + std::atomic variant_block_size; + i64 custom_align; + Type * polymorphic_params; // Type_Tuple + Type * polymorphic_parent; + Wait_Signal polymorphic_wait_signal; - i16 tag_size; - bool is_polymorphic; - bool is_poly_specialized; - UnionTypeKind kind; + std::atomic tag_size; + bool is_polymorphic; + bool is_poly_specialized; + UnionTypeKind kind; }; struct TypeProc { @@ -225,6 +226,7 @@ struct TypeNamed { TYPE_KIND(Generic, struct { \ i64 id; \ String name; \ + InternedString interned_name; \ Type * specialized; \ Scope * scope; \ Entity *entity; \ @@ -247,6 +249,12 @@ struct TypeNamed { }) \ TYPE_KIND(Slice, struct { Type *elem; }) \ TYPE_KIND(DynamicArray, struct { Type *elem; }) \ + TYPE_KIND(FixedCapacityDynamicArray, struct { \ + i64 capacity; \ + Type *generic_capacity; \ + Type *elem; \ + i64 padding_needed; /*-1 if unknown*/ \ + }) \ TYPE_KIND(Map, struct { \ Type *key; \ Type *value; \ @@ -377,6 +385,7 @@ enum Typeid_Kind : u8 { Typeid_Matrix, Typeid_SoaPointer, Typeid_Bit_Field, + Typeid_Fixed_Capacity_Dynamic_Array, Typeid__COUNT @@ -697,6 +706,7 @@ gb_global Type *t_type_info_simd_vector = nullptr; gb_global Type *t_type_info_matrix = nullptr; gb_global Type *t_type_info_soa_pointer = nullptr; gb_global Type *t_type_info_bit_field = nullptr; +gb_global Type *t_type_info_fixed_capacity_dynamic_array = nullptr; gb_global Type *t_type_info_named_ptr = nullptr; gb_global Type *t_type_info_integer_ptr = nullptr; @@ -725,6 +735,7 @@ gb_global Type *t_type_info_simd_vector_ptr = nullptr; gb_global Type *t_type_info_matrix_ptr = nullptr; gb_global Type *t_type_info_soa_pointer_ptr = nullptr; gb_global Type *t_type_info_bit_field_ptr = nullptr; +gb_global Type *t_type_info_fixed_capacity_dynamic_array_ptr = nullptr; gb_global Type *t_allocator = nullptr; gb_global Type *t_allocator_ptr = nullptr; @@ -968,10 +979,7 @@ gb_internal void set_base_type(Type *t, Type *base) { gb_internal Type *alloc_type(TypeKind kind) { - // gbAllocator a = heap_allocator(); - gbAllocator a = permanent_allocator(); - Type *t = gb_alloc_item(a, Type); - gb_zero_item(t); + Type *t = permanent_alloc_item(); t->kind = kind; t->cached_size = -1; t->cached_align = -1; @@ -979,10 +987,11 @@ gb_internal Type *alloc_type(TypeKind kind) { } -gb_internal Type *alloc_type_generic(Scope *scope, i64 id, String name, Type *specialized) { +gb_internal Type *alloc_type_generic(Scope *scope, i64 id, InternedString interned_name, Type *specialized) { Type *t = alloc_type(Type_Generic); t->Generic.id = id; - t->Generic.name = name; + t->Generic.name = interned_name.string(); + t->Generic.interned_name = interned_name; t->Generic.specialized = specialized; t->Generic.scope = scope; return t; @@ -1066,8 +1075,8 @@ gb_internal Type *alloc_type_enumerated_array(Type *elem, Type *index, ExactValu Type *t = alloc_type(Type_EnumeratedArray); t->EnumeratedArray.elem = elem; t->EnumeratedArray.index = index; - t->EnumeratedArray.min_value = gb_alloc_item(permanent_allocator(), ExactValue); - t->EnumeratedArray.max_value = gb_alloc_item(permanent_allocator(), ExactValue); + t->EnumeratedArray.min_value = permanent_alloc_item(); + t->EnumeratedArray.max_value = permanent_alloc_item(); gb_memmove(t->EnumeratedArray.min_value, min_value, gb_size_of(ExactValue)); gb_memmove(t->EnumeratedArray.max_value, max_value, gb_size_of(ExactValue)); t->EnumeratedArray.op = op; @@ -1093,6 +1102,23 @@ gb_internal Type *alloc_type_dynamic_array(Type *elem) { return t; } +gb_internal Type *alloc_type_fixed_capacity_dynamic_array(Type *elem, i64 capacity, Type *generic_capacity = nullptr) { + if (generic_capacity != nullptr) { + Type *t = alloc_type(Type_FixedCapacityDynamicArray); + t->FixedCapacityDynamicArray.elem = elem; + t->FixedCapacityDynamicArray.capacity = capacity; + t->FixedCapacityDynamicArray.generic_capacity = generic_capacity; + t->FixedCapacityDynamicArray.padding_needed = -1; + return t; + } + Type *t = alloc_type(Type_FixedCapacityDynamicArray); + t->FixedCapacityDynamicArray.elem = elem; + t->FixedCapacityDynamicArray.capacity = capacity; + t->FixedCapacityDynamicArray.padding_needed = -1; + return t; +} + + gb_internal Type *alloc_type_struct() { Type *t = alloc_type(Type_Struct); @@ -1114,8 +1140,8 @@ gb_internal Type *alloc_type_union() { gb_internal Type *alloc_type_enum() { Type *t = alloc_type(Type_Enum); - t->Enum.min_value = gb_alloc_item(permanent_allocator(), ExactValue); - t->Enum.max_value = gb_alloc_item(permanent_allocator(), ExactValue); + t->Enum.min_value = permanent_alloc_item(); + t->Enum.max_value = permanent_alloc_item(); return t; } @@ -1657,6 +1683,11 @@ gb_internal bool is_type_dynamic_array(Type *t) { if (t == nullptr) { return false; } return t->kind == Type_DynamicArray; } +gb_internal bool is_type_fixed_capacity_dynamic_array(Type *t) { + t = base_type(t); + if (t == nullptr) { return false; } + return t->kind == Type_FixedCapacityDynamicArray; +} gb_internal bool is_type_slice(Type *t) { t = base_type(t); if (t == nullptr) { return false; } @@ -1686,6 +1717,8 @@ gb_internal Type *base_array_type(Type *t) { return bt->EnumeratedArray.elem; } else if (is_type_simd_vector(bt)) { return bt->SimdVector.elem; + } else if (is_type_fixed_capacity_dynamic_array(bt)) { + return bt->FixedCapacityDynamicArray.elem; } else if (is_type_matrix(bt)) { return bt->Matrix.elem; } @@ -1701,6 +1734,8 @@ gb_internal Type *base_any_array_type(Type *t) { return bt->Slice.elem; } else if (is_type_dynamic_array(bt)) { return bt->DynamicArray.elem; + } else if (is_type_fixed_capacity_dynamic_array(bt)) { + return bt->FixedCapacityDynamicArray.elem; } else if (is_type_enumerated_array(bt)) { return bt->EnumeratedArray.elem; } else if (is_type_simd_vector(bt)) { @@ -2233,6 +2268,7 @@ gb_internal bool is_type_indexable(Type *t) { case Type_Array: case Type_Slice: case Type_DynamicArray: + case Type_FixedCapacityDynamicArray: case Type_Map: return true; case Type_MultiPointer: @@ -2253,6 +2289,7 @@ gb_internal bool is_type_sliceable(Type *t) { case Type_Array: case Type_Slice: case Type_DynamicArray: + case Type_FixedCapacityDynamicArray: return true; case Type_EnumeratedArray: return false; @@ -2393,6 +2430,11 @@ gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) { return is_type_polymorphic(t->SimdVector.elem, or_specialized); case Type_DynamicArray: return is_type_polymorphic(t->DynamicArray.elem, or_specialized); + case Type_FixedCapacityDynamicArray: + if (t->FixedCapacityDynamicArray.generic_capacity != nullptr) { + return true; + } + return is_type_polymorphic(t->FixedCapacityDynamicArray.elem, or_specialized); case Type_Slice: return is_type_polymorphic(t->Slice.elem, or_specialized); @@ -2514,6 +2556,11 @@ gb_internal bool type_has_nil(Type *t) { case Type_DynamicArray: case Type_Map: return true; + + case Type_FixedCapacityDynamicArray: + // it's like a normal array, so no, similar to `#soa[N]T + return false; + case Type_Union: return t->Union.kind != UnionType_no_nil; case Type_Struct: @@ -2641,6 +2688,9 @@ gb_internal bool is_type_comparable(Type *t) { case Type_Matrix: return is_type_comparable(t->Matrix.elem); + case Type_FixedCapacityDynamicArray: + return false; + case Type_BitSet: return true; @@ -2687,6 +2737,10 @@ gb_internal bool is_type_simple_compare(Type *t) { case Type_EnumeratedArray: return is_type_simple_compare(t->EnumeratedArray.elem); + case Type_FixedCapacityDynamicArray: + return false; + // return is_type_simple_compare(t->FixedCapacityDynamicArray.elem); + case Type_Basic: if (t->Basic.flags & BasicFlag_SimpleCompare) { return true; @@ -2701,12 +2755,16 @@ gb_internal bool is_type_simple_compare(Type *t) { case Type_SoaPointer: case Type_Proc: case Type_BitSet: + case Type_BitField: return true; case Type_Matrix: return is_type_simple_compare(t->Matrix.elem); case Type_Struct: + if (t->Struct.is_simple) { + return true; + } for_array(i, t->Struct.fields) { Entity *f = t->Struct.fields[i]; if (!is_type_simple_compare(f->type)) { @@ -2728,6 +2786,16 @@ gb_internal bool is_type_simple_compare(Type *t) { case Type_SimdVector: return is_type_simple_compare(t->SimdVector.elem); + case Type_Tuple: + if (t->Tuple.variables.count == 1) { + return is_type_simple_compare(t->Tuple.variables[0]->type); + } + break; + + case Type_Slice: + case Type_DynamicArray: + case Type_Map: + return false; } return false; @@ -2743,6 +2811,10 @@ gb_internal bool is_type_nearly_simple_compare(Type *t) { case Type_EnumeratedArray: return is_type_nearly_simple_compare(t->EnumeratedArray.elem); + case Type_FixedCapacityDynamicArray: + return false; + // return is_type_nearly_simple_compare(t->FixedCapacityDynamicArray.elem); + case Type_Basic: if (t->Basic.flags & (BasicFlag_SimpleCompare|BasicFlag_Numeric)) { return true; @@ -2757,12 +2829,16 @@ gb_internal bool is_type_nearly_simple_compare(Type *t) { case Type_SoaPointer: case Type_Proc: case Type_BitSet: + case Type_BitField: return true; case Type_Matrix: return is_type_nearly_simple_compare(t->Matrix.elem); case Type_Struct: + if (t->Struct.is_simple) { + return true; + } for_array(i, t->Struct.fields) { Entity *f = t->Struct.fields[i]; if (!is_type_nearly_simple_compare(f->type)) { @@ -2784,6 +2860,17 @@ gb_internal bool is_type_nearly_simple_compare(Type *t) { case Type_SimdVector: return is_type_nearly_simple_compare(t->SimdVector.elem); + case Type_Tuple: + if (t->Tuple.variables.count == 1) { + return is_type_nearly_simple_compare(t->Tuple.variables[0]->type); + } + break; + + case Type_Slice: + case Type_DynamicArray: + case Type_Map: + return false; + } return false; @@ -2808,6 +2895,7 @@ gb_internal bool is_type_load_safe(Type *type) { case Type_DynamicArray: case Type_Proc: case Type_SoaPointer: + case Type_FixedCapacityDynamicArray: return false; case Type_Enum: @@ -2962,6 +3050,10 @@ gb_internal bool are_types_identical_unique_tuples(Type *x, Type *y) { return false; } + // if (x->canonical_hash && y->canonical_hash && x->canonical_hash != y->canonical_hash) { + // return false; + // } + // MUTEX_GUARD(&g_type_mutex); return are_types_identical_internal(x, y, true); } @@ -2976,6 +3068,10 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple return false; } + // if (x->canonical_hash && y->canonical_hash && x->canonical_hash != y->canonical_hash) { + // return false; + // } + #if 0 if (x->kind == Type_Named) { Entity *e = x->Named.type_name; @@ -3017,6 +3113,10 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple case Type_DynamicArray: return are_types_identical(x->DynamicArray.elem, y->DynamicArray.elem); + case Type_FixedCapacityDynamicArray: + return (x->FixedCapacityDynamicArray.capacity == y->FixedCapacityDynamicArray.capacity) && + are_types_identical(x->FixedCapacityDynamicArray.elem, y->FixedCapacityDynamicArray.elem); + case Type_Slice: return are_types_identical(x->Slice.elem, y->Slice.elem); @@ -3282,7 +3382,7 @@ gb_internal bool union_variant_index_types_equal(Type *v, Type *vt) { return false; } -gb_internal i64 union_variant_index(Type *u, Type *v) { +gb_internal i64 union_variant_index_checked(Type *u, Type *v) { u = base_type(u); GB_ASSERT(u->kind == Type_Union); @@ -3296,9 +3396,24 @@ gb_internal i64 union_variant_index(Type *u, Type *v) { } } } - return 0; + GB_PANIC("unfound variant -> %s %s", type_to_string(u), type_to_string(v)); + return -1; } +gb_internal bool union_is_variant_of(Type *u, Type *v) { + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + for_array(i, u->Union.variants) { + Type *vt = u->Union.variants[i]; + if (union_variant_index_types_equal(v, vt)) { + return true; + } + } + return false; +} + + gb_internal i64 union_tag_size(Type *u) { u = base_type(u); GB_ASSERT(u->kind == Type_Union); @@ -3456,9 +3571,9 @@ gb_internal ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) -gb_internal Selection lookup_field_with_selection(Type *type_, String field_name, bool is_type, Selection sel, bool allow_blank_ident=false); +gb_internal Selection lookup_field_with_selection(Type *type_, InternedString field_name, bool is_type, Selection sel, bool allow_blank_ident=false); -gb_internal Selection lookup_field(Type *type_, String field_name, bool is_type, bool allow_blank_ident=false) { +gb_internal Selection lookup_field(Type *type_, InternedString field_name, bool is_type, bool allow_blank_ident=false) { return lookup_field_with_selection(type_, field_name, is_type, empty_selection, allow_blank_ident); } @@ -3511,13 +3626,13 @@ gb_internal Selection lookup_field_from_index(Type *type, i64 index) { return empty_selection; } -gb_internal Entity *scope_lookup_current(Scope *s, String const &name); +gb_internal Entity *scope_lookup_current(Scope *s, InternedString name, u32 hash=0); gb_internal bool has_type_got_objc_class_attribute(Type *t); -gb_internal Selection lookup_field_with_selection(Type *type_, String field_name, bool is_type, Selection sel, bool allow_blank_ident) { +gb_internal Selection lookup_field_with_selection(Type *type_, InternedString field_name, bool is_type, Selection sel, bool allow_blank_ident) { GB_ASSERT(type_ != nullptr); - if (!allow_blank_ident && is_blank_ident(field_name)) { + if (!allow_blank_ident && field_name.is_blank()) { return empty_selection; } @@ -3539,7 +3654,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name defer (mutex_unlock(md->mutex)); for (TypeNameObjCMetadataEntry const &entry : md->type_entries) { GB_ASSERT(entry.entity->kind == Entity_Procedure || entry.entity->kind == Entity_ProcGroup); - if (entry.name == field_name) { + if (entry.interned == field_name) { sel.entity = entry.entity; sel.pseudo_field = true; return sel; @@ -3566,7 +3681,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name for_array(i, type->Enum.fields) { Entity *f = type->Enum.fields[i]; GB_ASSERT(f->kind == Entity_Constant); - String str = f->token.string; + auto str = entity_interned_name(f); if (field_name == str) { sel.entity = f; @@ -3617,7 +3732,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name defer (mutex_unlock(md->mutex)); for (TypeNameObjCMetadataEntry const &entry : md->value_entries) { GB_ASSERT(entry.entity->kind == Entity_Procedure || entry.entity->kind == Entity_ProcGroup); - if (entry.name == field_name) { + if (entry.interned == field_name) { sel.entity = entry.entity; sel.pseudo_field = true; return sel; @@ -3646,7 +3761,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) { continue; } - String str = f->token.string; + auto str = entity_interned_name(f); if (field_name == str) { selection_add_index(&sel, i); // HACK(bill): Leaky memory sel.entity = f; @@ -3675,11 +3790,12 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name bool is_soa_of_array = is_soa && is_type_array(type->Struct.soa_elem); if (is_soa_of_array) { - String mapped_field_name = {}; - if (field_name == "r") mapped_field_name = str_lit("x"); - else if (field_name == "g") mapped_field_name = str_lit("y"); - else if (field_name == "b") mapped_field_name = str_lit("z"); - else if (field_name == "a") mapped_field_name = str_lit("w"); + InternedString mapped_field_name = {}; + String n = field_name.string(); + if (n == "r") mapped_field_name = string_interner_insert(str_lit("x")); + else if (n == "g") mapped_field_name = string_interner_insert(str_lit("y")); + else if (n == "b") mapped_field_name = string_interner_insert(str_lit("z")); + else if (n == "a") mapped_field_name = string_interner_insert(str_lit("w")); return lookup_field_with_selection(type, mapped_field_name, is_type, sel, allow_blank_ident); } } else if (type->kind == Type_BitField) { @@ -3688,7 +3804,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) { continue; } - String str = f->token.string; + auto str = entity_interned_name(f); if (field_name == str) { selection_add_index(&sel, i); // HACK(bill): Leaky memory sel.entity = f; @@ -3706,11 +3822,12 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name gb_local_persist Entity *entity__any_data = alloc_entity_field(nullptr, make_token_ident(data_str), t_rawptr, false, 0); gb_local_persist Entity *entity__any_id = alloc_entity_field(nullptr, make_token_ident(id_str), t_typeid, false, 1); - if (field_name == data_str) { + String n = field_name.string(); + if (n == data_str) { selection_add_index(&sel, 0); sel.entity = entity__any_data; return sel; - } else if (field_name == id_str) { + } else if (n == id_str) { selection_add_index(&sel, 1); sel.entity = entity__any_id; return sel; @@ -3728,19 +3845,21 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name gb_local_persist Entity *entity__x = alloc_entity_field(nullptr, make_token_ident(x), t_f16, false, 0); gb_local_persist Entity *entity__y = alloc_entity_field(nullptr, make_token_ident(y), t_f16, false, 1); gb_local_persist Entity *entity__z = alloc_entity_field(nullptr, make_token_ident(z), t_f16, false, 2); - if (field_name == w) { + + String n = field_name.string(); + if (n == w) { selection_add_index(&sel, 3); sel.entity = entity__w; return sel; - } else if (field_name == x) { + } else if (n == x) { selection_add_index(&sel, 0); sel.entity = entity__x; return sel; - } else if (field_name == y) { + } else if (n == y) { selection_add_index(&sel, 1); sel.entity = entity__y; return sel; - } else if (field_name == z) { + } else if (n == z) { selection_add_index(&sel, 2); sel.entity = entity__z; return sel; @@ -3757,19 +3876,21 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name gb_local_persist Entity *entity__x = alloc_entity_field(nullptr, make_token_ident(x), t_f32, false, 0); gb_local_persist Entity *entity__y = alloc_entity_field(nullptr, make_token_ident(y), t_f32, false, 1); gb_local_persist Entity *entity__z = alloc_entity_field(nullptr, make_token_ident(z), t_f32, false, 2); - if (field_name == w) { + + String n = field_name.string(); + if (n == w) { selection_add_index(&sel, 3); sel.entity = entity__w; return sel; - } else if (field_name == x) { + } else if (n == x) { selection_add_index(&sel, 0); sel.entity = entity__x; return sel; - } else if (field_name == y) { + } else if (n == y) { selection_add_index(&sel, 1); sel.entity = entity__y; return sel; - } else if (field_name == z) { + } else if (n == z) { selection_add_index(&sel, 2); sel.entity = entity__z; return sel; @@ -3786,19 +3907,21 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name gb_local_persist Entity *entity__x = alloc_entity_field(nullptr, make_token_ident(x), t_f64, false, 0); gb_local_persist Entity *entity__y = alloc_entity_field(nullptr, make_token_ident(y), t_f64, false, 1); gb_local_persist Entity *entity__z = alloc_entity_field(nullptr, make_token_ident(z), t_f64, false, 2); - if (field_name == w) { + + String n = field_name.string(); + if (n == w) { selection_add_index(&sel, 3); sel.entity = entity__w; return sel; - } else if (field_name == x) { + } else if (n == x) { selection_add_index(&sel, 0); sel.entity = entity__x; return sel; - } else if (field_name == y) { + } else if (n == y) { selection_add_index(&sel, 1); sel.entity = entity__y; return sel; - } else if (field_name == z) { + } else if (n == z) { selection_add_index(&sel, 2); sel.entity = entity__z; return sel; @@ -3815,19 +3938,21 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name gb_local_persist Entity *entity__x = alloc_entity_field(nullptr, make_token_ident(x), t_untyped_float, false, 0); gb_local_persist Entity *entity__y = alloc_entity_field(nullptr, make_token_ident(y), t_untyped_float, false, 1); gb_local_persist Entity *entity__z = alloc_entity_field(nullptr, make_token_ident(z), t_untyped_float, false, 2); - if (field_name == w) { + + String n = field_name.string(); + if (n == w) { selection_add_index(&sel, 3); sel.entity = entity__w; return sel; - } else if (field_name == x) { + } else if (n == x) { selection_add_index(&sel, 0); sel.entity = entity__x; return sel; - } else if (field_name == y) { + } else if (n == y) { selection_add_index(&sel, 1); sel.entity = entity__y; return sel; - } else if (field_name == z) { + } else if (n == z) { selection_add_index(&sel, 2); sel.entity = entity__z; return sel; @@ -3842,7 +3967,8 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name String allocator_str = str_lit("allocator"); gb_local_persist Entity *entity__allocator = alloc_entity_field(nullptr, make_token_ident(allocator_str), t_allocator, false, 3); - if (field_name == allocator_str) { + String n = field_name.string(); + if (n == allocator_str) { selection_add_index(&sel, 3); sel.entity = entity__allocator; return sel; @@ -3852,7 +3978,8 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name String allocator_str = str_lit("allocator"); gb_local_persist Entity *entity__allocator = alloc_entity_field(nullptr, make_token_ident(allocator_str), t_allocator, false, 2); - if (field_name == allocator_str) { + String n = field_name.string(); + if (n == allocator_str) { selection_add_index(&sel, 2); sel.entity = entity__allocator; return sel; @@ -3860,7 +3987,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name #define _ARRAY_FIELD_CASE_IF(_length, _name) \ - if (field_name == (_name)) { \ + if (n == (_name)) { \ selection_add_index(&sel, (_length)-1); \ sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), elem, (_length)-1); \ return sel; \ @@ -3873,7 +4000,7 @@ case (_length): \ } else if (type->kind == Type_Array) { - + String n = field_name.string(); Type *elem = type->Array.elem; if (type->Array.count <= 4) { @@ -3888,8 +4015,9 @@ case (_length): \ } } } else if (type->kind == Type_SimdVector) { - + String n = field_name.string(); Type *elem = type->SimdVector.elem; + if (type->SimdVector.count <= 4) { // HACK(bill): Memory leak switch (type->SimdVector.count) { @@ -4114,9 +4242,22 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) { } case Type_DynamicArray: - // data, count, capacity, allocator + // data, len, cap, allocator return build_context.int_size; + case Type_FixedCapacityDynamicArray: + // data, len + { + Type *elem = t->FixedCapacityDynamicArray.elem; + bool pop = type_path_push(path, elem); + if (path->failure) { + return FAILURE_ALIGNMENT; + } + i64 align = type_align_of_internal(elem, path); + if (pop) type_path_pop(path); + return gb_max(build_context.int_size, align); + } + case Type_Slice: return build_context.int_size; @@ -4171,8 +4312,9 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) { if (t->Struct.is_packed) { return 1; } - - type_set_offsets(t); + // Avoid forcing offset computation here. The caller's type-path state must + // be able to detect recursive field cycles before any nested struct tries to + // re-enter this struct's offset mutex. i64 max = 1; for_array(i, t->Struct.fields) { @@ -4278,14 +4420,17 @@ gb_internal i64 *type_set_offsets_of(Slice const &fields, bool is_pack gb_internal bool type_set_offsets(Type *t) { t = base_type(t); if (t->kind == Type_Struct) { + // if (t->Struct.are_offsets_being_processed.load()) { + // return true; + // } MUTEX_GUARD(&t->Struct.offset_mutex); if (!t->Struct.are_offsets_set) { t->Struct.are_offsets_being_processed.store(true); t->Struct.offsets = type_set_offsets_of(t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union, t->Struct.custom_min_field_align, t->Struct.custom_max_field_align); t->Struct.are_offsets_being_processed.store(false); t->Struct.are_offsets_set = true; - return true; } + return true; } else if (is_type_tuple(t)) { MUTEX_GUARD(&t->Tuple.mutex); if (!t->Tuple.are_offsets_set) { @@ -4293,8 +4438,8 @@ gb_internal bool type_set_offsets(Type *t) { t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false, 1, 0); t->Tuple.are_offsets_being_processed.store(false); t->Tuple.are_offsets_set = true; - return true; } + return true; } else { GB_PANIC("Invalid type for setting offsets"); } @@ -4385,6 +4530,31 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { // data + len + cap + allocator(procedure+data) return 3*build_context.int_size + 2*build_context.ptr_size; + case Type_FixedCapacityDynamicArray: + { + // data + len + i64 capacity = t->FixedCapacityDynamicArray.capacity; + Type *elem = t->FixedCapacityDynamicArray.elem; + i64 align = type_align_of_internal(elem, path); + if (path->failure) { + return FAILURE_SIZE; + } + align = gb_max(build_context.int_size, align); + + i64 size = type_size_of(elem); + size *= capacity; + + i64 old_size = size; + size = align_formula(size, build_context.int_size); + + i64 padding = size - old_size; + t->FixedCapacityDynamicArray.padding_needed = padding; + + size += 1*build_context.int_size; + size = align_formula(size, align); + return size; + } + case Type_Map: /* struct { @@ -4610,6 +4780,24 @@ gb_internal i64 type_offset_of(Type *t, i64 index, Type **field_type_) { return 3*build_context.int_size; // allocator } break; + + case Type_FixedCapacityDynamicArray: + switch (index) { + case 0: + if (field_type_) *field_type_ = alloc_type_array(t->FixedCapacityDynamicArray.elem, t->FixedCapacityDynamicArray.capacity); + return 0; // data + + case 1: // len + if (field_type_) *field_type_ = t_int; + { + i64 elem_size = type_size_of(t->FixedCapacityDynamicArray.elem); + i64 offset = 0; + offset = elem_size * t->FixedCapacityDynamicArray.capacity; + offset = align_formula(offset, build_context.int_size); + return offset; + } + } + break; case Type_Union: if (!is_type_union_maybe_pointer(t)) { /* i64 s = */ type_size_of(t); @@ -4677,6 +4865,12 @@ gb_internal i64 type_offset_of_from_selection(Type *type, Selection sel) { case 3: t = t_allocator; break; } break; + case Type_FixedCapacityDynamicArray: + switch (index) { + case 0: t = alloc_type_array(t->FixedCapacityDynamicArray.elem, t->FixedCapacityDynamicArray.capacity); break; + case 1: t = t_int; break; + } + break; } } } @@ -4936,6 +5130,15 @@ gb_internal Type *type_internal_index(Type *t, isize index) { default: GB_PANIC("invalid raw dynamic array index"); }; } + + case Type_FixedCapacityDynamicArray: + { + switch (index) { + case 0: t = alloc_type_array(t->FixedCapacityDynamicArray.elem, t->FixedCapacityDynamicArray.capacity); break; + case 1: return t_int; + default: GB_PANIC("invalid raw fixed capacity dynamic array index"); + }; + } case Type_Struct: return get_struct_field_type(bt, index); case Type_Union: @@ -5034,6 +5237,13 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha str = write_type_to_string(str, type->DynamicArray.elem, shorthand, allow_polymorphic); break; + case Type_FixedCapacityDynamicArray: + str = gb_string_appendc(str, "[dynamic; "); + str = gb_string_appendc(str, gb_bprintf("%lld", cast(long long)type->FixedCapacityDynamicArray.capacity)); + str = gb_string_appendc(str, "]"); + str = write_type_to_string(str, type->FixedCapacityDynamicArray.elem, shorthand, allow_polymorphic); + break; + case Type_Enum: str = gb_string_appendc(str, "enum"); if (type->Enum.base_type != nullptr) { @@ -5096,9 +5306,11 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha str = gb_string_appendc(str, ")"); } - if (type->Struct.is_packed) str = gb_string_appendc(str, " #packed"); - if (type->Struct.is_raw_union) str = gb_string_appendc(str, " #raw_union"); + if (type->Struct.is_packed) str = gb_string_appendc(str, " #packed"); + if (type->Struct.is_raw_union) str = gb_string_appendc(str, " #raw_union"); if (type->Struct.custom_align != 0) str = gb_string_append_fmt(str, " #align %d", cast(int)type->Struct.custom_align); + if (type->Struct.is_all_or_none) str = gb_string_appendc(str, " #all_or_none"); + if (type->Struct.is_simple) str = gb_string_appendc(str, " #simple"); str = gb_string_appendc(str, " {"); @@ -5207,40 +5419,12 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha case Type_Proc: str = gb_string_appendc(str, "proc"); - switch (type->Proc.calling_convention) { - case ProcCC_Odin: - if (default_calling_convention() != ProcCC_Odin) { - str = gb_string_appendc(str, " \"odin\" "); - } - break; - case ProcCC_Contextless: - if (default_calling_convention() != ProcCC_Contextless) { - str = gb_string_appendc(str, " \"contextless\" "); - } - break; - case ProcCC_CDecl: - str = gb_string_appendc(str, " \"c\" "); - break; - case ProcCC_StdCall: - str = gb_string_appendc(str, " \"std\" "); - break; - case ProcCC_FastCall: - str = gb_string_appendc(str, " \"fastcall\" "); - break; - break; - case ProcCC_None: - str = gb_string_appendc(str, " \"none\" "); - break; - case ProcCC_Naked: - str = gb_string_appendc(str, " \"naked\" "); - break; - // case ProcCC_VectorCall: - // str = gb_string_appendc(str, " \"vectorcall\" "); - // break; - // case ProcCC_ClrCall: - // str = gb_string_appendc(str, " \"clrcall\" "); - // break; + if (type->Proc.calling_convention != default_calling_convention()) { + str = gb_string_appendc(str, " \""); + str = gb_string_appendc(str, proc_calling_convention_strings[type->Proc.calling_convention]); + str = gb_string_appendc(str, "\" "); } + str = gb_string_appendc(str, "("); if (type->Proc.params) { str = write_type_to_string(str, type->Proc.params, shorthand, allow_polymorphic); diff --git a/tests/benchmark/crypto/benchmark_ecc.odin b/tests/benchmark/crypto/benchmark_ecc.odin index 16ca798dc..c1809c6ba 100644 --- a/tests/benchmark/crypto/benchmark_ecc.odin +++ b/tests/benchmark/crypto/benchmark_ecc.odin @@ -2,18 +2,23 @@ package benchmark_core_crypto import "base:runtime" import "core:encoding/hex" +import "core:log" import "core:testing" import "core:text/table" import "core:time" +import "core:crypto" +import "core:crypto/ecdh" +import "core:crypto/ecdsa" import "core:crypto/ed25519" -import "core:crypto/x25519" -import "core:crypto/x448" +import "core:crypto/hash" @(private = "file") ECDH_ITERS :: 10000 @(private = "file") DSA_ITERS :: 10000 +@(private = "file") +MSG : string : "Got a job for you, 621." @(test) benchmark_crypto_ecc :: proc(t: ^testing.T) { @@ -23,8 +28,12 @@ benchmark_crypto_ecc :: proc(t: ^testing.T) { bench_dsa() } -@(private = "file") +@(private="file") bench_ecdh :: proc() { + if !crypto.HAS_RAND_BYTES { + log.warnf("ECDH benchmarks skipped, no system entropy source") + } + tbl: table.Table table.init(&tbl) defer table.destroy(&tbl) @@ -42,64 +51,38 @@ bench_ecdh :: proc() { ) } - scalar_bp, scalar := bench_x25519() - append_tbl(&tbl, "X25519", scalar_bp, scalar) + for algo in ecdh.Curve { + if algo == .Invalid { + continue + } + algo_name := ecdh.CURVE_NAMES[algo] - scalar_bp, scalar = bench_x448() - append_tbl(&tbl, "X448", scalar_bp, scalar) + priv_key_alice: ecdh.Private_Key + start := time.tick_now() + for _ in 0 ..< ECDH_ITERS { + _ = ecdh.private_key_generate(&priv_key_alice, algo) + } + bp := time.tick_since(start) / ECDH_ITERS + + pub_key_alice: ecdh.Public_Key + ecdh.public_key_set_priv(&pub_key_alice, &priv_key_alice) + + priv_key_bob: ecdh.Private_Key + _ = ecdh.private_key_generate(&priv_key_bob, algo) + ss := make([]byte, ecdh.SHARED_SECRET_SIZES[algo], context.temp_allocator) + start = time.tick_now() + for _ in 0 ..< ECDH_ITERS { + _ = ecdh.ecdh(&priv_key_bob, &pub_key_alice, ss) + } + sc := time.tick_since(start) / ECDH_ITERS + + append_tbl(&tbl, algo_name, bp, sc) + } log_table(&tbl) } -@(private = "file") -bench_x25519 :: proc() -> (bp, sc: time.Duration) { - point_str := "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" - scalar_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe" - - point, _ := hex.decode(transmute([]byte)(point_str), context.temp_allocator) - scalar, _ := hex.decode(transmute([]byte)(scalar_str), context.temp_allocator) - out: [x25519.POINT_SIZE]byte = --- - - start := time.tick_now() - for _ in 0 ..< ECDH_ITERS { - x25519.scalarmult_basepoint(out[:], scalar[:]) - } - bp = time.tick_since(start) / ECDH_ITERS - - start = time.tick_now() - for _ in 0 ..< ECDH_ITERS { - x25519.scalarmult(out[:], scalar[:], point[:]) - } - sc = time.tick_since(start) / ECDH_ITERS - - return -} - -@(private = "file") -bench_x448 :: proc() -> (bp, sc: time.Duration) { - point_str := "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" - scalar_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe" - - point, _ := hex.decode(transmute([]byte)(point_str), context.temp_allocator) - scalar, _ := hex.decode(transmute([]byte)(scalar_str), context.temp_allocator) - out: [x448.POINT_SIZE]byte = --- - - start := time.tick_now() - for _ in 0 ..< ECDH_ITERS { - x448.scalarmult_basepoint(out[:], scalar[:]) - } - bp = time.tick_since(start) / ECDH_ITERS - - start = time.tick_now() - for _ in 0 ..< ECDH_ITERS { - x448.scalarmult(out[:], scalar[:], point[:]) - } - sc = time.tick_since(start) / ECDH_ITERS - - return -} - -@(private = "file") +@(private="file") bench_dsa :: proc() { tbl: table.Table table.init(&tbl) @@ -123,6 +106,20 @@ bench_dsa :: proc() { append_tbl(&tbl, "ed25519", "sign", sig) append_tbl(&tbl, "ed25519", "verify", verif) + table.row(&tbl) + + sk, sig, verif = bench_ecdsa(.SECP256R1, .SHA256) + append_tbl(&tbl, "secp256r1/SHA256/RFC6979", "private_key_set_bytes", sk) + append_tbl(&tbl, "secp256r1/SHA256/RFC6979", "sign", sig) + append_tbl(&tbl, "secp256r1/SHA256/RFC6979", "verify", verif) + + table.row(&tbl) + + sk, sig, verif = bench_ecdsa(.SECP384R1, .SHA384) + append_tbl(&tbl, "secp384r1/SHA384/RFC6979", "private_key_set_bytes", sk) + append_tbl(&tbl, "secp384r1/SHA384/RFC6979", "sign", sig) + append_tbl(&tbl, "secp384r1/SHA384/RFC6979", "verify", verif) + log_table(&tbl) } @@ -143,9 +140,8 @@ bench_ed25519 :: proc() -> (sk, sig, verif: time.Duration) { ok := ed25519.public_key_set_bytes(&pub_key, pub_bytes[:]) assert(ok, "public key should deserialize") - msg := "Got a job for you, 621." sig_bytes: [ed25519.SIGNATURE_SIZE]byte - msg_bytes := transmute([]byte)(msg) + msg_bytes := transmute([]byte)(MSG) start = time.tick_now() for _ in 0 ..< DSA_ITERS { ed25519.sign(&priv_key, msg_bytes, sig_bytes[:]) @@ -161,3 +157,37 @@ bench_ed25519 :: proc() -> (sk, sig, verif: time.Duration) { return } + +@(private="file") +bench_ecdsa :: proc(curve: ecdsa.Curve, hash: hash.Algorithm) -> (sk, sig, verif: time.Duration) { + priv_bytes := make([]byte, ecdsa.PRIVATE_KEY_SIZES[curve], context.temp_allocator) + crypto.set(raw_data(priv_bytes), 0x69, len(priv_bytes)) + priv_key: ecdsa.Private_Key + start := time.tick_now() + for _ in 0 ..< DSA_ITERS { + ok := ecdsa.private_key_set_bytes(&priv_key, curve, priv_bytes) + assert(ok, "private key should deserialize") + } + sk = time.tick_since(start) / DSA_ITERS + + pub_key: ecdsa.Public_Key + ecdsa.public_key_set_priv(&pub_key, &priv_key) + + sig_bytes := make([]byte, ecdsa.RAW_SIGNATURE_SIZES[curve], context.temp_allocator) + msg_bytes := transmute([]byte)(MSG) + start = time.tick_now() + for _ in 0 ..< DSA_ITERS { + ok := ecdsa.sign_raw(&priv_key, hash, msg_bytes, sig_bytes, true) + assert(ok, "signing should succeed") + } + sig = time.tick_since(start) / DSA_ITERS + + start = time.tick_now() + for _ in 0 ..< DSA_ITERS { + ok := ecdsa.verify_raw(&pub_key, hash, msg_bytes, sig_bytes) + assert(ok, "signature should validate") + } + verif = time.tick_since(start) / DSA_ITERS + + return +} diff --git a/tests/core/assets/UCD/PropList.txt b/tests/core/assets/UCD/PropList.txt new file mode 100644 index 000000000..e64b4224d --- /dev/null +++ b/tests/core/assets/UCD/PropList.txt @@ -0,0 +1,1944 @@ +# PropList-17.0.0.txt +# Date: 2025-06-30, 06:19:01 GMT +# © 2025 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use and license, see https://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see https://www.unicode.org/reports/tr44/ + +# ================================================ + +0009..000D ; White_Space # Cc [5] .. +0020 ; White_Space # Zs SPACE +0085 ; White_Space # Cc +00A0 ; White_Space # Zs NO-BREAK SPACE +1680 ; White_Space # Zs OGHAM SPACE MARK +2000..200A ; White_Space # Zs [11] EN QUAD..HAIR SPACE +2028 ; White_Space # Zl LINE SEPARATOR +2029 ; White_Space # Zp PARAGRAPH SEPARATOR +202F ; White_Space # Zs NARROW NO-BREAK SPACE +205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE +3000 ; White_Space # Zs IDEOGRAPHIC SPACE + +# Total code points: 25 + +# ================================================ + +061C ; Bidi_Control # Cf ARABIC LETTER MARK +200E..200F ; Bidi_Control # Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK +202A..202E ; Bidi_Control # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE +2066..2069 ; Bidi_Control # Cf [4] LEFT-TO-RIGHT ISOLATE..POP DIRECTIONAL ISOLATE + +# Total code points: 12 + +# ================================================ + +200C..200D ; Join_Control # Cf [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER + +# Total code points: 2 + +# ================================================ + +002D ; Dash # Pd HYPHEN-MINUS +058A ; Dash # Pd ARMENIAN HYPHEN +05BE ; Dash # Pd HEBREW PUNCTUATION MAQAF +1400 ; Dash # Pd CANADIAN SYLLABICS HYPHEN +1806 ; Dash # Pd MONGOLIAN TODO SOFT HYPHEN +2010..2015 ; Dash # Pd [6] HYPHEN..HORIZONTAL BAR +2053 ; Dash # Po SWUNG DASH +207B ; Dash # Sm SUPERSCRIPT MINUS +208B ; Dash # Sm SUBSCRIPT MINUS +2212 ; Dash # Sm MINUS SIGN +2E17 ; Dash # Pd DOUBLE OBLIQUE HYPHEN +2E1A ; Dash # Pd HYPHEN WITH DIAERESIS +2E3A..2E3B ; Dash # Pd [2] TWO-EM DASH..THREE-EM DASH +2E40 ; Dash # Pd DOUBLE HYPHEN +2E5D ; Dash # Pd OBLIQUE HYPHEN +301C ; Dash # Pd WAVE DASH +3030 ; Dash # Pd WAVY DASH +30A0 ; Dash # Pd KATAKANA-HIRAGANA DOUBLE HYPHEN +FE31..FE32 ; Dash # Pd [2] PRESENTATION FORM FOR VERTICAL EM DASH..PRESENTATION FORM FOR VERTICAL EN DASH +FE58 ; Dash # Pd SMALL EM DASH +FE63 ; Dash # Pd SMALL HYPHEN-MINUS +FF0D ; Dash # Pd FULLWIDTH HYPHEN-MINUS +10D6E ; Dash # Pd GARAY HYPHEN +10EAD ; Dash # Pd YEZIDI HYPHENATION MARK + +# Total code points: 31 + +# ================================================ + +002D ; Hyphen # Pd HYPHEN-MINUS +00AD ; Hyphen # Cf SOFT HYPHEN +058A ; Hyphen # Pd ARMENIAN HYPHEN +1806 ; Hyphen # Pd MONGOLIAN TODO SOFT HYPHEN +2010..2011 ; Hyphen # Pd [2] HYPHEN..NON-BREAKING HYPHEN +2E17 ; Hyphen # Pd DOUBLE OBLIQUE HYPHEN +30FB ; Hyphen # Po KATAKANA MIDDLE DOT +FE63 ; Hyphen # Pd SMALL HYPHEN-MINUS +FF0D ; Hyphen # Pd FULLWIDTH HYPHEN-MINUS +FF65 ; Hyphen # Po HALFWIDTH KATAKANA MIDDLE DOT + +# Total code points: 11 + +# ================================================ + +0022 ; Quotation_Mark # Po QUOTATION MARK +0027 ; Quotation_Mark # Po APOSTROPHE +00AB ; Quotation_Mark # Pi LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +00BB ; Quotation_Mark # Pf RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +2018 ; Quotation_Mark # Pi LEFT SINGLE QUOTATION MARK +2019 ; Quotation_Mark # Pf RIGHT SINGLE QUOTATION MARK +201A ; Quotation_Mark # Ps SINGLE LOW-9 QUOTATION MARK +201B..201C ; Quotation_Mark # Pi [2] SINGLE HIGH-REVERSED-9 QUOTATION MARK..LEFT DOUBLE QUOTATION MARK +201D ; Quotation_Mark # Pf RIGHT DOUBLE QUOTATION MARK +201E ; Quotation_Mark # Ps DOUBLE LOW-9 QUOTATION MARK +201F ; Quotation_Mark # Pi DOUBLE HIGH-REVERSED-9 QUOTATION MARK +2039 ; Quotation_Mark # Pi SINGLE LEFT-POINTING ANGLE QUOTATION MARK +203A ; Quotation_Mark # Pf SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +2E42 ; Quotation_Mark # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK +300C ; Quotation_Mark # Ps LEFT CORNER BRACKET +300D ; Quotation_Mark # Pe RIGHT CORNER BRACKET +300E ; Quotation_Mark # Ps LEFT WHITE CORNER BRACKET +300F ; Quotation_Mark # Pe RIGHT WHITE CORNER BRACKET +301D ; Quotation_Mark # Ps REVERSED DOUBLE PRIME QUOTATION MARK +301E..301F ; Quotation_Mark # Pe [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK +FE41 ; Quotation_Mark # Ps PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET +FE42 ; Quotation_Mark # Pe PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET +FE43 ; Quotation_Mark # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET +FE44 ; Quotation_Mark # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET +FF02 ; Quotation_Mark # Po FULLWIDTH QUOTATION MARK +FF07 ; Quotation_Mark # Po FULLWIDTH APOSTROPHE +FF62 ; Quotation_Mark # Ps HALFWIDTH LEFT CORNER BRACKET +FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET + +# Total code points: 30 + +# ================================================ + +0021 ; Terminal_Punctuation # Po EXCLAMATION MARK +002C ; Terminal_Punctuation # Po COMMA +002E ; Terminal_Punctuation # Po FULL STOP +003A..003B ; Terminal_Punctuation # Po [2] COLON..SEMICOLON +003F ; Terminal_Punctuation # Po QUESTION MARK +037E ; Terminal_Punctuation # Po GREEK QUESTION MARK +0387 ; Terminal_Punctuation # Po GREEK ANO TELEIA +0589 ; Terminal_Punctuation # Po ARMENIAN FULL STOP +05C3 ; Terminal_Punctuation # Po HEBREW PUNCTUATION SOF PASUQ +060C ; Terminal_Punctuation # Po ARABIC COMMA +061B ; Terminal_Punctuation # Po ARABIC SEMICOLON +061D..061F ; Terminal_Punctuation # Po [3] ARABIC END OF TEXT MARK..ARABIC QUESTION MARK +06D4 ; Terminal_Punctuation # Po ARABIC FULL STOP +0700..070A ; Terminal_Punctuation # Po [11] SYRIAC END OF PARAGRAPH..SYRIAC CONTRACTION +070C ; Terminal_Punctuation # Po SYRIAC HARKLEAN METOBELUS +07F8..07F9 ; Terminal_Punctuation # Po [2] NKO COMMA..NKO EXCLAMATION MARK +0830..0835 ; Terminal_Punctuation # Po [6] SAMARITAN PUNCTUATION NEQUDAA..SAMARITAN PUNCTUATION SHIYYAALAA +0837..083E ; Terminal_Punctuation # Po [8] SAMARITAN PUNCTUATION MELODIC QITSA..SAMARITAN PUNCTUATION ANNAAU +085E ; Terminal_Punctuation # Po MANDAIC PUNCTUATION +0964..0965 ; Terminal_Punctuation # Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA +0E5A..0E5B ; Terminal_Punctuation # Po [2] THAI CHARACTER ANGKHANKHU..THAI CHARACTER KHOMUT +0F08 ; Terminal_Punctuation # Po TIBETAN MARK SBRUL SHAD +0F0D..0F12 ; Terminal_Punctuation # Po [6] TIBETAN MARK SHAD..TIBETAN MARK RGYA GRAM SHAD +104A..104B ; Terminal_Punctuation # Po [2] MYANMAR SIGN LITTLE SECTION..MYANMAR SIGN SECTION +1361..1368 ; Terminal_Punctuation # Po [8] ETHIOPIC WORDSPACE..ETHIOPIC PARAGRAPH SEPARATOR +166E ; Terminal_Punctuation # Po CANADIAN SYLLABICS FULL STOP +16EB..16ED ; Terminal_Punctuation # Po [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION +1735..1736 ; Terminal_Punctuation # Po [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION +17D4..17D6 ; Terminal_Punctuation # Po [3] KHMER SIGN KHAN..KHMER SIGN CAMNUC PII KUUH +17DA ; Terminal_Punctuation # Po KHMER SIGN KOOMUUT +1802..1805 ; Terminal_Punctuation # Po [4] MONGOLIAN COMMA..MONGOLIAN FOUR DOTS +1808..1809 ; Terminal_Punctuation # Po [2] MONGOLIAN MANCHU COMMA..MONGOLIAN MANCHU FULL STOP +1944..1945 ; Terminal_Punctuation # Po [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK +1AA8..1AAB ; Terminal_Punctuation # Po [4] TAI THAM SIGN KAAN..TAI THAM SIGN SATKAANKUU +1B4E..1B4F ; Terminal_Punctuation # Po [2] BALINESE INVERTED CARIK SIKI..BALINESE INVERTED CARIK PAREREN +1B5A..1B5B ; Terminal_Punctuation # Po [2] BALINESE PANTI..BALINESE PAMADA +1B5D..1B5F ; Terminal_Punctuation # Po [3] BALINESE CARIK PAMUNGKAH..BALINESE CARIK PAREREN +1B7D..1B7F ; Terminal_Punctuation # Po [3] BALINESE PANTI LANTANG..BALINESE PANTI BAWAK +1C3B..1C3F ; Terminal_Punctuation # Po [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK +1C7E..1C7F ; Terminal_Punctuation # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD +2024 ; Terminal_Punctuation # Po ONE DOT LEADER +203C..203D ; Terminal_Punctuation # Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG +2047..2049 ; Terminal_Punctuation # Po [3] DOUBLE QUESTION MARK..EXCLAMATION QUESTION MARK +2CF9..2CFB ; Terminal_Punctuation # Po [3] COPTIC OLD NUBIAN FULL STOP..COPTIC OLD NUBIAN INDIRECT QUESTION MARK +2E2E ; Terminal_Punctuation # Po REVERSED QUESTION MARK +2E3C ; Terminal_Punctuation # Po STENOGRAPHIC FULL STOP +2E41 ; Terminal_Punctuation # Po REVERSED COMMA +2E4C ; Terminal_Punctuation # Po MEDIEVAL COMMA +2E4E..2E4F ; Terminal_Punctuation # Po [2] PUNCTUS ELEVATUS MARK..CORNISH VERSE DIVIDER +2E53..2E54 ; Terminal_Punctuation # Po [2] MEDIEVAL EXCLAMATION MARK..MEDIEVAL QUESTION MARK +3001..3002 ; Terminal_Punctuation # Po [2] IDEOGRAPHIC COMMA..IDEOGRAPHIC FULL STOP +A4FE..A4FF ; Terminal_Punctuation # Po [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP +A60D..A60F ; Terminal_Punctuation # Po [3] VAI COMMA..VAI QUESTION MARK +A6F3..A6F7 ; Terminal_Punctuation # Po [5] BAMUM FULL STOP..BAMUM QUESTION MARK +A876..A877 ; Terminal_Punctuation # Po [2] PHAGS-PA MARK SHAD..PHAGS-PA MARK DOUBLE SHAD +A8CE..A8CF ; Terminal_Punctuation # Po [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA +A92F ; Terminal_Punctuation # Po KAYAH LI SIGN SHYA +A9C7..A9C9 ; Terminal_Punctuation # Po [3] JAVANESE PADA PANGKAT..JAVANESE PADA LUNGSI +AA5D..AA5F ; Terminal_Punctuation # Po [3] CHAM PUNCTUATION DANDA..CHAM PUNCTUATION TRIPLE DANDA +AADF ; Terminal_Punctuation # Po TAI VIET SYMBOL KOI KOI +AAF0..AAF1 ; Terminal_Punctuation # Po [2] MEETEI MAYEK CHEIKHAN..MEETEI MAYEK AHANG KHUDAM +ABEB ; Terminal_Punctuation # Po MEETEI MAYEK CHEIKHEI +FE12 ; Terminal_Punctuation # Po PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP +FE15..FE16 ; Terminal_Punctuation # Po [2] PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK..PRESENTATION FORM FOR VERTICAL QUESTION MARK +FE50..FE52 ; Terminal_Punctuation # Po [3] SMALL COMMA..SMALL FULL STOP +FE54..FE57 ; Terminal_Punctuation # Po [4] SMALL SEMICOLON..SMALL EXCLAMATION MARK +FF01 ; Terminal_Punctuation # Po FULLWIDTH EXCLAMATION MARK +FF0C ; Terminal_Punctuation # Po FULLWIDTH COMMA +FF0E ; Terminal_Punctuation # Po FULLWIDTH FULL STOP +FF1A..FF1B ; Terminal_Punctuation # Po [2] FULLWIDTH COLON..FULLWIDTH SEMICOLON +FF1F ; Terminal_Punctuation # Po FULLWIDTH QUESTION MARK +FF61 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC FULL STOP +FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA +1039F ; Terminal_Punctuation # Po UGARITIC WORD DIVIDER +103D0 ; Terminal_Punctuation # Po OLD PERSIAN WORD DIVIDER +10857 ; Terminal_Punctuation # Po IMPERIAL ARAMAIC SECTION SIGN +1091F ; Terminal_Punctuation # Po PHOENICIAN WORD SEPARATOR +10A56..10A57 ; Terminal_Punctuation # Po [2] KHAROSHTHI PUNCTUATION DANDA..KHAROSHTHI PUNCTUATION DOUBLE DANDA +10AF0..10AF5 ; Terminal_Punctuation # Po [6] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION TWO DOTS +10B3A..10B3F ; Terminal_Punctuation # Po [6] TINY TWO DOTS OVER ONE DOT PUNCTUATION..LARGE ONE RING OVER TWO RINGS PUNCTUATION +10B99..10B9C ; Terminal_Punctuation # Po [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT +10F55..10F59 ; Terminal_Punctuation # Po [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT +10F86..10F89 ; Terminal_Punctuation # Po [4] OLD UYGHUR PUNCTUATION BAR..OLD UYGHUR PUNCTUATION FOUR DOTS +11047..1104D ; Terminal_Punctuation # Po [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS +110BE..110C1 ; Terminal_Punctuation # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA +11141..11143 ; Terminal_Punctuation # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK +111C5..111C6 ; Terminal_Punctuation # Po [2] SHARADA DANDA..SHARADA DOUBLE DANDA +111CD ; Terminal_Punctuation # Po SHARADA SUTRA MARK +111DE..111DF ; Terminal_Punctuation # Po [2] SHARADA SECTION MARK-1..SHARADA SECTION MARK-2 +11238..1123C ; Terminal_Punctuation # Po [5] KHOJKI DANDA..KHOJKI DOUBLE SECTION MARK +112A9 ; Terminal_Punctuation # Po MULTANI SECTION MARK +113D4..113D5 ; Terminal_Punctuation # Po [2] TULU-TIGALARI DANDA..TULU-TIGALARI DOUBLE DANDA +1144B..1144D ; Terminal_Punctuation # Po [3] NEWA DANDA..NEWA COMMA +1145A..1145B ; Terminal_Punctuation # Po [2] NEWA DOUBLE COMMA..NEWA PLACEHOLDER MARK +115C2..115C5 ; Terminal_Punctuation # Po [4] SIDDHAM DANDA..SIDDHAM SEPARATOR BAR +115C9..115D7 ; Terminal_Punctuation # Po [15] SIDDHAM END OF TEXT MARK..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES +11641..11642 ; Terminal_Punctuation # Po [2] MODI DANDA..MODI DOUBLE DANDA +1173C..1173E ; Terminal_Punctuation # Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI +11944 ; Terminal_Punctuation # Po DIVES AKURU DOUBLE DANDA +11946 ; Terminal_Punctuation # Po DIVES AKURU END OF TEXT MARK +11A42..11A43 ; Terminal_Punctuation # Po [2] ZANABAZAR SQUARE MARK SHAD..ZANABAZAR SQUARE MARK DOUBLE SHAD +11A9B..11A9C ; Terminal_Punctuation # Po [2] SOYOMBO MARK SHAD..SOYOMBO MARK DOUBLE SHAD +11AA1..11AA2 ; Terminal_Punctuation # Po [2] SOYOMBO TERMINAL MARK-1..SOYOMBO TERMINAL MARK-2 +11C41..11C43 ; Terminal_Punctuation # Po [3] BHAIKSUKI DANDA..BHAIKSUKI WORD SEPARATOR +11C71 ; Terminal_Punctuation # Po MARCHEN MARK SHAD +11EF7..11EF8 ; Terminal_Punctuation # Po [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION +11F43..11F44 ; Terminal_Punctuation # Po [2] KAWI DANDA..KAWI DOUBLE DANDA +12470..12474 ; Terminal_Punctuation # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON +16A6E..16A6F ; Terminal_Punctuation # Po [2] MRO DANDA..MRO DOUBLE DANDA +16AF5 ; Terminal_Punctuation # Po BASSA VAH FULL STOP +16B37..16B39 ; Terminal_Punctuation # Po [3] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN CIM CHEEM +16B44 ; Terminal_Punctuation # Po PAHAWH HMONG SIGN XAUS +16D6E..16D6F ; Terminal_Punctuation # Po [2] KIRAT RAI DANDA..KIRAT RAI DOUBLE DANDA +16E97..16E98 ; Terminal_Punctuation # Po [2] MEDEFAIDRIN COMMA..MEDEFAIDRIN FULL STOP +1BC9F ; Terminal_Punctuation # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP +1DA87..1DA8A ; Terminal_Punctuation # Po [4] SIGNWRITING COMMA..SIGNWRITING COLON + +# Total code points: 291 + +# ================================================ + +005E ; Other_Math # Sk CIRCUMFLEX ACCENT +03D0..03D2 ; Other_Math # L& [3] GREEK BETA SYMBOL..GREEK UPSILON WITH HOOK SYMBOL +03D5 ; Other_Math # L& GREEK PHI SYMBOL +03F0..03F1 ; Other_Math # L& [2] GREEK KAPPA SYMBOL..GREEK RHO SYMBOL +03F4..03F5 ; Other_Math # L& [2] GREEK CAPITAL THETA SYMBOL..GREEK LUNATE EPSILON SYMBOL +2016 ; Other_Math # Po DOUBLE VERTICAL LINE +2032..2034 ; Other_Math # Po [3] PRIME..TRIPLE PRIME +2040 ; Other_Math # Pc CHARACTER TIE +2061..2064 ; Other_Math # Cf [4] FUNCTION APPLICATION..INVISIBLE PLUS +207D ; Other_Math # Ps SUPERSCRIPT LEFT PARENTHESIS +207E ; Other_Math # Pe SUPERSCRIPT RIGHT PARENTHESIS +208D ; Other_Math # Ps SUBSCRIPT LEFT PARENTHESIS +208E ; Other_Math # Pe SUBSCRIPT RIGHT PARENTHESIS +20D0..20DC ; Other_Math # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE +20E1 ; Other_Math # Mn COMBINING LEFT RIGHT ARROW ABOVE +20E5..20E6 ; Other_Math # Mn [2] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING DOUBLE VERTICAL STROKE OVERLAY +20EB..20EF ; Other_Math # Mn [5] COMBINING LONG DOUBLE SOLIDUS OVERLAY..COMBINING RIGHT ARROW BELOW +2102 ; Other_Math # L& DOUBLE-STRUCK CAPITAL C +2107 ; Other_Math # L& EULER CONSTANT +210A..2113 ; Other_Math # L& [10] SCRIPT SMALL G..SCRIPT SMALL L +2115 ; Other_Math # L& DOUBLE-STRUCK CAPITAL N +2119..211D ; Other_Math # L& [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R +2124 ; Other_Math # L& DOUBLE-STRUCK CAPITAL Z +2128 ; Other_Math # L& BLACK-LETTER CAPITAL Z +2129 ; Other_Math # So TURNED GREEK SMALL LETTER IOTA +212C..212D ; Other_Math # L& [2] SCRIPT CAPITAL B..BLACK-LETTER CAPITAL C +212F..2131 ; Other_Math # L& [3] SCRIPT SMALL E..SCRIPT CAPITAL F +2133..2134 ; Other_Math # L& [2] SCRIPT CAPITAL M..SCRIPT SMALL O +2135..2138 ; Other_Math # Lo [4] ALEF SYMBOL..DALET SYMBOL +213C..213F ; Other_Math # L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI +2145..2149 ; Other_Math # L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J +2195..2199 ; Other_Math # So [5] UP DOWN ARROW..SOUTH WEST ARROW +219C..219F ; Other_Math # So [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW +21A1..21A2 ; Other_Math # So [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL +21A4..21A5 ; Other_Math # So [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR +21A7 ; Other_Math # So DOWNWARDS ARROW FROM BAR +21A9..21AD ; Other_Math # So [5] LEFTWARDS ARROW WITH HOOK..LEFT RIGHT WAVE ARROW +21B0..21B1 ; Other_Math # So [2] UPWARDS ARROW WITH TIP LEFTWARDS..UPWARDS ARROW WITH TIP RIGHTWARDS +21B6..21B7 ; Other_Math # So [2] ANTICLOCKWISE TOP SEMICIRCLE ARROW..CLOCKWISE TOP SEMICIRCLE ARROW +21BC..21CD ; Other_Math # So [18] LEFTWARDS HARPOON WITH BARB UPWARDS..LEFTWARDS DOUBLE ARROW WITH STROKE +21D0..21D1 ; Other_Math # So [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW +21D3 ; Other_Math # So DOWNWARDS DOUBLE ARROW +21D5..21DB ; Other_Math # So [7] UP DOWN DOUBLE ARROW..RIGHTWARDS TRIPLE ARROW +21DD ; Other_Math # So RIGHTWARDS SQUIGGLE ARROW +21E4..21E5 ; Other_Math # So [2] LEFTWARDS ARROW TO BAR..RIGHTWARDS ARROW TO BAR +2308 ; Other_Math # Ps LEFT CEILING +2309 ; Other_Math # Pe RIGHT CEILING +230A ; Other_Math # Ps LEFT FLOOR +230B ; Other_Math # Pe RIGHT FLOOR +23B4..23B5 ; Other_Math # So [2] TOP SQUARE BRACKET..BOTTOM SQUARE BRACKET +23B7 ; Other_Math # So RADICAL SYMBOL BOTTOM +23D0 ; Other_Math # So VERTICAL LINE EXTENSION +23E2 ; Other_Math # So WHITE TRAPEZIUM +25A0..25A1 ; Other_Math # So [2] BLACK SQUARE..WHITE SQUARE +25AE..25B6 ; Other_Math # So [9] BLACK VERTICAL RECTANGLE..BLACK RIGHT-POINTING TRIANGLE +25BC..25C0 ; Other_Math # So [5] BLACK DOWN-POINTING TRIANGLE..BLACK LEFT-POINTING TRIANGLE +25C6..25C7 ; Other_Math # So [2] BLACK DIAMOND..WHITE DIAMOND +25CA..25CB ; Other_Math # So [2] LOZENGE..WHITE CIRCLE +25CF..25D3 ; Other_Math # So [5] BLACK CIRCLE..CIRCLE WITH UPPER HALF BLACK +25E2 ; Other_Math # So BLACK LOWER RIGHT TRIANGLE +25E4 ; Other_Math # So BLACK UPPER LEFT TRIANGLE +25E7..25EC ; Other_Math # So [6] SQUARE WITH LEFT HALF BLACK..WHITE UP-POINTING TRIANGLE WITH DOT +2605..2606 ; Other_Math # So [2] BLACK STAR..WHITE STAR +2640 ; Other_Math # So FEMALE SIGN +2642 ; Other_Math # So MALE SIGN +2660..2663 ; Other_Math # So [4] BLACK SPADE SUIT..BLACK CLUB SUIT +266D..266E ; Other_Math # So [2] MUSIC FLAT SIGN..MUSIC NATURAL SIGN +27C5 ; Other_Math # Ps LEFT S-SHAPED BAG DELIMITER +27C6 ; Other_Math # Pe RIGHT S-SHAPED BAG DELIMITER +27E6 ; Other_Math # Ps MATHEMATICAL LEFT WHITE SQUARE BRACKET +27E7 ; Other_Math # Pe MATHEMATICAL RIGHT WHITE SQUARE BRACKET +27E8 ; Other_Math # Ps MATHEMATICAL LEFT ANGLE BRACKET +27E9 ; Other_Math # Pe MATHEMATICAL RIGHT ANGLE BRACKET +27EA ; Other_Math # Ps MATHEMATICAL LEFT DOUBLE ANGLE BRACKET +27EB ; Other_Math # Pe MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET +27EC ; Other_Math # Ps MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET +27ED ; Other_Math # Pe MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET +27EE ; Other_Math # Ps MATHEMATICAL LEFT FLATTENED PARENTHESIS +27EF ; Other_Math # Pe MATHEMATICAL RIGHT FLATTENED PARENTHESIS +2983 ; Other_Math # Ps LEFT WHITE CURLY BRACKET +2984 ; Other_Math # Pe RIGHT WHITE CURLY BRACKET +2985 ; Other_Math # Ps LEFT WHITE PARENTHESIS +2986 ; Other_Math # Pe RIGHT WHITE PARENTHESIS +2987 ; Other_Math # Ps Z NOTATION LEFT IMAGE BRACKET +2988 ; Other_Math # Pe Z NOTATION RIGHT IMAGE BRACKET +2989 ; Other_Math # Ps Z NOTATION LEFT BINDING BRACKET +298A ; Other_Math # Pe Z NOTATION RIGHT BINDING BRACKET +298B ; Other_Math # Ps LEFT SQUARE BRACKET WITH UNDERBAR +298C ; Other_Math # Pe RIGHT SQUARE BRACKET WITH UNDERBAR +298D ; Other_Math # Ps LEFT SQUARE BRACKET WITH TICK IN TOP CORNER +298E ; Other_Math # Pe RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER +298F ; Other_Math # Ps LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER +2990 ; Other_Math # Pe RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER +2991 ; Other_Math # Ps LEFT ANGLE BRACKET WITH DOT +2992 ; Other_Math # Pe RIGHT ANGLE BRACKET WITH DOT +2993 ; Other_Math # Ps LEFT ARC LESS-THAN BRACKET +2994 ; Other_Math # Pe RIGHT ARC GREATER-THAN BRACKET +2995 ; Other_Math # Ps DOUBLE LEFT ARC GREATER-THAN BRACKET +2996 ; Other_Math # Pe DOUBLE RIGHT ARC LESS-THAN BRACKET +2997 ; Other_Math # Ps LEFT BLACK TORTOISE SHELL BRACKET +2998 ; Other_Math # Pe RIGHT BLACK TORTOISE SHELL BRACKET +29D8 ; Other_Math # Ps LEFT WIGGLY FENCE +29D9 ; Other_Math # Pe RIGHT WIGGLY FENCE +29DA ; Other_Math # Ps LEFT DOUBLE WIGGLY FENCE +29DB ; Other_Math # Pe RIGHT DOUBLE WIGGLY FENCE +29FC ; Other_Math # Ps LEFT-POINTING CURVED ANGLE BRACKET +29FD ; Other_Math # Pe RIGHT-POINTING CURVED ANGLE BRACKET +FE61 ; Other_Math # Po SMALL ASTERISK +FE63 ; Other_Math # Pd SMALL HYPHEN-MINUS +FE68 ; Other_Math # Po SMALL REVERSE SOLIDUS +FF3C ; Other_Math # Po FULLWIDTH REVERSE SOLIDUS +FF3E ; Other_Math # Sk FULLWIDTH CIRCUMFLEX ACCENT +1D400..1D454 ; Other_Math # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G +1D456..1D49C ; Other_Math # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A +1D49E..1D49F ; Other_Math # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D +1D4A2 ; Other_Math # L& MATHEMATICAL SCRIPT CAPITAL G +1D4A5..1D4A6 ; Other_Math # L& [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K +1D4A9..1D4AC ; Other_Math # L& [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q +1D4AE..1D4B9 ; Other_Math # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D +1D4BB ; Other_Math # L& MATHEMATICAL SCRIPT SMALL F +1D4BD..1D4C3 ; Other_Math # L& [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N +1D4C5..1D505 ; Other_Math # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B +1D507..1D50A ; Other_Math # L& [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G +1D50D..1D514 ; Other_Math # L& [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q +1D516..1D51C ; Other_Math # L& [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y +1D51E..1D539 ; Other_Math # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B +1D53B..1D53E ; Other_Math # L& [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G +1D540..1D544 ; Other_Math # L& [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M +1D546 ; Other_Math # L& MATHEMATICAL DOUBLE-STRUCK CAPITAL O +1D54A..1D550 ; Other_Math # L& [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y +1D552..1D6A5 ; Other_Math # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J +1D6A8..1D6C0 ; Other_Math # L& [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA +1D6C2..1D6DA ; Other_Math # L& [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA +1D6DC..1D6FA ; Other_Math # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA +1D6FC..1D714 ; Other_Math # L& [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA +1D716..1D734 ; Other_Math # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA +1D736..1D74E ; Other_Math # L& [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA +1D750..1D76E ; Other_Math # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA +1D770..1D788 ; Other_Math # L& [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA +1D78A..1D7A8 ; Other_Math # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA +1D7AA..1D7C2 ; Other_Math # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA +1D7C4..1D7CB ; Other_Math # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA +1D7CE..1D7FF ; Other_Math # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE +1EE00..1EE03 ; Other_Math # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL +1EE05..1EE1F ; Other_Math # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF +1EE21..1EE22 ; Other_Math # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM +1EE24 ; Other_Math # Lo ARABIC MATHEMATICAL INITIAL HEH +1EE27 ; Other_Math # Lo ARABIC MATHEMATICAL INITIAL HAH +1EE29..1EE32 ; Other_Math # Lo [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF +1EE34..1EE37 ; Other_Math # Lo [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH +1EE39 ; Other_Math # Lo ARABIC MATHEMATICAL INITIAL DAD +1EE3B ; Other_Math # Lo ARABIC MATHEMATICAL INITIAL GHAIN +1EE42 ; Other_Math # Lo ARABIC MATHEMATICAL TAILED JEEM +1EE47 ; Other_Math # Lo ARABIC MATHEMATICAL TAILED HAH +1EE49 ; Other_Math # Lo ARABIC MATHEMATICAL TAILED YEH +1EE4B ; Other_Math # Lo ARABIC MATHEMATICAL TAILED LAM +1EE4D..1EE4F ; Other_Math # Lo [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN +1EE51..1EE52 ; Other_Math # Lo [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF +1EE54 ; Other_Math # Lo ARABIC MATHEMATICAL TAILED SHEEN +1EE57 ; Other_Math # Lo ARABIC MATHEMATICAL TAILED KHAH +1EE59 ; Other_Math # Lo ARABIC MATHEMATICAL TAILED DAD +1EE5B ; Other_Math # Lo ARABIC MATHEMATICAL TAILED GHAIN +1EE5D ; Other_Math # Lo ARABIC MATHEMATICAL TAILED DOTLESS NOON +1EE5F ; Other_Math # Lo ARABIC MATHEMATICAL TAILED DOTLESS QAF +1EE61..1EE62 ; Other_Math # Lo [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM +1EE64 ; Other_Math # Lo ARABIC MATHEMATICAL STRETCHED HEH +1EE67..1EE6A ; Other_Math # Lo [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF +1EE6C..1EE72 ; Other_Math # Lo [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF +1EE74..1EE77 ; Other_Math # Lo [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH +1EE79..1EE7C ; Other_Math # Lo [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH +1EE7E ; Other_Math # Lo ARABIC MATHEMATICAL STRETCHED DOTLESS FEH +1EE80..1EE89 ; Other_Math # Lo [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH +1EE8B..1EE9B ; Other_Math # Lo [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN +1EEA1..1EEA3 ; Other_Math # Lo [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL +1EEA5..1EEA9 ; Other_Math # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH +1EEAB..1EEBB ; Other_Math # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN + +# Total code points: 1362 + +# ================================================ + +0030..0039 ; Hex_Digit # Nd [10] DIGIT ZERO..DIGIT NINE +0041..0046 ; Hex_Digit # L& [6] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER F +0061..0066 ; Hex_Digit # L& [6] LATIN SMALL LETTER A..LATIN SMALL LETTER F +FF10..FF19 ; Hex_Digit # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE +FF21..FF26 ; Hex_Digit # L& [6] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER F +FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER F + +# Total code points: 44 + +# ================================================ + +0030..0039 ; ASCII_Hex_Digit # Nd [10] DIGIT ZERO..DIGIT NINE +0041..0046 ; ASCII_Hex_Digit # L& [6] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER F +0061..0066 ; ASCII_Hex_Digit # L& [6] LATIN SMALL LETTER A..LATIN SMALL LETTER F + +# Total code points: 22 + +# ================================================ + +0345 ; Other_Alphabetic # Mn COMBINING GREEK YPOGEGRAMMENI +0363..036F ; Other_Alphabetic # Mn [13] COMBINING LATIN SMALL LETTER A..COMBINING LATIN SMALL LETTER X +05B0..05BD ; Other_Alphabetic # Mn [14] HEBREW POINT SHEVA..HEBREW POINT METEG +05BF ; Other_Alphabetic # Mn HEBREW POINT RAFE +05C1..05C2 ; Other_Alphabetic # Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT +05C4..05C5 ; Other_Alphabetic # Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT +05C7 ; Other_Alphabetic # Mn HEBREW POINT QAMATS QATAN +0610..061A ; Other_Alphabetic # Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA +064B..0657 ; Other_Alphabetic # Mn [13] ARABIC FATHATAN..ARABIC INVERTED DAMMA +0659..065F ; Other_Alphabetic # Mn [7] ARABIC ZWARAKAY..ARABIC WAVY HAMZA BELOW +0670 ; Other_Alphabetic # Mn ARABIC LETTER SUPERSCRIPT ALEF +06D6..06DC ; Other_Alphabetic # Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN +06E1..06E4 ; Other_Alphabetic # Mn [4] ARABIC SMALL HIGH DOTLESS HEAD OF KHAH..ARABIC SMALL HIGH MADDA +06E7..06E8 ; Other_Alphabetic # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON +06ED ; Other_Alphabetic # Mn ARABIC SMALL LOW MEEM +0711 ; Other_Alphabetic # Mn SYRIAC LETTER SUPERSCRIPT ALAPH +0730..073F ; Other_Alphabetic # Mn [16] SYRIAC PTHAHA ABOVE..SYRIAC RWAHA +07A6..07B0 ; Other_Alphabetic # Mn [11] THAANA ABAFILI..THAANA SUKUN +0816..0817 ; Other_Alphabetic # Mn [2] SAMARITAN MARK IN..SAMARITAN MARK IN-ALAF +081B..0823 ; Other_Alphabetic # Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A +0825..0827 ; Other_Alphabetic # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U +0829..082C ; Other_Alphabetic # Mn [4] SAMARITAN VOWEL SIGN LONG I..SAMARITAN VOWEL SIGN SUKUN +0897 ; Other_Alphabetic # Mn ARABIC PEPET +08D4..08DF ; Other_Alphabetic # Mn [12] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH WORD WAQFA +08E3..08E9 ; Other_Alphabetic # Mn [7] ARABIC TURNED DAMMA BELOW..ARABIC CURLY KASRATAN +08F0..0902 ; Other_Alphabetic # Mn [19] ARABIC OPEN FATHATAN..DEVANAGARI SIGN ANUSVARA +0903 ; Other_Alphabetic # Mc DEVANAGARI SIGN VISARGA +093A ; Other_Alphabetic # Mn DEVANAGARI VOWEL SIGN OE +093B ; Other_Alphabetic # Mc DEVANAGARI VOWEL SIGN OOE +093E..0940 ; Other_Alphabetic # Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II +0941..0948 ; Other_Alphabetic # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI +0949..094C ; Other_Alphabetic # Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU +094E..094F ; Other_Alphabetic # Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW +0955..0957 ; Other_Alphabetic # Mn [3] DEVANAGARI VOWEL SIGN CANDRA LONG E..DEVANAGARI VOWEL SIGN UUE +0962..0963 ; Other_Alphabetic # Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL +0981 ; Other_Alphabetic # Mn BENGALI SIGN CANDRABINDU +0982..0983 ; Other_Alphabetic # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA +09BE..09C0 ; Other_Alphabetic # Mc [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II +09C1..09C4 ; Other_Alphabetic # Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR +09C7..09C8 ; Other_Alphabetic # Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI +09CB..09CC ; Other_Alphabetic # Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU +09D7 ; Other_Alphabetic # Mc BENGALI AU LENGTH MARK +09E2..09E3 ; Other_Alphabetic # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL +0A01..0A02 ; Other_Alphabetic # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI +0A03 ; Other_Alphabetic # Mc GURMUKHI SIGN VISARGA +0A3E..0A40 ; Other_Alphabetic # Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II +0A41..0A42 ; Other_Alphabetic # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU +0A47..0A48 ; Other_Alphabetic # Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI +0A4B..0A4C ; Other_Alphabetic # Mn [2] GURMUKHI VOWEL SIGN OO..GURMUKHI VOWEL SIGN AU +0A51 ; Other_Alphabetic # Mn GURMUKHI SIGN UDAAT +0A70..0A71 ; Other_Alphabetic # Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK +0A75 ; Other_Alphabetic # Mn GURMUKHI SIGN YAKASH +0A81..0A82 ; Other_Alphabetic # Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA +0A83 ; Other_Alphabetic # Mc GUJARATI SIGN VISARGA +0ABE..0AC0 ; Other_Alphabetic # Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II +0AC1..0AC5 ; Other_Alphabetic # Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E +0AC7..0AC8 ; Other_Alphabetic # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI +0AC9 ; Other_Alphabetic # Mc GUJARATI VOWEL SIGN CANDRA O +0ACB..0ACC ; Other_Alphabetic # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU +0AE2..0AE3 ; Other_Alphabetic # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL +0AFA..0AFC ; Other_Alphabetic # Mn [3] GUJARATI SIGN SUKUN..GUJARATI SIGN MADDAH +0B01 ; Other_Alphabetic # Mn ORIYA SIGN CANDRABINDU +0B02..0B03 ; Other_Alphabetic # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA +0B3E ; Other_Alphabetic # Mc ORIYA VOWEL SIGN AA +0B3F ; Other_Alphabetic # Mn ORIYA VOWEL SIGN I +0B40 ; Other_Alphabetic # Mc ORIYA VOWEL SIGN II +0B41..0B44 ; Other_Alphabetic # Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR +0B47..0B48 ; Other_Alphabetic # Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI +0B4B..0B4C ; Other_Alphabetic # Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU +0B56 ; Other_Alphabetic # Mn ORIYA AI LENGTH MARK +0B57 ; Other_Alphabetic # Mc ORIYA AU LENGTH MARK +0B62..0B63 ; Other_Alphabetic # Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL +0B82 ; Other_Alphabetic # Mn TAMIL SIGN ANUSVARA +0BBE..0BBF ; Other_Alphabetic # Mc [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I +0BC0 ; Other_Alphabetic # Mn TAMIL VOWEL SIGN II +0BC1..0BC2 ; Other_Alphabetic # Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU +0BC6..0BC8 ; Other_Alphabetic # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI +0BCA..0BCC ; Other_Alphabetic # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU +0BD7 ; Other_Alphabetic # Mc TAMIL AU LENGTH MARK +0C00 ; Other_Alphabetic # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE +0C01..0C03 ; Other_Alphabetic # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA +0C04 ; Other_Alphabetic # Mn TELUGU SIGN COMBINING ANUSVARA ABOVE +0C3E..0C40 ; Other_Alphabetic # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II +0C41..0C44 ; Other_Alphabetic # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR +0C46..0C48 ; Other_Alphabetic # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI +0C4A..0C4C ; Other_Alphabetic # Mn [3] TELUGU VOWEL SIGN O..TELUGU VOWEL SIGN AU +0C55..0C56 ; Other_Alphabetic # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK +0C62..0C63 ; Other_Alphabetic # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL +0C81 ; Other_Alphabetic # Mn KANNADA SIGN CANDRABINDU +0C82..0C83 ; Other_Alphabetic # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA +0CBE ; Other_Alphabetic # Mc KANNADA VOWEL SIGN AA +0CBF ; Other_Alphabetic # Mn KANNADA VOWEL SIGN I +0CC0..0CC4 ; Other_Alphabetic # Mc [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR +0CC6 ; Other_Alphabetic # Mn KANNADA VOWEL SIGN E +0CC7..0CC8 ; Other_Alphabetic # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI +0CCA..0CCB ; Other_Alphabetic # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO +0CCC ; Other_Alphabetic # Mn KANNADA VOWEL SIGN AU +0CD5..0CD6 ; Other_Alphabetic # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK +0CE2..0CE3 ; Other_Alphabetic # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL +0CF3 ; Other_Alphabetic # Mc KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT +0D00..0D01 ; Other_Alphabetic # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU +0D02..0D03 ; Other_Alphabetic # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA +0D3E..0D40 ; Other_Alphabetic # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II +0D41..0D44 ; Other_Alphabetic # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR +0D46..0D48 ; Other_Alphabetic # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI +0D4A..0D4C ; Other_Alphabetic # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU +0D57 ; Other_Alphabetic # Mc MALAYALAM AU LENGTH MARK +0D62..0D63 ; Other_Alphabetic # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL +0D81 ; Other_Alphabetic # Mn SINHALA SIGN CANDRABINDU +0D82..0D83 ; Other_Alphabetic # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA +0DCF..0DD1 ; Other_Alphabetic # Mc [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA +0DD2..0DD4 ; Other_Alphabetic # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA +0DD6 ; Other_Alphabetic # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA +0DD8..0DDF ; Other_Alphabetic # Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA +0DF2..0DF3 ; Other_Alphabetic # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA +0E31 ; Other_Alphabetic # Mn THAI CHARACTER MAI HAN-AKAT +0E34..0E3A ; Other_Alphabetic # Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU +0E4D ; Other_Alphabetic # Mn THAI CHARACTER NIKHAHIT +0EB1 ; Other_Alphabetic # Mn LAO VOWEL SIGN MAI KAN +0EB4..0EB9 ; Other_Alphabetic # Mn [6] LAO VOWEL SIGN I..LAO VOWEL SIGN UU +0EBB..0EBC ; Other_Alphabetic # Mn [2] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN LO +0ECD ; Other_Alphabetic # Mn LAO NIGGAHITA +0F71..0F7E ; Other_Alphabetic # Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO +0F7F ; Other_Alphabetic # Mc TIBETAN SIGN RNAM BCAD +0F80..0F83 ; Other_Alphabetic # Mn [4] TIBETAN VOWEL SIGN REVERSED I..TIBETAN SIGN SNA LDAN +0F8D..0F97 ; Other_Alphabetic # Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA +0F99..0FBC ; Other_Alphabetic # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA +102B..102C ; Other_Alphabetic # Mc [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA +102D..1030 ; Other_Alphabetic # Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU +1031 ; Other_Alphabetic # Mc MYANMAR VOWEL SIGN E +1032..1036 ; Other_Alphabetic # Mn [5] MYANMAR VOWEL SIGN AI..MYANMAR SIGN ANUSVARA +1038 ; Other_Alphabetic # Mc MYANMAR SIGN VISARGA +103B..103C ; Other_Alphabetic # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA +103D..103E ; Other_Alphabetic # Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA +1056..1057 ; Other_Alphabetic # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR +1058..1059 ; Other_Alphabetic # Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL +105E..1060 ; Other_Alphabetic # Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA +1062..1064 ; Other_Alphabetic # Mc [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO +1067..106D ; Other_Alphabetic # Mc [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5 +1071..1074 ; Other_Alphabetic # Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE +1082 ; Other_Alphabetic # Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA +1083..1084 ; Other_Alphabetic # Mc [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E +1085..1086 ; Other_Alphabetic # Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y +1087..108C ; Other_Alphabetic # Mc [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3 +108D ; Other_Alphabetic # Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE +108F ; Other_Alphabetic # Mc MYANMAR SIGN RUMAI PALAUNG TONE-5 +109A..109C ; Other_Alphabetic # Mc [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A +109D ; Other_Alphabetic # Mn MYANMAR VOWEL SIGN AITON AI +1712..1713 ; Other_Alphabetic # Mn [2] TAGALOG VOWEL SIGN I..TAGALOG VOWEL SIGN U +1732..1733 ; Other_Alphabetic # Mn [2] HANUNOO VOWEL SIGN I..HANUNOO VOWEL SIGN U +1752..1753 ; Other_Alphabetic # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U +1772..1773 ; Other_Alphabetic # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U +17B6 ; Other_Alphabetic # Mc KHMER VOWEL SIGN AA +17B7..17BD ; Other_Alphabetic # Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA +17BE..17C5 ; Other_Alphabetic # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU +17C6 ; Other_Alphabetic # Mn KHMER SIGN NIKAHIT +17C7..17C8 ; Other_Alphabetic # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU +1885..1886 ; Other_Alphabetic # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA +18A9 ; Other_Alphabetic # Mn MONGOLIAN LETTER ALI GALI DAGALGA +1920..1922 ; Other_Alphabetic # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U +1923..1926 ; Other_Alphabetic # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU +1927..1928 ; Other_Alphabetic # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O +1929..192B ; Other_Alphabetic # Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA +1930..1931 ; Other_Alphabetic # Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA +1932 ; Other_Alphabetic # Mn LIMBU SMALL LETTER ANUSVARA +1933..1938 ; Other_Alphabetic # Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA +1A17..1A18 ; Other_Alphabetic # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U +1A19..1A1A ; Other_Alphabetic # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O +1A1B ; Other_Alphabetic # Mn BUGINESE VOWEL SIGN AE +1A55 ; Other_Alphabetic # Mc TAI THAM CONSONANT SIGN MEDIAL RA +1A56 ; Other_Alphabetic # Mn TAI THAM CONSONANT SIGN MEDIAL LA +1A57 ; Other_Alphabetic # Mc TAI THAM CONSONANT SIGN LA TANG LAI +1A58..1A5E ; Other_Alphabetic # Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA +1A61 ; Other_Alphabetic # Mc TAI THAM VOWEL SIGN A +1A62 ; Other_Alphabetic # Mn TAI THAM VOWEL SIGN MAI SAT +1A63..1A64 ; Other_Alphabetic # Mc [2] TAI THAM VOWEL SIGN AA..TAI THAM VOWEL SIGN TALL AA +1A65..1A6C ; Other_Alphabetic # Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW +1A6D..1A72 ; Other_Alphabetic # Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI +1A73..1A74 ; Other_Alphabetic # Mn [2] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN MAI KANG +1ABF..1AC0 ; Other_Alphabetic # Mn [2] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER TURNED W BELOW +1ACC..1ACE ; Other_Alphabetic # Mn [3] COMBINING LATIN SMALL LETTER INSULAR G..COMBINING LATIN SMALL LETTER INSULAR T +1B00..1B03 ; Other_Alphabetic # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG +1B04 ; Other_Alphabetic # Mc BALINESE SIGN BISAH +1B35 ; Other_Alphabetic # Mc BALINESE VOWEL SIGN TEDUNG +1B36..1B3A ; Other_Alphabetic # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA +1B3B ; Other_Alphabetic # Mc BALINESE VOWEL SIGN RA REPA TEDUNG +1B3C ; Other_Alphabetic # Mn BALINESE VOWEL SIGN LA LENGA +1B3D..1B41 ; Other_Alphabetic # Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG +1B42 ; Other_Alphabetic # Mn BALINESE VOWEL SIGN PEPET +1B43 ; Other_Alphabetic # Mc BALINESE VOWEL SIGN PEPET TEDUNG +1B80..1B81 ; Other_Alphabetic # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR +1B82 ; Other_Alphabetic # Mc SUNDANESE SIGN PANGWISAD +1BA1 ; Other_Alphabetic # Mc SUNDANESE CONSONANT SIGN PAMINGKAL +1BA2..1BA5 ; Other_Alphabetic # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU +1BA6..1BA7 ; Other_Alphabetic # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG +1BA8..1BA9 ; Other_Alphabetic # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG +1BAC..1BAD ; Other_Alphabetic # Mn [2] SUNDANESE CONSONANT SIGN PASANGAN MA..SUNDANESE CONSONANT SIGN PASANGAN WA +1BE7 ; Other_Alphabetic # Mc BATAK VOWEL SIGN E +1BE8..1BE9 ; Other_Alphabetic # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE +1BEA..1BEC ; Other_Alphabetic # Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O +1BED ; Other_Alphabetic # Mn BATAK VOWEL SIGN KARO O +1BEE ; Other_Alphabetic # Mc BATAK VOWEL SIGN U +1BEF..1BF1 ; Other_Alphabetic # Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H +1C24..1C2B ; Other_Alphabetic # Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU +1C2C..1C33 ; Other_Alphabetic # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T +1C34..1C35 ; Other_Alphabetic # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG +1C36 ; Other_Alphabetic # Mn LEPCHA SIGN RAN +1DD3..1DF4 ; Other_Alphabetic # Mn [34] COMBINING LATIN SMALL LETTER FLATTENED OPEN A ABOVE..COMBINING LATIN SMALL LETTER U WITH DIAERESIS +24B6..24E9 ; Other_Alphabetic # So [52] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN SMALL LETTER Z +2DE0..2DFF ; Other_Alphabetic # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS +A674..A67B ; Other_Alphabetic # Mn [8] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC LETTER OMEGA +A69E..A69F ; Other_Alphabetic # Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E +A802 ; Other_Alphabetic # Mn SYLOTI NAGRI SIGN DVISVARA +A80B ; Other_Alphabetic # Mn SYLOTI NAGRI SIGN ANUSVARA +A823..A824 ; Other_Alphabetic # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I +A825..A826 ; Other_Alphabetic # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E +A827 ; Other_Alphabetic # Mc SYLOTI NAGRI VOWEL SIGN OO +A880..A881 ; Other_Alphabetic # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA +A8B4..A8C3 ; Other_Alphabetic # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU +A8C5 ; Other_Alphabetic # Mn SAURASHTRA SIGN CANDRABINDU +A8FF ; Other_Alphabetic # Mn DEVANAGARI VOWEL SIGN AY +A926..A92A ; Other_Alphabetic # Mn [5] KAYAH LI VOWEL UE..KAYAH LI VOWEL O +A947..A951 ; Other_Alphabetic # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R +A952 ; Other_Alphabetic # Mc REJANG CONSONANT SIGN H +A980..A982 ; Other_Alphabetic # Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR +A983 ; Other_Alphabetic # Mc JAVANESE SIGN WIGNYAN +A9B4..A9B5 ; Other_Alphabetic # Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG +A9B6..A9B9 ; Other_Alphabetic # Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT +A9BA..A9BB ; Other_Alphabetic # Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE +A9BC..A9BD ; Other_Alphabetic # Mn [2] JAVANESE VOWEL SIGN PEPET..JAVANESE CONSONANT SIGN KERET +A9BE..A9BF ; Other_Alphabetic # Mc [2] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE CONSONANT SIGN CAKRA +A9E5 ; Other_Alphabetic # Mn MYANMAR SIGN SHAN SAW +AA29..AA2E ; Other_Alphabetic # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE +AA2F..AA30 ; Other_Alphabetic # Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI +AA31..AA32 ; Other_Alphabetic # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE +AA33..AA34 ; Other_Alphabetic # Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA +AA35..AA36 ; Other_Alphabetic # Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA +AA43 ; Other_Alphabetic # Mn CHAM CONSONANT SIGN FINAL NG +AA4C ; Other_Alphabetic # Mn CHAM CONSONANT SIGN FINAL M +AA4D ; Other_Alphabetic # Mc CHAM CONSONANT SIGN FINAL H +AA7B ; Other_Alphabetic # Mc MYANMAR SIGN PAO KAREN TONE +AA7C ; Other_Alphabetic # Mn MYANMAR SIGN TAI LAING TONE-2 +AA7D ; Other_Alphabetic # Mc MYANMAR SIGN TAI LAING TONE-5 +AAB0 ; Other_Alphabetic # Mn TAI VIET MAI KANG +AAB2..AAB4 ; Other_Alphabetic # Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U +AAB7..AAB8 ; Other_Alphabetic # Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA +AABE ; Other_Alphabetic # Mn TAI VIET VOWEL AM +AAEB ; Other_Alphabetic # Mc MEETEI MAYEK VOWEL SIGN II +AAEC..AAED ; Other_Alphabetic # Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI +AAEE..AAEF ; Other_Alphabetic # Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU +AAF5 ; Other_Alphabetic # Mc MEETEI MAYEK VOWEL SIGN VISARGA +ABE3..ABE4 ; Other_Alphabetic # Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP +ABE5 ; Other_Alphabetic # Mn MEETEI MAYEK VOWEL SIGN ANAP +ABE6..ABE7 ; Other_Alphabetic # Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP +ABE8 ; Other_Alphabetic # Mn MEETEI MAYEK VOWEL SIGN UNAP +ABE9..ABEA ; Other_Alphabetic # Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG +FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA +10376..1037A ; Other_Alphabetic # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII +10A01..10A03 ; Other_Alphabetic # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R +10A05..10A06 ; Other_Alphabetic # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O +10A0C..10A0F ; Other_Alphabetic # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA +10D24..10D27 ; Other_Alphabetic # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI +10D69 ; Other_Alphabetic # Mn GARAY VOWEL SIGN E +10EAB..10EAC ; Other_Alphabetic # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK +10EFA..10EFC ; Other_Alphabetic # Mn [3] ARABIC DOUBLE VERTICAL BAR BELOW..ARABIC COMBINING ALEF OVERLAY +11000 ; Other_Alphabetic # Mc BRAHMI SIGN CANDRABINDU +11001 ; Other_Alphabetic # Mn BRAHMI SIGN ANUSVARA +11002 ; Other_Alphabetic # Mc BRAHMI SIGN VISARGA +11038..11045 ; Other_Alphabetic # Mn [14] BRAHMI VOWEL SIGN AA..BRAHMI VOWEL SIGN AU +11073..11074 ; Other_Alphabetic # Mn [2] BRAHMI VOWEL SIGN OLD TAMIL SHORT E..BRAHMI VOWEL SIGN OLD TAMIL SHORT O +11080..11081 ; Other_Alphabetic # Mn [2] KAITHI SIGN CANDRABINDU..KAITHI SIGN ANUSVARA +11082 ; Other_Alphabetic # Mc KAITHI SIGN VISARGA +110B0..110B2 ; Other_Alphabetic # Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II +110B3..110B6 ; Other_Alphabetic # Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI +110B7..110B8 ; Other_Alphabetic # Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU +110C2 ; Other_Alphabetic # Mn KAITHI VOWEL SIGN VOCALIC R +11100..11102 ; Other_Alphabetic # Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA +11127..1112B ; Other_Alphabetic # Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU +1112C ; Other_Alphabetic # Mc CHAKMA VOWEL SIGN E +1112D..11132 ; Other_Alphabetic # Mn [6] CHAKMA VOWEL SIGN AI..CHAKMA AU MARK +11145..11146 ; Other_Alphabetic # Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI +11180..11181 ; Other_Alphabetic # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA +11182 ; Other_Alphabetic # Mc SHARADA SIGN VISARGA +111B3..111B5 ; Other_Alphabetic # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II +111B6..111BE ; Other_Alphabetic # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O +111BF ; Other_Alphabetic # Mc SHARADA VOWEL SIGN AU +111CE ; Other_Alphabetic # Mc SHARADA VOWEL SIGN PRISHTHAMATRA E +111CF ; Other_Alphabetic # Mn SHARADA SIGN INVERTED CANDRABINDU +1122C..1122E ; Other_Alphabetic # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II +1122F..11231 ; Other_Alphabetic # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI +11232..11233 ; Other_Alphabetic # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU +11234 ; Other_Alphabetic # Mn KHOJKI SIGN ANUSVARA +11237 ; Other_Alphabetic # Mn KHOJKI SIGN SHADDA +1123E ; Other_Alphabetic # Mn KHOJKI SIGN SUKUN +11241 ; Other_Alphabetic # Mn KHOJKI VOWEL SIGN VOCALIC R +112DF ; Other_Alphabetic # Mn KHUDAWADI SIGN ANUSVARA +112E0..112E2 ; Other_Alphabetic # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II +112E3..112E8 ; Other_Alphabetic # Mn [6] KHUDAWADI VOWEL SIGN U..KHUDAWADI VOWEL SIGN AU +11300..11301 ; Other_Alphabetic # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU +11302..11303 ; Other_Alphabetic # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA +1133E..1133F ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I +11340 ; Other_Alphabetic # Mn GRANTHA VOWEL SIGN II +11341..11344 ; Other_Alphabetic # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR +11347..11348 ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI +1134B..1134C ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN OO..GRANTHA VOWEL SIGN AU +11357 ; Other_Alphabetic # Mc GRANTHA AU LENGTH MARK +11362..11363 ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +113B8..113BA ; Other_Alphabetic # Mc [3] TULU-TIGALARI VOWEL SIGN AA..TULU-TIGALARI VOWEL SIGN II +113BB..113C0 ; Other_Alphabetic # Mn [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL +113C2 ; Other_Alphabetic # Mc TULU-TIGALARI VOWEL SIGN EE +113C5 ; Other_Alphabetic # Mc TULU-TIGALARI VOWEL SIGN AI +113C7..113CA ; Other_Alphabetic # Mc [4] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI SIGN CANDRA ANUNASIKA +113CC..113CD ; Other_Alphabetic # Mc [2] TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI SIGN VISARGA +11435..11437 ; Other_Alphabetic # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II +11438..1143F ; Other_Alphabetic # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI +11440..11441 ; Other_Alphabetic # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU +11443..11444 ; Other_Alphabetic # Mn [2] NEWA SIGN CANDRABINDU..NEWA SIGN ANUSVARA +11445 ; Other_Alphabetic # Mc NEWA SIGN VISARGA +114B0..114B2 ; Other_Alphabetic # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II +114B3..114B8 ; Other_Alphabetic # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL +114B9 ; Other_Alphabetic # Mc TIRHUTA VOWEL SIGN E +114BA ; Other_Alphabetic # Mn TIRHUTA VOWEL SIGN SHORT E +114BB..114BE ; Other_Alphabetic # Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU +114BF..114C0 ; Other_Alphabetic # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA +114C1 ; Other_Alphabetic # Mc TIRHUTA SIGN VISARGA +115AF..115B1 ; Other_Alphabetic # Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II +115B2..115B5 ; Other_Alphabetic # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR +115B8..115BB ; Other_Alphabetic # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU +115BC..115BD ; Other_Alphabetic # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA +115BE ; Other_Alphabetic # Mc SIDDHAM SIGN VISARGA +115DC..115DD ; Other_Alphabetic # Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU +11630..11632 ; Other_Alphabetic # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II +11633..1163A ; Other_Alphabetic # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI +1163B..1163C ; Other_Alphabetic # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU +1163D ; Other_Alphabetic # Mn MODI SIGN ANUSVARA +1163E ; Other_Alphabetic # Mc MODI SIGN VISARGA +11640 ; Other_Alphabetic # Mn MODI SIGN ARDHACANDRA +116AB ; Other_Alphabetic # Mn TAKRI SIGN ANUSVARA +116AC ; Other_Alphabetic # Mc TAKRI SIGN VISARGA +116AD ; Other_Alphabetic # Mn TAKRI VOWEL SIGN AA +116AE..116AF ; Other_Alphabetic # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II +116B0..116B5 ; Other_Alphabetic # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU +1171D ; Other_Alphabetic # Mn AHOM CONSONANT SIGN MEDIAL LA +1171E ; Other_Alphabetic # Mc AHOM CONSONANT SIGN MEDIAL RA +1171F ; Other_Alphabetic # Mn AHOM CONSONANT SIGN MEDIAL LIGATING RA +11720..11721 ; Other_Alphabetic # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA +11722..11725 ; Other_Alphabetic # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU +11726 ; Other_Alphabetic # Mc AHOM VOWEL SIGN E +11727..1172A ; Other_Alphabetic # Mn [4] AHOM VOWEL SIGN AW..AHOM VOWEL SIGN AM +1182C..1182E ; Other_Alphabetic # Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II +1182F..11837 ; Other_Alphabetic # Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA +11838 ; Other_Alphabetic # Mc DOGRA SIGN VISARGA +11930..11935 ; Other_Alphabetic # Mc [6] DIVES AKURU VOWEL SIGN AA..DIVES AKURU VOWEL SIGN E +11937..11938 ; Other_Alphabetic # Mc [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O +1193B..1193C ; Other_Alphabetic # Mn [2] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN CANDRABINDU +11940 ; Other_Alphabetic # Mc DIVES AKURU MEDIAL YA +11942 ; Other_Alphabetic # Mc DIVES AKURU MEDIAL RA +119D1..119D3 ; Other_Alphabetic # Mc [3] NANDINAGARI VOWEL SIGN AA..NANDINAGARI VOWEL SIGN II +119D4..119D7 ; Other_Alphabetic # Mn [4] NANDINAGARI VOWEL SIGN U..NANDINAGARI VOWEL SIGN VOCALIC RR +119DA..119DB ; Other_Alphabetic # Mn [2] NANDINAGARI VOWEL SIGN E..NANDINAGARI VOWEL SIGN AI +119DC..119DF ; Other_Alphabetic # Mc [4] NANDINAGARI VOWEL SIGN O..NANDINAGARI SIGN VISARGA +119E4 ; Other_Alphabetic # Mc NANDINAGARI VOWEL SIGN PRISHTHAMATRA E +11A01..11A0A ; Other_Alphabetic # Mn [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK +11A35..11A38 ; Other_Alphabetic # Mn [4] ZANABAZAR SQUARE SIGN CANDRABINDU..ZANABAZAR SQUARE SIGN ANUSVARA +11A39 ; Other_Alphabetic # Mc ZANABAZAR SQUARE SIGN VISARGA +11A3B..11A3E ; Other_Alphabetic # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA +11A51..11A56 ; Other_Alphabetic # Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE +11A57..11A58 ; Other_Alphabetic # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU +11A59..11A5B ; Other_Alphabetic # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK +11A8A..11A96 ; Other_Alphabetic # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA +11A97 ; Other_Alphabetic # Mc SOYOMBO SIGN VISARGA +11B60 ; Other_Alphabetic # Mn SHARADA VOWEL SIGN OE +11B61 ; Other_Alphabetic # Mc SHARADA VOWEL SIGN OOE +11B62..11B64 ; Other_Alphabetic # Mn [3] SHARADA VOWEL SIGN UE..SHARADA VOWEL SIGN SHORT E +11B65 ; Other_Alphabetic # Mc SHARADA VOWEL SIGN SHORT O +11B66 ; Other_Alphabetic # Mn SHARADA VOWEL SIGN CANDRA E +11B67 ; Other_Alphabetic # Mc SHARADA VOWEL SIGN CANDRA O +11C2F ; Other_Alphabetic # Mc BHAIKSUKI VOWEL SIGN AA +11C30..11C36 ; Other_Alphabetic # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L +11C38..11C3D ; Other_Alphabetic # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA +11C3E ; Other_Alphabetic # Mc BHAIKSUKI SIGN VISARGA +11C92..11CA7 ; Other_Alphabetic # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA +11CA9 ; Other_Alphabetic # Mc MARCHEN SUBJOINED LETTER YA +11CAA..11CB0 ; Other_Alphabetic # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA +11CB1 ; Other_Alphabetic # Mc MARCHEN VOWEL SIGN I +11CB2..11CB3 ; Other_Alphabetic # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E +11CB4 ; Other_Alphabetic # Mc MARCHEN VOWEL SIGN O +11CB5..11CB6 ; Other_Alphabetic # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU +11D31..11D36 ; Other_Alphabetic # Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R +11D3A ; Other_Alphabetic # Mn MASARAM GONDI VOWEL SIGN E +11D3C..11D3D ; Other_Alphabetic # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O +11D3F..11D41 ; Other_Alphabetic # Mn [3] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI SIGN VISARGA +11D43 ; Other_Alphabetic # Mn MASARAM GONDI SIGN CANDRA +11D47 ; Other_Alphabetic # Mn MASARAM GONDI RA-KARA +11D8A..11D8E ; Other_Alphabetic # Mc [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU +11D90..11D91 ; Other_Alphabetic # Mn [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI +11D93..11D94 ; Other_Alphabetic # Mc [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU +11D95 ; Other_Alphabetic # Mn GUNJALA GONDI SIGN ANUSVARA +11D96 ; Other_Alphabetic # Mc GUNJALA GONDI SIGN VISARGA +11EF3..11EF4 ; Other_Alphabetic # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U +11EF5..11EF6 ; Other_Alphabetic # Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O +11F00..11F01 ; Other_Alphabetic # Mn [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA +11F03 ; Other_Alphabetic # Mc KAWI SIGN VISARGA +11F34..11F35 ; Other_Alphabetic # Mc [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA +11F36..11F3A ; Other_Alphabetic # Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R +11F3E..11F3F ; Other_Alphabetic # Mc [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI +11F40 ; Other_Alphabetic # Mn KAWI VOWEL SIGN EU +1611E..16129 ; Other_Alphabetic # Mn [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK +1612A..1612C ; Other_Alphabetic # Mc [3] GURUNG KHEMA CONSONANT SIGN MEDIAL YA..GURUNG KHEMA CONSONANT SIGN MEDIAL HA +1612D..1612E ; Other_Alphabetic # Mn [2] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA CONSONANT SIGN MEDIAL RA +16F4F ; Other_Alphabetic # Mn MIAO SIGN CONSONANT MODIFIER BAR +16F51..16F87 ; Other_Alphabetic # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI +16F8F..16F92 ; Other_Alphabetic # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW +16FF0..16FF1 ; Other_Alphabetic # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY +1BC9E ; Other_Alphabetic # Mn DUPLOYAN DOUBLE MARK +1E000..1E006 ; Other_Alphabetic # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE +1E008..1E018 ; Other_Alphabetic # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU +1E01B..1E021 ; Other_Alphabetic # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI +1E023..1E024 ; Other_Alphabetic # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS +1E026..1E02A ; Other_Alphabetic # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA +1E08F ; Other_Alphabetic # Mn COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I +1E6E3 ; Other_Alphabetic # Mn TAI YO SIGN UE +1E6E6 ; Other_Alphabetic # Mn TAI YO SIGN AU +1E6EE..1E6EF ; Other_Alphabetic # Mn [2] TAI YO SIGN AY..TAI YO SIGN ANG +1E6F5 ; Other_Alphabetic # Mn TAI YO SIGN OM +1E947 ; Other_Alphabetic # Mn ADLAM HAMZA +1F130..1F149 ; Other_Alphabetic # So [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z +1F150..1F169 ; Other_Alphabetic # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z +1F170..1F189 ; Other_Alphabetic # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z + +# Total code points: 1510 + +# ================================================ + +3006 ; Ideographic # Lo IDEOGRAPHIC CLOSING MARK +3007 ; Ideographic # Nl IDEOGRAPHIC NUMBER ZERO +3021..3029 ; Ideographic # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE +3038..303A ; Ideographic # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY +3400..4DBF ; Ideographic # Lo [6592] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DBF +4E00..9FFF ; Ideographic # Lo [20992] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFF +F900..FA6D ; Ideographic # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D +FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9 +16FE4 ; Ideographic # Mn KHITAN SMALL SCRIPT FILLER +16FF2..16FF3 ; Ideographic # Lm [2] CHINESE SMALL SIMPLIFIED ER..CHINESE SMALL TRADITIONAL ER +16FF4..16FF6 ; Ideographic # Nl [3] YANGQIN SIGN SLOW ONE BEAT..YANGQIN SIGN SLOW TWO BEATS +17000..18CD5 ; Ideographic # Lo [7382] TANGUT IDEOGRAPH-17000..KHITAN SMALL SCRIPT CHARACTER-18CD5 +18CFF..18D1E ; Ideographic # Lo [32] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D1E +18D80..18DF2 ; Ideographic # Lo [115] TANGUT COMPONENT-769..TANGUT COMPONENT-883 +1B170..1B2FB ; Ideographic # Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB +20000..2A6DF ; Ideographic # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF +2A700..2B81D ; Ideographic # Lo [4382] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B81D +2B820..2CEAD ; Ideographic # Lo [5774] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEAD +2CEB0..2EBE0 ; Ideographic # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 +2EBF0..2EE5D ; Ideographic # Lo [622] CJK UNIFIED IDEOGRAPH-2EBF0..CJK UNIFIED IDEOGRAPH-2EE5D +2F800..2FA1D ; Ideographic # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D +30000..3134A ; Ideographic # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A +31350..33479 ; Ideographic # Lo [8490] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-33479 + +# Total code points: 110943 + +# ================================================ + +005E ; Diacritic # Sk CIRCUMFLEX ACCENT +0060 ; Diacritic # Sk GRAVE ACCENT +00A8 ; Diacritic # Sk DIAERESIS +00AF ; Diacritic # Sk MACRON +00B4 ; Diacritic # Sk ACUTE ACCENT +00B7 ; Diacritic # Po MIDDLE DOT +00B8 ; Diacritic # Sk CEDILLA +02B0..02C1 ; Diacritic # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP +02C2..02C5 ; Diacritic # Sk [4] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER DOWN ARROWHEAD +02C6..02D1 ; Diacritic # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON +02D2..02DF ; Diacritic # Sk [14] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER CROSS ACCENT +02E0..02E4 ; Diacritic # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP +02E5..02EB ; Diacritic # Sk [7] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER YANG DEPARTING TONE MARK +02EC ; Diacritic # Lm MODIFIER LETTER VOICING +02ED ; Diacritic # Sk MODIFIER LETTER UNASPIRATED +02EE ; Diacritic # Lm MODIFIER LETTER DOUBLE APOSTROPHE +02EF..02FF ; Diacritic # Sk [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW +0300..034E ; Diacritic # Mn [79] COMBINING GRAVE ACCENT..COMBINING UPWARDS ARROW BELOW +0350..0357 ; Diacritic # Mn [8] COMBINING RIGHT ARROWHEAD ABOVE..COMBINING RIGHT HALF RING ABOVE +035D..0362 ; Diacritic # Mn [6] COMBINING DOUBLE BREVE..COMBINING DOUBLE RIGHTWARDS ARROW BELOW +0374 ; Diacritic # Lm GREEK NUMERAL SIGN +0375 ; Diacritic # Sk GREEK LOWER NUMERAL SIGN +037A ; Diacritic # Lm GREEK YPOGEGRAMMENI +0384..0385 ; Diacritic # Sk [2] GREEK TONOS..GREEK DIALYTIKA TONOS +0483..0487 ; Diacritic # Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE +0559 ; Diacritic # Lm ARMENIAN MODIFIER LETTER LEFT HALF RING +0591..05BD ; Diacritic # Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG +05BF ; Diacritic # Mn HEBREW POINT RAFE +05C1..05C2 ; Diacritic # Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT +05C4..05C5 ; Diacritic # Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT +05C7 ; Diacritic # Mn HEBREW POINT QAMATS QATAN +064B..0652 ; Diacritic # Mn [8] ARABIC FATHATAN..ARABIC SUKUN +0657..0658 ; Diacritic # Mn [2] ARABIC INVERTED DAMMA..ARABIC MARK NOON GHUNNA +06DF..06E0 ; Diacritic # Mn [2] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO +06E5..06E6 ; Diacritic # Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH +06EA..06EC ; Diacritic # Mn [3] ARABIC EMPTY CENTRE LOW STOP..ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE +0730..074A ; Diacritic # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH +07A6..07B0 ; Diacritic # Mn [11] THAANA ABAFILI..THAANA SUKUN +07EB..07F3 ; Diacritic # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE +07F4..07F5 ; Diacritic # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE +0818..0819 ; Diacritic # Mn [2] SAMARITAN MARK OCCLUSION..SAMARITAN MARK DAGESH +0898..089F ; Diacritic # Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA +08C9 ; Diacritic # Lm ARABIC SMALL FARSI YEH +08CA..08D2 ; Diacritic # Mn [9] ARABIC SMALL HIGH FARSI YEH..ARABIC LARGE ROUND DOT INSIDE CIRCLE BELOW +08E3..08FE ; Diacritic # Mn [28] ARABIC TURNED DAMMA BELOW..ARABIC DAMMA WITH DOT +093C ; Diacritic # Mn DEVANAGARI SIGN NUKTA +094D ; Diacritic # Mn DEVANAGARI SIGN VIRAMA +0951..0954 ; Diacritic # Mn [4] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI ACUTE ACCENT +0971 ; Diacritic # Lm DEVANAGARI SIGN HIGH SPACING DOT +09BC ; Diacritic # Mn BENGALI SIGN NUKTA +09CD ; Diacritic # Mn BENGALI SIGN VIRAMA +0A3C ; Diacritic # Mn GURMUKHI SIGN NUKTA +0A4D ; Diacritic # Mn GURMUKHI SIGN VIRAMA +0ABC ; Diacritic # Mn GUJARATI SIGN NUKTA +0ACD ; Diacritic # Mn GUJARATI SIGN VIRAMA +0AFD..0AFF ; Diacritic # Mn [3] GUJARATI SIGN THREE-DOT NUKTA ABOVE..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE +0B3C ; Diacritic # Mn ORIYA SIGN NUKTA +0B4D ; Diacritic # Mn ORIYA SIGN VIRAMA +0B55 ; Diacritic # Mn ORIYA SIGN OVERLINE +0BCD ; Diacritic # Mn TAMIL SIGN VIRAMA +0C3C ; Diacritic # Mn TELUGU SIGN NUKTA +0C4D ; Diacritic # Mn TELUGU SIGN VIRAMA +0CBC ; Diacritic # Mn KANNADA SIGN NUKTA +0CCD ; Diacritic # Mn KANNADA SIGN VIRAMA +0D3B..0D3C ; Diacritic # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA +0D4D ; Diacritic # Mn MALAYALAM SIGN VIRAMA +0DCA ; Diacritic # Mn SINHALA SIGN AL-LAKUNA +0E3A ; Diacritic # Mn THAI CHARACTER PHINTHU +0E47..0E4C ; Diacritic # Mn [6] THAI CHARACTER MAITAIKHU..THAI CHARACTER THANTHAKHAT +0E4E ; Diacritic # Mn THAI CHARACTER YAMAKKAN +0EBA ; Diacritic # Mn LAO SIGN PALI VIRAMA +0EC8..0ECC ; Diacritic # Mn [5] LAO TONE MAI EK..LAO CANCELLATION MARK +0F18..0F19 ; Diacritic # Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS +0F35 ; Diacritic # Mn TIBETAN MARK NGAS BZUNG NYI ZLA +0F37 ; Diacritic # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS +0F39 ; Diacritic # Mn TIBETAN MARK TSA -PHRU +0F3E..0F3F ; Diacritic # Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES +0F82..0F84 ; Diacritic # Mn [3] TIBETAN SIGN NYI ZLA NAA DA..TIBETAN MARK HALANTA +0F86..0F87 ; Diacritic # Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS +0FC6 ; Diacritic # Mn TIBETAN SYMBOL PADMA GDAN +1037 ; Diacritic # Mn MYANMAR SIGN DOT BELOW +1039..103A ; Diacritic # Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT +1063..1064 ; Diacritic # Mc [2] MYANMAR TONE MARK SGAW KAREN HATHI..MYANMAR TONE MARK SGAW KAREN KE PHO +1069..106D ; Diacritic # Mc [5] MYANMAR SIGN WESTERN PWO KAREN TONE-1..MYANMAR SIGN WESTERN PWO KAREN TONE-5 +1087..108C ; Diacritic # Mc [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3 +108D ; Diacritic # Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE +108F ; Diacritic # Mc MYANMAR SIGN RUMAI PALAUNG TONE-5 +109A..109B ; Diacritic # Mc [2] MYANMAR SIGN KHAMTI TONE-1..MYANMAR SIGN KHAMTI TONE-3 +135D..135F ; Diacritic # Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK +1714 ; Diacritic # Mn TAGALOG SIGN VIRAMA +1715 ; Diacritic # Mc TAGALOG SIGN PAMUDPOD +1734 ; Diacritic # Mc HANUNOO SIGN PAMUDPOD +17C9..17D3 ; Diacritic # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT +17DD ; Diacritic # Mn KHMER SIGN ATTHACAN +1939..193B ; Diacritic # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I +1A60 ; Diacritic # Mn TAI THAM SIGN SAKOT +1A75..1A7C ; Diacritic # Mn [8] TAI THAM SIGN TONE-1..TAI THAM SIGN KHUEN-LUE KARAN +1A7F ; Diacritic # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT +1AB0..1ABD ; Diacritic # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW +1ABE ; Diacritic # Me COMBINING PARENTHESES OVERLAY +1AC1..1ACB ; Diacritic # Mn [11] COMBINING LEFT PARENTHESIS ABOVE LEFT..COMBINING TRIPLE ACUTE ACCENT +1ACF..1ADD ; Diacritic # Mn [15] COMBINING DOUBLE CARON..COMBINING DOT-AND-RING BELOW +1AE0..1AEB ; Diacritic # Mn [12] COMBINING LEFT TACK ABOVE..COMBINING DOUBLE RIGHTWARDS ARROW ABOVE +1B34 ; Diacritic # Mn BALINESE SIGN REREKAN +1B44 ; Diacritic # Mc BALINESE ADEG ADEG +1B6B..1B73 ; Diacritic # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG +1BAA ; Diacritic # Mc SUNDANESE SIGN PAMAAEH +1BAB ; Diacritic # Mn SUNDANESE SIGN VIRAMA +1BE6 ; Diacritic # Mn BATAK SIGN TOMPI +1BF2..1BF3 ; Diacritic # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN +1C36..1C37 ; Diacritic # Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA +1C78..1C7D ; Diacritic # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD +1CD0..1CD2 ; Diacritic # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA +1CD3 ; Diacritic # Po VEDIC SIGN NIHSHVASA +1CD4..1CE0 ; Diacritic # Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA +1CE1 ; Diacritic # Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA +1CE2..1CE8 ; Diacritic # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL +1CED ; Diacritic # Mn VEDIC SIGN TIRYAK +1CF4 ; Diacritic # Mn VEDIC TONE CANDRA ABOVE +1CF7 ; Diacritic # Mc VEDIC SIGN ATIKRAMA +1CF8..1CF9 ; Diacritic # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE +1D2C..1D6A ; Diacritic # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI +1D9B..1DBE ; Diacritic # Lm [36] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL EZH +1DC4..1DCF ; Diacritic # Mn [12] COMBINING MACRON-ACUTE..COMBINING ZIGZAG BELOW +1DF5..1DFF ; Diacritic # Mn [11] COMBINING UP TACK ABOVE..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +1FBD ; Diacritic # Sk GREEK KORONIS +1FBF..1FC1 ; Diacritic # Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI +1FCD..1FCF ; Diacritic # Sk [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI +1FDD..1FDF ; Diacritic # Sk [3] GREEK DASIA AND VARIA..GREEK DASIA AND PERISPOMENI +1FED..1FEF ; Diacritic # Sk [3] GREEK DIALYTIKA AND VARIA..GREEK VARIA +1FFD..1FFE ; Diacritic # Sk [2] GREEK OXIA..GREEK DASIA +2CEF..2CF1 ; Diacritic # Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS +2E2F ; Diacritic # Lm VERTICAL TILDE +302A..302D ; Diacritic # Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK +302E..302F ; Diacritic # Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK +3099..309A ; Diacritic # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +309B..309C ; Diacritic # Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +30FC ; Diacritic # Lm KATAKANA-HIRAGANA PROLONGED SOUND MARK +A66F ; Diacritic # Mn COMBINING CYRILLIC VZMET +A67C..A67D ; Diacritic # Mn [2] COMBINING CYRILLIC KAVYKA..COMBINING CYRILLIC PAYEROK +A67F ; Diacritic # Lm CYRILLIC PAYEROK +A69C..A69D ; Diacritic # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN +A6F0..A6F1 ; Diacritic # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS +A700..A716 ; Diacritic # Sk [23] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR +A717..A71F ; Diacritic # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK +A720..A721 ; Diacritic # Sk [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE +A788 ; Diacritic # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT +A789..A78A ; Diacritic # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN +A7F1 ; Diacritic # Lm MODIFIER LETTER CAPITAL S +A7F8..A7F9 ; Diacritic # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE +A806 ; Diacritic # Mn SYLOTI NAGRI SIGN HASANTA +A82C ; Diacritic # Mn SYLOTI NAGRI SIGN ALTERNATE HASANTA +A8C4 ; Diacritic # Mn SAURASHTRA SIGN VIRAMA +A8E0..A8F1 ; Diacritic # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA +A92B..A92D ; Diacritic # Mn [3] KAYAH LI TONE PLOPHU..KAYAH LI TONE CALYA PLOPHU +A92E ; Diacritic # Po KAYAH LI SIGN CWI +A953 ; Diacritic # Mc REJANG VIRAMA +A9B3 ; Diacritic # Mn JAVANESE SIGN CECAK TELU +A9C0 ; Diacritic # Mc JAVANESE PANGKON +A9E5 ; Diacritic # Mn MYANMAR SIGN SHAN SAW +AA7B ; Diacritic # Mc MYANMAR SIGN PAO KAREN TONE +AA7C ; Diacritic # Mn MYANMAR SIGN TAI LAING TONE-2 +AA7D ; Diacritic # Mc MYANMAR SIGN TAI LAING TONE-5 +AABF ; Diacritic # Mn TAI VIET TONE MAI EK +AAC0 ; Diacritic # Lo TAI VIET TONE MAI NUENG +AAC1 ; Diacritic # Mn TAI VIET TONE MAI THO +AAC2 ; Diacritic # Lo TAI VIET TONE MAI SONG +AAF6 ; Diacritic # Mn MEETEI MAYEK VIRAMA +AB5B ; Diacritic # Sk MODIFIER BREVE WITH INVERTED BREVE +AB5C..AB5F ; Diacritic # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK +AB69 ; Diacritic # Lm MODIFIER LETTER SMALL TURNED W +AB6A..AB6B ; Diacritic # Sk [2] MODIFIER LETTER LEFT TACK..MODIFIER LETTER RIGHT TACK +ABEC ; Diacritic # Mc MEETEI MAYEK LUM IYEK +ABED ; Diacritic # Mn MEETEI MAYEK APUN IYEK +FB1E ; Diacritic # Mn HEBREW POINT JUDEO-SPANISH VARIKA +FE20..FE2F ; Diacritic # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF +FF3E ; Diacritic # Sk FULLWIDTH CIRCUMFLEX ACCENT +FF40 ; Diacritic # Sk FULLWIDTH GRAVE ACCENT +FF70 ; Diacritic # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK +FF9E..FF9F ; Diacritic # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK +FFE3 ; Diacritic # Sk FULLWIDTH MACRON +102E0 ; Diacritic # Mn COPTIC EPACT THOUSANDS MARK +10780..10785 ; Diacritic # Lm [6] MODIFIER LETTER SMALL CAPITAL AA..MODIFIER LETTER SMALL B WITH HOOK +10787..107B0 ; Diacritic # Lm [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK +107B2..107BA ; Diacritic # Lm [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL +10A38..10A3A ; Diacritic # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW +10A3F ; Diacritic # Mn KHAROSHTHI VIRAMA +10AE5..10AE6 ; Diacritic # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW +10D22..10D23 ; Diacritic # Lo [2] HANIFI ROHINGYA MARK SAKIN..HANIFI ROHINGYA MARK NA KHONNA +10D24..10D27 ; Diacritic # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI +10D4E ; Diacritic # Lm GARAY VOWEL LENGTH MARK +10D69..10D6D ; Diacritic # Mn [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK +10EFA ; Diacritic # Mn ARABIC DOUBLE VERTICAL BAR BELOW +10EFD..10EFF ; Diacritic # Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA +10F46..10F50 ; Diacritic # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW +10F82..10F85 ; Diacritic # Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW +11046 ; Diacritic # Mn BRAHMI VIRAMA +11070 ; Diacritic # Mn BRAHMI SIGN OLD TAMIL VIRAMA +110B9..110BA ; Diacritic # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA +11133..11134 ; Diacritic # Mn [2] CHAKMA VIRAMA..CHAKMA MAAYYAA +11173 ; Diacritic # Mn MAHAJANI SIGN NUKTA +111C0 ; Diacritic # Mc SHARADA SIGN VIRAMA +111CA..111CC ; Diacritic # Mn [3] SHARADA SIGN NUKTA..SHARADA EXTRA SHORT VOWEL MARK +11235 ; Diacritic # Mc KHOJKI SIGN VIRAMA +11236 ; Diacritic # Mn KHOJKI SIGN NUKTA +112E9..112EA ; Diacritic # Mn [2] KHUDAWADI SIGN NUKTA..KHUDAWADI SIGN VIRAMA +1133B..1133C ; Diacritic # Mn [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA +1134D ; Diacritic # Mc GRANTHA SIGN VIRAMA +11366..1136C ; Diacritic # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX +11370..11374 ; Diacritic # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +113CE ; Diacritic # Mn TULU-TIGALARI SIGN VIRAMA +113CF ; Diacritic # Mc TULU-TIGALARI SIGN LOOPED VIRAMA +113D0 ; Diacritic # Mn TULU-TIGALARI CONJOINER +113D2 ; Diacritic # Mn TULU-TIGALARI GEMINATION MARK +113D3 ; Diacritic # Lo TULU-TIGALARI SIGN PLUTA +113E1..113E2 ; Diacritic # Mn [2] TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA +11442 ; Diacritic # Mn NEWA SIGN VIRAMA +11446 ; Diacritic # Mn NEWA SIGN NUKTA +114C2..114C3 ; Diacritic # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA +115BF..115C0 ; Diacritic # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA +1163F ; Diacritic # Mn MODI SIGN VIRAMA +116B6 ; Diacritic # Mc TAKRI SIGN VIRAMA +116B7 ; Diacritic # Mn TAKRI SIGN NUKTA +1172B ; Diacritic # Mn AHOM SIGN KILLER +11839..1183A ; Diacritic # Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA +1193D ; Diacritic # Mc DIVES AKURU SIGN HALANTA +1193E ; Diacritic # Mn DIVES AKURU VIRAMA +11943 ; Diacritic # Mn DIVES AKURU SIGN NUKTA +119E0 ; Diacritic # Mn NANDINAGARI SIGN VIRAMA +11A34 ; Diacritic # Mn ZANABAZAR SQUARE SIGN VIRAMA +11A47 ; Diacritic # Mn ZANABAZAR SQUARE SUBJOINER +11A99 ; Diacritic # Mn SOYOMBO SUBJOINER +11C3F ; Diacritic # Mn BHAIKSUKI SIGN VIRAMA +11D42 ; Diacritic # Mn MASARAM GONDI SIGN NUKTA +11D44..11D45 ; Diacritic # Mn [2] MASARAM GONDI SIGN HALANTA..MASARAM GONDI VIRAMA +11D97 ; Diacritic # Mn GUNJALA GONDI VIRAMA +11DD9 ; Diacritic # Lm TOLONG SIKI SIGN SELA +11F41 ; Diacritic # Mc KAWI SIGN KILLER +11F42 ; Diacritic # Mn KAWI CONJOINER +11F5A ; Diacritic # Mn KAWI SIGN NUKTA +13447..13455 ; Diacritic # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED +1612F ; Diacritic # Mn GURUNG KHEMA SIGN THOLHOMA +16AF0..16AF4 ; Diacritic # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE +16B30..16B36 ; Diacritic # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM +16D6B..16D6C ; Diacritic # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT +16F8F..16F92 ; Diacritic # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW +16F93..16F9F ; Diacritic # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 +16FF0..16FF1 ; Diacritic # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY +1AFF0..1AFF3 ; Diacritic # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 +1AFF5..1AFFB ; Diacritic # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 +1AFFD..1AFFE ; Diacritic # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 +1CF00..1CF2D ; Diacritic # Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT +1CF30..1CF46 ; Diacritic # Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG +1D167..1D169 ; Diacritic # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 +1D16D..1D172 ; Diacritic # Mc [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5 +1D17B..1D182 ; Diacritic # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE +1D185..1D18B ; Diacritic # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE +1D1AA..1D1AD ; Diacritic # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO +1E030..1E06D ; Diacritic # Lm [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE +1E130..1E136 ; Diacritic # Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D +1E2AE ; Diacritic # Mn TOTO SIGN RISING TONE +1E2EC..1E2EF ; Diacritic # Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI +1E5EE..1E5EF ; Diacritic # Mn [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR +1E8D0..1E8D6 ; Diacritic # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS +1E944..1E946 ; Diacritic # Mn [3] ADLAM ALIF LENGTHENER..ADLAM GEMINATION MARK +1E948..1E94A ; Diacritic # Mn [3] ADLAM CONSONANT MODIFIER..ADLAM NUKTA + +# Total code points: 1247 + +# ================================================ + +00B7 ; Extender # Po MIDDLE DOT +02D0..02D1 ; Extender # Lm [2] MODIFIER LETTER TRIANGULAR COLON..MODIFIER LETTER HALF TRIANGULAR COLON +0640 ; Extender # Lm ARABIC TATWEEL +07FA ; Extender # Lm NKO LAJANYALAN +0A71 ; Extender # Mn GURMUKHI ADDAK +0AFB ; Extender # Mn GUJARATI SIGN SHADDA +0B55 ; Extender # Mn ORIYA SIGN OVERLINE +0E46 ; Extender # Lm THAI CHARACTER MAIYAMOK +0EC6 ; Extender # Lm LAO KO LA +180A ; Extender # Po MONGOLIAN NIRUGU +1843 ; Extender # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN +1AA7 ; Extender # Lm TAI THAM SIGN MAI YAMOK +1C36 ; Extender # Mn LEPCHA SIGN RAN +1C7B ; Extender # Lm OL CHIKI RELAA +3005 ; Extender # Lm IDEOGRAPHIC ITERATION MARK +3031..3035 ; Extender # Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF +309D..309E ; Extender # Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK +30FC..30FE ; Extender # Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK +A015 ; Extender # Lm YI SYLLABLE WU +A60C ; Extender # Lm VAI SYLLABLE LENGTHENER +A9CF ; Extender # Lm JAVANESE PANGRANGKEP +A9E6 ; Extender # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION +AA70 ; Extender # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION +AADD ; Extender # Lm TAI VIET SYMBOL SAM +AAF3..AAF4 ; Extender # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK +FF70 ; Extender # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK +10781..10782 ; Extender # Lm [2] MODIFIER LETTER SUPERSCRIPT TRIANGULAR COLON..MODIFIER LETTER SUPERSCRIPT HALF TRIANGULAR COLON +10D4E ; Extender # Lm GARAY VOWEL LENGTH MARK +10D6A ; Extender # Mn GARAY CONSONANT GEMINATION MARK +10D6F ; Extender # Lm GARAY REDUPLICATION MARK +11237 ; Extender # Mn KHOJKI SIGN SHADDA +1135D ; Extender # Lo GRANTHA SIGN PLUTA +113D2 ; Extender # Mn TULU-TIGALARI GEMINATION MARK +113D3 ; Extender # Lo TULU-TIGALARI SIGN PLUTA +115C6..115C8 ; Extender # Po [3] SIDDHAM REPETITION MARK-1..SIDDHAM REPETITION MARK-3 +11A98 ; Extender # Mn SOYOMBO GEMINATION MARK +11DD9 ; Extender # Lm TOLONG SIKI SIGN SELA +16B42..16B43 ; Extender # Lm [2] PAHAWH HMONG SIGN VOS NRUA..PAHAWH HMONG SIGN IB YAM +16FE0..16FE1 ; Extender # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK +16FE3 ; Extender # Lm OLD CHINESE ITERATION MARK +16FF2..16FF3 ; Extender # Lm [2] CHINESE SMALL SIMPLIFIED ER..CHINESE SMALL TRADITIONAL ER +1E13C..1E13D ; Extender # Lm [2] NYIAKENG PUACHUE HMONG SIGN XW XW..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER +1E5EF ; Extender # Mn OL ONAL SIGN IKIR +1E944..1E946 ; Extender # Mn [3] ADLAM ALIF LENGTHENER..ADLAM GEMINATION MARK + +# Total code points: 62 + +# ================================================ + +00AA ; Other_Lowercase # Lo FEMININE ORDINAL INDICATOR +00BA ; Other_Lowercase # Lo MASCULINE ORDINAL INDICATOR +02B0..02B8 ; Other_Lowercase # Lm [9] MODIFIER LETTER SMALL H..MODIFIER LETTER SMALL Y +02C0..02C1 ; Other_Lowercase # Lm [2] MODIFIER LETTER GLOTTAL STOP..MODIFIER LETTER REVERSED GLOTTAL STOP +02E0..02E4 ; Other_Lowercase # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP +0345 ; Other_Lowercase # Mn COMBINING GREEK YPOGEGRAMMENI +037A ; Other_Lowercase # Lm GREEK YPOGEGRAMMENI +10FC ; Other_Lowercase # Lm MODIFIER LETTER GEORGIAN NAR +1D2C..1D6A ; Other_Lowercase # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI +1D78 ; Other_Lowercase # Lm MODIFIER LETTER CYRILLIC EN +1D9B..1DBF ; Other_Lowercase # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA +2071 ; Other_Lowercase # Lm SUPERSCRIPT LATIN SMALL LETTER I +207F ; Other_Lowercase # Lm SUPERSCRIPT LATIN SMALL LETTER N +2090..209C ; Other_Lowercase # Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T +2170..217F ; Other_Lowercase # Nl [16] SMALL ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL ONE THOUSAND +24D0..24E9 ; Other_Lowercase # So [26] CIRCLED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z +2C7C..2C7D ; Other_Lowercase # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V +A69C..A69D ; Other_Lowercase # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN +A770 ; Other_Lowercase # Lm MODIFIER LETTER US +A7F1..A7F4 ; Other_Lowercase # Lm [4] MODIFIER LETTER CAPITAL S..MODIFIER LETTER CAPITAL Q +A7F8..A7F9 ; Other_Lowercase # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE +AB5C..AB5F ; Other_Lowercase # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK +AB69 ; Other_Lowercase # Lm MODIFIER LETTER SMALL TURNED W +10780 ; Other_Lowercase # Lm MODIFIER LETTER SMALL CAPITAL AA +10783..10785 ; Other_Lowercase # Lm [3] MODIFIER LETTER SMALL AE..MODIFIER LETTER SMALL B WITH HOOK +10787..107B0 ; Other_Lowercase # Lm [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK +107B2..107BA ; Other_Lowercase # Lm [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL +1E030..1E06D ; Other_Lowercase # Lm [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE + +# Total code points: 312 + +# ================================================ + +2160..216F ; Other_Uppercase # Nl [16] ROMAN NUMERAL ONE..ROMAN NUMERAL ONE THOUSAND +24B6..24CF ; Other_Uppercase # So [26] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN CAPITAL LETTER Z +1F130..1F149 ; Other_Uppercase # So [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z +1F150..1F169 ; Other_Uppercase # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z +1F170..1F189 ; Other_Uppercase # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z + +# Total code points: 120 + +# ================================================ + +FDD0..FDEF ; Noncharacter_Code_Point # Cn [32] .. +FFFE..FFFF ; Noncharacter_Code_Point # Cn [2] .. +1FFFE..1FFFF ; Noncharacter_Code_Point # Cn [2] .. +2FFFE..2FFFF ; Noncharacter_Code_Point # Cn [2] .. +3FFFE..3FFFF ; Noncharacter_Code_Point # Cn [2] .. +4FFFE..4FFFF ; Noncharacter_Code_Point # Cn [2] .. +5FFFE..5FFFF ; Noncharacter_Code_Point # Cn [2] .. +6FFFE..6FFFF ; Noncharacter_Code_Point # Cn [2] .. +7FFFE..7FFFF ; Noncharacter_Code_Point # Cn [2] .. +8FFFE..8FFFF ; Noncharacter_Code_Point # Cn [2] .. +9FFFE..9FFFF ; Noncharacter_Code_Point # Cn [2] .. +AFFFE..AFFFF ; Noncharacter_Code_Point # Cn [2] .. +BFFFE..BFFFF ; Noncharacter_Code_Point # Cn [2] .. +CFFFE..CFFFF ; Noncharacter_Code_Point # Cn [2] .. +DFFFE..DFFFF ; Noncharacter_Code_Point # Cn [2] .. +EFFFE..EFFFF ; Noncharacter_Code_Point # Cn [2] .. +FFFFE..FFFFF ; Noncharacter_Code_Point # Cn [2] .. +10FFFE..10FFFF; Noncharacter_Code_Point # Cn [2] .. + +# Total code points: 66 + +# ================================================ + +09BE ; Other_Grapheme_Extend # Mc BENGALI VOWEL SIGN AA +09D7 ; Other_Grapheme_Extend # Mc BENGALI AU LENGTH MARK +0B3E ; Other_Grapheme_Extend # Mc ORIYA VOWEL SIGN AA +0B57 ; Other_Grapheme_Extend # Mc ORIYA AU LENGTH MARK +0BBE ; Other_Grapheme_Extend # Mc TAMIL VOWEL SIGN AA +0BD7 ; Other_Grapheme_Extend # Mc TAMIL AU LENGTH MARK +0CC0 ; Other_Grapheme_Extend # Mc KANNADA VOWEL SIGN II +0CC2 ; Other_Grapheme_Extend # Mc KANNADA VOWEL SIGN UU +0CC7..0CC8 ; Other_Grapheme_Extend # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI +0CCA..0CCB ; Other_Grapheme_Extend # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO +0CD5..0CD6 ; Other_Grapheme_Extend # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK +0D3E ; Other_Grapheme_Extend # Mc MALAYALAM VOWEL SIGN AA +0D57 ; Other_Grapheme_Extend # Mc MALAYALAM AU LENGTH MARK +0DCF ; Other_Grapheme_Extend # Mc SINHALA VOWEL SIGN AELA-PILLA +0DDF ; Other_Grapheme_Extend # Mc SINHALA VOWEL SIGN GAYANUKITTA +1715 ; Other_Grapheme_Extend # Mc TAGALOG SIGN PAMUDPOD +1734 ; Other_Grapheme_Extend # Mc HANUNOO SIGN PAMUDPOD +1B35 ; Other_Grapheme_Extend # Mc BALINESE VOWEL SIGN TEDUNG +1B3B ; Other_Grapheme_Extend # Mc BALINESE VOWEL SIGN RA REPA TEDUNG +1B3D ; Other_Grapheme_Extend # Mc BALINESE VOWEL SIGN LA LENGA TEDUNG +1B43..1B44 ; Other_Grapheme_Extend # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG +1BAA ; Other_Grapheme_Extend # Mc SUNDANESE SIGN PAMAAEH +1BF2..1BF3 ; Other_Grapheme_Extend # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN +200C ; Other_Grapheme_Extend # Cf ZERO WIDTH NON-JOINER +302E..302F ; Other_Grapheme_Extend # Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK +A953 ; Other_Grapheme_Extend # Mc REJANG VIRAMA +A9C0 ; Other_Grapheme_Extend # Mc JAVANESE PANGKON +FF9E..FF9F ; Other_Grapheme_Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK +111C0 ; Other_Grapheme_Extend # Mc SHARADA SIGN VIRAMA +11235 ; Other_Grapheme_Extend # Mc KHOJKI SIGN VIRAMA +1133E ; Other_Grapheme_Extend # Mc GRANTHA VOWEL SIGN AA +1134D ; Other_Grapheme_Extend # Mc GRANTHA SIGN VIRAMA +11357 ; Other_Grapheme_Extend # Mc GRANTHA AU LENGTH MARK +113B8 ; Other_Grapheme_Extend # Mc TULU-TIGALARI VOWEL SIGN AA +113C2 ; Other_Grapheme_Extend # Mc TULU-TIGALARI VOWEL SIGN EE +113C5 ; Other_Grapheme_Extend # Mc TULU-TIGALARI VOWEL SIGN AI +113C7..113C9 ; Other_Grapheme_Extend # Mc [3] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI AU LENGTH MARK +113CF ; Other_Grapheme_Extend # Mc TULU-TIGALARI SIGN LOOPED VIRAMA +114B0 ; Other_Grapheme_Extend # Mc TIRHUTA VOWEL SIGN AA +114BD ; Other_Grapheme_Extend # Mc TIRHUTA VOWEL SIGN SHORT O +115AF ; Other_Grapheme_Extend # Mc SIDDHAM VOWEL SIGN AA +116B6 ; Other_Grapheme_Extend # Mc TAKRI SIGN VIRAMA +11930 ; Other_Grapheme_Extend # Mc DIVES AKURU VOWEL SIGN AA +1193D ; Other_Grapheme_Extend # Mc DIVES AKURU SIGN HALANTA +11F41 ; Other_Grapheme_Extend # Mc KAWI SIGN KILLER +16FF0..16FF1 ; Other_Grapheme_Extend # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY +1D165..1D166 ; Other_Grapheme_Extend # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM +1D16D..1D172 ; Other_Grapheme_Extend # Mc [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5 +E0020..E007F ; Other_Grapheme_Extend # Cf [96] TAG SPACE..CANCEL TAG + +# Total code points: 160 + +# ================================================ + +2FF0..2FF1 ; IDS_Binary_Operator # So [2] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO BELOW +2FF4..2FFD ; IDS_Binary_Operator # So [10] IDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUND..IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER RIGHT +31EF ; IDS_Binary_Operator # So IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION + +# Total code points: 13 + +# ================================================ + +2FF2..2FF3 ; IDS_Trinary_Operator # So [2] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO MIDDLE AND RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND BELOW + +# Total code points: 2 + +# ================================================ + +2FFE..2FFF ; IDS_Unary_Operator # So [2] IDEOGRAPHIC DESCRIPTION CHARACTER HORIZONTAL REFLECTION..IDEOGRAPHIC DESCRIPTION CHARACTER ROTATION + +# Total code points: 2 + +# ================================================ + +2E80..2E99 ; Radical # So [26] CJK RADICAL REPEAT..CJK RADICAL RAP +2E9B..2EF3 ; Radical # So [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE +2F00..2FD5 ; Radical # So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE + +# Total code points: 329 + +# ================================================ + +3400..4DBF ; Unified_Ideograph # Lo [6592] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DBF +4E00..9FFF ; Unified_Ideograph # Lo [20992] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFF +FA0E..FA0F ; Unified_Ideograph # Lo [2] CJK COMPATIBILITY IDEOGRAPH-FA0E..CJK COMPATIBILITY IDEOGRAPH-FA0F +FA11 ; Unified_Ideograph # Lo CJK COMPATIBILITY IDEOGRAPH-FA11 +FA13..FA14 ; Unified_Ideograph # Lo [2] CJK COMPATIBILITY IDEOGRAPH-FA13..CJK COMPATIBILITY IDEOGRAPH-FA14 +FA1F ; Unified_Ideograph # Lo CJK COMPATIBILITY IDEOGRAPH-FA1F +FA21 ; Unified_Ideograph # Lo CJK COMPATIBILITY IDEOGRAPH-FA21 +FA23..FA24 ; Unified_Ideograph # Lo [2] CJK COMPATIBILITY IDEOGRAPH-FA23..CJK COMPATIBILITY IDEOGRAPH-FA24 +FA27..FA29 ; Unified_Ideograph # Lo [3] CJK COMPATIBILITY IDEOGRAPH-FA27..CJK COMPATIBILITY IDEOGRAPH-FA29 +20000..2A6DF ; Unified_Ideograph # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF +2A700..2B81D ; Unified_Ideograph # Lo [4382] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B81D +2B820..2CEAD ; Unified_Ideograph # Lo [5774] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEAD +2CEB0..2EBE0 ; Unified_Ideograph # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 +2EBF0..2EE5D ; Unified_Ideograph # Lo [622] CJK UNIFIED IDEOGRAPH-2EBF0..CJK UNIFIED IDEOGRAPH-2EE5D +30000..3134A ; Unified_Ideograph # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A +31350..33479 ; Unified_Ideograph # Lo [8490] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-33479 + +# Total code points: 101996 + +# ================================================ + +034F ; Other_Default_Ignorable_Code_Point # Mn COMBINING GRAPHEME JOINER +115F..1160 ; Other_Default_Ignorable_Code_Point # Lo [2] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER +17B4..17B5 ; Other_Default_Ignorable_Code_Point # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA +2065 ; Other_Default_Ignorable_Code_Point # Cn +3164 ; Other_Default_Ignorable_Code_Point # Lo HANGUL FILLER +FFA0 ; Other_Default_Ignorable_Code_Point # Lo HALFWIDTH HANGUL FILLER +FFF0..FFF8 ; Other_Default_Ignorable_Code_Point # Cn [9] .. +E0000 ; Other_Default_Ignorable_Code_Point # Cn +E0002..E001F ; Other_Default_Ignorable_Code_Point # Cn [30] .. +E0080..E00FF ; Other_Default_Ignorable_Code_Point # Cn [128] .. +E01F0..E0FFF ; Other_Default_Ignorable_Code_Point # Cn [3600] .. + +# Total code points: 3776 + +# ================================================ + +0149 ; Deprecated # L& LATIN SMALL LETTER N PRECEDED BY APOSTROPHE +0673 ; Deprecated # Lo ARABIC LETTER ALEF WITH WAVY HAMZA BELOW +0F77 ; Deprecated # Mn TIBETAN VOWEL SIGN VOCALIC RR +0F79 ; Deprecated # Mn TIBETAN VOWEL SIGN VOCALIC LL +17A3..17A4 ; Deprecated # Lo [2] KHMER INDEPENDENT VOWEL QAQ..KHMER INDEPENDENT VOWEL QAA +206A..206F ; Deprecated # Cf [6] INHIBIT SYMMETRIC SWAPPING..NOMINAL DIGIT SHAPES +2329 ; Deprecated # Ps LEFT-POINTING ANGLE BRACKET +232A ; Deprecated # Pe RIGHT-POINTING ANGLE BRACKET +E0001 ; Deprecated # Cf LANGUAGE TAG + +# Total code points: 15 + +# ================================================ + +0069..006A ; Soft_Dotted # L& [2] LATIN SMALL LETTER I..LATIN SMALL LETTER J +012F ; Soft_Dotted # L& LATIN SMALL LETTER I WITH OGONEK +0249 ; Soft_Dotted # L& LATIN SMALL LETTER J WITH STROKE +0268 ; Soft_Dotted # L& LATIN SMALL LETTER I WITH STROKE +029D ; Soft_Dotted # L& LATIN SMALL LETTER J WITH CROSSED-TAIL +02B2 ; Soft_Dotted # Lm MODIFIER LETTER SMALL J +03F3 ; Soft_Dotted # L& GREEK LETTER YOT +0456 ; Soft_Dotted # L& CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I +0458 ; Soft_Dotted # L& CYRILLIC SMALL LETTER JE +1D62 ; Soft_Dotted # Lm LATIN SUBSCRIPT SMALL LETTER I +1D96 ; Soft_Dotted # L& LATIN SMALL LETTER I WITH RETROFLEX HOOK +1DA4 ; Soft_Dotted # Lm MODIFIER LETTER SMALL I WITH STROKE +1DA8 ; Soft_Dotted # Lm MODIFIER LETTER SMALL J WITH CROSSED-TAIL +1E2D ; Soft_Dotted # L& LATIN SMALL LETTER I WITH TILDE BELOW +1ECB ; Soft_Dotted # L& LATIN SMALL LETTER I WITH DOT BELOW +2071 ; Soft_Dotted # Lm SUPERSCRIPT LATIN SMALL LETTER I +2148..2149 ; Soft_Dotted # L& [2] DOUBLE-STRUCK ITALIC SMALL I..DOUBLE-STRUCK ITALIC SMALL J +2C7C ; Soft_Dotted # Lm LATIN SUBSCRIPT SMALL LETTER J +1D422..1D423 ; Soft_Dotted # L& [2] MATHEMATICAL BOLD SMALL I..MATHEMATICAL BOLD SMALL J +1D456..1D457 ; Soft_Dotted # L& [2] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL ITALIC SMALL J +1D48A..1D48B ; Soft_Dotted # L& [2] MATHEMATICAL BOLD ITALIC SMALL I..MATHEMATICAL BOLD ITALIC SMALL J +1D4BE..1D4BF ; Soft_Dotted # L& [2] MATHEMATICAL SCRIPT SMALL I..MATHEMATICAL SCRIPT SMALL J +1D4F2..1D4F3 ; Soft_Dotted # L& [2] MATHEMATICAL BOLD SCRIPT SMALL I..MATHEMATICAL BOLD SCRIPT SMALL J +1D526..1D527 ; Soft_Dotted # L& [2] MATHEMATICAL FRAKTUR SMALL I..MATHEMATICAL FRAKTUR SMALL J +1D55A..1D55B ; Soft_Dotted # L& [2] MATHEMATICAL DOUBLE-STRUCK SMALL I..MATHEMATICAL DOUBLE-STRUCK SMALL J +1D58E..1D58F ; Soft_Dotted # L& [2] MATHEMATICAL BOLD FRAKTUR SMALL I..MATHEMATICAL BOLD FRAKTUR SMALL J +1D5C2..1D5C3 ; Soft_Dotted # L& [2] MATHEMATICAL SANS-SERIF SMALL I..MATHEMATICAL SANS-SERIF SMALL J +1D5F6..1D5F7 ; Soft_Dotted # L& [2] MATHEMATICAL SANS-SERIF BOLD SMALL I..MATHEMATICAL SANS-SERIF BOLD SMALL J +1D62A..1D62B ; Soft_Dotted # L& [2] MATHEMATICAL SANS-SERIF ITALIC SMALL I..MATHEMATICAL SANS-SERIF ITALIC SMALL J +1D65E..1D65F ; Soft_Dotted # L& [2] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J +1D692..1D693 ; Soft_Dotted # L& [2] MATHEMATICAL MONOSPACE SMALL I..MATHEMATICAL MONOSPACE SMALL J +1DF1A ; Soft_Dotted # L& LATIN SMALL LETTER I WITH STROKE AND RETROFLEX HOOK +1E04C..1E04D ; Soft_Dotted # Lm [2] MODIFIER LETTER CYRILLIC SMALL BYELORUSSIAN-UKRAINIAN I..MODIFIER LETTER CYRILLIC SMALL JE +1E068 ; Soft_Dotted # Lm CYRILLIC SUBSCRIPT SMALL LETTER BYELORUSSIAN-UKRAINIAN I + +# Total code points: 50 + +# ================================================ + +0E40..0E44 ; Logical_Order_Exception # Lo [5] THAI CHARACTER SARA E..THAI CHARACTER SARA AI MAIMALAI +0EC0..0EC4 ; Logical_Order_Exception # Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI +19B5..19B7 ; Logical_Order_Exception # Lo [3] NEW TAI LUE VOWEL SIGN E..NEW TAI LUE VOWEL SIGN O +19BA ; Logical_Order_Exception # Lo NEW TAI LUE VOWEL SIGN AY +AAB5..AAB6 ; Logical_Order_Exception # Lo [2] TAI VIET VOWEL E..TAI VIET VOWEL O +AAB9 ; Logical_Order_Exception # Lo TAI VIET VOWEL UEA +AABB..AABC ; Logical_Order_Exception # Lo [2] TAI VIET VOWEL AUE..TAI VIET VOWEL AY + +# Total code points: 19 + +# ================================================ + +1885..1886 ; Other_ID_Start # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA +2118 ; Other_ID_Start # Sm SCRIPT CAPITAL P +212E ; Other_ID_Start # So ESTIMATED SYMBOL +309B..309C ; Other_ID_Start # Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK + +# Total code points: 6 + +# ================================================ + +00B7 ; Other_ID_Continue # Po MIDDLE DOT +0387 ; Other_ID_Continue # Po GREEK ANO TELEIA +1369..1371 ; Other_ID_Continue # No [9] ETHIOPIC DIGIT ONE..ETHIOPIC DIGIT NINE +19DA ; Other_ID_Continue # No NEW TAI LUE THAM DIGIT ONE +200C..200D ; Other_ID_Continue # Cf [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER +30FB ; Other_ID_Continue # Po KATAKANA MIDDLE DOT +FF65 ; Other_ID_Continue # Po HALFWIDTH KATAKANA MIDDLE DOT + +# Total code points: 16 + +# ================================================ + +00B2..00B3 ; ID_Compat_Math_Continue # No [2] SUPERSCRIPT TWO..SUPERSCRIPT THREE +00B9 ; ID_Compat_Math_Continue # No SUPERSCRIPT ONE +2070 ; ID_Compat_Math_Continue # No SUPERSCRIPT ZERO +2074..2079 ; ID_Compat_Math_Continue # No [6] SUPERSCRIPT FOUR..SUPERSCRIPT NINE +207A..207C ; ID_Compat_Math_Continue # Sm [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN +207D ; ID_Compat_Math_Continue # Ps SUPERSCRIPT LEFT PARENTHESIS +207E ; ID_Compat_Math_Continue # Pe SUPERSCRIPT RIGHT PARENTHESIS +2080..2089 ; ID_Compat_Math_Continue # No [10] SUBSCRIPT ZERO..SUBSCRIPT NINE +208A..208C ; ID_Compat_Math_Continue # Sm [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN +208D ; ID_Compat_Math_Continue # Ps SUBSCRIPT LEFT PARENTHESIS +208E ; ID_Compat_Math_Continue # Pe SUBSCRIPT RIGHT PARENTHESIS +2202 ; ID_Compat_Math_Continue # Sm PARTIAL DIFFERENTIAL +2207 ; ID_Compat_Math_Continue # Sm NABLA +221E ; ID_Compat_Math_Continue # Sm INFINITY +1D6C1 ; ID_Compat_Math_Continue # Sm MATHEMATICAL BOLD NABLA +1D6DB ; ID_Compat_Math_Continue # Sm MATHEMATICAL BOLD PARTIAL DIFFERENTIAL +1D6FB ; ID_Compat_Math_Continue # Sm MATHEMATICAL ITALIC NABLA +1D715 ; ID_Compat_Math_Continue # Sm MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL +1D735 ; ID_Compat_Math_Continue # Sm MATHEMATICAL BOLD ITALIC NABLA +1D74F ; ID_Compat_Math_Continue # Sm MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL +1D76F ; ID_Compat_Math_Continue # Sm MATHEMATICAL SANS-SERIF BOLD NABLA +1D789 ; ID_Compat_Math_Continue # Sm MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL +1D7A9 ; ID_Compat_Math_Continue # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA +1D7C3 ; ID_Compat_Math_Continue # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL + +# Total code points: 43 + +# ================================================ + +2202 ; ID_Compat_Math_Start # Sm PARTIAL DIFFERENTIAL +2207 ; ID_Compat_Math_Start # Sm NABLA +221E ; ID_Compat_Math_Start # Sm INFINITY +1D6C1 ; ID_Compat_Math_Start # Sm MATHEMATICAL BOLD NABLA +1D6DB ; ID_Compat_Math_Start # Sm MATHEMATICAL BOLD PARTIAL DIFFERENTIAL +1D6FB ; ID_Compat_Math_Start # Sm MATHEMATICAL ITALIC NABLA +1D715 ; ID_Compat_Math_Start # Sm MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL +1D735 ; ID_Compat_Math_Start # Sm MATHEMATICAL BOLD ITALIC NABLA +1D74F ; ID_Compat_Math_Start # Sm MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL +1D76F ; ID_Compat_Math_Start # Sm MATHEMATICAL SANS-SERIF BOLD NABLA +1D789 ; ID_Compat_Math_Start # Sm MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL +1D7A9 ; ID_Compat_Math_Start # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA +1D7C3 ; ID_Compat_Math_Start # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL + +# Total code points: 13 + +# ================================================ + +0021 ; Sentence_Terminal # Po EXCLAMATION MARK +002E ; Sentence_Terminal # Po FULL STOP +003F ; Sentence_Terminal # Po QUESTION MARK +0589 ; Sentence_Terminal # Po ARMENIAN FULL STOP +061D..061F ; Sentence_Terminal # Po [3] ARABIC END OF TEXT MARK..ARABIC QUESTION MARK +06D4 ; Sentence_Terminal # Po ARABIC FULL STOP +0700..0702 ; Sentence_Terminal # Po [3] SYRIAC END OF PARAGRAPH..SYRIAC SUBLINEAR FULL STOP +07F9 ; Sentence_Terminal # Po NKO EXCLAMATION MARK +0837 ; Sentence_Terminal # Po SAMARITAN PUNCTUATION MELODIC QITSA +0839 ; Sentence_Terminal # Po SAMARITAN PUNCTUATION QITSA +083D..083E ; Sentence_Terminal # Po [2] SAMARITAN PUNCTUATION SOF MASHFAAT..SAMARITAN PUNCTUATION ANNAAU +0964..0965 ; Sentence_Terminal # Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA +104A..104B ; Sentence_Terminal # Po [2] MYANMAR SIGN LITTLE SECTION..MYANMAR SIGN SECTION +1362 ; Sentence_Terminal # Po ETHIOPIC FULL STOP +1367..1368 ; Sentence_Terminal # Po [2] ETHIOPIC QUESTION MARK..ETHIOPIC PARAGRAPH SEPARATOR +166E ; Sentence_Terminal # Po CANADIAN SYLLABICS FULL STOP +1735..1736 ; Sentence_Terminal # Po [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION +17D4..17D5 ; Sentence_Terminal # Po [2] KHMER SIGN KHAN..KHMER SIGN BARIYOOSAN +1803 ; Sentence_Terminal # Po MONGOLIAN FULL STOP +1809 ; Sentence_Terminal # Po MONGOLIAN MANCHU FULL STOP +1944..1945 ; Sentence_Terminal # Po [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK +1AA8..1AAB ; Sentence_Terminal # Po [4] TAI THAM SIGN KAAN..TAI THAM SIGN SATKAANKUU +1B4E..1B4F ; Sentence_Terminal # Po [2] BALINESE INVERTED CARIK SIKI..BALINESE INVERTED CARIK PAREREN +1B5A..1B5B ; Sentence_Terminal # Po [2] BALINESE PANTI..BALINESE PAMADA +1B5E..1B5F ; Sentence_Terminal # Po [2] BALINESE CARIK SIKI..BALINESE CARIK PAREREN +1B7D..1B7F ; Sentence_Terminal # Po [3] BALINESE PANTI LANTANG..BALINESE PANTI BAWAK +1C3B..1C3C ; Sentence_Terminal # Po [2] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION NYET THYOOM TA-ROL +1C7E..1C7F ; Sentence_Terminal # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD +2024 ; Sentence_Terminal # Po ONE DOT LEADER +203C..203D ; Sentence_Terminal # Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG +2047..2049 ; Sentence_Terminal # Po [3] DOUBLE QUESTION MARK..EXCLAMATION QUESTION MARK +2CF9..2CFB ; Sentence_Terminal # Po [3] COPTIC OLD NUBIAN FULL STOP..COPTIC OLD NUBIAN INDIRECT QUESTION MARK +2E2E ; Sentence_Terminal # Po REVERSED QUESTION MARK +2E3C ; Sentence_Terminal # Po STENOGRAPHIC FULL STOP +2E53..2E54 ; Sentence_Terminal # Po [2] MEDIEVAL EXCLAMATION MARK..MEDIEVAL QUESTION MARK +3002 ; Sentence_Terminal # Po IDEOGRAPHIC FULL STOP +A4FF ; Sentence_Terminal # Po LISU PUNCTUATION FULL STOP +A60E..A60F ; Sentence_Terminal # Po [2] VAI FULL STOP..VAI QUESTION MARK +A6F3 ; Sentence_Terminal # Po BAMUM FULL STOP +A6F7 ; Sentence_Terminal # Po BAMUM QUESTION MARK +A876..A877 ; Sentence_Terminal # Po [2] PHAGS-PA MARK SHAD..PHAGS-PA MARK DOUBLE SHAD +A8CE..A8CF ; Sentence_Terminal # Po [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA +A92F ; Sentence_Terminal # Po KAYAH LI SIGN SHYA +A9C8..A9C9 ; Sentence_Terminal # Po [2] JAVANESE PADA LINGSA..JAVANESE PADA LUNGSI +AA5D..AA5F ; Sentence_Terminal # Po [3] CHAM PUNCTUATION DANDA..CHAM PUNCTUATION TRIPLE DANDA +AAF0..AAF1 ; Sentence_Terminal # Po [2] MEETEI MAYEK CHEIKHAN..MEETEI MAYEK AHANG KHUDAM +ABEB ; Sentence_Terminal # Po MEETEI MAYEK CHEIKHEI +FE12 ; Sentence_Terminal # Po PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP +FE15..FE16 ; Sentence_Terminal # Po [2] PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK..PRESENTATION FORM FOR VERTICAL QUESTION MARK +FE52 ; Sentence_Terminal # Po SMALL FULL STOP +FE56..FE57 ; Sentence_Terminal # Po [2] SMALL QUESTION MARK..SMALL EXCLAMATION MARK +FF01 ; Sentence_Terminal # Po FULLWIDTH EXCLAMATION MARK +FF0E ; Sentence_Terminal # Po FULLWIDTH FULL STOP +FF1F ; Sentence_Terminal # Po FULLWIDTH QUESTION MARK +FF61 ; Sentence_Terminal # Po HALFWIDTH IDEOGRAPHIC FULL STOP +10A56..10A57 ; Sentence_Terminal # Po [2] KHAROSHTHI PUNCTUATION DANDA..KHAROSHTHI PUNCTUATION DOUBLE DANDA +10F55..10F59 ; Sentence_Terminal # Po [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT +10F86..10F89 ; Sentence_Terminal # Po [4] OLD UYGHUR PUNCTUATION BAR..OLD UYGHUR PUNCTUATION FOUR DOTS +11047..11048 ; Sentence_Terminal # Po [2] BRAHMI DANDA..BRAHMI DOUBLE DANDA +110BE..110C1 ; Sentence_Terminal # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA +11141..11143 ; Sentence_Terminal # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK +111C5..111C6 ; Sentence_Terminal # Po [2] SHARADA DANDA..SHARADA DOUBLE DANDA +111CD ; Sentence_Terminal # Po SHARADA SUTRA MARK +111DE..111DF ; Sentence_Terminal # Po [2] SHARADA SECTION MARK-1..SHARADA SECTION MARK-2 +11238..11239 ; Sentence_Terminal # Po [2] KHOJKI DANDA..KHOJKI DOUBLE DANDA +1123B..1123C ; Sentence_Terminal # Po [2] KHOJKI SECTION MARK..KHOJKI DOUBLE SECTION MARK +112A9 ; Sentence_Terminal # Po MULTANI SECTION MARK +113D4..113D5 ; Sentence_Terminal # Po [2] TULU-TIGALARI DANDA..TULU-TIGALARI DOUBLE DANDA +1144B..1144C ; Sentence_Terminal # Po [2] NEWA DANDA..NEWA DOUBLE DANDA +115C2..115C3 ; Sentence_Terminal # Po [2] SIDDHAM DANDA..SIDDHAM DOUBLE DANDA +115C9..115D7 ; Sentence_Terminal # Po [15] SIDDHAM END OF TEXT MARK..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES +11641..11642 ; Sentence_Terminal # Po [2] MODI DANDA..MODI DOUBLE DANDA +1173C..1173E ; Sentence_Terminal # Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI +11944 ; Sentence_Terminal # Po DIVES AKURU DOUBLE DANDA +11946 ; Sentence_Terminal # Po DIVES AKURU END OF TEXT MARK +11A42..11A43 ; Sentence_Terminal # Po [2] ZANABAZAR SQUARE MARK SHAD..ZANABAZAR SQUARE MARK DOUBLE SHAD +11A9B..11A9C ; Sentence_Terminal # Po [2] SOYOMBO MARK SHAD..SOYOMBO MARK DOUBLE SHAD +11C41..11C42 ; Sentence_Terminal # Po [2] BHAIKSUKI DANDA..BHAIKSUKI DOUBLE DANDA +11EF7..11EF8 ; Sentence_Terminal # Po [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION +11F43..11F44 ; Sentence_Terminal # Po [2] KAWI DANDA..KAWI DOUBLE DANDA +16A6E..16A6F ; Sentence_Terminal # Po [2] MRO DANDA..MRO DOUBLE DANDA +16AF5 ; Sentence_Terminal # Po BASSA VAH FULL STOP +16B37..16B38 ; Sentence_Terminal # Po [2] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS TSHAB CEEB +16B44 ; Sentence_Terminal # Po PAHAWH HMONG SIGN XAUS +16D6E..16D6F ; Sentence_Terminal # Po [2] KIRAT RAI DANDA..KIRAT RAI DOUBLE DANDA +16E98 ; Sentence_Terminal # Po MEDEFAIDRIN FULL STOP +1BC9F ; Sentence_Terminal # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP +1DA88 ; Sentence_Terminal # Po SIGNWRITING FULL STOP + +# Total code points: 170 + +# ================================================ + +180B..180D ; Variation_Selector # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE +180F ; Variation_Selector # Mn MONGOLIAN FREE VARIATION SELECTOR FOUR +FE00..FE0F ; Variation_Selector # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16 +E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 + +# Total code points: 260 + +# ================================================ + +0009..000D ; Pattern_White_Space # Cc [5] .. +0020 ; Pattern_White_Space # Zs SPACE +0085 ; Pattern_White_Space # Cc +200E..200F ; Pattern_White_Space # Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK +2028 ; Pattern_White_Space # Zl LINE SEPARATOR +2029 ; Pattern_White_Space # Zp PARAGRAPH SEPARATOR + +# Total code points: 11 + +# ================================================ + +0021..0023 ; Pattern_Syntax # Po [3] EXCLAMATION MARK..NUMBER SIGN +0024 ; Pattern_Syntax # Sc DOLLAR SIGN +0025..0027 ; Pattern_Syntax # Po [3] PERCENT SIGN..APOSTROPHE +0028 ; Pattern_Syntax # Ps LEFT PARENTHESIS +0029 ; Pattern_Syntax # Pe RIGHT PARENTHESIS +002A ; Pattern_Syntax # Po ASTERISK +002B ; Pattern_Syntax # Sm PLUS SIGN +002C ; Pattern_Syntax # Po COMMA +002D ; Pattern_Syntax # Pd HYPHEN-MINUS +002E..002F ; Pattern_Syntax # Po [2] FULL STOP..SOLIDUS +003A..003B ; Pattern_Syntax # Po [2] COLON..SEMICOLON +003C..003E ; Pattern_Syntax # Sm [3] LESS-THAN SIGN..GREATER-THAN SIGN +003F..0040 ; Pattern_Syntax # Po [2] QUESTION MARK..COMMERCIAL AT +005B ; Pattern_Syntax # Ps LEFT SQUARE BRACKET +005C ; Pattern_Syntax # Po REVERSE SOLIDUS +005D ; Pattern_Syntax # Pe RIGHT SQUARE BRACKET +005E ; Pattern_Syntax # Sk CIRCUMFLEX ACCENT +0060 ; Pattern_Syntax # Sk GRAVE ACCENT +007B ; Pattern_Syntax # Ps LEFT CURLY BRACKET +007C ; Pattern_Syntax # Sm VERTICAL LINE +007D ; Pattern_Syntax # Pe RIGHT CURLY BRACKET +007E ; Pattern_Syntax # Sm TILDE +00A1 ; Pattern_Syntax # Po INVERTED EXCLAMATION MARK +00A2..00A5 ; Pattern_Syntax # Sc [4] CENT SIGN..YEN SIGN +00A6 ; Pattern_Syntax # So BROKEN BAR +00A7 ; Pattern_Syntax # Po SECTION SIGN +00A9 ; Pattern_Syntax # So COPYRIGHT SIGN +00AB ; Pattern_Syntax # Pi LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +00AC ; Pattern_Syntax # Sm NOT SIGN +00AE ; Pattern_Syntax # So REGISTERED SIGN +00B0 ; Pattern_Syntax # So DEGREE SIGN +00B1 ; Pattern_Syntax # Sm PLUS-MINUS SIGN +00B6 ; Pattern_Syntax # Po PILCROW SIGN +00BB ; Pattern_Syntax # Pf RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +00BF ; Pattern_Syntax # Po INVERTED QUESTION MARK +00D7 ; Pattern_Syntax # Sm MULTIPLICATION SIGN +00F7 ; Pattern_Syntax # Sm DIVISION SIGN +2010..2015 ; Pattern_Syntax # Pd [6] HYPHEN..HORIZONTAL BAR +2016..2017 ; Pattern_Syntax # Po [2] DOUBLE VERTICAL LINE..DOUBLE LOW LINE +2018 ; Pattern_Syntax # Pi LEFT SINGLE QUOTATION MARK +2019 ; Pattern_Syntax # Pf RIGHT SINGLE QUOTATION MARK +201A ; Pattern_Syntax # Ps SINGLE LOW-9 QUOTATION MARK +201B..201C ; Pattern_Syntax # Pi [2] SINGLE HIGH-REVERSED-9 QUOTATION MARK..LEFT DOUBLE QUOTATION MARK +201D ; Pattern_Syntax # Pf RIGHT DOUBLE QUOTATION MARK +201E ; Pattern_Syntax # Ps DOUBLE LOW-9 QUOTATION MARK +201F ; Pattern_Syntax # Pi DOUBLE HIGH-REVERSED-9 QUOTATION MARK +2020..2027 ; Pattern_Syntax # Po [8] DAGGER..HYPHENATION POINT +2030..2038 ; Pattern_Syntax # Po [9] PER MILLE SIGN..CARET +2039 ; Pattern_Syntax # Pi SINGLE LEFT-POINTING ANGLE QUOTATION MARK +203A ; Pattern_Syntax # Pf SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +203B..203E ; Pattern_Syntax # Po [4] REFERENCE MARK..OVERLINE +2041..2043 ; Pattern_Syntax # Po [3] CARET INSERTION POINT..HYPHEN BULLET +2044 ; Pattern_Syntax # Sm FRACTION SLASH +2045 ; Pattern_Syntax # Ps LEFT SQUARE BRACKET WITH QUILL +2046 ; Pattern_Syntax # Pe RIGHT SQUARE BRACKET WITH QUILL +2047..2051 ; Pattern_Syntax # Po [11] DOUBLE QUESTION MARK..TWO ASTERISKS ALIGNED VERTICALLY +2052 ; Pattern_Syntax # Sm COMMERCIAL MINUS SIGN +2053 ; Pattern_Syntax # Po SWUNG DASH +2055..205E ; Pattern_Syntax # Po [10] FLOWER PUNCTUATION MARK..VERTICAL FOUR DOTS +2190..2194 ; Pattern_Syntax # Sm [5] LEFTWARDS ARROW..LEFT RIGHT ARROW +2195..2199 ; Pattern_Syntax # So [5] UP DOWN ARROW..SOUTH WEST ARROW +219A..219B ; Pattern_Syntax # Sm [2] LEFTWARDS ARROW WITH STROKE..RIGHTWARDS ARROW WITH STROKE +219C..219F ; Pattern_Syntax # So [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW +21A0 ; Pattern_Syntax # Sm RIGHTWARDS TWO HEADED ARROW +21A1..21A2 ; Pattern_Syntax # So [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL +21A3 ; Pattern_Syntax # Sm RIGHTWARDS ARROW WITH TAIL +21A4..21A5 ; Pattern_Syntax # So [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR +21A6 ; Pattern_Syntax # Sm RIGHTWARDS ARROW FROM BAR +21A7..21AD ; Pattern_Syntax # So [7] DOWNWARDS ARROW FROM BAR..LEFT RIGHT WAVE ARROW +21AE ; Pattern_Syntax # Sm LEFT RIGHT ARROW WITH STROKE +21AF..21CD ; Pattern_Syntax # So [31] DOWNWARDS ZIGZAG ARROW..LEFTWARDS DOUBLE ARROW WITH STROKE +21CE..21CF ; Pattern_Syntax # Sm [2] LEFT RIGHT DOUBLE ARROW WITH STROKE..RIGHTWARDS DOUBLE ARROW WITH STROKE +21D0..21D1 ; Pattern_Syntax # So [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW +21D2 ; Pattern_Syntax # Sm RIGHTWARDS DOUBLE ARROW +21D3 ; Pattern_Syntax # So DOWNWARDS DOUBLE ARROW +21D4 ; Pattern_Syntax # Sm LEFT RIGHT DOUBLE ARROW +21D5..21F3 ; Pattern_Syntax # So [31] UP DOWN DOUBLE ARROW..UP DOWN WHITE ARROW +21F4..22FF ; Pattern_Syntax # Sm [268] RIGHT ARROW WITH SMALL CIRCLE..Z NOTATION BAG MEMBERSHIP +2300..2307 ; Pattern_Syntax # So [8] DIAMETER SIGN..WAVY LINE +2308 ; Pattern_Syntax # Ps LEFT CEILING +2309 ; Pattern_Syntax # Pe RIGHT CEILING +230A ; Pattern_Syntax # Ps LEFT FLOOR +230B ; Pattern_Syntax # Pe RIGHT FLOOR +230C..231F ; Pattern_Syntax # So [20] BOTTOM RIGHT CROP..BOTTOM RIGHT CORNER +2320..2321 ; Pattern_Syntax # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL +2322..2328 ; Pattern_Syntax # So [7] FROWN..KEYBOARD +2329 ; Pattern_Syntax # Ps LEFT-POINTING ANGLE BRACKET +232A ; Pattern_Syntax # Pe RIGHT-POINTING ANGLE BRACKET +232B..237B ; Pattern_Syntax # So [81] ERASE TO THE LEFT..NOT CHECK MARK +237C ; Pattern_Syntax # Sm RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW +237D..239A ; Pattern_Syntax # So [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL +239B..23B3 ; Pattern_Syntax # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM +23B4..23DB ; Pattern_Syntax # So [40] TOP SQUARE BRACKET..FUSE +23DC..23E1 ; Pattern_Syntax # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET +23E2..2429 ; Pattern_Syntax # So [72] WHITE TRAPEZIUM..SYMBOL FOR DELETE MEDIUM SHADE FORM +242A..243F ; Pattern_Syntax # Cn [22] .. +2440..244A ; Pattern_Syntax # So [11] OCR HOOK..OCR DOUBLE BACKSLASH +244B..245F ; Pattern_Syntax # Cn [21] .. +2500..25B6 ; Pattern_Syntax # So [183] BOX DRAWINGS LIGHT HORIZONTAL..BLACK RIGHT-POINTING TRIANGLE +25B7 ; Pattern_Syntax # Sm WHITE RIGHT-POINTING TRIANGLE +25B8..25C0 ; Pattern_Syntax # So [9] BLACK RIGHT-POINTING SMALL TRIANGLE..BLACK LEFT-POINTING TRIANGLE +25C1 ; Pattern_Syntax # Sm WHITE LEFT-POINTING TRIANGLE +25C2..25F7 ; Pattern_Syntax # So [54] BLACK LEFT-POINTING SMALL TRIANGLE..WHITE CIRCLE WITH UPPER RIGHT QUADRANT +25F8..25FF ; Pattern_Syntax # Sm [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE +2600..266E ; Pattern_Syntax # So [111] BLACK SUN WITH RAYS..MUSIC NATURAL SIGN +266F ; Pattern_Syntax # Sm MUSIC SHARP SIGN +2670..2767 ; Pattern_Syntax # So [248] WEST SYRIAC CROSS..ROTATED FLORAL HEART BULLET +2768 ; Pattern_Syntax # Ps MEDIUM LEFT PARENTHESIS ORNAMENT +2769 ; Pattern_Syntax # Pe MEDIUM RIGHT PARENTHESIS ORNAMENT +276A ; Pattern_Syntax # Ps MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT +276B ; Pattern_Syntax # Pe MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT +276C ; Pattern_Syntax # Ps MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT +276D ; Pattern_Syntax # Pe MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT +276E ; Pattern_Syntax # Ps HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT +276F ; Pattern_Syntax # Pe HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT +2770 ; Pattern_Syntax # Ps HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT +2771 ; Pattern_Syntax # Pe HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT +2772 ; Pattern_Syntax # Ps LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT +2773 ; Pattern_Syntax # Pe LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT +2774 ; Pattern_Syntax # Ps MEDIUM LEFT CURLY BRACKET ORNAMENT +2775 ; Pattern_Syntax # Pe MEDIUM RIGHT CURLY BRACKET ORNAMENT +2794..27BF ; Pattern_Syntax # So [44] HEAVY WIDE-HEADED RIGHTWARDS ARROW..DOUBLE CURLY LOOP +27C0..27C4 ; Pattern_Syntax # Sm [5] THREE DIMENSIONAL ANGLE..OPEN SUPERSET +27C5 ; Pattern_Syntax # Ps LEFT S-SHAPED BAG DELIMITER +27C6 ; Pattern_Syntax # Pe RIGHT S-SHAPED BAG DELIMITER +27C7..27E5 ; Pattern_Syntax # Sm [31] OR WITH DOT INSIDE..WHITE SQUARE WITH RIGHTWARDS TICK +27E6 ; Pattern_Syntax # Ps MATHEMATICAL LEFT WHITE SQUARE BRACKET +27E7 ; Pattern_Syntax # Pe MATHEMATICAL RIGHT WHITE SQUARE BRACKET +27E8 ; Pattern_Syntax # Ps MATHEMATICAL LEFT ANGLE BRACKET +27E9 ; Pattern_Syntax # Pe MATHEMATICAL RIGHT ANGLE BRACKET +27EA ; Pattern_Syntax # Ps MATHEMATICAL LEFT DOUBLE ANGLE BRACKET +27EB ; Pattern_Syntax # Pe MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET +27EC ; Pattern_Syntax # Ps MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET +27ED ; Pattern_Syntax # Pe MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET +27EE ; Pattern_Syntax # Ps MATHEMATICAL LEFT FLATTENED PARENTHESIS +27EF ; Pattern_Syntax # Pe MATHEMATICAL RIGHT FLATTENED PARENTHESIS +27F0..27FF ; Pattern_Syntax # Sm [16] UPWARDS QUADRUPLE ARROW..LONG RIGHTWARDS SQUIGGLE ARROW +2800..28FF ; Pattern_Syntax # So [256] BRAILLE PATTERN BLANK..BRAILLE PATTERN DOTS-12345678 +2900..2982 ; Pattern_Syntax # Sm [131] RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE..Z NOTATION TYPE COLON +2983 ; Pattern_Syntax # Ps LEFT WHITE CURLY BRACKET +2984 ; Pattern_Syntax # Pe RIGHT WHITE CURLY BRACKET +2985 ; Pattern_Syntax # Ps LEFT WHITE PARENTHESIS +2986 ; Pattern_Syntax # Pe RIGHT WHITE PARENTHESIS +2987 ; Pattern_Syntax # Ps Z NOTATION LEFT IMAGE BRACKET +2988 ; Pattern_Syntax # Pe Z NOTATION RIGHT IMAGE BRACKET +2989 ; Pattern_Syntax # Ps Z NOTATION LEFT BINDING BRACKET +298A ; Pattern_Syntax # Pe Z NOTATION RIGHT BINDING BRACKET +298B ; Pattern_Syntax # Ps LEFT SQUARE BRACKET WITH UNDERBAR +298C ; Pattern_Syntax # Pe RIGHT SQUARE BRACKET WITH UNDERBAR +298D ; Pattern_Syntax # Ps LEFT SQUARE BRACKET WITH TICK IN TOP CORNER +298E ; Pattern_Syntax # Pe RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER +298F ; Pattern_Syntax # Ps LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER +2990 ; Pattern_Syntax # Pe RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER +2991 ; Pattern_Syntax # Ps LEFT ANGLE BRACKET WITH DOT +2992 ; Pattern_Syntax # Pe RIGHT ANGLE BRACKET WITH DOT +2993 ; Pattern_Syntax # Ps LEFT ARC LESS-THAN BRACKET +2994 ; Pattern_Syntax # Pe RIGHT ARC GREATER-THAN BRACKET +2995 ; Pattern_Syntax # Ps DOUBLE LEFT ARC GREATER-THAN BRACKET +2996 ; Pattern_Syntax # Pe DOUBLE RIGHT ARC LESS-THAN BRACKET +2997 ; Pattern_Syntax # Ps LEFT BLACK TORTOISE SHELL BRACKET +2998 ; Pattern_Syntax # Pe RIGHT BLACK TORTOISE SHELL BRACKET +2999..29D7 ; Pattern_Syntax # Sm [63] DOTTED FENCE..BLACK HOURGLASS +29D8 ; Pattern_Syntax # Ps LEFT WIGGLY FENCE +29D9 ; Pattern_Syntax # Pe RIGHT WIGGLY FENCE +29DA ; Pattern_Syntax # Ps LEFT DOUBLE WIGGLY FENCE +29DB ; Pattern_Syntax # Pe RIGHT DOUBLE WIGGLY FENCE +29DC..29FB ; Pattern_Syntax # Sm [32] INCOMPLETE INFINITY..TRIPLE PLUS +29FC ; Pattern_Syntax # Ps LEFT-POINTING CURVED ANGLE BRACKET +29FD ; Pattern_Syntax # Pe RIGHT-POINTING CURVED ANGLE BRACKET +29FE..2AFF ; Pattern_Syntax # Sm [258] TINY..N-ARY WHITE VERTICAL BAR +2B00..2B2F ; Pattern_Syntax # So [48] NORTH EAST WHITE ARROW..WHITE VERTICAL ELLIPSE +2B30..2B44 ; Pattern_Syntax # Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET +2B45..2B46 ; Pattern_Syntax # So [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW +2B47..2B4C ; Pattern_Syntax # Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR +2B4D..2B73 ; Pattern_Syntax # So [39] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR +2B74..2B75 ; Pattern_Syntax # Cn [2] .. +2B76..2BFF ; Pattern_Syntax # So [138] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..HELLSCHREIBER PAUSE SYMBOL +2E00..2E01 ; Pattern_Syntax # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER +2E02 ; Pattern_Syntax # Pi LEFT SUBSTITUTION BRACKET +2E03 ; Pattern_Syntax # Pf RIGHT SUBSTITUTION BRACKET +2E04 ; Pattern_Syntax # Pi LEFT DOTTED SUBSTITUTION BRACKET +2E05 ; Pattern_Syntax # Pf RIGHT DOTTED SUBSTITUTION BRACKET +2E06..2E08 ; Pattern_Syntax # Po [3] RAISED INTERPOLATION MARKER..DOTTED TRANSPOSITION MARKER +2E09 ; Pattern_Syntax # Pi LEFT TRANSPOSITION BRACKET +2E0A ; Pattern_Syntax # Pf RIGHT TRANSPOSITION BRACKET +2E0B ; Pattern_Syntax # Po RAISED SQUARE +2E0C ; Pattern_Syntax # Pi LEFT RAISED OMISSION BRACKET +2E0D ; Pattern_Syntax # Pf RIGHT RAISED OMISSION BRACKET +2E0E..2E16 ; Pattern_Syntax # Po [9] EDITORIAL CORONIS..DOTTED RIGHT-POINTING ANGLE +2E17 ; Pattern_Syntax # Pd DOUBLE OBLIQUE HYPHEN +2E18..2E19 ; Pattern_Syntax # Po [2] INVERTED INTERROBANG..PALM BRANCH +2E1A ; Pattern_Syntax # Pd HYPHEN WITH DIAERESIS +2E1B ; Pattern_Syntax # Po TILDE WITH RING ABOVE +2E1C ; Pattern_Syntax # Pi LEFT LOW PARAPHRASE BRACKET +2E1D ; Pattern_Syntax # Pf RIGHT LOW PARAPHRASE BRACKET +2E1E..2E1F ; Pattern_Syntax # Po [2] TILDE WITH DOT ABOVE..TILDE WITH DOT BELOW +2E20 ; Pattern_Syntax # Pi LEFT VERTICAL BAR WITH QUILL +2E21 ; Pattern_Syntax # Pf RIGHT VERTICAL BAR WITH QUILL +2E22 ; Pattern_Syntax # Ps TOP LEFT HALF BRACKET +2E23 ; Pattern_Syntax # Pe TOP RIGHT HALF BRACKET +2E24 ; Pattern_Syntax # Ps BOTTOM LEFT HALF BRACKET +2E25 ; Pattern_Syntax # Pe BOTTOM RIGHT HALF BRACKET +2E26 ; Pattern_Syntax # Ps LEFT SIDEWAYS U BRACKET +2E27 ; Pattern_Syntax # Pe RIGHT SIDEWAYS U BRACKET +2E28 ; Pattern_Syntax # Ps LEFT DOUBLE PARENTHESIS +2E29 ; Pattern_Syntax # Pe RIGHT DOUBLE PARENTHESIS +2E2A..2E2E ; Pattern_Syntax # Po [5] TWO DOTS OVER ONE DOT PUNCTUATION..REVERSED QUESTION MARK +2E2F ; Pattern_Syntax # Lm VERTICAL TILDE +2E30..2E39 ; Pattern_Syntax # Po [10] RING POINT..TOP HALF SECTION SIGN +2E3A..2E3B ; Pattern_Syntax # Pd [2] TWO-EM DASH..THREE-EM DASH +2E3C..2E3F ; Pattern_Syntax # Po [4] STENOGRAPHIC FULL STOP..CAPITULUM +2E40 ; Pattern_Syntax # Pd DOUBLE HYPHEN +2E41 ; Pattern_Syntax # Po REVERSED COMMA +2E42 ; Pattern_Syntax # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK +2E43..2E4F ; Pattern_Syntax # Po [13] DASH WITH LEFT UPTURN..CORNISH VERSE DIVIDER +2E50..2E51 ; Pattern_Syntax # So [2] CROSS PATTY WITH RIGHT CROSSBAR..CROSS PATTY WITH LEFT CROSSBAR +2E52..2E54 ; Pattern_Syntax # Po [3] TIRONIAN SIGN CAPITAL ET..MEDIEVAL QUESTION MARK +2E55 ; Pattern_Syntax # Ps LEFT SQUARE BRACKET WITH STROKE +2E56 ; Pattern_Syntax # Pe RIGHT SQUARE BRACKET WITH STROKE +2E57 ; Pattern_Syntax # Ps LEFT SQUARE BRACKET WITH DOUBLE STROKE +2E58 ; Pattern_Syntax # Pe RIGHT SQUARE BRACKET WITH DOUBLE STROKE +2E59 ; Pattern_Syntax # Ps TOP HALF LEFT PARENTHESIS +2E5A ; Pattern_Syntax # Pe TOP HALF RIGHT PARENTHESIS +2E5B ; Pattern_Syntax # Ps BOTTOM HALF LEFT PARENTHESIS +2E5C ; Pattern_Syntax # Pe BOTTOM HALF RIGHT PARENTHESIS +2E5D ; Pattern_Syntax # Pd OBLIQUE HYPHEN +2E5E..2E7F ; Pattern_Syntax # Cn [34] .. +3001..3003 ; Pattern_Syntax # Po [3] IDEOGRAPHIC COMMA..DITTO MARK +3008 ; Pattern_Syntax # Ps LEFT ANGLE BRACKET +3009 ; Pattern_Syntax # Pe RIGHT ANGLE BRACKET +300A ; Pattern_Syntax # Ps LEFT DOUBLE ANGLE BRACKET +300B ; Pattern_Syntax # Pe RIGHT DOUBLE ANGLE BRACKET +300C ; Pattern_Syntax # Ps LEFT CORNER BRACKET +300D ; Pattern_Syntax # Pe RIGHT CORNER BRACKET +300E ; Pattern_Syntax # Ps LEFT WHITE CORNER BRACKET +300F ; Pattern_Syntax # Pe RIGHT WHITE CORNER BRACKET +3010 ; Pattern_Syntax # Ps LEFT BLACK LENTICULAR BRACKET +3011 ; Pattern_Syntax # Pe RIGHT BLACK LENTICULAR BRACKET +3012..3013 ; Pattern_Syntax # So [2] POSTAL MARK..GETA MARK +3014 ; Pattern_Syntax # Ps LEFT TORTOISE SHELL BRACKET +3015 ; Pattern_Syntax # Pe RIGHT TORTOISE SHELL BRACKET +3016 ; Pattern_Syntax # Ps LEFT WHITE LENTICULAR BRACKET +3017 ; Pattern_Syntax # Pe RIGHT WHITE LENTICULAR BRACKET +3018 ; Pattern_Syntax # Ps LEFT WHITE TORTOISE SHELL BRACKET +3019 ; Pattern_Syntax # Pe RIGHT WHITE TORTOISE SHELL BRACKET +301A ; Pattern_Syntax # Ps LEFT WHITE SQUARE BRACKET +301B ; Pattern_Syntax # Pe RIGHT WHITE SQUARE BRACKET +301C ; Pattern_Syntax # Pd WAVE DASH +301D ; Pattern_Syntax # Ps REVERSED DOUBLE PRIME QUOTATION MARK +301E..301F ; Pattern_Syntax # Pe [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK +3020 ; Pattern_Syntax # So POSTAL MARK FACE +3030 ; Pattern_Syntax # Pd WAVY DASH +FD3E ; Pattern_Syntax # Pe ORNATE LEFT PARENTHESIS +FD3F ; Pattern_Syntax # Ps ORNATE RIGHT PARENTHESIS +FE45..FE46 ; Pattern_Syntax # Po [2] SESAME DOT..WHITE SESAME DOT + +# Total code points: 2760 + +# ================================================ + +0600..0605 ; Prepended_Concatenation_Mark # Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE +06DD ; Prepended_Concatenation_Mark # Cf ARABIC END OF AYAH +070F ; Prepended_Concatenation_Mark # Cf SYRIAC ABBREVIATION MARK +0890..0891 ; Prepended_Concatenation_Mark # Cf [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE +08E2 ; Prepended_Concatenation_Mark # Cf ARABIC DISPUTED END OF AYAH +110BD ; Prepended_Concatenation_Mark # Cf KAITHI NUMBER SIGN +110CD ; Prepended_Concatenation_Mark # Cf KAITHI NUMBER SIGN ABOVE + +# Total code points: 13 + +# ================================================ + +1F1E6..1F1FF ; Regional_Indicator # So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z + +# Total code points: 26 + +# ================================================ + +0654..0655 ; Modifier_Combining_Mark # Mn [2] ARABIC HAMZA ABOVE..ARABIC HAMZA BELOW +0658 ; Modifier_Combining_Mark # Mn ARABIC MARK NOON GHUNNA +06DC ; Modifier_Combining_Mark # Mn ARABIC SMALL HIGH SEEN +06E3 ; Modifier_Combining_Mark # Mn ARABIC SMALL LOW SEEN +06E7..06E8 ; Modifier_Combining_Mark # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON +08CA..08CB ; Modifier_Combining_Mark # Mn [2] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH YEH BARREE WITH TWO DOTS BELOW +08CD..08CF ; Modifier_Combining_Mark # Mn [3] ARABIC SMALL HIGH ZAH..ARABIC LARGE ROUND DOT BELOW +08D3 ; Modifier_Combining_Mark # Mn ARABIC SMALL LOW WAW +08F3 ; Modifier_Combining_Mark # Mn ARABIC SMALL HIGH WAW + +# Total code points: 14 + +# EOF diff --git a/tests/core/assets/UCD/UnicodeData.txt b/tests/core/assets/UCD/UnicodeData.txt new file mode 100644 index 000000000..fca68e3e1 --- /dev/null +++ b/tests/core/assets/UCD/UnicodeData.txt @@ -0,0 +1,40575 @@ +0000;;Cc;0;BN;;;;;N;NULL;;;; +0001;;Cc;0;BN;;;;;N;START OF HEADING;;;; +0002;;Cc;0;BN;;;;;N;START OF TEXT;;;; +0003;;Cc;0;BN;;;;;N;END OF TEXT;;;; +0004;;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; +0005;;Cc;0;BN;;;;;N;ENQUIRY;;;; +0006;;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; +0007;;Cc;0;BN;;;;;N;BELL;;;; +0008;;Cc;0;BN;;;;;N;BACKSPACE;;;; +0009;;Cc;0;S;;;;;N;CHARACTER TABULATION;;;; +000A;;Cc;0;B;;;;;N;LINE FEED (LF);;;; +000B;;Cc;0;S;;;;;N;LINE TABULATION;;;; +000C;;Cc;0;WS;;;;;N;FORM FEED (FF);;;; +000D;;Cc;0;B;;;;;N;CARRIAGE RETURN (CR);;;; +000E;;Cc;0;BN;;;;;N;SHIFT OUT;;;; +000F;;Cc;0;BN;;;;;N;SHIFT IN;;;; +0010;;Cc;0;BN;;;;;N;DATA LINK ESCAPE;;;; +0011;;Cc;0;BN;;;;;N;DEVICE CONTROL ONE;;;; +0012;;Cc;0;BN;;;;;N;DEVICE CONTROL TWO;;;; +0013;;Cc;0;BN;;;;;N;DEVICE CONTROL THREE;;;; +0014;;Cc;0;BN;;;;;N;DEVICE CONTROL FOUR;;;; +0015;;Cc;0;BN;;;;;N;NEGATIVE ACKNOWLEDGE;;;; +0016;;Cc;0;BN;;;;;N;SYNCHRONOUS IDLE;;;; +0017;;Cc;0;BN;;;;;N;END OF TRANSMISSION BLOCK;;;; +0018;;Cc;0;BN;;;;;N;CANCEL;;;; +0019;;Cc;0;BN;;;;;N;END OF MEDIUM;;;; +001A;;Cc;0;BN;;;;;N;SUBSTITUTE;;;; +001B;;Cc;0;BN;;;;;N;ESCAPE;;;; +001C;;Cc;0;B;;;;;N;INFORMATION SEPARATOR FOUR;;;; +001D;;Cc;0;B;;;;;N;INFORMATION SEPARATOR THREE;;;; +001E;;Cc;0;B;;;;;N;INFORMATION SEPARATOR TWO;;;; +001F;;Cc;0;S;;;;;N;INFORMATION SEPARATOR ONE;;;; +0020;SPACE;Zs;0;WS;;;;;N;;;;; +0021;EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; +0022;QUOTATION MARK;Po;0;ON;;;;;N;;;;; +0023;NUMBER SIGN;Po;0;ET;;;;;N;;;;; +0024;DOLLAR SIGN;Sc;0;ET;;;;;N;;;;; +0025;PERCENT SIGN;Po;0;ET;;;;;N;;;;; +0026;AMPERSAND;Po;0;ON;;;;;N;;;;; +0027;APOSTROPHE;Po;0;ON;;;;;N;APOSTROPHE-QUOTE;;;; +0028;LEFT PARENTHESIS;Ps;0;ON;;;;;Y;OPENING PARENTHESIS;;;; +0029;RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;CLOSING PARENTHESIS;;;; +002A;ASTERISK;Po;0;ON;;;;;N;;;;; +002B;PLUS SIGN;Sm;0;ES;;;;;N;;;;; +002C;COMMA;Po;0;CS;;;;;N;;;;; +002D;HYPHEN-MINUS;Pd;0;ES;;;;;N;;;;; +002E;FULL STOP;Po;0;CS;;;;;N;PERIOD;;;; +002F;SOLIDUS;Po;0;CS;;;;;N;SLASH;;;; +0030;DIGIT ZERO;Nd;0;EN;;0;0;0;N;;;;; +0031;DIGIT ONE;Nd;0;EN;;1;1;1;N;;;;; +0032;DIGIT TWO;Nd;0;EN;;2;2;2;N;;;;; +0033;DIGIT THREE;Nd;0;EN;;3;3;3;N;;;;; +0034;DIGIT FOUR;Nd;0;EN;;4;4;4;N;;;;; +0035;DIGIT FIVE;Nd;0;EN;;5;5;5;N;;;;; +0036;DIGIT SIX;Nd;0;EN;;6;6;6;N;;;;; +0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;; +0038;DIGIT EIGHT;Nd;0;EN;;8;8;8;N;;;;; +0039;DIGIT NINE;Nd;0;EN;;9;9;9;N;;;;; +003A;COLON;Po;0;CS;;;;;N;;;;; +003B;SEMICOLON;Po;0;ON;;;;;N;;;;; +003C;LESS-THAN SIGN;Sm;0;ON;;;;;Y;;;;; +003D;EQUALS SIGN;Sm;0;ON;;;;;N;;;;; +003E;GREATER-THAN SIGN;Sm;0;ON;;;;;Y;;;;; +003F;QUESTION MARK;Po;0;ON;;;;;N;;;;; +0040;COMMERCIAL AT;Po;0;ON;;;;;N;;;;; +0041;LATIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0061; +0042;LATIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;0062; +0043;LATIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;0063; +0044;LATIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;0064; +0045;LATIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;0065; +0046;LATIN CAPITAL LETTER F;Lu;0;L;;;;;N;;;;0066; +0047;LATIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;0067; +0048;LATIN CAPITAL LETTER H;Lu;0;L;;;;;N;;;;0068; +0049;LATIN CAPITAL LETTER I;Lu;0;L;;;;;N;;;;0069; +004A;LATIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;006A; +004B;LATIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;006B; +004C;LATIN CAPITAL LETTER L;Lu;0;L;;;;;N;;;;006C; +004D;LATIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;006D; +004E;LATIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;006E; +004F;LATIN CAPITAL LETTER O;Lu;0;L;;;;;N;;;;006F; +0050;LATIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;0070; +0051;LATIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;0071; +0052;LATIN CAPITAL LETTER R;Lu;0;L;;;;;N;;;;0072; +0053;LATIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;0073; +0054;LATIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;0074; +0055;LATIN CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0075; +0056;LATIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;0076; +0057;LATIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;0077; +0058;LATIN CAPITAL LETTER X;Lu;0;L;;;;;N;;;;0078; +0059;LATIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;0079; +005A;LATIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;007A; +005B;LEFT SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING SQUARE BRACKET;;;; +005C;REVERSE SOLIDUS;Po;0;ON;;;;;N;BACKSLASH;;;; +005D;RIGHT SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING SQUARE BRACKET;;;; +005E;CIRCUMFLEX ACCENT;Sk;0;ON;;;;;N;SPACING CIRCUMFLEX;;;; +005F;LOW LINE;Pc;0;ON;;;;;N;SPACING UNDERSCORE;;;; +0060;GRAVE ACCENT;Sk;0;ON;;;;;N;SPACING GRAVE;;;; +0061;LATIN SMALL LETTER A;Ll;0;L;;;;;N;;;0041;;0041 +0062;LATIN SMALL LETTER B;Ll;0;L;;;;;N;;;0042;;0042 +0063;LATIN SMALL LETTER C;Ll;0;L;;;;;N;;;0043;;0043 +0064;LATIN SMALL LETTER D;Ll;0;L;;;;;N;;;0044;;0044 +0065;LATIN SMALL LETTER E;Ll;0;L;;;;;N;;;0045;;0045 +0066;LATIN SMALL LETTER F;Ll;0;L;;;;;N;;;0046;;0046 +0067;LATIN SMALL LETTER G;Ll;0;L;;;;;N;;;0047;;0047 +0068;LATIN SMALL LETTER H;Ll;0;L;;;;;N;;;0048;;0048 +0069;LATIN SMALL LETTER I;Ll;0;L;;;;;N;;;0049;;0049 +006A;LATIN SMALL LETTER J;Ll;0;L;;;;;N;;;004A;;004A +006B;LATIN SMALL LETTER K;Ll;0;L;;;;;N;;;004B;;004B +006C;LATIN SMALL LETTER L;Ll;0;L;;;;;N;;;004C;;004C +006D;LATIN SMALL LETTER M;Ll;0;L;;;;;N;;;004D;;004D +006E;LATIN SMALL LETTER N;Ll;0;L;;;;;N;;;004E;;004E +006F;LATIN SMALL LETTER O;Ll;0;L;;;;;N;;;004F;;004F +0070;LATIN SMALL LETTER P;Ll;0;L;;;;;N;;;0050;;0050 +0071;LATIN SMALL LETTER Q;Ll;0;L;;;;;N;;;0051;;0051 +0072;LATIN SMALL LETTER R;Ll;0;L;;;;;N;;;0052;;0052 +0073;LATIN SMALL LETTER S;Ll;0;L;;;;;N;;;0053;;0053 +0074;LATIN SMALL LETTER T;Ll;0;L;;;;;N;;;0054;;0054 +0075;LATIN SMALL LETTER U;Ll;0;L;;;;;N;;;0055;;0055 +0076;LATIN SMALL LETTER V;Ll;0;L;;;;;N;;;0056;;0056 +0077;LATIN SMALL LETTER W;Ll;0;L;;;;;N;;;0057;;0057 +0078;LATIN SMALL LETTER X;Ll;0;L;;;;;N;;;0058;;0058 +0079;LATIN SMALL LETTER Y;Ll;0;L;;;;;N;;;0059;;0059 +007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A +007B;LEFT CURLY BRACKET;Ps;0;ON;;;;;Y;OPENING CURLY BRACKET;;;; +007C;VERTICAL LINE;Sm;0;ON;;;;;N;VERTICAL BAR;;;; +007D;RIGHT CURLY BRACKET;Pe;0;ON;;;;;Y;CLOSING CURLY BRACKET;;;; +007E;TILDE;Sm;0;ON;;;;;N;;;;; +007F;;Cc;0;BN;;;;;N;DELETE;;;; +0080;;Cc;0;BN;;;;;N;;;;; +0081;;Cc;0;BN;;;;;N;;;;; +0082;;Cc;0;BN;;;;;N;BREAK PERMITTED HERE;;;; +0083;;Cc;0;BN;;;;;N;NO BREAK HERE;;;; +0084;;Cc;0;BN;;;;;N;;;;; +0085;;Cc;0;B;;;;;N;NEXT LINE (NEL);;;; +0086;;Cc;0;BN;;;;;N;START OF SELECTED AREA;;;; +0087;;Cc;0;BN;;;;;N;END OF SELECTED AREA;;;; +0088;;Cc;0;BN;;;;;N;CHARACTER TABULATION SET;;;; +0089;;Cc;0;BN;;;;;N;CHARACTER TABULATION WITH JUSTIFICATION;;;; +008A;;Cc;0;BN;;;;;N;LINE TABULATION SET;;;; +008B;;Cc;0;BN;;;;;N;PARTIAL LINE FORWARD;;;; +008C;;Cc;0;BN;;;;;N;PARTIAL LINE BACKWARD;;;; +008D;;Cc;0;BN;;;;;N;REVERSE LINE FEED;;;; +008E;;Cc;0;BN;;;;;N;SINGLE SHIFT TWO;;;; +008F;;Cc;0;BN;;;;;N;SINGLE SHIFT THREE;;;; +0090;;Cc;0;BN;;;;;N;DEVICE CONTROL STRING;;;; +0091;;Cc;0;BN;;;;;N;PRIVATE USE ONE;;;; +0092;;Cc;0;BN;;;;;N;PRIVATE USE TWO;;;; +0093;;Cc;0;BN;;;;;N;SET TRANSMIT STATE;;;; +0094;;Cc;0;BN;;;;;N;CANCEL CHARACTER;;;; +0095;;Cc;0;BN;;;;;N;MESSAGE WAITING;;;; +0096;;Cc;0;BN;;;;;N;START OF GUARDED AREA;;;; +0097;;Cc;0;BN;;;;;N;END OF GUARDED AREA;;;; +0098;;Cc;0;BN;;;;;N;START OF STRING;;;; +0099;;Cc;0;BN;;;;;N;;;;; +009A;;Cc;0;BN;;;;;N;SINGLE CHARACTER INTRODUCER;;;; +009B;;Cc;0;BN;;;;;N;CONTROL SEQUENCE INTRODUCER;;;; +009C;;Cc;0;BN;;;;;N;STRING TERMINATOR;;;; +009D;;Cc;0;BN;;;;;N;OPERATING SYSTEM COMMAND;;;; +009E;;Cc;0;BN;;;;;N;PRIVACY MESSAGE;;;; +009F;;Cc;0;BN;;;;;N;APPLICATION PROGRAM COMMAND;;;; +00A0;NO-BREAK SPACE;Zs;0;CS; 0020;;;;N;NON-BREAKING SPACE;;;; +00A1;INVERTED EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; +00A2;CENT SIGN;Sc;0;ET;;;;;N;;;;; +00A3;POUND SIGN;Sc;0;ET;;;;;N;;;;; +00A4;CURRENCY SIGN;Sc;0;ET;;;;;N;;;;; +00A5;YEN SIGN;Sc;0;ET;;;;;N;;;;; +00A6;BROKEN BAR;So;0;ON;;;;;N;BROKEN VERTICAL BAR;;;; +00A7;SECTION SIGN;Po;0;ON;;;;;N;;;;; +00A8;DIAERESIS;Sk;0;ON; 0020 0308;;;;N;SPACING DIAERESIS;;;; +00A9;COPYRIGHT SIGN;So;0;ON;;;;;N;;;;; +00AA;FEMININE ORDINAL INDICATOR;Lo;0;L; 0061;;;;N;;;;; +00AB;LEFT-POINTING DOUBLE ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING GUILLEMET;;;; +00AC;NOT SIGN;Sm;0;ON;;;;;N;;;;; +00AD;SOFT HYPHEN;Cf;0;BN;;;;;N;;;;; +00AE;REGISTERED SIGN;So;0;ON;;;;;N;REGISTERED TRADE MARK SIGN;;;; +00AF;MACRON;Sk;0;ON; 0020 0304;;;;N;SPACING MACRON;;;; +00B0;DEGREE SIGN;So;0;ET;;;;;N;;;;; +00B1;PLUS-MINUS SIGN;Sm;0;ET;;;;;N;PLUS-OR-MINUS SIGN;;;; +00B2;SUPERSCRIPT TWO;No;0;EN; 0032;;2;2;N;SUPERSCRIPT DIGIT TWO;;;; +00B3;SUPERSCRIPT THREE;No;0;EN; 0033;;3;3;N;SUPERSCRIPT DIGIT THREE;;;; +00B4;ACUTE ACCENT;Sk;0;ON; 0020 0301;;;;N;SPACING ACUTE;;;; +00B5;MICRO SIGN;Ll;0;L; 03BC;;;;N;;;039C;;039C +00B6;PILCROW SIGN;Po;0;ON;;;;;N;PARAGRAPH SIGN;;;; +00B7;MIDDLE DOT;Po;0;ON;;;;;N;;;;; +00B8;CEDILLA;Sk;0;ON; 0020 0327;;;;N;SPACING CEDILLA;;;; +00B9;SUPERSCRIPT ONE;No;0;EN; 0031;;1;1;N;SUPERSCRIPT DIGIT ONE;;;; +00BA;MASCULINE ORDINAL INDICATOR;Lo;0;L; 006F;;;;N;;;;; +00BB;RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING GUILLEMET;;;; +00BC;VULGAR FRACTION ONE QUARTER;No;0;ON; 0031 2044 0034;;;1/4;N;FRACTION ONE QUARTER;;;; +00BD;VULGAR FRACTION ONE HALF;No;0;ON; 0031 2044 0032;;;1/2;N;FRACTION ONE HALF;;;; +00BE;VULGAR FRACTION THREE QUARTERS;No;0;ON; 0033 2044 0034;;;3/4;N;FRACTION THREE QUARTERS;;;; +00BF;INVERTED QUESTION MARK;Po;0;ON;;;;;N;;;;; +00C0;LATIN CAPITAL LETTER A WITH GRAVE;Lu;0;L;0041 0300;;;;N;LATIN CAPITAL LETTER A GRAVE;;;00E0; +00C1;LATIN CAPITAL LETTER A WITH ACUTE;Lu;0;L;0041 0301;;;;N;LATIN CAPITAL LETTER A ACUTE;;;00E1; +00C2;LATIN CAPITAL LETTER A WITH CIRCUMFLEX;Lu;0;L;0041 0302;;;;N;LATIN CAPITAL LETTER A CIRCUMFLEX;;;00E2; +00C3;LATIN CAPITAL LETTER A WITH TILDE;Lu;0;L;0041 0303;;;;N;LATIN CAPITAL LETTER A TILDE;;;00E3; +00C4;LATIN CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0041 0308;;;;N;LATIN CAPITAL LETTER A DIAERESIS;;;00E4; +00C5;LATIN CAPITAL LETTER A WITH RING ABOVE;Lu;0;L;0041 030A;;;;N;LATIN CAPITAL LETTER A RING;;;00E5; +00C6;LATIN CAPITAL LETTER AE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER A E;;;00E6; +00C7;LATIN CAPITAL LETTER C WITH CEDILLA;Lu;0;L;0043 0327;;;;N;LATIN CAPITAL LETTER C CEDILLA;;;00E7; +00C8;LATIN CAPITAL LETTER E WITH GRAVE;Lu;0;L;0045 0300;;;;N;LATIN CAPITAL LETTER E GRAVE;;;00E8; +00C9;LATIN CAPITAL LETTER E WITH ACUTE;Lu;0;L;0045 0301;;;;N;LATIN CAPITAL LETTER E ACUTE;;;00E9; +00CA;LATIN CAPITAL LETTER E WITH CIRCUMFLEX;Lu;0;L;0045 0302;;;;N;LATIN CAPITAL LETTER E CIRCUMFLEX;;;00EA; +00CB;LATIN CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;0045 0308;;;;N;LATIN CAPITAL LETTER E DIAERESIS;;;00EB; +00CC;LATIN CAPITAL LETTER I WITH GRAVE;Lu;0;L;0049 0300;;;;N;LATIN CAPITAL LETTER I GRAVE;;;00EC; +00CD;LATIN CAPITAL LETTER I WITH ACUTE;Lu;0;L;0049 0301;;;;N;LATIN CAPITAL LETTER I ACUTE;;;00ED; +00CE;LATIN CAPITAL LETTER I WITH CIRCUMFLEX;Lu;0;L;0049 0302;;;;N;LATIN CAPITAL LETTER I CIRCUMFLEX;;;00EE; +00CF;LATIN CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0049 0308;;;;N;LATIN CAPITAL LETTER I DIAERESIS;;;00EF; +00D0;LATIN CAPITAL LETTER ETH;Lu;0;L;;;;;N;;;;00F0; +00D1;LATIN CAPITAL LETTER N WITH TILDE;Lu;0;L;004E 0303;;;;N;LATIN CAPITAL LETTER N TILDE;;;00F1; +00D2;LATIN CAPITAL LETTER O WITH GRAVE;Lu;0;L;004F 0300;;;;N;LATIN CAPITAL LETTER O GRAVE;;;00F2; +00D3;LATIN CAPITAL LETTER O WITH ACUTE;Lu;0;L;004F 0301;;;;N;LATIN CAPITAL LETTER O ACUTE;;;00F3; +00D4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX;Lu;0;L;004F 0302;;;;N;LATIN CAPITAL LETTER O CIRCUMFLEX;;;00F4; +00D5;LATIN CAPITAL LETTER O WITH TILDE;Lu;0;L;004F 0303;;;;N;LATIN CAPITAL LETTER O TILDE;;;00F5; +00D6;LATIN CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;004F 0308;;;;N;LATIN CAPITAL LETTER O DIAERESIS;;;00F6; +00D7;MULTIPLICATION SIGN;Sm;0;ON;;;;;N;;;;; +00D8;LATIN CAPITAL LETTER O WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O SLASH;;;00F8; +00D9;LATIN CAPITAL LETTER U WITH GRAVE;Lu;0;L;0055 0300;;;;N;LATIN CAPITAL LETTER U GRAVE;;;00F9; +00DA;LATIN CAPITAL LETTER U WITH ACUTE;Lu;0;L;0055 0301;;;;N;LATIN CAPITAL LETTER U ACUTE;;;00FA; +00DB;LATIN CAPITAL LETTER U WITH CIRCUMFLEX;Lu;0;L;0055 0302;;;;N;LATIN CAPITAL LETTER U CIRCUMFLEX;;;00FB; +00DC;LATIN CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0055 0308;;;;N;LATIN CAPITAL LETTER U DIAERESIS;;;00FC; +00DD;LATIN CAPITAL LETTER Y WITH ACUTE;Lu;0;L;0059 0301;;;;N;LATIN CAPITAL LETTER Y ACUTE;;;00FD; +00DE;LATIN CAPITAL LETTER THORN;Lu;0;L;;;;;N;;;;00FE; +00DF;LATIN SMALL LETTER SHARP S;Ll;0;L;;;;;N;;;;; +00E0;LATIN SMALL LETTER A WITH GRAVE;Ll;0;L;0061 0300;;;;N;LATIN SMALL LETTER A GRAVE;;00C0;;00C0 +00E1;LATIN SMALL LETTER A WITH ACUTE;Ll;0;L;0061 0301;;;;N;LATIN SMALL LETTER A ACUTE;;00C1;;00C1 +00E2;LATIN SMALL LETTER A WITH CIRCUMFLEX;Ll;0;L;0061 0302;;;;N;LATIN SMALL LETTER A CIRCUMFLEX;;00C2;;00C2 +00E3;LATIN SMALL LETTER A WITH TILDE;Ll;0;L;0061 0303;;;;N;LATIN SMALL LETTER A TILDE;;00C3;;00C3 +00E4;LATIN SMALL LETTER A WITH DIAERESIS;Ll;0;L;0061 0308;;;;N;LATIN SMALL LETTER A DIAERESIS;;00C4;;00C4 +00E5;LATIN SMALL LETTER A WITH RING ABOVE;Ll;0;L;0061 030A;;;;N;LATIN SMALL LETTER A RING;;00C5;;00C5 +00E6;LATIN SMALL LETTER AE;Ll;0;L;;;;;N;LATIN SMALL LETTER A E;;00C6;;00C6 +00E7;LATIN SMALL LETTER C WITH CEDILLA;Ll;0;L;0063 0327;;;;N;LATIN SMALL LETTER C CEDILLA;;00C7;;00C7 +00E8;LATIN SMALL LETTER E WITH GRAVE;Ll;0;L;0065 0300;;;;N;LATIN SMALL LETTER E GRAVE;;00C8;;00C8 +00E9;LATIN SMALL LETTER E WITH ACUTE;Ll;0;L;0065 0301;;;;N;LATIN SMALL LETTER E ACUTE;;00C9;;00C9 +00EA;LATIN SMALL LETTER E WITH CIRCUMFLEX;Ll;0;L;0065 0302;;;;N;LATIN SMALL LETTER E CIRCUMFLEX;;00CA;;00CA +00EB;LATIN SMALL LETTER E WITH DIAERESIS;Ll;0;L;0065 0308;;;;N;LATIN SMALL LETTER E DIAERESIS;;00CB;;00CB +00EC;LATIN SMALL LETTER I WITH GRAVE;Ll;0;L;0069 0300;;;;N;LATIN SMALL LETTER I GRAVE;;00CC;;00CC +00ED;LATIN SMALL LETTER I WITH ACUTE;Ll;0;L;0069 0301;;;;N;LATIN SMALL LETTER I ACUTE;;00CD;;00CD +00EE;LATIN SMALL LETTER I WITH CIRCUMFLEX;Ll;0;L;0069 0302;;;;N;LATIN SMALL LETTER I CIRCUMFLEX;;00CE;;00CE +00EF;LATIN SMALL LETTER I WITH DIAERESIS;Ll;0;L;0069 0308;;;;N;LATIN SMALL LETTER I DIAERESIS;;00CF;;00CF +00F0;LATIN SMALL LETTER ETH;Ll;0;L;;;;;N;;;00D0;;00D0 +00F1;LATIN SMALL LETTER N WITH TILDE;Ll;0;L;006E 0303;;;;N;LATIN SMALL LETTER N TILDE;;00D1;;00D1 +00F2;LATIN SMALL LETTER O WITH GRAVE;Ll;0;L;006F 0300;;;;N;LATIN SMALL LETTER O GRAVE;;00D2;;00D2 +00F3;LATIN SMALL LETTER O WITH ACUTE;Ll;0;L;006F 0301;;;;N;LATIN SMALL LETTER O ACUTE;;00D3;;00D3 +00F4;LATIN SMALL LETTER O WITH CIRCUMFLEX;Ll;0;L;006F 0302;;;;N;LATIN SMALL LETTER O CIRCUMFLEX;;00D4;;00D4 +00F5;LATIN SMALL LETTER O WITH TILDE;Ll;0;L;006F 0303;;;;N;LATIN SMALL LETTER O TILDE;;00D5;;00D5 +00F6;LATIN SMALL LETTER O WITH DIAERESIS;Ll;0;L;006F 0308;;;;N;LATIN SMALL LETTER O DIAERESIS;;00D6;;00D6 +00F7;DIVISION SIGN;Sm;0;ON;;;;;N;;;;; +00F8;LATIN SMALL LETTER O WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER O SLASH;;00D8;;00D8 +00F9;LATIN SMALL LETTER U WITH GRAVE;Ll;0;L;0075 0300;;;;N;LATIN SMALL LETTER U GRAVE;;00D9;;00D9 +00FA;LATIN SMALL LETTER U WITH ACUTE;Ll;0;L;0075 0301;;;;N;LATIN SMALL LETTER U ACUTE;;00DA;;00DA +00FB;LATIN SMALL LETTER U WITH CIRCUMFLEX;Ll;0;L;0075 0302;;;;N;LATIN SMALL LETTER U CIRCUMFLEX;;00DB;;00DB +00FC;LATIN SMALL LETTER U WITH DIAERESIS;Ll;0;L;0075 0308;;;;N;LATIN SMALL LETTER U DIAERESIS;;00DC;;00DC +00FD;LATIN SMALL LETTER Y WITH ACUTE;Ll;0;L;0079 0301;;;;N;LATIN SMALL LETTER Y ACUTE;;00DD;;00DD +00FE;LATIN SMALL LETTER THORN;Ll;0;L;;;;;N;;;00DE;;00DE +00FF;LATIN SMALL LETTER Y WITH DIAERESIS;Ll;0;L;0079 0308;;;;N;LATIN SMALL LETTER Y DIAERESIS;;0178;;0178 +0100;LATIN CAPITAL LETTER A WITH MACRON;Lu;0;L;0041 0304;;;;N;LATIN CAPITAL LETTER A MACRON;;;0101; +0101;LATIN SMALL LETTER A WITH MACRON;Ll;0;L;0061 0304;;;;N;LATIN SMALL LETTER A MACRON;;0100;;0100 +0102;LATIN CAPITAL LETTER A WITH BREVE;Lu;0;L;0041 0306;;;;N;LATIN CAPITAL LETTER A BREVE;;;0103; +0103;LATIN SMALL LETTER A WITH BREVE;Ll;0;L;0061 0306;;;;N;LATIN SMALL LETTER A BREVE;;0102;;0102 +0104;LATIN CAPITAL LETTER A WITH OGONEK;Lu;0;L;0041 0328;;;;N;LATIN CAPITAL LETTER A OGONEK;;;0105; +0105;LATIN SMALL LETTER A WITH OGONEK;Ll;0;L;0061 0328;;;;N;LATIN SMALL LETTER A OGONEK;;0104;;0104 +0106;LATIN CAPITAL LETTER C WITH ACUTE;Lu;0;L;0043 0301;;;;N;LATIN CAPITAL LETTER C ACUTE;;;0107; +0107;LATIN SMALL LETTER C WITH ACUTE;Ll;0;L;0063 0301;;;;N;LATIN SMALL LETTER C ACUTE;;0106;;0106 +0108;LATIN CAPITAL LETTER C WITH CIRCUMFLEX;Lu;0;L;0043 0302;;;;N;LATIN CAPITAL LETTER C CIRCUMFLEX;;;0109; +0109;LATIN SMALL LETTER C WITH CIRCUMFLEX;Ll;0;L;0063 0302;;;;N;LATIN SMALL LETTER C CIRCUMFLEX;;0108;;0108 +010A;LATIN CAPITAL LETTER C WITH DOT ABOVE;Lu;0;L;0043 0307;;;;N;LATIN CAPITAL LETTER C DOT;;;010B; +010B;LATIN SMALL LETTER C WITH DOT ABOVE;Ll;0;L;0063 0307;;;;N;LATIN SMALL LETTER C DOT;;010A;;010A +010C;LATIN CAPITAL LETTER C WITH CARON;Lu;0;L;0043 030C;;;;N;LATIN CAPITAL LETTER C HACEK;;;010D; +010D;LATIN SMALL LETTER C WITH CARON;Ll;0;L;0063 030C;;;;N;LATIN SMALL LETTER C HACEK;;010C;;010C +010E;LATIN CAPITAL LETTER D WITH CARON;Lu;0;L;0044 030C;;;;N;LATIN CAPITAL LETTER D HACEK;;;010F; +010F;LATIN SMALL LETTER D WITH CARON;Ll;0;L;0064 030C;;;;N;LATIN SMALL LETTER D HACEK;;010E;;010E +0110;LATIN CAPITAL LETTER D WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D BAR;;;0111; +0111;LATIN SMALL LETTER D WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER D BAR;;0110;;0110 +0112;LATIN CAPITAL LETTER E WITH MACRON;Lu;0;L;0045 0304;;;;N;LATIN CAPITAL LETTER E MACRON;;;0113; +0113;LATIN SMALL LETTER E WITH MACRON;Ll;0;L;0065 0304;;;;N;LATIN SMALL LETTER E MACRON;;0112;;0112 +0114;LATIN CAPITAL LETTER E WITH BREVE;Lu;0;L;0045 0306;;;;N;LATIN CAPITAL LETTER E BREVE;;;0115; +0115;LATIN SMALL LETTER E WITH BREVE;Ll;0;L;0065 0306;;;;N;LATIN SMALL LETTER E BREVE;;0114;;0114 +0116;LATIN CAPITAL LETTER E WITH DOT ABOVE;Lu;0;L;0045 0307;;;;N;LATIN CAPITAL LETTER E DOT;;;0117; +0117;LATIN SMALL LETTER E WITH DOT ABOVE;Ll;0;L;0065 0307;;;;N;LATIN SMALL LETTER E DOT;;0116;;0116 +0118;LATIN CAPITAL LETTER E WITH OGONEK;Lu;0;L;0045 0328;;;;N;LATIN CAPITAL LETTER E OGONEK;;;0119; +0119;LATIN SMALL LETTER E WITH OGONEK;Ll;0;L;0065 0328;;;;N;LATIN SMALL LETTER E OGONEK;;0118;;0118 +011A;LATIN CAPITAL LETTER E WITH CARON;Lu;0;L;0045 030C;;;;N;LATIN CAPITAL LETTER E HACEK;;;011B; +011B;LATIN SMALL LETTER E WITH CARON;Ll;0;L;0065 030C;;;;N;LATIN SMALL LETTER E HACEK;;011A;;011A +011C;LATIN CAPITAL LETTER G WITH CIRCUMFLEX;Lu;0;L;0047 0302;;;;N;LATIN CAPITAL LETTER G CIRCUMFLEX;;;011D; +011D;LATIN SMALL LETTER G WITH CIRCUMFLEX;Ll;0;L;0067 0302;;;;N;LATIN SMALL LETTER G CIRCUMFLEX;;011C;;011C +011E;LATIN CAPITAL LETTER G WITH BREVE;Lu;0;L;0047 0306;;;;N;LATIN CAPITAL LETTER G BREVE;;;011F; +011F;LATIN SMALL LETTER G WITH BREVE;Ll;0;L;0067 0306;;;;N;LATIN SMALL LETTER G BREVE;;011E;;011E +0120;LATIN CAPITAL LETTER G WITH DOT ABOVE;Lu;0;L;0047 0307;;;;N;LATIN CAPITAL LETTER G DOT;;;0121; +0121;LATIN SMALL LETTER G WITH DOT ABOVE;Ll;0;L;0067 0307;;;;N;LATIN SMALL LETTER G DOT;;0120;;0120 +0122;LATIN CAPITAL LETTER G WITH CEDILLA;Lu;0;L;0047 0327;;;;N;LATIN CAPITAL LETTER G CEDILLA;;;0123; +0123;LATIN SMALL LETTER G WITH CEDILLA;Ll;0;L;0067 0327;;;;N;LATIN SMALL LETTER G CEDILLA;;0122;;0122 +0124;LATIN CAPITAL LETTER H WITH CIRCUMFLEX;Lu;0;L;0048 0302;;;;N;LATIN CAPITAL LETTER H CIRCUMFLEX;;;0125; +0125;LATIN SMALL LETTER H WITH CIRCUMFLEX;Ll;0;L;0068 0302;;;;N;LATIN SMALL LETTER H CIRCUMFLEX;;0124;;0124 +0126;LATIN CAPITAL LETTER H WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER H BAR;;;0127; +0127;LATIN SMALL LETTER H WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER H BAR;;0126;;0126 +0128;LATIN CAPITAL LETTER I WITH TILDE;Lu;0;L;0049 0303;;;;N;LATIN CAPITAL LETTER I TILDE;;;0129; +0129;LATIN SMALL LETTER I WITH TILDE;Ll;0;L;0069 0303;;;;N;LATIN SMALL LETTER I TILDE;;0128;;0128 +012A;LATIN CAPITAL LETTER I WITH MACRON;Lu;0;L;0049 0304;;;;N;LATIN CAPITAL LETTER I MACRON;;;012B; +012B;LATIN SMALL LETTER I WITH MACRON;Ll;0;L;0069 0304;;;;N;LATIN SMALL LETTER I MACRON;;012A;;012A +012C;LATIN CAPITAL LETTER I WITH BREVE;Lu;0;L;0049 0306;;;;N;LATIN CAPITAL LETTER I BREVE;;;012D; +012D;LATIN SMALL LETTER I WITH BREVE;Ll;0;L;0069 0306;;;;N;LATIN SMALL LETTER I BREVE;;012C;;012C +012E;LATIN CAPITAL LETTER I WITH OGONEK;Lu;0;L;0049 0328;;;;N;LATIN CAPITAL LETTER I OGONEK;;;012F; +012F;LATIN SMALL LETTER I WITH OGONEK;Ll;0;L;0069 0328;;;;N;LATIN SMALL LETTER I OGONEK;;012E;;012E +0130;LATIN CAPITAL LETTER I WITH DOT ABOVE;Lu;0;L;0049 0307;;;;N;LATIN CAPITAL LETTER I DOT;;;0069; +0131;LATIN SMALL LETTER DOTLESS I;Ll;0;L;;;;;N;;;0049;;0049 +0132;LATIN CAPITAL LIGATURE IJ;Lu;0;L; 0049 004A;;;;N;LATIN CAPITAL LETTER I J;;;0133; +0133;LATIN SMALL LIGATURE IJ;Ll;0;L; 0069 006A;;;;N;LATIN SMALL LETTER I J;;0132;;0132 +0134;LATIN CAPITAL LETTER J WITH CIRCUMFLEX;Lu;0;L;004A 0302;;;;N;LATIN CAPITAL LETTER J CIRCUMFLEX;;;0135; +0135;LATIN SMALL LETTER J WITH CIRCUMFLEX;Ll;0;L;006A 0302;;;;N;LATIN SMALL LETTER J CIRCUMFLEX;;0134;;0134 +0136;LATIN CAPITAL LETTER K WITH CEDILLA;Lu;0;L;004B 0327;;;;N;LATIN CAPITAL LETTER K CEDILLA;;;0137; +0137;LATIN SMALL LETTER K WITH CEDILLA;Ll;0;L;006B 0327;;;;N;LATIN SMALL LETTER K CEDILLA;;0136;;0136 +0138;LATIN SMALL LETTER KRA;Ll;0;L;;;;;N;;;;; +0139;LATIN CAPITAL LETTER L WITH ACUTE;Lu;0;L;004C 0301;;;;N;LATIN CAPITAL LETTER L ACUTE;;;013A; +013A;LATIN SMALL LETTER L WITH ACUTE;Ll;0;L;006C 0301;;;;N;LATIN SMALL LETTER L ACUTE;;0139;;0139 +013B;LATIN CAPITAL LETTER L WITH CEDILLA;Lu;0;L;004C 0327;;;;N;LATIN CAPITAL LETTER L CEDILLA;;;013C; +013C;LATIN SMALL LETTER L WITH CEDILLA;Ll;0;L;006C 0327;;;;N;LATIN SMALL LETTER L CEDILLA;;013B;;013B +013D;LATIN CAPITAL LETTER L WITH CARON;Lu;0;L;004C 030C;;;;N;LATIN CAPITAL LETTER L HACEK;;;013E; +013E;LATIN SMALL LETTER L WITH CARON;Ll;0;L;006C 030C;;;;N;LATIN SMALL LETTER L HACEK;;013D;;013D +013F;LATIN CAPITAL LETTER L WITH MIDDLE DOT;Lu;0;L; 004C 00B7;;;;N;;;;0140; +0140;LATIN SMALL LETTER L WITH MIDDLE DOT;Ll;0;L; 006C 00B7;;;;N;;;013F;;013F +0141;LATIN CAPITAL LETTER L WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER L SLASH;;;0142; +0142;LATIN SMALL LETTER L WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER L SLASH;;0141;;0141 +0143;LATIN CAPITAL LETTER N WITH ACUTE;Lu;0;L;004E 0301;;;;N;LATIN CAPITAL LETTER N ACUTE;;;0144; +0144;LATIN SMALL LETTER N WITH ACUTE;Ll;0;L;006E 0301;;;;N;LATIN SMALL LETTER N ACUTE;;0143;;0143 +0145;LATIN CAPITAL LETTER N WITH CEDILLA;Lu;0;L;004E 0327;;;;N;LATIN CAPITAL LETTER N CEDILLA;;;0146; +0146;LATIN SMALL LETTER N WITH CEDILLA;Ll;0;L;006E 0327;;;;N;LATIN SMALL LETTER N CEDILLA;;0145;;0145 +0147;LATIN CAPITAL LETTER N WITH CARON;Lu;0;L;004E 030C;;;;N;LATIN CAPITAL LETTER N HACEK;;;0148; +0148;LATIN SMALL LETTER N WITH CARON;Ll;0;L;006E 030C;;;;N;LATIN SMALL LETTER N HACEK;;0147;;0147 +0149;LATIN SMALL LETTER N PRECEDED BY APOSTROPHE;Ll;0;L; 02BC 006E;;;;N;LATIN SMALL LETTER APOSTROPHE N;;;; +014A;LATIN CAPITAL LETTER ENG;Lu;0;L;;;;;N;;;;014B; +014B;LATIN SMALL LETTER ENG;Ll;0;L;;;;;N;;;014A;;014A +014C;LATIN CAPITAL LETTER O WITH MACRON;Lu;0;L;004F 0304;;;;N;LATIN CAPITAL LETTER O MACRON;;;014D; +014D;LATIN SMALL LETTER O WITH MACRON;Ll;0;L;006F 0304;;;;N;LATIN SMALL LETTER O MACRON;;014C;;014C +014E;LATIN CAPITAL LETTER O WITH BREVE;Lu;0;L;004F 0306;;;;N;LATIN CAPITAL LETTER O BREVE;;;014F; +014F;LATIN SMALL LETTER O WITH BREVE;Ll;0;L;006F 0306;;;;N;LATIN SMALL LETTER O BREVE;;014E;;014E +0150;LATIN CAPITAL LETTER O WITH DOUBLE ACUTE;Lu;0;L;004F 030B;;;;N;LATIN CAPITAL LETTER O DOUBLE ACUTE;;;0151; +0151;LATIN SMALL LETTER O WITH DOUBLE ACUTE;Ll;0;L;006F 030B;;;;N;LATIN SMALL LETTER O DOUBLE ACUTE;;0150;;0150 +0152;LATIN CAPITAL LIGATURE OE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O E;;;0153; +0153;LATIN SMALL LIGATURE OE;Ll;0;L;;;;;N;LATIN SMALL LETTER O E;;0152;;0152 +0154;LATIN CAPITAL LETTER R WITH ACUTE;Lu;0;L;0052 0301;;;;N;LATIN CAPITAL LETTER R ACUTE;;;0155; +0155;LATIN SMALL LETTER R WITH ACUTE;Ll;0;L;0072 0301;;;;N;LATIN SMALL LETTER R ACUTE;;0154;;0154 +0156;LATIN CAPITAL LETTER R WITH CEDILLA;Lu;0;L;0052 0327;;;;N;LATIN CAPITAL LETTER R CEDILLA;;;0157; +0157;LATIN SMALL LETTER R WITH CEDILLA;Ll;0;L;0072 0327;;;;N;LATIN SMALL LETTER R CEDILLA;;0156;;0156 +0158;LATIN CAPITAL LETTER R WITH CARON;Lu;0;L;0052 030C;;;;N;LATIN CAPITAL LETTER R HACEK;;;0159; +0159;LATIN SMALL LETTER R WITH CARON;Ll;0;L;0072 030C;;;;N;LATIN SMALL LETTER R HACEK;;0158;;0158 +015A;LATIN CAPITAL LETTER S WITH ACUTE;Lu;0;L;0053 0301;;;;N;LATIN CAPITAL LETTER S ACUTE;;;015B; +015B;LATIN SMALL LETTER S WITH ACUTE;Ll;0;L;0073 0301;;;;N;LATIN SMALL LETTER S ACUTE;;015A;;015A +015C;LATIN CAPITAL LETTER S WITH CIRCUMFLEX;Lu;0;L;0053 0302;;;;N;LATIN CAPITAL LETTER S CIRCUMFLEX;;;015D; +015D;LATIN SMALL LETTER S WITH CIRCUMFLEX;Ll;0;L;0073 0302;;;;N;LATIN SMALL LETTER S CIRCUMFLEX;;015C;;015C +015E;LATIN CAPITAL LETTER S WITH CEDILLA;Lu;0;L;0053 0327;;;;N;LATIN CAPITAL LETTER S CEDILLA;;;015F; +015F;LATIN SMALL LETTER S WITH CEDILLA;Ll;0;L;0073 0327;;;;N;LATIN SMALL LETTER S CEDILLA;;015E;;015E +0160;LATIN CAPITAL LETTER S WITH CARON;Lu;0;L;0053 030C;;;;N;LATIN CAPITAL LETTER S HACEK;;;0161; +0161;LATIN SMALL LETTER S WITH CARON;Ll;0;L;0073 030C;;;;N;LATIN SMALL LETTER S HACEK;;0160;;0160 +0162;LATIN CAPITAL LETTER T WITH CEDILLA;Lu;0;L;0054 0327;;;;N;LATIN CAPITAL LETTER T CEDILLA;;;0163; +0163;LATIN SMALL LETTER T WITH CEDILLA;Ll;0;L;0074 0327;;;;N;LATIN SMALL LETTER T CEDILLA;;0162;;0162 +0164;LATIN CAPITAL LETTER T WITH CARON;Lu;0;L;0054 030C;;;;N;LATIN CAPITAL LETTER T HACEK;;;0165; +0165;LATIN SMALL LETTER T WITH CARON;Ll;0;L;0074 030C;;;;N;LATIN SMALL LETTER T HACEK;;0164;;0164 +0166;LATIN CAPITAL LETTER T WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T BAR;;;0167; +0167;LATIN SMALL LETTER T WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER T BAR;;0166;;0166 +0168;LATIN CAPITAL LETTER U WITH TILDE;Lu;0;L;0055 0303;;;;N;LATIN CAPITAL LETTER U TILDE;;;0169; +0169;LATIN SMALL LETTER U WITH TILDE;Ll;0;L;0075 0303;;;;N;LATIN SMALL LETTER U TILDE;;0168;;0168 +016A;LATIN CAPITAL LETTER U WITH MACRON;Lu;0;L;0055 0304;;;;N;LATIN CAPITAL LETTER U MACRON;;;016B; +016B;LATIN SMALL LETTER U WITH MACRON;Ll;0;L;0075 0304;;;;N;LATIN SMALL LETTER U MACRON;;016A;;016A +016C;LATIN CAPITAL LETTER U WITH BREVE;Lu;0;L;0055 0306;;;;N;LATIN CAPITAL LETTER U BREVE;;;016D; +016D;LATIN SMALL LETTER U WITH BREVE;Ll;0;L;0075 0306;;;;N;LATIN SMALL LETTER U BREVE;;016C;;016C +016E;LATIN CAPITAL LETTER U WITH RING ABOVE;Lu;0;L;0055 030A;;;;N;LATIN CAPITAL LETTER U RING;;;016F; +016F;LATIN SMALL LETTER U WITH RING ABOVE;Ll;0;L;0075 030A;;;;N;LATIN SMALL LETTER U RING;;016E;;016E +0170;LATIN CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0055 030B;;;;N;LATIN CAPITAL LETTER U DOUBLE ACUTE;;;0171; +0171;LATIN SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0075 030B;;;;N;LATIN SMALL LETTER U DOUBLE ACUTE;;0170;;0170 +0172;LATIN CAPITAL LETTER U WITH OGONEK;Lu;0;L;0055 0328;;;;N;LATIN CAPITAL LETTER U OGONEK;;;0173; +0173;LATIN SMALL LETTER U WITH OGONEK;Ll;0;L;0075 0328;;;;N;LATIN SMALL LETTER U OGONEK;;0172;;0172 +0174;LATIN CAPITAL LETTER W WITH CIRCUMFLEX;Lu;0;L;0057 0302;;;;N;LATIN CAPITAL LETTER W CIRCUMFLEX;;;0175; +0175;LATIN SMALL LETTER W WITH CIRCUMFLEX;Ll;0;L;0077 0302;;;;N;LATIN SMALL LETTER W CIRCUMFLEX;;0174;;0174 +0176;LATIN CAPITAL LETTER Y WITH CIRCUMFLEX;Lu;0;L;0059 0302;;;;N;LATIN CAPITAL LETTER Y CIRCUMFLEX;;;0177; +0177;LATIN SMALL LETTER Y WITH CIRCUMFLEX;Ll;0;L;0079 0302;;;;N;LATIN SMALL LETTER Y CIRCUMFLEX;;0176;;0176 +0178;LATIN CAPITAL LETTER Y WITH DIAERESIS;Lu;0;L;0059 0308;;;;N;LATIN CAPITAL LETTER Y DIAERESIS;;;00FF; +0179;LATIN CAPITAL LETTER Z WITH ACUTE;Lu;0;L;005A 0301;;;;N;LATIN CAPITAL LETTER Z ACUTE;;;017A; +017A;LATIN SMALL LETTER Z WITH ACUTE;Ll;0;L;007A 0301;;;;N;LATIN SMALL LETTER Z ACUTE;;0179;;0179 +017B;LATIN CAPITAL LETTER Z WITH DOT ABOVE;Lu;0;L;005A 0307;;;;N;LATIN CAPITAL LETTER Z DOT;;;017C; +017C;LATIN SMALL LETTER Z WITH DOT ABOVE;Ll;0;L;007A 0307;;;;N;LATIN SMALL LETTER Z DOT;;017B;;017B +017D;LATIN CAPITAL LETTER Z WITH CARON;Lu;0;L;005A 030C;;;;N;LATIN CAPITAL LETTER Z HACEK;;;017E; +017E;LATIN SMALL LETTER Z WITH CARON;Ll;0;L;007A 030C;;;;N;LATIN SMALL LETTER Z HACEK;;017D;;017D +017F;LATIN SMALL LETTER LONG S;Ll;0;L; 0073;;;;N;;;0053;;0053 +0180;LATIN SMALL LETTER B WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER B BAR;;0243;;0243 +0181;LATIN CAPITAL LETTER B WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B HOOK;;;0253; +0182;LATIN CAPITAL LETTER B WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B TOPBAR;;;0183; +0183;LATIN SMALL LETTER B WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER B TOPBAR;;0182;;0182 +0184;LATIN CAPITAL LETTER TONE SIX;Lu;0;L;;;;;N;;;;0185; +0185;LATIN SMALL LETTER TONE SIX;Ll;0;L;;;;;N;;;0184;;0184 +0186;LATIN CAPITAL LETTER OPEN O;Lu;0;L;;;;;N;;;;0254; +0187;LATIN CAPITAL LETTER C WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER C HOOK;;;0188; +0188;LATIN SMALL LETTER C WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER C HOOK;;0187;;0187 +0189;LATIN CAPITAL LETTER AFRICAN D;Lu;0;L;;;;;N;;;;0256; +018A;LATIN CAPITAL LETTER D WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D HOOK;;;0257; +018B;LATIN CAPITAL LETTER D WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D TOPBAR;;;018C; +018C;LATIN SMALL LETTER D WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER D TOPBAR;;018B;;018B +018D;LATIN SMALL LETTER TURNED DELTA;Ll;0;L;;;;;N;;;;; +018E;LATIN CAPITAL LETTER REVERSED E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER TURNED E;;;01DD; +018F;LATIN CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;0259; +0190;LATIN CAPITAL LETTER OPEN E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER EPSILON;;;025B; +0191;LATIN CAPITAL LETTER F WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER F HOOK;;;0192; +0192;LATIN SMALL LETTER F WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT F;;0191;;0191 +0193;LATIN CAPITAL LETTER G WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G HOOK;;;0260; +0194;LATIN CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;0263; +0195;LATIN SMALL LETTER HV;Ll;0;L;;;;;N;LATIN SMALL LETTER H V;;01F6;;01F6 +0196;LATIN CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;0269; +0197;LATIN CAPITAL LETTER I WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED I;;;0268; +0198;LATIN CAPITAL LETTER K WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER K HOOK;;;0199; +0199;LATIN SMALL LETTER K WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER K HOOK;;0198;;0198 +019A;LATIN SMALL LETTER L WITH BAR;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED L;;023D;;023D +019B;LATIN SMALL LETTER LAMBDA WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED LAMBDA;;A7DC;;A7DC +019C;LATIN CAPITAL LETTER TURNED M;Lu;0;L;;;;;N;;;;026F; +019D;LATIN CAPITAL LETTER N WITH LEFT HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER N HOOK;;;0272; +019E;LATIN SMALL LETTER N WITH LONG RIGHT LEG;Ll;0;L;;;;;N;;;0220;;0220 +019F;LATIN CAPITAL LETTER O WITH MIDDLE TILDE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED O;;;0275; +01A0;LATIN CAPITAL LETTER O WITH HORN;Lu;0;L;004F 031B;;;;N;LATIN CAPITAL LETTER O HORN;;;01A1; +01A1;LATIN SMALL LETTER O WITH HORN;Ll;0;L;006F 031B;;;;N;LATIN SMALL LETTER O HORN;;01A0;;01A0 +01A2;LATIN CAPITAL LETTER OI;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O I;;;01A3; +01A3;LATIN SMALL LETTER OI;Ll;0;L;;;;;N;LATIN SMALL LETTER O I;;01A2;;01A2 +01A4;LATIN CAPITAL LETTER P WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER P HOOK;;;01A5; +01A5;LATIN SMALL LETTER P WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER P HOOK;;01A4;;01A4 +01A6;LATIN LETTER YR;Lu;0;L;;;;;N;LATIN LETTER Y R;;;0280; +01A7;LATIN CAPITAL LETTER TONE TWO;Lu;0;L;;;;;N;;;;01A8; +01A8;LATIN SMALL LETTER TONE TWO;Ll;0;L;;;;;N;;;01A7;;01A7 +01A9;LATIN CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;0283; +01AA;LATIN LETTER REVERSED ESH LOOP;Ll;0;L;;;;;N;;;;; +01AB;LATIN SMALL LETTER T WITH PALATAL HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T PALATAL HOOK;;;; +01AC;LATIN CAPITAL LETTER T WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T HOOK;;;01AD; +01AD;LATIN SMALL LETTER T WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T HOOK;;01AC;;01AC +01AE;LATIN CAPITAL LETTER T WITH RETROFLEX HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T RETROFLEX HOOK;;;0288; +01AF;LATIN CAPITAL LETTER U WITH HORN;Lu;0;L;0055 031B;;;;N;LATIN CAPITAL LETTER U HORN;;;01B0; +01B0;LATIN SMALL LETTER U WITH HORN;Ll;0;L;0075 031B;;;;N;LATIN SMALL LETTER U HORN;;01AF;;01AF +01B1;LATIN CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;028A; +01B2;LATIN CAPITAL LETTER V WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER SCRIPT V;;;028B; +01B3;LATIN CAPITAL LETTER Y WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Y HOOK;;;01B4; +01B4;LATIN SMALL LETTER Y WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Y HOOK;;01B3;;01B3 +01B5;LATIN CAPITAL LETTER Z WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Z BAR;;;01B6; +01B6;LATIN SMALL LETTER Z WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER Z BAR;;01B5;;01B5 +01B7;LATIN CAPITAL LETTER EZH;Lu;0;L;;;;;N;LATIN CAPITAL LETTER YOGH;;;0292; +01B8;LATIN CAPITAL LETTER EZH REVERSED;Lu;0;L;;;;;N;LATIN CAPITAL LETTER REVERSED YOGH;;;01B9; +01B9;LATIN SMALL LETTER EZH REVERSED;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED YOGH;;01B8;;01B8 +01BA;LATIN SMALL LETTER EZH WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH WITH TAIL;;;; +01BB;LATIN LETTER TWO WITH STROKE;Lo;0;L;;;;;N;LATIN LETTER TWO BAR;;;; +01BC;LATIN CAPITAL LETTER TONE FIVE;Lu;0;L;;;;;N;;;;01BD; +01BD;LATIN SMALL LETTER TONE FIVE;Ll;0;L;;;;;N;;;01BC;;01BC +01BE;LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER INVERTED GLOTTAL STOP BAR;;;; +01BF;LATIN LETTER WYNN;Ll;0;L;;;;;N;;;01F7;;01F7 +01C0;LATIN LETTER DENTAL CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE;;;; +01C1;LATIN LETTER LATERAL CLICK;Lo;0;L;;;;;N;LATIN LETTER DOUBLE PIPE;;;; +01C2;LATIN LETTER ALVEOLAR CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE DOUBLE BAR;;;; +01C3;LATIN LETTER RETROFLEX CLICK;Lo;0;L;;;;;N;LATIN LETTER EXCLAMATION MARK;;;; +01C4;LATIN CAPITAL LETTER DZ WITH CARON;Lu;0;L; 0044 017D;;;;N;LATIN CAPITAL LETTER D Z HACEK;;;01C6;01C5 +01C5;LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON;Lt;0;L; 0044 017E;;;;N;LATIN LETTER CAPITAL D SMALL Z HACEK;;01C4;01C6;01C5 +01C6;LATIN SMALL LETTER DZ WITH CARON;Ll;0;L; 0064 017E;;;;N;LATIN SMALL LETTER D Z HACEK;;01C4;;01C5 +01C7;LATIN CAPITAL LETTER LJ;Lu;0;L; 004C 004A;;;;N;LATIN CAPITAL LETTER L J;;;01C9;01C8 +01C8;LATIN CAPITAL LETTER L WITH SMALL LETTER J;Lt;0;L; 004C 006A;;;;N;LATIN LETTER CAPITAL L SMALL J;;01C7;01C9;01C8 +01C9;LATIN SMALL LETTER LJ;Ll;0;L; 006C 006A;;;;N;LATIN SMALL LETTER L J;;01C7;;01C8 +01CA;LATIN CAPITAL LETTER NJ;Lu;0;L; 004E 004A;;;;N;LATIN CAPITAL LETTER N J;;;01CC;01CB +01CB;LATIN CAPITAL LETTER N WITH SMALL LETTER J;Lt;0;L; 004E 006A;;;;N;LATIN LETTER CAPITAL N SMALL J;;01CA;01CC;01CB +01CC;LATIN SMALL LETTER NJ;Ll;0;L; 006E 006A;;;;N;LATIN SMALL LETTER N J;;01CA;;01CB +01CD;LATIN CAPITAL LETTER A WITH CARON;Lu;0;L;0041 030C;;;;N;LATIN CAPITAL LETTER A HACEK;;;01CE; +01CE;LATIN SMALL LETTER A WITH CARON;Ll;0;L;0061 030C;;;;N;LATIN SMALL LETTER A HACEK;;01CD;;01CD +01CF;LATIN CAPITAL LETTER I WITH CARON;Lu;0;L;0049 030C;;;;N;LATIN CAPITAL LETTER I HACEK;;;01D0; +01D0;LATIN SMALL LETTER I WITH CARON;Ll;0;L;0069 030C;;;;N;LATIN SMALL LETTER I HACEK;;01CF;;01CF +01D1;LATIN CAPITAL LETTER O WITH CARON;Lu;0;L;004F 030C;;;;N;LATIN CAPITAL LETTER O HACEK;;;01D2; +01D2;LATIN SMALL LETTER O WITH CARON;Ll;0;L;006F 030C;;;;N;LATIN SMALL LETTER O HACEK;;01D1;;01D1 +01D3;LATIN CAPITAL LETTER U WITH CARON;Lu;0;L;0055 030C;;;;N;LATIN CAPITAL LETTER U HACEK;;;01D4; +01D4;LATIN SMALL LETTER U WITH CARON;Ll;0;L;0075 030C;;;;N;LATIN SMALL LETTER U HACEK;;01D3;;01D3 +01D5;LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON;Lu;0;L;00DC 0304;;;;N;LATIN CAPITAL LETTER U DIAERESIS MACRON;;;01D6; +01D6;LATIN SMALL LETTER U WITH DIAERESIS AND MACRON;Ll;0;L;00FC 0304;;;;N;LATIN SMALL LETTER U DIAERESIS MACRON;;01D5;;01D5 +01D7;LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE;Lu;0;L;00DC 0301;;;;N;LATIN CAPITAL LETTER U DIAERESIS ACUTE;;;01D8; +01D8;LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE;Ll;0;L;00FC 0301;;;;N;LATIN SMALL LETTER U DIAERESIS ACUTE;;01D7;;01D7 +01D9;LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON;Lu;0;L;00DC 030C;;;;N;LATIN CAPITAL LETTER U DIAERESIS HACEK;;;01DA; +01DA;LATIN SMALL LETTER U WITH DIAERESIS AND CARON;Ll;0;L;00FC 030C;;;;N;LATIN SMALL LETTER U DIAERESIS HACEK;;01D9;;01D9 +01DB;LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE;Lu;0;L;00DC 0300;;;;N;LATIN CAPITAL LETTER U DIAERESIS GRAVE;;;01DC; +01DC;LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE;Ll;0;L;00FC 0300;;;;N;LATIN SMALL LETTER U DIAERESIS GRAVE;;01DB;;01DB +01DD;LATIN SMALL LETTER TURNED E;Ll;0;L;;;;;N;;;018E;;018E +01DE;LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON;Lu;0;L;00C4 0304;;;;N;LATIN CAPITAL LETTER A DIAERESIS MACRON;;;01DF; +01DF;LATIN SMALL LETTER A WITH DIAERESIS AND MACRON;Ll;0;L;00E4 0304;;;;N;LATIN SMALL LETTER A DIAERESIS MACRON;;01DE;;01DE +01E0;LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON;Lu;0;L;0226 0304;;;;N;LATIN CAPITAL LETTER A DOT MACRON;;;01E1; +01E1;LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON;Ll;0;L;0227 0304;;;;N;LATIN SMALL LETTER A DOT MACRON;;01E0;;01E0 +01E2;LATIN CAPITAL LETTER AE WITH MACRON;Lu;0;L;00C6 0304;;;;N;LATIN CAPITAL LETTER A E MACRON;;;01E3; +01E3;LATIN SMALL LETTER AE WITH MACRON;Ll;0;L;00E6 0304;;;;N;LATIN SMALL LETTER A E MACRON;;01E2;;01E2 +01E4;LATIN CAPITAL LETTER G WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G BAR;;;01E5; +01E5;LATIN SMALL LETTER G WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER G BAR;;01E4;;01E4 +01E6;LATIN CAPITAL LETTER G WITH CARON;Lu;0;L;0047 030C;;;;N;LATIN CAPITAL LETTER G HACEK;;;01E7; +01E7;LATIN SMALL LETTER G WITH CARON;Ll;0;L;0067 030C;;;;N;LATIN SMALL LETTER G HACEK;;01E6;;01E6 +01E8;LATIN CAPITAL LETTER K WITH CARON;Lu;0;L;004B 030C;;;;N;LATIN CAPITAL LETTER K HACEK;;;01E9; +01E9;LATIN SMALL LETTER K WITH CARON;Ll;0;L;006B 030C;;;;N;LATIN SMALL LETTER K HACEK;;01E8;;01E8 +01EA;LATIN CAPITAL LETTER O WITH OGONEK;Lu;0;L;004F 0328;;;;N;LATIN CAPITAL LETTER O OGONEK;;;01EB; +01EB;LATIN SMALL LETTER O WITH OGONEK;Ll;0;L;006F 0328;;;;N;LATIN SMALL LETTER O OGONEK;;01EA;;01EA +01EC;LATIN CAPITAL LETTER O WITH OGONEK AND MACRON;Lu;0;L;01EA 0304;;;;N;LATIN CAPITAL LETTER O OGONEK MACRON;;;01ED; +01ED;LATIN SMALL LETTER O WITH OGONEK AND MACRON;Ll;0;L;01EB 0304;;;;N;LATIN SMALL LETTER O OGONEK MACRON;;01EC;;01EC +01EE;LATIN CAPITAL LETTER EZH WITH CARON;Lu;0;L;01B7 030C;;;;N;LATIN CAPITAL LETTER YOGH HACEK;;;01EF; +01EF;LATIN SMALL LETTER EZH WITH CARON;Ll;0;L;0292 030C;;;;N;LATIN SMALL LETTER YOGH HACEK;;01EE;;01EE +01F0;LATIN SMALL LETTER J WITH CARON;Ll;0;L;006A 030C;;;;N;LATIN SMALL LETTER J HACEK;;;; +01F1;LATIN CAPITAL LETTER DZ;Lu;0;L; 0044 005A;;;;N;;;;01F3;01F2 +01F2;LATIN CAPITAL LETTER D WITH SMALL LETTER Z;Lt;0;L; 0044 007A;;;;N;;;01F1;01F3;01F2 +01F3;LATIN SMALL LETTER DZ;Ll;0;L; 0064 007A;;;;N;;;01F1;;01F2 +01F4;LATIN CAPITAL LETTER G WITH ACUTE;Lu;0;L;0047 0301;;;;N;;;;01F5; +01F5;LATIN SMALL LETTER G WITH ACUTE;Ll;0;L;0067 0301;;;;N;;;01F4;;01F4 +01F6;LATIN CAPITAL LETTER HWAIR;Lu;0;L;;;;;N;;;;0195; +01F7;LATIN CAPITAL LETTER WYNN;Lu;0;L;;;;;N;;;;01BF; +01F8;LATIN CAPITAL LETTER N WITH GRAVE;Lu;0;L;004E 0300;;;;N;;;;01F9; +01F9;LATIN SMALL LETTER N WITH GRAVE;Ll;0;L;006E 0300;;;;N;;;01F8;;01F8 +01FA;LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE;Lu;0;L;00C5 0301;;;;N;;;;01FB; +01FB;LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE;Ll;0;L;00E5 0301;;;;N;;;01FA;;01FA +01FC;LATIN CAPITAL LETTER AE WITH ACUTE;Lu;0;L;00C6 0301;;;;N;;;;01FD; +01FD;LATIN SMALL LETTER AE WITH ACUTE;Ll;0;L;00E6 0301;;;;N;;;01FC;;01FC +01FE;LATIN CAPITAL LETTER O WITH STROKE AND ACUTE;Lu;0;L;00D8 0301;;;;N;;;;01FF; +01FF;LATIN SMALL LETTER O WITH STROKE AND ACUTE;Ll;0;L;00F8 0301;;;;N;;;01FE;;01FE +0200;LATIN CAPITAL LETTER A WITH DOUBLE GRAVE;Lu;0;L;0041 030F;;;;N;;;;0201; +0201;LATIN SMALL LETTER A WITH DOUBLE GRAVE;Ll;0;L;0061 030F;;;;N;;;0200;;0200 +0202;LATIN CAPITAL LETTER A WITH INVERTED BREVE;Lu;0;L;0041 0311;;;;N;;;;0203; +0203;LATIN SMALL LETTER A WITH INVERTED BREVE;Ll;0;L;0061 0311;;;;N;;;0202;;0202 +0204;LATIN CAPITAL LETTER E WITH DOUBLE GRAVE;Lu;0;L;0045 030F;;;;N;;;;0205; +0205;LATIN SMALL LETTER E WITH DOUBLE GRAVE;Ll;0;L;0065 030F;;;;N;;;0204;;0204 +0206;LATIN CAPITAL LETTER E WITH INVERTED BREVE;Lu;0;L;0045 0311;;;;N;;;;0207; +0207;LATIN SMALL LETTER E WITH INVERTED BREVE;Ll;0;L;0065 0311;;;;N;;;0206;;0206 +0208;LATIN CAPITAL LETTER I WITH DOUBLE GRAVE;Lu;0;L;0049 030F;;;;N;;;;0209; +0209;LATIN SMALL LETTER I WITH DOUBLE GRAVE;Ll;0;L;0069 030F;;;;N;;;0208;;0208 +020A;LATIN CAPITAL LETTER I WITH INVERTED BREVE;Lu;0;L;0049 0311;;;;N;;;;020B; +020B;LATIN SMALL LETTER I WITH INVERTED BREVE;Ll;0;L;0069 0311;;;;N;;;020A;;020A +020C;LATIN CAPITAL LETTER O WITH DOUBLE GRAVE;Lu;0;L;004F 030F;;;;N;;;;020D; +020D;LATIN SMALL LETTER O WITH DOUBLE GRAVE;Ll;0;L;006F 030F;;;;N;;;020C;;020C +020E;LATIN CAPITAL LETTER O WITH INVERTED BREVE;Lu;0;L;004F 0311;;;;N;;;;020F; +020F;LATIN SMALL LETTER O WITH INVERTED BREVE;Ll;0;L;006F 0311;;;;N;;;020E;;020E +0210;LATIN CAPITAL LETTER R WITH DOUBLE GRAVE;Lu;0;L;0052 030F;;;;N;;;;0211; +0211;LATIN SMALL LETTER R WITH DOUBLE GRAVE;Ll;0;L;0072 030F;;;;N;;;0210;;0210 +0212;LATIN CAPITAL LETTER R WITH INVERTED BREVE;Lu;0;L;0052 0311;;;;N;;;;0213; +0213;LATIN SMALL LETTER R WITH INVERTED BREVE;Ll;0;L;0072 0311;;;;N;;;0212;;0212 +0214;LATIN CAPITAL LETTER U WITH DOUBLE GRAVE;Lu;0;L;0055 030F;;;;N;;;;0215; +0215;LATIN SMALL LETTER U WITH DOUBLE GRAVE;Ll;0;L;0075 030F;;;;N;;;0214;;0214 +0216;LATIN CAPITAL LETTER U WITH INVERTED BREVE;Lu;0;L;0055 0311;;;;N;;;;0217; +0217;LATIN SMALL LETTER U WITH INVERTED BREVE;Ll;0;L;0075 0311;;;;N;;;0216;;0216 +0218;LATIN CAPITAL LETTER S WITH COMMA BELOW;Lu;0;L;0053 0326;;;;N;;;;0219; +0219;LATIN SMALL LETTER S WITH COMMA BELOW;Ll;0;L;0073 0326;;;;N;;;0218;;0218 +021A;LATIN CAPITAL LETTER T WITH COMMA BELOW;Lu;0;L;0054 0326;;;;N;;;;021B; +021B;LATIN SMALL LETTER T WITH COMMA BELOW;Ll;0;L;0074 0326;;;;N;;;021A;;021A +021C;LATIN CAPITAL LETTER YOGH;Lu;0;L;;;;;N;;;;021D; +021D;LATIN SMALL LETTER YOGH;Ll;0;L;;;;;N;;;021C;;021C +021E;LATIN CAPITAL LETTER H WITH CARON;Lu;0;L;0048 030C;;;;N;;;;021F; +021F;LATIN SMALL LETTER H WITH CARON;Ll;0;L;0068 030C;;;;N;;;021E;;021E +0220;LATIN CAPITAL LETTER N WITH LONG RIGHT LEG;Lu;0;L;;;;;N;;;;019E; +0221;LATIN SMALL LETTER D WITH CURL;Ll;0;L;;;;;N;;;;; +0222;LATIN CAPITAL LETTER OU;Lu;0;L;;;;;N;;;;0223; +0223;LATIN SMALL LETTER OU;Ll;0;L;;;;;N;;;0222;;0222 +0224;LATIN CAPITAL LETTER Z WITH HOOK;Lu;0;L;;;;;N;;;;0225; +0225;LATIN SMALL LETTER Z WITH HOOK;Ll;0;L;;;;;N;;;0224;;0224 +0226;LATIN CAPITAL LETTER A WITH DOT ABOVE;Lu;0;L;0041 0307;;;;N;;;;0227; +0227;LATIN SMALL LETTER A WITH DOT ABOVE;Ll;0;L;0061 0307;;;;N;;;0226;;0226 +0228;LATIN CAPITAL LETTER E WITH CEDILLA;Lu;0;L;0045 0327;;;;N;;;;0229; +0229;LATIN SMALL LETTER E WITH CEDILLA;Ll;0;L;0065 0327;;;;N;;;0228;;0228 +022A;LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON;Lu;0;L;00D6 0304;;;;N;;;;022B; +022B;LATIN SMALL LETTER O WITH DIAERESIS AND MACRON;Ll;0;L;00F6 0304;;;;N;;;022A;;022A +022C;LATIN CAPITAL LETTER O WITH TILDE AND MACRON;Lu;0;L;00D5 0304;;;;N;;;;022D; +022D;LATIN SMALL LETTER O WITH TILDE AND MACRON;Ll;0;L;00F5 0304;;;;N;;;022C;;022C +022E;LATIN CAPITAL LETTER O WITH DOT ABOVE;Lu;0;L;004F 0307;;;;N;;;;022F; +022F;LATIN SMALL LETTER O WITH DOT ABOVE;Ll;0;L;006F 0307;;;;N;;;022E;;022E +0230;LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON;Lu;0;L;022E 0304;;;;N;;;;0231; +0231;LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON;Ll;0;L;022F 0304;;;;N;;;0230;;0230 +0232;LATIN CAPITAL LETTER Y WITH MACRON;Lu;0;L;0059 0304;;;;N;;;;0233; +0233;LATIN SMALL LETTER Y WITH MACRON;Ll;0;L;0079 0304;;;;N;;;0232;;0232 +0234;LATIN SMALL LETTER L WITH CURL;Ll;0;L;;;;;N;;;;; +0235;LATIN SMALL LETTER N WITH CURL;Ll;0;L;;;;;N;;;;; +0236;LATIN SMALL LETTER T WITH CURL;Ll;0;L;;;;;N;;;;; +0237;LATIN SMALL LETTER DOTLESS J;Ll;0;L;;;;;N;;;;; +0238;LATIN SMALL LETTER DB DIGRAPH;Ll;0;L;;;;;N;;;;; +0239;LATIN SMALL LETTER QP DIGRAPH;Ll;0;L;;;;;N;;;;; +023A;LATIN CAPITAL LETTER A WITH STROKE;Lu;0;L;;;;;N;;;;2C65; +023B;LATIN CAPITAL LETTER C WITH STROKE;Lu;0;L;;;;;N;;;;023C; +023C;LATIN SMALL LETTER C WITH STROKE;Ll;0;L;;;;;N;;;023B;;023B +023D;LATIN CAPITAL LETTER L WITH BAR;Lu;0;L;;;;;N;;;;019A; +023E;LATIN CAPITAL LETTER T WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;2C66; +023F;LATIN SMALL LETTER S WITH SWASH TAIL;Ll;0;L;;;;;N;;;2C7E;;2C7E +0240;LATIN SMALL LETTER Z WITH SWASH TAIL;Ll;0;L;;;;;N;;;2C7F;;2C7F +0241;LATIN CAPITAL LETTER GLOTTAL STOP;Lu;0;L;;;;;N;;;;0242; +0242;LATIN SMALL LETTER GLOTTAL STOP;Ll;0;L;;;;;N;;;0241;;0241 +0243;LATIN CAPITAL LETTER B WITH STROKE;Lu;0;L;;;;;N;;;;0180; +0244;LATIN CAPITAL LETTER U BAR;Lu;0;L;;;;;N;;;;0289; +0245;LATIN CAPITAL LETTER TURNED V;Lu;0;L;;;;;N;;;;028C; +0246;LATIN CAPITAL LETTER E WITH STROKE;Lu;0;L;;;;;N;;;;0247; +0247;LATIN SMALL LETTER E WITH STROKE;Ll;0;L;;;;;N;;;0246;;0246 +0248;LATIN CAPITAL LETTER J WITH STROKE;Lu;0;L;;;;;N;;;;0249; +0249;LATIN SMALL LETTER J WITH STROKE;Ll;0;L;;;;;N;;;0248;;0248 +024A;LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL;Lu;0;L;;;;;N;;;;024B; +024B;LATIN SMALL LETTER Q WITH HOOK TAIL;Ll;0;L;;;;;N;;;024A;;024A +024C;LATIN CAPITAL LETTER R WITH STROKE;Lu;0;L;;;;;N;;;;024D; +024D;LATIN SMALL LETTER R WITH STROKE;Ll;0;L;;;;;N;;;024C;;024C +024E;LATIN CAPITAL LETTER Y WITH STROKE;Lu;0;L;;;;;N;;;;024F; +024F;LATIN SMALL LETTER Y WITH STROKE;Ll;0;L;;;;;N;;;024E;;024E +0250;LATIN SMALL LETTER TURNED A;Ll;0;L;;;;;N;;;2C6F;;2C6F +0251;LATIN SMALL LETTER ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT A;;2C6D;;2C6D +0252;LATIN SMALL LETTER TURNED ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED SCRIPT A;;2C70;;2C70 +0253;LATIN SMALL LETTER B WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER B HOOK;;0181;;0181 +0254;LATIN SMALL LETTER OPEN O;Ll;0;L;;;;;N;;;0186;;0186 +0255;LATIN SMALL LETTER C WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER C CURL;;;; +0256;LATIN SMALL LETTER D WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER D RETROFLEX HOOK;;0189;;0189 +0257;LATIN SMALL LETTER D WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER D HOOK;;018A;;018A +0258;LATIN SMALL LETTER REVERSED E;Ll;0;L;;;;;N;;;;; +0259;LATIN SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;018F;;018F +025A;LATIN SMALL LETTER SCHWA WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCHWA HOOK;;;; +025B;LATIN SMALL LETTER OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER EPSILON;;0190;;0190 +025C;LATIN SMALL LETTER REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON;;A7AB;;A7AB +025D;LATIN SMALL LETTER REVERSED OPEN E WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON HOOK;;;; +025E;LATIN SMALL LETTER CLOSED REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED REVERSED EPSILON;;;; +025F;LATIN SMALL LETTER DOTLESS J WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR;;;; +0260;LATIN SMALL LETTER G WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER G HOOK;;0193;;0193 +0261;LATIN SMALL LETTER SCRIPT G;Ll;0;L;;;;;N;;;A7AC;;A7AC +0262;LATIN LETTER SMALL CAPITAL G;Ll;0;L;;;;;N;;;;; +0263;LATIN SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0194;;0194 +0264;LATIN SMALL LETTER RAMS HORN;Ll;0;L;;;;;N;LATIN SMALL LETTER BABY GAMMA;;A7CB;;A7CB +0265;LATIN SMALL LETTER TURNED H;Ll;0;L;;;;;N;;;A78D;;A78D +0266;LATIN SMALL LETTER H WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER H HOOK;;A7AA;;A7AA +0267;LATIN SMALL LETTER HENG WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER HENG HOOK;;;; +0268;LATIN SMALL LETTER I WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED I;;0197;;0197 +0269;LATIN SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0196;;0196 +026A;LATIN LETTER SMALL CAPITAL I;Ll;0;L;;;;;N;;;A7AE;;A7AE +026B;LATIN SMALL LETTER L WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;2C62;;2C62 +026C;LATIN SMALL LETTER L WITH BELT;Ll;0;L;;;;;N;LATIN SMALL LETTER L BELT;;A7AD;;A7AD +026D;LATIN SMALL LETTER L WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER L RETROFLEX HOOK;;;; +026E;LATIN SMALL LETTER LEZH;Ll;0;L;;;;;N;LATIN SMALL LETTER L YOGH;;;; +026F;LATIN SMALL LETTER TURNED M;Ll;0;L;;;;;N;;;019C;;019C +0270;LATIN SMALL LETTER TURNED M WITH LONG LEG;Ll;0;L;;;;;N;;;;; +0271;LATIN SMALL LETTER M WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER M HOOK;;2C6E;;2C6E +0272;LATIN SMALL LETTER N WITH LEFT HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N HOOK;;019D;;019D +0273;LATIN SMALL LETTER N WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N RETROFLEX HOOK;;;; +0274;LATIN LETTER SMALL CAPITAL N;Ll;0;L;;;;;N;;;;; +0275;LATIN SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;019F;;019F +0276;LATIN LETTER SMALL CAPITAL OE;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL O E;;;; +0277;LATIN SMALL LETTER CLOSED OMEGA;Ll;0;L;;;;;N;;;;; +0278;LATIN SMALL LETTER PHI;Ll;0;L;;;;;N;;;;; +0279;LATIN SMALL LETTER TURNED R;Ll;0;L;;;;;N;;;;; +027A;LATIN SMALL LETTER TURNED R WITH LONG LEG;Ll;0;L;;;;;N;;;;; +027B;LATIN SMALL LETTER TURNED R WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED R HOOK;;;; +027C;LATIN SMALL LETTER R WITH LONG LEG;Ll;0;L;;;;;N;;;;; +027D;LATIN SMALL LETTER R WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER R HOOK;;2C64;;2C64 +027E;LATIN SMALL LETTER R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER FISHHOOK R;;;; +027F;LATIN SMALL LETTER REVERSED R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED FISHHOOK R;;;; +0280;LATIN LETTER SMALL CAPITAL R;Ll;0;L;;;;;N;;;01A6;;01A6 +0281;LATIN LETTER SMALL CAPITAL INVERTED R;Ll;0;L;;;;;N;;;;; +0282;LATIN SMALL LETTER S WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER S HOOK;;A7C5;;A7C5 +0283;LATIN SMALL LETTER ESH;Ll;0;L;;;;;N;;;01A9;;01A9 +0284;LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR HOOK;;;; +0285;LATIN SMALL LETTER SQUAT REVERSED ESH;Ll;0;L;;;;;N;;;;; +0286;LATIN SMALL LETTER ESH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER ESH CURL;;;; +0287;LATIN SMALL LETTER TURNED T;Ll;0;L;;;;;N;;;A7B1;;A7B1 +0288;LATIN SMALL LETTER T WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T RETROFLEX HOOK;;01AE;;01AE +0289;LATIN SMALL LETTER U BAR;Ll;0;L;;;;;N;;;0244;;0244 +028A;LATIN SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;01B1;;01B1 +028B;LATIN SMALL LETTER V WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT V;;01B2;;01B2 +028C;LATIN SMALL LETTER TURNED V;Ll;0;L;;;;;N;;;0245;;0245 +028D;LATIN SMALL LETTER TURNED W;Ll;0;L;;;;;N;;;;; +028E;LATIN SMALL LETTER TURNED Y;Ll;0;L;;;;;N;;;;; +028F;LATIN LETTER SMALL CAPITAL Y;Ll;0;L;;;;;N;;;;; +0290;LATIN SMALL LETTER Z WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Z RETROFLEX HOOK;;;; +0291;LATIN SMALL LETTER Z WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER Z CURL;;;; +0292;LATIN SMALL LETTER EZH;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH;;01B7;;01B7 +0293;LATIN SMALL LETTER EZH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH CURL;;;; +0294;LATIN LETTER GLOTTAL STOP;Lo;0;L;;;;;N;;;;; +0295;LATIN LETTER PHARYNGEAL VOICED FRICATIVE;Lo;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP;;;; +0296;LATIN LETTER INVERTED GLOTTAL STOP;Ll;0;L;;;;;N;;;;; +0297;LATIN LETTER STRETCHED C;Ll;0;L;;;;;N;;;;; +0298;LATIN LETTER BILABIAL CLICK;Ll;0;L;;;;;N;LATIN LETTER BULLSEYE;;;; +0299;LATIN LETTER SMALL CAPITAL B;Ll;0;L;;;;;N;;;;; +029A;LATIN SMALL LETTER CLOSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED EPSILON;;;; +029B;LATIN LETTER SMALL CAPITAL G WITH HOOK;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL G HOOK;;;; +029C;LATIN LETTER SMALL CAPITAL H;Ll;0;L;;;;;N;;;;; +029D;LATIN SMALL LETTER J WITH CROSSED-TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER CROSSED-TAIL J;;A7B2;;A7B2 +029E;LATIN SMALL LETTER TURNED K;Ll;0;L;;;;;N;;;A7B0;;A7B0 +029F;LATIN LETTER SMALL CAPITAL L;Ll;0;L;;;;;N;;;;; +02A0;LATIN SMALL LETTER Q WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Q HOOK;;;; +02A1;LATIN LETTER GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER GLOTTAL STOP BAR;;;; +02A2;LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP BAR;;;; +02A3;LATIN SMALL LETTER DZ DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z;;;; +02A4;LATIN SMALL LETTER DEZH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D YOGH;;;; +02A5;LATIN SMALL LETTER DZ DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z CURL;;;; +02A6;LATIN SMALL LETTER TS DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T S;;;; +02A7;LATIN SMALL LETTER TESH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T ESH;;;; +02A8;LATIN SMALL LETTER TC DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER T C CURL;;;; +02A9;LATIN SMALL LETTER FENG DIGRAPH;Ll;0;L;;;;;N;;;;; +02AA;LATIN SMALL LETTER LS DIGRAPH;Ll;0;L;;;;;N;;;;; +02AB;LATIN SMALL LETTER LZ DIGRAPH;Ll;0;L;;;;;N;;;;; +02AC;LATIN LETTER BILABIAL PERCUSSIVE;Ll;0;L;;;;;N;;;;; +02AD;LATIN LETTER BIDENTAL PERCUSSIVE;Ll;0;L;;;;;N;;;;; +02AE;LATIN SMALL LETTER TURNED H WITH FISHHOOK;Ll;0;L;;;;;N;;;;; +02AF;LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL;Ll;0;L;;;;;N;;;;; +02B0;MODIFIER LETTER SMALL H;Lm;0;L; 0068;;;;N;;;;; +02B1;MODIFIER LETTER SMALL H WITH HOOK;Lm;0;L; 0266;;;;N;MODIFIER LETTER SMALL H HOOK;;;; +02B2;MODIFIER LETTER SMALL J;Lm;0;L; 006A;;;;N;;;;; +02B3;MODIFIER LETTER SMALL R;Lm;0;L; 0072;;;;N;;;;; +02B4;MODIFIER LETTER SMALL TURNED R;Lm;0;L; 0279;;;;N;;;;; +02B5;MODIFIER LETTER SMALL TURNED R WITH HOOK;Lm;0;L; 027B;;;;N;MODIFIER LETTER SMALL TURNED R HOOK;;;; +02B6;MODIFIER LETTER SMALL CAPITAL INVERTED R;Lm;0;L; 0281;;;;N;;;;; +02B7;MODIFIER LETTER SMALL W;Lm;0;L; 0077;;;;N;;;;; +02B8;MODIFIER LETTER SMALL Y;Lm;0;L; 0079;;;;N;;;;; +02B9;MODIFIER LETTER PRIME;Lm;0;ON;;;;;N;;;;; +02BA;MODIFIER LETTER DOUBLE PRIME;Lm;0;ON;;;;;N;;;;; +02BB;MODIFIER LETTER TURNED COMMA;Lm;0;L;;;;;N;;;;; +02BC;MODIFIER LETTER APOSTROPHE;Lm;0;L;;;;;N;;;;; +02BD;MODIFIER LETTER REVERSED COMMA;Lm;0;L;;;;;N;;;;; +02BE;MODIFIER LETTER RIGHT HALF RING;Lm;0;L;;;;;N;;;;; +02BF;MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;; +02C0;MODIFIER LETTER GLOTTAL STOP;Lm;0;L;;;;;N;;;;; +02C1;MODIFIER LETTER REVERSED GLOTTAL STOP;Lm;0;L;;;;;N;;;;; +02C2;MODIFIER LETTER LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02C3;MODIFIER LETTER RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02C4;MODIFIER LETTER UP ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02C5;MODIFIER LETTER DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02C6;MODIFIER LETTER CIRCUMFLEX ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER CIRCUMFLEX;;;; +02C7;CARON;Lm;0;ON;;;;;N;MODIFIER LETTER HACEK;;;; +02C8;MODIFIER LETTER VERTICAL LINE;Lm;0;ON;;;;;N;;;;; +02C9;MODIFIER LETTER MACRON;Lm;0;ON;;;;;N;;;;; +02CA;MODIFIER LETTER ACUTE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER ACUTE;;;; +02CB;MODIFIER LETTER GRAVE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER GRAVE;;;; +02CC;MODIFIER LETTER LOW VERTICAL LINE;Lm;0;ON;;;;;N;;;;; +02CD;MODIFIER LETTER LOW MACRON;Lm;0;ON;;;;;N;;;;; +02CE;MODIFIER LETTER LOW GRAVE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER LOW GRAVE;;;; +02CF;MODIFIER LETTER LOW ACUTE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER LOW ACUTE;;;; +02D0;MODIFIER LETTER TRIANGULAR COLON;Lm;0;L;;;;;N;;;;; +02D1;MODIFIER LETTER HALF TRIANGULAR COLON;Lm;0;L;;;;;N;;;;; +02D2;MODIFIER LETTER CENTRED RIGHT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED RIGHT HALF RING;;;; +02D3;MODIFIER LETTER CENTRED LEFT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED LEFT HALF RING;;;; +02D4;MODIFIER LETTER UP TACK;Sk;0;ON;;;;;N;;;;; +02D5;MODIFIER LETTER DOWN TACK;Sk;0;ON;;;;;N;;;;; +02D6;MODIFIER LETTER PLUS SIGN;Sk;0;ON;;;;;N;;;;; +02D7;MODIFIER LETTER MINUS SIGN;Sk;0;ON;;;;;N;;;;; +02D8;BREVE;Sk;0;ON; 0020 0306;;;;N;SPACING BREVE;;;; +02D9;DOT ABOVE;Sk;0;ON; 0020 0307;;;;N;SPACING DOT ABOVE;;;; +02DA;RING ABOVE;Sk;0;ON; 0020 030A;;;;N;SPACING RING ABOVE;;;; +02DB;OGONEK;Sk;0;ON; 0020 0328;;;;N;SPACING OGONEK;;;; +02DC;SMALL TILDE;Sk;0;ON; 0020 0303;;;;N;SPACING TILDE;;;; +02DD;DOUBLE ACUTE ACCENT;Sk;0;ON; 0020 030B;;;;N;SPACING DOUBLE ACUTE;;;; +02DE;MODIFIER LETTER RHOTIC HOOK;Sk;0;ON;;;;;N;;;;; +02DF;MODIFIER LETTER CROSS ACCENT;Sk;0;ON;;;;;N;;;;; +02E0;MODIFIER LETTER SMALL GAMMA;Lm;0;L; 0263;;;;N;;;;; +02E1;MODIFIER LETTER SMALL L;Lm;0;L; 006C;;;;N;;;;; +02E2;MODIFIER LETTER SMALL S;Lm;0;L; 0073;;;;N;;;;; +02E3;MODIFIER LETTER SMALL X;Lm;0;L; 0078;;;;N;;;;; +02E4;MODIFIER LETTER SMALL REVERSED GLOTTAL STOP;Lm;0;L; 0295;;;;N;;;;; +02E5;MODIFIER LETTER EXTRA-HIGH TONE BAR;Sk;0;ON;;;;;N;;;;; +02E6;MODIFIER LETTER HIGH TONE BAR;Sk;0;ON;;;;;N;;;;; +02E7;MODIFIER LETTER MID TONE BAR;Sk;0;ON;;;;;N;;;;; +02E8;MODIFIER LETTER LOW TONE BAR;Sk;0;ON;;;;;N;;;;; +02E9;MODIFIER LETTER EXTRA-LOW TONE BAR;Sk;0;ON;;;;;N;;;;; +02EA;MODIFIER LETTER YIN DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;; +02EB;MODIFIER LETTER YANG DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;; +02EC;MODIFIER LETTER VOICING;Lm;0;ON;;;;;N;;;;; +02ED;MODIFIER LETTER UNASPIRATED;Sk;0;ON;;;;;N;;;;; +02EE;MODIFIER LETTER DOUBLE APOSTROPHE;Lm;0;L;;;;;N;;;;; +02EF;MODIFIER LETTER LOW DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02F0;MODIFIER LETTER LOW UP ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02F1;MODIFIER LETTER LOW LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02F2;MODIFIER LETTER LOW RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02F3;MODIFIER LETTER LOW RING;Sk;0;ON;;;;;N;;;;; +02F4;MODIFIER LETTER MIDDLE GRAVE ACCENT;Sk;0;ON;;;;;N;;;;; +02F5;MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT;Sk;0;ON;;;;;N;;;;; +02F6;MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT;Sk;0;ON;;;;;N;;;;; +02F7;MODIFIER LETTER LOW TILDE;Sk;0;ON;;;;;N;;;;; +02F8;MODIFIER LETTER RAISED COLON;Sk;0;ON;;;;;N;;;;; +02F9;MODIFIER LETTER BEGIN HIGH TONE;Sk;0;ON;;;;;N;;;;; +02FA;MODIFIER LETTER END HIGH TONE;Sk;0;ON;;;;;N;;;;; +02FB;MODIFIER LETTER BEGIN LOW TONE;Sk;0;ON;;;;;N;;;;; +02FC;MODIFIER LETTER END LOW TONE;Sk;0;ON;;;;;N;;;;; +02FD;MODIFIER LETTER SHELF;Sk;0;ON;;;;;N;;;;; +02FE;MODIFIER LETTER OPEN SHELF;Sk;0;ON;;;;;N;;;;; +02FF;MODIFIER LETTER LOW LEFT ARROW;Sk;0;ON;;;;;N;;;;; +0300;COMBINING GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING GRAVE;;;; +0301;COMBINING ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING ACUTE;;;; +0302;COMBINING CIRCUMFLEX ACCENT;Mn;230;NSM;;;;;N;NON-SPACING CIRCUMFLEX;;;; +0303;COMBINING TILDE;Mn;230;NSM;;;;;N;NON-SPACING TILDE;;;; +0304;COMBINING MACRON;Mn;230;NSM;;;;;N;NON-SPACING MACRON;;;; +0305;COMBINING OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING OVERSCORE;;;; +0306;COMBINING BREVE;Mn;230;NSM;;;;;N;NON-SPACING BREVE;;;; +0307;COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOT ABOVE;;;; +0308;COMBINING DIAERESIS;Mn;230;NSM;;;;;N;NON-SPACING DIAERESIS;;;; +0309;COMBINING HOOK ABOVE;Mn;230;NSM;;;;;N;NON-SPACING HOOK ABOVE;;;; +030A;COMBINING RING ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RING ABOVE;;;; +030B;COMBINING DOUBLE ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE ACUTE;;;; +030C;COMBINING CARON;Mn;230;NSM;;;;;N;NON-SPACING HACEK;;;; +030D;COMBINING VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL LINE ABOVE;;;; +030E;COMBINING DOUBLE VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE VERTICAL LINE ABOVE;;;; +030F;COMBINING DOUBLE GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE GRAVE;;;; +0310;COMBINING CANDRABINDU;Mn;230;NSM;;;;;N;NON-SPACING CANDRABINDU;;;; +0311;COMBINING INVERTED BREVE;Mn;230;NSM;;;;;N;NON-SPACING INVERTED BREVE;;;; +0312;COMBINING TURNED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING TURNED COMMA ABOVE;;;; +0313;COMBINING COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING COMMA ABOVE;;;; +0314;COMBINING REVERSED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING REVERSED COMMA ABOVE;;;; +0315;COMBINING COMMA ABOVE RIGHT;Mn;232;NSM;;;;;N;NON-SPACING COMMA ABOVE RIGHT;;;; +0316;COMBINING GRAVE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING GRAVE BELOW;;;; +0317;COMBINING ACUTE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING ACUTE BELOW;;;; +0318;COMBINING LEFT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT TACK BELOW;;;; +0319;COMBINING RIGHT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT TACK BELOW;;;; +031A;COMBINING LEFT ANGLE ABOVE;Mn;232;NSM;;;;;N;NON-SPACING LEFT ANGLE ABOVE;;;; +031B;COMBINING HORN;Mn;216;NSM;;;;;N;NON-SPACING HORN;;;; +031C;COMBINING LEFT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT HALF RING BELOW;;;; +031D;COMBINING UP TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING UP TACK BELOW;;;; +031E;COMBINING DOWN TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOWN TACK BELOW;;;; +031F;COMBINING PLUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING PLUS SIGN BELOW;;;; +0320;COMBINING MINUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING MINUS SIGN BELOW;;;; +0321;COMBINING PALATALIZED HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING PALATALIZED HOOK BELOW;;;; +0322;COMBINING RETROFLEX HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING RETROFLEX HOOK BELOW;;;; +0323;COMBINING DOT BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOT BELOW;;;; +0324;COMBINING DIAERESIS BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE DOT BELOW;;;; +0325;COMBINING RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RING BELOW;;;; +0326;COMBINING COMMA BELOW;Mn;220;NSM;;;;;N;NON-SPACING COMMA BELOW;;;; +0327;COMBINING CEDILLA;Mn;202;NSM;;;;;N;NON-SPACING CEDILLA;;;; +0328;COMBINING OGONEK;Mn;202;NSM;;;;;N;NON-SPACING OGONEK;;;; +0329;COMBINING VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;NON-SPACING VERTICAL LINE BELOW;;;; +032A;COMBINING BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BRIDGE BELOW;;;; +032B;COMBINING INVERTED DOUBLE ARCH BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED DOUBLE ARCH BELOW;;;; +032C;COMBINING CARON BELOW;Mn;220;NSM;;;;;N;NON-SPACING HACEK BELOW;;;; +032D;COMBINING CIRCUMFLEX ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING CIRCUMFLEX BELOW;;;; +032E;COMBINING BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BREVE BELOW;;;; +032F;COMBINING INVERTED BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BREVE BELOW;;;; +0330;COMBINING TILDE BELOW;Mn;220;NSM;;;;;N;NON-SPACING TILDE BELOW;;;; +0331;COMBINING MACRON BELOW;Mn;220;NSM;;;;;N;NON-SPACING MACRON BELOW;;;; +0332;COMBINING LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING UNDERSCORE;;;; +0333;COMBINING DOUBLE LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE UNDERSCORE;;;; +0334;COMBINING TILDE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING TILDE OVERLAY;;;; +0335;COMBINING SHORT STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT BAR OVERLAY;;;; +0336;COMBINING LONG STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG BAR OVERLAY;;;; +0337;COMBINING SHORT SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT SLASH OVERLAY;;;; +0338;COMBINING LONG SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG SLASH OVERLAY;;;; +0339;COMBINING RIGHT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT HALF RING BELOW;;;; +033A;COMBINING INVERTED BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BRIDGE BELOW;;;; +033B;COMBINING SQUARE BELOW;Mn;220;NSM;;;;;N;NON-SPACING SQUARE BELOW;;;; +033C;COMBINING SEAGULL BELOW;Mn;220;NSM;;;;;N;NON-SPACING SEAGULL BELOW;;;; +033D;COMBINING X ABOVE;Mn;230;NSM;;;;;N;NON-SPACING X ABOVE;;;; +033E;COMBINING VERTICAL TILDE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL TILDE;;;; +033F;COMBINING DOUBLE OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE OVERSCORE;;;; +0340;COMBINING GRAVE TONE MARK;Mn;230;NSM;0300;;;;N;NON-SPACING GRAVE TONE MARK;;;; +0341;COMBINING ACUTE TONE MARK;Mn;230;NSM;0301;;;;N;NON-SPACING ACUTE TONE MARK;;;; +0342;COMBINING GREEK PERISPOMENI;Mn;230;NSM;;;;;N;;;;; +0343;COMBINING GREEK KORONIS;Mn;230;NSM;0313;;;;N;;;;; +0344;COMBINING GREEK DIALYTIKA TONOS;Mn;230;NSM;0308 0301;;;;N;GREEK NON-SPACING DIAERESIS TONOS;;;; +0345;COMBINING GREEK YPOGEGRAMMENI;Mn;240;NSM;;;;;N;GREEK NON-SPACING IOTA BELOW;;0399;;0399 +0346;COMBINING BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;; +0347;COMBINING EQUALS SIGN BELOW;Mn;220;NSM;;;;;N;;;;; +0348;COMBINING DOUBLE VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;;;;; +0349;COMBINING LEFT ANGLE BELOW;Mn;220;NSM;;;;;N;;;;; +034A;COMBINING NOT TILDE ABOVE;Mn;230;NSM;;;;;N;;;;; +034B;COMBINING HOMOTHETIC ABOVE;Mn;230;NSM;;;;;N;;;;; +034C;COMBINING ALMOST EQUAL TO ABOVE;Mn;230;NSM;;;;;N;;;;; +034D;COMBINING LEFT RIGHT ARROW BELOW;Mn;220;NSM;;;;;N;;;;; +034E;COMBINING UPWARDS ARROW BELOW;Mn;220;NSM;;;;;N;;;;; +034F;COMBINING GRAPHEME JOINER;Mn;0;NSM;;;;;N;;;;; +0350;COMBINING RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; +0351;COMBINING LEFT HALF RING ABOVE;Mn;230;NSM;;;;;N;;;;; +0352;COMBINING FERMATA;Mn;230;NSM;;;;;N;;;;; +0353;COMBINING X BELOW;Mn;220;NSM;;;;;N;;;;; +0354;COMBINING LEFT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; +0355;COMBINING RIGHT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; +0356;COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; +0357;COMBINING RIGHT HALF RING ABOVE;Mn;230;NSM;;;;;N;;;;; +0358;COMBINING DOT ABOVE RIGHT;Mn;232;NSM;;;;;N;;;;; +0359;COMBINING ASTERISK BELOW;Mn;220;NSM;;;;;N;;;;; +035A;COMBINING DOUBLE RING BELOW;Mn;220;NSM;;;;;N;;;;; +035B;COMBINING ZIGZAG ABOVE;Mn;230;NSM;;;;;N;;;;; +035C;COMBINING DOUBLE BREVE BELOW;Mn;233;NSM;;;;;N;;;;; +035D;COMBINING DOUBLE BREVE;Mn;234;NSM;;;;;N;;;;; +035E;COMBINING DOUBLE MACRON;Mn;234;NSM;;;;;N;;;;; +035F;COMBINING DOUBLE MACRON BELOW;Mn;233;NSM;;;;;N;;;;; +0360;COMBINING DOUBLE TILDE;Mn;234;NSM;;;;;N;;;;; +0361;COMBINING DOUBLE INVERTED BREVE;Mn;234;NSM;;;;;N;;;;; +0362;COMBINING DOUBLE RIGHTWARDS ARROW BELOW;Mn;233;NSM;;;;;N;;;;; +0363;COMBINING LATIN SMALL LETTER A;Mn;230;NSM;;;;;N;;;;; +0364;COMBINING LATIN SMALL LETTER E;Mn;230;NSM;;;;;N;;;;; +0365;COMBINING LATIN SMALL LETTER I;Mn;230;NSM;;;;;N;;;;; +0366;COMBINING LATIN SMALL LETTER O;Mn;230;NSM;;;;;N;;;;; +0367;COMBINING LATIN SMALL LETTER U;Mn;230;NSM;;;;;N;;;;; +0368;COMBINING LATIN SMALL LETTER C;Mn;230;NSM;;;;;N;;;;; +0369;COMBINING LATIN SMALL LETTER D;Mn;230;NSM;;;;;N;;;;; +036A;COMBINING LATIN SMALL LETTER H;Mn;230;NSM;;;;;N;;;;; +036B;COMBINING LATIN SMALL LETTER M;Mn;230;NSM;;;;;N;;;;; +036C;COMBINING LATIN SMALL LETTER R;Mn;230;NSM;;;;;N;;;;; +036D;COMBINING LATIN SMALL LETTER T;Mn;230;NSM;;;;;N;;;;; +036E;COMBINING LATIN SMALL LETTER V;Mn;230;NSM;;;;;N;;;;; +036F;COMBINING LATIN SMALL LETTER X;Mn;230;NSM;;;;;N;;;;; +0370;GREEK CAPITAL LETTER HETA;Lu;0;L;;;;;N;;;;0371; +0371;GREEK SMALL LETTER HETA;Ll;0;L;;;;;N;;;0370;;0370 +0372;GREEK CAPITAL LETTER ARCHAIC SAMPI;Lu;0;L;;;;;N;;;;0373; +0373;GREEK SMALL LETTER ARCHAIC SAMPI;Ll;0;L;;;;;N;;;0372;;0372 +0374;GREEK NUMERAL SIGN;Lm;0;ON;02B9;;;;N;GREEK UPPER NUMERAL SIGN;;;; +0375;GREEK LOWER NUMERAL SIGN;Sk;0;ON;;;;;N;;;;; +0376;GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA;Lu;0;L;;;;;N;;;;0377; +0377;GREEK SMALL LETTER PAMPHYLIAN DIGAMMA;Ll;0;L;;;;;N;;;0376;;0376 +037A;GREEK YPOGEGRAMMENI;Lm;0;L; 0020 0345;;;;N;GREEK SPACING IOTA BELOW;;;; +037B;GREEK SMALL REVERSED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FD;;03FD +037C;GREEK SMALL DOTTED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FE;;03FE +037D;GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FF;;03FF +037E;GREEK QUESTION MARK;Po;0;ON;003B;;;;N;;;;; +037F;GREEK CAPITAL LETTER YOT;Lu;0;L;;;;;N;;;;03F3; +0384;GREEK TONOS;Sk;0;ON; 0020 0301;;;;N;GREEK SPACING TONOS;;;; +0385;GREEK DIALYTIKA TONOS;Sk;0;ON;00A8 0301;;;;N;GREEK SPACING DIAERESIS TONOS;;;; +0386;GREEK CAPITAL LETTER ALPHA WITH TONOS;Lu;0;L;0391 0301;;;;N;GREEK CAPITAL LETTER ALPHA TONOS;;;03AC; +0387;GREEK ANO TELEIA;Po;0;ON;00B7;;;;N;;;;; +0388;GREEK CAPITAL LETTER EPSILON WITH TONOS;Lu;0;L;0395 0301;;;;N;GREEK CAPITAL LETTER EPSILON TONOS;;;03AD; +0389;GREEK CAPITAL LETTER ETA WITH TONOS;Lu;0;L;0397 0301;;;;N;GREEK CAPITAL LETTER ETA TONOS;;;03AE; +038A;GREEK CAPITAL LETTER IOTA WITH TONOS;Lu;0;L;0399 0301;;;;N;GREEK CAPITAL LETTER IOTA TONOS;;;03AF; +038C;GREEK CAPITAL LETTER OMICRON WITH TONOS;Lu;0;L;039F 0301;;;;N;GREEK CAPITAL LETTER OMICRON TONOS;;;03CC; +038E;GREEK CAPITAL LETTER UPSILON WITH TONOS;Lu;0;L;03A5 0301;;;;N;GREEK CAPITAL LETTER UPSILON TONOS;;;03CD; +038F;GREEK CAPITAL LETTER OMEGA WITH TONOS;Lu;0;L;03A9 0301;;;;N;GREEK CAPITAL LETTER OMEGA TONOS;;;03CE; +0390;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS;Ll;0;L;03CA 0301;;;;N;GREEK SMALL LETTER IOTA DIAERESIS TONOS;;;; +0391;GREEK CAPITAL LETTER ALPHA;Lu;0;L;;;;;N;;;;03B1; +0392;GREEK CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;03B2; +0393;GREEK CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;03B3; +0394;GREEK CAPITAL LETTER DELTA;Lu;0;L;;;;;N;;;;03B4; +0395;GREEK CAPITAL LETTER EPSILON;Lu;0;L;;;;;N;;;;03B5; +0396;GREEK CAPITAL LETTER ZETA;Lu;0;L;;;;;N;;;;03B6; +0397;GREEK CAPITAL LETTER ETA;Lu;0;L;;;;;N;;;;03B7; +0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8; +0399;GREEK CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;03B9; +039A;GREEK CAPITAL LETTER KAPPA;Lu;0;L;;;;;N;;;;03BA; +039B;GREEK CAPITAL LETTER LAMDA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER LAMBDA;;;03BB; +039C;GREEK CAPITAL LETTER MU;Lu;0;L;;;;;N;;;;03BC; +039D;GREEK CAPITAL LETTER NU;Lu;0;L;;;;;N;;;;03BD; +039E;GREEK CAPITAL LETTER XI;Lu;0;L;;;;;N;;;;03BE; +039F;GREEK CAPITAL LETTER OMICRON;Lu;0;L;;;;;N;;;;03BF; +03A0;GREEK CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;03C0; +03A1;GREEK CAPITAL LETTER RHO;Lu;0;L;;;;;N;;;;03C1; +03A3;GREEK CAPITAL LETTER SIGMA;Lu;0;L;;;;;N;;;;03C3; +03A4;GREEK CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;03C4; +03A5;GREEK CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;03C5; +03A6;GREEK CAPITAL LETTER PHI;Lu;0;L;;;;;N;;;;03C6; +03A7;GREEK CAPITAL LETTER CHI;Lu;0;L;;;;;N;;;;03C7; +03A8;GREEK CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;03C8; +03A9;GREEK CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;03C9; +03AA;GREEK CAPITAL LETTER IOTA WITH DIALYTIKA;Lu;0;L;0399 0308;;;;N;GREEK CAPITAL LETTER IOTA DIAERESIS;;;03CA; +03AB;GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA;Lu;0;L;03A5 0308;;;;N;GREEK CAPITAL LETTER UPSILON DIAERESIS;;;03CB; +03AC;GREEK SMALL LETTER ALPHA WITH TONOS;Ll;0;L;03B1 0301;;;;N;GREEK SMALL LETTER ALPHA TONOS;;0386;;0386 +03AD;GREEK SMALL LETTER EPSILON WITH TONOS;Ll;0;L;03B5 0301;;;;N;GREEK SMALL LETTER EPSILON TONOS;;0388;;0388 +03AE;GREEK SMALL LETTER ETA WITH TONOS;Ll;0;L;03B7 0301;;;;N;GREEK SMALL LETTER ETA TONOS;;0389;;0389 +03AF;GREEK SMALL LETTER IOTA WITH TONOS;Ll;0;L;03B9 0301;;;;N;GREEK SMALL LETTER IOTA TONOS;;038A;;038A +03B0;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS;Ll;0;L;03CB 0301;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS TONOS;;;; +03B1;GREEK SMALL LETTER ALPHA;Ll;0;L;;;;;N;;;0391;;0391 +03B2;GREEK SMALL LETTER BETA;Ll;0;L;;;;;N;;;0392;;0392 +03B3;GREEK SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0393;;0393 +03B4;GREEK SMALL LETTER DELTA;Ll;0;L;;;;;N;;;0394;;0394 +03B5;GREEK SMALL LETTER EPSILON;Ll;0;L;;;;;N;;;0395;;0395 +03B6;GREEK SMALL LETTER ZETA;Ll;0;L;;;;;N;;;0396;;0396 +03B7;GREEK SMALL LETTER ETA;Ll;0;L;;;;;N;;;0397;;0397 +03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398 +03B9;GREEK SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0399;;0399 +03BA;GREEK SMALL LETTER KAPPA;Ll;0;L;;;;;N;;;039A;;039A +03BB;GREEK SMALL LETTER LAMDA;Ll;0;L;;;;;N;GREEK SMALL LETTER LAMBDA;;039B;;039B +03BC;GREEK SMALL LETTER MU;Ll;0;L;;;;;N;;;039C;;039C +03BD;GREEK SMALL LETTER NU;Ll;0;L;;;;;N;;;039D;;039D +03BE;GREEK SMALL LETTER XI;Ll;0;L;;;;;N;;;039E;;039E +03BF;GREEK SMALL LETTER OMICRON;Ll;0;L;;;;;N;;;039F;;039F +03C0;GREEK SMALL LETTER PI;Ll;0;L;;;;;N;;;03A0;;03A0 +03C1;GREEK SMALL LETTER RHO;Ll;0;L;;;;;N;;;03A1;;03A1 +03C2;GREEK SMALL LETTER FINAL SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3 +03C3;GREEK SMALL LETTER SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3 +03C4;GREEK SMALL LETTER TAU;Ll;0;L;;;;;N;;;03A4;;03A4 +03C5;GREEK SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;03A5;;03A5 +03C6;GREEK SMALL LETTER PHI;Ll;0;L;;;;;N;;;03A6;;03A6 +03C7;GREEK SMALL LETTER CHI;Ll;0;L;;;;;N;;;03A7;;03A7 +03C8;GREEK SMALL LETTER PSI;Ll;0;L;;;;;N;;;03A8;;03A8 +03C9;GREEK SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;03A9;;03A9 +03CA;GREEK SMALL LETTER IOTA WITH DIALYTIKA;Ll;0;L;03B9 0308;;;;N;GREEK SMALL LETTER IOTA DIAERESIS;;03AA;;03AA +03CB;GREEK SMALL LETTER UPSILON WITH DIALYTIKA;Ll;0;L;03C5 0308;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS;;03AB;;03AB +03CC;GREEK SMALL LETTER OMICRON WITH TONOS;Ll;0;L;03BF 0301;;;;N;GREEK SMALL LETTER OMICRON TONOS;;038C;;038C +03CD;GREEK SMALL LETTER UPSILON WITH TONOS;Ll;0;L;03C5 0301;;;;N;GREEK SMALL LETTER UPSILON TONOS;;038E;;038E +03CE;GREEK SMALL LETTER OMEGA WITH TONOS;Ll;0;L;03C9 0301;;;;N;GREEK SMALL LETTER OMEGA TONOS;;038F;;038F +03CF;GREEK CAPITAL KAI SYMBOL;Lu;0;L;;;;;N;;;;03D7; +03D0;GREEK BETA SYMBOL;Ll;0;L; 03B2;;;;N;GREEK SMALL LETTER CURLED BETA;;0392;;0392 +03D1;GREEK THETA SYMBOL;Ll;0;L; 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398 +03D2;GREEK UPSILON WITH HOOK SYMBOL;Lu;0;L; 03A5;;;;N;GREEK CAPITAL LETTER UPSILON HOOK;;;; +03D3;GREEK UPSILON WITH ACUTE AND HOOK SYMBOL;Lu;0;L;03D2 0301;;;;N;GREEK CAPITAL LETTER UPSILON HOOK TONOS;;;; +03D4;GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL;Lu;0;L;03D2 0308;;;;N;GREEK CAPITAL LETTER UPSILON HOOK DIAERESIS;;;; +03D5;GREEK PHI SYMBOL;Ll;0;L; 03C6;;;;N;GREEK SMALL LETTER SCRIPT PHI;;03A6;;03A6 +03D6;GREEK PI SYMBOL;Ll;0;L; 03C0;;;;N;GREEK SMALL LETTER OMEGA PI;;03A0;;03A0 +03D7;GREEK KAI SYMBOL;Ll;0;L;;;;;N;;;03CF;;03CF +03D8;GREEK LETTER ARCHAIC KOPPA;Lu;0;L;;;;;N;;;;03D9; +03D9;GREEK SMALL LETTER ARCHAIC KOPPA;Ll;0;L;;;;;N;;;03D8;;03D8 +03DA;GREEK LETTER STIGMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER STIGMA;;;03DB; +03DB;GREEK SMALL LETTER STIGMA;Ll;0;L;;;;;N;;;03DA;;03DA +03DC;GREEK LETTER DIGAMMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DIGAMMA;;;03DD; +03DD;GREEK SMALL LETTER DIGAMMA;Ll;0;L;;;;;N;;;03DC;;03DC +03DE;GREEK LETTER KOPPA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KOPPA;;;03DF; +03DF;GREEK SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;03DE;;03DE +03E0;GREEK LETTER SAMPI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SAMPI;;;03E1; +03E1;GREEK SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;03E0;;03E0 +03E2;COPTIC CAPITAL LETTER SHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHEI;;;03E3; +03E3;COPTIC SMALL LETTER SHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER SHEI;;03E2;;03E2 +03E4;COPTIC CAPITAL LETTER FEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER FEI;;;03E5; +03E5;COPTIC SMALL LETTER FEI;Ll;0;L;;;;;N;GREEK SMALL LETTER FEI;;03E4;;03E4 +03E6;COPTIC CAPITAL LETTER KHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KHEI;;;03E7; +03E7;COPTIC SMALL LETTER KHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER KHEI;;03E6;;03E6 +03E8;COPTIC CAPITAL LETTER HORI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER HORI;;;03E9; +03E9;COPTIC SMALL LETTER HORI;Ll;0;L;;;;;N;GREEK SMALL LETTER HORI;;03E8;;03E8 +03EA;COPTIC CAPITAL LETTER GANGIA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER GANGIA;;;03EB; +03EB;COPTIC SMALL LETTER GANGIA;Ll;0;L;;;;;N;GREEK SMALL LETTER GANGIA;;03EA;;03EA +03EC;COPTIC CAPITAL LETTER SHIMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHIMA;;;03ED; +03ED;COPTIC SMALL LETTER SHIMA;Ll;0;L;;;;;N;GREEK SMALL LETTER SHIMA;;03EC;;03EC +03EE;COPTIC CAPITAL LETTER DEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DEI;;;03EF; +03EF;COPTIC SMALL LETTER DEI;Ll;0;L;;;;;N;GREEK SMALL LETTER DEI;;03EE;;03EE +03F0;GREEK KAPPA SYMBOL;Ll;0;L; 03BA;;;;N;GREEK SMALL LETTER SCRIPT KAPPA;;039A;;039A +03F1;GREEK RHO SYMBOL;Ll;0;L; 03C1;;;;N;GREEK SMALL LETTER TAILED RHO;;03A1;;03A1 +03F2;GREEK LUNATE SIGMA SYMBOL;Ll;0;L; 03C2;;;;N;GREEK SMALL LETTER LUNATE SIGMA;;03F9;;03F9 +03F3;GREEK LETTER YOT;Ll;0;L;;;;;N;;;037F;;037F +03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L; 0398;;;;N;;;;03B8; +03F5;GREEK LUNATE EPSILON SYMBOL;Ll;0;L; 03B5;;;;N;;;0395;;0395 +03F6;GREEK REVERSED LUNATE EPSILON SYMBOL;Sm;0;ON;;;;;N;;;;; +03F7;GREEK CAPITAL LETTER SHO;Lu;0;L;;;;;N;;;;03F8; +03F8;GREEK SMALL LETTER SHO;Ll;0;L;;;;;N;;;03F7;;03F7 +03F9;GREEK CAPITAL LUNATE SIGMA SYMBOL;Lu;0;L; 03A3;;;;N;;;;03F2; +03FA;GREEK CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;03FB; +03FB;GREEK SMALL LETTER SAN;Ll;0;L;;;;;N;;;03FA;;03FA +03FC;GREEK RHO WITH STROKE SYMBOL;Ll;0;L;;;;;N;;;;; +03FD;GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;037B; +03FE;GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;037C; +03FF;GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;037D; +0400;CYRILLIC CAPITAL LETTER IE WITH GRAVE;Lu;0;L;0415 0300;;;;N;;;;0450; +0401;CYRILLIC CAPITAL LETTER IO;Lu;0;L;0415 0308;;;;N;;;;0451; +0402;CYRILLIC CAPITAL LETTER DJE;Lu;0;L;;;;;N;;;;0452; +0403;CYRILLIC CAPITAL LETTER GJE;Lu;0;L;0413 0301;;;;N;;;;0453; +0404;CYRILLIC CAPITAL LETTER UKRAINIAN IE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER E;;;0454; +0405;CYRILLIC CAPITAL LETTER DZE;Lu;0;L;;;;;N;;;;0455; +0406;CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER I;;;0456; +0407;CYRILLIC CAPITAL LETTER YI;Lu;0;L;0406 0308;;;;N;;;;0457; +0408;CYRILLIC CAPITAL LETTER JE;Lu;0;L;;;;;N;;;;0458; +0409;CYRILLIC CAPITAL LETTER LJE;Lu;0;L;;;;;N;;;;0459; +040A;CYRILLIC CAPITAL LETTER NJE;Lu;0;L;;;;;N;;;;045A; +040B;CYRILLIC CAPITAL LETTER TSHE;Lu;0;L;;;;;N;;;;045B; +040C;CYRILLIC CAPITAL LETTER KJE;Lu;0;L;041A 0301;;;;N;;;;045C; +040D;CYRILLIC CAPITAL LETTER I WITH GRAVE;Lu;0;L;0418 0300;;;;N;;;;045D; +040E;CYRILLIC CAPITAL LETTER SHORT U;Lu;0;L;0423 0306;;;;N;;;;045E; +040F;CYRILLIC CAPITAL LETTER DZHE;Lu;0;L;;;;;N;;;;045F; +0410;CYRILLIC CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0430; +0411;CYRILLIC CAPITAL LETTER BE;Lu;0;L;;;;;N;;;;0431; +0412;CYRILLIC CAPITAL LETTER VE;Lu;0;L;;;;;N;;;;0432; +0413;CYRILLIC CAPITAL LETTER GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE;;;0433; +0414;CYRILLIC CAPITAL LETTER DE;Lu;0;L;;;;;N;;;;0434; +0415;CYRILLIC CAPITAL LETTER IE;Lu;0;L;;;;;N;;;;0435; +0416;CYRILLIC CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;0436; +0417;CYRILLIC CAPITAL LETTER ZE;Lu;0;L;;;;;N;;;;0437; +0418;CYRILLIC CAPITAL LETTER I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER II;;;0438; +0419;CYRILLIC CAPITAL LETTER SHORT I;Lu;0;L;0418 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT II;;;0439; +041A;CYRILLIC CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;043A; +041B;CYRILLIC CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;043B; +041C;CYRILLIC CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;043C; +041D;CYRILLIC CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;043D; +041E;CYRILLIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;043E; +041F;CYRILLIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;043F; +0420;CYRILLIC CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;0440; +0421;CYRILLIC CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;0441; +0422;CYRILLIC CAPITAL LETTER TE;Lu;0;L;;;;;N;;;;0442; +0423;CYRILLIC CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0443; +0424;CYRILLIC CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;0444; +0425;CYRILLIC CAPITAL LETTER HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA;;;0445; +0426;CYRILLIC CAPITAL LETTER TSE;Lu;0;L;;;;;N;;;;0446; +0427;CYRILLIC CAPITAL LETTER CHE;Lu;0;L;;;;;N;;;;0447; +0428;CYRILLIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0448; +0429;CYRILLIC CAPITAL LETTER SHCHA;Lu;0;L;;;;;N;;;;0449; +042A;CYRILLIC CAPITAL LETTER HARD SIGN;Lu;0;L;;;;;N;;;;044A; +042B;CYRILLIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER YERI;;;044B; +042C;CYRILLIC CAPITAL LETTER SOFT SIGN;Lu;0;L;;;;;N;;;;044C; +042D;CYRILLIC CAPITAL LETTER E;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED E;;;044D; +042E;CYRILLIC CAPITAL LETTER YU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IU;;;044E; +042F;CYRILLIC CAPITAL LETTER YA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IA;;;044F; +0430;CYRILLIC SMALL LETTER A;Ll;0;L;;;;;N;;;0410;;0410 +0431;CYRILLIC SMALL LETTER BE;Ll;0;L;;;;;N;;;0411;;0411 +0432;CYRILLIC SMALL LETTER VE;Ll;0;L;;;;;N;;;0412;;0412 +0433;CYRILLIC SMALL LETTER GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE;;0413;;0413 +0434;CYRILLIC SMALL LETTER DE;Ll;0;L;;;;;N;;;0414;;0414 +0435;CYRILLIC SMALL LETTER IE;Ll;0;L;;;;;N;;;0415;;0415 +0436;CYRILLIC SMALL LETTER ZHE;Ll;0;L;;;;;N;;;0416;;0416 +0437;CYRILLIC SMALL LETTER ZE;Ll;0;L;;;;;N;;;0417;;0417 +0438;CYRILLIC SMALL LETTER I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER II;;0418;;0418 +0439;CYRILLIC SMALL LETTER SHORT I;Ll;0;L;0438 0306;;;;N;CYRILLIC SMALL LETTER SHORT II;;0419;;0419 +043A;CYRILLIC SMALL LETTER KA;Ll;0;L;;;;;N;;;041A;;041A +043B;CYRILLIC SMALL LETTER EL;Ll;0;L;;;;;N;;;041B;;041B +043C;CYRILLIC SMALL LETTER EM;Ll;0;L;;;;;N;;;041C;;041C +043D;CYRILLIC SMALL LETTER EN;Ll;0;L;;;;;N;;;041D;;041D +043E;CYRILLIC SMALL LETTER O;Ll;0;L;;;;;N;;;041E;;041E +043F;CYRILLIC SMALL LETTER PE;Ll;0;L;;;;;N;;;041F;;041F +0440;CYRILLIC SMALL LETTER ER;Ll;0;L;;;;;N;;;0420;;0420 +0441;CYRILLIC SMALL LETTER ES;Ll;0;L;;;;;N;;;0421;;0421 +0442;CYRILLIC SMALL LETTER TE;Ll;0;L;;;;;N;;;0422;;0422 +0443;CYRILLIC SMALL LETTER U;Ll;0;L;;;;;N;;;0423;;0423 +0444;CYRILLIC SMALL LETTER EF;Ll;0;L;;;;;N;;;0424;;0424 +0445;CYRILLIC SMALL LETTER HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA;;0425;;0425 +0446;CYRILLIC SMALL LETTER TSE;Ll;0;L;;;;;N;;;0426;;0426 +0447;CYRILLIC SMALL LETTER CHE;Ll;0;L;;;;;N;;;0427;;0427 +0448;CYRILLIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;0428;;0428 +0449;CYRILLIC SMALL LETTER SHCHA;Ll;0;L;;;;;N;;;0429;;0429 +044A;CYRILLIC SMALL LETTER HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A +044B;CYRILLIC SMALL LETTER YERU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER YERI;;042B;;042B +044C;CYRILLIC SMALL LETTER SOFT SIGN;Ll;0;L;;;;;N;;;042C;;042C +044D;CYRILLIC SMALL LETTER E;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED E;;042D;;042D +044E;CYRILLIC SMALL LETTER YU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IU;;042E;;042E +044F;CYRILLIC SMALL LETTER YA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IA;;042F;;042F +0450;CYRILLIC SMALL LETTER IE WITH GRAVE;Ll;0;L;0435 0300;;;;N;;;0400;;0400 +0451;CYRILLIC SMALL LETTER IO;Ll;0;L;0435 0308;;;;N;;;0401;;0401 +0452;CYRILLIC SMALL LETTER DJE;Ll;0;L;;;;;N;;;0402;;0402 +0453;CYRILLIC SMALL LETTER GJE;Ll;0;L;0433 0301;;;;N;;;0403;;0403 +0454;CYRILLIC SMALL LETTER UKRAINIAN IE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER E;;0404;;0404 +0455;CYRILLIC SMALL LETTER DZE;Ll;0;L;;;;;N;;;0405;;0405 +0456;CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER I;;0406;;0406 +0457;CYRILLIC SMALL LETTER YI;Ll;0;L;0456 0308;;;;N;;;0407;;0407 +0458;CYRILLIC SMALL LETTER JE;Ll;0;L;;;;;N;;;0408;;0408 +0459;CYRILLIC SMALL LETTER LJE;Ll;0;L;;;;;N;;;0409;;0409 +045A;CYRILLIC SMALL LETTER NJE;Ll;0;L;;;;;N;;;040A;;040A +045B;CYRILLIC SMALL LETTER TSHE;Ll;0;L;;;;;N;;;040B;;040B +045C;CYRILLIC SMALL LETTER KJE;Ll;0;L;043A 0301;;;;N;;;040C;;040C +045D;CYRILLIC SMALL LETTER I WITH GRAVE;Ll;0;L;0438 0300;;;;N;;;040D;;040D +045E;CYRILLIC SMALL LETTER SHORT U;Ll;0;L;0443 0306;;;;N;;;040E;;040E +045F;CYRILLIC SMALL LETTER DZHE;Ll;0;L;;;;;N;;;040F;;040F +0460;CYRILLIC CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;0461; +0461;CYRILLIC SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;0460;;0460 +0462;CYRILLIC CAPITAL LETTER YAT;Lu;0;L;;;;;N;;;;0463; +0463;CYRILLIC SMALL LETTER YAT;Ll;0;L;;;;;N;;;0462;;0462 +0464;CYRILLIC CAPITAL LETTER IOTIFIED E;Lu;0;L;;;;;N;;;;0465; +0465;CYRILLIC SMALL LETTER IOTIFIED E;Ll;0;L;;;;;N;;;0464;;0464 +0466;CYRILLIC CAPITAL LETTER LITTLE YUS;Lu;0;L;;;;;N;;;;0467; +0467;CYRILLIC SMALL LETTER LITTLE YUS;Ll;0;L;;;;;N;;;0466;;0466 +0468;CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS;Lu;0;L;;;;;N;;;;0469; +0469;CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS;Ll;0;L;;;;;N;;;0468;;0468 +046A;CYRILLIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;046B; +046B;CYRILLIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;046A;;046A +046C;CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS;Lu;0;L;;;;;N;;;;046D; +046D;CYRILLIC SMALL LETTER IOTIFIED BIG YUS;Ll;0;L;;;;;N;;;046C;;046C +046E;CYRILLIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;046F; +046F;CYRILLIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;046E;;046E +0470;CYRILLIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;0471; +0471;CYRILLIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;0470;;0470 +0472;CYRILLIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;0473; +0473;CYRILLIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;0472;;0472 +0474;CYRILLIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;0475; +0475;CYRILLIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;0474;;0474 +0476;CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Lu;0;L;0474 030F;;;;N;CYRILLIC CAPITAL LETTER IZHITSA DOUBLE GRAVE;;;0477; +0477;CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Ll;0;L;0475 030F;;;;N;CYRILLIC SMALL LETTER IZHITSA DOUBLE GRAVE;;0476;;0476 +0478;CYRILLIC CAPITAL LETTER UK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER UK DIGRAPH;;;0479; +0479;CYRILLIC SMALL LETTER UK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER UK DIGRAPH;;0478;;0478 +047A;CYRILLIC CAPITAL LETTER ROUND OMEGA;Lu;0;L;;;;;N;;;;047B; +047B;CYRILLIC SMALL LETTER ROUND OMEGA;Ll;0;L;;;;;N;;;047A;;047A +047C;CYRILLIC CAPITAL LETTER OMEGA WITH TITLO;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER OMEGA TITLO;;;047D; +047D;CYRILLIC SMALL LETTER OMEGA WITH TITLO;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER OMEGA TITLO;;047C;;047C +047E;CYRILLIC CAPITAL LETTER OT;Lu;0;L;;;;;N;;;;047F; +047F;CYRILLIC SMALL LETTER OT;Ll;0;L;;;;;N;;;047E;;047E +0480;CYRILLIC CAPITAL LETTER KOPPA;Lu;0;L;;;;;N;;;;0481; +0481;CYRILLIC SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;0480;;0480 +0482;CYRILLIC THOUSANDS SIGN;So;0;L;;;;;N;;;;; +0483;COMBINING CYRILLIC TITLO;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING TITLO;;;; +0484;COMBINING CYRILLIC PALATALIZATION;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PALATALIZATION;;;; +0485;COMBINING CYRILLIC DASIA PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING DASIA PNEUMATA;;;; +0486;COMBINING CYRILLIC PSILI PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PSILI PNEUMATA;;;; +0487;COMBINING CYRILLIC POKRYTIE;Mn;230;NSM;;;;;N;;;;; +0488;COMBINING CYRILLIC HUNDRED THOUSANDS SIGN;Me;0;NSM;;;;;N;;;;; +0489;COMBINING CYRILLIC MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; +048A;CYRILLIC CAPITAL LETTER SHORT I WITH TAIL;Lu;0;L;;;;;N;;;;048B; +048B;CYRILLIC SMALL LETTER SHORT I WITH TAIL;Ll;0;L;;;;;N;;;048A;;048A +048C;CYRILLIC CAPITAL LETTER SEMISOFT SIGN;Lu;0;L;;;;;N;;;;048D; +048D;CYRILLIC SMALL LETTER SEMISOFT SIGN;Ll;0;L;;;;;N;;;048C;;048C +048E;CYRILLIC CAPITAL LETTER ER WITH TICK;Lu;0;L;;;;;N;;;;048F; +048F;CYRILLIC SMALL LETTER ER WITH TICK;Ll;0;L;;;;;N;;;048E;;048E +0490;CYRILLIC CAPITAL LETTER GHE WITH UPTURN;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE WITH UPTURN;;;0491; +0491;CYRILLIC SMALL LETTER GHE WITH UPTURN;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE WITH UPTURN;;0490;;0490 +0492;CYRILLIC CAPITAL LETTER GHE WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE BAR;;;0493; +0493;CYRILLIC SMALL LETTER GHE WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE BAR;;0492;;0492 +0494;CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE HOOK;;;0495; +0495;CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE HOOK;;0494;;0494 +0496;CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZHE WITH RIGHT DESCENDER;;;0497; +0497;CYRILLIC SMALL LETTER ZHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZHE WITH RIGHT DESCENDER;;0496;;0496 +0498;CYRILLIC CAPITAL LETTER ZE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZE CEDILLA;;;0499; +0499;CYRILLIC SMALL LETTER ZE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZE CEDILLA;;0498;;0498 +049A;CYRILLIC CAPITAL LETTER KA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA WITH RIGHT DESCENDER;;;049B; +049B;CYRILLIC SMALL LETTER KA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA WITH RIGHT DESCENDER;;049A;;049A +049C;CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA VERTICAL BAR;;;049D; +049D;CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA VERTICAL BAR;;049C;;049C +049E;CYRILLIC CAPITAL LETTER KA WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA BAR;;;049F; +049F;CYRILLIC SMALL LETTER KA WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA BAR;;049E;;049E +04A0;CYRILLIC CAPITAL LETTER BASHKIR KA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED GE KA;;;04A1; +04A1;CYRILLIC SMALL LETTER BASHKIR KA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED GE KA;;04A0;;04A0 +04A2;CYRILLIC CAPITAL LETTER EN WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN WITH RIGHT DESCENDER;;;04A3; +04A3;CYRILLIC SMALL LETTER EN WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN WITH RIGHT DESCENDER;;04A2;;04A2 +04A4;CYRILLIC CAPITAL LIGATURE EN GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN GE;;;04A5; +04A5;CYRILLIC SMALL LIGATURE EN GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN GE;;04A4;;04A4 +04A6;CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER PE HOOK;;;04A7; +04A7;CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER PE HOOK;;04A6;;04A6 +04A8;CYRILLIC CAPITAL LETTER ABKHASIAN HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER O HOOK;;;04A9; +04A9;CYRILLIC SMALL LETTER ABKHASIAN HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER O HOOK;;04A8;;04A8 +04AA;CYRILLIC CAPITAL LETTER ES WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ES CEDILLA;;;04AB; +04AB;CYRILLIC SMALL LETTER ES WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ES CEDILLA;;04AA;;04AA +04AC;CYRILLIC CAPITAL LETTER TE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE WITH RIGHT DESCENDER;;;04AD; +04AD;CYRILLIC SMALL LETTER TE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE WITH RIGHT DESCENDER;;04AC;;04AC +04AE;CYRILLIC CAPITAL LETTER STRAIGHT U;Lu;0;L;;;;;N;;;;04AF; +04AF;CYRILLIC SMALL LETTER STRAIGHT U;Ll;0;L;;;;;N;;;04AE;;04AE +04B0;CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER STRAIGHT U BAR;;;04B1; +04B1;CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER STRAIGHT U BAR;;04B0;;04B0 +04B2;CYRILLIC CAPITAL LETTER HA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA WITH RIGHT DESCENDER;;;04B3; +04B3;CYRILLIC SMALL LETTER HA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA WITH RIGHT DESCENDER;;04B2;;04B2 +04B4;CYRILLIC CAPITAL LIGATURE TE TSE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE TSE;;;04B5; +04B5;CYRILLIC SMALL LIGATURE TE TSE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE TSE;;04B4;;04B4 +04B6;CYRILLIC CAPITAL LETTER CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH RIGHT DESCENDER;;;04B7; +04B7;CYRILLIC SMALL LETTER CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH RIGHT DESCENDER;;04B6;;04B6 +04B8;CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE VERTICAL BAR;;;04B9; +04B9;CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE VERTICAL BAR;;04B8;;04B8 +04BA;CYRILLIC CAPITAL LETTER SHHA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER H;;;04BB; +04BB;CYRILLIC SMALL LETTER SHHA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER H;;04BA;;04BA +04BC;CYRILLIC CAPITAL LETTER ABKHASIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK;;;04BD; +04BD;CYRILLIC SMALL LETTER ABKHASIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK;;04BC;;04BC +04BE;CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK OGONEK;;;04BF; +04BF;CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK OGONEK;;04BE;;04BE +04C0;CYRILLIC LETTER PALOCHKA;Lu;0;L;;;;;N;CYRILLIC LETTER I;;;04CF; +04C1;CYRILLIC CAPITAL LETTER ZHE WITH BREVE;Lu;0;L;0416 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT ZHE;;;04C2; +04C2;CYRILLIC SMALL LETTER ZHE WITH BREVE;Ll;0;L;0436 0306;;;;N;CYRILLIC SMALL LETTER SHORT ZHE;;04C1;;04C1 +04C3;CYRILLIC CAPITAL LETTER KA WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA HOOK;;;04C4; +04C4;CYRILLIC SMALL LETTER KA WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA HOOK;;04C3;;04C3 +04C5;CYRILLIC CAPITAL LETTER EL WITH TAIL;Lu;0;L;;;;;N;;;;04C6; +04C6;CYRILLIC SMALL LETTER EL WITH TAIL;Ll;0;L;;;;;N;;;04C5;;04C5 +04C7;CYRILLIC CAPITAL LETTER EN WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN HOOK;;;04C8; +04C8;CYRILLIC SMALL LETTER EN WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN HOOK;;04C7;;04C7 +04C9;CYRILLIC CAPITAL LETTER EN WITH TAIL;Lu;0;L;;;;;N;;;;04CA; +04CA;CYRILLIC SMALL LETTER EN WITH TAIL;Ll;0;L;;;;;N;;;04C9;;04C9 +04CB;CYRILLIC CAPITAL LETTER KHAKASSIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH LEFT DESCENDER;;;04CC; +04CC;CYRILLIC SMALL LETTER KHAKASSIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH LEFT DESCENDER;;04CB;;04CB +04CD;CYRILLIC CAPITAL LETTER EM WITH TAIL;Lu;0;L;;;;;N;;;;04CE; +04CE;CYRILLIC SMALL LETTER EM WITH TAIL;Ll;0;L;;;;;N;;;04CD;;04CD +04CF;CYRILLIC SMALL LETTER PALOCHKA;Ll;0;L;;;;;N;;;04C0;;04C0 +04D0;CYRILLIC CAPITAL LETTER A WITH BREVE;Lu;0;L;0410 0306;;;;N;;;;04D1; +04D1;CYRILLIC SMALL LETTER A WITH BREVE;Ll;0;L;0430 0306;;;;N;;;04D0;;04D0 +04D2;CYRILLIC CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0410 0308;;;;N;;;;04D3; +04D3;CYRILLIC SMALL LETTER A WITH DIAERESIS;Ll;0;L;0430 0308;;;;N;;;04D2;;04D2 +04D4;CYRILLIC CAPITAL LIGATURE A IE;Lu;0;L;;;;;N;;;;04D5; +04D5;CYRILLIC SMALL LIGATURE A IE;Ll;0;L;;;;;N;;;04D4;;04D4 +04D6;CYRILLIC CAPITAL LETTER IE WITH BREVE;Lu;0;L;0415 0306;;;;N;;;;04D7; +04D7;CYRILLIC SMALL LETTER IE WITH BREVE;Ll;0;L;0435 0306;;;;N;;;04D6;;04D6 +04D8;CYRILLIC CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;04D9; +04D9;CYRILLIC SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;04D8;;04D8 +04DA;CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS;Lu;0;L;04D8 0308;;;;N;;;;04DB; +04DB;CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS;Ll;0;L;04D9 0308;;;;N;;;04DA;;04DA +04DC;CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS;Lu;0;L;0416 0308;;;;N;;;;04DD; +04DD;CYRILLIC SMALL LETTER ZHE WITH DIAERESIS;Ll;0;L;0436 0308;;;;N;;;04DC;;04DC +04DE;CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS;Lu;0;L;0417 0308;;;;N;;;;04DF; +04DF;CYRILLIC SMALL LETTER ZE WITH DIAERESIS;Ll;0;L;0437 0308;;;;N;;;04DE;;04DE +04E0;CYRILLIC CAPITAL LETTER ABKHASIAN DZE;Lu;0;L;;;;;N;;;;04E1; +04E1;CYRILLIC SMALL LETTER ABKHASIAN DZE;Ll;0;L;;;;;N;;;04E0;;04E0 +04E2;CYRILLIC CAPITAL LETTER I WITH MACRON;Lu;0;L;0418 0304;;;;N;;;;04E3; +04E3;CYRILLIC SMALL LETTER I WITH MACRON;Ll;0;L;0438 0304;;;;N;;;04E2;;04E2 +04E4;CYRILLIC CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0418 0308;;;;N;;;;04E5; +04E5;CYRILLIC SMALL LETTER I WITH DIAERESIS;Ll;0;L;0438 0308;;;;N;;;04E4;;04E4 +04E6;CYRILLIC CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;041E 0308;;;;N;;;;04E7; +04E7;CYRILLIC SMALL LETTER O WITH DIAERESIS;Ll;0;L;043E 0308;;;;N;;;04E6;;04E6 +04E8;CYRILLIC CAPITAL LETTER BARRED O;Lu;0;L;;;;;N;;;;04E9; +04E9;CYRILLIC SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;04E8;;04E8 +04EA;CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS;Lu;0;L;04E8 0308;;;;N;;;;04EB; +04EB;CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS;Ll;0;L;04E9 0308;;;;N;;;04EA;;04EA +04EC;CYRILLIC CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;042D 0308;;;;N;;;;04ED; +04ED;CYRILLIC SMALL LETTER E WITH DIAERESIS;Ll;0;L;044D 0308;;;;N;;;04EC;;04EC +04EE;CYRILLIC CAPITAL LETTER U WITH MACRON;Lu;0;L;0423 0304;;;;N;;;;04EF; +04EF;CYRILLIC SMALL LETTER U WITH MACRON;Ll;0;L;0443 0304;;;;N;;;04EE;;04EE +04F0;CYRILLIC CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0423 0308;;;;N;;;;04F1; +04F1;CYRILLIC SMALL LETTER U WITH DIAERESIS;Ll;0;L;0443 0308;;;;N;;;04F0;;04F0 +04F2;CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0423 030B;;;;N;;;;04F3; +04F3;CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0443 030B;;;;N;;;04F2;;04F2 +04F4;CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS;Lu;0;L;0427 0308;;;;N;;;;04F5; +04F5;CYRILLIC SMALL LETTER CHE WITH DIAERESIS;Ll;0;L;0447 0308;;;;N;;;04F4;;04F4 +04F6;CYRILLIC CAPITAL LETTER GHE WITH DESCENDER;Lu;0;L;;;;;N;;;;04F7; +04F7;CYRILLIC SMALL LETTER GHE WITH DESCENDER;Ll;0;L;;;;;N;;;04F6;;04F6 +04F8;CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS;Lu;0;L;042B 0308;;;;N;;;;04F9; +04F9;CYRILLIC SMALL LETTER YERU WITH DIAERESIS;Ll;0;L;044B 0308;;;;N;;;04F8;;04F8 +04FA;CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK;Lu;0;L;;;;;N;;;;04FB; +04FB;CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK;Ll;0;L;;;;;N;;;04FA;;04FA +04FC;CYRILLIC CAPITAL LETTER HA WITH HOOK;Lu;0;L;;;;;N;;;;04FD; +04FD;CYRILLIC SMALL LETTER HA WITH HOOK;Ll;0;L;;;;;N;;;04FC;;04FC +04FE;CYRILLIC CAPITAL LETTER HA WITH STROKE;Lu;0;L;;;;;N;;;;04FF; +04FF;CYRILLIC SMALL LETTER HA WITH STROKE;Ll;0;L;;;;;N;;;04FE;;04FE +0500;CYRILLIC CAPITAL LETTER KOMI DE;Lu;0;L;;;;;N;;;;0501; +0501;CYRILLIC SMALL LETTER KOMI DE;Ll;0;L;;;;;N;;;0500;;0500 +0502;CYRILLIC CAPITAL LETTER KOMI DJE;Lu;0;L;;;;;N;;;;0503; +0503;CYRILLIC SMALL LETTER KOMI DJE;Ll;0;L;;;;;N;;;0502;;0502 +0504;CYRILLIC CAPITAL LETTER KOMI ZJE;Lu;0;L;;;;;N;;;;0505; +0505;CYRILLIC SMALL LETTER KOMI ZJE;Ll;0;L;;;;;N;;;0504;;0504 +0506;CYRILLIC CAPITAL LETTER KOMI DZJE;Lu;0;L;;;;;N;;;;0507; +0507;CYRILLIC SMALL LETTER KOMI DZJE;Ll;0;L;;;;;N;;;0506;;0506 +0508;CYRILLIC CAPITAL LETTER KOMI LJE;Lu;0;L;;;;;N;;;;0509; +0509;CYRILLIC SMALL LETTER KOMI LJE;Ll;0;L;;;;;N;;;0508;;0508 +050A;CYRILLIC CAPITAL LETTER KOMI NJE;Lu;0;L;;;;;N;;;;050B; +050B;CYRILLIC SMALL LETTER KOMI NJE;Ll;0;L;;;;;N;;;050A;;050A +050C;CYRILLIC CAPITAL LETTER KOMI SJE;Lu;0;L;;;;;N;;;;050D; +050D;CYRILLIC SMALL LETTER KOMI SJE;Ll;0;L;;;;;N;;;050C;;050C +050E;CYRILLIC CAPITAL LETTER KOMI TJE;Lu;0;L;;;;;N;;;;050F; +050F;CYRILLIC SMALL LETTER KOMI TJE;Ll;0;L;;;;;N;;;050E;;050E +0510;CYRILLIC CAPITAL LETTER REVERSED ZE;Lu;0;L;;;;;N;;;;0511; +0511;CYRILLIC SMALL LETTER REVERSED ZE;Ll;0;L;;;;;N;;;0510;;0510 +0512;CYRILLIC CAPITAL LETTER EL WITH HOOK;Lu;0;L;;;;;N;;;;0513; +0513;CYRILLIC SMALL LETTER EL WITH HOOK;Ll;0;L;;;;;N;;;0512;;0512 +0514;CYRILLIC CAPITAL LETTER LHA;Lu;0;L;;;;;N;;;;0515; +0515;CYRILLIC SMALL LETTER LHA;Ll;0;L;;;;;N;;;0514;;0514 +0516;CYRILLIC CAPITAL LETTER RHA;Lu;0;L;;;;;N;;;;0517; +0517;CYRILLIC SMALL LETTER RHA;Ll;0;L;;;;;N;;;0516;;0516 +0518;CYRILLIC CAPITAL LETTER YAE;Lu;0;L;;;;;N;;;;0519; +0519;CYRILLIC SMALL LETTER YAE;Ll;0;L;;;;;N;;;0518;;0518 +051A;CYRILLIC CAPITAL LETTER QA;Lu;0;L;;;;;N;;;;051B; +051B;CYRILLIC SMALL LETTER QA;Ll;0;L;;;;;N;;;051A;;051A +051C;CYRILLIC CAPITAL LETTER WE;Lu;0;L;;;;;N;;;;051D; +051D;CYRILLIC SMALL LETTER WE;Ll;0;L;;;;;N;;;051C;;051C +051E;CYRILLIC CAPITAL LETTER ALEUT KA;Lu;0;L;;;;;N;;;;051F; +051F;CYRILLIC SMALL LETTER ALEUT KA;Ll;0;L;;;;;N;;;051E;;051E +0520;CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK;Lu;0;L;;;;;N;;;;0521; +0521;CYRILLIC SMALL LETTER EL WITH MIDDLE HOOK;Ll;0;L;;;;;N;;;0520;;0520 +0522;CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK;Lu;0;L;;;;;N;;;;0523; +0523;CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK;Ll;0;L;;;;;N;;;0522;;0522 +0524;CYRILLIC CAPITAL LETTER PE WITH DESCENDER;Lu;0;L;;;;;N;;;;0525; +0525;CYRILLIC SMALL LETTER PE WITH DESCENDER;Ll;0;L;;;;;N;;;0524;;0524 +0526;CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER;Lu;0;L;;;;;N;;;;0527; +0527;CYRILLIC SMALL LETTER SHHA WITH DESCENDER;Ll;0;L;;;;;N;;;0526;;0526 +0528;CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK;Lu;0;L;;;;;N;;;;0529; +0529;CYRILLIC SMALL LETTER EN WITH LEFT HOOK;Ll;0;L;;;;;N;;;0528;;0528 +052A;CYRILLIC CAPITAL LETTER DZZHE;Lu;0;L;;;;;N;;;;052B; +052B;CYRILLIC SMALL LETTER DZZHE;Ll;0;L;;;;;N;;;052A;;052A +052C;CYRILLIC CAPITAL LETTER DCHE;Lu;0;L;;;;;N;;;;052D; +052D;CYRILLIC SMALL LETTER DCHE;Ll;0;L;;;;;N;;;052C;;052C +052E;CYRILLIC CAPITAL LETTER EL WITH DESCENDER;Lu;0;L;;;;;N;;;;052F; +052F;CYRILLIC SMALL LETTER EL WITH DESCENDER;Ll;0;L;;;;;N;;;052E;;052E +0531;ARMENIAN CAPITAL LETTER AYB;Lu;0;L;;;;;N;;;;0561; +0532;ARMENIAN CAPITAL LETTER BEN;Lu;0;L;;;;;N;;;;0562; +0533;ARMENIAN CAPITAL LETTER GIM;Lu;0;L;;;;;N;;;;0563; +0534;ARMENIAN CAPITAL LETTER DA;Lu;0;L;;;;;N;;;;0564; +0535;ARMENIAN CAPITAL LETTER ECH;Lu;0;L;;;;;N;;;;0565; +0536;ARMENIAN CAPITAL LETTER ZA;Lu;0;L;;;;;N;;;;0566; +0537;ARMENIAN CAPITAL LETTER EH;Lu;0;L;;;;;N;;;;0567; +0538;ARMENIAN CAPITAL LETTER ET;Lu;0;L;;;;;N;;;;0568; +0539;ARMENIAN CAPITAL LETTER TO;Lu;0;L;;;;;N;;;;0569; +053A;ARMENIAN CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;056A; +053B;ARMENIAN CAPITAL LETTER INI;Lu;0;L;;;;;N;;;;056B; +053C;ARMENIAN CAPITAL LETTER LIWN;Lu;0;L;;;;;N;;;;056C; +053D;ARMENIAN CAPITAL LETTER XEH;Lu;0;L;;;;;N;;;;056D; +053E;ARMENIAN CAPITAL LETTER CA;Lu;0;L;;;;;N;;;;056E; +053F;ARMENIAN CAPITAL LETTER KEN;Lu;0;L;;;;;N;;;;056F; +0540;ARMENIAN CAPITAL LETTER HO;Lu;0;L;;;;;N;;;;0570; +0541;ARMENIAN CAPITAL LETTER JA;Lu;0;L;;;;;N;;;;0571; +0542;ARMENIAN CAPITAL LETTER GHAD;Lu;0;L;;;;;N;ARMENIAN CAPITAL LETTER LAD;;;0572; +0543;ARMENIAN CAPITAL LETTER CHEH;Lu;0;L;;;;;N;;;;0573; +0544;ARMENIAN CAPITAL LETTER MEN;Lu;0;L;;;;;N;;;;0574; +0545;ARMENIAN CAPITAL LETTER YI;Lu;0;L;;;;;N;;;;0575; +0546;ARMENIAN CAPITAL LETTER NOW;Lu;0;L;;;;;N;;;;0576; +0547;ARMENIAN CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0577; +0548;ARMENIAN CAPITAL LETTER VO;Lu;0;L;;;;;N;;;;0578; +0549;ARMENIAN CAPITAL LETTER CHA;Lu;0;L;;;;;N;;;;0579; +054A;ARMENIAN CAPITAL LETTER PEH;Lu;0;L;;;;;N;;;;057A; +054B;ARMENIAN CAPITAL LETTER JHEH;Lu;0;L;;;;;N;;;;057B; +054C;ARMENIAN CAPITAL LETTER RA;Lu;0;L;;;;;N;;;;057C; +054D;ARMENIAN CAPITAL LETTER SEH;Lu;0;L;;;;;N;;;;057D; +054E;ARMENIAN CAPITAL LETTER VEW;Lu;0;L;;;;;N;;;;057E; +054F;ARMENIAN CAPITAL LETTER TIWN;Lu;0;L;;;;;N;;;;057F; +0550;ARMENIAN CAPITAL LETTER REH;Lu;0;L;;;;;N;;;;0580; +0551;ARMENIAN CAPITAL LETTER CO;Lu;0;L;;;;;N;;;;0581; +0552;ARMENIAN CAPITAL LETTER YIWN;Lu;0;L;;;;;N;;;;0582; +0553;ARMENIAN CAPITAL LETTER PIWR;Lu;0;L;;;;;N;;;;0583; +0554;ARMENIAN CAPITAL LETTER KEH;Lu;0;L;;;;;N;;;;0584; +0555;ARMENIAN CAPITAL LETTER OH;Lu;0;L;;;;;N;;;;0585; +0556;ARMENIAN CAPITAL LETTER FEH;Lu;0;L;;;;;N;;;;0586; +0559;ARMENIAN MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;; +055A;ARMENIAN APOSTROPHE;Po;0;L;;;;;N;ARMENIAN MODIFIER LETTER RIGHT HALF RING;;;; +055B;ARMENIAN EMPHASIS MARK;Po;0;L;;;;;N;;;;; +055C;ARMENIAN EXCLAMATION MARK;Po;0;L;;;;;N;;;;; +055D;ARMENIAN COMMA;Po;0;L;;;;;N;;;;; +055E;ARMENIAN QUESTION MARK;Po;0;L;;;;;N;;;;; +055F;ARMENIAN ABBREVIATION MARK;Po;0;L;;;;;N;;;;; +0560;ARMENIAN SMALL LETTER TURNED AYB;Ll;0;L;;;;;N;;;;; +0561;ARMENIAN SMALL LETTER AYB;Ll;0;L;;;;;N;;;0531;;0531 +0562;ARMENIAN SMALL LETTER BEN;Ll;0;L;;;;;N;;;0532;;0532 +0563;ARMENIAN SMALL LETTER GIM;Ll;0;L;;;;;N;;;0533;;0533 +0564;ARMENIAN SMALL LETTER DA;Ll;0;L;;;;;N;;;0534;;0534 +0565;ARMENIAN SMALL LETTER ECH;Ll;0;L;;;;;N;;;0535;;0535 +0566;ARMENIAN SMALL LETTER ZA;Ll;0;L;;;;;N;;;0536;;0536 +0567;ARMENIAN SMALL LETTER EH;Ll;0;L;;;;;N;;;0537;;0537 +0568;ARMENIAN SMALL LETTER ET;Ll;0;L;;;;;N;;;0538;;0538 +0569;ARMENIAN SMALL LETTER TO;Ll;0;L;;;;;N;;;0539;;0539 +056A;ARMENIAN SMALL LETTER ZHE;Ll;0;L;;;;;N;;;053A;;053A +056B;ARMENIAN SMALL LETTER INI;Ll;0;L;;;;;N;;;053B;;053B +056C;ARMENIAN SMALL LETTER LIWN;Ll;0;L;;;;;N;;;053C;;053C +056D;ARMENIAN SMALL LETTER XEH;Ll;0;L;;;;;N;;;053D;;053D +056E;ARMENIAN SMALL LETTER CA;Ll;0;L;;;;;N;;;053E;;053E +056F;ARMENIAN SMALL LETTER KEN;Ll;0;L;;;;;N;;;053F;;053F +0570;ARMENIAN SMALL LETTER HO;Ll;0;L;;;;;N;;;0540;;0540 +0571;ARMENIAN SMALL LETTER JA;Ll;0;L;;;;;N;;;0541;;0541 +0572;ARMENIAN SMALL LETTER GHAD;Ll;0;L;;;;;N;ARMENIAN SMALL LETTER LAD;;0542;;0542 +0573;ARMENIAN SMALL LETTER CHEH;Ll;0;L;;;;;N;;;0543;;0543 +0574;ARMENIAN SMALL LETTER MEN;Ll;0;L;;;;;N;;;0544;;0544 +0575;ARMENIAN SMALL LETTER YI;Ll;0;L;;;;;N;;;0545;;0545 +0576;ARMENIAN SMALL LETTER NOW;Ll;0;L;;;;;N;;;0546;;0546 +0577;ARMENIAN SMALL LETTER SHA;Ll;0;L;;;;;N;;;0547;;0547 +0578;ARMENIAN SMALL LETTER VO;Ll;0;L;;;;;N;;;0548;;0548 +0579;ARMENIAN SMALL LETTER CHA;Ll;0;L;;;;;N;;;0549;;0549 +057A;ARMENIAN SMALL LETTER PEH;Ll;0;L;;;;;N;;;054A;;054A +057B;ARMENIAN SMALL LETTER JHEH;Ll;0;L;;;;;N;;;054B;;054B +057C;ARMENIAN SMALL LETTER RA;Ll;0;L;;;;;N;;;054C;;054C +057D;ARMENIAN SMALL LETTER SEH;Ll;0;L;;;;;N;;;054D;;054D +057E;ARMENIAN SMALL LETTER VEW;Ll;0;L;;;;;N;;;054E;;054E +057F;ARMENIAN SMALL LETTER TIWN;Ll;0;L;;;;;N;;;054F;;054F +0580;ARMENIAN SMALL LETTER REH;Ll;0;L;;;;;N;;;0550;;0550 +0581;ARMENIAN SMALL LETTER CO;Ll;0;L;;;;;N;;;0551;;0551 +0582;ARMENIAN SMALL LETTER YIWN;Ll;0;L;;;;;N;;;0552;;0552 +0583;ARMENIAN SMALL LETTER PIWR;Ll;0;L;;;;;N;;;0553;;0553 +0584;ARMENIAN SMALL LETTER KEH;Ll;0;L;;;;;N;;;0554;;0554 +0585;ARMENIAN SMALL LETTER OH;Ll;0;L;;;;;N;;;0555;;0555 +0586;ARMENIAN SMALL LETTER FEH;Ll;0;L;;;;;N;;;0556;;0556 +0587;ARMENIAN SMALL LIGATURE ECH YIWN;Ll;0;L; 0565 0582;;;;N;;;;; +0588;ARMENIAN SMALL LETTER YI WITH STROKE;Ll;0;L;;;;;N;;;;; +0589;ARMENIAN FULL STOP;Po;0;L;;;;;N;ARMENIAN PERIOD;;;; +058A;ARMENIAN HYPHEN;Pd;0;ON;;;;;N;;;;; +058D;RIGHT-FACING ARMENIAN ETERNITY SIGN;So;0;ON;;;;;N;;;;; +058E;LEFT-FACING ARMENIAN ETERNITY SIGN;So;0;ON;;;;;N;;;;; +058F;ARMENIAN DRAM SIGN;Sc;0;ET;;;;;N;;;;; +0591;HEBREW ACCENT ETNAHTA;Mn;220;NSM;;;;;N;;;;; +0592;HEBREW ACCENT SEGOL;Mn;230;NSM;;;;;N;;;;; +0593;HEBREW ACCENT SHALSHELET;Mn;230;NSM;;;;;N;;;;; +0594;HEBREW ACCENT ZAQEF QATAN;Mn;230;NSM;;;;;N;;;;; +0595;HEBREW ACCENT ZAQEF GADOL;Mn;230;NSM;;;;;N;;;;; +0596;HEBREW ACCENT TIPEHA;Mn;220;NSM;;;;;N;;;;; +0597;HEBREW ACCENT REVIA;Mn;230;NSM;;;;;N;;;;; +0598;HEBREW ACCENT ZARQA;Mn;230;NSM;;;;;N;;;;; +0599;HEBREW ACCENT PASHTA;Mn;230;NSM;;;;;N;;;;; +059A;HEBREW ACCENT YETIV;Mn;222;NSM;;;;;N;;;;; +059B;HEBREW ACCENT TEVIR;Mn;220;NSM;;;;;N;;;;; +059C;HEBREW ACCENT GERESH;Mn;230;NSM;;;;;N;;;;; +059D;HEBREW ACCENT GERESH MUQDAM;Mn;230;NSM;;;;;N;;;;; +059E;HEBREW ACCENT GERSHAYIM;Mn;230;NSM;;;;;N;;;;; +059F;HEBREW ACCENT QARNEY PARA;Mn;230;NSM;;;;;N;;;;; +05A0;HEBREW ACCENT TELISHA GEDOLA;Mn;230;NSM;;;;;N;;;;; +05A1;HEBREW ACCENT PAZER;Mn;230;NSM;;;;;N;;;;; +05A2;HEBREW ACCENT ATNAH HAFUKH;Mn;220;NSM;;;;;N;;;;; +05A3;HEBREW ACCENT MUNAH;Mn;220;NSM;;;;;N;;;;; +05A4;HEBREW ACCENT MAHAPAKH;Mn;220;NSM;;;;;N;;;;; +05A5;HEBREW ACCENT MERKHA;Mn;220;NSM;;;;;N;;;;; +05A6;HEBREW ACCENT MERKHA KEFULA;Mn;220;NSM;;;;;N;;;;; +05A7;HEBREW ACCENT DARGA;Mn;220;NSM;;;;;N;;;;; +05A8;HEBREW ACCENT QADMA;Mn;230;NSM;;;;;N;;;;; +05A9;HEBREW ACCENT TELISHA QETANA;Mn;230;NSM;;;;;N;;;;; +05AA;HEBREW ACCENT YERAH BEN YOMO;Mn;220;NSM;;;;;N;;;;; +05AB;HEBREW ACCENT OLE;Mn;230;NSM;;;;;N;;;;; +05AC;HEBREW ACCENT ILUY;Mn;230;NSM;;;;;N;;;;; +05AD;HEBREW ACCENT DEHI;Mn;222;NSM;;;;;N;;;;; +05AE;HEBREW ACCENT ZINOR;Mn;228;NSM;;;;;N;;;;; +05AF;HEBREW MARK MASORA CIRCLE;Mn;230;NSM;;;;;N;;;;; +05B0;HEBREW POINT SHEVA;Mn;10;NSM;;;;;N;;;;; +05B1;HEBREW POINT HATAF SEGOL;Mn;11;NSM;;;;;N;;;;; +05B2;HEBREW POINT HATAF PATAH;Mn;12;NSM;;;;;N;;;;; +05B3;HEBREW POINT HATAF QAMATS;Mn;13;NSM;;;;;N;;;;; +05B4;HEBREW POINT HIRIQ;Mn;14;NSM;;;;;N;;;;; +05B5;HEBREW POINT TSERE;Mn;15;NSM;;;;;N;;;;; +05B6;HEBREW POINT SEGOL;Mn;16;NSM;;;;;N;;;;; +05B7;HEBREW POINT PATAH;Mn;17;NSM;;;;;N;;;;; +05B8;HEBREW POINT QAMATS;Mn;18;NSM;;;;;N;;;;; +05B9;HEBREW POINT HOLAM;Mn;19;NSM;;;;;N;;;;; +05BA;HEBREW POINT HOLAM HASER FOR VAV;Mn;19;NSM;;;;;N;;;;; +05BB;HEBREW POINT QUBUTS;Mn;20;NSM;;;;;N;;;;; +05BC;HEBREW POINT DAGESH OR MAPIQ;Mn;21;NSM;;;;;N;HEBREW POINT DAGESH;;;; +05BD;HEBREW POINT METEG;Mn;22;NSM;;;;;N;;;;; +05BE;HEBREW PUNCTUATION MAQAF;Pd;0;R;;;;;N;;;;; +05BF;HEBREW POINT RAFE;Mn;23;NSM;;;;;N;;;;; +05C0;HEBREW PUNCTUATION PASEQ;Po;0;R;;;;;N;HEBREW POINT PASEQ;;;; +05C1;HEBREW POINT SHIN DOT;Mn;24;NSM;;;;;N;;;;; +05C2;HEBREW POINT SIN DOT;Mn;25;NSM;;;;;N;;;;; +05C3;HEBREW PUNCTUATION SOF PASUQ;Po;0;R;;;;;N;;;;; +05C4;HEBREW MARK UPPER DOT;Mn;230;NSM;;;;;N;;;;; +05C5;HEBREW MARK LOWER DOT;Mn;220;NSM;;;;;N;;;;; +05C6;HEBREW PUNCTUATION NUN HAFUKHA;Po;0;R;;;;;N;;;;; +05C7;HEBREW POINT QAMATS QATAN;Mn;18;NSM;;;;;N;;;;; +05D0;HEBREW LETTER ALEF;Lo;0;R;;;;;N;;;;; +05D1;HEBREW LETTER BET;Lo;0;R;;;;;N;;;;; +05D2;HEBREW LETTER GIMEL;Lo;0;R;;;;;N;;;;; +05D3;HEBREW LETTER DALET;Lo;0;R;;;;;N;;;;; +05D4;HEBREW LETTER HE;Lo;0;R;;;;;N;;;;; +05D5;HEBREW LETTER VAV;Lo;0;R;;;;;N;;;;; +05D6;HEBREW LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +05D7;HEBREW LETTER HET;Lo;0;R;;;;;N;;;;; +05D8;HEBREW LETTER TET;Lo;0;R;;;;;N;;;;; +05D9;HEBREW LETTER YOD;Lo;0;R;;;;;N;;;;; +05DA;HEBREW LETTER FINAL KAF;Lo;0;R;;;;;N;;;;; +05DB;HEBREW LETTER KAF;Lo;0;R;;;;;N;;;;; +05DC;HEBREW LETTER LAMED;Lo;0;R;;;;;N;;;;; +05DD;HEBREW LETTER FINAL MEM;Lo;0;R;;;;;N;;;;; +05DE;HEBREW LETTER MEM;Lo;0;R;;;;;N;;;;; +05DF;HEBREW LETTER FINAL NUN;Lo;0;R;;;;;N;;;;; +05E0;HEBREW LETTER NUN;Lo;0;R;;;;;N;;;;; +05E1;HEBREW LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +05E2;HEBREW LETTER AYIN;Lo;0;R;;;;;N;;;;; +05E3;HEBREW LETTER FINAL PE;Lo;0;R;;;;;N;;;;; +05E4;HEBREW LETTER PE;Lo;0;R;;;;;N;;;;; +05E5;HEBREW LETTER FINAL TSADI;Lo;0;R;;;;;N;;;;; +05E6;HEBREW LETTER TSADI;Lo;0;R;;;;;N;;;;; +05E7;HEBREW LETTER QOF;Lo;0;R;;;;;N;;;;; +05E8;HEBREW LETTER RESH;Lo;0;R;;;;;N;;;;; +05E9;HEBREW LETTER SHIN;Lo;0;R;;;;;N;;;;; +05EA;HEBREW LETTER TAV;Lo;0;R;;;;;N;;;;; +05EF;HEBREW YOD TRIANGLE;Lo;0;R;;;;;N;;;;; +05F0;HEBREW LIGATURE YIDDISH DOUBLE VAV;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE VAV;;;; +05F1;HEBREW LIGATURE YIDDISH VAV YOD;Lo;0;R;;;;;N;HEBREW LETTER VAV YOD;;;; +05F2;HEBREW LIGATURE YIDDISH DOUBLE YOD;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE YOD;;;; +05F3;HEBREW PUNCTUATION GERESH;Po;0;R;;;;;N;;;;; +05F4;HEBREW PUNCTUATION GERSHAYIM;Po;0;R;;;;;N;;;;; +0600;ARABIC NUMBER SIGN;Cf;0;AN;;;;;N;;;;; +0601;ARABIC SIGN SANAH;Cf;0;AN;;;;;N;;;;; +0602;ARABIC FOOTNOTE MARKER;Cf;0;AN;;;;;N;;;;; +0603;ARABIC SIGN SAFHA;Cf;0;AN;;;;;N;;;;; +0604;ARABIC SIGN SAMVAT;Cf;0;AN;;;;;N;;;;; +0605;ARABIC NUMBER MARK ABOVE;Cf;0;AN;;;;;N;;;;; +0606;ARABIC-INDIC CUBE ROOT;Sm;0;ON;;;;;N;;;;; +0607;ARABIC-INDIC FOURTH ROOT;Sm;0;ON;;;;;N;;;;; +0608;ARABIC RAY;Sm;0;AL;;;;;N;;;;; +0609;ARABIC-INDIC PER MILLE SIGN;Po;0;ET;;;;;N;;;;; +060A;ARABIC-INDIC PER TEN THOUSAND SIGN;Po;0;ET;;;;;N;;;;; +060B;AFGHANI SIGN;Sc;0;AL;;;;;N;;;;; +060C;ARABIC COMMA;Po;0;CS;;;;;N;;;;; +060D;ARABIC DATE SEPARATOR;Po;0;AL;;;;;N;;;;; +060E;ARABIC POETIC VERSE SIGN;So;0;ON;;;;;N;;;;; +060F;ARABIC SIGN MISRA;So;0;ON;;;;;N;;;;; +0610;ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM;Mn;230;NSM;;;;;N;;;;; +0611;ARABIC SIGN ALAYHE ASSALLAM;Mn;230;NSM;;;;;N;;;;; +0612;ARABIC SIGN RAHMATULLAH ALAYHE;Mn;230;NSM;;;;;N;;;;; +0613;ARABIC SIGN RADI ALLAHOU ANHU;Mn;230;NSM;;;;;N;;;;; +0614;ARABIC SIGN TAKHALLUS;Mn;230;NSM;;;;;N;;;;; +0615;ARABIC SMALL HIGH TAH;Mn;230;NSM;;;;;N;;;;; +0616;ARABIC SMALL HIGH LIGATURE ALEF WITH LAM WITH YEH;Mn;230;NSM;;;;;N;;;;; +0617;ARABIC SMALL HIGH ZAIN;Mn;230;NSM;;;;;N;;;;; +0618;ARABIC SMALL FATHA;Mn;30;NSM;;;;;N;;;;; +0619;ARABIC SMALL DAMMA;Mn;31;NSM;;;;;N;;;;; +061A;ARABIC SMALL KASRA;Mn;32;NSM;;;;;N;;;;; +061B;ARABIC SEMICOLON;Po;0;AL;;;;;N;;;;; +061C;ARABIC LETTER MARK;Cf;0;AL;;;;;N;;;;; +061D;ARABIC END OF TEXT MARK;Po;0;AL;;;;;N;;;;; +061E;ARABIC TRIPLE DOT PUNCTUATION MARK;Po;0;AL;;;;;N;;;;; +061F;ARABIC QUESTION MARK;Po;0;AL;;;;;N;;;;; +0620;ARABIC LETTER KASHMIRI YEH;Lo;0;AL;;;;;N;;;;; +0621;ARABIC LETTER HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH;;;; +0622;ARABIC LETTER ALEF WITH MADDA ABOVE;Lo;0;AL;0627 0653;;;;N;ARABIC LETTER MADDAH ON ALEF;;;; +0623;ARABIC LETTER ALEF WITH HAMZA ABOVE;Lo;0;AL;0627 0654;;;;N;ARABIC LETTER HAMZAH ON ALEF;;;; +0624;ARABIC LETTER WAW WITH HAMZA ABOVE;Lo;0;AL;0648 0654;;;;N;ARABIC LETTER HAMZAH ON WAW;;;; +0625;ARABIC LETTER ALEF WITH HAMZA BELOW;Lo;0;AL;0627 0655;;;;N;ARABIC LETTER HAMZAH UNDER ALEF;;;; +0626;ARABIC LETTER YEH WITH HAMZA ABOVE;Lo;0;AL;064A 0654;;;;N;ARABIC LETTER HAMZAH ON YA;;;; +0627;ARABIC LETTER ALEF;Lo;0;AL;;;;;N;;;;; +0628;ARABIC LETTER BEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA;;;; +0629;ARABIC LETTER TEH MARBUTA;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH;;;; +062A;ARABIC LETTER TEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA;;;; +062B;ARABIC LETTER THEH;Lo;0;AL;;;;;N;ARABIC LETTER THAA;;;; +062C;ARABIC LETTER JEEM;Lo;0;AL;;;;;N;;;;; +062D;ARABIC LETTER HAH;Lo;0;AL;;;;;N;ARABIC LETTER HAA;;;; +062E;ARABIC LETTER KHAH;Lo;0;AL;;;;;N;ARABIC LETTER KHAA;;;; +062F;ARABIC LETTER DAL;Lo;0;AL;;;;;N;;;;; +0630;ARABIC LETTER THAL;Lo;0;AL;;;;;N;;;;; +0631;ARABIC LETTER REH;Lo;0;AL;;;;;N;ARABIC LETTER RA;;;; +0632;ARABIC LETTER ZAIN;Lo;0;AL;;;;;N;;;;; +0633;ARABIC LETTER SEEN;Lo;0;AL;;;;;N;;;;; +0634;ARABIC LETTER SHEEN;Lo;0;AL;;;;;N;;;;; +0635;ARABIC LETTER SAD;Lo;0;AL;;;;;N;;;;; +0636;ARABIC LETTER DAD;Lo;0;AL;;;;;N;;;;; +0637;ARABIC LETTER TAH;Lo;0;AL;;;;;N;;;;; +0638;ARABIC LETTER ZAH;Lo;0;AL;;;;;N;ARABIC LETTER DHAH;;;; +0639;ARABIC LETTER AIN;Lo;0;AL;;;;;N;;;;; +063A;ARABIC LETTER GHAIN;Lo;0;AL;;;;;N;;;;; +063B;ARABIC LETTER KEHEH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +063C;ARABIC LETTER KEHEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +063D;ARABIC LETTER FARSI YEH WITH INVERTED V;Lo;0;AL;;;;;N;;;;; +063E;ARABIC LETTER FARSI YEH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +063F;ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +0640;ARABIC TATWEEL;Lm;0;AL;;;;;N;;;;; +0641;ARABIC LETTER FEH;Lo;0;AL;;;;;N;ARABIC LETTER FA;;;; +0642;ARABIC LETTER QAF;Lo;0;AL;;;;;N;;;;; +0643;ARABIC LETTER KAF;Lo;0;AL;;;;;N;ARABIC LETTER CAF;;;; +0644;ARABIC LETTER LAM;Lo;0;AL;;;;;N;;;;; +0645;ARABIC LETTER MEEM;Lo;0;AL;;;;;N;;;;; +0646;ARABIC LETTER NOON;Lo;0;AL;;;;;N;;;;; +0647;ARABIC LETTER HEH;Lo;0;AL;;;;;N;ARABIC LETTER HA;;;; +0648;ARABIC LETTER WAW;Lo;0;AL;;;;;N;;;;; +0649;ARABIC LETTER ALEF MAKSURA;Lo;0;AL;;;;;N;ARABIC LETTER ALEF MAQSURAH;;;; +064A;ARABIC LETTER YEH;Lo;0;AL;;;;;N;ARABIC LETTER YA;;;; +064B;ARABIC FATHATAN;Mn;27;NSM;;;;;N;;;;; +064C;ARABIC DAMMATAN;Mn;28;NSM;;;;;N;;;;; +064D;ARABIC KASRATAN;Mn;29;NSM;;;;;N;;;;; +064E;ARABIC FATHA;Mn;30;NSM;;;;;N;ARABIC FATHAH;;;; +064F;ARABIC DAMMA;Mn;31;NSM;;;;;N;ARABIC DAMMAH;;;; +0650;ARABIC KASRA;Mn;32;NSM;;;;;N;ARABIC KASRAH;;;; +0651;ARABIC SHADDA;Mn;33;NSM;;;;;N;ARABIC SHADDAH;;;; +0652;ARABIC SUKUN;Mn;34;NSM;;;;;N;;;;; +0653;ARABIC MADDAH ABOVE;Mn;230;NSM;;;;;N;;;;; +0654;ARABIC HAMZA ABOVE;Mn;230;NSM;;;;;N;;;;; +0655;ARABIC HAMZA BELOW;Mn;220;NSM;;;;;N;;;;; +0656;ARABIC SUBSCRIPT ALEF;Mn;220;NSM;;;;;N;;;;; +0657;ARABIC INVERTED DAMMA;Mn;230;NSM;;;;;N;;;;; +0658;ARABIC MARK NOON GHUNNA;Mn;230;NSM;;;;;N;;;;; +0659;ARABIC ZWARAKAY;Mn;230;NSM;;;;;N;;;;; +065A;ARABIC VOWEL SIGN SMALL V ABOVE;Mn;230;NSM;;;;;N;;;;; +065B;ARABIC VOWEL SIGN INVERTED SMALL V ABOVE;Mn;230;NSM;;;;;N;;;;; +065C;ARABIC VOWEL SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;; +065D;ARABIC REVERSED DAMMA;Mn;230;NSM;;;;;N;;;;; +065E;ARABIC FATHA WITH TWO DOTS;Mn;230;NSM;;;;;N;;;;; +065F;ARABIC WAVY HAMZA BELOW;Mn;220;NSM;;;;;N;;;;; +0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;; +0661;ARABIC-INDIC DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;; +0662;ARABIC-INDIC DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;; +0663;ARABIC-INDIC DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;; +0664;ARABIC-INDIC DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;; +0665;ARABIC-INDIC DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;; +0666;ARABIC-INDIC DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;; +0667;ARABIC-INDIC DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;; +0668;ARABIC-INDIC DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;; +0669;ARABIC-INDIC DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;; +066A;ARABIC PERCENT SIGN;Po;0;ET;;;;;N;;;;; +066B;ARABIC DECIMAL SEPARATOR;Po;0;AN;;;;;N;;;;; +066C;ARABIC THOUSANDS SEPARATOR;Po;0;AN;;;;;N;;;;; +066D;ARABIC FIVE POINTED STAR;Po;0;AL;;;;;N;;;;; +066E;ARABIC LETTER DOTLESS BEH;Lo;0;AL;;;;;N;;;;; +066F;ARABIC LETTER DOTLESS QAF;Lo;0;AL;;;;;N;;;;; +0670;ARABIC LETTER SUPERSCRIPT ALEF;Mn;35;NSM;;;;;N;ARABIC ALEF ABOVE;;;; +0671;ARABIC LETTER ALEF WASLA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAT WASL ON ALEF;;;; +0672;ARABIC LETTER ALEF WITH WAVY HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH ON ALEF;;;; +0673;ARABIC LETTER ALEF WITH WAVY HAMZA BELOW;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH UNDER ALEF;;;; +0674;ARABIC LETTER HIGH HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HIGH HAMZAH;;;; +0675;ARABIC LETTER HIGH HAMZA ALEF;Lo;0;AL; 0627 0674;;;;N;ARABIC LETTER HIGH HAMZAH ALEF;;;; +0676;ARABIC LETTER HIGH HAMZA WAW;Lo;0;AL; 0648 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW;;;; +0677;ARABIC LETTER U WITH HAMZA ABOVE;Lo;0;AL; 06C7 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW WITH DAMMAH;;;; +0678;ARABIC LETTER HIGH HAMZA YEH;Lo;0;AL; 064A 0674;;;;N;ARABIC LETTER HIGH HAMZAH YA;;;; +0679;ARABIC LETTER TTEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH SMALL TAH;;;; +067A;ARABIC LETTER TTEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH TWO DOTS VERTICAL ABOVE;;;; +067B;ARABIC LETTER BEEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH TWO DOTS VERTICAL BELOW;;;; +067C;ARABIC LETTER TEH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH RING;;;; +067D;ARABIC LETTER TEH WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS ABOVE DOWNWARD;;;; +067E;ARABIC LETTER PEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS BELOW;;;; +067F;ARABIC LETTER TEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH FOUR DOTS ABOVE;;;; +0680;ARABIC LETTER BEHEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH FOUR DOTS BELOW;;;; +0681;ARABIC LETTER HAH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH ON HAA;;;; +0682;ARABIC LETTER HAH WITH TWO DOTS VERTICAL ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH TWO DOTS VERTICAL ABOVE;;;; +0683;ARABIC LETTER NYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS;;;; +0684;ARABIC LETTER DYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS VERTICAL;;;; +0685;ARABIC LETTER HAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH THREE DOTS ABOVE;;;; +0686;ARABIC LETTER TCHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE THREE DOTS DOWNWARD;;;; +0687;ARABIC LETTER TCHEHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE FOUR DOTS;;;; +0688;ARABIC LETTER DDAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH SMALL TAH;;;; +0689;ARABIC LETTER DAL WITH RING;Lo;0;AL;;;;;N;;;;; +068A;ARABIC LETTER DAL WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +068B;ARABIC LETTER DAL WITH DOT BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;; +068C;ARABIC LETTER DAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS ABOVE;;;; +068D;ARABIC LETTER DDAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS BELOW;;;; +068E;ARABIC LETTER DUL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE;;;; +068F;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARD;;;; +0690;ARABIC LETTER DAL WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +0691;ARABIC LETTER RREH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL TAH;;;; +0692;ARABIC LETTER REH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V;;;; +0693;ARABIC LETTER REH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH RING;;;; +0694;ARABIC LETTER REH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW;;;; +0695;ARABIC LETTER REH WITH SMALL V BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V BELOW;;;; +0696;ARABIC LETTER REH WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW AND DOT ABOVE;;;; +0697;ARABIC LETTER REH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH TWO DOTS ABOVE;;;; +0698;ARABIC LETTER JEH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH THREE DOTS ABOVE;;;; +0699;ARABIC LETTER REH WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH FOUR DOTS ABOVE;;;; +069A;ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; +069B;ARABIC LETTER SEEN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +069C;ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +069D;ARABIC LETTER SAD WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; +069E;ARABIC LETTER SAD WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +069F;ARABIC LETTER TAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06A0;ARABIC LETTER AIN WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06A1;ARABIC LETTER DOTLESS FEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS FA;;;; +06A2;ARABIC LETTER FEH WITH DOT MOVED BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT MOVED BELOW;;;; +06A3;ARABIC LETTER FEH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT BELOW;;;; +06A4;ARABIC LETTER VEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS ABOVE;;;; +06A5;ARABIC LETTER FEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS BELOW;;;; +06A6;ARABIC LETTER PEHEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH FOUR DOTS ABOVE;;;; +06A7;ARABIC LETTER QAF WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +06A8;ARABIC LETTER QAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06A9;ARABIC LETTER KEHEH;Lo;0;AL;;;;;N;ARABIC LETTER OPEN CAF;;;; +06AA;ARABIC LETTER SWASH KAF;Lo;0;AL;;;;;N;ARABIC LETTER SWASH CAF;;;; +06AB;ARABIC LETTER KAF WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH RING;;;; +06AC;ARABIC LETTER KAF WITH DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH DOT ABOVE;;;; +06AD;ARABIC LETTER NG;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS ABOVE;;;; +06AE;ARABIC LETTER KAF WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS BELOW;;;; +06AF;ARABIC LETTER GAF;Lo;0;AL;;;;;N;;;;; +06B0;ARABIC LETTER GAF WITH RING;Lo;0;AL;;;;;N;;;;; +06B1;ARABIC LETTER NGOEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS ABOVE;;;; +06B2;ARABIC LETTER GAF WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; +06B3;ARABIC LETTER GUEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS VERTICAL BELOW;;;; +06B4;ARABIC LETTER GAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06B5;ARABIC LETTER LAM WITH SMALL V;Lo;0;AL;;;;;N;;;;; +06B6;ARABIC LETTER LAM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +06B7;ARABIC LETTER LAM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06B8;ARABIC LETTER LAM WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +06B9;ARABIC LETTER NOON WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +06BA;ARABIC LETTER NOON GHUNNA;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON;;;; +06BB;ARABIC LETTER RNOON;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON WITH SMALL TAH;;;; +06BC;ARABIC LETTER NOON WITH RING;Lo;0;AL;;;;;N;;;;; +06BD;ARABIC LETTER NOON WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06BE;ARABIC LETTER HEH DOACHASHMEE;Lo;0;AL;;;;;N;ARABIC LETTER KNOTTED HA;;;; +06BF;ARABIC LETTER TCHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +06C0;ARABIC LETTER HEH WITH YEH ABOVE;Lo;0;AL;06D5 0654;;;;N;ARABIC LETTER HAMZAH ON HA;;;; +06C1;ARABIC LETTER HEH GOAL;Lo;0;AL;;;;;N;ARABIC LETTER HA GOAL;;;; +06C2;ARABIC LETTER HEH GOAL WITH HAMZA ABOVE;Lo;0;AL;06C1 0654;;;;N;ARABIC LETTER HAMZAH ON HA GOAL;;;; +06C3;ARABIC LETTER TEH MARBUTA GOAL;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH GOAL;;;; +06C4;ARABIC LETTER WAW WITH RING;Lo;0;AL;;;;;N;;;;; +06C5;ARABIC LETTER KIRGHIZ OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH BAR;;;; +06C6;ARABIC LETTER OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH SMALL V;;;; +06C7;ARABIC LETTER U;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH DAMMAH;;;; +06C8;ARABIC LETTER YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH ALEF ABOVE;;;; +06C9;ARABIC LETTER KIRGHIZ YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH INVERTED SMALL V;;;; +06CA;ARABIC LETTER WAW WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06CB;ARABIC LETTER VE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH THREE DOTS ABOVE;;;; +06CC;ARABIC LETTER FARSI YEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS YA;;;; +06CD;ARABIC LETTER YEH WITH TAIL;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TAIL;;;; +06CE;ARABIC LETTER YEH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH SMALL V;;;; +06CF;ARABIC LETTER WAW WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +06D0;ARABIC LETTER E;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TWO DOTS VERTICAL BELOW;;;; +06D1;ARABIC LETTER YEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH THREE DOTS BELOW;;;; +06D2;ARABIC LETTER YEH BARREE;Lo;0;AL;;;;;N;ARABIC LETTER YA BARREE;;;; +06D3;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE;Lo;0;AL;06D2 0654;;;;N;ARABIC LETTER HAMZAH ON YA BARREE;;;; +06D4;ARABIC FULL STOP;Po;0;AL;;;;;N;ARABIC PERIOD;;;; +06D5;ARABIC LETTER AE;Lo;0;AL;;;;;N;;;;; +06D6;ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;; +06D7;ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;; +06D8;ARABIC SMALL HIGH MEEM INITIAL FORM;Mn;230;NSM;;;;;N;;;;; +06D9;ARABIC SMALL HIGH LAM ALEF;Mn;230;NSM;;;;;N;;;;; +06DA;ARABIC SMALL HIGH JEEM;Mn;230;NSM;;;;;N;;;;; +06DB;ARABIC SMALL HIGH THREE DOTS;Mn;230;NSM;;;;;N;;;;; +06DC;ARABIC SMALL HIGH SEEN;Mn;230;NSM;;;;;N;;;;; +06DD;ARABIC END OF AYAH;Cf;0;AN;;;;;N;;;;; +06DE;ARABIC START OF RUB EL HIZB;So;0;ON;;;;;N;;;;; +06DF;ARABIC SMALL HIGH ROUNDED ZERO;Mn;230;NSM;;;;;N;;;;; +06E0;ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO;Mn;230;NSM;;;;;N;;;;; +06E1;ARABIC SMALL HIGH DOTLESS HEAD OF KHAH;Mn;230;NSM;;;;;N;;;;; +06E2;ARABIC SMALL HIGH MEEM ISOLATED FORM;Mn;230;NSM;;;;;N;;;;; +06E3;ARABIC SMALL LOW SEEN;Mn;220;NSM;;;;;N;;;;; +06E4;ARABIC SMALL HIGH MADDA;Mn;230;NSM;;;;;N;;;;; +06E5;ARABIC SMALL WAW;Lm;0;AL;;;;;N;;;;; +06E6;ARABIC SMALL YEH;Lm;0;AL;;;;;N;;;;; +06E7;ARABIC SMALL HIGH YEH;Mn;230;NSM;;;;;N;;;;; +06E8;ARABIC SMALL HIGH NOON;Mn;230;NSM;;;;;N;;;;; +06E9;ARABIC PLACE OF SAJDAH;So;0;ON;;;;;N;;;;; +06EA;ARABIC EMPTY CENTRE LOW STOP;Mn;220;NSM;;;;;N;;;;; +06EB;ARABIC EMPTY CENTRE HIGH STOP;Mn;230;NSM;;;;;N;;;;; +06EC;ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE;Mn;230;NSM;;;;;N;;;;; +06ED;ARABIC SMALL LOW MEEM;Mn;220;NSM;;;;;N;;;;; +06EE;ARABIC LETTER DAL WITH INVERTED V;Lo;0;AL;;;;;N;;;;; +06EF;ARABIC LETTER REH WITH INVERTED V;Lo;0;AL;;;;;N;;;;; +06F0;EXTENDED ARABIC-INDIC DIGIT ZERO;Nd;0;EN;;0;0;0;N;EASTERN ARABIC-INDIC DIGIT ZERO;;;; +06F1;EXTENDED ARABIC-INDIC DIGIT ONE;Nd;0;EN;;1;1;1;N;EASTERN ARABIC-INDIC DIGIT ONE;;;; +06F2;EXTENDED ARABIC-INDIC DIGIT TWO;Nd;0;EN;;2;2;2;N;EASTERN ARABIC-INDIC DIGIT TWO;;;; +06F3;EXTENDED ARABIC-INDIC DIGIT THREE;Nd;0;EN;;3;3;3;N;EASTERN ARABIC-INDIC DIGIT THREE;;;; +06F4;EXTENDED ARABIC-INDIC DIGIT FOUR;Nd;0;EN;;4;4;4;N;EASTERN ARABIC-INDIC DIGIT FOUR;;;; +06F5;EXTENDED ARABIC-INDIC DIGIT FIVE;Nd;0;EN;;5;5;5;N;EASTERN ARABIC-INDIC DIGIT FIVE;;;; +06F6;EXTENDED ARABIC-INDIC DIGIT SIX;Nd;0;EN;;6;6;6;N;EASTERN ARABIC-INDIC DIGIT SIX;;;; +06F7;EXTENDED ARABIC-INDIC DIGIT SEVEN;Nd;0;EN;;7;7;7;N;EASTERN ARABIC-INDIC DIGIT SEVEN;;;; +06F8;EXTENDED ARABIC-INDIC DIGIT EIGHT;Nd;0;EN;;8;8;8;N;EASTERN ARABIC-INDIC DIGIT EIGHT;;;; +06F9;EXTENDED ARABIC-INDIC DIGIT NINE;Nd;0;EN;;9;9;9;N;EASTERN ARABIC-INDIC DIGIT NINE;;;; +06FA;ARABIC LETTER SHEEN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +06FB;ARABIC LETTER DAD WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +06FC;ARABIC LETTER GHAIN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +06FD;ARABIC SIGN SINDHI AMPERSAND;So;0;AL;;;;;N;;;;; +06FE;ARABIC SIGN SINDHI POSTPOSITION MEN;So;0;AL;;;;;N;;;;; +06FF;ARABIC LETTER HEH WITH INVERTED V;Lo;0;AL;;;;;N;;;;; +0700;SYRIAC END OF PARAGRAPH;Po;0;AL;;;;;N;;;;; +0701;SYRIAC SUPRALINEAR FULL STOP;Po;0;AL;;;;;N;;;;; +0702;SYRIAC SUBLINEAR FULL STOP;Po;0;AL;;;;;N;;;;; +0703;SYRIAC SUPRALINEAR COLON;Po;0;AL;;;;;N;;;;; +0704;SYRIAC SUBLINEAR COLON;Po;0;AL;;;;;N;;;;; +0705;SYRIAC HORIZONTAL COLON;Po;0;AL;;;;;N;;;;; +0706;SYRIAC COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;; +0707;SYRIAC COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;; +0708;SYRIAC SUPRALINEAR COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;; +0709;SYRIAC SUBLINEAR COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;; +070A;SYRIAC CONTRACTION;Po;0;AL;;;;;N;;;;; +070B;SYRIAC HARKLEAN OBELUS;Po;0;AL;;;;;N;;;;; +070C;SYRIAC HARKLEAN METOBELUS;Po;0;AL;;;;;N;;;;; +070D;SYRIAC HARKLEAN ASTERISCUS;Po;0;AL;;;;;N;;;;; +070F;SYRIAC ABBREVIATION MARK;Cf;0;AL;;;;;N;;;;; +0710;SYRIAC LETTER ALAPH;Lo;0;AL;;;;;N;;;;; +0711;SYRIAC LETTER SUPERSCRIPT ALAPH;Mn;36;NSM;;;;;N;;;;; +0712;SYRIAC LETTER BETH;Lo;0;AL;;;;;N;;;;; +0713;SYRIAC LETTER GAMAL;Lo;0;AL;;;;;N;;;;; +0714;SYRIAC LETTER GAMAL GARSHUNI;Lo;0;AL;;;;;N;;;;; +0715;SYRIAC LETTER DALATH;Lo;0;AL;;;;;N;;;;; +0716;SYRIAC LETTER DOTLESS DALATH RISH;Lo;0;AL;;;;;N;;;;; +0717;SYRIAC LETTER HE;Lo;0;AL;;;;;N;;;;; +0718;SYRIAC LETTER WAW;Lo;0;AL;;;;;N;;;;; +0719;SYRIAC LETTER ZAIN;Lo;0;AL;;;;;N;;;;; +071A;SYRIAC LETTER HETH;Lo;0;AL;;;;;N;;;;; +071B;SYRIAC LETTER TETH;Lo;0;AL;;;;;N;;;;; +071C;SYRIAC LETTER TETH GARSHUNI;Lo;0;AL;;;;;N;;;;; +071D;SYRIAC LETTER YUDH;Lo;0;AL;;;;;N;;;;; +071E;SYRIAC LETTER YUDH HE;Lo;0;AL;;;;;N;;;;; +071F;SYRIAC LETTER KAPH;Lo;0;AL;;;;;N;;;;; +0720;SYRIAC LETTER LAMADH;Lo;0;AL;;;;;N;;;;; +0721;SYRIAC LETTER MIM;Lo;0;AL;;;;;N;;;;; +0722;SYRIAC LETTER NUN;Lo;0;AL;;;;;N;;;;; +0723;SYRIAC LETTER SEMKATH;Lo;0;AL;;;;;N;;;;; +0724;SYRIAC LETTER FINAL SEMKATH;Lo;0;AL;;;;;N;;;;; +0725;SYRIAC LETTER E;Lo;0;AL;;;;;N;;;;; +0726;SYRIAC LETTER PE;Lo;0;AL;;;;;N;;;;; +0727;SYRIAC LETTER REVERSED PE;Lo;0;AL;;;;;N;;;;; +0728;SYRIAC LETTER SADHE;Lo;0;AL;;;;;N;;;;; +0729;SYRIAC LETTER QAPH;Lo;0;AL;;;;;N;;;;; +072A;SYRIAC LETTER RISH;Lo;0;AL;;;;;N;;;;; +072B;SYRIAC LETTER SHIN;Lo;0;AL;;;;;N;;;;; +072C;SYRIAC LETTER TAW;Lo;0;AL;;;;;N;;;;; +072D;SYRIAC LETTER PERSIAN BHETH;Lo;0;AL;;;;;N;;;;; +072E;SYRIAC LETTER PERSIAN GHAMAL;Lo;0;AL;;;;;N;;;;; +072F;SYRIAC LETTER PERSIAN DHALATH;Lo;0;AL;;;;;N;;;;; +0730;SYRIAC PTHAHA ABOVE;Mn;230;NSM;;;;;N;;;;; +0731;SYRIAC PTHAHA BELOW;Mn;220;NSM;;;;;N;;;;; +0732;SYRIAC PTHAHA DOTTED;Mn;230;NSM;;;;;N;;;;; +0733;SYRIAC ZQAPHA ABOVE;Mn;230;NSM;;;;;N;;;;; +0734;SYRIAC ZQAPHA BELOW;Mn;220;NSM;;;;;N;;;;; +0735;SYRIAC ZQAPHA DOTTED;Mn;230;NSM;;;;;N;;;;; +0736;SYRIAC RBASA ABOVE;Mn;230;NSM;;;;;N;;;;; +0737;SYRIAC RBASA BELOW;Mn;220;NSM;;;;;N;;;;; +0738;SYRIAC DOTTED ZLAMA HORIZONTAL;Mn;220;NSM;;;;;N;;;;; +0739;SYRIAC DOTTED ZLAMA ANGULAR;Mn;220;NSM;;;;;N;;;;; +073A;SYRIAC HBASA ABOVE;Mn;230;NSM;;;;;N;;;;; +073B;SYRIAC HBASA BELOW;Mn;220;NSM;;;;;N;;;;; +073C;SYRIAC HBASA-ESASA DOTTED;Mn;220;NSM;;;;;N;;;;; +073D;SYRIAC ESASA ABOVE;Mn;230;NSM;;;;;N;;;;; +073E;SYRIAC ESASA BELOW;Mn;220;NSM;;;;;N;;;;; +073F;SYRIAC RWAHA;Mn;230;NSM;;;;;N;;;;; +0740;SYRIAC FEMININE DOT;Mn;230;NSM;;;;;N;;;;; +0741;SYRIAC QUSHSHAYA;Mn;230;NSM;;;;;N;;;;; +0742;SYRIAC RUKKAKHA;Mn;220;NSM;;;;;N;;;;; +0743;SYRIAC TWO VERTICAL DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; +0744;SYRIAC TWO VERTICAL DOTS BELOW;Mn;220;NSM;;;;;N;;;;; +0745;SYRIAC THREE DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; +0746;SYRIAC THREE DOTS BELOW;Mn;220;NSM;;;;;N;;;;; +0747;SYRIAC OBLIQUE LINE ABOVE;Mn;230;NSM;;;;;N;;;;; +0748;SYRIAC OBLIQUE LINE BELOW;Mn;220;NSM;;;;;N;;;;; +0749;SYRIAC MUSIC;Mn;230;NSM;;;;;N;;;;; +074A;SYRIAC BARREKH;Mn;230;NSM;;;;;N;;;;; +074D;SYRIAC LETTER SOGDIAN ZHAIN;Lo;0;AL;;;;;N;;;;; +074E;SYRIAC LETTER SOGDIAN KHAPH;Lo;0;AL;;;;;N;;;;; +074F;SYRIAC LETTER SOGDIAN FE;Lo;0;AL;;;;;N;;;;; +0750;ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW;Lo;0;AL;;;;;N;;;;; +0751;ARABIC LETTER BEH WITH DOT BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +0752;ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;; +0753;ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW AND TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +0754;ARABIC LETTER BEH WITH TWO DOTS BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; +0755;ARABIC LETTER BEH WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;; +0756;ARABIC LETTER BEH WITH SMALL V;Lo;0;AL;;;;;N;;;;; +0757;ARABIC LETTER HAH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +0758;ARABIC LETTER HAH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;; +0759;ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;; +075A;ARABIC LETTER DAL WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;; +075B;ARABIC LETTER REH WITH STROKE;Lo;0;AL;;;;;N;;;;; +075C;ARABIC LETTER SEEN WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +075D;ARABIC LETTER AIN WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +075E;ARABIC LETTER AIN WITH THREE DOTS POINTING DOWNWARDS ABOVE;Lo;0;AL;;;;;N;;;;; +075F;ARABIC LETTER AIN WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;; +0760;ARABIC LETTER FEH WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; +0761;ARABIC LETTER FEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;; +0762;ARABIC LETTER KEHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +0763;ARABIC LETTER KEHEH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +0764;ARABIC LETTER KEHEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;; +0765;ARABIC LETTER MEEM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +0766;ARABIC LETTER MEEM WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +0767;ARABIC LETTER NOON WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; +0768;ARABIC LETTER NOON WITH SMALL TAH;Lo;0;AL;;;;;N;;;;; +0769;ARABIC LETTER NOON WITH SMALL V;Lo;0;AL;;;;;N;;;;; +076A;ARABIC LETTER LAM WITH BAR;Lo;0;AL;;;;;N;;;;; +076B;ARABIC LETTER REH WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;; +076C;ARABIC LETTER REH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;;;;; +076D;ARABIC LETTER SEEN WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;; +076E;ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH BELOW;Lo;0;AL;;;;;N;;;;; +076F;ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH AND TWO DOTS;Lo;0;AL;;;;;N;;;;; +0770;ARABIC LETTER SEEN WITH SMALL ARABIC LETTER TAH AND TWO DOTS;Lo;0;AL;;;;;N;;;;; +0771;ARABIC LETTER REH WITH SMALL ARABIC LETTER TAH AND TWO DOTS;Lo;0;AL;;;;;N;;;;; +0772;ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH ABOVE;Lo;0;AL;;;;;N;;;;; +0773;ARABIC LETTER ALEF WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;; +0774;ARABIC LETTER ALEF WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;; +0775;ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;; +0776;ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;; +0777;ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT FOUR BELOW;Lo;0;AL;;;;;N;;;;; +0778;ARABIC LETTER WAW WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;; +0779;ARABIC LETTER WAW WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;; +077A;ARABIC LETTER YEH BARREE WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;; +077B;ARABIC LETTER YEH BARREE WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;; +077C;ARABIC LETTER HAH WITH EXTENDED ARABIC-INDIC DIGIT FOUR BELOW;Lo;0;AL;;;;;N;;;;; +077D;ARABIC LETTER SEEN WITH EXTENDED ARABIC-INDIC DIGIT FOUR ABOVE;Lo;0;AL;;;;;N;;;;; +077E;ARABIC LETTER SEEN WITH INVERTED V;Lo;0;AL;;;;;N;;;;; +077F;ARABIC LETTER KAF WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +0780;THAANA LETTER HAA;Lo;0;AL;;;;;N;;;;; +0781;THAANA LETTER SHAVIYANI;Lo;0;AL;;;;;N;;;;; +0782;THAANA LETTER NOONU;Lo;0;AL;;;;;N;;;;; +0783;THAANA LETTER RAA;Lo;0;AL;;;;;N;;;;; +0784;THAANA LETTER BAA;Lo;0;AL;;;;;N;;;;; +0785;THAANA LETTER LHAVIYANI;Lo;0;AL;;;;;N;;;;; +0786;THAANA LETTER KAAFU;Lo;0;AL;;;;;N;;;;; +0787;THAANA LETTER ALIFU;Lo;0;AL;;;;;N;;;;; +0788;THAANA LETTER VAAVU;Lo;0;AL;;;;;N;;;;; +0789;THAANA LETTER MEEMU;Lo;0;AL;;;;;N;;;;; +078A;THAANA LETTER FAAFU;Lo;0;AL;;;;;N;;;;; +078B;THAANA LETTER DHAALU;Lo;0;AL;;;;;N;;;;; +078C;THAANA LETTER THAA;Lo;0;AL;;;;;N;;;;; +078D;THAANA LETTER LAAMU;Lo;0;AL;;;;;N;;;;; +078E;THAANA LETTER GAAFU;Lo;0;AL;;;;;N;;;;; +078F;THAANA LETTER GNAVIYANI;Lo;0;AL;;;;;N;;;;; +0790;THAANA LETTER SEENU;Lo;0;AL;;;;;N;;;;; +0791;THAANA LETTER DAVIYANI;Lo;0;AL;;;;;N;;;;; +0792;THAANA LETTER ZAVIYANI;Lo;0;AL;;;;;N;;;;; +0793;THAANA LETTER TAVIYANI;Lo;0;AL;;;;;N;;;;; +0794;THAANA LETTER YAA;Lo;0;AL;;;;;N;;;;; +0795;THAANA LETTER PAVIYANI;Lo;0;AL;;;;;N;;;;; +0796;THAANA LETTER JAVIYANI;Lo;0;AL;;;;;N;;;;; +0797;THAANA LETTER CHAVIYANI;Lo;0;AL;;;;;N;;;;; +0798;THAANA LETTER TTAA;Lo;0;AL;;;;;N;;;;; +0799;THAANA LETTER HHAA;Lo;0;AL;;;;;N;;;;; +079A;THAANA LETTER KHAA;Lo;0;AL;;;;;N;;;;; +079B;THAANA LETTER THAALU;Lo;0;AL;;;;;N;;;;; +079C;THAANA LETTER ZAA;Lo;0;AL;;;;;N;;;;; +079D;THAANA LETTER SHEENU;Lo;0;AL;;;;;N;;;;; +079E;THAANA LETTER SAADHU;Lo;0;AL;;;;;N;;;;; +079F;THAANA LETTER DAADHU;Lo;0;AL;;;;;N;;;;; +07A0;THAANA LETTER TO;Lo;0;AL;;;;;N;;;;; +07A1;THAANA LETTER ZO;Lo;0;AL;;;;;N;;;;; +07A2;THAANA LETTER AINU;Lo;0;AL;;;;;N;;;;; +07A3;THAANA LETTER GHAINU;Lo;0;AL;;;;;N;;;;; +07A4;THAANA LETTER QAAFU;Lo;0;AL;;;;;N;;;;; +07A5;THAANA LETTER WAAVU;Lo;0;AL;;;;;N;;;;; +07A6;THAANA ABAFILI;Mn;0;NSM;;;;;N;;;;; +07A7;THAANA AABAAFILI;Mn;0;NSM;;;;;N;;;;; +07A8;THAANA IBIFILI;Mn;0;NSM;;;;;N;;;;; +07A9;THAANA EEBEEFILI;Mn;0;NSM;;;;;N;;;;; +07AA;THAANA UBUFILI;Mn;0;NSM;;;;;N;;;;; +07AB;THAANA OOBOOFILI;Mn;0;NSM;;;;;N;;;;; +07AC;THAANA EBEFILI;Mn;0;NSM;;;;;N;;;;; +07AD;THAANA EYBEYFILI;Mn;0;NSM;;;;;N;;;;; +07AE;THAANA OBOFILI;Mn;0;NSM;;;;;N;;;;; +07AF;THAANA OABOAFILI;Mn;0;NSM;;;;;N;;;;; +07B0;THAANA SUKUN;Mn;0;NSM;;;;;N;;;;; +07B1;THAANA LETTER NAA;Lo;0;AL;;;;;N;;;;; +07C0;NKO DIGIT ZERO;Nd;0;R;;0;0;0;N;;;;; +07C1;NKO DIGIT ONE;Nd;0;R;;1;1;1;N;;;;; +07C2;NKO DIGIT TWO;Nd;0;R;;2;2;2;N;;;;; +07C3;NKO DIGIT THREE;Nd;0;R;;3;3;3;N;;;;; +07C4;NKO DIGIT FOUR;Nd;0;R;;4;4;4;N;;;;; +07C5;NKO DIGIT FIVE;Nd;0;R;;5;5;5;N;;;;; +07C6;NKO DIGIT SIX;Nd;0;R;;6;6;6;N;;;;; +07C7;NKO DIGIT SEVEN;Nd;0;R;;7;7;7;N;;;;; +07C8;NKO DIGIT EIGHT;Nd;0;R;;8;8;8;N;;;;; +07C9;NKO DIGIT NINE;Nd;0;R;;9;9;9;N;;;;; +07CA;NKO LETTER A;Lo;0;R;;;;;N;;;;; +07CB;NKO LETTER EE;Lo;0;R;;;;;N;;;;; +07CC;NKO LETTER I;Lo;0;R;;;;;N;;;;; +07CD;NKO LETTER E;Lo;0;R;;;;;N;;;;; +07CE;NKO LETTER U;Lo;0;R;;;;;N;;;;; +07CF;NKO LETTER OO;Lo;0;R;;;;;N;;;;; +07D0;NKO LETTER O;Lo;0;R;;;;;N;;;;; +07D1;NKO LETTER DAGBASINNA;Lo;0;R;;;;;N;;;;; +07D2;NKO LETTER N;Lo;0;R;;;;;N;;;;; +07D3;NKO LETTER BA;Lo;0;R;;;;;N;;;;; +07D4;NKO LETTER PA;Lo;0;R;;;;;N;;;;; +07D5;NKO LETTER TA;Lo;0;R;;;;;N;;;;; +07D6;NKO LETTER JA;Lo;0;R;;;;;N;;;;; +07D7;NKO LETTER CHA;Lo;0;R;;;;;N;;;;; +07D8;NKO LETTER DA;Lo;0;R;;;;;N;;;;; +07D9;NKO LETTER RA;Lo;0;R;;;;;N;;;;; +07DA;NKO LETTER RRA;Lo;0;R;;;;;N;;;;; +07DB;NKO LETTER SA;Lo;0;R;;;;;N;;;;; +07DC;NKO LETTER GBA;Lo;0;R;;;;;N;;;;; +07DD;NKO LETTER FA;Lo;0;R;;;;;N;;;;; +07DE;NKO LETTER KA;Lo;0;R;;;;;N;;;;; +07DF;NKO LETTER LA;Lo;0;R;;;;;N;;;;; +07E0;NKO LETTER NA WOLOSO;Lo;0;R;;;;;N;;;;; +07E1;NKO LETTER MA;Lo;0;R;;;;;N;;;;; +07E2;NKO LETTER NYA;Lo;0;R;;;;;N;;;;; +07E3;NKO LETTER NA;Lo;0;R;;;;;N;;;;; +07E4;NKO LETTER HA;Lo;0;R;;;;;N;;;;; +07E5;NKO LETTER WA;Lo;0;R;;;;;N;;;;; +07E6;NKO LETTER YA;Lo;0;R;;;;;N;;;;; +07E7;NKO LETTER NYA WOLOSO;Lo;0;R;;;;;N;;;;; +07E8;NKO LETTER JONA JA;Lo;0;R;;;;;N;;;;; +07E9;NKO LETTER JONA CHA;Lo;0;R;;;;;N;;;;; +07EA;NKO LETTER JONA RA;Lo;0;R;;;;;N;;;;; +07EB;NKO COMBINING SHORT HIGH TONE;Mn;230;NSM;;;;;N;;;;; +07EC;NKO COMBINING SHORT LOW TONE;Mn;230;NSM;;;;;N;;;;; +07ED;NKO COMBINING SHORT RISING TONE;Mn;230;NSM;;;;;N;;;;; +07EE;NKO COMBINING LONG DESCENDING TONE;Mn;230;NSM;;;;;N;;;;; +07EF;NKO COMBINING LONG HIGH TONE;Mn;230;NSM;;;;;N;;;;; +07F0;NKO COMBINING LONG LOW TONE;Mn;230;NSM;;;;;N;;;;; +07F1;NKO COMBINING LONG RISING TONE;Mn;230;NSM;;;;;N;;;;; +07F2;NKO COMBINING NASALIZATION MARK;Mn;220;NSM;;;;;N;;;;; +07F3;NKO COMBINING DOUBLE DOT ABOVE;Mn;230;NSM;;;;;N;;;;; +07F4;NKO HIGH TONE APOSTROPHE;Lm;0;R;;;;;N;;;;; +07F5;NKO LOW TONE APOSTROPHE;Lm;0;R;;;;;N;;;;; +07F6;NKO SYMBOL OO DENNEN;So;0;ON;;;;;N;;;;; +07F7;NKO SYMBOL GBAKURUNEN;Po;0;ON;;;;;N;;;;; +07F8;NKO COMMA;Po;0;ON;;;;;N;;;;; +07F9;NKO EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; +07FA;NKO LAJANYALAN;Lm;0;R;;;;;N;;;;; +07FD;NKO DANTAYALAN;Mn;220;NSM;;;;;N;;;;; +07FE;NKO DOROME SIGN;Sc;0;R;;;;;N;;;;; +07FF;NKO TAMAN SIGN;Sc;0;R;;;;;N;;;;; +0800;SAMARITAN LETTER ALAF;Lo;0;R;;;;;N;;;;; +0801;SAMARITAN LETTER BIT;Lo;0;R;;;;;N;;;;; +0802;SAMARITAN LETTER GAMAN;Lo;0;R;;;;;N;;;;; +0803;SAMARITAN LETTER DALAT;Lo;0;R;;;;;N;;;;; +0804;SAMARITAN LETTER IY;Lo;0;R;;;;;N;;;;; +0805;SAMARITAN LETTER BAA;Lo;0;R;;;;;N;;;;; +0806;SAMARITAN LETTER ZEN;Lo;0;R;;;;;N;;;;; +0807;SAMARITAN LETTER IT;Lo;0;R;;;;;N;;;;; +0808;SAMARITAN LETTER TIT;Lo;0;R;;;;;N;;;;; +0809;SAMARITAN LETTER YUT;Lo;0;R;;;;;N;;;;; +080A;SAMARITAN LETTER KAAF;Lo;0;R;;;;;N;;;;; +080B;SAMARITAN LETTER LABAT;Lo;0;R;;;;;N;;;;; +080C;SAMARITAN LETTER MIM;Lo;0;R;;;;;N;;;;; +080D;SAMARITAN LETTER NUN;Lo;0;R;;;;;N;;;;; +080E;SAMARITAN LETTER SINGAAT;Lo;0;R;;;;;N;;;;; +080F;SAMARITAN LETTER IN;Lo;0;R;;;;;N;;;;; +0810;SAMARITAN LETTER FI;Lo;0;R;;;;;N;;;;; +0811;SAMARITAN LETTER TSAADIY;Lo;0;R;;;;;N;;;;; +0812;SAMARITAN LETTER QUF;Lo;0;R;;;;;N;;;;; +0813;SAMARITAN LETTER RISH;Lo;0;R;;;;;N;;;;; +0814;SAMARITAN LETTER SHAN;Lo;0;R;;;;;N;;;;; +0815;SAMARITAN LETTER TAAF;Lo;0;R;;;;;N;;;;; +0816;SAMARITAN MARK IN;Mn;230;NSM;;;;;N;;;;; +0817;SAMARITAN MARK IN-ALAF;Mn;230;NSM;;;;;N;;;;; +0818;SAMARITAN MARK OCCLUSION;Mn;230;NSM;;;;;N;;;;; +0819;SAMARITAN MARK DAGESH;Mn;230;NSM;;;;;N;;;;; +081A;SAMARITAN MODIFIER LETTER EPENTHETIC YUT;Lm;0;R;;;;;N;;;;; +081B;SAMARITAN MARK EPENTHETIC YUT;Mn;230;NSM;;;;;N;;;;; +081C;SAMARITAN VOWEL SIGN LONG E;Mn;230;NSM;;;;;N;;;;; +081D;SAMARITAN VOWEL SIGN E;Mn;230;NSM;;;;;N;;;;; +081E;SAMARITAN VOWEL SIGN OVERLONG AA;Mn;230;NSM;;;;;N;;;;; +081F;SAMARITAN VOWEL SIGN LONG AA;Mn;230;NSM;;;;;N;;;;; +0820;SAMARITAN VOWEL SIGN AA;Mn;230;NSM;;;;;N;;;;; +0821;SAMARITAN VOWEL SIGN OVERLONG A;Mn;230;NSM;;;;;N;;;;; +0822;SAMARITAN VOWEL SIGN LONG A;Mn;230;NSM;;;;;N;;;;; +0823;SAMARITAN VOWEL SIGN A;Mn;230;NSM;;;;;N;;;;; +0824;SAMARITAN MODIFIER LETTER SHORT A;Lm;0;R;;;;;N;;;;; +0825;SAMARITAN VOWEL SIGN SHORT A;Mn;230;NSM;;;;;N;;;;; +0826;SAMARITAN VOWEL SIGN LONG U;Mn;230;NSM;;;;;N;;;;; +0827;SAMARITAN VOWEL SIGN U;Mn;230;NSM;;;;;N;;;;; +0828;SAMARITAN MODIFIER LETTER I;Lm;0;R;;;;;N;;;;; +0829;SAMARITAN VOWEL SIGN LONG I;Mn;230;NSM;;;;;N;;;;; +082A;SAMARITAN VOWEL SIGN I;Mn;230;NSM;;;;;N;;;;; +082B;SAMARITAN VOWEL SIGN O;Mn;230;NSM;;;;;N;;;;; +082C;SAMARITAN VOWEL SIGN SUKUN;Mn;230;NSM;;;;;N;;;;; +082D;SAMARITAN MARK NEQUDAA;Mn;230;NSM;;;;;N;;;;; +0830;SAMARITAN PUNCTUATION NEQUDAA;Po;0;R;;;;;N;;;;; +0831;SAMARITAN PUNCTUATION AFSAAQ;Po;0;R;;;;;N;;;;; +0832;SAMARITAN PUNCTUATION ANGED;Po;0;R;;;;;N;;;;; +0833;SAMARITAN PUNCTUATION BAU;Po;0;R;;;;;N;;;;; +0834;SAMARITAN PUNCTUATION ATMAAU;Po;0;R;;;;;N;;;;; +0835;SAMARITAN PUNCTUATION SHIYYAALAA;Po;0;R;;;;;N;;;;; +0836;SAMARITAN ABBREVIATION MARK;Po;0;R;;;;;N;;;;; +0837;SAMARITAN PUNCTUATION MELODIC QITSA;Po;0;R;;;;;N;;;;; +0838;SAMARITAN PUNCTUATION ZIQAA;Po;0;R;;;;;N;;;;; +0839;SAMARITAN PUNCTUATION QITSA;Po;0;R;;;;;N;;;;; +083A;SAMARITAN PUNCTUATION ZAEF;Po;0;R;;;;;N;;;;; +083B;SAMARITAN PUNCTUATION TURU;Po;0;R;;;;;N;;;;; +083C;SAMARITAN PUNCTUATION ARKAANU;Po;0;R;;;;;N;;;;; +083D;SAMARITAN PUNCTUATION SOF MASHFAAT;Po;0;R;;;;;N;;;;; +083E;SAMARITAN PUNCTUATION ANNAAU;Po;0;R;;;;;N;;;;; +0840;MANDAIC LETTER HALQA;Lo;0;R;;;;;N;;;;; +0841;MANDAIC LETTER AB;Lo;0;R;;;;;N;;;;; +0842;MANDAIC LETTER AG;Lo;0;R;;;;;N;;;;; +0843;MANDAIC LETTER AD;Lo;0;R;;;;;N;;;;; +0844;MANDAIC LETTER AH;Lo;0;R;;;;;N;;;;; +0845;MANDAIC LETTER USHENNA;Lo;0;R;;;;;N;;;;; +0846;MANDAIC LETTER AZ;Lo;0;R;;;;;N;;;;; +0847;MANDAIC LETTER IT;Lo;0;R;;;;;N;;;;; +0848;MANDAIC LETTER ATT;Lo;0;R;;;;;N;;;;; +0849;MANDAIC LETTER AKSA;Lo;0;R;;;;;N;;;;; +084A;MANDAIC LETTER AK;Lo;0;R;;;;;N;;;;; +084B;MANDAIC LETTER AL;Lo;0;R;;;;;N;;;;; +084C;MANDAIC LETTER AM;Lo;0;R;;;;;N;;;;; +084D;MANDAIC LETTER AN;Lo;0;R;;;;;N;;;;; +084E;MANDAIC LETTER AS;Lo;0;R;;;;;N;;;;; +084F;MANDAIC LETTER IN;Lo;0;R;;;;;N;;;;; +0850;MANDAIC LETTER AP;Lo;0;R;;;;;N;;;;; +0851;MANDAIC LETTER ASZ;Lo;0;R;;;;;N;;;;; +0852;MANDAIC LETTER AQ;Lo;0;R;;;;;N;;;;; +0853;MANDAIC LETTER AR;Lo;0;R;;;;;N;;;;; +0854;MANDAIC LETTER ASH;Lo;0;R;;;;;N;;;;; +0855;MANDAIC LETTER AT;Lo;0;R;;;;;N;;;;; +0856;MANDAIC LETTER DUSHENNA;Lo;0;R;;;;;N;;;;; +0857;MANDAIC LETTER KAD;Lo;0;R;;;;;N;;;;; +0858;MANDAIC LETTER AIN;Lo;0;R;;;;;N;;;;; +0859;MANDAIC AFFRICATION MARK;Mn;220;NSM;;;;;N;;;;; +085A;MANDAIC VOCALIZATION MARK;Mn;220;NSM;;;;;N;;;;; +085B;MANDAIC GEMINATION MARK;Mn;220;NSM;;;;;N;;;;; +085E;MANDAIC PUNCTUATION;Po;0;R;;;;;N;;;;; +0860;SYRIAC LETTER MALAYALAM NGA;Lo;0;AL;;;;;N;;;;; +0861;SYRIAC LETTER MALAYALAM JA;Lo;0;AL;;;;;N;;;;; +0862;SYRIAC LETTER MALAYALAM NYA;Lo;0;AL;;;;;N;;;;; +0863;SYRIAC LETTER MALAYALAM TTA;Lo;0;AL;;;;;N;;;;; +0864;SYRIAC LETTER MALAYALAM NNA;Lo;0;AL;;;;;N;;;;; +0865;SYRIAC LETTER MALAYALAM NNNA;Lo;0;AL;;;;;N;;;;; +0866;SYRIAC LETTER MALAYALAM BHA;Lo;0;AL;;;;;N;;;;; +0867;SYRIAC LETTER MALAYALAM RA;Lo;0;AL;;;;;N;;;;; +0868;SYRIAC LETTER MALAYALAM LLA;Lo;0;AL;;;;;N;;;;; +0869;SYRIAC LETTER MALAYALAM LLLA;Lo;0;AL;;;;;N;;;;; +086A;SYRIAC LETTER MALAYALAM SSA;Lo;0;AL;;;;;N;;;;; +0870;ARABIC LETTER ALEF WITH ATTACHED FATHA;Lo;0;AL;;;;;N;;;;; +0871;ARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA;Lo;0;AL;;;;;N;;;;; +0872;ARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE;Lo;0;AL;;;;;N;;;;; +0873;ARABIC LETTER ALEF WITH LEFT MIDDLE STROKE;Lo;0;AL;;;;;N;;;;; +0874;ARABIC LETTER ALEF WITH ATTACHED KASRA;Lo;0;AL;;;;;N;;;;; +0875;ARABIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRA;Lo;0;AL;;;;;N;;;;; +0876;ARABIC LETTER ALEF WITH ATTACHED ROUND DOT ABOVE;Lo;0;AL;;;;;N;;;;; +0877;ARABIC LETTER ALEF WITH ATTACHED RIGHT ROUND DOT;Lo;0;AL;;;;;N;;;;; +0878;ARABIC LETTER ALEF WITH ATTACHED LEFT ROUND DOT;Lo;0;AL;;;;;N;;;;; +0879;ARABIC LETTER ALEF WITH ATTACHED ROUND DOT BELOW;Lo;0;AL;;;;;N;;;;; +087A;ARABIC LETTER ALEF WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +087B;ARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; +087C;ARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; +087D;ARABIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRA AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; +087E;ARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA AND LEFT RING;Lo;0;AL;;;;;N;;;;; +087F;ARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE AND LEFT RING;Lo;0;AL;;;;;N;;;;; +0880;ARABIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRA AND LEFT RING;Lo;0;AL;;;;;N;;;;; +0881;ARABIC LETTER ALEF WITH ATTACHED RIGHT HAMZA;Lo;0;AL;;;;;N;;;;; +0882;ARABIC LETTER ALEF WITH ATTACHED LEFT HAMZA;Lo;0;AL;;;;;N;;;;; +0883;ARABIC TATWEEL WITH OVERSTRUCK HAMZA;Lo;0;AL;;;;;N;;;;; +0884;ARABIC TATWEEL WITH OVERSTRUCK WAW;Lo;0;AL;;;;;N;;;;; +0885;ARABIC TATWEEL WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; +0886;ARABIC LETTER THIN YEH;Lo;0;AL;;;;;N;;;;; +0887;ARABIC BASELINE ROUND DOT;Lo;0;AL;;;;;N;;;;; +0888;ARABIC RAISED ROUND DOT;Sk;0;AL;;;;;N;;;;; +0889;ARABIC LETTER NOON WITH INVERTED SMALL V;Lo;0;AL;;;;;N;;;;; +088A;ARABIC LETTER HAH WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;; +088B;ARABIC LETTER TAH WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +088C;ARABIC LETTER TAH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +088D;ARABIC LETTER KEHEH WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;; +088E;ARABIC VERTICAL TAIL;Lo;0;AL;;;;;N;;;;; +088F;ARABIC LETTER NOON WITH RING ABOVE;Lo;0;AL;;;;;N;;;;; +0890;ARABIC POUND MARK ABOVE;Cf;0;AN;;;;;N;;;;; +0891;ARABIC PIASTRE MARK ABOVE;Cf;0;AN;;;;;N;;;;; +0897;ARABIC PEPET;Mn;230;NSM;;;;;N;;;;; +0898;ARABIC SMALL HIGH WORD AL-JUZ;Mn;230;NSM;;;;;N;;;;; +0899;ARABIC SMALL LOW WORD ISHMAAM;Mn;220;NSM;;;;;N;;;;; +089A;ARABIC SMALL LOW WORD IMAALA;Mn;220;NSM;;;;;N;;;;; +089B;ARABIC SMALL LOW WORD TASHEEL;Mn;220;NSM;;;;;N;;;;; +089C;ARABIC MADDA WAAJIB;Mn;230;NSM;;;;;N;;;;; +089D;ARABIC SUPERSCRIPT ALEF MOKHASSAS;Mn;230;NSM;;;;;N;;;;; +089E;ARABIC DOUBLED MADDA;Mn;230;NSM;;;;;N;;;;; +089F;ARABIC HALF MADDA OVER MADDA;Mn;230;NSM;;;;;N;;;;; +08A0;ARABIC LETTER BEH WITH SMALL V BELOW;Lo;0;AL;;;;;N;;;;; +08A1;ARABIC LETTER BEH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;;;;; +08A2;ARABIC LETTER JEEM WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +08A3;ARABIC LETTER TAH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +08A4;ARABIC LETTER FEH WITH DOT BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +08A5;ARABIC LETTER QAF WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +08A6;ARABIC LETTER LAM WITH DOUBLE BAR;Lo;0;AL;;;;;N;;;;; +08A7;ARABIC LETTER MEEM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +08A8;ARABIC LETTER YEH WITH TWO DOTS BELOW AND HAMZA ABOVE;Lo;0;AL;;;;;N;;;;; +08A9;ARABIC LETTER YEH WITH TWO DOTS BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; +08AA;ARABIC LETTER REH WITH LOOP;Lo;0;AL;;;;;N;;;;; +08AB;ARABIC LETTER WAW WITH DOT WITHIN;Lo;0;AL;;;;;N;;;;; +08AC;ARABIC LETTER ROHINGYA YEH;Lo;0;AL;;;;;N;;;;; +08AD;ARABIC LETTER LOW ALEF;Lo;0;AL;;;;;N;;;;; +08AE;ARABIC LETTER DAL WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +08AF;ARABIC LETTER SAD WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +08B0;ARABIC LETTER GAF WITH INVERTED STROKE;Lo;0;AL;;;;;N;;;;; +08B1;ARABIC LETTER STRAIGHT WAW;Lo;0;AL;;;;;N;;;;; +08B2;ARABIC LETTER ZAIN WITH INVERTED V ABOVE;Lo;0;AL;;;;;N;;;;; +08B3;ARABIC LETTER AIN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +08B4;ARABIC LETTER KAF WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +08B5;ARABIC LETTER QAF WITH DOT BELOW AND NO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +08B6;ARABIC LETTER BEH WITH SMALL MEEM ABOVE;Lo;0;AL;;;;;N;;;;; +08B7;ARABIC LETTER PEH WITH SMALL MEEM ABOVE;Lo;0;AL;;;;;N;;;;; +08B8;ARABIC LETTER TEH WITH SMALL TEH ABOVE;Lo;0;AL;;;;;N;;;;; +08B9;ARABIC LETTER REH WITH SMALL NOON ABOVE;Lo;0;AL;;;;;N;;;;; +08BA;ARABIC LETTER YEH WITH TWO DOTS BELOW AND SMALL NOON ABOVE;Lo;0;AL;;;;;N;;;;; +08BB;ARABIC LETTER AFRICAN FEH;Lo;0;AL;;;;;N;;;;; +08BC;ARABIC LETTER AFRICAN QAF;Lo;0;AL;;;;;N;;;;; +08BD;ARABIC LETTER AFRICAN NOON;Lo;0;AL;;;;;N;;;;; +08BE;ARABIC LETTER PEH WITH SMALL V;Lo;0;AL;;;;;N;;;;; +08BF;ARABIC LETTER TEH WITH SMALL V;Lo;0;AL;;;;;N;;;;; +08C0;ARABIC LETTER TTEH WITH SMALL V;Lo;0;AL;;;;;N;;;;; +08C1;ARABIC LETTER TCHEH WITH SMALL V;Lo;0;AL;;;;;N;;;;; +08C2;ARABIC LETTER KEHEH WITH SMALL V;Lo;0;AL;;;;;N;;;;; +08C3;ARABIC LETTER GHAIN WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +08C4;ARABIC LETTER AFRICAN QAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +08C5;ARABIC LETTER JEEM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +08C6;ARABIC LETTER JEEM WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +08C7;ARABIC LETTER LAM WITH SMALL ARABIC LETTER TAH ABOVE;Lo;0;AL;;;;;N;;;;; +08C8;ARABIC LETTER GRAF;Lo;0;AL;;;;;N;;;;; +08C9;ARABIC SMALL FARSI YEH;Lm;0;AL;;;;;N;;;;; +08CA;ARABIC SMALL HIGH FARSI YEH;Mn;230;NSM;;;;;N;;;;; +08CB;ARABIC SMALL HIGH YEH BARREE WITH TWO DOTS BELOW;Mn;230;NSM;;;;;N;;;;; +08CC;ARABIC SMALL HIGH WORD SAH;Mn;230;NSM;;;;;N;;;;; +08CD;ARABIC SMALL HIGH ZAH;Mn;230;NSM;;;;;N;;;;; +08CE;ARABIC LARGE ROUND DOT ABOVE;Mn;230;NSM;;;;;N;;;;; +08CF;ARABIC LARGE ROUND DOT BELOW;Mn;220;NSM;;;;;N;;;;; +08D0;ARABIC SUKUN BELOW;Mn;220;NSM;;;;;N;;;;; +08D1;ARABIC LARGE CIRCLE BELOW;Mn;220;NSM;;;;;N;;;;; +08D2;ARABIC LARGE ROUND DOT INSIDE CIRCLE BELOW;Mn;220;NSM;;;;;N;;;;; +08D3;ARABIC SMALL LOW WAW;Mn;220;NSM;;;;;N;;;;; +08D4;ARABIC SMALL HIGH WORD AR-RUB;Mn;230;NSM;;;;;N;;;;; +08D5;ARABIC SMALL HIGH SAD;Mn;230;NSM;;;;;N;;;;; +08D6;ARABIC SMALL HIGH AIN;Mn;230;NSM;;;;;N;;;;; +08D7;ARABIC SMALL HIGH QAF;Mn;230;NSM;;;;;N;;;;; +08D8;ARABIC SMALL HIGH NOON WITH KASRA;Mn;230;NSM;;;;;N;;;;; +08D9;ARABIC SMALL LOW NOON WITH KASRA;Mn;230;NSM;;;;;N;;;;; +08DA;ARABIC SMALL HIGH WORD ATH-THALATHA;Mn;230;NSM;;;;;N;;;;; +08DB;ARABIC SMALL HIGH WORD AS-SAJDA;Mn;230;NSM;;;;;N;;;;; +08DC;ARABIC SMALL HIGH WORD AN-NISF;Mn;230;NSM;;;;;N;;;;; +08DD;ARABIC SMALL HIGH WORD SAKTA;Mn;230;NSM;;;;;N;;;;; +08DE;ARABIC SMALL HIGH WORD QIF;Mn;230;NSM;;;;;N;;;;; +08DF;ARABIC SMALL HIGH WORD WAQFA;Mn;230;NSM;;;;;N;;;;; +08E0;ARABIC SMALL HIGH FOOTNOTE MARKER;Mn;230;NSM;;;;;N;;;;; +08E1;ARABIC SMALL HIGH SIGN SAFHA;Mn;230;NSM;;;;;N;;;;; +08E2;ARABIC DISPUTED END OF AYAH;Cf;0;AN;;;;;N;;;;; +08E3;ARABIC TURNED DAMMA BELOW;Mn;220;NSM;;;;;N;;;;; +08E4;ARABIC CURLY FATHA;Mn;230;NSM;;;;;N;;;;; +08E5;ARABIC CURLY DAMMA;Mn;230;NSM;;;;;N;;;;; +08E6;ARABIC CURLY KASRA;Mn;220;NSM;;;;;N;;;;; +08E7;ARABIC CURLY FATHATAN;Mn;230;NSM;;;;;N;;;;; +08E8;ARABIC CURLY DAMMATAN;Mn;230;NSM;;;;;N;;;;; +08E9;ARABIC CURLY KASRATAN;Mn;220;NSM;;;;;N;;;;; +08EA;ARABIC TONE ONE DOT ABOVE;Mn;230;NSM;;;;;N;;;;; +08EB;ARABIC TONE TWO DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; +08EC;ARABIC TONE LOOP ABOVE;Mn;230;NSM;;;;;N;;;;; +08ED;ARABIC TONE ONE DOT BELOW;Mn;220;NSM;;;;;N;;;;; +08EE;ARABIC TONE TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;; +08EF;ARABIC TONE LOOP BELOW;Mn;220;NSM;;;;;N;;;;; +08F0;ARABIC OPEN FATHATAN;Mn;27;NSM;;;;;N;;;;; +08F1;ARABIC OPEN DAMMATAN;Mn;28;NSM;;;;;N;;;;; +08F2;ARABIC OPEN KASRATAN;Mn;29;NSM;;;;;N;;;;; +08F3;ARABIC SMALL HIGH WAW;Mn;230;NSM;;;;;N;;;;; +08F4;ARABIC FATHA WITH RING;Mn;230;NSM;;;;;N;;;;; +08F5;ARABIC FATHA WITH DOT ABOVE;Mn;230;NSM;;;;;N;;;;; +08F6;ARABIC KASRA WITH DOT BELOW;Mn;220;NSM;;;;;N;;;;; +08F7;ARABIC LEFT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; +08F8;ARABIC RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; +08F9;ARABIC LEFT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; +08FA;ARABIC RIGHT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; +08FB;ARABIC DOUBLE RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; +08FC;ARABIC DOUBLE RIGHT ARROWHEAD ABOVE WITH DOT;Mn;230;NSM;;;;;N;;;;; +08FD;ARABIC RIGHT ARROWHEAD ABOVE WITH DOT;Mn;230;NSM;;;;;N;;;;; +08FE;ARABIC DAMMA WITH DOT;Mn;230;NSM;;;;;N;;;;; +08FF;ARABIC MARK SIDEWAYS NOON GHUNNA;Mn;230;NSM;;;;;N;;;;; +0900;DEVANAGARI SIGN INVERTED CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +0901;DEVANAGARI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +0902;DEVANAGARI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +0903;DEVANAGARI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0904;DEVANAGARI LETTER SHORT A;Lo;0;L;;;;;N;;;;; +0905;DEVANAGARI LETTER A;Lo;0;L;;;;;N;;;;; +0906;DEVANAGARI LETTER AA;Lo;0;L;;;;;N;;;;; +0907;DEVANAGARI LETTER I;Lo;0;L;;;;;N;;;;; +0908;DEVANAGARI LETTER II;Lo;0;L;;;;;N;;;;; +0909;DEVANAGARI LETTER U;Lo;0;L;;;;;N;;;;; +090A;DEVANAGARI LETTER UU;Lo;0;L;;;;;N;;;;; +090B;DEVANAGARI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +090C;DEVANAGARI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +090D;DEVANAGARI LETTER CANDRA E;Lo;0;L;;;;;N;;;;; +090E;DEVANAGARI LETTER SHORT E;Lo;0;L;;;;;N;;;;; +090F;DEVANAGARI LETTER E;Lo;0;L;;;;;N;;;;; +0910;DEVANAGARI LETTER AI;Lo;0;L;;;;;N;;;;; +0911;DEVANAGARI LETTER CANDRA O;Lo;0;L;;;;;N;;;;; +0912;DEVANAGARI LETTER SHORT O;Lo;0;L;;;;;N;;;;; +0913;DEVANAGARI LETTER O;Lo;0;L;;;;;N;;;;; +0914;DEVANAGARI LETTER AU;Lo;0;L;;;;;N;;;;; +0915;DEVANAGARI LETTER KA;Lo;0;L;;;;;N;;;;; +0916;DEVANAGARI LETTER KHA;Lo;0;L;;;;;N;;;;; +0917;DEVANAGARI LETTER GA;Lo;0;L;;;;;N;;;;; +0918;DEVANAGARI LETTER GHA;Lo;0;L;;;;;N;;;;; +0919;DEVANAGARI LETTER NGA;Lo;0;L;;;;;N;;;;; +091A;DEVANAGARI LETTER CA;Lo;0;L;;;;;N;;;;; +091B;DEVANAGARI LETTER CHA;Lo;0;L;;;;;N;;;;; +091C;DEVANAGARI LETTER JA;Lo;0;L;;;;;N;;;;; +091D;DEVANAGARI LETTER JHA;Lo;0;L;;;;;N;;;;; +091E;DEVANAGARI LETTER NYA;Lo;0;L;;;;;N;;;;; +091F;DEVANAGARI LETTER TTA;Lo;0;L;;;;;N;;;;; +0920;DEVANAGARI LETTER TTHA;Lo;0;L;;;;;N;;;;; +0921;DEVANAGARI LETTER DDA;Lo;0;L;;;;;N;;;;; +0922;DEVANAGARI LETTER DDHA;Lo;0;L;;;;;N;;;;; +0923;DEVANAGARI LETTER NNA;Lo;0;L;;;;;N;;;;; +0924;DEVANAGARI LETTER TA;Lo;0;L;;;;;N;;;;; +0925;DEVANAGARI LETTER THA;Lo;0;L;;;;;N;;;;; +0926;DEVANAGARI LETTER DA;Lo;0;L;;;;;N;;;;; +0927;DEVANAGARI LETTER DHA;Lo;0;L;;;;;N;;;;; +0928;DEVANAGARI LETTER NA;Lo;0;L;;;;;N;;;;; +0929;DEVANAGARI LETTER NNNA;Lo;0;L;0928 093C;;;;N;;;;; +092A;DEVANAGARI LETTER PA;Lo;0;L;;;;;N;;;;; +092B;DEVANAGARI LETTER PHA;Lo;0;L;;;;;N;;;;; +092C;DEVANAGARI LETTER BA;Lo;0;L;;;;;N;;;;; +092D;DEVANAGARI LETTER BHA;Lo;0;L;;;;;N;;;;; +092E;DEVANAGARI LETTER MA;Lo;0;L;;;;;N;;;;; +092F;DEVANAGARI LETTER YA;Lo;0;L;;;;;N;;;;; +0930;DEVANAGARI LETTER RA;Lo;0;L;;;;;N;;;;; +0931;DEVANAGARI LETTER RRA;Lo;0;L;0930 093C;;;;N;;;;; +0932;DEVANAGARI LETTER LA;Lo;0;L;;;;;N;;;;; +0933;DEVANAGARI LETTER LLA;Lo;0;L;;;;;N;;;;; +0934;DEVANAGARI LETTER LLLA;Lo;0;L;0933 093C;;;;N;;;;; +0935;DEVANAGARI LETTER VA;Lo;0;L;;;;;N;;;;; +0936;DEVANAGARI LETTER SHA;Lo;0;L;;;;;N;;;;; +0937;DEVANAGARI LETTER SSA;Lo;0;L;;;;;N;;;;; +0938;DEVANAGARI LETTER SA;Lo;0;L;;;;;N;;;;; +0939;DEVANAGARI LETTER HA;Lo;0;L;;;;;N;;;;; +093A;DEVANAGARI VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;; +093B;DEVANAGARI VOWEL SIGN OOE;Mc;0;L;;;;;N;;;;; +093C;DEVANAGARI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +093D;DEVANAGARI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +093E;DEVANAGARI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +093F;DEVANAGARI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +0940;DEVANAGARI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +0941;DEVANAGARI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +0942;DEVANAGARI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +0943;DEVANAGARI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +0944;DEVANAGARI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +0945;DEVANAGARI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;; +0946;DEVANAGARI VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;; +0947;DEVANAGARI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +0948;DEVANAGARI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +0949;DEVANAGARI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;; +094A;DEVANAGARI VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;; +094B;DEVANAGARI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +094C;DEVANAGARI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +094D;DEVANAGARI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +094E;DEVANAGARI VOWEL SIGN PRISHTHAMATRA E;Mc;0;L;;;;;N;;;;; +094F;DEVANAGARI VOWEL SIGN AW;Mc;0;L;;;;;N;;;;; +0950;DEVANAGARI OM;Lo;0;L;;;;;N;;;;; +0951;DEVANAGARI STRESS SIGN UDATTA;Mn;230;NSM;;;;;N;;;;; +0952;DEVANAGARI STRESS SIGN ANUDATTA;Mn;220;NSM;;;;;N;;;;; +0953;DEVANAGARI GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;; +0954;DEVANAGARI ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;; +0955;DEVANAGARI VOWEL SIGN CANDRA LONG E;Mn;0;NSM;;;;;N;;;;; +0956;DEVANAGARI VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;; +0957;DEVANAGARI VOWEL SIGN UUE;Mn;0;NSM;;;;;N;;;;; +0958;DEVANAGARI LETTER QA;Lo;0;L;0915 093C;;;;N;;;;; +0959;DEVANAGARI LETTER KHHA;Lo;0;L;0916 093C;;;;N;;;;; +095A;DEVANAGARI LETTER GHHA;Lo;0;L;0917 093C;;;;N;;;;; +095B;DEVANAGARI LETTER ZA;Lo;0;L;091C 093C;;;;N;;;;; +095C;DEVANAGARI LETTER DDDHA;Lo;0;L;0921 093C;;;;N;;;;; +095D;DEVANAGARI LETTER RHA;Lo;0;L;0922 093C;;;;N;;;;; +095E;DEVANAGARI LETTER FA;Lo;0;L;092B 093C;;;;N;;;;; +095F;DEVANAGARI LETTER YYA;Lo;0;L;092F 093C;;;;N;;;;; +0960;DEVANAGARI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0961;DEVANAGARI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0962;DEVANAGARI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +0963;DEVANAGARI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +0964;DEVANAGARI DANDA;Po;0;L;;;;;N;;;;; +0965;DEVANAGARI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +0966;DEVANAGARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0967;DEVANAGARI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0968;DEVANAGARI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0969;DEVANAGARI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +096A;DEVANAGARI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +096B;DEVANAGARI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +096C;DEVANAGARI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +096D;DEVANAGARI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +096E;DEVANAGARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +096F;DEVANAGARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0970;DEVANAGARI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +0971;DEVANAGARI SIGN HIGH SPACING DOT;Lm;0;L;;;;;N;;;;; +0972;DEVANAGARI LETTER CANDRA A;Lo;0;L;;;;;N;;;;; +0973;DEVANAGARI LETTER OE;Lo;0;L;;;;;N;;;;; +0974;DEVANAGARI LETTER OOE;Lo;0;L;;;;;N;;;;; +0975;DEVANAGARI LETTER AW;Lo;0;L;;;;;N;;;;; +0976;DEVANAGARI LETTER UE;Lo;0;L;;;;;N;;;;; +0977;DEVANAGARI LETTER UUE;Lo;0;L;;;;;N;;;;; +0978;DEVANAGARI LETTER MARWARI DDA;Lo;0;L;;;;;N;;;;; +0979;DEVANAGARI LETTER ZHA;Lo;0;L;;;;;N;;;;; +097A;DEVANAGARI LETTER HEAVY YA;Lo;0;L;;;;;N;;;;; +097B;DEVANAGARI LETTER GGA;Lo;0;L;;;;;N;;;;; +097C;DEVANAGARI LETTER JJA;Lo;0;L;;;;;N;;;;; +097D;DEVANAGARI LETTER GLOTTAL STOP;Lo;0;L;;;;;N;;;;; +097E;DEVANAGARI LETTER DDDA;Lo;0;L;;;;;N;;;;; +097F;DEVANAGARI LETTER BBA;Lo;0;L;;;;;N;;;;; +0980;BENGALI ANJI;Lo;0;L;;;;;N;;;;; +0981;BENGALI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +0982;BENGALI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +0983;BENGALI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0985;BENGALI LETTER A;Lo;0;L;;;;;N;;;;; +0986;BENGALI LETTER AA;Lo;0;L;;;;;N;;;;; +0987;BENGALI LETTER I;Lo;0;L;;;;;N;;;;; +0988;BENGALI LETTER II;Lo;0;L;;;;;N;;;;; +0989;BENGALI LETTER U;Lo;0;L;;;;;N;;;;; +098A;BENGALI LETTER UU;Lo;0;L;;;;;N;;;;; +098B;BENGALI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +098C;BENGALI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +098F;BENGALI LETTER E;Lo;0;L;;;;;N;;;;; +0990;BENGALI LETTER AI;Lo;0;L;;;;;N;;;;; +0993;BENGALI LETTER O;Lo;0;L;;;;;N;;;;; +0994;BENGALI LETTER AU;Lo;0;L;;;;;N;;;;; +0995;BENGALI LETTER KA;Lo;0;L;;;;;N;;;;; +0996;BENGALI LETTER KHA;Lo;0;L;;;;;N;;;;; +0997;BENGALI LETTER GA;Lo;0;L;;;;;N;;;;; +0998;BENGALI LETTER GHA;Lo;0;L;;;;;N;;;;; +0999;BENGALI LETTER NGA;Lo;0;L;;;;;N;;;;; +099A;BENGALI LETTER CA;Lo;0;L;;;;;N;;;;; +099B;BENGALI LETTER CHA;Lo;0;L;;;;;N;;;;; +099C;BENGALI LETTER JA;Lo;0;L;;;;;N;;;;; +099D;BENGALI LETTER JHA;Lo;0;L;;;;;N;;;;; +099E;BENGALI LETTER NYA;Lo;0;L;;;;;N;;;;; +099F;BENGALI LETTER TTA;Lo;0;L;;;;;N;;;;; +09A0;BENGALI LETTER TTHA;Lo;0;L;;;;;N;;;;; +09A1;BENGALI LETTER DDA;Lo;0;L;;;;;N;;;;; +09A2;BENGALI LETTER DDHA;Lo;0;L;;;;;N;;;;; +09A3;BENGALI LETTER NNA;Lo;0;L;;;;;N;;;;; +09A4;BENGALI LETTER TA;Lo;0;L;;;;;N;;;;; +09A5;BENGALI LETTER THA;Lo;0;L;;;;;N;;;;; +09A6;BENGALI LETTER DA;Lo;0;L;;;;;N;;;;; +09A7;BENGALI LETTER DHA;Lo;0;L;;;;;N;;;;; +09A8;BENGALI LETTER NA;Lo;0;L;;;;;N;;;;; +09AA;BENGALI LETTER PA;Lo;0;L;;;;;N;;;;; +09AB;BENGALI LETTER PHA;Lo;0;L;;;;;N;;;;; +09AC;BENGALI LETTER BA;Lo;0;L;;;;;N;;;;; +09AD;BENGALI LETTER BHA;Lo;0;L;;;;;N;;;;; +09AE;BENGALI LETTER MA;Lo;0;L;;;;;N;;;;; +09AF;BENGALI LETTER YA;Lo;0;L;;;;;N;;;;; +09B0;BENGALI LETTER RA;Lo;0;L;;;;;N;;;;; +09B2;BENGALI LETTER LA;Lo;0;L;;;;;N;;;;; +09B6;BENGALI LETTER SHA;Lo;0;L;;;;;N;;;;; +09B7;BENGALI LETTER SSA;Lo;0;L;;;;;N;;;;; +09B8;BENGALI LETTER SA;Lo;0;L;;;;;N;;;;; +09B9;BENGALI LETTER HA;Lo;0;L;;;;;N;;;;; +09BC;BENGALI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +09BD;BENGALI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +09BE;BENGALI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +09BF;BENGALI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +09C0;BENGALI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +09C1;BENGALI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +09C2;BENGALI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +09C3;BENGALI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +09C4;BENGALI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +09C7;BENGALI VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +09C8;BENGALI VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +09CB;BENGALI VOWEL SIGN O;Mc;0;L;09C7 09BE;;;;N;;;;; +09CC;BENGALI VOWEL SIGN AU;Mc;0;L;09C7 09D7;;;;N;;;;; +09CD;BENGALI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +09CE;BENGALI LETTER KHANDA TA;Lo;0;L;;;;;N;;;;; +09D7;BENGALI AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +09DC;BENGALI LETTER RRA;Lo;0;L;09A1 09BC;;;;N;;;;; +09DD;BENGALI LETTER RHA;Lo;0;L;09A2 09BC;;;;N;;;;; +09DF;BENGALI LETTER YYA;Lo;0;L;09AF 09BC;;;;N;;;;; +09E0;BENGALI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +09E1;BENGALI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +09E2;BENGALI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +09E3;BENGALI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +09E6;BENGALI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +09E7;BENGALI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +09E8;BENGALI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +09E9;BENGALI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +09EA;BENGALI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +09EB;BENGALI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +09EC;BENGALI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +09ED;BENGALI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +09EE;BENGALI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +09EF;BENGALI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +09F0;BENGALI LETTER RA WITH MIDDLE DIAGONAL;Lo;0;L;;;;;N;;;;; +09F1;BENGALI LETTER RA WITH LOWER DIAGONAL;Lo;0;L;;;;;N;BENGALI LETTER VA WITH LOWER DIAGONAL;;;; +09F2;BENGALI RUPEE MARK;Sc;0;ET;;;;;N;;;;; +09F3;BENGALI RUPEE SIGN;Sc;0;ET;;;;;N;;;;; +09F4;BENGALI CURRENCY NUMERATOR ONE;No;0;L;;;;1/16;N;;;;; +09F5;BENGALI CURRENCY NUMERATOR TWO;No;0;L;;;;1/8;N;;;;; +09F6;BENGALI CURRENCY NUMERATOR THREE;No;0;L;;;;3/16;N;;;;; +09F7;BENGALI CURRENCY NUMERATOR FOUR;No;0;L;;;;1/4;N;;;;; +09F8;BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR;No;0;L;;;;3/4;N;;;;; +09F9;BENGALI CURRENCY DENOMINATOR SIXTEEN;No;0;L;;;;16;N;;;;; +09FA;BENGALI ISSHAR;So;0;L;;;;;N;;;;; +09FB;BENGALI GANDA MARK;Sc;0;ET;;;;;N;;;;; +09FC;BENGALI LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;; +09FD;BENGALI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +09FE;BENGALI SANDHI MARK;Mn;230;NSM;;;;;N;;;;; +0A01;GURMUKHI SIGN ADAK BINDI;Mn;0;NSM;;;;;N;;;;; +0A02;GURMUKHI SIGN BINDI;Mn;0;NSM;;;;;N;;;;; +0A03;GURMUKHI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0A05;GURMUKHI LETTER A;Lo;0;L;;;;;N;;;;; +0A06;GURMUKHI LETTER AA;Lo;0;L;;;;;N;;;;; +0A07;GURMUKHI LETTER I;Lo;0;L;;;;;N;;;;; +0A08;GURMUKHI LETTER II;Lo;0;L;;;;;N;;;;; +0A09;GURMUKHI LETTER U;Lo;0;L;;;;;N;;;;; +0A0A;GURMUKHI LETTER UU;Lo;0;L;;;;;N;;;;; +0A0F;GURMUKHI LETTER EE;Lo;0;L;;;;;N;;;;; +0A10;GURMUKHI LETTER AI;Lo;0;L;;;;;N;;;;; +0A13;GURMUKHI LETTER OO;Lo;0;L;;;;;N;;;;; +0A14;GURMUKHI LETTER AU;Lo;0;L;;;;;N;;;;; +0A15;GURMUKHI LETTER KA;Lo;0;L;;;;;N;;;;; +0A16;GURMUKHI LETTER KHA;Lo;0;L;;;;;N;;;;; +0A17;GURMUKHI LETTER GA;Lo;0;L;;;;;N;;;;; +0A18;GURMUKHI LETTER GHA;Lo;0;L;;;;;N;;;;; +0A19;GURMUKHI LETTER NGA;Lo;0;L;;;;;N;;;;; +0A1A;GURMUKHI LETTER CA;Lo;0;L;;;;;N;;;;; +0A1B;GURMUKHI LETTER CHA;Lo;0;L;;;;;N;;;;; +0A1C;GURMUKHI LETTER JA;Lo;0;L;;;;;N;;;;; +0A1D;GURMUKHI LETTER JHA;Lo;0;L;;;;;N;;;;; +0A1E;GURMUKHI LETTER NYA;Lo;0;L;;;;;N;;;;; +0A1F;GURMUKHI LETTER TTA;Lo;0;L;;;;;N;;;;; +0A20;GURMUKHI LETTER TTHA;Lo;0;L;;;;;N;;;;; +0A21;GURMUKHI LETTER DDA;Lo;0;L;;;;;N;;;;; +0A22;GURMUKHI LETTER DDHA;Lo;0;L;;;;;N;;;;; +0A23;GURMUKHI LETTER NNA;Lo;0;L;;;;;N;;;;; +0A24;GURMUKHI LETTER TA;Lo;0;L;;;;;N;;;;; +0A25;GURMUKHI LETTER THA;Lo;0;L;;;;;N;;;;; +0A26;GURMUKHI LETTER DA;Lo;0;L;;;;;N;;;;; +0A27;GURMUKHI LETTER DHA;Lo;0;L;;;;;N;;;;; +0A28;GURMUKHI LETTER NA;Lo;0;L;;;;;N;;;;; +0A2A;GURMUKHI LETTER PA;Lo;0;L;;;;;N;;;;; +0A2B;GURMUKHI LETTER PHA;Lo;0;L;;;;;N;;;;; +0A2C;GURMUKHI LETTER BA;Lo;0;L;;;;;N;;;;; +0A2D;GURMUKHI LETTER BHA;Lo;0;L;;;;;N;;;;; +0A2E;GURMUKHI LETTER MA;Lo;0;L;;;;;N;;;;; +0A2F;GURMUKHI LETTER YA;Lo;0;L;;;;;N;;;;; +0A30;GURMUKHI LETTER RA;Lo;0;L;;;;;N;;;;; +0A32;GURMUKHI LETTER LA;Lo;0;L;;;;;N;;;;; +0A33;GURMUKHI LETTER LLA;Lo;0;L;0A32 0A3C;;;;N;;;;; +0A35;GURMUKHI LETTER VA;Lo;0;L;;;;;N;;;;; +0A36;GURMUKHI LETTER SHA;Lo;0;L;0A38 0A3C;;;;N;;;;; +0A38;GURMUKHI LETTER SA;Lo;0;L;;;;;N;;;;; +0A39;GURMUKHI LETTER HA;Lo;0;L;;;;;N;;;;; +0A3C;GURMUKHI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +0A3E;GURMUKHI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0A3F;GURMUKHI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +0A40;GURMUKHI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +0A41;GURMUKHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +0A42;GURMUKHI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +0A47;GURMUKHI VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;; +0A48;GURMUKHI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +0A4B;GURMUKHI VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;; +0A4C;GURMUKHI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +0A4D;GURMUKHI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0A51;GURMUKHI SIGN UDAAT;Mn;0;NSM;;;;;N;;;;; +0A59;GURMUKHI LETTER KHHA;Lo;0;L;0A16 0A3C;;;;N;;;;; +0A5A;GURMUKHI LETTER GHHA;Lo;0;L;0A17 0A3C;;;;N;;;;; +0A5B;GURMUKHI LETTER ZA;Lo;0;L;0A1C 0A3C;;;;N;;;;; +0A5C;GURMUKHI LETTER RRA;Lo;0;L;;;;;N;;;;; +0A5E;GURMUKHI LETTER FA;Lo;0;L;0A2B 0A3C;;;;N;;;;; +0A66;GURMUKHI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0A67;GURMUKHI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0A68;GURMUKHI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0A69;GURMUKHI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0A6A;GURMUKHI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0A6B;GURMUKHI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0A6C;GURMUKHI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0A6D;GURMUKHI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0A6E;GURMUKHI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0A6F;GURMUKHI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0A70;GURMUKHI TIPPI;Mn;0;NSM;;;;;N;;;;; +0A71;GURMUKHI ADDAK;Mn;0;NSM;;;;;N;;;;; +0A72;GURMUKHI IRI;Lo;0;L;;;;;N;;;;; +0A73;GURMUKHI URA;Lo;0;L;;;;;N;;;;; +0A74;GURMUKHI EK ONKAR;Lo;0;L;;;;;N;;;;; +0A75;GURMUKHI SIGN YAKASH;Mn;0;NSM;;;;;N;;;;; +0A76;GURMUKHI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +0A81;GUJARATI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +0A82;GUJARATI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +0A83;GUJARATI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0A85;GUJARATI LETTER A;Lo;0;L;;;;;N;;;;; +0A86;GUJARATI LETTER AA;Lo;0;L;;;;;N;;;;; +0A87;GUJARATI LETTER I;Lo;0;L;;;;;N;;;;; +0A88;GUJARATI LETTER II;Lo;0;L;;;;;N;;;;; +0A89;GUJARATI LETTER U;Lo;0;L;;;;;N;;;;; +0A8A;GUJARATI LETTER UU;Lo;0;L;;;;;N;;;;; +0A8B;GUJARATI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +0A8C;GUJARATI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +0A8D;GUJARATI VOWEL CANDRA E;Lo;0;L;;;;;N;;;;; +0A8F;GUJARATI LETTER E;Lo;0;L;;;;;N;;;;; +0A90;GUJARATI LETTER AI;Lo;0;L;;;;;N;;;;; +0A91;GUJARATI VOWEL CANDRA O;Lo;0;L;;;;;N;;;;; +0A93;GUJARATI LETTER O;Lo;0;L;;;;;N;;;;; +0A94;GUJARATI LETTER AU;Lo;0;L;;;;;N;;;;; +0A95;GUJARATI LETTER KA;Lo;0;L;;;;;N;;;;; +0A96;GUJARATI LETTER KHA;Lo;0;L;;;;;N;;;;; +0A97;GUJARATI LETTER GA;Lo;0;L;;;;;N;;;;; +0A98;GUJARATI LETTER GHA;Lo;0;L;;;;;N;;;;; +0A99;GUJARATI LETTER NGA;Lo;0;L;;;;;N;;;;; +0A9A;GUJARATI LETTER CA;Lo;0;L;;;;;N;;;;; +0A9B;GUJARATI LETTER CHA;Lo;0;L;;;;;N;;;;; +0A9C;GUJARATI LETTER JA;Lo;0;L;;;;;N;;;;; +0A9D;GUJARATI LETTER JHA;Lo;0;L;;;;;N;;;;; +0A9E;GUJARATI LETTER NYA;Lo;0;L;;;;;N;;;;; +0A9F;GUJARATI LETTER TTA;Lo;0;L;;;;;N;;;;; +0AA0;GUJARATI LETTER TTHA;Lo;0;L;;;;;N;;;;; +0AA1;GUJARATI LETTER DDA;Lo;0;L;;;;;N;;;;; +0AA2;GUJARATI LETTER DDHA;Lo;0;L;;;;;N;;;;; +0AA3;GUJARATI LETTER NNA;Lo;0;L;;;;;N;;;;; +0AA4;GUJARATI LETTER TA;Lo;0;L;;;;;N;;;;; +0AA5;GUJARATI LETTER THA;Lo;0;L;;;;;N;;;;; +0AA6;GUJARATI LETTER DA;Lo;0;L;;;;;N;;;;; +0AA7;GUJARATI LETTER DHA;Lo;0;L;;;;;N;;;;; +0AA8;GUJARATI LETTER NA;Lo;0;L;;;;;N;;;;; +0AAA;GUJARATI LETTER PA;Lo;0;L;;;;;N;;;;; +0AAB;GUJARATI LETTER PHA;Lo;0;L;;;;;N;;;;; +0AAC;GUJARATI LETTER BA;Lo;0;L;;;;;N;;;;; +0AAD;GUJARATI LETTER BHA;Lo;0;L;;;;;N;;;;; +0AAE;GUJARATI LETTER MA;Lo;0;L;;;;;N;;;;; +0AAF;GUJARATI LETTER YA;Lo;0;L;;;;;N;;;;; +0AB0;GUJARATI LETTER RA;Lo;0;L;;;;;N;;;;; +0AB2;GUJARATI LETTER LA;Lo;0;L;;;;;N;;;;; +0AB3;GUJARATI LETTER LLA;Lo;0;L;;;;;N;;;;; +0AB5;GUJARATI LETTER VA;Lo;0;L;;;;;N;;;;; +0AB6;GUJARATI LETTER SHA;Lo;0;L;;;;;N;;;;; +0AB7;GUJARATI LETTER SSA;Lo;0;L;;;;;N;;;;; +0AB8;GUJARATI LETTER SA;Lo;0;L;;;;;N;;;;; +0AB9;GUJARATI LETTER HA;Lo;0;L;;;;;N;;;;; +0ABC;GUJARATI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +0ABD;GUJARATI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +0ABE;GUJARATI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0ABF;GUJARATI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +0AC0;GUJARATI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +0AC1;GUJARATI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +0AC2;GUJARATI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +0AC3;GUJARATI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +0AC4;GUJARATI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +0AC5;GUJARATI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;; +0AC7;GUJARATI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +0AC8;GUJARATI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +0AC9;GUJARATI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;; +0ACB;GUJARATI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +0ACC;GUJARATI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +0ACD;GUJARATI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0AD0;GUJARATI OM;Lo;0;L;;;;;N;;;;; +0AE0;GUJARATI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0AE1;GUJARATI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0AE2;GUJARATI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +0AE3;GUJARATI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +0AE6;GUJARATI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0AE7;GUJARATI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0AE8;GUJARATI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0AE9;GUJARATI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0AEA;GUJARATI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0AEB;GUJARATI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0AEC;GUJARATI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0AED;GUJARATI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0AEE;GUJARATI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0AEF;GUJARATI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0AF0;GUJARATI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +0AF1;GUJARATI RUPEE SIGN;Sc;0;ET;;;;;N;;;;; +0AF9;GUJARATI LETTER ZHA;Lo;0;L;;;;;N;;;;; +0AFA;GUJARATI SIGN SUKUN;Mn;0;NSM;;;;;N;;;;; +0AFB;GUJARATI SIGN SHADDA;Mn;0;NSM;;;;;N;;;;; +0AFC;GUJARATI SIGN MADDAH;Mn;0;NSM;;;;;N;;;;; +0AFD;GUJARATI SIGN THREE-DOT NUKTA ABOVE;Mn;0;NSM;;;;;N;;;;; +0AFE;GUJARATI SIGN CIRCLE NUKTA ABOVE;Mn;0;NSM;;;;;N;;;;; +0AFF;GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE;Mn;0;NSM;;;;;N;;;;; +0B01;ORIYA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +0B02;ORIYA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +0B03;ORIYA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0B05;ORIYA LETTER A;Lo;0;L;;;;;N;;;;; +0B06;ORIYA LETTER AA;Lo;0;L;;;;;N;;;;; +0B07;ORIYA LETTER I;Lo;0;L;;;;;N;;;;; +0B08;ORIYA LETTER II;Lo;0;L;;;;;N;;;;; +0B09;ORIYA LETTER U;Lo;0;L;;;;;N;;;;; +0B0A;ORIYA LETTER UU;Lo;0;L;;;;;N;;;;; +0B0B;ORIYA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +0B0C;ORIYA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +0B0F;ORIYA LETTER E;Lo;0;L;;;;;N;;;;; +0B10;ORIYA LETTER AI;Lo;0;L;;;;;N;;;;; +0B13;ORIYA LETTER O;Lo;0;L;;;;;N;;;;; +0B14;ORIYA LETTER AU;Lo;0;L;;;;;N;;;;; +0B15;ORIYA LETTER KA;Lo;0;L;;;;;N;;;;; +0B16;ORIYA LETTER KHA;Lo;0;L;;;;;N;;;;; +0B17;ORIYA LETTER GA;Lo;0;L;;;;;N;;;;; +0B18;ORIYA LETTER GHA;Lo;0;L;;;;;N;;;;; +0B19;ORIYA LETTER NGA;Lo;0;L;;;;;N;;;;; +0B1A;ORIYA LETTER CA;Lo;0;L;;;;;N;;;;; +0B1B;ORIYA LETTER CHA;Lo;0;L;;;;;N;;;;; +0B1C;ORIYA LETTER JA;Lo;0;L;;;;;N;;;;; +0B1D;ORIYA LETTER JHA;Lo;0;L;;;;;N;;;;; +0B1E;ORIYA LETTER NYA;Lo;0;L;;;;;N;;;;; +0B1F;ORIYA LETTER TTA;Lo;0;L;;;;;N;;;;; +0B20;ORIYA LETTER TTHA;Lo;0;L;;;;;N;;;;; +0B21;ORIYA LETTER DDA;Lo;0;L;;;;;N;;;;; +0B22;ORIYA LETTER DDHA;Lo;0;L;;;;;N;;;;; +0B23;ORIYA LETTER NNA;Lo;0;L;;;;;N;;;;; +0B24;ORIYA LETTER TA;Lo;0;L;;;;;N;;;;; +0B25;ORIYA LETTER THA;Lo;0;L;;;;;N;;;;; +0B26;ORIYA LETTER DA;Lo;0;L;;;;;N;;;;; +0B27;ORIYA LETTER DHA;Lo;0;L;;;;;N;;;;; +0B28;ORIYA LETTER NA;Lo;0;L;;;;;N;;;;; +0B2A;ORIYA LETTER PA;Lo;0;L;;;;;N;;;;; +0B2B;ORIYA LETTER PHA;Lo;0;L;;;;;N;;;;; +0B2C;ORIYA LETTER BA;Lo;0;L;;;;;N;;;;; +0B2D;ORIYA LETTER BHA;Lo;0;L;;;;;N;;;;; +0B2E;ORIYA LETTER MA;Lo;0;L;;;;;N;;;;; +0B2F;ORIYA LETTER YA;Lo;0;L;;;;;N;;;;; +0B30;ORIYA LETTER RA;Lo;0;L;;;;;N;;;;; +0B32;ORIYA LETTER LA;Lo;0;L;;;;;N;;;;; +0B33;ORIYA LETTER LLA;Lo;0;L;;;;;N;;;;; +0B35;ORIYA LETTER VA;Lo;0;L;;;;;N;;;;; +0B36;ORIYA LETTER SHA;Lo;0;L;;;;;N;;;;; +0B37;ORIYA LETTER SSA;Lo;0;L;;;;;N;;;;; +0B38;ORIYA LETTER SA;Lo;0;L;;;;;N;;;;; +0B39;ORIYA LETTER HA;Lo;0;L;;;;;N;;;;; +0B3C;ORIYA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +0B3D;ORIYA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +0B3E;ORIYA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0B3F;ORIYA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +0B40;ORIYA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +0B41;ORIYA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +0B42;ORIYA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +0B43;ORIYA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +0B44;ORIYA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +0B47;ORIYA VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +0B48;ORIYA VOWEL SIGN AI;Mc;0;L;0B47 0B56;;;;N;;;;; +0B4B;ORIYA VOWEL SIGN O;Mc;0;L;0B47 0B3E;;;;N;;;;; +0B4C;ORIYA VOWEL SIGN AU;Mc;0;L;0B47 0B57;;;;N;;;;; +0B4D;ORIYA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0B55;ORIYA SIGN OVERLINE;Mn;0;NSM;;;;;N;;;;; +0B56;ORIYA AI LENGTH MARK;Mn;0;NSM;;;;;N;;;;; +0B57;ORIYA AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +0B5C;ORIYA LETTER RRA;Lo;0;L;0B21 0B3C;;;;N;;;;; +0B5D;ORIYA LETTER RHA;Lo;0;L;0B22 0B3C;;;;N;;;;; +0B5F;ORIYA LETTER YYA;Lo;0;L;;;;;N;;;;; +0B60;ORIYA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0B61;ORIYA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0B62;ORIYA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +0B63;ORIYA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +0B66;ORIYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0B67;ORIYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0B68;ORIYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0B69;ORIYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0B6A;ORIYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0B6B;ORIYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0B6C;ORIYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0B6D;ORIYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0B6E;ORIYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0B6F;ORIYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0B70;ORIYA ISSHAR;So;0;L;;;;;N;;;;; +0B71;ORIYA LETTER WA;Lo;0;L;;;;;N;;;;; +0B72;ORIYA FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;; +0B73;ORIYA FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;; +0B74;ORIYA FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;; +0B75;ORIYA FRACTION ONE SIXTEENTH;No;0;L;;;;1/16;N;;;;; +0B76;ORIYA FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;; +0B77;ORIYA FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;; +0B82;TAMIL SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +0B83;TAMIL SIGN VISARGA;Lo;0;L;;;;;N;;;;; +0B85;TAMIL LETTER A;Lo;0;L;;;;;N;;;;; +0B86;TAMIL LETTER AA;Lo;0;L;;;;;N;;;;; +0B87;TAMIL LETTER I;Lo;0;L;;;;;N;;;;; +0B88;TAMIL LETTER II;Lo;0;L;;;;;N;;;;; +0B89;TAMIL LETTER U;Lo;0;L;;;;;N;;;;; +0B8A;TAMIL LETTER UU;Lo;0;L;;;;;N;;;;; +0B8E;TAMIL LETTER E;Lo;0;L;;;;;N;;;;; +0B8F;TAMIL LETTER EE;Lo;0;L;;;;;N;;;;; +0B90;TAMIL LETTER AI;Lo;0;L;;;;;N;;;;; +0B92;TAMIL LETTER O;Lo;0;L;;;;;N;;;;; +0B93;TAMIL LETTER OO;Lo;0;L;;;;;N;;;;; +0B94;TAMIL LETTER AU;Lo;0;L;0B92 0BD7;;;;N;;;;; +0B95;TAMIL LETTER KA;Lo;0;L;;;;;N;;;;; +0B99;TAMIL LETTER NGA;Lo;0;L;;;;;N;;;;; +0B9A;TAMIL LETTER CA;Lo;0;L;;;;;N;;;;; +0B9C;TAMIL LETTER JA;Lo;0;L;;;;;N;;;;; +0B9E;TAMIL LETTER NYA;Lo;0;L;;;;;N;;;;; +0B9F;TAMIL LETTER TTA;Lo;0;L;;;;;N;;;;; +0BA3;TAMIL LETTER NNA;Lo;0;L;;;;;N;;;;; +0BA4;TAMIL LETTER TA;Lo;0;L;;;;;N;;;;; +0BA8;TAMIL LETTER NA;Lo;0;L;;;;;N;;;;; +0BA9;TAMIL LETTER NNNA;Lo;0;L;;;;;N;;;;; +0BAA;TAMIL LETTER PA;Lo;0;L;;;;;N;;;;; +0BAE;TAMIL LETTER MA;Lo;0;L;;;;;N;;;;; +0BAF;TAMIL LETTER YA;Lo;0;L;;;;;N;;;;; +0BB0;TAMIL LETTER RA;Lo;0;L;;;;;N;;;;; +0BB1;TAMIL LETTER RRA;Lo;0;L;;;;;N;;;;; +0BB2;TAMIL LETTER LA;Lo;0;L;;;;;N;;;;; +0BB3;TAMIL LETTER LLA;Lo;0;L;;;;;N;;;;; +0BB4;TAMIL LETTER LLLA;Lo;0;L;;;;;N;;;;; +0BB5;TAMIL LETTER VA;Lo;0;L;;;;;N;;;;; +0BB6;TAMIL LETTER SHA;Lo;0;L;;;;;N;;;;; +0BB7;TAMIL LETTER SSA;Lo;0;L;;;;;N;;;;; +0BB8;TAMIL LETTER SA;Lo;0;L;;;;;N;;;;; +0BB9;TAMIL LETTER HA;Lo;0;L;;;;;N;;;;; +0BBE;TAMIL VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0BBF;TAMIL VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +0BC0;TAMIL VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +0BC1;TAMIL VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +0BC2;TAMIL VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +0BC6;TAMIL VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +0BC7;TAMIL VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; +0BC8;TAMIL VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +0BCA;TAMIL VOWEL SIGN O;Mc;0;L;0BC6 0BBE;;;;N;;;;; +0BCB;TAMIL VOWEL SIGN OO;Mc;0;L;0BC7 0BBE;;;;N;;;;; +0BCC;TAMIL VOWEL SIGN AU;Mc;0;L;0BC6 0BD7;;;;N;;;;; +0BCD;TAMIL SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0BD0;TAMIL OM;Lo;0;L;;;;;N;;;;; +0BD7;TAMIL AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +0BE6;TAMIL DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0BE7;TAMIL DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0BE8;TAMIL DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0BE9;TAMIL DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0BEA;TAMIL DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0BEB;TAMIL DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0BEC;TAMIL DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0BED;TAMIL DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0BEE;TAMIL DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0BEF;TAMIL DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0BF0;TAMIL NUMBER TEN;No;0;L;;;;10;N;;;;; +0BF1;TAMIL NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;; +0BF2;TAMIL NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;; +0BF3;TAMIL DAY SIGN;So;0;ON;;;;;N;;;;; +0BF4;TAMIL MONTH SIGN;So;0;ON;;;;;N;;;;; +0BF5;TAMIL YEAR SIGN;So;0;ON;;;;;N;;;;; +0BF6;TAMIL DEBIT SIGN;So;0;ON;;;;;N;;;;; +0BF7;TAMIL CREDIT SIGN;So;0;ON;;;;;N;;;;; +0BF8;TAMIL AS ABOVE SIGN;So;0;ON;;;;;N;;;;; +0BF9;TAMIL RUPEE SIGN;Sc;0;ET;;;;;N;;;;; +0BFA;TAMIL NUMBER SIGN;So;0;ON;;;;;N;;;;; +0C00;TELUGU SIGN COMBINING CANDRABINDU ABOVE;Mn;0;NSM;;;;;N;;;;; +0C01;TELUGU SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;; +0C02;TELUGU SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +0C03;TELUGU SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0C04;TELUGU SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;; +0C05;TELUGU LETTER A;Lo;0;L;;;;;N;;;;; +0C06;TELUGU LETTER AA;Lo;0;L;;;;;N;;;;; +0C07;TELUGU LETTER I;Lo;0;L;;;;;N;;;;; +0C08;TELUGU LETTER II;Lo;0;L;;;;;N;;;;; +0C09;TELUGU LETTER U;Lo;0;L;;;;;N;;;;; +0C0A;TELUGU LETTER UU;Lo;0;L;;;;;N;;;;; +0C0B;TELUGU LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +0C0C;TELUGU LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +0C0E;TELUGU LETTER E;Lo;0;L;;;;;N;;;;; +0C0F;TELUGU LETTER EE;Lo;0;L;;;;;N;;;;; +0C10;TELUGU LETTER AI;Lo;0;L;;;;;N;;;;; +0C12;TELUGU LETTER O;Lo;0;L;;;;;N;;;;; +0C13;TELUGU LETTER OO;Lo;0;L;;;;;N;;;;; +0C14;TELUGU LETTER AU;Lo;0;L;;;;;N;;;;; +0C15;TELUGU LETTER KA;Lo;0;L;;;;;N;;;;; +0C16;TELUGU LETTER KHA;Lo;0;L;;;;;N;;;;; +0C17;TELUGU LETTER GA;Lo;0;L;;;;;N;;;;; +0C18;TELUGU LETTER GHA;Lo;0;L;;;;;N;;;;; +0C19;TELUGU LETTER NGA;Lo;0;L;;;;;N;;;;; +0C1A;TELUGU LETTER CA;Lo;0;L;;;;;N;;;;; +0C1B;TELUGU LETTER CHA;Lo;0;L;;;;;N;;;;; +0C1C;TELUGU LETTER JA;Lo;0;L;;;;;N;;;;; +0C1D;TELUGU LETTER JHA;Lo;0;L;;;;;N;;;;; +0C1E;TELUGU LETTER NYA;Lo;0;L;;;;;N;;;;; +0C1F;TELUGU LETTER TTA;Lo;0;L;;;;;N;;;;; +0C20;TELUGU LETTER TTHA;Lo;0;L;;;;;N;;;;; +0C21;TELUGU LETTER DDA;Lo;0;L;;;;;N;;;;; +0C22;TELUGU LETTER DDHA;Lo;0;L;;;;;N;;;;; +0C23;TELUGU LETTER NNA;Lo;0;L;;;;;N;;;;; +0C24;TELUGU LETTER TA;Lo;0;L;;;;;N;;;;; +0C25;TELUGU LETTER THA;Lo;0;L;;;;;N;;;;; +0C26;TELUGU LETTER DA;Lo;0;L;;;;;N;;;;; +0C27;TELUGU LETTER DHA;Lo;0;L;;;;;N;;;;; +0C28;TELUGU LETTER NA;Lo;0;L;;;;;N;;;;; +0C2A;TELUGU LETTER PA;Lo;0;L;;;;;N;;;;; +0C2B;TELUGU LETTER PHA;Lo;0;L;;;;;N;;;;; +0C2C;TELUGU LETTER BA;Lo;0;L;;;;;N;;;;; +0C2D;TELUGU LETTER BHA;Lo;0;L;;;;;N;;;;; +0C2E;TELUGU LETTER MA;Lo;0;L;;;;;N;;;;; +0C2F;TELUGU LETTER YA;Lo;0;L;;;;;N;;;;; +0C30;TELUGU LETTER RA;Lo;0;L;;;;;N;;;;; +0C31;TELUGU LETTER RRA;Lo;0;L;;;;;N;;;;; +0C32;TELUGU LETTER LA;Lo;0;L;;;;;N;;;;; +0C33;TELUGU LETTER LLA;Lo;0;L;;;;;N;;;;; +0C34;TELUGU LETTER LLLA;Lo;0;L;;;;;N;;;;; +0C35;TELUGU LETTER VA;Lo;0;L;;;;;N;;;;; +0C36;TELUGU LETTER SHA;Lo;0;L;;;;;N;;;;; +0C37;TELUGU LETTER SSA;Lo;0;L;;;;;N;;;;; +0C38;TELUGU LETTER SA;Lo;0;L;;;;;N;;;;; +0C39;TELUGU LETTER HA;Lo;0;L;;;;;N;;;;; +0C3C;TELUGU SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +0C3D;TELUGU SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +0C3E;TELUGU VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; +0C3F;TELUGU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +0C40;TELUGU VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +0C41;TELUGU VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +0C42;TELUGU VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +0C43;TELUGU VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; +0C44;TELUGU VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; +0C46;TELUGU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +0C47;TELUGU VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;; +0C48;TELUGU VOWEL SIGN AI;Mn;0;NSM;0C46 0C56;;;;N;;;;; +0C4A;TELUGU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +0C4B;TELUGU VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;; +0C4C;TELUGU VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +0C4D;TELUGU SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0C55;TELUGU LENGTH MARK;Mn;84;NSM;;;;;N;;;;; +0C56;TELUGU AI LENGTH MARK;Mn;91;NSM;;;;;N;;;;; +0C58;TELUGU LETTER TSA;Lo;0;L;;;;;N;;;;; +0C59;TELUGU LETTER DZA;Lo;0;L;;;;;N;;;;; +0C5A;TELUGU LETTER RRRA;Lo;0;L;;;;;N;;;;; +0C5C;TELUGU ARCHAIC SHRII;Lo;0;L;;;;;N;;;;; +0C5D;TELUGU LETTER NAKAARA POLLU;Lo;0;L;;;;;N;;;;; +0C60;TELUGU LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0C61;TELUGU LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0C62;TELUGU VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +0C63;TELUGU VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +0C66;TELUGU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0C67;TELUGU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0C68;TELUGU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0C69;TELUGU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0C6A;TELUGU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0C6B;TELUGU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0C6C;TELUGU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0C6D;TELUGU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0C6E;TELUGU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0C6F;TELUGU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0C77;TELUGU SIGN SIDDHAM;Po;0;L;;;;;N;;;;; +0C78;TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR;No;0;ON;;;;0;N;;;;; +0C79;TELUGU FRACTION DIGIT ONE FOR ODD POWERS OF FOUR;No;0;ON;;;;1;N;;;;; +0C7A;TELUGU FRACTION DIGIT TWO FOR ODD POWERS OF FOUR;No;0;ON;;;;2;N;;;;; +0C7B;TELUGU FRACTION DIGIT THREE FOR ODD POWERS OF FOUR;No;0;ON;;;;3;N;;;;; +0C7C;TELUGU FRACTION DIGIT ONE FOR EVEN POWERS OF FOUR;No;0;ON;;;;1;N;;;;; +0C7D;TELUGU FRACTION DIGIT TWO FOR EVEN POWERS OF FOUR;No;0;ON;;;;2;N;;;;; +0C7E;TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR;No;0;ON;;;;3;N;;;;; +0C7F;TELUGU SIGN TUUMU;So;0;L;;;;;N;;;;; +0C80;KANNADA SIGN SPACING CANDRABINDU;Lo;0;L;;;;;N;;;;; +0C81;KANNADA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0C84;KANNADA SIGN SIDDHAM;Po;0;L;;;;;N;;;;; +0C85;KANNADA LETTER A;Lo;0;L;;;;;N;;;;; +0C86;KANNADA LETTER AA;Lo;0;L;;;;;N;;;;; +0C87;KANNADA LETTER I;Lo;0;L;;;;;N;;;;; +0C88;KANNADA LETTER II;Lo;0;L;;;;;N;;;;; +0C89;KANNADA LETTER U;Lo;0;L;;;;;N;;;;; +0C8A;KANNADA LETTER UU;Lo;0;L;;;;;N;;;;; +0C8B;KANNADA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +0C8C;KANNADA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +0C8E;KANNADA LETTER E;Lo;0;L;;;;;N;;;;; +0C8F;KANNADA LETTER EE;Lo;0;L;;;;;N;;;;; +0C90;KANNADA LETTER AI;Lo;0;L;;;;;N;;;;; +0C92;KANNADA LETTER O;Lo;0;L;;;;;N;;;;; +0C93;KANNADA LETTER OO;Lo;0;L;;;;;N;;;;; +0C94;KANNADA LETTER AU;Lo;0;L;;;;;N;;;;; +0C95;KANNADA LETTER KA;Lo;0;L;;;;;N;;;;; +0C96;KANNADA LETTER KHA;Lo;0;L;;;;;N;;;;; +0C97;KANNADA LETTER GA;Lo;0;L;;;;;N;;;;; +0C98;KANNADA LETTER GHA;Lo;0;L;;;;;N;;;;; +0C99;KANNADA LETTER NGA;Lo;0;L;;;;;N;;;;; +0C9A;KANNADA LETTER CA;Lo;0;L;;;;;N;;;;; +0C9B;KANNADA LETTER CHA;Lo;0;L;;;;;N;;;;; +0C9C;KANNADA LETTER JA;Lo;0;L;;;;;N;;;;; +0C9D;KANNADA LETTER JHA;Lo;0;L;;;;;N;;;;; +0C9E;KANNADA LETTER NYA;Lo;0;L;;;;;N;;;;; +0C9F;KANNADA LETTER TTA;Lo;0;L;;;;;N;;;;; +0CA0;KANNADA LETTER TTHA;Lo;0;L;;;;;N;;;;; +0CA1;KANNADA LETTER DDA;Lo;0;L;;;;;N;;;;; +0CA2;KANNADA LETTER DDHA;Lo;0;L;;;;;N;;;;; +0CA3;KANNADA LETTER NNA;Lo;0;L;;;;;N;;;;; +0CA4;KANNADA LETTER TA;Lo;0;L;;;;;N;;;;; +0CA5;KANNADA LETTER THA;Lo;0;L;;;;;N;;;;; +0CA6;KANNADA LETTER DA;Lo;0;L;;;;;N;;;;; +0CA7;KANNADA LETTER DHA;Lo;0;L;;;;;N;;;;; +0CA8;KANNADA LETTER NA;Lo;0;L;;;;;N;;;;; +0CAA;KANNADA LETTER PA;Lo;0;L;;;;;N;;;;; +0CAB;KANNADA LETTER PHA;Lo;0;L;;;;;N;;;;; +0CAC;KANNADA LETTER BA;Lo;0;L;;;;;N;;;;; +0CAD;KANNADA LETTER BHA;Lo;0;L;;;;;N;;;;; +0CAE;KANNADA LETTER MA;Lo;0;L;;;;;N;;;;; +0CAF;KANNADA LETTER YA;Lo;0;L;;;;;N;;;;; +0CB0;KANNADA LETTER RA;Lo;0;L;;;;;N;;;;; +0CB1;KANNADA LETTER RRA;Lo;0;L;;;;;N;;;;; +0CB2;KANNADA LETTER LA;Lo;0;L;;;;;N;;;;; +0CB3;KANNADA LETTER LLA;Lo;0;L;;;;;N;;;;; +0CB5;KANNADA LETTER VA;Lo;0;L;;;;;N;;;;; +0CB6;KANNADA LETTER SHA;Lo;0;L;;;;;N;;;;; +0CB7;KANNADA LETTER SSA;Lo;0;L;;;;;N;;;;; +0CB8;KANNADA LETTER SA;Lo;0;L;;;;;N;;;;; +0CB9;KANNADA LETTER HA;Lo;0;L;;;;;N;;;;; +0CBC;KANNADA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +0CBD;KANNADA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +0CBE;KANNADA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0CBF;KANNADA VOWEL SIGN I;Mn;0;L;;;;;N;;;;; +0CC0;KANNADA VOWEL SIGN II;Mc;0;L;0CBF 0CD5;;;;N;;;;; +0CC1;KANNADA VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +0CC2;KANNADA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +0CC3;KANNADA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; +0CC4;KANNADA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; +0CC6;KANNADA VOWEL SIGN E;Mn;0;L;;;;;N;;;;; +0CC7;KANNADA VOWEL SIGN EE;Mc;0;L;0CC6 0CD5;;;;N;;;;; +0CC8;KANNADA VOWEL SIGN AI;Mc;0;L;0CC6 0CD6;;;;N;;;;; +0CCA;KANNADA VOWEL SIGN O;Mc;0;L;0CC6 0CC2;;;;N;;;;; +0CCB;KANNADA VOWEL SIGN OO;Mc;0;L;0CCA 0CD5;;;;N;;;;; +0CCC;KANNADA VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +0CCD;KANNADA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0CD5;KANNADA LENGTH MARK;Mc;0;L;;;;;N;;;;; +0CD6;KANNADA AI LENGTH MARK;Mc;0;L;;;;;N;;;;; +0CDC;KANNADA ARCHAIC SHRII;Lo;0;L;;;;;N;;;;; +0CDD;KANNADA LETTER NAKAARA POLLU;Lo;0;L;;;;;N;;;;; +0CDE;KANNADA LETTER FA;Lo;0;L;;;;;N;;;;; +0CE0;KANNADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0CE1;KANNADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0CE2;KANNADA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +0CE3;KANNADA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +0CE6;KANNADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0CE7;KANNADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0CE8;KANNADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0CE9;KANNADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0CEA;KANNADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0CEB;KANNADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0CEC;KANNADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0CED;KANNADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0CEE;KANNADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0CF1;KANNADA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; +0CF2;KANNADA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; +0CF3;KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT;Mc;0;L;;;;;N;;;;; +0D00;MALAYALAM SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;; +0D01;MALAYALAM SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +0D03;MALAYALAM SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0D04;MALAYALAM LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;; +0D05;MALAYALAM LETTER A;Lo;0;L;;;;;N;;;;; +0D06;MALAYALAM LETTER AA;Lo;0;L;;;;;N;;;;; +0D07;MALAYALAM LETTER I;Lo;0;L;;;;;N;;;;; +0D08;MALAYALAM LETTER II;Lo;0;L;;;;;N;;;;; +0D09;MALAYALAM LETTER U;Lo;0;L;;;;;N;;;;; +0D0A;MALAYALAM LETTER UU;Lo;0;L;;;;;N;;;;; +0D0B;MALAYALAM LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +0D0C;MALAYALAM LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +0D0E;MALAYALAM LETTER E;Lo;0;L;;;;;N;;;;; +0D0F;MALAYALAM LETTER EE;Lo;0;L;;;;;N;;;;; +0D10;MALAYALAM LETTER AI;Lo;0;L;;;;;N;;;;; +0D12;MALAYALAM LETTER O;Lo;0;L;;;;;N;;;;; +0D13;MALAYALAM LETTER OO;Lo;0;L;;;;;N;;;;; +0D14;MALAYALAM LETTER AU;Lo;0;L;;;;;N;;;;; +0D15;MALAYALAM LETTER KA;Lo;0;L;;;;;N;;;;; +0D16;MALAYALAM LETTER KHA;Lo;0;L;;;;;N;;;;; +0D17;MALAYALAM LETTER GA;Lo;0;L;;;;;N;;;;; +0D18;MALAYALAM LETTER GHA;Lo;0;L;;;;;N;;;;; +0D19;MALAYALAM LETTER NGA;Lo;0;L;;;;;N;;;;; +0D1A;MALAYALAM LETTER CA;Lo;0;L;;;;;N;;;;; +0D1B;MALAYALAM LETTER CHA;Lo;0;L;;;;;N;;;;; +0D1C;MALAYALAM LETTER JA;Lo;0;L;;;;;N;;;;; +0D1D;MALAYALAM LETTER JHA;Lo;0;L;;;;;N;;;;; +0D1E;MALAYALAM LETTER NYA;Lo;0;L;;;;;N;;;;; +0D1F;MALAYALAM LETTER TTA;Lo;0;L;;;;;N;;;;; +0D20;MALAYALAM LETTER TTHA;Lo;0;L;;;;;N;;;;; +0D21;MALAYALAM LETTER DDA;Lo;0;L;;;;;N;;;;; +0D22;MALAYALAM LETTER DDHA;Lo;0;L;;;;;N;;;;; +0D23;MALAYALAM LETTER NNA;Lo;0;L;;;;;N;;;;; +0D24;MALAYALAM LETTER TA;Lo;0;L;;;;;N;;;;; +0D25;MALAYALAM LETTER THA;Lo;0;L;;;;;N;;;;; +0D26;MALAYALAM LETTER DA;Lo;0;L;;;;;N;;;;; +0D27;MALAYALAM LETTER DHA;Lo;0;L;;;;;N;;;;; +0D28;MALAYALAM LETTER NA;Lo;0;L;;;;;N;;;;; +0D29;MALAYALAM LETTER NNNA;Lo;0;L;;;;;N;;;;; +0D2A;MALAYALAM LETTER PA;Lo;0;L;;;;;N;;;;; +0D2B;MALAYALAM LETTER PHA;Lo;0;L;;;;;N;;;;; +0D2C;MALAYALAM LETTER BA;Lo;0;L;;;;;N;;;;; +0D2D;MALAYALAM LETTER BHA;Lo;0;L;;;;;N;;;;; +0D2E;MALAYALAM LETTER MA;Lo;0;L;;;;;N;;;;; +0D2F;MALAYALAM LETTER YA;Lo;0;L;;;;;N;;;;; +0D30;MALAYALAM LETTER RA;Lo;0;L;;;;;N;;;;; +0D31;MALAYALAM LETTER RRA;Lo;0;L;;;;;N;;;;; +0D32;MALAYALAM LETTER LA;Lo;0;L;;;;;N;;;;; +0D33;MALAYALAM LETTER LLA;Lo;0;L;;;;;N;;;;; +0D34;MALAYALAM LETTER LLLA;Lo;0;L;;;;;N;;;;; +0D35;MALAYALAM LETTER VA;Lo;0;L;;;;;N;;;;; +0D36;MALAYALAM LETTER SHA;Lo;0;L;;;;;N;;;;; +0D37;MALAYALAM LETTER SSA;Lo;0;L;;;;;N;;;;; +0D38;MALAYALAM LETTER SA;Lo;0;L;;;;;N;;;;; +0D39;MALAYALAM LETTER HA;Lo;0;L;;;;;N;;;;; +0D3A;MALAYALAM LETTER TTTA;Lo;0;L;;;;;N;;;;; +0D3B;MALAYALAM SIGN VERTICAL BAR VIRAMA;Mn;9;NSM;;;;;N;;;;; +0D3C;MALAYALAM SIGN CIRCULAR VIRAMA;Mn;9;NSM;;;;;N;;;;; +0D3D;MALAYALAM SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +0D3E;MALAYALAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0D3F;MALAYALAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +0D40;MALAYALAM VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +0D41;MALAYALAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +0D42;MALAYALAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +0D43;MALAYALAM VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +0D44;MALAYALAM VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +0D46;MALAYALAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +0D47;MALAYALAM VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; +0D48;MALAYALAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +0D4A;MALAYALAM VOWEL SIGN O;Mc;0;L;0D46 0D3E;;;;N;;;;; +0D4B;MALAYALAM VOWEL SIGN OO;Mc;0;L;0D47 0D3E;;;;N;;;;; +0D4C;MALAYALAM VOWEL SIGN AU;Mc;0;L;0D46 0D57;;;;N;;;;; +0D4D;MALAYALAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0D4E;MALAYALAM LETTER DOT REPH;Lo;0;L;;;;;N;;;;; +0D4F;MALAYALAM SIGN PARA;So;0;L;;;;;N;;;;; +0D54;MALAYALAM LETTER CHILLU M;Lo;0;L;;;;;N;;;;; +0D55;MALAYALAM LETTER CHILLU Y;Lo;0;L;;;;;N;;;;; +0D56;MALAYALAM LETTER CHILLU LLL;Lo;0;L;;;;;N;;;;; +0D57;MALAYALAM AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +0D58;MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH;No;0;L;;;;1/160;N;;;;; +0D59;MALAYALAM FRACTION ONE FORTIETH;No;0;L;;;;1/40;N;;;;; +0D5A;MALAYALAM FRACTION THREE EIGHTIETHS;No;0;L;;;;3/80;N;;;;; +0D5B;MALAYALAM FRACTION ONE TWENTIETH;No;0;L;;;;1/20;N;;;;; +0D5C;MALAYALAM FRACTION ONE TENTH;No;0;L;;;;1/10;N;;;;; +0D5D;MALAYALAM FRACTION THREE TWENTIETHS;No;0;L;;;;3/20;N;;;;; +0D5E;MALAYALAM FRACTION ONE FIFTH;No;0;L;;;;1/5;N;;;;; +0D5F;MALAYALAM LETTER ARCHAIC II;Lo;0;L;;;;;N;;;;; +0D60;MALAYALAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0D61;MALAYALAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0D62;MALAYALAM VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +0D63;MALAYALAM VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +0D66;MALAYALAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0D67;MALAYALAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0D68;MALAYALAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0D69;MALAYALAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0D6A;MALAYALAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0D6B;MALAYALAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0D6C;MALAYALAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0D6D;MALAYALAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0D6E;MALAYALAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0D6F;MALAYALAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0D70;MALAYALAM NUMBER TEN;No;0;L;;;;10;N;;;;; +0D71;MALAYALAM NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;; +0D72;MALAYALAM NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;; +0D73;MALAYALAM FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;; +0D74;MALAYALAM FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;; +0D75;MALAYALAM FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;; +0D76;MALAYALAM FRACTION ONE SIXTEENTH;No;0;L;;;;1/16;N;;;;; +0D77;MALAYALAM FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;; +0D78;MALAYALAM FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;; +0D79;MALAYALAM DATE MARK;So;0;L;;;;;N;;;;; +0D7A;MALAYALAM LETTER CHILLU NN;Lo;0;L;;;;;N;;;;; +0D7B;MALAYALAM LETTER CHILLU N;Lo;0;L;;;;;N;;;;; +0D7C;MALAYALAM LETTER CHILLU RR;Lo;0;L;;;;;N;;;;; +0D7D;MALAYALAM LETTER CHILLU L;Lo;0;L;;;;;N;;;;; +0D7E;MALAYALAM LETTER CHILLU LL;Lo;0;L;;;;;N;;;;; +0D7F;MALAYALAM LETTER CHILLU K;Lo;0;L;;;;;N;;;;; +0D81;SINHALA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +0D82;SINHALA SIGN ANUSVARAYA;Mc;0;L;;;;;N;;;;; +0D83;SINHALA SIGN VISARGAYA;Mc;0;L;;;;;N;;;;; +0D85;SINHALA LETTER AYANNA;Lo;0;L;;;;;N;;;;; +0D86;SINHALA LETTER AAYANNA;Lo;0;L;;;;;N;;;;; +0D87;SINHALA LETTER AEYANNA;Lo;0;L;;;;;N;;;;; +0D88;SINHALA LETTER AEEYANNA;Lo;0;L;;;;;N;;;;; +0D89;SINHALA LETTER IYANNA;Lo;0;L;;;;;N;;;;; +0D8A;SINHALA LETTER IIYANNA;Lo;0;L;;;;;N;;;;; +0D8B;SINHALA LETTER UYANNA;Lo;0;L;;;;;N;;;;; +0D8C;SINHALA LETTER UUYANNA;Lo;0;L;;;;;N;;;;; +0D8D;SINHALA LETTER IRUYANNA;Lo;0;L;;;;;N;;;;; +0D8E;SINHALA LETTER IRUUYANNA;Lo;0;L;;;;;N;;;;; +0D8F;SINHALA LETTER ILUYANNA;Lo;0;L;;;;;N;;;;; +0D90;SINHALA LETTER ILUUYANNA;Lo;0;L;;;;;N;;;;; +0D91;SINHALA LETTER EYANNA;Lo;0;L;;;;;N;;;;; +0D92;SINHALA LETTER EEYANNA;Lo;0;L;;;;;N;;;;; +0D93;SINHALA LETTER AIYANNA;Lo;0;L;;;;;N;;;;; +0D94;SINHALA LETTER OYANNA;Lo;0;L;;;;;N;;;;; +0D95;SINHALA LETTER OOYANNA;Lo;0;L;;;;;N;;;;; +0D96;SINHALA LETTER AUYANNA;Lo;0;L;;;;;N;;;;; +0D9A;SINHALA LETTER ALPAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;; +0D9B;SINHALA LETTER MAHAAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;; +0D9C;SINHALA LETTER ALPAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;; +0D9D;SINHALA LETTER MAHAAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;; +0D9E;SINHALA LETTER KANTAJA NAASIKYAYA;Lo;0;L;;;;;N;;;;; +0D9F;SINHALA LETTER SANYAKA GAYANNA;Lo;0;L;;;;;N;;;;; +0DA0;SINHALA LETTER ALPAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;; +0DA1;SINHALA LETTER MAHAAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;; +0DA2;SINHALA LETTER ALPAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;; +0DA3;SINHALA LETTER MAHAAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;; +0DA4;SINHALA LETTER TAALUJA NAASIKYAYA;Lo;0;L;;;;;N;;;;; +0DA5;SINHALA LETTER TAALUJA SANYOOGA NAAKSIKYAYA;Lo;0;L;;;;;N;;;;; +0DA6;SINHALA LETTER SANYAKA JAYANNA;Lo;0;L;;;;;N;;;;; +0DA7;SINHALA LETTER ALPAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;; +0DA8;SINHALA LETTER MAHAAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;; +0DA9;SINHALA LETTER ALPAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;; +0DAA;SINHALA LETTER MAHAAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;; +0DAB;SINHALA LETTER MUURDHAJA NAYANNA;Lo;0;L;;;;;N;;;;; +0DAC;SINHALA LETTER SANYAKA DDAYANNA;Lo;0;L;;;;;N;;;;; +0DAD;SINHALA LETTER ALPAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;; +0DAE;SINHALA LETTER MAHAAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;; +0DAF;SINHALA LETTER ALPAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;; +0DB0;SINHALA LETTER MAHAAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;; +0DB1;SINHALA LETTER DANTAJA NAYANNA;Lo;0;L;;;;;N;;;;; +0DB3;SINHALA LETTER SANYAKA DAYANNA;Lo;0;L;;;;;N;;;;; +0DB4;SINHALA LETTER ALPAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;; +0DB5;SINHALA LETTER MAHAAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;; +0DB6;SINHALA LETTER ALPAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;; +0DB7;SINHALA LETTER MAHAAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;; +0DB8;SINHALA LETTER MAYANNA;Lo;0;L;;;;;N;;;;; +0DB9;SINHALA LETTER AMBA BAYANNA;Lo;0;L;;;;;N;;;;; +0DBA;SINHALA LETTER YAYANNA;Lo;0;L;;;;;N;;;;; +0DBB;SINHALA LETTER RAYANNA;Lo;0;L;;;;;N;;;;; +0DBD;SINHALA LETTER DANTAJA LAYANNA;Lo;0;L;;;;;N;;;;; +0DC0;SINHALA LETTER VAYANNA;Lo;0;L;;;;;N;;;;; +0DC1;SINHALA LETTER TAALUJA SAYANNA;Lo;0;L;;;;;N;;;;; +0DC2;SINHALA LETTER MUURDHAJA SAYANNA;Lo;0;L;;;;;N;;;;; +0DC3;SINHALA LETTER DANTAJA SAYANNA;Lo;0;L;;;;;N;;;;; +0DC4;SINHALA LETTER HAYANNA;Lo;0;L;;;;;N;;;;; +0DC5;SINHALA LETTER MUURDHAJA LAYANNA;Lo;0;L;;;;;N;;;;; +0DC6;SINHALA LETTER FAYANNA;Lo;0;L;;;;;N;;;;; +0DCA;SINHALA SIGN AL-LAKUNA;Mn;9;NSM;;;;;N;;;;; +0DCF;SINHALA VOWEL SIGN AELA-PILLA;Mc;0;L;;;;;N;;;;; +0DD0;SINHALA VOWEL SIGN KETTI AEDA-PILLA;Mc;0;L;;;;;N;;;;; +0DD1;SINHALA VOWEL SIGN DIGA AEDA-PILLA;Mc;0;L;;;;;N;;;;; +0DD2;SINHALA VOWEL SIGN KETTI IS-PILLA;Mn;0;NSM;;;;;N;;;;; +0DD3;SINHALA VOWEL SIGN DIGA IS-PILLA;Mn;0;NSM;;;;;N;;;;; +0DD4;SINHALA VOWEL SIGN KETTI PAA-PILLA;Mn;0;NSM;;;;;N;;;;; +0DD6;SINHALA VOWEL SIGN DIGA PAA-PILLA;Mn;0;NSM;;;;;N;;;;; +0DD8;SINHALA VOWEL SIGN GAETTA-PILLA;Mc;0;L;;;;;N;;;;; +0DD9;SINHALA VOWEL SIGN KOMBUVA;Mc;0;L;;;;;N;;;;; +0DDA;SINHALA VOWEL SIGN DIGA KOMBUVA;Mc;0;L;0DD9 0DCA;;;;N;;;;; +0DDB;SINHALA VOWEL SIGN KOMBU DEKA;Mc;0;L;;;;;N;;;;; +0DDC;SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA;Mc;0;L;0DD9 0DCF;;;;N;;;;; +0DDD;SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA;Mc;0;L;0DDC 0DCA;;;;N;;;;; +0DDE;SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA;Mc;0;L;0DD9 0DDF;;;;N;;;;; +0DDF;SINHALA VOWEL SIGN GAYANUKITTA;Mc;0;L;;;;;N;;;;; +0DE6;SINHALA LITH DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0DE7;SINHALA LITH DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0DE8;SINHALA LITH DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0DE9;SINHALA LITH DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0DEA;SINHALA LITH DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0DEB;SINHALA LITH DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0DEC;SINHALA LITH DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0DED;SINHALA LITH DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0DEE;SINHALA LITH DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0DEF;SINHALA LITH DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0DF2;SINHALA VOWEL SIGN DIGA GAETTA-PILLA;Mc;0;L;;;;;N;;;;; +0DF3;SINHALA VOWEL SIGN DIGA GAYANUKITTA;Mc;0;L;;;;;N;;;;; +0DF4;SINHALA PUNCTUATION KUNDDALIYA;Po;0;L;;;;;N;;;;; +0E01;THAI CHARACTER KO KAI;Lo;0;L;;;;;N;THAI LETTER KO KAI;;;; +0E02;THAI CHARACTER KHO KHAI;Lo;0;L;;;;;N;THAI LETTER KHO KHAI;;;; +0E03;THAI CHARACTER KHO KHUAT;Lo;0;L;;;;;N;THAI LETTER KHO KHUAT;;;; +0E04;THAI CHARACTER KHO KHWAI;Lo;0;L;;;;;N;THAI LETTER KHO KHWAI;;;; +0E05;THAI CHARACTER KHO KHON;Lo;0;L;;;;;N;THAI LETTER KHO KHON;;;; +0E06;THAI CHARACTER KHO RAKHANG;Lo;0;L;;;;;N;THAI LETTER KHO RAKHANG;;;; +0E07;THAI CHARACTER NGO NGU;Lo;0;L;;;;;N;THAI LETTER NGO NGU;;;; +0E08;THAI CHARACTER CHO CHAN;Lo;0;L;;;;;N;THAI LETTER CHO CHAN;;;; +0E09;THAI CHARACTER CHO CHING;Lo;0;L;;;;;N;THAI LETTER CHO CHING;;;; +0E0A;THAI CHARACTER CHO CHANG;Lo;0;L;;;;;N;THAI LETTER CHO CHANG;;;; +0E0B;THAI CHARACTER SO SO;Lo;0;L;;;;;N;THAI LETTER SO SO;;;; +0E0C;THAI CHARACTER CHO CHOE;Lo;0;L;;;;;N;THAI LETTER CHO CHOE;;;; +0E0D;THAI CHARACTER YO YING;Lo;0;L;;;;;N;THAI LETTER YO YING;;;; +0E0E;THAI CHARACTER DO CHADA;Lo;0;L;;;;;N;THAI LETTER DO CHADA;;;; +0E0F;THAI CHARACTER TO PATAK;Lo;0;L;;;;;N;THAI LETTER TO PATAK;;;; +0E10;THAI CHARACTER THO THAN;Lo;0;L;;;;;N;THAI LETTER THO THAN;;;; +0E11;THAI CHARACTER THO NANGMONTHO;Lo;0;L;;;;;N;THAI LETTER THO NANGMONTHO;;;; +0E12;THAI CHARACTER THO PHUTHAO;Lo;0;L;;;;;N;THAI LETTER THO PHUTHAO;;;; +0E13;THAI CHARACTER NO NEN;Lo;0;L;;;;;N;THAI LETTER NO NEN;;;; +0E14;THAI CHARACTER DO DEK;Lo;0;L;;;;;N;THAI LETTER DO DEK;;;; +0E15;THAI CHARACTER TO TAO;Lo;0;L;;;;;N;THAI LETTER TO TAO;;;; +0E16;THAI CHARACTER THO THUNG;Lo;0;L;;;;;N;THAI LETTER THO THUNG;;;; +0E17;THAI CHARACTER THO THAHAN;Lo;0;L;;;;;N;THAI LETTER THO THAHAN;;;; +0E18;THAI CHARACTER THO THONG;Lo;0;L;;;;;N;THAI LETTER THO THONG;;;; +0E19;THAI CHARACTER NO NU;Lo;0;L;;;;;N;THAI LETTER NO NU;;;; +0E1A;THAI CHARACTER BO BAIMAI;Lo;0;L;;;;;N;THAI LETTER BO BAIMAI;;;; +0E1B;THAI CHARACTER PO PLA;Lo;0;L;;;;;N;THAI LETTER PO PLA;;;; +0E1C;THAI CHARACTER PHO PHUNG;Lo;0;L;;;;;N;THAI LETTER PHO PHUNG;;;; +0E1D;THAI CHARACTER FO FA;Lo;0;L;;;;;N;THAI LETTER FO FA;;;; +0E1E;THAI CHARACTER PHO PHAN;Lo;0;L;;;;;N;THAI LETTER PHO PHAN;;;; +0E1F;THAI CHARACTER FO FAN;Lo;0;L;;;;;N;THAI LETTER FO FAN;;;; +0E20;THAI CHARACTER PHO SAMPHAO;Lo;0;L;;;;;N;THAI LETTER PHO SAMPHAO;;;; +0E21;THAI CHARACTER MO MA;Lo;0;L;;;;;N;THAI LETTER MO MA;;;; +0E22;THAI CHARACTER YO YAK;Lo;0;L;;;;;N;THAI LETTER YO YAK;;;; +0E23;THAI CHARACTER RO RUA;Lo;0;L;;;;;N;THAI LETTER RO RUA;;;; +0E24;THAI CHARACTER RU;Lo;0;L;;;;;N;THAI LETTER RU;;;; +0E25;THAI CHARACTER LO LING;Lo;0;L;;;;;N;THAI LETTER LO LING;;;; +0E26;THAI CHARACTER LU;Lo;0;L;;;;;N;THAI LETTER LU;;;; +0E27;THAI CHARACTER WO WAEN;Lo;0;L;;;;;N;THAI LETTER WO WAEN;;;; +0E28;THAI CHARACTER SO SALA;Lo;0;L;;;;;N;THAI LETTER SO SALA;;;; +0E29;THAI CHARACTER SO RUSI;Lo;0;L;;;;;N;THAI LETTER SO RUSI;;;; +0E2A;THAI CHARACTER SO SUA;Lo;0;L;;;;;N;THAI LETTER SO SUA;;;; +0E2B;THAI CHARACTER HO HIP;Lo;0;L;;;;;N;THAI LETTER HO HIP;;;; +0E2C;THAI CHARACTER LO CHULA;Lo;0;L;;;;;N;THAI LETTER LO CHULA;;;; +0E2D;THAI CHARACTER O ANG;Lo;0;L;;;;;N;THAI LETTER O ANG;;;; +0E2E;THAI CHARACTER HO NOKHUK;Lo;0;L;;;;;N;THAI LETTER HO NOK HUK;;;; +0E2F;THAI CHARACTER PAIYANNOI;Lo;0;L;;;;;N;THAI PAI YAN NOI;;;; +0E30;THAI CHARACTER SARA A;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA A;;;; +0E31;THAI CHARACTER MAI HAN-AKAT;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI HAN-AKAT;;;; +0E32;THAI CHARACTER SARA AA;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AA;;;; +0E33;THAI CHARACTER SARA AM;Lo;0;L; 0E4D 0E32;;;;N;THAI VOWEL SIGN SARA AM;;;; +0E34;THAI CHARACTER SARA I;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA I;;;; +0E35;THAI CHARACTER SARA II;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA II;;;; +0E36;THAI CHARACTER SARA UE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UE;;;; +0E37;THAI CHARACTER SARA UEE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UEE;;;; +0E38;THAI CHARACTER SARA U;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA U;;;; +0E39;THAI CHARACTER SARA UU;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA UU;;;; +0E3A;THAI CHARACTER PHINTHU;Mn;9;NSM;;;;;N;THAI VOWEL SIGN PHINTHU;;;; +0E3F;THAI CURRENCY SYMBOL BAHT;Sc;0;ET;;;;;N;THAI BAHT SIGN;;;; +0E40;THAI CHARACTER SARA E;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA E;;;; +0E41;THAI CHARACTER SARA AE;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AE;;;; +0E42;THAI CHARACTER SARA O;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA O;;;; +0E43;THAI CHARACTER SARA AI MAIMUAN;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MUAN;;;; +0E44;THAI CHARACTER SARA AI MAIMALAI;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MALAI;;;; +0E45;THAI CHARACTER LAKKHANGYAO;Lo;0;L;;;;;N;THAI LAK KHANG YAO;;;; +0E46;THAI CHARACTER MAIYAMOK;Lm;0;L;;;;;N;THAI MAI YAMOK;;;; +0E47;THAI CHARACTER MAITAIKHU;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI TAI KHU;;;; +0E48;THAI CHARACTER MAI EK;Mn;107;NSM;;;;;N;THAI TONE MAI EK;;;; +0E49;THAI CHARACTER MAI THO;Mn;107;NSM;;;;;N;THAI TONE MAI THO;;;; +0E4A;THAI CHARACTER MAI TRI;Mn;107;NSM;;;;;N;THAI TONE MAI TRI;;;; +0E4B;THAI CHARACTER MAI CHATTAWA;Mn;107;NSM;;;;;N;THAI TONE MAI CHATTAWA;;;; +0E4C;THAI CHARACTER THANTHAKHAT;Mn;0;NSM;;;;;N;THAI THANTHAKHAT;;;; +0E4D;THAI CHARACTER NIKHAHIT;Mn;0;NSM;;;;;N;THAI NIKKHAHIT;;;; +0E4E;THAI CHARACTER YAMAKKAN;Mn;0;NSM;;;;;N;THAI YAMAKKAN;;;; +0E4F;THAI CHARACTER FONGMAN;Po;0;L;;;;;N;THAI FONGMAN;;;; +0E50;THAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0E51;THAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0E52;THAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0E53;THAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0E54;THAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0E55;THAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0E56;THAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0E57;THAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0E58;THAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0E59;THAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0E5A;THAI CHARACTER ANGKHANKHU;Po;0;L;;;;;N;THAI ANGKHANKHU;;;; +0E5B;THAI CHARACTER KHOMUT;Po;0;L;;;;;N;THAI KHOMUT;;;; +0E81;LAO LETTER KO;Lo;0;L;;;;;N;;;;; +0E82;LAO LETTER KHO SUNG;Lo;0;L;;;;;N;;;;; +0E84;LAO LETTER KHO TAM;Lo;0;L;;;;;N;;;;; +0E86;LAO LETTER PALI GHA;Lo;0;L;;;;;N;;;;; +0E87;LAO LETTER NGO;Lo;0;L;;;;;N;;;;; +0E88;LAO LETTER CO;Lo;0;L;;;;;N;;;;; +0E89;LAO LETTER PALI CHA;Lo;0;L;;;;;N;;;;; +0E8A;LAO LETTER SO TAM;Lo;0;L;;;;;N;;;;; +0E8C;LAO LETTER PALI JHA;Lo;0;L;;;;;N;;;;; +0E8D;LAO LETTER NYO;Lo;0;L;;;;;N;;;;; +0E8E;LAO LETTER PALI NYA;Lo;0;L;;;;;N;;;;; +0E8F;LAO LETTER PALI TTA;Lo;0;L;;;;;N;;;;; +0E90;LAO LETTER PALI TTHA;Lo;0;L;;;;;N;;;;; +0E91;LAO LETTER PALI DDA;Lo;0;L;;;;;N;;;;; +0E92;LAO LETTER PALI DDHA;Lo;0;L;;;;;N;;;;; +0E93;LAO LETTER PALI NNA;Lo;0;L;;;;;N;;;;; +0E94;LAO LETTER DO;Lo;0;L;;;;;N;;;;; +0E95;LAO LETTER TO;Lo;0;L;;;;;N;;;;; +0E96;LAO LETTER THO SUNG;Lo;0;L;;;;;N;;;;; +0E97;LAO LETTER THO TAM;Lo;0;L;;;;;N;;;;; +0E98;LAO LETTER PALI DHA;Lo;0;L;;;;;N;;;;; +0E99;LAO LETTER NO;Lo;0;L;;;;;N;;;;; +0E9A;LAO LETTER BO;Lo;0;L;;;;;N;;;;; +0E9B;LAO LETTER PO;Lo;0;L;;;;;N;;;;; +0E9C;LAO LETTER PHO SUNG;Lo;0;L;;;;;N;;;;; +0E9D;LAO LETTER FO TAM;Lo;0;L;;;;;N;;;;; +0E9E;LAO LETTER PHO TAM;Lo;0;L;;;;;N;;;;; +0E9F;LAO LETTER FO SUNG;Lo;0;L;;;;;N;;;;; +0EA0;LAO LETTER PALI BHA;Lo;0;L;;;;;N;;;;; +0EA1;LAO LETTER MO;Lo;0;L;;;;;N;;;;; +0EA2;LAO LETTER YO;Lo;0;L;;;;;N;;;;; +0EA3;LAO LETTER LO LING;Lo;0;L;;;;;N;;;;; +0EA5;LAO LETTER LO LOOT;Lo;0;L;;;;;N;;;;; +0EA7;LAO LETTER WO;Lo;0;L;;;;;N;;;;; +0EA8;LAO LETTER SANSKRIT SHA;Lo;0;L;;;;;N;;;;; +0EA9;LAO LETTER SANSKRIT SSA;Lo;0;L;;;;;N;;;;; +0EAA;LAO LETTER SO SUNG;Lo;0;L;;;;;N;;;;; +0EAB;LAO LETTER HO SUNG;Lo;0;L;;;;;N;;;;; +0EAC;LAO LETTER PALI LLA;Lo;0;L;;;;;N;;;;; +0EAD;LAO LETTER O;Lo;0;L;;;;;N;;;;; +0EAE;LAO LETTER HO TAM;Lo;0;L;;;;;N;;;;; +0EAF;LAO ELLIPSIS;Lo;0;L;;;;;N;;;;; +0EB0;LAO VOWEL SIGN A;Lo;0;L;;;;;N;;;;; +0EB1;LAO VOWEL SIGN MAI KAN;Mn;0;NSM;;;;;N;;;;; +0EB2;LAO VOWEL SIGN AA;Lo;0;L;;;;;N;;;;; +0EB3;LAO VOWEL SIGN AM;Lo;0;L; 0ECD 0EB2;;;;N;;;;; +0EB4;LAO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +0EB5;LAO VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +0EB6;LAO VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;; +0EB7;LAO VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;; +0EB8;LAO VOWEL SIGN U;Mn;118;NSM;;;;;N;;;;; +0EB9;LAO VOWEL SIGN UU;Mn;118;NSM;;;;;N;;;;; +0EBA;LAO SIGN PALI VIRAMA;Mn;9;NSM;;;;;N;;;;; +0EBB;LAO VOWEL SIGN MAI KON;Mn;0;NSM;;;;;N;;;;; +0EBC;LAO SEMIVOWEL SIGN LO;Mn;0;NSM;;;;;N;;;;; +0EBD;LAO SEMIVOWEL SIGN NYO;Lo;0;L;;;;;N;;;;; +0EC0;LAO VOWEL SIGN E;Lo;0;L;;;;;N;;;;; +0EC1;LAO VOWEL SIGN EI;Lo;0;L;;;;;N;;;;; +0EC2;LAO VOWEL SIGN O;Lo;0;L;;;;;N;;;;; +0EC3;LAO VOWEL SIGN AY;Lo;0;L;;;;;N;;;;; +0EC4;LAO VOWEL SIGN AI;Lo;0;L;;;;;N;;;;; +0EC6;LAO KO LA;Lm;0;L;;;;;N;;;;; +0EC8;LAO TONE MAI EK;Mn;122;NSM;;;;;N;;;;; +0EC9;LAO TONE MAI THO;Mn;122;NSM;;;;;N;;;;; +0ECA;LAO TONE MAI TI;Mn;122;NSM;;;;;N;;;;; +0ECB;LAO TONE MAI CATAWA;Mn;122;NSM;;;;;N;;;;; +0ECC;LAO CANCELLATION MARK;Mn;0;NSM;;;;;N;;;;; +0ECD;LAO NIGGAHITA;Mn;0;NSM;;;;;N;;;;; +0ECE;LAO YAMAKKAN;Mn;0;NSM;;;;;N;;;;; +0ED0;LAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0ED1;LAO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0ED2;LAO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0ED3;LAO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0ED4;LAO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0ED5;LAO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0ED6;LAO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0ED7;LAO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0ED8;LAO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0ED9;LAO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0EDC;LAO HO NO;Lo;0;L; 0EAB 0E99;;;;N;;;;; +0EDD;LAO HO MO;Lo;0;L; 0EAB 0EA1;;;;N;;;;; +0EDE;LAO LETTER KHMU GO;Lo;0;L;;;;;N;;;;; +0EDF;LAO LETTER KHMU NYO;Lo;0;L;;;;;N;;;;; +0F00;TIBETAN SYLLABLE OM;Lo;0;L;;;;;N;;;;; +0F01;TIBETAN MARK GTER YIG MGO TRUNCATED A;So;0;L;;;;;N;;;;; +0F02;TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA;So;0;L;;;;;N;;;;; +0F03;TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA;So;0;L;;;;;N;;;;; +0F04;TIBETAN MARK INITIAL YIG MGO MDUN MA;Po;0;L;;;;;N;TIBETAN SINGLE ORNAMENT;;;; +0F05;TIBETAN MARK CLOSING YIG MGO SGAB MA;Po;0;L;;;;;N;;;;; +0F06;TIBETAN MARK CARET YIG MGO PHUR SHAD MA;Po;0;L;;;;;N;;;;; +0F07;TIBETAN MARK YIG MGO TSHEG SHAD MA;Po;0;L;;;;;N;;;;; +0F08;TIBETAN MARK SBRUL SHAD;Po;0;L;;;;;N;TIBETAN RGYANSHAD;;;; +0F09;TIBETAN MARK BSKUR YIG MGO;Po;0;L;;;;;N;;;;; +0F0A;TIBETAN MARK BKA- SHOG YIG MGO;Po;0;L;;;;;N;;;;; +0F0B;TIBETAN MARK INTERSYLLABIC TSHEG;Po;0;L;;;;;N;TIBETAN TSEG;;;; +0F0C;TIBETAN MARK DELIMITER TSHEG BSTAR;Po;0;L; 0F0B;;;;N;;;;; +0F0D;TIBETAN MARK SHAD;Po;0;L;;;;;N;TIBETAN SHAD;;;; +0F0E;TIBETAN MARK NYIS SHAD;Po;0;L;;;;;N;TIBETAN DOUBLE SHAD;;;; +0F0F;TIBETAN MARK TSHEG SHAD;Po;0;L;;;;;N;;;;; +0F10;TIBETAN MARK NYIS TSHEG SHAD;Po;0;L;;;;;N;;;;; +0F11;TIBETAN MARK RIN CHEN SPUNGS SHAD;Po;0;L;;;;;N;TIBETAN RINCHANPHUNGSHAD;;;; +0F12;TIBETAN MARK RGYA GRAM SHAD;Po;0;L;;;;;N;;;;; +0F13;TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN;So;0;L;;;;;N;;;;; +0F14;TIBETAN MARK GTER TSHEG;Po;0;L;;;;;N;TIBETAN COMMA;;;; +0F15;TIBETAN LOGOTYPE SIGN CHAD RTAGS;So;0;L;;;;;N;;;;; +0F16;TIBETAN LOGOTYPE SIGN LHAG RTAGS;So;0;L;;;;;N;;;;; +0F17;TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS;So;0;L;;;;;N;;;;; +0F18;TIBETAN ASTROLOGICAL SIGN -KHYUD PA;Mn;220;NSM;;;;;N;;;;; +0F19;TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS;Mn;220;NSM;;;;;N;;;;; +0F1A;TIBETAN SIGN RDEL DKAR GCIG;So;0;L;;;;;N;;;;; +0F1B;TIBETAN SIGN RDEL DKAR GNYIS;So;0;L;;;;;N;;;;; +0F1C;TIBETAN SIGN RDEL DKAR GSUM;So;0;L;;;;;N;;;;; +0F1D;TIBETAN SIGN RDEL NAG GCIG;So;0;L;;;;;N;;;;; +0F1E;TIBETAN SIGN RDEL NAG GNYIS;So;0;L;;;;;N;;;;; +0F1F;TIBETAN SIGN RDEL DKAR RDEL NAG;So;0;L;;;;;N;;;;; +0F20;TIBETAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0F21;TIBETAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0F22;TIBETAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0F23;TIBETAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0F24;TIBETAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0F25;TIBETAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0F26;TIBETAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0F27;TIBETAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0F28;TIBETAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0F29;TIBETAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0F2A;TIBETAN DIGIT HALF ONE;No;0;L;;;;1/2;N;;;;; +0F2B;TIBETAN DIGIT HALF TWO;No;0;L;;;;3/2;N;;;;; +0F2C;TIBETAN DIGIT HALF THREE;No;0;L;;;;5/2;N;;;;; +0F2D;TIBETAN DIGIT HALF FOUR;No;0;L;;;;7/2;N;;;;; +0F2E;TIBETAN DIGIT HALF FIVE;No;0;L;;;;9/2;N;;;;; +0F2F;TIBETAN DIGIT HALF SIX;No;0;L;;;;11/2;N;;;;; +0F30;TIBETAN DIGIT HALF SEVEN;No;0;L;;;;13/2;N;;;;; +0F31;TIBETAN DIGIT HALF EIGHT;No;0;L;;;;15/2;N;;;;; +0F32;TIBETAN DIGIT HALF NINE;No;0;L;;;;17/2;N;;;;; +0F33;TIBETAN DIGIT HALF ZERO;No;0;L;;;;-1/2;N;;;;; +0F34;TIBETAN MARK BSDUS RTAGS;So;0;L;;;;;N;;;;; +0F35;TIBETAN MARK NGAS BZUNG NYI ZLA;Mn;220;NSM;;;;;N;TIBETAN HONORIFIC UNDER RING;;;; +0F36;TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN;So;0;L;;;;;N;;;;; +0F37;TIBETAN MARK NGAS BZUNG SGOR RTAGS;Mn;220;NSM;;;;;N;TIBETAN UNDER RING;;;; +0F38;TIBETAN MARK CHE MGO;So;0;L;;;;;N;;;;; +0F39;TIBETAN MARK TSA -PHRU;Mn;216;NSM;;;;;N;TIBETAN LENITION MARK;;;; +0F3A;TIBETAN MARK GUG RTAGS GYON;Ps;0;ON;;;;;Y;;;;; +0F3B;TIBETAN MARK GUG RTAGS GYAS;Pe;0;ON;;;;;Y;;;;; +0F3C;TIBETAN MARK ANG KHANG GYON;Ps;0;ON;;;;;Y;TIBETAN LEFT BRACE;;;; +0F3D;TIBETAN MARK ANG KHANG GYAS;Pe;0;ON;;;;;Y;TIBETAN RIGHT BRACE;;;; +0F3E;TIBETAN SIGN YAR TSHES;Mc;0;L;;;;;N;;;;; +0F3F;TIBETAN SIGN MAR TSHES;Mc;0;L;;;;;N;;;;; +0F40;TIBETAN LETTER KA;Lo;0;L;;;;;N;;;;; +0F41;TIBETAN LETTER KHA;Lo;0;L;;;;;N;;;;; +0F42;TIBETAN LETTER GA;Lo;0;L;;;;;N;;;;; +0F43;TIBETAN LETTER GHA;Lo;0;L;0F42 0FB7;;;;N;;;;; +0F44;TIBETAN LETTER NGA;Lo;0;L;;;;;N;;;;; +0F45;TIBETAN LETTER CA;Lo;0;L;;;;;N;;;;; +0F46;TIBETAN LETTER CHA;Lo;0;L;;;;;N;;;;; +0F47;TIBETAN LETTER JA;Lo;0;L;;;;;N;;;;; +0F49;TIBETAN LETTER NYA;Lo;0;L;;;;;N;;;;; +0F4A;TIBETAN LETTER TTA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED TA;;;; +0F4B;TIBETAN LETTER TTHA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED THA;;;; +0F4C;TIBETAN LETTER DDA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED DA;;;; +0F4D;TIBETAN LETTER DDHA;Lo;0;L;0F4C 0FB7;;;;N;;;;; +0F4E;TIBETAN LETTER NNA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED NA;;;; +0F4F;TIBETAN LETTER TA;Lo;0;L;;;;;N;;;;; +0F50;TIBETAN LETTER THA;Lo;0;L;;;;;N;;;;; +0F51;TIBETAN LETTER DA;Lo;0;L;;;;;N;;;;; +0F52;TIBETAN LETTER DHA;Lo;0;L;0F51 0FB7;;;;N;;;;; +0F53;TIBETAN LETTER NA;Lo;0;L;;;;;N;;;;; +0F54;TIBETAN LETTER PA;Lo;0;L;;;;;N;;;;; +0F55;TIBETAN LETTER PHA;Lo;0;L;;;;;N;;;;; +0F56;TIBETAN LETTER BA;Lo;0;L;;;;;N;;;;; +0F57;TIBETAN LETTER BHA;Lo;0;L;0F56 0FB7;;;;N;;;;; +0F58;TIBETAN LETTER MA;Lo;0;L;;;;;N;;;;; +0F59;TIBETAN LETTER TSA;Lo;0;L;;;;;N;;;;; +0F5A;TIBETAN LETTER TSHA;Lo;0;L;;;;;N;;;;; +0F5B;TIBETAN LETTER DZA;Lo;0;L;;;;;N;;;;; +0F5C;TIBETAN LETTER DZHA;Lo;0;L;0F5B 0FB7;;;;N;;;;; +0F5D;TIBETAN LETTER WA;Lo;0;L;;;;;N;;;;; +0F5E;TIBETAN LETTER ZHA;Lo;0;L;;;;;N;;;;; +0F5F;TIBETAN LETTER ZA;Lo;0;L;;;;;N;;;;; +0F60;TIBETAN LETTER -A;Lo;0;L;;;;;N;TIBETAN LETTER AA;;;; +0F61;TIBETAN LETTER YA;Lo;0;L;;;;;N;;;;; +0F62;TIBETAN LETTER RA;Lo;0;L;;;;;N;;;;; +0F63;TIBETAN LETTER LA;Lo;0;L;;;;;N;;;;; +0F64;TIBETAN LETTER SHA;Lo;0;L;;;;;N;;;;; +0F65;TIBETAN LETTER SSA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED SHA;;;; +0F66;TIBETAN LETTER SA;Lo;0;L;;;;;N;;;;; +0F67;TIBETAN LETTER HA;Lo;0;L;;;;;N;;;;; +0F68;TIBETAN LETTER A;Lo;0;L;;;;;N;;;;; +0F69;TIBETAN LETTER KSSA;Lo;0;L;0F40 0FB5;;;;N;;;;; +0F6A;TIBETAN LETTER FIXED-FORM RA;Lo;0;L;;;;;N;;;;; +0F6B;TIBETAN LETTER KKA;Lo;0;L;;;;;N;;;;; +0F6C;TIBETAN LETTER RRA;Lo;0;L;;;;;N;;;;; +0F71;TIBETAN VOWEL SIGN AA;Mn;129;NSM;;;;;N;;;;; +0F72;TIBETAN VOWEL SIGN I;Mn;130;NSM;;;;;N;;;;; +0F73;TIBETAN VOWEL SIGN II;Mn;0;NSM;0F71 0F72;;;;N;;;;; +0F74;TIBETAN VOWEL SIGN U;Mn;132;NSM;;;;;N;;;;; +0F75;TIBETAN VOWEL SIGN UU;Mn;0;NSM;0F71 0F74;;;;N;;;;; +0F76;TIBETAN VOWEL SIGN VOCALIC R;Mn;0;NSM;0FB2 0F80;;;;N;;;;; +0F77;TIBETAN VOWEL SIGN VOCALIC RR;Mn;0;NSM; 0FB2 0F81;;;;N;;;;; +0F78;TIBETAN VOWEL SIGN VOCALIC L;Mn;0;NSM;0FB3 0F80;;;;N;;;;; +0F79;TIBETAN VOWEL SIGN VOCALIC LL;Mn;0;NSM; 0FB3 0F81;;;;N;;;;; +0F7A;TIBETAN VOWEL SIGN E;Mn;130;NSM;;;;;N;;;;; +0F7B;TIBETAN VOWEL SIGN EE;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AI;;;; +0F7C;TIBETAN VOWEL SIGN O;Mn;130;NSM;;;;;N;;;;; +0F7D;TIBETAN VOWEL SIGN OO;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AU;;;; +0F7E;TIBETAN SIGN RJES SU NGA RO;Mn;0;NSM;;;;;N;TIBETAN ANUSVARA;;;; +0F7F;TIBETAN SIGN RNAM BCAD;Mc;0;L;;;;;N;TIBETAN VISARGA;;;; +0F80;TIBETAN VOWEL SIGN REVERSED I;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN SHORT I;;;; +0F81;TIBETAN VOWEL SIGN REVERSED II;Mn;0;NSM;0F71 0F80;;;;N;;;;; +0F82;TIBETAN SIGN NYI ZLA NAA DA;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU WITH ORNAMENT;;;; +0F83;TIBETAN SIGN SNA LDAN;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU;;;; +0F84;TIBETAN MARK HALANTA;Mn;9;NSM;;;;;N;TIBETAN VIRAMA;;;; +0F85;TIBETAN MARK PALUTA;Po;0;L;;;;;N;TIBETAN CHUCHENYIGE;;;; +0F86;TIBETAN SIGN LCI RTAGS;Mn;230;NSM;;;;;N;;;;; +0F87;TIBETAN SIGN YANG RTAGS;Mn;230;NSM;;;;;N;;;;; +0F88;TIBETAN SIGN LCE TSA CAN;Lo;0;L;;;;;N;;;;; +0F89;TIBETAN SIGN MCHU CAN;Lo;0;L;;;;;N;;;;; +0F8A;TIBETAN SIGN GRU CAN RGYINGS;Lo;0;L;;;;;N;;;;; +0F8B;TIBETAN SIGN GRU MED RGYINGS;Lo;0;L;;;;;N;;;;; +0F8C;TIBETAN SIGN INVERTED MCHU CAN;Lo;0;L;;;;;N;;;;; +0F8D;TIBETAN SUBJOINED SIGN LCE TSA CAN;Mn;0;NSM;;;;;N;;;;; +0F8E;TIBETAN SUBJOINED SIGN MCHU CAN;Mn;0;NSM;;;;;N;;;;; +0F8F;TIBETAN SUBJOINED SIGN INVERTED MCHU CAN;Mn;0;NSM;;;;;N;;;;; +0F90;TIBETAN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;; +0F91;TIBETAN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;; +0F92;TIBETAN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;; +0F93;TIBETAN SUBJOINED LETTER GHA;Mn;0;NSM;0F92 0FB7;;;;N;;;;; +0F94;TIBETAN SUBJOINED LETTER NGA;Mn;0;NSM;;;;;N;;;;; +0F95;TIBETAN SUBJOINED LETTER CA;Mn;0;NSM;;;;;N;;;;; +0F96;TIBETAN SUBJOINED LETTER CHA;Mn;0;NSM;;;;;N;;;;; +0F97;TIBETAN SUBJOINED LETTER JA;Mn;0;NSM;;;;;N;;;;; +0F99;TIBETAN SUBJOINED LETTER NYA;Mn;0;NSM;;;;;N;;;;; +0F9A;TIBETAN SUBJOINED LETTER TTA;Mn;0;NSM;;;;;N;;;;; +0F9B;TIBETAN SUBJOINED LETTER TTHA;Mn;0;NSM;;;;;N;;;;; +0F9C;TIBETAN SUBJOINED LETTER DDA;Mn;0;NSM;;;;;N;;;;; +0F9D;TIBETAN SUBJOINED LETTER DDHA;Mn;0;NSM;0F9C 0FB7;;;;N;;;;; +0F9E;TIBETAN SUBJOINED LETTER NNA;Mn;0;NSM;;;;;N;;;;; +0F9F;TIBETAN SUBJOINED LETTER TA;Mn;0;NSM;;;;;N;;;;; +0FA0;TIBETAN SUBJOINED LETTER THA;Mn;0;NSM;;;;;N;;;;; +0FA1;TIBETAN SUBJOINED LETTER DA;Mn;0;NSM;;;;;N;;;;; +0FA2;TIBETAN SUBJOINED LETTER DHA;Mn;0;NSM;0FA1 0FB7;;;;N;;;;; +0FA3;TIBETAN SUBJOINED LETTER NA;Mn;0;NSM;;;;;N;;;;; +0FA4;TIBETAN SUBJOINED LETTER PA;Mn;0;NSM;;;;;N;;;;; +0FA5;TIBETAN SUBJOINED LETTER PHA;Mn;0;NSM;;;;;N;;;;; +0FA6;TIBETAN SUBJOINED LETTER BA;Mn;0;NSM;;;;;N;;;;; +0FA7;TIBETAN SUBJOINED LETTER BHA;Mn;0;NSM;0FA6 0FB7;;;;N;;;;; +0FA8;TIBETAN SUBJOINED LETTER MA;Mn;0;NSM;;;;;N;;;;; +0FA9;TIBETAN SUBJOINED LETTER TSA;Mn;0;NSM;;;;;N;;;;; +0FAA;TIBETAN SUBJOINED LETTER TSHA;Mn;0;NSM;;;;;N;;;;; +0FAB;TIBETAN SUBJOINED LETTER DZA;Mn;0;NSM;;;;;N;;;;; +0FAC;TIBETAN SUBJOINED LETTER DZHA;Mn;0;NSM;0FAB 0FB7;;;;N;;;;; +0FAD;TIBETAN SUBJOINED LETTER WA;Mn;0;NSM;;;;;N;;;;; +0FAE;TIBETAN SUBJOINED LETTER ZHA;Mn;0;NSM;;;;;N;;;;; +0FAF;TIBETAN SUBJOINED LETTER ZA;Mn;0;NSM;;;;;N;;;;; +0FB0;TIBETAN SUBJOINED LETTER -A;Mn;0;NSM;;;;;N;;;;; +0FB1;TIBETAN SUBJOINED LETTER YA;Mn;0;NSM;;;;;N;;;;; +0FB2;TIBETAN SUBJOINED LETTER RA;Mn;0;NSM;;;;;N;;;;; +0FB3;TIBETAN SUBJOINED LETTER LA;Mn;0;NSM;;;;;N;;;;; +0FB4;TIBETAN SUBJOINED LETTER SHA;Mn;0;NSM;;;;;N;;;;; +0FB5;TIBETAN SUBJOINED LETTER SSA;Mn;0;NSM;;;;;N;;;;; +0FB6;TIBETAN SUBJOINED LETTER SA;Mn;0;NSM;;;;;N;;;;; +0FB7;TIBETAN SUBJOINED LETTER HA;Mn;0;NSM;;;;;N;;;;; +0FB8;TIBETAN SUBJOINED LETTER A;Mn;0;NSM;;;;;N;;;;; +0FB9;TIBETAN SUBJOINED LETTER KSSA;Mn;0;NSM;0F90 0FB5;;;;N;;;;; +0FBA;TIBETAN SUBJOINED LETTER FIXED-FORM WA;Mn;0;NSM;;;;;N;;;;; +0FBB;TIBETAN SUBJOINED LETTER FIXED-FORM YA;Mn;0;NSM;;;;;N;;;;; +0FBC;TIBETAN SUBJOINED LETTER FIXED-FORM RA;Mn;0;NSM;;;;;N;;;;; +0FBE;TIBETAN KU RU KHA;So;0;L;;;;;N;;;;; +0FBF;TIBETAN KU RU KHA BZHI MIG CAN;So;0;L;;;;;N;;;;; +0FC0;TIBETAN CANTILLATION SIGN HEAVY BEAT;So;0;L;;;;;N;;;;; +0FC1;TIBETAN CANTILLATION SIGN LIGHT BEAT;So;0;L;;;;;N;;;;; +0FC2;TIBETAN CANTILLATION SIGN CANG TE-U;So;0;L;;;;;N;;;;; +0FC3;TIBETAN CANTILLATION SIGN SBUB -CHAL;So;0;L;;;;;N;;;;; +0FC4;TIBETAN SYMBOL DRIL BU;So;0;L;;;;;N;;;;; +0FC5;TIBETAN SYMBOL RDO RJE;So;0;L;;;;;N;;;;; +0FC6;TIBETAN SYMBOL PADMA GDAN;Mn;220;NSM;;;;;N;;;;; +0FC7;TIBETAN SYMBOL RDO RJE RGYA GRAM;So;0;L;;;;;N;;;;; +0FC8;TIBETAN SYMBOL PHUR PA;So;0;L;;;;;N;;;;; +0FC9;TIBETAN SYMBOL NOR BU;So;0;L;;;;;N;;;;; +0FCA;TIBETAN SYMBOL NOR BU NYIS -KHYIL;So;0;L;;;;;N;;;;; +0FCB;TIBETAN SYMBOL NOR BU GSUM -KHYIL;So;0;L;;;;;N;;;;; +0FCC;TIBETAN SYMBOL NOR BU BZHI -KHYIL;So;0;L;;;;;N;;;;; +0FCE;TIBETAN SIGN RDEL NAG RDEL DKAR;So;0;L;;;;;N;;;;; +0FCF;TIBETAN SIGN RDEL NAG GSUM;So;0;L;;;;;N;;;;; +0FD0;TIBETAN MARK BSKA- SHOG GI MGO RGYAN;Po;0;L;;;;;N;;;;; +0FD1;TIBETAN MARK MNYAM YIG GI MGO RGYAN;Po;0;L;;;;;N;;;;; +0FD2;TIBETAN MARK NYIS TSHEG;Po;0;L;;;;;N;;;;; +0FD3;TIBETAN MARK INITIAL BRDA RNYING YIG MGO MDUN MA;Po;0;L;;;;;N;;;;; +0FD4;TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA;Po;0;L;;;;;N;;;;; +0FD5;RIGHT-FACING SVASTI SIGN;So;0;L;;;;;N;;;;; +0FD6;LEFT-FACING SVASTI SIGN;So;0;L;;;;;N;;;;; +0FD7;RIGHT-FACING SVASTI SIGN WITH DOTS;So;0;L;;;;;N;;;;; +0FD8;LEFT-FACING SVASTI SIGN WITH DOTS;So;0;L;;;;;N;;;;; +0FD9;TIBETAN MARK LEADING MCHAN RTAGS;Po;0;L;;;;;N;;;;; +0FDA;TIBETAN MARK TRAILING MCHAN RTAGS;Po;0;L;;;;;N;;;;; +1000;MYANMAR LETTER KA;Lo;0;L;;;;;N;;;;; +1001;MYANMAR LETTER KHA;Lo;0;L;;;;;N;;;;; +1002;MYANMAR LETTER GA;Lo;0;L;;;;;N;;;;; +1003;MYANMAR LETTER GHA;Lo;0;L;;;;;N;;;;; +1004;MYANMAR LETTER NGA;Lo;0;L;;;;;N;;;;; +1005;MYANMAR LETTER CA;Lo;0;L;;;;;N;;;;; +1006;MYANMAR LETTER CHA;Lo;0;L;;;;;N;;;;; +1007;MYANMAR LETTER JA;Lo;0;L;;;;;N;;;;; +1008;MYANMAR LETTER JHA;Lo;0;L;;;;;N;;;;; +1009;MYANMAR LETTER NYA;Lo;0;L;;;;;N;;;;; +100A;MYANMAR LETTER NNYA;Lo;0;L;;;;;N;;;;; +100B;MYANMAR LETTER TTA;Lo;0;L;;;;;N;;;;; +100C;MYANMAR LETTER TTHA;Lo;0;L;;;;;N;;;;; +100D;MYANMAR LETTER DDA;Lo;0;L;;;;;N;;;;; +100E;MYANMAR LETTER DDHA;Lo;0;L;;;;;N;;;;; +100F;MYANMAR LETTER NNA;Lo;0;L;;;;;N;;;;; +1010;MYANMAR LETTER TA;Lo;0;L;;;;;N;;;;; +1011;MYANMAR LETTER THA;Lo;0;L;;;;;N;;;;; +1012;MYANMAR LETTER DA;Lo;0;L;;;;;N;;;;; +1013;MYANMAR LETTER DHA;Lo;0;L;;;;;N;;;;; +1014;MYANMAR LETTER NA;Lo;0;L;;;;;N;;;;; +1015;MYANMAR LETTER PA;Lo;0;L;;;;;N;;;;; +1016;MYANMAR LETTER PHA;Lo;0;L;;;;;N;;;;; +1017;MYANMAR LETTER BA;Lo;0;L;;;;;N;;;;; +1018;MYANMAR LETTER BHA;Lo;0;L;;;;;N;;;;; +1019;MYANMAR LETTER MA;Lo;0;L;;;;;N;;;;; +101A;MYANMAR LETTER YA;Lo;0;L;;;;;N;;;;; +101B;MYANMAR LETTER RA;Lo;0;L;;;;;N;;;;; +101C;MYANMAR LETTER LA;Lo;0;L;;;;;N;;;;; +101D;MYANMAR LETTER WA;Lo;0;L;;;;;N;;;;; +101E;MYANMAR LETTER SA;Lo;0;L;;;;;N;;;;; +101F;MYANMAR LETTER HA;Lo;0;L;;;;;N;;;;; +1020;MYANMAR LETTER LLA;Lo;0;L;;;;;N;;;;; +1021;MYANMAR LETTER A;Lo;0;L;;;;;N;;;;; +1022;MYANMAR LETTER SHAN A;Lo;0;L;;;;;N;;;;; +1023;MYANMAR LETTER I;Lo;0;L;;;;;N;;;;; +1024;MYANMAR LETTER II;Lo;0;L;;;;;N;;;;; +1025;MYANMAR LETTER U;Lo;0;L;;;;;N;;;;; +1026;MYANMAR LETTER UU;Lo;0;L;1025 102E;;;;N;;;;; +1027;MYANMAR LETTER E;Lo;0;L;;;;;N;;;;; +1028;MYANMAR LETTER MON E;Lo;0;L;;;;;N;;;;; +1029;MYANMAR LETTER O;Lo;0;L;;;;;N;;;;; +102A;MYANMAR LETTER AU;Lo;0;L;;;;;N;;;;; +102B;MYANMAR VOWEL SIGN TALL AA;Mc;0;L;;;;;N;;;;; +102C;MYANMAR VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +102D;MYANMAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +102E;MYANMAR VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +102F;MYANMAR VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1030;MYANMAR VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +1031;MYANMAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +1032;MYANMAR VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +1033;MYANMAR VOWEL SIGN MON II;Mn;0;NSM;;;;;N;;;;; +1034;MYANMAR VOWEL SIGN MON O;Mn;0;NSM;;;;;N;;;;; +1035;MYANMAR VOWEL SIGN E ABOVE;Mn;0;NSM;;;;;N;;;;; +1036;MYANMAR SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +1037;MYANMAR SIGN DOT BELOW;Mn;7;NSM;;;;;N;;;;; +1038;MYANMAR SIGN VISARGA;Mc;0;L;;;;;N;;;;; +1039;MYANMAR SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +103A;MYANMAR SIGN ASAT;Mn;9;NSM;;;;;N;;;;; +103B;MYANMAR CONSONANT SIGN MEDIAL YA;Mc;0;L;;;;;N;;;;; +103C;MYANMAR CONSONANT SIGN MEDIAL RA;Mc;0;L;;;;;N;;;;; +103D;MYANMAR CONSONANT SIGN MEDIAL WA;Mn;0;NSM;;;;;N;;;;; +103E;MYANMAR CONSONANT SIGN MEDIAL HA;Mn;0;NSM;;;;;N;;;;; +103F;MYANMAR LETTER GREAT SA;Lo;0;L;;;;;N;;;;; +1040;MYANMAR DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1041;MYANMAR DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1042;MYANMAR DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1043;MYANMAR DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1044;MYANMAR DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1045;MYANMAR DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1046;MYANMAR DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1047;MYANMAR DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1048;MYANMAR DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1049;MYANMAR DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +104A;MYANMAR SIGN LITTLE SECTION;Po;0;L;;;;;N;;;;; +104B;MYANMAR SIGN SECTION;Po;0;L;;;;;N;;;;; +104C;MYANMAR SYMBOL LOCATIVE;Po;0;L;;;;;N;;;;; +104D;MYANMAR SYMBOL COMPLETED;Po;0;L;;;;;N;;;;; +104E;MYANMAR SYMBOL AFOREMENTIONED;Po;0;L;;;;;N;;;;; +104F;MYANMAR SYMBOL GENITIVE;Po;0;L;;;;;N;;;;; +1050;MYANMAR LETTER SHA;Lo;0;L;;;;;N;;;;; +1051;MYANMAR LETTER SSA;Lo;0;L;;;;;N;;;;; +1052;MYANMAR LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +1053;MYANMAR LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +1054;MYANMAR LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +1055;MYANMAR LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1056;MYANMAR VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; +1057;MYANMAR VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; +1058;MYANMAR VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +1059;MYANMAR VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +105A;MYANMAR LETTER MON NGA;Lo;0;L;;;;;N;;;;; +105B;MYANMAR LETTER MON JHA;Lo;0;L;;;;;N;;;;; +105C;MYANMAR LETTER MON BBA;Lo;0;L;;;;;N;;;;; +105D;MYANMAR LETTER MON BBE;Lo;0;L;;;;;N;;;;; +105E;MYANMAR CONSONANT SIGN MON MEDIAL NA;Mn;0;NSM;;;;;N;;;;; +105F;MYANMAR CONSONANT SIGN MON MEDIAL MA;Mn;0;NSM;;;;;N;;;;; +1060;MYANMAR CONSONANT SIGN MON MEDIAL LA;Mn;0;NSM;;;;;N;;;;; +1061;MYANMAR LETTER SGAW KAREN SHA;Lo;0;L;;;;;N;;;;; +1062;MYANMAR VOWEL SIGN SGAW KAREN EU;Mc;0;L;;;;;N;;;;; +1063;MYANMAR TONE MARK SGAW KAREN HATHI;Mc;0;L;;;;;N;;;;; +1064;MYANMAR TONE MARK SGAW KAREN KE PHO;Mc;0;L;;;;;N;;;;; +1065;MYANMAR LETTER WESTERN PWO KAREN THA;Lo;0;L;;;;;N;;;;; +1066;MYANMAR LETTER WESTERN PWO KAREN PWA;Lo;0;L;;;;;N;;;;; +1067;MYANMAR VOWEL SIGN WESTERN PWO KAREN EU;Mc;0;L;;;;;N;;;;; +1068;MYANMAR VOWEL SIGN WESTERN PWO KAREN UE;Mc;0;L;;;;;N;;;;; +1069;MYANMAR SIGN WESTERN PWO KAREN TONE-1;Mc;0;L;;;;;N;;;;; +106A;MYANMAR SIGN WESTERN PWO KAREN TONE-2;Mc;0;L;;;;;N;;;;; +106B;MYANMAR SIGN WESTERN PWO KAREN TONE-3;Mc;0;L;;;;;N;;;;; +106C;MYANMAR SIGN WESTERN PWO KAREN TONE-4;Mc;0;L;;;;;N;;;;; +106D;MYANMAR SIGN WESTERN PWO KAREN TONE-5;Mc;0;L;;;;;N;;;;; +106E;MYANMAR LETTER EASTERN PWO KAREN NNA;Lo;0;L;;;;;N;;;;; +106F;MYANMAR LETTER EASTERN PWO KAREN YWA;Lo;0;L;;;;;N;;;;; +1070;MYANMAR LETTER EASTERN PWO KAREN GHWA;Lo;0;L;;;;;N;;;;; +1071;MYANMAR VOWEL SIGN GEBA KAREN I;Mn;0;NSM;;;;;N;;;;; +1072;MYANMAR VOWEL SIGN KAYAH OE;Mn;0;NSM;;;;;N;;;;; +1073;MYANMAR VOWEL SIGN KAYAH U;Mn;0;NSM;;;;;N;;;;; +1074;MYANMAR VOWEL SIGN KAYAH EE;Mn;0;NSM;;;;;N;;;;; +1075;MYANMAR LETTER SHAN KA;Lo;0;L;;;;;N;;;;; +1076;MYANMAR LETTER SHAN KHA;Lo;0;L;;;;;N;;;;; +1077;MYANMAR LETTER SHAN GA;Lo;0;L;;;;;N;;;;; +1078;MYANMAR LETTER SHAN CA;Lo;0;L;;;;;N;;;;; +1079;MYANMAR LETTER SHAN ZA;Lo;0;L;;;;;N;;;;; +107A;MYANMAR LETTER SHAN NYA;Lo;0;L;;;;;N;;;;; +107B;MYANMAR LETTER SHAN DA;Lo;0;L;;;;;N;;;;; +107C;MYANMAR LETTER SHAN NA;Lo;0;L;;;;;N;;;;; +107D;MYANMAR LETTER SHAN PHA;Lo;0;L;;;;;N;;;;; +107E;MYANMAR LETTER SHAN FA;Lo;0;L;;;;;N;;;;; +107F;MYANMAR LETTER SHAN BA;Lo;0;L;;;;;N;;;;; +1080;MYANMAR LETTER SHAN THA;Lo;0;L;;;;;N;;;;; +1081;MYANMAR LETTER SHAN HA;Lo;0;L;;;;;N;;;;; +1082;MYANMAR CONSONANT SIGN SHAN MEDIAL WA;Mn;0;NSM;;;;;N;;;;; +1083;MYANMAR VOWEL SIGN SHAN AA;Mc;0;L;;;;;N;;;;; +1084;MYANMAR VOWEL SIGN SHAN E;Mc;0;L;;;;;N;;;;; +1085;MYANMAR VOWEL SIGN SHAN E ABOVE;Mn;0;NSM;;;;;N;;;;; +1086;MYANMAR VOWEL SIGN SHAN FINAL Y;Mn;0;NSM;;;;;N;;;;; +1087;MYANMAR SIGN SHAN TONE-2;Mc;0;L;;;;;N;;;;; +1088;MYANMAR SIGN SHAN TONE-3;Mc;0;L;;;;;N;;;;; +1089;MYANMAR SIGN SHAN TONE-5;Mc;0;L;;;;;N;;;;; +108A;MYANMAR SIGN SHAN TONE-6;Mc;0;L;;;;;N;;;;; +108B;MYANMAR SIGN SHAN COUNCIL TONE-2;Mc;0;L;;;;;N;;;;; +108C;MYANMAR SIGN SHAN COUNCIL TONE-3;Mc;0;L;;;;;N;;;;; +108D;MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE;Mn;220;NSM;;;;;N;;;;; +108E;MYANMAR LETTER RUMAI PALAUNG FA;Lo;0;L;;;;;N;;;;; +108F;MYANMAR SIGN RUMAI PALAUNG TONE-5;Mc;0;L;;;;;N;;;;; +1090;MYANMAR SHAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1091;MYANMAR SHAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1092;MYANMAR SHAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1093;MYANMAR SHAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1094;MYANMAR SHAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1095;MYANMAR SHAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1096;MYANMAR SHAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1097;MYANMAR SHAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1098;MYANMAR SHAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1099;MYANMAR SHAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +109A;MYANMAR SIGN KHAMTI TONE-1;Mc;0;L;;;;;N;;;;; +109B;MYANMAR SIGN KHAMTI TONE-3;Mc;0;L;;;;;N;;;;; +109C;MYANMAR VOWEL SIGN AITON A;Mc;0;L;;;;;N;;;;; +109D;MYANMAR VOWEL SIGN AITON AI;Mn;0;NSM;;;;;N;;;;; +109E;MYANMAR SYMBOL SHAN ONE;So;0;L;;;;;N;;;;; +109F;MYANMAR SYMBOL SHAN EXCLAMATION;So;0;L;;;;;N;;;;; +10A0;GEORGIAN CAPITAL LETTER AN;Lu;0;L;;;;;N;;;;2D00; +10A1;GEORGIAN CAPITAL LETTER BAN;Lu;0;L;;;;;N;;;;2D01; +10A2;GEORGIAN CAPITAL LETTER GAN;Lu;0;L;;;;;N;;;;2D02; +10A3;GEORGIAN CAPITAL LETTER DON;Lu;0;L;;;;;N;;;;2D03; +10A4;GEORGIAN CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;2D04; +10A5;GEORGIAN CAPITAL LETTER VIN;Lu;0;L;;;;;N;;;;2D05; +10A6;GEORGIAN CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;;;2D06; +10A7;GEORGIAN CAPITAL LETTER TAN;Lu;0;L;;;;;N;;;;2D07; +10A8;GEORGIAN CAPITAL LETTER IN;Lu;0;L;;;;;N;;;;2D08; +10A9;GEORGIAN CAPITAL LETTER KAN;Lu;0;L;;;;;N;;;;2D09; +10AA;GEORGIAN CAPITAL LETTER LAS;Lu;0;L;;;;;N;;;;2D0A; +10AB;GEORGIAN CAPITAL LETTER MAN;Lu;0;L;;;;;N;;;;2D0B; +10AC;GEORGIAN CAPITAL LETTER NAR;Lu;0;L;;;;;N;;;;2D0C; +10AD;GEORGIAN CAPITAL LETTER ON;Lu;0;L;;;;;N;;;;2D0D; +10AE;GEORGIAN CAPITAL LETTER PAR;Lu;0;L;;;;;N;;;;2D0E; +10AF;GEORGIAN CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;;;2D0F; +10B0;GEORGIAN CAPITAL LETTER RAE;Lu;0;L;;;;;N;;;;2D10; +10B1;GEORGIAN CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;2D11; +10B2;GEORGIAN CAPITAL LETTER TAR;Lu;0;L;;;;;N;;;;2D12; +10B3;GEORGIAN CAPITAL LETTER UN;Lu;0;L;;;;;N;;;;2D13; +10B4;GEORGIAN CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;;;2D14; +10B5;GEORGIAN CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;;;2D15; +10B6;GEORGIAN CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;;;2D16; +10B7;GEORGIAN CAPITAL LETTER QAR;Lu;0;L;;;;;N;;;;2D17; +10B8;GEORGIAN CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;;;2D18; +10B9;GEORGIAN CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;;;2D19; +10BA;GEORGIAN CAPITAL LETTER CAN;Lu;0;L;;;;;N;;;;2D1A; +10BB;GEORGIAN CAPITAL LETTER JIL;Lu;0;L;;;;;N;;;;2D1B; +10BC;GEORGIAN CAPITAL LETTER CIL;Lu;0;L;;;;;N;;;;2D1C; +10BD;GEORGIAN CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;;;2D1D; +10BE;GEORGIAN CAPITAL LETTER XAN;Lu;0;L;;;;;N;;;;2D1E; +10BF;GEORGIAN CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;;;2D1F; +10C0;GEORGIAN CAPITAL LETTER HAE;Lu;0;L;;;;;N;;;;2D20; +10C1;GEORGIAN CAPITAL LETTER HE;Lu;0;L;;;;;N;;;;2D21; +10C2;GEORGIAN CAPITAL LETTER HIE;Lu;0;L;;;;;N;;;;2D22; +10C3;GEORGIAN CAPITAL LETTER WE;Lu;0;L;;;;;N;;;;2D23; +10C4;GEORGIAN CAPITAL LETTER HAR;Lu;0;L;;;;;N;;;;2D24; +10C5;GEORGIAN CAPITAL LETTER HOE;Lu;0;L;;;;;N;;;;2D25; +10C7;GEORGIAN CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;2D27; +10CD;GEORGIAN CAPITAL LETTER AEN;Lu;0;L;;;;;N;;;;2D2D; +10D0;GEORGIAN LETTER AN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;1C90;;10D0 +10D1;GEORGIAN LETTER BAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;1C91;;10D1 +10D2;GEORGIAN LETTER GAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;1C92;;10D2 +10D3;GEORGIAN LETTER DON;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER DON;;1C93;;10D3 +10D4;GEORGIAN LETTER EN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER EN;;1C94;;10D4 +10D5;GEORGIAN LETTER VIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER VIN;;1C95;;10D5 +10D6;GEORGIAN LETTER ZEN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ZEN;;1C96;;10D6 +10D7;GEORGIAN LETTER TAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER TAN;;1C97;;10D7 +10D8;GEORGIAN LETTER IN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER IN;;1C98;;10D8 +10D9;GEORGIAN LETTER KAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER KAN;;1C99;;10D9 +10DA;GEORGIAN LETTER LAS;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER LAS;;1C9A;;10DA +10DB;GEORGIAN LETTER MAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER MAN;;1C9B;;10DB +10DC;GEORGIAN LETTER NAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER NAR;;1C9C;;10DC +10DD;GEORGIAN LETTER ON;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ON;;1C9D;;10DD +10DE;GEORGIAN LETTER PAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER PAR;;1C9E;;10DE +10DF;GEORGIAN LETTER ZHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ZHAR;;1C9F;;10DF +10E0;GEORGIAN LETTER RAE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER RAE;;1CA0;;10E0 +10E1;GEORGIAN LETTER SAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER SAN;;1CA1;;10E1 +10E2;GEORGIAN LETTER TAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER TAR;;1CA2;;10E2 +10E3;GEORGIAN LETTER UN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER UN;;1CA3;;10E3 +10E4;GEORGIAN LETTER PHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER PHAR;;1CA4;;10E4 +10E5;GEORGIAN LETTER KHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER KHAR;;1CA5;;10E5 +10E6;GEORGIAN LETTER GHAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER GHAN;;1CA6;;10E6 +10E7;GEORGIAN LETTER QAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER QAR;;1CA7;;10E7 +10E8;GEORGIAN LETTER SHIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER SHIN;;1CA8;;10E8 +10E9;GEORGIAN LETTER CHIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CHIN;;1CA9;;10E9 +10EA;GEORGIAN LETTER CAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CAN;;1CAA;;10EA +10EB;GEORGIAN LETTER JIL;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER JIL;;1CAB;;10EB +10EC;GEORGIAN LETTER CIL;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CIL;;1CAC;;10EC +10ED;GEORGIAN LETTER CHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CHAR;;1CAD;;10ED +10EE;GEORGIAN LETTER XAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER XAN;;1CAE;;10EE +10EF;GEORGIAN LETTER JHAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER JHAN;;1CAF;;10EF +10F0;GEORGIAN LETTER HAE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HAE;;1CB0;;10F0 +10F1;GEORGIAN LETTER HE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HE;;1CB1;;10F1 +10F2;GEORGIAN LETTER HIE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HIE;;1CB2;;10F2 +10F3;GEORGIAN LETTER WE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER WE;;1CB3;;10F3 +10F4;GEORGIAN LETTER HAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HAR;;1CB4;;10F4 +10F5;GEORGIAN LETTER HOE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HOE;;1CB5;;10F5 +10F6;GEORGIAN LETTER FI;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;1CB6;;10F6 +10F7;GEORGIAN LETTER YN;Ll;0;L;;;;;N;;;1CB7;;10F7 +10F8;GEORGIAN LETTER ELIFI;Ll;0;L;;;;;N;;;1CB8;;10F8 +10F9;GEORGIAN LETTER TURNED GAN;Ll;0;L;;;;;N;;;1CB9;;10F9 +10FA;GEORGIAN LETTER AIN;Ll;0;L;;;;;N;;;1CBA;;10FA +10FB;GEORGIAN PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;; +10FC;MODIFIER LETTER GEORGIAN NAR;Lm;0;L; 10DC;;;;N;;;;; +10FD;GEORGIAN LETTER AEN;Ll;0;L;;;;;N;;;1CBD;;10FD +10FE;GEORGIAN LETTER HARD SIGN;Ll;0;L;;;;;N;;;1CBE;;10FE +10FF;GEORGIAN LETTER LABIAL SIGN;Ll;0;L;;;;;N;;;1CBF;;10FF +1100;HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;;;; +1101;HANGUL CHOSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;;;; +1102;HANGUL CHOSEONG NIEUN;Lo;0;L;;;;;N;;;;; +1103;HANGUL CHOSEONG TIKEUT;Lo;0;L;;;;;N;;;;; +1104;HANGUL CHOSEONG SSANGTIKEUT;Lo;0;L;;;;;N;;;;; +1105;HANGUL CHOSEONG RIEUL;Lo;0;L;;;;;N;;;;; +1106;HANGUL CHOSEONG MIEUM;Lo;0;L;;;;;N;;;;; +1107;HANGUL CHOSEONG PIEUP;Lo;0;L;;;;;N;;;;; +1108;HANGUL CHOSEONG SSANGPIEUP;Lo;0;L;;;;;N;;;;; +1109;HANGUL CHOSEONG SIOS;Lo;0;L;;;;;N;;;;; +110A;HANGUL CHOSEONG SSANGSIOS;Lo;0;L;;;;;N;;;;; +110B;HANGUL CHOSEONG IEUNG;Lo;0;L;;;;;N;;;;; +110C;HANGUL CHOSEONG CIEUC;Lo;0;L;;;;;N;;;;; +110D;HANGUL CHOSEONG SSANGCIEUC;Lo;0;L;;;;;N;;;;; +110E;HANGUL CHOSEONG CHIEUCH;Lo;0;L;;;;;N;;;;; +110F;HANGUL CHOSEONG KHIEUKH;Lo;0;L;;;;;N;;;;; +1110;HANGUL CHOSEONG THIEUTH;Lo;0;L;;;;;N;;;;; +1111;HANGUL CHOSEONG PHIEUPH;Lo;0;L;;;;;N;;;;; +1112;HANGUL CHOSEONG HIEUH;Lo;0;L;;;;;N;;;;; +1113;HANGUL CHOSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;; +1114;HANGUL CHOSEONG SSANGNIEUN;Lo;0;L;;;;;N;;;;; +1115;HANGUL CHOSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;; +1116;HANGUL CHOSEONG NIEUN-PIEUP;Lo;0;L;;;;;N;;;;; +1117;HANGUL CHOSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;; +1118;HANGUL CHOSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;; +1119;HANGUL CHOSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;; +111A;HANGUL CHOSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;;;; +111B;HANGUL CHOSEONG KAPYEOUNRIEUL;Lo;0;L;;;;;N;;;;; +111C;HANGUL CHOSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;; +111D;HANGUL CHOSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;; +111E;HANGUL CHOSEONG PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;; +111F;HANGUL CHOSEONG PIEUP-NIEUN;Lo;0;L;;;;;N;;;;; +1120;HANGUL CHOSEONG PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;; +1121;HANGUL CHOSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;;;; +1122;HANGUL CHOSEONG PIEUP-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; +1123;HANGUL CHOSEONG PIEUP-SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; +1124;HANGUL CHOSEONG PIEUP-SIOS-PIEUP;Lo;0;L;;;;;N;;;;; +1125;HANGUL CHOSEONG PIEUP-SSANGSIOS;Lo;0;L;;;;;N;;;;; +1126;HANGUL CHOSEONG PIEUP-SIOS-CIEUC;Lo;0;L;;;;;N;;;;; +1127;HANGUL CHOSEONG PIEUP-CIEUC;Lo;0;L;;;;;N;;;;; +1128;HANGUL CHOSEONG PIEUP-CHIEUCH;Lo;0;L;;;;;N;;;;; +1129;HANGUL CHOSEONG PIEUP-THIEUTH;Lo;0;L;;;;;N;;;;; +112A;HANGUL CHOSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;; +112B;HANGUL CHOSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; +112C;HANGUL CHOSEONG KAPYEOUNSSANGPIEUP;Lo;0;L;;;;;N;;;;; +112D;HANGUL CHOSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; +112E;HANGUL CHOSEONG SIOS-NIEUN;Lo;0;L;;;;;N;;;;; +112F;HANGUL CHOSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; +1130;HANGUL CHOSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;; +1131;HANGUL CHOSEONG SIOS-MIEUM;Lo;0;L;;;;;N;;;;; +1132;HANGUL CHOSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;; +1133;HANGUL CHOSEONG SIOS-PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;; +1134;HANGUL CHOSEONG SIOS-SSANGSIOS;Lo;0;L;;;;;N;;;;; +1135;HANGUL CHOSEONG SIOS-IEUNG;Lo;0;L;;;;;N;;;;; +1136;HANGUL CHOSEONG SIOS-CIEUC;Lo;0;L;;;;;N;;;;; +1137;HANGUL CHOSEONG SIOS-CHIEUCH;Lo;0;L;;;;;N;;;;; +1138;HANGUL CHOSEONG SIOS-KHIEUKH;Lo;0;L;;;;;N;;;;; +1139;HANGUL CHOSEONG SIOS-THIEUTH;Lo;0;L;;;;;N;;;;; +113A;HANGUL CHOSEONG SIOS-PHIEUPH;Lo;0;L;;;;;N;;;;; +113B;HANGUL CHOSEONG SIOS-HIEUH;Lo;0;L;;;;;N;;;;; +113C;HANGUL CHOSEONG CHITUEUMSIOS;Lo;0;L;;;;;N;;;;; +113D;HANGUL CHOSEONG CHITUEUMSSANGSIOS;Lo;0;L;;;;;N;;;;; +113E;HANGUL CHOSEONG CEONGCHIEUMSIOS;Lo;0;L;;;;;N;;;;; +113F;HANGUL CHOSEONG CEONGCHIEUMSSANGSIOS;Lo;0;L;;;;;N;;;;; +1140;HANGUL CHOSEONG PANSIOS;Lo;0;L;;;;;N;;;;; +1141;HANGUL CHOSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;; +1142;HANGUL CHOSEONG IEUNG-TIKEUT;Lo;0;L;;;;;N;;;;; +1143;HANGUL CHOSEONG IEUNG-MIEUM;Lo;0;L;;;;;N;;;;; +1144;HANGUL CHOSEONG IEUNG-PIEUP;Lo;0;L;;;;;N;;;;; +1145;HANGUL CHOSEONG IEUNG-SIOS;Lo;0;L;;;;;N;;;;; +1146;HANGUL CHOSEONG IEUNG-PANSIOS;Lo;0;L;;;;;N;;;;; +1147;HANGUL CHOSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;; +1148;HANGUL CHOSEONG IEUNG-CIEUC;Lo;0;L;;;;;N;;;;; +1149;HANGUL CHOSEONG IEUNG-CHIEUCH;Lo;0;L;;;;;N;;;;; +114A;HANGUL CHOSEONG IEUNG-THIEUTH;Lo;0;L;;;;;N;;;;; +114B;HANGUL CHOSEONG IEUNG-PHIEUPH;Lo;0;L;;;;;N;;;;; +114C;HANGUL CHOSEONG YESIEUNG;Lo;0;L;;;;;N;;;;; +114D;HANGUL CHOSEONG CIEUC-IEUNG;Lo;0;L;;;;;N;;;;; +114E;HANGUL CHOSEONG CHITUEUMCIEUC;Lo;0;L;;;;;N;;;;; +114F;HANGUL CHOSEONG CHITUEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;; +1150;HANGUL CHOSEONG CEONGCHIEUMCIEUC;Lo;0;L;;;;;N;;;;; +1151;HANGUL CHOSEONG CEONGCHIEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;; +1152;HANGUL CHOSEONG CHIEUCH-KHIEUKH;Lo;0;L;;;;;N;;;;; +1153;HANGUL CHOSEONG CHIEUCH-HIEUH;Lo;0;L;;;;;N;;;;; +1154;HANGUL CHOSEONG CHITUEUMCHIEUCH;Lo;0;L;;;;;N;;;;; +1155;HANGUL CHOSEONG CEONGCHIEUMCHIEUCH;Lo;0;L;;;;;N;;;;; +1156;HANGUL CHOSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;; +1157;HANGUL CHOSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;; +1158;HANGUL CHOSEONG SSANGHIEUH;Lo;0;L;;;;;N;;;;; +1159;HANGUL CHOSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;; +115A;HANGUL CHOSEONG KIYEOK-TIKEUT;Lo;0;L;;;;;N;;;;; +115B;HANGUL CHOSEONG NIEUN-SIOS;Lo;0;L;;;;;N;;;;; +115C;HANGUL CHOSEONG NIEUN-CIEUC;Lo;0;L;;;;;N;;;;; +115D;HANGUL CHOSEONG NIEUN-HIEUH;Lo;0;L;;;;;N;;;;; +115E;HANGUL CHOSEONG TIKEUT-RIEUL;Lo;0;L;;;;;N;;;;; +115F;HANGUL CHOSEONG FILLER;Lo;0;L;;;;;N;;;;; +1160;HANGUL JUNGSEONG FILLER;Lo;0;L;;;;;N;;;;; +1161;HANGUL JUNGSEONG A;Lo;0;L;;;;;N;;;;; +1162;HANGUL JUNGSEONG AE;Lo;0;L;;;;;N;;;;; +1163;HANGUL JUNGSEONG YA;Lo;0;L;;;;;N;;;;; +1164;HANGUL JUNGSEONG YAE;Lo;0;L;;;;;N;;;;; +1165;HANGUL JUNGSEONG EO;Lo;0;L;;;;;N;;;;; +1166;HANGUL JUNGSEONG E;Lo;0;L;;;;;N;;;;; +1167;HANGUL JUNGSEONG YEO;Lo;0;L;;;;;N;;;;; +1168;HANGUL JUNGSEONG YE;Lo;0;L;;;;;N;;;;; +1169;HANGUL JUNGSEONG O;Lo;0;L;;;;;N;;;;; +116A;HANGUL JUNGSEONG WA;Lo;0;L;;;;;N;;;;; +116B;HANGUL JUNGSEONG WAE;Lo;0;L;;;;;N;;;;; +116C;HANGUL JUNGSEONG OE;Lo;0;L;;;;;N;;;;; +116D;HANGUL JUNGSEONG YO;Lo;0;L;;;;;N;;;;; +116E;HANGUL JUNGSEONG U;Lo;0;L;;;;;N;;;;; +116F;HANGUL JUNGSEONG WEO;Lo;0;L;;;;;N;;;;; +1170;HANGUL JUNGSEONG WE;Lo;0;L;;;;;N;;;;; +1171;HANGUL JUNGSEONG WI;Lo;0;L;;;;;N;;;;; +1172;HANGUL JUNGSEONG YU;Lo;0;L;;;;;N;;;;; +1173;HANGUL JUNGSEONG EU;Lo;0;L;;;;;N;;;;; +1174;HANGUL JUNGSEONG YI;Lo;0;L;;;;;N;;;;; +1175;HANGUL JUNGSEONG I;Lo;0;L;;;;;N;;;;; +1176;HANGUL JUNGSEONG A-O;Lo;0;L;;;;;N;;;;; +1177;HANGUL JUNGSEONG A-U;Lo;0;L;;;;;N;;;;; +1178;HANGUL JUNGSEONG YA-O;Lo;0;L;;;;;N;;;;; +1179;HANGUL JUNGSEONG YA-YO;Lo;0;L;;;;;N;;;;; +117A;HANGUL JUNGSEONG EO-O;Lo;0;L;;;;;N;;;;; +117B;HANGUL JUNGSEONG EO-U;Lo;0;L;;;;;N;;;;; +117C;HANGUL JUNGSEONG EO-EU;Lo;0;L;;;;;N;;;;; +117D;HANGUL JUNGSEONG YEO-O;Lo;0;L;;;;;N;;;;; +117E;HANGUL JUNGSEONG YEO-U;Lo;0;L;;;;;N;;;;; +117F;HANGUL JUNGSEONG O-EO;Lo;0;L;;;;;N;;;;; +1180;HANGUL JUNGSEONG O-E;Lo;0;L;;;;;N;;;;; +1181;HANGUL JUNGSEONG O-YE;Lo;0;L;;;;;N;;;;; +1182;HANGUL JUNGSEONG O-O;Lo;0;L;;;;;N;;;;; +1183;HANGUL JUNGSEONG O-U;Lo;0;L;;;;;N;;;;; +1184;HANGUL JUNGSEONG YO-YA;Lo;0;L;;;;;N;;;;; +1185;HANGUL JUNGSEONG YO-YAE;Lo;0;L;;;;;N;;;;; +1186;HANGUL JUNGSEONG YO-YEO;Lo;0;L;;;;;N;;;;; +1187;HANGUL JUNGSEONG YO-O;Lo;0;L;;;;;N;;;;; +1188;HANGUL JUNGSEONG YO-I;Lo;0;L;;;;;N;;;;; +1189;HANGUL JUNGSEONG U-A;Lo;0;L;;;;;N;;;;; +118A;HANGUL JUNGSEONG U-AE;Lo;0;L;;;;;N;;;;; +118B;HANGUL JUNGSEONG U-EO-EU;Lo;0;L;;;;;N;;;;; +118C;HANGUL JUNGSEONG U-YE;Lo;0;L;;;;;N;;;;; +118D;HANGUL JUNGSEONG U-U;Lo;0;L;;;;;N;;;;; +118E;HANGUL JUNGSEONG YU-A;Lo;0;L;;;;;N;;;;; +118F;HANGUL JUNGSEONG YU-EO;Lo;0;L;;;;;N;;;;; +1190;HANGUL JUNGSEONG YU-E;Lo;0;L;;;;;N;;;;; +1191;HANGUL JUNGSEONG YU-YEO;Lo;0;L;;;;;N;;;;; +1192;HANGUL JUNGSEONG YU-YE;Lo;0;L;;;;;N;;;;; +1193;HANGUL JUNGSEONG YU-U;Lo;0;L;;;;;N;;;;; +1194;HANGUL JUNGSEONG YU-I;Lo;0;L;;;;;N;;;;; +1195;HANGUL JUNGSEONG EU-U;Lo;0;L;;;;;N;;;;; +1196;HANGUL JUNGSEONG EU-EU;Lo;0;L;;;;;N;;;;; +1197;HANGUL JUNGSEONG YI-U;Lo;0;L;;;;;N;;;;; +1198;HANGUL JUNGSEONG I-A;Lo;0;L;;;;;N;;;;; +1199;HANGUL JUNGSEONG I-YA;Lo;0;L;;;;;N;;;;; +119A;HANGUL JUNGSEONG I-O;Lo;0;L;;;;;N;;;;; +119B;HANGUL JUNGSEONG I-U;Lo;0;L;;;;;N;;;;; +119C;HANGUL JUNGSEONG I-EU;Lo;0;L;;;;;N;;;;; +119D;HANGUL JUNGSEONG I-ARAEA;Lo;0;L;;;;;N;;;;; +119E;HANGUL JUNGSEONG ARAEA;Lo;0;L;;;;;N;;;;; +119F;HANGUL JUNGSEONG ARAEA-EO;Lo;0;L;;;;;N;;;;; +11A0;HANGUL JUNGSEONG ARAEA-U;Lo;0;L;;;;;N;;;;; +11A1;HANGUL JUNGSEONG ARAEA-I;Lo;0;L;;;;;N;;;;; +11A2;HANGUL JUNGSEONG SSANGARAEA;Lo;0;L;;;;;N;;;;; +11A3;HANGUL JUNGSEONG A-EU;Lo;0;L;;;;;N;;;;; +11A4;HANGUL JUNGSEONG YA-U;Lo;0;L;;;;;N;;;;; +11A5;HANGUL JUNGSEONG YEO-YA;Lo;0;L;;;;;N;;;;; +11A6;HANGUL JUNGSEONG O-YA;Lo;0;L;;;;;N;;;;; +11A7;HANGUL JUNGSEONG O-YAE;Lo;0;L;;;;;N;;;;; +11A8;HANGUL JONGSEONG KIYEOK;Lo;0;L;;;;;N;;;;; +11A9;HANGUL JONGSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;;;; +11AA;HANGUL JONGSEONG KIYEOK-SIOS;Lo;0;L;;;;;N;;;;; +11AB;HANGUL JONGSEONG NIEUN;Lo;0;L;;;;;N;;;;; +11AC;HANGUL JONGSEONG NIEUN-CIEUC;Lo;0;L;;;;;N;;;;; +11AD;HANGUL JONGSEONG NIEUN-HIEUH;Lo;0;L;;;;;N;;;;; +11AE;HANGUL JONGSEONG TIKEUT;Lo;0;L;;;;;N;;;;; +11AF;HANGUL JONGSEONG RIEUL;Lo;0;L;;;;;N;;;;; +11B0;HANGUL JONGSEONG RIEUL-KIYEOK;Lo;0;L;;;;;N;;;;; +11B1;HANGUL JONGSEONG RIEUL-MIEUM;Lo;0;L;;;;;N;;;;; +11B2;HANGUL JONGSEONG RIEUL-PIEUP;Lo;0;L;;;;;N;;;;; +11B3;HANGUL JONGSEONG RIEUL-SIOS;Lo;0;L;;;;;N;;;;; +11B4;HANGUL JONGSEONG RIEUL-THIEUTH;Lo;0;L;;;;;N;;;;; +11B5;HANGUL JONGSEONG RIEUL-PHIEUPH;Lo;0;L;;;;;N;;;;; +11B6;HANGUL JONGSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;;;; +11B7;HANGUL JONGSEONG MIEUM;Lo;0;L;;;;;N;;;;; +11B8;HANGUL JONGSEONG PIEUP;Lo;0;L;;;;;N;;;;; +11B9;HANGUL JONGSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;;;; +11BA;HANGUL JONGSEONG SIOS;Lo;0;L;;;;;N;;;;; +11BB;HANGUL JONGSEONG SSANGSIOS;Lo;0;L;;;;;N;;;;; +11BC;HANGUL JONGSEONG IEUNG;Lo;0;L;;;;;N;;;;; +11BD;HANGUL JONGSEONG CIEUC;Lo;0;L;;;;;N;;;;; +11BE;HANGUL JONGSEONG CHIEUCH;Lo;0;L;;;;;N;;;;; +11BF;HANGUL JONGSEONG KHIEUKH;Lo;0;L;;;;;N;;;;; +11C0;HANGUL JONGSEONG THIEUTH;Lo;0;L;;;;;N;;;;; +11C1;HANGUL JONGSEONG PHIEUPH;Lo;0;L;;;;;N;;;;; +11C2;HANGUL JONGSEONG HIEUH;Lo;0;L;;;;;N;;;;; +11C3;HANGUL JONGSEONG KIYEOK-RIEUL;Lo;0;L;;;;;N;;;;; +11C4;HANGUL JONGSEONG KIYEOK-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; +11C5;HANGUL JONGSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;; +11C6;HANGUL JONGSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;; +11C7;HANGUL JONGSEONG NIEUN-SIOS;Lo;0;L;;;;;N;;;;; +11C8;HANGUL JONGSEONG NIEUN-PANSIOS;Lo;0;L;;;;;N;;;;; +11C9;HANGUL JONGSEONG NIEUN-THIEUTH;Lo;0;L;;;;;N;;;;; +11CA;HANGUL JONGSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;; +11CB;HANGUL JONGSEONG TIKEUT-RIEUL;Lo;0;L;;;;;N;;;;; +11CC;HANGUL JONGSEONG RIEUL-KIYEOK-SIOS;Lo;0;L;;;;;N;;;;; +11CD;HANGUL JONGSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;; +11CE;HANGUL JONGSEONG RIEUL-TIKEUT;Lo;0;L;;;;;N;;;;; +11CF;HANGUL JONGSEONG RIEUL-TIKEUT-HIEUH;Lo;0;L;;;;;N;;;;; +11D0;HANGUL JONGSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;; +11D1;HANGUL JONGSEONG RIEUL-MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;; +11D2;HANGUL JONGSEONG RIEUL-MIEUM-SIOS;Lo;0;L;;;;;N;;;;; +11D3;HANGUL JONGSEONG RIEUL-PIEUP-SIOS;Lo;0;L;;;;;N;;;;; +11D4;HANGUL JONGSEONG RIEUL-PIEUP-HIEUH;Lo;0;L;;;;;N;;;;; +11D5;HANGUL JONGSEONG RIEUL-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; +11D6;HANGUL JONGSEONG RIEUL-SSANGSIOS;Lo;0;L;;;;;N;;;;; +11D7;HANGUL JONGSEONG RIEUL-PANSIOS;Lo;0;L;;;;;N;;;;; +11D8;HANGUL JONGSEONG RIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;; +11D9;HANGUL JONGSEONG RIEUL-YEORINHIEUH;Lo;0;L;;;;;N;;;;; +11DA;HANGUL JONGSEONG MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;; +11DB;HANGUL JONGSEONG MIEUM-RIEUL;Lo;0;L;;;;;N;;;;; +11DC;HANGUL JONGSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;; +11DD;HANGUL JONGSEONG MIEUM-SIOS;Lo;0;L;;;;;N;;;;; +11DE;HANGUL JONGSEONG MIEUM-SSANGSIOS;Lo;0;L;;;;;N;;;;; +11DF;HANGUL JONGSEONG MIEUM-PANSIOS;Lo;0;L;;;;;N;;;;; +11E0;HANGUL JONGSEONG MIEUM-CHIEUCH;Lo;0;L;;;;;N;;;;; +11E1;HANGUL JONGSEONG MIEUM-HIEUH;Lo;0;L;;;;;N;;;;; +11E2;HANGUL JONGSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;; +11E3;HANGUL JONGSEONG PIEUP-RIEUL;Lo;0;L;;;;;N;;;;; +11E4;HANGUL JONGSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;; +11E5;HANGUL JONGSEONG PIEUP-HIEUH;Lo;0;L;;;;;N;;;;; +11E6;HANGUL JONGSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; +11E7;HANGUL JONGSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; +11E8;HANGUL JONGSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; +11E9;HANGUL JONGSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;; +11EA;HANGUL JONGSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;; +11EB;HANGUL JONGSEONG PANSIOS;Lo;0;L;;;;;N;;;;; +11EC;HANGUL JONGSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;; +11ED;HANGUL JONGSEONG IEUNG-SSANGKIYEOK;Lo;0;L;;;;;N;;;;; +11EE;HANGUL JONGSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;; +11EF;HANGUL JONGSEONG IEUNG-KHIEUKH;Lo;0;L;;;;;N;;;;; +11F0;HANGUL JONGSEONG YESIEUNG;Lo;0;L;;;;;N;;;;; +11F1;HANGUL JONGSEONG YESIEUNG-SIOS;Lo;0;L;;;;;N;;;;; +11F2;HANGUL JONGSEONG YESIEUNG-PANSIOS;Lo;0;L;;;;;N;;;;; +11F3;HANGUL JONGSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;; +11F4;HANGUL JONGSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;; +11F5;HANGUL JONGSEONG HIEUH-NIEUN;Lo;0;L;;;;;N;;;;; +11F6;HANGUL JONGSEONG HIEUH-RIEUL;Lo;0;L;;;;;N;;;;; +11F7;HANGUL JONGSEONG HIEUH-MIEUM;Lo;0;L;;;;;N;;;;; +11F8;HANGUL JONGSEONG HIEUH-PIEUP;Lo;0;L;;;;;N;;;;; +11F9;HANGUL JONGSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;; +11FA;HANGUL JONGSEONG KIYEOK-NIEUN;Lo;0;L;;;;;N;;;;; +11FB;HANGUL JONGSEONG KIYEOK-PIEUP;Lo;0;L;;;;;N;;;;; +11FC;HANGUL JONGSEONG KIYEOK-CHIEUCH;Lo;0;L;;;;;N;;;;; +11FD;HANGUL JONGSEONG KIYEOK-KHIEUKH;Lo;0;L;;;;;N;;;;; +11FE;HANGUL JONGSEONG KIYEOK-HIEUH;Lo;0;L;;;;;N;;;;; +11FF;HANGUL JONGSEONG SSANGNIEUN;Lo;0;L;;;;;N;;;;; +1200;ETHIOPIC SYLLABLE HA;Lo;0;L;;;;;N;;;;; +1201;ETHIOPIC SYLLABLE HU;Lo;0;L;;;;;N;;;;; +1202;ETHIOPIC SYLLABLE HI;Lo;0;L;;;;;N;;;;; +1203;ETHIOPIC SYLLABLE HAA;Lo;0;L;;;;;N;;;;; +1204;ETHIOPIC SYLLABLE HEE;Lo;0;L;;;;;N;;;;; +1205;ETHIOPIC SYLLABLE HE;Lo;0;L;;;;;N;;;;; +1206;ETHIOPIC SYLLABLE HO;Lo;0;L;;;;;N;;;;; +1207;ETHIOPIC SYLLABLE HOA;Lo;0;L;;;;;N;;;;; +1208;ETHIOPIC SYLLABLE LA;Lo;0;L;;;;;N;;;;; +1209;ETHIOPIC SYLLABLE LU;Lo;0;L;;;;;N;;;;; +120A;ETHIOPIC SYLLABLE LI;Lo;0;L;;;;;N;;;;; +120B;ETHIOPIC SYLLABLE LAA;Lo;0;L;;;;;N;;;;; +120C;ETHIOPIC SYLLABLE LEE;Lo;0;L;;;;;N;;;;; +120D;ETHIOPIC SYLLABLE LE;Lo;0;L;;;;;N;;;;; +120E;ETHIOPIC SYLLABLE LO;Lo;0;L;;;;;N;;;;; +120F;ETHIOPIC SYLLABLE LWA;Lo;0;L;;;;;N;;;;; +1210;ETHIOPIC SYLLABLE HHA;Lo;0;L;;;;;N;;;;; +1211;ETHIOPIC SYLLABLE HHU;Lo;0;L;;;;;N;;;;; +1212;ETHIOPIC SYLLABLE HHI;Lo;0;L;;;;;N;;;;; +1213;ETHIOPIC SYLLABLE HHAA;Lo;0;L;;;;;N;;;;; +1214;ETHIOPIC SYLLABLE HHEE;Lo;0;L;;;;;N;;;;; +1215;ETHIOPIC SYLLABLE HHE;Lo;0;L;;;;;N;;;;; +1216;ETHIOPIC SYLLABLE HHO;Lo;0;L;;;;;N;;;;; +1217;ETHIOPIC SYLLABLE HHWA;Lo;0;L;;;;;N;;;;; +1218;ETHIOPIC SYLLABLE MA;Lo;0;L;;;;;N;;;;; +1219;ETHIOPIC SYLLABLE MU;Lo;0;L;;;;;N;;;;; +121A;ETHIOPIC SYLLABLE MI;Lo;0;L;;;;;N;;;;; +121B;ETHIOPIC SYLLABLE MAA;Lo;0;L;;;;;N;;;;; +121C;ETHIOPIC SYLLABLE MEE;Lo;0;L;;;;;N;;;;; +121D;ETHIOPIC SYLLABLE ME;Lo;0;L;;;;;N;;;;; +121E;ETHIOPIC SYLLABLE MO;Lo;0;L;;;;;N;;;;; +121F;ETHIOPIC SYLLABLE MWA;Lo;0;L;;;;;N;;;;; +1220;ETHIOPIC SYLLABLE SZA;Lo;0;L;;;;;N;;;;; +1221;ETHIOPIC SYLLABLE SZU;Lo;0;L;;;;;N;;;;; +1222;ETHIOPIC SYLLABLE SZI;Lo;0;L;;;;;N;;;;; +1223;ETHIOPIC SYLLABLE SZAA;Lo;0;L;;;;;N;;;;; +1224;ETHIOPIC SYLLABLE SZEE;Lo;0;L;;;;;N;;;;; +1225;ETHIOPIC SYLLABLE SZE;Lo;0;L;;;;;N;;;;; +1226;ETHIOPIC SYLLABLE SZO;Lo;0;L;;;;;N;;;;; +1227;ETHIOPIC SYLLABLE SZWA;Lo;0;L;;;;;N;;;;; +1228;ETHIOPIC SYLLABLE RA;Lo;0;L;;;;;N;;;;; +1229;ETHIOPIC SYLLABLE RU;Lo;0;L;;;;;N;;;;; +122A;ETHIOPIC SYLLABLE RI;Lo;0;L;;;;;N;;;;; +122B;ETHIOPIC SYLLABLE RAA;Lo;0;L;;;;;N;;;;; +122C;ETHIOPIC SYLLABLE REE;Lo;0;L;;;;;N;;;;; +122D;ETHIOPIC SYLLABLE RE;Lo;0;L;;;;;N;;;;; +122E;ETHIOPIC SYLLABLE RO;Lo;0;L;;;;;N;;;;; +122F;ETHIOPIC SYLLABLE RWA;Lo;0;L;;;;;N;;;;; +1230;ETHIOPIC SYLLABLE SA;Lo;0;L;;;;;N;;;;; +1231;ETHIOPIC SYLLABLE SU;Lo;0;L;;;;;N;;;;; +1232;ETHIOPIC SYLLABLE SI;Lo;0;L;;;;;N;;;;; +1233;ETHIOPIC SYLLABLE SAA;Lo;0;L;;;;;N;;;;; +1234;ETHIOPIC SYLLABLE SEE;Lo;0;L;;;;;N;;;;; +1235;ETHIOPIC SYLLABLE SE;Lo;0;L;;;;;N;;;;; +1236;ETHIOPIC SYLLABLE SO;Lo;0;L;;;;;N;;;;; +1237;ETHIOPIC SYLLABLE SWA;Lo;0;L;;;;;N;;;;; +1238;ETHIOPIC SYLLABLE SHA;Lo;0;L;;;;;N;;;;; +1239;ETHIOPIC SYLLABLE SHU;Lo;0;L;;;;;N;;;;; +123A;ETHIOPIC SYLLABLE SHI;Lo;0;L;;;;;N;;;;; +123B;ETHIOPIC SYLLABLE SHAA;Lo;0;L;;;;;N;;;;; +123C;ETHIOPIC SYLLABLE SHEE;Lo;0;L;;;;;N;;;;; +123D;ETHIOPIC SYLLABLE SHE;Lo;0;L;;;;;N;;;;; +123E;ETHIOPIC SYLLABLE SHO;Lo;0;L;;;;;N;;;;; +123F;ETHIOPIC SYLLABLE SHWA;Lo;0;L;;;;;N;;;;; +1240;ETHIOPIC SYLLABLE QA;Lo;0;L;;;;;N;;;;; +1241;ETHIOPIC SYLLABLE QU;Lo;0;L;;;;;N;;;;; +1242;ETHIOPIC SYLLABLE QI;Lo;0;L;;;;;N;;;;; +1243;ETHIOPIC SYLLABLE QAA;Lo;0;L;;;;;N;;;;; +1244;ETHIOPIC SYLLABLE QEE;Lo;0;L;;;;;N;;;;; +1245;ETHIOPIC SYLLABLE QE;Lo;0;L;;;;;N;;;;; +1246;ETHIOPIC SYLLABLE QO;Lo;0;L;;;;;N;;;;; +1247;ETHIOPIC SYLLABLE QOA;Lo;0;L;;;;;N;;;;; +1248;ETHIOPIC SYLLABLE QWA;Lo;0;L;;;;;N;;;;; +124A;ETHIOPIC SYLLABLE QWI;Lo;0;L;;;;;N;;;;; +124B;ETHIOPIC SYLLABLE QWAA;Lo;0;L;;;;;N;;;;; +124C;ETHIOPIC SYLLABLE QWEE;Lo;0;L;;;;;N;;;;; +124D;ETHIOPIC SYLLABLE QWE;Lo;0;L;;;;;N;;;;; +1250;ETHIOPIC SYLLABLE QHA;Lo;0;L;;;;;N;;;;; +1251;ETHIOPIC SYLLABLE QHU;Lo;0;L;;;;;N;;;;; +1252;ETHIOPIC SYLLABLE QHI;Lo;0;L;;;;;N;;;;; +1253;ETHIOPIC SYLLABLE QHAA;Lo;0;L;;;;;N;;;;; +1254;ETHIOPIC SYLLABLE QHEE;Lo;0;L;;;;;N;;;;; +1255;ETHIOPIC SYLLABLE QHE;Lo;0;L;;;;;N;;;;; +1256;ETHIOPIC SYLLABLE QHO;Lo;0;L;;;;;N;;;;; +1258;ETHIOPIC SYLLABLE QHWA;Lo;0;L;;;;;N;;;;; +125A;ETHIOPIC SYLLABLE QHWI;Lo;0;L;;;;;N;;;;; +125B;ETHIOPIC SYLLABLE QHWAA;Lo;0;L;;;;;N;;;;; +125C;ETHIOPIC SYLLABLE QHWEE;Lo;0;L;;;;;N;;;;; +125D;ETHIOPIC SYLLABLE QHWE;Lo;0;L;;;;;N;;;;; +1260;ETHIOPIC SYLLABLE BA;Lo;0;L;;;;;N;;;;; +1261;ETHIOPIC SYLLABLE BU;Lo;0;L;;;;;N;;;;; +1262;ETHIOPIC SYLLABLE BI;Lo;0;L;;;;;N;;;;; +1263;ETHIOPIC SYLLABLE BAA;Lo;0;L;;;;;N;;;;; +1264;ETHIOPIC SYLLABLE BEE;Lo;0;L;;;;;N;;;;; +1265;ETHIOPIC SYLLABLE BE;Lo;0;L;;;;;N;;;;; +1266;ETHIOPIC SYLLABLE BO;Lo;0;L;;;;;N;;;;; +1267;ETHIOPIC SYLLABLE BWA;Lo;0;L;;;;;N;;;;; +1268;ETHIOPIC SYLLABLE VA;Lo;0;L;;;;;N;;;;; +1269;ETHIOPIC SYLLABLE VU;Lo;0;L;;;;;N;;;;; +126A;ETHIOPIC SYLLABLE VI;Lo;0;L;;;;;N;;;;; +126B;ETHIOPIC SYLLABLE VAA;Lo;0;L;;;;;N;;;;; +126C;ETHIOPIC SYLLABLE VEE;Lo;0;L;;;;;N;;;;; +126D;ETHIOPIC SYLLABLE VE;Lo;0;L;;;;;N;;;;; +126E;ETHIOPIC SYLLABLE VO;Lo;0;L;;;;;N;;;;; +126F;ETHIOPIC SYLLABLE VWA;Lo;0;L;;;;;N;;;;; +1270;ETHIOPIC SYLLABLE TA;Lo;0;L;;;;;N;;;;; +1271;ETHIOPIC SYLLABLE TU;Lo;0;L;;;;;N;;;;; +1272;ETHIOPIC SYLLABLE TI;Lo;0;L;;;;;N;;;;; +1273;ETHIOPIC SYLLABLE TAA;Lo;0;L;;;;;N;;;;; +1274;ETHIOPIC SYLLABLE TEE;Lo;0;L;;;;;N;;;;; +1275;ETHIOPIC SYLLABLE TE;Lo;0;L;;;;;N;;;;; +1276;ETHIOPIC SYLLABLE TO;Lo;0;L;;;;;N;;;;; +1277;ETHIOPIC SYLLABLE TWA;Lo;0;L;;;;;N;;;;; +1278;ETHIOPIC SYLLABLE CA;Lo;0;L;;;;;N;;;;; +1279;ETHIOPIC SYLLABLE CU;Lo;0;L;;;;;N;;;;; +127A;ETHIOPIC SYLLABLE CI;Lo;0;L;;;;;N;;;;; +127B;ETHIOPIC SYLLABLE CAA;Lo;0;L;;;;;N;;;;; +127C;ETHIOPIC SYLLABLE CEE;Lo;0;L;;;;;N;;;;; +127D;ETHIOPIC SYLLABLE CE;Lo;0;L;;;;;N;;;;; +127E;ETHIOPIC SYLLABLE CO;Lo;0;L;;;;;N;;;;; +127F;ETHIOPIC SYLLABLE CWA;Lo;0;L;;;;;N;;;;; +1280;ETHIOPIC SYLLABLE XA;Lo;0;L;;;;;N;;;;; +1281;ETHIOPIC SYLLABLE XU;Lo;0;L;;;;;N;;;;; +1282;ETHIOPIC SYLLABLE XI;Lo;0;L;;;;;N;;;;; +1283;ETHIOPIC SYLLABLE XAA;Lo;0;L;;;;;N;;;;; +1284;ETHIOPIC SYLLABLE XEE;Lo;0;L;;;;;N;;;;; +1285;ETHIOPIC SYLLABLE XE;Lo;0;L;;;;;N;;;;; +1286;ETHIOPIC SYLLABLE XO;Lo;0;L;;;;;N;;;;; +1287;ETHIOPIC SYLLABLE XOA;Lo;0;L;;;;;N;;;;; +1288;ETHIOPIC SYLLABLE XWA;Lo;0;L;;;;;N;;;;; +128A;ETHIOPIC SYLLABLE XWI;Lo;0;L;;;;;N;;;;; +128B;ETHIOPIC SYLLABLE XWAA;Lo;0;L;;;;;N;;;;; +128C;ETHIOPIC SYLLABLE XWEE;Lo;0;L;;;;;N;;;;; +128D;ETHIOPIC SYLLABLE XWE;Lo;0;L;;;;;N;;;;; +1290;ETHIOPIC SYLLABLE NA;Lo;0;L;;;;;N;;;;; +1291;ETHIOPIC SYLLABLE NU;Lo;0;L;;;;;N;;;;; +1292;ETHIOPIC SYLLABLE NI;Lo;0;L;;;;;N;;;;; +1293;ETHIOPIC SYLLABLE NAA;Lo;0;L;;;;;N;;;;; +1294;ETHIOPIC SYLLABLE NEE;Lo;0;L;;;;;N;;;;; +1295;ETHIOPIC SYLLABLE NE;Lo;0;L;;;;;N;;;;; +1296;ETHIOPIC SYLLABLE NO;Lo;0;L;;;;;N;;;;; +1297;ETHIOPIC SYLLABLE NWA;Lo;0;L;;;;;N;;;;; +1298;ETHIOPIC SYLLABLE NYA;Lo;0;L;;;;;N;;;;; +1299;ETHIOPIC SYLLABLE NYU;Lo;0;L;;;;;N;;;;; +129A;ETHIOPIC SYLLABLE NYI;Lo;0;L;;;;;N;;;;; +129B;ETHIOPIC SYLLABLE NYAA;Lo;0;L;;;;;N;;;;; +129C;ETHIOPIC SYLLABLE NYEE;Lo;0;L;;;;;N;;;;; +129D;ETHIOPIC SYLLABLE NYE;Lo;0;L;;;;;N;;;;; +129E;ETHIOPIC SYLLABLE NYO;Lo;0;L;;;;;N;;;;; +129F;ETHIOPIC SYLLABLE NYWA;Lo;0;L;;;;;N;;;;; +12A0;ETHIOPIC SYLLABLE GLOTTAL A;Lo;0;L;;;;;N;;;;; +12A1;ETHIOPIC SYLLABLE GLOTTAL U;Lo;0;L;;;;;N;;;;; +12A2;ETHIOPIC SYLLABLE GLOTTAL I;Lo;0;L;;;;;N;;;;; +12A3;ETHIOPIC SYLLABLE GLOTTAL AA;Lo;0;L;;;;;N;;;;; +12A4;ETHIOPIC SYLLABLE GLOTTAL EE;Lo;0;L;;;;;N;;;;; +12A5;ETHIOPIC SYLLABLE GLOTTAL E;Lo;0;L;;;;;N;;;;; +12A6;ETHIOPIC SYLLABLE GLOTTAL O;Lo;0;L;;;;;N;;;;; +12A7;ETHIOPIC SYLLABLE GLOTTAL WA;Lo;0;L;;;;;N;;;;; +12A8;ETHIOPIC SYLLABLE KA;Lo;0;L;;;;;N;;;;; +12A9;ETHIOPIC SYLLABLE KU;Lo;0;L;;;;;N;;;;; +12AA;ETHIOPIC SYLLABLE KI;Lo;0;L;;;;;N;;;;; +12AB;ETHIOPIC SYLLABLE KAA;Lo;0;L;;;;;N;;;;; +12AC;ETHIOPIC SYLLABLE KEE;Lo;0;L;;;;;N;;;;; +12AD;ETHIOPIC SYLLABLE KE;Lo;0;L;;;;;N;;;;; +12AE;ETHIOPIC SYLLABLE KO;Lo;0;L;;;;;N;;;;; +12AF;ETHIOPIC SYLLABLE KOA;Lo;0;L;;;;;N;;;;; +12B0;ETHIOPIC SYLLABLE KWA;Lo;0;L;;;;;N;;;;; +12B2;ETHIOPIC SYLLABLE KWI;Lo;0;L;;;;;N;;;;; +12B3;ETHIOPIC SYLLABLE KWAA;Lo;0;L;;;;;N;;;;; +12B4;ETHIOPIC SYLLABLE KWEE;Lo;0;L;;;;;N;;;;; +12B5;ETHIOPIC SYLLABLE KWE;Lo;0;L;;;;;N;;;;; +12B8;ETHIOPIC SYLLABLE KXA;Lo;0;L;;;;;N;;;;; +12B9;ETHIOPIC SYLLABLE KXU;Lo;0;L;;;;;N;;;;; +12BA;ETHIOPIC SYLLABLE KXI;Lo;0;L;;;;;N;;;;; +12BB;ETHIOPIC SYLLABLE KXAA;Lo;0;L;;;;;N;;;;; +12BC;ETHIOPIC SYLLABLE KXEE;Lo;0;L;;;;;N;;;;; +12BD;ETHIOPIC SYLLABLE KXE;Lo;0;L;;;;;N;;;;; +12BE;ETHIOPIC SYLLABLE KXO;Lo;0;L;;;;;N;;;;; +12C0;ETHIOPIC SYLLABLE KXWA;Lo;0;L;;;;;N;;;;; +12C2;ETHIOPIC SYLLABLE KXWI;Lo;0;L;;;;;N;;;;; +12C3;ETHIOPIC SYLLABLE KXWAA;Lo;0;L;;;;;N;;;;; +12C4;ETHIOPIC SYLLABLE KXWEE;Lo;0;L;;;;;N;;;;; +12C5;ETHIOPIC SYLLABLE KXWE;Lo;0;L;;;;;N;;;;; +12C8;ETHIOPIC SYLLABLE WA;Lo;0;L;;;;;N;;;;; +12C9;ETHIOPIC SYLLABLE WU;Lo;0;L;;;;;N;;;;; +12CA;ETHIOPIC SYLLABLE WI;Lo;0;L;;;;;N;;;;; +12CB;ETHIOPIC SYLLABLE WAA;Lo;0;L;;;;;N;;;;; +12CC;ETHIOPIC SYLLABLE WEE;Lo;0;L;;;;;N;;;;; +12CD;ETHIOPIC SYLLABLE WE;Lo;0;L;;;;;N;;;;; +12CE;ETHIOPIC SYLLABLE WO;Lo;0;L;;;;;N;;;;; +12CF;ETHIOPIC SYLLABLE WOA;Lo;0;L;;;;;N;;;;; +12D0;ETHIOPIC SYLLABLE PHARYNGEAL A;Lo;0;L;;;;;N;;;;; +12D1;ETHIOPIC SYLLABLE PHARYNGEAL U;Lo;0;L;;;;;N;;;;; +12D2;ETHIOPIC SYLLABLE PHARYNGEAL I;Lo;0;L;;;;;N;;;;; +12D3;ETHIOPIC SYLLABLE PHARYNGEAL AA;Lo;0;L;;;;;N;;;;; +12D4;ETHIOPIC SYLLABLE PHARYNGEAL EE;Lo;0;L;;;;;N;;;;; +12D5;ETHIOPIC SYLLABLE PHARYNGEAL E;Lo;0;L;;;;;N;;;;; +12D6;ETHIOPIC SYLLABLE PHARYNGEAL O;Lo;0;L;;;;;N;;;;; +12D8;ETHIOPIC SYLLABLE ZA;Lo;0;L;;;;;N;;;;; +12D9;ETHIOPIC SYLLABLE ZU;Lo;0;L;;;;;N;;;;; +12DA;ETHIOPIC SYLLABLE ZI;Lo;0;L;;;;;N;;;;; +12DB;ETHIOPIC SYLLABLE ZAA;Lo;0;L;;;;;N;;;;; +12DC;ETHIOPIC SYLLABLE ZEE;Lo;0;L;;;;;N;;;;; +12DD;ETHIOPIC SYLLABLE ZE;Lo;0;L;;;;;N;;;;; +12DE;ETHIOPIC SYLLABLE ZO;Lo;0;L;;;;;N;;;;; +12DF;ETHIOPIC SYLLABLE ZWA;Lo;0;L;;;;;N;;;;; +12E0;ETHIOPIC SYLLABLE ZHA;Lo;0;L;;;;;N;;;;; +12E1;ETHIOPIC SYLLABLE ZHU;Lo;0;L;;;;;N;;;;; +12E2;ETHIOPIC SYLLABLE ZHI;Lo;0;L;;;;;N;;;;; +12E3;ETHIOPIC SYLLABLE ZHAA;Lo;0;L;;;;;N;;;;; +12E4;ETHIOPIC SYLLABLE ZHEE;Lo;0;L;;;;;N;;;;; +12E5;ETHIOPIC SYLLABLE ZHE;Lo;0;L;;;;;N;;;;; +12E6;ETHIOPIC SYLLABLE ZHO;Lo;0;L;;;;;N;;;;; +12E7;ETHIOPIC SYLLABLE ZHWA;Lo;0;L;;;;;N;;;;; +12E8;ETHIOPIC SYLLABLE YA;Lo;0;L;;;;;N;;;;; +12E9;ETHIOPIC SYLLABLE YU;Lo;0;L;;;;;N;;;;; +12EA;ETHIOPIC SYLLABLE YI;Lo;0;L;;;;;N;;;;; +12EB;ETHIOPIC SYLLABLE YAA;Lo;0;L;;;;;N;;;;; +12EC;ETHIOPIC SYLLABLE YEE;Lo;0;L;;;;;N;;;;; +12ED;ETHIOPIC SYLLABLE YE;Lo;0;L;;;;;N;;;;; +12EE;ETHIOPIC SYLLABLE YO;Lo;0;L;;;;;N;;;;; +12EF;ETHIOPIC SYLLABLE YOA;Lo;0;L;;;;;N;;;;; +12F0;ETHIOPIC SYLLABLE DA;Lo;0;L;;;;;N;;;;; +12F1;ETHIOPIC SYLLABLE DU;Lo;0;L;;;;;N;;;;; +12F2;ETHIOPIC SYLLABLE DI;Lo;0;L;;;;;N;;;;; +12F3;ETHIOPIC SYLLABLE DAA;Lo;0;L;;;;;N;;;;; +12F4;ETHIOPIC SYLLABLE DEE;Lo;0;L;;;;;N;;;;; +12F5;ETHIOPIC SYLLABLE DE;Lo;0;L;;;;;N;;;;; +12F6;ETHIOPIC SYLLABLE DO;Lo;0;L;;;;;N;;;;; +12F7;ETHIOPIC SYLLABLE DWA;Lo;0;L;;;;;N;;;;; +12F8;ETHIOPIC SYLLABLE DDA;Lo;0;L;;;;;N;;;;; +12F9;ETHIOPIC SYLLABLE DDU;Lo;0;L;;;;;N;;;;; +12FA;ETHIOPIC SYLLABLE DDI;Lo;0;L;;;;;N;;;;; +12FB;ETHIOPIC SYLLABLE DDAA;Lo;0;L;;;;;N;;;;; +12FC;ETHIOPIC SYLLABLE DDEE;Lo;0;L;;;;;N;;;;; +12FD;ETHIOPIC SYLLABLE DDE;Lo;0;L;;;;;N;;;;; +12FE;ETHIOPIC SYLLABLE DDO;Lo;0;L;;;;;N;;;;; +12FF;ETHIOPIC SYLLABLE DDWA;Lo;0;L;;;;;N;;;;; +1300;ETHIOPIC SYLLABLE JA;Lo;0;L;;;;;N;;;;; +1301;ETHIOPIC SYLLABLE JU;Lo;0;L;;;;;N;;;;; +1302;ETHIOPIC SYLLABLE JI;Lo;0;L;;;;;N;;;;; +1303;ETHIOPIC SYLLABLE JAA;Lo;0;L;;;;;N;;;;; +1304;ETHIOPIC SYLLABLE JEE;Lo;0;L;;;;;N;;;;; +1305;ETHIOPIC SYLLABLE JE;Lo;0;L;;;;;N;;;;; +1306;ETHIOPIC SYLLABLE JO;Lo;0;L;;;;;N;;;;; +1307;ETHIOPIC SYLLABLE JWA;Lo;0;L;;;;;N;;;;; +1308;ETHIOPIC SYLLABLE GA;Lo;0;L;;;;;N;;;;; +1309;ETHIOPIC SYLLABLE GU;Lo;0;L;;;;;N;;;;; +130A;ETHIOPIC SYLLABLE GI;Lo;0;L;;;;;N;;;;; +130B;ETHIOPIC SYLLABLE GAA;Lo;0;L;;;;;N;;;;; +130C;ETHIOPIC SYLLABLE GEE;Lo;0;L;;;;;N;;;;; +130D;ETHIOPIC SYLLABLE GE;Lo;0;L;;;;;N;;;;; +130E;ETHIOPIC SYLLABLE GO;Lo;0;L;;;;;N;;;;; +130F;ETHIOPIC SYLLABLE GOA;Lo;0;L;;;;;N;;;;; +1310;ETHIOPIC SYLLABLE GWA;Lo;0;L;;;;;N;;;;; +1312;ETHIOPIC SYLLABLE GWI;Lo;0;L;;;;;N;;;;; +1313;ETHIOPIC SYLLABLE GWAA;Lo;0;L;;;;;N;;;;; +1314;ETHIOPIC SYLLABLE GWEE;Lo;0;L;;;;;N;;;;; +1315;ETHIOPIC SYLLABLE GWE;Lo;0;L;;;;;N;;;;; +1318;ETHIOPIC SYLLABLE GGA;Lo;0;L;;;;;N;;;;; +1319;ETHIOPIC SYLLABLE GGU;Lo;0;L;;;;;N;;;;; +131A;ETHIOPIC SYLLABLE GGI;Lo;0;L;;;;;N;;;;; +131B;ETHIOPIC SYLLABLE GGAA;Lo;0;L;;;;;N;;;;; +131C;ETHIOPIC SYLLABLE GGEE;Lo;0;L;;;;;N;;;;; +131D;ETHIOPIC SYLLABLE GGE;Lo;0;L;;;;;N;;;;; +131E;ETHIOPIC SYLLABLE GGO;Lo;0;L;;;;;N;;;;; +131F;ETHIOPIC SYLLABLE GGWAA;Lo;0;L;;;;;N;;;;; +1320;ETHIOPIC SYLLABLE THA;Lo;0;L;;;;;N;;;;; +1321;ETHIOPIC SYLLABLE THU;Lo;0;L;;;;;N;;;;; +1322;ETHIOPIC SYLLABLE THI;Lo;0;L;;;;;N;;;;; +1323;ETHIOPIC SYLLABLE THAA;Lo;0;L;;;;;N;;;;; +1324;ETHIOPIC SYLLABLE THEE;Lo;0;L;;;;;N;;;;; +1325;ETHIOPIC SYLLABLE THE;Lo;0;L;;;;;N;;;;; +1326;ETHIOPIC SYLLABLE THO;Lo;0;L;;;;;N;;;;; +1327;ETHIOPIC SYLLABLE THWA;Lo;0;L;;;;;N;;;;; +1328;ETHIOPIC SYLLABLE CHA;Lo;0;L;;;;;N;;;;; +1329;ETHIOPIC SYLLABLE CHU;Lo;0;L;;;;;N;;;;; +132A;ETHIOPIC SYLLABLE CHI;Lo;0;L;;;;;N;;;;; +132B;ETHIOPIC SYLLABLE CHAA;Lo;0;L;;;;;N;;;;; +132C;ETHIOPIC SYLLABLE CHEE;Lo;0;L;;;;;N;;;;; +132D;ETHIOPIC SYLLABLE CHE;Lo;0;L;;;;;N;;;;; +132E;ETHIOPIC SYLLABLE CHO;Lo;0;L;;;;;N;;;;; +132F;ETHIOPIC SYLLABLE CHWA;Lo;0;L;;;;;N;;;;; +1330;ETHIOPIC SYLLABLE PHA;Lo;0;L;;;;;N;;;;; +1331;ETHIOPIC SYLLABLE PHU;Lo;0;L;;;;;N;;;;; +1332;ETHIOPIC SYLLABLE PHI;Lo;0;L;;;;;N;;;;; +1333;ETHIOPIC SYLLABLE PHAA;Lo;0;L;;;;;N;;;;; +1334;ETHIOPIC SYLLABLE PHEE;Lo;0;L;;;;;N;;;;; +1335;ETHIOPIC SYLLABLE PHE;Lo;0;L;;;;;N;;;;; +1336;ETHIOPIC SYLLABLE PHO;Lo;0;L;;;;;N;;;;; +1337;ETHIOPIC SYLLABLE PHWA;Lo;0;L;;;;;N;;;;; +1338;ETHIOPIC SYLLABLE TSA;Lo;0;L;;;;;N;;;;; +1339;ETHIOPIC SYLLABLE TSU;Lo;0;L;;;;;N;;;;; +133A;ETHIOPIC SYLLABLE TSI;Lo;0;L;;;;;N;;;;; +133B;ETHIOPIC SYLLABLE TSAA;Lo;0;L;;;;;N;;;;; +133C;ETHIOPIC SYLLABLE TSEE;Lo;0;L;;;;;N;;;;; +133D;ETHIOPIC SYLLABLE TSE;Lo;0;L;;;;;N;;;;; +133E;ETHIOPIC SYLLABLE TSO;Lo;0;L;;;;;N;;;;; +133F;ETHIOPIC SYLLABLE TSWA;Lo;0;L;;;;;N;;;;; +1340;ETHIOPIC SYLLABLE TZA;Lo;0;L;;;;;N;;;;; +1341;ETHIOPIC SYLLABLE TZU;Lo;0;L;;;;;N;;;;; +1342;ETHIOPIC SYLLABLE TZI;Lo;0;L;;;;;N;;;;; +1343;ETHIOPIC SYLLABLE TZAA;Lo;0;L;;;;;N;;;;; +1344;ETHIOPIC SYLLABLE TZEE;Lo;0;L;;;;;N;;;;; +1345;ETHIOPIC SYLLABLE TZE;Lo;0;L;;;;;N;;;;; +1346;ETHIOPIC SYLLABLE TZO;Lo;0;L;;;;;N;;;;; +1347;ETHIOPIC SYLLABLE TZOA;Lo;0;L;;;;;N;;;;; +1348;ETHIOPIC SYLLABLE FA;Lo;0;L;;;;;N;;;;; +1349;ETHIOPIC SYLLABLE FU;Lo;0;L;;;;;N;;;;; +134A;ETHIOPIC SYLLABLE FI;Lo;0;L;;;;;N;;;;; +134B;ETHIOPIC SYLLABLE FAA;Lo;0;L;;;;;N;;;;; +134C;ETHIOPIC SYLLABLE FEE;Lo;0;L;;;;;N;;;;; +134D;ETHIOPIC SYLLABLE FE;Lo;0;L;;;;;N;;;;; +134E;ETHIOPIC SYLLABLE FO;Lo;0;L;;;;;N;;;;; +134F;ETHIOPIC SYLLABLE FWA;Lo;0;L;;;;;N;;;;; +1350;ETHIOPIC SYLLABLE PA;Lo;0;L;;;;;N;;;;; +1351;ETHIOPIC SYLLABLE PU;Lo;0;L;;;;;N;;;;; +1352;ETHIOPIC SYLLABLE PI;Lo;0;L;;;;;N;;;;; +1353;ETHIOPIC SYLLABLE PAA;Lo;0;L;;;;;N;;;;; +1354;ETHIOPIC SYLLABLE PEE;Lo;0;L;;;;;N;;;;; +1355;ETHIOPIC SYLLABLE PE;Lo;0;L;;;;;N;;;;; +1356;ETHIOPIC SYLLABLE PO;Lo;0;L;;;;;N;;;;; +1357;ETHIOPIC SYLLABLE PWA;Lo;0;L;;;;;N;;;;; +1358;ETHIOPIC SYLLABLE RYA;Lo;0;L;;;;;N;;;;; +1359;ETHIOPIC SYLLABLE MYA;Lo;0;L;;;;;N;;;;; +135A;ETHIOPIC SYLLABLE FYA;Lo;0;L;;;;;N;;;;; +135D;ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK;Mn;230;NSM;;;;;N;;;;; +135E;ETHIOPIC COMBINING VOWEL LENGTH MARK;Mn;230;NSM;;;;;N;;;;; +135F;ETHIOPIC COMBINING GEMINATION MARK;Mn;230;NSM;;;;;N;;;;; +1360;ETHIOPIC SECTION MARK;Po;0;L;;;;;N;;;;; +1361;ETHIOPIC WORDSPACE;Po;0;L;;;;;N;;;;; +1362;ETHIOPIC FULL STOP;Po;0;L;;;;;N;;;;; +1363;ETHIOPIC COMMA;Po;0;L;;;;;N;;;;; +1364;ETHIOPIC SEMICOLON;Po;0;L;;;;;N;;;;; +1365;ETHIOPIC COLON;Po;0;L;;;;;N;;;;; +1366;ETHIOPIC PREFACE COLON;Po;0;L;;;;;N;;;;; +1367;ETHIOPIC QUESTION MARK;Po;0;L;;;;;N;;;;; +1368;ETHIOPIC PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;; +1369;ETHIOPIC DIGIT ONE;No;0;L;;;1;1;N;;;;; +136A;ETHIOPIC DIGIT TWO;No;0;L;;;2;2;N;;;;; +136B;ETHIOPIC DIGIT THREE;No;0;L;;;3;3;N;;;;; +136C;ETHIOPIC DIGIT FOUR;No;0;L;;;4;4;N;;;;; +136D;ETHIOPIC DIGIT FIVE;No;0;L;;;5;5;N;;;;; +136E;ETHIOPIC DIGIT SIX;No;0;L;;;6;6;N;;;;; +136F;ETHIOPIC DIGIT SEVEN;No;0;L;;;7;7;N;;;;; +1370;ETHIOPIC DIGIT EIGHT;No;0;L;;;8;8;N;;;;; +1371;ETHIOPIC DIGIT NINE;No;0;L;;;9;9;N;;;;; +1372;ETHIOPIC NUMBER TEN;No;0;L;;;;10;N;;;;; +1373;ETHIOPIC NUMBER TWENTY;No;0;L;;;;20;N;;;;; +1374;ETHIOPIC NUMBER THIRTY;No;0;L;;;;30;N;;;;; +1375;ETHIOPIC NUMBER FORTY;No;0;L;;;;40;N;;;;; +1376;ETHIOPIC NUMBER FIFTY;No;0;L;;;;50;N;;;;; +1377;ETHIOPIC NUMBER SIXTY;No;0;L;;;;60;N;;;;; +1378;ETHIOPIC NUMBER SEVENTY;No;0;L;;;;70;N;;;;; +1379;ETHIOPIC NUMBER EIGHTY;No;0;L;;;;80;N;;;;; +137A;ETHIOPIC NUMBER NINETY;No;0;L;;;;90;N;;;;; +137B;ETHIOPIC NUMBER HUNDRED;No;0;L;;;;100;N;;;;; +137C;ETHIOPIC NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;; +1380;ETHIOPIC SYLLABLE SEBATBEIT MWA;Lo;0;L;;;;;N;;;;; +1381;ETHIOPIC SYLLABLE MWI;Lo;0;L;;;;;N;;;;; +1382;ETHIOPIC SYLLABLE MWEE;Lo;0;L;;;;;N;;;;; +1383;ETHIOPIC SYLLABLE MWE;Lo;0;L;;;;;N;;;;; +1384;ETHIOPIC SYLLABLE SEBATBEIT BWA;Lo;0;L;;;;;N;;;;; +1385;ETHIOPIC SYLLABLE BWI;Lo;0;L;;;;;N;;;;; +1386;ETHIOPIC SYLLABLE BWEE;Lo;0;L;;;;;N;;;;; +1387;ETHIOPIC SYLLABLE BWE;Lo;0;L;;;;;N;;;;; +1388;ETHIOPIC SYLLABLE SEBATBEIT FWA;Lo;0;L;;;;;N;;;;; +1389;ETHIOPIC SYLLABLE FWI;Lo;0;L;;;;;N;;;;; +138A;ETHIOPIC SYLLABLE FWEE;Lo;0;L;;;;;N;;;;; +138B;ETHIOPIC SYLLABLE FWE;Lo;0;L;;;;;N;;;;; +138C;ETHIOPIC SYLLABLE SEBATBEIT PWA;Lo;0;L;;;;;N;;;;; +138D;ETHIOPIC SYLLABLE PWI;Lo;0;L;;;;;N;;;;; +138E;ETHIOPIC SYLLABLE PWEE;Lo;0;L;;;;;N;;;;; +138F;ETHIOPIC SYLLABLE PWE;Lo;0;L;;;;;N;;;;; +1390;ETHIOPIC TONAL MARK YIZET;So;0;ON;;;;;N;;;;; +1391;ETHIOPIC TONAL MARK DERET;So;0;ON;;;;;N;;;;; +1392;ETHIOPIC TONAL MARK RIKRIK;So;0;ON;;;;;N;;;;; +1393;ETHIOPIC TONAL MARK SHORT RIKRIK;So;0;ON;;;;;N;;;;; +1394;ETHIOPIC TONAL MARK DIFAT;So;0;ON;;;;;N;;;;; +1395;ETHIOPIC TONAL MARK KENAT;So;0;ON;;;;;N;;;;; +1396;ETHIOPIC TONAL MARK CHIRET;So;0;ON;;;;;N;;;;; +1397;ETHIOPIC TONAL MARK HIDET;So;0;ON;;;;;N;;;;; +1398;ETHIOPIC TONAL MARK DERET-HIDET;So;0;ON;;;;;N;;;;; +1399;ETHIOPIC TONAL MARK KURT;So;0;ON;;;;;N;;;;; +13A0;CHEROKEE LETTER A;Lu;0;L;;;;;N;;;;AB70; +13A1;CHEROKEE LETTER E;Lu;0;L;;;;;N;;;;AB71; +13A2;CHEROKEE LETTER I;Lu;0;L;;;;;N;;;;AB72; +13A3;CHEROKEE LETTER O;Lu;0;L;;;;;N;;;;AB73; +13A4;CHEROKEE LETTER U;Lu;0;L;;;;;N;;;;AB74; +13A5;CHEROKEE LETTER V;Lu;0;L;;;;;N;;;;AB75; +13A6;CHEROKEE LETTER GA;Lu;0;L;;;;;N;;;;AB76; +13A7;CHEROKEE LETTER KA;Lu;0;L;;;;;N;;;;AB77; +13A8;CHEROKEE LETTER GE;Lu;0;L;;;;;N;;;;AB78; +13A9;CHEROKEE LETTER GI;Lu;0;L;;;;;N;;;;AB79; +13AA;CHEROKEE LETTER GO;Lu;0;L;;;;;N;;;;AB7A; +13AB;CHEROKEE LETTER GU;Lu;0;L;;;;;N;;;;AB7B; +13AC;CHEROKEE LETTER GV;Lu;0;L;;;;;N;;;;AB7C; +13AD;CHEROKEE LETTER HA;Lu;0;L;;;;;N;;;;AB7D; +13AE;CHEROKEE LETTER HE;Lu;0;L;;;;;N;;;;AB7E; +13AF;CHEROKEE LETTER HI;Lu;0;L;;;;;N;;;;AB7F; +13B0;CHEROKEE LETTER HO;Lu;0;L;;;;;N;;;;AB80; +13B1;CHEROKEE LETTER HU;Lu;0;L;;;;;N;;;;AB81; +13B2;CHEROKEE LETTER HV;Lu;0;L;;;;;N;;;;AB82; +13B3;CHEROKEE LETTER LA;Lu;0;L;;;;;N;;;;AB83; +13B4;CHEROKEE LETTER LE;Lu;0;L;;;;;N;;;;AB84; +13B5;CHEROKEE LETTER LI;Lu;0;L;;;;;N;;;;AB85; +13B6;CHEROKEE LETTER LO;Lu;0;L;;;;;N;;;;AB86; +13B7;CHEROKEE LETTER LU;Lu;0;L;;;;;N;;;;AB87; +13B8;CHEROKEE LETTER LV;Lu;0;L;;;;;N;;;;AB88; +13B9;CHEROKEE LETTER MA;Lu;0;L;;;;;N;;;;AB89; +13BA;CHEROKEE LETTER ME;Lu;0;L;;;;;N;;;;AB8A; +13BB;CHEROKEE LETTER MI;Lu;0;L;;;;;N;;;;AB8B; +13BC;CHEROKEE LETTER MO;Lu;0;L;;;;;N;;;;AB8C; +13BD;CHEROKEE LETTER MU;Lu;0;L;;;;;N;;;;AB8D; +13BE;CHEROKEE LETTER NA;Lu;0;L;;;;;N;;;;AB8E; +13BF;CHEROKEE LETTER HNA;Lu;0;L;;;;;N;;;;AB8F; +13C0;CHEROKEE LETTER NAH;Lu;0;L;;;;;N;;;;AB90; +13C1;CHEROKEE LETTER NE;Lu;0;L;;;;;N;;;;AB91; +13C2;CHEROKEE LETTER NI;Lu;0;L;;;;;N;;;;AB92; +13C3;CHEROKEE LETTER NO;Lu;0;L;;;;;N;;;;AB93; +13C4;CHEROKEE LETTER NU;Lu;0;L;;;;;N;;;;AB94; +13C5;CHEROKEE LETTER NV;Lu;0;L;;;;;N;;;;AB95; +13C6;CHEROKEE LETTER QUA;Lu;0;L;;;;;N;;;;AB96; +13C7;CHEROKEE LETTER QUE;Lu;0;L;;;;;N;;;;AB97; +13C8;CHEROKEE LETTER QUI;Lu;0;L;;;;;N;;;;AB98; +13C9;CHEROKEE LETTER QUO;Lu;0;L;;;;;N;;;;AB99; +13CA;CHEROKEE LETTER QUU;Lu;0;L;;;;;N;;;;AB9A; +13CB;CHEROKEE LETTER QUV;Lu;0;L;;;;;N;;;;AB9B; +13CC;CHEROKEE LETTER SA;Lu;0;L;;;;;N;;;;AB9C; +13CD;CHEROKEE LETTER S;Lu;0;L;;;;;N;;;;AB9D; +13CE;CHEROKEE LETTER SE;Lu;0;L;;;;;N;;;;AB9E; +13CF;CHEROKEE LETTER SI;Lu;0;L;;;;;N;;;;AB9F; +13D0;CHEROKEE LETTER SO;Lu;0;L;;;;;N;;;;ABA0; +13D1;CHEROKEE LETTER SU;Lu;0;L;;;;;N;;;;ABA1; +13D2;CHEROKEE LETTER SV;Lu;0;L;;;;;N;;;;ABA2; +13D3;CHEROKEE LETTER DA;Lu;0;L;;;;;N;;;;ABA3; +13D4;CHEROKEE LETTER TA;Lu;0;L;;;;;N;;;;ABA4; +13D5;CHEROKEE LETTER DE;Lu;0;L;;;;;N;;;;ABA5; +13D6;CHEROKEE LETTER TE;Lu;0;L;;;;;N;;;;ABA6; +13D7;CHEROKEE LETTER DI;Lu;0;L;;;;;N;;;;ABA7; +13D8;CHEROKEE LETTER TI;Lu;0;L;;;;;N;;;;ABA8; +13D9;CHEROKEE LETTER DO;Lu;0;L;;;;;N;;;;ABA9; +13DA;CHEROKEE LETTER DU;Lu;0;L;;;;;N;;;;ABAA; +13DB;CHEROKEE LETTER DV;Lu;0;L;;;;;N;;;;ABAB; +13DC;CHEROKEE LETTER DLA;Lu;0;L;;;;;N;;;;ABAC; +13DD;CHEROKEE LETTER TLA;Lu;0;L;;;;;N;;;;ABAD; +13DE;CHEROKEE LETTER TLE;Lu;0;L;;;;;N;;;;ABAE; +13DF;CHEROKEE LETTER TLI;Lu;0;L;;;;;N;;;;ABAF; +13E0;CHEROKEE LETTER TLO;Lu;0;L;;;;;N;;;;ABB0; +13E1;CHEROKEE LETTER TLU;Lu;0;L;;;;;N;;;;ABB1; +13E2;CHEROKEE LETTER TLV;Lu;0;L;;;;;N;;;;ABB2; +13E3;CHEROKEE LETTER TSA;Lu;0;L;;;;;N;;;;ABB3; +13E4;CHEROKEE LETTER TSE;Lu;0;L;;;;;N;;;;ABB4; +13E5;CHEROKEE LETTER TSI;Lu;0;L;;;;;N;;;;ABB5; +13E6;CHEROKEE LETTER TSO;Lu;0;L;;;;;N;;;;ABB6; +13E7;CHEROKEE LETTER TSU;Lu;0;L;;;;;N;;;;ABB7; +13E8;CHEROKEE LETTER TSV;Lu;0;L;;;;;N;;;;ABB8; +13E9;CHEROKEE LETTER WA;Lu;0;L;;;;;N;;;;ABB9; +13EA;CHEROKEE LETTER WE;Lu;0;L;;;;;N;;;;ABBA; +13EB;CHEROKEE LETTER WI;Lu;0;L;;;;;N;;;;ABBB; +13EC;CHEROKEE LETTER WO;Lu;0;L;;;;;N;;;;ABBC; +13ED;CHEROKEE LETTER WU;Lu;0;L;;;;;N;;;;ABBD; +13EE;CHEROKEE LETTER WV;Lu;0;L;;;;;N;;;;ABBE; +13EF;CHEROKEE LETTER YA;Lu;0;L;;;;;N;;;;ABBF; +13F0;CHEROKEE LETTER YE;Lu;0;L;;;;;N;;;;13F8; +13F1;CHEROKEE LETTER YI;Lu;0;L;;;;;N;;;;13F9; +13F2;CHEROKEE LETTER YO;Lu;0;L;;;;;N;;;;13FA; +13F3;CHEROKEE LETTER YU;Lu;0;L;;;;;N;;;;13FB; +13F4;CHEROKEE LETTER YV;Lu;0;L;;;;;N;;;;13FC; +13F5;CHEROKEE LETTER MV;Lu;0;L;;;;;N;;;;13FD; +13F8;CHEROKEE SMALL LETTER YE;Ll;0;L;;;;;N;;;13F0;;13F0 +13F9;CHEROKEE SMALL LETTER YI;Ll;0;L;;;;;N;;;13F1;;13F1 +13FA;CHEROKEE SMALL LETTER YO;Ll;0;L;;;;;N;;;13F2;;13F2 +13FB;CHEROKEE SMALL LETTER YU;Ll;0;L;;;;;N;;;13F3;;13F3 +13FC;CHEROKEE SMALL LETTER YV;Ll;0;L;;;;;N;;;13F4;;13F4 +13FD;CHEROKEE SMALL LETTER MV;Ll;0;L;;;;;N;;;13F5;;13F5 +1400;CANADIAN SYLLABICS HYPHEN;Pd;0;ON;;;;;N;;;;; +1401;CANADIAN SYLLABICS E;Lo;0;L;;;;;N;;;;; +1402;CANADIAN SYLLABICS AAI;Lo;0;L;;;;;N;;;;; +1403;CANADIAN SYLLABICS I;Lo;0;L;;;;;N;;;;; +1404;CANADIAN SYLLABICS II;Lo;0;L;;;;;N;;;;; +1405;CANADIAN SYLLABICS O;Lo;0;L;;;;;N;;;;; +1406;CANADIAN SYLLABICS OO;Lo;0;L;;;;;N;;;;; +1407;CANADIAN SYLLABICS Y-CREE OO;Lo;0;L;;;;;N;;;;; +1408;CANADIAN SYLLABICS CARRIER EE;Lo;0;L;;;;;N;;;;; +1409;CANADIAN SYLLABICS CARRIER I;Lo;0;L;;;;;N;;;;; +140A;CANADIAN SYLLABICS A;Lo;0;L;;;;;N;;;;; +140B;CANADIAN SYLLABICS AA;Lo;0;L;;;;;N;;;;; +140C;CANADIAN SYLLABICS WE;Lo;0;L;;;;;N;;;;; +140D;CANADIAN SYLLABICS WEST-CREE WE;Lo;0;L;;;;;N;;;;; +140E;CANADIAN SYLLABICS WI;Lo;0;L;;;;;N;;;;; +140F;CANADIAN SYLLABICS WEST-CREE WI;Lo;0;L;;;;;N;;;;; +1410;CANADIAN SYLLABICS WII;Lo;0;L;;;;;N;;;;; +1411;CANADIAN SYLLABICS WEST-CREE WII;Lo;0;L;;;;;N;;;;; +1412;CANADIAN SYLLABICS WO;Lo;0;L;;;;;N;;;;; +1413;CANADIAN SYLLABICS WEST-CREE WO;Lo;0;L;;;;;N;;;;; +1414;CANADIAN SYLLABICS WOO;Lo;0;L;;;;;N;;;;; +1415;CANADIAN SYLLABICS WEST-CREE WOO;Lo;0;L;;;;;N;;;;; +1416;CANADIAN SYLLABICS NASKAPI WOO;Lo;0;L;;;;;N;;;;; +1417;CANADIAN SYLLABICS WA;Lo;0;L;;;;;N;;;;; +1418;CANADIAN SYLLABICS WEST-CREE WA;Lo;0;L;;;;;N;;;;; +1419;CANADIAN SYLLABICS WAA;Lo;0;L;;;;;N;;;;; +141A;CANADIAN SYLLABICS WEST-CREE WAA;Lo;0;L;;;;;N;;;;; +141B;CANADIAN SYLLABICS NASKAPI WAA;Lo;0;L;;;;;N;;;;; +141C;CANADIAN SYLLABICS AI;Lo;0;L;;;;;N;;;;; +141D;CANADIAN SYLLABICS Y-CREE W;Lo;0;L;;;;;N;;;;; +141E;CANADIAN SYLLABICS GLOTTAL STOP;Lo;0;L;;;;;N;;;;; +141F;CANADIAN SYLLABICS FINAL ACUTE;Lo;0;L;;;;;N;;;;; +1420;CANADIAN SYLLABICS FINAL GRAVE;Lo;0;L;;;;;N;;;;; +1421;CANADIAN SYLLABICS FINAL BOTTOM HALF RING;Lo;0;L;;;;;N;;;;; +1422;CANADIAN SYLLABICS FINAL TOP HALF RING;Lo;0;L;;;;;N;;;;; +1423;CANADIAN SYLLABICS FINAL RIGHT HALF RING;Lo;0;L;;;;;N;;;;; +1424;CANADIAN SYLLABICS FINAL RING;Lo;0;L;;;;;N;;;;; +1425;CANADIAN SYLLABICS FINAL DOUBLE ACUTE;Lo;0;L;;;;;N;;;;; +1426;CANADIAN SYLLABICS FINAL DOUBLE SHORT VERTICAL STROKES;Lo;0;L;;;;;N;;;;; +1427;CANADIAN SYLLABICS FINAL MIDDLE DOT;Lo;0;L;;;;;N;;;;; +1428;CANADIAN SYLLABICS FINAL SHORT HORIZONTAL STROKE;Lo;0;L;;;;;N;;;;; +1429;CANADIAN SYLLABICS FINAL PLUS;Lo;0;L;;;;;N;;;;; +142A;CANADIAN SYLLABICS FINAL DOWN TACK;Lo;0;L;;;;;N;;;;; +142B;CANADIAN SYLLABICS EN;Lo;0;L;;;;;N;;;;; +142C;CANADIAN SYLLABICS IN;Lo;0;L;;;;;N;;;;; +142D;CANADIAN SYLLABICS ON;Lo;0;L;;;;;N;;;;; +142E;CANADIAN SYLLABICS AN;Lo;0;L;;;;;N;;;;; +142F;CANADIAN SYLLABICS PE;Lo;0;L;;;;;N;;;;; +1430;CANADIAN SYLLABICS PAAI;Lo;0;L;;;;;N;;;;; +1431;CANADIAN SYLLABICS PI;Lo;0;L;;;;;N;;;;; +1432;CANADIAN SYLLABICS PII;Lo;0;L;;;;;N;;;;; +1433;CANADIAN SYLLABICS PO;Lo;0;L;;;;;N;;;;; +1434;CANADIAN SYLLABICS POO;Lo;0;L;;;;;N;;;;; +1435;CANADIAN SYLLABICS Y-CREE POO;Lo;0;L;;;;;N;;;;; +1436;CANADIAN SYLLABICS CARRIER HEE;Lo;0;L;;;;;N;;;;; +1437;CANADIAN SYLLABICS CARRIER HI;Lo;0;L;;;;;N;;;;; +1438;CANADIAN SYLLABICS PA;Lo;0;L;;;;;N;;;;; +1439;CANADIAN SYLLABICS PAA;Lo;0;L;;;;;N;;;;; +143A;CANADIAN SYLLABICS PWE;Lo;0;L;;;;;N;;;;; +143B;CANADIAN SYLLABICS WEST-CREE PWE;Lo;0;L;;;;;N;;;;; +143C;CANADIAN SYLLABICS PWI;Lo;0;L;;;;;N;;;;; +143D;CANADIAN SYLLABICS WEST-CREE PWI;Lo;0;L;;;;;N;;;;; +143E;CANADIAN SYLLABICS PWII;Lo;0;L;;;;;N;;;;; +143F;CANADIAN SYLLABICS WEST-CREE PWII;Lo;0;L;;;;;N;;;;; +1440;CANADIAN SYLLABICS PWO;Lo;0;L;;;;;N;;;;; +1441;CANADIAN SYLLABICS WEST-CREE PWO;Lo;0;L;;;;;N;;;;; +1442;CANADIAN SYLLABICS PWOO;Lo;0;L;;;;;N;;;;; +1443;CANADIAN SYLLABICS WEST-CREE PWOO;Lo;0;L;;;;;N;;;;; +1444;CANADIAN SYLLABICS PWA;Lo;0;L;;;;;N;;;;; +1445;CANADIAN SYLLABICS WEST-CREE PWA;Lo;0;L;;;;;N;;;;; +1446;CANADIAN SYLLABICS PWAA;Lo;0;L;;;;;N;;;;; +1447;CANADIAN SYLLABICS WEST-CREE PWAA;Lo;0;L;;;;;N;;;;; +1448;CANADIAN SYLLABICS Y-CREE PWAA;Lo;0;L;;;;;N;;;;; +1449;CANADIAN SYLLABICS P;Lo;0;L;;;;;N;;;;; +144A;CANADIAN SYLLABICS WEST-CREE P;Lo;0;L;;;;;N;;;;; +144B;CANADIAN SYLLABICS CARRIER H;Lo;0;L;;;;;N;;;;; +144C;CANADIAN SYLLABICS TE;Lo;0;L;;;;;N;;;;; +144D;CANADIAN SYLLABICS TAAI;Lo;0;L;;;;;N;;;;; +144E;CANADIAN SYLLABICS TI;Lo;0;L;;;;;N;;;;; +144F;CANADIAN SYLLABICS TII;Lo;0;L;;;;;N;;;;; +1450;CANADIAN SYLLABICS TO;Lo;0;L;;;;;N;;;;; +1451;CANADIAN SYLLABICS TOO;Lo;0;L;;;;;N;;;;; +1452;CANADIAN SYLLABICS Y-CREE TOO;Lo;0;L;;;;;N;;;;; +1453;CANADIAN SYLLABICS CARRIER DEE;Lo;0;L;;;;;N;;;;; +1454;CANADIAN SYLLABICS CARRIER DI;Lo;0;L;;;;;N;;;;; +1455;CANADIAN SYLLABICS TA;Lo;0;L;;;;;N;;;;; +1456;CANADIAN SYLLABICS TAA;Lo;0;L;;;;;N;;;;; +1457;CANADIAN SYLLABICS TWE;Lo;0;L;;;;;N;;;;; +1458;CANADIAN SYLLABICS WEST-CREE TWE;Lo;0;L;;;;;N;;;;; +1459;CANADIAN SYLLABICS TWI;Lo;0;L;;;;;N;;;;; +145A;CANADIAN SYLLABICS WEST-CREE TWI;Lo;0;L;;;;;N;;;;; +145B;CANADIAN SYLLABICS TWII;Lo;0;L;;;;;N;;;;; +145C;CANADIAN SYLLABICS WEST-CREE TWII;Lo;0;L;;;;;N;;;;; +145D;CANADIAN SYLLABICS TWO;Lo;0;L;;;;;N;;;;; +145E;CANADIAN SYLLABICS WEST-CREE TWO;Lo;0;L;;;;;N;;;;; +145F;CANADIAN SYLLABICS TWOO;Lo;0;L;;;;;N;;;;; +1460;CANADIAN SYLLABICS WEST-CREE TWOO;Lo;0;L;;;;;N;;;;; +1461;CANADIAN SYLLABICS TWA;Lo;0;L;;;;;N;;;;; +1462;CANADIAN SYLLABICS WEST-CREE TWA;Lo;0;L;;;;;N;;;;; +1463;CANADIAN SYLLABICS TWAA;Lo;0;L;;;;;N;;;;; +1464;CANADIAN SYLLABICS WEST-CREE TWAA;Lo;0;L;;;;;N;;;;; +1465;CANADIAN SYLLABICS NASKAPI TWAA;Lo;0;L;;;;;N;;;;; +1466;CANADIAN SYLLABICS T;Lo;0;L;;;;;N;;;;; +1467;CANADIAN SYLLABICS TTE;Lo;0;L;;;;;N;;;;; +1468;CANADIAN SYLLABICS TTI;Lo;0;L;;;;;N;;;;; +1469;CANADIAN SYLLABICS TTO;Lo;0;L;;;;;N;;;;; +146A;CANADIAN SYLLABICS TTA;Lo;0;L;;;;;N;;;;; +146B;CANADIAN SYLLABICS KE;Lo;0;L;;;;;N;;;;; +146C;CANADIAN SYLLABICS KAAI;Lo;0;L;;;;;N;;;;; +146D;CANADIAN SYLLABICS KI;Lo;0;L;;;;;N;;;;; +146E;CANADIAN SYLLABICS KII;Lo;0;L;;;;;N;;;;; +146F;CANADIAN SYLLABICS KO;Lo;0;L;;;;;N;;;;; +1470;CANADIAN SYLLABICS KOO;Lo;0;L;;;;;N;;;;; +1471;CANADIAN SYLLABICS Y-CREE KOO;Lo;0;L;;;;;N;;;;; +1472;CANADIAN SYLLABICS KA;Lo;0;L;;;;;N;;;;; +1473;CANADIAN SYLLABICS KAA;Lo;0;L;;;;;N;;;;; +1474;CANADIAN SYLLABICS KWE;Lo;0;L;;;;;N;;;;; +1475;CANADIAN SYLLABICS WEST-CREE KWE;Lo;0;L;;;;;N;;;;; +1476;CANADIAN SYLLABICS KWI;Lo;0;L;;;;;N;;;;; +1477;CANADIAN SYLLABICS WEST-CREE KWI;Lo;0;L;;;;;N;;;;; +1478;CANADIAN SYLLABICS KWII;Lo;0;L;;;;;N;;;;; +1479;CANADIAN SYLLABICS WEST-CREE KWII;Lo;0;L;;;;;N;;;;; +147A;CANADIAN SYLLABICS KWO;Lo;0;L;;;;;N;;;;; +147B;CANADIAN SYLLABICS WEST-CREE KWO;Lo;0;L;;;;;N;;;;; +147C;CANADIAN SYLLABICS KWOO;Lo;0;L;;;;;N;;;;; +147D;CANADIAN SYLLABICS WEST-CREE KWOO;Lo;0;L;;;;;N;;;;; +147E;CANADIAN SYLLABICS KWA;Lo;0;L;;;;;N;;;;; +147F;CANADIAN SYLLABICS WEST-CREE KWA;Lo;0;L;;;;;N;;;;; +1480;CANADIAN SYLLABICS KWAA;Lo;0;L;;;;;N;;;;; +1481;CANADIAN SYLLABICS WEST-CREE KWAA;Lo;0;L;;;;;N;;;;; +1482;CANADIAN SYLLABICS NASKAPI KWAA;Lo;0;L;;;;;N;;;;; +1483;CANADIAN SYLLABICS K;Lo;0;L;;;;;N;;;;; +1484;CANADIAN SYLLABICS KW;Lo;0;L;;;;;N;;;;; +1485;CANADIAN SYLLABICS SOUTH-SLAVEY KEH;Lo;0;L;;;;;N;;;;; +1486;CANADIAN SYLLABICS SOUTH-SLAVEY KIH;Lo;0;L;;;;;N;;;;; +1487;CANADIAN SYLLABICS SOUTH-SLAVEY KOH;Lo;0;L;;;;;N;;;;; +1488;CANADIAN SYLLABICS SOUTH-SLAVEY KAH;Lo;0;L;;;;;N;;;;; +1489;CANADIAN SYLLABICS CE;Lo;0;L;;;;;N;;;;; +148A;CANADIAN SYLLABICS CAAI;Lo;0;L;;;;;N;;;;; +148B;CANADIAN SYLLABICS CI;Lo;0;L;;;;;N;;;;; +148C;CANADIAN SYLLABICS CII;Lo;0;L;;;;;N;;;;; +148D;CANADIAN SYLLABICS CO;Lo;0;L;;;;;N;;;;; +148E;CANADIAN SYLLABICS COO;Lo;0;L;;;;;N;;;;; +148F;CANADIAN SYLLABICS Y-CREE COO;Lo;0;L;;;;;N;;;;; +1490;CANADIAN SYLLABICS CA;Lo;0;L;;;;;N;;;;; +1491;CANADIAN SYLLABICS CAA;Lo;0;L;;;;;N;;;;; +1492;CANADIAN SYLLABICS CWE;Lo;0;L;;;;;N;;;;; +1493;CANADIAN SYLLABICS WEST-CREE CWE;Lo;0;L;;;;;N;;;;; +1494;CANADIAN SYLLABICS CWI;Lo;0;L;;;;;N;;;;; +1495;CANADIAN SYLLABICS WEST-CREE CWI;Lo;0;L;;;;;N;;;;; +1496;CANADIAN SYLLABICS CWII;Lo;0;L;;;;;N;;;;; +1497;CANADIAN SYLLABICS WEST-CREE CWII;Lo;0;L;;;;;N;;;;; +1498;CANADIAN SYLLABICS CWO;Lo;0;L;;;;;N;;;;; +1499;CANADIAN SYLLABICS WEST-CREE CWO;Lo;0;L;;;;;N;;;;; +149A;CANADIAN SYLLABICS CWOO;Lo;0;L;;;;;N;;;;; +149B;CANADIAN SYLLABICS WEST-CREE CWOO;Lo;0;L;;;;;N;;;;; +149C;CANADIAN SYLLABICS CWA;Lo;0;L;;;;;N;;;;; +149D;CANADIAN SYLLABICS WEST-CREE CWA;Lo;0;L;;;;;N;;;;; +149E;CANADIAN SYLLABICS CWAA;Lo;0;L;;;;;N;;;;; +149F;CANADIAN SYLLABICS WEST-CREE CWAA;Lo;0;L;;;;;N;;;;; +14A0;CANADIAN SYLLABICS NASKAPI CWAA;Lo;0;L;;;;;N;;;;; +14A1;CANADIAN SYLLABICS C;Lo;0;L;;;;;N;;;;; +14A2;CANADIAN SYLLABICS SAYISI TH;Lo;0;L;;;;;N;;;;; +14A3;CANADIAN SYLLABICS ME;Lo;0;L;;;;;N;;;;; +14A4;CANADIAN SYLLABICS MAAI;Lo;0;L;;;;;N;;;;; +14A5;CANADIAN SYLLABICS MI;Lo;0;L;;;;;N;;;;; +14A6;CANADIAN SYLLABICS MII;Lo;0;L;;;;;N;;;;; +14A7;CANADIAN SYLLABICS MO;Lo;0;L;;;;;N;;;;; +14A8;CANADIAN SYLLABICS MOO;Lo;0;L;;;;;N;;;;; +14A9;CANADIAN SYLLABICS Y-CREE MOO;Lo;0;L;;;;;N;;;;; +14AA;CANADIAN SYLLABICS MA;Lo;0;L;;;;;N;;;;; +14AB;CANADIAN SYLLABICS MAA;Lo;0;L;;;;;N;;;;; +14AC;CANADIAN SYLLABICS MWE;Lo;0;L;;;;;N;;;;; +14AD;CANADIAN SYLLABICS WEST-CREE MWE;Lo;0;L;;;;;N;;;;; +14AE;CANADIAN SYLLABICS MWI;Lo;0;L;;;;;N;;;;; +14AF;CANADIAN SYLLABICS WEST-CREE MWI;Lo;0;L;;;;;N;;;;; +14B0;CANADIAN SYLLABICS MWII;Lo;0;L;;;;;N;;;;; +14B1;CANADIAN SYLLABICS WEST-CREE MWII;Lo;0;L;;;;;N;;;;; +14B2;CANADIAN SYLLABICS MWO;Lo;0;L;;;;;N;;;;; +14B3;CANADIAN SYLLABICS WEST-CREE MWO;Lo;0;L;;;;;N;;;;; +14B4;CANADIAN SYLLABICS MWOO;Lo;0;L;;;;;N;;;;; +14B5;CANADIAN SYLLABICS WEST-CREE MWOO;Lo;0;L;;;;;N;;;;; +14B6;CANADIAN SYLLABICS MWA;Lo;0;L;;;;;N;;;;; +14B7;CANADIAN SYLLABICS WEST-CREE MWA;Lo;0;L;;;;;N;;;;; +14B8;CANADIAN SYLLABICS MWAA;Lo;0;L;;;;;N;;;;; +14B9;CANADIAN SYLLABICS WEST-CREE MWAA;Lo;0;L;;;;;N;;;;; +14BA;CANADIAN SYLLABICS NASKAPI MWAA;Lo;0;L;;;;;N;;;;; +14BB;CANADIAN SYLLABICS M;Lo;0;L;;;;;N;;;;; +14BC;CANADIAN SYLLABICS WEST-CREE M;Lo;0;L;;;;;N;;;;; +14BD;CANADIAN SYLLABICS MH;Lo;0;L;;;;;N;;;;; +14BE;CANADIAN SYLLABICS ATHAPASCAN M;Lo;0;L;;;;;N;;;;; +14BF;CANADIAN SYLLABICS SAYISI M;Lo;0;L;;;;;N;;;;; +14C0;CANADIAN SYLLABICS NE;Lo;0;L;;;;;N;;;;; +14C1;CANADIAN SYLLABICS NAAI;Lo;0;L;;;;;N;;;;; +14C2;CANADIAN SYLLABICS NI;Lo;0;L;;;;;N;;;;; +14C3;CANADIAN SYLLABICS NII;Lo;0;L;;;;;N;;;;; +14C4;CANADIAN SYLLABICS NO;Lo;0;L;;;;;N;;;;; +14C5;CANADIAN SYLLABICS NOO;Lo;0;L;;;;;N;;;;; +14C6;CANADIAN SYLLABICS Y-CREE NOO;Lo;0;L;;;;;N;;;;; +14C7;CANADIAN SYLLABICS NA;Lo;0;L;;;;;N;;;;; +14C8;CANADIAN SYLLABICS NAA;Lo;0;L;;;;;N;;;;; +14C9;CANADIAN SYLLABICS NWE;Lo;0;L;;;;;N;;;;; +14CA;CANADIAN SYLLABICS WEST-CREE NWE;Lo;0;L;;;;;N;;;;; +14CB;CANADIAN SYLLABICS NWA;Lo;0;L;;;;;N;;;;; +14CC;CANADIAN SYLLABICS WEST-CREE NWA;Lo;0;L;;;;;N;;;;; +14CD;CANADIAN SYLLABICS NWAA;Lo;0;L;;;;;N;;;;; +14CE;CANADIAN SYLLABICS WEST-CREE NWAA;Lo;0;L;;;;;N;;;;; +14CF;CANADIAN SYLLABICS NASKAPI NWAA;Lo;0;L;;;;;N;;;;; +14D0;CANADIAN SYLLABICS N;Lo;0;L;;;;;N;;;;; +14D1;CANADIAN SYLLABICS CARRIER NG;Lo;0;L;;;;;N;;;;; +14D2;CANADIAN SYLLABICS NH;Lo;0;L;;;;;N;;;;; +14D3;CANADIAN SYLLABICS LE;Lo;0;L;;;;;N;;;;; +14D4;CANADIAN SYLLABICS LAAI;Lo;0;L;;;;;N;;;;; +14D5;CANADIAN SYLLABICS LI;Lo;0;L;;;;;N;;;;; +14D6;CANADIAN SYLLABICS LII;Lo;0;L;;;;;N;;;;; +14D7;CANADIAN SYLLABICS LO;Lo;0;L;;;;;N;;;;; +14D8;CANADIAN SYLLABICS LOO;Lo;0;L;;;;;N;;;;; +14D9;CANADIAN SYLLABICS Y-CREE LOO;Lo;0;L;;;;;N;;;;; +14DA;CANADIAN SYLLABICS LA;Lo;0;L;;;;;N;;;;; +14DB;CANADIAN SYLLABICS LAA;Lo;0;L;;;;;N;;;;; +14DC;CANADIAN SYLLABICS LWE;Lo;0;L;;;;;N;;;;; +14DD;CANADIAN SYLLABICS WEST-CREE LWE;Lo;0;L;;;;;N;;;;; +14DE;CANADIAN SYLLABICS LWI;Lo;0;L;;;;;N;;;;; +14DF;CANADIAN SYLLABICS WEST-CREE LWI;Lo;0;L;;;;;N;;;;; +14E0;CANADIAN SYLLABICS LWII;Lo;0;L;;;;;N;;;;; +14E1;CANADIAN SYLLABICS WEST-CREE LWII;Lo;0;L;;;;;N;;;;; +14E2;CANADIAN SYLLABICS LWO;Lo;0;L;;;;;N;;;;; +14E3;CANADIAN SYLLABICS WEST-CREE LWO;Lo;0;L;;;;;N;;;;; +14E4;CANADIAN SYLLABICS LWOO;Lo;0;L;;;;;N;;;;; +14E5;CANADIAN SYLLABICS WEST-CREE LWOO;Lo;0;L;;;;;N;;;;; +14E6;CANADIAN SYLLABICS LWA;Lo;0;L;;;;;N;;;;; +14E7;CANADIAN SYLLABICS WEST-CREE LWA;Lo;0;L;;;;;N;;;;; +14E8;CANADIAN SYLLABICS LWAA;Lo;0;L;;;;;N;;;;; +14E9;CANADIAN SYLLABICS WEST-CREE LWAA;Lo;0;L;;;;;N;;;;; +14EA;CANADIAN SYLLABICS L;Lo;0;L;;;;;N;;;;; +14EB;CANADIAN SYLLABICS WEST-CREE L;Lo;0;L;;;;;N;;;;; +14EC;CANADIAN SYLLABICS MEDIAL L;Lo;0;L;;;;;N;;;;; +14ED;CANADIAN SYLLABICS SE;Lo;0;L;;;;;N;;;;; +14EE;CANADIAN SYLLABICS SAAI;Lo;0;L;;;;;N;;;;; +14EF;CANADIAN SYLLABICS SI;Lo;0;L;;;;;N;;;;; +14F0;CANADIAN SYLLABICS SII;Lo;0;L;;;;;N;;;;; +14F1;CANADIAN SYLLABICS SO;Lo;0;L;;;;;N;;;;; +14F2;CANADIAN SYLLABICS SOO;Lo;0;L;;;;;N;;;;; +14F3;CANADIAN SYLLABICS Y-CREE SOO;Lo;0;L;;;;;N;;;;; +14F4;CANADIAN SYLLABICS SA;Lo;0;L;;;;;N;;;;; +14F5;CANADIAN SYLLABICS SAA;Lo;0;L;;;;;N;;;;; +14F6;CANADIAN SYLLABICS SWE;Lo;0;L;;;;;N;;;;; +14F7;CANADIAN SYLLABICS WEST-CREE SWE;Lo;0;L;;;;;N;;;;; +14F8;CANADIAN SYLLABICS SWI;Lo;0;L;;;;;N;;;;; +14F9;CANADIAN SYLLABICS WEST-CREE SWI;Lo;0;L;;;;;N;;;;; +14FA;CANADIAN SYLLABICS SWII;Lo;0;L;;;;;N;;;;; +14FB;CANADIAN SYLLABICS WEST-CREE SWII;Lo;0;L;;;;;N;;;;; +14FC;CANADIAN SYLLABICS SWO;Lo;0;L;;;;;N;;;;; +14FD;CANADIAN SYLLABICS WEST-CREE SWO;Lo;0;L;;;;;N;;;;; +14FE;CANADIAN SYLLABICS SWOO;Lo;0;L;;;;;N;;;;; +14FF;CANADIAN SYLLABICS WEST-CREE SWOO;Lo;0;L;;;;;N;;;;; +1500;CANADIAN SYLLABICS SWA;Lo;0;L;;;;;N;;;;; +1501;CANADIAN SYLLABICS WEST-CREE SWA;Lo;0;L;;;;;N;;;;; +1502;CANADIAN SYLLABICS SWAA;Lo;0;L;;;;;N;;;;; +1503;CANADIAN SYLLABICS WEST-CREE SWAA;Lo;0;L;;;;;N;;;;; +1504;CANADIAN SYLLABICS NASKAPI SWAA;Lo;0;L;;;;;N;;;;; +1505;CANADIAN SYLLABICS S;Lo;0;L;;;;;N;;;;; +1506;CANADIAN SYLLABICS ATHAPASCAN S;Lo;0;L;;;;;N;;;;; +1507;CANADIAN SYLLABICS SW;Lo;0;L;;;;;N;;;;; +1508;CANADIAN SYLLABICS BLACKFOOT S;Lo;0;L;;;;;N;;;;; +1509;CANADIAN SYLLABICS MOOSE-CREE SK;Lo;0;L;;;;;N;;;;; +150A;CANADIAN SYLLABICS NASKAPI SKW;Lo;0;L;;;;;N;;;;; +150B;CANADIAN SYLLABICS NASKAPI S-W;Lo;0;L;;;;;N;;;;; +150C;CANADIAN SYLLABICS NASKAPI SPWA;Lo;0;L;;;;;N;;;;; +150D;CANADIAN SYLLABICS NASKAPI STWA;Lo;0;L;;;;;N;;;;; +150E;CANADIAN SYLLABICS NASKAPI SKWA;Lo;0;L;;;;;N;;;;; +150F;CANADIAN SYLLABICS NASKAPI SCWA;Lo;0;L;;;;;N;;;;; +1510;CANADIAN SYLLABICS SHE;Lo;0;L;;;;;N;;;;; +1511;CANADIAN SYLLABICS SHI;Lo;0;L;;;;;N;;;;; +1512;CANADIAN SYLLABICS SHII;Lo;0;L;;;;;N;;;;; +1513;CANADIAN SYLLABICS SHO;Lo;0;L;;;;;N;;;;; +1514;CANADIAN SYLLABICS SHOO;Lo;0;L;;;;;N;;;;; +1515;CANADIAN SYLLABICS SHA;Lo;0;L;;;;;N;;;;; +1516;CANADIAN SYLLABICS SHAA;Lo;0;L;;;;;N;;;;; +1517;CANADIAN SYLLABICS SHWE;Lo;0;L;;;;;N;;;;; +1518;CANADIAN SYLLABICS WEST-CREE SHWE;Lo;0;L;;;;;N;;;;; +1519;CANADIAN SYLLABICS SHWI;Lo;0;L;;;;;N;;;;; +151A;CANADIAN SYLLABICS WEST-CREE SHWI;Lo;0;L;;;;;N;;;;; +151B;CANADIAN SYLLABICS SHWII;Lo;0;L;;;;;N;;;;; +151C;CANADIAN SYLLABICS WEST-CREE SHWII;Lo;0;L;;;;;N;;;;; +151D;CANADIAN SYLLABICS SHWO;Lo;0;L;;;;;N;;;;; +151E;CANADIAN SYLLABICS WEST-CREE SHWO;Lo;0;L;;;;;N;;;;; +151F;CANADIAN SYLLABICS SHWOO;Lo;0;L;;;;;N;;;;; +1520;CANADIAN SYLLABICS WEST-CREE SHWOO;Lo;0;L;;;;;N;;;;; +1521;CANADIAN SYLLABICS SHWA;Lo;0;L;;;;;N;;;;; +1522;CANADIAN SYLLABICS WEST-CREE SHWA;Lo;0;L;;;;;N;;;;; +1523;CANADIAN SYLLABICS SHWAA;Lo;0;L;;;;;N;;;;; +1524;CANADIAN SYLLABICS WEST-CREE SHWAA;Lo;0;L;;;;;N;;;;; +1525;CANADIAN SYLLABICS SH;Lo;0;L;;;;;N;;;;; +1526;CANADIAN SYLLABICS YE;Lo;0;L;;;;;N;;;;; +1527;CANADIAN SYLLABICS YAAI;Lo;0;L;;;;;N;;;;; +1528;CANADIAN SYLLABICS YI;Lo;0;L;;;;;N;;;;; +1529;CANADIAN SYLLABICS YII;Lo;0;L;;;;;N;;;;; +152A;CANADIAN SYLLABICS YO;Lo;0;L;;;;;N;;;;; +152B;CANADIAN SYLLABICS YOO;Lo;0;L;;;;;N;;;;; +152C;CANADIAN SYLLABICS Y-CREE YOO;Lo;0;L;;;;;N;;;;; +152D;CANADIAN SYLLABICS YA;Lo;0;L;;;;;N;;;;; +152E;CANADIAN SYLLABICS YAA;Lo;0;L;;;;;N;;;;; +152F;CANADIAN SYLLABICS YWE;Lo;0;L;;;;;N;;;;; +1530;CANADIAN SYLLABICS WEST-CREE YWE;Lo;0;L;;;;;N;;;;; +1531;CANADIAN SYLLABICS YWI;Lo;0;L;;;;;N;;;;; +1532;CANADIAN SYLLABICS WEST-CREE YWI;Lo;0;L;;;;;N;;;;; +1533;CANADIAN SYLLABICS YWII;Lo;0;L;;;;;N;;;;; +1534;CANADIAN SYLLABICS WEST-CREE YWII;Lo;0;L;;;;;N;;;;; +1535;CANADIAN SYLLABICS YWO;Lo;0;L;;;;;N;;;;; +1536;CANADIAN SYLLABICS WEST-CREE YWO;Lo;0;L;;;;;N;;;;; +1537;CANADIAN SYLLABICS YWOO;Lo;0;L;;;;;N;;;;; +1538;CANADIAN SYLLABICS WEST-CREE YWOO;Lo;0;L;;;;;N;;;;; +1539;CANADIAN SYLLABICS YWA;Lo;0;L;;;;;N;;;;; +153A;CANADIAN SYLLABICS WEST-CREE YWA;Lo;0;L;;;;;N;;;;; +153B;CANADIAN SYLLABICS YWAA;Lo;0;L;;;;;N;;;;; +153C;CANADIAN SYLLABICS WEST-CREE YWAA;Lo;0;L;;;;;N;;;;; +153D;CANADIAN SYLLABICS NASKAPI YWAA;Lo;0;L;;;;;N;;;;; +153E;CANADIAN SYLLABICS Y;Lo;0;L;;;;;N;;;;; +153F;CANADIAN SYLLABICS BIBLE-CREE Y;Lo;0;L;;;;;N;;;;; +1540;CANADIAN SYLLABICS WEST-CREE Y;Lo;0;L;;;;;N;;;;; +1541;CANADIAN SYLLABICS SAYISI YI;Lo;0;L;;;;;N;;;;; +1542;CANADIAN SYLLABICS RE;Lo;0;L;;;;;N;;;;; +1543;CANADIAN SYLLABICS R-CREE RE;Lo;0;L;;;;;N;;;;; +1544;CANADIAN SYLLABICS WEST-CREE LE;Lo;0;L;;;;;N;;;;; +1545;CANADIAN SYLLABICS RAAI;Lo;0;L;;;;;N;;;;; +1546;CANADIAN SYLLABICS RI;Lo;0;L;;;;;N;;;;; +1547;CANADIAN SYLLABICS RII;Lo;0;L;;;;;N;;;;; +1548;CANADIAN SYLLABICS RO;Lo;0;L;;;;;N;;;;; +1549;CANADIAN SYLLABICS ROO;Lo;0;L;;;;;N;;;;; +154A;CANADIAN SYLLABICS WEST-CREE LO;Lo;0;L;;;;;N;;;;; +154B;CANADIAN SYLLABICS RA;Lo;0;L;;;;;N;;;;; +154C;CANADIAN SYLLABICS RAA;Lo;0;L;;;;;N;;;;; +154D;CANADIAN SYLLABICS WEST-CREE LA;Lo;0;L;;;;;N;;;;; +154E;CANADIAN SYLLABICS RWAA;Lo;0;L;;;;;N;;;;; +154F;CANADIAN SYLLABICS WEST-CREE RWAA;Lo;0;L;;;;;N;;;;; +1550;CANADIAN SYLLABICS R;Lo;0;L;;;;;N;;;;; +1551;CANADIAN SYLLABICS WEST-CREE R;Lo;0;L;;;;;N;;;;; +1552;CANADIAN SYLLABICS MEDIAL R;Lo;0;L;;;;;N;;;;; +1553;CANADIAN SYLLABICS FE;Lo;0;L;;;;;N;;;;; +1554;CANADIAN SYLLABICS FAAI;Lo;0;L;;;;;N;;;;; +1555;CANADIAN SYLLABICS FI;Lo;0;L;;;;;N;;;;; +1556;CANADIAN SYLLABICS FII;Lo;0;L;;;;;N;;;;; +1557;CANADIAN SYLLABICS FO;Lo;0;L;;;;;N;;;;; +1558;CANADIAN SYLLABICS FOO;Lo;0;L;;;;;N;;;;; +1559;CANADIAN SYLLABICS FA;Lo;0;L;;;;;N;;;;; +155A;CANADIAN SYLLABICS FAA;Lo;0;L;;;;;N;;;;; +155B;CANADIAN SYLLABICS FWAA;Lo;0;L;;;;;N;;;;; +155C;CANADIAN SYLLABICS WEST-CREE FWAA;Lo;0;L;;;;;N;;;;; +155D;CANADIAN SYLLABICS F;Lo;0;L;;;;;N;;;;; +155E;CANADIAN SYLLABICS THE;Lo;0;L;;;;;N;;;;; +155F;CANADIAN SYLLABICS N-CREE THE;Lo;0;L;;;;;N;;;;; +1560;CANADIAN SYLLABICS THI;Lo;0;L;;;;;N;;;;; +1561;CANADIAN SYLLABICS N-CREE THI;Lo;0;L;;;;;N;;;;; +1562;CANADIAN SYLLABICS THII;Lo;0;L;;;;;N;;;;; +1563;CANADIAN SYLLABICS N-CREE THII;Lo;0;L;;;;;N;;;;; +1564;CANADIAN SYLLABICS THO;Lo;0;L;;;;;N;;;;; +1565;CANADIAN SYLLABICS THOO;Lo;0;L;;;;;N;;;;; +1566;CANADIAN SYLLABICS THA;Lo;0;L;;;;;N;;;;; +1567;CANADIAN SYLLABICS THAA;Lo;0;L;;;;;N;;;;; +1568;CANADIAN SYLLABICS THWAA;Lo;0;L;;;;;N;;;;; +1569;CANADIAN SYLLABICS WEST-CREE THWAA;Lo;0;L;;;;;N;;;;; +156A;CANADIAN SYLLABICS TH;Lo;0;L;;;;;N;;;;; +156B;CANADIAN SYLLABICS TTHE;Lo;0;L;;;;;N;;;;; +156C;CANADIAN SYLLABICS TTHI;Lo;0;L;;;;;N;;;;; +156D;CANADIAN SYLLABICS TTHO;Lo;0;L;;;;;N;;;;; +156E;CANADIAN SYLLABICS TTHA;Lo;0;L;;;;;N;;;;; +156F;CANADIAN SYLLABICS TTH;Lo;0;L;;;;;N;;;;; +1570;CANADIAN SYLLABICS TYE;Lo;0;L;;;;;N;;;;; +1571;CANADIAN SYLLABICS TYI;Lo;0;L;;;;;N;;;;; +1572;CANADIAN SYLLABICS TYO;Lo;0;L;;;;;N;;;;; +1573;CANADIAN SYLLABICS TYA;Lo;0;L;;;;;N;;;;; +1574;CANADIAN SYLLABICS NUNAVIK HE;Lo;0;L;;;;;N;;;;; +1575;CANADIAN SYLLABICS NUNAVIK HI;Lo;0;L;;;;;N;;;;; +1576;CANADIAN SYLLABICS NUNAVIK HII;Lo;0;L;;;;;N;;;;; +1577;CANADIAN SYLLABICS NUNAVIK HO;Lo;0;L;;;;;N;;;;; +1578;CANADIAN SYLLABICS NUNAVIK HOO;Lo;0;L;;;;;N;;;;; +1579;CANADIAN SYLLABICS NUNAVIK HA;Lo;0;L;;;;;N;;;;; +157A;CANADIAN SYLLABICS NUNAVIK HAA;Lo;0;L;;;;;N;;;;; +157B;CANADIAN SYLLABICS NUNAVIK H;Lo;0;L;;;;;N;;;;; +157C;CANADIAN SYLLABICS NUNAVUT H;Lo;0;L;;;;;N;;;;; +157D;CANADIAN SYLLABICS HK;Lo;0;L;;;;;N;;;;; +157E;CANADIAN SYLLABICS QAAI;Lo;0;L;;;;;N;;;;; +157F;CANADIAN SYLLABICS QI;Lo;0;L;;;;;N;;;;; +1580;CANADIAN SYLLABICS QII;Lo;0;L;;;;;N;;;;; +1581;CANADIAN SYLLABICS QO;Lo;0;L;;;;;N;;;;; +1582;CANADIAN SYLLABICS QOO;Lo;0;L;;;;;N;;;;; +1583;CANADIAN SYLLABICS QA;Lo;0;L;;;;;N;;;;; +1584;CANADIAN SYLLABICS QAA;Lo;0;L;;;;;N;;;;; +1585;CANADIAN SYLLABICS Q;Lo;0;L;;;;;N;;;;; +1586;CANADIAN SYLLABICS TLHE;Lo;0;L;;;;;N;;;;; +1587;CANADIAN SYLLABICS TLHI;Lo;0;L;;;;;N;;;;; +1588;CANADIAN SYLLABICS TLHO;Lo;0;L;;;;;N;;;;; +1589;CANADIAN SYLLABICS TLHA;Lo;0;L;;;;;N;;;;; +158A;CANADIAN SYLLABICS WEST-CREE RE;Lo;0;L;;;;;N;;;;; +158B;CANADIAN SYLLABICS WEST-CREE RI;Lo;0;L;;;;;N;;;;; +158C;CANADIAN SYLLABICS WEST-CREE RO;Lo;0;L;;;;;N;;;;; +158D;CANADIAN SYLLABICS WEST-CREE RA;Lo;0;L;;;;;N;;;;; +158E;CANADIAN SYLLABICS NGAAI;Lo;0;L;;;;;N;;;;; +158F;CANADIAN SYLLABICS NGI;Lo;0;L;;;;;N;;;;; +1590;CANADIAN SYLLABICS NGII;Lo;0;L;;;;;N;;;;; +1591;CANADIAN SYLLABICS NGO;Lo;0;L;;;;;N;;;;; +1592;CANADIAN SYLLABICS NGOO;Lo;0;L;;;;;N;;;;; +1593;CANADIAN SYLLABICS NGA;Lo;0;L;;;;;N;;;;; +1594;CANADIAN SYLLABICS NGAA;Lo;0;L;;;;;N;;;;; +1595;CANADIAN SYLLABICS NG;Lo;0;L;;;;;N;;;;; +1596;CANADIAN SYLLABICS NNG;Lo;0;L;;;;;N;;;;; +1597;CANADIAN SYLLABICS SAYISI SHE;Lo;0;L;;;;;N;;;;; +1598;CANADIAN SYLLABICS SAYISI SHI;Lo;0;L;;;;;N;;;;; +1599;CANADIAN SYLLABICS SAYISI SHO;Lo;0;L;;;;;N;;;;; +159A;CANADIAN SYLLABICS SAYISI SHA;Lo;0;L;;;;;N;;;;; +159B;CANADIAN SYLLABICS WOODS-CREE THE;Lo;0;L;;;;;N;;;;; +159C;CANADIAN SYLLABICS WOODS-CREE THI;Lo;0;L;;;;;N;;;;; +159D;CANADIAN SYLLABICS WOODS-CREE THO;Lo;0;L;;;;;N;;;;; +159E;CANADIAN SYLLABICS WOODS-CREE THA;Lo;0;L;;;;;N;;;;; +159F;CANADIAN SYLLABICS WOODS-CREE TH;Lo;0;L;;;;;N;;;;; +15A0;CANADIAN SYLLABICS LHI;Lo;0;L;;;;;N;;;;; +15A1;CANADIAN SYLLABICS LHII;Lo;0;L;;;;;N;;;;; +15A2;CANADIAN SYLLABICS LHO;Lo;0;L;;;;;N;;;;; +15A3;CANADIAN SYLLABICS LHOO;Lo;0;L;;;;;N;;;;; +15A4;CANADIAN SYLLABICS LHA;Lo;0;L;;;;;N;;;;; +15A5;CANADIAN SYLLABICS LHAA;Lo;0;L;;;;;N;;;;; +15A6;CANADIAN SYLLABICS LH;Lo;0;L;;;;;N;;;;; +15A7;CANADIAN SYLLABICS TH-CREE THE;Lo;0;L;;;;;N;;;;; +15A8;CANADIAN SYLLABICS TH-CREE THI;Lo;0;L;;;;;N;;;;; +15A9;CANADIAN SYLLABICS TH-CREE THII;Lo;0;L;;;;;N;;;;; +15AA;CANADIAN SYLLABICS TH-CREE THO;Lo;0;L;;;;;N;;;;; +15AB;CANADIAN SYLLABICS TH-CREE THOO;Lo;0;L;;;;;N;;;;; +15AC;CANADIAN SYLLABICS TH-CREE THA;Lo;0;L;;;;;N;;;;; +15AD;CANADIAN SYLLABICS TH-CREE THAA;Lo;0;L;;;;;N;;;;; +15AE;CANADIAN SYLLABICS TH-CREE TH;Lo;0;L;;;;;N;;;;; +15AF;CANADIAN SYLLABICS AIVILIK B;Lo;0;L;;;;;N;;;;; +15B0;CANADIAN SYLLABICS BLACKFOOT E;Lo;0;L;;;;;N;;;;; +15B1;CANADIAN SYLLABICS BLACKFOOT I;Lo;0;L;;;;;N;;;;; +15B2;CANADIAN SYLLABICS BLACKFOOT O;Lo;0;L;;;;;N;;;;; +15B3;CANADIAN SYLLABICS BLACKFOOT A;Lo;0;L;;;;;N;;;;; +15B4;CANADIAN SYLLABICS BLACKFOOT WE;Lo;0;L;;;;;N;;;;; +15B5;CANADIAN SYLLABICS BLACKFOOT WI;Lo;0;L;;;;;N;;;;; +15B6;CANADIAN SYLLABICS BLACKFOOT WO;Lo;0;L;;;;;N;;;;; +15B7;CANADIAN SYLLABICS BLACKFOOT WA;Lo;0;L;;;;;N;;;;; +15B8;CANADIAN SYLLABICS BLACKFOOT NE;Lo;0;L;;;;;N;;;;; +15B9;CANADIAN SYLLABICS BLACKFOOT NI;Lo;0;L;;;;;N;;;;; +15BA;CANADIAN SYLLABICS BLACKFOOT NO;Lo;0;L;;;;;N;;;;; +15BB;CANADIAN SYLLABICS BLACKFOOT NA;Lo;0;L;;;;;N;;;;; +15BC;CANADIAN SYLLABICS BLACKFOOT KE;Lo;0;L;;;;;N;;;;; +15BD;CANADIAN SYLLABICS BLACKFOOT KI;Lo;0;L;;;;;N;;;;; +15BE;CANADIAN SYLLABICS BLACKFOOT KO;Lo;0;L;;;;;N;;;;; +15BF;CANADIAN SYLLABICS BLACKFOOT KA;Lo;0;L;;;;;N;;;;; +15C0;CANADIAN SYLLABICS SAYISI HE;Lo;0;L;;;;;N;;;;; +15C1;CANADIAN SYLLABICS SAYISI HI;Lo;0;L;;;;;N;;;;; +15C2;CANADIAN SYLLABICS SAYISI HO;Lo;0;L;;;;;N;;;;; +15C3;CANADIAN SYLLABICS SAYISI HA;Lo;0;L;;;;;N;;;;; +15C4;CANADIAN SYLLABICS CARRIER GHU;Lo;0;L;;;;;N;;;;; +15C5;CANADIAN SYLLABICS CARRIER GHO;Lo;0;L;;;;;N;;;;; +15C6;CANADIAN SYLLABICS CARRIER GHE;Lo;0;L;;;;;N;;;;; +15C7;CANADIAN SYLLABICS CARRIER GHEE;Lo;0;L;;;;;N;;;;; +15C8;CANADIAN SYLLABICS CARRIER GHI;Lo;0;L;;;;;N;;;;; +15C9;CANADIAN SYLLABICS CARRIER GHA;Lo;0;L;;;;;N;;;;; +15CA;CANADIAN SYLLABICS CARRIER RU;Lo;0;L;;;;;N;;;;; +15CB;CANADIAN SYLLABICS CARRIER RO;Lo;0;L;;;;;N;;;;; +15CC;CANADIAN SYLLABICS CARRIER RE;Lo;0;L;;;;;N;;;;; +15CD;CANADIAN SYLLABICS CARRIER REE;Lo;0;L;;;;;N;;;;; +15CE;CANADIAN SYLLABICS CARRIER RI;Lo;0;L;;;;;N;;;;; +15CF;CANADIAN SYLLABICS CARRIER RA;Lo;0;L;;;;;N;;;;; +15D0;CANADIAN SYLLABICS CARRIER WU;Lo;0;L;;;;;N;;;;; +15D1;CANADIAN SYLLABICS CARRIER WO;Lo;0;L;;;;;N;;;;; +15D2;CANADIAN SYLLABICS CARRIER WE;Lo;0;L;;;;;N;;;;; +15D3;CANADIAN SYLLABICS CARRIER WEE;Lo;0;L;;;;;N;;;;; +15D4;CANADIAN SYLLABICS CARRIER WI;Lo;0;L;;;;;N;;;;; +15D5;CANADIAN SYLLABICS CARRIER WA;Lo;0;L;;;;;N;;;;; +15D6;CANADIAN SYLLABICS CARRIER HWU;Lo;0;L;;;;;N;;;;; +15D7;CANADIAN SYLLABICS CARRIER HWO;Lo;0;L;;;;;N;;;;; +15D8;CANADIAN SYLLABICS CARRIER HWE;Lo;0;L;;;;;N;;;;; +15D9;CANADIAN SYLLABICS CARRIER HWEE;Lo;0;L;;;;;N;;;;; +15DA;CANADIAN SYLLABICS CARRIER HWI;Lo;0;L;;;;;N;;;;; +15DB;CANADIAN SYLLABICS CARRIER HWA;Lo;0;L;;;;;N;;;;; +15DC;CANADIAN SYLLABICS CARRIER THU;Lo;0;L;;;;;N;;;;; +15DD;CANADIAN SYLLABICS CARRIER THO;Lo;0;L;;;;;N;;;;; +15DE;CANADIAN SYLLABICS CARRIER THE;Lo;0;L;;;;;N;;;;; +15DF;CANADIAN SYLLABICS CARRIER THEE;Lo;0;L;;;;;N;;;;; +15E0;CANADIAN SYLLABICS CARRIER THI;Lo;0;L;;;;;N;;;;; +15E1;CANADIAN SYLLABICS CARRIER THA;Lo;0;L;;;;;N;;;;; +15E2;CANADIAN SYLLABICS CARRIER TTU;Lo;0;L;;;;;N;;;;; +15E3;CANADIAN SYLLABICS CARRIER TTO;Lo;0;L;;;;;N;;;;; +15E4;CANADIAN SYLLABICS CARRIER TTE;Lo;0;L;;;;;N;;;;; +15E5;CANADIAN SYLLABICS CARRIER TTEE;Lo;0;L;;;;;N;;;;; +15E6;CANADIAN SYLLABICS CARRIER TTI;Lo;0;L;;;;;N;;;;; +15E7;CANADIAN SYLLABICS CARRIER TTA;Lo;0;L;;;;;N;;;;; +15E8;CANADIAN SYLLABICS CARRIER PU;Lo;0;L;;;;;N;;;;; +15E9;CANADIAN SYLLABICS CARRIER PO;Lo;0;L;;;;;N;;;;; +15EA;CANADIAN SYLLABICS CARRIER PE;Lo;0;L;;;;;N;;;;; +15EB;CANADIAN SYLLABICS CARRIER PEE;Lo;0;L;;;;;N;;;;; +15EC;CANADIAN SYLLABICS CARRIER PI;Lo;0;L;;;;;N;;;;; +15ED;CANADIAN SYLLABICS CARRIER PA;Lo;0;L;;;;;N;;;;; +15EE;CANADIAN SYLLABICS CARRIER P;Lo;0;L;;;;;N;;;;; +15EF;CANADIAN SYLLABICS CARRIER GU;Lo;0;L;;;;;N;;;;; +15F0;CANADIAN SYLLABICS CARRIER GO;Lo;0;L;;;;;N;;;;; +15F1;CANADIAN SYLLABICS CARRIER GE;Lo;0;L;;;;;N;;;;; +15F2;CANADIAN SYLLABICS CARRIER GEE;Lo;0;L;;;;;N;;;;; +15F3;CANADIAN SYLLABICS CARRIER GI;Lo;0;L;;;;;N;;;;; +15F4;CANADIAN SYLLABICS CARRIER GA;Lo;0;L;;;;;N;;;;; +15F5;CANADIAN SYLLABICS CARRIER KHU;Lo;0;L;;;;;N;;;;; +15F6;CANADIAN SYLLABICS CARRIER KHO;Lo;0;L;;;;;N;;;;; +15F7;CANADIAN SYLLABICS CARRIER KHE;Lo;0;L;;;;;N;;;;; +15F8;CANADIAN SYLLABICS CARRIER KHEE;Lo;0;L;;;;;N;;;;; +15F9;CANADIAN SYLLABICS CARRIER KHI;Lo;0;L;;;;;N;;;;; +15FA;CANADIAN SYLLABICS CARRIER KHA;Lo;0;L;;;;;N;;;;; +15FB;CANADIAN SYLLABICS CARRIER KKU;Lo;0;L;;;;;N;;;;; +15FC;CANADIAN SYLLABICS CARRIER KKO;Lo;0;L;;;;;N;;;;; +15FD;CANADIAN SYLLABICS CARRIER KKE;Lo;0;L;;;;;N;;;;; +15FE;CANADIAN SYLLABICS CARRIER KKEE;Lo;0;L;;;;;N;;;;; +15FF;CANADIAN SYLLABICS CARRIER KKI;Lo;0;L;;;;;N;;;;; +1600;CANADIAN SYLLABICS CARRIER KKA;Lo;0;L;;;;;N;;;;; +1601;CANADIAN SYLLABICS CARRIER KK;Lo;0;L;;;;;N;;;;; +1602;CANADIAN SYLLABICS CARRIER NU;Lo;0;L;;;;;N;;;;; +1603;CANADIAN SYLLABICS CARRIER NO;Lo;0;L;;;;;N;;;;; +1604;CANADIAN SYLLABICS CARRIER NE;Lo;0;L;;;;;N;;;;; +1605;CANADIAN SYLLABICS CARRIER NEE;Lo;0;L;;;;;N;;;;; +1606;CANADIAN SYLLABICS CARRIER NI;Lo;0;L;;;;;N;;;;; +1607;CANADIAN SYLLABICS CARRIER NA;Lo;0;L;;;;;N;;;;; +1608;CANADIAN SYLLABICS CARRIER MU;Lo;0;L;;;;;N;;;;; +1609;CANADIAN SYLLABICS CARRIER MO;Lo;0;L;;;;;N;;;;; +160A;CANADIAN SYLLABICS CARRIER ME;Lo;0;L;;;;;N;;;;; +160B;CANADIAN SYLLABICS CARRIER MEE;Lo;0;L;;;;;N;;;;; +160C;CANADIAN SYLLABICS CARRIER MI;Lo;0;L;;;;;N;;;;; +160D;CANADIAN SYLLABICS CARRIER MA;Lo;0;L;;;;;N;;;;; +160E;CANADIAN SYLLABICS CARRIER YU;Lo;0;L;;;;;N;;;;; +160F;CANADIAN SYLLABICS CARRIER YO;Lo;0;L;;;;;N;;;;; +1610;CANADIAN SYLLABICS CARRIER YE;Lo;0;L;;;;;N;;;;; +1611;CANADIAN SYLLABICS CARRIER YEE;Lo;0;L;;;;;N;;;;; +1612;CANADIAN SYLLABICS CARRIER YI;Lo;0;L;;;;;N;;;;; +1613;CANADIAN SYLLABICS CARRIER YA;Lo;0;L;;;;;N;;;;; +1614;CANADIAN SYLLABICS CARRIER JU;Lo;0;L;;;;;N;;;;; +1615;CANADIAN SYLLABICS SAYISI JU;Lo;0;L;;;;;N;;;;; +1616;CANADIAN SYLLABICS CARRIER JO;Lo;0;L;;;;;N;;;;; +1617;CANADIAN SYLLABICS CARRIER JE;Lo;0;L;;;;;N;;;;; +1618;CANADIAN SYLLABICS CARRIER JEE;Lo;0;L;;;;;N;;;;; +1619;CANADIAN SYLLABICS CARRIER JI;Lo;0;L;;;;;N;;;;; +161A;CANADIAN SYLLABICS SAYISI JI;Lo;0;L;;;;;N;;;;; +161B;CANADIAN SYLLABICS CARRIER JA;Lo;0;L;;;;;N;;;;; +161C;CANADIAN SYLLABICS CARRIER JJU;Lo;0;L;;;;;N;;;;; +161D;CANADIAN SYLLABICS CARRIER JJO;Lo;0;L;;;;;N;;;;; +161E;CANADIAN SYLLABICS CARRIER JJE;Lo;0;L;;;;;N;;;;; +161F;CANADIAN SYLLABICS CARRIER JJEE;Lo;0;L;;;;;N;;;;; +1620;CANADIAN SYLLABICS CARRIER JJI;Lo;0;L;;;;;N;;;;; +1621;CANADIAN SYLLABICS CARRIER JJA;Lo;0;L;;;;;N;;;;; +1622;CANADIAN SYLLABICS CARRIER LU;Lo;0;L;;;;;N;;;;; +1623;CANADIAN SYLLABICS CARRIER LO;Lo;0;L;;;;;N;;;;; +1624;CANADIAN SYLLABICS CARRIER LE;Lo;0;L;;;;;N;;;;; +1625;CANADIAN SYLLABICS CARRIER LEE;Lo;0;L;;;;;N;;;;; +1626;CANADIAN SYLLABICS CARRIER LI;Lo;0;L;;;;;N;;;;; +1627;CANADIAN SYLLABICS CARRIER LA;Lo;0;L;;;;;N;;;;; +1628;CANADIAN SYLLABICS CARRIER DLU;Lo;0;L;;;;;N;;;;; +1629;CANADIAN SYLLABICS CARRIER DLO;Lo;0;L;;;;;N;;;;; +162A;CANADIAN SYLLABICS CARRIER DLE;Lo;0;L;;;;;N;;;;; +162B;CANADIAN SYLLABICS CARRIER DLEE;Lo;0;L;;;;;N;;;;; +162C;CANADIAN SYLLABICS CARRIER DLI;Lo;0;L;;;;;N;;;;; +162D;CANADIAN SYLLABICS CARRIER DLA;Lo;0;L;;;;;N;;;;; +162E;CANADIAN SYLLABICS CARRIER LHU;Lo;0;L;;;;;N;;;;; +162F;CANADIAN SYLLABICS CARRIER LHO;Lo;0;L;;;;;N;;;;; +1630;CANADIAN SYLLABICS CARRIER LHE;Lo;0;L;;;;;N;;;;; +1631;CANADIAN SYLLABICS CARRIER LHEE;Lo;0;L;;;;;N;;;;; +1632;CANADIAN SYLLABICS CARRIER LHI;Lo;0;L;;;;;N;;;;; +1633;CANADIAN SYLLABICS CARRIER LHA;Lo;0;L;;;;;N;;;;; +1634;CANADIAN SYLLABICS CARRIER TLHU;Lo;0;L;;;;;N;;;;; +1635;CANADIAN SYLLABICS CARRIER TLHO;Lo;0;L;;;;;N;;;;; +1636;CANADIAN SYLLABICS CARRIER TLHE;Lo;0;L;;;;;N;;;;; +1637;CANADIAN SYLLABICS CARRIER TLHEE;Lo;0;L;;;;;N;;;;; +1638;CANADIAN SYLLABICS CARRIER TLHI;Lo;0;L;;;;;N;;;;; +1639;CANADIAN SYLLABICS CARRIER TLHA;Lo;0;L;;;;;N;;;;; +163A;CANADIAN SYLLABICS CARRIER TLU;Lo;0;L;;;;;N;;;;; +163B;CANADIAN SYLLABICS CARRIER TLO;Lo;0;L;;;;;N;;;;; +163C;CANADIAN SYLLABICS CARRIER TLE;Lo;0;L;;;;;N;;;;; +163D;CANADIAN SYLLABICS CARRIER TLEE;Lo;0;L;;;;;N;;;;; +163E;CANADIAN SYLLABICS CARRIER TLI;Lo;0;L;;;;;N;;;;; +163F;CANADIAN SYLLABICS CARRIER TLA;Lo;0;L;;;;;N;;;;; +1640;CANADIAN SYLLABICS CARRIER ZU;Lo;0;L;;;;;N;;;;; +1641;CANADIAN SYLLABICS CARRIER ZO;Lo;0;L;;;;;N;;;;; +1642;CANADIAN SYLLABICS CARRIER ZE;Lo;0;L;;;;;N;;;;; +1643;CANADIAN SYLLABICS CARRIER ZEE;Lo;0;L;;;;;N;;;;; +1644;CANADIAN SYLLABICS CARRIER ZI;Lo;0;L;;;;;N;;;;; +1645;CANADIAN SYLLABICS CARRIER ZA;Lo;0;L;;;;;N;;;;; +1646;CANADIAN SYLLABICS CARRIER Z;Lo;0;L;;;;;N;;;;; +1647;CANADIAN SYLLABICS CARRIER INITIAL Z;Lo;0;L;;;;;N;;;;; +1648;CANADIAN SYLLABICS CARRIER DZU;Lo;0;L;;;;;N;;;;; +1649;CANADIAN SYLLABICS CARRIER DZO;Lo;0;L;;;;;N;;;;; +164A;CANADIAN SYLLABICS CARRIER DZE;Lo;0;L;;;;;N;;;;; +164B;CANADIAN SYLLABICS CARRIER DZEE;Lo;0;L;;;;;N;;;;; +164C;CANADIAN SYLLABICS CARRIER DZI;Lo;0;L;;;;;N;;;;; +164D;CANADIAN SYLLABICS CARRIER DZA;Lo;0;L;;;;;N;;;;; +164E;CANADIAN SYLLABICS CARRIER SU;Lo;0;L;;;;;N;;;;; +164F;CANADIAN SYLLABICS CARRIER SO;Lo;0;L;;;;;N;;;;; +1650;CANADIAN SYLLABICS CARRIER SE;Lo;0;L;;;;;N;;;;; +1651;CANADIAN SYLLABICS CARRIER SEE;Lo;0;L;;;;;N;;;;; +1652;CANADIAN SYLLABICS CARRIER SI;Lo;0;L;;;;;N;;;;; +1653;CANADIAN SYLLABICS CARRIER SA;Lo;0;L;;;;;N;;;;; +1654;CANADIAN SYLLABICS CARRIER SHU;Lo;0;L;;;;;N;;;;; +1655;CANADIAN SYLLABICS CARRIER SHO;Lo;0;L;;;;;N;;;;; +1656;CANADIAN SYLLABICS CARRIER SHE;Lo;0;L;;;;;N;;;;; +1657;CANADIAN SYLLABICS CARRIER SHEE;Lo;0;L;;;;;N;;;;; +1658;CANADIAN SYLLABICS CARRIER SHI;Lo;0;L;;;;;N;;;;; +1659;CANADIAN SYLLABICS CARRIER SHA;Lo;0;L;;;;;N;;;;; +165A;CANADIAN SYLLABICS CARRIER SH;Lo;0;L;;;;;N;;;;; +165B;CANADIAN SYLLABICS CARRIER TSU;Lo;0;L;;;;;N;;;;; +165C;CANADIAN SYLLABICS CARRIER TSO;Lo;0;L;;;;;N;;;;; +165D;CANADIAN SYLLABICS CARRIER TSE;Lo;0;L;;;;;N;;;;; +165E;CANADIAN SYLLABICS CARRIER TSEE;Lo;0;L;;;;;N;;;;; +165F;CANADIAN SYLLABICS CARRIER TSI;Lo;0;L;;;;;N;;;;; +1660;CANADIAN SYLLABICS CARRIER TSA;Lo;0;L;;;;;N;;;;; +1661;CANADIAN SYLLABICS CARRIER CHU;Lo;0;L;;;;;N;;;;; +1662;CANADIAN SYLLABICS CARRIER CHO;Lo;0;L;;;;;N;;;;; +1663;CANADIAN SYLLABICS CARRIER CHE;Lo;0;L;;;;;N;;;;; +1664;CANADIAN SYLLABICS CARRIER CHEE;Lo;0;L;;;;;N;;;;; +1665;CANADIAN SYLLABICS CARRIER CHI;Lo;0;L;;;;;N;;;;; +1666;CANADIAN SYLLABICS CARRIER CHA;Lo;0;L;;;;;N;;;;; +1667;CANADIAN SYLLABICS CARRIER TTSU;Lo;0;L;;;;;N;;;;; +1668;CANADIAN SYLLABICS CARRIER TTSO;Lo;0;L;;;;;N;;;;; +1669;CANADIAN SYLLABICS CARRIER TTSE;Lo;0;L;;;;;N;;;;; +166A;CANADIAN SYLLABICS CARRIER TTSEE;Lo;0;L;;;;;N;;;;; +166B;CANADIAN SYLLABICS CARRIER TTSI;Lo;0;L;;;;;N;;;;; +166C;CANADIAN SYLLABICS CARRIER TTSA;Lo;0;L;;;;;N;;;;; +166D;CANADIAN SYLLABICS CHI SIGN;So;0;L;;;;;N;;;;; +166E;CANADIAN SYLLABICS FULL STOP;Po;0;L;;;;;N;;;;; +166F;CANADIAN SYLLABICS QAI;Lo;0;L;;;;;N;;;;; +1670;CANADIAN SYLLABICS NGAI;Lo;0;L;;;;;N;;;;; +1671;CANADIAN SYLLABICS NNGI;Lo;0;L;;;;;N;;;;; +1672;CANADIAN SYLLABICS NNGII;Lo;0;L;;;;;N;;;;; +1673;CANADIAN SYLLABICS NNGO;Lo;0;L;;;;;N;;;;; +1674;CANADIAN SYLLABICS NNGOO;Lo;0;L;;;;;N;;;;; +1675;CANADIAN SYLLABICS NNGA;Lo;0;L;;;;;N;;;;; +1676;CANADIAN SYLLABICS NNGAA;Lo;0;L;;;;;N;;;;; +1677;CANADIAN SYLLABICS WOODS-CREE THWEE;Lo;0;L;;;;;N;;;;; +1678;CANADIAN SYLLABICS WOODS-CREE THWI;Lo;0;L;;;;;N;;;;; +1679;CANADIAN SYLLABICS WOODS-CREE THWII;Lo;0;L;;;;;N;;;;; +167A;CANADIAN SYLLABICS WOODS-CREE THWO;Lo;0;L;;;;;N;;;;; +167B;CANADIAN SYLLABICS WOODS-CREE THWOO;Lo;0;L;;;;;N;;;;; +167C;CANADIAN SYLLABICS WOODS-CREE THWA;Lo;0;L;;;;;N;;;;; +167D;CANADIAN SYLLABICS WOODS-CREE THWAA;Lo;0;L;;;;;N;;;;; +167E;CANADIAN SYLLABICS WOODS-CREE FINAL TH;Lo;0;L;;;;;N;;;;; +167F;CANADIAN SYLLABICS BLACKFOOT W;Lo;0;L;;;;;N;;;;; +1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;; +1681;OGHAM LETTER BEITH;Lo;0;L;;;;;N;;;;; +1682;OGHAM LETTER LUIS;Lo;0;L;;;;;N;;;;; +1683;OGHAM LETTER FEARN;Lo;0;L;;;;;N;;;;; +1684;OGHAM LETTER SAIL;Lo;0;L;;;;;N;;;;; +1685;OGHAM LETTER NION;Lo;0;L;;;;;N;;;;; +1686;OGHAM LETTER UATH;Lo;0;L;;;;;N;;;;; +1687;OGHAM LETTER DAIR;Lo;0;L;;;;;N;;;;; +1688;OGHAM LETTER TINNE;Lo;0;L;;;;;N;;;;; +1689;OGHAM LETTER COLL;Lo;0;L;;;;;N;;;;; +168A;OGHAM LETTER CEIRT;Lo;0;L;;;;;N;;;;; +168B;OGHAM LETTER MUIN;Lo;0;L;;;;;N;;;;; +168C;OGHAM LETTER GORT;Lo;0;L;;;;;N;;;;; +168D;OGHAM LETTER NGEADAL;Lo;0;L;;;;;N;;;;; +168E;OGHAM LETTER STRAIF;Lo;0;L;;;;;N;;;;; +168F;OGHAM LETTER RUIS;Lo;0;L;;;;;N;;;;; +1690;OGHAM LETTER AILM;Lo;0;L;;;;;N;;;;; +1691;OGHAM LETTER ONN;Lo;0;L;;;;;N;;;;; +1692;OGHAM LETTER UR;Lo;0;L;;;;;N;;;;; +1693;OGHAM LETTER EADHADH;Lo;0;L;;;;;N;;;;; +1694;OGHAM LETTER IODHADH;Lo;0;L;;;;;N;;;;; +1695;OGHAM LETTER EABHADH;Lo;0;L;;;;;N;;;;; +1696;OGHAM LETTER OR;Lo;0;L;;;;;N;;;;; +1697;OGHAM LETTER UILLEANN;Lo;0;L;;;;;N;;;;; +1698;OGHAM LETTER IFIN;Lo;0;L;;;;;N;;;;; +1699;OGHAM LETTER EAMHANCHOLL;Lo;0;L;;;;;N;;;;; +169A;OGHAM LETTER PEITH;Lo;0;L;;;;;N;;;;; +169B;OGHAM FEATHER MARK;Ps;0;ON;;;;;Y;;;;; +169C;OGHAM REVERSED FEATHER MARK;Pe;0;ON;;;;;Y;;;;; +16A0;RUNIC LETTER FEHU FEOH FE F;Lo;0;L;;;;;N;;;;; +16A1;RUNIC LETTER V;Lo;0;L;;;;;N;;;;; +16A2;RUNIC LETTER URUZ UR U;Lo;0;L;;;;;N;;;;; +16A3;RUNIC LETTER YR;Lo;0;L;;;;;N;;;;; +16A4;RUNIC LETTER Y;Lo;0;L;;;;;N;;;;; +16A5;RUNIC LETTER W;Lo;0;L;;;;;N;;;;; +16A6;RUNIC LETTER THURISAZ THURS THORN;Lo;0;L;;;;;N;;;;; +16A7;RUNIC LETTER ETH;Lo;0;L;;;;;N;;;;; +16A8;RUNIC LETTER ANSUZ A;Lo;0;L;;;;;N;;;;; +16A9;RUNIC LETTER OS O;Lo;0;L;;;;;N;;;;; +16AA;RUNIC LETTER AC A;Lo;0;L;;;;;N;;;;; +16AB;RUNIC LETTER AESC;Lo;0;L;;;;;N;;;;; +16AC;RUNIC LETTER LONG-BRANCH-OSS O;Lo;0;L;;;;;N;;;;; +16AD;RUNIC LETTER SHORT-TWIG-OSS O;Lo;0;L;;;;;N;;;;; +16AE;RUNIC LETTER O;Lo;0;L;;;;;N;;;;; +16AF;RUNIC LETTER OE;Lo;0;L;;;;;N;;;;; +16B0;RUNIC LETTER ON;Lo;0;L;;;;;N;;;;; +16B1;RUNIC LETTER RAIDO RAD REID R;Lo;0;L;;;;;N;;;;; +16B2;RUNIC LETTER KAUNA;Lo;0;L;;;;;N;;;;; +16B3;RUNIC LETTER CEN;Lo;0;L;;;;;N;;;;; +16B4;RUNIC LETTER KAUN K;Lo;0;L;;;;;N;;;;; +16B5;RUNIC LETTER G;Lo;0;L;;;;;N;;;;; +16B6;RUNIC LETTER ENG;Lo;0;L;;;;;N;;;;; +16B7;RUNIC LETTER GEBO GYFU G;Lo;0;L;;;;;N;;;;; +16B8;RUNIC LETTER GAR;Lo;0;L;;;;;N;;;;; +16B9;RUNIC LETTER WUNJO WYNN W;Lo;0;L;;;;;N;;;;; +16BA;RUNIC LETTER HAGLAZ H;Lo;0;L;;;;;N;;;;; +16BB;RUNIC LETTER HAEGL H;Lo;0;L;;;;;N;;;;; +16BC;RUNIC LETTER LONG-BRANCH-HAGALL H;Lo;0;L;;;;;N;;;;; +16BD;RUNIC LETTER SHORT-TWIG-HAGALL H;Lo;0;L;;;;;N;;;;; +16BE;RUNIC LETTER NAUDIZ NYD NAUD N;Lo;0;L;;;;;N;;;;; +16BF;RUNIC LETTER SHORT-TWIG-NAUD N;Lo;0;L;;;;;N;;;;; +16C0;RUNIC LETTER DOTTED-N;Lo;0;L;;;;;N;;;;; +16C1;RUNIC LETTER ISAZ IS ISS I;Lo;0;L;;;;;N;;;;; +16C2;RUNIC LETTER E;Lo;0;L;;;;;N;;;;; +16C3;RUNIC LETTER JERAN J;Lo;0;L;;;;;N;;;;; +16C4;RUNIC LETTER GER;Lo;0;L;;;;;N;;;;; +16C5;RUNIC LETTER LONG-BRANCH-AR AE;Lo;0;L;;;;;N;;;;; +16C6;RUNIC LETTER SHORT-TWIG-AR A;Lo;0;L;;;;;N;;;;; +16C7;RUNIC LETTER IWAZ EOH;Lo;0;L;;;;;N;;;;; +16C8;RUNIC LETTER PERTHO PEORTH P;Lo;0;L;;;;;N;;;;; +16C9;RUNIC LETTER ALGIZ EOLHX;Lo;0;L;;;;;N;;;;; +16CA;RUNIC LETTER SOWILO S;Lo;0;L;;;;;N;;;;; +16CB;RUNIC LETTER SIGEL LONG-BRANCH-SOL S;Lo;0;L;;;;;N;;;;; +16CC;RUNIC LETTER SHORT-TWIG-SOL S;Lo;0;L;;;;;N;;;;; +16CD;RUNIC LETTER C;Lo;0;L;;;;;N;;;;; +16CE;RUNIC LETTER Z;Lo;0;L;;;;;N;;;;; +16CF;RUNIC LETTER TIWAZ TIR TYR T;Lo;0;L;;;;;N;;;;; +16D0;RUNIC LETTER SHORT-TWIG-TYR T;Lo;0;L;;;;;N;;;;; +16D1;RUNIC LETTER D;Lo;0;L;;;;;N;;;;; +16D2;RUNIC LETTER BERKANAN BEORC BJARKAN B;Lo;0;L;;;;;N;;;;; +16D3;RUNIC LETTER SHORT-TWIG-BJARKAN B;Lo;0;L;;;;;N;;;;; +16D4;RUNIC LETTER DOTTED-P;Lo;0;L;;;;;N;;;;; +16D5;RUNIC LETTER OPEN-P;Lo;0;L;;;;;N;;;;; +16D6;RUNIC LETTER EHWAZ EH E;Lo;0;L;;;;;N;;;;; +16D7;RUNIC LETTER MANNAZ MAN M;Lo;0;L;;;;;N;;;;; +16D8;RUNIC LETTER LONG-BRANCH-MADR M;Lo;0;L;;;;;N;;;;; +16D9;RUNIC LETTER SHORT-TWIG-MADR M;Lo;0;L;;;;;N;;;;; +16DA;RUNIC LETTER LAUKAZ LAGU LOGR L;Lo;0;L;;;;;N;;;;; +16DB;RUNIC LETTER DOTTED-L;Lo;0;L;;;;;N;;;;; +16DC;RUNIC LETTER INGWAZ;Lo;0;L;;;;;N;;;;; +16DD;RUNIC LETTER ING;Lo;0;L;;;;;N;;;;; +16DE;RUNIC LETTER DAGAZ DAEG D;Lo;0;L;;;;;N;;;;; +16DF;RUNIC LETTER OTHALAN ETHEL O;Lo;0;L;;;;;N;;;;; +16E0;RUNIC LETTER EAR;Lo;0;L;;;;;N;;;;; +16E1;RUNIC LETTER IOR;Lo;0;L;;;;;N;;;;; +16E2;RUNIC LETTER CWEORTH;Lo;0;L;;;;;N;;;;; +16E3;RUNIC LETTER CALC;Lo;0;L;;;;;N;;;;; +16E4;RUNIC LETTER CEALC;Lo;0;L;;;;;N;;;;; +16E5;RUNIC LETTER STAN;Lo;0;L;;;;;N;;;;; +16E6;RUNIC LETTER LONG-BRANCH-YR;Lo;0;L;;;;;N;;;;; +16E7;RUNIC LETTER SHORT-TWIG-YR;Lo;0;L;;;;;N;;;;; +16E8;RUNIC LETTER ICELANDIC-YR;Lo;0;L;;;;;N;;;;; +16E9;RUNIC LETTER Q;Lo;0;L;;;;;N;;;;; +16EA;RUNIC LETTER X;Lo;0;L;;;;;N;;;;; +16EB;RUNIC SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;; +16EC;RUNIC MULTIPLE PUNCTUATION;Po;0;L;;;;;N;;;;; +16ED;RUNIC CROSS PUNCTUATION;Po;0;L;;;;;N;;;;; +16EE;RUNIC ARLAUG SYMBOL;Nl;0;L;;;;17;N;;;;; +16EF;RUNIC TVIMADUR SYMBOL;Nl;0;L;;;;18;N;;;;; +16F0;RUNIC BELGTHOR SYMBOL;Nl;0;L;;;;19;N;;;;; +16F1;RUNIC LETTER K;Lo;0;L;;;;;N;;;;; +16F2;RUNIC LETTER SH;Lo;0;L;;;;;N;;;;; +16F3;RUNIC LETTER OO;Lo;0;L;;;;;N;;;;; +16F4;RUNIC LETTER FRANKS CASKET OS;Lo;0;L;;;;;N;;;;; +16F5;RUNIC LETTER FRANKS CASKET IS;Lo;0;L;;;;;N;;;;; +16F6;RUNIC LETTER FRANKS CASKET EH;Lo;0;L;;;;;N;;;;; +16F7;RUNIC LETTER FRANKS CASKET AC;Lo;0;L;;;;;N;;;;; +16F8;RUNIC LETTER FRANKS CASKET AESC;Lo;0;L;;;;;N;;;;; +1700;TAGALOG LETTER A;Lo;0;L;;;;;N;;;;; +1701;TAGALOG LETTER I;Lo;0;L;;;;;N;;;;; +1702;TAGALOG LETTER U;Lo;0;L;;;;;N;;;;; +1703;TAGALOG LETTER KA;Lo;0;L;;;;;N;;;;; +1704;TAGALOG LETTER GA;Lo;0;L;;;;;N;;;;; +1705;TAGALOG LETTER NGA;Lo;0;L;;;;;N;;;;; +1706;TAGALOG LETTER TA;Lo;0;L;;;;;N;;;;; +1707;TAGALOG LETTER DA;Lo;0;L;;;;;N;;;;; +1708;TAGALOG LETTER NA;Lo;0;L;;;;;N;;;;; +1709;TAGALOG LETTER PA;Lo;0;L;;;;;N;;;;; +170A;TAGALOG LETTER BA;Lo;0;L;;;;;N;;;;; +170B;TAGALOG LETTER MA;Lo;0;L;;;;;N;;;;; +170C;TAGALOG LETTER YA;Lo;0;L;;;;;N;;;;; +170D;TAGALOG LETTER RA;Lo;0;L;;;;;N;;;;; +170E;TAGALOG LETTER LA;Lo;0;L;;;;;N;;;;; +170F;TAGALOG LETTER WA;Lo;0;L;;;;;N;;;;; +1710;TAGALOG LETTER SA;Lo;0;L;;;;;N;;;;; +1711;TAGALOG LETTER HA;Lo;0;L;;;;;N;;;;; +1712;TAGALOG VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +1713;TAGALOG VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1714;TAGALOG SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +1715;TAGALOG SIGN PAMUDPOD;Mc;9;L;;;;;N;;;;; +171F;TAGALOG LETTER ARCHAIC RA;Lo;0;L;;;;;N;;;;; +1720;HANUNOO LETTER A;Lo;0;L;;;;;N;;;;; +1721;HANUNOO LETTER I;Lo;0;L;;;;;N;;;;; +1722;HANUNOO LETTER U;Lo;0;L;;;;;N;;;;; +1723;HANUNOO LETTER KA;Lo;0;L;;;;;N;;;;; +1724;HANUNOO LETTER GA;Lo;0;L;;;;;N;;;;; +1725;HANUNOO LETTER NGA;Lo;0;L;;;;;N;;;;; +1726;HANUNOO LETTER TA;Lo;0;L;;;;;N;;;;; +1727;HANUNOO LETTER DA;Lo;0;L;;;;;N;;;;; +1728;HANUNOO LETTER NA;Lo;0;L;;;;;N;;;;; +1729;HANUNOO LETTER PA;Lo;0;L;;;;;N;;;;; +172A;HANUNOO LETTER BA;Lo;0;L;;;;;N;;;;; +172B;HANUNOO LETTER MA;Lo;0;L;;;;;N;;;;; +172C;HANUNOO LETTER YA;Lo;0;L;;;;;N;;;;; +172D;HANUNOO LETTER RA;Lo;0;L;;;;;N;;;;; +172E;HANUNOO LETTER LA;Lo;0;L;;;;;N;;;;; +172F;HANUNOO LETTER WA;Lo;0;L;;;;;N;;;;; +1730;HANUNOO LETTER SA;Lo;0;L;;;;;N;;;;; +1731;HANUNOO LETTER HA;Lo;0;L;;;;;N;;;;; +1732;HANUNOO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +1733;HANUNOO VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1734;HANUNOO SIGN PAMUDPOD;Mc;9;L;;;;;N;;;;; +1735;PHILIPPINE SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;; +1736;PHILIPPINE DOUBLE PUNCTUATION;Po;0;L;;;;;N;;;;; +1740;BUHID LETTER A;Lo;0;L;;;;;N;;;;; +1741;BUHID LETTER I;Lo;0;L;;;;;N;;;;; +1742;BUHID LETTER U;Lo;0;L;;;;;N;;;;; +1743;BUHID LETTER KA;Lo;0;L;;;;;N;;;;; +1744;BUHID LETTER GA;Lo;0;L;;;;;N;;;;; +1745;BUHID LETTER NGA;Lo;0;L;;;;;N;;;;; +1746;BUHID LETTER TA;Lo;0;L;;;;;N;;;;; +1747;BUHID LETTER DA;Lo;0;L;;;;;N;;;;; +1748;BUHID LETTER NA;Lo;0;L;;;;;N;;;;; +1749;BUHID LETTER PA;Lo;0;L;;;;;N;;;;; +174A;BUHID LETTER BA;Lo;0;L;;;;;N;;;;; +174B;BUHID LETTER MA;Lo;0;L;;;;;N;;;;; +174C;BUHID LETTER YA;Lo;0;L;;;;;N;;;;; +174D;BUHID LETTER RA;Lo;0;L;;;;;N;;;;; +174E;BUHID LETTER LA;Lo;0;L;;;;;N;;;;; +174F;BUHID LETTER WA;Lo;0;L;;;;;N;;;;; +1750;BUHID LETTER SA;Lo;0;L;;;;;N;;;;; +1751;BUHID LETTER HA;Lo;0;L;;;;;N;;;;; +1752;BUHID VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +1753;BUHID VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1760;TAGBANWA LETTER A;Lo;0;L;;;;;N;;;;; +1761;TAGBANWA LETTER I;Lo;0;L;;;;;N;;;;; +1762;TAGBANWA LETTER U;Lo;0;L;;;;;N;;;;; +1763;TAGBANWA LETTER KA;Lo;0;L;;;;;N;;;;; +1764;TAGBANWA LETTER GA;Lo;0;L;;;;;N;;;;; +1765;TAGBANWA LETTER NGA;Lo;0;L;;;;;N;;;;; +1766;TAGBANWA LETTER TA;Lo;0;L;;;;;N;;;;; +1767;TAGBANWA LETTER DA;Lo;0;L;;;;;N;;;;; +1768;TAGBANWA LETTER NA;Lo;0;L;;;;;N;;;;; +1769;TAGBANWA LETTER PA;Lo;0;L;;;;;N;;;;; +176A;TAGBANWA LETTER BA;Lo;0;L;;;;;N;;;;; +176B;TAGBANWA LETTER MA;Lo;0;L;;;;;N;;;;; +176C;TAGBANWA LETTER YA;Lo;0;L;;;;;N;;;;; +176E;TAGBANWA LETTER LA;Lo;0;L;;;;;N;;;;; +176F;TAGBANWA LETTER WA;Lo;0;L;;;;;N;;;;; +1770;TAGBANWA LETTER SA;Lo;0;L;;;;;N;;;;; +1772;TAGBANWA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +1773;TAGBANWA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1780;KHMER LETTER KA;Lo;0;L;;;;;N;;;;; +1781;KHMER LETTER KHA;Lo;0;L;;;;;N;;;;; +1782;KHMER LETTER KO;Lo;0;L;;;;;N;;;;; +1783;KHMER LETTER KHO;Lo;0;L;;;;;N;;;;; +1784;KHMER LETTER NGO;Lo;0;L;;;;;N;;;;; +1785;KHMER LETTER CA;Lo;0;L;;;;;N;;;;; +1786;KHMER LETTER CHA;Lo;0;L;;;;;N;;;;; +1787;KHMER LETTER CO;Lo;0;L;;;;;N;;;;; +1788;KHMER LETTER CHO;Lo;0;L;;;;;N;;;;; +1789;KHMER LETTER NYO;Lo;0;L;;;;;N;;;;; +178A;KHMER LETTER DA;Lo;0;L;;;;;N;;;;; +178B;KHMER LETTER TTHA;Lo;0;L;;;;;N;;;;; +178C;KHMER LETTER DO;Lo;0;L;;;;;N;;;;; +178D;KHMER LETTER TTHO;Lo;0;L;;;;;N;;;;; +178E;KHMER LETTER NNO;Lo;0;L;;;;;N;;;;; +178F;KHMER LETTER TA;Lo;0;L;;;;;N;;;;; +1790;KHMER LETTER THA;Lo;0;L;;;;;N;;;;; +1791;KHMER LETTER TO;Lo;0;L;;;;;N;;;;; +1792;KHMER LETTER THO;Lo;0;L;;;;;N;;;;; +1793;KHMER LETTER NO;Lo;0;L;;;;;N;;;;; +1794;KHMER LETTER BA;Lo;0;L;;;;;N;;;;; +1795;KHMER LETTER PHA;Lo;0;L;;;;;N;;;;; +1796;KHMER LETTER PO;Lo;0;L;;;;;N;;;;; +1797;KHMER LETTER PHO;Lo;0;L;;;;;N;;;;; +1798;KHMER LETTER MO;Lo;0;L;;;;;N;;;;; +1799;KHMER LETTER YO;Lo;0;L;;;;;N;;;;; +179A;KHMER LETTER RO;Lo;0;L;;;;;N;;;;; +179B;KHMER LETTER LO;Lo;0;L;;;;;N;;;;; +179C;KHMER LETTER VO;Lo;0;L;;;;;N;;;;; +179D;KHMER LETTER SHA;Lo;0;L;;;;;N;;;;; +179E;KHMER LETTER SSO;Lo;0;L;;;;;N;;;;; +179F;KHMER LETTER SA;Lo;0;L;;;;;N;;;;; +17A0;KHMER LETTER HA;Lo;0;L;;;;;N;;;;; +17A1;KHMER LETTER LA;Lo;0;L;;;;;N;;;;; +17A2;KHMER LETTER QA;Lo;0;L;;;;;N;;;;; +17A3;KHMER INDEPENDENT VOWEL QAQ;Lo;0;L;;;;;N;;;;; +17A4;KHMER INDEPENDENT VOWEL QAA;Lo;0;L;;;;;N;;;;; +17A5;KHMER INDEPENDENT VOWEL QI;Lo;0;L;;;;;N;;;;; +17A6;KHMER INDEPENDENT VOWEL QII;Lo;0;L;;;;;N;;;;; +17A7;KHMER INDEPENDENT VOWEL QU;Lo;0;L;;;;;N;;;;; +17A8;KHMER INDEPENDENT VOWEL QUK;Lo;0;L;;;;;N;;;;; +17A9;KHMER INDEPENDENT VOWEL QUU;Lo;0;L;;;;;N;;;;; +17AA;KHMER INDEPENDENT VOWEL QUUV;Lo;0;L;;;;;N;;;;; +17AB;KHMER INDEPENDENT VOWEL RY;Lo;0;L;;;;;N;;;;; +17AC;KHMER INDEPENDENT VOWEL RYY;Lo;0;L;;;;;N;;;;; +17AD;KHMER INDEPENDENT VOWEL LY;Lo;0;L;;;;;N;;;;; +17AE;KHMER INDEPENDENT VOWEL LYY;Lo;0;L;;;;;N;;;;; +17AF;KHMER INDEPENDENT VOWEL QE;Lo;0;L;;;;;N;;;;; +17B0;KHMER INDEPENDENT VOWEL QAI;Lo;0;L;;;;;N;;;;; +17B1;KHMER INDEPENDENT VOWEL QOO TYPE ONE;Lo;0;L;;;;;N;;;;; +17B2;KHMER INDEPENDENT VOWEL QOO TYPE TWO;Lo;0;L;;;;;N;;;;; +17B3;KHMER INDEPENDENT VOWEL QAU;Lo;0;L;;;;;N;;;;; +17B4;KHMER VOWEL INHERENT AQ;Mn;0;NSM;;;;;N;;;;; +17B5;KHMER VOWEL INHERENT AA;Mn;0;NSM;;;;;N;;;;; +17B6;KHMER VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +17B7;KHMER VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +17B8;KHMER VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +17B9;KHMER VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;; +17BA;KHMER VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;; +17BB;KHMER VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +17BC;KHMER VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +17BD;KHMER VOWEL SIGN UA;Mn;0;NSM;;;;;N;;;;; +17BE;KHMER VOWEL SIGN OE;Mc;0;L;;;;;N;;;;; +17BF;KHMER VOWEL SIGN YA;Mc;0;L;;;;;N;;;;; +17C0;KHMER VOWEL SIGN IE;Mc;0;L;;;;;N;;;;; +17C1;KHMER VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +17C2;KHMER VOWEL SIGN AE;Mc;0;L;;;;;N;;;;; +17C3;KHMER VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +17C4;KHMER VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; +17C5;KHMER VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +17C6;KHMER SIGN NIKAHIT;Mn;0;NSM;;;;;N;;;;; +17C7;KHMER SIGN REAHMUK;Mc;0;L;;;;;N;;;;; +17C8;KHMER SIGN YUUKALEAPINTU;Mc;0;L;;;;;N;;;;; +17C9;KHMER SIGN MUUSIKATOAN;Mn;0;NSM;;;;;N;;;;; +17CA;KHMER SIGN TRIISAP;Mn;0;NSM;;;;;N;;;;; +17CB;KHMER SIGN BANTOC;Mn;0;NSM;;;;;N;;;;; +17CC;KHMER SIGN ROBAT;Mn;0;NSM;;;;;N;;;;; +17CD;KHMER SIGN TOANDAKHIAT;Mn;0;NSM;;;;;N;;;;; +17CE;KHMER SIGN KAKABAT;Mn;0;NSM;;;;;N;;;;; +17CF;KHMER SIGN AHSDA;Mn;0;NSM;;;;;N;;;;; +17D0;KHMER SIGN SAMYOK SANNYA;Mn;0;NSM;;;;;N;;;;; +17D1;KHMER SIGN VIRIAM;Mn;0;NSM;;;;;N;;;;; +17D2;KHMER SIGN COENG;Mn;9;NSM;;;;;N;;;;; +17D3;KHMER SIGN BATHAMASAT;Mn;0;NSM;;;;;N;;;;; +17D4;KHMER SIGN KHAN;Po;0;L;;;;;N;;;;; +17D5;KHMER SIGN BARIYOOSAN;Po;0;L;;;;;N;;;;; +17D6;KHMER SIGN CAMNUC PII KUUH;Po;0;L;;;;;N;;;;; +17D7;KHMER SIGN LEK TOO;Lm;0;L;;;;;N;;;;; +17D8;KHMER SIGN BEYYAL;Po;0;L;;;;;N;;;;; +17D9;KHMER SIGN PHNAEK MUAN;Po;0;L;;;;;N;;;;; +17DA;KHMER SIGN KOOMUUT;Po;0;L;;;;;N;;;;; +17DB;KHMER CURRENCY SYMBOL RIEL;Sc;0;ET;;;;;N;;;;; +17DC;KHMER SIGN AVAKRAHASANYA;Lo;0;L;;;;;N;;;;; +17DD;KHMER SIGN ATTHACAN;Mn;230;NSM;;;;;N;;;;; +17E0;KHMER DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +17E1;KHMER DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +17E2;KHMER DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +17E3;KHMER DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +17E4;KHMER DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +17E5;KHMER DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +17E6;KHMER DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +17E7;KHMER DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +17E8;KHMER DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +17E9;KHMER DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +17F0;KHMER SYMBOL LEK ATTAK SON;No;0;ON;;;;0;N;;;;; +17F1;KHMER SYMBOL LEK ATTAK MUOY;No;0;ON;;;;1;N;;;;; +17F2;KHMER SYMBOL LEK ATTAK PII;No;0;ON;;;;2;N;;;;; +17F3;KHMER SYMBOL LEK ATTAK BEI;No;0;ON;;;;3;N;;;;; +17F4;KHMER SYMBOL LEK ATTAK BUON;No;0;ON;;;;4;N;;;;; +17F5;KHMER SYMBOL LEK ATTAK PRAM;No;0;ON;;;;5;N;;;;; +17F6;KHMER SYMBOL LEK ATTAK PRAM-MUOY;No;0;ON;;;;6;N;;;;; +17F7;KHMER SYMBOL LEK ATTAK PRAM-PII;No;0;ON;;;;7;N;;;;; +17F8;KHMER SYMBOL LEK ATTAK PRAM-BEI;No;0;ON;;;;8;N;;;;; +17F9;KHMER SYMBOL LEK ATTAK PRAM-BUON;No;0;ON;;;;9;N;;;;; +1800;MONGOLIAN BIRGA;Po;0;ON;;;;;N;;;;; +1801;MONGOLIAN ELLIPSIS;Po;0;ON;;;;;N;;;;; +1802;MONGOLIAN COMMA;Po;0;ON;;;;;N;;;;; +1803;MONGOLIAN FULL STOP;Po;0;ON;;;;;N;;;;; +1804;MONGOLIAN COLON;Po;0;ON;;;;;N;;;;; +1805;MONGOLIAN FOUR DOTS;Po;0;ON;;;;;N;;;;; +1806;MONGOLIAN TODO SOFT HYPHEN;Pd;0;ON;;;;;N;;;;; +1807;MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER;Po;0;ON;;;;;N;;;;; +1808;MONGOLIAN MANCHU COMMA;Po;0;ON;;;;;N;;;;; +1809;MONGOLIAN MANCHU FULL STOP;Po;0;ON;;;;;N;;;;; +180A;MONGOLIAN NIRUGU;Po;0;ON;;;;;N;;;;; +180B;MONGOLIAN FREE VARIATION SELECTOR ONE;Mn;0;NSM;;;;;N;;;;; +180C;MONGOLIAN FREE VARIATION SELECTOR TWO;Mn;0;NSM;;;;;N;;;;; +180D;MONGOLIAN FREE VARIATION SELECTOR THREE;Mn;0;NSM;;;;;N;;;;; +180E;MONGOLIAN VOWEL SEPARATOR;Cf;0;BN;;;;;N;;;;; +180F;MONGOLIAN FREE VARIATION SELECTOR FOUR;Mn;0;NSM;;;;;N;;;;; +1810;MONGOLIAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1811;MONGOLIAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1812;MONGOLIAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1813;MONGOLIAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1814;MONGOLIAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1815;MONGOLIAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1816;MONGOLIAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1817;MONGOLIAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1818;MONGOLIAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1819;MONGOLIAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1820;MONGOLIAN LETTER A;Lo;0;L;;;;;N;;;;; +1821;MONGOLIAN LETTER E;Lo;0;L;;;;;N;;;;; +1822;MONGOLIAN LETTER I;Lo;0;L;;;;;N;;;;; +1823;MONGOLIAN LETTER O;Lo;0;L;;;;;N;;;;; +1824;MONGOLIAN LETTER U;Lo;0;L;;;;;N;;;;; +1825;MONGOLIAN LETTER OE;Lo;0;L;;;;;N;;;;; +1826;MONGOLIAN LETTER UE;Lo;0;L;;;;;N;;;;; +1827;MONGOLIAN LETTER EE;Lo;0;L;;;;;N;;;;; +1828;MONGOLIAN LETTER NA;Lo;0;L;;;;;N;;;;; +1829;MONGOLIAN LETTER ANG;Lo;0;L;;;;;N;;;;; +182A;MONGOLIAN LETTER BA;Lo;0;L;;;;;N;;;;; +182B;MONGOLIAN LETTER PA;Lo;0;L;;;;;N;;;;; +182C;MONGOLIAN LETTER QA;Lo;0;L;;;;;N;;;;; +182D;MONGOLIAN LETTER GA;Lo;0;L;;;;;N;;;;; +182E;MONGOLIAN LETTER MA;Lo;0;L;;;;;N;;;;; +182F;MONGOLIAN LETTER LA;Lo;0;L;;;;;N;;;;; +1830;MONGOLIAN LETTER SA;Lo;0;L;;;;;N;;;;; +1831;MONGOLIAN LETTER SHA;Lo;0;L;;;;;N;;;;; +1832;MONGOLIAN LETTER TA;Lo;0;L;;;;;N;;;;; +1833;MONGOLIAN LETTER DA;Lo;0;L;;;;;N;;;;; +1834;MONGOLIAN LETTER CHA;Lo;0;L;;;;;N;;;;; +1835;MONGOLIAN LETTER JA;Lo;0;L;;;;;N;;;;; +1836;MONGOLIAN LETTER YA;Lo;0;L;;;;;N;;;;; +1837;MONGOLIAN LETTER RA;Lo;0;L;;;;;N;;;;; +1838;MONGOLIAN LETTER WA;Lo;0;L;;;;;N;;;;; +1839;MONGOLIAN LETTER FA;Lo;0;L;;;;;N;;;;; +183A;MONGOLIAN LETTER KA;Lo;0;L;;;;;N;;;;; +183B;MONGOLIAN LETTER KHA;Lo;0;L;;;;;N;;;;; +183C;MONGOLIAN LETTER TSA;Lo;0;L;;;;;N;;;;; +183D;MONGOLIAN LETTER ZA;Lo;0;L;;;;;N;;;;; +183E;MONGOLIAN LETTER HAA;Lo;0;L;;;;;N;;;;; +183F;MONGOLIAN LETTER ZRA;Lo;0;L;;;;;N;;;;; +1840;MONGOLIAN LETTER LHA;Lo;0;L;;;;;N;;;;; +1841;MONGOLIAN LETTER ZHI;Lo;0;L;;;;;N;;;;; +1842;MONGOLIAN LETTER CHI;Lo;0;L;;;;;N;;;;; +1843;MONGOLIAN LETTER TODO LONG VOWEL SIGN;Lm;0;L;;;;;N;;;;; +1844;MONGOLIAN LETTER TODO E;Lo;0;L;;;;;N;;;;; +1845;MONGOLIAN LETTER TODO I;Lo;0;L;;;;;N;;;;; +1846;MONGOLIAN LETTER TODO O;Lo;0;L;;;;;N;;;;; +1847;MONGOLIAN LETTER TODO U;Lo;0;L;;;;;N;;;;; +1848;MONGOLIAN LETTER TODO OE;Lo;0;L;;;;;N;;;;; +1849;MONGOLIAN LETTER TODO UE;Lo;0;L;;;;;N;;;;; +184A;MONGOLIAN LETTER TODO ANG;Lo;0;L;;;;;N;;;;; +184B;MONGOLIAN LETTER TODO BA;Lo;0;L;;;;;N;;;;; +184C;MONGOLIAN LETTER TODO PA;Lo;0;L;;;;;N;;;;; +184D;MONGOLIAN LETTER TODO QA;Lo;0;L;;;;;N;;;;; +184E;MONGOLIAN LETTER TODO GA;Lo;0;L;;;;;N;;;;; +184F;MONGOLIAN LETTER TODO MA;Lo;0;L;;;;;N;;;;; +1850;MONGOLIAN LETTER TODO TA;Lo;0;L;;;;;N;;;;; +1851;MONGOLIAN LETTER TODO DA;Lo;0;L;;;;;N;;;;; +1852;MONGOLIAN LETTER TODO CHA;Lo;0;L;;;;;N;;;;; +1853;MONGOLIAN LETTER TODO JA;Lo;0;L;;;;;N;;;;; +1854;MONGOLIAN LETTER TODO TSA;Lo;0;L;;;;;N;;;;; +1855;MONGOLIAN LETTER TODO YA;Lo;0;L;;;;;N;;;;; +1856;MONGOLIAN LETTER TODO WA;Lo;0;L;;;;;N;;;;; +1857;MONGOLIAN LETTER TODO KA;Lo;0;L;;;;;N;;;;; +1858;MONGOLIAN LETTER TODO GAA;Lo;0;L;;;;;N;;;;; +1859;MONGOLIAN LETTER TODO HAA;Lo;0;L;;;;;N;;;;; +185A;MONGOLIAN LETTER TODO JIA;Lo;0;L;;;;;N;;;;; +185B;MONGOLIAN LETTER TODO NIA;Lo;0;L;;;;;N;;;;; +185C;MONGOLIAN LETTER TODO DZA;Lo;0;L;;;;;N;;;;; +185D;MONGOLIAN LETTER SIBE E;Lo;0;L;;;;;N;;;;; +185E;MONGOLIAN LETTER SIBE I;Lo;0;L;;;;;N;;;;; +185F;MONGOLIAN LETTER SIBE IY;Lo;0;L;;;;;N;;;;; +1860;MONGOLIAN LETTER SIBE UE;Lo;0;L;;;;;N;;;;; +1861;MONGOLIAN LETTER SIBE U;Lo;0;L;;;;;N;;;;; +1862;MONGOLIAN LETTER SIBE ANG;Lo;0;L;;;;;N;;;;; +1863;MONGOLIAN LETTER SIBE KA;Lo;0;L;;;;;N;;;;; +1864;MONGOLIAN LETTER SIBE GA;Lo;0;L;;;;;N;;;;; +1865;MONGOLIAN LETTER SIBE HA;Lo;0;L;;;;;N;;;;; +1866;MONGOLIAN LETTER SIBE PA;Lo;0;L;;;;;N;;;;; +1867;MONGOLIAN LETTER SIBE SHA;Lo;0;L;;;;;N;;;;; +1868;MONGOLIAN LETTER SIBE TA;Lo;0;L;;;;;N;;;;; +1869;MONGOLIAN LETTER SIBE DA;Lo;0;L;;;;;N;;;;; +186A;MONGOLIAN LETTER SIBE JA;Lo;0;L;;;;;N;;;;; +186B;MONGOLIAN LETTER SIBE FA;Lo;0;L;;;;;N;;;;; +186C;MONGOLIAN LETTER SIBE GAA;Lo;0;L;;;;;N;;;;; +186D;MONGOLIAN LETTER SIBE HAA;Lo;0;L;;;;;N;;;;; +186E;MONGOLIAN LETTER SIBE TSA;Lo;0;L;;;;;N;;;;; +186F;MONGOLIAN LETTER SIBE ZA;Lo;0;L;;;;;N;;;;; +1870;MONGOLIAN LETTER SIBE RAA;Lo;0;L;;;;;N;;;;; +1871;MONGOLIAN LETTER SIBE CHA;Lo;0;L;;;;;N;;;;; +1872;MONGOLIAN LETTER SIBE ZHA;Lo;0;L;;;;;N;;;;; +1873;MONGOLIAN LETTER MANCHU I;Lo;0;L;;;;;N;;;;; +1874;MONGOLIAN LETTER MANCHU KA;Lo;0;L;;;;;N;;;;; +1875;MONGOLIAN LETTER MANCHU RA;Lo;0;L;;;;;N;;;;; +1876;MONGOLIAN LETTER MANCHU FA;Lo;0;L;;;;;N;;;;; +1877;MONGOLIAN LETTER MANCHU ZHA;Lo;0;L;;;;;N;;;;; +1878;MONGOLIAN LETTER CHA WITH TWO DOTS;Lo;0;L;;;;;N;;;;; +1880;MONGOLIAN LETTER ALI GALI ANUSVARA ONE;Lo;0;L;;;;;N;;;;; +1881;MONGOLIAN LETTER ALI GALI VISARGA ONE;Lo;0;L;;;;;N;;;;; +1882;MONGOLIAN LETTER ALI GALI DAMARU;Lo;0;L;;;;;N;;;;; +1883;MONGOLIAN LETTER ALI GALI UBADAMA;Lo;0;L;;;;;N;;;;; +1884;MONGOLIAN LETTER ALI GALI INVERTED UBADAMA;Lo;0;L;;;;;N;;;;; +1885;MONGOLIAN LETTER ALI GALI BALUDA;Mn;0;NSM;;;;;N;;;;; +1886;MONGOLIAN LETTER ALI GALI THREE BALUDA;Mn;0;NSM;;;;;N;;;;; +1887;MONGOLIAN LETTER ALI GALI A;Lo;0;L;;;;;N;;;;; +1888;MONGOLIAN LETTER ALI GALI I;Lo;0;L;;;;;N;;;;; +1889;MONGOLIAN LETTER ALI GALI KA;Lo;0;L;;;;;N;;;;; +188A;MONGOLIAN LETTER ALI GALI NGA;Lo;0;L;;;;;N;;;;; +188B;MONGOLIAN LETTER ALI GALI CA;Lo;0;L;;;;;N;;;;; +188C;MONGOLIAN LETTER ALI GALI TTA;Lo;0;L;;;;;N;;;;; +188D;MONGOLIAN LETTER ALI GALI TTHA;Lo;0;L;;;;;N;;;;; +188E;MONGOLIAN LETTER ALI GALI DDA;Lo;0;L;;;;;N;;;;; +188F;MONGOLIAN LETTER ALI GALI NNA;Lo;0;L;;;;;N;;;;; +1890;MONGOLIAN LETTER ALI GALI TA;Lo;0;L;;;;;N;;;;; +1891;MONGOLIAN LETTER ALI GALI DA;Lo;0;L;;;;;N;;;;; +1892;MONGOLIAN LETTER ALI GALI PA;Lo;0;L;;;;;N;;;;; +1893;MONGOLIAN LETTER ALI GALI PHA;Lo;0;L;;;;;N;;;;; +1894;MONGOLIAN LETTER ALI GALI SSA;Lo;0;L;;;;;N;;;;; +1895;MONGOLIAN LETTER ALI GALI ZHA;Lo;0;L;;;;;N;;;;; +1896;MONGOLIAN LETTER ALI GALI ZA;Lo;0;L;;;;;N;;;;; +1897;MONGOLIAN LETTER ALI GALI AH;Lo;0;L;;;;;N;;;;; +1898;MONGOLIAN LETTER TODO ALI GALI TA;Lo;0;L;;;;;N;;;;; +1899;MONGOLIAN LETTER TODO ALI GALI ZHA;Lo;0;L;;;;;N;;;;; +189A;MONGOLIAN LETTER MANCHU ALI GALI GHA;Lo;0;L;;;;;N;;;;; +189B;MONGOLIAN LETTER MANCHU ALI GALI NGA;Lo;0;L;;;;;N;;;;; +189C;MONGOLIAN LETTER MANCHU ALI GALI CA;Lo;0;L;;;;;N;;;;; +189D;MONGOLIAN LETTER MANCHU ALI GALI JHA;Lo;0;L;;;;;N;;;;; +189E;MONGOLIAN LETTER MANCHU ALI GALI TTA;Lo;0;L;;;;;N;;;;; +189F;MONGOLIAN LETTER MANCHU ALI GALI DDHA;Lo;0;L;;;;;N;;;;; +18A0;MONGOLIAN LETTER MANCHU ALI GALI TA;Lo;0;L;;;;;N;;;;; +18A1;MONGOLIAN LETTER MANCHU ALI GALI DHA;Lo;0;L;;;;;N;;;;; +18A2;MONGOLIAN LETTER MANCHU ALI GALI SSA;Lo;0;L;;;;;N;;;;; +18A3;MONGOLIAN LETTER MANCHU ALI GALI CYA;Lo;0;L;;;;;N;;;;; +18A4;MONGOLIAN LETTER MANCHU ALI GALI ZHA;Lo;0;L;;;;;N;;;;; +18A5;MONGOLIAN LETTER MANCHU ALI GALI ZA;Lo;0;L;;;;;N;;;;; +18A6;MONGOLIAN LETTER ALI GALI HALF U;Lo;0;L;;;;;N;;;;; +18A7;MONGOLIAN LETTER ALI GALI HALF YA;Lo;0;L;;;;;N;;;;; +18A8;MONGOLIAN LETTER MANCHU ALI GALI BHA;Lo;0;L;;;;;N;;;;; +18A9;MONGOLIAN LETTER ALI GALI DAGALGA;Mn;228;NSM;;;;;N;;;;; +18AA;MONGOLIAN LETTER MANCHU ALI GALI LHA;Lo;0;L;;;;;N;;;;; +18B0;CANADIAN SYLLABICS OY;Lo;0;L;;;;;N;;;;; +18B1;CANADIAN SYLLABICS AY;Lo;0;L;;;;;N;;;;; +18B2;CANADIAN SYLLABICS AAY;Lo;0;L;;;;;N;;;;; +18B3;CANADIAN SYLLABICS WAY;Lo;0;L;;;;;N;;;;; +18B4;CANADIAN SYLLABICS POY;Lo;0;L;;;;;N;;;;; +18B5;CANADIAN SYLLABICS PAY;Lo;0;L;;;;;N;;;;; +18B6;CANADIAN SYLLABICS PWOY;Lo;0;L;;;;;N;;;;; +18B7;CANADIAN SYLLABICS TAY;Lo;0;L;;;;;N;;;;; +18B8;CANADIAN SYLLABICS KAY;Lo;0;L;;;;;N;;;;; +18B9;CANADIAN SYLLABICS KWAY;Lo;0;L;;;;;N;;;;; +18BA;CANADIAN SYLLABICS MAY;Lo;0;L;;;;;N;;;;; +18BB;CANADIAN SYLLABICS NOY;Lo;0;L;;;;;N;;;;; +18BC;CANADIAN SYLLABICS NAY;Lo;0;L;;;;;N;;;;; +18BD;CANADIAN SYLLABICS LAY;Lo;0;L;;;;;N;;;;; +18BE;CANADIAN SYLLABICS SOY;Lo;0;L;;;;;N;;;;; +18BF;CANADIAN SYLLABICS SAY;Lo;0;L;;;;;N;;;;; +18C0;CANADIAN SYLLABICS SHOY;Lo;0;L;;;;;N;;;;; +18C1;CANADIAN SYLLABICS SHAY;Lo;0;L;;;;;N;;;;; +18C2;CANADIAN SYLLABICS SHWOY;Lo;0;L;;;;;N;;;;; +18C3;CANADIAN SYLLABICS YOY;Lo;0;L;;;;;N;;;;; +18C4;CANADIAN SYLLABICS YAY;Lo;0;L;;;;;N;;;;; +18C5;CANADIAN SYLLABICS RAY;Lo;0;L;;;;;N;;;;; +18C6;CANADIAN SYLLABICS NWI;Lo;0;L;;;;;N;;;;; +18C7;CANADIAN SYLLABICS OJIBWAY NWI;Lo;0;L;;;;;N;;;;; +18C8;CANADIAN SYLLABICS NWII;Lo;0;L;;;;;N;;;;; +18C9;CANADIAN SYLLABICS OJIBWAY NWII;Lo;0;L;;;;;N;;;;; +18CA;CANADIAN SYLLABICS NWO;Lo;0;L;;;;;N;;;;; +18CB;CANADIAN SYLLABICS OJIBWAY NWO;Lo;0;L;;;;;N;;;;; +18CC;CANADIAN SYLLABICS NWOO;Lo;0;L;;;;;N;;;;; +18CD;CANADIAN SYLLABICS OJIBWAY NWOO;Lo;0;L;;;;;N;;;;; +18CE;CANADIAN SYLLABICS RWEE;Lo;0;L;;;;;N;;;;; +18CF;CANADIAN SYLLABICS RWI;Lo;0;L;;;;;N;;;;; +18D0;CANADIAN SYLLABICS RWII;Lo;0;L;;;;;N;;;;; +18D1;CANADIAN SYLLABICS RWO;Lo;0;L;;;;;N;;;;; +18D2;CANADIAN SYLLABICS RWOO;Lo;0;L;;;;;N;;;;; +18D3;CANADIAN SYLLABICS RWA;Lo;0;L;;;;;N;;;;; +18D4;CANADIAN SYLLABICS OJIBWAY P;Lo;0;L;;;;;N;;;;; +18D5;CANADIAN SYLLABICS OJIBWAY T;Lo;0;L;;;;;N;;;;; +18D6;CANADIAN SYLLABICS OJIBWAY K;Lo;0;L;;;;;N;;;;; +18D7;CANADIAN SYLLABICS OJIBWAY C;Lo;0;L;;;;;N;;;;; +18D8;CANADIAN SYLLABICS OJIBWAY M;Lo;0;L;;;;;N;;;;; +18D9;CANADIAN SYLLABICS OJIBWAY N;Lo;0;L;;;;;N;;;;; +18DA;CANADIAN SYLLABICS OJIBWAY S;Lo;0;L;;;;;N;;;;; +18DB;CANADIAN SYLLABICS OJIBWAY SH;Lo;0;L;;;;;N;;;;; +18DC;CANADIAN SYLLABICS EASTERN W;Lo;0;L;;;;;N;;;;; +18DD;CANADIAN SYLLABICS WESTERN W;Lo;0;L;;;;;N;;;;; +18DE;CANADIAN SYLLABICS FINAL SMALL RING;Lo;0;L;;;;;N;;;;; +18DF;CANADIAN SYLLABICS FINAL RAISED DOT;Lo;0;L;;;;;N;;;;; +18E0;CANADIAN SYLLABICS R-CREE RWE;Lo;0;L;;;;;N;;;;; +18E1;CANADIAN SYLLABICS WEST-CREE LOO;Lo;0;L;;;;;N;;;;; +18E2;CANADIAN SYLLABICS WEST-CREE LAA;Lo;0;L;;;;;N;;;;; +18E3;CANADIAN SYLLABICS THWE;Lo;0;L;;;;;N;;;;; +18E4;CANADIAN SYLLABICS THWA;Lo;0;L;;;;;N;;;;; +18E5;CANADIAN SYLLABICS TTHWE;Lo;0;L;;;;;N;;;;; +18E6;CANADIAN SYLLABICS TTHOO;Lo;0;L;;;;;N;;;;; +18E7;CANADIAN SYLLABICS TTHAA;Lo;0;L;;;;;N;;;;; +18E8;CANADIAN SYLLABICS TLHWE;Lo;0;L;;;;;N;;;;; +18E9;CANADIAN SYLLABICS TLHOO;Lo;0;L;;;;;N;;;;; +18EA;CANADIAN SYLLABICS SAYISI SHWE;Lo;0;L;;;;;N;;;;; +18EB;CANADIAN SYLLABICS SAYISI SHOO;Lo;0;L;;;;;N;;;;; +18EC;CANADIAN SYLLABICS SAYISI HOO;Lo;0;L;;;;;N;;;;; +18ED;CANADIAN SYLLABICS CARRIER GWU;Lo;0;L;;;;;N;;;;; +18EE;CANADIAN SYLLABICS CARRIER DENE GEE;Lo;0;L;;;;;N;;;;; +18EF;CANADIAN SYLLABICS CARRIER GAA;Lo;0;L;;;;;N;;;;; +18F0;CANADIAN SYLLABICS CARRIER GWA;Lo;0;L;;;;;N;;;;; +18F1;CANADIAN SYLLABICS SAYISI JUU;Lo;0;L;;;;;N;;;;; +18F2;CANADIAN SYLLABICS CARRIER JWA;Lo;0;L;;;;;N;;;;; +18F3;CANADIAN SYLLABICS BEAVER DENE L;Lo;0;L;;;;;N;;;;; +18F4;CANADIAN SYLLABICS BEAVER DENE R;Lo;0;L;;;;;N;;;;; +18F5;CANADIAN SYLLABICS CARRIER DENTAL S;Lo;0;L;;;;;N;;;;; +1900;LIMBU VOWEL-CARRIER LETTER;Lo;0;L;;;;;N;;;;; +1901;LIMBU LETTER KA;Lo;0;L;;;;;N;;;;; +1902;LIMBU LETTER KHA;Lo;0;L;;;;;N;;;;; +1903;LIMBU LETTER GA;Lo;0;L;;;;;N;;;;; +1904;LIMBU LETTER GHA;Lo;0;L;;;;;N;;;;; +1905;LIMBU LETTER NGA;Lo;0;L;;;;;N;;;;; +1906;LIMBU LETTER CA;Lo;0;L;;;;;N;;;;; +1907;LIMBU LETTER CHA;Lo;0;L;;;;;N;;;;; +1908;LIMBU LETTER JA;Lo;0;L;;;;;N;;;;; +1909;LIMBU LETTER JHA;Lo;0;L;;;;;N;;;;; +190A;LIMBU LETTER YAN;Lo;0;L;;;;;N;;;;; +190B;LIMBU LETTER TA;Lo;0;L;;;;;N;;;;; +190C;LIMBU LETTER THA;Lo;0;L;;;;;N;;;;; +190D;LIMBU LETTER DA;Lo;0;L;;;;;N;;;;; +190E;LIMBU LETTER DHA;Lo;0;L;;;;;N;;;;; +190F;LIMBU LETTER NA;Lo;0;L;;;;;N;;;;; +1910;LIMBU LETTER PA;Lo;0;L;;;;;N;;;;; +1911;LIMBU LETTER PHA;Lo;0;L;;;;;N;;;;; +1912;LIMBU LETTER BA;Lo;0;L;;;;;N;;;;; +1913;LIMBU LETTER BHA;Lo;0;L;;;;;N;;;;; +1914;LIMBU LETTER MA;Lo;0;L;;;;;N;;;;; +1915;LIMBU LETTER YA;Lo;0;L;;;;;N;;;;; +1916;LIMBU LETTER RA;Lo;0;L;;;;;N;;;;; +1917;LIMBU LETTER LA;Lo;0;L;;;;;N;;;;; +1918;LIMBU LETTER WA;Lo;0;L;;;;;N;;;;; +1919;LIMBU LETTER SHA;Lo;0;L;;;;;N;;;;; +191A;LIMBU LETTER SSA;Lo;0;L;;;;;N;;;;; +191B;LIMBU LETTER SA;Lo;0;L;;;;;N;;;;; +191C;LIMBU LETTER HA;Lo;0;L;;;;;N;;;;; +191D;LIMBU LETTER GYAN;Lo;0;L;;;;;N;;;;; +191E;LIMBU LETTER TRA;Lo;0;L;;;;;N;;;;; +1920;LIMBU VOWEL SIGN A;Mn;0;NSM;;;;;N;;;;; +1921;LIMBU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +1922;LIMBU VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1923;LIMBU VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; +1924;LIMBU VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +1925;LIMBU VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; +1926;LIMBU VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +1927;LIMBU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +1928;LIMBU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +1929;LIMBU SUBJOINED LETTER YA;Mc;0;L;;;;;N;;;;; +192A;LIMBU SUBJOINED LETTER RA;Mc;0;L;;;;;N;;;;; +192B;LIMBU SUBJOINED LETTER WA;Mc;0;L;;;;;N;;;;; +1930;LIMBU SMALL LETTER KA;Mc;0;L;;;;;N;;;;; +1931;LIMBU SMALL LETTER NGA;Mc;0;L;;;;;N;;;;; +1932;LIMBU SMALL LETTER ANUSVARA;Mn;0;NSM;;;;;N;;;;; +1933;LIMBU SMALL LETTER TA;Mc;0;L;;;;;N;;;;; +1934;LIMBU SMALL LETTER NA;Mc;0;L;;;;;N;;;;; +1935;LIMBU SMALL LETTER PA;Mc;0;L;;;;;N;;;;; +1936;LIMBU SMALL LETTER MA;Mc;0;L;;;;;N;;;;; +1937;LIMBU SMALL LETTER RA;Mc;0;L;;;;;N;;;;; +1938;LIMBU SMALL LETTER LA;Mc;0;L;;;;;N;;;;; +1939;LIMBU SIGN MUKPHRENG;Mn;222;NSM;;;;;N;;;;; +193A;LIMBU SIGN KEMPHRENG;Mn;230;NSM;;;;;N;;;;; +193B;LIMBU SIGN SA-I;Mn;220;NSM;;;;;N;;;;; +1940;LIMBU SIGN LOO;So;0;ON;;;;;N;;;;; +1944;LIMBU EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; +1945;LIMBU QUESTION MARK;Po;0;ON;;;;;N;;;;; +1946;LIMBU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1947;LIMBU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1948;LIMBU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1949;LIMBU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +194A;LIMBU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +194B;LIMBU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +194C;LIMBU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +194D;LIMBU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +194E;LIMBU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +194F;LIMBU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1950;TAI LE LETTER KA;Lo;0;L;;;;;N;;;;; +1951;TAI LE LETTER XA;Lo;0;L;;;;;N;;;;; +1952;TAI LE LETTER NGA;Lo;0;L;;;;;N;;;;; +1953;TAI LE LETTER TSA;Lo;0;L;;;;;N;;;;; +1954;TAI LE LETTER SA;Lo;0;L;;;;;N;;;;; +1955;TAI LE LETTER YA;Lo;0;L;;;;;N;;;;; +1956;TAI LE LETTER TA;Lo;0;L;;;;;N;;;;; +1957;TAI LE LETTER THA;Lo;0;L;;;;;N;;;;; +1958;TAI LE LETTER LA;Lo;0;L;;;;;N;;;;; +1959;TAI LE LETTER PA;Lo;0;L;;;;;N;;;;; +195A;TAI LE LETTER PHA;Lo;0;L;;;;;N;;;;; +195B;TAI LE LETTER MA;Lo;0;L;;;;;N;;;;; +195C;TAI LE LETTER FA;Lo;0;L;;;;;N;;;;; +195D;TAI LE LETTER VA;Lo;0;L;;;;;N;;;;; +195E;TAI LE LETTER HA;Lo;0;L;;;;;N;;;;; +195F;TAI LE LETTER QA;Lo;0;L;;;;;N;;;;; +1960;TAI LE LETTER KHA;Lo;0;L;;;;;N;;;;; +1961;TAI LE LETTER TSHA;Lo;0;L;;;;;N;;;;; +1962;TAI LE LETTER NA;Lo;0;L;;;;;N;;;;; +1963;TAI LE LETTER A;Lo;0;L;;;;;N;;;;; +1964;TAI LE LETTER I;Lo;0;L;;;;;N;;;;; +1965;TAI LE LETTER EE;Lo;0;L;;;;;N;;;;; +1966;TAI LE LETTER EH;Lo;0;L;;;;;N;;;;; +1967;TAI LE LETTER U;Lo;0;L;;;;;N;;;;; +1968;TAI LE LETTER OO;Lo;0;L;;;;;N;;;;; +1969;TAI LE LETTER O;Lo;0;L;;;;;N;;;;; +196A;TAI LE LETTER UE;Lo;0;L;;;;;N;;;;; +196B;TAI LE LETTER E;Lo;0;L;;;;;N;;;;; +196C;TAI LE LETTER AUE;Lo;0;L;;;;;N;;;;; +196D;TAI LE LETTER AI;Lo;0;L;;;;;N;;;;; +1970;TAI LE LETTER TONE-2;Lo;0;L;;;;;N;;;;; +1971;TAI LE LETTER TONE-3;Lo;0;L;;;;;N;;;;; +1972;TAI LE LETTER TONE-4;Lo;0;L;;;;;N;;;;; +1973;TAI LE LETTER TONE-5;Lo;0;L;;;;;N;;;;; +1974;TAI LE LETTER TONE-6;Lo;0;L;;;;;N;;;;; +1980;NEW TAI LUE LETTER HIGH QA;Lo;0;L;;;;;N;;;;; +1981;NEW TAI LUE LETTER LOW QA;Lo;0;L;;;;;N;;;;; +1982;NEW TAI LUE LETTER HIGH KA;Lo;0;L;;;;;N;;;;; +1983;NEW TAI LUE LETTER HIGH XA;Lo;0;L;;;;;N;;;;; +1984;NEW TAI LUE LETTER HIGH NGA;Lo;0;L;;;;;N;;;;; +1985;NEW TAI LUE LETTER LOW KA;Lo;0;L;;;;;N;;;;; +1986;NEW TAI LUE LETTER LOW XA;Lo;0;L;;;;;N;;;;; +1987;NEW TAI LUE LETTER LOW NGA;Lo;0;L;;;;;N;;;;; +1988;NEW TAI LUE LETTER HIGH TSA;Lo;0;L;;;;;N;;;;; +1989;NEW TAI LUE LETTER HIGH SA;Lo;0;L;;;;;N;;;;; +198A;NEW TAI LUE LETTER HIGH YA;Lo;0;L;;;;;N;;;;; +198B;NEW TAI LUE LETTER LOW TSA;Lo;0;L;;;;;N;;;;; +198C;NEW TAI LUE LETTER LOW SA;Lo;0;L;;;;;N;;;;; +198D;NEW TAI LUE LETTER LOW YA;Lo;0;L;;;;;N;;;;; +198E;NEW TAI LUE LETTER HIGH TA;Lo;0;L;;;;;N;;;;; +198F;NEW TAI LUE LETTER HIGH THA;Lo;0;L;;;;;N;;;;; +1990;NEW TAI LUE LETTER HIGH NA;Lo;0;L;;;;;N;;;;; +1991;NEW TAI LUE LETTER LOW TA;Lo;0;L;;;;;N;;;;; +1992;NEW TAI LUE LETTER LOW THA;Lo;0;L;;;;;N;;;;; +1993;NEW TAI LUE LETTER LOW NA;Lo;0;L;;;;;N;;;;; +1994;NEW TAI LUE LETTER HIGH PA;Lo;0;L;;;;;N;;;;; +1995;NEW TAI LUE LETTER HIGH PHA;Lo;0;L;;;;;N;;;;; +1996;NEW TAI LUE LETTER HIGH MA;Lo;0;L;;;;;N;;;;; +1997;NEW TAI LUE LETTER LOW PA;Lo;0;L;;;;;N;;;;; +1998;NEW TAI LUE LETTER LOW PHA;Lo;0;L;;;;;N;;;;; +1999;NEW TAI LUE LETTER LOW MA;Lo;0;L;;;;;N;;;;; +199A;NEW TAI LUE LETTER HIGH FA;Lo;0;L;;;;;N;;;;; +199B;NEW TAI LUE LETTER HIGH VA;Lo;0;L;;;;;N;;;;; +199C;NEW TAI LUE LETTER HIGH LA;Lo;0;L;;;;;N;;;;; +199D;NEW TAI LUE LETTER LOW FA;Lo;0;L;;;;;N;;;;; +199E;NEW TAI LUE LETTER LOW VA;Lo;0;L;;;;;N;;;;; +199F;NEW TAI LUE LETTER LOW LA;Lo;0;L;;;;;N;;;;; +19A0;NEW TAI LUE LETTER HIGH HA;Lo;0;L;;;;;N;;;;; +19A1;NEW TAI LUE LETTER HIGH DA;Lo;0;L;;;;;N;;;;; +19A2;NEW TAI LUE LETTER HIGH BA;Lo;0;L;;;;;N;;;;; +19A3;NEW TAI LUE LETTER LOW HA;Lo;0;L;;;;;N;;;;; +19A4;NEW TAI LUE LETTER LOW DA;Lo;0;L;;;;;N;;;;; +19A5;NEW TAI LUE LETTER LOW BA;Lo;0;L;;;;;N;;;;; +19A6;NEW TAI LUE LETTER HIGH KVA;Lo;0;L;;;;;N;;;;; +19A7;NEW TAI LUE LETTER HIGH XVA;Lo;0;L;;;;;N;;;;; +19A8;NEW TAI LUE LETTER LOW KVA;Lo;0;L;;;;;N;;;;; +19A9;NEW TAI LUE LETTER LOW XVA;Lo;0;L;;;;;N;;;;; +19AA;NEW TAI LUE LETTER HIGH SUA;Lo;0;L;;;;;N;;;;; +19AB;NEW TAI LUE LETTER LOW SUA;Lo;0;L;;;;;N;;;;; +19B0;NEW TAI LUE VOWEL SIGN VOWEL SHORTENER;Lo;0;L;;;;;N;;;;; +19B1;NEW TAI LUE VOWEL SIGN AA;Lo;0;L;;;;;N;;;;; +19B2;NEW TAI LUE VOWEL SIGN II;Lo;0;L;;;;;N;;;;; +19B3;NEW TAI LUE VOWEL SIGN U;Lo;0;L;;;;;N;;;;; +19B4;NEW TAI LUE VOWEL SIGN UU;Lo;0;L;;;;;N;;;;; +19B5;NEW TAI LUE VOWEL SIGN E;Lo;0;L;;;;;N;;;;; +19B6;NEW TAI LUE VOWEL SIGN AE;Lo;0;L;;;;;N;;;;; +19B7;NEW TAI LUE VOWEL SIGN O;Lo;0;L;;;;;N;;;;; +19B8;NEW TAI LUE VOWEL SIGN OA;Lo;0;L;;;;;N;;;;; +19B9;NEW TAI LUE VOWEL SIGN UE;Lo;0;L;;;;;N;;;;; +19BA;NEW TAI LUE VOWEL SIGN AY;Lo;0;L;;;;;N;;;;; +19BB;NEW TAI LUE VOWEL SIGN AAY;Lo;0;L;;;;;N;;;;; +19BC;NEW TAI LUE VOWEL SIGN UY;Lo;0;L;;;;;N;;;;; +19BD;NEW TAI LUE VOWEL SIGN OY;Lo;0;L;;;;;N;;;;; +19BE;NEW TAI LUE VOWEL SIGN OAY;Lo;0;L;;;;;N;;;;; +19BF;NEW TAI LUE VOWEL SIGN UEY;Lo;0;L;;;;;N;;;;; +19C0;NEW TAI LUE VOWEL SIGN IY;Lo;0;L;;;;;N;;;;; +19C1;NEW TAI LUE LETTER FINAL V;Lo;0;L;;;;;N;;;;; +19C2;NEW TAI LUE LETTER FINAL NG;Lo;0;L;;;;;N;;;;; +19C3;NEW TAI LUE LETTER FINAL N;Lo;0;L;;;;;N;;;;; +19C4;NEW TAI LUE LETTER FINAL M;Lo;0;L;;;;;N;;;;; +19C5;NEW TAI LUE LETTER FINAL K;Lo;0;L;;;;;N;;;;; +19C6;NEW TAI LUE LETTER FINAL D;Lo;0;L;;;;;N;;;;; +19C7;NEW TAI LUE LETTER FINAL B;Lo;0;L;;;;;N;;;;; +19C8;NEW TAI LUE TONE MARK-1;Lo;0;L;;;;;N;;;;; +19C9;NEW TAI LUE TONE MARK-2;Lo;0;L;;;;;N;;;;; +19D0;NEW TAI LUE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +19D1;NEW TAI LUE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +19D2;NEW TAI LUE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +19D3;NEW TAI LUE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +19D4;NEW TAI LUE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +19D5;NEW TAI LUE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +19D6;NEW TAI LUE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +19D7;NEW TAI LUE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +19D8;NEW TAI LUE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +19D9;NEW TAI LUE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +19DA;NEW TAI LUE THAM DIGIT ONE;No;0;L;;;1;1;N;;;;; +19DE;NEW TAI LUE SIGN LAE;So;0;ON;;;;;N;;;;; +19DF;NEW TAI LUE SIGN LAEV;So;0;ON;;;;;N;;;;; +19E0;KHMER SYMBOL PATHAMASAT;So;0;ON;;;;;N;;;;; +19E1;KHMER SYMBOL MUOY KOET;So;0;ON;;;;;N;;;;; +19E2;KHMER SYMBOL PII KOET;So;0;ON;;;;;N;;;;; +19E3;KHMER SYMBOL BEI KOET;So;0;ON;;;;;N;;;;; +19E4;KHMER SYMBOL BUON KOET;So;0;ON;;;;;N;;;;; +19E5;KHMER SYMBOL PRAM KOET;So;0;ON;;;;;N;;;;; +19E6;KHMER SYMBOL PRAM-MUOY KOET;So;0;ON;;;;;N;;;;; +19E7;KHMER SYMBOL PRAM-PII KOET;So;0;ON;;;;;N;;;;; +19E8;KHMER SYMBOL PRAM-BEI KOET;So;0;ON;;;;;N;;;;; +19E9;KHMER SYMBOL PRAM-BUON KOET;So;0;ON;;;;;N;;;;; +19EA;KHMER SYMBOL DAP KOET;So;0;ON;;;;;N;;;;; +19EB;KHMER SYMBOL DAP-MUOY KOET;So;0;ON;;;;;N;;;;; +19EC;KHMER SYMBOL DAP-PII KOET;So;0;ON;;;;;N;;;;; +19ED;KHMER SYMBOL DAP-BEI KOET;So;0;ON;;;;;N;;;;; +19EE;KHMER SYMBOL DAP-BUON KOET;So;0;ON;;;;;N;;;;; +19EF;KHMER SYMBOL DAP-PRAM KOET;So;0;ON;;;;;N;;;;; +19F0;KHMER SYMBOL TUTEYASAT;So;0;ON;;;;;N;;;;; +19F1;KHMER SYMBOL MUOY ROC;So;0;ON;;;;;N;;;;; +19F2;KHMER SYMBOL PII ROC;So;0;ON;;;;;N;;;;; +19F3;KHMER SYMBOL BEI ROC;So;0;ON;;;;;N;;;;; +19F4;KHMER SYMBOL BUON ROC;So;0;ON;;;;;N;;;;; +19F5;KHMER SYMBOL PRAM ROC;So;0;ON;;;;;N;;;;; +19F6;KHMER SYMBOL PRAM-MUOY ROC;So;0;ON;;;;;N;;;;; +19F7;KHMER SYMBOL PRAM-PII ROC;So;0;ON;;;;;N;;;;; +19F8;KHMER SYMBOL PRAM-BEI ROC;So;0;ON;;;;;N;;;;; +19F9;KHMER SYMBOL PRAM-BUON ROC;So;0;ON;;;;;N;;;;; +19FA;KHMER SYMBOL DAP ROC;So;0;ON;;;;;N;;;;; +19FB;KHMER SYMBOL DAP-MUOY ROC;So;0;ON;;;;;N;;;;; +19FC;KHMER SYMBOL DAP-PII ROC;So;0;ON;;;;;N;;;;; +19FD;KHMER SYMBOL DAP-BEI ROC;So;0;ON;;;;;N;;;;; +19FE;KHMER SYMBOL DAP-BUON ROC;So;0;ON;;;;;N;;;;; +19FF;KHMER SYMBOL DAP-PRAM ROC;So;0;ON;;;;;N;;;;; +1A00;BUGINESE LETTER KA;Lo;0;L;;;;;N;;;;; +1A01;BUGINESE LETTER GA;Lo;0;L;;;;;N;;;;; +1A02;BUGINESE LETTER NGA;Lo;0;L;;;;;N;;;;; +1A03;BUGINESE LETTER NGKA;Lo;0;L;;;;;N;;;;; +1A04;BUGINESE LETTER PA;Lo;0;L;;;;;N;;;;; +1A05;BUGINESE LETTER BA;Lo;0;L;;;;;N;;;;; +1A06;BUGINESE LETTER MA;Lo;0;L;;;;;N;;;;; +1A07;BUGINESE LETTER MPA;Lo;0;L;;;;;N;;;;; +1A08;BUGINESE LETTER TA;Lo;0;L;;;;;N;;;;; +1A09;BUGINESE LETTER DA;Lo;0;L;;;;;N;;;;; +1A0A;BUGINESE LETTER NA;Lo;0;L;;;;;N;;;;; +1A0B;BUGINESE LETTER NRA;Lo;0;L;;;;;N;;;;; +1A0C;BUGINESE LETTER CA;Lo;0;L;;;;;N;;;;; +1A0D;BUGINESE LETTER JA;Lo;0;L;;;;;N;;;;; +1A0E;BUGINESE LETTER NYA;Lo;0;L;;;;;N;;;;; +1A0F;BUGINESE LETTER NYCA;Lo;0;L;;;;;N;;;;; +1A10;BUGINESE LETTER YA;Lo;0;L;;;;;N;;;;; +1A11;BUGINESE LETTER RA;Lo;0;L;;;;;N;;;;; +1A12;BUGINESE LETTER LA;Lo;0;L;;;;;N;;;;; +1A13;BUGINESE LETTER VA;Lo;0;L;;;;;N;;;;; +1A14;BUGINESE LETTER SA;Lo;0;L;;;;;N;;;;; +1A15;BUGINESE LETTER A;Lo;0;L;;;;;N;;;;; +1A16;BUGINESE LETTER HA;Lo;0;L;;;;;N;;;;; +1A17;BUGINESE VOWEL SIGN I;Mn;230;NSM;;;;;N;;;;; +1A18;BUGINESE VOWEL SIGN U;Mn;220;NSM;;;;;N;;;;; +1A19;BUGINESE VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +1A1A;BUGINESE VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +1A1B;BUGINESE VOWEL SIGN AE;Mn;0;NSM;;;;;N;;;;; +1A1E;BUGINESE PALLAWA;Po;0;L;;;;;N;;;;; +1A1F;BUGINESE END OF SECTION;Po;0;L;;;;;N;;;;; +1A20;TAI THAM LETTER HIGH KA;Lo;0;L;;;;;N;;;;; +1A21;TAI THAM LETTER HIGH KHA;Lo;0;L;;;;;N;;;;; +1A22;TAI THAM LETTER HIGH KXA;Lo;0;L;;;;;N;;;;; +1A23;TAI THAM LETTER LOW KA;Lo;0;L;;;;;N;;;;; +1A24;TAI THAM LETTER LOW KXA;Lo;0;L;;;;;N;;;;; +1A25;TAI THAM LETTER LOW KHA;Lo;0;L;;;;;N;;;;; +1A26;TAI THAM LETTER NGA;Lo;0;L;;;;;N;;;;; +1A27;TAI THAM LETTER HIGH CA;Lo;0;L;;;;;N;;;;; +1A28;TAI THAM LETTER HIGH CHA;Lo;0;L;;;;;N;;;;; +1A29;TAI THAM LETTER LOW CA;Lo;0;L;;;;;N;;;;; +1A2A;TAI THAM LETTER LOW SA;Lo;0;L;;;;;N;;;;; +1A2B;TAI THAM LETTER LOW CHA;Lo;0;L;;;;;N;;;;; +1A2C;TAI THAM LETTER NYA;Lo;0;L;;;;;N;;;;; +1A2D;TAI THAM LETTER RATA;Lo;0;L;;;;;N;;;;; +1A2E;TAI THAM LETTER HIGH RATHA;Lo;0;L;;;;;N;;;;; +1A2F;TAI THAM LETTER DA;Lo;0;L;;;;;N;;;;; +1A30;TAI THAM LETTER LOW RATHA;Lo;0;L;;;;;N;;;;; +1A31;TAI THAM LETTER RANA;Lo;0;L;;;;;N;;;;; +1A32;TAI THAM LETTER HIGH TA;Lo;0;L;;;;;N;;;;; +1A33;TAI THAM LETTER HIGH THA;Lo;0;L;;;;;N;;;;; +1A34;TAI THAM LETTER LOW TA;Lo;0;L;;;;;N;;;;; +1A35;TAI THAM LETTER LOW THA;Lo;0;L;;;;;N;;;;; +1A36;TAI THAM LETTER NA;Lo;0;L;;;;;N;;;;; +1A37;TAI THAM LETTER BA;Lo;0;L;;;;;N;;;;; +1A38;TAI THAM LETTER HIGH PA;Lo;0;L;;;;;N;;;;; +1A39;TAI THAM LETTER HIGH PHA;Lo;0;L;;;;;N;;;;; +1A3A;TAI THAM LETTER HIGH FA;Lo;0;L;;;;;N;;;;; +1A3B;TAI THAM LETTER LOW PA;Lo;0;L;;;;;N;;;;; +1A3C;TAI THAM LETTER LOW FA;Lo;0;L;;;;;N;;;;; +1A3D;TAI THAM LETTER LOW PHA;Lo;0;L;;;;;N;;;;; +1A3E;TAI THAM LETTER MA;Lo;0;L;;;;;N;;;;; +1A3F;TAI THAM LETTER LOW YA;Lo;0;L;;;;;N;;;;; +1A40;TAI THAM LETTER HIGH YA;Lo;0;L;;;;;N;;;;; +1A41;TAI THAM LETTER RA;Lo;0;L;;;;;N;;;;; +1A42;TAI THAM LETTER RUE;Lo;0;L;;;;;N;;;;; +1A43;TAI THAM LETTER LA;Lo;0;L;;;;;N;;;;; +1A44;TAI THAM LETTER LUE;Lo;0;L;;;;;N;;;;; +1A45;TAI THAM LETTER WA;Lo;0;L;;;;;N;;;;; +1A46;TAI THAM LETTER HIGH SHA;Lo;0;L;;;;;N;;;;; +1A47;TAI THAM LETTER HIGH SSA;Lo;0;L;;;;;N;;;;; +1A48;TAI THAM LETTER HIGH SA;Lo;0;L;;;;;N;;;;; +1A49;TAI THAM LETTER HIGH HA;Lo;0;L;;;;;N;;;;; +1A4A;TAI THAM LETTER LLA;Lo;0;L;;;;;N;;;;; +1A4B;TAI THAM LETTER A;Lo;0;L;;;;;N;;;;; +1A4C;TAI THAM LETTER LOW HA;Lo;0;L;;;;;N;;;;; +1A4D;TAI THAM LETTER I;Lo;0;L;;;;;N;;;;; +1A4E;TAI THAM LETTER II;Lo;0;L;;;;;N;;;;; +1A4F;TAI THAM LETTER U;Lo;0;L;;;;;N;;;;; +1A50;TAI THAM LETTER UU;Lo;0;L;;;;;N;;;;; +1A51;TAI THAM LETTER EE;Lo;0;L;;;;;N;;;;; +1A52;TAI THAM LETTER OO;Lo;0;L;;;;;N;;;;; +1A53;TAI THAM LETTER LAE;Lo;0;L;;;;;N;;;;; +1A54;TAI THAM LETTER GREAT SA;Lo;0;L;;;;;N;;;;; +1A55;TAI THAM CONSONANT SIGN MEDIAL RA;Mc;0;L;;;;;N;;;;; +1A56;TAI THAM CONSONANT SIGN MEDIAL LA;Mn;0;NSM;;;;;N;;;;; +1A57;TAI THAM CONSONANT SIGN LA TANG LAI;Mc;0;L;;;;;N;;;;; +1A58;TAI THAM SIGN MAI KANG LAI;Mn;0;NSM;;;;;N;;;;; +1A59;TAI THAM CONSONANT SIGN FINAL NGA;Mn;0;NSM;;;;;N;;;;; +1A5A;TAI THAM CONSONANT SIGN LOW PA;Mn;0;NSM;;;;;N;;;;; +1A5B;TAI THAM CONSONANT SIGN HIGH RATHA OR LOW PA;Mn;0;NSM;;;;;N;;;;; +1A5C;TAI THAM CONSONANT SIGN MA;Mn;0;NSM;;;;;N;;;;; +1A5D;TAI THAM CONSONANT SIGN BA;Mn;0;NSM;;;;;N;;;;; +1A5E;TAI THAM CONSONANT SIGN SA;Mn;0;NSM;;;;;N;;;;; +1A60;TAI THAM SIGN SAKOT;Mn;9;NSM;;;;;N;;;;; +1A61;TAI THAM VOWEL SIGN A;Mc;0;L;;;;;N;;;;; +1A62;TAI THAM VOWEL SIGN MAI SAT;Mn;0;NSM;;;;;N;;;;; +1A63;TAI THAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +1A64;TAI THAM VOWEL SIGN TALL AA;Mc;0;L;;;;;N;;;;; +1A65;TAI THAM VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +1A66;TAI THAM VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +1A67;TAI THAM VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;; +1A68;TAI THAM VOWEL SIGN UUE;Mn;0;NSM;;;;;N;;;;; +1A69;TAI THAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1A6A;TAI THAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +1A6B;TAI THAM VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +1A6C;TAI THAM VOWEL SIGN OA BELOW;Mn;0;NSM;;;;;N;;;;; +1A6D;TAI THAM VOWEL SIGN OY;Mc;0;L;;;;;N;;;;; +1A6E;TAI THAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +1A6F;TAI THAM VOWEL SIGN AE;Mc;0;L;;;;;N;;;;; +1A70;TAI THAM VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; +1A71;TAI THAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +1A72;TAI THAM VOWEL SIGN THAM AI;Mc;0;L;;;;;N;;;;; +1A73;TAI THAM VOWEL SIGN OA ABOVE;Mn;0;NSM;;;;;N;;;;; +1A74;TAI THAM SIGN MAI KANG;Mn;0;NSM;;;;;N;;;;; +1A75;TAI THAM SIGN TONE-1;Mn;230;NSM;;;;;N;;;;; +1A76;TAI THAM SIGN TONE-2;Mn;230;NSM;;;;;N;;;;; +1A77;TAI THAM SIGN KHUEN TONE-3;Mn;230;NSM;;;;;N;;;;; +1A78;TAI THAM SIGN KHUEN TONE-4;Mn;230;NSM;;;;;N;;;;; +1A79;TAI THAM SIGN KHUEN TONE-5;Mn;230;NSM;;;;;N;;;;; +1A7A;TAI THAM SIGN RA HAAM;Mn;230;NSM;;;;;N;;;;; +1A7B;TAI THAM SIGN MAI SAM;Mn;230;NSM;;;;;N;;;;; +1A7C;TAI THAM SIGN KHUEN-LUE KARAN;Mn;230;NSM;;;;;N;;;;; +1A7F;TAI THAM COMBINING CRYPTOGRAMMIC DOT;Mn;220;NSM;;;;;N;;;;; +1A80;TAI THAM HORA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1A81;TAI THAM HORA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1A82;TAI THAM HORA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1A83;TAI THAM HORA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1A84;TAI THAM HORA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1A85;TAI THAM HORA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1A86;TAI THAM HORA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1A87;TAI THAM HORA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1A88;TAI THAM HORA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1A89;TAI THAM HORA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1A90;TAI THAM THAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1A91;TAI THAM THAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1A92;TAI THAM THAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1A93;TAI THAM THAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1A94;TAI THAM THAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1A95;TAI THAM THAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1A96;TAI THAM THAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1A97;TAI THAM THAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1A98;TAI THAM THAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1A99;TAI THAM THAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1AA0;TAI THAM SIGN WIANG;Po;0;L;;;;;N;;;;; +1AA1;TAI THAM SIGN WIANGWAAK;Po;0;L;;;;;N;;;;; +1AA2;TAI THAM SIGN SAWAN;Po;0;L;;;;;N;;;;; +1AA3;TAI THAM SIGN KEOW;Po;0;L;;;;;N;;;;; +1AA4;TAI THAM SIGN HOY;Po;0;L;;;;;N;;;;; +1AA5;TAI THAM SIGN DOKMAI;Po;0;L;;;;;N;;;;; +1AA6;TAI THAM SIGN REVERSED ROTATED RANA;Po;0;L;;;;;N;;;;; +1AA7;TAI THAM SIGN MAI YAMOK;Lm;0;L;;;;;N;;;;; +1AA8;TAI THAM SIGN KAAN;Po;0;L;;;;;N;;;;; +1AA9;TAI THAM SIGN KAANKUU;Po;0;L;;;;;N;;;;; +1AAA;TAI THAM SIGN SATKAAN;Po;0;L;;;;;N;;;;; +1AAB;TAI THAM SIGN SATKAANKUU;Po;0;L;;;;;N;;;;; +1AAC;TAI THAM SIGN HANG;Po;0;L;;;;;N;;;;; +1AAD;TAI THAM SIGN CAANG;Po;0;L;;;;;N;;;;; +1AB0;COMBINING DOUBLED CIRCUMFLEX ACCENT;Mn;230;NSM;;;;;N;;;;; +1AB1;COMBINING DIAERESIS-RING;Mn;230;NSM;;;;;N;;;;; +1AB2;COMBINING INFINITY;Mn;230;NSM;;;;;N;;;;; +1AB3;COMBINING DOWNWARDS ARROW;Mn;230;NSM;;;;;N;;;;; +1AB4;COMBINING TRIPLE DOT;Mn;230;NSM;;;;;N;;;;; +1AB5;COMBINING X-X BELOW;Mn;220;NSM;;;;;N;;;;; +1AB6;COMBINING WIGGLY LINE BELOW;Mn;220;NSM;;;;;N;;;;; +1AB7;COMBINING OPEN MARK BELOW;Mn;220;NSM;;;;;N;;;;; +1AB8;COMBINING DOUBLE OPEN MARK BELOW;Mn;220;NSM;;;;;N;;;;; +1AB9;COMBINING LIGHT CENTRALIZATION STROKE BELOW;Mn;220;NSM;;;;;N;;;;; +1ABA;COMBINING STRONG CENTRALIZATION STROKE BELOW;Mn;220;NSM;;;;;N;;;;; +1ABB;COMBINING PARENTHESES ABOVE;Mn;230;NSM;;;;;N;;;;; +1ABC;COMBINING DOUBLE PARENTHESES ABOVE;Mn;230;NSM;;;;;N;;;;; +1ABD;COMBINING PARENTHESES BELOW;Mn;220;NSM;;;;;N;;;;; +1ABE;COMBINING PARENTHESES OVERLAY;Me;0;NSM;;;;;N;;;;; +1ABF;COMBINING LATIN SMALL LETTER W BELOW;Mn;220;NSM;;;;;N;;;;; +1AC0;COMBINING LATIN SMALL LETTER TURNED W BELOW;Mn;220;NSM;;;;;N;;;;; +1AC1;COMBINING LEFT PARENTHESIS ABOVE LEFT;Mn;230;NSM;;;;;N;;;;; +1AC2;COMBINING RIGHT PARENTHESIS ABOVE RIGHT;Mn;230;NSM;;;;;N;;;;; +1AC3;COMBINING LEFT PARENTHESIS BELOW LEFT;Mn;220;NSM;;;;;N;;;;; +1AC4;COMBINING RIGHT PARENTHESIS BELOW RIGHT;Mn;220;NSM;;;;;N;;;;; +1AC5;COMBINING SQUARE BRACKETS ABOVE;Mn;230;NSM;;;;;N;;;;; +1AC6;COMBINING NUMBER SIGN ABOVE;Mn;230;NSM;;;;;N;;;;; +1AC7;COMBINING INVERTED DOUBLE ARCH ABOVE;Mn;230;NSM;;;;;N;;;;; +1AC8;COMBINING PLUS SIGN ABOVE;Mn;230;NSM;;;;;N;;;;; +1AC9;COMBINING DOUBLE PLUS SIGN ABOVE;Mn;230;NSM;;;;;N;;;;; +1ACA;COMBINING DOUBLE PLUS SIGN BELOW;Mn;220;NSM;;;;;N;;;;; +1ACB;COMBINING TRIPLE ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;; +1ACC;COMBINING LATIN SMALL LETTER INSULAR G;Mn;230;NSM;;;;;N;;;;; +1ACD;COMBINING LATIN SMALL LETTER INSULAR R;Mn;230;NSM;;;;;N;;;;; +1ACE;COMBINING LATIN SMALL LETTER INSULAR T;Mn;230;NSM;;;;;N;;;;; +1ACF;COMBINING DOUBLE CARON;Mn;230;NSM;;;;;N;;;;; +1AD0;COMBINING VERTICAL-LINE-ACUTE;Mn;230;NSM;;;;;N;;;;; +1AD1;COMBINING GRAVE-VERTICAL-LINE;Mn;230;NSM;;;;;N;;;;; +1AD2;COMBINING VERTICAL-LINE-GRAVE;Mn;230;NSM;;;;;N;;;;; +1AD3;COMBINING ACUTE-VERTICAL-LINE;Mn;230;NSM;;;;;N;;;;; +1AD4;COMBINING VERTICAL-LINE-MACRON;Mn;230;NSM;;;;;N;;;;; +1AD5;COMBINING MACRON-VERTICAL-LINE;Mn;230;NSM;;;;;N;;;;; +1AD6;COMBINING VERTICAL-LINE-ACUTE-GRAVE;Mn;230;NSM;;;;;N;;;;; +1AD7;COMBINING VERTICAL-LINE-GRAVE-ACUTE;Mn;230;NSM;;;;;N;;;;; +1AD8;COMBINING MACRON-ACUTE-GRAVE;Mn;230;NSM;;;;;N;;;;; +1AD9;COMBINING SHARP SIGN;Mn;230;NSM;;;;;N;;;;; +1ADA;COMBINING FLAT SIGN;Mn;230;NSM;;;;;N;;;;; +1ADB;COMBINING DOWN TACK ABOVE;Mn;230;NSM;;;;;N;;;;; +1ADC;COMBINING DIAERESIS WITH RAISED LEFT DOT;Mn;230;NSM;;;;;N;;;;; +1ADD;COMBINING DOT-AND-RING BELOW;Mn;220;NSM;;;;;N;;;;; +1AE0;COMBINING LEFT TACK ABOVE;Mn;230;NSM;;;;;N;;;;; +1AE1;COMBINING RIGHT TACK ABOVE;Mn;230;NSM;;;;;N;;;;; +1AE2;COMBINING MINUS SIGN ABOVE;Mn;230;NSM;;;;;N;;;;; +1AE3;COMBINING INVERTED BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;; +1AE4;COMBINING SQUARE ABOVE;Mn;230;NSM;;;;;N;;;;; +1AE5;COMBINING SEAGULL ABOVE;Mn;230;NSM;;;;;N;;;;; +1AE6;COMBINING DOUBLE ARCH BELOW;Mn;220;NSM;;;;;N;;;;; +1AE7;COMBINING DOUBLE ARCH ABOVE;Mn;230;NSM;;;;;N;;;;; +1AE8;COMBINING EQUALS SIGN ABOVE;Mn;230;NSM;;;;;N;;;;; +1AE9;COMBINING LEFT ANGLE CENTRED ABOVE;Mn;230;NSM;;;;;N;;;;; +1AEA;COMBINING UPWARDS ARROW ABOVE;Mn;230;NSM;;;;;N;;;;; +1AEB;COMBINING DOUBLE RIGHTWARDS ARROW ABOVE;Mn;234;NSM;;;;;N;;;;; +1B00;BALINESE SIGN ULU RICEM;Mn;0;NSM;;;;;N;;;;; +1B01;BALINESE SIGN ULU CANDRA;Mn;0;NSM;;;;;N;;;;; +1B02;BALINESE SIGN CECEK;Mn;0;NSM;;;;;N;;;;; +1B03;BALINESE SIGN SURANG;Mn;0;NSM;;;;;N;;;;; +1B04;BALINESE SIGN BISAH;Mc;0;L;;;;;N;;;;; +1B05;BALINESE LETTER AKARA;Lo;0;L;;;;;N;;;;; +1B06;BALINESE LETTER AKARA TEDUNG;Lo;0;L;1B05 1B35;;;;N;;;;; +1B07;BALINESE LETTER IKARA;Lo;0;L;;;;;N;;;;; +1B08;BALINESE LETTER IKARA TEDUNG;Lo;0;L;1B07 1B35;;;;N;;;;; +1B09;BALINESE LETTER UKARA;Lo;0;L;;;;;N;;;;; +1B0A;BALINESE LETTER UKARA TEDUNG;Lo;0;L;1B09 1B35;;;;N;;;;; +1B0B;BALINESE LETTER RA REPA;Lo;0;L;;;;;N;;;;; +1B0C;BALINESE LETTER RA REPA TEDUNG;Lo;0;L;1B0B 1B35;;;;N;;;;; +1B0D;BALINESE LETTER LA LENGA;Lo;0;L;;;;;N;;;;; +1B0E;BALINESE LETTER LA LENGA TEDUNG;Lo;0;L;1B0D 1B35;;;;N;;;;; +1B0F;BALINESE LETTER EKARA;Lo;0;L;;;;;N;;;;; +1B10;BALINESE LETTER AIKARA;Lo;0;L;;;;;N;;;;; +1B11;BALINESE LETTER OKARA;Lo;0;L;;;;;N;;;;; +1B12;BALINESE LETTER OKARA TEDUNG;Lo;0;L;1B11 1B35;;;;N;;;;; +1B13;BALINESE LETTER KA;Lo;0;L;;;;;N;;;;; +1B14;BALINESE LETTER KA MAHAPRANA;Lo;0;L;;;;;N;;;;; +1B15;BALINESE LETTER GA;Lo;0;L;;;;;N;;;;; +1B16;BALINESE LETTER GA GORA;Lo;0;L;;;;;N;;;;; +1B17;BALINESE LETTER NGA;Lo;0;L;;;;;N;;;;; +1B18;BALINESE LETTER CA;Lo;0;L;;;;;N;;;;; +1B19;BALINESE LETTER CA LACA;Lo;0;L;;;;;N;;;;; +1B1A;BALINESE LETTER JA;Lo;0;L;;;;;N;;;;; +1B1B;BALINESE LETTER JA JERA;Lo;0;L;;;;;N;;;;; +1B1C;BALINESE LETTER NYA;Lo;0;L;;;;;N;;;;; +1B1D;BALINESE LETTER TA LATIK;Lo;0;L;;;;;N;;;;; +1B1E;BALINESE LETTER TA MURDA MAHAPRANA;Lo;0;L;;;;;N;;;;; +1B1F;BALINESE LETTER DA MURDA ALPAPRANA;Lo;0;L;;;;;N;;;;; +1B20;BALINESE LETTER DA MURDA MAHAPRANA;Lo;0;L;;;;;N;;;;; +1B21;BALINESE LETTER NA RAMBAT;Lo;0;L;;;;;N;;;;; +1B22;BALINESE LETTER TA;Lo;0;L;;;;;N;;;;; +1B23;BALINESE LETTER TA TAWA;Lo;0;L;;;;;N;;;;; +1B24;BALINESE LETTER DA;Lo;0;L;;;;;N;;;;; +1B25;BALINESE LETTER DA MADU;Lo;0;L;;;;;N;;;;; +1B26;BALINESE LETTER NA;Lo;0;L;;;;;N;;;;; +1B27;BALINESE LETTER PA;Lo;0;L;;;;;N;;;;; +1B28;BALINESE LETTER PA KAPAL;Lo;0;L;;;;;N;;;;; +1B29;BALINESE LETTER BA;Lo;0;L;;;;;N;;;;; +1B2A;BALINESE LETTER BA KEMBANG;Lo;0;L;;;;;N;;;;; +1B2B;BALINESE LETTER MA;Lo;0;L;;;;;N;;;;; +1B2C;BALINESE LETTER YA;Lo;0;L;;;;;N;;;;; +1B2D;BALINESE LETTER RA;Lo;0;L;;;;;N;;;;; +1B2E;BALINESE LETTER LA;Lo;0;L;;;;;N;;;;; +1B2F;BALINESE LETTER WA;Lo;0;L;;;;;N;;;;; +1B30;BALINESE LETTER SA SAGA;Lo;0;L;;;;;N;;;;; +1B31;BALINESE LETTER SA SAPA;Lo;0;L;;;;;N;;;;; +1B32;BALINESE LETTER SA;Lo;0;L;;;;;N;;;;; +1B33;BALINESE LETTER HA;Lo;0;L;;;;;N;;;;; +1B34;BALINESE SIGN REREKAN;Mn;7;NSM;;;;;N;;;;; +1B35;BALINESE VOWEL SIGN TEDUNG;Mc;0;L;;;;;N;;;;; +1B36;BALINESE VOWEL SIGN ULU;Mn;0;NSM;;;;;N;;;;; +1B37;BALINESE VOWEL SIGN ULU SARI;Mn;0;NSM;;;;;N;;;;; +1B38;BALINESE VOWEL SIGN SUKU;Mn;0;NSM;;;;;N;;;;; +1B39;BALINESE VOWEL SIGN SUKU ILUT;Mn;0;NSM;;;;;N;;;;; +1B3A;BALINESE VOWEL SIGN RA REPA;Mn;0;NSM;;;;;N;;;;; +1B3B;BALINESE VOWEL SIGN RA REPA TEDUNG;Mc;0;L;1B3A 1B35;;;;N;;;;; +1B3C;BALINESE VOWEL SIGN LA LENGA;Mn;0;NSM;;;;;N;;;;; +1B3D;BALINESE VOWEL SIGN LA LENGA TEDUNG;Mc;0;L;1B3C 1B35;;;;N;;;;; +1B3E;BALINESE VOWEL SIGN TALING;Mc;0;L;;;;;N;;;;; +1B3F;BALINESE VOWEL SIGN TALING REPA;Mc;0;L;;;;;N;;;;; +1B40;BALINESE VOWEL SIGN TALING TEDUNG;Mc;0;L;1B3E 1B35;;;;N;;;;; +1B41;BALINESE VOWEL SIGN TALING REPA TEDUNG;Mc;0;L;1B3F 1B35;;;;N;;;;; +1B42;BALINESE VOWEL SIGN PEPET;Mn;0;NSM;;;;;N;;;;; +1B43;BALINESE VOWEL SIGN PEPET TEDUNG;Mc;0;L;1B42 1B35;;;;N;;;;; +1B44;BALINESE ADEG ADEG;Mc;9;L;;;;;N;;;;; +1B45;BALINESE LETTER KAF SASAK;Lo;0;L;;;;;N;;;;; +1B46;BALINESE LETTER KHOT SASAK;Lo;0;L;;;;;N;;;;; +1B47;BALINESE LETTER TZIR SASAK;Lo;0;L;;;;;N;;;;; +1B48;BALINESE LETTER EF SASAK;Lo;0;L;;;;;N;;;;; +1B49;BALINESE LETTER VE SASAK;Lo;0;L;;;;;N;;;;; +1B4A;BALINESE LETTER ZAL SASAK;Lo;0;L;;;;;N;;;;; +1B4B;BALINESE LETTER ASYURA SASAK;Lo;0;L;;;;;N;;;;; +1B4C;BALINESE LETTER ARCHAIC JNYA;Lo;0;L;;;;;N;;;;; +1B4E;BALINESE INVERTED CARIK SIKI;Po;0;L;;;;;N;;;;; +1B4F;BALINESE INVERTED CARIK PAREREN;Po;0;L;;;;;N;;;;; +1B50;BALINESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1B51;BALINESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1B52;BALINESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1B53;BALINESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1B54;BALINESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1B55;BALINESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1B56;BALINESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1B57;BALINESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1B58;BALINESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1B59;BALINESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1B5A;BALINESE PANTI;Po;0;L;;;;;N;;;;; +1B5B;BALINESE PAMADA;Po;0;L;;;;;N;;;;; +1B5C;BALINESE WINDU;Po;0;L;;;;;N;;;;; +1B5D;BALINESE CARIK PAMUNGKAH;Po;0;L;;;;;N;;;;; +1B5E;BALINESE CARIK SIKI;Po;0;L;;;;;N;;;;; +1B5F;BALINESE CARIK PAREREN;Po;0;L;;;;;N;;;;; +1B60;BALINESE PAMENENG;Po;0;L;;;;;N;;;;; +1B61;BALINESE MUSICAL SYMBOL DONG;So;0;L;;;;;N;;;;; +1B62;BALINESE MUSICAL SYMBOL DENG;So;0;L;;;;;N;;;;; +1B63;BALINESE MUSICAL SYMBOL DUNG;So;0;L;;;;;N;;;;; +1B64;BALINESE MUSICAL SYMBOL DANG;So;0;L;;;;;N;;;;; +1B65;BALINESE MUSICAL SYMBOL DANG SURANG;So;0;L;;;;;N;;;;; +1B66;BALINESE MUSICAL SYMBOL DING;So;0;L;;;;;N;;;;; +1B67;BALINESE MUSICAL SYMBOL DAENG;So;0;L;;;;;N;;;;; +1B68;BALINESE MUSICAL SYMBOL DEUNG;So;0;L;;;;;N;;;;; +1B69;BALINESE MUSICAL SYMBOL DAING;So;0;L;;;;;N;;;;; +1B6A;BALINESE MUSICAL SYMBOL DANG GEDE;So;0;L;;;;;N;;;;; +1B6B;BALINESE MUSICAL SYMBOL COMBINING TEGEH;Mn;230;NSM;;;;;N;;;;; +1B6C;BALINESE MUSICAL SYMBOL COMBINING ENDEP;Mn;220;NSM;;;;;N;;;;; +1B6D;BALINESE MUSICAL SYMBOL COMBINING KEMPUL;Mn;230;NSM;;;;;N;;;;; +1B6E;BALINESE MUSICAL SYMBOL COMBINING KEMPLI;Mn;230;NSM;;;;;N;;;;; +1B6F;BALINESE MUSICAL SYMBOL COMBINING JEGOGAN;Mn;230;NSM;;;;;N;;;;; +1B70;BALINESE MUSICAL SYMBOL COMBINING KEMPUL WITH JEGOGAN;Mn;230;NSM;;;;;N;;;;; +1B71;BALINESE MUSICAL SYMBOL COMBINING KEMPLI WITH JEGOGAN;Mn;230;NSM;;;;;N;;;;; +1B72;BALINESE MUSICAL SYMBOL COMBINING BENDE;Mn;230;NSM;;;;;N;;;;; +1B73;BALINESE MUSICAL SYMBOL COMBINING GONG;Mn;230;NSM;;;;;N;;;;; +1B74;BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG;So;0;L;;;;;N;;;;; +1B75;BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DAG;So;0;L;;;;;N;;;;; +1B76;BALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TUK;So;0;L;;;;;N;;;;; +1B77;BALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TAK;So;0;L;;;;;N;;;;; +1B78;BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PANG;So;0;L;;;;;N;;;;; +1B79;BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PUNG;So;0;L;;;;;N;;;;; +1B7A;BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLAK;So;0;L;;;;;N;;;;; +1B7B;BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLUK;So;0;L;;;;;N;;;;; +1B7C;BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING;So;0;L;;;;;N;;;;; +1B7D;BALINESE PANTI LANTANG;Po;0;L;;;;;N;;;;; +1B7E;BALINESE PAMADA LANTANG;Po;0;L;;;;;N;;;;; +1B7F;BALINESE PANTI BAWAK;Po;0;L;;;;;N;;;;; +1B80;SUNDANESE SIGN PANYECEK;Mn;0;NSM;;;;;N;;;;; +1B81;SUNDANESE SIGN PANGLAYAR;Mn;0;NSM;;;;;N;;;;; +1B82;SUNDANESE SIGN PANGWISAD;Mc;0;L;;;;;N;;;;; +1B83;SUNDANESE LETTER A;Lo;0;L;;;;;N;;;;; +1B84;SUNDANESE LETTER I;Lo;0;L;;;;;N;;;;; +1B85;SUNDANESE LETTER U;Lo;0;L;;;;;N;;;;; +1B86;SUNDANESE LETTER AE;Lo;0;L;;;;;N;;;;; +1B87;SUNDANESE LETTER O;Lo;0;L;;;;;N;;;;; +1B88;SUNDANESE LETTER E;Lo;0;L;;;;;N;;;;; +1B89;SUNDANESE LETTER EU;Lo;0;L;;;;;N;;;;; +1B8A;SUNDANESE LETTER KA;Lo;0;L;;;;;N;;;;; +1B8B;SUNDANESE LETTER QA;Lo;0;L;;;;;N;;;;; +1B8C;SUNDANESE LETTER GA;Lo;0;L;;;;;N;;;;; +1B8D;SUNDANESE LETTER NGA;Lo;0;L;;;;;N;;;;; +1B8E;SUNDANESE LETTER CA;Lo;0;L;;;;;N;;;;; +1B8F;SUNDANESE LETTER JA;Lo;0;L;;;;;N;;;;; +1B90;SUNDANESE LETTER ZA;Lo;0;L;;;;;N;;;;; +1B91;SUNDANESE LETTER NYA;Lo;0;L;;;;;N;;;;; +1B92;SUNDANESE LETTER TA;Lo;0;L;;;;;N;;;;; +1B93;SUNDANESE LETTER DA;Lo;0;L;;;;;N;;;;; +1B94;SUNDANESE LETTER NA;Lo;0;L;;;;;N;;;;; +1B95;SUNDANESE LETTER PA;Lo;0;L;;;;;N;;;;; +1B96;SUNDANESE LETTER FA;Lo;0;L;;;;;N;;;;; +1B97;SUNDANESE LETTER VA;Lo;0;L;;;;;N;;;;; +1B98;SUNDANESE LETTER BA;Lo;0;L;;;;;N;;;;; +1B99;SUNDANESE LETTER MA;Lo;0;L;;;;;N;;;;; +1B9A;SUNDANESE LETTER YA;Lo;0;L;;;;;N;;;;; +1B9B;SUNDANESE LETTER RA;Lo;0;L;;;;;N;;;;; +1B9C;SUNDANESE LETTER LA;Lo;0;L;;;;;N;;;;; +1B9D;SUNDANESE LETTER WA;Lo;0;L;;;;;N;;;;; +1B9E;SUNDANESE LETTER SA;Lo;0;L;;;;;N;;;;; +1B9F;SUNDANESE LETTER XA;Lo;0;L;;;;;N;;;;; +1BA0;SUNDANESE LETTER HA;Lo;0;L;;;;;N;;;;; +1BA1;SUNDANESE CONSONANT SIGN PAMINGKAL;Mc;0;L;;;;;N;;;;; +1BA2;SUNDANESE CONSONANT SIGN PANYAKRA;Mn;0;NSM;;;;;N;;;;; +1BA3;SUNDANESE CONSONANT SIGN PANYIKU;Mn;0;NSM;;;;;N;;;;; +1BA4;SUNDANESE VOWEL SIGN PANGHULU;Mn;0;NSM;;;;;N;;;;; +1BA5;SUNDANESE VOWEL SIGN PANYUKU;Mn;0;NSM;;;;;N;;;;; +1BA6;SUNDANESE VOWEL SIGN PANAELAENG;Mc;0;L;;;;;N;;;;; +1BA7;SUNDANESE VOWEL SIGN PANOLONG;Mc;0;L;;;;;N;;;;; +1BA8;SUNDANESE VOWEL SIGN PAMEPET;Mn;0;NSM;;;;;N;;;;; +1BA9;SUNDANESE VOWEL SIGN PANEULEUNG;Mn;0;NSM;;;;;N;;;;; +1BAA;SUNDANESE SIGN PAMAAEH;Mc;9;L;;;;;N;;;;; +1BAB;SUNDANESE SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +1BAC;SUNDANESE CONSONANT SIGN PASANGAN MA;Mn;0;NSM;;;;;N;;;;; +1BAD;SUNDANESE CONSONANT SIGN PASANGAN WA;Mn;0;NSM;;;;;N;;;;; +1BAE;SUNDANESE LETTER KHA;Lo;0;L;;;;;N;;;;; +1BAF;SUNDANESE LETTER SYA;Lo;0;L;;;;;N;;;;; +1BB0;SUNDANESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1BB1;SUNDANESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1BB2;SUNDANESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1BB3;SUNDANESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1BB4;SUNDANESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1BB5;SUNDANESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1BB6;SUNDANESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1BB7;SUNDANESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1BB8;SUNDANESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1BB9;SUNDANESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1BBA;SUNDANESE AVAGRAHA;Lo;0;L;;;;;N;;;;; +1BBB;SUNDANESE LETTER REU;Lo;0;L;;;;;N;;;;; +1BBC;SUNDANESE LETTER LEU;Lo;0;L;;;;;N;;;;; +1BBD;SUNDANESE LETTER BHA;Lo;0;L;;;;;N;;;;; +1BBE;SUNDANESE LETTER FINAL K;Lo;0;L;;;;;N;;;;; +1BBF;SUNDANESE LETTER FINAL M;Lo;0;L;;;;;N;;;;; +1BC0;BATAK LETTER A;Lo;0;L;;;;;N;;;;; +1BC1;BATAK LETTER SIMALUNGUN A;Lo;0;L;;;;;N;;;;; +1BC2;BATAK LETTER HA;Lo;0;L;;;;;N;;;;; +1BC3;BATAK LETTER SIMALUNGUN HA;Lo;0;L;;;;;N;;;;; +1BC4;BATAK LETTER MANDAILING HA;Lo;0;L;;;;;N;;;;; +1BC5;BATAK LETTER BA;Lo;0;L;;;;;N;;;;; +1BC6;BATAK LETTER KARO BA;Lo;0;L;;;;;N;;;;; +1BC7;BATAK LETTER PA;Lo;0;L;;;;;N;;;;; +1BC8;BATAK LETTER SIMALUNGUN PA;Lo;0;L;;;;;N;;;;; +1BC9;BATAK LETTER NA;Lo;0;L;;;;;N;;;;; +1BCA;BATAK LETTER MANDAILING NA;Lo;0;L;;;;;N;;;;; +1BCB;BATAK LETTER WA;Lo;0;L;;;;;N;;;;; +1BCC;BATAK LETTER SIMALUNGUN WA;Lo;0;L;;;;;N;;;;; +1BCD;BATAK LETTER PAKPAK WA;Lo;0;L;;;;;N;;;;; +1BCE;BATAK LETTER GA;Lo;0;L;;;;;N;;;;; +1BCF;BATAK LETTER SIMALUNGUN GA;Lo;0;L;;;;;N;;;;; +1BD0;BATAK LETTER JA;Lo;0;L;;;;;N;;;;; +1BD1;BATAK LETTER DA;Lo;0;L;;;;;N;;;;; +1BD2;BATAK LETTER RA;Lo;0;L;;;;;N;;;;; +1BD3;BATAK LETTER SIMALUNGUN RA;Lo;0;L;;;;;N;;;;; +1BD4;BATAK LETTER MA;Lo;0;L;;;;;N;;;;; +1BD5;BATAK LETTER SIMALUNGUN MA;Lo;0;L;;;;;N;;;;; +1BD6;BATAK LETTER SOUTHERN TA;Lo;0;L;;;;;N;;;;; +1BD7;BATAK LETTER NORTHERN TA;Lo;0;L;;;;;N;;;;; +1BD8;BATAK LETTER SA;Lo;0;L;;;;;N;;;;; +1BD9;BATAK LETTER SIMALUNGUN SA;Lo;0;L;;;;;N;;;;; +1BDA;BATAK LETTER MANDAILING SA;Lo;0;L;;;;;N;;;;; +1BDB;BATAK LETTER YA;Lo;0;L;;;;;N;;;;; +1BDC;BATAK LETTER SIMALUNGUN YA;Lo;0;L;;;;;N;;;;; +1BDD;BATAK LETTER NGA;Lo;0;L;;;;;N;;;;; +1BDE;BATAK LETTER LA;Lo;0;L;;;;;N;;;;; +1BDF;BATAK LETTER SIMALUNGUN LA;Lo;0;L;;;;;N;;;;; +1BE0;BATAK LETTER NYA;Lo;0;L;;;;;N;;;;; +1BE1;BATAK LETTER CA;Lo;0;L;;;;;N;;;;; +1BE2;BATAK LETTER NDA;Lo;0;L;;;;;N;;;;; +1BE3;BATAK LETTER MBA;Lo;0;L;;;;;N;;;;; +1BE4;BATAK LETTER I;Lo;0;L;;;;;N;;;;; +1BE5;BATAK LETTER U;Lo;0;L;;;;;N;;;;; +1BE6;BATAK SIGN TOMPI;Mn;7;NSM;;;;;N;;;;; +1BE7;BATAK VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +1BE8;BATAK VOWEL SIGN PAKPAK E;Mn;0;NSM;;;;;N;;;;; +1BE9;BATAK VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;; +1BEA;BATAK VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +1BEB;BATAK VOWEL SIGN KARO I;Mc;0;L;;;;;N;;;;; +1BEC;BATAK VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +1BED;BATAK VOWEL SIGN KARO O;Mn;0;NSM;;;;;N;;;;; +1BEE;BATAK VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +1BEF;BATAK VOWEL SIGN U FOR SIMALUNGUN SA;Mn;0;NSM;;;;;N;;;;; +1BF0;BATAK CONSONANT SIGN NG;Mn;0;NSM;;;;;N;;;;; +1BF1;BATAK CONSONANT SIGN H;Mn;0;NSM;;;;;N;;;;; +1BF2;BATAK PANGOLAT;Mc;9;L;;;;;N;;;;; +1BF3;BATAK PANONGONAN;Mc;9;L;;;;;N;;;;; +1BFC;BATAK SYMBOL BINDU NA METEK;Po;0;L;;;;;N;;;;; +1BFD;BATAK SYMBOL BINDU PINARBORAS;Po;0;L;;;;;N;;;;; +1BFE;BATAK SYMBOL BINDU JUDUL;Po;0;L;;;;;N;;;;; +1BFF;BATAK SYMBOL BINDU PANGOLAT;Po;0;L;;;;;N;;;;; +1C00;LEPCHA LETTER KA;Lo;0;L;;;;;N;;;;; +1C01;LEPCHA LETTER KLA;Lo;0;L;;;;;N;;;;; +1C02;LEPCHA LETTER KHA;Lo;0;L;;;;;N;;;;; +1C03;LEPCHA LETTER GA;Lo;0;L;;;;;N;;;;; +1C04;LEPCHA LETTER GLA;Lo;0;L;;;;;N;;;;; +1C05;LEPCHA LETTER NGA;Lo;0;L;;;;;N;;;;; +1C06;LEPCHA LETTER CA;Lo;0;L;;;;;N;;;;; +1C07;LEPCHA LETTER CHA;Lo;0;L;;;;;N;;;;; +1C08;LEPCHA LETTER JA;Lo;0;L;;;;;N;;;;; +1C09;LEPCHA LETTER NYA;Lo;0;L;;;;;N;;;;; +1C0A;LEPCHA LETTER TA;Lo;0;L;;;;;N;;;;; +1C0B;LEPCHA LETTER THA;Lo;0;L;;;;;N;;;;; +1C0C;LEPCHA LETTER DA;Lo;0;L;;;;;N;;;;; +1C0D;LEPCHA LETTER NA;Lo;0;L;;;;;N;;;;; +1C0E;LEPCHA LETTER PA;Lo;0;L;;;;;N;;;;; +1C0F;LEPCHA LETTER PLA;Lo;0;L;;;;;N;;;;; +1C10;LEPCHA LETTER PHA;Lo;0;L;;;;;N;;;;; +1C11;LEPCHA LETTER FA;Lo;0;L;;;;;N;;;;; +1C12;LEPCHA LETTER FLA;Lo;0;L;;;;;N;;;;; +1C13;LEPCHA LETTER BA;Lo;0;L;;;;;N;;;;; +1C14;LEPCHA LETTER BLA;Lo;0;L;;;;;N;;;;; +1C15;LEPCHA LETTER MA;Lo;0;L;;;;;N;;;;; +1C16;LEPCHA LETTER MLA;Lo;0;L;;;;;N;;;;; +1C17;LEPCHA LETTER TSA;Lo;0;L;;;;;N;;;;; +1C18;LEPCHA LETTER TSHA;Lo;0;L;;;;;N;;;;; +1C19;LEPCHA LETTER DZA;Lo;0;L;;;;;N;;;;; +1C1A;LEPCHA LETTER YA;Lo;0;L;;;;;N;;;;; +1C1B;LEPCHA LETTER RA;Lo;0;L;;;;;N;;;;; +1C1C;LEPCHA LETTER LA;Lo;0;L;;;;;N;;;;; +1C1D;LEPCHA LETTER HA;Lo;0;L;;;;;N;;;;; +1C1E;LEPCHA LETTER HLA;Lo;0;L;;;;;N;;;;; +1C1F;LEPCHA LETTER VA;Lo;0;L;;;;;N;;;;; +1C20;LEPCHA LETTER SA;Lo;0;L;;;;;N;;;;; +1C21;LEPCHA LETTER SHA;Lo;0;L;;;;;N;;;;; +1C22;LEPCHA LETTER WA;Lo;0;L;;;;;N;;;;; +1C23;LEPCHA LETTER A;Lo;0;L;;;;;N;;;;; +1C24;LEPCHA SUBJOINED LETTER YA;Mc;0;L;;;;;N;;;;; +1C25;LEPCHA SUBJOINED LETTER RA;Mc;0;L;;;;;N;;;;; +1C26;LEPCHA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +1C27;LEPCHA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +1C28;LEPCHA VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +1C29;LEPCHA VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; +1C2A;LEPCHA VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +1C2B;LEPCHA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +1C2C;LEPCHA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +1C2D;LEPCHA CONSONANT SIGN K;Mn;0;NSM;;;;;N;;;;; +1C2E;LEPCHA CONSONANT SIGN M;Mn;0;NSM;;;;;N;;;;; +1C2F;LEPCHA CONSONANT SIGN L;Mn;0;NSM;;;;;N;;;;; +1C30;LEPCHA CONSONANT SIGN N;Mn;0;NSM;;;;;N;;;;; +1C31;LEPCHA CONSONANT SIGN P;Mn;0;NSM;;;;;N;;;;; +1C32;LEPCHA CONSONANT SIGN R;Mn;0;NSM;;;;;N;;;;; +1C33;LEPCHA CONSONANT SIGN T;Mn;0;NSM;;;;;N;;;;; +1C34;LEPCHA CONSONANT SIGN NYIN-DO;Mc;0;L;;;;;N;;;;; +1C35;LEPCHA CONSONANT SIGN KANG;Mc;0;L;;;;;N;;;;; +1C36;LEPCHA SIGN RAN;Mn;0;NSM;;;;;N;;;;; +1C37;LEPCHA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +1C3B;LEPCHA PUNCTUATION TA-ROL;Po;0;L;;;;;N;;;;; +1C3C;LEPCHA PUNCTUATION NYET THYOOM TA-ROL;Po;0;L;;;;;N;;;;; +1C3D;LEPCHA PUNCTUATION CER-WA;Po;0;L;;;;;N;;;;; +1C3E;LEPCHA PUNCTUATION TSHOOK CER-WA;Po;0;L;;;;;N;;;;; +1C3F;LEPCHA PUNCTUATION TSHOOK;Po;0;L;;;;;N;;;;; +1C40;LEPCHA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1C41;LEPCHA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1C42;LEPCHA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1C43;LEPCHA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1C44;LEPCHA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1C45;LEPCHA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1C46;LEPCHA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1C47;LEPCHA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1C48;LEPCHA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1C49;LEPCHA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1C4D;LEPCHA LETTER TTA;Lo;0;L;;;;;N;;;;; +1C4E;LEPCHA LETTER TTHA;Lo;0;L;;;;;N;;;;; +1C4F;LEPCHA LETTER DDA;Lo;0;L;;;;;N;;;;; +1C50;OL CHIKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1C51;OL CHIKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1C52;OL CHIKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1C53;OL CHIKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1C54;OL CHIKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1C55;OL CHIKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1C56;OL CHIKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1C57;OL CHIKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1C58;OL CHIKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1C59;OL CHIKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1C5A;OL CHIKI LETTER LA;Lo;0;L;;;;;N;;;;; +1C5B;OL CHIKI LETTER AT;Lo;0;L;;;;;N;;;;; +1C5C;OL CHIKI LETTER AG;Lo;0;L;;;;;N;;;;; +1C5D;OL CHIKI LETTER ANG;Lo;0;L;;;;;N;;;;; +1C5E;OL CHIKI LETTER AL;Lo;0;L;;;;;N;;;;; +1C5F;OL CHIKI LETTER LAA;Lo;0;L;;;;;N;;;;; +1C60;OL CHIKI LETTER AAK;Lo;0;L;;;;;N;;;;; +1C61;OL CHIKI LETTER AAJ;Lo;0;L;;;;;N;;;;; +1C62;OL CHIKI LETTER AAM;Lo;0;L;;;;;N;;;;; +1C63;OL CHIKI LETTER AAW;Lo;0;L;;;;;N;;;;; +1C64;OL CHIKI LETTER LI;Lo;0;L;;;;;N;;;;; +1C65;OL CHIKI LETTER IS;Lo;0;L;;;;;N;;;;; +1C66;OL CHIKI LETTER IH;Lo;0;L;;;;;N;;;;; +1C67;OL CHIKI LETTER INY;Lo;0;L;;;;;N;;;;; +1C68;OL CHIKI LETTER IR;Lo;0;L;;;;;N;;;;; +1C69;OL CHIKI LETTER LU;Lo;0;L;;;;;N;;;;; +1C6A;OL CHIKI LETTER UC;Lo;0;L;;;;;N;;;;; +1C6B;OL CHIKI LETTER UD;Lo;0;L;;;;;N;;;;; +1C6C;OL CHIKI LETTER UNN;Lo;0;L;;;;;N;;;;; +1C6D;OL CHIKI LETTER UY;Lo;0;L;;;;;N;;;;; +1C6E;OL CHIKI LETTER LE;Lo;0;L;;;;;N;;;;; +1C6F;OL CHIKI LETTER EP;Lo;0;L;;;;;N;;;;; +1C70;OL CHIKI LETTER EDD;Lo;0;L;;;;;N;;;;; +1C71;OL CHIKI LETTER EN;Lo;0;L;;;;;N;;;;; +1C72;OL CHIKI LETTER ERR;Lo;0;L;;;;;N;;;;; +1C73;OL CHIKI LETTER LO;Lo;0;L;;;;;N;;;;; +1C74;OL CHIKI LETTER OTT;Lo;0;L;;;;;N;;;;; +1C75;OL CHIKI LETTER OB;Lo;0;L;;;;;N;;;;; +1C76;OL CHIKI LETTER OV;Lo;0;L;;;;;N;;;;; +1C77;OL CHIKI LETTER OH;Lo;0;L;;;;;N;;;;; +1C78;OL CHIKI MU TTUDDAG;Lm;0;L;;;;;N;;;;; +1C79;OL CHIKI GAAHLAA TTUDDAAG;Lm;0;L;;;;;N;;;;; +1C7A;OL CHIKI MU-GAAHLAA TTUDDAAG;Lm;0;L;;;;;N;;;;; +1C7B;OL CHIKI RELAA;Lm;0;L;;;;;N;;;;; +1C7C;OL CHIKI PHAARKAA;Lm;0;L;;;;;N;;;;; +1C7D;OL CHIKI AHAD;Lm;0;L;;;;;N;;;;; +1C7E;OL CHIKI PUNCTUATION MUCAAD;Po;0;L;;;;;N;;;;; +1C7F;OL CHIKI PUNCTUATION DOUBLE MUCAAD;Po;0;L;;;;;N;;;;; +1C80;CYRILLIC SMALL LETTER ROUNDED VE;Ll;0;L;;;;;N;;;0412;;0412 +1C81;CYRILLIC SMALL LETTER LONG-LEGGED DE;Ll;0;L;;;;;N;;;0414;;0414 +1C82;CYRILLIC SMALL LETTER NARROW O;Ll;0;L;;;;;N;;;041E;;041E +1C83;CYRILLIC SMALL LETTER WIDE ES;Ll;0;L;;;;;N;;;0421;;0421 +1C84;CYRILLIC SMALL LETTER TALL TE;Ll;0;L;;;;;N;;;0422;;0422 +1C85;CYRILLIC SMALL LETTER THREE-LEGGED TE;Ll;0;L;;;;;N;;;0422;;0422 +1C86;CYRILLIC SMALL LETTER TALL HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A +1C87;CYRILLIC SMALL LETTER TALL YAT;Ll;0;L;;;;;N;;;0462;;0462 +1C88;CYRILLIC SMALL LETTER UNBLENDED UK;Ll;0;L;;;;;N;;;A64A;;A64A +1C89;CYRILLIC CAPITAL LETTER TJE;Lu;0;L;;;;;N;;;;1C8A; +1C8A;CYRILLIC SMALL LETTER TJE;Ll;0;L;;;;;N;;;1C89;;1C89 +1C90;GEORGIAN MTAVRULI CAPITAL LETTER AN;Lu;0;L;;;;;N;;;;10D0; +1C91;GEORGIAN MTAVRULI CAPITAL LETTER BAN;Lu;0;L;;;;;N;;;;10D1; +1C92;GEORGIAN MTAVRULI CAPITAL LETTER GAN;Lu;0;L;;;;;N;;;;10D2; +1C93;GEORGIAN MTAVRULI CAPITAL LETTER DON;Lu;0;L;;;;;N;;;;10D3; +1C94;GEORGIAN MTAVRULI CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;10D4; +1C95;GEORGIAN MTAVRULI CAPITAL LETTER VIN;Lu;0;L;;;;;N;;;;10D5; +1C96;GEORGIAN MTAVRULI CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;;;10D6; +1C97;GEORGIAN MTAVRULI CAPITAL LETTER TAN;Lu;0;L;;;;;N;;;;10D7; +1C98;GEORGIAN MTAVRULI CAPITAL LETTER IN;Lu;0;L;;;;;N;;;;10D8; +1C99;GEORGIAN MTAVRULI CAPITAL LETTER KAN;Lu;0;L;;;;;N;;;;10D9; +1C9A;GEORGIAN MTAVRULI CAPITAL LETTER LAS;Lu;0;L;;;;;N;;;;10DA; +1C9B;GEORGIAN MTAVRULI CAPITAL LETTER MAN;Lu;0;L;;;;;N;;;;10DB; +1C9C;GEORGIAN MTAVRULI CAPITAL LETTER NAR;Lu;0;L;;;;;N;;;;10DC; +1C9D;GEORGIAN MTAVRULI CAPITAL LETTER ON;Lu;0;L;;;;;N;;;;10DD; +1C9E;GEORGIAN MTAVRULI CAPITAL LETTER PAR;Lu;0;L;;;;;N;;;;10DE; +1C9F;GEORGIAN MTAVRULI CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;;;10DF; +1CA0;GEORGIAN MTAVRULI CAPITAL LETTER RAE;Lu;0;L;;;;;N;;;;10E0; +1CA1;GEORGIAN MTAVRULI CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;10E1; +1CA2;GEORGIAN MTAVRULI CAPITAL LETTER TAR;Lu;0;L;;;;;N;;;;10E2; +1CA3;GEORGIAN MTAVRULI CAPITAL LETTER UN;Lu;0;L;;;;;N;;;;10E3; +1CA4;GEORGIAN MTAVRULI CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;;;10E4; +1CA5;GEORGIAN MTAVRULI CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;;;10E5; +1CA6;GEORGIAN MTAVRULI CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;;;10E6; +1CA7;GEORGIAN MTAVRULI CAPITAL LETTER QAR;Lu;0;L;;;;;N;;;;10E7; +1CA8;GEORGIAN MTAVRULI CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;;;10E8; +1CA9;GEORGIAN MTAVRULI CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;;;10E9; +1CAA;GEORGIAN MTAVRULI CAPITAL LETTER CAN;Lu;0;L;;;;;N;;;;10EA; +1CAB;GEORGIAN MTAVRULI CAPITAL LETTER JIL;Lu;0;L;;;;;N;;;;10EB; +1CAC;GEORGIAN MTAVRULI CAPITAL LETTER CIL;Lu;0;L;;;;;N;;;;10EC; +1CAD;GEORGIAN MTAVRULI CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;;;10ED; +1CAE;GEORGIAN MTAVRULI CAPITAL LETTER XAN;Lu;0;L;;;;;N;;;;10EE; +1CAF;GEORGIAN MTAVRULI CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;;;10EF; +1CB0;GEORGIAN MTAVRULI CAPITAL LETTER HAE;Lu;0;L;;;;;N;;;;10F0; +1CB1;GEORGIAN MTAVRULI CAPITAL LETTER HE;Lu;0;L;;;;;N;;;;10F1; +1CB2;GEORGIAN MTAVRULI CAPITAL LETTER HIE;Lu;0;L;;;;;N;;;;10F2; +1CB3;GEORGIAN MTAVRULI CAPITAL LETTER WE;Lu;0;L;;;;;N;;;;10F3; +1CB4;GEORGIAN MTAVRULI CAPITAL LETTER HAR;Lu;0;L;;;;;N;;;;10F4; +1CB5;GEORGIAN MTAVRULI CAPITAL LETTER HOE;Lu;0;L;;;;;N;;;;10F5; +1CB6;GEORGIAN MTAVRULI CAPITAL LETTER FI;Lu;0;L;;;;;N;;;;10F6; +1CB7;GEORGIAN MTAVRULI CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;10F7; +1CB8;GEORGIAN MTAVRULI CAPITAL LETTER ELIFI;Lu;0;L;;;;;N;;;;10F8; +1CB9;GEORGIAN MTAVRULI CAPITAL LETTER TURNED GAN;Lu;0;L;;;;;N;;;;10F9; +1CBA;GEORGIAN MTAVRULI CAPITAL LETTER AIN;Lu;0;L;;;;;N;;;;10FA; +1CBD;GEORGIAN MTAVRULI CAPITAL LETTER AEN;Lu;0;L;;;;;N;;;;10FD; +1CBE;GEORGIAN MTAVRULI CAPITAL LETTER HARD SIGN;Lu;0;L;;;;;N;;;;10FE; +1CBF;GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN;Lu;0;L;;;;;N;;;;10FF; +1CC0;SUNDANESE PUNCTUATION BINDU SURYA;Po;0;L;;;;;N;;;;; +1CC1;SUNDANESE PUNCTUATION BINDU PANGLONG;Po;0;L;;;;;N;;;;; +1CC2;SUNDANESE PUNCTUATION BINDU PURNAMA;Po;0;L;;;;;N;;;;; +1CC3;SUNDANESE PUNCTUATION BINDU CAKRA;Po;0;L;;;;;N;;;;; +1CC4;SUNDANESE PUNCTUATION BINDU LEU SATANGA;Po;0;L;;;;;N;;;;; +1CC5;SUNDANESE PUNCTUATION BINDU KA SATANGA;Po;0;L;;;;;N;;;;; +1CC6;SUNDANESE PUNCTUATION BINDU DA SATANGA;Po;0;L;;;;;N;;;;; +1CC7;SUNDANESE PUNCTUATION BINDU BA SATANGA;Po;0;L;;;;;N;;;;; +1CD0;VEDIC TONE KARSHANA;Mn;230;NSM;;;;;N;;;;; +1CD1;VEDIC TONE SHARA;Mn;230;NSM;;;;;N;;;;; +1CD2;VEDIC TONE PRENKHA;Mn;230;NSM;;;;;N;;;;; +1CD3;VEDIC SIGN NIHSHVASA;Po;0;L;;;;;N;;;;; +1CD4;VEDIC SIGN YAJURVEDIC MIDLINE SVARITA;Mn;1;NSM;;;;;N;;;;; +1CD5;VEDIC TONE YAJURVEDIC AGGRAVATED INDEPENDENT SVARITA;Mn;220;NSM;;;;;N;;;;; +1CD6;VEDIC TONE YAJURVEDIC INDEPENDENT SVARITA;Mn;220;NSM;;;;;N;;;;; +1CD7;VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA;Mn;220;NSM;;;;;N;;;;; +1CD8;VEDIC TONE CANDRA BELOW;Mn;220;NSM;;;;;N;;;;; +1CD9;VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA SCHROEDER;Mn;220;NSM;;;;;N;;;;; +1CDA;VEDIC TONE DOUBLE SVARITA;Mn;230;NSM;;;;;N;;;;; +1CDB;VEDIC TONE TRIPLE SVARITA;Mn;230;NSM;;;;;N;;;;; +1CDC;VEDIC TONE KATHAKA ANUDATTA;Mn;220;NSM;;;;;N;;;;; +1CDD;VEDIC TONE DOT BELOW;Mn;220;NSM;;;;;N;;;;; +1CDE;VEDIC TONE TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;; +1CDF;VEDIC TONE THREE DOTS BELOW;Mn;220;NSM;;;;;N;;;;; +1CE0;VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA;Mn;230;NSM;;;;;N;;;;; +1CE1;VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA;Mc;0;L;;;;;N;;;;; +1CE2;VEDIC SIGN VISARGA SVARITA;Mn;1;NSM;;;;;N;;;;; +1CE3;VEDIC SIGN VISARGA UDATTA;Mn;1;NSM;;;;;N;;;;; +1CE4;VEDIC SIGN REVERSED VISARGA UDATTA;Mn;1;NSM;;;;;N;;;;; +1CE5;VEDIC SIGN VISARGA ANUDATTA;Mn;1;NSM;;;;;N;;;;; +1CE6;VEDIC SIGN REVERSED VISARGA ANUDATTA;Mn;1;NSM;;;;;N;;;;; +1CE7;VEDIC SIGN VISARGA UDATTA WITH TAIL;Mn;1;NSM;;;;;N;;;;; +1CE8;VEDIC SIGN VISARGA ANUDATTA WITH TAIL;Mn;1;NSM;;;;;N;;;;; +1CE9;VEDIC SIGN ANUSVARA ANTARGOMUKHA;Lo;0;L;;;;;N;;;;; +1CEA;VEDIC SIGN ANUSVARA BAHIRGOMUKHA;Lo;0;L;;;;;N;;;;; +1CEB;VEDIC SIGN ANUSVARA VAMAGOMUKHA;Lo;0;L;;;;;N;;;;; +1CEC;VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL;Lo;0;L;;;;;N;;;;; +1CED;VEDIC SIGN TIRYAK;Mn;220;NSM;;;;;N;;;;; +1CEE;VEDIC SIGN HEXIFORM LONG ANUSVARA;Lo;0;L;;;;;N;;;;; +1CEF;VEDIC SIGN LONG ANUSVARA;Lo;0;L;;;;;N;;;;; +1CF0;VEDIC SIGN RTHANG LONG ANUSVARA;Lo;0;L;;;;;N;;;;; +1CF1;VEDIC SIGN ANUSVARA UBHAYATO MUKHA;Lo;0;L;;;;;N;;;;; +1CF2;VEDIC SIGN ARDHAVISARGA;Lo;0;L;;;;;N;;;;; +1CF3;VEDIC SIGN ROTATED ARDHAVISARGA;Lo;0;L;;;;;N;;;;; +1CF4;VEDIC TONE CANDRA ABOVE;Mn;230;NSM;;;;;N;;;;; +1CF5;VEDIC SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; +1CF6;VEDIC SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; +1CF7;VEDIC SIGN ATIKRAMA;Mc;0;L;;;;;N;;;;; +1CF8;VEDIC TONE RING ABOVE;Mn;230;NSM;;;;;N;;;;; +1CF9;VEDIC TONE DOUBLE RING ABOVE;Mn;230;NSM;;;;;N;;;;; +1CFA;VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA;Lo;0;L;;;;;N;;;;; +1D00;LATIN LETTER SMALL CAPITAL A;Ll;0;L;;;;;N;;;;; +1D01;LATIN LETTER SMALL CAPITAL AE;Ll;0;L;;;;;N;;;;; +1D02;LATIN SMALL LETTER TURNED AE;Ll;0;L;;;;;N;;;;; +1D03;LATIN LETTER SMALL CAPITAL BARRED B;Ll;0;L;;;;;N;;;;; +1D04;LATIN LETTER SMALL CAPITAL C;Ll;0;L;;;;;N;;;;; +1D05;LATIN LETTER SMALL CAPITAL D;Ll;0;L;;;;;N;;;;; +1D06;LATIN LETTER SMALL CAPITAL ETH;Ll;0;L;;;;;N;;;;; +1D07;LATIN LETTER SMALL CAPITAL E;Ll;0;L;;;;;N;;;;; +1D08;LATIN SMALL LETTER TURNED OPEN E;Ll;0;L;;;;;N;;;;; +1D09;LATIN SMALL LETTER TURNED I;Ll;0;L;;;;;N;;;;; +1D0A;LATIN LETTER SMALL CAPITAL J;Ll;0;L;;;;;N;;;;; +1D0B;LATIN LETTER SMALL CAPITAL K;Ll;0;L;;;;;N;;;;; +1D0C;LATIN LETTER SMALL CAPITAL L WITH STROKE;Ll;0;L;;;;;N;;;;; +1D0D;LATIN LETTER SMALL CAPITAL M;Ll;0;L;;;;;N;;;;; +1D0E;LATIN LETTER SMALL CAPITAL REVERSED N;Ll;0;L;;;;;N;;;;; +1D0F;LATIN LETTER SMALL CAPITAL O;Ll;0;L;;;;;N;;;;; +1D10;LATIN LETTER SMALL CAPITAL OPEN O;Ll;0;L;;;;;N;;;;; +1D11;LATIN SMALL LETTER SIDEWAYS O;Ll;0;L;;;;;N;;;;; +1D12;LATIN SMALL LETTER SIDEWAYS OPEN O;Ll;0;L;;;;;N;;;;; +1D13;LATIN SMALL LETTER SIDEWAYS O WITH STROKE;Ll;0;L;;;;;N;;;;; +1D14;LATIN SMALL LETTER TURNED OE;Ll;0;L;;;;;N;;;;; +1D15;LATIN LETTER SMALL CAPITAL OU;Ll;0;L;;;;;N;;;;; +1D16;LATIN SMALL LETTER TOP HALF O;Ll;0;L;;;;;N;;;;; +1D17;LATIN SMALL LETTER BOTTOM HALF O;Ll;0;L;;;;;N;;;;; +1D18;LATIN LETTER SMALL CAPITAL P;Ll;0;L;;;;;N;;;;; +1D19;LATIN LETTER SMALL CAPITAL REVERSED R;Ll;0;L;;;;;N;;;;; +1D1A;LATIN LETTER SMALL CAPITAL TURNED R;Ll;0;L;;;;;N;;;;; +1D1B;LATIN LETTER SMALL CAPITAL T;Ll;0;L;;;;;N;;;;; +1D1C;LATIN LETTER SMALL CAPITAL U;Ll;0;L;;;;;N;;;;; +1D1D;LATIN SMALL LETTER SIDEWAYS U;Ll;0;L;;;;;N;;;;; +1D1E;LATIN SMALL LETTER SIDEWAYS DIAERESIZED U;Ll;0;L;;;;;N;;;;; +1D1F;LATIN SMALL LETTER SIDEWAYS TURNED M;Ll;0;L;;;;;N;;;;; +1D20;LATIN LETTER SMALL CAPITAL V;Ll;0;L;;;;;N;;;;; +1D21;LATIN LETTER SMALL CAPITAL W;Ll;0;L;;;;;N;;;;; +1D22;LATIN LETTER SMALL CAPITAL Z;Ll;0;L;;;;;N;;;;; +1D23;LATIN LETTER SMALL CAPITAL EZH;Ll;0;L;;;;;N;;;;; +1D24;LATIN LETTER VOICED LARYNGEAL SPIRANT;Ll;0;L;;;;;N;;;;; +1D25;LATIN LETTER AIN;Ll;0;L;;;;;N;;;;; +1D26;GREEK LETTER SMALL CAPITAL GAMMA;Ll;0;L;;;;;N;;;;; +1D27;GREEK LETTER SMALL CAPITAL LAMDA;Ll;0;L;;;;;N;;;;; +1D28;GREEK LETTER SMALL CAPITAL PI;Ll;0;L;;;;;N;;;;; +1D29;GREEK LETTER SMALL CAPITAL RHO;Ll;0;L;;;;;N;;;;; +1D2A;GREEK LETTER SMALL CAPITAL PSI;Ll;0;L;;;;;N;;;;; +1D2B;CYRILLIC LETTER SMALL CAPITAL EL;Ll;0;L;;;;;N;;;;; +1D2C;MODIFIER LETTER CAPITAL A;Lm;0;L; 0041;;;;N;;;;; +1D2D;MODIFIER LETTER CAPITAL AE;Lm;0;L; 00C6;;;;N;;;;; +1D2E;MODIFIER LETTER CAPITAL B;Lm;0;L; 0042;;;;N;;;;; +1D2F;MODIFIER LETTER CAPITAL BARRED B;Lm;0;L;;;;;N;;;;; +1D30;MODIFIER LETTER CAPITAL D;Lm;0;L; 0044;;;;N;;;;; +1D31;MODIFIER LETTER CAPITAL E;Lm;0;L; 0045;;;;N;;;;; +1D32;MODIFIER LETTER CAPITAL REVERSED E;Lm;0;L; 018E;;;;N;;;;; +1D33;MODIFIER LETTER CAPITAL G;Lm;0;L; 0047;;;;N;;;;; +1D34;MODIFIER LETTER CAPITAL H;Lm;0;L; 0048;;;;N;;;;; +1D35;MODIFIER LETTER CAPITAL I;Lm;0;L; 0049;;;;N;;;;; +1D36;MODIFIER LETTER CAPITAL J;Lm;0;L; 004A;;;;N;;;;; +1D37;MODIFIER LETTER CAPITAL K;Lm;0;L; 004B;;;;N;;;;; +1D38;MODIFIER LETTER CAPITAL L;Lm;0;L; 004C;;;;N;;;;; +1D39;MODIFIER LETTER CAPITAL M;Lm;0;L; 004D;;;;N;;;;; +1D3A;MODIFIER LETTER CAPITAL N;Lm;0;L; 004E;;;;N;;;;; +1D3B;MODIFIER LETTER CAPITAL REVERSED N;Lm;0;L;;;;;N;;;;; +1D3C;MODIFIER LETTER CAPITAL O;Lm;0;L; 004F;;;;N;;;;; +1D3D;MODIFIER LETTER CAPITAL OU;Lm;0;L; 0222;;;;N;;;;; +1D3E;MODIFIER LETTER CAPITAL P;Lm;0;L; 0050;;;;N;;;;; +1D3F;MODIFIER LETTER CAPITAL R;Lm;0;L; 0052;;;;N;;;;; +1D40;MODIFIER LETTER CAPITAL T;Lm;0;L; 0054;;;;N;;;;; +1D41;MODIFIER LETTER CAPITAL U;Lm;0;L; 0055;;;;N;;;;; +1D42;MODIFIER LETTER CAPITAL W;Lm;0;L; 0057;;;;N;;;;; +1D43;MODIFIER LETTER SMALL A;Lm;0;L; 0061;;;;N;;;;; +1D44;MODIFIER LETTER SMALL TURNED A;Lm;0;L; 0250;;;;N;;;;; +1D45;MODIFIER LETTER SMALL ALPHA;Lm;0;L; 0251;;;;N;;;;; +1D46;MODIFIER LETTER SMALL TURNED AE;Lm;0;L; 1D02;;;;N;;;;; +1D47;MODIFIER LETTER SMALL B;Lm;0;L; 0062;;;;N;;;;; +1D48;MODIFIER LETTER SMALL D;Lm;0;L; 0064;;;;N;;;;; +1D49;MODIFIER LETTER SMALL E;Lm;0;L; 0065;;;;N;;;;; +1D4A;MODIFIER LETTER SMALL SCHWA;Lm;0;L; 0259;;;;N;;;;; +1D4B;MODIFIER LETTER SMALL OPEN E;Lm;0;L; 025B;;;;N;;;;; +1D4C;MODIFIER LETTER SMALL TURNED OPEN E;Lm;0;L; 025C;;;;N;;;;; +1D4D;MODIFIER LETTER SMALL G;Lm;0;L; 0067;;;;N;;;;; +1D4E;MODIFIER LETTER SMALL TURNED I;Lm;0;L;;;;;N;;;;; +1D4F;MODIFIER LETTER SMALL K;Lm;0;L; 006B;;;;N;;;;; +1D50;MODIFIER LETTER SMALL M;Lm;0;L; 006D;;;;N;;;;; +1D51;MODIFIER LETTER SMALL ENG;Lm;0;L; 014B;;;;N;;;;; +1D52;MODIFIER LETTER SMALL O;Lm;0;L; 006F;;;;N;;;;; +1D53;MODIFIER LETTER SMALL OPEN O;Lm;0;L; 0254;;;;N;;;;; +1D54;MODIFIER LETTER SMALL TOP HALF O;Lm;0;L; 1D16;;;;N;;;;; +1D55;MODIFIER LETTER SMALL BOTTOM HALF O;Lm;0;L; 1D17;;;;N;;;;; +1D56;MODIFIER LETTER SMALL P;Lm;0;L; 0070;;;;N;;;;; +1D57;MODIFIER LETTER SMALL T;Lm;0;L; 0074;;;;N;;;;; +1D58;MODIFIER LETTER SMALL U;Lm;0;L; 0075;;;;N;;;;; +1D59;MODIFIER LETTER SMALL SIDEWAYS U;Lm;0;L; 1D1D;;;;N;;;;; +1D5A;MODIFIER LETTER SMALL TURNED M;Lm;0;L; 026F;;;;N;;;;; +1D5B;MODIFIER LETTER SMALL V;Lm;0;L; 0076;;;;N;;;;; +1D5C;MODIFIER LETTER SMALL AIN;Lm;0;L; 1D25;;;;N;;;;; +1D5D;MODIFIER LETTER SMALL BETA;Lm;0;L; 03B2;;;;N;;;;; +1D5E;MODIFIER LETTER SMALL GREEK GAMMA;Lm;0;L; 03B3;;;;N;;;;; +1D5F;MODIFIER LETTER SMALL DELTA;Lm;0;L; 03B4;;;;N;;;;; +1D60;MODIFIER LETTER SMALL GREEK PHI;Lm;0;L; 03C6;;;;N;;;;; +1D61;MODIFIER LETTER SMALL CHI;Lm;0;L; 03C7;;;;N;;;;; +1D62;LATIN SUBSCRIPT SMALL LETTER I;Lm;0;L; 0069;;;;N;;;;; +1D63;LATIN SUBSCRIPT SMALL LETTER R;Lm;0;L; 0072;;;;N;;;;; +1D64;LATIN SUBSCRIPT SMALL LETTER U;Lm;0;L; 0075;;;;N;;;;; +1D65;LATIN SUBSCRIPT SMALL LETTER V;Lm;0;L; 0076;;;;N;;;;; +1D66;GREEK SUBSCRIPT SMALL LETTER BETA;Lm;0;L; 03B2;;;;N;;;;; +1D67;GREEK SUBSCRIPT SMALL LETTER GAMMA;Lm;0;L; 03B3;;;;N;;;;; +1D68;GREEK SUBSCRIPT SMALL LETTER RHO;Lm;0;L; 03C1;;;;N;;;;; +1D69;GREEK SUBSCRIPT SMALL LETTER PHI;Lm;0;L; 03C6;;;;N;;;;; +1D6A;GREEK SUBSCRIPT SMALL LETTER CHI;Lm;0;L; 03C7;;;;N;;;;; +1D6B;LATIN SMALL LETTER UE;Ll;0;L;;;;;N;;;;; +1D6C;LATIN SMALL LETTER B WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D6D;LATIN SMALL LETTER D WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D6E;LATIN SMALL LETTER F WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D6F;LATIN SMALL LETTER M WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D70;LATIN SMALL LETTER N WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D71;LATIN SMALL LETTER P WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D72;LATIN SMALL LETTER R WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D73;LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D74;LATIN SMALL LETTER S WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D75;LATIN SMALL LETTER T WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D76;LATIN SMALL LETTER Z WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +1D77;LATIN SMALL LETTER TURNED G;Ll;0;L;;;;;N;;;;; +1D78;MODIFIER LETTER CYRILLIC EN;Lm;0;L; 043D;;;;N;;;;; +1D79;LATIN SMALL LETTER INSULAR G;Ll;0;L;;;;;N;;;A77D;;A77D +1D7A;LATIN SMALL LETTER TH WITH STRIKETHROUGH;Ll;0;L;;;;;N;;;;; +1D7B;LATIN SMALL CAPITAL LETTER I WITH STROKE;Ll;0;L;;;;;N;;;;; +1D7C;LATIN SMALL LETTER IOTA WITH STROKE;Ll;0;L;;;;;N;;;;; +1D7D;LATIN SMALL LETTER P WITH STROKE;Ll;0;L;;;;;N;;;2C63;;2C63 +1D7E;LATIN SMALL CAPITAL LETTER U WITH STROKE;Ll;0;L;;;;;N;;;;; +1D7F;LATIN SMALL LETTER UPSILON WITH STROKE;Ll;0;L;;;;;N;;;;; +1D80;LATIN SMALL LETTER B WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D81;LATIN SMALL LETTER D WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D82;LATIN SMALL LETTER F WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D83;LATIN SMALL LETTER G WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D84;LATIN SMALL LETTER K WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D85;LATIN SMALL LETTER L WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D86;LATIN SMALL LETTER M WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D87;LATIN SMALL LETTER N WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D88;LATIN SMALL LETTER P WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D89;LATIN SMALL LETTER R WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D8A;LATIN SMALL LETTER S WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D8B;LATIN SMALL LETTER ESH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D8C;LATIN SMALL LETTER V WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D8D;LATIN SMALL LETTER X WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1D8E;LATIN SMALL LETTER Z WITH PALATAL HOOK;Ll;0;L;;;;;N;;;A7C6;;A7C6 +1D8F;LATIN SMALL LETTER A WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D90;LATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D91;LATIN SMALL LETTER D WITH HOOK AND TAIL;Ll;0;L;;;;;N;;;;; +1D92;LATIN SMALL LETTER E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D93;LATIN SMALL LETTER OPEN E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D94;LATIN SMALL LETTER REVERSED OPEN E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D95;LATIN SMALL LETTER SCHWA WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D96;LATIN SMALL LETTER I WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D97;LATIN SMALL LETTER OPEN O WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D98;LATIN SMALL LETTER ESH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D99;LATIN SMALL LETTER U WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D9A;LATIN SMALL LETTER EZH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1D9B;MODIFIER LETTER SMALL TURNED ALPHA;Lm;0;L; 0252;;;;N;;;;; +1D9C;MODIFIER LETTER SMALL C;Lm;0;L; 0063;;;;N;;;;; +1D9D;MODIFIER LETTER SMALL C WITH CURL;Lm;0;L; 0255;;;;N;;;;; +1D9E;MODIFIER LETTER SMALL ETH;Lm;0;L; 00F0;;;;N;;;;; +1D9F;MODIFIER LETTER SMALL REVERSED OPEN E;Lm;0;L; 025C;;;;N;;;;; +1DA0;MODIFIER LETTER SMALL F;Lm;0;L; 0066;;;;N;;;;; +1DA1;MODIFIER LETTER SMALL DOTLESS J WITH STROKE;Lm;0;L; 025F;;;;N;;;;; +1DA2;MODIFIER LETTER SMALL SCRIPT G;Lm;0;L; 0261;;;;N;;;;; +1DA3;MODIFIER LETTER SMALL TURNED H;Lm;0;L; 0265;;;;N;;;;; +1DA4;MODIFIER LETTER SMALL I WITH STROKE;Lm;0;L; 0268;;;;N;;;;; +1DA5;MODIFIER LETTER SMALL IOTA;Lm;0;L; 0269;;;;N;;;;; +1DA6;MODIFIER LETTER SMALL CAPITAL I;Lm;0;L; 026A;;;;N;;;;; +1DA7;MODIFIER LETTER SMALL CAPITAL I WITH STROKE;Lm;0;L; 1D7B;;;;N;;;;; +1DA8;MODIFIER LETTER SMALL J WITH CROSSED-TAIL;Lm;0;L; 029D;;;;N;;;;; +1DA9;MODIFIER LETTER SMALL L WITH RETROFLEX HOOK;Lm;0;L; 026D;;;;N;;;;; +1DAA;MODIFIER LETTER SMALL L WITH PALATAL HOOK;Lm;0;L; 1D85;;;;N;;;;; +1DAB;MODIFIER LETTER SMALL CAPITAL L;Lm;0;L; 029F;;;;N;;;;; +1DAC;MODIFIER LETTER SMALL M WITH HOOK;Lm;0;L; 0271;;;;N;;;;; +1DAD;MODIFIER LETTER SMALL TURNED M WITH LONG LEG;Lm;0;L; 0270;;;;N;;;;; +1DAE;MODIFIER LETTER SMALL N WITH LEFT HOOK;Lm;0;L; 0272;;;;N;;;;; +1DAF;MODIFIER LETTER SMALL N WITH RETROFLEX HOOK;Lm;0;L; 0273;;;;N;;;;; +1DB0;MODIFIER LETTER SMALL CAPITAL N;Lm;0;L; 0274;;;;N;;;;; +1DB1;MODIFIER LETTER SMALL BARRED O;Lm;0;L; 0275;;;;N;;;;; +1DB2;MODIFIER LETTER SMALL PHI;Lm;0;L; 0278;;;;N;;;;; +1DB3;MODIFIER LETTER SMALL S WITH HOOK;Lm;0;L; 0282;;;;N;;;;; +1DB4;MODIFIER LETTER SMALL ESH;Lm;0;L; 0283;;;;N;;;;; +1DB5;MODIFIER LETTER SMALL T WITH PALATAL HOOK;Lm;0;L; 01AB;;;;N;;;;; +1DB6;MODIFIER LETTER SMALL U BAR;Lm;0;L; 0289;;;;N;;;;; +1DB7;MODIFIER LETTER SMALL UPSILON;Lm;0;L; 028A;;;;N;;;;; +1DB8;MODIFIER LETTER SMALL CAPITAL U;Lm;0;L; 1D1C;;;;N;;;;; +1DB9;MODIFIER LETTER SMALL V WITH HOOK;Lm;0;L; 028B;;;;N;;;;; +1DBA;MODIFIER LETTER SMALL TURNED V;Lm;0;L; 028C;;;;N;;;;; +1DBB;MODIFIER LETTER SMALL Z;Lm;0;L; 007A;;;;N;;;;; +1DBC;MODIFIER LETTER SMALL Z WITH RETROFLEX HOOK;Lm;0;L; 0290;;;;N;;;;; +1DBD;MODIFIER LETTER SMALL Z WITH CURL;Lm;0;L; 0291;;;;N;;;;; +1DBE;MODIFIER LETTER SMALL EZH;Lm;0;L; 0292;;;;N;;;;; +1DBF;MODIFIER LETTER SMALL THETA;Lm;0;L; 03B8;;;;N;;;;; +1DC0;COMBINING DOTTED GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;; +1DC1;COMBINING DOTTED ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;; +1DC2;COMBINING SNAKE BELOW;Mn;220;NSM;;;;;N;;;;; +1DC3;COMBINING SUSPENSION MARK;Mn;230;NSM;;;;;N;;;;; +1DC4;COMBINING MACRON-ACUTE;Mn;230;NSM;;;;;N;;;;; +1DC5;COMBINING GRAVE-MACRON;Mn;230;NSM;;;;;N;;;;; +1DC6;COMBINING MACRON-GRAVE;Mn;230;NSM;;;;;N;;;;; +1DC7;COMBINING ACUTE-MACRON;Mn;230;NSM;;;;;N;;;;; +1DC8;COMBINING GRAVE-ACUTE-GRAVE;Mn;230;NSM;;;;;N;;;;; +1DC9;COMBINING ACUTE-GRAVE-ACUTE;Mn;230;NSM;;;;;N;;;;; +1DCA;COMBINING LATIN SMALL LETTER R BELOW;Mn;220;NSM;;;;;N;;;;; +1DCB;COMBINING BREVE-MACRON;Mn;230;NSM;;;;;N;;;;; +1DCC;COMBINING MACRON-BREVE;Mn;230;NSM;;;;;N;;;;; +1DCD;COMBINING DOUBLE CIRCUMFLEX ABOVE;Mn;234;NSM;;;;;N;;;;; +1DCE;COMBINING OGONEK ABOVE;Mn;214;NSM;;;;;N;;;;; +1DCF;COMBINING ZIGZAG BELOW;Mn;220;NSM;;;;;N;;;;; +1DD0;COMBINING IS BELOW;Mn;202;NSM;;;;;N;;;;; +1DD1;COMBINING UR ABOVE;Mn;230;NSM;;;;;N;;;;; +1DD2;COMBINING US ABOVE;Mn;230;NSM;;;;;N;;;;; +1DD3;COMBINING LATIN SMALL LETTER FLATTENED OPEN A ABOVE;Mn;230;NSM;;;;;N;;;;; +1DD4;COMBINING LATIN SMALL LETTER AE;Mn;230;NSM;;;;;N;;;;; +1DD5;COMBINING LATIN SMALL LETTER AO;Mn;230;NSM;;;;;N;;;;; +1DD6;COMBINING LATIN SMALL LETTER AV;Mn;230;NSM;;;;;N;;;;; +1DD7;COMBINING LATIN SMALL LETTER C CEDILLA;Mn;230;NSM;;;;;N;;;;; +1DD8;COMBINING LATIN SMALL LETTER INSULAR D;Mn;230;NSM;;;;;N;;;;; +1DD9;COMBINING LATIN SMALL LETTER ETH;Mn;230;NSM;;;;;N;;;;; +1DDA;COMBINING LATIN SMALL LETTER G;Mn;230;NSM;;;;;N;;;;; +1DDB;COMBINING LATIN LETTER SMALL CAPITAL G;Mn;230;NSM;;;;;N;;;;; +1DDC;COMBINING LATIN SMALL LETTER K;Mn;230;NSM;;;;;N;;;;; +1DDD;COMBINING LATIN SMALL LETTER L;Mn;230;NSM;;;;;N;;;;; +1DDE;COMBINING LATIN LETTER SMALL CAPITAL L;Mn;230;NSM;;;;;N;;;;; +1DDF;COMBINING LATIN LETTER SMALL CAPITAL M;Mn;230;NSM;;;;;N;;;;; +1DE0;COMBINING LATIN SMALL LETTER N;Mn;230;NSM;;;;;N;;;;; +1DE1;COMBINING LATIN LETTER SMALL CAPITAL N;Mn;230;NSM;;;;;N;;;;; +1DE2;COMBINING LATIN LETTER SMALL CAPITAL R;Mn;230;NSM;;;;;N;;;;; +1DE3;COMBINING LATIN SMALL LETTER R ROTUNDA;Mn;230;NSM;;;;;N;;;;; +1DE4;COMBINING LATIN SMALL LETTER S;Mn;230;NSM;;;;;N;;;;; +1DE5;COMBINING LATIN SMALL LETTER LONG S;Mn;230;NSM;;;;;N;;;;; +1DE6;COMBINING LATIN SMALL LETTER Z;Mn;230;NSM;;;;;N;;;;; +1DE7;COMBINING LATIN SMALL LETTER ALPHA;Mn;230;NSM;;;;;N;;;;; +1DE8;COMBINING LATIN SMALL LETTER B;Mn;230;NSM;;;;;N;;;;; +1DE9;COMBINING LATIN SMALL LETTER BETA;Mn;230;NSM;;;;;N;;;;; +1DEA;COMBINING LATIN SMALL LETTER SCHWA;Mn;230;NSM;;;;;N;;;;; +1DEB;COMBINING LATIN SMALL LETTER F;Mn;230;NSM;;;;;N;;;;; +1DEC;COMBINING LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE;Mn;230;NSM;;;;;N;;;;; +1DED;COMBINING LATIN SMALL LETTER O WITH LIGHT CENTRALIZATION STROKE;Mn;230;NSM;;;;;N;;;;; +1DEE;COMBINING LATIN SMALL LETTER P;Mn;230;NSM;;;;;N;;;;; +1DEF;COMBINING LATIN SMALL LETTER ESH;Mn;230;NSM;;;;;N;;;;; +1DF0;COMBINING LATIN SMALL LETTER U WITH LIGHT CENTRALIZATION STROKE;Mn;230;NSM;;;;;N;;;;; +1DF1;COMBINING LATIN SMALL LETTER W;Mn;230;NSM;;;;;N;;;;; +1DF2;COMBINING LATIN SMALL LETTER A WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;; +1DF3;COMBINING LATIN SMALL LETTER O WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;; +1DF4;COMBINING LATIN SMALL LETTER U WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;; +1DF5;COMBINING UP TACK ABOVE;Mn;230;NSM;;;;;N;;;;; +1DF6;COMBINING KAVYKA ABOVE RIGHT;Mn;232;NSM;;;;;N;;;;; +1DF7;COMBINING KAVYKA ABOVE LEFT;Mn;228;NSM;;;;;N;;;;; +1DF8;COMBINING DOT ABOVE LEFT;Mn;228;NSM;;;;;N;;;;; +1DF9;COMBINING WIDE INVERTED BRIDGE BELOW;Mn;220;NSM;;;;;N;;;;; +1DFA;COMBINING DOT BELOW LEFT;Mn;218;NSM;;;;;N;;;;; +1DFB;COMBINING DELETION MARK;Mn;230;NSM;;;;;N;;;;; +1DFC;COMBINING DOUBLE INVERTED BREVE BELOW;Mn;233;NSM;;;;;N;;;;; +1DFD;COMBINING ALMOST EQUAL TO BELOW;Mn;220;NSM;;;;;N;;;;; +1DFE;COMBINING LEFT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; +1DFF;COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; +1E00;LATIN CAPITAL LETTER A WITH RING BELOW;Lu;0;L;0041 0325;;;;N;;;;1E01; +1E01;LATIN SMALL LETTER A WITH RING BELOW;Ll;0;L;0061 0325;;;;N;;;1E00;;1E00 +1E02;LATIN CAPITAL LETTER B WITH DOT ABOVE;Lu;0;L;0042 0307;;;;N;;;;1E03; +1E03;LATIN SMALL LETTER B WITH DOT ABOVE;Ll;0;L;0062 0307;;;;N;;;1E02;;1E02 +1E04;LATIN CAPITAL LETTER B WITH DOT BELOW;Lu;0;L;0042 0323;;;;N;;;;1E05; +1E05;LATIN SMALL LETTER B WITH DOT BELOW;Ll;0;L;0062 0323;;;;N;;;1E04;;1E04 +1E06;LATIN CAPITAL LETTER B WITH LINE BELOW;Lu;0;L;0042 0331;;;;N;;;;1E07; +1E07;LATIN SMALL LETTER B WITH LINE BELOW;Ll;0;L;0062 0331;;;;N;;;1E06;;1E06 +1E08;LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE;Lu;0;L;00C7 0301;;;;N;;;;1E09; +1E09;LATIN SMALL LETTER C WITH CEDILLA AND ACUTE;Ll;0;L;00E7 0301;;;;N;;;1E08;;1E08 +1E0A;LATIN CAPITAL LETTER D WITH DOT ABOVE;Lu;0;L;0044 0307;;;;N;;;;1E0B; +1E0B;LATIN SMALL LETTER D WITH DOT ABOVE;Ll;0;L;0064 0307;;;;N;;;1E0A;;1E0A +1E0C;LATIN CAPITAL LETTER D WITH DOT BELOW;Lu;0;L;0044 0323;;;;N;;;;1E0D; +1E0D;LATIN SMALL LETTER D WITH DOT BELOW;Ll;0;L;0064 0323;;;;N;;;1E0C;;1E0C +1E0E;LATIN CAPITAL LETTER D WITH LINE BELOW;Lu;0;L;0044 0331;;;;N;;;;1E0F; +1E0F;LATIN SMALL LETTER D WITH LINE BELOW;Ll;0;L;0064 0331;;;;N;;;1E0E;;1E0E +1E10;LATIN CAPITAL LETTER D WITH CEDILLA;Lu;0;L;0044 0327;;;;N;;;;1E11; +1E11;LATIN SMALL LETTER D WITH CEDILLA;Ll;0;L;0064 0327;;;;N;;;1E10;;1E10 +1E12;LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW;Lu;0;L;0044 032D;;;;N;;;;1E13; +1E13;LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW;Ll;0;L;0064 032D;;;;N;;;1E12;;1E12 +1E14;LATIN CAPITAL LETTER E WITH MACRON AND GRAVE;Lu;0;L;0112 0300;;;;N;;;;1E15; +1E15;LATIN SMALL LETTER E WITH MACRON AND GRAVE;Ll;0;L;0113 0300;;;;N;;;1E14;;1E14 +1E16;LATIN CAPITAL LETTER E WITH MACRON AND ACUTE;Lu;0;L;0112 0301;;;;N;;;;1E17; +1E17;LATIN SMALL LETTER E WITH MACRON AND ACUTE;Ll;0;L;0113 0301;;;;N;;;1E16;;1E16 +1E18;LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW;Lu;0;L;0045 032D;;;;N;;;;1E19; +1E19;LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW;Ll;0;L;0065 032D;;;;N;;;1E18;;1E18 +1E1A;LATIN CAPITAL LETTER E WITH TILDE BELOW;Lu;0;L;0045 0330;;;;N;;;;1E1B; +1E1B;LATIN SMALL LETTER E WITH TILDE BELOW;Ll;0;L;0065 0330;;;;N;;;1E1A;;1E1A +1E1C;LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE;Lu;0;L;0228 0306;;;;N;;;;1E1D; +1E1D;LATIN SMALL LETTER E WITH CEDILLA AND BREVE;Ll;0;L;0229 0306;;;;N;;;1E1C;;1E1C +1E1E;LATIN CAPITAL LETTER F WITH DOT ABOVE;Lu;0;L;0046 0307;;;;N;;;;1E1F; +1E1F;LATIN SMALL LETTER F WITH DOT ABOVE;Ll;0;L;0066 0307;;;;N;;;1E1E;;1E1E +1E20;LATIN CAPITAL LETTER G WITH MACRON;Lu;0;L;0047 0304;;;;N;;;;1E21; +1E21;LATIN SMALL LETTER G WITH MACRON;Ll;0;L;0067 0304;;;;N;;;1E20;;1E20 +1E22;LATIN CAPITAL LETTER H WITH DOT ABOVE;Lu;0;L;0048 0307;;;;N;;;;1E23; +1E23;LATIN SMALL LETTER H WITH DOT ABOVE;Ll;0;L;0068 0307;;;;N;;;1E22;;1E22 +1E24;LATIN CAPITAL LETTER H WITH DOT BELOW;Lu;0;L;0048 0323;;;;N;;;;1E25; +1E25;LATIN SMALL LETTER H WITH DOT BELOW;Ll;0;L;0068 0323;;;;N;;;1E24;;1E24 +1E26;LATIN CAPITAL LETTER H WITH DIAERESIS;Lu;0;L;0048 0308;;;;N;;;;1E27; +1E27;LATIN SMALL LETTER H WITH DIAERESIS;Ll;0;L;0068 0308;;;;N;;;1E26;;1E26 +1E28;LATIN CAPITAL LETTER H WITH CEDILLA;Lu;0;L;0048 0327;;;;N;;;;1E29; +1E29;LATIN SMALL LETTER H WITH CEDILLA;Ll;0;L;0068 0327;;;;N;;;1E28;;1E28 +1E2A;LATIN CAPITAL LETTER H WITH BREVE BELOW;Lu;0;L;0048 032E;;;;N;;;;1E2B; +1E2B;LATIN SMALL LETTER H WITH BREVE BELOW;Ll;0;L;0068 032E;;;;N;;;1E2A;;1E2A +1E2C;LATIN CAPITAL LETTER I WITH TILDE BELOW;Lu;0;L;0049 0330;;;;N;;;;1E2D; +1E2D;LATIN SMALL LETTER I WITH TILDE BELOW;Ll;0;L;0069 0330;;;;N;;;1E2C;;1E2C +1E2E;LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE;Lu;0;L;00CF 0301;;;;N;;;;1E2F; +1E2F;LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE;Ll;0;L;00EF 0301;;;;N;;;1E2E;;1E2E +1E30;LATIN CAPITAL LETTER K WITH ACUTE;Lu;0;L;004B 0301;;;;N;;;;1E31; +1E31;LATIN SMALL LETTER K WITH ACUTE;Ll;0;L;006B 0301;;;;N;;;1E30;;1E30 +1E32;LATIN CAPITAL LETTER K WITH DOT BELOW;Lu;0;L;004B 0323;;;;N;;;;1E33; +1E33;LATIN SMALL LETTER K WITH DOT BELOW;Ll;0;L;006B 0323;;;;N;;;1E32;;1E32 +1E34;LATIN CAPITAL LETTER K WITH LINE BELOW;Lu;0;L;004B 0331;;;;N;;;;1E35; +1E35;LATIN SMALL LETTER K WITH LINE BELOW;Ll;0;L;006B 0331;;;;N;;;1E34;;1E34 +1E36;LATIN CAPITAL LETTER L WITH DOT BELOW;Lu;0;L;004C 0323;;;;N;;;;1E37; +1E37;LATIN SMALL LETTER L WITH DOT BELOW;Ll;0;L;006C 0323;;;;N;;;1E36;;1E36 +1E38;LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON;Lu;0;L;1E36 0304;;;;N;;;;1E39; +1E39;LATIN SMALL LETTER L WITH DOT BELOW AND MACRON;Ll;0;L;1E37 0304;;;;N;;;1E38;;1E38 +1E3A;LATIN CAPITAL LETTER L WITH LINE BELOW;Lu;0;L;004C 0331;;;;N;;;;1E3B; +1E3B;LATIN SMALL LETTER L WITH LINE BELOW;Ll;0;L;006C 0331;;;;N;;;1E3A;;1E3A +1E3C;LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW;Lu;0;L;004C 032D;;;;N;;;;1E3D; +1E3D;LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW;Ll;0;L;006C 032D;;;;N;;;1E3C;;1E3C +1E3E;LATIN CAPITAL LETTER M WITH ACUTE;Lu;0;L;004D 0301;;;;N;;;;1E3F; +1E3F;LATIN SMALL LETTER M WITH ACUTE;Ll;0;L;006D 0301;;;;N;;;1E3E;;1E3E +1E40;LATIN CAPITAL LETTER M WITH DOT ABOVE;Lu;0;L;004D 0307;;;;N;;;;1E41; +1E41;LATIN SMALL LETTER M WITH DOT ABOVE;Ll;0;L;006D 0307;;;;N;;;1E40;;1E40 +1E42;LATIN CAPITAL LETTER M WITH DOT BELOW;Lu;0;L;004D 0323;;;;N;;;;1E43; +1E43;LATIN SMALL LETTER M WITH DOT BELOW;Ll;0;L;006D 0323;;;;N;;;1E42;;1E42 +1E44;LATIN CAPITAL LETTER N WITH DOT ABOVE;Lu;0;L;004E 0307;;;;N;;;;1E45; +1E45;LATIN SMALL LETTER N WITH DOT ABOVE;Ll;0;L;006E 0307;;;;N;;;1E44;;1E44 +1E46;LATIN CAPITAL LETTER N WITH DOT BELOW;Lu;0;L;004E 0323;;;;N;;;;1E47; +1E47;LATIN SMALL LETTER N WITH DOT BELOW;Ll;0;L;006E 0323;;;;N;;;1E46;;1E46 +1E48;LATIN CAPITAL LETTER N WITH LINE BELOW;Lu;0;L;004E 0331;;;;N;;;;1E49; +1E49;LATIN SMALL LETTER N WITH LINE BELOW;Ll;0;L;006E 0331;;;;N;;;1E48;;1E48 +1E4A;LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW;Lu;0;L;004E 032D;;;;N;;;;1E4B; +1E4B;LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW;Ll;0;L;006E 032D;;;;N;;;1E4A;;1E4A +1E4C;LATIN CAPITAL LETTER O WITH TILDE AND ACUTE;Lu;0;L;00D5 0301;;;;N;;;;1E4D; +1E4D;LATIN SMALL LETTER O WITH TILDE AND ACUTE;Ll;0;L;00F5 0301;;;;N;;;1E4C;;1E4C +1E4E;LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS;Lu;0;L;00D5 0308;;;;N;;;;1E4F; +1E4F;LATIN SMALL LETTER O WITH TILDE AND DIAERESIS;Ll;0;L;00F5 0308;;;;N;;;1E4E;;1E4E +1E50;LATIN CAPITAL LETTER O WITH MACRON AND GRAVE;Lu;0;L;014C 0300;;;;N;;;;1E51; +1E51;LATIN SMALL LETTER O WITH MACRON AND GRAVE;Ll;0;L;014D 0300;;;;N;;;1E50;;1E50 +1E52;LATIN CAPITAL LETTER O WITH MACRON AND ACUTE;Lu;0;L;014C 0301;;;;N;;;;1E53; +1E53;LATIN SMALL LETTER O WITH MACRON AND ACUTE;Ll;0;L;014D 0301;;;;N;;;1E52;;1E52 +1E54;LATIN CAPITAL LETTER P WITH ACUTE;Lu;0;L;0050 0301;;;;N;;;;1E55; +1E55;LATIN SMALL LETTER P WITH ACUTE;Ll;0;L;0070 0301;;;;N;;;1E54;;1E54 +1E56;LATIN CAPITAL LETTER P WITH DOT ABOVE;Lu;0;L;0050 0307;;;;N;;;;1E57; +1E57;LATIN SMALL LETTER P WITH DOT ABOVE;Ll;0;L;0070 0307;;;;N;;;1E56;;1E56 +1E58;LATIN CAPITAL LETTER R WITH DOT ABOVE;Lu;0;L;0052 0307;;;;N;;;;1E59; +1E59;LATIN SMALL LETTER R WITH DOT ABOVE;Ll;0;L;0072 0307;;;;N;;;1E58;;1E58 +1E5A;LATIN CAPITAL LETTER R WITH DOT BELOW;Lu;0;L;0052 0323;;;;N;;;;1E5B; +1E5B;LATIN SMALL LETTER R WITH DOT BELOW;Ll;0;L;0072 0323;;;;N;;;1E5A;;1E5A +1E5C;LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON;Lu;0;L;1E5A 0304;;;;N;;;;1E5D; +1E5D;LATIN SMALL LETTER R WITH DOT BELOW AND MACRON;Ll;0;L;1E5B 0304;;;;N;;;1E5C;;1E5C +1E5E;LATIN CAPITAL LETTER R WITH LINE BELOW;Lu;0;L;0052 0331;;;;N;;;;1E5F; +1E5F;LATIN SMALL LETTER R WITH LINE BELOW;Ll;0;L;0072 0331;;;;N;;;1E5E;;1E5E +1E60;LATIN CAPITAL LETTER S WITH DOT ABOVE;Lu;0;L;0053 0307;;;;N;;;;1E61; +1E61;LATIN SMALL LETTER S WITH DOT ABOVE;Ll;0;L;0073 0307;;;;N;;;1E60;;1E60 +1E62;LATIN CAPITAL LETTER S WITH DOT BELOW;Lu;0;L;0053 0323;;;;N;;;;1E63; +1E63;LATIN SMALL LETTER S WITH DOT BELOW;Ll;0;L;0073 0323;;;;N;;;1E62;;1E62 +1E64;LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE;Lu;0;L;015A 0307;;;;N;;;;1E65; +1E65;LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE;Ll;0;L;015B 0307;;;;N;;;1E64;;1E64 +1E66;LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE;Lu;0;L;0160 0307;;;;N;;;;1E67; +1E67;LATIN SMALL LETTER S WITH CARON AND DOT ABOVE;Ll;0;L;0161 0307;;;;N;;;1E66;;1E66 +1E68;LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE;Lu;0;L;1E62 0307;;;;N;;;;1E69; +1E69;LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE;Ll;0;L;1E63 0307;;;;N;;;1E68;;1E68 +1E6A;LATIN CAPITAL LETTER T WITH DOT ABOVE;Lu;0;L;0054 0307;;;;N;;;;1E6B; +1E6B;LATIN SMALL LETTER T WITH DOT ABOVE;Ll;0;L;0074 0307;;;;N;;;1E6A;;1E6A +1E6C;LATIN CAPITAL LETTER T WITH DOT BELOW;Lu;0;L;0054 0323;;;;N;;;;1E6D; +1E6D;LATIN SMALL LETTER T WITH DOT BELOW;Ll;0;L;0074 0323;;;;N;;;1E6C;;1E6C +1E6E;LATIN CAPITAL LETTER T WITH LINE BELOW;Lu;0;L;0054 0331;;;;N;;;;1E6F; +1E6F;LATIN SMALL LETTER T WITH LINE BELOW;Ll;0;L;0074 0331;;;;N;;;1E6E;;1E6E +1E70;LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW;Lu;0;L;0054 032D;;;;N;;;;1E71; +1E71;LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW;Ll;0;L;0074 032D;;;;N;;;1E70;;1E70 +1E72;LATIN CAPITAL LETTER U WITH DIAERESIS BELOW;Lu;0;L;0055 0324;;;;N;;;;1E73; +1E73;LATIN SMALL LETTER U WITH DIAERESIS BELOW;Ll;0;L;0075 0324;;;;N;;;1E72;;1E72 +1E74;LATIN CAPITAL LETTER U WITH TILDE BELOW;Lu;0;L;0055 0330;;;;N;;;;1E75; +1E75;LATIN SMALL LETTER U WITH TILDE BELOW;Ll;0;L;0075 0330;;;;N;;;1E74;;1E74 +1E76;LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW;Lu;0;L;0055 032D;;;;N;;;;1E77; +1E77;LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW;Ll;0;L;0075 032D;;;;N;;;1E76;;1E76 +1E78;LATIN CAPITAL LETTER U WITH TILDE AND ACUTE;Lu;0;L;0168 0301;;;;N;;;;1E79; +1E79;LATIN SMALL LETTER U WITH TILDE AND ACUTE;Ll;0;L;0169 0301;;;;N;;;1E78;;1E78 +1E7A;LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS;Lu;0;L;016A 0308;;;;N;;;;1E7B; +1E7B;LATIN SMALL LETTER U WITH MACRON AND DIAERESIS;Ll;0;L;016B 0308;;;;N;;;1E7A;;1E7A +1E7C;LATIN CAPITAL LETTER V WITH TILDE;Lu;0;L;0056 0303;;;;N;;;;1E7D; +1E7D;LATIN SMALL LETTER V WITH TILDE;Ll;0;L;0076 0303;;;;N;;;1E7C;;1E7C +1E7E;LATIN CAPITAL LETTER V WITH DOT BELOW;Lu;0;L;0056 0323;;;;N;;;;1E7F; +1E7F;LATIN SMALL LETTER V WITH DOT BELOW;Ll;0;L;0076 0323;;;;N;;;1E7E;;1E7E +1E80;LATIN CAPITAL LETTER W WITH GRAVE;Lu;0;L;0057 0300;;;;N;;;;1E81; +1E81;LATIN SMALL LETTER W WITH GRAVE;Ll;0;L;0077 0300;;;;N;;;1E80;;1E80 +1E82;LATIN CAPITAL LETTER W WITH ACUTE;Lu;0;L;0057 0301;;;;N;;;;1E83; +1E83;LATIN SMALL LETTER W WITH ACUTE;Ll;0;L;0077 0301;;;;N;;;1E82;;1E82 +1E84;LATIN CAPITAL LETTER W WITH DIAERESIS;Lu;0;L;0057 0308;;;;N;;;;1E85; +1E85;LATIN SMALL LETTER W WITH DIAERESIS;Ll;0;L;0077 0308;;;;N;;;1E84;;1E84 +1E86;LATIN CAPITAL LETTER W WITH DOT ABOVE;Lu;0;L;0057 0307;;;;N;;;;1E87; +1E87;LATIN SMALL LETTER W WITH DOT ABOVE;Ll;0;L;0077 0307;;;;N;;;1E86;;1E86 +1E88;LATIN CAPITAL LETTER W WITH DOT BELOW;Lu;0;L;0057 0323;;;;N;;;;1E89; +1E89;LATIN SMALL LETTER W WITH DOT BELOW;Ll;0;L;0077 0323;;;;N;;;1E88;;1E88 +1E8A;LATIN CAPITAL LETTER X WITH DOT ABOVE;Lu;0;L;0058 0307;;;;N;;;;1E8B; +1E8B;LATIN SMALL LETTER X WITH DOT ABOVE;Ll;0;L;0078 0307;;;;N;;;1E8A;;1E8A +1E8C;LATIN CAPITAL LETTER X WITH DIAERESIS;Lu;0;L;0058 0308;;;;N;;;;1E8D; +1E8D;LATIN SMALL LETTER X WITH DIAERESIS;Ll;0;L;0078 0308;;;;N;;;1E8C;;1E8C +1E8E;LATIN CAPITAL LETTER Y WITH DOT ABOVE;Lu;0;L;0059 0307;;;;N;;;;1E8F; +1E8F;LATIN SMALL LETTER Y WITH DOT ABOVE;Ll;0;L;0079 0307;;;;N;;;1E8E;;1E8E +1E90;LATIN CAPITAL LETTER Z WITH CIRCUMFLEX;Lu;0;L;005A 0302;;;;N;;;;1E91; +1E91;LATIN SMALL LETTER Z WITH CIRCUMFLEX;Ll;0;L;007A 0302;;;;N;;;1E90;;1E90 +1E92;LATIN CAPITAL LETTER Z WITH DOT BELOW;Lu;0;L;005A 0323;;;;N;;;;1E93; +1E93;LATIN SMALL LETTER Z WITH DOT BELOW;Ll;0;L;007A 0323;;;;N;;;1E92;;1E92 +1E94;LATIN CAPITAL LETTER Z WITH LINE BELOW;Lu;0;L;005A 0331;;;;N;;;;1E95; +1E95;LATIN SMALL LETTER Z WITH LINE BELOW;Ll;0;L;007A 0331;;;;N;;;1E94;;1E94 +1E96;LATIN SMALL LETTER H WITH LINE BELOW;Ll;0;L;0068 0331;;;;N;;;;; +1E97;LATIN SMALL LETTER T WITH DIAERESIS;Ll;0;L;0074 0308;;;;N;;;;; +1E98;LATIN SMALL LETTER W WITH RING ABOVE;Ll;0;L;0077 030A;;;;N;;;;; +1E99;LATIN SMALL LETTER Y WITH RING ABOVE;Ll;0;L;0079 030A;;;;N;;;;; +1E9A;LATIN SMALL LETTER A WITH RIGHT HALF RING;Ll;0;L; 0061 02BE;;;;N;;;;; +1E9B;LATIN SMALL LETTER LONG S WITH DOT ABOVE;Ll;0;L;017F 0307;;;;N;;;1E60;;1E60 +1E9C;LATIN SMALL LETTER LONG S WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;;; +1E9D;LATIN SMALL LETTER LONG S WITH HIGH STROKE;Ll;0;L;;;;;N;;;;; +1E9E;LATIN CAPITAL LETTER SHARP S;Lu;0;L;;;;;N;;;;00DF; +1E9F;LATIN SMALL LETTER DELTA;Ll;0;L;;;;;N;;;;; +1EA0;LATIN CAPITAL LETTER A WITH DOT BELOW;Lu;0;L;0041 0323;;;;N;;;;1EA1; +1EA1;LATIN SMALL LETTER A WITH DOT BELOW;Ll;0;L;0061 0323;;;;N;;;1EA0;;1EA0 +1EA2;LATIN CAPITAL LETTER A WITH HOOK ABOVE;Lu;0;L;0041 0309;;;;N;;;;1EA3; +1EA3;LATIN SMALL LETTER A WITH HOOK ABOVE;Ll;0;L;0061 0309;;;;N;;;1EA2;;1EA2 +1EA4;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00C2 0301;;;;N;;;;1EA5; +1EA5;LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00E2 0301;;;;N;;;1EA4;;1EA4 +1EA6;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00C2 0300;;;;N;;;;1EA7; +1EA7;LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00E2 0300;;;;N;;;1EA6;;1EA6 +1EA8;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00C2 0309;;;;N;;;;1EA9; +1EA9;LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00E2 0309;;;;N;;;1EA8;;1EA8 +1EAA;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE;Lu;0;L;00C2 0303;;;;N;;;;1EAB; +1EAB;LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE;Ll;0;L;00E2 0303;;;;N;;;1EAA;;1EAA +1EAC;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EA0 0302;;;;N;;;;1EAD; +1EAD;LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EA1 0302;;;;N;;;1EAC;;1EAC +1EAE;LATIN CAPITAL LETTER A WITH BREVE AND ACUTE;Lu;0;L;0102 0301;;;;N;;;;1EAF; +1EAF;LATIN SMALL LETTER A WITH BREVE AND ACUTE;Ll;0;L;0103 0301;;;;N;;;1EAE;;1EAE +1EB0;LATIN CAPITAL LETTER A WITH BREVE AND GRAVE;Lu;0;L;0102 0300;;;;N;;;;1EB1; +1EB1;LATIN SMALL LETTER A WITH BREVE AND GRAVE;Ll;0;L;0103 0300;;;;N;;;1EB0;;1EB0 +1EB2;LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE;Lu;0;L;0102 0309;;;;N;;;;1EB3; +1EB3;LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE;Ll;0;L;0103 0309;;;;N;;;1EB2;;1EB2 +1EB4;LATIN CAPITAL LETTER A WITH BREVE AND TILDE;Lu;0;L;0102 0303;;;;N;;;;1EB5; +1EB5;LATIN SMALL LETTER A WITH BREVE AND TILDE;Ll;0;L;0103 0303;;;;N;;;1EB4;;1EB4 +1EB6;LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW;Lu;0;L;1EA0 0306;;;;N;;;;1EB7; +1EB7;LATIN SMALL LETTER A WITH BREVE AND DOT BELOW;Ll;0;L;1EA1 0306;;;;N;;;1EB6;;1EB6 +1EB8;LATIN CAPITAL LETTER E WITH DOT BELOW;Lu;0;L;0045 0323;;;;N;;;;1EB9; +1EB9;LATIN SMALL LETTER E WITH DOT BELOW;Ll;0;L;0065 0323;;;;N;;;1EB8;;1EB8 +1EBA;LATIN CAPITAL LETTER E WITH HOOK ABOVE;Lu;0;L;0045 0309;;;;N;;;;1EBB; +1EBB;LATIN SMALL LETTER E WITH HOOK ABOVE;Ll;0;L;0065 0309;;;;N;;;1EBA;;1EBA +1EBC;LATIN CAPITAL LETTER E WITH TILDE;Lu;0;L;0045 0303;;;;N;;;;1EBD; +1EBD;LATIN SMALL LETTER E WITH TILDE;Ll;0;L;0065 0303;;;;N;;;1EBC;;1EBC +1EBE;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00CA 0301;;;;N;;;;1EBF; +1EBF;LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00EA 0301;;;;N;;;1EBE;;1EBE +1EC0;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00CA 0300;;;;N;;;;1EC1; +1EC1;LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00EA 0300;;;;N;;;1EC0;;1EC0 +1EC2;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00CA 0309;;;;N;;;;1EC3; +1EC3;LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00EA 0309;;;;N;;;1EC2;;1EC2 +1EC4;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE;Lu;0;L;00CA 0303;;;;N;;;;1EC5; +1EC5;LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE;Ll;0;L;00EA 0303;;;;N;;;1EC4;;1EC4 +1EC6;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EB8 0302;;;;N;;;;1EC7; +1EC7;LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EB9 0302;;;;N;;;1EC6;;1EC6 +1EC8;LATIN CAPITAL LETTER I WITH HOOK ABOVE;Lu;0;L;0049 0309;;;;N;;;;1EC9; +1EC9;LATIN SMALL LETTER I WITH HOOK ABOVE;Ll;0;L;0069 0309;;;;N;;;1EC8;;1EC8 +1ECA;LATIN CAPITAL LETTER I WITH DOT BELOW;Lu;0;L;0049 0323;;;;N;;;;1ECB; +1ECB;LATIN SMALL LETTER I WITH DOT BELOW;Ll;0;L;0069 0323;;;;N;;;1ECA;;1ECA +1ECC;LATIN CAPITAL LETTER O WITH DOT BELOW;Lu;0;L;004F 0323;;;;N;;;;1ECD; +1ECD;LATIN SMALL LETTER O WITH DOT BELOW;Ll;0;L;006F 0323;;;;N;;;1ECC;;1ECC +1ECE;LATIN CAPITAL LETTER O WITH HOOK ABOVE;Lu;0;L;004F 0309;;;;N;;;;1ECF; +1ECF;LATIN SMALL LETTER O WITH HOOK ABOVE;Ll;0;L;006F 0309;;;;N;;;1ECE;;1ECE +1ED0;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00D4 0301;;;;N;;;;1ED1; +1ED1;LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00F4 0301;;;;N;;;1ED0;;1ED0 +1ED2;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00D4 0300;;;;N;;;;1ED3; +1ED3;LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00F4 0300;;;;N;;;1ED2;;1ED2 +1ED4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00D4 0309;;;;N;;;;1ED5; +1ED5;LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00F4 0309;;;;N;;;1ED4;;1ED4 +1ED6;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE;Lu;0;L;00D4 0303;;;;N;;;;1ED7; +1ED7;LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE;Ll;0;L;00F4 0303;;;;N;;;1ED6;;1ED6 +1ED8;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1ECC 0302;;;;N;;;;1ED9; +1ED9;LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1ECD 0302;;;;N;;;1ED8;;1ED8 +1EDA;LATIN CAPITAL LETTER O WITH HORN AND ACUTE;Lu;0;L;01A0 0301;;;;N;;;;1EDB; +1EDB;LATIN SMALL LETTER O WITH HORN AND ACUTE;Ll;0;L;01A1 0301;;;;N;;;1EDA;;1EDA +1EDC;LATIN CAPITAL LETTER O WITH HORN AND GRAVE;Lu;0;L;01A0 0300;;;;N;;;;1EDD; +1EDD;LATIN SMALL LETTER O WITH HORN AND GRAVE;Ll;0;L;01A1 0300;;;;N;;;1EDC;;1EDC +1EDE;LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE;Lu;0;L;01A0 0309;;;;N;;;;1EDF; +1EDF;LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE;Ll;0;L;01A1 0309;;;;N;;;1EDE;;1EDE +1EE0;LATIN CAPITAL LETTER O WITH HORN AND TILDE;Lu;0;L;01A0 0303;;;;N;;;;1EE1; +1EE1;LATIN SMALL LETTER O WITH HORN AND TILDE;Ll;0;L;01A1 0303;;;;N;;;1EE0;;1EE0 +1EE2;LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW;Lu;0;L;01A0 0323;;;;N;;;;1EE3; +1EE3;LATIN SMALL LETTER O WITH HORN AND DOT BELOW;Ll;0;L;01A1 0323;;;;N;;;1EE2;;1EE2 +1EE4;LATIN CAPITAL LETTER U WITH DOT BELOW;Lu;0;L;0055 0323;;;;N;;;;1EE5; +1EE5;LATIN SMALL LETTER U WITH DOT BELOW;Ll;0;L;0075 0323;;;;N;;;1EE4;;1EE4 +1EE6;LATIN CAPITAL LETTER U WITH HOOK ABOVE;Lu;0;L;0055 0309;;;;N;;;;1EE7; +1EE7;LATIN SMALL LETTER U WITH HOOK ABOVE;Ll;0;L;0075 0309;;;;N;;;1EE6;;1EE6 +1EE8;LATIN CAPITAL LETTER U WITH HORN AND ACUTE;Lu;0;L;01AF 0301;;;;N;;;;1EE9; +1EE9;LATIN SMALL LETTER U WITH HORN AND ACUTE;Ll;0;L;01B0 0301;;;;N;;;1EE8;;1EE8 +1EEA;LATIN CAPITAL LETTER U WITH HORN AND GRAVE;Lu;0;L;01AF 0300;;;;N;;;;1EEB; +1EEB;LATIN SMALL LETTER U WITH HORN AND GRAVE;Ll;0;L;01B0 0300;;;;N;;;1EEA;;1EEA +1EEC;LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE;Lu;0;L;01AF 0309;;;;N;;;;1EED; +1EED;LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE;Ll;0;L;01B0 0309;;;;N;;;1EEC;;1EEC +1EEE;LATIN CAPITAL LETTER U WITH HORN AND TILDE;Lu;0;L;01AF 0303;;;;N;;;;1EEF; +1EEF;LATIN SMALL LETTER U WITH HORN AND TILDE;Ll;0;L;01B0 0303;;;;N;;;1EEE;;1EEE +1EF0;LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW;Lu;0;L;01AF 0323;;;;N;;;;1EF1; +1EF1;LATIN SMALL LETTER U WITH HORN AND DOT BELOW;Ll;0;L;01B0 0323;;;;N;;;1EF0;;1EF0 +1EF2;LATIN CAPITAL LETTER Y WITH GRAVE;Lu;0;L;0059 0300;;;;N;;;;1EF3; +1EF3;LATIN SMALL LETTER Y WITH GRAVE;Ll;0;L;0079 0300;;;;N;;;1EF2;;1EF2 +1EF4;LATIN CAPITAL LETTER Y WITH DOT BELOW;Lu;0;L;0059 0323;;;;N;;;;1EF5; +1EF5;LATIN SMALL LETTER Y WITH DOT BELOW;Ll;0;L;0079 0323;;;;N;;;1EF4;;1EF4 +1EF6;LATIN CAPITAL LETTER Y WITH HOOK ABOVE;Lu;0;L;0059 0309;;;;N;;;;1EF7; +1EF7;LATIN SMALL LETTER Y WITH HOOK ABOVE;Ll;0;L;0079 0309;;;;N;;;1EF6;;1EF6 +1EF8;LATIN CAPITAL LETTER Y WITH TILDE;Lu;0;L;0059 0303;;;;N;;;;1EF9; +1EF9;LATIN SMALL LETTER Y WITH TILDE;Ll;0;L;0079 0303;;;;N;;;1EF8;;1EF8 +1EFA;LATIN CAPITAL LETTER MIDDLE-WELSH LL;Lu;0;L;;;;;N;;;;1EFB; +1EFB;LATIN SMALL LETTER MIDDLE-WELSH LL;Ll;0;L;;;;;N;;;1EFA;;1EFA +1EFC;LATIN CAPITAL LETTER MIDDLE-WELSH V;Lu;0;L;;;;;N;;;;1EFD; +1EFD;LATIN SMALL LETTER MIDDLE-WELSH V;Ll;0;L;;;;;N;;;1EFC;;1EFC +1EFE;LATIN CAPITAL LETTER Y WITH LOOP;Lu;0;L;;;;;N;;;;1EFF; +1EFF;LATIN SMALL LETTER Y WITH LOOP;Ll;0;L;;;;;N;;;1EFE;;1EFE +1F00;GREEK SMALL LETTER ALPHA WITH PSILI;Ll;0;L;03B1 0313;;;;N;;;1F08;;1F08 +1F01;GREEK SMALL LETTER ALPHA WITH DASIA;Ll;0;L;03B1 0314;;;;N;;;1F09;;1F09 +1F02;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA;Ll;0;L;1F00 0300;;;;N;;;1F0A;;1F0A +1F03;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA;Ll;0;L;1F01 0300;;;;N;;;1F0B;;1F0B +1F04;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA;Ll;0;L;1F00 0301;;;;N;;;1F0C;;1F0C +1F05;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA;Ll;0;L;1F01 0301;;;;N;;;1F0D;;1F0D +1F06;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI;Ll;0;L;1F00 0342;;;;N;;;1F0E;;1F0E +1F07;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI;Ll;0;L;1F01 0342;;;;N;;;1F0F;;1F0F +1F08;GREEK CAPITAL LETTER ALPHA WITH PSILI;Lu;0;L;0391 0313;;;;N;;;;1F00; +1F09;GREEK CAPITAL LETTER ALPHA WITH DASIA;Lu;0;L;0391 0314;;;;N;;;;1F01; +1F0A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA;Lu;0;L;1F08 0300;;;;N;;;;1F02; +1F0B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA;Lu;0;L;1F09 0300;;;;N;;;;1F03; +1F0C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA;Lu;0;L;1F08 0301;;;;N;;;;1F04; +1F0D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA;Lu;0;L;1F09 0301;;;;N;;;;1F05; +1F0E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI;Lu;0;L;1F08 0342;;;;N;;;;1F06; +1F0F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI;Lu;0;L;1F09 0342;;;;N;;;;1F07; +1F10;GREEK SMALL LETTER EPSILON WITH PSILI;Ll;0;L;03B5 0313;;;;N;;;1F18;;1F18 +1F11;GREEK SMALL LETTER EPSILON WITH DASIA;Ll;0;L;03B5 0314;;;;N;;;1F19;;1F19 +1F12;GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA;Ll;0;L;1F10 0300;;;;N;;;1F1A;;1F1A +1F13;GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA;Ll;0;L;1F11 0300;;;;N;;;1F1B;;1F1B +1F14;GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA;Ll;0;L;1F10 0301;;;;N;;;1F1C;;1F1C +1F15;GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA;Ll;0;L;1F11 0301;;;;N;;;1F1D;;1F1D +1F18;GREEK CAPITAL LETTER EPSILON WITH PSILI;Lu;0;L;0395 0313;;;;N;;;;1F10; +1F19;GREEK CAPITAL LETTER EPSILON WITH DASIA;Lu;0;L;0395 0314;;;;N;;;;1F11; +1F1A;GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA;Lu;0;L;1F18 0300;;;;N;;;;1F12; +1F1B;GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA;Lu;0;L;1F19 0300;;;;N;;;;1F13; +1F1C;GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA;Lu;0;L;1F18 0301;;;;N;;;;1F14; +1F1D;GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA;Lu;0;L;1F19 0301;;;;N;;;;1F15; +1F20;GREEK SMALL LETTER ETA WITH PSILI;Ll;0;L;03B7 0313;;;;N;;;1F28;;1F28 +1F21;GREEK SMALL LETTER ETA WITH DASIA;Ll;0;L;03B7 0314;;;;N;;;1F29;;1F29 +1F22;GREEK SMALL LETTER ETA WITH PSILI AND VARIA;Ll;0;L;1F20 0300;;;;N;;;1F2A;;1F2A +1F23;GREEK SMALL LETTER ETA WITH DASIA AND VARIA;Ll;0;L;1F21 0300;;;;N;;;1F2B;;1F2B +1F24;GREEK SMALL LETTER ETA WITH PSILI AND OXIA;Ll;0;L;1F20 0301;;;;N;;;1F2C;;1F2C +1F25;GREEK SMALL LETTER ETA WITH DASIA AND OXIA;Ll;0;L;1F21 0301;;;;N;;;1F2D;;1F2D +1F26;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI;Ll;0;L;1F20 0342;;;;N;;;1F2E;;1F2E +1F27;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI;Ll;0;L;1F21 0342;;;;N;;;1F2F;;1F2F +1F28;GREEK CAPITAL LETTER ETA WITH PSILI;Lu;0;L;0397 0313;;;;N;;;;1F20; +1F29;GREEK CAPITAL LETTER ETA WITH DASIA;Lu;0;L;0397 0314;;;;N;;;;1F21; +1F2A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA;Lu;0;L;1F28 0300;;;;N;;;;1F22; +1F2B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA;Lu;0;L;1F29 0300;;;;N;;;;1F23; +1F2C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA;Lu;0;L;1F28 0301;;;;N;;;;1F24; +1F2D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA;Lu;0;L;1F29 0301;;;;N;;;;1F25; +1F2E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI;Lu;0;L;1F28 0342;;;;N;;;;1F26; +1F2F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI;Lu;0;L;1F29 0342;;;;N;;;;1F27; +1F30;GREEK SMALL LETTER IOTA WITH PSILI;Ll;0;L;03B9 0313;;;;N;;;1F38;;1F38 +1F31;GREEK SMALL LETTER IOTA WITH DASIA;Ll;0;L;03B9 0314;;;;N;;;1F39;;1F39 +1F32;GREEK SMALL LETTER IOTA WITH PSILI AND VARIA;Ll;0;L;1F30 0300;;;;N;;;1F3A;;1F3A +1F33;GREEK SMALL LETTER IOTA WITH DASIA AND VARIA;Ll;0;L;1F31 0300;;;;N;;;1F3B;;1F3B +1F34;GREEK SMALL LETTER IOTA WITH PSILI AND OXIA;Ll;0;L;1F30 0301;;;;N;;;1F3C;;1F3C +1F35;GREEK SMALL LETTER IOTA WITH DASIA AND OXIA;Ll;0;L;1F31 0301;;;;N;;;1F3D;;1F3D +1F36;GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI;Ll;0;L;1F30 0342;;;;N;;;1F3E;;1F3E +1F37;GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI;Ll;0;L;1F31 0342;;;;N;;;1F3F;;1F3F +1F38;GREEK CAPITAL LETTER IOTA WITH PSILI;Lu;0;L;0399 0313;;;;N;;;;1F30; +1F39;GREEK CAPITAL LETTER IOTA WITH DASIA;Lu;0;L;0399 0314;;;;N;;;;1F31; +1F3A;GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA;Lu;0;L;1F38 0300;;;;N;;;;1F32; +1F3B;GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA;Lu;0;L;1F39 0300;;;;N;;;;1F33; +1F3C;GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA;Lu;0;L;1F38 0301;;;;N;;;;1F34; +1F3D;GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA;Lu;0;L;1F39 0301;;;;N;;;;1F35; +1F3E;GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI;Lu;0;L;1F38 0342;;;;N;;;;1F36; +1F3F;GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI;Lu;0;L;1F39 0342;;;;N;;;;1F37; +1F40;GREEK SMALL LETTER OMICRON WITH PSILI;Ll;0;L;03BF 0313;;;;N;;;1F48;;1F48 +1F41;GREEK SMALL LETTER OMICRON WITH DASIA;Ll;0;L;03BF 0314;;;;N;;;1F49;;1F49 +1F42;GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA;Ll;0;L;1F40 0300;;;;N;;;1F4A;;1F4A +1F43;GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA;Ll;0;L;1F41 0300;;;;N;;;1F4B;;1F4B +1F44;GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA;Ll;0;L;1F40 0301;;;;N;;;1F4C;;1F4C +1F45;GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA;Ll;0;L;1F41 0301;;;;N;;;1F4D;;1F4D +1F48;GREEK CAPITAL LETTER OMICRON WITH PSILI;Lu;0;L;039F 0313;;;;N;;;;1F40; +1F49;GREEK CAPITAL LETTER OMICRON WITH DASIA;Lu;0;L;039F 0314;;;;N;;;;1F41; +1F4A;GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA;Lu;0;L;1F48 0300;;;;N;;;;1F42; +1F4B;GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA;Lu;0;L;1F49 0300;;;;N;;;;1F43; +1F4C;GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA;Lu;0;L;1F48 0301;;;;N;;;;1F44; +1F4D;GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA;Lu;0;L;1F49 0301;;;;N;;;;1F45; +1F50;GREEK SMALL LETTER UPSILON WITH PSILI;Ll;0;L;03C5 0313;;;;N;;;;; +1F51;GREEK SMALL LETTER UPSILON WITH DASIA;Ll;0;L;03C5 0314;;;;N;;;1F59;;1F59 +1F52;GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA;Ll;0;L;1F50 0300;;;;N;;;;; +1F53;GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA;Ll;0;L;1F51 0300;;;;N;;;1F5B;;1F5B +1F54;GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA;Ll;0;L;1F50 0301;;;;N;;;;; +1F55;GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA;Ll;0;L;1F51 0301;;;;N;;;1F5D;;1F5D +1F56;GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI;Ll;0;L;1F50 0342;;;;N;;;;; +1F57;GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI;Ll;0;L;1F51 0342;;;;N;;;1F5F;;1F5F +1F59;GREEK CAPITAL LETTER UPSILON WITH DASIA;Lu;0;L;03A5 0314;;;;N;;;;1F51; +1F5B;GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA;Lu;0;L;1F59 0300;;;;N;;;;1F53; +1F5D;GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA;Lu;0;L;1F59 0301;;;;N;;;;1F55; +1F5F;GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI;Lu;0;L;1F59 0342;;;;N;;;;1F57; +1F60;GREEK SMALL LETTER OMEGA WITH PSILI;Ll;0;L;03C9 0313;;;;N;;;1F68;;1F68 +1F61;GREEK SMALL LETTER OMEGA WITH DASIA;Ll;0;L;03C9 0314;;;;N;;;1F69;;1F69 +1F62;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA;Ll;0;L;1F60 0300;;;;N;;;1F6A;;1F6A +1F63;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA;Ll;0;L;1F61 0300;;;;N;;;1F6B;;1F6B +1F64;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA;Ll;0;L;1F60 0301;;;;N;;;1F6C;;1F6C +1F65;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA;Ll;0;L;1F61 0301;;;;N;;;1F6D;;1F6D +1F66;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI;Ll;0;L;1F60 0342;;;;N;;;1F6E;;1F6E +1F67;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI;Ll;0;L;1F61 0342;;;;N;;;1F6F;;1F6F +1F68;GREEK CAPITAL LETTER OMEGA WITH PSILI;Lu;0;L;03A9 0313;;;;N;;;;1F60; +1F69;GREEK CAPITAL LETTER OMEGA WITH DASIA;Lu;0;L;03A9 0314;;;;N;;;;1F61; +1F6A;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA;Lu;0;L;1F68 0300;;;;N;;;;1F62; +1F6B;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA;Lu;0;L;1F69 0300;;;;N;;;;1F63; +1F6C;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA;Lu;0;L;1F68 0301;;;;N;;;;1F64; +1F6D;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA;Lu;0;L;1F69 0301;;;;N;;;;1F65; +1F6E;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI;Lu;0;L;1F68 0342;;;;N;;;;1F66; +1F6F;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI;Lu;0;L;1F69 0342;;;;N;;;;1F67; +1F70;GREEK SMALL LETTER ALPHA WITH VARIA;Ll;0;L;03B1 0300;;;;N;;;1FBA;;1FBA +1F71;GREEK SMALL LETTER ALPHA WITH OXIA;Ll;0;L;03AC;;;;N;;;1FBB;;1FBB +1F72;GREEK SMALL LETTER EPSILON WITH VARIA;Ll;0;L;03B5 0300;;;;N;;;1FC8;;1FC8 +1F73;GREEK SMALL LETTER EPSILON WITH OXIA;Ll;0;L;03AD;;;;N;;;1FC9;;1FC9 +1F74;GREEK SMALL LETTER ETA WITH VARIA;Ll;0;L;03B7 0300;;;;N;;;1FCA;;1FCA +1F75;GREEK SMALL LETTER ETA WITH OXIA;Ll;0;L;03AE;;;;N;;;1FCB;;1FCB +1F76;GREEK SMALL LETTER IOTA WITH VARIA;Ll;0;L;03B9 0300;;;;N;;;1FDA;;1FDA +1F77;GREEK SMALL LETTER IOTA WITH OXIA;Ll;0;L;03AF;;;;N;;;1FDB;;1FDB +1F78;GREEK SMALL LETTER OMICRON WITH VARIA;Ll;0;L;03BF 0300;;;;N;;;1FF8;;1FF8 +1F79;GREEK SMALL LETTER OMICRON WITH OXIA;Ll;0;L;03CC;;;;N;;;1FF9;;1FF9 +1F7A;GREEK SMALL LETTER UPSILON WITH VARIA;Ll;0;L;03C5 0300;;;;N;;;1FEA;;1FEA +1F7B;GREEK SMALL LETTER UPSILON WITH OXIA;Ll;0;L;03CD;;;;N;;;1FEB;;1FEB +1F7C;GREEK SMALL LETTER OMEGA WITH VARIA;Ll;0;L;03C9 0300;;;;N;;;1FFA;;1FFA +1F7D;GREEK SMALL LETTER OMEGA WITH OXIA;Ll;0;L;03CE;;;;N;;;1FFB;;1FFB +1F80;GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F00 0345;;;;N;;;1F88;;1F88 +1F81;GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F01 0345;;;;N;;;1F89;;1F89 +1F82;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F02 0345;;;;N;;;1F8A;;1F8A +1F83;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F03 0345;;;;N;;;1F8B;;1F8B +1F84;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F04 0345;;;;N;;;1F8C;;1F8C +1F85;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F05 0345;;;;N;;;1F8D;;1F8D +1F86;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F06 0345;;;;N;;;1F8E;;1F8E +1F87;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F07 0345;;;;N;;;1F8F;;1F8F +1F88;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F08 0345;;;;N;;;;1F80; +1F89;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F09 0345;;;;N;;;;1F81; +1F8A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0A 0345;;;;N;;;;1F82; +1F8B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0B 0345;;;;N;;;;1F83; +1F8C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0C 0345;;;;N;;;;1F84; +1F8D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0D 0345;;;;N;;;;1F85; +1F8E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0E 0345;;;;N;;;;1F86; +1F8F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0F 0345;;;;N;;;;1F87; +1F90;GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F20 0345;;;;N;;;1F98;;1F98 +1F91;GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F21 0345;;;;N;;;1F99;;1F99 +1F92;GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F22 0345;;;;N;;;1F9A;;1F9A +1F93;GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F23 0345;;;;N;;;1F9B;;1F9B +1F94;GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F24 0345;;;;N;;;1F9C;;1F9C +1F95;GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F25 0345;;;;N;;;1F9D;;1F9D +1F96;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F26 0345;;;;N;;;1F9E;;1F9E +1F97;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F27 0345;;;;N;;;1F9F;;1F9F +1F98;GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F28 0345;;;;N;;;;1F90; +1F99;GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F29 0345;;;;N;;;;1F91; +1F9A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2A 0345;;;;N;;;;1F92; +1F9B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2B 0345;;;;N;;;;1F93; +1F9C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2C 0345;;;;N;;;;1F94; +1F9D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2D 0345;;;;N;;;;1F95; +1F9E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2E 0345;;;;N;;;;1F96; +1F9F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2F 0345;;;;N;;;;1F97; +1FA0;GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F60 0345;;;;N;;;1FA8;;1FA8 +1FA1;GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F61 0345;;;;N;;;1FA9;;1FA9 +1FA2;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F62 0345;;;;N;;;1FAA;;1FAA +1FA3;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F63 0345;;;;N;;;1FAB;;1FAB +1FA4;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F64 0345;;;;N;;;1FAC;;1FAC +1FA5;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F65 0345;;;;N;;;1FAD;;1FAD +1FA6;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F66 0345;;;;N;;;1FAE;;1FAE +1FA7;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F67 0345;;;;N;;;1FAF;;1FAF +1FA8;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F68 0345;;;;N;;;;1FA0; +1FA9;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F69 0345;;;;N;;;;1FA1; +1FAA;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6A 0345;;;;N;;;;1FA2; +1FAB;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6B 0345;;;;N;;;;1FA3; +1FAC;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6C 0345;;;;N;;;;1FA4; +1FAD;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6D 0345;;;;N;;;;1FA5; +1FAE;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6E 0345;;;;N;;;;1FA6; +1FAF;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6F 0345;;;;N;;;;1FA7; +1FB0;GREEK SMALL LETTER ALPHA WITH VRACHY;Ll;0;L;03B1 0306;;;;N;;;1FB8;;1FB8 +1FB1;GREEK SMALL LETTER ALPHA WITH MACRON;Ll;0;L;03B1 0304;;;;N;;;1FB9;;1FB9 +1FB2;GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F70 0345;;;;N;;;;; +1FB3;GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI;Ll;0;L;03B1 0345;;;;N;;;1FBC;;1FBC +1FB4;GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AC 0345;;;;N;;;;; +1FB6;GREEK SMALL LETTER ALPHA WITH PERISPOMENI;Ll;0;L;03B1 0342;;;;N;;;;; +1FB7;GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FB6 0345;;;;N;;;;; +1FB8;GREEK CAPITAL LETTER ALPHA WITH VRACHY;Lu;0;L;0391 0306;;;;N;;;;1FB0; +1FB9;GREEK CAPITAL LETTER ALPHA WITH MACRON;Lu;0;L;0391 0304;;;;N;;;;1FB1; +1FBA;GREEK CAPITAL LETTER ALPHA WITH VARIA;Lu;0;L;0391 0300;;;;N;;;;1F70; +1FBB;GREEK CAPITAL LETTER ALPHA WITH OXIA;Lu;0;L;0386;;;;N;;;;1F71; +1FBC;GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI;Lt;0;L;0391 0345;;;;N;;;;1FB3; +1FBD;GREEK KORONIS;Sk;0;ON; 0020 0313;;;;N;;;;; +1FBE;GREEK PROSGEGRAMMENI;Ll;0;L;03B9;;;;N;;;0399;;0399 +1FBF;GREEK PSILI;Sk;0;ON; 0020 0313;;;;N;;;;; +1FC0;GREEK PERISPOMENI;Sk;0;ON; 0020 0342;;;;N;;;;; +1FC1;GREEK DIALYTIKA AND PERISPOMENI;Sk;0;ON;00A8 0342;;;;N;;;;; +1FC2;GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F74 0345;;;;N;;;;; +1FC3;GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI;Ll;0;L;03B7 0345;;;;N;;;1FCC;;1FCC +1FC4;GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AE 0345;;;;N;;;;; +1FC6;GREEK SMALL LETTER ETA WITH PERISPOMENI;Ll;0;L;03B7 0342;;;;N;;;;; +1FC7;GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FC6 0345;;;;N;;;;; +1FC8;GREEK CAPITAL LETTER EPSILON WITH VARIA;Lu;0;L;0395 0300;;;;N;;;;1F72; +1FC9;GREEK CAPITAL LETTER EPSILON WITH OXIA;Lu;0;L;0388;;;;N;;;;1F73; +1FCA;GREEK CAPITAL LETTER ETA WITH VARIA;Lu;0;L;0397 0300;;;;N;;;;1F74; +1FCB;GREEK CAPITAL LETTER ETA WITH OXIA;Lu;0;L;0389;;;;N;;;;1F75; +1FCC;GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI;Lt;0;L;0397 0345;;;;N;;;;1FC3; +1FCD;GREEK PSILI AND VARIA;Sk;0;ON;1FBF 0300;;;;N;;;;; +1FCE;GREEK PSILI AND OXIA;Sk;0;ON;1FBF 0301;;;;N;;;;; +1FCF;GREEK PSILI AND PERISPOMENI;Sk;0;ON;1FBF 0342;;;;N;;;;; +1FD0;GREEK SMALL LETTER IOTA WITH VRACHY;Ll;0;L;03B9 0306;;;;N;;;1FD8;;1FD8 +1FD1;GREEK SMALL LETTER IOTA WITH MACRON;Ll;0;L;03B9 0304;;;;N;;;1FD9;;1FD9 +1FD2;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA;Ll;0;L;03CA 0300;;;;N;;;;; +1FD3;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA;Ll;0;L;0390;;;;N;;;;; +1FD6;GREEK SMALL LETTER IOTA WITH PERISPOMENI;Ll;0;L;03B9 0342;;;;N;;;;; +1FD7;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CA 0342;;;;N;;;;; +1FD8;GREEK CAPITAL LETTER IOTA WITH VRACHY;Lu;0;L;0399 0306;;;;N;;;;1FD0; +1FD9;GREEK CAPITAL LETTER IOTA WITH MACRON;Lu;0;L;0399 0304;;;;N;;;;1FD1; +1FDA;GREEK CAPITAL LETTER IOTA WITH VARIA;Lu;0;L;0399 0300;;;;N;;;;1F76; +1FDB;GREEK CAPITAL LETTER IOTA WITH OXIA;Lu;0;L;038A;;;;N;;;;1F77; +1FDD;GREEK DASIA AND VARIA;Sk;0;ON;1FFE 0300;;;;N;;;;; +1FDE;GREEK DASIA AND OXIA;Sk;0;ON;1FFE 0301;;;;N;;;;; +1FDF;GREEK DASIA AND PERISPOMENI;Sk;0;ON;1FFE 0342;;;;N;;;;; +1FE0;GREEK SMALL LETTER UPSILON WITH VRACHY;Ll;0;L;03C5 0306;;;;N;;;1FE8;;1FE8 +1FE1;GREEK SMALL LETTER UPSILON WITH MACRON;Ll;0;L;03C5 0304;;;;N;;;1FE9;;1FE9 +1FE2;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA;Ll;0;L;03CB 0300;;;;N;;;;; +1FE3;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA;Ll;0;L;03B0;;;;N;;;;; +1FE4;GREEK SMALL LETTER RHO WITH PSILI;Ll;0;L;03C1 0313;;;;N;;;;; +1FE5;GREEK SMALL LETTER RHO WITH DASIA;Ll;0;L;03C1 0314;;;;N;;;1FEC;;1FEC +1FE6;GREEK SMALL LETTER UPSILON WITH PERISPOMENI;Ll;0;L;03C5 0342;;;;N;;;;; +1FE7;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CB 0342;;;;N;;;;; +1FE8;GREEK CAPITAL LETTER UPSILON WITH VRACHY;Lu;0;L;03A5 0306;;;;N;;;;1FE0; +1FE9;GREEK CAPITAL LETTER UPSILON WITH MACRON;Lu;0;L;03A5 0304;;;;N;;;;1FE1; +1FEA;GREEK CAPITAL LETTER UPSILON WITH VARIA;Lu;0;L;03A5 0300;;;;N;;;;1F7A; +1FEB;GREEK CAPITAL LETTER UPSILON WITH OXIA;Lu;0;L;038E;;;;N;;;;1F7B; +1FEC;GREEK CAPITAL LETTER RHO WITH DASIA;Lu;0;L;03A1 0314;;;;N;;;;1FE5; +1FED;GREEK DIALYTIKA AND VARIA;Sk;0;ON;00A8 0300;;;;N;;;;; +1FEE;GREEK DIALYTIKA AND OXIA;Sk;0;ON;0385;;;;N;;;;; +1FEF;GREEK VARIA;Sk;0;ON;0060;;;;N;;;;; +1FF2;GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F7C 0345;;;;N;;;;; +1FF3;GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI;Ll;0;L;03C9 0345;;;;N;;;1FFC;;1FFC +1FF4;GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03CE 0345;;;;N;;;;; +1FF6;GREEK SMALL LETTER OMEGA WITH PERISPOMENI;Ll;0;L;03C9 0342;;;;N;;;;; +1FF7;GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FF6 0345;;;;N;;;;; +1FF8;GREEK CAPITAL LETTER OMICRON WITH VARIA;Lu;0;L;039F 0300;;;;N;;;;1F78; +1FF9;GREEK CAPITAL LETTER OMICRON WITH OXIA;Lu;0;L;038C;;;;N;;;;1F79; +1FFA;GREEK CAPITAL LETTER OMEGA WITH VARIA;Lu;0;L;03A9 0300;;;;N;;;;1F7C; +1FFB;GREEK CAPITAL LETTER OMEGA WITH OXIA;Lu;0;L;038F;;;;N;;;;1F7D; +1FFC;GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI;Lt;0;L;03A9 0345;;;;N;;;;1FF3; +1FFD;GREEK OXIA;Sk;0;ON;00B4;;;;N;;;;; +1FFE;GREEK DASIA;Sk;0;ON; 0020 0314;;;;N;;;;; +2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;; +2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;; +2002;EN SPACE;Zs;0;WS; 0020;;;;N;;;;; +2003;EM SPACE;Zs;0;WS; 0020;;;;N;;;;; +2004;THREE-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; +2005;FOUR-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; +2006;SIX-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; +2007;FIGURE SPACE;Zs;0;WS; 0020;;;;N;;;;; +2008;PUNCTUATION SPACE;Zs;0;WS; 0020;;;;N;;;;; +2009;THIN SPACE;Zs;0;WS; 0020;;;;N;;;;; +200A;HAIR SPACE;Zs;0;WS; 0020;;;;N;;;;; +200B;ZERO WIDTH SPACE;Cf;0;BN;;;;;N;;;;; +200C;ZERO WIDTH NON-JOINER;Cf;0;BN;;;;;N;;;;; +200D;ZERO WIDTH JOINER;Cf;0;BN;;;;;N;;;;; +200E;LEFT-TO-RIGHT MARK;Cf;0;L;;;;;N;;;;; +200F;RIGHT-TO-LEFT MARK;Cf;0;R;;;;;N;;;;; +2010;HYPHEN;Pd;0;ON;;;;;N;;;;; +2011;NON-BREAKING HYPHEN;Pd;0;ON; 2010;;;;N;;;;; +2012;FIGURE DASH;Pd;0;ON;;;;;N;;;;; +2013;EN DASH;Pd;0;ON;;;;;N;;;;; +2014;EM DASH;Pd;0;ON;;;;;N;;;;; +2015;HORIZONTAL BAR;Pd;0;ON;;;;;N;QUOTATION DASH;;;; +2016;DOUBLE VERTICAL LINE;Po;0;ON;;;;;N;DOUBLE VERTICAL BAR;;;; +2017;DOUBLE LOW LINE;Po;0;ON; 0020 0333;;;;N;SPACING DOUBLE UNDERSCORE;;;; +2018;LEFT SINGLE QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE TURNED COMMA QUOTATION MARK;;;; +2019;RIGHT SINGLE QUOTATION MARK;Pf;0;ON;;;;;N;SINGLE COMMA QUOTATION MARK;;;; +201A;SINGLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW SINGLE COMMA QUOTATION MARK;;;; +201B;SINGLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE REVERSED COMMA QUOTATION MARK;;;; +201C;LEFT DOUBLE QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE TURNED COMMA QUOTATION MARK;;;; +201D;RIGHT DOUBLE QUOTATION MARK;Pf;0;ON;;;;;N;DOUBLE COMMA QUOTATION MARK;;;; +201E;DOUBLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW DOUBLE COMMA QUOTATION MARK;;;; +201F;DOUBLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE REVERSED COMMA QUOTATION MARK;;;; +2020;DAGGER;Po;0;ON;;;;;N;;;;; +2021;DOUBLE DAGGER;Po;0;ON;;;;;N;;;;; +2022;BULLET;Po;0;ON;;;;;N;;;;; +2023;TRIANGULAR BULLET;Po;0;ON;;;;;N;;;;; +2024;ONE DOT LEADER;Po;0;ON; 002E;;;;N;;;;; +2025;TWO DOT LEADER;Po;0;ON; 002E 002E;;;;N;;;;; +2026;HORIZONTAL ELLIPSIS;Po;0;ON; 002E 002E 002E;;;;N;;;;; +2027;HYPHENATION POINT;Po;0;ON;;;;;N;;;;; +2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; +2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; +202A;LEFT-TO-RIGHT EMBEDDING;Cf;0;LRE;;;;;N;;;;; +202B;RIGHT-TO-LEFT EMBEDDING;Cf;0;RLE;;;;;N;;;;; +202C;POP DIRECTIONAL FORMATTING;Cf;0;PDF;;;;;N;;;;; +202D;LEFT-TO-RIGHT OVERRIDE;Cf;0;LRO;;;;;N;;;;; +202E;RIGHT-TO-LEFT OVERRIDE;Cf;0;RLO;;;;;N;;;;; +202F;NARROW NO-BREAK SPACE;Zs;0;CS; 0020;;;;N;;;;; +2030;PER MILLE SIGN;Po;0;ET;;;;;N;;;;; +2031;PER TEN THOUSAND SIGN;Po;0;ET;;;;;N;;;;; +2032;PRIME;Po;0;ET;;;;;N;;;;; +2033;DOUBLE PRIME;Po;0;ET; 2032 2032;;;;N;;;;; +2034;TRIPLE PRIME;Po;0;ET; 2032 2032 2032;;;;N;;;;; +2035;REVERSED PRIME;Po;0;ON;;;;;N;;;;; +2036;REVERSED DOUBLE PRIME;Po;0;ON; 2035 2035;;;;N;;;;; +2037;REVERSED TRIPLE PRIME;Po;0;ON; 2035 2035 2035;;;;N;;;;; +2038;CARET;Po;0;ON;;;;;N;;;;; +2039;SINGLE LEFT-POINTING ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING SINGLE GUILLEMET;;;; +203A;SINGLE RIGHT-POINTING ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING SINGLE GUILLEMET;;;; +203B;REFERENCE MARK;Po;0;ON;;;;;N;;;;; +203C;DOUBLE EXCLAMATION MARK;Po;0;ON; 0021 0021;;;;N;;;;; +203D;INTERROBANG;Po;0;ON;;;;;N;;;;; +203E;OVERLINE;Po;0;ON; 0020 0305;;;;N;SPACING OVERSCORE;;;; +203F;UNDERTIE;Pc;0;ON;;;;;N;;;;; +2040;CHARACTER TIE;Pc;0;ON;;;;;N;;;;; +2041;CARET INSERTION POINT;Po;0;ON;;;;;N;;;;; +2042;ASTERISM;Po;0;ON;;;;;N;;;;; +2043;HYPHEN BULLET;Po;0;ON;;;;;N;;;;; +2044;FRACTION SLASH;Sm;0;CS;;;;;N;;;;; +2045;LEFT SQUARE BRACKET WITH QUILL;Ps;0;ON;;;;;Y;;;;; +2046;RIGHT SQUARE BRACKET WITH QUILL;Pe;0;ON;;;;;Y;;;;; +2047;DOUBLE QUESTION MARK;Po;0;ON; 003F 003F;;;;N;;;;; +2048;QUESTION EXCLAMATION MARK;Po;0;ON; 003F 0021;;;;N;;;;; +2049;EXCLAMATION QUESTION MARK;Po;0;ON; 0021 003F;;;;N;;;;; +204A;TIRONIAN SIGN ET;Po;0;ON;;;;;N;;;;; +204B;REVERSED PILCROW SIGN;Po;0;ON;;;;;N;;;;; +204C;BLACK LEFTWARDS BULLET;Po;0;ON;;;;;N;;;;; +204D;BLACK RIGHTWARDS BULLET;Po;0;ON;;;;;N;;;;; +204E;LOW ASTERISK;Po;0;ON;;;;;N;;;;; +204F;REVERSED SEMICOLON;Po;0;ON;;;;;N;;;;; +2050;CLOSE UP;Po;0;ON;;;;;N;;;;; +2051;TWO ASTERISKS ALIGNED VERTICALLY;Po;0;ON;;;;;N;;;;; +2052;COMMERCIAL MINUS SIGN;Sm;0;ON;;;;;N;;;;; +2053;SWUNG DASH;Po;0;ON;;;;;N;;;;; +2054;INVERTED UNDERTIE;Pc;0;ON;;;;;N;;;;; +2055;FLOWER PUNCTUATION MARK;Po;0;ON;;;;;N;;;;; +2056;THREE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; +2057;QUADRUPLE PRIME;Po;0;ON; 2032 2032 2032 2032;;;;N;;;;; +2058;FOUR DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; +2059;FIVE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; +205A;TWO DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; +205B;FOUR DOT MARK;Po;0;ON;;;;;N;;;;; +205C;DOTTED CROSS;Po;0;ON;;;;;N;;;;; +205D;TRICOLON;Po;0;ON;;;;;N;;;;; +205E;VERTICAL FOUR DOTS;Po;0;ON;;;;;N;;;;; +205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS; 0020;;;;N;;;;; +2060;WORD JOINER;Cf;0;BN;;;;;N;;;;; +2061;FUNCTION APPLICATION;Cf;0;BN;;;;;N;;;;; +2062;INVISIBLE TIMES;Cf;0;BN;;;;;N;;;;; +2063;INVISIBLE SEPARATOR;Cf;0;BN;;;;;N;;;;; +2064;INVISIBLE PLUS;Cf;0;BN;;;;;N;;;;; +2066;LEFT-TO-RIGHT ISOLATE;Cf;0;LRI;;;;;N;;;;; +2067;RIGHT-TO-LEFT ISOLATE;Cf;0;RLI;;;;;N;;;;; +2068;FIRST STRONG ISOLATE;Cf;0;FSI;;;;;N;;;;; +2069;POP DIRECTIONAL ISOLATE;Cf;0;PDI;;;;;N;;;;; +206A;INHIBIT SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;; +206B;ACTIVATE SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;; +206C;INHIBIT ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;; +206D;ACTIVATE ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;; +206E;NATIONAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;; +206F;NOMINAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;; +2070;SUPERSCRIPT ZERO;No;0;EN; 0030;;0;0;N;SUPERSCRIPT DIGIT ZERO;;;; +2071;SUPERSCRIPT LATIN SMALL LETTER I;Lm;0;L; 0069;;;;N;;;;; +2074;SUPERSCRIPT FOUR;No;0;EN; 0034;;4;4;N;SUPERSCRIPT DIGIT FOUR;;;; +2075;SUPERSCRIPT FIVE;No;0;EN; 0035;;5;5;N;SUPERSCRIPT DIGIT FIVE;;;; +2076;SUPERSCRIPT SIX;No;0;EN; 0036;;6;6;N;SUPERSCRIPT DIGIT SIX;;;; +2077;SUPERSCRIPT SEVEN;No;0;EN; 0037;;7;7;N;SUPERSCRIPT DIGIT SEVEN;;;; +2078;SUPERSCRIPT EIGHT;No;0;EN; 0038;;8;8;N;SUPERSCRIPT DIGIT EIGHT;;;; +2079;SUPERSCRIPT NINE;No;0;EN; 0039;;9;9;N;SUPERSCRIPT DIGIT NINE;;;; +207A;SUPERSCRIPT PLUS SIGN;Sm;0;ES; 002B;;;;N;;;;; +207B;SUPERSCRIPT MINUS;Sm;0;ES; 2212;;;;N;SUPERSCRIPT HYPHEN-MINUS;;;; +207C;SUPERSCRIPT EQUALS SIGN;Sm;0;ON; 003D;;;;N;;;;; +207D;SUPERSCRIPT LEFT PARENTHESIS;Ps;0;ON; 0028;;;;Y;SUPERSCRIPT OPENING PARENTHESIS;;;; +207E;SUPERSCRIPT RIGHT PARENTHESIS;Pe;0;ON; 0029;;;;Y;SUPERSCRIPT CLOSING PARENTHESIS;;;; +207F;SUPERSCRIPT LATIN SMALL LETTER N;Lm;0;L; 006E;;;;N;;;;; +2080;SUBSCRIPT ZERO;No;0;EN; 0030;;0;0;N;SUBSCRIPT DIGIT ZERO;;;; +2081;SUBSCRIPT ONE;No;0;EN; 0031;;1;1;N;SUBSCRIPT DIGIT ONE;;;; +2082;SUBSCRIPT TWO;No;0;EN; 0032;;2;2;N;SUBSCRIPT DIGIT TWO;;;; +2083;SUBSCRIPT THREE;No;0;EN; 0033;;3;3;N;SUBSCRIPT DIGIT THREE;;;; +2084;SUBSCRIPT FOUR;No;0;EN; 0034;;4;4;N;SUBSCRIPT DIGIT FOUR;;;; +2085;SUBSCRIPT FIVE;No;0;EN; 0035;;5;5;N;SUBSCRIPT DIGIT FIVE;;;; +2086;SUBSCRIPT SIX;No;0;EN; 0036;;6;6;N;SUBSCRIPT DIGIT SIX;;;; +2087;SUBSCRIPT SEVEN;No;0;EN; 0037;;7;7;N;SUBSCRIPT DIGIT SEVEN;;;; +2088;SUBSCRIPT EIGHT;No;0;EN; 0038;;8;8;N;SUBSCRIPT DIGIT EIGHT;;;; +2089;SUBSCRIPT NINE;No;0;EN; 0039;;9;9;N;SUBSCRIPT DIGIT NINE;;;; +208A;SUBSCRIPT PLUS SIGN;Sm;0;ES; 002B;;;;N;;;;; +208B;SUBSCRIPT MINUS;Sm;0;ES; 2212;;;;N;SUBSCRIPT HYPHEN-MINUS;;;; +208C;SUBSCRIPT EQUALS SIGN;Sm;0;ON; 003D;;;;N;;;;; +208D;SUBSCRIPT LEFT PARENTHESIS;Ps;0;ON; 0028;;;;Y;SUBSCRIPT OPENING PARENTHESIS;;;; +208E;SUBSCRIPT RIGHT PARENTHESIS;Pe;0;ON; 0029;;;;Y;SUBSCRIPT CLOSING PARENTHESIS;;;; +2090;LATIN SUBSCRIPT SMALL LETTER A;Lm;0;L; 0061;;;;N;;;;; +2091;LATIN SUBSCRIPT SMALL LETTER E;Lm;0;L; 0065;;;;N;;;;; +2092;LATIN SUBSCRIPT SMALL LETTER O;Lm;0;L; 006F;;;;N;;;;; +2093;LATIN SUBSCRIPT SMALL LETTER X;Lm;0;L; 0078;;;;N;;;;; +2094;LATIN SUBSCRIPT SMALL LETTER SCHWA;Lm;0;L; 0259;;;;N;;;;; +2095;LATIN SUBSCRIPT SMALL LETTER H;Lm;0;L; 0068;;;;N;;;;; +2096;LATIN SUBSCRIPT SMALL LETTER K;Lm;0;L; 006B;;;;N;;;;; +2097;LATIN SUBSCRIPT SMALL LETTER L;Lm;0;L; 006C;;;;N;;;;; +2098;LATIN SUBSCRIPT SMALL LETTER M;Lm;0;L; 006D;;;;N;;;;; +2099;LATIN SUBSCRIPT SMALL LETTER N;Lm;0;L; 006E;;;;N;;;;; +209A;LATIN SUBSCRIPT SMALL LETTER P;Lm;0;L; 0070;;;;N;;;;; +209B;LATIN SUBSCRIPT SMALL LETTER S;Lm;0;L; 0073;;;;N;;;;; +209C;LATIN SUBSCRIPT SMALL LETTER T;Lm;0;L; 0074;;;;N;;;;; +20A0;EURO-CURRENCY SIGN;Sc;0;ET;;;;;N;;;;; +20A1;COLON SIGN;Sc;0;ET;;;;;N;;;;; +20A2;CRUZEIRO SIGN;Sc;0;ET;;;;;N;;;;; +20A3;FRENCH FRANC SIGN;Sc;0;ET;;;;;N;;;;; +20A4;LIRA SIGN;Sc;0;ET;;;;;N;;;;; +20A5;MILL SIGN;Sc;0;ET;;;;;N;;;;; +20A6;NAIRA SIGN;Sc;0;ET;;;;;N;;;;; +20A7;PESETA SIGN;Sc;0;ET;;;;;N;;;;; +20A8;RUPEE SIGN;Sc;0;ET; 0052 0073;;;;N;;;;; +20A9;WON SIGN;Sc;0;ET;;;;;N;;;;; +20AA;NEW SHEQEL SIGN;Sc;0;ET;;;;;N;;;;; +20AB;DONG SIGN;Sc;0;ET;;;;;N;;;;; +20AC;EURO SIGN;Sc;0;ET;;;;;N;;;;; +20AD;KIP SIGN;Sc;0;ET;;;;;N;;;;; +20AE;TUGRIK SIGN;Sc;0;ET;;;;;N;;;;; +20AF;DRACHMA SIGN;Sc;0;ET;;;;;N;;;;; +20B0;GERMAN PENNY SIGN;Sc;0;ET;;;;;N;;;;; +20B1;PESO SIGN;Sc;0;ET;;;;;N;;;;; +20B2;GUARANI SIGN;Sc;0;ET;;;;;N;;;;; +20B3;AUSTRAL SIGN;Sc;0;ET;;;;;N;;;;; +20B4;HRYVNIA SIGN;Sc;0;ET;;;;;N;;;;; +20B5;CEDI SIGN;Sc;0;ET;;;;;N;;;;; +20B6;LIVRE TOURNOIS SIGN;Sc;0;ET;;;;;N;;;;; +20B7;SPESMILO SIGN;Sc;0;ET;;;;;N;;;;; +20B8;TENGE SIGN;Sc;0;ET;;;;;N;;;;; +20B9;INDIAN RUPEE SIGN;Sc;0;ET;;;;;N;;;;; +20BA;TURKISH LIRA SIGN;Sc;0;ET;;;;;N;;;;; +20BB;NORDIC MARK SIGN;Sc;0;ET;;;;;N;;;;; +20BC;MANAT SIGN;Sc;0;ET;;;;;N;;;;; +20BD;RUBLE SIGN;Sc;0;ET;;;;;N;;;;; +20BE;LARI SIGN;Sc;0;ET;;;;;N;;;;; +20BF;BITCOIN SIGN;Sc;0;ET;;;;;N;;;;; +20C0;SOM SIGN;Sc;0;ET;;;;;N;;;;; +20C1;SAUDI RIYAL SIGN;Sc;0;ET;;;;;N;;;;; +20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;; +20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;; +20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;; +20D3;COMBINING SHORT VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT VERTICAL BAR OVERLAY;;;; +20D4;COMBINING ANTICLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING ANTICLOCKWISE ARROW ABOVE;;;; +20D5;COMBINING CLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING CLOCKWISE ARROW ABOVE;;;; +20D6;COMBINING LEFT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT ARROW ABOVE;;;; +20D7;COMBINING RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT ARROW ABOVE;;;; +20D8;COMBINING RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING RING OVERLAY;;;; +20D9;COMBINING CLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING CLOCKWISE RING OVERLAY;;;; +20DA;COMBINING ANTICLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING ANTICLOCKWISE RING OVERLAY;;;; +20DB;COMBINING THREE DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING THREE DOTS ABOVE;;;; +20DC;COMBINING FOUR DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING FOUR DOTS ABOVE;;;; +20DD;COMBINING ENCLOSING CIRCLE;Me;0;NSM;;;;;N;ENCLOSING CIRCLE;;;; +20DE;COMBINING ENCLOSING SQUARE;Me;0;NSM;;;;;N;ENCLOSING SQUARE;;;; +20DF;COMBINING ENCLOSING DIAMOND;Me;0;NSM;;;;;N;ENCLOSING DIAMOND;;;; +20E0;COMBINING ENCLOSING CIRCLE BACKSLASH;Me;0;NSM;;;;;N;ENCLOSING CIRCLE SLASH;;;; +20E1;COMBINING LEFT RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT RIGHT ARROW ABOVE;;;; +20E2;COMBINING ENCLOSING SCREEN;Me;0;NSM;;;;;N;;;;; +20E3;COMBINING ENCLOSING KEYCAP;Me;0;NSM;;;;;N;;;;; +20E4;COMBINING ENCLOSING UPWARD POINTING TRIANGLE;Me;0;NSM;;;;;N;;;;; +20E5;COMBINING REVERSE SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;;;;; +20E6;COMBINING DOUBLE VERTICAL STROKE OVERLAY;Mn;1;NSM;;;;;N;;;;; +20E7;COMBINING ANNUITY SYMBOL;Mn;230;NSM;;;;;N;;;;; +20E8;COMBINING TRIPLE UNDERDOT;Mn;220;NSM;;;;;N;;;;; +20E9;COMBINING WIDE BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;; +20EA;COMBINING LEFTWARDS ARROW OVERLAY;Mn;1;NSM;;;;;N;;;;; +20EB;COMBINING LONG DOUBLE SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;;;;; +20EC;COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS;Mn;220;NSM;;;;;N;;;;; +20ED;COMBINING LEFTWARDS HARPOON WITH BARB DOWNWARDS;Mn;220;NSM;;;;;N;;;;; +20EE;COMBINING LEFT ARROW BELOW;Mn;220;NSM;;;;;N;;;;; +20EF;COMBINING RIGHT ARROW BELOW;Mn;220;NSM;;;;;N;;;;; +20F0;COMBINING ASTERISK ABOVE;Mn;230;NSM;;;;;N;;;;; +2100;ACCOUNT OF;So;0;ON; 0061 002F 0063;;;;N;;;;; +2101;ADDRESSED TO THE SUBJECT;So;0;ON; 0061 002F 0073;;;;N;;;;; +2102;DOUBLE-STRUCK CAPITAL C;Lu;0;L; 0043;;;;N;DOUBLE-STRUCK C;;;; +2103;DEGREE CELSIUS;So;0;ON; 00B0 0043;;;;N;DEGREES CENTIGRADE;;;; +2104;CENTRE LINE SYMBOL;So;0;ON;;;;;N;C L SYMBOL;;;; +2105;CARE OF;So;0;ON; 0063 002F 006F;;;;N;;;;; +2106;CADA UNA;So;0;ON; 0063 002F 0075;;;;N;;;;; +2107;EULER CONSTANT;Lu;0;L; 0190;;;;N;EULERS;;;; +2108;SCRUPLE;So;0;ON;;;;;N;;;;; +2109;DEGREE FAHRENHEIT;So;0;ON; 00B0 0046;;;;N;DEGREES FAHRENHEIT;;;; +210A;SCRIPT SMALL G;Ll;0;L; 0067;;;;N;;;;; +210B;SCRIPT CAPITAL H;Lu;0;L; 0048;;;;N;SCRIPT H;;;; +210C;BLACK-LETTER CAPITAL H;Lu;0;L; 0048;;;;N;BLACK-LETTER H;;;; +210D;DOUBLE-STRUCK CAPITAL H;Lu;0;L; 0048;;;;N;DOUBLE-STRUCK H;;;; +210E;PLANCK CONSTANT;Ll;0;L; 0068;;;;N;;;;; +210F;PLANCK CONSTANT OVER TWO PI;Ll;0;L; 0127;;;;N;PLANCK CONSTANT OVER 2 PI;;;; +2110;SCRIPT CAPITAL I;Lu;0;L; 0049;;;;N;SCRIPT I;;;; +2111;BLACK-LETTER CAPITAL I;Lu;0;L; 0049;;;;N;BLACK-LETTER I;;;; +2112;SCRIPT CAPITAL L;Lu;0;L; 004C;;;;N;SCRIPT L;;;; +2113;SCRIPT SMALL L;Ll;0;L; 006C;;;;N;;;;; +2114;L B BAR SYMBOL;So;0;ON;;;;;N;;;;; +2115;DOUBLE-STRUCK CAPITAL N;Lu;0;L; 004E;;;;N;DOUBLE-STRUCK N;;;; +2116;NUMERO SIGN;So;0;ON; 004E 006F;;;;N;NUMERO;;;; +2117;SOUND RECORDING COPYRIGHT;So;0;ON;;;;;N;;;;; +2118;SCRIPT CAPITAL P;Sm;0;ON;;;;;N;SCRIPT P;;;; +2119;DOUBLE-STRUCK CAPITAL P;Lu;0;L; 0050;;;;N;DOUBLE-STRUCK P;;;; +211A;DOUBLE-STRUCK CAPITAL Q;Lu;0;L; 0051;;;;N;DOUBLE-STRUCK Q;;;; +211B;SCRIPT CAPITAL R;Lu;0;L; 0052;;;;N;SCRIPT R;;;; +211C;BLACK-LETTER CAPITAL R;Lu;0;L; 0052;;;;N;BLACK-LETTER R;;;; +211D;DOUBLE-STRUCK CAPITAL R;Lu;0;L; 0052;;;;N;DOUBLE-STRUCK R;;;; +211E;PRESCRIPTION TAKE;So;0;ON;;;;;N;;;;; +211F;RESPONSE;So;0;ON;;;;;N;;;;; +2120;SERVICE MARK;So;0;ON; 0053 004D;;;;N;;;;; +2121;TELEPHONE SIGN;So;0;ON; 0054 0045 004C;;;;N;T E L SYMBOL;;;; +2122;TRADE MARK SIGN;So;0;ON; 0054 004D;;;;N;TRADEMARK;;;; +2123;VERSICLE;So;0;ON;;;;;N;;;;; +2124;DOUBLE-STRUCK CAPITAL Z;Lu;0;L; 005A;;;;N;DOUBLE-STRUCK Z;;;; +2125;OUNCE SIGN;So;0;ON;;;;;N;OUNCE;;;; +2126;OHM SIGN;Lu;0;L;03A9;;;;N;OHM;;;03C9; +2127;INVERTED OHM SIGN;So;0;ON;;;;;N;MHO;;;; +2128;BLACK-LETTER CAPITAL Z;Lu;0;L; 005A;;;;N;BLACK-LETTER Z;;;; +2129;TURNED GREEK SMALL LETTER IOTA;So;0;ON;;;;;N;;;;; +212A;KELVIN SIGN;Lu;0;L;004B;;;;N;DEGREES KELVIN;;;006B; +212B;ANGSTROM SIGN;Lu;0;L;00C5;;;;N;ANGSTROM UNIT;;;00E5; +212C;SCRIPT CAPITAL B;Lu;0;L; 0042;;;;N;SCRIPT B;;;; +212D;BLACK-LETTER CAPITAL C;Lu;0;L; 0043;;;;N;BLACK-LETTER C;;;; +212E;ESTIMATED SYMBOL;So;0;ET;;;;;N;;;;; +212F;SCRIPT SMALL E;Ll;0;L; 0065;;;;N;;;;; +2130;SCRIPT CAPITAL E;Lu;0;L; 0045;;;;N;SCRIPT E;;;; +2131;SCRIPT CAPITAL F;Lu;0;L; 0046;;;;N;SCRIPT F;;;; +2132;TURNED CAPITAL F;Lu;0;L;;;;;N;TURNED F;;;214E; +2133;SCRIPT CAPITAL M;Lu;0;L; 004D;;;;N;SCRIPT M;;;; +2134;SCRIPT SMALL O;Ll;0;L; 006F;;;;N;;;;; +2135;ALEF SYMBOL;Lo;0;L; 05D0;;;;N;FIRST TRANSFINITE CARDINAL;;;; +2136;BET SYMBOL;Lo;0;L; 05D1;;;;N;SECOND TRANSFINITE CARDINAL;;;; +2137;GIMEL SYMBOL;Lo;0;L; 05D2;;;;N;THIRD TRANSFINITE CARDINAL;;;; +2138;DALET SYMBOL;Lo;0;L; 05D3;;;;N;FOURTH TRANSFINITE CARDINAL;;;; +2139;INFORMATION SOURCE;Ll;0;L; 0069;;;;N;;;;; +213A;ROTATED CAPITAL Q;So;0;ON;;;;;N;;;;; +213B;FACSIMILE SIGN;So;0;ON; 0046 0041 0058;;;;N;;;;; +213C;DOUBLE-STRUCK SMALL PI;Ll;0;L; 03C0;;;;N;;;;; +213D;DOUBLE-STRUCK SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; +213E;DOUBLE-STRUCK CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; +213F;DOUBLE-STRUCK CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; +2140;DOUBLE-STRUCK N-ARY SUMMATION;Sm;0;ON; 2211;;;;Y;;;;; +2141;TURNED SANS-SERIF CAPITAL G;Sm;0;ON;;;;;N;;;;; +2142;TURNED SANS-SERIF CAPITAL L;Sm;0;ON;;;;;N;;;;; +2143;REVERSED SANS-SERIF CAPITAL L;Sm;0;ON;;;;;N;;;;; +2144;TURNED SANS-SERIF CAPITAL Y;Sm;0;ON;;;;;N;;;;; +2145;DOUBLE-STRUCK ITALIC CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +2146;DOUBLE-STRUCK ITALIC SMALL D;Ll;0;L; 0064;;;;N;;;;; +2147;DOUBLE-STRUCK ITALIC SMALL E;Ll;0;L; 0065;;;;N;;;;; +2148;DOUBLE-STRUCK ITALIC SMALL I;Ll;0;L; 0069;;;;N;;;;; +2149;DOUBLE-STRUCK ITALIC SMALL J;Ll;0;L; 006A;;;;N;;;;; +214A;PROPERTY LINE;So;0;ON;;;;;N;;;;; +214B;TURNED AMPERSAND;Sm;0;ON;;;;;N;;;;; +214C;PER SIGN;So;0;ON;;;;;N;;;;; +214D;AKTIESELSKAB;So;0;ON;;;;;N;;;;; +214E;TURNED SMALL F;Ll;0;L;;;;;N;;;2132;;2132 +214F;SYMBOL FOR SAMARITAN SOURCE;So;0;L;;;;;N;;;;; +2150;VULGAR FRACTION ONE SEVENTH;No;0;ON; 0031 2044 0037;;;1/7;N;;;;; +2151;VULGAR FRACTION ONE NINTH;No;0;ON; 0031 2044 0039;;;1/9;N;;;;; +2152;VULGAR FRACTION ONE TENTH;No;0;ON; 0031 2044 0031 0030;;;1/10;N;;;;; +2153;VULGAR FRACTION ONE THIRD;No;0;ON; 0031 2044 0033;;;1/3;N;FRACTION ONE THIRD;;;; +2154;VULGAR FRACTION TWO THIRDS;No;0;ON; 0032 2044 0033;;;2/3;N;FRACTION TWO THIRDS;;;; +2155;VULGAR FRACTION ONE FIFTH;No;0;ON; 0031 2044 0035;;;1/5;N;FRACTION ONE FIFTH;;;; +2156;VULGAR FRACTION TWO FIFTHS;No;0;ON; 0032 2044 0035;;;2/5;N;FRACTION TWO FIFTHS;;;; +2157;VULGAR FRACTION THREE FIFTHS;No;0;ON; 0033 2044 0035;;;3/5;N;FRACTION THREE FIFTHS;;;; +2158;VULGAR FRACTION FOUR FIFTHS;No;0;ON; 0034 2044 0035;;;4/5;N;FRACTION FOUR FIFTHS;;;; +2159;VULGAR FRACTION ONE SIXTH;No;0;ON; 0031 2044 0036;;;1/6;N;FRACTION ONE SIXTH;;;; +215A;VULGAR FRACTION FIVE SIXTHS;No;0;ON; 0035 2044 0036;;;5/6;N;FRACTION FIVE SIXTHS;;;; +215B;VULGAR FRACTION ONE EIGHTH;No;0;ON; 0031 2044 0038;;;1/8;N;FRACTION ONE EIGHTH;;;; +215C;VULGAR FRACTION THREE EIGHTHS;No;0;ON; 0033 2044 0038;;;3/8;N;FRACTION THREE EIGHTHS;;;; +215D;VULGAR FRACTION FIVE EIGHTHS;No;0;ON; 0035 2044 0038;;;5/8;N;FRACTION FIVE EIGHTHS;;;; +215E;VULGAR FRACTION SEVEN EIGHTHS;No;0;ON; 0037 2044 0038;;;7/8;N;FRACTION SEVEN EIGHTHS;;;; +215F;FRACTION NUMERATOR ONE;No;0;ON; 0031 2044;;;1;N;;;;; +2160;ROMAN NUMERAL ONE;Nl;0;L; 0049;;;1;N;;;;2170; +2161;ROMAN NUMERAL TWO;Nl;0;L; 0049 0049;;;2;N;;;;2171; +2162;ROMAN NUMERAL THREE;Nl;0;L; 0049 0049 0049;;;3;N;;;;2172; +2163;ROMAN NUMERAL FOUR;Nl;0;L; 0049 0056;;;4;N;;;;2173; +2164;ROMAN NUMERAL FIVE;Nl;0;L; 0056;;;5;N;;;;2174; +2165;ROMAN NUMERAL SIX;Nl;0;L; 0056 0049;;;6;N;;;;2175; +2166;ROMAN NUMERAL SEVEN;Nl;0;L; 0056 0049 0049;;;7;N;;;;2176; +2167;ROMAN NUMERAL EIGHT;Nl;0;L; 0056 0049 0049 0049;;;8;N;;;;2177; +2168;ROMAN NUMERAL NINE;Nl;0;L; 0049 0058;;;9;N;;;;2178; +2169;ROMAN NUMERAL TEN;Nl;0;L; 0058;;;10;N;;;;2179; +216A;ROMAN NUMERAL ELEVEN;Nl;0;L; 0058 0049;;;11;N;;;;217A; +216B;ROMAN NUMERAL TWELVE;Nl;0;L; 0058 0049 0049;;;12;N;;;;217B; +216C;ROMAN NUMERAL FIFTY;Nl;0;L; 004C;;;50;N;;;;217C; +216D;ROMAN NUMERAL ONE HUNDRED;Nl;0;L; 0043;;;100;N;;;;217D; +216E;ROMAN NUMERAL FIVE HUNDRED;Nl;0;L; 0044;;;500;N;;;;217E; +216F;ROMAN NUMERAL ONE THOUSAND;Nl;0;L; 004D;;;1000;N;;;;217F; +2170;SMALL ROMAN NUMERAL ONE;Nl;0;L; 0069;;;1;N;;;2160;;2160 +2171;SMALL ROMAN NUMERAL TWO;Nl;0;L; 0069 0069;;;2;N;;;2161;;2161 +2172;SMALL ROMAN NUMERAL THREE;Nl;0;L; 0069 0069 0069;;;3;N;;;2162;;2162 +2173;SMALL ROMAN NUMERAL FOUR;Nl;0;L; 0069 0076;;;4;N;;;2163;;2163 +2174;SMALL ROMAN NUMERAL FIVE;Nl;0;L; 0076;;;5;N;;;2164;;2164 +2175;SMALL ROMAN NUMERAL SIX;Nl;0;L; 0076 0069;;;6;N;;;2165;;2165 +2176;SMALL ROMAN NUMERAL SEVEN;Nl;0;L; 0076 0069 0069;;;7;N;;;2166;;2166 +2177;SMALL ROMAN NUMERAL EIGHT;Nl;0;L; 0076 0069 0069 0069;;;8;N;;;2167;;2167 +2178;SMALL ROMAN NUMERAL NINE;Nl;0;L; 0069 0078;;;9;N;;;2168;;2168 +2179;SMALL ROMAN NUMERAL TEN;Nl;0;L; 0078;;;10;N;;;2169;;2169 +217A;SMALL ROMAN NUMERAL ELEVEN;Nl;0;L; 0078 0069;;;11;N;;;216A;;216A +217B;SMALL ROMAN NUMERAL TWELVE;Nl;0;L; 0078 0069 0069;;;12;N;;;216B;;216B +217C;SMALL ROMAN NUMERAL FIFTY;Nl;0;L; 006C;;;50;N;;;216C;;216C +217D;SMALL ROMAN NUMERAL ONE HUNDRED;Nl;0;L; 0063;;;100;N;;;216D;;216D +217E;SMALL ROMAN NUMERAL FIVE HUNDRED;Nl;0;L; 0064;;;500;N;;;216E;;216E +217F;SMALL ROMAN NUMERAL ONE THOUSAND;Nl;0;L; 006D;;;1000;N;;;216F;;216F +2180;ROMAN NUMERAL ONE THOUSAND C D;Nl;0;L;;;;1000;N;;;;; +2181;ROMAN NUMERAL FIVE THOUSAND;Nl;0;L;;;;5000;N;;;;; +2182;ROMAN NUMERAL TEN THOUSAND;Nl;0;L;;;;10000;N;;;;; +2183;ROMAN NUMERAL REVERSED ONE HUNDRED;Lu;0;L;;;;;N;;;;2184; +2184;LATIN SMALL LETTER REVERSED C;Ll;0;L;;;;;N;;;2183;;2183 +2185;ROMAN NUMERAL SIX LATE FORM;Nl;0;L;;;;6;N;;;;; +2186;ROMAN NUMERAL FIFTY EARLY FORM;Nl;0;L;;;;50;N;;;;; +2187;ROMAN NUMERAL FIFTY THOUSAND;Nl;0;L;;;;50000;N;;;;; +2188;ROMAN NUMERAL ONE HUNDRED THOUSAND;Nl;0;L;;;;100000;N;;;;; +2189;VULGAR FRACTION ZERO THIRDS;No;0;ON; 0030 2044 0033;;;0;N;;;;; +218A;TURNED DIGIT TWO;So;0;ON;;;;;N;;;;; +218B;TURNED DIGIT THREE;So;0;ON;;;;;N;;;;; +2190;LEFTWARDS ARROW;Sm;0;ON;;;;;N;LEFT ARROW;;;; +2191;UPWARDS ARROW;Sm;0;ON;;;;;N;UP ARROW;;;; +2192;RIGHTWARDS ARROW;Sm;0;ON;;;;;N;RIGHT ARROW;;;; +2193;DOWNWARDS ARROW;Sm;0;ON;;;;;N;DOWN ARROW;;;; +2194;LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;; +2195;UP DOWN ARROW;So;0;ON;;;;;N;;;;; +2196;NORTH WEST ARROW;So;0;ON;;;;;N;UPPER LEFT ARROW;;;; +2197;NORTH EAST ARROW;So;0;ON;;;;;N;UPPER RIGHT ARROW;;;; +2198;SOUTH EAST ARROW;So;0;ON;;;;;N;LOWER RIGHT ARROW;;;; +2199;SOUTH WEST ARROW;So;0;ON;;;;;N;LOWER LEFT ARROW;;;; +219A;LEFTWARDS ARROW WITH STROKE;Sm;0;ON;2190 0338;;;;N;LEFT ARROW WITH STROKE;;;; +219B;RIGHTWARDS ARROW WITH STROKE;Sm;0;ON;2192 0338;;;;N;RIGHT ARROW WITH STROKE;;;; +219C;LEFTWARDS WAVE ARROW;So;0;ON;;;;;N;LEFT WAVE ARROW;;;; +219D;RIGHTWARDS WAVE ARROW;So;0;ON;;;;;N;RIGHT WAVE ARROW;;;; +219E;LEFTWARDS TWO HEADED ARROW;So;0;ON;;;;;N;LEFT TWO HEADED ARROW;;;; +219F;UPWARDS TWO HEADED ARROW;So;0;ON;;;;;N;UP TWO HEADED ARROW;;;; +21A0;RIGHTWARDS TWO HEADED ARROW;Sm;0;ON;;;;;N;RIGHT TWO HEADED ARROW;;;; +21A1;DOWNWARDS TWO HEADED ARROW;So;0;ON;;;;;N;DOWN TWO HEADED ARROW;;;; +21A2;LEFTWARDS ARROW WITH TAIL;So;0;ON;;;;;N;LEFT ARROW WITH TAIL;;;; +21A3;RIGHTWARDS ARROW WITH TAIL;Sm;0;ON;;;;;N;RIGHT ARROW WITH TAIL;;;; +21A4;LEFTWARDS ARROW FROM BAR;So;0;ON;;;;;N;LEFT ARROW FROM BAR;;;; +21A5;UPWARDS ARROW FROM BAR;So;0;ON;;;;;N;UP ARROW FROM BAR;;;; +21A6;RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;RIGHT ARROW FROM BAR;;;; +21A7;DOWNWARDS ARROW FROM BAR;So;0;ON;;;;;N;DOWN ARROW FROM BAR;;;; +21A8;UP DOWN ARROW WITH BASE;So;0;ON;;;;;N;;;;; +21A9;LEFTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;LEFT ARROW WITH HOOK;;;; +21AA;RIGHTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;RIGHT ARROW WITH HOOK;;;; +21AB;LEFTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;LEFT ARROW WITH LOOP;;;; +21AC;RIGHTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;RIGHT ARROW WITH LOOP;;;; +21AD;LEFT RIGHT WAVE ARROW;So;0;ON;;;;;N;;;;; +21AE;LEFT RIGHT ARROW WITH STROKE;Sm;0;ON;2194 0338;;;;N;;;;; +21AF;DOWNWARDS ZIGZAG ARROW;So;0;ON;;;;;N;DOWN ZIGZAG ARROW;;;; +21B0;UPWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP LEFT;;;; +21B1;UPWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP RIGHT;;;; +21B2;DOWNWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP LEFT;;;; +21B3;DOWNWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP RIGHT;;;; +21B4;RIGHTWARDS ARROW WITH CORNER DOWNWARDS;So;0;ON;;;;;N;RIGHT ARROW WITH CORNER DOWN;;;; +21B5;DOWNWARDS ARROW WITH CORNER LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH CORNER LEFT;;;; +21B6;ANTICLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;; +21B7;CLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;; +21B8;NORTH WEST ARROW TO LONG BAR;So;0;ON;;;;;N;UPPER LEFT ARROW TO LONG BAR;;;; +21B9;LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR OVER RIGHT ARROW TO BAR;;;; +21BA;ANTICLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;; +21BB;CLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;; +21BC;LEFTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB UP;;;; +21BD;LEFTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB DOWN;;;; +21BE;UPWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB RIGHT;;;; +21BF;UPWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB LEFT;;;; +21C0;RIGHTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB UP;;;; +21C1;RIGHTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB DOWN;;;; +21C2;DOWNWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB RIGHT;;;; +21C3;DOWNWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB LEFT;;;; +21C4;RIGHTWARDS ARROW OVER LEFTWARDS ARROW;So;0;ON;;;;;N;RIGHT ARROW OVER LEFT ARROW;;;; +21C5;UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW;So;0;ON;;;;;N;UP ARROW LEFT OF DOWN ARROW;;;; +21C6;LEFTWARDS ARROW OVER RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT ARROW OVER RIGHT ARROW;;;; +21C7;LEFTWARDS PAIRED ARROWS;So;0;ON;;;;;N;LEFT PAIRED ARROWS;;;; +21C8;UPWARDS PAIRED ARROWS;So;0;ON;;;;;N;UP PAIRED ARROWS;;;; +21C9;RIGHTWARDS PAIRED ARROWS;So;0;ON;;;;;N;RIGHT PAIRED ARROWS;;;; +21CA;DOWNWARDS PAIRED ARROWS;So;0;ON;;;;;N;DOWN PAIRED ARROWS;;;; +21CB;LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON;So;0;ON;;;;;N;LEFT HARPOON OVER RIGHT HARPOON;;;; +21CC;RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON;So;0;ON;;;;;N;RIGHT HARPOON OVER LEFT HARPOON;;;; +21CD;LEFTWARDS DOUBLE ARROW WITH STROKE;So;0;ON;21D0 0338;;;;N;LEFT DOUBLE ARROW WITH STROKE;;;; +21CE;LEFT RIGHT DOUBLE ARROW WITH STROKE;Sm;0;ON;21D4 0338;;;;N;;;;; +21CF;RIGHTWARDS DOUBLE ARROW WITH STROKE;Sm;0;ON;21D2 0338;;;;N;RIGHT DOUBLE ARROW WITH STROKE;;;; +21D0;LEFTWARDS DOUBLE ARROW;So;0;ON;;;;;N;LEFT DOUBLE ARROW;;;; +21D1;UPWARDS DOUBLE ARROW;So;0;ON;;;;;N;UP DOUBLE ARROW;;;; +21D2;RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;RIGHT DOUBLE ARROW;;;; +21D3;DOWNWARDS DOUBLE ARROW;So;0;ON;;;;;N;DOWN DOUBLE ARROW;;;; +21D4;LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; +21D5;UP DOWN DOUBLE ARROW;So;0;ON;;;;;N;;;;; +21D6;NORTH WEST DOUBLE ARROW;So;0;ON;;;;;N;UPPER LEFT DOUBLE ARROW;;;; +21D7;NORTH EAST DOUBLE ARROW;So;0;ON;;;;;N;UPPER RIGHT DOUBLE ARROW;;;; +21D8;SOUTH EAST DOUBLE ARROW;So;0;ON;;;;;N;LOWER RIGHT DOUBLE ARROW;;;; +21D9;SOUTH WEST DOUBLE ARROW;So;0;ON;;;;;N;LOWER LEFT DOUBLE ARROW;;;; +21DA;LEFTWARDS TRIPLE ARROW;So;0;ON;;;;;N;LEFT TRIPLE ARROW;;;; +21DB;RIGHTWARDS TRIPLE ARROW;So;0;ON;;;;;N;RIGHT TRIPLE ARROW;;;; +21DC;LEFTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;LEFT SQUIGGLE ARROW;;;; +21DD;RIGHTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;RIGHT SQUIGGLE ARROW;;;; +21DE;UPWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;UP ARROW WITH DOUBLE STROKE;;;; +21DF;DOWNWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;DOWN ARROW WITH DOUBLE STROKE;;;; +21E0;LEFTWARDS DASHED ARROW;So;0;ON;;;;;N;LEFT DASHED ARROW;;;; +21E1;UPWARDS DASHED ARROW;So;0;ON;;;;;N;UP DASHED ARROW;;;; +21E2;RIGHTWARDS DASHED ARROW;So;0;ON;;;;;N;RIGHT DASHED ARROW;;;; +21E3;DOWNWARDS DASHED ARROW;So;0;ON;;;;;N;DOWN DASHED ARROW;;;; +21E4;LEFTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR;;;; +21E5;RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;RIGHT ARROW TO BAR;;;; +21E6;LEFTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE LEFT ARROW;;;; +21E7;UPWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE UP ARROW;;;; +21E8;RIGHTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE RIGHT ARROW;;;; +21E9;DOWNWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE DOWN ARROW;;;; +21EA;UPWARDS WHITE ARROW FROM BAR;So;0;ON;;;;;N;WHITE UP ARROW FROM BAR;;;; +21EB;UPWARDS WHITE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;; +21EC;UPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;; +21ED;UPWARDS WHITE ARROW ON PEDESTAL WITH VERTICAL BAR;So;0;ON;;;;;N;;;;; +21EE;UPWARDS WHITE DOUBLE ARROW;So;0;ON;;;;;N;;;;; +21EF;UPWARDS WHITE DOUBLE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;; +21F0;RIGHTWARDS WHITE ARROW FROM WALL;So;0;ON;;;;;N;;;;; +21F1;NORTH WEST ARROW TO CORNER;So;0;ON;;;;;N;;;;; +21F2;SOUTH EAST ARROW TO CORNER;So;0;ON;;;;;N;;;;; +21F3;UP DOWN WHITE ARROW;So;0;ON;;;;;N;;;;; +21F4;RIGHT ARROW WITH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; +21F5;DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW;Sm;0;ON;;;;;N;;;;; +21F6;THREE RIGHTWARDS ARROWS;Sm;0;ON;;;;;N;;;;; +21F7;LEFTWARDS ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +21F8;RIGHTWARDS ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +21F9;LEFT RIGHT ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +21FA;LEFTWARDS ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +21FB;RIGHTWARDS ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +21FC;LEFT RIGHT ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +21FD;LEFTWARDS OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;; +21FE;RIGHTWARDS OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;; +21FF;LEFT RIGHT OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;; +2200;FOR ALL;Sm;0;ON;;;;;N;;;;; +2201;COMPLEMENT;Sm;0;ON;;;;;Y;;;;; +2202;PARTIAL DIFFERENTIAL;Sm;0;ON;;;;;Y;;;;; +2203;THERE EXISTS;Sm;0;ON;;;;;Y;;;;; +2204;THERE DOES NOT EXIST;Sm;0;ON;2203 0338;;;;Y;;;;; +2205;EMPTY SET;Sm;0;ON;;;;;N;;;;; +2206;INCREMENT;Sm;0;ON;;;;;N;;;;; +2207;NABLA;Sm;0;ON;;;;;N;;;;; +2208;ELEMENT OF;Sm;0;ON;;;;;Y;;;;; +2209;NOT AN ELEMENT OF;Sm;0;ON;2208 0338;;;;Y;;;;; +220A;SMALL ELEMENT OF;Sm;0;ON;;;;;Y;;;;; +220B;CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;; +220C;DOES NOT CONTAIN AS MEMBER;Sm;0;ON;220B 0338;;;;Y;;;;; +220D;SMALL CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;; +220E;END OF PROOF;Sm;0;ON;;;;;N;;;;; +220F;N-ARY PRODUCT;Sm;0;ON;;;;;N;;;;; +2210;N-ARY COPRODUCT;Sm;0;ON;;;;;N;;;;; +2211;N-ARY SUMMATION;Sm;0;ON;;;;;Y;;;;; +2212;MINUS SIGN;Sm;0;ES;;;;;N;;;;; +2213;MINUS-OR-PLUS SIGN;Sm;0;ET;;;;;N;;;;; +2214;DOT PLUS;Sm;0;ON;;;;;N;;;;; +2215;DIVISION SLASH;Sm;0;ON;;;;;Y;;;;; +2216;SET MINUS;Sm;0;ON;;;;;Y;;;;; +2217;ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;; +2218;RING OPERATOR;Sm;0;ON;;;;;N;;;;; +2219;BULLET OPERATOR;Sm;0;ON;;;;;N;;;;; +221A;SQUARE ROOT;Sm;0;ON;;;;;Y;;;;; +221B;CUBE ROOT;Sm;0;ON;;;;;Y;;;;; +221C;FOURTH ROOT;Sm;0;ON;;;;;Y;;;;; +221D;PROPORTIONAL TO;Sm;0;ON;;;;;Y;;;;; +221E;INFINITY;Sm;0;ON;;;;;N;;;;; +221F;RIGHT ANGLE;Sm;0;ON;;;;;Y;;;;; +2220;ANGLE;Sm;0;ON;;;;;Y;;;;; +2221;MEASURED ANGLE;Sm;0;ON;;;;;Y;;;;; +2222;SPHERICAL ANGLE;Sm;0;ON;;;;;Y;;;;; +2223;DIVIDES;Sm;0;ON;;;;;N;;;;; +2224;DOES NOT DIVIDE;Sm;0;ON;2223 0338;;;;Y;;;;; +2225;PARALLEL TO;Sm;0;ON;;;;;N;;;;; +2226;NOT PARALLEL TO;Sm;0;ON;2225 0338;;;;Y;;;;; +2227;LOGICAL AND;Sm;0;ON;;;;;N;;;;; +2228;LOGICAL OR;Sm;0;ON;;;;;N;;;;; +2229;INTERSECTION;Sm;0;ON;;;;;N;;;;; +222A;UNION;Sm;0;ON;;;;;N;;;;; +222B;INTEGRAL;Sm;0;ON;;;;;Y;;;;; +222C;DOUBLE INTEGRAL;Sm;0;ON; 222B 222B;;;;Y;;;;; +222D;TRIPLE INTEGRAL;Sm;0;ON; 222B 222B 222B;;;;Y;;;;; +222E;CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;; +222F;SURFACE INTEGRAL;Sm;0;ON; 222E 222E;;;;Y;;;;; +2230;VOLUME INTEGRAL;Sm;0;ON; 222E 222E 222E;;;;Y;;;;; +2231;CLOCKWISE INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2232;CLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2233;ANTICLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2234;THEREFORE;Sm;0;ON;;;;;N;;;;; +2235;BECAUSE;Sm;0;ON;;;;;N;;;;; +2236;RATIO;Sm;0;ON;;;;;N;;;;; +2237;PROPORTION;Sm;0;ON;;;;;N;;;;; +2238;DOT MINUS;Sm;0;ON;;;;;N;;;;; +2239;EXCESS;Sm;0;ON;;;;;Y;;;;; +223A;GEOMETRIC PROPORTION;Sm;0;ON;;;;;N;;;;; +223B;HOMOTHETIC;Sm;0;ON;;;;;Y;;;;; +223C;TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; +223D;REVERSED TILDE;Sm;0;ON;;;;;Y;;;;; +223E;INVERTED LAZY S;Sm;0;ON;;;;;Y;;;;; +223F;SINE WAVE;Sm;0;ON;;;;;Y;;;;; +2240;WREATH PRODUCT;Sm;0;ON;;;;;Y;;;;; +2241;NOT TILDE;Sm;0;ON;223C 0338;;;;Y;;;;; +2242;MINUS TILDE;Sm;0;ON;;;;;Y;;;;; +2243;ASYMPTOTICALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2244;NOT ASYMPTOTICALLY EQUAL TO;Sm;0;ON;2243 0338;;;;Y;;;;; +2245;APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2246;APPROXIMATELY BUT NOT ACTUALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2247;NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO;Sm;0;ON;2245 0338;;;;Y;;;;; +2248;ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2249;NOT ALMOST EQUAL TO;Sm;0;ON;2248 0338;;;;Y;;;;; +224A;ALMOST EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +224B;TRIPLE TILDE;Sm;0;ON;;;;;Y;;;;; +224C;ALL EQUAL TO;Sm;0;ON;;;;;Y;;;;; +224D;EQUIVALENT TO;Sm;0;ON;;;;;N;;;;; +224E;GEOMETRICALLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;; +224F;DIFFERENCE BETWEEN;Sm;0;ON;;;;;N;;;;; +2250;APPROACHES THE LIMIT;Sm;0;ON;;;;;N;;;;; +2251;GEOMETRICALLY EQUAL TO;Sm;0;ON;;;;;N;;;;; +2252;APPROXIMATELY EQUAL TO OR THE IMAGE OF;Sm;0;ON;;;;;Y;;;;; +2253;IMAGE OF OR APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2254;COLON EQUALS;Sm;0;ON;;;;;Y;COLON EQUAL;;;; +2255;EQUALS COLON;Sm;0;ON;;;;;Y;EQUAL COLON;;;; +2256;RING IN EQUAL TO;Sm;0;ON;;;;;N;;;;; +2257;RING EQUAL TO;Sm;0;ON;;;;;N;;;;; +2258;CORRESPONDS TO;Sm;0;ON;;;;;N;;;;; +2259;ESTIMATES;Sm;0;ON;;;;;N;;;;; +225A;EQUIANGULAR TO;Sm;0;ON;;;;;N;;;;; +225B;STAR EQUALS;Sm;0;ON;;;;;N;;;;; +225C;DELTA EQUAL TO;Sm;0;ON;;;;;N;;;;; +225D;EQUAL TO BY DEFINITION;Sm;0;ON;;;;;N;;;;; +225E;MEASURED BY;Sm;0;ON;;;;;N;;;;; +225F;QUESTIONED EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2260;NOT EQUAL TO;Sm;0;ON;003D 0338;;;;Y;;;;; +2261;IDENTICAL TO;Sm;0;ON;;;;;N;;;;; +2262;NOT IDENTICAL TO;Sm;0;ON;2261 0338;;;;Y;;;;; +2263;STRICTLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;; +2264;LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUAL TO;;;; +2265;GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUAL TO;;;; +2266;LESS-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OVER EQUAL TO;;;; +2267;GREATER-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OVER EQUAL TO;;;; +2268;LESS-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUAL TO;;;; +2269;GREATER-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUAL TO;;;; +226A;MUCH LESS-THAN;Sm;0;ON;;;;;Y;MUCH LESS THAN;;;; +226B;MUCH GREATER-THAN;Sm;0;ON;;;;;Y;MUCH GREATER THAN;;;; +226C;BETWEEN;Sm;0;ON;;;;;N;;;;; +226D;NOT EQUIVALENT TO;Sm;0;ON;224D 0338;;;;Y;;;;; +226E;NOT LESS-THAN;Sm;0;ON;003C 0338;;;;Y;NOT LESS THAN;;;; +226F;NOT GREATER-THAN;Sm;0;ON;003E 0338;;;;Y;NOT GREATER THAN;;;; +2270;NEITHER LESS-THAN NOR EQUAL TO;Sm;0;ON;2264 0338;;;;Y;NEITHER LESS THAN NOR EQUAL TO;;;; +2271;NEITHER GREATER-THAN NOR EQUAL TO;Sm;0;ON;2265 0338;;;;Y;NEITHER GREATER THAN NOR EQUAL TO;;;; +2272;LESS-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUIVALENT TO;;;; +2273;GREATER-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUIVALENT TO;;;; +2274;NEITHER LESS-THAN NOR EQUIVALENT TO;Sm;0;ON;2272 0338;;;;Y;NEITHER LESS THAN NOR EQUIVALENT TO;;;; +2275;NEITHER GREATER-THAN NOR EQUIVALENT TO;Sm;0;ON;2273 0338;;;;Y;NEITHER GREATER THAN NOR EQUIVALENT TO;;;; +2276;LESS-THAN OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN OR GREATER THAN;;;; +2277;GREATER-THAN OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN OR LESS THAN;;;; +2278;NEITHER LESS-THAN NOR GREATER-THAN;Sm;0;ON;2276 0338;;;;Y;NEITHER LESS THAN NOR GREATER THAN;;;; +2279;NEITHER GREATER-THAN NOR LESS-THAN;Sm;0;ON;2277 0338;;;;Y;NEITHER GREATER THAN NOR LESS THAN;;;; +227A;PRECEDES;Sm;0;ON;;;;;Y;;;;; +227B;SUCCEEDS;Sm;0;ON;;;;;Y;;;;; +227C;PRECEDES OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +227D;SUCCEEDS OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +227E;PRECEDES OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; +227F;SUCCEEDS OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; +2280;DOES NOT PRECEDE;Sm;0;ON;227A 0338;;;;Y;;;;; +2281;DOES NOT SUCCEED;Sm;0;ON;227B 0338;;;;Y;;;;; +2282;SUBSET OF;Sm;0;ON;;;;;Y;;;;; +2283;SUPERSET OF;Sm;0;ON;;;;;Y;;;;; +2284;NOT A SUBSET OF;Sm;0;ON;2282 0338;;;;Y;;;;; +2285;NOT A SUPERSET OF;Sm;0;ON;2283 0338;;;;Y;;;;; +2286;SUBSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2287;SUPERSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2288;NEITHER A SUBSET OF NOR EQUAL TO;Sm;0;ON;2286 0338;;;;Y;;;;; +2289;NEITHER A SUPERSET OF NOR EQUAL TO;Sm;0;ON;2287 0338;;;;Y;;;;; +228A;SUBSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUBSET OF OR NOT EQUAL TO;;;; +228B;SUPERSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUPERSET OF OR NOT EQUAL TO;;;; +228C;MULTISET;Sm;0;ON;;;;;Y;;;;; +228D;MULTISET MULTIPLICATION;Sm;0;ON;;;;;N;;;;; +228E;MULTISET UNION;Sm;0;ON;;;;;N;;;;; +228F;SQUARE IMAGE OF;Sm;0;ON;;;;;Y;;;;; +2290;SQUARE ORIGINAL OF;Sm;0;ON;;;;;Y;;;;; +2291;SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2292;SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2293;SQUARE CAP;Sm;0;ON;;;;;N;;;;; +2294;SQUARE CUP;Sm;0;ON;;;;;N;;;;; +2295;CIRCLED PLUS;Sm;0;ON;;;;;N;;;;; +2296;CIRCLED MINUS;Sm;0;ON;;;;;N;;;;; +2297;CIRCLED TIMES;Sm;0;ON;;;;;N;;;;; +2298;CIRCLED DIVISION SLASH;Sm;0;ON;;;;;Y;;;;; +2299;CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;; +229A;CIRCLED RING OPERATOR;Sm;0;ON;;;;;N;;;;; +229B;CIRCLED ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;; +229C;CIRCLED EQUALS;Sm;0;ON;;;;;N;;;;; +229D;CIRCLED DASH;Sm;0;ON;;;;;N;;;;; +229E;SQUARED PLUS;Sm;0;ON;;;;;N;;;;; +229F;SQUARED MINUS;Sm;0;ON;;;;;N;;;;; +22A0;SQUARED TIMES;Sm;0;ON;;;;;N;;;;; +22A1;SQUARED DOT OPERATOR;Sm;0;ON;;;;;N;;;;; +22A2;RIGHT TACK;Sm;0;ON;;;;;Y;;;;; +22A3;LEFT TACK;Sm;0;ON;;;;;Y;;;;; +22A4;DOWN TACK;Sm;0;ON;;;;;N;;;;; +22A5;UP TACK;Sm;0;ON;;;;;N;;;;; +22A6;ASSERTION;Sm;0;ON;;;;;Y;;;;; +22A7;MODELS;Sm;0;ON;;;;;Y;;;;; +22A8;TRUE;Sm;0;ON;;;;;Y;;;;; +22A9;FORCES;Sm;0;ON;;;;;Y;;;;; +22AA;TRIPLE VERTICAL BAR RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;; +22AB;DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;; +22AC;DOES NOT PROVE;Sm;0;ON;22A2 0338;;;;Y;;;;; +22AD;NOT TRUE;Sm;0;ON;22A8 0338;;;;Y;;;;; +22AE;DOES NOT FORCE;Sm;0;ON;22A9 0338;;;;Y;;;;; +22AF;NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;22AB 0338;;;;Y;;;;; +22B0;PRECEDES UNDER RELATION;Sm;0;ON;;;;;Y;;;;; +22B1;SUCCEEDS UNDER RELATION;Sm;0;ON;;;;;Y;;;;; +22B2;NORMAL SUBGROUP OF;Sm;0;ON;;;;;Y;;;;; +22B3;CONTAINS AS NORMAL SUBGROUP;Sm;0;ON;;;;;Y;;;;; +22B4;NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +22B5;CONTAINS AS NORMAL SUBGROUP OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +22B6;ORIGINAL OF;Sm;0;ON;;;;;Y;;;;; +22B7;IMAGE OF;Sm;0;ON;;;;;Y;;;;; +22B8;MULTIMAP;Sm;0;ON;;;;;Y;;;;; +22B9;HERMITIAN CONJUGATE MATRIX;Sm;0;ON;;;;;N;;;;; +22BA;INTERCALATE;Sm;0;ON;;;;;N;;;;; +22BB;XOR;Sm;0;ON;;;;;N;;;;; +22BC;NAND;Sm;0;ON;;;;;N;;;;; +22BD;NOR;Sm;0;ON;;;;;N;;;;; +22BE;RIGHT ANGLE WITH ARC;Sm;0;ON;;;;;Y;;;;; +22BF;RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;; +22C0;N-ARY LOGICAL AND;Sm;0;ON;;;;;N;;;;; +22C1;N-ARY LOGICAL OR;Sm;0;ON;;;;;N;;;;; +22C2;N-ARY INTERSECTION;Sm;0;ON;;;;;N;;;;; +22C3;N-ARY UNION;Sm;0;ON;;;;;N;;;;; +22C4;DIAMOND OPERATOR;Sm;0;ON;;;;;N;;;;; +22C5;DOT OPERATOR;Sm;0;ON;;;;;N;;;;; +22C6;STAR OPERATOR;Sm;0;ON;;;;;N;;;;; +22C7;DIVISION TIMES;Sm;0;ON;;;;;N;;;;; +22C8;BOWTIE;Sm;0;ON;;;;;N;;;;; +22C9;LEFT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; +22CA;RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; +22CB;LEFT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; +22CC;RIGHT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; +22CD;REVERSED TILDE EQUALS;Sm;0;ON;;;;;Y;;;;; +22CE;CURLY LOGICAL OR;Sm;0;ON;;;;;N;;;;; +22CF;CURLY LOGICAL AND;Sm;0;ON;;;;;N;;;;; +22D0;DOUBLE SUBSET;Sm;0;ON;;;;;Y;;;;; +22D1;DOUBLE SUPERSET;Sm;0;ON;;;;;Y;;;;; +22D2;DOUBLE INTERSECTION;Sm;0;ON;;;;;N;;;;; +22D3;DOUBLE UNION;Sm;0;ON;;;;;N;;;;; +22D4;PITCHFORK;Sm;0;ON;;;;;N;;;;; +22D5;EQUAL AND PARALLEL TO;Sm;0;ON;;;;;N;;;;; +22D6;LESS-THAN WITH DOT;Sm;0;ON;;;;;Y;LESS THAN WITH DOT;;;; +22D7;GREATER-THAN WITH DOT;Sm;0;ON;;;;;Y;GREATER THAN WITH DOT;;;; +22D8;VERY MUCH LESS-THAN;Sm;0;ON;;;;;Y;VERY MUCH LESS THAN;;;; +22D9;VERY MUCH GREATER-THAN;Sm;0;ON;;;;;Y;VERY MUCH GREATER THAN;;;; +22DA;LESS-THAN EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN EQUAL TO OR GREATER THAN;;;; +22DB;GREATER-THAN EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN EQUAL TO OR LESS THAN;;;; +22DC;EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR LESS THAN;;;; +22DD;EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR GREATER THAN;;;; +22DE;EQUAL TO OR PRECEDES;Sm;0;ON;;;;;Y;;;;; +22DF;EQUAL TO OR SUCCEEDS;Sm;0;ON;;;;;Y;;;;; +22E0;DOES NOT PRECEDE OR EQUAL;Sm;0;ON;227C 0338;;;;Y;;;;; +22E1;DOES NOT SUCCEED OR EQUAL;Sm;0;ON;227D 0338;;;;Y;;;;; +22E2;NOT SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;2291 0338;;;;Y;;;;; +22E3;NOT SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;2292 0338;;;;Y;;;;; +22E4;SQUARE IMAGE OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +22E5;SQUARE ORIGINAL OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +22E6;LESS-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUIVALENT TO;;;; +22E7;GREATER-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUIVALENT TO;;;; +22E8;PRECEDES BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; +22E9;SUCCEEDS BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; +22EA;NOT NORMAL SUBGROUP OF;Sm;0;ON;22B2 0338;;;;Y;;;;; +22EB;DOES NOT CONTAIN AS NORMAL SUBGROUP;Sm;0;ON;22B3 0338;;;;Y;;;;; +22EC;NOT NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;22B4 0338;;;;Y;;;;; +22ED;DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL;Sm;0;ON;22B5 0338;;;;Y;;;;; +22EE;VERTICAL ELLIPSIS;Sm;0;ON;;;;;N;;;;; +22EF;MIDLINE HORIZONTAL ELLIPSIS;Sm;0;ON;;;;;N;;;;; +22F0;UP RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;; +22F1;DOWN RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;; +22F2;ELEMENT OF WITH LONG HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; +22F3;ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; +22F4;SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; +22F5;ELEMENT OF WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; +22F6;ELEMENT OF WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; +22F7;SMALL ELEMENT OF WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; +22F8;ELEMENT OF WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; +22F9;ELEMENT OF WITH TWO HORIZONTAL STROKES;Sm;0;ON;;;;;Y;;;;; +22FA;CONTAINS WITH LONG HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; +22FB;CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; +22FC;SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; +22FD;CONTAINS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; +22FE;SMALL CONTAINS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; +22FF;Z NOTATION BAG MEMBERSHIP;Sm;0;ON;;;;;Y;;;;; +2300;DIAMETER SIGN;So;0;ON;;;;;N;;;;; +2301;ELECTRIC ARROW;So;0;ON;;;;;N;;;;; +2302;HOUSE;So;0;ON;;;;;N;;;;; +2303;UP ARROWHEAD;So;0;ON;;;;;N;;;;; +2304;DOWN ARROWHEAD;So;0;ON;;;;;N;;;;; +2305;PROJECTIVE;So;0;ON;;;;;N;;;;; +2306;PERSPECTIVE;So;0;ON;;;;;N;;;;; +2307;WAVY LINE;So;0;ON;;;;;N;;;;; +2308;LEFT CEILING;Ps;0;ON;;;;;Y;;;;; +2309;RIGHT CEILING;Pe;0;ON;;;;;Y;;;;; +230A;LEFT FLOOR;Ps;0;ON;;;;;Y;;;;; +230B;RIGHT FLOOR;Pe;0;ON;;;;;Y;;;;; +230C;BOTTOM RIGHT CROP;So;0;ON;;;;;N;;;;; +230D;BOTTOM LEFT CROP;So;0;ON;;;;;N;;;;; +230E;TOP RIGHT CROP;So;0;ON;;;;;N;;;;; +230F;TOP LEFT CROP;So;0;ON;;;;;N;;;;; +2310;REVERSED NOT SIGN;So;0;ON;;;;;N;;;;; +2311;SQUARE LOZENGE;So;0;ON;;;;;N;;;;; +2312;ARC;So;0;ON;;;;;N;;;;; +2313;SEGMENT;So;0;ON;;;;;N;;;;; +2314;SECTOR;So;0;ON;;;;;N;;;;; +2315;TELEPHONE RECORDER;So;0;ON;;;;;N;;;;; +2316;POSITION INDICATOR;So;0;ON;;;;;N;;;;; +2317;VIEWDATA SQUARE;So;0;ON;;;;;N;;;;; +2318;PLACE OF INTEREST SIGN;So;0;ON;;;;;N;COMMAND KEY;;;; +2319;TURNED NOT SIGN;So;0;ON;;;;;N;;;;; +231A;WATCH;So;0;ON;;;;;N;;;;; +231B;HOURGLASS;So;0;ON;;;;;N;;;;; +231C;TOP LEFT CORNER;So;0;ON;;;;;N;;;;; +231D;TOP RIGHT CORNER;So;0;ON;;;;;N;;;;; +231E;BOTTOM LEFT CORNER;So;0;ON;;;;;N;;;;; +231F;BOTTOM RIGHT CORNER;So;0;ON;;;;;N;;;;; +2320;TOP HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2321;BOTTOM HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2322;FROWN;So;0;ON;;;;;N;;;;; +2323;SMILE;So;0;ON;;;;;N;;;;; +2324;UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS;So;0;ON;;;;;N;ENTER KEY;;;; +2325;OPTION KEY;So;0;ON;;;;;N;;;;; +2326;ERASE TO THE RIGHT;So;0;ON;;;;;N;DELETE TO THE RIGHT KEY;;;; +2327;X IN A RECTANGLE BOX;So;0;ON;;;;;N;CLEAR KEY;;;; +2328;KEYBOARD;So;0;ON;;;;;N;;;;; +2329;LEFT-POINTING ANGLE BRACKET;Ps;0;ON;3008;;;;Y;BRA;;;; +232A;RIGHT-POINTING ANGLE BRACKET;Pe;0;ON;3009;;;;Y;KET;;;; +232B;ERASE TO THE LEFT;So;0;ON;;;;;N;DELETE TO THE LEFT KEY;;;; +232C;BENZENE RING;So;0;ON;;;;;N;;;;; +232D;CYLINDRICITY;So;0;ON;;;;;N;;;;; +232E;ALL AROUND-PROFILE;So;0;ON;;;;;N;;;;; +232F;SYMMETRY;So;0;ON;;;;;N;;;;; +2330;TOTAL RUNOUT;So;0;ON;;;;;N;;;;; +2331;DIMENSION ORIGIN;So;0;ON;;;;;N;;;;; +2332;CONICAL TAPER;So;0;ON;;;;;N;;;;; +2333;SLOPE;So;0;ON;;;;;N;;;;; +2334;COUNTERBORE;So;0;ON;;;;;N;;;;; +2335;COUNTERSINK;So;0;ON;;;;;N;;;;; +2336;APL FUNCTIONAL SYMBOL I-BEAM;So;0;L;;;;;N;;;;; +2337;APL FUNCTIONAL SYMBOL SQUISH QUAD;So;0;L;;;;;N;;;;; +2338;APL FUNCTIONAL SYMBOL QUAD EQUAL;So;0;L;;;;;N;;;;; +2339;APL FUNCTIONAL SYMBOL QUAD DIVIDE;So;0;L;;;;;N;;;;; +233A;APL FUNCTIONAL SYMBOL QUAD DIAMOND;So;0;L;;;;;N;;;;; +233B;APL FUNCTIONAL SYMBOL QUAD JOT;So;0;L;;;;;N;;;;; +233C;APL FUNCTIONAL SYMBOL QUAD CIRCLE;So;0;L;;;;;N;;;;; +233D;APL FUNCTIONAL SYMBOL CIRCLE STILE;So;0;L;;;;;N;;;;; +233E;APL FUNCTIONAL SYMBOL CIRCLE JOT;So;0;L;;;;;N;;;;; +233F;APL FUNCTIONAL SYMBOL SLASH BAR;So;0;L;;;;;N;;;;; +2340;APL FUNCTIONAL SYMBOL BACKSLASH BAR;So;0;L;;;;;N;;;;; +2341;APL FUNCTIONAL SYMBOL QUAD SLASH;So;0;L;;;;;N;;;;; +2342;APL FUNCTIONAL SYMBOL QUAD BACKSLASH;So;0;L;;;;;N;;;;; +2343;APL FUNCTIONAL SYMBOL QUAD LESS-THAN;So;0;L;;;;;N;;;;; +2344;APL FUNCTIONAL SYMBOL QUAD GREATER-THAN;So;0;L;;;;;N;;;;; +2345;APL FUNCTIONAL SYMBOL LEFTWARDS VANE;So;0;L;;;;;N;;;;; +2346;APL FUNCTIONAL SYMBOL RIGHTWARDS VANE;So;0;L;;;;;N;;;;; +2347;APL FUNCTIONAL SYMBOL QUAD LEFTWARDS ARROW;So;0;L;;;;;N;;;;; +2348;APL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROW;So;0;L;;;;;N;;;;; +2349;APL FUNCTIONAL SYMBOL CIRCLE BACKSLASH;So;0;L;;;;;N;;;;; +234A;APL FUNCTIONAL SYMBOL DOWN TACK UNDERBAR;So;0;L;;;;;N;;;;; +234B;APL FUNCTIONAL SYMBOL DELTA STILE;So;0;L;;;;;N;;;;; +234C;APL FUNCTIONAL SYMBOL QUAD DOWN CARET;So;0;L;;;;;N;;;;; +234D;APL FUNCTIONAL SYMBOL QUAD DELTA;So;0;L;;;;;N;;;;; +234E;APL FUNCTIONAL SYMBOL DOWN TACK JOT;So;0;L;;;;;N;;;;; +234F;APL FUNCTIONAL SYMBOL UPWARDS VANE;So;0;L;;;;;N;;;;; +2350;APL FUNCTIONAL SYMBOL QUAD UPWARDS ARROW;So;0;L;;;;;N;;;;; +2351;APL FUNCTIONAL SYMBOL UP TACK OVERBAR;So;0;L;;;;;N;;;;; +2352;APL FUNCTIONAL SYMBOL DEL STILE;So;0;L;;;;;N;;;;; +2353;APL FUNCTIONAL SYMBOL QUAD UP CARET;So;0;L;;;;;N;;;;; +2354;APL FUNCTIONAL SYMBOL QUAD DEL;So;0;L;;;;;N;;;;; +2355;APL FUNCTIONAL SYMBOL UP TACK JOT;So;0;L;;;;;N;;;;; +2356;APL FUNCTIONAL SYMBOL DOWNWARDS VANE;So;0;L;;;;;N;;;;; +2357;APL FUNCTIONAL SYMBOL QUAD DOWNWARDS ARROW;So;0;L;;;;;N;;;;; +2358;APL FUNCTIONAL SYMBOL QUOTE UNDERBAR;So;0;L;;;;;N;;;;; +2359;APL FUNCTIONAL SYMBOL DELTA UNDERBAR;So;0;L;;;;;N;;;;; +235A;APL FUNCTIONAL SYMBOL DIAMOND UNDERBAR;So;0;L;;;;;N;;;;; +235B;APL FUNCTIONAL SYMBOL JOT UNDERBAR;So;0;L;;;;;N;;;;; +235C;APL FUNCTIONAL SYMBOL CIRCLE UNDERBAR;So;0;L;;;;;N;;;;; +235D;APL FUNCTIONAL SYMBOL UP SHOE JOT;So;0;L;;;;;N;;;;; +235E;APL FUNCTIONAL SYMBOL QUOTE QUAD;So;0;L;;;;;N;;;;; +235F;APL FUNCTIONAL SYMBOL CIRCLE STAR;So;0;L;;;;;N;;;;; +2360;APL FUNCTIONAL SYMBOL QUAD COLON;So;0;L;;;;;N;;;;; +2361;APL FUNCTIONAL SYMBOL UP TACK DIAERESIS;So;0;L;;;;;N;;;;; +2362;APL FUNCTIONAL SYMBOL DEL DIAERESIS;So;0;L;;;;;N;;;;; +2363;APL FUNCTIONAL SYMBOL STAR DIAERESIS;So;0;L;;;;;N;;;;; +2364;APL FUNCTIONAL SYMBOL JOT DIAERESIS;So;0;L;;;;;N;;;;; +2365;APL FUNCTIONAL SYMBOL CIRCLE DIAERESIS;So;0;L;;;;;N;;;;; +2366;APL FUNCTIONAL SYMBOL DOWN SHOE STILE;So;0;L;;;;;N;;;;; +2367;APL FUNCTIONAL SYMBOL LEFT SHOE STILE;So;0;L;;;;;N;;;;; +2368;APL FUNCTIONAL SYMBOL TILDE DIAERESIS;So;0;L;;;;;N;;;;; +2369;APL FUNCTIONAL SYMBOL GREATER-THAN DIAERESIS;So;0;L;;;;;N;;;;; +236A;APL FUNCTIONAL SYMBOL COMMA BAR;So;0;L;;;;;N;;;;; +236B;APL FUNCTIONAL SYMBOL DEL TILDE;So;0;L;;;;;N;;;;; +236C;APL FUNCTIONAL SYMBOL ZILDE;So;0;L;;;;;N;;;;; +236D;APL FUNCTIONAL SYMBOL STILE TILDE;So;0;L;;;;;N;;;;; +236E;APL FUNCTIONAL SYMBOL SEMICOLON UNDERBAR;So;0;L;;;;;N;;;;; +236F;APL FUNCTIONAL SYMBOL QUAD NOT EQUAL;So;0;L;;;;;N;;;;; +2370;APL FUNCTIONAL SYMBOL QUAD QUESTION;So;0;L;;;;;N;;;;; +2371;APL FUNCTIONAL SYMBOL DOWN CARET TILDE;So;0;L;;;;;N;;;;; +2372;APL FUNCTIONAL SYMBOL UP CARET TILDE;So;0;L;;;;;N;;;;; +2373;APL FUNCTIONAL SYMBOL IOTA;So;0;L;;;;;N;;;;; +2374;APL FUNCTIONAL SYMBOL RHO;So;0;L;;;;;N;;;;; +2375;APL FUNCTIONAL SYMBOL OMEGA;So;0;L;;;;;N;;;;; +2376;APL FUNCTIONAL SYMBOL ALPHA UNDERBAR;So;0;L;;;;;N;;;;; +2377;APL FUNCTIONAL SYMBOL EPSILON UNDERBAR;So;0;L;;;;;N;;;;; +2378;APL FUNCTIONAL SYMBOL IOTA UNDERBAR;So;0;L;;;;;N;;;;; +2379;APL FUNCTIONAL SYMBOL OMEGA UNDERBAR;So;0;L;;;;;N;;;;; +237A;APL FUNCTIONAL SYMBOL ALPHA;So;0;L;;;;;N;;;;; +237B;NOT CHECK MARK;So;0;ON;;;;;N;;;;; +237C;RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW;Sm;0;ON;;;;;N;;;;; +237D;SHOULDERED OPEN BOX;So;0;ON;;;;;N;;;;; +237E;BELL SYMBOL;So;0;ON;;;;;N;;;;; +237F;VERTICAL LINE WITH MIDDLE DOT;So;0;ON;;;;;N;;;;; +2380;INSERTION SYMBOL;So;0;ON;;;;;N;;;;; +2381;CONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;; +2382;DISCONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;; +2383;EMPHASIS SYMBOL;So;0;ON;;;;;N;;;;; +2384;COMPOSITION SYMBOL;So;0;ON;;;;;N;;;;; +2385;WHITE SQUARE WITH CENTRE VERTICAL LINE;So;0;ON;;;;;N;;;;; +2386;ENTER SYMBOL;So;0;ON;;;;;N;;;;; +2387;ALTERNATIVE KEY SYMBOL;So;0;ON;;;;;N;;;;; +2388;HELM SYMBOL;So;0;ON;;;;;N;;;;; +2389;CIRCLED HORIZONTAL BAR WITH NOTCH;So;0;ON;;;;;N;;;;; +238A;CIRCLED TRIANGLE DOWN;So;0;ON;;;;;N;;;;; +238B;BROKEN CIRCLE WITH NORTHWEST ARROW;So;0;ON;;;;;N;;;;; +238C;UNDO SYMBOL;So;0;ON;;;;;N;;;;; +238D;MONOSTABLE SYMBOL;So;0;ON;;;;;N;;;;; +238E;HYSTERESIS SYMBOL;So;0;ON;;;;;N;;;;; +238F;OPEN-CIRCUIT-OUTPUT H-TYPE SYMBOL;So;0;ON;;;;;N;;;;; +2390;OPEN-CIRCUIT-OUTPUT L-TYPE SYMBOL;So;0;ON;;;;;N;;;;; +2391;PASSIVE-PULL-DOWN-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;; +2392;PASSIVE-PULL-UP-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;; +2393;DIRECT CURRENT SYMBOL FORM TWO;So;0;ON;;;;;N;;;;; +2394;SOFTWARE-FUNCTION SYMBOL;So;0;ON;;;;;N;;;;; +2395;APL FUNCTIONAL SYMBOL QUAD;So;0;L;;;;;N;;;;; +2396;DECIMAL SEPARATOR KEY SYMBOL;So;0;ON;;;;;N;;;;; +2397;PREVIOUS PAGE;So;0;ON;;;;;N;;;;; +2398;NEXT PAGE;So;0;ON;;;;;N;;;;; +2399;PRINT SCREEN SYMBOL;So;0;ON;;;;;N;;;;; +239A;CLEAR SCREEN SYMBOL;So;0;ON;;;;;N;;;;; +239B;LEFT PARENTHESIS UPPER HOOK;Sm;0;ON;;;;;N;;;;; +239C;LEFT PARENTHESIS EXTENSION;Sm;0;ON;;;;;N;;;;; +239D;LEFT PARENTHESIS LOWER HOOK;Sm;0;ON;;;;;N;;;;; +239E;RIGHT PARENTHESIS UPPER HOOK;Sm;0;ON;;;;;N;;;;; +239F;RIGHT PARENTHESIS EXTENSION;Sm;0;ON;;;;;N;;;;; +23A0;RIGHT PARENTHESIS LOWER HOOK;Sm;0;ON;;;;;N;;;;; +23A1;LEFT SQUARE BRACKET UPPER CORNER;Sm;0;ON;;;;;N;;;;; +23A2;LEFT SQUARE BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;; +23A3;LEFT SQUARE BRACKET LOWER CORNER;Sm;0;ON;;;;;N;;;;; +23A4;RIGHT SQUARE BRACKET UPPER CORNER;Sm;0;ON;;;;;N;;;;; +23A5;RIGHT SQUARE BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;; +23A6;RIGHT SQUARE BRACKET LOWER CORNER;Sm;0;ON;;;;;N;;;;; +23A7;LEFT CURLY BRACKET UPPER HOOK;Sm;0;ON;;;;;N;;;;; +23A8;LEFT CURLY BRACKET MIDDLE PIECE;Sm;0;ON;;;;;N;;;;; +23A9;LEFT CURLY BRACKET LOWER HOOK;Sm;0;ON;;;;;N;;;;; +23AA;CURLY BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;; +23AB;RIGHT CURLY BRACKET UPPER HOOK;Sm;0;ON;;;;;N;;;;; +23AC;RIGHT CURLY BRACKET MIDDLE PIECE;Sm;0;ON;;;;;N;;;;; +23AD;RIGHT CURLY BRACKET LOWER HOOK;Sm;0;ON;;;;;N;;;;; +23AE;INTEGRAL EXTENSION;Sm;0;ON;;;;;N;;;;; +23AF;HORIZONTAL LINE EXTENSION;Sm;0;ON;;;;;N;;;;; +23B0;UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;; +23B1;UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;; +23B2;SUMMATION TOP;Sm;0;ON;;;;;N;;;;; +23B3;SUMMATION BOTTOM;Sm;0;ON;;;;;N;;;;; +23B4;TOP SQUARE BRACKET;So;0;ON;;;;;N;;;;; +23B5;BOTTOM SQUARE BRACKET;So;0;ON;;;;;N;;;;; +23B6;BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET;So;0;ON;;;;;N;;;;; +23B7;RADICAL SYMBOL BOTTOM;So;0;ON;;;;;N;;;;; +23B8;LEFT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;; +23B9;RIGHT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;; +23BA;HORIZONTAL SCAN LINE-1;So;0;ON;;;;;N;;;;; +23BB;HORIZONTAL SCAN LINE-3;So;0;ON;;;;;N;;;;; +23BC;HORIZONTAL SCAN LINE-7;So;0;ON;;;;;N;;;;; +23BD;HORIZONTAL SCAN LINE-9;So;0;ON;;;;;N;;;;; +23BE;DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT;So;0;ON;;;;;N;;;;; +23BF;DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT;So;0;ON;;;;;N;;;;; +23C0;DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE;So;0;ON;;;;;N;;;;; +23C1;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE;So;0;ON;;;;;N;;;;; +23C2;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE;So;0;ON;;;;;N;;;;; +23C3;DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE;So;0;ON;;;;;N;;;;; +23C4;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE;So;0;ON;;;;;N;;;;; +23C5;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE;So;0;ON;;;;;N;;;;; +23C6;DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE;So;0;ON;;;;;N;;;;; +23C7;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE;So;0;ON;;;;;N;;;;; +23C8;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE;So;0;ON;;;;;N;;;;; +23C9;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;;;;; +23CA;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;;;;; +23CB;DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT;So;0;ON;;;;;N;;;;; +23CC;DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT;So;0;ON;;;;;N;;;;; +23CD;SQUARE FOOT;So;0;ON;;;;;N;;;;; +23CE;RETURN SYMBOL;So;0;ON;;;;;N;;;;; +23CF;EJECT SYMBOL;So;0;ON;;;;;N;;;;; +23D0;VERTICAL LINE EXTENSION;So;0;ON;;;;;N;;;;; +23D1;METRICAL BREVE;So;0;ON;;;;;N;;;;; +23D2;METRICAL LONG OVER SHORT;So;0;ON;;;;;N;;;;; +23D3;METRICAL SHORT OVER LONG;So;0;ON;;;;;N;;;;; +23D4;METRICAL LONG OVER TWO SHORTS;So;0;ON;;;;;N;;;;; +23D5;METRICAL TWO SHORTS OVER LONG;So;0;ON;;;;;N;;;;; +23D6;METRICAL TWO SHORTS JOINED;So;0;ON;;;;;N;;;;; +23D7;METRICAL TRISEME;So;0;ON;;;;;N;;;;; +23D8;METRICAL TETRASEME;So;0;ON;;;;;N;;;;; +23D9;METRICAL PENTASEME;So;0;ON;;;;;N;;;;; +23DA;EARTH GROUND;So;0;ON;;;;;N;;;;; +23DB;FUSE;So;0;ON;;;;;N;;;;; +23DC;TOP PARENTHESIS;Sm;0;ON;;;;;N;;;;; +23DD;BOTTOM PARENTHESIS;Sm;0;ON;;;;;N;;;;; +23DE;TOP CURLY BRACKET;Sm;0;ON;;;;;N;;;;; +23DF;BOTTOM CURLY BRACKET;Sm;0;ON;;;;;N;;;;; +23E0;TOP TORTOISE SHELL BRACKET;Sm;0;ON;;;;;N;;;;; +23E1;BOTTOM TORTOISE SHELL BRACKET;Sm;0;ON;;;;;N;;;;; +23E2;WHITE TRAPEZIUM;So;0;ON;;;;;N;;;;; +23E3;BENZENE RING WITH CIRCLE;So;0;ON;;;;;N;;;;; +23E4;STRAIGHTNESS;So;0;ON;;;;;N;;;;; +23E5;FLATNESS;So;0;ON;;;;;N;;;;; +23E6;AC CURRENT;So;0;ON;;;;;N;;;;; +23E7;ELECTRICAL INTERSECTION;So;0;ON;;;;;N;;;;; +23E8;DECIMAL EXPONENT SYMBOL;So;0;ON;;;;;N;;;;; +23E9;BLACK RIGHT-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;; +23EA;BLACK LEFT-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;; +23EB;BLACK UP-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;; +23EC;BLACK DOWN-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;; +23ED;BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR;So;0;ON;;;;;N;;;;; +23EE;BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR;So;0;ON;;;;;N;;;;; +23EF;BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR;So;0;ON;;;;;N;;;;; +23F0;ALARM CLOCK;So;0;ON;;;;;N;;;;; +23F1;STOPWATCH;So;0;ON;;;;;N;;;;; +23F2;TIMER CLOCK;So;0;ON;;;;;N;;;;; +23F3;HOURGLASS WITH FLOWING SAND;So;0;ON;;;;;N;;;;; +23F4;BLACK MEDIUM LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; +23F5;BLACK MEDIUM RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; +23F6;BLACK MEDIUM UP-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; +23F7;BLACK MEDIUM DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; +23F8;DOUBLE VERTICAL BAR;So;0;ON;;;;;N;;;;; +23F9;BLACK SQUARE FOR STOP;So;0;ON;;;;;N;;;;; +23FA;BLACK CIRCLE FOR RECORD;So;0;ON;;;;;N;;;;; +23FB;POWER SYMBOL;So;0;ON;;;;;N;;;;; +23FC;POWER ON-OFF SYMBOL;So;0;ON;;;;;N;;;;; +23FD;POWER ON SYMBOL;So;0;ON;;;;;N;;;;; +23FE;POWER SLEEP SYMBOL;So;0;ON;;;;;N;;;;; +23FF;OBSERVER EYE SYMBOL;So;0;ON;;;;;N;;;;; +2400;SYMBOL FOR NULL;So;0;ON;;;;;N;GRAPHIC FOR NULL;;;; +2401;SYMBOL FOR START OF HEADING;So;0;ON;;;;;N;GRAPHIC FOR START OF HEADING;;;; +2402;SYMBOL FOR START OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR START OF TEXT;;;; +2403;SYMBOL FOR END OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR END OF TEXT;;;; +2404;SYMBOL FOR END OF TRANSMISSION;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION;;;; +2405;SYMBOL FOR ENQUIRY;So;0;ON;;;;;N;GRAPHIC FOR ENQUIRY;;;; +2406;SYMBOL FOR ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR ACKNOWLEDGE;;;; +2407;SYMBOL FOR BELL;So;0;ON;;;;;N;GRAPHIC FOR BELL;;;; +2408;SYMBOL FOR BACKSPACE;So;0;ON;;;;;N;GRAPHIC FOR BACKSPACE;;;; +2409;SYMBOL FOR HORIZONTAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR HORIZONTAL TABULATION;;;; +240A;SYMBOL FOR LINE FEED;So;0;ON;;;;;N;GRAPHIC FOR LINE FEED;;;; +240B;SYMBOL FOR VERTICAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR VERTICAL TABULATION;;;; +240C;SYMBOL FOR FORM FEED;So;0;ON;;;;;N;GRAPHIC FOR FORM FEED;;;; +240D;SYMBOL FOR CARRIAGE RETURN;So;0;ON;;;;;N;GRAPHIC FOR CARRIAGE RETURN;;;; +240E;SYMBOL FOR SHIFT OUT;So;0;ON;;;;;N;GRAPHIC FOR SHIFT OUT;;;; +240F;SYMBOL FOR SHIFT IN;So;0;ON;;;;;N;GRAPHIC FOR SHIFT IN;;;; +2410;SYMBOL FOR DATA LINK ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR DATA LINK ESCAPE;;;; +2411;SYMBOL FOR DEVICE CONTROL ONE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL ONE;;;; +2412;SYMBOL FOR DEVICE CONTROL TWO;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL TWO;;;; +2413;SYMBOL FOR DEVICE CONTROL THREE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL THREE;;;; +2414;SYMBOL FOR DEVICE CONTROL FOUR;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL FOUR;;;; +2415;SYMBOL FOR NEGATIVE ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR NEGATIVE ACKNOWLEDGE;;;; +2416;SYMBOL FOR SYNCHRONOUS IDLE;So;0;ON;;;;;N;GRAPHIC FOR SYNCHRONOUS IDLE;;;; +2417;SYMBOL FOR END OF TRANSMISSION BLOCK;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION BLOCK;;;; +2418;SYMBOL FOR CANCEL;So;0;ON;;;;;N;GRAPHIC FOR CANCEL;;;; +2419;SYMBOL FOR END OF MEDIUM;So;0;ON;;;;;N;GRAPHIC FOR END OF MEDIUM;;;; +241A;SYMBOL FOR SUBSTITUTE;So;0;ON;;;;;N;GRAPHIC FOR SUBSTITUTE;;;; +241B;SYMBOL FOR ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR ESCAPE;;;; +241C;SYMBOL FOR FILE SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR FILE SEPARATOR;;;; +241D;SYMBOL FOR GROUP SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR GROUP SEPARATOR;;;; +241E;SYMBOL FOR RECORD SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR RECORD SEPARATOR;;;; +241F;SYMBOL FOR UNIT SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR UNIT SEPARATOR;;;; +2420;SYMBOL FOR SPACE;So;0;ON;;;;;N;GRAPHIC FOR SPACE;;;; +2421;SYMBOL FOR DELETE;So;0;ON;;;;;N;GRAPHIC FOR DELETE;;;; +2422;BLANK SYMBOL;So;0;ON;;;;;N;BLANK;;;; +2423;OPEN BOX;So;0;ON;;;;;N;;;;; +2424;SYMBOL FOR NEWLINE;So;0;ON;;;;;N;GRAPHIC FOR NEWLINE;;;; +2425;SYMBOL FOR DELETE FORM TWO;So;0;ON;;;;;N;;;;; +2426;SYMBOL FOR SUBSTITUTE FORM TWO;So;0;ON;;;;;N;;;;; +2427;SYMBOL FOR DELETE SQUARE CHECKER BOARD FORM;So;0;ON;;;;;N;;;;; +2428;SYMBOL FOR DELETE RECTANGULAR CHECKER BOARD FORM;So;0;ON;;;;;N;;;;; +2429;SYMBOL FOR DELETE MEDIUM SHADE FORM;So;0;ON;;;;;N;;;;; +2440;OCR HOOK;So;0;ON;;;;;N;;;;; +2441;OCR CHAIR;So;0;ON;;;;;N;;;;; +2442;OCR FORK;So;0;ON;;;;;N;;;;; +2443;OCR INVERTED FORK;So;0;ON;;;;;N;;;;; +2444;OCR BELT BUCKLE;So;0;ON;;;;;N;;;;; +2445;OCR BOW TIE;So;0;ON;;;;;N;;;;; +2446;OCR BRANCH BANK IDENTIFICATION;So;0;ON;;;;;N;;;;; +2447;OCR AMOUNT OF CHECK;So;0;ON;;;;;N;;;;; +2448;OCR DASH;So;0;ON;;;;;N;;;;; +2449;OCR CUSTOMER ACCOUNT NUMBER;So;0;ON;;;;;N;;;;; +244A;OCR DOUBLE BACKSLASH;So;0;ON;;;;;N;;;;; +2460;CIRCLED DIGIT ONE;No;0;ON; 0031;;1;1;N;;;;; +2461;CIRCLED DIGIT TWO;No;0;ON; 0032;;2;2;N;;;;; +2462;CIRCLED DIGIT THREE;No;0;ON; 0033;;3;3;N;;;;; +2463;CIRCLED DIGIT FOUR;No;0;ON; 0034;;4;4;N;;;;; +2464;CIRCLED DIGIT FIVE;No;0;ON; 0035;;5;5;N;;;;; +2465;CIRCLED DIGIT SIX;No;0;ON; 0036;;6;6;N;;;;; +2466;CIRCLED DIGIT SEVEN;No;0;ON; 0037;;7;7;N;;;;; +2467;CIRCLED DIGIT EIGHT;No;0;ON; 0038;;8;8;N;;;;; +2468;CIRCLED DIGIT NINE;No;0;ON; 0039;;9;9;N;;;;; +2469;CIRCLED NUMBER TEN;No;0;ON; 0031 0030;;;10;N;;;;; +246A;CIRCLED NUMBER ELEVEN;No;0;ON; 0031 0031;;;11;N;;;;; +246B;CIRCLED NUMBER TWELVE;No;0;ON; 0031 0032;;;12;N;;;;; +246C;CIRCLED NUMBER THIRTEEN;No;0;ON; 0031 0033;;;13;N;;;;; +246D;CIRCLED NUMBER FOURTEEN;No;0;ON; 0031 0034;;;14;N;;;;; +246E;CIRCLED NUMBER FIFTEEN;No;0;ON; 0031 0035;;;15;N;;;;; +246F;CIRCLED NUMBER SIXTEEN;No;0;ON; 0031 0036;;;16;N;;;;; +2470;CIRCLED NUMBER SEVENTEEN;No;0;ON; 0031 0037;;;17;N;;;;; +2471;CIRCLED NUMBER EIGHTEEN;No;0;ON; 0031 0038;;;18;N;;;;; +2472;CIRCLED NUMBER NINETEEN;No;0;ON; 0031 0039;;;19;N;;;;; +2473;CIRCLED NUMBER TWENTY;No;0;ON; 0032 0030;;;20;N;;;;; +2474;PARENTHESIZED DIGIT ONE;No;0;ON; 0028 0031 0029;;1;1;N;;;;; +2475;PARENTHESIZED DIGIT TWO;No;0;ON; 0028 0032 0029;;2;2;N;;;;; +2476;PARENTHESIZED DIGIT THREE;No;0;ON; 0028 0033 0029;;3;3;N;;;;; +2477;PARENTHESIZED DIGIT FOUR;No;0;ON; 0028 0034 0029;;4;4;N;;;;; +2478;PARENTHESIZED DIGIT FIVE;No;0;ON; 0028 0035 0029;;5;5;N;;;;; +2479;PARENTHESIZED DIGIT SIX;No;0;ON; 0028 0036 0029;;6;6;N;;;;; +247A;PARENTHESIZED DIGIT SEVEN;No;0;ON; 0028 0037 0029;;7;7;N;;;;; +247B;PARENTHESIZED DIGIT EIGHT;No;0;ON; 0028 0038 0029;;8;8;N;;;;; +247C;PARENTHESIZED DIGIT NINE;No;0;ON; 0028 0039 0029;;9;9;N;;;;; +247D;PARENTHESIZED NUMBER TEN;No;0;ON; 0028 0031 0030 0029;;;10;N;;;;; +247E;PARENTHESIZED NUMBER ELEVEN;No;0;ON; 0028 0031 0031 0029;;;11;N;;;;; +247F;PARENTHESIZED NUMBER TWELVE;No;0;ON; 0028 0031 0032 0029;;;12;N;;;;; +2480;PARENTHESIZED NUMBER THIRTEEN;No;0;ON; 0028 0031 0033 0029;;;13;N;;;;; +2481;PARENTHESIZED NUMBER FOURTEEN;No;0;ON; 0028 0031 0034 0029;;;14;N;;;;; +2482;PARENTHESIZED NUMBER FIFTEEN;No;0;ON; 0028 0031 0035 0029;;;15;N;;;;; +2483;PARENTHESIZED NUMBER SIXTEEN;No;0;ON; 0028 0031 0036 0029;;;16;N;;;;; +2484;PARENTHESIZED NUMBER SEVENTEEN;No;0;ON; 0028 0031 0037 0029;;;17;N;;;;; +2485;PARENTHESIZED NUMBER EIGHTEEN;No;0;ON; 0028 0031 0038 0029;;;18;N;;;;; +2486;PARENTHESIZED NUMBER NINETEEN;No;0;ON; 0028 0031 0039 0029;;;19;N;;;;; +2487;PARENTHESIZED NUMBER TWENTY;No;0;ON; 0028 0032 0030 0029;;;20;N;;;;; +2488;DIGIT ONE FULL STOP;No;0;EN; 0031 002E;;1;1;N;DIGIT ONE PERIOD;;;; +2489;DIGIT TWO FULL STOP;No;0;EN; 0032 002E;;2;2;N;DIGIT TWO PERIOD;;;; +248A;DIGIT THREE FULL STOP;No;0;EN; 0033 002E;;3;3;N;DIGIT THREE PERIOD;;;; +248B;DIGIT FOUR FULL STOP;No;0;EN; 0034 002E;;4;4;N;DIGIT FOUR PERIOD;;;; +248C;DIGIT FIVE FULL STOP;No;0;EN; 0035 002E;;5;5;N;DIGIT FIVE PERIOD;;;; +248D;DIGIT SIX FULL STOP;No;0;EN; 0036 002E;;6;6;N;DIGIT SIX PERIOD;;;; +248E;DIGIT SEVEN FULL STOP;No;0;EN; 0037 002E;;7;7;N;DIGIT SEVEN PERIOD;;;; +248F;DIGIT EIGHT FULL STOP;No;0;EN; 0038 002E;;8;8;N;DIGIT EIGHT PERIOD;;;; +2490;DIGIT NINE FULL STOP;No;0;EN; 0039 002E;;9;9;N;DIGIT NINE PERIOD;;;; +2491;NUMBER TEN FULL STOP;No;0;EN; 0031 0030 002E;;;10;N;NUMBER TEN PERIOD;;;; +2492;NUMBER ELEVEN FULL STOP;No;0;EN; 0031 0031 002E;;;11;N;NUMBER ELEVEN PERIOD;;;; +2493;NUMBER TWELVE FULL STOP;No;0;EN; 0031 0032 002E;;;12;N;NUMBER TWELVE PERIOD;;;; +2494;NUMBER THIRTEEN FULL STOP;No;0;EN; 0031 0033 002E;;;13;N;NUMBER THIRTEEN PERIOD;;;; +2495;NUMBER FOURTEEN FULL STOP;No;0;EN; 0031 0034 002E;;;14;N;NUMBER FOURTEEN PERIOD;;;; +2496;NUMBER FIFTEEN FULL STOP;No;0;EN; 0031 0035 002E;;;15;N;NUMBER FIFTEEN PERIOD;;;; +2497;NUMBER SIXTEEN FULL STOP;No;0;EN; 0031 0036 002E;;;16;N;NUMBER SIXTEEN PERIOD;;;; +2498;NUMBER SEVENTEEN FULL STOP;No;0;EN; 0031 0037 002E;;;17;N;NUMBER SEVENTEEN PERIOD;;;; +2499;NUMBER EIGHTEEN FULL STOP;No;0;EN; 0031 0038 002E;;;18;N;NUMBER EIGHTEEN PERIOD;;;; +249A;NUMBER NINETEEN FULL STOP;No;0;EN; 0031 0039 002E;;;19;N;NUMBER NINETEEN PERIOD;;;; +249B;NUMBER TWENTY FULL STOP;No;0;EN; 0032 0030 002E;;;20;N;NUMBER TWENTY PERIOD;;;; +249C;PARENTHESIZED LATIN SMALL LETTER A;So;0;L; 0028 0061 0029;;;;N;;;;; +249D;PARENTHESIZED LATIN SMALL LETTER B;So;0;L; 0028 0062 0029;;;;N;;;;; +249E;PARENTHESIZED LATIN SMALL LETTER C;So;0;L; 0028 0063 0029;;;;N;;;;; +249F;PARENTHESIZED LATIN SMALL LETTER D;So;0;L; 0028 0064 0029;;;;N;;;;; +24A0;PARENTHESIZED LATIN SMALL LETTER E;So;0;L; 0028 0065 0029;;;;N;;;;; +24A1;PARENTHESIZED LATIN SMALL LETTER F;So;0;L; 0028 0066 0029;;;;N;;;;; +24A2;PARENTHESIZED LATIN SMALL LETTER G;So;0;L; 0028 0067 0029;;;;N;;;;; +24A3;PARENTHESIZED LATIN SMALL LETTER H;So;0;L; 0028 0068 0029;;;;N;;;;; +24A4;PARENTHESIZED LATIN SMALL LETTER I;So;0;L; 0028 0069 0029;;;;N;;;;; +24A5;PARENTHESIZED LATIN SMALL LETTER J;So;0;L; 0028 006A 0029;;;;N;;;;; +24A6;PARENTHESIZED LATIN SMALL LETTER K;So;0;L; 0028 006B 0029;;;;N;;;;; +24A7;PARENTHESIZED LATIN SMALL LETTER L;So;0;L; 0028 006C 0029;;;;N;;;;; +24A8;PARENTHESIZED LATIN SMALL LETTER M;So;0;L; 0028 006D 0029;;;;N;;;;; +24A9;PARENTHESIZED LATIN SMALL LETTER N;So;0;L; 0028 006E 0029;;;;N;;;;; +24AA;PARENTHESIZED LATIN SMALL LETTER O;So;0;L; 0028 006F 0029;;;;N;;;;; +24AB;PARENTHESIZED LATIN SMALL LETTER P;So;0;L; 0028 0070 0029;;;;N;;;;; +24AC;PARENTHESIZED LATIN SMALL LETTER Q;So;0;L; 0028 0071 0029;;;;N;;;;; +24AD;PARENTHESIZED LATIN SMALL LETTER R;So;0;L; 0028 0072 0029;;;;N;;;;; +24AE;PARENTHESIZED LATIN SMALL LETTER S;So;0;L; 0028 0073 0029;;;;N;;;;; +24AF;PARENTHESIZED LATIN SMALL LETTER T;So;0;L; 0028 0074 0029;;;;N;;;;; +24B0;PARENTHESIZED LATIN SMALL LETTER U;So;0;L; 0028 0075 0029;;;;N;;;;; +24B1;PARENTHESIZED LATIN SMALL LETTER V;So;0;L; 0028 0076 0029;;;;N;;;;; +24B2;PARENTHESIZED LATIN SMALL LETTER W;So;0;L; 0028 0077 0029;;;;N;;;;; +24B3;PARENTHESIZED LATIN SMALL LETTER X;So;0;L; 0028 0078 0029;;;;N;;;;; +24B4;PARENTHESIZED LATIN SMALL LETTER Y;So;0;L; 0028 0079 0029;;;;N;;;;; +24B5;PARENTHESIZED LATIN SMALL LETTER Z;So;0;L; 0028 007A 0029;;;;N;;;;; +24B6;CIRCLED LATIN CAPITAL LETTER A;So;0;L; 0041;;;;N;;;;24D0; +24B7;CIRCLED LATIN CAPITAL LETTER B;So;0;L; 0042;;;;N;;;;24D1; +24B8;CIRCLED LATIN CAPITAL LETTER C;So;0;L; 0043;;;;N;;;;24D2; +24B9;CIRCLED LATIN CAPITAL LETTER D;So;0;L; 0044;;;;N;;;;24D3; +24BA;CIRCLED LATIN CAPITAL LETTER E;So;0;L; 0045;;;;N;;;;24D4; +24BB;CIRCLED LATIN CAPITAL LETTER F;So;0;L; 0046;;;;N;;;;24D5; +24BC;CIRCLED LATIN CAPITAL LETTER G;So;0;L; 0047;;;;N;;;;24D6; +24BD;CIRCLED LATIN CAPITAL LETTER H;So;0;L; 0048;;;;N;;;;24D7; +24BE;CIRCLED LATIN CAPITAL LETTER I;So;0;L; 0049;;;;N;;;;24D8; +24BF;CIRCLED LATIN CAPITAL LETTER J;So;0;L; 004A;;;;N;;;;24D9; +24C0;CIRCLED LATIN CAPITAL LETTER K;So;0;L; 004B;;;;N;;;;24DA; +24C1;CIRCLED LATIN CAPITAL LETTER L;So;0;L; 004C;;;;N;;;;24DB; +24C2;CIRCLED LATIN CAPITAL LETTER M;So;0;L; 004D;;;;N;;;;24DC; +24C3;CIRCLED LATIN CAPITAL LETTER N;So;0;L; 004E;;;;N;;;;24DD; +24C4;CIRCLED LATIN CAPITAL LETTER O;So;0;L; 004F;;;;N;;;;24DE; +24C5;CIRCLED LATIN CAPITAL LETTER P;So;0;L; 0050;;;;N;;;;24DF; +24C6;CIRCLED LATIN CAPITAL LETTER Q;So;0;L; 0051;;;;N;;;;24E0; +24C7;CIRCLED LATIN CAPITAL LETTER R;So;0;L; 0052;;;;N;;;;24E1; +24C8;CIRCLED LATIN CAPITAL LETTER S;So;0;L; 0053;;;;N;;;;24E2; +24C9;CIRCLED LATIN CAPITAL LETTER T;So;0;L; 0054;;;;N;;;;24E3; +24CA;CIRCLED LATIN CAPITAL LETTER U;So;0;L; 0055;;;;N;;;;24E4; +24CB;CIRCLED LATIN CAPITAL LETTER V;So;0;L; 0056;;;;N;;;;24E5; +24CC;CIRCLED LATIN CAPITAL LETTER W;So;0;L; 0057;;;;N;;;;24E6; +24CD;CIRCLED LATIN CAPITAL LETTER X;So;0;L; 0058;;;;N;;;;24E7; +24CE;CIRCLED LATIN CAPITAL LETTER Y;So;0;L; 0059;;;;N;;;;24E8; +24CF;CIRCLED LATIN CAPITAL LETTER Z;So;0;L; 005A;;;;N;;;;24E9; +24D0;CIRCLED LATIN SMALL LETTER A;So;0;L; 0061;;;;N;;;24B6;;24B6 +24D1;CIRCLED LATIN SMALL LETTER B;So;0;L; 0062;;;;N;;;24B7;;24B7 +24D2;CIRCLED LATIN SMALL LETTER C;So;0;L; 0063;;;;N;;;24B8;;24B8 +24D3;CIRCLED LATIN SMALL LETTER D;So;0;L; 0064;;;;N;;;24B9;;24B9 +24D4;CIRCLED LATIN SMALL LETTER E;So;0;L; 0065;;;;N;;;24BA;;24BA +24D5;CIRCLED LATIN SMALL LETTER F;So;0;L; 0066;;;;N;;;24BB;;24BB +24D6;CIRCLED LATIN SMALL LETTER G;So;0;L; 0067;;;;N;;;24BC;;24BC +24D7;CIRCLED LATIN SMALL LETTER H;So;0;L; 0068;;;;N;;;24BD;;24BD +24D8;CIRCLED LATIN SMALL LETTER I;So;0;L; 0069;;;;N;;;24BE;;24BE +24D9;CIRCLED LATIN SMALL LETTER J;So;0;L; 006A;;;;N;;;24BF;;24BF +24DA;CIRCLED LATIN SMALL LETTER K;So;0;L; 006B;;;;N;;;24C0;;24C0 +24DB;CIRCLED LATIN SMALL LETTER L;So;0;L; 006C;;;;N;;;24C1;;24C1 +24DC;CIRCLED LATIN SMALL LETTER M;So;0;L; 006D;;;;N;;;24C2;;24C2 +24DD;CIRCLED LATIN SMALL LETTER N;So;0;L; 006E;;;;N;;;24C3;;24C3 +24DE;CIRCLED LATIN SMALL LETTER O;So;0;L; 006F;;;;N;;;24C4;;24C4 +24DF;CIRCLED LATIN SMALL LETTER P;So;0;L; 0070;;;;N;;;24C5;;24C5 +24E0;CIRCLED LATIN SMALL LETTER Q;So;0;L; 0071;;;;N;;;24C6;;24C6 +24E1;CIRCLED LATIN SMALL LETTER R;So;0;L; 0072;;;;N;;;24C7;;24C7 +24E2;CIRCLED LATIN SMALL LETTER S;So;0;L; 0073;;;;N;;;24C8;;24C8 +24E3;CIRCLED LATIN SMALL LETTER T;So;0;L; 0074;;;;N;;;24C9;;24C9 +24E4;CIRCLED LATIN SMALL LETTER U;So;0;L; 0075;;;;N;;;24CA;;24CA +24E5;CIRCLED LATIN SMALL LETTER V;So;0;L; 0076;;;;N;;;24CB;;24CB +24E6;CIRCLED LATIN SMALL LETTER W;So;0;L; 0077;;;;N;;;24CC;;24CC +24E7;CIRCLED LATIN SMALL LETTER X;So;0;L; 0078;;;;N;;;24CD;;24CD +24E8;CIRCLED LATIN SMALL LETTER Y;So;0;L; 0079;;;;N;;;24CE;;24CE +24E9;CIRCLED LATIN SMALL LETTER Z;So;0;L; 007A;;;;N;;;24CF;;24CF +24EA;CIRCLED DIGIT ZERO;No;0;ON; 0030;;0;0;N;;;;; +24EB;NEGATIVE CIRCLED NUMBER ELEVEN;No;0;ON;;;;11;N;;;;; +24EC;NEGATIVE CIRCLED NUMBER TWELVE;No;0;ON;;;;12;N;;;;; +24ED;NEGATIVE CIRCLED NUMBER THIRTEEN;No;0;ON;;;;13;N;;;;; +24EE;NEGATIVE CIRCLED NUMBER FOURTEEN;No;0;ON;;;;14;N;;;;; +24EF;NEGATIVE CIRCLED NUMBER FIFTEEN;No;0;ON;;;;15;N;;;;; +24F0;NEGATIVE CIRCLED NUMBER SIXTEEN;No;0;ON;;;;16;N;;;;; +24F1;NEGATIVE CIRCLED NUMBER SEVENTEEN;No;0;ON;;;;17;N;;;;; +24F2;NEGATIVE CIRCLED NUMBER EIGHTEEN;No;0;ON;;;;18;N;;;;; +24F3;NEGATIVE CIRCLED NUMBER NINETEEN;No;0;ON;;;;19;N;;;;; +24F4;NEGATIVE CIRCLED NUMBER TWENTY;No;0;ON;;;;20;N;;;;; +24F5;DOUBLE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;;;;; +24F6;DOUBLE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;;;;; +24F7;DOUBLE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;;;;; +24F8;DOUBLE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;;;;; +24F9;DOUBLE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;;;;; +24FA;DOUBLE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;;;;; +24FB;DOUBLE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;;;;; +24FC;DOUBLE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;;;;; +24FD;DOUBLE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;;;;; +24FE;DOUBLE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;;;;; +24FF;NEGATIVE CIRCLED DIGIT ZERO;No;0;ON;;;0;0;N;;;;; +2500;BOX DRAWINGS LIGHT HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT HORIZONTAL;;;; +2501;BOX DRAWINGS HEAVY HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY HORIZONTAL;;;; +2502;BOX DRAWINGS LIGHT VERTICAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL;;;; +2503;BOX DRAWINGS HEAVY VERTICAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL;;;; +2504;BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH HORIZONTAL;;;; +2505;BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH HORIZONTAL;;;; +2506;BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH VERTICAL;;;; +2507;BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH VERTICAL;;;; +2508;BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH HORIZONTAL;;;; +2509;BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH HORIZONTAL;;;; +250A;BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH VERTICAL;;;; +250B;BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH VERTICAL;;;; +250C;BOX DRAWINGS LIGHT DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND RIGHT;;;; +250D;BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT HEAVY;;;; +250E;BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT LIGHT;;;; +250F;BOX DRAWINGS HEAVY DOWN AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND RIGHT;;;; +2510;BOX DRAWINGS LIGHT DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND LEFT;;;; +2511;BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT HEAVY;;;; +2512;BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT LIGHT;;;; +2513;BOX DRAWINGS HEAVY DOWN AND LEFT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND LEFT;;;; +2514;BOX DRAWINGS LIGHT UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT UP AND RIGHT;;;; +2515;BOX DRAWINGS UP LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT HEAVY;;;; +2516;BOX DRAWINGS UP HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT LIGHT;;;; +2517;BOX DRAWINGS HEAVY UP AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY UP AND RIGHT;;;; +2518;BOX DRAWINGS LIGHT UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT UP AND LEFT;;;; +2519;BOX DRAWINGS UP LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT HEAVY;;;; +251A;BOX DRAWINGS UP HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT LIGHT;;;; +251B;BOX DRAWINGS HEAVY UP AND LEFT;So;0;ON;;;;;N;FORMS HEAVY UP AND LEFT;;;; +251C;BOX DRAWINGS LIGHT VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND RIGHT;;;; +251D;BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND RIGHT HEAVY;;;; +251E;BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT DOWN LIGHT;;;; +251F;BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT UP LIGHT;;;; +2520;BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND RIGHT LIGHT;;;; +2521;BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT UP HEAVY;;;; +2522;BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT DOWN HEAVY;;;; +2523;BOX DRAWINGS HEAVY VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND RIGHT;;;; +2524;BOX DRAWINGS LIGHT VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND LEFT;;;; +2525;BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND LEFT HEAVY;;;; +2526;BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT DOWN LIGHT;;;; +2527;BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT UP LIGHT;;;; +2528;BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND LEFT LIGHT;;;; +2529;BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT UP HEAVY;;;; +252A;BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT DOWN HEAVY;;;; +252B;BOX DRAWINGS HEAVY VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND LEFT;;;; +252C;BOX DRAWINGS LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOWN AND HORIZONTAL;;;; +252D;BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT DOWN LIGHT;;;; +252E;BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT DOWN LIGHT;;;; +252F;BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND HORIZONTAL HEAVY;;;; +2530;BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND HORIZONTAL LIGHT;;;; +2531;BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT DOWN HEAVY;;;; +2532;BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT DOWN HEAVY;;;; +2533;BOX DRAWINGS HEAVY DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOWN AND HORIZONTAL;;;; +2534;BOX DRAWINGS LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT UP AND HORIZONTAL;;;; +2535;BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT UP LIGHT;;;; +2536;BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT UP LIGHT;;;; +2537;BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND HORIZONTAL HEAVY;;;; +2538;BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND HORIZONTAL LIGHT;;;; +2539;BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT UP HEAVY;;;; +253A;BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT UP HEAVY;;;; +253B;BOX DRAWINGS HEAVY UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY UP AND HORIZONTAL;;;; +253C;BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND HORIZONTAL;;;; +253D;BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT VERTICAL LIGHT;;;; +253E;BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT VERTICAL LIGHT;;;; +253F;BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND HORIZONTAL HEAVY;;;; +2540;BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND DOWN HORIZONTAL LIGHT;;;; +2541;BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND UP HORIZONTAL LIGHT;;;; +2542;BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND HORIZONTAL LIGHT;;;; +2543;BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT UP HEAVY AND RIGHT DOWN LIGHT;;;; +2544;BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT UP HEAVY AND LEFT DOWN LIGHT;;;; +2545;BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT DOWN HEAVY AND RIGHT UP LIGHT;;;; +2546;BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT DOWN HEAVY AND LEFT UP LIGHT;;;; +2547;BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND UP HORIZONTAL HEAVY;;;; +2548;BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND DOWN HORIZONTAL HEAVY;;;; +2549;BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT VERTICAL HEAVY;;;; +254A;BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT VERTICAL HEAVY;;;; +254B;BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND HORIZONTAL;;;; +254C;BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH HORIZONTAL;;;; +254D;BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH HORIZONTAL;;;; +254E;BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH VERTICAL;;;; +254F;BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH VERTICAL;;;; +2550;BOX DRAWINGS DOUBLE HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE HORIZONTAL;;;; +2551;BOX DRAWINGS DOUBLE VERTICAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL;;;; +2552;BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND RIGHT DOUBLE;;;; +2553;BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND RIGHT SINGLE;;;; +2554;BOX DRAWINGS DOUBLE DOWN AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND RIGHT;;;; +2555;BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND LEFT DOUBLE;;;; +2556;BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND LEFT SINGLE;;;; +2557;BOX DRAWINGS DOUBLE DOWN AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND LEFT;;;; +2558;BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND RIGHT DOUBLE;;;; +2559;BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND RIGHT SINGLE;;;; +255A;BOX DRAWINGS DOUBLE UP AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE UP AND RIGHT;;;; +255B;BOX DRAWINGS UP SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND LEFT DOUBLE;;;; +255C;BOX DRAWINGS UP DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND LEFT SINGLE;;;; +255D;BOX DRAWINGS DOUBLE UP AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE UP AND LEFT;;;; +255E;BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND RIGHT DOUBLE;;;; +255F;BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND RIGHT SINGLE;;;; +2560;BOX DRAWINGS DOUBLE VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND RIGHT;;;; +2561;BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND LEFT DOUBLE;;;; +2562;BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND LEFT SINGLE;;;; +2563;BOX DRAWINGS DOUBLE VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND LEFT;;;; +2564;BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND HORIZONTAL DOUBLE;;;; +2565;BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND HORIZONTAL SINGLE;;;; +2566;BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND HORIZONTAL;;;; +2567;BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND HORIZONTAL DOUBLE;;;; +2568;BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND HORIZONTAL SINGLE;;;; +2569;BOX DRAWINGS DOUBLE UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE UP AND HORIZONTAL;;;; +256A;BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND HORIZONTAL DOUBLE;;;; +256B;BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND HORIZONTAL SINGLE;;;; +256C;BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND HORIZONTAL;;;; +256D;BOX DRAWINGS LIGHT ARC DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND RIGHT;;;; +256E;BOX DRAWINGS LIGHT ARC DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND LEFT;;;; +256F;BOX DRAWINGS LIGHT ARC UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND LEFT;;;; +2570;BOX DRAWINGS LIGHT ARC UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND RIGHT;;;; +2571;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;;;; +2572;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;;;; +2573;BOX DRAWINGS LIGHT DIAGONAL CROSS;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL CROSS;;;; +2574;BOX DRAWINGS LIGHT LEFT;So;0;ON;;;;;N;FORMS LIGHT LEFT;;;; +2575;BOX DRAWINGS LIGHT UP;So;0;ON;;;;;N;FORMS LIGHT UP;;;; +2576;BOX DRAWINGS LIGHT RIGHT;So;0;ON;;;;;N;FORMS LIGHT RIGHT;;;; +2577;BOX DRAWINGS LIGHT DOWN;So;0;ON;;;;;N;FORMS LIGHT DOWN;;;; +2578;BOX DRAWINGS HEAVY LEFT;So;0;ON;;;;;N;FORMS HEAVY LEFT;;;; +2579;BOX DRAWINGS HEAVY UP;So;0;ON;;;;;N;FORMS HEAVY UP;;;; +257A;BOX DRAWINGS HEAVY RIGHT;So;0;ON;;;;;N;FORMS HEAVY RIGHT;;;; +257B;BOX DRAWINGS HEAVY DOWN;So;0;ON;;;;;N;FORMS HEAVY DOWN;;;; +257C;BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT;So;0;ON;;;;;N;FORMS LIGHT LEFT AND HEAVY RIGHT;;;; +257D;BOX DRAWINGS LIGHT UP AND HEAVY DOWN;So;0;ON;;;;;N;FORMS LIGHT UP AND HEAVY DOWN;;;; +257E;BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT;So;0;ON;;;;;N;FORMS HEAVY LEFT AND LIGHT RIGHT;;;; +257F;BOX DRAWINGS HEAVY UP AND LIGHT DOWN;So;0;ON;;;;;N;FORMS HEAVY UP AND LIGHT DOWN;;;; +2580;UPPER HALF BLOCK;So;0;ON;;;;;N;;;;; +2581;LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +2582;LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +2583;LOWER THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +2584;LOWER HALF BLOCK;So;0;ON;;;;;N;;;;; +2585;LOWER FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +2586;LOWER THREE QUARTERS BLOCK;So;0;ON;;;;;N;LOWER THREE QUARTER BLOCK;;;; +2587;LOWER SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +2588;FULL BLOCK;So;0;ON;;;;;N;;;;; +2589;LEFT SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +258A;LEFT THREE QUARTERS BLOCK;So;0;ON;;;;;N;LEFT THREE QUARTER BLOCK;;;; +258B;LEFT FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +258C;LEFT HALF BLOCK;So;0;ON;;;;;N;;;;; +258D;LEFT THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +258E;LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +258F;LEFT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +2590;RIGHT HALF BLOCK;So;0;ON;;;;;N;;;;; +2591;LIGHT SHADE;So;0;ON;;;;;N;;;;; +2592;MEDIUM SHADE;So;0;ON;;;;;N;;;;; +2593;DARK SHADE;So;0;ON;;;;;N;;;;; +2594;UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +2595;RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +2596;QUADRANT LOWER LEFT;So;0;ON;;;;;N;;;;; +2597;QUADRANT LOWER RIGHT;So;0;ON;;;;;N;;;;; +2598;QUADRANT UPPER LEFT;So;0;ON;;;;;N;;;;; +2599;QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; +259A;QUADRANT UPPER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; +259B;QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT;So;0;ON;;;;;N;;;;; +259C;QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; +259D;QUADRANT UPPER RIGHT;So;0;ON;;;;;N;;;;; +259E;QUADRANT UPPER RIGHT AND LOWER LEFT;So;0;ON;;;;;N;;;;; +259F;QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; +25A0;BLACK SQUARE;So;0;ON;;;;;N;;;;; +25A1;WHITE SQUARE;So;0;ON;;;;;N;;;;; +25A2;WHITE SQUARE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;; +25A3;WHITE SQUARE CONTAINING BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;; +25A4;SQUARE WITH HORIZONTAL FILL;So;0;ON;;;;;N;;;;; +25A5;SQUARE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;; +25A6;SQUARE WITH ORTHOGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;; +25A7;SQUARE WITH UPPER LEFT TO LOWER RIGHT FILL;So;0;ON;;;;;N;;;;; +25A8;SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL;So;0;ON;;;;;N;;;;; +25A9;SQUARE WITH DIAGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;; +25AA;BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;; +25AB;WHITE SMALL SQUARE;So;0;ON;;;;;N;;;;; +25AC;BLACK RECTANGLE;So;0;ON;;;;;N;;;;; +25AD;WHITE RECTANGLE;So;0;ON;;;;;N;;;;; +25AE;BLACK VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;; +25AF;WHITE VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;; +25B0;BLACK PARALLELOGRAM;So;0;ON;;;;;N;;;;; +25B1;WHITE PARALLELOGRAM;So;0;ON;;;;;N;;;;; +25B2;BLACK UP-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING TRIANGLE;;;; +25B3;WHITE UP-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE;;;; +25B4;BLACK UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING SMALL TRIANGLE;;;; +25B5;WHITE UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING SMALL TRIANGLE;;;; +25B6;BLACK RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING TRIANGLE;;;; +25B7;WHITE RIGHT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE RIGHT POINTING TRIANGLE;;;; +25B8;BLACK RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING SMALL TRIANGLE;;;; +25B9;WHITE RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE RIGHT POINTING SMALL TRIANGLE;;;; +25BA;BLACK RIGHT-POINTING POINTER;So;0;ON;;;;;N;BLACK RIGHT POINTING POINTER;;;; +25BB;WHITE RIGHT-POINTING POINTER;So;0;ON;;;;;N;WHITE RIGHT POINTING POINTER;;;; +25BC;BLACK DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING TRIANGLE;;;; +25BD;WHITE DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING TRIANGLE;;;; +25BE;BLACK DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING SMALL TRIANGLE;;;; +25BF;WHITE DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING SMALL TRIANGLE;;;; +25C0;BLACK LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING TRIANGLE;;;; +25C1;WHITE LEFT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE LEFT POINTING TRIANGLE;;;; +25C2;BLACK LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING SMALL TRIANGLE;;;; +25C3;WHITE LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE LEFT POINTING SMALL TRIANGLE;;;; +25C4;BLACK LEFT-POINTING POINTER;So;0;ON;;;;;N;BLACK LEFT POINTING POINTER;;;; +25C5;WHITE LEFT-POINTING POINTER;So;0;ON;;;;;N;WHITE LEFT POINTING POINTER;;;; +25C6;BLACK DIAMOND;So;0;ON;;;;;N;;;;; +25C7;WHITE DIAMOND;So;0;ON;;;;;N;;;;; +25C8;WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND;So;0;ON;;;;;N;;;;; +25C9;FISHEYE;So;0;ON;;;;;N;;;;; +25CA;LOZENGE;So;0;ON;;;;;N;;;;; +25CB;WHITE CIRCLE;So;0;ON;;;;;N;;;;; +25CC;DOTTED CIRCLE;So;0;ON;;;;;N;;;;; +25CD;CIRCLE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;; +25CE;BULLSEYE;So;0;ON;;;;;N;;;;; +25CF;BLACK CIRCLE;So;0;ON;;;;;N;;;;; +25D0;CIRCLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;; +25D1;CIRCLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;; +25D2;CIRCLE WITH LOWER HALF BLACK;So;0;ON;;;;;N;;;;; +25D3;CIRCLE WITH UPPER HALF BLACK;So;0;ON;;;;;N;;;;; +25D4;CIRCLE WITH UPPER RIGHT QUADRANT BLACK;So;0;ON;;;;;N;;;;; +25D5;CIRCLE WITH ALL BUT UPPER LEFT QUADRANT BLACK;So;0;ON;;;;;N;;;;; +25D6;LEFT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; +25D7;RIGHT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; +25D8;INVERSE BULLET;So;0;ON;;;;;N;;;;; +25D9;INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;; +25DA;UPPER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;; +25DB;LOWER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;; +25DC;UPPER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; +25DD;UPPER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; +25DE;LOWER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; +25DF;LOWER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; +25E0;UPPER HALF CIRCLE;So;0;ON;;;;;N;;;;; +25E1;LOWER HALF CIRCLE;So;0;ON;;;;;N;;;;; +25E2;BLACK LOWER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; +25E3;BLACK LOWER LEFT TRIANGLE;So;0;ON;;;;;N;;;;; +25E4;BLACK UPPER LEFT TRIANGLE;So;0;ON;;;;;N;;;;; +25E5;BLACK UPPER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; +25E6;WHITE BULLET;So;0;ON;;;;;N;;;;; +25E7;SQUARE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;; +25E8;SQUARE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;; +25E9;SQUARE WITH UPPER LEFT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;; +25EA;SQUARE WITH LOWER RIGHT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;; +25EB;WHITE SQUARE WITH VERTICAL BISECTING LINE;So;0;ON;;;;;N;;;;; +25EC;WHITE UP-POINTING TRIANGLE WITH DOT;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE WITH DOT;;;; +25ED;UP-POINTING TRIANGLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH LEFT HALF BLACK;;;; +25EE;UP-POINTING TRIANGLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH RIGHT HALF BLACK;;;; +25EF;LARGE CIRCLE;So;0;ON;;;;;N;;;;; +25F0;WHITE SQUARE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;; +25F1;WHITE SQUARE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;; +25F2;WHITE SQUARE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; +25F3;WHITE SQUARE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; +25F4;WHITE CIRCLE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;; +25F5;WHITE CIRCLE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;; +25F6;WHITE CIRCLE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; +25F7;WHITE CIRCLE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; +25F8;UPPER LEFT TRIANGLE;Sm;0;ON;;;;;N;;;;; +25F9;UPPER RIGHT TRIANGLE;Sm;0;ON;;;;;N;;;;; +25FA;LOWER LEFT TRIANGLE;Sm;0;ON;;;;;N;;;;; +25FB;WHITE MEDIUM SQUARE;Sm;0;ON;;;;;N;;;;; +25FC;BLACK MEDIUM SQUARE;Sm;0;ON;;;;;N;;;;; +25FD;WHITE MEDIUM SMALL SQUARE;Sm;0;ON;;;;;N;;;;; +25FE;BLACK MEDIUM SMALL SQUARE;Sm;0;ON;;;;;N;;;;; +25FF;LOWER RIGHT TRIANGLE;Sm;0;ON;;;;;N;;;;; +2600;BLACK SUN WITH RAYS;So;0;ON;;;;;N;;;;; +2601;CLOUD;So;0;ON;;;;;N;;;;; +2602;UMBRELLA;So;0;ON;;;;;N;;;;; +2603;SNOWMAN;So;0;ON;;;;;N;;;;; +2604;COMET;So;0;ON;;;;;N;;;;; +2605;BLACK STAR;So;0;ON;;;;;N;;;;; +2606;WHITE STAR;So;0;ON;;;;;N;;;;; +2607;LIGHTNING;So;0;ON;;;;;N;;;;; +2608;THUNDERSTORM;So;0;ON;;;;;N;;;;; +2609;SUN;So;0;ON;;;;;N;;;;; +260A;ASCENDING NODE;So;0;ON;;;;;N;;;;; +260B;DESCENDING NODE;So;0;ON;;;;;N;;;;; +260C;CONJUNCTION;So;0;ON;;;;;N;;;;; +260D;OPPOSITION;So;0;ON;;;;;N;;;;; +260E;BLACK TELEPHONE;So;0;ON;;;;;N;;;;; +260F;WHITE TELEPHONE;So;0;ON;;;;;N;;;;; +2610;BALLOT BOX;So;0;ON;;;;;N;;;;; +2611;BALLOT BOX WITH CHECK;So;0;ON;;;;;N;;;;; +2612;BALLOT BOX WITH X;So;0;ON;;;;;N;;;;; +2613;SALTIRE;So;0;ON;;;;;N;;;;; +2614;UMBRELLA WITH RAIN DROPS;So;0;ON;;;;;N;;;;; +2615;HOT BEVERAGE;So;0;ON;;;;;N;;;;; +2616;WHITE SHOGI PIECE;So;0;ON;;;;;N;;;;; +2617;BLACK SHOGI PIECE;So;0;ON;;;;;N;;;;; +2618;SHAMROCK;So;0;ON;;;;;N;;;;; +2619;REVERSED ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;; +261A;BLACK LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; +261B;BLACK RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; +261C;WHITE LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; +261D;WHITE UP POINTING INDEX;So;0;ON;;;;;N;;;;; +261E;WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; +261F;WHITE DOWN POINTING INDEX;So;0;ON;;;;;N;;;;; +2620;SKULL AND CROSSBONES;So;0;ON;;;;;N;;;;; +2621;CAUTION SIGN;So;0;ON;;;;;N;;;;; +2622;RADIOACTIVE SIGN;So;0;ON;;;;;N;;;;; +2623;BIOHAZARD SIGN;So;0;ON;;;;;N;;;;; +2624;CADUCEUS;So;0;ON;;;;;N;;;;; +2625;ANKH;So;0;ON;;;;;N;;;;; +2626;ORTHODOX CROSS;So;0;ON;;;;;N;;;;; +2627;CHI RHO;So;0;ON;;;;;N;;;;; +2628;CROSS OF LORRAINE;So;0;ON;;;;;N;;;;; +2629;CROSS OF JERUSALEM;So;0;ON;;;;;N;;;;; +262A;STAR AND CRESCENT;So;0;ON;;;;;N;;;;; +262B;FARSI SYMBOL;So;0;ON;;;;;N;SYMBOL OF IRAN;;;; +262C;ADI SHAKTI;So;0;ON;;;;;N;;;;; +262D;HAMMER AND SICKLE;So;0;ON;;;;;N;;;;; +262E;PEACE SYMBOL;So;0;ON;;;;;N;;;;; +262F;YIN YANG;So;0;ON;;;;;N;;;;; +2630;TRIGRAM FOR HEAVEN;So;0;ON;;;;;N;;;;; +2631;TRIGRAM FOR LAKE;So;0;ON;;;;;N;;;;; +2632;TRIGRAM FOR FIRE;So;0;ON;;;;;N;;;;; +2633;TRIGRAM FOR THUNDER;So;0;ON;;;;;N;;;;; +2634;TRIGRAM FOR WIND;So;0;ON;;;;;N;;;;; +2635;TRIGRAM FOR WATER;So;0;ON;;;;;N;;;;; +2636;TRIGRAM FOR MOUNTAIN;So;0;ON;;;;;N;;;;; +2637;TRIGRAM FOR EARTH;So;0;ON;;;;;N;;;;; +2638;WHEEL OF DHARMA;So;0;ON;;;;;N;;;;; +2639;WHITE FROWNING FACE;So;0;ON;;;;;N;;;;; +263A;WHITE SMILING FACE;So;0;ON;;;;;N;;;;; +263B;BLACK SMILING FACE;So;0;ON;;;;;N;;;;; +263C;WHITE SUN WITH RAYS;So;0;ON;;;;;N;;;;; +263D;FIRST QUARTER MOON;So;0;ON;;;;;N;;;;; +263E;LAST QUARTER MOON;So;0;ON;;;;;N;;;;; +263F;MERCURY;So;0;ON;;;;;N;;;;; +2640;FEMALE SIGN;So;0;ON;;;;;N;;;;; +2641;EARTH;So;0;ON;;;;;N;;;;; +2642;MALE SIGN;So;0;ON;;;;;N;;;;; +2643;JUPITER;So;0;ON;;;;;N;;;;; +2644;SATURN;So;0;ON;;;;;N;;;;; +2645;URANUS;So;0;ON;;;;;N;;;;; +2646;NEPTUNE;So;0;ON;;;;;N;;;;; +2647;PLUTO;So;0;ON;;;;;N;;;;; +2648;ARIES;So;0;ON;;;;;N;;;;; +2649;TAURUS;So;0;ON;;;;;N;;;;; +264A;GEMINI;So;0;ON;;;;;N;;;;; +264B;CANCER;So;0;ON;;;;;N;;;;; +264C;LEO;So;0;ON;;;;;N;;;;; +264D;VIRGO;So;0;ON;;;;;N;;;;; +264E;LIBRA;So;0;ON;;;;;N;;;;; +264F;SCORPIUS;So;0;ON;;;;;N;;;;; +2650;SAGITTARIUS;So;0;ON;;;;;N;;;;; +2651;CAPRICORN;So;0;ON;;;;;N;;;;; +2652;AQUARIUS;So;0;ON;;;;;N;;;;; +2653;PISCES;So;0;ON;;;;;N;;;;; +2654;WHITE CHESS KING;So;0;ON;;;;;N;;;;; +2655;WHITE CHESS QUEEN;So;0;ON;;;;;N;;;;; +2656;WHITE CHESS ROOK;So;0;ON;;;;;N;;;;; +2657;WHITE CHESS BISHOP;So;0;ON;;;;;N;;;;; +2658;WHITE CHESS KNIGHT;So;0;ON;;;;;N;;;;; +2659;WHITE CHESS PAWN;So;0;ON;;;;;N;;;;; +265A;BLACK CHESS KING;So;0;ON;;;;;N;;;;; +265B;BLACK CHESS QUEEN;So;0;ON;;;;;N;;;;; +265C;BLACK CHESS ROOK;So;0;ON;;;;;N;;;;; +265D;BLACK CHESS BISHOP;So;0;ON;;;;;N;;;;; +265E;BLACK CHESS KNIGHT;So;0;ON;;;;;N;;;;; +265F;BLACK CHESS PAWN;So;0;ON;;;;;N;;;;; +2660;BLACK SPADE SUIT;So;0;ON;;;;;N;;;;; +2661;WHITE HEART SUIT;So;0;ON;;;;;N;;;;; +2662;WHITE DIAMOND SUIT;So;0;ON;;;;;N;;;;; +2663;BLACK CLUB SUIT;So;0;ON;;;;;N;;;;; +2664;WHITE SPADE SUIT;So;0;ON;;;;;N;;;;; +2665;BLACK HEART SUIT;So;0;ON;;;;;N;;;;; +2666;BLACK DIAMOND SUIT;So;0;ON;;;;;N;;;;; +2667;WHITE CLUB SUIT;So;0;ON;;;;;N;;;;; +2668;HOT SPRINGS;So;0;ON;;;;;N;;;;; +2669;QUARTER NOTE;So;0;ON;;;;;N;;;;; +266A;EIGHTH NOTE;So;0;ON;;;;;N;;;;; +266B;BEAMED EIGHTH NOTES;So;0;ON;;;;;N;BARRED EIGHTH NOTES;;;; +266C;BEAMED SIXTEENTH NOTES;So;0;ON;;;;;N;BARRED SIXTEENTH NOTES;;;; +266D;MUSIC FLAT SIGN;So;0;ON;;;;;N;FLAT;;;; +266E;MUSIC NATURAL SIGN;So;0;ON;;;;;N;NATURAL;;;; +266F;MUSIC SHARP SIGN;Sm;0;ON;;;;;N;SHARP;;;; +2670;WEST SYRIAC CROSS;So;0;ON;;;;;N;;;;; +2671;EAST SYRIAC CROSS;So;0;ON;;;;;N;;;;; +2672;UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;; +2673;RECYCLING SYMBOL FOR TYPE-1 PLASTICS;So;0;ON;;;;;N;;;;; +2674;RECYCLING SYMBOL FOR TYPE-2 PLASTICS;So;0;ON;;;;;N;;;;; +2675;RECYCLING SYMBOL FOR TYPE-3 PLASTICS;So;0;ON;;;;;N;;;;; +2676;RECYCLING SYMBOL FOR TYPE-4 PLASTICS;So;0;ON;;;;;N;;;;; +2677;RECYCLING SYMBOL FOR TYPE-5 PLASTICS;So;0;ON;;;;;N;;;;; +2678;RECYCLING SYMBOL FOR TYPE-6 PLASTICS;So;0;ON;;;;;N;;;;; +2679;RECYCLING SYMBOL FOR TYPE-7 PLASTICS;So;0;ON;;;;;N;;;;; +267A;RECYCLING SYMBOL FOR GENERIC MATERIALS;So;0;ON;;;;;N;;;;; +267B;BLACK UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;; +267C;RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;; +267D;PARTIALLY-RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;; +267E;PERMANENT PAPER SIGN;So;0;ON;;;;;N;;;;; +267F;WHEELCHAIR SYMBOL;So;0;ON;;;;;N;;;;; +2680;DIE FACE-1;So;0;ON;;;;;N;;;;; +2681;DIE FACE-2;So;0;ON;;;;;N;;;;; +2682;DIE FACE-3;So;0;ON;;;;;N;;;;; +2683;DIE FACE-4;So;0;ON;;;;;N;;;;; +2684;DIE FACE-5;So;0;ON;;;;;N;;;;; +2685;DIE FACE-6;So;0;ON;;;;;N;;;;; +2686;WHITE CIRCLE WITH DOT RIGHT;So;0;ON;;;;;N;;;;; +2687;WHITE CIRCLE WITH TWO DOTS;So;0;ON;;;;;N;;;;; +2688;BLACK CIRCLE WITH WHITE DOT RIGHT;So;0;ON;;;;;N;;;;; +2689;BLACK CIRCLE WITH TWO WHITE DOTS;So;0;ON;;;;;N;;;;; +268A;MONOGRAM FOR YANG;So;0;ON;;;;;N;;;;; +268B;MONOGRAM FOR YIN;So;0;ON;;;;;N;;;;; +268C;DIGRAM FOR GREATER YANG;So;0;ON;;;;;N;;;;; +268D;DIGRAM FOR LESSER YIN;So;0;ON;;;;;N;;;;; +268E;DIGRAM FOR LESSER YANG;So;0;ON;;;;;N;;;;; +268F;DIGRAM FOR GREATER YIN;So;0;ON;;;;;N;;;;; +2690;WHITE FLAG;So;0;ON;;;;;N;;;;; +2691;BLACK FLAG;So;0;ON;;;;;N;;;;; +2692;HAMMER AND PICK;So;0;ON;;;;;N;;;;; +2693;ANCHOR;So;0;ON;;;;;N;;;;; +2694;CROSSED SWORDS;So;0;ON;;;;;N;;;;; +2695;STAFF OF AESCULAPIUS;So;0;ON;;;;;N;;;;; +2696;SCALES;So;0;ON;;;;;N;;;;; +2697;ALEMBIC;So;0;ON;;;;;N;;;;; +2698;FLOWER;So;0;ON;;;;;N;;;;; +2699;GEAR;So;0;ON;;;;;N;;;;; +269A;STAFF OF HERMES;So;0;ON;;;;;N;;;;; +269B;ATOM SYMBOL;So;0;ON;;;;;N;;;;; +269C;FLEUR-DE-LIS;So;0;ON;;;;;N;;;;; +269D;OUTLINED WHITE STAR;So;0;ON;;;;;N;;;;; +269E;THREE LINES CONVERGING RIGHT;So;0;ON;;;;;N;;;;; +269F;THREE LINES CONVERGING LEFT;So;0;ON;;;;;N;;;;; +26A0;WARNING SIGN;So;0;ON;;;;;N;;;;; +26A1;HIGH VOLTAGE SIGN;So;0;ON;;;;;N;;;;; +26A2;DOUBLED FEMALE SIGN;So;0;ON;;;;;N;;;;; +26A3;DOUBLED MALE SIGN;So;0;ON;;;;;N;;;;; +26A4;INTERLOCKED FEMALE AND MALE SIGN;So;0;ON;;;;;N;;;;; +26A5;MALE AND FEMALE SIGN;So;0;ON;;;;;N;;;;; +26A6;MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;; +26A7;MALE WITH STROKE AND MALE AND FEMALE SIGN;So;0;ON;;;;;N;;;;; +26A8;VERTICAL MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;; +26A9;HORIZONTAL MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;; +26AA;MEDIUM WHITE CIRCLE;So;0;ON;;;;;N;;;;; +26AB;MEDIUM BLACK CIRCLE;So;0;ON;;;;;N;;;;; +26AC;MEDIUM SMALL WHITE CIRCLE;So;0;L;;;;;N;;;;; +26AD;MARRIAGE SYMBOL;So;0;ON;;;;;N;;;;; +26AE;DIVORCE SYMBOL;So;0;ON;;;;;N;;;;; +26AF;UNMARRIED PARTNERSHIP SYMBOL;So;0;ON;;;;;N;;;;; +26B0;COFFIN;So;0;ON;;;;;N;;;;; +26B1;FUNERAL URN;So;0;ON;;;;;N;;;;; +26B2;NEUTER;So;0;ON;;;;;N;;;;; +26B3;CERES;So;0;ON;;;;;N;;;;; +26B4;PALLAS;So;0;ON;;;;;N;;;;; +26B5;JUNO;So;0;ON;;;;;N;;;;; +26B6;VESTA;So;0;ON;;;;;N;;;;; +26B7;CHIRON;So;0;ON;;;;;N;;;;; +26B8;BLACK MOON LILITH;So;0;ON;;;;;N;;;;; +26B9;SEXTILE;So;0;ON;;;;;N;;;;; +26BA;SEMISEXTILE;So;0;ON;;;;;N;;;;; +26BB;QUINCUNX;So;0;ON;;;;;N;;;;; +26BC;SESQUIQUADRATE;So;0;ON;;;;;N;;;;; +26BD;SOCCER BALL;So;0;ON;;;;;N;;;;; +26BE;BASEBALL;So;0;ON;;;;;N;;;;; +26BF;SQUARED KEY;So;0;ON;;;;;N;;;;; +26C0;WHITE DRAUGHTS MAN;So;0;ON;;;;;N;;;;; +26C1;WHITE DRAUGHTS KING;So;0;ON;;;;;N;;;;; +26C2;BLACK DRAUGHTS MAN;So;0;ON;;;;;N;;;;; +26C3;BLACK DRAUGHTS KING;So;0;ON;;;;;N;;;;; +26C4;SNOWMAN WITHOUT SNOW;So;0;ON;;;;;N;;;;; +26C5;SUN BEHIND CLOUD;So;0;ON;;;;;N;;;;; +26C6;RAIN;So;0;ON;;;;;N;;;;; +26C7;BLACK SNOWMAN;So;0;ON;;;;;N;;;;; +26C8;THUNDER CLOUD AND RAIN;So;0;ON;;;;;N;;;;; +26C9;TURNED WHITE SHOGI PIECE;So;0;ON;;;;;N;;;;; +26CA;TURNED BLACK SHOGI PIECE;So;0;ON;;;;;N;;;;; +26CB;WHITE DIAMOND IN SQUARE;So;0;ON;;;;;N;;;;; +26CC;CROSSING LANES;So;0;ON;;;;;N;;;;; +26CD;DISABLED CAR;So;0;ON;;;;;N;;;;; +26CE;OPHIUCHUS;So;0;ON;;;;;N;;;;; +26CF;PICK;So;0;ON;;;;;N;;;;; +26D0;CAR SLIDING;So;0;ON;;;;;N;;;;; +26D1;HELMET WITH WHITE CROSS;So;0;ON;;;;;N;;;;; +26D2;CIRCLED CROSSING LANES;So;0;ON;;;;;N;;;;; +26D3;CHAINS;So;0;ON;;;;;N;;;;; +26D4;NO ENTRY;So;0;ON;;;;;N;;;;; +26D5;ALTERNATE ONE-WAY LEFT WAY TRAFFIC;So;0;ON;;;;;N;;;;; +26D6;BLACK TWO-WAY LEFT WAY TRAFFIC;So;0;ON;;;;;N;;;;; +26D7;WHITE TWO-WAY LEFT WAY TRAFFIC;So;0;ON;;;;;N;;;;; +26D8;BLACK LEFT LANE MERGE;So;0;ON;;;;;N;;;;; +26D9;WHITE LEFT LANE MERGE;So;0;ON;;;;;N;;;;; +26DA;DRIVE SLOW SIGN;So;0;ON;;;;;N;;;;; +26DB;HEAVY WHITE DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; +26DC;LEFT CLOSED ENTRY;So;0;ON;;;;;N;;;;; +26DD;SQUARED SALTIRE;So;0;ON;;;;;N;;;;; +26DE;FALLING DIAGONAL IN WHITE CIRCLE IN BLACK SQUARE;So;0;ON;;;;;N;;;;; +26DF;BLACK TRUCK;So;0;ON;;;;;N;;;;; +26E0;RESTRICTED LEFT ENTRY-1;So;0;ON;;;;;N;;;;; +26E1;RESTRICTED LEFT ENTRY-2;So;0;ON;;;;;N;;;;; +26E2;ASTRONOMICAL SYMBOL FOR URANUS;So;0;ON;;;;;N;;;;; +26E3;HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE;So;0;ON;;;;;N;;;;; +26E4;PENTAGRAM;So;0;ON;;;;;N;;;;; +26E5;RIGHT-HANDED INTERLACED PENTAGRAM;So;0;ON;;;;;N;;;;; +26E6;LEFT-HANDED INTERLACED PENTAGRAM;So;0;ON;;;;;N;;;;; +26E7;INVERTED PENTAGRAM;So;0;ON;;;;;N;;;;; +26E8;BLACK CROSS ON SHIELD;So;0;ON;;;;;N;;;;; +26E9;SHINTO SHRINE;So;0;ON;;;;;N;;;;; +26EA;CHURCH;So;0;ON;;;;;N;;;;; +26EB;CASTLE;So;0;ON;;;;;N;;;;; +26EC;HISTORIC SITE;So;0;ON;;;;;N;;;;; +26ED;GEAR WITHOUT HUB;So;0;ON;;;;;N;;;;; +26EE;GEAR WITH HANDLES;So;0;ON;;;;;N;;;;; +26EF;MAP SYMBOL FOR LIGHTHOUSE;So;0;ON;;;;;N;;;;; +26F0;MOUNTAIN;So;0;ON;;;;;N;;;;; +26F1;UMBRELLA ON GROUND;So;0;ON;;;;;N;;;;; +26F2;FOUNTAIN;So;0;ON;;;;;N;;;;; +26F3;FLAG IN HOLE;So;0;ON;;;;;N;;;;; +26F4;FERRY;So;0;ON;;;;;N;;;;; +26F5;SAILBOAT;So;0;ON;;;;;N;;;;; +26F6;SQUARE FOUR CORNERS;So;0;ON;;;;;N;;;;; +26F7;SKIER;So;0;ON;;;;;N;;;;; +26F8;ICE SKATE;So;0;ON;;;;;N;;;;; +26F9;PERSON WITH BALL;So;0;ON;;;;;N;;;;; +26FA;TENT;So;0;ON;;;;;N;;;;; +26FB;JAPANESE BANK SYMBOL;So;0;ON;;;;;N;;;;; +26FC;HEADSTONE GRAVEYARD SYMBOL;So;0;ON;;;;;N;;;;; +26FD;FUEL PUMP;So;0;ON;;;;;N;;;;; +26FE;CUP ON BLACK SQUARE;So;0;ON;;;;;N;;;;; +26FF;WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE;So;0;ON;;;;;N;;;;; +2700;BLACK SAFETY SCISSORS;So;0;ON;;;;;N;;;;; +2701;UPPER BLADE SCISSORS;So;0;ON;;;;;N;;;;; +2702;BLACK SCISSORS;So;0;ON;;;;;N;;;;; +2703;LOWER BLADE SCISSORS;So;0;ON;;;;;N;;;;; +2704;WHITE SCISSORS;So;0;ON;;;;;N;;;;; +2705;WHITE HEAVY CHECK MARK;So;0;ON;;;;;N;;;;; +2706;TELEPHONE LOCATION SIGN;So;0;ON;;;;;N;;;;; +2707;TAPE DRIVE;So;0;ON;;;;;N;;;;; +2708;AIRPLANE;So;0;ON;;;;;N;;;;; +2709;ENVELOPE;So;0;ON;;;;;N;;;;; +270A;RAISED FIST;So;0;ON;;;;;N;;;;; +270B;RAISED HAND;So;0;ON;;;;;N;;;;; +270C;VICTORY HAND;So;0;ON;;;;;N;;;;; +270D;WRITING HAND;So;0;ON;;;;;N;;;;; +270E;LOWER RIGHT PENCIL;So;0;ON;;;;;N;;;;; +270F;PENCIL;So;0;ON;;;;;N;;;;; +2710;UPPER RIGHT PENCIL;So;0;ON;;;;;N;;;;; +2711;WHITE NIB;So;0;ON;;;;;N;;;;; +2712;BLACK NIB;So;0;ON;;;;;N;;;;; +2713;CHECK MARK;So;0;ON;;;;;N;;;;; +2714;HEAVY CHECK MARK;So;0;ON;;;;;N;;;;; +2715;MULTIPLICATION X;So;0;ON;;;;;N;;;;; +2716;HEAVY MULTIPLICATION X;So;0;ON;;;;;N;;;;; +2717;BALLOT X;So;0;ON;;;;;N;;;;; +2718;HEAVY BALLOT X;So;0;ON;;;;;N;;;;; +2719;OUTLINED GREEK CROSS;So;0;ON;;;;;N;;;;; +271A;HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;; +271B;OPEN CENTRE CROSS;So;0;ON;;;;;N;OPEN CENTER CROSS;;;; +271C;HEAVY OPEN CENTRE CROSS;So;0;ON;;;;;N;HEAVY OPEN CENTER CROSS;;;; +271D;LATIN CROSS;So;0;ON;;;;;N;;;;; +271E;SHADOWED WHITE LATIN CROSS;So;0;ON;;;;;N;;;;; +271F;OUTLINED LATIN CROSS;So;0;ON;;;;;N;;;;; +2720;MALTESE CROSS;So;0;ON;;;;;N;;;;; +2721;STAR OF DAVID;So;0;ON;;;;;N;;;;; +2722;FOUR TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +2723;FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +2724;HEAVY FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +2725;FOUR CLUB-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +2726;BLACK FOUR POINTED STAR;So;0;ON;;;;;N;;;;; +2727;WHITE FOUR POINTED STAR;So;0;ON;;;;;N;;;;; +2728;SPARKLES;So;0;ON;;;;;N;;;;; +2729;STRESS OUTLINED WHITE STAR;So;0;ON;;;;;N;;;;; +272A;CIRCLED WHITE STAR;So;0;ON;;;;;N;;;;; +272B;OPEN CENTRE BLACK STAR;So;0;ON;;;;;N;OPEN CENTER BLACK STAR;;;; +272C;BLACK CENTRE WHITE STAR;So;0;ON;;;;;N;BLACK CENTER WHITE STAR;;;; +272D;OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;; +272E;HEAVY OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;; +272F;PINWHEEL STAR;So;0;ON;;;;;N;;;;; +2730;SHADOWED WHITE STAR;So;0;ON;;;;;N;;;;; +2731;HEAVY ASTERISK;So;0;ON;;;;;N;;;;; +2732;OPEN CENTRE ASTERISK;So;0;ON;;;;;N;OPEN CENTER ASTERISK;;;; +2733;EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +2734;EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +2735;EIGHT POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; +2736;SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +2737;EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;; +2738;HEAVY EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;; +2739;TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +273A;SIXTEEN POINTED ASTERISK;So;0;ON;;;;;N;;;;; +273B;TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +273C;OPEN CENTRE TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;OPEN CENTER TEARDROP-SPOKED ASTERISK;;;; +273D;HEAVY TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +273E;SIX PETALLED BLACK AND WHITE FLORETTE;So;0;ON;;;;;N;;;;; +273F;BLACK FLORETTE;So;0;ON;;;;;N;;;;; +2740;WHITE FLORETTE;So;0;ON;;;;;N;;;;; +2741;EIGHT PETALLED OUTLINED BLACK FLORETTE;So;0;ON;;;;;N;;;;; +2742;CIRCLED OPEN CENTRE EIGHT POINTED STAR;So;0;ON;;;;;N;CIRCLED OPEN CENTER EIGHT POINTED STAR;;;; +2743;HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK;So;0;ON;;;;;N;;;;; +2744;SNOWFLAKE;So;0;ON;;;;;N;;;;; +2745;TIGHT TRIFOLIATE SNOWFLAKE;So;0;ON;;;;;N;;;;; +2746;HEAVY CHEVRON SNOWFLAKE;So;0;ON;;;;;N;;;;; +2747;SPARKLE;So;0;ON;;;;;N;;;;; +2748;HEAVY SPARKLE;So;0;ON;;;;;N;;;;; +2749;BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +274A;EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;; +274B;HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;; +274C;CROSS MARK;So;0;ON;;;;;N;;;;; +274D;SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;; +274E;NEGATIVE SQUARED CROSS MARK;So;0;ON;;;;;N;;;;; +274F;LOWER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; +2750;UPPER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; +2751;LOWER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; +2752;UPPER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; +2753;BLACK QUESTION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +2754;WHITE QUESTION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +2755;WHITE EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +2756;BLACK DIAMOND MINUS WHITE X;So;0;ON;;;;;N;;;;; +2757;HEAVY EXCLAMATION MARK SYMBOL;So;0;ON;;;;;N;;;;; +2758;LIGHT VERTICAL BAR;So;0;ON;;;;;N;;;;; +2759;MEDIUM VERTICAL BAR;So;0;ON;;;;;N;;;;; +275A;HEAVY VERTICAL BAR;So;0;ON;;;;;N;;;;; +275B;HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +275C;HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +275D;HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +275E;HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +275F;HEAVY LOW SINGLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +2760;HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +2761;CURVED STEM PARAGRAPH SIGN ORNAMENT;So;0;ON;;;;;N;;;;; +2762;HEAVY EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +2763;HEAVY HEART EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +2764;HEAVY BLACK HEART;So;0;ON;;;;;N;;;;; +2765;ROTATED HEAVY BLACK HEART BULLET;So;0;ON;;;;;N;;;;; +2766;FLORAL HEART;So;0;ON;;;;;N;;;;; +2767;ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;; +2768;MEDIUM LEFT PARENTHESIS ORNAMENT;Ps;0;ON;;;;;Y;;;;; +2769;MEDIUM RIGHT PARENTHESIS ORNAMENT;Pe;0;ON;;;;;Y;;;;; +276A;MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT;Ps;0;ON;;;;;Y;;;;; +276B;MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT;Pe;0;ON;;;;;Y;;;;; +276C;MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;; +276D;MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;; +276E;HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT;Ps;0;ON;;;;;Y;;;;; +276F;HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT;Pe;0;ON;;;;;Y;;;;; +2770;HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;; +2771;HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;; +2772;LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;; +2773;LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;; +2774;MEDIUM LEFT CURLY BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;; +2775;MEDIUM RIGHT CURLY BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;; +2776;DINGBAT NEGATIVE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED DIGIT ONE;;;; +2777;DINGBAT NEGATIVE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED DIGIT TWO;;;; +2778;DINGBAT NEGATIVE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED DIGIT THREE;;;; +2779;DINGBAT NEGATIVE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED DIGIT FOUR;;;; +277A;DINGBAT NEGATIVE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED DIGIT FIVE;;;; +277B;DINGBAT NEGATIVE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED DIGIT SIX;;;; +277C;DINGBAT NEGATIVE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED DIGIT SEVEN;;;; +277D;DINGBAT NEGATIVE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED DIGIT EIGHT;;;; +277E;DINGBAT NEGATIVE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED DIGIT NINE;;;; +277F;DINGBAT NEGATIVE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED NUMBER TEN;;;; +2780;DINGBAT CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;CIRCLED SANS-SERIF DIGIT ONE;;;; +2781;DINGBAT CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;CIRCLED SANS-SERIF DIGIT TWO;;;; +2782;DINGBAT CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;CIRCLED SANS-SERIF DIGIT THREE;;;; +2783;DINGBAT CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;CIRCLED SANS-SERIF DIGIT FOUR;;;; +2784;DINGBAT CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;CIRCLED SANS-SERIF DIGIT FIVE;;;; +2785;DINGBAT CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;CIRCLED SANS-SERIF DIGIT SIX;;;; +2786;DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;CIRCLED SANS-SERIF DIGIT SEVEN;;;; +2787;DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;CIRCLED SANS-SERIF DIGIT EIGHT;;;; +2788;DINGBAT CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;CIRCLED SANS-SERIF DIGIT NINE;;;; +2789;DINGBAT CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;CIRCLED SANS-SERIF NUMBER TEN;;;; +278A;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED SANS-SERIF DIGIT ONE;;;; +278B;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED SANS-SERIF DIGIT TWO;;;; +278C;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED SANS-SERIF DIGIT THREE;;;; +278D;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED SANS-SERIF DIGIT FOUR;;;; +278E;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED SANS-SERIF DIGIT FIVE;;;; +278F;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED SANS-SERIF DIGIT SIX;;;; +2790;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED SANS-SERIF DIGIT SEVEN;;;; +2791;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED SANS-SERIF DIGIT EIGHT;;;; +2792;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED SANS-SERIF DIGIT NINE;;;; +2793;DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED SANS-SERIF NUMBER TEN;;;; +2794;HEAVY WIDE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WIDE-HEADED RIGHT ARROW;;;; +2795;HEAVY PLUS SIGN;So;0;ON;;;;;N;;;;; +2796;HEAVY MINUS SIGN;So;0;ON;;;;;N;;;;; +2797;HEAVY DIVISION SIGN;So;0;ON;;;;;N;;;;; +2798;HEAVY SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT ARROW;;;; +2799;HEAVY RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY RIGHT ARROW;;;; +279A;HEAVY NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT ARROW;;;; +279B;DRAFTING POINT RIGHTWARDS ARROW;So;0;ON;;;;;N;DRAFTING POINT RIGHT ARROW;;;; +279C;HEAVY ROUND-TIPPED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY ROUND-TIPPED RIGHT ARROW;;;; +279D;TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;TRIANGLE-HEADED RIGHT ARROW;;;; +279E;HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TRIANGLE-HEADED RIGHT ARROW;;;; +279F;DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;DASHED TRIANGLE-HEADED RIGHT ARROW;;;; +27A0;HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY DASHED TRIANGLE-HEADED RIGHT ARROW;;;; +27A1;BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK RIGHT ARROW;;;; +27A2;THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D TOP-LIGHTED RIGHT ARROWHEAD;;;; +27A3;THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D BOTTOM-LIGHTED RIGHT ARROWHEAD;;;; +27A4;BLACK RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;BLACK RIGHT ARROWHEAD;;;; +27A5;HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED DOWN AND RIGHT ARROW;;;; +27A6;HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED UP AND RIGHT ARROW;;;; +27A7;SQUAT BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;SQUAT BLACK RIGHT ARROW;;;; +27A8;HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY CONCAVE-POINTED BLACK RIGHT ARROW;;;; +27A9;RIGHT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;RIGHT-SHADED WHITE RIGHT ARROW;;;; +27AA;LEFT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT-SHADED WHITE RIGHT ARROW;;;; +27AB;BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;BACK-TILTED SHADOWED WHITE RIGHT ARROW;;;; +27AC;FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;FRONT-TILTED SHADOWED WHITE RIGHT ARROW;;;; +27AD;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; +27AE;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; +27AF;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; +27B0;CURLY LOOP;So;0;ON;;;;;N;;;;; +27B1;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; +27B2;CIRCLED HEAVY WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;CIRCLED HEAVY WHITE RIGHT ARROW;;;; +27B3;WHITE-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;WHITE-FEATHERED RIGHT ARROW;;;; +27B4;BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED LOWER RIGHT ARROW;;;; +27B5;BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK-FEATHERED RIGHT ARROW;;;; +27B6;BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED UPPER RIGHT ARROW;;;; +27B7;HEAVY BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED LOWER RIGHT ARROW;;;; +27B8;HEAVY BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED RIGHT ARROW;;;; +27B9;HEAVY BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED UPPER RIGHT ARROW;;;; +27BA;TEARDROP-BARBED RIGHTWARDS ARROW;So;0;ON;;;;;N;TEARDROP-BARBED RIGHT ARROW;;;; +27BB;HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TEARDROP-SHANKED RIGHT ARROW;;;; +27BC;WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;WEDGE-TAILED RIGHT ARROW;;;; +27BD;HEAVY WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WEDGE-TAILED RIGHT ARROW;;;; +27BE;OPEN-OUTLINED RIGHTWARDS ARROW;So;0;ON;;;;;N;OPEN-OUTLINED RIGHT ARROW;;;; +27BF;DOUBLE CURLY LOOP;So;0;ON;;;;;N;;;;; +27C0;THREE DIMENSIONAL ANGLE;Sm;0;ON;;;;;Y;;;;; +27C1;WHITE TRIANGLE CONTAINING SMALL WHITE TRIANGLE;Sm;0;ON;;;;;N;;;;; +27C2;PERPENDICULAR;Sm;0;ON;;;;;N;;;;; +27C3;OPEN SUBSET;Sm;0;ON;;;;;Y;;;;; +27C4;OPEN SUPERSET;Sm;0;ON;;;;;Y;;;;; +27C5;LEFT S-SHAPED BAG DELIMITER;Ps;0;ON;;;;;Y;;;;; +27C6;RIGHT S-SHAPED BAG DELIMITER;Pe;0;ON;;;;;Y;;;;; +27C7;OR WITH DOT INSIDE;Sm;0;ON;;;;;N;;;;; +27C8;REVERSE SOLIDUS PRECEDING SUBSET;Sm;0;ON;;;;;Y;;;;; +27C9;SUPERSET PRECEDING SOLIDUS;Sm;0;ON;;;;;Y;;;;; +27CA;VERTICAL BAR WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; +27CB;MATHEMATICAL RISING DIAGONAL;Sm;0;ON;;;;;Y;;;;; +27CC;LONG DIVISION;Sm;0;ON;;;;;Y;;;;; +27CD;MATHEMATICAL FALLING DIAGONAL;Sm;0;ON;;;;;Y;;;;; +27CE;SQUARED LOGICAL AND;Sm;0;ON;;;;;N;;;;; +27CF;SQUARED LOGICAL OR;Sm;0;ON;;;;;N;;;;; +27D0;WHITE DIAMOND WITH CENTRED DOT;Sm;0;ON;;;;;N;;;;; +27D1;AND WITH DOT;Sm;0;ON;;;;;N;;;;; +27D2;ELEMENT OF OPENING UPWARDS;Sm;0;ON;;;;;N;;;;; +27D3;LOWER RIGHT CORNER WITH DOT;Sm;0;ON;;;;;Y;;;;; +27D4;UPPER LEFT CORNER WITH DOT;Sm;0;ON;;;;;Y;;;;; +27D5;LEFT OUTER JOIN;Sm;0;ON;;;;;Y;;;;; +27D6;RIGHT OUTER JOIN;Sm;0;ON;;;;;Y;;;;; +27D7;FULL OUTER JOIN;Sm;0;ON;;;;;N;;;;; +27D8;LARGE UP TACK;Sm;0;ON;;;;;N;;;;; +27D9;LARGE DOWN TACK;Sm;0;ON;;;;;N;;;;; +27DA;LEFT AND RIGHT DOUBLE TURNSTILE;Sm;0;ON;;;;;N;;;;; +27DB;LEFT AND RIGHT TACK;Sm;0;ON;;;;;N;;;;; +27DC;LEFT MULTIMAP;Sm;0;ON;;;;;Y;;;;; +27DD;LONG RIGHT TACK;Sm;0;ON;;;;;Y;;;;; +27DE;LONG LEFT TACK;Sm;0;ON;;;;;Y;;;;; +27DF;UP TACK WITH CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;; +27E0;LOZENGE DIVIDED BY HORIZONTAL RULE;Sm;0;ON;;;;;N;;;;; +27E1;WHITE CONCAVE-SIDED DIAMOND;Sm;0;ON;;;;;N;;;;; +27E2;WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK;Sm;0;ON;;;;;Y;;;;; +27E3;WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK;Sm;0;ON;;;;;Y;;;;; +27E4;WHITE SQUARE WITH LEFTWARDS TICK;Sm;0;ON;;;;;Y;;;;; +27E5;WHITE SQUARE WITH RIGHTWARDS TICK;Sm;0;ON;;;;;Y;;;;; +27E6;MATHEMATICAL LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;;;;; +27E7;MATHEMATICAL RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;;;;; +27E8;MATHEMATICAL LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;; +27E9;MATHEMATICAL RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;; +27EA;MATHEMATICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;; +27EB;MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;; +27EC;MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;;;;; +27ED;MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;;;;; +27EE;MATHEMATICAL LEFT FLATTENED PARENTHESIS;Ps;0;ON;;;;;Y;;;;; +27EF;MATHEMATICAL RIGHT FLATTENED PARENTHESIS;Pe;0;ON;;;;;Y;;;;; +27F0;UPWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;; +27F1;DOWNWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;; +27F2;ANTICLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; +27F3;CLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; +27F4;RIGHT ARROW WITH CIRCLED PLUS;Sm;0;ON;;;;;N;;;;; +27F5;LONG LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +27F6;LONG RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +27F7;LONG LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;; +27F8;LONG LEFTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; +27F9;LONG RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; +27FA;LONG LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; +27FB;LONG LEFTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; +27FC;LONG RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; +27FD;LONG LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; +27FE;LONG RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; +27FF;LONG RIGHTWARDS SQUIGGLE ARROW;Sm;0;ON;;;;;N;;;;; +2800;BRAILLE PATTERN BLANK;So;0;L;;;;;N;;;;; +2801;BRAILLE PATTERN DOTS-1;So;0;L;;;;;N;;;;; +2802;BRAILLE PATTERN DOTS-2;So;0;L;;;;;N;;;;; +2803;BRAILLE PATTERN DOTS-12;So;0;L;;;;;N;;;;; +2804;BRAILLE PATTERN DOTS-3;So;0;L;;;;;N;;;;; +2805;BRAILLE PATTERN DOTS-13;So;0;L;;;;;N;;;;; +2806;BRAILLE PATTERN DOTS-23;So;0;L;;;;;N;;;;; +2807;BRAILLE PATTERN DOTS-123;So;0;L;;;;;N;;;;; +2808;BRAILLE PATTERN DOTS-4;So;0;L;;;;;N;;;;; +2809;BRAILLE PATTERN DOTS-14;So;0;L;;;;;N;;;;; +280A;BRAILLE PATTERN DOTS-24;So;0;L;;;;;N;;;;; +280B;BRAILLE PATTERN DOTS-124;So;0;L;;;;;N;;;;; +280C;BRAILLE PATTERN DOTS-34;So;0;L;;;;;N;;;;; +280D;BRAILLE PATTERN DOTS-134;So;0;L;;;;;N;;;;; +280E;BRAILLE PATTERN DOTS-234;So;0;L;;;;;N;;;;; +280F;BRAILLE PATTERN DOTS-1234;So;0;L;;;;;N;;;;; +2810;BRAILLE PATTERN DOTS-5;So;0;L;;;;;N;;;;; +2811;BRAILLE PATTERN DOTS-15;So;0;L;;;;;N;;;;; +2812;BRAILLE PATTERN DOTS-25;So;0;L;;;;;N;;;;; +2813;BRAILLE PATTERN DOTS-125;So;0;L;;;;;N;;;;; +2814;BRAILLE PATTERN DOTS-35;So;0;L;;;;;N;;;;; +2815;BRAILLE PATTERN DOTS-135;So;0;L;;;;;N;;;;; +2816;BRAILLE PATTERN DOTS-235;So;0;L;;;;;N;;;;; +2817;BRAILLE PATTERN DOTS-1235;So;0;L;;;;;N;;;;; +2818;BRAILLE PATTERN DOTS-45;So;0;L;;;;;N;;;;; +2819;BRAILLE PATTERN DOTS-145;So;0;L;;;;;N;;;;; +281A;BRAILLE PATTERN DOTS-245;So;0;L;;;;;N;;;;; +281B;BRAILLE PATTERN DOTS-1245;So;0;L;;;;;N;;;;; +281C;BRAILLE PATTERN DOTS-345;So;0;L;;;;;N;;;;; +281D;BRAILLE PATTERN DOTS-1345;So;0;L;;;;;N;;;;; +281E;BRAILLE PATTERN DOTS-2345;So;0;L;;;;;N;;;;; +281F;BRAILLE PATTERN DOTS-12345;So;0;L;;;;;N;;;;; +2820;BRAILLE PATTERN DOTS-6;So;0;L;;;;;N;;;;; +2821;BRAILLE PATTERN DOTS-16;So;0;L;;;;;N;;;;; +2822;BRAILLE PATTERN DOTS-26;So;0;L;;;;;N;;;;; +2823;BRAILLE PATTERN DOTS-126;So;0;L;;;;;N;;;;; +2824;BRAILLE PATTERN DOTS-36;So;0;L;;;;;N;;;;; +2825;BRAILLE PATTERN DOTS-136;So;0;L;;;;;N;;;;; +2826;BRAILLE PATTERN DOTS-236;So;0;L;;;;;N;;;;; +2827;BRAILLE PATTERN DOTS-1236;So;0;L;;;;;N;;;;; +2828;BRAILLE PATTERN DOTS-46;So;0;L;;;;;N;;;;; +2829;BRAILLE PATTERN DOTS-146;So;0;L;;;;;N;;;;; +282A;BRAILLE PATTERN DOTS-246;So;0;L;;;;;N;;;;; +282B;BRAILLE PATTERN DOTS-1246;So;0;L;;;;;N;;;;; +282C;BRAILLE PATTERN DOTS-346;So;0;L;;;;;N;;;;; +282D;BRAILLE PATTERN DOTS-1346;So;0;L;;;;;N;;;;; +282E;BRAILLE PATTERN DOTS-2346;So;0;L;;;;;N;;;;; +282F;BRAILLE PATTERN DOTS-12346;So;0;L;;;;;N;;;;; +2830;BRAILLE PATTERN DOTS-56;So;0;L;;;;;N;;;;; +2831;BRAILLE PATTERN DOTS-156;So;0;L;;;;;N;;;;; +2832;BRAILLE PATTERN DOTS-256;So;0;L;;;;;N;;;;; +2833;BRAILLE PATTERN DOTS-1256;So;0;L;;;;;N;;;;; +2834;BRAILLE PATTERN DOTS-356;So;0;L;;;;;N;;;;; +2835;BRAILLE PATTERN DOTS-1356;So;0;L;;;;;N;;;;; +2836;BRAILLE PATTERN DOTS-2356;So;0;L;;;;;N;;;;; +2837;BRAILLE PATTERN DOTS-12356;So;0;L;;;;;N;;;;; +2838;BRAILLE PATTERN DOTS-456;So;0;L;;;;;N;;;;; +2839;BRAILLE PATTERN DOTS-1456;So;0;L;;;;;N;;;;; +283A;BRAILLE PATTERN DOTS-2456;So;0;L;;;;;N;;;;; +283B;BRAILLE PATTERN DOTS-12456;So;0;L;;;;;N;;;;; +283C;BRAILLE PATTERN DOTS-3456;So;0;L;;;;;N;;;;; +283D;BRAILLE PATTERN DOTS-13456;So;0;L;;;;;N;;;;; +283E;BRAILLE PATTERN DOTS-23456;So;0;L;;;;;N;;;;; +283F;BRAILLE PATTERN DOTS-123456;So;0;L;;;;;N;;;;; +2840;BRAILLE PATTERN DOTS-7;So;0;L;;;;;N;;;;; +2841;BRAILLE PATTERN DOTS-17;So;0;L;;;;;N;;;;; +2842;BRAILLE PATTERN DOTS-27;So;0;L;;;;;N;;;;; +2843;BRAILLE PATTERN DOTS-127;So;0;L;;;;;N;;;;; +2844;BRAILLE PATTERN DOTS-37;So;0;L;;;;;N;;;;; +2845;BRAILLE PATTERN DOTS-137;So;0;L;;;;;N;;;;; +2846;BRAILLE PATTERN DOTS-237;So;0;L;;;;;N;;;;; +2847;BRAILLE PATTERN DOTS-1237;So;0;L;;;;;N;;;;; +2848;BRAILLE PATTERN DOTS-47;So;0;L;;;;;N;;;;; +2849;BRAILLE PATTERN DOTS-147;So;0;L;;;;;N;;;;; +284A;BRAILLE PATTERN DOTS-247;So;0;L;;;;;N;;;;; +284B;BRAILLE PATTERN DOTS-1247;So;0;L;;;;;N;;;;; +284C;BRAILLE PATTERN DOTS-347;So;0;L;;;;;N;;;;; +284D;BRAILLE PATTERN DOTS-1347;So;0;L;;;;;N;;;;; +284E;BRAILLE PATTERN DOTS-2347;So;0;L;;;;;N;;;;; +284F;BRAILLE PATTERN DOTS-12347;So;0;L;;;;;N;;;;; +2850;BRAILLE PATTERN DOTS-57;So;0;L;;;;;N;;;;; +2851;BRAILLE PATTERN DOTS-157;So;0;L;;;;;N;;;;; +2852;BRAILLE PATTERN DOTS-257;So;0;L;;;;;N;;;;; +2853;BRAILLE PATTERN DOTS-1257;So;0;L;;;;;N;;;;; +2854;BRAILLE PATTERN DOTS-357;So;0;L;;;;;N;;;;; +2855;BRAILLE PATTERN DOTS-1357;So;0;L;;;;;N;;;;; +2856;BRAILLE PATTERN DOTS-2357;So;0;L;;;;;N;;;;; +2857;BRAILLE PATTERN DOTS-12357;So;0;L;;;;;N;;;;; +2858;BRAILLE PATTERN DOTS-457;So;0;L;;;;;N;;;;; +2859;BRAILLE PATTERN DOTS-1457;So;0;L;;;;;N;;;;; +285A;BRAILLE PATTERN DOTS-2457;So;0;L;;;;;N;;;;; +285B;BRAILLE PATTERN DOTS-12457;So;0;L;;;;;N;;;;; +285C;BRAILLE PATTERN DOTS-3457;So;0;L;;;;;N;;;;; +285D;BRAILLE PATTERN DOTS-13457;So;0;L;;;;;N;;;;; +285E;BRAILLE PATTERN DOTS-23457;So;0;L;;;;;N;;;;; +285F;BRAILLE PATTERN DOTS-123457;So;0;L;;;;;N;;;;; +2860;BRAILLE PATTERN DOTS-67;So;0;L;;;;;N;;;;; +2861;BRAILLE PATTERN DOTS-167;So;0;L;;;;;N;;;;; +2862;BRAILLE PATTERN DOTS-267;So;0;L;;;;;N;;;;; +2863;BRAILLE PATTERN DOTS-1267;So;0;L;;;;;N;;;;; +2864;BRAILLE PATTERN DOTS-367;So;0;L;;;;;N;;;;; +2865;BRAILLE PATTERN DOTS-1367;So;0;L;;;;;N;;;;; +2866;BRAILLE PATTERN DOTS-2367;So;0;L;;;;;N;;;;; +2867;BRAILLE PATTERN DOTS-12367;So;0;L;;;;;N;;;;; +2868;BRAILLE PATTERN DOTS-467;So;0;L;;;;;N;;;;; +2869;BRAILLE PATTERN DOTS-1467;So;0;L;;;;;N;;;;; +286A;BRAILLE PATTERN DOTS-2467;So;0;L;;;;;N;;;;; +286B;BRAILLE PATTERN DOTS-12467;So;0;L;;;;;N;;;;; +286C;BRAILLE PATTERN DOTS-3467;So;0;L;;;;;N;;;;; +286D;BRAILLE PATTERN DOTS-13467;So;0;L;;;;;N;;;;; +286E;BRAILLE PATTERN DOTS-23467;So;0;L;;;;;N;;;;; +286F;BRAILLE PATTERN DOTS-123467;So;0;L;;;;;N;;;;; +2870;BRAILLE PATTERN DOTS-567;So;0;L;;;;;N;;;;; +2871;BRAILLE PATTERN DOTS-1567;So;0;L;;;;;N;;;;; +2872;BRAILLE PATTERN DOTS-2567;So;0;L;;;;;N;;;;; +2873;BRAILLE PATTERN DOTS-12567;So;0;L;;;;;N;;;;; +2874;BRAILLE PATTERN DOTS-3567;So;0;L;;;;;N;;;;; +2875;BRAILLE PATTERN DOTS-13567;So;0;L;;;;;N;;;;; +2876;BRAILLE PATTERN DOTS-23567;So;0;L;;;;;N;;;;; +2877;BRAILLE PATTERN DOTS-123567;So;0;L;;;;;N;;;;; +2878;BRAILLE PATTERN DOTS-4567;So;0;L;;;;;N;;;;; +2879;BRAILLE PATTERN DOTS-14567;So;0;L;;;;;N;;;;; +287A;BRAILLE PATTERN DOTS-24567;So;0;L;;;;;N;;;;; +287B;BRAILLE PATTERN DOTS-124567;So;0;L;;;;;N;;;;; +287C;BRAILLE PATTERN DOTS-34567;So;0;L;;;;;N;;;;; +287D;BRAILLE PATTERN DOTS-134567;So;0;L;;;;;N;;;;; +287E;BRAILLE PATTERN DOTS-234567;So;0;L;;;;;N;;;;; +287F;BRAILLE PATTERN DOTS-1234567;So;0;L;;;;;N;;;;; +2880;BRAILLE PATTERN DOTS-8;So;0;L;;;;;N;;;;; +2881;BRAILLE PATTERN DOTS-18;So;0;L;;;;;N;;;;; +2882;BRAILLE PATTERN DOTS-28;So;0;L;;;;;N;;;;; +2883;BRAILLE PATTERN DOTS-128;So;0;L;;;;;N;;;;; +2884;BRAILLE PATTERN DOTS-38;So;0;L;;;;;N;;;;; +2885;BRAILLE PATTERN DOTS-138;So;0;L;;;;;N;;;;; +2886;BRAILLE PATTERN DOTS-238;So;0;L;;;;;N;;;;; +2887;BRAILLE PATTERN DOTS-1238;So;0;L;;;;;N;;;;; +2888;BRAILLE PATTERN DOTS-48;So;0;L;;;;;N;;;;; +2889;BRAILLE PATTERN DOTS-148;So;0;L;;;;;N;;;;; +288A;BRAILLE PATTERN DOTS-248;So;0;L;;;;;N;;;;; +288B;BRAILLE PATTERN DOTS-1248;So;0;L;;;;;N;;;;; +288C;BRAILLE PATTERN DOTS-348;So;0;L;;;;;N;;;;; +288D;BRAILLE PATTERN DOTS-1348;So;0;L;;;;;N;;;;; +288E;BRAILLE PATTERN DOTS-2348;So;0;L;;;;;N;;;;; +288F;BRAILLE PATTERN DOTS-12348;So;0;L;;;;;N;;;;; +2890;BRAILLE PATTERN DOTS-58;So;0;L;;;;;N;;;;; +2891;BRAILLE PATTERN DOTS-158;So;0;L;;;;;N;;;;; +2892;BRAILLE PATTERN DOTS-258;So;0;L;;;;;N;;;;; +2893;BRAILLE PATTERN DOTS-1258;So;0;L;;;;;N;;;;; +2894;BRAILLE PATTERN DOTS-358;So;0;L;;;;;N;;;;; +2895;BRAILLE PATTERN DOTS-1358;So;0;L;;;;;N;;;;; +2896;BRAILLE PATTERN DOTS-2358;So;0;L;;;;;N;;;;; +2897;BRAILLE PATTERN DOTS-12358;So;0;L;;;;;N;;;;; +2898;BRAILLE PATTERN DOTS-458;So;0;L;;;;;N;;;;; +2899;BRAILLE PATTERN DOTS-1458;So;0;L;;;;;N;;;;; +289A;BRAILLE PATTERN DOTS-2458;So;0;L;;;;;N;;;;; +289B;BRAILLE PATTERN DOTS-12458;So;0;L;;;;;N;;;;; +289C;BRAILLE PATTERN DOTS-3458;So;0;L;;;;;N;;;;; +289D;BRAILLE PATTERN DOTS-13458;So;0;L;;;;;N;;;;; +289E;BRAILLE PATTERN DOTS-23458;So;0;L;;;;;N;;;;; +289F;BRAILLE PATTERN DOTS-123458;So;0;L;;;;;N;;;;; +28A0;BRAILLE PATTERN DOTS-68;So;0;L;;;;;N;;;;; +28A1;BRAILLE PATTERN DOTS-168;So;0;L;;;;;N;;;;; +28A2;BRAILLE PATTERN DOTS-268;So;0;L;;;;;N;;;;; +28A3;BRAILLE PATTERN DOTS-1268;So;0;L;;;;;N;;;;; +28A4;BRAILLE PATTERN DOTS-368;So;0;L;;;;;N;;;;; +28A5;BRAILLE PATTERN DOTS-1368;So;0;L;;;;;N;;;;; +28A6;BRAILLE PATTERN DOTS-2368;So;0;L;;;;;N;;;;; +28A7;BRAILLE PATTERN DOTS-12368;So;0;L;;;;;N;;;;; +28A8;BRAILLE PATTERN DOTS-468;So;0;L;;;;;N;;;;; +28A9;BRAILLE PATTERN DOTS-1468;So;0;L;;;;;N;;;;; +28AA;BRAILLE PATTERN DOTS-2468;So;0;L;;;;;N;;;;; +28AB;BRAILLE PATTERN DOTS-12468;So;0;L;;;;;N;;;;; +28AC;BRAILLE PATTERN DOTS-3468;So;0;L;;;;;N;;;;; +28AD;BRAILLE PATTERN DOTS-13468;So;0;L;;;;;N;;;;; +28AE;BRAILLE PATTERN DOTS-23468;So;0;L;;;;;N;;;;; +28AF;BRAILLE PATTERN DOTS-123468;So;0;L;;;;;N;;;;; +28B0;BRAILLE PATTERN DOTS-568;So;0;L;;;;;N;;;;; +28B1;BRAILLE PATTERN DOTS-1568;So;0;L;;;;;N;;;;; +28B2;BRAILLE PATTERN DOTS-2568;So;0;L;;;;;N;;;;; +28B3;BRAILLE PATTERN DOTS-12568;So;0;L;;;;;N;;;;; +28B4;BRAILLE PATTERN DOTS-3568;So;0;L;;;;;N;;;;; +28B5;BRAILLE PATTERN DOTS-13568;So;0;L;;;;;N;;;;; +28B6;BRAILLE PATTERN DOTS-23568;So;0;L;;;;;N;;;;; +28B7;BRAILLE PATTERN DOTS-123568;So;0;L;;;;;N;;;;; +28B8;BRAILLE PATTERN DOTS-4568;So;0;L;;;;;N;;;;; +28B9;BRAILLE PATTERN DOTS-14568;So;0;L;;;;;N;;;;; +28BA;BRAILLE PATTERN DOTS-24568;So;0;L;;;;;N;;;;; +28BB;BRAILLE PATTERN DOTS-124568;So;0;L;;;;;N;;;;; +28BC;BRAILLE PATTERN DOTS-34568;So;0;L;;;;;N;;;;; +28BD;BRAILLE PATTERN DOTS-134568;So;0;L;;;;;N;;;;; +28BE;BRAILLE PATTERN DOTS-234568;So;0;L;;;;;N;;;;; +28BF;BRAILLE PATTERN DOTS-1234568;So;0;L;;;;;N;;;;; +28C0;BRAILLE PATTERN DOTS-78;So;0;L;;;;;N;;;;; +28C1;BRAILLE PATTERN DOTS-178;So;0;L;;;;;N;;;;; +28C2;BRAILLE PATTERN DOTS-278;So;0;L;;;;;N;;;;; +28C3;BRAILLE PATTERN DOTS-1278;So;0;L;;;;;N;;;;; +28C4;BRAILLE PATTERN DOTS-378;So;0;L;;;;;N;;;;; +28C5;BRAILLE PATTERN DOTS-1378;So;0;L;;;;;N;;;;; +28C6;BRAILLE PATTERN DOTS-2378;So;0;L;;;;;N;;;;; +28C7;BRAILLE PATTERN DOTS-12378;So;0;L;;;;;N;;;;; +28C8;BRAILLE PATTERN DOTS-478;So;0;L;;;;;N;;;;; +28C9;BRAILLE PATTERN DOTS-1478;So;0;L;;;;;N;;;;; +28CA;BRAILLE PATTERN DOTS-2478;So;0;L;;;;;N;;;;; +28CB;BRAILLE PATTERN DOTS-12478;So;0;L;;;;;N;;;;; +28CC;BRAILLE PATTERN DOTS-3478;So;0;L;;;;;N;;;;; +28CD;BRAILLE PATTERN DOTS-13478;So;0;L;;;;;N;;;;; +28CE;BRAILLE PATTERN DOTS-23478;So;0;L;;;;;N;;;;; +28CF;BRAILLE PATTERN DOTS-123478;So;0;L;;;;;N;;;;; +28D0;BRAILLE PATTERN DOTS-578;So;0;L;;;;;N;;;;; +28D1;BRAILLE PATTERN DOTS-1578;So;0;L;;;;;N;;;;; +28D2;BRAILLE PATTERN DOTS-2578;So;0;L;;;;;N;;;;; +28D3;BRAILLE PATTERN DOTS-12578;So;0;L;;;;;N;;;;; +28D4;BRAILLE PATTERN DOTS-3578;So;0;L;;;;;N;;;;; +28D5;BRAILLE PATTERN DOTS-13578;So;0;L;;;;;N;;;;; +28D6;BRAILLE PATTERN DOTS-23578;So;0;L;;;;;N;;;;; +28D7;BRAILLE PATTERN DOTS-123578;So;0;L;;;;;N;;;;; +28D8;BRAILLE PATTERN DOTS-4578;So;0;L;;;;;N;;;;; +28D9;BRAILLE PATTERN DOTS-14578;So;0;L;;;;;N;;;;; +28DA;BRAILLE PATTERN DOTS-24578;So;0;L;;;;;N;;;;; +28DB;BRAILLE PATTERN DOTS-124578;So;0;L;;;;;N;;;;; +28DC;BRAILLE PATTERN DOTS-34578;So;0;L;;;;;N;;;;; +28DD;BRAILLE PATTERN DOTS-134578;So;0;L;;;;;N;;;;; +28DE;BRAILLE PATTERN DOTS-234578;So;0;L;;;;;N;;;;; +28DF;BRAILLE PATTERN DOTS-1234578;So;0;L;;;;;N;;;;; +28E0;BRAILLE PATTERN DOTS-678;So;0;L;;;;;N;;;;; +28E1;BRAILLE PATTERN DOTS-1678;So;0;L;;;;;N;;;;; +28E2;BRAILLE PATTERN DOTS-2678;So;0;L;;;;;N;;;;; +28E3;BRAILLE PATTERN DOTS-12678;So;0;L;;;;;N;;;;; +28E4;BRAILLE PATTERN DOTS-3678;So;0;L;;;;;N;;;;; +28E5;BRAILLE PATTERN DOTS-13678;So;0;L;;;;;N;;;;; +28E6;BRAILLE PATTERN DOTS-23678;So;0;L;;;;;N;;;;; +28E7;BRAILLE PATTERN DOTS-123678;So;0;L;;;;;N;;;;; +28E8;BRAILLE PATTERN DOTS-4678;So;0;L;;;;;N;;;;; +28E9;BRAILLE PATTERN DOTS-14678;So;0;L;;;;;N;;;;; +28EA;BRAILLE PATTERN DOTS-24678;So;0;L;;;;;N;;;;; +28EB;BRAILLE PATTERN DOTS-124678;So;0;L;;;;;N;;;;; +28EC;BRAILLE PATTERN DOTS-34678;So;0;L;;;;;N;;;;; +28ED;BRAILLE PATTERN DOTS-134678;So;0;L;;;;;N;;;;; +28EE;BRAILLE PATTERN DOTS-234678;So;0;L;;;;;N;;;;; +28EF;BRAILLE PATTERN DOTS-1234678;So;0;L;;;;;N;;;;; +28F0;BRAILLE PATTERN DOTS-5678;So;0;L;;;;;N;;;;; +28F1;BRAILLE PATTERN DOTS-15678;So;0;L;;;;;N;;;;; +28F2;BRAILLE PATTERN DOTS-25678;So;0;L;;;;;N;;;;; +28F3;BRAILLE PATTERN DOTS-125678;So;0;L;;;;;N;;;;; +28F4;BRAILLE PATTERN DOTS-35678;So;0;L;;;;;N;;;;; +28F5;BRAILLE PATTERN DOTS-135678;So;0;L;;;;;N;;;;; +28F6;BRAILLE PATTERN DOTS-235678;So;0;L;;;;;N;;;;; +28F7;BRAILLE PATTERN DOTS-1235678;So;0;L;;;;;N;;;;; +28F8;BRAILLE PATTERN DOTS-45678;So;0;L;;;;;N;;;;; +28F9;BRAILLE PATTERN DOTS-145678;So;0;L;;;;;N;;;;; +28FA;BRAILLE PATTERN DOTS-245678;So;0;L;;;;;N;;;;; +28FB;BRAILLE PATTERN DOTS-1245678;So;0;L;;;;;N;;;;; +28FC;BRAILLE PATTERN DOTS-345678;So;0;L;;;;;N;;;;; +28FD;BRAILLE PATTERN DOTS-1345678;So;0;L;;;;;N;;;;; +28FE;BRAILLE PATTERN DOTS-2345678;So;0;L;;;;;N;;;;; +28FF;BRAILLE PATTERN DOTS-12345678;So;0;L;;;;;N;;;;; +2900;RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2901;RIGHTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2902;LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2903;RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2904;LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2905;RIGHTWARDS TWO-HEADED ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; +2906;LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; +2907;RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; +2908;DOWNWARDS ARROW WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; +2909;UPWARDS ARROW WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; +290A;UPWARDS TRIPLE ARROW;Sm;0;ON;;;;;N;;;;; +290B;DOWNWARDS TRIPLE ARROW;Sm;0;ON;;;;;N;;;;; +290C;LEFTWARDS DOUBLE DASH ARROW;Sm;0;ON;;;;;N;;;;; +290D;RIGHTWARDS DOUBLE DASH ARROW;Sm;0;ON;;;;;N;;;;; +290E;LEFTWARDS TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;; +290F;RIGHTWARDS TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;; +2910;RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;; +2911;RIGHTWARDS ARROW WITH DOTTED STEM;Sm;0;ON;;;;;N;;;;; +2912;UPWARDS ARROW TO BAR;Sm;0;ON;;;;;N;;;;; +2913;DOWNWARDS ARROW TO BAR;Sm;0;ON;;;;;N;;;;; +2914;RIGHTWARDS ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2915;RIGHTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2916;RIGHTWARDS TWO-HEADED ARROW WITH TAIL;Sm;0;ON;;;;;N;;;;; +2917;RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2918;RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2919;LEFTWARDS ARROW-TAIL;Sm;0;ON;;;;;N;;;;; +291A;RIGHTWARDS ARROW-TAIL;Sm;0;ON;;;;;N;;;;; +291B;LEFTWARDS DOUBLE ARROW-TAIL;Sm;0;ON;;;;;N;;;;; +291C;RIGHTWARDS DOUBLE ARROW-TAIL;Sm;0;ON;;;;;N;;;;; +291D;LEFTWARDS ARROW TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; +291E;RIGHTWARDS ARROW TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; +291F;LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; +2920;RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; +2921;NORTH WEST AND SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;; +2922;NORTH EAST AND SOUTH WEST ARROW;Sm;0;ON;;;;;N;;;;; +2923;NORTH WEST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;; +2924;NORTH EAST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;; +2925;SOUTH EAST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;; +2926;SOUTH WEST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;; +2927;NORTH WEST ARROW AND NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;; +2928;NORTH EAST ARROW AND SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;; +2929;SOUTH EAST ARROW AND SOUTH WEST ARROW;Sm;0;ON;;;;;N;;;;; +292A;SOUTH WEST ARROW AND NORTH WEST ARROW;Sm;0;ON;;;;;N;;;;; +292B;RISING DIAGONAL CROSSING FALLING DIAGONAL;Sm;0;ON;;;;;N;;;;; +292C;FALLING DIAGONAL CROSSING RISING DIAGONAL;Sm;0;ON;;;;;N;;;;; +292D;SOUTH EAST ARROW CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;; +292E;NORTH EAST ARROW CROSSING SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;; +292F;FALLING DIAGONAL CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;; +2930;RISING DIAGONAL CROSSING SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;; +2931;NORTH EAST ARROW CROSSING NORTH WEST ARROW;Sm;0;ON;;;;;N;;;;; +2932;NORTH WEST ARROW CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;; +2933;WAVE ARROW POINTING DIRECTLY RIGHT;Sm;0;ON;;;;;N;;;;; +2934;ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS;Sm;0;ON;;;;;N;;;;; +2935;ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS;Sm;0;ON;;;;;N;;;;; +2936;ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS;Sm;0;ON;;;;;N;;;;; +2937;ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS;Sm;0;ON;;;;;N;;;;; +2938;RIGHT-SIDE ARC CLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; +2939;LEFT-SIDE ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; +293A;TOP ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; +293B;BOTTOM ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; +293C;TOP ARC CLOCKWISE ARROW WITH MINUS;Sm;0;ON;;;;;N;;;;; +293D;TOP ARC ANTICLOCKWISE ARROW WITH PLUS;Sm;0;ON;;;;;N;;;;; +293E;LOWER RIGHT SEMICIRCULAR CLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; +293F;LOWER LEFT SEMICIRCULAR ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; +2940;ANTICLOCKWISE CLOSED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; +2941;CLOCKWISE CLOSED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; +2942;RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2943;LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2944;SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2945;RIGHTWARDS ARROW WITH PLUS BELOW;Sm;0;ON;;;;;N;;;;; +2946;LEFTWARDS ARROW WITH PLUS BELOW;Sm;0;ON;;;;;N;;;;; +2947;RIGHTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;; +2948;LEFT RIGHT ARROW THROUGH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; +2949;UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; +294A;LEFT BARB UP RIGHT BARB DOWN HARPOON;Sm;0;ON;;;;;N;;;;; +294B;LEFT BARB DOWN RIGHT BARB UP HARPOON;Sm;0;ON;;;;;N;;;;; +294C;UP BARB RIGHT DOWN BARB LEFT HARPOON;Sm;0;ON;;;;;N;;;;; +294D;UP BARB LEFT DOWN BARB RIGHT HARPOON;Sm;0;ON;;;;;N;;;;; +294E;LEFT BARB UP RIGHT BARB UP HARPOON;Sm;0;ON;;;;;N;;;;; +294F;UP BARB RIGHT DOWN BARB RIGHT HARPOON;Sm;0;ON;;;;;N;;;;; +2950;LEFT BARB DOWN RIGHT BARB DOWN HARPOON;Sm;0;ON;;;;;N;;;;; +2951;UP BARB LEFT DOWN BARB LEFT HARPOON;Sm;0;ON;;;;;N;;;;; +2952;LEFTWARDS HARPOON WITH BARB UP TO BAR;Sm;0;ON;;;;;N;;;;; +2953;RIGHTWARDS HARPOON WITH BARB UP TO BAR;Sm;0;ON;;;;;N;;;;; +2954;UPWARDS HARPOON WITH BARB RIGHT TO BAR;Sm;0;ON;;;;;N;;;;; +2955;DOWNWARDS HARPOON WITH BARB RIGHT TO BAR;Sm;0;ON;;;;;N;;;;; +2956;LEFTWARDS HARPOON WITH BARB DOWN TO BAR;Sm;0;ON;;;;;N;;;;; +2957;RIGHTWARDS HARPOON WITH BARB DOWN TO BAR;Sm;0;ON;;;;;N;;;;; +2958;UPWARDS HARPOON WITH BARB LEFT TO BAR;Sm;0;ON;;;;;N;;;;; +2959;DOWNWARDS HARPOON WITH BARB LEFT TO BAR;Sm;0;ON;;;;;N;;;;; +295A;LEFTWARDS HARPOON WITH BARB UP FROM BAR;Sm;0;ON;;;;;N;;;;; +295B;RIGHTWARDS HARPOON WITH BARB UP FROM BAR;Sm;0;ON;;;;;N;;;;; +295C;UPWARDS HARPOON WITH BARB RIGHT FROM BAR;Sm;0;ON;;;;;N;;;;; +295D;DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR;Sm;0;ON;;;;;N;;;;; +295E;LEFTWARDS HARPOON WITH BARB DOWN FROM BAR;Sm;0;ON;;;;;N;;;;; +295F;RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR;Sm;0;ON;;;;;N;;;;; +2960;UPWARDS HARPOON WITH BARB LEFT FROM BAR;Sm;0;ON;;;;;N;;;;; +2961;DOWNWARDS HARPOON WITH BARB LEFT FROM BAR;Sm;0;ON;;;;;N;;;;; +2962;LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;; +2963;UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;; +2964;RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;; +2965;DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;; +2966;LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP;Sm;0;ON;;;;;N;;;;; +2967;LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;; +2968;RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP;Sm;0;ON;;;;;N;;;;; +2969;RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;; +296A;LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH;Sm;0;ON;;;;;N;;;;; +296B;LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH;Sm;0;ON;;;;;N;;;;; +296C;RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH;Sm;0;ON;;;;;N;;;;; +296D;RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH;Sm;0;ON;;;;;N;;;;; +296E;UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;; +296F;DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;; +2970;RIGHT DOUBLE ARROW WITH ROUNDED HEAD;Sm;0;ON;;;;;N;;;;; +2971;EQUALS SIGN ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2972;TILDE OPERATOR ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2973;LEFTWARDS ARROW ABOVE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;; +2974;RIGHTWARDS ARROW ABOVE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;; +2975;RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;; +2976;LESS-THAN ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2977;LEFTWARDS ARROW THROUGH LESS-THAN;Sm;0;ON;;;;;N;;;;; +2978;GREATER-THAN ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2979;SUBSET ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +297A;LEFTWARDS ARROW THROUGH SUBSET;Sm;0;ON;;;;;N;;;;; +297B;SUPERSET ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +297C;LEFT FISH TAIL;Sm;0;ON;;;;;N;;;;; +297D;RIGHT FISH TAIL;Sm;0;ON;;;;;N;;;;; +297E;UP FISH TAIL;Sm;0;ON;;;;;N;;;;; +297F;DOWN FISH TAIL;Sm;0;ON;;;;;N;;;;; +2980;TRIPLE VERTICAL BAR DELIMITER;Sm;0;ON;;;;;N;;;;; +2981;Z NOTATION SPOT;Sm;0;ON;;;;;N;;;;; +2982;Z NOTATION TYPE COLON;Sm;0;ON;;;;;N;;;;; +2983;LEFT WHITE CURLY BRACKET;Ps;0;ON;;;;;Y;;;;; +2984;RIGHT WHITE CURLY BRACKET;Pe;0;ON;;;;;Y;;;;; +2985;LEFT WHITE PARENTHESIS;Ps;0;ON;;;;;Y;;;;; +2986;RIGHT WHITE PARENTHESIS;Pe;0;ON;;;;;Y;;;;; +2987;Z NOTATION LEFT IMAGE BRACKET;Ps;0;ON;;;;;Y;;;;; +2988;Z NOTATION RIGHT IMAGE BRACKET;Pe;0;ON;;;;;Y;;;;; +2989;Z NOTATION LEFT BINDING BRACKET;Ps;0;ON;;;;;Y;;;;; +298A;Z NOTATION RIGHT BINDING BRACKET;Pe;0;ON;;;;;Y;;;;; +298B;LEFT SQUARE BRACKET WITH UNDERBAR;Ps;0;ON;;;;;Y;;;;; +298C;RIGHT SQUARE BRACKET WITH UNDERBAR;Pe;0;ON;;;;;Y;;;;; +298D;LEFT SQUARE BRACKET WITH TICK IN TOP CORNER;Ps;0;ON;;;;;Y;;;;; +298E;RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Pe;0;ON;;;;;Y;;;;; +298F;LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Ps;0;ON;;;;;Y;;;;; +2990;RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER;Pe;0;ON;;;;;Y;;;;; +2991;LEFT ANGLE BRACKET WITH DOT;Ps;0;ON;;;;;Y;;;;; +2992;RIGHT ANGLE BRACKET WITH DOT;Pe;0;ON;;;;;Y;;;;; +2993;LEFT ARC LESS-THAN BRACKET;Ps;0;ON;;;;;Y;;;;; +2994;RIGHT ARC GREATER-THAN BRACKET;Pe;0;ON;;;;;Y;;;;; +2995;DOUBLE LEFT ARC GREATER-THAN BRACKET;Ps;0;ON;;;;;Y;;;;; +2996;DOUBLE RIGHT ARC LESS-THAN BRACKET;Pe;0;ON;;;;;Y;;;;; +2997;LEFT BLACK TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;;;;; +2998;RIGHT BLACK TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;;;;; +2999;DOTTED FENCE;Sm;0;ON;;;;;N;;;;; +299A;VERTICAL ZIGZAG LINE;Sm;0;ON;;;;;N;;;;; +299B;MEASURED ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;; +299C;RIGHT ANGLE VARIANT WITH SQUARE;Sm;0;ON;;;;;Y;;;;; +299D;MEASURED RIGHT ANGLE WITH DOT;Sm;0;ON;;;;;Y;;;;; +299E;ANGLE WITH S INSIDE;Sm;0;ON;;;;;Y;;;;; +299F;ACUTE ANGLE;Sm;0;ON;;;;;Y;;;;; +29A0;SPHERICAL ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;; +29A1;SPHERICAL ANGLE OPENING UP;Sm;0;ON;;;;;N;;;;; +29A2;TURNED ANGLE;Sm;0;ON;;;;;Y;;;;; +29A3;REVERSED ANGLE;Sm;0;ON;;;;;Y;;;;; +29A4;ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; +29A5;REVERSED ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; +29A6;OBLIQUE ANGLE OPENING UP;Sm;0;ON;;;;;Y;;;;; +29A7;OBLIQUE ANGLE OPENING DOWN;Sm;0;ON;;;;;Y;;;;; +29A8;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT;Sm;0;ON;;;;;Y;;;;; +29A9;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT;Sm;0;ON;;;;;Y;;;;; +29AA;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT;Sm;0;ON;;;;;Y;;;;; +29AB;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT;Sm;0;ON;;;;;Y;;;;; +29AC;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP;Sm;0;ON;;;;;Y;;;;; +29AD;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP;Sm;0;ON;;;;;Y;;;;; +29AE;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN;Sm;0;ON;;;;;Y;;;;; +29AF;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN;Sm;0;ON;;;;;Y;;;;; +29B0;REVERSED EMPTY SET;Sm;0;ON;;;;;N;;;;; +29B1;EMPTY SET WITH OVERBAR;Sm;0;ON;;;;;N;;;;; +29B2;EMPTY SET WITH SMALL CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;; +29B3;EMPTY SET WITH RIGHT ARROW ABOVE;Sm;0;ON;;;;;N;;;;; +29B4;EMPTY SET WITH LEFT ARROW ABOVE;Sm;0;ON;;;;;N;;;;; +29B5;CIRCLE WITH HORIZONTAL BAR;Sm;0;ON;;;;;N;;;;; +29B6;CIRCLED VERTICAL BAR;Sm;0;ON;;;;;N;;;;; +29B7;CIRCLED PARALLEL;Sm;0;ON;;;;;N;;;;; +29B8;CIRCLED REVERSE SOLIDUS;Sm;0;ON;;;;;Y;;;;; +29B9;CIRCLED PERPENDICULAR;Sm;0;ON;;;;;N;;;;; +29BA;CIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTICAL BAR;Sm;0;ON;;;;;N;;;;; +29BB;CIRCLE WITH SUPERIMPOSED X;Sm;0;ON;;;;;N;;;;; +29BC;CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN;Sm;0;ON;;;;;N;;;;; +29BD;UP ARROW THROUGH CIRCLE;Sm;0;ON;;;;;N;;;;; +29BE;CIRCLED WHITE BULLET;Sm;0;ON;;;;;N;;;;; +29BF;CIRCLED BULLET;Sm;0;ON;;;;;N;;;;; +29C0;CIRCLED LESS-THAN;Sm;0;ON;;;;;Y;;;;; +29C1;CIRCLED GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +29C2;CIRCLE WITH SMALL CIRCLE TO THE RIGHT;Sm;0;ON;;;;;Y;;;;; +29C3;CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT;Sm;0;ON;;;;;Y;;;;; +29C4;SQUARED RISING DIAGONAL SLASH;Sm;0;ON;;;;;Y;;;;; +29C5;SQUARED FALLING DIAGONAL SLASH;Sm;0;ON;;;;;Y;;;;; +29C6;SQUARED ASTERISK;Sm;0;ON;;;;;N;;;;; +29C7;SQUARED SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; +29C8;SQUARED SQUARE;Sm;0;ON;;;;;N;;;;; +29C9;TWO JOINED SQUARES;Sm;0;ON;;;;;Y;;;;; +29CA;TRIANGLE WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; +29CB;TRIANGLE WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; +29CC;S IN TRIANGLE;Sm;0;ON;;;;;N;;;;; +29CD;TRIANGLE WITH SERIFS AT BOTTOM;Sm;0;ON;;;;;N;;;;; +29CE;RIGHT TRIANGLE ABOVE LEFT TRIANGLE;Sm;0;ON;;;;;Y;;;;; +29CF;LEFT TRIANGLE BESIDE VERTICAL BAR;Sm;0;ON;;;;;Y;;;;; +29D0;VERTICAL BAR BESIDE RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;; +29D1;BOWTIE WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;; +29D2;BOWTIE WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;; +29D3;BLACK BOWTIE;Sm;0;ON;;;;;N;;;;; +29D4;TIMES WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;; +29D5;TIMES WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;; +29D6;WHITE HOURGLASS;Sm;0;ON;;;;;N;;;;; +29D7;BLACK HOURGLASS;Sm;0;ON;;;;;N;;;;; +29D8;LEFT WIGGLY FENCE;Ps;0;ON;;;;;Y;;;;; +29D9;RIGHT WIGGLY FENCE;Pe;0;ON;;;;;Y;;;;; +29DA;LEFT DOUBLE WIGGLY FENCE;Ps;0;ON;;;;;Y;;;;; +29DB;RIGHT DOUBLE WIGGLY FENCE;Pe;0;ON;;;;;Y;;;;; +29DC;INCOMPLETE INFINITY;Sm;0;ON;;;;;Y;;;;; +29DD;TIE OVER INFINITY;Sm;0;ON;;;;;N;;;;; +29DE;INFINITY NEGATED WITH VERTICAL BAR;Sm;0;ON;;;;;N;;;;; +29DF;DOUBLE-ENDED MULTIMAP;Sm;0;ON;;;;;N;;;;; +29E0;SQUARE WITH CONTOURED OUTLINE;Sm;0;ON;;;;;N;;;;; +29E1;INCREASES AS;Sm;0;ON;;;;;Y;;;;; +29E2;SHUFFLE PRODUCT;Sm;0;ON;;;;;N;;;;; +29E3;EQUALS SIGN AND SLANTED PARALLEL;Sm;0;ON;;;;;Y;;;;; +29E4;EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE;Sm;0;ON;;;;;Y;;;;; +29E5;IDENTICAL TO AND SLANTED PARALLEL;Sm;0;ON;;;;;Y;;;;; +29E6;GLEICH STARK;Sm;0;ON;;;;;N;;;;; +29E7;THERMODYNAMIC;Sm;0;ON;;;;;N;;;;; +29E8;DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;; +29E9;DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;; +29EA;BLACK DIAMOND WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;; +29EB;BLACK LOZENGE;Sm;0;ON;;;;;N;;;;; +29EC;WHITE CIRCLE WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;; +29ED;BLACK CIRCLE WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;; +29EE;ERROR-BARRED WHITE SQUARE;Sm;0;ON;;;;;N;;;;; +29EF;ERROR-BARRED BLACK SQUARE;Sm;0;ON;;;;;N;;;;; +29F0;ERROR-BARRED WHITE DIAMOND;Sm;0;ON;;;;;N;;;;; +29F1;ERROR-BARRED BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; +29F2;ERROR-BARRED WHITE CIRCLE;Sm;0;ON;;;;;N;;;;; +29F3;ERROR-BARRED BLACK CIRCLE;Sm;0;ON;;;;;N;;;;; +29F4;RULE-DELAYED;Sm;0;ON;;;;;Y;;;;; +29F5;REVERSE SOLIDUS OPERATOR;Sm;0;ON;;;;;Y;;;;; +29F6;SOLIDUS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; +29F7;REVERSE SOLIDUS WITH HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; +29F8;BIG SOLIDUS;Sm;0;ON;;;;;Y;;;;; +29F9;BIG REVERSE SOLIDUS;Sm;0;ON;;;;;Y;;;;; +29FA;DOUBLE PLUS;Sm;0;ON;;;;;N;;;;; +29FB;TRIPLE PLUS;Sm;0;ON;;;;;N;;;;; +29FC;LEFT-POINTING CURVED ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;; +29FD;RIGHT-POINTING CURVED ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;; +29FE;TINY;Sm;0;ON;;;;;N;;;;; +29FF;MINY;Sm;0;ON;;;;;N;;;;; +2A00;N-ARY CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;; +2A01;N-ARY CIRCLED PLUS OPERATOR;Sm;0;ON;;;;;N;;;;; +2A02;N-ARY CIRCLED TIMES OPERATOR;Sm;0;ON;;;;;N;;;;; +2A03;N-ARY UNION OPERATOR WITH DOT;Sm;0;ON;;;;;N;;;;; +2A04;N-ARY UNION OPERATOR WITH PLUS;Sm;0;ON;;;;;N;;;;; +2A05;N-ARY SQUARE INTERSECTION OPERATOR;Sm;0;ON;;;;;N;;;;; +2A06;N-ARY SQUARE UNION OPERATOR;Sm;0;ON;;;;;N;;;;; +2A07;TWO LOGICAL AND OPERATOR;Sm;0;ON;;;;;N;;;;; +2A08;TWO LOGICAL OR OPERATOR;Sm;0;ON;;;;;N;;;;; +2A09;N-ARY TIMES OPERATOR;Sm;0;ON;;;;;N;;;;; +2A0A;MODULO TWO SUM;Sm;0;ON;;;;;Y;;;;; +2A0B;SUMMATION WITH INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2A0C;QUADRUPLE INTEGRAL OPERATOR;Sm;0;ON; 222B 222B 222B 222B;;;;Y;;;;; +2A0D;FINITE PART INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2A0E;INTEGRAL WITH DOUBLE STROKE;Sm;0;ON;;;;;Y;;;;; +2A0F;INTEGRAL AVERAGE WITH SLASH;Sm;0;ON;;;;;Y;;;;; +2A10;CIRCULATION FUNCTION;Sm;0;ON;;;;;Y;;;;; +2A11;ANTICLOCKWISE INTEGRATION;Sm;0;ON;;;;;Y;;;;; +2A12;LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE;Sm;0;ON;;;;;Y;;;;; +2A13;LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE;Sm;0;ON;;;;;Y;;;;; +2A14;LINE INTEGRATION NOT INCLUDING THE POLE;Sm;0;ON;;;;;Y;;;;; +2A15;INTEGRAL AROUND A POINT OPERATOR;Sm;0;ON;;;;;Y;;;;; +2A16;QUATERNION INTEGRAL OPERATOR;Sm;0;ON;;;;;Y;;;;; +2A17;INTEGRAL WITH LEFTWARDS ARROW WITH HOOK;Sm;0;ON;;;;;Y;;;;; +2A18;INTEGRAL WITH TIMES SIGN;Sm;0;ON;;;;;Y;;;;; +2A19;INTEGRAL WITH INTERSECTION;Sm;0;ON;;;;;Y;;;;; +2A1A;INTEGRAL WITH UNION;Sm;0;ON;;;;;Y;;;;; +2A1B;INTEGRAL WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; +2A1C;INTEGRAL WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; +2A1D;JOIN;Sm;0;ON;;;;;N;;;;; +2A1E;LARGE LEFT TRIANGLE OPERATOR;Sm;0;ON;;;;;Y;;;;; +2A1F;Z NOTATION SCHEMA COMPOSITION;Sm;0;ON;;;;;Y;;;;; +2A20;Z NOTATION SCHEMA PIPING;Sm;0;ON;;;;;Y;;;;; +2A21;Z NOTATION SCHEMA PROJECTION;Sm;0;ON;;;;;Y;;;;; +2A22;PLUS SIGN WITH SMALL CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;; +2A23;PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE;Sm;0;ON;;;;;N;;;;; +2A24;PLUS SIGN WITH TILDE ABOVE;Sm;0;ON;;;;;Y;;;;; +2A25;PLUS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;; +2A26;PLUS SIGN WITH TILDE BELOW;Sm;0;ON;;;;;Y;;;;; +2A27;PLUS SIGN WITH SUBSCRIPT TWO;Sm;0;ON;;;;;N;;;;; +2A28;PLUS SIGN WITH BLACK TRIANGLE;Sm;0;ON;;;;;N;;;;; +2A29;MINUS SIGN WITH COMMA ABOVE;Sm;0;ON;;;;;Y;;;;; +2A2A;MINUS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;; +2A2B;MINUS SIGN WITH FALLING DOTS;Sm;0;ON;;;;;Y;;;;; +2A2C;MINUS SIGN WITH RISING DOTS;Sm;0;ON;;;;;Y;;;;; +2A2D;PLUS SIGN IN LEFT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;; +2A2E;PLUS SIGN IN RIGHT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;; +2A2F;VECTOR OR CROSS PRODUCT;Sm;0;ON;;;;;N;;;;; +2A30;MULTIPLICATION SIGN WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; +2A31;MULTIPLICATION SIGN WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; +2A32;SEMIDIRECT PRODUCT WITH BOTTOM CLOSED;Sm;0;ON;;;;;N;;;;; +2A33;SMASH PRODUCT;Sm;0;ON;;;;;N;;;;; +2A34;MULTIPLICATION SIGN IN LEFT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;; +2A35;MULTIPLICATION SIGN IN RIGHT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;; +2A36;CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT;Sm;0;ON;;;;;N;;;;; +2A37;MULTIPLICATION SIGN IN DOUBLE CIRCLE;Sm;0;ON;;;;;N;;;;; +2A38;CIRCLED DIVISION SIGN;Sm;0;ON;;;;;N;;;;; +2A39;PLUS SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;; +2A3A;MINUS SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;; +2A3B;MULTIPLICATION SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;; +2A3C;INTERIOR PRODUCT;Sm;0;ON;;;;;Y;;;;; +2A3D;RIGHTHAND INTERIOR PRODUCT;Sm;0;ON;;;;;Y;;;;; +2A3E;Z NOTATION RELATIONAL COMPOSITION;Sm;0;ON;;;;;Y;;;;; +2A3F;AMALGAMATION OR COPRODUCT;Sm;0;ON;;;;;N;;;;; +2A40;INTERSECTION WITH DOT;Sm;0;ON;;;;;N;;;;; +2A41;UNION WITH MINUS SIGN;Sm;0;ON;;;;;N;;;;; +2A42;UNION WITH OVERBAR;Sm;0;ON;;;;;N;;;;; +2A43;INTERSECTION WITH OVERBAR;Sm;0;ON;;;;;N;;;;; +2A44;INTERSECTION WITH LOGICAL AND;Sm;0;ON;;;;;N;;;;; +2A45;UNION WITH LOGICAL OR;Sm;0;ON;;;;;N;;;;; +2A46;UNION ABOVE INTERSECTION;Sm;0;ON;;;;;N;;;;; +2A47;INTERSECTION ABOVE UNION;Sm;0;ON;;;;;N;;;;; +2A48;UNION ABOVE BAR ABOVE INTERSECTION;Sm;0;ON;;;;;N;;;;; +2A49;INTERSECTION ABOVE BAR ABOVE UNION;Sm;0;ON;;;;;N;;;;; +2A4A;UNION BESIDE AND JOINED WITH UNION;Sm;0;ON;;;;;N;;;;; +2A4B;INTERSECTION BESIDE AND JOINED WITH INTERSECTION;Sm;0;ON;;;;;N;;;;; +2A4C;CLOSED UNION WITH SERIFS;Sm;0;ON;;;;;N;;;;; +2A4D;CLOSED INTERSECTION WITH SERIFS;Sm;0;ON;;;;;N;;;;; +2A4E;DOUBLE SQUARE INTERSECTION;Sm;0;ON;;;;;N;;;;; +2A4F;DOUBLE SQUARE UNION;Sm;0;ON;;;;;N;;;;; +2A50;CLOSED UNION WITH SERIFS AND SMASH PRODUCT;Sm;0;ON;;;;;N;;;;; +2A51;LOGICAL AND WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; +2A52;LOGICAL OR WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; +2A53;DOUBLE LOGICAL AND;Sm;0;ON;;;;;N;;;;; +2A54;DOUBLE LOGICAL OR;Sm;0;ON;;;;;N;;;;; +2A55;TWO INTERSECTING LOGICAL AND;Sm;0;ON;;;;;N;;;;; +2A56;TWO INTERSECTING LOGICAL OR;Sm;0;ON;;;;;N;;;;; +2A57;SLOPING LARGE OR;Sm;0;ON;;;;;Y;;;;; +2A58;SLOPING LARGE AND;Sm;0;ON;;;;;Y;;;;; +2A59;LOGICAL OR OVERLAPPING LOGICAL AND;Sm;0;ON;;;;;N;;;;; +2A5A;LOGICAL AND WITH MIDDLE STEM;Sm;0;ON;;;;;N;;;;; +2A5B;LOGICAL OR WITH MIDDLE STEM;Sm;0;ON;;;;;N;;;;; +2A5C;LOGICAL AND WITH HORIZONTAL DASH;Sm;0;ON;;;;;N;;;;; +2A5D;LOGICAL OR WITH HORIZONTAL DASH;Sm;0;ON;;;;;N;;;;; +2A5E;LOGICAL AND WITH DOUBLE OVERBAR;Sm;0;ON;;;;;N;;;;; +2A5F;LOGICAL AND WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; +2A60;LOGICAL AND WITH DOUBLE UNDERBAR;Sm;0;ON;;;;;N;;;;; +2A61;SMALL VEE WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; +2A62;LOGICAL OR WITH DOUBLE OVERBAR;Sm;0;ON;;;;;N;;;;; +2A63;LOGICAL OR WITH DOUBLE UNDERBAR;Sm;0;ON;;;;;N;;;;; +2A64;Z NOTATION DOMAIN ANTIRESTRICTION;Sm;0;ON;;;;;Y;;;;; +2A65;Z NOTATION RANGE ANTIRESTRICTION;Sm;0;ON;;;;;Y;;;;; +2A66;EQUALS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;; +2A67;IDENTICAL WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; +2A68;TRIPLE HORIZONTAL BAR WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2A69;TRIPLE HORIZONTAL BAR WITH TRIPLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2A6A;TILDE OPERATOR WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; +2A6B;TILDE OPERATOR WITH RISING DOTS;Sm;0;ON;;;;;Y;;;;; +2A6C;SIMILAR MINUS SIMILAR;Sm;0;ON;;;;;Y;;;;; +2A6D;CONGRUENT WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; +2A6E;EQUALS WITH ASTERISK;Sm;0;ON;;;;;N;;;;; +2A6F;ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT;Sm;0;ON;;;;;Y;;;;; +2A70;APPROXIMATELY EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2A71;EQUALS SIGN ABOVE PLUS SIGN;Sm;0;ON;;;;;N;;;;; +2A72;PLUS SIGN ABOVE EQUALS SIGN;Sm;0;ON;;;;;N;;;;; +2A73;EQUALS SIGN ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; +2A74;DOUBLE COLON EQUAL;Sm;0;ON; 003A 003A 003D;;;;Y;;;;; +2A75;TWO CONSECUTIVE EQUALS SIGNS;Sm;0;ON; 003D 003D;;;;N;;;;; +2A76;THREE CONSECUTIVE EQUALS SIGNS;Sm;0;ON; 003D 003D 003D;;;;N;;;;; +2A77;EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW;Sm;0;ON;;;;;N;;;;; +2A78;EQUIVALENT WITH FOUR DOTS ABOVE;Sm;0;ON;;;;;N;;;;; +2A79;LESS-THAN WITH CIRCLE INSIDE;Sm;0;ON;;;;;Y;;;;; +2A7A;GREATER-THAN WITH CIRCLE INSIDE;Sm;0;ON;;;;;Y;;;;; +2A7B;LESS-THAN WITH QUESTION MARK ABOVE;Sm;0;ON;;;;;Y;;;;; +2A7C;GREATER-THAN WITH QUESTION MARK ABOVE;Sm;0;ON;;;;;Y;;;;; +2A7D;LESS-THAN OR SLANTED EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2A7E;GREATER-THAN OR SLANTED EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2A7F;LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;; +2A80;GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;; +2A81;LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; +2A82;GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; +2A83;LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT;Sm;0;ON;;;;;Y;;;;; +2A84;GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT;Sm;0;ON;;;;;Y;;;;; +2A85;LESS-THAN OR APPROXIMATE;Sm;0;ON;;;;;Y;;;;; +2A86;GREATER-THAN OR APPROXIMATE;Sm;0;ON;;;;;Y;;;;; +2A87;LESS-THAN AND SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2A88;GREATER-THAN AND SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2A89;LESS-THAN AND NOT APPROXIMATE;Sm;0;ON;;;;;Y;;;;; +2A8A;GREATER-THAN AND NOT APPROXIMATE;Sm;0;ON;;;;;Y;;;;; +2A8B;LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +2A8C;GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN;Sm;0;ON;;;;;Y;;;;; +2A8D;LESS-THAN ABOVE SIMILAR OR EQUAL;Sm;0;ON;;;;;Y;;;;; +2A8E;GREATER-THAN ABOVE SIMILAR OR EQUAL;Sm;0;ON;;;;;Y;;;;; +2A8F;LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +2A90;GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN;Sm;0;ON;;;;;Y;;;;; +2A91;LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL;Sm;0;ON;;;;;Y;;;;; +2A92;GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL;Sm;0;ON;;;;;Y;;;;; +2A93;LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;; +2A94;GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;; +2A95;SLANTED EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;; +2A96;SLANTED EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +2A97;SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;; +2A98;SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;; +2A99;DOUBLE-LINE EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;; +2A9A;DOUBLE-LINE EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +2A9B;DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;; +2A9C;DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +2A9D;SIMILAR OR LESS-THAN;Sm;0;ON;;;;;Y;;;;; +2A9E;SIMILAR OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +2A9F;SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; +2AA0;SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; +2AA1;DOUBLE NESTED LESS-THAN;Sm;0;ON;;;;;Y;;;;; +2AA2;DOUBLE NESTED GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +2AA3;DOUBLE NESTED LESS-THAN WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; +2AA4;GREATER-THAN OVERLAPPING LESS-THAN;Sm;0;ON;;;;;N;;;;; +2AA5;GREATER-THAN BESIDE LESS-THAN;Sm;0;ON;;;;;N;;;;; +2AA6;LESS-THAN CLOSED BY CURVE;Sm;0;ON;;;;;Y;;;;; +2AA7;GREATER-THAN CLOSED BY CURVE;Sm;0;ON;;;;;Y;;;;; +2AA8;LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;; +2AA9;GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;; +2AAA;SMALLER THAN;Sm;0;ON;;;;;Y;;;;; +2AAB;LARGER THAN;Sm;0;ON;;;;;Y;;;;; +2AAC;SMALLER THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AAD;LARGER THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AAE;EQUALS SIGN WITH BUMPY ABOVE;Sm;0;ON;;;;;N;;;;; +2AAF;PRECEDES ABOVE SINGLE-LINE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; +2AB0;SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; +2AB1;PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AB2;SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AB3;PRECEDES ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; +2AB4;SUCCEEDS ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; +2AB5;PRECEDES ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AB6;SUCCEEDS ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AB7;PRECEDES ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AB8;SUCCEEDS ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AB9;PRECEDES ABOVE NOT ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2ABA;SUCCEEDS ABOVE NOT ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2ABB;DOUBLE PRECEDES;Sm;0;ON;;;;;Y;;;;; +2ABC;DOUBLE SUCCEEDS;Sm;0;ON;;;;;Y;;;;; +2ABD;SUBSET WITH DOT;Sm;0;ON;;;;;Y;;;;; +2ABE;SUPERSET WITH DOT;Sm;0;ON;;;;;Y;;;;; +2ABF;SUBSET WITH PLUS SIGN BELOW;Sm;0;ON;;;;;Y;;;;; +2AC0;SUPERSET WITH PLUS SIGN BELOW;Sm;0;ON;;;;;Y;;;;; +2AC1;SUBSET WITH MULTIPLICATION SIGN BELOW;Sm;0;ON;;;;;Y;;;;; +2AC2;SUPERSET WITH MULTIPLICATION SIGN BELOW;Sm;0;ON;;;;;Y;;;;; +2AC3;SUBSET OF OR EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; +2AC4;SUPERSET OF OR EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; +2AC5;SUBSET OF ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; +2AC6;SUPERSET OF ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; +2AC7;SUBSET OF ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; +2AC8;SUPERSET OF ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; +2AC9;SUBSET OF ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2ACA;SUPERSET OF ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2ACB;SUBSET OF ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2ACC;SUPERSET OF ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2ACD;SQUARE LEFT OPEN BOX OPERATOR;Sm;0;ON;;;;;Y;;;;; +2ACE;SQUARE RIGHT OPEN BOX OPERATOR;Sm;0;ON;;;;;Y;;;;; +2ACF;CLOSED SUBSET;Sm;0;ON;;;;;Y;;;;; +2AD0;CLOSED SUPERSET;Sm;0;ON;;;;;Y;;;;; +2AD1;CLOSED SUBSET OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AD2;CLOSED SUPERSET OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AD3;SUBSET ABOVE SUPERSET;Sm;0;ON;;;;;Y;;;;; +2AD4;SUPERSET ABOVE SUBSET;Sm;0;ON;;;;;Y;;;;; +2AD5;SUBSET ABOVE SUBSET;Sm;0;ON;;;;;Y;;;;; +2AD6;SUPERSET ABOVE SUPERSET;Sm;0;ON;;;;;Y;;;;; +2AD7;SUPERSET BESIDE SUBSET;Sm;0;ON;;;;;N;;;;; +2AD8;SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET;Sm;0;ON;;;;;N;;;;; +2AD9;ELEMENT OF OPENING DOWNWARDS;Sm;0;ON;;;;;N;;;;; +2ADA;PITCHFORK WITH TEE TOP;Sm;0;ON;;;;;N;;;;; +2ADB;TRANSVERSAL INTERSECTION;Sm;0;ON;;;;;N;;;;; +2ADC;FORKING;Sm;0;ON;2ADD 0338;;;;Y;;;;; +2ADD;NONFORKING;Sm;0;ON;;;;;N;;;;; +2ADE;SHORT LEFT TACK;Sm;0;ON;;;;;Y;;;;; +2ADF;SHORT DOWN TACK;Sm;0;ON;;;;;N;;;;; +2AE0;SHORT UP TACK;Sm;0;ON;;;;;N;;;;; +2AE1;PERPENDICULAR WITH S;Sm;0;ON;;;;;N;;;;; +2AE2;VERTICAL BAR TRIPLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;; +2AE3;DOUBLE VERTICAL BAR LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;; +2AE4;VERTICAL BAR DOUBLE LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;; +2AE5;DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;; +2AE6;LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL;Sm;0;ON;;;;;Y;;;;; +2AE7;SHORT DOWN TACK WITH OVERBAR;Sm;0;ON;;;;;N;;;;; +2AE8;SHORT UP TACK WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; +2AE9;SHORT UP TACK ABOVE SHORT DOWN TACK;Sm;0;ON;;;;;N;;;;; +2AEA;DOUBLE DOWN TACK;Sm;0;ON;;;;;N;;;;; +2AEB;DOUBLE UP TACK;Sm;0;ON;;;;;N;;;;; +2AEC;DOUBLE STROKE NOT SIGN;Sm;0;ON;;;;;Y;;;;; +2AED;REVERSED DOUBLE STROKE NOT SIGN;Sm;0;ON;;;;;Y;;;;; +2AEE;DOES NOT DIVIDE WITH REVERSED NEGATION SLASH;Sm;0;ON;;;;;Y;;;;; +2AEF;VERTICAL LINE WITH CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;; +2AF0;VERTICAL LINE WITH CIRCLE BELOW;Sm;0;ON;;;;;N;;;;; +2AF1;DOWN TACK WITH CIRCLE BELOW;Sm;0;ON;;;;;N;;;;; +2AF2;PARALLEL WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; +2AF3;PARALLEL WITH TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; +2AF4;TRIPLE VERTICAL BAR BINARY RELATION;Sm;0;ON;;;;;N;;;;; +2AF5;TRIPLE VERTICAL BAR WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; +2AF6;TRIPLE COLON OPERATOR;Sm;0;ON;;;;;N;;;;; +2AF7;TRIPLE NESTED LESS-THAN;Sm;0;ON;;;;;Y;;;;; +2AF8;TRIPLE NESTED GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +2AF9;DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AFA;DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AFB;TRIPLE SOLIDUS BINARY RELATION;Sm;0;ON;;;;;Y;;;;; +2AFC;LARGE TRIPLE VERTICAL BAR OPERATOR;Sm;0;ON;;;;;N;;;;; +2AFD;DOUBLE SOLIDUS OPERATOR;Sm;0;ON;;;;;Y;;;;; +2AFE;WHITE VERTICAL BAR;Sm;0;ON;;;;;N;;;;; +2AFF;N-ARY WHITE VERTICAL BAR;Sm;0;ON;;;;;N;;;;; +2B00;NORTH EAST WHITE ARROW;So;0;ON;;;;;N;;;;; +2B01;NORTH WEST WHITE ARROW;So;0;ON;;;;;N;;;;; +2B02;SOUTH EAST WHITE ARROW;So;0;ON;;;;;N;;;;; +2B03;SOUTH WEST WHITE ARROW;So;0;ON;;;;;N;;;;; +2B04;LEFT RIGHT WHITE ARROW;So;0;ON;;;;;N;;;;; +2B05;LEFTWARDS BLACK ARROW;So;0;ON;;;;;N;;;;; +2B06;UPWARDS BLACK ARROW;So;0;ON;;;;;N;;;;; +2B07;DOWNWARDS BLACK ARROW;So;0;ON;;;;;N;;;;; +2B08;NORTH EAST BLACK ARROW;So;0;ON;;;;;N;;;;; +2B09;NORTH WEST BLACK ARROW;So;0;ON;;;;;N;;;;; +2B0A;SOUTH EAST BLACK ARROW;So;0;ON;;;;;N;;;;; +2B0B;SOUTH WEST BLACK ARROW;So;0;ON;;;;;N;;;;; +2B0C;LEFT RIGHT BLACK ARROW;So;0;ON;;;;;N;;;;; +2B0D;UP DOWN BLACK ARROW;So;0;ON;;;;;N;;;;; +2B0E;RIGHTWARDS ARROW WITH TIP DOWNWARDS;So;0;ON;;;;;N;;;;; +2B0F;RIGHTWARDS ARROW WITH TIP UPWARDS;So;0;ON;;;;;N;;;;; +2B10;LEFTWARDS ARROW WITH TIP DOWNWARDS;So;0;ON;;;;;N;;;;; +2B11;LEFTWARDS ARROW WITH TIP UPWARDS;So;0;ON;;;;;N;;;;; +2B12;SQUARE WITH TOP HALF BLACK;So;0;ON;;;;;N;;;;; +2B13;SQUARE WITH BOTTOM HALF BLACK;So;0;ON;;;;;N;;;;; +2B14;SQUARE WITH UPPER RIGHT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;; +2B15;SQUARE WITH LOWER LEFT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;; +2B16;DIAMOND WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;; +2B17;DIAMOND WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;; +2B18;DIAMOND WITH TOP HALF BLACK;So;0;ON;;;;;N;;;;; +2B19;DIAMOND WITH BOTTOM HALF BLACK;So;0;ON;;;;;N;;;;; +2B1A;DOTTED SQUARE;So;0;ON;;;;;N;;;;; +2B1B;BLACK LARGE SQUARE;So;0;ON;;;;;N;;;;; +2B1C;WHITE LARGE SQUARE;So;0;ON;;;;;N;;;;; +2B1D;BLACK VERY SMALL SQUARE;So;0;ON;;;;;N;;;;; +2B1E;WHITE VERY SMALL SQUARE;So;0;ON;;;;;N;;;;; +2B1F;BLACK PENTAGON;So;0;ON;;;;;N;;;;; +2B20;WHITE PENTAGON;So;0;ON;;;;;N;;;;; +2B21;WHITE HEXAGON;So;0;ON;;;;;N;;;;; +2B22;BLACK HEXAGON;So;0;ON;;;;;N;;;;; +2B23;HORIZONTAL BLACK HEXAGON;So;0;ON;;;;;N;;;;; +2B24;BLACK LARGE CIRCLE;So;0;ON;;;;;N;;;;; +2B25;BLACK MEDIUM DIAMOND;So;0;ON;;;;;N;;;;; +2B26;WHITE MEDIUM DIAMOND;So;0;ON;;;;;N;;;;; +2B27;BLACK MEDIUM LOZENGE;So;0;ON;;;;;N;;;;; +2B28;WHITE MEDIUM LOZENGE;So;0;ON;;;;;N;;;;; +2B29;BLACK SMALL DIAMOND;So;0;ON;;;;;N;;;;; +2B2A;BLACK SMALL LOZENGE;So;0;ON;;;;;N;;;;; +2B2B;WHITE SMALL LOZENGE;So;0;ON;;;;;N;;;;; +2B2C;BLACK HORIZONTAL ELLIPSE;So;0;ON;;;;;N;;;;; +2B2D;WHITE HORIZONTAL ELLIPSE;So;0;ON;;;;;N;;;;; +2B2E;BLACK VERTICAL ELLIPSE;So;0;ON;;;;;N;;;;; +2B2F;WHITE VERTICAL ELLIPSE;So;0;ON;;;;;N;;;;; +2B30;LEFT ARROW WITH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; +2B31;THREE LEFTWARDS ARROWS;Sm;0;ON;;;;;N;;;;; +2B32;LEFT ARROW WITH CIRCLED PLUS;Sm;0;ON;;;;;N;;;;; +2B33;LONG LEFTWARDS SQUIGGLE ARROW;Sm;0;ON;;;;;N;;;;; +2B34;LEFTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2B35;LEFTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2B36;LEFTWARDS TWO-HEADED ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; +2B37;LEFTWARDS TWO-HEADED TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;; +2B38;LEFTWARDS ARROW WITH DOTTED STEM;Sm;0;ON;;;;;N;;;;; +2B39;LEFTWARDS ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2B3A;LEFTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2B3B;LEFTWARDS TWO-HEADED ARROW WITH TAIL;Sm;0;ON;;;;;N;;;;; +2B3C;LEFTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2B3D;LEFTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2B3E;LEFTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;; +2B3F;WAVE ARROW POINTING DIRECTLY LEFT;Sm;0;ON;;;;;N;;;;; +2B40;EQUALS SIGN ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2B41;REVERSE TILDE OPERATOR ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2B42;LEFTWARDS ARROW ABOVE REVERSE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;; +2B43;RIGHTWARDS ARROW THROUGH GREATER-THAN;Sm;0;ON;;;;;N;;;;; +2B44;RIGHTWARDS ARROW THROUGH SUPERSET;Sm;0;ON;;;;;N;;;;; +2B45;LEFTWARDS QUADRUPLE ARROW;So;0;ON;;;;;N;;;;; +2B46;RIGHTWARDS QUADRUPLE ARROW;So;0;ON;;;;;N;;;;; +2B47;REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2B48;RIGHTWARDS ARROW ABOVE REVERSE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;; +2B49;TILDE OPERATOR ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2B4A;LEFTWARDS ARROW ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;; +2B4B;LEFTWARDS ARROW ABOVE REVERSE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;; +2B4C;RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;; +2B4D;DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW;So;0;ON;;;;;N;;;;; +2B4E;SHORT SLANTED NORTH ARROW;So;0;ON;;;;;N;;;;; +2B4F;SHORT BACKSLANTED SOUTH ARROW;So;0;ON;;;;;N;;;;; +2B50;WHITE MEDIUM STAR;So;0;ON;;;;;N;;;;; +2B51;BLACK SMALL STAR;So;0;ON;;;;;N;;;;; +2B52;WHITE SMALL STAR;So;0;ON;;;;;N;;;;; +2B53;BLACK RIGHT-POINTING PENTAGON;So;0;ON;;;;;N;;;;; +2B54;WHITE RIGHT-POINTING PENTAGON;So;0;ON;;;;;N;;;;; +2B55;HEAVY LARGE CIRCLE;So;0;ON;;;;;N;;;;; +2B56;HEAVY OVAL WITH OVAL INSIDE;So;0;ON;;;;;N;;;;; +2B57;HEAVY CIRCLE WITH CIRCLE INSIDE;So;0;ON;;;;;N;;;;; +2B58;HEAVY CIRCLE;So;0;ON;;;;;N;;;;; +2B59;HEAVY CIRCLED SALTIRE;So;0;ON;;;;;N;;;;; +2B5A;SLANTED NORTH ARROW WITH HOOKED HEAD;So;0;ON;;;;;N;;;;; +2B5B;BACKSLANTED SOUTH ARROW WITH HOOKED TAIL;So;0;ON;;;;;N;;;;; +2B5C;SLANTED NORTH ARROW WITH HORIZONTAL TAIL;So;0;ON;;;;;N;;;;; +2B5D;BACKSLANTED SOUTH ARROW WITH HORIZONTAL TAIL;So;0;ON;;;;;N;;;;; +2B5E;BENT ARROW POINTING DOWNWARDS THEN NORTH EAST;So;0;ON;;;;;N;;;;; +2B5F;SHORT BENT ARROW POINTING DOWNWARDS THEN NORTH EAST;So;0;ON;;;;;N;;;;; +2B60;LEFTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B61;UPWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B62;RIGHTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B63;DOWNWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B64;LEFT RIGHT TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B65;UP DOWN TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B66;NORTH WEST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B67;NORTH EAST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B68;SOUTH EAST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B69;SOUTH WEST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B6A;LEFTWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;; +2B6B;UPWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;; +2B6C;RIGHTWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;; +2B6D;DOWNWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;; +2B6E;CLOCKWISE TRIANGLE-HEADED OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;; +2B6F;ANTICLOCKWISE TRIANGLE-HEADED OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;; +2B70;LEFTWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; +2B71;UPWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; +2B72;RIGHTWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; +2B73;DOWNWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; +2B76;NORTH WEST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; +2B77;NORTH EAST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; +2B78;SOUTH EAST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; +2B79;SOUTH WEST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; +2B7A;LEFTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;; +2B7B;UPWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;; +2B7C;RIGHTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;; +2B7D;DOWNWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;; +2B7E;HORIZONTAL TAB KEY;So;0;ON;;;;;N;;;;; +2B7F;VERTICAL TAB KEY;So;0;ON;;;;;N;;;;; +2B80;LEFTWARDS TRIANGLE-HEADED ARROW OVER RIGHTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B81;UPWARDS TRIANGLE-HEADED ARROW LEFTWARDS OF DOWNWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B82;RIGHTWARDS TRIANGLE-HEADED ARROW OVER LEFTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B83;DOWNWARDS TRIANGLE-HEADED ARROW LEFTWARDS OF UPWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B84;LEFTWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;; +2B85;UPWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;; +2B86;RIGHTWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;; +2B87;DOWNWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;; +2B88;LEFTWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;; +2B89;UPWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;; +2B8A;RIGHTWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;; +2B8B;DOWNWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;; +2B8C;ANTICLOCKWISE TRIANGLE-HEADED RIGHT U-SHAPED ARROW;So;0;ON;;;;;N;;;;; +2B8D;ANTICLOCKWISE TRIANGLE-HEADED BOTTOM U-SHAPED ARROW;So;0;ON;;;;;N;;;;; +2B8E;ANTICLOCKWISE TRIANGLE-HEADED LEFT U-SHAPED ARROW;So;0;ON;;;;;N;;;;; +2B8F;ANTICLOCKWISE TRIANGLE-HEADED TOP U-SHAPED ARROW;So;0;ON;;;;;N;;;;; +2B90;RETURN LEFT;So;0;ON;;;;;N;;;;; +2B91;RETURN RIGHT;So;0;ON;;;;;N;;;;; +2B92;NEWLINE LEFT;So;0;ON;;;;;N;;;;; +2B93;NEWLINE RIGHT;So;0;ON;;;;;N;;;;; +2B94;FOUR CORNER ARROWS CIRCLING ANTICLOCKWISE;So;0;ON;;;;;N;;;;; +2B95;RIGHTWARDS BLACK ARROW;So;0;ON;;;;;N;;;;; +2B96;EQUALS SIGN WITH INFINITY ABOVE;So;0;ON;;;;;N;;;;; +2B97;SYMBOL FOR TYPE A ELECTRONICS;So;0;ON;;;;;N;;;;; +2B98;THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +2B99;THREE-D RIGHT-LIGHTED UPWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +2B9A;THREE-D TOP-LIGHTED RIGHTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +2B9B;THREE-D LEFT-LIGHTED DOWNWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +2B9C;BLACK LEFTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +2B9D;BLACK UPWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +2B9E;BLACK RIGHTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +2B9F;BLACK DOWNWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +2BA0;DOWNWARDS TRIANGLE-HEADED ARROW WITH LONG TIP LEFTWARDS;So;0;ON;;;;;N;;;;; +2BA1;DOWNWARDS TRIANGLE-HEADED ARROW WITH LONG TIP RIGHTWARDS;So;0;ON;;;;;N;;;;; +2BA2;UPWARDS TRIANGLE-HEADED ARROW WITH LONG TIP LEFTWARDS;So;0;ON;;;;;N;;;;; +2BA3;UPWARDS TRIANGLE-HEADED ARROW WITH LONG TIP RIGHTWARDS;So;0;ON;;;;;N;;;;; +2BA4;LEFTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP UPWARDS;So;0;ON;;;;;N;;;;; +2BA5;RIGHTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP UPWARDS;So;0;ON;;;;;N;;;;; +2BA6;LEFTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP DOWNWARDS;So;0;ON;;;;;N;;;;; +2BA7;RIGHTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP DOWNWARDS;So;0;ON;;;;;N;;;;; +2BA8;BLACK CURVED DOWNWARDS AND LEFTWARDS ARROW;So;0;ON;;;;;N;;;;; +2BA9;BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;;;;; +2BAA;BLACK CURVED UPWARDS AND LEFTWARDS ARROW;So;0;ON;;;;;N;;;;; +2BAB;BLACK CURVED UPWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;;;;; +2BAC;BLACK CURVED LEFTWARDS AND UPWARDS ARROW;So;0;ON;;;;;N;;;;; +2BAD;BLACK CURVED RIGHTWARDS AND UPWARDS ARROW;So;0;ON;;;;;N;;;;; +2BAE;BLACK CURVED LEFTWARDS AND DOWNWARDS ARROW;So;0;ON;;;;;N;;;;; +2BAF;BLACK CURVED RIGHTWARDS AND DOWNWARDS ARROW;So;0;ON;;;;;N;;;;; +2BB0;RIBBON ARROW DOWN LEFT;So;0;ON;;;;;N;;;;; +2BB1;RIBBON ARROW DOWN RIGHT;So;0;ON;;;;;N;;;;; +2BB2;RIBBON ARROW UP LEFT;So;0;ON;;;;;N;;;;; +2BB3;RIBBON ARROW UP RIGHT;So;0;ON;;;;;N;;;;; +2BB4;RIBBON ARROW LEFT UP;So;0;ON;;;;;N;;;;; +2BB5;RIBBON ARROW RIGHT UP;So;0;ON;;;;;N;;;;; +2BB6;RIBBON ARROW LEFT DOWN;So;0;ON;;;;;N;;;;; +2BB7;RIBBON ARROW RIGHT DOWN;So;0;ON;;;;;N;;;;; +2BB8;UPWARDS WHITE ARROW FROM BAR WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;; +2BB9;UP ARROWHEAD IN A RECTANGLE BOX;So;0;ON;;;;;N;;;;; +2BBA;OVERLAPPING WHITE SQUARES;So;0;ON;;;;;N;;;;; +2BBB;OVERLAPPING WHITE AND BLACK SQUARES;So;0;ON;;;;;N;;;;; +2BBC;OVERLAPPING BLACK SQUARES;So;0;ON;;;;;N;;;;; +2BBD;BALLOT BOX WITH LIGHT X;So;0;ON;;;;;N;;;;; +2BBE;CIRCLED X;So;0;ON;;;;;N;;;;; +2BBF;CIRCLED BOLD X;So;0;ON;;;;;N;;;;; +2BC0;BLACK SQUARE CENTRED;So;0;ON;;;;;N;;;;; +2BC1;BLACK DIAMOND CENTRED;So;0;ON;;;;;N;;;;; +2BC2;TURNED BLACK PENTAGON;So;0;ON;;;;;N;;;;; +2BC3;HORIZONTAL BLACK OCTAGON;So;0;ON;;;;;N;;;;; +2BC4;BLACK OCTAGON;So;0;ON;;;;;N;;;;; +2BC5;BLACK MEDIUM UP-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;; +2BC6;BLACK MEDIUM DOWN-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;; +2BC7;BLACK MEDIUM LEFT-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;; +2BC8;BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;; +2BC9;NEPTUNE FORM TWO;So;0;ON;;;;;N;;;;; +2BCA;TOP HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; +2BCB;BOTTOM HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; +2BCC;LIGHT FOUR POINTED BLACK CUSP;So;0;ON;;;;;N;;;;; +2BCD;ROTATED LIGHT FOUR POINTED BLACK CUSP;So;0;ON;;;;;N;;;;; +2BCE;WHITE FOUR POINTED CUSP;So;0;ON;;;;;N;;;;; +2BCF;ROTATED WHITE FOUR POINTED CUSP;So;0;ON;;;;;N;;;;; +2BD0;SQUARE POSITION INDICATOR;So;0;ON;;;;;N;;;;; +2BD1;UNCERTAINTY SIGN;So;0;ON;;;;;N;;;;; +2BD2;GROUP MARK;So;0;ON;;;;;N;;;;; +2BD3;PLUTO FORM TWO;So;0;ON;;;;;N;;;;; +2BD4;PLUTO FORM THREE;So;0;ON;;;;;N;;;;; +2BD5;PLUTO FORM FOUR;So;0;ON;;;;;N;;;;; +2BD6;PLUTO FORM FIVE;So;0;ON;;;;;N;;;;; +2BD7;TRANSPLUTO;So;0;ON;;;;;N;;;;; +2BD8;PROSERPINA;So;0;ON;;;;;N;;;;; +2BD9;ASTRAEA;So;0;ON;;;;;N;;;;; +2BDA;HYGIEA;So;0;ON;;;;;N;;;;; +2BDB;PHOLUS;So;0;ON;;;;;N;;;;; +2BDC;NESSUS;So;0;ON;;;;;N;;;;; +2BDD;WHITE MOON SELENA;So;0;ON;;;;;N;;;;; +2BDE;BLACK DIAMOND ON CROSS;So;0;ON;;;;;N;;;;; +2BDF;TRUE LIGHT MOON ARTA;So;0;ON;;;;;N;;;;; +2BE0;CUPIDO;So;0;ON;;;;;N;;;;; +2BE1;HADES;So;0;ON;;;;;N;;;;; +2BE2;ZEUS;So;0;ON;;;;;N;;;;; +2BE3;KRONOS;So;0;ON;;;;;N;;;;; +2BE4;APOLLON;So;0;ON;;;;;N;;;;; +2BE5;ADMETOS;So;0;ON;;;;;N;;;;; +2BE6;VULCANUS;So;0;ON;;;;;N;;;;; +2BE7;POSEIDON;So;0;ON;;;;;N;;;;; +2BE8;LEFT HALF BLACK STAR;So;0;ON;;;;;N;;;;; +2BE9;RIGHT HALF BLACK STAR;So;0;ON;;;;;N;;;;; +2BEA;STAR WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;; +2BEB;STAR WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;; +2BEC;LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; +2BED;UPWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; +2BEE;RIGHTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; +2BEF;DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; +2BF0;ERIS FORM ONE;So;0;ON;;;;;N;;;;; +2BF1;ERIS FORM TWO;So;0;ON;;;;;N;;;;; +2BF2;SEDNA;So;0;ON;;;;;N;;;;; +2BF3;RUSSIAN ASTROLOGICAL SYMBOL VIGINTILE;So;0;ON;;;;;N;;;;; +2BF4;RUSSIAN ASTROLOGICAL SYMBOL NOVILE;So;0;ON;;;;;N;;;;; +2BF5;RUSSIAN ASTROLOGICAL SYMBOL QUINTILE;So;0;ON;;;;;N;;;;; +2BF6;RUSSIAN ASTROLOGICAL SYMBOL BINOVILE;So;0;ON;;;;;N;;;;; +2BF7;RUSSIAN ASTROLOGICAL SYMBOL SENTAGON;So;0;ON;;;;;N;;;;; +2BF8;RUSSIAN ASTROLOGICAL SYMBOL TREDECILE;So;0;ON;;;;;N;;;;; +2BF9;EQUALS SIGN WITH INFINITY BELOW;So;0;ON;;;;;N;;;;; +2BFA;UNITED SYMBOL;So;0;ON;;;;;N;;;;; +2BFB;SEPARATED SYMBOL;So;0;ON;;;;;N;;;;; +2BFC;DOUBLED SYMBOL;So;0;ON;;;;;N;;;;; +2BFD;PASSED SYMBOL;So;0;ON;;;;;N;;;;; +2BFE;REVERSED RIGHT ANGLE;So;0;ON;;;;;Y;;;;; +2BFF;HELLSCHREIBER PAUSE SYMBOL;So;0;ON;;;;;N;;;;; +2C00;GLAGOLITIC CAPITAL LETTER AZU;Lu;0;L;;;;;N;;;;2C30; +2C01;GLAGOLITIC CAPITAL LETTER BUKY;Lu;0;L;;;;;N;;;;2C31; +2C02;GLAGOLITIC CAPITAL LETTER VEDE;Lu;0;L;;;;;N;;;;2C32; +2C03;GLAGOLITIC CAPITAL LETTER GLAGOLI;Lu;0;L;;;;;N;;;;2C33; +2C04;GLAGOLITIC CAPITAL LETTER DOBRO;Lu;0;L;;;;;N;;;;2C34; +2C05;GLAGOLITIC CAPITAL LETTER YESTU;Lu;0;L;;;;;N;;;;2C35; +2C06;GLAGOLITIC CAPITAL LETTER ZHIVETE;Lu;0;L;;;;;N;;;;2C36; +2C07;GLAGOLITIC CAPITAL LETTER DZELO;Lu;0;L;;;;;N;;;;2C37; +2C08;GLAGOLITIC CAPITAL LETTER ZEMLJA;Lu;0;L;;;;;N;;;;2C38; +2C09;GLAGOLITIC CAPITAL LETTER IZHE;Lu;0;L;;;;;N;;;;2C39; +2C0A;GLAGOLITIC CAPITAL LETTER INITIAL IZHE;Lu;0;L;;;;;N;;;;2C3A; +2C0B;GLAGOLITIC CAPITAL LETTER I;Lu;0;L;;;;;N;;;;2C3B; +2C0C;GLAGOLITIC CAPITAL LETTER DJERVI;Lu;0;L;;;;;N;;;;2C3C; +2C0D;GLAGOLITIC CAPITAL LETTER KAKO;Lu;0;L;;;;;N;;;;2C3D; +2C0E;GLAGOLITIC CAPITAL LETTER LJUDIJE;Lu;0;L;;;;;N;;;;2C3E; +2C0F;GLAGOLITIC CAPITAL LETTER MYSLITE;Lu;0;L;;;;;N;;;;2C3F; +2C10;GLAGOLITIC CAPITAL LETTER NASHI;Lu;0;L;;;;;N;;;;2C40; +2C11;GLAGOLITIC CAPITAL LETTER ONU;Lu;0;L;;;;;N;;;;2C41; +2C12;GLAGOLITIC CAPITAL LETTER POKOJI;Lu;0;L;;;;;N;;;;2C42; +2C13;GLAGOLITIC CAPITAL LETTER RITSI;Lu;0;L;;;;;N;;;;2C43; +2C14;GLAGOLITIC CAPITAL LETTER SLOVO;Lu;0;L;;;;;N;;;;2C44; +2C15;GLAGOLITIC CAPITAL LETTER TVRIDO;Lu;0;L;;;;;N;;;;2C45; +2C16;GLAGOLITIC CAPITAL LETTER UKU;Lu;0;L;;;;;N;;;;2C46; +2C17;GLAGOLITIC CAPITAL LETTER FRITU;Lu;0;L;;;;;N;;;;2C47; +2C18;GLAGOLITIC CAPITAL LETTER HERU;Lu;0;L;;;;;N;;;;2C48; +2C19;GLAGOLITIC CAPITAL LETTER OTU;Lu;0;L;;;;;N;;;;2C49; +2C1A;GLAGOLITIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;2C4A; +2C1B;GLAGOLITIC CAPITAL LETTER SHTA;Lu;0;L;;;;;N;;;;2C4B; +2C1C;GLAGOLITIC CAPITAL LETTER TSI;Lu;0;L;;;;;N;;;;2C4C; +2C1D;GLAGOLITIC CAPITAL LETTER CHRIVI;Lu;0;L;;;;;N;;;;2C4D; +2C1E;GLAGOLITIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;2C4E; +2C1F;GLAGOLITIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;;;;2C4F; +2C20;GLAGOLITIC CAPITAL LETTER YERI;Lu;0;L;;;;;N;;;;2C50; +2C21;GLAGOLITIC CAPITAL LETTER YATI;Lu;0;L;;;;;N;;;;2C51; +2C22;GLAGOLITIC CAPITAL LETTER SPIDERY HA;Lu;0;L;;;;;N;;;;2C52; +2C23;GLAGOLITIC CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;2C53; +2C24;GLAGOLITIC CAPITAL LETTER SMALL YUS;Lu;0;L;;;;;N;;;;2C54; +2C25;GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL;Lu;0;L;;;;;N;;;;2C55; +2C26;GLAGOLITIC CAPITAL LETTER YO;Lu;0;L;;;;;N;;;;2C56; +2C27;GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS;Lu;0;L;;;;;N;;;;2C57; +2C28;GLAGOLITIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;2C58; +2C29;GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS;Lu;0;L;;;;;N;;;;2C59; +2C2A;GLAGOLITIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;2C5A; +2C2B;GLAGOLITIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;2C5B; +2C2C;GLAGOLITIC CAPITAL LETTER SHTAPIC;Lu;0;L;;;;;N;;;;2C5C; +2C2D;GLAGOLITIC CAPITAL LETTER TROKUTASTI A;Lu;0;L;;;;;N;;;;2C5D; +2C2E;GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE;Lu;0;L;;;;;N;;;;2C5E; +2C2F;GLAGOLITIC CAPITAL LETTER CAUDATE CHRIVI;Lu;0;L;;;;;N;;;;2C5F; +2C30;GLAGOLITIC SMALL LETTER AZU;Ll;0;L;;;;;N;;;2C00;;2C00 +2C31;GLAGOLITIC SMALL LETTER BUKY;Ll;0;L;;;;;N;;;2C01;;2C01 +2C32;GLAGOLITIC SMALL LETTER VEDE;Ll;0;L;;;;;N;;;2C02;;2C02 +2C33;GLAGOLITIC SMALL LETTER GLAGOLI;Ll;0;L;;;;;N;;;2C03;;2C03 +2C34;GLAGOLITIC SMALL LETTER DOBRO;Ll;0;L;;;;;N;;;2C04;;2C04 +2C35;GLAGOLITIC SMALL LETTER YESTU;Ll;0;L;;;;;N;;;2C05;;2C05 +2C36;GLAGOLITIC SMALL LETTER ZHIVETE;Ll;0;L;;;;;N;;;2C06;;2C06 +2C37;GLAGOLITIC SMALL LETTER DZELO;Ll;0;L;;;;;N;;;2C07;;2C07 +2C38;GLAGOLITIC SMALL LETTER ZEMLJA;Ll;0;L;;;;;N;;;2C08;;2C08 +2C39;GLAGOLITIC SMALL LETTER IZHE;Ll;0;L;;;;;N;;;2C09;;2C09 +2C3A;GLAGOLITIC SMALL LETTER INITIAL IZHE;Ll;0;L;;;;;N;;;2C0A;;2C0A +2C3B;GLAGOLITIC SMALL LETTER I;Ll;0;L;;;;;N;;;2C0B;;2C0B +2C3C;GLAGOLITIC SMALL LETTER DJERVI;Ll;0;L;;;;;N;;;2C0C;;2C0C +2C3D;GLAGOLITIC SMALL LETTER KAKO;Ll;0;L;;;;;N;;;2C0D;;2C0D +2C3E;GLAGOLITIC SMALL LETTER LJUDIJE;Ll;0;L;;;;;N;;;2C0E;;2C0E +2C3F;GLAGOLITIC SMALL LETTER MYSLITE;Ll;0;L;;;;;N;;;2C0F;;2C0F +2C40;GLAGOLITIC SMALL LETTER NASHI;Ll;0;L;;;;;N;;;2C10;;2C10 +2C41;GLAGOLITIC SMALL LETTER ONU;Ll;0;L;;;;;N;;;2C11;;2C11 +2C42;GLAGOLITIC SMALL LETTER POKOJI;Ll;0;L;;;;;N;;;2C12;;2C12 +2C43;GLAGOLITIC SMALL LETTER RITSI;Ll;0;L;;;;;N;;;2C13;;2C13 +2C44;GLAGOLITIC SMALL LETTER SLOVO;Ll;0;L;;;;;N;;;2C14;;2C14 +2C45;GLAGOLITIC SMALL LETTER TVRIDO;Ll;0;L;;;;;N;;;2C15;;2C15 +2C46;GLAGOLITIC SMALL LETTER UKU;Ll;0;L;;;;;N;;;2C16;;2C16 +2C47;GLAGOLITIC SMALL LETTER FRITU;Ll;0;L;;;;;N;;;2C17;;2C17 +2C48;GLAGOLITIC SMALL LETTER HERU;Ll;0;L;;;;;N;;;2C18;;2C18 +2C49;GLAGOLITIC SMALL LETTER OTU;Ll;0;L;;;;;N;;;2C19;;2C19 +2C4A;GLAGOLITIC SMALL LETTER PE;Ll;0;L;;;;;N;;;2C1A;;2C1A +2C4B;GLAGOLITIC SMALL LETTER SHTA;Ll;0;L;;;;;N;;;2C1B;;2C1B +2C4C;GLAGOLITIC SMALL LETTER TSI;Ll;0;L;;;;;N;;;2C1C;;2C1C +2C4D;GLAGOLITIC SMALL LETTER CHRIVI;Ll;0;L;;;;;N;;;2C1D;;2C1D +2C4E;GLAGOLITIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;2C1E;;2C1E +2C4F;GLAGOLITIC SMALL LETTER YERU;Ll;0;L;;;;;N;;;2C1F;;2C1F +2C50;GLAGOLITIC SMALL LETTER YERI;Ll;0;L;;;;;N;;;2C20;;2C20 +2C51;GLAGOLITIC SMALL LETTER YATI;Ll;0;L;;;;;N;;;2C21;;2C21 +2C52;GLAGOLITIC SMALL LETTER SPIDERY HA;Ll;0;L;;;;;N;;;2C22;;2C22 +2C53;GLAGOLITIC SMALL LETTER YU;Ll;0;L;;;;;N;;;2C23;;2C23 +2C54;GLAGOLITIC SMALL LETTER SMALL YUS;Ll;0;L;;;;;N;;;2C24;;2C24 +2C55;GLAGOLITIC SMALL LETTER SMALL YUS WITH TAIL;Ll;0;L;;;;;N;;;2C25;;2C25 +2C56;GLAGOLITIC SMALL LETTER YO;Ll;0;L;;;;;N;;;2C26;;2C26 +2C57;GLAGOLITIC SMALL LETTER IOTATED SMALL YUS;Ll;0;L;;;;;N;;;2C27;;2C27 +2C58;GLAGOLITIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;2C28;;2C28 +2C59;GLAGOLITIC SMALL LETTER IOTATED BIG YUS;Ll;0;L;;;;;N;;;2C29;;2C29 +2C5A;GLAGOLITIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;2C2A;;2C2A +2C5B;GLAGOLITIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;2C2B;;2C2B +2C5C;GLAGOLITIC SMALL LETTER SHTAPIC;Ll;0;L;;;;;N;;;2C2C;;2C2C +2C5D;GLAGOLITIC SMALL LETTER TROKUTASTI A;Ll;0;L;;;;;N;;;2C2D;;2C2D +2C5E;GLAGOLITIC SMALL LETTER LATINATE MYSLITE;Ll;0;L;;;;;N;;;2C2E;;2C2E +2C5F;GLAGOLITIC SMALL LETTER CAUDATE CHRIVI;Ll;0;L;;;;;N;;;2C2F;;2C2F +2C60;LATIN CAPITAL LETTER L WITH DOUBLE BAR;Lu;0;L;;;;;N;;;;2C61; +2C61;LATIN SMALL LETTER L WITH DOUBLE BAR;Ll;0;L;;;;;N;;;2C60;;2C60 +2C62;LATIN CAPITAL LETTER L WITH MIDDLE TILDE;Lu;0;L;;;;;N;;;;026B; +2C63;LATIN CAPITAL LETTER P WITH STROKE;Lu;0;L;;;;;N;;;;1D7D; +2C64;LATIN CAPITAL LETTER R WITH TAIL;Lu;0;L;;;;;N;;;;027D; +2C65;LATIN SMALL LETTER A WITH STROKE;Ll;0;L;;;;;N;;;023A;;023A +2C66;LATIN SMALL LETTER T WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;023E;;023E +2C67;LATIN CAPITAL LETTER H WITH DESCENDER;Lu;0;L;;;;;N;;;;2C68; +2C68;LATIN SMALL LETTER H WITH DESCENDER;Ll;0;L;;;;;N;;;2C67;;2C67 +2C69;LATIN CAPITAL LETTER K WITH DESCENDER;Lu;0;L;;;;;N;;;;2C6A; +2C6A;LATIN SMALL LETTER K WITH DESCENDER;Ll;0;L;;;;;N;;;2C69;;2C69 +2C6B;LATIN CAPITAL LETTER Z WITH DESCENDER;Lu;0;L;;;;;N;;;;2C6C; +2C6C;LATIN SMALL LETTER Z WITH DESCENDER;Ll;0;L;;;;;N;;;2C6B;;2C6B +2C6D;LATIN CAPITAL LETTER ALPHA;Lu;0;L;;;;;N;;;;0251; +2C6E;LATIN CAPITAL LETTER M WITH HOOK;Lu;0;L;;;;;N;;;;0271; +2C6F;LATIN CAPITAL LETTER TURNED A;Lu;0;L;;;;;N;;;;0250; +2C70;LATIN CAPITAL LETTER TURNED ALPHA;Lu;0;L;;;;;N;;;;0252; +2C71;LATIN SMALL LETTER V WITH RIGHT HOOK;Ll;0;L;;;;;N;;;;; +2C72;LATIN CAPITAL LETTER W WITH HOOK;Lu;0;L;;;;;N;;;;2C73; +2C73;LATIN SMALL LETTER W WITH HOOK;Ll;0;L;;;;;N;;;2C72;;2C72 +2C74;LATIN SMALL LETTER V WITH CURL;Ll;0;L;;;;;N;;;;; +2C75;LATIN CAPITAL LETTER HALF H;Lu;0;L;;;;;N;;;;2C76; +2C76;LATIN SMALL LETTER HALF H;Ll;0;L;;;;;N;;;2C75;;2C75 +2C77;LATIN SMALL LETTER TAILLESS PHI;Ll;0;L;;;;;N;;;;; +2C78;LATIN SMALL LETTER E WITH NOTCH;Ll;0;L;;;;;N;;;;; +2C79;LATIN SMALL LETTER TURNED R WITH TAIL;Ll;0;L;;;;;N;;;;; +2C7A;LATIN SMALL LETTER O WITH LOW RING INSIDE;Ll;0;L;;;;;N;;;;; +2C7B;LATIN LETTER SMALL CAPITAL TURNED E;Ll;0;L;;;;;N;;;;; +2C7C;LATIN SUBSCRIPT SMALL LETTER J;Lm;0;L; 006A;;;;N;;;;; +2C7D;MODIFIER LETTER CAPITAL V;Lm;0;L; 0056;;;;N;;;;; +2C7E;LATIN CAPITAL LETTER S WITH SWASH TAIL;Lu;0;L;;;;;N;;;;023F; +2C7F;LATIN CAPITAL LETTER Z WITH SWASH TAIL;Lu;0;L;;;;;N;;;;0240; +2C80;COPTIC CAPITAL LETTER ALFA;Lu;0;L;;;;;N;;;;2C81; +2C81;COPTIC SMALL LETTER ALFA;Ll;0;L;;;;;N;;;2C80;;2C80 +2C82;COPTIC CAPITAL LETTER VIDA;Lu;0;L;;;;;N;;;;2C83; +2C83;COPTIC SMALL LETTER VIDA;Ll;0;L;;;;;N;;;2C82;;2C82 +2C84;COPTIC CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;2C85; +2C85;COPTIC SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;2C84;;2C84 +2C86;COPTIC CAPITAL LETTER DALDA;Lu;0;L;;;;;N;;;;2C87; +2C87;COPTIC SMALL LETTER DALDA;Ll;0;L;;;;;N;;;2C86;;2C86 +2C88;COPTIC CAPITAL LETTER EIE;Lu;0;L;;;;;N;;;;2C89; +2C89;COPTIC SMALL LETTER EIE;Ll;0;L;;;;;N;;;2C88;;2C88 +2C8A;COPTIC CAPITAL LETTER SOU;Lu;0;L;;;;;N;;;;2C8B; +2C8B;COPTIC SMALL LETTER SOU;Ll;0;L;;;;;N;;;2C8A;;2C8A +2C8C;COPTIC CAPITAL LETTER ZATA;Lu;0;L;;;;;N;;;;2C8D; +2C8D;COPTIC SMALL LETTER ZATA;Ll;0;L;;;;;N;;;2C8C;;2C8C +2C8E;COPTIC CAPITAL LETTER HATE;Lu;0;L;;;;;N;;;;2C8F; +2C8F;COPTIC SMALL LETTER HATE;Ll;0;L;;;;;N;;;2C8E;;2C8E +2C90;COPTIC CAPITAL LETTER THETHE;Lu;0;L;;;;;N;;;;2C91; +2C91;COPTIC SMALL LETTER THETHE;Ll;0;L;;;;;N;;;2C90;;2C90 +2C92;COPTIC CAPITAL LETTER IAUDA;Lu;0;L;;;;;N;;;;2C93; +2C93;COPTIC SMALL LETTER IAUDA;Ll;0;L;;;;;N;;;2C92;;2C92 +2C94;COPTIC CAPITAL LETTER KAPA;Lu;0;L;;;;;N;;;;2C95; +2C95;COPTIC SMALL LETTER KAPA;Ll;0;L;;;;;N;;;2C94;;2C94 +2C96;COPTIC CAPITAL LETTER LAULA;Lu;0;L;;;;;N;;;;2C97; +2C97;COPTIC SMALL LETTER LAULA;Ll;0;L;;;;;N;;;2C96;;2C96 +2C98;COPTIC CAPITAL LETTER MI;Lu;0;L;;;;;N;;;;2C99; +2C99;COPTIC SMALL LETTER MI;Ll;0;L;;;;;N;;;2C98;;2C98 +2C9A;COPTIC CAPITAL LETTER NI;Lu;0;L;;;;;N;;;;2C9B; +2C9B;COPTIC SMALL LETTER NI;Ll;0;L;;;;;N;;;2C9A;;2C9A +2C9C;COPTIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;2C9D; +2C9D;COPTIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;2C9C;;2C9C +2C9E;COPTIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;2C9F; +2C9F;COPTIC SMALL LETTER O;Ll;0;L;;;;;N;;;2C9E;;2C9E +2CA0;COPTIC CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;2CA1; +2CA1;COPTIC SMALL LETTER PI;Ll;0;L;;;;;N;;;2CA0;;2CA0 +2CA2;COPTIC CAPITAL LETTER RO;Lu;0;L;;;;;N;;;;2CA3; +2CA3;COPTIC SMALL LETTER RO;Ll;0;L;;;;;N;;;2CA2;;2CA2 +2CA4;COPTIC CAPITAL LETTER SIMA;Lu;0;L;;;;;N;;;;2CA5; +2CA5;COPTIC SMALL LETTER SIMA;Ll;0;L;;;;;N;;;2CA4;;2CA4 +2CA6;COPTIC CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;2CA7; +2CA7;COPTIC SMALL LETTER TAU;Ll;0;L;;;;;N;;;2CA6;;2CA6 +2CA8;COPTIC CAPITAL LETTER UA;Lu;0;L;;;;;N;;;;2CA9; +2CA9;COPTIC SMALL LETTER UA;Ll;0;L;;;;;N;;;2CA8;;2CA8 +2CAA;COPTIC CAPITAL LETTER FI;Lu;0;L;;;;;N;;;;2CAB; +2CAB;COPTIC SMALL LETTER FI;Ll;0;L;;;;;N;;;2CAA;;2CAA +2CAC;COPTIC CAPITAL LETTER KHI;Lu;0;L;;;;;N;;;;2CAD; +2CAD;COPTIC SMALL LETTER KHI;Ll;0;L;;;;;N;;;2CAC;;2CAC +2CAE;COPTIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;2CAF; +2CAF;COPTIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;2CAE;;2CAE +2CB0;COPTIC CAPITAL LETTER OOU;Lu;0;L;;;;;N;;;;2CB1; +2CB1;COPTIC SMALL LETTER OOU;Ll;0;L;;;;;N;;;2CB0;;2CB0 +2CB2;COPTIC CAPITAL LETTER DIALECT-P ALEF;Lu;0;L;;;;;N;;;;2CB3; +2CB3;COPTIC SMALL LETTER DIALECT-P ALEF;Ll;0;L;;;;;N;;;2CB2;;2CB2 +2CB4;COPTIC CAPITAL LETTER OLD COPTIC AIN;Lu;0;L;;;;;N;;;;2CB5; +2CB5;COPTIC SMALL LETTER OLD COPTIC AIN;Ll;0;L;;;;;N;;;2CB4;;2CB4 +2CB6;COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE;Lu;0;L;;;;;N;;;;2CB7; +2CB7;COPTIC SMALL LETTER CRYPTOGRAMMIC EIE;Ll;0;L;;;;;N;;;2CB6;;2CB6 +2CB8;COPTIC CAPITAL LETTER DIALECT-P KAPA;Lu;0;L;;;;;N;;;;2CB9; +2CB9;COPTIC SMALL LETTER DIALECT-P KAPA;Ll;0;L;;;;;N;;;2CB8;;2CB8 +2CBA;COPTIC CAPITAL LETTER DIALECT-P NI;Lu;0;L;;;;;N;;;;2CBB; +2CBB;COPTIC SMALL LETTER DIALECT-P NI;Ll;0;L;;;;;N;;;2CBA;;2CBA +2CBC;COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI;Lu;0;L;;;;;N;;;;2CBD; +2CBD;COPTIC SMALL LETTER CRYPTOGRAMMIC NI;Ll;0;L;;;;;N;;;2CBC;;2CBC +2CBE;COPTIC CAPITAL LETTER OLD COPTIC OOU;Lu;0;L;;;;;N;;;;2CBF; +2CBF;COPTIC SMALL LETTER OLD COPTIC OOU;Ll;0;L;;;;;N;;;2CBE;;2CBE +2CC0;COPTIC CAPITAL LETTER SAMPI;Lu;0;L;;;;;N;;;;2CC1; +2CC1;COPTIC SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;2CC0;;2CC0 +2CC2;COPTIC CAPITAL LETTER CROSSED SHEI;Lu;0;L;;;;;N;;;;2CC3; +2CC3;COPTIC SMALL LETTER CROSSED SHEI;Ll;0;L;;;;;N;;;2CC2;;2CC2 +2CC4;COPTIC CAPITAL LETTER OLD COPTIC SHEI;Lu;0;L;;;;;N;;;;2CC5; +2CC5;COPTIC SMALL LETTER OLD COPTIC SHEI;Ll;0;L;;;;;N;;;2CC4;;2CC4 +2CC6;COPTIC CAPITAL LETTER OLD COPTIC ESH;Lu;0;L;;;;;N;;;;2CC7; +2CC7;COPTIC SMALL LETTER OLD COPTIC ESH;Ll;0;L;;;;;N;;;2CC6;;2CC6 +2CC8;COPTIC CAPITAL LETTER AKHMIMIC KHEI;Lu;0;L;;;;;N;;;;2CC9; +2CC9;COPTIC SMALL LETTER AKHMIMIC KHEI;Ll;0;L;;;;;N;;;2CC8;;2CC8 +2CCA;COPTIC CAPITAL LETTER DIALECT-P HORI;Lu;0;L;;;;;N;;;;2CCB; +2CCB;COPTIC SMALL LETTER DIALECT-P HORI;Ll;0;L;;;;;N;;;2CCA;;2CCA +2CCC;COPTIC CAPITAL LETTER OLD COPTIC HORI;Lu;0;L;;;;;N;;;;2CCD; +2CCD;COPTIC SMALL LETTER OLD COPTIC HORI;Ll;0;L;;;;;N;;;2CCC;;2CCC +2CCE;COPTIC CAPITAL LETTER OLD COPTIC HA;Lu;0;L;;;;;N;;;;2CCF; +2CCF;COPTIC SMALL LETTER OLD COPTIC HA;Ll;0;L;;;;;N;;;2CCE;;2CCE +2CD0;COPTIC CAPITAL LETTER L-SHAPED HA;Lu;0;L;;;;;N;;;;2CD1; +2CD1;COPTIC SMALL LETTER L-SHAPED HA;Ll;0;L;;;;;N;;;2CD0;;2CD0 +2CD2;COPTIC CAPITAL LETTER OLD COPTIC HEI;Lu;0;L;;;;;N;;;;2CD3; +2CD3;COPTIC SMALL LETTER OLD COPTIC HEI;Ll;0;L;;;;;N;;;2CD2;;2CD2 +2CD4;COPTIC CAPITAL LETTER OLD COPTIC HAT;Lu;0;L;;;;;N;;;;2CD5; +2CD5;COPTIC SMALL LETTER OLD COPTIC HAT;Ll;0;L;;;;;N;;;2CD4;;2CD4 +2CD6;COPTIC CAPITAL LETTER OLD COPTIC GANGIA;Lu;0;L;;;;;N;;;;2CD7; +2CD7;COPTIC SMALL LETTER OLD COPTIC GANGIA;Ll;0;L;;;;;N;;;2CD6;;2CD6 +2CD8;COPTIC CAPITAL LETTER OLD COPTIC DJA;Lu;0;L;;;;;N;;;;2CD9; +2CD9;COPTIC SMALL LETTER OLD COPTIC DJA;Ll;0;L;;;;;N;;;2CD8;;2CD8 +2CDA;COPTIC CAPITAL LETTER OLD COPTIC SHIMA;Lu;0;L;;;;;N;;;;2CDB; +2CDB;COPTIC SMALL LETTER OLD COPTIC SHIMA;Ll;0;L;;;;;N;;;2CDA;;2CDA +2CDC;COPTIC CAPITAL LETTER OLD NUBIAN SHIMA;Lu;0;L;;;;;N;;;;2CDD; +2CDD;COPTIC SMALL LETTER OLD NUBIAN SHIMA;Ll;0;L;;;;;N;;;2CDC;;2CDC +2CDE;COPTIC CAPITAL LETTER OLD NUBIAN NGI;Lu;0;L;;;;;N;;;;2CDF; +2CDF;COPTIC SMALL LETTER OLD NUBIAN NGI;Ll;0;L;;;;;N;;;2CDE;;2CDE +2CE0;COPTIC CAPITAL LETTER OLD NUBIAN NYI;Lu;0;L;;;;;N;;;;2CE1; +2CE1;COPTIC SMALL LETTER OLD NUBIAN NYI;Ll;0;L;;;;;N;;;2CE0;;2CE0 +2CE2;COPTIC CAPITAL LETTER OLD NUBIAN WAU;Lu;0;L;;;;;N;;;;2CE3; +2CE3;COPTIC SMALL LETTER OLD NUBIAN WAU;Ll;0;L;;;;;N;;;2CE2;;2CE2 +2CE4;COPTIC SYMBOL KAI;Ll;0;L;;;;;N;;;;; +2CE5;COPTIC SYMBOL MI RO;So;0;ON;;;;;N;;;;; +2CE6;COPTIC SYMBOL PI RO;So;0;ON;;;;;N;;;;; +2CE7;COPTIC SYMBOL STAUROS;So;0;ON;;;;;N;;;;; +2CE8;COPTIC SYMBOL TAU RO;So;0;ON;;;;;N;;;;; +2CE9;COPTIC SYMBOL KHI RO;So;0;ON;;;;;N;;;;; +2CEA;COPTIC SYMBOL SHIMA SIMA;So;0;ON;;;;;N;;;;; +2CEB;COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI;Lu;0;L;;;;;N;;;;2CEC; +2CEC;COPTIC SMALL LETTER CRYPTOGRAMMIC SHEI;Ll;0;L;;;;;N;;;2CEB;;2CEB +2CED;COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA;Lu;0;L;;;;;N;;;;2CEE; +2CEE;COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA;Ll;0;L;;;;;N;;;2CED;;2CED +2CEF;COPTIC COMBINING NI ABOVE;Mn;230;NSM;;;;;N;;;;; +2CF0;COPTIC COMBINING SPIRITUS ASPER;Mn;230;NSM;;;;;N;;;;; +2CF1;COPTIC COMBINING SPIRITUS LENIS;Mn;230;NSM;;;;;N;;;;; +2CF2;COPTIC CAPITAL LETTER BOHAIRIC KHEI;Lu;0;L;;;;;N;;;;2CF3; +2CF3;COPTIC SMALL LETTER BOHAIRIC KHEI;Ll;0;L;;;;;N;;;2CF2;;2CF2 +2CF9;COPTIC OLD NUBIAN FULL STOP;Po;0;ON;;;;;N;;;;; +2CFA;COPTIC OLD NUBIAN DIRECT QUESTION MARK;Po;0;ON;;;;;N;;;;; +2CFB;COPTIC OLD NUBIAN INDIRECT QUESTION MARK;Po;0;ON;;;;;N;;;;; +2CFC;COPTIC OLD NUBIAN VERSE DIVIDER;Po;0;ON;;;;;N;;;;; +2CFD;COPTIC FRACTION ONE HALF;No;0;ON;;;;1/2;N;;;;; +2CFE;COPTIC FULL STOP;Po;0;ON;;;;;N;;;;; +2CFF;COPTIC MORPHOLOGICAL DIVIDER;Po;0;ON;;;;;N;;;;; +2D00;GEORGIAN SMALL LETTER AN;Ll;0;L;;;;;N;;;10A0;;10A0 +2D01;GEORGIAN SMALL LETTER BAN;Ll;0;L;;;;;N;;;10A1;;10A1 +2D02;GEORGIAN SMALL LETTER GAN;Ll;0;L;;;;;N;;;10A2;;10A2 +2D03;GEORGIAN SMALL LETTER DON;Ll;0;L;;;;;N;;;10A3;;10A3 +2D04;GEORGIAN SMALL LETTER EN;Ll;0;L;;;;;N;;;10A4;;10A4 +2D05;GEORGIAN SMALL LETTER VIN;Ll;0;L;;;;;N;;;10A5;;10A5 +2D06;GEORGIAN SMALL LETTER ZEN;Ll;0;L;;;;;N;;;10A6;;10A6 +2D07;GEORGIAN SMALL LETTER TAN;Ll;0;L;;;;;N;;;10A7;;10A7 +2D08;GEORGIAN SMALL LETTER IN;Ll;0;L;;;;;N;;;10A8;;10A8 +2D09;GEORGIAN SMALL LETTER KAN;Ll;0;L;;;;;N;;;10A9;;10A9 +2D0A;GEORGIAN SMALL LETTER LAS;Ll;0;L;;;;;N;;;10AA;;10AA +2D0B;GEORGIAN SMALL LETTER MAN;Ll;0;L;;;;;N;;;10AB;;10AB +2D0C;GEORGIAN SMALL LETTER NAR;Ll;0;L;;;;;N;;;10AC;;10AC +2D0D;GEORGIAN SMALL LETTER ON;Ll;0;L;;;;;N;;;10AD;;10AD +2D0E;GEORGIAN SMALL LETTER PAR;Ll;0;L;;;;;N;;;10AE;;10AE +2D0F;GEORGIAN SMALL LETTER ZHAR;Ll;0;L;;;;;N;;;10AF;;10AF +2D10;GEORGIAN SMALL LETTER RAE;Ll;0;L;;;;;N;;;10B0;;10B0 +2D11;GEORGIAN SMALL LETTER SAN;Ll;0;L;;;;;N;;;10B1;;10B1 +2D12;GEORGIAN SMALL LETTER TAR;Ll;0;L;;;;;N;;;10B2;;10B2 +2D13;GEORGIAN SMALL LETTER UN;Ll;0;L;;;;;N;;;10B3;;10B3 +2D14;GEORGIAN SMALL LETTER PHAR;Ll;0;L;;;;;N;;;10B4;;10B4 +2D15;GEORGIAN SMALL LETTER KHAR;Ll;0;L;;;;;N;;;10B5;;10B5 +2D16;GEORGIAN SMALL LETTER GHAN;Ll;0;L;;;;;N;;;10B6;;10B6 +2D17;GEORGIAN SMALL LETTER QAR;Ll;0;L;;;;;N;;;10B7;;10B7 +2D18;GEORGIAN SMALL LETTER SHIN;Ll;0;L;;;;;N;;;10B8;;10B8 +2D19;GEORGIAN SMALL LETTER CHIN;Ll;0;L;;;;;N;;;10B9;;10B9 +2D1A;GEORGIAN SMALL LETTER CAN;Ll;0;L;;;;;N;;;10BA;;10BA +2D1B;GEORGIAN SMALL LETTER JIL;Ll;0;L;;;;;N;;;10BB;;10BB +2D1C;GEORGIAN SMALL LETTER CIL;Ll;0;L;;;;;N;;;10BC;;10BC +2D1D;GEORGIAN SMALL LETTER CHAR;Ll;0;L;;;;;N;;;10BD;;10BD +2D1E;GEORGIAN SMALL LETTER XAN;Ll;0;L;;;;;N;;;10BE;;10BE +2D1F;GEORGIAN SMALL LETTER JHAN;Ll;0;L;;;;;N;;;10BF;;10BF +2D20;GEORGIAN SMALL LETTER HAE;Ll;0;L;;;;;N;;;10C0;;10C0 +2D21;GEORGIAN SMALL LETTER HE;Ll;0;L;;;;;N;;;10C1;;10C1 +2D22;GEORGIAN SMALL LETTER HIE;Ll;0;L;;;;;N;;;10C2;;10C2 +2D23;GEORGIAN SMALL LETTER WE;Ll;0;L;;;;;N;;;10C3;;10C3 +2D24;GEORGIAN SMALL LETTER HAR;Ll;0;L;;;;;N;;;10C4;;10C4 +2D25;GEORGIAN SMALL LETTER HOE;Ll;0;L;;;;;N;;;10C5;;10C5 +2D27;GEORGIAN SMALL LETTER YN;Ll;0;L;;;;;N;;;10C7;;10C7 +2D2D;GEORGIAN SMALL LETTER AEN;Ll;0;L;;;;;N;;;10CD;;10CD +2D30;TIFINAGH LETTER YA;Lo;0;L;;;;;N;;;;; +2D31;TIFINAGH LETTER YAB;Lo;0;L;;;;;N;;;;; +2D32;TIFINAGH LETTER YABH;Lo;0;L;;;;;N;;;;; +2D33;TIFINAGH LETTER YAG;Lo;0;L;;;;;N;;;;; +2D34;TIFINAGH LETTER YAGHH;Lo;0;L;;;;;N;;;;; +2D35;TIFINAGH LETTER BERBER ACADEMY YAJ;Lo;0;L;;;;;N;;;;; +2D36;TIFINAGH LETTER YAJ;Lo;0;L;;;;;N;;;;; +2D37;TIFINAGH LETTER YAD;Lo;0;L;;;;;N;;;;; +2D38;TIFINAGH LETTER YADH;Lo;0;L;;;;;N;;;;; +2D39;TIFINAGH LETTER YADD;Lo;0;L;;;;;N;;;;; +2D3A;TIFINAGH LETTER YADDH;Lo;0;L;;;;;N;;;;; +2D3B;TIFINAGH LETTER YEY;Lo;0;L;;;;;N;;;;; +2D3C;TIFINAGH LETTER YAF;Lo;0;L;;;;;N;;;;; +2D3D;TIFINAGH LETTER YAK;Lo;0;L;;;;;N;;;;; +2D3E;TIFINAGH LETTER TUAREG YAK;Lo;0;L;;;;;N;;;;; +2D3F;TIFINAGH LETTER YAKHH;Lo;0;L;;;;;N;;;;; +2D40;TIFINAGH LETTER YAH;Lo;0;L;;;;;N;;;;; +2D41;TIFINAGH LETTER BERBER ACADEMY YAH;Lo;0;L;;;;;N;;;;; +2D42;TIFINAGH LETTER TUAREG YAH;Lo;0;L;;;;;N;;;;; +2D43;TIFINAGH LETTER YAHH;Lo;0;L;;;;;N;;;;; +2D44;TIFINAGH LETTER YAA;Lo;0;L;;;;;N;;;;; +2D45;TIFINAGH LETTER YAKH;Lo;0;L;;;;;N;;;;; +2D46;TIFINAGH LETTER TUAREG YAKH;Lo;0;L;;;;;N;;;;; +2D47;TIFINAGH LETTER YAQ;Lo;0;L;;;;;N;;;;; +2D48;TIFINAGH LETTER TUAREG YAQ;Lo;0;L;;;;;N;;;;; +2D49;TIFINAGH LETTER YI;Lo;0;L;;;;;N;;;;; +2D4A;TIFINAGH LETTER YAZH;Lo;0;L;;;;;N;;;;; +2D4B;TIFINAGH LETTER AHAGGAR YAZH;Lo;0;L;;;;;N;;;;; +2D4C;TIFINAGH LETTER TUAREG YAZH;Lo;0;L;;;;;N;;;;; +2D4D;TIFINAGH LETTER YAL;Lo;0;L;;;;;N;;;;; +2D4E;TIFINAGH LETTER YAM;Lo;0;L;;;;;N;;;;; +2D4F;TIFINAGH LETTER YAN;Lo;0;L;;;;;N;;;;; +2D50;TIFINAGH LETTER TUAREG YAGN;Lo;0;L;;;;;N;;;;; +2D51;TIFINAGH LETTER TUAREG YANG;Lo;0;L;;;;;N;;;;; +2D52;TIFINAGH LETTER YAP;Lo;0;L;;;;;N;;;;; +2D53;TIFINAGH LETTER YU;Lo;0;L;;;;;N;;;;; +2D54;TIFINAGH LETTER YAR;Lo;0;L;;;;;N;;;;; +2D55;TIFINAGH LETTER YARR;Lo;0;L;;;;;N;;;;; +2D56;TIFINAGH LETTER YAGH;Lo;0;L;;;;;N;;;;; +2D57;TIFINAGH LETTER TUAREG YAGH;Lo;0;L;;;;;N;;;;; +2D58;TIFINAGH LETTER AYER YAGH;Lo;0;L;;;;;N;;;;; +2D59;TIFINAGH LETTER YAS;Lo;0;L;;;;;N;;;;; +2D5A;TIFINAGH LETTER YASS;Lo;0;L;;;;;N;;;;; +2D5B;TIFINAGH LETTER YASH;Lo;0;L;;;;;N;;;;; +2D5C;TIFINAGH LETTER YAT;Lo;0;L;;;;;N;;;;; +2D5D;TIFINAGH LETTER YATH;Lo;0;L;;;;;N;;;;; +2D5E;TIFINAGH LETTER YACH;Lo;0;L;;;;;N;;;;; +2D5F;TIFINAGH LETTER YATT;Lo;0;L;;;;;N;;;;; +2D60;TIFINAGH LETTER YAV;Lo;0;L;;;;;N;;;;; +2D61;TIFINAGH LETTER YAW;Lo;0;L;;;;;N;;;;; +2D62;TIFINAGH LETTER YAY;Lo;0;L;;;;;N;;;;; +2D63;TIFINAGH LETTER YAZ;Lo;0;L;;;;;N;;;;; +2D64;TIFINAGH LETTER TAWELLEMET YAZ;Lo;0;L;;;;;N;;;;; +2D65;TIFINAGH LETTER YAZZ;Lo;0;L;;;;;N;;;;; +2D66;TIFINAGH LETTER YE;Lo;0;L;;;;;N;;;;; +2D67;TIFINAGH LETTER YO;Lo;0;L;;;;;N;;;;; +2D6F;TIFINAGH MODIFIER LETTER LABIALIZATION MARK;Lm;0;L; 2D61;;;;N;;;;; +2D70;TIFINAGH SEPARATOR MARK;Po;0;L;;;;;N;;;;; +2D7F;TIFINAGH CONSONANT JOINER;Mn;9;NSM;;;;;N;;;;; +2D80;ETHIOPIC SYLLABLE LOA;Lo;0;L;;;;;N;;;;; +2D81;ETHIOPIC SYLLABLE MOA;Lo;0;L;;;;;N;;;;; +2D82;ETHIOPIC SYLLABLE ROA;Lo;0;L;;;;;N;;;;; +2D83;ETHIOPIC SYLLABLE SOA;Lo;0;L;;;;;N;;;;; +2D84;ETHIOPIC SYLLABLE SHOA;Lo;0;L;;;;;N;;;;; +2D85;ETHIOPIC SYLLABLE BOA;Lo;0;L;;;;;N;;;;; +2D86;ETHIOPIC SYLLABLE TOA;Lo;0;L;;;;;N;;;;; +2D87;ETHIOPIC SYLLABLE COA;Lo;0;L;;;;;N;;;;; +2D88;ETHIOPIC SYLLABLE NOA;Lo;0;L;;;;;N;;;;; +2D89;ETHIOPIC SYLLABLE NYOA;Lo;0;L;;;;;N;;;;; +2D8A;ETHIOPIC SYLLABLE GLOTTAL OA;Lo;0;L;;;;;N;;;;; +2D8B;ETHIOPIC SYLLABLE ZOA;Lo;0;L;;;;;N;;;;; +2D8C;ETHIOPIC SYLLABLE DOA;Lo;0;L;;;;;N;;;;; +2D8D;ETHIOPIC SYLLABLE DDOA;Lo;0;L;;;;;N;;;;; +2D8E;ETHIOPIC SYLLABLE JOA;Lo;0;L;;;;;N;;;;; +2D8F;ETHIOPIC SYLLABLE THOA;Lo;0;L;;;;;N;;;;; +2D90;ETHIOPIC SYLLABLE CHOA;Lo;0;L;;;;;N;;;;; +2D91;ETHIOPIC SYLLABLE PHOA;Lo;0;L;;;;;N;;;;; +2D92;ETHIOPIC SYLLABLE POA;Lo;0;L;;;;;N;;;;; +2D93;ETHIOPIC SYLLABLE GGWA;Lo;0;L;;;;;N;;;;; +2D94;ETHIOPIC SYLLABLE GGWI;Lo;0;L;;;;;N;;;;; +2D95;ETHIOPIC SYLLABLE GGWEE;Lo;0;L;;;;;N;;;;; +2D96;ETHIOPIC SYLLABLE GGWE;Lo;0;L;;;;;N;;;;; +2DA0;ETHIOPIC SYLLABLE SSA;Lo;0;L;;;;;N;;;;; +2DA1;ETHIOPIC SYLLABLE SSU;Lo;0;L;;;;;N;;;;; +2DA2;ETHIOPIC SYLLABLE SSI;Lo;0;L;;;;;N;;;;; +2DA3;ETHIOPIC SYLLABLE SSAA;Lo;0;L;;;;;N;;;;; +2DA4;ETHIOPIC SYLLABLE SSEE;Lo;0;L;;;;;N;;;;; +2DA5;ETHIOPIC SYLLABLE SSE;Lo;0;L;;;;;N;;;;; +2DA6;ETHIOPIC SYLLABLE SSO;Lo;0;L;;;;;N;;;;; +2DA8;ETHIOPIC SYLLABLE CCA;Lo;0;L;;;;;N;;;;; +2DA9;ETHIOPIC SYLLABLE CCU;Lo;0;L;;;;;N;;;;; +2DAA;ETHIOPIC SYLLABLE CCI;Lo;0;L;;;;;N;;;;; +2DAB;ETHIOPIC SYLLABLE CCAA;Lo;0;L;;;;;N;;;;; +2DAC;ETHIOPIC SYLLABLE CCEE;Lo;0;L;;;;;N;;;;; +2DAD;ETHIOPIC SYLLABLE CCE;Lo;0;L;;;;;N;;;;; +2DAE;ETHIOPIC SYLLABLE CCO;Lo;0;L;;;;;N;;;;; +2DB0;ETHIOPIC SYLLABLE ZZA;Lo;0;L;;;;;N;;;;; +2DB1;ETHIOPIC SYLLABLE ZZU;Lo;0;L;;;;;N;;;;; +2DB2;ETHIOPIC SYLLABLE ZZI;Lo;0;L;;;;;N;;;;; +2DB3;ETHIOPIC SYLLABLE ZZAA;Lo;0;L;;;;;N;;;;; +2DB4;ETHIOPIC SYLLABLE ZZEE;Lo;0;L;;;;;N;;;;; +2DB5;ETHIOPIC SYLLABLE ZZE;Lo;0;L;;;;;N;;;;; +2DB6;ETHIOPIC SYLLABLE ZZO;Lo;0;L;;;;;N;;;;; +2DB8;ETHIOPIC SYLLABLE CCHA;Lo;0;L;;;;;N;;;;; +2DB9;ETHIOPIC SYLLABLE CCHU;Lo;0;L;;;;;N;;;;; +2DBA;ETHIOPIC SYLLABLE CCHI;Lo;0;L;;;;;N;;;;; +2DBB;ETHIOPIC SYLLABLE CCHAA;Lo;0;L;;;;;N;;;;; +2DBC;ETHIOPIC SYLLABLE CCHEE;Lo;0;L;;;;;N;;;;; +2DBD;ETHIOPIC SYLLABLE CCHE;Lo;0;L;;;;;N;;;;; +2DBE;ETHIOPIC SYLLABLE CCHO;Lo;0;L;;;;;N;;;;; +2DC0;ETHIOPIC SYLLABLE QYA;Lo;0;L;;;;;N;;;;; +2DC1;ETHIOPIC SYLLABLE QYU;Lo;0;L;;;;;N;;;;; +2DC2;ETHIOPIC SYLLABLE QYI;Lo;0;L;;;;;N;;;;; +2DC3;ETHIOPIC SYLLABLE QYAA;Lo;0;L;;;;;N;;;;; +2DC4;ETHIOPIC SYLLABLE QYEE;Lo;0;L;;;;;N;;;;; +2DC5;ETHIOPIC SYLLABLE QYE;Lo;0;L;;;;;N;;;;; +2DC6;ETHIOPIC SYLLABLE QYO;Lo;0;L;;;;;N;;;;; +2DC8;ETHIOPIC SYLLABLE KYA;Lo;0;L;;;;;N;;;;; +2DC9;ETHIOPIC SYLLABLE KYU;Lo;0;L;;;;;N;;;;; +2DCA;ETHIOPIC SYLLABLE KYI;Lo;0;L;;;;;N;;;;; +2DCB;ETHIOPIC SYLLABLE KYAA;Lo;0;L;;;;;N;;;;; +2DCC;ETHIOPIC SYLLABLE KYEE;Lo;0;L;;;;;N;;;;; +2DCD;ETHIOPIC SYLLABLE KYE;Lo;0;L;;;;;N;;;;; +2DCE;ETHIOPIC SYLLABLE KYO;Lo;0;L;;;;;N;;;;; +2DD0;ETHIOPIC SYLLABLE XYA;Lo;0;L;;;;;N;;;;; +2DD1;ETHIOPIC SYLLABLE XYU;Lo;0;L;;;;;N;;;;; +2DD2;ETHIOPIC SYLLABLE XYI;Lo;0;L;;;;;N;;;;; +2DD3;ETHIOPIC SYLLABLE XYAA;Lo;0;L;;;;;N;;;;; +2DD4;ETHIOPIC SYLLABLE XYEE;Lo;0;L;;;;;N;;;;; +2DD5;ETHIOPIC SYLLABLE XYE;Lo;0;L;;;;;N;;;;; +2DD6;ETHIOPIC SYLLABLE XYO;Lo;0;L;;;;;N;;;;; +2DD8;ETHIOPIC SYLLABLE GYA;Lo;0;L;;;;;N;;;;; +2DD9;ETHIOPIC SYLLABLE GYU;Lo;0;L;;;;;N;;;;; +2DDA;ETHIOPIC SYLLABLE GYI;Lo;0;L;;;;;N;;;;; +2DDB;ETHIOPIC SYLLABLE GYAA;Lo;0;L;;;;;N;;;;; +2DDC;ETHIOPIC SYLLABLE GYEE;Lo;0;L;;;;;N;;;;; +2DDD;ETHIOPIC SYLLABLE GYE;Lo;0;L;;;;;N;;;;; +2DDE;ETHIOPIC SYLLABLE GYO;Lo;0;L;;;;;N;;;;; +2DE0;COMBINING CYRILLIC LETTER BE;Mn;230;NSM;;;;;N;;;;; +2DE1;COMBINING CYRILLIC LETTER VE;Mn;230;NSM;;;;;N;;;;; +2DE2;COMBINING CYRILLIC LETTER GHE;Mn;230;NSM;;;;;N;;;;; +2DE3;COMBINING CYRILLIC LETTER DE;Mn;230;NSM;;;;;N;;;;; +2DE4;COMBINING CYRILLIC LETTER ZHE;Mn;230;NSM;;;;;N;;;;; +2DE5;COMBINING CYRILLIC LETTER ZE;Mn;230;NSM;;;;;N;;;;; +2DE6;COMBINING CYRILLIC LETTER KA;Mn;230;NSM;;;;;N;;;;; +2DE7;COMBINING CYRILLIC LETTER EL;Mn;230;NSM;;;;;N;;;;; +2DE8;COMBINING CYRILLIC LETTER EM;Mn;230;NSM;;;;;N;;;;; +2DE9;COMBINING CYRILLIC LETTER EN;Mn;230;NSM;;;;;N;;;;; +2DEA;COMBINING CYRILLIC LETTER O;Mn;230;NSM;;;;;N;;;;; +2DEB;COMBINING CYRILLIC LETTER PE;Mn;230;NSM;;;;;N;;;;; +2DEC;COMBINING CYRILLIC LETTER ER;Mn;230;NSM;;;;;N;;;;; +2DED;COMBINING CYRILLIC LETTER ES;Mn;230;NSM;;;;;N;;;;; +2DEE;COMBINING CYRILLIC LETTER TE;Mn;230;NSM;;;;;N;;;;; +2DEF;COMBINING CYRILLIC LETTER HA;Mn;230;NSM;;;;;N;;;;; +2DF0;COMBINING CYRILLIC LETTER TSE;Mn;230;NSM;;;;;N;;;;; +2DF1;COMBINING CYRILLIC LETTER CHE;Mn;230;NSM;;;;;N;;;;; +2DF2;COMBINING CYRILLIC LETTER SHA;Mn;230;NSM;;;;;N;;;;; +2DF3;COMBINING CYRILLIC LETTER SHCHA;Mn;230;NSM;;;;;N;;;;; +2DF4;COMBINING CYRILLIC LETTER FITA;Mn;230;NSM;;;;;N;;;;; +2DF5;COMBINING CYRILLIC LETTER ES-TE;Mn;230;NSM;;;;;N;;;;; +2DF6;COMBINING CYRILLIC LETTER A;Mn;230;NSM;;;;;N;;;;; +2DF7;COMBINING CYRILLIC LETTER IE;Mn;230;NSM;;;;;N;;;;; +2DF8;COMBINING CYRILLIC LETTER DJERV;Mn;230;NSM;;;;;N;;;;; +2DF9;COMBINING CYRILLIC LETTER MONOGRAPH UK;Mn;230;NSM;;;;;N;;;;; +2DFA;COMBINING CYRILLIC LETTER YAT;Mn;230;NSM;;;;;N;;;;; +2DFB;COMBINING CYRILLIC LETTER YU;Mn;230;NSM;;;;;N;;;;; +2DFC;COMBINING CYRILLIC LETTER IOTIFIED A;Mn;230;NSM;;;;;N;;;;; +2DFD;COMBINING CYRILLIC LETTER LITTLE YUS;Mn;230;NSM;;;;;N;;;;; +2DFE;COMBINING CYRILLIC LETTER BIG YUS;Mn;230;NSM;;;;;N;;;;; +2DFF;COMBINING CYRILLIC LETTER IOTIFIED BIG YUS;Mn;230;NSM;;;;;N;;;;; +2E00;RIGHT ANGLE SUBSTITUTION MARKER;Po;0;ON;;;;;N;;;;; +2E01;RIGHT ANGLE DOTTED SUBSTITUTION MARKER;Po;0;ON;;;;;N;;;;; +2E02;LEFT SUBSTITUTION BRACKET;Pi;0;ON;;;;;Y;;;;; +2E03;RIGHT SUBSTITUTION BRACKET;Pf;0;ON;;;;;Y;;;;; +2E04;LEFT DOTTED SUBSTITUTION BRACKET;Pi;0;ON;;;;;Y;;;;; +2E05;RIGHT DOTTED SUBSTITUTION BRACKET;Pf;0;ON;;;;;Y;;;;; +2E06;RAISED INTERPOLATION MARKER;Po;0;ON;;;;;N;;;;; +2E07;RAISED DOTTED INTERPOLATION MARKER;Po;0;ON;;;;;N;;;;; +2E08;DOTTED TRANSPOSITION MARKER;Po;0;ON;;;;;N;;;;; +2E09;LEFT TRANSPOSITION BRACKET;Pi;0;ON;;;;;Y;;;;; +2E0A;RIGHT TRANSPOSITION BRACKET;Pf;0;ON;;;;;Y;;;;; +2E0B;RAISED SQUARE;Po;0;ON;;;;;N;;;;; +2E0C;LEFT RAISED OMISSION BRACKET;Pi;0;ON;;;;;Y;;;;; +2E0D;RIGHT RAISED OMISSION BRACKET;Pf;0;ON;;;;;Y;;;;; +2E0E;EDITORIAL CORONIS;Po;0;ON;;;;;N;;;;; +2E0F;PARAGRAPHOS;Po;0;ON;;;;;N;;;;; +2E10;FORKED PARAGRAPHOS;Po;0;ON;;;;;N;;;;; +2E11;REVERSED FORKED PARAGRAPHOS;Po;0;ON;;;;;N;;;;; +2E12;HYPODIASTOLE;Po;0;ON;;;;;N;;;;; +2E13;DOTTED OBELOS;Po;0;ON;;;;;N;;;;; +2E14;DOWNWARDS ANCORA;Po;0;ON;;;;;N;;;;; +2E15;UPWARDS ANCORA;Po;0;ON;;;;;N;;;;; +2E16;DOTTED RIGHT-POINTING ANGLE;Po;0;ON;;;;;N;;;;; +2E17;DOUBLE OBLIQUE HYPHEN;Pd;0;ON;;;;;N;;;;; +2E18;INVERTED INTERROBANG;Po;0;ON;;;;;N;;;;; +2E19;PALM BRANCH;Po;0;ON;;;;;N;;;;; +2E1A;HYPHEN WITH DIAERESIS;Pd;0;ON;;;;;N;;;;; +2E1B;TILDE WITH RING ABOVE;Po;0;ON;;;;;N;;;;; +2E1C;LEFT LOW PARAPHRASE BRACKET;Pi;0;ON;;;;;Y;;;;; +2E1D;RIGHT LOW PARAPHRASE BRACKET;Pf;0;ON;;;;;Y;;;;; +2E1E;TILDE WITH DOT ABOVE;Po;0;ON;;;;;N;;;;; +2E1F;TILDE WITH DOT BELOW;Po;0;ON;;;;;N;;;;; +2E20;LEFT VERTICAL BAR WITH QUILL;Pi;0;ON;;;;;Y;;;;; +2E21;RIGHT VERTICAL BAR WITH QUILL;Pf;0;ON;;;;;Y;;;;; +2E22;TOP LEFT HALF BRACKET;Ps;0;ON;;;;;Y;;;;; +2E23;TOP RIGHT HALF BRACKET;Pe;0;ON;;;;;Y;;;;; +2E24;BOTTOM LEFT HALF BRACKET;Ps;0;ON;;;;;Y;;;;; +2E25;BOTTOM RIGHT HALF BRACKET;Pe;0;ON;;;;;Y;;;;; +2E26;LEFT SIDEWAYS U BRACKET;Ps;0;ON;;;;;Y;;;;; +2E27;RIGHT SIDEWAYS U BRACKET;Pe;0;ON;;;;;Y;;;;; +2E28;LEFT DOUBLE PARENTHESIS;Ps;0;ON;;;;;Y;;;;; +2E29;RIGHT DOUBLE PARENTHESIS;Pe;0;ON;;;;;Y;;;;; +2E2A;TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; +2E2B;ONE DOT OVER TWO DOTS PUNCTUATION;Po;0;ON;;;;;N;;;;; +2E2C;SQUARED FOUR DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; +2E2D;FIVE DOT MARK;Po;0;ON;;;;;N;;;;; +2E2E;REVERSED QUESTION MARK;Po;0;ON;;;;;N;;;;; +2E2F;VERTICAL TILDE;Lm;0;ON;;;;;N;;;;; +2E30;RING POINT;Po;0;ON;;;;;N;;;;; +2E31;WORD SEPARATOR MIDDLE DOT;Po;0;ON;;;;;N;;;;; +2E32;TURNED COMMA;Po;0;ON;;;;;N;;;;; +2E33;RAISED DOT;Po;0;ON;;;;;N;;;;; +2E34;RAISED COMMA;Po;0;ON;;;;;N;;;;; +2E35;TURNED SEMICOLON;Po;0;ON;;;;;N;;;;; +2E36;DAGGER WITH LEFT GUARD;Po;0;ON;;;;;N;;;;; +2E37;DAGGER WITH RIGHT GUARD;Po;0;ON;;;;;N;;;;; +2E38;TURNED DAGGER;Po;0;ON;;;;;N;;;;; +2E39;TOP HALF SECTION SIGN;Po;0;ON;;;;;N;;;;; +2E3A;TWO-EM DASH;Pd;0;ON;;;;;N;;;;; +2E3B;THREE-EM DASH;Pd;0;ON;;;;;N;;;;; +2E3C;STENOGRAPHIC FULL STOP;Po;0;ON;;;;;N;;;;; +2E3D;VERTICAL SIX DOTS;Po;0;ON;;;;;N;;;;; +2E3E;WIGGLY VERTICAL LINE;Po;0;ON;;;;;N;;;;; +2E3F;CAPITULUM;Po;0;ON;;;;;N;;;;; +2E40;DOUBLE HYPHEN;Pd;0;ON;;;;;N;;;;; +2E41;REVERSED COMMA;Po;0;ON;;;;;N;;;;; +2E42;DOUBLE LOW-REVERSED-9 QUOTATION MARK;Ps;0;ON;;;;;N;;;;; +2E43;DASH WITH LEFT UPTURN;Po;0;ON;;;;;N;;;;; +2E44;DOUBLE SUSPENSION MARK;Po;0;ON;;;;;N;;;;; +2E45;INVERTED LOW KAVYKA;Po;0;ON;;;;;N;;;;; +2E46;INVERTED LOW KAVYKA WITH KAVYKA ABOVE;Po;0;ON;;;;;N;;;;; +2E47;LOW KAVYKA;Po;0;ON;;;;;N;;;;; +2E48;LOW KAVYKA WITH DOT;Po;0;ON;;;;;N;;;;; +2E49;DOUBLE STACKED COMMA;Po;0;ON;;;;;N;;;;; +2E4A;DOTTED SOLIDUS;Po;0;ON;;;;;N;;;;; +2E4B;TRIPLE DAGGER;Po;0;ON;;;;;N;;;;; +2E4C;MEDIEVAL COMMA;Po;0;ON;;;;;N;;;;; +2E4D;PARAGRAPHUS MARK;Po;0;ON;;;;;N;;;;; +2E4E;PUNCTUS ELEVATUS MARK;Po;0;ON;;;;;N;;;;; +2E4F;CORNISH VERSE DIVIDER;Po;0;ON;;;;;N;;;;; +2E50;CROSS PATTY WITH RIGHT CROSSBAR;So;0;ON;;;;;N;;;;; +2E51;CROSS PATTY WITH LEFT CROSSBAR;So;0;ON;;;;;N;;;;; +2E52;TIRONIAN SIGN CAPITAL ET;Po;0;ON;;;;;N;;;;; +2E53;MEDIEVAL EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; +2E54;MEDIEVAL QUESTION MARK;Po;0;ON;;;;;N;;;;; +2E55;LEFT SQUARE BRACKET WITH STROKE;Ps;0;ON;;;;;Y;;;;; +2E56;RIGHT SQUARE BRACKET WITH STROKE;Pe;0;ON;;;;;Y;;;;; +2E57;LEFT SQUARE BRACKET WITH DOUBLE STROKE;Ps;0;ON;;;;;Y;;;;; +2E58;RIGHT SQUARE BRACKET WITH DOUBLE STROKE;Pe;0;ON;;;;;Y;;;;; +2E59;TOP HALF LEFT PARENTHESIS;Ps;0;ON;;;;;Y;;;;; +2E5A;TOP HALF RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;;;;; +2E5B;BOTTOM HALF LEFT PARENTHESIS;Ps;0;ON;;;;;Y;;;;; +2E5C;BOTTOM HALF RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;;;;; +2E5D;OBLIQUE HYPHEN;Pd;0;ON;;;;;N;;;;; +2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;; +2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;; +2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;; +2E83;CJK RADICAL SECOND TWO;So;0;ON;;;;;N;;;;; +2E84;CJK RADICAL SECOND THREE;So;0;ON;;;;;N;;;;; +2E85;CJK RADICAL PERSON;So;0;ON;;;;;N;;;;; +2E86;CJK RADICAL BOX;So;0;ON;;;;;N;;;;; +2E87;CJK RADICAL TABLE;So;0;ON;;;;;N;;;;; +2E88;CJK RADICAL KNIFE ONE;So;0;ON;;;;;N;;;;; +2E89;CJK RADICAL KNIFE TWO;So;0;ON;;;;;N;;;;; +2E8A;CJK RADICAL DIVINATION;So;0;ON;;;;;N;;;;; +2E8B;CJK RADICAL SEAL;So;0;ON;;;;;N;;;;; +2E8C;CJK RADICAL SMALL ONE;So;0;ON;;;;;N;;;;; +2E8D;CJK RADICAL SMALL TWO;So;0;ON;;;;;N;;;;; +2E8E;CJK RADICAL LAME ONE;So;0;ON;;;;;N;;;;; +2E8F;CJK RADICAL LAME TWO;So;0;ON;;;;;N;;;;; +2E90;CJK RADICAL LAME THREE;So;0;ON;;;;;N;;;;; +2E91;CJK RADICAL LAME FOUR;So;0;ON;;;;;N;;;;; +2E92;CJK RADICAL SNAKE;So;0;ON;;;;;N;;;;; +2E93;CJK RADICAL THREAD;So;0;ON;;;;;N;;;;; +2E94;CJK RADICAL SNOUT ONE;So;0;ON;;;;;N;;;;; +2E95;CJK RADICAL SNOUT TWO;So;0;ON;;;;;N;;;;; +2E96;CJK RADICAL HEART ONE;So;0;ON;;;;;N;;;;; +2E97;CJK RADICAL HEART TWO;So;0;ON;;;;;N;;;;; +2E98;CJK RADICAL HAND;So;0;ON;;;;;N;;;;; +2E99;CJK RADICAL RAP;So;0;ON;;;;;N;;;;; +2E9B;CJK RADICAL CHOKE;So;0;ON;;;;;N;;;;; +2E9C;CJK RADICAL SUN;So;0;ON;;;;;N;;;;; +2E9D;CJK RADICAL MOON;So;0;ON;;;;;N;;;;; +2E9E;CJK RADICAL DEATH;So;0;ON;;;;;N;;;;; +2E9F;CJK RADICAL MOTHER;So;0;ON; 6BCD;;;;N;;;;; +2EA0;CJK RADICAL CIVILIAN;So;0;ON;;;;;N;;;;; +2EA1;CJK RADICAL WATER ONE;So;0;ON;;;;;N;;;;; +2EA2;CJK RADICAL WATER TWO;So;0;ON;;;;;N;;;;; +2EA3;CJK RADICAL FIRE;So;0;ON;;;;;N;;;;; +2EA4;CJK RADICAL PAW ONE;So;0;ON;;;;;N;;;;; +2EA5;CJK RADICAL PAW TWO;So;0;ON;;;;;N;;;;; +2EA6;CJK RADICAL SIMPLIFIED HALF TREE TRUNK;So;0;ON;;;;;N;;;;; +2EA7;CJK RADICAL COW;So;0;ON;;;;;N;;;;; +2EA8;CJK RADICAL DOG;So;0;ON;;;;;N;;;;; +2EA9;CJK RADICAL JADE;So;0;ON;;;;;N;;;;; +2EAA;CJK RADICAL BOLT OF CLOTH;So;0;ON;;;;;N;;;;; +2EAB;CJK RADICAL EYE;So;0;ON;;;;;N;;;;; +2EAC;CJK RADICAL SPIRIT ONE;So;0;ON;;;;;N;;;;; +2EAD;CJK RADICAL SPIRIT TWO;So;0;ON;;;;;N;;;;; +2EAE;CJK RADICAL BAMBOO;So;0;ON;;;;;N;;;;; +2EAF;CJK RADICAL SILK;So;0;ON;;;;;N;;;;; +2EB0;CJK RADICAL C-SIMPLIFIED SILK;So;0;ON;;;;;N;;;;; +2EB1;CJK RADICAL NET ONE;So;0;ON;;;;;N;;;;; +2EB2;CJK RADICAL NET TWO;So;0;ON;;;;;N;;;;; +2EB3;CJK RADICAL NET THREE;So;0;ON;;;;;N;;;;; +2EB4;CJK RADICAL NET FOUR;So;0;ON;;;;;N;;;;; +2EB5;CJK RADICAL MESH;So;0;ON;;;;;N;;;;; +2EB6;CJK RADICAL SHEEP;So;0;ON;;;;;N;;;;; +2EB7;CJK RADICAL RAM;So;0;ON;;;;;N;;;;; +2EB8;CJK RADICAL EWE;So;0;ON;;;;;N;;;;; +2EB9;CJK RADICAL OLD;So;0;ON;;;;;N;;;;; +2EBA;CJK RADICAL BRUSH ONE;So;0;ON;;;;;N;;;;; +2EBB;CJK RADICAL BRUSH TWO;So;0;ON;;;;;N;;;;; +2EBC;CJK RADICAL MEAT;So;0;ON;;;;;N;;;;; +2EBD;CJK RADICAL MORTAR;So;0;ON;;;;;N;;;;; +2EBE;CJK RADICAL GRASS ONE;So;0;ON;;;;;N;;;;; +2EBF;CJK RADICAL GRASS TWO;So;0;ON;;;;;N;;;;; +2EC0;CJK RADICAL GRASS THREE;So;0;ON;;;;;N;;;;; +2EC1;CJK RADICAL TIGER;So;0;ON;;;;;N;;;;; +2EC2;CJK RADICAL CLOTHES;So;0;ON;;;;;N;;;;; +2EC3;CJK RADICAL WEST ONE;So;0;ON;;;;;N;;;;; +2EC4;CJK RADICAL WEST TWO;So;0;ON;;;;;N;;;;; +2EC5;CJK RADICAL C-SIMPLIFIED SEE;So;0;ON;;;;;N;;;;; +2EC6;CJK RADICAL SIMPLIFIED HORN;So;0;ON;;;;;N;;;;; +2EC7;CJK RADICAL HORN;So;0;ON;;;;;N;;;;; +2EC8;CJK RADICAL C-SIMPLIFIED SPEECH;So;0;ON;;;;;N;;;;; +2EC9;CJK RADICAL C-SIMPLIFIED SHELL;So;0;ON;;;;;N;;;;; +2ECA;CJK RADICAL FOOT;So;0;ON;;;;;N;;;;; +2ECB;CJK RADICAL C-SIMPLIFIED CART;So;0;ON;;;;;N;;;;; +2ECC;CJK RADICAL SIMPLIFIED WALK;So;0;ON;;;;;N;;;;; +2ECD;CJK RADICAL WALK ONE;So;0;ON;;;;;N;;;;; +2ECE;CJK RADICAL WALK TWO;So;0;ON;;;;;N;;;;; +2ECF;CJK RADICAL CITY;So;0;ON;;;;;N;;;;; +2ED0;CJK RADICAL C-SIMPLIFIED GOLD;So;0;ON;;;;;N;;;;; +2ED1;CJK RADICAL LONG ONE;So;0;ON;;;;;N;;;;; +2ED2;CJK RADICAL LONG TWO;So;0;ON;;;;;N;;;;; +2ED3;CJK RADICAL C-SIMPLIFIED LONG;So;0;ON;;;;;N;;;;; +2ED4;CJK RADICAL C-SIMPLIFIED GATE;So;0;ON;;;;;N;;;;; +2ED5;CJK RADICAL MOUND ONE;So;0;ON;;;;;N;;;;; +2ED6;CJK RADICAL MOUND TWO;So;0;ON;;;;;N;;;;; +2ED7;CJK RADICAL RAIN;So;0;ON;;;;;N;;;;; +2ED8;CJK RADICAL BLUE;So;0;ON;;;;;N;;;;; +2ED9;CJK RADICAL C-SIMPLIFIED TANNED LEATHER;So;0;ON;;;;;N;;;;; +2EDA;CJK RADICAL C-SIMPLIFIED LEAF;So;0;ON;;;;;N;;;;; +2EDB;CJK RADICAL C-SIMPLIFIED WIND;So;0;ON;;;;;N;;;;; +2EDC;CJK RADICAL C-SIMPLIFIED FLY;So;0;ON;;;;;N;;;;; +2EDD;CJK RADICAL EAT ONE;So;0;ON;;;;;N;;;;; +2EDE;CJK RADICAL EAT TWO;So;0;ON;;;;;N;;;;; +2EDF;CJK RADICAL EAT THREE;So;0;ON;;;;;N;;;;; +2EE0;CJK RADICAL C-SIMPLIFIED EAT;So;0;ON;;;;;N;;;;; +2EE1;CJK RADICAL HEAD;So;0;ON;;;;;N;;;;; +2EE2;CJK RADICAL C-SIMPLIFIED HORSE;So;0;ON;;;;;N;;;;; +2EE3;CJK RADICAL BONE;So;0;ON;;;;;N;;;;; +2EE4;CJK RADICAL GHOST;So;0;ON;;;;;N;;;;; +2EE5;CJK RADICAL C-SIMPLIFIED FISH;So;0;ON;;;;;N;;;;; +2EE6;CJK RADICAL C-SIMPLIFIED BIRD;So;0;ON;;;;;N;;;;; +2EE7;CJK RADICAL C-SIMPLIFIED SALT;So;0;ON;;;;;N;;;;; +2EE8;CJK RADICAL SIMPLIFIED WHEAT;So;0;ON;;;;;N;;;;; +2EE9;CJK RADICAL SIMPLIFIED YELLOW;So;0;ON;;;;;N;;;;; +2EEA;CJK RADICAL C-SIMPLIFIED FROG;So;0;ON;;;;;N;;;;; +2EEB;CJK RADICAL J-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;; +2EEC;CJK RADICAL C-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;; +2EED;CJK RADICAL J-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;; +2EEE;CJK RADICAL C-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;; +2EEF;CJK RADICAL J-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;; +2EF0;CJK RADICAL C-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;; +2EF1;CJK RADICAL TURTLE;So;0;ON;;;;;N;;;;; +2EF2;CJK RADICAL J-SIMPLIFIED TURTLE;So;0;ON;;;;;N;;;;; +2EF3;CJK RADICAL C-SIMPLIFIED TURTLE;So;0;ON; 9F9F;;;;N;;;;; +2F00;KANGXI RADICAL ONE;So;0;ON; 4E00;;;;N;;;;; +2F01;KANGXI RADICAL LINE;So;0;ON; 4E28;;;;N;;;;; +2F02;KANGXI RADICAL DOT;So;0;ON; 4E36;;;;N;;;;; +2F03;KANGXI RADICAL SLASH;So;0;ON; 4E3F;;;;N;;;;; +2F04;KANGXI RADICAL SECOND;So;0;ON; 4E59;;;;N;;;;; +2F05;KANGXI RADICAL HOOK;So;0;ON; 4E85;;;;N;;;;; +2F06;KANGXI RADICAL TWO;So;0;ON; 4E8C;;;;N;;;;; +2F07;KANGXI RADICAL LID;So;0;ON; 4EA0;;;;N;;;;; +2F08;KANGXI RADICAL MAN;So;0;ON; 4EBA;;;;N;;;;; +2F09;KANGXI RADICAL LEGS;So;0;ON; 513F;;;;N;;;;; +2F0A;KANGXI RADICAL ENTER;So;0;ON; 5165;;;;N;;;;; +2F0B;KANGXI RADICAL EIGHT;So;0;ON; 516B;;;;N;;;;; +2F0C;KANGXI RADICAL DOWN BOX;So;0;ON; 5182;;;;N;;;;; +2F0D;KANGXI RADICAL COVER;So;0;ON; 5196;;;;N;;;;; +2F0E;KANGXI RADICAL ICE;So;0;ON; 51AB;;;;N;;;;; +2F0F;KANGXI RADICAL TABLE;So;0;ON; 51E0;;;;N;;;;; +2F10;KANGXI RADICAL OPEN BOX;So;0;ON; 51F5;;;;N;;;;; +2F11;KANGXI RADICAL KNIFE;So;0;ON; 5200;;;;N;;;;; +2F12;KANGXI RADICAL POWER;So;0;ON; 529B;;;;N;;;;; +2F13;KANGXI RADICAL WRAP;So;0;ON; 52F9;;;;N;;;;; +2F14;KANGXI RADICAL SPOON;So;0;ON; 5315;;;;N;;;;; +2F15;KANGXI RADICAL RIGHT OPEN BOX;So;0;ON; 531A;;;;N;;;;; +2F16;KANGXI RADICAL HIDING ENCLOSURE;So;0;ON; 5338;;;;N;;;;; +2F17;KANGXI RADICAL TEN;So;0;ON; 5341;;;;N;;;;; +2F18;KANGXI RADICAL DIVINATION;So;0;ON; 535C;;;;N;;;;; +2F19;KANGXI RADICAL SEAL;So;0;ON; 5369;;;;N;;;;; +2F1A;KANGXI RADICAL CLIFF;So;0;ON; 5382;;;;N;;;;; +2F1B;KANGXI RADICAL PRIVATE;So;0;ON; 53B6;;;;N;;;;; +2F1C;KANGXI RADICAL AGAIN;So;0;ON; 53C8;;;;N;;;;; +2F1D;KANGXI RADICAL MOUTH;So;0;ON; 53E3;;;;N;;;;; +2F1E;KANGXI RADICAL ENCLOSURE;So;0;ON; 56D7;;;;N;;;;; +2F1F;KANGXI RADICAL EARTH;So;0;ON; 571F;;;;N;;;;; +2F20;KANGXI RADICAL SCHOLAR;So;0;ON; 58EB;;;;N;;;;; +2F21;KANGXI RADICAL GO;So;0;ON; 5902;;;;N;;;;; +2F22;KANGXI RADICAL GO SLOWLY;So;0;ON; 590A;;;;N;;;;; +2F23;KANGXI RADICAL EVENING;So;0;ON; 5915;;;;N;;;;; +2F24;KANGXI RADICAL BIG;So;0;ON; 5927;;;;N;;;;; +2F25;KANGXI RADICAL WOMAN;So;0;ON; 5973;;;;N;;;;; +2F26;KANGXI RADICAL CHILD;So;0;ON; 5B50;;;;N;;;;; +2F27;KANGXI RADICAL ROOF;So;0;ON; 5B80;;;;N;;;;; +2F28;KANGXI RADICAL INCH;So;0;ON; 5BF8;;;;N;;;;; +2F29;KANGXI RADICAL SMALL;So;0;ON; 5C0F;;;;N;;;;; +2F2A;KANGXI RADICAL LAME;So;0;ON; 5C22;;;;N;;;;; +2F2B;KANGXI RADICAL CORPSE;So;0;ON; 5C38;;;;N;;;;; +2F2C;KANGXI RADICAL SPROUT;So;0;ON; 5C6E;;;;N;;;;; +2F2D;KANGXI RADICAL MOUNTAIN;So;0;ON; 5C71;;;;N;;;;; +2F2E;KANGXI RADICAL RIVER;So;0;ON; 5DDB;;;;N;;;;; +2F2F;KANGXI RADICAL WORK;So;0;ON; 5DE5;;;;N;;;;; +2F30;KANGXI RADICAL ONESELF;So;0;ON; 5DF1;;;;N;;;;; +2F31;KANGXI RADICAL TURBAN;So;0;ON; 5DFE;;;;N;;;;; +2F32;KANGXI RADICAL DRY;So;0;ON; 5E72;;;;N;;;;; +2F33;KANGXI RADICAL SHORT THREAD;So;0;ON; 5E7A;;;;N;;;;; +2F34;KANGXI RADICAL DOTTED CLIFF;So;0;ON; 5E7F;;;;N;;;;; +2F35;KANGXI RADICAL LONG STRIDE;So;0;ON; 5EF4;;;;N;;;;; +2F36;KANGXI RADICAL TWO HANDS;So;0;ON; 5EFE;;;;N;;;;; +2F37;KANGXI RADICAL SHOOT;So;0;ON; 5F0B;;;;N;;;;; +2F38;KANGXI RADICAL BOW;So;0;ON; 5F13;;;;N;;;;; +2F39;KANGXI RADICAL SNOUT;So;0;ON; 5F50;;;;N;;;;; +2F3A;KANGXI RADICAL BRISTLE;So;0;ON; 5F61;;;;N;;;;; +2F3B;KANGXI RADICAL STEP;So;0;ON; 5F73;;;;N;;;;; +2F3C;KANGXI RADICAL HEART;So;0;ON; 5FC3;;;;N;;;;; +2F3D;KANGXI RADICAL HALBERD;So;0;ON; 6208;;;;N;;;;; +2F3E;KANGXI RADICAL DOOR;So;0;ON; 6236;;;;N;;;;; +2F3F;KANGXI RADICAL HAND;So;0;ON; 624B;;;;N;;;;; +2F40;KANGXI RADICAL BRANCH;So;0;ON; 652F;;;;N;;;;; +2F41;KANGXI RADICAL RAP;So;0;ON; 6534;;;;N;;;;; +2F42;KANGXI RADICAL SCRIPT;So;0;ON; 6587;;;;N;;;;; +2F43;KANGXI RADICAL DIPPER;So;0;ON; 6597;;;;N;;;;; +2F44;KANGXI RADICAL AXE;So;0;ON; 65A4;;;;N;;;;; +2F45;KANGXI RADICAL SQUARE;So;0;ON; 65B9;;;;N;;;;; +2F46;KANGXI RADICAL NOT;So;0;ON; 65E0;;;;N;;;;; +2F47;KANGXI RADICAL SUN;So;0;ON; 65E5;;;;N;;;;; +2F48;KANGXI RADICAL SAY;So;0;ON; 66F0;;;;N;;;;; +2F49;KANGXI RADICAL MOON;So;0;ON; 6708;;;;N;;;;; +2F4A;KANGXI RADICAL TREE;So;0;ON; 6728;;;;N;;;;; +2F4B;KANGXI RADICAL LACK;So;0;ON; 6B20;;;;N;;;;; +2F4C;KANGXI RADICAL STOP;So;0;ON; 6B62;;;;N;;;;; +2F4D;KANGXI RADICAL DEATH;So;0;ON; 6B79;;;;N;;;;; +2F4E;KANGXI RADICAL WEAPON;So;0;ON; 6BB3;;;;N;;;;; +2F4F;KANGXI RADICAL DO NOT;So;0;ON; 6BCB;;;;N;;;;; +2F50;KANGXI RADICAL COMPARE;So;0;ON; 6BD4;;;;N;;;;; +2F51;KANGXI RADICAL FUR;So;0;ON; 6BDB;;;;N;;;;; +2F52;KANGXI RADICAL CLAN;So;0;ON; 6C0F;;;;N;;;;; +2F53;KANGXI RADICAL STEAM;So;0;ON; 6C14;;;;N;;;;; +2F54;KANGXI RADICAL WATER;So;0;ON; 6C34;;;;N;;;;; +2F55;KANGXI RADICAL FIRE;So;0;ON; 706B;;;;N;;;;; +2F56;KANGXI RADICAL CLAW;So;0;ON; 722A;;;;N;;;;; +2F57;KANGXI RADICAL FATHER;So;0;ON; 7236;;;;N;;;;; +2F58;KANGXI RADICAL DOUBLE X;So;0;ON; 723B;;;;N;;;;; +2F59;KANGXI RADICAL HALF TREE TRUNK;So;0;ON; 723F;;;;N;;;;; +2F5A;KANGXI RADICAL SLICE;So;0;ON; 7247;;;;N;;;;; +2F5B;KANGXI RADICAL FANG;So;0;ON; 7259;;;;N;;;;; +2F5C;KANGXI RADICAL COW;So;0;ON; 725B;;;;N;;;;; +2F5D;KANGXI RADICAL DOG;So;0;ON; 72AC;;;;N;;;;; +2F5E;KANGXI RADICAL PROFOUND;So;0;ON; 7384;;;;N;;;;; +2F5F;KANGXI RADICAL JADE;So;0;ON; 7389;;;;N;;;;; +2F60;KANGXI RADICAL MELON;So;0;ON; 74DC;;;;N;;;;; +2F61;KANGXI RADICAL TILE;So;0;ON; 74E6;;;;N;;;;; +2F62;KANGXI RADICAL SWEET;So;0;ON; 7518;;;;N;;;;; +2F63;KANGXI RADICAL LIFE;So;0;ON; 751F;;;;N;;;;; +2F64;KANGXI RADICAL USE;So;0;ON; 7528;;;;N;;;;; +2F65;KANGXI RADICAL FIELD;So;0;ON; 7530;;;;N;;;;; +2F66;KANGXI RADICAL BOLT OF CLOTH;So;0;ON; 758B;;;;N;;;;; +2F67;KANGXI RADICAL SICKNESS;So;0;ON; 7592;;;;N;;;;; +2F68;KANGXI RADICAL DOTTED TENT;So;0;ON; 7676;;;;N;;;;; +2F69;KANGXI RADICAL WHITE;So;0;ON; 767D;;;;N;;;;; +2F6A;KANGXI RADICAL SKIN;So;0;ON; 76AE;;;;N;;;;; +2F6B;KANGXI RADICAL DISH;So;0;ON; 76BF;;;;N;;;;; +2F6C;KANGXI RADICAL EYE;So;0;ON; 76EE;;;;N;;;;; +2F6D;KANGXI RADICAL SPEAR;So;0;ON; 77DB;;;;N;;;;; +2F6E;KANGXI RADICAL ARROW;So;0;ON; 77E2;;;;N;;;;; +2F6F;KANGXI RADICAL STONE;So;0;ON; 77F3;;;;N;;;;; +2F70;KANGXI RADICAL SPIRIT;So;0;ON; 793A;;;;N;;;;; +2F71;KANGXI RADICAL TRACK;So;0;ON; 79B8;;;;N;;;;; +2F72;KANGXI RADICAL GRAIN;So;0;ON; 79BE;;;;N;;;;; +2F73;KANGXI RADICAL CAVE;So;0;ON; 7A74;;;;N;;;;; +2F74;KANGXI RADICAL STAND;So;0;ON; 7ACB;;;;N;;;;; +2F75;KANGXI RADICAL BAMBOO;So;0;ON; 7AF9;;;;N;;;;; +2F76;KANGXI RADICAL RICE;So;0;ON; 7C73;;;;N;;;;; +2F77;KANGXI RADICAL SILK;So;0;ON; 7CF8;;;;N;;;;; +2F78;KANGXI RADICAL JAR;So;0;ON; 7F36;;;;N;;;;; +2F79;KANGXI RADICAL NET;So;0;ON; 7F51;;;;N;;;;; +2F7A;KANGXI RADICAL SHEEP;So;0;ON; 7F8A;;;;N;;;;; +2F7B;KANGXI RADICAL FEATHER;So;0;ON; 7FBD;;;;N;;;;; +2F7C;KANGXI RADICAL OLD;So;0;ON; 8001;;;;N;;;;; +2F7D;KANGXI RADICAL AND;So;0;ON; 800C;;;;N;;;;; +2F7E;KANGXI RADICAL PLOW;So;0;ON; 8012;;;;N;;;;; +2F7F;KANGXI RADICAL EAR;So;0;ON; 8033;;;;N;;;;; +2F80;KANGXI RADICAL BRUSH;So;0;ON; 807F;;;;N;;;;; +2F81;KANGXI RADICAL MEAT;So;0;ON; 8089;;;;N;;;;; +2F82;KANGXI RADICAL MINISTER;So;0;ON; 81E3;;;;N;;;;; +2F83;KANGXI RADICAL SELF;So;0;ON; 81EA;;;;N;;;;; +2F84;KANGXI RADICAL ARRIVE;So;0;ON; 81F3;;;;N;;;;; +2F85;KANGXI RADICAL MORTAR;So;0;ON; 81FC;;;;N;;;;; +2F86;KANGXI RADICAL TONGUE;So;0;ON; 820C;;;;N;;;;; +2F87;KANGXI RADICAL OPPOSE;So;0;ON; 821B;;;;N;;;;; +2F88;KANGXI RADICAL BOAT;So;0;ON; 821F;;;;N;;;;; +2F89;KANGXI RADICAL STOPPING;So;0;ON; 826E;;;;N;;;;; +2F8A;KANGXI RADICAL COLOR;So;0;ON; 8272;;;;N;;;;; +2F8B;KANGXI RADICAL GRASS;So;0;ON; 8278;;;;N;;;;; +2F8C;KANGXI RADICAL TIGER;So;0;ON; 864D;;;;N;;;;; +2F8D;KANGXI RADICAL INSECT;So;0;ON; 866B;;;;N;;;;; +2F8E;KANGXI RADICAL BLOOD;So;0;ON; 8840;;;;N;;;;; +2F8F;KANGXI RADICAL WALK ENCLOSURE;So;0;ON; 884C;;;;N;;;;; +2F90;KANGXI RADICAL CLOTHES;So;0;ON; 8863;;;;N;;;;; +2F91;KANGXI RADICAL WEST;So;0;ON; 897E;;;;N;;;;; +2F92;KANGXI RADICAL SEE;So;0;ON; 898B;;;;N;;;;; +2F93;KANGXI RADICAL HORN;So;0;ON; 89D2;;;;N;;;;; +2F94;KANGXI RADICAL SPEECH;So;0;ON; 8A00;;;;N;;;;; +2F95;KANGXI RADICAL VALLEY;So;0;ON; 8C37;;;;N;;;;; +2F96;KANGXI RADICAL BEAN;So;0;ON; 8C46;;;;N;;;;; +2F97;KANGXI RADICAL PIG;So;0;ON; 8C55;;;;N;;;;; +2F98;KANGXI RADICAL BADGER;So;0;ON; 8C78;;;;N;;;;; +2F99;KANGXI RADICAL SHELL;So;0;ON; 8C9D;;;;N;;;;; +2F9A;KANGXI RADICAL RED;So;0;ON; 8D64;;;;N;;;;; +2F9B;KANGXI RADICAL RUN;So;0;ON; 8D70;;;;N;;;;; +2F9C;KANGXI RADICAL FOOT;So;0;ON; 8DB3;;;;N;;;;; +2F9D;KANGXI RADICAL BODY;So;0;ON; 8EAB;;;;N;;;;; +2F9E;KANGXI RADICAL CART;So;0;ON; 8ECA;;;;N;;;;; +2F9F;KANGXI RADICAL BITTER;So;0;ON; 8F9B;;;;N;;;;; +2FA0;KANGXI RADICAL MORNING;So;0;ON; 8FB0;;;;N;;;;; +2FA1;KANGXI RADICAL WALK;So;0;ON; 8FB5;;;;N;;;;; +2FA2;KANGXI RADICAL CITY;So;0;ON; 9091;;;;N;;;;; +2FA3;KANGXI RADICAL WINE;So;0;ON; 9149;;;;N;;;;; +2FA4;KANGXI RADICAL DISTINGUISH;So;0;ON; 91C6;;;;N;;;;; +2FA5;KANGXI RADICAL VILLAGE;So;0;ON; 91CC;;;;N;;;;; +2FA6;KANGXI RADICAL GOLD;So;0;ON; 91D1;;;;N;;;;; +2FA7;KANGXI RADICAL LONG;So;0;ON; 9577;;;;N;;;;; +2FA8;KANGXI RADICAL GATE;So;0;ON; 9580;;;;N;;;;; +2FA9;KANGXI RADICAL MOUND;So;0;ON; 961C;;;;N;;;;; +2FAA;KANGXI RADICAL SLAVE;So;0;ON; 96B6;;;;N;;;;; +2FAB;KANGXI RADICAL SHORT TAILED BIRD;So;0;ON; 96B9;;;;N;;;;; +2FAC;KANGXI RADICAL RAIN;So;0;ON; 96E8;;;;N;;;;; +2FAD;KANGXI RADICAL BLUE;So;0;ON; 9751;;;;N;;;;; +2FAE;KANGXI RADICAL WRONG;So;0;ON; 975E;;;;N;;;;; +2FAF;KANGXI RADICAL FACE;So;0;ON; 9762;;;;N;;;;; +2FB0;KANGXI RADICAL LEATHER;So;0;ON; 9769;;;;N;;;;; +2FB1;KANGXI RADICAL TANNED LEATHER;So;0;ON; 97CB;;;;N;;;;; +2FB2;KANGXI RADICAL LEEK;So;0;ON; 97ED;;;;N;;;;; +2FB3;KANGXI RADICAL SOUND;So;0;ON; 97F3;;;;N;;;;; +2FB4;KANGXI RADICAL LEAF;So;0;ON; 9801;;;;N;;;;; +2FB5;KANGXI RADICAL WIND;So;0;ON; 98A8;;;;N;;;;; +2FB6;KANGXI RADICAL FLY;So;0;ON; 98DB;;;;N;;;;; +2FB7;KANGXI RADICAL EAT;So;0;ON; 98DF;;;;N;;;;; +2FB8;KANGXI RADICAL HEAD;So;0;ON; 9996;;;;N;;;;; +2FB9;KANGXI RADICAL FRAGRANT;So;0;ON; 9999;;;;N;;;;; +2FBA;KANGXI RADICAL HORSE;So;0;ON; 99AC;;;;N;;;;; +2FBB;KANGXI RADICAL BONE;So;0;ON; 9AA8;;;;N;;;;; +2FBC;KANGXI RADICAL TALL;So;0;ON; 9AD8;;;;N;;;;; +2FBD;KANGXI RADICAL HAIR;So;0;ON; 9ADF;;;;N;;;;; +2FBE;KANGXI RADICAL FIGHT;So;0;ON; 9B25;;;;N;;;;; +2FBF;KANGXI RADICAL SACRIFICIAL WINE;So;0;ON; 9B2F;;;;N;;;;; +2FC0;KANGXI RADICAL CAULDRON;So;0;ON; 9B32;;;;N;;;;; +2FC1;KANGXI RADICAL GHOST;So;0;ON; 9B3C;;;;N;;;;; +2FC2;KANGXI RADICAL FISH;So;0;ON; 9B5A;;;;N;;;;; +2FC3;KANGXI RADICAL BIRD;So;0;ON; 9CE5;;;;N;;;;; +2FC4;KANGXI RADICAL SALT;So;0;ON; 9E75;;;;N;;;;; +2FC5;KANGXI RADICAL DEER;So;0;ON; 9E7F;;;;N;;;;; +2FC6;KANGXI RADICAL WHEAT;So;0;ON; 9EA5;;;;N;;;;; +2FC7;KANGXI RADICAL HEMP;So;0;ON; 9EBB;;;;N;;;;; +2FC8;KANGXI RADICAL YELLOW;So;0;ON; 9EC3;;;;N;;;;; +2FC9;KANGXI RADICAL MILLET;So;0;ON; 9ECD;;;;N;;;;; +2FCA;KANGXI RADICAL BLACK;So;0;ON; 9ED1;;;;N;;;;; +2FCB;KANGXI RADICAL EMBROIDERY;So;0;ON; 9EF9;;;;N;;;;; +2FCC;KANGXI RADICAL FROG;So;0;ON; 9EFD;;;;N;;;;; +2FCD;KANGXI RADICAL TRIPOD;So;0;ON; 9F0E;;;;N;;;;; +2FCE;KANGXI RADICAL DRUM;So;0;ON; 9F13;;;;N;;;;; +2FCF;KANGXI RADICAL RAT;So;0;ON; 9F20;;;;N;;;;; +2FD0;KANGXI RADICAL NOSE;So;0;ON; 9F3B;;;;N;;;;; +2FD1;KANGXI RADICAL EVEN;So;0;ON; 9F4A;;;;N;;;;; +2FD2;KANGXI RADICAL TOOTH;So;0;ON; 9F52;;;;N;;;;; +2FD3;KANGXI RADICAL DRAGON;So;0;ON; 9F8D;;;;N;;;;; +2FD4;KANGXI RADICAL TURTLE;So;0;ON; 9F9C;;;;N;;;;; +2FD5;KANGXI RADICAL FLUTE;So;0;ON; 9FA0;;;;N;;;;; +2FF0;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT;So;0;ON;;;;;N;;;;; +2FF1;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO BELOW;So;0;ON;;;;;N;;;;; +2FF2;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO MIDDLE AND RIGHT;So;0;ON;;;;;N;;;;; +2FF3;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND BELOW;So;0;ON;;;;;N;;;;; +2FF4;IDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUND;So;0;ON;;;;;N;;;;; +2FF5;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM ABOVE;So;0;ON;;;;;N;;;;; +2FF6;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM BELOW;So;0;ON;;;;;N;;;;; +2FF7;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LEFT;So;0;ON;;;;;N;;;;; +2FF8;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER LEFT;So;0;ON;;;;;N;;;;; +2FF9;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER RIGHT;So;0;ON;;;;;N;;;;; +2FFA;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER LEFT;So;0;ON;;;;;N;;;;; +2FFB;IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID;So;0;ON;;;;;N;;;;; +2FFC;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM RIGHT;So;0;ON;;;;;N;;;;; +2FFD;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER RIGHT;So;0;ON;;;;;N;;;;; +2FFE;IDEOGRAPHIC DESCRIPTION CHARACTER HORIZONTAL REFLECTION;So;0;ON;;;;;N;;;;; +2FFF;IDEOGRAPHIC DESCRIPTION CHARACTER ROTATION;So;0;ON;;;;;N;;;;; +3000;IDEOGRAPHIC SPACE;Zs;0;WS; 0020;;;;N;;;;; +3001;IDEOGRAPHIC COMMA;Po;0;ON;;;;;N;;;;; +3002;IDEOGRAPHIC FULL STOP;Po;0;ON;;;;;N;IDEOGRAPHIC PERIOD;;;; +3003;DITTO MARK;Po;0;ON;;;;;N;;;;; +3004;JAPANESE INDUSTRIAL STANDARD SYMBOL;So;0;ON;;;;;N;;;;; +3005;IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;; +3006;IDEOGRAPHIC CLOSING MARK;Lo;0;L;;;;;N;;;;; +3007;IDEOGRAPHIC NUMBER ZERO;Nl;0;L;;;;0;N;;;;; +3008;LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING ANGLE BRACKET;;;; +3009;RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING ANGLE BRACKET;;;; +300A;LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING DOUBLE ANGLE BRACKET;;;; +300B;RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING DOUBLE ANGLE BRACKET;;;; +300C;LEFT CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING CORNER BRACKET;;;; +300D;RIGHT CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING CORNER BRACKET;;;; +300E;LEFT WHITE CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE CORNER BRACKET;;;; +300F;RIGHT WHITE CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE CORNER BRACKET;;;; +3010;LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING BLACK LENTICULAR BRACKET;;;; +3011;RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING BLACK LENTICULAR BRACKET;;;; +3012;POSTAL MARK;So;0;ON;;;;;N;;;;; +3013;GETA MARK;So;0;ON;;;;;N;;;;; +3014;LEFT TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING TORTOISE SHELL BRACKET;;;; +3015;RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING TORTOISE SHELL BRACKET;;;; +3016;LEFT WHITE LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE LENTICULAR BRACKET;;;; +3017;RIGHT WHITE LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE LENTICULAR BRACKET;;;; +3018;LEFT WHITE TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE TORTOISE SHELL BRACKET;;;; +3019;RIGHT WHITE TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE TORTOISE SHELL BRACKET;;;; +301A;LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE SQUARE BRACKET;;;; +301B;RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE SQUARE BRACKET;;;; +301C;WAVE DASH;Pd;0;ON;;;;;N;;;;; +301D;REVERSED DOUBLE PRIME QUOTATION MARK;Ps;0;ON;;;;;N;;;;; +301E;DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;; +301F;LOW DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;; +3020;POSTAL MARK FACE;So;0;ON;;;;;N;;;;; +3021;HANGZHOU NUMERAL ONE;Nl;0;L;;;;1;N;;;;; +3022;HANGZHOU NUMERAL TWO;Nl;0;L;;;;2;N;;;;; +3023;HANGZHOU NUMERAL THREE;Nl;0;L;;;;3;N;;;;; +3024;HANGZHOU NUMERAL FOUR;Nl;0;L;;;;4;N;;;;; +3025;HANGZHOU NUMERAL FIVE;Nl;0;L;;;;5;N;;;;; +3026;HANGZHOU NUMERAL SIX;Nl;0;L;;;;6;N;;;;; +3027;HANGZHOU NUMERAL SEVEN;Nl;0;L;;;;7;N;;;;; +3028;HANGZHOU NUMERAL EIGHT;Nl;0;L;;;;8;N;;;;; +3029;HANGZHOU NUMERAL NINE;Nl;0;L;;;;9;N;;;;; +302A;IDEOGRAPHIC LEVEL TONE MARK;Mn;218;NSM;;;;;N;;;;; +302B;IDEOGRAPHIC RISING TONE MARK;Mn;228;NSM;;;;;N;;;;; +302C;IDEOGRAPHIC DEPARTING TONE MARK;Mn;232;NSM;;;;;N;;;;; +302D;IDEOGRAPHIC ENTERING TONE MARK;Mn;222;NSM;;;;;N;;;;; +302E;HANGUL SINGLE DOT TONE MARK;Mc;224;L;;;;;N;;;;; +302F;HANGUL DOUBLE DOT TONE MARK;Mc;224;L;;;;;N;;;;; +3030;WAVY DASH;Pd;0;ON;;;;;N;;;;; +3031;VERTICAL KANA REPEAT MARK;Lm;0;L;;;;;N;;;;; +3032;VERTICAL KANA REPEAT WITH VOICED SOUND MARK;Lm;0;L;;;;;N;;;;; +3033;VERTICAL KANA REPEAT MARK UPPER HALF;Lm;0;L;;;;;N;;;;; +3034;VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF;Lm;0;L;;;;;N;;;;; +3035;VERTICAL KANA REPEAT MARK LOWER HALF;Lm;0;L;;;;;N;;;;; +3036;CIRCLED POSTAL MARK;So;0;ON; 3012;;;;N;;;;; +3037;IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL;So;0;ON;;;;;N;;;;; +3038;HANGZHOU NUMERAL TEN;Nl;0;L; 5341;;;10;N;;;;; +3039;HANGZHOU NUMERAL TWENTY;Nl;0;L; 5344;;;20;N;;;;; +303A;HANGZHOU NUMERAL THIRTY;Nl;0;L; 5345;;;30;N;;;;; +303B;VERTICAL IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;; +303C;MASU MARK;Lo;0;L;;;;;N;;;;; +303D;PART ALTERNATION MARK;Po;0;ON;;;;;N;;;;; +303E;IDEOGRAPHIC VARIATION INDICATOR;So;0;ON;;;;;N;;;;; +303F;IDEOGRAPHIC HALF FILL SPACE;So;0;ON;;;;;N;;;;; +3041;HIRAGANA LETTER SMALL A;Lo;0;L;;;;;N;;;;; +3042;HIRAGANA LETTER A;Lo;0;L;;;;;N;;;;; +3043;HIRAGANA LETTER SMALL I;Lo;0;L;;;;;N;;;;; +3044;HIRAGANA LETTER I;Lo;0;L;;;;;N;;;;; +3045;HIRAGANA LETTER SMALL U;Lo;0;L;;;;;N;;;;; +3046;HIRAGANA LETTER U;Lo;0;L;;;;;N;;;;; +3047;HIRAGANA LETTER SMALL E;Lo;0;L;;;;;N;;;;; +3048;HIRAGANA LETTER E;Lo;0;L;;;;;N;;;;; +3049;HIRAGANA LETTER SMALL O;Lo;0;L;;;;;N;;;;; +304A;HIRAGANA LETTER O;Lo;0;L;;;;;N;;;;; +304B;HIRAGANA LETTER KA;Lo;0;L;;;;;N;;;;; +304C;HIRAGANA LETTER GA;Lo;0;L;304B 3099;;;;N;;;;; +304D;HIRAGANA LETTER KI;Lo;0;L;;;;;N;;;;; +304E;HIRAGANA LETTER GI;Lo;0;L;304D 3099;;;;N;;;;; +304F;HIRAGANA LETTER KU;Lo;0;L;;;;;N;;;;; +3050;HIRAGANA LETTER GU;Lo;0;L;304F 3099;;;;N;;;;; +3051;HIRAGANA LETTER KE;Lo;0;L;;;;;N;;;;; +3052;HIRAGANA LETTER GE;Lo;0;L;3051 3099;;;;N;;;;; +3053;HIRAGANA LETTER KO;Lo;0;L;;;;;N;;;;; +3054;HIRAGANA LETTER GO;Lo;0;L;3053 3099;;;;N;;;;; +3055;HIRAGANA LETTER SA;Lo;0;L;;;;;N;;;;; +3056;HIRAGANA LETTER ZA;Lo;0;L;3055 3099;;;;N;;;;; +3057;HIRAGANA LETTER SI;Lo;0;L;;;;;N;;;;; +3058;HIRAGANA LETTER ZI;Lo;0;L;3057 3099;;;;N;;;;; +3059;HIRAGANA LETTER SU;Lo;0;L;;;;;N;;;;; +305A;HIRAGANA LETTER ZU;Lo;0;L;3059 3099;;;;N;;;;; +305B;HIRAGANA LETTER SE;Lo;0;L;;;;;N;;;;; +305C;HIRAGANA LETTER ZE;Lo;0;L;305B 3099;;;;N;;;;; +305D;HIRAGANA LETTER SO;Lo;0;L;;;;;N;;;;; +305E;HIRAGANA LETTER ZO;Lo;0;L;305D 3099;;;;N;;;;; +305F;HIRAGANA LETTER TA;Lo;0;L;;;;;N;;;;; +3060;HIRAGANA LETTER DA;Lo;0;L;305F 3099;;;;N;;;;; +3061;HIRAGANA LETTER TI;Lo;0;L;;;;;N;;;;; +3062;HIRAGANA LETTER DI;Lo;0;L;3061 3099;;;;N;;;;; +3063;HIRAGANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;; +3064;HIRAGANA LETTER TU;Lo;0;L;;;;;N;;;;; +3065;HIRAGANA LETTER DU;Lo;0;L;3064 3099;;;;N;;;;; +3066;HIRAGANA LETTER TE;Lo;0;L;;;;;N;;;;; +3067;HIRAGANA LETTER DE;Lo;0;L;3066 3099;;;;N;;;;; +3068;HIRAGANA LETTER TO;Lo;0;L;;;;;N;;;;; +3069;HIRAGANA LETTER DO;Lo;0;L;3068 3099;;;;N;;;;; +306A;HIRAGANA LETTER NA;Lo;0;L;;;;;N;;;;; +306B;HIRAGANA LETTER NI;Lo;0;L;;;;;N;;;;; +306C;HIRAGANA LETTER NU;Lo;0;L;;;;;N;;;;; +306D;HIRAGANA LETTER NE;Lo;0;L;;;;;N;;;;; +306E;HIRAGANA LETTER NO;Lo;0;L;;;;;N;;;;; +306F;HIRAGANA LETTER HA;Lo;0;L;;;;;N;;;;; +3070;HIRAGANA LETTER BA;Lo;0;L;306F 3099;;;;N;;;;; +3071;HIRAGANA LETTER PA;Lo;0;L;306F 309A;;;;N;;;;; +3072;HIRAGANA LETTER HI;Lo;0;L;;;;;N;;;;; +3073;HIRAGANA LETTER BI;Lo;0;L;3072 3099;;;;N;;;;; +3074;HIRAGANA LETTER PI;Lo;0;L;3072 309A;;;;N;;;;; +3075;HIRAGANA LETTER HU;Lo;0;L;;;;;N;;;;; +3076;HIRAGANA LETTER BU;Lo;0;L;3075 3099;;;;N;;;;; +3077;HIRAGANA LETTER PU;Lo;0;L;3075 309A;;;;N;;;;; +3078;HIRAGANA LETTER HE;Lo;0;L;;;;;N;;;;; +3079;HIRAGANA LETTER BE;Lo;0;L;3078 3099;;;;N;;;;; +307A;HIRAGANA LETTER PE;Lo;0;L;3078 309A;;;;N;;;;; +307B;HIRAGANA LETTER HO;Lo;0;L;;;;;N;;;;; +307C;HIRAGANA LETTER BO;Lo;0;L;307B 3099;;;;N;;;;; +307D;HIRAGANA LETTER PO;Lo;0;L;307B 309A;;;;N;;;;; +307E;HIRAGANA LETTER MA;Lo;0;L;;;;;N;;;;; +307F;HIRAGANA LETTER MI;Lo;0;L;;;;;N;;;;; +3080;HIRAGANA LETTER MU;Lo;0;L;;;;;N;;;;; +3081;HIRAGANA LETTER ME;Lo;0;L;;;;;N;;;;; +3082;HIRAGANA LETTER MO;Lo;0;L;;;;;N;;;;; +3083;HIRAGANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;; +3084;HIRAGANA LETTER YA;Lo;0;L;;;;;N;;;;; +3085;HIRAGANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;; +3086;HIRAGANA LETTER YU;Lo;0;L;;;;;N;;;;; +3087;HIRAGANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;; +3088;HIRAGANA LETTER YO;Lo;0;L;;;;;N;;;;; +3089;HIRAGANA LETTER RA;Lo;0;L;;;;;N;;;;; +308A;HIRAGANA LETTER RI;Lo;0;L;;;;;N;;;;; +308B;HIRAGANA LETTER RU;Lo;0;L;;;;;N;;;;; +308C;HIRAGANA LETTER RE;Lo;0;L;;;;;N;;;;; +308D;HIRAGANA LETTER RO;Lo;0;L;;;;;N;;;;; +308E;HIRAGANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;; +308F;HIRAGANA LETTER WA;Lo;0;L;;;;;N;;;;; +3090;HIRAGANA LETTER WI;Lo;0;L;;;;;N;;;;; +3091;HIRAGANA LETTER WE;Lo;0;L;;;;;N;;;;; +3092;HIRAGANA LETTER WO;Lo;0;L;;;;;N;;;;; +3093;HIRAGANA LETTER N;Lo;0;L;;;;;N;;;;; +3094;HIRAGANA LETTER VU;Lo;0;L;3046 3099;;;;N;;;;; +3095;HIRAGANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;; +3096;HIRAGANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;; +3099;COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA VOICED SOUND MARK;;;; +309A;COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;;;; +309B;KATAKANA-HIRAGANA VOICED SOUND MARK;Sk;0;ON; 0020 3099;;;;N;;;;; +309C;KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Sk;0;ON; 0020 309A;;;;N;;;;; +309D;HIRAGANA ITERATION MARK;Lm;0;L;;;;;N;;;;; +309E;HIRAGANA VOICED ITERATION MARK;Lm;0;L;309D 3099;;;;N;;;;; +309F;HIRAGANA DIGRAPH YORI;Lo;0;L; 3088 308A;;;;N;;;;; +30A0;KATAKANA-HIRAGANA DOUBLE HYPHEN;Pd;0;ON;;;;;N;;;;; +30A1;KATAKANA LETTER SMALL A;Lo;0;L;;;;;N;;;;; +30A2;KATAKANA LETTER A;Lo;0;L;;;;;N;;;;; +30A3;KATAKANA LETTER SMALL I;Lo;0;L;;;;;N;;;;; +30A4;KATAKANA LETTER I;Lo;0;L;;;;;N;;;;; +30A5;KATAKANA LETTER SMALL U;Lo;0;L;;;;;N;;;;; +30A6;KATAKANA LETTER U;Lo;0;L;;;;;N;;;;; +30A7;KATAKANA LETTER SMALL E;Lo;0;L;;;;;N;;;;; +30A8;KATAKANA LETTER E;Lo;0;L;;;;;N;;;;; +30A9;KATAKANA LETTER SMALL O;Lo;0;L;;;;;N;;;;; +30AA;KATAKANA LETTER O;Lo;0;L;;;;;N;;;;; +30AB;KATAKANA LETTER KA;Lo;0;L;;;;;N;;;;; +30AC;KATAKANA LETTER GA;Lo;0;L;30AB 3099;;;;N;;;;; +30AD;KATAKANA LETTER KI;Lo;0;L;;;;;N;;;;; +30AE;KATAKANA LETTER GI;Lo;0;L;30AD 3099;;;;N;;;;; +30AF;KATAKANA LETTER KU;Lo;0;L;;;;;N;;;;; +30B0;KATAKANA LETTER GU;Lo;0;L;30AF 3099;;;;N;;;;; +30B1;KATAKANA LETTER KE;Lo;0;L;;;;;N;;;;; +30B2;KATAKANA LETTER GE;Lo;0;L;30B1 3099;;;;N;;;;; +30B3;KATAKANA LETTER KO;Lo;0;L;;;;;N;;;;; +30B4;KATAKANA LETTER GO;Lo;0;L;30B3 3099;;;;N;;;;; +30B5;KATAKANA LETTER SA;Lo;0;L;;;;;N;;;;; +30B6;KATAKANA LETTER ZA;Lo;0;L;30B5 3099;;;;N;;;;; +30B7;KATAKANA LETTER SI;Lo;0;L;;;;;N;;;;; +30B8;KATAKANA LETTER ZI;Lo;0;L;30B7 3099;;;;N;;;;; +30B9;KATAKANA LETTER SU;Lo;0;L;;;;;N;;;;; +30BA;KATAKANA LETTER ZU;Lo;0;L;30B9 3099;;;;N;;;;; +30BB;KATAKANA LETTER SE;Lo;0;L;;;;;N;;;;; +30BC;KATAKANA LETTER ZE;Lo;0;L;30BB 3099;;;;N;;;;; +30BD;KATAKANA LETTER SO;Lo;0;L;;;;;N;;;;; +30BE;KATAKANA LETTER ZO;Lo;0;L;30BD 3099;;;;N;;;;; +30BF;KATAKANA LETTER TA;Lo;0;L;;;;;N;;;;; +30C0;KATAKANA LETTER DA;Lo;0;L;30BF 3099;;;;N;;;;; +30C1;KATAKANA LETTER TI;Lo;0;L;;;;;N;;;;; +30C2;KATAKANA LETTER DI;Lo;0;L;30C1 3099;;;;N;;;;; +30C3;KATAKANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;; +30C4;KATAKANA LETTER TU;Lo;0;L;;;;;N;;;;; +30C5;KATAKANA LETTER DU;Lo;0;L;30C4 3099;;;;N;;;;; +30C6;KATAKANA LETTER TE;Lo;0;L;;;;;N;;;;; +30C7;KATAKANA LETTER DE;Lo;0;L;30C6 3099;;;;N;;;;; +30C8;KATAKANA LETTER TO;Lo;0;L;;;;;N;;;;; +30C9;KATAKANA LETTER DO;Lo;0;L;30C8 3099;;;;N;;;;; +30CA;KATAKANA LETTER NA;Lo;0;L;;;;;N;;;;; +30CB;KATAKANA LETTER NI;Lo;0;L;;;;;N;;;;; +30CC;KATAKANA LETTER NU;Lo;0;L;;;;;N;;;;; +30CD;KATAKANA LETTER NE;Lo;0;L;;;;;N;;;;; +30CE;KATAKANA LETTER NO;Lo;0;L;;;;;N;;;;; +30CF;KATAKANA LETTER HA;Lo;0;L;;;;;N;;;;; +30D0;KATAKANA LETTER BA;Lo;0;L;30CF 3099;;;;N;;;;; +30D1;KATAKANA LETTER PA;Lo;0;L;30CF 309A;;;;N;;;;; +30D2;KATAKANA LETTER HI;Lo;0;L;;;;;N;;;;; +30D3;KATAKANA LETTER BI;Lo;0;L;30D2 3099;;;;N;;;;; +30D4;KATAKANA LETTER PI;Lo;0;L;30D2 309A;;;;N;;;;; +30D5;KATAKANA LETTER HU;Lo;0;L;;;;;N;;;;; +30D6;KATAKANA LETTER BU;Lo;0;L;30D5 3099;;;;N;;;;; +30D7;KATAKANA LETTER PU;Lo;0;L;30D5 309A;;;;N;;;;; +30D8;KATAKANA LETTER HE;Lo;0;L;;;;;N;;;;; +30D9;KATAKANA LETTER BE;Lo;0;L;30D8 3099;;;;N;;;;; +30DA;KATAKANA LETTER PE;Lo;0;L;30D8 309A;;;;N;;;;; +30DB;KATAKANA LETTER HO;Lo;0;L;;;;;N;;;;; +30DC;KATAKANA LETTER BO;Lo;0;L;30DB 3099;;;;N;;;;; +30DD;KATAKANA LETTER PO;Lo;0;L;30DB 309A;;;;N;;;;; +30DE;KATAKANA LETTER MA;Lo;0;L;;;;;N;;;;; +30DF;KATAKANA LETTER MI;Lo;0;L;;;;;N;;;;; +30E0;KATAKANA LETTER MU;Lo;0;L;;;;;N;;;;; +30E1;KATAKANA LETTER ME;Lo;0;L;;;;;N;;;;; +30E2;KATAKANA LETTER MO;Lo;0;L;;;;;N;;;;; +30E3;KATAKANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;; +30E4;KATAKANA LETTER YA;Lo;0;L;;;;;N;;;;; +30E5;KATAKANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;; +30E6;KATAKANA LETTER YU;Lo;0;L;;;;;N;;;;; +30E7;KATAKANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;; +30E8;KATAKANA LETTER YO;Lo;0;L;;;;;N;;;;; +30E9;KATAKANA LETTER RA;Lo;0;L;;;;;N;;;;; +30EA;KATAKANA LETTER RI;Lo;0;L;;;;;N;;;;; +30EB;KATAKANA LETTER RU;Lo;0;L;;;;;N;;;;; +30EC;KATAKANA LETTER RE;Lo;0;L;;;;;N;;;;; +30ED;KATAKANA LETTER RO;Lo;0;L;;;;;N;;;;; +30EE;KATAKANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;; +30EF;KATAKANA LETTER WA;Lo;0;L;;;;;N;;;;; +30F0;KATAKANA LETTER WI;Lo;0;L;;;;;N;;;;; +30F1;KATAKANA LETTER WE;Lo;0;L;;;;;N;;;;; +30F2;KATAKANA LETTER WO;Lo;0;L;;;;;N;;;;; +30F3;KATAKANA LETTER N;Lo;0;L;;;;;N;;;;; +30F4;KATAKANA LETTER VU;Lo;0;L;30A6 3099;;;;N;;;;; +30F5;KATAKANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;; +30F6;KATAKANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;; +30F7;KATAKANA LETTER VA;Lo;0;L;30EF 3099;;;;N;;;;; +30F8;KATAKANA LETTER VI;Lo;0;L;30F0 3099;;;;N;;;;; +30F9;KATAKANA LETTER VE;Lo;0;L;30F1 3099;;;;N;;;;; +30FA;KATAKANA LETTER VO;Lo;0;L;30F2 3099;;;;N;;;;; +30FB;KATAKANA MIDDLE DOT;Po;0;ON;;;;;N;;;;; +30FC;KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;;;;;N;;;;; +30FD;KATAKANA ITERATION MARK;Lm;0;L;;;;;N;;;;; +30FE;KATAKANA VOICED ITERATION MARK;Lm;0;L;30FD 3099;;;;N;;;;; +30FF;KATAKANA DIGRAPH KOTO;Lo;0;L; 30B3 30C8;;;;N;;;;; +3105;BOPOMOFO LETTER B;Lo;0;L;;;;;N;;;;; +3106;BOPOMOFO LETTER P;Lo;0;L;;;;;N;;;;; +3107;BOPOMOFO LETTER M;Lo;0;L;;;;;N;;;;; +3108;BOPOMOFO LETTER F;Lo;0;L;;;;;N;;;;; +3109;BOPOMOFO LETTER D;Lo;0;L;;;;;N;;;;; +310A;BOPOMOFO LETTER T;Lo;0;L;;;;;N;;;;; +310B;BOPOMOFO LETTER N;Lo;0;L;;;;;N;;;;; +310C;BOPOMOFO LETTER L;Lo;0;L;;;;;N;;;;; +310D;BOPOMOFO LETTER G;Lo;0;L;;;;;N;;;;; +310E;BOPOMOFO LETTER K;Lo;0;L;;;;;N;;;;; +310F;BOPOMOFO LETTER H;Lo;0;L;;;;;N;;;;; +3110;BOPOMOFO LETTER J;Lo;0;L;;;;;N;;;;; +3111;BOPOMOFO LETTER Q;Lo;0;L;;;;;N;;;;; +3112;BOPOMOFO LETTER X;Lo;0;L;;;;;N;;;;; +3113;BOPOMOFO LETTER ZH;Lo;0;L;;;;;N;;;;; +3114;BOPOMOFO LETTER CH;Lo;0;L;;;;;N;;;;; +3115;BOPOMOFO LETTER SH;Lo;0;L;;;;;N;;;;; +3116;BOPOMOFO LETTER R;Lo;0;L;;;;;N;;;;; +3117;BOPOMOFO LETTER Z;Lo;0;L;;;;;N;;;;; +3118;BOPOMOFO LETTER C;Lo;0;L;;;;;N;;;;; +3119;BOPOMOFO LETTER S;Lo;0;L;;;;;N;;;;; +311A;BOPOMOFO LETTER A;Lo;0;L;;;;;N;;;;; +311B;BOPOMOFO LETTER O;Lo;0;L;;;;;N;;;;; +311C;BOPOMOFO LETTER E;Lo;0;L;;;;;N;;;;; +311D;BOPOMOFO LETTER EH;Lo;0;L;;;;;N;;;;; +311E;BOPOMOFO LETTER AI;Lo;0;L;;;;;N;;;;; +311F;BOPOMOFO LETTER EI;Lo;0;L;;;;;N;;;;; +3120;BOPOMOFO LETTER AU;Lo;0;L;;;;;N;;;;; +3121;BOPOMOFO LETTER OU;Lo;0;L;;;;;N;;;;; +3122;BOPOMOFO LETTER AN;Lo;0;L;;;;;N;;;;; +3123;BOPOMOFO LETTER EN;Lo;0;L;;;;;N;;;;; +3124;BOPOMOFO LETTER ANG;Lo;0;L;;;;;N;;;;; +3125;BOPOMOFO LETTER ENG;Lo;0;L;;;;;N;;;;; +3126;BOPOMOFO LETTER ER;Lo;0;L;;;;;N;;;;; +3127;BOPOMOFO LETTER I;Lo;0;L;;;;;N;;;;; +3128;BOPOMOFO LETTER U;Lo;0;L;;;;;N;;;;; +3129;BOPOMOFO LETTER IU;Lo;0;L;;;;;N;;;;; +312A;BOPOMOFO LETTER V;Lo;0;L;;;;;N;;;;; +312B;BOPOMOFO LETTER NG;Lo;0;L;;;;;N;;;;; +312C;BOPOMOFO LETTER GN;Lo;0;L;;;;;N;;;;; +312D;BOPOMOFO LETTER IH;Lo;0;L;;;;;N;;;;; +312E;BOPOMOFO LETTER O WITH DOT ABOVE;Lo;0;L;;;;;N;;;;; +312F;BOPOMOFO LETTER NN;Lo;0;L;;;;;N;;;;; +3131;HANGUL LETTER KIYEOK;Lo;0;L; 1100;;;;N;HANGUL LETTER GIYEOG;;;; +3132;HANGUL LETTER SSANGKIYEOK;Lo;0;L; 1101;;;;N;HANGUL LETTER SSANG GIYEOG;;;; +3133;HANGUL LETTER KIYEOK-SIOS;Lo;0;L; 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;; +3134;HANGUL LETTER NIEUN;Lo;0;L; 1102;;;;N;;;;; +3135;HANGUL LETTER NIEUN-CIEUC;Lo;0;L; 11AC;;;;N;HANGUL LETTER NIEUN JIEUJ;;;; +3136;HANGUL LETTER NIEUN-HIEUH;Lo;0;L; 11AD;;;;N;HANGUL LETTER NIEUN HIEUH;;;; +3137;HANGUL LETTER TIKEUT;Lo;0;L; 1103;;;;N;HANGUL LETTER DIGEUD;;;; +3138;HANGUL LETTER SSANGTIKEUT;Lo;0;L; 1104;;;;N;HANGUL LETTER SSANG DIGEUD;;;; +3139;HANGUL LETTER RIEUL;Lo;0;L; 1105;;;;N;HANGUL LETTER LIEUL;;;; +313A;HANGUL LETTER RIEUL-KIYEOK;Lo;0;L; 11B0;;;;N;HANGUL LETTER LIEUL GIYEOG;;;; +313B;HANGUL LETTER RIEUL-MIEUM;Lo;0;L; 11B1;;;;N;HANGUL LETTER LIEUL MIEUM;;;; +313C;HANGUL LETTER RIEUL-PIEUP;Lo;0;L; 11B2;;;;N;HANGUL LETTER LIEUL BIEUB;;;; +313D;HANGUL LETTER RIEUL-SIOS;Lo;0;L; 11B3;;;;N;HANGUL LETTER LIEUL SIOS;;;; +313E;HANGUL LETTER RIEUL-THIEUTH;Lo;0;L; 11B4;;;;N;HANGUL LETTER LIEUL TIEUT;;;; +313F;HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L; 11B5;;;;N;HANGUL LETTER LIEUL PIEUP;;;; +3140;HANGUL LETTER RIEUL-HIEUH;Lo;0;L; 111A;;;;N;HANGUL LETTER LIEUL HIEUH;;;; +3141;HANGUL LETTER MIEUM;Lo;0;L; 1106;;;;N;;;;; +3142;HANGUL LETTER PIEUP;Lo;0;L; 1107;;;;N;HANGUL LETTER BIEUB;;;; +3143;HANGUL LETTER SSANGPIEUP;Lo;0;L; 1108;;;;N;HANGUL LETTER SSANG BIEUB;;;; +3144;HANGUL LETTER PIEUP-SIOS;Lo;0;L; 1121;;;;N;HANGUL LETTER BIEUB SIOS;;;; +3145;HANGUL LETTER SIOS;Lo;0;L; 1109;;;;N;;;;; +3146;HANGUL LETTER SSANGSIOS;Lo;0;L; 110A;;;;N;HANGUL LETTER SSANG SIOS;;;; +3147;HANGUL LETTER IEUNG;Lo;0;L; 110B;;;;N;;;;; +3148;HANGUL LETTER CIEUC;Lo;0;L; 110C;;;;N;HANGUL LETTER JIEUJ;;;; +3149;HANGUL LETTER SSANGCIEUC;Lo;0;L; 110D;;;;N;HANGUL LETTER SSANG JIEUJ;;;; +314A;HANGUL LETTER CHIEUCH;Lo;0;L; 110E;;;;N;HANGUL LETTER CIEUC;;;; +314B;HANGUL LETTER KHIEUKH;Lo;0;L; 110F;;;;N;HANGUL LETTER KIYEOK;;;; +314C;HANGUL LETTER THIEUTH;Lo;0;L; 1110;;;;N;HANGUL LETTER TIEUT;;;; +314D;HANGUL LETTER PHIEUPH;Lo;0;L; 1111;;;;N;HANGUL LETTER PIEUP;;;; +314E;HANGUL LETTER HIEUH;Lo;0;L; 1112;;;;N;;;;; +314F;HANGUL LETTER A;Lo;0;L; 1161;;;;N;;;;; +3150;HANGUL LETTER AE;Lo;0;L; 1162;;;;N;;;;; +3151;HANGUL LETTER YA;Lo;0;L; 1163;;;;N;;;;; +3152;HANGUL LETTER YAE;Lo;0;L; 1164;;;;N;;;;; +3153;HANGUL LETTER EO;Lo;0;L; 1165;;;;N;;;;; +3154;HANGUL LETTER E;Lo;0;L; 1166;;;;N;;;;; +3155;HANGUL LETTER YEO;Lo;0;L; 1167;;;;N;;;;; +3156;HANGUL LETTER YE;Lo;0;L; 1168;;;;N;;;;; +3157;HANGUL LETTER O;Lo;0;L; 1169;;;;N;;;;; +3158;HANGUL LETTER WA;Lo;0;L; 116A;;;;N;;;;; +3159;HANGUL LETTER WAE;Lo;0;L; 116B;;;;N;;;;; +315A;HANGUL LETTER OE;Lo;0;L; 116C;;;;N;;;;; +315B;HANGUL LETTER YO;Lo;0;L; 116D;;;;N;;;;; +315C;HANGUL LETTER U;Lo;0;L; 116E;;;;N;;;;; +315D;HANGUL LETTER WEO;Lo;0;L; 116F;;;;N;;;;; +315E;HANGUL LETTER WE;Lo;0;L; 1170;;;;N;;;;; +315F;HANGUL LETTER WI;Lo;0;L; 1171;;;;N;;;;; +3160;HANGUL LETTER YU;Lo;0;L; 1172;;;;N;;;;; +3161;HANGUL LETTER EU;Lo;0;L; 1173;;;;N;;;;; +3162;HANGUL LETTER YI;Lo;0;L; 1174;;;;N;;;;; +3163;HANGUL LETTER I;Lo;0;L; 1175;;;;N;;;;; +3164;HANGUL FILLER;Lo;0;L; 1160;;;;N;HANGUL CAE OM;;;; +3165;HANGUL LETTER SSANGNIEUN;Lo;0;L; 1114;;;;N;HANGUL LETTER SSANG NIEUN;;;; +3166;HANGUL LETTER NIEUN-TIKEUT;Lo;0;L; 1115;;;;N;HANGUL LETTER NIEUN DIGEUD;;;; +3167;HANGUL LETTER NIEUN-SIOS;Lo;0;L; 11C7;;;;N;HANGUL LETTER NIEUN SIOS;;;; +3168;HANGUL LETTER NIEUN-PANSIOS;Lo;0;L; 11C8;;;;N;HANGUL LETTER NIEUN BAN CHI EUM;;;; +3169;HANGUL LETTER RIEUL-KIYEOK-SIOS;Lo;0;L; 11CC;;;;N;HANGUL LETTER LIEUL GIYEOG SIOS;;;; +316A;HANGUL LETTER RIEUL-TIKEUT;Lo;0;L; 11CE;;;;N;HANGUL LETTER LIEUL DIGEUD;;;; +316B;HANGUL LETTER RIEUL-PIEUP-SIOS;Lo;0;L; 11D3;;;;N;HANGUL LETTER LIEUL BIEUB SIOS;;;; +316C;HANGUL LETTER RIEUL-PANSIOS;Lo;0;L; 11D7;;;;N;HANGUL LETTER LIEUL BAN CHI EUM;;;; +316D;HANGUL LETTER RIEUL-YEORINHIEUH;Lo;0;L; 11D9;;;;N;HANGUL LETTER LIEUL YEOLIN HIEUH;;;; +316E;HANGUL LETTER MIEUM-PIEUP;Lo;0;L; 111C;;;;N;HANGUL LETTER MIEUM BIEUB;;;; +316F;HANGUL LETTER MIEUM-SIOS;Lo;0;L; 11DD;;;;N;HANGUL LETTER MIEUM SIOS;;;; +3170;HANGUL LETTER MIEUM-PANSIOS;Lo;0;L; 11DF;;;;N;HANGUL LETTER BIEUB BAN CHI EUM;;;; +3171;HANGUL LETTER KAPYEOUNMIEUM;Lo;0;L; 111D;;;;N;HANGUL LETTER MIEUM SUN GYEONG EUM;;;; +3172;HANGUL LETTER PIEUP-KIYEOK;Lo;0;L; 111E;;;;N;HANGUL LETTER BIEUB GIYEOG;;;; +3173;HANGUL LETTER PIEUP-TIKEUT;Lo;0;L; 1120;;;;N;HANGUL LETTER BIEUB DIGEUD;;;; +3174;HANGUL LETTER PIEUP-SIOS-KIYEOK;Lo;0;L; 1122;;;;N;HANGUL LETTER BIEUB SIOS GIYEOG;;;; +3175;HANGUL LETTER PIEUP-SIOS-TIKEUT;Lo;0;L; 1123;;;;N;HANGUL LETTER BIEUB SIOS DIGEUD;;;; +3176;HANGUL LETTER PIEUP-CIEUC;Lo;0;L; 1127;;;;N;HANGUL LETTER BIEUB JIEUJ;;;; +3177;HANGUL LETTER PIEUP-THIEUTH;Lo;0;L; 1129;;;;N;HANGUL LETTER BIEUB TIEUT;;;; +3178;HANGUL LETTER KAPYEOUNPIEUP;Lo;0;L; 112B;;;;N;HANGUL LETTER BIEUB SUN GYEONG EUM;;;; +3179;HANGUL LETTER KAPYEOUNSSANGPIEUP;Lo;0;L; 112C;;;;N;HANGUL LETTER SSANG BIEUB SUN GYEONG EUM;;;; +317A;HANGUL LETTER SIOS-KIYEOK;Lo;0;L; 112D;;;;N;HANGUL LETTER SIOS GIYEOG;;;; +317B;HANGUL LETTER SIOS-NIEUN;Lo;0;L; 112E;;;;N;HANGUL LETTER SIOS NIEUN;;;; +317C;HANGUL LETTER SIOS-TIKEUT;Lo;0;L; 112F;;;;N;HANGUL LETTER SIOS DIGEUD;;;; +317D;HANGUL LETTER SIOS-PIEUP;Lo;0;L; 1132;;;;N;HANGUL LETTER SIOS BIEUB;;;; +317E;HANGUL LETTER SIOS-CIEUC;Lo;0;L; 1136;;;;N;HANGUL LETTER SIOS JIEUJ;;;; +317F;HANGUL LETTER PANSIOS;Lo;0;L; 1140;;;;N;HANGUL LETTER BAN CHI EUM;;;; +3180;HANGUL LETTER SSANGIEUNG;Lo;0;L; 1147;;;;N;HANGUL LETTER SSANG IEUNG;;;; +3181;HANGUL LETTER YESIEUNG;Lo;0;L; 114C;;;;N;HANGUL LETTER NGIEUNG;;;; +3182;HANGUL LETTER YESIEUNG-SIOS;Lo;0;L; 11F1;;;;N;HANGUL LETTER NGIEUNG SIOS;;;; +3183;HANGUL LETTER YESIEUNG-PANSIOS;Lo;0;L; 11F2;;;;N;HANGUL LETTER NGIEUNG BAN CHI EUM;;;; +3184;HANGUL LETTER KAPYEOUNPHIEUPH;Lo;0;L; 1157;;;;N;HANGUL LETTER PIEUP SUN GYEONG EUM;;;; +3185;HANGUL LETTER SSANGHIEUH;Lo;0;L; 1158;;;;N;HANGUL LETTER SSANG HIEUH;;;; +3186;HANGUL LETTER YEORINHIEUH;Lo;0;L; 1159;;;;N;HANGUL LETTER YEOLIN HIEUH;;;; +3187;HANGUL LETTER YO-YA;Lo;0;L; 1184;;;;N;HANGUL LETTER YOYA;;;; +3188;HANGUL LETTER YO-YAE;Lo;0;L; 1185;;;;N;HANGUL LETTER YOYAE;;;; +3189;HANGUL LETTER YO-I;Lo;0;L; 1188;;;;N;HANGUL LETTER YOI;;;; +318A;HANGUL LETTER YU-YEO;Lo;0;L; 1191;;;;N;HANGUL LETTER YUYEO;;;; +318B;HANGUL LETTER YU-YE;Lo;0;L; 1192;;;;N;HANGUL LETTER YUYE;;;; +318C;HANGUL LETTER YU-I;Lo;0;L; 1194;;;;N;HANGUL LETTER YUI;;;; +318D;HANGUL LETTER ARAEA;Lo;0;L; 119E;;;;N;HANGUL LETTER ALAE A;;;; +318E;HANGUL LETTER ARAEAE;Lo;0;L; 11A1;;;;N;HANGUL LETTER ALAE AE;;;; +3190;IDEOGRAPHIC ANNOTATION LINKING MARK;So;0;L;;;;;N;KANBUN TATETEN;;;; +3191;IDEOGRAPHIC ANNOTATION REVERSE MARK;So;0;L;;;;;N;KAERITEN RE;;;; +3192;IDEOGRAPHIC ANNOTATION ONE MARK;No;0;L; 4E00;;;1;N;KAERITEN ITI;;;; +3193;IDEOGRAPHIC ANNOTATION TWO MARK;No;0;L; 4E8C;;;2;N;KAERITEN NI;;;; +3194;IDEOGRAPHIC ANNOTATION THREE MARK;No;0;L; 4E09;;;3;N;KAERITEN SAN;;;; +3195;IDEOGRAPHIC ANNOTATION FOUR MARK;No;0;L; 56DB;;;4;N;KAERITEN SI;;;; +3196;IDEOGRAPHIC ANNOTATION TOP MARK;So;0;L; 4E0A;;;;N;KAERITEN ZYOU;;;; +3197;IDEOGRAPHIC ANNOTATION MIDDLE MARK;So;0;L; 4E2D;;;;N;KAERITEN TYUU;;;; +3198;IDEOGRAPHIC ANNOTATION BOTTOM MARK;So;0;L; 4E0B;;;;N;KAERITEN GE;;;; +3199;IDEOGRAPHIC ANNOTATION FIRST MARK;So;0;L; 7532;;;;N;KAERITEN KOU;;;; +319A;IDEOGRAPHIC ANNOTATION SECOND MARK;So;0;L; 4E59;;;;N;KAERITEN OTU;;;; +319B;IDEOGRAPHIC ANNOTATION THIRD MARK;So;0;L; 4E19;;;;N;KAERITEN HEI;;;; +319C;IDEOGRAPHIC ANNOTATION FOURTH MARK;So;0;L; 4E01;;;;N;KAERITEN TEI;;;; +319D;IDEOGRAPHIC ANNOTATION HEAVEN MARK;So;0;L; 5929;;;;N;KAERITEN TEN;;;; +319E;IDEOGRAPHIC ANNOTATION EARTH MARK;So;0;L; 5730;;;;N;KAERITEN TI;;;; +319F;IDEOGRAPHIC ANNOTATION MAN MARK;So;0;L; 4EBA;;;;N;KAERITEN ZIN;;;; +31A0;BOPOMOFO LETTER BU;Lo;0;L;;;;;N;;;;; +31A1;BOPOMOFO LETTER ZI;Lo;0;L;;;;;N;;;;; +31A2;BOPOMOFO LETTER JI;Lo;0;L;;;;;N;;;;; +31A3;BOPOMOFO LETTER GU;Lo;0;L;;;;;N;;;;; +31A4;BOPOMOFO LETTER EE;Lo;0;L;;;;;N;;;;; +31A5;BOPOMOFO LETTER ENN;Lo;0;L;;;;;N;;;;; +31A6;BOPOMOFO LETTER OO;Lo;0;L;;;;;N;;;;; +31A7;BOPOMOFO LETTER ONN;Lo;0;L;;;;;N;;;;; +31A8;BOPOMOFO LETTER IR;Lo;0;L;;;;;N;;;;; +31A9;BOPOMOFO LETTER ANN;Lo;0;L;;;;;N;;;;; +31AA;BOPOMOFO LETTER INN;Lo;0;L;;;;;N;;;;; +31AB;BOPOMOFO LETTER UNN;Lo;0;L;;;;;N;;;;; +31AC;BOPOMOFO LETTER IM;Lo;0;L;;;;;N;;;;; +31AD;BOPOMOFO LETTER NGG;Lo;0;L;;;;;N;;;;; +31AE;BOPOMOFO LETTER AINN;Lo;0;L;;;;;N;;;;; +31AF;BOPOMOFO LETTER AUNN;Lo;0;L;;;;;N;;;;; +31B0;BOPOMOFO LETTER AM;Lo;0;L;;;;;N;;;;; +31B1;BOPOMOFO LETTER OM;Lo;0;L;;;;;N;;;;; +31B2;BOPOMOFO LETTER ONG;Lo;0;L;;;;;N;;;;; +31B3;BOPOMOFO LETTER INNN;Lo;0;L;;;;;N;;;;; +31B4;BOPOMOFO FINAL LETTER P;Lo;0;L;;;;;N;;;;; +31B5;BOPOMOFO FINAL LETTER T;Lo;0;L;;;;;N;;;;; +31B6;BOPOMOFO FINAL LETTER K;Lo;0;L;;;;;N;;;;; +31B7;BOPOMOFO FINAL LETTER H;Lo;0;L;;;;;N;;;;; +31B8;BOPOMOFO LETTER GH;Lo;0;L;;;;;N;;;;; +31B9;BOPOMOFO LETTER LH;Lo;0;L;;;;;N;;;;; +31BA;BOPOMOFO LETTER ZY;Lo;0;L;;;;;N;;;;; +31BB;BOPOMOFO FINAL LETTER G;Lo;0;L;;;;;N;;;;; +31BC;BOPOMOFO LETTER GW;Lo;0;L;;;;;N;;;;; +31BD;BOPOMOFO LETTER KW;Lo;0;L;;;;;N;;;;; +31BE;BOPOMOFO LETTER OE;Lo;0;L;;;;;N;;;;; +31BF;BOPOMOFO LETTER AH;Lo;0;L;;;;;N;;;;; +31C0;CJK STROKE T;So;0;ON;;;;;N;;;;; +31C1;CJK STROKE WG;So;0;ON;;;;;N;;;;; +31C2;CJK STROKE XG;So;0;ON;;;;;N;;;;; +31C3;CJK STROKE BXG;So;0;ON;;;;;N;;;;; +31C4;CJK STROKE SW;So;0;ON;;;;;N;;;;; +31C5;CJK STROKE HZZ;So;0;ON;;;;;N;;;;; +31C6;CJK STROKE HZG;So;0;ON;;;;;N;;;;; +31C7;CJK STROKE HP;So;0;ON;;;;;N;;;;; +31C8;CJK STROKE HZWG;So;0;ON;;;;;N;;;;; +31C9;CJK STROKE SZWG;So;0;ON;;;;;N;;;;; +31CA;CJK STROKE HZT;So;0;ON;;;;;N;;;;; +31CB;CJK STROKE HZZP;So;0;ON;;;;;N;;;;; +31CC;CJK STROKE HPWG;So;0;ON;;;;;N;;;;; +31CD;CJK STROKE HZW;So;0;ON;;;;;N;;;;; +31CE;CJK STROKE HZZZ;So;0;ON;;;;;N;;;;; +31CF;CJK STROKE N;So;0;ON;;;;;N;;;;; +31D0;CJK STROKE H;So;0;ON;;;;;N;;;;; +31D1;CJK STROKE S;So;0;ON;;;;;N;;;;; +31D2;CJK STROKE P;So;0;ON;;;;;N;;;;; +31D3;CJK STROKE SP;So;0;ON;;;;;N;;;;; +31D4;CJK STROKE D;So;0;ON;;;;;N;;;;; +31D5;CJK STROKE HZ;So;0;ON;;;;;N;;;;; +31D6;CJK STROKE HG;So;0;ON;;;;;N;;;;; +31D7;CJK STROKE SZ;So;0;ON;;;;;N;;;;; +31D8;CJK STROKE SWZ;So;0;ON;;;;;N;;;;; +31D9;CJK STROKE ST;So;0;ON;;;;;N;;;;; +31DA;CJK STROKE SG;So;0;ON;;;;;N;;;;; +31DB;CJK STROKE PD;So;0;ON;;;;;N;;;;; +31DC;CJK STROKE PZ;So;0;ON;;;;;N;;;;; +31DD;CJK STROKE TN;So;0;ON;;;;;N;;;;; +31DE;CJK STROKE SZZ;So;0;ON;;;;;N;;;;; +31DF;CJK STROKE SWG;So;0;ON;;;;;N;;;;; +31E0;CJK STROKE HXWG;So;0;ON;;;;;N;;;;; +31E1;CJK STROKE HZZZG;So;0;ON;;;;;N;;;;; +31E2;CJK STROKE PG;So;0;ON;;;;;N;;;;; +31E3;CJK STROKE Q;So;0;ON;;;;;N;;;;; +31E4;CJK STROKE HXG;So;0;ON;;;;;N;;;;; +31E5;CJK STROKE SZP;So;0;ON;;;;;N;;;;; +31EF;IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION;So;0;ON;;;;;N;;;;; +31F0;KATAKANA LETTER SMALL KU;Lo;0;L;;;;;N;;;;; +31F1;KATAKANA LETTER SMALL SI;Lo;0;L;;;;;N;;;;; +31F2;KATAKANA LETTER SMALL SU;Lo;0;L;;;;;N;;;;; +31F3;KATAKANA LETTER SMALL TO;Lo;0;L;;;;;N;;;;; +31F4;KATAKANA LETTER SMALL NU;Lo;0;L;;;;;N;;;;; +31F5;KATAKANA LETTER SMALL HA;Lo;0;L;;;;;N;;;;; +31F6;KATAKANA LETTER SMALL HI;Lo;0;L;;;;;N;;;;; +31F7;KATAKANA LETTER SMALL HU;Lo;0;L;;;;;N;;;;; +31F8;KATAKANA LETTER SMALL HE;Lo;0;L;;;;;N;;;;; +31F9;KATAKANA LETTER SMALL HO;Lo;0;L;;;;;N;;;;; +31FA;KATAKANA LETTER SMALL MU;Lo;0;L;;;;;N;;;;; +31FB;KATAKANA LETTER SMALL RA;Lo;0;L;;;;;N;;;;; +31FC;KATAKANA LETTER SMALL RI;Lo;0;L;;;;;N;;;;; +31FD;KATAKANA LETTER SMALL RU;Lo;0;L;;;;;N;;;;; +31FE;KATAKANA LETTER SMALL RE;Lo;0;L;;;;;N;;;;; +31FF;KATAKANA LETTER SMALL RO;Lo;0;L;;;;;N;;;;; +3200;PARENTHESIZED HANGUL KIYEOK;So;0;L; 0028 1100 0029;;;;N;PARENTHESIZED HANGUL GIYEOG;;;; +3201;PARENTHESIZED HANGUL NIEUN;So;0;L; 0028 1102 0029;;;;N;;;;; +3202;PARENTHESIZED HANGUL TIKEUT;So;0;L; 0028 1103 0029;;;;N;PARENTHESIZED HANGUL DIGEUD;;;; +3203;PARENTHESIZED HANGUL RIEUL;So;0;L; 0028 1105 0029;;;;N;PARENTHESIZED HANGUL LIEUL;;;; +3204;PARENTHESIZED HANGUL MIEUM;So;0;L; 0028 1106 0029;;;;N;;;;; +3205;PARENTHESIZED HANGUL PIEUP;So;0;L; 0028 1107 0029;;;;N;PARENTHESIZED HANGUL BIEUB;;;; +3206;PARENTHESIZED HANGUL SIOS;So;0;L; 0028 1109 0029;;;;N;;;;; +3207;PARENTHESIZED HANGUL IEUNG;So;0;L; 0028 110B 0029;;;;N;;;;; +3208;PARENTHESIZED HANGUL CIEUC;So;0;L; 0028 110C 0029;;;;N;PARENTHESIZED HANGUL JIEUJ;;;; +3209;PARENTHESIZED HANGUL CHIEUCH;So;0;L; 0028 110E 0029;;;;N;PARENTHESIZED HANGUL CIEUC;;;; +320A;PARENTHESIZED HANGUL KHIEUKH;So;0;L; 0028 110F 0029;;;;N;PARENTHESIZED HANGUL KIYEOK;;;; +320B;PARENTHESIZED HANGUL THIEUTH;So;0;L; 0028 1110 0029;;;;N;PARENTHESIZED HANGUL TIEUT;;;; +320C;PARENTHESIZED HANGUL PHIEUPH;So;0;L; 0028 1111 0029;;;;N;PARENTHESIZED HANGUL PIEUP;;;; +320D;PARENTHESIZED HANGUL HIEUH;So;0;L; 0028 1112 0029;;;;N;;;;; +320E;PARENTHESIZED HANGUL KIYEOK A;So;0;L; 0028 1100 1161 0029;;;;N;PARENTHESIZED HANGUL GA;;;; +320F;PARENTHESIZED HANGUL NIEUN A;So;0;L; 0028 1102 1161 0029;;;;N;PARENTHESIZED HANGUL NA;;;; +3210;PARENTHESIZED HANGUL TIKEUT A;So;0;L; 0028 1103 1161 0029;;;;N;PARENTHESIZED HANGUL DA;;;; +3211;PARENTHESIZED HANGUL RIEUL A;So;0;L; 0028 1105 1161 0029;;;;N;PARENTHESIZED HANGUL LA;;;; +3212;PARENTHESIZED HANGUL MIEUM A;So;0;L; 0028 1106 1161 0029;;;;N;PARENTHESIZED HANGUL MA;;;; +3213;PARENTHESIZED HANGUL PIEUP A;So;0;L; 0028 1107 1161 0029;;;;N;PARENTHESIZED HANGUL BA;;;; +3214;PARENTHESIZED HANGUL SIOS A;So;0;L; 0028 1109 1161 0029;;;;N;PARENTHESIZED HANGUL SA;;;; +3215;PARENTHESIZED HANGUL IEUNG A;So;0;L; 0028 110B 1161 0029;;;;N;PARENTHESIZED HANGUL A;;;; +3216;PARENTHESIZED HANGUL CIEUC A;So;0;L; 0028 110C 1161 0029;;;;N;PARENTHESIZED HANGUL JA;;;; +3217;PARENTHESIZED HANGUL CHIEUCH A;So;0;L; 0028 110E 1161 0029;;;;N;PARENTHESIZED HANGUL CA;;;; +3218;PARENTHESIZED HANGUL KHIEUKH A;So;0;L; 0028 110F 1161 0029;;;;N;PARENTHESIZED HANGUL KA;;;; +3219;PARENTHESIZED HANGUL THIEUTH A;So;0;L; 0028 1110 1161 0029;;;;N;PARENTHESIZED HANGUL TA;;;; +321A;PARENTHESIZED HANGUL PHIEUPH A;So;0;L; 0028 1111 1161 0029;;;;N;PARENTHESIZED HANGUL PA;;;; +321B;PARENTHESIZED HANGUL HIEUH A;So;0;L; 0028 1112 1161 0029;;;;N;PARENTHESIZED HANGUL HA;;;; +321C;PARENTHESIZED HANGUL CIEUC U;So;0;L; 0028 110C 116E 0029;;;;N;PARENTHESIZED HANGUL JU;;;; +321D;PARENTHESIZED KOREAN CHARACTER OJEON;So;0;ON; 0028 110B 1169 110C 1165 11AB 0029;;;;N;;;;; +321E;PARENTHESIZED KOREAN CHARACTER O HU;So;0;ON; 0028 110B 1169 1112 116E 0029;;;;N;;;;; +3220;PARENTHESIZED IDEOGRAPH ONE;No;0;L; 0028 4E00 0029;;;1;N;;;;; +3221;PARENTHESIZED IDEOGRAPH TWO;No;0;L; 0028 4E8C 0029;;;2;N;;;;; +3222;PARENTHESIZED IDEOGRAPH THREE;No;0;L; 0028 4E09 0029;;;3;N;;;;; +3223;PARENTHESIZED IDEOGRAPH FOUR;No;0;L; 0028 56DB 0029;;;4;N;;;;; +3224;PARENTHESIZED IDEOGRAPH FIVE;No;0;L; 0028 4E94 0029;;;5;N;;;;; +3225;PARENTHESIZED IDEOGRAPH SIX;No;0;L; 0028 516D 0029;;;6;N;;;;; +3226;PARENTHESIZED IDEOGRAPH SEVEN;No;0;L; 0028 4E03 0029;;;7;N;;;;; +3227;PARENTHESIZED IDEOGRAPH EIGHT;No;0;L; 0028 516B 0029;;;8;N;;;;; +3228;PARENTHESIZED IDEOGRAPH NINE;No;0;L; 0028 4E5D 0029;;;9;N;;;;; +3229;PARENTHESIZED IDEOGRAPH TEN;No;0;L; 0028 5341 0029;;;10;N;;;;; +322A;PARENTHESIZED IDEOGRAPH MOON;So;0;L; 0028 6708 0029;;;;N;;;;; +322B;PARENTHESIZED IDEOGRAPH FIRE;So;0;L; 0028 706B 0029;;;;N;;;;; +322C;PARENTHESIZED IDEOGRAPH WATER;So;0;L; 0028 6C34 0029;;;;N;;;;; +322D;PARENTHESIZED IDEOGRAPH WOOD;So;0;L; 0028 6728 0029;;;;N;;;;; +322E;PARENTHESIZED IDEOGRAPH METAL;So;0;L; 0028 91D1 0029;;;;N;;;;; +322F;PARENTHESIZED IDEOGRAPH EARTH;So;0;L; 0028 571F 0029;;;;N;;;;; +3230;PARENTHESIZED IDEOGRAPH SUN;So;0;L; 0028 65E5 0029;;;;N;;;;; +3231;PARENTHESIZED IDEOGRAPH STOCK;So;0;L; 0028 682A 0029;;;;N;;;;; +3232;PARENTHESIZED IDEOGRAPH HAVE;So;0;L; 0028 6709 0029;;;;N;;;;; +3233;PARENTHESIZED IDEOGRAPH SOCIETY;So;0;L; 0028 793E 0029;;;;N;;;;; +3234;PARENTHESIZED IDEOGRAPH NAME;So;0;L; 0028 540D 0029;;;;N;;;;; +3235;PARENTHESIZED IDEOGRAPH SPECIAL;So;0;L; 0028 7279 0029;;;;N;;;;; +3236;PARENTHESIZED IDEOGRAPH FINANCIAL;So;0;L; 0028 8CA1 0029;;;;N;;;;; +3237;PARENTHESIZED IDEOGRAPH CONGRATULATION;So;0;L; 0028 795D 0029;;;;N;;;;; +3238;PARENTHESIZED IDEOGRAPH LABOR;So;0;L; 0028 52B4 0029;;;;N;;;;; +3239;PARENTHESIZED IDEOGRAPH REPRESENT;So;0;L; 0028 4EE3 0029;;;;N;;;;; +323A;PARENTHESIZED IDEOGRAPH CALL;So;0;L; 0028 547C 0029;;;;N;;;;; +323B;PARENTHESIZED IDEOGRAPH STUDY;So;0;L; 0028 5B66 0029;;;;N;;;;; +323C;PARENTHESIZED IDEOGRAPH SUPERVISE;So;0;L; 0028 76E3 0029;;;;N;;;;; +323D;PARENTHESIZED IDEOGRAPH ENTERPRISE;So;0;L; 0028 4F01 0029;;;;N;;;;; +323E;PARENTHESIZED IDEOGRAPH RESOURCE;So;0;L; 0028 8CC7 0029;;;;N;;;;; +323F;PARENTHESIZED IDEOGRAPH ALLIANCE;So;0;L; 0028 5354 0029;;;;N;;;;; +3240;PARENTHESIZED IDEOGRAPH FESTIVAL;So;0;L; 0028 796D 0029;;;;N;;;;; +3241;PARENTHESIZED IDEOGRAPH REST;So;0;L; 0028 4F11 0029;;;;N;;;;; +3242;PARENTHESIZED IDEOGRAPH SELF;So;0;L; 0028 81EA 0029;;;;N;;;;; +3243;PARENTHESIZED IDEOGRAPH REACH;So;0;L; 0028 81F3 0029;;;;N;;;;; +3244;CIRCLED IDEOGRAPH QUESTION;So;0;L; 554F;;;;N;;;;; +3245;CIRCLED IDEOGRAPH KINDERGARTEN;So;0;L; 5E7C;;;;N;;;;; +3246;CIRCLED IDEOGRAPH SCHOOL;So;0;L; 6587;;;;N;;;;; +3247;CIRCLED IDEOGRAPH KOTO;So;0;L; 7B8F;;;;N;;;;; +3248;CIRCLED NUMBER TEN ON BLACK SQUARE;No;0;L;;;;10;N;;;;; +3249;CIRCLED NUMBER TWENTY ON BLACK SQUARE;No;0;L;;;;20;N;;;;; +324A;CIRCLED NUMBER THIRTY ON BLACK SQUARE;No;0;L;;;;30;N;;;;; +324B;CIRCLED NUMBER FORTY ON BLACK SQUARE;No;0;L;;;;40;N;;;;; +324C;CIRCLED NUMBER FIFTY ON BLACK SQUARE;No;0;L;;;;50;N;;;;; +324D;CIRCLED NUMBER SIXTY ON BLACK SQUARE;No;0;L;;;;60;N;;;;; +324E;CIRCLED NUMBER SEVENTY ON BLACK SQUARE;No;0;L;;;;70;N;;;;; +324F;CIRCLED NUMBER EIGHTY ON BLACK SQUARE;No;0;L;;;;80;N;;;;; +3250;PARTNERSHIP SIGN;So;0;ON; 0050 0054 0045;;;;N;;;;; +3251;CIRCLED NUMBER TWENTY ONE;No;0;ON; 0032 0031;;;21;N;;;;; +3252;CIRCLED NUMBER TWENTY TWO;No;0;ON; 0032 0032;;;22;N;;;;; +3253;CIRCLED NUMBER TWENTY THREE;No;0;ON; 0032 0033;;;23;N;;;;; +3254;CIRCLED NUMBER TWENTY FOUR;No;0;ON; 0032 0034;;;24;N;;;;; +3255;CIRCLED NUMBER TWENTY FIVE;No;0;ON; 0032 0035;;;25;N;;;;; +3256;CIRCLED NUMBER TWENTY SIX;No;0;ON; 0032 0036;;;26;N;;;;; +3257;CIRCLED NUMBER TWENTY SEVEN;No;0;ON; 0032 0037;;;27;N;;;;; +3258;CIRCLED NUMBER TWENTY EIGHT;No;0;ON; 0032 0038;;;28;N;;;;; +3259;CIRCLED NUMBER TWENTY NINE;No;0;ON; 0032 0039;;;29;N;;;;; +325A;CIRCLED NUMBER THIRTY;No;0;ON; 0033 0030;;;30;N;;;;; +325B;CIRCLED NUMBER THIRTY ONE;No;0;ON; 0033 0031;;;31;N;;;;; +325C;CIRCLED NUMBER THIRTY TWO;No;0;ON; 0033 0032;;;32;N;;;;; +325D;CIRCLED NUMBER THIRTY THREE;No;0;ON; 0033 0033;;;33;N;;;;; +325E;CIRCLED NUMBER THIRTY FOUR;No;0;ON; 0033 0034;;;34;N;;;;; +325F;CIRCLED NUMBER THIRTY FIVE;No;0;ON; 0033 0035;;;35;N;;;;; +3260;CIRCLED HANGUL KIYEOK;So;0;L; 1100;;;;N;CIRCLED HANGUL GIYEOG;;;; +3261;CIRCLED HANGUL NIEUN;So;0;L; 1102;;;;N;;;;; +3262;CIRCLED HANGUL TIKEUT;So;0;L; 1103;;;;N;CIRCLED HANGUL DIGEUD;;;; +3263;CIRCLED HANGUL RIEUL;So;0;L; 1105;;;;N;CIRCLED HANGUL LIEUL;;;; +3264;CIRCLED HANGUL MIEUM;So;0;L; 1106;;;;N;;;;; +3265;CIRCLED HANGUL PIEUP;So;0;L; 1107;;;;N;CIRCLED HANGUL BIEUB;;;; +3266;CIRCLED HANGUL SIOS;So;0;L; 1109;;;;N;;;;; +3267;CIRCLED HANGUL IEUNG;So;0;L; 110B;;;;N;;;;; +3268;CIRCLED HANGUL CIEUC;So;0;L; 110C;;;;N;CIRCLED HANGUL JIEUJ;;;; +3269;CIRCLED HANGUL CHIEUCH;So;0;L; 110E;;;;N;CIRCLED HANGUL CIEUC;;;; +326A;CIRCLED HANGUL KHIEUKH;So;0;L; 110F;;;;N;CIRCLED HANGUL KIYEOK;;;; +326B;CIRCLED HANGUL THIEUTH;So;0;L; 1110;;;;N;CIRCLED HANGUL TIEUT;;;; +326C;CIRCLED HANGUL PHIEUPH;So;0;L; 1111;;;;N;CIRCLED HANGUL PIEUP;;;; +326D;CIRCLED HANGUL HIEUH;So;0;L; 1112;;;;N;;;;; +326E;CIRCLED HANGUL KIYEOK A;So;0;L; 1100 1161;;;;N;CIRCLED HANGUL GA;;;; +326F;CIRCLED HANGUL NIEUN A;So;0;L; 1102 1161;;;;N;CIRCLED HANGUL NA;;;; +3270;CIRCLED HANGUL TIKEUT A;So;0;L; 1103 1161;;;;N;CIRCLED HANGUL DA;;;; +3271;CIRCLED HANGUL RIEUL A;So;0;L; 1105 1161;;;;N;CIRCLED HANGUL LA;;;; +3272;CIRCLED HANGUL MIEUM A;So;0;L; 1106 1161;;;;N;CIRCLED HANGUL MA;;;; +3273;CIRCLED HANGUL PIEUP A;So;0;L; 1107 1161;;;;N;CIRCLED HANGUL BA;;;; +3274;CIRCLED HANGUL SIOS A;So;0;L; 1109 1161;;;;N;CIRCLED HANGUL SA;;;; +3275;CIRCLED HANGUL IEUNG A;So;0;L; 110B 1161;;;;N;CIRCLED HANGUL A;;;; +3276;CIRCLED HANGUL CIEUC A;So;0;L; 110C 1161;;;;N;CIRCLED HANGUL JA;;;; +3277;CIRCLED HANGUL CHIEUCH A;So;0;L; 110E 1161;;;;N;CIRCLED HANGUL CA;;;; +3278;CIRCLED HANGUL KHIEUKH A;So;0;L; 110F 1161;;;;N;CIRCLED HANGUL KA;;;; +3279;CIRCLED HANGUL THIEUTH A;So;0;L; 1110 1161;;;;N;CIRCLED HANGUL TA;;;; +327A;CIRCLED HANGUL PHIEUPH A;So;0;L; 1111 1161;;;;N;CIRCLED HANGUL PA;;;; +327B;CIRCLED HANGUL HIEUH A;So;0;L; 1112 1161;;;;N;CIRCLED HANGUL HA;;;; +327C;CIRCLED KOREAN CHARACTER CHAMKO;So;0;ON; 110E 1161 11B7 1100 1169;;;;N;;;;; +327D;CIRCLED KOREAN CHARACTER JUEUI;So;0;ON; 110C 116E 110B 1174;;;;N;;;;; +327E;CIRCLED HANGUL IEUNG U;So;0;ON; 110B 116E;;;;N;;;;; +327F;KOREAN STANDARD SYMBOL;So;0;L;;;;;N;;;;; +3280;CIRCLED IDEOGRAPH ONE;No;0;L; 4E00;;;1;N;;;;; +3281;CIRCLED IDEOGRAPH TWO;No;0;L; 4E8C;;;2;N;;;;; +3282;CIRCLED IDEOGRAPH THREE;No;0;L; 4E09;;;3;N;;;;; +3283;CIRCLED IDEOGRAPH FOUR;No;0;L; 56DB;;;4;N;;;;; +3284;CIRCLED IDEOGRAPH FIVE;No;0;L; 4E94;;;5;N;;;;; +3285;CIRCLED IDEOGRAPH SIX;No;0;L; 516D;;;6;N;;;;; +3286;CIRCLED IDEOGRAPH SEVEN;No;0;L; 4E03;;;7;N;;;;; +3287;CIRCLED IDEOGRAPH EIGHT;No;0;L; 516B;;;8;N;;;;; +3288;CIRCLED IDEOGRAPH NINE;No;0;L; 4E5D;;;9;N;;;;; +3289;CIRCLED IDEOGRAPH TEN;No;0;L; 5341;;;10;N;;;;; +328A;CIRCLED IDEOGRAPH MOON;So;0;L; 6708;;;;N;;;;; +328B;CIRCLED IDEOGRAPH FIRE;So;0;L; 706B;;;;N;;;;; +328C;CIRCLED IDEOGRAPH WATER;So;0;L; 6C34;;;;N;;;;; +328D;CIRCLED IDEOGRAPH WOOD;So;0;L; 6728;;;;N;;;;; +328E;CIRCLED IDEOGRAPH METAL;So;0;L; 91D1;;;;N;;;;; +328F;CIRCLED IDEOGRAPH EARTH;So;0;L; 571F;;;;N;;;;; +3290;CIRCLED IDEOGRAPH SUN;So;0;L; 65E5;;;;N;;;;; +3291;CIRCLED IDEOGRAPH STOCK;So;0;L; 682A;;;;N;;;;; +3292;CIRCLED IDEOGRAPH HAVE;So;0;L; 6709;;;;N;;;;; +3293;CIRCLED IDEOGRAPH SOCIETY;So;0;L; 793E;;;;N;;;;; +3294;CIRCLED IDEOGRAPH NAME;So;0;L; 540D;;;;N;;;;; +3295;CIRCLED IDEOGRAPH SPECIAL;So;0;L; 7279;;;;N;;;;; +3296;CIRCLED IDEOGRAPH FINANCIAL;So;0;L; 8CA1;;;;N;;;;; +3297;CIRCLED IDEOGRAPH CONGRATULATION;So;0;L; 795D;;;;N;;;;; +3298;CIRCLED IDEOGRAPH LABOR;So;0;L; 52B4;;;;N;;;;; +3299;CIRCLED IDEOGRAPH SECRET;So;0;L; 79D8;;;;N;;;;; +329A;CIRCLED IDEOGRAPH MALE;So;0;L; 7537;;;;N;;;;; +329B;CIRCLED IDEOGRAPH FEMALE;So;0;L; 5973;;;;N;;;;; +329C;CIRCLED IDEOGRAPH SUITABLE;So;0;L; 9069;;;;N;;;;; +329D;CIRCLED IDEOGRAPH EXCELLENT;So;0;L; 512A;;;;N;;;;; +329E;CIRCLED IDEOGRAPH PRINT;So;0;L; 5370;;;;N;;;;; +329F;CIRCLED IDEOGRAPH ATTENTION;So;0;L; 6CE8;;;;N;;;;; +32A0;CIRCLED IDEOGRAPH ITEM;So;0;L; 9805;;;;N;;;;; +32A1;CIRCLED IDEOGRAPH REST;So;0;L; 4F11;;;;N;;;;; +32A2;CIRCLED IDEOGRAPH COPY;So;0;L; 5199;;;;N;;;;; +32A3;CIRCLED IDEOGRAPH CORRECT;So;0;L; 6B63;;;;N;;;;; +32A4;CIRCLED IDEOGRAPH HIGH;So;0;L; 4E0A;;;;N;;;;; +32A5;CIRCLED IDEOGRAPH CENTRE;So;0;L; 4E2D;;;;N;CIRCLED IDEOGRAPH CENTER;;;; +32A6;CIRCLED IDEOGRAPH LOW;So;0;L; 4E0B;;;;N;;;;; +32A7;CIRCLED IDEOGRAPH LEFT;So;0;L; 5DE6;;;;N;;;;; +32A8;CIRCLED IDEOGRAPH RIGHT;So;0;L; 53F3;;;;N;;;;; +32A9;CIRCLED IDEOGRAPH MEDICINE;So;0;L; 533B;;;;N;;;;; +32AA;CIRCLED IDEOGRAPH RELIGION;So;0;L; 5B97;;;;N;;;;; +32AB;CIRCLED IDEOGRAPH STUDY;So;0;L; 5B66;;;;N;;;;; +32AC;CIRCLED IDEOGRAPH SUPERVISE;So;0;L; 76E3;;;;N;;;;; +32AD;CIRCLED IDEOGRAPH ENTERPRISE;So;0;L; 4F01;;;;N;;;;; +32AE;CIRCLED IDEOGRAPH RESOURCE;So;0;L; 8CC7;;;;N;;;;; +32AF;CIRCLED IDEOGRAPH ALLIANCE;So;0;L; 5354;;;;N;;;;; +32B0;CIRCLED IDEOGRAPH NIGHT;So;0;L; 591C;;;;N;;;;; +32B1;CIRCLED NUMBER THIRTY SIX;No;0;ON; 0033 0036;;;36;N;;;;; +32B2;CIRCLED NUMBER THIRTY SEVEN;No;0;ON; 0033 0037;;;37;N;;;;; +32B3;CIRCLED NUMBER THIRTY EIGHT;No;0;ON; 0033 0038;;;38;N;;;;; +32B4;CIRCLED NUMBER THIRTY NINE;No;0;ON; 0033 0039;;;39;N;;;;; +32B5;CIRCLED NUMBER FORTY;No;0;ON; 0034 0030;;;40;N;;;;; +32B6;CIRCLED NUMBER FORTY ONE;No;0;ON; 0034 0031;;;41;N;;;;; +32B7;CIRCLED NUMBER FORTY TWO;No;0;ON; 0034 0032;;;42;N;;;;; +32B8;CIRCLED NUMBER FORTY THREE;No;0;ON; 0034 0033;;;43;N;;;;; +32B9;CIRCLED NUMBER FORTY FOUR;No;0;ON; 0034 0034;;;44;N;;;;; +32BA;CIRCLED NUMBER FORTY FIVE;No;0;ON; 0034 0035;;;45;N;;;;; +32BB;CIRCLED NUMBER FORTY SIX;No;0;ON; 0034 0036;;;46;N;;;;; +32BC;CIRCLED NUMBER FORTY SEVEN;No;0;ON; 0034 0037;;;47;N;;;;; +32BD;CIRCLED NUMBER FORTY EIGHT;No;0;ON; 0034 0038;;;48;N;;;;; +32BE;CIRCLED NUMBER FORTY NINE;No;0;ON; 0034 0039;;;49;N;;;;; +32BF;CIRCLED NUMBER FIFTY;No;0;ON; 0035 0030;;;50;N;;;;; +32C0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY;So;0;L; 0031 6708;;;;N;;;;; +32C1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY;So;0;L; 0032 6708;;;;N;;;;; +32C2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH;So;0;L; 0033 6708;;;;N;;;;; +32C3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL;So;0;L; 0034 6708;;;;N;;;;; +32C4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY;So;0;L; 0035 6708;;;;N;;;;; +32C5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE;So;0;L; 0036 6708;;;;N;;;;; +32C6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY;So;0;L; 0037 6708;;;;N;;;;; +32C7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST;So;0;L; 0038 6708;;;;N;;;;; +32C8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER;So;0;L; 0039 6708;;;;N;;;;; +32C9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER;So;0;L; 0031 0030 6708;;;;N;;;;; +32CA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER;So;0;L; 0031 0031 6708;;;;N;;;;; +32CB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER;So;0;L; 0031 0032 6708;;;;N;;;;; +32CC;SQUARE HG;So;0;ON; 0048 0067;;;;N;;;;; +32CD;SQUARE ERG;So;0;ON; 0065 0072 0067;;;;N;;;;; +32CE;SQUARE EV;So;0;ON; 0065 0056;;;;N;;;;; +32CF;LIMITED LIABILITY SIGN;So;0;ON; 004C 0054 0044;;;;N;;;;; +32D0;CIRCLED KATAKANA A;So;0;L; 30A2;;;;N;;;;; +32D1;CIRCLED KATAKANA I;So;0;L; 30A4;;;;N;;;;; +32D2;CIRCLED KATAKANA U;So;0;L; 30A6;;;;N;;;;; +32D3;CIRCLED KATAKANA E;So;0;L; 30A8;;;;N;;;;; +32D4;CIRCLED KATAKANA O;So;0;L; 30AA;;;;N;;;;; +32D5;CIRCLED KATAKANA KA;So;0;L; 30AB;;;;N;;;;; +32D6;CIRCLED KATAKANA KI;So;0;L; 30AD;;;;N;;;;; +32D7;CIRCLED KATAKANA KU;So;0;L; 30AF;;;;N;;;;; +32D8;CIRCLED KATAKANA KE;So;0;L; 30B1;;;;N;;;;; +32D9;CIRCLED KATAKANA KO;So;0;L; 30B3;;;;N;;;;; +32DA;CIRCLED KATAKANA SA;So;0;L; 30B5;;;;N;;;;; +32DB;CIRCLED KATAKANA SI;So;0;L; 30B7;;;;N;;;;; +32DC;CIRCLED KATAKANA SU;So;0;L; 30B9;;;;N;;;;; +32DD;CIRCLED KATAKANA SE;So;0;L; 30BB;;;;N;;;;; +32DE;CIRCLED KATAKANA SO;So;0;L; 30BD;;;;N;;;;; +32DF;CIRCLED KATAKANA TA;So;0;L; 30BF;;;;N;;;;; +32E0;CIRCLED KATAKANA TI;So;0;L; 30C1;;;;N;;;;; +32E1;CIRCLED KATAKANA TU;So;0;L; 30C4;;;;N;;;;; +32E2;CIRCLED KATAKANA TE;So;0;L; 30C6;;;;N;;;;; +32E3;CIRCLED KATAKANA TO;So;0;L; 30C8;;;;N;;;;; +32E4;CIRCLED KATAKANA NA;So;0;L; 30CA;;;;N;;;;; +32E5;CIRCLED KATAKANA NI;So;0;L; 30CB;;;;N;;;;; +32E6;CIRCLED KATAKANA NU;So;0;L; 30CC;;;;N;;;;; +32E7;CIRCLED KATAKANA NE;So;0;L; 30CD;;;;N;;;;; +32E8;CIRCLED KATAKANA NO;So;0;L; 30CE;;;;N;;;;; +32E9;CIRCLED KATAKANA HA;So;0;L; 30CF;;;;N;;;;; +32EA;CIRCLED KATAKANA HI;So;0;L; 30D2;;;;N;;;;; +32EB;CIRCLED KATAKANA HU;So;0;L; 30D5;;;;N;;;;; +32EC;CIRCLED KATAKANA HE;So;0;L; 30D8;;;;N;;;;; +32ED;CIRCLED KATAKANA HO;So;0;L; 30DB;;;;N;;;;; +32EE;CIRCLED KATAKANA MA;So;0;L; 30DE;;;;N;;;;; +32EF;CIRCLED KATAKANA MI;So;0;L; 30DF;;;;N;;;;; +32F0;CIRCLED KATAKANA MU;So;0;L; 30E0;;;;N;;;;; +32F1;CIRCLED KATAKANA ME;So;0;L; 30E1;;;;N;;;;; +32F2;CIRCLED KATAKANA MO;So;0;L; 30E2;;;;N;;;;; +32F3;CIRCLED KATAKANA YA;So;0;L; 30E4;;;;N;;;;; +32F4;CIRCLED KATAKANA YU;So;0;L; 30E6;;;;N;;;;; +32F5;CIRCLED KATAKANA YO;So;0;L; 30E8;;;;N;;;;; +32F6;CIRCLED KATAKANA RA;So;0;L; 30E9;;;;N;;;;; +32F7;CIRCLED KATAKANA RI;So;0;L; 30EA;;;;N;;;;; +32F8;CIRCLED KATAKANA RU;So;0;L; 30EB;;;;N;;;;; +32F9;CIRCLED KATAKANA RE;So;0;L; 30EC;;;;N;;;;; +32FA;CIRCLED KATAKANA RO;So;0;L; 30ED;;;;N;;;;; +32FB;CIRCLED KATAKANA WA;So;0;L; 30EF;;;;N;;;;; +32FC;CIRCLED KATAKANA WI;So;0;L; 30F0;;;;N;;;;; +32FD;CIRCLED KATAKANA WE;So;0;L; 30F1;;;;N;;;;; +32FE;CIRCLED KATAKANA WO;So;0;L; 30F2;;;;N;;;;; +32FF;SQUARE ERA NAME REIWA;So;0;L; 4EE4 548C;;;;N;;;;; +3300;SQUARE APAATO;So;0;L; 30A2 30D1 30FC 30C8;;;;N;SQUARED APAATO;;;; +3301;SQUARE ARUHUA;So;0;L; 30A2 30EB 30D5 30A1;;;;N;SQUARED ARUHUA;;;; +3302;SQUARE ANPEA;So;0;L; 30A2 30F3 30DA 30A2;;;;N;SQUARED ANPEA;;;; +3303;SQUARE AARU;So;0;L; 30A2 30FC 30EB;;;;N;SQUARED AARU;;;; +3304;SQUARE ININGU;So;0;L; 30A4 30CB 30F3 30B0;;;;N;SQUARED ININGU;;;; +3305;SQUARE INTI;So;0;L; 30A4 30F3 30C1;;;;N;SQUARED INTI;;;; +3306;SQUARE UON;So;0;L; 30A6 30A9 30F3;;;;N;SQUARED UON;;;; +3307;SQUARE ESUKUUDO;So;0;L; 30A8 30B9 30AF 30FC 30C9;;;;N;SQUARED ESUKUUDO;;;; +3308;SQUARE EEKAA;So;0;L; 30A8 30FC 30AB 30FC;;;;N;SQUARED EEKAA;;;; +3309;SQUARE ONSU;So;0;L; 30AA 30F3 30B9;;;;N;SQUARED ONSU;;;; +330A;SQUARE OOMU;So;0;L; 30AA 30FC 30E0;;;;N;SQUARED OOMU;;;; +330B;SQUARE KAIRI;So;0;L; 30AB 30A4 30EA;;;;N;SQUARED KAIRI;;;; +330C;SQUARE KARATTO;So;0;L; 30AB 30E9 30C3 30C8;;;;N;SQUARED KARATTO;;;; +330D;SQUARE KARORII;So;0;L; 30AB 30ED 30EA 30FC;;;;N;SQUARED KARORII;;;; +330E;SQUARE GARON;So;0;L; 30AC 30ED 30F3;;;;N;SQUARED GARON;;;; +330F;SQUARE GANMA;So;0;L; 30AC 30F3 30DE;;;;N;SQUARED GANMA;;;; +3310;SQUARE GIGA;So;0;L; 30AE 30AC;;;;N;SQUARED GIGA;;;; +3311;SQUARE GINII;So;0;L; 30AE 30CB 30FC;;;;N;SQUARED GINII;;;; +3312;SQUARE KYURII;So;0;L; 30AD 30E5 30EA 30FC;;;;N;SQUARED KYURII;;;; +3313;SQUARE GIRUDAA;So;0;L; 30AE 30EB 30C0 30FC;;;;N;SQUARED GIRUDAA;;;; +3314;SQUARE KIRO;So;0;L; 30AD 30ED;;;;N;SQUARED KIRO;;;; +3315;SQUARE KIROGURAMU;So;0;L; 30AD 30ED 30B0 30E9 30E0;;;;N;SQUARED KIROGURAMU;;;; +3316;SQUARE KIROMEETORU;So;0;L; 30AD 30ED 30E1 30FC 30C8 30EB;;;;N;SQUARED KIROMEETORU;;;; +3317;SQUARE KIROWATTO;So;0;L; 30AD 30ED 30EF 30C3 30C8;;;;N;SQUARED KIROWATTO;;;; +3318;SQUARE GURAMU;So;0;L; 30B0 30E9 30E0;;;;N;SQUARED GURAMU;;;; +3319;SQUARE GURAMUTON;So;0;L; 30B0 30E9 30E0 30C8 30F3;;;;N;SQUARED GURAMUTON;;;; +331A;SQUARE KURUZEIRO;So;0;L; 30AF 30EB 30BC 30A4 30ED;;;;N;SQUARED KURUZEIRO;;;; +331B;SQUARE KUROONE;So;0;L; 30AF 30ED 30FC 30CD;;;;N;SQUARED KUROONE;;;; +331C;SQUARE KEESU;So;0;L; 30B1 30FC 30B9;;;;N;SQUARED KEESU;;;; +331D;SQUARE KORUNA;So;0;L; 30B3 30EB 30CA;;;;N;SQUARED KORUNA;;;; +331E;SQUARE KOOPO;So;0;L; 30B3 30FC 30DD;;;;N;SQUARED KOOPO;;;; +331F;SQUARE SAIKURU;So;0;L; 30B5 30A4 30AF 30EB;;;;N;SQUARED SAIKURU;;;; +3320;SQUARE SANTIIMU;So;0;L; 30B5 30F3 30C1 30FC 30E0;;;;N;SQUARED SANTIIMU;;;; +3321;SQUARE SIRINGU;So;0;L; 30B7 30EA 30F3 30B0;;;;N;SQUARED SIRINGU;;;; +3322;SQUARE SENTI;So;0;L; 30BB 30F3 30C1;;;;N;SQUARED SENTI;;;; +3323;SQUARE SENTO;So;0;L; 30BB 30F3 30C8;;;;N;SQUARED SENTO;;;; +3324;SQUARE DAASU;So;0;L; 30C0 30FC 30B9;;;;N;SQUARED DAASU;;;; +3325;SQUARE DESI;So;0;L; 30C7 30B7;;;;N;SQUARED DESI;;;; +3326;SQUARE DORU;So;0;L; 30C9 30EB;;;;N;SQUARED DORU;;;; +3327;SQUARE TON;So;0;L; 30C8 30F3;;;;N;SQUARED TON;;;; +3328;SQUARE NANO;So;0;L; 30CA 30CE;;;;N;SQUARED NANO;;;; +3329;SQUARE NOTTO;So;0;L; 30CE 30C3 30C8;;;;N;SQUARED NOTTO;;;; +332A;SQUARE HAITU;So;0;L; 30CF 30A4 30C4;;;;N;SQUARED HAITU;;;; +332B;SQUARE PAASENTO;So;0;L; 30D1 30FC 30BB 30F3 30C8;;;;N;SQUARED PAASENTO;;;; +332C;SQUARE PAATU;So;0;L; 30D1 30FC 30C4;;;;N;SQUARED PAATU;;;; +332D;SQUARE BAARERU;So;0;L; 30D0 30FC 30EC 30EB;;;;N;SQUARED BAARERU;;;; +332E;SQUARE PIASUTORU;So;0;L; 30D4 30A2 30B9 30C8 30EB;;;;N;SQUARED PIASUTORU;;;; +332F;SQUARE PIKURU;So;0;L; 30D4 30AF 30EB;;;;N;SQUARED PIKURU;;;; +3330;SQUARE PIKO;So;0;L; 30D4 30B3;;;;N;SQUARED PIKO;;;; +3331;SQUARE BIRU;So;0;L; 30D3 30EB;;;;N;SQUARED BIRU;;;; +3332;SQUARE HUARADDO;So;0;L; 30D5 30A1 30E9 30C3 30C9;;;;N;SQUARED HUARADDO;;;; +3333;SQUARE HUIITO;So;0;L; 30D5 30A3 30FC 30C8;;;;N;SQUARED HUIITO;;;; +3334;SQUARE BUSSYERU;So;0;L; 30D6 30C3 30B7 30A7 30EB;;;;N;SQUARED BUSSYERU;;;; +3335;SQUARE HURAN;So;0;L; 30D5 30E9 30F3;;;;N;SQUARED HURAN;;;; +3336;SQUARE HEKUTAARU;So;0;L; 30D8 30AF 30BF 30FC 30EB;;;;N;SQUARED HEKUTAARU;;;; +3337;SQUARE PESO;So;0;L; 30DA 30BD;;;;N;SQUARED PESO;;;; +3338;SQUARE PENIHI;So;0;L; 30DA 30CB 30D2;;;;N;SQUARED PENIHI;;;; +3339;SQUARE HERUTU;So;0;L; 30D8 30EB 30C4;;;;N;SQUARED HERUTU;;;; +333A;SQUARE PENSU;So;0;L; 30DA 30F3 30B9;;;;N;SQUARED PENSU;;;; +333B;SQUARE PEEZI;So;0;L; 30DA 30FC 30B8;;;;N;SQUARED PEEZI;;;; +333C;SQUARE BEETA;So;0;L; 30D9 30FC 30BF;;;;N;SQUARED BEETA;;;; +333D;SQUARE POINTO;So;0;L; 30DD 30A4 30F3 30C8;;;;N;SQUARED POINTO;;;; +333E;SQUARE BORUTO;So;0;L; 30DC 30EB 30C8;;;;N;SQUARED BORUTO;;;; +333F;SQUARE HON;So;0;L; 30DB 30F3;;;;N;SQUARED HON;;;; +3340;SQUARE PONDO;So;0;L; 30DD 30F3 30C9;;;;N;SQUARED PONDO;;;; +3341;SQUARE HOORU;So;0;L; 30DB 30FC 30EB;;;;N;SQUARED HOORU;;;; +3342;SQUARE HOON;So;0;L; 30DB 30FC 30F3;;;;N;SQUARED HOON;;;; +3343;SQUARE MAIKURO;So;0;L; 30DE 30A4 30AF 30ED;;;;N;SQUARED MAIKURO;;;; +3344;SQUARE MAIRU;So;0;L; 30DE 30A4 30EB;;;;N;SQUARED MAIRU;;;; +3345;SQUARE MAHHA;So;0;L; 30DE 30C3 30CF;;;;N;SQUARED MAHHA;;;; +3346;SQUARE MARUKU;So;0;L; 30DE 30EB 30AF;;;;N;SQUARED MARUKU;;;; +3347;SQUARE MANSYON;So;0;L; 30DE 30F3 30B7 30E7 30F3;;;;N;SQUARED MANSYON;;;; +3348;SQUARE MIKURON;So;0;L; 30DF 30AF 30ED 30F3;;;;N;SQUARED MIKURON;;;; +3349;SQUARE MIRI;So;0;L; 30DF 30EA;;;;N;SQUARED MIRI;;;; +334A;SQUARE MIRIBAARU;So;0;L; 30DF 30EA 30D0 30FC 30EB;;;;N;SQUARED MIRIBAARU;;;; +334B;SQUARE MEGA;So;0;L; 30E1 30AC;;;;N;SQUARED MEGA;;;; +334C;SQUARE MEGATON;So;0;L; 30E1 30AC 30C8 30F3;;;;N;SQUARED MEGATON;;;; +334D;SQUARE MEETORU;So;0;L; 30E1 30FC 30C8 30EB;;;;N;SQUARED MEETORU;;;; +334E;SQUARE YAADO;So;0;L; 30E4 30FC 30C9;;;;N;SQUARED YAADO;;;; +334F;SQUARE YAARU;So;0;L; 30E4 30FC 30EB;;;;N;SQUARED YAARU;;;; +3350;SQUARE YUAN;So;0;L; 30E6 30A2 30F3;;;;N;SQUARED YUAN;;;; +3351;SQUARE RITTORU;So;0;L; 30EA 30C3 30C8 30EB;;;;N;SQUARED RITTORU;;;; +3352;SQUARE RIRA;So;0;L; 30EA 30E9;;;;N;SQUARED RIRA;;;; +3353;SQUARE RUPII;So;0;L; 30EB 30D4 30FC;;;;N;SQUARED RUPII;;;; +3354;SQUARE RUUBURU;So;0;L; 30EB 30FC 30D6 30EB;;;;N;SQUARED RUUBURU;;;; +3355;SQUARE REMU;So;0;L; 30EC 30E0;;;;N;SQUARED REMU;;;; +3356;SQUARE RENTOGEN;So;0;L; 30EC 30F3 30C8 30B2 30F3;;;;N;SQUARED RENTOGEN;;;; +3357;SQUARE WATTO;So;0;L; 30EF 30C3 30C8;;;;N;SQUARED WATTO;;;; +3358;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO;So;0;L; 0030 70B9;;;;N;;;;; +3359;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE;So;0;L; 0031 70B9;;;;N;;;;; +335A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO;So;0;L; 0032 70B9;;;;N;;;;; +335B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE;So;0;L; 0033 70B9;;;;N;;;;; +335C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR;So;0;L; 0034 70B9;;;;N;;;;; +335D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE;So;0;L; 0035 70B9;;;;N;;;;; +335E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX;So;0;L; 0036 70B9;;;;N;;;;; +335F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN;So;0;L; 0037 70B9;;;;N;;;;; +3360;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT;So;0;L; 0038 70B9;;;;N;;;;; +3361;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE;So;0;L; 0039 70B9;;;;N;;;;; +3362;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN;So;0;L; 0031 0030 70B9;;;;N;;;;; +3363;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN;So;0;L; 0031 0031 70B9;;;;N;;;;; +3364;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE;So;0;L; 0031 0032 70B9;;;;N;;;;; +3365;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN;So;0;L; 0031 0033 70B9;;;;N;;;;; +3366;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN;So;0;L; 0031 0034 70B9;;;;N;;;;; +3367;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN;So;0;L; 0031 0035 70B9;;;;N;;;;; +3368;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN;So;0;L; 0031 0036 70B9;;;;N;;;;; +3369;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN;So;0;L; 0031 0037 70B9;;;;N;;;;; +336A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN;So;0;L; 0031 0038 70B9;;;;N;;;;; +336B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN;So;0;L; 0031 0039 70B9;;;;N;;;;; +336C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY;So;0;L; 0032 0030 70B9;;;;N;;;;; +336D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE;So;0;L; 0032 0031 70B9;;;;N;;;;; +336E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO;So;0;L; 0032 0032 70B9;;;;N;;;;; +336F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE;So;0;L; 0032 0033 70B9;;;;N;;;;; +3370;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR;So;0;L; 0032 0034 70B9;;;;N;;;;; +3371;SQUARE HPA;So;0;L; 0068 0050 0061;;;;N;;;;; +3372;SQUARE DA;So;0;L; 0064 0061;;;;N;;;;; +3373;SQUARE AU;So;0;L; 0041 0055;;;;N;;;;; +3374;SQUARE BAR;So;0;L; 0062 0061 0072;;;;N;;;;; +3375;SQUARE OV;So;0;L; 006F 0056;;;;N;;;;; +3376;SQUARE PC;So;0;L; 0070 0063;;;;N;;;;; +3377;SQUARE DM;So;0;ON; 0064 006D;;;;N;;;;; +3378;SQUARE DM SQUARED;So;0;ON; 0064 006D 00B2;;;;N;;;;; +3379;SQUARE DM CUBED;So;0;ON; 0064 006D 00B3;;;;N;;;;; +337A;SQUARE IU;So;0;ON; 0049 0055;;;;N;;;;; +337B;SQUARE ERA NAME HEISEI;So;0;L; 5E73 6210;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME HEISEI;;;; +337C;SQUARE ERA NAME SYOUWA;So;0;L; 662D 548C;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME SYOUWA;;;; +337D;SQUARE ERA NAME TAISYOU;So;0;L; 5927 6B63;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME TAISYOU;;;; +337E;SQUARE ERA NAME MEIZI;So;0;L; 660E 6CBB;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME MEIZI;;;; +337F;SQUARE CORPORATION;So;0;L; 682A 5F0F 4F1A 793E;;;;N;SQUARED FOUR IDEOGRAPHS CORPORATION;;;; +3380;SQUARE PA AMPS;So;0;L; 0070 0041;;;;N;SQUARED PA AMPS;;;; +3381;SQUARE NA;So;0;L; 006E 0041;;;;N;SQUARED NA;;;; +3382;SQUARE MU A;So;0;L; 03BC 0041;;;;N;SQUARED MU A;;;; +3383;SQUARE MA;So;0;L; 006D 0041;;;;N;SQUARED MA;;;; +3384;SQUARE KA;So;0;L; 006B 0041;;;;N;SQUARED KA;;;; +3385;SQUARE KB;So;0;L; 004B 0042;;;;N;SQUARED KB;;;; +3386;SQUARE MB;So;0;L; 004D 0042;;;;N;SQUARED MB;;;; +3387;SQUARE GB;So;0;L; 0047 0042;;;;N;SQUARED GB;;;; +3388;SQUARE CAL;So;0;L; 0063 0061 006C;;;;N;SQUARED CAL;;;; +3389;SQUARE KCAL;So;0;L; 006B 0063 0061 006C;;;;N;SQUARED KCAL;;;; +338A;SQUARE PF;So;0;L; 0070 0046;;;;N;SQUARED PF;;;; +338B;SQUARE NF;So;0;L; 006E 0046;;;;N;SQUARED NF;;;; +338C;SQUARE MU F;So;0;L; 03BC 0046;;;;N;SQUARED MU F;;;; +338D;SQUARE MU G;So;0;L; 03BC 0067;;;;N;SQUARED MU G;;;; +338E;SQUARE MG;So;0;L; 006D 0067;;;;N;SQUARED MG;;;; +338F;SQUARE KG;So;0;L; 006B 0067;;;;N;SQUARED KG;;;; +3390;SQUARE HZ;So;0;L; 0048 007A;;;;N;SQUARED HZ;;;; +3391;SQUARE KHZ;So;0;L; 006B 0048 007A;;;;N;SQUARED KHZ;;;; +3392;SQUARE MHZ;So;0;L; 004D 0048 007A;;;;N;SQUARED MHZ;;;; +3393;SQUARE GHZ;So;0;L; 0047 0048 007A;;;;N;SQUARED GHZ;;;; +3394;SQUARE THZ;So;0;L; 0054 0048 007A;;;;N;SQUARED THZ;;;; +3395;SQUARE MU L;So;0;L; 03BC 2113;;;;N;SQUARED MU L;;;; +3396;SQUARE ML;So;0;L; 006D 2113;;;;N;SQUARED ML;;;; +3397;SQUARE DL;So;0;L; 0064 2113;;;;N;SQUARED DL;;;; +3398;SQUARE KL;So;0;L; 006B 2113;;;;N;SQUARED KL;;;; +3399;SQUARE FM;So;0;L; 0066 006D;;;;N;SQUARED FM;;;; +339A;SQUARE NM;So;0;L; 006E 006D;;;;N;SQUARED NM;;;; +339B;SQUARE MU M;So;0;L; 03BC 006D;;;;N;SQUARED MU M;;;; +339C;SQUARE MM;So;0;L; 006D 006D;;;;N;SQUARED MM;;;; +339D;SQUARE CM;So;0;L; 0063 006D;;;;N;SQUARED CM;;;; +339E;SQUARE KM;So;0;L; 006B 006D;;;;N;SQUARED KM;;;; +339F;SQUARE MM SQUARED;So;0;L; 006D 006D 00B2;;;;N;SQUARED MM SQUARED;;;; +33A0;SQUARE CM SQUARED;So;0;L; 0063 006D 00B2;;;;N;SQUARED CM SQUARED;;;; +33A1;SQUARE M SQUARED;So;0;L; 006D 00B2;;;;N;SQUARED M SQUARED;;;; +33A2;SQUARE KM SQUARED;So;0;L; 006B 006D 00B2;;;;N;SQUARED KM SQUARED;;;; +33A3;SQUARE MM CUBED;So;0;L; 006D 006D 00B3;;;;N;SQUARED MM CUBED;;;; +33A4;SQUARE CM CUBED;So;0;L; 0063 006D 00B3;;;;N;SQUARED CM CUBED;;;; +33A5;SQUARE M CUBED;So;0;L; 006D 00B3;;;;N;SQUARED M CUBED;;;; +33A6;SQUARE KM CUBED;So;0;L; 006B 006D 00B3;;;;N;SQUARED KM CUBED;;;; +33A7;SQUARE M OVER S;So;0;L; 006D 2215 0073;;;;N;SQUARED M OVER S;;;; +33A8;SQUARE M OVER S SQUARED;So;0;L; 006D 2215 0073 00B2;;;;N;SQUARED M OVER S SQUARED;;;; +33A9;SQUARE PA;So;0;L; 0050 0061;;;;N;SQUARED PA;;;; +33AA;SQUARE KPA;So;0;L; 006B 0050 0061;;;;N;SQUARED KPA;;;; +33AB;SQUARE MPA;So;0;L; 004D 0050 0061;;;;N;SQUARED MPA;;;; +33AC;SQUARE GPA;So;0;L; 0047 0050 0061;;;;N;SQUARED GPA;;;; +33AD;SQUARE RAD;So;0;L; 0072 0061 0064;;;;N;SQUARED RAD;;;; +33AE;SQUARE RAD OVER S;So;0;L; 0072 0061 0064 2215 0073;;;;N;SQUARED RAD OVER S;;;; +33AF;SQUARE RAD OVER S SQUARED;So;0;L; 0072 0061 0064 2215 0073 00B2;;;;N;SQUARED RAD OVER S SQUARED;;;; +33B0;SQUARE PS;So;0;L; 0070 0073;;;;N;SQUARED PS;;;; +33B1;SQUARE NS;So;0;L; 006E 0073;;;;N;SQUARED NS;;;; +33B2;SQUARE MU S;So;0;L; 03BC 0073;;;;N;SQUARED MU S;;;; +33B3;SQUARE MS;So;0;L; 006D 0073;;;;N;SQUARED MS;;;; +33B4;SQUARE PV;So;0;L; 0070 0056;;;;N;SQUARED PV;;;; +33B5;SQUARE NV;So;0;L; 006E 0056;;;;N;SQUARED NV;;;; +33B6;SQUARE MU V;So;0;L; 03BC 0056;;;;N;SQUARED MU V;;;; +33B7;SQUARE MV;So;0;L; 006D 0056;;;;N;SQUARED MV;;;; +33B8;SQUARE KV;So;0;L; 006B 0056;;;;N;SQUARED KV;;;; +33B9;SQUARE MV MEGA;So;0;L; 004D 0056;;;;N;SQUARED MV MEGA;;;; +33BA;SQUARE PW;So;0;L; 0070 0057;;;;N;SQUARED PW;;;; +33BB;SQUARE NW;So;0;L; 006E 0057;;;;N;SQUARED NW;;;; +33BC;SQUARE MU W;So;0;L; 03BC 0057;;;;N;SQUARED MU W;;;; +33BD;SQUARE MW;So;0;L; 006D 0057;;;;N;SQUARED MW;;;; +33BE;SQUARE KW;So;0;L; 006B 0057;;;;N;SQUARED KW;;;; +33BF;SQUARE MW MEGA;So;0;L; 004D 0057;;;;N;SQUARED MW MEGA;;;; +33C0;SQUARE K OHM;So;0;L; 006B 03A9;;;;N;SQUARED K OHM;;;; +33C1;SQUARE M OHM;So;0;L; 004D 03A9;;;;N;SQUARED M OHM;;;; +33C2;SQUARE AM;So;0;L; 0061 002E 006D 002E;;;;N;SQUARED AM;;;; +33C3;SQUARE BQ;So;0;L; 0042 0071;;;;N;SQUARED BQ;;;; +33C4;SQUARE CC;So;0;L; 0063 0063;;;;N;SQUARED CC;;;; +33C5;SQUARE CD;So;0;L; 0063 0064;;;;N;SQUARED CD;;;; +33C6;SQUARE C OVER KG;So;0;L; 0043 2215 006B 0067;;;;N;SQUARED C OVER KG;;;; +33C7;SQUARE CO;So;0;L; 0043 006F 002E;;;;N;SQUARED CO;;;; +33C8;SQUARE DB;So;0;L; 0064 0042;;;;N;SQUARED DB;;;; +33C9;SQUARE GY;So;0;L; 0047 0079;;;;N;SQUARED GY;;;; +33CA;SQUARE HA;So;0;L; 0068 0061;;;;N;SQUARED HA;;;; +33CB;SQUARE HP;So;0;L; 0048 0050;;;;N;SQUARED HP;;;; +33CC;SQUARE IN;So;0;L; 0069 006E;;;;N;SQUARED IN;;;; +33CD;SQUARE KK;So;0;L; 004B 004B;;;;N;SQUARED KK;;;; +33CE;SQUARE KM CAPITAL;So;0;L; 004B 004D;;;;N;SQUARED KM CAPITAL;;;; +33CF;SQUARE KT;So;0;L; 006B 0074;;;;N;SQUARED KT;;;; +33D0;SQUARE LM;So;0;L; 006C 006D;;;;N;SQUARED LM;;;; +33D1;SQUARE LN;So;0;L; 006C 006E;;;;N;SQUARED LN;;;; +33D2;SQUARE LOG;So;0;L; 006C 006F 0067;;;;N;SQUARED LOG;;;; +33D3;SQUARE LX;So;0;L; 006C 0078;;;;N;SQUARED LX;;;; +33D4;SQUARE MB SMALL;So;0;L; 006D 0062;;;;N;SQUARED MB SMALL;;;; +33D5;SQUARE MIL;So;0;L; 006D 0069 006C;;;;N;SQUARED MIL;;;; +33D6;SQUARE MOL;So;0;L; 006D 006F 006C;;;;N;SQUARED MOL;;;; +33D7;SQUARE PH;So;0;L; 0050 0048;;;;N;SQUARED PH;;;; +33D8;SQUARE PM;So;0;L; 0070 002E 006D 002E;;;;N;SQUARED PM;;;; +33D9;SQUARE PPM;So;0;L; 0050 0050 004D;;;;N;SQUARED PPM;;;; +33DA;SQUARE PR;So;0;L; 0050 0052;;;;N;SQUARED PR;;;; +33DB;SQUARE SR;So;0;L; 0073 0072;;;;N;SQUARED SR;;;; +33DC;SQUARE SV;So;0;L; 0053 0076;;;;N;SQUARED SV;;;; +33DD;SQUARE WB;So;0;L; 0057 0062;;;;N;SQUARED WB;;;; +33DE;SQUARE V OVER M;So;0;ON; 0056 2215 006D;;;;N;;;;; +33DF;SQUARE A OVER M;So;0;ON; 0041 2215 006D;;;;N;;;;; +33E0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE;So;0;L; 0031 65E5;;;;N;;;;; +33E1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO;So;0;L; 0032 65E5;;;;N;;;;; +33E2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE;So;0;L; 0033 65E5;;;;N;;;;; +33E3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR;So;0;L; 0034 65E5;;;;N;;;;; +33E4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE;So;0;L; 0035 65E5;;;;N;;;;; +33E5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX;So;0;L; 0036 65E5;;;;N;;;;; +33E6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN;So;0;L; 0037 65E5;;;;N;;;;; +33E7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT;So;0;L; 0038 65E5;;;;N;;;;; +33E8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE;So;0;L; 0039 65E5;;;;N;;;;; +33E9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN;So;0;L; 0031 0030 65E5;;;;N;;;;; +33EA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN;So;0;L; 0031 0031 65E5;;;;N;;;;; +33EB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE;So;0;L; 0031 0032 65E5;;;;N;;;;; +33EC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN;So;0;L; 0031 0033 65E5;;;;N;;;;; +33ED;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN;So;0;L; 0031 0034 65E5;;;;N;;;;; +33EE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN;So;0;L; 0031 0035 65E5;;;;N;;;;; +33EF;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN;So;0;L; 0031 0036 65E5;;;;N;;;;; +33F0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN;So;0;L; 0031 0037 65E5;;;;N;;;;; +33F1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN;So;0;L; 0031 0038 65E5;;;;N;;;;; +33F2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN;So;0;L; 0031 0039 65E5;;;;N;;;;; +33F3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY;So;0;L; 0032 0030 65E5;;;;N;;;;; +33F4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE;So;0;L; 0032 0031 65E5;;;;N;;;;; +33F5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO;So;0;L; 0032 0032 65E5;;;;N;;;;; +33F6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE;So;0;L; 0032 0033 65E5;;;;N;;;;; +33F7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR;So;0;L; 0032 0034 65E5;;;;N;;;;; +33F8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE;So;0;L; 0032 0035 65E5;;;;N;;;;; +33F9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX;So;0;L; 0032 0036 65E5;;;;N;;;;; +33FA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN;So;0;L; 0032 0037 65E5;;;;N;;;;; +33FB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT;So;0;L; 0032 0038 65E5;;;;N;;;;; +33FC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE;So;0;L; 0032 0039 65E5;;;;N;;;;; +33FD;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY;So;0;L; 0033 0030 65E5;;;;N;;;;; +33FE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE;So;0;L; 0033 0031 65E5;;;;N;;;;; +33FF;SQUARE GAL;So;0;ON; 0067 0061 006C;;;;N;;;;; +3400;;Lo;0;L;;;;;N;;;;; +4DBF;;Lo;0;L;;;;;N;;;;; +4DC0;HEXAGRAM FOR THE CREATIVE HEAVEN;So;0;ON;;;;;N;;;;; +4DC1;HEXAGRAM FOR THE RECEPTIVE EARTH;So;0;ON;;;;;N;;;;; +4DC2;HEXAGRAM FOR DIFFICULTY AT THE BEGINNING;So;0;ON;;;;;N;;;;; +4DC3;HEXAGRAM FOR YOUTHFUL FOLLY;So;0;ON;;;;;N;;;;; +4DC4;HEXAGRAM FOR WAITING;So;0;ON;;;;;N;;;;; +4DC5;HEXAGRAM FOR CONFLICT;So;0;ON;;;;;N;;;;; +4DC6;HEXAGRAM FOR THE ARMY;So;0;ON;;;;;N;;;;; +4DC7;HEXAGRAM FOR HOLDING TOGETHER;So;0;ON;;;;;N;;;;; +4DC8;HEXAGRAM FOR SMALL TAMING;So;0;ON;;;;;N;;;;; +4DC9;HEXAGRAM FOR TREADING;So;0;ON;;;;;N;;;;; +4DCA;HEXAGRAM FOR PEACE;So;0;ON;;;;;N;;;;; +4DCB;HEXAGRAM FOR STANDSTILL;So;0;ON;;;;;N;;;;; +4DCC;HEXAGRAM FOR FELLOWSHIP;So;0;ON;;;;;N;;;;; +4DCD;HEXAGRAM FOR GREAT POSSESSION;So;0;ON;;;;;N;;;;; +4DCE;HEXAGRAM FOR MODESTY;So;0;ON;;;;;N;;;;; +4DCF;HEXAGRAM FOR ENTHUSIASM;So;0;ON;;;;;N;;;;; +4DD0;HEXAGRAM FOR FOLLOWING;So;0;ON;;;;;N;;;;; +4DD1;HEXAGRAM FOR WORK ON THE DECAYED;So;0;ON;;;;;N;;;;; +4DD2;HEXAGRAM FOR APPROACH;So;0;ON;;;;;N;;;;; +4DD3;HEXAGRAM FOR CONTEMPLATION;So;0;ON;;;;;N;;;;; +4DD4;HEXAGRAM FOR BITING THROUGH;So;0;ON;;;;;N;;;;; +4DD5;HEXAGRAM FOR GRACE;So;0;ON;;;;;N;;;;; +4DD6;HEXAGRAM FOR SPLITTING APART;So;0;ON;;;;;N;;;;; +4DD7;HEXAGRAM FOR RETURN;So;0;ON;;;;;N;;;;; +4DD8;HEXAGRAM FOR INNOCENCE;So;0;ON;;;;;N;;;;; +4DD9;HEXAGRAM FOR GREAT TAMING;So;0;ON;;;;;N;;;;; +4DDA;HEXAGRAM FOR MOUTH CORNERS;So;0;ON;;;;;N;;;;; +4DDB;HEXAGRAM FOR GREAT PREPONDERANCE;So;0;ON;;;;;N;;;;; +4DDC;HEXAGRAM FOR THE ABYSMAL WATER;So;0;ON;;;;;N;;;;; +4DDD;HEXAGRAM FOR THE CLINGING FIRE;So;0;ON;;;;;N;;;;; +4DDE;HEXAGRAM FOR INFLUENCE;So;0;ON;;;;;N;;;;; +4DDF;HEXAGRAM FOR DURATION;So;0;ON;;;;;N;;;;; +4DE0;HEXAGRAM FOR RETREAT;So;0;ON;;;;;N;;;;; +4DE1;HEXAGRAM FOR GREAT POWER;So;0;ON;;;;;N;;;;; +4DE2;HEXAGRAM FOR PROGRESS;So;0;ON;;;;;N;;;;; +4DE3;HEXAGRAM FOR DARKENING OF THE LIGHT;So;0;ON;;;;;N;;;;; +4DE4;HEXAGRAM FOR THE FAMILY;So;0;ON;;;;;N;;;;; +4DE5;HEXAGRAM FOR OPPOSITION;So;0;ON;;;;;N;;;;; +4DE6;HEXAGRAM FOR OBSTRUCTION;So;0;ON;;;;;N;;;;; +4DE7;HEXAGRAM FOR DELIVERANCE;So;0;ON;;;;;N;;;;; +4DE8;HEXAGRAM FOR DECREASE;So;0;ON;;;;;N;;;;; +4DE9;HEXAGRAM FOR INCREASE;So;0;ON;;;;;N;;;;; +4DEA;HEXAGRAM FOR BREAKTHROUGH;So;0;ON;;;;;N;;;;; +4DEB;HEXAGRAM FOR COMING TO MEET;So;0;ON;;;;;N;;;;; +4DEC;HEXAGRAM FOR GATHERING TOGETHER;So;0;ON;;;;;N;;;;; +4DED;HEXAGRAM FOR PUSHING UPWARD;So;0;ON;;;;;N;;;;; +4DEE;HEXAGRAM FOR OPPRESSION;So;0;ON;;;;;N;;;;; +4DEF;HEXAGRAM FOR THE WELL;So;0;ON;;;;;N;;;;; +4DF0;HEXAGRAM FOR REVOLUTION;So;0;ON;;;;;N;;;;; +4DF1;HEXAGRAM FOR THE CAULDRON;So;0;ON;;;;;N;;;;; +4DF2;HEXAGRAM FOR THE AROUSING THUNDER;So;0;ON;;;;;N;;;;; +4DF3;HEXAGRAM FOR THE KEEPING STILL MOUNTAIN;So;0;ON;;;;;N;;;;; +4DF4;HEXAGRAM FOR DEVELOPMENT;So;0;ON;;;;;N;;;;; +4DF5;HEXAGRAM FOR THE MARRYING MAIDEN;So;0;ON;;;;;N;;;;; +4DF6;HEXAGRAM FOR ABUNDANCE;So;0;ON;;;;;N;;;;; +4DF7;HEXAGRAM FOR THE WANDERER;So;0;ON;;;;;N;;;;; +4DF8;HEXAGRAM FOR THE GENTLE WIND;So;0;ON;;;;;N;;;;; +4DF9;HEXAGRAM FOR THE JOYOUS LAKE;So;0;ON;;;;;N;;;;; +4DFA;HEXAGRAM FOR DISPERSION;So;0;ON;;;;;N;;;;; +4DFB;HEXAGRAM FOR LIMITATION;So;0;ON;;;;;N;;;;; +4DFC;HEXAGRAM FOR INNER TRUTH;So;0;ON;;;;;N;;;;; +4DFD;HEXAGRAM FOR SMALL PREPONDERANCE;So;0;ON;;;;;N;;;;; +4DFE;HEXAGRAM FOR AFTER COMPLETION;So;0;ON;;;;;N;;;;; +4DFF;HEXAGRAM FOR BEFORE COMPLETION;So;0;ON;;;;;N;;;;; +4E00;;Lo;0;L;;;;;N;;;;; +9FFF;;Lo;0;L;;;;;N;;;;; +A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;; +A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;; +A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;; +A003;YI SYLLABLE IP;Lo;0;L;;;;;N;;;;; +A004;YI SYLLABLE IET;Lo;0;L;;;;;N;;;;; +A005;YI SYLLABLE IEX;Lo;0;L;;;;;N;;;;; +A006;YI SYLLABLE IE;Lo;0;L;;;;;N;;;;; +A007;YI SYLLABLE IEP;Lo;0;L;;;;;N;;;;; +A008;YI SYLLABLE AT;Lo;0;L;;;;;N;;;;; +A009;YI SYLLABLE AX;Lo;0;L;;;;;N;;;;; +A00A;YI SYLLABLE A;Lo;0;L;;;;;N;;;;; +A00B;YI SYLLABLE AP;Lo;0;L;;;;;N;;;;; +A00C;YI SYLLABLE UOX;Lo;0;L;;;;;N;;;;; +A00D;YI SYLLABLE UO;Lo;0;L;;;;;N;;;;; +A00E;YI SYLLABLE UOP;Lo;0;L;;;;;N;;;;; +A00F;YI SYLLABLE OT;Lo;0;L;;;;;N;;;;; +A010;YI SYLLABLE OX;Lo;0;L;;;;;N;;;;; +A011;YI SYLLABLE O;Lo;0;L;;;;;N;;;;; +A012;YI SYLLABLE OP;Lo;0;L;;;;;N;;;;; +A013;YI SYLLABLE EX;Lo;0;L;;;;;N;;;;; +A014;YI SYLLABLE E;Lo;0;L;;;;;N;;;;; +A015;YI SYLLABLE WU;Lm;0;L;;;;;N;;;;; +A016;YI SYLLABLE BIT;Lo;0;L;;;;;N;;;;; +A017;YI SYLLABLE BIX;Lo;0;L;;;;;N;;;;; +A018;YI SYLLABLE BI;Lo;0;L;;;;;N;;;;; +A019;YI SYLLABLE BIP;Lo;0;L;;;;;N;;;;; +A01A;YI SYLLABLE BIET;Lo;0;L;;;;;N;;;;; +A01B;YI SYLLABLE BIEX;Lo;0;L;;;;;N;;;;; +A01C;YI SYLLABLE BIE;Lo;0;L;;;;;N;;;;; +A01D;YI SYLLABLE BIEP;Lo;0;L;;;;;N;;;;; +A01E;YI SYLLABLE BAT;Lo;0;L;;;;;N;;;;; +A01F;YI SYLLABLE BAX;Lo;0;L;;;;;N;;;;; +A020;YI SYLLABLE BA;Lo;0;L;;;;;N;;;;; +A021;YI SYLLABLE BAP;Lo;0;L;;;;;N;;;;; +A022;YI SYLLABLE BUOX;Lo;0;L;;;;;N;;;;; +A023;YI SYLLABLE BUO;Lo;0;L;;;;;N;;;;; +A024;YI SYLLABLE BUOP;Lo;0;L;;;;;N;;;;; +A025;YI SYLLABLE BOT;Lo;0;L;;;;;N;;;;; +A026;YI SYLLABLE BOX;Lo;0;L;;;;;N;;;;; +A027;YI SYLLABLE BO;Lo;0;L;;;;;N;;;;; +A028;YI SYLLABLE BOP;Lo;0;L;;;;;N;;;;; +A029;YI SYLLABLE BEX;Lo;0;L;;;;;N;;;;; +A02A;YI SYLLABLE BE;Lo;0;L;;;;;N;;;;; +A02B;YI SYLLABLE BEP;Lo;0;L;;;;;N;;;;; +A02C;YI SYLLABLE BUT;Lo;0;L;;;;;N;;;;; +A02D;YI SYLLABLE BUX;Lo;0;L;;;;;N;;;;; +A02E;YI SYLLABLE BU;Lo;0;L;;;;;N;;;;; +A02F;YI SYLLABLE BUP;Lo;0;L;;;;;N;;;;; +A030;YI SYLLABLE BURX;Lo;0;L;;;;;N;;;;; +A031;YI SYLLABLE BUR;Lo;0;L;;;;;N;;;;; +A032;YI SYLLABLE BYT;Lo;0;L;;;;;N;;;;; +A033;YI SYLLABLE BYX;Lo;0;L;;;;;N;;;;; +A034;YI SYLLABLE BY;Lo;0;L;;;;;N;;;;; +A035;YI SYLLABLE BYP;Lo;0;L;;;;;N;;;;; +A036;YI SYLLABLE BYRX;Lo;0;L;;;;;N;;;;; +A037;YI SYLLABLE BYR;Lo;0;L;;;;;N;;;;; +A038;YI SYLLABLE PIT;Lo;0;L;;;;;N;;;;; +A039;YI SYLLABLE PIX;Lo;0;L;;;;;N;;;;; +A03A;YI SYLLABLE PI;Lo;0;L;;;;;N;;;;; +A03B;YI SYLLABLE PIP;Lo;0;L;;;;;N;;;;; +A03C;YI SYLLABLE PIEX;Lo;0;L;;;;;N;;;;; +A03D;YI SYLLABLE PIE;Lo;0;L;;;;;N;;;;; +A03E;YI SYLLABLE PIEP;Lo;0;L;;;;;N;;;;; +A03F;YI SYLLABLE PAT;Lo;0;L;;;;;N;;;;; +A040;YI SYLLABLE PAX;Lo;0;L;;;;;N;;;;; +A041;YI SYLLABLE PA;Lo;0;L;;;;;N;;;;; +A042;YI SYLLABLE PAP;Lo;0;L;;;;;N;;;;; +A043;YI SYLLABLE PUOX;Lo;0;L;;;;;N;;;;; +A044;YI SYLLABLE PUO;Lo;0;L;;;;;N;;;;; +A045;YI SYLLABLE PUOP;Lo;0;L;;;;;N;;;;; +A046;YI SYLLABLE POT;Lo;0;L;;;;;N;;;;; +A047;YI SYLLABLE POX;Lo;0;L;;;;;N;;;;; +A048;YI SYLLABLE PO;Lo;0;L;;;;;N;;;;; +A049;YI SYLLABLE POP;Lo;0;L;;;;;N;;;;; +A04A;YI SYLLABLE PUT;Lo;0;L;;;;;N;;;;; +A04B;YI SYLLABLE PUX;Lo;0;L;;;;;N;;;;; +A04C;YI SYLLABLE PU;Lo;0;L;;;;;N;;;;; +A04D;YI SYLLABLE PUP;Lo;0;L;;;;;N;;;;; +A04E;YI SYLLABLE PURX;Lo;0;L;;;;;N;;;;; +A04F;YI SYLLABLE PUR;Lo;0;L;;;;;N;;;;; +A050;YI SYLLABLE PYT;Lo;0;L;;;;;N;;;;; +A051;YI SYLLABLE PYX;Lo;0;L;;;;;N;;;;; +A052;YI SYLLABLE PY;Lo;0;L;;;;;N;;;;; +A053;YI SYLLABLE PYP;Lo;0;L;;;;;N;;;;; +A054;YI SYLLABLE PYRX;Lo;0;L;;;;;N;;;;; +A055;YI SYLLABLE PYR;Lo;0;L;;;;;N;;;;; +A056;YI SYLLABLE BBIT;Lo;0;L;;;;;N;;;;; +A057;YI SYLLABLE BBIX;Lo;0;L;;;;;N;;;;; +A058;YI SYLLABLE BBI;Lo;0;L;;;;;N;;;;; +A059;YI SYLLABLE BBIP;Lo;0;L;;;;;N;;;;; +A05A;YI SYLLABLE BBIET;Lo;0;L;;;;;N;;;;; +A05B;YI SYLLABLE BBIEX;Lo;0;L;;;;;N;;;;; +A05C;YI SYLLABLE BBIE;Lo;0;L;;;;;N;;;;; +A05D;YI SYLLABLE BBIEP;Lo;0;L;;;;;N;;;;; +A05E;YI SYLLABLE BBAT;Lo;0;L;;;;;N;;;;; +A05F;YI SYLLABLE BBAX;Lo;0;L;;;;;N;;;;; +A060;YI SYLLABLE BBA;Lo;0;L;;;;;N;;;;; +A061;YI SYLLABLE BBAP;Lo;0;L;;;;;N;;;;; +A062;YI SYLLABLE BBUOX;Lo;0;L;;;;;N;;;;; +A063;YI SYLLABLE BBUO;Lo;0;L;;;;;N;;;;; +A064;YI SYLLABLE BBUOP;Lo;0;L;;;;;N;;;;; +A065;YI SYLLABLE BBOT;Lo;0;L;;;;;N;;;;; +A066;YI SYLLABLE BBOX;Lo;0;L;;;;;N;;;;; +A067;YI SYLLABLE BBO;Lo;0;L;;;;;N;;;;; +A068;YI SYLLABLE BBOP;Lo;0;L;;;;;N;;;;; +A069;YI SYLLABLE BBEX;Lo;0;L;;;;;N;;;;; +A06A;YI SYLLABLE BBE;Lo;0;L;;;;;N;;;;; +A06B;YI SYLLABLE BBEP;Lo;0;L;;;;;N;;;;; +A06C;YI SYLLABLE BBUT;Lo;0;L;;;;;N;;;;; +A06D;YI SYLLABLE BBUX;Lo;0;L;;;;;N;;;;; +A06E;YI SYLLABLE BBU;Lo;0;L;;;;;N;;;;; +A06F;YI SYLLABLE BBUP;Lo;0;L;;;;;N;;;;; +A070;YI SYLLABLE BBURX;Lo;0;L;;;;;N;;;;; +A071;YI SYLLABLE BBUR;Lo;0;L;;;;;N;;;;; +A072;YI SYLLABLE BBYT;Lo;0;L;;;;;N;;;;; +A073;YI SYLLABLE BBYX;Lo;0;L;;;;;N;;;;; +A074;YI SYLLABLE BBY;Lo;0;L;;;;;N;;;;; +A075;YI SYLLABLE BBYP;Lo;0;L;;;;;N;;;;; +A076;YI SYLLABLE NBIT;Lo;0;L;;;;;N;;;;; +A077;YI SYLLABLE NBIX;Lo;0;L;;;;;N;;;;; +A078;YI SYLLABLE NBI;Lo;0;L;;;;;N;;;;; +A079;YI SYLLABLE NBIP;Lo;0;L;;;;;N;;;;; +A07A;YI SYLLABLE NBIEX;Lo;0;L;;;;;N;;;;; +A07B;YI SYLLABLE NBIE;Lo;0;L;;;;;N;;;;; +A07C;YI SYLLABLE NBIEP;Lo;0;L;;;;;N;;;;; +A07D;YI SYLLABLE NBAT;Lo;0;L;;;;;N;;;;; +A07E;YI SYLLABLE NBAX;Lo;0;L;;;;;N;;;;; +A07F;YI SYLLABLE NBA;Lo;0;L;;;;;N;;;;; +A080;YI SYLLABLE NBAP;Lo;0;L;;;;;N;;;;; +A081;YI SYLLABLE NBOT;Lo;0;L;;;;;N;;;;; +A082;YI SYLLABLE NBOX;Lo;0;L;;;;;N;;;;; +A083;YI SYLLABLE NBO;Lo;0;L;;;;;N;;;;; +A084;YI SYLLABLE NBOP;Lo;0;L;;;;;N;;;;; +A085;YI SYLLABLE NBUT;Lo;0;L;;;;;N;;;;; +A086;YI SYLLABLE NBUX;Lo;0;L;;;;;N;;;;; +A087;YI SYLLABLE NBU;Lo;0;L;;;;;N;;;;; +A088;YI SYLLABLE NBUP;Lo;0;L;;;;;N;;;;; +A089;YI SYLLABLE NBURX;Lo;0;L;;;;;N;;;;; +A08A;YI SYLLABLE NBUR;Lo;0;L;;;;;N;;;;; +A08B;YI SYLLABLE NBYT;Lo;0;L;;;;;N;;;;; +A08C;YI SYLLABLE NBYX;Lo;0;L;;;;;N;;;;; +A08D;YI SYLLABLE NBY;Lo;0;L;;;;;N;;;;; +A08E;YI SYLLABLE NBYP;Lo;0;L;;;;;N;;;;; +A08F;YI SYLLABLE NBYRX;Lo;0;L;;;;;N;;;;; +A090;YI SYLLABLE NBYR;Lo;0;L;;;;;N;;;;; +A091;YI SYLLABLE HMIT;Lo;0;L;;;;;N;;;;; +A092;YI SYLLABLE HMIX;Lo;0;L;;;;;N;;;;; +A093;YI SYLLABLE HMI;Lo;0;L;;;;;N;;;;; +A094;YI SYLLABLE HMIP;Lo;0;L;;;;;N;;;;; +A095;YI SYLLABLE HMIEX;Lo;0;L;;;;;N;;;;; +A096;YI SYLLABLE HMIE;Lo;0;L;;;;;N;;;;; +A097;YI SYLLABLE HMIEP;Lo;0;L;;;;;N;;;;; +A098;YI SYLLABLE HMAT;Lo;0;L;;;;;N;;;;; +A099;YI SYLLABLE HMAX;Lo;0;L;;;;;N;;;;; +A09A;YI SYLLABLE HMA;Lo;0;L;;;;;N;;;;; +A09B;YI SYLLABLE HMAP;Lo;0;L;;;;;N;;;;; +A09C;YI SYLLABLE HMUOX;Lo;0;L;;;;;N;;;;; +A09D;YI SYLLABLE HMUO;Lo;0;L;;;;;N;;;;; +A09E;YI SYLLABLE HMUOP;Lo;0;L;;;;;N;;;;; +A09F;YI SYLLABLE HMOT;Lo;0;L;;;;;N;;;;; +A0A0;YI SYLLABLE HMOX;Lo;0;L;;;;;N;;;;; +A0A1;YI SYLLABLE HMO;Lo;0;L;;;;;N;;;;; +A0A2;YI SYLLABLE HMOP;Lo;0;L;;;;;N;;;;; +A0A3;YI SYLLABLE HMUT;Lo;0;L;;;;;N;;;;; +A0A4;YI SYLLABLE HMUX;Lo;0;L;;;;;N;;;;; +A0A5;YI SYLLABLE HMU;Lo;0;L;;;;;N;;;;; +A0A6;YI SYLLABLE HMUP;Lo;0;L;;;;;N;;;;; +A0A7;YI SYLLABLE HMURX;Lo;0;L;;;;;N;;;;; +A0A8;YI SYLLABLE HMUR;Lo;0;L;;;;;N;;;;; +A0A9;YI SYLLABLE HMYX;Lo;0;L;;;;;N;;;;; +A0AA;YI SYLLABLE HMY;Lo;0;L;;;;;N;;;;; +A0AB;YI SYLLABLE HMYP;Lo;0;L;;;;;N;;;;; +A0AC;YI SYLLABLE HMYRX;Lo;0;L;;;;;N;;;;; +A0AD;YI SYLLABLE HMYR;Lo;0;L;;;;;N;;;;; +A0AE;YI SYLLABLE MIT;Lo;0;L;;;;;N;;;;; +A0AF;YI SYLLABLE MIX;Lo;0;L;;;;;N;;;;; +A0B0;YI SYLLABLE MI;Lo;0;L;;;;;N;;;;; +A0B1;YI SYLLABLE MIP;Lo;0;L;;;;;N;;;;; +A0B2;YI SYLLABLE MIEX;Lo;0;L;;;;;N;;;;; +A0B3;YI SYLLABLE MIE;Lo;0;L;;;;;N;;;;; +A0B4;YI SYLLABLE MIEP;Lo;0;L;;;;;N;;;;; +A0B5;YI SYLLABLE MAT;Lo;0;L;;;;;N;;;;; +A0B6;YI SYLLABLE MAX;Lo;0;L;;;;;N;;;;; +A0B7;YI SYLLABLE MA;Lo;0;L;;;;;N;;;;; +A0B8;YI SYLLABLE MAP;Lo;0;L;;;;;N;;;;; +A0B9;YI SYLLABLE MUOT;Lo;0;L;;;;;N;;;;; +A0BA;YI SYLLABLE MUOX;Lo;0;L;;;;;N;;;;; +A0BB;YI SYLLABLE MUO;Lo;0;L;;;;;N;;;;; +A0BC;YI SYLLABLE MUOP;Lo;0;L;;;;;N;;;;; +A0BD;YI SYLLABLE MOT;Lo;0;L;;;;;N;;;;; +A0BE;YI SYLLABLE MOX;Lo;0;L;;;;;N;;;;; +A0BF;YI SYLLABLE MO;Lo;0;L;;;;;N;;;;; +A0C0;YI SYLLABLE MOP;Lo;0;L;;;;;N;;;;; +A0C1;YI SYLLABLE MEX;Lo;0;L;;;;;N;;;;; +A0C2;YI SYLLABLE ME;Lo;0;L;;;;;N;;;;; +A0C3;YI SYLLABLE MUT;Lo;0;L;;;;;N;;;;; +A0C4;YI SYLLABLE MUX;Lo;0;L;;;;;N;;;;; +A0C5;YI SYLLABLE MU;Lo;0;L;;;;;N;;;;; +A0C6;YI SYLLABLE MUP;Lo;0;L;;;;;N;;;;; +A0C7;YI SYLLABLE MURX;Lo;0;L;;;;;N;;;;; +A0C8;YI SYLLABLE MUR;Lo;0;L;;;;;N;;;;; +A0C9;YI SYLLABLE MYT;Lo;0;L;;;;;N;;;;; +A0CA;YI SYLLABLE MYX;Lo;0;L;;;;;N;;;;; +A0CB;YI SYLLABLE MY;Lo;0;L;;;;;N;;;;; +A0CC;YI SYLLABLE MYP;Lo;0;L;;;;;N;;;;; +A0CD;YI SYLLABLE FIT;Lo;0;L;;;;;N;;;;; +A0CE;YI SYLLABLE FIX;Lo;0;L;;;;;N;;;;; +A0CF;YI SYLLABLE FI;Lo;0;L;;;;;N;;;;; +A0D0;YI SYLLABLE FIP;Lo;0;L;;;;;N;;;;; +A0D1;YI SYLLABLE FAT;Lo;0;L;;;;;N;;;;; +A0D2;YI SYLLABLE FAX;Lo;0;L;;;;;N;;;;; +A0D3;YI SYLLABLE FA;Lo;0;L;;;;;N;;;;; +A0D4;YI SYLLABLE FAP;Lo;0;L;;;;;N;;;;; +A0D5;YI SYLLABLE FOX;Lo;0;L;;;;;N;;;;; +A0D6;YI SYLLABLE FO;Lo;0;L;;;;;N;;;;; +A0D7;YI SYLLABLE FOP;Lo;0;L;;;;;N;;;;; +A0D8;YI SYLLABLE FUT;Lo;0;L;;;;;N;;;;; +A0D9;YI SYLLABLE FUX;Lo;0;L;;;;;N;;;;; +A0DA;YI SYLLABLE FU;Lo;0;L;;;;;N;;;;; +A0DB;YI SYLLABLE FUP;Lo;0;L;;;;;N;;;;; +A0DC;YI SYLLABLE FURX;Lo;0;L;;;;;N;;;;; +A0DD;YI SYLLABLE FUR;Lo;0;L;;;;;N;;;;; +A0DE;YI SYLLABLE FYT;Lo;0;L;;;;;N;;;;; +A0DF;YI SYLLABLE FYX;Lo;0;L;;;;;N;;;;; +A0E0;YI SYLLABLE FY;Lo;0;L;;;;;N;;;;; +A0E1;YI SYLLABLE FYP;Lo;0;L;;;;;N;;;;; +A0E2;YI SYLLABLE VIT;Lo;0;L;;;;;N;;;;; +A0E3;YI SYLLABLE VIX;Lo;0;L;;;;;N;;;;; +A0E4;YI SYLLABLE VI;Lo;0;L;;;;;N;;;;; +A0E5;YI SYLLABLE VIP;Lo;0;L;;;;;N;;;;; +A0E6;YI SYLLABLE VIET;Lo;0;L;;;;;N;;;;; +A0E7;YI SYLLABLE VIEX;Lo;0;L;;;;;N;;;;; +A0E8;YI SYLLABLE VIE;Lo;0;L;;;;;N;;;;; +A0E9;YI SYLLABLE VIEP;Lo;0;L;;;;;N;;;;; +A0EA;YI SYLLABLE VAT;Lo;0;L;;;;;N;;;;; +A0EB;YI SYLLABLE VAX;Lo;0;L;;;;;N;;;;; +A0EC;YI SYLLABLE VA;Lo;0;L;;;;;N;;;;; +A0ED;YI SYLLABLE VAP;Lo;0;L;;;;;N;;;;; +A0EE;YI SYLLABLE VOT;Lo;0;L;;;;;N;;;;; +A0EF;YI SYLLABLE VOX;Lo;0;L;;;;;N;;;;; +A0F0;YI SYLLABLE VO;Lo;0;L;;;;;N;;;;; +A0F1;YI SYLLABLE VOP;Lo;0;L;;;;;N;;;;; +A0F2;YI SYLLABLE VEX;Lo;0;L;;;;;N;;;;; +A0F3;YI SYLLABLE VEP;Lo;0;L;;;;;N;;;;; +A0F4;YI SYLLABLE VUT;Lo;0;L;;;;;N;;;;; +A0F5;YI SYLLABLE VUX;Lo;0;L;;;;;N;;;;; +A0F6;YI SYLLABLE VU;Lo;0;L;;;;;N;;;;; +A0F7;YI SYLLABLE VUP;Lo;0;L;;;;;N;;;;; +A0F8;YI SYLLABLE VURX;Lo;0;L;;;;;N;;;;; +A0F9;YI SYLLABLE VUR;Lo;0;L;;;;;N;;;;; +A0FA;YI SYLLABLE VYT;Lo;0;L;;;;;N;;;;; +A0FB;YI SYLLABLE VYX;Lo;0;L;;;;;N;;;;; +A0FC;YI SYLLABLE VY;Lo;0;L;;;;;N;;;;; +A0FD;YI SYLLABLE VYP;Lo;0;L;;;;;N;;;;; +A0FE;YI SYLLABLE VYRX;Lo;0;L;;;;;N;;;;; +A0FF;YI SYLLABLE VYR;Lo;0;L;;;;;N;;;;; +A100;YI SYLLABLE DIT;Lo;0;L;;;;;N;;;;; +A101;YI SYLLABLE DIX;Lo;0;L;;;;;N;;;;; +A102;YI SYLLABLE DI;Lo;0;L;;;;;N;;;;; +A103;YI SYLLABLE DIP;Lo;0;L;;;;;N;;;;; +A104;YI SYLLABLE DIEX;Lo;0;L;;;;;N;;;;; +A105;YI SYLLABLE DIE;Lo;0;L;;;;;N;;;;; +A106;YI SYLLABLE DIEP;Lo;0;L;;;;;N;;;;; +A107;YI SYLLABLE DAT;Lo;0;L;;;;;N;;;;; +A108;YI SYLLABLE DAX;Lo;0;L;;;;;N;;;;; +A109;YI SYLLABLE DA;Lo;0;L;;;;;N;;;;; +A10A;YI SYLLABLE DAP;Lo;0;L;;;;;N;;;;; +A10B;YI SYLLABLE DUOX;Lo;0;L;;;;;N;;;;; +A10C;YI SYLLABLE DUO;Lo;0;L;;;;;N;;;;; +A10D;YI SYLLABLE DOT;Lo;0;L;;;;;N;;;;; +A10E;YI SYLLABLE DOX;Lo;0;L;;;;;N;;;;; +A10F;YI SYLLABLE DO;Lo;0;L;;;;;N;;;;; +A110;YI SYLLABLE DOP;Lo;0;L;;;;;N;;;;; +A111;YI SYLLABLE DEX;Lo;0;L;;;;;N;;;;; +A112;YI SYLLABLE DE;Lo;0;L;;;;;N;;;;; +A113;YI SYLLABLE DEP;Lo;0;L;;;;;N;;;;; +A114;YI SYLLABLE DUT;Lo;0;L;;;;;N;;;;; +A115;YI SYLLABLE DUX;Lo;0;L;;;;;N;;;;; +A116;YI SYLLABLE DU;Lo;0;L;;;;;N;;;;; +A117;YI SYLLABLE DUP;Lo;0;L;;;;;N;;;;; +A118;YI SYLLABLE DURX;Lo;0;L;;;;;N;;;;; +A119;YI SYLLABLE DUR;Lo;0;L;;;;;N;;;;; +A11A;YI SYLLABLE TIT;Lo;0;L;;;;;N;;;;; +A11B;YI SYLLABLE TIX;Lo;0;L;;;;;N;;;;; +A11C;YI SYLLABLE TI;Lo;0;L;;;;;N;;;;; +A11D;YI SYLLABLE TIP;Lo;0;L;;;;;N;;;;; +A11E;YI SYLLABLE TIEX;Lo;0;L;;;;;N;;;;; +A11F;YI SYLLABLE TIE;Lo;0;L;;;;;N;;;;; +A120;YI SYLLABLE TIEP;Lo;0;L;;;;;N;;;;; +A121;YI SYLLABLE TAT;Lo;0;L;;;;;N;;;;; +A122;YI SYLLABLE TAX;Lo;0;L;;;;;N;;;;; +A123;YI SYLLABLE TA;Lo;0;L;;;;;N;;;;; +A124;YI SYLLABLE TAP;Lo;0;L;;;;;N;;;;; +A125;YI SYLLABLE TUOT;Lo;0;L;;;;;N;;;;; +A126;YI SYLLABLE TUOX;Lo;0;L;;;;;N;;;;; +A127;YI SYLLABLE TUO;Lo;0;L;;;;;N;;;;; +A128;YI SYLLABLE TUOP;Lo;0;L;;;;;N;;;;; +A129;YI SYLLABLE TOT;Lo;0;L;;;;;N;;;;; +A12A;YI SYLLABLE TOX;Lo;0;L;;;;;N;;;;; +A12B;YI SYLLABLE TO;Lo;0;L;;;;;N;;;;; +A12C;YI SYLLABLE TOP;Lo;0;L;;;;;N;;;;; +A12D;YI SYLLABLE TEX;Lo;0;L;;;;;N;;;;; +A12E;YI SYLLABLE TE;Lo;0;L;;;;;N;;;;; +A12F;YI SYLLABLE TEP;Lo;0;L;;;;;N;;;;; +A130;YI SYLLABLE TUT;Lo;0;L;;;;;N;;;;; +A131;YI SYLLABLE TUX;Lo;0;L;;;;;N;;;;; +A132;YI SYLLABLE TU;Lo;0;L;;;;;N;;;;; +A133;YI SYLLABLE TUP;Lo;0;L;;;;;N;;;;; +A134;YI SYLLABLE TURX;Lo;0;L;;;;;N;;;;; +A135;YI SYLLABLE TUR;Lo;0;L;;;;;N;;;;; +A136;YI SYLLABLE DDIT;Lo;0;L;;;;;N;;;;; +A137;YI SYLLABLE DDIX;Lo;0;L;;;;;N;;;;; +A138;YI SYLLABLE DDI;Lo;0;L;;;;;N;;;;; +A139;YI SYLLABLE DDIP;Lo;0;L;;;;;N;;;;; +A13A;YI SYLLABLE DDIEX;Lo;0;L;;;;;N;;;;; +A13B;YI SYLLABLE DDIE;Lo;0;L;;;;;N;;;;; +A13C;YI SYLLABLE DDIEP;Lo;0;L;;;;;N;;;;; +A13D;YI SYLLABLE DDAT;Lo;0;L;;;;;N;;;;; +A13E;YI SYLLABLE DDAX;Lo;0;L;;;;;N;;;;; +A13F;YI SYLLABLE DDA;Lo;0;L;;;;;N;;;;; +A140;YI SYLLABLE DDAP;Lo;0;L;;;;;N;;;;; +A141;YI SYLLABLE DDUOX;Lo;0;L;;;;;N;;;;; +A142;YI SYLLABLE DDUO;Lo;0;L;;;;;N;;;;; +A143;YI SYLLABLE DDUOP;Lo;0;L;;;;;N;;;;; +A144;YI SYLLABLE DDOT;Lo;0;L;;;;;N;;;;; +A145;YI SYLLABLE DDOX;Lo;0;L;;;;;N;;;;; +A146;YI SYLLABLE DDO;Lo;0;L;;;;;N;;;;; +A147;YI SYLLABLE DDOP;Lo;0;L;;;;;N;;;;; +A148;YI SYLLABLE DDEX;Lo;0;L;;;;;N;;;;; +A149;YI SYLLABLE DDE;Lo;0;L;;;;;N;;;;; +A14A;YI SYLLABLE DDEP;Lo;0;L;;;;;N;;;;; +A14B;YI SYLLABLE DDUT;Lo;0;L;;;;;N;;;;; +A14C;YI SYLLABLE DDUX;Lo;0;L;;;;;N;;;;; +A14D;YI SYLLABLE DDU;Lo;0;L;;;;;N;;;;; +A14E;YI SYLLABLE DDUP;Lo;0;L;;;;;N;;;;; +A14F;YI SYLLABLE DDURX;Lo;0;L;;;;;N;;;;; +A150;YI SYLLABLE DDUR;Lo;0;L;;;;;N;;;;; +A151;YI SYLLABLE NDIT;Lo;0;L;;;;;N;;;;; +A152;YI SYLLABLE NDIX;Lo;0;L;;;;;N;;;;; +A153;YI SYLLABLE NDI;Lo;0;L;;;;;N;;;;; +A154;YI SYLLABLE NDIP;Lo;0;L;;;;;N;;;;; +A155;YI SYLLABLE NDIEX;Lo;0;L;;;;;N;;;;; +A156;YI SYLLABLE NDIE;Lo;0;L;;;;;N;;;;; +A157;YI SYLLABLE NDAT;Lo;0;L;;;;;N;;;;; +A158;YI SYLLABLE NDAX;Lo;0;L;;;;;N;;;;; +A159;YI SYLLABLE NDA;Lo;0;L;;;;;N;;;;; +A15A;YI SYLLABLE NDAP;Lo;0;L;;;;;N;;;;; +A15B;YI SYLLABLE NDOT;Lo;0;L;;;;;N;;;;; +A15C;YI SYLLABLE NDOX;Lo;0;L;;;;;N;;;;; +A15D;YI SYLLABLE NDO;Lo;0;L;;;;;N;;;;; +A15E;YI SYLLABLE NDOP;Lo;0;L;;;;;N;;;;; +A15F;YI SYLLABLE NDEX;Lo;0;L;;;;;N;;;;; +A160;YI SYLLABLE NDE;Lo;0;L;;;;;N;;;;; +A161;YI SYLLABLE NDEP;Lo;0;L;;;;;N;;;;; +A162;YI SYLLABLE NDUT;Lo;0;L;;;;;N;;;;; +A163;YI SYLLABLE NDUX;Lo;0;L;;;;;N;;;;; +A164;YI SYLLABLE NDU;Lo;0;L;;;;;N;;;;; +A165;YI SYLLABLE NDUP;Lo;0;L;;;;;N;;;;; +A166;YI SYLLABLE NDURX;Lo;0;L;;;;;N;;;;; +A167;YI SYLLABLE NDUR;Lo;0;L;;;;;N;;;;; +A168;YI SYLLABLE HNIT;Lo;0;L;;;;;N;;;;; +A169;YI SYLLABLE HNIX;Lo;0;L;;;;;N;;;;; +A16A;YI SYLLABLE HNI;Lo;0;L;;;;;N;;;;; +A16B;YI SYLLABLE HNIP;Lo;0;L;;;;;N;;;;; +A16C;YI SYLLABLE HNIET;Lo;0;L;;;;;N;;;;; +A16D;YI SYLLABLE HNIEX;Lo;0;L;;;;;N;;;;; +A16E;YI SYLLABLE HNIE;Lo;0;L;;;;;N;;;;; +A16F;YI SYLLABLE HNIEP;Lo;0;L;;;;;N;;;;; +A170;YI SYLLABLE HNAT;Lo;0;L;;;;;N;;;;; +A171;YI SYLLABLE HNAX;Lo;0;L;;;;;N;;;;; +A172;YI SYLLABLE HNA;Lo;0;L;;;;;N;;;;; +A173;YI SYLLABLE HNAP;Lo;0;L;;;;;N;;;;; +A174;YI SYLLABLE HNUOX;Lo;0;L;;;;;N;;;;; +A175;YI SYLLABLE HNUO;Lo;0;L;;;;;N;;;;; +A176;YI SYLLABLE HNOT;Lo;0;L;;;;;N;;;;; +A177;YI SYLLABLE HNOX;Lo;0;L;;;;;N;;;;; +A178;YI SYLLABLE HNOP;Lo;0;L;;;;;N;;;;; +A179;YI SYLLABLE HNEX;Lo;0;L;;;;;N;;;;; +A17A;YI SYLLABLE HNE;Lo;0;L;;;;;N;;;;; +A17B;YI SYLLABLE HNEP;Lo;0;L;;;;;N;;;;; +A17C;YI SYLLABLE HNUT;Lo;0;L;;;;;N;;;;; +A17D;YI SYLLABLE NIT;Lo;0;L;;;;;N;;;;; +A17E;YI SYLLABLE NIX;Lo;0;L;;;;;N;;;;; +A17F;YI SYLLABLE NI;Lo;0;L;;;;;N;;;;; +A180;YI SYLLABLE NIP;Lo;0;L;;;;;N;;;;; +A181;YI SYLLABLE NIEX;Lo;0;L;;;;;N;;;;; +A182;YI SYLLABLE NIE;Lo;0;L;;;;;N;;;;; +A183;YI SYLLABLE NIEP;Lo;0;L;;;;;N;;;;; +A184;YI SYLLABLE NAX;Lo;0;L;;;;;N;;;;; +A185;YI SYLLABLE NA;Lo;0;L;;;;;N;;;;; +A186;YI SYLLABLE NAP;Lo;0;L;;;;;N;;;;; +A187;YI SYLLABLE NUOX;Lo;0;L;;;;;N;;;;; +A188;YI SYLLABLE NUO;Lo;0;L;;;;;N;;;;; +A189;YI SYLLABLE NUOP;Lo;0;L;;;;;N;;;;; +A18A;YI SYLLABLE NOT;Lo;0;L;;;;;N;;;;; +A18B;YI SYLLABLE NOX;Lo;0;L;;;;;N;;;;; +A18C;YI SYLLABLE NO;Lo;0;L;;;;;N;;;;; +A18D;YI SYLLABLE NOP;Lo;0;L;;;;;N;;;;; +A18E;YI SYLLABLE NEX;Lo;0;L;;;;;N;;;;; +A18F;YI SYLLABLE NE;Lo;0;L;;;;;N;;;;; +A190;YI SYLLABLE NEP;Lo;0;L;;;;;N;;;;; +A191;YI SYLLABLE NUT;Lo;0;L;;;;;N;;;;; +A192;YI SYLLABLE NUX;Lo;0;L;;;;;N;;;;; +A193;YI SYLLABLE NU;Lo;0;L;;;;;N;;;;; +A194;YI SYLLABLE NUP;Lo;0;L;;;;;N;;;;; +A195;YI SYLLABLE NURX;Lo;0;L;;;;;N;;;;; +A196;YI SYLLABLE NUR;Lo;0;L;;;;;N;;;;; +A197;YI SYLLABLE HLIT;Lo;0;L;;;;;N;;;;; +A198;YI SYLLABLE HLIX;Lo;0;L;;;;;N;;;;; +A199;YI SYLLABLE HLI;Lo;0;L;;;;;N;;;;; +A19A;YI SYLLABLE HLIP;Lo;0;L;;;;;N;;;;; +A19B;YI SYLLABLE HLIEX;Lo;0;L;;;;;N;;;;; +A19C;YI SYLLABLE HLIE;Lo;0;L;;;;;N;;;;; +A19D;YI SYLLABLE HLIEP;Lo;0;L;;;;;N;;;;; +A19E;YI SYLLABLE HLAT;Lo;0;L;;;;;N;;;;; +A19F;YI SYLLABLE HLAX;Lo;0;L;;;;;N;;;;; +A1A0;YI SYLLABLE HLA;Lo;0;L;;;;;N;;;;; +A1A1;YI SYLLABLE HLAP;Lo;0;L;;;;;N;;;;; +A1A2;YI SYLLABLE HLUOX;Lo;0;L;;;;;N;;;;; +A1A3;YI SYLLABLE HLUO;Lo;0;L;;;;;N;;;;; +A1A4;YI SYLLABLE HLUOP;Lo;0;L;;;;;N;;;;; +A1A5;YI SYLLABLE HLOX;Lo;0;L;;;;;N;;;;; +A1A6;YI SYLLABLE HLO;Lo;0;L;;;;;N;;;;; +A1A7;YI SYLLABLE HLOP;Lo;0;L;;;;;N;;;;; +A1A8;YI SYLLABLE HLEX;Lo;0;L;;;;;N;;;;; +A1A9;YI SYLLABLE HLE;Lo;0;L;;;;;N;;;;; +A1AA;YI SYLLABLE HLEP;Lo;0;L;;;;;N;;;;; +A1AB;YI SYLLABLE HLUT;Lo;0;L;;;;;N;;;;; +A1AC;YI SYLLABLE HLUX;Lo;0;L;;;;;N;;;;; +A1AD;YI SYLLABLE HLU;Lo;0;L;;;;;N;;;;; +A1AE;YI SYLLABLE HLUP;Lo;0;L;;;;;N;;;;; +A1AF;YI SYLLABLE HLURX;Lo;0;L;;;;;N;;;;; +A1B0;YI SYLLABLE HLUR;Lo;0;L;;;;;N;;;;; +A1B1;YI SYLLABLE HLYT;Lo;0;L;;;;;N;;;;; +A1B2;YI SYLLABLE HLYX;Lo;0;L;;;;;N;;;;; +A1B3;YI SYLLABLE HLY;Lo;0;L;;;;;N;;;;; +A1B4;YI SYLLABLE HLYP;Lo;0;L;;;;;N;;;;; +A1B5;YI SYLLABLE HLYRX;Lo;0;L;;;;;N;;;;; +A1B6;YI SYLLABLE HLYR;Lo;0;L;;;;;N;;;;; +A1B7;YI SYLLABLE LIT;Lo;0;L;;;;;N;;;;; +A1B8;YI SYLLABLE LIX;Lo;0;L;;;;;N;;;;; +A1B9;YI SYLLABLE LI;Lo;0;L;;;;;N;;;;; +A1BA;YI SYLLABLE LIP;Lo;0;L;;;;;N;;;;; +A1BB;YI SYLLABLE LIET;Lo;0;L;;;;;N;;;;; +A1BC;YI SYLLABLE LIEX;Lo;0;L;;;;;N;;;;; +A1BD;YI SYLLABLE LIE;Lo;0;L;;;;;N;;;;; +A1BE;YI SYLLABLE LIEP;Lo;0;L;;;;;N;;;;; +A1BF;YI SYLLABLE LAT;Lo;0;L;;;;;N;;;;; +A1C0;YI SYLLABLE LAX;Lo;0;L;;;;;N;;;;; +A1C1;YI SYLLABLE LA;Lo;0;L;;;;;N;;;;; +A1C2;YI SYLLABLE LAP;Lo;0;L;;;;;N;;;;; +A1C3;YI SYLLABLE LUOT;Lo;0;L;;;;;N;;;;; +A1C4;YI SYLLABLE LUOX;Lo;0;L;;;;;N;;;;; +A1C5;YI SYLLABLE LUO;Lo;0;L;;;;;N;;;;; +A1C6;YI SYLLABLE LUOP;Lo;0;L;;;;;N;;;;; +A1C7;YI SYLLABLE LOT;Lo;0;L;;;;;N;;;;; +A1C8;YI SYLLABLE LOX;Lo;0;L;;;;;N;;;;; +A1C9;YI SYLLABLE LO;Lo;0;L;;;;;N;;;;; +A1CA;YI SYLLABLE LOP;Lo;0;L;;;;;N;;;;; +A1CB;YI SYLLABLE LEX;Lo;0;L;;;;;N;;;;; +A1CC;YI SYLLABLE LE;Lo;0;L;;;;;N;;;;; +A1CD;YI SYLLABLE LEP;Lo;0;L;;;;;N;;;;; +A1CE;YI SYLLABLE LUT;Lo;0;L;;;;;N;;;;; +A1CF;YI SYLLABLE LUX;Lo;0;L;;;;;N;;;;; +A1D0;YI SYLLABLE LU;Lo;0;L;;;;;N;;;;; +A1D1;YI SYLLABLE LUP;Lo;0;L;;;;;N;;;;; +A1D2;YI SYLLABLE LURX;Lo;0;L;;;;;N;;;;; +A1D3;YI SYLLABLE LUR;Lo;0;L;;;;;N;;;;; +A1D4;YI SYLLABLE LYT;Lo;0;L;;;;;N;;;;; +A1D5;YI SYLLABLE LYX;Lo;0;L;;;;;N;;;;; +A1D6;YI SYLLABLE LY;Lo;0;L;;;;;N;;;;; +A1D7;YI SYLLABLE LYP;Lo;0;L;;;;;N;;;;; +A1D8;YI SYLLABLE LYRX;Lo;0;L;;;;;N;;;;; +A1D9;YI SYLLABLE LYR;Lo;0;L;;;;;N;;;;; +A1DA;YI SYLLABLE GIT;Lo;0;L;;;;;N;;;;; +A1DB;YI SYLLABLE GIX;Lo;0;L;;;;;N;;;;; +A1DC;YI SYLLABLE GI;Lo;0;L;;;;;N;;;;; +A1DD;YI SYLLABLE GIP;Lo;0;L;;;;;N;;;;; +A1DE;YI SYLLABLE GIET;Lo;0;L;;;;;N;;;;; +A1DF;YI SYLLABLE GIEX;Lo;0;L;;;;;N;;;;; +A1E0;YI SYLLABLE GIE;Lo;0;L;;;;;N;;;;; +A1E1;YI SYLLABLE GIEP;Lo;0;L;;;;;N;;;;; +A1E2;YI SYLLABLE GAT;Lo;0;L;;;;;N;;;;; +A1E3;YI SYLLABLE GAX;Lo;0;L;;;;;N;;;;; +A1E4;YI SYLLABLE GA;Lo;0;L;;;;;N;;;;; +A1E5;YI SYLLABLE GAP;Lo;0;L;;;;;N;;;;; +A1E6;YI SYLLABLE GUOT;Lo;0;L;;;;;N;;;;; +A1E7;YI SYLLABLE GUOX;Lo;0;L;;;;;N;;;;; +A1E8;YI SYLLABLE GUO;Lo;0;L;;;;;N;;;;; +A1E9;YI SYLLABLE GUOP;Lo;0;L;;;;;N;;;;; +A1EA;YI SYLLABLE GOT;Lo;0;L;;;;;N;;;;; +A1EB;YI SYLLABLE GOX;Lo;0;L;;;;;N;;;;; +A1EC;YI SYLLABLE GO;Lo;0;L;;;;;N;;;;; +A1ED;YI SYLLABLE GOP;Lo;0;L;;;;;N;;;;; +A1EE;YI SYLLABLE GET;Lo;0;L;;;;;N;;;;; +A1EF;YI SYLLABLE GEX;Lo;0;L;;;;;N;;;;; +A1F0;YI SYLLABLE GE;Lo;0;L;;;;;N;;;;; +A1F1;YI SYLLABLE GEP;Lo;0;L;;;;;N;;;;; +A1F2;YI SYLLABLE GUT;Lo;0;L;;;;;N;;;;; +A1F3;YI SYLLABLE GUX;Lo;0;L;;;;;N;;;;; +A1F4;YI SYLLABLE GU;Lo;0;L;;;;;N;;;;; +A1F5;YI SYLLABLE GUP;Lo;0;L;;;;;N;;;;; +A1F6;YI SYLLABLE GURX;Lo;0;L;;;;;N;;;;; +A1F7;YI SYLLABLE GUR;Lo;0;L;;;;;N;;;;; +A1F8;YI SYLLABLE KIT;Lo;0;L;;;;;N;;;;; +A1F9;YI SYLLABLE KIX;Lo;0;L;;;;;N;;;;; +A1FA;YI SYLLABLE KI;Lo;0;L;;;;;N;;;;; +A1FB;YI SYLLABLE KIP;Lo;0;L;;;;;N;;;;; +A1FC;YI SYLLABLE KIEX;Lo;0;L;;;;;N;;;;; +A1FD;YI SYLLABLE KIE;Lo;0;L;;;;;N;;;;; +A1FE;YI SYLLABLE KIEP;Lo;0;L;;;;;N;;;;; +A1FF;YI SYLLABLE KAT;Lo;0;L;;;;;N;;;;; +A200;YI SYLLABLE KAX;Lo;0;L;;;;;N;;;;; +A201;YI SYLLABLE KA;Lo;0;L;;;;;N;;;;; +A202;YI SYLLABLE KAP;Lo;0;L;;;;;N;;;;; +A203;YI SYLLABLE KUOX;Lo;0;L;;;;;N;;;;; +A204;YI SYLLABLE KUO;Lo;0;L;;;;;N;;;;; +A205;YI SYLLABLE KUOP;Lo;0;L;;;;;N;;;;; +A206;YI SYLLABLE KOT;Lo;0;L;;;;;N;;;;; +A207;YI SYLLABLE KOX;Lo;0;L;;;;;N;;;;; +A208;YI SYLLABLE KO;Lo;0;L;;;;;N;;;;; +A209;YI SYLLABLE KOP;Lo;0;L;;;;;N;;;;; +A20A;YI SYLLABLE KET;Lo;0;L;;;;;N;;;;; +A20B;YI SYLLABLE KEX;Lo;0;L;;;;;N;;;;; +A20C;YI SYLLABLE KE;Lo;0;L;;;;;N;;;;; +A20D;YI SYLLABLE KEP;Lo;0;L;;;;;N;;;;; +A20E;YI SYLLABLE KUT;Lo;0;L;;;;;N;;;;; +A20F;YI SYLLABLE KUX;Lo;0;L;;;;;N;;;;; +A210;YI SYLLABLE KU;Lo;0;L;;;;;N;;;;; +A211;YI SYLLABLE KUP;Lo;0;L;;;;;N;;;;; +A212;YI SYLLABLE KURX;Lo;0;L;;;;;N;;;;; +A213;YI SYLLABLE KUR;Lo;0;L;;;;;N;;;;; +A214;YI SYLLABLE GGIT;Lo;0;L;;;;;N;;;;; +A215;YI SYLLABLE GGIX;Lo;0;L;;;;;N;;;;; +A216;YI SYLLABLE GGI;Lo;0;L;;;;;N;;;;; +A217;YI SYLLABLE GGIEX;Lo;0;L;;;;;N;;;;; +A218;YI SYLLABLE GGIE;Lo;0;L;;;;;N;;;;; +A219;YI SYLLABLE GGIEP;Lo;0;L;;;;;N;;;;; +A21A;YI SYLLABLE GGAT;Lo;0;L;;;;;N;;;;; +A21B;YI SYLLABLE GGAX;Lo;0;L;;;;;N;;;;; +A21C;YI SYLLABLE GGA;Lo;0;L;;;;;N;;;;; +A21D;YI SYLLABLE GGAP;Lo;0;L;;;;;N;;;;; +A21E;YI SYLLABLE GGUOT;Lo;0;L;;;;;N;;;;; +A21F;YI SYLLABLE GGUOX;Lo;0;L;;;;;N;;;;; +A220;YI SYLLABLE GGUO;Lo;0;L;;;;;N;;;;; +A221;YI SYLLABLE GGUOP;Lo;0;L;;;;;N;;;;; +A222;YI SYLLABLE GGOT;Lo;0;L;;;;;N;;;;; +A223;YI SYLLABLE GGOX;Lo;0;L;;;;;N;;;;; +A224;YI SYLLABLE GGO;Lo;0;L;;;;;N;;;;; +A225;YI SYLLABLE GGOP;Lo;0;L;;;;;N;;;;; +A226;YI SYLLABLE GGET;Lo;0;L;;;;;N;;;;; +A227;YI SYLLABLE GGEX;Lo;0;L;;;;;N;;;;; +A228;YI SYLLABLE GGE;Lo;0;L;;;;;N;;;;; +A229;YI SYLLABLE GGEP;Lo;0;L;;;;;N;;;;; +A22A;YI SYLLABLE GGUT;Lo;0;L;;;;;N;;;;; +A22B;YI SYLLABLE GGUX;Lo;0;L;;;;;N;;;;; +A22C;YI SYLLABLE GGU;Lo;0;L;;;;;N;;;;; +A22D;YI SYLLABLE GGUP;Lo;0;L;;;;;N;;;;; +A22E;YI SYLLABLE GGURX;Lo;0;L;;;;;N;;;;; +A22F;YI SYLLABLE GGUR;Lo;0;L;;;;;N;;;;; +A230;YI SYLLABLE MGIEX;Lo;0;L;;;;;N;;;;; +A231;YI SYLLABLE MGIE;Lo;0;L;;;;;N;;;;; +A232;YI SYLLABLE MGAT;Lo;0;L;;;;;N;;;;; +A233;YI SYLLABLE MGAX;Lo;0;L;;;;;N;;;;; +A234;YI SYLLABLE MGA;Lo;0;L;;;;;N;;;;; +A235;YI SYLLABLE MGAP;Lo;0;L;;;;;N;;;;; +A236;YI SYLLABLE MGUOX;Lo;0;L;;;;;N;;;;; +A237;YI SYLLABLE MGUO;Lo;0;L;;;;;N;;;;; +A238;YI SYLLABLE MGUOP;Lo;0;L;;;;;N;;;;; +A239;YI SYLLABLE MGOT;Lo;0;L;;;;;N;;;;; +A23A;YI SYLLABLE MGOX;Lo;0;L;;;;;N;;;;; +A23B;YI SYLLABLE MGO;Lo;0;L;;;;;N;;;;; +A23C;YI SYLLABLE MGOP;Lo;0;L;;;;;N;;;;; +A23D;YI SYLLABLE MGEX;Lo;0;L;;;;;N;;;;; +A23E;YI SYLLABLE MGE;Lo;0;L;;;;;N;;;;; +A23F;YI SYLLABLE MGEP;Lo;0;L;;;;;N;;;;; +A240;YI SYLLABLE MGUT;Lo;0;L;;;;;N;;;;; +A241;YI SYLLABLE MGUX;Lo;0;L;;;;;N;;;;; +A242;YI SYLLABLE MGU;Lo;0;L;;;;;N;;;;; +A243;YI SYLLABLE MGUP;Lo;0;L;;;;;N;;;;; +A244;YI SYLLABLE MGURX;Lo;0;L;;;;;N;;;;; +A245;YI SYLLABLE MGUR;Lo;0;L;;;;;N;;;;; +A246;YI SYLLABLE HXIT;Lo;0;L;;;;;N;;;;; +A247;YI SYLLABLE HXIX;Lo;0;L;;;;;N;;;;; +A248;YI SYLLABLE HXI;Lo;0;L;;;;;N;;;;; +A249;YI SYLLABLE HXIP;Lo;0;L;;;;;N;;;;; +A24A;YI SYLLABLE HXIET;Lo;0;L;;;;;N;;;;; +A24B;YI SYLLABLE HXIEX;Lo;0;L;;;;;N;;;;; +A24C;YI SYLLABLE HXIE;Lo;0;L;;;;;N;;;;; +A24D;YI SYLLABLE HXIEP;Lo;0;L;;;;;N;;;;; +A24E;YI SYLLABLE HXAT;Lo;0;L;;;;;N;;;;; +A24F;YI SYLLABLE HXAX;Lo;0;L;;;;;N;;;;; +A250;YI SYLLABLE HXA;Lo;0;L;;;;;N;;;;; +A251;YI SYLLABLE HXAP;Lo;0;L;;;;;N;;;;; +A252;YI SYLLABLE HXUOT;Lo;0;L;;;;;N;;;;; +A253;YI SYLLABLE HXUOX;Lo;0;L;;;;;N;;;;; +A254;YI SYLLABLE HXUO;Lo;0;L;;;;;N;;;;; +A255;YI SYLLABLE HXUOP;Lo;0;L;;;;;N;;;;; +A256;YI SYLLABLE HXOT;Lo;0;L;;;;;N;;;;; +A257;YI SYLLABLE HXOX;Lo;0;L;;;;;N;;;;; +A258;YI SYLLABLE HXO;Lo;0;L;;;;;N;;;;; +A259;YI SYLLABLE HXOP;Lo;0;L;;;;;N;;;;; +A25A;YI SYLLABLE HXEX;Lo;0;L;;;;;N;;;;; +A25B;YI SYLLABLE HXE;Lo;0;L;;;;;N;;;;; +A25C;YI SYLLABLE HXEP;Lo;0;L;;;;;N;;;;; +A25D;YI SYLLABLE NGIEX;Lo;0;L;;;;;N;;;;; +A25E;YI SYLLABLE NGIE;Lo;0;L;;;;;N;;;;; +A25F;YI SYLLABLE NGIEP;Lo;0;L;;;;;N;;;;; +A260;YI SYLLABLE NGAT;Lo;0;L;;;;;N;;;;; +A261;YI SYLLABLE NGAX;Lo;0;L;;;;;N;;;;; +A262;YI SYLLABLE NGA;Lo;0;L;;;;;N;;;;; +A263;YI SYLLABLE NGAP;Lo;0;L;;;;;N;;;;; +A264;YI SYLLABLE NGUOT;Lo;0;L;;;;;N;;;;; +A265;YI SYLLABLE NGUOX;Lo;0;L;;;;;N;;;;; +A266;YI SYLLABLE NGUO;Lo;0;L;;;;;N;;;;; +A267;YI SYLLABLE NGOT;Lo;0;L;;;;;N;;;;; +A268;YI SYLLABLE NGOX;Lo;0;L;;;;;N;;;;; +A269;YI SYLLABLE NGO;Lo;0;L;;;;;N;;;;; +A26A;YI SYLLABLE NGOP;Lo;0;L;;;;;N;;;;; +A26B;YI SYLLABLE NGEX;Lo;0;L;;;;;N;;;;; +A26C;YI SYLLABLE NGE;Lo;0;L;;;;;N;;;;; +A26D;YI SYLLABLE NGEP;Lo;0;L;;;;;N;;;;; +A26E;YI SYLLABLE HIT;Lo;0;L;;;;;N;;;;; +A26F;YI SYLLABLE HIEX;Lo;0;L;;;;;N;;;;; +A270;YI SYLLABLE HIE;Lo;0;L;;;;;N;;;;; +A271;YI SYLLABLE HAT;Lo;0;L;;;;;N;;;;; +A272;YI SYLLABLE HAX;Lo;0;L;;;;;N;;;;; +A273;YI SYLLABLE HA;Lo;0;L;;;;;N;;;;; +A274;YI SYLLABLE HAP;Lo;0;L;;;;;N;;;;; +A275;YI SYLLABLE HUOT;Lo;0;L;;;;;N;;;;; +A276;YI SYLLABLE HUOX;Lo;0;L;;;;;N;;;;; +A277;YI SYLLABLE HUO;Lo;0;L;;;;;N;;;;; +A278;YI SYLLABLE HUOP;Lo;0;L;;;;;N;;;;; +A279;YI SYLLABLE HOT;Lo;0;L;;;;;N;;;;; +A27A;YI SYLLABLE HOX;Lo;0;L;;;;;N;;;;; +A27B;YI SYLLABLE HO;Lo;0;L;;;;;N;;;;; +A27C;YI SYLLABLE HOP;Lo;0;L;;;;;N;;;;; +A27D;YI SYLLABLE HEX;Lo;0;L;;;;;N;;;;; +A27E;YI SYLLABLE HE;Lo;0;L;;;;;N;;;;; +A27F;YI SYLLABLE HEP;Lo;0;L;;;;;N;;;;; +A280;YI SYLLABLE WAT;Lo;0;L;;;;;N;;;;; +A281;YI SYLLABLE WAX;Lo;0;L;;;;;N;;;;; +A282;YI SYLLABLE WA;Lo;0;L;;;;;N;;;;; +A283;YI SYLLABLE WAP;Lo;0;L;;;;;N;;;;; +A284;YI SYLLABLE WUOX;Lo;0;L;;;;;N;;;;; +A285;YI SYLLABLE WUO;Lo;0;L;;;;;N;;;;; +A286;YI SYLLABLE WUOP;Lo;0;L;;;;;N;;;;; +A287;YI SYLLABLE WOX;Lo;0;L;;;;;N;;;;; +A288;YI SYLLABLE WO;Lo;0;L;;;;;N;;;;; +A289;YI SYLLABLE WOP;Lo;0;L;;;;;N;;;;; +A28A;YI SYLLABLE WEX;Lo;0;L;;;;;N;;;;; +A28B;YI SYLLABLE WE;Lo;0;L;;;;;N;;;;; +A28C;YI SYLLABLE WEP;Lo;0;L;;;;;N;;;;; +A28D;YI SYLLABLE ZIT;Lo;0;L;;;;;N;;;;; +A28E;YI SYLLABLE ZIX;Lo;0;L;;;;;N;;;;; +A28F;YI SYLLABLE ZI;Lo;0;L;;;;;N;;;;; +A290;YI SYLLABLE ZIP;Lo;0;L;;;;;N;;;;; +A291;YI SYLLABLE ZIEX;Lo;0;L;;;;;N;;;;; +A292;YI SYLLABLE ZIE;Lo;0;L;;;;;N;;;;; +A293;YI SYLLABLE ZIEP;Lo;0;L;;;;;N;;;;; +A294;YI SYLLABLE ZAT;Lo;0;L;;;;;N;;;;; +A295;YI SYLLABLE ZAX;Lo;0;L;;;;;N;;;;; +A296;YI SYLLABLE ZA;Lo;0;L;;;;;N;;;;; +A297;YI SYLLABLE ZAP;Lo;0;L;;;;;N;;;;; +A298;YI SYLLABLE ZUOX;Lo;0;L;;;;;N;;;;; +A299;YI SYLLABLE ZUO;Lo;0;L;;;;;N;;;;; +A29A;YI SYLLABLE ZUOP;Lo;0;L;;;;;N;;;;; +A29B;YI SYLLABLE ZOT;Lo;0;L;;;;;N;;;;; +A29C;YI SYLLABLE ZOX;Lo;0;L;;;;;N;;;;; +A29D;YI SYLLABLE ZO;Lo;0;L;;;;;N;;;;; +A29E;YI SYLLABLE ZOP;Lo;0;L;;;;;N;;;;; +A29F;YI SYLLABLE ZEX;Lo;0;L;;;;;N;;;;; +A2A0;YI SYLLABLE ZE;Lo;0;L;;;;;N;;;;; +A2A1;YI SYLLABLE ZEP;Lo;0;L;;;;;N;;;;; +A2A2;YI SYLLABLE ZUT;Lo;0;L;;;;;N;;;;; +A2A3;YI SYLLABLE ZUX;Lo;0;L;;;;;N;;;;; +A2A4;YI SYLLABLE ZU;Lo;0;L;;;;;N;;;;; +A2A5;YI SYLLABLE ZUP;Lo;0;L;;;;;N;;;;; +A2A6;YI SYLLABLE ZURX;Lo;0;L;;;;;N;;;;; +A2A7;YI SYLLABLE ZUR;Lo;0;L;;;;;N;;;;; +A2A8;YI SYLLABLE ZYT;Lo;0;L;;;;;N;;;;; +A2A9;YI SYLLABLE ZYX;Lo;0;L;;;;;N;;;;; +A2AA;YI SYLLABLE ZY;Lo;0;L;;;;;N;;;;; +A2AB;YI SYLLABLE ZYP;Lo;0;L;;;;;N;;;;; +A2AC;YI SYLLABLE ZYRX;Lo;0;L;;;;;N;;;;; +A2AD;YI SYLLABLE ZYR;Lo;0;L;;;;;N;;;;; +A2AE;YI SYLLABLE CIT;Lo;0;L;;;;;N;;;;; +A2AF;YI SYLLABLE CIX;Lo;0;L;;;;;N;;;;; +A2B0;YI SYLLABLE CI;Lo;0;L;;;;;N;;;;; +A2B1;YI SYLLABLE CIP;Lo;0;L;;;;;N;;;;; +A2B2;YI SYLLABLE CIET;Lo;0;L;;;;;N;;;;; +A2B3;YI SYLLABLE CIEX;Lo;0;L;;;;;N;;;;; +A2B4;YI SYLLABLE CIE;Lo;0;L;;;;;N;;;;; +A2B5;YI SYLLABLE CIEP;Lo;0;L;;;;;N;;;;; +A2B6;YI SYLLABLE CAT;Lo;0;L;;;;;N;;;;; +A2B7;YI SYLLABLE CAX;Lo;0;L;;;;;N;;;;; +A2B8;YI SYLLABLE CA;Lo;0;L;;;;;N;;;;; +A2B9;YI SYLLABLE CAP;Lo;0;L;;;;;N;;;;; +A2BA;YI SYLLABLE CUOX;Lo;0;L;;;;;N;;;;; +A2BB;YI SYLLABLE CUO;Lo;0;L;;;;;N;;;;; +A2BC;YI SYLLABLE CUOP;Lo;0;L;;;;;N;;;;; +A2BD;YI SYLLABLE COT;Lo;0;L;;;;;N;;;;; +A2BE;YI SYLLABLE COX;Lo;0;L;;;;;N;;;;; +A2BF;YI SYLLABLE CO;Lo;0;L;;;;;N;;;;; +A2C0;YI SYLLABLE COP;Lo;0;L;;;;;N;;;;; +A2C1;YI SYLLABLE CEX;Lo;0;L;;;;;N;;;;; +A2C2;YI SYLLABLE CE;Lo;0;L;;;;;N;;;;; +A2C3;YI SYLLABLE CEP;Lo;0;L;;;;;N;;;;; +A2C4;YI SYLLABLE CUT;Lo;0;L;;;;;N;;;;; +A2C5;YI SYLLABLE CUX;Lo;0;L;;;;;N;;;;; +A2C6;YI SYLLABLE CU;Lo;0;L;;;;;N;;;;; +A2C7;YI SYLLABLE CUP;Lo;0;L;;;;;N;;;;; +A2C8;YI SYLLABLE CURX;Lo;0;L;;;;;N;;;;; +A2C9;YI SYLLABLE CUR;Lo;0;L;;;;;N;;;;; +A2CA;YI SYLLABLE CYT;Lo;0;L;;;;;N;;;;; +A2CB;YI SYLLABLE CYX;Lo;0;L;;;;;N;;;;; +A2CC;YI SYLLABLE CY;Lo;0;L;;;;;N;;;;; +A2CD;YI SYLLABLE CYP;Lo;0;L;;;;;N;;;;; +A2CE;YI SYLLABLE CYRX;Lo;0;L;;;;;N;;;;; +A2CF;YI SYLLABLE CYR;Lo;0;L;;;;;N;;;;; +A2D0;YI SYLLABLE ZZIT;Lo;0;L;;;;;N;;;;; +A2D1;YI SYLLABLE ZZIX;Lo;0;L;;;;;N;;;;; +A2D2;YI SYLLABLE ZZI;Lo;0;L;;;;;N;;;;; +A2D3;YI SYLLABLE ZZIP;Lo;0;L;;;;;N;;;;; +A2D4;YI SYLLABLE ZZIET;Lo;0;L;;;;;N;;;;; +A2D5;YI SYLLABLE ZZIEX;Lo;0;L;;;;;N;;;;; +A2D6;YI SYLLABLE ZZIE;Lo;0;L;;;;;N;;;;; +A2D7;YI SYLLABLE ZZIEP;Lo;0;L;;;;;N;;;;; +A2D8;YI SYLLABLE ZZAT;Lo;0;L;;;;;N;;;;; +A2D9;YI SYLLABLE ZZAX;Lo;0;L;;;;;N;;;;; +A2DA;YI SYLLABLE ZZA;Lo;0;L;;;;;N;;;;; +A2DB;YI SYLLABLE ZZAP;Lo;0;L;;;;;N;;;;; +A2DC;YI SYLLABLE ZZOX;Lo;0;L;;;;;N;;;;; +A2DD;YI SYLLABLE ZZO;Lo;0;L;;;;;N;;;;; +A2DE;YI SYLLABLE ZZOP;Lo;0;L;;;;;N;;;;; +A2DF;YI SYLLABLE ZZEX;Lo;0;L;;;;;N;;;;; +A2E0;YI SYLLABLE ZZE;Lo;0;L;;;;;N;;;;; +A2E1;YI SYLLABLE ZZEP;Lo;0;L;;;;;N;;;;; +A2E2;YI SYLLABLE ZZUX;Lo;0;L;;;;;N;;;;; +A2E3;YI SYLLABLE ZZU;Lo;0;L;;;;;N;;;;; +A2E4;YI SYLLABLE ZZUP;Lo;0;L;;;;;N;;;;; +A2E5;YI SYLLABLE ZZURX;Lo;0;L;;;;;N;;;;; +A2E6;YI SYLLABLE ZZUR;Lo;0;L;;;;;N;;;;; +A2E7;YI SYLLABLE ZZYT;Lo;0;L;;;;;N;;;;; +A2E8;YI SYLLABLE ZZYX;Lo;0;L;;;;;N;;;;; +A2E9;YI SYLLABLE ZZY;Lo;0;L;;;;;N;;;;; +A2EA;YI SYLLABLE ZZYP;Lo;0;L;;;;;N;;;;; +A2EB;YI SYLLABLE ZZYRX;Lo;0;L;;;;;N;;;;; +A2EC;YI SYLLABLE ZZYR;Lo;0;L;;;;;N;;;;; +A2ED;YI SYLLABLE NZIT;Lo;0;L;;;;;N;;;;; +A2EE;YI SYLLABLE NZIX;Lo;0;L;;;;;N;;;;; +A2EF;YI SYLLABLE NZI;Lo;0;L;;;;;N;;;;; +A2F0;YI SYLLABLE NZIP;Lo;0;L;;;;;N;;;;; +A2F1;YI SYLLABLE NZIEX;Lo;0;L;;;;;N;;;;; +A2F2;YI SYLLABLE NZIE;Lo;0;L;;;;;N;;;;; +A2F3;YI SYLLABLE NZIEP;Lo;0;L;;;;;N;;;;; +A2F4;YI SYLLABLE NZAT;Lo;0;L;;;;;N;;;;; +A2F5;YI SYLLABLE NZAX;Lo;0;L;;;;;N;;;;; +A2F6;YI SYLLABLE NZA;Lo;0;L;;;;;N;;;;; +A2F7;YI SYLLABLE NZAP;Lo;0;L;;;;;N;;;;; +A2F8;YI SYLLABLE NZUOX;Lo;0;L;;;;;N;;;;; +A2F9;YI SYLLABLE NZUO;Lo;0;L;;;;;N;;;;; +A2FA;YI SYLLABLE NZOX;Lo;0;L;;;;;N;;;;; +A2FB;YI SYLLABLE NZOP;Lo;0;L;;;;;N;;;;; +A2FC;YI SYLLABLE NZEX;Lo;0;L;;;;;N;;;;; +A2FD;YI SYLLABLE NZE;Lo;0;L;;;;;N;;;;; +A2FE;YI SYLLABLE NZUX;Lo;0;L;;;;;N;;;;; +A2FF;YI SYLLABLE NZU;Lo;0;L;;;;;N;;;;; +A300;YI SYLLABLE NZUP;Lo;0;L;;;;;N;;;;; +A301;YI SYLLABLE NZURX;Lo;0;L;;;;;N;;;;; +A302;YI SYLLABLE NZUR;Lo;0;L;;;;;N;;;;; +A303;YI SYLLABLE NZYT;Lo;0;L;;;;;N;;;;; +A304;YI SYLLABLE NZYX;Lo;0;L;;;;;N;;;;; +A305;YI SYLLABLE NZY;Lo;0;L;;;;;N;;;;; +A306;YI SYLLABLE NZYP;Lo;0;L;;;;;N;;;;; +A307;YI SYLLABLE NZYRX;Lo;0;L;;;;;N;;;;; +A308;YI SYLLABLE NZYR;Lo;0;L;;;;;N;;;;; +A309;YI SYLLABLE SIT;Lo;0;L;;;;;N;;;;; +A30A;YI SYLLABLE SIX;Lo;0;L;;;;;N;;;;; +A30B;YI SYLLABLE SI;Lo;0;L;;;;;N;;;;; +A30C;YI SYLLABLE SIP;Lo;0;L;;;;;N;;;;; +A30D;YI SYLLABLE SIEX;Lo;0;L;;;;;N;;;;; +A30E;YI SYLLABLE SIE;Lo;0;L;;;;;N;;;;; +A30F;YI SYLLABLE SIEP;Lo;0;L;;;;;N;;;;; +A310;YI SYLLABLE SAT;Lo;0;L;;;;;N;;;;; +A311;YI SYLLABLE SAX;Lo;0;L;;;;;N;;;;; +A312;YI SYLLABLE SA;Lo;0;L;;;;;N;;;;; +A313;YI SYLLABLE SAP;Lo;0;L;;;;;N;;;;; +A314;YI SYLLABLE SUOX;Lo;0;L;;;;;N;;;;; +A315;YI SYLLABLE SUO;Lo;0;L;;;;;N;;;;; +A316;YI SYLLABLE SUOP;Lo;0;L;;;;;N;;;;; +A317;YI SYLLABLE SOT;Lo;0;L;;;;;N;;;;; +A318;YI SYLLABLE SOX;Lo;0;L;;;;;N;;;;; +A319;YI SYLLABLE SO;Lo;0;L;;;;;N;;;;; +A31A;YI SYLLABLE SOP;Lo;0;L;;;;;N;;;;; +A31B;YI SYLLABLE SEX;Lo;0;L;;;;;N;;;;; +A31C;YI SYLLABLE SE;Lo;0;L;;;;;N;;;;; +A31D;YI SYLLABLE SEP;Lo;0;L;;;;;N;;;;; +A31E;YI SYLLABLE SUT;Lo;0;L;;;;;N;;;;; +A31F;YI SYLLABLE SUX;Lo;0;L;;;;;N;;;;; +A320;YI SYLLABLE SU;Lo;0;L;;;;;N;;;;; +A321;YI SYLLABLE SUP;Lo;0;L;;;;;N;;;;; +A322;YI SYLLABLE SURX;Lo;0;L;;;;;N;;;;; +A323;YI SYLLABLE SUR;Lo;0;L;;;;;N;;;;; +A324;YI SYLLABLE SYT;Lo;0;L;;;;;N;;;;; +A325;YI SYLLABLE SYX;Lo;0;L;;;;;N;;;;; +A326;YI SYLLABLE SY;Lo;0;L;;;;;N;;;;; +A327;YI SYLLABLE SYP;Lo;0;L;;;;;N;;;;; +A328;YI SYLLABLE SYRX;Lo;0;L;;;;;N;;;;; +A329;YI SYLLABLE SYR;Lo;0;L;;;;;N;;;;; +A32A;YI SYLLABLE SSIT;Lo;0;L;;;;;N;;;;; +A32B;YI SYLLABLE SSIX;Lo;0;L;;;;;N;;;;; +A32C;YI SYLLABLE SSI;Lo;0;L;;;;;N;;;;; +A32D;YI SYLLABLE SSIP;Lo;0;L;;;;;N;;;;; +A32E;YI SYLLABLE SSIEX;Lo;0;L;;;;;N;;;;; +A32F;YI SYLLABLE SSIE;Lo;0;L;;;;;N;;;;; +A330;YI SYLLABLE SSIEP;Lo;0;L;;;;;N;;;;; +A331;YI SYLLABLE SSAT;Lo;0;L;;;;;N;;;;; +A332;YI SYLLABLE SSAX;Lo;0;L;;;;;N;;;;; +A333;YI SYLLABLE SSA;Lo;0;L;;;;;N;;;;; +A334;YI SYLLABLE SSAP;Lo;0;L;;;;;N;;;;; +A335;YI SYLLABLE SSOT;Lo;0;L;;;;;N;;;;; +A336;YI SYLLABLE SSOX;Lo;0;L;;;;;N;;;;; +A337;YI SYLLABLE SSO;Lo;0;L;;;;;N;;;;; +A338;YI SYLLABLE SSOP;Lo;0;L;;;;;N;;;;; +A339;YI SYLLABLE SSEX;Lo;0;L;;;;;N;;;;; +A33A;YI SYLLABLE SSE;Lo;0;L;;;;;N;;;;; +A33B;YI SYLLABLE SSEP;Lo;0;L;;;;;N;;;;; +A33C;YI SYLLABLE SSUT;Lo;0;L;;;;;N;;;;; +A33D;YI SYLLABLE SSUX;Lo;0;L;;;;;N;;;;; +A33E;YI SYLLABLE SSU;Lo;0;L;;;;;N;;;;; +A33F;YI SYLLABLE SSUP;Lo;0;L;;;;;N;;;;; +A340;YI SYLLABLE SSYT;Lo;0;L;;;;;N;;;;; +A341;YI SYLLABLE SSYX;Lo;0;L;;;;;N;;;;; +A342;YI SYLLABLE SSY;Lo;0;L;;;;;N;;;;; +A343;YI SYLLABLE SSYP;Lo;0;L;;;;;N;;;;; +A344;YI SYLLABLE SSYRX;Lo;0;L;;;;;N;;;;; +A345;YI SYLLABLE SSYR;Lo;0;L;;;;;N;;;;; +A346;YI SYLLABLE ZHAT;Lo;0;L;;;;;N;;;;; +A347;YI SYLLABLE ZHAX;Lo;0;L;;;;;N;;;;; +A348;YI SYLLABLE ZHA;Lo;0;L;;;;;N;;;;; +A349;YI SYLLABLE ZHAP;Lo;0;L;;;;;N;;;;; +A34A;YI SYLLABLE ZHUOX;Lo;0;L;;;;;N;;;;; +A34B;YI SYLLABLE ZHUO;Lo;0;L;;;;;N;;;;; +A34C;YI SYLLABLE ZHUOP;Lo;0;L;;;;;N;;;;; +A34D;YI SYLLABLE ZHOT;Lo;0;L;;;;;N;;;;; +A34E;YI SYLLABLE ZHOX;Lo;0;L;;;;;N;;;;; +A34F;YI SYLLABLE ZHO;Lo;0;L;;;;;N;;;;; +A350;YI SYLLABLE ZHOP;Lo;0;L;;;;;N;;;;; +A351;YI SYLLABLE ZHET;Lo;0;L;;;;;N;;;;; +A352;YI SYLLABLE ZHEX;Lo;0;L;;;;;N;;;;; +A353;YI SYLLABLE ZHE;Lo;0;L;;;;;N;;;;; +A354;YI SYLLABLE ZHEP;Lo;0;L;;;;;N;;;;; +A355;YI SYLLABLE ZHUT;Lo;0;L;;;;;N;;;;; +A356;YI SYLLABLE ZHUX;Lo;0;L;;;;;N;;;;; +A357;YI SYLLABLE ZHU;Lo;0;L;;;;;N;;;;; +A358;YI SYLLABLE ZHUP;Lo;0;L;;;;;N;;;;; +A359;YI SYLLABLE ZHURX;Lo;0;L;;;;;N;;;;; +A35A;YI SYLLABLE ZHUR;Lo;0;L;;;;;N;;;;; +A35B;YI SYLLABLE ZHYT;Lo;0;L;;;;;N;;;;; +A35C;YI SYLLABLE ZHYX;Lo;0;L;;;;;N;;;;; +A35D;YI SYLLABLE ZHY;Lo;0;L;;;;;N;;;;; +A35E;YI SYLLABLE ZHYP;Lo;0;L;;;;;N;;;;; +A35F;YI SYLLABLE ZHYRX;Lo;0;L;;;;;N;;;;; +A360;YI SYLLABLE ZHYR;Lo;0;L;;;;;N;;;;; +A361;YI SYLLABLE CHAT;Lo;0;L;;;;;N;;;;; +A362;YI SYLLABLE CHAX;Lo;0;L;;;;;N;;;;; +A363;YI SYLLABLE CHA;Lo;0;L;;;;;N;;;;; +A364;YI SYLLABLE CHAP;Lo;0;L;;;;;N;;;;; +A365;YI SYLLABLE CHUOT;Lo;0;L;;;;;N;;;;; +A366;YI SYLLABLE CHUOX;Lo;0;L;;;;;N;;;;; +A367;YI SYLLABLE CHUO;Lo;0;L;;;;;N;;;;; +A368;YI SYLLABLE CHUOP;Lo;0;L;;;;;N;;;;; +A369;YI SYLLABLE CHOT;Lo;0;L;;;;;N;;;;; +A36A;YI SYLLABLE CHOX;Lo;0;L;;;;;N;;;;; +A36B;YI SYLLABLE CHO;Lo;0;L;;;;;N;;;;; +A36C;YI SYLLABLE CHOP;Lo;0;L;;;;;N;;;;; +A36D;YI SYLLABLE CHET;Lo;0;L;;;;;N;;;;; +A36E;YI SYLLABLE CHEX;Lo;0;L;;;;;N;;;;; +A36F;YI SYLLABLE CHE;Lo;0;L;;;;;N;;;;; +A370;YI SYLLABLE CHEP;Lo;0;L;;;;;N;;;;; +A371;YI SYLLABLE CHUX;Lo;0;L;;;;;N;;;;; +A372;YI SYLLABLE CHU;Lo;0;L;;;;;N;;;;; +A373;YI SYLLABLE CHUP;Lo;0;L;;;;;N;;;;; +A374;YI SYLLABLE CHURX;Lo;0;L;;;;;N;;;;; +A375;YI SYLLABLE CHUR;Lo;0;L;;;;;N;;;;; +A376;YI SYLLABLE CHYT;Lo;0;L;;;;;N;;;;; +A377;YI SYLLABLE CHYX;Lo;0;L;;;;;N;;;;; +A378;YI SYLLABLE CHY;Lo;0;L;;;;;N;;;;; +A379;YI SYLLABLE CHYP;Lo;0;L;;;;;N;;;;; +A37A;YI SYLLABLE CHYRX;Lo;0;L;;;;;N;;;;; +A37B;YI SYLLABLE CHYR;Lo;0;L;;;;;N;;;;; +A37C;YI SYLLABLE RRAX;Lo;0;L;;;;;N;;;;; +A37D;YI SYLLABLE RRA;Lo;0;L;;;;;N;;;;; +A37E;YI SYLLABLE RRUOX;Lo;0;L;;;;;N;;;;; +A37F;YI SYLLABLE RRUO;Lo;0;L;;;;;N;;;;; +A380;YI SYLLABLE RROT;Lo;0;L;;;;;N;;;;; +A381;YI SYLLABLE RROX;Lo;0;L;;;;;N;;;;; +A382;YI SYLLABLE RRO;Lo;0;L;;;;;N;;;;; +A383;YI SYLLABLE RROP;Lo;0;L;;;;;N;;;;; +A384;YI SYLLABLE RRET;Lo;0;L;;;;;N;;;;; +A385;YI SYLLABLE RREX;Lo;0;L;;;;;N;;;;; +A386;YI SYLLABLE RRE;Lo;0;L;;;;;N;;;;; +A387;YI SYLLABLE RREP;Lo;0;L;;;;;N;;;;; +A388;YI SYLLABLE RRUT;Lo;0;L;;;;;N;;;;; +A389;YI SYLLABLE RRUX;Lo;0;L;;;;;N;;;;; +A38A;YI SYLLABLE RRU;Lo;0;L;;;;;N;;;;; +A38B;YI SYLLABLE RRUP;Lo;0;L;;;;;N;;;;; +A38C;YI SYLLABLE RRURX;Lo;0;L;;;;;N;;;;; +A38D;YI SYLLABLE RRUR;Lo;0;L;;;;;N;;;;; +A38E;YI SYLLABLE RRYT;Lo;0;L;;;;;N;;;;; +A38F;YI SYLLABLE RRYX;Lo;0;L;;;;;N;;;;; +A390;YI SYLLABLE RRY;Lo;0;L;;;;;N;;;;; +A391;YI SYLLABLE RRYP;Lo;0;L;;;;;N;;;;; +A392;YI SYLLABLE RRYRX;Lo;0;L;;;;;N;;;;; +A393;YI SYLLABLE RRYR;Lo;0;L;;;;;N;;;;; +A394;YI SYLLABLE NRAT;Lo;0;L;;;;;N;;;;; +A395;YI SYLLABLE NRAX;Lo;0;L;;;;;N;;;;; +A396;YI SYLLABLE NRA;Lo;0;L;;;;;N;;;;; +A397;YI SYLLABLE NRAP;Lo;0;L;;;;;N;;;;; +A398;YI SYLLABLE NROX;Lo;0;L;;;;;N;;;;; +A399;YI SYLLABLE NRO;Lo;0;L;;;;;N;;;;; +A39A;YI SYLLABLE NROP;Lo;0;L;;;;;N;;;;; +A39B;YI SYLLABLE NRET;Lo;0;L;;;;;N;;;;; +A39C;YI SYLLABLE NREX;Lo;0;L;;;;;N;;;;; +A39D;YI SYLLABLE NRE;Lo;0;L;;;;;N;;;;; +A39E;YI SYLLABLE NREP;Lo;0;L;;;;;N;;;;; +A39F;YI SYLLABLE NRUT;Lo;0;L;;;;;N;;;;; +A3A0;YI SYLLABLE NRUX;Lo;0;L;;;;;N;;;;; +A3A1;YI SYLLABLE NRU;Lo;0;L;;;;;N;;;;; +A3A2;YI SYLLABLE NRUP;Lo;0;L;;;;;N;;;;; +A3A3;YI SYLLABLE NRURX;Lo;0;L;;;;;N;;;;; +A3A4;YI SYLLABLE NRUR;Lo;0;L;;;;;N;;;;; +A3A5;YI SYLLABLE NRYT;Lo;0;L;;;;;N;;;;; +A3A6;YI SYLLABLE NRYX;Lo;0;L;;;;;N;;;;; +A3A7;YI SYLLABLE NRY;Lo;0;L;;;;;N;;;;; +A3A8;YI SYLLABLE NRYP;Lo;0;L;;;;;N;;;;; +A3A9;YI SYLLABLE NRYRX;Lo;0;L;;;;;N;;;;; +A3AA;YI SYLLABLE NRYR;Lo;0;L;;;;;N;;;;; +A3AB;YI SYLLABLE SHAT;Lo;0;L;;;;;N;;;;; +A3AC;YI SYLLABLE SHAX;Lo;0;L;;;;;N;;;;; +A3AD;YI SYLLABLE SHA;Lo;0;L;;;;;N;;;;; +A3AE;YI SYLLABLE SHAP;Lo;0;L;;;;;N;;;;; +A3AF;YI SYLLABLE SHUOX;Lo;0;L;;;;;N;;;;; +A3B0;YI SYLLABLE SHUO;Lo;0;L;;;;;N;;;;; +A3B1;YI SYLLABLE SHUOP;Lo;0;L;;;;;N;;;;; +A3B2;YI SYLLABLE SHOT;Lo;0;L;;;;;N;;;;; +A3B3;YI SYLLABLE SHOX;Lo;0;L;;;;;N;;;;; +A3B4;YI SYLLABLE SHO;Lo;0;L;;;;;N;;;;; +A3B5;YI SYLLABLE SHOP;Lo;0;L;;;;;N;;;;; +A3B6;YI SYLLABLE SHET;Lo;0;L;;;;;N;;;;; +A3B7;YI SYLLABLE SHEX;Lo;0;L;;;;;N;;;;; +A3B8;YI SYLLABLE SHE;Lo;0;L;;;;;N;;;;; +A3B9;YI SYLLABLE SHEP;Lo;0;L;;;;;N;;;;; +A3BA;YI SYLLABLE SHUT;Lo;0;L;;;;;N;;;;; +A3BB;YI SYLLABLE SHUX;Lo;0;L;;;;;N;;;;; +A3BC;YI SYLLABLE SHU;Lo;0;L;;;;;N;;;;; +A3BD;YI SYLLABLE SHUP;Lo;0;L;;;;;N;;;;; +A3BE;YI SYLLABLE SHURX;Lo;0;L;;;;;N;;;;; +A3BF;YI SYLLABLE SHUR;Lo;0;L;;;;;N;;;;; +A3C0;YI SYLLABLE SHYT;Lo;0;L;;;;;N;;;;; +A3C1;YI SYLLABLE SHYX;Lo;0;L;;;;;N;;;;; +A3C2;YI SYLLABLE SHY;Lo;0;L;;;;;N;;;;; +A3C3;YI SYLLABLE SHYP;Lo;0;L;;;;;N;;;;; +A3C4;YI SYLLABLE SHYRX;Lo;0;L;;;;;N;;;;; +A3C5;YI SYLLABLE SHYR;Lo;0;L;;;;;N;;;;; +A3C6;YI SYLLABLE RAT;Lo;0;L;;;;;N;;;;; +A3C7;YI SYLLABLE RAX;Lo;0;L;;;;;N;;;;; +A3C8;YI SYLLABLE RA;Lo;0;L;;;;;N;;;;; +A3C9;YI SYLLABLE RAP;Lo;0;L;;;;;N;;;;; +A3CA;YI SYLLABLE RUOX;Lo;0;L;;;;;N;;;;; +A3CB;YI SYLLABLE RUO;Lo;0;L;;;;;N;;;;; +A3CC;YI SYLLABLE RUOP;Lo;0;L;;;;;N;;;;; +A3CD;YI SYLLABLE ROT;Lo;0;L;;;;;N;;;;; +A3CE;YI SYLLABLE ROX;Lo;0;L;;;;;N;;;;; +A3CF;YI SYLLABLE RO;Lo;0;L;;;;;N;;;;; +A3D0;YI SYLLABLE ROP;Lo;0;L;;;;;N;;;;; +A3D1;YI SYLLABLE REX;Lo;0;L;;;;;N;;;;; +A3D2;YI SYLLABLE RE;Lo;0;L;;;;;N;;;;; +A3D3;YI SYLLABLE REP;Lo;0;L;;;;;N;;;;; +A3D4;YI SYLLABLE RUT;Lo;0;L;;;;;N;;;;; +A3D5;YI SYLLABLE RUX;Lo;0;L;;;;;N;;;;; +A3D6;YI SYLLABLE RU;Lo;0;L;;;;;N;;;;; +A3D7;YI SYLLABLE RUP;Lo;0;L;;;;;N;;;;; +A3D8;YI SYLLABLE RURX;Lo;0;L;;;;;N;;;;; +A3D9;YI SYLLABLE RUR;Lo;0;L;;;;;N;;;;; +A3DA;YI SYLLABLE RYT;Lo;0;L;;;;;N;;;;; +A3DB;YI SYLLABLE RYX;Lo;0;L;;;;;N;;;;; +A3DC;YI SYLLABLE RY;Lo;0;L;;;;;N;;;;; +A3DD;YI SYLLABLE RYP;Lo;0;L;;;;;N;;;;; +A3DE;YI SYLLABLE RYRX;Lo;0;L;;;;;N;;;;; +A3DF;YI SYLLABLE RYR;Lo;0;L;;;;;N;;;;; +A3E0;YI SYLLABLE JIT;Lo;0;L;;;;;N;;;;; +A3E1;YI SYLLABLE JIX;Lo;0;L;;;;;N;;;;; +A3E2;YI SYLLABLE JI;Lo;0;L;;;;;N;;;;; +A3E3;YI SYLLABLE JIP;Lo;0;L;;;;;N;;;;; +A3E4;YI SYLLABLE JIET;Lo;0;L;;;;;N;;;;; +A3E5;YI SYLLABLE JIEX;Lo;0;L;;;;;N;;;;; +A3E6;YI SYLLABLE JIE;Lo;0;L;;;;;N;;;;; +A3E7;YI SYLLABLE JIEP;Lo;0;L;;;;;N;;;;; +A3E8;YI SYLLABLE JUOT;Lo;0;L;;;;;N;;;;; +A3E9;YI SYLLABLE JUOX;Lo;0;L;;;;;N;;;;; +A3EA;YI SYLLABLE JUO;Lo;0;L;;;;;N;;;;; +A3EB;YI SYLLABLE JUOP;Lo;0;L;;;;;N;;;;; +A3EC;YI SYLLABLE JOT;Lo;0;L;;;;;N;;;;; +A3ED;YI SYLLABLE JOX;Lo;0;L;;;;;N;;;;; +A3EE;YI SYLLABLE JO;Lo;0;L;;;;;N;;;;; +A3EF;YI SYLLABLE JOP;Lo;0;L;;;;;N;;;;; +A3F0;YI SYLLABLE JUT;Lo;0;L;;;;;N;;;;; +A3F1;YI SYLLABLE JUX;Lo;0;L;;;;;N;;;;; +A3F2;YI SYLLABLE JU;Lo;0;L;;;;;N;;;;; +A3F3;YI SYLLABLE JUP;Lo;0;L;;;;;N;;;;; +A3F4;YI SYLLABLE JURX;Lo;0;L;;;;;N;;;;; +A3F5;YI SYLLABLE JUR;Lo;0;L;;;;;N;;;;; +A3F6;YI SYLLABLE JYT;Lo;0;L;;;;;N;;;;; +A3F7;YI SYLLABLE JYX;Lo;0;L;;;;;N;;;;; +A3F8;YI SYLLABLE JY;Lo;0;L;;;;;N;;;;; +A3F9;YI SYLLABLE JYP;Lo;0;L;;;;;N;;;;; +A3FA;YI SYLLABLE JYRX;Lo;0;L;;;;;N;;;;; +A3FB;YI SYLLABLE JYR;Lo;0;L;;;;;N;;;;; +A3FC;YI SYLLABLE QIT;Lo;0;L;;;;;N;;;;; +A3FD;YI SYLLABLE QIX;Lo;0;L;;;;;N;;;;; +A3FE;YI SYLLABLE QI;Lo;0;L;;;;;N;;;;; +A3FF;YI SYLLABLE QIP;Lo;0;L;;;;;N;;;;; +A400;YI SYLLABLE QIET;Lo;0;L;;;;;N;;;;; +A401;YI SYLLABLE QIEX;Lo;0;L;;;;;N;;;;; +A402;YI SYLLABLE QIE;Lo;0;L;;;;;N;;;;; +A403;YI SYLLABLE QIEP;Lo;0;L;;;;;N;;;;; +A404;YI SYLLABLE QUOT;Lo;0;L;;;;;N;;;;; +A405;YI SYLLABLE QUOX;Lo;0;L;;;;;N;;;;; +A406;YI SYLLABLE QUO;Lo;0;L;;;;;N;;;;; +A407;YI SYLLABLE QUOP;Lo;0;L;;;;;N;;;;; +A408;YI SYLLABLE QOT;Lo;0;L;;;;;N;;;;; +A409;YI SYLLABLE QOX;Lo;0;L;;;;;N;;;;; +A40A;YI SYLLABLE QO;Lo;0;L;;;;;N;;;;; +A40B;YI SYLLABLE QOP;Lo;0;L;;;;;N;;;;; +A40C;YI SYLLABLE QUT;Lo;0;L;;;;;N;;;;; +A40D;YI SYLLABLE QUX;Lo;0;L;;;;;N;;;;; +A40E;YI SYLLABLE QU;Lo;0;L;;;;;N;;;;; +A40F;YI SYLLABLE QUP;Lo;0;L;;;;;N;;;;; +A410;YI SYLLABLE QURX;Lo;0;L;;;;;N;;;;; +A411;YI SYLLABLE QUR;Lo;0;L;;;;;N;;;;; +A412;YI SYLLABLE QYT;Lo;0;L;;;;;N;;;;; +A413;YI SYLLABLE QYX;Lo;0;L;;;;;N;;;;; +A414;YI SYLLABLE QY;Lo;0;L;;;;;N;;;;; +A415;YI SYLLABLE QYP;Lo;0;L;;;;;N;;;;; +A416;YI SYLLABLE QYRX;Lo;0;L;;;;;N;;;;; +A417;YI SYLLABLE QYR;Lo;0;L;;;;;N;;;;; +A418;YI SYLLABLE JJIT;Lo;0;L;;;;;N;;;;; +A419;YI SYLLABLE JJIX;Lo;0;L;;;;;N;;;;; +A41A;YI SYLLABLE JJI;Lo;0;L;;;;;N;;;;; +A41B;YI SYLLABLE JJIP;Lo;0;L;;;;;N;;;;; +A41C;YI SYLLABLE JJIET;Lo;0;L;;;;;N;;;;; +A41D;YI SYLLABLE JJIEX;Lo;0;L;;;;;N;;;;; +A41E;YI SYLLABLE JJIE;Lo;0;L;;;;;N;;;;; +A41F;YI SYLLABLE JJIEP;Lo;0;L;;;;;N;;;;; +A420;YI SYLLABLE JJUOX;Lo;0;L;;;;;N;;;;; +A421;YI SYLLABLE JJUO;Lo;0;L;;;;;N;;;;; +A422;YI SYLLABLE JJUOP;Lo;0;L;;;;;N;;;;; +A423;YI SYLLABLE JJOT;Lo;0;L;;;;;N;;;;; +A424;YI SYLLABLE JJOX;Lo;0;L;;;;;N;;;;; +A425;YI SYLLABLE JJO;Lo;0;L;;;;;N;;;;; +A426;YI SYLLABLE JJOP;Lo;0;L;;;;;N;;;;; +A427;YI SYLLABLE JJUT;Lo;0;L;;;;;N;;;;; +A428;YI SYLLABLE JJUX;Lo;0;L;;;;;N;;;;; +A429;YI SYLLABLE JJU;Lo;0;L;;;;;N;;;;; +A42A;YI SYLLABLE JJUP;Lo;0;L;;;;;N;;;;; +A42B;YI SYLLABLE JJURX;Lo;0;L;;;;;N;;;;; +A42C;YI SYLLABLE JJUR;Lo;0;L;;;;;N;;;;; +A42D;YI SYLLABLE JJYT;Lo;0;L;;;;;N;;;;; +A42E;YI SYLLABLE JJYX;Lo;0;L;;;;;N;;;;; +A42F;YI SYLLABLE JJY;Lo;0;L;;;;;N;;;;; +A430;YI SYLLABLE JJYP;Lo;0;L;;;;;N;;;;; +A431;YI SYLLABLE NJIT;Lo;0;L;;;;;N;;;;; +A432;YI SYLLABLE NJIX;Lo;0;L;;;;;N;;;;; +A433;YI SYLLABLE NJI;Lo;0;L;;;;;N;;;;; +A434;YI SYLLABLE NJIP;Lo;0;L;;;;;N;;;;; +A435;YI SYLLABLE NJIET;Lo;0;L;;;;;N;;;;; +A436;YI SYLLABLE NJIEX;Lo;0;L;;;;;N;;;;; +A437;YI SYLLABLE NJIE;Lo;0;L;;;;;N;;;;; +A438;YI SYLLABLE NJIEP;Lo;0;L;;;;;N;;;;; +A439;YI SYLLABLE NJUOX;Lo;0;L;;;;;N;;;;; +A43A;YI SYLLABLE NJUO;Lo;0;L;;;;;N;;;;; +A43B;YI SYLLABLE NJOT;Lo;0;L;;;;;N;;;;; +A43C;YI SYLLABLE NJOX;Lo;0;L;;;;;N;;;;; +A43D;YI SYLLABLE NJO;Lo;0;L;;;;;N;;;;; +A43E;YI SYLLABLE NJOP;Lo;0;L;;;;;N;;;;; +A43F;YI SYLLABLE NJUX;Lo;0;L;;;;;N;;;;; +A440;YI SYLLABLE NJU;Lo;0;L;;;;;N;;;;; +A441;YI SYLLABLE NJUP;Lo;0;L;;;;;N;;;;; +A442;YI SYLLABLE NJURX;Lo;0;L;;;;;N;;;;; +A443;YI SYLLABLE NJUR;Lo;0;L;;;;;N;;;;; +A444;YI SYLLABLE NJYT;Lo;0;L;;;;;N;;;;; +A445;YI SYLLABLE NJYX;Lo;0;L;;;;;N;;;;; +A446;YI SYLLABLE NJY;Lo;0;L;;;;;N;;;;; +A447;YI SYLLABLE NJYP;Lo;0;L;;;;;N;;;;; +A448;YI SYLLABLE NJYRX;Lo;0;L;;;;;N;;;;; +A449;YI SYLLABLE NJYR;Lo;0;L;;;;;N;;;;; +A44A;YI SYLLABLE NYIT;Lo;0;L;;;;;N;;;;; +A44B;YI SYLLABLE NYIX;Lo;0;L;;;;;N;;;;; +A44C;YI SYLLABLE NYI;Lo;0;L;;;;;N;;;;; +A44D;YI SYLLABLE NYIP;Lo;0;L;;;;;N;;;;; +A44E;YI SYLLABLE NYIET;Lo;0;L;;;;;N;;;;; +A44F;YI SYLLABLE NYIEX;Lo;0;L;;;;;N;;;;; +A450;YI SYLLABLE NYIE;Lo;0;L;;;;;N;;;;; +A451;YI SYLLABLE NYIEP;Lo;0;L;;;;;N;;;;; +A452;YI SYLLABLE NYUOX;Lo;0;L;;;;;N;;;;; +A453;YI SYLLABLE NYUO;Lo;0;L;;;;;N;;;;; +A454;YI SYLLABLE NYUOP;Lo;0;L;;;;;N;;;;; +A455;YI SYLLABLE NYOT;Lo;0;L;;;;;N;;;;; +A456;YI SYLLABLE NYOX;Lo;0;L;;;;;N;;;;; +A457;YI SYLLABLE NYO;Lo;0;L;;;;;N;;;;; +A458;YI SYLLABLE NYOP;Lo;0;L;;;;;N;;;;; +A459;YI SYLLABLE NYUT;Lo;0;L;;;;;N;;;;; +A45A;YI SYLLABLE NYUX;Lo;0;L;;;;;N;;;;; +A45B;YI SYLLABLE NYU;Lo;0;L;;;;;N;;;;; +A45C;YI SYLLABLE NYUP;Lo;0;L;;;;;N;;;;; +A45D;YI SYLLABLE XIT;Lo;0;L;;;;;N;;;;; +A45E;YI SYLLABLE XIX;Lo;0;L;;;;;N;;;;; +A45F;YI SYLLABLE XI;Lo;0;L;;;;;N;;;;; +A460;YI SYLLABLE XIP;Lo;0;L;;;;;N;;;;; +A461;YI SYLLABLE XIET;Lo;0;L;;;;;N;;;;; +A462;YI SYLLABLE XIEX;Lo;0;L;;;;;N;;;;; +A463;YI SYLLABLE XIE;Lo;0;L;;;;;N;;;;; +A464;YI SYLLABLE XIEP;Lo;0;L;;;;;N;;;;; +A465;YI SYLLABLE XUOX;Lo;0;L;;;;;N;;;;; +A466;YI SYLLABLE XUO;Lo;0;L;;;;;N;;;;; +A467;YI SYLLABLE XOT;Lo;0;L;;;;;N;;;;; +A468;YI SYLLABLE XOX;Lo;0;L;;;;;N;;;;; +A469;YI SYLLABLE XO;Lo;0;L;;;;;N;;;;; +A46A;YI SYLLABLE XOP;Lo;0;L;;;;;N;;;;; +A46B;YI SYLLABLE XYT;Lo;0;L;;;;;N;;;;; +A46C;YI SYLLABLE XYX;Lo;0;L;;;;;N;;;;; +A46D;YI SYLLABLE XY;Lo;0;L;;;;;N;;;;; +A46E;YI SYLLABLE XYP;Lo;0;L;;;;;N;;;;; +A46F;YI SYLLABLE XYRX;Lo;0;L;;;;;N;;;;; +A470;YI SYLLABLE XYR;Lo;0;L;;;;;N;;;;; +A471;YI SYLLABLE YIT;Lo;0;L;;;;;N;;;;; +A472;YI SYLLABLE YIX;Lo;0;L;;;;;N;;;;; +A473;YI SYLLABLE YI;Lo;0;L;;;;;N;;;;; +A474;YI SYLLABLE YIP;Lo;0;L;;;;;N;;;;; +A475;YI SYLLABLE YIET;Lo;0;L;;;;;N;;;;; +A476;YI SYLLABLE YIEX;Lo;0;L;;;;;N;;;;; +A477;YI SYLLABLE YIE;Lo;0;L;;;;;N;;;;; +A478;YI SYLLABLE YIEP;Lo;0;L;;;;;N;;;;; +A479;YI SYLLABLE YUOT;Lo;0;L;;;;;N;;;;; +A47A;YI SYLLABLE YUOX;Lo;0;L;;;;;N;;;;; +A47B;YI SYLLABLE YUO;Lo;0;L;;;;;N;;;;; +A47C;YI SYLLABLE YUOP;Lo;0;L;;;;;N;;;;; +A47D;YI SYLLABLE YOT;Lo;0;L;;;;;N;;;;; +A47E;YI SYLLABLE YOX;Lo;0;L;;;;;N;;;;; +A47F;YI SYLLABLE YO;Lo;0;L;;;;;N;;;;; +A480;YI SYLLABLE YOP;Lo;0;L;;;;;N;;;;; +A481;YI SYLLABLE YUT;Lo;0;L;;;;;N;;;;; +A482;YI SYLLABLE YUX;Lo;0;L;;;;;N;;;;; +A483;YI SYLLABLE YU;Lo;0;L;;;;;N;;;;; +A484;YI SYLLABLE YUP;Lo;0;L;;;;;N;;;;; +A485;YI SYLLABLE YURX;Lo;0;L;;;;;N;;;;; +A486;YI SYLLABLE YUR;Lo;0;L;;;;;N;;;;; +A487;YI SYLLABLE YYT;Lo;0;L;;;;;N;;;;; +A488;YI SYLLABLE YYX;Lo;0;L;;;;;N;;;;; +A489;YI SYLLABLE YY;Lo;0;L;;;;;N;;;;; +A48A;YI SYLLABLE YYP;Lo;0;L;;;;;N;;;;; +A48B;YI SYLLABLE YYRX;Lo;0;L;;;;;N;;;;; +A48C;YI SYLLABLE YYR;Lo;0;L;;;;;N;;;;; +A490;YI RADICAL QOT;So;0;ON;;;;;N;;;;; +A491;YI RADICAL LI;So;0;ON;;;;;N;;;;; +A492;YI RADICAL KIT;So;0;ON;;;;;N;;;;; +A493;YI RADICAL NYIP;So;0;ON;;;;;N;;;;; +A494;YI RADICAL CYP;So;0;ON;;;;;N;;;;; +A495;YI RADICAL SSI;So;0;ON;;;;;N;;;;; +A496;YI RADICAL GGOP;So;0;ON;;;;;N;;;;; +A497;YI RADICAL GEP;So;0;ON;;;;;N;;;;; +A498;YI RADICAL MI;So;0;ON;;;;;N;;;;; +A499;YI RADICAL HXIT;So;0;ON;;;;;N;;;;; +A49A;YI RADICAL LYR;So;0;ON;;;;;N;;;;; +A49B;YI RADICAL BBUT;So;0;ON;;;;;N;;;;; +A49C;YI RADICAL MOP;So;0;ON;;;;;N;;;;; +A49D;YI RADICAL YO;So;0;ON;;;;;N;;;;; +A49E;YI RADICAL PUT;So;0;ON;;;;;N;;;;; +A49F;YI RADICAL HXUO;So;0;ON;;;;;N;;;;; +A4A0;YI RADICAL TAT;So;0;ON;;;;;N;;;;; +A4A1;YI RADICAL GA;So;0;ON;;;;;N;;;;; +A4A2;YI RADICAL ZUP;So;0;ON;;;;;N;;;;; +A4A3;YI RADICAL CYT;So;0;ON;;;;;N;;;;; +A4A4;YI RADICAL DDUR;So;0;ON;;;;;N;;;;; +A4A5;YI RADICAL BUR;So;0;ON;;;;;N;;;;; +A4A6;YI RADICAL GGUO;So;0;ON;;;;;N;;;;; +A4A7;YI RADICAL NYOP;So;0;ON;;;;;N;;;;; +A4A8;YI RADICAL TU;So;0;ON;;;;;N;;;;; +A4A9;YI RADICAL OP;So;0;ON;;;;;N;;;;; +A4AA;YI RADICAL JJUT;So;0;ON;;;;;N;;;;; +A4AB;YI RADICAL ZOT;So;0;ON;;;;;N;;;;; +A4AC;YI RADICAL PYT;So;0;ON;;;;;N;;;;; +A4AD;YI RADICAL HMO;So;0;ON;;;;;N;;;;; +A4AE;YI RADICAL YIT;So;0;ON;;;;;N;;;;; +A4AF;YI RADICAL VUR;So;0;ON;;;;;N;;;;; +A4B0;YI RADICAL SHY;So;0;ON;;;;;N;;;;; +A4B1;YI RADICAL VEP;So;0;ON;;;;;N;;;;; +A4B2;YI RADICAL ZA;So;0;ON;;;;;N;;;;; +A4B3;YI RADICAL JO;So;0;ON;;;;;N;;;;; +A4B4;YI RADICAL NZUP;So;0;ON;;;;;N;;;;; +A4B5;YI RADICAL JJY;So;0;ON;;;;;N;;;;; +A4B6;YI RADICAL GOT;So;0;ON;;;;;N;;;;; +A4B7;YI RADICAL JJIE;So;0;ON;;;;;N;;;;; +A4B8;YI RADICAL WO;So;0;ON;;;;;N;;;;; +A4B9;YI RADICAL DU;So;0;ON;;;;;N;;;;; +A4BA;YI RADICAL SHUR;So;0;ON;;;;;N;;;;; +A4BB;YI RADICAL LIE;So;0;ON;;;;;N;;;;; +A4BC;YI RADICAL CY;So;0;ON;;;;;N;;;;; +A4BD;YI RADICAL CUOP;So;0;ON;;;;;N;;;;; +A4BE;YI RADICAL CIP;So;0;ON;;;;;N;;;;; +A4BF;YI RADICAL HXOP;So;0;ON;;;;;N;;;;; +A4C0;YI RADICAL SHAT;So;0;ON;;;;;N;;;;; +A4C1;YI RADICAL ZUR;So;0;ON;;;;;N;;;;; +A4C2;YI RADICAL SHOP;So;0;ON;;;;;N;;;;; +A4C3;YI RADICAL CHE;So;0;ON;;;;;N;;;;; +A4C4;YI RADICAL ZZIET;So;0;ON;;;;;N;;;;; +A4C5;YI RADICAL NBIE;So;0;ON;;;;;N;;;;; +A4C6;YI RADICAL KE;So;0;ON;;;;;N;;;;; +A4D0;LISU LETTER BA;Lo;0;L;;;;;N;;;;; +A4D1;LISU LETTER PA;Lo;0;L;;;;;N;;;;; +A4D2;LISU LETTER PHA;Lo;0;L;;;;;N;;;;; +A4D3;LISU LETTER DA;Lo;0;L;;;;;N;;;;; +A4D4;LISU LETTER TA;Lo;0;L;;;;;N;;;;; +A4D5;LISU LETTER THA;Lo;0;L;;;;;N;;;;; +A4D6;LISU LETTER GA;Lo;0;L;;;;;N;;;;; +A4D7;LISU LETTER KA;Lo;0;L;;;;;N;;;;; +A4D8;LISU LETTER KHA;Lo;0;L;;;;;N;;;;; +A4D9;LISU LETTER JA;Lo;0;L;;;;;N;;;;; +A4DA;LISU LETTER CA;Lo;0;L;;;;;N;;;;; +A4DB;LISU LETTER CHA;Lo;0;L;;;;;N;;;;; +A4DC;LISU LETTER DZA;Lo;0;L;;;;;N;;;;; +A4DD;LISU LETTER TSA;Lo;0;L;;;;;N;;;;; +A4DE;LISU LETTER TSHA;Lo;0;L;;;;;N;;;;; +A4DF;LISU LETTER MA;Lo;0;L;;;;;N;;;;; +A4E0;LISU LETTER NA;Lo;0;L;;;;;N;;;;; +A4E1;LISU LETTER LA;Lo;0;L;;;;;N;;;;; +A4E2;LISU LETTER SA;Lo;0;L;;;;;N;;;;; +A4E3;LISU LETTER ZHA;Lo;0;L;;;;;N;;;;; +A4E4;LISU LETTER ZA;Lo;0;L;;;;;N;;;;; +A4E5;LISU LETTER NGA;Lo;0;L;;;;;N;;;;; +A4E6;LISU LETTER HA;Lo;0;L;;;;;N;;;;; +A4E7;LISU LETTER XA;Lo;0;L;;;;;N;;;;; +A4E8;LISU LETTER HHA;Lo;0;L;;;;;N;;;;; +A4E9;LISU LETTER FA;Lo;0;L;;;;;N;;;;; +A4EA;LISU LETTER WA;Lo;0;L;;;;;N;;;;; +A4EB;LISU LETTER SHA;Lo;0;L;;;;;N;;;;; +A4EC;LISU LETTER YA;Lo;0;L;;;;;N;;;;; +A4ED;LISU LETTER GHA;Lo;0;L;;;;;N;;;;; +A4EE;LISU LETTER A;Lo;0;L;;;;;N;;;;; +A4EF;LISU LETTER AE;Lo;0;L;;;;;N;;;;; +A4F0;LISU LETTER E;Lo;0;L;;;;;N;;;;; +A4F1;LISU LETTER EU;Lo;0;L;;;;;N;;;;; +A4F2;LISU LETTER I;Lo;0;L;;;;;N;;;;; +A4F3;LISU LETTER O;Lo;0;L;;;;;N;;;;; +A4F4;LISU LETTER U;Lo;0;L;;;;;N;;;;; +A4F5;LISU LETTER UE;Lo;0;L;;;;;N;;;;; +A4F6;LISU LETTER UH;Lo;0;L;;;;;N;;;;; +A4F7;LISU LETTER OE;Lo;0;L;;;;;N;;;;; +A4F8;LISU LETTER TONE MYA TI;Lm;0;L;;;;;N;;;;; +A4F9;LISU LETTER TONE NA PO;Lm;0;L;;;;;N;;;;; +A4FA;LISU LETTER TONE MYA CYA;Lm;0;L;;;;;N;;;;; +A4FB;LISU LETTER TONE MYA BO;Lm;0;L;;;;;N;;;;; +A4FC;LISU LETTER TONE MYA NA;Lm;0;L;;;;;N;;;;; +A4FD;LISU LETTER TONE MYA JEU;Lm;0;L;;;;;N;;;;; +A4FE;LISU PUNCTUATION COMMA;Po;0;L;;;;;N;;;;; +A4FF;LISU PUNCTUATION FULL STOP;Po;0;L;;;;;N;;;;; +A500;VAI SYLLABLE EE;Lo;0;L;;;;;N;;;;; +A501;VAI SYLLABLE EEN;Lo;0;L;;;;;N;;;;; +A502;VAI SYLLABLE HEE;Lo;0;L;;;;;N;;;;; +A503;VAI SYLLABLE WEE;Lo;0;L;;;;;N;;;;; +A504;VAI SYLLABLE WEEN;Lo;0;L;;;;;N;;;;; +A505;VAI SYLLABLE PEE;Lo;0;L;;;;;N;;;;; +A506;VAI SYLLABLE BHEE;Lo;0;L;;;;;N;;;;; +A507;VAI SYLLABLE BEE;Lo;0;L;;;;;N;;;;; +A508;VAI SYLLABLE MBEE;Lo;0;L;;;;;N;;;;; +A509;VAI SYLLABLE KPEE;Lo;0;L;;;;;N;;;;; +A50A;VAI SYLLABLE MGBEE;Lo;0;L;;;;;N;;;;; +A50B;VAI SYLLABLE GBEE;Lo;0;L;;;;;N;;;;; +A50C;VAI SYLLABLE FEE;Lo;0;L;;;;;N;;;;; +A50D;VAI SYLLABLE VEE;Lo;0;L;;;;;N;;;;; +A50E;VAI SYLLABLE TEE;Lo;0;L;;;;;N;;;;; +A50F;VAI SYLLABLE THEE;Lo;0;L;;;;;N;;;;; +A510;VAI SYLLABLE DHEE;Lo;0;L;;;;;N;;;;; +A511;VAI SYLLABLE DHHEE;Lo;0;L;;;;;N;;;;; +A512;VAI SYLLABLE LEE;Lo;0;L;;;;;N;;;;; +A513;VAI SYLLABLE REE;Lo;0;L;;;;;N;;;;; +A514;VAI SYLLABLE DEE;Lo;0;L;;;;;N;;;;; +A515;VAI SYLLABLE NDEE;Lo;0;L;;;;;N;;;;; +A516;VAI SYLLABLE SEE;Lo;0;L;;;;;N;;;;; +A517;VAI SYLLABLE SHEE;Lo;0;L;;;;;N;;;;; +A518;VAI SYLLABLE ZEE;Lo;0;L;;;;;N;;;;; +A519;VAI SYLLABLE ZHEE;Lo;0;L;;;;;N;;;;; +A51A;VAI SYLLABLE CEE;Lo;0;L;;;;;N;;;;; +A51B;VAI SYLLABLE JEE;Lo;0;L;;;;;N;;;;; +A51C;VAI SYLLABLE NJEE;Lo;0;L;;;;;N;;;;; +A51D;VAI SYLLABLE YEE;Lo;0;L;;;;;N;;;;; +A51E;VAI SYLLABLE KEE;Lo;0;L;;;;;N;;;;; +A51F;VAI SYLLABLE NGGEE;Lo;0;L;;;;;N;;;;; +A520;VAI SYLLABLE GEE;Lo;0;L;;;;;N;;;;; +A521;VAI SYLLABLE MEE;Lo;0;L;;;;;N;;;;; +A522;VAI SYLLABLE NEE;Lo;0;L;;;;;N;;;;; +A523;VAI SYLLABLE NYEE;Lo;0;L;;;;;N;;;;; +A524;VAI SYLLABLE I;Lo;0;L;;;;;N;;;;; +A525;VAI SYLLABLE IN;Lo;0;L;;;;;N;;;;; +A526;VAI SYLLABLE HI;Lo;0;L;;;;;N;;;;; +A527;VAI SYLLABLE HIN;Lo;0;L;;;;;N;;;;; +A528;VAI SYLLABLE WI;Lo;0;L;;;;;N;;;;; +A529;VAI SYLLABLE WIN;Lo;0;L;;;;;N;;;;; +A52A;VAI SYLLABLE PI;Lo;0;L;;;;;N;;;;; +A52B;VAI SYLLABLE BHI;Lo;0;L;;;;;N;;;;; +A52C;VAI SYLLABLE BI;Lo;0;L;;;;;N;;;;; +A52D;VAI SYLLABLE MBI;Lo;0;L;;;;;N;;;;; +A52E;VAI SYLLABLE KPI;Lo;0;L;;;;;N;;;;; +A52F;VAI SYLLABLE MGBI;Lo;0;L;;;;;N;;;;; +A530;VAI SYLLABLE GBI;Lo;0;L;;;;;N;;;;; +A531;VAI SYLLABLE FI;Lo;0;L;;;;;N;;;;; +A532;VAI SYLLABLE VI;Lo;0;L;;;;;N;;;;; +A533;VAI SYLLABLE TI;Lo;0;L;;;;;N;;;;; +A534;VAI SYLLABLE THI;Lo;0;L;;;;;N;;;;; +A535;VAI SYLLABLE DHI;Lo;0;L;;;;;N;;;;; +A536;VAI SYLLABLE DHHI;Lo;0;L;;;;;N;;;;; +A537;VAI SYLLABLE LI;Lo;0;L;;;;;N;;;;; +A538;VAI SYLLABLE RI;Lo;0;L;;;;;N;;;;; +A539;VAI SYLLABLE DI;Lo;0;L;;;;;N;;;;; +A53A;VAI SYLLABLE NDI;Lo;0;L;;;;;N;;;;; +A53B;VAI SYLLABLE SI;Lo;0;L;;;;;N;;;;; +A53C;VAI SYLLABLE SHI;Lo;0;L;;;;;N;;;;; +A53D;VAI SYLLABLE ZI;Lo;0;L;;;;;N;;;;; +A53E;VAI SYLLABLE ZHI;Lo;0;L;;;;;N;;;;; +A53F;VAI SYLLABLE CI;Lo;0;L;;;;;N;;;;; +A540;VAI SYLLABLE JI;Lo;0;L;;;;;N;;;;; +A541;VAI SYLLABLE NJI;Lo;0;L;;;;;N;;;;; +A542;VAI SYLLABLE YI;Lo;0;L;;;;;N;;;;; +A543;VAI SYLLABLE KI;Lo;0;L;;;;;N;;;;; +A544;VAI SYLLABLE NGGI;Lo;0;L;;;;;N;;;;; +A545;VAI SYLLABLE GI;Lo;0;L;;;;;N;;;;; +A546;VAI SYLLABLE MI;Lo;0;L;;;;;N;;;;; +A547;VAI SYLLABLE NI;Lo;0;L;;;;;N;;;;; +A548;VAI SYLLABLE NYI;Lo;0;L;;;;;N;;;;; +A549;VAI SYLLABLE A;Lo;0;L;;;;;N;;;;; +A54A;VAI SYLLABLE AN;Lo;0;L;;;;;N;;;;; +A54B;VAI SYLLABLE NGAN;Lo;0;L;;;;;N;;;;; +A54C;VAI SYLLABLE HA;Lo;0;L;;;;;N;;;;; +A54D;VAI SYLLABLE HAN;Lo;0;L;;;;;N;;;;; +A54E;VAI SYLLABLE WA;Lo;0;L;;;;;N;;;;; +A54F;VAI SYLLABLE WAN;Lo;0;L;;;;;N;;;;; +A550;VAI SYLLABLE PA;Lo;0;L;;;;;N;;;;; +A551;VAI SYLLABLE BHA;Lo;0;L;;;;;N;;;;; +A552;VAI SYLLABLE BA;Lo;0;L;;;;;N;;;;; +A553;VAI SYLLABLE MBA;Lo;0;L;;;;;N;;;;; +A554;VAI SYLLABLE KPA;Lo;0;L;;;;;N;;;;; +A555;VAI SYLLABLE KPAN;Lo;0;L;;;;;N;;;;; +A556;VAI SYLLABLE MGBA;Lo;0;L;;;;;N;;;;; +A557;VAI SYLLABLE GBA;Lo;0;L;;;;;N;;;;; +A558;VAI SYLLABLE FA;Lo;0;L;;;;;N;;;;; +A559;VAI SYLLABLE VA;Lo;0;L;;;;;N;;;;; +A55A;VAI SYLLABLE TA;Lo;0;L;;;;;N;;;;; +A55B;VAI SYLLABLE THA;Lo;0;L;;;;;N;;;;; +A55C;VAI SYLLABLE DHA;Lo;0;L;;;;;N;;;;; +A55D;VAI SYLLABLE DHHA;Lo;0;L;;;;;N;;;;; +A55E;VAI SYLLABLE LA;Lo;0;L;;;;;N;;;;; +A55F;VAI SYLLABLE RA;Lo;0;L;;;;;N;;;;; +A560;VAI SYLLABLE DA;Lo;0;L;;;;;N;;;;; +A561;VAI SYLLABLE NDA;Lo;0;L;;;;;N;;;;; +A562;VAI SYLLABLE SA;Lo;0;L;;;;;N;;;;; +A563;VAI SYLLABLE SHA;Lo;0;L;;;;;N;;;;; +A564;VAI SYLLABLE ZA;Lo;0;L;;;;;N;;;;; +A565;VAI SYLLABLE ZHA;Lo;0;L;;;;;N;;;;; +A566;VAI SYLLABLE CA;Lo;0;L;;;;;N;;;;; +A567;VAI SYLLABLE JA;Lo;0;L;;;;;N;;;;; +A568;VAI SYLLABLE NJA;Lo;0;L;;;;;N;;;;; +A569;VAI SYLLABLE YA;Lo;0;L;;;;;N;;;;; +A56A;VAI SYLLABLE KA;Lo;0;L;;;;;N;;;;; +A56B;VAI SYLLABLE KAN;Lo;0;L;;;;;N;;;;; +A56C;VAI SYLLABLE NGGA;Lo;0;L;;;;;N;;;;; +A56D;VAI SYLLABLE GA;Lo;0;L;;;;;N;;;;; +A56E;VAI SYLLABLE MA;Lo;0;L;;;;;N;;;;; +A56F;VAI SYLLABLE NA;Lo;0;L;;;;;N;;;;; +A570;VAI SYLLABLE NYA;Lo;0;L;;;;;N;;;;; +A571;VAI SYLLABLE OO;Lo;0;L;;;;;N;;;;; +A572;VAI SYLLABLE OON;Lo;0;L;;;;;N;;;;; +A573;VAI SYLLABLE HOO;Lo;0;L;;;;;N;;;;; +A574;VAI SYLLABLE WOO;Lo;0;L;;;;;N;;;;; +A575;VAI SYLLABLE WOON;Lo;0;L;;;;;N;;;;; +A576;VAI SYLLABLE POO;Lo;0;L;;;;;N;;;;; +A577;VAI SYLLABLE BHOO;Lo;0;L;;;;;N;;;;; +A578;VAI SYLLABLE BOO;Lo;0;L;;;;;N;;;;; +A579;VAI SYLLABLE MBOO;Lo;0;L;;;;;N;;;;; +A57A;VAI SYLLABLE KPOO;Lo;0;L;;;;;N;;;;; +A57B;VAI SYLLABLE MGBOO;Lo;0;L;;;;;N;;;;; +A57C;VAI SYLLABLE GBOO;Lo;0;L;;;;;N;;;;; +A57D;VAI SYLLABLE FOO;Lo;0;L;;;;;N;;;;; +A57E;VAI SYLLABLE VOO;Lo;0;L;;;;;N;;;;; +A57F;VAI SYLLABLE TOO;Lo;0;L;;;;;N;;;;; +A580;VAI SYLLABLE THOO;Lo;0;L;;;;;N;;;;; +A581;VAI SYLLABLE DHOO;Lo;0;L;;;;;N;;;;; +A582;VAI SYLLABLE DHHOO;Lo;0;L;;;;;N;;;;; +A583;VAI SYLLABLE LOO;Lo;0;L;;;;;N;;;;; +A584;VAI SYLLABLE ROO;Lo;0;L;;;;;N;;;;; +A585;VAI SYLLABLE DOO;Lo;0;L;;;;;N;;;;; +A586;VAI SYLLABLE NDOO;Lo;0;L;;;;;N;;;;; +A587;VAI SYLLABLE SOO;Lo;0;L;;;;;N;;;;; +A588;VAI SYLLABLE SHOO;Lo;0;L;;;;;N;;;;; +A589;VAI SYLLABLE ZOO;Lo;0;L;;;;;N;;;;; +A58A;VAI SYLLABLE ZHOO;Lo;0;L;;;;;N;;;;; +A58B;VAI SYLLABLE COO;Lo;0;L;;;;;N;;;;; +A58C;VAI SYLLABLE JOO;Lo;0;L;;;;;N;;;;; +A58D;VAI SYLLABLE NJOO;Lo;0;L;;;;;N;;;;; +A58E;VAI SYLLABLE YOO;Lo;0;L;;;;;N;;;;; +A58F;VAI SYLLABLE KOO;Lo;0;L;;;;;N;;;;; +A590;VAI SYLLABLE NGGOO;Lo;0;L;;;;;N;;;;; +A591;VAI SYLLABLE GOO;Lo;0;L;;;;;N;;;;; +A592;VAI SYLLABLE MOO;Lo;0;L;;;;;N;;;;; +A593;VAI SYLLABLE NOO;Lo;0;L;;;;;N;;;;; +A594;VAI SYLLABLE NYOO;Lo;0;L;;;;;N;;;;; +A595;VAI SYLLABLE U;Lo;0;L;;;;;N;;;;; +A596;VAI SYLLABLE UN;Lo;0;L;;;;;N;;;;; +A597;VAI SYLLABLE HU;Lo;0;L;;;;;N;;;;; +A598;VAI SYLLABLE HUN;Lo;0;L;;;;;N;;;;; +A599;VAI SYLLABLE WU;Lo;0;L;;;;;N;;;;; +A59A;VAI SYLLABLE WUN;Lo;0;L;;;;;N;;;;; +A59B;VAI SYLLABLE PU;Lo;0;L;;;;;N;;;;; +A59C;VAI SYLLABLE BHU;Lo;0;L;;;;;N;;;;; +A59D;VAI SYLLABLE BU;Lo;0;L;;;;;N;;;;; +A59E;VAI SYLLABLE MBU;Lo;0;L;;;;;N;;;;; +A59F;VAI SYLLABLE KPU;Lo;0;L;;;;;N;;;;; +A5A0;VAI SYLLABLE MGBU;Lo;0;L;;;;;N;;;;; +A5A1;VAI SYLLABLE GBU;Lo;0;L;;;;;N;;;;; +A5A2;VAI SYLLABLE FU;Lo;0;L;;;;;N;;;;; +A5A3;VAI SYLLABLE VU;Lo;0;L;;;;;N;;;;; +A5A4;VAI SYLLABLE TU;Lo;0;L;;;;;N;;;;; +A5A5;VAI SYLLABLE THU;Lo;0;L;;;;;N;;;;; +A5A6;VAI SYLLABLE DHU;Lo;0;L;;;;;N;;;;; +A5A7;VAI SYLLABLE DHHU;Lo;0;L;;;;;N;;;;; +A5A8;VAI SYLLABLE LU;Lo;0;L;;;;;N;;;;; +A5A9;VAI SYLLABLE RU;Lo;0;L;;;;;N;;;;; +A5AA;VAI SYLLABLE DU;Lo;0;L;;;;;N;;;;; +A5AB;VAI SYLLABLE NDU;Lo;0;L;;;;;N;;;;; +A5AC;VAI SYLLABLE SU;Lo;0;L;;;;;N;;;;; +A5AD;VAI SYLLABLE SHU;Lo;0;L;;;;;N;;;;; +A5AE;VAI SYLLABLE ZU;Lo;0;L;;;;;N;;;;; +A5AF;VAI SYLLABLE ZHU;Lo;0;L;;;;;N;;;;; +A5B0;VAI SYLLABLE CU;Lo;0;L;;;;;N;;;;; +A5B1;VAI SYLLABLE JU;Lo;0;L;;;;;N;;;;; +A5B2;VAI SYLLABLE NJU;Lo;0;L;;;;;N;;;;; +A5B3;VAI SYLLABLE YU;Lo;0;L;;;;;N;;;;; +A5B4;VAI SYLLABLE KU;Lo;0;L;;;;;N;;;;; +A5B5;VAI SYLLABLE NGGU;Lo;0;L;;;;;N;;;;; +A5B6;VAI SYLLABLE GU;Lo;0;L;;;;;N;;;;; +A5B7;VAI SYLLABLE MU;Lo;0;L;;;;;N;;;;; +A5B8;VAI SYLLABLE NU;Lo;0;L;;;;;N;;;;; +A5B9;VAI SYLLABLE NYU;Lo;0;L;;;;;N;;;;; +A5BA;VAI SYLLABLE O;Lo;0;L;;;;;N;;;;; +A5BB;VAI SYLLABLE ON;Lo;0;L;;;;;N;;;;; +A5BC;VAI SYLLABLE NGON;Lo;0;L;;;;;N;;;;; +A5BD;VAI SYLLABLE HO;Lo;0;L;;;;;N;;;;; +A5BE;VAI SYLLABLE HON;Lo;0;L;;;;;N;;;;; +A5BF;VAI SYLLABLE WO;Lo;0;L;;;;;N;;;;; +A5C0;VAI SYLLABLE WON;Lo;0;L;;;;;N;;;;; +A5C1;VAI SYLLABLE PO;Lo;0;L;;;;;N;;;;; +A5C2;VAI SYLLABLE BHO;Lo;0;L;;;;;N;;;;; +A5C3;VAI SYLLABLE BO;Lo;0;L;;;;;N;;;;; +A5C4;VAI SYLLABLE MBO;Lo;0;L;;;;;N;;;;; +A5C5;VAI SYLLABLE KPO;Lo;0;L;;;;;N;;;;; +A5C6;VAI SYLLABLE MGBO;Lo;0;L;;;;;N;;;;; +A5C7;VAI SYLLABLE GBO;Lo;0;L;;;;;N;;;;; +A5C8;VAI SYLLABLE GBON;Lo;0;L;;;;;N;;;;; +A5C9;VAI SYLLABLE FO;Lo;0;L;;;;;N;;;;; +A5CA;VAI SYLLABLE VO;Lo;0;L;;;;;N;;;;; +A5CB;VAI SYLLABLE TO;Lo;0;L;;;;;N;;;;; +A5CC;VAI SYLLABLE THO;Lo;0;L;;;;;N;;;;; +A5CD;VAI SYLLABLE DHO;Lo;0;L;;;;;N;;;;; +A5CE;VAI SYLLABLE DHHO;Lo;0;L;;;;;N;;;;; +A5CF;VAI SYLLABLE LO;Lo;0;L;;;;;N;;;;; +A5D0;VAI SYLLABLE RO;Lo;0;L;;;;;N;;;;; +A5D1;VAI SYLLABLE DO;Lo;0;L;;;;;N;;;;; +A5D2;VAI SYLLABLE NDO;Lo;0;L;;;;;N;;;;; +A5D3;VAI SYLLABLE SO;Lo;0;L;;;;;N;;;;; +A5D4;VAI SYLLABLE SHO;Lo;0;L;;;;;N;;;;; +A5D5;VAI SYLLABLE ZO;Lo;0;L;;;;;N;;;;; +A5D6;VAI SYLLABLE ZHO;Lo;0;L;;;;;N;;;;; +A5D7;VAI SYLLABLE CO;Lo;0;L;;;;;N;;;;; +A5D8;VAI SYLLABLE JO;Lo;0;L;;;;;N;;;;; +A5D9;VAI SYLLABLE NJO;Lo;0;L;;;;;N;;;;; +A5DA;VAI SYLLABLE YO;Lo;0;L;;;;;N;;;;; +A5DB;VAI SYLLABLE KO;Lo;0;L;;;;;N;;;;; +A5DC;VAI SYLLABLE NGGO;Lo;0;L;;;;;N;;;;; +A5DD;VAI SYLLABLE GO;Lo;0;L;;;;;N;;;;; +A5DE;VAI SYLLABLE MO;Lo;0;L;;;;;N;;;;; +A5DF;VAI SYLLABLE NO;Lo;0;L;;;;;N;;;;; +A5E0;VAI SYLLABLE NYO;Lo;0;L;;;;;N;;;;; +A5E1;VAI SYLLABLE E;Lo;0;L;;;;;N;;;;; +A5E2;VAI SYLLABLE EN;Lo;0;L;;;;;N;;;;; +A5E3;VAI SYLLABLE NGEN;Lo;0;L;;;;;N;;;;; +A5E4;VAI SYLLABLE HE;Lo;0;L;;;;;N;;;;; +A5E5;VAI SYLLABLE HEN;Lo;0;L;;;;;N;;;;; +A5E6;VAI SYLLABLE WE;Lo;0;L;;;;;N;;;;; +A5E7;VAI SYLLABLE WEN;Lo;0;L;;;;;N;;;;; +A5E8;VAI SYLLABLE PE;Lo;0;L;;;;;N;;;;; +A5E9;VAI SYLLABLE BHE;Lo;0;L;;;;;N;;;;; +A5EA;VAI SYLLABLE BE;Lo;0;L;;;;;N;;;;; +A5EB;VAI SYLLABLE MBE;Lo;0;L;;;;;N;;;;; +A5EC;VAI SYLLABLE KPE;Lo;0;L;;;;;N;;;;; +A5ED;VAI SYLLABLE KPEN;Lo;0;L;;;;;N;;;;; +A5EE;VAI SYLLABLE MGBE;Lo;0;L;;;;;N;;;;; +A5EF;VAI SYLLABLE GBE;Lo;0;L;;;;;N;;;;; +A5F0;VAI SYLLABLE GBEN;Lo;0;L;;;;;N;;;;; +A5F1;VAI SYLLABLE FE;Lo;0;L;;;;;N;;;;; +A5F2;VAI SYLLABLE VE;Lo;0;L;;;;;N;;;;; +A5F3;VAI SYLLABLE TE;Lo;0;L;;;;;N;;;;; +A5F4;VAI SYLLABLE THE;Lo;0;L;;;;;N;;;;; +A5F5;VAI SYLLABLE DHE;Lo;0;L;;;;;N;;;;; +A5F6;VAI SYLLABLE DHHE;Lo;0;L;;;;;N;;;;; +A5F7;VAI SYLLABLE LE;Lo;0;L;;;;;N;;;;; +A5F8;VAI SYLLABLE RE;Lo;0;L;;;;;N;;;;; +A5F9;VAI SYLLABLE DE;Lo;0;L;;;;;N;;;;; +A5FA;VAI SYLLABLE NDE;Lo;0;L;;;;;N;;;;; +A5FB;VAI SYLLABLE SE;Lo;0;L;;;;;N;;;;; +A5FC;VAI SYLLABLE SHE;Lo;0;L;;;;;N;;;;; +A5FD;VAI SYLLABLE ZE;Lo;0;L;;;;;N;;;;; +A5FE;VAI SYLLABLE ZHE;Lo;0;L;;;;;N;;;;; +A5FF;VAI SYLLABLE CE;Lo;0;L;;;;;N;;;;; +A600;VAI SYLLABLE JE;Lo;0;L;;;;;N;;;;; +A601;VAI SYLLABLE NJE;Lo;0;L;;;;;N;;;;; +A602;VAI SYLLABLE YE;Lo;0;L;;;;;N;;;;; +A603;VAI SYLLABLE KE;Lo;0;L;;;;;N;;;;; +A604;VAI SYLLABLE NGGE;Lo;0;L;;;;;N;;;;; +A605;VAI SYLLABLE NGGEN;Lo;0;L;;;;;N;;;;; +A606;VAI SYLLABLE GE;Lo;0;L;;;;;N;;;;; +A607;VAI SYLLABLE GEN;Lo;0;L;;;;;N;;;;; +A608;VAI SYLLABLE ME;Lo;0;L;;;;;N;;;;; +A609;VAI SYLLABLE NE;Lo;0;L;;;;;N;;;;; +A60A;VAI SYLLABLE NYE;Lo;0;L;;;;;N;;;;; +A60B;VAI SYLLABLE NG;Lo;0;L;;;;;N;;;;; +A60C;VAI SYLLABLE LENGTHENER;Lm;0;L;;;;;N;;;;; +A60D;VAI COMMA;Po;0;ON;;;;;N;;;;; +A60E;VAI FULL STOP;Po;0;ON;;;;;N;;;;; +A60F;VAI QUESTION MARK;Po;0;ON;;;;;N;;;;; +A610;VAI SYLLABLE NDOLE FA;Lo;0;L;;;;;N;;;;; +A611;VAI SYLLABLE NDOLE KA;Lo;0;L;;;;;N;;;;; +A612;VAI SYLLABLE NDOLE SOO;Lo;0;L;;;;;N;;;;; +A613;VAI SYMBOL FEENG;Lo;0;L;;;;;N;;;;; +A614;VAI SYMBOL KEENG;Lo;0;L;;;;;N;;;;; +A615;VAI SYMBOL TING;Lo;0;L;;;;;N;;;;; +A616;VAI SYMBOL NII;Lo;0;L;;;;;N;;;;; +A617;VAI SYMBOL BANG;Lo;0;L;;;;;N;;;;; +A618;VAI SYMBOL FAA;Lo;0;L;;;;;N;;;;; +A619;VAI SYMBOL TAA;Lo;0;L;;;;;N;;;;; +A61A;VAI SYMBOL DANG;Lo;0;L;;;;;N;;;;; +A61B;VAI SYMBOL DOONG;Lo;0;L;;;;;N;;;;; +A61C;VAI SYMBOL KUNG;Lo;0;L;;;;;N;;;;; +A61D;VAI SYMBOL TONG;Lo;0;L;;;;;N;;;;; +A61E;VAI SYMBOL DO-O;Lo;0;L;;;;;N;;;;; +A61F;VAI SYMBOL JONG;Lo;0;L;;;;;N;;;;; +A620;VAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +A621;VAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +A622;VAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +A623;VAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +A624;VAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +A625;VAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +A626;VAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +A627;VAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +A628;VAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +A629;VAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +A62A;VAI SYLLABLE NDOLE MA;Lo;0;L;;;;;N;;;;; +A62B;VAI SYLLABLE NDOLE DO;Lo;0;L;;;;;N;;;;; +A640;CYRILLIC CAPITAL LETTER ZEMLYA;Lu;0;L;;;;;N;;;;A641; +A641;CYRILLIC SMALL LETTER ZEMLYA;Ll;0;L;;;;;N;;;A640;;A640 +A642;CYRILLIC CAPITAL LETTER DZELO;Lu;0;L;;;;;N;;;;A643; +A643;CYRILLIC SMALL LETTER DZELO;Ll;0;L;;;;;N;;;A642;;A642 +A644;CYRILLIC CAPITAL LETTER REVERSED DZE;Lu;0;L;;;;;N;;;;A645; +A645;CYRILLIC SMALL LETTER REVERSED DZE;Ll;0;L;;;;;N;;;A644;;A644 +A646;CYRILLIC CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;A647; +A647;CYRILLIC SMALL LETTER IOTA;Ll;0;L;;;;;N;;;A646;;A646 +A648;CYRILLIC CAPITAL LETTER DJERV;Lu;0;L;;;;;N;;;;A649; +A649;CYRILLIC SMALL LETTER DJERV;Ll;0;L;;;;;N;;;A648;;A648 +A64A;CYRILLIC CAPITAL LETTER MONOGRAPH UK;Lu;0;L;;;;;N;;;;A64B; +A64B;CYRILLIC SMALL LETTER MONOGRAPH UK;Ll;0;L;;;;;N;;;A64A;;A64A +A64C;CYRILLIC CAPITAL LETTER BROAD OMEGA;Lu;0;L;;;;;N;;;;A64D; +A64D;CYRILLIC SMALL LETTER BROAD OMEGA;Ll;0;L;;;;;N;;;A64C;;A64C +A64E;CYRILLIC CAPITAL LETTER NEUTRAL YER;Lu;0;L;;;;;N;;;;A64F; +A64F;CYRILLIC SMALL LETTER NEUTRAL YER;Ll;0;L;;;;;N;;;A64E;;A64E +A650;CYRILLIC CAPITAL LETTER YERU WITH BACK YER;Lu;0;L;;;;;N;;;;A651; +A651;CYRILLIC SMALL LETTER YERU WITH BACK YER;Ll;0;L;;;;;N;;;A650;;A650 +A652;CYRILLIC CAPITAL LETTER IOTIFIED YAT;Lu;0;L;;;;;N;;;;A653; +A653;CYRILLIC SMALL LETTER IOTIFIED YAT;Ll;0;L;;;;;N;;;A652;;A652 +A654;CYRILLIC CAPITAL LETTER REVERSED YU;Lu;0;L;;;;;N;;;;A655; +A655;CYRILLIC SMALL LETTER REVERSED YU;Ll;0;L;;;;;N;;;A654;;A654 +A656;CYRILLIC CAPITAL LETTER IOTIFIED A;Lu;0;L;;;;;N;;;;A657; +A657;CYRILLIC SMALL LETTER IOTIFIED A;Ll;0;L;;;;;N;;;A656;;A656 +A658;CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS;Lu;0;L;;;;;N;;;;A659; +A659;CYRILLIC SMALL LETTER CLOSED LITTLE YUS;Ll;0;L;;;;;N;;;A658;;A658 +A65A;CYRILLIC CAPITAL LETTER BLENDED YUS;Lu;0;L;;;;;N;;;;A65B; +A65B;CYRILLIC SMALL LETTER BLENDED YUS;Ll;0;L;;;;;N;;;A65A;;A65A +A65C;CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS;Lu;0;L;;;;;N;;;;A65D; +A65D;CYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUS;Ll;0;L;;;;;N;;;A65C;;A65C +A65E;CYRILLIC CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;A65F; +A65F;CYRILLIC SMALL LETTER YN;Ll;0;L;;;;;N;;;A65E;;A65E +A660;CYRILLIC CAPITAL LETTER REVERSED TSE;Lu;0;L;;;;;N;;;;A661; +A661;CYRILLIC SMALL LETTER REVERSED TSE;Ll;0;L;;;;;N;;;A660;;A660 +A662;CYRILLIC CAPITAL LETTER SOFT DE;Lu;0;L;;;;;N;;;;A663; +A663;CYRILLIC SMALL LETTER SOFT DE;Ll;0;L;;;;;N;;;A662;;A662 +A664;CYRILLIC CAPITAL LETTER SOFT EL;Lu;0;L;;;;;N;;;;A665; +A665;CYRILLIC SMALL LETTER SOFT EL;Ll;0;L;;;;;N;;;A664;;A664 +A666;CYRILLIC CAPITAL LETTER SOFT EM;Lu;0;L;;;;;N;;;;A667; +A667;CYRILLIC SMALL LETTER SOFT EM;Ll;0;L;;;;;N;;;A666;;A666 +A668;CYRILLIC CAPITAL LETTER MONOCULAR O;Lu;0;L;;;;;N;;;;A669; +A669;CYRILLIC SMALL LETTER MONOCULAR O;Ll;0;L;;;;;N;;;A668;;A668 +A66A;CYRILLIC CAPITAL LETTER BINOCULAR O;Lu;0;L;;;;;N;;;;A66B; +A66B;CYRILLIC SMALL LETTER BINOCULAR O;Ll;0;L;;;;;N;;;A66A;;A66A +A66C;CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O;Lu;0;L;;;;;N;;;;A66D; +A66D;CYRILLIC SMALL LETTER DOUBLE MONOCULAR O;Ll;0;L;;;;;N;;;A66C;;A66C +A66E;CYRILLIC LETTER MULTIOCULAR O;Lo;0;L;;;;;N;;;;; +A66F;COMBINING CYRILLIC VZMET;Mn;230;NSM;;;;;N;;;;; +A670;COMBINING CYRILLIC TEN MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; +A671;COMBINING CYRILLIC HUNDRED MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; +A672;COMBINING CYRILLIC THOUSAND MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; +A673;SLAVONIC ASTERISK;Po;0;ON;;;;;N;;;;; +A674;COMBINING CYRILLIC LETTER UKRAINIAN IE;Mn;230;NSM;;;;;N;;;;; +A675;COMBINING CYRILLIC LETTER I;Mn;230;NSM;;;;;N;;;;; +A676;COMBINING CYRILLIC LETTER YI;Mn;230;NSM;;;;;N;;;;; +A677;COMBINING CYRILLIC LETTER U;Mn;230;NSM;;;;;N;;;;; +A678;COMBINING CYRILLIC LETTER HARD SIGN;Mn;230;NSM;;;;;N;;;;; +A679;COMBINING CYRILLIC LETTER YERU;Mn;230;NSM;;;;;N;;;;; +A67A;COMBINING CYRILLIC LETTER SOFT SIGN;Mn;230;NSM;;;;;N;;;;; +A67B;COMBINING CYRILLIC LETTER OMEGA;Mn;230;NSM;;;;;N;;;;; +A67C;COMBINING CYRILLIC KAVYKA;Mn;230;NSM;;;;;N;;;;; +A67D;COMBINING CYRILLIC PAYEROK;Mn;230;NSM;;;;;N;;;;; +A67E;CYRILLIC KAVYKA;Po;0;ON;;;;;N;;;;; +A67F;CYRILLIC PAYEROK;Lm;0;ON;;;;;N;;;;; +A680;CYRILLIC CAPITAL LETTER DWE;Lu;0;L;;;;;N;;;;A681; +A681;CYRILLIC SMALL LETTER DWE;Ll;0;L;;;;;N;;;A680;;A680 +A682;CYRILLIC CAPITAL LETTER DZWE;Lu;0;L;;;;;N;;;;A683; +A683;CYRILLIC SMALL LETTER DZWE;Ll;0;L;;;;;N;;;A682;;A682 +A684;CYRILLIC CAPITAL LETTER ZHWE;Lu;0;L;;;;;N;;;;A685; +A685;CYRILLIC SMALL LETTER ZHWE;Ll;0;L;;;;;N;;;A684;;A684 +A686;CYRILLIC CAPITAL LETTER CCHE;Lu;0;L;;;;;N;;;;A687; +A687;CYRILLIC SMALL LETTER CCHE;Ll;0;L;;;;;N;;;A686;;A686 +A688;CYRILLIC CAPITAL LETTER DZZE;Lu;0;L;;;;;N;;;;A689; +A689;CYRILLIC SMALL LETTER DZZE;Ll;0;L;;;;;N;;;A688;;A688 +A68A;CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK;Lu;0;L;;;;;N;;;;A68B; +A68B;CYRILLIC SMALL LETTER TE WITH MIDDLE HOOK;Ll;0;L;;;;;N;;;A68A;;A68A +A68C;CYRILLIC CAPITAL LETTER TWE;Lu;0;L;;;;;N;;;;A68D; +A68D;CYRILLIC SMALL LETTER TWE;Ll;0;L;;;;;N;;;A68C;;A68C +A68E;CYRILLIC CAPITAL LETTER TSWE;Lu;0;L;;;;;N;;;;A68F; +A68F;CYRILLIC SMALL LETTER TSWE;Ll;0;L;;;;;N;;;A68E;;A68E +A690;CYRILLIC CAPITAL LETTER TSSE;Lu;0;L;;;;;N;;;;A691; +A691;CYRILLIC SMALL LETTER TSSE;Ll;0;L;;;;;N;;;A690;;A690 +A692;CYRILLIC CAPITAL LETTER TCHE;Lu;0;L;;;;;N;;;;A693; +A693;CYRILLIC SMALL LETTER TCHE;Ll;0;L;;;;;N;;;A692;;A692 +A694;CYRILLIC CAPITAL LETTER HWE;Lu;0;L;;;;;N;;;;A695; +A695;CYRILLIC SMALL LETTER HWE;Ll;0;L;;;;;N;;;A694;;A694 +A696;CYRILLIC CAPITAL LETTER SHWE;Lu;0;L;;;;;N;;;;A697; +A697;CYRILLIC SMALL LETTER SHWE;Ll;0;L;;;;;N;;;A696;;A696 +A698;CYRILLIC CAPITAL LETTER DOUBLE O;Lu;0;L;;;;;N;;;;A699; +A699;CYRILLIC SMALL LETTER DOUBLE O;Ll;0;L;;;;;N;;;A698;;A698 +A69A;CYRILLIC CAPITAL LETTER CROSSED O;Lu;0;L;;;;;N;;;;A69B; +A69B;CYRILLIC SMALL LETTER CROSSED O;Ll;0;L;;;;;N;;;A69A;;A69A +A69C;MODIFIER LETTER CYRILLIC HARD SIGN;Lm;0;L; 044A;;;;N;;;;; +A69D;MODIFIER LETTER CYRILLIC SOFT SIGN;Lm;0;L; 044C;;;;N;;;;; +A69E;COMBINING CYRILLIC LETTER EF;Mn;230;NSM;;;;;N;;;;; +A69F;COMBINING CYRILLIC LETTER IOTIFIED E;Mn;230;NSM;;;;;N;;;;; +A6A0;BAMUM LETTER A;Lo;0;L;;;;;N;;;;; +A6A1;BAMUM LETTER KA;Lo;0;L;;;;;N;;;;; +A6A2;BAMUM LETTER U;Lo;0;L;;;;;N;;;;; +A6A3;BAMUM LETTER KU;Lo;0;L;;;;;N;;;;; +A6A4;BAMUM LETTER EE;Lo;0;L;;;;;N;;;;; +A6A5;BAMUM LETTER REE;Lo;0;L;;;;;N;;;;; +A6A6;BAMUM LETTER TAE;Lo;0;L;;;;;N;;;;; +A6A7;BAMUM LETTER O;Lo;0;L;;;;;N;;;;; +A6A8;BAMUM LETTER NYI;Lo;0;L;;;;;N;;;;; +A6A9;BAMUM LETTER I;Lo;0;L;;;;;N;;;;; +A6AA;BAMUM LETTER LA;Lo;0;L;;;;;N;;;;; +A6AB;BAMUM LETTER PA;Lo;0;L;;;;;N;;;;; +A6AC;BAMUM LETTER RII;Lo;0;L;;;;;N;;;;; +A6AD;BAMUM LETTER RIEE;Lo;0;L;;;;;N;;;;; +A6AE;BAMUM LETTER LEEEE;Lo;0;L;;;;;N;;;;; +A6AF;BAMUM LETTER MEEEE;Lo;0;L;;;;;N;;;;; +A6B0;BAMUM LETTER TAA;Lo;0;L;;;;;N;;;;; +A6B1;BAMUM LETTER NDAA;Lo;0;L;;;;;N;;;;; +A6B2;BAMUM LETTER NJAEM;Lo;0;L;;;;;N;;;;; +A6B3;BAMUM LETTER M;Lo;0;L;;;;;N;;;;; +A6B4;BAMUM LETTER SUU;Lo;0;L;;;;;N;;;;; +A6B5;BAMUM LETTER MU;Lo;0;L;;;;;N;;;;; +A6B6;BAMUM LETTER SHII;Lo;0;L;;;;;N;;;;; +A6B7;BAMUM LETTER SI;Lo;0;L;;;;;N;;;;; +A6B8;BAMUM LETTER SHEUX;Lo;0;L;;;;;N;;;;; +A6B9;BAMUM LETTER SEUX;Lo;0;L;;;;;N;;;;; +A6BA;BAMUM LETTER KYEE;Lo;0;L;;;;;N;;;;; +A6BB;BAMUM LETTER KET;Lo;0;L;;;;;N;;;;; +A6BC;BAMUM LETTER NUAE;Lo;0;L;;;;;N;;;;; +A6BD;BAMUM LETTER NU;Lo;0;L;;;;;N;;;;; +A6BE;BAMUM LETTER NJUAE;Lo;0;L;;;;;N;;;;; +A6BF;BAMUM LETTER YOQ;Lo;0;L;;;;;N;;;;; +A6C0;BAMUM LETTER SHU;Lo;0;L;;;;;N;;;;; +A6C1;BAMUM LETTER YUQ;Lo;0;L;;;;;N;;;;; +A6C2;BAMUM LETTER YA;Lo;0;L;;;;;N;;;;; +A6C3;BAMUM LETTER NSHA;Lo;0;L;;;;;N;;;;; +A6C4;BAMUM LETTER KEUX;Lo;0;L;;;;;N;;;;; +A6C5;BAMUM LETTER PEUX;Lo;0;L;;;;;N;;;;; +A6C6;BAMUM LETTER NJEE;Lo;0;L;;;;;N;;;;; +A6C7;BAMUM LETTER NTEE;Lo;0;L;;;;;N;;;;; +A6C8;BAMUM LETTER PUE;Lo;0;L;;;;;N;;;;; +A6C9;BAMUM LETTER WUE;Lo;0;L;;;;;N;;;;; +A6CA;BAMUM LETTER PEE;Lo;0;L;;;;;N;;;;; +A6CB;BAMUM LETTER FEE;Lo;0;L;;;;;N;;;;; +A6CC;BAMUM LETTER RU;Lo;0;L;;;;;N;;;;; +A6CD;BAMUM LETTER LU;Lo;0;L;;;;;N;;;;; +A6CE;BAMUM LETTER MI;Lo;0;L;;;;;N;;;;; +A6CF;BAMUM LETTER NI;Lo;0;L;;;;;N;;;;; +A6D0;BAMUM LETTER REUX;Lo;0;L;;;;;N;;;;; +A6D1;BAMUM LETTER RAE;Lo;0;L;;;;;N;;;;; +A6D2;BAMUM LETTER KEN;Lo;0;L;;;;;N;;;;; +A6D3;BAMUM LETTER NGKWAEN;Lo;0;L;;;;;N;;;;; +A6D4;BAMUM LETTER NGGA;Lo;0;L;;;;;N;;;;; +A6D5;BAMUM LETTER NGA;Lo;0;L;;;;;N;;;;; +A6D6;BAMUM LETTER SHO;Lo;0;L;;;;;N;;;;; +A6D7;BAMUM LETTER PUAE;Lo;0;L;;;;;N;;;;; +A6D8;BAMUM LETTER FU;Lo;0;L;;;;;N;;;;; +A6D9;BAMUM LETTER FOM;Lo;0;L;;;;;N;;;;; +A6DA;BAMUM LETTER WA;Lo;0;L;;;;;N;;;;; +A6DB;BAMUM LETTER NA;Lo;0;L;;;;;N;;;;; +A6DC;BAMUM LETTER LI;Lo;0;L;;;;;N;;;;; +A6DD;BAMUM LETTER PI;Lo;0;L;;;;;N;;;;; +A6DE;BAMUM LETTER LOQ;Lo;0;L;;;;;N;;;;; +A6DF;BAMUM LETTER KO;Lo;0;L;;;;;N;;;;; +A6E0;BAMUM LETTER MBEN;Lo;0;L;;;;;N;;;;; +A6E1;BAMUM LETTER REN;Lo;0;L;;;;;N;;;;; +A6E2;BAMUM LETTER MEN;Lo;0;L;;;;;N;;;;; +A6E3;BAMUM LETTER MA;Lo;0;L;;;;;N;;;;; +A6E4;BAMUM LETTER TI;Lo;0;L;;;;;N;;;;; +A6E5;BAMUM LETTER KI;Lo;0;L;;;;;N;;;;; +A6E6;BAMUM LETTER MO;Nl;0;L;;;;1;N;;;;; +A6E7;BAMUM LETTER MBAA;Nl;0;L;;;;2;N;;;;; +A6E8;BAMUM LETTER TET;Nl;0;L;;;;3;N;;;;; +A6E9;BAMUM LETTER KPA;Nl;0;L;;;;4;N;;;;; +A6EA;BAMUM LETTER TEN;Nl;0;L;;;;5;N;;;;; +A6EB;BAMUM LETTER NTUU;Nl;0;L;;;;6;N;;;;; +A6EC;BAMUM LETTER SAMBA;Nl;0;L;;;;7;N;;;;; +A6ED;BAMUM LETTER FAAMAE;Nl;0;L;;;;8;N;;;;; +A6EE;BAMUM LETTER KOVUU;Nl;0;L;;;;9;N;;;;; +A6EF;BAMUM LETTER KOGHOM;Nl;0;L;;;;0;N;;;;; +A6F0;BAMUM COMBINING MARK KOQNDON;Mn;230;NSM;;;;;N;;;;; +A6F1;BAMUM COMBINING MARK TUKWENTIS;Mn;230;NSM;;;;;N;;;;; +A6F2;BAMUM NJAEMLI;Po;0;L;;;;;N;;;;; +A6F3;BAMUM FULL STOP;Po;0;L;;;;;N;;;;; +A6F4;BAMUM COLON;Po;0;L;;;;;N;;;;; +A6F5;BAMUM COMMA;Po;0;L;;;;;N;;;;; +A6F6;BAMUM SEMICOLON;Po;0;L;;;;;N;;;;; +A6F7;BAMUM QUESTION MARK;Po;0;L;;;;;N;;;;; +A700;MODIFIER LETTER CHINESE TONE YIN PING;Sk;0;ON;;;;;N;;;;; +A701;MODIFIER LETTER CHINESE TONE YANG PING;Sk;0;ON;;;;;N;;;;; +A702;MODIFIER LETTER CHINESE TONE YIN SHANG;Sk;0;ON;;;;;N;;;;; +A703;MODIFIER LETTER CHINESE TONE YANG SHANG;Sk;0;ON;;;;;N;;;;; +A704;MODIFIER LETTER CHINESE TONE YIN QU;Sk;0;ON;;;;;N;;;;; +A705;MODIFIER LETTER CHINESE TONE YANG QU;Sk;0;ON;;;;;N;;;;; +A706;MODIFIER LETTER CHINESE TONE YIN RU;Sk;0;ON;;;;;N;;;;; +A707;MODIFIER LETTER CHINESE TONE YANG RU;Sk;0;ON;;;;;N;;;;; +A708;MODIFIER LETTER EXTRA-HIGH DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;; +A709;MODIFIER LETTER HIGH DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;; +A70A;MODIFIER LETTER MID DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;; +A70B;MODIFIER LETTER LOW DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;; +A70C;MODIFIER LETTER EXTRA-LOW DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;; +A70D;MODIFIER LETTER EXTRA-HIGH DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A70E;MODIFIER LETTER HIGH DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A70F;MODIFIER LETTER MID DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A710;MODIFIER LETTER LOW DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A711;MODIFIER LETTER EXTRA-LOW DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A712;MODIFIER LETTER EXTRA-HIGH LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A713;MODIFIER LETTER HIGH LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A714;MODIFIER LETTER MID LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A715;MODIFIER LETTER LOW LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A716;MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; +A717;MODIFIER LETTER DOT VERTICAL BAR;Lm;0;ON;;;;;N;;;;; +A718;MODIFIER LETTER DOT SLASH;Lm;0;ON;;;;;N;;;;; +A719;MODIFIER LETTER DOT HORIZONTAL BAR;Lm;0;ON;;;;;N;;;;; +A71A;MODIFIER LETTER LOWER RIGHT CORNER ANGLE;Lm;0;ON;;;;;N;;;;; +A71B;MODIFIER LETTER RAISED UP ARROW;Lm;0;ON;;;;;N;;;;; +A71C;MODIFIER LETTER RAISED DOWN ARROW;Lm;0;ON;;;;;N;;;;; +A71D;MODIFIER LETTER RAISED EXCLAMATION MARK;Lm;0;ON;;;;;N;;;;; +A71E;MODIFIER LETTER RAISED INVERTED EXCLAMATION MARK;Lm;0;ON;;;;;N;;;;; +A71F;MODIFIER LETTER LOW INVERTED EXCLAMATION MARK;Lm;0;ON;;;;;N;;;;; +A720;MODIFIER LETTER STRESS AND HIGH TONE;Sk;0;ON;;;;;N;;;;; +A721;MODIFIER LETTER STRESS AND LOW TONE;Sk;0;ON;;;;;N;;;;; +A722;LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF;Lu;0;L;;;;;N;;;;A723; +A723;LATIN SMALL LETTER EGYPTOLOGICAL ALEF;Ll;0;L;;;;;N;;;A722;;A722 +A724;LATIN CAPITAL LETTER EGYPTOLOGICAL AIN;Lu;0;L;;;;;N;;;;A725; +A725;LATIN SMALL LETTER EGYPTOLOGICAL AIN;Ll;0;L;;;;;N;;;A724;;A724 +A726;LATIN CAPITAL LETTER HENG;Lu;0;L;;;;;N;;;;A727; +A727;LATIN SMALL LETTER HENG;Ll;0;L;;;;;N;;;A726;;A726 +A728;LATIN CAPITAL LETTER TZ;Lu;0;L;;;;;N;;;;A729; +A729;LATIN SMALL LETTER TZ;Ll;0;L;;;;;N;;;A728;;A728 +A72A;LATIN CAPITAL LETTER TRESILLO;Lu;0;L;;;;;N;;;;A72B; +A72B;LATIN SMALL LETTER TRESILLO;Ll;0;L;;;;;N;;;A72A;;A72A +A72C;LATIN CAPITAL LETTER CUATRILLO;Lu;0;L;;;;;N;;;;A72D; +A72D;LATIN SMALL LETTER CUATRILLO;Ll;0;L;;;;;N;;;A72C;;A72C +A72E;LATIN CAPITAL LETTER CUATRILLO WITH COMMA;Lu;0;L;;;;;N;;;;A72F; +A72F;LATIN SMALL LETTER CUATRILLO WITH COMMA;Ll;0;L;;;;;N;;;A72E;;A72E +A730;LATIN LETTER SMALL CAPITAL F;Ll;0;L;;;;;N;;;;; +A731;LATIN LETTER SMALL CAPITAL S;Ll;0;L;;;;;N;;;;; +A732;LATIN CAPITAL LETTER AA;Lu;0;L;;;;;N;;;;A733; +A733;LATIN SMALL LETTER AA;Ll;0;L;;;;;N;;;A732;;A732 +A734;LATIN CAPITAL LETTER AO;Lu;0;L;;;;;N;;;;A735; +A735;LATIN SMALL LETTER AO;Ll;0;L;;;;;N;;;A734;;A734 +A736;LATIN CAPITAL LETTER AU;Lu;0;L;;;;;N;;;;A737; +A737;LATIN SMALL LETTER AU;Ll;0;L;;;;;N;;;A736;;A736 +A738;LATIN CAPITAL LETTER AV;Lu;0;L;;;;;N;;;;A739; +A739;LATIN SMALL LETTER AV;Ll;0;L;;;;;N;;;A738;;A738 +A73A;LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR;Lu;0;L;;;;;N;;;;A73B; +A73B;LATIN SMALL LETTER AV WITH HORIZONTAL BAR;Ll;0;L;;;;;N;;;A73A;;A73A +A73C;LATIN CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;A73D; +A73D;LATIN SMALL LETTER AY;Ll;0;L;;;;;N;;;A73C;;A73C +A73E;LATIN CAPITAL LETTER REVERSED C WITH DOT;Lu;0;L;;;;;N;;;;A73F; +A73F;LATIN SMALL LETTER REVERSED C WITH DOT;Ll;0;L;;;;;N;;;A73E;;A73E +A740;LATIN CAPITAL LETTER K WITH STROKE;Lu;0;L;;;;;N;;;;A741; +A741;LATIN SMALL LETTER K WITH STROKE;Ll;0;L;;;;;N;;;A740;;A740 +A742;LATIN CAPITAL LETTER K WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A743; +A743;LATIN SMALL LETTER K WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A742;;A742 +A744;LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A745; +A745;LATIN SMALL LETTER K WITH STROKE AND DIAGONAL STROKE;Ll;0;L;;;;;N;;;A744;;A744 +A746;LATIN CAPITAL LETTER BROKEN L;Lu;0;L;;;;;N;;;;A747; +A747;LATIN SMALL LETTER BROKEN L;Ll;0;L;;;;;N;;;A746;;A746 +A748;LATIN CAPITAL LETTER L WITH HIGH STROKE;Lu;0;L;;;;;N;;;;A749; +A749;LATIN SMALL LETTER L WITH HIGH STROKE;Ll;0;L;;;;;N;;;A748;;A748 +A74A;LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY;Lu;0;L;;;;;N;;;;A74B; +A74B;LATIN SMALL LETTER O WITH LONG STROKE OVERLAY;Ll;0;L;;;;;N;;;A74A;;A74A +A74C;LATIN CAPITAL LETTER O WITH LOOP;Lu;0;L;;;;;N;;;;A74D; +A74D;LATIN SMALL LETTER O WITH LOOP;Ll;0;L;;;;;N;;;A74C;;A74C +A74E;LATIN CAPITAL LETTER OO;Lu;0;L;;;;;N;;;;A74F; +A74F;LATIN SMALL LETTER OO;Ll;0;L;;;;;N;;;A74E;;A74E +A750;LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER;Lu;0;L;;;;;N;;;;A751; +A751;LATIN SMALL LETTER P WITH STROKE THROUGH DESCENDER;Ll;0;L;;;;;N;;;A750;;A750 +A752;LATIN CAPITAL LETTER P WITH FLOURISH;Lu;0;L;;;;;N;;;;A753; +A753;LATIN SMALL LETTER P WITH FLOURISH;Ll;0;L;;;;;N;;;A752;;A752 +A754;LATIN CAPITAL LETTER P WITH SQUIRREL TAIL;Lu;0;L;;;;;N;;;;A755; +A755;LATIN SMALL LETTER P WITH SQUIRREL TAIL;Ll;0;L;;;;;N;;;A754;;A754 +A756;LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER;Lu;0;L;;;;;N;;;;A757; +A757;LATIN SMALL LETTER Q WITH STROKE THROUGH DESCENDER;Ll;0;L;;;;;N;;;A756;;A756 +A758;LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A759; +A759;LATIN SMALL LETTER Q WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A758;;A758 +A75A;LATIN CAPITAL LETTER R ROTUNDA;Lu;0;L;;;;;N;;;;A75B; +A75B;LATIN SMALL LETTER R ROTUNDA;Ll;0;L;;;;;N;;;A75A;;A75A +A75C;LATIN CAPITAL LETTER RUM ROTUNDA;Lu;0;L;;;;;N;;;;A75D; +A75D;LATIN SMALL LETTER RUM ROTUNDA;Ll;0;L;;;;;N;;;A75C;;A75C +A75E;LATIN CAPITAL LETTER V WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A75F; +A75F;LATIN SMALL LETTER V WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A75E;;A75E +A760;LATIN CAPITAL LETTER VY;Lu;0;L;;;;;N;;;;A761; +A761;LATIN SMALL LETTER VY;Ll;0;L;;;;;N;;;A760;;A760 +A762;LATIN CAPITAL LETTER VISIGOTHIC Z;Lu;0;L;;;;;N;;;;A763; +A763;LATIN SMALL LETTER VISIGOTHIC Z;Ll;0;L;;;;;N;;;A762;;A762 +A764;LATIN CAPITAL LETTER THORN WITH STROKE;Lu;0;L;;;;;N;;;;A765; +A765;LATIN SMALL LETTER THORN WITH STROKE;Ll;0;L;;;;;N;;;A764;;A764 +A766;LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER;Lu;0;L;;;;;N;;;;A767; +A767;LATIN SMALL LETTER THORN WITH STROKE THROUGH DESCENDER;Ll;0;L;;;;;N;;;A766;;A766 +A768;LATIN CAPITAL LETTER VEND;Lu;0;L;;;;;N;;;;A769; +A769;LATIN SMALL LETTER VEND;Ll;0;L;;;;;N;;;A768;;A768 +A76A;LATIN CAPITAL LETTER ET;Lu;0;L;;;;;N;;;;A76B; +A76B;LATIN SMALL LETTER ET;Ll;0;L;;;;;N;;;A76A;;A76A +A76C;LATIN CAPITAL LETTER IS;Lu;0;L;;;;;N;;;;A76D; +A76D;LATIN SMALL LETTER IS;Ll;0;L;;;;;N;;;A76C;;A76C +A76E;LATIN CAPITAL LETTER CON;Lu;0;L;;;;;N;;;;A76F; +A76F;LATIN SMALL LETTER CON;Ll;0;L;;;;;N;;;A76E;;A76E +A770;MODIFIER LETTER US;Lm;0;L; A76F;;;;N;;;;; +A771;LATIN SMALL LETTER DUM;Ll;0;L;;;;;N;;;;; +A772;LATIN SMALL LETTER LUM;Ll;0;L;;;;;N;;;;; +A773;LATIN SMALL LETTER MUM;Ll;0;L;;;;;N;;;;; +A774;LATIN SMALL LETTER NUM;Ll;0;L;;;;;N;;;;; +A775;LATIN SMALL LETTER RUM;Ll;0;L;;;;;N;;;;; +A776;LATIN LETTER SMALL CAPITAL RUM;Ll;0;L;;;;;N;;;;; +A777;LATIN SMALL LETTER TUM;Ll;0;L;;;;;N;;;;; +A778;LATIN SMALL LETTER UM;Ll;0;L;;;;;N;;;;; +A779;LATIN CAPITAL LETTER INSULAR D;Lu;0;L;;;;;N;;;;A77A; +A77A;LATIN SMALL LETTER INSULAR D;Ll;0;L;;;;;N;;;A779;;A779 +A77B;LATIN CAPITAL LETTER INSULAR F;Lu;0;L;;;;;N;;;;A77C; +A77C;LATIN SMALL LETTER INSULAR F;Ll;0;L;;;;;N;;;A77B;;A77B +A77D;LATIN CAPITAL LETTER INSULAR G;Lu;0;L;;;;;N;;;;1D79; +A77E;LATIN CAPITAL LETTER TURNED INSULAR G;Lu;0;L;;;;;N;;;;A77F; +A77F;LATIN SMALL LETTER TURNED INSULAR G;Ll;0;L;;;;;N;;;A77E;;A77E +A780;LATIN CAPITAL LETTER TURNED L;Lu;0;L;;;;;N;;;;A781; +A781;LATIN SMALL LETTER TURNED L;Ll;0;L;;;;;N;;;A780;;A780 +A782;LATIN CAPITAL LETTER INSULAR R;Lu;0;L;;;;;N;;;;A783; +A783;LATIN SMALL LETTER INSULAR R;Ll;0;L;;;;;N;;;A782;;A782 +A784;LATIN CAPITAL LETTER INSULAR S;Lu;0;L;;;;;N;;;;A785; +A785;LATIN SMALL LETTER INSULAR S;Ll;0;L;;;;;N;;;A784;;A784 +A786;LATIN CAPITAL LETTER INSULAR T;Lu;0;L;;;;;N;;;;A787; +A787;LATIN SMALL LETTER INSULAR T;Ll;0;L;;;;;N;;;A786;;A786 +A788;MODIFIER LETTER LOW CIRCUMFLEX ACCENT;Lm;0;ON;;;;;N;;;;; +A789;MODIFIER LETTER COLON;Sk;0;L;;;;;N;;;;; +A78A;MODIFIER LETTER SHORT EQUALS SIGN;Sk;0;L;;;;;N;;;;; +A78B;LATIN CAPITAL LETTER SALTILLO;Lu;0;L;;;;;N;;;;A78C; +A78C;LATIN SMALL LETTER SALTILLO;Ll;0;L;;;;;N;;;A78B;;A78B +A78D;LATIN CAPITAL LETTER TURNED H;Lu;0;L;;;;;N;;;;0265; +A78E;LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT;Ll;0;L;;;;;N;;;;; +A78F;LATIN LETTER SINOLOGICAL DOT;Lo;0;L;;;;;N;;;;; +A790;LATIN CAPITAL LETTER N WITH DESCENDER;Lu;0;L;;;;;N;;;;A791; +A791;LATIN SMALL LETTER N WITH DESCENDER;Ll;0;L;;;;;N;;;A790;;A790 +A792;LATIN CAPITAL LETTER C WITH BAR;Lu;0;L;;;;;N;;;;A793; +A793;LATIN SMALL LETTER C WITH BAR;Ll;0;L;;;;;N;;;A792;;A792 +A794;LATIN SMALL LETTER C WITH PALATAL HOOK;Ll;0;L;;;;;N;;;A7C4;;A7C4 +A795;LATIN SMALL LETTER H WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +A796;LATIN CAPITAL LETTER B WITH FLOURISH;Lu;0;L;;;;;N;;;;A797; +A797;LATIN SMALL LETTER B WITH FLOURISH;Ll;0;L;;;;;N;;;A796;;A796 +A798;LATIN CAPITAL LETTER F WITH STROKE;Lu;0;L;;;;;N;;;;A799; +A799;LATIN SMALL LETTER F WITH STROKE;Ll;0;L;;;;;N;;;A798;;A798 +A79A;LATIN CAPITAL LETTER VOLAPUK AE;Lu;0;L;;;;;N;;;;A79B; +A79B;LATIN SMALL LETTER VOLAPUK AE;Ll;0;L;;;;;N;;;A79A;;A79A +A79C;LATIN CAPITAL LETTER VOLAPUK OE;Lu;0;L;;;;;N;;;;A79D; +A79D;LATIN SMALL LETTER VOLAPUK OE;Ll;0;L;;;;;N;;;A79C;;A79C +A79E;LATIN CAPITAL LETTER VOLAPUK UE;Lu;0;L;;;;;N;;;;A79F; +A79F;LATIN SMALL LETTER VOLAPUK UE;Ll;0;L;;;;;N;;;A79E;;A79E +A7A0;LATIN CAPITAL LETTER G WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A1; +A7A1;LATIN SMALL LETTER G WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A0;;A7A0 +A7A2;LATIN CAPITAL LETTER K WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A3; +A7A3;LATIN SMALL LETTER K WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A2;;A7A2 +A7A4;LATIN CAPITAL LETTER N WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A5; +A7A5;LATIN SMALL LETTER N WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A4;;A7A4 +A7A6;LATIN CAPITAL LETTER R WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A7; +A7A7;LATIN SMALL LETTER R WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A6;;A7A6 +A7A8;LATIN CAPITAL LETTER S WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A9; +A7A9;LATIN SMALL LETTER S WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A8;;A7A8 +A7AA;LATIN CAPITAL LETTER H WITH HOOK;Lu;0;L;;;;;N;;;;0266; +A7AB;LATIN CAPITAL LETTER REVERSED OPEN E;Lu;0;L;;;;;N;;;;025C; +A7AC;LATIN CAPITAL LETTER SCRIPT G;Lu;0;L;;;;;N;;;;0261; +A7AD;LATIN CAPITAL LETTER L WITH BELT;Lu;0;L;;;;;N;;;;026C; +A7AE;LATIN CAPITAL LETTER SMALL CAPITAL I;Lu;0;L;;;;;N;;;;026A; +A7AF;LATIN LETTER SMALL CAPITAL Q;Ll;0;L;;;;;N;;;;; +A7B0;LATIN CAPITAL LETTER TURNED K;Lu;0;L;;;;;N;;;;029E; +A7B1;LATIN CAPITAL LETTER TURNED T;Lu;0;L;;;;;N;;;;0287; +A7B2;LATIN CAPITAL LETTER J WITH CROSSED-TAIL;Lu;0;L;;;;;N;;;;029D; +A7B3;LATIN CAPITAL LETTER CHI;Lu;0;L;;;;;N;;;;AB53; +A7B4;LATIN CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;A7B5; +A7B5;LATIN SMALL LETTER BETA;Ll;0;L;;;;;N;;;A7B4;;A7B4 +A7B6;LATIN CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;A7B7; +A7B7;LATIN SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;A7B6;;A7B6 +A7B8;LATIN CAPITAL LETTER U WITH STROKE;Lu;0;L;;;;;N;;;;A7B9; +A7B9;LATIN SMALL LETTER U WITH STROKE;Ll;0;L;;;;;N;;;A7B8;;A7B8 +A7BA;LATIN CAPITAL LETTER GLOTTAL A;Lu;0;L;;;;;N;;;;A7BB; +A7BB;LATIN SMALL LETTER GLOTTAL A;Ll;0;L;;;;;N;;;A7BA;;A7BA +A7BC;LATIN CAPITAL LETTER GLOTTAL I;Lu;0;L;;;;;N;;;;A7BD; +A7BD;LATIN SMALL LETTER GLOTTAL I;Ll;0;L;;;;;N;;;A7BC;;A7BC +A7BE;LATIN CAPITAL LETTER GLOTTAL U;Lu;0;L;;;;;N;;;;A7BF; +A7BF;LATIN SMALL LETTER GLOTTAL U;Ll;0;L;;;;;N;;;A7BE;;A7BE +A7C0;LATIN CAPITAL LETTER OLD POLISH O;Lu;0;L;;;;;N;;;;A7C1; +A7C1;LATIN SMALL LETTER OLD POLISH O;Ll;0;L;;;;;N;;;A7C0;;A7C0 +A7C2;LATIN CAPITAL LETTER ANGLICANA W;Lu;0;L;;;;;N;;;;A7C3; +A7C3;LATIN SMALL LETTER ANGLICANA W;Ll;0;L;;;;;N;;;A7C2;;A7C2 +A7C4;LATIN CAPITAL LETTER C WITH PALATAL HOOK;Lu;0;L;;;;;N;;;;A794; +A7C5;LATIN CAPITAL LETTER S WITH HOOK;Lu;0;L;;;;;N;;;;0282; +A7C6;LATIN CAPITAL LETTER Z WITH PALATAL HOOK;Lu;0;L;;;;;N;;;;1D8E; +A7C7;LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY;Lu;0;L;;;;;N;;;;A7C8; +A7C8;LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY;Ll;0;L;;;;;N;;;A7C7;;A7C7 +A7C9;LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY;Lu;0;L;;;;;N;;;;A7CA; +A7CA;LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY;Ll;0;L;;;;;N;;;A7C9;;A7C9 +A7CB;LATIN CAPITAL LETTER RAMS HORN;Lu;0;L;;;;;N;;;;0264; +A7CC;LATIN CAPITAL LETTER S WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A7CD; +A7CD;LATIN SMALL LETTER S WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A7CC;;A7CC +A7CE;LATIN CAPITAL LETTER PHARYNGEAL VOICED FRICATIVE;Lu;0;L;;;;;N;;;;A7CF; +A7CF;LATIN SMALL LETTER PHARYNGEAL VOICED FRICATIVE;Ll;0;L;;;;;N;;;A7CE;;A7CE +A7D0;LATIN CAPITAL LETTER CLOSED INSULAR G;Lu;0;L;;;;;N;;;;A7D1; +A7D1;LATIN SMALL LETTER CLOSED INSULAR G;Ll;0;L;;;;;N;;;A7D0;;A7D0 +A7D2;LATIN CAPITAL LETTER DOUBLE THORN;Lu;0;L;;;;;N;;;;A7D3; +A7D3;LATIN SMALL LETTER DOUBLE THORN;Ll;0;L;;;;;N;;;A7D2;;A7D2 +A7D4;LATIN CAPITAL LETTER DOUBLE WYNN;Lu;0;L;;;;;N;;;;A7D5; +A7D5;LATIN SMALL LETTER DOUBLE WYNN;Ll;0;L;;;;;N;;;A7D4;;A7D4 +A7D6;LATIN CAPITAL LETTER MIDDLE SCOTS S;Lu;0;L;;;;;N;;;;A7D7; +A7D7;LATIN SMALL LETTER MIDDLE SCOTS S;Ll;0;L;;;;;N;;;A7D6;;A7D6 +A7D8;LATIN CAPITAL LETTER SIGMOID S;Lu;0;L;;;;;N;;;;A7D9; +A7D9;LATIN SMALL LETTER SIGMOID S;Ll;0;L;;;;;N;;;A7D8;;A7D8 +A7DA;LATIN CAPITAL LETTER LAMBDA;Lu;0;L;;;;;N;;;;A7DB; +A7DB;LATIN SMALL LETTER LAMBDA;Ll;0;L;;;;;N;;;A7DA;;A7DA +A7DC;LATIN CAPITAL LETTER LAMBDA WITH STROKE;Lu;0;L;;;;;N;;;;019B; +A7F1;MODIFIER LETTER CAPITAL S;Lm;0;L; 0053;;;;N;;;;; +A7F2;MODIFIER LETTER CAPITAL C;Lm;0;L; 0043;;;;N;;;;; +A7F3;MODIFIER LETTER CAPITAL F;Lm;0;L; 0046;;;;N;;;;; +A7F4;MODIFIER LETTER CAPITAL Q;Lm;0;L; 0051;;;;N;;;;; +A7F5;LATIN CAPITAL LETTER REVERSED HALF H;Lu;0;L;;;;;N;;;;A7F6; +A7F6;LATIN SMALL LETTER REVERSED HALF H;Ll;0;L;;;;;N;;;A7F5;;A7F5 +A7F7;LATIN EPIGRAPHIC LETTER SIDEWAYS I;Lo;0;L;;;;;N;;;;; +A7F8;MODIFIER LETTER CAPITAL H WITH STROKE;Lm;0;L; 0126;;;;N;;;;; +A7F9;MODIFIER LETTER SMALL LIGATURE OE;Lm;0;L; 0153;;;;N;;;;; +A7FA;LATIN LETTER SMALL CAPITAL TURNED M;Ll;0;L;;;;;N;;;;; +A7FB;LATIN EPIGRAPHIC LETTER REVERSED F;Lo;0;L;;;;;N;;;;; +A7FC;LATIN EPIGRAPHIC LETTER REVERSED P;Lo;0;L;;;;;N;;;;; +A7FD;LATIN EPIGRAPHIC LETTER INVERTED M;Lo;0;L;;;;;N;;;;; +A7FE;LATIN EPIGRAPHIC LETTER I LONGA;Lo;0;L;;;;;N;;;;; +A7FF;LATIN EPIGRAPHIC LETTER ARCHAIC M;Lo;0;L;;;;;N;;;;; +A800;SYLOTI NAGRI LETTER A;Lo;0;L;;;;;N;;;;; +A801;SYLOTI NAGRI LETTER I;Lo;0;L;;;;;N;;;;; +A802;SYLOTI NAGRI SIGN DVISVARA;Mn;0;NSM;;;;;N;;;;; +A803;SYLOTI NAGRI LETTER U;Lo;0;L;;;;;N;;;;; +A804;SYLOTI NAGRI LETTER E;Lo;0;L;;;;;N;;;;; +A805;SYLOTI NAGRI LETTER O;Lo;0;L;;;;;N;;;;; +A806;SYLOTI NAGRI SIGN HASANTA;Mn;9;NSM;;;;;N;;;;; +A807;SYLOTI NAGRI LETTER KO;Lo;0;L;;;;;N;;;;; +A808;SYLOTI NAGRI LETTER KHO;Lo;0;L;;;;;N;;;;; +A809;SYLOTI NAGRI LETTER GO;Lo;0;L;;;;;N;;;;; +A80A;SYLOTI NAGRI LETTER GHO;Lo;0;L;;;;;N;;;;; +A80B;SYLOTI NAGRI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +A80C;SYLOTI NAGRI LETTER CO;Lo;0;L;;;;;N;;;;; +A80D;SYLOTI NAGRI LETTER CHO;Lo;0;L;;;;;N;;;;; +A80E;SYLOTI NAGRI LETTER JO;Lo;0;L;;;;;N;;;;; +A80F;SYLOTI NAGRI LETTER JHO;Lo;0;L;;;;;N;;;;; +A810;SYLOTI NAGRI LETTER TTO;Lo;0;L;;;;;N;;;;; +A811;SYLOTI NAGRI LETTER TTHO;Lo;0;L;;;;;N;;;;; +A812;SYLOTI NAGRI LETTER DDO;Lo;0;L;;;;;N;;;;; +A813;SYLOTI NAGRI LETTER DDHO;Lo;0;L;;;;;N;;;;; +A814;SYLOTI NAGRI LETTER TO;Lo;0;L;;;;;N;;;;; +A815;SYLOTI NAGRI LETTER THO;Lo;0;L;;;;;N;;;;; +A816;SYLOTI NAGRI LETTER DO;Lo;0;L;;;;;N;;;;; +A817;SYLOTI NAGRI LETTER DHO;Lo;0;L;;;;;N;;;;; +A818;SYLOTI NAGRI LETTER NO;Lo;0;L;;;;;N;;;;; +A819;SYLOTI NAGRI LETTER PO;Lo;0;L;;;;;N;;;;; +A81A;SYLOTI NAGRI LETTER PHO;Lo;0;L;;;;;N;;;;; +A81B;SYLOTI NAGRI LETTER BO;Lo;0;L;;;;;N;;;;; +A81C;SYLOTI NAGRI LETTER BHO;Lo;0;L;;;;;N;;;;; +A81D;SYLOTI NAGRI LETTER MO;Lo;0;L;;;;;N;;;;; +A81E;SYLOTI NAGRI LETTER RO;Lo;0;L;;;;;N;;;;; +A81F;SYLOTI NAGRI LETTER LO;Lo;0;L;;;;;N;;;;; +A820;SYLOTI NAGRI LETTER RRO;Lo;0;L;;;;;N;;;;; +A821;SYLOTI NAGRI LETTER SO;Lo;0;L;;;;;N;;;;; +A822;SYLOTI NAGRI LETTER HO;Lo;0;L;;;;;N;;;;; +A823;SYLOTI NAGRI VOWEL SIGN A;Mc;0;L;;;;;N;;;;; +A824;SYLOTI NAGRI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +A825;SYLOTI NAGRI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +A826;SYLOTI NAGRI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +A827;SYLOTI NAGRI VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; +A828;SYLOTI NAGRI POETRY MARK-1;So;0;ON;;;;;N;;;;; +A829;SYLOTI NAGRI POETRY MARK-2;So;0;ON;;;;;N;;;;; +A82A;SYLOTI NAGRI POETRY MARK-3;So;0;ON;;;;;N;;;;; +A82B;SYLOTI NAGRI POETRY MARK-4;So;0;ON;;;;;N;;;;; +A82C;SYLOTI NAGRI SIGN ALTERNATE HASANTA;Mn;9;NSM;;;;;N;;;;; +A830;NORTH INDIC FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;; +A831;NORTH INDIC FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;; +A832;NORTH INDIC FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;; +A833;NORTH INDIC FRACTION ONE SIXTEENTH;No;0;L;;;;1/16;N;;;;; +A834;NORTH INDIC FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;; +A835;NORTH INDIC FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;; +A836;NORTH INDIC QUARTER MARK;So;0;L;;;;;N;;;;; +A837;NORTH INDIC PLACEHOLDER MARK;So;0;L;;;;;N;;;;; +A838;NORTH INDIC RUPEE MARK;Sc;0;ET;;;;;N;;;;; +A839;NORTH INDIC QUANTITY MARK;So;0;ET;;;;;N;;;;; +A840;PHAGS-PA LETTER KA;Lo;0;L;;;;;N;;;;; +A841;PHAGS-PA LETTER KHA;Lo;0;L;;;;;N;;;;; +A842;PHAGS-PA LETTER GA;Lo;0;L;;;;;N;;;;; +A843;PHAGS-PA LETTER NGA;Lo;0;L;;;;;N;;;;; +A844;PHAGS-PA LETTER CA;Lo;0;L;;;;;N;;;;; +A845;PHAGS-PA LETTER CHA;Lo;0;L;;;;;N;;;;; +A846;PHAGS-PA LETTER JA;Lo;0;L;;;;;N;;;;; +A847;PHAGS-PA LETTER NYA;Lo;0;L;;;;;N;;;;; +A848;PHAGS-PA LETTER TA;Lo;0;L;;;;;N;;;;; +A849;PHAGS-PA LETTER THA;Lo;0;L;;;;;N;;;;; +A84A;PHAGS-PA LETTER DA;Lo;0;L;;;;;N;;;;; +A84B;PHAGS-PA LETTER NA;Lo;0;L;;;;;N;;;;; +A84C;PHAGS-PA LETTER PA;Lo;0;L;;;;;N;;;;; +A84D;PHAGS-PA LETTER PHA;Lo;0;L;;;;;N;;;;; +A84E;PHAGS-PA LETTER BA;Lo;0;L;;;;;N;;;;; +A84F;PHAGS-PA LETTER MA;Lo;0;L;;;;;N;;;;; +A850;PHAGS-PA LETTER TSA;Lo;0;L;;;;;N;;;;; +A851;PHAGS-PA LETTER TSHA;Lo;0;L;;;;;N;;;;; +A852;PHAGS-PA LETTER DZA;Lo;0;L;;;;;N;;;;; +A853;PHAGS-PA LETTER WA;Lo;0;L;;;;;N;;;;; +A854;PHAGS-PA LETTER ZHA;Lo;0;L;;;;;N;;;;; +A855;PHAGS-PA LETTER ZA;Lo;0;L;;;;;N;;;;; +A856;PHAGS-PA LETTER SMALL A;Lo;0;L;;;;;N;;;;; +A857;PHAGS-PA LETTER YA;Lo;0;L;;;;;N;;;;; +A858;PHAGS-PA LETTER RA;Lo;0;L;;;;;N;;;;; +A859;PHAGS-PA LETTER LA;Lo;0;L;;;;;N;;;;; +A85A;PHAGS-PA LETTER SHA;Lo;0;L;;;;;N;;;;; +A85B;PHAGS-PA LETTER SA;Lo;0;L;;;;;N;;;;; +A85C;PHAGS-PA LETTER HA;Lo;0;L;;;;;N;;;;; +A85D;PHAGS-PA LETTER A;Lo;0;L;;;;;N;;;;; +A85E;PHAGS-PA LETTER I;Lo;0;L;;;;;N;;;;; +A85F;PHAGS-PA LETTER U;Lo;0;L;;;;;N;;;;; +A860;PHAGS-PA LETTER E;Lo;0;L;;;;;N;;;;; +A861;PHAGS-PA LETTER O;Lo;0;L;;;;;N;;;;; +A862;PHAGS-PA LETTER QA;Lo;0;L;;;;;N;;;;; +A863;PHAGS-PA LETTER XA;Lo;0;L;;;;;N;;;;; +A864;PHAGS-PA LETTER FA;Lo;0;L;;;;;N;;;;; +A865;PHAGS-PA LETTER GGA;Lo;0;L;;;;;N;;;;; +A866;PHAGS-PA LETTER EE;Lo;0;L;;;;;N;;;;; +A867;PHAGS-PA SUBJOINED LETTER WA;Lo;0;L;;;;;N;;;;; +A868;PHAGS-PA SUBJOINED LETTER YA;Lo;0;L;;;;;N;;;;; +A869;PHAGS-PA LETTER TTA;Lo;0;L;;;;;N;;;;; +A86A;PHAGS-PA LETTER TTHA;Lo;0;L;;;;;N;;;;; +A86B;PHAGS-PA LETTER DDA;Lo;0;L;;;;;N;;;;; +A86C;PHAGS-PA LETTER NNA;Lo;0;L;;;;;N;;;;; +A86D;PHAGS-PA LETTER ALTERNATE YA;Lo;0;L;;;;;N;;;;; +A86E;PHAGS-PA LETTER VOICELESS SHA;Lo;0;L;;;;;N;;;;; +A86F;PHAGS-PA LETTER VOICED HA;Lo;0;L;;;;;N;;;;; +A870;PHAGS-PA LETTER ASPIRATED FA;Lo;0;L;;;;;N;;;;; +A871;PHAGS-PA SUBJOINED LETTER RA;Lo;0;L;;;;;N;;;;; +A872;PHAGS-PA SUPERFIXED LETTER RA;Lo;0;L;;;;;N;;;;; +A873;PHAGS-PA LETTER CANDRABINDU;Lo;0;L;;;;;N;;;;; +A874;PHAGS-PA SINGLE HEAD MARK;Po;0;ON;;;;;N;;;;; +A875;PHAGS-PA DOUBLE HEAD MARK;Po;0;ON;;;;;N;;;;; +A876;PHAGS-PA MARK SHAD;Po;0;ON;;;;;N;;;;; +A877;PHAGS-PA MARK DOUBLE SHAD;Po;0;ON;;;;;N;;;;; +A880;SAURASHTRA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +A881;SAURASHTRA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +A882;SAURASHTRA LETTER A;Lo;0;L;;;;;N;;;;; +A883;SAURASHTRA LETTER AA;Lo;0;L;;;;;N;;;;; +A884;SAURASHTRA LETTER I;Lo;0;L;;;;;N;;;;; +A885;SAURASHTRA LETTER II;Lo;0;L;;;;;N;;;;; +A886;SAURASHTRA LETTER U;Lo;0;L;;;;;N;;;;; +A887;SAURASHTRA LETTER UU;Lo;0;L;;;;;N;;;;; +A888;SAURASHTRA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +A889;SAURASHTRA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +A88A;SAURASHTRA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +A88B;SAURASHTRA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +A88C;SAURASHTRA LETTER E;Lo;0;L;;;;;N;;;;; +A88D;SAURASHTRA LETTER EE;Lo;0;L;;;;;N;;;;; +A88E;SAURASHTRA LETTER AI;Lo;0;L;;;;;N;;;;; +A88F;SAURASHTRA LETTER O;Lo;0;L;;;;;N;;;;; +A890;SAURASHTRA LETTER OO;Lo;0;L;;;;;N;;;;; +A891;SAURASHTRA LETTER AU;Lo;0;L;;;;;N;;;;; +A892;SAURASHTRA LETTER KA;Lo;0;L;;;;;N;;;;; +A893;SAURASHTRA LETTER KHA;Lo;0;L;;;;;N;;;;; +A894;SAURASHTRA LETTER GA;Lo;0;L;;;;;N;;;;; +A895;SAURASHTRA LETTER GHA;Lo;0;L;;;;;N;;;;; +A896;SAURASHTRA LETTER NGA;Lo;0;L;;;;;N;;;;; +A897;SAURASHTRA LETTER CA;Lo;0;L;;;;;N;;;;; +A898;SAURASHTRA LETTER CHA;Lo;0;L;;;;;N;;;;; +A899;SAURASHTRA LETTER JA;Lo;0;L;;;;;N;;;;; +A89A;SAURASHTRA LETTER JHA;Lo;0;L;;;;;N;;;;; +A89B;SAURASHTRA LETTER NYA;Lo;0;L;;;;;N;;;;; +A89C;SAURASHTRA LETTER TTA;Lo;0;L;;;;;N;;;;; +A89D;SAURASHTRA LETTER TTHA;Lo;0;L;;;;;N;;;;; +A89E;SAURASHTRA LETTER DDA;Lo;0;L;;;;;N;;;;; +A89F;SAURASHTRA LETTER DDHA;Lo;0;L;;;;;N;;;;; +A8A0;SAURASHTRA LETTER NNA;Lo;0;L;;;;;N;;;;; +A8A1;SAURASHTRA LETTER TA;Lo;0;L;;;;;N;;;;; +A8A2;SAURASHTRA LETTER THA;Lo;0;L;;;;;N;;;;; +A8A3;SAURASHTRA LETTER DA;Lo;0;L;;;;;N;;;;; +A8A4;SAURASHTRA LETTER DHA;Lo;0;L;;;;;N;;;;; +A8A5;SAURASHTRA LETTER NA;Lo;0;L;;;;;N;;;;; +A8A6;SAURASHTRA LETTER PA;Lo;0;L;;;;;N;;;;; +A8A7;SAURASHTRA LETTER PHA;Lo;0;L;;;;;N;;;;; +A8A8;SAURASHTRA LETTER BA;Lo;0;L;;;;;N;;;;; +A8A9;SAURASHTRA LETTER BHA;Lo;0;L;;;;;N;;;;; +A8AA;SAURASHTRA LETTER MA;Lo;0;L;;;;;N;;;;; +A8AB;SAURASHTRA LETTER YA;Lo;0;L;;;;;N;;;;; +A8AC;SAURASHTRA LETTER RA;Lo;0;L;;;;;N;;;;; +A8AD;SAURASHTRA LETTER LA;Lo;0;L;;;;;N;;;;; +A8AE;SAURASHTRA LETTER VA;Lo;0;L;;;;;N;;;;; +A8AF;SAURASHTRA LETTER SHA;Lo;0;L;;;;;N;;;;; +A8B0;SAURASHTRA LETTER SSA;Lo;0;L;;;;;N;;;;; +A8B1;SAURASHTRA LETTER SA;Lo;0;L;;;;;N;;;;; +A8B2;SAURASHTRA LETTER HA;Lo;0;L;;;;;N;;;;; +A8B3;SAURASHTRA LETTER LLA;Lo;0;L;;;;;N;;;;; +A8B4;SAURASHTRA CONSONANT SIGN HAARU;Mc;0;L;;;;;N;;;;; +A8B5;SAURASHTRA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +A8B6;SAURASHTRA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +A8B7;SAURASHTRA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +A8B8;SAURASHTRA VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +A8B9;SAURASHTRA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +A8BA;SAURASHTRA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; +A8BB;SAURASHTRA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; +A8BC;SAURASHTRA VOWEL SIGN VOCALIC L;Mc;0;L;;;;;N;;;;; +A8BD;SAURASHTRA VOWEL SIGN VOCALIC LL;Mc;0;L;;;;;N;;;;; +A8BE;SAURASHTRA VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +A8BF;SAURASHTRA VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; +A8C0;SAURASHTRA VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +A8C1;SAURASHTRA VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +A8C2;SAURASHTRA VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; +A8C3;SAURASHTRA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +A8C4;SAURASHTRA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +A8C5;SAURASHTRA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +A8CE;SAURASHTRA DANDA;Po;0;L;;;;;N;;;;; +A8CF;SAURASHTRA DOUBLE DANDA;Po;0;L;;;;;N;;;;; +A8D0;SAURASHTRA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +A8D1;SAURASHTRA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +A8D2;SAURASHTRA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +A8D3;SAURASHTRA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +A8D4;SAURASHTRA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +A8D5;SAURASHTRA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +A8D6;SAURASHTRA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +A8D7;SAURASHTRA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +A8D8;SAURASHTRA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +A8D9;SAURASHTRA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +A8E0;COMBINING DEVANAGARI DIGIT ZERO;Mn;230;NSM;;;;;N;;;;; +A8E1;COMBINING DEVANAGARI DIGIT ONE;Mn;230;NSM;;;;;N;;;;; +A8E2;COMBINING DEVANAGARI DIGIT TWO;Mn;230;NSM;;;;;N;;;;; +A8E3;COMBINING DEVANAGARI DIGIT THREE;Mn;230;NSM;;;;;N;;;;; +A8E4;COMBINING DEVANAGARI DIGIT FOUR;Mn;230;NSM;;;;;N;;;;; +A8E5;COMBINING DEVANAGARI DIGIT FIVE;Mn;230;NSM;;;;;N;;;;; +A8E6;COMBINING DEVANAGARI DIGIT SIX;Mn;230;NSM;;;;;N;;;;; +A8E7;COMBINING DEVANAGARI DIGIT SEVEN;Mn;230;NSM;;;;;N;;;;; +A8E8;COMBINING DEVANAGARI DIGIT EIGHT;Mn;230;NSM;;;;;N;;;;; +A8E9;COMBINING DEVANAGARI DIGIT NINE;Mn;230;NSM;;;;;N;;;;; +A8EA;COMBINING DEVANAGARI LETTER A;Mn;230;NSM;;;;;N;;;;; +A8EB;COMBINING DEVANAGARI LETTER U;Mn;230;NSM;;;;;N;;;;; +A8EC;COMBINING DEVANAGARI LETTER KA;Mn;230;NSM;;;;;N;;;;; +A8ED;COMBINING DEVANAGARI LETTER NA;Mn;230;NSM;;;;;N;;;;; +A8EE;COMBINING DEVANAGARI LETTER PA;Mn;230;NSM;;;;;N;;;;; +A8EF;COMBINING DEVANAGARI LETTER RA;Mn;230;NSM;;;;;N;;;;; +A8F0;COMBINING DEVANAGARI LETTER VI;Mn;230;NSM;;;;;N;;;;; +A8F1;COMBINING DEVANAGARI SIGN AVAGRAHA;Mn;230;NSM;;;;;N;;;;; +A8F2;DEVANAGARI SIGN SPACING CANDRABINDU;Lo;0;L;;;;;N;;;;; +A8F3;DEVANAGARI SIGN CANDRABINDU VIRAMA;Lo;0;L;;;;;N;;;;; +A8F4;DEVANAGARI SIGN DOUBLE CANDRABINDU VIRAMA;Lo;0;L;;;;;N;;;;; +A8F5;DEVANAGARI SIGN CANDRABINDU TWO;Lo;0;L;;;;;N;;;;; +A8F6;DEVANAGARI SIGN CANDRABINDU THREE;Lo;0;L;;;;;N;;;;; +A8F7;DEVANAGARI SIGN CANDRABINDU AVAGRAHA;Lo;0;L;;;;;N;;;;; +A8F8;DEVANAGARI SIGN PUSHPIKA;Po;0;L;;;;;N;;;;; +A8F9;DEVANAGARI GAP FILLER;Po;0;L;;;;;N;;;;; +A8FA;DEVANAGARI CARET;Po;0;L;;;;;N;;;;; +A8FB;DEVANAGARI HEADSTROKE;Lo;0;L;;;;;N;;;;; +A8FC;DEVANAGARI SIGN SIDDHAM;Po;0;L;;;;;N;;;;; +A8FD;DEVANAGARI JAIN OM;Lo;0;L;;;;;N;;;;; +A8FE;DEVANAGARI LETTER AY;Lo;0;L;;;;;N;;;;; +A8FF;DEVANAGARI VOWEL SIGN AY;Mn;0;NSM;;;;;N;;;;; +A900;KAYAH LI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +A901;KAYAH LI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +A902;KAYAH LI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +A903;KAYAH LI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +A904;KAYAH LI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +A905;KAYAH LI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +A906;KAYAH LI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +A907;KAYAH LI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +A908;KAYAH LI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +A909;KAYAH LI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +A90A;KAYAH LI LETTER KA;Lo;0;L;;;;;N;;;;; +A90B;KAYAH LI LETTER KHA;Lo;0;L;;;;;N;;;;; +A90C;KAYAH LI LETTER GA;Lo;0;L;;;;;N;;;;; +A90D;KAYAH LI LETTER NGA;Lo;0;L;;;;;N;;;;; +A90E;KAYAH LI LETTER SA;Lo;0;L;;;;;N;;;;; +A90F;KAYAH LI LETTER SHA;Lo;0;L;;;;;N;;;;; +A910;KAYAH LI LETTER ZA;Lo;0;L;;;;;N;;;;; +A911;KAYAH LI LETTER NYA;Lo;0;L;;;;;N;;;;; +A912;KAYAH LI LETTER TA;Lo;0;L;;;;;N;;;;; +A913;KAYAH LI LETTER HTA;Lo;0;L;;;;;N;;;;; +A914;KAYAH LI LETTER NA;Lo;0;L;;;;;N;;;;; +A915;KAYAH LI LETTER PA;Lo;0;L;;;;;N;;;;; +A916;KAYAH LI LETTER PHA;Lo;0;L;;;;;N;;;;; +A917;KAYAH LI LETTER MA;Lo;0;L;;;;;N;;;;; +A918;KAYAH LI LETTER DA;Lo;0;L;;;;;N;;;;; +A919;KAYAH LI LETTER BA;Lo;0;L;;;;;N;;;;; +A91A;KAYAH LI LETTER RA;Lo;0;L;;;;;N;;;;; +A91B;KAYAH LI LETTER YA;Lo;0;L;;;;;N;;;;; +A91C;KAYAH LI LETTER LA;Lo;0;L;;;;;N;;;;; +A91D;KAYAH LI LETTER WA;Lo;0;L;;;;;N;;;;; +A91E;KAYAH LI LETTER THA;Lo;0;L;;;;;N;;;;; +A91F;KAYAH LI LETTER HA;Lo;0;L;;;;;N;;;;; +A920;KAYAH LI LETTER VA;Lo;0;L;;;;;N;;;;; +A921;KAYAH LI LETTER CA;Lo;0;L;;;;;N;;;;; +A922;KAYAH LI LETTER A;Lo;0;L;;;;;N;;;;; +A923;KAYAH LI LETTER OE;Lo;0;L;;;;;N;;;;; +A924;KAYAH LI LETTER I;Lo;0;L;;;;;N;;;;; +A925;KAYAH LI LETTER OO;Lo;0;L;;;;;N;;;;; +A926;KAYAH LI VOWEL UE;Mn;0;NSM;;;;;N;;;;; +A927;KAYAH LI VOWEL E;Mn;0;NSM;;;;;N;;;;; +A928;KAYAH LI VOWEL U;Mn;0;NSM;;;;;N;;;;; +A929;KAYAH LI VOWEL EE;Mn;0;NSM;;;;;N;;;;; +A92A;KAYAH LI VOWEL O;Mn;0;NSM;;;;;N;;;;; +A92B;KAYAH LI TONE PLOPHU;Mn;220;NSM;;;;;N;;;;; +A92C;KAYAH LI TONE CALYA;Mn;220;NSM;;;;;N;;;;; +A92D;KAYAH LI TONE CALYA PLOPHU;Mn;220;NSM;;;;;N;;;;; +A92E;KAYAH LI SIGN CWI;Po;0;L;;;;;N;;;;; +A92F;KAYAH LI SIGN SHYA;Po;0;L;;;;;N;;;;; +A930;REJANG LETTER KA;Lo;0;L;;;;;N;;;;; +A931;REJANG LETTER GA;Lo;0;L;;;;;N;;;;; +A932;REJANG LETTER NGA;Lo;0;L;;;;;N;;;;; +A933;REJANG LETTER TA;Lo;0;L;;;;;N;;;;; +A934;REJANG LETTER DA;Lo;0;L;;;;;N;;;;; +A935;REJANG LETTER NA;Lo;0;L;;;;;N;;;;; +A936;REJANG LETTER PA;Lo;0;L;;;;;N;;;;; +A937;REJANG LETTER BA;Lo;0;L;;;;;N;;;;; +A938;REJANG LETTER MA;Lo;0;L;;;;;N;;;;; +A939;REJANG LETTER CA;Lo;0;L;;;;;N;;;;; +A93A;REJANG LETTER JA;Lo;0;L;;;;;N;;;;; +A93B;REJANG LETTER NYA;Lo;0;L;;;;;N;;;;; +A93C;REJANG LETTER SA;Lo;0;L;;;;;N;;;;; +A93D;REJANG LETTER RA;Lo;0;L;;;;;N;;;;; +A93E;REJANG LETTER LA;Lo;0;L;;;;;N;;;;; +A93F;REJANG LETTER YA;Lo;0;L;;;;;N;;;;; +A940;REJANG LETTER WA;Lo;0;L;;;;;N;;;;; +A941;REJANG LETTER HA;Lo;0;L;;;;;N;;;;; +A942;REJANG LETTER MBA;Lo;0;L;;;;;N;;;;; +A943;REJANG LETTER NGGA;Lo;0;L;;;;;N;;;;; +A944;REJANG LETTER NDA;Lo;0;L;;;;;N;;;;; +A945;REJANG LETTER NYJA;Lo;0;L;;;;;N;;;;; +A946;REJANG LETTER A;Lo;0;L;;;;;N;;;;; +A947;REJANG VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +A948;REJANG VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +A949;REJANG VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +A94A;REJANG VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +A94B;REJANG VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +A94C;REJANG VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +A94D;REJANG VOWEL SIGN EU;Mn;0;NSM;;;;;N;;;;; +A94E;REJANG VOWEL SIGN EA;Mn;0;NSM;;;;;N;;;;; +A94F;REJANG CONSONANT SIGN NG;Mn;0;NSM;;;;;N;;;;; +A950;REJANG CONSONANT SIGN N;Mn;0;NSM;;;;;N;;;;; +A951;REJANG CONSONANT SIGN R;Mn;0;NSM;;;;;N;;;;; +A952;REJANG CONSONANT SIGN H;Mc;0;L;;;;;N;;;;; +A953;REJANG VIRAMA;Mc;9;L;;;;;N;;;;; +A95F;REJANG SECTION MARK;Po;0;L;;;;;N;;;;; +A960;HANGUL CHOSEONG TIKEUT-MIEUM;Lo;0;L;;;;;N;;;;; +A961;HANGUL CHOSEONG TIKEUT-PIEUP;Lo;0;L;;;;;N;;;;; +A962;HANGUL CHOSEONG TIKEUT-SIOS;Lo;0;L;;;;;N;;;;; +A963;HANGUL CHOSEONG TIKEUT-CIEUC;Lo;0;L;;;;;N;;;;; +A964;HANGUL CHOSEONG RIEUL-KIYEOK;Lo;0;L;;;;;N;;;;; +A965;HANGUL CHOSEONG RIEUL-SSANGKIYEOK;Lo;0;L;;;;;N;;;;; +A966;HANGUL CHOSEONG RIEUL-TIKEUT;Lo;0;L;;;;;N;;;;; +A967;HANGUL CHOSEONG RIEUL-SSANGTIKEUT;Lo;0;L;;;;;N;;;;; +A968;HANGUL CHOSEONG RIEUL-MIEUM;Lo;0;L;;;;;N;;;;; +A969;HANGUL CHOSEONG RIEUL-PIEUP;Lo;0;L;;;;;N;;;;; +A96A;HANGUL CHOSEONG RIEUL-SSANGPIEUP;Lo;0;L;;;;;N;;;;; +A96B;HANGUL CHOSEONG RIEUL-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; +A96C;HANGUL CHOSEONG RIEUL-SIOS;Lo;0;L;;;;;N;;;;; +A96D;HANGUL CHOSEONG RIEUL-CIEUC;Lo;0;L;;;;;N;;;;; +A96E;HANGUL CHOSEONG RIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;; +A96F;HANGUL CHOSEONG MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;; +A970;HANGUL CHOSEONG MIEUM-TIKEUT;Lo;0;L;;;;;N;;;;; +A971;HANGUL CHOSEONG MIEUM-SIOS;Lo;0;L;;;;;N;;;;; +A972;HANGUL CHOSEONG PIEUP-SIOS-THIEUTH;Lo;0;L;;;;;N;;;;; +A973;HANGUL CHOSEONG PIEUP-KHIEUKH;Lo;0;L;;;;;N;;;;; +A974;HANGUL CHOSEONG PIEUP-HIEUH;Lo;0;L;;;;;N;;;;; +A975;HANGUL CHOSEONG SSANGSIOS-PIEUP;Lo;0;L;;;;;N;;;;; +A976;HANGUL CHOSEONG IEUNG-RIEUL;Lo;0;L;;;;;N;;;;; +A977;HANGUL CHOSEONG IEUNG-HIEUH;Lo;0;L;;;;;N;;;;; +A978;HANGUL CHOSEONG SSANGCIEUC-HIEUH;Lo;0;L;;;;;N;;;;; +A979;HANGUL CHOSEONG SSANGTHIEUTH;Lo;0;L;;;;;N;;;;; +A97A;HANGUL CHOSEONG PHIEUPH-HIEUH;Lo;0;L;;;;;N;;;;; +A97B;HANGUL CHOSEONG HIEUH-SIOS;Lo;0;L;;;;;N;;;;; +A97C;HANGUL CHOSEONG SSANGYEORINHIEUH;Lo;0;L;;;;;N;;;;; +A980;JAVANESE SIGN PANYANGGA;Mn;0;NSM;;;;;N;;;;; +A981;JAVANESE SIGN CECAK;Mn;0;NSM;;;;;N;;;;; +A982;JAVANESE SIGN LAYAR;Mn;0;NSM;;;;;N;;;;; +A983;JAVANESE SIGN WIGNYAN;Mc;0;L;;;;;N;;;;; +A984;JAVANESE LETTER A;Lo;0;L;;;;;N;;;;; +A985;JAVANESE LETTER I KAWI;Lo;0;L;;;;;N;;;;; +A986;JAVANESE LETTER I;Lo;0;L;;;;;N;;;;; +A987;JAVANESE LETTER II;Lo;0;L;;;;;N;;;;; +A988;JAVANESE LETTER U;Lo;0;L;;;;;N;;;;; +A989;JAVANESE LETTER PA CEREK;Lo;0;L;;;;;N;;;;; +A98A;JAVANESE LETTER NGA LELET;Lo;0;L;;;;;N;;;;; +A98B;JAVANESE LETTER NGA LELET RASWADI;Lo;0;L;;;;;N;;;;; +A98C;JAVANESE LETTER E;Lo;0;L;;;;;N;;;;; +A98D;JAVANESE LETTER AI;Lo;0;L;;;;;N;;;;; +A98E;JAVANESE LETTER O;Lo;0;L;;;;;N;;;;; +A98F;JAVANESE LETTER KA;Lo;0;L;;;;;N;;;;; +A990;JAVANESE LETTER KA SASAK;Lo;0;L;;;;;N;;;;; +A991;JAVANESE LETTER KA MURDA;Lo;0;L;;;;;N;;;;; +A992;JAVANESE LETTER GA;Lo;0;L;;;;;N;;;;; +A993;JAVANESE LETTER GA MURDA;Lo;0;L;;;;;N;;;;; +A994;JAVANESE LETTER NGA;Lo;0;L;;;;;N;;;;; +A995;JAVANESE LETTER CA;Lo;0;L;;;;;N;;;;; +A996;JAVANESE LETTER CA MURDA;Lo;0;L;;;;;N;;;;; +A997;JAVANESE LETTER JA;Lo;0;L;;;;;N;;;;; +A998;JAVANESE LETTER NYA MURDA;Lo;0;L;;;;;N;;;;; +A999;JAVANESE LETTER JA MAHAPRANA;Lo;0;L;;;;;N;;;;; +A99A;JAVANESE LETTER NYA;Lo;0;L;;;;;N;;;;; +A99B;JAVANESE LETTER TTA;Lo;0;L;;;;;N;;;;; +A99C;JAVANESE LETTER TTA MAHAPRANA;Lo;0;L;;;;;N;;;;; +A99D;JAVANESE LETTER DDA;Lo;0;L;;;;;N;;;;; +A99E;JAVANESE LETTER DDA MAHAPRANA;Lo;0;L;;;;;N;;;;; +A99F;JAVANESE LETTER NA MURDA;Lo;0;L;;;;;N;;;;; +A9A0;JAVANESE LETTER TA;Lo;0;L;;;;;N;;;;; +A9A1;JAVANESE LETTER TA MURDA;Lo;0;L;;;;;N;;;;; +A9A2;JAVANESE LETTER DA;Lo;0;L;;;;;N;;;;; +A9A3;JAVANESE LETTER DA MAHAPRANA;Lo;0;L;;;;;N;;;;; +A9A4;JAVANESE LETTER NA;Lo;0;L;;;;;N;;;;; +A9A5;JAVANESE LETTER PA;Lo;0;L;;;;;N;;;;; +A9A6;JAVANESE LETTER PA MURDA;Lo;0;L;;;;;N;;;;; +A9A7;JAVANESE LETTER BA;Lo;0;L;;;;;N;;;;; +A9A8;JAVANESE LETTER BA MURDA;Lo;0;L;;;;;N;;;;; +A9A9;JAVANESE LETTER MA;Lo;0;L;;;;;N;;;;; +A9AA;JAVANESE LETTER YA;Lo;0;L;;;;;N;;;;; +A9AB;JAVANESE LETTER RA;Lo;0;L;;;;;N;;;;; +A9AC;JAVANESE LETTER RA AGUNG;Lo;0;L;;;;;N;;;;; +A9AD;JAVANESE LETTER LA;Lo;0;L;;;;;N;;;;; +A9AE;JAVANESE LETTER WA;Lo;0;L;;;;;N;;;;; +A9AF;JAVANESE LETTER SA MURDA;Lo;0;L;;;;;N;;;;; +A9B0;JAVANESE LETTER SA MAHAPRANA;Lo;0;L;;;;;N;;;;; +A9B1;JAVANESE LETTER SA;Lo;0;L;;;;;N;;;;; +A9B2;JAVANESE LETTER HA;Lo;0;L;;;;;N;;;;; +A9B3;JAVANESE SIGN CECAK TELU;Mn;7;NSM;;;;;N;;;;; +A9B4;JAVANESE VOWEL SIGN TARUNG;Mc;0;L;;;;;N;;;;; +A9B5;JAVANESE VOWEL SIGN TOLONG;Mc;0;L;;;;;N;;;;; +A9B6;JAVANESE VOWEL SIGN WULU;Mn;0;NSM;;;;;N;;;;; +A9B7;JAVANESE VOWEL SIGN WULU MELIK;Mn;0;NSM;;;;;N;;;;; +A9B8;JAVANESE VOWEL SIGN SUKU;Mn;0;NSM;;;;;N;;;;; +A9B9;JAVANESE VOWEL SIGN SUKU MENDUT;Mn;0;NSM;;;;;N;;;;; +A9BA;JAVANESE VOWEL SIGN TALING;Mc;0;L;;;;;N;;;;; +A9BB;JAVANESE VOWEL SIGN DIRGA MURE;Mc;0;L;;;;;N;;;;; +A9BC;JAVANESE VOWEL SIGN PEPET;Mn;0;NSM;;;;;N;;;;; +A9BD;JAVANESE CONSONANT SIGN KERET;Mn;0;NSM;;;;;N;;;;; +A9BE;JAVANESE CONSONANT SIGN PENGKAL;Mc;0;L;;;;;N;;;;; +A9BF;JAVANESE CONSONANT SIGN CAKRA;Mc;0;L;;;;;N;;;;; +A9C0;JAVANESE PANGKON;Mc;9;L;;;;;N;;;;; +A9C1;JAVANESE LEFT RERENGGAN;Po;0;L;;;;;N;;;;; +A9C2;JAVANESE RIGHT RERENGGAN;Po;0;L;;;;;N;;;;; +A9C3;JAVANESE PADA ANDAP;Po;0;L;;;;;N;;;;; +A9C4;JAVANESE PADA MADYA;Po;0;L;;;;;N;;;;; +A9C5;JAVANESE PADA LUHUR;Po;0;L;;;;;N;;;;; +A9C6;JAVANESE PADA WINDU;Po;0;L;;;;;N;;;;; +A9C7;JAVANESE PADA PANGKAT;Po;0;L;;;;;N;;;;; +A9C8;JAVANESE PADA LINGSA;Po;0;L;;;;;N;;;;; +A9C9;JAVANESE PADA LUNGSI;Po;0;L;;;;;N;;;;; +A9CA;JAVANESE PADA ADEG;Po;0;L;;;;;N;;;;; +A9CB;JAVANESE PADA ADEG ADEG;Po;0;L;;;;;N;;;;; +A9CC;JAVANESE PADA PISELEH;Po;0;L;;;;;N;;;;; +A9CD;JAVANESE TURNED PADA PISELEH;Po;0;L;;;;;N;;;;; +A9CF;JAVANESE PANGRANGKEP;Lm;0;L;;;;;N;;;;; +A9D0;JAVANESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +A9D1;JAVANESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +A9D2;JAVANESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +A9D3;JAVANESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +A9D4;JAVANESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +A9D5;JAVANESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +A9D6;JAVANESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +A9D7;JAVANESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +A9D8;JAVANESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +A9D9;JAVANESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +A9DE;JAVANESE PADA TIRTA TUMETES;Po;0;L;;;;;N;;;;; +A9DF;JAVANESE PADA ISEN-ISEN;Po;0;L;;;;;N;;;;; +A9E0;MYANMAR LETTER SHAN GHA;Lo;0;L;;;;;N;;;;; +A9E1;MYANMAR LETTER SHAN CHA;Lo;0;L;;;;;N;;;;; +A9E2;MYANMAR LETTER SHAN JHA;Lo;0;L;;;;;N;;;;; +A9E3;MYANMAR LETTER SHAN NNA;Lo;0;L;;;;;N;;;;; +A9E4;MYANMAR LETTER SHAN BHA;Lo;0;L;;;;;N;;;;; +A9E5;MYANMAR SIGN SHAN SAW;Mn;0;NSM;;;;;N;;;;; +A9E6;MYANMAR MODIFIER LETTER SHAN REDUPLICATION;Lm;0;L;;;;;N;;;;; +A9E7;MYANMAR LETTER TAI LAING NYA;Lo;0;L;;;;;N;;;;; +A9E8;MYANMAR LETTER TAI LAING FA;Lo;0;L;;;;;N;;;;; +A9E9;MYANMAR LETTER TAI LAING GA;Lo;0;L;;;;;N;;;;; +A9EA;MYANMAR LETTER TAI LAING GHA;Lo;0;L;;;;;N;;;;; +A9EB;MYANMAR LETTER TAI LAING JA;Lo;0;L;;;;;N;;;;; +A9EC;MYANMAR LETTER TAI LAING JHA;Lo;0;L;;;;;N;;;;; +A9ED;MYANMAR LETTER TAI LAING DDA;Lo;0;L;;;;;N;;;;; +A9EE;MYANMAR LETTER TAI LAING DDHA;Lo;0;L;;;;;N;;;;; +A9EF;MYANMAR LETTER TAI LAING NNA;Lo;0;L;;;;;N;;;;; +A9F0;MYANMAR TAI LAING DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +A9F1;MYANMAR TAI LAING DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +A9F2;MYANMAR TAI LAING DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +A9F3;MYANMAR TAI LAING DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +A9F4;MYANMAR TAI LAING DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +A9F5;MYANMAR TAI LAING DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +A9F6;MYANMAR TAI LAING DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +A9F7;MYANMAR TAI LAING DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +A9F8;MYANMAR TAI LAING DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +A9F9;MYANMAR TAI LAING DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +A9FA;MYANMAR LETTER TAI LAING LLA;Lo;0;L;;;;;N;;;;; +A9FB;MYANMAR LETTER TAI LAING DA;Lo;0;L;;;;;N;;;;; +A9FC;MYANMAR LETTER TAI LAING DHA;Lo;0;L;;;;;N;;;;; +A9FD;MYANMAR LETTER TAI LAING BA;Lo;0;L;;;;;N;;;;; +A9FE;MYANMAR LETTER TAI LAING BHA;Lo;0;L;;;;;N;;;;; +AA00;CHAM LETTER A;Lo;0;L;;;;;N;;;;; +AA01;CHAM LETTER I;Lo;0;L;;;;;N;;;;; +AA02;CHAM LETTER U;Lo;0;L;;;;;N;;;;; +AA03;CHAM LETTER E;Lo;0;L;;;;;N;;;;; +AA04;CHAM LETTER AI;Lo;0;L;;;;;N;;;;; +AA05;CHAM LETTER O;Lo;0;L;;;;;N;;;;; +AA06;CHAM LETTER KA;Lo;0;L;;;;;N;;;;; +AA07;CHAM LETTER KHA;Lo;0;L;;;;;N;;;;; +AA08;CHAM LETTER GA;Lo;0;L;;;;;N;;;;; +AA09;CHAM LETTER GHA;Lo;0;L;;;;;N;;;;; +AA0A;CHAM LETTER NGUE;Lo;0;L;;;;;N;;;;; +AA0B;CHAM LETTER NGA;Lo;0;L;;;;;N;;;;; +AA0C;CHAM LETTER CHA;Lo;0;L;;;;;N;;;;; +AA0D;CHAM LETTER CHHA;Lo;0;L;;;;;N;;;;; +AA0E;CHAM LETTER JA;Lo;0;L;;;;;N;;;;; +AA0F;CHAM LETTER JHA;Lo;0;L;;;;;N;;;;; +AA10;CHAM LETTER NHUE;Lo;0;L;;;;;N;;;;; +AA11;CHAM LETTER NHA;Lo;0;L;;;;;N;;;;; +AA12;CHAM LETTER NHJA;Lo;0;L;;;;;N;;;;; +AA13;CHAM LETTER TA;Lo;0;L;;;;;N;;;;; +AA14;CHAM LETTER THA;Lo;0;L;;;;;N;;;;; +AA15;CHAM LETTER DA;Lo;0;L;;;;;N;;;;; +AA16;CHAM LETTER DHA;Lo;0;L;;;;;N;;;;; +AA17;CHAM LETTER NUE;Lo;0;L;;;;;N;;;;; +AA18;CHAM LETTER NA;Lo;0;L;;;;;N;;;;; +AA19;CHAM LETTER DDA;Lo;0;L;;;;;N;;;;; +AA1A;CHAM LETTER PA;Lo;0;L;;;;;N;;;;; +AA1B;CHAM LETTER PPA;Lo;0;L;;;;;N;;;;; +AA1C;CHAM LETTER PHA;Lo;0;L;;;;;N;;;;; +AA1D;CHAM LETTER BA;Lo;0;L;;;;;N;;;;; +AA1E;CHAM LETTER BHA;Lo;0;L;;;;;N;;;;; +AA1F;CHAM LETTER MUE;Lo;0;L;;;;;N;;;;; +AA20;CHAM LETTER MA;Lo;0;L;;;;;N;;;;; +AA21;CHAM LETTER BBA;Lo;0;L;;;;;N;;;;; +AA22;CHAM LETTER YA;Lo;0;L;;;;;N;;;;; +AA23;CHAM LETTER RA;Lo;0;L;;;;;N;;;;; +AA24;CHAM LETTER LA;Lo;0;L;;;;;N;;;;; +AA25;CHAM LETTER VA;Lo;0;L;;;;;N;;;;; +AA26;CHAM LETTER SSA;Lo;0;L;;;;;N;;;;; +AA27;CHAM LETTER SA;Lo;0;L;;;;;N;;;;; +AA28;CHAM LETTER HA;Lo;0;L;;;;;N;;;;; +AA29;CHAM VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; +AA2A;CHAM VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +AA2B;CHAM VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +AA2C;CHAM VOWEL SIGN EI;Mn;0;NSM;;;;;N;;;;; +AA2D;CHAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +AA2E;CHAM VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;; +AA2F;CHAM VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +AA30;CHAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +AA31;CHAM VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +AA32;CHAM VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;; +AA33;CHAM CONSONANT SIGN YA;Mc;0;L;;;;;N;;;;; +AA34;CHAM CONSONANT SIGN RA;Mc;0;L;;;;;N;;;;; +AA35;CHAM CONSONANT SIGN LA;Mn;0;NSM;;;;;N;;;;; +AA36;CHAM CONSONANT SIGN WA;Mn;0;NSM;;;;;N;;;;; +AA40;CHAM LETTER FINAL K;Lo;0;L;;;;;N;;;;; +AA41;CHAM LETTER FINAL G;Lo;0;L;;;;;N;;;;; +AA42;CHAM LETTER FINAL NG;Lo;0;L;;;;;N;;;;; +AA43;CHAM CONSONANT SIGN FINAL NG;Mn;0;NSM;;;;;N;;;;; +AA44;CHAM LETTER FINAL CH;Lo;0;L;;;;;N;;;;; +AA45;CHAM LETTER FINAL T;Lo;0;L;;;;;N;;;;; +AA46;CHAM LETTER FINAL N;Lo;0;L;;;;;N;;;;; +AA47;CHAM LETTER FINAL P;Lo;0;L;;;;;N;;;;; +AA48;CHAM LETTER FINAL Y;Lo;0;L;;;;;N;;;;; +AA49;CHAM LETTER FINAL R;Lo;0;L;;;;;N;;;;; +AA4A;CHAM LETTER FINAL L;Lo;0;L;;;;;N;;;;; +AA4B;CHAM LETTER FINAL SS;Lo;0;L;;;;;N;;;;; +AA4C;CHAM CONSONANT SIGN FINAL M;Mn;0;NSM;;;;;N;;;;; +AA4D;CHAM CONSONANT SIGN FINAL H;Mc;0;L;;;;;N;;;;; +AA50;CHAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +AA51;CHAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +AA52;CHAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +AA53;CHAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +AA54;CHAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +AA55;CHAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +AA56;CHAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +AA57;CHAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +AA58;CHAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +AA59;CHAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +AA5C;CHAM PUNCTUATION SPIRAL;Po;0;L;;;;;N;;;;; +AA5D;CHAM PUNCTUATION DANDA;Po;0;L;;;;;N;;;;; +AA5E;CHAM PUNCTUATION DOUBLE DANDA;Po;0;L;;;;;N;;;;; +AA5F;CHAM PUNCTUATION TRIPLE DANDA;Po;0;L;;;;;N;;;;; +AA60;MYANMAR LETTER KHAMTI GA;Lo;0;L;;;;;N;;;;; +AA61;MYANMAR LETTER KHAMTI CA;Lo;0;L;;;;;N;;;;; +AA62;MYANMAR LETTER KHAMTI CHA;Lo;0;L;;;;;N;;;;; +AA63;MYANMAR LETTER KHAMTI JA;Lo;0;L;;;;;N;;;;; +AA64;MYANMAR LETTER KHAMTI JHA;Lo;0;L;;;;;N;;;;; +AA65;MYANMAR LETTER KHAMTI NYA;Lo;0;L;;;;;N;;;;; +AA66;MYANMAR LETTER KHAMTI TTA;Lo;0;L;;;;;N;;;;; +AA67;MYANMAR LETTER KHAMTI TTHA;Lo;0;L;;;;;N;;;;; +AA68;MYANMAR LETTER KHAMTI DDA;Lo;0;L;;;;;N;;;;; +AA69;MYANMAR LETTER KHAMTI DDHA;Lo;0;L;;;;;N;;;;; +AA6A;MYANMAR LETTER KHAMTI DHA;Lo;0;L;;;;;N;;;;; +AA6B;MYANMAR LETTER KHAMTI NA;Lo;0;L;;;;;N;;;;; +AA6C;MYANMAR LETTER KHAMTI SA;Lo;0;L;;;;;N;;;;; +AA6D;MYANMAR LETTER KHAMTI HA;Lo;0;L;;;;;N;;;;; +AA6E;MYANMAR LETTER KHAMTI HHA;Lo;0;L;;;;;N;;;;; +AA6F;MYANMAR LETTER KHAMTI FA;Lo;0;L;;;;;N;;;;; +AA70;MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION;Lm;0;L;;;;;N;;;;; +AA71;MYANMAR LETTER KHAMTI XA;Lo;0;L;;;;;N;;;;; +AA72;MYANMAR LETTER KHAMTI ZA;Lo;0;L;;;;;N;;;;; +AA73;MYANMAR LETTER KHAMTI RA;Lo;0;L;;;;;N;;;;; +AA74;MYANMAR LOGOGRAM KHAMTI OAY;Lo;0;L;;;;;N;;;;; +AA75;MYANMAR LOGOGRAM KHAMTI QN;Lo;0;L;;;;;N;;;;; +AA76;MYANMAR LOGOGRAM KHAMTI HM;Lo;0;L;;;;;N;;;;; +AA77;MYANMAR SYMBOL AITON EXCLAMATION;So;0;L;;;;;N;;;;; +AA78;MYANMAR SYMBOL AITON ONE;So;0;L;;;;;N;;;;; +AA79;MYANMAR SYMBOL AITON TWO;So;0;L;;;;;N;;;;; +AA7A;MYANMAR LETTER AITON RA;Lo;0;L;;;;;N;;;;; +AA7B;MYANMAR SIGN PAO KAREN TONE;Mc;0;L;;;;;N;;;;; +AA7C;MYANMAR SIGN TAI LAING TONE-2;Mn;0;NSM;;;;;N;;;;; +AA7D;MYANMAR SIGN TAI LAING TONE-5;Mc;0;L;;;;;N;;;;; +AA7E;MYANMAR LETTER SHWE PALAUNG CHA;Lo;0;L;;;;;N;;;;; +AA7F;MYANMAR LETTER SHWE PALAUNG SHA;Lo;0;L;;;;;N;;;;; +AA80;TAI VIET LETTER LOW KO;Lo;0;L;;;;;N;;;;; +AA81;TAI VIET LETTER HIGH KO;Lo;0;L;;;;;N;;;;; +AA82;TAI VIET LETTER LOW KHO;Lo;0;L;;;;;N;;;;; +AA83;TAI VIET LETTER HIGH KHO;Lo;0;L;;;;;N;;;;; +AA84;TAI VIET LETTER LOW KHHO;Lo;0;L;;;;;N;;;;; +AA85;TAI VIET LETTER HIGH KHHO;Lo;0;L;;;;;N;;;;; +AA86;TAI VIET LETTER LOW GO;Lo;0;L;;;;;N;;;;; +AA87;TAI VIET LETTER HIGH GO;Lo;0;L;;;;;N;;;;; +AA88;TAI VIET LETTER LOW NGO;Lo;0;L;;;;;N;;;;; +AA89;TAI VIET LETTER HIGH NGO;Lo;0;L;;;;;N;;;;; +AA8A;TAI VIET LETTER LOW CO;Lo;0;L;;;;;N;;;;; +AA8B;TAI VIET LETTER HIGH CO;Lo;0;L;;;;;N;;;;; +AA8C;TAI VIET LETTER LOW CHO;Lo;0;L;;;;;N;;;;; +AA8D;TAI VIET LETTER HIGH CHO;Lo;0;L;;;;;N;;;;; +AA8E;TAI VIET LETTER LOW SO;Lo;0;L;;;;;N;;;;; +AA8F;TAI VIET LETTER HIGH SO;Lo;0;L;;;;;N;;;;; +AA90;TAI VIET LETTER LOW NYO;Lo;0;L;;;;;N;;;;; +AA91;TAI VIET LETTER HIGH NYO;Lo;0;L;;;;;N;;;;; +AA92;TAI VIET LETTER LOW DO;Lo;0;L;;;;;N;;;;; +AA93;TAI VIET LETTER HIGH DO;Lo;0;L;;;;;N;;;;; +AA94;TAI VIET LETTER LOW TO;Lo;0;L;;;;;N;;;;; +AA95;TAI VIET LETTER HIGH TO;Lo;0;L;;;;;N;;;;; +AA96;TAI VIET LETTER LOW THO;Lo;0;L;;;;;N;;;;; +AA97;TAI VIET LETTER HIGH THO;Lo;0;L;;;;;N;;;;; +AA98;TAI VIET LETTER LOW NO;Lo;0;L;;;;;N;;;;; +AA99;TAI VIET LETTER HIGH NO;Lo;0;L;;;;;N;;;;; +AA9A;TAI VIET LETTER LOW BO;Lo;0;L;;;;;N;;;;; +AA9B;TAI VIET LETTER HIGH BO;Lo;0;L;;;;;N;;;;; +AA9C;TAI VIET LETTER LOW PO;Lo;0;L;;;;;N;;;;; +AA9D;TAI VIET LETTER HIGH PO;Lo;0;L;;;;;N;;;;; +AA9E;TAI VIET LETTER LOW PHO;Lo;0;L;;;;;N;;;;; +AA9F;TAI VIET LETTER HIGH PHO;Lo;0;L;;;;;N;;;;; +AAA0;TAI VIET LETTER LOW FO;Lo;0;L;;;;;N;;;;; +AAA1;TAI VIET LETTER HIGH FO;Lo;0;L;;;;;N;;;;; +AAA2;TAI VIET LETTER LOW MO;Lo;0;L;;;;;N;;;;; +AAA3;TAI VIET LETTER HIGH MO;Lo;0;L;;;;;N;;;;; +AAA4;TAI VIET LETTER LOW YO;Lo;0;L;;;;;N;;;;; +AAA5;TAI VIET LETTER HIGH YO;Lo;0;L;;;;;N;;;;; +AAA6;TAI VIET LETTER LOW RO;Lo;0;L;;;;;N;;;;; +AAA7;TAI VIET LETTER HIGH RO;Lo;0;L;;;;;N;;;;; +AAA8;TAI VIET LETTER LOW LO;Lo;0;L;;;;;N;;;;; +AAA9;TAI VIET LETTER HIGH LO;Lo;0;L;;;;;N;;;;; +AAAA;TAI VIET LETTER LOW VO;Lo;0;L;;;;;N;;;;; +AAAB;TAI VIET LETTER HIGH VO;Lo;0;L;;;;;N;;;;; +AAAC;TAI VIET LETTER LOW HO;Lo;0;L;;;;;N;;;;; +AAAD;TAI VIET LETTER HIGH HO;Lo;0;L;;;;;N;;;;; +AAAE;TAI VIET LETTER LOW O;Lo;0;L;;;;;N;;;;; +AAAF;TAI VIET LETTER HIGH O;Lo;0;L;;;;;N;;;;; +AAB0;TAI VIET MAI KANG;Mn;230;NSM;;;;;N;;;;; +AAB1;TAI VIET VOWEL AA;Lo;0;L;;;;;N;;;;; +AAB2;TAI VIET VOWEL I;Mn;230;NSM;;;;;N;;;;; +AAB3;TAI VIET VOWEL UE;Mn;230;NSM;;;;;N;;;;; +AAB4;TAI VIET VOWEL U;Mn;220;NSM;;;;;N;;;;; +AAB5;TAI VIET VOWEL E;Lo;0;L;;;;;N;;;;; +AAB6;TAI VIET VOWEL O;Lo;0;L;;;;;N;;;;; +AAB7;TAI VIET MAI KHIT;Mn;230;NSM;;;;;N;;;;; +AAB8;TAI VIET VOWEL IA;Mn;230;NSM;;;;;N;;;;; +AAB9;TAI VIET VOWEL UEA;Lo;0;L;;;;;N;;;;; +AABA;TAI VIET VOWEL UA;Lo;0;L;;;;;N;;;;; +AABB;TAI VIET VOWEL AUE;Lo;0;L;;;;;N;;;;; +AABC;TAI VIET VOWEL AY;Lo;0;L;;;;;N;;;;; +AABD;TAI VIET VOWEL AN;Lo;0;L;;;;;N;;;;; +AABE;TAI VIET VOWEL AM;Mn;230;NSM;;;;;N;;;;; +AABF;TAI VIET TONE MAI EK;Mn;230;NSM;;;;;N;;;;; +AAC0;TAI VIET TONE MAI NUENG;Lo;0;L;;;;;N;;;;; +AAC1;TAI VIET TONE MAI THO;Mn;230;NSM;;;;;N;;;;; +AAC2;TAI VIET TONE MAI SONG;Lo;0;L;;;;;N;;;;; +AADB;TAI VIET SYMBOL KON;Lo;0;L;;;;;N;;;;; +AADC;TAI VIET SYMBOL NUENG;Lo;0;L;;;;;N;;;;; +AADD;TAI VIET SYMBOL SAM;Lm;0;L;;;;;N;;;;; +AADE;TAI VIET SYMBOL HO HOI;Po;0;L;;;;;N;;;;; +AADF;TAI VIET SYMBOL KOI KOI;Po;0;L;;;;;N;;;;; +AAE0;MEETEI MAYEK LETTER E;Lo;0;L;;;;;N;;;;; +AAE1;MEETEI MAYEK LETTER O;Lo;0;L;;;;;N;;;;; +AAE2;MEETEI MAYEK LETTER CHA;Lo;0;L;;;;;N;;;;; +AAE3;MEETEI MAYEK LETTER NYA;Lo;0;L;;;;;N;;;;; +AAE4;MEETEI MAYEK LETTER TTA;Lo;0;L;;;;;N;;;;; +AAE5;MEETEI MAYEK LETTER TTHA;Lo;0;L;;;;;N;;;;; +AAE6;MEETEI MAYEK LETTER DDA;Lo;0;L;;;;;N;;;;; +AAE7;MEETEI MAYEK LETTER DDHA;Lo;0;L;;;;;N;;;;; +AAE8;MEETEI MAYEK LETTER NNA;Lo;0;L;;;;;N;;;;; +AAE9;MEETEI MAYEK LETTER SHA;Lo;0;L;;;;;N;;;;; +AAEA;MEETEI MAYEK LETTER SSA;Lo;0;L;;;;;N;;;;; +AAEB;MEETEI MAYEK VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +AAEC;MEETEI MAYEK VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +AAED;MEETEI MAYEK VOWEL SIGN AAI;Mn;0;NSM;;;;;N;;;;; +AAEE;MEETEI MAYEK VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +AAEF;MEETEI MAYEK VOWEL SIGN AAU;Mc;0;L;;;;;N;;;;; +AAF0;MEETEI MAYEK CHEIKHAN;Po;0;L;;;;;N;;;;; +AAF1;MEETEI MAYEK AHANG KHUDAM;Po;0;L;;;;;N;;;;; +AAF2;MEETEI MAYEK ANJI;Lo;0;L;;;;;N;;;;; +AAF3;MEETEI MAYEK SYLLABLE REPETITION MARK;Lm;0;L;;;;;N;;;;; +AAF4;MEETEI MAYEK WORD REPETITION MARK;Lm;0;L;;;;;N;;;;; +AAF5;MEETEI MAYEK VOWEL SIGN VISARGA;Mc;0;L;;;;;N;;;;; +AAF6;MEETEI MAYEK VIRAMA;Mn;9;NSM;;;;;N;;;;; +AB01;ETHIOPIC SYLLABLE TTHU;Lo;0;L;;;;;N;;;;; +AB02;ETHIOPIC SYLLABLE TTHI;Lo;0;L;;;;;N;;;;; +AB03;ETHIOPIC SYLLABLE TTHAA;Lo;0;L;;;;;N;;;;; +AB04;ETHIOPIC SYLLABLE TTHEE;Lo;0;L;;;;;N;;;;; +AB05;ETHIOPIC SYLLABLE TTHE;Lo;0;L;;;;;N;;;;; +AB06;ETHIOPIC SYLLABLE TTHO;Lo;0;L;;;;;N;;;;; +AB09;ETHIOPIC SYLLABLE DDHU;Lo;0;L;;;;;N;;;;; +AB0A;ETHIOPIC SYLLABLE DDHI;Lo;0;L;;;;;N;;;;; +AB0B;ETHIOPIC SYLLABLE DDHAA;Lo;0;L;;;;;N;;;;; +AB0C;ETHIOPIC SYLLABLE DDHEE;Lo;0;L;;;;;N;;;;; +AB0D;ETHIOPIC SYLLABLE DDHE;Lo;0;L;;;;;N;;;;; +AB0E;ETHIOPIC SYLLABLE DDHO;Lo;0;L;;;;;N;;;;; +AB11;ETHIOPIC SYLLABLE DZU;Lo;0;L;;;;;N;;;;; +AB12;ETHIOPIC SYLLABLE DZI;Lo;0;L;;;;;N;;;;; +AB13;ETHIOPIC SYLLABLE DZAA;Lo;0;L;;;;;N;;;;; +AB14;ETHIOPIC SYLLABLE DZEE;Lo;0;L;;;;;N;;;;; +AB15;ETHIOPIC SYLLABLE DZE;Lo;0;L;;;;;N;;;;; +AB16;ETHIOPIC SYLLABLE DZO;Lo;0;L;;;;;N;;;;; +AB20;ETHIOPIC SYLLABLE CCHHA;Lo;0;L;;;;;N;;;;; +AB21;ETHIOPIC SYLLABLE CCHHU;Lo;0;L;;;;;N;;;;; +AB22;ETHIOPIC SYLLABLE CCHHI;Lo;0;L;;;;;N;;;;; +AB23;ETHIOPIC SYLLABLE CCHHAA;Lo;0;L;;;;;N;;;;; +AB24;ETHIOPIC SYLLABLE CCHHEE;Lo;0;L;;;;;N;;;;; +AB25;ETHIOPIC SYLLABLE CCHHE;Lo;0;L;;;;;N;;;;; +AB26;ETHIOPIC SYLLABLE CCHHO;Lo;0;L;;;;;N;;;;; +AB28;ETHIOPIC SYLLABLE BBA;Lo;0;L;;;;;N;;;;; +AB29;ETHIOPIC SYLLABLE BBU;Lo;0;L;;;;;N;;;;; +AB2A;ETHIOPIC SYLLABLE BBI;Lo;0;L;;;;;N;;;;; +AB2B;ETHIOPIC SYLLABLE BBAA;Lo;0;L;;;;;N;;;;; +AB2C;ETHIOPIC SYLLABLE BBEE;Lo;0;L;;;;;N;;;;; +AB2D;ETHIOPIC SYLLABLE BBE;Lo;0;L;;;;;N;;;;; +AB2E;ETHIOPIC SYLLABLE BBO;Lo;0;L;;;;;N;;;;; +AB30;LATIN SMALL LETTER BARRED ALPHA;Ll;0;L;;;;;N;;;;; +AB31;LATIN SMALL LETTER A REVERSED-SCHWA;Ll;0;L;;;;;N;;;;; +AB32;LATIN SMALL LETTER BLACKLETTER E;Ll;0;L;;;;;N;;;;; +AB33;LATIN SMALL LETTER BARRED E;Ll;0;L;;;;;N;;;;; +AB34;LATIN SMALL LETTER E WITH FLOURISH;Ll;0;L;;;;;N;;;;; +AB35;LATIN SMALL LETTER LENIS F;Ll;0;L;;;;;N;;;;; +AB36;LATIN SMALL LETTER SCRIPT G WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; +AB37;LATIN SMALL LETTER L WITH INVERTED LAZY S;Ll;0;L;;;;;N;;;;; +AB38;LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +AB39;LATIN SMALL LETTER L WITH MIDDLE RING;Ll;0;L;;;;;N;;;;; +AB3A;LATIN SMALL LETTER M WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; +AB3B;LATIN SMALL LETTER N WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; +AB3C;LATIN SMALL LETTER ENG WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; +AB3D;LATIN SMALL LETTER BLACKLETTER O;Ll;0;L;;;;;N;;;;; +AB3E;LATIN SMALL LETTER BLACKLETTER O WITH STROKE;Ll;0;L;;;;;N;;;;; +AB3F;LATIN SMALL LETTER OPEN O WITH STROKE;Ll;0;L;;;;;N;;;;; +AB40;LATIN SMALL LETTER INVERTED OE;Ll;0;L;;;;;N;;;;; +AB41;LATIN SMALL LETTER TURNED OE WITH STROKE;Ll;0;L;;;;;N;;;;; +AB42;LATIN SMALL LETTER TURNED OE WITH HORIZONTAL STROKE;Ll;0;L;;;;;N;;;;; +AB43;LATIN SMALL LETTER TURNED O OPEN-O;Ll;0;L;;;;;N;;;;; +AB44;LATIN SMALL LETTER TURNED O OPEN-O WITH STROKE;Ll;0;L;;;;;N;;;;; +AB45;LATIN SMALL LETTER STIRRUP R;Ll;0;L;;;;;N;;;;; +AB46;LATIN LETTER SMALL CAPITAL R WITH RIGHT LEG;Ll;0;L;;;;;N;;;;; +AB47;LATIN SMALL LETTER R WITHOUT HANDLE;Ll;0;L;;;;;N;;;;; +AB48;LATIN SMALL LETTER DOUBLE R;Ll;0;L;;;;;N;;;;; +AB49;LATIN SMALL LETTER R WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; +AB4A;LATIN SMALL LETTER DOUBLE R WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; +AB4B;LATIN SMALL LETTER SCRIPT R;Ll;0;L;;;;;N;;;;; +AB4C;LATIN SMALL LETTER SCRIPT R WITH RING;Ll;0;L;;;;;N;;;;; +AB4D;LATIN SMALL LETTER BASELINE ESH;Ll;0;L;;;;;N;;;;; +AB4E;LATIN SMALL LETTER U WITH SHORT RIGHT LEG;Ll;0;L;;;;;N;;;;; +AB4F;LATIN SMALL LETTER U BAR WITH SHORT RIGHT LEG;Ll;0;L;;;;;N;;;;; +AB50;LATIN SMALL LETTER UI;Ll;0;L;;;;;N;;;;; +AB51;LATIN SMALL LETTER TURNED UI;Ll;0;L;;;;;N;;;;; +AB52;LATIN SMALL LETTER U WITH LEFT HOOK;Ll;0;L;;;;;N;;;;; +AB53;LATIN SMALL LETTER CHI;Ll;0;L;;;;;N;;;A7B3;;A7B3 +AB54;LATIN SMALL LETTER CHI WITH LOW RIGHT RING;Ll;0;L;;;;;N;;;;; +AB55;LATIN SMALL LETTER CHI WITH LOW LEFT SERIF;Ll;0;L;;;;;N;;;;; +AB56;LATIN SMALL LETTER X WITH LOW RIGHT RING;Ll;0;L;;;;;N;;;;; +AB57;LATIN SMALL LETTER X WITH LONG LEFT LEG;Ll;0;L;;;;;N;;;;; +AB58;LATIN SMALL LETTER X WITH LONG LEFT LEG AND LOW RIGHT RING;Ll;0;L;;;;;N;;;;; +AB59;LATIN SMALL LETTER X WITH LONG LEFT LEG WITH SERIF;Ll;0;L;;;;;N;;;;; +AB5A;LATIN SMALL LETTER Y WITH SHORT RIGHT LEG;Ll;0;L;;;;;N;;;;; +AB5B;MODIFIER BREVE WITH INVERTED BREVE;Sk;0;L;;;;;N;;;;; +AB5C;MODIFIER LETTER SMALL HENG;Lm;0;L; A727;;;;N;;;;; +AB5D;MODIFIER LETTER SMALL L WITH INVERTED LAZY S;Lm;0;L; AB37;;;;N;;;;; +AB5E;MODIFIER LETTER SMALL L WITH MIDDLE TILDE;Lm;0;L; 026B;;;;N;;;;; +AB5F;MODIFIER LETTER SMALL U WITH LEFT HOOK;Lm;0;L; AB52;;;;N;;;;; +AB60;LATIN SMALL LETTER SAKHA YAT;Ll;0;L;;;;;N;;;;; +AB61;LATIN SMALL LETTER IOTIFIED E;Ll;0;L;;;;;N;;;;; +AB62;LATIN SMALL LETTER OPEN OE;Ll;0;L;;;;;N;;;;; +AB63;LATIN SMALL LETTER UO;Ll;0;L;;;;;N;;;;; +AB64;LATIN SMALL LETTER INVERTED ALPHA;Ll;0;L;;;;;N;;;;; +AB65;GREEK LETTER SMALL CAPITAL OMEGA;Ll;0;L;;;;;N;;;;; +AB66;LATIN SMALL LETTER DZ DIGRAPH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +AB67;LATIN SMALL LETTER TS DIGRAPH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +AB68;LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +AB69;MODIFIER LETTER SMALL TURNED W;Lm;0;L; 028D;;;;N;;;;; +AB6A;MODIFIER LETTER LEFT TACK;Sk;0;ON;;;;;N;;;;; +AB6B;MODIFIER LETTER RIGHT TACK;Sk;0;ON;;;;;N;;;;; +AB70;CHEROKEE SMALL LETTER A;Ll;0;L;;;;;N;;;13A0;;13A0 +AB71;CHEROKEE SMALL LETTER E;Ll;0;L;;;;;N;;;13A1;;13A1 +AB72;CHEROKEE SMALL LETTER I;Ll;0;L;;;;;N;;;13A2;;13A2 +AB73;CHEROKEE SMALL LETTER O;Ll;0;L;;;;;N;;;13A3;;13A3 +AB74;CHEROKEE SMALL LETTER U;Ll;0;L;;;;;N;;;13A4;;13A4 +AB75;CHEROKEE SMALL LETTER V;Ll;0;L;;;;;N;;;13A5;;13A5 +AB76;CHEROKEE SMALL LETTER GA;Ll;0;L;;;;;N;;;13A6;;13A6 +AB77;CHEROKEE SMALL LETTER KA;Ll;0;L;;;;;N;;;13A7;;13A7 +AB78;CHEROKEE SMALL LETTER GE;Ll;0;L;;;;;N;;;13A8;;13A8 +AB79;CHEROKEE SMALL LETTER GI;Ll;0;L;;;;;N;;;13A9;;13A9 +AB7A;CHEROKEE SMALL LETTER GO;Ll;0;L;;;;;N;;;13AA;;13AA +AB7B;CHEROKEE SMALL LETTER GU;Ll;0;L;;;;;N;;;13AB;;13AB +AB7C;CHEROKEE SMALL LETTER GV;Ll;0;L;;;;;N;;;13AC;;13AC +AB7D;CHEROKEE SMALL LETTER HA;Ll;0;L;;;;;N;;;13AD;;13AD +AB7E;CHEROKEE SMALL LETTER HE;Ll;0;L;;;;;N;;;13AE;;13AE +AB7F;CHEROKEE SMALL LETTER HI;Ll;0;L;;;;;N;;;13AF;;13AF +AB80;CHEROKEE SMALL LETTER HO;Ll;0;L;;;;;N;;;13B0;;13B0 +AB81;CHEROKEE SMALL LETTER HU;Ll;0;L;;;;;N;;;13B1;;13B1 +AB82;CHEROKEE SMALL LETTER HV;Ll;0;L;;;;;N;;;13B2;;13B2 +AB83;CHEROKEE SMALL LETTER LA;Ll;0;L;;;;;N;;;13B3;;13B3 +AB84;CHEROKEE SMALL LETTER LE;Ll;0;L;;;;;N;;;13B4;;13B4 +AB85;CHEROKEE SMALL LETTER LI;Ll;0;L;;;;;N;;;13B5;;13B5 +AB86;CHEROKEE SMALL LETTER LO;Ll;0;L;;;;;N;;;13B6;;13B6 +AB87;CHEROKEE SMALL LETTER LU;Ll;0;L;;;;;N;;;13B7;;13B7 +AB88;CHEROKEE SMALL LETTER LV;Ll;0;L;;;;;N;;;13B8;;13B8 +AB89;CHEROKEE SMALL LETTER MA;Ll;0;L;;;;;N;;;13B9;;13B9 +AB8A;CHEROKEE SMALL LETTER ME;Ll;0;L;;;;;N;;;13BA;;13BA +AB8B;CHEROKEE SMALL LETTER MI;Ll;0;L;;;;;N;;;13BB;;13BB +AB8C;CHEROKEE SMALL LETTER MO;Ll;0;L;;;;;N;;;13BC;;13BC +AB8D;CHEROKEE SMALL LETTER MU;Ll;0;L;;;;;N;;;13BD;;13BD +AB8E;CHEROKEE SMALL LETTER NA;Ll;0;L;;;;;N;;;13BE;;13BE +AB8F;CHEROKEE SMALL LETTER HNA;Ll;0;L;;;;;N;;;13BF;;13BF +AB90;CHEROKEE SMALL LETTER NAH;Ll;0;L;;;;;N;;;13C0;;13C0 +AB91;CHEROKEE SMALL LETTER NE;Ll;0;L;;;;;N;;;13C1;;13C1 +AB92;CHEROKEE SMALL LETTER NI;Ll;0;L;;;;;N;;;13C2;;13C2 +AB93;CHEROKEE SMALL LETTER NO;Ll;0;L;;;;;N;;;13C3;;13C3 +AB94;CHEROKEE SMALL LETTER NU;Ll;0;L;;;;;N;;;13C4;;13C4 +AB95;CHEROKEE SMALL LETTER NV;Ll;0;L;;;;;N;;;13C5;;13C5 +AB96;CHEROKEE SMALL LETTER QUA;Ll;0;L;;;;;N;;;13C6;;13C6 +AB97;CHEROKEE SMALL LETTER QUE;Ll;0;L;;;;;N;;;13C7;;13C7 +AB98;CHEROKEE SMALL LETTER QUI;Ll;0;L;;;;;N;;;13C8;;13C8 +AB99;CHEROKEE SMALL LETTER QUO;Ll;0;L;;;;;N;;;13C9;;13C9 +AB9A;CHEROKEE SMALL LETTER QUU;Ll;0;L;;;;;N;;;13CA;;13CA +AB9B;CHEROKEE SMALL LETTER QUV;Ll;0;L;;;;;N;;;13CB;;13CB +AB9C;CHEROKEE SMALL LETTER SA;Ll;0;L;;;;;N;;;13CC;;13CC +AB9D;CHEROKEE SMALL LETTER S;Ll;0;L;;;;;N;;;13CD;;13CD +AB9E;CHEROKEE SMALL LETTER SE;Ll;0;L;;;;;N;;;13CE;;13CE +AB9F;CHEROKEE SMALL LETTER SI;Ll;0;L;;;;;N;;;13CF;;13CF +ABA0;CHEROKEE SMALL LETTER SO;Ll;0;L;;;;;N;;;13D0;;13D0 +ABA1;CHEROKEE SMALL LETTER SU;Ll;0;L;;;;;N;;;13D1;;13D1 +ABA2;CHEROKEE SMALL LETTER SV;Ll;0;L;;;;;N;;;13D2;;13D2 +ABA3;CHEROKEE SMALL LETTER DA;Ll;0;L;;;;;N;;;13D3;;13D3 +ABA4;CHEROKEE SMALL LETTER TA;Ll;0;L;;;;;N;;;13D4;;13D4 +ABA5;CHEROKEE SMALL LETTER DE;Ll;0;L;;;;;N;;;13D5;;13D5 +ABA6;CHEROKEE SMALL LETTER TE;Ll;0;L;;;;;N;;;13D6;;13D6 +ABA7;CHEROKEE SMALL LETTER DI;Ll;0;L;;;;;N;;;13D7;;13D7 +ABA8;CHEROKEE SMALL LETTER TI;Ll;0;L;;;;;N;;;13D8;;13D8 +ABA9;CHEROKEE SMALL LETTER DO;Ll;0;L;;;;;N;;;13D9;;13D9 +ABAA;CHEROKEE SMALL LETTER DU;Ll;0;L;;;;;N;;;13DA;;13DA +ABAB;CHEROKEE SMALL LETTER DV;Ll;0;L;;;;;N;;;13DB;;13DB +ABAC;CHEROKEE SMALL LETTER DLA;Ll;0;L;;;;;N;;;13DC;;13DC +ABAD;CHEROKEE SMALL LETTER TLA;Ll;0;L;;;;;N;;;13DD;;13DD +ABAE;CHEROKEE SMALL LETTER TLE;Ll;0;L;;;;;N;;;13DE;;13DE +ABAF;CHEROKEE SMALL LETTER TLI;Ll;0;L;;;;;N;;;13DF;;13DF +ABB0;CHEROKEE SMALL LETTER TLO;Ll;0;L;;;;;N;;;13E0;;13E0 +ABB1;CHEROKEE SMALL LETTER TLU;Ll;0;L;;;;;N;;;13E1;;13E1 +ABB2;CHEROKEE SMALL LETTER TLV;Ll;0;L;;;;;N;;;13E2;;13E2 +ABB3;CHEROKEE SMALL LETTER TSA;Ll;0;L;;;;;N;;;13E3;;13E3 +ABB4;CHEROKEE SMALL LETTER TSE;Ll;0;L;;;;;N;;;13E4;;13E4 +ABB5;CHEROKEE SMALL LETTER TSI;Ll;0;L;;;;;N;;;13E5;;13E5 +ABB6;CHEROKEE SMALL LETTER TSO;Ll;0;L;;;;;N;;;13E6;;13E6 +ABB7;CHEROKEE SMALL LETTER TSU;Ll;0;L;;;;;N;;;13E7;;13E7 +ABB8;CHEROKEE SMALL LETTER TSV;Ll;0;L;;;;;N;;;13E8;;13E8 +ABB9;CHEROKEE SMALL LETTER WA;Ll;0;L;;;;;N;;;13E9;;13E9 +ABBA;CHEROKEE SMALL LETTER WE;Ll;0;L;;;;;N;;;13EA;;13EA +ABBB;CHEROKEE SMALL LETTER WI;Ll;0;L;;;;;N;;;13EB;;13EB +ABBC;CHEROKEE SMALL LETTER WO;Ll;0;L;;;;;N;;;13EC;;13EC +ABBD;CHEROKEE SMALL LETTER WU;Ll;0;L;;;;;N;;;13ED;;13ED +ABBE;CHEROKEE SMALL LETTER WV;Ll;0;L;;;;;N;;;13EE;;13EE +ABBF;CHEROKEE SMALL LETTER YA;Ll;0;L;;;;;N;;;13EF;;13EF +ABC0;MEETEI MAYEK LETTER KOK;Lo;0;L;;;;;N;;;;; +ABC1;MEETEI MAYEK LETTER SAM;Lo;0;L;;;;;N;;;;; +ABC2;MEETEI MAYEK LETTER LAI;Lo;0;L;;;;;N;;;;; +ABC3;MEETEI MAYEK LETTER MIT;Lo;0;L;;;;;N;;;;; +ABC4;MEETEI MAYEK LETTER PA;Lo;0;L;;;;;N;;;;; +ABC5;MEETEI MAYEK LETTER NA;Lo;0;L;;;;;N;;;;; +ABC6;MEETEI MAYEK LETTER CHIL;Lo;0;L;;;;;N;;;;; +ABC7;MEETEI MAYEK LETTER TIL;Lo;0;L;;;;;N;;;;; +ABC8;MEETEI MAYEK LETTER KHOU;Lo;0;L;;;;;N;;;;; +ABC9;MEETEI MAYEK LETTER NGOU;Lo;0;L;;;;;N;;;;; +ABCA;MEETEI MAYEK LETTER THOU;Lo;0;L;;;;;N;;;;; +ABCB;MEETEI MAYEK LETTER WAI;Lo;0;L;;;;;N;;;;; +ABCC;MEETEI MAYEK LETTER YANG;Lo;0;L;;;;;N;;;;; +ABCD;MEETEI MAYEK LETTER HUK;Lo;0;L;;;;;N;;;;; +ABCE;MEETEI MAYEK LETTER UN;Lo;0;L;;;;;N;;;;; +ABCF;MEETEI MAYEK LETTER I;Lo;0;L;;;;;N;;;;; +ABD0;MEETEI MAYEK LETTER PHAM;Lo;0;L;;;;;N;;;;; +ABD1;MEETEI MAYEK LETTER ATIYA;Lo;0;L;;;;;N;;;;; +ABD2;MEETEI MAYEK LETTER GOK;Lo;0;L;;;;;N;;;;; +ABD3;MEETEI MAYEK LETTER JHAM;Lo;0;L;;;;;N;;;;; +ABD4;MEETEI MAYEK LETTER RAI;Lo;0;L;;;;;N;;;;; +ABD5;MEETEI MAYEK LETTER BA;Lo;0;L;;;;;N;;;;; +ABD6;MEETEI MAYEK LETTER JIL;Lo;0;L;;;;;N;;;;; +ABD7;MEETEI MAYEK LETTER DIL;Lo;0;L;;;;;N;;;;; +ABD8;MEETEI MAYEK LETTER GHOU;Lo;0;L;;;;;N;;;;; +ABD9;MEETEI MAYEK LETTER DHOU;Lo;0;L;;;;;N;;;;; +ABDA;MEETEI MAYEK LETTER BHAM;Lo;0;L;;;;;N;;;;; +ABDB;MEETEI MAYEK LETTER KOK LONSUM;Lo;0;L;;;;;N;;;;; +ABDC;MEETEI MAYEK LETTER LAI LONSUM;Lo;0;L;;;;;N;;;;; +ABDD;MEETEI MAYEK LETTER MIT LONSUM;Lo;0;L;;;;;N;;;;; +ABDE;MEETEI MAYEK LETTER PA LONSUM;Lo;0;L;;;;;N;;;;; +ABDF;MEETEI MAYEK LETTER NA LONSUM;Lo;0;L;;;;;N;;;;; +ABE0;MEETEI MAYEK LETTER TIL LONSUM;Lo;0;L;;;;;N;;;;; +ABE1;MEETEI MAYEK LETTER NGOU LONSUM;Lo;0;L;;;;;N;;;;; +ABE2;MEETEI MAYEK LETTER I LONSUM;Lo;0;L;;;;;N;;;;; +ABE3;MEETEI MAYEK VOWEL SIGN ONAP;Mc;0;L;;;;;N;;;;; +ABE4;MEETEI MAYEK VOWEL SIGN INAP;Mc;0;L;;;;;N;;;;; +ABE5;MEETEI MAYEK VOWEL SIGN ANAP;Mn;0;NSM;;;;;N;;;;; +ABE6;MEETEI MAYEK VOWEL SIGN YENAP;Mc;0;L;;;;;N;;;;; +ABE7;MEETEI MAYEK VOWEL SIGN SOUNAP;Mc;0;L;;;;;N;;;;; +ABE8;MEETEI MAYEK VOWEL SIGN UNAP;Mn;0;NSM;;;;;N;;;;; +ABE9;MEETEI MAYEK VOWEL SIGN CHEINAP;Mc;0;L;;;;;N;;;;; +ABEA;MEETEI MAYEK VOWEL SIGN NUNG;Mc;0;L;;;;;N;;;;; +ABEB;MEETEI MAYEK CHEIKHEI;Po;0;L;;;;;N;;;;; +ABEC;MEETEI MAYEK LUM IYEK;Mc;0;L;;;;;N;;;;; +ABED;MEETEI MAYEK APUN IYEK;Mn;9;NSM;;;;;N;;;;; +ABF0;MEETEI MAYEK DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +ABF1;MEETEI MAYEK DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +ABF2;MEETEI MAYEK DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +ABF3;MEETEI MAYEK DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +ABF4;MEETEI MAYEK DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +ABF5;MEETEI MAYEK DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +ABF6;MEETEI MAYEK DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +ABF7;MEETEI MAYEK DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +ABF8;MEETEI MAYEK DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +ABF9;MEETEI MAYEK DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +AC00;;Lo;0;L;;;;;N;;;;; +D7A3;;Lo;0;L;;;;;N;;;;; +D7B0;HANGUL JUNGSEONG O-YEO;Lo;0;L;;;;;N;;;;; +D7B1;HANGUL JUNGSEONG O-O-I;Lo;0;L;;;;;N;;;;; +D7B2;HANGUL JUNGSEONG YO-A;Lo;0;L;;;;;N;;;;; +D7B3;HANGUL JUNGSEONG YO-AE;Lo;0;L;;;;;N;;;;; +D7B4;HANGUL JUNGSEONG YO-EO;Lo;0;L;;;;;N;;;;; +D7B5;HANGUL JUNGSEONG U-YEO;Lo;0;L;;;;;N;;;;; +D7B6;HANGUL JUNGSEONG U-I-I;Lo;0;L;;;;;N;;;;; +D7B7;HANGUL JUNGSEONG YU-AE;Lo;0;L;;;;;N;;;;; +D7B8;HANGUL JUNGSEONG YU-O;Lo;0;L;;;;;N;;;;; +D7B9;HANGUL JUNGSEONG EU-A;Lo;0;L;;;;;N;;;;; +D7BA;HANGUL JUNGSEONG EU-EO;Lo;0;L;;;;;N;;;;; +D7BB;HANGUL JUNGSEONG EU-E;Lo;0;L;;;;;N;;;;; +D7BC;HANGUL JUNGSEONG EU-O;Lo;0;L;;;;;N;;;;; +D7BD;HANGUL JUNGSEONG I-YA-O;Lo;0;L;;;;;N;;;;; +D7BE;HANGUL JUNGSEONG I-YAE;Lo;0;L;;;;;N;;;;; +D7BF;HANGUL JUNGSEONG I-YEO;Lo;0;L;;;;;N;;;;; +D7C0;HANGUL JUNGSEONG I-YE;Lo;0;L;;;;;N;;;;; +D7C1;HANGUL JUNGSEONG I-O-I;Lo;0;L;;;;;N;;;;; +D7C2;HANGUL JUNGSEONG I-YO;Lo;0;L;;;;;N;;;;; +D7C3;HANGUL JUNGSEONG I-YU;Lo;0;L;;;;;N;;;;; +D7C4;HANGUL JUNGSEONG I-I;Lo;0;L;;;;;N;;;;; +D7C5;HANGUL JUNGSEONG ARAEA-A;Lo;0;L;;;;;N;;;;; +D7C6;HANGUL JUNGSEONG ARAEA-E;Lo;0;L;;;;;N;;;;; +D7CB;HANGUL JONGSEONG NIEUN-RIEUL;Lo;0;L;;;;;N;;;;; +D7CC;HANGUL JONGSEONG NIEUN-CHIEUCH;Lo;0;L;;;;;N;;;;; +D7CD;HANGUL JONGSEONG SSANGTIKEUT;Lo;0;L;;;;;N;;;;; +D7CE;HANGUL JONGSEONG SSANGTIKEUT-PIEUP;Lo;0;L;;;;;N;;;;; +D7CF;HANGUL JONGSEONG TIKEUT-PIEUP;Lo;0;L;;;;;N;;;;; +D7D0;HANGUL JONGSEONG TIKEUT-SIOS;Lo;0;L;;;;;N;;;;; +D7D1;HANGUL JONGSEONG TIKEUT-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; +D7D2;HANGUL JONGSEONG TIKEUT-CIEUC;Lo;0;L;;;;;N;;;;; +D7D3;HANGUL JONGSEONG TIKEUT-CHIEUCH;Lo;0;L;;;;;N;;;;; +D7D4;HANGUL JONGSEONG TIKEUT-THIEUTH;Lo;0;L;;;;;N;;;;; +D7D5;HANGUL JONGSEONG RIEUL-SSANGKIYEOK;Lo;0;L;;;;;N;;;;; +D7D6;HANGUL JONGSEONG RIEUL-KIYEOK-HIEUH;Lo;0;L;;;;;N;;;;; +D7D7;HANGUL JONGSEONG SSANGRIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;; +D7D8;HANGUL JONGSEONG RIEUL-MIEUM-HIEUH;Lo;0;L;;;;;N;;;;; +D7D9;HANGUL JONGSEONG RIEUL-PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;; +D7DA;HANGUL JONGSEONG RIEUL-PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;; +D7DB;HANGUL JONGSEONG RIEUL-YESIEUNG;Lo;0;L;;;;;N;;;;; +D7DC;HANGUL JONGSEONG RIEUL-YEORINHIEUH-HIEUH;Lo;0;L;;;;;N;;;;; +D7DD;HANGUL JONGSEONG KAPYEOUNRIEUL;Lo;0;L;;;;;N;;;;; +D7DE;HANGUL JONGSEONG MIEUM-NIEUN;Lo;0;L;;;;;N;;;;; +D7DF;HANGUL JONGSEONG MIEUM-SSANGNIEUN;Lo;0;L;;;;;N;;;;; +D7E0;HANGUL JONGSEONG SSANGMIEUM;Lo;0;L;;;;;N;;;;; +D7E1;HANGUL JONGSEONG MIEUM-PIEUP-SIOS;Lo;0;L;;;;;N;;;;; +D7E2;HANGUL JONGSEONG MIEUM-CIEUC;Lo;0;L;;;;;N;;;;; +D7E3;HANGUL JONGSEONG PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;; +D7E4;HANGUL JONGSEONG PIEUP-RIEUL-PHIEUPH;Lo;0;L;;;;;N;;;;; +D7E5;HANGUL JONGSEONG PIEUP-MIEUM;Lo;0;L;;;;;N;;;;; +D7E6;HANGUL JONGSEONG SSANGPIEUP;Lo;0;L;;;;;N;;;;; +D7E7;HANGUL JONGSEONG PIEUP-SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; +D7E8;HANGUL JONGSEONG PIEUP-CIEUC;Lo;0;L;;;;;N;;;;; +D7E9;HANGUL JONGSEONG PIEUP-CHIEUCH;Lo;0;L;;;;;N;;;;; +D7EA;HANGUL JONGSEONG SIOS-MIEUM;Lo;0;L;;;;;N;;;;; +D7EB;HANGUL JONGSEONG SIOS-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; +D7EC;HANGUL JONGSEONG SSANGSIOS-KIYEOK;Lo;0;L;;;;;N;;;;; +D7ED;HANGUL JONGSEONG SSANGSIOS-TIKEUT;Lo;0;L;;;;;N;;;;; +D7EE;HANGUL JONGSEONG SIOS-PANSIOS;Lo;0;L;;;;;N;;;;; +D7EF;HANGUL JONGSEONG SIOS-CIEUC;Lo;0;L;;;;;N;;;;; +D7F0;HANGUL JONGSEONG SIOS-CHIEUCH;Lo;0;L;;;;;N;;;;; +D7F1;HANGUL JONGSEONG SIOS-THIEUTH;Lo;0;L;;;;;N;;;;; +D7F2;HANGUL JONGSEONG SIOS-HIEUH;Lo;0;L;;;;;N;;;;; +D7F3;HANGUL JONGSEONG PANSIOS-PIEUP;Lo;0;L;;;;;N;;;;; +D7F4;HANGUL JONGSEONG PANSIOS-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; +D7F5;HANGUL JONGSEONG YESIEUNG-MIEUM;Lo;0;L;;;;;N;;;;; +D7F6;HANGUL JONGSEONG YESIEUNG-HIEUH;Lo;0;L;;;;;N;;;;; +D7F7;HANGUL JONGSEONG CIEUC-PIEUP;Lo;0;L;;;;;N;;;;; +D7F8;HANGUL JONGSEONG CIEUC-SSANGPIEUP;Lo;0;L;;;;;N;;;;; +D7F9;HANGUL JONGSEONG SSANGCIEUC;Lo;0;L;;;;;N;;;;; +D7FA;HANGUL JONGSEONG PHIEUPH-SIOS;Lo;0;L;;;;;N;;;;; +D7FB;HANGUL JONGSEONG PHIEUPH-THIEUTH;Lo;0;L;;;;;N;;;;; +D800;;Cs;0;L;;;;;N;;;;; +DB7F;;Cs;0;L;;;;;N;;;;; +DB80;;Cs;0;L;;;;;N;;;;; +DBFF;;Cs;0;L;;;;;N;;;;; +DC00;;Cs;0;L;;;;;N;;;;; +DFFF;;Cs;0;L;;;;;N;;;;; +E000;;Co;0;L;;;;;N;;;;; +F8FF;;Co;0;L;;;;;N;;;;; +F900;CJK COMPATIBILITY IDEOGRAPH-F900;Lo;0;L;8C48;;;;N;;;;; +F901;CJK COMPATIBILITY IDEOGRAPH-F901;Lo;0;L;66F4;;;;N;;;;; +F902;CJK COMPATIBILITY IDEOGRAPH-F902;Lo;0;L;8ECA;;;;N;;;;; +F903;CJK COMPATIBILITY IDEOGRAPH-F903;Lo;0;L;8CC8;;;;N;;;;; +F904;CJK COMPATIBILITY IDEOGRAPH-F904;Lo;0;L;6ED1;;;;N;;;;; +F905;CJK COMPATIBILITY IDEOGRAPH-F905;Lo;0;L;4E32;;;;N;;;;; +F906;CJK COMPATIBILITY IDEOGRAPH-F906;Lo;0;L;53E5;;;;N;;;;; +F907;CJK COMPATIBILITY IDEOGRAPH-F907;Lo;0;L;9F9C;;;;N;;;;; +F908;CJK COMPATIBILITY IDEOGRAPH-F908;Lo;0;L;9F9C;;;;N;;;;; +F909;CJK COMPATIBILITY IDEOGRAPH-F909;Lo;0;L;5951;;;;N;;;;; +F90A;CJK COMPATIBILITY IDEOGRAPH-F90A;Lo;0;L;91D1;;;;N;;;;; +F90B;CJK COMPATIBILITY IDEOGRAPH-F90B;Lo;0;L;5587;;;;N;;;;; +F90C;CJK COMPATIBILITY IDEOGRAPH-F90C;Lo;0;L;5948;;;;N;;;;; +F90D;CJK COMPATIBILITY IDEOGRAPH-F90D;Lo;0;L;61F6;;;;N;;;;; +F90E;CJK COMPATIBILITY IDEOGRAPH-F90E;Lo;0;L;7669;;;;N;;;;; +F90F;CJK COMPATIBILITY IDEOGRAPH-F90F;Lo;0;L;7F85;;;;N;;;;; +F910;CJK COMPATIBILITY IDEOGRAPH-F910;Lo;0;L;863F;;;;N;;;;; +F911;CJK COMPATIBILITY IDEOGRAPH-F911;Lo;0;L;87BA;;;;N;;;;; +F912;CJK COMPATIBILITY IDEOGRAPH-F912;Lo;0;L;88F8;;;;N;;;;; +F913;CJK COMPATIBILITY IDEOGRAPH-F913;Lo;0;L;908F;;;;N;;;;; +F914;CJK COMPATIBILITY IDEOGRAPH-F914;Lo;0;L;6A02;;;;N;;;;; +F915;CJK COMPATIBILITY IDEOGRAPH-F915;Lo;0;L;6D1B;;;;N;;;;; +F916;CJK COMPATIBILITY IDEOGRAPH-F916;Lo;0;L;70D9;;;;N;;;;; +F917;CJK COMPATIBILITY IDEOGRAPH-F917;Lo;0;L;73DE;;;;N;;;;; +F918;CJK COMPATIBILITY IDEOGRAPH-F918;Lo;0;L;843D;;;;N;;;;; +F919;CJK COMPATIBILITY IDEOGRAPH-F919;Lo;0;L;916A;;;;N;;;;; +F91A;CJK COMPATIBILITY IDEOGRAPH-F91A;Lo;0;L;99F1;;;;N;;;;; +F91B;CJK COMPATIBILITY IDEOGRAPH-F91B;Lo;0;L;4E82;;;;N;;;;; +F91C;CJK COMPATIBILITY IDEOGRAPH-F91C;Lo;0;L;5375;;;;N;;;;; +F91D;CJK COMPATIBILITY IDEOGRAPH-F91D;Lo;0;L;6B04;;;;N;;;;; +F91E;CJK COMPATIBILITY IDEOGRAPH-F91E;Lo;0;L;721B;;;;N;;;;; +F91F;CJK COMPATIBILITY IDEOGRAPH-F91F;Lo;0;L;862D;;;;N;;;;; +F920;CJK COMPATIBILITY IDEOGRAPH-F920;Lo;0;L;9E1E;;;;N;;;;; +F921;CJK COMPATIBILITY IDEOGRAPH-F921;Lo;0;L;5D50;;;;N;;;;; +F922;CJK COMPATIBILITY IDEOGRAPH-F922;Lo;0;L;6FEB;;;;N;;;;; +F923;CJK COMPATIBILITY IDEOGRAPH-F923;Lo;0;L;85CD;;;;N;;;;; +F924;CJK COMPATIBILITY IDEOGRAPH-F924;Lo;0;L;8964;;;;N;;;;; +F925;CJK COMPATIBILITY IDEOGRAPH-F925;Lo;0;L;62C9;;;;N;;;;; +F926;CJK COMPATIBILITY IDEOGRAPH-F926;Lo;0;L;81D8;;;;N;;;;; +F927;CJK COMPATIBILITY IDEOGRAPH-F927;Lo;0;L;881F;;;;N;;;;; +F928;CJK COMPATIBILITY IDEOGRAPH-F928;Lo;0;L;5ECA;;;;N;;;;; +F929;CJK COMPATIBILITY IDEOGRAPH-F929;Lo;0;L;6717;;;;N;;;;; +F92A;CJK COMPATIBILITY IDEOGRAPH-F92A;Lo;0;L;6D6A;;;;N;;;;; +F92B;CJK COMPATIBILITY IDEOGRAPH-F92B;Lo;0;L;72FC;;;;N;;;;; +F92C;CJK COMPATIBILITY IDEOGRAPH-F92C;Lo;0;L;90CE;;;;N;;;;; +F92D;CJK COMPATIBILITY IDEOGRAPH-F92D;Lo;0;L;4F86;;;;N;;;;; +F92E;CJK COMPATIBILITY IDEOGRAPH-F92E;Lo;0;L;51B7;;;;N;;;;; +F92F;CJK COMPATIBILITY IDEOGRAPH-F92F;Lo;0;L;52DE;;;;N;;;;; +F930;CJK COMPATIBILITY IDEOGRAPH-F930;Lo;0;L;64C4;;;;N;;;;; +F931;CJK COMPATIBILITY IDEOGRAPH-F931;Lo;0;L;6AD3;;;;N;;;;; +F932;CJK COMPATIBILITY IDEOGRAPH-F932;Lo;0;L;7210;;;;N;;;;; +F933;CJK COMPATIBILITY IDEOGRAPH-F933;Lo;0;L;76E7;;;;N;;;;; +F934;CJK COMPATIBILITY IDEOGRAPH-F934;Lo;0;L;8001;;;;N;;;;; +F935;CJK COMPATIBILITY IDEOGRAPH-F935;Lo;0;L;8606;;;;N;;;;; +F936;CJK COMPATIBILITY IDEOGRAPH-F936;Lo;0;L;865C;;;;N;;;;; +F937;CJK COMPATIBILITY IDEOGRAPH-F937;Lo;0;L;8DEF;;;;N;;;;; +F938;CJK COMPATIBILITY IDEOGRAPH-F938;Lo;0;L;9732;;;;N;;;;; +F939;CJK COMPATIBILITY IDEOGRAPH-F939;Lo;0;L;9B6F;;;;N;;;;; +F93A;CJK COMPATIBILITY IDEOGRAPH-F93A;Lo;0;L;9DFA;;;;N;;;;; +F93B;CJK COMPATIBILITY IDEOGRAPH-F93B;Lo;0;L;788C;;;;N;;;;; +F93C;CJK COMPATIBILITY IDEOGRAPH-F93C;Lo;0;L;797F;;;;N;;;;; +F93D;CJK COMPATIBILITY IDEOGRAPH-F93D;Lo;0;L;7DA0;;;;N;;;;; +F93E;CJK COMPATIBILITY IDEOGRAPH-F93E;Lo;0;L;83C9;;;;N;;;;; +F93F;CJK COMPATIBILITY IDEOGRAPH-F93F;Lo;0;L;9304;;;;N;;;;; +F940;CJK COMPATIBILITY IDEOGRAPH-F940;Lo;0;L;9E7F;;;;N;;;;; +F941;CJK COMPATIBILITY IDEOGRAPH-F941;Lo;0;L;8AD6;;;;N;;;;; +F942;CJK COMPATIBILITY IDEOGRAPH-F942;Lo;0;L;58DF;;;;N;;;;; +F943;CJK COMPATIBILITY IDEOGRAPH-F943;Lo;0;L;5F04;;;;N;;;;; +F944;CJK COMPATIBILITY IDEOGRAPH-F944;Lo;0;L;7C60;;;;N;;;;; +F945;CJK COMPATIBILITY IDEOGRAPH-F945;Lo;0;L;807E;;;;N;;;;; +F946;CJK COMPATIBILITY IDEOGRAPH-F946;Lo;0;L;7262;;;;N;;;;; +F947;CJK COMPATIBILITY IDEOGRAPH-F947;Lo;0;L;78CA;;;;N;;;;; +F948;CJK COMPATIBILITY IDEOGRAPH-F948;Lo;0;L;8CC2;;;;N;;;;; +F949;CJK COMPATIBILITY IDEOGRAPH-F949;Lo;0;L;96F7;;;;N;;;;; +F94A;CJK COMPATIBILITY IDEOGRAPH-F94A;Lo;0;L;58D8;;;;N;;;;; +F94B;CJK COMPATIBILITY IDEOGRAPH-F94B;Lo;0;L;5C62;;;;N;;;;; +F94C;CJK COMPATIBILITY IDEOGRAPH-F94C;Lo;0;L;6A13;;;;N;;;;; +F94D;CJK COMPATIBILITY IDEOGRAPH-F94D;Lo;0;L;6DDA;;;;N;;;;; +F94E;CJK COMPATIBILITY IDEOGRAPH-F94E;Lo;0;L;6F0F;;;;N;;;;; +F94F;CJK COMPATIBILITY IDEOGRAPH-F94F;Lo;0;L;7D2F;;;;N;;;;; +F950;CJK COMPATIBILITY IDEOGRAPH-F950;Lo;0;L;7E37;;;;N;;;;; +F951;CJK COMPATIBILITY IDEOGRAPH-F951;Lo;0;L;964B;;;;N;;;;; +F952;CJK COMPATIBILITY IDEOGRAPH-F952;Lo;0;L;52D2;;;;N;;;;; +F953;CJK COMPATIBILITY IDEOGRAPH-F953;Lo;0;L;808B;;;;N;;;;; +F954;CJK COMPATIBILITY IDEOGRAPH-F954;Lo;0;L;51DC;;;;N;;;;; +F955;CJK COMPATIBILITY IDEOGRAPH-F955;Lo;0;L;51CC;;;;N;;;;; +F956;CJK COMPATIBILITY IDEOGRAPH-F956;Lo;0;L;7A1C;;;;N;;;;; +F957;CJK COMPATIBILITY IDEOGRAPH-F957;Lo;0;L;7DBE;;;;N;;;;; +F958;CJK COMPATIBILITY IDEOGRAPH-F958;Lo;0;L;83F1;;;;N;;;;; +F959;CJK COMPATIBILITY IDEOGRAPH-F959;Lo;0;L;9675;;;;N;;;;; +F95A;CJK COMPATIBILITY IDEOGRAPH-F95A;Lo;0;L;8B80;;;;N;;;;; +F95B;CJK COMPATIBILITY IDEOGRAPH-F95B;Lo;0;L;62CF;;;;N;;;;; +F95C;CJK COMPATIBILITY IDEOGRAPH-F95C;Lo;0;L;6A02;;;;N;;;;; +F95D;CJK COMPATIBILITY IDEOGRAPH-F95D;Lo;0;L;8AFE;;;;N;;;;; +F95E;CJK COMPATIBILITY IDEOGRAPH-F95E;Lo;0;L;4E39;;;;N;;;;; +F95F;CJK COMPATIBILITY IDEOGRAPH-F95F;Lo;0;L;5BE7;;;;N;;;;; +F960;CJK COMPATIBILITY IDEOGRAPH-F960;Lo;0;L;6012;;;;N;;;;; +F961;CJK COMPATIBILITY IDEOGRAPH-F961;Lo;0;L;7387;;;;N;;;;; +F962;CJK COMPATIBILITY IDEOGRAPH-F962;Lo;0;L;7570;;;;N;;;;; +F963;CJK COMPATIBILITY IDEOGRAPH-F963;Lo;0;L;5317;;;;N;;;;; +F964;CJK COMPATIBILITY IDEOGRAPH-F964;Lo;0;L;78FB;;;;N;;;;; +F965;CJK COMPATIBILITY IDEOGRAPH-F965;Lo;0;L;4FBF;;;;N;;;;; +F966;CJK COMPATIBILITY IDEOGRAPH-F966;Lo;0;L;5FA9;;;;N;;;;; +F967;CJK COMPATIBILITY IDEOGRAPH-F967;Lo;0;L;4E0D;;;;N;;;;; +F968;CJK COMPATIBILITY IDEOGRAPH-F968;Lo;0;L;6CCC;;;;N;;;;; +F969;CJK COMPATIBILITY IDEOGRAPH-F969;Lo;0;L;6578;;;;N;;;;; +F96A;CJK COMPATIBILITY IDEOGRAPH-F96A;Lo;0;L;7D22;;;;N;;;;; +F96B;CJK COMPATIBILITY IDEOGRAPH-F96B;Lo;0;L;53C3;;;3;N;;;;; +F96C;CJK COMPATIBILITY IDEOGRAPH-F96C;Lo;0;L;585E;;;;N;;;;; +F96D;CJK COMPATIBILITY IDEOGRAPH-F96D;Lo;0;L;7701;;;;N;;;;; +F96E;CJK COMPATIBILITY IDEOGRAPH-F96E;Lo;0;L;8449;;;;N;;;;; +F96F;CJK COMPATIBILITY IDEOGRAPH-F96F;Lo;0;L;8AAA;;;;N;;;;; +F970;CJK COMPATIBILITY IDEOGRAPH-F970;Lo;0;L;6BBA;;;;N;;;;; +F971;CJK COMPATIBILITY IDEOGRAPH-F971;Lo;0;L;8FB0;;;;N;;;;; +F972;CJK COMPATIBILITY IDEOGRAPH-F972;Lo;0;L;6C88;;;;N;;;;; +F973;CJK COMPATIBILITY IDEOGRAPH-F973;Lo;0;L;62FE;;;10;N;;;;; +F974;CJK COMPATIBILITY IDEOGRAPH-F974;Lo;0;L;82E5;;;;N;;;;; +F975;CJK COMPATIBILITY IDEOGRAPH-F975;Lo;0;L;63A0;;;;N;;;;; +F976;CJK COMPATIBILITY IDEOGRAPH-F976;Lo;0;L;7565;;;;N;;;;; +F977;CJK COMPATIBILITY IDEOGRAPH-F977;Lo;0;L;4EAE;;;;N;;;;; +F978;CJK COMPATIBILITY IDEOGRAPH-F978;Lo;0;L;5169;;;2;N;;;;; +F979;CJK COMPATIBILITY IDEOGRAPH-F979;Lo;0;L;51C9;;;;N;;;;; +F97A;CJK COMPATIBILITY IDEOGRAPH-F97A;Lo;0;L;6881;;;;N;;;;; +F97B;CJK COMPATIBILITY IDEOGRAPH-F97B;Lo;0;L;7CE7;;;;N;;;;; +F97C;CJK COMPATIBILITY IDEOGRAPH-F97C;Lo;0;L;826F;;;;N;;;;; +F97D;CJK COMPATIBILITY IDEOGRAPH-F97D;Lo;0;L;8AD2;;;;N;;;;; +F97E;CJK COMPATIBILITY IDEOGRAPH-F97E;Lo;0;L;91CF;;;;N;;;;; +F97F;CJK COMPATIBILITY IDEOGRAPH-F97F;Lo;0;L;52F5;;;;N;;;;; +F980;CJK COMPATIBILITY IDEOGRAPH-F980;Lo;0;L;5442;;;;N;;;;; +F981;CJK COMPATIBILITY IDEOGRAPH-F981;Lo;0;L;5973;;;;N;;;;; +F982;CJK COMPATIBILITY IDEOGRAPH-F982;Lo;0;L;5EEC;;;;N;;;;; +F983;CJK COMPATIBILITY IDEOGRAPH-F983;Lo;0;L;65C5;;;;N;;;;; +F984;CJK COMPATIBILITY IDEOGRAPH-F984;Lo;0;L;6FFE;;;;N;;;;; +F985;CJK COMPATIBILITY IDEOGRAPH-F985;Lo;0;L;792A;;;;N;;;;; +F986;CJK COMPATIBILITY IDEOGRAPH-F986;Lo;0;L;95AD;;;;N;;;;; +F987;CJK COMPATIBILITY IDEOGRAPH-F987;Lo;0;L;9A6A;;;;N;;;;; +F988;CJK COMPATIBILITY IDEOGRAPH-F988;Lo;0;L;9E97;;;;N;;;;; +F989;CJK COMPATIBILITY IDEOGRAPH-F989;Lo;0;L;9ECE;;;;N;;;;; +F98A;CJK COMPATIBILITY IDEOGRAPH-F98A;Lo;0;L;529B;;;;N;;;;; +F98B;CJK COMPATIBILITY IDEOGRAPH-F98B;Lo;0;L;66C6;;;;N;;;;; +F98C;CJK COMPATIBILITY IDEOGRAPH-F98C;Lo;0;L;6B77;;;;N;;;;; +F98D;CJK COMPATIBILITY IDEOGRAPH-F98D;Lo;0;L;8F62;;;;N;;;;; +F98E;CJK COMPATIBILITY IDEOGRAPH-F98E;Lo;0;L;5E74;;;;N;;;;; +F98F;CJK COMPATIBILITY IDEOGRAPH-F98F;Lo;0;L;6190;;;;N;;;;; +F990;CJK COMPATIBILITY IDEOGRAPH-F990;Lo;0;L;6200;;;;N;;;;; +F991;CJK COMPATIBILITY IDEOGRAPH-F991;Lo;0;L;649A;;;;N;;;;; +F992;CJK COMPATIBILITY IDEOGRAPH-F992;Lo;0;L;6F23;;;;N;;;;; +F993;CJK COMPATIBILITY IDEOGRAPH-F993;Lo;0;L;7149;;;;N;;;;; +F994;CJK COMPATIBILITY IDEOGRAPH-F994;Lo;0;L;7489;;;;N;;;;; +F995;CJK COMPATIBILITY IDEOGRAPH-F995;Lo;0;L;79CA;;;;N;;;;; +F996;CJK COMPATIBILITY IDEOGRAPH-F996;Lo;0;L;7DF4;;;;N;;;;; +F997;CJK COMPATIBILITY IDEOGRAPH-F997;Lo;0;L;806F;;;;N;;;;; +F998;CJK COMPATIBILITY IDEOGRAPH-F998;Lo;0;L;8F26;;;;N;;;;; +F999;CJK COMPATIBILITY IDEOGRAPH-F999;Lo;0;L;84EE;;;;N;;;;; +F99A;CJK COMPATIBILITY IDEOGRAPH-F99A;Lo;0;L;9023;;;;N;;;;; +F99B;CJK COMPATIBILITY IDEOGRAPH-F99B;Lo;0;L;934A;;;;N;;;;; +F99C;CJK COMPATIBILITY IDEOGRAPH-F99C;Lo;0;L;5217;;;;N;;;;; +F99D;CJK COMPATIBILITY IDEOGRAPH-F99D;Lo;0;L;52A3;;;;N;;;;; +F99E;CJK COMPATIBILITY IDEOGRAPH-F99E;Lo;0;L;54BD;;;;N;;;;; +F99F;CJK COMPATIBILITY IDEOGRAPH-F99F;Lo;0;L;70C8;;;;N;;;;; +F9A0;CJK COMPATIBILITY IDEOGRAPH-F9A0;Lo;0;L;88C2;;;;N;;;;; +F9A1;CJK COMPATIBILITY IDEOGRAPH-F9A1;Lo;0;L;8AAA;;;;N;;;;; +F9A2;CJK COMPATIBILITY IDEOGRAPH-F9A2;Lo;0;L;5EC9;;;;N;;;;; +F9A3;CJK COMPATIBILITY IDEOGRAPH-F9A3;Lo;0;L;5FF5;;;;N;;;;; +F9A4;CJK COMPATIBILITY IDEOGRAPH-F9A4;Lo;0;L;637B;;;;N;;;;; +F9A5;CJK COMPATIBILITY IDEOGRAPH-F9A5;Lo;0;L;6BAE;;;;N;;;;; +F9A6;CJK COMPATIBILITY IDEOGRAPH-F9A6;Lo;0;L;7C3E;;;;N;;;;; +F9A7;CJK COMPATIBILITY IDEOGRAPH-F9A7;Lo;0;L;7375;;;;N;;;;; +F9A8;CJK COMPATIBILITY IDEOGRAPH-F9A8;Lo;0;L;4EE4;;;;N;;;;; +F9A9;CJK COMPATIBILITY IDEOGRAPH-F9A9;Lo;0;L;56F9;;;;N;;;;; +F9AA;CJK COMPATIBILITY IDEOGRAPH-F9AA;Lo;0;L;5BE7;;;;N;;;;; +F9AB;CJK COMPATIBILITY IDEOGRAPH-F9AB;Lo;0;L;5DBA;;;;N;;;;; +F9AC;CJK COMPATIBILITY IDEOGRAPH-F9AC;Lo;0;L;601C;;;;N;;;;; +F9AD;CJK COMPATIBILITY IDEOGRAPH-F9AD;Lo;0;L;73B2;;;;N;;;;; +F9AE;CJK COMPATIBILITY IDEOGRAPH-F9AE;Lo;0;L;7469;;;;N;;;;; +F9AF;CJK COMPATIBILITY IDEOGRAPH-F9AF;Lo;0;L;7F9A;;;;N;;;;; +F9B0;CJK COMPATIBILITY IDEOGRAPH-F9B0;Lo;0;L;8046;;;;N;;;;; +F9B1;CJK COMPATIBILITY IDEOGRAPH-F9B1;Lo;0;L;9234;;;;N;;;;; +F9B2;CJK COMPATIBILITY IDEOGRAPH-F9B2;Lo;0;L;96F6;;;0;N;;;;; +F9B3;CJK COMPATIBILITY IDEOGRAPH-F9B3;Lo;0;L;9748;;;;N;;;;; +F9B4;CJK COMPATIBILITY IDEOGRAPH-F9B4;Lo;0;L;9818;;;;N;;;;; +F9B5;CJK COMPATIBILITY IDEOGRAPH-F9B5;Lo;0;L;4F8B;;;;N;;;;; +F9B6;CJK COMPATIBILITY IDEOGRAPH-F9B6;Lo;0;L;79AE;;;;N;;;;; +F9B7;CJK COMPATIBILITY IDEOGRAPH-F9B7;Lo;0;L;91B4;;;;N;;;;; +F9B8;CJK COMPATIBILITY IDEOGRAPH-F9B8;Lo;0;L;96B8;;;;N;;;;; +F9B9;CJK COMPATIBILITY IDEOGRAPH-F9B9;Lo;0;L;60E1;;;;N;;;;; +F9BA;CJK COMPATIBILITY IDEOGRAPH-F9BA;Lo;0;L;4E86;;;;N;;;;; +F9BB;CJK COMPATIBILITY IDEOGRAPH-F9BB;Lo;0;L;50DA;;;;N;;;;; +F9BC;CJK COMPATIBILITY IDEOGRAPH-F9BC;Lo;0;L;5BEE;;;;N;;;;; +F9BD;CJK COMPATIBILITY IDEOGRAPH-F9BD;Lo;0;L;5C3F;;;;N;;;;; +F9BE;CJK COMPATIBILITY IDEOGRAPH-F9BE;Lo;0;L;6599;;;;N;;;;; +F9BF;CJK COMPATIBILITY IDEOGRAPH-F9BF;Lo;0;L;6A02;;;;N;;;;; +F9C0;CJK COMPATIBILITY IDEOGRAPH-F9C0;Lo;0;L;71CE;;;;N;;;;; +F9C1;CJK COMPATIBILITY IDEOGRAPH-F9C1;Lo;0;L;7642;;;;N;;;;; +F9C2;CJK COMPATIBILITY IDEOGRAPH-F9C2;Lo;0;L;84FC;;;;N;;;;; +F9C3;CJK COMPATIBILITY IDEOGRAPH-F9C3;Lo;0;L;907C;;;;N;;;;; +F9C4;CJK COMPATIBILITY IDEOGRAPH-F9C4;Lo;0;L;9F8D;;;;N;;;;; +F9C5;CJK COMPATIBILITY IDEOGRAPH-F9C5;Lo;0;L;6688;;;;N;;;;; +F9C6;CJK COMPATIBILITY IDEOGRAPH-F9C6;Lo;0;L;962E;;;;N;;;;; +F9C7;CJK COMPATIBILITY IDEOGRAPH-F9C7;Lo;0;L;5289;;;;N;;;;; +F9C8;CJK COMPATIBILITY IDEOGRAPH-F9C8;Lo;0;L;677B;;;;N;;;;; +F9C9;CJK COMPATIBILITY IDEOGRAPH-F9C9;Lo;0;L;67F3;;;;N;;;;; +F9CA;CJK COMPATIBILITY IDEOGRAPH-F9CA;Lo;0;L;6D41;;;;N;;;;; +F9CB;CJK COMPATIBILITY IDEOGRAPH-F9CB;Lo;0;L;6E9C;;;;N;;;;; +F9CC;CJK COMPATIBILITY IDEOGRAPH-F9CC;Lo;0;L;7409;;;;N;;;;; +F9CD;CJK COMPATIBILITY IDEOGRAPH-F9CD;Lo;0;L;7559;;;;N;;;;; +F9CE;CJK COMPATIBILITY IDEOGRAPH-F9CE;Lo;0;L;786B;;;;N;;;;; +F9CF;CJK COMPATIBILITY IDEOGRAPH-F9CF;Lo;0;L;7D10;;;;N;;;;; +F9D0;CJK COMPATIBILITY IDEOGRAPH-F9D0;Lo;0;L;985E;;;;N;;;;; +F9D1;CJK COMPATIBILITY IDEOGRAPH-F9D1;Lo;0;L;516D;;;6;N;;;;; +F9D2;CJK COMPATIBILITY IDEOGRAPH-F9D2;Lo;0;L;622E;;;;N;;;;; +F9D3;CJK COMPATIBILITY IDEOGRAPH-F9D3;Lo;0;L;9678;;;6;N;;;;; +F9D4;CJK COMPATIBILITY IDEOGRAPH-F9D4;Lo;0;L;502B;;;;N;;;;; +F9D5;CJK COMPATIBILITY IDEOGRAPH-F9D5;Lo;0;L;5D19;;;;N;;;;; +F9D6;CJK COMPATIBILITY IDEOGRAPH-F9D6;Lo;0;L;6DEA;;;;N;;;;; +F9D7;CJK COMPATIBILITY IDEOGRAPH-F9D7;Lo;0;L;8F2A;;;;N;;;;; +F9D8;CJK COMPATIBILITY IDEOGRAPH-F9D8;Lo;0;L;5F8B;;;;N;;;;; +F9D9;CJK COMPATIBILITY IDEOGRAPH-F9D9;Lo;0;L;6144;;;;N;;;;; +F9DA;CJK COMPATIBILITY IDEOGRAPH-F9DA;Lo;0;L;6817;;;;N;;;;; +F9DB;CJK COMPATIBILITY IDEOGRAPH-F9DB;Lo;0;L;7387;;;;N;;;;; +F9DC;CJK COMPATIBILITY IDEOGRAPH-F9DC;Lo;0;L;9686;;;;N;;;;; +F9DD;CJK COMPATIBILITY IDEOGRAPH-F9DD;Lo;0;L;5229;;;;N;;;;; +F9DE;CJK COMPATIBILITY IDEOGRAPH-F9DE;Lo;0;L;540F;;;;N;;;;; +F9DF;CJK COMPATIBILITY IDEOGRAPH-F9DF;Lo;0;L;5C65;;;;N;;;;; +F9E0;CJK COMPATIBILITY IDEOGRAPH-F9E0;Lo;0;L;6613;;;;N;;;;; +F9E1;CJK COMPATIBILITY IDEOGRAPH-F9E1;Lo;0;L;674E;;;;N;;;;; +F9E2;CJK COMPATIBILITY IDEOGRAPH-F9E2;Lo;0;L;68A8;;;;N;;;;; +F9E3;CJK COMPATIBILITY IDEOGRAPH-F9E3;Lo;0;L;6CE5;;;;N;;;;; +F9E4;CJK COMPATIBILITY IDEOGRAPH-F9E4;Lo;0;L;7406;;;;N;;;;; +F9E5;CJK COMPATIBILITY IDEOGRAPH-F9E5;Lo;0;L;75E2;;;;N;;;;; +F9E6;CJK COMPATIBILITY IDEOGRAPH-F9E6;Lo;0;L;7F79;;;;N;;;;; +F9E7;CJK COMPATIBILITY IDEOGRAPH-F9E7;Lo;0;L;88CF;;;;N;;;;; +F9E8;CJK COMPATIBILITY IDEOGRAPH-F9E8;Lo;0;L;88E1;;;;N;;;;; +F9E9;CJK COMPATIBILITY IDEOGRAPH-F9E9;Lo;0;L;91CC;;;;N;;;;; +F9EA;CJK COMPATIBILITY IDEOGRAPH-F9EA;Lo;0;L;96E2;;;;N;;;;; +F9EB;CJK COMPATIBILITY IDEOGRAPH-F9EB;Lo;0;L;533F;;;;N;;;;; +F9EC;CJK COMPATIBILITY IDEOGRAPH-F9EC;Lo;0;L;6EBA;;;;N;;;;; +F9ED;CJK COMPATIBILITY IDEOGRAPH-F9ED;Lo;0;L;541D;;;;N;;;;; +F9EE;CJK COMPATIBILITY IDEOGRAPH-F9EE;Lo;0;L;71D0;;;;N;;;;; +F9EF;CJK COMPATIBILITY IDEOGRAPH-F9EF;Lo;0;L;7498;;;;N;;;;; +F9F0;CJK COMPATIBILITY IDEOGRAPH-F9F0;Lo;0;L;85FA;;;;N;;;;; +F9F1;CJK COMPATIBILITY IDEOGRAPH-F9F1;Lo;0;L;96A3;;;;N;;;;; +F9F2;CJK COMPATIBILITY IDEOGRAPH-F9F2;Lo;0;L;9C57;;;;N;;;;; +F9F3;CJK COMPATIBILITY IDEOGRAPH-F9F3;Lo;0;L;9E9F;;;;N;;;;; +F9F4;CJK COMPATIBILITY IDEOGRAPH-F9F4;Lo;0;L;6797;;;;N;;;;; +F9F5;CJK COMPATIBILITY IDEOGRAPH-F9F5;Lo;0;L;6DCB;;;;N;;;;; +F9F6;CJK COMPATIBILITY IDEOGRAPH-F9F6;Lo;0;L;81E8;;;;N;;;;; +F9F7;CJK COMPATIBILITY IDEOGRAPH-F9F7;Lo;0;L;7ACB;;;;N;;;;; +F9F8;CJK COMPATIBILITY IDEOGRAPH-F9F8;Lo;0;L;7B20;;;;N;;;;; +F9F9;CJK COMPATIBILITY IDEOGRAPH-F9F9;Lo;0;L;7C92;;;;N;;;;; +F9FA;CJK COMPATIBILITY IDEOGRAPH-F9FA;Lo;0;L;72C0;;;;N;;;;; +F9FB;CJK COMPATIBILITY IDEOGRAPH-F9FB;Lo;0;L;7099;;;;N;;;;; +F9FC;CJK COMPATIBILITY IDEOGRAPH-F9FC;Lo;0;L;8B58;;;;N;;;;; +F9FD;CJK COMPATIBILITY IDEOGRAPH-F9FD;Lo;0;L;4EC0;;;10;N;;;;; +F9FE;CJK COMPATIBILITY IDEOGRAPH-F9FE;Lo;0;L;8336;;;;N;;;;; +F9FF;CJK COMPATIBILITY IDEOGRAPH-F9FF;Lo;0;L;523A;;;;N;;;;; +FA00;CJK COMPATIBILITY IDEOGRAPH-FA00;Lo;0;L;5207;;;;N;;;;; +FA01;CJK COMPATIBILITY IDEOGRAPH-FA01;Lo;0;L;5EA6;;;;N;;;;; +FA02;CJK COMPATIBILITY IDEOGRAPH-FA02;Lo;0;L;62D3;;;;N;;;;; +FA03;CJK COMPATIBILITY IDEOGRAPH-FA03;Lo;0;L;7CD6;;;;N;;;;; +FA04;CJK COMPATIBILITY IDEOGRAPH-FA04;Lo;0;L;5B85;;;;N;;;;; +FA05;CJK COMPATIBILITY IDEOGRAPH-FA05;Lo;0;L;6D1E;;;;N;;;;; +FA06;CJK COMPATIBILITY IDEOGRAPH-FA06;Lo;0;L;66B4;;;;N;;;;; +FA07;CJK COMPATIBILITY IDEOGRAPH-FA07;Lo;0;L;8F3B;;;;N;;;;; +FA08;CJK COMPATIBILITY IDEOGRAPH-FA08;Lo;0;L;884C;;;;N;;;;; +FA09;CJK COMPATIBILITY IDEOGRAPH-FA09;Lo;0;L;964D;;;;N;;;;; +FA0A;CJK COMPATIBILITY IDEOGRAPH-FA0A;Lo;0;L;898B;;;;N;;;;; +FA0B;CJK COMPATIBILITY IDEOGRAPH-FA0B;Lo;0;L;5ED3;;;;N;;;;; +FA0C;CJK COMPATIBILITY IDEOGRAPH-FA0C;Lo;0;L;5140;;;;N;;;;; +FA0D;CJK COMPATIBILITY IDEOGRAPH-FA0D;Lo;0;L;55C0;;;;N;;;;; +FA0E;CJK COMPATIBILITY IDEOGRAPH-FA0E;Lo;0;L;;;;;N;;;;; +FA0F;CJK COMPATIBILITY IDEOGRAPH-FA0F;Lo;0;L;;;;;N;;;;; +FA10;CJK COMPATIBILITY IDEOGRAPH-FA10;Lo;0;L;585A;;;;N;;;;; +FA11;CJK COMPATIBILITY IDEOGRAPH-FA11;Lo;0;L;;;;;N;;;;; +FA12;CJK COMPATIBILITY IDEOGRAPH-FA12;Lo;0;L;6674;;;;N;;;;; +FA13;CJK COMPATIBILITY IDEOGRAPH-FA13;Lo;0;L;;;;;N;;;;; +FA14;CJK COMPATIBILITY IDEOGRAPH-FA14;Lo;0;L;;;;;N;;;;; +FA15;CJK COMPATIBILITY IDEOGRAPH-FA15;Lo;0;L;51DE;;;;N;;;;; +FA16;CJK COMPATIBILITY IDEOGRAPH-FA16;Lo;0;L;732A;;;;N;;;;; +FA17;CJK COMPATIBILITY IDEOGRAPH-FA17;Lo;0;L;76CA;;;;N;;;;; +FA18;CJK COMPATIBILITY IDEOGRAPH-FA18;Lo;0;L;793C;;;;N;;;;; +FA19;CJK COMPATIBILITY IDEOGRAPH-FA19;Lo;0;L;795E;;;;N;;;;; +FA1A;CJK COMPATIBILITY IDEOGRAPH-FA1A;Lo;0;L;7965;;;;N;;;;; +FA1B;CJK COMPATIBILITY IDEOGRAPH-FA1B;Lo;0;L;798F;;;;N;;;;; +FA1C;CJK COMPATIBILITY IDEOGRAPH-FA1C;Lo;0;L;9756;;;;N;;;;; +FA1D;CJK COMPATIBILITY IDEOGRAPH-FA1D;Lo;0;L;7CBE;;;;N;;;;; +FA1E;CJK COMPATIBILITY IDEOGRAPH-FA1E;Lo;0;L;7FBD;;;;N;;;;; +FA1F;CJK COMPATIBILITY IDEOGRAPH-FA1F;Lo;0;L;;;;;N;;;;; +FA20;CJK COMPATIBILITY IDEOGRAPH-FA20;Lo;0;L;8612;;;;N;;;;; +FA21;CJK COMPATIBILITY IDEOGRAPH-FA21;Lo;0;L;;;;;N;;;;; +FA22;CJK COMPATIBILITY IDEOGRAPH-FA22;Lo;0;L;8AF8;;;;N;;;;; +FA23;CJK COMPATIBILITY IDEOGRAPH-FA23;Lo;0;L;;;;;N;;;;; +FA24;CJK COMPATIBILITY IDEOGRAPH-FA24;Lo;0;L;;;;;N;;;;; +FA25;CJK COMPATIBILITY IDEOGRAPH-FA25;Lo;0;L;9038;;;;N;;;;; +FA26;CJK COMPATIBILITY IDEOGRAPH-FA26;Lo;0;L;90FD;;;;N;;;;; +FA27;CJK COMPATIBILITY IDEOGRAPH-FA27;Lo;0;L;;;;;N;;;;; +FA28;CJK COMPATIBILITY IDEOGRAPH-FA28;Lo;0;L;;;;;N;;;;; +FA29;CJK COMPATIBILITY IDEOGRAPH-FA29;Lo;0;L;;;;;N;;;;; +FA2A;CJK COMPATIBILITY IDEOGRAPH-FA2A;Lo;0;L;98EF;;;;N;;;;; +FA2B;CJK COMPATIBILITY IDEOGRAPH-FA2B;Lo;0;L;98FC;;;;N;;;;; +FA2C;CJK COMPATIBILITY IDEOGRAPH-FA2C;Lo;0;L;9928;;;;N;;;;; +FA2D;CJK COMPATIBILITY IDEOGRAPH-FA2D;Lo;0;L;9DB4;;;;N;;;;; +FA2E;CJK COMPATIBILITY IDEOGRAPH-FA2E;Lo;0;L;90DE;;;;N;;;;; +FA2F;CJK COMPATIBILITY IDEOGRAPH-FA2F;Lo;0;L;96B7;;;;N;;;;; +FA30;CJK COMPATIBILITY IDEOGRAPH-FA30;Lo;0;L;4FAE;;;;N;;;;; +FA31;CJK COMPATIBILITY IDEOGRAPH-FA31;Lo;0;L;50E7;;;;N;;;;; +FA32;CJK COMPATIBILITY IDEOGRAPH-FA32;Lo;0;L;514D;;;;N;;;;; +FA33;CJK COMPATIBILITY IDEOGRAPH-FA33;Lo;0;L;52C9;;;;N;;;;; +FA34;CJK COMPATIBILITY IDEOGRAPH-FA34;Lo;0;L;52E4;;;;N;;;;; +FA35;CJK COMPATIBILITY IDEOGRAPH-FA35;Lo;0;L;5351;;;;N;;;;; +FA36;CJK COMPATIBILITY IDEOGRAPH-FA36;Lo;0;L;559D;;;;N;;;;; +FA37;CJK COMPATIBILITY IDEOGRAPH-FA37;Lo;0;L;5606;;;;N;;;;; +FA38;CJK COMPATIBILITY IDEOGRAPH-FA38;Lo;0;L;5668;;;;N;;;;; +FA39;CJK COMPATIBILITY IDEOGRAPH-FA39;Lo;0;L;5840;;;;N;;;;; +FA3A;CJK COMPATIBILITY IDEOGRAPH-FA3A;Lo;0;L;58A8;;;;N;;;;; +FA3B;CJK COMPATIBILITY IDEOGRAPH-FA3B;Lo;0;L;5C64;;;;N;;;;; +FA3C;CJK COMPATIBILITY IDEOGRAPH-FA3C;Lo;0;L;5C6E;;;;N;;;;; +FA3D;CJK COMPATIBILITY IDEOGRAPH-FA3D;Lo;0;L;6094;;;;N;;;;; +FA3E;CJK COMPATIBILITY IDEOGRAPH-FA3E;Lo;0;L;6168;;;;N;;;;; +FA3F;CJK COMPATIBILITY IDEOGRAPH-FA3F;Lo;0;L;618E;;;;N;;;;; +FA40;CJK COMPATIBILITY IDEOGRAPH-FA40;Lo;0;L;61F2;;;;N;;;;; +FA41;CJK COMPATIBILITY IDEOGRAPH-FA41;Lo;0;L;654F;;;;N;;;;; +FA42;CJK COMPATIBILITY IDEOGRAPH-FA42;Lo;0;L;65E2;;;;N;;;;; +FA43;CJK COMPATIBILITY IDEOGRAPH-FA43;Lo;0;L;6691;;;;N;;;;; +FA44;CJK COMPATIBILITY IDEOGRAPH-FA44;Lo;0;L;6885;;;;N;;;;; +FA45;CJK COMPATIBILITY IDEOGRAPH-FA45;Lo;0;L;6D77;;;;N;;;;; +FA46;CJK COMPATIBILITY IDEOGRAPH-FA46;Lo;0;L;6E1A;;;;N;;;;; +FA47;CJK COMPATIBILITY IDEOGRAPH-FA47;Lo;0;L;6F22;;;;N;;;;; +FA48;CJK COMPATIBILITY IDEOGRAPH-FA48;Lo;0;L;716E;;;;N;;;;; +FA49;CJK COMPATIBILITY IDEOGRAPH-FA49;Lo;0;L;722B;;;;N;;;;; +FA4A;CJK COMPATIBILITY IDEOGRAPH-FA4A;Lo;0;L;7422;;;;N;;;;; +FA4B;CJK COMPATIBILITY IDEOGRAPH-FA4B;Lo;0;L;7891;;;;N;;;;; +FA4C;CJK COMPATIBILITY IDEOGRAPH-FA4C;Lo;0;L;793E;;;;N;;;;; +FA4D;CJK COMPATIBILITY IDEOGRAPH-FA4D;Lo;0;L;7949;;;;N;;;;; +FA4E;CJK COMPATIBILITY IDEOGRAPH-FA4E;Lo;0;L;7948;;;;N;;;;; +FA4F;CJK COMPATIBILITY IDEOGRAPH-FA4F;Lo;0;L;7950;;;;N;;;;; +FA50;CJK COMPATIBILITY IDEOGRAPH-FA50;Lo;0;L;7956;;;;N;;;;; +FA51;CJK COMPATIBILITY IDEOGRAPH-FA51;Lo;0;L;795D;;;;N;;;;; +FA52;CJK COMPATIBILITY IDEOGRAPH-FA52;Lo;0;L;798D;;;;N;;;;; +FA53;CJK COMPATIBILITY IDEOGRAPH-FA53;Lo;0;L;798E;;;;N;;;;; +FA54;CJK COMPATIBILITY IDEOGRAPH-FA54;Lo;0;L;7A40;;;;N;;;;; +FA55;CJK COMPATIBILITY IDEOGRAPH-FA55;Lo;0;L;7A81;;;;N;;;;; +FA56;CJK COMPATIBILITY IDEOGRAPH-FA56;Lo;0;L;7BC0;;;;N;;;;; +FA57;CJK COMPATIBILITY IDEOGRAPH-FA57;Lo;0;L;7DF4;;;;N;;;;; +FA58;CJK COMPATIBILITY IDEOGRAPH-FA58;Lo;0;L;7E09;;;;N;;;;; +FA59;CJK COMPATIBILITY IDEOGRAPH-FA59;Lo;0;L;7E41;;;;N;;;;; +FA5A;CJK COMPATIBILITY IDEOGRAPH-FA5A;Lo;0;L;7F72;;;;N;;;;; +FA5B;CJK COMPATIBILITY IDEOGRAPH-FA5B;Lo;0;L;8005;;;;N;;;;; +FA5C;CJK COMPATIBILITY IDEOGRAPH-FA5C;Lo;0;L;81ED;;;;N;;;;; +FA5D;CJK COMPATIBILITY IDEOGRAPH-FA5D;Lo;0;L;8279;;;;N;;;;; +FA5E;CJK COMPATIBILITY IDEOGRAPH-FA5E;Lo;0;L;8279;;;;N;;;;; +FA5F;CJK COMPATIBILITY IDEOGRAPH-FA5F;Lo;0;L;8457;;;;N;;;;; +FA60;CJK COMPATIBILITY IDEOGRAPH-FA60;Lo;0;L;8910;;;;N;;;;; +FA61;CJK COMPATIBILITY IDEOGRAPH-FA61;Lo;0;L;8996;;;;N;;;;; +FA62;CJK COMPATIBILITY IDEOGRAPH-FA62;Lo;0;L;8B01;;;;N;;;;; +FA63;CJK COMPATIBILITY IDEOGRAPH-FA63;Lo;0;L;8B39;;;;N;;;;; +FA64;CJK COMPATIBILITY IDEOGRAPH-FA64;Lo;0;L;8CD3;;;;N;;;;; +FA65;CJK COMPATIBILITY IDEOGRAPH-FA65;Lo;0;L;8D08;;;;N;;;;; +FA66;CJK COMPATIBILITY IDEOGRAPH-FA66;Lo;0;L;8FB6;;;;N;;;;; +FA67;CJK COMPATIBILITY IDEOGRAPH-FA67;Lo;0;L;9038;;;;N;;;;; +FA68;CJK COMPATIBILITY IDEOGRAPH-FA68;Lo;0;L;96E3;;;;N;;;;; +FA69;CJK COMPATIBILITY IDEOGRAPH-FA69;Lo;0;L;97FF;;;;N;;;;; +FA6A;CJK COMPATIBILITY IDEOGRAPH-FA6A;Lo;0;L;983B;;;;N;;;;; +FA6B;CJK COMPATIBILITY IDEOGRAPH-FA6B;Lo;0;L;6075;;;;N;;;;; +FA6C;CJK COMPATIBILITY IDEOGRAPH-FA6C;Lo;0;L;242EE;;;;N;;;;; +FA6D;CJK COMPATIBILITY IDEOGRAPH-FA6D;Lo;0;L;8218;;;;N;;;;; +FA70;CJK COMPATIBILITY IDEOGRAPH-FA70;Lo;0;L;4E26;;;;N;;;;; +FA71;CJK COMPATIBILITY IDEOGRAPH-FA71;Lo;0;L;51B5;;;;N;;;;; +FA72;CJK COMPATIBILITY IDEOGRAPH-FA72;Lo;0;L;5168;;;;N;;;;; +FA73;CJK COMPATIBILITY IDEOGRAPH-FA73;Lo;0;L;4F80;;;;N;;;;; +FA74;CJK COMPATIBILITY IDEOGRAPH-FA74;Lo;0;L;5145;;;;N;;;;; +FA75;CJK COMPATIBILITY IDEOGRAPH-FA75;Lo;0;L;5180;;;;N;;;;; +FA76;CJK COMPATIBILITY IDEOGRAPH-FA76;Lo;0;L;52C7;;;;N;;;;; +FA77;CJK COMPATIBILITY IDEOGRAPH-FA77;Lo;0;L;52FA;;;;N;;;;; +FA78;CJK COMPATIBILITY IDEOGRAPH-FA78;Lo;0;L;559D;;;;N;;;;; +FA79;CJK COMPATIBILITY IDEOGRAPH-FA79;Lo;0;L;5555;;;;N;;;;; +FA7A;CJK COMPATIBILITY IDEOGRAPH-FA7A;Lo;0;L;5599;;;;N;;;;; +FA7B;CJK COMPATIBILITY IDEOGRAPH-FA7B;Lo;0;L;55E2;;;;N;;;;; +FA7C;CJK COMPATIBILITY IDEOGRAPH-FA7C;Lo;0;L;585A;;;;N;;;;; +FA7D;CJK COMPATIBILITY IDEOGRAPH-FA7D;Lo;0;L;58B3;;;;N;;;;; +FA7E;CJK COMPATIBILITY IDEOGRAPH-FA7E;Lo;0;L;5944;;;;N;;;;; +FA7F;CJK COMPATIBILITY IDEOGRAPH-FA7F;Lo;0;L;5954;;;;N;;;;; +FA80;CJK COMPATIBILITY IDEOGRAPH-FA80;Lo;0;L;5A62;;;;N;;;;; +FA81;CJK COMPATIBILITY IDEOGRAPH-FA81;Lo;0;L;5B28;;;;N;;;;; +FA82;CJK COMPATIBILITY IDEOGRAPH-FA82;Lo;0;L;5ED2;;;;N;;;;; +FA83;CJK COMPATIBILITY IDEOGRAPH-FA83;Lo;0;L;5ED9;;;;N;;;;; +FA84;CJK COMPATIBILITY IDEOGRAPH-FA84;Lo;0;L;5F69;;;;N;;;;; +FA85;CJK COMPATIBILITY IDEOGRAPH-FA85;Lo;0;L;5FAD;;;;N;;;;; +FA86;CJK COMPATIBILITY IDEOGRAPH-FA86;Lo;0;L;60D8;;;;N;;;;; +FA87;CJK COMPATIBILITY IDEOGRAPH-FA87;Lo;0;L;614E;;;;N;;;;; +FA88;CJK COMPATIBILITY IDEOGRAPH-FA88;Lo;0;L;6108;;;;N;;;;; +FA89;CJK COMPATIBILITY IDEOGRAPH-FA89;Lo;0;L;618E;;;;N;;;;; +FA8A;CJK COMPATIBILITY IDEOGRAPH-FA8A;Lo;0;L;6160;;;;N;;;;; +FA8B;CJK COMPATIBILITY IDEOGRAPH-FA8B;Lo;0;L;61F2;;;;N;;;;; +FA8C;CJK COMPATIBILITY IDEOGRAPH-FA8C;Lo;0;L;6234;;;;N;;;;; +FA8D;CJK COMPATIBILITY IDEOGRAPH-FA8D;Lo;0;L;63C4;;;;N;;;;; +FA8E;CJK COMPATIBILITY IDEOGRAPH-FA8E;Lo;0;L;641C;;;;N;;;;; +FA8F;CJK COMPATIBILITY IDEOGRAPH-FA8F;Lo;0;L;6452;;;;N;;;;; +FA90;CJK COMPATIBILITY IDEOGRAPH-FA90;Lo;0;L;6556;;;;N;;;;; +FA91;CJK COMPATIBILITY IDEOGRAPH-FA91;Lo;0;L;6674;;;;N;;;;; +FA92;CJK COMPATIBILITY IDEOGRAPH-FA92;Lo;0;L;6717;;;;N;;;;; +FA93;CJK COMPATIBILITY IDEOGRAPH-FA93;Lo;0;L;671B;;;;N;;;;; +FA94;CJK COMPATIBILITY IDEOGRAPH-FA94;Lo;0;L;6756;;;;N;;;;; +FA95;CJK COMPATIBILITY IDEOGRAPH-FA95;Lo;0;L;6B79;;;;N;;;;; +FA96;CJK COMPATIBILITY IDEOGRAPH-FA96;Lo;0;L;6BBA;;;;N;;;;; +FA97;CJK COMPATIBILITY IDEOGRAPH-FA97;Lo;0;L;6D41;;;;N;;;;; +FA98;CJK COMPATIBILITY IDEOGRAPH-FA98;Lo;0;L;6EDB;;;;N;;;;; +FA99;CJK COMPATIBILITY IDEOGRAPH-FA99;Lo;0;L;6ECB;;;;N;;;;; +FA9A;CJK COMPATIBILITY IDEOGRAPH-FA9A;Lo;0;L;6F22;;;;N;;;;; +FA9B;CJK COMPATIBILITY IDEOGRAPH-FA9B;Lo;0;L;701E;;;;N;;;;; +FA9C;CJK COMPATIBILITY IDEOGRAPH-FA9C;Lo;0;L;716E;;;;N;;;;; +FA9D;CJK COMPATIBILITY IDEOGRAPH-FA9D;Lo;0;L;77A7;;;;N;;;;; +FA9E;CJK COMPATIBILITY IDEOGRAPH-FA9E;Lo;0;L;7235;;;;N;;;;; +FA9F;CJK COMPATIBILITY IDEOGRAPH-FA9F;Lo;0;L;72AF;;;;N;;;;; +FAA0;CJK COMPATIBILITY IDEOGRAPH-FAA0;Lo;0;L;732A;;;;N;;;;; +FAA1;CJK COMPATIBILITY IDEOGRAPH-FAA1;Lo;0;L;7471;;;;N;;;;; +FAA2;CJK COMPATIBILITY IDEOGRAPH-FAA2;Lo;0;L;7506;;;;N;;;;; +FAA3;CJK COMPATIBILITY IDEOGRAPH-FAA3;Lo;0;L;753B;;;;N;;;;; +FAA4;CJK COMPATIBILITY IDEOGRAPH-FAA4;Lo;0;L;761D;;;;N;;;;; +FAA5;CJK COMPATIBILITY IDEOGRAPH-FAA5;Lo;0;L;761F;;;;N;;;;; +FAA6;CJK COMPATIBILITY IDEOGRAPH-FAA6;Lo;0;L;76CA;;;;N;;;;; +FAA7;CJK COMPATIBILITY IDEOGRAPH-FAA7;Lo;0;L;76DB;;;;N;;;;; +FAA8;CJK COMPATIBILITY IDEOGRAPH-FAA8;Lo;0;L;76F4;;;;N;;;;; +FAA9;CJK COMPATIBILITY IDEOGRAPH-FAA9;Lo;0;L;774A;;;;N;;;;; +FAAA;CJK COMPATIBILITY IDEOGRAPH-FAAA;Lo;0;L;7740;;;;N;;;;; +FAAB;CJK COMPATIBILITY IDEOGRAPH-FAAB;Lo;0;L;78CC;;;;N;;;;; +FAAC;CJK COMPATIBILITY IDEOGRAPH-FAAC;Lo;0;L;7AB1;;;;N;;;;; +FAAD;CJK COMPATIBILITY IDEOGRAPH-FAAD;Lo;0;L;7BC0;;;;N;;;;; +FAAE;CJK COMPATIBILITY IDEOGRAPH-FAAE;Lo;0;L;7C7B;;;;N;;;;; +FAAF;CJK COMPATIBILITY IDEOGRAPH-FAAF;Lo;0;L;7D5B;;;;N;;;;; +FAB0;CJK COMPATIBILITY IDEOGRAPH-FAB0;Lo;0;L;7DF4;;;;N;;;;; +FAB1;CJK COMPATIBILITY IDEOGRAPH-FAB1;Lo;0;L;7F3E;;;;N;;;;; +FAB2;CJK COMPATIBILITY IDEOGRAPH-FAB2;Lo;0;L;8005;;;;N;;;;; +FAB3;CJK COMPATIBILITY IDEOGRAPH-FAB3;Lo;0;L;8352;;;;N;;;;; +FAB4;CJK COMPATIBILITY IDEOGRAPH-FAB4;Lo;0;L;83EF;;;;N;;;;; +FAB5;CJK COMPATIBILITY IDEOGRAPH-FAB5;Lo;0;L;8779;;;;N;;;;; +FAB6;CJK COMPATIBILITY IDEOGRAPH-FAB6;Lo;0;L;8941;;;;N;;;;; +FAB7;CJK COMPATIBILITY IDEOGRAPH-FAB7;Lo;0;L;8986;;;;N;;;;; +FAB8;CJK COMPATIBILITY IDEOGRAPH-FAB8;Lo;0;L;8996;;;;N;;;;; +FAB9;CJK COMPATIBILITY IDEOGRAPH-FAB9;Lo;0;L;8ABF;;;;N;;;;; +FABA;CJK COMPATIBILITY IDEOGRAPH-FABA;Lo;0;L;8AF8;;;;N;;;;; +FABB;CJK COMPATIBILITY IDEOGRAPH-FABB;Lo;0;L;8ACB;;;;N;;;;; +FABC;CJK COMPATIBILITY IDEOGRAPH-FABC;Lo;0;L;8B01;;;;N;;;;; +FABD;CJK COMPATIBILITY IDEOGRAPH-FABD;Lo;0;L;8AFE;;;;N;;;;; +FABE;CJK COMPATIBILITY IDEOGRAPH-FABE;Lo;0;L;8AED;;;;N;;;;; +FABF;CJK COMPATIBILITY IDEOGRAPH-FABF;Lo;0;L;8B39;;;;N;;;;; +FAC0;CJK COMPATIBILITY IDEOGRAPH-FAC0;Lo;0;L;8B8A;;;;N;;;;; +FAC1;CJK COMPATIBILITY IDEOGRAPH-FAC1;Lo;0;L;8D08;;;;N;;;;; +FAC2;CJK COMPATIBILITY IDEOGRAPH-FAC2;Lo;0;L;8F38;;;;N;;;;; +FAC3;CJK COMPATIBILITY IDEOGRAPH-FAC3;Lo;0;L;9072;;;;N;;;;; +FAC4;CJK COMPATIBILITY IDEOGRAPH-FAC4;Lo;0;L;9199;;;;N;;;;; +FAC5;CJK COMPATIBILITY IDEOGRAPH-FAC5;Lo;0;L;9276;;;;N;;;;; +FAC6;CJK COMPATIBILITY IDEOGRAPH-FAC6;Lo;0;L;967C;;;;N;;;;; +FAC7;CJK COMPATIBILITY IDEOGRAPH-FAC7;Lo;0;L;96E3;;;;N;;;;; +FAC8;CJK COMPATIBILITY IDEOGRAPH-FAC8;Lo;0;L;9756;;;;N;;;;; +FAC9;CJK COMPATIBILITY IDEOGRAPH-FAC9;Lo;0;L;97DB;;;;N;;;;; +FACA;CJK COMPATIBILITY IDEOGRAPH-FACA;Lo;0;L;97FF;;;;N;;;;; +FACB;CJK COMPATIBILITY IDEOGRAPH-FACB;Lo;0;L;980B;;;;N;;;;; +FACC;CJK COMPATIBILITY IDEOGRAPH-FACC;Lo;0;L;983B;;;;N;;;;; +FACD;CJK COMPATIBILITY IDEOGRAPH-FACD;Lo;0;L;9B12;;;;N;;;;; +FACE;CJK COMPATIBILITY IDEOGRAPH-FACE;Lo;0;L;9F9C;;;;N;;;;; +FACF;CJK COMPATIBILITY IDEOGRAPH-FACF;Lo;0;L;2284A;;;;N;;;;; +FAD0;CJK COMPATIBILITY IDEOGRAPH-FAD0;Lo;0;L;22844;;;;N;;;;; +FAD1;CJK COMPATIBILITY IDEOGRAPH-FAD1;Lo;0;L;233D5;;;;N;;;;; +FAD2;CJK COMPATIBILITY IDEOGRAPH-FAD2;Lo;0;L;3B9D;;;;N;;;;; +FAD3;CJK COMPATIBILITY IDEOGRAPH-FAD3;Lo;0;L;4018;;;;N;;;;; +FAD4;CJK COMPATIBILITY IDEOGRAPH-FAD4;Lo;0;L;4039;;;;N;;;;; +FAD5;CJK COMPATIBILITY IDEOGRAPH-FAD5;Lo;0;L;25249;;;;N;;;;; +FAD6;CJK COMPATIBILITY IDEOGRAPH-FAD6;Lo;0;L;25CD0;;;;N;;;;; +FAD7;CJK COMPATIBILITY IDEOGRAPH-FAD7;Lo;0;L;27ED3;;;;N;;;;; +FAD8;CJK COMPATIBILITY IDEOGRAPH-FAD8;Lo;0;L;9F43;;;;N;;;;; +FAD9;CJK COMPATIBILITY IDEOGRAPH-FAD9;Lo;0;L;9F8E;;;;N;;;;; +FB00;LATIN SMALL LIGATURE FF;Ll;0;L; 0066 0066;;;;N;;;;; +FB01;LATIN SMALL LIGATURE FI;Ll;0;L; 0066 0069;;;;N;;;;; +FB02;LATIN SMALL LIGATURE FL;Ll;0;L; 0066 006C;;;;N;;;;; +FB03;LATIN SMALL LIGATURE FFI;Ll;0;L; 0066 0066 0069;;;;N;;;;; +FB04;LATIN SMALL LIGATURE FFL;Ll;0;L; 0066 0066 006C;;;;N;;;;; +FB05;LATIN SMALL LIGATURE LONG S T;Ll;0;L; 017F 0074;;;;N;;;;; +FB06;LATIN SMALL LIGATURE ST;Ll;0;L; 0073 0074;;;;N;;;;; +FB13;ARMENIAN SMALL LIGATURE MEN NOW;Ll;0;L; 0574 0576;;;;N;;;;; +FB14;ARMENIAN SMALL LIGATURE MEN ECH;Ll;0;L; 0574 0565;;;;N;;;;; +FB15;ARMENIAN SMALL LIGATURE MEN INI;Ll;0;L; 0574 056B;;;;N;;;;; +FB16;ARMENIAN SMALL LIGATURE VEW NOW;Ll;0;L; 057E 0576;;;;N;;;;; +FB17;ARMENIAN SMALL LIGATURE MEN XEH;Ll;0;L; 0574 056D;;;;N;;;;; +FB1D;HEBREW LETTER YOD WITH HIRIQ;Lo;0;R;05D9 05B4;;;;N;;;;; +FB1E;HEBREW POINT JUDEO-SPANISH VARIKA;Mn;26;NSM;;;;;N;HEBREW POINT VARIKA;;;; +FB1F;HEBREW LIGATURE YIDDISH YOD YOD PATAH;Lo;0;R;05F2 05B7;;;;N;;;;; +FB20;HEBREW LETTER ALTERNATIVE AYIN;Lo;0;R; 05E2;;;;N;;;;; +FB21;HEBREW LETTER WIDE ALEF;Lo;0;R; 05D0;;;;N;;;;; +FB22;HEBREW LETTER WIDE DALET;Lo;0;R; 05D3;;;;N;;;;; +FB23;HEBREW LETTER WIDE HE;Lo;0;R; 05D4;;;;N;;;;; +FB24;HEBREW LETTER WIDE KAF;Lo;0;R; 05DB;;;;N;;;;; +FB25;HEBREW LETTER WIDE LAMED;Lo;0;R; 05DC;;;;N;;;;; +FB26;HEBREW LETTER WIDE FINAL MEM;Lo;0;R; 05DD;;;;N;;;;; +FB27;HEBREW LETTER WIDE RESH;Lo;0;R; 05E8;;;;N;;;;; +FB28;HEBREW LETTER WIDE TAV;Lo;0;R; 05EA;;;;N;;;;; +FB29;HEBREW LETTER ALTERNATIVE PLUS SIGN;Sm;0;ES; 002B;;;;N;;;;; +FB2A;HEBREW LETTER SHIN WITH SHIN DOT;Lo;0;R;05E9 05C1;;;;N;;;;; +FB2B;HEBREW LETTER SHIN WITH SIN DOT;Lo;0;R;05E9 05C2;;;;N;;;;; +FB2C;HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT;Lo;0;R;FB49 05C1;;;;N;;;;; +FB2D;HEBREW LETTER SHIN WITH DAGESH AND SIN DOT;Lo;0;R;FB49 05C2;;;;N;;;;; +FB2E;HEBREW LETTER ALEF WITH PATAH;Lo;0;R;05D0 05B7;;;;N;;;;; +FB2F;HEBREW LETTER ALEF WITH QAMATS;Lo;0;R;05D0 05B8;;;;N;;;;; +FB30;HEBREW LETTER ALEF WITH MAPIQ;Lo;0;R;05D0 05BC;;;;N;;;;; +FB31;HEBREW LETTER BET WITH DAGESH;Lo;0;R;05D1 05BC;;;;N;;;;; +FB32;HEBREW LETTER GIMEL WITH DAGESH;Lo;0;R;05D2 05BC;;;;N;;;;; +FB33;HEBREW LETTER DALET WITH DAGESH;Lo;0;R;05D3 05BC;;;;N;;;;; +FB34;HEBREW LETTER HE WITH MAPIQ;Lo;0;R;05D4 05BC;;;;N;;;;; +FB35;HEBREW LETTER VAV WITH DAGESH;Lo;0;R;05D5 05BC;;;;N;;;;; +FB36;HEBREW LETTER ZAYIN WITH DAGESH;Lo;0;R;05D6 05BC;;;;N;;;;; +FB38;HEBREW LETTER TET WITH DAGESH;Lo;0;R;05D8 05BC;;;;N;;;;; +FB39;HEBREW LETTER YOD WITH DAGESH;Lo;0;R;05D9 05BC;;;;N;;;;; +FB3A;HEBREW LETTER FINAL KAF WITH DAGESH;Lo;0;R;05DA 05BC;;;;N;;;;; +FB3B;HEBREW LETTER KAF WITH DAGESH;Lo;0;R;05DB 05BC;;;;N;;;;; +FB3C;HEBREW LETTER LAMED WITH DAGESH;Lo;0;R;05DC 05BC;;;;N;;;;; +FB3E;HEBREW LETTER MEM WITH DAGESH;Lo;0;R;05DE 05BC;;;;N;;;;; +FB40;HEBREW LETTER NUN WITH DAGESH;Lo;0;R;05E0 05BC;;;;N;;;;; +FB41;HEBREW LETTER SAMEKH WITH DAGESH;Lo;0;R;05E1 05BC;;;;N;;;;; +FB43;HEBREW LETTER FINAL PE WITH DAGESH;Lo;0;R;05E3 05BC;;;;N;;;;; +FB44;HEBREW LETTER PE WITH DAGESH;Lo;0;R;05E4 05BC;;;;N;;;;; +FB46;HEBREW LETTER TSADI WITH DAGESH;Lo;0;R;05E6 05BC;;;;N;;;;; +FB47;HEBREW LETTER QOF WITH DAGESH;Lo;0;R;05E7 05BC;;;;N;;;;; +FB48;HEBREW LETTER RESH WITH DAGESH;Lo;0;R;05E8 05BC;;;;N;;;;; +FB49;HEBREW LETTER SHIN WITH DAGESH;Lo;0;R;05E9 05BC;;;;N;;;;; +FB4A;HEBREW LETTER TAV WITH DAGESH;Lo;0;R;05EA 05BC;;;;N;;;;; +FB4B;HEBREW LETTER VAV WITH HOLAM;Lo;0;R;05D5 05B9;;;;N;;;;; +FB4C;HEBREW LETTER BET WITH RAFE;Lo;0;R;05D1 05BF;;;;N;;;;; +FB4D;HEBREW LETTER KAF WITH RAFE;Lo;0;R;05DB 05BF;;;;N;;;;; +FB4E;HEBREW LETTER PE WITH RAFE;Lo;0;R;05E4 05BF;;;;N;;;;; +FB4F;HEBREW LIGATURE ALEF LAMED;Lo;0;R; 05D0 05DC;;;;N;;;;; +FB50;ARABIC LETTER ALEF WASLA ISOLATED FORM;Lo;0;AL; 0671;;;;N;;;;; +FB51;ARABIC LETTER ALEF WASLA FINAL FORM;Lo;0;AL; 0671;;;;N;;;;; +FB52;ARABIC LETTER BEEH ISOLATED FORM;Lo;0;AL; 067B;;;;N;;;;; +FB53;ARABIC LETTER BEEH FINAL FORM;Lo;0;AL; 067B;;;;N;;;;; +FB54;ARABIC LETTER BEEH INITIAL FORM;Lo;0;AL; 067B;;;;N;;;;; +FB55;ARABIC LETTER BEEH MEDIAL FORM;Lo;0;AL; 067B;;;;N;;;;; +FB56;ARABIC LETTER PEH ISOLATED FORM;Lo;0;AL; 067E;;;;N;;;;; +FB57;ARABIC LETTER PEH FINAL FORM;Lo;0;AL; 067E;;;;N;;;;; +FB58;ARABIC LETTER PEH INITIAL FORM;Lo;0;AL; 067E;;;;N;;;;; +FB59;ARABIC LETTER PEH MEDIAL FORM;Lo;0;AL; 067E;;;;N;;;;; +FB5A;ARABIC LETTER BEHEH ISOLATED FORM;Lo;0;AL; 0680;;;;N;;;;; +FB5B;ARABIC LETTER BEHEH FINAL FORM;Lo;0;AL; 0680;;;;N;;;;; +FB5C;ARABIC LETTER BEHEH INITIAL FORM;Lo;0;AL; 0680;;;;N;;;;; +FB5D;ARABIC LETTER BEHEH MEDIAL FORM;Lo;0;AL; 0680;;;;N;;;;; +FB5E;ARABIC LETTER TTEHEH ISOLATED FORM;Lo;0;AL; 067A;;;;N;;;;; +FB5F;ARABIC LETTER TTEHEH FINAL FORM;Lo;0;AL; 067A;;;;N;;;;; +FB60;ARABIC LETTER TTEHEH INITIAL FORM;Lo;0;AL; 067A;;;;N;;;;; +FB61;ARABIC LETTER TTEHEH MEDIAL FORM;Lo;0;AL; 067A;;;;N;;;;; +FB62;ARABIC LETTER TEHEH ISOLATED FORM;Lo;0;AL; 067F;;;;N;;;;; +FB63;ARABIC LETTER TEHEH FINAL FORM;Lo;0;AL; 067F;;;;N;;;;; +FB64;ARABIC LETTER TEHEH INITIAL FORM;Lo;0;AL; 067F;;;;N;;;;; +FB65;ARABIC LETTER TEHEH MEDIAL FORM;Lo;0;AL; 067F;;;;N;;;;; +FB66;ARABIC LETTER TTEH ISOLATED FORM;Lo;0;AL; 0679;;;;N;;;;; +FB67;ARABIC LETTER TTEH FINAL FORM;Lo;0;AL; 0679;;;;N;;;;; +FB68;ARABIC LETTER TTEH INITIAL FORM;Lo;0;AL; 0679;;;;N;;;;; +FB69;ARABIC LETTER TTEH MEDIAL FORM;Lo;0;AL; 0679;;;;N;;;;; +FB6A;ARABIC LETTER VEH ISOLATED FORM;Lo;0;AL; 06A4;;;;N;;;;; +FB6B;ARABIC LETTER VEH FINAL FORM;Lo;0;AL; 06A4;;;;N;;;;; +FB6C;ARABIC LETTER VEH INITIAL FORM;Lo;0;AL; 06A4;;;;N;;;;; +FB6D;ARABIC LETTER VEH MEDIAL FORM;Lo;0;AL; 06A4;;;;N;;;;; +FB6E;ARABIC LETTER PEHEH ISOLATED FORM;Lo;0;AL; 06A6;;;;N;;;;; +FB6F;ARABIC LETTER PEHEH FINAL FORM;Lo;0;AL; 06A6;;;;N;;;;; +FB70;ARABIC LETTER PEHEH INITIAL FORM;Lo;0;AL; 06A6;;;;N;;;;; +FB71;ARABIC LETTER PEHEH MEDIAL FORM;Lo;0;AL; 06A6;;;;N;;;;; +FB72;ARABIC LETTER DYEH ISOLATED FORM;Lo;0;AL; 0684;;;;N;;;;; +FB73;ARABIC LETTER DYEH FINAL FORM;Lo;0;AL; 0684;;;;N;;;;; +FB74;ARABIC LETTER DYEH INITIAL FORM;Lo;0;AL; 0684;;;;N;;;;; +FB75;ARABIC LETTER DYEH MEDIAL FORM;Lo;0;AL; 0684;;;;N;;;;; +FB76;ARABIC LETTER NYEH ISOLATED FORM;Lo;0;AL; 0683;;;;N;;;;; +FB77;ARABIC LETTER NYEH FINAL FORM;Lo;0;AL; 0683;;;;N;;;;; +FB78;ARABIC LETTER NYEH INITIAL FORM;Lo;0;AL; 0683;;;;N;;;;; +FB79;ARABIC LETTER NYEH MEDIAL FORM;Lo;0;AL; 0683;;;;N;;;;; +FB7A;ARABIC LETTER TCHEH ISOLATED FORM;Lo;0;AL; 0686;;;;N;;;;; +FB7B;ARABIC LETTER TCHEH FINAL FORM;Lo;0;AL; 0686;;;;N;;;;; +FB7C;ARABIC LETTER TCHEH INITIAL FORM;Lo;0;AL; 0686;;;;N;;;;; +FB7D;ARABIC LETTER TCHEH MEDIAL FORM;Lo;0;AL; 0686;;;;N;;;;; +FB7E;ARABIC LETTER TCHEHEH ISOLATED FORM;Lo;0;AL; 0687;;;;N;;;;; +FB7F;ARABIC LETTER TCHEHEH FINAL FORM;Lo;0;AL; 0687;;;;N;;;;; +FB80;ARABIC LETTER TCHEHEH INITIAL FORM;Lo;0;AL; 0687;;;;N;;;;; +FB81;ARABIC LETTER TCHEHEH MEDIAL FORM;Lo;0;AL; 0687;;;;N;;;;; +FB82;ARABIC LETTER DDAHAL ISOLATED FORM;Lo;0;AL; 068D;;;;N;;;;; +FB83;ARABIC LETTER DDAHAL FINAL FORM;Lo;0;AL; 068D;;;;N;;;;; +FB84;ARABIC LETTER DAHAL ISOLATED FORM;Lo;0;AL; 068C;;;;N;;;;; +FB85;ARABIC LETTER DAHAL FINAL FORM;Lo;0;AL; 068C;;;;N;;;;; +FB86;ARABIC LETTER DUL ISOLATED FORM;Lo;0;AL; 068E;;;;N;;;;; +FB87;ARABIC LETTER DUL FINAL FORM;Lo;0;AL; 068E;;;;N;;;;; +FB88;ARABIC LETTER DDAL ISOLATED FORM;Lo;0;AL; 0688;;;;N;;;;; +FB89;ARABIC LETTER DDAL FINAL FORM;Lo;0;AL; 0688;;;;N;;;;; +FB8A;ARABIC LETTER JEH ISOLATED FORM;Lo;0;AL; 0698;;;;N;;;;; +FB8B;ARABIC LETTER JEH FINAL FORM;Lo;0;AL; 0698;;;;N;;;;; +FB8C;ARABIC LETTER RREH ISOLATED FORM;Lo;0;AL; 0691;;;;N;;;;; +FB8D;ARABIC LETTER RREH FINAL FORM;Lo;0;AL; 0691;;;;N;;;;; +FB8E;ARABIC LETTER KEHEH ISOLATED FORM;Lo;0;AL; 06A9;;;;N;;;;; +FB8F;ARABIC LETTER KEHEH FINAL FORM;Lo;0;AL; 06A9;;;;N;;;;; +FB90;ARABIC LETTER KEHEH INITIAL FORM;Lo;0;AL; 06A9;;;;N;;;;; +FB91;ARABIC LETTER KEHEH MEDIAL FORM;Lo;0;AL; 06A9;;;;N;;;;; +FB92;ARABIC LETTER GAF ISOLATED FORM;Lo;0;AL; 06AF;;;;N;;;;; +FB93;ARABIC LETTER GAF FINAL FORM;Lo;0;AL; 06AF;;;;N;;;;; +FB94;ARABIC LETTER GAF INITIAL FORM;Lo;0;AL; 06AF;;;;N;;;;; +FB95;ARABIC LETTER GAF MEDIAL FORM;Lo;0;AL; 06AF;;;;N;;;;; +FB96;ARABIC LETTER GUEH ISOLATED FORM;Lo;0;AL; 06B3;;;;N;;;;; +FB97;ARABIC LETTER GUEH FINAL FORM;Lo;0;AL; 06B3;;;;N;;;;; +FB98;ARABIC LETTER GUEH INITIAL FORM;Lo;0;AL; 06B3;;;;N;;;;; +FB99;ARABIC LETTER GUEH MEDIAL FORM;Lo;0;AL; 06B3;;;;N;;;;; +FB9A;ARABIC LETTER NGOEH ISOLATED FORM;Lo;0;AL; 06B1;;;;N;;;;; +FB9B;ARABIC LETTER NGOEH FINAL FORM;Lo;0;AL; 06B1;;;;N;;;;; +FB9C;ARABIC LETTER NGOEH INITIAL FORM;Lo;0;AL; 06B1;;;;N;;;;; +FB9D;ARABIC LETTER NGOEH MEDIAL FORM;Lo;0;AL; 06B1;;;;N;;;;; +FB9E;ARABIC LETTER NOON GHUNNA ISOLATED FORM;Lo;0;AL; 06BA;;;;N;;;;; +FB9F;ARABIC LETTER NOON GHUNNA FINAL FORM;Lo;0;AL; 06BA;;;;N;;;;; +FBA0;ARABIC LETTER RNOON ISOLATED FORM;Lo;0;AL; 06BB;;;;N;;;;; +FBA1;ARABIC LETTER RNOON FINAL FORM;Lo;0;AL; 06BB;;;;N;;;;; +FBA2;ARABIC LETTER RNOON INITIAL FORM;Lo;0;AL; 06BB;;;;N;;;;; +FBA3;ARABIC LETTER RNOON MEDIAL FORM;Lo;0;AL; 06BB;;;;N;;;;; +FBA4;ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM;Lo;0;AL; 06C0;;;;N;;;;; +FBA5;ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM;Lo;0;AL; 06C0;;;;N;;;;; +FBA6;ARABIC LETTER HEH GOAL ISOLATED FORM;Lo;0;AL; 06C1;;;;N;;;;; +FBA7;ARABIC LETTER HEH GOAL FINAL FORM;Lo;0;AL; 06C1;;;;N;;;;; +FBA8;ARABIC LETTER HEH GOAL INITIAL FORM;Lo;0;AL; 06C1;;;;N;;;;; +FBA9;ARABIC LETTER HEH GOAL MEDIAL FORM;Lo;0;AL; 06C1;;;;N;;;;; +FBAA;ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM;Lo;0;AL; 06BE;;;;N;;;;; +FBAB;ARABIC LETTER HEH DOACHASHMEE FINAL FORM;Lo;0;AL; 06BE;;;;N;;;;; +FBAC;ARABIC LETTER HEH DOACHASHMEE INITIAL FORM;Lo;0;AL; 06BE;;;;N;;;;; +FBAD;ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM;Lo;0;AL; 06BE;;;;N;;;;; +FBAE;ARABIC LETTER YEH BARREE ISOLATED FORM;Lo;0;AL; 06D2;;;;N;;;;; +FBAF;ARABIC LETTER YEH BARREE FINAL FORM;Lo;0;AL; 06D2;;;;N;;;;; +FBB0;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 06D3;;;;N;;;;; +FBB1;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM;Lo;0;AL; 06D3;;;;N;;;;; +FBB2;ARABIC SYMBOL DOT ABOVE;Sk;0;AL;;;;;N;;;;; +FBB3;ARABIC SYMBOL DOT BELOW;Sk;0;AL;;;;;N;;;;; +FBB4;ARABIC SYMBOL TWO DOTS ABOVE;Sk;0;AL;;;;;N;;;;; +FBB5;ARABIC SYMBOL TWO DOTS BELOW;Sk;0;AL;;;;;N;;;;; +FBB6;ARABIC SYMBOL THREE DOTS ABOVE;Sk;0;AL;;;;;N;;;;; +FBB7;ARABIC SYMBOL THREE DOTS BELOW;Sk;0;AL;;;;;N;;;;; +FBB8;ARABIC SYMBOL THREE DOTS POINTING DOWNWARDS ABOVE;Sk;0;AL;;;;;N;;;;; +FBB9;ARABIC SYMBOL THREE DOTS POINTING DOWNWARDS BELOW;Sk;0;AL;;;;;N;;;;; +FBBA;ARABIC SYMBOL FOUR DOTS ABOVE;Sk;0;AL;;;;;N;;;;; +FBBB;ARABIC SYMBOL FOUR DOTS BELOW;Sk;0;AL;;;;;N;;;;; +FBBC;ARABIC SYMBOL DOUBLE VERTICAL BAR BELOW;Sk;0;AL;;;;;N;;;;; +FBBD;ARABIC SYMBOL TWO DOTS VERTICALLY ABOVE;Sk;0;AL;;;;;N;;;;; +FBBE;ARABIC SYMBOL TWO DOTS VERTICALLY BELOW;Sk;0;AL;;;;;N;;;;; +FBBF;ARABIC SYMBOL RING;Sk;0;AL;;;;;N;;;;; +FBC0;ARABIC SYMBOL SMALL TAH ABOVE;Sk;0;AL;;;;;N;;;;; +FBC1;ARABIC SYMBOL SMALL TAH BELOW;Sk;0;AL;;;;;N;;;;; +FBC2;ARABIC SYMBOL WASLA ABOVE;Sk;0;AL;;;;;N;;;;; +FBC3;ARABIC LIGATURE JALLA WA-ALAA;So;0;ON;;;;;N;;;;; +FBC4;ARABIC LIGATURE DAAMAT BARAKAATUHUM;So;0;ON;;;;;N;;;;; +FBC5;ARABIC LIGATURE RAHMATU ALLAAHI TAAALAA ALAYH;So;0;ON;;;;;N;;;;; +FBC6;ARABIC LIGATURE RAHMATU ALLAAHI ALAYHIM;So;0;ON;;;;;N;;;;; +FBC7;ARABIC LIGATURE RAHMATU ALLAAHI ALAYHIMAA;So;0;ON;;;;;N;;;;; +FBC8;ARABIC LIGATURE RAHIMAHUM ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;; +FBC9;ARABIC LIGATURE RAHIMAHUMAA ALLAAH;So;0;ON;;;;;N;;;;; +FBCA;ARABIC LIGATURE RAHIMAHUMAA ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;; +FBCB;ARABIC LIGATURE RADI ALLAAHU TAAALAA ANHUM;So;0;ON;;;;;N;;;;; +FBCC;ARABIC LIGATURE HAFIZAHU ALLAAH;So;0;ON;;;;;N;;;;; +FBCD;ARABIC LIGATURE HAFIZAHU ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;; +FBCE;ARABIC LIGATURE HAFIZAHUM ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;; +FBCF;ARABIC LIGATURE HAFIZAHUMAA ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;; +FBD0;ARABIC LIGATURE SALLALLAAHU TAAALAA ALAYHI WA-SALLAM;So;0;ON;;;;;N;;;;; +FBD1;ARABIC LIGATURE AJJAL ALLAAHU FARAJAHU ASH-SHAREEF;So;0;ON;;;;;N;;;;; +FBD2;ARABIC LIGATURE ALAYHI AR-RAHMAH;So;0;ON;;;;;N;;;;; +FBD3;ARABIC LETTER NG ISOLATED FORM;Lo;0;AL; 06AD;;;;N;;;;; +FBD4;ARABIC LETTER NG FINAL FORM;Lo;0;AL; 06AD;;;;N;;;;; +FBD5;ARABIC LETTER NG INITIAL FORM;Lo;0;AL; 06AD;;;;N;;;;; +FBD6;ARABIC LETTER NG MEDIAL FORM;Lo;0;AL; 06AD;;;;N;;;;; +FBD7;ARABIC LETTER U ISOLATED FORM;Lo;0;AL; 06C7;;;;N;;;;; +FBD8;ARABIC LETTER U FINAL FORM;Lo;0;AL; 06C7;;;;N;;;;; +FBD9;ARABIC LETTER OE ISOLATED FORM;Lo;0;AL; 06C6;;;;N;;;;; +FBDA;ARABIC LETTER OE FINAL FORM;Lo;0;AL; 06C6;;;;N;;;;; +FBDB;ARABIC LETTER YU ISOLATED FORM;Lo;0;AL; 06C8;;;;N;;;;; +FBDC;ARABIC LETTER YU FINAL FORM;Lo;0;AL; 06C8;;;;N;;;;; +FBDD;ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 0677;;;;N;;;;; +FBDE;ARABIC LETTER VE ISOLATED FORM;Lo;0;AL; 06CB;;;;N;;;;; +FBDF;ARABIC LETTER VE FINAL FORM;Lo;0;AL; 06CB;;;;N;;;;; +FBE0;ARABIC LETTER KIRGHIZ OE ISOLATED FORM;Lo;0;AL; 06C5;;;;N;;;;; +FBE1;ARABIC LETTER KIRGHIZ OE FINAL FORM;Lo;0;AL; 06C5;;;;N;;;;; +FBE2;ARABIC LETTER KIRGHIZ YU ISOLATED FORM;Lo;0;AL; 06C9;;;;N;;;;; +FBE3;ARABIC LETTER KIRGHIZ YU FINAL FORM;Lo;0;AL; 06C9;;;;N;;;;; +FBE4;ARABIC LETTER E ISOLATED FORM;Lo;0;AL; 06D0;;;;N;;;;; +FBE5;ARABIC LETTER E FINAL FORM;Lo;0;AL; 06D0;;;;N;;;;; +FBE6;ARABIC LETTER E INITIAL FORM;Lo;0;AL; 06D0;;;;N;;;;; +FBE7;ARABIC LETTER E MEDIAL FORM;Lo;0;AL; 06D0;;;;N;;;;; +FBE8;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM;Lo;0;AL; 0649;;;;N;;;;; +FBE9;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM;Lo;0;AL; 0649;;;;N;;;;; +FBEA;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM;Lo;0;AL; 0626 0627;;;;N;;;;; +FBEB;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM;Lo;0;AL; 0626 0627;;;;N;;;;; +FBEC;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM;Lo;0;AL; 0626 06D5;;;;N;;;;; +FBED;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM;Lo;0;AL; 0626 06D5;;;;N;;;;; +FBEE;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM;Lo;0;AL; 0626 0648;;;;N;;;;; +FBEF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM;Lo;0;AL; 0626 0648;;;;N;;;;; +FBF0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM;Lo;0;AL; 0626 06C7;;;;N;;;;; +FBF1;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM;Lo;0;AL; 0626 06C7;;;;N;;;;; +FBF2;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM;Lo;0;AL; 0626 06C6;;;;N;;;;; +FBF3;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM;Lo;0;AL; 0626 06C6;;;;N;;;;; +FBF4;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM;Lo;0;AL; 0626 06C8;;;;N;;;;; +FBF5;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM;Lo;0;AL; 0626 06C8;;;;N;;;;; +FBF6;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM;Lo;0;AL; 0626 06D0;;;;N;;;;; +FBF7;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORM;Lo;0;AL; 0626 06D0;;;;N;;;;; +FBF8;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM;Lo;0;AL; 0626 06D0;;;;N;;;;; +FBF9;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0626 0649;;;;N;;;;; +FBFA;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0626 0649;;;;N;;;;; +FBFB;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM;Lo;0;AL; 0626 0649;;;;N;;;;; +FBFC;ARABIC LETTER FARSI YEH ISOLATED FORM;Lo;0;AL; 06CC;;;;N;;;;; +FBFD;ARABIC LETTER FARSI YEH FINAL FORM;Lo;0;AL; 06CC;;;;N;;;;; +FBFE;ARABIC LETTER FARSI YEH INITIAL FORM;Lo;0;AL; 06CC;;;;N;;;;; +FBFF;ARABIC LETTER FARSI YEH MEDIAL FORM;Lo;0;AL; 06CC;;;;N;;;;; +FC00;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM;Lo;0;AL; 0626 062C;;;;N;;;;; +FC01;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM;Lo;0;AL; 0626 062D;;;;N;;;;; +FC02;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM;Lo;0;AL; 0626 0645;;;;N;;;;; +FC03;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0626 0649;;;;N;;;;; +FC04;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM;Lo;0;AL; 0626 064A;;;;N;;;;; +FC05;ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM;Lo;0;AL; 0628 062C;;;;N;;;;; +FC06;ARABIC LIGATURE BEH WITH HAH ISOLATED FORM;Lo;0;AL; 0628 062D;;;;N;;;;; +FC07;ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM;Lo;0;AL; 0628 062E;;;;N;;;;; +FC08;ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM;Lo;0;AL; 0628 0645;;;;N;;;;; +FC09;ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0628 0649;;;;N;;;;; +FC0A;ARABIC LIGATURE BEH WITH YEH ISOLATED FORM;Lo;0;AL; 0628 064A;;;;N;;;;; +FC0B;ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM;Lo;0;AL; 062A 062C;;;;N;;;;; +FC0C;ARABIC LIGATURE TEH WITH HAH ISOLATED FORM;Lo;0;AL; 062A 062D;;;;N;;;;; +FC0D;ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM;Lo;0;AL; 062A 062E;;;;N;;;;; +FC0E;ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM;Lo;0;AL; 062A 0645;;;;N;;;;; +FC0F;ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 062A 0649;;;;N;;;;; +FC10;ARABIC LIGATURE TEH WITH YEH ISOLATED FORM;Lo;0;AL; 062A 064A;;;;N;;;;; +FC11;ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM;Lo;0;AL; 062B 062C;;;;N;;;;; +FC12;ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM;Lo;0;AL; 062B 0645;;;;N;;;;; +FC13;ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 062B 0649;;;;N;;;;; +FC14;ARABIC LIGATURE THEH WITH YEH ISOLATED FORM;Lo;0;AL; 062B 064A;;;;N;;;;; +FC15;ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM;Lo;0;AL; 062C 062D;;;;N;;;;; +FC16;ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM;Lo;0;AL; 062C 0645;;;;N;;;;; +FC17;ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM;Lo;0;AL; 062D 062C;;;;N;;;;; +FC18;ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM;Lo;0;AL; 062D 0645;;;;N;;;;; +FC19;ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM;Lo;0;AL; 062E 062C;;;;N;;;;; +FC1A;ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM;Lo;0;AL; 062E 062D;;;;N;;;;; +FC1B;ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM;Lo;0;AL; 062E 0645;;;;N;;;;; +FC1C;ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM;Lo;0;AL; 0633 062C;;;;N;;;;; +FC1D;ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM;Lo;0;AL; 0633 062D;;;;N;;;;; +FC1E;ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM;Lo;0;AL; 0633 062E;;;;N;;;;; +FC1F;ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM;Lo;0;AL; 0633 0645;;;;N;;;;; +FC20;ARABIC LIGATURE SAD WITH HAH ISOLATED FORM;Lo;0;AL; 0635 062D;;;;N;;;;; +FC21;ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM;Lo;0;AL; 0635 0645;;;;N;;;;; +FC22;ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM;Lo;0;AL; 0636 062C;;;;N;;;;; +FC23;ARABIC LIGATURE DAD WITH HAH ISOLATED FORM;Lo;0;AL; 0636 062D;;;;N;;;;; +FC24;ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM;Lo;0;AL; 0636 062E;;;;N;;;;; +FC25;ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM;Lo;0;AL; 0636 0645;;;;N;;;;; +FC26;ARABIC LIGATURE TAH WITH HAH ISOLATED FORM;Lo;0;AL; 0637 062D;;;;N;;;;; +FC27;ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM;Lo;0;AL; 0637 0645;;;;N;;;;; +FC28;ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM;Lo;0;AL; 0638 0645;;;;N;;;;; +FC29;ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM;Lo;0;AL; 0639 062C;;;;N;;;;; +FC2A;ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM;Lo;0;AL; 0639 0645;;;;N;;;;; +FC2B;ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM;Lo;0;AL; 063A 062C;;;;N;;;;; +FC2C;ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM;Lo;0;AL; 063A 0645;;;;N;;;;; +FC2D;ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM;Lo;0;AL; 0641 062C;;;;N;;;;; +FC2E;ARABIC LIGATURE FEH WITH HAH ISOLATED FORM;Lo;0;AL; 0641 062D;;;;N;;;;; +FC2F;ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM;Lo;0;AL; 0641 062E;;;;N;;;;; +FC30;ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM;Lo;0;AL; 0641 0645;;;;N;;;;; +FC31;ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0641 0649;;;;N;;;;; +FC32;ARABIC LIGATURE FEH WITH YEH ISOLATED FORM;Lo;0;AL; 0641 064A;;;;N;;;;; +FC33;ARABIC LIGATURE QAF WITH HAH ISOLATED FORM;Lo;0;AL; 0642 062D;;;;N;;;;; +FC34;ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM;Lo;0;AL; 0642 0645;;;;N;;;;; +FC35;ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0642 0649;;;;N;;;;; +FC36;ARABIC LIGATURE QAF WITH YEH ISOLATED FORM;Lo;0;AL; 0642 064A;;;;N;;;;; +FC37;ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM;Lo;0;AL; 0643 0627;;;;N;;;;; +FC38;ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM;Lo;0;AL; 0643 062C;;;;N;;;;; +FC39;ARABIC LIGATURE KAF WITH HAH ISOLATED FORM;Lo;0;AL; 0643 062D;;;;N;;;;; +FC3A;ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM;Lo;0;AL; 0643 062E;;;;N;;;;; +FC3B;ARABIC LIGATURE KAF WITH LAM ISOLATED FORM;Lo;0;AL; 0643 0644;;;;N;;;;; +FC3C;ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM;Lo;0;AL; 0643 0645;;;;N;;;;; +FC3D;ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0643 0649;;;;N;;;;; +FC3E;ARABIC LIGATURE KAF WITH YEH ISOLATED FORM;Lo;0;AL; 0643 064A;;;;N;;;;; +FC3F;ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM;Lo;0;AL; 0644 062C;;;;N;;;;; +FC40;ARABIC LIGATURE LAM WITH HAH ISOLATED FORM;Lo;0;AL; 0644 062D;;;;N;;;;; +FC41;ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM;Lo;0;AL; 0644 062E;;;;N;;;;; +FC42;ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM;Lo;0;AL; 0644 0645;;;;N;;;;; +FC43;ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0644 0649;;;;N;;;;; +FC44;ARABIC LIGATURE LAM WITH YEH ISOLATED FORM;Lo;0;AL; 0644 064A;;;;N;;;;; +FC45;ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM;Lo;0;AL; 0645 062C;;;;N;;;;; +FC46;ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM;Lo;0;AL; 0645 062D;;;;N;;;;; +FC47;ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM;Lo;0;AL; 0645 062E;;;;N;;;;; +FC48;ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM;Lo;0;AL; 0645 0645;;;;N;;;;; +FC49;ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0645 0649;;;;N;;;;; +FC4A;ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM;Lo;0;AL; 0645 064A;;;;N;;;;; +FC4B;ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM;Lo;0;AL; 0646 062C;;;;N;;;;; +FC4C;ARABIC LIGATURE NOON WITH HAH ISOLATED FORM;Lo;0;AL; 0646 062D;;;;N;;;;; +FC4D;ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM;Lo;0;AL; 0646 062E;;;;N;;;;; +FC4E;ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM;Lo;0;AL; 0646 0645;;;;N;;;;; +FC4F;ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0646 0649;;;;N;;;;; +FC50;ARABIC LIGATURE NOON WITH YEH ISOLATED FORM;Lo;0;AL; 0646 064A;;;;N;;;;; +FC51;ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM;Lo;0;AL; 0647 062C;;;;N;;;;; +FC52;ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM;Lo;0;AL; 0647 0645;;;;N;;;;; +FC53;ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0647 0649;;;;N;;;;; +FC54;ARABIC LIGATURE HEH WITH YEH ISOLATED FORM;Lo;0;AL; 0647 064A;;;;N;;;;; +FC55;ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM;Lo;0;AL; 064A 062C;;;;N;;;;; +FC56;ARABIC LIGATURE YEH WITH HAH ISOLATED FORM;Lo;0;AL; 064A 062D;;;;N;;;;; +FC57;ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM;Lo;0;AL; 064A 062E;;;;N;;;;; +FC58;ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM;Lo;0;AL; 064A 0645;;;;N;;;;; +FC59;ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 064A 0649;;;;N;;;;; +FC5A;ARABIC LIGATURE YEH WITH YEH ISOLATED FORM;Lo;0;AL; 064A 064A;;;;N;;;;; +FC5B;ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL; 0630 0670;;;;N;;;;; +FC5C;ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL; 0631 0670;;;;N;;;;; +FC5D;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL; 0649 0670;;;;N;;;;; +FC5E;ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM;Lo;0;AL; 0020 064C 0651;;;;N;;;;; +FC5F;ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM;Lo;0;AL; 0020 064D 0651;;;;N;;;;; +FC60;ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM;Lo;0;AL; 0020 064E 0651;;;;N;;;;; +FC61;ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM;Lo;0;AL; 0020 064F 0651;;;;N;;;;; +FC62;ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM;Lo;0;AL; 0020 0650 0651;;;;N;;;;; +FC63;ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL; 0020 0651 0670;;;;N;;;;; +FC64;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM;Lo;0;AL; 0626 0631;;;;N;;;;; +FC65;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM;Lo;0;AL; 0626 0632;;;;N;;;;; +FC66;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM;Lo;0;AL; 0626 0645;;;;N;;;;; +FC67;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM;Lo;0;AL; 0626 0646;;;;N;;;;; +FC68;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0626 0649;;;;N;;;;; +FC69;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM;Lo;0;AL; 0626 064A;;;;N;;;;; +FC6A;ARABIC LIGATURE BEH WITH REH FINAL FORM;Lo;0;AL; 0628 0631;;;;N;;;;; +FC6B;ARABIC LIGATURE BEH WITH ZAIN FINAL FORM;Lo;0;AL; 0628 0632;;;;N;;;;; +FC6C;ARABIC LIGATURE BEH WITH MEEM FINAL FORM;Lo;0;AL; 0628 0645;;;;N;;;;; +FC6D;ARABIC LIGATURE BEH WITH NOON FINAL FORM;Lo;0;AL; 0628 0646;;;;N;;;;; +FC6E;ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0628 0649;;;;N;;;;; +FC6F;ARABIC LIGATURE BEH WITH YEH FINAL FORM;Lo;0;AL; 0628 064A;;;;N;;;;; +FC70;ARABIC LIGATURE TEH WITH REH FINAL FORM;Lo;0;AL; 062A 0631;;;;N;;;;; +FC71;ARABIC LIGATURE TEH WITH ZAIN FINAL FORM;Lo;0;AL; 062A 0632;;;;N;;;;; +FC72;ARABIC LIGATURE TEH WITH MEEM FINAL FORM;Lo;0;AL; 062A 0645;;;;N;;;;; +FC73;ARABIC LIGATURE TEH WITH NOON FINAL FORM;Lo;0;AL; 062A 0646;;;;N;;;;; +FC74;ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062A 0649;;;;N;;;;; +FC75;ARABIC LIGATURE TEH WITH YEH FINAL FORM;Lo;0;AL; 062A 064A;;;;N;;;;; +FC76;ARABIC LIGATURE THEH WITH REH FINAL FORM;Lo;0;AL; 062B 0631;;;;N;;;;; +FC77;ARABIC LIGATURE THEH WITH ZAIN FINAL FORM;Lo;0;AL; 062B 0632;;;;N;;;;; +FC78;ARABIC LIGATURE THEH WITH MEEM FINAL FORM;Lo;0;AL; 062B 0645;;;;N;;;;; +FC79;ARABIC LIGATURE THEH WITH NOON FINAL FORM;Lo;0;AL; 062B 0646;;;;N;;;;; +FC7A;ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062B 0649;;;;N;;;;; +FC7B;ARABIC LIGATURE THEH WITH YEH FINAL FORM;Lo;0;AL; 062B 064A;;;;N;;;;; +FC7C;ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0641 0649;;;;N;;;;; +FC7D;ARABIC LIGATURE FEH WITH YEH FINAL FORM;Lo;0;AL; 0641 064A;;;;N;;;;; +FC7E;ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0642 0649;;;;N;;;;; +FC7F;ARABIC LIGATURE QAF WITH YEH FINAL FORM;Lo;0;AL; 0642 064A;;;;N;;;;; +FC80;ARABIC LIGATURE KAF WITH ALEF FINAL FORM;Lo;0;AL; 0643 0627;;;;N;;;;; +FC81;ARABIC LIGATURE KAF WITH LAM FINAL FORM;Lo;0;AL; 0643 0644;;;;N;;;;; +FC82;ARABIC LIGATURE KAF WITH MEEM FINAL FORM;Lo;0;AL; 0643 0645;;;;N;;;;; +FC83;ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0643 0649;;;;N;;;;; +FC84;ARABIC LIGATURE KAF WITH YEH FINAL FORM;Lo;0;AL; 0643 064A;;;;N;;;;; +FC85;ARABIC LIGATURE LAM WITH MEEM FINAL FORM;Lo;0;AL; 0644 0645;;;;N;;;;; +FC86;ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0644 0649;;;;N;;;;; +FC87;ARABIC LIGATURE LAM WITH YEH FINAL FORM;Lo;0;AL; 0644 064A;;;;N;;;;; +FC88;ARABIC LIGATURE MEEM WITH ALEF FINAL FORM;Lo;0;AL; 0645 0627;;;;N;;;;; +FC89;ARABIC LIGATURE MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0645 0645;;;;N;;;;; +FC8A;ARABIC LIGATURE NOON WITH REH FINAL FORM;Lo;0;AL; 0646 0631;;;;N;;;;; +FC8B;ARABIC LIGATURE NOON WITH ZAIN FINAL FORM;Lo;0;AL; 0646 0632;;;;N;;;;; +FC8C;ARABIC LIGATURE NOON WITH MEEM FINAL FORM;Lo;0;AL; 0646 0645;;;;N;;;;; +FC8D;ARABIC LIGATURE NOON WITH NOON FINAL FORM;Lo;0;AL; 0646 0646;;;;N;;;;; +FC8E;ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0646 0649;;;;N;;;;; +FC8F;ARABIC LIGATURE NOON WITH YEH FINAL FORM;Lo;0;AL; 0646 064A;;;;N;;;;; +FC90;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM;Lo;0;AL; 0649 0670;;;;N;;;;; +FC91;ARABIC LIGATURE YEH WITH REH FINAL FORM;Lo;0;AL; 064A 0631;;;;N;;;;; +FC92;ARABIC LIGATURE YEH WITH ZAIN FINAL FORM;Lo;0;AL; 064A 0632;;;;N;;;;; +FC93;ARABIC LIGATURE YEH WITH MEEM FINAL FORM;Lo;0;AL; 064A 0645;;;;N;;;;; +FC94;ARABIC LIGATURE YEH WITH NOON FINAL FORM;Lo;0;AL; 064A 0646;;;;N;;;;; +FC95;ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 064A 0649;;;;N;;;;; +FC96;ARABIC LIGATURE YEH WITH YEH FINAL FORM;Lo;0;AL; 064A 064A;;;;N;;;;; +FC97;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM;Lo;0;AL; 0626 062C;;;;N;;;;; +FC98;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM;Lo;0;AL; 0626 062D;;;;N;;;;; +FC99;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM;Lo;0;AL; 0626 062E;;;;N;;;;; +FC9A;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM;Lo;0;AL; 0626 0645;;;;N;;;;; +FC9B;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM;Lo;0;AL; 0626 0647;;;;N;;;;; +FC9C;ARABIC LIGATURE BEH WITH JEEM INITIAL FORM;Lo;0;AL; 0628 062C;;;;N;;;;; +FC9D;ARABIC LIGATURE BEH WITH HAH INITIAL FORM;Lo;0;AL; 0628 062D;;;;N;;;;; +FC9E;ARABIC LIGATURE BEH WITH KHAH INITIAL FORM;Lo;0;AL; 0628 062E;;;;N;;;;; +FC9F;ARABIC LIGATURE BEH WITH MEEM INITIAL FORM;Lo;0;AL; 0628 0645;;;;N;;;;; +FCA0;ARABIC LIGATURE BEH WITH HEH INITIAL FORM;Lo;0;AL; 0628 0647;;;;N;;;;; +FCA1;ARABIC LIGATURE TEH WITH JEEM INITIAL FORM;Lo;0;AL; 062A 062C;;;;N;;;;; +FCA2;ARABIC LIGATURE TEH WITH HAH INITIAL FORM;Lo;0;AL; 062A 062D;;;;N;;;;; +FCA3;ARABIC LIGATURE TEH WITH KHAH INITIAL FORM;Lo;0;AL; 062A 062E;;;;N;;;;; +FCA4;ARABIC LIGATURE TEH WITH MEEM INITIAL FORM;Lo;0;AL; 062A 0645;;;;N;;;;; +FCA5;ARABIC LIGATURE TEH WITH HEH INITIAL FORM;Lo;0;AL; 062A 0647;;;;N;;;;; +FCA6;ARABIC LIGATURE THEH WITH MEEM INITIAL FORM;Lo;0;AL; 062B 0645;;;;N;;;;; +FCA7;ARABIC LIGATURE JEEM WITH HAH INITIAL FORM;Lo;0;AL; 062C 062D;;;;N;;;;; +FCA8;ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 062C 0645;;;;N;;;;; +FCA9;ARABIC LIGATURE HAH WITH JEEM INITIAL FORM;Lo;0;AL; 062D 062C;;;;N;;;;; +FCAA;ARABIC LIGATURE HAH WITH MEEM INITIAL FORM;Lo;0;AL; 062D 0645;;;;N;;;;; +FCAB;ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM;Lo;0;AL; 062E 062C;;;;N;;;;; +FCAC;ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 062E 0645;;;;N;;;;; +FCAD;ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM;Lo;0;AL; 0633 062C;;;;N;;;;; +FCAE;ARABIC LIGATURE SEEN WITH HAH INITIAL FORM;Lo;0;AL; 0633 062D;;;;N;;;;; +FCAF;ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM;Lo;0;AL; 0633 062E;;;;N;;;;; +FCB0;ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM;Lo;0;AL; 0633 0645;;;;N;;;;; +FCB1;ARABIC LIGATURE SAD WITH HAH INITIAL FORM;Lo;0;AL; 0635 062D;;;;N;;;;; +FCB2;ARABIC LIGATURE SAD WITH KHAH INITIAL FORM;Lo;0;AL; 0635 062E;;;;N;;;;; +FCB3;ARABIC LIGATURE SAD WITH MEEM INITIAL FORM;Lo;0;AL; 0635 0645;;;;N;;;;; +FCB4;ARABIC LIGATURE DAD WITH JEEM INITIAL FORM;Lo;0;AL; 0636 062C;;;;N;;;;; +FCB5;ARABIC LIGATURE DAD WITH HAH INITIAL FORM;Lo;0;AL; 0636 062D;;;;N;;;;; +FCB6;ARABIC LIGATURE DAD WITH KHAH INITIAL FORM;Lo;0;AL; 0636 062E;;;;N;;;;; +FCB7;ARABIC LIGATURE DAD WITH MEEM INITIAL FORM;Lo;0;AL; 0636 0645;;;;N;;;;; +FCB8;ARABIC LIGATURE TAH WITH HAH INITIAL FORM;Lo;0;AL; 0637 062D;;;;N;;;;; +FCB9;ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM;Lo;0;AL; 0638 0645;;;;N;;;;; +FCBA;ARABIC LIGATURE AIN WITH JEEM INITIAL FORM;Lo;0;AL; 0639 062C;;;;N;;;;; +FCBB;ARABIC LIGATURE AIN WITH MEEM INITIAL FORM;Lo;0;AL; 0639 0645;;;;N;;;;; +FCBC;ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM;Lo;0;AL; 063A 062C;;;;N;;;;; +FCBD;ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM;Lo;0;AL; 063A 0645;;;;N;;;;; +FCBE;ARABIC LIGATURE FEH WITH JEEM INITIAL FORM;Lo;0;AL; 0641 062C;;;;N;;;;; +FCBF;ARABIC LIGATURE FEH WITH HAH INITIAL FORM;Lo;0;AL; 0641 062D;;;;N;;;;; +FCC0;ARABIC LIGATURE FEH WITH KHAH INITIAL FORM;Lo;0;AL; 0641 062E;;;;N;;;;; +FCC1;ARABIC LIGATURE FEH WITH MEEM INITIAL FORM;Lo;0;AL; 0641 0645;;;;N;;;;; +FCC2;ARABIC LIGATURE QAF WITH HAH INITIAL FORM;Lo;0;AL; 0642 062D;;;;N;;;;; +FCC3;ARABIC LIGATURE QAF WITH MEEM INITIAL FORM;Lo;0;AL; 0642 0645;;;;N;;;;; +FCC4;ARABIC LIGATURE KAF WITH JEEM INITIAL FORM;Lo;0;AL; 0643 062C;;;;N;;;;; +FCC5;ARABIC LIGATURE KAF WITH HAH INITIAL FORM;Lo;0;AL; 0643 062D;;;;N;;;;; +FCC6;ARABIC LIGATURE KAF WITH KHAH INITIAL FORM;Lo;0;AL; 0643 062E;;;;N;;;;; +FCC7;ARABIC LIGATURE KAF WITH LAM INITIAL FORM;Lo;0;AL; 0643 0644;;;;N;;;;; +FCC8;ARABIC LIGATURE KAF WITH MEEM INITIAL FORM;Lo;0;AL; 0643 0645;;;;N;;;;; +FCC9;ARABIC LIGATURE LAM WITH JEEM INITIAL FORM;Lo;0;AL; 0644 062C;;;;N;;;;; +FCCA;ARABIC LIGATURE LAM WITH HAH INITIAL FORM;Lo;0;AL; 0644 062D;;;;N;;;;; +FCCB;ARABIC LIGATURE LAM WITH KHAH INITIAL FORM;Lo;0;AL; 0644 062E;;;;N;;;;; +FCCC;ARABIC LIGATURE LAM WITH MEEM INITIAL FORM;Lo;0;AL; 0644 0645;;;;N;;;;; +FCCD;ARABIC LIGATURE LAM WITH HEH INITIAL FORM;Lo;0;AL; 0644 0647;;;;N;;;;; +FCCE;ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM;Lo;0;AL; 0645 062C;;;;N;;;;; +FCCF;ARABIC LIGATURE MEEM WITH HAH INITIAL FORM;Lo;0;AL; 0645 062D;;;;N;;;;; +FCD0;ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM;Lo;0;AL; 0645 062E;;;;N;;;;; +FCD1;ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0645 0645;;;;N;;;;; +FCD2;ARABIC LIGATURE NOON WITH JEEM INITIAL FORM;Lo;0;AL; 0646 062C;;;;N;;;;; +FCD3;ARABIC LIGATURE NOON WITH HAH INITIAL FORM;Lo;0;AL; 0646 062D;;;;N;;;;; +FCD4;ARABIC LIGATURE NOON WITH KHAH INITIAL FORM;Lo;0;AL; 0646 062E;;;;N;;;;; +FCD5;ARABIC LIGATURE NOON WITH MEEM INITIAL FORM;Lo;0;AL; 0646 0645;;;;N;;;;; +FCD6;ARABIC LIGATURE NOON WITH HEH INITIAL FORM;Lo;0;AL; 0646 0647;;;;N;;;;; +FCD7;ARABIC LIGATURE HEH WITH JEEM INITIAL FORM;Lo;0;AL; 0647 062C;;;;N;;;;; +FCD8;ARABIC LIGATURE HEH WITH MEEM INITIAL FORM;Lo;0;AL; 0647 0645;;;;N;;;;; +FCD9;ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM;Lo;0;AL; 0647 0670;;;;N;;;;; +FCDA;ARABIC LIGATURE YEH WITH JEEM INITIAL FORM;Lo;0;AL; 064A 062C;;;;N;;;;; +FCDB;ARABIC LIGATURE YEH WITH HAH INITIAL FORM;Lo;0;AL; 064A 062D;;;;N;;;;; +FCDC;ARABIC LIGATURE YEH WITH KHAH INITIAL FORM;Lo;0;AL; 064A 062E;;;;N;;;;; +FCDD;ARABIC LIGATURE YEH WITH MEEM INITIAL FORM;Lo;0;AL; 064A 0645;;;;N;;;;; +FCDE;ARABIC LIGATURE YEH WITH HEH INITIAL FORM;Lo;0;AL; 064A 0647;;;;N;;;;; +FCDF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM;Lo;0;AL; 0626 0645;;;;N;;;;; +FCE0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM;Lo;0;AL; 0626 0647;;;;N;;;;; +FCE1;ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM;Lo;0;AL; 0628 0645;;;;N;;;;; +FCE2;ARABIC LIGATURE BEH WITH HEH MEDIAL FORM;Lo;0;AL; 0628 0647;;;;N;;;;; +FCE3;ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM;Lo;0;AL; 062A 0645;;;;N;;;;; +FCE4;ARABIC LIGATURE TEH WITH HEH MEDIAL FORM;Lo;0;AL; 062A 0647;;;;N;;;;; +FCE5;ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM;Lo;0;AL; 062B 0645;;;;N;;;;; +FCE6;ARABIC LIGATURE THEH WITH HEH MEDIAL FORM;Lo;0;AL; 062B 0647;;;;N;;;;; +FCE7;ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM;Lo;0;AL; 0633 0645;;;;N;;;;; +FCE8;ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM;Lo;0;AL; 0633 0647;;;;N;;;;; +FCE9;ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM;Lo;0;AL; 0634 0645;;;;N;;;;; +FCEA;ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM;Lo;0;AL; 0634 0647;;;;N;;;;; +FCEB;ARABIC LIGATURE KAF WITH LAM MEDIAL FORM;Lo;0;AL; 0643 0644;;;;N;;;;; +FCEC;ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM;Lo;0;AL; 0643 0645;;;;N;;;;; +FCED;ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM;Lo;0;AL; 0644 0645;;;;N;;;;; +FCEE;ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM;Lo;0;AL; 0646 0645;;;;N;;;;; +FCEF;ARABIC LIGATURE NOON WITH HEH MEDIAL FORM;Lo;0;AL; 0646 0647;;;;N;;;;; +FCF0;ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM;Lo;0;AL; 064A 0645;;;;N;;;;; +FCF1;ARABIC LIGATURE YEH WITH HEH MEDIAL FORM;Lo;0;AL; 064A 0647;;;;N;;;;; +FCF2;ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM;Lo;0;AL; 0640 064E 0651;;;;N;;;;; +FCF3;ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM;Lo;0;AL; 0640 064F 0651;;;;N;;;;; +FCF4;ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM;Lo;0;AL; 0640 0650 0651;;;;N;;;;; +FCF5;ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0637 0649;;;;N;;;;; +FCF6;ARABIC LIGATURE TAH WITH YEH ISOLATED FORM;Lo;0;AL; 0637 064A;;;;N;;;;; +FCF7;ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0639 0649;;;;N;;;;; +FCF8;ARABIC LIGATURE AIN WITH YEH ISOLATED FORM;Lo;0;AL; 0639 064A;;;;N;;;;; +FCF9;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 063A 0649;;;;N;;;;; +FCFA;ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM;Lo;0;AL; 063A 064A;;;;N;;;;; +FCFB;ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0633 0649;;;;N;;;;; +FCFC;ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM;Lo;0;AL; 0633 064A;;;;N;;;;; +FCFD;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0634 0649;;;;N;;;;; +FCFE;ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM;Lo;0;AL; 0634 064A;;;;N;;;;; +FCFF;ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 062D 0649;;;;N;;;;; +FD00;ARABIC LIGATURE HAH WITH YEH ISOLATED FORM;Lo;0;AL; 062D 064A;;;;N;;;;; +FD01;ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 062C 0649;;;;N;;;;; +FD02;ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM;Lo;0;AL; 062C 064A;;;;N;;;;; +FD03;ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 062E 0649;;;;N;;;;; +FD04;ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM;Lo;0;AL; 062E 064A;;;;N;;;;; +FD05;ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0635 0649;;;;N;;;;; +FD06;ARABIC LIGATURE SAD WITH YEH ISOLATED FORM;Lo;0;AL; 0635 064A;;;;N;;;;; +FD07;ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0636 0649;;;;N;;;;; +FD08;ARABIC LIGATURE DAD WITH YEH ISOLATED FORM;Lo;0;AL; 0636 064A;;;;N;;;;; +FD09;ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM;Lo;0;AL; 0634 062C;;;;N;;;;; +FD0A;ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM;Lo;0;AL; 0634 062D;;;;N;;;;; +FD0B;ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM;Lo;0;AL; 0634 062E;;;;N;;;;; +FD0C;ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM;Lo;0;AL; 0634 0645;;;;N;;;;; +FD0D;ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM;Lo;0;AL; 0634 0631;;;;N;;;;; +FD0E;ARABIC LIGATURE SEEN WITH REH ISOLATED FORM;Lo;0;AL; 0633 0631;;;;N;;;;; +FD0F;ARABIC LIGATURE SAD WITH REH ISOLATED FORM;Lo;0;AL; 0635 0631;;;;N;;;;; +FD10;ARABIC LIGATURE DAD WITH REH ISOLATED FORM;Lo;0;AL; 0636 0631;;;;N;;;;; +FD11;ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0637 0649;;;;N;;;;; +FD12;ARABIC LIGATURE TAH WITH YEH FINAL FORM;Lo;0;AL; 0637 064A;;;;N;;;;; +FD13;ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0639 0649;;;;N;;;;; +FD14;ARABIC LIGATURE AIN WITH YEH FINAL FORM;Lo;0;AL; 0639 064A;;;;N;;;;; +FD15;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 063A 0649;;;;N;;;;; +FD16;ARABIC LIGATURE GHAIN WITH YEH FINAL FORM;Lo;0;AL; 063A 064A;;;;N;;;;; +FD17;ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0633 0649;;;;N;;;;; +FD18;ARABIC LIGATURE SEEN WITH YEH FINAL FORM;Lo;0;AL; 0633 064A;;;;N;;;;; +FD19;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0634 0649;;;;N;;;;; +FD1A;ARABIC LIGATURE SHEEN WITH YEH FINAL FORM;Lo;0;AL; 0634 064A;;;;N;;;;; +FD1B;ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062D 0649;;;;N;;;;; +FD1C;ARABIC LIGATURE HAH WITH YEH FINAL FORM;Lo;0;AL; 062D 064A;;;;N;;;;; +FD1D;ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062C 0649;;;;N;;;;; +FD1E;ARABIC LIGATURE JEEM WITH YEH FINAL FORM;Lo;0;AL; 062C 064A;;;;N;;;;; +FD1F;ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062E 0649;;;;N;;;;; +FD20;ARABIC LIGATURE KHAH WITH YEH FINAL FORM;Lo;0;AL; 062E 064A;;;;N;;;;; +FD21;ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0635 0649;;;;N;;;;; +FD22;ARABIC LIGATURE SAD WITH YEH FINAL FORM;Lo;0;AL; 0635 064A;;;;N;;;;; +FD23;ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0636 0649;;;;N;;;;; +FD24;ARABIC LIGATURE DAD WITH YEH FINAL FORM;Lo;0;AL; 0636 064A;;;;N;;;;; +FD25;ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM;Lo;0;AL; 0634 062C;;;;N;;;;; +FD26;ARABIC LIGATURE SHEEN WITH HAH FINAL FORM;Lo;0;AL; 0634 062D;;;;N;;;;; +FD27;ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM;Lo;0;AL; 0634 062E;;;;N;;;;; +FD28;ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM;Lo;0;AL; 0634 0645;;;;N;;;;; +FD29;ARABIC LIGATURE SHEEN WITH REH FINAL FORM;Lo;0;AL; 0634 0631;;;;N;;;;; +FD2A;ARABIC LIGATURE SEEN WITH REH FINAL FORM;Lo;0;AL; 0633 0631;;;;N;;;;; +FD2B;ARABIC LIGATURE SAD WITH REH FINAL FORM;Lo;0;AL; 0635 0631;;;;N;;;;; +FD2C;ARABIC LIGATURE DAD WITH REH FINAL FORM;Lo;0;AL; 0636 0631;;;;N;;;;; +FD2D;ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM;Lo;0;AL; 0634 062C;;;;N;;;;; +FD2E;ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM;Lo;0;AL; 0634 062D;;;;N;;;;; +FD2F;ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM;Lo;0;AL; 0634 062E;;;;N;;;;; +FD30;ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM;Lo;0;AL; 0634 0645;;;;N;;;;; +FD31;ARABIC LIGATURE SEEN WITH HEH INITIAL FORM;Lo;0;AL; 0633 0647;;;;N;;;;; +FD32;ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM;Lo;0;AL; 0634 0647;;;;N;;;;; +FD33;ARABIC LIGATURE TAH WITH MEEM INITIAL FORM;Lo;0;AL; 0637 0645;;;;N;;;;; +FD34;ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM;Lo;0;AL; 0633 062C;;;;N;;;;; +FD35;ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM;Lo;0;AL; 0633 062D;;;;N;;;;; +FD36;ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM;Lo;0;AL; 0633 062E;;;;N;;;;; +FD37;ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM;Lo;0;AL; 0634 062C;;;;N;;;;; +FD38;ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM;Lo;0;AL; 0634 062D;;;;N;;;;; +FD39;ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM;Lo;0;AL; 0634 062E;;;;N;;;;; +FD3A;ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM;Lo;0;AL; 0637 0645;;;;N;;;;; +FD3B;ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM;Lo;0;AL; 0638 0645;;;;N;;;;; +FD3C;ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM;Lo;0;AL; 0627 064B;;;;N;;;;; +FD3D;ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM;Lo;0;AL; 0627 064B;;;;N;;;;; +FD3E;ORNATE LEFT PARENTHESIS;Pe;0;ON;;;;;N;;;;; +FD3F;ORNATE RIGHT PARENTHESIS;Ps;0;ON;;;;;N;;;;; +FD40;ARABIC LIGATURE RAHIMAHU ALLAAH;So;0;ON;;;;;N;;;;; +FD41;ARABIC LIGATURE RADI ALLAAHU ANH;So;0;ON;;;;;N;;;;; +FD42;ARABIC LIGATURE RADI ALLAAHU ANHAA;So;0;ON;;;;;N;;;;; +FD43;ARABIC LIGATURE RADI ALLAAHU ANHUM;So;0;ON;;;;;N;;;;; +FD44;ARABIC LIGATURE RADI ALLAAHU ANHUMAA;So;0;ON;;;;;N;;;;; +FD45;ARABIC LIGATURE RADI ALLAAHU ANHUNNA;So;0;ON;;;;;N;;;;; +FD46;ARABIC LIGATURE SALLALLAAHU ALAYHI WA-AALIH;So;0;ON;;;;;N;;;;; +FD47;ARABIC LIGATURE ALAYHI AS-SALAAM;So;0;ON;;;;;N;;;;; +FD48;ARABIC LIGATURE ALAYHIM AS-SALAAM;So;0;ON;;;;;N;;;;; +FD49;ARABIC LIGATURE ALAYHIMAA AS-SALAAM;So;0;ON;;;;;N;;;;; +FD4A;ARABIC LIGATURE ALAYHI AS-SALAATU WAS-SALAAM;So;0;ON;;;;;N;;;;; +FD4B;ARABIC LIGATURE QUDDISA SIRRAH;So;0;ON;;;;;N;;;;; +FD4C;ARABIC LIGATURE SALLALLAHU ALAYHI WAAALIHEE WA-SALLAM;So;0;ON;;;;;N;;;;; +FD4D;ARABIC LIGATURE ALAYHAA AS-SALAAM;So;0;ON;;;;;N;;;;; +FD4E;ARABIC LIGATURE TABAARAKA WA-TAAALAA;So;0;ON;;;;;N;;;;; +FD4F;ARABIC LIGATURE RAHIMAHUM ALLAAH;So;0;ON;;;;;N;;;;; +FD50;ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 062A 062C 0645;;;;N;;;;; +FD51;ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM;Lo;0;AL; 062A 062D 062C;;;;N;;;;; +FD52;ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL; 062A 062D 062C;;;;N;;;;; +FD53;ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL; 062A 062D 0645;;;;N;;;;; +FD54;ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 062A 062E 0645;;;;N;;;;; +FD55;ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL; 062A 0645 062C;;;;N;;;;; +FD56;ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 062A 0645 062D;;;;N;;;;; +FD57;ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL; 062A 0645 062E;;;;N;;;;; +FD58;ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL; 062C 0645 062D;;;;N;;;;; +FD59;ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 062C 0645 062D;;;;N;;;;; +FD5A;ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 062D 0645 064A;;;;N;;;;; +FD5B;ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062D 0645 0649;;;;N;;;;; +FD5C;ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL; 0633 062D 062C;;;;N;;;;; +FD5D;ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL; 0633 062C 062D;;;;N;;;;; +FD5E;ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0633 062C 0649;;;;N;;;;; +FD5F;ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM;Lo;0;AL; 0633 0645 062D;;;;N;;;;; +FD60;ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 0633 0645 062D;;;;N;;;;; +FD61;ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL; 0633 0645 062C;;;;N;;;;; +FD62;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0633 0645 0645;;;;N;;;;; +FD63;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0633 0645 0645;;;;N;;;;; +FD64;ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM;Lo;0;AL; 0635 062D 062D;;;;N;;;;; +FD65;ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM;Lo;0;AL; 0635 062D 062D;;;;N;;;;; +FD66;ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0635 0645 0645;;;;N;;;;; +FD67;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM;Lo;0;AL; 0634 062D 0645;;;;N;;;;; +FD68;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL; 0634 062D 0645;;;;N;;;;; +FD69;ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 0634 062C 064A;;;;N;;;;; +FD6A;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM;Lo;0;AL; 0634 0645 062E;;;;N;;;;; +FD6B;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL; 0634 0645 062E;;;;N;;;;; +FD6C;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0634 0645 0645;;;;N;;;;; +FD6D;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0634 0645 0645;;;;N;;;;; +FD6E;ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0636 062D 0649;;;;N;;;;; +FD6F;ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL; 0636 062E 0645;;;;N;;;;; +FD70;ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 0636 062E 0645;;;;N;;;;; +FD71;ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM;Lo;0;AL; 0637 0645 062D;;;;N;;;;; +FD72;ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 0637 0645 062D;;;;N;;;;; +FD73;ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0637 0645 0645;;;;N;;;;; +FD74;ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0637 0645 064A;;;;N;;;;; +FD75;ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL; 0639 062C 0645;;;;N;;;;; +FD76;ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0639 0645 0645;;;;N;;;;; +FD77;ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0639 0645 0645;;;;N;;;;; +FD78;ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0639 0645 0649;;;;N;;;;; +FD79;ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 063A 0645 0645;;;;N;;;;; +FD7A;ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 063A 0645 064A;;;;N;;;;; +FD7B;ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 063A 0645 0649;;;;N;;;;; +FD7C;ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL; 0641 062E 0645;;;;N;;;;; +FD7D;ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 0641 062E 0645;;;;N;;;;; +FD7E;ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM;Lo;0;AL; 0642 0645 062D;;;;N;;;;; +FD7F;ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0642 0645 0645;;;;N;;;;; +FD80;ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM;Lo;0;AL; 0644 062D 0645;;;;N;;;;; +FD81;ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0644 062D 064A;;;;N;;;;; +FD82;ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0644 062D 0649;;;;N;;;;; +FD83;ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM;Lo;0;AL; 0644 062C 062C;;;;N;;;;; +FD84;ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM;Lo;0;AL; 0644 062C 062C;;;;N;;;;; +FD85;ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL; 0644 062E 0645;;;;N;;;;; +FD86;ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 0644 062E 0645;;;;N;;;;; +FD87;ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL; 0644 0645 062D;;;;N;;;;; +FD88;ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 0644 0645 062D;;;;N;;;;; +FD89;ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL; 0645 062D 062C;;;;N;;;;; +FD8A;ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL; 0645 062D 0645;;;;N;;;;; +FD8B;ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0645 062D 064A;;;;N;;;;; +FD8C;ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL; 0645 062C 062D;;;;N;;;;; +FD8D;ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0645 062C 0645;;;;N;;;;; +FD8E;ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM;Lo;0;AL; 0645 062E 062C;;;;N;;;;; +FD8F;ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 0645 062E 0645;;;;N;;;;; +FD90;ARABIC LIGATURE RAHMATU ALLAAHI ALAYH;So;0;ON;;;;;N;;;;; +FD91;ARABIC LIGATURE RAHMATU ALLAAHI ALAYHAA;So;0;ON;;;;;N;;;;; +FD92;ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM;Lo;0;AL; 0645 062C 062E;;;;N;;;;; +FD93;ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL; 0647 0645 062C;;;;N;;;;; +FD94;ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0647 0645 0645;;;;N;;;;; +FD95;ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL; 0646 062D 0645;;;;N;;;;; +FD96;ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0646 062D 0649;;;;N;;;;; +FD97;ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL; 0646 062C 0645;;;;N;;;;; +FD98;ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0646 062C 0645;;;;N;;;;; +FD99;ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0646 062C 0649;;;;N;;;;; +FD9A;ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0646 0645 064A;;;;N;;;;; +FD9B;ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0646 0645 0649;;;;N;;;;; +FD9C;ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 064A 0645 0645;;;;N;;;;; +FD9D;ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 064A 0645 0645;;;;N;;;;; +FD9E;ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL; 0628 062E 064A;;;;N;;;;; +FD9F;ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 062A 062C 064A;;;;N;;;;; +FDA0;ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062A 062C 0649;;;;N;;;;; +FDA1;ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL; 062A 062E 064A;;;;N;;;;; +FDA2;ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062A 062E 0649;;;;N;;;;; +FDA3;ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 062A 0645 064A;;;;N;;;;; +FDA4;ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062A 0645 0649;;;;N;;;;; +FDA5;ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 062C 0645 064A;;;;N;;;;; +FDA6;ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062C 062D 0649;;;;N;;;;; +FDA7;ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062C 0645 0649;;;;N;;;;; +FDA8;ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0633 062E 0649;;;;N;;;;; +FDA9;ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0635 062D 064A;;;;N;;;;; +FDAA;ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0634 062D 064A;;;;N;;;;; +FDAB;ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0636 062D 064A;;;;N;;;;; +FDAC;ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 0644 062C 064A;;;;N;;;;; +FDAD;ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0644 0645 064A;;;;N;;;;; +FDAE;ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 064A 062D 064A;;;;N;;;;; +FDAF;ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 064A 062C 064A;;;;N;;;;; +FDB0;ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 064A 0645 064A;;;;N;;;;; +FDB1;ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0645 0645 064A;;;;N;;;;; +FDB2;ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0642 0645 064A;;;;N;;;;; +FDB3;ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0646 062D 064A;;;;N;;;;; +FDB4;ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 0642 0645 062D;;;;N;;;;; +FDB5;ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL; 0644 062D 0645;;;;N;;;;; +FDB6;ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0639 0645 064A;;;;N;;;;; +FDB7;ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0643 0645 064A;;;;N;;;;; +FDB8;ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL; 0646 062C 062D;;;;N;;;;; +FDB9;ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM;Lo;0;AL; 0645 062E 064A;;;;N;;;;; +FDBA;ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0644 062C 0645;;;;N;;;;; +FDBB;ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0643 0645 0645;;;;N;;;;; +FDBC;ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL; 0644 062C 0645;;;;N;;;;; +FDBD;ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM;Lo;0;AL; 0646 062C 062D;;;;N;;;;; +FDBE;ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 062C 062D 064A;;;;N;;;;; +FDBF;ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 062D 062C 064A;;;;N;;;;; +FDC0;ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 0645 062C 064A;;;;N;;;;; +FDC1;ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0641 0645 064A;;;;N;;;;; +FDC2;ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0628 062D 064A;;;;N;;;;; +FDC3;ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0643 0645 0645;;;;N;;;;; +FDC4;ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0639 062C 0645;;;;N;;;;; +FDC5;ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0635 0645 0645;;;;N;;;;; +FDC6;ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM;Lo;0;AL; 0633 062E 064A;;;;N;;;;; +FDC7;ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 0646 062C 064A;;;;N;;;;; +FDC8;ARABIC LIGATURE RAHIMAHU ALLAAH TAAALAA;So;0;ON;;;;;N;;;;; +FDC9;ARABIC LIGATURE RADI ALLAAHU TAAALAA ANH;So;0;ON;;;;;N;;;;; +FDCA;ARABIC LIGATURE RADI ALLAAHU TAAALAA ANHAA;So;0;ON;;;;;N;;;;; +FDCB;ARABIC LIGATURE RADI ALLAAHU TAAALAA ANHUMAA;So;0;ON;;;;;N;;;;; +FDCC;ARABIC LIGATURE SALLALLAHU ALAYHI WA-ALAA AALIHEE WA-SALLAM;So;0;ON;;;;;N;;;;; +FDCD;ARABIC LIGATURE AJJAL ALLAAHU TAAALAA FARAJAHU ASH-SHAREEF;So;0;ON;;;;;N;;;;; +FDCE;ARABIC LIGATURE KARRAMA ALLAAHU WAJHAH;So;0;ON;;;;;N;;;;; +FDCF;ARABIC LIGATURE SALAAMUHU ALAYNAA;So;0;ON;;;;;N;;;;; +FDF0;ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL; 0635 0644 06D2;;;;N;;;;; +FDF1;ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL; 0642 0644 06D2;;;;N;;;;; +FDF2;ARABIC LIGATURE ALLAH ISOLATED FORM;Lo;0;AL; 0627 0644 0644 0647;;;;N;;;;; +FDF3;ARABIC LIGATURE AKBAR ISOLATED FORM;Lo;0;AL; 0627 0643 0628 0631;;;;N;;;;; +FDF4;ARABIC LIGATURE MOHAMMAD ISOLATED FORM;Lo;0;AL; 0645 062D 0645 062F;;;;N;;;;; +FDF5;ARABIC LIGATURE SALAM ISOLATED FORM;Lo;0;AL; 0635 0644 0639 0645;;;;N;;;;; +FDF6;ARABIC LIGATURE RASOUL ISOLATED FORM;Lo;0;AL; 0631 0633 0648 0644;;;;N;;;;; +FDF7;ARABIC LIGATURE ALAYHE ISOLATED FORM;Lo;0;AL; 0639 0644 064A 0647;;;;N;;;;; +FDF8;ARABIC LIGATURE WASALLAM ISOLATED FORM;Lo;0;AL; 0648 0633 0644 0645;;;;N;;;;; +FDF9;ARABIC LIGATURE SALLA ISOLATED FORM;Lo;0;AL; 0635 0644 0649;;;;N;;;;; +FDFA;ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM;Lo;0;AL; 0635 0644 0649 0020 0627 0644 0644 0647 0020 0639 0644 064A 0647 0020 0648 0633 0644 0645;;;;N;ARABIC LETTER SALLALLAHOU ALAYHE WASALLAM;;;; +FDFB;ARABIC LIGATURE JALLAJALALOUHOU;Lo;0;AL; 062C 0644 0020 062C 0644 0627 0644 0647;;;;N;ARABIC LETTER JALLAJALALOUHOU;;;; +FDFC;RIAL SIGN;Sc;0;AL; 0631 06CC 0627 0644;;;;N;;;;; +FDFD;ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM;So;0;ON;;;;;N;;;;; +FDFE;ARABIC LIGATURE SUBHAANAHU WA TAAALAA;So;0;ON;;;;;N;;;;; +FDFF;ARABIC LIGATURE AZZA WA JALL;So;0;ON;;;;;N;;;;; +FE00;VARIATION SELECTOR-1;Mn;0;NSM;;;;;N;;;;; +FE01;VARIATION SELECTOR-2;Mn;0;NSM;;;;;N;;;;; +FE02;VARIATION SELECTOR-3;Mn;0;NSM;;;;;N;;;;; +FE03;VARIATION SELECTOR-4;Mn;0;NSM;;;;;N;;;;; +FE04;VARIATION SELECTOR-5;Mn;0;NSM;;;;;N;;;;; +FE05;VARIATION SELECTOR-6;Mn;0;NSM;;;;;N;;;;; +FE06;VARIATION SELECTOR-7;Mn;0;NSM;;;;;N;;;;; +FE07;VARIATION SELECTOR-8;Mn;0;NSM;;;;;N;;;;; +FE08;VARIATION SELECTOR-9;Mn;0;NSM;;;;;N;;;;; +FE09;VARIATION SELECTOR-10;Mn;0;NSM;;;;;N;;;;; +FE0A;VARIATION SELECTOR-11;Mn;0;NSM;;;;;N;;;;; +FE0B;VARIATION SELECTOR-12;Mn;0;NSM;;;;;N;;;;; +FE0C;VARIATION SELECTOR-13;Mn;0;NSM;;;;;N;;;;; +FE0D;VARIATION SELECTOR-14;Mn;0;NSM;;;;;N;;;;; +FE0E;VARIATION SELECTOR-15;Mn;0;NSM;;;;;N;;;;; +FE0F;VARIATION SELECTOR-16;Mn;0;NSM;;;;;N;;;;; +FE10;PRESENTATION FORM FOR VERTICAL COMMA;Po;0;ON; 002C;;;;N;;;;; +FE11;PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA;Po;0;ON; 3001;;;;N;;;;; +FE12;PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP;Po;0;ON; 3002;;;;N;;;;; +FE13;PRESENTATION FORM FOR VERTICAL COLON;Po;0;ON; 003A;;;;N;;;;; +FE14;PRESENTATION FORM FOR VERTICAL SEMICOLON;Po;0;ON; 003B;;;;N;;;;; +FE15;PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK;Po;0;ON; 0021;;;;N;;;;; +FE16;PRESENTATION FORM FOR VERTICAL QUESTION MARK;Po;0;ON; 003F;;;;N;;;;; +FE17;PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET;Ps;0;ON; 3016;;;;N;;;;; +FE18;PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET;Pe;0;ON; 3017;;;;N;;;;; +FE19;PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS;Po;0;ON; 2026;;;;N;;;;; +FE20;COMBINING LIGATURE LEFT HALF;Mn;230;NSM;;;;;N;;;;; +FE21;COMBINING LIGATURE RIGHT HALF;Mn;230;NSM;;;;;N;;;;; +FE22;COMBINING DOUBLE TILDE LEFT HALF;Mn;230;NSM;;;;;N;;;;; +FE23;COMBINING DOUBLE TILDE RIGHT HALF;Mn;230;NSM;;;;;N;;;;; +FE24;COMBINING MACRON LEFT HALF;Mn;230;NSM;;;;;N;;;;; +FE25;COMBINING MACRON RIGHT HALF;Mn;230;NSM;;;;;N;;;;; +FE26;COMBINING CONJOINING MACRON;Mn;230;NSM;;;;;N;;;;; +FE27;COMBINING LIGATURE LEFT HALF BELOW;Mn;220;NSM;;;;;N;;;;; +FE28;COMBINING LIGATURE RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;; +FE29;COMBINING TILDE LEFT HALF BELOW;Mn;220;NSM;;;;;N;;;;; +FE2A;COMBINING TILDE RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;; +FE2B;COMBINING MACRON LEFT HALF BELOW;Mn;220;NSM;;;;;N;;;;; +FE2C;COMBINING MACRON RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;; +FE2D;COMBINING CONJOINING MACRON BELOW;Mn;220;NSM;;;;;N;;;;; +FE2E;COMBINING CYRILLIC TITLO LEFT HALF;Mn;230;NSM;;;;;N;;;;; +FE2F;COMBINING CYRILLIC TITLO RIGHT HALF;Mn;230;NSM;;;;;N;;;;; +FE30;PRESENTATION FORM FOR VERTICAL TWO DOT LEADER;Po;0;ON; 2025;;;;N;GLYPH FOR VERTICAL TWO DOT LEADER;;;; +FE31;PRESENTATION FORM FOR VERTICAL EM DASH;Pd;0;ON; 2014;;;;N;GLYPH FOR VERTICAL EM DASH;;;; +FE32;PRESENTATION FORM FOR VERTICAL EN DASH;Pd;0;ON; 2013;;;;N;GLYPH FOR VERTICAL EN DASH;;;; +FE33;PRESENTATION FORM FOR VERTICAL LOW LINE;Pc;0;ON; 005F;;;;N;GLYPH FOR VERTICAL SPACING UNDERSCORE;;;; +FE34;PRESENTATION FORM FOR VERTICAL WAVY LOW LINE;Pc;0;ON; 005F;;;;N;GLYPH FOR VERTICAL SPACING WAVY UNDERSCORE;;;; +FE35;PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS;Ps;0;ON; 0028;;;;N;GLYPH FOR VERTICAL OPENING PARENTHESIS;;;; +FE36;PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS;Pe;0;ON; 0029;;;;N;GLYPH FOR VERTICAL CLOSING PARENTHESIS;;;; +FE37;PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET;Ps;0;ON; 007B;;;;N;GLYPH FOR VERTICAL OPENING CURLY BRACKET;;;; +FE38;PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET;Pe;0;ON; 007D;;;;N;GLYPH FOR VERTICAL CLOSING CURLY BRACKET;;;; +FE39;PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET;Ps;0;ON; 3014;;;;N;GLYPH FOR VERTICAL OPENING TORTOISE SHELL BRACKET;;;; +FE3A;PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON; 3015;;;;N;GLYPH FOR VERTICAL CLOSING TORTOISE SHELL BRACKET;;;; +FE3B;PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET;Ps;0;ON; 3010;;;;N;GLYPH FOR VERTICAL OPENING BLACK LENTICULAR BRACKET;;;; +FE3C;PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON; 3011;;;;N;GLYPH FOR VERTICAL CLOSING BLACK LENTICULAR BRACKET;;;; +FE3D;PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON; 300A;;;;N;GLYPH FOR VERTICAL OPENING DOUBLE ANGLE BRACKET;;;; +FE3E;PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON; 300B;;;;N;GLYPH FOR VERTICAL CLOSING DOUBLE ANGLE BRACKET;;;; +FE3F;PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET;Ps;0;ON; 3008;;;;N;GLYPH FOR VERTICAL OPENING ANGLE BRACKET;;;; +FE40;PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET;Pe;0;ON; 3009;;;;N;GLYPH FOR VERTICAL CLOSING ANGLE BRACKET;;;; +FE41;PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET;Ps;0;ON; 300C;;;;N;GLYPH FOR VERTICAL OPENING CORNER BRACKET;;;; +FE42;PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET;Pe;0;ON; 300D;;;;N;GLYPH FOR VERTICAL CLOSING CORNER BRACKET;;;; +FE43;PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET;Ps;0;ON; 300E;;;;N;GLYPH FOR VERTICAL OPENING WHITE CORNER BRACKET;;;; +FE44;PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET;Pe;0;ON; 300F;;;;N;GLYPH FOR VERTICAL CLOSING WHITE CORNER BRACKET;;;; +FE45;SESAME DOT;Po;0;ON;;;;;N;;;;; +FE46;WHITE SESAME DOT;Po;0;ON;;;;;N;;;;; +FE47;PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET;Ps;0;ON; 005B;;;;N;;;;; +FE48;PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET;Pe;0;ON; 005D;;;;N;;;;; +FE49;DASHED OVERLINE;Po;0;ON; 203E;;;;N;SPACING DASHED OVERSCORE;;;; +FE4A;CENTRELINE OVERLINE;Po;0;ON; 203E;;;;N;SPACING CENTERLINE OVERSCORE;;;; +FE4B;WAVY OVERLINE;Po;0;ON; 203E;;;;N;SPACING WAVY OVERSCORE;;;; +FE4C;DOUBLE WAVY OVERLINE;Po;0;ON; 203E;;;;N;SPACING DOUBLE WAVY OVERSCORE;;;; +FE4D;DASHED LOW LINE;Pc;0;ON; 005F;;;;N;SPACING DASHED UNDERSCORE;;;; +FE4E;CENTRELINE LOW LINE;Pc;0;ON; 005F;;;;N;SPACING CENTERLINE UNDERSCORE;;;; +FE4F;WAVY LOW LINE;Pc;0;ON; 005F;;;;N;SPACING WAVY UNDERSCORE;;;; +FE50;SMALL COMMA;Po;0;CS; 002C;;;;N;;;;; +FE51;SMALL IDEOGRAPHIC COMMA;Po;0;ON; 3001;;;;N;;;;; +FE52;SMALL FULL STOP;Po;0;CS; 002E;;;;N;SMALL PERIOD;;;; +FE54;SMALL SEMICOLON;Po;0;ON; 003B;;;;N;;;;; +FE55;SMALL COLON;Po;0;CS; 003A;;;;N;;;;; +FE56;SMALL QUESTION MARK;Po;0;ON; 003F;;;;N;;;;; +FE57;SMALL EXCLAMATION MARK;Po;0;ON; 0021;;;;N;;;;; +FE58;SMALL EM DASH;Pd;0;ON; 2014;;;;N;;;;; +FE59;SMALL LEFT PARENTHESIS;Ps;0;ON; 0028;;;;Y;SMALL OPENING PARENTHESIS;;;; +FE5A;SMALL RIGHT PARENTHESIS;Pe;0;ON; 0029;;;;Y;SMALL CLOSING PARENTHESIS;;;; +FE5B;SMALL LEFT CURLY BRACKET;Ps;0;ON; 007B;;;;Y;SMALL OPENING CURLY BRACKET;;;; +FE5C;SMALL RIGHT CURLY BRACKET;Pe;0;ON; 007D;;;;Y;SMALL CLOSING CURLY BRACKET;;;; +FE5D;SMALL LEFT TORTOISE SHELL BRACKET;Ps;0;ON; 3014;;;;Y;SMALL OPENING TORTOISE SHELL BRACKET;;;; +FE5E;SMALL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON; 3015;;;;Y;SMALL CLOSING TORTOISE SHELL BRACKET;;;; +FE5F;SMALL NUMBER SIGN;Po;0;ET; 0023;;;;N;;;;; +FE60;SMALL AMPERSAND;Po;0;ON; 0026;;;;N;;;;; +FE61;SMALL ASTERISK;Po;0;ON; 002A;;;;N;;;;; +FE62;SMALL PLUS SIGN;Sm;0;ES; 002B;;;;N;;;;; +FE63;SMALL HYPHEN-MINUS;Pd;0;ES; 002D;;;;N;;;;; +FE64;SMALL LESS-THAN SIGN;Sm;0;ON; 003C;;;;Y;;;;; +FE65;SMALL GREATER-THAN SIGN;Sm;0;ON; 003E;;;;Y;;;;; +FE66;SMALL EQUALS SIGN;Sm;0;ON; 003D;;;;N;;;;; +FE68;SMALL REVERSE SOLIDUS;Po;0;ON; 005C;;;;N;SMALL BACKSLASH;;;; +FE69;SMALL DOLLAR SIGN;Sc;0;ET; 0024;;;;N;;;;; +FE6A;SMALL PERCENT SIGN;Po;0;ET; 0025;;;;N;;;;; +FE6B;SMALL COMMERCIAL AT;Po;0;ON; 0040;;;;N;;;;; +FE70;ARABIC FATHATAN ISOLATED FORM;Lo;0;AL; 0020 064B;;;;N;ARABIC SPACING FATHATAN;;;; +FE71;ARABIC TATWEEL WITH FATHATAN ABOVE;Lo;0;AL; 0640 064B;;;;N;ARABIC FATHATAN ON TATWEEL;;;; +FE72;ARABIC DAMMATAN ISOLATED FORM;Lo;0;AL; 0020 064C;;;;N;ARABIC SPACING DAMMATAN;;;; +FE73;ARABIC TAIL FRAGMENT;Lo;0;AL;;;;;N;;;;; +FE74;ARABIC KASRATAN ISOLATED FORM;Lo;0;AL; 0020 064D;;;;N;ARABIC SPACING KASRATAN;;;; +FE76;ARABIC FATHA ISOLATED FORM;Lo;0;AL; 0020 064E;;;;N;ARABIC SPACING FATHAH;;;; +FE77;ARABIC FATHA MEDIAL FORM;Lo;0;AL; 0640 064E;;;;N;ARABIC FATHAH ON TATWEEL;;;; +FE78;ARABIC DAMMA ISOLATED FORM;Lo;0;AL; 0020 064F;;;;N;ARABIC SPACING DAMMAH;;;; +FE79;ARABIC DAMMA MEDIAL FORM;Lo;0;AL; 0640 064F;;;;N;ARABIC DAMMAH ON TATWEEL;;;; +FE7A;ARABIC KASRA ISOLATED FORM;Lo;0;AL; 0020 0650;;;;N;ARABIC SPACING KASRAH;;;; +FE7B;ARABIC KASRA MEDIAL FORM;Lo;0;AL; 0640 0650;;;;N;ARABIC KASRAH ON TATWEEL;;;; +FE7C;ARABIC SHADDA ISOLATED FORM;Lo;0;AL; 0020 0651;;;;N;ARABIC SPACING SHADDAH;;;; +FE7D;ARABIC SHADDA MEDIAL FORM;Lo;0;AL; 0640 0651;;;;N;ARABIC SHADDAH ON TATWEEL;;;; +FE7E;ARABIC SUKUN ISOLATED FORM;Lo;0;AL; 0020 0652;;;;N;ARABIC SPACING SUKUN;;;; +FE7F;ARABIC SUKUN MEDIAL FORM;Lo;0;AL; 0640 0652;;;;N;ARABIC SUKUN ON TATWEEL;;;; +FE80;ARABIC LETTER HAMZA ISOLATED FORM;Lo;0;AL; 0621;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH;;;; +FE81;ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL; 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON ALEF;;;; +FE82;ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL; 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON ALEF;;;; +FE83;ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON ALEF;;;; +FE84;ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL; 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON ALEF;;;; +FE85;ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 0624;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON WAW;;;; +FE86;ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM;Lo;0;AL; 0624;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON WAW;;;; +FE87;ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL; 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER ALEF;;;; +FE88;ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL; 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER ALEF;;;; +FE89;ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 0626;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON YA;;;; +FE8A;ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM;Lo;0;AL; 0626;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON YA;;;; +FE8B;ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM;Lo;0;AL; 0626;;;;N;GLYPH FOR INITIAL ARABIC HAMZAH ON YA;;;; +FE8C;ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM;Lo;0;AL; 0626;;;;N;GLYPH FOR MEDIAL ARABIC HAMZAH ON YA;;;; +FE8D;ARABIC LETTER ALEF ISOLATED FORM;Lo;0;AL; 0627;;;;N;GLYPH FOR ISOLATE ARABIC ALEF;;;; +FE8E;ARABIC LETTER ALEF FINAL FORM;Lo;0;AL; 0627;;;;N;GLYPH FOR FINAL ARABIC ALEF;;;; +FE8F;ARABIC LETTER BEH ISOLATED FORM;Lo;0;AL; 0628;;;;N;GLYPH FOR ISOLATE ARABIC BAA;;;; +FE90;ARABIC LETTER BEH FINAL FORM;Lo;0;AL; 0628;;;;N;GLYPH FOR FINAL ARABIC BAA;;;; +FE91;ARABIC LETTER BEH INITIAL FORM;Lo;0;AL; 0628;;;;N;GLYPH FOR INITIAL ARABIC BAA;;;; +FE92;ARABIC LETTER BEH MEDIAL FORM;Lo;0;AL; 0628;;;;N;GLYPH FOR MEDIAL ARABIC BAA;;;; +FE93;ARABIC LETTER TEH MARBUTA ISOLATED FORM;Lo;0;AL; 0629;;;;N;GLYPH FOR ISOLATE ARABIC TAA MARBUTAH;;;; +FE94;ARABIC LETTER TEH MARBUTA FINAL FORM;Lo;0;AL; 0629;;;;N;GLYPH FOR FINAL ARABIC TAA MARBUTAH;;;; +FE95;ARABIC LETTER TEH ISOLATED FORM;Lo;0;AL; 062A;;;;N;GLYPH FOR ISOLATE ARABIC TAA;;;; +FE96;ARABIC LETTER TEH FINAL FORM;Lo;0;AL; 062A;;;;N;GLYPH FOR FINAL ARABIC TAA;;;; +FE97;ARABIC LETTER TEH INITIAL FORM;Lo;0;AL; 062A;;;;N;GLYPH FOR INITIAL ARABIC TAA;;;; +FE98;ARABIC LETTER TEH MEDIAL FORM;Lo;0;AL; 062A;;;;N;GLYPH FOR MEDIAL ARABIC TAA;;;; +FE99;ARABIC LETTER THEH ISOLATED FORM;Lo;0;AL; 062B;;;;N;GLYPH FOR ISOLATE ARABIC THAA;;;; +FE9A;ARABIC LETTER THEH FINAL FORM;Lo;0;AL; 062B;;;;N;GLYPH FOR FINAL ARABIC THAA;;;; +FE9B;ARABIC LETTER THEH INITIAL FORM;Lo;0;AL; 062B;;;;N;GLYPH FOR INITIAL ARABIC THAA;;;; +FE9C;ARABIC LETTER THEH MEDIAL FORM;Lo;0;AL; 062B;;;;N;GLYPH FOR MEDIAL ARABIC THAA;;;; +FE9D;ARABIC LETTER JEEM ISOLATED FORM;Lo;0;AL; 062C;;;;N;GLYPH FOR ISOLATE ARABIC JEEM;;;; +FE9E;ARABIC LETTER JEEM FINAL FORM;Lo;0;AL; 062C;;;;N;GLYPH FOR FINAL ARABIC JEEM;;;; +FE9F;ARABIC LETTER JEEM INITIAL FORM;Lo;0;AL; 062C;;;;N;GLYPH FOR INITIAL ARABIC JEEM;;;; +FEA0;ARABIC LETTER JEEM MEDIAL FORM;Lo;0;AL; 062C;;;;N;GLYPH FOR MEDIAL ARABIC JEEM;;;; +FEA1;ARABIC LETTER HAH ISOLATED FORM;Lo;0;AL; 062D;;;;N;GLYPH FOR ISOLATE ARABIC HAA;;;; +FEA2;ARABIC LETTER HAH FINAL FORM;Lo;0;AL; 062D;;;;N;GLYPH FOR FINAL ARABIC HAA;;;; +FEA3;ARABIC LETTER HAH INITIAL FORM;Lo;0;AL; 062D;;;;N;GLYPH FOR INITIAL ARABIC HAA;;;; +FEA4;ARABIC LETTER HAH MEDIAL FORM;Lo;0;AL; 062D;;;;N;GLYPH FOR MEDIAL ARABIC HAA;;;; +FEA5;ARABIC LETTER KHAH ISOLATED FORM;Lo;0;AL; 062E;;;;N;GLYPH FOR ISOLATE ARABIC KHAA;;;; +FEA6;ARABIC LETTER KHAH FINAL FORM;Lo;0;AL; 062E;;;;N;GLYPH FOR FINAL ARABIC KHAA;;;; +FEA7;ARABIC LETTER KHAH INITIAL FORM;Lo;0;AL; 062E;;;;N;GLYPH FOR INITIAL ARABIC KHAA;;;; +FEA8;ARABIC LETTER KHAH MEDIAL FORM;Lo;0;AL; 062E;;;;N;GLYPH FOR MEDIAL ARABIC KHAA;;;; +FEA9;ARABIC LETTER DAL ISOLATED FORM;Lo;0;AL; 062F;;;;N;GLYPH FOR ISOLATE ARABIC DAL;;;; +FEAA;ARABIC LETTER DAL FINAL FORM;Lo;0;AL; 062F;;;;N;GLYPH FOR FINAL ARABIC DAL;;;; +FEAB;ARABIC LETTER THAL ISOLATED FORM;Lo;0;AL; 0630;;;;N;GLYPH FOR ISOLATE ARABIC THAL;;;; +FEAC;ARABIC LETTER THAL FINAL FORM;Lo;0;AL; 0630;;;;N;GLYPH FOR FINAL ARABIC THAL;;;; +FEAD;ARABIC LETTER REH ISOLATED FORM;Lo;0;AL; 0631;;;;N;GLYPH FOR ISOLATE ARABIC RA;;;; +FEAE;ARABIC LETTER REH FINAL FORM;Lo;0;AL; 0631;;;;N;GLYPH FOR FINAL ARABIC RA;;;; +FEAF;ARABIC LETTER ZAIN ISOLATED FORM;Lo;0;AL; 0632;;;;N;GLYPH FOR ISOLATE ARABIC ZAIN;;;; +FEB0;ARABIC LETTER ZAIN FINAL FORM;Lo;0;AL; 0632;;;;N;GLYPH FOR FINAL ARABIC ZAIN;;;; +FEB1;ARABIC LETTER SEEN ISOLATED FORM;Lo;0;AL; 0633;;;;N;GLYPH FOR ISOLATE ARABIC SEEN;;;; +FEB2;ARABIC LETTER SEEN FINAL FORM;Lo;0;AL; 0633;;;;N;GLYPH FOR FINAL ARABIC SEEN;;;; +FEB3;ARABIC LETTER SEEN INITIAL FORM;Lo;0;AL; 0633;;;;N;GLYPH FOR INITIAL ARABIC SEEN;;;; +FEB4;ARABIC LETTER SEEN MEDIAL FORM;Lo;0;AL; 0633;;;;N;GLYPH FOR MEDIAL ARABIC SEEN;;;; +FEB5;ARABIC LETTER SHEEN ISOLATED FORM;Lo;0;AL; 0634;;;;N;GLYPH FOR ISOLATE ARABIC SHEEN;;;; +FEB6;ARABIC LETTER SHEEN FINAL FORM;Lo;0;AL; 0634;;;;N;GLYPH FOR FINAL ARABIC SHEEN;;;; +FEB7;ARABIC LETTER SHEEN INITIAL FORM;Lo;0;AL; 0634;;;;N;GLYPH FOR INITIAL ARABIC SHEEN;;;; +FEB8;ARABIC LETTER SHEEN MEDIAL FORM;Lo;0;AL; 0634;;;;N;GLYPH FOR MEDIAL ARABIC SHEEN;;;; +FEB9;ARABIC LETTER SAD ISOLATED FORM;Lo;0;AL; 0635;;;;N;GLYPH FOR ISOLATE ARABIC SAD;;;; +FEBA;ARABIC LETTER SAD FINAL FORM;Lo;0;AL; 0635;;;;N;GLYPH FOR FINAL ARABIC SAD;;;; +FEBB;ARABIC LETTER SAD INITIAL FORM;Lo;0;AL; 0635;;;;N;GLYPH FOR INITIAL ARABIC SAD;;;; +FEBC;ARABIC LETTER SAD MEDIAL FORM;Lo;0;AL; 0635;;;;N;GLYPH FOR MEDIAL ARABIC SAD;;;; +FEBD;ARABIC LETTER DAD ISOLATED FORM;Lo;0;AL; 0636;;;;N;GLYPH FOR ISOLATE ARABIC DAD;;;; +FEBE;ARABIC LETTER DAD FINAL FORM;Lo;0;AL; 0636;;;;N;GLYPH FOR FINAL ARABIC DAD;;;; +FEBF;ARABIC LETTER DAD INITIAL FORM;Lo;0;AL; 0636;;;;N;GLYPH FOR INITIAL ARABIC DAD;;;; +FEC0;ARABIC LETTER DAD MEDIAL FORM;Lo;0;AL; 0636;;;;N;GLYPH FOR MEDIAL ARABIC DAD;;;; +FEC1;ARABIC LETTER TAH ISOLATED FORM;Lo;0;AL; 0637;;;;N;GLYPH FOR ISOLATE ARABIC TAH;;;; +FEC2;ARABIC LETTER TAH FINAL FORM;Lo;0;AL; 0637;;;;N;GLYPH FOR FINAL ARABIC TAH;;;; +FEC3;ARABIC LETTER TAH INITIAL FORM;Lo;0;AL; 0637;;;;N;GLYPH FOR INITIAL ARABIC TAH;;;; +FEC4;ARABIC LETTER TAH MEDIAL FORM;Lo;0;AL; 0637;;;;N;GLYPH FOR MEDIAL ARABIC TAH;;;; +FEC5;ARABIC LETTER ZAH ISOLATED FORM;Lo;0;AL; 0638;;;;N;GLYPH FOR ISOLATE ARABIC DHAH;;;; +FEC6;ARABIC LETTER ZAH FINAL FORM;Lo;0;AL; 0638;;;;N;GLYPH FOR FINAL ARABIC DHAH;;;; +FEC7;ARABIC LETTER ZAH INITIAL FORM;Lo;0;AL; 0638;;;;N;GLYPH FOR INITIAL ARABIC DHAH;;;; +FEC8;ARABIC LETTER ZAH MEDIAL FORM;Lo;0;AL; 0638;;;;N;GLYPH FOR MEDIAL ARABIC DHAH;;;; +FEC9;ARABIC LETTER AIN ISOLATED FORM;Lo;0;AL; 0639;;;;N;GLYPH FOR ISOLATE ARABIC AIN;;;; +FECA;ARABIC LETTER AIN FINAL FORM;Lo;0;AL; 0639;;;;N;GLYPH FOR FINAL ARABIC AIN;;;; +FECB;ARABIC LETTER AIN INITIAL FORM;Lo;0;AL; 0639;;;;N;GLYPH FOR INITIAL ARABIC AIN;;;; +FECC;ARABIC LETTER AIN MEDIAL FORM;Lo;0;AL; 0639;;;;N;GLYPH FOR MEDIAL ARABIC AIN;;;; +FECD;ARABIC LETTER GHAIN ISOLATED FORM;Lo;0;AL; 063A;;;;N;GLYPH FOR ISOLATE ARABIC GHAIN;;;; +FECE;ARABIC LETTER GHAIN FINAL FORM;Lo;0;AL; 063A;;;;N;GLYPH FOR FINAL ARABIC GHAIN;;;; +FECF;ARABIC LETTER GHAIN INITIAL FORM;Lo;0;AL; 063A;;;;N;GLYPH FOR INITIAL ARABIC GHAIN;;;; +FED0;ARABIC LETTER GHAIN MEDIAL FORM;Lo;0;AL; 063A;;;;N;GLYPH FOR MEDIAL ARABIC GHAIN;;;; +FED1;ARABIC LETTER FEH ISOLATED FORM;Lo;0;AL; 0641;;;;N;GLYPH FOR ISOLATE ARABIC FA;;;; +FED2;ARABIC LETTER FEH FINAL FORM;Lo;0;AL; 0641;;;;N;GLYPH FOR FINAL ARABIC FA;;;; +FED3;ARABIC LETTER FEH INITIAL FORM;Lo;0;AL; 0641;;;;N;GLYPH FOR INITIAL ARABIC FA;;;; +FED4;ARABIC LETTER FEH MEDIAL FORM;Lo;0;AL; 0641;;;;N;GLYPH FOR MEDIAL ARABIC FA;;;; +FED5;ARABIC LETTER QAF ISOLATED FORM;Lo;0;AL; 0642;;;;N;GLYPH FOR ISOLATE ARABIC QAF;;;; +FED6;ARABIC LETTER QAF FINAL FORM;Lo;0;AL; 0642;;;;N;GLYPH FOR FINAL ARABIC QAF;;;; +FED7;ARABIC LETTER QAF INITIAL FORM;Lo;0;AL; 0642;;;;N;GLYPH FOR INITIAL ARABIC QAF;;;; +FED8;ARABIC LETTER QAF MEDIAL FORM;Lo;0;AL; 0642;;;;N;GLYPH FOR MEDIAL ARABIC QAF;;;; +FED9;ARABIC LETTER KAF ISOLATED FORM;Lo;0;AL; 0643;;;;N;GLYPH FOR ISOLATE ARABIC CAF;;;; +FEDA;ARABIC LETTER KAF FINAL FORM;Lo;0;AL; 0643;;;;N;GLYPH FOR FINAL ARABIC CAF;;;; +FEDB;ARABIC LETTER KAF INITIAL FORM;Lo;0;AL; 0643;;;;N;GLYPH FOR INITIAL ARABIC CAF;;;; +FEDC;ARABIC LETTER KAF MEDIAL FORM;Lo;0;AL; 0643;;;;N;GLYPH FOR MEDIAL ARABIC CAF;;;; +FEDD;ARABIC LETTER LAM ISOLATED FORM;Lo;0;AL; 0644;;;;N;GLYPH FOR ISOLATE ARABIC LAM;;;; +FEDE;ARABIC LETTER LAM FINAL FORM;Lo;0;AL; 0644;;;;N;GLYPH FOR FINAL ARABIC LAM;;;; +FEDF;ARABIC LETTER LAM INITIAL FORM;Lo;0;AL; 0644;;;;N;GLYPH FOR INITIAL ARABIC LAM;;;; +FEE0;ARABIC LETTER LAM MEDIAL FORM;Lo;0;AL; 0644;;;;N;GLYPH FOR MEDIAL ARABIC LAM;;;; +FEE1;ARABIC LETTER MEEM ISOLATED FORM;Lo;0;AL; 0645;;;;N;GLYPH FOR ISOLATE ARABIC MEEM;;;; +FEE2;ARABIC LETTER MEEM FINAL FORM;Lo;0;AL; 0645;;;;N;GLYPH FOR FINAL ARABIC MEEM;;;; +FEE3;ARABIC LETTER MEEM INITIAL FORM;Lo;0;AL; 0645;;;;N;GLYPH FOR INITIAL ARABIC MEEM;;;; +FEE4;ARABIC LETTER MEEM MEDIAL FORM;Lo;0;AL; 0645;;;;N;GLYPH FOR MEDIAL ARABIC MEEM;;;; +FEE5;ARABIC LETTER NOON ISOLATED FORM;Lo;0;AL; 0646;;;;N;GLYPH FOR ISOLATE ARABIC NOON;;;; +FEE6;ARABIC LETTER NOON FINAL FORM;Lo;0;AL; 0646;;;;N;GLYPH FOR FINAL ARABIC NOON;;;; +FEE7;ARABIC LETTER NOON INITIAL FORM;Lo;0;AL; 0646;;;;N;GLYPH FOR INITIAL ARABIC NOON;;;; +FEE8;ARABIC LETTER NOON MEDIAL FORM;Lo;0;AL; 0646;;;;N;GLYPH FOR MEDIAL ARABIC NOON;;;; +FEE9;ARABIC LETTER HEH ISOLATED FORM;Lo;0;AL; 0647;;;;N;GLYPH FOR ISOLATE ARABIC HA;;;; +FEEA;ARABIC LETTER HEH FINAL FORM;Lo;0;AL; 0647;;;;N;GLYPH FOR FINAL ARABIC HA;;;; +FEEB;ARABIC LETTER HEH INITIAL FORM;Lo;0;AL; 0647;;;;N;GLYPH FOR INITIAL ARABIC HA;;;; +FEEC;ARABIC LETTER HEH MEDIAL FORM;Lo;0;AL; 0647;;;;N;GLYPH FOR MEDIAL ARABIC HA;;;; +FEED;ARABIC LETTER WAW ISOLATED FORM;Lo;0;AL; 0648;;;;N;GLYPH FOR ISOLATE ARABIC WAW;;;; +FEEE;ARABIC LETTER WAW FINAL FORM;Lo;0;AL; 0648;;;;N;GLYPH FOR FINAL ARABIC WAW;;;; +FEEF;ARABIC LETTER ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0649;;;;N;GLYPH FOR ISOLATE ARABIC ALEF MAQSURAH;;;; +FEF0;ARABIC LETTER ALEF MAKSURA FINAL FORM;Lo;0;AL; 0649;;;;N;GLYPH FOR FINAL ARABIC ALEF MAQSURAH;;;; +FEF1;ARABIC LETTER YEH ISOLATED FORM;Lo;0;AL; 064A;;;;N;GLYPH FOR ISOLATE ARABIC YA;;;; +FEF2;ARABIC LETTER YEH FINAL FORM;Lo;0;AL; 064A;;;;N;GLYPH FOR FINAL ARABIC YA;;;; +FEF3;ARABIC LETTER YEH INITIAL FORM;Lo;0;AL; 064A;;;;N;GLYPH FOR INITIAL ARABIC YA;;;; +FEF4;ARABIC LETTER YEH MEDIAL FORM;Lo;0;AL; 064A;;;;N;GLYPH FOR MEDIAL ARABIC YA;;;; +FEF5;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL; 0644 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON LIGATURE LAM ALEF;;;; +FEF6;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL; 0644 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON LIGATURE LAM ALEF;;;; +FEF7;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 0644 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON LIGATURE LAM ALEF;;;; +FEF8;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL; 0644 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON LIGATURE LAM ALEF;;;; +FEF9;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL; 0644 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;; +FEFA;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL; 0644 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;; +FEFB;ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM;Lo;0;AL; 0644 0627;;;;N;GLYPH FOR ISOLATE ARABIC LIGATURE LAM ALEF;;;; +FEFC;ARABIC LIGATURE LAM WITH ALEF FINAL FORM;Lo;0;AL; 0644 0627;;;;N;GLYPH FOR FINAL ARABIC LIGATURE LAM ALEF;;;; +FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; +FF01;FULLWIDTH EXCLAMATION MARK;Po;0;ON; 0021;;;;N;;;;; +FF02;FULLWIDTH QUOTATION MARK;Po;0;ON; 0022;;;;N;;;;; +FF03;FULLWIDTH NUMBER SIGN;Po;0;ET; 0023;;;;N;;;;; +FF04;FULLWIDTH DOLLAR SIGN;Sc;0;ET; 0024;;;;N;;;;; +FF05;FULLWIDTH PERCENT SIGN;Po;0;ET; 0025;;;;N;;;;; +FF06;FULLWIDTH AMPERSAND;Po;0;ON; 0026;;;;N;;;;; +FF07;FULLWIDTH APOSTROPHE;Po;0;ON; 0027;;;;N;;;;; +FF08;FULLWIDTH LEFT PARENTHESIS;Ps;0;ON; 0028;;;;Y;FULLWIDTH OPENING PARENTHESIS;;;; +FF09;FULLWIDTH RIGHT PARENTHESIS;Pe;0;ON; 0029;;;;Y;FULLWIDTH CLOSING PARENTHESIS;;;; +FF0A;FULLWIDTH ASTERISK;Po;0;ON; 002A;;;;N;;;;; +FF0B;FULLWIDTH PLUS SIGN;Sm;0;ES; 002B;;;;N;;;;; +FF0C;FULLWIDTH COMMA;Po;0;CS; 002C;;;;N;;;;; +FF0D;FULLWIDTH HYPHEN-MINUS;Pd;0;ES; 002D;;;;N;;;;; +FF0E;FULLWIDTH FULL STOP;Po;0;CS; 002E;;;;N;FULLWIDTH PERIOD;;;; +FF0F;FULLWIDTH SOLIDUS;Po;0;CS; 002F;;;;N;FULLWIDTH SLASH;;;; +FF10;FULLWIDTH DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; +FF11;FULLWIDTH DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; +FF12;FULLWIDTH DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; +FF13;FULLWIDTH DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; +FF14;FULLWIDTH DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; +FF15;FULLWIDTH DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; +FF16;FULLWIDTH DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; +FF17;FULLWIDTH DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; +FF18;FULLWIDTH DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; +FF19;FULLWIDTH DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +FF1A;FULLWIDTH COLON;Po;0;CS; 003A;;;;N;;;;; +FF1B;FULLWIDTH SEMICOLON;Po;0;ON; 003B;;;;N;;;;; +FF1C;FULLWIDTH LESS-THAN SIGN;Sm;0;ON; 003C;;;;Y;;;;; +FF1D;FULLWIDTH EQUALS SIGN;Sm;0;ON; 003D;;;;N;;;;; +FF1E;FULLWIDTH GREATER-THAN SIGN;Sm;0;ON; 003E;;;;Y;;;;; +FF1F;FULLWIDTH QUESTION MARK;Po;0;ON; 003F;;;;N;;;;; +FF20;FULLWIDTH COMMERCIAL AT;Po;0;ON; 0040;;;;N;;;;; +FF21;FULLWIDTH LATIN CAPITAL LETTER A;Lu;0;L; 0041;;;;N;;;;FF41; +FF22;FULLWIDTH LATIN CAPITAL LETTER B;Lu;0;L; 0042;;;;N;;;;FF42; +FF23;FULLWIDTH LATIN CAPITAL LETTER C;Lu;0;L; 0043;;;;N;;;;FF43; +FF24;FULLWIDTH LATIN CAPITAL LETTER D;Lu;0;L; 0044;;;;N;;;;FF44; +FF25;FULLWIDTH LATIN CAPITAL LETTER E;Lu;0;L; 0045;;;;N;;;;FF45; +FF26;FULLWIDTH LATIN CAPITAL LETTER F;Lu;0;L; 0046;;;;N;;;;FF46; +FF27;FULLWIDTH LATIN CAPITAL LETTER G;Lu;0;L; 0047;;;;N;;;;FF47; +FF28;FULLWIDTH LATIN CAPITAL LETTER H;Lu;0;L; 0048;;;;N;;;;FF48; +FF29;FULLWIDTH LATIN CAPITAL LETTER I;Lu;0;L; 0049;;;;N;;;;FF49; +FF2A;FULLWIDTH LATIN CAPITAL LETTER J;Lu;0;L; 004A;;;;N;;;;FF4A; +FF2B;FULLWIDTH LATIN CAPITAL LETTER K;Lu;0;L; 004B;;;;N;;;;FF4B; +FF2C;FULLWIDTH LATIN CAPITAL LETTER L;Lu;0;L; 004C;;;;N;;;;FF4C; +FF2D;FULLWIDTH LATIN CAPITAL LETTER M;Lu;0;L; 004D;;;;N;;;;FF4D; +FF2E;FULLWIDTH LATIN CAPITAL LETTER N;Lu;0;L; 004E;;;;N;;;;FF4E; +FF2F;FULLWIDTH LATIN CAPITAL LETTER O;Lu;0;L; 004F;;;;N;;;;FF4F; +FF30;FULLWIDTH LATIN CAPITAL LETTER P;Lu;0;L; 0050;;;;N;;;;FF50; +FF31;FULLWIDTH LATIN CAPITAL LETTER Q;Lu;0;L; 0051;;;;N;;;;FF51; +FF32;FULLWIDTH LATIN CAPITAL LETTER R;Lu;0;L; 0052;;;;N;;;;FF52; +FF33;FULLWIDTH LATIN CAPITAL LETTER S;Lu;0;L; 0053;;;;N;;;;FF53; +FF34;FULLWIDTH LATIN CAPITAL LETTER T;Lu;0;L; 0054;;;;N;;;;FF54; +FF35;FULLWIDTH LATIN CAPITAL LETTER U;Lu;0;L; 0055;;;;N;;;;FF55; +FF36;FULLWIDTH LATIN CAPITAL LETTER V;Lu;0;L; 0056;;;;N;;;;FF56; +FF37;FULLWIDTH LATIN CAPITAL LETTER W;Lu;0;L; 0057;;;;N;;;;FF57; +FF38;FULLWIDTH LATIN CAPITAL LETTER X;Lu;0;L; 0058;;;;N;;;;FF58; +FF39;FULLWIDTH LATIN CAPITAL LETTER Y;Lu;0;L; 0059;;;;N;;;;FF59; +FF3A;FULLWIDTH LATIN CAPITAL LETTER Z;Lu;0;L; 005A;;;;N;;;;FF5A; +FF3B;FULLWIDTH LEFT SQUARE BRACKET;Ps;0;ON; 005B;;;;Y;FULLWIDTH OPENING SQUARE BRACKET;;;; +FF3C;FULLWIDTH REVERSE SOLIDUS;Po;0;ON; 005C;;;;N;FULLWIDTH BACKSLASH;;;; +FF3D;FULLWIDTH RIGHT SQUARE BRACKET;Pe;0;ON; 005D;;;;Y;FULLWIDTH CLOSING SQUARE BRACKET;;;; +FF3E;FULLWIDTH CIRCUMFLEX ACCENT;Sk;0;ON; 005E;;;;N;FULLWIDTH SPACING CIRCUMFLEX;;;; +FF3F;FULLWIDTH LOW LINE;Pc;0;ON; 005F;;;;N;FULLWIDTH SPACING UNDERSCORE;;;; +FF40;FULLWIDTH GRAVE ACCENT;Sk;0;ON; 0060;;;;N;FULLWIDTH SPACING GRAVE;;;; +FF41;FULLWIDTH LATIN SMALL LETTER A;Ll;0;L; 0061;;;;N;;;FF21;;FF21 +FF42;FULLWIDTH LATIN SMALL LETTER B;Ll;0;L; 0062;;;;N;;;FF22;;FF22 +FF43;FULLWIDTH LATIN SMALL LETTER C;Ll;0;L; 0063;;;;N;;;FF23;;FF23 +FF44;FULLWIDTH LATIN SMALL LETTER D;Ll;0;L; 0064;;;;N;;;FF24;;FF24 +FF45;FULLWIDTH LATIN SMALL LETTER E;Ll;0;L; 0065;;;;N;;;FF25;;FF25 +FF46;FULLWIDTH LATIN SMALL LETTER F;Ll;0;L; 0066;;;;N;;;FF26;;FF26 +FF47;FULLWIDTH LATIN SMALL LETTER G;Ll;0;L; 0067;;;;N;;;FF27;;FF27 +FF48;FULLWIDTH LATIN SMALL LETTER H;Ll;0;L; 0068;;;;N;;;FF28;;FF28 +FF49;FULLWIDTH LATIN SMALL LETTER I;Ll;0;L; 0069;;;;N;;;FF29;;FF29 +FF4A;FULLWIDTH LATIN SMALL LETTER J;Ll;0;L; 006A;;;;N;;;FF2A;;FF2A +FF4B;FULLWIDTH LATIN SMALL LETTER K;Ll;0;L; 006B;;;;N;;;FF2B;;FF2B +FF4C;FULLWIDTH LATIN SMALL LETTER L;Ll;0;L; 006C;;;;N;;;FF2C;;FF2C +FF4D;FULLWIDTH LATIN SMALL LETTER M;Ll;0;L; 006D;;;;N;;;FF2D;;FF2D +FF4E;FULLWIDTH LATIN SMALL LETTER N;Ll;0;L; 006E;;;;N;;;FF2E;;FF2E +FF4F;FULLWIDTH LATIN SMALL LETTER O;Ll;0;L; 006F;;;;N;;;FF2F;;FF2F +FF50;FULLWIDTH LATIN SMALL LETTER P;Ll;0;L; 0070;;;;N;;;FF30;;FF30 +FF51;FULLWIDTH LATIN SMALL LETTER Q;Ll;0;L; 0071;;;;N;;;FF31;;FF31 +FF52;FULLWIDTH LATIN SMALL LETTER R;Ll;0;L; 0072;;;;N;;;FF32;;FF32 +FF53;FULLWIDTH LATIN SMALL LETTER S;Ll;0;L; 0073;;;;N;;;FF33;;FF33 +FF54;FULLWIDTH LATIN SMALL LETTER T;Ll;0;L; 0074;;;;N;;;FF34;;FF34 +FF55;FULLWIDTH LATIN SMALL LETTER U;Ll;0;L; 0075;;;;N;;;FF35;;FF35 +FF56;FULLWIDTH LATIN SMALL LETTER V;Ll;0;L; 0076;;;;N;;;FF36;;FF36 +FF57;FULLWIDTH LATIN SMALL LETTER W;Ll;0;L; 0077;;;;N;;;FF37;;FF37 +FF58;FULLWIDTH LATIN SMALL LETTER X;Ll;0;L; 0078;;;;N;;;FF38;;FF38 +FF59;FULLWIDTH LATIN SMALL LETTER Y;Ll;0;L; 0079;;;;N;;;FF39;;FF39 +FF5A;FULLWIDTH LATIN SMALL LETTER Z;Ll;0;L; 007A;;;;N;;;FF3A;;FF3A +FF5B;FULLWIDTH LEFT CURLY BRACKET;Ps;0;ON; 007B;;;;Y;FULLWIDTH OPENING CURLY BRACKET;;;; +FF5C;FULLWIDTH VERTICAL LINE;Sm;0;ON; 007C;;;;N;FULLWIDTH VERTICAL BAR;;;; +FF5D;FULLWIDTH RIGHT CURLY BRACKET;Pe;0;ON; 007D;;;;Y;FULLWIDTH CLOSING CURLY BRACKET;;;; +FF5E;FULLWIDTH TILDE;Sm;0;ON; 007E;;;;N;FULLWIDTH SPACING TILDE;;;; +FF5F;FULLWIDTH LEFT WHITE PARENTHESIS;Ps;0;ON; 2985;;;;Y;;;;; +FF60;FULLWIDTH RIGHT WHITE PARENTHESIS;Pe;0;ON; 2986;;;;Y;;;;; +FF61;HALFWIDTH IDEOGRAPHIC FULL STOP;Po;0;ON; 3002;;;;N;HALFWIDTH IDEOGRAPHIC PERIOD;;;; +FF62;HALFWIDTH LEFT CORNER BRACKET;Ps;0;ON; 300C;;;;Y;HALFWIDTH OPENING CORNER BRACKET;;;; +FF63;HALFWIDTH RIGHT CORNER BRACKET;Pe;0;ON; 300D;;;;Y;HALFWIDTH CLOSING CORNER BRACKET;;;; +FF64;HALFWIDTH IDEOGRAPHIC COMMA;Po;0;ON; 3001;;;;N;;;;; +FF65;HALFWIDTH KATAKANA MIDDLE DOT;Po;0;ON; 30FB;;;;N;;;;; +FF66;HALFWIDTH KATAKANA LETTER WO;Lo;0;L; 30F2;;;;N;;;;; +FF67;HALFWIDTH KATAKANA LETTER SMALL A;Lo;0;L; 30A1;;;;N;;;;; +FF68;HALFWIDTH KATAKANA LETTER SMALL I;Lo;0;L; 30A3;;;;N;;;;; +FF69;HALFWIDTH KATAKANA LETTER SMALL U;Lo;0;L; 30A5;;;;N;;;;; +FF6A;HALFWIDTH KATAKANA LETTER SMALL E;Lo;0;L; 30A7;;;;N;;;;; +FF6B;HALFWIDTH KATAKANA LETTER SMALL O;Lo;0;L; 30A9;;;;N;;;;; +FF6C;HALFWIDTH KATAKANA LETTER SMALL YA;Lo;0;L; 30E3;;;;N;;;;; +FF6D;HALFWIDTH KATAKANA LETTER SMALL YU;Lo;0;L; 30E5;;;;N;;;;; +FF6E;HALFWIDTH KATAKANA LETTER SMALL YO;Lo;0;L; 30E7;;;;N;;;;; +FF6F;HALFWIDTH KATAKANA LETTER SMALL TU;Lo;0;L; 30C3;;;;N;;;;; +FF70;HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L; 30FC;;;;N;;;;; +FF71;HALFWIDTH KATAKANA LETTER A;Lo;0;L; 30A2;;;;N;;;;; +FF72;HALFWIDTH KATAKANA LETTER I;Lo;0;L; 30A4;;;;N;;;;; +FF73;HALFWIDTH KATAKANA LETTER U;Lo;0;L; 30A6;;;;N;;;;; +FF74;HALFWIDTH KATAKANA LETTER E;Lo;0;L; 30A8;;;;N;;;;; +FF75;HALFWIDTH KATAKANA LETTER O;Lo;0;L; 30AA;;;;N;;;;; +FF76;HALFWIDTH KATAKANA LETTER KA;Lo;0;L; 30AB;;;;N;;;;; +FF77;HALFWIDTH KATAKANA LETTER KI;Lo;0;L; 30AD;;;;N;;;;; +FF78;HALFWIDTH KATAKANA LETTER KU;Lo;0;L; 30AF;;;;N;;;;; +FF79;HALFWIDTH KATAKANA LETTER KE;Lo;0;L; 30B1;;;;N;;;;; +FF7A;HALFWIDTH KATAKANA LETTER KO;Lo;0;L; 30B3;;;;N;;;;; +FF7B;HALFWIDTH KATAKANA LETTER SA;Lo;0;L; 30B5;;;;N;;;;; +FF7C;HALFWIDTH KATAKANA LETTER SI;Lo;0;L; 30B7;;;;N;;;;; +FF7D;HALFWIDTH KATAKANA LETTER SU;Lo;0;L; 30B9;;;;N;;;;; +FF7E;HALFWIDTH KATAKANA LETTER SE;Lo;0;L; 30BB;;;;N;;;;; +FF7F;HALFWIDTH KATAKANA LETTER SO;Lo;0;L; 30BD;;;;N;;;;; +FF80;HALFWIDTH KATAKANA LETTER TA;Lo;0;L; 30BF;;;;N;;;;; +FF81;HALFWIDTH KATAKANA LETTER TI;Lo;0;L; 30C1;;;;N;;;;; +FF82;HALFWIDTH KATAKANA LETTER TU;Lo;0;L; 30C4;;;;N;;;;; +FF83;HALFWIDTH KATAKANA LETTER TE;Lo;0;L; 30C6;;;;N;;;;; +FF84;HALFWIDTH KATAKANA LETTER TO;Lo;0;L; 30C8;;;;N;;;;; +FF85;HALFWIDTH KATAKANA LETTER NA;Lo;0;L; 30CA;;;;N;;;;; +FF86;HALFWIDTH KATAKANA LETTER NI;Lo;0;L; 30CB;;;;N;;;;; +FF87;HALFWIDTH KATAKANA LETTER NU;Lo;0;L; 30CC;;;;N;;;;; +FF88;HALFWIDTH KATAKANA LETTER NE;Lo;0;L; 30CD;;;;N;;;;; +FF89;HALFWIDTH KATAKANA LETTER NO;Lo;0;L; 30CE;;;;N;;;;; +FF8A;HALFWIDTH KATAKANA LETTER HA;Lo;0;L; 30CF;;;;N;;;;; +FF8B;HALFWIDTH KATAKANA LETTER HI;Lo;0;L; 30D2;;;;N;;;;; +FF8C;HALFWIDTH KATAKANA LETTER HU;Lo;0;L; 30D5;;;;N;;;;; +FF8D;HALFWIDTH KATAKANA LETTER HE;Lo;0;L; 30D8;;;;N;;;;; +FF8E;HALFWIDTH KATAKANA LETTER HO;Lo;0;L; 30DB;;;;N;;;;; +FF8F;HALFWIDTH KATAKANA LETTER MA;Lo;0;L; 30DE;;;;N;;;;; +FF90;HALFWIDTH KATAKANA LETTER MI;Lo;0;L; 30DF;;;;N;;;;; +FF91;HALFWIDTH KATAKANA LETTER MU;Lo;0;L; 30E0;;;;N;;;;; +FF92;HALFWIDTH KATAKANA LETTER ME;Lo;0;L; 30E1;;;;N;;;;; +FF93;HALFWIDTH KATAKANA LETTER MO;Lo;0;L; 30E2;;;;N;;;;; +FF94;HALFWIDTH KATAKANA LETTER YA;Lo;0;L; 30E4;;;;N;;;;; +FF95;HALFWIDTH KATAKANA LETTER YU;Lo;0;L; 30E6;;;;N;;;;; +FF96;HALFWIDTH KATAKANA LETTER YO;Lo;0;L; 30E8;;;;N;;;;; +FF97;HALFWIDTH KATAKANA LETTER RA;Lo;0;L; 30E9;;;;N;;;;; +FF98;HALFWIDTH KATAKANA LETTER RI;Lo;0;L; 30EA;;;;N;;;;; +FF99;HALFWIDTH KATAKANA LETTER RU;Lo;0;L; 30EB;;;;N;;;;; +FF9A;HALFWIDTH KATAKANA LETTER RE;Lo;0;L; 30EC;;;;N;;;;; +FF9B;HALFWIDTH KATAKANA LETTER RO;Lo;0;L; 30ED;;;;N;;;;; +FF9C;HALFWIDTH KATAKANA LETTER WA;Lo;0;L; 30EF;;;;N;;;;; +FF9D;HALFWIDTH KATAKANA LETTER N;Lo;0;L; 30F3;;;;N;;;;; +FF9E;HALFWIDTH KATAKANA VOICED SOUND MARK;Lm;0;L; 3099;;;;N;;;;; +FF9F;HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK;Lm;0;L; 309A;;;;N;;;;; +FFA0;HALFWIDTH HANGUL FILLER;Lo;0;L; 3164;;;;N;HALFWIDTH HANGUL CAE OM;;;; +FFA1;HALFWIDTH HANGUL LETTER KIYEOK;Lo;0;L; 3131;;;;N;HALFWIDTH HANGUL LETTER GIYEOG;;;; +FFA2;HALFWIDTH HANGUL LETTER SSANGKIYEOK;Lo;0;L; 3132;;;;N;HALFWIDTH HANGUL LETTER SSANG GIYEOG;;;; +FFA3;HALFWIDTH HANGUL LETTER KIYEOK-SIOS;Lo;0;L; 3133;;;;N;HALFWIDTH HANGUL LETTER GIYEOG SIOS;;;; +FFA4;HALFWIDTH HANGUL LETTER NIEUN;Lo;0;L; 3134;;;;N;;;;; +FFA5;HALFWIDTH HANGUL LETTER NIEUN-CIEUC;Lo;0;L; 3135;;;;N;HALFWIDTH HANGUL LETTER NIEUN JIEUJ;;;; +FFA6;HALFWIDTH HANGUL LETTER NIEUN-HIEUH;Lo;0;L; 3136;;;;N;HALFWIDTH HANGUL LETTER NIEUN HIEUH;;;; +FFA7;HALFWIDTH HANGUL LETTER TIKEUT;Lo;0;L; 3137;;;;N;HALFWIDTH HANGUL LETTER DIGEUD;;;; +FFA8;HALFWIDTH HANGUL LETTER SSANGTIKEUT;Lo;0;L; 3138;;;;N;HALFWIDTH HANGUL LETTER SSANG DIGEUD;;;; +FFA9;HALFWIDTH HANGUL LETTER RIEUL;Lo;0;L; 3139;;;;N;HALFWIDTH HANGUL LETTER LIEUL;;;; +FFAA;HALFWIDTH HANGUL LETTER RIEUL-KIYEOK;Lo;0;L; 313A;;;;N;HALFWIDTH HANGUL LETTER LIEUL GIYEOG;;;; +FFAB;HALFWIDTH HANGUL LETTER RIEUL-MIEUM;Lo;0;L; 313B;;;;N;HALFWIDTH HANGUL LETTER LIEUL MIEUM;;;; +FFAC;HALFWIDTH HANGUL LETTER RIEUL-PIEUP;Lo;0;L; 313C;;;;N;HALFWIDTH HANGUL LETTER LIEUL BIEUB;;;; +FFAD;HALFWIDTH HANGUL LETTER RIEUL-SIOS;Lo;0;L; 313D;;;;N;HALFWIDTH HANGUL LETTER LIEUL SIOS;;;; +FFAE;HALFWIDTH HANGUL LETTER RIEUL-THIEUTH;Lo;0;L; 313E;;;;N;HALFWIDTH HANGUL LETTER LIEUL TIEUT;;;; +FFAF;HALFWIDTH HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L; 313F;;;;N;HALFWIDTH HANGUL LETTER LIEUL PIEUP;;;; +FFB0;HALFWIDTH HANGUL LETTER RIEUL-HIEUH;Lo;0;L; 3140;;;;N;HALFWIDTH HANGUL LETTER LIEUL HIEUH;;;; +FFB1;HALFWIDTH HANGUL LETTER MIEUM;Lo;0;L; 3141;;;;N;;;;; +FFB2;HALFWIDTH HANGUL LETTER PIEUP;Lo;0;L; 3142;;;;N;HALFWIDTH HANGUL LETTER BIEUB;;;; +FFB3;HALFWIDTH HANGUL LETTER SSANGPIEUP;Lo;0;L; 3143;;;;N;HALFWIDTH HANGUL LETTER SSANG BIEUB;;;; +FFB4;HALFWIDTH HANGUL LETTER PIEUP-SIOS;Lo;0;L; 3144;;;;N;HALFWIDTH HANGUL LETTER BIEUB SIOS;;;; +FFB5;HALFWIDTH HANGUL LETTER SIOS;Lo;0;L; 3145;;;;N;;;;; +FFB6;HALFWIDTH HANGUL LETTER SSANGSIOS;Lo;0;L; 3146;;;;N;HALFWIDTH HANGUL LETTER SSANG SIOS;;;; +FFB7;HALFWIDTH HANGUL LETTER IEUNG;Lo;0;L; 3147;;;;N;;;;; +FFB8;HALFWIDTH HANGUL LETTER CIEUC;Lo;0;L; 3148;;;;N;HALFWIDTH HANGUL LETTER JIEUJ;;;; +FFB9;HALFWIDTH HANGUL LETTER SSANGCIEUC;Lo;0;L; 3149;;;;N;HALFWIDTH HANGUL LETTER SSANG JIEUJ;;;; +FFBA;HALFWIDTH HANGUL LETTER CHIEUCH;Lo;0;L; 314A;;;;N;HALFWIDTH HANGUL LETTER CIEUC;;;; +FFBB;HALFWIDTH HANGUL LETTER KHIEUKH;Lo;0;L; 314B;;;;N;HALFWIDTH HANGUL LETTER KIYEOK;;;; +FFBC;HALFWIDTH HANGUL LETTER THIEUTH;Lo;0;L; 314C;;;;N;HALFWIDTH HANGUL LETTER TIEUT;;;; +FFBD;HALFWIDTH HANGUL LETTER PHIEUPH;Lo;0;L; 314D;;;;N;HALFWIDTH HANGUL LETTER PIEUP;;;; +FFBE;HALFWIDTH HANGUL LETTER HIEUH;Lo;0;L; 314E;;;;N;;;;; +FFC2;HALFWIDTH HANGUL LETTER A;Lo;0;L; 314F;;;;N;;;;; +FFC3;HALFWIDTH HANGUL LETTER AE;Lo;0;L; 3150;;;;N;;;;; +FFC4;HALFWIDTH HANGUL LETTER YA;Lo;0;L; 3151;;;;N;;;;; +FFC5;HALFWIDTH HANGUL LETTER YAE;Lo;0;L; 3152;;;;N;;;;; +FFC6;HALFWIDTH HANGUL LETTER EO;Lo;0;L; 3153;;;;N;;;;; +FFC7;HALFWIDTH HANGUL LETTER E;Lo;0;L; 3154;;;;N;;;;; +FFCA;HALFWIDTH HANGUL LETTER YEO;Lo;0;L; 3155;;;;N;;;;; +FFCB;HALFWIDTH HANGUL LETTER YE;Lo;0;L; 3156;;;;N;;;;; +FFCC;HALFWIDTH HANGUL LETTER O;Lo;0;L; 3157;;;;N;;;;; +FFCD;HALFWIDTH HANGUL LETTER WA;Lo;0;L; 3158;;;;N;;;;; +FFCE;HALFWIDTH HANGUL LETTER WAE;Lo;0;L; 3159;;;;N;;;;; +FFCF;HALFWIDTH HANGUL LETTER OE;Lo;0;L; 315A;;;;N;;;;; +FFD2;HALFWIDTH HANGUL LETTER YO;Lo;0;L; 315B;;;;N;;;;; +FFD3;HALFWIDTH HANGUL LETTER U;Lo;0;L; 315C;;;;N;;;;; +FFD4;HALFWIDTH HANGUL LETTER WEO;Lo;0;L; 315D;;;;N;;;;; +FFD5;HALFWIDTH HANGUL LETTER WE;Lo;0;L; 315E;;;;N;;;;; +FFD6;HALFWIDTH HANGUL LETTER WI;Lo;0;L; 315F;;;;N;;;;; +FFD7;HALFWIDTH HANGUL LETTER YU;Lo;0;L; 3160;;;;N;;;;; +FFDA;HALFWIDTH HANGUL LETTER EU;Lo;0;L; 3161;;;;N;;;;; +FFDB;HALFWIDTH HANGUL LETTER YI;Lo;0;L; 3162;;;;N;;;;; +FFDC;HALFWIDTH HANGUL LETTER I;Lo;0;L; 3163;;;;N;;;;; +FFE0;FULLWIDTH CENT SIGN;Sc;0;ET; 00A2;;;;N;;;;; +FFE1;FULLWIDTH POUND SIGN;Sc;0;ET; 00A3;;;;N;;;;; +FFE2;FULLWIDTH NOT SIGN;Sm;0;ON; 00AC;;;;N;;;;; +FFE3;FULLWIDTH MACRON;Sk;0;ON; 00AF;;;;N;FULLWIDTH SPACING MACRON;;;; +FFE4;FULLWIDTH BROKEN BAR;So;0;ON; 00A6;;;;N;FULLWIDTH BROKEN VERTICAL BAR;;;; +FFE5;FULLWIDTH YEN SIGN;Sc;0;ET; 00A5;;;;N;;;;; +FFE6;FULLWIDTH WON SIGN;Sc;0;ET; 20A9;;;;N;;;;; +FFE8;HALFWIDTH FORMS LIGHT VERTICAL;So;0;ON; 2502;;;;N;;;;; +FFE9;HALFWIDTH LEFTWARDS ARROW;Sm;0;ON; 2190;;;;N;;;;; +FFEA;HALFWIDTH UPWARDS ARROW;Sm;0;ON; 2191;;;;N;;;;; +FFEB;HALFWIDTH RIGHTWARDS ARROW;Sm;0;ON; 2192;;;;N;;;;; +FFEC;HALFWIDTH DOWNWARDS ARROW;Sm;0;ON; 2193;;;;N;;;;; +FFED;HALFWIDTH BLACK SQUARE;So;0;ON; 25A0;;;;N;;;;; +FFEE;HALFWIDTH WHITE CIRCLE;So;0;ON; 25CB;;;;N;;;;; +FFF9;INTERLINEAR ANNOTATION ANCHOR;Cf;0;ON;;;;;N;;;;; +FFFA;INTERLINEAR ANNOTATION SEPARATOR;Cf;0;ON;;;;;N;;;;; +FFFB;INTERLINEAR ANNOTATION TERMINATOR;Cf;0;ON;;;;;N;;;;; +FFFC;OBJECT REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; +FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; +10000;LINEAR B SYLLABLE B008 A;Lo;0;L;;;;;N;;;;; +10001;LINEAR B SYLLABLE B038 E;Lo;0;L;;;;;N;;;;; +10002;LINEAR B SYLLABLE B028 I;Lo;0;L;;;;;N;;;;; +10003;LINEAR B SYLLABLE B061 O;Lo;0;L;;;;;N;;;;; +10004;LINEAR B SYLLABLE B010 U;Lo;0;L;;;;;N;;;;; +10005;LINEAR B SYLLABLE B001 DA;Lo;0;L;;;;;N;;;;; +10006;LINEAR B SYLLABLE B045 DE;Lo;0;L;;;;;N;;;;; +10007;LINEAR B SYLLABLE B007 DI;Lo;0;L;;;;;N;;;;; +10008;LINEAR B SYLLABLE B014 DO;Lo;0;L;;;;;N;;;;; +10009;LINEAR B SYLLABLE B051 DU;Lo;0;L;;;;;N;;;;; +1000A;LINEAR B SYLLABLE B057 JA;Lo;0;L;;;;;N;;;;; +1000B;LINEAR B SYLLABLE B046 JE;Lo;0;L;;;;;N;;;;; +1000D;LINEAR B SYLLABLE B036 JO;Lo;0;L;;;;;N;;;;; +1000E;LINEAR B SYLLABLE B065 JU;Lo;0;L;;;;;N;;;;; +1000F;LINEAR B SYLLABLE B077 KA;Lo;0;L;;;;;N;;;;; +10010;LINEAR B SYLLABLE B044 KE;Lo;0;L;;;;;N;;;;; +10011;LINEAR B SYLLABLE B067 KI;Lo;0;L;;;;;N;;;;; +10012;LINEAR B SYLLABLE B070 KO;Lo;0;L;;;;;N;;;;; +10013;LINEAR B SYLLABLE B081 KU;Lo;0;L;;;;;N;;;;; +10014;LINEAR B SYLLABLE B080 MA;Lo;0;L;;;;;N;;;;; +10015;LINEAR B SYLLABLE B013 ME;Lo;0;L;;;;;N;;;;; +10016;LINEAR B SYLLABLE B073 MI;Lo;0;L;;;;;N;;;;; +10017;LINEAR B SYLLABLE B015 MO;Lo;0;L;;;;;N;;;;; +10018;LINEAR B SYLLABLE B023 MU;Lo;0;L;;;;;N;;;;; +10019;LINEAR B SYLLABLE B006 NA;Lo;0;L;;;;;N;;;;; +1001A;LINEAR B SYLLABLE B024 NE;Lo;0;L;;;;;N;;;;; +1001B;LINEAR B SYLLABLE B030 NI;Lo;0;L;;;;;N;;;;; +1001C;LINEAR B SYLLABLE B052 NO;Lo;0;L;;;;;N;;;;; +1001D;LINEAR B SYLLABLE B055 NU;Lo;0;L;;;;;N;;;;; +1001E;LINEAR B SYLLABLE B003 PA;Lo;0;L;;;;;N;;;;; +1001F;LINEAR B SYLLABLE B072 PE;Lo;0;L;;;;;N;;;;; +10020;LINEAR B SYLLABLE B039 PI;Lo;0;L;;;;;N;;;;; +10021;LINEAR B SYLLABLE B011 PO;Lo;0;L;;;;;N;;;;; +10022;LINEAR B SYLLABLE B050 PU;Lo;0;L;;;;;N;;;;; +10023;LINEAR B SYLLABLE B016 QA;Lo;0;L;;;;;N;;;;; +10024;LINEAR B SYLLABLE B078 QE;Lo;0;L;;;;;N;;;;; +10025;LINEAR B SYLLABLE B021 QI;Lo;0;L;;;;;N;;;;; +10026;LINEAR B SYLLABLE B032 QO;Lo;0;L;;;;;N;;;;; +10028;LINEAR B SYLLABLE B060 RA;Lo;0;L;;;;;N;;;;; +10029;LINEAR B SYLLABLE B027 RE;Lo;0;L;;;;;N;;;;; +1002A;LINEAR B SYLLABLE B053 RI;Lo;0;L;;;;;N;;;;; +1002B;LINEAR B SYLLABLE B002 RO;Lo;0;L;;;;;N;;;;; +1002C;LINEAR B SYLLABLE B026 RU;Lo;0;L;;;;;N;;;;; +1002D;LINEAR B SYLLABLE B031 SA;Lo;0;L;;;;;N;;;;; +1002E;LINEAR B SYLLABLE B009 SE;Lo;0;L;;;;;N;;;;; +1002F;LINEAR B SYLLABLE B041 SI;Lo;0;L;;;;;N;;;;; +10030;LINEAR B SYLLABLE B012 SO;Lo;0;L;;;;;N;;;;; +10031;LINEAR B SYLLABLE B058 SU;Lo;0;L;;;;;N;;;;; +10032;LINEAR B SYLLABLE B059 TA;Lo;0;L;;;;;N;;;;; +10033;LINEAR B SYLLABLE B004 TE;Lo;0;L;;;;;N;;;;; +10034;LINEAR B SYLLABLE B037 TI;Lo;0;L;;;;;N;;;;; +10035;LINEAR B SYLLABLE B005 TO;Lo;0;L;;;;;N;;;;; +10036;LINEAR B SYLLABLE B069 TU;Lo;0;L;;;;;N;;;;; +10037;LINEAR B SYLLABLE B054 WA;Lo;0;L;;;;;N;;;;; +10038;LINEAR B SYLLABLE B075 WE;Lo;0;L;;;;;N;;;;; +10039;LINEAR B SYLLABLE B040 WI;Lo;0;L;;;;;N;;;;; +1003A;LINEAR B SYLLABLE B042 WO;Lo;0;L;;;;;N;;;;; +1003C;LINEAR B SYLLABLE B017 ZA;Lo;0;L;;;;;N;;;;; +1003D;LINEAR B SYLLABLE B074 ZE;Lo;0;L;;;;;N;;;;; +1003F;LINEAR B SYLLABLE B020 ZO;Lo;0;L;;;;;N;;;;; +10040;LINEAR B SYLLABLE B025 A2;Lo;0;L;;;;;N;;;;; +10041;LINEAR B SYLLABLE B043 A3;Lo;0;L;;;;;N;;;;; +10042;LINEAR B SYLLABLE B085 AU;Lo;0;L;;;;;N;;;;; +10043;LINEAR B SYLLABLE B071 DWE;Lo;0;L;;;;;N;;;;; +10044;LINEAR B SYLLABLE B090 DWO;Lo;0;L;;;;;N;;;;; +10045;LINEAR B SYLLABLE B048 NWA;Lo;0;L;;;;;N;;;;; +10046;LINEAR B SYLLABLE B029 PU2;Lo;0;L;;;;;N;;;;; +10047;LINEAR B SYLLABLE B062 PTE;Lo;0;L;;;;;N;;;;; +10048;LINEAR B SYLLABLE B076 RA2;Lo;0;L;;;;;N;;;;; +10049;LINEAR B SYLLABLE B033 RA3;Lo;0;L;;;;;N;;;;; +1004A;LINEAR B SYLLABLE B068 RO2;Lo;0;L;;;;;N;;;;; +1004B;LINEAR B SYLLABLE B066 TA2;Lo;0;L;;;;;N;;;;; +1004C;LINEAR B SYLLABLE B087 TWE;Lo;0;L;;;;;N;;;;; +1004D;LINEAR B SYLLABLE B091 TWO;Lo;0;L;;;;;N;;;;; +10050;LINEAR B SYMBOL B018;Lo;0;L;;;;;N;;;;; +10051;LINEAR B SYMBOL B019;Lo;0;L;;;;;N;;;;; +10052;LINEAR B SYMBOL B022;Lo;0;L;;;;;N;;;;; +10053;LINEAR B SYMBOL B034;Lo;0;L;;;;;N;;;;; +10054;LINEAR B SYMBOL B047;Lo;0;L;;;;;N;;;;; +10055;LINEAR B SYMBOL B049;Lo;0;L;;;;;N;;;;; +10056;LINEAR B SYMBOL B056;Lo;0;L;;;;;N;;;;; +10057;LINEAR B SYMBOL B063;Lo;0;L;;;;;N;;;;; +10058;LINEAR B SYMBOL B064;Lo;0;L;;;;;N;;;;; +10059;LINEAR B SYMBOL B079;Lo;0;L;;;;;N;;;;; +1005A;LINEAR B SYMBOL B082;Lo;0;L;;;;;N;;;;; +1005B;LINEAR B SYMBOL B083;Lo;0;L;;;;;N;;;;; +1005C;LINEAR B SYMBOL B086;Lo;0;L;;;;;N;;;;; +1005D;LINEAR B SYMBOL B089;Lo;0;L;;;;;N;;;;; +10080;LINEAR B IDEOGRAM B100 MAN;Lo;0;L;;;;;N;;;;; +10081;LINEAR B IDEOGRAM B102 WOMAN;Lo;0;L;;;;;N;;;;; +10082;LINEAR B IDEOGRAM B104 DEER;Lo;0;L;;;;;N;;;;; +10083;LINEAR B IDEOGRAM B105 EQUID;Lo;0;L;;;;;N;;;;; +10084;LINEAR B IDEOGRAM B105F MARE;Lo;0;L;;;;;N;;;;; +10085;LINEAR B IDEOGRAM B105M STALLION;Lo;0;L;;;;;N;;;;; +10086;LINEAR B IDEOGRAM B106F EWE;Lo;0;L;;;;;N;;;;; +10087;LINEAR B IDEOGRAM B106M RAM;Lo;0;L;;;;;N;;;;; +10088;LINEAR B IDEOGRAM B107F SHE-GOAT;Lo;0;L;;;;;N;;;;; +10089;LINEAR B IDEOGRAM B107M HE-GOAT;Lo;0;L;;;;;N;;;;; +1008A;LINEAR B IDEOGRAM B108F SOW;Lo;0;L;;;;;N;;;;; +1008B;LINEAR B IDEOGRAM B108M BOAR;Lo;0;L;;;;;N;;;;; +1008C;LINEAR B IDEOGRAM B109F COW;Lo;0;L;;;;;N;;;;; +1008D;LINEAR B IDEOGRAM B109M BULL;Lo;0;L;;;;;N;;;;; +1008E;LINEAR B IDEOGRAM B120 WHEAT;Lo;0;L;;;;;N;;;;; +1008F;LINEAR B IDEOGRAM B121 BARLEY;Lo;0;L;;;;;N;;;;; +10090;LINEAR B IDEOGRAM B122 OLIVE;Lo;0;L;;;;;N;;;;; +10091;LINEAR B IDEOGRAM B123 SPICE;Lo;0;L;;;;;N;;;;; +10092;LINEAR B IDEOGRAM B125 CYPERUS;Lo;0;L;;;;;N;;;;; +10093;LINEAR B MONOGRAM B127 KAPO;Lo;0;L;;;;;N;;;;; +10094;LINEAR B MONOGRAM B128 KANAKO;Lo;0;L;;;;;N;;;;; +10095;LINEAR B IDEOGRAM B130 OIL;Lo;0;L;;;;;N;;;;; +10096;LINEAR B IDEOGRAM B131 WINE;Lo;0;L;;;;;N;;;;; +10097;LINEAR B IDEOGRAM B132;Lo;0;L;;;;;N;;;;; +10098;LINEAR B MONOGRAM B133 AREPA;Lo;0;L;;;;;N;;;;; +10099;LINEAR B MONOGRAM B135 MERI;Lo;0;L;;;;;N;;;;; +1009A;LINEAR B IDEOGRAM B140 BRONZE;Lo;0;L;;;;;N;;;;; +1009B;LINEAR B IDEOGRAM B141 GOLD;Lo;0;L;;;;;N;;;;; +1009C;LINEAR B IDEOGRAM B142;Lo;0;L;;;;;N;;;;; +1009D;LINEAR B IDEOGRAM B145 WOOL;Lo;0;L;;;;;N;;;;; +1009E;LINEAR B IDEOGRAM B146;Lo;0;L;;;;;N;;;;; +1009F;LINEAR B IDEOGRAM B150;Lo;0;L;;;;;N;;;;; +100A0;LINEAR B IDEOGRAM B151 HORN;Lo;0;L;;;;;N;;;;; +100A1;LINEAR B IDEOGRAM B152;Lo;0;L;;;;;N;;;;; +100A2;LINEAR B IDEOGRAM B153;Lo;0;L;;;;;N;;;;; +100A3;LINEAR B IDEOGRAM B154;Lo;0;L;;;;;N;;;;; +100A4;LINEAR B MONOGRAM B156 TURO2;Lo;0;L;;;;;N;;;;; +100A5;LINEAR B IDEOGRAM B157;Lo;0;L;;;;;N;;;;; +100A6;LINEAR B IDEOGRAM B158;Lo;0;L;;;;;N;;;;; +100A7;LINEAR B IDEOGRAM B159 CLOTH;Lo;0;L;;;;;N;;;;; +100A8;LINEAR B IDEOGRAM B160;Lo;0;L;;;;;N;;;;; +100A9;LINEAR B IDEOGRAM B161;Lo;0;L;;;;;N;;;;; +100AA;LINEAR B IDEOGRAM B162 GARMENT;Lo;0;L;;;;;N;;;;; +100AB;LINEAR B IDEOGRAM B163 ARMOUR;Lo;0;L;;;;;N;;;;; +100AC;LINEAR B IDEOGRAM B164;Lo;0;L;;;;;N;;;;; +100AD;LINEAR B IDEOGRAM B165;Lo;0;L;;;;;N;;;;; +100AE;LINEAR B IDEOGRAM B166;Lo;0;L;;;;;N;;;;; +100AF;LINEAR B IDEOGRAM B167;Lo;0;L;;;;;N;;;;; +100B0;LINEAR B IDEOGRAM B168;Lo;0;L;;;;;N;;;;; +100B1;LINEAR B IDEOGRAM B169;Lo;0;L;;;;;N;;;;; +100B2;LINEAR B IDEOGRAM B170;Lo;0;L;;;;;N;;;;; +100B3;LINEAR B IDEOGRAM B171;Lo;0;L;;;;;N;;;;; +100B4;LINEAR B IDEOGRAM B172;Lo;0;L;;;;;N;;;;; +100B5;LINEAR B IDEOGRAM B173 MONTH;Lo;0;L;;;;;N;;;;; +100B6;LINEAR B IDEOGRAM B174;Lo;0;L;;;;;N;;;;; +100B7;LINEAR B IDEOGRAM B176 TREE;Lo;0;L;;;;;N;;;;; +100B8;LINEAR B IDEOGRAM B177;Lo;0;L;;;;;N;;;;; +100B9;LINEAR B IDEOGRAM B178;Lo;0;L;;;;;N;;;;; +100BA;LINEAR B IDEOGRAM B179;Lo;0;L;;;;;N;;;;; +100BB;LINEAR B IDEOGRAM B180;Lo;0;L;;;;;N;;;;; +100BC;LINEAR B IDEOGRAM B181;Lo;0;L;;;;;N;;;;; +100BD;LINEAR B IDEOGRAM B182;Lo;0;L;;;;;N;;;;; +100BE;LINEAR B IDEOGRAM B183;Lo;0;L;;;;;N;;;;; +100BF;LINEAR B IDEOGRAM B184;Lo;0;L;;;;;N;;;;; +100C0;LINEAR B IDEOGRAM B185;Lo;0;L;;;;;N;;;;; +100C1;LINEAR B IDEOGRAM B189;Lo;0;L;;;;;N;;;;; +100C2;LINEAR B IDEOGRAM B190;Lo;0;L;;;;;N;;;;; +100C3;LINEAR B IDEOGRAM B191 HELMET;Lo;0;L;;;;;N;;;;; +100C4;LINEAR B IDEOGRAM B220 FOOTSTOOL;Lo;0;L;;;;;N;;;;; +100C5;LINEAR B IDEOGRAM B225 BATHTUB;Lo;0;L;;;;;N;;;;; +100C6;LINEAR B IDEOGRAM B230 SPEAR;Lo;0;L;;;;;N;;;;; +100C7;LINEAR B IDEOGRAM B231 ARROW;Lo;0;L;;;;;N;;;;; +100C8;LINEAR B IDEOGRAM B232;Lo;0;L;;;;;N;;;;; +100C9;LINEAR B IDEOGRAM B233 SWORD;Lo;0;L;;;;;N;;;;; +100CA;LINEAR B IDEOGRAM B234;Lo;0;L;;;;;N;;;;; +100CB;LINEAR B IDEOGRAM B236;Lo;0;L;;;;;N;;;;; +100CC;LINEAR B IDEOGRAM B240 WHEELED CHARIOT;Lo;0;L;;;;;N;;;;; +100CD;LINEAR B IDEOGRAM B241 CHARIOT;Lo;0;L;;;;;N;;;;; +100CE;LINEAR B IDEOGRAM B242 CHARIOT FRAME;Lo;0;L;;;;;N;;;;; +100CF;LINEAR B IDEOGRAM B243 WHEEL;Lo;0;L;;;;;N;;;;; +100D0;LINEAR B IDEOGRAM B245;Lo;0;L;;;;;N;;;;; +100D1;LINEAR B IDEOGRAM B246;Lo;0;L;;;;;N;;;;; +100D2;LINEAR B MONOGRAM B247 DIPTE;Lo;0;L;;;;;N;;;;; +100D3;LINEAR B IDEOGRAM B248;Lo;0;L;;;;;N;;;;; +100D4;LINEAR B IDEOGRAM B249;Lo;0;L;;;;;N;;;;; +100D5;LINEAR B IDEOGRAM B251;Lo;0;L;;;;;N;;;;; +100D6;LINEAR B IDEOGRAM B252;Lo;0;L;;;;;N;;;;; +100D7;LINEAR B IDEOGRAM B253;Lo;0;L;;;;;N;;;;; +100D8;LINEAR B IDEOGRAM B254 DART;Lo;0;L;;;;;N;;;;; +100D9;LINEAR B IDEOGRAM B255;Lo;0;L;;;;;N;;;;; +100DA;LINEAR B IDEOGRAM B256;Lo;0;L;;;;;N;;;;; +100DB;LINEAR B IDEOGRAM B257;Lo;0;L;;;;;N;;;;; +100DC;LINEAR B IDEOGRAM B258;Lo;0;L;;;;;N;;;;; +100DD;LINEAR B IDEOGRAM B259;Lo;0;L;;;;;N;;;;; +100DE;LINEAR B IDEOGRAM VESSEL B155;Lo;0;L;;;;;N;;;;; +100DF;LINEAR B IDEOGRAM VESSEL B200;Lo;0;L;;;;;N;;;;; +100E0;LINEAR B IDEOGRAM VESSEL B201;Lo;0;L;;;;;N;;;;; +100E1;LINEAR B IDEOGRAM VESSEL B202;Lo;0;L;;;;;N;;;;; +100E2;LINEAR B IDEOGRAM VESSEL B203;Lo;0;L;;;;;N;;;;; +100E3;LINEAR B IDEOGRAM VESSEL B204;Lo;0;L;;;;;N;;;;; +100E4;LINEAR B IDEOGRAM VESSEL B205;Lo;0;L;;;;;N;;;;; +100E5;LINEAR B IDEOGRAM VESSEL B206;Lo;0;L;;;;;N;;;;; +100E6;LINEAR B IDEOGRAM VESSEL B207;Lo;0;L;;;;;N;;;;; +100E7;LINEAR B IDEOGRAM VESSEL B208;Lo;0;L;;;;;N;;;;; +100E8;LINEAR B IDEOGRAM VESSEL B209;Lo;0;L;;;;;N;;;;; +100E9;LINEAR B IDEOGRAM VESSEL B210;Lo;0;L;;;;;N;;;;; +100EA;LINEAR B IDEOGRAM VESSEL B211;Lo;0;L;;;;;N;;;;; +100EB;LINEAR B IDEOGRAM VESSEL B212;Lo;0;L;;;;;N;;;;; +100EC;LINEAR B IDEOGRAM VESSEL B213;Lo;0;L;;;;;N;;;;; +100ED;LINEAR B IDEOGRAM VESSEL B214;Lo;0;L;;;;;N;;;;; +100EE;LINEAR B IDEOGRAM VESSEL B215;Lo;0;L;;;;;N;;;;; +100EF;LINEAR B IDEOGRAM VESSEL B216;Lo;0;L;;;;;N;;;;; +100F0;LINEAR B IDEOGRAM VESSEL B217;Lo;0;L;;;;;N;;;;; +100F1;LINEAR B IDEOGRAM VESSEL B218;Lo;0;L;;;;;N;;;;; +100F2;LINEAR B IDEOGRAM VESSEL B219;Lo;0;L;;;;;N;;;;; +100F3;LINEAR B IDEOGRAM VESSEL B221;Lo;0;L;;;;;N;;;;; +100F4;LINEAR B IDEOGRAM VESSEL B222;Lo;0;L;;;;;N;;;;; +100F5;LINEAR B IDEOGRAM VESSEL B226;Lo;0;L;;;;;N;;;;; +100F6;LINEAR B IDEOGRAM VESSEL B227;Lo;0;L;;;;;N;;;;; +100F7;LINEAR B IDEOGRAM VESSEL B228;Lo;0;L;;;;;N;;;;; +100F8;LINEAR B IDEOGRAM VESSEL B229;Lo;0;L;;;;;N;;;;; +100F9;LINEAR B IDEOGRAM VESSEL B250;Lo;0;L;;;;;N;;;;; +100FA;LINEAR B IDEOGRAM VESSEL B305;Lo;0;L;;;;;N;;;;; +10100;AEGEAN WORD SEPARATOR LINE;Po;0;L;;;;;N;;;;; +10101;AEGEAN WORD SEPARATOR DOT;Po;0;ON;;;;;N;;;;; +10102;AEGEAN CHECK MARK;Po;0;L;;;;;N;;;;; +10107;AEGEAN NUMBER ONE;No;0;L;;;;1;N;;;;; +10108;AEGEAN NUMBER TWO;No;0;L;;;;2;N;;;;; +10109;AEGEAN NUMBER THREE;No;0;L;;;;3;N;;;;; +1010A;AEGEAN NUMBER FOUR;No;0;L;;;;4;N;;;;; +1010B;AEGEAN NUMBER FIVE;No;0;L;;;;5;N;;;;; +1010C;AEGEAN NUMBER SIX;No;0;L;;;;6;N;;;;; +1010D;AEGEAN NUMBER SEVEN;No;0;L;;;;7;N;;;;; +1010E;AEGEAN NUMBER EIGHT;No;0;L;;;;8;N;;;;; +1010F;AEGEAN NUMBER NINE;No;0;L;;;;9;N;;;;; +10110;AEGEAN NUMBER TEN;No;0;L;;;;10;N;;;;; +10111;AEGEAN NUMBER TWENTY;No;0;L;;;;20;N;;;;; +10112;AEGEAN NUMBER THIRTY;No;0;L;;;;30;N;;;;; +10113;AEGEAN NUMBER FORTY;No;0;L;;;;40;N;;;;; +10114;AEGEAN NUMBER FIFTY;No;0;L;;;;50;N;;;;; +10115;AEGEAN NUMBER SIXTY;No;0;L;;;;60;N;;;;; +10116;AEGEAN NUMBER SEVENTY;No;0;L;;;;70;N;;;;; +10117;AEGEAN NUMBER EIGHTY;No;0;L;;;;80;N;;;;; +10118;AEGEAN NUMBER NINETY;No;0;L;;;;90;N;;;;; +10119;AEGEAN NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;; +1011A;AEGEAN NUMBER TWO HUNDRED;No;0;L;;;;200;N;;;;; +1011B;AEGEAN NUMBER THREE HUNDRED;No;0;L;;;;300;N;;;;; +1011C;AEGEAN NUMBER FOUR HUNDRED;No;0;L;;;;400;N;;;;; +1011D;AEGEAN NUMBER FIVE HUNDRED;No;0;L;;;;500;N;;;;; +1011E;AEGEAN NUMBER SIX HUNDRED;No;0;L;;;;600;N;;;;; +1011F;AEGEAN NUMBER SEVEN HUNDRED;No;0;L;;;;700;N;;;;; +10120;AEGEAN NUMBER EIGHT HUNDRED;No;0;L;;;;800;N;;;;; +10121;AEGEAN NUMBER NINE HUNDRED;No;0;L;;;;900;N;;;;; +10122;AEGEAN NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;; +10123;AEGEAN NUMBER TWO THOUSAND;No;0;L;;;;2000;N;;;;; +10124;AEGEAN NUMBER THREE THOUSAND;No;0;L;;;;3000;N;;;;; +10125;AEGEAN NUMBER FOUR THOUSAND;No;0;L;;;;4000;N;;;;; +10126;AEGEAN NUMBER FIVE THOUSAND;No;0;L;;;;5000;N;;;;; +10127;AEGEAN NUMBER SIX THOUSAND;No;0;L;;;;6000;N;;;;; +10128;AEGEAN NUMBER SEVEN THOUSAND;No;0;L;;;;7000;N;;;;; +10129;AEGEAN NUMBER EIGHT THOUSAND;No;0;L;;;;8000;N;;;;; +1012A;AEGEAN NUMBER NINE THOUSAND;No;0;L;;;;9000;N;;;;; +1012B;AEGEAN NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;; +1012C;AEGEAN NUMBER TWENTY THOUSAND;No;0;L;;;;20000;N;;;;; +1012D;AEGEAN NUMBER THIRTY THOUSAND;No;0;L;;;;30000;N;;;;; +1012E;AEGEAN NUMBER FORTY THOUSAND;No;0;L;;;;40000;N;;;;; +1012F;AEGEAN NUMBER FIFTY THOUSAND;No;0;L;;;;50000;N;;;;; +10130;AEGEAN NUMBER SIXTY THOUSAND;No;0;L;;;;60000;N;;;;; +10131;AEGEAN NUMBER SEVENTY THOUSAND;No;0;L;;;;70000;N;;;;; +10132;AEGEAN NUMBER EIGHTY THOUSAND;No;0;L;;;;80000;N;;;;; +10133;AEGEAN NUMBER NINETY THOUSAND;No;0;L;;;;90000;N;;;;; +10137;AEGEAN WEIGHT BASE UNIT;So;0;L;;;;;N;;;;; +10138;AEGEAN WEIGHT FIRST SUBUNIT;So;0;L;;;;;N;;;;; +10139;AEGEAN WEIGHT SECOND SUBUNIT;So;0;L;;;;;N;;;;; +1013A;AEGEAN WEIGHT THIRD SUBUNIT;So;0;L;;;;;N;;;;; +1013B;AEGEAN WEIGHT FOURTH SUBUNIT;So;0;L;;;;;N;;;;; +1013C;AEGEAN DRY MEASURE FIRST SUBUNIT;So;0;L;;;;;N;;;;; +1013D;AEGEAN LIQUID MEASURE FIRST SUBUNIT;So;0;L;;;;;N;;;;; +1013E;AEGEAN MEASURE SECOND SUBUNIT;So;0;L;;;;;N;;;;; +1013F;AEGEAN MEASURE THIRD SUBUNIT;So;0;L;;;;;N;;;;; +10140;GREEK ACROPHONIC ATTIC ONE QUARTER;Nl;0;ON;;;;1/4;N;;;;; +10141;GREEK ACROPHONIC ATTIC ONE HALF;Nl;0;ON;;;;1/2;N;;;;; +10142;GREEK ACROPHONIC ATTIC ONE DRACHMA;Nl;0;ON;;;;1;N;;;;; +10143;GREEK ACROPHONIC ATTIC FIVE;Nl;0;ON;;;;5;N;;;;; +10144;GREEK ACROPHONIC ATTIC FIFTY;Nl;0;ON;;;;50;N;;;;; +10145;GREEK ACROPHONIC ATTIC FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; +10146;GREEK ACROPHONIC ATTIC FIVE THOUSAND;Nl;0;ON;;;;5000;N;;;;; +10147;GREEK ACROPHONIC ATTIC FIFTY THOUSAND;Nl;0;ON;;;;50000;N;;;;; +10148;GREEK ACROPHONIC ATTIC FIVE TALENTS;Nl;0;ON;;;;5;N;;;;; +10149;GREEK ACROPHONIC ATTIC TEN TALENTS;Nl;0;ON;;;;10;N;;;;; +1014A;GREEK ACROPHONIC ATTIC FIFTY TALENTS;Nl;0;ON;;;;50;N;;;;; +1014B;GREEK ACROPHONIC ATTIC ONE HUNDRED TALENTS;Nl;0;ON;;;;100;N;;;;; +1014C;GREEK ACROPHONIC ATTIC FIVE HUNDRED TALENTS;Nl;0;ON;;;;500;N;;;;; +1014D;GREEK ACROPHONIC ATTIC ONE THOUSAND TALENTS;Nl;0;ON;;;;1000;N;;;;; +1014E;GREEK ACROPHONIC ATTIC FIVE THOUSAND TALENTS;Nl;0;ON;;;;5000;N;;;;; +1014F;GREEK ACROPHONIC ATTIC FIVE STATERS;Nl;0;ON;;;;5;N;;;;; +10150;GREEK ACROPHONIC ATTIC TEN STATERS;Nl;0;ON;;;;10;N;;;;; +10151;GREEK ACROPHONIC ATTIC FIFTY STATERS;Nl;0;ON;;;;50;N;;;;; +10152;GREEK ACROPHONIC ATTIC ONE HUNDRED STATERS;Nl;0;ON;;;;100;N;;;;; +10153;GREEK ACROPHONIC ATTIC FIVE HUNDRED STATERS;Nl;0;ON;;;;500;N;;;;; +10154;GREEK ACROPHONIC ATTIC ONE THOUSAND STATERS;Nl;0;ON;;;;1000;N;;;;; +10155;GREEK ACROPHONIC ATTIC TEN THOUSAND STATERS;Nl;0;ON;;;;10000;N;;;;; +10156;GREEK ACROPHONIC ATTIC FIFTY THOUSAND STATERS;Nl;0;ON;;;;50000;N;;;;; +10157;GREEK ACROPHONIC ATTIC TEN MNAS;Nl;0;ON;;;;10;N;;;;; +10158;GREEK ACROPHONIC HERAEUM ONE PLETHRON;Nl;0;ON;;;;1;N;;;;; +10159;GREEK ACROPHONIC THESPIAN ONE;Nl;0;ON;;;;1;N;;;;; +1015A;GREEK ACROPHONIC HERMIONIAN ONE;Nl;0;ON;;;;1;N;;;;; +1015B;GREEK ACROPHONIC EPIDAUREAN TWO;Nl;0;ON;;;;2;N;;;;; +1015C;GREEK ACROPHONIC THESPIAN TWO;Nl;0;ON;;;;2;N;;;;; +1015D;GREEK ACROPHONIC CYRENAIC TWO DRACHMAS;Nl;0;ON;;;;2;N;;;;; +1015E;GREEK ACROPHONIC EPIDAUREAN TWO DRACHMAS;Nl;0;ON;;;;2;N;;;;; +1015F;GREEK ACROPHONIC TROEZENIAN FIVE;Nl;0;ON;;;;5;N;;;;; +10160;GREEK ACROPHONIC TROEZENIAN TEN;Nl;0;ON;;;;10;N;;;;; +10161;GREEK ACROPHONIC TROEZENIAN TEN ALTERNATE FORM;Nl;0;ON;;;;10;N;;;;; +10162;GREEK ACROPHONIC HERMIONIAN TEN;Nl;0;ON;;;;10;N;;;;; +10163;GREEK ACROPHONIC MESSENIAN TEN;Nl;0;ON;;;;10;N;;;;; +10164;GREEK ACROPHONIC THESPIAN TEN;Nl;0;ON;;;;10;N;;;;; +10165;GREEK ACROPHONIC THESPIAN THIRTY;Nl;0;ON;;;;30;N;;;;; +10166;GREEK ACROPHONIC TROEZENIAN FIFTY;Nl;0;ON;;;;50;N;;;;; +10167;GREEK ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM;Nl;0;ON;;;;50;N;;;;; +10168;GREEK ACROPHONIC HERMIONIAN FIFTY;Nl;0;ON;;;;50;N;;;;; +10169;GREEK ACROPHONIC THESPIAN FIFTY;Nl;0;ON;;;;50;N;;;;; +1016A;GREEK ACROPHONIC THESPIAN ONE HUNDRED;Nl;0;ON;;;;100;N;;;;; +1016B;GREEK ACROPHONIC THESPIAN THREE HUNDRED;Nl;0;ON;;;;300;N;;;;; +1016C;GREEK ACROPHONIC EPIDAUREAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; +1016D;GREEK ACROPHONIC TROEZENIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; +1016E;GREEK ACROPHONIC THESPIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; +1016F;GREEK ACROPHONIC CARYSTIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; +10170;GREEK ACROPHONIC NAXIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; +10171;GREEK ACROPHONIC THESPIAN ONE THOUSAND;Nl;0;ON;;;;1000;N;;;;; +10172;GREEK ACROPHONIC THESPIAN FIVE THOUSAND;Nl;0;ON;;;;5000;N;;;;; +10173;GREEK ACROPHONIC DELPHIC FIVE MNAS;Nl;0;ON;;;;5;N;;;;; +10174;GREEK ACROPHONIC STRATIAN FIFTY MNAS;Nl;0;ON;;;;50;N;;;;; +10175;GREEK ONE HALF SIGN;No;0;ON;;;;1/2;N;;;;; +10176;GREEK ONE HALF SIGN ALTERNATE FORM;No;0;ON;;;;1/2;N;;;;; +10177;GREEK TWO THIRDS SIGN;No;0;ON;;;;2/3;N;;;;; +10178;GREEK THREE QUARTERS SIGN;No;0;ON;;;;3/4;N;;;;; +10179;GREEK YEAR SIGN;So;0;ON;;;;;N;;;;; +1017A;GREEK TALENT SIGN;So;0;ON;;;;;N;;;;; +1017B;GREEK DRACHMA SIGN;So;0;ON;;;;;N;;;;; +1017C;GREEK OBOL SIGN;So;0;ON;;;;;N;;;;; +1017D;GREEK TWO OBOLS SIGN;So;0;ON;;;;;N;;;;; +1017E;GREEK THREE OBOLS SIGN;So;0;ON;;;;;N;;;;; +1017F;GREEK FOUR OBOLS SIGN;So;0;ON;;;;;N;;;;; +10180;GREEK FIVE OBOLS SIGN;So;0;ON;;;;;N;;;;; +10181;GREEK METRETES SIGN;So;0;ON;;;;;N;;;;; +10182;GREEK KYATHOS BASE SIGN;So;0;ON;;;;;N;;;;; +10183;GREEK LITRA SIGN;So;0;ON;;;;;N;;;;; +10184;GREEK OUNKIA SIGN;So;0;ON;;;;;N;;;;; +10185;GREEK XESTES SIGN;So;0;ON;;;;;N;;;;; +10186;GREEK ARTABE SIGN;So;0;ON;;;;;N;;;;; +10187;GREEK AROURA SIGN;So;0;ON;;;;;N;;;;; +10188;GREEK GRAMMA SIGN;So;0;ON;;;;;N;;;;; +10189;GREEK TRYBLION BASE SIGN;So;0;ON;;;;;N;;;;; +1018A;GREEK ZERO SIGN;No;0;ON;;;;0;N;;;;; +1018B;GREEK ONE QUARTER SIGN;No;0;ON;;;;1/4;N;;;;; +1018C;GREEK SINUSOID SIGN;So;0;ON;;;;;N;;;;; +1018D;GREEK INDICTION SIGN;So;0;L;;;;;N;;;;; +1018E;NOMISMA SIGN;So;0;L;;;;;N;;;;; +10190;ROMAN SEXTANS SIGN;So;0;ON;;;;;N;;;;; +10191;ROMAN UNCIA SIGN;So;0;ON;;;;;N;;;;; +10192;ROMAN SEMUNCIA SIGN;So;0;ON;;;;;N;;;;; +10193;ROMAN SEXTULA SIGN;So;0;ON;;;;;N;;;;; +10194;ROMAN DIMIDIA SEXTULA SIGN;So;0;ON;;;;;N;;;;; +10195;ROMAN SILIQUA SIGN;So;0;ON;;;;;N;;;;; +10196;ROMAN DENARIUS SIGN;So;0;ON;;;;;N;;;;; +10197;ROMAN QUINARIUS SIGN;So;0;ON;;;;;N;;;;; +10198;ROMAN SESTERTIUS SIGN;So;0;ON;;;;;N;;;;; +10199;ROMAN DUPONDIUS SIGN;So;0;ON;;;;;N;;;;; +1019A;ROMAN AS SIGN;So;0;ON;;;;;N;;;;; +1019B;ROMAN CENTURIAL SIGN;So;0;ON;;;;;N;;;;; +1019C;ASCIA SYMBOL;So;0;ON;;;;;N;;;;; +101A0;GREEK SYMBOL TAU RHO;So;0;ON;;;;;N;;;;; +101D0;PHAISTOS DISC SIGN PEDESTRIAN;So;0;L;;;;;N;;;;; +101D1;PHAISTOS DISC SIGN PLUMED HEAD;So;0;L;;;;;N;;;;; +101D2;PHAISTOS DISC SIGN TATTOOED HEAD;So;0;L;;;;;N;;;;; +101D3;PHAISTOS DISC SIGN CAPTIVE;So;0;L;;;;;N;;;;; +101D4;PHAISTOS DISC SIGN CHILD;So;0;L;;;;;N;;;;; +101D5;PHAISTOS DISC SIGN WOMAN;So;0;L;;;;;N;;;;; +101D6;PHAISTOS DISC SIGN HELMET;So;0;L;;;;;N;;;;; +101D7;PHAISTOS DISC SIGN GAUNTLET;So;0;L;;;;;N;;;;; +101D8;PHAISTOS DISC SIGN TIARA;So;0;L;;;;;N;;;;; +101D9;PHAISTOS DISC SIGN ARROW;So;0;L;;;;;N;;;;; +101DA;PHAISTOS DISC SIGN BOW;So;0;L;;;;;N;;;;; +101DB;PHAISTOS DISC SIGN SHIELD;So;0;L;;;;;N;;;;; +101DC;PHAISTOS DISC SIGN CLUB;So;0;L;;;;;N;;;;; +101DD;PHAISTOS DISC SIGN MANACLES;So;0;L;;;;;N;;;;; +101DE;PHAISTOS DISC SIGN MATTOCK;So;0;L;;;;;N;;;;; +101DF;PHAISTOS DISC SIGN SAW;So;0;L;;;;;N;;;;; +101E0;PHAISTOS DISC SIGN LID;So;0;L;;;;;N;;;;; +101E1;PHAISTOS DISC SIGN BOOMERANG;So;0;L;;;;;N;;;;; +101E2;PHAISTOS DISC SIGN CARPENTRY PLANE;So;0;L;;;;;N;;;;; +101E3;PHAISTOS DISC SIGN DOLIUM;So;0;L;;;;;N;;;;; +101E4;PHAISTOS DISC SIGN COMB;So;0;L;;;;;N;;;;; +101E5;PHAISTOS DISC SIGN SLING;So;0;L;;;;;N;;;;; +101E6;PHAISTOS DISC SIGN COLUMN;So;0;L;;;;;N;;;;; +101E7;PHAISTOS DISC SIGN BEEHIVE;So;0;L;;;;;N;;;;; +101E8;PHAISTOS DISC SIGN SHIP;So;0;L;;;;;N;;;;; +101E9;PHAISTOS DISC SIGN HORN;So;0;L;;;;;N;;;;; +101EA;PHAISTOS DISC SIGN HIDE;So;0;L;;;;;N;;;;; +101EB;PHAISTOS DISC SIGN BULLS LEG;So;0;L;;;;;N;;;;; +101EC;PHAISTOS DISC SIGN CAT;So;0;L;;;;;N;;;;; +101ED;PHAISTOS DISC SIGN RAM;So;0;L;;;;;N;;;;; +101EE;PHAISTOS DISC SIGN EAGLE;So;0;L;;;;;N;;;;; +101EF;PHAISTOS DISC SIGN DOVE;So;0;L;;;;;N;;;;; +101F0;PHAISTOS DISC SIGN TUNNY;So;0;L;;;;;N;;;;; +101F1;PHAISTOS DISC SIGN BEE;So;0;L;;;;;N;;;;; +101F2;PHAISTOS DISC SIGN PLANE TREE;So;0;L;;;;;N;;;;; +101F3;PHAISTOS DISC SIGN VINE;So;0;L;;;;;N;;;;; +101F4;PHAISTOS DISC SIGN PAPYRUS;So;0;L;;;;;N;;;;; +101F5;PHAISTOS DISC SIGN ROSETTE;So;0;L;;;;;N;;;;; +101F6;PHAISTOS DISC SIGN LILY;So;0;L;;;;;N;;;;; +101F7;PHAISTOS DISC SIGN OX BACK;So;0;L;;;;;N;;;;; +101F8;PHAISTOS DISC SIGN FLUTE;So;0;L;;;;;N;;;;; +101F9;PHAISTOS DISC SIGN GRATER;So;0;L;;;;;N;;;;; +101FA;PHAISTOS DISC SIGN STRAINER;So;0;L;;;;;N;;;;; +101FB;PHAISTOS DISC SIGN SMALL AXE;So;0;L;;;;;N;;;;; +101FC;PHAISTOS DISC SIGN WAVY BAND;So;0;L;;;;;N;;;;; +101FD;PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE;Mn;220;NSM;;;;;N;;;;; +10280;LYCIAN LETTER A;Lo;0;L;;;;;N;;;;; +10281;LYCIAN LETTER E;Lo;0;L;;;;;N;;;;; +10282;LYCIAN LETTER B;Lo;0;L;;;;;N;;;;; +10283;LYCIAN LETTER BH;Lo;0;L;;;;;N;;;;; +10284;LYCIAN LETTER G;Lo;0;L;;;;;N;;;;; +10285;LYCIAN LETTER D;Lo;0;L;;;;;N;;;;; +10286;LYCIAN LETTER I;Lo;0;L;;;;;N;;;;; +10287;LYCIAN LETTER W;Lo;0;L;;;;;N;;;;; +10288;LYCIAN LETTER Z;Lo;0;L;;;;;N;;;;; +10289;LYCIAN LETTER TH;Lo;0;L;;;;;N;;;;; +1028A;LYCIAN LETTER J;Lo;0;L;;;;;N;;;;; +1028B;LYCIAN LETTER K;Lo;0;L;;;;;N;;;;; +1028C;LYCIAN LETTER Q;Lo;0;L;;;;;N;;;;; +1028D;LYCIAN LETTER L;Lo;0;L;;;;;N;;;;; +1028E;LYCIAN LETTER M;Lo;0;L;;;;;N;;;;; +1028F;LYCIAN LETTER N;Lo;0;L;;;;;N;;;;; +10290;LYCIAN LETTER MM;Lo;0;L;;;;;N;;;;; +10291;LYCIAN LETTER NN;Lo;0;L;;;;;N;;;;; +10292;LYCIAN LETTER U;Lo;0;L;;;;;N;;;;; +10293;LYCIAN LETTER P;Lo;0;L;;;;;N;;;;; +10294;LYCIAN LETTER KK;Lo;0;L;;;;;N;;;;; +10295;LYCIAN LETTER R;Lo;0;L;;;;;N;;;;; +10296;LYCIAN LETTER S;Lo;0;L;;;;;N;;;;; +10297;LYCIAN LETTER T;Lo;0;L;;;;;N;;;;; +10298;LYCIAN LETTER TT;Lo;0;L;;;;;N;;;;; +10299;LYCIAN LETTER AN;Lo;0;L;;;;;N;;;;; +1029A;LYCIAN LETTER EN;Lo;0;L;;;;;N;;;;; +1029B;LYCIAN LETTER H;Lo;0;L;;;;;N;;;;; +1029C;LYCIAN LETTER X;Lo;0;L;;;;;N;;;;; +102A0;CARIAN LETTER A;Lo;0;L;;;;;N;;;;; +102A1;CARIAN LETTER P2;Lo;0;L;;;;;N;;;;; +102A2;CARIAN LETTER D;Lo;0;L;;;;;N;;;;; +102A3;CARIAN LETTER L;Lo;0;L;;;;;N;;;;; +102A4;CARIAN LETTER UUU;Lo;0;L;;;;;N;;;;; +102A5;CARIAN LETTER R;Lo;0;L;;;;;N;;;;; +102A6;CARIAN LETTER LD;Lo;0;L;;;;;N;;;;; +102A7;CARIAN LETTER A2;Lo;0;L;;;;;N;;;;; +102A8;CARIAN LETTER Q;Lo;0;L;;;;;N;;;;; +102A9;CARIAN LETTER B;Lo;0;L;;;;;N;;;;; +102AA;CARIAN LETTER M;Lo;0;L;;;;;N;;;;; +102AB;CARIAN LETTER O;Lo;0;L;;;;;N;;;;; +102AC;CARIAN LETTER D2;Lo;0;L;;;;;N;;;;; +102AD;CARIAN LETTER T;Lo;0;L;;;;;N;;;;; +102AE;CARIAN LETTER SH;Lo;0;L;;;;;N;;;;; +102AF;CARIAN LETTER SH2;Lo;0;L;;;;;N;;;;; +102B0;CARIAN LETTER S;Lo;0;L;;;;;N;;;;; +102B1;CARIAN LETTER C-18;Lo;0;L;;;;;N;;;;; +102B2;CARIAN LETTER U;Lo;0;L;;;;;N;;;;; +102B3;CARIAN LETTER NN;Lo;0;L;;;;;N;;;;; +102B4;CARIAN LETTER X;Lo;0;L;;;;;N;;;;; +102B5;CARIAN LETTER N;Lo;0;L;;;;;N;;;;; +102B6;CARIAN LETTER TT2;Lo;0;L;;;;;N;;;;; +102B7;CARIAN LETTER P;Lo;0;L;;;;;N;;;;; +102B8;CARIAN LETTER SS;Lo;0;L;;;;;N;;;;; +102B9;CARIAN LETTER I;Lo;0;L;;;;;N;;;;; +102BA;CARIAN LETTER E;Lo;0;L;;;;;N;;;;; +102BB;CARIAN LETTER UUUU;Lo;0;L;;;;;N;;;;; +102BC;CARIAN LETTER K;Lo;0;L;;;;;N;;;;; +102BD;CARIAN LETTER K2;Lo;0;L;;;;;N;;;;; +102BE;CARIAN LETTER ND;Lo;0;L;;;;;N;;;;; +102BF;CARIAN LETTER UU;Lo;0;L;;;;;N;;;;; +102C0;CARIAN LETTER G;Lo;0;L;;;;;N;;;;; +102C1;CARIAN LETTER G2;Lo;0;L;;;;;N;;;;; +102C2;CARIAN LETTER ST;Lo;0;L;;;;;N;;;;; +102C3;CARIAN LETTER ST2;Lo;0;L;;;;;N;;;;; +102C4;CARIAN LETTER NG;Lo;0;L;;;;;N;;;;; +102C5;CARIAN LETTER II;Lo;0;L;;;;;N;;;;; +102C6;CARIAN LETTER C-39;Lo;0;L;;;;;N;;;;; +102C7;CARIAN LETTER TT;Lo;0;L;;;;;N;;;;; +102C8;CARIAN LETTER UUU2;Lo;0;L;;;;;N;;;;; +102C9;CARIAN LETTER RR;Lo;0;L;;;;;N;;;;; +102CA;CARIAN LETTER MB;Lo;0;L;;;;;N;;;;; +102CB;CARIAN LETTER MB2;Lo;0;L;;;;;N;;;;; +102CC;CARIAN LETTER MB3;Lo;0;L;;;;;N;;;;; +102CD;CARIAN LETTER MB4;Lo;0;L;;;;;N;;;;; +102CE;CARIAN LETTER LD2;Lo;0;L;;;;;N;;;;; +102CF;CARIAN LETTER E2;Lo;0;L;;;;;N;;;;; +102D0;CARIAN LETTER UUU3;Lo;0;L;;;;;N;;;;; +102E0;COPTIC EPACT THOUSANDS MARK;Mn;220;NSM;;;;;N;;;;; +102E1;COPTIC EPACT DIGIT ONE;No;0;EN;;;;1;N;;;;; +102E2;COPTIC EPACT DIGIT TWO;No;0;EN;;;;2;N;;;;; +102E3;COPTIC EPACT DIGIT THREE;No;0;EN;;;;3;N;;;;; +102E4;COPTIC EPACT DIGIT FOUR;No;0;EN;;;;4;N;;;;; +102E5;COPTIC EPACT DIGIT FIVE;No;0;EN;;;;5;N;;;;; +102E6;COPTIC EPACT DIGIT SIX;No;0;EN;;;;6;N;;;;; +102E7;COPTIC EPACT DIGIT SEVEN;No;0;EN;;;;7;N;;;;; +102E8;COPTIC EPACT DIGIT EIGHT;No;0;EN;;;;8;N;;;;; +102E9;COPTIC EPACT DIGIT NINE;No;0;EN;;;;9;N;;;;; +102EA;COPTIC EPACT NUMBER TEN;No;0;EN;;;;10;N;;;;; +102EB;COPTIC EPACT NUMBER TWENTY;No;0;EN;;;;20;N;;;;; +102EC;COPTIC EPACT NUMBER THIRTY;No;0;EN;;;;30;N;;;;; +102ED;COPTIC EPACT NUMBER FORTY;No;0;EN;;;;40;N;;;;; +102EE;COPTIC EPACT NUMBER FIFTY;No;0;EN;;;;50;N;;;;; +102EF;COPTIC EPACT NUMBER SIXTY;No;0;EN;;;;60;N;;;;; +102F0;COPTIC EPACT NUMBER SEVENTY;No;0;EN;;;;70;N;;;;; +102F1;COPTIC EPACT NUMBER EIGHTY;No;0;EN;;;;80;N;;;;; +102F2;COPTIC EPACT NUMBER NINETY;No;0;EN;;;;90;N;;;;; +102F3;COPTIC EPACT NUMBER ONE HUNDRED;No;0;EN;;;;100;N;;;;; +102F4;COPTIC EPACT NUMBER TWO HUNDRED;No;0;EN;;;;200;N;;;;; +102F5;COPTIC EPACT NUMBER THREE HUNDRED;No;0;EN;;;;300;N;;;;; +102F6;COPTIC EPACT NUMBER FOUR HUNDRED;No;0;EN;;;;400;N;;;;; +102F7;COPTIC EPACT NUMBER FIVE HUNDRED;No;0;EN;;;;500;N;;;;; +102F8;COPTIC EPACT NUMBER SIX HUNDRED;No;0;EN;;;;600;N;;;;; +102F9;COPTIC EPACT NUMBER SEVEN HUNDRED;No;0;EN;;;;700;N;;;;; +102FA;COPTIC EPACT NUMBER EIGHT HUNDRED;No;0;EN;;;;800;N;;;;; +102FB;COPTIC EPACT NUMBER NINE HUNDRED;No;0;EN;;;;900;N;;;;; +10300;OLD ITALIC LETTER A;Lo;0;L;;;;;N;;;;; +10301;OLD ITALIC LETTER BE;Lo;0;L;;;;;N;;;;; +10302;OLD ITALIC LETTER KE;Lo;0;L;;;;;N;;;;; +10303;OLD ITALIC LETTER DE;Lo;0;L;;;;;N;;;;; +10304;OLD ITALIC LETTER E;Lo;0;L;;;;;N;;;;; +10305;OLD ITALIC LETTER VE;Lo;0;L;;;;;N;;;;; +10306;OLD ITALIC LETTER ZE;Lo;0;L;;;;;N;;;;; +10307;OLD ITALIC LETTER HE;Lo;0;L;;;;;N;;;;; +10308;OLD ITALIC LETTER THE;Lo;0;L;;;;;N;;;;; +10309;OLD ITALIC LETTER I;Lo;0;L;;;;;N;;;;; +1030A;OLD ITALIC LETTER KA;Lo;0;L;;;;;N;;;;; +1030B;OLD ITALIC LETTER EL;Lo;0;L;;;;;N;;;;; +1030C;OLD ITALIC LETTER EM;Lo;0;L;;;;;N;;;;; +1030D;OLD ITALIC LETTER EN;Lo;0;L;;;;;N;;;;; +1030E;OLD ITALIC LETTER ESH;Lo;0;L;;;;;N;;;;; +1030F;OLD ITALIC LETTER O;Lo;0;L;;;;;N;;;;; +10310;OLD ITALIC LETTER PE;Lo;0;L;;;;;N;;;;; +10311;OLD ITALIC LETTER SHE;Lo;0;L;;;;;N;;;;; +10312;OLD ITALIC LETTER KU;Lo;0;L;;;;;N;;;;; +10313;OLD ITALIC LETTER ER;Lo;0;L;;;;;N;;;;; +10314;OLD ITALIC LETTER ES;Lo;0;L;;;;;N;;;;; +10315;OLD ITALIC LETTER TE;Lo;0;L;;;;;N;;;;; +10316;OLD ITALIC LETTER U;Lo;0;L;;;;;N;;;;; +10317;OLD ITALIC LETTER EKS;Lo;0;L;;;;;N;;;;; +10318;OLD ITALIC LETTER PHE;Lo;0;L;;;;;N;;;;; +10319;OLD ITALIC LETTER KHE;Lo;0;L;;;;;N;;;;; +1031A;OLD ITALIC LETTER EF;Lo;0;L;;;;;N;;;;; +1031B;OLD ITALIC LETTER ERS;Lo;0;L;;;;;N;;;;; +1031C;OLD ITALIC LETTER CHE;Lo;0;L;;;;;N;;;;; +1031D;OLD ITALIC LETTER II;Lo;0;L;;;;;N;;;;; +1031E;OLD ITALIC LETTER UU;Lo;0;L;;;;;N;;;;; +1031F;OLD ITALIC LETTER ESS;Lo;0;L;;;;;N;;;;; +10320;OLD ITALIC NUMERAL ONE;No;0;L;;;;1;N;;;;; +10321;OLD ITALIC NUMERAL FIVE;No;0;L;;;;5;N;;;;; +10322;OLD ITALIC NUMERAL TEN;No;0;L;;;;10;N;;;;; +10323;OLD ITALIC NUMERAL FIFTY;No;0;L;;;;50;N;;;;; +1032D;OLD ITALIC LETTER YE;Lo;0;L;;;;;N;;;;; +1032E;OLD ITALIC LETTER NORTHERN TSE;Lo;0;L;;;;;N;;;;; +1032F;OLD ITALIC LETTER SOUTHERN TSE;Lo;0;L;;;;;N;;;;; +10330;GOTHIC LETTER AHSA;Lo;0;L;;;;;N;;;;; +10331;GOTHIC LETTER BAIRKAN;Lo;0;L;;;;;N;;;;; +10332;GOTHIC LETTER GIBA;Lo;0;L;;;;;N;;;;; +10333;GOTHIC LETTER DAGS;Lo;0;L;;;;;N;;;;; +10334;GOTHIC LETTER AIHVUS;Lo;0;L;;;;;N;;;;; +10335;GOTHIC LETTER QAIRTHRA;Lo;0;L;;;;;N;;;;; +10336;GOTHIC LETTER IUJA;Lo;0;L;;;;;N;;;;; +10337;GOTHIC LETTER HAGL;Lo;0;L;;;;;N;;;;; +10338;GOTHIC LETTER THIUTH;Lo;0;L;;;;;N;;;;; +10339;GOTHIC LETTER EIS;Lo;0;L;;;;;N;;;;; +1033A;GOTHIC LETTER KUSMA;Lo;0;L;;;;;N;;;;; +1033B;GOTHIC LETTER LAGUS;Lo;0;L;;;;;N;;;;; +1033C;GOTHIC LETTER MANNA;Lo;0;L;;;;;N;;;;; +1033D;GOTHIC LETTER NAUTHS;Lo;0;L;;;;;N;;;;; +1033E;GOTHIC LETTER JER;Lo;0;L;;;;;N;;;;; +1033F;GOTHIC LETTER URUS;Lo;0;L;;;;;N;;;;; +10340;GOTHIC LETTER PAIRTHRA;Lo;0;L;;;;;N;;;;; +10341;GOTHIC LETTER NINETY;Nl;0;L;;;;90;N;;;;; +10342;GOTHIC LETTER RAIDA;Lo;0;L;;;;;N;;;;; +10343;GOTHIC LETTER SAUIL;Lo;0;L;;;;;N;;;;; +10344;GOTHIC LETTER TEIWS;Lo;0;L;;;;;N;;;;; +10345;GOTHIC LETTER WINJA;Lo;0;L;;;;;N;;;;; +10346;GOTHIC LETTER FAIHU;Lo;0;L;;;;;N;;;;; +10347;GOTHIC LETTER IGGWS;Lo;0;L;;;;;N;;;;; +10348;GOTHIC LETTER HWAIR;Lo;0;L;;;;;N;;;;; +10349;GOTHIC LETTER OTHAL;Lo;0;L;;;;;N;;;;; +1034A;GOTHIC LETTER NINE HUNDRED;Nl;0;L;;;;900;N;;;;; +10350;OLD PERMIC LETTER AN;Lo;0;L;;;;;N;;;;; +10351;OLD PERMIC LETTER BUR;Lo;0;L;;;;;N;;;;; +10352;OLD PERMIC LETTER GAI;Lo;0;L;;;;;N;;;;; +10353;OLD PERMIC LETTER DOI;Lo;0;L;;;;;N;;;;; +10354;OLD PERMIC LETTER E;Lo;0;L;;;;;N;;;;; +10355;OLD PERMIC LETTER ZHOI;Lo;0;L;;;;;N;;;;; +10356;OLD PERMIC LETTER DZHOI;Lo;0;L;;;;;N;;;;; +10357;OLD PERMIC LETTER ZATA;Lo;0;L;;;;;N;;;;; +10358;OLD PERMIC LETTER DZITA;Lo;0;L;;;;;N;;;;; +10359;OLD PERMIC LETTER I;Lo;0;L;;;;;N;;;;; +1035A;OLD PERMIC LETTER KOKE;Lo;0;L;;;;;N;;;;; +1035B;OLD PERMIC LETTER LEI;Lo;0;L;;;;;N;;;;; +1035C;OLD PERMIC LETTER MENOE;Lo;0;L;;;;;N;;;;; +1035D;OLD PERMIC LETTER NENOE;Lo;0;L;;;;;N;;;;; +1035E;OLD PERMIC LETTER VOOI;Lo;0;L;;;;;N;;;;; +1035F;OLD PERMIC LETTER PEEI;Lo;0;L;;;;;N;;;;; +10360;OLD PERMIC LETTER REI;Lo;0;L;;;;;N;;;;; +10361;OLD PERMIC LETTER SII;Lo;0;L;;;;;N;;;;; +10362;OLD PERMIC LETTER TAI;Lo;0;L;;;;;N;;;;; +10363;OLD PERMIC LETTER U;Lo;0;L;;;;;N;;;;; +10364;OLD PERMIC LETTER CHERY;Lo;0;L;;;;;N;;;;; +10365;OLD PERMIC LETTER SHOOI;Lo;0;L;;;;;N;;;;; +10366;OLD PERMIC LETTER SHCHOOI;Lo;0;L;;;;;N;;;;; +10367;OLD PERMIC LETTER YRY;Lo;0;L;;;;;N;;;;; +10368;OLD PERMIC LETTER YERU;Lo;0;L;;;;;N;;;;; +10369;OLD PERMIC LETTER O;Lo;0;L;;;;;N;;;;; +1036A;OLD PERMIC LETTER OO;Lo;0;L;;;;;N;;;;; +1036B;OLD PERMIC LETTER EF;Lo;0;L;;;;;N;;;;; +1036C;OLD PERMIC LETTER HA;Lo;0;L;;;;;N;;;;; +1036D;OLD PERMIC LETTER TSIU;Lo;0;L;;;;;N;;;;; +1036E;OLD PERMIC LETTER VER;Lo;0;L;;;;;N;;;;; +1036F;OLD PERMIC LETTER YER;Lo;0;L;;;;;N;;;;; +10370;OLD PERMIC LETTER YERI;Lo;0;L;;;;;N;;;;; +10371;OLD PERMIC LETTER YAT;Lo;0;L;;;;;N;;;;; +10372;OLD PERMIC LETTER IE;Lo;0;L;;;;;N;;;;; +10373;OLD PERMIC LETTER YU;Lo;0;L;;;;;N;;;;; +10374;OLD PERMIC LETTER YA;Lo;0;L;;;;;N;;;;; +10375;OLD PERMIC LETTER IA;Lo;0;L;;;;;N;;;;; +10376;COMBINING OLD PERMIC LETTER AN;Mn;230;NSM;;;;;N;;;;; +10377;COMBINING OLD PERMIC LETTER DOI;Mn;230;NSM;;;;;N;;;;; +10378;COMBINING OLD PERMIC LETTER ZATA;Mn;230;NSM;;;;;N;;;;; +10379;COMBINING OLD PERMIC LETTER NENOE;Mn;230;NSM;;;;;N;;;;; +1037A;COMBINING OLD PERMIC LETTER SII;Mn;230;NSM;;;;;N;;;;; +10380;UGARITIC LETTER ALPA;Lo;0;L;;;;;N;;;;; +10381;UGARITIC LETTER BETA;Lo;0;L;;;;;N;;;;; +10382;UGARITIC LETTER GAMLA;Lo;0;L;;;;;N;;;;; +10383;UGARITIC LETTER KHA;Lo;0;L;;;;;N;;;;; +10384;UGARITIC LETTER DELTA;Lo;0;L;;;;;N;;;;; +10385;UGARITIC LETTER HO;Lo;0;L;;;;;N;;;;; +10386;UGARITIC LETTER WO;Lo;0;L;;;;;N;;;;; +10387;UGARITIC LETTER ZETA;Lo;0;L;;;;;N;;;;; +10388;UGARITIC LETTER HOTA;Lo;0;L;;;;;N;;;;; +10389;UGARITIC LETTER TET;Lo;0;L;;;;;N;;;;; +1038A;UGARITIC LETTER YOD;Lo;0;L;;;;;N;;;;; +1038B;UGARITIC LETTER KAF;Lo;0;L;;;;;N;;;;; +1038C;UGARITIC LETTER SHIN;Lo;0;L;;;;;N;;;;; +1038D;UGARITIC LETTER LAMDA;Lo;0;L;;;;;N;;;;; +1038E;UGARITIC LETTER MEM;Lo;0;L;;;;;N;;;;; +1038F;UGARITIC LETTER DHAL;Lo;0;L;;;;;N;;;;; +10390;UGARITIC LETTER NUN;Lo;0;L;;;;;N;;;;; +10391;UGARITIC LETTER ZU;Lo;0;L;;;;;N;;;;; +10392;UGARITIC LETTER SAMKA;Lo;0;L;;;;;N;;;;; +10393;UGARITIC LETTER AIN;Lo;0;L;;;;;N;;;;; +10394;UGARITIC LETTER PU;Lo;0;L;;;;;N;;;;; +10395;UGARITIC LETTER SADE;Lo;0;L;;;;;N;;;;; +10396;UGARITIC LETTER QOPA;Lo;0;L;;;;;N;;;;; +10397;UGARITIC LETTER RASHA;Lo;0;L;;;;;N;;;;; +10398;UGARITIC LETTER THANNA;Lo;0;L;;;;;N;;;;; +10399;UGARITIC LETTER GHAIN;Lo;0;L;;;;;N;;;;; +1039A;UGARITIC LETTER TO;Lo;0;L;;;;;N;;;;; +1039B;UGARITIC LETTER I;Lo;0;L;;;;;N;;;;; +1039C;UGARITIC LETTER U;Lo;0;L;;;;;N;;;;; +1039D;UGARITIC LETTER SSU;Lo;0;L;;;;;N;;;;; +1039F;UGARITIC WORD DIVIDER;Po;0;L;;;;;N;;;;; +103A0;OLD PERSIAN SIGN A;Lo;0;L;;;;;N;;;;; +103A1;OLD PERSIAN SIGN I;Lo;0;L;;;;;N;;;;; +103A2;OLD PERSIAN SIGN U;Lo;0;L;;;;;N;;;;; +103A3;OLD PERSIAN SIGN KA;Lo;0;L;;;;;N;;;;; +103A4;OLD PERSIAN SIGN KU;Lo;0;L;;;;;N;;;;; +103A5;OLD PERSIAN SIGN GA;Lo;0;L;;;;;N;;;;; +103A6;OLD PERSIAN SIGN GU;Lo;0;L;;;;;N;;;;; +103A7;OLD PERSIAN SIGN XA;Lo;0;L;;;;;N;;;;; +103A8;OLD PERSIAN SIGN CA;Lo;0;L;;;;;N;;;;; +103A9;OLD PERSIAN SIGN JA;Lo;0;L;;;;;N;;;;; +103AA;OLD PERSIAN SIGN JI;Lo;0;L;;;;;N;;;;; +103AB;OLD PERSIAN SIGN TA;Lo;0;L;;;;;N;;;;; +103AC;OLD PERSIAN SIGN TU;Lo;0;L;;;;;N;;;;; +103AD;OLD PERSIAN SIGN DA;Lo;0;L;;;;;N;;;;; +103AE;OLD PERSIAN SIGN DI;Lo;0;L;;;;;N;;;;; +103AF;OLD PERSIAN SIGN DU;Lo;0;L;;;;;N;;;;; +103B0;OLD PERSIAN SIGN THA;Lo;0;L;;;;;N;;;;; +103B1;OLD PERSIAN SIGN PA;Lo;0;L;;;;;N;;;;; +103B2;OLD PERSIAN SIGN BA;Lo;0;L;;;;;N;;;;; +103B3;OLD PERSIAN SIGN FA;Lo;0;L;;;;;N;;;;; +103B4;OLD PERSIAN SIGN NA;Lo;0;L;;;;;N;;;;; +103B5;OLD PERSIAN SIGN NU;Lo;0;L;;;;;N;;;;; +103B6;OLD PERSIAN SIGN MA;Lo;0;L;;;;;N;;;;; +103B7;OLD PERSIAN SIGN MI;Lo;0;L;;;;;N;;;;; +103B8;OLD PERSIAN SIGN MU;Lo;0;L;;;;;N;;;;; +103B9;OLD PERSIAN SIGN YA;Lo;0;L;;;;;N;;;;; +103BA;OLD PERSIAN SIGN VA;Lo;0;L;;;;;N;;;;; +103BB;OLD PERSIAN SIGN VI;Lo;0;L;;;;;N;;;;; +103BC;OLD PERSIAN SIGN RA;Lo;0;L;;;;;N;;;;; +103BD;OLD PERSIAN SIGN RU;Lo;0;L;;;;;N;;;;; +103BE;OLD PERSIAN SIGN LA;Lo;0;L;;;;;N;;;;; +103BF;OLD PERSIAN SIGN SA;Lo;0;L;;;;;N;;;;; +103C0;OLD PERSIAN SIGN ZA;Lo;0;L;;;;;N;;;;; +103C1;OLD PERSIAN SIGN SHA;Lo;0;L;;;;;N;;;;; +103C2;OLD PERSIAN SIGN SSA;Lo;0;L;;;;;N;;;;; +103C3;OLD PERSIAN SIGN HA;Lo;0;L;;;;;N;;;;; +103C8;OLD PERSIAN SIGN AURAMAZDAA;Lo;0;L;;;;;N;;;;; +103C9;OLD PERSIAN SIGN AURAMAZDAA-2;Lo;0;L;;;;;N;;;;; +103CA;OLD PERSIAN SIGN AURAMAZDAAHA;Lo;0;L;;;;;N;;;;; +103CB;OLD PERSIAN SIGN XSHAAYATHIYA;Lo;0;L;;;;;N;;;;; +103CC;OLD PERSIAN SIGN DAHYAAUSH;Lo;0;L;;;;;N;;;;; +103CD;OLD PERSIAN SIGN DAHYAAUSH-2;Lo;0;L;;;;;N;;;;; +103CE;OLD PERSIAN SIGN BAGA;Lo;0;L;;;;;N;;;;; +103CF;OLD PERSIAN SIGN BUUMISH;Lo;0;L;;;;;N;;;;; +103D0;OLD PERSIAN WORD DIVIDER;Po;0;L;;;;;N;;;;; +103D1;OLD PERSIAN NUMBER ONE;Nl;0;L;;;;1;N;;;;; +103D2;OLD PERSIAN NUMBER TWO;Nl;0;L;;;;2;N;;;;; +103D3;OLD PERSIAN NUMBER TEN;Nl;0;L;;;;10;N;;;;; +103D4;OLD PERSIAN NUMBER TWENTY;Nl;0;L;;;;20;N;;;;; +103D5;OLD PERSIAN NUMBER HUNDRED;Nl;0;L;;;;100;N;;;;; +10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428; +10401;DESERET CAPITAL LETTER LONG E;Lu;0;L;;;;;N;;;;10429; +10402;DESERET CAPITAL LETTER LONG A;Lu;0;L;;;;;N;;;;1042A; +10403;DESERET CAPITAL LETTER LONG AH;Lu;0;L;;;;;N;;;;1042B; +10404;DESERET CAPITAL LETTER LONG O;Lu;0;L;;;;;N;;;;1042C; +10405;DESERET CAPITAL LETTER LONG OO;Lu;0;L;;;;;N;;;;1042D; +10406;DESERET CAPITAL LETTER SHORT I;Lu;0;L;;;;;N;;;;1042E; +10407;DESERET CAPITAL LETTER SHORT E;Lu;0;L;;;;;N;;;;1042F; +10408;DESERET CAPITAL LETTER SHORT A;Lu;0;L;;;;;N;;;;10430; +10409;DESERET CAPITAL LETTER SHORT AH;Lu;0;L;;;;;N;;;;10431; +1040A;DESERET CAPITAL LETTER SHORT O;Lu;0;L;;;;;N;;;;10432; +1040B;DESERET CAPITAL LETTER SHORT OO;Lu;0;L;;;;;N;;;;10433; +1040C;DESERET CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;10434; +1040D;DESERET CAPITAL LETTER OW;Lu;0;L;;;;;N;;;;10435; +1040E;DESERET CAPITAL LETTER WU;Lu;0;L;;;;;N;;;;10436; +1040F;DESERET CAPITAL LETTER YEE;Lu;0;L;;;;;N;;;;10437; +10410;DESERET CAPITAL LETTER H;Lu;0;L;;;;;N;;;;10438; +10411;DESERET CAPITAL LETTER PEE;Lu;0;L;;;;;N;;;;10439; +10412;DESERET CAPITAL LETTER BEE;Lu;0;L;;;;;N;;;;1043A; +10413;DESERET CAPITAL LETTER TEE;Lu;0;L;;;;;N;;;;1043B; +10414;DESERET CAPITAL LETTER DEE;Lu;0;L;;;;;N;;;;1043C; +10415;DESERET CAPITAL LETTER CHEE;Lu;0;L;;;;;N;;;;1043D; +10416;DESERET CAPITAL LETTER JEE;Lu;0;L;;;;;N;;;;1043E; +10417;DESERET CAPITAL LETTER KAY;Lu;0;L;;;;;N;;;;1043F; +10418;DESERET CAPITAL LETTER GAY;Lu;0;L;;;;;N;;;;10440; +10419;DESERET CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;10441; +1041A;DESERET CAPITAL LETTER VEE;Lu;0;L;;;;;N;;;;10442; +1041B;DESERET CAPITAL LETTER ETH;Lu;0;L;;;;;N;;;;10443; +1041C;DESERET CAPITAL LETTER THEE;Lu;0;L;;;;;N;;;;10444; +1041D;DESERET CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;10445; +1041E;DESERET CAPITAL LETTER ZEE;Lu;0;L;;;;;N;;;;10446; +1041F;DESERET CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;10447; +10420;DESERET CAPITAL LETTER ZHEE;Lu;0;L;;;;;N;;;;10448; +10421;DESERET CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;10449; +10422;DESERET CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;1044A; +10423;DESERET CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;1044B; +10424;DESERET CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;1044C; +10425;DESERET CAPITAL LETTER ENG;Lu;0;L;;;;;N;;;;1044D; +10426;DESERET CAPITAL LETTER OI;Lu;0;L;;;;;N;;;;1044E; +10427;DESERET CAPITAL LETTER EW;Lu;0;L;;;;;N;;;;1044F; +10428;DESERET SMALL LETTER LONG I;Ll;0;L;;;;;N;;;10400;;10400 +10429;DESERET SMALL LETTER LONG E;Ll;0;L;;;;;N;;;10401;;10401 +1042A;DESERET SMALL LETTER LONG A;Ll;0;L;;;;;N;;;10402;;10402 +1042B;DESERET SMALL LETTER LONG AH;Ll;0;L;;;;;N;;;10403;;10403 +1042C;DESERET SMALL LETTER LONG O;Ll;0;L;;;;;N;;;10404;;10404 +1042D;DESERET SMALL LETTER LONG OO;Ll;0;L;;;;;N;;;10405;;10405 +1042E;DESERET SMALL LETTER SHORT I;Ll;0;L;;;;;N;;;10406;;10406 +1042F;DESERET SMALL LETTER SHORT E;Ll;0;L;;;;;N;;;10407;;10407 +10430;DESERET SMALL LETTER SHORT A;Ll;0;L;;;;;N;;;10408;;10408 +10431;DESERET SMALL LETTER SHORT AH;Ll;0;L;;;;;N;;;10409;;10409 +10432;DESERET SMALL LETTER SHORT O;Ll;0;L;;;;;N;;;1040A;;1040A +10433;DESERET SMALL LETTER SHORT OO;Ll;0;L;;;;;N;;;1040B;;1040B +10434;DESERET SMALL LETTER AY;Ll;0;L;;;;;N;;;1040C;;1040C +10435;DESERET SMALL LETTER OW;Ll;0;L;;;;;N;;;1040D;;1040D +10436;DESERET SMALL LETTER WU;Ll;0;L;;;;;N;;;1040E;;1040E +10437;DESERET SMALL LETTER YEE;Ll;0;L;;;;;N;;;1040F;;1040F +10438;DESERET SMALL LETTER H;Ll;0;L;;;;;N;;;10410;;10410 +10439;DESERET SMALL LETTER PEE;Ll;0;L;;;;;N;;;10411;;10411 +1043A;DESERET SMALL LETTER BEE;Ll;0;L;;;;;N;;;10412;;10412 +1043B;DESERET SMALL LETTER TEE;Ll;0;L;;;;;N;;;10413;;10413 +1043C;DESERET SMALL LETTER DEE;Ll;0;L;;;;;N;;;10414;;10414 +1043D;DESERET SMALL LETTER CHEE;Ll;0;L;;;;;N;;;10415;;10415 +1043E;DESERET SMALL LETTER JEE;Ll;0;L;;;;;N;;;10416;;10416 +1043F;DESERET SMALL LETTER KAY;Ll;0;L;;;;;N;;;10417;;10417 +10440;DESERET SMALL LETTER GAY;Ll;0;L;;;;;N;;;10418;;10418 +10441;DESERET SMALL LETTER EF;Ll;0;L;;;;;N;;;10419;;10419 +10442;DESERET SMALL LETTER VEE;Ll;0;L;;;;;N;;;1041A;;1041A +10443;DESERET SMALL LETTER ETH;Ll;0;L;;;;;N;;;1041B;;1041B +10444;DESERET SMALL LETTER THEE;Ll;0;L;;;;;N;;;1041C;;1041C +10445;DESERET SMALL LETTER ES;Ll;0;L;;;;;N;;;1041D;;1041D +10446;DESERET SMALL LETTER ZEE;Ll;0;L;;;;;N;;;1041E;;1041E +10447;DESERET SMALL LETTER ESH;Ll;0;L;;;;;N;;;1041F;;1041F +10448;DESERET SMALL LETTER ZHEE;Ll;0;L;;;;;N;;;10420;;10420 +10449;DESERET SMALL LETTER ER;Ll;0;L;;;;;N;;;10421;;10421 +1044A;DESERET SMALL LETTER EL;Ll;0;L;;;;;N;;;10422;;10422 +1044B;DESERET SMALL LETTER EM;Ll;0;L;;;;;N;;;10423;;10423 +1044C;DESERET SMALL LETTER EN;Ll;0;L;;;;;N;;;10424;;10424 +1044D;DESERET SMALL LETTER ENG;Ll;0;L;;;;;N;;;10425;;10425 +1044E;DESERET SMALL LETTER OI;Ll;0;L;;;;;N;;;10426;;10426 +1044F;DESERET SMALL LETTER EW;Ll;0;L;;;;;N;;;10427;;10427 +10450;SHAVIAN LETTER PEEP;Lo;0;L;;;;;N;;;;; +10451;SHAVIAN LETTER TOT;Lo;0;L;;;;;N;;;;; +10452;SHAVIAN LETTER KICK;Lo;0;L;;;;;N;;;;; +10453;SHAVIAN LETTER FEE;Lo;0;L;;;;;N;;;;; +10454;SHAVIAN LETTER THIGH;Lo;0;L;;;;;N;;;;; +10455;SHAVIAN LETTER SO;Lo;0;L;;;;;N;;;;; +10456;SHAVIAN LETTER SURE;Lo;0;L;;;;;N;;;;; +10457;SHAVIAN LETTER CHURCH;Lo;0;L;;;;;N;;;;; +10458;SHAVIAN LETTER YEA;Lo;0;L;;;;;N;;;;; +10459;SHAVIAN LETTER HUNG;Lo;0;L;;;;;N;;;;; +1045A;SHAVIAN LETTER BIB;Lo;0;L;;;;;N;;;;; +1045B;SHAVIAN LETTER DEAD;Lo;0;L;;;;;N;;;;; +1045C;SHAVIAN LETTER GAG;Lo;0;L;;;;;N;;;;; +1045D;SHAVIAN LETTER VOW;Lo;0;L;;;;;N;;;;; +1045E;SHAVIAN LETTER THEY;Lo;0;L;;;;;N;;;;; +1045F;SHAVIAN LETTER ZOO;Lo;0;L;;;;;N;;;;; +10460;SHAVIAN LETTER MEASURE;Lo;0;L;;;;;N;;;;; +10461;SHAVIAN LETTER JUDGE;Lo;0;L;;;;;N;;;;; +10462;SHAVIAN LETTER WOE;Lo;0;L;;;;;N;;;;; +10463;SHAVIAN LETTER HA-HA;Lo;0;L;;;;;N;;;;; +10464;SHAVIAN LETTER LOLL;Lo;0;L;;;;;N;;;;; +10465;SHAVIAN LETTER MIME;Lo;0;L;;;;;N;;;;; +10466;SHAVIAN LETTER IF;Lo;0;L;;;;;N;;;;; +10467;SHAVIAN LETTER EGG;Lo;0;L;;;;;N;;;;; +10468;SHAVIAN LETTER ASH;Lo;0;L;;;;;N;;;;; +10469;SHAVIAN LETTER ADO;Lo;0;L;;;;;N;;;;; +1046A;SHAVIAN LETTER ON;Lo;0;L;;;;;N;;;;; +1046B;SHAVIAN LETTER WOOL;Lo;0;L;;;;;N;;;;; +1046C;SHAVIAN LETTER OUT;Lo;0;L;;;;;N;;;;; +1046D;SHAVIAN LETTER AH;Lo;0;L;;;;;N;;;;; +1046E;SHAVIAN LETTER ROAR;Lo;0;L;;;;;N;;;;; +1046F;SHAVIAN LETTER NUN;Lo;0;L;;;;;N;;;;; +10470;SHAVIAN LETTER EAT;Lo;0;L;;;;;N;;;;; +10471;SHAVIAN LETTER AGE;Lo;0;L;;;;;N;;;;; +10472;SHAVIAN LETTER ICE;Lo;0;L;;;;;N;;;;; +10473;SHAVIAN LETTER UP;Lo;0;L;;;;;N;;;;; +10474;SHAVIAN LETTER OAK;Lo;0;L;;;;;N;;;;; +10475;SHAVIAN LETTER OOZE;Lo;0;L;;;;;N;;;;; +10476;SHAVIAN LETTER OIL;Lo;0;L;;;;;N;;;;; +10477;SHAVIAN LETTER AWE;Lo;0;L;;;;;N;;;;; +10478;SHAVIAN LETTER ARE;Lo;0;L;;;;;N;;;;; +10479;SHAVIAN LETTER OR;Lo;0;L;;;;;N;;;;; +1047A;SHAVIAN LETTER AIR;Lo;0;L;;;;;N;;;;; +1047B;SHAVIAN LETTER ERR;Lo;0;L;;;;;N;;;;; +1047C;SHAVIAN LETTER ARRAY;Lo;0;L;;;;;N;;;;; +1047D;SHAVIAN LETTER EAR;Lo;0;L;;;;;N;;;;; +1047E;SHAVIAN LETTER IAN;Lo;0;L;;;;;N;;;;; +1047F;SHAVIAN LETTER YEW;Lo;0;L;;;;;N;;;;; +10480;OSMANYA LETTER ALEF;Lo;0;L;;;;;N;;;;; +10481;OSMANYA LETTER BA;Lo;0;L;;;;;N;;;;; +10482;OSMANYA LETTER TA;Lo;0;L;;;;;N;;;;; +10483;OSMANYA LETTER JA;Lo;0;L;;;;;N;;;;; +10484;OSMANYA LETTER XA;Lo;0;L;;;;;N;;;;; +10485;OSMANYA LETTER KHA;Lo;0;L;;;;;N;;;;; +10486;OSMANYA LETTER DEEL;Lo;0;L;;;;;N;;;;; +10487;OSMANYA LETTER RA;Lo;0;L;;;;;N;;;;; +10488;OSMANYA LETTER SA;Lo;0;L;;;;;N;;;;; +10489;OSMANYA LETTER SHIIN;Lo;0;L;;;;;N;;;;; +1048A;OSMANYA LETTER DHA;Lo;0;L;;;;;N;;;;; +1048B;OSMANYA LETTER CAYN;Lo;0;L;;;;;N;;;;; +1048C;OSMANYA LETTER GA;Lo;0;L;;;;;N;;;;; +1048D;OSMANYA LETTER FA;Lo;0;L;;;;;N;;;;; +1048E;OSMANYA LETTER QAAF;Lo;0;L;;;;;N;;;;; +1048F;OSMANYA LETTER KAAF;Lo;0;L;;;;;N;;;;; +10490;OSMANYA LETTER LAAN;Lo;0;L;;;;;N;;;;; +10491;OSMANYA LETTER MIIN;Lo;0;L;;;;;N;;;;; +10492;OSMANYA LETTER NUUN;Lo;0;L;;;;;N;;;;; +10493;OSMANYA LETTER WAW;Lo;0;L;;;;;N;;;;; +10494;OSMANYA LETTER HA;Lo;0;L;;;;;N;;;;; +10495;OSMANYA LETTER YA;Lo;0;L;;;;;N;;;;; +10496;OSMANYA LETTER A;Lo;0;L;;;;;N;;;;; +10497;OSMANYA LETTER E;Lo;0;L;;;;;N;;;;; +10498;OSMANYA LETTER I;Lo;0;L;;;;;N;;;;; +10499;OSMANYA LETTER O;Lo;0;L;;;;;N;;;;; +1049A;OSMANYA LETTER U;Lo;0;L;;;;;N;;;;; +1049B;OSMANYA LETTER AA;Lo;0;L;;;;;N;;;;; +1049C;OSMANYA LETTER EE;Lo;0;L;;;;;N;;;;; +1049D;OSMANYA LETTER OO;Lo;0;L;;;;;N;;;;; +104A0;OSMANYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +104A1;OSMANYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +104A2;OSMANYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +104A3;OSMANYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +104A4;OSMANYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +104A5;OSMANYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +104A6;OSMANYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +104A7;OSMANYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +104A8;OSMANYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +104A9;OSMANYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +104B0;OSAGE CAPITAL LETTER A;Lu;0;L;;;;;N;;;;104D8; +104B1;OSAGE CAPITAL LETTER AI;Lu;0;L;;;;;N;;;;104D9; +104B2;OSAGE CAPITAL LETTER AIN;Lu;0;L;;;;;N;;;;104DA; +104B3;OSAGE CAPITAL LETTER AH;Lu;0;L;;;;;N;;;;104DB; +104B4;OSAGE CAPITAL LETTER BRA;Lu;0;L;;;;;N;;;;104DC; +104B5;OSAGE CAPITAL LETTER CHA;Lu;0;L;;;;;N;;;;104DD; +104B6;OSAGE CAPITAL LETTER EHCHA;Lu;0;L;;;;;N;;;;104DE; +104B7;OSAGE CAPITAL LETTER E;Lu;0;L;;;;;N;;;;104DF; +104B8;OSAGE CAPITAL LETTER EIN;Lu;0;L;;;;;N;;;;104E0; +104B9;OSAGE CAPITAL LETTER HA;Lu;0;L;;;;;N;;;;104E1; +104BA;OSAGE CAPITAL LETTER HYA;Lu;0;L;;;;;N;;;;104E2; +104BB;OSAGE CAPITAL LETTER I;Lu;0;L;;;;;N;;;;104E3; +104BC;OSAGE CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;104E4; +104BD;OSAGE CAPITAL LETTER EHKA;Lu;0;L;;;;;N;;;;104E5; +104BE;OSAGE CAPITAL LETTER KYA;Lu;0;L;;;;;N;;;;104E6; +104BF;OSAGE CAPITAL LETTER LA;Lu;0;L;;;;;N;;;;104E7; +104C0;OSAGE CAPITAL LETTER MA;Lu;0;L;;;;;N;;;;104E8; +104C1;OSAGE CAPITAL LETTER NA;Lu;0;L;;;;;N;;;;104E9; +104C2;OSAGE CAPITAL LETTER O;Lu;0;L;;;;;N;;;;104EA; +104C3;OSAGE CAPITAL LETTER OIN;Lu;0;L;;;;;N;;;;104EB; +104C4;OSAGE CAPITAL LETTER PA;Lu;0;L;;;;;N;;;;104EC; +104C5;OSAGE CAPITAL LETTER EHPA;Lu;0;L;;;;;N;;;;104ED; +104C6;OSAGE CAPITAL LETTER SA;Lu;0;L;;;;;N;;;;104EE; +104C7;OSAGE CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;104EF; +104C8;OSAGE CAPITAL LETTER TA;Lu;0;L;;;;;N;;;;104F0; +104C9;OSAGE CAPITAL LETTER EHTA;Lu;0;L;;;;;N;;;;104F1; +104CA;OSAGE CAPITAL LETTER TSA;Lu;0;L;;;;;N;;;;104F2; +104CB;OSAGE CAPITAL LETTER EHTSA;Lu;0;L;;;;;N;;;;104F3; +104CC;OSAGE CAPITAL LETTER TSHA;Lu;0;L;;;;;N;;;;104F4; +104CD;OSAGE CAPITAL LETTER DHA;Lu;0;L;;;;;N;;;;104F5; +104CE;OSAGE CAPITAL LETTER U;Lu;0;L;;;;;N;;;;104F6; +104CF;OSAGE CAPITAL LETTER WA;Lu;0;L;;;;;N;;;;104F7; +104D0;OSAGE CAPITAL LETTER KHA;Lu;0;L;;;;;N;;;;104F8; +104D1;OSAGE CAPITAL LETTER GHA;Lu;0;L;;;;;N;;;;104F9; +104D2;OSAGE CAPITAL LETTER ZA;Lu;0;L;;;;;N;;;;104FA; +104D3;OSAGE CAPITAL LETTER ZHA;Lu;0;L;;;;;N;;;;104FB; +104D8;OSAGE SMALL LETTER A;Ll;0;L;;;;;N;;;104B0;;104B0 +104D9;OSAGE SMALL LETTER AI;Ll;0;L;;;;;N;;;104B1;;104B1 +104DA;OSAGE SMALL LETTER AIN;Ll;0;L;;;;;N;;;104B2;;104B2 +104DB;OSAGE SMALL LETTER AH;Ll;0;L;;;;;N;;;104B3;;104B3 +104DC;OSAGE SMALL LETTER BRA;Ll;0;L;;;;;N;;;104B4;;104B4 +104DD;OSAGE SMALL LETTER CHA;Ll;0;L;;;;;N;;;104B5;;104B5 +104DE;OSAGE SMALL LETTER EHCHA;Ll;0;L;;;;;N;;;104B6;;104B6 +104DF;OSAGE SMALL LETTER E;Ll;0;L;;;;;N;;;104B7;;104B7 +104E0;OSAGE SMALL LETTER EIN;Ll;0;L;;;;;N;;;104B8;;104B8 +104E1;OSAGE SMALL LETTER HA;Ll;0;L;;;;;N;;;104B9;;104B9 +104E2;OSAGE SMALL LETTER HYA;Ll;0;L;;;;;N;;;104BA;;104BA +104E3;OSAGE SMALL LETTER I;Ll;0;L;;;;;N;;;104BB;;104BB +104E4;OSAGE SMALL LETTER KA;Ll;0;L;;;;;N;;;104BC;;104BC +104E5;OSAGE SMALL LETTER EHKA;Ll;0;L;;;;;N;;;104BD;;104BD +104E6;OSAGE SMALL LETTER KYA;Ll;0;L;;;;;N;;;104BE;;104BE +104E7;OSAGE SMALL LETTER LA;Ll;0;L;;;;;N;;;104BF;;104BF +104E8;OSAGE SMALL LETTER MA;Ll;0;L;;;;;N;;;104C0;;104C0 +104E9;OSAGE SMALL LETTER NA;Ll;0;L;;;;;N;;;104C1;;104C1 +104EA;OSAGE SMALL LETTER O;Ll;0;L;;;;;N;;;104C2;;104C2 +104EB;OSAGE SMALL LETTER OIN;Ll;0;L;;;;;N;;;104C3;;104C3 +104EC;OSAGE SMALL LETTER PA;Ll;0;L;;;;;N;;;104C4;;104C4 +104ED;OSAGE SMALL LETTER EHPA;Ll;0;L;;;;;N;;;104C5;;104C5 +104EE;OSAGE SMALL LETTER SA;Ll;0;L;;;;;N;;;104C6;;104C6 +104EF;OSAGE SMALL LETTER SHA;Ll;0;L;;;;;N;;;104C7;;104C7 +104F0;OSAGE SMALL LETTER TA;Ll;0;L;;;;;N;;;104C8;;104C8 +104F1;OSAGE SMALL LETTER EHTA;Ll;0;L;;;;;N;;;104C9;;104C9 +104F2;OSAGE SMALL LETTER TSA;Ll;0;L;;;;;N;;;104CA;;104CA +104F3;OSAGE SMALL LETTER EHTSA;Ll;0;L;;;;;N;;;104CB;;104CB +104F4;OSAGE SMALL LETTER TSHA;Ll;0;L;;;;;N;;;104CC;;104CC +104F5;OSAGE SMALL LETTER DHA;Ll;0;L;;;;;N;;;104CD;;104CD +104F6;OSAGE SMALL LETTER U;Ll;0;L;;;;;N;;;104CE;;104CE +104F7;OSAGE SMALL LETTER WA;Ll;0;L;;;;;N;;;104CF;;104CF +104F8;OSAGE SMALL LETTER KHA;Ll;0;L;;;;;N;;;104D0;;104D0 +104F9;OSAGE SMALL LETTER GHA;Ll;0;L;;;;;N;;;104D1;;104D1 +104FA;OSAGE SMALL LETTER ZA;Ll;0;L;;;;;N;;;104D2;;104D2 +104FB;OSAGE SMALL LETTER ZHA;Ll;0;L;;;;;N;;;104D3;;104D3 +10500;ELBASAN LETTER A;Lo;0;L;;;;;N;;;;; +10501;ELBASAN LETTER BE;Lo;0;L;;;;;N;;;;; +10502;ELBASAN LETTER CE;Lo;0;L;;;;;N;;;;; +10503;ELBASAN LETTER CHE;Lo;0;L;;;;;N;;;;; +10504;ELBASAN LETTER DE;Lo;0;L;;;;;N;;;;; +10505;ELBASAN LETTER NDE;Lo;0;L;;;;;N;;;;; +10506;ELBASAN LETTER DHE;Lo;0;L;;;;;N;;;;; +10507;ELBASAN LETTER EI;Lo;0;L;;;;;N;;;;; +10508;ELBASAN LETTER E;Lo;0;L;;;;;N;;;;; +10509;ELBASAN LETTER FE;Lo;0;L;;;;;N;;;;; +1050A;ELBASAN LETTER GE;Lo;0;L;;;;;N;;;;; +1050B;ELBASAN LETTER GJE;Lo;0;L;;;;;N;;;;; +1050C;ELBASAN LETTER HE;Lo;0;L;;;;;N;;;;; +1050D;ELBASAN LETTER I;Lo;0;L;;;;;N;;;;; +1050E;ELBASAN LETTER JE;Lo;0;L;;;;;N;;;;; +1050F;ELBASAN LETTER KE;Lo;0;L;;;;;N;;;;; +10510;ELBASAN LETTER LE;Lo;0;L;;;;;N;;;;; +10511;ELBASAN LETTER LLE;Lo;0;L;;;;;N;;;;; +10512;ELBASAN LETTER ME;Lo;0;L;;;;;N;;;;; +10513;ELBASAN LETTER NE;Lo;0;L;;;;;N;;;;; +10514;ELBASAN LETTER NA;Lo;0;L;;;;;N;;;;; +10515;ELBASAN LETTER NJE;Lo;0;L;;;;;N;;;;; +10516;ELBASAN LETTER O;Lo;0;L;;;;;N;;;;; +10517;ELBASAN LETTER PE;Lo;0;L;;;;;N;;;;; +10518;ELBASAN LETTER QE;Lo;0;L;;;;;N;;;;; +10519;ELBASAN LETTER RE;Lo;0;L;;;;;N;;;;; +1051A;ELBASAN LETTER RRE;Lo;0;L;;;;;N;;;;; +1051B;ELBASAN LETTER SE;Lo;0;L;;;;;N;;;;; +1051C;ELBASAN LETTER SHE;Lo;0;L;;;;;N;;;;; +1051D;ELBASAN LETTER TE;Lo;0;L;;;;;N;;;;; +1051E;ELBASAN LETTER THE;Lo;0;L;;;;;N;;;;; +1051F;ELBASAN LETTER U;Lo;0;L;;;;;N;;;;; +10520;ELBASAN LETTER VE;Lo;0;L;;;;;N;;;;; +10521;ELBASAN LETTER XE;Lo;0;L;;;;;N;;;;; +10522;ELBASAN LETTER Y;Lo;0;L;;;;;N;;;;; +10523;ELBASAN LETTER ZE;Lo;0;L;;;;;N;;;;; +10524;ELBASAN LETTER ZHE;Lo;0;L;;;;;N;;;;; +10525;ELBASAN LETTER GHE;Lo;0;L;;;;;N;;;;; +10526;ELBASAN LETTER GHAMMA;Lo;0;L;;;;;N;;;;; +10527;ELBASAN LETTER KHE;Lo;0;L;;;;;N;;;;; +10530;CAUCASIAN ALBANIAN LETTER ALT;Lo;0;L;;;;;N;;;;; +10531;CAUCASIAN ALBANIAN LETTER BET;Lo;0;L;;;;;N;;;;; +10532;CAUCASIAN ALBANIAN LETTER GIM;Lo;0;L;;;;;N;;;;; +10533;CAUCASIAN ALBANIAN LETTER DAT;Lo;0;L;;;;;N;;;;; +10534;CAUCASIAN ALBANIAN LETTER EB;Lo;0;L;;;;;N;;;;; +10535;CAUCASIAN ALBANIAN LETTER ZARL;Lo;0;L;;;;;N;;;;; +10536;CAUCASIAN ALBANIAN LETTER EYN;Lo;0;L;;;;;N;;;;; +10537;CAUCASIAN ALBANIAN LETTER ZHIL;Lo;0;L;;;;;N;;;;; +10538;CAUCASIAN ALBANIAN LETTER TAS;Lo;0;L;;;;;N;;;;; +10539;CAUCASIAN ALBANIAN LETTER CHA;Lo;0;L;;;;;N;;;;; +1053A;CAUCASIAN ALBANIAN LETTER YOWD;Lo;0;L;;;;;N;;;;; +1053B;CAUCASIAN ALBANIAN LETTER ZHA;Lo;0;L;;;;;N;;;;; +1053C;CAUCASIAN ALBANIAN LETTER IRB;Lo;0;L;;;;;N;;;;; +1053D;CAUCASIAN ALBANIAN LETTER SHA;Lo;0;L;;;;;N;;;;; +1053E;CAUCASIAN ALBANIAN LETTER LAN;Lo;0;L;;;;;N;;;;; +1053F;CAUCASIAN ALBANIAN LETTER INYA;Lo;0;L;;;;;N;;;;; +10540;CAUCASIAN ALBANIAN LETTER XEYN;Lo;0;L;;;;;N;;;;; +10541;CAUCASIAN ALBANIAN LETTER DYAN;Lo;0;L;;;;;N;;;;; +10542;CAUCASIAN ALBANIAN LETTER CAR;Lo;0;L;;;;;N;;;;; +10543;CAUCASIAN ALBANIAN LETTER JHOX;Lo;0;L;;;;;N;;;;; +10544;CAUCASIAN ALBANIAN LETTER KAR;Lo;0;L;;;;;N;;;;; +10545;CAUCASIAN ALBANIAN LETTER LYIT;Lo;0;L;;;;;N;;;;; +10546;CAUCASIAN ALBANIAN LETTER HEYT;Lo;0;L;;;;;N;;;;; +10547;CAUCASIAN ALBANIAN LETTER QAY;Lo;0;L;;;;;N;;;;; +10548;CAUCASIAN ALBANIAN LETTER AOR;Lo;0;L;;;;;N;;;;; +10549;CAUCASIAN ALBANIAN LETTER CHOY;Lo;0;L;;;;;N;;;;; +1054A;CAUCASIAN ALBANIAN LETTER CHI;Lo;0;L;;;;;N;;;;; +1054B;CAUCASIAN ALBANIAN LETTER CYAY;Lo;0;L;;;;;N;;;;; +1054C;CAUCASIAN ALBANIAN LETTER MAQ;Lo;0;L;;;;;N;;;;; +1054D;CAUCASIAN ALBANIAN LETTER QAR;Lo;0;L;;;;;N;;;;; +1054E;CAUCASIAN ALBANIAN LETTER NOWC;Lo;0;L;;;;;N;;;;; +1054F;CAUCASIAN ALBANIAN LETTER DZYAY;Lo;0;L;;;;;N;;;;; +10550;CAUCASIAN ALBANIAN LETTER SHAK;Lo;0;L;;;;;N;;;;; +10551;CAUCASIAN ALBANIAN LETTER JAYN;Lo;0;L;;;;;N;;;;; +10552;CAUCASIAN ALBANIAN LETTER ON;Lo;0;L;;;;;N;;;;; +10553;CAUCASIAN ALBANIAN LETTER TYAY;Lo;0;L;;;;;N;;;;; +10554;CAUCASIAN ALBANIAN LETTER FAM;Lo;0;L;;;;;N;;;;; +10555;CAUCASIAN ALBANIAN LETTER DZAY;Lo;0;L;;;;;N;;;;; +10556;CAUCASIAN ALBANIAN LETTER CHAT;Lo;0;L;;;;;N;;;;; +10557;CAUCASIAN ALBANIAN LETTER PEN;Lo;0;L;;;;;N;;;;; +10558;CAUCASIAN ALBANIAN LETTER GHEYS;Lo;0;L;;;;;N;;;;; +10559;CAUCASIAN ALBANIAN LETTER RAT;Lo;0;L;;;;;N;;;;; +1055A;CAUCASIAN ALBANIAN LETTER SEYK;Lo;0;L;;;;;N;;;;; +1055B;CAUCASIAN ALBANIAN LETTER VEYZ;Lo;0;L;;;;;N;;;;; +1055C;CAUCASIAN ALBANIAN LETTER TIWR;Lo;0;L;;;;;N;;;;; +1055D;CAUCASIAN ALBANIAN LETTER SHOY;Lo;0;L;;;;;N;;;;; +1055E;CAUCASIAN ALBANIAN LETTER IWN;Lo;0;L;;;;;N;;;;; +1055F;CAUCASIAN ALBANIAN LETTER CYAW;Lo;0;L;;;;;N;;;;; +10560;CAUCASIAN ALBANIAN LETTER CAYN;Lo;0;L;;;;;N;;;;; +10561;CAUCASIAN ALBANIAN LETTER YAYD;Lo;0;L;;;;;N;;;;; +10562;CAUCASIAN ALBANIAN LETTER PIWR;Lo;0;L;;;;;N;;;;; +10563;CAUCASIAN ALBANIAN LETTER KIW;Lo;0;L;;;;;N;;;;; +1056F;CAUCASIAN ALBANIAN CITATION MARK;Po;0;L;;;;;N;;;;; +10570;VITHKUQI CAPITAL LETTER A;Lu;0;L;;;;;N;;;;10597; +10571;VITHKUQI CAPITAL LETTER BBE;Lu;0;L;;;;;N;;;;10598; +10572;VITHKUQI CAPITAL LETTER BE;Lu;0;L;;;;;N;;;;10599; +10573;VITHKUQI CAPITAL LETTER CE;Lu;0;L;;;;;N;;;;1059A; +10574;VITHKUQI CAPITAL LETTER CHE;Lu;0;L;;;;;N;;;;1059B; +10575;VITHKUQI CAPITAL LETTER DE;Lu;0;L;;;;;N;;;;1059C; +10576;VITHKUQI CAPITAL LETTER DHE;Lu;0;L;;;;;N;;;;1059D; +10577;VITHKUQI CAPITAL LETTER EI;Lu;0;L;;;;;N;;;;1059E; +10578;VITHKUQI CAPITAL LETTER E;Lu;0;L;;;;;N;;;;1059F; +10579;VITHKUQI CAPITAL LETTER FE;Lu;0;L;;;;;N;;;;105A0; +1057A;VITHKUQI CAPITAL LETTER GA;Lu;0;L;;;;;N;;;;105A1; +1057C;VITHKUQI CAPITAL LETTER HA;Lu;0;L;;;;;N;;;;105A3; +1057D;VITHKUQI CAPITAL LETTER HHA;Lu;0;L;;;;;N;;;;105A4; +1057E;VITHKUQI CAPITAL LETTER I;Lu;0;L;;;;;N;;;;105A5; +1057F;VITHKUQI CAPITAL LETTER IJE;Lu;0;L;;;;;N;;;;105A6; +10580;VITHKUQI CAPITAL LETTER JE;Lu;0;L;;;;;N;;;;105A7; +10581;VITHKUQI CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;105A8; +10582;VITHKUQI CAPITAL LETTER LA;Lu;0;L;;;;;N;;;;105A9; +10583;VITHKUQI CAPITAL LETTER LLA;Lu;0;L;;;;;N;;;;105AA; +10584;VITHKUQI CAPITAL LETTER ME;Lu;0;L;;;;;N;;;;105AB; +10585;VITHKUQI CAPITAL LETTER NE;Lu;0;L;;;;;N;;;;105AC; +10586;VITHKUQI CAPITAL LETTER NJE;Lu;0;L;;;;;N;;;;105AD; +10587;VITHKUQI CAPITAL LETTER O;Lu;0;L;;;;;N;;;;105AE; +10588;VITHKUQI CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;105AF; +10589;VITHKUQI CAPITAL LETTER QA;Lu;0;L;;;;;N;;;;105B0; +1058A;VITHKUQI CAPITAL LETTER RE;Lu;0;L;;;;;N;;;;105B1; +1058C;VITHKUQI CAPITAL LETTER SE;Lu;0;L;;;;;N;;;;105B3; +1058D;VITHKUQI CAPITAL LETTER SHE;Lu;0;L;;;;;N;;;;105B4; +1058E;VITHKUQI CAPITAL LETTER TE;Lu;0;L;;;;;N;;;;105B5; +1058F;VITHKUQI CAPITAL LETTER THE;Lu;0;L;;;;;N;;;;105B6; +10590;VITHKUQI CAPITAL LETTER U;Lu;0;L;;;;;N;;;;105B7; +10591;VITHKUQI CAPITAL LETTER VE;Lu;0;L;;;;;N;;;;105B8; +10592;VITHKUQI CAPITAL LETTER XE;Lu;0;L;;;;;N;;;;105B9; +10594;VITHKUQI CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;105BB; +10595;VITHKUQI CAPITAL LETTER ZE;Lu;0;L;;;;;N;;;;105BC; +10597;VITHKUQI SMALL LETTER A;Ll;0;L;;;;;N;;;10570;;10570 +10598;VITHKUQI SMALL LETTER BBE;Ll;0;L;;;;;N;;;10571;;10571 +10599;VITHKUQI SMALL LETTER BE;Ll;0;L;;;;;N;;;10572;;10572 +1059A;VITHKUQI SMALL LETTER CE;Ll;0;L;;;;;N;;;10573;;10573 +1059B;VITHKUQI SMALL LETTER CHE;Ll;0;L;;;;;N;;;10574;;10574 +1059C;VITHKUQI SMALL LETTER DE;Ll;0;L;;;;;N;;;10575;;10575 +1059D;VITHKUQI SMALL LETTER DHE;Ll;0;L;;;;;N;;;10576;;10576 +1059E;VITHKUQI SMALL LETTER EI;Ll;0;L;;;;;N;;;10577;;10577 +1059F;VITHKUQI SMALL LETTER E;Ll;0;L;;;;;N;;;10578;;10578 +105A0;VITHKUQI SMALL LETTER FE;Ll;0;L;;;;;N;;;10579;;10579 +105A1;VITHKUQI SMALL LETTER GA;Ll;0;L;;;;;N;;;1057A;;1057A +105A3;VITHKUQI SMALL LETTER HA;Ll;0;L;;;;;N;;;1057C;;1057C +105A4;VITHKUQI SMALL LETTER HHA;Ll;0;L;;;;;N;;;1057D;;1057D +105A5;VITHKUQI SMALL LETTER I;Ll;0;L;;;;;N;;;1057E;;1057E +105A6;VITHKUQI SMALL LETTER IJE;Ll;0;L;;;;;N;;;1057F;;1057F +105A7;VITHKUQI SMALL LETTER JE;Ll;0;L;;;;;N;;;10580;;10580 +105A8;VITHKUQI SMALL LETTER KA;Ll;0;L;;;;;N;;;10581;;10581 +105A9;VITHKUQI SMALL LETTER LA;Ll;0;L;;;;;N;;;10582;;10582 +105AA;VITHKUQI SMALL LETTER LLA;Ll;0;L;;;;;N;;;10583;;10583 +105AB;VITHKUQI SMALL LETTER ME;Ll;0;L;;;;;N;;;10584;;10584 +105AC;VITHKUQI SMALL LETTER NE;Ll;0;L;;;;;N;;;10585;;10585 +105AD;VITHKUQI SMALL LETTER NJE;Ll;0;L;;;;;N;;;10586;;10586 +105AE;VITHKUQI SMALL LETTER O;Ll;0;L;;;;;N;;;10587;;10587 +105AF;VITHKUQI SMALL LETTER PE;Ll;0;L;;;;;N;;;10588;;10588 +105B0;VITHKUQI SMALL LETTER QA;Ll;0;L;;;;;N;;;10589;;10589 +105B1;VITHKUQI SMALL LETTER RE;Ll;0;L;;;;;N;;;1058A;;1058A +105B3;VITHKUQI SMALL LETTER SE;Ll;0;L;;;;;N;;;1058C;;1058C +105B4;VITHKUQI SMALL LETTER SHE;Ll;0;L;;;;;N;;;1058D;;1058D +105B5;VITHKUQI SMALL LETTER TE;Ll;0;L;;;;;N;;;1058E;;1058E +105B6;VITHKUQI SMALL LETTER THE;Ll;0;L;;;;;N;;;1058F;;1058F +105B7;VITHKUQI SMALL LETTER U;Ll;0;L;;;;;N;;;10590;;10590 +105B8;VITHKUQI SMALL LETTER VE;Ll;0;L;;;;;N;;;10591;;10591 +105B9;VITHKUQI SMALL LETTER XE;Ll;0;L;;;;;N;;;10592;;10592 +105BB;VITHKUQI SMALL LETTER Y;Ll;0;L;;;;;N;;;10594;;10594 +105BC;VITHKUQI SMALL LETTER ZE;Ll;0;L;;;;;N;;;10595;;10595 +105C0;TODHRI LETTER A;Lo;0;L;;;;;N;;;;; +105C1;TODHRI LETTER AS;Lo;0;L;;;;;N;;;;; +105C2;TODHRI LETTER BA;Lo;0;L;;;;;N;;;;; +105C3;TODHRI LETTER MBA;Lo;0;L;;;;;N;;;;; +105C4;TODHRI LETTER CA;Lo;0;L;;;;;N;;;;; +105C5;TODHRI LETTER CHA;Lo;0;L;;;;;N;;;;; +105C6;TODHRI LETTER DA;Lo;0;L;;;;;N;;;;; +105C7;TODHRI LETTER NDA;Lo;0;L;;;;;N;;;;; +105C8;TODHRI LETTER DHA;Lo;0;L;;;;;N;;;;; +105C9;TODHRI LETTER EI;Lo;0;L;105D2 0307;;;;N;;;;; +105CA;TODHRI LETTER E;Lo;0;L;;;;;N;;;;; +105CB;TODHRI LETTER FA;Lo;0;L;;;;;N;;;;; +105CC;TODHRI LETTER GA;Lo;0;L;;;;;N;;;;; +105CD;TODHRI LETTER NGA;Lo;0;L;;;;;N;;;;; +105CE;TODHRI LETTER GJA;Lo;0;L;;;;;N;;;;; +105CF;TODHRI LETTER NGJA;Lo;0;L;;;;;N;;;;; +105D0;TODHRI LETTER HA;Lo;0;L;;;;;N;;;;; +105D1;TODHRI LETTER HJA;Lo;0;L;;;;;N;;;;; +105D2;TODHRI LETTER I;Lo;0;L;;;;;N;;;;; +105D3;TODHRI LETTER JA;Lo;0;L;;;;;N;;;;; +105D4;TODHRI LETTER KA;Lo;0;L;;;;;N;;;;; +105D5;TODHRI LETTER LA;Lo;0;L;;;;;N;;;;; +105D6;TODHRI LETTER LLA;Lo;0;L;;;;;N;;;;; +105D7;TODHRI LETTER MA;Lo;0;L;;;;;N;;;;; +105D8;TODHRI LETTER NA;Lo;0;L;;;;;N;;;;; +105D9;TODHRI LETTER NJAN;Lo;0;L;;;;;N;;;;; +105DA;TODHRI LETTER O;Lo;0;L;;;;;N;;;;; +105DB;TODHRI LETTER PA;Lo;0;L;;;;;N;;;;; +105DC;TODHRI LETTER QA;Lo;0;L;;;;;N;;;;; +105DD;TODHRI LETTER RA;Lo;0;L;;;;;N;;;;; +105DE;TODHRI LETTER RRA;Lo;0;L;;;;;N;;;;; +105DF;TODHRI LETTER SA;Lo;0;L;;;;;N;;;;; +105E0;TODHRI LETTER SHA;Lo;0;L;;;;;N;;;;; +105E1;TODHRI LETTER SHTA;Lo;0;L;;;;;N;;;;; +105E2;TODHRI LETTER TA;Lo;0;L;;;;;N;;;;; +105E3;TODHRI LETTER THA;Lo;0;L;;;;;N;;;;; +105E4;TODHRI LETTER U;Lo;0;L;105DA 0307;;;;N;;;;; +105E5;TODHRI LETTER VA;Lo;0;L;;;;;N;;;;; +105E6;TODHRI LETTER XA;Lo;0;L;;;;;N;;;;; +105E7;TODHRI LETTER NXA;Lo;0;L;;;;;N;;;;; +105E8;TODHRI LETTER XHA;Lo;0;L;;;;;N;;;;; +105E9;TODHRI LETTER NXHA;Lo;0;L;;;;;N;;;;; +105EA;TODHRI LETTER Y;Lo;0;L;;;;;N;;;;; +105EB;TODHRI LETTER JY;Lo;0;L;;;;;N;;;;; +105EC;TODHRI LETTER ZA;Lo;0;L;;;;;N;;;;; +105ED;TODHRI LETTER ZHA;Lo;0;L;;;;;N;;;;; +105EE;TODHRI LETTER GHA;Lo;0;L;;;;;N;;;;; +105EF;TODHRI LETTER STA;Lo;0;L;;;;;N;;;;; +105F0;TODHRI LETTER SKAN;Lo;0;L;;;;;N;;;;; +105F1;TODHRI LETTER KHA;Lo;0;L;;;;;N;;;;; +105F2;TODHRI LETTER PSA;Lo;0;L;;;;;N;;;;; +105F3;TODHRI LETTER OO;Lo;0;L;;;;;N;;;;; +10600;LINEAR A SIGN AB001;Lo;0;L;;;;;N;;;;; +10601;LINEAR A SIGN AB002;Lo;0;L;;;;;N;;;;; +10602;LINEAR A SIGN AB003;Lo;0;L;;;;;N;;;;; +10603;LINEAR A SIGN AB004;Lo;0;L;;;;;N;;;;; +10604;LINEAR A SIGN AB005;Lo;0;L;;;;;N;;;;; +10605;LINEAR A SIGN AB006;Lo;0;L;;;;;N;;;;; +10606;LINEAR A SIGN AB007;Lo;0;L;;;;;N;;;;; +10607;LINEAR A SIGN AB008;Lo;0;L;;;;;N;;;;; +10608;LINEAR A SIGN AB009;Lo;0;L;;;;;N;;;;; +10609;LINEAR A SIGN AB010;Lo;0;L;;;;;N;;;;; +1060A;LINEAR A SIGN AB011;Lo;0;L;;;;;N;;;;; +1060B;LINEAR A SIGN AB013;Lo;0;L;;;;;N;;;;; +1060C;LINEAR A SIGN AB016;Lo;0;L;;;;;N;;;;; +1060D;LINEAR A SIGN AB017;Lo;0;L;;;;;N;;;;; +1060E;LINEAR A SIGN AB020;Lo;0;L;;;;;N;;;;; +1060F;LINEAR A SIGN AB021;Lo;0;L;;;;;N;;;;; +10610;LINEAR A SIGN AB021F;Lo;0;L;;;;;N;;;;; +10611;LINEAR A SIGN AB021M;Lo;0;L;;;;;N;;;;; +10612;LINEAR A SIGN AB022;Lo;0;L;;;;;N;;;;; +10613;LINEAR A SIGN AB022F;Lo;0;L;;;;;N;;;;; +10614;LINEAR A SIGN AB022M;Lo;0;L;;;;;N;;;;; +10615;LINEAR A SIGN AB023;Lo;0;L;;;;;N;;;;; +10616;LINEAR A SIGN AB023M;Lo;0;L;;;;;N;;;;; +10617;LINEAR A SIGN AB024;Lo;0;L;;;;;N;;;;; +10618;LINEAR A SIGN AB026;Lo;0;L;;;;;N;;;;; +10619;LINEAR A SIGN AB027;Lo;0;L;;;;;N;;;;; +1061A;LINEAR A SIGN AB028;Lo;0;L;;;;;N;;;;; +1061B;LINEAR A SIGN A028B;Lo;0;L;;;;;N;;;;; +1061C;LINEAR A SIGN AB029;Lo;0;L;;;;;N;;;;; +1061D;LINEAR A SIGN AB030;Lo;0;L;;;;;N;;;;; +1061E;LINEAR A SIGN AB031;Lo;0;L;;;;;N;;;;; +1061F;LINEAR A SIGN AB034;Lo;0;L;;;;;N;;;;; +10620;LINEAR A SIGN AB037;Lo;0;L;;;;;N;;;;; +10621;LINEAR A SIGN AB038;Lo;0;L;;;;;N;;;;; +10622;LINEAR A SIGN AB039;Lo;0;L;;;;;N;;;;; +10623;LINEAR A SIGN AB040;Lo;0;L;;;;;N;;;;; +10624;LINEAR A SIGN AB041;Lo;0;L;;;;;N;;;;; +10625;LINEAR A SIGN AB044;Lo;0;L;;;;;N;;;;; +10626;LINEAR A SIGN AB045;Lo;0;L;;;;;N;;;;; +10627;LINEAR A SIGN AB046;Lo;0;L;;;;;N;;;;; +10628;LINEAR A SIGN AB047;Lo;0;L;;;;;N;;;;; +10629;LINEAR A SIGN AB048;Lo;0;L;;;;;N;;;;; +1062A;LINEAR A SIGN AB049;Lo;0;L;;;;;N;;;;; +1062B;LINEAR A SIGN AB050;Lo;0;L;;;;;N;;;;; +1062C;LINEAR A SIGN AB051;Lo;0;L;;;;;N;;;;; +1062D;LINEAR A SIGN AB053;Lo;0;L;;;;;N;;;;; +1062E;LINEAR A SIGN AB054;Lo;0;L;;;;;N;;;;; +1062F;LINEAR A SIGN AB055;Lo;0;L;;;;;N;;;;; +10630;LINEAR A SIGN AB056;Lo;0;L;;;;;N;;;;; +10631;LINEAR A SIGN AB057;Lo;0;L;;;;;N;;;;; +10632;LINEAR A SIGN AB058;Lo;0;L;;;;;N;;;;; +10633;LINEAR A SIGN AB059;Lo;0;L;;;;;N;;;;; +10634;LINEAR A SIGN AB060;Lo;0;L;;;;;N;;;;; +10635;LINEAR A SIGN AB061;Lo;0;L;;;;;N;;;;; +10636;LINEAR A SIGN AB065;Lo;0;L;;;;;N;;;;; +10637;LINEAR A SIGN AB066;Lo;0;L;;;;;N;;;;; +10638;LINEAR A SIGN AB067;Lo;0;L;;;;;N;;;;; +10639;LINEAR A SIGN AB069;Lo;0;L;;;;;N;;;;; +1063A;LINEAR A SIGN AB070;Lo;0;L;;;;;N;;;;; +1063B;LINEAR A SIGN AB073;Lo;0;L;;;;;N;;;;; +1063C;LINEAR A SIGN AB074;Lo;0;L;;;;;N;;;;; +1063D;LINEAR A SIGN AB076;Lo;0;L;;;;;N;;;;; +1063E;LINEAR A SIGN AB077;Lo;0;L;;;;;N;;;;; +1063F;LINEAR A SIGN AB078;Lo;0;L;;;;;N;;;;; +10640;LINEAR A SIGN AB079;Lo;0;L;;;;;N;;;;; +10641;LINEAR A SIGN AB080;Lo;0;L;;;;;N;;;;; +10642;LINEAR A SIGN AB081;Lo;0;L;;;;;N;;;;; +10643;LINEAR A SIGN AB082;Lo;0;L;;;;;N;;;;; +10644;LINEAR A SIGN AB085;Lo;0;L;;;;;N;;;;; +10645;LINEAR A SIGN AB086;Lo;0;L;;;;;N;;;;; +10646;LINEAR A SIGN AB087;Lo;0;L;;;;;N;;;;; +10647;LINEAR A SIGN A100-102;Lo;0;L;;;;;N;;;;; +10648;LINEAR A SIGN AB118;Lo;0;L;;;;;N;;;;; +10649;LINEAR A SIGN AB120;Lo;0;L;;;;;N;;;;; +1064A;LINEAR A SIGN A120B;Lo;0;L;;;;;N;;;;; +1064B;LINEAR A SIGN AB122;Lo;0;L;;;;;N;;;;; +1064C;LINEAR A SIGN AB123;Lo;0;L;;;;;N;;;;; +1064D;LINEAR A SIGN AB131A;Lo;0;L;;;;;N;;;;; +1064E;LINEAR A SIGN AB131B;Lo;0;L;;;;;N;;;;; +1064F;LINEAR A SIGN A131C;Lo;0;L;;;;;N;;;;; +10650;LINEAR A SIGN AB164;Lo;0;L;;;;;N;;;;; +10651;LINEAR A SIGN AB171;Lo;0;L;;;;;N;;;;; +10652;LINEAR A SIGN AB180;Lo;0;L;;;;;N;;;;; +10653;LINEAR A SIGN AB188;Lo;0;L;;;;;N;;;;; +10654;LINEAR A SIGN AB191;Lo;0;L;;;;;N;;;;; +10655;LINEAR A SIGN A301;Lo;0;L;;;;;N;;;;; +10656;LINEAR A SIGN A302;Lo;0;L;;;;;N;;;;; +10657;LINEAR A SIGN A303;Lo;0;L;;;;;N;;;;; +10658;LINEAR A SIGN A304;Lo;0;L;;;;;N;;;;; +10659;LINEAR A SIGN A305;Lo;0;L;;;;;N;;;;; +1065A;LINEAR A SIGN A306;Lo;0;L;;;;;N;;;;; +1065B;LINEAR A SIGN A307;Lo;0;L;;;;;N;;;;; +1065C;LINEAR A SIGN A308;Lo;0;L;;;;;N;;;;; +1065D;LINEAR A SIGN A309A;Lo;0;L;;;;;N;;;;; +1065E;LINEAR A SIGN A309B;Lo;0;L;;;;;N;;;;; +1065F;LINEAR A SIGN A309C;Lo;0;L;;;;;N;;;;; +10660;LINEAR A SIGN A310;Lo;0;L;;;;;N;;;;; +10661;LINEAR A SIGN A311;Lo;0;L;;;;;N;;;;; +10662;LINEAR A SIGN A312;Lo;0;L;;;;;N;;;;; +10663;LINEAR A SIGN A313A;Lo;0;L;;;;;N;;;;; +10664;LINEAR A SIGN A313B;Lo;0;L;;;;;N;;;;; +10665;LINEAR A SIGN A313C;Lo;0;L;;;;;N;;;;; +10666;LINEAR A SIGN A314;Lo;0;L;;;;;N;;;;; +10667;LINEAR A SIGN A315;Lo;0;L;;;;;N;;;;; +10668;LINEAR A SIGN A316;Lo;0;L;;;;;N;;;;; +10669;LINEAR A SIGN A317;Lo;0;L;;;;;N;;;;; +1066A;LINEAR A SIGN A318;Lo;0;L;;;;;N;;;;; +1066B;LINEAR A SIGN A319;Lo;0;L;;;;;N;;;;; +1066C;LINEAR A SIGN A320;Lo;0;L;;;;;N;;;;; +1066D;LINEAR A SIGN A321;Lo;0;L;;;;;N;;;;; +1066E;LINEAR A SIGN A322;Lo;0;L;;;;;N;;;;; +1066F;LINEAR A SIGN A323;Lo;0;L;;;;;N;;;;; +10670;LINEAR A SIGN A324;Lo;0;L;;;;;N;;;;; +10671;LINEAR A SIGN A325;Lo;0;L;;;;;N;;;;; +10672;LINEAR A SIGN A326;Lo;0;L;;;;;N;;;;; +10673;LINEAR A SIGN A327;Lo;0;L;;;;;N;;;;; +10674;LINEAR A SIGN A328;Lo;0;L;;;;;N;;;;; +10675;LINEAR A SIGN A329;Lo;0;L;;;;;N;;;;; +10676;LINEAR A SIGN A330;Lo;0;L;;;;;N;;;;; +10677;LINEAR A SIGN A331;Lo;0;L;;;;;N;;;;; +10678;LINEAR A SIGN A332;Lo;0;L;;;;;N;;;;; +10679;LINEAR A SIGN A333;Lo;0;L;;;;;N;;;;; +1067A;LINEAR A SIGN A334;Lo;0;L;;;;;N;;;;; +1067B;LINEAR A SIGN A335;Lo;0;L;;;;;N;;;;; +1067C;LINEAR A SIGN A336;Lo;0;L;;;;;N;;;;; +1067D;LINEAR A SIGN A337;Lo;0;L;;;;;N;;;;; +1067E;LINEAR A SIGN A338;Lo;0;L;;;;;N;;;;; +1067F;LINEAR A SIGN A339;Lo;0;L;;;;;N;;;;; +10680;LINEAR A SIGN A340;Lo;0;L;;;;;N;;;;; +10681;LINEAR A SIGN A341;Lo;0;L;;;;;N;;;;; +10682;LINEAR A SIGN A342;Lo;0;L;;;;;N;;;;; +10683;LINEAR A SIGN A343;Lo;0;L;;;;;N;;;;; +10684;LINEAR A SIGN A344;Lo;0;L;;;;;N;;;;; +10685;LINEAR A SIGN A345;Lo;0;L;;;;;N;;;;; +10686;LINEAR A SIGN A346;Lo;0;L;;;;;N;;;;; +10687;LINEAR A SIGN A347;Lo;0;L;;;;;N;;;;; +10688;LINEAR A SIGN A348;Lo;0;L;;;;;N;;;;; +10689;LINEAR A SIGN A349;Lo;0;L;;;;;N;;;;; +1068A;LINEAR A SIGN A350;Lo;0;L;;;;;N;;;;; +1068B;LINEAR A SIGN A351;Lo;0;L;;;;;N;;;;; +1068C;LINEAR A SIGN A352;Lo;0;L;;;;;N;;;;; +1068D;LINEAR A SIGN A353;Lo;0;L;;;;;N;;;;; +1068E;LINEAR A SIGN A354;Lo;0;L;;;;;N;;;;; +1068F;LINEAR A SIGN A355;Lo;0;L;;;;;N;;;;; +10690;LINEAR A SIGN A356;Lo;0;L;;;;;N;;;;; +10691;LINEAR A SIGN A357;Lo;0;L;;;;;N;;;;; +10692;LINEAR A SIGN A358;Lo;0;L;;;;;N;;;;; +10693;LINEAR A SIGN A359;Lo;0;L;;;;;N;;;;; +10694;LINEAR A SIGN A360;Lo;0;L;;;;;N;;;;; +10695;LINEAR A SIGN A361;Lo;0;L;;;;;N;;;;; +10696;LINEAR A SIGN A362;Lo;0;L;;;;;N;;;;; +10697;LINEAR A SIGN A363;Lo;0;L;;;;;N;;;;; +10698;LINEAR A SIGN A364;Lo;0;L;;;;;N;;;;; +10699;LINEAR A SIGN A365;Lo;0;L;;;;;N;;;;; +1069A;LINEAR A SIGN A366;Lo;0;L;;;;;N;;;;; +1069B;LINEAR A SIGN A367;Lo;0;L;;;;;N;;;;; +1069C;LINEAR A SIGN A368;Lo;0;L;;;;;N;;;;; +1069D;LINEAR A SIGN A369;Lo;0;L;;;;;N;;;;; +1069E;LINEAR A SIGN A370;Lo;0;L;;;;;N;;;;; +1069F;LINEAR A SIGN A371;Lo;0;L;;;;;N;;;;; +106A0;LINEAR A SIGN A400-VAS;Lo;0;L;;;;;N;;;;; +106A1;LINEAR A SIGN A401-VAS;Lo;0;L;;;;;N;;;;; +106A2;LINEAR A SIGN A402-VAS;Lo;0;L;;;;;N;;;;; +106A3;LINEAR A SIGN A403-VAS;Lo;0;L;;;;;N;;;;; +106A4;LINEAR A SIGN A404-VAS;Lo;0;L;;;;;N;;;;; +106A5;LINEAR A SIGN A405-VAS;Lo;0;L;;;;;N;;;;; +106A6;LINEAR A SIGN A406-VAS;Lo;0;L;;;;;N;;;;; +106A7;LINEAR A SIGN A407-VAS;Lo;0;L;;;;;N;;;;; +106A8;LINEAR A SIGN A408-VAS;Lo;0;L;;;;;N;;;;; +106A9;LINEAR A SIGN A409-VAS;Lo;0;L;;;;;N;;;;; +106AA;LINEAR A SIGN A410-VAS;Lo;0;L;;;;;N;;;;; +106AB;LINEAR A SIGN A411-VAS;Lo;0;L;;;;;N;;;;; +106AC;LINEAR A SIGN A412-VAS;Lo;0;L;;;;;N;;;;; +106AD;LINEAR A SIGN A413-VAS;Lo;0;L;;;;;N;;;;; +106AE;LINEAR A SIGN A414-VAS;Lo;0;L;;;;;N;;;;; +106AF;LINEAR A SIGN A415-VAS;Lo;0;L;;;;;N;;;;; +106B0;LINEAR A SIGN A416-VAS;Lo;0;L;;;;;N;;;;; +106B1;LINEAR A SIGN A417-VAS;Lo;0;L;;;;;N;;;;; +106B2;LINEAR A SIGN A418-VAS;Lo;0;L;;;;;N;;;;; +106B3;LINEAR A SIGN A501;Lo;0;L;;;;;N;;;;; +106B4;LINEAR A SIGN A502;Lo;0;L;;;;;N;;;;; +106B5;LINEAR A SIGN A503;Lo;0;L;;;;;N;;;;; +106B6;LINEAR A SIGN A504;Lo;0;L;;;;;N;;;;; +106B7;LINEAR A SIGN A505;Lo;0;L;;;;;N;;;;; +106B8;LINEAR A SIGN A506;Lo;0;L;;;;;N;;;;; +106B9;LINEAR A SIGN A508;Lo;0;L;;;;;N;;;;; +106BA;LINEAR A SIGN A509;Lo;0;L;;;;;N;;;;; +106BB;LINEAR A SIGN A510;Lo;0;L;;;;;N;;;;; +106BC;LINEAR A SIGN A511;Lo;0;L;;;;;N;;;;; +106BD;LINEAR A SIGN A512;Lo;0;L;;;;;N;;;;; +106BE;LINEAR A SIGN A513;Lo;0;L;;;;;N;;;;; +106BF;LINEAR A SIGN A515;Lo;0;L;;;;;N;;;;; +106C0;LINEAR A SIGN A516;Lo;0;L;;;;;N;;;;; +106C1;LINEAR A SIGN A520;Lo;0;L;;;;;N;;;;; +106C2;LINEAR A SIGN A521;Lo;0;L;;;;;N;;;;; +106C3;LINEAR A SIGN A523;Lo;0;L;;;;;N;;;;; +106C4;LINEAR A SIGN A524;Lo;0;L;;;;;N;;;;; +106C5;LINEAR A SIGN A525;Lo;0;L;;;;;N;;;;; +106C6;LINEAR A SIGN A526;Lo;0;L;;;;;N;;;;; +106C7;LINEAR A SIGN A527;Lo;0;L;;;;;N;;;;; +106C8;LINEAR A SIGN A528;Lo;0;L;;;;;N;;;;; +106C9;LINEAR A SIGN A529;Lo;0;L;;;;;N;;;;; +106CA;LINEAR A SIGN A530;Lo;0;L;;;;;N;;;;; +106CB;LINEAR A SIGN A531;Lo;0;L;;;;;N;;;;; +106CC;LINEAR A SIGN A532;Lo;0;L;;;;;N;;;;; +106CD;LINEAR A SIGN A534;Lo;0;L;;;;;N;;;;; +106CE;LINEAR A SIGN A535;Lo;0;L;;;;;N;;;;; +106CF;LINEAR A SIGN A536;Lo;0;L;;;;;N;;;;; +106D0;LINEAR A SIGN A537;Lo;0;L;;;;;N;;;;; +106D1;LINEAR A SIGN A538;Lo;0;L;;;;;N;;;;; +106D2;LINEAR A SIGN A539;Lo;0;L;;;;;N;;;;; +106D3;LINEAR A SIGN A540;Lo;0;L;;;;;N;;;;; +106D4;LINEAR A SIGN A541;Lo;0;L;;;;;N;;;;; +106D5;LINEAR A SIGN A542;Lo;0;L;;;;;N;;;;; +106D6;LINEAR A SIGN A545;Lo;0;L;;;;;N;;;;; +106D7;LINEAR A SIGN A547;Lo;0;L;;;;;N;;;;; +106D8;LINEAR A SIGN A548;Lo;0;L;;;;;N;;;;; +106D9;LINEAR A SIGN A549;Lo;0;L;;;;;N;;;;; +106DA;LINEAR A SIGN A550;Lo;0;L;;;;;N;;;;; +106DB;LINEAR A SIGN A551;Lo;0;L;;;;;N;;;;; +106DC;LINEAR A SIGN A552;Lo;0;L;;;;;N;;;;; +106DD;LINEAR A SIGN A553;Lo;0;L;;;;;N;;;;; +106DE;LINEAR A SIGN A554;Lo;0;L;;;;;N;;;;; +106DF;LINEAR A SIGN A555;Lo;0;L;;;;;N;;;;; +106E0;LINEAR A SIGN A556;Lo;0;L;;;;;N;;;;; +106E1;LINEAR A SIGN A557;Lo;0;L;;;;;N;;;;; +106E2;LINEAR A SIGN A559;Lo;0;L;;;;;N;;;;; +106E3;LINEAR A SIGN A563;Lo;0;L;;;;;N;;;;; +106E4;LINEAR A SIGN A564;Lo;0;L;;;;;N;;;;; +106E5;LINEAR A SIGN A565;Lo;0;L;;;;;N;;;;; +106E6;LINEAR A SIGN A566;Lo;0;L;;;;;N;;;;; +106E7;LINEAR A SIGN A568;Lo;0;L;;;;;N;;;;; +106E8;LINEAR A SIGN A569;Lo;0;L;;;;;N;;;;; +106E9;LINEAR A SIGN A570;Lo;0;L;;;;;N;;;;; +106EA;LINEAR A SIGN A571;Lo;0;L;;;;;N;;;;; +106EB;LINEAR A SIGN A572;Lo;0;L;;;;;N;;;;; +106EC;LINEAR A SIGN A573;Lo;0;L;;;;;N;;;;; +106ED;LINEAR A SIGN A574;Lo;0;L;;;;;N;;;;; +106EE;LINEAR A SIGN A575;Lo;0;L;;;;;N;;;;; +106EF;LINEAR A SIGN A576;Lo;0;L;;;;;N;;;;; +106F0;LINEAR A SIGN A577;Lo;0;L;;;;;N;;;;; +106F1;LINEAR A SIGN A578;Lo;0;L;;;;;N;;;;; +106F2;LINEAR A SIGN A579;Lo;0;L;;;;;N;;;;; +106F3;LINEAR A SIGN A580;Lo;0;L;;;;;N;;;;; +106F4;LINEAR A SIGN A581;Lo;0;L;;;;;N;;;;; +106F5;LINEAR A SIGN A582;Lo;0;L;;;;;N;;;;; +106F6;LINEAR A SIGN A583;Lo;0;L;;;;;N;;;;; +106F7;LINEAR A SIGN A584;Lo;0;L;;;;;N;;;;; +106F8;LINEAR A SIGN A585;Lo;0;L;;;;;N;;;;; +106F9;LINEAR A SIGN A586;Lo;0;L;;;;;N;;;;; +106FA;LINEAR A SIGN A587;Lo;0;L;;;;;N;;;;; +106FB;LINEAR A SIGN A588;Lo;0;L;;;;;N;;;;; +106FC;LINEAR A SIGN A589;Lo;0;L;;;;;N;;;;; +106FD;LINEAR A SIGN A591;Lo;0;L;;;;;N;;;;; +106FE;LINEAR A SIGN A592;Lo;0;L;;;;;N;;;;; +106FF;LINEAR A SIGN A594;Lo;0;L;;;;;N;;;;; +10700;LINEAR A SIGN A595;Lo;0;L;;;;;N;;;;; +10701;LINEAR A SIGN A596;Lo;0;L;;;;;N;;;;; +10702;LINEAR A SIGN A598;Lo;0;L;;;;;N;;;;; +10703;LINEAR A SIGN A600;Lo;0;L;;;;;N;;;;; +10704;LINEAR A SIGN A601;Lo;0;L;;;;;N;;;;; +10705;LINEAR A SIGN A602;Lo;0;L;;;;;N;;;;; +10706;LINEAR A SIGN A603;Lo;0;L;;;;;N;;;;; +10707;LINEAR A SIGN A604;Lo;0;L;;;;;N;;;;; +10708;LINEAR A SIGN A606;Lo;0;L;;;;;N;;;;; +10709;LINEAR A SIGN A608;Lo;0;L;;;;;N;;;;; +1070A;LINEAR A SIGN A609;Lo;0;L;;;;;N;;;;; +1070B;LINEAR A SIGN A610;Lo;0;L;;;;;N;;;;; +1070C;LINEAR A SIGN A611;Lo;0;L;;;;;N;;;;; +1070D;LINEAR A SIGN A612;Lo;0;L;;;;;N;;;;; +1070E;LINEAR A SIGN A613;Lo;0;L;;;;;N;;;;; +1070F;LINEAR A SIGN A614;Lo;0;L;;;;;N;;;;; +10710;LINEAR A SIGN A615;Lo;0;L;;;;;N;;;;; +10711;LINEAR A SIGN A616;Lo;0;L;;;;;N;;;;; +10712;LINEAR A SIGN A617;Lo;0;L;;;;;N;;;;; +10713;LINEAR A SIGN A618;Lo;0;L;;;;;N;;;;; +10714;LINEAR A SIGN A619;Lo;0;L;;;;;N;;;;; +10715;LINEAR A SIGN A620;Lo;0;L;;;;;N;;;;; +10716;LINEAR A SIGN A621;Lo;0;L;;;;;N;;;;; +10717;LINEAR A SIGN A622;Lo;0;L;;;;;N;;;;; +10718;LINEAR A SIGN A623;Lo;0;L;;;;;N;;;;; +10719;LINEAR A SIGN A624;Lo;0;L;;;;;N;;;;; +1071A;LINEAR A SIGN A626;Lo;0;L;;;;;N;;;;; +1071B;LINEAR A SIGN A627;Lo;0;L;;;;;N;;;;; +1071C;LINEAR A SIGN A628;Lo;0;L;;;;;N;;;;; +1071D;LINEAR A SIGN A629;Lo;0;L;;;;;N;;;;; +1071E;LINEAR A SIGN A634;Lo;0;L;;;;;N;;;;; +1071F;LINEAR A SIGN A637;Lo;0;L;;;;;N;;;;; +10720;LINEAR A SIGN A638;Lo;0;L;;;;;N;;;;; +10721;LINEAR A SIGN A640;Lo;0;L;;;;;N;;;;; +10722;LINEAR A SIGN A642;Lo;0;L;;;;;N;;;;; +10723;LINEAR A SIGN A643;Lo;0;L;;;;;N;;;;; +10724;LINEAR A SIGN A644;Lo;0;L;;;;;N;;;;; +10725;LINEAR A SIGN A645;Lo;0;L;;;;;N;;;;; +10726;LINEAR A SIGN A646;Lo;0;L;;;;;N;;;;; +10727;LINEAR A SIGN A648;Lo;0;L;;;;;N;;;;; +10728;LINEAR A SIGN A649;Lo;0;L;;;;;N;;;;; +10729;LINEAR A SIGN A651;Lo;0;L;;;;;N;;;;; +1072A;LINEAR A SIGN A652;Lo;0;L;;;;;N;;;;; +1072B;LINEAR A SIGN A653;Lo;0;L;;;;;N;;;;; +1072C;LINEAR A SIGN A654;Lo;0;L;;;;;N;;;;; +1072D;LINEAR A SIGN A655;Lo;0;L;;;;;N;;;;; +1072E;LINEAR A SIGN A656;Lo;0;L;;;;;N;;;;; +1072F;LINEAR A SIGN A657;Lo;0;L;;;;;N;;;;; +10730;LINEAR A SIGN A658;Lo;0;L;;;;;N;;;;; +10731;LINEAR A SIGN A659;Lo;0;L;;;;;N;;;;; +10732;LINEAR A SIGN A660;Lo;0;L;;;;;N;;;;; +10733;LINEAR A SIGN A661;Lo;0;L;;;;;N;;;;; +10734;LINEAR A SIGN A662;Lo;0;L;;;;;N;;;;; +10735;LINEAR A SIGN A663;Lo;0;L;;;;;N;;;;; +10736;LINEAR A SIGN A664;Lo;0;L;;;;;N;;;;; +10740;LINEAR A SIGN A701 A;Lo;0;L;;;;;N;;;;; +10741;LINEAR A SIGN A702 B;Lo;0;L;;;;;N;;;;; +10742;LINEAR A SIGN A703 D;Lo;0;L;;;;;N;;;;; +10743;LINEAR A SIGN A704 E;Lo;0;L;;;;;N;;;;; +10744;LINEAR A SIGN A705 F;Lo;0;L;;;;;N;;;;; +10745;LINEAR A SIGN A706 H;Lo;0;L;;;;;N;;;;; +10746;LINEAR A SIGN A707 J;Lo;0;L;;;;;N;;;;; +10747;LINEAR A SIGN A708 K;Lo;0;L;;;;;N;;;;; +10748;LINEAR A SIGN A709 L;Lo;0;L;;;;;N;;;;; +10749;LINEAR A SIGN A709-2 L2;Lo;0;L;;;;;N;;;;; +1074A;LINEAR A SIGN A709-3 L3;Lo;0;L;;;;;N;;;;; +1074B;LINEAR A SIGN A709-4 L4;Lo;0;L;;;;;N;;;;; +1074C;LINEAR A SIGN A709-6 L6;Lo;0;L;;;;;N;;;;; +1074D;LINEAR A SIGN A710 W;Lo;0;L;;;;;N;;;;; +1074E;LINEAR A SIGN A711 X;Lo;0;L;;;;;N;;;;; +1074F;LINEAR A SIGN A712 Y;Lo;0;L;;;;;N;;;;; +10750;LINEAR A SIGN A713 OMEGA;Lo;0;L;;;;;N;;;;; +10751;LINEAR A SIGN A714 ABB;Lo;0;L;;;;;N;;;;; +10752;LINEAR A SIGN A715 BB;Lo;0;L;;;;;N;;;;; +10753;LINEAR A SIGN A717 DD;Lo;0;L;;;;;N;;;;; +10754;LINEAR A SIGN A726 EYYY;Lo;0;L;;;;;N;;;;; +10755;LINEAR A SIGN A732 JE;Lo;0;L;;;;;N;;;;; +10760;LINEAR A SIGN A800;Lo;0;L;;;;;N;;;;; +10761;LINEAR A SIGN A801;Lo;0;L;;;;;N;;;;; +10762;LINEAR A SIGN A802;Lo;0;L;;;;;N;;;;; +10763;LINEAR A SIGN A803;Lo;0;L;;;;;N;;;;; +10764;LINEAR A SIGN A804;Lo;0;L;;;;;N;;;;; +10765;LINEAR A SIGN A805;Lo;0;L;;;;;N;;;;; +10766;LINEAR A SIGN A806;Lo;0;L;;;;;N;;;;; +10767;LINEAR A SIGN A807;Lo;0;L;;;;;N;;;;; +10780;MODIFIER LETTER SMALL CAPITAL AA;Lm;0;L;;;;;N;;;;; +10781;MODIFIER LETTER SUPERSCRIPT TRIANGULAR COLON;Lm;0;L; 02D0;;;;N;;;;; +10782;MODIFIER LETTER SUPERSCRIPT HALF TRIANGULAR COLON;Lm;0;L; 02D1;;;;N;;;;; +10783;MODIFIER LETTER SMALL AE;Lm;0;L; 00E6;;;;N;;;;; +10784;MODIFIER LETTER SMALL CAPITAL B;Lm;0;L; 0299;;;;N;;;;; +10785;MODIFIER LETTER SMALL B WITH HOOK;Lm;0;L; 0253;;;;N;;;;; +10787;MODIFIER LETTER SMALL DZ DIGRAPH;Lm;0;L; 02A3;;;;N;;;;; +10788;MODIFIER LETTER SMALL DZ DIGRAPH WITH RETROFLEX HOOK;Lm;0;L; AB66;;;;N;;;;; +10789;MODIFIER LETTER SMALL DZ DIGRAPH WITH CURL;Lm;0;L; 02A5;;;;N;;;;; +1078A;MODIFIER LETTER SMALL DEZH DIGRAPH;Lm;0;L; 02A4;;;;N;;;;; +1078B;MODIFIER LETTER SMALL D WITH TAIL;Lm;0;L; 0256;;;;N;;;;; +1078C;MODIFIER LETTER SMALL D WITH HOOK;Lm;0;L; 0257;;;;N;;;;; +1078D;MODIFIER LETTER SMALL D WITH HOOK AND TAIL;Lm;0;L; 1D91;;;;N;;;;; +1078E;MODIFIER LETTER SMALL REVERSED E;Lm;0;L; 0258;;;;N;;;;; +1078F;MODIFIER LETTER SMALL CLOSED REVERSED OPEN E;Lm;0;L; 025E;;;;N;;;;; +10790;MODIFIER LETTER SMALL FENG DIGRAPH;Lm;0;L; 02A9;;;;N;;;;; +10791;MODIFIER LETTER SMALL RAMS HORN;Lm;0;L; 0264;;;;N;;;;; +10792;MODIFIER LETTER SMALL CAPITAL G;Lm;0;L; 0262;;;;N;;;;; +10793;MODIFIER LETTER SMALL G WITH HOOK;Lm;0;L; 0260;;;;N;;;;; +10794;MODIFIER LETTER SMALL CAPITAL G WITH HOOK;Lm;0;L; 029B;;;;N;;;;; +10795;MODIFIER LETTER SMALL H WITH STROKE;Lm;0;L; 0127;;;;N;;;;; +10796;MODIFIER LETTER SMALL CAPITAL H;Lm;0;L; 029C;;;;N;;;;; +10797;MODIFIER LETTER SMALL HENG WITH HOOK;Lm;0;L; 0267;;;;N;;;;; +10798;MODIFIER LETTER SMALL DOTLESS J WITH STROKE AND HOOK;Lm;0;L; 0284;;;;N;;;;; +10799;MODIFIER LETTER SMALL LS DIGRAPH;Lm;0;L; 02AA;;;;N;;;;; +1079A;MODIFIER LETTER SMALL LZ DIGRAPH;Lm;0;L; 02AB;;;;N;;;;; +1079B;MODIFIER LETTER SMALL L WITH BELT;Lm;0;L; 026C;;;;N;;;;; +1079C;MODIFIER LETTER SMALL CAPITAL L WITH BELT;Lm;0;L; 1DF04;;;;N;;;;; +1079D;MODIFIER LETTER SMALL L WITH RETROFLEX HOOK AND BELT;Lm;0;L; A78E;;;;N;;;;; +1079E;MODIFIER LETTER SMALL LEZH;Lm;0;L; 026E;;;;N;;;;; +1079F;MODIFIER LETTER SMALL LEZH WITH RETROFLEX HOOK;Lm;0;L; 1DF05;;;;N;;;;; +107A0;MODIFIER LETTER SMALL TURNED Y;Lm;0;L; 028E;;;;N;;;;; +107A1;MODIFIER LETTER SMALL TURNED Y WITH BELT;Lm;0;L; 1DF06;;;;N;;;;; +107A2;MODIFIER LETTER SMALL O WITH STROKE;Lm;0;L; 00F8;;;;N;;;;; +107A3;MODIFIER LETTER SMALL CAPITAL OE;Lm;0;L; 0276;;;;N;;;;; +107A4;MODIFIER LETTER SMALL CLOSED OMEGA;Lm;0;L; 0277;;;;N;;;;; +107A5;MODIFIER LETTER SMALL Q;Lm;0;L; 0071;;;;N;;;;; +107A6;MODIFIER LETTER SMALL TURNED R WITH LONG LEG;Lm;0;L; 027A;;;;N;;;;; +107A7;MODIFIER LETTER SMALL TURNED R WITH LONG LEG AND RETROFLEX HOOK;Lm;0;L; 1DF08;;;;N;;;;; +107A8;MODIFIER LETTER SMALL R WITH TAIL;Lm;0;L; 027D;;;;N;;;;; +107A9;MODIFIER LETTER SMALL R WITH FISHHOOK;Lm;0;L; 027E;;;;N;;;;; +107AA;MODIFIER LETTER SMALL CAPITAL R;Lm;0;L; 0280;;;;N;;;;; +107AB;MODIFIER LETTER SMALL TC DIGRAPH WITH CURL;Lm;0;L; 02A8;;;;N;;;;; +107AC;MODIFIER LETTER SMALL TS DIGRAPH;Lm;0;L; 02A6;;;;N;;;;; +107AD;MODIFIER LETTER SMALL TS DIGRAPH WITH RETROFLEX HOOK;Lm;0;L; AB67;;;;N;;;;; +107AE;MODIFIER LETTER SMALL TESH DIGRAPH;Lm;0;L; 02A7;;;;N;;;;; +107AF;MODIFIER LETTER SMALL T WITH RETROFLEX HOOK;Lm;0;L; 0288;;;;N;;;;; +107B0;MODIFIER LETTER SMALL V WITH RIGHT HOOK;Lm;0;L; 2C71;;;;N;;;;; +107B2;MODIFIER LETTER SMALL CAPITAL Y;Lm;0;L; 028F;;;;N;;;;; +107B3;MODIFIER LETTER GLOTTAL STOP WITH STROKE;Lm;0;L; 02A1;;;;N;;;;; +107B4;MODIFIER LETTER REVERSED GLOTTAL STOP WITH STROKE;Lm;0;L; 02A2;;;;N;;;;; +107B5;MODIFIER LETTER BILABIAL CLICK;Lm;0;L; 0298;;;;N;;;;; +107B6;MODIFIER LETTER DENTAL CLICK;Lm;0;L; 01C0;;;;N;;;;; +107B7;MODIFIER LETTER LATERAL CLICK;Lm;0;L; 01C1;;;;N;;;;; +107B8;MODIFIER LETTER ALVEOLAR CLICK;Lm;0;L; 01C2;;;;N;;;;; +107B9;MODIFIER LETTER RETROFLEX CLICK WITH RETROFLEX HOOK;Lm;0;L; 1DF0A;;;;N;;;;; +107BA;MODIFIER LETTER SMALL S WITH CURL;Lm;0;L; 1DF1E;;;;N;;;;; +10800;CYPRIOT SYLLABLE A;Lo;0;R;;;;;N;;;;; +10801;CYPRIOT SYLLABLE E;Lo;0;R;;;;;N;;;;; +10802;CYPRIOT SYLLABLE I;Lo;0;R;;;;;N;;;;; +10803;CYPRIOT SYLLABLE O;Lo;0;R;;;;;N;;;;; +10804;CYPRIOT SYLLABLE U;Lo;0;R;;;;;N;;;;; +10805;CYPRIOT SYLLABLE JA;Lo;0;R;;;;;N;;;;; +10808;CYPRIOT SYLLABLE JO;Lo;0;R;;;;;N;;;;; +1080A;CYPRIOT SYLLABLE KA;Lo;0;R;;;;;N;;;;; +1080B;CYPRIOT SYLLABLE KE;Lo;0;R;;;;;N;;;;; +1080C;CYPRIOT SYLLABLE KI;Lo;0;R;;;;;N;;;;; +1080D;CYPRIOT SYLLABLE KO;Lo;0;R;;;;;N;;;;; +1080E;CYPRIOT SYLLABLE KU;Lo;0;R;;;;;N;;;;; +1080F;CYPRIOT SYLLABLE LA;Lo;0;R;;;;;N;;;;; +10810;CYPRIOT SYLLABLE LE;Lo;0;R;;;;;N;;;;; +10811;CYPRIOT SYLLABLE LI;Lo;0;R;;;;;N;;;;; +10812;CYPRIOT SYLLABLE LO;Lo;0;R;;;;;N;;;;; +10813;CYPRIOT SYLLABLE LU;Lo;0;R;;;;;N;;;;; +10814;CYPRIOT SYLLABLE MA;Lo;0;R;;;;;N;;;;; +10815;CYPRIOT SYLLABLE ME;Lo;0;R;;;;;N;;;;; +10816;CYPRIOT SYLLABLE MI;Lo;0;R;;;;;N;;;;; +10817;CYPRIOT SYLLABLE MO;Lo;0;R;;;;;N;;;;; +10818;CYPRIOT SYLLABLE MU;Lo;0;R;;;;;N;;;;; +10819;CYPRIOT SYLLABLE NA;Lo;0;R;;;;;N;;;;; +1081A;CYPRIOT SYLLABLE NE;Lo;0;R;;;;;N;;;;; +1081B;CYPRIOT SYLLABLE NI;Lo;0;R;;;;;N;;;;; +1081C;CYPRIOT SYLLABLE NO;Lo;0;R;;;;;N;;;;; +1081D;CYPRIOT SYLLABLE NU;Lo;0;R;;;;;N;;;;; +1081E;CYPRIOT SYLLABLE PA;Lo;0;R;;;;;N;;;;; +1081F;CYPRIOT SYLLABLE PE;Lo;0;R;;;;;N;;;;; +10820;CYPRIOT SYLLABLE PI;Lo;0;R;;;;;N;;;;; +10821;CYPRIOT SYLLABLE PO;Lo;0;R;;;;;N;;;;; +10822;CYPRIOT SYLLABLE PU;Lo;0;R;;;;;N;;;;; +10823;CYPRIOT SYLLABLE RA;Lo;0;R;;;;;N;;;;; +10824;CYPRIOT SYLLABLE RE;Lo;0;R;;;;;N;;;;; +10825;CYPRIOT SYLLABLE RI;Lo;0;R;;;;;N;;;;; +10826;CYPRIOT SYLLABLE RO;Lo;0;R;;;;;N;;;;; +10827;CYPRIOT SYLLABLE RU;Lo;0;R;;;;;N;;;;; +10828;CYPRIOT SYLLABLE SA;Lo;0;R;;;;;N;;;;; +10829;CYPRIOT SYLLABLE SE;Lo;0;R;;;;;N;;;;; +1082A;CYPRIOT SYLLABLE SI;Lo;0;R;;;;;N;;;;; +1082B;CYPRIOT SYLLABLE SO;Lo;0;R;;;;;N;;;;; +1082C;CYPRIOT SYLLABLE SU;Lo;0;R;;;;;N;;;;; +1082D;CYPRIOT SYLLABLE TA;Lo;0;R;;;;;N;;;;; +1082E;CYPRIOT SYLLABLE TE;Lo;0;R;;;;;N;;;;; +1082F;CYPRIOT SYLLABLE TI;Lo;0;R;;;;;N;;;;; +10830;CYPRIOT SYLLABLE TO;Lo;0;R;;;;;N;;;;; +10831;CYPRIOT SYLLABLE TU;Lo;0;R;;;;;N;;;;; +10832;CYPRIOT SYLLABLE WA;Lo;0;R;;;;;N;;;;; +10833;CYPRIOT SYLLABLE WE;Lo;0;R;;;;;N;;;;; +10834;CYPRIOT SYLLABLE WI;Lo;0;R;;;;;N;;;;; +10835;CYPRIOT SYLLABLE WO;Lo;0;R;;;;;N;;;;; +10837;CYPRIOT SYLLABLE XA;Lo;0;R;;;;;N;;;;; +10838;CYPRIOT SYLLABLE XE;Lo;0;R;;;;;N;;;;; +1083C;CYPRIOT SYLLABLE ZA;Lo;0;R;;;;;N;;;;; +1083F;CYPRIOT SYLLABLE ZO;Lo;0;R;;;;;N;;;;; +10840;IMPERIAL ARAMAIC LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10841;IMPERIAL ARAMAIC LETTER BETH;Lo;0;R;;;;;N;;;;; +10842;IMPERIAL ARAMAIC LETTER GIMEL;Lo;0;R;;;;;N;;;;; +10843;IMPERIAL ARAMAIC LETTER DALETH;Lo;0;R;;;;;N;;;;; +10844;IMPERIAL ARAMAIC LETTER HE;Lo;0;R;;;;;N;;;;; +10845;IMPERIAL ARAMAIC LETTER WAW;Lo;0;R;;;;;N;;;;; +10846;IMPERIAL ARAMAIC LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +10847;IMPERIAL ARAMAIC LETTER HETH;Lo;0;R;;;;;N;;;;; +10848;IMPERIAL ARAMAIC LETTER TETH;Lo;0;R;;;;;N;;;;; +10849;IMPERIAL ARAMAIC LETTER YODH;Lo;0;R;;;;;N;;;;; +1084A;IMPERIAL ARAMAIC LETTER KAPH;Lo;0;R;;;;;N;;;;; +1084B;IMPERIAL ARAMAIC LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +1084C;IMPERIAL ARAMAIC LETTER MEM;Lo;0;R;;;;;N;;;;; +1084D;IMPERIAL ARAMAIC LETTER NUN;Lo;0;R;;;;;N;;;;; +1084E;IMPERIAL ARAMAIC LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +1084F;IMPERIAL ARAMAIC LETTER AYIN;Lo;0;R;;;;;N;;;;; +10850;IMPERIAL ARAMAIC LETTER PE;Lo;0;R;;;;;N;;;;; +10851;IMPERIAL ARAMAIC LETTER SADHE;Lo;0;R;;;;;N;;;;; +10852;IMPERIAL ARAMAIC LETTER QOPH;Lo;0;R;;;;;N;;;;; +10853;IMPERIAL ARAMAIC LETTER RESH;Lo;0;R;;;;;N;;;;; +10854;IMPERIAL ARAMAIC LETTER SHIN;Lo;0;R;;;;;N;;;;; +10855;IMPERIAL ARAMAIC LETTER TAW;Lo;0;R;;;;;N;;;;; +10857;IMPERIAL ARAMAIC SECTION SIGN;Po;0;R;;;;;N;;;;; +10858;IMPERIAL ARAMAIC NUMBER ONE;No;0;R;;;;1;N;;;;; +10859;IMPERIAL ARAMAIC NUMBER TWO;No;0;R;;;;2;N;;;;; +1085A;IMPERIAL ARAMAIC NUMBER THREE;No;0;R;;;;3;N;;;;; +1085B;IMPERIAL ARAMAIC NUMBER TEN;No;0;R;;;;10;N;;;;; +1085C;IMPERIAL ARAMAIC NUMBER TWENTY;No;0;R;;;;20;N;;;;; +1085D;IMPERIAL ARAMAIC NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +1085E;IMPERIAL ARAMAIC NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; +1085F;IMPERIAL ARAMAIC NUMBER TEN THOUSAND;No;0;R;;;;10000;N;;;;; +10860;PALMYRENE LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10861;PALMYRENE LETTER BETH;Lo;0;R;;;;;N;;;;; +10862;PALMYRENE LETTER GIMEL;Lo;0;R;;;;;N;;;;; +10863;PALMYRENE LETTER DALETH;Lo;0;R;;;;;N;;;;; +10864;PALMYRENE LETTER HE;Lo;0;R;;;;;N;;;;; +10865;PALMYRENE LETTER WAW;Lo;0;R;;;;;N;;;;; +10866;PALMYRENE LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +10867;PALMYRENE LETTER HETH;Lo;0;R;;;;;N;;;;; +10868;PALMYRENE LETTER TETH;Lo;0;R;;;;;N;;;;; +10869;PALMYRENE LETTER YODH;Lo;0;R;;;;;N;;;;; +1086A;PALMYRENE LETTER KAPH;Lo;0;R;;;;;N;;;;; +1086B;PALMYRENE LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +1086C;PALMYRENE LETTER MEM;Lo;0;R;;;;;N;;;;; +1086D;PALMYRENE LETTER FINAL NUN;Lo;0;R;;;;;N;;;;; +1086E;PALMYRENE LETTER NUN;Lo;0;R;;;;;N;;;;; +1086F;PALMYRENE LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10870;PALMYRENE LETTER AYIN;Lo;0;R;;;;;N;;;;; +10871;PALMYRENE LETTER PE;Lo;0;R;;;;;N;;;;; +10872;PALMYRENE LETTER SADHE;Lo;0;R;;;;;N;;;;; +10873;PALMYRENE LETTER QOPH;Lo;0;R;;;;;N;;;;; +10874;PALMYRENE LETTER RESH;Lo;0;R;;;;;N;;;;; +10875;PALMYRENE LETTER SHIN;Lo;0;R;;;;;N;;;;; +10876;PALMYRENE LETTER TAW;Lo;0;R;;;;;N;;;;; +10877;PALMYRENE LEFT-POINTING FLEURON;So;0;R;;;;;N;;;;; +10878;PALMYRENE RIGHT-POINTING FLEURON;So;0;R;;;;;N;;;;; +10879;PALMYRENE NUMBER ONE;No;0;R;;;;1;N;;;;; +1087A;PALMYRENE NUMBER TWO;No;0;R;;;;2;N;;;;; +1087B;PALMYRENE NUMBER THREE;No;0;R;;;;3;N;;;;; +1087C;PALMYRENE NUMBER FOUR;No;0;R;;;;4;N;;;;; +1087D;PALMYRENE NUMBER FIVE;No;0;R;;;;5;N;;;;; +1087E;PALMYRENE NUMBER TEN;No;0;R;;;;10;N;;;;; +1087F;PALMYRENE NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10880;NABATAEAN LETTER FINAL ALEPH;Lo;0;R;;;;;N;;;;; +10881;NABATAEAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10882;NABATAEAN LETTER FINAL BETH;Lo;0;R;;;;;N;;;;; +10883;NABATAEAN LETTER BETH;Lo;0;R;;;;;N;;;;; +10884;NABATAEAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; +10885;NABATAEAN LETTER DALETH;Lo;0;R;;;;;N;;;;; +10886;NABATAEAN LETTER FINAL HE;Lo;0;R;;;;;N;;;;; +10887;NABATAEAN LETTER HE;Lo;0;R;;;;;N;;;;; +10888;NABATAEAN LETTER WAW;Lo;0;R;;;;;N;;;;; +10889;NABATAEAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +1088A;NABATAEAN LETTER HETH;Lo;0;R;;;;;N;;;;; +1088B;NABATAEAN LETTER TETH;Lo;0;R;;;;;N;;;;; +1088C;NABATAEAN LETTER FINAL YODH;Lo;0;R;;;;;N;;;;; +1088D;NABATAEAN LETTER YODH;Lo;0;R;;;;;N;;;;; +1088E;NABATAEAN LETTER FINAL KAPH;Lo;0;R;;;;;N;;;;; +1088F;NABATAEAN LETTER KAPH;Lo;0;R;;;;;N;;;;; +10890;NABATAEAN LETTER FINAL LAMEDH;Lo;0;R;;;;;N;;;;; +10891;NABATAEAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +10892;NABATAEAN LETTER FINAL MEM;Lo;0;R;;;;;N;;;;; +10893;NABATAEAN LETTER MEM;Lo;0;R;;;;;N;;;;; +10894;NABATAEAN LETTER FINAL NUN;Lo;0;R;;;;;N;;;;; +10895;NABATAEAN LETTER NUN;Lo;0;R;;;;;N;;;;; +10896;NABATAEAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10897;NABATAEAN LETTER AYIN;Lo;0;R;;;;;N;;;;; +10898;NABATAEAN LETTER PE;Lo;0;R;;;;;N;;;;; +10899;NABATAEAN LETTER SADHE;Lo;0;R;;;;;N;;;;; +1089A;NABATAEAN LETTER QOPH;Lo;0;R;;;;;N;;;;; +1089B;NABATAEAN LETTER RESH;Lo;0;R;;;;;N;;;;; +1089C;NABATAEAN LETTER FINAL SHIN;Lo;0;R;;;;;N;;;;; +1089D;NABATAEAN LETTER SHIN;Lo;0;R;;;;;N;;;;; +1089E;NABATAEAN LETTER TAW;Lo;0;R;;;;;N;;;;; +108A7;NABATAEAN NUMBER ONE;No;0;R;;;;1;N;;;;; +108A8;NABATAEAN NUMBER TWO;No;0;R;;;;2;N;;;;; +108A9;NABATAEAN NUMBER THREE;No;0;R;;;;3;N;;;;; +108AA;NABATAEAN NUMBER FOUR;No;0;R;;;;4;N;;;;; +108AB;NABATAEAN CRUCIFORM NUMBER FOUR;No;0;R;;;;4;N;;;;; +108AC;NABATAEAN NUMBER FIVE;No;0;R;;;;5;N;;;;; +108AD;NABATAEAN NUMBER TEN;No;0;R;;;;10;N;;;;; +108AE;NABATAEAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; +108AF;NABATAEAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +108E0;HATRAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; +108E1;HATRAN LETTER BETH;Lo;0;R;;;;;N;;;;; +108E2;HATRAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; +108E3;HATRAN LETTER DALETH-RESH;Lo;0;R;;;;;N;;;;; +108E4;HATRAN LETTER HE;Lo;0;R;;;;;N;;;;; +108E5;HATRAN LETTER WAW;Lo;0;R;;;;;N;;;;; +108E6;HATRAN LETTER ZAYN;Lo;0;R;;;;;N;;;;; +108E7;HATRAN LETTER HETH;Lo;0;R;;;;;N;;;;; +108E8;HATRAN LETTER TETH;Lo;0;R;;;;;N;;;;; +108E9;HATRAN LETTER YODH;Lo;0;R;;;;;N;;;;; +108EA;HATRAN LETTER KAPH;Lo;0;R;;;;;N;;;;; +108EB;HATRAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +108EC;HATRAN LETTER MEM;Lo;0;R;;;;;N;;;;; +108ED;HATRAN LETTER NUN;Lo;0;R;;;;;N;;;;; +108EE;HATRAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +108EF;HATRAN LETTER AYN;Lo;0;R;;;;;N;;;;; +108F0;HATRAN LETTER PE;Lo;0;R;;;;;N;;;;; +108F1;HATRAN LETTER SADHE;Lo;0;R;;;;;N;;;;; +108F2;HATRAN LETTER QOPH;Lo;0;R;;;;;N;;;;; +108F4;HATRAN LETTER SHIN;Lo;0;R;;;;;N;;;;; +108F5;HATRAN LETTER TAW;Lo;0;R;;;;;N;;;;; +108FB;HATRAN NUMBER ONE;No;0;R;;;;1;N;;;;; +108FC;HATRAN NUMBER FIVE;No;0;R;;;;5;N;;;;; +108FD;HATRAN NUMBER TEN;No;0;R;;;;10;N;;;;; +108FE;HATRAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; +108FF;HATRAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +10900;PHOENICIAN LETTER ALF;Lo;0;R;;;;;N;;;;; +10901;PHOENICIAN LETTER BET;Lo;0;R;;;;;N;;;;; +10902;PHOENICIAN LETTER GAML;Lo;0;R;;;;;N;;;;; +10903;PHOENICIAN LETTER DELT;Lo;0;R;;;;;N;;;;; +10904;PHOENICIAN LETTER HE;Lo;0;R;;;;;N;;;;; +10905;PHOENICIAN LETTER WAU;Lo;0;R;;;;;N;;;;; +10906;PHOENICIAN LETTER ZAI;Lo;0;R;;;;;N;;;;; +10907;PHOENICIAN LETTER HET;Lo;0;R;;;;;N;;;;; +10908;PHOENICIAN LETTER TET;Lo;0;R;;;;;N;;;;; +10909;PHOENICIAN LETTER YOD;Lo;0;R;;;;;N;;;;; +1090A;PHOENICIAN LETTER KAF;Lo;0;R;;;;;N;;;;; +1090B;PHOENICIAN LETTER LAMD;Lo;0;R;;;;;N;;;;; +1090C;PHOENICIAN LETTER MEM;Lo;0;R;;;;;N;;;;; +1090D;PHOENICIAN LETTER NUN;Lo;0;R;;;;;N;;;;; +1090E;PHOENICIAN LETTER SEMK;Lo;0;R;;;;;N;;;;; +1090F;PHOENICIAN LETTER AIN;Lo;0;R;;;;;N;;;;; +10910;PHOENICIAN LETTER PE;Lo;0;R;;;;;N;;;;; +10911;PHOENICIAN LETTER SADE;Lo;0;R;;;;;N;;;;; +10912;PHOENICIAN LETTER QOF;Lo;0;R;;;;;N;;;;; +10913;PHOENICIAN LETTER ROSH;Lo;0;R;;;;;N;;;;; +10914;PHOENICIAN LETTER SHIN;Lo;0;R;;;;;N;;;;; +10915;PHOENICIAN LETTER TAU;Lo;0;R;;;;;N;;;;; +10916;PHOENICIAN NUMBER ONE;No;0;R;;;;1;N;;;;; +10917;PHOENICIAN NUMBER TEN;No;0;R;;;;10;N;;;;; +10918;PHOENICIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10919;PHOENICIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +1091A;PHOENICIAN NUMBER TWO;No;0;R;;;;2;N;;;;; +1091B;PHOENICIAN NUMBER THREE;No;0;R;;;;3;N;;;;; +1091F;PHOENICIAN WORD SEPARATOR;Po;0;ON;;;;;N;;;;; +10920;LYDIAN LETTER A;Lo;0;R;;;;;N;;;;; +10921;LYDIAN LETTER B;Lo;0;R;;;;;N;;;;; +10922;LYDIAN LETTER G;Lo;0;R;;;;;N;;;;; +10923;LYDIAN LETTER D;Lo;0;R;;;;;N;;;;; +10924;LYDIAN LETTER E;Lo;0;R;;;;;N;;;;; +10925;LYDIAN LETTER V;Lo;0;R;;;;;N;;;;; +10926;LYDIAN LETTER I;Lo;0;R;;;;;N;;;;; +10927;LYDIAN LETTER Y;Lo;0;R;;;;;N;;;;; +10928;LYDIAN LETTER K;Lo;0;R;;;;;N;;;;; +10929;LYDIAN LETTER L;Lo;0;R;;;;;N;;;;; +1092A;LYDIAN LETTER M;Lo;0;R;;;;;N;;;;; +1092B;LYDIAN LETTER N;Lo;0;R;;;;;N;;;;; +1092C;LYDIAN LETTER O;Lo;0;R;;;;;N;;;;; +1092D;LYDIAN LETTER R;Lo;0;R;;;;;N;;;;; +1092E;LYDIAN LETTER SS;Lo;0;R;;;;;N;;;;; +1092F;LYDIAN LETTER T;Lo;0;R;;;;;N;;;;; +10930;LYDIAN LETTER U;Lo;0;R;;;;;N;;;;; +10931;LYDIAN LETTER F;Lo;0;R;;;;;N;;;;; +10932;LYDIAN LETTER Q;Lo;0;R;;;;;N;;;;; +10933;LYDIAN LETTER S;Lo;0;R;;;;;N;;;;; +10934;LYDIAN LETTER TT;Lo;0;R;;;;;N;;;;; +10935;LYDIAN LETTER AN;Lo;0;R;;;;;N;;;;; +10936;LYDIAN LETTER EN;Lo;0;R;;;;;N;;;;; +10937;LYDIAN LETTER LY;Lo;0;R;;;;;N;;;;; +10938;LYDIAN LETTER NN;Lo;0;R;;;;;N;;;;; +10939;LYDIAN LETTER C;Lo;0;R;;;;;N;;;;; +1093F;LYDIAN TRIANGULAR MARK;Po;0;R;;;;;N;;;;; +10940;SIDETIC LETTER N01;Lo;0;R;;;;;N;;;;; +10941;SIDETIC LETTER N02;Lo;0;R;;;;;N;;;;; +10942;SIDETIC LETTER N03;Lo;0;R;;;;;N;;;;; +10943;SIDETIC LETTER N04;Lo;0;R;;;;;N;;;;; +10944;SIDETIC LETTER N05;Lo;0;R;;;;;N;;;;; +10945;SIDETIC LETTER N06;Lo;0;R;;;;;N;;;;; +10946;SIDETIC LETTER N07;Lo;0;R;;;;;N;;;;; +10947;SIDETIC LETTER N08;Lo;0;R;;;;;N;;;;; +10948;SIDETIC LETTER N09;Lo;0;R;;;;;N;;;;; +10949;SIDETIC LETTER N10;Lo;0;R;;;;;N;;;;; +1094A;SIDETIC LETTER N11;Lo;0;R;;;;;N;;;;; +1094B;SIDETIC LETTER N12;Lo;0;R;;;;;N;;;;; +1094C;SIDETIC LETTER N13;Lo;0;R;;;;;N;;;;; +1094D;SIDETIC LETTER N14;Lo;0;R;;;;;N;;;;; +1094E;SIDETIC LETTER N15;Lo;0;R;;;;;N;;;;; +1094F;SIDETIC LETTER N16;Lo;0;R;;;;;N;;;;; +10950;SIDETIC LETTER N17;Lo;0;R;;;;;N;;;;; +10951;SIDETIC LETTER N18;Lo;0;R;;;;;N;;;;; +10952;SIDETIC LETTER N19;Lo;0;R;;;;;N;;;;; +10953;SIDETIC LETTER N20;Lo;0;R;;;;;N;;;;; +10954;SIDETIC LETTER N21;Lo;0;R;;;;;N;;;;; +10955;SIDETIC LETTER N22;Lo;0;R;;;;;N;;;;; +10956;SIDETIC LETTER N23;Lo;0;R;;;;;N;;;;; +10957;SIDETIC LETTER N24;Lo;0;R;;;;;N;;;;; +10958;SIDETIC LETTER N25;Lo;0;R;;;;;N;;;;; +10959;SIDETIC LETTER N26;Lo;0;R;;;;;N;;;;; +10980;MEROITIC HIEROGLYPHIC LETTER A;Lo;0;R;;;;;N;;;;; +10981;MEROITIC HIEROGLYPHIC LETTER E;Lo;0;R;;;;;N;;;;; +10982;MEROITIC HIEROGLYPHIC LETTER I;Lo;0;R;;;;;N;;;;; +10983;MEROITIC HIEROGLYPHIC LETTER O;Lo;0;R;;;;;N;;;;; +10984;MEROITIC HIEROGLYPHIC LETTER YA;Lo;0;R;;;;;N;;;;; +10985;MEROITIC HIEROGLYPHIC LETTER WA;Lo;0;R;;;;;N;;;;; +10986;MEROITIC HIEROGLYPHIC LETTER BA;Lo;0;R;;;;;N;;;;; +10987;MEROITIC HIEROGLYPHIC LETTER BA-2;Lo;0;R;;;;;N;;;;; +10988;MEROITIC HIEROGLYPHIC LETTER PA;Lo;0;R;;;;;N;;;;; +10989;MEROITIC HIEROGLYPHIC LETTER MA;Lo;0;R;;;;;N;;;;; +1098A;MEROITIC HIEROGLYPHIC LETTER NA;Lo;0;R;;;;;N;;;;; +1098B;MEROITIC HIEROGLYPHIC LETTER NA-2;Lo;0;R;;;;;N;;;;; +1098C;MEROITIC HIEROGLYPHIC LETTER NE;Lo;0;R;;;;;N;;;;; +1098D;MEROITIC HIEROGLYPHIC LETTER NE-2;Lo;0;R;;;;;N;;;;; +1098E;MEROITIC HIEROGLYPHIC LETTER RA;Lo;0;R;;;;;N;;;;; +1098F;MEROITIC HIEROGLYPHIC LETTER RA-2;Lo;0;R;;;;;N;;;;; +10990;MEROITIC HIEROGLYPHIC LETTER LA;Lo;0;R;;;;;N;;;;; +10991;MEROITIC HIEROGLYPHIC LETTER KHA;Lo;0;R;;;;;N;;;;; +10992;MEROITIC HIEROGLYPHIC LETTER HHA;Lo;0;R;;;;;N;;;;; +10993;MEROITIC HIEROGLYPHIC LETTER SA;Lo;0;R;;;;;N;;;;; +10994;MEROITIC HIEROGLYPHIC LETTER SA-2;Lo;0;R;;;;;N;;;;; +10995;MEROITIC HIEROGLYPHIC LETTER SE;Lo;0;R;;;;;N;;;;; +10996;MEROITIC HIEROGLYPHIC LETTER KA;Lo;0;R;;;;;N;;;;; +10997;MEROITIC HIEROGLYPHIC LETTER QA;Lo;0;R;;;;;N;;;;; +10998;MEROITIC HIEROGLYPHIC LETTER TA;Lo;0;R;;;;;N;;;;; +10999;MEROITIC HIEROGLYPHIC LETTER TA-2;Lo;0;R;;;;;N;;;;; +1099A;MEROITIC HIEROGLYPHIC LETTER TE;Lo;0;R;;;;;N;;;;; +1099B;MEROITIC HIEROGLYPHIC LETTER TE-2;Lo;0;R;;;;;N;;;;; +1099C;MEROITIC HIEROGLYPHIC LETTER TO;Lo;0;R;;;;;N;;;;; +1099D;MEROITIC HIEROGLYPHIC LETTER DA;Lo;0;R;;;;;N;;;;; +1099E;MEROITIC HIEROGLYPHIC SYMBOL VIDJ;Lo;0;R;;;;;N;;;;; +1099F;MEROITIC HIEROGLYPHIC SYMBOL VIDJ-2;Lo;0;R;;;;;N;;;;; +109A0;MEROITIC CURSIVE LETTER A;Lo;0;R;;;;;N;;;;; +109A1;MEROITIC CURSIVE LETTER E;Lo;0;R;;;;;N;;;;; +109A2;MEROITIC CURSIVE LETTER I;Lo;0;R;;;;;N;;;;; +109A3;MEROITIC CURSIVE LETTER O;Lo;0;R;;;;;N;;;;; +109A4;MEROITIC CURSIVE LETTER YA;Lo;0;R;;;;;N;;;;; +109A5;MEROITIC CURSIVE LETTER WA;Lo;0;R;;;;;N;;;;; +109A6;MEROITIC CURSIVE LETTER BA;Lo;0;R;;;;;N;;;;; +109A7;MEROITIC CURSIVE LETTER PA;Lo;0;R;;;;;N;;;;; +109A8;MEROITIC CURSIVE LETTER MA;Lo;0;R;;;;;N;;;;; +109A9;MEROITIC CURSIVE LETTER NA;Lo;0;R;;;;;N;;;;; +109AA;MEROITIC CURSIVE LETTER NE;Lo;0;R;;;;;N;;;;; +109AB;MEROITIC CURSIVE LETTER RA;Lo;0;R;;;;;N;;;;; +109AC;MEROITIC CURSIVE LETTER LA;Lo;0;R;;;;;N;;;;; +109AD;MEROITIC CURSIVE LETTER KHA;Lo;0;R;;;;;N;;;;; +109AE;MEROITIC CURSIVE LETTER HHA;Lo;0;R;;;;;N;;;;; +109AF;MEROITIC CURSIVE LETTER SA;Lo;0;R;;;;;N;;;;; +109B0;MEROITIC CURSIVE LETTER ARCHAIC SA;Lo;0;R;;;;;N;;;;; +109B1;MEROITIC CURSIVE LETTER SE;Lo;0;R;;;;;N;;;;; +109B2;MEROITIC CURSIVE LETTER KA;Lo;0;R;;;;;N;;;;; +109B3;MEROITIC CURSIVE LETTER QA;Lo;0;R;;;;;N;;;;; +109B4;MEROITIC CURSIVE LETTER TA;Lo;0;R;;;;;N;;;;; +109B5;MEROITIC CURSIVE LETTER TE;Lo;0;R;;;;;N;;;;; +109B6;MEROITIC CURSIVE LETTER TO;Lo;0;R;;;;;N;;;;; +109B7;MEROITIC CURSIVE LETTER DA;Lo;0;R;;;;;N;;;;; +109BC;MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS;No;0;R;;;;11/12;N;;;;; +109BD;MEROITIC CURSIVE FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;; +109BE;MEROITIC CURSIVE LOGOGRAM RMT;Lo;0;R;;;;;N;;;;; +109BF;MEROITIC CURSIVE LOGOGRAM IMN;Lo;0;R;;;;;N;;;;; +109C0;MEROITIC CURSIVE NUMBER ONE;No;0;R;;;;1;N;;;;; +109C1;MEROITIC CURSIVE NUMBER TWO;No;0;R;;;;2;N;;;;; +109C2;MEROITIC CURSIVE NUMBER THREE;No;0;R;;;;3;N;;;;; +109C3;MEROITIC CURSIVE NUMBER FOUR;No;0;R;;;;4;N;;;;; +109C4;MEROITIC CURSIVE NUMBER FIVE;No;0;R;;;;5;N;;;;; +109C5;MEROITIC CURSIVE NUMBER SIX;No;0;R;;;;6;N;;;;; +109C6;MEROITIC CURSIVE NUMBER SEVEN;No;0;R;;;;7;N;;;;; +109C7;MEROITIC CURSIVE NUMBER EIGHT;No;0;R;;;;8;N;;;;; +109C8;MEROITIC CURSIVE NUMBER NINE;No;0;R;;;;9;N;;;;; +109C9;MEROITIC CURSIVE NUMBER TEN;No;0;R;;;;10;N;;;;; +109CA;MEROITIC CURSIVE NUMBER TWENTY;No;0;R;;;;20;N;;;;; +109CB;MEROITIC CURSIVE NUMBER THIRTY;No;0;R;;;;30;N;;;;; +109CC;MEROITIC CURSIVE NUMBER FORTY;No;0;R;;;;40;N;;;;; +109CD;MEROITIC CURSIVE NUMBER FIFTY;No;0;R;;;;50;N;;;;; +109CE;MEROITIC CURSIVE NUMBER SIXTY;No;0;R;;;;60;N;;;;; +109CF;MEROITIC CURSIVE NUMBER SEVENTY;No;0;R;;;;70;N;;;;; +109D2;MEROITIC CURSIVE NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +109D3;MEROITIC CURSIVE NUMBER TWO HUNDRED;No;0;R;;;;200;N;;;;; +109D4;MEROITIC CURSIVE NUMBER THREE HUNDRED;No;0;R;;;;300;N;;;;; +109D5;MEROITIC CURSIVE NUMBER FOUR HUNDRED;No;0;R;;;;400;N;;;;; +109D6;MEROITIC CURSIVE NUMBER FIVE HUNDRED;No;0;R;;;;500;N;;;;; +109D7;MEROITIC CURSIVE NUMBER SIX HUNDRED;No;0;R;;;;600;N;;;;; +109D8;MEROITIC CURSIVE NUMBER SEVEN HUNDRED;No;0;R;;;;700;N;;;;; +109D9;MEROITIC CURSIVE NUMBER EIGHT HUNDRED;No;0;R;;;;800;N;;;;; +109DA;MEROITIC CURSIVE NUMBER NINE HUNDRED;No;0;R;;;;900;N;;;;; +109DB;MEROITIC CURSIVE NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; +109DC;MEROITIC CURSIVE NUMBER TWO THOUSAND;No;0;R;;;;2000;N;;;;; +109DD;MEROITIC CURSIVE NUMBER THREE THOUSAND;No;0;R;;;;3000;N;;;;; +109DE;MEROITIC CURSIVE NUMBER FOUR THOUSAND;No;0;R;;;;4000;N;;;;; +109DF;MEROITIC CURSIVE NUMBER FIVE THOUSAND;No;0;R;;;;5000;N;;;;; +109E0;MEROITIC CURSIVE NUMBER SIX THOUSAND;No;0;R;;;;6000;N;;;;; +109E1;MEROITIC CURSIVE NUMBER SEVEN THOUSAND;No;0;R;;;;7000;N;;;;; +109E2;MEROITIC CURSIVE NUMBER EIGHT THOUSAND;No;0;R;;;;8000;N;;;;; +109E3;MEROITIC CURSIVE NUMBER NINE THOUSAND;No;0;R;;;;9000;N;;;;; +109E4;MEROITIC CURSIVE NUMBER TEN THOUSAND;No;0;R;;;;10000;N;;;;; +109E5;MEROITIC CURSIVE NUMBER TWENTY THOUSAND;No;0;R;;;;20000;N;;;;; +109E6;MEROITIC CURSIVE NUMBER THIRTY THOUSAND;No;0;R;;;;30000;N;;;;; +109E7;MEROITIC CURSIVE NUMBER FORTY THOUSAND;No;0;R;;;;40000;N;;;;; +109E8;MEROITIC CURSIVE NUMBER FIFTY THOUSAND;No;0;R;;;;50000;N;;;;; +109E9;MEROITIC CURSIVE NUMBER SIXTY THOUSAND;No;0;R;;;;60000;N;;;;; +109EA;MEROITIC CURSIVE NUMBER SEVENTY THOUSAND;No;0;R;;;;70000;N;;;;; +109EB;MEROITIC CURSIVE NUMBER EIGHTY THOUSAND;No;0;R;;;;80000;N;;;;; +109EC;MEROITIC CURSIVE NUMBER NINETY THOUSAND;No;0;R;;;;90000;N;;;;; +109ED;MEROITIC CURSIVE NUMBER ONE HUNDRED THOUSAND;No;0;R;;;;100000;N;;;;; +109EE;MEROITIC CURSIVE NUMBER TWO HUNDRED THOUSAND;No;0;R;;;;200000;N;;;;; +109EF;MEROITIC CURSIVE NUMBER THREE HUNDRED THOUSAND;No;0;R;;;;300000;N;;;;; +109F0;MEROITIC CURSIVE NUMBER FOUR HUNDRED THOUSAND;No;0;R;;;;400000;N;;;;; +109F1;MEROITIC CURSIVE NUMBER FIVE HUNDRED THOUSAND;No;0;R;;;;500000;N;;;;; +109F2;MEROITIC CURSIVE NUMBER SIX HUNDRED THOUSAND;No;0;R;;;;600000;N;;;;; +109F3;MEROITIC CURSIVE NUMBER SEVEN HUNDRED THOUSAND;No;0;R;;;;700000;N;;;;; +109F4;MEROITIC CURSIVE NUMBER EIGHT HUNDRED THOUSAND;No;0;R;;;;800000;N;;;;; +109F5;MEROITIC CURSIVE NUMBER NINE HUNDRED THOUSAND;No;0;R;;;;900000;N;;;;; +109F6;MEROITIC CURSIVE FRACTION ONE TWELFTH;No;0;R;;;;1/12;N;;;;; +109F7;MEROITIC CURSIVE FRACTION TWO TWELFTHS;No;0;R;;;;2/12;N;;;;; +109F8;MEROITIC CURSIVE FRACTION THREE TWELFTHS;No;0;R;;;;3/12;N;;;;; +109F9;MEROITIC CURSIVE FRACTION FOUR TWELFTHS;No;0;R;;;;4/12;N;;;;; +109FA;MEROITIC CURSIVE FRACTION FIVE TWELFTHS;No;0;R;;;;5/12;N;;;;; +109FB;MEROITIC CURSIVE FRACTION SIX TWELFTHS;No;0;R;;;;6/12;N;;;;; +109FC;MEROITIC CURSIVE FRACTION SEVEN TWELFTHS;No;0;R;;;;7/12;N;;;;; +109FD;MEROITIC CURSIVE FRACTION EIGHT TWELFTHS;No;0;R;;;;8/12;N;;;;; +109FE;MEROITIC CURSIVE FRACTION NINE TWELFTHS;No;0;R;;;;9/12;N;;;;; +109FF;MEROITIC CURSIVE FRACTION TEN TWELFTHS;No;0;R;;;;10/12;N;;;;; +10A00;KHAROSHTHI LETTER A;Lo;0;R;;;;;N;;;;; +10A01;KHAROSHTHI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +10A02;KHAROSHTHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +10A03;KHAROSHTHI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +10A05;KHAROSHTHI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +10A06;KHAROSHTHI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +10A0C;KHAROSHTHI VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;; +10A0D;KHAROSHTHI SIGN DOUBLE RING BELOW;Mn;220;NSM;;;;;N;;;;; +10A0E;KHAROSHTHI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +10A0F;KHAROSHTHI SIGN VISARGA;Mn;230;NSM;;;;;N;;;;; +10A10;KHAROSHTHI LETTER KA;Lo;0;R;;;;;N;;;;; +10A11;KHAROSHTHI LETTER KHA;Lo;0;R;;;;;N;;;;; +10A12;KHAROSHTHI LETTER GA;Lo;0;R;;;;;N;;;;; +10A13;KHAROSHTHI LETTER GHA;Lo;0;R;;;;;N;;;;; +10A15;KHAROSHTHI LETTER CA;Lo;0;R;;;;;N;;;;; +10A16;KHAROSHTHI LETTER CHA;Lo;0;R;;;;;N;;;;; +10A17;KHAROSHTHI LETTER JA;Lo;0;R;;;;;N;;;;; +10A19;KHAROSHTHI LETTER NYA;Lo;0;R;;;;;N;;;;; +10A1A;KHAROSHTHI LETTER TTA;Lo;0;R;;;;;N;;;;; +10A1B;KHAROSHTHI LETTER TTHA;Lo;0;R;;;;;N;;;;; +10A1C;KHAROSHTHI LETTER DDA;Lo;0;R;;;;;N;;;;; +10A1D;KHAROSHTHI LETTER DDHA;Lo;0;R;;;;;N;;;;; +10A1E;KHAROSHTHI LETTER NNA;Lo;0;R;;;;;N;;;;; +10A1F;KHAROSHTHI LETTER TA;Lo;0;R;;;;;N;;;;; +10A20;KHAROSHTHI LETTER THA;Lo;0;R;;;;;N;;;;; +10A21;KHAROSHTHI LETTER DA;Lo;0;R;;;;;N;;;;; +10A22;KHAROSHTHI LETTER DHA;Lo;0;R;;;;;N;;;;; +10A23;KHAROSHTHI LETTER NA;Lo;0;R;;;;;N;;;;; +10A24;KHAROSHTHI LETTER PA;Lo;0;R;;;;;N;;;;; +10A25;KHAROSHTHI LETTER PHA;Lo;0;R;;;;;N;;;;; +10A26;KHAROSHTHI LETTER BA;Lo;0;R;;;;;N;;;;; +10A27;KHAROSHTHI LETTER BHA;Lo;0;R;;;;;N;;;;; +10A28;KHAROSHTHI LETTER MA;Lo;0;R;;;;;N;;;;; +10A29;KHAROSHTHI LETTER YA;Lo;0;R;;;;;N;;;;; +10A2A;KHAROSHTHI LETTER RA;Lo;0;R;;;;;N;;;;; +10A2B;KHAROSHTHI LETTER LA;Lo;0;R;;;;;N;;;;; +10A2C;KHAROSHTHI LETTER VA;Lo;0;R;;;;;N;;;;; +10A2D;KHAROSHTHI LETTER SHA;Lo;0;R;;;;;N;;;;; +10A2E;KHAROSHTHI LETTER SSA;Lo;0;R;;;;;N;;;;; +10A2F;KHAROSHTHI LETTER SA;Lo;0;R;;;;;N;;;;; +10A30;KHAROSHTHI LETTER ZA;Lo;0;R;;;;;N;;;;; +10A31;KHAROSHTHI LETTER HA;Lo;0;R;;;;;N;;;;; +10A32;KHAROSHTHI LETTER KKA;Lo;0;R;;;;;N;;;;; +10A33;KHAROSHTHI LETTER TTTHA;Lo;0;R;;;;;N;;;;; +10A34;KHAROSHTHI LETTER TTTA;Lo;0;R;;;;;N;;;;; +10A35;KHAROSHTHI LETTER VHA;Lo;0;R;;;;;N;;;;; +10A38;KHAROSHTHI SIGN BAR ABOVE;Mn;230;NSM;;;;;N;;;;; +10A39;KHAROSHTHI SIGN CAUDA;Mn;1;NSM;;;;;N;;;;; +10A3A;KHAROSHTHI SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;; +10A3F;KHAROSHTHI VIRAMA;Mn;9;NSM;;;;;N;;;;; +10A40;KHAROSHTHI DIGIT ONE;No;0;R;;;1;1;N;;;;; +10A41;KHAROSHTHI DIGIT TWO;No;0;R;;;2;2;N;;;;; +10A42;KHAROSHTHI DIGIT THREE;No;0;R;;;3;3;N;;;;; +10A43;KHAROSHTHI DIGIT FOUR;No;0;R;;;4;4;N;;;;; +10A44;KHAROSHTHI NUMBER TEN;No;0;R;;;;10;N;;;;; +10A45;KHAROSHTHI NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10A46;KHAROSHTHI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +10A47;KHAROSHTHI NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; +10A48;KHAROSHTHI FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;; +10A50;KHAROSHTHI PUNCTUATION DOT;Po;0;R;;;;;N;;;;; +10A51;KHAROSHTHI PUNCTUATION SMALL CIRCLE;Po;0;R;;;;;N;;;;; +10A52;KHAROSHTHI PUNCTUATION CIRCLE;Po;0;R;;;;;N;;;;; +10A53;KHAROSHTHI PUNCTUATION CRESCENT BAR;Po;0;R;;;;;N;;;;; +10A54;KHAROSHTHI PUNCTUATION MANGALAM;Po;0;R;;;;;N;;;;; +10A55;KHAROSHTHI PUNCTUATION LOTUS;Po;0;R;;;;;N;;;;; +10A56;KHAROSHTHI PUNCTUATION DANDA;Po;0;R;;;;;N;;;;; +10A57;KHAROSHTHI PUNCTUATION DOUBLE DANDA;Po;0;R;;;;;N;;;;; +10A58;KHAROSHTHI PUNCTUATION LINES;Po;0;R;;;;;N;;;;; +10A60;OLD SOUTH ARABIAN LETTER HE;Lo;0;R;;;;;N;;;;; +10A61;OLD SOUTH ARABIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +10A62;OLD SOUTH ARABIAN LETTER HETH;Lo;0;R;;;;;N;;;;; +10A63;OLD SOUTH ARABIAN LETTER MEM;Lo;0;R;;;;;N;;;;; +10A64;OLD SOUTH ARABIAN LETTER QOPH;Lo;0;R;;;;;N;;;;; +10A65;OLD SOUTH ARABIAN LETTER WAW;Lo;0;R;;;;;N;;;;; +10A66;OLD SOUTH ARABIAN LETTER SHIN;Lo;0;R;;;;;N;;;;; +10A67;OLD SOUTH ARABIAN LETTER RESH;Lo;0;R;;;;;N;;;;; +10A68;OLD SOUTH ARABIAN LETTER BETH;Lo;0;R;;;;;N;;;;; +10A69;OLD SOUTH ARABIAN LETTER TAW;Lo;0;R;;;;;N;;;;; +10A6A;OLD SOUTH ARABIAN LETTER SAT;Lo;0;R;;;;;N;;;;; +10A6B;OLD SOUTH ARABIAN LETTER KAPH;Lo;0;R;;;;;N;;;;; +10A6C;OLD SOUTH ARABIAN LETTER NUN;Lo;0;R;;;;;N;;;;; +10A6D;OLD SOUTH ARABIAN LETTER KHETH;Lo;0;R;;;;;N;;;;; +10A6E;OLD SOUTH ARABIAN LETTER SADHE;Lo;0;R;;;;;N;;;;; +10A6F;OLD SOUTH ARABIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10A70;OLD SOUTH ARABIAN LETTER FE;Lo;0;R;;;;;N;;;;; +10A71;OLD SOUTH ARABIAN LETTER ALEF;Lo;0;R;;;;;N;;;;; +10A72;OLD SOUTH ARABIAN LETTER AYN;Lo;0;R;;;;;N;;;;; +10A73;OLD SOUTH ARABIAN LETTER DHADHE;Lo;0;R;;;;;N;;;;; +10A74;OLD SOUTH ARABIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; +10A75;OLD SOUTH ARABIAN LETTER DALETH;Lo;0;R;;;;;N;;;;; +10A76;OLD SOUTH ARABIAN LETTER GHAYN;Lo;0;R;;;;;N;;;;; +10A77;OLD SOUTH ARABIAN LETTER TETH;Lo;0;R;;;;;N;;;;; +10A78;OLD SOUTH ARABIAN LETTER ZAYN;Lo;0;R;;;;;N;;;;; +10A79;OLD SOUTH ARABIAN LETTER DHALETH;Lo;0;R;;;;;N;;;;; +10A7A;OLD SOUTH ARABIAN LETTER YODH;Lo;0;R;;;;;N;;;;; +10A7B;OLD SOUTH ARABIAN LETTER THAW;Lo;0;R;;;;;N;;;;; +10A7C;OLD SOUTH ARABIAN LETTER THETH;Lo;0;R;;;;;N;;;;; +10A7D;OLD SOUTH ARABIAN NUMBER ONE;No;0;R;;;;1;N;;;;; +10A7E;OLD SOUTH ARABIAN NUMBER FIFTY;No;0;R;;;;50;N;;;;; +10A7F;OLD SOUTH ARABIAN NUMERIC INDICATOR;Po;0;R;;;;;N;;;;; +10A80;OLD NORTH ARABIAN LETTER HEH;Lo;0;R;;;;;N;;;;; +10A81;OLD NORTH ARABIAN LETTER LAM;Lo;0;R;;;;;N;;;;; +10A82;OLD NORTH ARABIAN LETTER HAH;Lo;0;R;;;;;N;;;;; +10A83;OLD NORTH ARABIAN LETTER MEEM;Lo;0;R;;;;;N;;;;; +10A84;OLD NORTH ARABIAN LETTER QAF;Lo;0;R;;;;;N;;;;; +10A85;OLD NORTH ARABIAN LETTER WAW;Lo;0;R;;;;;N;;;;; +10A86;OLD NORTH ARABIAN LETTER ES-2;Lo;0;R;;;;;N;;;;; +10A87;OLD NORTH ARABIAN LETTER REH;Lo;0;R;;;;;N;;;;; +10A88;OLD NORTH ARABIAN LETTER BEH;Lo;0;R;;;;;N;;;;; +10A89;OLD NORTH ARABIAN LETTER TEH;Lo;0;R;;;;;N;;;;; +10A8A;OLD NORTH ARABIAN LETTER ES-1;Lo;0;R;;;;;N;;;;; +10A8B;OLD NORTH ARABIAN LETTER KAF;Lo;0;R;;;;;N;;;;; +10A8C;OLD NORTH ARABIAN LETTER NOON;Lo;0;R;;;;;N;;;;; +10A8D;OLD NORTH ARABIAN LETTER KHAH;Lo;0;R;;;;;N;;;;; +10A8E;OLD NORTH ARABIAN LETTER SAD;Lo;0;R;;;;;N;;;;; +10A8F;OLD NORTH ARABIAN LETTER ES-3;Lo;0;R;;;;;N;;;;; +10A90;OLD NORTH ARABIAN LETTER FEH;Lo;0;R;;;;;N;;;;; +10A91;OLD NORTH ARABIAN LETTER ALEF;Lo;0;R;;;;;N;;;;; +10A92;OLD NORTH ARABIAN LETTER AIN;Lo;0;R;;;;;N;;;;; +10A93;OLD NORTH ARABIAN LETTER DAD;Lo;0;R;;;;;N;;;;; +10A94;OLD NORTH ARABIAN LETTER GEEM;Lo;0;R;;;;;N;;;;; +10A95;OLD NORTH ARABIAN LETTER DAL;Lo;0;R;;;;;N;;;;; +10A96;OLD NORTH ARABIAN LETTER GHAIN;Lo;0;R;;;;;N;;;;; +10A97;OLD NORTH ARABIAN LETTER TAH;Lo;0;R;;;;;N;;;;; +10A98;OLD NORTH ARABIAN LETTER ZAIN;Lo;0;R;;;;;N;;;;; +10A99;OLD NORTH ARABIAN LETTER THAL;Lo;0;R;;;;;N;;;;; +10A9A;OLD NORTH ARABIAN LETTER YEH;Lo;0;R;;;;;N;;;;; +10A9B;OLD NORTH ARABIAN LETTER THEH;Lo;0;R;;;;;N;;;;; +10A9C;OLD NORTH ARABIAN LETTER ZAH;Lo;0;R;;;;;N;;;;; +10A9D;OLD NORTH ARABIAN NUMBER ONE;No;0;R;;;;1;N;;;;; +10A9E;OLD NORTH ARABIAN NUMBER TEN;No;0;R;;;;10;N;;;;; +10A9F;OLD NORTH ARABIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10AC0;MANICHAEAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10AC1;MANICHAEAN LETTER BETH;Lo;0;R;;;;;N;;;;; +10AC2;MANICHAEAN LETTER BHETH;Lo;0;R;;;;;N;;;;; +10AC3;MANICHAEAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; +10AC4;MANICHAEAN LETTER GHIMEL;Lo;0;R;;;;;N;;;;; +10AC5;MANICHAEAN LETTER DALETH;Lo;0;R;;;;;N;;;;; +10AC6;MANICHAEAN LETTER HE;Lo;0;R;;;;;N;;;;; +10AC7;MANICHAEAN LETTER WAW;Lo;0;R;;;;;N;;;;; +10AC8;MANICHAEAN SIGN UD;So;0;R;;;;;N;;;;; +10AC9;MANICHAEAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +10ACA;MANICHAEAN LETTER ZHAYIN;Lo;0;R;;;;;N;;;;; +10ACB;MANICHAEAN LETTER JAYIN;Lo;0;R;;;;;N;;;;; +10ACC;MANICHAEAN LETTER JHAYIN;Lo;0;R;;;;;N;;;;; +10ACD;MANICHAEAN LETTER HETH;Lo;0;R;;;;;N;;;;; +10ACE;MANICHAEAN LETTER TETH;Lo;0;R;;;;;N;;;;; +10ACF;MANICHAEAN LETTER YODH;Lo;0;R;;;;;N;;;;; +10AD0;MANICHAEAN LETTER KAPH;Lo;0;R;;;;;N;;;;; +10AD1;MANICHAEAN LETTER XAPH;Lo;0;R;;;;;N;;;;; +10AD2;MANICHAEAN LETTER KHAPH;Lo;0;R;;;;;N;;;;; +10AD3;MANICHAEAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +10AD4;MANICHAEAN LETTER DHAMEDH;Lo;0;R;;;;;N;;;;; +10AD5;MANICHAEAN LETTER THAMEDH;Lo;0;R;;;;;N;;;;; +10AD6;MANICHAEAN LETTER MEM;Lo;0;R;;;;;N;;;;; +10AD7;MANICHAEAN LETTER NUN;Lo;0;R;;;;;N;;;;; +10AD8;MANICHAEAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10AD9;MANICHAEAN LETTER AYIN;Lo;0;R;;;;;N;;;;; +10ADA;MANICHAEAN LETTER AAYIN;Lo;0;R;;;;;N;;;;; +10ADB;MANICHAEAN LETTER PE;Lo;0;R;;;;;N;;;;; +10ADC;MANICHAEAN LETTER FE;Lo;0;R;;;;;N;;;;; +10ADD;MANICHAEAN LETTER SADHE;Lo;0;R;;;;;N;;;;; +10ADE;MANICHAEAN LETTER QOPH;Lo;0;R;;;;;N;;;;; +10ADF;MANICHAEAN LETTER XOPH;Lo;0;R;;;;;N;;;;; +10AE0;MANICHAEAN LETTER QHOPH;Lo;0;R;;;;;N;;;;; +10AE1;MANICHAEAN LETTER RESH;Lo;0;R;;;;;N;;;;; +10AE2;MANICHAEAN LETTER SHIN;Lo;0;R;;;;;N;;;;; +10AE3;MANICHAEAN LETTER SSHIN;Lo;0;R;;;;;N;;;;; +10AE4;MANICHAEAN LETTER TAW;Lo;0;R;;;;;N;;;;; +10AE5;MANICHAEAN ABBREVIATION MARK ABOVE;Mn;230;NSM;;;;;N;;;;; +10AE6;MANICHAEAN ABBREVIATION MARK BELOW;Mn;220;NSM;;;;;N;;;;; +10AEB;MANICHAEAN NUMBER ONE;No;0;R;;;;1;N;;;;; +10AEC;MANICHAEAN NUMBER FIVE;No;0;R;;;;5;N;;;;; +10AED;MANICHAEAN NUMBER TEN;No;0;R;;;;10;N;;;;; +10AEE;MANICHAEAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10AEF;MANICHAEAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +10AF0;MANICHAEAN PUNCTUATION STAR;Po;0;R;;;;;N;;;;; +10AF1;MANICHAEAN PUNCTUATION FLEURON;Po;0;R;;;;;N;;;;; +10AF2;MANICHAEAN PUNCTUATION DOUBLE DOT WITHIN DOT;Po;0;R;;;;;N;;;;; +10AF3;MANICHAEAN PUNCTUATION DOT WITHIN DOT;Po;0;R;;;;;N;;;;; +10AF4;MANICHAEAN PUNCTUATION DOT;Po;0;R;;;;;N;;;;; +10AF5;MANICHAEAN PUNCTUATION TWO DOTS;Po;0;R;;;;;N;;;;; +10AF6;MANICHAEAN PUNCTUATION LINE FILLER;Po;0;R;;;;;N;;;;; +10B00;AVESTAN LETTER A;Lo;0;R;;;;;N;;;;; +10B01;AVESTAN LETTER AA;Lo;0;R;;;;;N;;;;; +10B02;AVESTAN LETTER AO;Lo;0;R;;;;;N;;;;; +10B03;AVESTAN LETTER AAO;Lo;0;R;;;;;N;;;;; +10B04;AVESTAN LETTER AN;Lo;0;R;;;;;N;;;;; +10B05;AVESTAN LETTER AAN;Lo;0;R;;;;;N;;;;; +10B06;AVESTAN LETTER AE;Lo;0;R;;;;;N;;;;; +10B07;AVESTAN LETTER AEE;Lo;0;R;;;;;N;;;;; +10B08;AVESTAN LETTER E;Lo;0;R;;;;;N;;;;; +10B09;AVESTAN LETTER EE;Lo;0;R;;;;;N;;;;; +10B0A;AVESTAN LETTER O;Lo;0;R;;;;;N;;;;; +10B0B;AVESTAN LETTER OO;Lo;0;R;;;;;N;;;;; +10B0C;AVESTAN LETTER I;Lo;0;R;;;;;N;;;;; +10B0D;AVESTAN LETTER II;Lo;0;R;;;;;N;;;;; +10B0E;AVESTAN LETTER U;Lo;0;R;;;;;N;;;;; +10B0F;AVESTAN LETTER UU;Lo;0;R;;;;;N;;;;; +10B10;AVESTAN LETTER KE;Lo;0;R;;;;;N;;;;; +10B11;AVESTAN LETTER XE;Lo;0;R;;;;;N;;;;; +10B12;AVESTAN LETTER XYE;Lo;0;R;;;;;N;;;;; +10B13;AVESTAN LETTER XVE;Lo;0;R;;;;;N;;;;; +10B14;AVESTAN LETTER GE;Lo;0;R;;;;;N;;;;; +10B15;AVESTAN LETTER GGE;Lo;0;R;;;;;N;;;;; +10B16;AVESTAN LETTER GHE;Lo;0;R;;;;;N;;;;; +10B17;AVESTAN LETTER CE;Lo;0;R;;;;;N;;;;; +10B18;AVESTAN LETTER JE;Lo;0;R;;;;;N;;;;; +10B19;AVESTAN LETTER TE;Lo;0;R;;;;;N;;;;; +10B1A;AVESTAN LETTER THE;Lo;0;R;;;;;N;;;;; +10B1B;AVESTAN LETTER DE;Lo;0;R;;;;;N;;;;; +10B1C;AVESTAN LETTER DHE;Lo;0;R;;;;;N;;;;; +10B1D;AVESTAN LETTER TTE;Lo;0;R;;;;;N;;;;; +10B1E;AVESTAN LETTER PE;Lo;0;R;;;;;N;;;;; +10B1F;AVESTAN LETTER FE;Lo;0;R;;;;;N;;;;; +10B20;AVESTAN LETTER BE;Lo;0;R;;;;;N;;;;; +10B21;AVESTAN LETTER BHE;Lo;0;R;;;;;N;;;;; +10B22;AVESTAN LETTER NGE;Lo;0;R;;;;;N;;;;; +10B23;AVESTAN LETTER NGYE;Lo;0;R;;;;;N;;;;; +10B24;AVESTAN LETTER NGVE;Lo;0;R;;;;;N;;;;; +10B25;AVESTAN LETTER NE;Lo;0;R;;;;;N;;;;; +10B26;AVESTAN LETTER NYE;Lo;0;R;;;;;N;;;;; +10B27;AVESTAN LETTER NNE;Lo;0;R;;;;;N;;;;; +10B28;AVESTAN LETTER ME;Lo;0;R;;;;;N;;;;; +10B29;AVESTAN LETTER HME;Lo;0;R;;;;;N;;;;; +10B2A;AVESTAN LETTER YYE;Lo;0;R;;;;;N;;;;; +10B2B;AVESTAN LETTER YE;Lo;0;R;;;;;N;;;;; +10B2C;AVESTAN LETTER VE;Lo;0;R;;;;;N;;;;; +10B2D;AVESTAN LETTER RE;Lo;0;R;;;;;N;;;;; +10B2E;AVESTAN LETTER LE;Lo;0;R;;;;;N;;;;; +10B2F;AVESTAN LETTER SE;Lo;0;R;;;;;N;;;;; +10B30;AVESTAN LETTER ZE;Lo;0;R;;;;;N;;;;; +10B31;AVESTAN LETTER SHE;Lo;0;R;;;;;N;;;;; +10B32;AVESTAN LETTER ZHE;Lo;0;R;;;;;N;;;;; +10B33;AVESTAN LETTER SHYE;Lo;0;R;;;;;N;;;;; +10B34;AVESTAN LETTER SSHE;Lo;0;R;;;;;N;;;;; +10B35;AVESTAN LETTER HE;Lo;0;R;;;;;N;;;;; +10B39;AVESTAN ABBREVIATION MARK;Po;0;ON;;;;;N;;;;; +10B3A;TINY TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; +10B3B;SMALL TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; +10B3C;LARGE TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; +10B3D;LARGE ONE DOT OVER TWO DOTS PUNCTUATION;Po;0;ON;;;;;N;;;;; +10B3E;LARGE TWO RINGS OVER ONE RING PUNCTUATION;Po;0;ON;;;;;N;;;;; +10B3F;LARGE ONE RING OVER TWO RINGS PUNCTUATION;Po;0;ON;;;;;N;;;;; +10B40;INSCRIPTIONAL PARTHIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10B41;INSCRIPTIONAL PARTHIAN LETTER BETH;Lo;0;R;;;;;N;;;;; +10B42;INSCRIPTIONAL PARTHIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; +10B43;INSCRIPTIONAL PARTHIAN LETTER DALETH;Lo;0;R;;;;;N;;;;; +10B44;INSCRIPTIONAL PARTHIAN LETTER HE;Lo;0;R;;;;;N;;;;; +10B45;INSCRIPTIONAL PARTHIAN LETTER WAW;Lo;0;R;;;;;N;;;;; +10B46;INSCRIPTIONAL PARTHIAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +10B47;INSCRIPTIONAL PARTHIAN LETTER HETH;Lo;0;R;;;;;N;;;;; +10B48;INSCRIPTIONAL PARTHIAN LETTER TETH;Lo;0;R;;;;;N;;;;; +10B49;INSCRIPTIONAL PARTHIAN LETTER YODH;Lo;0;R;;;;;N;;;;; +10B4A;INSCRIPTIONAL PARTHIAN LETTER KAPH;Lo;0;R;;;;;N;;;;; +10B4B;INSCRIPTIONAL PARTHIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +10B4C;INSCRIPTIONAL PARTHIAN LETTER MEM;Lo;0;R;;;;;N;;;;; +10B4D;INSCRIPTIONAL PARTHIAN LETTER NUN;Lo;0;R;;;;;N;;;;; +10B4E;INSCRIPTIONAL PARTHIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10B4F;INSCRIPTIONAL PARTHIAN LETTER AYIN;Lo;0;R;;;;;N;;;;; +10B50;INSCRIPTIONAL PARTHIAN LETTER PE;Lo;0;R;;;;;N;;;;; +10B51;INSCRIPTIONAL PARTHIAN LETTER SADHE;Lo;0;R;;;;;N;;;;; +10B52;INSCRIPTIONAL PARTHIAN LETTER QOPH;Lo;0;R;;;;;N;;;;; +10B53;INSCRIPTIONAL PARTHIAN LETTER RESH;Lo;0;R;;;;;N;;;;; +10B54;INSCRIPTIONAL PARTHIAN LETTER SHIN;Lo;0;R;;;;;N;;;;; +10B55;INSCRIPTIONAL PARTHIAN LETTER TAW;Lo;0;R;;;;;N;;;;; +10B58;INSCRIPTIONAL PARTHIAN NUMBER ONE;No;0;R;;;;1;N;;;;; +10B59;INSCRIPTIONAL PARTHIAN NUMBER TWO;No;0;R;;;;2;N;;;;; +10B5A;INSCRIPTIONAL PARTHIAN NUMBER THREE;No;0;R;;;;3;N;;;;; +10B5B;INSCRIPTIONAL PARTHIAN NUMBER FOUR;No;0;R;;;;4;N;;;;; +10B5C;INSCRIPTIONAL PARTHIAN NUMBER TEN;No;0;R;;;;10;N;;;;; +10B5D;INSCRIPTIONAL PARTHIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10B5E;INSCRIPTIONAL PARTHIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +10B5F;INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; +10B60;INSCRIPTIONAL PAHLAVI LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10B61;INSCRIPTIONAL PAHLAVI LETTER BETH;Lo;0;R;;;;;N;;;;; +10B62;INSCRIPTIONAL PAHLAVI LETTER GIMEL;Lo;0;R;;;;;N;;;;; +10B63;INSCRIPTIONAL PAHLAVI LETTER DALETH;Lo;0;R;;;;;N;;;;; +10B64;INSCRIPTIONAL PAHLAVI LETTER HE;Lo;0;R;;;;;N;;;;; +10B65;INSCRIPTIONAL PAHLAVI LETTER WAW-AYIN-RESH;Lo;0;R;;;;;N;;;;; +10B66;INSCRIPTIONAL PAHLAVI LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +10B67;INSCRIPTIONAL PAHLAVI LETTER HETH;Lo;0;R;;;;;N;;;;; +10B68;INSCRIPTIONAL PAHLAVI LETTER TETH;Lo;0;R;;;;;N;;;;; +10B69;INSCRIPTIONAL PAHLAVI LETTER YODH;Lo;0;R;;;;;N;;;;; +10B6A;INSCRIPTIONAL PAHLAVI LETTER KAPH;Lo;0;R;;;;;N;;;;; +10B6B;INSCRIPTIONAL PAHLAVI LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +10B6C;INSCRIPTIONAL PAHLAVI LETTER MEM-QOPH;Lo;0;R;;;;;N;;;;; +10B6D;INSCRIPTIONAL PAHLAVI LETTER NUN;Lo;0;R;;;;;N;;;;; +10B6E;INSCRIPTIONAL PAHLAVI LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10B6F;INSCRIPTIONAL PAHLAVI LETTER PE;Lo;0;R;;;;;N;;;;; +10B70;INSCRIPTIONAL PAHLAVI LETTER SADHE;Lo;0;R;;;;;N;;;;; +10B71;INSCRIPTIONAL PAHLAVI LETTER SHIN;Lo;0;R;;;;;N;;;;; +10B72;INSCRIPTIONAL PAHLAVI LETTER TAW;Lo;0;R;;;;;N;;;;; +10B78;INSCRIPTIONAL PAHLAVI NUMBER ONE;No;0;R;;;;1;N;;;;; +10B79;INSCRIPTIONAL PAHLAVI NUMBER TWO;No;0;R;;;;2;N;;;;; +10B7A;INSCRIPTIONAL PAHLAVI NUMBER THREE;No;0;R;;;;3;N;;;;; +10B7B;INSCRIPTIONAL PAHLAVI NUMBER FOUR;No;0;R;;;;4;N;;;;; +10B7C;INSCRIPTIONAL PAHLAVI NUMBER TEN;No;0;R;;;;10;N;;;;; +10B7D;INSCRIPTIONAL PAHLAVI NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10B7E;INSCRIPTIONAL PAHLAVI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +10B7F;INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; +10B80;PSALTER PAHLAVI LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10B81;PSALTER PAHLAVI LETTER BETH;Lo;0;R;;;;;N;;;;; +10B82;PSALTER PAHLAVI LETTER GIMEL;Lo;0;R;;;;;N;;;;; +10B83;PSALTER PAHLAVI LETTER DALETH;Lo;0;R;;;;;N;;;;; +10B84;PSALTER PAHLAVI LETTER HE;Lo;0;R;;;;;N;;;;; +10B85;PSALTER PAHLAVI LETTER WAW-AYIN-RESH;Lo;0;R;;;;;N;;;;; +10B86;PSALTER PAHLAVI LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +10B87;PSALTER PAHLAVI LETTER HETH;Lo;0;R;;;;;N;;;;; +10B88;PSALTER PAHLAVI LETTER YODH;Lo;0;R;;;;;N;;;;; +10B89;PSALTER PAHLAVI LETTER KAPH;Lo;0;R;;;;;N;;;;; +10B8A;PSALTER PAHLAVI LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +10B8B;PSALTER PAHLAVI LETTER MEM-QOPH;Lo;0;R;;;;;N;;;;; +10B8C;PSALTER PAHLAVI LETTER NUN;Lo;0;R;;;;;N;;;;; +10B8D;PSALTER PAHLAVI LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10B8E;PSALTER PAHLAVI LETTER PE;Lo;0;R;;;;;N;;;;; +10B8F;PSALTER PAHLAVI LETTER SADHE;Lo;0;R;;;;;N;;;;; +10B90;PSALTER PAHLAVI LETTER SHIN;Lo;0;R;;;;;N;;;;; +10B91;PSALTER PAHLAVI LETTER TAW;Lo;0;R;;;;;N;;;;; +10B99;PSALTER PAHLAVI SECTION MARK;Po;0;R;;;;;N;;;;; +10B9A;PSALTER PAHLAVI TURNED SECTION MARK;Po;0;R;;;;;N;;;;; +10B9B;PSALTER PAHLAVI FOUR DOTS WITH CROSS;Po;0;R;;;;;N;;;;; +10B9C;PSALTER PAHLAVI FOUR DOTS WITH DOT;Po;0;R;;;;;N;;;;; +10BA9;PSALTER PAHLAVI NUMBER ONE;No;0;R;;;;1;N;;;;; +10BAA;PSALTER PAHLAVI NUMBER TWO;No;0;R;;;;2;N;;;;; +10BAB;PSALTER PAHLAVI NUMBER THREE;No;0;R;;;;3;N;;;;; +10BAC;PSALTER PAHLAVI NUMBER FOUR;No;0;R;;;;4;N;;;;; +10BAD;PSALTER PAHLAVI NUMBER TEN;No;0;R;;;;10;N;;;;; +10BAE;PSALTER PAHLAVI NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10BAF;PSALTER PAHLAVI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +10C00;OLD TURKIC LETTER ORKHON A;Lo;0;R;;;;;N;;;;; +10C01;OLD TURKIC LETTER YENISEI A;Lo;0;R;;;;;N;;;;; +10C02;OLD TURKIC LETTER YENISEI AE;Lo;0;R;;;;;N;;;;; +10C03;OLD TURKIC LETTER ORKHON I;Lo;0;R;;;;;N;;;;; +10C04;OLD TURKIC LETTER YENISEI I;Lo;0;R;;;;;N;;;;; +10C05;OLD TURKIC LETTER YENISEI E;Lo;0;R;;;;;N;;;;; +10C06;OLD TURKIC LETTER ORKHON O;Lo;0;R;;;;;N;;;;; +10C07;OLD TURKIC LETTER ORKHON OE;Lo;0;R;;;;;N;;;;; +10C08;OLD TURKIC LETTER YENISEI OE;Lo;0;R;;;;;N;;;;; +10C09;OLD TURKIC LETTER ORKHON AB;Lo;0;R;;;;;N;;;;; +10C0A;OLD TURKIC LETTER YENISEI AB;Lo;0;R;;;;;N;;;;; +10C0B;OLD TURKIC LETTER ORKHON AEB;Lo;0;R;;;;;N;;;;; +10C0C;OLD TURKIC LETTER YENISEI AEB;Lo;0;R;;;;;N;;;;; +10C0D;OLD TURKIC LETTER ORKHON AG;Lo;0;R;;;;;N;;;;; +10C0E;OLD TURKIC LETTER YENISEI AG;Lo;0;R;;;;;N;;;;; +10C0F;OLD TURKIC LETTER ORKHON AEG;Lo;0;R;;;;;N;;;;; +10C10;OLD TURKIC LETTER YENISEI AEG;Lo;0;R;;;;;N;;;;; +10C11;OLD TURKIC LETTER ORKHON AD;Lo;0;R;;;;;N;;;;; +10C12;OLD TURKIC LETTER YENISEI AD;Lo;0;R;;;;;N;;;;; +10C13;OLD TURKIC LETTER ORKHON AED;Lo;0;R;;;;;N;;;;; +10C14;OLD TURKIC LETTER ORKHON EZ;Lo;0;R;;;;;N;;;;; +10C15;OLD TURKIC LETTER YENISEI EZ;Lo;0;R;;;;;N;;;;; +10C16;OLD TURKIC LETTER ORKHON AY;Lo;0;R;;;;;N;;;;; +10C17;OLD TURKIC LETTER YENISEI AY;Lo;0;R;;;;;N;;;;; +10C18;OLD TURKIC LETTER ORKHON AEY;Lo;0;R;;;;;N;;;;; +10C19;OLD TURKIC LETTER YENISEI AEY;Lo;0;R;;;;;N;;;;; +10C1A;OLD TURKIC LETTER ORKHON AEK;Lo;0;R;;;;;N;;;;; +10C1B;OLD TURKIC LETTER YENISEI AEK;Lo;0;R;;;;;N;;;;; +10C1C;OLD TURKIC LETTER ORKHON OEK;Lo;0;R;;;;;N;;;;; +10C1D;OLD TURKIC LETTER YENISEI OEK;Lo;0;R;;;;;N;;;;; +10C1E;OLD TURKIC LETTER ORKHON AL;Lo;0;R;;;;;N;;;;; +10C1F;OLD TURKIC LETTER YENISEI AL;Lo;0;R;;;;;N;;;;; +10C20;OLD TURKIC LETTER ORKHON AEL;Lo;0;R;;;;;N;;;;; +10C21;OLD TURKIC LETTER ORKHON ELT;Lo;0;R;;;;;N;;;;; +10C22;OLD TURKIC LETTER ORKHON EM;Lo;0;R;;;;;N;;;;; +10C23;OLD TURKIC LETTER ORKHON AN;Lo;0;R;;;;;N;;;;; +10C24;OLD TURKIC LETTER ORKHON AEN;Lo;0;R;;;;;N;;;;; +10C25;OLD TURKIC LETTER YENISEI AEN;Lo;0;R;;;;;N;;;;; +10C26;OLD TURKIC LETTER ORKHON ENT;Lo;0;R;;;;;N;;;;; +10C27;OLD TURKIC LETTER YENISEI ENT;Lo;0;R;;;;;N;;;;; +10C28;OLD TURKIC LETTER ORKHON ENC;Lo;0;R;;;;;N;;;;; +10C29;OLD TURKIC LETTER YENISEI ENC;Lo;0;R;;;;;N;;;;; +10C2A;OLD TURKIC LETTER ORKHON ENY;Lo;0;R;;;;;N;;;;; +10C2B;OLD TURKIC LETTER YENISEI ENY;Lo;0;R;;;;;N;;;;; +10C2C;OLD TURKIC LETTER YENISEI ANG;Lo;0;R;;;;;N;;;;; +10C2D;OLD TURKIC LETTER ORKHON ENG;Lo;0;R;;;;;N;;;;; +10C2E;OLD TURKIC LETTER YENISEI AENG;Lo;0;R;;;;;N;;;;; +10C2F;OLD TURKIC LETTER ORKHON EP;Lo;0;R;;;;;N;;;;; +10C30;OLD TURKIC LETTER ORKHON OP;Lo;0;R;;;;;N;;;;; +10C31;OLD TURKIC LETTER ORKHON IC;Lo;0;R;;;;;N;;;;; +10C32;OLD TURKIC LETTER ORKHON EC;Lo;0;R;;;;;N;;;;; +10C33;OLD TURKIC LETTER YENISEI EC;Lo;0;R;;;;;N;;;;; +10C34;OLD TURKIC LETTER ORKHON AQ;Lo;0;R;;;;;N;;;;; +10C35;OLD TURKIC LETTER YENISEI AQ;Lo;0;R;;;;;N;;;;; +10C36;OLD TURKIC LETTER ORKHON IQ;Lo;0;R;;;;;N;;;;; +10C37;OLD TURKIC LETTER YENISEI IQ;Lo;0;R;;;;;N;;;;; +10C38;OLD TURKIC LETTER ORKHON OQ;Lo;0;R;;;;;N;;;;; +10C39;OLD TURKIC LETTER YENISEI OQ;Lo;0;R;;;;;N;;;;; +10C3A;OLD TURKIC LETTER ORKHON AR;Lo;0;R;;;;;N;;;;; +10C3B;OLD TURKIC LETTER YENISEI AR;Lo;0;R;;;;;N;;;;; +10C3C;OLD TURKIC LETTER ORKHON AER;Lo;0;R;;;;;N;;;;; +10C3D;OLD TURKIC LETTER ORKHON AS;Lo;0;R;;;;;N;;;;; +10C3E;OLD TURKIC LETTER ORKHON AES;Lo;0;R;;;;;N;;;;; +10C3F;OLD TURKIC LETTER ORKHON ASH;Lo;0;R;;;;;N;;;;; +10C40;OLD TURKIC LETTER YENISEI ASH;Lo;0;R;;;;;N;;;;; +10C41;OLD TURKIC LETTER ORKHON ESH;Lo;0;R;;;;;N;;;;; +10C42;OLD TURKIC LETTER YENISEI ESH;Lo;0;R;;;;;N;;;;; +10C43;OLD TURKIC LETTER ORKHON AT;Lo;0;R;;;;;N;;;;; +10C44;OLD TURKIC LETTER YENISEI AT;Lo;0;R;;;;;N;;;;; +10C45;OLD TURKIC LETTER ORKHON AET;Lo;0;R;;;;;N;;;;; +10C46;OLD TURKIC LETTER YENISEI AET;Lo;0;R;;;;;N;;;;; +10C47;OLD TURKIC LETTER ORKHON OT;Lo;0;R;;;;;N;;;;; +10C48;OLD TURKIC LETTER ORKHON BASH;Lo;0;R;;;;;N;;;;; +10C80;OLD HUNGARIAN CAPITAL LETTER A;Lu;0;R;;;;;N;;;;10CC0; +10C81;OLD HUNGARIAN CAPITAL LETTER AA;Lu;0;R;;;;;N;;;;10CC1; +10C82;OLD HUNGARIAN CAPITAL LETTER EB;Lu;0;R;;;;;N;;;;10CC2; +10C83;OLD HUNGARIAN CAPITAL LETTER AMB;Lu;0;R;;;;;N;;;;10CC3; +10C84;OLD HUNGARIAN CAPITAL LETTER EC;Lu;0;R;;;;;N;;;;10CC4; +10C85;OLD HUNGARIAN CAPITAL LETTER ENC;Lu;0;R;;;;;N;;;;10CC5; +10C86;OLD HUNGARIAN CAPITAL LETTER ECS;Lu;0;R;;;;;N;;;;10CC6; +10C87;OLD HUNGARIAN CAPITAL LETTER ED;Lu;0;R;;;;;N;;;;10CC7; +10C88;OLD HUNGARIAN CAPITAL LETTER AND;Lu;0;R;;;;;N;;;;10CC8; +10C89;OLD HUNGARIAN CAPITAL LETTER E;Lu;0;R;;;;;N;;;;10CC9; +10C8A;OLD HUNGARIAN CAPITAL LETTER CLOSE E;Lu;0;R;;;;;N;;;;10CCA; +10C8B;OLD HUNGARIAN CAPITAL LETTER EE;Lu;0;R;;;;;N;;;;10CCB; +10C8C;OLD HUNGARIAN CAPITAL LETTER EF;Lu;0;R;;;;;N;;;;10CCC; +10C8D;OLD HUNGARIAN CAPITAL LETTER EG;Lu;0;R;;;;;N;;;;10CCD; +10C8E;OLD HUNGARIAN CAPITAL LETTER EGY;Lu;0;R;;;;;N;;;;10CCE; +10C8F;OLD HUNGARIAN CAPITAL LETTER EH;Lu;0;R;;;;;N;;;;10CCF; +10C90;OLD HUNGARIAN CAPITAL LETTER I;Lu;0;R;;;;;N;;;;10CD0; +10C91;OLD HUNGARIAN CAPITAL LETTER II;Lu;0;R;;;;;N;;;;10CD1; +10C92;OLD HUNGARIAN CAPITAL LETTER EJ;Lu;0;R;;;;;N;;;;10CD2; +10C93;OLD HUNGARIAN CAPITAL LETTER EK;Lu;0;R;;;;;N;;;;10CD3; +10C94;OLD HUNGARIAN CAPITAL LETTER AK;Lu;0;R;;;;;N;;;;10CD4; +10C95;OLD HUNGARIAN CAPITAL LETTER UNK;Lu;0;R;;;;;N;;;;10CD5; +10C96;OLD HUNGARIAN CAPITAL LETTER EL;Lu;0;R;;;;;N;;;;10CD6; +10C97;OLD HUNGARIAN CAPITAL LETTER ELY;Lu;0;R;;;;;N;;;;10CD7; +10C98;OLD HUNGARIAN CAPITAL LETTER EM;Lu;0;R;;;;;N;;;;10CD8; +10C99;OLD HUNGARIAN CAPITAL LETTER EN;Lu;0;R;;;;;N;;;;10CD9; +10C9A;OLD HUNGARIAN CAPITAL LETTER ENY;Lu;0;R;;;;;N;;;;10CDA; +10C9B;OLD HUNGARIAN CAPITAL LETTER O;Lu;0;R;;;;;N;;;;10CDB; +10C9C;OLD HUNGARIAN CAPITAL LETTER OO;Lu;0;R;;;;;N;;;;10CDC; +10C9D;OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE;Lu;0;R;;;;;N;;;;10CDD; +10C9E;OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE;Lu;0;R;;;;;N;;;;10CDE; +10C9F;OLD HUNGARIAN CAPITAL LETTER OEE;Lu;0;R;;;;;N;;;;10CDF; +10CA0;OLD HUNGARIAN CAPITAL LETTER EP;Lu;0;R;;;;;N;;;;10CE0; +10CA1;OLD HUNGARIAN CAPITAL LETTER EMP;Lu;0;R;;;;;N;;;;10CE1; +10CA2;OLD HUNGARIAN CAPITAL LETTER ER;Lu;0;R;;;;;N;;;;10CE2; +10CA3;OLD HUNGARIAN CAPITAL LETTER SHORT ER;Lu;0;R;;;;;N;;;;10CE3; +10CA4;OLD HUNGARIAN CAPITAL LETTER ES;Lu;0;R;;;;;N;;;;10CE4; +10CA5;OLD HUNGARIAN CAPITAL LETTER ESZ;Lu;0;R;;;;;N;;;;10CE5; +10CA6;OLD HUNGARIAN CAPITAL LETTER ET;Lu;0;R;;;;;N;;;;10CE6; +10CA7;OLD HUNGARIAN CAPITAL LETTER ENT;Lu;0;R;;;;;N;;;;10CE7; +10CA8;OLD HUNGARIAN CAPITAL LETTER ETY;Lu;0;R;;;;;N;;;;10CE8; +10CA9;OLD HUNGARIAN CAPITAL LETTER ECH;Lu;0;R;;;;;N;;;;10CE9; +10CAA;OLD HUNGARIAN CAPITAL LETTER U;Lu;0;R;;;;;N;;;;10CEA; +10CAB;OLD HUNGARIAN CAPITAL LETTER UU;Lu;0;R;;;;;N;;;;10CEB; +10CAC;OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE;Lu;0;R;;;;;N;;;;10CEC; +10CAD;OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE;Lu;0;R;;;;;N;;;;10CED; +10CAE;OLD HUNGARIAN CAPITAL LETTER EV;Lu;0;R;;;;;N;;;;10CEE; +10CAF;OLD HUNGARIAN CAPITAL LETTER EZ;Lu;0;R;;;;;N;;;;10CEF; +10CB0;OLD HUNGARIAN CAPITAL LETTER EZS;Lu;0;R;;;;;N;;;;10CF0; +10CB1;OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN;Lu;0;R;;;;;N;;;;10CF1; +10CB2;OLD HUNGARIAN CAPITAL LETTER US;Lu;0;R;;;;;N;;;;10CF2; +10CC0;OLD HUNGARIAN SMALL LETTER A;Ll;0;R;;;;;N;;;10C80;;10C80 +10CC1;OLD HUNGARIAN SMALL LETTER AA;Ll;0;R;;;;;N;;;10C81;;10C81 +10CC2;OLD HUNGARIAN SMALL LETTER EB;Ll;0;R;;;;;N;;;10C82;;10C82 +10CC3;OLD HUNGARIAN SMALL LETTER AMB;Ll;0;R;;;;;N;;;10C83;;10C83 +10CC4;OLD HUNGARIAN SMALL LETTER EC;Ll;0;R;;;;;N;;;10C84;;10C84 +10CC5;OLD HUNGARIAN SMALL LETTER ENC;Ll;0;R;;;;;N;;;10C85;;10C85 +10CC6;OLD HUNGARIAN SMALL LETTER ECS;Ll;0;R;;;;;N;;;10C86;;10C86 +10CC7;OLD HUNGARIAN SMALL LETTER ED;Ll;0;R;;;;;N;;;10C87;;10C87 +10CC8;OLD HUNGARIAN SMALL LETTER AND;Ll;0;R;;;;;N;;;10C88;;10C88 +10CC9;OLD HUNGARIAN SMALL LETTER E;Ll;0;R;;;;;N;;;10C89;;10C89 +10CCA;OLD HUNGARIAN SMALL LETTER CLOSE E;Ll;0;R;;;;;N;;;10C8A;;10C8A +10CCB;OLD HUNGARIAN SMALL LETTER EE;Ll;0;R;;;;;N;;;10C8B;;10C8B +10CCC;OLD HUNGARIAN SMALL LETTER EF;Ll;0;R;;;;;N;;;10C8C;;10C8C +10CCD;OLD HUNGARIAN SMALL LETTER EG;Ll;0;R;;;;;N;;;10C8D;;10C8D +10CCE;OLD HUNGARIAN SMALL LETTER EGY;Ll;0;R;;;;;N;;;10C8E;;10C8E +10CCF;OLD HUNGARIAN SMALL LETTER EH;Ll;0;R;;;;;N;;;10C8F;;10C8F +10CD0;OLD HUNGARIAN SMALL LETTER I;Ll;0;R;;;;;N;;;10C90;;10C90 +10CD1;OLD HUNGARIAN SMALL LETTER II;Ll;0;R;;;;;N;;;10C91;;10C91 +10CD2;OLD HUNGARIAN SMALL LETTER EJ;Ll;0;R;;;;;N;;;10C92;;10C92 +10CD3;OLD HUNGARIAN SMALL LETTER EK;Ll;0;R;;;;;N;;;10C93;;10C93 +10CD4;OLD HUNGARIAN SMALL LETTER AK;Ll;0;R;;;;;N;;;10C94;;10C94 +10CD5;OLD HUNGARIAN SMALL LETTER UNK;Ll;0;R;;;;;N;;;10C95;;10C95 +10CD6;OLD HUNGARIAN SMALL LETTER EL;Ll;0;R;;;;;N;;;10C96;;10C96 +10CD7;OLD HUNGARIAN SMALL LETTER ELY;Ll;0;R;;;;;N;;;10C97;;10C97 +10CD8;OLD HUNGARIAN SMALL LETTER EM;Ll;0;R;;;;;N;;;10C98;;10C98 +10CD9;OLD HUNGARIAN SMALL LETTER EN;Ll;0;R;;;;;N;;;10C99;;10C99 +10CDA;OLD HUNGARIAN SMALL LETTER ENY;Ll;0;R;;;;;N;;;10C9A;;10C9A +10CDB;OLD HUNGARIAN SMALL LETTER O;Ll;0;R;;;;;N;;;10C9B;;10C9B +10CDC;OLD HUNGARIAN SMALL LETTER OO;Ll;0;R;;;;;N;;;10C9C;;10C9C +10CDD;OLD HUNGARIAN SMALL LETTER NIKOLSBURG OE;Ll;0;R;;;;;N;;;10C9D;;10C9D +10CDE;OLD HUNGARIAN SMALL LETTER RUDIMENTA OE;Ll;0;R;;;;;N;;;10C9E;;10C9E +10CDF;OLD HUNGARIAN SMALL LETTER OEE;Ll;0;R;;;;;N;;;10C9F;;10C9F +10CE0;OLD HUNGARIAN SMALL LETTER EP;Ll;0;R;;;;;N;;;10CA0;;10CA0 +10CE1;OLD HUNGARIAN SMALL LETTER EMP;Ll;0;R;;;;;N;;;10CA1;;10CA1 +10CE2;OLD HUNGARIAN SMALL LETTER ER;Ll;0;R;;;;;N;;;10CA2;;10CA2 +10CE3;OLD HUNGARIAN SMALL LETTER SHORT ER;Ll;0;R;;;;;N;;;10CA3;;10CA3 +10CE4;OLD HUNGARIAN SMALL LETTER ES;Ll;0;R;;;;;N;;;10CA4;;10CA4 +10CE5;OLD HUNGARIAN SMALL LETTER ESZ;Ll;0;R;;;;;N;;;10CA5;;10CA5 +10CE6;OLD HUNGARIAN SMALL LETTER ET;Ll;0;R;;;;;N;;;10CA6;;10CA6 +10CE7;OLD HUNGARIAN SMALL LETTER ENT;Ll;0;R;;;;;N;;;10CA7;;10CA7 +10CE8;OLD HUNGARIAN SMALL LETTER ETY;Ll;0;R;;;;;N;;;10CA8;;10CA8 +10CE9;OLD HUNGARIAN SMALL LETTER ECH;Ll;0;R;;;;;N;;;10CA9;;10CA9 +10CEA;OLD HUNGARIAN SMALL LETTER U;Ll;0;R;;;;;N;;;10CAA;;10CAA +10CEB;OLD HUNGARIAN SMALL LETTER UU;Ll;0;R;;;;;N;;;10CAB;;10CAB +10CEC;OLD HUNGARIAN SMALL LETTER NIKOLSBURG UE;Ll;0;R;;;;;N;;;10CAC;;10CAC +10CED;OLD HUNGARIAN SMALL LETTER RUDIMENTA UE;Ll;0;R;;;;;N;;;10CAD;;10CAD +10CEE;OLD HUNGARIAN SMALL LETTER EV;Ll;0;R;;;;;N;;;10CAE;;10CAE +10CEF;OLD HUNGARIAN SMALL LETTER EZ;Ll;0;R;;;;;N;;;10CAF;;10CAF +10CF0;OLD HUNGARIAN SMALL LETTER EZS;Ll;0;R;;;;;N;;;10CB0;;10CB0 +10CF1;OLD HUNGARIAN SMALL LETTER ENT-SHAPED SIGN;Ll;0;R;;;;;N;;;10CB1;;10CB1 +10CF2;OLD HUNGARIAN SMALL LETTER US;Ll;0;R;;;;;N;;;10CB2;;10CB2 +10CFA;OLD HUNGARIAN NUMBER ONE;No;0;R;;;;1;N;;;;; +10CFB;OLD HUNGARIAN NUMBER FIVE;No;0;R;;;;5;N;;;;; +10CFC;OLD HUNGARIAN NUMBER TEN;No;0;R;;;;10;N;;;;; +10CFD;OLD HUNGARIAN NUMBER FIFTY;No;0;R;;;;50;N;;;;; +10CFE;OLD HUNGARIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +10CFF;OLD HUNGARIAN NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; +10D00;HANIFI ROHINGYA LETTER A;Lo;0;AL;;;;;N;;;;; +10D01;HANIFI ROHINGYA LETTER BA;Lo;0;AL;;;;;N;;;;; +10D02;HANIFI ROHINGYA LETTER PA;Lo;0;AL;;;;;N;;;;; +10D03;HANIFI ROHINGYA LETTER TA;Lo;0;AL;;;;;N;;;;; +10D04;HANIFI ROHINGYA LETTER TTA;Lo;0;AL;;;;;N;;;;; +10D05;HANIFI ROHINGYA LETTER JA;Lo;0;AL;;;;;N;;;;; +10D06;HANIFI ROHINGYA LETTER CA;Lo;0;AL;;;;;N;;;;; +10D07;HANIFI ROHINGYA LETTER HA;Lo;0;AL;;;;;N;;;;; +10D08;HANIFI ROHINGYA LETTER KHA;Lo;0;AL;;;;;N;;;;; +10D09;HANIFI ROHINGYA LETTER FA;Lo;0;AL;;;;;N;;;;; +10D0A;HANIFI ROHINGYA LETTER DA;Lo;0;AL;;;;;N;;;;; +10D0B;HANIFI ROHINGYA LETTER DDA;Lo;0;AL;;;;;N;;;;; +10D0C;HANIFI ROHINGYA LETTER RA;Lo;0;AL;;;;;N;;;;; +10D0D;HANIFI ROHINGYA LETTER RRA;Lo;0;AL;;;;;N;;;;; +10D0E;HANIFI ROHINGYA LETTER ZA;Lo;0;AL;;;;;N;;;;; +10D0F;HANIFI ROHINGYA LETTER SA;Lo;0;AL;;;;;N;;;;; +10D10;HANIFI ROHINGYA LETTER SHA;Lo;0;AL;;;;;N;;;;; +10D11;HANIFI ROHINGYA LETTER KA;Lo;0;AL;;;;;N;;;;; +10D12;HANIFI ROHINGYA LETTER GA;Lo;0;AL;;;;;N;;;;; +10D13;HANIFI ROHINGYA LETTER LA;Lo;0;AL;;;;;N;;;;; +10D14;HANIFI ROHINGYA LETTER MA;Lo;0;AL;;;;;N;;;;; +10D15;HANIFI ROHINGYA LETTER NA;Lo;0;AL;;;;;N;;;;; +10D16;HANIFI ROHINGYA LETTER WA;Lo;0;AL;;;;;N;;;;; +10D17;HANIFI ROHINGYA LETTER KINNA WA;Lo;0;AL;;;;;N;;;;; +10D18;HANIFI ROHINGYA LETTER YA;Lo;0;AL;;;;;N;;;;; +10D19;HANIFI ROHINGYA LETTER KINNA YA;Lo;0;AL;;;;;N;;;;; +10D1A;HANIFI ROHINGYA LETTER NGA;Lo;0;AL;;;;;N;;;;; +10D1B;HANIFI ROHINGYA LETTER NYA;Lo;0;AL;;;;;N;;;;; +10D1C;HANIFI ROHINGYA LETTER VA;Lo;0;AL;;;;;N;;;;; +10D1D;HANIFI ROHINGYA VOWEL A;Lo;0;AL;;;;;N;;;;; +10D1E;HANIFI ROHINGYA VOWEL I;Lo;0;AL;;;;;N;;;;; +10D1F;HANIFI ROHINGYA VOWEL U;Lo;0;AL;;;;;N;;;;; +10D20;HANIFI ROHINGYA VOWEL E;Lo;0;AL;;;;;N;;;;; +10D21;HANIFI ROHINGYA VOWEL O;Lo;0;AL;;;;;N;;;;; +10D22;HANIFI ROHINGYA MARK SAKIN;Lo;0;AL;;;;;N;;;;; +10D23;HANIFI ROHINGYA MARK NA KHONNA;Lo;0;AL;;;;;N;;;;; +10D24;HANIFI ROHINGYA SIGN HARBAHAY;Mn;230;NSM;;;;;N;;;;; +10D25;HANIFI ROHINGYA SIGN TAHALA;Mn;230;NSM;;;;;N;;;;; +10D26;HANIFI ROHINGYA SIGN TANA;Mn;230;NSM;;;;;N;;;;; +10D27;HANIFI ROHINGYA SIGN TASSI;Mn;230;NSM;;;;;N;;;;; +10D30;HANIFI ROHINGYA DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;; +10D31;HANIFI ROHINGYA DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;; +10D32;HANIFI ROHINGYA DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;; +10D33;HANIFI ROHINGYA DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;; +10D34;HANIFI ROHINGYA DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;; +10D35;HANIFI ROHINGYA DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;; +10D36;HANIFI ROHINGYA DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;; +10D37;HANIFI ROHINGYA DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;; +10D38;HANIFI ROHINGYA DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;; +10D39;HANIFI ROHINGYA DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;; +10D40;GARAY DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;; +10D41;GARAY DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;; +10D42;GARAY DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;; +10D43;GARAY DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;; +10D44;GARAY DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;; +10D45;GARAY DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;; +10D46;GARAY DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;; +10D47;GARAY DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;; +10D48;GARAY DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;; +10D49;GARAY DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;; +10D4A;GARAY VOWEL SIGN A;Lo;0;R;;;;;N;;;;; +10D4B;GARAY VOWEL SIGN I;Lo;0;R;;;;;N;;;;; +10D4C;GARAY VOWEL SIGN O;Lo;0;R;;;;;N;;;;; +10D4D;GARAY VOWEL SIGN EE;Lo;0;R;;;;;N;;;;; +10D4E;GARAY VOWEL LENGTH MARK;Lm;0;R;;;;;N;;;;; +10D4F;GARAY SUKUN;Lo;0;R;;;;;N;;;;; +10D50;GARAY CAPITAL LETTER A;Lu;0;R;;;;;N;;;;10D70; +10D51;GARAY CAPITAL LETTER CA;Lu;0;R;;;;;N;;;;10D71; +10D52;GARAY CAPITAL LETTER MA;Lu;0;R;;;;;N;;;;10D72; +10D53;GARAY CAPITAL LETTER KA;Lu;0;R;;;;;N;;;;10D73; +10D54;GARAY CAPITAL LETTER BA;Lu;0;R;;;;;N;;;;10D74; +10D55;GARAY CAPITAL LETTER JA;Lu;0;R;;;;;N;;;;10D75; +10D56;GARAY CAPITAL LETTER SA;Lu;0;R;;;;;N;;;;10D76; +10D57;GARAY CAPITAL LETTER WA;Lu;0;R;;;;;N;;;;10D77; +10D58;GARAY CAPITAL LETTER LA;Lu;0;R;;;;;N;;;;10D78; +10D59;GARAY CAPITAL LETTER GA;Lu;0;R;;;;;N;;;;10D79; +10D5A;GARAY CAPITAL LETTER DA;Lu;0;R;;;;;N;;;;10D7A; +10D5B;GARAY CAPITAL LETTER XA;Lu;0;R;;;;;N;;;;10D7B; +10D5C;GARAY CAPITAL LETTER YA;Lu;0;R;;;;;N;;;;10D7C; +10D5D;GARAY CAPITAL LETTER TA;Lu;0;R;;;;;N;;;;10D7D; +10D5E;GARAY CAPITAL LETTER RA;Lu;0;R;;;;;N;;;;10D7E; +10D5F;GARAY CAPITAL LETTER NYA;Lu;0;R;;;;;N;;;;10D7F; +10D60;GARAY CAPITAL LETTER FA;Lu;0;R;;;;;N;;;;10D80; +10D61;GARAY CAPITAL LETTER NA;Lu;0;R;;;;;N;;;;10D81; +10D62;GARAY CAPITAL LETTER PA;Lu;0;R;;;;;N;;;;10D82; +10D63;GARAY CAPITAL LETTER HA;Lu;0;R;;;;;N;;;;10D83; +10D64;GARAY CAPITAL LETTER OLD KA;Lu;0;R;;;;;N;;;;10D84; +10D65;GARAY CAPITAL LETTER OLD NA;Lu;0;R;;;;;N;;;;10D85; +10D69;GARAY VOWEL SIGN E;Mn;230;NSM;;;;;N;;;;; +10D6A;GARAY CONSONANT GEMINATION MARK;Mn;230;NSM;;;;;N;;;;; +10D6B;GARAY COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;;;;; +10D6C;GARAY COMBINING DOUBLE DOT ABOVE;Mn;230;NSM;;;;;N;;;;; +10D6D;GARAY CONSONANT NASALIZATION MARK;Mn;230;NSM;;;;;N;;;;; +10D6E;GARAY HYPHEN;Pd;0;ON;;;;;N;;;;; +10D6F;GARAY REDUPLICATION MARK;Lm;0;R;;;;;N;;;;; +10D70;GARAY SMALL LETTER A;Ll;0;R;;;;;N;;;10D50;;10D50 +10D71;GARAY SMALL LETTER CA;Ll;0;R;;;;;N;;;10D51;;10D51 +10D72;GARAY SMALL LETTER MA;Ll;0;R;;;;;N;;;10D52;;10D52 +10D73;GARAY SMALL LETTER KA;Ll;0;R;;;;;N;;;10D53;;10D53 +10D74;GARAY SMALL LETTER BA;Ll;0;R;;;;;N;;;10D54;;10D54 +10D75;GARAY SMALL LETTER JA;Ll;0;R;;;;;N;;;10D55;;10D55 +10D76;GARAY SMALL LETTER SA;Ll;0;R;;;;;N;;;10D56;;10D56 +10D77;GARAY SMALL LETTER WA;Ll;0;R;;;;;N;;;10D57;;10D57 +10D78;GARAY SMALL LETTER LA;Ll;0;R;;;;;N;;;10D58;;10D58 +10D79;GARAY SMALL LETTER GA;Ll;0;R;;;;;N;;;10D59;;10D59 +10D7A;GARAY SMALL LETTER DA;Ll;0;R;;;;;N;;;10D5A;;10D5A +10D7B;GARAY SMALL LETTER XA;Ll;0;R;;;;;N;;;10D5B;;10D5B +10D7C;GARAY SMALL LETTER YA;Ll;0;R;;;;;N;;;10D5C;;10D5C +10D7D;GARAY SMALL LETTER TA;Ll;0;R;;;;;N;;;10D5D;;10D5D +10D7E;GARAY SMALL LETTER RA;Ll;0;R;;;;;N;;;10D5E;;10D5E +10D7F;GARAY SMALL LETTER NYA;Ll;0;R;;;;;N;;;10D5F;;10D5F +10D80;GARAY SMALL LETTER FA;Ll;0;R;;;;;N;;;10D60;;10D60 +10D81;GARAY SMALL LETTER NA;Ll;0;R;;;;;N;;;10D61;;10D61 +10D82;GARAY SMALL LETTER PA;Ll;0;R;;;;;N;;;10D62;;10D62 +10D83;GARAY SMALL LETTER HA;Ll;0;R;;;;;N;;;10D63;;10D63 +10D84;GARAY SMALL LETTER OLD KA;Ll;0;R;;;;;N;;;10D64;;10D64 +10D85;GARAY SMALL LETTER OLD NA;Ll;0;R;;;;;N;;;10D65;;10D65 +10D8E;GARAY PLUS SIGN;Sm;0;R;;;;;N;;;;; +10D8F;GARAY MINUS SIGN;Sm;0;R;;;;;N;;;;; +10E60;RUMI DIGIT ONE;No;0;AN;;;1;1;N;;;;; +10E61;RUMI DIGIT TWO;No;0;AN;;;2;2;N;;;;; +10E62;RUMI DIGIT THREE;No;0;AN;;;3;3;N;;;;; +10E63;RUMI DIGIT FOUR;No;0;AN;;;4;4;N;;;;; +10E64;RUMI DIGIT FIVE;No;0;AN;;;5;5;N;;;;; +10E65;RUMI DIGIT SIX;No;0;AN;;;6;6;N;;;;; +10E66;RUMI DIGIT SEVEN;No;0;AN;;;7;7;N;;;;; +10E67;RUMI DIGIT EIGHT;No;0;AN;;;8;8;N;;;;; +10E68;RUMI DIGIT NINE;No;0;AN;;;9;9;N;;;;; +10E69;RUMI NUMBER TEN;No;0;AN;;;;10;N;;;;; +10E6A;RUMI NUMBER TWENTY;No;0;AN;;;;20;N;;;;; +10E6B;RUMI NUMBER THIRTY;No;0;AN;;;;30;N;;;;; +10E6C;RUMI NUMBER FORTY;No;0;AN;;;;40;N;;;;; +10E6D;RUMI NUMBER FIFTY;No;0;AN;;;;50;N;;;;; +10E6E;RUMI NUMBER SIXTY;No;0;AN;;;;60;N;;;;; +10E6F;RUMI NUMBER SEVENTY;No;0;AN;;;;70;N;;;;; +10E70;RUMI NUMBER EIGHTY;No;0;AN;;;;80;N;;;;; +10E71;RUMI NUMBER NINETY;No;0;AN;;;;90;N;;;;; +10E72;RUMI NUMBER ONE HUNDRED;No;0;AN;;;;100;N;;;;; +10E73;RUMI NUMBER TWO HUNDRED;No;0;AN;;;;200;N;;;;; +10E74;RUMI NUMBER THREE HUNDRED;No;0;AN;;;;300;N;;;;; +10E75;RUMI NUMBER FOUR HUNDRED;No;0;AN;;;;400;N;;;;; +10E76;RUMI NUMBER FIVE HUNDRED;No;0;AN;;;;500;N;;;;; +10E77;RUMI NUMBER SIX HUNDRED;No;0;AN;;;;600;N;;;;; +10E78;RUMI NUMBER SEVEN HUNDRED;No;0;AN;;;;700;N;;;;; +10E79;RUMI NUMBER EIGHT HUNDRED;No;0;AN;;;;800;N;;;;; +10E7A;RUMI NUMBER NINE HUNDRED;No;0;AN;;;;900;N;;;;; +10E7B;RUMI FRACTION ONE HALF;No;0;AN;;;;1/2;N;;;;; +10E7C;RUMI FRACTION ONE QUARTER;No;0;AN;;;;1/4;N;;;;; +10E7D;RUMI FRACTION ONE THIRD;No;0;AN;;;;1/3;N;;;;; +10E7E;RUMI FRACTION TWO THIRDS;No;0;AN;;;;2/3;N;;;;; +10E80;YEZIDI LETTER ELIF;Lo;0;R;;;;;N;;;;; +10E81;YEZIDI LETTER BE;Lo;0;R;;;;;N;;;;; +10E82;YEZIDI LETTER PE;Lo;0;R;;;;;N;;;;; +10E83;YEZIDI LETTER PHE;Lo;0;R;;;;;N;;;;; +10E84;YEZIDI LETTER THE;Lo;0;R;;;;;N;;;;; +10E85;YEZIDI LETTER SE;Lo;0;R;;;;;N;;;;; +10E86;YEZIDI LETTER CIM;Lo;0;R;;;;;N;;;;; +10E87;YEZIDI LETTER CHIM;Lo;0;R;;;;;N;;;;; +10E88;YEZIDI LETTER CHHIM;Lo;0;R;;;;;N;;;;; +10E89;YEZIDI LETTER HHA;Lo;0;R;;;;;N;;;;; +10E8A;YEZIDI LETTER XA;Lo;0;R;;;;;N;;;;; +10E8B;YEZIDI LETTER DAL;Lo;0;R;;;;;N;;;;; +10E8C;YEZIDI LETTER ZAL;Lo;0;R;;;;;N;;;;; +10E8D;YEZIDI LETTER RA;Lo;0;R;;;;;N;;;;; +10E8E;YEZIDI LETTER RHA;Lo;0;R;;;;;N;;;;; +10E8F;YEZIDI LETTER ZA;Lo;0;R;;;;;N;;;;; +10E90;YEZIDI LETTER JA;Lo;0;R;;;;;N;;;;; +10E91;YEZIDI LETTER SIN;Lo;0;R;;;;;N;;;;; +10E92;YEZIDI LETTER SHIN;Lo;0;R;;;;;N;;;;; +10E93;YEZIDI LETTER SAD;Lo;0;R;;;;;N;;;;; +10E94;YEZIDI LETTER DAD;Lo;0;R;;;;;N;;;;; +10E95;YEZIDI LETTER TA;Lo;0;R;;;;;N;;;;; +10E96;YEZIDI LETTER ZE;Lo;0;R;;;;;N;;;;; +10E97;YEZIDI LETTER EYN;Lo;0;R;;;;;N;;;;; +10E98;YEZIDI LETTER XHEYN;Lo;0;R;;;;;N;;;;; +10E99;YEZIDI LETTER FA;Lo;0;R;;;;;N;;;;; +10E9A;YEZIDI LETTER VA;Lo;0;R;;;;;N;;;;; +10E9B;YEZIDI LETTER VA ALTERNATE FORM;Lo;0;R;;;;;N;;;;; +10E9C;YEZIDI LETTER QAF;Lo;0;R;;;;;N;;;;; +10E9D;YEZIDI LETTER KAF;Lo;0;R;;;;;N;;;;; +10E9E;YEZIDI LETTER KHAF;Lo;0;R;;;;;N;;;;; +10E9F;YEZIDI LETTER GAF;Lo;0;R;;;;;N;;;;; +10EA0;YEZIDI LETTER LAM;Lo;0;R;;;;;N;;;;; +10EA1;YEZIDI LETTER MIM;Lo;0;R;;;;;N;;;;; +10EA2;YEZIDI LETTER NUN;Lo;0;R;;;;;N;;;;; +10EA3;YEZIDI LETTER UM;Lo;0;R;;;;;N;;;;; +10EA4;YEZIDI LETTER WAW;Lo;0;R;;;;;N;;;;; +10EA5;YEZIDI LETTER OW;Lo;0;R;;;;;N;;;;; +10EA6;YEZIDI LETTER EW;Lo;0;R;;;;;N;;;;; +10EA7;YEZIDI LETTER HAY;Lo;0;R;;;;;N;;;;; +10EA8;YEZIDI LETTER YOT;Lo;0;R;;;;;N;;;;; +10EA9;YEZIDI LETTER ET;Lo;0;R;;;;;N;;;;; +10EAB;YEZIDI COMBINING HAMZA MARK;Mn;230;NSM;;;;;N;;;;; +10EAC;YEZIDI COMBINING MADDA MARK;Mn;230;NSM;;;;;N;;;;; +10EAD;YEZIDI HYPHENATION MARK;Pd;0;R;;;;;N;;;;; +10EB0;YEZIDI LETTER LAM WITH DOT ABOVE;Lo;0;R;;;;;N;;;;; +10EB1;YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE;Lo;0;R;;;;;N;;;;; +10EC2;ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;; +10EC3;ARABIC LETTER TAH WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;; +10EC4;ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;; +10EC5;ARABIC SMALL YEH BARREE WITH TWO DOTS BELOW;Lm;0;AL;;;;;N;;;;; +10EC6;ARABIC LETTER THIN NOON;Lo;0;AL;;;;;N;;;;; +10EC7;ARABIC LETTER YEH WITH FOUR DOTS BELOW;Lo;0;AL;;;;;N;;;;; +10ED0;ARABIC BIBLICAL END OF VERSE;Po;0;ON;;;;;N;;;;; +10ED1;ARABIC LIGATURE ALAYHAA AS-SALAATU WAS-SALAAM;So;0;ON;;;;;N;;;;; +10ED2;ARABIC LIGATURE ALAYHIM AS-SALAATU WAS-SALAAM;So;0;ON;;;;;N;;;;; +10ED3;ARABIC LIGATURE ALAYHIMAA AS-SALAATU WAS-SALAAM;So;0;ON;;;;;N;;;;; +10ED4;ARABIC LIGATURE QADDASA ALLAAHU SIRRAH;So;0;ON;;;;;N;;;;; +10ED5;ARABIC LIGATURE QUDDISA SIRRUHUM;So;0;ON;;;;;N;;;;; +10ED6;ARABIC LIGATURE QUDDISA SIRRUHUMAA;So;0;ON;;;;;N;;;;; +10ED7;ARABIC LIGATURE QUDDISAT ASRAARUHUM;So;0;ON;;;;;N;;;;; +10ED8;ARABIC LIGATURE NAWWARA ALLAAHU MARQADAH;So;0;ON;;;;;N;;;;; +10EFA;ARABIC DOUBLE VERTICAL BAR BELOW;Mn;220;NSM;;;;;N;;;;; +10EFB;ARABIC SMALL LOW NOON;Mn;220;NSM;;;;;N;;;;; +10EFC;ARABIC COMBINING ALEF OVERLAY;Mn;0;NSM;;;;;N;;;;; +10EFD;ARABIC SMALL LOW WORD SAKTA;Mn;220;NSM;;;;;N;;;;; +10EFE;ARABIC SMALL LOW WORD QASR;Mn;220;NSM;;;;;N;;;;; +10EFF;ARABIC SMALL LOW WORD MADDA;Mn;220;NSM;;;;;N;;;;; +10F00;OLD SOGDIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10F01;OLD SOGDIAN LETTER FINAL ALEPH;Lo;0;R;;;;;N;;;;; +10F02;OLD SOGDIAN LETTER BETH;Lo;0;R;;;;;N;;;;; +10F03;OLD SOGDIAN LETTER FINAL BETH;Lo;0;R;;;;;N;;;;; +10F04;OLD SOGDIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; +10F05;OLD SOGDIAN LETTER HE;Lo;0;R;;;;;N;;;;; +10F06;OLD SOGDIAN LETTER FINAL HE;Lo;0;R;;;;;N;;;;; +10F07;OLD SOGDIAN LETTER WAW;Lo;0;R;;;;;N;;;;; +10F08;OLD SOGDIAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +10F09;OLD SOGDIAN LETTER HETH;Lo;0;R;;;;;N;;;;; +10F0A;OLD SOGDIAN LETTER YODH;Lo;0;R;;;;;N;;;;; +10F0B;OLD SOGDIAN LETTER KAPH;Lo;0;R;;;;;N;;;;; +10F0C;OLD SOGDIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +10F0D;OLD SOGDIAN LETTER MEM;Lo;0;R;;;;;N;;;;; +10F0E;OLD SOGDIAN LETTER NUN;Lo;0;R;;;;;N;;;;; +10F0F;OLD SOGDIAN LETTER FINAL NUN;Lo;0;R;;;;;N;;;;; +10F10;OLD SOGDIAN LETTER FINAL NUN WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;; +10F11;OLD SOGDIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10F12;OLD SOGDIAN LETTER AYIN;Lo;0;R;;;;;N;;;;; +10F13;OLD SOGDIAN LETTER ALTERNATE AYIN;Lo;0;R;;;;;N;;;;; +10F14;OLD SOGDIAN LETTER PE;Lo;0;R;;;;;N;;;;; +10F15;OLD SOGDIAN LETTER SADHE;Lo;0;R;;;;;N;;;;; +10F16;OLD SOGDIAN LETTER FINAL SADHE;Lo;0;R;;;;;N;;;;; +10F17;OLD SOGDIAN LETTER FINAL SADHE WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;; +10F18;OLD SOGDIAN LETTER RESH-AYIN-DALETH;Lo;0;R;;;;;N;;;;; +10F19;OLD SOGDIAN LETTER SHIN;Lo;0;R;;;;;N;;;;; +10F1A;OLD SOGDIAN LETTER TAW;Lo;0;R;;;;;N;;;;; +10F1B;OLD SOGDIAN LETTER FINAL TAW;Lo;0;R;;;;;N;;;;; +10F1C;OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;; +10F1D;OLD SOGDIAN NUMBER ONE;No;0;R;;;;1;N;;;;; +10F1E;OLD SOGDIAN NUMBER TWO;No;0;R;;;;2;N;;;;; +10F1F;OLD SOGDIAN NUMBER THREE;No;0;R;;;;3;N;;;;; +10F20;OLD SOGDIAN NUMBER FOUR;No;0;R;;;;4;N;;;;; +10F21;OLD SOGDIAN NUMBER FIVE;No;0;R;;;;5;N;;;;; +10F22;OLD SOGDIAN NUMBER TEN;No;0;R;;;;10;N;;;;; +10F23;OLD SOGDIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10F24;OLD SOGDIAN NUMBER THIRTY;No;0;R;;;;30;N;;;;; +10F25;OLD SOGDIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +10F26;OLD SOGDIAN FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;; +10F27;OLD SOGDIAN LIGATURE AYIN-DALETH;Lo;0;R;;;;;N;;;;; +10F30;SOGDIAN LETTER ALEPH;Lo;0;AL;;;;;N;;;;; +10F31;SOGDIAN LETTER BETH;Lo;0;AL;;;;;N;;;;; +10F32;SOGDIAN LETTER GIMEL;Lo;0;AL;;;;;N;;;;; +10F33;SOGDIAN LETTER HE;Lo;0;AL;;;;;N;;;;; +10F34;SOGDIAN LETTER WAW;Lo;0;AL;;;;;N;;;;; +10F35;SOGDIAN LETTER ZAYIN;Lo;0;AL;;;;;N;;;;; +10F36;SOGDIAN LETTER HETH;Lo;0;AL;;;;;N;;;;; +10F37;SOGDIAN LETTER YODH;Lo;0;AL;;;;;N;;;;; +10F38;SOGDIAN LETTER KAPH;Lo;0;AL;;;;;N;;;;; +10F39;SOGDIAN LETTER LAMEDH;Lo;0;AL;;;;;N;;;;; +10F3A;SOGDIAN LETTER MEM;Lo;0;AL;;;;;N;;;;; +10F3B;SOGDIAN LETTER NUN;Lo;0;AL;;;;;N;;;;; +10F3C;SOGDIAN LETTER SAMEKH;Lo;0;AL;;;;;N;;;;; +10F3D;SOGDIAN LETTER AYIN;Lo;0;AL;;;;;N;;;;; +10F3E;SOGDIAN LETTER PE;Lo;0;AL;;;;;N;;;;; +10F3F;SOGDIAN LETTER SADHE;Lo;0;AL;;;;;N;;;;; +10F40;SOGDIAN LETTER RESH-AYIN;Lo;0;AL;;;;;N;;;;; +10F41;SOGDIAN LETTER SHIN;Lo;0;AL;;;;;N;;;;; +10F42;SOGDIAN LETTER TAW;Lo;0;AL;;;;;N;;;;; +10F43;SOGDIAN LETTER FETH;Lo;0;AL;;;;;N;;;;; +10F44;SOGDIAN LETTER LESH;Lo;0;AL;;;;;N;;;;; +10F45;SOGDIAN INDEPENDENT SHIN;Lo;0;AL;;;;;N;;;;; +10F46;SOGDIAN COMBINING DOT BELOW;Mn;220;NSM;;;;;N;;;;; +10F47;SOGDIAN COMBINING TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;; +10F48;SOGDIAN COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;;;;; +10F49;SOGDIAN COMBINING TWO DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; +10F4A;SOGDIAN COMBINING CURVE ABOVE;Mn;230;NSM;;;;;N;;;;; +10F4B;SOGDIAN COMBINING CURVE BELOW;Mn;220;NSM;;;;;N;;;;; +10F4C;SOGDIAN COMBINING HOOK ABOVE;Mn;230;NSM;;;;;N;;;;; +10F4D;SOGDIAN COMBINING HOOK BELOW;Mn;220;NSM;;;;;N;;;;; +10F4E;SOGDIAN COMBINING LONG HOOK BELOW;Mn;220;NSM;;;;;N;;;;; +10F4F;SOGDIAN COMBINING RESH BELOW;Mn;220;NSM;;;;;N;;;;; +10F50;SOGDIAN COMBINING STROKE BELOW;Mn;220;NSM;;;;;N;;;;; +10F51;SOGDIAN NUMBER ONE;No;0;AL;;;;1;N;;;;; +10F52;SOGDIAN NUMBER TEN;No;0;AL;;;;10;N;;;;; +10F53;SOGDIAN NUMBER TWENTY;No;0;AL;;;;20;N;;;;; +10F54;SOGDIAN NUMBER ONE HUNDRED;No;0;AL;;;;100;N;;;;; +10F55;SOGDIAN PUNCTUATION TWO VERTICAL BARS;Po;0;AL;;;;;N;;;;; +10F56;SOGDIAN PUNCTUATION TWO VERTICAL BARS WITH DOTS;Po;0;AL;;;;;N;;;;; +10F57;SOGDIAN PUNCTUATION CIRCLE WITH DOT;Po;0;AL;;;;;N;;;;; +10F58;SOGDIAN PUNCTUATION TWO CIRCLES WITH DOTS;Po;0;AL;;;;;N;;;;; +10F59;SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT;Po;0;AL;;;;;N;;;;; +10F70;OLD UYGHUR LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10F71;OLD UYGHUR LETTER BETH;Lo;0;R;;;;;N;;;;; +10F72;OLD UYGHUR LETTER GIMEL-HETH;Lo;0;R;;;;;N;;;;; +10F73;OLD UYGHUR LETTER WAW;Lo;0;R;;;;;N;;;;; +10F74;OLD UYGHUR LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +10F75;OLD UYGHUR LETTER FINAL HETH;Lo;0;R;;;;;N;;;;; +10F76;OLD UYGHUR LETTER YODH;Lo;0;R;;;;;N;;;;; +10F77;OLD UYGHUR LETTER KAPH;Lo;0;R;;;;;N;;;;; +10F78;OLD UYGHUR LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +10F79;OLD UYGHUR LETTER MEM;Lo;0;R;;;;;N;;;;; +10F7A;OLD UYGHUR LETTER NUN;Lo;0;R;;;;;N;;;;; +10F7B;OLD UYGHUR LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10F7C;OLD UYGHUR LETTER PE;Lo;0;R;;;;;N;;;;; +10F7D;OLD UYGHUR LETTER SADHE;Lo;0;R;;;;;N;;;;; +10F7E;OLD UYGHUR LETTER RESH;Lo;0;R;;;;;N;;;;; +10F7F;OLD UYGHUR LETTER SHIN;Lo;0;R;;;;;N;;;;; +10F80;OLD UYGHUR LETTER TAW;Lo;0;R;;;;;N;;;;; +10F81;OLD UYGHUR LETTER LESH;Lo;0;R;;;;;N;;;;; +10F82;OLD UYGHUR COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;;;;; +10F83;OLD UYGHUR COMBINING DOT BELOW;Mn;220;NSM;;;;;N;;;;; +10F84;OLD UYGHUR COMBINING TWO DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; +10F85;OLD UYGHUR COMBINING TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;; +10F86;OLD UYGHUR PUNCTUATION BAR;Po;0;R;;;;;N;;;;; +10F87;OLD UYGHUR PUNCTUATION TWO BARS;Po;0;R;;;;;N;;;;; +10F88;OLD UYGHUR PUNCTUATION TWO DOTS;Po;0;R;;;;;N;;;;; +10F89;OLD UYGHUR PUNCTUATION FOUR DOTS;Po;0;R;;;;;N;;;;; +10FB0;CHORASMIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10FB1;CHORASMIAN LETTER SMALL ALEPH;Lo;0;R;;;;;N;;;;; +10FB2;CHORASMIAN LETTER BETH;Lo;0;R;;;;;N;;;;; +10FB3;CHORASMIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; +10FB4;CHORASMIAN LETTER DALETH;Lo;0;R;;;;;N;;;;; +10FB5;CHORASMIAN LETTER HE;Lo;0;R;;;;;N;;;;; +10FB6;CHORASMIAN LETTER WAW;Lo;0;R;;;;;N;;;;; +10FB7;CHORASMIAN LETTER CURLED WAW;Lo;0;R;;;;;N;;;;; +10FB8;CHORASMIAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +10FB9;CHORASMIAN LETTER HETH;Lo;0;R;;;;;N;;;;; +10FBA;CHORASMIAN LETTER YODH;Lo;0;R;;;;;N;;;;; +10FBB;CHORASMIAN LETTER KAPH;Lo;0;R;;;;;N;;;;; +10FBC;CHORASMIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +10FBD;CHORASMIAN LETTER MEM;Lo;0;R;;;;;N;;;;; +10FBE;CHORASMIAN LETTER NUN;Lo;0;R;;;;;N;;;;; +10FBF;CHORASMIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10FC0;CHORASMIAN LETTER AYIN;Lo;0;R;;;;;N;;;;; +10FC1;CHORASMIAN LETTER PE;Lo;0;R;;;;;N;;;;; +10FC2;CHORASMIAN LETTER RESH;Lo;0;R;;;;;N;;;;; +10FC3;CHORASMIAN LETTER SHIN;Lo;0;R;;;;;N;;;;; +10FC4;CHORASMIAN LETTER TAW;Lo;0;R;;;;;N;;;;; +10FC5;CHORASMIAN NUMBER ONE;No;0;R;;;;1;N;;;;; +10FC6;CHORASMIAN NUMBER TWO;No;0;R;;;;2;N;;;;; +10FC7;CHORASMIAN NUMBER THREE;No;0;R;;;;3;N;;;;; +10FC8;CHORASMIAN NUMBER FOUR;No;0;R;;;;4;N;;;;; +10FC9;CHORASMIAN NUMBER TEN;No;0;R;;;;10;N;;;;; +10FCA;CHORASMIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10FCB;CHORASMIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +10FE0;ELYMAIC LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10FE1;ELYMAIC LETTER BETH;Lo;0;R;;;;;N;;;;; +10FE2;ELYMAIC LETTER GIMEL;Lo;0;R;;;;;N;;;;; +10FE3;ELYMAIC LETTER DALETH;Lo;0;R;;;;;N;;;;; +10FE4;ELYMAIC LETTER HE;Lo;0;R;;;;;N;;;;; +10FE5;ELYMAIC LETTER WAW;Lo;0;R;;;;;N;;;;; +10FE6;ELYMAIC LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +10FE7;ELYMAIC LETTER HETH;Lo;0;R;;;;;N;;;;; +10FE8;ELYMAIC LETTER TETH;Lo;0;R;;;;;N;;;;; +10FE9;ELYMAIC LETTER YODH;Lo;0;R;;;;;N;;;;; +10FEA;ELYMAIC LETTER KAPH;Lo;0;R;;;;;N;;;;; +10FEB;ELYMAIC LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +10FEC;ELYMAIC LETTER MEM;Lo;0;R;;;;;N;;;;; +10FED;ELYMAIC LETTER NUN;Lo;0;R;;;;;N;;;;; +10FEE;ELYMAIC LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10FEF;ELYMAIC LETTER AYIN;Lo;0;R;;;;;N;;;;; +10FF0;ELYMAIC LETTER PE;Lo;0;R;;;;;N;;;;; +10FF1;ELYMAIC LETTER SADHE;Lo;0;R;;;;;N;;;;; +10FF2;ELYMAIC LETTER QOPH;Lo;0;R;;;;;N;;;;; +10FF3;ELYMAIC LETTER RESH;Lo;0;R;;;;;N;;;;; +10FF4;ELYMAIC LETTER SHIN;Lo;0;R;;;;;N;;;;; +10FF5;ELYMAIC LETTER TAW;Lo;0;R;;;;;N;;;;; +10FF6;ELYMAIC LIGATURE ZAYIN-YODH;Lo;0;R;;;;;N;;;;; +11000;BRAHMI SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;; +11001;BRAHMI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11002;BRAHMI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11003;BRAHMI SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; +11004;BRAHMI SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; +11005;BRAHMI LETTER A;Lo;0;L;;;;;N;;;;; +11006;BRAHMI LETTER AA;Lo;0;L;;;;;N;;;;; +11007;BRAHMI LETTER I;Lo;0;L;;;;;N;;;;; +11008;BRAHMI LETTER II;Lo;0;L;;;;;N;;;;; +11009;BRAHMI LETTER U;Lo;0;L;;;;;N;;;;; +1100A;BRAHMI LETTER UU;Lo;0;L;;;;;N;;;;; +1100B;BRAHMI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +1100C;BRAHMI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +1100D;BRAHMI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +1100E;BRAHMI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1100F;BRAHMI LETTER E;Lo;0;L;;;;;N;;;;; +11010;BRAHMI LETTER AI;Lo;0;L;;;;;N;;;;; +11011;BRAHMI LETTER O;Lo;0;L;;;;;N;;;;; +11012;BRAHMI LETTER AU;Lo;0;L;;;;;N;;;;; +11013;BRAHMI LETTER KA;Lo;0;L;;;;;N;;;;; +11014;BRAHMI LETTER KHA;Lo;0;L;;;;;N;;;;; +11015;BRAHMI LETTER GA;Lo;0;L;;;;;N;;;;; +11016;BRAHMI LETTER GHA;Lo;0;L;;;;;N;;;;; +11017;BRAHMI LETTER NGA;Lo;0;L;;;;;N;;;;; +11018;BRAHMI LETTER CA;Lo;0;L;;;;;N;;;;; +11019;BRAHMI LETTER CHA;Lo;0;L;;;;;N;;;;; +1101A;BRAHMI LETTER JA;Lo;0;L;;;;;N;;;;; +1101B;BRAHMI LETTER JHA;Lo;0;L;;;;;N;;;;; +1101C;BRAHMI LETTER NYA;Lo;0;L;;;;;N;;;;; +1101D;BRAHMI LETTER TTA;Lo;0;L;;;;;N;;;;; +1101E;BRAHMI LETTER TTHA;Lo;0;L;;;;;N;;;;; +1101F;BRAHMI LETTER DDA;Lo;0;L;;;;;N;;;;; +11020;BRAHMI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11021;BRAHMI LETTER NNA;Lo;0;L;;;;;N;;;;; +11022;BRAHMI LETTER TA;Lo;0;L;;;;;N;;;;; +11023;BRAHMI LETTER THA;Lo;0;L;;;;;N;;;;; +11024;BRAHMI LETTER DA;Lo;0;L;;;;;N;;;;; +11025;BRAHMI LETTER DHA;Lo;0;L;;;;;N;;;;; +11026;BRAHMI LETTER NA;Lo;0;L;;;;;N;;;;; +11027;BRAHMI LETTER PA;Lo;0;L;;;;;N;;;;; +11028;BRAHMI LETTER PHA;Lo;0;L;;;;;N;;;;; +11029;BRAHMI LETTER BA;Lo;0;L;;;;;N;;;;; +1102A;BRAHMI LETTER BHA;Lo;0;L;;;;;N;;;;; +1102B;BRAHMI LETTER MA;Lo;0;L;;;;;N;;;;; +1102C;BRAHMI LETTER YA;Lo;0;L;;;;;N;;;;; +1102D;BRAHMI LETTER RA;Lo;0;L;;;;;N;;;;; +1102E;BRAHMI LETTER LA;Lo;0;L;;;;;N;;;;; +1102F;BRAHMI LETTER VA;Lo;0;L;;;;;N;;;;; +11030;BRAHMI LETTER SHA;Lo;0;L;;;;;N;;;;; +11031;BRAHMI LETTER SSA;Lo;0;L;;;;;N;;;;; +11032;BRAHMI LETTER SA;Lo;0;L;;;;;N;;;;; +11033;BRAHMI LETTER HA;Lo;0;L;;;;;N;;;;; +11034;BRAHMI LETTER LLA;Lo;0;L;;;;;N;;;;; +11035;BRAHMI LETTER OLD TAMIL LLLA;Lo;0;L;;;;;N;;;;; +11036;BRAHMI LETTER OLD TAMIL RRA;Lo;0;L;;;;;N;;;;; +11037;BRAHMI LETTER OLD TAMIL NNNA;Lo;0;L;;;;;N;;;;; +11038;BRAHMI VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; +11039;BRAHMI VOWEL SIGN BHATTIPROLU AA;Mn;0;NSM;;;;;N;;;;; +1103A;BRAHMI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +1103B;BRAHMI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +1103C;BRAHMI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1103D;BRAHMI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +1103E;BRAHMI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +1103F;BRAHMI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +11040;BRAHMI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +11041;BRAHMI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +11042;BRAHMI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11043;BRAHMI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +11044;BRAHMI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +11045;BRAHMI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +11046;BRAHMI VIRAMA;Mn;9;NSM;;;;;N;;;;; +11047;BRAHMI DANDA;Po;0;L;;;;;N;;;;; +11048;BRAHMI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +11049;BRAHMI PUNCTUATION DOT;Po;0;L;;;;;N;;;;; +1104A;BRAHMI PUNCTUATION DOUBLE DOT;Po;0;L;;;;;N;;;;; +1104B;BRAHMI PUNCTUATION LINE;Po;0;L;;;;;N;;;;; +1104C;BRAHMI PUNCTUATION CRESCENT BAR;Po;0;L;;;;;N;;;;; +1104D;BRAHMI PUNCTUATION LOTUS;Po;0;L;;;;;N;;;;; +11052;BRAHMI NUMBER ONE;No;0;ON;;;1;1;N;;;;; +11053;BRAHMI NUMBER TWO;No;0;ON;;;2;2;N;;;;; +11054;BRAHMI NUMBER THREE;No;0;ON;;;3;3;N;;;;; +11055;BRAHMI NUMBER FOUR;No;0;ON;;;4;4;N;;;;; +11056;BRAHMI NUMBER FIVE;No;0;ON;;;5;5;N;;;;; +11057;BRAHMI NUMBER SIX;No;0;ON;;;6;6;N;;;;; +11058;BRAHMI NUMBER SEVEN;No;0;ON;;;7;7;N;;;;; +11059;BRAHMI NUMBER EIGHT;No;0;ON;;;8;8;N;;;;; +1105A;BRAHMI NUMBER NINE;No;0;ON;;;9;9;N;;;;; +1105B;BRAHMI NUMBER TEN;No;0;ON;;;;10;N;;;;; +1105C;BRAHMI NUMBER TWENTY;No;0;ON;;;;20;N;;;;; +1105D;BRAHMI NUMBER THIRTY;No;0;ON;;;;30;N;;;;; +1105E;BRAHMI NUMBER FORTY;No;0;ON;;;;40;N;;;;; +1105F;BRAHMI NUMBER FIFTY;No;0;ON;;;;50;N;;;;; +11060;BRAHMI NUMBER SIXTY;No;0;ON;;;;60;N;;;;; +11061;BRAHMI NUMBER SEVENTY;No;0;ON;;;;70;N;;;;; +11062;BRAHMI NUMBER EIGHTY;No;0;ON;;;;80;N;;;;; +11063;BRAHMI NUMBER NINETY;No;0;ON;;;;90;N;;;;; +11064;BRAHMI NUMBER ONE HUNDRED;No;0;ON;;;;100;N;;;;; +11065;BRAHMI NUMBER ONE THOUSAND;No;0;ON;;;;1000;N;;;;; +11066;BRAHMI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11067;BRAHMI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11068;BRAHMI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11069;BRAHMI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1106A;BRAHMI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1106B;BRAHMI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1106C;BRAHMI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1106D;BRAHMI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1106E;BRAHMI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1106F;BRAHMI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11070;BRAHMI SIGN OLD TAMIL VIRAMA;Mn;9;NSM;;;;;N;;;;; +11071;BRAHMI LETTER OLD TAMIL SHORT E;Lo;0;L;;;;;N;;;;; +11072;BRAHMI LETTER OLD TAMIL SHORT O;Lo;0;L;;;;;N;;;;; +11073;BRAHMI VOWEL SIGN OLD TAMIL SHORT E;Mn;0;NSM;;;;;N;;;;; +11074;BRAHMI VOWEL SIGN OLD TAMIL SHORT O;Mn;0;NSM;;;;;N;;;;; +11075;BRAHMI LETTER OLD TAMIL LLA;Lo;0;L;;;;;N;;;;; +1107F;BRAHMI NUMBER JOINER;Mn;9;NSM;;;;;N;;;;; +11080;KAITHI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11081;KAITHI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11082;KAITHI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11083;KAITHI LETTER A;Lo;0;L;;;;;N;;;;; +11084;KAITHI LETTER AA;Lo;0;L;;;;;N;;;;; +11085;KAITHI LETTER I;Lo;0;L;;;;;N;;;;; +11086;KAITHI LETTER II;Lo;0;L;;;;;N;;;;; +11087;KAITHI LETTER U;Lo;0;L;;;;;N;;;;; +11088;KAITHI LETTER UU;Lo;0;L;;;;;N;;;;; +11089;KAITHI LETTER E;Lo;0;L;;;;;N;;;;; +1108A;KAITHI LETTER AI;Lo;0;L;;;;;N;;;;; +1108B;KAITHI LETTER O;Lo;0;L;;;;;N;;;;; +1108C;KAITHI LETTER AU;Lo;0;L;;;;;N;;;;; +1108D;KAITHI LETTER KA;Lo;0;L;;;;;N;;;;; +1108E;KAITHI LETTER KHA;Lo;0;L;;;;;N;;;;; +1108F;KAITHI LETTER GA;Lo;0;L;;;;;N;;;;; +11090;KAITHI LETTER GHA;Lo;0;L;;;;;N;;;;; +11091;KAITHI LETTER NGA;Lo;0;L;;;;;N;;;;; +11092;KAITHI LETTER CA;Lo;0;L;;;;;N;;;;; +11093;KAITHI LETTER CHA;Lo;0;L;;;;;N;;;;; +11094;KAITHI LETTER JA;Lo;0;L;;;;;N;;;;; +11095;KAITHI LETTER JHA;Lo;0;L;;;;;N;;;;; +11096;KAITHI LETTER NYA;Lo;0;L;;;;;N;;;;; +11097;KAITHI LETTER TTA;Lo;0;L;;;;;N;;;;; +11098;KAITHI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11099;KAITHI LETTER DDA;Lo;0;L;;;;;N;;;;; +1109A;KAITHI LETTER DDDHA;Lo;0;L;11099 110BA;;;;N;;;;; +1109B;KAITHI LETTER DDHA;Lo;0;L;;;;;N;;;;; +1109C;KAITHI LETTER RHA;Lo;0;L;1109B 110BA;;;;N;;;;; +1109D;KAITHI LETTER NNA;Lo;0;L;;;;;N;;;;; +1109E;KAITHI LETTER TA;Lo;0;L;;;;;N;;;;; +1109F;KAITHI LETTER THA;Lo;0;L;;;;;N;;;;; +110A0;KAITHI LETTER DA;Lo;0;L;;;;;N;;;;; +110A1;KAITHI LETTER DHA;Lo;0;L;;;;;N;;;;; +110A2;KAITHI LETTER NA;Lo;0;L;;;;;N;;;;; +110A3;KAITHI LETTER PA;Lo;0;L;;;;;N;;;;; +110A4;KAITHI LETTER PHA;Lo;0;L;;;;;N;;;;; +110A5;KAITHI LETTER BA;Lo;0;L;;;;;N;;;;; +110A6;KAITHI LETTER BHA;Lo;0;L;;;;;N;;;;; +110A7;KAITHI LETTER MA;Lo;0;L;;;;;N;;;;; +110A8;KAITHI LETTER YA;Lo;0;L;;;;;N;;;;; +110A9;KAITHI LETTER RA;Lo;0;L;;;;;N;;;;; +110AA;KAITHI LETTER LA;Lo;0;L;;;;;N;;;;; +110AB;KAITHI LETTER VA;Lo;0;L;110A5 110BA;;;;N;;;;; +110AC;KAITHI LETTER SHA;Lo;0;L;;;;;N;;;;; +110AD;KAITHI LETTER SSA;Lo;0;L;;;;;N;;;;; +110AE;KAITHI LETTER SA;Lo;0;L;;;;;N;;;;; +110AF;KAITHI LETTER HA;Lo;0;L;;;;;N;;;;; +110B0;KAITHI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +110B1;KAITHI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +110B2;KAITHI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +110B3;KAITHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +110B4;KAITHI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +110B5;KAITHI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +110B6;KAITHI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +110B7;KAITHI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +110B8;KAITHI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +110B9;KAITHI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +110BA;KAITHI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +110BB;KAITHI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +110BC;KAITHI ENUMERATION SIGN;Po;0;L;;;;;N;;;;; +110BD;KAITHI NUMBER SIGN;Cf;0;L;;;;;N;;;;; +110BE;KAITHI SECTION MARK;Po;0;L;;;;;N;;;;; +110BF;KAITHI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;; +110C0;KAITHI DANDA;Po;0;L;;;;;N;;;;; +110C1;KAITHI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +110C2;KAITHI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +110CD;KAITHI NUMBER SIGN ABOVE;Cf;0;L;;;;;N;;;;; +110D0;SORA SOMPENG LETTER SAH;Lo;0;L;;;;;N;;;;; +110D1;SORA SOMPENG LETTER TAH;Lo;0;L;;;;;N;;;;; +110D2;SORA SOMPENG LETTER BAH;Lo;0;L;;;;;N;;;;; +110D3;SORA SOMPENG LETTER CAH;Lo;0;L;;;;;N;;;;; +110D4;SORA SOMPENG LETTER DAH;Lo;0;L;;;;;N;;;;; +110D5;SORA SOMPENG LETTER GAH;Lo;0;L;;;;;N;;;;; +110D6;SORA SOMPENG LETTER MAH;Lo;0;L;;;;;N;;;;; +110D7;SORA SOMPENG LETTER NGAH;Lo;0;L;;;;;N;;;;; +110D8;SORA SOMPENG LETTER LAH;Lo;0;L;;;;;N;;;;; +110D9;SORA SOMPENG LETTER NAH;Lo;0;L;;;;;N;;;;; +110DA;SORA SOMPENG LETTER VAH;Lo;0;L;;;;;N;;;;; +110DB;SORA SOMPENG LETTER PAH;Lo;0;L;;;;;N;;;;; +110DC;SORA SOMPENG LETTER YAH;Lo;0;L;;;;;N;;;;; +110DD;SORA SOMPENG LETTER RAH;Lo;0;L;;;;;N;;;;; +110DE;SORA SOMPENG LETTER HAH;Lo;0;L;;;;;N;;;;; +110DF;SORA SOMPENG LETTER KAH;Lo;0;L;;;;;N;;;;; +110E0;SORA SOMPENG LETTER JAH;Lo;0;L;;;;;N;;;;; +110E1;SORA SOMPENG LETTER NYAH;Lo;0;L;;;;;N;;;;; +110E2;SORA SOMPENG LETTER AH;Lo;0;L;;;;;N;;;;; +110E3;SORA SOMPENG LETTER EEH;Lo;0;L;;;;;N;;;;; +110E4;SORA SOMPENG LETTER IH;Lo;0;L;;;;;N;;;;; +110E5;SORA SOMPENG LETTER UH;Lo;0;L;;;;;N;;;;; +110E6;SORA SOMPENG LETTER OH;Lo;0;L;;;;;N;;;;; +110E7;SORA SOMPENG LETTER EH;Lo;0;L;;;;;N;;;;; +110E8;SORA SOMPENG LETTER MAE;Lo;0;L;;;;;N;;;;; +110F0;SORA SOMPENG DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +110F1;SORA SOMPENG DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +110F2;SORA SOMPENG DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +110F3;SORA SOMPENG DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +110F4;SORA SOMPENG DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +110F5;SORA SOMPENG DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +110F6;SORA SOMPENG DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +110F7;SORA SOMPENG DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +110F8;SORA SOMPENG DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +110F9;SORA SOMPENG DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11100;CHAKMA SIGN CANDRABINDU;Mn;230;NSM;;;;;N;;;;; +11101;CHAKMA SIGN ANUSVARA;Mn;230;NSM;;;;;N;;;;; +11102;CHAKMA SIGN VISARGA;Mn;230;NSM;;;;;N;;;;; +11103;CHAKMA LETTER AA;Lo;0;L;;;;;N;;;;; +11104;CHAKMA LETTER I;Lo;0;L;;;;;N;;;;; +11105;CHAKMA LETTER U;Lo;0;L;;;;;N;;;;; +11106;CHAKMA LETTER E;Lo;0;L;;;;;N;;;;; +11107;CHAKMA LETTER KAA;Lo;0;L;;;;;N;;;;; +11108;CHAKMA LETTER KHAA;Lo;0;L;;;;;N;;;;; +11109;CHAKMA LETTER GAA;Lo;0;L;;;;;N;;;;; +1110A;CHAKMA LETTER GHAA;Lo;0;L;;;;;N;;;;; +1110B;CHAKMA LETTER NGAA;Lo;0;L;;;;;N;;;;; +1110C;CHAKMA LETTER CAA;Lo;0;L;;;;;N;;;;; +1110D;CHAKMA LETTER CHAA;Lo;0;L;;;;;N;;;;; +1110E;CHAKMA LETTER JAA;Lo;0;L;;;;;N;;;;; +1110F;CHAKMA LETTER JHAA;Lo;0;L;;;;;N;;;;; +11110;CHAKMA LETTER NYAA;Lo;0;L;;;;;N;;;;; +11111;CHAKMA LETTER TTAA;Lo;0;L;;;;;N;;;;; +11112;CHAKMA LETTER TTHAA;Lo;0;L;;;;;N;;;;; +11113;CHAKMA LETTER DDAA;Lo;0;L;;;;;N;;;;; +11114;CHAKMA LETTER DDHAA;Lo;0;L;;;;;N;;;;; +11115;CHAKMA LETTER NNAA;Lo;0;L;;;;;N;;;;; +11116;CHAKMA LETTER TAA;Lo;0;L;;;;;N;;;;; +11117;CHAKMA LETTER THAA;Lo;0;L;;;;;N;;;;; +11118;CHAKMA LETTER DAA;Lo;0;L;;;;;N;;;;; +11119;CHAKMA LETTER DHAA;Lo;0;L;;;;;N;;;;; +1111A;CHAKMA LETTER NAA;Lo;0;L;;;;;N;;;;; +1111B;CHAKMA LETTER PAA;Lo;0;L;;;;;N;;;;; +1111C;CHAKMA LETTER PHAA;Lo;0;L;;;;;N;;;;; +1111D;CHAKMA LETTER BAA;Lo;0;L;;;;;N;;;;; +1111E;CHAKMA LETTER BHAA;Lo;0;L;;;;;N;;;;; +1111F;CHAKMA LETTER MAA;Lo;0;L;;;;;N;;;;; +11120;CHAKMA LETTER YYAA;Lo;0;L;;;;;N;;;;; +11121;CHAKMA LETTER YAA;Lo;0;L;;;;;N;;;;; +11122;CHAKMA LETTER RAA;Lo;0;L;;;;;N;;;;; +11123;CHAKMA LETTER LAA;Lo;0;L;;;;;N;;;;; +11124;CHAKMA LETTER WAA;Lo;0;L;;;;;N;;;;; +11125;CHAKMA LETTER SAA;Lo;0;L;;;;;N;;;;; +11126;CHAKMA LETTER HAA;Lo;0;L;;;;;N;;;;; +11127;CHAKMA VOWEL SIGN A;Mn;0;NSM;;;;;N;;;;; +11128;CHAKMA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11129;CHAKMA VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +1112A;CHAKMA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1112B;CHAKMA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +1112C;CHAKMA VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +1112D;CHAKMA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +1112E;CHAKMA VOWEL SIGN O;Mn;0;NSM;11131 11127;;;;N;;;;; +1112F;CHAKMA VOWEL SIGN AU;Mn;0;NSM;11132 11127;;;;N;;;;; +11130;CHAKMA VOWEL SIGN OI;Mn;0;NSM;;;;;N;;;;; +11131;CHAKMA O MARK;Mn;0;NSM;;;;;N;;;;; +11132;CHAKMA AU MARK;Mn;0;NSM;;;;;N;;;;; +11133;CHAKMA VIRAMA;Mn;9;NSM;;;;;N;;;;; +11134;CHAKMA MAAYYAA;Mn;9;NSM;;;;;N;;;;; +11136;CHAKMA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11137;CHAKMA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11138;CHAKMA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11139;CHAKMA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1113A;CHAKMA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1113B;CHAKMA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1113C;CHAKMA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1113D;CHAKMA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1113E;CHAKMA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1113F;CHAKMA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11140;CHAKMA SECTION MARK;Po;0;L;;;;;N;;;;; +11141;CHAKMA DANDA;Po;0;L;;;;;N;;;;; +11142;CHAKMA DOUBLE DANDA;Po;0;L;;;;;N;;;;; +11143;CHAKMA QUESTION MARK;Po;0;L;;;;;N;;;;; +11144;CHAKMA LETTER LHAA;Lo;0;L;;;;;N;;;;; +11145;CHAKMA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11146;CHAKMA VOWEL SIGN EI;Mc;0;L;;;;;N;;;;; +11147;CHAKMA LETTER VAA;Lo;0;L;;;;;N;;;;; +11150;MAHAJANI LETTER A;Lo;0;L;;;;;N;;;;; +11151;MAHAJANI LETTER I;Lo;0;L;;;;;N;;;;; +11152;MAHAJANI LETTER U;Lo;0;L;;;;;N;;;;; +11153;MAHAJANI LETTER E;Lo;0;L;;;;;N;;;;; +11154;MAHAJANI LETTER O;Lo;0;L;;;;;N;;;;; +11155;MAHAJANI LETTER KA;Lo;0;L;;;;;N;;;;; +11156;MAHAJANI LETTER KHA;Lo;0;L;;;;;N;;;;; +11157;MAHAJANI LETTER GA;Lo;0;L;;;;;N;;;;; +11158;MAHAJANI LETTER GHA;Lo;0;L;;;;;N;;;;; +11159;MAHAJANI LETTER CA;Lo;0;L;;;;;N;;;;; +1115A;MAHAJANI LETTER CHA;Lo;0;L;;;;;N;;;;; +1115B;MAHAJANI LETTER JA;Lo;0;L;;;;;N;;;;; +1115C;MAHAJANI LETTER JHA;Lo;0;L;;;;;N;;;;; +1115D;MAHAJANI LETTER NYA;Lo;0;L;;;;;N;;;;; +1115E;MAHAJANI LETTER TTA;Lo;0;L;;;;;N;;;;; +1115F;MAHAJANI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11160;MAHAJANI LETTER DDA;Lo;0;L;;;;;N;;;;; +11161;MAHAJANI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11162;MAHAJANI LETTER NNA;Lo;0;L;;;;;N;;;;; +11163;MAHAJANI LETTER TA;Lo;0;L;;;;;N;;;;; +11164;MAHAJANI LETTER THA;Lo;0;L;;;;;N;;;;; +11165;MAHAJANI LETTER DA;Lo;0;L;;;;;N;;;;; +11166;MAHAJANI LETTER DHA;Lo;0;L;;;;;N;;;;; +11167;MAHAJANI LETTER NA;Lo;0;L;;;;;N;;;;; +11168;MAHAJANI LETTER PA;Lo;0;L;;;;;N;;;;; +11169;MAHAJANI LETTER PHA;Lo;0;L;;;;;N;;;;; +1116A;MAHAJANI LETTER BA;Lo;0;L;;;;;N;;;;; +1116B;MAHAJANI LETTER BHA;Lo;0;L;;;;;N;;;;; +1116C;MAHAJANI LETTER MA;Lo;0;L;;;;;N;;;;; +1116D;MAHAJANI LETTER RA;Lo;0;L;;;;;N;;;;; +1116E;MAHAJANI LETTER LA;Lo;0;L;;;;;N;;;;; +1116F;MAHAJANI LETTER VA;Lo;0;L;;;;;N;;;;; +11170;MAHAJANI LETTER SA;Lo;0;L;;;;;N;;;;; +11171;MAHAJANI LETTER HA;Lo;0;L;;;;;N;;;;; +11172;MAHAJANI LETTER RRA;Lo;0;L;;;;;N;;;;; +11173;MAHAJANI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +11174;MAHAJANI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +11175;MAHAJANI SECTION MARK;Po;0;L;;;;;N;;;;; +11176;MAHAJANI LIGATURE SHRI;Lo;0;L;;;;;N;;;;; +11180;SHARADA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11181;SHARADA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11182;SHARADA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11183;SHARADA LETTER A;Lo;0;L;;;;;N;;;;; +11184;SHARADA LETTER AA;Lo;0;L;;;;;N;;;;; +11185;SHARADA LETTER I;Lo;0;L;;;;;N;;;;; +11186;SHARADA LETTER II;Lo;0;L;;;;;N;;;;; +11187;SHARADA LETTER U;Lo;0;L;;;;;N;;;;; +11188;SHARADA LETTER UU;Lo;0;L;;;;;N;;;;; +11189;SHARADA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +1118A;SHARADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +1118B;SHARADA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +1118C;SHARADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1118D;SHARADA LETTER E;Lo;0;L;;;;;N;;;;; +1118E;SHARADA LETTER AI;Lo;0;L;;;;;N;;;;; +1118F;SHARADA LETTER O;Lo;0;L;;;;;N;;;;; +11190;SHARADA LETTER AU;Lo;0;L;;;;;N;;;;; +11191;SHARADA LETTER KA;Lo;0;L;;;;;N;;;;; +11192;SHARADA LETTER KHA;Lo;0;L;;;;;N;;;;; +11193;SHARADA LETTER GA;Lo;0;L;;;;;N;;;;; +11194;SHARADA LETTER GHA;Lo;0;L;;;;;N;;;;; +11195;SHARADA LETTER NGA;Lo;0;L;;;;;N;;;;; +11196;SHARADA LETTER CA;Lo;0;L;;;;;N;;;;; +11197;SHARADA LETTER CHA;Lo;0;L;;;;;N;;;;; +11198;SHARADA LETTER JA;Lo;0;L;;;;;N;;;;; +11199;SHARADA LETTER JHA;Lo;0;L;;;;;N;;;;; +1119A;SHARADA LETTER NYA;Lo;0;L;;;;;N;;;;; +1119B;SHARADA LETTER TTA;Lo;0;L;;;;;N;;;;; +1119C;SHARADA LETTER TTHA;Lo;0;L;;;;;N;;;;; +1119D;SHARADA LETTER DDA;Lo;0;L;;;;;N;;;;; +1119E;SHARADA LETTER DDHA;Lo;0;L;;;;;N;;;;; +1119F;SHARADA LETTER NNA;Lo;0;L;;;;;N;;;;; +111A0;SHARADA LETTER TA;Lo;0;L;;;;;N;;;;; +111A1;SHARADA LETTER THA;Lo;0;L;;;;;N;;;;; +111A2;SHARADA LETTER DA;Lo;0;L;;;;;N;;;;; +111A3;SHARADA LETTER DHA;Lo;0;L;;;;;N;;;;; +111A4;SHARADA LETTER NA;Lo;0;L;;;;;N;;;;; +111A5;SHARADA LETTER PA;Lo;0;L;;;;;N;;;;; +111A6;SHARADA LETTER PHA;Lo;0;L;;;;;N;;;;; +111A7;SHARADA LETTER BA;Lo;0;L;;;;;N;;;;; +111A8;SHARADA LETTER BHA;Lo;0;L;;;;;N;;;;; +111A9;SHARADA LETTER MA;Lo;0;L;;;;;N;;;;; +111AA;SHARADA LETTER YA;Lo;0;L;;;;;N;;;;; +111AB;SHARADA LETTER RA;Lo;0;L;;;;;N;;;;; +111AC;SHARADA LETTER LA;Lo;0;L;;;;;N;;;;; +111AD;SHARADA LETTER LLA;Lo;0;L;;;;;N;;;;; +111AE;SHARADA LETTER VA;Lo;0;L;;;;;N;;;;; +111AF;SHARADA LETTER SHA;Lo;0;L;;;;;N;;;;; +111B0;SHARADA LETTER SSA;Lo;0;L;;;;;N;;;;; +111B1;SHARADA LETTER SA;Lo;0;L;;;;;N;;;;; +111B2;SHARADA LETTER HA;Lo;0;L;;;;;N;;;;; +111B3;SHARADA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +111B4;SHARADA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +111B5;SHARADA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +111B6;SHARADA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +111B7;SHARADA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +111B8;SHARADA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +111B9;SHARADA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +111BA;SHARADA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +111BB;SHARADA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +111BC;SHARADA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +111BD;SHARADA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +111BE;SHARADA VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +111BF;SHARADA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +111C0;SHARADA SIGN VIRAMA;Mc;9;L;;;;;N;;;;; +111C1;SHARADA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +111C2;SHARADA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; +111C3;SHARADA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; +111C4;SHARADA OM;Lo;0;L;;;;;N;;;;; +111C5;SHARADA DANDA;Po;0;L;;;;;N;;;;; +111C6;SHARADA DOUBLE DANDA;Po;0;L;;;;;N;;;;; +111C7;SHARADA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +111C8;SHARADA SEPARATOR;Po;0;L;;;;;N;;;;; +111C9;SHARADA SANDHI MARK;Mn;0;NSM;;;;;N;;;;; +111CA;SHARADA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +111CB;SHARADA VOWEL MODIFIER MARK;Mn;0;NSM;;;;;N;;;;; +111CC;SHARADA EXTRA SHORT VOWEL MARK;Mn;0;NSM;;;;;N;;;;; +111CD;SHARADA SUTRA MARK;Po;0;L;;;;;N;;;;; +111CE;SHARADA VOWEL SIGN PRISHTHAMATRA E;Mc;0;L;;;;;N;;;;; +111CF;SHARADA SIGN INVERTED CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +111D0;SHARADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +111D1;SHARADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +111D2;SHARADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +111D3;SHARADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +111D4;SHARADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +111D5;SHARADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +111D6;SHARADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +111D7;SHARADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +111D8;SHARADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +111D9;SHARADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +111DA;SHARADA EKAM;Lo;0;L;;;;;N;;;;; +111DB;SHARADA SIGN SIDDHAM;Po;0;L;;;;;N;;;;; +111DC;SHARADA HEADSTROKE;Lo;0;L;;;;;N;;;;; +111DD;SHARADA CONTINUATION SIGN;Po;0;L;;;;;N;;;;; +111DE;SHARADA SECTION MARK-1;Po;0;L;;;;;N;;;;; +111DF;SHARADA SECTION MARK-2;Po;0;L;;;;;N;;;;; +111E1;SINHALA ARCHAIC DIGIT ONE;No;0;L;;;;1;N;;;;; +111E2;SINHALA ARCHAIC DIGIT TWO;No;0;L;;;;2;N;;;;; +111E3;SINHALA ARCHAIC DIGIT THREE;No;0;L;;;;3;N;;;;; +111E4;SINHALA ARCHAIC DIGIT FOUR;No;0;L;;;;4;N;;;;; +111E5;SINHALA ARCHAIC DIGIT FIVE;No;0;L;;;;5;N;;;;; +111E6;SINHALA ARCHAIC DIGIT SIX;No;0;L;;;;6;N;;;;; +111E7;SINHALA ARCHAIC DIGIT SEVEN;No;0;L;;;;7;N;;;;; +111E8;SINHALA ARCHAIC DIGIT EIGHT;No;0;L;;;;8;N;;;;; +111E9;SINHALA ARCHAIC DIGIT NINE;No;0;L;;;;9;N;;;;; +111EA;SINHALA ARCHAIC NUMBER TEN;No;0;L;;;;10;N;;;;; +111EB;SINHALA ARCHAIC NUMBER TWENTY;No;0;L;;;;20;N;;;;; +111EC;SINHALA ARCHAIC NUMBER THIRTY;No;0;L;;;;30;N;;;;; +111ED;SINHALA ARCHAIC NUMBER FORTY;No;0;L;;;;40;N;;;;; +111EE;SINHALA ARCHAIC NUMBER FIFTY;No;0;L;;;;50;N;;;;; +111EF;SINHALA ARCHAIC NUMBER SIXTY;No;0;L;;;;60;N;;;;; +111F0;SINHALA ARCHAIC NUMBER SEVENTY;No;0;L;;;;70;N;;;;; +111F1;SINHALA ARCHAIC NUMBER EIGHTY;No;0;L;;;;80;N;;;;; +111F2;SINHALA ARCHAIC NUMBER NINETY;No;0;L;;;;90;N;;;;; +111F3;SINHALA ARCHAIC NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;; +111F4;SINHALA ARCHAIC NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;; +11200;KHOJKI LETTER A;Lo;0;L;;;;;N;;;;; +11201;KHOJKI LETTER AA;Lo;0;L;;;;;N;;;;; +11202;KHOJKI LETTER I;Lo;0;L;;;;;N;;;;; +11203;KHOJKI LETTER U;Lo;0;L;;;;;N;;;;; +11204;KHOJKI LETTER E;Lo;0;L;;;;;N;;;;; +11205;KHOJKI LETTER AI;Lo;0;L;;;;;N;;;;; +11206;KHOJKI LETTER O;Lo;0;L;;;;;N;;;;; +11207;KHOJKI LETTER AU;Lo;0;L;;;;;N;;;;; +11208;KHOJKI LETTER KA;Lo;0;L;;;;;N;;;;; +11209;KHOJKI LETTER KHA;Lo;0;L;;;;;N;;;;; +1120A;KHOJKI LETTER GA;Lo;0;L;;;;;N;;;;; +1120B;KHOJKI LETTER GGA;Lo;0;L;;;;;N;;;;; +1120C;KHOJKI LETTER GHA;Lo;0;L;;;;;N;;;;; +1120D;KHOJKI LETTER NGA;Lo;0;L;;;;;N;;;;; +1120E;KHOJKI LETTER CA;Lo;0;L;;;;;N;;;;; +1120F;KHOJKI LETTER CHA;Lo;0;L;;;;;N;;;;; +11210;KHOJKI LETTER JA;Lo;0;L;;;;;N;;;;; +11211;KHOJKI LETTER JJA;Lo;0;L;;;;;N;;;;; +11213;KHOJKI LETTER NYA;Lo;0;L;;;;;N;;;;; +11214;KHOJKI LETTER TTA;Lo;0;L;;;;;N;;;;; +11215;KHOJKI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11216;KHOJKI LETTER DDA;Lo;0;L;;;;;N;;;;; +11217;KHOJKI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11218;KHOJKI LETTER NNA;Lo;0;L;;;;;N;;;;; +11219;KHOJKI LETTER TA;Lo;0;L;;;;;N;;;;; +1121A;KHOJKI LETTER THA;Lo;0;L;;;;;N;;;;; +1121B;KHOJKI LETTER DA;Lo;0;L;;;;;N;;;;; +1121C;KHOJKI LETTER DDDA;Lo;0;L;;;;;N;;;;; +1121D;KHOJKI LETTER DHA;Lo;0;L;;;;;N;;;;; +1121E;KHOJKI LETTER NA;Lo;0;L;;;;;N;;;;; +1121F;KHOJKI LETTER PA;Lo;0;L;;;;;N;;;;; +11220;KHOJKI LETTER PHA;Lo;0;L;;;;;N;;;;; +11221;KHOJKI LETTER BA;Lo;0;L;;;;;N;;;;; +11222;KHOJKI LETTER BBA;Lo;0;L;;;;;N;;;;; +11223;KHOJKI LETTER BHA;Lo;0;L;;;;;N;;;;; +11224;KHOJKI LETTER MA;Lo;0;L;;;;;N;;;;; +11225;KHOJKI LETTER YA;Lo;0;L;;;;;N;;;;; +11226;KHOJKI LETTER RA;Lo;0;L;;;;;N;;;;; +11227;KHOJKI LETTER LA;Lo;0;L;;;;;N;;;;; +11228;KHOJKI LETTER VA;Lo;0;L;;;;;N;;;;; +11229;KHOJKI LETTER SA;Lo;0;L;;;;;N;;;;; +1122A;KHOJKI LETTER HA;Lo;0;L;;;;;N;;;;; +1122B;KHOJKI LETTER LLA;Lo;0;L;;;;;N;;;;; +1122C;KHOJKI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +1122D;KHOJKI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +1122E;KHOJKI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +1122F;KHOJKI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11230;KHOJKI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11231;KHOJKI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +11232;KHOJKI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +11233;KHOJKI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +11234;KHOJKI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11235;KHOJKI SIGN VIRAMA;Mc;9;L;;;;;N;;;;; +11236;KHOJKI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +11237;KHOJKI SIGN SHADDA;Mn;0;NSM;;;;;N;;;;; +11238;KHOJKI DANDA;Po;0;L;;;;;N;;;;; +11239;KHOJKI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +1123A;KHOJKI WORD SEPARATOR;Po;0;L;;;;;N;;;;; +1123B;KHOJKI SECTION MARK;Po;0;L;;;;;N;;;;; +1123C;KHOJKI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;; +1123D;KHOJKI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +1123E;KHOJKI SIGN SUKUN;Mn;0;NSM;;;;;N;;;;; +1123F;KHOJKI LETTER QA;Lo;0;L;;;;;N;;;;; +11240;KHOJKI LETTER SHORT I;Lo;0;L;;;;;N;;;;; +11241;KHOJKI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +11280;MULTANI LETTER A;Lo;0;L;;;;;N;;;;; +11281;MULTANI LETTER I;Lo;0;L;;;;;N;;;;; +11282;MULTANI LETTER U;Lo;0;L;;;;;N;;;;; +11283;MULTANI LETTER E;Lo;0;L;;;;;N;;;;; +11284;MULTANI LETTER KA;Lo;0;L;;;;;N;;;;; +11285;MULTANI LETTER KHA;Lo;0;L;;;;;N;;;;; +11286;MULTANI LETTER GA;Lo;0;L;;;;;N;;;;; +11288;MULTANI LETTER GHA;Lo;0;L;;;;;N;;;;; +1128A;MULTANI LETTER CA;Lo;0;L;;;;;N;;;;; +1128B;MULTANI LETTER CHA;Lo;0;L;;;;;N;;;;; +1128C;MULTANI LETTER JA;Lo;0;L;;;;;N;;;;; +1128D;MULTANI LETTER JJA;Lo;0;L;;;;;N;;;;; +1128F;MULTANI LETTER NYA;Lo;0;L;;;;;N;;;;; +11290;MULTANI LETTER TTA;Lo;0;L;;;;;N;;;;; +11291;MULTANI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11292;MULTANI LETTER DDA;Lo;0;L;;;;;N;;;;; +11293;MULTANI LETTER DDDA;Lo;0;L;;;;;N;;;;; +11294;MULTANI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11295;MULTANI LETTER NNA;Lo;0;L;;;;;N;;;;; +11296;MULTANI LETTER TA;Lo;0;L;;;;;N;;;;; +11297;MULTANI LETTER THA;Lo;0;L;;;;;N;;;;; +11298;MULTANI LETTER DA;Lo;0;L;;;;;N;;;;; +11299;MULTANI LETTER DHA;Lo;0;L;;;;;N;;;;; +1129A;MULTANI LETTER NA;Lo;0;L;;;;;N;;;;; +1129B;MULTANI LETTER PA;Lo;0;L;;;;;N;;;;; +1129C;MULTANI LETTER PHA;Lo;0;L;;;;;N;;;;; +1129D;MULTANI LETTER BA;Lo;0;L;;;;;N;;;;; +1129F;MULTANI LETTER BHA;Lo;0;L;;;;;N;;;;; +112A0;MULTANI LETTER MA;Lo;0;L;;;;;N;;;;; +112A1;MULTANI LETTER YA;Lo;0;L;;;;;N;;;;; +112A2;MULTANI LETTER RA;Lo;0;L;;;;;N;;;;; +112A3;MULTANI LETTER LA;Lo;0;L;;;;;N;;;;; +112A4;MULTANI LETTER VA;Lo;0;L;;;;;N;;;;; +112A5;MULTANI LETTER SA;Lo;0;L;;;;;N;;;;; +112A6;MULTANI LETTER HA;Lo;0;L;;;;;N;;;;; +112A7;MULTANI LETTER RRA;Lo;0;L;;;;;N;;;;; +112A8;MULTANI LETTER RHA;Lo;0;L;;;;;N;;;;; +112A9;MULTANI SECTION MARK;Po;0;L;;;;;N;;;;; +112B0;KHUDAWADI LETTER A;Lo;0;L;;;;;N;;;;; +112B1;KHUDAWADI LETTER AA;Lo;0;L;;;;;N;;;;; +112B2;KHUDAWADI LETTER I;Lo;0;L;;;;;N;;;;; +112B3;KHUDAWADI LETTER II;Lo;0;L;;;;;N;;;;; +112B4;KHUDAWADI LETTER U;Lo;0;L;;;;;N;;;;; +112B5;KHUDAWADI LETTER UU;Lo;0;L;;;;;N;;;;; +112B6;KHUDAWADI LETTER E;Lo;0;L;;;;;N;;;;; +112B7;KHUDAWADI LETTER AI;Lo;0;L;;;;;N;;;;; +112B8;KHUDAWADI LETTER O;Lo;0;L;;;;;N;;;;; +112B9;KHUDAWADI LETTER AU;Lo;0;L;;;;;N;;;;; +112BA;KHUDAWADI LETTER KA;Lo;0;L;;;;;N;;;;; +112BB;KHUDAWADI LETTER KHA;Lo;0;L;;;;;N;;;;; +112BC;KHUDAWADI LETTER GA;Lo;0;L;;;;;N;;;;; +112BD;KHUDAWADI LETTER GGA;Lo;0;L;;;;;N;;;;; +112BE;KHUDAWADI LETTER GHA;Lo;0;L;;;;;N;;;;; +112BF;KHUDAWADI LETTER NGA;Lo;0;L;;;;;N;;;;; +112C0;KHUDAWADI LETTER CA;Lo;0;L;;;;;N;;;;; +112C1;KHUDAWADI LETTER CHA;Lo;0;L;;;;;N;;;;; +112C2;KHUDAWADI LETTER JA;Lo;0;L;;;;;N;;;;; +112C3;KHUDAWADI LETTER JJA;Lo;0;L;;;;;N;;;;; +112C4;KHUDAWADI LETTER JHA;Lo;0;L;;;;;N;;;;; +112C5;KHUDAWADI LETTER NYA;Lo;0;L;;;;;N;;;;; +112C6;KHUDAWADI LETTER TTA;Lo;0;L;;;;;N;;;;; +112C7;KHUDAWADI LETTER TTHA;Lo;0;L;;;;;N;;;;; +112C8;KHUDAWADI LETTER DDA;Lo;0;L;;;;;N;;;;; +112C9;KHUDAWADI LETTER DDDA;Lo;0;L;;;;;N;;;;; +112CA;KHUDAWADI LETTER RRA;Lo;0;L;;;;;N;;;;; +112CB;KHUDAWADI LETTER DDHA;Lo;0;L;;;;;N;;;;; +112CC;KHUDAWADI LETTER NNA;Lo;0;L;;;;;N;;;;; +112CD;KHUDAWADI LETTER TA;Lo;0;L;;;;;N;;;;; +112CE;KHUDAWADI LETTER THA;Lo;0;L;;;;;N;;;;; +112CF;KHUDAWADI LETTER DA;Lo;0;L;;;;;N;;;;; +112D0;KHUDAWADI LETTER DHA;Lo;0;L;;;;;N;;;;; +112D1;KHUDAWADI LETTER NA;Lo;0;L;;;;;N;;;;; +112D2;KHUDAWADI LETTER PA;Lo;0;L;;;;;N;;;;; +112D3;KHUDAWADI LETTER PHA;Lo;0;L;;;;;N;;;;; +112D4;KHUDAWADI LETTER BA;Lo;0;L;;;;;N;;;;; +112D5;KHUDAWADI LETTER BBA;Lo;0;L;;;;;N;;;;; +112D6;KHUDAWADI LETTER BHA;Lo;0;L;;;;;N;;;;; +112D7;KHUDAWADI LETTER MA;Lo;0;L;;;;;N;;;;; +112D8;KHUDAWADI LETTER YA;Lo;0;L;;;;;N;;;;; +112D9;KHUDAWADI LETTER RA;Lo;0;L;;;;;N;;;;; +112DA;KHUDAWADI LETTER LA;Lo;0;L;;;;;N;;;;; +112DB;KHUDAWADI LETTER VA;Lo;0;L;;;;;N;;;;; +112DC;KHUDAWADI LETTER SHA;Lo;0;L;;;;;N;;;;; +112DD;KHUDAWADI LETTER SA;Lo;0;L;;;;;N;;;;; +112DE;KHUDAWADI LETTER HA;Lo;0;L;;;;;N;;;;; +112DF;KHUDAWADI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +112E0;KHUDAWADI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +112E1;KHUDAWADI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +112E2;KHUDAWADI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +112E3;KHUDAWADI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +112E4;KHUDAWADI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +112E5;KHUDAWADI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +112E6;KHUDAWADI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +112E7;KHUDAWADI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +112E8;KHUDAWADI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +112E9;KHUDAWADI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +112EA;KHUDAWADI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +112F0;KHUDAWADI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +112F1;KHUDAWADI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +112F2;KHUDAWADI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +112F3;KHUDAWADI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +112F4;KHUDAWADI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +112F5;KHUDAWADI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +112F6;KHUDAWADI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +112F7;KHUDAWADI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +112F8;KHUDAWADI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +112F9;KHUDAWADI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11300;GRANTHA SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;; +11301;GRANTHA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11302;GRANTHA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +11303;GRANTHA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11305;GRANTHA LETTER A;Lo;0;L;;;;;N;;;;; +11306;GRANTHA LETTER AA;Lo;0;L;;;;;N;;;;; +11307;GRANTHA LETTER I;Lo;0;L;;;;;N;;;;; +11308;GRANTHA LETTER II;Lo;0;L;;;;;N;;;;; +11309;GRANTHA LETTER U;Lo;0;L;;;;;N;;;;; +1130A;GRANTHA LETTER UU;Lo;0;L;;;;;N;;;;; +1130B;GRANTHA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +1130C;GRANTHA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +1130F;GRANTHA LETTER EE;Lo;0;L;;;;;N;;;;; +11310;GRANTHA LETTER AI;Lo;0;L;;;;;N;;;;; +11313;GRANTHA LETTER OO;Lo;0;L;;;;;N;;;;; +11314;GRANTHA LETTER AU;Lo;0;L;;;;;N;;;;; +11315;GRANTHA LETTER KA;Lo;0;L;;;;;N;;;;; +11316;GRANTHA LETTER KHA;Lo;0;L;;;;;N;;;;; +11317;GRANTHA LETTER GA;Lo;0;L;;;;;N;;;;; +11318;GRANTHA LETTER GHA;Lo;0;L;;;;;N;;;;; +11319;GRANTHA LETTER NGA;Lo;0;L;;;;;N;;;;; +1131A;GRANTHA LETTER CA;Lo;0;L;;;;;N;;;;; +1131B;GRANTHA LETTER CHA;Lo;0;L;;;;;N;;;;; +1131C;GRANTHA LETTER JA;Lo;0;L;;;;;N;;;;; +1131D;GRANTHA LETTER JHA;Lo;0;L;;;;;N;;;;; +1131E;GRANTHA LETTER NYA;Lo;0;L;;;;;N;;;;; +1131F;GRANTHA LETTER TTA;Lo;0;L;;;;;N;;;;; +11320;GRANTHA LETTER TTHA;Lo;0;L;;;;;N;;;;; +11321;GRANTHA LETTER DDA;Lo;0;L;;;;;N;;;;; +11322;GRANTHA LETTER DDHA;Lo;0;L;;;;;N;;;;; +11323;GRANTHA LETTER NNA;Lo;0;L;;;;;N;;;;; +11324;GRANTHA LETTER TA;Lo;0;L;;;;;N;;;;; +11325;GRANTHA LETTER THA;Lo;0;L;;;;;N;;;;; +11326;GRANTHA LETTER DA;Lo;0;L;;;;;N;;;;; +11327;GRANTHA LETTER DHA;Lo;0;L;;;;;N;;;;; +11328;GRANTHA LETTER NA;Lo;0;L;;;;;N;;;;; +1132A;GRANTHA LETTER PA;Lo;0;L;;;;;N;;;;; +1132B;GRANTHA LETTER PHA;Lo;0;L;;;;;N;;;;; +1132C;GRANTHA LETTER BA;Lo;0;L;;;;;N;;;;; +1132D;GRANTHA LETTER BHA;Lo;0;L;;;;;N;;;;; +1132E;GRANTHA LETTER MA;Lo;0;L;;;;;N;;;;; +1132F;GRANTHA LETTER YA;Lo;0;L;;;;;N;;;;; +11330;GRANTHA LETTER RA;Lo;0;L;;;;;N;;;;; +11332;GRANTHA LETTER LA;Lo;0;L;;;;;N;;;;; +11333;GRANTHA LETTER LLA;Lo;0;L;;;;;N;;;;; +11335;GRANTHA LETTER VA;Lo;0;L;;;;;N;;;;; +11336;GRANTHA LETTER SHA;Lo;0;L;;;;;N;;;;; +11337;GRANTHA LETTER SSA;Lo;0;L;;;;;N;;;;; +11338;GRANTHA LETTER SA;Lo;0;L;;;;;N;;;;; +11339;GRANTHA LETTER HA;Lo;0;L;;;;;N;;;;; +1133B;COMBINING BINDU BELOW;Mn;7;NSM;;;;;N;;;;; +1133C;GRANTHA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +1133D;GRANTHA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +1133E;GRANTHA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +1133F;GRANTHA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +11340;GRANTHA VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +11341;GRANTHA VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +11342;GRANTHA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +11343;GRANTHA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; +11344;GRANTHA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; +11347;GRANTHA VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; +11348;GRANTHA VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +1134B;GRANTHA VOWEL SIGN OO;Mc;0;L;11347 1133E;;;;N;;;;; +1134C;GRANTHA VOWEL SIGN AU;Mc;0;L;11347 11357;;;;N;;;;; +1134D;GRANTHA SIGN VIRAMA;Mc;9;L;;;;;N;;;;; +11350;GRANTHA OM;Lo;0;L;;;;;N;;;;; +11357;GRANTHA AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +1135D;GRANTHA SIGN PLUTA;Lo;0;L;;;;;N;;;;; +1135E;GRANTHA LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;; +1135F;GRANTHA LETTER VEDIC DOUBLE ANUSVARA;Lo;0;L;;;;;N;;;;; +11360;GRANTHA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11361;GRANTHA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +11362;GRANTHA VOWEL SIGN VOCALIC L;Mc;0;L;;;;;N;;;;; +11363;GRANTHA VOWEL SIGN VOCALIC LL;Mc;0;L;;;;;N;;;;; +11366;COMBINING GRANTHA DIGIT ZERO;Mn;230;NSM;;;;;N;;;;; +11367;COMBINING GRANTHA DIGIT ONE;Mn;230;NSM;;;;;N;;;;; +11368;COMBINING GRANTHA DIGIT TWO;Mn;230;NSM;;;;;N;;;;; +11369;COMBINING GRANTHA DIGIT THREE;Mn;230;NSM;;;;;N;;;;; +1136A;COMBINING GRANTHA DIGIT FOUR;Mn;230;NSM;;;;;N;;;;; +1136B;COMBINING GRANTHA DIGIT FIVE;Mn;230;NSM;;;;;N;;;;; +1136C;COMBINING GRANTHA DIGIT SIX;Mn;230;NSM;;;;;N;;;;; +11370;COMBINING GRANTHA LETTER A;Mn;230;NSM;;;;;N;;;;; +11371;COMBINING GRANTHA LETTER KA;Mn;230;NSM;;;;;N;;;;; +11372;COMBINING GRANTHA LETTER NA;Mn;230;NSM;;;;;N;;;;; +11373;COMBINING GRANTHA LETTER VI;Mn;230;NSM;;;;;N;;;;; +11374;COMBINING GRANTHA LETTER PA;Mn;230;NSM;;;;;N;;;;; +11380;TULU-TIGALARI LETTER A;Lo;0;L;;;;;N;;;;; +11381;TULU-TIGALARI LETTER AA;Lo;0;L;;;;;N;;;;; +11382;TULU-TIGALARI LETTER I;Lo;0;L;;;;;N;;;;; +11383;TULU-TIGALARI LETTER II;Lo;0;L;11382 113C9;;;;N;;;;; +11384;TULU-TIGALARI LETTER U;Lo;0;L;;;;;N;;;;; +11385;TULU-TIGALARI LETTER UU;Lo;0;L;11384 113BB;;;;N;;;;; +11386;TULU-TIGALARI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +11387;TULU-TIGALARI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11388;TULU-TIGALARI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +11389;TULU-TIGALARI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1138B;TULU-TIGALARI LETTER EE;Lo;0;L;;;;;N;;;;; +1138E;TULU-TIGALARI LETTER AI;Lo;0;L;1138B 113C2;;;;N;;;;; +11390;TULU-TIGALARI LETTER OO;Lo;0;L;;;;;N;;;;; +11391;TULU-TIGALARI LETTER AU;Lo;0;L;11390 113C9;;;;N;;;;; +11392;TULU-TIGALARI LETTER KA;Lo;0;L;;;;;N;;;;; +11393;TULU-TIGALARI LETTER KHA;Lo;0;L;;;;;N;;;;; +11394;TULU-TIGALARI LETTER GA;Lo;0;L;;;;;N;;;;; +11395;TULU-TIGALARI LETTER GHA;Lo;0;L;;;;;N;;;;; +11396;TULU-TIGALARI LETTER NGA;Lo;0;L;;;;;N;;;;; +11397;TULU-TIGALARI LETTER CA;Lo;0;L;;;;;N;;;;; +11398;TULU-TIGALARI LETTER CHA;Lo;0;L;;;;;N;;;;; +11399;TULU-TIGALARI LETTER JA;Lo;0;L;;;;;N;;;;; +1139A;TULU-TIGALARI LETTER JHA;Lo;0;L;;;;;N;;;;; +1139B;TULU-TIGALARI LETTER NYA;Lo;0;L;;;;;N;;;;; +1139C;TULU-TIGALARI LETTER TTA;Lo;0;L;;;;;N;;;;; +1139D;TULU-TIGALARI LETTER TTHA;Lo;0;L;;;;;N;;;;; +1139E;TULU-TIGALARI LETTER DDA;Lo;0;L;;;;;N;;;;; +1139F;TULU-TIGALARI LETTER DDHA;Lo;0;L;;;;;N;;;;; +113A0;TULU-TIGALARI LETTER NNA;Lo;0;L;;;;;N;;;;; +113A1;TULU-TIGALARI LETTER TA;Lo;0;L;;;;;N;;;;; +113A2;TULU-TIGALARI LETTER THA;Lo;0;L;;;;;N;;;;; +113A3;TULU-TIGALARI LETTER DA;Lo;0;L;;;;;N;;;;; +113A4;TULU-TIGALARI LETTER DHA;Lo;0;L;;;;;N;;;;; +113A5;TULU-TIGALARI LETTER NA;Lo;0;L;;;;;N;;;;; +113A6;TULU-TIGALARI LETTER PA;Lo;0;L;;;;;N;;;;; +113A7;TULU-TIGALARI LETTER PHA;Lo;0;L;;;;;N;;;;; +113A8;TULU-TIGALARI LETTER BA;Lo;0;L;;;;;N;;;;; +113A9;TULU-TIGALARI LETTER BHA;Lo;0;L;;;;;N;;;;; +113AA;TULU-TIGALARI LETTER MA;Lo;0;L;;;;;N;;;;; +113AB;TULU-TIGALARI LETTER YA;Lo;0;L;;;;;N;;;;; +113AC;TULU-TIGALARI LETTER RA;Lo;0;L;;;;;N;;;;; +113AD;TULU-TIGALARI LETTER LA;Lo;0;L;;;;;N;;;;; +113AE;TULU-TIGALARI LETTER VA;Lo;0;L;;;;;N;;;;; +113AF;TULU-TIGALARI LETTER SHA;Lo;0;L;;;;;N;;;;; +113B0;TULU-TIGALARI LETTER SSA;Lo;0;L;;;;;N;;;;; +113B1;TULU-TIGALARI LETTER SA;Lo;0;L;;;;;N;;;;; +113B2;TULU-TIGALARI LETTER HA;Lo;0;L;;;;;N;;;;; +113B3;TULU-TIGALARI LETTER LLA;Lo;0;L;;;;;N;;;;; +113B4;TULU-TIGALARI LETTER RRA;Lo;0;L;;;;;N;;;;; +113B5;TULU-TIGALARI LETTER LLLA;Lo;0;L;;;;;N;;;;; +113B7;TULU-TIGALARI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +113B8;TULU-TIGALARI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +113B9;TULU-TIGALARI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +113BA;TULU-TIGALARI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +113BB;TULU-TIGALARI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +113BC;TULU-TIGALARI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +113BD;TULU-TIGALARI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +113BE;TULU-TIGALARI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +113BF;TULU-TIGALARI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +113C0;TULU-TIGALARI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +113C2;TULU-TIGALARI VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; +113C5;TULU-TIGALARI VOWEL SIGN AI;Mc;0;L;113C2 113C2;;;;N;;;;; +113C7;TULU-TIGALARI VOWEL SIGN OO;Mc;0;L;113C2 113B8;;;;N;;;;; +113C8;TULU-TIGALARI VOWEL SIGN AU;Mc;0;L;113C2 113C9;;;;N;;;;; +113C9;TULU-TIGALARI AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +113CA;TULU-TIGALARI SIGN CANDRA ANUNASIKA;Mc;0;L;;;;;N;;;;; +113CC;TULU-TIGALARI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +113CD;TULU-TIGALARI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +113CE;TULU-TIGALARI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +113CF;TULU-TIGALARI SIGN LOOPED VIRAMA;Mc;9;L;;;;;N;;;;; +113D0;TULU-TIGALARI CONJOINER;Mn;9;NSM;;;;;N;;;;; +113D1;TULU-TIGALARI REPHA;Lo;0;L;;;;;N;;;;; +113D2;TULU-TIGALARI GEMINATION MARK;Mn;0;NSM;;;;;N;;;;; +113D3;TULU-TIGALARI SIGN PLUTA;Lo;0;L;;;;;N;;;;; +113D4;TULU-TIGALARI DANDA;Po;0;L;;;;;N;;;;; +113D5;TULU-TIGALARI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +113D7;TULU-TIGALARI SIGN OM PUSHPIKA;Po;0;L;;;;;N;;;;; +113D8;TULU-TIGALARI SIGN SHRII PUSHPIKA;Po;0;L;;;;;N;;;;; +113E1;TULU-TIGALARI VEDIC TONE SVARITA;Mn;0;NSM;;;;;N;;;;; +113E2;TULU-TIGALARI VEDIC TONE ANUDATTA;Mn;0;NSM;;;;;N;;;;; +11400;NEWA LETTER A;Lo;0;L;;;;;N;;;;; +11401;NEWA LETTER AA;Lo;0;L;;;;;N;;;;; +11402;NEWA LETTER I;Lo;0;L;;;;;N;;;;; +11403;NEWA LETTER II;Lo;0;L;;;;;N;;;;; +11404;NEWA LETTER U;Lo;0;L;;;;;N;;;;; +11405;NEWA LETTER UU;Lo;0;L;;;;;N;;;;; +11406;NEWA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +11407;NEWA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11408;NEWA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +11409;NEWA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1140A;NEWA LETTER E;Lo;0;L;;;;;N;;;;; +1140B;NEWA LETTER AI;Lo;0;L;;;;;N;;;;; +1140C;NEWA LETTER O;Lo;0;L;;;;;N;;;;; +1140D;NEWA LETTER AU;Lo;0;L;;;;;N;;;;; +1140E;NEWA LETTER KA;Lo;0;L;;;;;N;;;;; +1140F;NEWA LETTER KHA;Lo;0;L;;;;;N;;;;; +11410;NEWA LETTER GA;Lo;0;L;;;;;N;;;;; +11411;NEWA LETTER GHA;Lo;0;L;;;;;N;;;;; +11412;NEWA LETTER NGA;Lo;0;L;;;;;N;;;;; +11413;NEWA LETTER NGHA;Lo;0;L;;;;;N;;;;; +11414;NEWA LETTER CA;Lo;0;L;;;;;N;;;;; +11415;NEWA LETTER CHA;Lo;0;L;;;;;N;;;;; +11416;NEWA LETTER JA;Lo;0;L;;;;;N;;;;; +11417;NEWA LETTER JHA;Lo;0;L;;;;;N;;;;; +11418;NEWA LETTER NYA;Lo;0;L;;;;;N;;;;; +11419;NEWA LETTER NYHA;Lo;0;L;;;;;N;;;;; +1141A;NEWA LETTER TTA;Lo;0;L;;;;;N;;;;; +1141B;NEWA LETTER TTHA;Lo;0;L;;;;;N;;;;; +1141C;NEWA LETTER DDA;Lo;0;L;;;;;N;;;;; +1141D;NEWA LETTER DDHA;Lo;0;L;;;;;N;;;;; +1141E;NEWA LETTER NNA;Lo;0;L;;;;;N;;;;; +1141F;NEWA LETTER TA;Lo;0;L;;;;;N;;;;; +11420;NEWA LETTER THA;Lo;0;L;;;;;N;;;;; +11421;NEWA LETTER DA;Lo;0;L;;;;;N;;;;; +11422;NEWA LETTER DHA;Lo;0;L;;;;;N;;;;; +11423;NEWA LETTER NA;Lo;0;L;;;;;N;;;;; +11424;NEWA LETTER NHA;Lo;0;L;;;;;N;;;;; +11425;NEWA LETTER PA;Lo;0;L;;;;;N;;;;; +11426;NEWA LETTER PHA;Lo;0;L;;;;;N;;;;; +11427;NEWA LETTER BA;Lo;0;L;;;;;N;;;;; +11428;NEWA LETTER BHA;Lo;0;L;;;;;N;;;;; +11429;NEWA LETTER MA;Lo;0;L;;;;;N;;;;; +1142A;NEWA LETTER MHA;Lo;0;L;;;;;N;;;;; +1142B;NEWA LETTER YA;Lo;0;L;;;;;N;;;;; +1142C;NEWA LETTER RA;Lo;0;L;;;;;N;;;;; +1142D;NEWA LETTER RHA;Lo;0;L;;;;;N;;;;; +1142E;NEWA LETTER LA;Lo;0;L;;;;;N;;;;; +1142F;NEWA LETTER LHA;Lo;0;L;;;;;N;;;;; +11430;NEWA LETTER WA;Lo;0;L;;;;;N;;;;; +11431;NEWA LETTER SHA;Lo;0;L;;;;;N;;;;; +11432;NEWA LETTER SSA;Lo;0;L;;;;;N;;;;; +11433;NEWA LETTER SA;Lo;0;L;;;;;N;;;;; +11434;NEWA LETTER HA;Lo;0;L;;;;;N;;;;; +11435;NEWA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11436;NEWA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +11437;NEWA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +11438;NEWA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11439;NEWA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +1143A;NEWA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +1143B;NEWA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +1143C;NEWA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +1143D;NEWA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +1143E;NEWA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +1143F;NEWA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +11440;NEWA VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +11441;NEWA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +11442;NEWA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +11443;NEWA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11444;NEWA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11445;NEWA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11446;NEWA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +11447;NEWA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +11448;NEWA SIGN FINAL ANUSVARA;Lo;0;L;;;;;N;;;;; +11449;NEWA OM;Lo;0;L;;;;;N;;;;; +1144A;NEWA SIDDHI;Lo;0;L;;;;;N;;;;; +1144B;NEWA DANDA;Po;0;L;;;;;N;;;;; +1144C;NEWA DOUBLE DANDA;Po;0;L;;;;;N;;;;; +1144D;NEWA COMMA;Po;0;L;;;;;N;;;;; +1144E;NEWA GAP FILLER;Po;0;L;;;;;N;;;;; +1144F;NEWA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +11450;NEWA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11451;NEWA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11452;NEWA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11453;NEWA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11454;NEWA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11455;NEWA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11456;NEWA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11457;NEWA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11458;NEWA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11459;NEWA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1145A;NEWA DOUBLE COMMA;Po;0;L;;;;;N;;;;; +1145B;NEWA PLACEHOLDER MARK;Po;0;L;;;;;N;;;;; +1145D;NEWA INSERTION SIGN;Po;0;L;;;;;N;;;;; +1145E;NEWA SANDHI MARK;Mn;230;NSM;;;;;N;;;;; +1145F;NEWA LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;; +11460;NEWA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; +11461;NEWA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; +11480;TIRHUTA ANJI;Lo;0;L;;;;;N;;;;; +11481;TIRHUTA LETTER A;Lo;0;L;;;;;N;;;;; +11482;TIRHUTA LETTER AA;Lo;0;L;;;;;N;;;;; +11483;TIRHUTA LETTER I;Lo;0;L;;;;;N;;;;; +11484;TIRHUTA LETTER II;Lo;0;L;;;;;N;;;;; +11485;TIRHUTA LETTER U;Lo;0;L;;;;;N;;;;; +11486;TIRHUTA LETTER UU;Lo;0;L;;;;;N;;;;; +11487;TIRHUTA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +11488;TIRHUTA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11489;TIRHUTA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +1148A;TIRHUTA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1148B;TIRHUTA LETTER E;Lo;0;L;;;;;N;;;;; +1148C;TIRHUTA LETTER AI;Lo;0;L;;;;;N;;;;; +1148D;TIRHUTA LETTER O;Lo;0;L;;;;;N;;;;; +1148E;TIRHUTA LETTER AU;Lo;0;L;;;;;N;;;;; +1148F;TIRHUTA LETTER KA;Lo;0;L;;;;;N;;;;; +11490;TIRHUTA LETTER KHA;Lo;0;L;;;;;N;;;;; +11491;TIRHUTA LETTER GA;Lo;0;L;;;;;N;;;;; +11492;TIRHUTA LETTER GHA;Lo;0;L;;;;;N;;;;; +11493;TIRHUTA LETTER NGA;Lo;0;L;;;;;N;;;;; +11494;TIRHUTA LETTER CA;Lo;0;L;;;;;N;;;;; +11495;TIRHUTA LETTER CHA;Lo;0;L;;;;;N;;;;; +11496;TIRHUTA LETTER JA;Lo;0;L;;;;;N;;;;; +11497;TIRHUTA LETTER JHA;Lo;0;L;;;;;N;;;;; +11498;TIRHUTA LETTER NYA;Lo;0;L;;;;;N;;;;; +11499;TIRHUTA LETTER TTA;Lo;0;L;;;;;N;;;;; +1149A;TIRHUTA LETTER TTHA;Lo;0;L;;;;;N;;;;; +1149B;TIRHUTA LETTER DDA;Lo;0;L;;;;;N;;;;; +1149C;TIRHUTA LETTER DDHA;Lo;0;L;;;;;N;;;;; +1149D;TIRHUTA LETTER NNA;Lo;0;L;;;;;N;;;;; +1149E;TIRHUTA LETTER TA;Lo;0;L;;;;;N;;;;; +1149F;TIRHUTA LETTER THA;Lo;0;L;;;;;N;;;;; +114A0;TIRHUTA LETTER DA;Lo;0;L;;;;;N;;;;; +114A1;TIRHUTA LETTER DHA;Lo;0;L;;;;;N;;;;; +114A2;TIRHUTA LETTER NA;Lo;0;L;;;;;N;;;;; +114A3;TIRHUTA LETTER PA;Lo;0;L;;;;;N;;;;; +114A4;TIRHUTA LETTER PHA;Lo;0;L;;;;;N;;;;; +114A5;TIRHUTA LETTER BA;Lo;0;L;;;;;N;;;;; +114A6;TIRHUTA LETTER BHA;Lo;0;L;;;;;N;;;;; +114A7;TIRHUTA LETTER MA;Lo;0;L;;;;;N;;;;; +114A8;TIRHUTA LETTER YA;Lo;0;L;;;;;N;;;;; +114A9;TIRHUTA LETTER RA;Lo;0;L;;;;;N;;;;; +114AA;TIRHUTA LETTER LA;Lo;0;L;;;;;N;;;;; +114AB;TIRHUTA LETTER VA;Lo;0;L;;;;;N;;;;; +114AC;TIRHUTA LETTER SHA;Lo;0;L;;;;;N;;;;; +114AD;TIRHUTA LETTER SSA;Lo;0;L;;;;;N;;;;; +114AE;TIRHUTA LETTER SA;Lo;0;L;;;;;N;;;;; +114AF;TIRHUTA LETTER HA;Lo;0;L;;;;;N;;;;; +114B0;TIRHUTA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +114B1;TIRHUTA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +114B2;TIRHUTA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +114B3;TIRHUTA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +114B4;TIRHUTA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +114B5;TIRHUTA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +114B6;TIRHUTA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +114B7;TIRHUTA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +114B8;TIRHUTA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +114B9;TIRHUTA VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +114BA;TIRHUTA VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;; +114BB;TIRHUTA VOWEL SIGN AI;Mc;0;L;114B9 114BA;;;;N;;;;; +114BC;TIRHUTA VOWEL SIGN O;Mc;0;L;114B9 114B0;;;;N;;;;; +114BD;TIRHUTA VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;; +114BE;TIRHUTA VOWEL SIGN AU;Mc;0;L;114B9 114BD;;;;N;;;;; +114BF;TIRHUTA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +114C0;TIRHUTA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +114C1;TIRHUTA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +114C2;TIRHUTA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +114C3;TIRHUTA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +114C4;TIRHUTA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +114C5;TIRHUTA GVANG;Lo;0;L;;;;;N;;;;; +114C6;TIRHUTA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +114C7;TIRHUTA OM;Lo;0;L;;;;;N;;;;; +114D0;TIRHUTA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +114D1;TIRHUTA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +114D2;TIRHUTA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +114D3;TIRHUTA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +114D4;TIRHUTA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +114D5;TIRHUTA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +114D6;TIRHUTA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +114D7;TIRHUTA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +114D8;TIRHUTA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +114D9;TIRHUTA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11580;SIDDHAM LETTER A;Lo;0;L;;;;;N;;;;; +11581;SIDDHAM LETTER AA;Lo;0;L;;;;;N;;;;; +11582;SIDDHAM LETTER I;Lo;0;L;;;;;N;;;;; +11583;SIDDHAM LETTER II;Lo;0;L;;;;;N;;;;; +11584;SIDDHAM LETTER U;Lo;0;L;;;;;N;;;;; +11585;SIDDHAM LETTER UU;Lo;0;L;;;;;N;;;;; +11586;SIDDHAM LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +11587;SIDDHAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11588;SIDDHAM LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +11589;SIDDHAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1158A;SIDDHAM LETTER E;Lo;0;L;;;;;N;;;;; +1158B;SIDDHAM LETTER AI;Lo;0;L;;;;;N;;;;; +1158C;SIDDHAM LETTER O;Lo;0;L;;;;;N;;;;; +1158D;SIDDHAM LETTER AU;Lo;0;L;;;;;N;;;;; +1158E;SIDDHAM LETTER KA;Lo;0;L;;;;;N;;;;; +1158F;SIDDHAM LETTER KHA;Lo;0;L;;;;;N;;;;; +11590;SIDDHAM LETTER GA;Lo;0;L;;;;;N;;;;; +11591;SIDDHAM LETTER GHA;Lo;0;L;;;;;N;;;;; +11592;SIDDHAM LETTER NGA;Lo;0;L;;;;;N;;;;; +11593;SIDDHAM LETTER CA;Lo;0;L;;;;;N;;;;; +11594;SIDDHAM LETTER CHA;Lo;0;L;;;;;N;;;;; +11595;SIDDHAM LETTER JA;Lo;0;L;;;;;N;;;;; +11596;SIDDHAM LETTER JHA;Lo;0;L;;;;;N;;;;; +11597;SIDDHAM LETTER NYA;Lo;0;L;;;;;N;;;;; +11598;SIDDHAM LETTER TTA;Lo;0;L;;;;;N;;;;; +11599;SIDDHAM LETTER TTHA;Lo;0;L;;;;;N;;;;; +1159A;SIDDHAM LETTER DDA;Lo;0;L;;;;;N;;;;; +1159B;SIDDHAM LETTER DDHA;Lo;0;L;;;;;N;;;;; +1159C;SIDDHAM LETTER NNA;Lo;0;L;;;;;N;;;;; +1159D;SIDDHAM LETTER TA;Lo;0;L;;;;;N;;;;; +1159E;SIDDHAM LETTER THA;Lo;0;L;;;;;N;;;;; +1159F;SIDDHAM LETTER DA;Lo;0;L;;;;;N;;;;; +115A0;SIDDHAM LETTER DHA;Lo;0;L;;;;;N;;;;; +115A1;SIDDHAM LETTER NA;Lo;0;L;;;;;N;;;;; +115A2;SIDDHAM LETTER PA;Lo;0;L;;;;;N;;;;; +115A3;SIDDHAM LETTER PHA;Lo;0;L;;;;;N;;;;; +115A4;SIDDHAM LETTER BA;Lo;0;L;;;;;N;;;;; +115A5;SIDDHAM LETTER BHA;Lo;0;L;;;;;N;;;;; +115A6;SIDDHAM LETTER MA;Lo;0;L;;;;;N;;;;; +115A7;SIDDHAM LETTER YA;Lo;0;L;;;;;N;;;;; +115A8;SIDDHAM LETTER RA;Lo;0;L;;;;;N;;;;; +115A9;SIDDHAM LETTER LA;Lo;0;L;;;;;N;;;;; +115AA;SIDDHAM LETTER VA;Lo;0;L;;;;;N;;;;; +115AB;SIDDHAM LETTER SHA;Lo;0;L;;;;;N;;;;; +115AC;SIDDHAM LETTER SSA;Lo;0;L;;;;;N;;;;; +115AD;SIDDHAM LETTER SA;Lo;0;L;;;;;N;;;;; +115AE;SIDDHAM LETTER HA;Lo;0;L;;;;;N;;;;; +115AF;SIDDHAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +115B0;SIDDHAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +115B1;SIDDHAM VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +115B2;SIDDHAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +115B3;SIDDHAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +115B4;SIDDHAM VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +115B5;SIDDHAM VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +115B8;SIDDHAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +115B9;SIDDHAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +115BA;SIDDHAM VOWEL SIGN O;Mc;0;L;115B8 115AF;;;;N;;;;; +115BB;SIDDHAM VOWEL SIGN AU;Mc;0;L;115B9 115AF;;;;N;;;;; +115BC;SIDDHAM SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +115BD;SIDDHAM SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +115BE;SIDDHAM SIGN VISARGA;Mc;0;L;;;;;N;;;;; +115BF;SIDDHAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +115C0;SIDDHAM SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +115C1;SIDDHAM SIGN SIDDHAM;Po;0;L;;;;;N;;;;; +115C2;SIDDHAM DANDA;Po;0;L;;;;;N;;;;; +115C3;SIDDHAM DOUBLE DANDA;Po;0;L;;;;;N;;;;; +115C4;SIDDHAM SEPARATOR DOT;Po;0;L;;;;;N;;;;; +115C5;SIDDHAM SEPARATOR BAR;Po;0;L;;;;;N;;;;; +115C6;SIDDHAM REPETITION MARK-1;Po;0;L;;;;;N;;;;; +115C7;SIDDHAM REPETITION MARK-2;Po;0;L;;;;;N;;;;; +115C8;SIDDHAM REPETITION MARK-3;Po;0;L;;;;;N;;;;; +115C9;SIDDHAM END OF TEXT MARK;Po;0;L;;;;;N;;;;; +115CA;SIDDHAM SECTION MARK WITH TRIDENT AND U-SHAPED ORNAMENTS;Po;0;L;;;;;N;;;;; +115CB;SIDDHAM SECTION MARK WITH TRIDENT AND DOTTED CRESCENTS;Po;0;L;;;;;N;;;;; +115CC;SIDDHAM SECTION MARK WITH RAYS AND DOTTED CRESCENTS;Po;0;L;;;;;N;;;;; +115CD;SIDDHAM SECTION MARK WITH RAYS AND DOTTED DOUBLE CRESCENTS;Po;0;L;;;;;N;;;;; +115CE;SIDDHAM SECTION MARK WITH RAYS AND DOTTED TRIPLE CRESCENTS;Po;0;L;;;;;N;;;;; +115CF;SIDDHAM SECTION MARK DOUBLE RING;Po;0;L;;;;;N;;;;; +115D0;SIDDHAM SECTION MARK DOUBLE RING WITH RAYS;Po;0;L;;;;;N;;;;; +115D1;SIDDHAM SECTION MARK WITH DOUBLE CRESCENTS;Po;0;L;;;;;N;;;;; +115D2;SIDDHAM SECTION MARK WITH TRIPLE CRESCENTS;Po;0;L;;;;;N;;;;; +115D3;SIDDHAM SECTION MARK WITH QUADRUPLE CRESCENTS;Po;0;L;;;;;N;;;;; +115D4;SIDDHAM SECTION MARK WITH SEPTUPLE CRESCENTS;Po;0;L;;;;;N;;;;; +115D5;SIDDHAM SECTION MARK WITH CIRCLES AND RAYS;Po;0;L;;;;;N;;;;; +115D6;SIDDHAM SECTION MARK WITH CIRCLES AND TWO ENCLOSURES;Po;0;L;;;;;N;;;;; +115D7;SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES;Po;0;L;;;;;N;;;;; +115D8;SIDDHAM LETTER THREE-CIRCLE ALTERNATE I;Lo;0;L;;;;;N;;;;; +115D9;SIDDHAM LETTER TWO-CIRCLE ALTERNATE I;Lo;0;L;;;;;N;;;;; +115DA;SIDDHAM LETTER TWO-CIRCLE ALTERNATE II;Lo;0;L;;;;;N;;;;; +115DB;SIDDHAM LETTER ALTERNATE U;Lo;0;L;;;;;N;;;;; +115DC;SIDDHAM VOWEL SIGN ALTERNATE U;Mn;0;NSM;;;;;N;;;;; +115DD;SIDDHAM VOWEL SIGN ALTERNATE UU;Mn;0;NSM;;;;;N;;;;; +11600;MODI LETTER A;Lo;0;L;;;;;N;;;;; +11601;MODI LETTER AA;Lo;0;L;;;;;N;;;;; +11602;MODI LETTER I;Lo;0;L;;;;;N;;;;; +11603;MODI LETTER II;Lo;0;L;;;;;N;;;;; +11604;MODI LETTER U;Lo;0;L;;;;;N;;;;; +11605;MODI LETTER UU;Lo;0;L;;;;;N;;;;; +11606;MODI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +11607;MODI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11608;MODI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +11609;MODI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1160A;MODI LETTER E;Lo;0;L;;;;;N;;;;; +1160B;MODI LETTER AI;Lo;0;L;;;;;N;;;;; +1160C;MODI LETTER O;Lo;0;L;;;;;N;;;;; +1160D;MODI LETTER AU;Lo;0;L;;;;;N;;;;; +1160E;MODI LETTER KA;Lo;0;L;;;;;N;;;;; +1160F;MODI LETTER KHA;Lo;0;L;;;;;N;;;;; +11610;MODI LETTER GA;Lo;0;L;;;;;N;;;;; +11611;MODI LETTER GHA;Lo;0;L;;;;;N;;;;; +11612;MODI LETTER NGA;Lo;0;L;;;;;N;;;;; +11613;MODI LETTER CA;Lo;0;L;;;;;N;;;;; +11614;MODI LETTER CHA;Lo;0;L;;;;;N;;;;; +11615;MODI LETTER JA;Lo;0;L;;;;;N;;;;; +11616;MODI LETTER JHA;Lo;0;L;;;;;N;;;;; +11617;MODI LETTER NYA;Lo;0;L;;;;;N;;;;; +11618;MODI LETTER TTA;Lo;0;L;;;;;N;;;;; +11619;MODI LETTER TTHA;Lo;0;L;;;;;N;;;;; +1161A;MODI LETTER DDA;Lo;0;L;;;;;N;;;;; +1161B;MODI LETTER DDHA;Lo;0;L;;;;;N;;;;; +1161C;MODI LETTER NNA;Lo;0;L;;;;;N;;;;; +1161D;MODI LETTER TA;Lo;0;L;;;;;N;;;;; +1161E;MODI LETTER THA;Lo;0;L;;;;;N;;;;; +1161F;MODI LETTER DA;Lo;0;L;;;;;N;;;;; +11620;MODI LETTER DHA;Lo;0;L;;;;;N;;;;; +11621;MODI LETTER NA;Lo;0;L;;;;;N;;;;; +11622;MODI LETTER PA;Lo;0;L;;;;;N;;;;; +11623;MODI LETTER PHA;Lo;0;L;;;;;N;;;;; +11624;MODI LETTER BA;Lo;0;L;;;;;N;;;;; +11625;MODI LETTER BHA;Lo;0;L;;;;;N;;;;; +11626;MODI LETTER MA;Lo;0;L;;;;;N;;;;; +11627;MODI LETTER YA;Lo;0;L;;;;;N;;;;; +11628;MODI LETTER RA;Lo;0;L;;;;;N;;;;; +11629;MODI LETTER LA;Lo;0;L;;;;;N;;;;; +1162A;MODI LETTER VA;Lo;0;L;;;;;N;;;;; +1162B;MODI LETTER SHA;Lo;0;L;;;;;N;;;;; +1162C;MODI LETTER SSA;Lo;0;L;;;;;N;;;;; +1162D;MODI LETTER SA;Lo;0;L;;;;;N;;;;; +1162E;MODI LETTER HA;Lo;0;L;;;;;N;;;;; +1162F;MODI LETTER LLA;Lo;0;L;;;;;N;;;;; +11630;MODI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11631;MODI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +11632;MODI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +11633;MODI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11634;MODI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +11635;MODI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +11636;MODI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +11637;MODI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +11638;MODI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +11639;MODI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +1163A;MODI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +1163B;MODI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +1163C;MODI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +1163D;MODI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +1163E;MODI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +1163F;MODI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +11640;MODI SIGN ARDHACANDRA;Mn;0;NSM;;;;;N;;;;; +11641;MODI DANDA;Po;0;L;;;;;N;;;;; +11642;MODI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +11643;MODI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +11644;MODI SIGN HUVA;Lo;0;L;;;;;N;;;;; +11650;MODI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11651;MODI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11652;MODI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11653;MODI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11654;MODI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11655;MODI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11656;MODI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11657;MODI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11658;MODI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11659;MODI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11660;MONGOLIAN BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; +11661;MONGOLIAN ROTATED BIRGA;Po;0;ON;;;;;N;;;;; +11662;MONGOLIAN DOUBLE BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; +11663;MONGOLIAN TRIPLE BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; +11664;MONGOLIAN BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; +11665;MONGOLIAN ROTATED BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; +11666;MONGOLIAN ROTATED BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; +11667;MONGOLIAN INVERTED BIRGA;Po;0;ON;;;;;N;;;;; +11668;MONGOLIAN INVERTED BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; +11669;MONGOLIAN SWIRL BIRGA;Po;0;ON;;;;;N;;;;; +1166A;MONGOLIAN SWIRL BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; +1166B;MONGOLIAN SWIRL BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; +1166C;MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; +11680;TAKRI LETTER A;Lo;0;L;;;;;N;;;;; +11681;TAKRI LETTER AA;Lo;0;L;;;;;N;;;;; +11682;TAKRI LETTER I;Lo;0;L;;;;;N;;;;; +11683;TAKRI LETTER II;Lo;0;L;;;;;N;;;;; +11684;TAKRI LETTER U;Lo;0;L;;;;;N;;;;; +11685;TAKRI LETTER UU;Lo;0;L;;;;;N;;;;; +11686;TAKRI LETTER E;Lo;0;L;;;;;N;;;;; +11687;TAKRI LETTER AI;Lo;0;L;;;;;N;;;;; +11688;TAKRI LETTER O;Lo;0;L;;;;;N;;;;; +11689;TAKRI LETTER AU;Lo;0;L;;;;;N;;;;; +1168A;TAKRI LETTER KA;Lo;0;L;;;;;N;;;;; +1168B;TAKRI LETTER KHA;Lo;0;L;;;;;N;;;;; +1168C;TAKRI LETTER GA;Lo;0;L;;;;;N;;;;; +1168D;TAKRI LETTER GHA;Lo;0;L;;;;;N;;;;; +1168E;TAKRI LETTER NGA;Lo;0;L;;;;;N;;;;; +1168F;TAKRI LETTER CA;Lo;0;L;;;;;N;;;;; +11690;TAKRI LETTER CHA;Lo;0;L;;;;;N;;;;; +11691;TAKRI LETTER JA;Lo;0;L;;;;;N;;;;; +11692;TAKRI LETTER JHA;Lo;0;L;;;;;N;;;;; +11693;TAKRI LETTER NYA;Lo;0;L;;;;;N;;;;; +11694;TAKRI LETTER TTA;Lo;0;L;;;;;N;;;;; +11695;TAKRI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11696;TAKRI LETTER DDA;Lo;0;L;;;;;N;;;;; +11697;TAKRI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11698;TAKRI LETTER NNA;Lo;0;L;;;;;N;;;;; +11699;TAKRI LETTER TA;Lo;0;L;;;;;N;;;;; +1169A;TAKRI LETTER THA;Lo;0;L;;;;;N;;;;; +1169B;TAKRI LETTER DA;Lo;0;L;;;;;N;;;;; +1169C;TAKRI LETTER DHA;Lo;0;L;;;;;N;;;;; +1169D;TAKRI LETTER NA;Lo;0;L;;;;;N;;;;; +1169E;TAKRI LETTER PA;Lo;0;L;;;;;N;;;;; +1169F;TAKRI LETTER PHA;Lo;0;L;;;;;N;;;;; +116A0;TAKRI LETTER BA;Lo;0;L;;;;;N;;;;; +116A1;TAKRI LETTER BHA;Lo;0;L;;;;;N;;;;; +116A2;TAKRI LETTER MA;Lo;0;L;;;;;N;;;;; +116A3;TAKRI LETTER YA;Lo;0;L;;;;;N;;;;; +116A4;TAKRI LETTER RA;Lo;0;L;;;;;N;;;;; +116A5;TAKRI LETTER LA;Lo;0;L;;;;;N;;;;; +116A6;TAKRI LETTER VA;Lo;0;L;;;;;N;;;;; +116A7;TAKRI LETTER SHA;Lo;0;L;;;;;N;;;;; +116A8;TAKRI LETTER SA;Lo;0;L;;;;;N;;;;; +116A9;TAKRI LETTER HA;Lo;0;L;;;;;N;;;;; +116AA;TAKRI LETTER RRA;Lo;0;L;;;;;N;;;;; +116AB;TAKRI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +116AC;TAKRI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +116AD;TAKRI VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; +116AE;TAKRI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +116AF;TAKRI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +116B0;TAKRI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +116B1;TAKRI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +116B2;TAKRI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +116B3;TAKRI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +116B4;TAKRI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +116B5;TAKRI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +116B6;TAKRI SIGN VIRAMA;Mc;9;L;;;;;N;;;;; +116B7;TAKRI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +116B8;TAKRI LETTER ARCHAIC KHA;Lo;0;L;;;;;N;;;;; +116B9;TAKRI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +116C0;TAKRI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +116C1;TAKRI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +116C2;TAKRI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +116C3;TAKRI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +116C4;TAKRI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +116C5;TAKRI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +116C6;TAKRI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +116C7;TAKRI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +116C8;TAKRI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +116C9;TAKRI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +116D0;MYANMAR PAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +116D1;MYANMAR PAO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +116D2;MYANMAR PAO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +116D3;MYANMAR PAO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +116D4;MYANMAR PAO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +116D5;MYANMAR PAO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +116D6;MYANMAR PAO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +116D7;MYANMAR PAO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +116D8;MYANMAR PAO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +116D9;MYANMAR PAO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +116DA;MYANMAR EASTERN PWO KAREN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +116DB;MYANMAR EASTERN PWO KAREN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +116DC;MYANMAR EASTERN PWO KAREN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +116DD;MYANMAR EASTERN PWO KAREN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +116DE;MYANMAR EASTERN PWO KAREN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +116DF;MYANMAR EASTERN PWO KAREN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +116E0;MYANMAR EASTERN PWO KAREN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +116E1;MYANMAR EASTERN PWO KAREN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +116E2;MYANMAR EASTERN PWO KAREN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +116E3;MYANMAR EASTERN PWO KAREN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11700;AHOM LETTER KA;Lo;0;L;;;;;N;;;;; +11701;AHOM LETTER KHA;Lo;0;L;;;;;N;;;;; +11702;AHOM LETTER NGA;Lo;0;L;;;;;N;;;;; +11703;AHOM LETTER NA;Lo;0;L;;;;;N;;;;; +11704;AHOM LETTER TA;Lo;0;L;;;;;N;;;;; +11705;AHOM LETTER ALTERNATE TA;Lo;0;L;;;;;N;;;;; +11706;AHOM LETTER PA;Lo;0;L;;;;;N;;;;; +11707;AHOM LETTER PHA;Lo;0;L;;;;;N;;;;; +11708;AHOM LETTER BA;Lo;0;L;;;;;N;;;;; +11709;AHOM LETTER MA;Lo;0;L;;;;;N;;;;; +1170A;AHOM LETTER JA;Lo;0;L;;;;;N;;;;; +1170B;AHOM LETTER CHA;Lo;0;L;;;;;N;;;;; +1170C;AHOM LETTER THA;Lo;0;L;;;;;N;;;;; +1170D;AHOM LETTER RA;Lo;0;L;;;;;N;;;;; +1170E;AHOM LETTER LA;Lo;0;L;;;;;N;;;;; +1170F;AHOM LETTER SA;Lo;0;L;;;;;N;;;;; +11710;AHOM LETTER NYA;Lo;0;L;;;;;N;;;;; +11711;AHOM LETTER HA;Lo;0;L;;;;;N;;;;; +11712;AHOM LETTER A;Lo;0;L;;;;;N;;;;; +11713;AHOM LETTER DA;Lo;0;L;;;;;N;;;;; +11714;AHOM LETTER DHA;Lo;0;L;;;;;N;;;;; +11715;AHOM LETTER GA;Lo;0;L;;;;;N;;;;; +11716;AHOM LETTER ALTERNATE GA;Lo;0;L;;;;;N;;;;; +11717;AHOM LETTER GHA;Lo;0;L;;;;;N;;;;; +11718;AHOM LETTER BHA;Lo;0;L;;;;;N;;;;; +11719;AHOM LETTER JHA;Lo;0;L;;;;;N;;;;; +1171A;AHOM LETTER ALTERNATE BA;Lo;0;L;;;;;N;;;;; +1171D;AHOM CONSONANT SIGN MEDIAL LA;Mn;0;NSM;;;;;N;;;;; +1171E;AHOM CONSONANT SIGN MEDIAL RA;Mc;0;L;;;;;N;;;;; +1171F;AHOM CONSONANT SIGN MEDIAL LIGATING RA;Mn;0;NSM;;;;;N;;;;; +11720;AHOM VOWEL SIGN A;Mc;0;L;;;;;N;;;;; +11721;AHOM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11722;AHOM VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11723;AHOM VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +11724;AHOM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11725;AHOM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +11726;AHOM VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +11727;AHOM VOWEL SIGN AW;Mn;0;NSM;;;;;N;;;;; +11728;AHOM VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +11729;AHOM VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +1172A;AHOM VOWEL SIGN AM;Mn;0;NSM;;;;;N;;;;; +1172B;AHOM SIGN KILLER;Mn;9;NSM;;;;;N;;;;; +11730;AHOM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11731;AHOM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11732;AHOM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11733;AHOM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11734;AHOM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11735;AHOM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11736;AHOM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11737;AHOM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11738;AHOM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11739;AHOM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1173A;AHOM NUMBER TEN;No;0;L;;;;10;N;;;;; +1173B;AHOM NUMBER TWENTY;No;0;L;;;;20;N;;;;; +1173C;AHOM SIGN SMALL SECTION;Po;0;L;;;;;N;;;;; +1173D;AHOM SIGN SECTION;Po;0;L;;;;;N;;;;; +1173E;AHOM SIGN RULAI;Po;0;L;;;;;N;;;;; +1173F;AHOM SYMBOL VI;So;0;L;;;;;N;;;;; +11740;AHOM LETTER CA;Lo;0;L;;;;;N;;;;; +11741;AHOM LETTER TTA;Lo;0;L;;;;;N;;;;; +11742;AHOM LETTER TTHA;Lo;0;L;;;;;N;;;;; +11743;AHOM LETTER DDA;Lo;0;L;;;;;N;;;;; +11744;AHOM LETTER DDHA;Lo;0;L;;;;;N;;;;; +11745;AHOM LETTER NNA;Lo;0;L;;;;;N;;;;; +11746;AHOM LETTER LLA;Lo;0;L;;;;;N;;;;; +11800;DOGRA LETTER A;Lo;0;L;;;;;N;;;;; +11801;DOGRA LETTER AA;Lo;0;L;;;;;N;;;;; +11802;DOGRA LETTER I;Lo;0;L;;;;;N;;;;; +11803;DOGRA LETTER II;Lo;0;L;;;;;N;;;;; +11804;DOGRA LETTER U;Lo;0;L;;;;;N;;;;; +11805;DOGRA LETTER UU;Lo;0;L;;;;;N;;;;; +11806;DOGRA LETTER E;Lo;0;L;;;;;N;;;;; +11807;DOGRA LETTER AI;Lo;0;L;;;;;N;;;;; +11808;DOGRA LETTER O;Lo;0;L;;;;;N;;;;; +11809;DOGRA LETTER AU;Lo;0;L;;;;;N;;;;; +1180A;DOGRA LETTER KA;Lo;0;L;;;;;N;;;;; +1180B;DOGRA LETTER KHA;Lo;0;L;;;;;N;;;;; +1180C;DOGRA LETTER GA;Lo;0;L;;;;;N;;;;; +1180D;DOGRA LETTER GHA;Lo;0;L;;;;;N;;;;; +1180E;DOGRA LETTER NGA;Lo;0;L;;;;;N;;;;; +1180F;DOGRA LETTER CA;Lo;0;L;;;;;N;;;;; +11810;DOGRA LETTER CHA;Lo;0;L;;;;;N;;;;; +11811;DOGRA LETTER JA;Lo;0;L;;;;;N;;;;; +11812;DOGRA LETTER JHA;Lo;0;L;;;;;N;;;;; +11813;DOGRA LETTER NYA;Lo;0;L;;;;;N;;;;; +11814;DOGRA LETTER TTA;Lo;0;L;;;;;N;;;;; +11815;DOGRA LETTER TTHA;Lo;0;L;;;;;N;;;;; +11816;DOGRA LETTER DDA;Lo;0;L;;;;;N;;;;; +11817;DOGRA LETTER DDHA;Lo;0;L;;;;;N;;;;; +11818;DOGRA LETTER NNA;Lo;0;L;;;;;N;;;;; +11819;DOGRA LETTER TA;Lo;0;L;;;;;N;;;;; +1181A;DOGRA LETTER THA;Lo;0;L;;;;;N;;;;; +1181B;DOGRA LETTER DA;Lo;0;L;;;;;N;;;;; +1181C;DOGRA LETTER DHA;Lo;0;L;;;;;N;;;;; +1181D;DOGRA LETTER NA;Lo;0;L;;;;;N;;;;; +1181E;DOGRA LETTER PA;Lo;0;L;;;;;N;;;;; +1181F;DOGRA LETTER PHA;Lo;0;L;;;;;N;;;;; +11820;DOGRA LETTER BA;Lo;0;L;;;;;N;;;;; +11821;DOGRA LETTER BHA;Lo;0;L;;;;;N;;;;; +11822;DOGRA LETTER MA;Lo;0;L;;;;;N;;;;; +11823;DOGRA LETTER YA;Lo;0;L;;;;;N;;;;; +11824;DOGRA LETTER RA;Lo;0;L;;;;;N;;;;; +11825;DOGRA LETTER LA;Lo;0;L;;;;;N;;;;; +11826;DOGRA LETTER VA;Lo;0;L;;;;;N;;;;; +11827;DOGRA LETTER SHA;Lo;0;L;;;;;N;;;;; +11828;DOGRA LETTER SSA;Lo;0;L;;;;;N;;;;; +11829;DOGRA LETTER SA;Lo;0;L;;;;;N;;;;; +1182A;DOGRA LETTER HA;Lo;0;L;;;;;N;;;;; +1182B;DOGRA LETTER RRA;Lo;0;L;;;;;N;;;;; +1182C;DOGRA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +1182D;DOGRA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +1182E;DOGRA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +1182F;DOGRA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11830;DOGRA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +11831;DOGRA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +11832;DOGRA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +11833;DOGRA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11834;DOGRA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +11835;DOGRA VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +11836;DOGRA VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +11837;DOGRA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11838;DOGRA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11839;DOGRA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +1183A;DOGRA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +1183B;DOGRA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +118A0;WARANG CITI CAPITAL LETTER NGAA;Lu;0;L;;;;;N;;;;118C0; +118A1;WARANG CITI CAPITAL LETTER A;Lu;0;L;;;;;N;;;;118C1; +118A2;WARANG CITI CAPITAL LETTER WI;Lu;0;L;;;;;N;;;;118C2; +118A3;WARANG CITI CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;118C3; +118A4;WARANG CITI CAPITAL LETTER YA;Lu;0;L;;;;;N;;;;118C4; +118A5;WARANG CITI CAPITAL LETTER YO;Lu;0;L;;;;;N;;;;118C5; +118A6;WARANG CITI CAPITAL LETTER II;Lu;0;L;;;;;N;;;;118C6; +118A7;WARANG CITI CAPITAL LETTER UU;Lu;0;L;;;;;N;;;;118C7; +118A8;WARANG CITI CAPITAL LETTER E;Lu;0;L;;;;;N;;;;118C8; +118A9;WARANG CITI CAPITAL LETTER O;Lu;0;L;;;;;N;;;;118C9; +118AA;WARANG CITI CAPITAL LETTER ANG;Lu;0;L;;;;;N;;;;118CA; +118AB;WARANG CITI CAPITAL LETTER GA;Lu;0;L;;;;;N;;;;118CB; +118AC;WARANG CITI CAPITAL LETTER KO;Lu;0;L;;;;;N;;;;118CC; +118AD;WARANG CITI CAPITAL LETTER ENY;Lu;0;L;;;;;N;;;;118CD; +118AE;WARANG CITI CAPITAL LETTER YUJ;Lu;0;L;;;;;N;;;;118CE; +118AF;WARANG CITI CAPITAL LETTER UC;Lu;0;L;;;;;N;;;;118CF; +118B0;WARANG CITI CAPITAL LETTER ENN;Lu;0;L;;;;;N;;;;118D0; +118B1;WARANG CITI CAPITAL LETTER ODD;Lu;0;L;;;;;N;;;;118D1; +118B2;WARANG CITI CAPITAL LETTER TTE;Lu;0;L;;;;;N;;;;118D2; +118B3;WARANG CITI CAPITAL LETTER NUNG;Lu;0;L;;;;;N;;;;118D3; +118B4;WARANG CITI CAPITAL LETTER DA;Lu;0;L;;;;;N;;;;118D4; +118B5;WARANG CITI CAPITAL LETTER AT;Lu;0;L;;;;;N;;;;118D5; +118B6;WARANG CITI CAPITAL LETTER AM;Lu;0;L;;;;;N;;;;118D6; +118B7;WARANG CITI CAPITAL LETTER BU;Lu;0;L;;;;;N;;;;118D7; +118B8;WARANG CITI CAPITAL LETTER PU;Lu;0;L;;;;;N;;;;118D8; +118B9;WARANG CITI CAPITAL LETTER HIYO;Lu;0;L;;;;;N;;;;118D9; +118BA;WARANG CITI CAPITAL LETTER HOLO;Lu;0;L;;;;;N;;;;118DA; +118BB;WARANG CITI CAPITAL LETTER HORR;Lu;0;L;;;;;N;;;;118DB; +118BC;WARANG CITI CAPITAL LETTER HAR;Lu;0;L;;;;;N;;;;118DC; +118BD;WARANG CITI CAPITAL LETTER SSUU;Lu;0;L;;;;;N;;;;118DD; +118BE;WARANG CITI CAPITAL LETTER SII;Lu;0;L;;;;;N;;;;118DE; +118BF;WARANG CITI CAPITAL LETTER VIYO;Lu;0;L;;;;;N;;;;118DF; +118C0;WARANG CITI SMALL LETTER NGAA;Ll;0;L;;;;;N;;;118A0;;118A0 +118C1;WARANG CITI SMALL LETTER A;Ll;0;L;;;;;N;;;118A1;;118A1 +118C2;WARANG CITI SMALL LETTER WI;Ll;0;L;;;;;N;;;118A2;;118A2 +118C3;WARANG CITI SMALL LETTER YU;Ll;0;L;;;;;N;;;118A3;;118A3 +118C4;WARANG CITI SMALL LETTER YA;Ll;0;L;;;;;N;;;118A4;;118A4 +118C5;WARANG CITI SMALL LETTER YO;Ll;0;L;;;;;N;;;118A5;;118A5 +118C6;WARANG CITI SMALL LETTER II;Ll;0;L;;;;;N;;;118A6;;118A6 +118C7;WARANG CITI SMALL LETTER UU;Ll;0;L;;;;;N;;;118A7;;118A7 +118C8;WARANG CITI SMALL LETTER E;Ll;0;L;;;;;N;;;118A8;;118A8 +118C9;WARANG CITI SMALL LETTER O;Ll;0;L;;;;;N;;;118A9;;118A9 +118CA;WARANG CITI SMALL LETTER ANG;Ll;0;L;;;;;N;;;118AA;;118AA +118CB;WARANG CITI SMALL LETTER GA;Ll;0;L;;;;;N;;;118AB;;118AB +118CC;WARANG CITI SMALL LETTER KO;Ll;0;L;;;;;N;;;118AC;;118AC +118CD;WARANG CITI SMALL LETTER ENY;Ll;0;L;;;;;N;;;118AD;;118AD +118CE;WARANG CITI SMALL LETTER YUJ;Ll;0;L;;;;;N;;;118AE;;118AE +118CF;WARANG CITI SMALL LETTER UC;Ll;0;L;;;;;N;;;118AF;;118AF +118D0;WARANG CITI SMALL LETTER ENN;Ll;0;L;;;;;N;;;118B0;;118B0 +118D1;WARANG CITI SMALL LETTER ODD;Ll;0;L;;;;;N;;;118B1;;118B1 +118D2;WARANG CITI SMALL LETTER TTE;Ll;0;L;;;;;N;;;118B2;;118B2 +118D3;WARANG CITI SMALL LETTER NUNG;Ll;0;L;;;;;N;;;118B3;;118B3 +118D4;WARANG CITI SMALL LETTER DA;Ll;0;L;;;;;N;;;118B4;;118B4 +118D5;WARANG CITI SMALL LETTER AT;Ll;0;L;;;;;N;;;118B5;;118B5 +118D6;WARANG CITI SMALL LETTER AM;Ll;0;L;;;;;N;;;118B6;;118B6 +118D7;WARANG CITI SMALL LETTER BU;Ll;0;L;;;;;N;;;118B7;;118B7 +118D8;WARANG CITI SMALL LETTER PU;Ll;0;L;;;;;N;;;118B8;;118B8 +118D9;WARANG CITI SMALL LETTER HIYO;Ll;0;L;;;;;N;;;118B9;;118B9 +118DA;WARANG CITI SMALL LETTER HOLO;Ll;0;L;;;;;N;;;118BA;;118BA +118DB;WARANG CITI SMALL LETTER HORR;Ll;0;L;;;;;N;;;118BB;;118BB +118DC;WARANG CITI SMALL LETTER HAR;Ll;0;L;;;;;N;;;118BC;;118BC +118DD;WARANG CITI SMALL LETTER SSUU;Ll;0;L;;;;;N;;;118BD;;118BD +118DE;WARANG CITI SMALL LETTER SII;Ll;0;L;;;;;N;;;118BE;;118BE +118DF;WARANG CITI SMALL LETTER VIYO;Ll;0;L;;;;;N;;;118BF;;118BF +118E0;WARANG CITI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +118E1;WARANG CITI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +118E2;WARANG CITI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +118E3;WARANG CITI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +118E4;WARANG CITI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +118E5;WARANG CITI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +118E6;WARANG CITI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +118E7;WARANG CITI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +118E8;WARANG CITI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +118E9;WARANG CITI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +118EA;WARANG CITI NUMBER TEN;No;0;L;;;;10;N;;;;; +118EB;WARANG CITI NUMBER TWENTY;No;0;L;;;;20;N;;;;; +118EC;WARANG CITI NUMBER THIRTY;No;0;L;;;;30;N;;;;; +118ED;WARANG CITI NUMBER FORTY;No;0;L;;;;40;N;;;;; +118EE;WARANG CITI NUMBER FIFTY;No;0;L;;;;50;N;;;;; +118EF;WARANG CITI NUMBER SIXTY;No;0;L;;;;60;N;;;;; +118F0;WARANG CITI NUMBER SEVENTY;No;0;L;;;;70;N;;;;; +118F1;WARANG CITI NUMBER EIGHTY;No;0;L;;;;80;N;;;;; +118F2;WARANG CITI NUMBER NINETY;No;0;L;;;;90;N;;;;; +118FF;WARANG CITI OM;Lo;0;L;;;;;N;;;;; +11900;DIVES AKURU LETTER A;Lo;0;L;;;;;N;;;;; +11901;DIVES AKURU LETTER AA;Lo;0;L;;;;;N;;;;; +11902;DIVES AKURU LETTER I;Lo;0;L;;;;;N;;;;; +11903;DIVES AKURU LETTER II;Lo;0;L;;;;;N;;;;; +11904;DIVES AKURU LETTER U;Lo;0;L;;;;;N;;;;; +11905;DIVES AKURU LETTER UU;Lo;0;L;;;;;N;;;;; +11906;DIVES AKURU LETTER E;Lo;0;L;;;;;N;;;;; +11909;DIVES AKURU LETTER O;Lo;0;L;;;;;N;;;;; +1190C;DIVES AKURU LETTER KA;Lo;0;L;;;;;N;;;;; +1190D;DIVES AKURU LETTER KHA;Lo;0;L;;;;;N;;;;; +1190E;DIVES AKURU LETTER GA;Lo;0;L;;;;;N;;;;; +1190F;DIVES AKURU LETTER GHA;Lo;0;L;;;;;N;;;;; +11910;DIVES AKURU LETTER NGA;Lo;0;L;;;;;N;;;;; +11911;DIVES AKURU LETTER CA;Lo;0;L;;;;;N;;;;; +11912;DIVES AKURU LETTER CHA;Lo;0;L;;;;;N;;;;; +11913;DIVES AKURU LETTER JA;Lo;0;L;;;;;N;;;;; +11915;DIVES AKURU LETTER NYA;Lo;0;L;;;;;N;;;;; +11916;DIVES AKURU LETTER TTA;Lo;0;L;;;;;N;;;;; +11918;DIVES AKURU LETTER DDA;Lo;0;L;;;;;N;;;;; +11919;DIVES AKURU LETTER DDHA;Lo;0;L;;;;;N;;;;; +1191A;DIVES AKURU LETTER NNA;Lo;0;L;;;;;N;;;;; +1191B;DIVES AKURU LETTER TA;Lo;0;L;;;;;N;;;;; +1191C;DIVES AKURU LETTER THA;Lo;0;L;;;;;N;;;;; +1191D;DIVES AKURU LETTER DA;Lo;0;L;;;;;N;;;;; +1191E;DIVES AKURU LETTER DHA;Lo;0;L;;;;;N;;;;; +1191F;DIVES AKURU LETTER NA;Lo;0;L;;;;;N;;;;; +11920;DIVES AKURU LETTER PA;Lo;0;L;;;;;N;;;;; +11921;DIVES AKURU LETTER PHA;Lo;0;L;;;;;N;;;;; +11922;DIVES AKURU LETTER BA;Lo;0;L;;;;;N;;;;; +11923;DIVES AKURU LETTER BHA;Lo;0;L;;;;;N;;;;; +11924;DIVES AKURU LETTER MA;Lo;0;L;;;;;N;;;;; +11925;DIVES AKURU LETTER YA;Lo;0;L;;;;;N;;;;; +11926;DIVES AKURU LETTER YYA;Lo;0;L;;;;;N;;;;; +11927;DIVES AKURU LETTER RA;Lo;0;L;;;;;N;;;;; +11928;DIVES AKURU LETTER LA;Lo;0;L;;;;;N;;;;; +11929;DIVES AKURU LETTER VA;Lo;0;L;;;;;N;;;;; +1192A;DIVES AKURU LETTER SHA;Lo;0;L;;;;;N;;;;; +1192B;DIVES AKURU LETTER SSA;Lo;0;L;;;;;N;;;;; +1192C;DIVES AKURU LETTER SA;Lo;0;L;;;;;N;;;;; +1192D;DIVES AKURU LETTER HA;Lo;0;L;;;;;N;;;;; +1192E;DIVES AKURU LETTER LLA;Lo;0;L;;;;;N;;;;; +1192F;DIVES AKURU LETTER ZA;Lo;0;L;;;;;N;;;;; +11930;DIVES AKURU VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11931;DIVES AKURU VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +11932;DIVES AKURU VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +11933;DIVES AKURU VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +11934;DIVES AKURU VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +11935;DIVES AKURU VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +11937;DIVES AKURU VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +11938;DIVES AKURU VOWEL SIGN O;Mc;0;L;11935 11930;;;;N;;;;; +1193B;DIVES AKURU SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +1193C;DIVES AKURU SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +1193D;DIVES AKURU SIGN HALANTA;Mc;9;L;;;;;N;;;;; +1193E;DIVES AKURU VIRAMA;Mn;9;NSM;;;;;N;;;;; +1193F;DIVES AKURU PREFIXED NASAL SIGN;Lo;0;L;;;;;N;;;;; +11940;DIVES AKURU MEDIAL YA;Mc;0;L;;;;;N;;;;; +11941;DIVES AKURU INITIAL RA;Lo;0;L;;;;;N;;;;; +11942;DIVES AKURU MEDIAL RA;Mc;0;L;;;;;N;;;;; +11943;DIVES AKURU SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +11944;DIVES AKURU DOUBLE DANDA;Po;0;L;;;;;N;;;;; +11945;DIVES AKURU GAP FILLER;Po;0;L;;;;;N;;;;; +11946;DIVES AKURU END OF TEXT MARK;Po;0;L;;;;;N;;;;; +11950;DIVES AKURU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11951;DIVES AKURU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11952;DIVES AKURU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11953;DIVES AKURU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11954;DIVES AKURU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11955;DIVES AKURU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11956;DIVES AKURU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11957;DIVES AKURU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11958;DIVES AKURU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11959;DIVES AKURU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +119A0;NANDINAGARI LETTER A;Lo;0;L;;;;;N;;;;; +119A1;NANDINAGARI LETTER AA;Lo;0;L;;;;;N;;;;; +119A2;NANDINAGARI LETTER I;Lo;0;L;;;;;N;;;;; +119A3;NANDINAGARI LETTER II;Lo;0;L;;;;;N;;;;; +119A4;NANDINAGARI LETTER U;Lo;0;L;;;;;N;;;;; +119A5;NANDINAGARI LETTER UU;Lo;0;L;;;;;N;;;;; +119A6;NANDINAGARI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +119A7;NANDINAGARI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +119AA;NANDINAGARI LETTER E;Lo;0;L;;;;;N;;;;; +119AB;NANDINAGARI LETTER AI;Lo;0;L;;;;;N;;;;; +119AC;NANDINAGARI LETTER O;Lo;0;L;;;;;N;;;;; +119AD;NANDINAGARI LETTER AU;Lo;0;L;;;;;N;;;;; +119AE;NANDINAGARI LETTER KA;Lo;0;L;;;;;N;;;;; +119AF;NANDINAGARI LETTER KHA;Lo;0;L;;;;;N;;;;; +119B0;NANDINAGARI LETTER GA;Lo;0;L;;;;;N;;;;; +119B1;NANDINAGARI LETTER GHA;Lo;0;L;;;;;N;;;;; +119B2;NANDINAGARI LETTER NGA;Lo;0;L;;;;;N;;;;; +119B3;NANDINAGARI LETTER CA;Lo;0;L;;;;;N;;;;; +119B4;NANDINAGARI LETTER CHA;Lo;0;L;;;;;N;;;;; +119B5;NANDINAGARI LETTER JA;Lo;0;L;;;;;N;;;;; +119B6;NANDINAGARI LETTER JHA;Lo;0;L;;;;;N;;;;; +119B7;NANDINAGARI LETTER NYA;Lo;0;L;;;;;N;;;;; +119B8;NANDINAGARI LETTER TTA;Lo;0;L;;;;;N;;;;; +119B9;NANDINAGARI LETTER TTHA;Lo;0;L;;;;;N;;;;; +119BA;NANDINAGARI LETTER DDA;Lo;0;L;;;;;N;;;;; +119BB;NANDINAGARI LETTER DDHA;Lo;0;L;;;;;N;;;;; +119BC;NANDINAGARI LETTER NNA;Lo;0;L;;;;;N;;;;; +119BD;NANDINAGARI LETTER TA;Lo;0;L;;;;;N;;;;; +119BE;NANDINAGARI LETTER THA;Lo;0;L;;;;;N;;;;; +119BF;NANDINAGARI LETTER DA;Lo;0;L;;;;;N;;;;; +119C0;NANDINAGARI LETTER DHA;Lo;0;L;;;;;N;;;;; +119C1;NANDINAGARI LETTER NA;Lo;0;L;;;;;N;;;;; +119C2;NANDINAGARI LETTER PA;Lo;0;L;;;;;N;;;;; +119C3;NANDINAGARI LETTER PHA;Lo;0;L;;;;;N;;;;; +119C4;NANDINAGARI LETTER BA;Lo;0;L;;;;;N;;;;; +119C5;NANDINAGARI LETTER BHA;Lo;0;L;;;;;N;;;;; +119C6;NANDINAGARI LETTER MA;Lo;0;L;;;;;N;;;;; +119C7;NANDINAGARI LETTER YA;Lo;0;L;;;;;N;;;;; +119C8;NANDINAGARI LETTER RA;Lo;0;L;;;;;N;;;;; +119C9;NANDINAGARI LETTER LA;Lo;0;L;;;;;N;;;;; +119CA;NANDINAGARI LETTER VA;Lo;0;L;;;;;N;;;;; +119CB;NANDINAGARI LETTER SHA;Lo;0;L;;;;;N;;;;; +119CC;NANDINAGARI LETTER SSA;Lo;0;L;;;;;N;;;;; +119CD;NANDINAGARI LETTER SA;Lo;0;L;;;;;N;;;;; +119CE;NANDINAGARI LETTER HA;Lo;0;L;;;;;N;;;;; +119CF;NANDINAGARI LETTER LLA;Lo;0;L;;;;;N;;;;; +119D0;NANDINAGARI LETTER RRA;Lo;0;L;;;;;N;;;;; +119D1;NANDINAGARI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +119D2;NANDINAGARI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +119D3;NANDINAGARI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +119D4;NANDINAGARI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +119D5;NANDINAGARI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +119D6;NANDINAGARI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +119D7;NANDINAGARI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +119DA;NANDINAGARI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +119DB;NANDINAGARI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +119DC;NANDINAGARI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +119DD;NANDINAGARI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +119DE;NANDINAGARI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +119DF;NANDINAGARI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +119E0;NANDINAGARI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +119E1;NANDINAGARI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +119E2;NANDINAGARI SIGN SIDDHAM;Po;0;L;;;;;N;;;;; +119E3;NANDINAGARI HEADSTROKE;Lo;0;L;;;;;N;;;;; +119E4;NANDINAGARI VOWEL SIGN PRISHTHAMATRA E;Mc;0;L;;;;;N;;;;; +11A00;ZANABAZAR SQUARE LETTER A;Lo;0;L;;;;;N;;;;; +11A01;ZANABAZAR SQUARE VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11A02;ZANABAZAR SQUARE VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;; +11A03;ZANABAZAR SQUARE VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11A04;ZANABAZAR SQUARE VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11A05;ZANABAZAR SQUARE VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;; +11A06;ZANABAZAR SQUARE VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +11A07;ZANABAZAR SQUARE VOWEL SIGN AI;Mn;0;L;;;;;N;;;;; +11A08;ZANABAZAR SQUARE VOWEL SIGN AU;Mn;0;L;;;;;N;;;;; +11A09;ZANABAZAR SQUARE VOWEL SIGN REVERSED I;Mn;0;NSM;;;;;N;;;;; +11A0A;ZANABAZAR SQUARE VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;; +11A0B;ZANABAZAR SQUARE LETTER KA;Lo;0;L;;;;;N;;;;; +11A0C;ZANABAZAR SQUARE LETTER KHA;Lo;0;L;;;;;N;;;;; +11A0D;ZANABAZAR SQUARE LETTER GA;Lo;0;L;;;;;N;;;;; +11A0E;ZANABAZAR SQUARE LETTER GHA;Lo;0;L;;;;;N;;;;; +11A0F;ZANABAZAR SQUARE LETTER NGA;Lo;0;L;;;;;N;;;;; +11A10;ZANABAZAR SQUARE LETTER CA;Lo;0;L;;;;;N;;;;; +11A11;ZANABAZAR SQUARE LETTER CHA;Lo;0;L;;;;;N;;;;; +11A12;ZANABAZAR SQUARE LETTER JA;Lo;0;L;;;;;N;;;;; +11A13;ZANABAZAR SQUARE LETTER NYA;Lo;0;L;;;;;N;;;;; +11A14;ZANABAZAR SQUARE LETTER TTA;Lo;0;L;;;;;N;;;;; +11A15;ZANABAZAR SQUARE LETTER TTHA;Lo;0;L;;;;;N;;;;; +11A16;ZANABAZAR SQUARE LETTER DDA;Lo;0;L;;;;;N;;;;; +11A17;ZANABAZAR SQUARE LETTER DDHA;Lo;0;L;;;;;N;;;;; +11A18;ZANABAZAR SQUARE LETTER NNA;Lo;0;L;;;;;N;;;;; +11A19;ZANABAZAR SQUARE LETTER TA;Lo;0;L;;;;;N;;;;; +11A1A;ZANABAZAR SQUARE LETTER THA;Lo;0;L;;;;;N;;;;; +11A1B;ZANABAZAR SQUARE LETTER DA;Lo;0;L;;;;;N;;;;; +11A1C;ZANABAZAR SQUARE LETTER DHA;Lo;0;L;;;;;N;;;;; +11A1D;ZANABAZAR SQUARE LETTER NA;Lo;0;L;;;;;N;;;;; +11A1E;ZANABAZAR SQUARE LETTER PA;Lo;0;L;;;;;N;;;;; +11A1F;ZANABAZAR SQUARE LETTER PHA;Lo;0;L;;;;;N;;;;; +11A20;ZANABAZAR SQUARE LETTER BA;Lo;0;L;;;;;N;;;;; +11A21;ZANABAZAR SQUARE LETTER BHA;Lo;0;L;;;;;N;;;;; +11A22;ZANABAZAR SQUARE LETTER MA;Lo;0;L;;;;;N;;;;; +11A23;ZANABAZAR SQUARE LETTER TSA;Lo;0;L;;;;;N;;;;; +11A24;ZANABAZAR SQUARE LETTER TSHA;Lo;0;L;;;;;N;;;;; +11A25;ZANABAZAR SQUARE LETTER DZA;Lo;0;L;;;;;N;;;;; +11A26;ZANABAZAR SQUARE LETTER DZHA;Lo;0;L;;;;;N;;;;; +11A27;ZANABAZAR SQUARE LETTER ZHA;Lo;0;L;;;;;N;;;;; +11A28;ZANABAZAR SQUARE LETTER ZA;Lo;0;L;;;;;N;;;;; +11A29;ZANABAZAR SQUARE LETTER -A;Lo;0;L;;;;;N;;;;; +11A2A;ZANABAZAR SQUARE LETTER YA;Lo;0;L;;;;;N;;;;; +11A2B;ZANABAZAR SQUARE LETTER RA;Lo;0;L;;;;;N;;;;; +11A2C;ZANABAZAR SQUARE LETTER LA;Lo;0;L;;;;;N;;;;; +11A2D;ZANABAZAR SQUARE LETTER VA;Lo;0;L;;;;;N;;;;; +11A2E;ZANABAZAR SQUARE LETTER SHA;Lo;0;L;;;;;N;;;;; +11A2F;ZANABAZAR SQUARE LETTER SSA;Lo;0;L;;;;;N;;;;; +11A30;ZANABAZAR SQUARE LETTER SA;Lo;0;L;;;;;N;;;;; +11A31;ZANABAZAR SQUARE LETTER HA;Lo;0;L;;;;;N;;;;; +11A32;ZANABAZAR SQUARE LETTER KSSA;Lo;0;L;;;;;N;;;;; +11A33;ZANABAZAR SQUARE FINAL CONSONANT MARK;Mn;0;NSM;;;;;N;;;;; +11A34;ZANABAZAR SQUARE SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +11A35;ZANABAZAR SQUARE SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11A36;ZANABAZAR SQUARE SIGN CANDRABINDU WITH ORNAMENT;Mn;0;NSM;;;;;N;;;;; +11A37;ZANABAZAR SQUARE SIGN CANDRA WITH ORNAMENT;Mn;0;NSM;;;;;N;;;;; +11A38;ZANABAZAR SQUARE SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11A39;ZANABAZAR SQUARE SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11A3A;ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA;Lo;0;L;;;;;N;;;;; +11A3B;ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA;Mn;0;NSM;;;;;N;;;;; +11A3C;ZANABAZAR SQUARE CLUSTER-FINAL LETTER RA;Mn;0;NSM;;;;;N;;;;; +11A3D;ZANABAZAR SQUARE CLUSTER-FINAL LETTER LA;Mn;0;NSM;;;;;N;;;;; +11A3E;ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA;Mn;0;NSM;;;;;N;;;;; +11A3F;ZANABAZAR SQUARE INITIAL HEAD MARK;Po;0;L;;;;;N;;;;; +11A40;ZANABAZAR SQUARE CLOSING HEAD MARK;Po;0;L;;;;;N;;;;; +11A41;ZANABAZAR SQUARE MARK TSHEG;Po;0;L;;;;;N;;;;; +11A42;ZANABAZAR SQUARE MARK SHAD;Po;0;L;;;;;N;;;;; +11A43;ZANABAZAR SQUARE MARK DOUBLE SHAD;Po;0;L;;;;;N;;;;; +11A44;ZANABAZAR SQUARE MARK LONG TSHEG;Po;0;L;;;;;N;;;;; +11A45;ZANABAZAR SQUARE INITIAL DOUBLE-LINED HEAD MARK;Po;0;L;;;;;N;;;;; +11A46;ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK;Po;0;L;;;;;N;;;;; +11A47;ZANABAZAR SQUARE SUBJOINER;Mn;9;NSM;;;;;N;;;;; +11A50;SOYOMBO LETTER A;Lo;0;L;;;;;N;;;;; +11A51;SOYOMBO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11A52;SOYOMBO VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;; +11A53;SOYOMBO VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11A54;SOYOMBO VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11A55;SOYOMBO VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +11A56;SOYOMBO VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;; +11A57;SOYOMBO VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +11A58;SOYOMBO VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +11A59;SOYOMBO VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +11A5A;SOYOMBO VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +11A5B;SOYOMBO VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;; +11A5C;SOYOMBO LETTER KA;Lo;0;L;;;;;N;;;;; +11A5D;SOYOMBO LETTER KHA;Lo;0;L;;;;;N;;;;; +11A5E;SOYOMBO LETTER GA;Lo;0;L;;;;;N;;;;; +11A5F;SOYOMBO LETTER GHA;Lo;0;L;;;;;N;;;;; +11A60;SOYOMBO LETTER NGA;Lo;0;L;;;;;N;;;;; +11A61;SOYOMBO LETTER CA;Lo;0;L;;;;;N;;;;; +11A62;SOYOMBO LETTER CHA;Lo;0;L;;;;;N;;;;; +11A63;SOYOMBO LETTER JA;Lo;0;L;;;;;N;;;;; +11A64;SOYOMBO LETTER JHA;Lo;0;L;;;;;N;;;;; +11A65;SOYOMBO LETTER NYA;Lo;0;L;;;;;N;;;;; +11A66;SOYOMBO LETTER TTA;Lo;0;L;;;;;N;;;;; +11A67;SOYOMBO LETTER TTHA;Lo;0;L;;;;;N;;;;; +11A68;SOYOMBO LETTER DDA;Lo;0;L;;;;;N;;;;; +11A69;SOYOMBO LETTER DDHA;Lo;0;L;;;;;N;;;;; +11A6A;SOYOMBO LETTER NNA;Lo;0;L;;;;;N;;;;; +11A6B;SOYOMBO LETTER TA;Lo;0;L;;;;;N;;;;; +11A6C;SOYOMBO LETTER THA;Lo;0;L;;;;;N;;;;; +11A6D;SOYOMBO LETTER DA;Lo;0;L;;;;;N;;;;; +11A6E;SOYOMBO LETTER DHA;Lo;0;L;;;;;N;;;;; +11A6F;SOYOMBO LETTER NA;Lo;0;L;;;;;N;;;;; +11A70;SOYOMBO LETTER PA;Lo;0;L;;;;;N;;;;; +11A71;SOYOMBO LETTER PHA;Lo;0;L;;;;;N;;;;; +11A72;SOYOMBO LETTER BA;Lo;0;L;;;;;N;;;;; +11A73;SOYOMBO LETTER BHA;Lo;0;L;;;;;N;;;;; +11A74;SOYOMBO LETTER MA;Lo;0;L;;;;;N;;;;; +11A75;SOYOMBO LETTER TSA;Lo;0;L;;;;;N;;;;; +11A76;SOYOMBO LETTER TSHA;Lo;0;L;;;;;N;;;;; +11A77;SOYOMBO LETTER DZA;Lo;0;L;;;;;N;;;;; +11A78;SOYOMBO LETTER ZHA;Lo;0;L;;;;;N;;;;; +11A79;SOYOMBO LETTER ZA;Lo;0;L;;;;;N;;;;; +11A7A;SOYOMBO LETTER -A;Lo;0;L;;;;;N;;;;; +11A7B;SOYOMBO LETTER YA;Lo;0;L;;;;;N;;;;; +11A7C;SOYOMBO LETTER RA;Lo;0;L;;;;;N;;;;; +11A7D;SOYOMBO LETTER LA;Lo;0;L;;;;;N;;;;; +11A7E;SOYOMBO LETTER VA;Lo;0;L;;;;;N;;;;; +11A7F;SOYOMBO LETTER SHA;Lo;0;L;;;;;N;;;;; +11A80;SOYOMBO LETTER SSA;Lo;0;L;;;;;N;;;;; +11A81;SOYOMBO LETTER SA;Lo;0;L;;;;;N;;;;; +11A82;SOYOMBO LETTER HA;Lo;0;L;;;;;N;;;;; +11A83;SOYOMBO LETTER KSSA;Lo;0;L;;;;;N;;;;; +11A84;SOYOMBO SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; +11A85;SOYOMBO SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; +11A86;SOYOMBO CLUSTER-INITIAL LETTER RA;Lo;0;L;;;;;N;;;;; +11A87;SOYOMBO CLUSTER-INITIAL LETTER LA;Lo;0;L;;;;;N;;;;; +11A88;SOYOMBO CLUSTER-INITIAL LETTER SHA;Lo;0;L;;;;;N;;;;; +11A89;SOYOMBO CLUSTER-INITIAL LETTER SA;Lo;0;L;;;;;N;;;;; +11A8A;SOYOMBO FINAL CONSONANT SIGN G;Mn;0;NSM;;;;;N;;;;; +11A8B;SOYOMBO FINAL CONSONANT SIGN K;Mn;0;NSM;;;;;N;;;;; +11A8C;SOYOMBO FINAL CONSONANT SIGN NG;Mn;0;NSM;;;;;N;;;;; +11A8D;SOYOMBO FINAL CONSONANT SIGN D;Mn;0;NSM;;;;;N;;;;; +11A8E;SOYOMBO FINAL CONSONANT SIGN N;Mn;0;NSM;;;;;N;;;;; +11A8F;SOYOMBO FINAL CONSONANT SIGN B;Mn;0;NSM;;;;;N;;;;; +11A90;SOYOMBO FINAL CONSONANT SIGN M;Mn;0;NSM;;;;;N;;;;; +11A91;SOYOMBO FINAL CONSONANT SIGN R;Mn;0;NSM;;;;;N;;;;; +11A92;SOYOMBO FINAL CONSONANT SIGN L;Mn;0;NSM;;;;;N;;;;; +11A93;SOYOMBO FINAL CONSONANT SIGN SH;Mn;0;NSM;;;;;N;;;;; +11A94;SOYOMBO FINAL CONSONANT SIGN S;Mn;0;NSM;;;;;N;;;;; +11A95;SOYOMBO FINAL CONSONANT SIGN -A;Mn;0;NSM;;;;;N;;;;; +11A96;SOYOMBO SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11A97;SOYOMBO SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11A98;SOYOMBO GEMINATION MARK;Mn;0;NSM;;;;;N;;;;; +11A99;SOYOMBO SUBJOINER;Mn;9;NSM;;;;;N;;;;; +11A9A;SOYOMBO MARK TSHEG;Po;0;L;;;;;N;;;;; +11A9B;SOYOMBO MARK SHAD;Po;0;L;;;;;N;;;;; +11A9C;SOYOMBO MARK DOUBLE SHAD;Po;0;L;;;;;N;;;;; +11A9D;SOYOMBO MARK PLUTA;Lo;0;L;;;;;N;;;;; +11A9E;SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME;Po;0;L;;;;;N;;;;; +11A9F;SOYOMBO HEAD MARK WITH MOON AND SUN AND FLAME;Po;0;L;;;;;N;;;;; +11AA0;SOYOMBO HEAD MARK WITH MOON AND SUN;Po;0;L;;;;;N;;;;; +11AA1;SOYOMBO TERMINAL MARK-1;Po;0;L;;;;;N;;;;; +11AA2;SOYOMBO TERMINAL MARK-2;Po;0;L;;;;;N;;;;; +11AB0;CANADIAN SYLLABICS NATTILIK HI;Lo;0;L;;;;;N;;;;; +11AB1;CANADIAN SYLLABICS NATTILIK HII;Lo;0;L;;;;;N;;;;; +11AB2;CANADIAN SYLLABICS NATTILIK HO;Lo;0;L;;;;;N;;;;; +11AB3;CANADIAN SYLLABICS NATTILIK HOO;Lo;0;L;;;;;N;;;;; +11AB4;CANADIAN SYLLABICS NATTILIK HA;Lo;0;L;;;;;N;;;;; +11AB5;CANADIAN SYLLABICS NATTILIK HAA;Lo;0;L;;;;;N;;;;; +11AB6;CANADIAN SYLLABICS NATTILIK SHRI;Lo;0;L;;;;;N;;;;; +11AB7;CANADIAN SYLLABICS NATTILIK SHRII;Lo;0;L;;;;;N;;;;; +11AB8;CANADIAN SYLLABICS NATTILIK SHRO;Lo;0;L;;;;;N;;;;; +11AB9;CANADIAN SYLLABICS NATTILIK SHROO;Lo;0;L;;;;;N;;;;; +11ABA;CANADIAN SYLLABICS NATTILIK SHRA;Lo;0;L;;;;;N;;;;; +11ABB;CANADIAN SYLLABICS NATTILIK SHRAA;Lo;0;L;;;;;N;;;;; +11ABC;CANADIAN SYLLABICS SPE;Lo;0;L;;;;;N;;;;; +11ABD;CANADIAN SYLLABICS SPI;Lo;0;L;;;;;N;;;;; +11ABE;CANADIAN SYLLABICS SPO;Lo;0;L;;;;;N;;;;; +11ABF;CANADIAN SYLLABICS SPA;Lo;0;L;;;;;N;;;;; +11AC0;PAU CIN HAU LETTER PA;Lo;0;L;;;;;N;;;;; +11AC1;PAU CIN HAU LETTER KA;Lo;0;L;;;;;N;;;;; +11AC2;PAU CIN HAU LETTER LA;Lo;0;L;;;;;N;;;;; +11AC3;PAU CIN HAU LETTER MA;Lo;0;L;;;;;N;;;;; +11AC4;PAU CIN HAU LETTER DA;Lo;0;L;;;;;N;;;;; +11AC5;PAU CIN HAU LETTER ZA;Lo;0;L;;;;;N;;;;; +11AC6;PAU CIN HAU LETTER VA;Lo;0;L;;;;;N;;;;; +11AC7;PAU CIN HAU LETTER NGA;Lo;0;L;;;;;N;;;;; +11AC8;PAU CIN HAU LETTER HA;Lo;0;L;;;;;N;;;;; +11AC9;PAU CIN HAU LETTER GA;Lo;0;L;;;;;N;;;;; +11ACA;PAU CIN HAU LETTER KHA;Lo;0;L;;;;;N;;;;; +11ACB;PAU CIN HAU LETTER SA;Lo;0;L;;;;;N;;;;; +11ACC;PAU CIN HAU LETTER BA;Lo;0;L;;;;;N;;;;; +11ACD;PAU CIN HAU LETTER CA;Lo;0;L;;;;;N;;;;; +11ACE;PAU CIN HAU LETTER TA;Lo;0;L;;;;;N;;;;; +11ACF;PAU CIN HAU LETTER THA;Lo;0;L;;;;;N;;;;; +11AD0;PAU CIN HAU LETTER NA;Lo;0;L;;;;;N;;;;; +11AD1;PAU CIN HAU LETTER PHA;Lo;0;L;;;;;N;;;;; +11AD2;PAU CIN HAU LETTER RA;Lo;0;L;;;;;N;;;;; +11AD3;PAU CIN HAU LETTER FA;Lo;0;L;;;;;N;;;;; +11AD4;PAU CIN HAU LETTER CHA;Lo;0;L;;;;;N;;;;; +11AD5;PAU CIN HAU LETTER A;Lo;0;L;;;;;N;;;;; +11AD6;PAU CIN HAU LETTER E;Lo;0;L;;;;;N;;;;; +11AD7;PAU CIN HAU LETTER I;Lo;0;L;;;;;N;;;;; +11AD8;PAU CIN HAU LETTER O;Lo;0;L;;;;;N;;;;; +11AD9;PAU CIN HAU LETTER U;Lo;0;L;;;;;N;;;;; +11ADA;PAU CIN HAU LETTER UA;Lo;0;L;;;;;N;;;;; +11ADB;PAU CIN HAU LETTER IA;Lo;0;L;;;;;N;;;;; +11ADC;PAU CIN HAU LETTER FINAL P;Lo;0;L;;;;;N;;;;; +11ADD;PAU CIN HAU LETTER FINAL K;Lo;0;L;;;;;N;;;;; +11ADE;PAU CIN HAU LETTER FINAL T;Lo;0;L;;;;;N;;;;; +11ADF;PAU CIN HAU LETTER FINAL M;Lo;0;L;;;;;N;;;;; +11AE0;PAU CIN HAU LETTER FINAL N;Lo;0;L;;;;;N;;;;; +11AE1;PAU CIN HAU LETTER FINAL L;Lo;0;L;;;;;N;;;;; +11AE2;PAU CIN HAU LETTER FINAL W;Lo;0;L;;;;;N;;;;; +11AE3;PAU CIN HAU LETTER FINAL NG;Lo;0;L;;;;;N;;;;; +11AE4;PAU CIN HAU LETTER FINAL Y;Lo;0;L;;;;;N;;;;; +11AE5;PAU CIN HAU RISING TONE LONG;Lo;0;L;;;;;N;;;;; +11AE6;PAU CIN HAU RISING TONE;Lo;0;L;;;;;N;;;;; +11AE7;PAU CIN HAU SANDHI GLOTTAL STOP;Lo;0;L;;;;;N;;;;; +11AE8;PAU CIN HAU RISING TONE LONG FINAL;Lo;0;L;;;;;N;;;;; +11AE9;PAU CIN HAU RISING TONE FINAL;Lo;0;L;;;;;N;;;;; +11AEA;PAU CIN HAU SANDHI GLOTTAL STOP FINAL;Lo;0;L;;;;;N;;;;; +11AEB;PAU CIN HAU SANDHI TONE LONG;Lo;0;L;;;;;N;;;;; +11AEC;PAU CIN HAU SANDHI TONE;Lo;0;L;;;;;N;;;;; +11AED;PAU CIN HAU SANDHI TONE LONG FINAL;Lo;0;L;;;;;N;;;;; +11AEE;PAU CIN HAU SANDHI TONE FINAL;Lo;0;L;;;;;N;;;;; +11AEF;PAU CIN HAU MID-LEVEL TONE;Lo;0;L;;;;;N;;;;; +11AF0;PAU CIN HAU GLOTTAL STOP VARIANT;Lo;0;L;;;;;N;;;;; +11AF1;PAU CIN HAU MID-LEVEL TONE LONG FINAL;Lo;0;L;;;;;N;;;;; +11AF2;PAU CIN HAU MID-LEVEL TONE FINAL;Lo;0;L;;;;;N;;;;; +11AF3;PAU CIN HAU LOW-FALLING TONE LONG;Lo;0;L;;;;;N;;;;; +11AF4;PAU CIN HAU LOW-FALLING TONE;Lo;0;L;;;;;N;;;;; +11AF5;PAU CIN HAU GLOTTAL STOP;Lo;0;L;;;;;N;;;;; +11AF6;PAU CIN HAU LOW-FALLING TONE LONG FINAL;Lo;0;L;;;;;N;;;;; +11AF7;PAU CIN HAU LOW-FALLING TONE FINAL;Lo;0;L;;;;;N;;;;; +11AF8;PAU CIN HAU GLOTTAL STOP FINAL;Lo;0;L;;;;;N;;;;; +11B00;DEVANAGARI HEAD MARK;Po;0;L;;;;;N;;;;; +11B01;DEVANAGARI HEAD MARK WITH HEADSTROKE;Po;0;L;;;;;N;;;;; +11B02;DEVANAGARI SIGN BHALE;Po;0;L;;;;;N;;;;; +11B03;DEVANAGARI SIGN BHALE WITH HOOK;Po;0;L;;;;;N;;;;; +11B04;DEVANAGARI SIGN EXTENDED BHALE;Po;0;L;;;;;N;;;;; +11B05;DEVANAGARI SIGN EXTENDED BHALE WITH HOOK;Po;0;L;;;;;N;;;;; +11B06;DEVANAGARI SIGN WESTERN FIVE-LIKE BHALE;Po;0;L;;;;;N;;;;; +11B07;DEVANAGARI SIGN WESTERN NINE-LIKE BHALE;Po;0;L;;;;;N;;;;; +11B08;DEVANAGARI SIGN REVERSED NINE-LIKE BHALE;Po;0;L;;;;;N;;;;; +11B09;DEVANAGARI SIGN MINDU;Po;0;L;;;;;N;;;;; +11B60;SHARADA VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;; +11B61;SHARADA VOWEL SIGN OOE;Mc;0;L;;;;;N;;;;; +11B62;SHARADA VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;; +11B63;SHARADA VOWEL SIGN UUE;Mn;0;NSM;;;;;N;;;;; +11B64;SHARADA VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;; +11B65;SHARADA VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;; +11B66;SHARADA VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;; +11B67;SHARADA VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;; +11BC0;SUNUWAR LETTER DEVI;Lo;0;L;;;;;N;;;;; +11BC1;SUNUWAR LETTER TASLA;Lo;0;L;;;;;N;;;;; +11BC2;SUNUWAR LETTER EKO;Lo;0;L;;;;;N;;;;; +11BC3;SUNUWAR LETTER IMAR;Lo;0;L;;;;;N;;;;; +11BC4;SUNUWAR LETTER REU;Lo;0;L;;;;;N;;;;; +11BC5;SUNUWAR LETTER UTTHI;Lo;0;L;;;;;N;;;;; +11BC6;SUNUWAR LETTER KIK;Lo;0;L;;;;;N;;;;; +11BC7;SUNUWAR LETTER MA;Lo;0;L;;;;;N;;;;; +11BC8;SUNUWAR LETTER APPHO;Lo;0;L;;;;;N;;;;; +11BC9;SUNUWAR LETTER PIP;Lo;0;L;;;;;N;;;;; +11BCA;SUNUWAR LETTER GIL;Lo;0;L;;;;;N;;;;; +11BCB;SUNUWAR LETTER HAMSO;Lo;0;L;;;;;N;;;;; +11BCC;SUNUWAR LETTER CARMI;Lo;0;L;;;;;N;;;;; +11BCD;SUNUWAR LETTER NAH;Lo;0;L;;;;;N;;;;; +11BCE;SUNUWAR LETTER BUR;Lo;0;L;;;;;N;;;;; +11BCF;SUNUWAR LETTER JYAH;Lo;0;L;;;;;N;;;;; +11BD0;SUNUWAR LETTER LOACHA;Lo;0;L;;;;;N;;;;; +11BD1;SUNUWAR LETTER OTTHI;Lo;0;L;;;;;N;;;;; +11BD2;SUNUWAR LETTER SHYELE;Lo;0;L;;;;;N;;;;; +11BD3;SUNUWAR LETTER VARCA;Lo;0;L;;;;;N;;;;; +11BD4;SUNUWAR LETTER YAT;Lo;0;L;;;;;N;;;;; +11BD5;SUNUWAR LETTER AVA;Lo;0;L;;;;;N;;;;; +11BD6;SUNUWAR LETTER AAL;Lo;0;L;;;;;N;;;;; +11BD7;SUNUWAR LETTER DONGA;Lo;0;L;;;;;N;;;;; +11BD8;SUNUWAR LETTER THARI;Lo;0;L;;;;;N;;;;; +11BD9;SUNUWAR LETTER PHAR;Lo;0;L;;;;;N;;;;; +11BDA;SUNUWAR LETTER NGAR;Lo;0;L;;;;;N;;;;; +11BDB;SUNUWAR LETTER KHA;Lo;0;L;;;;;N;;;;; +11BDC;SUNUWAR LETTER SHYER;Lo;0;L;;;;;N;;;;; +11BDD;SUNUWAR LETTER CHELAP;Lo;0;L;;;;;N;;;;; +11BDE;SUNUWAR LETTER TENTU;Lo;0;L;;;;;N;;;;; +11BDF;SUNUWAR LETTER THELE;Lo;0;L;;;;;N;;;;; +11BE0;SUNUWAR LETTER KLOKO;Lo;0;L;;;;;N;;;;; +11BE1;SUNUWAR SIGN PVO;Po;0;L;;;;;N;;;;; +11BF0;SUNUWAR DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11BF1;SUNUWAR DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11BF2;SUNUWAR DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11BF3;SUNUWAR DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11BF4;SUNUWAR DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11BF5;SUNUWAR DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11BF6;SUNUWAR DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11BF7;SUNUWAR DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11BF8;SUNUWAR DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11BF9;SUNUWAR DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11C00;BHAIKSUKI LETTER A;Lo;0;L;;;;;N;;;;; +11C01;BHAIKSUKI LETTER AA;Lo;0;L;;;;;N;;;;; +11C02;BHAIKSUKI LETTER I;Lo;0;L;;;;;N;;;;; +11C03;BHAIKSUKI LETTER II;Lo;0;L;;;;;N;;;;; +11C04;BHAIKSUKI LETTER U;Lo;0;L;;;;;N;;;;; +11C05;BHAIKSUKI LETTER UU;Lo;0;L;;;;;N;;;;; +11C06;BHAIKSUKI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +11C07;BHAIKSUKI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11C08;BHAIKSUKI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +11C0A;BHAIKSUKI LETTER E;Lo;0;L;;;;;N;;;;; +11C0B;BHAIKSUKI LETTER AI;Lo;0;L;;;;;N;;;;; +11C0C;BHAIKSUKI LETTER O;Lo;0;L;;;;;N;;;;; +11C0D;BHAIKSUKI LETTER AU;Lo;0;L;;;;;N;;;;; +11C0E;BHAIKSUKI LETTER KA;Lo;0;L;;;;;N;;;;; +11C0F;BHAIKSUKI LETTER KHA;Lo;0;L;;;;;N;;;;; +11C10;BHAIKSUKI LETTER GA;Lo;0;L;;;;;N;;;;; +11C11;BHAIKSUKI LETTER GHA;Lo;0;L;;;;;N;;;;; +11C12;BHAIKSUKI LETTER NGA;Lo;0;L;;;;;N;;;;; +11C13;BHAIKSUKI LETTER CA;Lo;0;L;;;;;N;;;;; +11C14;BHAIKSUKI LETTER CHA;Lo;0;L;;;;;N;;;;; +11C15;BHAIKSUKI LETTER JA;Lo;0;L;;;;;N;;;;; +11C16;BHAIKSUKI LETTER JHA;Lo;0;L;;;;;N;;;;; +11C17;BHAIKSUKI LETTER NYA;Lo;0;L;;;;;N;;;;; +11C18;BHAIKSUKI LETTER TTA;Lo;0;L;;;;;N;;;;; +11C19;BHAIKSUKI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11C1A;BHAIKSUKI LETTER DDA;Lo;0;L;;;;;N;;;;; +11C1B;BHAIKSUKI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11C1C;BHAIKSUKI LETTER NNA;Lo;0;L;;;;;N;;;;; +11C1D;BHAIKSUKI LETTER TA;Lo;0;L;;;;;N;;;;; +11C1E;BHAIKSUKI LETTER THA;Lo;0;L;;;;;N;;;;; +11C1F;BHAIKSUKI LETTER DA;Lo;0;L;;;;;N;;;;; +11C20;BHAIKSUKI LETTER DHA;Lo;0;L;;;;;N;;;;; +11C21;BHAIKSUKI LETTER NA;Lo;0;L;;;;;N;;;;; +11C22;BHAIKSUKI LETTER PA;Lo;0;L;;;;;N;;;;; +11C23;BHAIKSUKI LETTER PHA;Lo;0;L;;;;;N;;;;; +11C24;BHAIKSUKI LETTER BA;Lo;0;L;;;;;N;;;;; +11C25;BHAIKSUKI LETTER BHA;Lo;0;L;;;;;N;;;;; +11C26;BHAIKSUKI LETTER MA;Lo;0;L;;;;;N;;;;; +11C27;BHAIKSUKI LETTER YA;Lo;0;L;;;;;N;;;;; +11C28;BHAIKSUKI LETTER RA;Lo;0;L;;;;;N;;;;; +11C29;BHAIKSUKI LETTER LA;Lo;0;L;;;;;N;;;;; +11C2A;BHAIKSUKI LETTER VA;Lo;0;L;;;;;N;;;;; +11C2B;BHAIKSUKI LETTER SHA;Lo;0;L;;;;;N;;;;; +11C2C;BHAIKSUKI LETTER SSA;Lo;0;L;;;;;N;;;;; +11C2D;BHAIKSUKI LETTER SA;Lo;0;L;;;;;N;;;;; +11C2E;BHAIKSUKI LETTER HA;Lo;0;L;;;;;N;;;;; +11C2F;BHAIKSUKI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11C30;BHAIKSUKI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11C31;BHAIKSUKI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +11C32;BHAIKSUKI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11C33;BHAIKSUKI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +11C34;BHAIKSUKI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +11C35;BHAIKSUKI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +11C36;BHAIKSUKI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +11C38;BHAIKSUKI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11C39;BHAIKSUKI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +11C3A;BHAIKSUKI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +11C3B;BHAIKSUKI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +11C3C;BHAIKSUKI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11C3D;BHAIKSUKI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11C3E;BHAIKSUKI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11C3F;BHAIKSUKI SIGN VIRAMA;Mn;9;L;;;;;N;;;;; +11C40;BHAIKSUKI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +11C41;BHAIKSUKI DANDA;Po;0;L;;;;;N;;;;; +11C42;BHAIKSUKI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +11C43;BHAIKSUKI WORD SEPARATOR;Po;0;L;;;;;N;;;;; +11C44;BHAIKSUKI GAP FILLER-1;Po;0;L;;;;;N;;;;; +11C45;BHAIKSUKI GAP FILLER-2;Po;0;L;;;;;N;;;;; +11C50;BHAIKSUKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11C51;BHAIKSUKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11C52;BHAIKSUKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11C53;BHAIKSUKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11C54;BHAIKSUKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11C55;BHAIKSUKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11C56;BHAIKSUKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11C57;BHAIKSUKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11C58;BHAIKSUKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11C59;BHAIKSUKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11C5A;BHAIKSUKI NUMBER ONE;No;0;L;;;;1;N;;;;; +11C5B;BHAIKSUKI NUMBER TWO;No;0;L;;;;2;N;;;;; +11C5C;BHAIKSUKI NUMBER THREE;No;0;L;;;;3;N;;;;; +11C5D;BHAIKSUKI NUMBER FOUR;No;0;L;;;;4;N;;;;; +11C5E;BHAIKSUKI NUMBER FIVE;No;0;L;;;;5;N;;;;; +11C5F;BHAIKSUKI NUMBER SIX;No;0;L;;;;6;N;;;;; +11C60;BHAIKSUKI NUMBER SEVEN;No;0;L;;;;7;N;;;;; +11C61;BHAIKSUKI NUMBER EIGHT;No;0;L;;;;8;N;;;;; +11C62;BHAIKSUKI NUMBER NINE;No;0;L;;;;9;N;;;;; +11C63;BHAIKSUKI NUMBER TEN;No;0;L;;;;10;N;;;;; +11C64;BHAIKSUKI NUMBER TWENTY;No;0;L;;;;20;N;;;;; +11C65;BHAIKSUKI NUMBER THIRTY;No;0;L;;;;30;N;;;;; +11C66;BHAIKSUKI NUMBER FORTY;No;0;L;;;;40;N;;;;; +11C67;BHAIKSUKI NUMBER FIFTY;No;0;L;;;;50;N;;;;; +11C68;BHAIKSUKI NUMBER SIXTY;No;0;L;;;;60;N;;;;; +11C69;BHAIKSUKI NUMBER SEVENTY;No;0;L;;;;70;N;;;;; +11C6A;BHAIKSUKI NUMBER EIGHTY;No;0;L;;;;80;N;;;;; +11C6B;BHAIKSUKI NUMBER NINETY;No;0;L;;;;90;N;;;;; +11C6C;BHAIKSUKI HUNDREDS UNIT MARK;No;0;L;;;;100;N;;;;; +11C70;MARCHEN HEAD MARK;Po;0;L;;;;;N;;;;; +11C71;MARCHEN MARK SHAD;Po;0;L;;;;;N;;;;; +11C72;MARCHEN LETTER KA;Lo;0;L;;;;;N;;;;; +11C73;MARCHEN LETTER KHA;Lo;0;L;;;;;N;;;;; +11C74;MARCHEN LETTER GA;Lo;0;L;;;;;N;;;;; +11C75;MARCHEN LETTER NGA;Lo;0;L;;;;;N;;;;; +11C76;MARCHEN LETTER CA;Lo;0;L;;;;;N;;;;; +11C77;MARCHEN LETTER CHA;Lo;0;L;;;;;N;;;;; +11C78;MARCHEN LETTER JA;Lo;0;L;;;;;N;;;;; +11C79;MARCHEN LETTER NYA;Lo;0;L;;;;;N;;;;; +11C7A;MARCHEN LETTER TA;Lo;0;L;;;;;N;;;;; +11C7B;MARCHEN LETTER THA;Lo;0;L;;;;;N;;;;; +11C7C;MARCHEN LETTER DA;Lo;0;L;;;;;N;;;;; +11C7D;MARCHEN LETTER NA;Lo;0;L;;;;;N;;;;; +11C7E;MARCHEN LETTER PA;Lo;0;L;;;;;N;;;;; +11C7F;MARCHEN LETTER PHA;Lo;0;L;;;;;N;;;;; +11C80;MARCHEN LETTER BA;Lo;0;L;;;;;N;;;;; +11C81;MARCHEN LETTER MA;Lo;0;L;;;;;N;;;;; +11C82;MARCHEN LETTER TSA;Lo;0;L;;;;;N;;;;; +11C83;MARCHEN LETTER TSHA;Lo;0;L;;;;;N;;;;; +11C84;MARCHEN LETTER DZA;Lo;0;L;;;;;N;;;;; +11C85;MARCHEN LETTER WA;Lo;0;L;;;;;N;;;;; +11C86;MARCHEN LETTER ZHA;Lo;0;L;;;;;N;;;;; +11C87;MARCHEN LETTER ZA;Lo;0;L;;;;;N;;;;; +11C88;MARCHEN LETTER -A;Lo;0;L;;;;;N;;;;; +11C89;MARCHEN LETTER YA;Lo;0;L;;;;;N;;;;; +11C8A;MARCHEN LETTER RA;Lo;0;L;;;;;N;;;;; +11C8B;MARCHEN LETTER LA;Lo;0;L;;;;;N;;;;; +11C8C;MARCHEN LETTER SHA;Lo;0;L;;;;;N;;;;; +11C8D;MARCHEN LETTER SA;Lo;0;L;;;;;N;;;;; +11C8E;MARCHEN LETTER HA;Lo;0;L;;;;;N;;;;; +11C8F;MARCHEN LETTER A;Lo;0;L;;;;;N;;;;; +11C92;MARCHEN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;; +11C93;MARCHEN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;; +11C94;MARCHEN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;; +11C95;MARCHEN SUBJOINED LETTER NGA;Mn;0;NSM;;;;;N;;;;; +11C96;MARCHEN SUBJOINED LETTER CA;Mn;0;NSM;;;;;N;;;;; +11C97;MARCHEN SUBJOINED LETTER CHA;Mn;0;NSM;;;;;N;;;;; +11C98;MARCHEN SUBJOINED LETTER JA;Mn;0;NSM;;;;;N;;;;; +11C99;MARCHEN SUBJOINED LETTER NYA;Mn;0;NSM;;;;;N;;;;; +11C9A;MARCHEN SUBJOINED LETTER TA;Mn;0;NSM;;;;;N;;;;; +11C9B;MARCHEN SUBJOINED LETTER THA;Mn;0;NSM;;;;;N;;;;; +11C9C;MARCHEN SUBJOINED LETTER DA;Mn;0;NSM;;;;;N;;;;; +11C9D;MARCHEN SUBJOINED LETTER NA;Mn;0;NSM;;;;;N;;;;; +11C9E;MARCHEN SUBJOINED LETTER PA;Mn;0;NSM;;;;;N;;;;; +11C9F;MARCHEN SUBJOINED LETTER PHA;Mn;0;NSM;;;;;N;;;;; +11CA0;MARCHEN SUBJOINED LETTER BA;Mn;0;NSM;;;;;N;;;;; +11CA1;MARCHEN SUBJOINED LETTER MA;Mn;0;NSM;;;;;N;;;;; +11CA2;MARCHEN SUBJOINED LETTER TSA;Mn;0;NSM;;;;;N;;;;; +11CA3;MARCHEN SUBJOINED LETTER TSHA;Mn;0;NSM;;;;;N;;;;; +11CA4;MARCHEN SUBJOINED LETTER DZA;Mn;0;NSM;;;;;N;;;;; +11CA5;MARCHEN SUBJOINED LETTER WA;Mn;0;NSM;;;;;N;;;;; +11CA6;MARCHEN SUBJOINED LETTER ZHA;Mn;0;NSM;;;;;N;;;;; +11CA7;MARCHEN SUBJOINED LETTER ZA;Mn;0;NSM;;;;;N;;;;; +11CA9;MARCHEN SUBJOINED LETTER YA;Mc;0;L;;;;;N;;;;; +11CAA;MARCHEN SUBJOINED LETTER RA;Mn;0;NSM;;;;;N;;;;; +11CAB;MARCHEN SUBJOINED LETTER LA;Mn;0;NSM;;;;;N;;;;; +11CAC;MARCHEN SUBJOINED LETTER SHA;Mn;0;NSM;;;;;N;;;;; +11CAD;MARCHEN SUBJOINED LETTER SA;Mn;0;NSM;;;;;N;;;;; +11CAE;MARCHEN SUBJOINED LETTER HA;Mn;0;NSM;;;;;N;;;;; +11CAF;MARCHEN SUBJOINED LETTER A;Mn;0;NSM;;;;;N;;;;; +11CB0;MARCHEN VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; +11CB1;MARCHEN VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +11CB2;MARCHEN VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11CB3;MARCHEN VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11CB4;MARCHEN VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +11CB5;MARCHEN SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11CB6;MARCHEN SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11D00;MASARAM GONDI LETTER A;Lo;0;L;;;;;N;;;;; +11D01;MASARAM GONDI LETTER AA;Lo;0;L;;;;;N;;;;; +11D02;MASARAM GONDI LETTER I;Lo;0;L;;;;;N;;;;; +11D03;MASARAM GONDI LETTER II;Lo;0;L;;;;;N;;;;; +11D04;MASARAM GONDI LETTER U;Lo;0;L;;;;;N;;;;; +11D05;MASARAM GONDI LETTER UU;Lo;0;L;;;;;N;;;;; +11D06;MASARAM GONDI LETTER E;Lo;0;L;;;;;N;;;;; +11D08;MASARAM GONDI LETTER AI;Lo;0;L;;;;;N;;;;; +11D09;MASARAM GONDI LETTER O;Lo;0;L;;;;;N;;;;; +11D0B;MASARAM GONDI LETTER AU;Lo;0;L;;;;;N;;;;; +11D0C;MASARAM GONDI LETTER KA;Lo;0;L;;;;;N;;;;; +11D0D;MASARAM GONDI LETTER KHA;Lo;0;L;;;;;N;;;;; +11D0E;MASARAM GONDI LETTER GA;Lo;0;L;;;;;N;;;;; +11D0F;MASARAM GONDI LETTER GHA;Lo;0;L;;;;;N;;;;; +11D10;MASARAM GONDI LETTER NGA;Lo;0;L;;;;;N;;;;; +11D11;MASARAM GONDI LETTER CA;Lo;0;L;;;;;N;;;;; +11D12;MASARAM GONDI LETTER CHA;Lo;0;L;;;;;N;;;;; +11D13;MASARAM GONDI LETTER JA;Lo;0;L;;;;;N;;;;; +11D14;MASARAM GONDI LETTER JHA;Lo;0;L;;;;;N;;;;; +11D15;MASARAM GONDI LETTER NYA;Lo;0;L;;;;;N;;;;; +11D16;MASARAM GONDI LETTER TTA;Lo;0;L;;;;;N;;;;; +11D17;MASARAM GONDI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11D18;MASARAM GONDI LETTER DDA;Lo;0;L;;;;;N;;;;; +11D19;MASARAM GONDI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11D1A;MASARAM GONDI LETTER NNA;Lo;0;L;;;;;N;;;;; +11D1B;MASARAM GONDI LETTER TA;Lo;0;L;;;;;N;;;;; +11D1C;MASARAM GONDI LETTER THA;Lo;0;L;;;;;N;;;;; +11D1D;MASARAM GONDI LETTER DA;Lo;0;L;;;;;N;;;;; +11D1E;MASARAM GONDI LETTER DHA;Lo;0;L;;;;;N;;;;; +11D1F;MASARAM GONDI LETTER NA;Lo;0;L;;;;;N;;;;; +11D20;MASARAM GONDI LETTER PA;Lo;0;L;;;;;N;;;;; +11D21;MASARAM GONDI LETTER PHA;Lo;0;L;;;;;N;;;;; +11D22;MASARAM GONDI LETTER BA;Lo;0;L;;;;;N;;;;; +11D23;MASARAM GONDI LETTER BHA;Lo;0;L;;;;;N;;;;; +11D24;MASARAM GONDI LETTER MA;Lo;0;L;;;;;N;;;;; +11D25;MASARAM GONDI LETTER YA;Lo;0;L;;;;;N;;;;; +11D26;MASARAM GONDI LETTER RA;Lo;0;L;;;;;N;;;;; +11D27;MASARAM GONDI LETTER LA;Lo;0;L;;;;;N;;;;; +11D28;MASARAM GONDI LETTER VA;Lo;0;L;;;;;N;;;;; +11D29;MASARAM GONDI LETTER SHA;Lo;0;L;;;;;N;;;;; +11D2A;MASARAM GONDI LETTER SSA;Lo;0;L;;;;;N;;;;; +11D2B;MASARAM GONDI LETTER SA;Lo;0;L;;;;;N;;;;; +11D2C;MASARAM GONDI LETTER HA;Lo;0;L;;;;;N;;;;; +11D2D;MASARAM GONDI LETTER LLA;Lo;0;L;;;;;N;;;;; +11D2E;MASARAM GONDI LETTER KSSA;Lo;0;L;;;;;N;;;;; +11D2F;MASARAM GONDI LETTER JNYA;Lo;0;L;;;;;N;;;;; +11D30;MASARAM GONDI LETTER TRA;Lo;0;L;;;;;N;;;;; +11D31;MASARAM GONDI VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; +11D32;MASARAM GONDI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11D33;MASARAM GONDI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +11D34;MASARAM GONDI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11D35;MASARAM GONDI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +11D36;MASARAM GONDI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +11D3A;MASARAM GONDI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11D3C;MASARAM GONDI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +11D3D;MASARAM GONDI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +11D3F;MASARAM GONDI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +11D40;MASARAM GONDI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11D41;MASARAM GONDI SIGN VISARGA;Mn;0;NSM;;;;;N;;;;; +11D42;MASARAM GONDI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +11D43;MASARAM GONDI SIGN CANDRA;Mn;0;NSM;;;;;N;;;;; +11D44;MASARAM GONDI SIGN HALANTA;Mn;9;NSM;;;;;N;;;;; +11D45;MASARAM GONDI VIRAMA;Mn;9;NSM;;;;;N;;;;; +11D46;MASARAM GONDI REPHA;Lo;0;L;;;;;N;;;;; +11D47;MASARAM GONDI RA-KARA;Mn;0;NSM;;;;;N;;;;; +11D50;MASARAM GONDI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11D51;MASARAM GONDI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11D52;MASARAM GONDI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11D53;MASARAM GONDI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11D54;MASARAM GONDI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11D55;MASARAM GONDI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11D56;MASARAM GONDI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11D57;MASARAM GONDI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11D58;MASARAM GONDI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11D59;MASARAM GONDI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11D60;GUNJALA GONDI LETTER A;Lo;0;L;;;;;N;;;;; +11D61;GUNJALA GONDI LETTER AA;Lo;0;L;;;;;N;;;;; +11D62;GUNJALA GONDI LETTER I;Lo;0;L;;;;;N;;;;; +11D63;GUNJALA GONDI LETTER II;Lo;0;L;;;;;N;;;;; +11D64;GUNJALA GONDI LETTER U;Lo;0;L;;;;;N;;;;; +11D65;GUNJALA GONDI LETTER UU;Lo;0;L;;;;;N;;;;; +11D67;GUNJALA GONDI LETTER EE;Lo;0;L;;;;;N;;;;; +11D68;GUNJALA GONDI LETTER AI;Lo;0;L;;;;;N;;;;; +11D6A;GUNJALA GONDI LETTER OO;Lo;0;L;;;;;N;;;;; +11D6B;GUNJALA GONDI LETTER AU;Lo;0;L;;;;;N;;;;; +11D6C;GUNJALA GONDI LETTER YA;Lo;0;L;;;;;N;;;;; +11D6D;GUNJALA GONDI LETTER VA;Lo;0;L;;;;;N;;;;; +11D6E;GUNJALA GONDI LETTER BA;Lo;0;L;;;;;N;;;;; +11D6F;GUNJALA GONDI LETTER BHA;Lo;0;L;;;;;N;;;;; +11D70;GUNJALA GONDI LETTER MA;Lo;0;L;;;;;N;;;;; +11D71;GUNJALA GONDI LETTER KA;Lo;0;L;;;;;N;;;;; +11D72;GUNJALA GONDI LETTER KHA;Lo;0;L;;;;;N;;;;; +11D73;GUNJALA GONDI LETTER TA;Lo;0;L;;;;;N;;;;; +11D74;GUNJALA GONDI LETTER THA;Lo;0;L;;;;;N;;;;; +11D75;GUNJALA GONDI LETTER LA;Lo;0;L;;;;;N;;;;; +11D76;GUNJALA GONDI LETTER GA;Lo;0;L;;;;;N;;;;; +11D77;GUNJALA GONDI LETTER GHA;Lo;0;L;;;;;N;;;;; +11D78;GUNJALA GONDI LETTER DA;Lo;0;L;;;;;N;;;;; +11D79;GUNJALA GONDI LETTER DHA;Lo;0;L;;;;;N;;;;; +11D7A;GUNJALA GONDI LETTER NA;Lo;0;L;;;;;N;;;;; +11D7B;GUNJALA GONDI LETTER CA;Lo;0;L;;;;;N;;;;; +11D7C;GUNJALA GONDI LETTER CHA;Lo;0;L;;;;;N;;;;; +11D7D;GUNJALA GONDI LETTER TTA;Lo;0;L;;;;;N;;;;; +11D7E;GUNJALA GONDI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11D7F;GUNJALA GONDI LETTER LLA;Lo;0;L;;;;;N;;;;; +11D80;GUNJALA GONDI LETTER JA;Lo;0;L;;;;;N;;;;; +11D81;GUNJALA GONDI LETTER JHA;Lo;0;L;;;;;N;;;;; +11D82;GUNJALA GONDI LETTER DDA;Lo;0;L;;;;;N;;;;; +11D83;GUNJALA GONDI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11D84;GUNJALA GONDI LETTER NGA;Lo;0;L;;;;;N;;;;; +11D85;GUNJALA GONDI LETTER PA;Lo;0;L;;;;;N;;;;; +11D86;GUNJALA GONDI LETTER PHA;Lo;0;L;;;;;N;;;;; +11D87;GUNJALA GONDI LETTER HA;Lo;0;L;;;;;N;;;;; +11D88;GUNJALA GONDI LETTER RA;Lo;0;L;;;;;N;;;;; +11D89;GUNJALA GONDI LETTER SA;Lo;0;L;;;;;N;;;;; +11D8A;GUNJALA GONDI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11D8B;GUNJALA GONDI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +11D8C;GUNJALA GONDI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +11D8D;GUNJALA GONDI VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +11D8E;GUNJALA GONDI VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +11D90;GUNJALA GONDI VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;; +11D91;GUNJALA GONDI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +11D93;GUNJALA GONDI VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; +11D94;GUNJALA GONDI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +11D95;GUNJALA GONDI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11D96;GUNJALA GONDI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11D97;GUNJALA GONDI VIRAMA;Mn;9;NSM;;;;;N;;;;; +11D98;GUNJALA GONDI OM;Lo;0;L;;;;;N;;;;; +11DA0;GUNJALA GONDI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11DA1;GUNJALA GONDI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11DA2;GUNJALA GONDI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11DA3;GUNJALA GONDI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11DA4;GUNJALA GONDI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11DA5;GUNJALA GONDI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11DA6;GUNJALA GONDI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11DA7;GUNJALA GONDI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11DA8;GUNJALA GONDI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11DA9;GUNJALA GONDI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11DB0;TOLONG SIKI LETTER I;Lo;0;L;;;;;N;;;;; +11DB1;TOLONG SIKI LETTER E;Lo;0;L;;;;;N;;;;; +11DB2;TOLONG SIKI LETTER U;Lo;0;L;;;;;N;;;;; +11DB3;TOLONG SIKI LETTER O;Lo;0;L;;;;;N;;;;; +11DB4;TOLONG SIKI LETTER A;Lo;0;L;;;;;N;;;;; +11DB5;TOLONG SIKI LETTER AA;Lo;0;L;;;;;N;;;;; +11DB6;TOLONG SIKI LETTER P;Lo;0;L;;;;;N;;;;; +11DB7;TOLONG SIKI LETTER PH;Lo;0;L;;;;;N;;;;; +11DB8;TOLONG SIKI LETTER B;Lo;0;L;;;;;N;;;;; +11DB9;TOLONG SIKI LETTER BH;Lo;0;L;;;;;N;;;;; +11DBA;TOLONG SIKI LETTER M;Lo;0;L;;;;;N;;;;; +11DBB;TOLONG SIKI LETTER T;Lo;0;L;;;;;N;;;;; +11DBC;TOLONG SIKI LETTER TH;Lo;0;L;;;;;N;;;;; +11DBD;TOLONG SIKI LETTER D;Lo;0;L;;;;;N;;;;; +11DBE;TOLONG SIKI LETTER DH;Lo;0;L;;;;;N;;;;; +11DBF;TOLONG SIKI LETTER N;Lo;0;L;;;;;N;;;;; +11DC0;TOLONG SIKI LETTER TT;Lo;0;L;;;;;N;;;;; +11DC1;TOLONG SIKI LETTER TTH;Lo;0;L;;;;;N;;;;; +11DC2;TOLONG SIKI LETTER DD;Lo;0;L;;;;;N;;;;; +11DC3;TOLONG SIKI LETTER DDH;Lo;0;L;;;;;N;;;;; +11DC4;TOLONG SIKI LETTER NN;Lo;0;L;;;;;N;;;;; +11DC5;TOLONG SIKI LETTER C;Lo;0;L;;;;;N;;;;; +11DC6;TOLONG SIKI LETTER CH;Lo;0;L;;;;;N;;;;; +11DC7;TOLONG SIKI LETTER J;Lo;0;L;;;;;N;;;;; +11DC8;TOLONG SIKI LETTER JH;Lo;0;L;;;;;N;;;;; +11DC9;TOLONG SIKI LETTER NY;Lo;0;L;;;;;N;;;;; +11DCA;TOLONG SIKI LETTER K;Lo;0;L;;;;;N;;;;; +11DCB;TOLONG SIKI LETTER KH;Lo;0;L;;;;;N;;;;; +11DCC;TOLONG SIKI LETTER G;Lo;0;L;;;;;N;;;;; +11DCD;TOLONG SIKI LETTER GH;Lo;0;L;;;;;N;;;;; +11DCE;TOLONG SIKI LETTER NG;Lo;0;L;;;;;N;;;;; +11DCF;TOLONG SIKI LETTER Y;Lo;0;L;;;;;N;;;;; +11DD0;TOLONG SIKI LETTER R;Lo;0;L;;;;;N;;;;; +11DD1;TOLONG SIKI LETTER L;Lo;0;L;;;;;N;;;;; +11DD2;TOLONG SIKI LETTER V;Lo;0;L;;;;;N;;;;; +11DD3;TOLONG SIKI LETTER NNY;Lo;0;L;;;;;N;;;;; +11DD4;TOLONG SIKI LETTER S;Lo;0;L;;;;;N;;;;; +11DD5;TOLONG SIKI LETTER H;Lo;0;L;;;;;N;;;;; +11DD6;TOLONG SIKI LETTER X;Lo;0;L;;;;;N;;;;; +11DD7;TOLONG SIKI LETTER RR;Lo;0;L;;;;;N;;;;; +11DD8;TOLONG SIKI LETTER RRH;Lo;0;L;;;;;N;;;;; +11DD9;TOLONG SIKI SIGN SELA;Lm;0;L;;;;;N;;;;; +11DDA;TOLONG SIKI SIGN HECAKA;Lo;0;L;;;;;N;;;;; +11DDB;TOLONG SIKI UNGGA;Lo;0;L;;;;;N;;;;; +11DE0;TOLONG SIKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11DE1;TOLONG SIKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11DE2;TOLONG SIKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11DE3;TOLONG SIKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11DE4;TOLONG SIKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11DE5;TOLONG SIKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11DE6;TOLONG SIKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11DE7;TOLONG SIKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11DE8;TOLONG SIKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11DE9;TOLONG SIKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11EE0;MAKASAR LETTER KA;Lo;0;L;;;;;N;;;;; +11EE1;MAKASAR LETTER GA;Lo;0;L;;;;;N;;;;; +11EE2;MAKASAR LETTER NGA;Lo;0;L;;;;;N;;;;; +11EE3;MAKASAR LETTER PA;Lo;0;L;;;;;N;;;;; +11EE4;MAKASAR LETTER BA;Lo;0;L;;;;;N;;;;; +11EE5;MAKASAR LETTER MA;Lo;0;L;;;;;N;;;;; +11EE6;MAKASAR LETTER TA;Lo;0;L;;;;;N;;;;; +11EE7;MAKASAR LETTER DA;Lo;0;L;;;;;N;;;;; +11EE8;MAKASAR LETTER NA;Lo;0;L;;;;;N;;;;; +11EE9;MAKASAR LETTER CA;Lo;0;L;;;;;N;;;;; +11EEA;MAKASAR LETTER JA;Lo;0;L;;;;;N;;;;; +11EEB;MAKASAR LETTER NYA;Lo;0;L;;;;;N;;;;; +11EEC;MAKASAR LETTER YA;Lo;0;L;;;;;N;;;;; +11EED;MAKASAR LETTER RA;Lo;0;L;;;;;N;;;;; +11EEE;MAKASAR LETTER LA;Lo;0;L;;;;;N;;;;; +11EEF;MAKASAR LETTER VA;Lo;0;L;;;;;N;;;;; +11EF0;MAKASAR LETTER SA;Lo;0;L;;;;;N;;;;; +11EF1;MAKASAR LETTER A;Lo;0;L;;;;;N;;;;; +11EF2;MAKASAR ANGKA;Lo;0;L;;;;;N;;;;; +11EF3;MAKASAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11EF4;MAKASAR VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11EF5;MAKASAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +11EF6;MAKASAR VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +11EF7;MAKASAR PASSIMBANG;Po;0;L;;;;;N;;;;; +11EF8;MAKASAR END OF SECTION;Po;0;L;;;;;N;;;;; +11F00;KAWI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11F01;KAWI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11F02;KAWI SIGN REPHA;Lo;0;L;;;;;N;;;;; +11F03;KAWI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11F04;KAWI LETTER A;Lo;0;L;;;;;N;;;;; +11F05;KAWI LETTER AA;Lo;0;L;;;;;N;;;;; +11F06;KAWI LETTER I;Lo;0;L;;;;;N;;;;; +11F07;KAWI LETTER II;Lo;0;L;;;;;N;;;;; +11F08;KAWI LETTER U;Lo;0;L;;;;;N;;;;; +11F09;KAWI LETTER UU;Lo;0;L;;;;;N;;;;; +11F0A;KAWI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +11F0B;KAWI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11F0C;KAWI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +11F0D;KAWI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +11F0E;KAWI LETTER E;Lo;0;L;;;;;N;;;;; +11F0F;KAWI LETTER AI;Lo;0;L;;;;;N;;;;; +11F10;KAWI LETTER O;Lo;0;L;;;;;N;;;;; +11F12;KAWI LETTER KA;Lo;0;L;;;;;N;;;;; +11F13;KAWI LETTER KHA;Lo;0;L;;;;;N;;;;; +11F14;KAWI LETTER GA;Lo;0;L;;;;;N;;;;; +11F15;KAWI LETTER GHA;Lo;0;L;;;;;N;;;;; +11F16;KAWI LETTER NGA;Lo;0;L;;;;;N;;;;; +11F17;KAWI LETTER CA;Lo;0;L;;;;;N;;;;; +11F18;KAWI LETTER CHA;Lo;0;L;;;;;N;;;;; +11F19;KAWI LETTER JA;Lo;0;L;;;;;N;;;;; +11F1A;KAWI LETTER JHA;Lo;0;L;;;;;N;;;;; +11F1B;KAWI LETTER NYA;Lo;0;L;;;;;N;;;;; +11F1C;KAWI LETTER TTA;Lo;0;L;;;;;N;;;;; +11F1D;KAWI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11F1E;KAWI LETTER DDA;Lo;0;L;;;;;N;;;;; +11F1F;KAWI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11F20;KAWI LETTER NNA;Lo;0;L;;;;;N;;;;; +11F21;KAWI LETTER TA;Lo;0;L;;;;;N;;;;; +11F22;KAWI LETTER THA;Lo;0;L;;;;;N;;;;; +11F23;KAWI LETTER DA;Lo;0;L;;;;;N;;;;; +11F24;KAWI LETTER DHA;Lo;0;L;;;;;N;;;;; +11F25;KAWI LETTER NA;Lo;0;L;;;;;N;;;;; +11F26;KAWI LETTER PA;Lo;0;L;;;;;N;;;;; +11F27;KAWI LETTER PHA;Lo;0;L;;;;;N;;;;; +11F28;KAWI LETTER BA;Lo;0;L;;;;;N;;;;; +11F29;KAWI LETTER BHA;Lo;0;L;;;;;N;;;;; +11F2A;KAWI LETTER MA;Lo;0;L;;;;;N;;;;; +11F2B;KAWI LETTER YA;Lo;0;L;;;;;N;;;;; +11F2C;KAWI LETTER RA;Lo;0;L;;;;;N;;;;; +11F2D;KAWI LETTER LA;Lo;0;L;;;;;N;;;;; +11F2E;KAWI LETTER WA;Lo;0;L;;;;;N;;;;; +11F2F;KAWI LETTER SHA;Lo;0;L;;;;;N;;;;; +11F30;KAWI LETTER SSA;Lo;0;L;;;;;N;;;;; +11F31;KAWI LETTER SA;Lo;0;L;;;;;N;;;;; +11F32;KAWI LETTER HA;Lo;0;L;;;;;N;;;;; +11F33;KAWI LETTER JNYA;Lo;0;L;;;;;N;;;;; +11F34;KAWI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11F35;KAWI VOWEL SIGN ALTERNATE AA;Mc;0;L;;;;;N;;;;; +11F36;KAWI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11F37;KAWI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +11F38;KAWI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11F39;KAWI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +11F3A;KAWI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +11F3E;KAWI VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +11F3F;KAWI VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +11F40;KAWI VOWEL SIGN EU;Mn;0;NSM;;;;;N;;;;; +11F41;KAWI SIGN KILLER;Mc;9;L;;;;;N;;;;; +11F42;KAWI CONJOINER;Mn;9;NSM;;;;;N;;;;; +11F43;KAWI DANDA;Po;0;L;;;;;N;;;;; +11F44;KAWI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +11F45;KAWI PUNCTUATION SECTION MARKER;Po;0;L;;;;;N;;;;; +11F46;KAWI PUNCTUATION ALTERNATE SECTION MARKER;Po;0;L;;;;;N;;;;; +11F47;KAWI PUNCTUATION FLOWER;Po;0;L;;;;;N;;;;; +11F48;KAWI PUNCTUATION SPACE FILLER;Po;0;L;;;;;N;;;;; +11F49;KAWI PUNCTUATION DOT;Po;0;L;;;;;N;;;;; +11F4A;KAWI PUNCTUATION DOUBLE DOT;Po;0;L;;;;;N;;;;; +11F4B;KAWI PUNCTUATION TRIPLE DOT;Po;0;L;;;;;N;;;;; +11F4C;KAWI PUNCTUATION CIRCLE;Po;0;L;;;;;N;;;;; +11F4D;KAWI PUNCTUATION FILLED CIRCLE;Po;0;L;;;;;N;;;;; +11F4E;KAWI PUNCTUATION SPIRAL;Po;0;L;;;;;N;;;;; +11F4F;KAWI PUNCTUATION CLOSING SPIRAL;Po;0;L;;;;;N;;;;; +11F50;KAWI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11F51;KAWI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11F52;KAWI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11F53;KAWI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11F54;KAWI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11F55;KAWI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11F56;KAWI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11F57;KAWI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11F58;KAWI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11F59;KAWI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11F5A;KAWI SIGN NUKTA;Mn;0;NSM;;;;;N;;;;; +11FB0;LISU LETTER YHA;Lo;0;L;;;;;N;;;;; +11FC0;TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH;No;0;L;;;;1/320;N;;;;; +11FC1;TAMIL FRACTION ONE ONE-HUNDRED-AND-SIXTIETH;No;0;L;;;;1/160;N;;;;; +11FC2;TAMIL FRACTION ONE EIGHTIETH;No;0;L;;;;1/80;N;;;;; +11FC3;TAMIL FRACTION ONE SIXTY-FOURTH;No;0;L;;;;1/64;N;;;;; +11FC4;TAMIL FRACTION ONE FORTIETH;No;0;L;;;;1/40;N;;;;; +11FC5;TAMIL FRACTION ONE THIRTY-SECOND;No;0;L;;;;1/32;N;;;;; +11FC6;TAMIL FRACTION THREE EIGHTIETHS;No;0;L;;;;3/80;N;;;;; +11FC7;TAMIL FRACTION THREE SIXTY-FOURTHS;No;0;L;;;;3/64;N;;;;; +11FC8;TAMIL FRACTION ONE TWENTIETH;No;0;L;;;;1/20;N;;;;; +11FC9;TAMIL FRACTION ONE SIXTEENTH-1;No;0;L;;;;1/16;N;;;;; +11FCA;TAMIL FRACTION ONE SIXTEENTH-2;No;0;L;;;;1/16;N;;;;; +11FCB;TAMIL FRACTION ONE TENTH;No;0;L;;;;1/10;N;;;;; +11FCC;TAMIL FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;; +11FCD;TAMIL FRACTION THREE TWENTIETHS;No;0;L;;;;3/20;N;;;;; +11FCE;TAMIL FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;; +11FCF;TAMIL FRACTION ONE FIFTH;No;0;L;;;;1/5;N;;;;; +11FD0;TAMIL FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;; +11FD1;TAMIL FRACTION ONE HALF-1;No;0;L;;;;1/2;N;;;;; +11FD2;TAMIL FRACTION ONE HALF-2;No;0;L;;;;1/2;N;;;;; +11FD3;TAMIL FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;; +11FD4;TAMIL FRACTION DOWNSCALING FACTOR KIIZH;No;0;L;;;;1/320;N;;;;; +11FD5;TAMIL SIGN NEL;So;0;ON;;;;;N;;;;; +11FD6;TAMIL SIGN CEVITU;So;0;ON;;;;;N;;;;; +11FD7;TAMIL SIGN AAZHAAKKU;So;0;ON;;;;;N;;;;; +11FD8;TAMIL SIGN UZHAKKU;So;0;ON;;;;;N;;;;; +11FD9;TAMIL SIGN MUUVUZHAKKU;So;0;ON;;;;;N;;;;; +11FDA;TAMIL SIGN KURUNI;So;0;ON;;;;;N;;;;; +11FDB;TAMIL SIGN PATHAKKU;So;0;ON;;;;;N;;;;; +11FDC;TAMIL SIGN MUKKURUNI;So;0;ON;;;;;N;;;;; +11FDD;TAMIL SIGN KAACU;Sc;0;ET;;;;;N;;;;; +11FDE;TAMIL SIGN PANAM;Sc;0;ET;;;;;N;;;;; +11FDF;TAMIL SIGN PON;Sc;0;ET;;;;;N;;;;; +11FE0;TAMIL SIGN VARAAKAN;Sc;0;ET;;;;;N;;;;; +11FE1;TAMIL SIGN PAARAM;So;0;ON;;;;;N;;;;; +11FE2;TAMIL SIGN KUZHI;So;0;ON;;;;;N;;;;; +11FE3;TAMIL SIGN VELI;So;0;ON;;;;;N;;;;; +11FE4;TAMIL WET CULTIVATION SIGN;So;0;ON;;;;;N;;;;; +11FE5;TAMIL DRY CULTIVATION SIGN;So;0;ON;;;;;N;;;;; +11FE6;TAMIL LAND SIGN;So;0;ON;;;;;N;;;;; +11FE7;TAMIL SALT PAN SIGN;So;0;ON;;;;;N;;;;; +11FE8;TAMIL TRADITIONAL CREDIT SIGN;So;0;ON;;;;;N;;;;; +11FE9;TAMIL TRADITIONAL NUMBER SIGN;So;0;ON;;;;;N;;;;; +11FEA;TAMIL CURRENT SIGN;So;0;ON;;;;;N;;;;; +11FEB;TAMIL AND ODD SIGN;So;0;ON;;;;;N;;;;; +11FEC;TAMIL SPENT SIGN;So;0;ON;;;;;N;;;;; +11FED;TAMIL TOTAL SIGN;So;0;ON;;;;;N;;;;; +11FEE;TAMIL IN POSSESSION SIGN;So;0;ON;;;;;N;;;;; +11FEF;TAMIL STARTING FROM SIGN;So;0;ON;;;;;N;;;;; +11FF0;TAMIL SIGN MUTHALIYA;So;0;ON;;;;;N;;;;; +11FF1;TAMIL SIGN VAKAIYARAA;So;0;ON;;;;;N;;;;; +11FFF;TAMIL PUNCTUATION END OF TEXT;Po;0;L;;;;;N;;;;; +12000;CUNEIFORM SIGN A;Lo;0;L;;;;;N;;;;; +12001;CUNEIFORM SIGN A TIMES A;Lo;0;L;;;;;N;;;;; +12002;CUNEIFORM SIGN A TIMES BAD;Lo;0;L;;;;;N;;;;; +12003;CUNEIFORM SIGN A TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +12004;CUNEIFORM SIGN A TIMES HA;Lo;0;L;;;;;N;;;;; +12005;CUNEIFORM SIGN A TIMES IGI;Lo;0;L;;;;;N;;;;; +12006;CUNEIFORM SIGN A TIMES LAGAR GUNU;Lo;0;L;;;;;N;;;;; +12007;CUNEIFORM SIGN A TIMES MUSH;Lo;0;L;;;;;N;;;;; +12008;CUNEIFORM SIGN A TIMES SAG;Lo;0;L;;;;;N;;;;; +12009;CUNEIFORM SIGN A2;Lo;0;L;;;;;N;;;;; +1200A;CUNEIFORM SIGN AB;Lo;0;L;;;;;N;;;;; +1200B;CUNEIFORM SIGN AB TIMES ASH2;Lo;0;L;;;;;N;;;;; +1200C;CUNEIFORM SIGN AB TIMES DUN3 GUNU;Lo;0;L;;;;;N;;;;; +1200D;CUNEIFORM SIGN AB TIMES GAL;Lo;0;L;;;;;N;;;;; +1200E;CUNEIFORM SIGN AB TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +1200F;CUNEIFORM SIGN AB TIMES HA;Lo;0;L;;;;;N;;;;; +12010;CUNEIFORM SIGN AB TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +12011;CUNEIFORM SIGN AB TIMES IMIN;Lo;0;L;;;;;N;;;;; +12012;CUNEIFORM SIGN AB TIMES LAGAB;Lo;0;L;;;;;N;;;;; +12013;CUNEIFORM SIGN AB TIMES SHESH;Lo;0;L;;;;;N;;;;; +12014;CUNEIFORM SIGN AB TIMES U PLUS U PLUS U;Lo;0;L;;;;;N;;;;; +12015;CUNEIFORM SIGN AB GUNU;Lo;0;L;;;;;N;;;;; +12016;CUNEIFORM SIGN AB2;Lo;0;L;;;;;N;;;;; +12017;CUNEIFORM SIGN AB2 TIMES BALAG;Lo;0;L;;;;;N;;;;; +12018;CUNEIFORM SIGN AB2 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +12019;CUNEIFORM SIGN AB2 TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;; +1201A;CUNEIFORM SIGN AB2 TIMES SHA3;Lo;0;L;;;;;N;;;;; +1201B;CUNEIFORM SIGN AB2 TIMES TAK4;Lo;0;L;;;;;N;;;;; +1201C;CUNEIFORM SIGN AD;Lo;0;L;;;;;N;;;;; +1201D;CUNEIFORM SIGN AK;Lo;0;L;;;;;N;;;;; +1201E;CUNEIFORM SIGN AK TIMES ERIN2;Lo;0;L;;;;;N;;;;; +1201F;CUNEIFORM SIGN AK TIMES SHITA PLUS GISH;Lo;0;L;;;;;N;;;;; +12020;CUNEIFORM SIGN AL;Lo;0;L;;;;;N;;;;; +12021;CUNEIFORM SIGN AL TIMES AL;Lo;0;L;;;;;N;;;;; +12022;CUNEIFORM SIGN AL TIMES DIM2;Lo;0;L;;;;;N;;;;; +12023;CUNEIFORM SIGN AL TIMES GISH;Lo;0;L;;;;;N;;;;; +12024;CUNEIFORM SIGN AL TIMES HA;Lo;0;L;;;;;N;;;;; +12025;CUNEIFORM SIGN AL TIMES KAD3;Lo;0;L;;;;;N;;;;; +12026;CUNEIFORM SIGN AL TIMES KI;Lo;0;L;;;;;N;;;;; +12027;CUNEIFORM SIGN AL TIMES SHE;Lo;0;L;;;;;N;;;;; +12028;CUNEIFORM SIGN AL TIMES USH;Lo;0;L;;;;;N;;;;; +12029;CUNEIFORM SIGN ALAN;Lo;0;L;;;;;N;;;;; +1202A;CUNEIFORM SIGN ALEPH;Lo;0;L;;;;;N;;;;; +1202B;CUNEIFORM SIGN AMAR;Lo;0;L;;;;;N;;;;; +1202C;CUNEIFORM SIGN AMAR TIMES SHE;Lo;0;L;;;;;N;;;;; +1202D;CUNEIFORM SIGN AN;Lo;0;L;;;;;N;;;;; +1202E;CUNEIFORM SIGN AN OVER AN;Lo;0;L;;;;;N;;;;; +1202F;CUNEIFORM SIGN AN THREE TIMES;Lo;0;L;;;;;N;;;;; +12030;CUNEIFORM SIGN AN PLUS NAGA OPPOSING AN PLUS NAGA;Lo;0;L;;;;;N;;;;; +12031;CUNEIFORM SIGN AN PLUS NAGA SQUARED;Lo;0;L;;;;;N;;;;; +12032;CUNEIFORM SIGN ANSHE;Lo;0;L;;;;;N;;;;; +12033;CUNEIFORM SIGN APIN;Lo;0;L;;;;;N;;;;; +12034;CUNEIFORM SIGN ARAD;Lo;0;L;;;;;N;;;;; +12035;CUNEIFORM SIGN ARAD TIMES KUR;Lo;0;L;;;;;N;;;;; +12036;CUNEIFORM SIGN ARKAB;Lo;0;L;;;;;N;;;;; +12037;CUNEIFORM SIGN ASAL2;Lo;0;L;;;;;N;;;;; +12038;CUNEIFORM SIGN ASH;Lo;0;L;;;;1;N;;;;; +12039;CUNEIFORM SIGN ASH ZIDA TENU;Lo;0;L;;;;1;N;;;;; +1203A;CUNEIFORM SIGN ASH KABA TENU;Lo;0;L;;;;;N;;;;; +1203B;CUNEIFORM SIGN ASH OVER ASH TUG2 OVER TUG2 TUG2 OVER TUG2 PAP;Lo;0;L;;;;;N;;;;; +1203C;CUNEIFORM SIGN ASH OVER ASH OVER ASH;Lo;0;L;;;;;N;;;;; +1203D;CUNEIFORM SIGN ASH OVER ASH OVER ASH CROSSING ASH OVER ASH OVER ASH;Lo;0;L;;;;;N;;;;; +1203E;CUNEIFORM SIGN ASH2;Lo;0;L;;;;;N;;;;; +1203F;CUNEIFORM SIGN ASHGAB;Lo;0;L;;;;;N;;;;; +12040;CUNEIFORM SIGN BA;Lo;0;L;;;;;N;;;;; +12041;CUNEIFORM SIGN BAD;Lo;0;L;;;;;N;;;;; +12042;CUNEIFORM SIGN BAG3;Lo;0;L;;;;;N;;;;; +12043;CUNEIFORM SIGN BAHAR2;Lo;0;L;;;;;N;;;;; +12044;CUNEIFORM SIGN BAL;Lo;0;L;;;;;N;;;;; +12045;CUNEIFORM SIGN BAL OVER BAL;Lo;0;L;;;;;N;;;;; +12046;CUNEIFORM SIGN BALAG;Lo;0;L;;;;;N;;;;; +12047;CUNEIFORM SIGN BAR;Lo;0;L;;;;;N;;;;; +12048;CUNEIFORM SIGN BARA2;Lo;0;L;;;;;N;;;;; +12049;CUNEIFORM SIGN BI;Lo;0;L;;;;;N;;;;; +1204A;CUNEIFORM SIGN BI TIMES A;Lo;0;L;;;;;N;;;;; +1204B;CUNEIFORM SIGN BI TIMES GAR;Lo;0;L;;;;;N;;;;; +1204C;CUNEIFORM SIGN BI TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +1204D;CUNEIFORM SIGN BU;Lo;0;L;;;;;N;;;;; +1204E;CUNEIFORM SIGN BU OVER BU AB;Lo;0;L;;;;;N;;;;; +1204F;CUNEIFORM SIGN BU OVER BU UN;Lo;0;L;;;;;N;;;;; +12050;CUNEIFORM SIGN BU CROSSING BU;Lo;0;L;;;;;N;;;;; +12051;CUNEIFORM SIGN BULUG;Lo;0;L;;;;;N;;;;; +12052;CUNEIFORM SIGN BULUG OVER BULUG;Lo;0;L;;;;;N;;;;; +12053;CUNEIFORM SIGN BUR;Lo;0;L;;;;;N;;;;; +12054;CUNEIFORM SIGN BUR2;Lo;0;L;;;;;N;;;;; +12055;CUNEIFORM SIGN DA;Lo;0;L;;;;;N;;;;; +12056;CUNEIFORM SIGN DAG;Lo;0;L;;;;;N;;;;; +12057;CUNEIFORM SIGN DAG KISIM5 TIMES A PLUS MASH;Lo;0;L;;;;;N;;;;; +12058;CUNEIFORM SIGN DAG KISIM5 TIMES AMAR;Lo;0;L;;;;;N;;;;; +12059;CUNEIFORM SIGN DAG KISIM5 TIMES BALAG;Lo;0;L;;;;;N;;;;; +1205A;CUNEIFORM SIGN DAG KISIM5 TIMES BI;Lo;0;L;;;;;N;;;;; +1205B;CUNEIFORM SIGN DAG KISIM5 TIMES GA;Lo;0;L;;;;;N;;;;; +1205C;CUNEIFORM SIGN DAG KISIM5 TIMES GA PLUS MASH;Lo;0;L;;;;;N;;;;; +1205D;CUNEIFORM SIGN DAG KISIM5 TIMES GI;Lo;0;L;;;;;N;;;;; +1205E;CUNEIFORM SIGN DAG KISIM5 TIMES GIR2;Lo;0;L;;;;;N;;;;; +1205F;CUNEIFORM SIGN DAG KISIM5 TIMES GUD;Lo;0;L;;;;;N;;;;; +12060;CUNEIFORM SIGN DAG KISIM5 TIMES HA;Lo;0;L;;;;;N;;;;; +12061;CUNEIFORM SIGN DAG KISIM5 TIMES IR;Lo;0;L;;;;;N;;;;; +12062;CUNEIFORM SIGN DAG KISIM5 TIMES IR PLUS LU;Lo;0;L;;;;;N;;;;; +12063;CUNEIFORM SIGN DAG KISIM5 TIMES KAK;Lo;0;L;;;;;N;;;;; +12064;CUNEIFORM SIGN DAG KISIM5 TIMES LA;Lo;0;L;;;;;N;;;;; +12065;CUNEIFORM SIGN DAG KISIM5 TIMES LU;Lo;0;L;;;;;N;;;;; +12066;CUNEIFORM SIGN DAG KISIM5 TIMES LU PLUS MASH2;Lo;0;L;;;;;N;;;;; +12067;CUNEIFORM SIGN DAG KISIM5 TIMES LUM;Lo;0;L;;;;;N;;;;; +12068;CUNEIFORM SIGN DAG KISIM5 TIMES NE;Lo;0;L;;;;;N;;;;; +12069;CUNEIFORM SIGN DAG KISIM5 TIMES PAP PLUS PAP;Lo;0;L;;;;;N;;;;; +1206A;CUNEIFORM SIGN DAG KISIM5 TIMES SI;Lo;0;L;;;;;N;;;;; +1206B;CUNEIFORM SIGN DAG KISIM5 TIMES TAK4;Lo;0;L;;;;;N;;;;; +1206C;CUNEIFORM SIGN DAG KISIM5 TIMES U2 PLUS GIR2;Lo;0;L;;;;;N;;;;; +1206D;CUNEIFORM SIGN DAG KISIM5 TIMES USH;Lo;0;L;;;;;N;;;;; +1206E;CUNEIFORM SIGN DAM;Lo;0;L;;;;;N;;;;; +1206F;CUNEIFORM SIGN DAR;Lo;0;L;;;;;N;;;;; +12070;CUNEIFORM SIGN DARA3;Lo;0;L;;;;;N;;;;; +12071;CUNEIFORM SIGN DARA4;Lo;0;L;;;;;N;;;;; +12072;CUNEIFORM SIGN DI;Lo;0;L;;;;;N;;;;; +12073;CUNEIFORM SIGN DIB;Lo;0;L;;;;;N;;;;; +12074;CUNEIFORM SIGN DIM;Lo;0;L;;;;;N;;;;; +12075;CUNEIFORM SIGN DIM TIMES SHE;Lo;0;L;;;;;N;;;;; +12076;CUNEIFORM SIGN DIM2;Lo;0;L;;;;;N;;;;; +12077;CUNEIFORM SIGN DIN;Lo;0;L;;;;;N;;;;; +12078;CUNEIFORM SIGN DIN KASKAL U GUNU DISH;Lo;0;L;;;;;N;;;;; +12079;CUNEIFORM SIGN DISH;Lo;0;L;;;;1;N;;;;; +1207A;CUNEIFORM SIGN DU;Lo;0;L;;;;;N;;;;; +1207B;CUNEIFORM SIGN DU OVER DU;Lo;0;L;;;;;N;;;;; +1207C;CUNEIFORM SIGN DU GUNU;Lo;0;L;;;;;N;;;;; +1207D;CUNEIFORM SIGN DU SHESHIG;Lo;0;L;;;;;N;;;;; +1207E;CUNEIFORM SIGN DUB;Lo;0;L;;;;;N;;;;; +1207F;CUNEIFORM SIGN DUB TIMES ESH2;Lo;0;L;;;;;N;;;;; +12080;CUNEIFORM SIGN DUB2;Lo;0;L;;;;;N;;;;; +12081;CUNEIFORM SIGN DUG;Lo;0;L;;;;;N;;;;; +12082;CUNEIFORM SIGN DUGUD;Lo;0;L;;;;;N;;;;; +12083;CUNEIFORM SIGN DUH;Lo;0;L;;;;;N;;;;; +12084;CUNEIFORM SIGN DUN;Lo;0;L;;;;;N;;;;; +12085;CUNEIFORM SIGN DUN3;Lo;0;L;;;;;N;;;;; +12086;CUNEIFORM SIGN DUN3 GUNU;Lo;0;L;;;;;N;;;;; +12087;CUNEIFORM SIGN DUN3 GUNU GUNU;Lo;0;L;;;;;N;;;;; +12088;CUNEIFORM SIGN DUN4;Lo;0;L;;;;;N;;;;; +12089;CUNEIFORM SIGN DUR2;Lo;0;L;;;;;N;;;;; +1208A;CUNEIFORM SIGN E;Lo;0;L;;;;;N;;;;; +1208B;CUNEIFORM SIGN E TIMES PAP;Lo;0;L;;;;;N;;;;; +1208C;CUNEIFORM SIGN E OVER E NUN OVER NUN;Lo;0;L;;;;;N;;;;; +1208D;CUNEIFORM SIGN E2;Lo;0;L;;;;;N;;;;; +1208E;CUNEIFORM SIGN E2 TIMES A PLUS HA PLUS DA;Lo;0;L;;;;;N;;;;; +1208F;CUNEIFORM SIGN E2 TIMES GAR;Lo;0;L;;;;;N;;;;; +12090;CUNEIFORM SIGN E2 TIMES MI;Lo;0;L;;;;;N;;;;; +12091;CUNEIFORM SIGN E2 TIMES SAL;Lo;0;L;;;;;N;;;;; +12092;CUNEIFORM SIGN E2 TIMES SHE;Lo;0;L;;;;;N;;;;; +12093;CUNEIFORM SIGN E2 TIMES U;Lo;0;L;;;;;N;;;;; +12094;CUNEIFORM SIGN EDIN;Lo;0;L;;;;;N;;;;; +12095;CUNEIFORM SIGN EGIR;Lo;0;L;;;;;N;;;;; +12096;CUNEIFORM SIGN EL;Lo;0;L;;;;;N;;;;; +12097;CUNEIFORM SIGN EN;Lo;0;L;;;;;N;;;;; +12098;CUNEIFORM SIGN EN TIMES GAN2;Lo;0;L;;;;;N;;;;; +12099;CUNEIFORM SIGN EN TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +1209A;CUNEIFORM SIGN EN TIMES ME;Lo;0;L;;;;;N;;;;; +1209B;CUNEIFORM SIGN EN CROSSING EN;Lo;0;L;;;;;N;;;;; +1209C;CUNEIFORM SIGN EN OPPOSING EN;Lo;0;L;;;;;N;;;;; +1209D;CUNEIFORM SIGN EN SQUARED;Lo;0;L;;;;;N;;;;; +1209E;CUNEIFORM SIGN EREN;Lo;0;L;;;;;N;;;;; +1209F;CUNEIFORM SIGN ERIN2;Lo;0;L;;;;;N;;;;; +120A0;CUNEIFORM SIGN ESH2;Lo;0;L;;;;;N;;;;; +120A1;CUNEIFORM SIGN EZEN;Lo;0;L;;;;;N;;;;; +120A2;CUNEIFORM SIGN EZEN TIMES A;Lo;0;L;;;;;N;;;;; +120A3;CUNEIFORM SIGN EZEN TIMES A PLUS LAL;Lo;0;L;;;;;N;;;;; +120A4;CUNEIFORM SIGN EZEN TIMES A PLUS LAL TIMES LAL;Lo;0;L;;;;;N;;;;; +120A5;CUNEIFORM SIGN EZEN TIMES AN;Lo;0;L;;;;;N;;;;; +120A6;CUNEIFORM SIGN EZEN TIMES BAD;Lo;0;L;;;;;N;;;;; +120A7;CUNEIFORM SIGN EZEN TIMES DUN3 GUNU;Lo;0;L;;;;;N;;;;; +120A8;CUNEIFORM SIGN EZEN TIMES DUN3 GUNU GUNU;Lo;0;L;;;;;N;;;;; +120A9;CUNEIFORM SIGN EZEN TIMES HA;Lo;0;L;;;;;N;;;;; +120AA;CUNEIFORM SIGN EZEN TIMES HA GUNU;Lo;0;L;;;;;N;;;;; +120AB;CUNEIFORM SIGN EZEN TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +120AC;CUNEIFORM SIGN EZEN TIMES KASKAL;Lo;0;L;;;;;N;;;;; +120AD;CUNEIFORM SIGN EZEN TIMES KASKAL SQUARED;Lo;0;L;;;;;N;;;;; +120AE;CUNEIFORM SIGN EZEN TIMES KU3;Lo;0;L;;;;;N;;;;; +120AF;CUNEIFORM SIGN EZEN TIMES LA;Lo;0;L;;;;;N;;;;; +120B0;CUNEIFORM SIGN EZEN TIMES LAL TIMES LAL;Lo;0;L;;;;;N;;;;; +120B1;CUNEIFORM SIGN EZEN TIMES LI;Lo;0;L;;;;;N;;;;; +120B2;CUNEIFORM SIGN EZEN TIMES LU;Lo;0;L;;;;;N;;;;; +120B3;CUNEIFORM SIGN EZEN TIMES U2;Lo;0;L;;;;;N;;;;; +120B4;CUNEIFORM SIGN EZEN TIMES UD;Lo;0;L;;;;;N;;;;; +120B5;CUNEIFORM SIGN GA;Lo;0;L;;;;;N;;;;; +120B6;CUNEIFORM SIGN GA GUNU;Lo;0;L;;;;;N;;;;; +120B7;CUNEIFORM SIGN GA2;Lo;0;L;;;;;N;;;;; +120B8;CUNEIFORM SIGN GA2 TIMES A PLUS DA PLUS HA;Lo;0;L;;;;;N;;;;; +120B9;CUNEIFORM SIGN GA2 TIMES A PLUS HA;Lo;0;L;;;;;N;;;;; +120BA;CUNEIFORM SIGN GA2 TIMES A PLUS IGI;Lo;0;L;;;;;N;;;;; +120BB;CUNEIFORM SIGN GA2 TIMES AB2 TENU PLUS TAB;Lo;0;L;;;;;N;;;;; +120BC;CUNEIFORM SIGN GA2 TIMES AN;Lo;0;L;;;;;N;;;;; +120BD;CUNEIFORM SIGN GA2 TIMES ASH;Lo;0;L;;;;;N;;;;; +120BE;CUNEIFORM SIGN GA2 TIMES ASH2 PLUS GAL;Lo;0;L;;;;;N;;;;; +120BF;CUNEIFORM SIGN GA2 TIMES BAD;Lo;0;L;;;;;N;;;;; +120C0;CUNEIFORM SIGN GA2 TIMES BAR PLUS RA;Lo;0;L;;;;;N;;;;; +120C1;CUNEIFORM SIGN GA2 TIMES BUR;Lo;0;L;;;;;N;;;;; +120C2;CUNEIFORM SIGN GA2 TIMES BUR PLUS RA;Lo;0;L;;;;;N;;;;; +120C3;CUNEIFORM SIGN GA2 TIMES DA;Lo;0;L;;;;;N;;;;; +120C4;CUNEIFORM SIGN GA2 TIMES DI;Lo;0;L;;;;;N;;;;; +120C5;CUNEIFORM SIGN GA2 TIMES DIM TIMES SHE;Lo;0;L;;;;;N;;;;; +120C6;CUNEIFORM SIGN GA2 TIMES DUB;Lo;0;L;;;;;N;;;;; +120C7;CUNEIFORM SIGN GA2 TIMES EL;Lo;0;L;;;;;N;;;;; +120C8;CUNEIFORM SIGN GA2 TIMES EL PLUS LA;Lo;0;L;;;;;N;;;;; +120C9;CUNEIFORM SIGN GA2 TIMES EN;Lo;0;L;;;;;N;;;;; +120CA;CUNEIFORM SIGN GA2 TIMES EN TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +120CB;CUNEIFORM SIGN GA2 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +120CC;CUNEIFORM SIGN GA2 TIMES GAR;Lo;0;L;;;;;N;;;;; +120CD;CUNEIFORM SIGN GA2 TIMES GI;Lo;0;L;;;;;N;;;;; +120CE;CUNEIFORM SIGN GA2 TIMES GI4;Lo;0;L;;;;;N;;;;; +120CF;CUNEIFORM SIGN GA2 TIMES GI4 PLUS A;Lo;0;L;;;;;N;;;;; +120D0;CUNEIFORM SIGN GA2 TIMES GIR2 PLUS SU;Lo;0;L;;;;;N;;;;; +120D1;CUNEIFORM SIGN GA2 TIMES HA PLUS LU PLUS ESH2;Lo;0;L;;;;;N;;;;; +120D2;CUNEIFORM SIGN GA2 TIMES HAL;Lo;0;L;;;;;N;;;;; +120D3;CUNEIFORM SIGN GA2 TIMES HAL PLUS LA;Lo;0;L;;;;;N;;;;; +120D4;CUNEIFORM SIGN GA2 TIMES HI PLUS LI;Lo;0;L;;;;;N;;;;; +120D5;CUNEIFORM SIGN GA2 TIMES HUB2;Lo;0;L;;;;;N;;;;; +120D6;CUNEIFORM SIGN GA2 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +120D7;CUNEIFORM SIGN GA2 TIMES ISH PLUS HU PLUS ASH;Lo;0;L;;;;;N;;;;; +120D8;CUNEIFORM SIGN GA2 TIMES KAK;Lo;0;L;;;;;N;;;;; +120D9;CUNEIFORM SIGN GA2 TIMES KASKAL;Lo;0;L;;;;;N;;;;; +120DA;CUNEIFORM SIGN GA2 TIMES KID;Lo;0;L;;;;;N;;;;; +120DB;CUNEIFORM SIGN GA2 TIMES KID PLUS LAL;Lo;0;L;;;;;N;;;;; +120DC;CUNEIFORM SIGN GA2 TIMES KU3 PLUS AN;Lo;0;L;;;;;N;;;;; +120DD;CUNEIFORM SIGN GA2 TIMES LA;Lo;0;L;;;;;N;;;;; +120DE;CUNEIFORM SIGN GA2 TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;; +120DF;CUNEIFORM SIGN GA2 TIMES MI;Lo;0;L;;;;;N;;;;; +120E0;CUNEIFORM SIGN GA2 TIMES NUN;Lo;0;L;;;;;N;;;;; +120E1;CUNEIFORM SIGN GA2 TIMES NUN OVER NUN;Lo;0;L;;;;;N;;;;; +120E2;CUNEIFORM SIGN GA2 TIMES PA;Lo;0;L;;;;;N;;;;; +120E3;CUNEIFORM SIGN GA2 TIMES SAL;Lo;0;L;;;;;N;;;;; +120E4;CUNEIFORM SIGN GA2 TIMES SAR;Lo;0;L;;;;;N;;;;; +120E5;CUNEIFORM SIGN GA2 TIMES SHE;Lo;0;L;;;;;N;;;;; +120E6;CUNEIFORM SIGN GA2 TIMES SHE PLUS TUR;Lo;0;L;;;;;N;;;;; +120E7;CUNEIFORM SIGN GA2 TIMES SHID;Lo;0;L;;;;;N;;;;; +120E8;CUNEIFORM SIGN GA2 TIMES SUM;Lo;0;L;;;;;N;;;;; +120E9;CUNEIFORM SIGN GA2 TIMES TAK4;Lo;0;L;;;;;N;;;;; +120EA;CUNEIFORM SIGN GA2 TIMES U;Lo;0;L;;;;;N;;;;; +120EB;CUNEIFORM SIGN GA2 TIMES UD;Lo;0;L;;;;;N;;;;; +120EC;CUNEIFORM SIGN GA2 TIMES UD PLUS DU;Lo;0;L;;;;;N;;;;; +120ED;CUNEIFORM SIGN GA2 OVER GA2;Lo;0;L;;;;;N;;;;; +120EE;CUNEIFORM SIGN GABA;Lo;0;L;;;;;N;;;;; +120EF;CUNEIFORM SIGN GABA CROSSING GABA;Lo;0;L;;;;;N;;;;; +120F0;CUNEIFORM SIGN GAD;Lo;0;L;;;;;N;;;;; +120F1;CUNEIFORM SIGN GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;; +120F2;CUNEIFORM SIGN GAL;Lo;0;L;;;;;N;;;;; +120F3;CUNEIFORM SIGN GAL GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;; +120F4;CUNEIFORM SIGN GALAM;Lo;0;L;;;;;N;;;;; +120F5;CUNEIFORM SIGN GAM;Lo;0;L;;;;;N;;;;; +120F6;CUNEIFORM SIGN GAN;Lo;0;L;;;;;N;;;;; +120F7;CUNEIFORM SIGN GAN2;Lo;0;L;;;;;N;;;;; +120F8;CUNEIFORM SIGN GAN2 TENU;Lo;0;L;;;;;N;;;;; +120F9;CUNEIFORM SIGN GAN2 OVER GAN2;Lo;0;L;;;;;N;;;;; +120FA;CUNEIFORM SIGN GAN2 CROSSING GAN2;Lo;0;L;;;;;N;;;;; +120FB;CUNEIFORM SIGN GAR;Lo;0;L;;;;;N;;;;; +120FC;CUNEIFORM SIGN GAR3;Lo;0;L;;;;;N;;;;; +120FD;CUNEIFORM SIGN GASHAN;Lo;0;L;;;;;N;;;;; +120FE;CUNEIFORM SIGN GESHTIN;Lo;0;L;;;;;N;;;;; +120FF;CUNEIFORM SIGN GESHTIN TIMES KUR;Lo;0;L;;;;;N;;;;; +12100;CUNEIFORM SIGN GI;Lo;0;L;;;;;N;;;;; +12101;CUNEIFORM SIGN GI TIMES E;Lo;0;L;;;;;N;;;;; +12102;CUNEIFORM SIGN GI TIMES U;Lo;0;L;;;;;N;;;;; +12103;CUNEIFORM SIGN GI CROSSING GI;Lo;0;L;;;;;N;;;;; +12104;CUNEIFORM SIGN GI4;Lo;0;L;;;;;N;;;;; +12105;CUNEIFORM SIGN GI4 OVER GI4;Lo;0;L;;;;;N;;;;; +12106;CUNEIFORM SIGN GI4 CROSSING GI4;Lo;0;L;;;;;N;;;;; +12107;CUNEIFORM SIGN GIDIM;Lo;0;L;;;;;N;;;;; +12108;CUNEIFORM SIGN GIR2;Lo;0;L;;;;;N;;;;; +12109;CUNEIFORM SIGN GIR2 GUNU;Lo;0;L;;;;;N;;;;; +1210A;CUNEIFORM SIGN GIR3;Lo;0;L;;;;;N;;;;; +1210B;CUNEIFORM SIGN GIR3 TIMES A PLUS IGI;Lo;0;L;;;;;N;;;;; +1210C;CUNEIFORM SIGN GIR3 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +1210D;CUNEIFORM SIGN GIR3 TIMES IGI;Lo;0;L;;;;;N;;;;; +1210E;CUNEIFORM SIGN GIR3 TIMES LU PLUS IGI;Lo;0;L;;;;;N;;;;; +1210F;CUNEIFORM SIGN GIR3 TIMES PA;Lo;0;L;;;;;N;;;;; +12110;CUNEIFORM SIGN GISAL;Lo;0;L;;;;;N;;;;; +12111;CUNEIFORM SIGN GISH;Lo;0;L;;;;;N;;;;; +12112;CUNEIFORM SIGN GISH CROSSING GISH;Lo;0;L;;;;;N;;;;; +12113;CUNEIFORM SIGN GISH TIMES BAD;Lo;0;L;;;;;N;;;;; +12114;CUNEIFORM SIGN GISH TIMES TAK4;Lo;0;L;;;;;N;;;;; +12115;CUNEIFORM SIGN GISH TENU;Lo;0;L;;;;;N;;;;; +12116;CUNEIFORM SIGN GU;Lo;0;L;;;;;N;;;;; +12117;CUNEIFORM SIGN GU CROSSING GU;Lo;0;L;;;;;N;;;;; +12118;CUNEIFORM SIGN GU2;Lo;0;L;;;;;N;;;;; +12119;CUNEIFORM SIGN GU2 TIMES KAK;Lo;0;L;;;;;N;;;;; +1211A;CUNEIFORM SIGN GU2 TIMES KAK TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +1211B;CUNEIFORM SIGN GU2 TIMES NUN;Lo;0;L;;;;;N;;;;; +1211C;CUNEIFORM SIGN GU2 TIMES SAL PLUS TUG2;Lo;0;L;;;;;N;;;;; +1211D;CUNEIFORM SIGN GU2 GUNU;Lo;0;L;;;;;N;;;;; +1211E;CUNEIFORM SIGN GUD;Lo;0;L;;;;;N;;;;; +1211F;CUNEIFORM SIGN GUD TIMES A PLUS KUR;Lo;0;L;;;;;N;;;;; +12120;CUNEIFORM SIGN GUD TIMES KUR;Lo;0;L;;;;;N;;;;; +12121;CUNEIFORM SIGN GUD OVER GUD LUGAL;Lo;0;L;;;;;N;;;;; +12122;CUNEIFORM SIGN GUL;Lo;0;L;;;;;N;;;;; +12123;CUNEIFORM SIGN GUM;Lo;0;L;;;;;N;;;;; +12124;CUNEIFORM SIGN GUM TIMES SHE;Lo;0;L;;;;;N;;;;; +12125;CUNEIFORM SIGN GUR;Lo;0;L;;;;;N;;;;; +12126;CUNEIFORM SIGN GUR7;Lo;0;L;;;;;N;;;;; +12127;CUNEIFORM SIGN GURUN;Lo;0;L;;;;;N;;;;; +12128;CUNEIFORM SIGN GURUSH;Lo;0;L;;;;;N;;;;; +12129;CUNEIFORM SIGN HA;Lo;0;L;;;;;N;;;;; +1212A;CUNEIFORM SIGN HA TENU;Lo;0;L;;;;;N;;;;; +1212B;CUNEIFORM SIGN HA GUNU;Lo;0;L;;;;;N;;;;; +1212C;CUNEIFORM SIGN HAL;Lo;0;L;;;;;N;;;;; +1212D;CUNEIFORM SIGN HI;Lo;0;L;;;;;N;;;;; +1212E;CUNEIFORM SIGN HI TIMES ASH;Lo;0;L;;;;;N;;;;; +1212F;CUNEIFORM SIGN HI TIMES ASH2;Lo;0;L;;;;;N;;;;; +12130;CUNEIFORM SIGN HI TIMES BAD;Lo;0;L;;;;;N;;;;; +12131;CUNEIFORM SIGN HI TIMES DISH;Lo;0;L;;;;;N;;;;; +12132;CUNEIFORM SIGN HI TIMES GAD;Lo;0;L;;;;;N;;;;; +12133;CUNEIFORM SIGN HI TIMES KIN;Lo;0;L;;;;;N;;;;; +12134;CUNEIFORM SIGN HI TIMES NUN;Lo;0;L;;;;;N;;;;; +12135;CUNEIFORM SIGN HI TIMES SHE;Lo;0;L;;;;;N;;;;; +12136;CUNEIFORM SIGN HI TIMES U;Lo;0;L;;;;;N;;;;; +12137;CUNEIFORM SIGN HU;Lo;0;L;;;;;N;;;;; +12138;CUNEIFORM SIGN HUB2;Lo;0;L;;;;;N;;;;; +12139;CUNEIFORM SIGN HUB2 TIMES AN;Lo;0;L;;;;;N;;;;; +1213A;CUNEIFORM SIGN HUB2 TIMES HAL;Lo;0;L;;;;;N;;;;; +1213B;CUNEIFORM SIGN HUB2 TIMES KASKAL;Lo;0;L;;;;;N;;;;; +1213C;CUNEIFORM SIGN HUB2 TIMES LISH;Lo;0;L;;;;;N;;;;; +1213D;CUNEIFORM SIGN HUB2 TIMES UD;Lo;0;L;;;;;N;;;;; +1213E;CUNEIFORM SIGN HUL2;Lo;0;L;;;;;N;;;;; +1213F;CUNEIFORM SIGN I;Lo;0;L;;;;;N;;;;; +12140;CUNEIFORM SIGN I A;Lo;0;L;;;;;N;;;;; +12141;CUNEIFORM SIGN IB;Lo;0;L;;;;;N;;;;; +12142;CUNEIFORM SIGN IDIM;Lo;0;L;;;;;N;;;;; +12143;CUNEIFORM SIGN IDIM OVER IDIM BUR;Lo;0;L;;;;;N;;;;; +12144;CUNEIFORM SIGN IDIM OVER IDIM SQUARED;Lo;0;L;;;;;N;;;;; +12145;CUNEIFORM SIGN IG;Lo;0;L;;;;;N;;;;; +12146;CUNEIFORM SIGN IGI;Lo;0;L;;;;;N;;;;; +12147;CUNEIFORM SIGN IGI DIB;Lo;0;L;;;;;N;;;;; +12148;CUNEIFORM SIGN IGI RI;Lo;0;L;;;;;N;;;;; +12149;CUNEIFORM SIGN IGI OVER IGI SHIR OVER SHIR UD OVER UD;Lo;0;L;;;;;N;;;;; +1214A;CUNEIFORM SIGN IGI GUNU;Lo;0;L;;;;;N;;;;; +1214B;CUNEIFORM SIGN IL;Lo;0;L;;;;;N;;;;; +1214C;CUNEIFORM SIGN IL TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +1214D;CUNEIFORM SIGN IL2;Lo;0;L;;;;;N;;;;; +1214E;CUNEIFORM SIGN IM;Lo;0;L;;;;;N;;;;; +1214F;CUNEIFORM SIGN IM TIMES TAK4;Lo;0;L;;;;;N;;;;; +12150;CUNEIFORM SIGN IM CROSSING IM;Lo;0;L;;;;;N;;;;; +12151;CUNEIFORM SIGN IM OPPOSING IM;Lo;0;L;;;;;N;;;;; +12152;CUNEIFORM SIGN IM SQUARED;Lo;0;L;;;;;N;;;;; +12153;CUNEIFORM SIGN IMIN;Lo;0;L;;;;;N;;;;; +12154;CUNEIFORM SIGN IN;Lo;0;L;;;;;N;;;;; +12155;CUNEIFORM SIGN IR;Lo;0;L;;;;;N;;;;; +12156;CUNEIFORM SIGN ISH;Lo;0;L;;;;;N;;;;; +12157;CUNEIFORM SIGN KA;Lo;0;L;;;;;N;;;;; +12158;CUNEIFORM SIGN KA TIMES A;Lo;0;L;;;;;N;;;;; +12159;CUNEIFORM SIGN KA TIMES AD;Lo;0;L;;;;;N;;;;; +1215A;CUNEIFORM SIGN KA TIMES AD PLUS KU3;Lo;0;L;;;;;N;;;;; +1215B;CUNEIFORM SIGN KA TIMES ASH2;Lo;0;L;;;;;N;;;;; +1215C;CUNEIFORM SIGN KA TIMES BAD;Lo;0;L;;;;;N;;;;; +1215D;CUNEIFORM SIGN KA TIMES BALAG;Lo;0;L;;;;;N;;;;; +1215E;CUNEIFORM SIGN KA TIMES BAR;Lo;0;L;;;;;N;;;;; +1215F;CUNEIFORM SIGN KA TIMES BI;Lo;0;L;;;;;N;;;;; +12160;CUNEIFORM SIGN KA TIMES ERIN2;Lo;0;L;;;;;N;;;;; +12161;CUNEIFORM SIGN KA TIMES ESH2;Lo;0;L;;;;;N;;;;; +12162;CUNEIFORM SIGN KA TIMES GA;Lo;0;L;;;;;N;;;;; +12163;CUNEIFORM SIGN KA TIMES GAL;Lo;0;L;;;;;N;;;;; +12164;CUNEIFORM SIGN KA TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +12165;CUNEIFORM SIGN KA TIMES GAR;Lo;0;L;;;;;N;;;;; +12166;CUNEIFORM SIGN KA TIMES GAR PLUS SHA3 PLUS A;Lo;0;L;;;;;N;;;;; +12167;CUNEIFORM SIGN KA TIMES GI;Lo;0;L;;;;;N;;;;; +12168;CUNEIFORM SIGN KA TIMES GIR2;Lo;0;L;;;;;N;;;;; +12169;CUNEIFORM SIGN KA TIMES GISH PLUS SAR;Lo;0;L;;;;;N;;;;; +1216A;CUNEIFORM SIGN KA TIMES GISH CROSSING GISH;Lo;0;L;;;;;N;;;;; +1216B;CUNEIFORM SIGN KA TIMES GU;Lo;0;L;;;;;N;;;;; +1216C;CUNEIFORM SIGN KA TIMES GUR7;Lo;0;L;;;;;N;;;;; +1216D;CUNEIFORM SIGN KA TIMES IGI;Lo;0;L;;;;;N;;;;; +1216E;CUNEIFORM SIGN KA TIMES IM;Lo;0;L;;;;;N;;;;; +1216F;CUNEIFORM SIGN KA TIMES KAK;Lo;0;L;;;;;N;;;;; +12170;CUNEIFORM SIGN KA TIMES KI;Lo;0;L;;;;;N;;;;; +12171;CUNEIFORM SIGN KA TIMES KID;Lo;0;L;;;;;N;;;;; +12172;CUNEIFORM SIGN KA TIMES LI;Lo;0;L;;;;;N;;;;; +12173;CUNEIFORM SIGN KA TIMES LU;Lo;0;L;;;;;N;;;;; +12174;CUNEIFORM SIGN KA TIMES ME;Lo;0;L;;;;;N;;;;; +12175;CUNEIFORM SIGN KA TIMES ME PLUS DU;Lo;0;L;;;;;N;;;;; +12176;CUNEIFORM SIGN KA TIMES ME PLUS GI;Lo;0;L;;;;;N;;;;; +12177;CUNEIFORM SIGN KA TIMES ME PLUS TE;Lo;0;L;;;;;N;;;;; +12178;CUNEIFORM SIGN KA TIMES MI;Lo;0;L;;;;;N;;;;; +12179;CUNEIFORM SIGN KA TIMES MI PLUS NUNUZ;Lo;0;L;;;;;N;;;;; +1217A;CUNEIFORM SIGN KA TIMES NE;Lo;0;L;;;;;N;;;;; +1217B;CUNEIFORM SIGN KA TIMES NUN;Lo;0;L;;;;;N;;;;; +1217C;CUNEIFORM SIGN KA TIMES PI;Lo;0;L;;;;;N;;;;; +1217D;CUNEIFORM SIGN KA TIMES RU;Lo;0;L;;;;;N;;;;; +1217E;CUNEIFORM SIGN KA TIMES SA;Lo;0;L;;;;;N;;;;; +1217F;CUNEIFORM SIGN KA TIMES SAR;Lo;0;L;;;;;N;;;;; +12180;CUNEIFORM SIGN KA TIMES SHA;Lo;0;L;;;;;N;;;;; +12181;CUNEIFORM SIGN KA TIMES SHE;Lo;0;L;;;;;N;;;;; +12182;CUNEIFORM SIGN KA TIMES SHID;Lo;0;L;;;;;N;;;;; +12183;CUNEIFORM SIGN KA TIMES SHU;Lo;0;L;;;;;N;;;;; +12184;CUNEIFORM SIGN KA TIMES SIG;Lo;0;L;;;;;N;;;;; +12185;CUNEIFORM SIGN KA TIMES SUHUR;Lo;0;L;;;;;N;;;;; +12186;CUNEIFORM SIGN KA TIMES TAR;Lo;0;L;;;;;N;;;;; +12187;CUNEIFORM SIGN KA TIMES U;Lo;0;L;;;;;N;;;;; +12188;CUNEIFORM SIGN KA TIMES U2;Lo;0;L;;;;;N;;;;; +12189;CUNEIFORM SIGN KA TIMES UD;Lo;0;L;;;;;N;;;;; +1218A;CUNEIFORM SIGN KA TIMES UMUM TIMES PA;Lo;0;L;;;;;N;;;;; +1218B;CUNEIFORM SIGN KA TIMES USH;Lo;0;L;;;;;N;;;;; +1218C;CUNEIFORM SIGN KA TIMES ZI;Lo;0;L;;;;;N;;;;; +1218D;CUNEIFORM SIGN KA2;Lo;0;L;;;;;N;;;;; +1218E;CUNEIFORM SIGN KA2 CROSSING KA2;Lo;0;L;;;;;N;;;;; +1218F;CUNEIFORM SIGN KAB;Lo;0;L;;;;;N;;;;; +12190;CUNEIFORM SIGN KAD2;Lo;0;L;;;;;N;;;;; +12191;CUNEIFORM SIGN KAD3;Lo;0;L;;;;;N;;;;; +12192;CUNEIFORM SIGN KAD4;Lo;0;L;;;;;N;;;;; +12193;CUNEIFORM SIGN KAD5;Lo;0;L;;;;;N;;;;; +12194;CUNEIFORM SIGN KAD5 OVER KAD5;Lo;0;L;;;;;N;;;;; +12195;CUNEIFORM SIGN KAK;Lo;0;L;;;;;N;;;;; +12196;CUNEIFORM SIGN KAK TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +12197;CUNEIFORM SIGN KAL;Lo;0;L;;;;;N;;;;; +12198;CUNEIFORM SIGN KAL TIMES BAD;Lo;0;L;;;;;N;;;;; +12199;CUNEIFORM SIGN KAL CROSSING KAL;Lo;0;L;;;;;N;;;;; +1219A;CUNEIFORM SIGN KAM2;Lo;0;L;;;;;N;;;;; +1219B;CUNEIFORM SIGN KAM4;Lo;0;L;;;;;N;;;;; +1219C;CUNEIFORM SIGN KASKAL;Lo;0;L;;;;;N;;;;; +1219D;CUNEIFORM SIGN KASKAL LAGAB TIMES U OVER LAGAB TIMES U;Lo;0;L;;;;;N;;;;; +1219E;CUNEIFORM SIGN KASKAL OVER KASKAL LAGAB TIMES U OVER LAGAB TIMES U;Lo;0;L;;;;;N;;;;; +1219F;CUNEIFORM SIGN KESH2;Lo;0;L;;;;;N;;;;; +121A0;CUNEIFORM SIGN KI;Lo;0;L;;;;;N;;;;; +121A1;CUNEIFORM SIGN KI TIMES BAD;Lo;0;L;;;;;N;;;;; +121A2;CUNEIFORM SIGN KI TIMES U;Lo;0;L;;;;;N;;;;; +121A3;CUNEIFORM SIGN KI TIMES UD;Lo;0;L;;;;;N;;;;; +121A4;CUNEIFORM SIGN KID;Lo;0;L;;;;;N;;;;; +121A5;CUNEIFORM SIGN KIN;Lo;0;L;;;;;N;;;;; +121A6;CUNEIFORM SIGN KISAL;Lo;0;L;;;;;N;;;;; +121A7;CUNEIFORM SIGN KISH;Lo;0;L;;;;;N;;;;; +121A8;CUNEIFORM SIGN KISIM5;Lo;0;L;;;;;N;;;;; +121A9;CUNEIFORM SIGN KISIM5 OVER KISIM5;Lo;0;L;;;;;N;;;;; +121AA;CUNEIFORM SIGN KU;Lo;0;L;;;;;N;;;;; +121AB;CUNEIFORM SIGN KU OVER HI TIMES ASH2 KU OVER HI TIMES ASH2;Lo;0;L;;;;;N;;;;; +121AC;CUNEIFORM SIGN KU3;Lo;0;L;;;;;N;;;;; +121AD;CUNEIFORM SIGN KU4;Lo;0;L;;;;;N;;;;; +121AE;CUNEIFORM SIGN KU4 VARIANT FORM;Lo;0;L;;;;;N;;;;; +121AF;CUNEIFORM SIGN KU7;Lo;0;L;;;;;N;;;;; +121B0;CUNEIFORM SIGN KUL;Lo;0;L;;;;;N;;;;; +121B1;CUNEIFORM SIGN KUL GUNU;Lo;0;L;;;;;N;;;;; +121B2;CUNEIFORM SIGN KUN;Lo;0;L;;;;;N;;;;; +121B3;CUNEIFORM SIGN KUR;Lo;0;L;;;;;N;;;;; +121B4;CUNEIFORM SIGN KUR OPPOSING KUR;Lo;0;L;;;;;N;;;;; +121B5;CUNEIFORM SIGN KUSHU2;Lo;0;L;;;;;N;;;;; +121B6;CUNEIFORM SIGN KWU318;Lo;0;L;;;;;N;;;;; +121B7;CUNEIFORM SIGN LA;Lo;0;L;;;;;N;;;;; +121B8;CUNEIFORM SIGN LAGAB;Lo;0;L;;;;;N;;;;; +121B9;CUNEIFORM SIGN LAGAB TIMES A;Lo;0;L;;;;;N;;;;; +121BA;CUNEIFORM SIGN LAGAB TIMES A PLUS DA PLUS HA;Lo;0;L;;;;;N;;;;; +121BB;CUNEIFORM SIGN LAGAB TIMES A PLUS GAR;Lo;0;L;;;;;N;;;;; +121BC;CUNEIFORM SIGN LAGAB TIMES A PLUS LAL;Lo;0;L;;;;;N;;;;; +121BD;CUNEIFORM SIGN LAGAB TIMES AL;Lo;0;L;;;;;N;;;;; +121BE;CUNEIFORM SIGN LAGAB TIMES AN;Lo;0;L;;;;;N;;;;; +121BF;CUNEIFORM SIGN LAGAB TIMES ASH ZIDA TENU;Lo;0;L;;;;;N;;;;; +121C0;CUNEIFORM SIGN LAGAB TIMES BAD;Lo;0;L;;;;;N;;;;; +121C1;CUNEIFORM SIGN LAGAB TIMES BI;Lo;0;L;;;;;N;;;;; +121C2;CUNEIFORM SIGN LAGAB TIMES DAR;Lo;0;L;;;;;N;;;;; +121C3;CUNEIFORM SIGN LAGAB TIMES EN;Lo;0;L;;;;;N;;;;; +121C4;CUNEIFORM SIGN LAGAB TIMES GA;Lo;0;L;;;;;N;;;;; +121C5;CUNEIFORM SIGN LAGAB TIMES GAR;Lo;0;L;;;;;N;;;;; +121C6;CUNEIFORM SIGN LAGAB TIMES GUD;Lo;0;L;;;;;N;;;;; +121C7;CUNEIFORM SIGN LAGAB TIMES GUD PLUS GUD;Lo;0;L;;;;;N;;;;; +121C8;CUNEIFORM SIGN LAGAB TIMES HA;Lo;0;L;;;;;N;;;;; +121C9;CUNEIFORM SIGN LAGAB TIMES HAL;Lo;0;L;;;;;N;;;;; +121CA;CUNEIFORM SIGN LAGAB TIMES HI TIMES NUN;Lo;0;L;;;;;N;;;;; +121CB;CUNEIFORM SIGN LAGAB TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +121CC;CUNEIFORM SIGN LAGAB TIMES IM;Lo;0;L;;;;;N;;;;; +121CD;CUNEIFORM SIGN LAGAB TIMES IM PLUS HA;Lo;0;L;;;;;N;;;;; +121CE;CUNEIFORM SIGN LAGAB TIMES IM PLUS LU;Lo;0;L;;;;;N;;;;; +121CF;CUNEIFORM SIGN LAGAB TIMES KI;Lo;0;L;;;;;N;;;;; +121D0;CUNEIFORM SIGN LAGAB TIMES KIN;Lo;0;L;;;;;N;;;;; +121D1;CUNEIFORM SIGN LAGAB TIMES KU3;Lo;0;L;;;;;N;;;;; +121D2;CUNEIFORM SIGN LAGAB TIMES KUL;Lo;0;L;;;;;N;;;;; +121D3;CUNEIFORM SIGN LAGAB TIMES KUL PLUS HI PLUS A;Lo;0;L;;;;;N;;;;; +121D4;CUNEIFORM SIGN LAGAB TIMES LAGAB;Lo;0;L;;;;;N;;;;; +121D5;CUNEIFORM SIGN LAGAB TIMES LISH;Lo;0;L;;;;;N;;;;; +121D6;CUNEIFORM SIGN LAGAB TIMES LU;Lo;0;L;;;;;N;;;;; +121D7;CUNEIFORM SIGN LAGAB TIMES LUL;Lo;0;L;;;;;N;;;;; +121D8;CUNEIFORM SIGN LAGAB TIMES ME;Lo;0;L;;;;;N;;;;; +121D9;CUNEIFORM SIGN LAGAB TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;; +121DA;CUNEIFORM SIGN LAGAB TIMES MUSH;Lo;0;L;;;;;N;;;;; +121DB;CUNEIFORM SIGN LAGAB TIMES NE;Lo;0;L;;;;;N;;;;; +121DC;CUNEIFORM SIGN LAGAB TIMES SHE PLUS SUM;Lo;0;L;;;;;N;;;;; +121DD;CUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH PLUS ERIN2;Lo;0;L;;;;;N;;;;; +121DE;CUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH TENU;Lo;0;L;;;;;N;;;;; +121DF;CUNEIFORM SIGN LAGAB TIMES SHU2;Lo;0;L;;;;;N;;;;; +121E0;CUNEIFORM SIGN LAGAB TIMES SHU2 PLUS SHU2;Lo;0;L;;;;;N;;;;; +121E1;CUNEIFORM SIGN LAGAB TIMES SUM;Lo;0;L;;;;;N;;;;; +121E2;CUNEIFORM SIGN LAGAB TIMES TAG;Lo;0;L;;;;;N;;;;; +121E3;CUNEIFORM SIGN LAGAB TIMES TAK4;Lo;0;L;;;;;N;;;;; +121E4;CUNEIFORM SIGN LAGAB TIMES TE PLUS A PLUS SU PLUS NA;Lo;0;L;;;;;N;;;;; +121E5;CUNEIFORM SIGN LAGAB TIMES U;Lo;0;L;;;;;N;;;;; +121E6;CUNEIFORM SIGN LAGAB TIMES U PLUS A;Lo;0;L;;;;;N;;;;; +121E7;CUNEIFORM SIGN LAGAB TIMES U PLUS U PLUS U;Lo;0;L;;;;;N;;;;; +121E8;CUNEIFORM SIGN LAGAB TIMES U2 PLUS ASH;Lo;0;L;;;;;N;;;;; +121E9;CUNEIFORM SIGN LAGAB TIMES UD;Lo;0;L;;;;;N;;;;; +121EA;CUNEIFORM SIGN LAGAB TIMES USH;Lo;0;L;;;;;N;;;;; +121EB;CUNEIFORM SIGN LAGAB SQUARED;Lo;0;L;;;;;N;;;;; +121EC;CUNEIFORM SIGN LAGAR;Lo;0;L;;;;;N;;;;; +121ED;CUNEIFORM SIGN LAGAR TIMES SHE;Lo;0;L;;;;;N;;;;; +121EE;CUNEIFORM SIGN LAGAR TIMES SHE PLUS SUM;Lo;0;L;;;;;N;;;;; +121EF;CUNEIFORM SIGN LAGAR GUNU;Lo;0;L;;;;;N;;;;; +121F0;CUNEIFORM SIGN LAGAR GUNU OVER LAGAR GUNU SHE;Lo;0;L;;;;;N;;;;; +121F1;CUNEIFORM SIGN LAHSHU;Lo;0;L;;;;;N;;;;; +121F2;CUNEIFORM SIGN LAL;Lo;0;L;;;;;N;;;;; +121F3;CUNEIFORM SIGN LAL TIMES LAL;Lo;0;L;;;;;N;;;;; +121F4;CUNEIFORM SIGN LAM;Lo;0;L;;;;;N;;;;; +121F5;CUNEIFORM SIGN LAM TIMES KUR;Lo;0;L;;;;;N;;;;; +121F6;CUNEIFORM SIGN LAM TIMES KUR PLUS RU;Lo;0;L;;;;;N;;;;; +121F7;CUNEIFORM SIGN LI;Lo;0;L;;;;;N;;;;; +121F8;CUNEIFORM SIGN LIL;Lo;0;L;;;;;N;;;;; +121F9;CUNEIFORM SIGN LIMMU2;Lo;0;L;;;;;N;;;;; +121FA;CUNEIFORM SIGN LISH;Lo;0;L;;;;;N;;;;; +121FB;CUNEIFORM SIGN LU;Lo;0;L;;;;;N;;;;; +121FC;CUNEIFORM SIGN LU TIMES BAD;Lo;0;L;;;;;N;;;;; +121FD;CUNEIFORM SIGN LU2;Lo;0;L;;;;;N;;;;; +121FE;CUNEIFORM SIGN LU2 TIMES AL;Lo;0;L;;;;;N;;;;; +121FF;CUNEIFORM SIGN LU2 TIMES BAD;Lo;0;L;;;;;N;;;;; +12200;CUNEIFORM SIGN LU2 TIMES ESH2;Lo;0;L;;;;;N;;;;; +12201;CUNEIFORM SIGN LU2 TIMES ESH2 TENU;Lo;0;L;;;;;N;;;;; +12202;CUNEIFORM SIGN LU2 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +12203;CUNEIFORM SIGN LU2 TIMES HI TIMES BAD;Lo;0;L;;;;;N;;;;; +12204;CUNEIFORM SIGN LU2 TIMES IM;Lo;0;L;;;;;N;;;;; +12205;CUNEIFORM SIGN LU2 TIMES KAD2;Lo;0;L;;;;;N;;;;; +12206;CUNEIFORM SIGN LU2 TIMES KAD3;Lo;0;L;;;;;N;;;;; +12207;CUNEIFORM SIGN LU2 TIMES KAD3 PLUS ASH;Lo;0;L;;;;;N;;;;; +12208;CUNEIFORM SIGN LU2 TIMES KI;Lo;0;L;;;;;N;;;;; +12209;CUNEIFORM SIGN LU2 TIMES LA PLUS ASH;Lo;0;L;;;;;N;;;;; +1220A;CUNEIFORM SIGN LU2 TIMES LAGAB;Lo;0;L;;;;;N;;;;; +1220B;CUNEIFORM SIGN LU2 TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;; +1220C;CUNEIFORM SIGN LU2 TIMES NE;Lo;0;L;;;;;N;;;;; +1220D;CUNEIFORM SIGN LU2 TIMES NU;Lo;0;L;;;;;N;;;;; +1220E;CUNEIFORM SIGN LU2 TIMES SI PLUS ASH;Lo;0;L;;;;;N;;;;; +1220F;CUNEIFORM SIGN LU2 TIMES SIK2 PLUS BU;Lo;0;L;;;;;N;;;;; +12210;CUNEIFORM SIGN LU2 TIMES TUG2;Lo;0;L;;;;;N;;;;; +12211;CUNEIFORM SIGN LU2 TENU;Lo;0;L;;;;;N;;;;; +12212;CUNEIFORM SIGN LU2 CROSSING LU2;Lo;0;L;;;;;N;;;;; +12213;CUNEIFORM SIGN LU2 OPPOSING LU2;Lo;0;L;;;;;N;;;;; +12214;CUNEIFORM SIGN LU2 SQUARED;Lo;0;L;;;;;N;;;;; +12215;CUNEIFORM SIGN LU2 SHESHIG;Lo;0;L;;;;;N;;;;; +12216;CUNEIFORM SIGN LU3;Lo;0;L;;;;;N;;;;; +12217;CUNEIFORM SIGN LUGAL;Lo;0;L;;;;;N;;;;; +12218;CUNEIFORM SIGN LUGAL OVER LUGAL;Lo;0;L;;;;;N;;;;; +12219;CUNEIFORM SIGN LUGAL OPPOSING LUGAL;Lo;0;L;;;;;N;;;;; +1221A;CUNEIFORM SIGN LUGAL SHESHIG;Lo;0;L;;;;;N;;;;; +1221B;CUNEIFORM SIGN LUH;Lo;0;L;;;;;N;;;;; +1221C;CUNEIFORM SIGN LUL;Lo;0;L;;;;;N;;;;; +1221D;CUNEIFORM SIGN LUM;Lo;0;L;;;;;N;;;;; +1221E;CUNEIFORM SIGN LUM OVER LUM;Lo;0;L;;;;;N;;;;; +1221F;CUNEIFORM SIGN LUM OVER LUM GAR OVER GAR;Lo;0;L;;;;;N;;;;; +12220;CUNEIFORM SIGN MA;Lo;0;L;;;;;N;;;;; +12221;CUNEIFORM SIGN MA TIMES TAK4;Lo;0;L;;;;;N;;;;; +12222;CUNEIFORM SIGN MA GUNU;Lo;0;L;;;;;N;;;;; +12223;CUNEIFORM SIGN MA2;Lo;0;L;;;;;N;;;;; +12224;CUNEIFORM SIGN MAH;Lo;0;L;;;;;N;;;;; +12225;CUNEIFORM SIGN MAR;Lo;0;L;;;;;N;;;;; +12226;CUNEIFORM SIGN MASH;Lo;0;L;;;;1/2;N;;;;; +12227;CUNEIFORM SIGN MASH2;Lo;0;L;;;;;N;;;;; +12228;CUNEIFORM SIGN ME;Lo;0;L;;;;;N;;;;; +12229;CUNEIFORM SIGN MES;Lo;0;L;;;;;N;;;;; +1222A;CUNEIFORM SIGN MI;Lo;0;L;;;;;N;;;;; +1222B;CUNEIFORM SIGN MIN;Lo;0;L;;;;2;N;;;;; +1222C;CUNEIFORM SIGN MU;Lo;0;L;;;;;N;;;;; +1222D;CUNEIFORM SIGN MU OVER MU;Lo;0;L;;;;;N;;;;; +1222E;CUNEIFORM SIGN MUG;Lo;0;L;;;;;N;;;;; +1222F;CUNEIFORM SIGN MUG GUNU;Lo;0;L;;;;;N;;;;; +12230;CUNEIFORM SIGN MUNSUB;Lo;0;L;;;;;N;;;;; +12231;CUNEIFORM SIGN MURGU2;Lo;0;L;;;;;N;;;;; +12232;CUNEIFORM SIGN MUSH;Lo;0;L;;;;;N;;;;; +12233;CUNEIFORM SIGN MUSH TIMES A;Lo;0;L;;;;;N;;;;; +12234;CUNEIFORM SIGN MUSH TIMES KUR;Lo;0;L;;;;;N;;;;; +12235;CUNEIFORM SIGN MUSH TIMES ZA;Lo;0;L;;;;;N;;;;; +12236;CUNEIFORM SIGN MUSH OVER MUSH;Lo;0;L;;;;;N;;;;; +12237;CUNEIFORM SIGN MUSH OVER MUSH TIMES A PLUS NA;Lo;0;L;;;;;N;;;;; +12238;CUNEIFORM SIGN MUSH CROSSING MUSH;Lo;0;L;;;;;N;;;;; +12239;CUNEIFORM SIGN MUSH3;Lo;0;L;;;;;N;;;;; +1223A;CUNEIFORM SIGN MUSH3 TIMES A;Lo;0;L;;;;;N;;;;; +1223B;CUNEIFORM SIGN MUSH3 TIMES A PLUS DI;Lo;0;L;;;;;N;;;;; +1223C;CUNEIFORM SIGN MUSH3 TIMES DI;Lo;0;L;;;;;N;;;;; +1223D;CUNEIFORM SIGN MUSH3 GUNU;Lo;0;L;;;;;N;;;;; +1223E;CUNEIFORM SIGN NA;Lo;0;L;;;;;N;;;;; +1223F;CUNEIFORM SIGN NA2;Lo;0;L;;;;;N;;;;; +12240;CUNEIFORM SIGN NAGA;Lo;0;L;;;;;N;;;;; +12241;CUNEIFORM SIGN NAGA INVERTED;Lo;0;L;;;;;N;;;;; +12242;CUNEIFORM SIGN NAGA TIMES SHU TENU;Lo;0;L;;;;;N;;;;; +12243;CUNEIFORM SIGN NAGA OPPOSING NAGA;Lo;0;L;;;;;N;;;;; +12244;CUNEIFORM SIGN NAGAR;Lo;0;L;;;;;N;;;;; +12245;CUNEIFORM SIGN NAM NUTILLU;Lo;0;L;;;;;N;;;;; +12246;CUNEIFORM SIGN NAM;Lo;0;L;;;;;N;;;;; +12247;CUNEIFORM SIGN NAM2;Lo;0;L;;;;;N;;;;; +12248;CUNEIFORM SIGN NE;Lo;0;L;;;;;N;;;;; +12249;CUNEIFORM SIGN NE TIMES A;Lo;0;L;;;;;N;;;;; +1224A;CUNEIFORM SIGN NE TIMES UD;Lo;0;L;;;;;N;;;;; +1224B;CUNEIFORM SIGN NE SHESHIG;Lo;0;L;;;;;N;;;;; +1224C;CUNEIFORM SIGN NI;Lo;0;L;;;;;N;;;;; +1224D;CUNEIFORM SIGN NI TIMES E;Lo;0;L;;;;;N;;;;; +1224E;CUNEIFORM SIGN NI2;Lo;0;L;;;;;N;;;;; +1224F;CUNEIFORM SIGN NIM;Lo;0;L;;;;;N;;;;; +12250;CUNEIFORM SIGN NIM TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +12251;CUNEIFORM SIGN NIM TIMES GAR PLUS GAN2 TENU;Lo;0;L;;;;;N;;;;; +12252;CUNEIFORM SIGN NINDA2;Lo;0;L;;;;;N;;;;; +12253;CUNEIFORM SIGN NINDA2 TIMES AN;Lo;0;L;;;;;N;;;;; +12254;CUNEIFORM SIGN NINDA2 TIMES ASH;Lo;0;L;;;;;N;;;;; +12255;CUNEIFORM SIGN NINDA2 TIMES ASH PLUS ASH;Lo;0;L;;;;;N;;;;; +12256;CUNEIFORM SIGN NINDA2 TIMES GUD;Lo;0;L;;;;;N;;;;; +12257;CUNEIFORM SIGN NINDA2 TIMES ME PLUS GAN2 TENU;Lo;0;L;;;;;N;;;;; +12258;CUNEIFORM SIGN NINDA2 TIMES NE;Lo;0;L;;;;;N;;;;; +12259;CUNEIFORM SIGN NINDA2 TIMES NUN;Lo;0;L;;;;;N;;;;; +1225A;CUNEIFORM SIGN NINDA2 TIMES SHE;Lo;0;L;;;;;N;;;;; +1225B;CUNEIFORM SIGN NINDA2 TIMES SHE PLUS A AN;Lo;0;L;;;;;N;;;;; +1225C;CUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH;Lo;0;L;;;;;N;;;;; +1225D;CUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH PLUS ASH;Lo;0;L;;;;;N;;;;; +1225E;CUNEIFORM SIGN NINDA2 TIMES U2 PLUS ASH;Lo;0;L;;;;;N;;;;; +1225F;CUNEIFORM SIGN NINDA2 TIMES USH;Lo;0;L;;;;;N;;;;; +12260;CUNEIFORM SIGN NISAG;Lo;0;L;;;;;N;;;;; +12261;CUNEIFORM SIGN NU;Lo;0;L;;;;;N;;;;; +12262;CUNEIFORM SIGN NU11;Lo;0;L;;;;;N;;;;; +12263;CUNEIFORM SIGN NUN;Lo;0;L;;;;;N;;;;; +12264;CUNEIFORM SIGN NUN LAGAR TIMES GAR;Lo;0;L;;;;;N;;;;; +12265;CUNEIFORM SIGN NUN LAGAR TIMES MASH;Lo;0;L;;;;;N;;;;; +12266;CUNEIFORM SIGN NUN LAGAR TIMES SAL;Lo;0;L;;;;;N;;;;; +12267;CUNEIFORM SIGN NUN LAGAR TIMES SAL OVER NUN LAGAR TIMES SAL;Lo;0;L;;;;;N;;;;; +12268;CUNEIFORM SIGN NUN LAGAR TIMES USH;Lo;0;L;;;;;N;;;;; +12269;CUNEIFORM SIGN NUN TENU;Lo;0;L;;;;;N;;;;; +1226A;CUNEIFORM SIGN NUN OVER NUN;Lo;0;L;;;;;N;;;;; +1226B;CUNEIFORM SIGN NUN CROSSING NUN;Lo;0;L;;;;;N;;;;; +1226C;CUNEIFORM SIGN NUN CROSSING NUN LAGAR OVER LAGAR;Lo;0;L;;;;;N;;;;; +1226D;CUNEIFORM SIGN NUNUZ;Lo;0;L;;;;;N;;;;; +1226E;CUNEIFORM SIGN NUNUZ AB2 TIMES ASHGAB;Lo;0;L;;;;;N;;;;; +1226F;CUNEIFORM SIGN NUNUZ AB2 TIMES BI;Lo;0;L;;;;;N;;;;; +12270;CUNEIFORM SIGN NUNUZ AB2 TIMES DUG;Lo;0;L;;;;;N;;;;; +12271;CUNEIFORM SIGN NUNUZ AB2 TIMES GUD;Lo;0;L;;;;;N;;;;; +12272;CUNEIFORM SIGN NUNUZ AB2 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +12273;CUNEIFORM SIGN NUNUZ AB2 TIMES KAD3;Lo;0;L;;;;;N;;;;; +12274;CUNEIFORM SIGN NUNUZ AB2 TIMES LA;Lo;0;L;;;;;N;;;;; +12275;CUNEIFORM SIGN NUNUZ AB2 TIMES NE;Lo;0;L;;;;;N;;;;; +12276;CUNEIFORM SIGN NUNUZ AB2 TIMES SILA3;Lo;0;L;;;;;N;;;;; +12277;CUNEIFORM SIGN NUNUZ AB2 TIMES U2;Lo;0;L;;;;;N;;;;; +12278;CUNEIFORM SIGN NUNUZ KISIM5 TIMES BI;Lo;0;L;;;;;N;;;;; +12279;CUNEIFORM SIGN NUNUZ KISIM5 TIMES BI U;Lo;0;L;;;;;N;;;;; +1227A;CUNEIFORM SIGN PA;Lo;0;L;;;;;N;;;;; +1227B;CUNEIFORM SIGN PAD;Lo;0;L;;;;;N;;;;; +1227C;CUNEIFORM SIGN PAN;Lo;0;L;;;;;N;;;;; +1227D;CUNEIFORM SIGN PAP;Lo;0;L;;;;;N;;;;; +1227E;CUNEIFORM SIGN PESH2;Lo;0;L;;;;;N;;;;; +1227F;CUNEIFORM SIGN PI;Lo;0;L;;;;;N;;;;; +12280;CUNEIFORM SIGN PI TIMES A;Lo;0;L;;;;;N;;;;; +12281;CUNEIFORM SIGN PI TIMES AB;Lo;0;L;;;;;N;;;;; +12282;CUNEIFORM SIGN PI TIMES BI;Lo;0;L;;;;;N;;;;; +12283;CUNEIFORM SIGN PI TIMES BU;Lo;0;L;;;;;N;;;;; +12284;CUNEIFORM SIGN PI TIMES E;Lo;0;L;;;;;N;;;;; +12285;CUNEIFORM SIGN PI TIMES I;Lo;0;L;;;;;N;;;;; +12286;CUNEIFORM SIGN PI TIMES IB;Lo;0;L;;;;;N;;;;; +12287;CUNEIFORM SIGN PI TIMES U;Lo;0;L;;;;;N;;;;; +12288;CUNEIFORM SIGN PI TIMES U2;Lo;0;L;;;;;N;;;;; +12289;CUNEIFORM SIGN PI CROSSING PI;Lo;0;L;;;;;N;;;;; +1228A;CUNEIFORM SIGN PIRIG;Lo;0;L;;;;;N;;;;; +1228B;CUNEIFORM SIGN PIRIG TIMES KAL;Lo;0;L;;;;;N;;;;; +1228C;CUNEIFORM SIGN PIRIG TIMES UD;Lo;0;L;;;;;N;;;;; +1228D;CUNEIFORM SIGN PIRIG TIMES ZA;Lo;0;L;;;;;N;;;;; +1228E;CUNEIFORM SIGN PIRIG OPPOSING PIRIG;Lo;0;L;;;;;N;;;;; +1228F;CUNEIFORM SIGN RA;Lo;0;L;;;;;N;;;;; +12290;CUNEIFORM SIGN RAB;Lo;0;L;;;;;N;;;;; +12291;CUNEIFORM SIGN RI;Lo;0;L;;;;;N;;;;; +12292;CUNEIFORM SIGN RU;Lo;0;L;;;;;N;;;;; +12293;CUNEIFORM SIGN SA;Lo;0;L;;;;;N;;;;; +12294;CUNEIFORM SIGN SAG NUTILLU;Lo;0;L;;;;;N;;;;; +12295;CUNEIFORM SIGN SAG;Lo;0;L;;;;;N;;;;; +12296;CUNEIFORM SIGN SAG TIMES A;Lo;0;L;;;;;N;;;;; +12297;CUNEIFORM SIGN SAG TIMES DU;Lo;0;L;;;;;N;;;;; +12298;CUNEIFORM SIGN SAG TIMES DUB;Lo;0;L;;;;;N;;;;; +12299;CUNEIFORM SIGN SAG TIMES HA;Lo;0;L;;;;;N;;;;; +1229A;CUNEIFORM SIGN SAG TIMES KAK;Lo;0;L;;;;;N;;;;; +1229B;CUNEIFORM SIGN SAG TIMES KUR;Lo;0;L;;;;;N;;;;; +1229C;CUNEIFORM SIGN SAG TIMES LUM;Lo;0;L;;;;;N;;;;; +1229D;CUNEIFORM SIGN SAG TIMES MI;Lo;0;L;;;;;N;;;;; +1229E;CUNEIFORM SIGN SAG TIMES NUN;Lo;0;L;;;;;N;;;;; +1229F;CUNEIFORM SIGN SAG TIMES SAL;Lo;0;L;;;;;N;;;;; +122A0;CUNEIFORM SIGN SAG TIMES SHID;Lo;0;L;;;;;N;;;;; +122A1;CUNEIFORM SIGN SAG TIMES TAB;Lo;0;L;;;;;N;;;;; +122A2;CUNEIFORM SIGN SAG TIMES U2;Lo;0;L;;;;;N;;;;; +122A3;CUNEIFORM SIGN SAG TIMES UB;Lo;0;L;;;;;N;;;;; +122A4;CUNEIFORM SIGN SAG TIMES UM;Lo;0;L;;;;;N;;;;; +122A5;CUNEIFORM SIGN SAG TIMES UR;Lo;0;L;;;;;N;;;;; +122A6;CUNEIFORM SIGN SAG TIMES USH;Lo;0;L;;;;;N;;;;; +122A7;CUNEIFORM SIGN SAG OVER SAG;Lo;0;L;;;;;N;;;;; +122A8;CUNEIFORM SIGN SAG GUNU;Lo;0;L;;;;;N;;;;; +122A9;CUNEIFORM SIGN SAL;Lo;0;L;;;;;N;;;;; +122AA;CUNEIFORM SIGN SAL LAGAB TIMES ASH2;Lo;0;L;;;;;N;;;;; +122AB;CUNEIFORM SIGN SANGA2;Lo;0;L;;;;;N;;;;; +122AC;CUNEIFORM SIGN SAR;Lo;0;L;;;;;N;;;;; +122AD;CUNEIFORM SIGN SHA;Lo;0;L;;;;;N;;;;; +122AE;CUNEIFORM SIGN SHA3;Lo;0;L;;;;;N;;;;; +122AF;CUNEIFORM SIGN SHA3 TIMES A;Lo;0;L;;;;;N;;;;; +122B0;CUNEIFORM SIGN SHA3 TIMES BAD;Lo;0;L;;;;;N;;;;; +122B1;CUNEIFORM SIGN SHA3 TIMES GISH;Lo;0;L;;;;;N;;;;; +122B2;CUNEIFORM SIGN SHA3 TIMES NE;Lo;0;L;;;;;N;;;;; +122B3;CUNEIFORM SIGN SHA3 TIMES SHU2;Lo;0;L;;;;;N;;;;; +122B4;CUNEIFORM SIGN SHA3 TIMES TUR;Lo;0;L;;;;;N;;;;; +122B5;CUNEIFORM SIGN SHA3 TIMES U;Lo;0;L;;;;;N;;;;; +122B6;CUNEIFORM SIGN SHA3 TIMES U PLUS A;Lo;0;L;;;;;N;;;;; +122B7;CUNEIFORM SIGN SHA6;Lo;0;L;;;;;N;;;;; +122B8;CUNEIFORM SIGN SHAB6;Lo;0;L;;;;;N;;;;; +122B9;CUNEIFORM SIGN SHAR2;Lo;0;L;;;;;N;;;;; +122BA;CUNEIFORM SIGN SHE;Lo;0;L;;;;;N;;;;; +122BB;CUNEIFORM SIGN SHE HU;Lo;0;L;;;;;N;;;;; +122BC;CUNEIFORM SIGN SHE OVER SHE GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;; +122BD;CUNEIFORM SIGN SHE OVER SHE TAB OVER TAB GAR OVER GAR;Lo;0;L;;;;;N;;;;; +122BE;CUNEIFORM SIGN SHEG9;Lo;0;L;;;;;N;;;;; +122BF;CUNEIFORM SIGN SHEN;Lo;0;L;;;;;N;;;;; +122C0;CUNEIFORM SIGN SHESH;Lo;0;L;;;;;N;;;;; +122C1;CUNEIFORM SIGN SHESH2;Lo;0;L;;;;;N;;;;; +122C2;CUNEIFORM SIGN SHESHLAM;Lo;0;L;;;;;N;;;;; +122C3;CUNEIFORM SIGN SHID;Lo;0;L;;;;;N;;;;; +122C4;CUNEIFORM SIGN SHID TIMES A;Lo;0;L;;;;;N;;;;; +122C5;CUNEIFORM SIGN SHID TIMES IM;Lo;0;L;;;;;N;;;;; +122C6;CUNEIFORM SIGN SHIM;Lo;0;L;;;;;N;;;;; +122C7;CUNEIFORM SIGN SHIM TIMES A;Lo;0;L;;;;;N;;;;; +122C8;CUNEIFORM SIGN SHIM TIMES BAL;Lo;0;L;;;;;N;;;;; +122C9;CUNEIFORM SIGN SHIM TIMES BULUG;Lo;0;L;;;;;N;;;;; +122CA;CUNEIFORM SIGN SHIM TIMES DIN;Lo;0;L;;;;;N;;;;; +122CB;CUNEIFORM SIGN SHIM TIMES GAR;Lo;0;L;;;;;N;;;;; +122CC;CUNEIFORM SIGN SHIM TIMES IGI;Lo;0;L;;;;;N;;;;; +122CD;CUNEIFORM SIGN SHIM TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +122CE;CUNEIFORM SIGN SHIM TIMES KUSHU2;Lo;0;L;;;;;N;;;;; +122CF;CUNEIFORM SIGN SHIM TIMES LUL;Lo;0;L;;;;;N;;;;; +122D0;CUNEIFORM SIGN SHIM TIMES MUG;Lo;0;L;;;;;N;;;;; +122D1;CUNEIFORM SIGN SHIM TIMES SAL;Lo;0;L;;;;;N;;;;; +122D2;CUNEIFORM SIGN SHINIG;Lo;0;L;;;;;N;;;;; +122D3;CUNEIFORM SIGN SHIR;Lo;0;L;;;;;N;;;;; +122D4;CUNEIFORM SIGN SHIR TENU;Lo;0;L;;;;;N;;;;; +122D5;CUNEIFORM SIGN SHIR OVER SHIR BUR OVER BUR;Lo;0;L;;;;;N;;;;; +122D6;CUNEIFORM SIGN SHITA;Lo;0;L;;;;;N;;;;; +122D7;CUNEIFORM SIGN SHU;Lo;0;L;;;;;N;;;;; +122D8;CUNEIFORM SIGN SHU OVER INVERTED SHU;Lo;0;L;;;;;N;;;;; +122D9;CUNEIFORM SIGN SHU2;Lo;0;L;;;;;N;;;;; +122DA;CUNEIFORM SIGN SHUBUR;Lo;0;L;;;;;N;;;;; +122DB;CUNEIFORM SIGN SI;Lo;0;L;;;;;N;;;;; +122DC;CUNEIFORM SIGN SI GUNU;Lo;0;L;;;;;N;;;;; +122DD;CUNEIFORM SIGN SIG;Lo;0;L;;;;;N;;;;; +122DE;CUNEIFORM SIGN SIG4;Lo;0;L;;;;;N;;;;; +122DF;CUNEIFORM SIGN SIG4 OVER SIG4 SHU2;Lo;0;L;;;;;N;;;;; +122E0;CUNEIFORM SIGN SIK2;Lo;0;L;;;;;N;;;;; +122E1;CUNEIFORM SIGN SILA3;Lo;0;L;;;;;N;;;;; +122E2;CUNEIFORM SIGN SU;Lo;0;L;;;;;N;;;;; +122E3;CUNEIFORM SIGN SU OVER SU;Lo;0;L;;;;;N;;;;; +122E4;CUNEIFORM SIGN SUD;Lo;0;L;;;;;N;;;;; +122E5;CUNEIFORM SIGN SUD2;Lo;0;L;;;;;N;;;;; +122E6;CUNEIFORM SIGN SUHUR;Lo;0;L;;;;;N;;;;; +122E7;CUNEIFORM SIGN SUM;Lo;0;L;;;;;N;;;;; +122E8;CUNEIFORM SIGN SUMASH;Lo;0;L;;;;;N;;;;; +122E9;CUNEIFORM SIGN SUR;Lo;0;L;;;;;N;;;;; +122EA;CUNEIFORM SIGN SUR9;Lo;0;L;;;;;N;;;;; +122EB;CUNEIFORM SIGN TA;Lo;0;L;;;;;N;;;;; +122EC;CUNEIFORM SIGN TA ASTERISK;Lo;0;L;;;;;N;;;;; +122ED;CUNEIFORM SIGN TA TIMES HI;Lo;0;L;;;;;N;;;;; +122EE;CUNEIFORM SIGN TA TIMES MI;Lo;0;L;;;;;N;;;;; +122EF;CUNEIFORM SIGN TA GUNU;Lo;0;L;;;;;N;;;;; +122F0;CUNEIFORM SIGN TAB;Lo;0;L;;;;;N;;;;; +122F1;CUNEIFORM SIGN TAB OVER TAB NI OVER NI DISH OVER DISH;Lo;0;L;;;;;N;;;;; +122F2;CUNEIFORM SIGN TAB SQUARED;Lo;0;L;;;;;N;;;;; +122F3;CUNEIFORM SIGN TAG;Lo;0;L;;;;;N;;;;; +122F4;CUNEIFORM SIGN TAG TIMES BI;Lo;0;L;;;;;N;;;;; +122F5;CUNEIFORM SIGN TAG TIMES GUD;Lo;0;L;;;;;N;;;;; +122F6;CUNEIFORM SIGN TAG TIMES SHE;Lo;0;L;;;;;N;;;;; +122F7;CUNEIFORM SIGN TAG TIMES SHU;Lo;0;L;;;;;N;;;;; +122F8;CUNEIFORM SIGN TAG TIMES TUG2;Lo;0;L;;;;;N;;;;; +122F9;CUNEIFORM SIGN TAG TIMES UD;Lo;0;L;;;;;N;;;;; +122FA;CUNEIFORM SIGN TAK4;Lo;0;L;;;;;N;;;;; +122FB;CUNEIFORM SIGN TAR;Lo;0;L;;;;;N;;;;; +122FC;CUNEIFORM SIGN TE;Lo;0;L;;;;;N;;;;; +122FD;CUNEIFORM SIGN TE GUNU;Lo;0;L;;;;;N;;;;; +122FE;CUNEIFORM SIGN TI;Lo;0;L;;;;;N;;;;; +122FF;CUNEIFORM SIGN TI TENU;Lo;0;L;;;;;N;;;;; +12300;CUNEIFORM SIGN TIL;Lo;0;L;;;;;N;;;;; +12301;CUNEIFORM SIGN TIR;Lo;0;L;;;;;N;;;;; +12302;CUNEIFORM SIGN TIR TIMES TAK4;Lo;0;L;;;;;N;;;;; +12303;CUNEIFORM SIGN TIR OVER TIR;Lo;0;L;;;;;N;;;;; +12304;CUNEIFORM SIGN TIR OVER TIR GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;; +12305;CUNEIFORM SIGN TU;Lo;0;L;;;;;N;;;;; +12306;CUNEIFORM SIGN TUG2;Lo;0;L;;;;;N;;;;; +12307;CUNEIFORM SIGN TUK;Lo;0;L;;;;;N;;;;; +12308;CUNEIFORM SIGN TUM;Lo;0;L;;;;;N;;;;; +12309;CUNEIFORM SIGN TUR;Lo;0;L;;;;;N;;;;; +1230A;CUNEIFORM SIGN TUR OVER TUR ZA OVER ZA;Lo;0;L;;;;;N;;;;; +1230B;CUNEIFORM SIGN U;Lo;0;L;;;;1;N;;;;; +1230C;CUNEIFORM SIGN U GUD;Lo;0;L;;;;;N;;;;; +1230D;CUNEIFORM SIGN U U U;Lo;0;L;;;;3;N;;;;; +1230E;CUNEIFORM SIGN U OVER U PA OVER PA GAR OVER GAR;Lo;0;L;;;;;N;;;;; +1230F;CUNEIFORM SIGN U OVER U SUR OVER SUR;Lo;0;L;;;;;N;;;;; +12310;CUNEIFORM SIGN U OVER U U REVERSED OVER U REVERSED;Lo;0;L;;;;;N;;;;; +12311;CUNEIFORM SIGN U2;Lo;0;L;;;;;N;;;;; +12312;CUNEIFORM SIGN UB;Lo;0;L;;;;;N;;;;; +12313;CUNEIFORM SIGN UD;Lo;0;L;;;;;N;;;;; +12314;CUNEIFORM SIGN UD KUSHU2;Lo;0;L;;;;;N;;;;; +12315;CUNEIFORM SIGN UD TIMES BAD;Lo;0;L;;;;;N;;;;; +12316;CUNEIFORM SIGN UD TIMES MI;Lo;0;L;;;;;N;;;;; +12317;CUNEIFORM SIGN UD TIMES U PLUS U PLUS U;Lo;0;L;;;;;N;;;;; +12318;CUNEIFORM SIGN UD TIMES U PLUS U PLUS U GUNU;Lo;0;L;;;;;N;;;;; +12319;CUNEIFORM SIGN UD GUNU;Lo;0;L;;;;;N;;;;; +1231A;CUNEIFORM SIGN UD SHESHIG;Lo;0;L;;;;;N;;;;; +1231B;CUNEIFORM SIGN UD SHESHIG TIMES BAD;Lo;0;L;;;;;N;;;;; +1231C;CUNEIFORM SIGN UDUG;Lo;0;L;;;;;N;;;;; +1231D;CUNEIFORM SIGN UM;Lo;0;L;;;;;N;;;;; +1231E;CUNEIFORM SIGN UM TIMES LAGAB;Lo;0;L;;;;;N;;;;; +1231F;CUNEIFORM SIGN UM TIMES ME PLUS DA;Lo;0;L;;;;;N;;;;; +12320;CUNEIFORM SIGN UM TIMES SHA3;Lo;0;L;;;;;N;;;;; +12321;CUNEIFORM SIGN UM TIMES U;Lo;0;L;;;;;N;;;;; +12322;CUNEIFORM SIGN UMBIN;Lo;0;L;;;;;N;;;;; +12323;CUNEIFORM SIGN UMUM;Lo;0;L;;;;;N;;;;; +12324;CUNEIFORM SIGN UMUM TIMES KASKAL;Lo;0;L;;;;;N;;;;; +12325;CUNEIFORM SIGN UMUM TIMES PA;Lo;0;L;;;;;N;;;;; +12326;CUNEIFORM SIGN UN;Lo;0;L;;;;;N;;;;; +12327;CUNEIFORM SIGN UN GUNU;Lo;0;L;;;;;N;;;;; +12328;CUNEIFORM SIGN UR;Lo;0;L;;;;;N;;;;; +12329;CUNEIFORM SIGN UR CROSSING UR;Lo;0;L;;;;;N;;;;; +1232A;CUNEIFORM SIGN UR SHESHIG;Lo;0;L;;;;;N;;;;; +1232B;CUNEIFORM SIGN UR2;Lo;0;L;;;;;N;;;;; +1232C;CUNEIFORM SIGN UR2 TIMES A PLUS HA;Lo;0;L;;;;;N;;;;; +1232D;CUNEIFORM SIGN UR2 TIMES A PLUS NA;Lo;0;L;;;;;N;;;;; +1232E;CUNEIFORM SIGN UR2 TIMES AL;Lo;0;L;;;;;N;;;;; +1232F;CUNEIFORM SIGN UR2 TIMES HA;Lo;0;L;;;;;N;;;;; +12330;CUNEIFORM SIGN UR2 TIMES NUN;Lo;0;L;;;;;N;;;;; +12331;CUNEIFORM SIGN UR2 TIMES U2;Lo;0;L;;;;;N;;;;; +12332;CUNEIFORM SIGN UR2 TIMES U2 PLUS ASH;Lo;0;L;;;;;N;;;;; +12333;CUNEIFORM SIGN UR2 TIMES U2 PLUS BI;Lo;0;L;;;;;N;;;;; +12334;CUNEIFORM SIGN UR4;Lo;0;L;;;;;N;;;;; +12335;CUNEIFORM SIGN URI;Lo;0;L;;;;;N;;;;; +12336;CUNEIFORM SIGN URI3;Lo;0;L;;;;;N;;;;; +12337;CUNEIFORM SIGN URU;Lo;0;L;;;;;N;;;;; +12338;CUNEIFORM SIGN URU TIMES A;Lo;0;L;;;;;N;;;;; +12339;CUNEIFORM SIGN URU TIMES ASHGAB;Lo;0;L;;;;;N;;;;; +1233A;CUNEIFORM SIGN URU TIMES BAR;Lo;0;L;;;;;N;;;;; +1233B;CUNEIFORM SIGN URU TIMES DUN;Lo;0;L;;;;;N;;;;; +1233C;CUNEIFORM SIGN URU TIMES GA;Lo;0;L;;;;;N;;;;; +1233D;CUNEIFORM SIGN URU TIMES GAL;Lo;0;L;;;;;N;;;;; +1233E;CUNEIFORM SIGN URU TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +1233F;CUNEIFORM SIGN URU TIMES GAR;Lo;0;L;;;;;N;;;;; +12340;CUNEIFORM SIGN URU TIMES GU;Lo;0;L;;;;;N;;;;; +12341;CUNEIFORM SIGN URU TIMES HA;Lo;0;L;;;;;N;;;;; +12342;CUNEIFORM SIGN URU TIMES IGI;Lo;0;L;;;;;N;;;;; +12343;CUNEIFORM SIGN URU TIMES IM;Lo;0;L;;;;;N;;;;; +12344;CUNEIFORM SIGN URU TIMES ISH;Lo;0;L;;;;;N;;;;; +12345;CUNEIFORM SIGN URU TIMES KI;Lo;0;L;;;;;N;;;;; +12346;CUNEIFORM SIGN URU TIMES LUM;Lo;0;L;;;;;N;;;;; +12347;CUNEIFORM SIGN URU TIMES MIN;Lo;0;L;;;;;N;;;;; +12348;CUNEIFORM SIGN URU TIMES PA;Lo;0;L;;;;;N;;;;; +12349;CUNEIFORM SIGN URU TIMES SHE;Lo;0;L;;;;;N;;;;; +1234A;CUNEIFORM SIGN URU TIMES SIG4;Lo;0;L;;;;;N;;;;; +1234B;CUNEIFORM SIGN URU TIMES TU;Lo;0;L;;;;;N;;;;; +1234C;CUNEIFORM SIGN URU TIMES U PLUS GUD;Lo;0;L;;;;;N;;;;; +1234D;CUNEIFORM SIGN URU TIMES UD;Lo;0;L;;;;;N;;;;; +1234E;CUNEIFORM SIGN URU TIMES URUDA;Lo;0;L;;;;;N;;;;; +1234F;CUNEIFORM SIGN URUDA;Lo;0;L;;;;;N;;;;; +12350;CUNEIFORM SIGN URUDA TIMES U;Lo;0;L;;;;;N;;;;; +12351;CUNEIFORM SIGN USH;Lo;0;L;;;;;N;;;;; +12352;CUNEIFORM SIGN USH TIMES A;Lo;0;L;;;;;N;;;;; +12353;CUNEIFORM SIGN USH TIMES KU;Lo;0;L;;;;;N;;;;; +12354;CUNEIFORM SIGN USH TIMES KUR;Lo;0;L;;;;;N;;;;; +12355;CUNEIFORM SIGN USH TIMES TAK4;Lo;0;L;;;;;N;;;;; +12356;CUNEIFORM SIGN USHX;Lo;0;L;;;;;N;;;;; +12357;CUNEIFORM SIGN USH2;Lo;0;L;;;;;N;;;;; +12358;CUNEIFORM SIGN USHUMX;Lo;0;L;;;;;N;;;;; +12359;CUNEIFORM SIGN UTUKI;Lo;0;L;;;;;N;;;;; +1235A;CUNEIFORM SIGN UZ3;Lo;0;L;;;;;N;;;;; +1235B;CUNEIFORM SIGN UZ3 TIMES KASKAL;Lo;0;L;;;;;N;;;;; +1235C;CUNEIFORM SIGN UZU;Lo;0;L;;;;;N;;;;; +1235D;CUNEIFORM SIGN ZA;Lo;0;L;;;;;N;;;;; +1235E;CUNEIFORM SIGN ZA TENU;Lo;0;L;;;;;N;;;;; +1235F;CUNEIFORM SIGN ZA SQUARED TIMES KUR;Lo;0;L;;;;;N;;;;; +12360;CUNEIFORM SIGN ZAG;Lo;0;L;;;;;N;;;;; +12361;CUNEIFORM SIGN ZAMX;Lo;0;L;;;;;N;;;;; +12362;CUNEIFORM SIGN ZE2;Lo;0;L;;;;;N;;;;; +12363;CUNEIFORM SIGN ZI;Lo;0;L;;;;;N;;;;; +12364;CUNEIFORM SIGN ZI OVER ZI;Lo;0;L;;;;;N;;;;; +12365;CUNEIFORM SIGN ZI3;Lo;0;L;;;;;N;;;;; +12366;CUNEIFORM SIGN ZIB;Lo;0;L;;;;;N;;;;; +12367;CUNEIFORM SIGN ZIB KABA TENU;Lo;0;L;;;;;N;;;;; +12368;CUNEIFORM SIGN ZIG;Lo;0;L;;;;;N;;;;; +12369;CUNEIFORM SIGN ZIZ2;Lo;0;L;;;;;N;;;;; +1236A;CUNEIFORM SIGN ZU;Lo;0;L;;;;;N;;;;; +1236B;CUNEIFORM SIGN ZU5;Lo;0;L;;;;;N;;;;; +1236C;CUNEIFORM SIGN ZU5 TIMES A;Lo;0;L;;;;;N;;;;; +1236D;CUNEIFORM SIGN ZUBUR;Lo;0;L;;;;;N;;;;; +1236E;CUNEIFORM SIGN ZUM;Lo;0;L;;;;;N;;;;; +1236F;CUNEIFORM SIGN KAP ELAMITE;Lo;0;L;;;;;N;;;;; +12370;CUNEIFORM SIGN AB TIMES NUN;Lo;0;L;;;;;N;;;;; +12371;CUNEIFORM SIGN AB2 TIMES A;Lo;0;L;;;;;N;;;;; +12372;CUNEIFORM SIGN AMAR TIMES KUG;Lo;0;L;;;;;N;;;;; +12373;CUNEIFORM SIGN DAG KISIM5 TIMES U2 PLUS MASH;Lo;0;L;;;;;N;;;;; +12374;CUNEIFORM SIGN DAG3;Lo;0;L;;;;;N;;;;; +12375;CUNEIFORM SIGN DISH PLUS SHU;Lo;0;L;;;;;N;;;;; +12376;CUNEIFORM SIGN DUB TIMES SHE;Lo;0;L;;;;;N;;;;; +12377;CUNEIFORM SIGN EZEN TIMES GUD;Lo;0;L;;;;;N;;;;; +12378;CUNEIFORM SIGN EZEN TIMES SHE;Lo;0;L;;;;;N;;;;; +12379;CUNEIFORM SIGN GA2 TIMES AN PLUS KAK PLUS A;Lo;0;L;;;;;N;;;;; +1237A;CUNEIFORM SIGN GA2 TIMES ASH2;Lo;0;L;;;;;N;;;;; +1237B;CUNEIFORM SIGN GE22;Lo;0;L;;;;;N;;;;; +1237C;CUNEIFORM SIGN GIG;Lo;0;L;;;;;N;;;;; +1237D;CUNEIFORM SIGN HUSH;Lo;0;L;;;;;N;;;;; +1237E;CUNEIFORM SIGN KA TIMES ANSHE;Lo;0;L;;;;;N;;;;; +1237F;CUNEIFORM SIGN KA TIMES ASH3;Lo;0;L;;;;;N;;;;; +12380;CUNEIFORM SIGN KA TIMES GISH;Lo;0;L;;;;;N;;;;; +12381;CUNEIFORM SIGN KA TIMES GUD;Lo;0;L;;;;;N;;;;; +12382;CUNEIFORM SIGN KA TIMES HI TIMES ASH2;Lo;0;L;;;;;N;;;;; +12383;CUNEIFORM SIGN KA TIMES LUM;Lo;0;L;;;;;N;;;;; +12384;CUNEIFORM SIGN KA TIMES PA;Lo;0;L;;;;;N;;;;; +12385;CUNEIFORM SIGN KA TIMES SHUL;Lo;0;L;;;;;N;;;;; +12386;CUNEIFORM SIGN KA TIMES TU;Lo;0;L;;;;;N;;;;; +12387;CUNEIFORM SIGN KA TIMES UR2;Lo;0;L;;;;;N;;;;; +12388;CUNEIFORM SIGN LAGAB TIMES GI;Lo;0;L;;;;;N;;;;; +12389;CUNEIFORM SIGN LU2 SHESHIG TIMES BAD;Lo;0;L;;;;;N;;;;; +1238A;CUNEIFORM SIGN LU2 TIMES ESH2 PLUS LAL;Lo;0;L;;;;;N;;;;; +1238B;CUNEIFORM SIGN LU2 TIMES SHU;Lo;0;L;;;;;N;;;;; +1238C;CUNEIFORM SIGN MESH;Lo;0;L;;;;;N;;;;; +1238D;CUNEIFORM SIGN MUSH3 TIMES ZA;Lo;0;L;;;;;N;;;;; +1238E;CUNEIFORM SIGN NA4;Lo;0;L;;;;;N;;;;; +1238F;CUNEIFORM SIGN NIN;Lo;0;L;;;;;N;;;;; +12390;CUNEIFORM SIGN NIN9;Lo;0;L;;;;;N;;;;; +12391;CUNEIFORM SIGN NINDA2 TIMES BAL;Lo;0;L;;;;;N;;;;; +12392;CUNEIFORM SIGN NINDA2 TIMES GI;Lo;0;L;;;;;N;;;;; +12393;CUNEIFORM SIGN NU11 ROTATED NINETY DEGREES;Lo;0;L;;;;;N;;;;; +12394;CUNEIFORM SIGN PESH2 ASTERISK;Lo;0;L;;;;;N;;;;; +12395;CUNEIFORM SIGN PIR2;Lo;0;L;;;;;N;;;;; +12396;CUNEIFORM SIGN SAG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +12397;CUNEIFORM SIGN TI2;Lo;0;L;;;;;N;;;;; +12398;CUNEIFORM SIGN UM TIMES ME;Lo;0;L;;;;;N;;;;; +12399;CUNEIFORM SIGN U U;Lo;0;L;;;;2;N;;;;; +12400;CUNEIFORM NUMERIC SIGN TWO ASH;Nl;0;L;;;;2;N;;;;; +12401;CUNEIFORM NUMERIC SIGN THREE ASH;Nl;0;L;;;;3;N;;;;; +12402;CUNEIFORM NUMERIC SIGN FOUR ASH;Nl;0;L;;;;4;N;;;;; +12403;CUNEIFORM NUMERIC SIGN FIVE ASH;Nl;0;L;;;;5;N;;;;; +12404;CUNEIFORM NUMERIC SIGN SIX ASH;Nl;0;L;;;;6;N;;;;; +12405;CUNEIFORM NUMERIC SIGN SEVEN ASH;Nl;0;L;;;;7;N;;;;; +12406;CUNEIFORM NUMERIC SIGN EIGHT ASH;Nl;0;L;;;;8;N;;;;; +12407;CUNEIFORM NUMERIC SIGN NINE ASH;Nl;0;L;;;;9;N;;;;; +12408;CUNEIFORM NUMERIC SIGN THREE DISH;Nl;0;L;;;;3;N;;;;; +12409;CUNEIFORM NUMERIC SIGN FOUR DISH;Nl;0;L;;;;4;N;;;;; +1240A;CUNEIFORM NUMERIC SIGN FIVE DISH;Nl;0;L;;;;5;N;;;;; +1240B;CUNEIFORM NUMERIC SIGN SIX DISH;Nl;0;L;;;;6;N;;;;; +1240C;CUNEIFORM NUMERIC SIGN SEVEN DISH;Nl;0;L;;;;7;N;;;;; +1240D;CUNEIFORM NUMERIC SIGN EIGHT DISH;Nl;0;L;;;;8;N;;;;; +1240E;CUNEIFORM NUMERIC SIGN NINE DISH;Nl;0;L;;;;9;N;;;;; +1240F;CUNEIFORM NUMERIC SIGN FOUR U;Nl;0;L;;;;4;N;;;;; +12410;CUNEIFORM NUMERIC SIGN FIVE U;Nl;0;L;;;;5;N;;;;; +12411;CUNEIFORM NUMERIC SIGN SIX U;Nl;0;L;;;;6;N;;;;; +12412;CUNEIFORM NUMERIC SIGN SEVEN U;Nl;0;L;;;;7;N;;;;; +12413;CUNEIFORM NUMERIC SIGN EIGHT U;Nl;0;L;;;;8;N;;;;; +12414;CUNEIFORM NUMERIC SIGN NINE U;Nl;0;L;;;;9;N;;;;; +12415;CUNEIFORM NUMERIC SIGN ONE GESH2;Nl;0;L;;;;1;N;;;;; +12416;CUNEIFORM NUMERIC SIGN TWO GESH2;Nl;0;L;;;;2;N;;;;; +12417;CUNEIFORM NUMERIC SIGN THREE GESH2;Nl;0;L;;;;3;N;;;;; +12418;CUNEIFORM NUMERIC SIGN FOUR GESH2;Nl;0;L;;;;4;N;;;;; +12419;CUNEIFORM NUMERIC SIGN FIVE GESH2;Nl;0;L;;;;5;N;;;;; +1241A;CUNEIFORM NUMERIC SIGN SIX GESH2;Nl;0;L;;;;6;N;;;;; +1241B;CUNEIFORM NUMERIC SIGN SEVEN GESH2;Nl;0;L;;;;7;N;;;;; +1241C;CUNEIFORM NUMERIC SIGN EIGHT GESH2;Nl;0;L;;;;8;N;;;;; +1241D;CUNEIFORM NUMERIC SIGN NINE GESH2;Nl;0;L;;;;9;N;;;;; +1241E;CUNEIFORM NUMERIC SIGN ONE GESHU;Nl;0;L;;;;1;N;;;;; +1241F;CUNEIFORM NUMERIC SIGN TWO GESHU;Nl;0;L;;;;2;N;;;;; +12420;CUNEIFORM NUMERIC SIGN THREE GESHU;Nl;0;L;;;;3;N;;;;; +12421;CUNEIFORM NUMERIC SIGN FOUR GESHU;Nl;0;L;;;;4;N;;;;; +12422;CUNEIFORM NUMERIC SIGN FIVE GESHU;Nl;0;L;;;;5;N;;;;; +12423;CUNEIFORM NUMERIC SIGN TWO SHAR2;Nl;0;L;;;;2;N;;;;; +12424;CUNEIFORM NUMERIC SIGN THREE SHAR2;Nl;0;L;;;;3;N;;;;; +12425;CUNEIFORM NUMERIC SIGN THREE SHAR2 VARIANT FORM;Nl;0;L;;;;3;N;;;;; +12426;CUNEIFORM NUMERIC SIGN FOUR SHAR2;Nl;0;L;;;;4;N;;;;; +12427;CUNEIFORM NUMERIC SIGN FIVE SHAR2;Nl;0;L;;;;5;N;;;;; +12428;CUNEIFORM NUMERIC SIGN SIX SHAR2;Nl;0;L;;;;6;N;;;;; +12429;CUNEIFORM NUMERIC SIGN SEVEN SHAR2;Nl;0;L;;;;7;N;;;;; +1242A;CUNEIFORM NUMERIC SIGN EIGHT SHAR2;Nl;0;L;;;;8;N;;;;; +1242B;CUNEIFORM NUMERIC SIGN NINE SHAR2;Nl;0;L;;;;9;N;;;;; +1242C;CUNEIFORM NUMERIC SIGN ONE SHARU;Nl;0;L;;;;1;N;;;;; +1242D;CUNEIFORM NUMERIC SIGN TWO SHARU;Nl;0;L;;;;2;N;;;;; +1242E;CUNEIFORM NUMERIC SIGN THREE SHARU;Nl;0;L;;;;3;N;;;;; +1242F;CUNEIFORM NUMERIC SIGN THREE SHARU VARIANT FORM;Nl;0;L;;;;3;N;;;;; +12430;CUNEIFORM NUMERIC SIGN FOUR SHARU;Nl;0;L;;;;4;N;;;;; +12431;CUNEIFORM NUMERIC SIGN FIVE SHARU;Nl;0;L;;;;5;N;;;;; +12432;CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS DISH;Nl;0;L;;;;216000;N;;;;; +12433;CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS MIN;Nl;0;L;;;;432000;N;;;;; +12434;CUNEIFORM NUMERIC SIGN ONE BURU;Nl;0;L;;;;1;N;;;;; +12435;CUNEIFORM NUMERIC SIGN TWO BURU;Nl;0;L;;;;2;N;;;;; +12436;CUNEIFORM NUMERIC SIGN THREE BURU;Nl;0;L;;;;3;N;;;;; +12437;CUNEIFORM NUMERIC SIGN THREE BURU VARIANT FORM;Nl;0;L;;;;3;N;;;;; +12438;CUNEIFORM NUMERIC SIGN FOUR BURU;Nl;0;L;;;;4;N;;;;; +12439;CUNEIFORM NUMERIC SIGN FIVE BURU;Nl;0;L;;;;5;N;;;;; +1243A;CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH16;Nl;0;L;;;;3;N;;;;; +1243B;CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH21;Nl;0;L;;;;3;N;;;;; +1243C;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU;Nl;0;L;;;;4;N;;;;; +1243D;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU4;Nl;0;L;;;;4;N;;;;; +1243E;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU A;Nl;0;L;;;;4;N;;;;; +1243F;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU B;Nl;0;L;;;;4;N;;;;; +12440;CUNEIFORM NUMERIC SIGN SIX VARIANT FORM ASH9;Nl;0;L;;;;6;N;;;;; +12441;CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN3;Nl;0;L;;;;7;N;;;;; +12442;CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN A;Nl;0;L;;;;7;N;;;;; +12443;CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN B;Nl;0;L;;;;7;N;;;;; +12444;CUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSU;Nl;0;L;;;;8;N;;;;; +12445;CUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSU3;Nl;0;L;;;;8;N;;;;; +12446;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU;Nl;0;L;;;;9;N;;;;; +12447;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU3;Nl;0;L;;;;9;N;;;;; +12448;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU4;Nl;0;L;;;;9;N;;;;; +12449;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU A;Nl;0;L;;;;9;N;;;;; +1244A;CUNEIFORM NUMERIC SIGN TWO ASH TENU;Nl;0;L;;;;2;N;;;;; +1244B;CUNEIFORM NUMERIC SIGN THREE ASH TENU;Nl;0;L;;;;3;N;;;;; +1244C;CUNEIFORM NUMERIC SIGN FOUR ASH TENU;Nl;0;L;;;;4;N;;;;; +1244D;CUNEIFORM NUMERIC SIGN FIVE ASH TENU;Nl;0;L;;;;5;N;;;;; +1244E;CUNEIFORM NUMERIC SIGN SIX ASH TENU;Nl;0;L;;;;6;N;;;;; +1244F;CUNEIFORM NUMERIC SIGN ONE BAN2;Nl;0;L;;;;1;N;;;;; +12450;CUNEIFORM NUMERIC SIGN TWO BAN2;Nl;0;L;;;;2;N;;;;; +12451;CUNEIFORM NUMERIC SIGN THREE BAN2;Nl;0;L;;;;3;N;;;;; +12452;CUNEIFORM NUMERIC SIGN FOUR BAN2;Nl;0;L;;;;4;N;;;;; +12453;CUNEIFORM NUMERIC SIGN FOUR BAN2 VARIANT FORM;Nl;0;L;;;;4;N;;;;; +12454;CUNEIFORM NUMERIC SIGN FIVE BAN2;Nl;0;L;;;;5;N;;;;; +12455;CUNEIFORM NUMERIC SIGN FIVE BAN2 VARIANT FORM;Nl;0;L;;;;5;N;;;;; +12456;CUNEIFORM NUMERIC SIGN NIGIDAMIN;Nl;0;L;;;;2;N;;;;; +12457;CUNEIFORM NUMERIC SIGN NIGIDAESH;Nl;0;L;;;;3;N;;;;; +12458;CUNEIFORM NUMERIC SIGN ONE ESHE3;Nl;0;L;;;;1;N;;;;; +12459;CUNEIFORM NUMERIC SIGN TWO ESHE3;Nl;0;L;;;;2;N;;;;; +1245A;CUNEIFORM NUMERIC SIGN ONE THIRD DISH;Nl;0;L;;;;1/3;N;;;;; +1245B;CUNEIFORM NUMERIC SIGN TWO THIRDS DISH;Nl;0;L;;;;2/3;N;;;;; +1245C;CUNEIFORM NUMERIC SIGN FIVE SIXTHS DISH;Nl;0;L;;;;5/6;N;;;;; +1245D;CUNEIFORM NUMERIC SIGN ONE THIRD VARIANT FORM A;Nl;0;L;;;;1/3;N;;;;; +1245E;CUNEIFORM NUMERIC SIGN TWO THIRDS VARIANT FORM A;Nl;0;L;;;;2/3;N;;;;; +1245F;CUNEIFORM NUMERIC SIGN ONE EIGHTH ASH;Nl;0;L;;;;1/8;N;;;;; +12460;CUNEIFORM NUMERIC SIGN ONE QUARTER ASH;Nl;0;L;;;;1/4;N;;;;; +12461;CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE SIXTH;Nl;0;L;;;;1/6;N;;;;; +12462;CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER;Nl;0;L;;;;1/4;N;;;;; +12463;CUNEIFORM NUMERIC SIGN ONE QUARTER GUR;Nl;0;L;;;;1/4;N;;;;; +12464;CUNEIFORM NUMERIC SIGN ONE HALF GUR;Nl;0;L;;;;1/2;N;;;;; +12465;CUNEIFORM NUMERIC SIGN ELAMITE ONE THIRD;Nl;0;L;;;;1/3;N;;;;; +12466;CUNEIFORM NUMERIC SIGN ELAMITE TWO THIRDS;Nl;0;L;;;;2/3;N;;;;; +12467;CUNEIFORM NUMERIC SIGN ELAMITE FORTY;Nl;0;L;;;;40;N;;;;; +12468;CUNEIFORM NUMERIC SIGN ELAMITE FIFTY;Nl;0;L;;;;50;N;;;;; +12469;CUNEIFORM NUMERIC SIGN FOUR U VARIANT FORM;Nl;0;L;;;;4;N;;;;; +1246A;CUNEIFORM NUMERIC SIGN FIVE U VARIANT FORM;Nl;0;L;;;;5;N;;;;; +1246B;CUNEIFORM NUMERIC SIGN SIX U VARIANT FORM;Nl;0;L;;;;6;N;;;;; +1246C;CUNEIFORM NUMERIC SIGN SEVEN U VARIANT FORM;Nl;0;L;;;;7;N;;;;; +1246D;CUNEIFORM NUMERIC SIGN EIGHT U VARIANT FORM;Nl;0;L;;;;8;N;;;;; +1246E;CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM;Nl;0;L;;;;9;N;;;;; +12470;CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER;Po;0;L;;;;;N;;;;; +12471;CUNEIFORM PUNCTUATION SIGN VERTICAL COLON;Po;0;L;;;;;N;;;;; +12472;CUNEIFORM PUNCTUATION SIGN DIAGONAL COLON;Po;0;L;;;;;N;;;;; +12473;CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON;Po;0;L;;;;;N;;;;; +12474;CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON;Po;0;L;;;;;N;;;;; +12480;CUNEIFORM SIGN AB TIMES NUN TENU;Lo;0;L;;;;;N;;;;; +12481;CUNEIFORM SIGN AB TIMES SHU2;Lo;0;L;;;;;N;;;;; +12482;CUNEIFORM SIGN AD TIMES ESH2;Lo;0;L;;;;;N;;;;; +12483;CUNEIFORM SIGN BAD TIMES DISH TENU;Lo;0;L;;;;;N;;;;; +12484;CUNEIFORM SIGN BAHAR2 TIMES AB2;Lo;0;L;;;;;N;;;;; +12485;CUNEIFORM SIGN BAHAR2 TIMES NI;Lo;0;L;;;;;N;;;;; +12486;CUNEIFORM SIGN BAHAR2 TIMES ZA;Lo;0;L;;;;;N;;;;; +12487;CUNEIFORM SIGN BU OVER BU TIMES NA2;Lo;0;L;;;;;N;;;;; +12488;CUNEIFORM SIGN DA TIMES TAK4;Lo;0;L;;;;;N;;;;; +12489;CUNEIFORM SIGN DAG TIMES KUR;Lo;0;L;;;;;N;;;;; +1248A;CUNEIFORM SIGN DIM TIMES IGI;Lo;0;L;;;;;N;;;;; +1248B;CUNEIFORM SIGN DIM TIMES U U U;Lo;0;L;;;;;N;;;;; +1248C;CUNEIFORM SIGN DIM2 TIMES UD;Lo;0;L;;;;;N;;;;; +1248D;CUNEIFORM SIGN DUG TIMES ANSHE;Lo;0;L;;;;;N;;;;; +1248E;CUNEIFORM SIGN DUG TIMES ASH;Lo;0;L;;;;;N;;;;; +1248F;CUNEIFORM SIGN DUG TIMES ASH AT LEFT;Lo;0;L;;;;;N;;;;; +12490;CUNEIFORM SIGN DUG TIMES DIN;Lo;0;L;;;;;N;;;;; +12491;CUNEIFORM SIGN DUG TIMES DUN;Lo;0;L;;;;;N;;;;; +12492;CUNEIFORM SIGN DUG TIMES ERIN2;Lo;0;L;;;;;N;;;;; +12493;CUNEIFORM SIGN DUG TIMES GA;Lo;0;L;;;;;N;;;;; +12494;CUNEIFORM SIGN DUG TIMES GI;Lo;0;L;;;;;N;;;;; +12495;CUNEIFORM SIGN DUG TIMES GIR2 GUNU;Lo;0;L;;;;;N;;;;; +12496;CUNEIFORM SIGN DUG TIMES GISH;Lo;0;L;;;;;N;;;;; +12497;CUNEIFORM SIGN DUG TIMES HA;Lo;0;L;;;;;N;;;;; +12498;CUNEIFORM SIGN DUG TIMES HI;Lo;0;L;;;;;N;;;;; +12499;CUNEIFORM SIGN DUG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +1249A;CUNEIFORM SIGN DUG TIMES KASKAL;Lo;0;L;;;;;N;;;;; +1249B;CUNEIFORM SIGN DUG TIMES KUR;Lo;0;L;;;;;N;;;;; +1249C;CUNEIFORM SIGN DUG TIMES KUSHU2;Lo;0;L;;;;;N;;;;; +1249D;CUNEIFORM SIGN DUG TIMES KUSHU2 PLUS KASKAL;Lo;0;L;;;;;N;;;;; +1249E;CUNEIFORM SIGN DUG TIMES LAK-020;Lo;0;L;;;;;N;;;;; +1249F;CUNEIFORM SIGN DUG TIMES LAM;Lo;0;L;;;;;N;;;;; +124A0;CUNEIFORM SIGN DUG TIMES LAM TIMES KUR;Lo;0;L;;;;;N;;;;; +124A1;CUNEIFORM SIGN DUG TIMES LUH PLUS GISH;Lo;0;L;;;;;N;;;;; +124A2;CUNEIFORM SIGN DUG TIMES MASH;Lo;0;L;;;;;N;;;;; +124A3;CUNEIFORM SIGN DUG TIMES MES;Lo;0;L;;;;;N;;;;; +124A4;CUNEIFORM SIGN DUG TIMES MI;Lo;0;L;;;;;N;;;;; +124A5;CUNEIFORM SIGN DUG TIMES NI;Lo;0;L;;;;;N;;;;; +124A6;CUNEIFORM SIGN DUG TIMES PI;Lo;0;L;;;;;N;;;;; +124A7;CUNEIFORM SIGN DUG TIMES SHE;Lo;0;L;;;;;N;;;;; +124A8;CUNEIFORM SIGN DUG TIMES SI GUNU;Lo;0;L;;;;;N;;;;; +124A9;CUNEIFORM SIGN E2 TIMES KUR;Lo;0;L;;;;;N;;;;; +124AA;CUNEIFORM SIGN E2 TIMES PAP;Lo;0;L;;;;;N;;;;; +124AB;CUNEIFORM SIGN ERIN2 X;Lo;0;L;;;;;N;;;;; +124AC;CUNEIFORM SIGN ESH2 CROSSING ESH2;Lo;0;L;;;;;N;;;;; +124AD;CUNEIFORM SIGN EZEN SHESHIG TIMES ASH;Lo;0;L;;;;;N;;;;; +124AE;CUNEIFORM SIGN EZEN SHESHIG TIMES HI;Lo;0;L;;;;;N;;;;; +124AF;CUNEIFORM SIGN EZEN SHESHIG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +124B0;CUNEIFORM SIGN EZEN SHESHIG TIMES LA;Lo;0;L;;;;;N;;;;; +124B1;CUNEIFORM SIGN EZEN SHESHIG TIMES LAL;Lo;0;L;;;;;N;;;;; +124B2;CUNEIFORM SIGN EZEN SHESHIG TIMES ME;Lo;0;L;;;;;N;;;;; +124B3;CUNEIFORM SIGN EZEN SHESHIG TIMES MES;Lo;0;L;;;;;N;;;;; +124B4;CUNEIFORM SIGN EZEN SHESHIG TIMES SU;Lo;0;L;;;;;N;;;;; +124B5;CUNEIFORM SIGN EZEN TIMES SU;Lo;0;L;;;;;N;;;;; +124B6;CUNEIFORM SIGN GA2 TIMES BAHAR2;Lo;0;L;;;;;N;;;;; +124B7;CUNEIFORM SIGN GA2 TIMES DIM GUNU;Lo;0;L;;;;;N;;;;; +124B8;CUNEIFORM SIGN GA2 TIMES DUG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +124B9;CUNEIFORM SIGN GA2 TIMES DUG TIMES KASKAL;Lo;0;L;;;;;N;;;;; +124BA;CUNEIFORM SIGN GA2 TIMES EREN;Lo;0;L;;;;;N;;;;; +124BB;CUNEIFORM SIGN GA2 TIMES GA;Lo;0;L;;;;;N;;;;; +124BC;CUNEIFORM SIGN GA2 TIMES GAR PLUS DI;Lo;0;L;;;;;N;;;;; +124BD;CUNEIFORM SIGN GA2 TIMES GAR PLUS NE;Lo;0;L;;;;;N;;;;; +124BE;CUNEIFORM SIGN GA2 TIMES HA PLUS A;Lo;0;L;;;;;N;;;;; +124BF;CUNEIFORM SIGN GA2 TIMES KUSHU2 PLUS KASKAL;Lo;0;L;;;;;N;;;;; +124C0;CUNEIFORM SIGN GA2 TIMES LAM;Lo;0;L;;;;;N;;;;; +124C1;CUNEIFORM SIGN GA2 TIMES LAM TIMES KUR;Lo;0;L;;;;;N;;;;; +124C2;CUNEIFORM SIGN GA2 TIMES LUH;Lo;0;L;;;;;N;;;;; +124C3;CUNEIFORM SIGN GA2 TIMES MUSH;Lo;0;L;;;;;N;;;;; +124C4;CUNEIFORM SIGN GA2 TIMES NE;Lo;0;L;;;;;N;;;;; +124C5;CUNEIFORM SIGN GA2 TIMES NE PLUS E2;Lo;0;L;;;;;N;;;;; +124C6;CUNEIFORM SIGN GA2 TIMES NE PLUS GI;Lo;0;L;;;;;N;;;;; +124C7;CUNEIFORM SIGN GA2 TIMES SHIM;Lo;0;L;;;;;N;;;;; +124C8;CUNEIFORM SIGN GA2 TIMES ZIZ2;Lo;0;L;;;;;N;;;;; +124C9;CUNEIFORM SIGN GABA ROTATED NINETY DEGREES;Lo;0;L;;;;;N;;;;; +124CA;CUNEIFORM SIGN GESHTIN TIMES U;Lo;0;L;;;;;N;;;;; +124CB;CUNEIFORM SIGN GISH TIMES GISH CROSSING GISH;Lo;0;L;;;;;N;;;;; +124CC;CUNEIFORM SIGN GU2 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +124CD;CUNEIFORM SIGN GUD PLUS GISH TIMES TAK4;Lo;0;L;;;;;N;;;;; +124CE;CUNEIFORM SIGN HA TENU GUNU;Lo;0;L;;;;;N;;;;; +124CF;CUNEIFORM SIGN HI TIMES ASH OVER HI TIMES ASH;Lo;0;L;;;;;N;;;;; +124D0;CUNEIFORM SIGN KA TIMES BU;Lo;0;L;;;;;N;;;;; +124D1;CUNEIFORM SIGN KA TIMES KA;Lo;0;L;;;;;N;;;;; +124D2;CUNEIFORM SIGN KA TIMES U U U;Lo;0;L;;;;;N;;;;; +124D3;CUNEIFORM SIGN KA TIMES UR;Lo;0;L;;;;;N;;;;; +124D4;CUNEIFORM SIGN LAGAB TIMES ZU OVER ZU;Lo;0;L;;;;;N;;;;; +124D5;CUNEIFORM SIGN LAK-003;Lo;0;L;;;;;N;;;;; +124D6;CUNEIFORM SIGN LAK-021;Lo;0;L;;;;;N;;;;; +124D7;CUNEIFORM SIGN LAK-025;Lo;0;L;;;;;N;;;;; +124D8;CUNEIFORM SIGN LAK-030;Lo;0;L;;;;;N;;;;; +124D9;CUNEIFORM SIGN LAK-050;Lo;0;L;;;;;N;;;;; +124DA;CUNEIFORM SIGN LAK-051;Lo;0;L;;;;;N;;;;; +124DB;CUNEIFORM SIGN LAK-062;Lo;0;L;;;;;N;;;;; +124DC;CUNEIFORM SIGN LAK-079 OVER LAK-079 GUNU;Lo;0;L;;;;;N;;;;; +124DD;CUNEIFORM SIGN LAK-080;Lo;0;L;;;;;N;;;;; +124DE;CUNEIFORM SIGN LAK-081 OVER LAK-081;Lo;0;L;;;;;N;;;;; +124DF;CUNEIFORM SIGN LAK-092;Lo;0;L;;;;;N;;;;; +124E0;CUNEIFORM SIGN LAK-130;Lo;0;L;;;;;N;;;;; +124E1;CUNEIFORM SIGN LAK-142;Lo;0;L;;;;;N;;;;; +124E2;CUNEIFORM SIGN LAK-210;Lo;0;L;;;;;N;;;;; +124E3;CUNEIFORM SIGN LAK-219;Lo;0;L;;;;;N;;;;; +124E4;CUNEIFORM SIGN LAK-220;Lo;0;L;;;;;N;;;;; +124E5;CUNEIFORM SIGN LAK-225;Lo;0;L;;;;;N;;;;; +124E6;CUNEIFORM SIGN LAK-228;Lo;0;L;;;;;N;;;;; +124E7;CUNEIFORM SIGN LAK-238;Lo;0;L;;;;;N;;;;; +124E8;CUNEIFORM SIGN LAK-265;Lo;0;L;;;;;N;;;;; +124E9;CUNEIFORM SIGN LAK-266;Lo;0;L;;;;;N;;;;; +124EA;CUNEIFORM SIGN LAK-343;Lo;0;L;;;;;N;;;;; +124EB;CUNEIFORM SIGN LAK-347;Lo;0;L;;;;;N;;;;; +124EC;CUNEIFORM SIGN LAK-348;Lo;0;L;;;;;N;;;;; +124ED;CUNEIFORM SIGN LAK-383;Lo;0;L;;;;;N;;;;; +124EE;CUNEIFORM SIGN LAK-384;Lo;0;L;;;;;N;;;;; +124EF;CUNEIFORM SIGN LAK-390;Lo;0;L;;;;;N;;;;; +124F0;CUNEIFORM SIGN LAK-441;Lo;0;L;;;;;N;;;;; +124F1;CUNEIFORM SIGN LAK-449;Lo;0;L;;;;;N;;;;; +124F2;CUNEIFORM SIGN LAK-449 TIMES GU;Lo;0;L;;;;;N;;;;; +124F3;CUNEIFORM SIGN LAK-449 TIMES IGI;Lo;0;L;;;;;N;;;;; +124F4;CUNEIFORM SIGN LAK-449 TIMES PAP PLUS LU3;Lo;0;L;;;;;N;;;;; +124F5;CUNEIFORM SIGN LAK-449 TIMES PAP PLUS PAP PLUS LU3;Lo;0;L;;;;;N;;;;; +124F6;CUNEIFORM SIGN LAK-449 TIMES U2 PLUS BA;Lo;0;L;;;;;N;;;;; +124F7;CUNEIFORM SIGN LAK-450;Lo;0;L;;;;;N;;;;; +124F8;CUNEIFORM SIGN LAK-457;Lo;0;L;;;;;N;;;;; +124F9;CUNEIFORM SIGN LAK-470;Lo;0;L;;;;;N;;;;; +124FA;CUNEIFORM SIGN LAK-483;Lo;0;L;;;;;N;;;;; +124FB;CUNEIFORM SIGN LAK-490;Lo;0;L;;;;;N;;;;; +124FC;CUNEIFORM SIGN LAK-492;Lo;0;L;;;;;N;;;;; +124FD;CUNEIFORM SIGN LAK-493;Lo;0;L;;;;;N;;;;; +124FE;CUNEIFORM SIGN LAK-495;Lo;0;L;;;;;N;;;;; +124FF;CUNEIFORM SIGN LAK-550;Lo;0;L;;;;;N;;;;; +12500;CUNEIFORM SIGN LAK-608;Lo;0;L;;;;;N;;;;; +12501;CUNEIFORM SIGN LAK-617;Lo;0;L;;;;;N;;;;; +12502;CUNEIFORM SIGN LAK-617 TIMES ASH;Lo;0;L;;;;;N;;;;; +12503;CUNEIFORM SIGN LAK-617 TIMES BAD;Lo;0;L;;;;;N;;;;; +12504;CUNEIFORM SIGN LAK-617 TIMES DUN3 GUNU GUNU;Lo;0;L;;;;;N;;;;; +12505;CUNEIFORM SIGN LAK-617 TIMES KU3;Lo;0;L;;;;;N;;;;; +12506;CUNEIFORM SIGN LAK-617 TIMES LA;Lo;0;L;;;;;N;;;;; +12507;CUNEIFORM SIGN LAK-617 TIMES TAR;Lo;0;L;;;;;N;;;;; +12508;CUNEIFORM SIGN LAK-617 TIMES TE;Lo;0;L;;;;;N;;;;; +12509;CUNEIFORM SIGN LAK-617 TIMES U2;Lo;0;L;;;;;N;;;;; +1250A;CUNEIFORM SIGN LAK-617 TIMES UD;Lo;0;L;;;;;N;;;;; +1250B;CUNEIFORM SIGN LAK-617 TIMES URUDA;Lo;0;L;;;;;N;;;;; +1250C;CUNEIFORM SIGN LAK-636;Lo;0;L;;;;;N;;;;; +1250D;CUNEIFORM SIGN LAK-648;Lo;0;L;;;;;N;;;;; +1250E;CUNEIFORM SIGN LAK-648 TIMES DUB;Lo;0;L;;;;;N;;;;; +1250F;CUNEIFORM SIGN LAK-648 TIMES GA;Lo;0;L;;;;;N;;;;; +12510;CUNEIFORM SIGN LAK-648 TIMES IGI;Lo;0;L;;;;;N;;;;; +12511;CUNEIFORM SIGN LAK-648 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +12512;CUNEIFORM SIGN LAK-648 TIMES NI;Lo;0;L;;;;;N;;;;; +12513;CUNEIFORM SIGN LAK-648 TIMES PAP PLUS PAP PLUS LU3;Lo;0;L;;;;;N;;;;; +12514;CUNEIFORM SIGN LAK-648 TIMES SHESH PLUS KI;Lo;0;L;;;;;N;;;;; +12515;CUNEIFORM SIGN LAK-648 TIMES UD;Lo;0;L;;;;;N;;;;; +12516;CUNEIFORM SIGN LAK-648 TIMES URUDA;Lo;0;L;;;;;N;;;;; +12517;CUNEIFORM SIGN LAK-724;Lo;0;L;;;;;N;;;;; +12518;CUNEIFORM SIGN LAK-749;Lo;0;L;;;;;N;;;;; +12519;CUNEIFORM SIGN LU2 GUNU TIMES ASH;Lo;0;L;;;;;N;;;;; +1251A;CUNEIFORM SIGN LU2 TIMES DISH;Lo;0;L;;;;;N;;;;; +1251B;CUNEIFORM SIGN LU2 TIMES HAL;Lo;0;L;;;;;N;;;;; +1251C;CUNEIFORM SIGN LU2 TIMES PAP;Lo;0;L;;;;;N;;;;; +1251D;CUNEIFORM SIGN LU2 TIMES PAP PLUS PAP PLUS LU3;Lo;0;L;;;;;N;;;;; +1251E;CUNEIFORM SIGN LU2 TIMES TAK4;Lo;0;L;;;;;N;;;;; +1251F;CUNEIFORM SIGN MI PLUS ZA7;Lo;0;L;;;;;N;;;;; +12520;CUNEIFORM SIGN MUSH OVER MUSH TIMES GA;Lo;0;L;;;;;N;;;;; +12521;CUNEIFORM SIGN MUSH OVER MUSH TIMES KAK;Lo;0;L;;;;;N;;;;; +12522;CUNEIFORM SIGN NINDA2 TIMES DIM GUNU;Lo;0;L;;;;;N;;;;; +12523;CUNEIFORM SIGN NINDA2 TIMES GISH;Lo;0;L;;;;;N;;;;; +12524;CUNEIFORM SIGN NINDA2 TIMES GUL;Lo;0;L;;;;;N;;;;; +12525;CUNEIFORM SIGN NINDA2 TIMES HI;Lo;0;L;;;;;N;;;;; +12526;CUNEIFORM SIGN NINDA2 TIMES KESH2;Lo;0;L;;;;;N;;;;; +12527;CUNEIFORM SIGN NINDA2 TIMES LAK-050;Lo;0;L;;;;;N;;;;; +12528;CUNEIFORM SIGN NINDA2 TIMES MASH;Lo;0;L;;;;;N;;;;; +12529;CUNEIFORM SIGN NINDA2 TIMES PAP PLUS PAP;Lo;0;L;;;;;N;;;;; +1252A;CUNEIFORM SIGN NINDA2 TIMES U;Lo;0;L;;;;;N;;;;; +1252B;CUNEIFORM SIGN NINDA2 TIMES U PLUS U;Lo;0;L;;;;;N;;;;; +1252C;CUNEIFORM SIGN NINDA2 TIMES URUDA;Lo;0;L;;;;;N;;;;; +1252D;CUNEIFORM SIGN SAG GUNU TIMES HA;Lo;0;L;;;;;N;;;;; +1252E;CUNEIFORM SIGN SAG TIMES EN;Lo;0;L;;;;;N;;;;; +1252F;CUNEIFORM SIGN SAG TIMES SHE AT LEFT;Lo;0;L;;;;;N;;;;; +12530;CUNEIFORM SIGN SAG TIMES TAK4;Lo;0;L;;;;;N;;;;; +12531;CUNEIFORM SIGN SHA6 TENU;Lo;0;L;;;;;N;;;;; +12532;CUNEIFORM SIGN SHE OVER SHE;Lo;0;L;;;;;N;;;;; +12533;CUNEIFORM SIGN SHE PLUS HUB2;Lo;0;L;;;;;N;;;;; +12534;CUNEIFORM SIGN SHE PLUS NAM2;Lo;0;L;;;;;N;;;;; +12535;CUNEIFORM SIGN SHE PLUS SAR;Lo;0;L;;;;;N;;;;; +12536;CUNEIFORM SIGN SHU2 PLUS DUG TIMES NI;Lo;0;L;;;;;N;;;;; +12537;CUNEIFORM SIGN SHU2 PLUS E2 TIMES AN;Lo;0;L;;;;;N;;;;; +12538;CUNEIFORM SIGN SI TIMES TAK4;Lo;0;L;;;;;N;;;;; +12539;CUNEIFORM SIGN TAK4 PLUS SAG;Lo;0;L;;;;;N;;;;; +1253A;CUNEIFORM SIGN TUM TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +1253B;CUNEIFORM SIGN TUM TIMES THREE DISH;Lo;0;L;;;;;N;;;;; +1253C;CUNEIFORM SIGN UR2 INVERTED;Lo;0;L;;;;;N;;;;; +1253D;CUNEIFORM SIGN UR2 TIMES UD;Lo;0;L;;;;;N;;;;; +1253E;CUNEIFORM SIGN URU TIMES DARA3;Lo;0;L;;;;;N;;;;; +1253F;CUNEIFORM SIGN URU TIMES LAK-668;Lo;0;L;;;;;N;;;;; +12540;CUNEIFORM SIGN URU TIMES LU3;Lo;0;L;;;;;N;;;;; +12541;CUNEIFORM SIGN ZA7;Lo;0;L;;;;;N;;;;; +12542;CUNEIFORM SIGN ZU OVER ZU PLUS SAR;Lo;0;L;;;;;N;;;;; +12543;CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU;Lo;0;L;;;;;N;;;;; +12F90;CYPRO-MINOAN SIGN CM001;Lo;0;L;;;;;N;;;;; +12F91;CYPRO-MINOAN SIGN CM002;Lo;0;L;;;;;N;;;;; +12F92;CYPRO-MINOAN SIGN CM004;Lo;0;L;;;;;N;;;;; +12F93;CYPRO-MINOAN SIGN CM005;Lo;0;L;;;;;N;;;;; +12F94;CYPRO-MINOAN SIGN CM006;Lo;0;L;;;;;N;;;;; +12F95;CYPRO-MINOAN SIGN CM007;Lo;0;L;;;;;N;;;;; +12F96;CYPRO-MINOAN SIGN CM008;Lo;0;L;;;;;N;;;;; +12F97;CYPRO-MINOAN SIGN CM009;Lo;0;L;;;;;N;;;;; +12F98;CYPRO-MINOAN SIGN CM010;Lo;0;L;;;;;N;;;;; +12F99;CYPRO-MINOAN SIGN CM011;Lo;0;L;;;;;N;;;;; +12F9A;CYPRO-MINOAN SIGN CM012;Lo;0;L;;;;;N;;;;; +12F9B;CYPRO-MINOAN SIGN CM012B;Lo;0;L;;;;;N;;;;; +12F9C;CYPRO-MINOAN SIGN CM013;Lo;0;L;;;;;N;;;;; +12F9D;CYPRO-MINOAN SIGN CM015;Lo;0;L;;;;;N;;;;; +12F9E;CYPRO-MINOAN SIGN CM017;Lo;0;L;;;;;N;;;;; +12F9F;CYPRO-MINOAN SIGN CM019;Lo;0;L;;;;;N;;;;; +12FA0;CYPRO-MINOAN SIGN CM021;Lo;0;L;;;;;N;;;;; +12FA1;CYPRO-MINOAN SIGN CM023;Lo;0;L;;;;;N;;;;; +12FA2;CYPRO-MINOAN SIGN CM024;Lo;0;L;;;;;N;;;;; +12FA3;CYPRO-MINOAN SIGN CM025;Lo;0;L;;;;;N;;;;; +12FA4;CYPRO-MINOAN SIGN CM026;Lo;0;L;;;;;N;;;;; +12FA5;CYPRO-MINOAN SIGN CM027;Lo;0;L;;;;;N;;;;; +12FA6;CYPRO-MINOAN SIGN CM028;Lo;0;L;;;;;N;;;;; +12FA7;CYPRO-MINOAN SIGN CM029;Lo;0;L;;;;;N;;;;; +12FA8;CYPRO-MINOAN SIGN CM030;Lo;0;L;;;;;N;;;;; +12FA9;CYPRO-MINOAN SIGN CM033;Lo;0;L;;;;;N;;;;; +12FAA;CYPRO-MINOAN SIGN CM034;Lo;0;L;;;;;N;;;;; +12FAB;CYPRO-MINOAN SIGN CM035;Lo;0;L;;;;;N;;;;; +12FAC;CYPRO-MINOAN SIGN CM036;Lo;0;L;;;;;N;;;;; +12FAD;CYPRO-MINOAN SIGN CM037;Lo;0;L;;;;;N;;;;; +12FAE;CYPRO-MINOAN SIGN CM038;Lo;0;L;;;;;N;;;;; +12FAF;CYPRO-MINOAN SIGN CM039;Lo;0;L;;;;;N;;;;; +12FB0;CYPRO-MINOAN SIGN CM040;Lo;0;L;;;;;N;;;;; +12FB1;CYPRO-MINOAN SIGN CM041;Lo;0;L;;;;;N;;;;; +12FB2;CYPRO-MINOAN SIGN CM044;Lo;0;L;;;;;N;;;;; +12FB3;CYPRO-MINOAN SIGN CM046;Lo;0;L;;;;;N;;;;; +12FB4;CYPRO-MINOAN SIGN CM047;Lo;0;L;;;;;N;;;;; +12FB5;CYPRO-MINOAN SIGN CM049;Lo;0;L;;;;;N;;;;; +12FB6;CYPRO-MINOAN SIGN CM050;Lo;0;L;;;;;N;;;;; +12FB7;CYPRO-MINOAN SIGN CM051;Lo;0;L;;;;;N;;;;; +12FB8;CYPRO-MINOAN SIGN CM052;Lo;0;L;;;;;N;;;;; +12FB9;CYPRO-MINOAN SIGN CM053;Lo;0;L;;;;;N;;;;; +12FBA;CYPRO-MINOAN SIGN CM054;Lo;0;L;;;;;N;;;;; +12FBB;CYPRO-MINOAN SIGN CM055;Lo;0;L;;;;;N;;;;; +12FBC;CYPRO-MINOAN SIGN CM056;Lo;0;L;;;;;N;;;;; +12FBD;CYPRO-MINOAN SIGN CM058;Lo;0;L;;;;;N;;;;; +12FBE;CYPRO-MINOAN SIGN CM059;Lo;0;L;;;;;N;;;;; +12FBF;CYPRO-MINOAN SIGN CM060;Lo;0;L;;;;;N;;;;; +12FC0;CYPRO-MINOAN SIGN CM061;Lo;0;L;;;;;N;;;;; +12FC1;CYPRO-MINOAN SIGN CM062;Lo;0;L;;;;;N;;;;; +12FC2;CYPRO-MINOAN SIGN CM063;Lo;0;L;;;;;N;;;;; +12FC3;CYPRO-MINOAN SIGN CM064;Lo;0;L;;;;;N;;;;; +12FC4;CYPRO-MINOAN SIGN CM066;Lo;0;L;;;;;N;;;;; +12FC5;CYPRO-MINOAN SIGN CM067;Lo;0;L;;;;;N;;;;; +12FC6;CYPRO-MINOAN SIGN CM068;Lo;0;L;;;;;N;;;;; +12FC7;CYPRO-MINOAN SIGN CM069;Lo;0;L;;;;;N;;;;; +12FC8;CYPRO-MINOAN SIGN CM070;Lo;0;L;;;;;N;;;;; +12FC9;CYPRO-MINOAN SIGN CM071;Lo;0;L;;;;;N;;;;; +12FCA;CYPRO-MINOAN SIGN CM072;Lo;0;L;;;;;N;;;;; +12FCB;CYPRO-MINOAN SIGN CM073;Lo;0;L;;;;;N;;;;; +12FCC;CYPRO-MINOAN SIGN CM074;Lo;0;L;;;;;N;;;;; +12FCD;CYPRO-MINOAN SIGN CM075;Lo;0;L;;;;;N;;;;; +12FCE;CYPRO-MINOAN SIGN CM075B;Lo;0;L;;;;;N;;;;; +12FCF;CYPRO-MINOAN SIGN CM076;Lo;0;L;;;;;N;;;;; +12FD0;CYPRO-MINOAN SIGN CM078;Lo;0;L;;;;;N;;;;; +12FD1;CYPRO-MINOAN SIGN CM079;Lo;0;L;;;;;N;;;;; +12FD2;CYPRO-MINOAN SIGN CM080;Lo;0;L;;;;;N;;;;; +12FD3;CYPRO-MINOAN SIGN CM081;Lo;0;L;;;;;N;;;;; +12FD4;CYPRO-MINOAN SIGN CM082;Lo;0;L;;;;;N;;;;; +12FD5;CYPRO-MINOAN SIGN CM083;Lo;0;L;;;;;N;;;;; +12FD6;CYPRO-MINOAN SIGN CM084;Lo;0;L;;;;;N;;;;; +12FD7;CYPRO-MINOAN SIGN CM085;Lo;0;L;;;;;N;;;;; +12FD8;CYPRO-MINOAN SIGN CM086;Lo;0;L;;;;;N;;;;; +12FD9;CYPRO-MINOAN SIGN CM087;Lo;0;L;;;;;N;;;;; +12FDA;CYPRO-MINOAN SIGN CM088;Lo;0;L;;;;;N;;;;; +12FDB;CYPRO-MINOAN SIGN CM089;Lo;0;L;;;;;N;;;;; +12FDC;CYPRO-MINOAN SIGN CM090;Lo;0;L;;;;;N;;;;; +12FDD;CYPRO-MINOAN SIGN CM091;Lo;0;L;;;;;N;;;;; +12FDE;CYPRO-MINOAN SIGN CM092;Lo;0;L;;;;;N;;;;; +12FDF;CYPRO-MINOAN SIGN CM094;Lo;0;L;;;;;N;;;;; +12FE0;CYPRO-MINOAN SIGN CM095;Lo;0;L;;;;;N;;;;; +12FE1;CYPRO-MINOAN SIGN CM096;Lo;0;L;;;;;N;;;;; +12FE2;CYPRO-MINOAN SIGN CM097;Lo;0;L;;;;;N;;;;; +12FE3;CYPRO-MINOAN SIGN CM098;Lo;0;L;;;;;N;;;;; +12FE4;CYPRO-MINOAN SIGN CM099;Lo;0;L;;;;;N;;;;; +12FE5;CYPRO-MINOAN SIGN CM100;Lo;0;L;;;;;N;;;;; +12FE6;CYPRO-MINOAN SIGN CM101;Lo;0;L;;;;;N;;;;; +12FE7;CYPRO-MINOAN SIGN CM102;Lo;0;L;;;;;N;;;;; +12FE8;CYPRO-MINOAN SIGN CM103;Lo;0;L;;;;;N;;;;; +12FE9;CYPRO-MINOAN SIGN CM104;Lo;0;L;;;;;N;;;;; +12FEA;CYPRO-MINOAN SIGN CM105;Lo;0;L;;;;;N;;;;; +12FEB;CYPRO-MINOAN SIGN CM107;Lo;0;L;;;;;N;;;;; +12FEC;CYPRO-MINOAN SIGN CM108;Lo;0;L;;;;;N;;;;; +12FED;CYPRO-MINOAN SIGN CM109;Lo;0;L;;;;;N;;;;; +12FEE;CYPRO-MINOAN SIGN CM110;Lo;0;L;;;;;N;;;;; +12FEF;CYPRO-MINOAN SIGN CM112;Lo;0;L;;;;;N;;;;; +12FF0;CYPRO-MINOAN SIGN CM114;Lo;0;L;;;;;N;;;;; +12FF1;CYPRO-MINOAN SIGN CM301;Po;0;L;;;;;N;;;;; +12FF2;CYPRO-MINOAN SIGN CM302;Po;0;L;;;;;N;;;;; +13000;EGYPTIAN HIEROGLYPH A001;Lo;0;L;;;;;N;;;;; +13001;EGYPTIAN HIEROGLYPH A002;Lo;0;L;;;;;N;;;;; +13002;EGYPTIAN HIEROGLYPH A003;Lo;0;L;;;;;N;;;;; +13003;EGYPTIAN HIEROGLYPH A004;Lo;0;L;;;;;N;;;;; +13004;EGYPTIAN HIEROGLYPH A005;Lo;0;L;;;;;N;;;;; +13005;EGYPTIAN HIEROGLYPH A005A;Lo;0;L;;;;;N;;;;; +13006;EGYPTIAN HIEROGLYPH A006;Lo;0;L;;;;;N;;;;; +13007;EGYPTIAN HIEROGLYPH A006A;Lo;0;L;;;;;N;;;;; +13008;EGYPTIAN HIEROGLYPH A006B;Lo;0;L;;;;;N;;;;; +13009;EGYPTIAN HIEROGLYPH A007;Lo;0;L;;;;;N;;;;; +1300A;EGYPTIAN HIEROGLYPH A008;Lo;0;L;;;;;N;;;;; +1300B;EGYPTIAN HIEROGLYPH A009;Lo;0;L;;;;;N;;;;; +1300C;EGYPTIAN HIEROGLYPH A010;Lo;0;L;;;;;N;;;;; +1300D;EGYPTIAN HIEROGLYPH A011;Lo;0;L;;;;;N;;;;; +1300E;EGYPTIAN HIEROGLYPH A012;Lo;0;L;;;;;N;;;;; +1300F;EGYPTIAN HIEROGLYPH A013;Lo;0;L;;;;;N;;;;; +13010;EGYPTIAN HIEROGLYPH A014;Lo;0;L;;;;;N;;;;; +13011;EGYPTIAN HIEROGLYPH A014A;Lo;0;L;;;;;N;;;;; +13012;EGYPTIAN HIEROGLYPH A015;Lo;0;L;;;;;N;;;;; +13013;EGYPTIAN HIEROGLYPH A016;Lo;0;L;;;;;N;;;;; +13014;EGYPTIAN HIEROGLYPH A017;Lo;0;L;;;;;N;;;;; +13015;EGYPTIAN HIEROGLYPH A017A;Lo;0;L;;;;;N;;;;; +13016;EGYPTIAN HIEROGLYPH A018;Lo;0;L;;;;;N;;;;; +13017;EGYPTIAN HIEROGLYPH A019;Lo;0;L;;;;;N;;;;; +13018;EGYPTIAN HIEROGLYPH A020;Lo;0;L;;;;;N;;;;; +13019;EGYPTIAN HIEROGLYPH A021;Lo;0;L;;;;;N;;;;; +1301A;EGYPTIAN HIEROGLYPH A022;Lo;0;L;;;;;N;;;;; +1301B;EGYPTIAN HIEROGLYPH A023;Lo;0;L;;;;;N;;;;; +1301C;EGYPTIAN HIEROGLYPH A024;Lo;0;L;;;;;N;;;;; +1301D;EGYPTIAN HIEROGLYPH A025;Lo;0;L;;;;;N;;;;; +1301E;EGYPTIAN HIEROGLYPH A026;Lo;0;L;;;;;N;;;;; +1301F;EGYPTIAN HIEROGLYPH A027;Lo;0;L;;;;;N;;;;; +13020;EGYPTIAN HIEROGLYPH A028;Lo;0;L;;;;;N;;;;; +13021;EGYPTIAN HIEROGLYPH A029;Lo;0;L;;;;;N;;;;; +13022;EGYPTIAN HIEROGLYPH A030;Lo;0;L;;;;;N;;;;; +13023;EGYPTIAN HIEROGLYPH A031;Lo;0;L;;;;;N;;;;; +13024;EGYPTIAN HIEROGLYPH A032;Lo;0;L;;;;;N;;;;; +13025;EGYPTIAN HIEROGLYPH A032A;Lo;0;L;;;;;N;;;;; +13026;EGYPTIAN HIEROGLYPH A033;Lo;0;L;;;;;N;;;;; +13027;EGYPTIAN HIEROGLYPH A034;Lo;0;L;;;;;N;;;;; +13028;EGYPTIAN HIEROGLYPH A035;Lo;0;L;;;;;N;;;;; +13029;EGYPTIAN HIEROGLYPH A036;Lo;0;L;;;;;N;;;;; +1302A;EGYPTIAN HIEROGLYPH A037;Lo;0;L;;;;;N;;;;; +1302B;EGYPTIAN HIEROGLYPH A038;Lo;0;L;;;;;N;;;;; +1302C;EGYPTIAN HIEROGLYPH A039;Lo;0;L;;;;;N;;;;; +1302D;EGYPTIAN HIEROGLYPH A040;Lo;0;L;;;;;N;;;;; +1302E;EGYPTIAN HIEROGLYPH A040A;Lo;0;L;;;;;N;;;;; +1302F;EGYPTIAN HIEROGLYPH A041;Lo;0;L;;;;;N;;;;; +13030;EGYPTIAN HIEROGLYPH A042;Lo;0;L;;;;;N;;;;; +13031;EGYPTIAN HIEROGLYPH A042A;Lo;0;L;;;;;N;;;;; +13032;EGYPTIAN HIEROGLYPH A043;Lo;0;L;;;;;N;;;;; +13033;EGYPTIAN HIEROGLYPH A043A;Lo;0;L;;;;;N;;;;; +13034;EGYPTIAN HIEROGLYPH A044;Lo;0;L;;;;;N;;;;; +13035;EGYPTIAN HIEROGLYPH A045;Lo;0;L;;;;;N;;;;; +13036;EGYPTIAN HIEROGLYPH A045A;Lo;0;L;;;;;N;;;;; +13037;EGYPTIAN HIEROGLYPH A046;Lo;0;L;;;;;N;;;;; +13038;EGYPTIAN HIEROGLYPH A047;Lo;0;L;;;;;N;;;;; +13039;EGYPTIAN HIEROGLYPH A048;Lo;0;L;;;;;N;;;;; +1303A;EGYPTIAN HIEROGLYPH A049;Lo;0;L;;;;;N;;;;; +1303B;EGYPTIAN HIEROGLYPH A050;Lo;0;L;;;;;N;;;;; +1303C;EGYPTIAN HIEROGLYPH A051;Lo;0;L;;;;;N;;;;; +1303D;EGYPTIAN HIEROGLYPH A052;Lo;0;L;;;;;N;;;;; +1303E;EGYPTIAN HIEROGLYPH A053;Lo;0;L;;;;;N;;;;; +1303F;EGYPTIAN HIEROGLYPH A054;Lo;0;L;;;;;N;;;;; +13040;EGYPTIAN HIEROGLYPH A055;Lo;0;L;;;;;N;;;;; +13041;EGYPTIAN HIEROGLYPH A056;Lo;0;L;;;;;N;;;;; +13042;EGYPTIAN HIEROGLYPH A057;Lo;0;L;;;;;N;;;;; +13043;EGYPTIAN HIEROGLYPH A058;Lo;0;L;;;;;N;;;;; +13044;EGYPTIAN HIEROGLYPH A059;Lo;0;L;;;;;N;;;;; +13045;EGYPTIAN HIEROGLYPH A060;Lo;0;L;;;;;N;;;;; +13046;EGYPTIAN HIEROGLYPH A061;Lo;0;L;;;;;N;;;;; +13047;EGYPTIAN HIEROGLYPH A062;Lo;0;L;;;;;N;;;;; +13048;EGYPTIAN HIEROGLYPH A063;Lo;0;L;;;;;N;;;;; +13049;EGYPTIAN HIEROGLYPH A064;Lo;0;L;;;;;N;;;;; +1304A;EGYPTIAN HIEROGLYPH A065;Lo;0;L;;;;;N;;;;; +1304B;EGYPTIAN HIEROGLYPH A066;Lo;0;L;;;;;N;;;;; +1304C;EGYPTIAN HIEROGLYPH A067;Lo;0;L;;;;;N;;;;; +1304D;EGYPTIAN HIEROGLYPH A068;Lo;0;L;;;;;N;;;;; +1304E;EGYPTIAN HIEROGLYPH A069;Lo;0;L;;;;;N;;;;; +1304F;EGYPTIAN HIEROGLYPH A070;Lo;0;L;;;;;N;;;;; +13050;EGYPTIAN HIEROGLYPH B001;Lo;0;L;;;;;N;;;;; +13051;EGYPTIAN HIEROGLYPH B002;Lo;0;L;;;;;N;;;;; +13052;EGYPTIAN HIEROGLYPH B003;Lo;0;L;;;;;N;;;;; +13053;EGYPTIAN HIEROGLYPH B004;Lo;0;L;;;;;N;;;;; +13054;EGYPTIAN HIEROGLYPH B005;Lo;0;L;;;;;N;;;;; +13055;EGYPTIAN HIEROGLYPH B005A;Lo;0;L;;;;;N;;;;; +13056;EGYPTIAN HIEROGLYPH B006;Lo;0;L;;;;;N;;;;; +13057;EGYPTIAN HIEROGLYPH B007;Lo;0;L;;;;;N;;;;; +13058;EGYPTIAN HIEROGLYPH B008;Lo;0;L;;;;;N;;;;; +13059;EGYPTIAN HIEROGLYPH B009;Lo;0;L;;;;;N;;;;; +1305A;EGYPTIAN HIEROGLYPH C001;Lo;0;L;;;;;N;;;;; +1305B;EGYPTIAN HIEROGLYPH C002;Lo;0;L;;;;;N;;;;; +1305C;EGYPTIAN HIEROGLYPH C002A;Lo;0;L;;;;;N;;;;; +1305D;EGYPTIAN HIEROGLYPH C002B;Lo;0;L;;;;;N;;;;; +1305E;EGYPTIAN HIEROGLYPH C002C;Lo;0;L;;;;;N;;;;; +1305F;EGYPTIAN HIEROGLYPH C003;Lo;0;L;;;;;N;;;;; +13060;EGYPTIAN HIEROGLYPH C004;Lo;0;L;;;;;N;;;;; +13061;EGYPTIAN HIEROGLYPH C005;Lo;0;L;;;;;N;;;;; +13062;EGYPTIAN HIEROGLYPH C006;Lo;0;L;;;;;N;;;;; +13063;EGYPTIAN HIEROGLYPH C007;Lo;0;L;;;;;N;;;;; +13064;EGYPTIAN HIEROGLYPH C008;Lo;0;L;;;;;N;;;;; +13065;EGYPTIAN HIEROGLYPH C009;Lo;0;L;;;;;N;;;;; +13066;EGYPTIAN HIEROGLYPH C010;Lo;0;L;;;;;N;;;;; +13067;EGYPTIAN HIEROGLYPH C010A;Lo;0;L;;;;;N;;;;; +13068;EGYPTIAN HIEROGLYPH C011;Lo;0;L;;;;;N;;;;; +13069;EGYPTIAN HIEROGLYPH C012;Lo;0;L;;;;;N;;;;; +1306A;EGYPTIAN HIEROGLYPH C013;Lo;0;L;;;;;N;;;;; +1306B;EGYPTIAN HIEROGLYPH C014;Lo;0;L;;;;;N;;;;; +1306C;EGYPTIAN HIEROGLYPH C015;Lo;0;L;;;;;N;;;;; +1306D;EGYPTIAN HIEROGLYPH C016;Lo;0;L;;;;;N;;;;; +1306E;EGYPTIAN HIEROGLYPH C017;Lo;0;L;;;;;N;;;;; +1306F;EGYPTIAN HIEROGLYPH C018;Lo;0;L;;;;;N;;;;; +13070;EGYPTIAN HIEROGLYPH C019;Lo;0;L;;;;;N;;;;; +13071;EGYPTIAN HIEROGLYPH C020;Lo;0;L;;;;;N;;;;; +13072;EGYPTIAN HIEROGLYPH C021;Lo;0;L;;;;;N;;;;; +13073;EGYPTIAN HIEROGLYPH C022;Lo;0;L;;;;;N;;;;; +13074;EGYPTIAN HIEROGLYPH C023;Lo;0;L;;;;;N;;;;; +13075;EGYPTIAN HIEROGLYPH C024;Lo;0;L;;;;;N;;;;; +13076;EGYPTIAN HIEROGLYPH D001;Lo;0;L;;;;;N;;;;; +13077;EGYPTIAN HIEROGLYPH D002;Lo;0;L;;;;;N;;;;; +13078;EGYPTIAN HIEROGLYPH D003;Lo;0;L;;;;;N;;;;; +13079;EGYPTIAN HIEROGLYPH D004;Lo;0;L;;;;;N;;;;; +1307A;EGYPTIAN HIEROGLYPH D005;Lo;0;L;;;;;N;;;;; +1307B;EGYPTIAN HIEROGLYPH D006;Lo;0;L;;;;;N;;;;; +1307C;EGYPTIAN HIEROGLYPH D007;Lo;0;L;;;;;N;;;;; +1307D;EGYPTIAN HIEROGLYPH D008;Lo;0;L;;;;;N;;;;; +1307E;EGYPTIAN HIEROGLYPH D008A;Lo;0;L;;;;;N;;;;; +1307F;EGYPTIAN HIEROGLYPH D009;Lo;0;L;;;;;N;;;;; +13080;EGYPTIAN HIEROGLYPH D010;Lo;0;L;;;;;N;;;;; +13081;EGYPTIAN HIEROGLYPH D011;Lo;0;L;;;;;N;;;;; +13082;EGYPTIAN HIEROGLYPH D012;Lo;0;L;;;;;N;;;;; +13083;EGYPTIAN HIEROGLYPH D013;Lo;0;L;;;;;N;;;;; +13084;EGYPTIAN HIEROGLYPH D014;Lo;0;L;;;;;N;;;;; +13085;EGYPTIAN HIEROGLYPH D015;Lo;0;L;;;;;N;;;;; +13086;EGYPTIAN HIEROGLYPH D016;Lo;0;L;;;;;N;;;;; +13087;EGYPTIAN HIEROGLYPH D017;Lo;0;L;;;;;N;;;;; +13088;EGYPTIAN HIEROGLYPH D018;Lo;0;L;;;;;N;;;;; +13089;EGYPTIAN HIEROGLYPH D019;Lo;0;L;;;;;N;;;;; +1308A;EGYPTIAN HIEROGLYPH D020;Lo;0;L;;;;;N;;;;; +1308B;EGYPTIAN HIEROGLYPH D021;Lo;0;L;;;;;N;;;;; +1308C;EGYPTIAN HIEROGLYPH D022;Lo;0;L;;;;;N;;;;; +1308D;EGYPTIAN HIEROGLYPH D023;Lo;0;L;;;;;N;;;;; +1308E;EGYPTIAN HIEROGLYPH D024;Lo;0;L;;;;;N;;;;; +1308F;EGYPTIAN HIEROGLYPH D025;Lo;0;L;;;;;N;;;;; +13090;EGYPTIAN HIEROGLYPH D026;Lo;0;L;;;;;N;;;;; +13091;EGYPTIAN HIEROGLYPH D027;Lo;0;L;;;;;N;;;;; +13092;EGYPTIAN HIEROGLYPH D027A;Lo;0;L;;;;;N;;;;; +13093;EGYPTIAN HIEROGLYPH D028;Lo;0;L;;;;;N;;;;; +13094;EGYPTIAN HIEROGLYPH D029;Lo;0;L;;;;;N;;;;; +13095;EGYPTIAN HIEROGLYPH D030;Lo;0;L;;;;;N;;;;; +13096;EGYPTIAN HIEROGLYPH D031;Lo;0;L;;;;;N;;;;; +13097;EGYPTIAN HIEROGLYPH D031A;Lo;0;L;;;;;N;;;;; +13098;EGYPTIAN HIEROGLYPH D032;Lo;0;L;;;;;N;;;;; +13099;EGYPTIAN HIEROGLYPH D033;Lo;0;L;;;;;N;;;;; +1309A;EGYPTIAN HIEROGLYPH D034;Lo;0;L;;;;;N;;;;; +1309B;EGYPTIAN HIEROGLYPH D034A;Lo;0;L;;;;;N;;;;; +1309C;EGYPTIAN HIEROGLYPH D035;Lo;0;L;;;;;N;;;;; +1309D;EGYPTIAN HIEROGLYPH D036;Lo;0;L;;;;;N;;;;; +1309E;EGYPTIAN HIEROGLYPH D037;Lo;0;L;;;;;N;;;;; +1309F;EGYPTIAN HIEROGLYPH D038;Lo;0;L;;;;;N;;;;; +130A0;EGYPTIAN HIEROGLYPH D039;Lo;0;L;;;;;N;;;;; +130A1;EGYPTIAN HIEROGLYPH D040;Lo;0;L;;;;;N;;;;; +130A2;EGYPTIAN HIEROGLYPH D041;Lo;0;L;;;;;N;;;;; +130A3;EGYPTIAN HIEROGLYPH D042;Lo;0;L;;;;;N;;;;; +130A4;EGYPTIAN HIEROGLYPH D043;Lo;0;L;;;;;N;;;;; +130A5;EGYPTIAN HIEROGLYPH D044;Lo;0;L;;;;;N;;;;; +130A6;EGYPTIAN HIEROGLYPH D045;Lo;0;L;;;;;N;;;;; +130A7;EGYPTIAN HIEROGLYPH D046;Lo;0;L;;;;;N;;;;; +130A8;EGYPTIAN HIEROGLYPH D046A;Lo;0;L;;;;;N;;;;; +130A9;EGYPTIAN HIEROGLYPH D047;Lo;0;L;;;;;N;;;;; +130AA;EGYPTIAN HIEROGLYPH D048;Lo;0;L;;;;;N;;;;; +130AB;EGYPTIAN HIEROGLYPH D048A;Lo;0;L;;;;;N;;;;; +130AC;EGYPTIAN HIEROGLYPH D049;Lo;0;L;;;;;N;;;;; +130AD;EGYPTIAN HIEROGLYPH D050;Lo;0;L;;;;;N;;;;; +130AE;EGYPTIAN HIEROGLYPH D050A;Lo;0;L;;;;;N;;;;; +130AF;EGYPTIAN HIEROGLYPH D050B;Lo;0;L;;;;;N;;;;; +130B0;EGYPTIAN HIEROGLYPH D050C;Lo;0;L;;;;;N;;;;; +130B1;EGYPTIAN HIEROGLYPH D050D;Lo;0;L;;;;;N;;;;; +130B2;EGYPTIAN HIEROGLYPH D050E;Lo;0;L;;;;;N;;;;; +130B3;EGYPTIAN HIEROGLYPH D050F;Lo;0;L;;;;;N;;;;; +130B4;EGYPTIAN HIEROGLYPH D050G;Lo;0;L;;;;;N;;;;; +130B5;EGYPTIAN HIEROGLYPH D050H;Lo;0;L;;;;;N;;;;; +130B6;EGYPTIAN HIEROGLYPH D050I;Lo;0;L;;;;;N;;;;; +130B7;EGYPTIAN HIEROGLYPH D051;Lo;0;L;;;;;N;;;;; +130B8;EGYPTIAN HIEROGLYPH D052;Lo;0;L;;;;;N;;;;; +130B9;EGYPTIAN HIEROGLYPH D052A;Lo;0;L;;;;;N;;;;; +130BA;EGYPTIAN HIEROGLYPH D053;Lo;0;L;;;;;N;;;;; +130BB;EGYPTIAN HIEROGLYPH D054;Lo;0;L;;;;;N;;;;; +130BC;EGYPTIAN HIEROGLYPH D054A;Lo;0;L;;;;;N;;;;; +130BD;EGYPTIAN HIEROGLYPH D055;Lo;0;L;;;;;N;;;;; +130BE;EGYPTIAN HIEROGLYPH D056;Lo;0;L;;;;;N;;;;; +130BF;EGYPTIAN HIEROGLYPH D057;Lo;0;L;;;;;N;;;;; +130C0;EGYPTIAN HIEROGLYPH D058;Lo;0;L;;;;;N;;;;; +130C1;EGYPTIAN HIEROGLYPH D059;Lo;0;L;;;;;N;;;;; +130C2;EGYPTIAN HIEROGLYPH D060;Lo;0;L;;;;;N;;;;; +130C3;EGYPTIAN HIEROGLYPH D061;Lo;0;L;;;;;N;;;;; +130C4;EGYPTIAN HIEROGLYPH D062;Lo;0;L;;;;;N;;;;; +130C5;EGYPTIAN HIEROGLYPH D063;Lo;0;L;;;;;N;;;;; +130C6;EGYPTIAN HIEROGLYPH D064;Lo;0;L;;;;;N;;;;; +130C7;EGYPTIAN HIEROGLYPH D065;Lo;0;L;;;;;N;;;;; +130C8;EGYPTIAN HIEROGLYPH D066;Lo;0;L;;;;;N;;;;; +130C9;EGYPTIAN HIEROGLYPH D067;Lo;0;L;;;;;N;;;;; +130CA;EGYPTIAN HIEROGLYPH D067A;Lo;0;L;;;;;N;;;;; +130CB;EGYPTIAN HIEROGLYPH D067B;Lo;0;L;;;;;N;;;;; +130CC;EGYPTIAN HIEROGLYPH D067C;Lo;0;L;;;;;N;;;;; +130CD;EGYPTIAN HIEROGLYPH D067D;Lo;0;L;;;;;N;;;;; +130CE;EGYPTIAN HIEROGLYPH D067E;Lo;0;L;;;;;N;;;;; +130CF;EGYPTIAN HIEROGLYPH D067F;Lo;0;L;;;;;N;;;;; +130D0;EGYPTIAN HIEROGLYPH D067G;Lo;0;L;;;;;N;;;;; +130D1;EGYPTIAN HIEROGLYPH D067H;Lo;0;L;;;;;N;;;;; +130D2;EGYPTIAN HIEROGLYPH E001;Lo;0;L;;;;;N;;;;; +130D3;EGYPTIAN HIEROGLYPH E002;Lo;0;L;;;;;N;;;;; +130D4;EGYPTIAN HIEROGLYPH E003;Lo;0;L;;;;;N;;;;; +130D5;EGYPTIAN HIEROGLYPH E004;Lo;0;L;;;;;N;;;;; +130D6;EGYPTIAN HIEROGLYPH E005;Lo;0;L;;;;;N;;;;; +130D7;EGYPTIAN HIEROGLYPH E006;Lo;0;L;;;;;N;;;;; +130D8;EGYPTIAN HIEROGLYPH E007;Lo;0;L;;;;;N;;;;; +130D9;EGYPTIAN HIEROGLYPH E008;Lo;0;L;;;;;N;;;;; +130DA;EGYPTIAN HIEROGLYPH E008A;Lo;0;L;;;;;N;;;;; +130DB;EGYPTIAN HIEROGLYPH E009;Lo;0;L;;;;;N;;;;; +130DC;EGYPTIAN HIEROGLYPH E009A;Lo;0;L;;;;;N;;;;; +130DD;EGYPTIAN HIEROGLYPH E010;Lo;0;L;;;;;N;;;;; +130DE;EGYPTIAN HIEROGLYPH E011;Lo;0;L;;;;;N;;;;; +130DF;EGYPTIAN HIEROGLYPH E012;Lo;0;L;;;;;N;;;;; +130E0;EGYPTIAN HIEROGLYPH E013;Lo;0;L;;;;;N;;;;; +130E1;EGYPTIAN HIEROGLYPH E014;Lo;0;L;;;;;N;;;;; +130E2;EGYPTIAN HIEROGLYPH E015;Lo;0;L;;;;;N;;;;; +130E3;EGYPTIAN HIEROGLYPH E016;Lo;0;L;;;;;N;;;;; +130E4;EGYPTIAN HIEROGLYPH E016A;Lo;0;L;;;;;N;;;;; +130E5;EGYPTIAN HIEROGLYPH E017;Lo;0;L;;;;;N;;;;; +130E6;EGYPTIAN HIEROGLYPH E017A;Lo;0;L;;;;;N;;;;; +130E7;EGYPTIAN HIEROGLYPH E018;Lo;0;L;;;;;N;;;;; +130E8;EGYPTIAN HIEROGLYPH E019;Lo;0;L;;;;;N;;;;; +130E9;EGYPTIAN HIEROGLYPH E020;Lo;0;L;;;;;N;;;;; +130EA;EGYPTIAN HIEROGLYPH E020A;Lo;0;L;;;;;N;;;;; +130EB;EGYPTIAN HIEROGLYPH E021;Lo;0;L;;;;;N;;;;; +130EC;EGYPTIAN HIEROGLYPH E022;Lo;0;L;;;;;N;;;;; +130ED;EGYPTIAN HIEROGLYPH E023;Lo;0;L;;;;;N;;;;; +130EE;EGYPTIAN HIEROGLYPH E024;Lo;0;L;;;;;N;;;;; +130EF;EGYPTIAN HIEROGLYPH E025;Lo;0;L;;;;;N;;;;; +130F0;EGYPTIAN HIEROGLYPH E026;Lo;0;L;;;;;N;;;;; +130F1;EGYPTIAN HIEROGLYPH E027;Lo;0;L;;;;;N;;;;; +130F2;EGYPTIAN HIEROGLYPH E028;Lo;0;L;;;;;N;;;;; +130F3;EGYPTIAN HIEROGLYPH E028A;Lo;0;L;;;;;N;;;;; +130F4;EGYPTIAN HIEROGLYPH E029;Lo;0;L;;;;;N;;;;; +130F5;EGYPTIAN HIEROGLYPH E030;Lo;0;L;;;;;N;;;;; +130F6;EGYPTIAN HIEROGLYPH E031;Lo;0;L;;;;;N;;;;; +130F7;EGYPTIAN HIEROGLYPH E032;Lo;0;L;;;;;N;;;;; +130F8;EGYPTIAN HIEROGLYPH E033;Lo;0;L;;;;;N;;;;; +130F9;EGYPTIAN HIEROGLYPH E034;Lo;0;L;;;;;N;;;;; +130FA;EGYPTIAN HIEROGLYPH E034A;Lo;0;L;;;;;N;;;;; +130FB;EGYPTIAN HIEROGLYPH E036;Lo;0;L;;;;;N;;;;; +130FC;EGYPTIAN HIEROGLYPH E037;Lo;0;L;;;;;N;;;;; +130FD;EGYPTIAN HIEROGLYPH E038;Lo;0;L;;;;;N;;;;; +130FE;EGYPTIAN HIEROGLYPH F001;Lo;0;L;;;;;N;;;;; +130FF;EGYPTIAN HIEROGLYPH F001A;Lo;0;L;;;;;N;;;;; +13100;EGYPTIAN HIEROGLYPH F002;Lo;0;L;;;;;N;;;;; +13101;EGYPTIAN HIEROGLYPH F003;Lo;0;L;;;;;N;;;;; +13102;EGYPTIAN HIEROGLYPH F004;Lo;0;L;;;;;N;;;;; +13103;EGYPTIAN HIEROGLYPH F005;Lo;0;L;;;;;N;;;;; +13104;EGYPTIAN HIEROGLYPH F006;Lo;0;L;;;;;N;;;;; +13105;EGYPTIAN HIEROGLYPH F007;Lo;0;L;;;;;N;;;;; +13106;EGYPTIAN HIEROGLYPH F008;Lo;0;L;;;;;N;;;;; +13107;EGYPTIAN HIEROGLYPH F009;Lo;0;L;;;;;N;;;;; +13108;EGYPTIAN HIEROGLYPH F010;Lo;0;L;;;;;N;;;;; +13109;EGYPTIAN HIEROGLYPH F011;Lo;0;L;;;;;N;;;;; +1310A;EGYPTIAN HIEROGLYPH F012;Lo;0;L;;;;;N;;;;; +1310B;EGYPTIAN HIEROGLYPH F013;Lo;0;L;;;;;N;;;;; +1310C;EGYPTIAN HIEROGLYPH F013A;Lo;0;L;;;;;N;;;;; +1310D;EGYPTIAN HIEROGLYPH F014;Lo;0;L;;;;;N;;;;; +1310E;EGYPTIAN HIEROGLYPH F015;Lo;0;L;;;;;N;;;;; +1310F;EGYPTIAN HIEROGLYPH F016;Lo;0;L;;;;;N;;;;; +13110;EGYPTIAN HIEROGLYPH F017;Lo;0;L;;;;;N;;;;; +13111;EGYPTIAN HIEROGLYPH F018;Lo;0;L;;;;;N;;;;; +13112;EGYPTIAN HIEROGLYPH F019;Lo;0;L;;;;;N;;;;; +13113;EGYPTIAN HIEROGLYPH F020;Lo;0;L;;;;;N;;;;; +13114;EGYPTIAN HIEROGLYPH F021;Lo;0;L;;;;;N;;;;; +13115;EGYPTIAN HIEROGLYPH F021A;Lo;0;L;;;;;N;;;;; +13116;EGYPTIAN HIEROGLYPH F022;Lo;0;L;;;;;N;;;;; +13117;EGYPTIAN HIEROGLYPH F023;Lo;0;L;;;;;N;;;;; +13118;EGYPTIAN HIEROGLYPH F024;Lo;0;L;;;;;N;;;;; +13119;EGYPTIAN HIEROGLYPH F025;Lo;0;L;;;;;N;;;;; +1311A;EGYPTIAN HIEROGLYPH F026;Lo;0;L;;;;;N;;;;; +1311B;EGYPTIAN HIEROGLYPH F027;Lo;0;L;;;;;N;;;;; +1311C;EGYPTIAN HIEROGLYPH F028;Lo;0;L;;;;;N;;;;; +1311D;EGYPTIAN HIEROGLYPH F029;Lo;0;L;;;;;N;;;;; +1311E;EGYPTIAN HIEROGLYPH F030;Lo;0;L;;;;;N;;;;; +1311F;EGYPTIAN HIEROGLYPH F031;Lo;0;L;;;;;N;;;;; +13120;EGYPTIAN HIEROGLYPH F031A;Lo;0;L;;;;;N;;;;; +13121;EGYPTIAN HIEROGLYPH F032;Lo;0;L;;;;;N;;;;; +13122;EGYPTIAN HIEROGLYPH F033;Lo;0;L;;;;;N;;;;; +13123;EGYPTIAN HIEROGLYPH F034;Lo;0;L;;;;;N;;;;; +13124;EGYPTIAN HIEROGLYPH F035;Lo;0;L;;;;;N;;;;; +13125;EGYPTIAN HIEROGLYPH F036;Lo;0;L;;;;;N;;;;; +13126;EGYPTIAN HIEROGLYPH F037;Lo;0;L;;;;;N;;;;; +13127;EGYPTIAN HIEROGLYPH F037A;Lo;0;L;;;;;N;;;;; +13128;EGYPTIAN HIEROGLYPH F038;Lo;0;L;;;;;N;;;;; +13129;EGYPTIAN HIEROGLYPH F038A;Lo;0;L;;;;;N;;;;; +1312A;EGYPTIAN HIEROGLYPH F039;Lo;0;L;;;;;N;;;;; +1312B;EGYPTIAN HIEROGLYPH F040;Lo;0;L;;;;;N;;;;; +1312C;EGYPTIAN HIEROGLYPH F041;Lo;0;L;;;;;N;;;;; +1312D;EGYPTIAN HIEROGLYPH F042;Lo;0;L;;;;;N;;;;; +1312E;EGYPTIAN HIEROGLYPH F043;Lo;0;L;;;;;N;;;;; +1312F;EGYPTIAN HIEROGLYPH F044;Lo;0;L;;;;;N;;;;; +13130;EGYPTIAN HIEROGLYPH F045;Lo;0;L;;;;;N;;;;; +13131;EGYPTIAN HIEROGLYPH F045A;Lo;0;L;;;;;N;;;;; +13132;EGYPTIAN HIEROGLYPH F046;Lo;0;L;;;;;N;;;;; +13133;EGYPTIAN HIEROGLYPH F046A;Lo;0;L;;;;;N;;;;; +13134;EGYPTIAN HIEROGLYPH F047;Lo;0;L;;;;;N;;;;; +13135;EGYPTIAN HIEROGLYPH F047A;Lo;0;L;;;;;N;;;;; +13136;EGYPTIAN HIEROGLYPH F048;Lo;0;L;;;;;N;;;;; +13137;EGYPTIAN HIEROGLYPH F049;Lo;0;L;;;;;N;;;;; +13138;EGYPTIAN HIEROGLYPH F050;Lo;0;L;;;;;N;;;;; +13139;EGYPTIAN HIEROGLYPH F051;Lo;0;L;;;;;N;;;;; +1313A;EGYPTIAN HIEROGLYPH F051A;Lo;0;L;;;;;N;;;;; +1313B;EGYPTIAN HIEROGLYPH F051B;Lo;0;L;;;;;N;;;;; +1313C;EGYPTIAN HIEROGLYPH F051C;Lo;0;L;;;;;N;;;;; +1313D;EGYPTIAN HIEROGLYPH F052;Lo;0;L;;;;;N;;;;; +1313E;EGYPTIAN HIEROGLYPH F053;Lo;0;L;;;;;N;;;;; +1313F;EGYPTIAN HIEROGLYPH G001;Lo;0;L;;;;;N;;;;; +13140;EGYPTIAN HIEROGLYPH G002;Lo;0;L;;;;;N;;;;; +13141;EGYPTIAN HIEROGLYPH G003;Lo;0;L;;;;;N;;;;; +13142;EGYPTIAN HIEROGLYPH G004;Lo;0;L;;;;;N;;;;; +13143;EGYPTIAN HIEROGLYPH G005;Lo;0;L;;;;;N;;;;; +13144;EGYPTIAN HIEROGLYPH G006;Lo;0;L;;;;;N;;;;; +13145;EGYPTIAN HIEROGLYPH G006A;Lo;0;L;;;;;N;;;;; +13146;EGYPTIAN HIEROGLYPH G007;Lo;0;L;;;;;N;;;;; +13147;EGYPTIAN HIEROGLYPH G007A;Lo;0;L;;;;;N;;;;; +13148;EGYPTIAN HIEROGLYPH G007B;Lo;0;L;;;;;N;;;;; +13149;EGYPTIAN HIEROGLYPH G008;Lo;0;L;;;;;N;;;;; +1314A;EGYPTIAN HIEROGLYPH G009;Lo;0;L;;;;;N;;;;; +1314B;EGYPTIAN HIEROGLYPH G010;Lo;0;L;;;;;N;;;;; +1314C;EGYPTIAN HIEROGLYPH G011;Lo;0;L;;;;;N;;;;; +1314D;EGYPTIAN HIEROGLYPH G011A;Lo;0;L;;;;;N;;;;; +1314E;EGYPTIAN HIEROGLYPH G012;Lo;0;L;;;;;N;;;;; +1314F;EGYPTIAN HIEROGLYPH G013;Lo;0;L;;;;;N;;;;; +13150;EGYPTIAN HIEROGLYPH G014;Lo;0;L;;;;;N;;;;; +13151;EGYPTIAN HIEROGLYPH G015;Lo;0;L;;;;;N;;;;; +13152;EGYPTIAN HIEROGLYPH G016;Lo;0;L;;;;;N;;;;; +13153;EGYPTIAN HIEROGLYPH G017;Lo;0;L;;;;;N;;;;; +13154;EGYPTIAN HIEROGLYPH G018;Lo;0;L;;;;;N;;;;; +13155;EGYPTIAN HIEROGLYPH G019;Lo;0;L;;;;;N;;;;; +13156;EGYPTIAN HIEROGLYPH G020;Lo;0;L;;;;;N;;;;; +13157;EGYPTIAN HIEROGLYPH G020A;Lo;0;L;;;;;N;;;;; +13158;EGYPTIAN HIEROGLYPH G021;Lo;0;L;;;;;N;;;;; +13159;EGYPTIAN HIEROGLYPH G022;Lo;0;L;;;;;N;;;;; +1315A;EGYPTIAN HIEROGLYPH G023;Lo;0;L;;;;;N;;;;; +1315B;EGYPTIAN HIEROGLYPH G024;Lo;0;L;;;;;N;;;;; +1315C;EGYPTIAN HIEROGLYPH G025;Lo;0;L;;;;;N;;;;; +1315D;EGYPTIAN HIEROGLYPH G026;Lo;0;L;;;;;N;;;;; +1315E;EGYPTIAN HIEROGLYPH G026A;Lo;0;L;;;;;N;;;;; +1315F;EGYPTIAN HIEROGLYPH G027;Lo;0;L;;;;;N;;;;; +13160;EGYPTIAN HIEROGLYPH G028;Lo;0;L;;;;;N;;;;; +13161;EGYPTIAN HIEROGLYPH G029;Lo;0;L;;;;;N;;;;; +13162;EGYPTIAN HIEROGLYPH G030;Lo;0;L;;;;;N;;;;; +13163;EGYPTIAN HIEROGLYPH G031;Lo;0;L;;;;;N;;;;; +13164;EGYPTIAN HIEROGLYPH G032;Lo;0;L;;;;;N;;;;; +13165;EGYPTIAN HIEROGLYPH G033;Lo;0;L;;;;;N;;;;; +13166;EGYPTIAN HIEROGLYPH G034;Lo;0;L;;;;;N;;;;; +13167;EGYPTIAN HIEROGLYPH G035;Lo;0;L;;;;;N;;;;; +13168;EGYPTIAN HIEROGLYPH G036;Lo;0;L;;;;;N;;;;; +13169;EGYPTIAN HIEROGLYPH G036A;Lo;0;L;;;;;N;;;;; +1316A;EGYPTIAN HIEROGLYPH G037;Lo;0;L;;;;;N;;;;; +1316B;EGYPTIAN HIEROGLYPH G037A;Lo;0;L;;;;;N;;;;; +1316C;EGYPTIAN HIEROGLYPH G038;Lo;0;L;;;;;N;;;;; +1316D;EGYPTIAN HIEROGLYPH G039;Lo;0;L;;;;;N;;;;; +1316E;EGYPTIAN HIEROGLYPH G040;Lo;0;L;;;;;N;;;;; +1316F;EGYPTIAN HIEROGLYPH G041;Lo;0;L;;;;;N;;;;; +13170;EGYPTIAN HIEROGLYPH G042;Lo;0;L;;;;;N;;;;; +13171;EGYPTIAN HIEROGLYPH G043;Lo;0;L;;;;;N;;;;; +13172;EGYPTIAN HIEROGLYPH G043A;Lo;0;L;;;;;N;;;;; +13173;EGYPTIAN HIEROGLYPH G044;Lo;0;L;;;;;N;;;;; +13174;EGYPTIAN HIEROGLYPH G045;Lo;0;L;;;;;N;;;;; +13175;EGYPTIAN HIEROGLYPH G045A;Lo;0;L;;;;;N;;;;; +13176;EGYPTIAN HIEROGLYPH G046;Lo;0;L;;;;;N;;;;; +13177;EGYPTIAN HIEROGLYPH G047;Lo;0;L;;;;;N;;;;; +13178;EGYPTIAN HIEROGLYPH G048;Lo;0;L;;;;;N;;;;; +13179;EGYPTIAN HIEROGLYPH G049;Lo;0;L;;;;;N;;;;; +1317A;EGYPTIAN HIEROGLYPH G050;Lo;0;L;;;;;N;;;;; +1317B;EGYPTIAN HIEROGLYPH G051;Lo;0;L;;;;;N;;;;; +1317C;EGYPTIAN HIEROGLYPH G052;Lo;0;L;;;;;N;;;;; +1317D;EGYPTIAN HIEROGLYPH G053;Lo;0;L;;;;;N;;;;; +1317E;EGYPTIAN HIEROGLYPH G054;Lo;0;L;;;;;N;;;;; +1317F;EGYPTIAN HIEROGLYPH H001;Lo;0;L;;;;;N;;;;; +13180;EGYPTIAN HIEROGLYPH H002;Lo;0;L;;;;;N;;;;; +13181;EGYPTIAN HIEROGLYPH H003;Lo;0;L;;;;;N;;;;; +13182;EGYPTIAN HIEROGLYPH H004;Lo;0;L;;;;;N;;;;; +13183;EGYPTIAN HIEROGLYPH H005;Lo;0;L;;;;;N;;;;; +13184;EGYPTIAN HIEROGLYPH H006;Lo;0;L;;;;;N;;;;; +13185;EGYPTIAN HIEROGLYPH H006A;Lo;0;L;;;;;N;;;;; +13186;EGYPTIAN HIEROGLYPH H007;Lo;0;L;;;;;N;;;;; +13187;EGYPTIAN HIEROGLYPH H008;Lo;0;L;;;;;N;;;;; +13188;EGYPTIAN HIEROGLYPH I001;Lo;0;L;;;;;N;;;;; +13189;EGYPTIAN HIEROGLYPH I002;Lo;0;L;;;;;N;;;;; +1318A;EGYPTIAN HIEROGLYPH I003;Lo;0;L;;;;;N;;;;; +1318B;EGYPTIAN HIEROGLYPH I004;Lo;0;L;;;;;N;;;;; +1318C;EGYPTIAN HIEROGLYPH I005;Lo;0;L;;;;;N;;;;; +1318D;EGYPTIAN HIEROGLYPH I005A;Lo;0;L;;;;;N;;;;; +1318E;EGYPTIAN HIEROGLYPH I006;Lo;0;L;;;;;N;;;;; +1318F;EGYPTIAN HIEROGLYPH I007;Lo;0;L;;;;;N;;;;; +13190;EGYPTIAN HIEROGLYPH I008;Lo;0;L;;;;;N;;;;; +13191;EGYPTIAN HIEROGLYPH I009;Lo;0;L;;;;;N;;;;; +13192;EGYPTIAN HIEROGLYPH I009A;Lo;0;L;;;;;N;;;;; +13193;EGYPTIAN HIEROGLYPH I010;Lo;0;L;;;;;N;;;;; +13194;EGYPTIAN HIEROGLYPH I010A;Lo;0;L;;;;;N;;;;; +13195;EGYPTIAN HIEROGLYPH I011;Lo;0;L;;;;;N;;;;; +13196;EGYPTIAN HIEROGLYPH I011A;Lo;0;L;;;;;N;;;;; +13197;EGYPTIAN HIEROGLYPH I012;Lo;0;L;;;;;N;;;;; +13198;EGYPTIAN HIEROGLYPH I013;Lo;0;L;;;;;N;;;;; +13199;EGYPTIAN HIEROGLYPH I014;Lo;0;L;;;;;N;;;;; +1319A;EGYPTIAN HIEROGLYPH I015;Lo;0;L;;;;;N;;;;; +1319B;EGYPTIAN HIEROGLYPH K001;Lo;0;L;;;;;N;;;;; +1319C;EGYPTIAN HIEROGLYPH K002;Lo;0;L;;;;;N;;;;; +1319D;EGYPTIAN HIEROGLYPH K003;Lo;0;L;;;;;N;;;;; +1319E;EGYPTIAN HIEROGLYPH K004;Lo;0;L;;;;;N;;;;; +1319F;EGYPTIAN HIEROGLYPH K005;Lo;0;L;;;;;N;;;;; +131A0;EGYPTIAN HIEROGLYPH K006;Lo;0;L;;;;;N;;;;; +131A1;EGYPTIAN HIEROGLYPH K007;Lo;0;L;;;;;N;;;;; +131A2;EGYPTIAN HIEROGLYPH K008;Lo;0;L;;;;;N;;;;; +131A3;EGYPTIAN HIEROGLYPH L001;Lo;0;L;;;;;N;;;;; +131A4;EGYPTIAN HIEROGLYPH L002;Lo;0;L;;;;;N;;;;; +131A5;EGYPTIAN HIEROGLYPH L002A;Lo;0;L;;;;;N;;;;; +131A6;EGYPTIAN HIEROGLYPH L003;Lo;0;L;;;;;N;;;;; +131A7;EGYPTIAN HIEROGLYPH L004;Lo;0;L;;;;;N;;;;; +131A8;EGYPTIAN HIEROGLYPH L005;Lo;0;L;;;;;N;;;;; +131A9;EGYPTIAN HIEROGLYPH L006;Lo;0;L;;;;;N;;;;; +131AA;EGYPTIAN HIEROGLYPH L006A;Lo;0;L;;;;;N;;;;; +131AB;EGYPTIAN HIEROGLYPH L007;Lo;0;L;;;;;N;;;;; +131AC;EGYPTIAN HIEROGLYPH L008;Lo;0;L;;;;;N;;;;; +131AD;EGYPTIAN HIEROGLYPH M001;Lo;0;L;;;;;N;;;;; +131AE;EGYPTIAN HIEROGLYPH M001A;Lo;0;L;;;;;N;;;;; +131AF;EGYPTIAN HIEROGLYPH M001B;Lo;0;L;;;;;N;;;;; +131B0;EGYPTIAN HIEROGLYPH M002;Lo;0;L;;;;;N;;;;; +131B1;EGYPTIAN HIEROGLYPH M003;Lo;0;L;;;;;N;;;;; +131B2;EGYPTIAN HIEROGLYPH M003A;Lo;0;L;;;;;N;;;;; +131B3;EGYPTIAN HIEROGLYPH M004;Lo;0;L;;;;;N;;;;; +131B4;EGYPTIAN HIEROGLYPH M005;Lo;0;L;;;;;N;;;;; +131B5;EGYPTIAN HIEROGLYPH M006;Lo;0;L;;;;;N;;;;; +131B6;EGYPTIAN HIEROGLYPH M007;Lo;0;L;;;;;N;;;;; +131B7;EGYPTIAN HIEROGLYPH M008;Lo;0;L;;;;;N;;;;; +131B8;EGYPTIAN HIEROGLYPH M009;Lo;0;L;;;;;N;;;;; +131B9;EGYPTIAN HIEROGLYPH M010;Lo;0;L;;;;;N;;;;; +131BA;EGYPTIAN HIEROGLYPH M010A;Lo;0;L;;;;;N;;;;; +131BB;EGYPTIAN HIEROGLYPH M011;Lo;0;L;;;;;N;;;;; +131BC;EGYPTIAN HIEROGLYPH M012;Lo;0;L;;;;;N;;;;; +131BD;EGYPTIAN HIEROGLYPH M012A;Lo;0;L;;;;;N;;;;; +131BE;EGYPTIAN HIEROGLYPH M012B;Lo;0;L;;;;;N;;;;; +131BF;EGYPTIAN HIEROGLYPH M012C;Lo;0;L;;;;;N;;;;; +131C0;EGYPTIAN HIEROGLYPH M012D;Lo;0;L;;;;;N;;;;; +131C1;EGYPTIAN HIEROGLYPH M012E;Lo;0;L;;;;;N;;;;; +131C2;EGYPTIAN HIEROGLYPH M012F;Lo;0;L;;;;;N;;;;; +131C3;EGYPTIAN HIEROGLYPH M012G;Lo;0;L;;;;;N;;;;; +131C4;EGYPTIAN HIEROGLYPH M012H;Lo;0;L;;;;;N;;;;; +131C5;EGYPTIAN HIEROGLYPH M013;Lo;0;L;;;;;N;;;;; +131C6;EGYPTIAN HIEROGLYPH M014;Lo;0;L;;;;;N;;;;; +131C7;EGYPTIAN HIEROGLYPH M015;Lo;0;L;;;;;N;;;;; +131C8;EGYPTIAN HIEROGLYPH M015A;Lo;0;L;;;;;N;;;;; +131C9;EGYPTIAN HIEROGLYPH M016;Lo;0;L;;;;;N;;;;; +131CA;EGYPTIAN HIEROGLYPH M016A;Lo;0;L;;;;;N;;;;; +131CB;EGYPTIAN HIEROGLYPH M017;Lo;0;L;;;;;N;;;;; +131CC;EGYPTIAN HIEROGLYPH M017A;Lo;0;L;;;;;N;;;;; +131CD;EGYPTIAN HIEROGLYPH M018;Lo;0;L;;;;;N;;;;; +131CE;EGYPTIAN HIEROGLYPH M019;Lo;0;L;;;;;N;;;;; +131CF;EGYPTIAN HIEROGLYPH M020;Lo;0;L;;;;;N;;;;; +131D0;EGYPTIAN HIEROGLYPH M021;Lo;0;L;;;;;N;;;;; +131D1;EGYPTIAN HIEROGLYPH M022;Lo;0;L;;;;;N;;;;; +131D2;EGYPTIAN HIEROGLYPH M022A;Lo;0;L;;;;;N;;;;; +131D3;EGYPTIAN HIEROGLYPH M023;Lo;0;L;;;;;N;;;;; +131D4;EGYPTIAN HIEROGLYPH M024;Lo;0;L;;;;;N;;;;; +131D5;EGYPTIAN HIEROGLYPH M024A;Lo;0;L;;;;;N;;;;; +131D6;EGYPTIAN HIEROGLYPH M025;Lo;0;L;;;;;N;;;;; +131D7;EGYPTIAN HIEROGLYPH M026;Lo;0;L;;;;;N;;;;; +131D8;EGYPTIAN HIEROGLYPH M027;Lo;0;L;;;;;N;;;;; +131D9;EGYPTIAN HIEROGLYPH M028;Lo;0;L;;;;;N;;;;; +131DA;EGYPTIAN HIEROGLYPH M028A;Lo;0;L;;;;;N;;;;; +131DB;EGYPTIAN HIEROGLYPH M029;Lo;0;L;;;;;N;;;;; +131DC;EGYPTIAN HIEROGLYPH M030;Lo;0;L;;;;;N;;;;; +131DD;EGYPTIAN HIEROGLYPH M031;Lo;0;L;;;;;N;;;;; +131DE;EGYPTIAN HIEROGLYPH M031A;Lo;0;L;;;;;N;;;;; +131DF;EGYPTIAN HIEROGLYPH M032;Lo;0;L;;;;;N;;;;; +131E0;EGYPTIAN HIEROGLYPH M033;Lo;0;L;;;;;N;;;;; +131E1;EGYPTIAN HIEROGLYPH M033A;Lo;0;L;;;;;N;;;;; +131E2;EGYPTIAN HIEROGLYPH M033B;Lo;0;L;;;;;N;;;;; +131E3;EGYPTIAN HIEROGLYPH M034;Lo;0;L;;;;;N;;;;; +131E4;EGYPTIAN HIEROGLYPH M035;Lo;0;L;;;;;N;;;;; +131E5;EGYPTIAN HIEROGLYPH M036;Lo;0;L;;;;;N;;;;; +131E6;EGYPTIAN HIEROGLYPH M037;Lo;0;L;;;;;N;;;;; +131E7;EGYPTIAN HIEROGLYPH M038;Lo;0;L;;;;;N;;;;; +131E8;EGYPTIAN HIEROGLYPH M039;Lo;0;L;;;;;N;;;;; +131E9;EGYPTIAN HIEROGLYPH M040;Lo;0;L;;;;;N;;;;; +131EA;EGYPTIAN HIEROGLYPH M040A;Lo;0;L;;;;;N;;;;; +131EB;EGYPTIAN HIEROGLYPH M041;Lo;0;L;;;;;N;;;;; +131EC;EGYPTIAN HIEROGLYPH M042;Lo;0;L;;;;;N;;;;; +131ED;EGYPTIAN HIEROGLYPH M043;Lo;0;L;;;;;N;;;;; +131EE;EGYPTIAN HIEROGLYPH M044;Lo;0;L;;;;;N;;;;; +131EF;EGYPTIAN HIEROGLYPH N001;Lo;0;L;;;;;N;;;;; +131F0;EGYPTIAN HIEROGLYPH N002;Lo;0;L;;;;;N;;;;; +131F1;EGYPTIAN HIEROGLYPH N003;Lo;0;L;;;;;N;;;;; +131F2;EGYPTIAN HIEROGLYPH N004;Lo;0;L;;;;;N;;;;; +131F3;EGYPTIAN HIEROGLYPH N005;Lo;0;L;;;;;N;;;;; +131F4;EGYPTIAN HIEROGLYPH N006;Lo;0;L;;;;;N;;;;; +131F5;EGYPTIAN HIEROGLYPH N007;Lo;0;L;;;;;N;;;;; +131F6;EGYPTIAN HIEROGLYPH N008;Lo;0;L;;;;;N;;;;; +131F7;EGYPTIAN HIEROGLYPH N009;Lo;0;L;;;;;N;;;;; +131F8;EGYPTIAN HIEROGLYPH N010;Lo;0;L;;;;;N;;;;; +131F9;EGYPTIAN HIEROGLYPH N011;Lo;0;L;;;;;N;;;;; +131FA;EGYPTIAN HIEROGLYPH N012;Lo;0;L;;;;;N;;;;; +131FB;EGYPTIAN HIEROGLYPH N013;Lo;0;L;;;;;N;;;;; +131FC;EGYPTIAN HIEROGLYPH N014;Lo;0;L;;;;;N;;;;; +131FD;EGYPTIAN HIEROGLYPH N015;Lo;0;L;;;;;N;;;;; +131FE;EGYPTIAN HIEROGLYPH N016;Lo;0;L;;;;;N;;;;; +131FF;EGYPTIAN HIEROGLYPH N017;Lo;0;L;;;;;N;;;;; +13200;EGYPTIAN HIEROGLYPH N018;Lo;0;L;;;;;N;;;;; +13201;EGYPTIAN HIEROGLYPH N018A;Lo;0;L;;;;;N;;;;; +13202;EGYPTIAN HIEROGLYPH N018B;Lo;0;L;;;;;N;;;;; +13203;EGYPTIAN HIEROGLYPH N019;Lo;0;L;;;;;N;;;;; +13204;EGYPTIAN HIEROGLYPH N020;Lo;0;L;;;;;N;;;;; +13205;EGYPTIAN HIEROGLYPH N021;Lo;0;L;;;;;N;;;;; +13206;EGYPTIAN HIEROGLYPH N022;Lo;0;L;;;;;N;;;;; +13207;EGYPTIAN HIEROGLYPH N023;Lo;0;L;;;;;N;;;;; +13208;EGYPTIAN HIEROGLYPH N024;Lo;0;L;;;;;N;;;;; +13209;EGYPTIAN HIEROGLYPH N025;Lo;0;L;;;;;N;;;;; +1320A;EGYPTIAN HIEROGLYPH N025A;Lo;0;L;;;;;N;;;;; +1320B;EGYPTIAN HIEROGLYPH N026;Lo;0;L;;;;;N;;;;; +1320C;EGYPTIAN HIEROGLYPH N027;Lo;0;L;;;;;N;;;;; +1320D;EGYPTIAN HIEROGLYPH N028;Lo;0;L;;;;;N;;;;; +1320E;EGYPTIAN HIEROGLYPH N029;Lo;0;L;;;;;N;;;;; +1320F;EGYPTIAN HIEROGLYPH N030;Lo;0;L;;;;;N;;;;; +13210;EGYPTIAN HIEROGLYPH N031;Lo;0;L;;;;;N;;;;; +13211;EGYPTIAN HIEROGLYPH N032;Lo;0;L;;;;;N;;;;; +13212;EGYPTIAN HIEROGLYPH N033;Lo;0;L;;;;;N;;;;; +13213;EGYPTIAN HIEROGLYPH N033A;Lo;0;L;;;;;N;;;;; +13214;EGYPTIAN HIEROGLYPH N034;Lo;0;L;;;;;N;;;;; +13215;EGYPTIAN HIEROGLYPH N034A;Lo;0;L;;;;;N;;;;; +13216;EGYPTIAN HIEROGLYPH N035;Lo;0;L;;;;;N;;;;; +13217;EGYPTIAN HIEROGLYPH N035A;Lo;0;L;;;;;N;;;;; +13218;EGYPTIAN HIEROGLYPH N036;Lo;0;L;;;;;N;;;;; +13219;EGYPTIAN HIEROGLYPH N037;Lo;0;L;;;;;N;;;;; +1321A;EGYPTIAN HIEROGLYPH N037A;Lo;0;L;;;;;N;;;;; +1321B;EGYPTIAN HIEROGLYPH N038;Lo;0;L;;;;;N;;;;; +1321C;EGYPTIAN HIEROGLYPH N039;Lo;0;L;;;;;N;;;;; +1321D;EGYPTIAN HIEROGLYPH N040;Lo;0;L;;;;;N;;;;; +1321E;EGYPTIAN HIEROGLYPH N041;Lo;0;L;;;;;N;;;;; +1321F;EGYPTIAN HIEROGLYPH N042;Lo;0;L;;;;;N;;;;; +13220;EGYPTIAN HIEROGLYPH NL001;Lo;0;L;;;;;N;;;;; +13221;EGYPTIAN HIEROGLYPH NL002;Lo;0;L;;;;;N;;;;; +13222;EGYPTIAN HIEROGLYPH NL003;Lo;0;L;;;;;N;;;;; +13223;EGYPTIAN HIEROGLYPH NL004;Lo;0;L;;;;;N;;;;; +13224;EGYPTIAN HIEROGLYPH NL005;Lo;0;L;;;;;N;;;;; +13225;EGYPTIAN HIEROGLYPH NL005A;Lo;0;L;;;;;N;;;;; +13226;EGYPTIAN HIEROGLYPH NL006;Lo;0;L;;;;;N;;;;; +13227;EGYPTIAN HIEROGLYPH NL007;Lo;0;L;;;;;N;;;;; +13228;EGYPTIAN HIEROGLYPH NL008;Lo;0;L;;;;;N;;;;; +13229;EGYPTIAN HIEROGLYPH NL009;Lo;0;L;;;;;N;;;;; +1322A;EGYPTIAN HIEROGLYPH NL010;Lo;0;L;;;;;N;;;;; +1322B;EGYPTIAN HIEROGLYPH NL011;Lo;0;L;;;;;N;;;;; +1322C;EGYPTIAN HIEROGLYPH NL012;Lo;0;L;;;;;N;;;;; +1322D;EGYPTIAN HIEROGLYPH NL013;Lo;0;L;;;;;N;;;;; +1322E;EGYPTIAN HIEROGLYPH NL014;Lo;0;L;;;;;N;;;;; +1322F;EGYPTIAN HIEROGLYPH NL015;Lo;0;L;;;;;N;;;;; +13230;EGYPTIAN HIEROGLYPH NL016;Lo;0;L;;;;;N;;;;; +13231;EGYPTIAN HIEROGLYPH NL017;Lo;0;L;;;;;N;;;;; +13232;EGYPTIAN HIEROGLYPH NL017A;Lo;0;L;;;;;N;;;;; +13233;EGYPTIAN HIEROGLYPH NL018;Lo;0;L;;;;;N;;;;; +13234;EGYPTIAN HIEROGLYPH NL019;Lo;0;L;;;;;N;;;;; +13235;EGYPTIAN HIEROGLYPH NL020;Lo;0;L;;;;;N;;;;; +13236;EGYPTIAN HIEROGLYPH NU001;Lo;0;L;;;;;N;;;;; +13237;EGYPTIAN HIEROGLYPH NU002;Lo;0;L;;;;;N;;;;; +13238;EGYPTIAN HIEROGLYPH NU003;Lo;0;L;;;;;N;;;;; +13239;EGYPTIAN HIEROGLYPH NU004;Lo;0;L;;;;;N;;;;; +1323A;EGYPTIAN HIEROGLYPH NU005;Lo;0;L;;;;;N;;;;; +1323B;EGYPTIAN HIEROGLYPH NU006;Lo;0;L;;;;;N;;;;; +1323C;EGYPTIAN HIEROGLYPH NU007;Lo;0;L;;;;;N;;;;; +1323D;EGYPTIAN HIEROGLYPH NU008;Lo;0;L;;;;;N;;;;; +1323E;EGYPTIAN HIEROGLYPH NU009;Lo;0;L;;;;;N;;;;; +1323F;EGYPTIAN HIEROGLYPH NU010;Lo;0;L;;;;;N;;;;; +13240;EGYPTIAN HIEROGLYPH NU010A;Lo;0;L;;;;;N;;;;; +13241;EGYPTIAN HIEROGLYPH NU011;Lo;0;L;;;;;N;;;;; +13242;EGYPTIAN HIEROGLYPH NU011A;Lo;0;L;;;;;N;;;;; +13243;EGYPTIAN HIEROGLYPH NU012;Lo;0;L;;;;;N;;;;; +13244;EGYPTIAN HIEROGLYPH NU013;Lo;0;L;;;;;N;;;;; +13245;EGYPTIAN HIEROGLYPH NU014;Lo;0;L;;;;;N;;;;; +13246;EGYPTIAN HIEROGLYPH NU015;Lo;0;L;;;;;N;;;;; +13247;EGYPTIAN HIEROGLYPH NU016;Lo;0;L;;;;;N;;;;; +13248;EGYPTIAN HIEROGLYPH NU017;Lo;0;L;;;;;N;;;;; +13249;EGYPTIAN HIEROGLYPH NU018;Lo;0;L;;;;;N;;;;; +1324A;EGYPTIAN HIEROGLYPH NU018A;Lo;0;L;;;;;N;;;;; +1324B;EGYPTIAN HIEROGLYPH NU019;Lo;0;L;;;;;N;;;;; +1324C;EGYPTIAN HIEROGLYPH NU020;Lo;0;L;;;;;N;;;;; +1324D;EGYPTIAN HIEROGLYPH NU021;Lo;0;L;;;;;N;;;;; +1324E;EGYPTIAN HIEROGLYPH NU022;Lo;0;L;;;;;N;;;;; +1324F;EGYPTIAN HIEROGLYPH NU022A;Lo;0;L;;;;;N;;;;; +13250;EGYPTIAN HIEROGLYPH O001;Lo;0;L;;;;;N;;;;; +13251;EGYPTIAN HIEROGLYPH O001A;Lo;0;L;;;;;N;;;;; +13252;EGYPTIAN HIEROGLYPH O002;Lo;0;L;;;;;N;;;;; +13253;EGYPTIAN HIEROGLYPH O003;Lo;0;L;;;;;N;;;;; +13254;EGYPTIAN HIEROGLYPH O004;Lo;0;L;;;;;N;;;;; +13255;EGYPTIAN HIEROGLYPH O005;Lo;0;L;;;;;N;;;;; +13256;EGYPTIAN HIEROGLYPH O005A;Lo;0;L;;;;;N;;;;; +13257;EGYPTIAN HIEROGLYPH O006;Lo;0;L;;;;;N;;;;; +13258;EGYPTIAN HIEROGLYPH O006A;Lo;0;L;;;;;N;;;;; +13259;EGYPTIAN HIEROGLYPH O006B;Lo;0;L;;;;;N;;;;; +1325A;EGYPTIAN HIEROGLYPH O006C;Lo;0;L;;;;;N;;;;; +1325B;EGYPTIAN HIEROGLYPH O006D;Lo;0;L;;;;;N;;;;; +1325C;EGYPTIAN HIEROGLYPH O006E;Lo;0;L;;;;;N;;;;; +1325D;EGYPTIAN HIEROGLYPH O006F;Lo;0;L;;;;;N;;;;; +1325E;EGYPTIAN HIEROGLYPH O007;Lo;0;L;;;;;N;;;;; +1325F;EGYPTIAN HIEROGLYPH O008;Lo;0;L;;;;;N;;;;; +13260;EGYPTIAN HIEROGLYPH O009;Lo;0;L;;;;;N;;;;; +13261;EGYPTIAN HIEROGLYPH O010;Lo;0;L;;;;;N;;;;; +13262;EGYPTIAN HIEROGLYPH O010A;Lo;0;L;;;;;N;;;;; +13263;EGYPTIAN HIEROGLYPH O010B;Lo;0;L;;;;;N;;;;; +13264;EGYPTIAN HIEROGLYPH O010C;Lo;0;L;;;;;N;;;;; +13265;EGYPTIAN HIEROGLYPH O011;Lo;0;L;;;;;N;;;;; +13266;EGYPTIAN HIEROGLYPH O012;Lo;0;L;;;;;N;;;;; +13267;EGYPTIAN HIEROGLYPH O013;Lo;0;L;;;;;N;;;;; +13268;EGYPTIAN HIEROGLYPH O014;Lo;0;L;;;;;N;;;;; +13269;EGYPTIAN HIEROGLYPH O015;Lo;0;L;;;;;N;;;;; +1326A;EGYPTIAN HIEROGLYPH O016;Lo;0;L;;;;;N;;;;; +1326B;EGYPTIAN HIEROGLYPH O017;Lo;0;L;;;;;N;;;;; +1326C;EGYPTIAN HIEROGLYPH O018;Lo;0;L;;;;;N;;;;; +1326D;EGYPTIAN HIEROGLYPH O019;Lo;0;L;;;;;N;;;;; +1326E;EGYPTIAN HIEROGLYPH O019A;Lo;0;L;;;;;N;;;;; +1326F;EGYPTIAN HIEROGLYPH O020;Lo;0;L;;;;;N;;;;; +13270;EGYPTIAN HIEROGLYPH O020A;Lo;0;L;;;;;N;;;;; +13271;EGYPTIAN HIEROGLYPH O021;Lo;0;L;;;;;N;;;;; +13272;EGYPTIAN HIEROGLYPH O022;Lo;0;L;;;;;N;;;;; +13273;EGYPTIAN HIEROGLYPH O023;Lo;0;L;;;;;N;;;;; +13274;EGYPTIAN HIEROGLYPH O024;Lo;0;L;;;;;N;;;;; +13275;EGYPTIAN HIEROGLYPH O024A;Lo;0;L;;;;;N;;;;; +13276;EGYPTIAN HIEROGLYPH O025;Lo;0;L;;;;;N;;;;; +13277;EGYPTIAN HIEROGLYPH O025A;Lo;0;L;;;;;N;;;;; +13278;EGYPTIAN HIEROGLYPH O026;Lo;0;L;;;;;N;;;;; +13279;EGYPTIAN HIEROGLYPH O027;Lo;0;L;;;;;N;;;;; +1327A;EGYPTIAN HIEROGLYPH O028;Lo;0;L;;;;;N;;;;; +1327B;EGYPTIAN HIEROGLYPH O029;Lo;0;L;;;;;N;;;;; +1327C;EGYPTIAN HIEROGLYPH O029A;Lo;0;L;;;;;N;;;;; +1327D;EGYPTIAN HIEROGLYPH O030;Lo;0;L;;;;;N;;;;; +1327E;EGYPTIAN HIEROGLYPH O030A;Lo;0;L;;;;;N;;;;; +1327F;EGYPTIAN HIEROGLYPH O031;Lo;0;L;;;;;N;;;;; +13280;EGYPTIAN HIEROGLYPH O032;Lo;0;L;;;;;N;;;;; +13281;EGYPTIAN HIEROGLYPH O033;Lo;0;L;;;;;N;;;;; +13282;EGYPTIAN HIEROGLYPH O033A;Lo;0;L;;;;;N;;;;; +13283;EGYPTIAN HIEROGLYPH O034;Lo;0;L;;;;;N;;;;; +13284;EGYPTIAN HIEROGLYPH O035;Lo;0;L;;;;;N;;;;; +13285;EGYPTIAN HIEROGLYPH O036;Lo;0;L;;;;;N;;;;; +13286;EGYPTIAN HIEROGLYPH O036A;Lo;0;L;;;;;N;;;;; +13287;EGYPTIAN HIEROGLYPH O036B;Lo;0;L;;;;;N;;;;; +13288;EGYPTIAN HIEROGLYPH O036C;Lo;0;L;;;;;N;;;;; +13289;EGYPTIAN HIEROGLYPH O036D;Lo;0;L;;;;;N;;;;; +1328A;EGYPTIAN HIEROGLYPH O037;Lo;0;L;;;;;N;;;;; +1328B;EGYPTIAN HIEROGLYPH O038;Lo;0;L;;;;;N;;;;; +1328C;EGYPTIAN HIEROGLYPH O039;Lo;0;L;;;;;N;;;;; +1328D;EGYPTIAN HIEROGLYPH O040;Lo;0;L;;;;;N;;;;; +1328E;EGYPTIAN HIEROGLYPH O041;Lo;0;L;;;;;N;;;;; +1328F;EGYPTIAN HIEROGLYPH O042;Lo;0;L;;;;;N;;;;; +13290;EGYPTIAN HIEROGLYPH O043;Lo;0;L;;;;;N;;;;; +13291;EGYPTIAN HIEROGLYPH O044;Lo;0;L;;;;;N;;;;; +13292;EGYPTIAN HIEROGLYPH O045;Lo;0;L;;;;;N;;;;; +13293;EGYPTIAN HIEROGLYPH O046;Lo;0;L;;;;;N;;;;; +13294;EGYPTIAN HIEROGLYPH O047;Lo;0;L;;;;;N;;;;; +13295;EGYPTIAN HIEROGLYPH O048;Lo;0;L;;;;;N;;;;; +13296;EGYPTIAN HIEROGLYPH O049;Lo;0;L;;;;;N;;;;; +13297;EGYPTIAN HIEROGLYPH O050;Lo;0;L;;;;;N;;;;; +13298;EGYPTIAN HIEROGLYPH O050A;Lo;0;L;;;;;N;;;;; +13299;EGYPTIAN HIEROGLYPH O050B;Lo;0;L;;;;;N;;;;; +1329A;EGYPTIAN HIEROGLYPH O051;Lo;0;L;;;;;N;;;;; +1329B;EGYPTIAN HIEROGLYPH P001;Lo;0;L;;;;;N;;;;; +1329C;EGYPTIAN HIEROGLYPH P001A;Lo;0;L;;;;;N;;;;; +1329D;EGYPTIAN HIEROGLYPH P002;Lo;0;L;;;;;N;;;;; +1329E;EGYPTIAN HIEROGLYPH P003;Lo;0;L;;;;;N;;;;; +1329F;EGYPTIAN HIEROGLYPH P003A;Lo;0;L;;;;;N;;;;; +132A0;EGYPTIAN HIEROGLYPH P004;Lo;0;L;;;;;N;;;;; +132A1;EGYPTIAN HIEROGLYPH P005;Lo;0;L;;;;;N;;;;; +132A2;EGYPTIAN HIEROGLYPH P006;Lo;0;L;;;;;N;;;;; +132A3;EGYPTIAN HIEROGLYPH P007;Lo;0;L;;;;;N;;;;; +132A4;EGYPTIAN HIEROGLYPH P008;Lo;0;L;;;;;N;;;;; +132A5;EGYPTIAN HIEROGLYPH P009;Lo;0;L;;;;;N;;;;; +132A6;EGYPTIAN HIEROGLYPH P010;Lo;0;L;;;;;N;;;;; +132A7;EGYPTIAN HIEROGLYPH P011;Lo;0;L;;;;;N;;;;; +132A8;EGYPTIAN HIEROGLYPH Q001;Lo;0;L;;;;;N;;;;; +132A9;EGYPTIAN HIEROGLYPH Q002;Lo;0;L;;;;;N;;;;; +132AA;EGYPTIAN HIEROGLYPH Q003;Lo;0;L;;;;;N;;;;; +132AB;EGYPTIAN HIEROGLYPH Q004;Lo;0;L;;;;;N;;;;; +132AC;EGYPTIAN HIEROGLYPH Q005;Lo;0;L;;;;;N;;;;; +132AD;EGYPTIAN HIEROGLYPH Q006;Lo;0;L;;;;;N;;;;; +132AE;EGYPTIAN HIEROGLYPH Q007;Lo;0;L;;;;;N;;;;; +132AF;EGYPTIAN HIEROGLYPH R001;Lo;0;L;;;;;N;;;;; +132B0;EGYPTIAN HIEROGLYPH R002;Lo;0;L;;;;;N;;;;; +132B1;EGYPTIAN HIEROGLYPH R002A;Lo;0;L;;;;;N;;;;; +132B2;EGYPTIAN HIEROGLYPH R003;Lo;0;L;;;;;N;;;;; +132B3;EGYPTIAN HIEROGLYPH R003A;Lo;0;L;;;;;N;;;;; +132B4;EGYPTIAN HIEROGLYPH R003B;Lo;0;L;;;;;N;;;;; +132B5;EGYPTIAN HIEROGLYPH R004;Lo;0;L;;;;;N;;;;; +132B6;EGYPTIAN HIEROGLYPH R005;Lo;0;L;;;;;N;;;;; +132B7;EGYPTIAN HIEROGLYPH R006;Lo;0;L;;;;;N;;;;; +132B8;EGYPTIAN HIEROGLYPH R007;Lo;0;L;;;;;N;;;;; +132B9;EGYPTIAN HIEROGLYPH R008;Lo;0;L;;;;;N;;;;; +132BA;EGYPTIAN HIEROGLYPH R009;Lo;0;L;;;;;N;;;;; +132BB;EGYPTIAN HIEROGLYPH R010;Lo;0;L;;;;;N;;;;; +132BC;EGYPTIAN HIEROGLYPH R010A;Lo;0;L;;;;;N;;;;; +132BD;EGYPTIAN HIEROGLYPH R011;Lo;0;L;;;;;N;;;;; +132BE;EGYPTIAN HIEROGLYPH R012;Lo;0;L;;;;;N;;;;; +132BF;EGYPTIAN HIEROGLYPH R013;Lo;0;L;;;;;N;;;;; +132C0;EGYPTIAN HIEROGLYPH R014;Lo;0;L;;;;;N;;;;; +132C1;EGYPTIAN HIEROGLYPH R015;Lo;0;L;;;;;N;;;;; +132C2;EGYPTIAN HIEROGLYPH R016;Lo;0;L;;;;;N;;;;; +132C3;EGYPTIAN HIEROGLYPH R016A;Lo;0;L;;;;;N;;;;; +132C4;EGYPTIAN HIEROGLYPH R017;Lo;0;L;;;;;N;;;;; +132C5;EGYPTIAN HIEROGLYPH R018;Lo;0;L;;;;;N;;;;; +132C6;EGYPTIAN HIEROGLYPH R019;Lo;0;L;;;;;N;;;;; +132C7;EGYPTIAN HIEROGLYPH R020;Lo;0;L;;;;;N;;;;; +132C8;EGYPTIAN HIEROGLYPH R021;Lo;0;L;;;;;N;;;;; +132C9;EGYPTIAN HIEROGLYPH R022;Lo;0;L;;;;;N;;;;; +132CA;EGYPTIAN HIEROGLYPH R023;Lo;0;L;;;;;N;;;;; +132CB;EGYPTIAN HIEROGLYPH R024;Lo;0;L;;;;;N;;;;; +132CC;EGYPTIAN HIEROGLYPH R025;Lo;0;L;;;;;N;;;;; +132CD;EGYPTIAN HIEROGLYPH R026;Lo;0;L;;;;;N;;;;; +132CE;EGYPTIAN HIEROGLYPH R027;Lo;0;L;;;;;N;;;;; +132CF;EGYPTIAN HIEROGLYPH R028;Lo;0;L;;;;;N;;;;; +132D0;EGYPTIAN HIEROGLYPH R029;Lo;0;L;;;;;N;;;;; +132D1;EGYPTIAN HIEROGLYPH S001;Lo;0;L;;;;;N;;;;; +132D2;EGYPTIAN HIEROGLYPH S002;Lo;0;L;;;;;N;;;;; +132D3;EGYPTIAN HIEROGLYPH S002A;Lo;0;L;;;;;N;;;;; +132D4;EGYPTIAN HIEROGLYPH S003;Lo;0;L;;;;;N;;;;; +132D5;EGYPTIAN HIEROGLYPH S004;Lo;0;L;;;;;N;;;;; +132D6;EGYPTIAN HIEROGLYPH S005;Lo;0;L;;;;;N;;;;; +132D7;EGYPTIAN HIEROGLYPH S006;Lo;0;L;;;;;N;;;;; +132D8;EGYPTIAN HIEROGLYPH S006A;Lo;0;L;;;;;N;;;;; +132D9;EGYPTIAN HIEROGLYPH S007;Lo;0;L;;;;;N;;;;; +132DA;EGYPTIAN HIEROGLYPH S008;Lo;0;L;;;;;N;;;;; +132DB;EGYPTIAN HIEROGLYPH S009;Lo;0;L;;;;;N;;;;; +132DC;EGYPTIAN HIEROGLYPH S010;Lo;0;L;;;;;N;;;;; +132DD;EGYPTIAN HIEROGLYPH S011;Lo;0;L;;;;;N;;;;; +132DE;EGYPTIAN HIEROGLYPH S012;Lo;0;L;;;;;N;;;;; +132DF;EGYPTIAN HIEROGLYPH S013;Lo;0;L;;;;;N;;;;; +132E0;EGYPTIAN HIEROGLYPH S014;Lo;0;L;;;;;N;;;;; +132E1;EGYPTIAN HIEROGLYPH S014A;Lo;0;L;;;;;N;;;;; +132E2;EGYPTIAN HIEROGLYPH S014B;Lo;0;L;;;;;N;;;;; +132E3;EGYPTIAN HIEROGLYPH S015;Lo;0;L;;;;;N;;;;; +132E4;EGYPTIAN HIEROGLYPH S016;Lo;0;L;;;;;N;;;;; +132E5;EGYPTIAN HIEROGLYPH S017;Lo;0;L;;;;;N;;;;; +132E6;EGYPTIAN HIEROGLYPH S017A;Lo;0;L;;;;;N;;;;; +132E7;EGYPTIAN HIEROGLYPH S018;Lo;0;L;;;;;N;;;;; +132E8;EGYPTIAN HIEROGLYPH S019;Lo;0;L;;;;;N;;;;; +132E9;EGYPTIAN HIEROGLYPH S020;Lo;0;L;;;;;N;;;;; +132EA;EGYPTIAN HIEROGLYPH S021;Lo;0;L;;;;;N;;;;; +132EB;EGYPTIAN HIEROGLYPH S022;Lo;0;L;;;;;N;;;;; +132EC;EGYPTIAN HIEROGLYPH S023;Lo;0;L;;;;;N;;;;; +132ED;EGYPTIAN HIEROGLYPH S024;Lo;0;L;;;;;N;;;;; +132EE;EGYPTIAN HIEROGLYPH S025;Lo;0;L;;;;;N;;;;; +132EF;EGYPTIAN HIEROGLYPH S026;Lo;0;L;;;;;N;;;;; +132F0;EGYPTIAN HIEROGLYPH S026A;Lo;0;L;;;;;N;;;;; +132F1;EGYPTIAN HIEROGLYPH S026B;Lo;0;L;;;;;N;;;;; +132F2;EGYPTIAN HIEROGLYPH S027;Lo;0;L;;;;;N;;;;; +132F3;EGYPTIAN HIEROGLYPH S028;Lo;0;L;;;;;N;;;;; +132F4;EGYPTIAN HIEROGLYPH S029;Lo;0;L;;;;;N;;;;; +132F5;EGYPTIAN HIEROGLYPH S030;Lo;0;L;;;;;N;;;;; +132F6;EGYPTIAN HIEROGLYPH S031;Lo;0;L;;;;;N;;;;; +132F7;EGYPTIAN HIEROGLYPH S032;Lo;0;L;;;;;N;;;;; +132F8;EGYPTIAN HIEROGLYPH S033;Lo;0;L;;;;;N;;;;; +132F9;EGYPTIAN HIEROGLYPH S034;Lo;0;L;;;;;N;;;;; +132FA;EGYPTIAN HIEROGLYPH S035;Lo;0;L;;;;;N;;;;; +132FB;EGYPTIAN HIEROGLYPH S035A;Lo;0;L;;;;;N;;;;; +132FC;EGYPTIAN HIEROGLYPH S036;Lo;0;L;;;;;N;;;;; +132FD;EGYPTIAN HIEROGLYPH S037;Lo;0;L;;;;;N;;;;; +132FE;EGYPTIAN HIEROGLYPH S038;Lo;0;L;;;;;N;;;;; +132FF;EGYPTIAN HIEROGLYPH S039;Lo;0;L;;;;;N;;;;; +13300;EGYPTIAN HIEROGLYPH S040;Lo;0;L;;;;;N;;;;; +13301;EGYPTIAN HIEROGLYPH S041;Lo;0;L;;;;;N;;;;; +13302;EGYPTIAN HIEROGLYPH S042;Lo;0;L;;;;;N;;;;; +13303;EGYPTIAN HIEROGLYPH S043;Lo;0;L;;;;;N;;;;; +13304;EGYPTIAN HIEROGLYPH S044;Lo;0;L;;;;;N;;;;; +13305;EGYPTIAN HIEROGLYPH S045;Lo;0;L;;;;;N;;;;; +13306;EGYPTIAN HIEROGLYPH S046;Lo;0;L;;;;;N;;;;; +13307;EGYPTIAN HIEROGLYPH T001;Lo;0;L;;;;;N;;;;; +13308;EGYPTIAN HIEROGLYPH T002;Lo;0;L;;;;;N;;;;; +13309;EGYPTIAN HIEROGLYPH T003;Lo;0;L;;;;;N;;;;; +1330A;EGYPTIAN HIEROGLYPH T003A;Lo;0;L;;;;;N;;;;; +1330B;EGYPTIAN HIEROGLYPH T004;Lo;0;L;;;;;N;;;;; +1330C;EGYPTIAN HIEROGLYPH T005;Lo;0;L;;;;;N;;;;; +1330D;EGYPTIAN HIEROGLYPH T006;Lo;0;L;;;;;N;;;;; +1330E;EGYPTIAN HIEROGLYPH T007;Lo;0;L;;;;;N;;;;; +1330F;EGYPTIAN HIEROGLYPH T007A;Lo;0;L;;;;;N;;;;; +13310;EGYPTIAN HIEROGLYPH T008;Lo;0;L;;;;;N;;;;; +13311;EGYPTIAN HIEROGLYPH T008A;Lo;0;L;;;;;N;;;;; +13312;EGYPTIAN HIEROGLYPH T009;Lo;0;L;;;;;N;;;;; +13313;EGYPTIAN HIEROGLYPH T009A;Lo;0;L;;;;;N;;;;; +13314;EGYPTIAN HIEROGLYPH T010;Lo;0;L;;;;;N;;;;; +13315;EGYPTIAN HIEROGLYPH T011;Lo;0;L;;;;;N;;;;; +13316;EGYPTIAN HIEROGLYPH T011A;Lo;0;L;;;;;N;;;;; +13317;EGYPTIAN HIEROGLYPH T012;Lo;0;L;;;;;N;;;;; +13318;EGYPTIAN HIEROGLYPH T013;Lo;0;L;;;;;N;;;;; +13319;EGYPTIAN HIEROGLYPH T014;Lo;0;L;;;;;N;;;;; +1331A;EGYPTIAN HIEROGLYPH T015;Lo;0;L;;;;;N;;;;; +1331B;EGYPTIAN HIEROGLYPH T016;Lo;0;L;;;;;N;;;;; +1331C;EGYPTIAN HIEROGLYPH T016A;Lo;0;L;;;;;N;;;;; +1331D;EGYPTIAN HIEROGLYPH T017;Lo;0;L;;;;;N;;;;; +1331E;EGYPTIAN HIEROGLYPH T018;Lo;0;L;;;;;N;;;;; +1331F;EGYPTIAN HIEROGLYPH T019;Lo;0;L;;;;;N;;;;; +13320;EGYPTIAN HIEROGLYPH T020;Lo;0;L;;;;;N;;;;; +13321;EGYPTIAN HIEROGLYPH T021;Lo;0;L;;;;;N;;;;; +13322;EGYPTIAN HIEROGLYPH T022;Lo;0;L;;;;;N;;;;; +13323;EGYPTIAN HIEROGLYPH T023;Lo;0;L;;;;;N;;;;; +13324;EGYPTIAN HIEROGLYPH T024;Lo;0;L;;;;;N;;;;; +13325;EGYPTIAN HIEROGLYPH T025;Lo;0;L;;;;;N;;;;; +13326;EGYPTIAN HIEROGLYPH T026;Lo;0;L;;;;;N;;;;; +13327;EGYPTIAN HIEROGLYPH T027;Lo;0;L;;;;;N;;;;; +13328;EGYPTIAN HIEROGLYPH T028;Lo;0;L;;;;;N;;;;; +13329;EGYPTIAN HIEROGLYPH T029;Lo;0;L;;;;;N;;;;; +1332A;EGYPTIAN HIEROGLYPH T030;Lo;0;L;;;;;N;;;;; +1332B;EGYPTIAN HIEROGLYPH T031;Lo;0;L;;;;;N;;;;; +1332C;EGYPTIAN HIEROGLYPH T032;Lo;0;L;;;;;N;;;;; +1332D;EGYPTIAN HIEROGLYPH T032A;Lo;0;L;;;;;N;;;;; +1332E;EGYPTIAN HIEROGLYPH T033;Lo;0;L;;;;;N;;;;; +1332F;EGYPTIAN HIEROGLYPH T033A;Lo;0;L;;;;;N;;;;; +13330;EGYPTIAN HIEROGLYPH T034;Lo;0;L;;;;;N;;;;; +13331;EGYPTIAN HIEROGLYPH T035;Lo;0;L;;;;;N;;;;; +13332;EGYPTIAN HIEROGLYPH T036;Lo;0;L;;;;;N;;;;; +13333;EGYPTIAN HIEROGLYPH U001;Lo;0;L;;;;;N;;;;; +13334;EGYPTIAN HIEROGLYPH U002;Lo;0;L;;;;;N;;;;; +13335;EGYPTIAN HIEROGLYPH U003;Lo;0;L;;;;;N;;;;; +13336;EGYPTIAN HIEROGLYPH U004;Lo;0;L;;;;;N;;;;; +13337;EGYPTIAN HIEROGLYPH U005;Lo;0;L;;;;;N;;;;; +13338;EGYPTIAN HIEROGLYPH U006;Lo;0;L;;;;;N;;;;; +13339;EGYPTIAN HIEROGLYPH U006A;Lo;0;L;;;;;N;;;;; +1333A;EGYPTIAN HIEROGLYPH U006B;Lo;0;L;;;;;N;;;;; +1333B;EGYPTIAN HIEROGLYPH U007;Lo;0;L;;;;;N;;;;; +1333C;EGYPTIAN HIEROGLYPH U008;Lo;0;L;;;;;N;;;;; +1333D;EGYPTIAN HIEROGLYPH U009;Lo;0;L;;;;;N;;;;; +1333E;EGYPTIAN HIEROGLYPH U010;Lo;0;L;;;;;N;;;;; +1333F;EGYPTIAN HIEROGLYPH U011;Lo;0;L;;;;;N;;;;; +13340;EGYPTIAN HIEROGLYPH U012;Lo;0;L;;;;;N;;;;; +13341;EGYPTIAN HIEROGLYPH U013;Lo;0;L;;;;;N;;;;; +13342;EGYPTIAN HIEROGLYPH U014;Lo;0;L;;;;;N;;;;; +13343;EGYPTIAN HIEROGLYPH U015;Lo;0;L;;;;;N;;;;; +13344;EGYPTIAN HIEROGLYPH U016;Lo;0;L;;;;;N;;;;; +13345;EGYPTIAN HIEROGLYPH U017;Lo;0;L;;;;;N;;;;; +13346;EGYPTIAN HIEROGLYPH U018;Lo;0;L;;;;;N;;;;; +13347;EGYPTIAN HIEROGLYPH U019;Lo;0;L;;;;;N;;;;; +13348;EGYPTIAN HIEROGLYPH U020;Lo;0;L;;;;;N;;;;; +13349;EGYPTIAN HIEROGLYPH U021;Lo;0;L;;;;;N;;;;; +1334A;EGYPTIAN HIEROGLYPH U022;Lo;0;L;;;;;N;;;;; +1334B;EGYPTIAN HIEROGLYPH U023;Lo;0;L;;;;;N;;;;; +1334C;EGYPTIAN HIEROGLYPH U023A;Lo;0;L;;;;;N;;;;; +1334D;EGYPTIAN HIEROGLYPH U024;Lo;0;L;;;;;N;;;;; +1334E;EGYPTIAN HIEROGLYPH U025;Lo;0;L;;;;;N;;;;; +1334F;EGYPTIAN HIEROGLYPH U026;Lo;0;L;;;;;N;;;;; +13350;EGYPTIAN HIEROGLYPH U027;Lo;0;L;;;;;N;;;;; +13351;EGYPTIAN HIEROGLYPH U028;Lo;0;L;;;;;N;;;;; +13352;EGYPTIAN HIEROGLYPH U029;Lo;0;L;;;;;N;;;;; +13353;EGYPTIAN HIEROGLYPH U029A;Lo;0;L;;;;;N;;;;; +13354;EGYPTIAN HIEROGLYPH U030;Lo;0;L;;;;;N;;;;; +13355;EGYPTIAN HIEROGLYPH U031;Lo;0;L;;;;;N;;;;; +13356;EGYPTIAN HIEROGLYPH U032;Lo;0;L;;;;;N;;;;; +13357;EGYPTIAN HIEROGLYPH U032A;Lo;0;L;;;;;N;;;;; +13358;EGYPTIAN HIEROGLYPH U033;Lo;0;L;;;;;N;;;;; +13359;EGYPTIAN HIEROGLYPH U034;Lo;0;L;;;;;N;;;;; +1335A;EGYPTIAN HIEROGLYPH U035;Lo;0;L;;;;;N;;;;; +1335B;EGYPTIAN HIEROGLYPH U036;Lo;0;L;;;;;N;;;;; +1335C;EGYPTIAN HIEROGLYPH U037;Lo;0;L;;;;;N;;;;; +1335D;EGYPTIAN HIEROGLYPH U038;Lo;0;L;;;;;N;;;;; +1335E;EGYPTIAN HIEROGLYPH U039;Lo;0;L;;;;;N;;;;; +1335F;EGYPTIAN HIEROGLYPH U040;Lo;0;L;;;;;N;;;;; +13360;EGYPTIAN HIEROGLYPH U041;Lo;0;L;;;;;N;;;;; +13361;EGYPTIAN HIEROGLYPH U042;Lo;0;L;;;;;N;;;;; +13362;EGYPTIAN HIEROGLYPH V001;Lo;0;L;;;;;N;;;;; +13363;EGYPTIAN HIEROGLYPH V001A;Lo;0;L;;;;;N;;;;; +13364;EGYPTIAN HIEROGLYPH V001B;Lo;0;L;;;;;N;;;;; +13365;EGYPTIAN HIEROGLYPH V001C;Lo;0;L;;;;;N;;;;; +13366;EGYPTIAN HIEROGLYPH V001D;Lo;0;L;;;;;N;;;;; +13367;EGYPTIAN HIEROGLYPH V001E;Lo;0;L;;;;;N;;;;; +13368;EGYPTIAN HIEROGLYPH V001F;Lo;0;L;;;;;N;;;;; +13369;EGYPTIAN HIEROGLYPH V001G;Lo;0;L;;;;;N;;;;; +1336A;EGYPTIAN HIEROGLYPH V001H;Lo;0;L;;;;;N;;;;; +1336B;EGYPTIAN HIEROGLYPH V001I;Lo;0;L;;;;;N;;;;; +1336C;EGYPTIAN HIEROGLYPH V002;Lo;0;L;;;;;N;;;;; +1336D;EGYPTIAN HIEROGLYPH V002A;Lo;0;L;;;;;N;;;;; +1336E;EGYPTIAN HIEROGLYPH V003;Lo;0;L;;;;;N;;;;; +1336F;EGYPTIAN HIEROGLYPH V004;Lo;0;L;;;;;N;;;;; +13370;EGYPTIAN HIEROGLYPH V005;Lo;0;L;;;;;N;;;;; +13371;EGYPTIAN HIEROGLYPH V006;Lo;0;L;;;;;N;;;;; +13372;EGYPTIAN HIEROGLYPH V007;Lo;0;L;;;;;N;;;;; +13373;EGYPTIAN HIEROGLYPH V007A;Lo;0;L;;;;;N;;;;; +13374;EGYPTIAN HIEROGLYPH V007B;Lo;0;L;;;;;N;;;;; +13375;EGYPTIAN HIEROGLYPH V008;Lo;0;L;;;;;N;;;;; +13376;EGYPTIAN HIEROGLYPH V009;Lo;0;L;;;;;N;;;;; +13377;EGYPTIAN HIEROGLYPH V010;Lo;0;L;;;;;N;;;;; +13378;EGYPTIAN HIEROGLYPH V011;Lo;0;L;;;;;N;;;;; +13379;EGYPTIAN HIEROGLYPH V011A;Lo;0;L;;;;;N;;;;; +1337A;EGYPTIAN HIEROGLYPH V011B;Lo;0;L;;;;;N;;;;; +1337B;EGYPTIAN HIEROGLYPH V011C;Lo;0;L;;;;;N;;;;; +1337C;EGYPTIAN HIEROGLYPH V012;Lo;0;L;;;;;N;;;;; +1337D;EGYPTIAN HIEROGLYPH V012A;Lo;0;L;;;;;N;;;;; +1337E;EGYPTIAN HIEROGLYPH V012B;Lo;0;L;;;;;N;;;;; +1337F;EGYPTIAN HIEROGLYPH V013;Lo;0;L;;;;;N;;;;; +13380;EGYPTIAN HIEROGLYPH V014;Lo;0;L;;;;;N;;;;; +13381;EGYPTIAN HIEROGLYPH V015;Lo;0;L;;;;;N;;;;; +13382;EGYPTIAN HIEROGLYPH V016;Lo;0;L;;;;;N;;;;; +13383;EGYPTIAN HIEROGLYPH V017;Lo;0;L;;;;;N;;;;; +13384;EGYPTIAN HIEROGLYPH V018;Lo;0;L;;;;;N;;;;; +13385;EGYPTIAN HIEROGLYPH V019;Lo;0;L;;;;;N;;;;; +13386;EGYPTIAN HIEROGLYPH V020;Lo;0;L;;;;;N;;;;; +13387;EGYPTIAN HIEROGLYPH V020A;Lo;0;L;;;;;N;;;;; +13388;EGYPTIAN HIEROGLYPH V020B;Lo;0;L;;;;;N;;;;; +13389;EGYPTIAN HIEROGLYPH V020C;Lo;0;L;;;;;N;;;;; +1338A;EGYPTIAN HIEROGLYPH V020D;Lo;0;L;;;;;N;;;;; +1338B;EGYPTIAN HIEROGLYPH V020E;Lo;0;L;;;;;N;;;;; +1338C;EGYPTIAN HIEROGLYPH V020F;Lo;0;L;;;;;N;;;;; +1338D;EGYPTIAN HIEROGLYPH V020G;Lo;0;L;;;;;N;;;;; +1338E;EGYPTIAN HIEROGLYPH V020H;Lo;0;L;;;;;N;;;;; +1338F;EGYPTIAN HIEROGLYPH V020I;Lo;0;L;;;;;N;;;;; +13390;EGYPTIAN HIEROGLYPH V020J;Lo;0;L;;;;;N;;;;; +13391;EGYPTIAN HIEROGLYPH V020K;Lo;0;L;;;;;N;;;;; +13392;EGYPTIAN HIEROGLYPH V020L;Lo;0;L;;;;;N;;;;; +13393;EGYPTIAN HIEROGLYPH V021;Lo;0;L;;;;;N;;;;; +13394;EGYPTIAN HIEROGLYPH V022;Lo;0;L;;;;;N;;;;; +13395;EGYPTIAN HIEROGLYPH V023;Lo;0;L;;;;;N;;;;; +13396;EGYPTIAN HIEROGLYPH V023A;Lo;0;L;;;;;N;;;;; +13397;EGYPTIAN HIEROGLYPH V024;Lo;0;L;;;;;N;;;;; +13398;EGYPTIAN HIEROGLYPH V025;Lo;0;L;;;;;N;;;;; +13399;EGYPTIAN HIEROGLYPH V026;Lo;0;L;;;;;N;;;;; +1339A;EGYPTIAN HIEROGLYPH V027;Lo;0;L;;;;;N;;;;; +1339B;EGYPTIAN HIEROGLYPH V028;Lo;0;L;;;;;N;;;;; +1339C;EGYPTIAN HIEROGLYPH V028A;Lo;0;L;;;;;N;;;;; +1339D;EGYPTIAN HIEROGLYPH V029;Lo;0;L;;;;;N;;;;; +1339E;EGYPTIAN HIEROGLYPH V029A;Lo;0;L;;;;;N;;;;; +1339F;EGYPTIAN HIEROGLYPH V030;Lo;0;L;;;;;N;;;;; +133A0;EGYPTIAN HIEROGLYPH V030A;Lo;0;L;;;;;N;;;;; +133A1;EGYPTIAN HIEROGLYPH V031;Lo;0;L;;;;;N;;;;; +133A2;EGYPTIAN HIEROGLYPH V031A;Lo;0;L;;;;;N;;;;; +133A3;EGYPTIAN HIEROGLYPH V032;Lo;0;L;;;;;N;;;;; +133A4;EGYPTIAN HIEROGLYPH V033;Lo;0;L;;;;;N;;;;; +133A5;EGYPTIAN HIEROGLYPH V033A;Lo;0;L;;;;;N;;;;; +133A6;EGYPTIAN HIEROGLYPH V034;Lo;0;L;;;;;N;;;;; +133A7;EGYPTIAN HIEROGLYPH V035;Lo;0;L;;;;;N;;;;; +133A8;EGYPTIAN HIEROGLYPH V036;Lo;0;L;;;;;N;;;;; +133A9;EGYPTIAN HIEROGLYPH V037;Lo;0;L;;;;;N;;;;; +133AA;EGYPTIAN HIEROGLYPH V037A;Lo;0;L;;;;;N;;;;; +133AB;EGYPTIAN HIEROGLYPH V038;Lo;0;L;;;;;N;;;;; +133AC;EGYPTIAN HIEROGLYPH V039;Lo;0;L;;;;;N;;;;; +133AD;EGYPTIAN HIEROGLYPH V040;Lo;0;L;;;;;N;;;;; +133AE;EGYPTIAN HIEROGLYPH V040A;Lo;0;L;;;;;N;;;;; +133AF;EGYPTIAN HIEROGLYPH W001;Lo;0;L;;;;;N;;;;; +133B0;EGYPTIAN HIEROGLYPH W002;Lo;0;L;;;;;N;;;;; +133B1;EGYPTIAN HIEROGLYPH W003;Lo;0;L;;;;;N;;;;; +133B2;EGYPTIAN HIEROGLYPH W003A;Lo;0;L;;;;;N;;;;; +133B3;EGYPTIAN HIEROGLYPH W004;Lo;0;L;;;;;N;;;;; +133B4;EGYPTIAN HIEROGLYPH W005;Lo;0;L;;;;;N;;;;; +133B5;EGYPTIAN HIEROGLYPH W006;Lo;0;L;;;;;N;;;;; +133B6;EGYPTIAN HIEROGLYPH W007;Lo;0;L;;;;;N;;;;; +133B7;EGYPTIAN HIEROGLYPH W008;Lo;0;L;;;;;N;;;;; +133B8;EGYPTIAN HIEROGLYPH W009;Lo;0;L;;;;;N;;;;; +133B9;EGYPTIAN HIEROGLYPH W009A;Lo;0;L;;;;;N;;;;; +133BA;EGYPTIAN HIEROGLYPH W010;Lo;0;L;;;;;N;;;;; +133BB;EGYPTIAN HIEROGLYPH W010A;Lo;0;L;;;;;N;;;;; +133BC;EGYPTIAN HIEROGLYPH W011;Lo;0;L;;;;;N;;;;; +133BD;EGYPTIAN HIEROGLYPH W012;Lo;0;L;;;;;N;;;;; +133BE;EGYPTIAN HIEROGLYPH W013;Lo;0;L;;;;;N;;;;; +133BF;EGYPTIAN HIEROGLYPH W014;Lo;0;L;;;;;N;;;;; +133C0;EGYPTIAN HIEROGLYPH W014A;Lo;0;L;;;;;N;;;;; +133C1;EGYPTIAN HIEROGLYPH W015;Lo;0;L;;;;;N;;;;; +133C2;EGYPTIAN HIEROGLYPH W016;Lo;0;L;;;;;N;;;;; +133C3;EGYPTIAN HIEROGLYPH W017;Lo;0;L;;;;;N;;;;; +133C4;EGYPTIAN HIEROGLYPH W017A;Lo;0;L;;;;;N;;;;; +133C5;EGYPTIAN HIEROGLYPH W018;Lo;0;L;;;;;N;;;;; +133C6;EGYPTIAN HIEROGLYPH W018A;Lo;0;L;;;;;N;;;;; +133C7;EGYPTIAN HIEROGLYPH W019;Lo;0;L;;;;;N;;;;; +133C8;EGYPTIAN HIEROGLYPH W020;Lo;0;L;;;;;N;;;;; +133C9;EGYPTIAN HIEROGLYPH W021;Lo;0;L;;;;;N;;;;; +133CA;EGYPTIAN HIEROGLYPH W022;Lo;0;L;;;;;N;;;;; +133CB;EGYPTIAN HIEROGLYPH W023;Lo;0;L;;;;;N;;;;; +133CC;EGYPTIAN HIEROGLYPH W024;Lo;0;L;;;;;N;;;;; +133CD;EGYPTIAN HIEROGLYPH W024A;Lo;0;L;;;;;N;;;;; +133CE;EGYPTIAN HIEROGLYPH W025;Lo;0;L;;;;;N;;;;; +133CF;EGYPTIAN HIEROGLYPH X001;Lo;0;L;;;;;N;;;;; +133D0;EGYPTIAN HIEROGLYPH X002;Lo;0;L;;;;;N;;;;; +133D1;EGYPTIAN HIEROGLYPH X003;Lo;0;L;;;;;N;;;;; +133D2;EGYPTIAN HIEROGLYPH X004;Lo;0;L;;;;;N;;;;; +133D3;EGYPTIAN HIEROGLYPH X004A;Lo;0;L;;;;;N;;;;; +133D4;EGYPTIAN HIEROGLYPH X004B;Lo;0;L;;;;;N;;;;; +133D5;EGYPTIAN HIEROGLYPH X005;Lo;0;L;;;;;N;;;;; +133D6;EGYPTIAN HIEROGLYPH X006;Lo;0;L;;;;;N;;;;; +133D7;EGYPTIAN HIEROGLYPH X006A;Lo;0;L;;;;;N;;;;; +133D8;EGYPTIAN HIEROGLYPH X007;Lo;0;L;;;;;N;;;;; +133D9;EGYPTIAN HIEROGLYPH X008;Lo;0;L;;;;;N;;;;; +133DA;EGYPTIAN HIEROGLYPH X008A;Lo;0;L;;;;;N;;;;; +133DB;EGYPTIAN HIEROGLYPH Y001;Lo;0;L;;;;;N;;;;; +133DC;EGYPTIAN HIEROGLYPH Y001A;Lo;0;L;;;;;N;;;;; +133DD;EGYPTIAN HIEROGLYPH Y002;Lo;0;L;;;;;N;;;;; +133DE;EGYPTIAN HIEROGLYPH Y003;Lo;0;L;;;;;N;;;;; +133DF;EGYPTIAN HIEROGLYPH Y004;Lo;0;L;;;;;N;;;;; +133E0;EGYPTIAN HIEROGLYPH Y005;Lo;0;L;;;;;N;;;;; +133E1;EGYPTIAN HIEROGLYPH Y006;Lo;0;L;;;;;N;;;;; +133E2;EGYPTIAN HIEROGLYPH Y007;Lo;0;L;;;;;N;;;;; +133E3;EGYPTIAN HIEROGLYPH Y008;Lo;0;L;;;;;N;;;;; +133E4;EGYPTIAN HIEROGLYPH Z001;Lo;0;L;;;;;N;;;;; +133E5;EGYPTIAN HIEROGLYPH Z002;Lo;0;L;;;;;N;;;;; +133E6;EGYPTIAN HIEROGLYPH Z002A;Lo;0;L;;;;;N;;;;; +133E7;EGYPTIAN HIEROGLYPH Z002B;Lo;0;L;;;;;N;;;;; +133E8;EGYPTIAN HIEROGLYPH Z002C;Lo;0;L;;;;;N;;;;; +133E9;EGYPTIAN HIEROGLYPH Z002D;Lo;0;L;;;;;N;;;;; +133EA;EGYPTIAN HIEROGLYPH Z003;Lo;0;L;;;;;N;;;;; +133EB;EGYPTIAN HIEROGLYPH Z003A;Lo;0;L;;;;;N;;;;; +133EC;EGYPTIAN HIEROGLYPH Z003B;Lo;0;L;;;;;N;;;;; +133ED;EGYPTIAN HIEROGLYPH Z004;Lo;0;L;;;;;N;;;;; +133EE;EGYPTIAN HIEROGLYPH Z004A;Lo;0;L;;;;;N;;;;; +133EF;EGYPTIAN HIEROGLYPH Z005;Lo;0;L;;;;;N;;;;; +133F0;EGYPTIAN HIEROGLYPH Z005A;Lo;0;L;;;;;N;;;;; +133F1;EGYPTIAN HIEROGLYPH Z006;Lo;0;L;;;;;N;;;;; +133F2;EGYPTIAN HIEROGLYPH Z007;Lo;0;L;;;;;N;;;;; +133F3;EGYPTIAN HIEROGLYPH Z008;Lo;0;L;;;;;N;;;;; +133F4;EGYPTIAN HIEROGLYPH Z009;Lo;0;L;;;;;N;;;;; +133F5;EGYPTIAN HIEROGLYPH Z010;Lo;0;L;;;;;N;;;;; +133F6;EGYPTIAN HIEROGLYPH Z011;Lo;0;L;;;;;N;;;;; +133F7;EGYPTIAN HIEROGLYPH Z012;Lo;0;L;;;;;N;;;;; +133F8;EGYPTIAN HIEROGLYPH Z013;Lo;0;L;;;;;N;;;;; +133F9;EGYPTIAN HIEROGLYPH Z014;Lo;0;L;;;;;N;;;;; +133FA;EGYPTIAN HIEROGLYPH Z015;Lo;0;L;;;;;N;;;;; +133FB;EGYPTIAN HIEROGLYPH Z015A;Lo;0;L;;;;;N;;;;; +133FC;EGYPTIAN HIEROGLYPH Z015B;Lo;0;L;;;;;N;;;;; +133FD;EGYPTIAN HIEROGLYPH Z015C;Lo;0;L;;;;;N;;;;; +133FE;EGYPTIAN HIEROGLYPH Z015D;Lo;0;L;;;;;N;;;;; +133FF;EGYPTIAN HIEROGLYPH Z015E;Lo;0;L;;;;;N;;;;; +13400;EGYPTIAN HIEROGLYPH Z015F;Lo;0;L;;;;;N;;;;; +13401;EGYPTIAN HIEROGLYPH Z015G;Lo;0;L;;;;;N;;;;; +13402;EGYPTIAN HIEROGLYPH Z015H;Lo;0;L;;;;;N;;;;; +13403;EGYPTIAN HIEROGLYPH Z015I;Lo;0;L;;;;;N;;;;; +13404;EGYPTIAN HIEROGLYPH Z016;Lo;0;L;;;;;N;;;;; +13405;EGYPTIAN HIEROGLYPH Z016A;Lo;0;L;;;;;N;;;;; +13406;EGYPTIAN HIEROGLYPH Z016B;Lo;0;L;;;;;N;;;;; +13407;EGYPTIAN HIEROGLYPH Z016C;Lo;0;L;;;;;N;;;;; +13408;EGYPTIAN HIEROGLYPH Z016D;Lo;0;L;;;;;N;;;;; +13409;EGYPTIAN HIEROGLYPH Z016E;Lo;0;L;;;;;N;;;;; +1340A;EGYPTIAN HIEROGLYPH Z016F;Lo;0;L;;;;;N;;;;; +1340B;EGYPTIAN HIEROGLYPH Z016G;Lo;0;L;;;;;N;;;;; +1340C;EGYPTIAN HIEROGLYPH Z016H;Lo;0;L;;;;;N;;;;; +1340D;EGYPTIAN HIEROGLYPH AA001;Lo;0;L;;;;;N;;;;; +1340E;EGYPTIAN HIEROGLYPH AA002;Lo;0;L;;;;;N;;;;; +1340F;EGYPTIAN HIEROGLYPH AA003;Lo;0;L;;;;;N;;;;; +13410;EGYPTIAN HIEROGLYPH AA004;Lo;0;L;;;;;N;;;;; +13411;EGYPTIAN HIEROGLYPH AA005;Lo;0;L;;;;;N;;;;; +13412;EGYPTIAN HIEROGLYPH AA006;Lo;0;L;;;;;N;;;;; +13413;EGYPTIAN HIEROGLYPH AA007;Lo;0;L;;;;;N;;;;; +13414;EGYPTIAN HIEROGLYPH AA007A;Lo;0;L;;;;;N;;;;; +13415;EGYPTIAN HIEROGLYPH AA007B;Lo;0;L;;;;;N;;;;; +13416;EGYPTIAN HIEROGLYPH AA008;Lo;0;L;;;;;N;;;;; +13417;EGYPTIAN HIEROGLYPH AA009;Lo;0;L;;;;;N;;;;; +13418;EGYPTIAN HIEROGLYPH AA010;Lo;0;L;;;;;N;;;;; +13419;EGYPTIAN HIEROGLYPH AA011;Lo;0;L;;;;;N;;;;; +1341A;EGYPTIAN HIEROGLYPH AA012;Lo;0;L;;;;;N;;;;; +1341B;EGYPTIAN HIEROGLYPH AA013;Lo;0;L;;;;;N;;;;; +1341C;EGYPTIAN HIEROGLYPH AA014;Lo;0;L;;;;;N;;;;; +1341D;EGYPTIAN HIEROGLYPH AA015;Lo;0;L;;;;;N;;;;; +1341E;EGYPTIAN HIEROGLYPH AA016;Lo;0;L;;;;;N;;;;; +1341F;EGYPTIAN HIEROGLYPH AA017;Lo;0;L;;;;;N;;;;; +13420;EGYPTIAN HIEROGLYPH AA018;Lo;0;L;;;;;N;;;;; +13421;EGYPTIAN HIEROGLYPH AA019;Lo;0;L;;;;;N;;;;; +13422;EGYPTIAN HIEROGLYPH AA020;Lo;0;L;;;;;N;;;;; +13423;EGYPTIAN HIEROGLYPH AA021;Lo;0;L;;;;;N;;;;; +13424;EGYPTIAN HIEROGLYPH AA022;Lo;0;L;;;;;N;;;;; +13425;EGYPTIAN HIEROGLYPH AA023;Lo;0;L;;;;;N;;;;; +13426;EGYPTIAN HIEROGLYPH AA024;Lo;0;L;;;;;N;;;;; +13427;EGYPTIAN HIEROGLYPH AA025;Lo;0;L;;;;;N;;;;; +13428;EGYPTIAN HIEROGLYPH AA026;Lo;0;L;;;;;N;;;;; +13429;EGYPTIAN HIEROGLYPH AA027;Lo;0;L;;;;;N;;;;; +1342A;EGYPTIAN HIEROGLYPH AA028;Lo;0;L;;;;;N;;;;; +1342B;EGYPTIAN HIEROGLYPH AA029;Lo;0;L;;;;;N;;;;; +1342C;EGYPTIAN HIEROGLYPH AA030;Lo;0;L;;;;;N;;;;; +1342D;EGYPTIAN HIEROGLYPH AA031;Lo;0;L;;;;;N;;;;; +1342E;EGYPTIAN HIEROGLYPH AA032;Lo;0;L;;;;;N;;;;; +1342F;EGYPTIAN HIEROGLYPH V011D;Lo;0;L;;;;;N;;;;; +13430;EGYPTIAN HIEROGLYPH VERTICAL JOINER;Cf;0;L;;;;;N;;;;; +13431;EGYPTIAN HIEROGLYPH HORIZONTAL JOINER;Cf;0;L;;;;;N;;;;; +13432;EGYPTIAN HIEROGLYPH INSERT AT TOP START;Cf;0;L;;;;;N;;;;; +13433;EGYPTIAN HIEROGLYPH INSERT AT BOTTOM START;Cf;0;L;;;;;N;;;;; +13434;EGYPTIAN HIEROGLYPH INSERT AT TOP END;Cf;0;L;;;;;N;;;;; +13435;EGYPTIAN HIEROGLYPH INSERT AT BOTTOM END;Cf;0;L;;;;;N;;;;; +13436;EGYPTIAN HIEROGLYPH OVERLAY MIDDLE;Cf;0;L;;;;;N;;;;; +13437;EGYPTIAN HIEROGLYPH BEGIN SEGMENT;Cf;0;L;;;;;N;;;;; +13438;EGYPTIAN HIEROGLYPH END SEGMENT;Cf;0;L;;;;;N;;;;; +13439;EGYPTIAN HIEROGLYPH INSERT AT MIDDLE;Cf;0;L;;;;;N;;;;; +1343A;EGYPTIAN HIEROGLYPH INSERT AT TOP;Cf;0;L;;;;;N;;;;; +1343B;EGYPTIAN HIEROGLYPH INSERT AT BOTTOM;Cf;0;L;;;;;N;;;;; +1343C;EGYPTIAN HIEROGLYPH BEGIN ENCLOSURE;Cf;0;L;;;;;N;;;;; +1343D;EGYPTIAN HIEROGLYPH END ENCLOSURE;Cf;0;L;;;;;N;;;;; +1343E;EGYPTIAN HIEROGLYPH BEGIN WALLED ENCLOSURE;Cf;0;L;;;;;N;;;;; +1343F;EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE;Cf;0;L;;;;;N;;;;; +13440;EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY;Mn;0;NSM;;;;;N;;;;; +13441;EGYPTIAN HIEROGLYPH FULL BLANK;Lo;0;L;;;;;N;;;;; +13442;EGYPTIAN HIEROGLYPH HALF BLANK;Lo;0;L;;;;;N;;;;; +13443;EGYPTIAN HIEROGLYPH LOST SIGN;Lo;0;L;;;;;N;;;;; +13444;EGYPTIAN HIEROGLYPH HALF LOST SIGN;Lo;0;L;;;;;N;;;;; +13445;EGYPTIAN HIEROGLYPH TALL LOST SIGN;Lo;0;L;;;;;N;;;;; +13446;EGYPTIAN HIEROGLYPH WIDE LOST SIGN;Lo;0;L;;;;;N;;;;; +13447;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START;Mn;0;NSM;;;;;N;;;;; +13448;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM START;Mn;0;NSM;;;;;N;;;;; +13449;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT START;Mn;0;NSM;;;;;N;;;;; +1344A;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP END;Mn;0;NSM;;;;;N;;;;; +1344B;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP;Mn;0;NSM;;;;;N;;;;; +1344C;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM START AND TOP END;Mn;0;NSM;;;;;N;;;;; +1344D;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT START AND TOP;Mn;0;NSM;;;;;N;;;;; +1344E;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM END;Mn;0;NSM;;;;;N;;;;; +1344F;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START AND BOTTOM END;Mn;0;NSM;;;;;N;;;;; +13450;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM;Mn;0;NSM;;;;;N;;;;; +13451;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT START AND BOTTOM;Mn;0;NSM;;;;;N;;;;; +13452;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT END;Mn;0;NSM;;;;;N;;;;; +13453;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP AND END;Mn;0;NSM;;;;;N;;;;; +13454;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM AND END;Mn;0;NSM;;;;;N;;;;; +13455;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED;Mn;0;NSM;;;;;N;;;;; +13460;EGYPTIAN HIEROGLYPH-13460;Lo;0;L;;;;;N;;;;; +13461;EGYPTIAN HIEROGLYPH-13461;Lo;0;L;;;;;N;;;;; +13462;EGYPTIAN HIEROGLYPH-13462;Lo;0;L;;;;;N;;;;; +13463;EGYPTIAN HIEROGLYPH-13463;Lo;0;L;;;;;N;;;;; +13464;EGYPTIAN HIEROGLYPH-13464;Lo;0;L;;;;;N;;;;; +13465;EGYPTIAN HIEROGLYPH-13465;Lo;0;L;;;;;N;;;;; +13466;EGYPTIAN HIEROGLYPH-13466;Lo;0;L;;;;;N;;;;; +13467;EGYPTIAN HIEROGLYPH-13467;Lo;0;L;;;;;N;;;;; +13468;EGYPTIAN HIEROGLYPH-13468;Lo;0;L;;;;;N;;;;; +13469;EGYPTIAN HIEROGLYPH-13469;Lo;0;L;;;;;N;;;;; +1346A;EGYPTIAN HIEROGLYPH-1346A;Lo;0;L;;;;;N;;;;; +1346B;EGYPTIAN HIEROGLYPH-1346B;Lo;0;L;;;;;N;;;;; +1346C;EGYPTIAN HIEROGLYPH-1346C;Lo;0;L;;;;;N;;;;; +1346D;EGYPTIAN HIEROGLYPH-1346D;Lo;0;L;;;;;N;;;;; +1346E;EGYPTIAN HIEROGLYPH-1346E;Lo;0;L;;;;;N;;;;; +1346F;EGYPTIAN HIEROGLYPH-1346F;Lo;0;L;;;;;N;;;;; +13470;EGYPTIAN HIEROGLYPH-13470;Lo;0;L;;;;;N;;;;; +13471;EGYPTIAN HIEROGLYPH-13471;Lo;0;L;;;;;N;;;;; +13472;EGYPTIAN HIEROGLYPH-13472;Lo;0;L;;;;;N;;;;; +13473;EGYPTIAN HIEROGLYPH-13473;Lo;0;L;;;;;N;;;;; +13474;EGYPTIAN HIEROGLYPH-13474;Lo;0;L;;;;;N;;;;; +13475;EGYPTIAN HIEROGLYPH-13475;Lo;0;L;;;;;N;;;;; +13476;EGYPTIAN HIEROGLYPH-13476;Lo;0;L;;;;;N;;;;; +13477;EGYPTIAN HIEROGLYPH-13477;Lo;0;L;;;;;N;;;;; +13478;EGYPTIAN HIEROGLYPH-13478;Lo;0;L;;;;;N;;;;; +13479;EGYPTIAN HIEROGLYPH-13479;Lo;0;L;;;;;N;;;;; +1347A;EGYPTIAN HIEROGLYPH-1347A;Lo;0;L;;;;;N;;;;; +1347B;EGYPTIAN HIEROGLYPH-1347B;Lo;0;L;;;;;N;;;;; +1347C;EGYPTIAN HIEROGLYPH-1347C;Lo;0;L;;;;;N;;;;; +1347D;EGYPTIAN HIEROGLYPH-1347D;Lo;0;L;;;;;N;;;;; +1347E;EGYPTIAN HIEROGLYPH-1347E;Lo;0;L;;;;;N;;;;; +1347F;EGYPTIAN HIEROGLYPH-1347F;Lo;0;L;;;;;N;;;;; +13480;EGYPTIAN HIEROGLYPH-13480;Lo;0;L;;;;;N;;;;; +13481;EGYPTIAN HIEROGLYPH-13481;Lo;0;L;;;;;N;;;;; +13482;EGYPTIAN HIEROGLYPH-13482;Lo;0;L;;;;;N;;;;; +13483;EGYPTIAN HIEROGLYPH-13483;Lo;0;L;;;;;N;;;;; +13484;EGYPTIAN HIEROGLYPH-13484;Lo;0;L;;;;;N;;;;; +13485;EGYPTIAN HIEROGLYPH-13485;Lo;0;L;;;;;N;;;;; +13486;EGYPTIAN HIEROGLYPH-13486;Lo;0;L;;;;;N;;;;; +13487;EGYPTIAN HIEROGLYPH-13487;Lo;0;L;;;;;N;;;;; +13488;EGYPTIAN HIEROGLYPH-13488;Lo;0;L;;;;;N;;;;; +13489;EGYPTIAN HIEROGLYPH-13489;Lo;0;L;;;;;N;;;;; +1348A;EGYPTIAN HIEROGLYPH-1348A;Lo;0;L;;;;;N;;;;; +1348B;EGYPTIAN HIEROGLYPH-1348B;Lo;0;L;;;;;N;;;;; +1348C;EGYPTIAN HIEROGLYPH-1348C;Lo;0;L;;;;;N;;;;; +1348D;EGYPTIAN HIEROGLYPH-1348D;Lo;0;L;;;;;N;;;;; +1348E;EGYPTIAN HIEROGLYPH-1348E;Lo;0;L;;;;;N;;;;; +1348F;EGYPTIAN HIEROGLYPH-1348F;Lo;0;L;;;;;N;;;;; +13490;EGYPTIAN HIEROGLYPH-13490;Lo;0;L;;;;;N;;;;; +13491;EGYPTIAN HIEROGLYPH-13491;Lo;0;L;;;;;N;;;;; +13492;EGYPTIAN HIEROGLYPH-13492;Lo;0;L;;;;;N;;;;; +13493;EGYPTIAN HIEROGLYPH-13493;Lo;0;L;;;;;N;;;;; +13494;EGYPTIAN HIEROGLYPH-13494;Lo;0;L;;;;;N;;;;; +13495;EGYPTIAN HIEROGLYPH-13495;Lo;0;L;;;;;N;;;;; +13496;EGYPTIAN HIEROGLYPH-13496;Lo;0;L;;;;;N;;;;; +13497;EGYPTIAN HIEROGLYPH-13497;Lo;0;L;;;;;N;;;;; +13498;EGYPTIAN HIEROGLYPH-13498;Lo;0;L;;;;;N;;;;; +13499;EGYPTIAN HIEROGLYPH-13499;Lo;0;L;;;;;N;;;;; +1349A;EGYPTIAN HIEROGLYPH-1349A;Lo;0;L;;;;;N;;;;; +1349B;EGYPTIAN HIEROGLYPH-1349B;Lo;0;L;;;;;N;;;;; +1349C;EGYPTIAN HIEROGLYPH-1349C;Lo;0;L;;;;;N;;;;; +1349D;EGYPTIAN HIEROGLYPH-1349D;Lo;0;L;;;;;N;;;;; +1349E;EGYPTIAN HIEROGLYPH-1349E;Lo;0;L;;;;;N;;;;; +1349F;EGYPTIAN HIEROGLYPH-1349F;Lo;0;L;;;;;N;;;;; +134A0;EGYPTIAN HIEROGLYPH-134A0;Lo;0;L;;;;;N;;;;; +134A1;EGYPTIAN HIEROGLYPH-134A1;Lo;0;L;;;;;N;;;;; +134A2;EGYPTIAN HIEROGLYPH-134A2;Lo;0;L;;;;;N;;;;; +134A3;EGYPTIAN HIEROGLYPH-134A3;Lo;0;L;;;;;N;;;;; +134A4;EGYPTIAN HIEROGLYPH-134A4;Lo;0;L;;;;;N;;;;; +134A5;EGYPTIAN HIEROGLYPH-134A5;Lo;0;L;;;;;N;;;;; +134A6;EGYPTIAN HIEROGLYPH-134A6;Lo;0;L;;;;;N;;;;; +134A7;EGYPTIAN HIEROGLYPH-134A7;Lo;0;L;;;;;N;;;;; +134A8;EGYPTIAN HIEROGLYPH-134A8;Lo;0;L;;;;;N;;;;; +134A9;EGYPTIAN HIEROGLYPH-134A9;Lo;0;L;;;;;N;;;;; +134AA;EGYPTIAN HIEROGLYPH-134AA;Lo;0;L;;;;;N;;;;; +134AB;EGYPTIAN HIEROGLYPH-134AB;Lo;0;L;;;;;N;;;;; +134AC;EGYPTIAN HIEROGLYPH-134AC;Lo;0;L;;;;;N;;;;; +134AD;EGYPTIAN HIEROGLYPH-134AD;Lo;0;L;;;;;N;;;;; +134AE;EGYPTIAN HIEROGLYPH-134AE;Lo;0;L;;;;;N;;;;; +134AF;EGYPTIAN HIEROGLYPH-134AF;Lo;0;L;;;;;N;;;;; +134B0;EGYPTIAN HIEROGLYPH-134B0;Lo;0;L;;;;;N;;;;; +134B1;EGYPTIAN HIEROGLYPH-134B1;Lo;0;L;;;;;N;;;;; +134B2;EGYPTIAN HIEROGLYPH-134B2;Lo;0;L;;;;;N;;;;; +134B3;EGYPTIAN HIEROGLYPH-134B3;Lo;0;L;;;;;N;;;;; +134B4;EGYPTIAN HIEROGLYPH-134B4;Lo;0;L;;;;;N;;;;; +134B5;EGYPTIAN HIEROGLYPH-134B5;Lo;0;L;;;;;N;;;;; +134B6;EGYPTIAN HIEROGLYPH-134B6;Lo;0;L;;;;;N;;;;; +134B7;EGYPTIAN HIEROGLYPH-134B7;Lo;0;L;;;;;N;;;;; +134B8;EGYPTIAN HIEROGLYPH-134B8;Lo;0;L;;;;;N;;;;; +134B9;EGYPTIAN HIEROGLYPH-134B9;Lo;0;L;;;;;N;;;;; +134BA;EGYPTIAN HIEROGLYPH-134BA;Lo;0;L;;;;;N;;;;; +134BB;EGYPTIAN HIEROGLYPH-134BB;Lo;0;L;;;;;N;;;;; +134BC;EGYPTIAN HIEROGLYPH-134BC;Lo;0;L;;;;;N;;;;; +134BD;EGYPTIAN HIEROGLYPH-134BD;Lo;0;L;;;;;N;;;;; +134BE;EGYPTIAN HIEROGLYPH-134BE;Lo;0;L;;;;;N;;;;; +134BF;EGYPTIAN HIEROGLYPH-134BF;Lo;0;L;;;;;N;;;;; +134C0;EGYPTIAN HIEROGLYPH-134C0;Lo;0;L;;;;;N;;;;; +134C1;EGYPTIAN HIEROGLYPH-134C1;Lo;0;L;;;;;N;;;;; +134C2;EGYPTIAN HIEROGLYPH-134C2;Lo;0;L;;;;;N;;;;; +134C3;EGYPTIAN HIEROGLYPH-134C3;Lo;0;L;;;;;N;;;;; +134C4;EGYPTIAN HIEROGLYPH-134C4;Lo;0;L;;;;;N;;;;; +134C5;EGYPTIAN HIEROGLYPH-134C5;Lo;0;L;;;;;N;;;;; +134C6;EGYPTIAN HIEROGLYPH-134C6;Lo;0;L;;;;;N;;;;; +134C7;EGYPTIAN HIEROGLYPH-134C7;Lo;0;L;;;;;N;;;;; +134C8;EGYPTIAN HIEROGLYPH-134C8;Lo;0;L;;;;;N;;;;; +134C9;EGYPTIAN HIEROGLYPH-134C9;Lo;0;L;;;;;N;;;;; +134CA;EGYPTIAN HIEROGLYPH-134CA;Lo;0;L;;;;;N;;;;; +134CB;EGYPTIAN HIEROGLYPH-134CB;Lo;0;L;;;;;N;;;;; +134CC;EGYPTIAN HIEROGLYPH-134CC;Lo;0;L;;;;;N;;;;; +134CD;EGYPTIAN HIEROGLYPH-134CD;Lo;0;L;;;;;N;;;;; +134CE;EGYPTIAN HIEROGLYPH-134CE;Lo;0;L;;;;;N;;;;; +134CF;EGYPTIAN HIEROGLYPH-134CF;Lo;0;L;;;;;N;;;;; +134D0;EGYPTIAN HIEROGLYPH-134D0;Lo;0;L;;;;;N;;;;; +134D1;EGYPTIAN HIEROGLYPH-134D1;Lo;0;L;;;;;N;;;;; +134D2;EGYPTIAN HIEROGLYPH-134D2;Lo;0;L;;;;;N;;;;; +134D3;EGYPTIAN HIEROGLYPH-134D3;Lo;0;L;;;;;N;;;;; +134D4;EGYPTIAN HIEROGLYPH-134D4;Lo;0;L;;;;;N;;;;; +134D5;EGYPTIAN HIEROGLYPH-134D5;Lo;0;L;;;;;N;;;;; +134D6;EGYPTIAN HIEROGLYPH-134D6;Lo;0;L;;;;;N;;;;; +134D7;EGYPTIAN HIEROGLYPH-134D7;Lo;0;L;;;;;N;;;;; +134D8;EGYPTIAN HIEROGLYPH-134D8;Lo;0;L;;;;;N;;;;; +134D9;EGYPTIAN HIEROGLYPH-134D9;Lo;0;L;;;;;N;;;;; +134DA;EGYPTIAN HIEROGLYPH-134DA;Lo;0;L;;;;;N;;;;; +134DB;EGYPTIAN HIEROGLYPH-134DB;Lo;0;L;;;;;N;;;;; +134DC;EGYPTIAN HIEROGLYPH-134DC;Lo;0;L;;;;;N;;;;; +134DD;EGYPTIAN HIEROGLYPH-134DD;Lo;0;L;;;;;N;;;;; +134DE;EGYPTIAN HIEROGLYPH-134DE;Lo;0;L;;;;;N;;;;; +134DF;EGYPTIAN HIEROGLYPH-134DF;Lo;0;L;;;;;N;;;;; +134E0;EGYPTIAN HIEROGLYPH-134E0;Lo;0;L;;;;;N;;;;; +134E1;EGYPTIAN HIEROGLYPH-134E1;Lo;0;L;;;;;N;;;;; +134E2;EGYPTIAN HIEROGLYPH-134E2;Lo;0;L;;;;;N;;;;; +134E3;EGYPTIAN HIEROGLYPH-134E3;Lo;0;L;;;;;N;;;;; +134E4;EGYPTIAN HIEROGLYPH-134E4;Lo;0;L;;;;;N;;;;; +134E5;EGYPTIAN HIEROGLYPH-134E5;Lo;0;L;;;;;N;;;;; +134E6;EGYPTIAN HIEROGLYPH-134E6;Lo;0;L;;;;;N;;;;; +134E7;EGYPTIAN HIEROGLYPH-134E7;Lo;0;L;;;;;N;;;;; +134E8;EGYPTIAN HIEROGLYPH-134E8;Lo;0;L;;;;;N;;;;; +134E9;EGYPTIAN HIEROGLYPH-134E9;Lo;0;L;;;;;N;;;;; +134EA;EGYPTIAN HIEROGLYPH-134EA;Lo;0;L;;;;;N;;;;; +134EB;EGYPTIAN HIEROGLYPH-134EB;Lo;0;L;;;;;N;;;;; +134EC;EGYPTIAN HIEROGLYPH-134EC;Lo;0;L;;;;;N;;;;; +134ED;EGYPTIAN HIEROGLYPH-134ED;Lo;0;L;;;;;N;;;;; +134EE;EGYPTIAN HIEROGLYPH-134EE;Lo;0;L;;;;;N;;;;; +134EF;EGYPTIAN HIEROGLYPH-134EF;Lo;0;L;;;;;N;;;;; +134F0;EGYPTIAN HIEROGLYPH-134F0;Lo;0;L;;;;;N;;;;; +134F1;EGYPTIAN HIEROGLYPH-134F1;Lo;0;L;;;;;N;;;;; +134F2;EGYPTIAN HIEROGLYPH-134F2;Lo;0;L;;;;;N;;;;; +134F3;EGYPTIAN HIEROGLYPH-134F3;Lo;0;L;;;;;N;;;;; +134F4;EGYPTIAN HIEROGLYPH-134F4;Lo;0;L;;;;;N;;;;; +134F5;EGYPTIAN HIEROGLYPH-134F5;Lo;0;L;;;;;N;;;;; +134F6;EGYPTIAN HIEROGLYPH-134F6;Lo;0;L;;;;;N;;;;; +134F7;EGYPTIAN HIEROGLYPH-134F7;Lo;0;L;;;;;N;;;;; +134F8;EGYPTIAN HIEROGLYPH-134F8;Lo;0;L;;;;;N;;;;; +134F9;EGYPTIAN HIEROGLYPH-134F9;Lo;0;L;;;;;N;;;;; +134FA;EGYPTIAN HIEROGLYPH-134FA;Lo;0;L;;;;;N;;;;; +134FB;EGYPTIAN HIEROGLYPH-134FB;Lo;0;L;;;;;N;;;;; +134FC;EGYPTIAN HIEROGLYPH-134FC;Lo;0;L;;;;;N;;;;; +134FD;EGYPTIAN HIEROGLYPH-134FD;Lo;0;L;;;;;N;;;;; +134FE;EGYPTIAN HIEROGLYPH-134FE;Lo;0;L;;;;;N;;;;; +134FF;EGYPTIAN HIEROGLYPH-134FF;Lo;0;L;;;;;N;;;;; +13500;EGYPTIAN HIEROGLYPH-13500;Lo;0;L;;;;;N;;;;; +13501;EGYPTIAN HIEROGLYPH-13501;Lo;0;L;;;;;N;;;;; +13502;EGYPTIAN HIEROGLYPH-13502;Lo;0;L;;;;;N;;;;; +13503;EGYPTIAN HIEROGLYPH-13503;Lo;0;L;;;;;N;;;;; +13504;EGYPTIAN HIEROGLYPH-13504;Lo;0;L;;;;;N;;;;; +13505;EGYPTIAN HIEROGLYPH-13505;Lo;0;L;;;;;N;;;;; +13506;EGYPTIAN HIEROGLYPH-13506;Lo;0;L;;;;;N;;;;; +13507;EGYPTIAN HIEROGLYPH-13507;Lo;0;L;;;;;N;;;;; +13508;EGYPTIAN HIEROGLYPH-13508;Lo;0;L;;;;;N;;;;; +13509;EGYPTIAN HIEROGLYPH-13509;Lo;0;L;;;;;N;;;;; +1350A;EGYPTIAN HIEROGLYPH-1350A;Lo;0;L;;;;;N;;;;; +1350B;EGYPTIAN HIEROGLYPH-1350B;Lo;0;L;;;;;N;;;;; +1350C;EGYPTIAN HIEROGLYPH-1350C;Lo;0;L;;;;;N;;;;; +1350D;EGYPTIAN HIEROGLYPH-1350D;Lo;0;L;;;;;N;;;;; +1350E;EGYPTIAN HIEROGLYPH-1350E;Lo;0;L;;;;;N;;;;; +1350F;EGYPTIAN HIEROGLYPH-1350F;Lo;0;L;;;;;N;;;;; +13510;EGYPTIAN HIEROGLYPH-13510;Lo;0;L;;;;;N;;;;; +13511;EGYPTIAN HIEROGLYPH-13511;Lo;0;L;;;;;N;;;;; +13512;EGYPTIAN HIEROGLYPH-13512;Lo;0;L;;;;;N;;;;; +13513;EGYPTIAN HIEROGLYPH-13513;Lo;0;L;;;;;N;;;;; +13514;EGYPTIAN HIEROGLYPH-13514;Lo;0;L;;;;;N;;;;; +13515;EGYPTIAN HIEROGLYPH-13515;Lo;0;L;;;;;N;;;;; +13516;EGYPTIAN HIEROGLYPH-13516;Lo;0;L;;;;;N;;;;; +13517;EGYPTIAN HIEROGLYPH-13517;Lo;0;L;;;;;N;;;;; +13518;EGYPTIAN HIEROGLYPH-13518;Lo;0;L;;;;;N;;;;; +13519;EGYPTIAN HIEROGLYPH-13519;Lo;0;L;;;;;N;;;;; +1351A;EGYPTIAN HIEROGLYPH-1351A;Lo;0;L;;;;;N;;;;; +1351B;EGYPTIAN HIEROGLYPH-1351B;Lo;0;L;;;;;N;;;;; +1351C;EGYPTIAN HIEROGLYPH-1351C;Lo;0;L;;;;;N;;;;; +1351D;EGYPTIAN HIEROGLYPH-1351D;Lo;0;L;;;;;N;;;;; +1351E;EGYPTIAN HIEROGLYPH-1351E;Lo;0;L;;;;;N;;;;; +1351F;EGYPTIAN HIEROGLYPH-1351F;Lo;0;L;;;;;N;;;;; +13520;EGYPTIAN HIEROGLYPH-13520;Lo;0;L;;;;;N;;;;; +13521;EGYPTIAN HIEROGLYPH-13521;Lo;0;L;;;;;N;;;;; +13522;EGYPTIAN HIEROGLYPH-13522;Lo;0;L;;;;;N;;;;; +13523;EGYPTIAN HIEROGLYPH-13523;Lo;0;L;;;;;N;;;;; +13524;EGYPTIAN HIEROGLYPH-13524;Lo;0;L;;;;;N;;;;; +13525;EGYPTIAN HIEROGLYPH-13525;Lo;0;L;;;;;N;;;;; +13526;EGYPTIAN HIEROGLYPH-13526;Lo;0;L;;;;;N;;;;; +13527;EGYPTIAN HIEROGLYPH-13527;Lo;0;L;;;;;N;;;;; +13528;EGYPTIAN HIEROGLYPH-13528;Lo;0;L;;;;;N;;;;; +13529;EGYPTIAN HIEROGLYPH-13529;Lo;0;L;;;;;N;;;;; +1352A;EGYPTIAN HIEROGLYPH-1352A;Lo;0;L;;;;;N;;;;; +1352B;EGYPTIAN HIEROGLYPH-1352B;Lo;0;L;;;;;N;;;;; +1352C;EGYPTIAN HIEROGLYPH-1352C;Lo;0;L;;;;;N;;;;; +1352D;EGYPTIAN HIEROGLYPH-1352D;Lo;0;L;;;;;N;;;;; +1352E;EGYPTIAN HIEROGLYPH-1352E;Lo;0;L;;;;;N;;;;; +1352F;EGYPTIAN HIEROGLYPH-1352F;Lo;0;L;;;;;N;;;;; +13530;EGYPTIAN HIEROGLYPH-13530;Lo;0;L;;;;;N;;;;; +13531;EGYPTIAN HIEROGLYPH-13531;Lo;0;L;;;;;N;;;;; +13532;EGYPTIAN HIEROGLYPH-13532;Lo;0;L;;;;;N;;;;; +13533;EGYPTIAN HIEROGLYPH-13533;Lo;0;L;;;;;N;;;;; +13534;EGYPTIAN HIEROGLYPH-13534;Lo;0;L;;;;;N;;;;; +13535;EGYPTIAN HIEROGLYPH-13535;Lo;0;L;;;;;N;;;;; +13536;EGYPTIAN HIEROGLYPH-13536;Lo;0;L;;;;;N;;;;; +13537;EGYPTIAN HIEROGLYPH-13537;Lo;0;L;;;;;N;;;;; +13538;EGYPTIAN HIEROGLYPH-13538;Lo;0;L;;;;;N;;;;; +13539;EGYPTIAN HIEROGLYPH-13539;Lo;0;L;;;;;N;;;;; +1353A;EGYPTIAN HIEROGLYPH-1353A;Lo;0;L;;;;;N;;;;; +1353B;EGYPTIAN HIEROGLYPH-1353B;Lo;0;L;;;;;N;;;;; +1353C;EGYPTIAN HIEROGLYPH-1353C;Lo;0;L;;;;;N;;;;; +1353D;EGYPTIAN HIEROGLYPH-1353D;Lo;0;L;;;;;N;;;;; +1353E;EGYPTIAN HIEROGLYPH-1353E;Lo;0;L;;;;;N;;;;; +1353F;EGYPTIAN HIEROGLYPH-1353F;Lo;0;L;;;;;N;;;;; +13540;EGYPTIAN HIEROGLYPH-13540;Lo;0;L;;;;;N;;;;; +13541;EGYPTIAN HIEROGLYPH-13541;Lo;0;L;;;;;N;;;;; +13542;EGYPTIAN HIEROGLYPH-13542;Lo;0;L;;;;;N;;;;; +13543;EGYPTIAN HIEROGLYPH-13543;Lo;0;L;;;;;N;;;;; +13544;EGYPTIAN HIEROGLYPH-13544;Lo;0;L;;;;;N;;;;; +13545;EGYPTIAN HIEROGLYPH-13545;Lo;0;L;;;;;N;;;;; +13546;EGYPTIAN HIEROGLYPH-13546;Lo;0;L;;;;;N;;;;; +13547;EGYPTIAN HIEROGLYPH-13547;Lo;0;L;;;;;N;;;;; +13548;EGYPTIAN HIEROGLYPH-13548;Lo;0;L;;;;;N;;;;; +13549;EGYPTIAN HIEROGLYPH-13549;Lo;0;L;;;;;N;;;;; +1354A;EGYPTIAN HIEROGLYPH-1354A;Lo;0;L;;;;;N;;;;; +1354B;EGYPTIAN HIEROGLYPH-1354B;Lo;0;L;;;;;N;;;;; +1354C;EGYPTIAN HIEROGLYPH-1354C;Lo;0;L;;;;;N;;;;; +1354D;EGYPTIAN HIEROGLYPH-1354D;Lo;0;L;;;;;N;;;;; +1354E;EGYPTIAN HIEROGLYPH-1354E;Lo;0;L;;;;;N;;;;; +1354F;EGYPTIAN HIEROGLYPH-1354F;Lo;0;L;;;;;N;;;;; +13550;EGYPTIAN HIEROGLYPH-13550;Lo;0;L;;;;;N;;;;; +13551;EGYPTIAN HIEROGLYPH-13551;Lo;0;L;;;;;N;;;;; +13552;EGYPTIAN HIEROGLYPH-13552;Lo;0;L;;;;;N;;;;; +13553;EGYPTIAN HIEROGLYPH-13553;Lo;0;L;;;;;N;;;;; +13554;EGYPTIAN HIEROGLYPH-13554;Lo;0;L;;;;;N;;;;; +13555;EGYPTIAN HIEROGLYPH-13555;Lo;0;L;;;;;N;;;;; +13556;EGYPTIAN HIEROGLYPH-13556;Lo;0;L;;;;;N;;;;; +13557;EGYPTIAN HIEROGLYPH-13557;Lo;0;L;;;;;N;;;;; +13558;EGYPTIAN HIEROGLYPH-13558;Lo;0;L;;;;;N;;;;; +13559;EGYPTIAN HIEROGLYPH-13559;Lo;0;L;;;;;N;;;;; +1355A;EGYPTIAN HIEROGLYPH-1355A;Lo;0;L;;;;;N;;;;; +1355B;EGYPTIAN HIEROGLYPH-1355B;Lo;0;L;;;;;N;;;;; +1355C;EGYPTIAN HIEROGLYPH-1355C;Lo;0;L;;;;;N;;;;; +1355D;EGYPTIAN HIEROGLYPH-1355D;Lo;0;L;;;;;N;;;;; +1355E;EGYPTIAN HIEROGLYPH-1355E;Lo;0;L;;;;;N;;;;; +1355F;EGYPTIAN HIEROGLYPH-1355F;Lo;0;L;;;;;N;;;;; +13560;EGYPTIAN HIEROGLYPH-13560;Lo;0;L;;;;;N;;;;; +13561;EGYPTIAN HIEROGLYPH-13561;Lo;0;L;;;;;N;;;;; +13562;EGYPTIAN HIEROGLYPH-13562;Lo;0;L;;;;;N;;;;; +13563;EGYPTIAN HIEROGLYPH-13563;Lo;0;L;;;;;N;;;;; +13564;EGYPTIAN HIEROGLYPH-13564;Lo;0;L;;;;;N;;;;; +13565;EGYPTIAN HIEROGLYPH-13565;Lo;0;L;;;;;N;;;;; +13566;EGYPTIAN HIEROGLYPH-13566;Lo;0;L;;;;;N;;;;; +13567;EGYPTIAN HIEROGLYPH-13567;Lo;0;L;;;;;N;;;;; +13568;EGYPTIAN HIEROGLYPH-13568;Lo;0;L;;;;;N;;;;; +13569;EGYPTIAN HIEROGLYPH-13569;Lo;0;L;;;;;N;;;;; +1356A;EGYPTIAN HIEROGLYPH-1356A;Lo;0;L;;;;;N;;;;; +1356B;EGYPTIAN HIEROGLYPH-1356B;Lo;0;L;;;;;N;;;;; +1356C;EGYPTIAN HIEROGLYPH-1356C;Lo;0;L;;;;;N;;;;; +1356D;EGYPTIAN HIEROGLYPH-1356D;Lo;0;L;;;;;N;;;;; +1356E;EGYPTIAN HIEROGLYPH-1356E;Lo;0;L;;;;;N;;;;; +1356F;EGYPTIAN HIEROGLYPH-1356F;Lo;0;L;;;;;N;;;;; +13570;EGYPTIAN HIEROGLYPH-13570;Lo;0;L;;;;;N;;;;; +13571;EGYPTIAN HIEROGLYPH-13571;Lo;0;L;;;;;N;;;;; +13572;EGYPTIAN HIEROGLYPH-13572;Lo;0;L;;;;;N;;;;; +13573;EGYPTIAN HIEROGLYPH-13573;Lo;0;L;;;;;N;;;;; +13574;EGYPTIAN HIEROGLYPH-13574;Lo;0;L;;;;;N;;;;; +13575;EGYPTIAN HIEROGLYPH-13575;Lo;0;L;;;;;N;;;;; +13576;EGYPTIAN HIEROGLYPH-13576;Lo;0;L;;;;;N;;;;; +13577;EGYPTIAN HIEROGLYPH-13577;Lo;0;L;;;;;N;;;;; +13578;EGYPTIAN HIEROGLYPH-13578;Lo;0;L;;;;;N;;;;; +13579;EGYPTIAN HIEROGLYPH-13579;Lo;0;L;;;;;N;;;;; +1357A;EGYPTIAN HIEROGLYPH-1357A;Lo;0;L;;;;;N;;;;; +1357B;EGYPTIAN HIEROGLYPH-1357B;Lo;0;L;;;;;N;;;;; +1357C;EGYPTIAN HIEROGLYPH-1357C;Lo;0;L;;;;;N;;;;; +1357D;EGYPTIAN HIEROGLYPH-1357D;Lo;0;L;;;;;N;;;;; +1357E;EGYPTIAN HIEROGLYPH-1357E;Lo;0;L;;;;;N;;;;; +1357F;EGYPTIAN HIEROGLYPH-1357F;Lo;0;L;;;;;N;;;;; +13580;EGYPTIAN HIEROGLYPH-13580;Lo;0;L;;;;;N;;;;; +13581;EGYPTIAN HIEROGLYPH-13581;Lo;0;L;;;;;N;;;;; +13582;EGYPTIAN HIEROGLYPH-13582;Lo;0;L;;;;;N;;;;; +13583;EGYPTIAN HIEROGLYPH-13583;Lo;0;L;;;;;N;;;;; +13584;EGYPTIAN HIEROGLYPH-13584;Lo;0;L;;;;;N;;;;; +13585;EGYPTIAN HIEROGLYPH-13585;Lo;0;L;;;;;N;;;;; +13586;EGYPTIAN HIEROGLYPH-13586;Lo;0;L;;;;;N;;;;; +13587;EGYPTIAN HIEROGLYPH-13587;Lo;0;L;;;;;N;;;;; +13588;EGYPTIAN HIEROGLYPH-13588;Lo;0;L;;;;;N;;;;; +13589;EGYPTIAN HIEROGLYPH-13589;Lo;0;L;;;;;N;;;;; +1358A;EGYPTIAN HIEROGLYPH-1358A;Lo;0;L;;;;;N;;;;; +1358B;EGYPTIAN HIEROGLYPH-1358B;Lo;0;L;;;;;N;;;;; +1358C;EGYPTIAN HIEROGLYPH-1358C;Lo;0;L;;;;;N;;;;; +1358D;EGYPTIAN HIEROGLYPH-1358D;Lo;0;L;;;;;N;;;;; +1358E;EGYPTIAN HIEROGLYPH-1358E;Lo;0;L;;;;;N;;;;; +1358F;EGYPTIAN HIEROGLYPH-1358F;Lo;0;L;;;;;N;;;;; +13590;EGYPTIAN HIEROGLYPH-13590;Lo;0;L;;;;;N;;;;; +13591;EGYPTIAN HIEROGLYPH-13591;Lo;0;L;;;;;N;;;;; +13592;EGYPTIAN HIEROGLYPH-13592;Lo;0;L;;;;;N;;;;; +13593;EGYPTIAN HIEROGLYPH-13593;Lo;0;L;;;;;N;;;;; +13594;EGYPTIAN HIEROGLYPH-13594;Lo;0;L;;;;;N;;;;; +13595;EGYPTIAN HIEROGLYPH-13595;Lo;0;L;;;;;N;;;;; +13596;EGYPTIAN HIEROGLYPH-13596;Lo;0;L;;;;;N;;;;; +13597;EGYPTIAN HIEROGLYPH-13597;Lo;0;L;;;;;N;;;;; +13598;EGYPTIAN HIEROGLYPH-13598;Lo;0;L;;;;;N;;;;; +13599;EGYPTIAN HIEROGLYPH-13599;Lo;0;L;;;;;N;;;;; +1359A;EGYPTIAN HIEROGLYPH-1359A;Lo;0;L;;;;;N;;;;; +1359B;EGYPTIAN HIEROGLYPH-1359B;Lo;0;L;;;;;N;;;;; +1359C;EGYPTIAN HIEROGLYPH-1359C;Lo;0;L;;;;;N;;;;; +1359D;EGYPTIAN HIEROGLYPH-1359D;Lo;0;L;;;;;N;;;;; +1359E;EGYPTIAN HIEROGLYPH-1359E;Lo;0;L;;;;;N;;;;; +1359F;EGYPTIAN HIEROGLYPH-1359F;Lo;0;L;;;;;N;;;;; +135A0;EGYPTIAN HIEROGLYPH-135A0;Lo;0;L;;;;;N;;;;; +135A1;EGYPTIAN HIEROGLYPH-135A1;Lo;0;L;;;;;N;;;;; +135A2;EGYPTIAN HIEROGLYPH-135A2;Lo;0;L;;;;;N;;;;; +135A3;EGYPTIAN HIEROGLYPH-135A3;Lo;0;L;;;;;N;;;;; +135A4;EGYPTIAN HIEROGLYPH-135A4;Lo;0;L;;;;;N;;;;; +135A5;EGYPTIAN HIEROGLYPH-135A5;Lo;0;L;;;;;N;;;;; +135A6;EGYPTIAN HIEROGLYPH-135A6;Lo;0;L;;;;;N;;;;; +135A7;EGYPTIAN HIEROGLYPH-135A7;Lo;0;L;;;;;N;;;;; +135A8;EGYPTIAN HIEROGLYPH-135A8;Lo;0;L;;;;;N;;;;; +135A9;EGYPTIAN HIEROGLYPH-135A9;Lo;0;L;;;;;N;;;;; +135AA;EGYPTIAN HIEROGLYPH-135AA;Lo;0;L;;;;;N;;;;; +135AB;EGYPTIAN HIEROGLYPH-135AB;Lo;0;L;;;;;N;;;;; +135AC;EGYPTIAN HIEROGLYPH-135AC;Lo;0;L;;;;;N;;;;; +135AD;EGYPTIAN HIEROGLYPH-135AD;Lo;0;L;;;;;N;;;;; +135AE;EGYPTIAN HIEROGLYPH-135AE;Lo;0;L;;;;;N;;;;; +135AF;EGYPTIAN HIEROGLYPH-135AF;Lo;0;L;;;;;N;;;;; +135B0;EGYPTIAN HIEROGLYPH-135B0;Lo;0;L;;;;;N;;;;; +135B1;EGYPTIAN HIEROGLYPH-135B1;Lo;0;L;;;;;N;;;;; +135B2;EGYPTIAN HIEROGLYPH-135B2;Lo;0;L;;;;;N;;;;; +135B3;EGYPTIAN HIEROGLYPH-135B3;Lo;0;L;;;;;N;;;;; +135B4;EGYPTIAN HIEROGLYPH-135B4;Lo;0;L;;;;;N;;;;; +135B5;EGYPTIAN HIEROGLYPH-135B5;Lo;0;L;;;;;N;;;;; +135B6;EGYPTIAN HIEROGLYPH-135B6;Lo;0;L;;;;;N;;;;; +135B7;EGYPTIAN HIEROGLYPH-135B7;Lo;0;L;;;;;N;;;;; +135B8;EGYPTIAN HIEROGLYPH-135B8;Lo;0;L;;;;;N;;;;; +135B9;EGYPTIAN HIEROGLYPH-135B9;Lo;0;L;;;;;N;;;;; +135BA;EGYPTIAN HIEROGLYPH-135BA;Lo;0;L;;;;;N;;;;; +135BB;EGYPTIAN HIEROGLYPH-135BB;Lo;0;L;;;;;N;;;;; +135BC;EGYPTIAN HIEROGLYPH-135BC;Lo;0;L;;;;;N;;;;; +135BD;EGYPTIAN HIEROGLYPH-135BD;Lo;0;L;;;;;N;;;;; +135BE;EGYPTIAN HIEROGLYPH-135BE;Lo;0;L;;;;;N;;;;; +135BF;EGYPTIAN HIEROGLYPH-135BF;Lo;0;L;;;;;N;;;;; +135C0;EGYPTIAN HIEROGLYPH-135C0;Lo;0;L;;;;;N;;;;; +135C1;EGYPTIAN HIEROGLYPH-135C1;Lo;0;L;;;;;N;;;;; +135C2;EGYPTIAN HIEROGLYPH-135C2;Lo;0;L;;;;;N;;;;; +135C3;EGYPTIAN HIEROGLYPH-135C3;Lo;0;L;;;;;N;;;;; +135C4;EGYPTIAN HIEROGLYPH-135C4;Lo;0;L;;;;;N;;;;; +135C5;EGYPTIAN HIEROGLYPH-135C5;Lo;0;L;;;;;N;;;;; +135C6;EGYPTIAN HIEROGLYPH-135C6;Lo;0;L;;;;;N;;;;; +135C7;EGYPTIAN HIEROGLYPH-135C7;Lo;0;L;;;;;N;;;;; +135C8;EGYPTIAN HIEROGLYPH-135C8;Lo;0;L;;;;;N;;;;; +135C9;EGYPTIAN HIEROGLYPH-135C9;Lo;0;L;;;;;N;;;;; +135CA;EGYPTIAN HIEROGLYPH-135CA;Lo;0;L;;;;;N;;;;; +135CB;EGYPTIAN HIEROGLYPH-135CB;Lo;0;L;;;;;N;;;;; +135CC;EGYPTIAN HIEROGLYPH-135CC;Lo;0;L;;;;;N;;;;; +135CD;EGYPTIAN HIEROGLYPH-135CD;Lo;0;L;;;;;N;;;;; +135CE;EGYPTIAN HIEROGLYPH-135CE;Lo;0;L;;;;;N;;;;; +135CF;EGYPTIAN HIEROGLYPH-135CF;Lo;0;L;;;;;N;;;;; +135D0;EGYPTIAN HIEROGLYPH-135D0;Lo;0;L;;;;;N;;;;; +135D1;EGYPTIAN HIEROGLYPH-135D1;Lo;0;L;;;;;N;;;;; +135D2;EGYPTIAN HIEROGLYPH-135D2;Lo;0;L;;;;;N;;;;; +135D3;EGYPTIAN HIEROGLYPH-135D3;Lo;0;L;;;;;N;;;;; +135D4;EGYPTIAN HIEROGLYPH-135D4;Lo;0;L;;;;;N;;;;; +135D5;EGYPTIAN HIEROGLYPH-135D5;Lo;0;L;;;;;N;;;;; +135D6;EGYPTIAN HIEROGLYPH-135D6;Lo;0;L;;;;;N;;;;; +135D7;EGYPTIAN HIEROGLYPH-135D7;Lo;0;L;;;;;N;;;;; +135D8;EGYPTIAN HIEROGLYPH-135D8;Lo;0;L;;;;;N;;;;; +135D9;EGYPTIAN HIEROGLYPH-135D9;Lo;0;L;;;;;N;;;;; +135DA;EGYPTIAN HIEROGLYPH-135DA;Lo;0;L;;;;;N;;;;; +135DB;EGYPTIAN HIEROGLYPH-135DB;Lo;0;L;;;;;N;;;;; +135DC;EGYPTIAN HIEROGLYPH-135DC;Lo;0;L;;;;;N;;;;; +135DD;EGYPTIAN HIEROGLYPH-135DD;Lo;0;L;;;;;N;;;;; +135DE;EGYPTIAN HIEROGLYPH-135DE;Lo;0;L;;;;;N;;;;; +135DF;EGYPTIAN HIEROGLYPH-135DF;Lo;0;L;;;;;N;;;;; +135E0;EGYPTIAN HIEROGLYPH-135E0;Lo;0;L;;;;;N;;;;; +135E1;EGYPTIAN HIEROGLYPH-135E1;Lo;0;L;;;;;N;;;;; +135E2;EGYPTIAN HIEROGLYPH-135E2;Lo;0;L;;;;;N;;;;; +135E3;EGYPTIAN HIEROGLYPH-135E3;Lo;0;L;;;;;N;;;;; +135E4;EGYPTIAN HIEROGLYPH-135E4;Lo;0;L;;;;;N;;;;; +135E5;EGYPTIAN HIEROGLYPH-135E5;Lo;0;L;;;;;N;;;;; +135E6;EGYPTIAN HIEROGLYPH-135E6;Lo;0;L;;;;;N;;;;; +135E7;EGYPTIAN HIEROGLYPH-135E7;Lo;0;L;;;;;N;;;;; +135E8;EGYPTIAN HIEROGLYPH-135E8;Lo;0;L;;;;;N;;;;; +135E9;EGYPTIAN HIEROGLYPH-135E9;Lo;0;L;;;;;N;;;;; +135EA;EGYPTIAN HIEROGLYPH-135EA;Lo;0;L;;;;;N;;;;; +135EB;EGYPTIAN HIEROGLYPH-135EB;Lo;0;L;;;;;N;;;;; +135EC;EGYPTIAN HIEROGLYPH-135EC;Lo;0;L;;;;;N;;;;; +135ED;EGYPTIAN HIEROGLYPH-135ED;Lo;0;L;;;;;N;;;;; +135EE;EGYPTIAN HIEROGLYPH-135EE;Lo;0;L;;;;;N;;;;; +135EF;EGYPTIAN HIEROGLYPH-135EF;Lo;0;L;;;;;N;;;;; +135F0;EGYPTIAN HIEROGLYPH-135F0;Lo;0;L;;;;;N;;;;; +135F1;EGYPTIAN HIEROGLYPH-135F1;Lo;0;L;;;;;N;;;;; +135F2;EGYPTIAN HIEROGLYPH-135F2;Lo;0;L;;;;;N;;;;; +135F3;EGYPTIAN HIEROGLYPH-135F3;Lo;0;L;;;;;N;;;;; +135F4;EGYPTIAN HIEROGLYPH-135F4;Lo;0;L;;;;;N;;;;; +135F5;EGYPTIAN HIEROGLYPH-135F5;Lo;0;L;;;;;N;;;;; +135F6;EGYPTIAN HIEROGLYPH-135F6;Lo;0;L;;;;;N;;;;; +135F7;EGYPTIAN HIEROGLYPH-135F7;Lo;0;L;;;;;N;;;;; +135F8;EGYPTIAN HIEROGLYPH-135F8;Lo;0;L;;;;;N;;;;; +135F9;EGYPTIAN HIEROGLYPH-135F9;Lo;0;L;;;;;N;;;;; +135FA;EGYPTIAN HIEROGLYPH-135FA;Lo;0;L;;;;;N;;;;; +135FB;EGYPTIAN HIEROGLYPH-135FB;Lo;0;L;;;;;N;;;;; +135FC;EGYPTIAN HIEROGLYPH-135FC;Lo;0;L;;;;;N;;;;; +135FD;EGYPTIAN HIEROGLYPH-135FD;Lo;0;L;;;;;N;;;;; +135FE;EGYPTIAN HIEROGLYPH-135FE;Lo;0;L;;;;;N;;;;; +135FF;EGYPTIAN HIEROGLYPH-135FF;Lo;0;L;;;;;N;;;;; +13600;EGYPTIAN HIEROGLYPH-13600;Lo;0;L;;;;;N;;;;; +13601;EGYPTIAN HIEROGLYPH-13601;Lo;0;L;;;;;N;;;;; +13602;EGYPTIAN HIEROGLYPH-13602;Lo;0;L;;;;;N;;;;; +13603;EGYPTIAN HIEROGLYPH-13603;Lo;0;L;;;;;N;;;;; +13604;EGYPTIAN HIEROGLYPH-13604;Lo;0;L;;;;;N;;;;; +13605;EGYPTIAN HIEROGLYPH-13605;Lo;0;L;;;;;N;;;;; +13606;EGYPTIAN HIEROGLYPH-13606;Lo;0;L;;;;;N;;;;; +13607;EGYPTIAN HIEROGLYPH-13607;Lo;0;L;;;;;N;;;;; +13608;EGYPTIAN HIEROGLYPH-13608;Lo;0;L;;;;;N;;;;; +13609;EGYPTIAN HIEROGLYPH-13609;Lo;0;L;;;;;N;;;;; +1360A;EGYPTIAN HIEROGLYPH-1360A;Lo;0;L;;;;;N;;;;; +1360B;EGYPTIAN HIEROGLYPH-1360B;Lo;0;L;;;;;N;;;;; +1360C;EGYPTIAN HIEROGLYPH-1360C;Lo;0;L;;;;;N;;;;; +1360D;EGYPTIAN HIEROGLYPH-1360D;Lo;0;L;;;;;N;;;;; +1360E;EGYPTIAN HIEROGLYPH-1360E;Lo;0;L;;;;;N;;;;; +1360F;EGYPTIAN HIEROGLYPH-1360F;Lo;0;L;;;;;N;;;;; +13610;EGYPTIAN HIEROGLYPH-13610;Lo;0;L;;;;;N;;;;; +13611;EGYPTIAN HIEROGLYPH-13611;Lo;0;L;;;;;N;;;;; +13612;EGYPTIAN HIEROGLYPH-13612;Lo;0;L;;;;;N;;;;; +13613;EGYPTIAN HIEROGLYPH-13613;Lo;0;L;;;;;N;;;;; +13614;EGYPTIAN HIEROGLYPH-13614;Lo;0;L;;;;;N;;;;; +13615;EGYPTIAN HIEROGLYPH-13615;Lo;0;L;;;;;N;;;;; +13616;EGYPTIAN HIEROGLYPH-13616;Lo;0;L;;;;;N;;;;; +13617;EGYPTIAN HIEROGLYPH-13617;Lo;0;L;;;;;N;;;;; +13618;EGYPTIAN HIEROGLYPH-13618;Lo;0;L;;;;;N;;;;; +13619;EGYPTIAN HIEROGLYPH-13619;Lo;0;L;;;;;N;;;;; +1361A;EGYPTIAN HIEROGLYPH-1361A;Lo;0;L;;;;;N;;;;; +1361B;EGYPTIAN HIEROGLYPH-1361B;Lo;0;L;;;;;N;;;;; +1361C;EGYPTIAN HIEROGLYPH-1361C;Lo;0;L;;;;;N;;;;; +1361D;EGYPTIAN HIEROGLYPH-1361D;Lo;0;L;;;;;N;;;;; +1361E;EGYPTIAN HIEROGLYPH-1361E;Lo;0;L;;;;;N;;;;; +1361F;EGYPTIAN HIEROGLYPH-1361F;Lo;0;L;;;;;N;;;;; +13620;EGYPTIAN HIEROGLYPH-13620;Lo;0;L;;;;;N;;;;; +13621;EGYPTIAN HIEROGLYPH-13621;Lo;0;L;;;;;N;;;;; +13622;EGYPTIAN HIEROGLYPH-13622;Lo;0;L;;;;;N;;;;; +13623;EGYPTIAN HIEROGLYPH-13623;Lo;0;L;;;;;N;;;;; +13624;EGYPTIAN HIEROGLYPH-13624;Lo;0;L;;;;;N;;;;; +13625;EGYPTIAN HIEROGLYPH-13625;Lo;0;L;;;;;N;;;;; +13626;EGYPTIAN HIEROGLYPH-13626;Lo;0;L;;;;;N;;;;; +13627;EGYPTIAN HIEROGLYPH-13627;Lo;0;L;;;;;N;;;;; +13628;EGYPTIAN HIEROGLYPH-13628;Lo;0;L;;;;;N;;;;; +13629;EGYPTIAN HIEROGLYPH-13629;Lo;0;L;;;;;N;;;;; +1362A;EGYPTIAN HIEROGLYPH-1362A;Lo;0;L;;;;;N;;;;; +1362B;EGYPTIAN HIEROGLYPH-1362B;Lo;0;L;;;;;N;;;;; +1362C;EGYPTIAN HIEROGLYPH-1362C;Lo;0;L;;;;;N;;;;; +1362D;EGYPTIAN HIEROGLYPH-1362D;Lo;0;L;;;;;N;;;;; +1362E;EGYPTIAN HIEROGLYPH-1362E;Lo;0;L;;;;;N;;;;; +1362F;EGYPTIAN HIEROGLYPH-1362F;Lo;0;L;;;;;N;;;;; +13630;EGYPTIAN HIEROGLYPH-13630;Lo;0;L;;;;;N;;;;; +13631;EGYPTIAN HIEROGLYPH-13631;Lo;0;L;;;;;N;;;;; +13632;EGYPTIAN HIEROGLYPH-13632;Lo;0;L;;;;;N;;;;; +13633;EGYPTIAN HIEROGLYPH-13633;Lo;0;L;;;;;N;;;;; +13634;EGYPTIAN HIEROGLYPH-13634;Lo;0;L;;;;;N;;;;; +13635;EGYPTIAN HIEROGLYPH-13635;Lo;0;L;;;;;N;;;;; +13636;EGYPTIAN HIEROGLYPH-13636;Lo;0;L;;;;;N;;;;; +13637;EGYPTIAN HIEROGLYPH-13637;Lo;0;L;;;;;N;;;;; +13638;EGYPTIAN HIEROGLYPH-13638;Lo;0;L;;;;;N;;;;; +13639;EGYPTIAN HIEROGLYPH-13639;Lo;0;L;;;;;N;;;;; +1363A;EGYPTIAN HIEROGLYPH-1363A;Lo;0;L;;;;;N;;;;; +1363B;EGYPTIAN HIEROGLYPH-1363B;Lo;0;L;;;;;N;;;;; +1363C;EGYPTIAN HIEROGLYPH-1363C;Lo;0;L;;;;;N;;;;; +1363D;EGYPTIAN HIEROGLYPH-1363D;Lo;0;L;;;;;N;;;;; +1363E;EGYPTIAN HIEROGLYPH-1363E;Lo;0;L;;;;;N;;;;; +1363F;EGYPTIAN HIEROGLYPH-1363F;Lo;0;L;;;;;N;;;;; +13640;EGYPTIAN HIEROGLYPH-13640;Lo;0;L;;;;;N;;;;; +13641;EGYPTIAN HIEROGLYPH-13641;Lo;0;L;;;;;N;;;;; +13642;EGYPTIAN HIEROGLYPH-13642;Lo;0;L;;;;;N;;;;; +13643;EGYPTIAN HIEROGLYPH-13643;Lo;0;L;;;;;N;;;;; +13644;EGYPTIAN HIEROGLYPH-13644;Lo;0;L;;;;;N;;;;; +13645;EGYPTIAN HIEROGLYPH-13645;Lo;0;L;;;;;N;;;;; +13646;EGYPTIAN HIEROGLYPH-13646;Lo;0;L;;;;;N;;;;; +13647;EGYPTIAN HIEROGLYPH-13647;Lo;0;L;;;;;N;;;;; +13648;EGYPTIAN HIEROGLYPH-13648;Lo;0;L;;;;;N;;;;; +13649;EGYPTIAN HIEROGLYPH-13649;Lo;0;L;;;;;N;;;;; +1364A;EGYPTIAN HIEROGLYPH-1364A;Lo;0;L;;;;;N;;;;; +1364B;EGYPTIAN HIEROGLYPH-1364B;Lo;0;L;;;;;N;;;;; +1364C;EGYPTIAN HIEROGLYPH-1364C;Lo;0;L;;;;;N;;;;; +1364D;EGYPTIAN HIEROGLYPH-1364D;Lo;0;L;;;;;N;;;;; +1364E;EGYPTIAN HIEROGLYPH-1364E;Lo;0;L;;;;;N;;;;; +1364F;EGYPTIAN HIEROGLYPH-1364F;Lo;0;L;;;;;N;;;;; +13650;EGYPTIAN HIEROGLYPH-13650;Lo;0;L;;;;;N;;;;; +13651;EGYPTIAN HIEROGLYPH-13651;Lo;0;L;;;;;N;;;;; +13652;EGYPTIAN HIEROGLYPH-13652;Lo;0;L;;;;;N;;;;; +13653;EGYPTIAN HIEROGLYPH-13653;Lo;0;L;;;;;N;;;;; +13654;EGYPTIAN HIEROGLYPH-13654;Lo;0;L;;;;;N;;;;; +13655;EGYPTIAN HIEROGLYPH-13655;Lo;0;L;;;;;N;;;;; +13656;EGYPTIAN HIEROGLYPH-13656;Lo;0;L;;;;;N;;;;; +13657;EGYPTIAN HIEROGLYPH-13657;Lo;0;L;;;;;N;;;;; +13658;EGYPTIAN HIEROGLYPH-13658;Lo;0;L;;;;;N;;;;; +13659;EGYPTIAN HIEROGLYPH-13659;Lo;0;L;;;;;N;;;;; +1365A;EGYPTIAN HIEROGLYPH-1365A;Lo;0;L;;;;;N;;;;; +1365B;EGYPTIAN HIEROGLYPH-1365B;Lo;0;L;;;;;N;;;;; +1365C;EGYPTIAN HIEROGLYPH-1365C;Lo;0;L;;;;;N;;;;; +1365D;EGYPTIAN HIEROGLYPH-1365D;Lo;0;L;;;;;N;;;;; +1365E;EGYPTIAN HIEROGLYPH-1365E;Lo;0;L;;;;;N;;;;; +1365F;EGYPTIAN HIEROGLYPH-1365F;Lo;0;L;;;;;N;;;;; +13660;EGYPTIAN HIEROGLYPH-13660;Lo;0;L;;;;;N;;;;; +13661;EGYPTIAN HIEROGLYPH-13661;Lo;0;L;;;;;N;;;;; +13662;EGYPTIAN HIEROGLYPH-13662;Lo;0;L;;;;;N;;;;; +13663;EGYPTIAN HIEROGLYPH-13663;Lo;0;L;;;;;N;;;;; +13664;EGYPTIAN HIEROGLYPH-13664;Lo;0;L;;;;;N;;;;; +13665;EGYPTIAN HIEROGLYPH-13665;Lo;0;L;;;;;N;;;;; +13666;EGYPTIAN HIEROGLYPH-13666;Lo;0;L;;;;;N;;;;; +13667;EGYPTIAN HIEROGLYPH-13667;Lo;0;L;;;;;N;;;;; +13668;EGYPTIAN HIEROGLYPH-13668;Lo;0;L;;;;;N;;;;; +13669;EGYPTIAN HIEROGLYPH-13669;Lo;0;L;;;;;N;;;;; +1366A;EGYPTIAN HIEROGLYPH-1366A;Lo;0;L;;;;;N;;;;; +1366B;EGYPTIAN HIEROGLYPH-1366B;Lo;0;L;;;;;N;;;;; +1366C;EGYPTIAN HIEROGLYPH-1366C;Lo;0;L;;;;;N;;;;; +1366D;EGYPTIAN HIEROGLYPH-1366D;Lo;0;L;;;;;N;;;;; +1366E;EGYPTIAN HIEROGLYPH-1366E;Lo;0;L;;;;;N;;;;; +1366F;EGYPTIAN HIEROGLYPH-1366F;Lo;0;L;;;;;N;;;;; +13670;EGYPTIAN HIEROGLYPH-13670;Lo;0;L;;;;;N;;;;; +13671;EGYPTIAN HIEROGLYPH-13671;Lo;0;L;;;;;N;;;;; +13672;EGYPTIAN HIEROGLYPH-13672;Lo;0;L;;;;;N;;;;; +13673;EGYPTIAN HIEROGLYPH-13673;Lo;0;L;;;;;N;;;;; +13674;EGYPTIAN HIEROGLYPH-13674;Lo;0;L;;;;;N;;;;; +13675;EGYPTIAN HIEROGLYPH-13675;Lo;0;L;;;;;N;;;;; +13676;EGYPTIAN HIEROGLYPH-13676;Lo;0;L;;;;;N;;;;; +13677;EGYPTIAN HIEROGLYPH-13677;Lo;0;L;;;;;N;;;;; +13678;EGYPTIAN HIEROGLYPH-13678;Lo;0;L;;;;;N;;;;; +13679;EGYPTIAN HIEROGLYPH-13679;Lo;0;L;;;;;N;;;;; +1367A;EGYPTIAN HIEROGLYPH-1367A;Lo;0;L;;;;;N;;;;; +1367B;EGYPTIAN HIEROGLYPH-1367B;Lo;0;L;;;;;N;;;;; +1367C;EGYPTIAN HIEROGLYPH-1367C;Lo;0;L;;;;;N;;;;; +1367D;EGYPTIAN HIEROGLYPH-1367D;Lo;0;L;;;;;N;;;;; +1367E;EGYPTIAN HIEROGLYPH-1367E;Lo;0;L;;;;;N;;;;; +1367F;EGYPTIAN HIEROGLYPH-1367F;Lo;0;L;;;;;N;;;;; +13680;EGYPTIAN HIEROGLYPH-13680;Lo;0;L;;;;;N;;;;; +13681;EGYPTIAN HIEROGLYPH-13681;Lo;0;L;;;;;N;;;;; +13682;EGYPTIAN HIEROGLYPH-13682;Lo;0;L;;;;;N;;;;; +13683;EGYPTIAN HIEROGLYPH-13683;Lo;0;L;;;;;N;;;;; +13684;EGYPTIAN HIEROGLYPH-13684;Lo;0;L;;;;;N;;;;; +13685;EGYPTIAN HIEROGLYPH-13685;Lo;0;L;;;;;N;;;;; +13686;EGYPTIAN HIEROGLYPH-13686;Lo;0;L;;;;;N;;;;; +13687;EGYPTIAN HIEROGLYPH-13687;Lo;0;L;;;;;N;;;;; +13688;EGYPTIAN HIEROGLYPH-13688;Lo;0;L;;;;;N;;;;; +13689;EGYPTIAN HIEROGLYPH-13689;Lo;0;L;;;;;N;;;;; +1368A;EGYPTIAN HIEROGLYPH-1368A;Lo;0;L;;;;;N;;;;; +1368B;EGYPTIAN HIEROGLYPH-1368B;Lo;0;L;;;;;N;;;;; +1368C;EGYPTIAN HIEROGLYPH-1368C;Lo;0;L;;;;;N;;;;; +1368D;EGYPTIAN HIEROGLYPH-1368D;Lo;0;L;;;;;N;;;;; +1368E;EGYPTIAN HIEROGLYPH-1368E;Lo;0;L;;;;;N;;;;; +1368F;EGYPTIAN HIEROGLYPH-1368F;Lo;0;L;;;;;N;;;;; +13690;EGYPTIAN HIEROGLYPH-13690;Lo;0;L;;;;;N;;;;; +13691;EGYPTIAN HIEROGLYPH-13691;Lo;0;L;;;;;N;;;;; +13692;EGYPTIAN HIEROGLYPH-13692;Lo;0;L;;;;;N;;;;; +13693;EGYPTIAN HIEROGLYPH-13693;Lo;0;L;;;;;N;;;;; +13694;EGYPTIAN HIEROGLYPH-13694;Lo;0;L;;;;;N;;;;; +13695;EGYPTIAN HIEROGLYPH-13695;Lo;0;L;;;;;N;;;;; +13696;EGYPTIAN HIEROGLYPH-13696;Lo;0;L;;;;;N;;;;; +13697;EGYPTIAN HIEROGLYPH-13697;Lo;0;L;;;;;N;;;;; +13698;EGYPTIAN HIEROGLYPH-13698;Lo;0;L;;;;;N;;;;; +13699;EGYPTIAN HIEROGLYPH-13699;Lo;0;L;;;;;N;;;;; +1369A;EGYPTIAN HIEROGLYPH-1369A;Lo;0;L;;;;;N;;;;; +1369B;EGYPTIAN HIEROGLYPH-1369B;Lo;0;L;;;;;N;;;;; +1369C;EGYPTIAN HIEROGLYPH-1369C;Lo;0;L;;;;;N;;;;; +1369D;EGYPTIAN HIEROGLYPH-1369D;Lo;0;L;;;;;N;;;;; +1369E;EGYPTIAN HIEROGLYPH-1369E;Lo;0;L;;;;;N;;;;; +1369F;EGYPTIAN HIEROGLYPH-1369F;Lo;0;L;;;;;N;;;;; +136A0;EGYPTIAN HIEROGLYPH-136A0;Lo;0;L;;;;;N;;;;; +136A1;EGYPTIAN HIEROGLYPH-136A1;Lo;0;L;;;;;N;;;;; +136A2;EGYPTIAN HIEROGLYPH-136A2;Lo;0;L;;;;;N;;;;; +136A3;EGYPTIAN HIEROGLYPH-136A3;Lo;0;L;;;;;N;;;;; +136A4;EGYPTIAN HIEROGLYPH-136A4;Lo;0;L;;;;;N;;;;; +136A5;EGYPTIAN HIEROGLYPH-136A5;Lo;0;L;;;;;N;;;;; +136A6;EGYPTIAN HIEROGLYPH-136A6;Lo;0;L;;;;;N;;;;; +136A7;EGYPTIAN HIEROGLYPH-136A7;Lo;0;L;;;;;N;;;;; +136A8;EGYPTIAN HIEROGLYPH-136A8;Lo;0;L;;;;;N;;;;; +136A9;EGYPTIAN HIEROGLYPH-136A9;Lo;0;L;;;;;N;;;;; +136AA;EGYPTIAN HIEROGLYPH-136AA;Lo;0;L;;;;;N;;;;; +136AB;EGYPTIAN HIEROGLYPH-136AB;Lo;0;L;;;;;N;;;;; +136AC;EGYPTIAN HIEROGLYPH-136AC;Lo;0;L;;;;;N;;;;; +136AD;EGYPTIAN HIEROGLYPH-136AD;Lo;0;L;;;;;N;;;;; +136AE;EGYPTIAN HIEROGLYPH-136AE;Lo;0;L;;;;;N;;;;; +136AF;EGYPTIAN HIEROGLYPH-136AF;Lo;0;L;;;;;N;;;;; +136B0;EGYPTIAN HIEROGLYPH-136B0;Lo;0;L;;;;;N;;;;; +136B1;EGYPTIAN HIEROGLYPH-136B1;Lo;0;L;;;;;N;;;;; +136B2;EGYPTIAN HIEROGLYPH-136B2;Lo;0;L;;;;;N;;;;; +136B3;EGYPTIAN HIEROGLYPH-136B3;Lo;0;L;;;;;N;;;;; +136B4;EGYPTIAN HIEROGLYPH-136B4;Lo;0;L;;;;;N;;;;; +136B5;EGYPTIAN HIEROGLYPH-136B5;Lo;0;L;;;;;N;;;;; +136B6;EGYPTIAN HIEROGLYPH-136B6;Lo;0;L;;;;;N;;;;; +136B7;EGYPTIAN HIEROGLYPH-136B7;Lo;0;L;;;;;N;;;;; +136B8;EGYPTIAN HIEROGLYPH-136B8;Lo;0;L;;;;;N;;;;; +136B9;EGYPTIAN HIEROGLYPH-136B9;Lo;0;L;;;;;N;;;;; +136BA;EGYPTIAN HIEROGLYPH-136BA;Lo;0;L;;;;;N;;;;; +136BB;EGYPTIAN HIEROGLYPH-136BB;Lo;0;L;;;;;N;;;;; +136BC;EGYPTIAN HIEROGLYPH-136BC;Lo;0;L;;;;;N;;;;; +136BD;EGYPTIAN HIEROGLYPH-136BD;Lo;0;L;;;;;N;;;;; +136BE;EGYPTIAN HIEROGLYPH-136BE;Lo;0;L;;;;;N;;;;; +136BF;EGYPTIAN HIEROGLYPH-136BF;Lo;0;L;;;;;N;;;;; +136C0;EGYPTIAN HIEROGLYPH-136C0;Lo;0;L;;;;;N;;;;; +136C1;EGYPTIAN HIEROGLYPH-136C1;Lo;0;L;;;;;N;;;;; +136C2;EGYPTIAN HIEROGLYPH-136C2;Lo;0;L;;;;;N;;;;; +136C3;EGYPTIAN HIEROGLYPH-136C3;Lo;0;L;;;;;N;;;;; +136C4;EGYPTIAN HIEROGLYPH-136C4;Lo;0;L;;;;;N;;;;; +136C5;EGYPTIAN HIEROGLYPH-136C5;Lo;0;L;;;;;N;;;;; +136C6;EGYPTIAN HIEROGLYPH-136C6;Lo;0;L;;;;;N;;;;; +136C7;EGYPTIAN HIEROGLYPH-136C7;Lo;0;L;;;;;N;;;;; +136C8;EGYPTIAN HIEROGLYPH-136C8;Lo;0;L;;;;;N;;;;; +136C9;EGYPTIAN HIEROGLYPH-136C9;Lo;0;L;;;;;N;;;;; +136CA;EGYPTIAN HIEROGLYPH-136CA;Lo;0;L;;;;;N;;;;; +136CB;EGYPTIAN HIEROGLYPH-136CB;Lo;0;L;;;;;N;;;;; +136CC;EGYPTIAN HIEROGLYPH-136CC;Lo;0;L;;;;;N;;;;; +136CD;EGYPTIAN HIEROGLYPH-136CD;Lo;0;L;;;;;N;;;;; +136CE;EGYPTIAN HIEROGLYPH-136CE;Lo;0;L;;;;;N;;;;; +136CF;EGYPTIAN HIEROGLYPH-136CF;Lo;0;L;;;;;N;;;;; +136D0;EGYPTIAN HIEROGLYPH-136D0;Lo;0;L;;;;;N;;;;; +136D1;EGYPTIAN HIEROGLYPH-136D1;Lo;0;L;;;;;N;;;;; +136D2;EGYPTIAN HIEROGLYPH-136D2;Lo;0;L;;;;;N;;;;; +136D3;EGYPTIAN HIEROGLYPH-136D3;Lo;0;L;;;;;N;;;;; +136D4;EGYPTIAN HIEROGLYPH-136D4;Lo;0;L;;;;;N;;;;; +136D5;EGYPTIAN HIEROGLYPH-136D5;Lo;0;L;;;;;N;;;;; +136D6;EGYPTIAN HIEROGLYPH-136D6;Lo;0;L;;;;;N;;;;; +136D7;EGYPTIAN HIEROGLYPH-136D7;Lo;0;L;;;;;N;;;;; +136D8;EGYPTIAN HIEROGLYPH-136D8;Lo;0;L;;;;;N;;;;; +136D9;EGYPTIAN HIEROGLYPH-136D9;Lo;0;L;;;;;N;;;;; +136DA;EGYPTIAN HIEROGLYPH-136DA;Lo;0;L;;;;;N;;;;; +136DB;EGYPTIAN HIEROGLYPH-136DB;Lo;0;L;;;;;N;;;;; +136DC;EGYPTIAN HIEROGLYPH-136DC;Lo;0;L;;;;;N;;;;; +136DD;EGYPTIAN HIEROGLYPH-136DD;Lo;0;L;;;;;N;;;;; +136DE;EGYPTIAN HIEROGLYPH-136DE;Lo;0;L;;;;;N;;;;; +136DF;EGYPTIAN HIEROGLYPH-136DF;Lo;0;L;;;;;N;;;;; +136E0;EGYPTIAN HIEROGLYPH-136E0;Lo;0;L;;;;;N;;;;; +136E1;EGYPTIAN HIEROGLYPH-136E1;Lo;0;L;;;;;N;;;;; +136E2;EGYPTIAN HIEROGLYPH-136E2;Lo;0;L;;;;;N;;;;; +136E3;EGYPTIAN HIEROGLYPH-136E3;Lo;0;L;;;;;N;;;;; +136E4;EGYPTIAN HIEROGLYPH-136E4;Lo;0;L;;;;;N;;;;; +136E5;EGYPTIAN HIEROGLYPH-136E5;Lo;0;L;;;;;N;;;;; +136E6;EGYPTIAN HIEROGLYPH-136E6;Lo;0;L;;;;;N;;;;; +136E7;EGYPTIAN HIEROGLYPH-136E7;Lo;0;L;;;;;N;;;;; +136E8;EGYPTIAN HIEROGLYPH-136E8;Lo;0;L;;;;;N;;;;; +136E9;EGYPTIAN HIEROGLYPH-136E9;Lo;0;L;;;;;N;;;;; +136EA;EGYPTIAN HIEROGLYPH-136EA;Lo;0;L;;;;;N;;;;; +136EB;EGYPTIAN HIEROGLYPH-136EB;Lo;0;L;;;;;N;;;;; +136EC;EGYPTIAN HIEROGLYPH-136EC;Lo;0;L;;;;;N;;;;; +136ED;EGYPTIAN HIEROGLYPH-136ED;Lo;0;L;;;;;N;;;;; +136EE;EGYPTIAN HIEROGLYPH-136EE;Lo;0;L;;;;;N;;;;; +136EF;EGYPTIAN HIEROGLYPH-136EF;Lo;0;L;;;;;N;;;;; +136F0;EGYPTIAN HIEROGLYPH-136F0;Lo;0;L;;;;;N;;;;; +136F1;EGYPTIAN HIEROGLYPH-136F1;Lo;0;L;;;;;N;;;;; +136F2;EGYPTIAN HIEROGLYPH-136F2;Lo;0;L;;;;;N;;;;; +136F3;EGYPTIAN HIEROGLYPH-136F3;Lo;0;L;;;;;N;;;;; +136F4;EGYPTIAN HIEROGLYPH-136F4;Lo;0;L;;;;;N;;;;; +136F5;EGYPTIAN HIEROGLYPH-136F5;Lo;0;L;;;;;N;;;;; +136F6;EGYPTIAN HIEROGLYPH-136F6;Lo;0;L;;;;;N;;;;; +136F7;EGYPTIAN HIEROGLYPH-136F7;Lo;0;L;;;;;N;;;;; +136F8;EGYPTIAN HIEROGLYPH-136F8;Lo;0;L;;;;;N;;;;; +136F9;EGYPTIAN HIEROGLYPH-136F9;Lo;0;L;;;;;N;;;;; +136FA;EGYPTIAN HIEROGLYPH-136FA;Lo;0;L;;;;;N;;;;; +136FB;EGYPTIAN HIEROGLYPH-136FB;Lo;0;L;;;;;N;;;;; +136FC;EGYPTIAN HIEROGLYPH-136FC;Lo;0;L;;;;;N;;;;; +136FD;EGYPTIAN HIEROGLYPH-136FD;Lo;0;L;;;;;N;;;;; +136FE;EGYPTIAN HIEROGLYPH-136FE;Lo;0;L;;;;;N;;;;; +136FF;EGYPTIAN HIEROGLYPH-136FF;Lo;0;L;;;;;N;;;;; +13700;EGYPTIAN HIEROGLYPH-13700;Lo;0;L;;;;;N;;;;; +13701;EGYPTIAN HIEROGLYPH-13701;Lo;0;L;;;;;N;;;;; +13702;EGYPTIAN HIEROGLYPH-13702;Lo;0;L;;;;;N;;;;; +13703;EGYPTIAN HIEROGLYPH-13703;Lo;0;L;;;;;N;;;;; +13704;EGYPTIAN HIEROGLYPH-13704;Lo;0;L;;;;;N;;;;; +13705;EGYPTIAN HIEROGLYPH-13705;Lo;0;L;;;;;N;;;;; +13706;EGYPTIAN HIEROGLYPH-13706;Lo;0;L;;;;;N;;;;; +13707;EGYPTIAN HIEROGLYPH-13707;Lo;0;L;;;;;N;;;;; +13708;EGYPTIAN HIEROGLYPH-13708;Lo;0;L;;;;;N;;;;; +13709;EGYPTIAN HIEROGLYPH-13709;Lo;0;L;;;;;N;;;;; +1370A;EGYPTIAN HIEROGLYPH-1370A;Lo;0;L;;;;;N;;;;; +1370B;EGYPTIAN HIEROGLYPH-1370B;Lo;0;L;;;;;N;;;;; +1370C;EGYPTIAN HIEROGLYPH-1370C;Lo;0;L;;;;;N;;;;; +1370D;EGYPTIAN HIEROGLYPH-1370D;Lo;0;L;;;;;N;;;;; +1370E;EGYPTIAN HIEROGLYPH-1370E;Lo;0;L;;;;;N;;;;; +1370F;EGYPTIAN HIEROGLYPH-1370F;Lo;0;L;;;;;N;;;;; +13710;EGYPTIAN HIEROGLYPH-13710;Lo;0;L;;;;;N;;;;; +13711;EGYPTIAN HIEROGLYPH-13711;Lo;0;L;;;;;N;;;;; +13712;EGYPTIAN HIEROGLYPH-13712;Lo;0;L;;;;;N;;;;; +13713;EGYPTIAN HIEROGLYPH-13713;Lo;0;L;;;;;N;;;;; +13714;EGYPTIAN HIEROGLYPH-13714;Lo;0;L;;;;;N;;;;; +13715;EGYPTIAN HIEROGLYPH-13715;Lo;0;L;;;;;N;;;;; +13716;EGYPTIAN HIEROGLYPH-13716;Lo;0;L;;;;;N;;;;; +13717;EGYPTIAN HIEROGLYPH-13717;Lo;0;L;;;;;N;;;;; +13718;EGYPTIAN HIEROGLYPH-13718;Lo;0;L;;;;;N;;;;; +13719;EGYPTIAN HIEROGLYPH-13719;Lo;0;L;;;;;N;;;;; +1371A;EGYPTIAN HIEROGLYPH-1371A;Lo;0;L;;;;;N;;;;; +1371B;EGYPTIAN HIEROGLYPH-1371B;Lo;0;L;;;;;N;;;;; +1371C;EGYPTIAN HIEROGLYPH-1371C;Lo;0;L;;;;;N;;;;; +1371D;EGYPTIAN HIEROGLYPH-1371D;Lo;0;L;;;;;N;;;;; +1371E;EGYPTIAN HIEROGLYPH-1371E;Lo;0;L;;;;;N;;;;; +1371F;EGYPTIAN HIEROGLYPH-1371F;Lo;0;L;;;;;N;;;;; +13720;EGYPTIAN HIEROGLYPH-13720;Lo;0;L;;;;;N;;;;; +13721;EGYPTIAN HIEROGLYPH-13721;Lo;0;L;;;;;N;;;;; +13722;EGYPTIAN HIEROGLYPH-13722;Lo;0;L;;;;;N;;;;; +13723;EGYPTIAN HIEROGLYPH-13723;Lo;0;L;;;;;N;;;;; +13724;EGYPTIAN HIEROGLYPH-13724;Lo;0;L;;;;;N;;;;; +13725;EGYPTIAN HIEROGLYPH-13725;Lo;0;L;;;;;N;;;;; +13726;EGYPTIAN HIEROGLYPH-13726;Lo;0;L;;;;;N;;;;; +13727;EGYPTIAN HIEROGLYPH-13727;Lo;0;L;;;;;N;;;;; +13728;EGYPTIAN HIEROGLYPH-13728;Lo;0;L;;;;;N;;;;; +13729;EGYPTIAN HIEROGLYPH-13729;Lo;0;L;;;;;N;;;;; +1372A;EGYPTIAN HIEROGLYPH-1372A;Lo;0;L;;;;;N;;;;; +1372B;EGYPTIAN HIEROGLYPH-1372B;Lo;0;L;;;;;N;;;;; +1372C;EGYPTIAN HIEROGLYPH-1372C;Lo;0;L;;;;;N;;;;; +1372D;EGYPTIAN HIEROGLYPH-1372D;Lo;0;L;;;;;N;;;;; +1372E;EGYPTIAN HIEROGLYPH-1372E;Lo;0;L;;;;;N;;;;; +1372F;EGYPTIAN HIEROGLYPH-1372F;Lo;0;L;;;;;N;;;;; +13730;EGYPTIAN HIEROGLYPH-13730;Lo;0;L;;;;;N;;;;; +13731;EGYPTIAN HIEROGLYPH-13731;Lo;0;L;;;;;N;;;;; +13732;EGYPTIAN HIEROGLYPH-13732;Lo;0;L;;;;;N;;;;; +13733;EGYPTIAN HIEROGLYPH-13733;Lo;0;L;;;;;N;;;;; +13734;EGYPTIAN HIEROGLYPH-13734;Lo;0;L;;;;;N;;;;; +13735;EGYPTIAN HIEROGLYPH-13735;Lo;0;L;;;;;N;;;;; +13736;EGYPTIAN HIEROGLYPH-13736;Lo;0;L;;;;;N;;;;; +13737;EGYPTIAN HIEROGLYPH-13737;Lo;0;L;;;;;N;;;;; +13738;EGYPTIAN HIEROGLYPH-13738;Lo;0;L;;;;;N;;;;; +13739;EGYPTIAN HIEROGLYPH-13739;Lo;0;L;;;;;N;;;;; +1373A;EGYPTIAN HIEROGLYPH-1373A;Lo;0;L;;;;;N;;;;; +1373B;EGYPTIAN HIEROGLYPH-1373B;Lo;0;L;;;;;N;;;;; +1373C;EGYPTIAN HIEROGLYPH-1373C;Lo;0;L;;;;;N;;;;; +1373D;EGYPTIAN HIEROGLYPH-1373D;Lo;0;L;;;;;N;;;;; +1373E;EGYPTIAN HIEROGLYPH-1373E;Lo;0;L;;;;;N;;;;; +1373F;EGYPTIAN HIEROGLYPH-1373F;Lo;0;L;;;;;N;;;;; +13740;EGYPTIAN HIEROGLYPH-13740;Lo;0;L;;;;;N;;;;; +13741;EGYPTIAN HIEROGLYPH-13741;Lo;0;L;;;;;N;;;;; +13742;EGYPTIAN HIEROGLYPH-13742;Lo;0;L;;;;;N;;;;; +13743;EGYPTIAN HIEROGLYPH-13743;Lo;0;L;;;;;N;;;;; +13744;EGYPTIAN HIEROGLYPH-13744;Lo;0;L;;;;;N;;;;; +13745;EGYPTIAN HIEROGLYPH-13745;Lo;0;L;;;;;N;;;;; +13746;EGYPTIAN HIEROGLYPH-13746;Lo;0;L;;;;;N;;;;; +13747;EGYPTIAN HIEROGLYPH-13747;Lo;0;L;;;;;N;;;;; +13748;EGYPTIAN HIEROGLYPH-13748;Lo;0;L;;;;;N;;;;; +13749;EGYPTIAN HIEROGLYPH-13749;Lo;0;L;;;;;N;;;;; +1374A;EGYPTIAN HIEROGLYPH-1374A;Lo;0;L;;;;;N;;;;; +1374B;EGYPTIAN HIEROGLYPH-1374B;Lo;0;L;;;;;N;;;;; +1374C;EGYPTIAN HIEROGLYPH-1374C;Lo;0;L;;;;;N;;;;; +1374D;EGYPTIAN HIEROGLYPH-1374D;Lo;0;L;;;;;N;;;;; +1374E;EGYPTIAN HIEROGLYPH-1374E;Lo;0;L;;;;;N;;;;; +1374F;EGYPTIAN HIEROGLYPH-1374F;Lo;0;L;;;;;N;;;;; +13750;EGYPTIAN HIEROGLYPH-13750;Lo;0;L;;;;;N;;;;; +13751;EGYPTIAN HIEROGLYPH-13751;Lo;0;L;;;;;N;;;;; +13752;EGYPTIAN HIEROGLYPH-13752;Lo;0;L;;;;;N;;;;; +13753;EGYPTIAN HIEROGLYPH-13753;Lo;0;L;;;;;N;;;;; +13754;EGYPTIAN HIEROGLYPH-13754;Lo;0;L;;;;;N;;;;; +13755;EGYPTIAN HIEROGLYPH-13755;Lo;0;L;;;;;N;;;;; +13756;EGYPTIAN HIEROGLYPH-13756;Lo;0;L;;;;;N;;;;; +13757;EGYPTIAN HIEROGLYPH-13757;Lo;0;L;;;;;N;;;;; +13758;EGYPTIAN HIEROGLYPH-13758;Lo;0;L;;;;;N;;;;; +13759;EGYPTIAN HIEROGLYPH-13759;Lo;0;L;;;;;N;;;;; +1375A;EGYPTIAN HIEROGLYPH-1375A;Lo;0;L;;;;;N;;;;; +1375B;EGYPTIAN HIEROGLYPH-1375B;Lo;0;L;;;;;N;;;;; +1375C;EGYPTIAN HIEROGLYPH-1375C;Lo;0;L;;;;;N;;;;; +1375D;EGYPTIAN HIEROGLYPH-1375D;Lo;0;L;;;;;N;;;;; +1375E;EGYPTIAN HIEROGLYPH-1375E;Lo;0;L;;;;;N;;;;; +1375F;EGYPTIAN HIEROGLYPH-1375F;Lo;0;L;;;;;N;;;;; +13760;EGYPTIAN HIEROGLYPH-13760;Lo;0;L;;;;;N;;;;; +13761;EGYPTIAN HIEROGLYPH-13761;Lo;0;L;;;;;N;;;;; +13762;EGYPTIAN HIEROGLYPH-13762;Lo;0;L;;;;;N;;;;; +13763;EGYPTIAN HIEROGLYPH-13763;Lo;0;L;;;;;N;;;;; +13764;EGYPTIAN HIEROGLYPH-13764;Lo;0;L;;;;;N;;;;; +13765;EGYPTIAN HIEROGLYPH-13765;Lo;0;L;;;;;N;;;;; +13766;EGYPTIAN HIEROGLYPH-13766;Lo;0;L;;;;;N;;;;; +13767;EGYPTIAN HIEROGLYPH-13767;Lo;0;L;;;;;N;;;;; +13768;EGYPTIAN HIEROGLYPH-13768;Lo;0;L;;;;;N;;;;; +13769;EGYPTIAN HIEROGLYPH-13769;Lo;0;L;;;;;N;;;;; +1376A;EGYPTIAN HIEROGLYPH-1376A;Lo;0;L;;;;;N;;;;; +1376B;EGYPTIAN HIEROGLYPH-1376B;Lo;0;L;;;;;N;;;;; +1376C;EGYPTIAN HIEROGLYPH-1376C;Lo;0;L;;;;;N;;;;; +1376D;EGYPTIAN HIEROGLYPH-1376D;Lo;0;L;;;;;N;;;;; +1376E;EGYPTIAN HIEROGLYPH-1376E;Lo;0;L;;;;;N;;;;; +1376F;EGYPTIAN HIEROGLYPH-1376F;Lo;0;L;;;;;N;;;;; +13770;EGYPTIAN HIEROGLYPH-13770;Lo;0;L;;;;;N;;;;; +13771;EGYPTIAN HIEROGLYPH-13771;Lo;0;L;;;;;N;;;;; +13772;EGYPTIAN HIEROGLYPH-13772;Lo;0;L;;;;;N;;;;; +13773;EGYPTIAN HIEROGLYPH-13773;Lo;0;L;;;;;N;;;;; +13774;EGYPTIAN HIEROGLYPH-13774;Lo;0;L;;;;;N;;;;; +13775;EGYPTIAN HIEROGLYPH-13775;Lo;0;L;;;;;N;;;;; +13776;EGYPTIAN HIEROGLYPH-13776;Lo;0;L;;;;;N;;;;; +13777;EGYPTIAN HIEROGLYPH-13777;Lo;0;L;;;;;N;;;;; +13778;EGYPTIAN HIEROGLYPH-13778;Lo;0;L;;;;;N;;;;; +13779;EGYPTIAN HIEROGLYPH-13779;Lo;0;L;;;;;N;;;;; +1377A;EGYPTIAN HIEROGLYPH-1377A;Lo;0;L;;;;;N;;;;; +1377B;EGYPTIAN HIEROGLYPH-1377B;Lo;0;L;;;;;N;;;;; +1377C;EGYPTIAN HIEROGLYPH-1377C;Lo;0;L;;;;;N;;;;; +1377D;EGYPTIAN HIEROGLYPH-1377D;Lo;0;L;;;;;N;;;;; +1377E;EGYPTIAN HIEROGLYPH-1377E;Lo;0;L;;;;;N;;;;; +1377F;EGYPTIAN HIEROGLYPH-1377F;Lo;0;L;;;;;N;;;;; +13780;EGYPTIAN HIEROGLYPH-13780;Lo;0;L;;;;;N;;;;; +13781;EGYPTIAN HIEROGLYPH-13781;Lo;0;L;;;;;N;;;;; +13782;EGYPTIAN HIEROGLYPH-13782;Lo;0;L;;;;;N;;;;; +13783;EGYPTIAN HIEROGLYPH-13783;Lo;0;L;;;;;N;;;;; +13784;EGYPTIAN HIEROGLYPH-13784;Lo;0;L;;;;;N;;;;; +13785;EGYPTIAN HIEROGLYPH-13785;Lo;0;L;;;;;N;;;;; +13786;EGYPTIAN HIEROGLYPH-13786;Lo;0;L;;;;;N;;;;; +13787;EGYPTIAN HIEROGLYPH-13787;Lo;0;L;;;;;N;;;;; +13788;EGYPTIAN HIEROGLYPH-13788;Lo;0;L;;;;;N;;;;; +13789;EGYPTIAN HIEROGLYPH-13789;Lo;0;L;;;;;N;;;;; +1378A;EGYPTIAN HIEROGLYPH-1378A;Lo;0;L;;;;;N;;;;; +1378B;EGYPTIAN HIEROGLYPH-1378B;Lo;0;L;;;;;N;;;;; +1378C;EGYPTIAN HIEROGLYPH-1378C;Lo;0;L;;;;;N;;;;; +1378D;EGYPTIAN HIEROGLYPH-1378D;Lo;0;L;;;;;N;;;;; +1378E;EGYPTIAN HIEROGLYPH-1378E;Lo;0;L;;;;;N;;;;; +1378F;EGYPTIAN HIEROGLYPH-1378F;Lo;0;L;;;;;N;;;;; +13790;EGYPTIAN HIEROGLYPH-13790;Lo;0;L;;;;;N;;;;; +13791;EGYPTIAN HIEROGLYPH-13791;Lo;0;L;;;;;N;;;;; +13792;EGYPTIAN HIEROGLYPH-13792;Lo;0;L;;;;;N;;;;; +13793;EGYPTIAN HIEROGLYPH-13793;Lo;0;L;;;;;N;;;;; +13794;EGYPTIAN HIEROGLYPH-13794;Lo;0;L;;;;;N;;;;; +13795;EGYPTIAN HIEROGLYPH-13795;Lo;0;L;;;;;N;;;;; +13796;EGYPTIAN HIEROGLYPH-13796;Lo;0;L;;;;;N;;;;; +13797;EGYPTIAN HIEROGLYPH-13797;Lo;0;L;;;;;N;;;;; +13798;EGYPTIAN HIEROGLYPH-13798;Lo;0;L;;;;;N;;;;; +13799;EGYPTIAN HIEROGLYPH-13799;Lo;0;L;;;;;N;;;;; +1379A;EGYPTIAN HIEROGLYPH-1379A;Lo;0;L;;;;;N;;;;; +1379B;EGYPTIAN HIEROGLYPH-1379B;Lo;0;L;;;;;N;;;;; +1379C;EGYPTIAN HIEROGLYPH-1379C;Lo;0;L;;;;;N;;;;; +1379D;EGYPTIAN HIEROGLYPH-1379D;Lo;0;L;;;;;N;;;;; +1379E;EGYPTIAN HIEROGLYPH-1379E;Lo;0;L;;;;;N;;;;; +1379F;EGYPTIAN HIEROGLYPH-1379F;Lo;0;L;;;;;N;;;;; +137A0;EGYPTIAN HIEROGLYPH-137A0;Lo;0;L;;;;;N;;;;; +137A1;EGYPTIAN HIEROGLYPH-137A1;Lo;0;L;;;;;N;;;;; +137A2;EGYPTIAN HIEROGLYPH-137A2;Lo;0;L;;;;;N;;;;; +137A3;EGYPTIAN HIEROGLYPH-137A3;Lo;0;L;;;;;N;;;;; +137A4;EGYPTIAN HIEROGLYPH-137A4;Lo;0;L;;;;;N;;;;; +137A5;EGYPTIAN HIEROGLYPH-137A5;Lo;0;L;;;;;N;;;;; +137A6;EGYPTIAN HIEROGLYPH-137A6;Lo;0;L;;;;;N;;;;; +137A7;EGYPTIAN HIEROGLYPH-137A7;Lo;0;L;;;;;N;;;;; +137A8;EGYPTIAN HIEROGLYPH-137A8;Lo;0;L;;;;;N;;;;; +137A9;EGYPTIAN HIEROGLYPH-137A9;Lo;0;L;;;;;N;;;;; +137AA;EGYPTIAN HIEROGLYPH-137AA;Lo;0;L;;;;;N;;;;; +137AB;EGYPTIAN HIEROGLYPH-137AB;Lo;0;L;;;;;N;;;;; +137AC;EGYPTIAN HIEROGLYPH-137AC;Lo;0;L;;;;;N;;;;; +137AD;EGYPTIAN HIEROGLYPH-137AD;Lo;0;L;;;;;N;;;;; +137AE;EGYPTIAN HIEROGLYPH-137AE;Lo;0;L;;;;;N;;;;; +137AF;EGYPTIAN HIEROGLYPH-137AF;Lo;0;L;;;;;N;;;;; +137B0;EGYPTIAN HIEROGLYPH-137B0;Lo;0;L;;;;;N;;;;; +137B1;EGYPTIAN HIEROGLYPH-137B1;Lo;0;L;;;;;N;;;;; +137B2;EGYPTIAN HIEROGLYPH-137B2;Lo;0;L;;;;;N;;;;; +137B3;EGYPTIAN HIEROGLYPH-137B3;Lo;0;L;;;;;N;;;;; +137B4;EGYPTIAN HIEROGLYPH-137B4;Lo;0;L;;;;;N;;;;; +137B5;EGYPTIAN HIEROGLYPH-137B5;Lo;0;L;;;;;N;;;;; +137B6;EGYPTIAN HIEROGLYPH-137B6;Lo;0;L;;;;;N;;;;; +137B7;EGYPTIAN HIEROGLYPH-137B7;Lo;0;L;;;;;N;;;;; +137B8;EGYPTIAN HIEROGLYPH-137B8;Lo;0;L;;;;;N;;;;; +137B9;EGYPTIAN HIEROGLYPH-137B9;Lo;0;L;;;;;N;;;;; +137BA;EGYPTIAN HIEROGLYPH-137BA;Lo;0;L;;;;;N;;;;; +137BB;EGYPTIAN HIEROGLYPH-137BB;Lo;0;L;;;;;N;;;;; +137BC;EGYPTIAN HIEROGLYPH-137BC;Lo;0;L;;;;;N;;;;; +137BD;EGYPTIAN HIEROGLYPH-137BD;Lo;0;L;;;;;N;;;;; +137BE;EGYPTIAN HIEROGLYPH-137BE;Lo;0;L;;;;;N;;;;; +137BF;EGYPTIAN HIEROGLYPH-137BF;Lo;0;L;;;;;N;;;;; +137C0;EGYPTIAN HIEROGLYPH-137C0;Lo;0;L;;;;;N;;;;; +137C1;EGYPTIAN HIEROGLYPH-137C1;Lo;0;L;;;;;N;;;;; +137C2;EGYPTIAN HIEROGLYPH-137C2;Lo;0;L;;;;;N;;;;; +137C3;EGYPTIAN HIEROGLYPH-137C3;Lo;0;L;;;;;N;;;;; +137C4;EGYPTIAN HIEROGLYPH-137C4;Lo;0;L;;;;;N;;;;; +137C5;EGYPTIAN HIEROGLYPH-137C5;Lo;0;L;;;;;N;;;;; +137C6;EGYPTIAN HIEROGLYPH-137C6;Lo;0;L;;;;;N;;;;; +137C7;EGYPTIAN HIEROGLYPH-137C7;Lo;0;L;;;;;N;;;;; +137C8;EGYPTIAN HIEROGLYPH-137C8;Lo;0;L;;;;;N;;;;; +137C9;EGYPTIAN HIEROGLYPH-137C9;Lo;0;L;;;;;N;;;;; +137CA;EGYPTIAN HIEROGLYPH-137CA;Lo;0;L;;;;;N;;;;; +137CB;EGYPTIAN HIEROGLYPH-137CB;Lo;0;L;;;;;N;;;;; +137CC;EGYPTIAN HIEROGLYPH-137CC;Lo;0;L;;;;;N;;;;; +137CD;EGYPTIAN HIEROGLYPH-137CD;Lo;0;L;;;;;N;;;;; +137CE;EGYPTIAN HIEROGLYPH-137CE;Lo;0;L;;;;;N;;;;; +137CF;EGYPTIAN HIEROGLYPH-137CF;Lo;0;L;;;;;N;;;;; +137D0;EGYPTIAN HIEROGLYPH-137D0;Lo;0;L;;;;;N;;;;; +137D1;EGYPTIAN HIEROGLYPH-137D1;Lo;0;L;;;;;N;;;;; +137D2;EGYPTIAN HIEROGLYPH-137D2;Lo;0;L;;;;;N;;;;; +137D3;EGYPTIAN HIEROGLYPH-137D3;Lo;0;L;;;;;N;;;;; +137D4;EGYPTIAN HIEROGLYPH-137D4;Lo;0;L;;;;;N;;;;; +137D5;EGYPTIAN HIEROGLYPH-137D5;Lo;0;L;;;;;N;;;;; +137D6;EGYPTIAN HIEROGLYPH-137D6;Lo;0;L;;;;;N;;;;; +137D7;EGYPTIAN HIEROGLYPH-137D7;Lo;0;L;;;;;N;;;;; +137D8;EGYPTIAN HIEROGLYPH-137D8;Lo;0;L;;;;;N;;;;; +137D9;EGYPTIAN HIEROGLYPH-137D9;Lo;0;L;;;;;N;;;;; +137DA;EGYPTIAN HIEROGLYPH-137DA;Lo;0;L;;;;;N;;;;; +137DB;EGYPTIAN HIEROGLYPH-137DB;Lo;0;L;;;;;N;;;;; +137DC;EGYPTIAN HIEROGLYPH-137DC;Lo;0;L;;;;;N;;;;; +137DD;EGYPTIAN HIEROGLYPH-137DD;Lo;0;L;;;;;N;;;;; +137DE;EGYPTIAN HIEROGLYPH-137DE;Lo;0;L;;;;;N;;;;; +137DF;EGYPTIAN HIEROGLYPH-137DF;Lo;0;L;;;;;N;;;;; +137E0;EGYPTIAN HIEROGLYPH-137E0;Lo;0;L;;;;;N;;;;; +137E1;EGYPTIAN HIEROGLYPH-137E1;Lo;0;L;;;;;N;;;;; +137E2;EGYPTIAN HIEROGLYPH-137E2;Lo;0;L;;;;;N;;;;; +137E3;EGYPTIAN HIEROGLYPH-137E3;Lo;0;L;;;;;N;;;;; +137E4;EGYPTIAN HIEROGLYPH-137E4;Lo;0;L;;;;;N;;;;; +137E5;EGYPTIAN HIEROGLYPH-137E5;Lo;0;L;;;;;N;;;;; +137E6;EGYPTIAN HIEROGLYPH-137E6;Lo;0;L;;;;;N;;;;; +137E7;EGYPTIAN HIEROGLYPH-137E7;Lo;0;L;;;;;N;;;;; +137E8;EGYPTIAN HIEROGLYPH-137E8;Lo;0;L;;;;;N;;;;; +137E9;EGYPTIAN HIEROGLYPH-137E9;Lo;0;L;;;;;N;;;;; +137EA;EGYPTIAN HIEROGLYPH-137EA;Lo;0;L;;;;;N;;;;; +137EB;EGYPTIAN HIEROGLYPH-137EB;Lo;0;L;;;;;N;;;;; +137EC;EGYPTIAN HIEROGLYPH-137EC;Lo;0;L;;;;;N;;;;; +137ED;EGYPTIAN HIEROGLYPH-137ED;Lo;0;L;;;;;N;;;;; +137EE;EGYPTIAN HIEROGLYPH-137EE;Lo;0;L;;;;;N;;;;; +137EF;EGYPTIAN HIEROGLYPH-137EF;Lo;0;L;;;;;N;;;;; +137F0;EGYPTIAN HIEROGLYPH-137F0;Lo;0;L;;;;;N;;;;; +137F1;EGYPTIAN HIEROGLYPH-137F1;Lo;0;L;;;;;N;;;;; +137F2;EGYPTIAN HIEROGLYPH-137F2;Lo;0;L;;;;;N;;;;; +137F3;EGYPTIAN HIEROGLYPH-137F3;Lo;0;L;;;;;N;;;;; +137F4;EGYPTIAN HIEROGLYPH-137F4;Lo;0;L;;;;;N;;;;; +137F5;EGYPTIAN HIEROGLYPH-137F5;Lo;0;L;;;;;N;;;;; +137F6;EGYPTIAN HIEROGLYPH-137F6;Lo;0;L;;;;;N;;;;; +137F7;EGYPTIAN HIEROGLYPH-137F7;Lo;0;L;;;;;N;;;;; +137F8;EGYPTIAN HIEROGLYPH-137F8;Lo;0;L;;;;;N;;;;; +137F9;EGYPTIAN HIEROGLYPH-137F9;Lo;0;L;;;;;N;;;;; +137FA;EGYPTIAN HIEROGLYPH-137FA;Lo;0;L;;;;;N;;;;; +137FB;EGYPTIAN HIEROGLYPH-137FB;Lo;0;L;;;;;N;;;;; +137FC;EGYPTIAN HIEROGLYPH-137FC;Lo;0;L;;;;;N;;;;; +137FD;EGYPTIAN HIEROGLYPH-137FD;Lo;0;L;;;;;N;;;;; +137FE;EGYPTIAN HIEROGLYPH-137FE;Lo;0;L;;;;;N;;;;; +137FF;EGYPTIAN HIEROGLYPH-137FF;Lo;0;L;;;;;N;;;;; +13800;EGYPTIAN HIEROGLYPH-13800;Lo;0;L;;;;;N;;;;; +13801;EGYPTIAN HIEROGLYPH-13801;Lo;0;L;;;;;N;;;;; +13802;EGYPTIAN HIEROGLYPH-13802;Lo;0;L;;;;;N;;;;; +13803;EGYPTIAN HIEROGLYPH-13803;Lo;0;L;;;;;N;;;;; +13804;EGYPTIAN HIEROGLYPH-13804;Lo;0;L;;;;;N;;;;; +13805;EGYPTIAN HIEROGLYPH-13805;Lo;0;L;;;;;N;;;;; +13806;EGYPTIAN HIEROGLYPH-13806;Lo;0;L;;;;;N;;;;; +13807;EGYPTIAN HIEROGLYPH-13807;Lo;0;L;;;;;N;;;;; +13808;EGYPTIAN HIEROGLYPH-13808;Lo;0;L;;;;;N;;;;; +13809;EGYPTIAN HIEROGLYPH-13809;Lo;0;L;;;;;N;;;;; +1380A;EGYPTIAN HIEROGLYPH-1380A;Lo;0;L;;;;;N;;;;; +1380B;EGYPTIAN HIEROGLYPH-1380B;Lo;0;L;;;;;N;;;;; +1380C;EGYPTIAN HIEROGLYPH-1380C;Lo;0;L;;;;;N;;;;; +1380D;EGYPTIAN HIEROGLYPH-1380D;Lo;0;L;;;;;N;;;;; +1380E;EGYPTIAN HIEROGLYPH-1380E;Lo;0;L;;;;;N;;;;; +1380F;EGYPTIAN HIEROGLYPH-1380F;Lo;0;L;;;;;N;;;;; +13810;EGYPTIAN HIEROGLYPH-13810;Lo;0;L;;;;;N;;;;; +13811;EGYPTIAN HIEROGLYPH-13811;Lo;0;L;;;;;N;;;;; +13812;EGYPTIAN HIEROGLYPH-13812;Lo;0;L;;;;;N;;;;; +13813;EGYPTIAN HIEROGLYPH-13813;Lo;0;L;;;;;N;;;;; +13814;EGYPTIAN HIEROGLYPH-13814;Lo;0;L;;;;;N;;;;; +13815;EGYPTIAN HIEROGLYPH-13815;Lo;0;L;;;;;N;;;;; +13816;EGYPTIAN HIEROGLYPH-13816;Lo;0;L;;;;;N;;;;; +13817;EGYPTIAN HIEROGLYPH-13817;Lo;0;L;;;;;N;;;;; +13818;EGYPTIAN HIEROGLYPH-13818;Lo;0;L;;;;;N;;;;; +13819;EGYPTIAN HIEROGLYPH-13819;Lo;0;L;;;;;N;;;;; +1381A;EGYPTIAN HIEROGLYPH-1381A;Lo;0;L;;;;;N;;;;; +1381B;EGYPTIAN HIEROGLYPH-1381B;Lo;0;L;;;;;N;;;;; +1381C;EGYPTIAN HIEROGLYPH-1381C;Lo;0;L;;;;;N;;;;; +1381D;EGYPTIAN HIEROGLYPH-1381D;Lo;0;L;;;;;N;;;;; +1381E;EGYPTIAN HIEROGLYPH-1381E;Lo;0;L;;;;;N;;;;; +1381F;EGYPTIAN HIEROGLYPH-1381F;Lo;0;L;;;;;N;;;;; +13820;EGYPTIAN HIEROGLYPH-13820;Lo;0;L;;;;;N;;;;; +13821;EGYPTIAN HIEROGLYPH-13821;Lo;0;L;;;;;N;;;;; +13822;EGYPTIAN HIEROGLYPH-13822;Lo;0;L;;;;;N;;;;; +13823;EGYPTIAN HIEROGLYPH-13823;Lo;0;L;;;;;N;;;;; +13824;EGYPTIAN HIEROGLYPH-13824;Lo;0;L;;;;;N;;;;; +13825;EGYPTIAN HIEROGLYPH-13825;Lo;0;L;;;;;N;;;;; +13826;EGYPTIAN HIEROGLYPH-13826;Lo;0;L;;;;;N;;;;; +13827;EGYPTIAN HIEROGLYPH-13827;Lo;0;L;;;;;N;;;;; +13828;EGYPTIAN HIEROGLYPH-13828;Lo;0;L;;;;;N;;;;; +13829;EGYPTIAN HIEROGLYPH-13829;Lo;0;L;;;;;N;;;;; +1382A;EGYPTIAN HIEROGLYPH-1382A;Lo;0;L;;;;;N;;;;; +1382B;EGYPTIAN HIEROGLYPH-1382B;Lo;0;L;;;;;N;;;;; +1382C;EGYPTIAN HIEROGLYPH-1382C;Lo;0;L;;;;;N;;;;; +1382D;EGYPTIAN HIEROGLYPH-1382D;Lo;0;L;;;;;N;;;;; +1382E;EGYPTIAN HIEROGLYPH-1382E;Lo;0;L;;;;;N;;;;; +1382F;EGYPTIAN HIEROGLYPH-1382F;Lo;0;L;;;;;N;;;;; +13830;EGYPTIAN HIEROGLYPH-13830;Lo;0;L;;;;;N;;;;; +13831;EGYPTIAN HIEROGLYPH-13831;Lo;0;L;;;;;N;;;;; +13832;EGYPTIAN HIEROGLYPH-13832;Lo;0;L;;;;;N;;;;; +13833;EGYPTIAN HIEROGLYPH-13833;Lo;0;L;;;;;N;;;;; +13834;EGYPTIAN HIEROGLYPH-13834;Lo;0;L;;;;;N;;;;; +13835;EGYPTIAN HIEROGLYPH-13835;Lo;0;L;;;;;N;;;;; +13836;EGYPTIAN HIEROGLYPH-13836;Lo;0;L;;;;;N;;;;; +13837;EGYPTIAN HIEROGLYPH-13837;Lo;0;L;;;;;N;;;;; +13838;EGYPTIAN HIEROGLYPH-13838;Lo;0;L;;;;;N;;;;; +13839;EGYPTIAN HIEROGLYPH-13839;Lo;0;L;;;;;N;;;;; +1383A;EGYPTIAN HIEROGLYPH-1383A;Lo;0;L;;;;;N;;;;; +1383B;EGYPTIAN HIEROGLYPH-1383B;Lo;0;L;;;;;N;;;;; +1383C;EGYPTIAN HIEROGLYPH-1383C;Lo;0;L;;;;;N;;;;; +1383D;EGYPTIAN HIEROGLYPH-1383D;Lo;0;L;;;;;N;;;;; +1383E;EGYPTIAN HIEROGLYPH-1383E;Lo;0;L;;;;;N;;;;; +1383F;EGYPTIAN HIEROGLYPH-1383F;Lo;0;L;;;;;N;;;;; +13840;EGYPTIAN HIEROGLYPH-13840;Lo;0;L;;;;;N;;;;; +13841;EGYPTIAN HIEROGLYPH-13841;Lo;0;L;;;;;N;;;;; +13842;EGYPTIAN HIEROGLYPH-13842;Lo;0;L;;;;;N;;;;; +13843;EGYPTIAN HIEROGLYPH-13843;Lo;0;L;;;;;N;;;;; +13844;EGYPTIAN HIEROGLYPH-13844;Lo;0;L;;;;;N;;;;; +13845;EGYPTIAN HIEROGLYPH-13845;Lo;0;L;;;;;N;;;;; +13846;EGYPTIAN HIEROGLYPH-13846;Lo;0;L;;;;;N;;;;; +13847;EGYPTIAN HIEROGLYPH-13847;Lo;0;L;;;;;N;;;;; +13848;EGYPTIAN HIEROGLYPH-13848;Lo;0;L;;;;;N;;;;; +13849;EGYPTIAN HIEROGLYPH-13849;Lo;0;L;;;;;N;;;;; +1384A;EGYPTIAN HIEROGLYPH-1384A;Lo;0;L;;;;;N;;;;; +1384B;EGYPTIAN HIEROGLYPH-1384B;Lo;0;L;;;;;N;;;;; +1384C;EGYPTIAN HIEROGLYPH-1384C;Lo;0;L;;;;;N;;;;; +1384D;EGYPTIAN HIEROGLYPH-1384D;Lo;0;L;;;;;N;;;;; +1384E;EGYPTIAN HIEROGLYPH-1384E;Lo;0;L;;;;;N;;;;; +1384F;EGYPTIAN HIEROGLYPH-1384F;Lo;0;L;;;;;N;;;;; +13850;EGYPTIAN HIEROGLYPH-13850;Lo;0;L;;;;;N;;;;; +13851;EGYPTIAN HIEROGLYPH-13851;Lo;0;L;;;;;N;;;;; +13852;EGYPTIAN HIEROGLYPH-13852;Lo;0;L;;;;;N;;;;; +13853;EGYPTIAN HIEROGLYPH-13853;Lo;0;L;;;;;N;;;;; +13854;EGYPTIAN HIEROGLYPH-13854;Lo;0;L;;;;;N;;;;; +13855;EGYPTIAN HIEROGLYPH-13855;Lo;0;L;;;;;N;;;;; +13856;EGYPTIAN HIEROGLYPH-13856;Lo;0;L;;;;;N;;;;; +13857;EGYPTIAN HIEROGLYPH-13857;Lo;0;L;;;;;N;;;;; +13858;EGYPTIAN HIEROGLYPH-13858;Lo;0;L;;;;;N;;;;; +13859;EGYPTIAN HIEROGLYPH-13859;Lo;0;L;;;;;N;;;;; +1385A;EGYPTIAN HIEROGLYPH-1385A;Lo;0;L;;;;;N;;;;; +1385B;EGYPTIAN HIEROGLYPH-1385B;Lo;0;L;;;;;N;;;;; +1385C;EGYPTIAN HIEROGLYPH-1385C;Lo;0;L;;;;;N;;;;; +1385D;EGYPTIAN HIEROGLYPH-1385D;Lo;0;L;;;;;N;;;;; +1385E;EGYPTIAN HIEROGLYPH-1385E;Lo;0;L;;;;;N;;;;; +1385F;EGYPTIAN HIEROGLYPH-1385F;Lo;0;L;;;;;N;;;;; +13860;EGYPTIAN HIEROGLYPH-13860;Lo;0;L;;;;;N;;;;; +13861;EGYPTIAN HIEROGLYPH-13861;Lo;0;L;;;;;N;;;;; +13862;EGYPTIAN HIEROGLYPH-13862;Lo;0;L;;;;;N;;;;; +13863;EGYPTIAN HIEROGLYPH-13863;Lo;0;L;;;;;N;;;;; +13864;EGYPTIAN HIEROGLYPH-13864;Lo;0;L;;;;;N;;;;; +13865;EGYPTIAN HIEROGLYPH-13865;Lo;0;L;;;;;N;;;;; +13866;EGYPTIAN HIEROGLYPH-13866;Lo;0;L;;;;;N;;;;; +13867;EGYPTIAN HIEROGLYPH-13867;Lo;0;L;;;;;N;;;;; +13868;EGYPTIAN HIEROGLYPH-13868;Lo;0;L;;;;;N;;;;; +13869;EGYPTIAN HIEROGLYPH-13869;Lo;0;L;;;;;N;;;;; +1386A;EGYPTIAN HIEROGLYPH-1386A;Lo;0;L;;;;;N;;;;; +1386B;EGYPTIAN HIEROGLYPH-1386B;Lo;0;L;;;;;N;;;;; +1386C;EGYPTIAN HIEROGLYPH-1386C;Lo;0;L;;;;;N;;;;; +1386D;EGYPTIAN HIEROGLYPH-1386D;Lo;0;L;;;;;N;;;;; +1386E;EGYPTIAN HIEROGLYPH-1386E;Lo;0;L;;;;;N;;;;; +1386F;EGYPTIAN HIEROGLYPH-1386F;Lo;0;L;;;;;N;;;;; +13870;EGYPTIAN HIEROGLYPH-13870;Lo;0;L;;;;;N;;;;; +13871;EGYPTIAN HIEROGLYPH-13871;Lo;0;L;;;;;N;;;;; +13872;EGYPTIAN HIEROGLYPH-13872;Lo;0;L;;;;;N;;;;; +13873;EGYPTIAN HIEROGLYPH-13873;Lo;0;L;;;;;N;;;;; +13874;EGYPTIAN HIEROGLYPH-13874;Lo;0;L;;;;;N;;;;; +13875;EGYPTIAN HIEROGLYPH-13875;Lo;0;L;;;;;N;;;;; +13876;EGYPTIAN HIEROGLYPH-13876;Lo;0;L;;;;;N;;;;; +13877;EGYPTIAN HIEROGLYPH-13877;Lo;0;L;;;;;N;;;;; +13878;EGYPTIAN HIEROGLYPH-13878;Lo;0;L;;;;;N;;;;; +13879;EGYPTIAN HIEROGLYPH-13879;Lo;0;L;;;;;N;;;;; +1387A;EGYPTIAN HIEROGLYPH-1387A;Lo;0;L;;;;;N;;;;; +1387B;EGYPTIAN HIEROGLYPH-1387B;Lo;0;L;;;;;N;;;;; +1387C;EGYPTIAN HIEROGLYPH-1387C;Lo;0;L;;;;;N;;;;; +1387D;EGYPTIAN HIEROGLYPH-1387D;Lo;0;L;;;;;N;;;;; +1387E;EGYPTIAN HIEROGLYPH-1387E;Lo;0;L;;;;;N;;;;; +1387F;EGYPTIAN HIEROGLYPH-1387F;Lo;0;L;;;;;N;;;;; +13880;EGYPTIAN HIEROGLYPH-13880;Lo;0;L;;;;;N;;;;; +13881;EGYPTIAN HIEROGLYPH-13881;Lo;0;L;;;;;N;;;;; +13882;EGYPTIAN HIEROGLYPH-13882;Lo;0;L;;;;;N;;;;; +13883;EGYPTIAN HIEROGLYPH-13883;Lo;0;L;;;;;N;;;;; +13884;EGYPTIAN HIEROGLYPH-13884;Lo;0;L;;;;;N;;;;; +13885;EGYPTIAN HIEROGLYPH-13885;Lo;0;L;;;;;N;;;;; +13886;EGYPTIAN HIEROGLYPH-13886;Lo;0;L;;;;;N;;;;; +13887;EGYPTIAN HIEROGLYPH-13887;Lo;0;L;;;;;N;;;;; +13888;EGYPTIAN HIEROGLYPH-13888;Lo;0;L;;;;;N;;;;; +13889;EGYPTIAN HIEROGLYPH-13889;Lo;0;L;;;;;N;;;;; +1388A;EGYPTIAN HIEROGLYPH-1388A;Lo;0;L;;;;;N;;;;; +1388B;EGYPTIAN HIEROGLYPH-1388B;Lo;0;L;;;;;N;;;;; +1388C;EGYPTIAN HIEROGLYPH-1388C;Lo;0;L;;;;;N;;;;; +1388D;EGYPTIAN HIEROGLYPH-1388D;Lo;0;L;;;;;N;;;;; +1388E;EGYPTIAN HIEROGLYPH-1388E;Lo;0;L;;;;;N;;;;; +1388F;EGYPTIAN HIEROGLYPH-1388F;Lo;0;L;;;;;N;;;;; +13890;EGYPTIAN HIEROGLYPH-13890;Lo;0;L;;;;;N;;;;; +13891;EGYPTIAN HIEROGLYPH-13891;Lo;0;L;;;;;N;;;;; +13892;EGYPTIAN HIEROGLYPH-13892;Lo;0;L;;;;;N;;;;; +13893;EGYPTIAN HIEROGLYPH-13893;Lo;0;L;;;;;N;;;;; +13894;EGYPTIAN HIEROGLYPH-13894;Lo;0;L;;;;;N;;;;; +13895;EGYPTIAN HIEROGLYPH-13895;Lo;0;L;;;;;N;;;;; +13896;EGYPTIAN HIEROGLYPH-13896;Lo;0;L;;;;;N;;;;; +13897;EGYPTIAN HIEROGLYPH-13897;Lo;0;L;;;;;N;;;;; +13898;EGYPTIAN HIEROGLYPH-13898;Lo;0;L;;;;;N;;;;; +13899;EGYPTIAN HIEROGLYPH-13899;Lo;0;L;;;;;N;;;;; +1389A;EGYPTIAN HIEROGLYPH-1389A;Lo;0;L;;;;;N;;;;; +1389B;EGYPTIAN HIEROGLYPH-1389B;Lo;0;L;;;;;N;;;;; +1389C;EGYPTIAN HIEROGLYPH-1389C;Lo;0;L;;;;;N;;;;; +1389D;EGYPTIAN HIEROGLYPH-1389D;Lo;0;L;;;;;N;;;;; +1389E;EGYPTIAN HIEROGLYPH-1389E;Lo;0;L;;;;;N;;;;; +1389F;EGYPTIAN HIEROGLYPH-1389F;Lo;0;L;;;;;N;;;;; +138A0;EGYPTIAN HIEROGLYPH-138A0;Lo;0;L;;;;;N;;;;; +138A1;EGYPTIAN HIEROGLYPH-138A1;Lo;0;L;;;;;N;;;;; +138A2;EGYPTIAN HIEROGLYPH-138A2;Lo;0;L;;;;;N;;;;; +138A3;EGYPTIAN HIEROGLYPH-138A3;Lo;0;L;;;;;N;;;;; +138A4;EGYPTIAN HIEROGLYPH-138A4;Lo;0;L;;;;;N;;;;; +138A5;EGYPTIAN HIEROGLYPH-138A5;Lo;0;L;;;;;N;;;;; +138A6;EGYPTIAN HIEROGLYPH-138A6;Lo;0;L;;;;;N;;;;; +138A7;EGYPTIAN HIEROGLYPH-138A7;Lo;0;L;;;;;N;;;;; +138A8;EGYPTIAN HIEROGLYPH-138A8;Lo;0;L;;;;;N;;;;; +138A9;EGYPTIAN HIEROGLYPH-138A9;Lo;0;L;;;;;N;;;;; +138AA;EGYPTIAN HIEROGLYPH-138AA;Lo;0;L;;;;;N;;;;; +138AB;EGYPTIAN HIEROGLYPH-138AB;Lo;0;L;;;;;N;;;;; +138AC;EGYPTIAN HIEROGLYPH-138AC;Lo;0;L;;;;;N;;;;; +138AD;EGYPTIAN HIEROGLYPH-138AD;Lo;0;L;;;;;N;;;;; +138AE;EGYPTIAN HIEROGLYPH-138AE;Lo;0;L;;;;;N;;;;; +138AF;EGYPTIAN HIEROGLYPH-138AF;Lo;0;L;;;;;N;;;;; +138B0;EGYPTIAN HIEROGLYPH-138B0;Lo;0;L;;;;;N;;;;; +138B1;EGYPTIAN HIEROGLYPH-138B1;Lo;0;L;;;;;N;;;;; +138B2;EGYPTIAN HIEROGLYPH-138B2;Lo;0;L;;;;;N;;;;; +138B3;EGYPTIAN HIEROGLYPH-138B3;Lo;0;L;;;;;N;;;;; +138B4;EGYPTIAN HIEROGLYPH-138B4;Lo;0;L;;;;;N;;;;; +138B5;EGYPTIAN HIEROGLYPH-138B5;Lo;0;L;;;;;N;;;;; +138B6;EGYPTIAN HIEROGLYPH-138B6;Lo;0;L;;;;;N;;;;; +138B7;EGYPTIAN HIEROGLYPH-138B7;Lo;0;L;;;;;N;;;;; +138B8;EGYPTIAN HIEROGLYPH-138B8;Lo;0;L;;;;;N;;;;; +138B9;EGYPTIAN HIEROGLYPH-138B9;Lo;0;L;;;;;N;;;;; +138BA;EGYPTIAN HIEROGLYPH-138BA;Lo;0;L;;;;;N;;;;; +138BB;EGYPTIAN HIEROGLYPH-138BB;Lo;0;L;;;;;N;;;;; +138BC;EGYPTIAN HIEROGLYPH-138BC;Lo;0;L;;;;;N;;;;; +138BD;EGYPTIAN HIEROGLYPH-138BD;Lo;0;L;;;;;N;;;;; +138BE;EGYPTIAN HIEROGLYPH-138BE;Lo;0;L;;;;;N;;;;; +138BF;EGYPTIAN HIEROGLYPH-138BF;Lo;0;L;;;;;N;;;;; +138C0;EGYPTIAN HIEROGLYPH-138C0;Lo;0;L;;;;;N;;;;; +138C1;EGYPTIAN HIEROGLYPH-138C1;Lo;0;L;;;;;N;;;;; +138C2;EGYPTIAN HIEROGLYPH-138C2;Lo;0;L;;;;;N;;;;; +138C3;EGYPTIAN HIEROGLYPH-138C3;Lo;0;L;;;;;N;;;;; +138C4;EGYPTIAN HIEROGLYPH-138C4;Lo;0;L;;;;;N;;;;; +138C5;EGYPTIAN HIEROGLYPH-138C5;Lo;0;L;;;;;N;;;;; +138C6;EGYPTIAN HIEROGLYPH-138C6;Lo;0;L;;;;;N;;;;; +138C7;EGYPTIAN HIEROGLYPH-138C7;Lo;0;L;;;;;N;;;;; +138C8;EGYPTIAN HIEROGLYPH-138C8;Lo;0;L;;;;;N;;;;; +138C9;EGYPTIAN HIEROGLYPH-138C9;Lo;0;L;;;;;N;;;;; +138CA;EGYPTIAN HIEROGLYPH-138CA;Lo;0;L;;;;;N;;;;; +138CB;EGYPTIAN HIEROGLYPH-138CB;Lo;0;L;;;;;N;;;;; +138CC;EGYPTIAN HIEROGLYPH-138CC;Lo;0;L;;;;;N;;;;; +138CD;EGYPTIAN HIEROGLYPH-138CD;Lo;0;L;;;;;N;;;;; +138CE;EGYPTIAN HIEROGLYPH-138CE;Lo;0;L;;;;;N;;;;; +138CF;EGYPTIAN HIEROGLYPH-138CF;Lo;0;L;;;;;N;;;;; +138D0;EGYPTIAN HIEROGLYPH-138D0;Lo;0;L;;;;;N;;;;; +138D1;EGYPTIAN HIEROGLYPH-138D1;Lo;0;L;;;;;N;;;;; +138D2;EGYPTIAN HIEROGLYPH-138D2;Lo;0;L;;;;;N;;;;; +138D3;EGYPTIAN HIEROGLYPH-138D3;Lo;0;L;;;;;N;;;;; +138D4;EGYPTIAN HIEROGLYPH-138D4;Lo;0;L;;;;;N;;;;; +138D5;EGYPTIAN HIEROGLYPH-138D5;Lo;0;L;;;;;N;;;;; +138D6;EGYPTIAN HIEROGLYPH-138D6;Lo;0;L;;;;;N;;;;; +138D7;EGYPTIAN HIEROGLYPH-138D7;Lo;0;L;;;;;N;;;;; +138D8;EGYPTIAN HIEROGLYPH-138D8;Lo;0;L;;;;;N;;;;; +138D9;EGYPTIAN HIEROGLYPH-138D9;Lo;0;L;;;;;N;;;;; +138DA;EGYPTIAN HIEROGLYPH-138DA;Lo;0;L;;;;;N;;;;; +138DB;EGYPTIAN HIEROGLYPH-138DB;Lo;0;L;;;;;N;;;;; +138DC;EGYPTIAN HIEROGLYPH-138DC;Lo;0;L;;;;;N;;;;; +138DD;EGYPTIAN HIEROGLYPH-138DD;Lo;0;L;;;;;N;;;;; +138DE;EGYPTIAN HIEROGLYPH-138DE;Lo;0;L;;;;;N;;;;; +138DF;EGYPTIAN HIEROGLYPH-138DF;Lo;0;L;;;;;N;;;;; +138E0;EGYPTIAN HIEROGLYPH-138E0;Lo;0;L;;;;;N;;;;; +138E1;EGYPTIAN HIEROGLYPH-138E1;Lo;0;L;;;;;N;;;;; +138E2;EGYPTIAN HIEROGLYPH-138E2;Lo;0;L;;;;;N;;;;; +138E3;EGYPTIAN HIEROGLYPH-138E3;Lo;0;L;;;;;N;;;;; +138E4;EGYPTIAN HIEROGLYPH-138E4;Lo;0;L;;;;;N;;;;; +138E5;EGYPTIAN HIEROGLYPH-138E5;Lo;0;L;;;;;N;;;;; +138E6;EGYPTIAN HIEROGLYPH-138E6;Lo;0;L;;;;;N;;;;; +138E7;EGYPTIAN HIEROGLYPH-138E7;Lo;0;L;;;;;N;;;;; +138E8;EGYPTIAN HIEROGLYPH-138E8;Lo;0;L;;;;;N;;;;; +138E9;EGYPTIAN HIEROGLYPH-138E9;Lo;0;L;;;;;N;;;;; +138EA;EGYPTIAN HIEROGLYPH-138EA;Lo;0;L;;;;;N;;;;; +138EB;EGYPTIAN HIEROGLYPH-138EB;Lo;0;L;;;;;N;;;;; +138EC;EGYPTIAN HIEROGLYPH-138EC;Lo;0;L;;;;;N;;;;; +138ED;EGYPTIAN HIEROGLYPH-138ED;Lo;0;L;;;;;N;;;;; +138EE;EGYPTIAN HIEROGLYPH-138EE;Lo;0;L;;;;;N;;;;; +138EF;EGYPTIAN HIEROGLYPH-138EF;Lo;0;L;;;;;N;;;;; +138F0;EGYPTIAN HIEROGLYPH-138F0;Lo;0;L;;;;;N;;;;; +138F1;EGYPTIAN HIEROGLYPH-138F1;Lo;0;L;;;;;N;;;;; +138F2;EGYPTIAN HIEROGLYPH-138F2;Lo;0;L;;;;;N;;;;; +138F3;EGYPTIAN HIEROGLYPH-138F3;Lo;0;L;;;;;N;;;;; +138F4;EGYPTIAN HIEROGLYPH-138F4;Lo;0;L;;;;;N;;;;; +138F5;EGYPTIAN HIEROGLYPH-138F5;Lo;0;L;;;;;N;;;;; +138F6;EGYPTIAN HIEROGLYPH-138F6;Lo;0;L;;;;;N;;;;; +138F7;EGYPTIAN HIEROGLYPH-138F7;Lo;0;L;;;;;N;;;;; +138F8;EGYPTIAN HIEROGLYPH-138F8;Lo;0;L;;;;;N;;;;; +138F9;EGYPTIAN HIEROGLYPH-138F9;Lo;0;L;;;;;N;;;;; +138FA;EGYPTIAN HIEROGLYPH-138FA;Lo;0;L;;;;;N;;;;; +138FB;EGYPTIAN HIEROGLYPH-138FB;Lo;0;L;;;;;N;;;;; +138FC;EGYPTIAN HIEROGLYPH-138FC;Lo;0;L;;;;;N;;;;; +138FD;EGYPTIAN HIEROGLYPH-138FD;Lo;0;L;;;;;N;;;;; +138FE;EGYPTIAN HIEROGLYPH-138FE;Lo;0;L;;;;;N;;;;; +138FF;EGYPTIAN HIEROGLYPH-138FF;Lo;0;L;;;;;N;;;;; +13900;EGYPTIAN HIEROGLYPH-13900;Lo;0;L;;;;;N;;;;; +13901;EGYPTIAN HIEROGLYPH-13901;Lo;0;L;;;;;N;;;;; +13902;EGYPTIAN HIEROGLYPH-13902;Lo;0;L;;;;;N;;;;; +13903;EGYPTIAN HIEROGLYPH-13903;Lo;0;L;;;;;N;;;;; +13904;EGYPTIAN HIEROGLYPH-13904;Lo;0;L;;;;;N;;;;; +13905;EGYPTIAN HIEROGLYPH-13905;Lo;0;L;;;;;N;;;;; +13906;EGYPTIAN HIEROGLYPH-13906;Lo;0;L;;;;;N;;;;; +13907;EGYPTIAN HIEROGLYPH-13907;Lo;0;L;;;;;N;;;;; +13908;EGYPTIAN HIEROGLYPH-13908;Lo;0;L;;;;;N;;;;; +13909;EGYPTIAN HIEROGLYPH-13909;Lo;0;L;;;;;N;;;;; +1390A;EGYPTIAN HIEROGLYPH-1390A;Lo;0;L;;;;;N;;;;; +1390B;EGYPTIAN HIEROGLYPH-1390B;Lo;0;L;;;;;N;;;;; +1390C;EGYPTIAN HIEROGLYPH-1390C;Lo;0;L;;;;;N;;;;; +1390D;EGYPTIAN HIEROGLYPH-1390D;Lo;0;L;;;;;N;;;;; +1390E;EGYPTIAN HIEROGLYPH-1390E;Lo;0;L;;;;;N;;;;; +1390F;EGYPTIAN HIEROGLYPH-1390F;Lo;0;L;;;;;N;;;;; +13910;EGYPTIAN HIEROGLYPH-13910;Lo;0;L;;;;;N;;;;; +13911;EGYPTIAN HIEROGLYPH-13911;Lo;0;L;;;;;N;;;;; +13912;EGYPTIAN HIEROGLYPH-13912;Lo;0;L;;;;;N;;;;; +13913;EGYPTIAN HIEROGLYPH-13913;Lo;0;L;;;;;N;;;;; +13914;EGYPTIAN HIEROGLYPH-13914;Lo;0;L;;;;;N;;;;; +13915;EGYPTIAN HIEROGLYPH-13915;Lo;0;L;;;;;N;;;;; +13916;EGYPTIAN HIEROGLYPH-13916;Lo;0;L;;;;;N;;;;; +13917;EGYPTIAN HIEROGLYPH-13917;Lo;0;L;;;;;N;;;;; +13918;EGYPTIAN HIEROGLYPH-13918;Lo;0;L;;;;;N;;;;; +13919;EGYPTIAN HIEROGLYPH-13919;Lo;0;L;;;;;N;;;;; +1391A;EGYPTIAN HIEROGLYPH-1391A;Lo;0;L;;;;;N;;;;; +1391B;EGYPTIAN HIEROGLYPH-1391B;Lo;0;L;;;;;N;;;;; +1391C;EGYPTIAN HIEROGLYPH-1391C;Lo;0;L;;;;;N;;;;; +1391D;EGYPTIAN HIEROGLYPH-1391D;Lo;0;L;;;;;N;;;;; +1391E;EGYPTIAN HIEROGLYPH-1391E;Lo;0;L;;;;;N;;;;; +1391F;EGYPTIAN HIEROGLYPH-1391F;Lo;0;L;;;;;N;;;;; +13920;EGYPTIAN HIEROGLYPH-13920;Lo;0;L;;;;;N;;;;; +13921;EGYPTIAN HIEROGLYPH-13921;Lo;0;L;;;;;N;;;;; +13922;EGYPTIAN HIEROGLYPH-13922;Lo;0;L;;;;;N;;;;; +13923;EGYPTIAN HIEROGLYPH-13923;Lo;0;L;;;;;N;;;;; +13924;EGYPTIAN HIEROGLYPH-13924;Lo;0;L;;;;;N;;;;; +13925;EGYPTIAN HIEROGLYPH-13925;Lo;0;L;;;;;N;;;;; +13926;EGYPTIAN HIEROGLYPH-13926;Lo;0;L;;;;;N;;;;; +13927;EGYPTIAN HIEROGLYPH-13927;Lo;0;L;;;;;N;;;;; +13928;EGYPTIAN HIEROGLYPH-13928;Lo;0;L;;;;;N;;;;; +13929;EGYPTIAN HIEROGLYPH-13929;Lo;0;L;;;;;N;;;;; +1392A;EGYPTIAN HIEROGLYPH-1392A;Lo;0;L;;;;;N;;;;; +1392B;EGYPTIAN HIEROGLYPH-1392B;Lo;0;L;;;;;N;;;;; +1392C;EGYPTIAN HIEROGLYPH-1392C;Lo;0;L;;;;;N;;;;; +1392D;EGYPTIAN HIEROGLYPH-1392D;Lo;0;L;;;;;N;;;;; +1392E;EGYPTIAN HIEROGLYPH-1392E;Lo;0;L;;;;;N;;;;; +1392F;EGYPTIAN HIEROGLYPH-1392F;Lo;0;L;;;;;N;;;;; +13930;EGYPTIAN HIEROGLYPH-13930;Lo;0;L;;;;;N;;;;; +13931;EGYPTIAN HIEROGLYPH-13931;Lo;0;L;;;;;N;;;;; +13932;EGYPTIAN HIEROGLYPH-13932;Lo;0;L;;;;;N;;;;; +13933;EGYPTIAN HIEROGLYPH-13933;Lo;0;L;;;;;N;;;;; +13934;EGYPTIAN HIEROGLYPH-13934;Lo;0;L;;;;;N;;;;; +13935;EGYPTIAN HIEROGLYPH-13935;Lo;0;L;;;;;N;;;;; +13936;EGYPTIAN HIEROGLYPH-13936;Lo;0;L;;;;;N;;;;; +13937;EGYPTIAN HIEROGLYPH-13937;Lo;0;L;;;;;N;;;;; +13938;EGYPTIAN HIEROGLYPH-13938;Lo;0;L;;;;;N;;;;; +13939;EGYPTIAN HIEROGLYPH-13939;Lo;0;L;;;;;N;;;;; +1393A;EGYPTIAN HIEROGLYPH-1393A;Lo;0;L;;;;;N;;;;; +1393B;EGYPTIAN HIEROGLYPH-1393B;Lo;0;L;;;;;N;;;;; +1393C;EGYPTIAN HIEROGLYPH-1393C;Lo;0;L;;;;;N;;;;; +1393D;EGYPTIAN HIEROGLYPH-1393D;Lo;0;L;;;;;N;;;;; +1393E;EGYPTIAN HIEROGLYPH-1393E;Lo;0;L;;;;;N;;;;; +1393F;EGYPTIAN HIEROGLYPH-1393F;Lo;0;L;;;;;N;;;;; +13940;EGYPTIAN HIEROGLYPH-13940;Lo;0;L;;;;;N;;;;; +13941;EGYPTIAN HIEROGLYPH-13941;Lo;0;L;;;;;N;;;;; +13942;EGYPTIAN HIEROGLYPH-13942;Lo;0;L;;;;;N;;;;; +13943;EGYPTIAN HIEROGLYPH-13943;Lo;0;L;;;;;N;;;;; +13944;EGYPTIAN HIEROGLYPH-13944;Lo;0;L;;;;;N;;;;; +13945;EGYPTIAN HIEROGLYPH-13945;Lo;0;L;;;;;N;;;;; +13946;EGYPTIAN HIEROGLYPH-13946;Lo;0;L;;;;;N;;;;; +13947;EGYPTIAN HIEROGLYPH-13947;Lo;0;L;;;;;N;;;;; +13948;EGYPTIAN HIEROGLYPH-13948;Lo;0;L;;;;;N;;;;; +13949;EGYPTIAN HIEROGLYPH-13949;Lo;0;L;;;;;N;;;;; +1394A;EGYPTIAN HIEROGLYPH-1394A;Lo;0;L;;;;;N;;;;; +1394B;EGYPTIAN HIEROGLYPH-1394B;Lo;0;L;;;;;N;;;;; +1394C;EGYPTIAN HIEROGLYPH-1394C;Lo;0;L;;;;;N;;;;; +1394D;EGYPTIAN HIEROGLYPH-1394D;Lo;0;L;;;;;N;;;;; +1394E;EGYPTIAN HIEROGLYPH-1394E;Lo;0;L;;;;;N;;;;; +1394F;EGYPTIAN HIEROGLYPH-1394F;Lo;0;L;;;;;N;;;;; +13950;EGYPTIAN HIEROGLYPH-13950;Lo;0;L;;;;;N;;;;; +13951;EGYPTIAN HIEROGLYPH-13951;Lo;0;L;;;;;N;;;;; +13952;EGYPTIAN HIEROGLYPH-13952;Lo;0;L;;;;;N;;;;; +13953;EGYPTIAN HIEROGLYPH-13953;Lo;0;L;;;;;N;;;;; +13954;EGYPTIAN HIEROGLYPH-13954;Lo;0;L;;;;;N;;;;; +13955;EGYPTIAN HIEROGLYPH-13955;Lo;0;L;;;;;N;;;;; +13956;EGYPTIAN HIEROGLYPH-13956;Lo;0;L;;;;;N;;;;; +13957;EGYPTIAN HIEROGLYPH-13957;Lo;0;L;;;;;N;;;;; +13958;EGYPTIAN HIEROGLYPH-13958;Lo;0;L;;;;;N;;;;; +13959;EGYPTIAN HIEROGLYPH-13959;Lo;0;L;;;;;N;;;;; +1395A;EGYPTIAN HIEROGLYPH-1395A;Lo;0;L;;;;;N;;;;; +1395B;EGYPTIAN HIEROGLYPH-1395B;Lo;0;L;;;;;N;;;;; +1395C;EGYPTIAN HIEROGLYPH-1395C;Lo;0;L;;;;;N;;;;; +1395D;EGYPTIAN HIEROGLYPH-1395D;Lo;0;L;;;;;N;;;;; +1395E;EGYPTIAN HIEROGLYPH-1395E;Lo;0;L;;;;;N;;;;; +1395F;EGYPTIAN HIEROGLYPH-1395F;Lo;0;L;;;;;N;;;;; +13960;EGYPTIAN HIEROGLYPH-13960;Lo;0;L;;;;;N;;;;; +13961;EGYPTIAN HIEROGLYPH-13961;Lo;0;L;;;;;N;;;;; +13962;EGYPTIAN HIEROGLYPH-13962;Lo;0;L;;;;;N;;;;; +13963;EGYPTIAN HIEROGLYPH-13963;Lo;0;L;;;;;N;;;;; +13964;EGYPTIAN HIEROGLYPH-13964;Lo;0;L;;;;;N;;;;; +13965;EGYPTIAN HIEROGLYPH-13965;Lo;0;L;;;;;N;;;;; +13966;EGYPTIAN HIEROGLYPH-13966;Lo;0;L;;;;;N;;;;; +13967;EGYPTIAN HIEROGLYPH-13967;Lo;0;L;;;;;N;;;;; +13968;EGYPTIAN HIEROGLYPH-13968;Lo;0;L;;;;;N;;;;; +13969;EGYPTIAN HIEROGLYPH-13969;Lo;0;L;;;;;N;;;;; +1396A;EGYPTIAN HIEROGLYPH-1396A;Lo;0;L;;;;;N;;;;; +1396B;EGYPTIAN HIEROGLYPH-1396B;Lo;0;L;;;;;N;;;;; +1396C;EGYPTIAN HIEROGLYPH-1396C;Lo;0;L;;;;;N;;;;; +1396D;EGYPTIAN HIEROGLYPH-1396D;Lo;0;L;;;;;N;;;;; +1396E;EGYPTIAN HIEROGLYPH-1396E;Lo;0;L;;;;;N;;;;; +1396F;EGYPTIAN HIEROGLYPH-1396F;Lo;0;L;;;;;N;;;;; +13970;EGYPTIAN HIEROGLYPH-13970;Lo;0;L;;;;;N;;;;; +13971;EGYPTIAN HIEROGLYPH-13971;Lo;0;L;;;;;N;;;;; +13972;EGYPTIAN HIEROGLYPH-13972;Lo;0;L;;;;;N;;;;; +13973;EGYPTIAN HIEROGLYPH-13973;Lo;0;L;;;;;N;;;;; +13974;EGYPTIAN HIEROGLYPH-13974;Lo;0;L;;;;;N;;;;; +13975;EGYPTIAN HIEROGLYPH-13975;Lo;0;L;;;;;N;;;;; +13976;EGYPTIAN HIEROGLYPH-13976;Lo;0;L;;;;;N;;;;; +13977;EGYPTIAN HIEROGLYPH-13977;Lo;0;L;;;;;N;;;;; +13978;EGYPTIAN HIEROGLYPH-13978;Lo;0;L;;;;;N;;;;; +13979;EGYPTIAN HIEROGLYPH-13979;Lo;0;L;;;;;N;;;;; +1397A;EGYPTIAN HIEROGLYPH-1397A;Lo;0;L;;;;;N;;;;; +1397B;EGYPTIAN HIEROGLYPH-1397B;Lo;0;L;;;;;N;;;;; +1397C;EGYPTIAN HIEROGLYPH-1397C;Lo;0;L;;;;;N;;;;; +1397D;EGYPTIAN HIEROGLYPH-1397D;Lo;0;L;;;;;N;;;;; +1397E;EGYPTIAN HIEROGLYPH-1397E;Lo;0;L;;;;;N;;;;; +1397F;EGYPTIAN HIEROGLYPH-1397F;Lo;0;L;;;;;N;;;;; +13980;EGYPTIAN HIEROGLYPH-13980;Lo;0;L;;;;;N;;;;; +13981;EGYPTIAN HIEROGLYPH-13981;Lo;0;L;;;;;N;;;;; +13982;EGYPTIAN HIEROGLYPH-13982;Lo;0;L;;;;;N;;;;; +13983;EGYPTIAN HIEROGLYPH-13983;Lo;0;L;;;;;N;;;;; +13984;EGYPTIAN HIEROGLYPH-13984;Lo;0;L;;;;;N;;;;; +13985;EGYPTIAN HIEROGLYPH-13985;Lo;0;L;;;;;N;;;;; +13986;EGYPTIAN HIEROGLYPH-13986;Lo;0;L;;;;;N;;;;; +13987;EGYPTIAN HIEROGLYPH-13987;Lo;0;L;;;;;N;;;;; +13988;EGYPTIAN HIEROGLYPH-13988;Lo;0;L;;;;;N;;;;; +13989;EGYPTIAN HIEROGLYPH-13989;Lo;0;L;;;;;N;;;;; +1398A;EGYPTIAN HIEROGLYPH-1398A;Lo;0;L;;;;;N;;;;; +1398B;EGYPTIAN HIEROGLYPH-1398B;Lo;0;L;;;;;N;;;;; +1398C;EGYPTIAN HIEROGLYPH-1398C;Lo;0;L;;;;;N;;;;; +1398D;EGYPTIAN HIEROGLYPH-1398D;Lo;0;L;;;;;N;;;;; +1398E;EGYPTIAN HIEROGLYPH-1398E;Lo;0;L;;;;;N;;;;; +1398F;EGYPTIAN HIEROGLYPH-1398F;Lo;0;L;;;;;N;;;;; +13990;EGYPTIAN HIEROGLYPH-13990;Lo;0;L;;;;;N;;;;; +13991;EGYPTIAN HIEROGLYPH-13991;Lo;0;L;;;;;N;;;;; +13992;EGYPTIAN HIEROGLYPH-13992;Lo;0;L;;;;;N;;;;; +13993;EGYPTIAN HIEROGLYPH-13993;Lo;0;L;;;;;N;;;;; +13994;EGYPTIAN HIEROGLYPH-13994;Lo;0;L;;;;;N;;;;; +13995;EGYPTIAN HIEROGLYPH-13995;Lo;0;L;;;;;N;;;;; +13996;EGYPTIAN HIEROGLYPH-13996;Lo;0;L;;;;;N;;;;; +13997;EGYPTIAN HIEROGLYPH-13997;Lo;0;L;;;;;N;;;;; +13998;EGYPTIAN HIEROGLYPH-13998;Lo;0;L;;;;;N;;;;; +13999;EGYPTIAN HIEROGLYPH-13999;Lo;0;L;;;;;N;;;;; +1399A;EGYPTIAN HIEROGLYPH-1399A;Lo;0;L;;;;;N;;;;; +1399B;EGYPTIAN HIEROGLYPH-1399B;Lo;0;L;;;;;N;;;;; +1399C;EGYPTIAN HIEROGLYPH-1399C;Lo;0;L;;;;;N;;;;; +1399D;EGYPTIAN HIEROGLYPH-1399D;Lo;0;L;;;;;N;;;;; +1399E;EGYPTIAN HIEROGLYPH-1399E;Lo;0;L;;;;;N;;;;; +1399F;EGYPTIAN HIEROGLYPH-1399F;Lo;0;L;;;;;N;;;;; +139A0;EGYPTIAN HIEROGLYPH-139A0;Lo;0;L;;;;;N;;;;; +139A1;EGYPTIAN HIEROGLYPH-139A1;Lo;0;L;;;;;N;;;;; +139A2;EGYPTIAN HIEROGLYPH-139A2;Lo;0;L;;;;;N;;;;; +139A3;EGYPTIAN HIEROGLYPH-139A3;Lo;0;L;;;;;N;;;;; +139A4;EGYPTIAN HIEROGLYPH-139A4;Lo;0;L;;;;;N;;;;; +139A5;EGYPTIAN HIEROGLYPH-139A5;Lo;0;L;;;;;N;;;;; +139A6;EGYPTIAN HIEROGLYPH-139A6;Lo;0;L;;;;;N;;;;; +139A7;EGYPTIAN HIEROGLYPH-139A7;Lo;0;L;;;;;N;;;;; +139A8;EGYPTIAN HIEROGLYPH-139A8;Lo;0;L;;;;;N;;;;; +139A9;EGYPTIAN HIEROGLYPH-139A9;Lo;0;L;;;;;N;;;;; +139AA;EGYPTIAN HIEROGLYPH-139AA;Lo;0;L;;;;;N;;;;; +139AB;EGYPTIAN HIEROGLYPH-139AB;Lo;0;L;;;;;N;;;;; +139AC;EGYPTIAN HIEROGLYPH-139AC;Lo;0;L;;;;;N;;;;; +139AD;EGYPTIAN HIEROGLYPH-139AD;Lo;0;L;;;;;N;;;;; +139AE;EGYPTIAN HIEROGLYPH-139AE;Lo;0;L;;;;;N;;;;; +139AF;EGYPTIAN HIEROGLYPH-139AF;Lo;0;L;;;;;N;;;;; +139B0;EGYPTIAN HIEROGLYPH-139B0;Lo;0;L;;;;;N;;;;; +139B1;EGYPTIAN HIEROGLYPH-139B1;Lo;0;L;;;;;N;;;;; +139B2;EGYPTIAN HIEROGLYPH-139B2;Lo;0;L;;;;;N;;;;; +139B3;EGYPTIAN HIEROGLYPH-139B3;Lo;0;L;;;;;N;;;;; +139B4;EGYPTIAN HIEROGLYPH-139B4;Lo;0;L;;;;;N;;;;; +139B5;EGYPTIAN HIEROGLYPH-139B5;Lo;0;L;;;;;N;;;;; +139B6;EGYPTIAN HIEROGLYPH-139B6;Lo;0;L;;;;;N;;;;; +139B7;EGYPTIAN HIEROGLYPH-139B7;Lo;0;L;;;;;N;;;;; +139B8;EGYPTIAN HIEROGLYPH-139B8;Lo;0;L;;;;;N;;;;; +139B9;EGYPTIAN HIEROGLYPH-139B9;Lo;0;L;;;;;N;;;;; +139BA;EGYPTIAN HIEROGLYPH-139BA;Lo;0;L;;;;;N;;;;; +139BB;EGYPTIAN HIEROGLYPH-139BB;Lo;0;L;;;;;N;;;;; +139BC;EGYPTIAN HIEROGLYPH-139BC;Lo;0;L;;;;;N;;;;; +139BD;EGYPTIAN HIEROGLYPH-139BD;Lo;0;L;;;;;N;;;;; +139BE;EGYPTIAN HIEROGLYPH-139BE;Lo;0;L;;;;;N;;;;; +139BF;EGYPTIAN HIEROGLYPH-139BF;Lo;0;L;;;;;N;;;;; +139C0;EGYPTIAN HIEROGLYPH-139C0;Lo;0;L;;;;;N;;;;; +139C1;EGYPTIAN HIEROGLYPH-139C1;Lo;0;L;;;;;N;;;;; +139C2;EGYPTIAN HIEROGLYPH-139C2;Lo;0;L;;;;;N;;;;; +139C3;EGYPTIAN HIEROGLYPH-139C3;Lo;0;L;;;;;N;;;;; +139C4;EGYPTIAN HIEROGLYPH-139C4;Lo;0;L;;;;;N;;;;; +139C5;EGYPTIAN HIEROGLYPH-139C5;Lo;0;L;;;;;N;;;;; +139C6;EGYPTIAN HIEROGLYPH-139C6;Lo;0;L;;;;;N;;;;; +139C7;EGYPTIAN HIEROGLYPH-139C7;Lo;0;L;;;;;N;;;;; +139C8;EGYPTIAN HIEROGLYPH-139C8;Lo;0;L;;;;;N;;;;; +139C9;EGYPTIAN HIEROGLYPH-139C9;Lo;0;L;;;;;N;;;;; +139CA;EGYPTIAN HIEROGLYPH-139CA;Lo;0;L;;;;;N;;;;; +139CB;EGYPTIAN HIEROGLYPH-139CB;Lo;0;L;;;;;N;;;;; +139CC;EGYPTIAN HIEROGLYPH-139CC;Lo;0;L;;;;;N;;;;; +139CD;EGYPTIAN HIEROGLYPH-139CD;Lo;0;L;;;;;N;;;;; +139CE;EGYPTIAN HIEROGLYPH-139CE;Lo;0;L;;;;;N;;;;; +139CF;EGYPTIAN HIEROGLYPH-139CF;Lo;0;L;;;;;N;;;;; +139D0;EGYPTIAN HIEROGLYPH-139D0;Lo;0;L;;;;;N;;;;; +139D1;EGYPTIAN HIEROGLYPH-139D1;Lo;0;L;;;;;N;;;;; +139D2;EGYPTIAN HIEROGLYPH-139D2;Lo;0;L;;;;;N;;;;; +139D3;EGYPTIAN HIEROGLYPH-139D3;Lo;0;L;;;;;N;;;;; +139D4;EGYPTIAN HIEROGLYPH-139D4;Lo;0;L;;;;;N;;;;; +139D5;EGYPTIAN HIEROGLYPH-139D5;Lo;0;L;;;;;N;;;;; +139D6;EGYPTIAN HIEROGLYPH-139D6;Lo;0;L;;;;;N;;;;; +139D7;EGYPTIAN HIEROGLYPH-139D7;Lo;0;L;;;;;N;;;;; +139D8;EGYPTIAN HIEROGLYPH-139D8;Lo;0;L;;;;;N;;;;; +139D9;EGYPTIAN HIEROGLYPH-139D9;Lo;0;L;;;;;N;;;;; +139DA;EGYPTIAN HIEROGLYPH-139DA;Lo;0;L;;;;;N;;;;; +139DB;EGYPTIAN HIEROGLYPH-139DB;Lo;0;L;;;;;N;;;;; +139DC;EGYPTIAN HIEROGLYPH-139DC;Lo;0;L;;;;;N;;;;; +139DD;EGYPTIAN HIEROGLYPH-139DD;Lo;0;L;;;;;N;;;;; +139DE;EGYPTIAN HIEROGLYPH-139DE;Lo;0;L;;;;;N;;;;; +139DF;EGYPTIAN HIEROGLYPH-139DF;Lo;0;L;;;;;N;;;;; +139E0;EGYPTIAN HIEROGLYPH-139E0;Lo;0;L;;;;;N;;;;; +139E1;EGYPTIAN HIEROGLYPH-139E1;Lo;0;L;;;;;N;;;;; +139E2;EGYPTIAN HIEROGLYPH-139E2;Lo;0;L;;;;;N;;;;; +139E3;EGYPTIAN HIEROGLYPH-139E3;Lo;0;L;;;;;N;;;;; +139E4;EGYPTIAN HIEROGLYPH-139E4;Lo;0;L;;;;;N;;;;; +139E5;EGYPTIAN HIEROGLYPH-139E5;Lo;0;L;;;;;N;;;;; +139E6;EGYPTIAN HIEROGLYPH-139E6;Lo;0;L;;;;;N;;;;; +139E7;EGYPTIAN HIEROGLYPH-139E7;Lo;0;L;;;;;N;;;;; +139E8;EGYPTIAN HIEROGLYPH-139E8;Lo;0;L;;;;;N;;;;; +139E9;EGYPTIAN HIEROGLYPH-139E9;Lo;0;L;;;;;N;;;;; +139EA;EGYPTIAN HIEROGLYPH-139EA;Lo;0;L;;;;;N;;;;; +139EB;EGYPTIAN HIEROGLYPH-139EB;Lo;0;L;;;;;N;;;;; +139EC;EGYPTIAN HIEROGLYPH-139EC;Lo;0;L;;;;;N;;;;; +139ED;EGYPTIAN HIEROGLYPH-139ED;Lo;0;L;;;;;N;;;;; +139EE;EGYPTIAN HIEROGLYPH-139EE;Lo;0;L;;;;;N;;;;; +139EF;EGYPTIAN HIEROGLYPH-139EF;Lo;0;L;;;;;N;;;;; +139F0;EGYPTIAN HIEROGLYPH-139F0;Lo;0;L;;;;;N;;;;; +139F1;EGYPTIAN HIEROGLYPH-139F1;Lo;0;L;;;;;N;;;;; +139F2;EGYPTIAN HIEROGLYPH-139F2;Lo;0;L;;;;;N;;;;; +139F3;EGYPTIAN HIEROGLYPH-139F3;Lo;0;L;;;;;N;;;;; +139F4;EGYPTIAN HIEROGLYPH-139F4;Lo;0;L;;;;;N;;;;; +139F5;EGYPTIAN HIEROGLYPH-139F5;Lo;0;L;;;;;N;;;;; +139F6;EGYPTIAN HIEROGLYPH-139F6;Lo;0;L;;;;;N;;;;; +139F7;EGYPTIAN HIEROGLYPH-139F7;Lo;0;L;;;;;N;;;;; +139F8;EGYPTIAN HIEROGLYPH-139F8;Lo;0;L;;;;;N;;;;; +139F9;EGYPTIAN HIEROGLYPH-139F9;Lo;0;L;;;;;N;;;;; +139FA;EGYPTIAN HIEROGLYPH-139FA;Lo;0;L;;;;;N;;;;; +139FB;EGYPTIAN HIEROGLYPH-139FB;Lo;0;L;;;;;N;;;;; +139FC;EGYPTIAN HIEROGLYPH-139FC;Lo;0;L;;;;;N;;;;; +139FD;EGYPTIAN HIEROGLYPH-139FD;Lo;0;L;;;;;N;;;;; +139FE;EGYPTIAN HIEROGLYPH-139FE;Lo;0;L;;;;;N;;;;; +139FF;EGYPTIAN HIEROGLYPH-139FF;Lo;0;L;;;;;N;;;;; +13A00;EGYPTIAN HIEROGLYPH-13A00;Lo;0;L;;;;;N;;;;; +13A01;EGYPTIAN HIEROGLYPH-13A01;Lo;0;L;;;;;N;;;;; +13A02;EGYPTIAN HIEROGLYPH-13A02;Lo;0;L;;;;;N;;;;; +13A03;EGYPTIAN HIEROGLYPH-13A03;Lo;0;L;;;;;N;;;;; +13A04;EGYPTIAN HIEROGLYPH-13A04;Lo;0;L;;;;;N;;;;; +13A05;EGYPTIAN HIEROGLYPH-13A05;Lo;0;L;;;;;N;;;;; +13A06;EGYPTIAN HIEROGLYPH-13A06;Lo;0;L;;;;;N;;;;; +13A07;EGYPTIAN HIEROGLYPH-13A07;Lo;0;L;;;;;N;;;;; +13A08;EGYPTIAN HIEROGLYPH-13A08;Lo;0;L;;;;;N;;;;; +13A09;EGYPTIAN HIEROGLYPH-13A09;Lo;0;L;;;;;N;;;;; +13A0A;EGYPTIAN HIEROGLYPH-13A0A;Lo;0;L;;;;;N;;;;; +13A0B;EGYPTIAN HIEROGLYPH-13A0B;Lo;0;L;;;;;N;;;;; +13A0C;EGYPTIAN HIEROGLYPH-13A0C;Lo;0;L;;;;;N;;;;; +13A0D;EGYPTIAN HIEROGLYPH-13A0D;Lo;0;L;;;;;N;;;;; +13A0E;EGYPTIAN HIEROGLYPH-13A0E;Lo;0;L;;;;;N;;;;; +13A0F;EGYPTIAN HIEROGLYPH-13A0F;Lo;0;L;;;;;N;;;;; +13A10;EGYPTIAN HIEROGLYPH-13A10;Lo;0;L;;;;;N;;;;; +13A11;EGYPTIAN HIEROGLYPH-13A11;Lo;0;L;;;;;N;;;;; +13A12;EGYPTIAN HIEROGLYPH-13A12;Lo;0;L;;;;;N;;;;; +13A13;EGYPTIAN HIEROGLYPH-13A13;Lo;0;L;;;;;N;;;;; +13A14;EGYPTIAN HIEROGLYPH-13A14;Lo;0;L;;;;;N;;;;; +13A15;EGYPTIAN HIEROGLYPH-13A15;Lo;0;L;;;;;N;;;;; +13A16;EGYPTIAN HIEROGLYPH-13A16;Lo;0;L;;;;;N;;;;; +13A17;EGYPTIAN HIEROGLYPH-13A17;Lo;0;L;;;;;N;;;;; +13A18;EGYPTIAN HIEROGLYPH-13A18;Lo;0;L;;;;;N;;;;; +13A19;EGYPTIAN HIEROGLYPH-13A19;Lo;0;L;;;;;N;;;;; +13A1A;EGYPTIAN HIEROGLYPH-13A1A;Lo;0;L;;;;;N;;;;; +13A1B;EGYPTIAN HIEROGLYPH-13A1B;Lo;0;L;;;;;N;;;;; +13A1C;EGYPTIAN HIEROGLYPH-13A1C;Lo;0;L;;;;;N;;;;; +13A1D;EGYPTIAN HIEROGLYPH-13A1D;Lo;0;L;;;;;N;;;;; +13A1E;EGYPTIAN HIEROGLYPH-13A1E;Lo;0;L;;;;;N;;;;; +13A1F;EGYPTIAN HIEROGLYPH-13A1F;Lo;0;L;;;;;N;;;;; +13A20;EGYPTIAN HIEROGLYPH-13A20;Lo;0;L;;;;;N;;;;; +13A21;EGYPTIAN HIEROGLYPH-13A21;Lo;0;L;;;;;N;;;;; +13A22;EGYPTIAN HIEROGLYPH-13A22;Lo;0;L;;;;;N;;;;; +13A23;EGYPTIAN HIEROGLYPH-13A23;Lo;0;L;;;;;N;;;;; +13A24;EGYPTIAN HIEROGLYPH-13A24;Lo;0;L;;;;;N;;;;; +13A25;EGYPTIAN HIEROGLYPH-13A25;Lo;0;L;;;;;N;;;;; +13A26;EGYPTIAN HIEROGLYPH-13A26;Lo;0;L;;;;;N;;;;; +13A27;EGYPTIAN HIEROGLYPH-13A27;Lo;0;L;;;;;N;;;;; +13A28;EGYPTIAN HIEROGLYPH-13A28;Lo;0;L;;;;;N;;;;; +13A29;EGYPTIAN HIEROGLYPH-13A29;Lo;0;L;;;;;N;;;;; +13A2A;EGYPTIAN HIEROGLYPH-13A2A;Lo;0;L;;;;;N;;;;; +13A2B;EGYPTIAN HIEROGLYPH-13A2B;Lo;0;L;;;;;N;;;;; +13A2C;EGYPTIAN HIEROGLYPH-13A2C;Lo;0;L;;;;;N;;;;; +13A2D;EGYPTIAN HIEROGLYPH-13A2D;Lo;0;L;;;;;N;;;;; +13A2E;EGYPTIAN HIEROGLYPH-13A2E;Lo;0;L;;;;;N;;;;; +13A2F;EGYPTIAN HIEROGLYPH-13A2F;Lo;0;L;;;;;N;;;;; +13A30;EGYPTIAN HIEROGLYPH-13A30;Lo;0;L;;;;;N;;;;; +13A31;EGYPTIAN HIEROGLYPH-13A31;Lo;0;L;;;;;N;;;;; +13A32;EGYPTIAN HIEROGLYPH-13A32;Lo;0;L;;;;;N;;;;; +13A33;EGYPTIAN HIEROGLYPH-13A33;Lo;0;L;;;;;N;;;;; +13A34;EGYPTIAN HIEROGLYPH-13A34;Lo;0;L;;;;;N;;;;; +13A35;EGYPTIAN HIEROGLYPH-13A35;Lo;0;L;;;;;N;;;;; +13A36;EGYPTIAN HIEROGLYPH-13A36;Lo;0;L;;;;;N;;;;; +13A37;EGYPTIAN HIEROGLYPH-13A37;Lo;0;L;;;;;N;;;;; +13A38;EGYPTIAN HIEROGLYPH-13A38;Lo;0;L;;;;;N;;;;; +13A39;EGYPTIAN HIEROGLYPH-13A39;Lo;0;L;;;;;N;;;;; +13A3A;EGYPTIAN HIEROGLYPH-13A3A;Lo;0;L;;;;;N;;;;; +13A3B;EGYPTIAN HIEROGLYPH-13A3B;Lo;0;L;;;;;N;;;;; +13A3C;EGYPTIAN HIEROGLYPH-13A3C;Lo;0;L;;;;;N;;;;; +13A3D;EGYPTIAN HIEROGLYPH-13A3D;Lo;0;L;;;;;N;;;;; +13A3E;EGYPTIAN HIEROGLYPH-13A3E;Lo;0;L;;;;;N;;;;; +13A3F;EGYPTIAN HIEROGLYPH-13A3F;Lo;0;L;;;;;N;;;;; +13A40;EGYPTIAN HIEROGLYPH-13A40;Lo;0;L;;;;;N;;;;; +13A41;EGYPTIAN HIEROGLYPH-13A41;Lo;0;L;;;;;N;;;;; +13A42;EGYPTIAN HIEROGLYPH-13A42;Lo;0;L;;;;;N;;;;; +13A43;EGYPTIAN HIEROGLYPH-13A43;Lo;0;L;;;;;N;;;;; +13A44;EGYPTIAN HIEROGLYPH-13A44;Lo;0;L;;;;;N;;;;; +13A45;EGYPTIAN HIEROGLYPH-13A45;Lo;0;L;;;;;N;;;;; +13A46;EGYPTIAN HIEROGLYPH-13A46;Lo;0;L;;;;;N;;;;; +13A47;EGYPTIAN HIEROGLYPH-13A47;Lo;0;L;;;;;N;;;;; +13A48;EGYPTIAN HIEROGLYPH-13A48;Lo;0;L;;;;;N;;;;; +13A49;EGYPTIAN HIEROGLYPH-13A49;Lo;0;L;;;;;N;;;;; +13A4A;EGYPTIAN HIEROGLYPH-13A4A;Lo;0;L;;;;;N;;;;; +13A4B;EGYPTIAN HIEROGLYPH-13A4B;Lo;0;L;;;;;N;;;;; +13A4C;EGYPTIAN HIEROGLYPH-13A4C;Lo;0;L;;;;;N;;;;; +13A4D;EGYPTIAN HIEROGLYPH-13A4D;Lo;0;L;;;;;N;;;;; +13A4E;EGYPTIAN HIEROGLYPH-13A4E;Lo;0;L;;;;;N;;;;; +13A4F;EGYPTIAN HIEROGLYPH-13A4F;Lo;0;L;;;;;N;;;;; +13A50;EGYPTIAN HIEROGLYPH-13A50;Lo;0;L;;;;;N;;;;; +13A51;EGYPTIAN HIEROGLYPH-13A51;Lo;0;L;;;;;N;;;;; +13A52;EGYPTIAN HIEROGLYPH-13A52;Lo;0;L;;;;;N;;;;; +13A53;EGYPTIAN HIEROGLYPH-13A53;Lo;0;L;;;;;N;;;;; +13A54;EGYPTIAN HIEROGLYPH-13A54;Lo;0;L;;;;;N;;;;; +13A55;EGYPTIAN HIEROGLYPH-13A55;Lo;0;L;;;;;N;;;;; +13A56;EGYPTIAN HIEROGLYPH-13A56;Lo;0;L;;;;;N;;;;; +13A57;EGYPTIAN HIEROGLYPH-13A57;Lo;0;L;;;;;N;;;;; +13A58;EGYPTIAN HIEROGLYPH-13A58;Lo;0;L;;;;;N;;;;; +13A59;EGYPTIAN HIEROGLYPH-13A59;Lo;0;L;;;;;N;;;;; +13A5A;EGYPTIAN HIEROGLYPH-13A5A;Lo;0;L;;;;;N;;;;; +13A5B;EGYPTIAN HIEROGLYPH-13A5B;Lo;0;L;;;;;N;;;;; +13A5C;EGYPTIAN HIEROGLYPH-13A5C;Lo;0;L;;;;;N;;;;; +13A5D;EGYPTIAN HIEROGLYPH-13A5D;Lo;0;L;;;;;N;;;;; +13A5E;EGYPTIAN HIEROGLYPH-13A5E;Lo;0;L;;;;;N;;;;; +13A5F;EGYPTIAN HIEROGLYPH-13A5F;Lo;0;L;;;;;N;;;;; +13A60;EGYPTIAN HIEROGLYPH-13A60;Lo;0;L;;;;;N;;;;; +13A61;EGYPTIAN HIEROGLYPH-13A61;Lo;0;L;;;;;N;;;;; +13A62;EGYPTIAN HIEROGLYPH-13A62;Lo;0;L;;;;;N;;;;; +13A63;EGYPTIAN HIEROGLYPH-13A63;Lo;0;L;;;;;N;;;;; +13A64;EGYPTIAN HIEROGLYPH-13A64;Lo;0;L;;;;;N;;;;; +13A65;EGYPTIAN HIEROGLYPH-13A65;Lo;0;L;;;;;N;;;;; +13A66;EGYPTIAN HIEROGLYPH-13A66;Lo;0;L;;;;;N;;;;; +13A67;EGYPTIAN HIEROGLYPH-13A67;Lo;0;L;;;;;N;;;;; +13A68;EGYPTIAN HIEROGLYPH-13A68;Lo;0;L;;;;;N;;;;; +13A69;EGYPTIAN HIEROGLYPH-13A69;Lo;0;L;;;;;N;;;;; +13A6A;EGYPTIAN HIEROGLYPH-13A6A;Lo;0;L;;;;;N;;;;; +13A6B;EGYPTIAN HIEROGLYPH-13A6B;Lo;0;L;;;;;N;;;;; +13A6C;EGYPTIAN HIEROGLYPH-13A6C;Lo;0;L;;;;;N;;;;; +13A6D;EGYPTIAN HIEROGLYPH-13A6D;Lo;0;L;;;;;N;;;;; +13A6E;EGYPTIAN HIEROGLYPH-13A6E;Lo;0;L;;;;;N;;;;; +13A6F;EGYPTIAN HIEROGLYPH-13A6F;Lo;0;L;;;;;N;;;;; +13A70;EGYPTIAN HIEROGLYPH-13A70;Lo;0;L;;;;;N;;;;; +13A71;EGYPTIAN HIEROGLYPH-13A71;Lo;0;L;;;;;N;;;;; +13A72;EGYPTIAN HIEROGLYPH-13A72;Lo;0;L;;;;;N;;;;; +13A73;EGYPTIAN HIEROGLYPH-13A73;Lo;0;L;;;;;N;;;;; +13A74;EGYPTIAN HIEROGLYPH-13A74;Lo;0;L;;;;;N;;;;; +13A75;EGYPTIAN HIEROGLYPH-13A75;Lo;0;L;;;;;N;;;;; +13A76;EGYPTIAN HIEROGLYPH-13A76;Lo;0;L;;;;;N;;;;; +13A77;EGYPTIAN HIEROGLYPH-13A77;Lo;0;L;;;;;N;;;;; +13A78;EGYPTIAN HIEROGLYPH-13A78;Lo;0;L;;;;;N;;;;; +13A79;EGYPTIAN HIEROGLYPH-13A79;Lo;0;L;;;;;N;;;;; +13A7A;EGYPTIAN HIEROGLYPH-13A7A;Lo;0;L;;;;;N;;;;; +13A7B;EGYPTIAN HIEROGLYPH-13A7B;Lo;0;L;;;;;N;;;;; +13A7C;EGYPTIAN HIEROGLYPH-13A7C;Lo;0;L;;;;;N;;;;; +13A7D;EGYPTIAN HIEROGLYPH-13A7D;Lo;0;L;;;;;N;;;;; +13A7E;EGYPTIAN HIEROGLYPH-13A7E;Lo;0;L;;;;;N;;;;; +13A7F;EGYPTIAN HIEROGLYPH-13A7F;Lo;0;L;;;;;N;;;;; +13A80;EGYPTIAN HIEROGLYPH-13A80;Lo;0;L;;;;;N;;;;; +13A81;EGYPTIAN HIEROGLYPH-13A81;Lo;0;L;;;;;N;;;;; +13A82;EGYPTIAN HIEROGLYPH-13A82;Lo;0;L;;;;;N;;;;; +13A83;EGYPTIAN HIEROGLYPH-13A83;Lo;0;L;;;;;N;;;;; +13A84;EGYPTIAN HIEROGLYPH-13A84;Lo;0;L;;;;;N;;;;; +13A85;EGYPTIAN HIEROGLYPH-13A85;Lo;0;L;;;;;N;;;;; +13A86;EGYPTIAN HIEROGLYPH-13A86;Lo;0;L;;;;;N;;;;; +13A87;EGYPTIAN HIEROGLYPH-13A87;Lo;0;L;;;;;N;;;;; +13A88;EGYPTIAN HIEROGLYPH-13A88;Lo;0;L;;;;;N;;;;; +13A89;EGYPTIAN HIEROGLYPH-13A89;Lo;0;L;;;;;N;;;;; +13A8A;EGYPTIAN HIEROGLYPH-13A8A;Lo;0;L;;;;;N;;;;; +13A8B;EGYPTIAN HIEROGLYPH-13A8B;Lo;0;L;;;;;N;;;;; +13A8C;EGYPTIAN HIEROGLYPH-13A8C;Lo;0;L;;;;;N;;;;; +13A8D;EGYPTIAN HIEROGLYPH-13A8D;Lo;0;L;;;;;N;;;;; +13A8E;EGYPTIAN HIEROGLYPH-13A8E;Lo;0;L;;;;;N;;;;; +13A8F;EGYPTIAN HIEROGLYPH-13A8F;Lo;0;L;;;;;N;;;;; +13A90;EGYPTIAN HIEROGLYPH-13A90;Lo;0;L;;;;;N;;;;; +13A91;EGYPTIAN HIEROGLYPH-13A91;Lo;0;L;;;;;N;;;;; +13A92;EGYPTIAN HIEROGLYPH-13A92;Lo;0;L;;;;;N;;;;; +13A93;EGYPTIAN HIEROGLYPH-13A93;Lo;0;L;;;;;N;;;;; +13A94;EGYPTIAN HIEROGLYPH-13A94;Lo;0;L;;;;;N;;;;; +13A95;EGYPTIAN HIEROGLYPH-13A95;Lo;0;L;;;;;N;;;;; +13A96;EGYPTIAN HIEROGLYPH-13A96;Lo;0;L;;;;;N;;;;; +13A97;EGYPTIAN HIEROGLYPH-13A97;Lo;0;L;;;;;N;;;;; +13A98;EGYPTIAN HIEROGLYPH-13A98;Lo;0;L;;;;;N;;;;; +13A99;EGYPTIAN HIEROGLYPH-13A99;Lo;0;L;;;;;N;;;;; +13A9A;EGYPTIAN HIEROGLYPH-13A9A;Lo;0;L;;;;;N;;;;; +13A9B;EGYPTIAN HIEROGLYPH-13A9B;Lo;0;L;;;;;N;;;;; +13A9C;EGYPTIAN HIEROGLYPH-13A9C;Lo;0;L;;;;;N;;;;; +13A9D;EGYPTIAN HIEROGLYPH-13A9D;Lo;0;L;;;;;N;;;;; +13A9E;EGYPTIAN HIEROGLYPH-13A9E;Lo;0;L;;;;;N;;;;; +13A9F;EGYPTIAN HIEROGLYPH-13A9F;Lo;0;L;;;;;N;;;;; +13AA0;EGYPTIAN HIEROGLYPH-13AA0;Lo;0;L;;;;;N;;;;; +13AA1;EGYPTIAN HIEROGLYPH-13AA1;Lo;0;L;;;;;N;;;;; +13AA2;EGYPTIAN HIEROGLYPH-13AA2;Lo;0;L;;;;;N;;;;; +13AA3;EGYPTIAN HIEROGLYPH-13AA3;Lo;0;L;;;;;N;;;;; +13AA4;EGYPTIAN HIEROGLYPH-13AA4;Lo;0;L;;;;;N;;;;; +13AA5;EGYPTIAN HIEROGLYPH-13AA5;Lo;0;L;;;;;N;;;;; +13AA6;EGYPTIAN HIEROGLYPH-13AA6;Lo;0;L;;;;;N;;;;; +13AA7;EGYPTIAN HIEROGLYPH-13AA7;Lo;0;L;;;;;N;;;;; +13AA8;EGYPTIAN HIEROGLYPH-13AA8;Lo;0;L;;;;;N;;;;; +13AA9;EGYPTIAN HIEROGLYPH-13AA9;Lo;0;L;;;;;N;;;;; +13AAA;EGYPTIAN HIEROGLYPH-13AAA;Lo;0;L;;;;;N;;;;; +13AAB;EGYPTIAN HIEROGLYPH-13AAB;Lo;0;L;;;;;N;;;;; +13AAC;EGYPTIAN HIEROGLYPH-13AAC;Lo;0;L;;;;;N;;;;; +13AAD;EGYPTIAN HIEROGLYPH-13AAD;Lo;0;L;;;;;N;;;;; +13AAE;EGYPTIAN HIEROGLYPH-13AAE;Lo;0;L;;;;;N;;;;; +13AAF;EGYPTIAN HIEROGLYPH-13AAF;Lo;0;L;;;;;N;;;;; +13AB0;EGYPTIAN HIEROGLYPH-13AB0;Lo;0;L;;;;;N;;;;; +13AB1;EGYPTIAN HIEROGLYPH-13AB1;Lo;0;L;;;;;N;;;;; +13AB2;EGYPTIAN HIEROGLYPH-13AB2;Lo;0;L;;;;;N;;;;; +13AB3;EGYPTIAN HIEROGLYPH-13AB3;Lo;0;L;;;;;N;;;;; +13AB4;EGYPTIAN HIEROGLYPH-13AB4;Lo;0;L;;;;;N;;;;; +13AB5;EGYPTIAN HIEROGLYPH-13AB5;Lo;0;L;;;;;N;;;;; +13AB6;EGYPTIAN HIEROGLYPH-13AB6;Lo;0;L;;;;;N;;;;; +13AB7;EGYPTIAN HIEROGLYPH-13AB7;Lo;0;L;;;;;N;;;;; +13AB8;EGYPTIAN HIEROGLYPH-13AB8;Lo;0;L;;;;;N;;;;; +13AB9;EGYPTIAN HIEROGLYPH-13AB9;Lo;0;L;;;;;N;;;;; +13ABA;EGYPTIAN HIEROGLYPH-13ABA;Lo;0;L;;;;;N;;;;; +13ABB;EGYPTIAN HIEROGLYPH-13ABB;Lo;0;L;;;;;N;;;;; +13ABC;EGYPTIAN HIEROGLYPH-13ABC;Lo;0;L;;;;;N;;;;; +13ABD;EGYPTIAN HIEROGLYPH-13ABD;Lo;0;L;;;;;N;;;;; +13ABE;EGYPTIAN HIEROGLYPH-13ABE;Lo;0;L;;;;;N;;;;; +13ABF;EGYPTIAN HIEROGLYPH-13ABF;Lo;0;L;;;;;N;;;;; +13AC0;EGYPTIAN HIEROGLYPH-13AC0;Lo;0;L;;;;;N;;;;; +13AC1;EGYPTIAN HIEROGLYPH-13AC1;Lo;0;L;;;;;N;;;;; +13AC2;EGYPTIAN HIEROGLYPH-13AC2;Lo;0;L;;;;;N;;;;; +13AC3;EGYPTIAN HIEROGLYPH-13AC3;Lo;0;L;;;;;N;;;;; +13AC4;EGYPTIAN HIEROGLYPH-13AC4;Lo;0;L;;;;;N;;;;; +13AC5;EGYPTIAN HIEROGLYPH-13AC5;Lo;0;L;;;;;N;;;;; +13AC6;EGYPTIAN HIEROGLYPH-13AC6;Lo;0;L;;;;;N;;;;; +13AC7;EGYPTIAN HIEROGLYPH-13AC7;Lo;0;L;;;;;N;;;;; +13AC8;EGYPTIAN HIEROGLYPH-13AC8;Lo;0;L;;;;;N;;;;; +13AC9;EGYPTIAN HIEROGLYPH-13AC9;Lo;0;L;;;;;N;;;;; +13ACA;EGYPTIAN HIEROGLYPH-13ACA;Lo;0;L;;;;;N;;;;; +13ACB;EGYPTIAN HIEROGLYPH-13ACB;Lo;0;L;;;;;N;;;;; +13ACC;EGYPTIAN HIEROGLYPH-13ACC;Lo;0;L;;;;;N;;;;; +13ACD;EGYPTIAN HIEROGLYPH-13ACD;Lo;0;L;;;;;N;;;;; +13ACE;EGYPTIAN HIEROGLYPH-13ACE;Lo;0;L;;;;;N;;;;; +13ACF;EGYPTIAN HIEROGLYPH-13ACF;Lo;0;L;;;;;N;;;;; +13AD0;EGYPTIAN HIEROGLYPH-13AD0;Lo;0;L;;;;;N;;;;; +13AD1;EGYPTIAN HIEROGLYPH-13AD1;Lo;0;L;;;;;N;;;;; +13AD2;EGYPTIAN HIEROGLYPH-13AD2;Lo;0;L;;;;;N;;;;; +13AD3;EGYPTIAN HIEROGLYPH-13AD3;Lo;0;L;;;;;N;;;;; +13AD4;EGYPTIAN HIEROGLYPH-13AD4;Lo;0;L;;;;;N;;;;; +13AD5;EGYPTIAN HIEROGLYPH-13AD5;Lo;0;L;;;;;N;;;;; +13AD6;EGYPTIAN HIEROGLYPH-13AD6;Lo;0;L;;;;;N;;;;; +13AD7;EGYPTIAN HIEROGLYPH-13AD7;Lo;0;L;;;;;N;;;;; +13AD8;EGYPTIAN HIEROGLYPH-13AD8;Lo;0;L;;;;;N;;;;; +13AD9;EGYPTIAN HIEROGLYPH-13AD9;Lo;0;L;;;;;N;;;;; +13ADA;EGYPTIAN HIEROGLYPH-13ADA;Lo;0;L;;;;;N;;;;; +13ADB;EGYPTIAN HIEROGLYPH-13ADB;Lo;0;L;;;;;N;;;;; +13ADC;EGYPTIAN HIEROGLYPH-13ADC;Lo;0;L;;;;;N;;;;; +13ADD;EGYPTIAN HIEROGLYPH-13ADD;Lo;0;L;;;;;N;;;;; +13ADE;EGYPTIAN HIEROGLYPH-13ADE;Lo;0;L;;;;;N;;;;; +13ADF;EGYPTIAN HIEROGLYPH-13ADF;Lo;0;L;;;;;N;;;;; +13AE0;EGYPTIAN HIEROGLYPH-13AE0;Lo;0;L;;;;;N;;;;; +13AE1;EGYPTIAN HIEROGLYPH-13AE1;Lo;0;L;;;;;N;;;;; +13AE2;EGYPTIAN HIEROGLYPH-13AE2;Lo;0;L;;;;;N;;;;; +13AE3;EGYPTIAN HIEROGLYPH-13AE3;Lo;0;L;;;;;N;;;;; +13AE4;EGYPTIAN HIEROGLYPH-13AE4;Lo;0;L;;;;;N;;;;; +13AE5;EGYPTIAN HIEROGLYPH-13AE5;Lo;0;L;;;;;N;;;;; +13AE6;EGYPTIAN HIEROGLYPH-13AE6;Lo;0;L;;;;;N;;;;; +13AE7;EGYPTIAN HIEROGLYPH-13AE7;Lo;0;L;;;;;N;;;;; +13AE8;EGYPTIAN HIEROGLYPH-13AE8;Lo;0;L;;;;;N;;;;; +13AE9;EGYPTIAN HIEROGLYPH-13AE9;Lo;0;L;;;;;N;;;;; +13AEA;EGYPTIAN HIEROGLYPH-13AEA;Lo;0;L;;;;;N;;;;; +13AEB;EGYPTIAN HIEROGLYPH-13AEB;Lo;0;L;;;;;N;;;;; +13AEC;EGYPTIAN HIEROGLYPH-13AEC;Lo;0;L;;;;;N;;;;; +13AED;EGYPTIAN HIEROGLYPH-13AED;Lo;0;L;;;;;N;;;;; +13AEE;EGYPTIAN HIEROGLYPH-13AEE;Lo;0;L;;;;;N;;;;; +13AEF;EGYPTIAN HIEROGLYPH-13AEF;Lo;0;L;;;;;N;;;;; +13AF0;EGYPTIAN HIEROGLYPH-13AF0;Lo;0;L;;;;;N;;;;; +13AF1;EGYPTIAN HIEROGLYPH-13AF1;Lo;0;L;;;;;N;;;;; +13AF2;EGYPTIAN HIEROGLYPH-13AF2;Lo;0;L;;;;;N;;;;; +13AF3;EGYPTIAN HIEROGLYPH-13AF3;Lo;0;L;;;;;N;;;;; +13AF4;EGYPTIAN HIEROGLYPH-13AF4;Lo;0;L;;;;;N;;;;; +13AF5;EGYPTIAN HIEROGLYPH-13AF5;Lo;0;L;;;;;N;;;;; +13AF6;EGYPTIAN HIEROGLYPH-13AF6;Lo;0;L;;;;;N;;;;; +13AF7;EGYPTIAN HIEROGLYPH-13AF7;Lo;0;L;;;;;N;;;;; +13AF8;EGYPTIAN HIEROGLYPH-13AF8;Lo;0;L;;;;;N;;;;; +13AF9;EGYPTIAN HIEROGLYPH-13AF9;Lo;0;L;;;;;N;;;;; +13AFA;EGYPTIAN HIEROGLYPH-13AFA;Lo;0;L;;;;;N;;;;; +13AFB;EGYPTIAN HIEROGLYPH-13AFB;Lo;0;L;;;;;N;;;;; +13AFC;EGYPTIAN HIEROGLYPH-13AFC;Lo;0;L;;;;;N;;;;; +13AFD;EGYPTIAN HIEROGLYPH-13AFD;Lo;0;L;;;;;N;;;;; +13AFE;EGYPTIAN HIEROGLYPH-13AFE;Lo;0;L;;;;;N;;;;; +13AFF;EGYPTIAN HIEROGLYPH-13AFF;Lo;0;L;;;;;N;;;;; +13B00;EGYPTIAN HIEROGLYPH-13B00;Lo;0;L;;;;;N;;;;; +13B01;EGYPTIAN HIEROGLYPH-13B01;Lo;0;L;;;;;N;;;;; +13B02;EGYPTIAN HIEROGLYPH-13B02;Lo;0;L;;;;;N;;;;; +13B03;EGYPTIAN HIEROGLYPH-13B03;Lo;0;L;;;;;N;;;;; +13B04;EGYPTIAN HIEROGLYPH-13B04;Lo;0;L;;;;;N;;;;; +13B05;EGYPTIAN HIEROGLYPH-13B05;Lo;0;L;;;;;N;;;;; +13B06;EGYPTIAN HIEROGLYPH-13B06;Lo;0;L;;;;;N;;;;; +13B07;EGYPTIAN HIEROGLYPH-13B07;Lo;0;L;;;;;N;;;;; +13B08;EGYPTIAN HIEROGLYPH-13B08;Lo;0;L;;;;;N;;;;; +13B09;EGYPTIAN HIEROGLYPH-13B09;Lo;0;L;;;;;N;;;;; +13B0A;EGYPTIAN HIEROGLYPH-13B0A;Lo;0;L;;;;;N;;;;; +13B0B;EGYPTIAN HIEROGLYPH-13B0B;Lo;0;L;;;;;N;;;;; +13B0C;EGYPTIAN HIEROGLYPH-13B0C;Lo;0;L;;;;;N;;;;; +13B0D;EGYPTIAN HIEROGLYPH-13B0D;Lo;0;L;;;;;N;;;;; +13B0E;EGYPTIAN HIEROGLYPH-13B0E;Lo;0;L;;;;;N;;;;; +13B0F;EGYPTIAN HIEROGLYPH-13B0F;Lo;0;L;;;;;N;;;;; +13B10;EGYPTIAN HIEROGLYPH-13B10;Lo;0;L;;;;;N;;;;; +13B11;EGYPTIAN HIEROGLYPH-13B11;Lo;0;L;;;;;N;;;;; +13B12;EGYPTIAN HIEROGLYPH-13B12;Lo;0;L;;;;;N;;;;; +13B13;EGYPTIAN HIEROGLYPH-13B13;Lo;0;L;;;;;N;;;;; +13B14;EGYPTIAN HIEROGLYPH-13B14;Lo;0;L;;;;;N;;;;; +13B15;EGYPTIAN HIEROGLYPH-13B15;Lo;0;L;;;;;N;;;;; +13B16;EGYPTIAN HIEROGLYPH-13B16;Lo;0;L;;;;;N;;;;; +13B17;EGYPTIAN HIEROGLYPH-13B17;Lo;0;L;;;;;N;;;;; +13B18;EGYPTIAN HIEROGLYPH-13B18;Lo;0;L;;;;;N;;;;; +13B19;EGYPTIAN HIEROGLYPH-13B19;Lo;0;L;;;;;N;;;;; +13B1A;EGYPTIAN HIEROGLYPH-13B1A;Lo;0;L;;;;;N;;;;; +13B1B;EGYPTIAN HIEROGLYPH-13B1B;Lo;0;L;;;;;N;;;;; +13B1C;EGYPTIAN HIEROGLYPH-13B1C;Lo;0;L;;;;;N;;;;; +13B1D;EGYPTIAN HIEROGLYPH-13B1D;Lo;0;L;;;;;N;;;;; +13B1E;EGYPTIAN HIEROGLYPH-13B1E;Lo;0;L;;;;;N;;;;; +13B1F;EGYPTIAN HIEROGLYPH-13B1F;Lo;0;L;;;;;N;;;;; +13B20;EGYPTIAN HIEROGLYPH-13B20;Lo;0;L;;;;;N;;;;; +13B21;EGYPTIAN HIEROGLYPH-13B21;Lo;0;L;;;;;N;;;;; +13B22;EGYPTIAN HIEROGLYPH-13B22;Lo;0;L;;;;;N;;;;; +13B23;EGYPTIAN HIEROGLYPH-13B23;Lo;0;L;;;;;N;;;;; +13B24;EGYPTIAN HIEROGLYPH-13B24;Lo;0;L;;;;;N;;;;; +13B25;EGYPTIAN HIEROGLYPH-13B25;Lo;0;L;;;;;N;;;;; +13B26;EGYPTIAN HIEROGLYPH-13B26;Lo;0;L;;;;;N;;;;; +13B27;EGYPTIAN HIEROGLYPH-13B27;Lo;0;L;;;;;N;;;;; +13B28;EGYPTIAN HIEROGLYPH-13B28;Lo;0;L;;;;;N;;;;; +13B29;EGYPTIAN HIEROGLYPH-13B29;Lo;0;L;;;;;N;;;;; +13B2A;EGYPTIAN HIEROGLYPH-13B2A;Lo;0;L;;;;;N;;;;; +13B2B;EGYPTIAN HIEROGLYPH-13B2B;Lo;0;L;;;;;N;;;;; +13B2C;EGYPTIAN HIEROGLYPH-13B2C;Lo;0;L;;;;;N;;;;; +13B2D;EGYPTIAN HIEROGLYPH-13B2D;Lo;0;L;;;;;N;;;;; +13B2E;EGYPTIAN HIEROGLYPH-13B2E;Lo;0;L;;;;;N;;;;; +13B2F;EGYPTIAN HIEROGLYPH-13B2F;Lo;0;L;;;;;N;;;;; +13B30;EGYPTIAN HIEROGLYPH-13B30;Lo;0;L;;;;;N;;;;; +13B31;EGYPTIAN HIEROGLYPH-13B31;Lo;0;L;;;;;N;;;;; +13B32;EGYPTIAN HIEROGLYPH-13B32;Lo;0;L;;;;;N;;;;; +13B33;EGYPTIAN HIEROGLYPH-13B33;Lo;0;L;;;;;N;;;;; +13B34;EGYPTIAN HIEROGLYPH-13B34;Lo;0;L;;;;;N;;;;; +13B35;EGYPTIAN HIEROGLYPH-13B35;Lo;0;L;;;;;N;;;;; +13B36;EGYPTIAN HIEROGLYPH-13B36;Lo;0;L;;;;;N;;;;; +13B37;EGYPTIAN HIEROGLYPH-13B37;Lo;0;L;;;;;N;;;;; +13B38;EGYPTIAN HIEROGLYPH-13B38;Lo;0;L;;;;;N;;;;; +13B39;EGYPTIAN HIEROGLYPH-13B39;Lo;0;L;;;;;N;;;;; +13B3A;EGYPTIAN HIEROGLYPH-13B3A;Lo;0;L;;;;;N;;;;; +13B3B;EGYPTIAN HIEROGLYPH-13B3B;Lo;0;L;;;;;N;;;;; +13B3C;EGYPTIAN HIEROGLYPH-13B3C;Lo;0;L;;;;;N;;;;; +13B3D;EGYPTIAN HIEROGLYPH-13B3D;Lo;0;L;;;;;N;;;;; +13B3E;EGYPTIAN HIEROGLYPH-13B3E;Lo;0;L;;;;;N;;;;; +13B3F;EGYPTIAN HIEROGLYPH-13B3F;Lo;0;L;;;;;N;;;;; +13B40;EGYPTIAN HIEROGLYPH-13B40;Lo;0;L;;;;;N;;;;; +13B41;EGYPTIAN HIEROGLYPH-13B41;Lo;0;L;;;;;N;;;;; +13B42;EGYPTIAN HIEROGLYPH-13B42;Lo;0;L;;;;;N;;;;; +13B43;EGYPTIAN HIEROGLYPH-13B43;Lo;0;L;;;;;N;;;;; +13B44;EGYPTIAN HIEROGLYPH-13B44;Lo;0;L;;;;;N;;;;; +13B45;EGYPTIAN HIEROGLYPH-13B45;Lo;0;L;;;;;N;;;;; +13B46;EGYPTIAN HIEROGLYPH-13B46;Lo;0;L;;;;;N;;;;; +13B47;EGYPTIAN HIEROGLYPH-13B47;Lo;0;L;;;;;N;;;;; +13B48;EGYPTIAN HIEROGLYPH-13B48;Lo;0;L;;;;;N;;;;; +13B49;EGYPTIAN HIEROGLYPH-13B49;Lo;0;L;;;;;N;;;;; +13B4A;EGYPTIAN HIEROGLYPH-13B4A;Lo;0;L;;;;;N;;;;; +13B4B;EGYPTIAN HIEROGLYPH-13B4B;Lo;0;L;;;;;N;;;;; +13B4C;EGYPTIAN HIEROGLYPH-13B4C;Lo;0;L;;;;;N;;;;; +13B4D;EGYPTIAN HIEROGLYPH-13B4D;Lo;0;L;;;;;N;;;;; +13B4E;EGYPTIAN HIEROGLYPH-13B4E;Lo;0;L;;;;;N;;;;; +13B4F;EGYPTIAN HIEROGLYPH-13B4F;Lo;0;L;;;;;N;;;;; +13B50;EGYPTIAN HIEROGLYPH-13B50;Lo;0;L;;;;;N;;;;; +13B51;EGYPTIAN HIEROGLYPH-13B51;Lo;0;L;;;;;N;;;;; +13B52;EGYPTIAN HIEROGLYPH-13B52;Lo;0;L;;;;;N;;;;; +13B53;EGYPTIAN HIEROGLYPH-13B53;Lo;0;L;;;;;N;;;;; +13B54;EGYPTIAN HIEROGLYPH-13B54;Lo;0;L;;;;;N;;;;; +13B55;EGYPTIAN HIEROGLYPH-13B55;Lo;0;L;;;;;N;;;;; +13B56;EGYPTIAN HIEROGLYPH-13B56;Lo;0;L;;;;;N;;;;; +13B57;EGYPTIAN HIEROGLYPH-13B57;Lo;0;L;;;;;N;;;;; +13B58;EGYPTIAN HIEROGLYPH-13B58;Lo;0;L;;;;;N;;;;; +13B59;EGYPTIAN HIEROGLYPH-13B59;Lo;0;L;;;;;N;;;;; +13B5A;EGYPTIAN HIEROGLYPH-13B5A;Lo;0;L;;;;;N;;;;; +13B5B;EGYPTIAN HIEROGLYPH-13B5B;Lo;0;L;;;;;N;;;;; +13B5C;EGYPTIAN HIEROGLYPH-13B5C;Lo;0;L;;;;;N;;;;; +13B5D;EGYPTIAN HIEROGLYPH-13B5D;Lo;0;L;;;;;N;;;;; +13B5E;EGYPTIAN HIEROGLYPH-13B5E;Lo;0;L;;;;;N;;;;; +13B5F;EGYPTIAN HIEROGLYPH-13B5F;Lo;0;L;;;;;N;;;;; +13B60;EGYPTIAN HIEROGLYPH-13B60;Lo;0;L;;;;;N;;;;; +13B61;EGYPTIAN HIEROGLYPH-13B61;Lo;0;L;;;;;N;;;;; +13B62;EGYPTIAN HIEROGLYPH-13B62;Lo;0;L;;;;;N;;;;; +13B63;EGYPTIAN HIEROGLYPH-13B63;Lo;0;L;;;;;N;;;;; +13B64;EGYPTIAN HIEROGLYPH-13B64;Lo;0;L;;;;;N;;;;; +13B65;EGYPTIAN HIEROGLYPH-13B65;Lo;0;L;;;;;N;;;;; +13B66;EGYPTIAN HIEROGLYPH-13B66;Lo;0;L;;;;;N;;;;; +13B67;EGYPTIAN HIEROGLYPH-13B67;Lo;0;L;;;;;N;;;;; +13B68;EGYPTIAN HIEROGLYPH-13B68;Lo;0;L;;;;;N;;;;; +13B69;EGYPTIAN HIEROGLYPH-13B69;Lo;0;L;;;;;N;;;;; +13B6A;EGYPTIAN HIEROGLYPH-13B6A;Lo;0;L;;;;;N;;;;; +13B6B;EGYPTIAN HIEROGLYPH-13B6B;Lo;0;L;;;;;N;;;;; +13B6C;EGYPTIAN HIEROGLYPH-13B6C;Lo;0;L;;;;;N;;;;; +13B6D;EGYPTIAN HIEROGLYPH-13B6D;Lo;0;L;;;;;N;;;;; +13B6E;EGYPTIAN HIEROGLYPH-13B6E;Lo;0;L;;;;;N;;;;; +13B6F;EGYPTIAN HIEROGLYPH-13B6F;Lo;0;L;;;;;N;;;;; +13B70;EGYPTIAN HIEROGLYPH-13B70;Lo;0;L;;;;;N;;;;; +13B71;EGYPTIAN HIEROGLYPH-13B71;Lo;0;L;;;;;N;;;;; +13B72;EGYPTIAN HIEROGLYPH-13B72;Lo;0;L;;;;;N;;;;; +13B73;EGYPTIAN HIEROGLYPH-13B73;Lo;0;L;;;;;N;;;;; +13B74;EGYPTIAN HIEROGLYPH-13B74;Lo;0;L;;;;;N;;;;; +13B75;EGYPTIAN HIEROGLYPH-13B75;Lo;0;L;;;;;N;;;;; +13B76;EGYPTIAN HIEROGLYPH-13B76;Lo;0;L;;;;;N;;;;; +13B77;EGYPTIAN HIEROGLYPH-13B77;Lo;0;L;;;;;N;;;;; +13B78;EGYPTIAN HIEROGLYPH-13B78;Lo;0;L;;;;;N;;;;; +13B79;EGYPTIAN HIEROGLYPH-13B79;Lo;0;L;;;;;N;;;;; +13B7A;EGYPTIAN HIEROGLYPH-13B7A;Lo;0;L;;;;;N;;;;; +13B7B;EGYPTIAN HIEROGLYPH-13B7B;Lo;0;L;;;;;N;;;;; +13B7C;EGYPTIAN HIEROGLYPH-13B7C;Lo;0;L;;;;;N;;;;; +13B7D;EGYPTIAN HIEROGLYPH-13B7D;Lo;0;L;;;;;N;;;;; +13B7E;EGYPTIAN HIEROGLYPH-13B7E;Lo;0;L;;;;;N;;;;; +13B7F;EGYPTIAN HIEROGLYPH-13B7F;Lo;0;L;;;;;N;;;;; +13B80;EGYPTIAN HIEROGLYPH-13B80;Lo;0;L;;;;;N;;;;; +13B81;EGYPTIAN HIEROGLYPH-13B81;Lo;0;L;;;;;N;;;;; +13B82;EGYPTIAN HIEROGLYPH-13B82;Lo;0;L;;;;;N;;;;; +13B83;EGYPTIAN HIEROGLYPH-13B83;Lo;0;L;;;;;N;;;;; +13B84;EGYPTIAN HIEROGLYPH-13B84;Lo;0;L;;;;;N;;;;; +13B85;EGYPTIAN HIEROGLYPH-13B85;Lo;0;L;;;;;N;;;;; +13B86;EGYPTIAN HIEROGLYPH-13B86;Lo;0;L;;;;;N;;;;; +13B87;EGYPTIAN HIEROGLYPH-13B87;Lo;0;L;;;;;N;;;;; +13B88;EGYPTIAN HIEROGLYPH-13B88;Lo;0;L;;;;;N;;;;; +13B89;EGYPTIAN HIEROGLYPH-13B89;Lo;0;L;;;;;N;;;;; +13B8A;EGYPTIAN HIEROGLYPH-13B8A;Lo;0;L;;;;;N;;;;; +13B8B;EGYPTIAN HIEROGLYPH-13B8B;Lo;0;L;;;;;N;;;;; +13B8C;EGYPTIAN HIEROGLYPH-13B8C;Lo;0;L;;;;;N;;;;; +13B8D;EGYPTIAN HIEROGLYPH-13B8D;Lo;0;L;;;;;N;;;;; +13B8E;EGYPTIAN HIEROGLYPH-13B8E;Lo;0;L;;;;;N;;;;; +13B8F;EGYPTIAN HIEROGLYPH-13B8F;Lo;0;L;;;;;N;;;;; +13B90;EGYPTIAN HIEROGLYPH-13B90;Lo;0;L;;;;;N;;;;; +13B91;EGYPTIAN HIEROGLYPH-13B91;Lo;0;L;;;;;N;;;;; +13B92;EGYPTIAN HIEROGLYPH-13B92;Lo;0;L;;;;;N;;;;; +13B93;EGYPTIAN HIEROGLYPH-13B93;Lo;0;L;;;;;N;;;;; +13B94;EGYPTIAN HIEROGLYPH-13B94;Lo;0;L;;;;;N;;;;; +13B95;EGYPTIAN HIEROGLYPH-13B95;Lo;0;L;;;;;N;;;;; +13B96;EGYPTIAN HIEROGLYPH-13B96;Lo;0;L;;;;;N;;;;; +13B97;EGYPTIAN HIEROGLYPH-13B97;Lo;0;L;;;;;N;;;;; +13B98;EGYPTIAN HIEROGLYPH-13B98;Lo;0;L;;;;;N;;;;; +13B99;EGYPTIAN HIEROGLYPH-13B99;Lo;0;L;;;;;N;;;;; +13B9A;EGYPTIAN HIEROGLYPH-13B9A;Lo;0;L;;;;;N;;;;; +13B9B;EGYPTIAN HIEROGLYPH-13B9B;Lo;0;L;;;;;N;;;;; +13B9C;EGYPTIAN HIEROGLYPH-13B9C;Lo;0;L;;;;;N;;;;; +13B9D;EGYPTIAN HIEROGLYPH-13B9D;Lo;0;L;;;;;N;;;;; +13B9E;EGYPTIAN HIEROGLYPH-13B9E;Lo;0;L;;;;;N;;;;; +13B9F;EGYPTIAN HIEROGLYPH-13B9F;Lo;0;L;;;;;N;;;;; +13BA0;EGYPTIAN HIEROGLYPH-13BA0;Lo;0;L;;;;;N;;;;; +13BA1;EGYPTIAN HIEROGLYPH-13BA1;Lo;0;L;;;;;N;;;;; +13BA2;EGYPTIAN HIEROGLYPH-13BA2;Lo;0;L;;;;;N;;;;; +13BA3;EGYPTIAN HIEROGLYPH-13BA3;Lo;0;L;;;;;N;;;;; +13BA4;EGYPTIAN HIEROGLYPH-13BA4;Lo;0;L;;;;;N;;;;; +13BA5;EGYPTIAN HIEROGLYPH-13BA5;Lo;0;L;;;;;N;;;;; +13BA6;EGYPTIAN HIEROGLYPH-13BA6;Lo;0;L;;;;;N;;;;; +13BA7;EGYPTIAN HIEROGLYPH-13BA7;Lo;0;L;;;;;N;;;;; +13BA8;EGYPTIAN HIEROGLYPH-13BA8;Lo;0;L;;;;;N;;;;; +13BA9;EGYPTIAN HIEROGLYPH-13BA9;Lo;0;L;;;;;N;;;;; +13BAA;EGYPTIAN HIEROGLYPH-13BAA;Lo;0;L;;;;;N;;;;; +13BAB;EGYPTIAN HIEROGLYPH-13BAB;Lo;0;L;;;;;N;;;;; +13BAC;EGYPTIAN HIEROGLYPH-13BAC;Lo;0;L;;;;;N;;;;; +13BAD;EGYPTIAN HIEROGLYPH-13BAD;Lo;0;L;;;;;N;;;;; +13BAE;EGYPTIAN HIEROGLYPH-13BAE;Lo;0;L;;;;;N;;;;; +13BAF;EGYPTIAN HIEROGLYPH-13BAF;Lo;0;L;;;;;N;;;;; +13BB0;EGYPTIAN HIEROGLYPH-13BB0;Lo;0;L;;;;;N;;;;; +13BB1;EGYPTIAN HIEROGLYPH-13BB1;Lo;0;L;;;;;N;;;;; +13BB2;EGYPTIAN HIEROGLYPH-13BB2;Lo;0;L;;;;;N;;;;; +13BB3;EGYPTIAN HIEROGLYPH-13BB3;Lo;0;L;;;;;N;;;;; +13BB4;EGYPTIAN HIEROGLYPH-13BB4;Lo;0;L;;;;;N;;;;; +13BB5;EGYPTIAN HIEROGLYPH-13BB5;Lo;0;L;;;;;N;;;;; +13BB6;EGYPTIAN HIEROGLYPH-13BB6;Lo;0;L;;;;;N;;;;; +13BB7;EGYPTIAN HIEROGLYPH-13BB7;Lo;0;L;;;;;N;;;;; +13BB8;EGYPTIAN HIEROGLYPH-13BB8;Lo;0;L;;;;;N;;;;; +13BB9;EGYPTIAN HIEROGLYPH-13BB9;Lo;0;L;;;;;N;;;;; +13BBA;EGYPTIAN HIEROGLYPH-13BBA;Lo;0;L;;;;;N;;;;; +13BBB;EGYPTIAN HIEROGLYPH-13BBB;Lo;0;L;;;;;N;;;;; +13BBC;EGYPTIAN HIEROGLYPH-13BBC;Lo;0;L;;;;;N;;;;; +13BBD;EGYPTIAN HIEROGLYPH-13BBD;Lo;0;L;;;;;N;;;;; +13BBE;EGYPTIAN HIEROGLYPH-13BBE;Lo;0;L;;;;;N;;;;; +13BBF;EGYPTIAN HIEROGLYPH-13BBF;Lo;0;L;;;;;N;;;;; +13BC0;EGYPTIAN HIEROGLYPH-13BC0;Lo;0;L;;;;;N;;;;; +13BC1;EGYPTIAN HIEROGLYPH-13BC1;Lo;0;L;;;;;N;;;;; +13BC2;EGYPTIAN HIEROGLYPH-13BC2;Lo;0;L;;;;;N;;;;; +13BC3;EGYPTIAN HIEROGLYPH-13BC3;Lo;0;L;;;;;N;;;;; +13BC4;EGYPTIAN HIEROGLYPH-13BC4;Lo;0;L;;;;;N;;;;; +13BC5;EGYPTIAN HIEROGLYPH-13BC5;Lo;0;L;;;;;N;;;;; +13BC6;EGYPTIAN HIEROGLYPH-13BC6;Lo;0;L;;;;;N;;;;; +13BC7;EGYPTIAN HIEROGLYPH-13BC7;Lo;0;L;;;;;N;;;;; +13BC8;EGYPTIAN HIEROGLYPH-13BC8;Lo;0;L;;;;;N;;;;; +13BC9;EGYPTIAN HIEROGLYPH-13BC9;Lo;0;L;;;;;N;;;;; +13BCA;EGYPTIAN HIEROGLYPH-13BCA;Lo;0;L;;;;;N;;;;; +13BCB;EGYPTIAN HIEROGLYPH-13BCB;Lo;0;L;;;;;N;;;;; +13BCC;EGYPTIAN HIEROGLYPH-13BCC;Lo;0;L;;;;;N;;;;; +13BCD;EGYPTIAN HIEROGLYPH-13BCD;Lo;0;L;;;;;N;;;;; +13BCE;EGYPTIAN HIEROGLYPH-13BCE;Lo;0;L;;;;;N;;;;; +13BCF;EGYPTIAN HIEROGLYPH-13BCF;Lo;0;L;;;;;N;;;;; +13BD0;EGYPTIAN HIEROGLYPH-13BD0;Lo;0;L;;;;;N;;;;; +13BD1;EGYPTIAN HIEROGLYPH-13BD1;Lo;0;L;;;;;N;;;;; +13BD2;EGYPTIAN HIEROGLYPH-13BD2;Lo;0;L;;;;;N;;;;; +13BD3;EGYPTIAN HIEROGLYPH-13BD3;Lo;0;L;;;;;N;;;;; +13BD4;EGYPTIAN HIEROGLYPH-13BD4;Lo;0;L;;;;;N;;;;; +13BD5;EGYPTIAN HIEROGLYPH-13BD5;Lo;0;L;;;;;N;;;;; +13BD6;EGYPTIAN HIEROGLYPH-13BD6;Lo;0;L;;;;;N;;;;; +13BD7;EGYPTIAN HIEROGLYPH-13BD7;Lo;0;L;;;;;N;;;;; +13BD8;EGYPTIAN HIEROGLYPH-13BD8;Lo;0;L;;;;;N;;;;; +13BD9;EGYPTIAN HIEROGLYPH-13BD9;Lo;0;L;;;;;N;;;;; +13BDA;EGYPTIAN HIEROGLYPH-13BDA;Lo;0;L;;;;;N;;;;; +13BDB;EGYPTIAN HIEROGLYPH-13BDB;Lo;0;L;;;;;N;;;;; +13BDC;EGYPTIAN HIEROGLYPH-13BDC;Lo;0;L;;;;;N;;;;; +13BDD;EGYPTIAN HIEROGLYPH-13BDD;Lo;0;L;;;;;N;;;;; +13BDE;EGYPTIAN HIEROGLYPH-13BDE;Lo;0;L;;;;;N;;;;; +13BDF;EGYPTIAN HIEROGLYPH-13BDF;Lo;0;L;;;;;N;;;;; +13BE0;EGYPTIAN HIEROGLYPH-13BE0;Lo;0;L;;;;;N;;;;; +13BE1;EGYPTIAN HIEROGLYPH-13BE1;Lo;0;L;;;;;N;;;;; +13BE2;EGYPTIAN HIEROGLYPH-13BE2;Lo;0;L;;;;;N;;;;; +13BE3;EGYPTIAN HIEROGLYPH-13BE3;Lo;0;L;;;;;N;;;;; +13BE4;EGYPTIAN HIEROGLYPH-13BE4;Lo;0;L;;;;;N;;;;; +13BE5;EGYPTIAN HIEROGLYPH-13BE5;Lo;0;L;;;;;N;;;;; +13BE6;EGYPTIAN HIEROGLYPH-13BE6;Lo;0;L;;;;;N;;;;; +13BE7;EGYPTIAN HIEROGLYPH-13BE7;Lo;0;L;;;;;N;;;;; +13BE8;EGYPTIAN HIEROGLYPH-13BE8;Lo;0;L;;;;;N;;;;; +13BE9;EGYPTIAN HIEROGLYPH-13BE9;Lo;0;L;;;;;N;;;;; +13BEA;EGYPTIAN HIEROGLYPH-13BEA;Lo;0;L;;;;;N;;;;; +13BEB;EGYPTIAN HIEROGLYPH-13BEB;Lo;0;L;;;;;N;;;;; +13BEC;EGYPTIAN HIEROGLYPH-13BEC;Lo;0;L;;;;;N;;;;; +13BED;EGYPTIAN HIEROGLYPH-13BED;Lo;0;L;;;;;N;;;;; +13BEE;EGYPTIAN HIEROGLYPH-13BEE;Lo;0;L;;;;;N;;;;; +13BEF;EGYPTIAN HIEROGLYPH-13BEF;Lo;0;L;;;;;N;;;;; +13BF0;EGYPTIAN HIEROGLYPH-13BF0;Lo;0;L;;;;;N;;;;; +13BF1;EGYPTIAN HIEROGLYPH-13BF1;Lo;0;L;;;;;N;;;;; +13BF2;EGYPTIAN HIEROGLYPH-13BF2;Lo;0;L;;;;;N;;;;; +13BF3;EGYPTIAN HIEROGLYPH-13BF3;Lo;0;L;;;;;N;;;;; +13BF4;EGYPTIAN HIEROGLYPH-13BF4;Lo;0;L;;;;;N;;;;; +13BF5;EGYPTIAN HIEROGLYPH-13BF5;Lo;0;L;;;;;N;;;;; +13BF6;EGYPTIAN HIEROGLYPH-13BF6;Lo;0;L;;;;;N;;;;; +13BF7;EGYPTIAN HIEROGLYPH-13BF7;Lo;0;L;;;;;N;;;;; +13BF8;EGYPTIAN HIEROGLYPH-13BF8;Lo;0;L;;;;;N;;;;; +13BF9;EGYPTIAN HIEROGLYPH-13BF9;Lo;0;L;;;;;N;;;;; +13BFA;EGYPTIAN HIEROGLYPH-13BFA;Lo;0;L;;;;;N;;;;; +13BFB;EGYPTIAN HIEROGLYPH-13BFB;Lo;0;L;;;;;N;;;;; +13BFC;EGYPTIAN HIEROGLYPH-13BFC;Lo;0;L;;;;;N;;;;; +13BFD;EGYPTIAN HIEROGLYPH-13BFD;Lo;0;L;;;;;N;;;;; +13BFE;EGYPTIAN HIEROGLYPH-13BFE;Lo;0;L;;;;;N;;;;; +13BFF;EGYPTIAN HIEROGLYPH-13BFF;Lo;0;L;;;;;N;;;;; +13C00;EGYPTIAN HIEROGLYPH-13C00;Lo;0;L;;;;;N;;;;; +13C01;EGYPTIAN HIEROGLYPH-13C01;Lo;0;L;;;;;N;;;;; +13C02;EGYPTIAN HIEROGLYPH-13C02;Lo;0;L;;;;;N;;;;; +13C03;EGYPTIAN HIEROGLYPH-13C03;Lo;0;L;;;;;N;;;;; +13C04;EGYPTIAN HIEROGLYPH-13C04;Lo;0;L;;;;;N;;;;; +13C05;EGYPTIAN HIEROGLYPH-13C05;Lo;0;L;;;;;N;;;;; +13C06;EGYPTIAN HIEROGLYPH-13C06;Lo;0;L;;;;;N;;;;; +13C07;EGYPTIAN HIEROGLYPH-13C07;Lo;0;L;;;;;N;;;;; +13C08;EGYPTIAN HIEROGLYPH-13C08;Lo;0;L;;;;;N;;;;; +13C09;EGYPTIAN HIEROGLYPH-13C09;Lo;0;L;;;;;N;;;;; +13C0A;EGYPTIAN HIEROGLYPH-13C0A;Lo;0;L;;;;;N;;;;; +13C0B;EGYPTIAN HIEROGLYPH-13C0B;Lo;0;L;;;;;N;;;;; +13C0C;EGYPTIAN HIEROGLYPH-13C0C;Lo;0;L;;;;;N;;;;; +13C0D;EGYPTIAN HIEROGLYPH-13C0D;Lo;0;L;;;;;N;;;;; +13C0E;EGYPTIAN HIEROGLYPH-13C0E;Lo;0;L;;;;;N;;;;; +13C0F;EGYPTIAN HIEROGLYPH-13C0F;Lo;0;L;;;;;N;;;;; +13C10;EGYPTIAN HIEROGLYPH-13C10;Lo;0;L;;;;;N;;;;; +13C11;EGYPTIAN HIEROGLYPH-13C11;Lo;0;L;;;;;N;;;;; +13C12;EGYPTIAN HIEROGLYPH-13C12;Lo;0;L;;;;;N;;;;; +13C13;EGYPTIAN HIEROGLYPH-13C13;Lo;0;L;;;;;N;;;;; +13C14;EGYPTIAN HIEROGLYPH-13C14;Lo;0;L;;;;;N;;;;; +13C15;EGYPTIAN HIEROGLYPH-13C15;Lo;0;L;;;;;N;;;;; +13C16;EGYPTIAN HIEROGLYPH-13C16;Lo;0;L;;;;;N;;;;; +13C17;EGYPTIAN HIEROGLYPH-13C17;Lo;0;L;;;;;N;;;;; +13C18;EGYPTIAN HIEROGLYPH-13C18;Lo;0;L;;;;;N;;;;; +13C19;EGYPTIAN HIEROGLYPH-13C19;Lo;0;L;;;;;N;;;;; +13C1A;EGYPTIAN HIEROGLYPH-13C1A;Lo;0;L;;;;;N;;;;; +13C1B;EGYPTIAN HIEROGLYPH-13C1B;Lo;0;L;;;;;N;;;;; +13C1C;EGYPTIAN HIEROGLYPH-13C1C;Lo;0;L;;;;;N;;;;; +13C1D;EGYPTIAN HIEROGLYPH-13C1D;Lo;0;L;;;;;N;;;;; +13C1E;EGYPTIAN HIEROGLYPH-13C1E;Lo;0;L;;;;;N;;;;; +13C1F;EGYPTIAN HIEROGLYPH-13C1F;Lo;0;L;;;;;N;;;;; +13C20;EGYPTIAN HIEROGLYPH-13C20;Lo;0;L;;;;;N;;;;; +13C21;EGYPTIAN HIEROGLYPH-13C21;Lo;0;L;;;;;N;;;;; +13C22;EGYPTIAN HIEROGLYPH-13C22;Lo;0;L;;;;;N;;;;; +13C23;EGYPTIAN HIEROGLYPH-13C23;Lo;0;L;;;;;N;;;;; +13C24;EGYPTIAN HIEROGLYPH-13C24;Lo;0;L;;;;;N;;;;; +13C25;EGYPTIAN HIEROGLYPH-13C25;Lo;0;L;;;;;N;;;;; +13C26;EGYPTIAN HIEROGLYPH-13C26;Lo;0;L;;;;;N;;;;; +13C27;EGYPTIAN HIEROGLYPH-13C27;Lo;0;L;;;;;N;;;;; +13C28;EGYPTIAN HIEROGLYPH-13C28;Lo;0;L;;;;;N;;;;; +13C29;EGYPTIAN HIEROGLYPH-13C29;Lo;0;L;;;;;N;;;;; +13C2A;EGYPTIAN HIEROGLYPH-13C2A;Lo;0;L;;;;;N;;;;; +13C2B;EGYPTIAN HIEROGLYPH-13C2B;Lo;0;L;;;;;N;;;;; +13C2C;EGYPTIAN HIEROGLYPH-13C2C;Lo;0;L;;;;;N;;;;; +13C2D;EGYPTIAN HIEROGLYPH-13C2D;Lo;0;L;;;;;N;;;;; +13C2E;EGYPTIAN HIEROGLYPH-13C2E;Lo;0;L;;;;;N;;;;; +13C2F;EGYPTIAN HIEROGLYPH-13C2F;Lo;0;L;;;;;N;;;;; +13C30;EGYPTIAN HIEROGLYPH-13C30;Lo;0;L;;;;;N;;;;; +13C31;EGYPTIAN HIEROGLYPH-13C31;Lo;0;L;;;;;N;;;;; +13C32;EGYPTIAN HIEROGLYPH-13C32;Lo;0;L;;;;;N;;;;; +13C33;EGYPTIAN HIEROGLYPH-13C33;Lo;0;L;;;;;N;;;;; +13C34;EGYPTIAN HIEROGLYPH-13C34;Lo;0;L;;;;;N;;;;; +13C35;EGYPTIAN HIEROGLYPH-13C35;Lo;0;L;;;;;N;;;;; +13C36;EGYPTIAN HIEROGLYPH-13C36;Lo;0;L;;;;;N;;;;; +13C37;EGYPTIAN HIEROGLYPH-13C37;Lo;0;L;;;;;N;;;;; +13C38;EGYPTIAN HIEROGLYPH-13C38;Lo;0;L;;;;;N;;;;; +13C39;EGYPTIAN HIEROGLYPH-13C39;Lo;0;L;;;;;N;;;;; +13C3A;EGYPTIAN HIEROGLYPH-13C3A;Lo;0;L;;;;;N;;;;; +13C3B;EGYPTIAN HIEROGLYPH-13C3B;Lo;0;L;;;;;N;;;;; +13C3C;EGYPTIAN HIEROGLYPH-13C3C;Lo;0;L;;;;;N;;;;; +13C3D;EGYPTIAN HIEROGLYPH-13C3D;Lo;0;L;;;;;N;;;;; +13C3E;EGYPTIAN HIEROGLYPH-13C3E;Lo;0;L;;;;;N;;;;; +13C3F;EGYPTIAN HIEROGLYPH-13C3F;Lo;0;L;;;;;N;;;;; +13C40;EGYPTIAN HIEROGLYPH-13C40;Lo;0;L;;;;;N;;;;; +13C41;EGYPTIAN HIEROGLYPH-13C41;Lo;0;L;;;;;N;;;;; +13C42;EGYPTIAN HIEROGLYPH-13C42;Lo;0;L;;;;;N;;;;; +13C43;EGYPTIAN HIEROGLYPH-13C43;Lo;0;L;;;;;N;;;;; +13C44;EGYPTIAN HIEROGLYPH-13C44;Lo;0;L;;;;;N;;;;; +13C45;EGYPTIAN HIEROGLYPH-13C45;Lo;0;L;;;;;N;;;;; +13C46;EGYPTIAN HIEROGLYPH-13C46;Lo;0;L;;;;;N;;;;; +13C47;EGYPTIAN HIEROGLYPH-13C47;Lo;0;L;;;;;N;;;;; +13C48;EGYPTIAN HIEROGLYPH-13C48;Lo;0;L;;;;;N;;;;; +13C49;EGYPTIAN HIEROGLYPH-13C49;Lo;0;L;;;;;N;;;;; +13C4A;EGYPTIAN HIEROGLYPH-13C4A;Lo;0;L;;;;;N;;;;; +13C4B;EGYPTIAN HIEROGLYPH-13C4B;Lo;0;L;;;;;N;;;;; +13C4C;EGYPTIAN HIEROGLYPH-13C4C;Lo;0;L;;;;;N;;;;; +13C4D;EGYPTIAN HIEROGLYPH-13C4D;Lo;0;L;;;;;N;;;;; +13C4E;EGYPTIAN HIEROGLYPH-13C4E;Lo;0;L;;;;;N;;;;; +13C4F;EGYPTIAN HIEROGLYPH-13C4F;Lo;0;L;;;;;N;;;;; +13C50;EGYPTIAN HIEROGLYPH-13C50;Lo;0;L;;;;;N;;;;; +13C51;EGYPTIAN HIEROGLYPH-13C51;Lo;0;L;;;;;N;;;;; +13C52;EGYPTIAN HIEROGLYPH-13C52;Lo;0;L;;;;;N;;;;; +13C53;EGYPTIAN HIEROGLYPH-13C53;Lo;0;L;;;;;N;;;;; +13C54;EGYPTIAN HIEROGLYPH-13C54;Lo;0;L;;;;;N;;;;; +13C55;EGYPTIAN HIEROGLYPH-13C55;Lo;0;L;;;;;N;;;;; +13C56;EGYPTIAN HIEROGLYPH-13C56;Lo;0;L;;;;;N;;;;; +13C57;EGYPTIAN HIEROGLYPH-13C57;Lo;0;L;;;;;N;;;;; +13C58;EGYPTIAN HIEROGLYPH-13C58;Lo;0;L;;;;;N;;;;; +13C59;EGYPTIAN HIEROGLYPH-13C59;Lo;0;L;;;;;N;;;;; +13C5A;EGYPTIAN HIEROGLYPH-13C5A;Lo;0;L;;;;;N;;;;; +13C5B;EGYPTIAN HIEROGLYPH-13C5B;Lo;0;L;;;;;N;;;;; +13C5C;EGYPTIAN HIEROGLYPH-13C5C;Lo;0;L;;;;;N;;;;; +13C5D;EGYPTIAN HIEROGLYPH-13C5D;Lo;0;L;;;;;N;;;;; +13C5E;EGYPTIAN HIEROGLYPH-13C5E;Lo;0;L;;;;;N;;;;; +13C5F;EGYPTIAN HIEROGLYPH-13C5F;Lo;0;L;;;;;N;;;;; +13C60;EGYPTIAN HIEROGLYPH-13C60;Lo;0;L;;;;;N;;;;; +13C61;EGYPTIAN HIEROGLYPH-13C61;Lo;0;L;;;;;N;;;;; +13C62;EGYPTIAN HIEROGLYPH-13C62;Lo;0;L;;;;;N;;;;; +13C63;EGYPTIAN HIEROGLYPH-13C63;Lo;0;L;;;;;N;;;;; +13C64;EGYPTIAN HIEROGLYPH-13C64;Lo;0;L;;;;;N;;;;; +13C65;EGYPTIAN HIEROGLYPH-13C65;Lo;0;L;;;;;N;;;;; +13C66;EGYPTIAN HIEROGLYPH-13C66;Lo;0;L;;;;;N;;;;; +13C67;EGYPTIAN HIEROGLYPH-13C67;Lo;0;L;;;;;N;;;;; +13C68;EGYPTIAN HIEROGLYPH-13C68;Lo;0;L;;;;;N;;;;; +13C69;EGYPTIAN HIEROGLYPH-13C69;Lo;0;L;;;;;N;;;;; +13C6A;EGYPTIAN HIEROGLYPH-13C6A;Lo;0;L;;;;;N;;;;; +13C6B;EGYPTIAN HIEROGLYPH-13C6B;Lo;0;L;;;;;N;;;;; +13C6C;EGYPTIAN HIEROGLYPH-13C6C;Lo;0;L;;;;;N;;;;; +13C6D;EGYPTIAN HIEROGLYPH-13C6D;Lo;0;L;;;;;N;;;;; +13C6E;EGYPTIAN HIEROGLYPH-13C6E;Lo;0;L;;;;;N;;;;; +13C6F;EGYPTIAN HIEROGLYPH-13C6F;Lo;0;L;;;;;N;;;;; +13C70;EGYPTIAN HIEROGLYPH-13C70;Lo;0;L;;;;;N;;;;; +13C71;EGYPTIAN HIEROGLYPH-13C71;Lo;0;L;;;;;N;;;;; +13C72;EGYPTIAN HIEROGLYPH-13C72;Lo;0;L;;;;;N;;;;; +13C73;EGYPTIAN HIEROGLYPH-13C73;Lo;0;L;;;;;N;;;;; +13C74;EGYPTIAN HIEROGLYPH-13C74;Lo;0;L;;;;;N;;;;; +13C75;EGYPTIAN HIEROGLYPH-13C75;Lo;0;L;;;;;N;;;;; +13C76;EGYPTIAN HIEROGLYPH-13C76;Lo;0;L;;;;;N;;;;; +13C77;EGYPTIAN HIEROGLYPH-13C77;Lo;0;L;;;;;N;;;;; +13C78;EGYPTIAN HIEROGLYPH-13C78;Lo;0;L;;;;;N;;;;; +13C79;EGYPTIAN HIEROGLYPH-13C79;Lo;0;L;;;;;N;;;;; +13C7A;EGYPTIAN HIEROGLYPH-13C7A;Lo;0;L;;;;;N;;;;; +13C7B;EGYPTIAN HIEROGLYPH-13C7B;Lo;0;L;;;;;N;;;;; +13C7C;EGYPTIAN HIEROGLYPH-13C7C;Lo;0;L;;;;;N;;;;; +13C7D;EGYPTIAN HIEROGLYPH-13C7D;Lo;0;L;;;;;N;;;;; +13C7E;EGYPTIAN HIEROGLYPH-13C7E;Lo;0;L;;;;;N;;;;; +13C7F;EGYPTIAN HIEROGLYPH-13C7F;Lo;0;L;;;;;N;;;;; +13C80;EGYPTIAN HIEROGLYPH-13C80;Lo;0;L;;;;;N;;;;; +13C81;EGYPTIAN HIEROGLYPH-13C81;Lo;0;L;;;;;N;;;;; +13C82;EGYPTIAN HIEROGLYPH-13C82;Lo;0;L;;;;;N;;;;; +13C83;EGYPTIAN HIEROGLYPH-13C83;Lo;0;L;;;;;N;;;;; +13C84;EGYPTIAN HIEROGLYPH-13C84;Lo;0;L;;;;;N;;;;; +13C85;EGYPTIAN HIEROGLYPH-13C85;Lo;0;L;;;;;N;;;;; +13C86;EGYPTIAN HIEROGLYPH-13C86;Lo;0;L;;;;;N;;;;; +13C87;EGYPTIAN HIEROGLYPH-13C87;Lo;0;L;;;;;N;;;;; +13C88;EGYPTIAN HIEROGLYPH-13C88;Lo;0;L;;;;;N;;;;; +13C89;EGYPTIAN HIEROGLYPH-13C89;Lo;0;L;;;;;N;;;;; +13C8A;EGYPTIAN HIEROGLYPH-13C8A;Lo;0;L;;;;;N;;;;; +13C8B;EGYPTIAN HIEROGLYPH-13C8B;Lo;0;L;;;;;N;;;;; +13C8C;EGYPTIAN HIEROGLYPH-13C8C;Lo;0;L;;;;;N;;;;; +13C8D;EGYPTIAN HIEROGLYPH-13C8D;Lo;0;L;;;;;N;;;;; +13C8E;EGYPTIAN HIEROGLYPH-13C8E;Lo;0;L;;;;;N;;;;; +13C8F;EGYPTIAN HIEROGLYPH-13C8F;Lo;0;L;;;;;N;;;;; +13C90;EGYPTIAN HIEROGLYPH-13C90;Lo;0;L;;;;;N;;;;; +13C91;EGYPTIAN HIEROGLYPH-13C91;Lo;0;L;;;;;N;;;;; +13C92;EGYPTIAN HIEROGLYPH-13C92;Lo;0;L;;;;;N;;;;; +13C93;EGYPTIAN HIEROGLYPH-13C93;Lo;0;L;;;;;N;;;;; +13C94;EGYPTIAN HIEROGLYPH-13C94;Lo;0;L;;;;;N;;;;; +13C95;EGYPTIAN HIEROGLYPH-13C95;Lo;0;L;;;;;N;;;;; +13C96;EGYPTIAN HIEROGLYPH-13C96;Lo;0;L;;;;;N;;;;; +13C97;EGYPTIAN HIEROGLYPH-13C97;Lo;0;L;;;;;N;;;;; +13C98;EGYPTIAN HIEROGLYPH-13C98;Lo;0;L;;;;;N;;;;; +13C99;EGYPTIAN HIEROGLYPH-13C99;Lo;0;L;;;;;N;;;;; +13C9A;EGYPTIAN HIEROGLYPH-13C9A;Lo;0;L;;;;;N;;;;; +13C9B;EGYPTIAN HIEROGLYPH-13C9B;Lo;0;L;;;;;N;;;;; +13C9C;EGYPTIAN HIEROGLYPH-13C9C;Lo;0;L;;;;;N;;;;; +13C9D;EGYPTIAN HIEROGLYPH-13C9D;Lo;0;L;;;;;N;;;;; +13C9E;EGYPTIAN HIEROGLYPH-13C9E;Lo;0;L;;;;;N;;;;; +13C9F;EGYPTIAN HIEROGLYPH-13C9F;Lo;0;L;;;;;N;;;;; +13CA0;EGYPTIAN HIEROGLYPH-13CA0;Lo;0;L;;;;;N;;;;; +13CA1;EGYPTIAN HIEROGLYPH-13CA1;Lo;0;L;;;;;N;;;;; +13CA2;EGYPTIAN HIEROGLYPH-13CA2;Lo;0;L;;;;;N;;;;; +13CA3;EGYPTIAN HIEROGLYPH-13CA3;Lo;0;L;;;;;N;;;;; +13CA4;EGYPTIAN HIEROGLYPH-13CA4;Lo;0;L;;;;;N;;;;; +13CA5;EGYPTIAN HIEROGLYPH-13CA5;Lo;0;L;;;;;N;;;;; +13CA6;EGYPTIAN HIEROGLYPH-13CA6;Lo;0;L;;;;;N;;;;; +13CA7;EGYPTIAN HIEROGLYPH-13CA7;Lo;0;L;;;;;N;;;;; +13CA8;EGYPTIAN HIEROGLYPH-13CA8;Lo;0;L;;;;;N;;;;; +13CA9;EGYPTIAN HIEROGLYPH-13CA9;Lo;0;L;;;;;N;;;;; +13CAA;EGYPTIAN HIEROGLYPH-13CAA;Lo;0;L;;;;;N;;;;; +13CAB;EGYPTIAN HIEROGLYPH-13CAB;Lo;0;L;;;;;N;;;;; +13CAC;EGYPTIAN HIEROGLYPH-13CAC;Lo;0;L;;;;;N;;;;; +13CAD;EGYPTIAN HIEROGLYPH-13CAD;Lo;0;L;;;;;N;;;;; +13CAE;EGYPTIAN HIEROGLYPH-13CAE;Lo;0;L;;;;;N;;;;; +13CAF;EGYPTIAN HIEROGLYPH-13CAF;Lo;0;L;;;;;N;;;;; +13CB0;EGYPTIAN HIEROGLYPH-13CB0;Lo;0;L;;;;;N;;;;; +13CB1;EGYPTIAN HIEROGLYPH-13CB1;Lo;0;L;;;;;N;;;;; +13CB2;EGYPTIAN HIEROGLYPH-13CB2;Lo;0;L;;;;;N;;;;; +13CB3;EGYPTIAN HIEROGLYPH-13CB3;Lo;0;L;;;;;N;;;;; +13CB4;EGYPTIAN HIEROGLYPH-13CB4;Lo;0;L;;;;;N;;;;; +13CB5;EGYPTIAN HIEROGLYPH-13CB5;Lo;0;L;;;;;N;;;;; +13CB6;EGYPTIAN HIEROGLYPH-13CB6;Lo;0;L;;;;;N;;;;; +13CB7;EGYPTIAN HIEROGLYPH-13CB7;Lo;0;L;;;;;N;;;;; +13CB8;EGYPTIAN HIEROGLYPH-13CB8;Lo;0;L;;;;;N;;;;; +13CB9;EGYPTIAN HIEROGLYPH-13CB9;Lo;0;L;;;;;N;;;;; +13CBA;EGYPTIAN HIEROGLYPH-13CBA;Lo;0;L;;;;;N;;;;; +13CBB;EGYPTIAN HIEROGLYPH-13CBB;Lo;0;L;;;;;N;;;;; +13CBC;EGYPTIAN HIEROGLYPH-13CBC;Lo;0;L;;;;;N;;;;; +13CBD;EGYPTIAN HIEROGLYPH-13CBD;Lo;0;L;;;;;N;;;;; +13CBE;EGYPTIAN HIEROGLYPH-13CBE;Lo;0;L;;;;;N;;;;; +13CBF;EGYPTIAN HIEROGLYPH-13CBF;Lo;0;L;;;;;N;;;;; +13CC0;EGYPTIAN HIEROGLYPH-13CC0;Lo;0;L;;;;;N;;;;; +13CC1;EGYPTIAN HIEROGLYPH-13CC1;Lo;0;L;;;;;N;;;;; +13CC2;EGYPTIAN HIEROGLYPH-13CC2;Lo;0;L;;;;;N;;;;; +13CC3;EGYPTIAN HIEROGLYPH-13CC3;Lo;0;L;;;;;N;;;;; +13CC4;EGYPTIAN HIEROGLYPH-13CC4;Lo;0;L;;;;;N;;;;; +13CC5;EGYPTIAN HIEROGLYPH-13CC5;Lo;0;L;;;;;N;;;;; +13CC6;EGYPTIAN HIEROGLYPH-13CC6;Lo;0;L;;;;;N;;;;; +13CC7;EGYPTIAN HIEROGLYPH-13CC7;Lo;0;L;;;;;N;;;;; +13CC8;EGYPTIAN HIEROGLYPH-13CC8;Lo;0;L;;;;;N;;;;; +13CC9;EGYPTIAN HIEROGLYPH-13CC9;Lo;0;L;;;;;N;;;;; +13CCA;EGYPTIAN HIEROGLYPH-13CCA;Lo;0;L;;;;;N;;;;; +13CCB;EGYPTIAN HIEROGLYPH-13CCB;Lo;0;L;;;;;N;;;;; +13CCC;EGYPTIAN HIEROGLYPH-13CCC;Lo;0;L;;;;;N;;;;; +13CCD;EGYPTIAN HIEROGLYPH-13CCD;Lo;0;L;;;;;N;;;;; +13CCE;EGYPTIAN HIEROGLYPH-13CCE;Lo;0;L;;;;;N;;;;; +13CCF;EGYPTIAN HIEROGLYPH-13CCF;Lo;0;L;;;;;N;;;;; +13CD0;EGYPTIAN HIEROGLYPH-13CD0;Lo;0;L;;;;;N;;;;; +13CD1;EGYPTIAN HIEROGLYPH-13CD1;Lo;0;L;;;;;N;;;;; +13CD2;EGYPTIAN HIEROGLYPH-13CD2;Lo;0;L;;;;;N;;;;; +13CD3;EGYPTIAN HIEROGLYPH-13CD3;Lo;0;L;;;;;N;;;;; +13CD4;EGYPTIAN HIEROGLYPH-13CD4;Lo;0;L;;;;;N;;;;; +13CD5;EGYPTIAN HIEROGLYPH-13CD5;Lo;0;L;;;;;N;;;;; +13CD6;EGYPTIAN HIEROGLYPH-13CD6;Lo;0;L;;;;;N;;;;; +13CD7;EGYPTIAN HIEROGLYPH-13CD7;Lo;0;L;;;;;N;;;;; +13CD8;EGYPTIAN HIEROGLYPH-13CD8;Lo;0;L;;;;;N;;;;; +13CD9;EGYPTIAN HIEROGLYPH-13CD9;Lo;0;L;;;;;N;;;;; +13CDA;EGYPTIAN HIEROGLYPH-13CDA;Lo;0;L;;;;;N;;;;; +13CDB;EGYPTIAN HIEROGLYPH-13CDB;Lo;0;L;;;;;N;;;;; +13CDC;EGYPTIAN HIEROGLYPH-13CDC;Lo;0;L;;;;;N;;;;; +13CDD;EGYPTIAN HIEROGLYPH-13CDD;Lo;0;L;;;;;N;;;;; +13CDE;EGYPTIAN HIEROGLYPH-13CDE;Lo;0;L;;;;;N;;;;; +13CDF;EGYPTIAN HIEROGLYPH-13CDF;Lo;0;L;;;;;N;;;;; +13CE0;EGYPTIAN HIEROGLYPH-13CE0;Lo;0;L;;;;;N;;;;; +13CE1;EGYPTIAN HIEROGLYPH-13CE1;Lo;0;L;;;;;N;;;;; +13CE2;EGYPTIAN HIEROGLYPH-13CE2;Lo;0;L;;;;;N;;;;; +13CE3;EGYPTIAN HIEROGLYPH-13CE3;Lo;0;L;;;;;N;;;;; +13CE4;EGYPTIAN HIEROGLYPH-13CE4;Lo;0;L;;;;;N;;;;; +13CE5;EGYPTIAN HIEROGLYPH-13CE5;Lo;0;L;;;;;N;;;;; +13CE6;EGYPTIAN HIEROGLYPH-13CE6;Lo;0;L;;;;;N;;;;; +13CE7;EGYPTIAN HIEROGLYPH-13CE7;Lo;0;L;;;;;N;;;;; +13CE8;EGYPTIAN HIEROGLYPH-13CE8;Lo;0;L;;;;;N;;;;; +13CE9;EGYPTIAN HIEROGLYPH-13CE9;Lo;0;L;;;;;N;;;;; +13CEA;EGYPTIAN HIEROGLYPH-13CEA;Lo;0;L;;;;;N;;;;; +13CEB;EGYPTIAN HIEROGLYPH-13CEB;Lo;0;L;;;;;N;;;;; +13CEC;EGYPTIAN HIEROGLYPH-13CEC;Lo;0;L;;;;;N;;;;; +13CED;EGYPTIAN HIEROGLYPH-13CED;Lo;0;L;;;;;N;;;;; +13CEE;EGYPTIAN HIEROGLYPH-13CEE;Lo;0;L;;;;;N;;;;; +13CEF;EGYPTIAN HIEROGLYPH-13CEF;Lo;0;L;;;;;N;;;;; +13CF0;EGYPTIAN HIEROGLYPH-13CF0;Lo;0;L;;;;;N;;;;; +13CF1;EGYPTIAN HIEROGLYPH-13CF1;Lo;0;L;;;;;N;;;;; +13CF2;EGYPTIAN HIEROGLYPH-13CF2;Lo;0;L;;;;;N;;;;; +13CF3;EGYPTIAN HIEROGLYPH-13CF3;Lo;0;L;;;;;N;;;;; +13CF4;EGYPTIAN HIEROGLYPH-13CF4;Lo;0;L;;;;;N;;;;; +13CF5;EGYPTIAN HIEROGLYPH-13CF5;Lo;0;L;;;;;N;;;;; +13CF6;EGYPTIAN HIEROGLYPH-13CF6;Lo;0;L;;;;;N;;;;; +13CF7;EGYPTIAN HIEROGLYPH-13CF7;Lo;0;L;;;;;N;;;;; +13CF8;EGYPTIAN HIEROGLYPH-13CF8;Lo;0;L;;;;;N;;;;; +13CF9;EGYPTIAN HIEROGLYPH-13CF9;Lo;0;L;;;;;N;;;;; +13CFA;EGYPTIAN HIEROGLYPH-13CFA;Lo;0;L;;;;;N;;;;; +13CFB;EGYPTIAN HIEROGLYPH-13CFB;Lo;0;L;;;;;N;;;;; +13CFC;EGYPTIAN HIEROGLYPH-13CFC;Lo;0;L;;;;;N;;;;; +13CFD;EGYPTIAN HIEROGLYPH-13CFD;Lo;0;L;;;;;N;;;;; +13CFE;EGYPTIAN HIEROGLYPH-13CFE;Lo;0;L;;;;;N;;;;; +13CFF;EGYPTIAN HIEROGLYPH-13CFF;Lo;0;L;;;;;N;;;;; +13D00;EGYPTIAN HIEROGLYPH-13D00;Lo;0;L;;;;;N;;;;; +13D01;EGYPTIAN HIEROGLYPH-13D01;Lo;0;L;;;;;N;;;;; +13D02;EGYPTIAN HIEROGLYPH-13D02;Lo;0;L;;;;;N;;;;; +13D03;EGYPTIAN HIEROGLYPH-13D03;Lo;0;L;;;;;N;;;;; +13D04;EGYPTIAN HIEROGLYPH-13D04;Lo;0;L;;;;;N;;;;; +13D05;EGYPTIAN HIEROGLYPH-13D05;Lo;0;L;;;;;N;;;;; +13D06;EGYPTIAN HIEROGLYPH-13D06;Lo;0;L;;;;;N;;;;; +13D07;EGYPTIAN HIEROGLYPH-13D07;Lo;0;L;;;;;N;;;;; +13D08;EGYPTIAN HIEROGLYPH-13D08;Lo;0;L;;;;;N;;;;; +13D09;EGYPTIAN HIEROGLYPH-13D09;Lo;0;L;;;;;N;;;;; +13D0A;EGYPTIAN HIEROGLYPH-13D0A;Lo;0;L;;;;;N;;;;; +13D0B;EGYPTIAN HIEROGLYPH-13D0B;Lo;0;L;;;;;N;;;;; +13D0C;EGYPTIAN HIEROGLYPH-13D0C;Lo;0;L;;;;;N;;;;; +13D0D;EGYPTIAN HIEROGLYPH-13D0D;Lo;0;L;;;;;N;;;;; +13D0E;EGYPTIAN HIEROGLYPH-13D0E;Lo;0;L;;;;;N;;;;; +13D0F;EGYPTIAN HIEROGLYPH-13D0F;Lo;0;L;;;;;N;;;;; +13D10;EGYPTIAN HIEROGLYPH-13D10;Lo;0;L;;;;;N;;;;; +13D11;EGYPTIAN HIEROGLYPH-13D11;Lo;0;L;;;;;N;;;;; +13D12;EGYPTIAN HIEROGLYPH-13D12;Lo;0;L;;;;;N;;;;; +13D13;EGYPTIAN HIEROGLYPH-13D13;Lo;0;L;;;;;N;;;;; +13D14;EGYPTIAN HIEROGLYPH-13D14;Lo;0;L;;;;;N;;;;; +13D15;EGYPTIAN HIEROGLYPH-13D15;Lo;0;L;;;;;N;;;;; +13D16;EGYPTIAN HIEROGLYPH-13D16;Lo;0;L;;;;;N;;;;; +13D17;EGYPTIAN HIEROGLYPH-13D17;Lo;0;L;;;;;N;;;;; +13D18;EGYPTIAN HIEROGLYPH-13D18;Lo;0;L;;;;;N;;;;; +13D19;EGYPTIAN HIEROGLYPH-13D19;Lo;0;L;;;;;N;;;;; +13D1A;EGYPTIAN HIEROGLYPH-13D1A;Lo;0;L;;;;;N;;;;; +13D1B;EGYPTIAN HIEROGLYPH-13D1B;Lo;0;L;;;;;N;;;;; +13D1C;EGYPTIAN HIEROGLYPH-13D1C;Lo;0;L;;;;;N;;;;; +13D1D;EGYPTIAN HIEROGLYPH-13D1D;Lo;0;L;;;;;N;;;;; +13D1E;EGYPTIAN HIEROGLYPH-13D1E;Lo;0;L;;;;;N;;;;; +13D1F;EGYPTIAN HIEROGLYPH-13D1F;Lo;0;L;;;;;N;;;;; +13D20;EGYPTIAN HIEROGLYPH-13D20;Lo;0;L;;;;;N;;;;; +13D21;EGYPTIAN HIEROGLYPH-13D21;Lo;0;L;;;;;N;;;;; +13D22;EGYPTIAN HIEROGLYPH-13D22;Lo;0;L;;;;;N;;;;; +13D23;EGYPTIAN HIEROGLYPH-13D23;Lo;0;L;;;;;N;;;;; +13D24;EGYPTIAN HIEROGLYPH-13D24;Lo;0;L;;;;;N;;;;; +13D25;EGYPTIAN HIEROGLYPH-13D25;Lo;0;L;;;;;N;;;;; +13D26;EGYPTIAN HIEROGLYPH-13D26;Lo;0;L;;;;;N;;;;; +13D27;EGYPTIAN HIEROGLYPH-13D27;Lo;0;L;;;;;N;;;;; +13D28;EGYPTIAN HIEROGLYPH-13D28;Lo;0;L;;;;;N;;;;; +13D29;EGYPTIAN HIEROGLYPH-13D29;Lo;0;L;;;;;N;;;;; +13D2A;EGYPTIAN HIEROGLYPH-13D2A;Lo;0;L;;;;;N;;;;; +13D2B;EGYPTIAN HIEROGLYPH-13D2B;Lo;0;L;;;;;N;;;;; +13D2C;EGYPTIAN HIEROGLYPH-13D2C;Lo;0;L;;;;;N;;;;; +13D2D;EGYPTIAN HIEROGLYPH-13D2D;Lo;0;L;;;;;N;;;;; +13D2E;EGYPTIAN HIEROGLYPH-13D2E;Lo;0;L;;;;;N;;;;; +13D2F;EGYPTIAN HIEROGLYPH-13D2F;Lo;0;L;;;;;N;;;;; +13D30;EGYPTIAN HIEROGLYPH-13D30;Lo;0;L;;;;;N;;;;; +13D31;EGYPTIAN HIEROGLYPH-13D31;Lo;0;L;;;;;N;;;;; +13D32;EGYPTIAN HIEROGLYPH-13D32;Lo;0;L;;;;;N;;;;; +13D33;EGYPTIAN HIEROGLYPH-13D33;Lo;0;L;;;;;N;;;;; +13D34;EGYPTIAN HIEROGLYPH-13D34;Lo;0;L;;;;;N;;;;; +13D35;EGYPTIAN HIEROGLYPH-13D35;Lo;0;L;;;;;N;;;;; +13D36;EGYPTIAN HIEROGLYPH-13D36;Lo;0;L;;;;;N;;;;; +13D37;EGYPTIAN HIEROGLYPH-13D37;Lo;0;L;;;;;N;;;;; +13D38;EGYPTIAN HIEROGLYPH-13D38;Lo;0;L;;;;;N;;;;; +13D39;EGYPTIAN HIEROGLYPH-13D39;Lo;0;L;;;;;N;;;;; +13D3A;EGYPTIAN HIEROGLYPH-13D3A;Lo;0;L;;;;;N;;;;; +13D3B;EGYPTIAN HIEROGLYPH-13D3B;Lo;0;L;;;;;N;;;;; +13D3C;EGYPTIAN HIEROGLYPH-13D3C;Lo;0;L;;;;;N;;;;; +13D3D;EGYPTIAN HIEROGLYPH-13D3D;Lo;0;L;;;;;N;;;;; +13D3E;EGYPTIAN HIEROGLYPH-13D3E;Lo;0;L;;;;;N;;;;; +13D3F;EGYPTIAN HIEROGLYPH-13D3F;Lo;0;L;;;;;N;;;;; +13D40;EGYPTIAN HIEROGLYPH-13D40;Lo;0;L;;;;;N;;;;; +13D41;EGYPTIAN HIEROGLYPH-13D41;Lo;0;L;;;;;N;;;;; +13D42;EGYPTIAN HIEROGLYPH-13D42;Lo;0;L;;;;;N;;;;; +13D43;EGYPTIAN HIEROGLYPH-13D43;Lo;0;L;;;;;N;;;;; +13D44;EGYPTIAN HIEROGLYPH-13D44;Lo;0;L;;;;;N;;;;; +13D45;EGYPTIAN HIEROGLYPH-13D45;Lo;0;L;;;;;N;;;;; +13D46;EGYPTIAN HIEROGLYPH-13D46;Lo;0;L;;;;;N;;;;; +13D47;EGYPTIAN HIEROGLYPH-13D47;Lo;0;L;;;;;N;;;;; +13D48;EGYPTIAN HIEROGLYPH-13D48;Lo;0;L;;;;;N;;;;; +13D49;EGYPTIAN HIEROGLYPH-13D49;Lo;0;L;;;;;N;;;;; +13D4A;EGYPTIAN HIEROGLYPH-13D4A;Lo;0;L;;;;;N;;;;; +13D4B;EGYPTIAN HIEROGLYPH-13D4B;Lo;0;L;;;;;N;;;;; +13D4C;EGYPTIAN HIEROGLYPH-13D4C;Lo;0;L;;;;;N;;;;; +13D4D;EGYPTIAN HIEROGLYPH-13D4D;Lo;0;L;;;;;N;;;;; +13D4E;EGYPTIAN HIEROGLYPH-13D4E;Lo;0;L;;;;;N;;;;; +13D4F;EGYPTIAN HIEROGLYPH-13D4F;Lo;0;L;;;;;N;;;;; +13D50;EGYPTIAN HIEROGLYPH-13D50;Lo;0;L;;;;;N;;;;; +13D51;EGYPTIAN HIEROGLYPH-13D51;Lo;0;L;;;;;N;;;;; +13D52;EGYPTIAN HIEROGLYPH-13D52;Lo;0;L;;;;;N;;;;; +13D53;EGYPTIAN HIEROGLYPH-13D53;Lo;0;L;;;;;N;;;;; +13D54;EGYPTIAN HIEROGLYPH-13D54;Lo;0;L;;;;;N;;;;; +13D55;EGYPTIAN HIEROGLYPH-13D55;Lo;0;L;;;;;N;;;;; +13D56;EGYPTIAN HIEROGLYPH-13D56;Lo;0;L;;;;;N;;;;; +13D57;EGYPTIAN HIEROGLYPH-13D57;Lo;0;L;;;;;N;;;;; +13D58;EGYPTIAN HIEROGLYPH-13D58;Lo;0;L;;;;;N;;;;; +13D59;EGYPTIAN HIEROGLYPH-13D59;Lo;0;L;;;;;N;;;;; +13D5A;EGYPTIAN HIEROGLYPH-13D5A;Lo;0;L;;;;;N;;;;; +13D5B;EGYPTIAN HIEROGLYPH-13D5B;Lo;0;L;;;;;N;;;;; +13D5C;EGYPTIAN HIEROGLYPH-13D5C;Lo;0;L;;;;;N;;;;; +13D5D;EGYPTIAN HIEROGLYPH-13D5D;Lo;0;L;;;;;N;;;;; +13D5E;EGYPTIAN HIEROGLYPH-13D5E;Lo;0;L;;;;;N;;;;; +13D5F;EGYPTIAN HIEROGLYPH-13D5F;Lo;0;L;;;;;N;;;;; +13D60;EGYPTIAN HIEROGLYPH-13D60;Lo;0;L;;;;;N;;;;; +13D61;EGYPTIAN HIEROGLYPH-13D61;Lo;0;L;;;;;N;;;;; +13D62;EGYPTIAN HIEROGLYPH-13D62;Lo;0;L;;;;;N;;;;; +13D63;EGYPTIAN HIEROGLYPH-13D63;Lo;0;L;;;;;N;;;;; +13D64;EGYPTIAN HIEROGLYPH-13D64;Lo;0;L;;;;;N;;;;; +13D65;EGYPTIAN HIEROGLYPH-13D65;Lo;0;L;;;;;N;;;;; +13D66;EGYPTIAN HIEROGLYPH-13D66;Lo;0;L;;;;;N;;;;; +13D67;EGYPTIAN HIEROGLYPH-13D67;Lo;0;L;;;;;N;;;;; +13D68;EGYPTIAN HIEROGLYPH-13D68;Lo;0;L;;;;;N;;;;; +13D69;EGYPTIAN HIEROGLYPH-13D69;Lo;0;L;;;;;N;;;;; +13D6A;EGYPTIAN HIEROGLYPH-13D6A;Lo;0;L;;;;;N;;;;; +13D6B;EGYPTIAN HIEROGLYPH-13D6B;Lo;0;L;;;;;N;;;;; +13D6C;EGYPTIAN HIEROGLYPH-13D6C;Lo;0;L;;;;;N;;;;; +13D6D;EGYPTIAN HIEROGLYPH-13D6D;Lo;0;L;;;;;N;;;;; +13D6E;EGYPTIAN HIEROGLYPH-13D6E;Lo;0;L;;;;;N;;;;; +13D6F;EGYPTIAN HIEROGLYPH-13D6F;Lo;0;L;;;;;N;;;;; +13D70;EGYPTIAN HIEROGLYPH-13D70;Lo;0;L;;;;;N;;;;; +13D71;EGYPTIAN HIEROGLYPH-13D71;Lo;0;L;;;;;N;;;;; +13D72;EGYPTIAN HIEROGLYPH-13D72;Lo;0;L;;;;;N;;;;; +13D73;EGYPTIAN HIEROGLYPH-13D73;Lo;0;L;;;;;N;;;;; +13D74;EGYPTIAN HIEROGLYPH-13D74;Lo;0;L;;;;;N;;;;; +13D75;EGYPTIAN HIEROGLYPH-13D75;Lo;0;L;;;;;N;;;;; +13D76;EGYPTIAN HIEROGLYPH-13D76;Lo;0;L;;;;;N;;;;; +13D77;EGYPTIAN HIEROGLYPH-13D77;Lo;0;L;;;;;N;;;;; +13D78;EGYPTIAN HIEROGLYPH-13D78;Lo;0;L;;;;;N;;;;; +13D79;EGYPTIAN HIEROGLYPH-13D79;Lo;0;L;;;;;N;;;;; +13D7A;EGYPTIAN HIEROGLYPH-13D7A;Lo;0;L;;;;;N;;;;; +13D7B;EGYPTIAN HIEROGLYPH-13D7B;Lo;0;L;;;;;N;;;;; +13D7C;EGYPTIAN HIEROGLYPH-13D7C;Lo;0;L;;;;;N;;;;; +13D7D;EGYPTIAN HIEROGLYPH-13D7D;Lo;0;L;;;;;N;;;;; +13D7E;EGYPTIAN HIEROGLYPH-13D7E;Lo;0;L;;;;;N;;;;; +13D7F;EGYPTIAN HIEROGLYPH-13D7F;Lo;0;L;;;;;N;;;;; +13D80;EGYPTIAN HIEROGLYPH-13D80;Lo;0;L;;;;;N;;;;; +13D81;EGYPTIAN HIEROGLYPH-13D81;Lo;0;L;;;;;N;;;;; +13D82;EGYPTIAN HIEROGLYPH-13D82;Lo;0;L;;;;;N;;;;; +13D83;EGYPTIAN HIEROGLYPH-13D83;Lo;0;L;;;;;N;;;;; +13D84;EGYPTIAN HIEROGLYPH-13D84;Lo;0;L;;;;;N;;;;; +13D85;EGYPTIAN HIEROGLYPH-13D85;Lo;0;L;;;;;N;;;;; +13D86;EGYPTIAN HIEROGLYPH-13D86;Lo;0;L;;;;;N;;;;; +13D87;EGYPTIAN HIEROGLYPH-13D87;Lo;0;L;;;;;N;;;;; +13D88;EGYPTIAN HIEROGLYPH-13D88;Lo;0;L;;;;;N;;;;; +13D89;EGYPTIAN HIEROGLYPH-13D89;Lo;0;L;;;;;N;;;;; +13D8A;EGYPTIAN HIEROGLYPH-13D8A;Lo;0;L;;;;;N;;;;; +13D8B;EGYPTIAN HIEROGLYPH-13D8B;Lo;0;L;;;;;N;;;;; +13D8C;EGYPTIAN HIEROGLYPH-13D8C;Lo;0;L;;;;;N;;;;; +13D8D;EGYPTIAN HIEROGLYPH-13D8D;Lo;0;L;;;;;N;;;;; +13D8E;EGYPTIAN HIEROGLYPH-13D8E;Lo;0;L;;;;;N;;;;; +13D8F;EGYPTIAN HIEROGLYPH-13D8F;Lo;0;L;;;;;N;;;;; +13D90;EGYPTIAN HIEROGLYPH-13D90;Lo;0;L;;;;;N;;;;; +13D91;EGYPTIAN HIEROGLYPH-13D91;Lo;0;L;;;;;N;;;;; +13D92;EGYPTIAN HIEROGLYPH-13D92;Lo;0;L;;;;;N;;;;; +13D93;EGYPTIAN HIEROGLYPH-13D93;Lo;0;L;;;;;N;;;;; +13D94;EGYPTIAN HIEROGLYPH-13D94;Lo;0;L;;;;;N;;;;; +13D95;EGYPTIAN HIEROGLYPH-13D95;Lo;0;L;;;;;N;;;;; +13D96;EGYPTIAN HIEROGLYPH-13D96;Lo;0;L;;;;;N;;;;; +13D97;EGYPTIAN HIEROGLYPH-13D97;Lo;0;L;;;;;N;;;;; +13D98;EGYPTIAN HIEROGLYPH-13D98;Lo;0;L;;;;;N;;;;; +13D99;EGYPTIAN HIEROGLYPH-13D99;Lo;0;L;;;;;N;;;;; +13D9A;EGYPTIAN HIEROGLYPH-13D9A;Lo;0;L;;;;;N;;;;; +13D9B;EGYPTIAN HIEROGLYPH-13D9B;Lo;0;L;;;;;N;;;;; +13D9C;EGYPTIAN HIEROGLYPH-13D9C;Lo;0;L;;;;;N;;;;; +13D9D;EGYPTIAN HIEROGLYPH-13D9D;Lo;0;L;;;;;N;;;;; +13D9E;EGYPTIAN HIEROGLYPH-13D9E;Lo;0;L;;;;;N;;;;; +13D9F;EGYPTIAN HIEROGLYPH-13D9F;Lo;0;L;;;;;N;;;;; +13DA0;EGYPTIAN HIEROGLYPH-13DA0;Lo;0;L;;;;;N;;;;; +13DA1;EGYPTIAN HIEROGLYPH-13DA1;Lo;0;L;;;;;N;;;;; +13DA2;EGYPTIAN HIEROGLYPH-13DA2;Lo;0;L;;;;;N;;;;; +13DA3;EGYPTIAN HIEROGLYPH-13DA3;Lo;0;L;;;;;N;;;;; +13DA4;EGYPTIAN HIEROGLYPH-13DA4;Lo;0;L;;;;;N;;;;; +13DA5;EGYPTIAN HIEROGLYPH-13DA5;Lo;0;L;;;;;N;;;;; +13DA6;EGYPTIAN HIEROGLYPH-13DA6;Lo;0;L;;;;;N;;;;; +13DA7;EGYPTIAN HIEROGLYPH-13DA7;Lo;0;L;;;;;N;;;;; +13DA8;EGYPTIAN HIEROGLYPH-13DA8;Lo;0;L;;;;;N;;;;; +13DA9;EGYPTIAN HIEROGLYPH-13DA9;Lo;0;L;;;;;N;;;;; +13DAA;EGYPTIAN HIEROGLYPH-13DAA;Lo;0;L;;;;;N;;;;; +13DAB;EGYPTIAN HIEROGLYPH-13DAB;Lo;0;L;;;;;N;;;;; +13DAC;EGYPTIAN HIEROGLYPH-13DAC;Lo;0;L;;;;;N;;;;; +13DAD;EGYPTIAN HIEROGLYPH-13DAD;Lo;0;L;;;;;N;;;;; +13DAE;EGYPTIAN HIEROGLYPH-13DAE;Lo;0;L;;;;;N;;;;; +13DAF;EGYPTIAN HIEROGLYPH-13DAF;Lo;0;L;;;;;N;;;;; +13DB0;EGYPTIAN HIEROGLYPH-13DB0;Lo;0;L;;;;;N;;;;; +13DB1;EGYPTIAN HIEROGLYPH-13DB1;Lo;0;L;;;;;N;;;;; +13DB2;EGYPTIAN HIEROGLYPH-13DB2;Lo;0;L;;;;;N;;;;; +13DB3;EGYPTIAN HIEROGLYPH-13DB3;Lo;0;L;;;;;N;;;;; +13DB4;EGYPTIAN HIEROGLYPH-13DB4;Lo;0;L;;;;;N;;;;; +13DB5;EGYPTIAN HIEROGLYPH-13DB5;Lo;0;L;;;;;N;;;;; +13DB6;EGYPTIAN HIEROGLYPH-13DB6;Lo;0;L;;;;;N;;;;; +13DB7;EGYPTIAN HIEROGLYPH-13DB7;Lo;0;L;;;;;N;;;;; +13DB8;EGYPTIAN HIEROGLYPH-13DB8;Lo;0;L;;;;;N;;;;; +13DB9;EGYPTIAN HIEROGLYPH-13DB9;Lo;0;L;;;;;N;;;;; +13DBA;EGYPTIAN HIEROGLYPH-13DBA;Lo;0;L;;;;;N;;;;; +13DBB;EGYPTIAN HIEROGLYPH-13DBB;Lo;0;L;;;;;N;;;;; +13DBC;EGYPTIAN HIEROGLYPH-13DBC;Lo;0;L;;;;;N;;;;; +13DBD;EGYPTIAN HIEROGLYPH-13DBD;Lo;0;L;;;;;N;;;;; +13DBE;EGYPTIAN HIEROGLYPH-13DBE;Lo;0;L;;;;;N;;;;; +13DBF;EGYPTIAN HIEROGLYPH-13DBF;Lo;0;L;;;;;N;;;;; +13DC0;EGYPTIAN HIEROGLYPH-13DC0;Lo;0;L;;;;;N;;;;; +13DC1;EGYPTIAN HIEROGLYPH-13DC1;Lo;0;L;;;;;N;;;;; +13DC2;EGYPTIAN HIEROGLYPH-13DC2;Lo;0;L;;;;;N;;;;; +13DC3;EGYPTIAN HIEROGLYPH-13DC3;Lo;0;L;;;;;N;;;;; +13DC4;EGYPTIAN HIEROGLYPH-13DC4;Lo;0;L;;;;;N;;;;; +13DC5;EGYPTIAN HIEROGLYPH-13DC5;Lo;0;L;;;;;N;;;;; +13DC6;EGYPTIAN HIEROGLYPH-13DC6;Lo;0;L;;;;;N;;;;; +13DC7;EGYPTIAN HIEROGLYPH-13DC7;Lo;0;L;;;;;N;;;;; +13DC8;EGYPTIAN HIEROGLYPH-13DC8;Lo;0;L;;;;;N;;;;; +13DC9;EGYPTIAN HIEROGLYPH-13DC9;Lo;0;L;;;;;N;;;;; +13DCA;EGYPTIAN HIEROGLYPH-13DCA;Lo;0;L;;;;;N;;;;; +13DCB;EGYPTIAN HIEROGLYPH-13DCB;Lo;0;L;;;;;N;;;;; +13DCC;EGYPTIAN HIEROGLYPH-13DCC;Lo;0;L;;;;;N;;;;; +13DCD;EGYPTIAN HIEROGLYPH-13DCD;Lo;0;L;;;;;N;;;;; +13DCE;EGYPTIAN HIEROGLYPH-13DCE;Lo;0;L;;;;;N;;;;; +13DCF;EGYPTIAN HIEROGLYPH-13DCF;Lo;0;L;;;;;N;;;;; +13DD0;EGYPTIAN HIEROGLYPH-13DD0;Lo;0;L;;;;;N;;;;; +13DD1;EGYPTIAN HIEROGLYPH-13DD1;Lo;0;L;;;;;N;;;;; +13DD2;EGYPTIAN HIEROGLYPH-13DD2;Lo;0;L;;;;;N;;;;; +13DD3;EGYPTIAN HIEROGLYPH-13DD3;Lo;0;L;;;;;N;;;;; +13DD4;EGYPTIAN HIEROGLYPH-13DD4;Lo;0;L;;;;;N;;;;; +13DD5;EGYPTIAN HIEROGLYPH-13DD5;Lo;0;L;;;;;N;;;;; +13DD6;EGYPTIAN HIEROGLYPH-13DD6;Lo;0;L;;;;;N;;;;; +13DD7;EGYPTIAN HIEROGLYPH-13DD7;Lo;0;L;;;;;N;;;;; +13DD8;EGYPTIAN HIEROGLYPH-13DD8;Lo;0;L;;;;;N;;;;; +13DD9;EGYPTIAN HIEROGLYPH-13DD9;Lo;0;L;;;;;N;;;;; +13DDA;EGYPTIAN HIEROGLYPH-13DDA;Lo;0;L;;;;;N;;;;; +13DDB;EGYPTIAN HIEROGLYPH-13DDB;Lo;0;L;;;;;N;;;;; +13DDC;EGYPTIAN HIEROGLYPH-13DDC;Lo;0;L;;;;;N;;;;; +13DDD;EGYPTIAN HIEROGLYPH-13DDD;Lo;0;L;;;;;N;;;;; +13DDE;EGYPTIAN HIEROGLYPH-13DDE;Lo;0;L;;;;;N;;;;; +13DDF;EGYPTIAN HIEROGLYPH-13DDF;Lo;0;L;;;;;N;;;;; +13DE0;EGYPTIAN HIEROGLYPH-13DE0;Lo;0;L;;;;;N;;;;; +13DE1;EGYPTIAN HIEROGLYPH-13DE1;Lo;0;L;;;;;N;;;;; +13DE2;EGYPTIAN HIEROGLYPH-13DE2;Lo;0;L;;;;;N;;;;; +13DE3;EGYPTIAN HIEROGLYPH-13DE3;Lo;0;L;;;;;N;;;;; +13DE4;EGYPTIAN HIEROGLYPH-13DE4;Lo;0;L;;;;;N;;;;; +13DE5;EGYPTIAN HIEROGLYPH-13DE5;Lo;0;L;;;;;N;;;;; +13DE6;EGYPTIAN HIEROGLYPH-13DE6;Lo;0;L;;;;;N;;;;; +13DE7;EGYPTIAN HIEROGLYPH-13DE7;Lo;0;L;;;;;N;;;;; +13DE8;EGYPTIAN HIEROGLYPH-13DE8;Lo;0;L;;;;;N;;;;; +13DE9;EGYPTIAN HIEROGLYPH-13DE9;Lo;0;L;;;;;N;;;;; +13DEA;EGYPTIAN HIEROGLYPH-13DEA;Lo;0;L;;;;;N;;;;; +13DEB;EGYPTIAN HIEROGLYPH-13DEB;Lo;0;L;;;;;N;;;;; +13DEC;EGYPTIAN HIEROGLYPH-13DEC;Lo;0;L;;;;;N;;;;; +13DED;EGYPTIAN HIEROGLYPH-13DED;Lo;0;L;;;;;N;;;;; +13DEE;EGYPTIAN HIEROGLYPH-13DEE;Lo;0;L;;;;;N;;;;; +13DEF;EGYPTIAN HIEROGLYPH-13DEF;Lo;0;L;;;;;N;;;;; +13DF0;EGYPTIAN HIEROGLYPH-13DF0;Lo;0;L;;;;;N;;;;; +13DF1;EGYPTIAN HIEROGLYPH-13DF1;Lo;0;L;;;;;N;;;;; +13DF2;EGYPTIAN HIEROGLYPH-13DF2;Lo;0;L;;;;;N;;;;; +13DF3;EGYPTIAN HIEROGLYPH-13DF3;Lo;0;L;;;;;N;;;;; +13DF4;EGYPTIAN HIEROGLYPH-13DF4;Lo;0;L;;;;;N;;;;; +13DF5;EGYPTIAN HIEROGLYPH-13DF5;Lo;0;L;;;;;N;;;;; +13DF6;EGYPTIAN HIEROGLYPH-13DF6;Lo;0;L;;;;;N;;;;; +13DF7;EGYPTIAN HIEROGLYPH-13DF7;Lo;0;L;;;;;N;;;;; +13DF8;EGYPTIAN HIEROGLYPH-13DF8;Lo;0;L;;;;;N;;;;; +13DF9;EGYPTIAN HIEROGLYPH-13DF9;Lo;0;L;;;;;N;;;;; +13DFA;EGYPTIAN HIEROGLYPH-13DFA;Lo;0;L;;;;;N;;;;; +13DFB;EGYPTIAN HIEROGLYPH-13DFB;Lo;0;L;;;;;N;;;;; +13DFC;EGYPTIAN HIEROGLYPH-13DFC;Lo;0;L;;;;;N;;;;; +13DFD;EGYPTIAN HIEROGLYPH-13DFD;Lo;0;L;;;;;N;;;;; +13DFE;EGYPTIAN HIEROGLYPH-13DFE;Lo;0;L;;;;;N;;;;; +13DFF;EGYPTIAN HIEROGLYPH-13DFF;Lo;0;L;;;;;N;;;;; +13E00;EGYPTIAN HIEROGLYPH-13E00;Lo;0;L;;;;;N;;;;; +13E01;EGYPTIAN HIEROGLYPH-13E01;Lo;0;L;;;;;N;;;;; +13E02;EGYPTIAN HIEROGLYPH-13E02;Lo;0;L;;;;;N;;;;; +13E03;EGYPTIAN HIEROGLYPH-13E03;Lo;0;L;;;;;N;;;;; +13E04;EGYPTIAN HIEROGLYPH-13E04;Lo;0;L;;;;;N;;;;; +13E05;EGYPTIAN HIEROGLYPH-13E05;Lo;0;L;;;;;N;;;;; +13E06;EGYPTIAN HIEROGLYPH-13E06;Lo;0;L;;;;;N;;;;; +13E07;EGYPTIAN HIEROGLYPH-13E07;Lo;0;L;;;;;N;;;;; +13E08;EGYPTIAN HIEROGLYPH-13E08;Lo;0;L;;;;;N;;;;; +13E09;EGYPTIAN HIEROGLYPH-13E09;Lo;0;L;;;;;N;;;;; +13E0A;EGYPTIAN HIEROGLYPH-13E0A;Lo;0;L;;;;;N;;;;; +13E0B;EGYPTIAN HIEROGLYPH-13E0B;Lo;0;L;;;;;N;;;;; +13E0C;EGYPTIAN HIEROGLYPH-13E0C;Lo;0;L;;;;;N;;;;; +13E0D;EGYPTIAN HIEROGLYPH-13E0D;Lo;0;L;;;;;N;;;;; +13E0E;EGYPTIAN HIEROGLYPH-13E0E;Lo;0;L;;;;;N;;;;; +13E0F;EGYPTIAN HIEROGLYPH-13E0F;Lo;0;L;;;;;N;;;;; +13E10;EGYPTIAN HIEROGLYPH-13E10;Lo;0;L;;;;;N;;;;; +13E11;EGYPTIAN HIEROGLYPH-13E11;Lo;0;L;;;;;N;;;;; +13E12;EGYPTIAN HIEROGLYPH-13E12;Lo;0;L;;;;;N;;;;; +13E13;EGYPTIAN HIEROGLYPH-13E13;Lo;0;L;;;;;N;;;;; +13E14;EGYPTIAN HIEROGLYPH-13E14;Lo;0;L;;;;;N;;;;; +13E15;EGYPTIAN HIEROGLYPH-13E15;Lo;0;L;;;;;N;;;;; +13E16;EGYPTIAN HIEROGLYPH-13E16;Lo;0;L;;;;;N;;;;; +13E17;EGYPTIAN HIEROGLYPH-13E17;Lo;0;L;;;;;N;;;;; +13E18;EGYPTIAN HIEROGLYPH-13E18;Lo;0;L;;;;;N;;;;; +13E19;EGYPTIAN HIEROGLYPH-13E19;Lo;0;L;;;;;N;;;;; +13E1A;EGYPTIAN HIEROGLYPH-13E1A;Lo;0;L;;;;;N;;;;; +13E1B;EGYPTIAN HIEROGLYPH-13E1B;Lo;0;L;;;;;N;;;;; +13E1C;EGYPTIAN HIEROGLYPH-13E1C;Lo;0;L;;;;;N;;;;; +13E1D;EGYPTIAN HIEROGLYPH-13E1D;Lo;0;L;;;;;N;;;;; +13E1E;EGYPTIAN HIEROGLYPH-13E1E;Lo;0;L;;;;;N;;;;; +13E1F;EGYPTIAN HIEROGLYPH-13E1F;Lo;0;L;;;;;N;;;;; +13E20;EGYPTIAN HIEROGLYPH-13E20;Lo;0;L;;;;;N;;;;; +13E21;EGYPTIAN HIEROGLYPH-13E21;Lo;0;L;;;;;N;;;;; +13E22;EGYPTIAN HIEROGLYPH-13E22;Lo;0;L;;;;;N;;;;; +13E23;EGYPTIAN HIEROGLYPH-13E23;Lo;0;L;;;;;N;;;;; +13E24;EGYPTIAN HIEROGLYPH-13E24;Lo;0;L;;;;;N;;;;; +13E25;EGYPTIAN HIEROGLYPH-13E25;Lo;0;L;;;;;N;;;;; +13E26;EGYPTIAN HIEROGLYPH-13E26;Lo;0;L;;;;;N;;;;; +13E27;EGYPTIAN HIEROGLYPH-13E27;Lo;0;L;;;;;N;;;;; +13E28;EGYPTIAN HIEROGLYPH-13E28;Lo;0;L;;;;;N;;;;; +13E29;EGYPTIAN HIEROGLYPH-13E29;Lo;0;L;;;;;N;;;;; +13E2A;EGYPTIAN HIEROGLYPH-13E2A;Lo;0;L;;;;;N;;;;; +13E2B;EGYPTIAN HIEROGLYPH-13E2B;Lo;0;L;;;;;N;;;;; +13E2C;EGYPTIAN HIEROGLYPH-13E2C;Lo;0;L;;;;;N;;;;; +13E2D;EGYPTIAN HIEROGLYPH-13E2D;Lo;0;L;;;;;N;;;;; +13E2E;EGYPTIAN HIEROGLYPH-13E2E;Lo;0;L;;;;;N;;;;; +13E2F;EGYPTIAN HIEROGLYPH-13E2F;Lo;0;L;;;;;N;;;;; +13E30;EGYPTIAN HIEROGLYPH-13E30;Lo;0;L;;;;;N;;;;; +13E31;EGYPTIAN HIEROGLYPH-13E31;Lo;0;L;;;;;N;;;;; +13E32;EGYPTIAN HIEROGLYPH-13E32;Lo;0;L;;;;;N;;;;; +13E33;EGYPTIAN HIEROGLYPH-13E33;Lo;0;L;;;;;N;;;;; +13E34;EGYPTIAN HIEROGLYPH-13E34;Lo;0;L;;;;;N;;;;; +13E35;EGYPTIAN HIEROGLYPH-13E35;Lo;0;L;;;;;N;;;;; +13E36;EGYPTIAN HIEROGLYPH-13E36;Lo;0;L;;;;;N;;;;; +13E37;EGYPTIAN HIEROGLYPH-13E37;Lo;0;L;;;;;N;;;;; +13E38;EGYPTIAN HIEROGLYPH-13E38;Lo;0;L;;;;;N;;;;; +13E39;EGYPTIAN HIEROGLYPH-13E39;Lo;0;L;;;;;N;;;;; +13E3A;EGYPTIAN HIEROGLYPH-13E3A;Lo;0;L;;;;;N;;;;; +13E3B;EGYPTIAN HIEROGLYPH-13E3B;Lo;0;L;;;;;N;;;;; +13E3C;EGYPTIAN HIEROGLYPH-13E3C;Lo;0;L;;;;;N;;;;; +13E3D;EGYPTIAN HIEROGLYPH-13E3D;Lo;0;L;;;;;N;;;;; +13E3E;EGYPTIAN HIEROGLYPH-13E3E;Lo;0;L;;;;;N;;;;; +13E3F;EGYPTIAN HIEROGLYPH-13E3F;Lo;0;L;;;;;N;;;;; +13E40;EGYPTIAN HIEROGLYPH-13E40;Lo;0;L;;;;;N;;;;; +13E41;EGYPTIAN HIEROGLYPH-13E41;Lo;0;L;;;;;N;;;;; +13E42;EGYPTIAN HIEROGLYPH-13E42;Lo;0;L;;;;;N;;;;; +13E43;EGYPTIAN HIEROGLYPH-13E43;Lo;0;L;;;;;N;;;;; +13E44;EGYPTIAN HIEROGLYPH-13E44;Lo;0;L;;;;;N;;;;; +13E45;EGYPTIAN HIEROGLYPH-13E45;Lo;0;L;;;;;N;;;;; +13E46;EGYPTIAN HIEROGLYPH-13E46;Lo;0;L;;;;;N;;;;; +13E47;EGYPTIAN HIEROGLYPH-13E47;Lo;0;L;;;;;N;;;;; +13E48;EGYPTIAN HIEROGLYPH-13E48;Lo;0;L;;;;;N;;;;; +13E49;EGYPTIAN HIEROGLYPH-13E49;Lo;0;L;;;;;N;;;;; +13E4A;EGYPTIAN HIEROGLYPH-13E4A;Lo;0;L;;;;;N;;;;; +13E4B;EGYPTIAN HIEROGLYPH-13E4B;Lo;0;L;;;;;N;;;;; +13E4C;EGYPTIAN HIEROGLYPH-13E4C;Lo;0;L;;;;;N;;;;; +13E4D;EGYPTIAN HIEROGLYPH-13E4D;Lo;0;L;;;;;N;;;;; +13E4E;EGYPTIAN HIEROGLYPH-13E4E;Lo;0;L;;;;;N;;;;; +13E4F;EGYPTIAN HIEROGLYPH-13E4F;Lo;0;L;;;;;N;;;;; +13E50;EGYPTIAN HIEROGLYPH-13E50;Lo;0;L;;;;;N;;;;; +13E51;EGYPTIAN HIEROGLYPH-13E51;Lo;0;L;;;;;N;;;;; +13E52;EGYPTIAN HIEROGLYPH-13E52;Lo;0;L;;;;;N;;;;; +13E53;EGYPTIAN HIEROGLYPH-13E53;Lo;0;L;;;;;N;;;;; +13E54;EGYPTIAN HIEROGLYPH-13E54;Lo;0;L;;;;;N;;;;; +13E55;EGYPTIAN HIEROGLYPH-13E55;Lo;0;L;;;;;N;;;;; +13E56;EGYPTIAN HIEROGLYPH-13E56;Lo;0;L;;;;;N;;;;; +13E57;EGYPTIAN HIEROGLYPH-13E57;Lo;0;L;;;;;N;;;;; +13E58;EGYPTIAN HIEROGLYPH-13E58;Lo;0;L;;;;;N;;;;; +13E59;EGYPTIAN HIEROGLYPH-13E59;Lo;0;L;;;;;N;;;;; +13E5A;EGYPTIAN HIEROGLYPH-13E5A;Lo;0;L;;;;;N;;;;; +13E5B;EGYPTIAN HIEROGLYPH-13E5B;Lo;0;L;;;;;N;;;;; +13E5C;EGYPTIAN HIEROGLYPH-13E5C;Lo;0;L;;;;;N;;;;; +13E5D;EGYPTIAN HIEROGLYPH-13E5D;Lo;0;L;;;;;N;;;;; +13E5E;EGYPTIAN HIEROGLYPH-13E5E;Lo;0;L;;;;;N;;;;; +13E5F;EGYPTIAN HIEROGLYPH-13E5F;Lo;0;L;;;;;N;;;;; +13E60;EGYPTIAN HIEROGLYPH-13E60;Lo;0;L;;;;;N;;;;; +13E61;EGYPTIAN HIEROGLYPH-13E61;Lo;0;L;;;;;N;;;;; +13E62;EGYPTIAN HIEROGLYPH-13E62;Lo;0;L;;;;;N;;;;; +13E63;EGYPTIAN HIEROGLYPH-13E63;Lo;0;L;;;;;N;;;;; +13E64;EGYPTIAN HIEROGLYPH-13E64;Lo;0;L;;;;;N;;;;; +13E65;EGYPTIAN HIEROGLYPH-13E65;Lo;0;L;;;;;N;;;;; +13E66;EGYPTIAN HIEROGLYPH-13E66;Lo;0;L;;;;;N;;;;; +13E67;EGYPTIAN HIEROGLYPH-13E67;Lo;0;L;;;;;N;;;;; +13E68;EGYPTIAN HIEROGLYPH-13E68;Lo;0;L;;;;;N;;;;; +13E69;EGYPTIAN HIEROGLYPH-13E69;Lo;0;L;;;;;N;;;;; +13E6A;EGYPTIAN HIEROGLYPH-13E6A;Lo;0;L;;;;;N;;;;; +13E6B;EGYPTIAN HIEROGLYPH-13E6B;Lo;0;L;;;;;N;;;;; +13E6C;EGYPTIAN HIEROGLYPH-13E6C;Lo;0;L;;;;;N;;;;; +13E6D;EGYPTIAN HIEROGLYPH-13E6D;Lo;0;L;;;;;N;;;;; +13E6E;EGYPTIAN HIEROGLYPH-13E6E;Lo;0;L;;;;;N;;;;; +13E6F;EGYPTIAN HIEROGLYPH-13E6F;Lo;0;L;;;;;N;;;;; +13E70;EGYPTIAN HIEROGLYPH-13E70;Lo;0;L;;;;;N;;;;; +13E71;EGYPTIAN HIEROGLYPH-13E71;Lo;0;L;;;;;N;;;;; +13E72;EGYPTIAN HIEROGLYPH-13E72;Lo;0;L;;;;;N;;;;; +13E73;EGYPTIAN HIEROGLYPH-13E73;Lo;0;L;;;;;N;;;;; +13E74;EGYPTIAN HIEROGLYPH-13E74;Lo;0;L;;;;;N;;;;; +13E75;EGYPTIAN HIEROGLYPH-13E75;Lo;0;L;;;;;N;;;;; +13E76;EGYPTIAN HIEROGLYPH-13E76;Lo;0;L;;;;;N;;;;; +13E77;EGYPTIAN HIEROGLYPH-13E77;Lo;0;L;;;;;N;;;;; +13E78;EGYPTIAN HIEROGLYPH-13E78;Lo;0;L;;;;;N;;;;; +13E79;EGYPTIAN HIEROGLYPH-13E79;Lo;0;L;;;;;N;;;;; +13E7A;EGYPTIAN HIEROGLYPH-13E7A;Lo;0;L;;;;;N;;;;; +13E7B;EGYPTIAN HIEROGLYPH-13E7B;Lo;0;L;;;;;N;;;;; +13E7C;EGYPTIAN HIEROGLYPH-13E7C;Lo;0;L;;;;;N;;;;; +13E7D;EGYPTIAN HIEROGLYPH-13E7D;Lo;0;L;;;;;N;;;;; +13E7E;EGYPTIAN HIEROGLYPH-13E7E;Lo;0;L;;;;;N;;;;; +13E7F;EGYPTIAN HIEROGLYPH-13E7F;Lo;0;L;;;;;N;;;;; +13E80;EGYPTIAN HIEROGLYPH-13E80;Lo;0;L;;;;;N;;;;; +13E81;EGYPTIAN HIEROGLYPH-13E81;Lo;0;L;;;;;N;;;;; +13E82;EGYPTIAN HIEROGLYPH-13E82;Lo;0;L;;;;;N;;;;; +13E83;EGYPTIAN HIEROGLYPH-13E83;Lo;0;L;;;;;N;;;;; +13E84;EGYPTIAN HIEROGLYPH-13E84;Lo;0;L;;;;;N;;;;; +13E85;EGYPTIAN HIEROGLYPH-13E85;Lo;0;L;;;;;N;;;;; +13E86;EGYPTIAN HIEROGLYPH-13E86;Lo;0;L;;;;;N;;;;; +13E87;EGYPTIAN HIEROGLYPH-13E87;Lo;0;L;;;;;N;;;;; +13E88;EGYPTIAN HIEROGLYPH-13E88;Lo;0;L;;;;;N;;;;; +13E89;EGYPTIAN HIEROGLYPH-13E89;Lo;0;L;;;;;N;;;;; +13E8A;EGYPTIAN HIEROGLYPH-13E8A;Lo;0;L;;;;;N;;;;; +13E8B;EGYPTIAN HIEROGLYPH-13E8B;Lo;0;L;;;;;N;;;;; +13E8C;EGYPTIAN HIEROGLYPH-13E8C;Lo;0;L;;;;;N;;;;; +13E8D;EGYPTIAN HIEROGLYPH-13E8D;Lo;0;L;;;;;N;;;;; +13E8E;EGYPTIAN HIEROGLYPH-13E8E;Lo;0;L;;;;;N;;;;; +13E8F;EGYPTIAN HIEROGLYPH-13E8F;Lo;0;L;;;;;N;;;;; +13E90;EGYPTIAN HIEROGLYPH-13E90;Lo;0;L;;;;;N;;;;; +13E91;EGYPTIAN HIEROGLYPH-13E91;Lo;0;L;;;;;N;;;;; +13E92;EGYPTIAN HIEROGLYPH-13E92;Lo;0;L;;;;;N;;;;; +13E93;EGYPTIAN HIEROGLYPH-13E93;Lo;0;L;;;;;N;;;;; +13E94;EGYPTIAN HIEROGLYPH-13E94;Lo;0;L;;;;;N;;;;; +13E95;EGYPTIAN HIEROGLYPH-13E95;Lo;0;L;;;;;N;;;;; +13E96;EGYPTIAN HIEROGLYPH-13E96;Lo;0;L;;;;;N;;;;; +13E97;EGYPTIAN HIEROGLYPH-13E97;Lo;0;L;;;;;N;;;;; +13E98;EGYPTIAN HIEROGLYPH-13E98;Lo;0;L;;;;;N;;;;; +13E99;EGYPTIAN HIEROGLYPH-13E99;Lo;0;L;;;;;N;;;;; +13E9A;EGYPTIAN HIEROGLYPH-13E9A;Lo;0;L;;;;;N;;;;; +13E9B;EGYPTIAN HIEROGLYPH-13E9B;Lo;0;L;;;;;N;;;;; +13E9C;EGYPTIAN HIEROGLYPH-13E9C;Lo;0;L;;;;;N;;;;; +13E9D;EGYPTIAN HIEROGLYPH-13E9D;Lo;0;L;;;;;N;;;;; +13E9E;EGYPTIAN HIEROGLYPH-13E9E;Lo;0;L;;;;;N;;;;; +13E9F;EGYPTIAN HIEROGLYPH-13E9F;Lo;0;L;;;;;N;;;;; +13EA0;EGYPTIAN HIEROGLYPH-13EA0;Lo;0;L;;;;;N;;;;; +13EA1;EGYPTIAN HIEROGLYPH-13EA1;Lo;0;L;;;;;N;;;;; +13EA2;EGYPTIAN HIEROGLYPH-13EA2;Lo;0;L;;;;;N;;;;; +13EA3;EGYPTIAN HIEROGLYPH-13EA3;Lo;0;L;;;;;N;;;;; +13EA4;EGYPTIAN HIEROGLYPH-13EA4;Lo;0;L;;;;;N;;;;; +13EA5;EGYPTIAN HIEROGLYPH-13EA5;Lo;0;L;;;;;N;;;;; +13EA6;EGYPTIAN HIEROGLYPH-13EA6;Lo;0;L;;;;;N;;;;; +13EA7;EGYPTIAN HIEROGLYPH-13EA7;Lo;0;L;;;;;N;;;;; +13EA8;EGYPTIAN HIEROGLYPH-13EA8;Lo;0;L;;;;;N;;;;; +13EA9;EGYPTIAN HIEROGLYPH-13EA9;Lo;0;L;;;;;N;;;;; +13EAA;EGYPTIAN HIEROGLYPH-13EAA;Lo;0;L;;;;;N;;;;; +13EAB;EGYPTIAN HIEROGLYPH-13EAB;Lo;0;L;;;;;N;;;;; +13EAC;EGYPTIAN HIEROGLYPH-13EAC;Lo;0;L;;;;;N;;;;; +13EAD;EGYPTIAN HIEROGLYPH-13EAD;Lo;0;L;;;;;N;;;;; +13EAE;EGYPTIAN HIEROGLYPH-13EAE;Lo;0;L;;;;;N;;;;; +13EAF;EGYPTIAN HIEROGLYPH-13EAF;Lo;0;L;;;;;N;;;;; +13EB0;EGYPTIAN HIEROGLYPH-13EB0;Lo;0;L;;;;;N;;;;; +13EB1;EGYPTIAN HIEROGLYPH-13EB1;Lo;0;L;;;;;N;;;;; +13EB2;EGYPTIAN HIEROGLYPH-13EB2;Lo;0;L;;;;;N;;;;; +13EB3;EGYPTIAN HIEROGLYPH-13EB3;Lo;0;L;;;;;N;;;;; +13EB4;EGYPTIAN HIEROGLYPH-13EB4;Lo;0;L;;;;;N;;;;; +13EB5;EGYPTIAN HIEROGLYPH-13EB5;Lo;0;L;;;;;N;;;;; +13EB6;EGYPTIAN HIEROGLYPH-13EB6;Lo;0;L;;;;;N;;;;; +13EB7;EGYPTIAN HIEROGLYPH-13EB7;Lo;0;L;;;;;N;;;;; +13EB8;EGYPTIAN HIEROGLYPH-13EB8;Lo;0;L;;;;;N;;;;; +13EB9;EGYPTIAN HIEROGLYPH-13EB9;Lo;0;L;;;;;N;;;;; +13EBA;EGYPTIAN HIEROGLYPH-13EBA;Lo;0;L;;;;;N;;;;; +13EBB;EGYPTIAN HIEROGLYPH-13EBB;Lo;0;L;;;;;N;;;;; +13EBC;EGYPTIAN HIEROGLYPH-13EBC;Lo;0;L;;;;;N;;;;; +13EBD;EGYPTIAN HIEROGLYPH-13EBD;Lo;0;L;;;;;N;;;;; +13EBE;EGYPTIAN HIEROGLYPH-13EBE;Lo;0;L;;;;;N;;;;; +13EBF;EGYPTIAN HIEROGLYPH-13EBF;Lo;0;L;;;;;N;;;;; +13EC0;EGYPTIAN HIEROGLYPH-13EC0;Lo;0;L;;;;;N;;;;; +13EC1;EGYPTIAN HIEROGLYPH-13EC1;Lo;0;L;;;;;N;;;;; +13EC2;EGYPTIAN HIEROGLYPH-13EC2;Lo;0;L;;;;;N;;;;; +13EC3;EGYPTIAN HIEROGLYPH-13EC3;Lo;0;L;;;;;N;;;;; +13EC4;EGYPTIAN HIEROGLYPH-13EC4;Lo;0;L;;;;;N;;;;; +13EC5;EGYPTIAN HIEROGLYPH-13EC5;Lo;0;L;;;;;N;;;;; +13EC6;EGYPTIAN HIEROGLYPH-13EC6;Lo;0;L;;;;;N;;;;; +13EC7;EGYPTIAN HIEROGLYPH-13EC7;Lo;0;L;;;;;N;;;;; +13EC8;EGYPTIAN HIEROGLYPH-13EC8;Lo;0;L;;;;;N;;;;; +13EC9;EGYPTIAN HIEROGLYPH-13EC9;Lo;0;L;;;;;N;;;;; +13ECA;EGYPTIAN HIEROGLYPH-13ECA;Lo;0;L;;;;;N;;;;; +13ECB;EGYPTIAN HIEROGLYPH-13ECB;Lo;0;L;;;;;N;;;;; +13ECC;EGYPTIAN HIEROGLYPH-13ECC;Lo;0;L;;;;;N;;;;; +13ECD;EGYPTIAN HIEROGLYPH-13ECD;Lo;0;L;;;;;N;;;;; +13ECE;EGYPTIAN HIEROGLYPH-13ECE;Lo;0;L;;;;;N;;;;; +13ECF;EGYPTIAN HIEROGLYPH-13ECF;Lo;0;L;;;;;N;;;;; +13ED0;EGYPTIAN HIEROGLYPH-13ED0;Lo;0;L;;;;;N;;;;; +13ED1;EGYPTIAN HIEROGLYPH-13ED1;Lo;0;L;;;;;N;;;;; +13ED2;EGYPTIAN HIEROGLYPH-13ED2;Lo;0;L;;;;;N;;;;; +13ED3;EGYPTIAN HIEROGLYPH-13ED3;Lo;0;L;;;;;N;;;;; +13ED4;EGYPTIAN HIEROGLYPH-13ED4;Lo;0;L;;;;;N;;;;; +13ED5;EGYPTIAN HIEROGLYPH-13ED5;Lo;0;L;;;;;N;;;;; +13ED6;EGYPTIAN HIEROGLYPH-13ED6;Lo;0;L;;;;;N;;;;; +13ED7;EGYPTIAN HIEROGLYPH-13ED7;Lo;0;L;;;;;N;;;;; +13ED8;EGYPTIAN HIEROGLYPH-13ED8;Lo;0;L;;;;;N;;;;; +13ED9;EGYPTIAN HIEROGLYPH-13ED9;Lo;0;L;;;;;N;;;;; +13EDA;EGYPTIAN HIEROGLYPH-13EDA;Lo;0;L;;;;;N;;;;; +13EDB;EGYPTIAN HIEROGLYPH-13EDB;Lo;0;L;;;;;N;;;;; +13EDC;EGYPTIAN HIEROGLYPH-13EDC;Lo;0;L;;;;;N;;;;; +13EDD;EGYPTIAN HIEROGLYPH-13EDD;Lo;0;L;;;;;N;;;;; +13EDE;EGYPTIAN HIEROGLYPH-13EDE;Lo;0;L;;;;;N;;;;; +13EDF;EGYPTIAN HIEROGLYPH-13EDF;Lo;0;L;;;;;N;;;;; +13EE0;EGYPTIAN HIEROGLYPH-13EE0;Lo;0;L;;;;;N;;;;; +13EE1;EGYPTIAN HIEROGLYPH-13EE1;Lo;0;L;;;;;N;;;;; +13EE2;EGYPTIAN HIEROGLYPH-13EE2;Lo;0;L;;;;;N;;;;; +13EE3;EGYPTIAN HIEROGLYPH-13EE3;Lo;0;L;;;;;N;;;;; +13EE4;EGYPTIAN HIEROGLYPH-13EE4;Lo;0;L;;;;;N;;;;; +13EE5;EGYPTIAN HIEROGLYPH-13EE5;Lo;0;L;;;;;N;;;;; +13EE6;EGYPTIAN HIEROGLYPH-13EE6;Lo;0;L;;;;;N;;;;; +13EE7;EGYPTIAN HIEROGLYPH-13EE7;Lo;0;L;;;;;N;;;;; +13EE8;EGYPTIAN HIEROGLYPH-13EE8;Lo;0;L;;;;;N;;;;; +13EE9;EGYPTIAN HIEROGLYPH-13EE9;Lo;0;L;;;;;N;;;;; +13EEA;EGYPTIAN HIEROGLYPH-13EEA;Lo;0;L;;;;;N;;;;; +13EEB;EGYPTIAN HIEROGLYPH-13EEB;Lo;0;L;;;;;N;;;;; +13EEC;EGYPTIAN HIEROGLYPH-13EEC;Lo;0;L;;;;;N;;;;; +13EED;EGYPTIAN HIEROGLYPH-13EED;Lo;0;L;;;;;N;;;;; +13EEE;EGYPTIAN HIEROGLYPH-13EEE;Lo;0;L;;;;;N;;;;; +13EEF;EGYPTIAN HIEROGLYPH-13EEF;Lo;0;L;;;;;N;;;;; +13EF0;EGYPTIAN HIEROGLYPH-13EF0;Lo;0;L;;;;;N;;;;; +13EF1;EGYPTIAN HIEROGLYPH-13EF1;Lo;0;L;;;;;N;;;;; +13EF2;EGYPTIAN HIEROGLYPH-13EF2;Lo;0;L;;;;;N;;;;; +13EF3;EGYPTIAN HIEROGLYPH-13EF3;Lo;0;L;;;;;N;;;;; +13EF4;EGYPTIAN HIEROGLYPH-13EF4;Lo;0;L;;;;;N;;;;; +13EF5;EGYPTIAN HIEROGLYPH-13EF5;Lo;0;L;;;;;N;;;;; +13EF6;EGYPTIAN HIEROGLYPH-13EF6;Lo;0;L;;;;;N;;;;; +13EF7;EGYPTIAN HIEROGLYPH-13EF7;Lo;0;L;;;;;N;;;;; +13EF8;EGYPTIAN HIEROGLYPH-13EF8;Lo;0;L;;;;;N;;;;; +13EF9;EGYPTIAN HIEROGLYPH-13EF9;Lo;0;L;;;;;N;;;;; +13EFA;EGYPTIAN HIEROGLYPH-13EFA;Lo;0;L;;;;;N;;;;; +13EFB;EGYPTIAN HIEROGLYPH-13EFB;Lo;0;L;;;;;N;;;;; +13EFC;EGYPTIAN HIEROGLYPH-13EFC;Lo;0;L;;;;;N;;;;; +13EFD;EGYPTIAN HIEROGLYPH-13EFD;Lo;0;L;;;;;N;;;;; +13EFE;EGYPTIAN HIEROGLYPH-13EFE;Lo;0;L;;;;;N;;;;; +13EFF;EGYPTIAN HIEROGLYPH-13EFF;Lo;0;L;;;;;N;;;;; +13F00;EGYPTIAN HIEROGLYPH-13F00;Lo;0;L;;;;;N;;;;; +13F01;EGYPTIAN HIEROGLYPH-13F01;Lo;0;L;;;;;N;;;;; +13F02;EGYPTIAN HIEROGLYPH-13F02;Lo;0;L;;;;;N;;;;; +13F03;EGYPTIAN HIEROGLYPH-13F03;Lo;0;L;;;;;N;;;;; +13F04;EGYPTIAN HIEROGLYPH-13F04;Lo;0;L;;;;;N;;;;; +13F05;EGYPTIAN HIEROGLYPH-13F05;Lo;0;L;;;;;N;;;;; +13F06;EGYPTIAN HIEROGLYPH-13F06;Lo;0;L;;;;;N;;;;; +13F07;EGYPTIAN HIEROGLYPH-13F07;Lo;0;L;;;;;N;;;;; +13F08;EGYPTIAN HIEROGLYPH-13F08;Lo;0;L;;;;;N;;;;; +13F09;EGYPTIAN HIEROGLYPH-13F09;Lo;0;L;;;;;N;;;;; +13F0A;EGYPTIAN HIEROGLYPH-13F0A;Lo;0;L;;;;;N;;;;; +13F0B;EGYPTIAN HIEROGLYPH-13F0B;Lo;0;L;;;;;N;;;;; +13F0C;EGYPTIAN HIEROGLYPH-13F0C;Lo;0;L;;;;;N;;;;; +13F0D;EGYPTIAN HIEROGLYPH-13F0D;Lo;0;L;;;;;N;;;;; +13F0E;EGYPTIAN HIEROGLYPH-13F0E;Lo;0;L;;;;;N;;;;; +13F0F;EGYPTIAN HIEROGLYPH-13F0F;Lo;0;L;;;;;N;;;;; +13F10;EGYPTIAN HIEROGLYPH-13F10;Lo;0;L;;;;;N;;;;; +13F11;EGYPTIAN HIEROGLYPH-13F11;Lo;0;L;;;;;N;;;;; +13F12;EGYPTIAN HIEROGLYPH-13F12;Lo;0;L;;;;;N;;;;; +13F13;EGYPTIAN HIEROGLYPH-13F13;Lo;0;L;;;;;N;;;;; +13F14;EGYPTIAN HIEROGLYPH-13F14;Lo;0;L;;;;;N;;;;; +13F15;EGYPTIAN HIEROGLYPH-13F15;Lo;0;L;;;;;N;;;;; +13F16;EGYPTIAN HIEROGLYPH-13F16;Lo;0;L;;;;;N;;;;; +13F17;EGYPTIAN HIEROGLYPH-13F17;Lo;0;L;;;;;N;;;;; +13F18;EGYPTIAN HIEROGLYPH-13F18;Lo;0;L;;;;;N;;;;; +13F19;EGYPTIAN HIEROGLYPH-13F19;Lo;0;L;;;;;N;;;;; +13F1A;EGYPTIAN HIEROGLYPH-13F1A;Lo;0;L;;;;;N;;;;; +13F1B;EGYPTIAN HIEROGLYPH-13F1B;Lo;0;L;;;;;N;;;;; +13F1C;EGYPTIAN HIEROGLYPH-13F1C;Lo;0;L;;;;;N;;;;; +13F1D;EGYPTIAN HIEROGLYPH-13F1D;Lo;0;L;;;;;N;;;;; +13F1E;EGYPTIAN HIEROGLYPH-13F1E;Lo;0;L;;;;;N;;;;; +13F1F;EGYPTIAN HIEROGLYPH-13F1F;Lo;0;L;;;;;N;;;;; +13F20;EGYPTIAN HIEROGLYPH-13F20;Lo;0;L;;;;;N;;;;; +13F21;EGYPTIAN HIEROGLYPH-13F21;Lo;0;L;;;;;N;;;;; +13F22;EGYPTIAN HIEROGLYPH-13F22;Lo;0;L;;;;;N;;;;; +13F23;EGYPTIAN HIEROGLYPH-13F23;Lo;0;L;;;;;N;;;;; +13F24;EGYPTIAN HIEROGLYPH-13F24;Lo;0;L;;;;;N;;;;; +13F25;EGYPTIAN HIEROGLYPH-13F25;Lo;0;L;;;;;N;;;;; +13F26;EGYPTIAN HIEROGLYPH-13F26;Lo;0;L;;;;;N;;;;; +13F27;EGYPTIAN HIEROGLYPH-13F27;Lo;0;L;;;;;N;;;;; +13F28;EGYPTIAN HIEROGLYPH-13F28;Lo;0;L;;;;;N;;;;; +13F29;EGYPTIAN HIEROGLYPH-13F29;Lo;0;L;;;;;N;;;;; +13F2A;EGYPTIAN HIEROGLYPH-13F2A;Lo;0;L;;;;;N;;;;; +13F2B;EGYPTIAN HIEROGLYPH-13F2B;Lo;0;L;;;;;N;;;;; +13F2C;EGYPTIAN HIEROGLYPH-13F2C;Lo;0;L;;;;;N;;;;; +13F2D;EGYPTIAN HIEROGLYPH-13F2D;Lo;0;L;;;;;N;;;;; +13F2E;EGYPTIAN HIEROGLYPH-13F2E;Lo;0;L;;;;;N;;;;; +13F2F;EGYPTIAN HIEROGLYPH-13F2F;Lo;0;L;;;;;N;;;;; +13F30;EGYPTIAN HIEROGLYPH-13F30;Lo;0;L;;;;;N;;;;; +13F31;EGYPTIAN HIEROGLYPH-13F31;Lo;0;L;;;;;N;;;;; +13F32;EGYPTIAN HIEROGLYPH-13F32;Lo;0;L;;;;;N;;;;; +13F33;EGYPTIAN HIEROGLYPH-13F33;Lo;0;L;;;;;N;;;;; +13F34;EGYPTIAN HIEROGLYPH-13F34;Lo;0;L;;;;;N;;;;; +13F35;EGYPTIAN HIEROGLYPH-13F35;Lo;0;L;;;;;N;;;;; +13F36;EGYPTIAN HIEROGLYPH-13F36;Lo;0;L;;;;;N;;;;; +13F37;EGYPTIAN HIEROGLYPH-13F37;Lo;0;L;;;;;N;;;;; +13F38;EGYPTIAN HIEROGLYPH-13F38;Lo;0;L;;;;;N;;;;; +13F39;EGYPTIAN HIEROGLYPH-13F39;Lo;0;L;;;;;N;;;;; +13F3A;EGYPTIAN HIEROGLYPH-13F3A;Lo;0;L;;;;;N;;;;; +13F3B;EGYPTIAN HIEROGLYPH-13F3B;Lo;0;L;;;;;N;;;;; +13F3C;EGYPTIAN HIEROGLYPH-13F3C;Lo;0;L;;;;;N;;;;; +13F3D;EGYPTIAN HIEROGLYPH-13F3D;Lo;0;L;;;;;N;;;;; +13F3E;EGYPTIAN HIEROGLYPH-13F3E;Lo;0;L;;;;;N;;;;; +13F3F;EGYPTIAN HIEROGLYPH-13F3F;Lo;0;L;;;;;N;;;;; +13F40;EGYPTIAN HIEROGLYPH-13F40;Lo;0;L;;;;;N;;;;; +13F41;EGYPTIAN HIEROGLYPH-13F41;Lo;0;L;;;;;N;;;;; +13F42;EGYPTIAN HIEROGLYPH-13F42;Lo;0;L;;;;;N;;;;; +13F43;EGYPTIAN HIEROGLYPH-13F43;Lo;0;L;;;;;N;;;;; +13F44;EGYPTIAN HIEROGLYPH-13F44;Lo;0;L;;;;;N;;;;; +13F45;EGYPTIAN HIEROGLYPH-13F45;Lo;0;L;;;;;N;;;;; +13F46;EGYPTIAN HIEROGLYPH-13F46;Lo;0;L;;;;;N;;;;; +13F47;EGYPTIAN HIEROGLYPH-13F47;Lo;0;L;;;;;N;;;;; +13F48;EGYPTIAN HIEROGLYPH-13F48;Lo;0;L;;;;;N;;;;; +13F49;EGYPTIAN HIEROGLYPH-13F49;Lo;0;L;;;;;N;;;;; +13F4A;EGYPTIAN HIEROGLYPH-13F4A;Lo;0;L;;;;;N;;;;; +13F4B;EGYPTIAN HIEROGLYPH-13F4B;Lo;0;L;;;;;N;;;;; +13F4C;EGYPTIAN HIEROGLYPH-13F4C;Lo;0;L;;;;;N;;;;; +13F4D;EGYPTIAN HIEROGLYPH-13F4D;Lo;0;L;;;;;N;;;;; +13F4E;EGYPTIAN HIEROGLYPH-13F4E;Lo;0;L;;;;;N;;;;; +13F4F;EGYPTIAN HIEROGLYPH-13F4F;Lo;0;L;;;;;N;;;;; +13F50;EGYPTIAN HIEROGLYPH-13F50;Lo;0;L;;;;;N;;;;; +13F51;EGYPTIAN HIEROGLYPH-13F51;Lo;0;L;;;;;N;;;;; +13F52;EGYPTIAN HIEROGLYPH-13F52;Lo;0;L;;;;;N;;;;; +13F53;EGYPTIAN HIEROGLYPH-13F53;Lo;0;L;;;;;N;;;;; +13F54;EGYPTIAN HIEROGLYPH-13F54;Lo;0;L;;;;;N;;;;; +13F55;EGYPTIAN HIEROGLYPH-13F55;Lo;0;L;;;;;N;;;;; +13F56;EGYPTIAN HIEROGLYPH-13F56;Lo;0;L;;;;;N;;;;; +13F57;EGYPTIAN HIEROGLYPH-13F57;Lo;0;L;;;;;N;;;;; +13F58;EGYPTIAN HIEROGLYPH-13F58;Lo;0;L;;;;;N;;;;; +13F59;EGYPTIAN HIEROGLYPH-13F59;Lo;0;L;;;;;N;;;;; +13F5A;EGYPTIAN HIEROGLYPH-13F5A;Lo;0;L;;;;;N;;;;; +13F5B;EGYPTIAN HIEROGLYPH-13F5B;Lo;0;L;;;;;N;;;;; +13F5C;EGYPTIAN HIEROGLYPH-13F5C;Lo;0;L;;;;;N;;;;; +13F5D;EGYPTIAN HIEROGLYPH-13F5D;Lo;0;L;;;;;N;;;;; +13F5E;EGYPTIAN HIEROGLYPH-13F5E;Lo;0;L;;;;;N;;;;; +13F5F;EGYPTIAN HIEROGLYPH-13F5F;Lo;0;L;;;;;N;;;;; +13F60;EGYPTIAN HIEROGLYPH-13F60;Lo;0;L;;;;;N;;;;; +13F61;EGYPTIAN HIEROGLYPH-13F61;Lo;0;L;;;;;N;;;;; +13F62;EGYPTIAN HIEROGLYPH-13F62;Lo;0;L;;;;;N;;;;; +13F63;EGYPTIAN HIEROGLYPH-13F63;Lo;0;L;;;;;N;;;;; +13F64;EGYPTIAN HIEROGLYPH-13F64;Lo;0;L;;;;;N;;;;; +13F65;EGYPTIAN HIEROGLYPH-13F65;Lo;0;L;;;;;N;;;;; +13F66;EGYPTIAN HIEROGLYPH-13F66;Lo;0;L;;;;;N;;;;; +13F67;EGYPTIAN HIEROGLYPH-13F67;Lo;0;L;;;;;N;;;;; +13F68;EGYPTIAN HIEROGLYPH-13F68;Lo;0;L;;;;;N;;;;; +13F69;EGYPTIAN HIEROGLYPH-13F69;Lo;0;L;;;;;N;;;;; +13F6A;EGYPTIAN HIEROGLYPH-13F6A;Lo;0;L;;;;;N;;;;; +13F6B;EGYPTIAN HIEROGLYPH-13F6B;Lo;0;L;;;;;N;;;;; +13F6C;EGYPTIAN HIEROGLYPH-13F6C;Lo;0;L;;;;;N;;;;; +13F6D;EGYPTIAN HIEROGLYPH-13F6D;Lo;0;L;;;;;N;;;;; +13F6E;EGYPTIAN HIEROGLYPH-13F6E;Lo;0;L;;;;;N;;;;; +13F6F;EGYPTIAN HIEROGLYPH-13F6F;Lo;0;L;;;;;N;;;;; +13F70;EGYPTIAN HIEROGLYPH-13F70;Lo;0;L;;;;;N;;;;; +13F71;EGYPTIAN HIEROGLYPH-13F71;Lo;0;L;;;;;N;;;;; +13F72;EGYPTIAN HIEROGLYPH-13F72;Lo;0;L;;;;;N;;;;; +13F73;EGYPTIAN HIEROGLYPH-13F73;Lo;0;L;;;;;N;;;;; +13F74;EGYPTIAN HIEROGLYPH-13F74;Lo;0;L;;;;;N;;;;; +13F75;EGYPTIAN HIEROGLYPH-13F75;Lo;0;L;;;;;N;;;;; +13F76;EGYPTIAN HIEROGLYPH-13F76;Lo;0;L;;;;;N;;;;; +13F77;EGYPTIAN HIEROGLYPH-13F77;Lo;0;L;;;;;N;;;;; +13F78;EGYPTIAN HIEROGLYPH-13F78;Lo;0;L;;;;;N;;;;; +13F79;EGYPTIAN HIEROGLYPH-13F79;Lo;0;L;;;;;N;;;;; +13F7A;EGYPTIAN HIEROGLYPH-13F7A;Lo;0;L;;;;;N;;;;; +13F7B;EGYPTIAN HIEROGLYPH-13F7B;Lo;0;L;;;;;N;;;;; +13F7C;EGYPTIAN HIEROGLYPH-13F7C;Lo;0;L;;;;;N;;;;; +13F7D;EGYPTIAN HIEROGLYPH-13F7D;Lo;0;L;;;;;N;;;;; +13F7E;EGYPTIAN HIEROGLYPH-13F7E;Lo;0;L;;;;;N;;;;; +13F7F;EGYPTIAN HIEROGLYPH-13F7F;Lo;0;L;;;;;N;;;;; +13F80;EGYPTIAN HIEROGLYPH-13F80;Lo;0;L;;;;;N;;;;; +13F81;EGYPTIAN HIEROGLYPH-13F81;Lo;0;L;;;;;N;;;;; +13F82;EGYPTIAN HIEROGLYPH-13F82;Lo;0;L;;;;;N;;;;; +13F83;EGYPTIAN HIEROGLYPH-13F83;Lo;0;L;;;;;N;;;;; +13F84;EGYPTIAN HIEROGLYPH-13F84;Lo;0;L;;;;;N;;;;; +13F85;EGYPTIAN HIEROGLYPH-13F85;Lo;0;L;;;;;N;;;;; +13F86;EGYPTIAN HIEROGLYPH-13F86;Lo;0;L;;;;;N;;;;; +13F87;EGYPTIAN HIEROGLYPH-13F87;Lo;0;L;;;;;N;;;;; +13F88;EGYPTIAN HIEROGLYPH-13F88;Lo;0;L;;;;;N;;;;; +13F89;EGYPTIAN HIEROGLYPH-13F89;Lo;0;L;;;;;N;;;;; +13F8A;EGYPTIAN HIEROGLYPH-13F8A;Lo;0;L;;;;;N;;;;; +13F8B;EGYPTIAN HIEROGLYPH-13F8B;Lo;0;L;;;;;N;;;;; +13F8C;EGYPTIAN HIEROGLYPH-13F8C;Lo;0;L;;;;;N;;;;; +13F8D;EGYPTIAN HIEROGLYPH-13F8D;Lo;0;L;;;;;N;;;;; +13F8E;EGYPTIAN HIEROGLYPH-13F8E;Lo;0;L;;;;;N;;;;; +13F8F;EGYPTIAN HIEROGLYPH-13F8F;Lo;0;L;;;;;N;;;;; +13F90;EGYPTIAN HIEROGLYPH-13F90;Lo;0;L;;;;;N;;;;; +13F91;EGYPTIAN HIEROGLYPH-13F91;Lo;0;L;;;;;N;;;;; +13F92;EGYPTIAN HIEROGLYPH-13F92;Lo;0;L;;;;;N;;;;; +13F93;EGYPTIAN HIEROGLYPH-13F93;Lo;0;L;;;;;N;;;;; +13F94;EGYPTIAN HIEROGLYPH-13F94;Lo;0;L;;;;;N;;;;; +13F95;EGYPTIAN HIEROGLYPH-13F95;Lo;0;L;;;;;N;;;;; +13F96;EGYPTIAN HIEROGLYPH-13F96;Lo;0;L;;;;;N;;;;; +13F97;EGYPTIAN HIEROGLYPH-13F97;Lo;0;L;;;;;N;;;;; +13F98;EGYPTIAN HIEROGLYPH-13F98;Lo;0;L;;;;;N;;;;; +13F99;EGYPTIAN HIEROGLYPH-13F99;Lo;0;L;;;;;N;;;;; +13F9A;EGYPTIAN HIEROGLYPH-13F9A;Lo;0;L;;;;;N;;;;; +13F9B;EGYPTIAN HIEROGLYPH-13F9B;Lo;0;L;;;;;N;;;;; +13F9C;EGYPTIAN HIEROGLYPH-13F9C;Lo;0;L;;;;;N;;;;; +13F9D;EGYPTIAN HIEROGLYPH-13F9D;Lo;0;L;;;;;N;;;;; +13F9E;EGYPTIAN HIEROGLYPH-13F9E;Lo;0;L;;;;;N;;;;; +13F9F;EGYPTIAN HIEROGLYPH-13F9F;Lo;0;L;;;;;N;;;;; +13FA0;EGYPTIAN HIEROGLYPH-13FA0;Lo;0;L;;;;;N;;;;; +13FA1;EGYPTIAN HIEROGLYPH-13FA1;Lo;0;L;;;;;N;;;;; +13FA2;EGYPTIAN HIEROGLYPH-13FA2;Lo;0;L;;;;;N;;;;; +13FA3;EGYPTIAN HIEROGLYPH-13FA3;Lo;0;L;;;;;N;;;;; +13FA4;EGYPTIAN HIEROGLYPH-13FA4;Lo;0;L;;;;;N;;;;; +13FA5;EGYPTIAN HIEROGLYPH-13FA5;Lo;0;L;;;;;N;;;;; +13FA6;EGYPTIAN HIEROGLYPH-13FA6;Lo;0;L;;;;;N;;;;; +13FA7;EGYPTIAN HIEROGLYPH-13FA7;Lo;0;L;;;;;N;;;;; +13FA8;EGYPTIAN HIEROGLYPH-13FA8;Lo;0;L;;;;;N;;;;; +13FA9;EGYPTIAN HIEROGLYPH-13FA9;Lo;0;L;;;;;N;;;;; +13FAA;EGYPTIAN HIEROGLYPH-13FAA;Lo;0;L;;;;;N;;;;; +13FAB;EGYPTIAN HIEROGLYPH-13FAB;Lo;0;L;;;;;N;;;;; +13FAC;EGYPTIAN HIEROGLYPH-13FAC;Lo;0;L;;;;;N;;;;; +13FAD;EGYPTIAN HIEROGLYPH-13FAD;Lo;0;L;;;;;N;;;;; +13FAE;EGYPTIAN HIEROGLYPH-13FAE;Lo;0;L;;;;;N;;;;; +13FAF;EGYPTIAN HIEROGLYPH-13FAF;Lo;0;L;;;;;N;;;;; +13FB0;EGYPTIAN HIEROGLYPH-13FB0;Lo;0;L;;;;;N;;;;; +13FB1;EGYPTIAN HIEROGLYPH-13FB1;Lo;0;L;;;;;N;;;;; +13FB2;EGYPTIAN HIEROGLYPH-13FB2;Lo;0;L;;;;;N;;;;; +13FB3;EGYPTIAN HIEROGLYPH-13FB3;Lo;0;L;;;;;N;;;;; +13FB4;EGYPTIAN HIEROGLYPH-13FB4;Lo;0;L;;;;;N;;;;; +13FB5;EGYPTIAN HIEROGLYPH-13FB5;Lo;0;L;;;;;N;;;;; +13FB6;EGYPTIAN HIEROGLYPH-13FB6;Lo;0;L;;;;;N;;;;; +13FB7;EGYPTIAN HIEROGLYPH-13FB7;Lo;0;L;;;;;N;;;;; +13FB8;EGYPTIAN HIEROGLYPH-13FB8;Lo;0;L;;;;;N;;;;; +13FB9;EGYPTIAN HIEROGLYPH-13FB9;Lo;0;L;;;;;N;;;;; +13FBA;EGYPTIAN HIEROGLYPH-13FBA;Lo;0;L;;;;;N;;;;; +13FBB;EGYPTIAN HIEROGLYPH-13FBB;Lo;0;L;;;;;N;;;;; +13FBC;EGYPTIAN HIEROGLYPH-13FBC;Lo;0;L;;;;;N;;;;; +13FBD;EGYPTIAN HIEROGLYPH-13FBD;Lo;0;L;;;;;N;;;;; +13FBE;EGYPTIAN HIEROGLYPH-13FBE;Lo;0;L;;;;;N;;;;; +13FBF;EGYPTIAN HIEROGLYPH-13FBF;Lo;0;L;;;;;N;;;;; +13FC0;EGYPTIAN HIEROGLYPH-13FC0;Lo;0;L;;;;;N;;;;; +13FC1;EGYPTIAN HIEROGLYPH-13FC1;Lo;0;L;;;;;N;;;;; +13FC2;EGYPTIAN HIEROGLYPH-13FC2;Lo;0;L;;;;;N;;;;; +13FC3;EGYPTIAN HIEROGLYPH-13FC3;Lo;0;L;;;;;N;;;;; +13FC4;EGYPTIAN HIEROGLYPH-13FC4;Lo;0;L;;;;;N;;;;; +13FC5;EGYPTIAN HIEROGLYPH-13FC5;Lo;0;L;;;;;N;;;;; +13FC6;EGYPTIAN HIEROGLYPH-13FC6;Lo;0;L;;;;;N;;;;; +13FC7;EGYPTIAN HIEROGLYPH-13FC7;Lo;0;L;;;;;N;;;;; +13FC8;EGYPTIAN HIEROGLYPH-13FC8;Lo;0;L;;;;;N;;;;; +13FC9;EGYPTIAN HIEROGLYPH-13FC9;Lo;0;L;;;;;N;;;;; +13FCA;EGYPTIAN HIEROGLYPH-13FCA;Lo;0;L;;;;;N;;;;; +13FCB;EGYPTIAN HIEROGLYPH-13FCB;Lo;0;L;;;;;N;;;;; +13FCC;EGYPTIAN HIEROGLYPH-13FCC;Lo;0;L;;;;;N;;;;; +13FCD;EGYPTIAN HIEROGLYPH-13FCD;Lo;0;L;;;;;N;;;;; +13FCE;EGYPTIAN HIEROGLYPH-13FCE;Lo;0;L;;;;;N;;;;; +13FCF;EGYPTIAN HIEROGLYPH-13FCF;Lo;0;L;;;;;N;;;;; +13FD0;EGYPTIAN HIEROGLYPH-13FD0;Lo;0;L;;;;;N;;;;; +13FD1;EGYPTIAN HIEROGLYPH-13FD1;Lo;0;L;;;;;N;;;;; +13FD2;EGYPTIAN HIEROGLYPH-13FD2;Lo;0;L;;;;;N;;;;; +13FD3;EGYPTIAN HIEROGLYPH-13FD3;Lo;0;L;;;;;N;;;;; +13FD4;EGYPTIAN HIEROGLYPH-13FD4;Lo;0;L;;;;;N;;;;; +13FD5;EGYPTIAN HIEROGLYPH-13FD5;Lo;0;L;;;;;N;;;;; +13FD6;EGYPTIAN HIEROGLYPH-13FD6;Lo;0;L;;;;;N;;;;; +13FD7;EGYPTIAN HIEROGLYPH-13FD7;Lo;0;L;;;;;N;;;;; +13FD8;EGYPTIAN HIEROGLYPH-13FD8;Lo;0;L;;;;;N;;;;; +13FD9;EGYPTIAN HIEROGLYPH-13FD9;Lo;0;L;;;;;N;;;;; +13FDA;EGYPTIAN HIEROGLYPH-13FDA;Lo;0;L;;;;;N;;;;; +13FDB;EGYPTIAN HIEROGLYPH-13FDB;Lo;0;L;;;;;N;;;;; +13FDC;EGYPTIAN HIEROGLYPH-13FDC;Lo;0;L;;;;;N;;;;; +13FDD;EGYPTIAN HIEROGLYPH-13FDD;Lo;0;L;;;;;N;;;;; +13FDE;EGYPTIAN HIEROGLYPH-13FDE;Lo;0;L;;;;;N;;;;; +13FDF;EGYPTIAN HIEROGLYPH-13FDF;Lo;0;L;;;;;N;;;;; +13FE0;EGYPTIAN HIEROGLYPH-13FE0;Lo;0;L;;;;;N;;;;; +13FE1;EGYPTIAN HIEROGLYPH-13FE1;Lo;0;L;;;;;N;;;;; +13FE2;EGYPTIAN HIEROGLYPH-13FE2;Lo;0;L;;;;;N;;;;; +13FE3;EGYPTIAN HIEROGLYPH-13FE3;Lo;0;L;;;;;N;;;;; +13FE4;EGYPTIAN HIEROGLYPH-13FE4;Lo;0;L;;;;;N;;;;; +13FE5;EGYPTIAN HIEROGLYPH-13FE5;Lo;0;L;;;;;N;;;;; +13FE6;EGYPTIAN HIEROGLYPH-13FE6;Lo;0;L;;;;;N;;;;; +13FE7;EGYPTIAN HIEROGLYPH-13FE7;Lo;0;L;;;;;N;;;;; +13FE8;EGYPTIAN HIEROGLYPH-13FE8;Lo;0;L;;;;;N;;;;; +13FE9;EGYPTIAN HIEROGLYPH-13FE9;Lo;0;L;;;;;N;;;;; +13FEA;EGYPTIAN HIEROGLYPH-13FEA;Lo;0;L;;;;;N;;;;; +13FEB;EGYPTIAN HIEROGLYPH-13FEB;Lo;0;L;;;;;N;;;;; +13FEC;EGYPTIAN HIEROGLYPH-13FEC;Lo;0;L;;;;;N;;;;; +13FED;EGYPTIAN HIEROGLYPH-13FED;Lo;0;L;;;;;N;;;;; +13FEE;EGYPTIAN HIEROGLYPH-13FEE;Lo;0;L;;;;;N;;;;; +13FEF;EGYPTIAN HIEROGLYPH-13FEF;Lo;0;L;;;;;N;;;;; +13FF0;EGYPTIAN HIEROGLYPH-13FF0;Lo;0;L;;;;;N;;;;; +13FF1;EGYPTIAN HIEROGLYPH-13FF1;Lo;0;L;;;;;N;;;;; +13FF2;EGYPTIAN HIEROGLYPH-13FF2;Lo;0;L;;;;;N;;;;; +13FF3;EGYPTIAN HIEROGLYPH-13FF3;Lo;0;L;;;;;N;;;;; +13FF4;EGYPTIAN HIEROGLYPH-13FF4;Lo;0;L;;;;;N;;;;; +13FF5;EGYPTIAN HIEROGLYPH-13FF5;Lo;0;L;;;;;N;;;;; +13FF6;EGYPTIAN HIEROGLYPH-13FF6;Lo;0;L;;;;;N;;;;; +13FF7;EGYPTIAN HIEROGLYPH-13FF7;Lo;0;L;;;;;N;;;;; +13FF8;EGYPTIAN HIEROGLYPH-13FF8;Lo;0;L;;;;;N;;;;; +13FF9;EGYPTIAN HIEROGLYPH-13FF9;Lo;0;L;;;;;N;;;;; +13FFA;EGYPTIAN HIEROGLYPH-13FFA;Lo;0;L;;;;;N;;;;; +13FFB;EGYPTIAN HIEROGLYPH-13FFB;Lo;0;L;;;;;N;;;;; +13FFC;EGYPTIAN HIEROGLYPH-13FFC;Lo;0;L;;;;;N;;;;; +13FFD;EGYPTIAN HIEROGLYPH-13FFD;Lo;0;L;;;;;N;;;;; +13FFE;EGYPTIAN HIEROGLYPH-13FFE;Lo;0;L;;;;;N;;;;; +13FFF;EGYPTIAN HIEROGLYPH-13FFF;Lo;0;L;;;;;N;;;;; +14000;EGYPTIAN HIEROGLYPH-14000;Lo;0;L;;;;;N;;;;; +14001;EGYPTIAN HIEROGLYPH-14001;Lo;0;L;;;;;N;;;;; +14002;EGYPTIAN HIEROGLYPH-14002;Lo;0;L;;;;;N;;;;; +14003;EGYPTIAN HIEROGLYPH-14003;Lo;0;L;;;;;N;;;;; +14004;EGYPTIAN HIEROGLYPH-14004;Lo;0;L;;;;;N;;;;; +14005;EGYPTIAN HIEROGLYPH-14005;Lo;0;L;;;;;N;;;;; +14006;EGYPTIAN HIEROGLYPH-14006;Lo;0;L;;;;;N;;;;; +14007;EGYPTIAN HIEROGLYPH-14007;Lo;0;L;;;;;N;;;;; +14008;EGYPTIAN HIEROGLYPH-14008;Lo;0;L;;;;;N;;;;; +14009;EGYPTIAN HIEROGLYPH-14009;Lo;0;L;;;;;N;;;;; +1400A;EGYPTIAN HIEROGLYPH-1400A;Lo;0;L;;;;;N;;;;; +1400B;EGYPTIAN HIEROGLYPH-1400B;Lo;0;L;;;;;N;;;;; +1400C;EGYPTIAN HIEROGLYPH-1400C;Lo;0;L;;;;;N;;;;; +1400D;EGYPTIAN HIEROGLYPH-1400D;Lo;0;L;;;;;N;;;;; +1400E;EGYPTIAN HIEROGLYPH-1400E;Lo;0;L;;;;;N;;;;; +1400F;EGYPTIAN HIEROGLYPH-1400F;Lo;0;L;;;;;N;;;;; +14010;EGYPTIAN HIEROGLYPH-14010;Lo;0;L;;;;;N;;;;; +14011;EGYPTIAN HIEROGLYPH-14011;Lo;0;L;;;;;N;;;;; +14012;EGYPTIAN HIEROGLYPH-14012;Lo;0;L;;;;;N;;;;; +14013;EGYPTIAN HIEROGLYPH-14013;Lo;0;L;;;;;N;;;;; +14014;EGYPTIAN HIEROGLYPH-14014;Lo;0;L;;;;;N;;;;; +14015;EGYPTIAN HIEROGLYPH-14015;Lo;0;L;;;;;N;;;;; +14016;EGYPTIAN HIEROGLYPH-14016;Lo;0;L;;;;;N;;;;; +14017;EGYPTIAN HIEROGLYPH-14017;Lo;0;L;;;;;N;;;;; +14018;EGYPTIAN HIEROGLYPH-14018;Lo;0;L;;;;;N;;;;; +14019;EGYPTIAN HIEROGLYPH-14019;Lo;0;L;;;;;N;;;;; +1401A;EGYPTIAN HIEROGLYPH-1401A;Lo;0;L;;;;;N;;;;; +1401B;EGYPTIAN HIEROGLYPH-1401B;Lo;0;L;;;;;N;;;;; +1401C;EGYPTIAN HIEROGLYPH-1401C;Lo;0;L;;;;;N;;;;; +1401D;EGYPTIAN HIEROGLYPH-1401D;Lo;0;L;;;;;N;;;;; +1401E;EGYPTIAN HIEROGLYPH-1401E;Lo;0;L;;;;;N;;;;; +1401F;EGYPTIAN HIEROGLYPH-1401F;Lo;0;L;;;;;N;;;;; +14020;EGYPTIAN HIEROGLYPH-14020;Lo;0;L;;;;;N;;;;; +14021;EGYPTIAN HIEROGLYPH-14021;Lo;0;L;;;;;N;;;;; +14022;EGYPTIAN HIEROGLYPH-14022;Lo;0;L;;;;;N;;;;; +14023;EGYPTIAN HIEROGLYPH-14023;Lo;0;L;;;;;N;;;;; +14024;EGYPTIAN HIEROGLYPH-14024;Lo;0;L;;;;;N;;;;; +14025;EGYPTIAN HIEROGLYPH-14025;Lo;0;L;;;;;N;;;;; +14026;EGYPTIAN HIEROGLYPH-14026;Lo;0;L;;;;;N;;;;; +14027;EGYPTIAN HIEROGLYPH-14027;Lo;0;L;;;;;N;;;;; +14028;EGYPTIAN HIEROGLYPH-14028;Lo;0;L;;;;;N;;;;; +14029;EGYPTIAN HIEROGLYPH-14029;Lo;0;L;;;;;N;;;;; +1402A;EGYPTIAN HIEROGLYPH-1402A;Lo;0;L;;;;;N;;;;; +1402B;EGYPTIAN HIEROGLYPH-1402B;Lo;0;L;;;;;N;;;;; +1402C;EGYPTIAN HIEROGLYPH-1402C;Lo;0;L;;;;;N;;;;; +1402D;EGYPTIAN HIEROGLYPH-1402D;Lo;0;L;;;;;N;;;;; +1402E;EGYPTIAN HIEROGLYPH-1402E;Lo;0;L;;;;;N;;;;; +1402F;EGYPTIAN HIEROGLYPH-1402F;Lo;0;L;;;;;N;;;;; +14030;EGYPTIAN HIEROGLYPH-14030;Lo;0;L;;;;;N;;;;; +14031;EGYPTIAN HIEROGLYPH-14031;Lo;0;L;;;;;N;;;;; +14032;EGYPTIAN HIEROGLYPH-14032;Lo;0;L;;;;;N;;;;; +14033;EGYPTIAN HIEROGLYPH-14033;Lo;0;L;;;;;N;;;;; +14034;EGYPTIAN HIEROGLYPH-14034;Lo;0;L;;;;;N;;;;; +14035;EGYPTIAN HIEROGLYPH-14035;Lo;0;L;;;;;N;;;;; +14036;EGYPTIAN HIEROGLYPH-14036;Lo;0;L;;;;;N;;;;; +14037;EGYPTIAN HIEROGLYPH-14037;Lo;0;L;;;;;N;;;;; +14038;EGYPTIAN HIEROGLYPH-14038;Lo;0;L;;;;;N;;;;; +14039;EGYPTIAN HIEROGLYPH-14039;Lo;0;L;;;;;N;;;;; +1403A;EGYPTIAN HIEROGLYPH-1403A;Lo;0;L;;;;;N;;;;; +1403B;EGYPTIAN HIEROGLYPH-1403B;Lo;0;L;;;;;N;;;;; +1403C;EGYPTIAN HIEROGLYPH-1403C;Lo;0;L;;;;;N;;;;; +1403D;EGYPTIAN HIEROGLYPH-1403D;Lo;0;L;;;;;N;;;;; +1403E;EGYPTIAN HIEROGLYPH-1403E;Lo;0;L;;;;;N;;;;; +1403F;EGYPTIAN HIEROGLYPH-1403F;Lo;0;L;;;;;N;;;;; +14040;EGYPTIAN HIEROGLYPH-14040;Lo;0;L;;;;;N;;;;; +14041;EGYPTIAN HIEROGLYPH-14041;Lo;0;L;;;;;N;;;;; +14042;EGYPTIAN HIEROGLYPH-14042;Lo;0;L;;;;;N;;;;; +14043;EGYPTIAN HIEROGLYPH-14043;Lo;0;L;;;;;N;;;;; +14044;EGYPTIAN HIEROGLYPH-14044;Lo;0;L;;;;;N;;;;; +14045;EGYPTIAN HIEROGLYPH-14045;Lo;0;L;;;;;N;;;;; +14046;EGYPTIAN HIEROGLYPH-14046;Lo;0;L;;;;;N;;;;; +14047;EGYPTIAN HIEROGLYPH-14047;Lo;0;L;;;;;N;;;;; +14048;EGYPTIAN HIEROGLYPH-14048;Lo;0;L;;;;;N;;;;; +14049;EGYPTIAN HIEROGLYPH-14049;Lo;0;L;;;;;N;;;;; +1404A;EGYPTIAN HIEROGLYPH-1404A;Lo;0;L;;;;;N;;;;; +1404B;EGYPTIAN HIEROGLYPH-1404B;Lo;0;L;;;;;N;;;;; +1404C;EGYPTIAN HIEROGLYPH-1404C;Lo;0;L;;;;;N;;;;; +1404D;EGYPTIAN HIEROGLYPH-1404D;Lo;0;L;;;;;N;;;;; +1404E;EGYPTIAN HIEROGLYPH-1404E;Lo;0;L;;;;;N;;;;; +1404F;EGYPTIAN HIEROGLYPH-1404F;Lo;0;L;;;;;N;;;;; +14050;EGYPTIAN HIEROGLYPH-14050;Lo;0;L;;;;;N;;;;; +14051;EGYPTIAN HIEROGLYPH-14051;Lo;0;L;;;;;N;;;;; +14052;EGYPTIAN HIEROGLYPH-14052;Lo;0;L;;;;;N;;;;; +14053;EGYPTIAN HIEROGLYPH-14053;Lo;0;L;;;;;N;;;;; +14054;EGYPTIAN HIEROGLYPH-14054;Lo;0;L;;;;;N;;;;; +14055;EGYPTIAN HIEROGLYPH-14055;Lo;0;L;;;;;N;;;;; +14056;EGYPTIAN HIEROGLYPH-14056;Lo;0;L;;;;;N;;;;; +14057;EGYPTIAN HIEROGLYPH-14057;Lo;0;L;;;;;N;;;;; +14058;EGYPTIAN HIEROGLYPH-14058;Lo;0;L;;;;;N;;;;; +14059;EGYPTIAN HIEROGLYPH-14059;Lo;0;L;;;;;N;;;;; +1405A;EGYPTIAN HIEROGLYPH-1405A;Lo;0;L;;;;;N;;;;; +1405B;EGYPTIAN HIEROGLYPH-1405B;Lo;0;L;;;;;N;;;;; +1405C;EGYPTIAN HIEROGLYPH-1405C;Lo;0;L;;;;;N;;;;; +1405D;EGYPTIAN HIEROGLYPH-1405D;Lo;0;L;;;;;N;;;;; +1405E;EGYPTIAN HIEROGLYPH-1405E;Lo;0;L;;;;;N;;;;; +1405F;EGYPTIAN HIEROGLYPH-1405F;Lo;0;L;;;;;N;;;;; +14060;EGYPTIAN HIEROGLYPH-14060;Lo;0;L;;;;;N;;;;; +14061;EGYPTIAN HIEROGLYPH-14061;Lo;0;L;;;;;N;;;;; +14062;EGYPTIAN HIEROGLYPH-14062;Lo;0;L;;;;;N;;;;; +14063;EGYPTIAN HIEROGLYPH-14063;Lo;0;L;;;;;N;;;;; +14064;EGYPTIAN HIEROGLYPH-14064;Lo;0;L;;;;;N;;;;; +14065;EGYPTIAN HIEROGLYPH-14065;Lo;0;L;;;;;N;;;;; +14066;EGYPTIAN HIEROGLYPH-14066;Lo;0;L;;;;;N;;;;; +14067;EGYPTIAN HIEROGLYPH-14067;Lo;0;L;;;;;N;;;;; +14068;EGYPTIAN HIEROGLYPH-14068;Lo;0;L;;;;;N;;;;; +14069;EGYPTIAN HIEROGLYPH-14069;Lo;0;L;;;;;N;;;;; +1406A;EGYPTIAN HIEROGLYPH-1406A;Lo;0;L;;;;;N;;;;; +1406B;EGYPTIAN HIEROGLYPH-1406B;Lo;0;L;;;;;N;;;;; +1406C;EGYPTIAN HIEROGLYPH-1406C;Lo;0;L;;;;;N;;;;; +1406D;EGYPTIAN HIEROGLYPH-1406D;Lo;0;L;;;;;N;;;;; +1406E;EGYPTIAN HIEROGLYPH-1406E;Lo;0;L;;;;;N;;;;; +1406F;EGYPTIAN HIEROGLYPH-1406F;Lo;0;L;;;;;N;;;;; +14070;EGYPTIAN HIEROGLYPH-14070;Lo;0;L;;;;;N;;;;; +14071;EGYPTIAN HIEROGLYPH-14071;Lo;0;L;;;;;N;;;;; +14072;EGYPTIAN HIEROGLYPH-14072;Lo;0;L;;;;;N;;;;; +14073;EGYPTIAN HIEROGLYPH-14073;Lo;0;L;;;;;N;;;;; +14074;EGYPTIAN HIEROGLYPH-14074;Lo;0;L;;;;;N;;;;; +14075;EGYPTIAN HIEROGLYPH-14075;Lo;0;L;;;;;N;;;;; +14076;EGYPTIAN HIEROGLYPH-14076;Lo;0;L;;;;;N;;;;; +14077;EGYPTIAN HIEROGLYPH-14077;Lo;0;L;;;;;N;;;;; +14078;EGYPTIAN HIEROGLYPH-14078;Lo;0;L;;;;;N;;;;; +14079;EGYPTIAN HIEROGLYPH-14079;Lo;0;L;;;;;N;;;;; +1407A;EGYPTIAN HIEROGLYPH-1407A;Lo;0;L;;;;;N;;;;; +1407B;EGYPTIAN HIEROGLYPH-1407B;Lo;0;L;;;;;N;;;;; +1407C;EGYPTIAN HIEROGLYPH-1407C;Lo;0;L;;;;;N;;;;; +1407D;EGYPTIAN HIEROGLYPH-1407D;Lo;0;L;;;;;N;;;;; +1407E;EGYPTIAN HIEROGLYPH-1407E;Lo;0;L;;;;;N;;;;; +1407F;EGYPTIAN HIEROGLYPH-1407F;Lo;0;L;;;;;N;;;;; +14080;EGYPTIAN HIEROGLYPH-14080;Lo;0;L;;;;;N;;;;; +14081;EGYPTIAN HIEROGLYPH-14081;Lo;0;L;;;;;N;;;;; +14082;EGYPTIAN HIEROGLYPH-14082;Lo;0;L;;;;;N;;;;; +14083;EGYPTIAN HIEROGLYPH-14083;Lo;0;L;;;;;N;;;;; +14084;EGYPTIAN HIEROGLYPH-14084;Lo;0;L;;;;;N;;;;; +14085;EGYPTIAN HIEROGLYPH-14085;Lo;0;L;;;;;N;;;;; +14086;EGYPTIAN HIEROGLYPH-14086;Lo;0;L;;;;;N;;;;; +14087;EGYPTIAN HIEROGLYPH-14087;Lo;0;L;;;;;N;;;;; +14088;EGYPTIAN HIEROGLYPH-14088;Lo;0;L;;;;;N;;;;; +14089;EGYPTIAN HIEROGLYPH-14089;Lo;0;L;;;;;N;;;;; +1408A;EGYPTIAN HIEROGLYPH-1408A;Lo;0;L;;;;;N;;;;; +1408B;EGYPTIAN HIEROGLYPH-1408B;Lo;0;L;;;;;N;;;;; +1408C;EGYPTIAN HIEROGLYPH-1408C;Lo;0;L;;;;;N;;;;; +1408D;EGYPTIAN HIEROGLYPH-1408D;Lo;0;L;;;;;N;;;;; +1408E;EGYPTIAN HIEROGLYPH-1408E;Lo;0;L;;;;;N;;;;; +1408F;EGYPTIAN HIEROGLYPH-1408F;Lo;0;L;;;;;N;;;;; +14090;EGYPTIAN HIEROGLYPH-14090;Lo;0;L;;;;;N;;;;; +14091;EGYPTIAN HIEROGLYPH-14091;Lo;0;L;;;;;N;;;;; +14092;EGYPTIAN HIEROGLYPH-14092;Lo;0;L;;;;;N;;;;; +14093;EGYPTIAN HIEROGLYPH-14093;Lo;0;L;;;;;N;;;;; +14094;EGYPTIAN HIEROGLYPH-14094;Lo;0;L;;;;;N;;;;; +14095;EGYPTIAN HIEROGLYPH-14095;Lo;0;L;;;;;N;;;;; +14096;EGYPTIAN HIEROGLYPH-14096;Lo;0;L;;;;;N;;;;; +14097;EGYPTIAN HIEROGLYPH-14097;Lo;0;L;;;;;N;;;;; +14098;EGYPTIAN HIEROGLYPH-14098;Lo;0;L;;;;;N;;;;; +14099;EGYPTIAN HIEROGLYPH-14099;Lo;0;L;;;;;N;;;;; +1409A;EGYPTIAN HIEROGLYPH-1409A;Lo;0;L;;;;;N;;;;; +1409B;EGYPTIAN HIEROGLYPH-1409B;Lo;0;L;;;;;N;;;;; +1409C;EGYPTIAN HIEROGLYPH-1409C;Lo;0;L;;;;;N;;;;; +1409D;EGYPTIAN HIEROGLYPH-1409D;Lo;0;L;;;;;N;;;;; +1409E;EGYPTIAN HIEROGLYPH-1409E;Lo;0;L;;;;;N;;;;; +1409F;EGYPTIAN HIEROGLYPH-1409F;Lo;0;L;;;;;N;;;;; +140A0;EGYPTIAN HIEROGLYPH-140A0;Lo;0;L;;;;;N;;;;; +140A1;EGYPTIAN HIEROGLYPH-140A1;Lo;0;L;;;;;N;;;;; +140A2;EGYPTIAN HIEROGLYPH-140A2;Lo;0;L;;;;;N;;;;; +140A3;EGYPTIAN HIEROGLYPH-140A3;Lo;0;L;;;;;N;;;;; +140A4;EGYPTIAN HIEROGLYPH-140A4;Lo;0;L;;;;;N;;;;; +140A5;EGYPTIAN HIEROGLYPH-140A5;Lo;0;L;;;;;N;;;;; +140A6;EGYPTIAN HIEROGLYPH-140A6;Lo;0;L;;;;;N;;;;; +140A7;EGYPTIAN HIEROGLYPH-140A7;Lo;0;L;;;;;N;;;;; +140A8;EGYPTIAN HIEROGLYPH-140A8;Lo;0;L;;;;;N;;;;; +140A9;EGYPTIAN HIEROGLYPH-140A9;Lo;0;L;;;;;N;;;;; +140AA;EGYPTIAN HIEROGLYPH-140AA;Lo;0;L;;;;;N;;;;; +140AB;EGYPTIAN HIEROGLYPH-140AB;Lo;0;L;;;;;N;;;;; +140AC;EGYPTIAN HIEROGLYPH-140AC;Lo;0;L;;;;;N;;;;; +140AD;EGYPTIAN HIEROGLYPH-140AD;Lo;0;L;;;;;N;;;;; +140AE;EGYPTIAN HIEROGLYPH-140AE;Lo;0;L;;;;;N;;;;; +140AF;EGYPTIAN HIEROGLYPH-140AF;Lo;0;L;;;;;N;;;;; +140B0;EGYPTIAN HIEROGLYPH-140B0;Lo;0;L;;;;;N;;;;; +140B1;EGYPTIAN HIEROGLYPH-140B1;Lo;0;L;;;;;N;;;;; +140B2;EGYPTIAN HIEROGLYPH-140B2;Lo;0;L;;;;;N;;;;; +140B3;EGYPTIAN HIEROGLYPH-140B3;Lo;0;L;;;;;N;;;;; +140B4;EGYPTIAN HIEROGLYPH-140B4;Lo;0;L;;;;;N;;;;; +140B5;EGYPTIAN HIEROGLYPH-140B5;Lo;0;L;;;;;N;;;;; +140B6;EGYPTIAN HIEROGLYPH-140B6;Lo;0;L;;;;;N;;;;; +140B7;EGYPTIAN HIEROGLYPH-140B7;Lo;0;L;;;;;N;;;;; +140B8;EGYPTIAN HIEROGLYPH-140B8;Lo;0;L;;;;;N;;;;; +140B9;EGYPTIAN HIEROGLYPH-140B9;Lo;0;L;;;;;N;;;;; +140BA;EGYPTIAN HIEROGLYPH-140BA;Lo;0;L;;;;;N;;;;; +140BB;EGYPTIAN HIEROGLYPH-140BB;Lo;0;L;;;;;N;;;;; +140BC;EGYPTIAN HIEROGLYPH-140BC;Lo;0;L;;;;;N;;;;; +140BD;EGYPTIAN HIEROGLYPH-140BD;Lo;0;L;;;;;N;;;;; +140BE;EGYPTIAN HIEROGLYPH-140BE;Lo;0;L;;;;;N;;;;; +140BF;EGYPTIAN HIEROGLYPH-140BF;Lo;0;L;;;;;N;;;;; +140C0;EGYPTIAN HIEROGLYPH-140C0;Lo;0;L;;;;;N;;;;; +140C1;EGYPTIAN HIEROGLYPH-140C1;Lo;0;L;;;;;N;;;;; +140C2;EGYPTIAN HIEROGLYPH-140C2;Lo;0;L;;;;;N;;;;; +140C3;EGYPTIAN HIEROGLYPH-140C3;Lo;0;L;;;;;N;;;;; +140C4;EGYPTIAN HIEROGLYPH-140C4;Lo;0;L;;;;;N;;;;; +140C5;EGYPTIAN HIEROGLYPH-140C5;Lo;0;L;;;;;N;;;;; +140C6;EGYPTIAN HIEROGLYPH-140C6;Lo;0;L;;;;;N;;;;; +140C7;EGYPTIAN HIEROGLYPH-140C7;Lo;0;L;;;;;N;;;;; +140C8;EGYPTIAN HIEROGLYPH-140C8;Lo;0;L;;;;;N;;;;; +140C9;EGYPTIAN HIEROGLYPH-140C9;Lo;0;L;;;;;N;;;;; +140CA;EGYPTIAN HIEROGLYPH-140CA;Lo;0;L;;;;;N;;;;; +140CB;EGYPTIAN HIEROGLYPH-140CB;Lo;0;L;;;;;N;;;;; +140CC;EGYPTIAN HIEROGLYPH-140CC;Lo;0;L;;;;;N;;;;; +140CD;EGYPTIAN HIEROGLYPH-140CD;Lo;0;L;;;;;N;;;;; +140CE;EGYPTIAN HIEROGLYPH-140CE;Lo;0;L;;;;;N;;;;; +140CF;EGYPTIAN HIEROGLYPH-140CF;Lo;0;L;;;;;N;;;;; +140D0;EGYPTIAN HIEROGLYPH-140D0;Lo;0;L;;;;;N;;;;; +140D1;EGYPTIAN HIEROGLYPH-140D1;Lo;0;L;;;;;N;;;;; +140D2;EGYPTIAN HIEROGLYPH-140D2;Lo;0;L;;;;;N;;;;; +140D3;EGYPTIAN HIEROGLYPH-140D3;Lo;0;L;;;;;N;;;;; +140D4;EGYPTIAN HIEROGLYPH-140D4;Lo;0;L;;;;;N;;;;; +140D5;EGYPTIAN HIEROGLYPH-140D5;Lo;0;L;;;;;N;;;;; +140D6;EGYPTIAN HIEROGLYPH-140D6;Lo;0;L;;;;;N;;;;; +140D7;EGYPTIAN HIEROGLYPH-140D7;Lo;0;L;;;;;N;;;;; +140D8;EGYPTIAN HIEROGLYPH-140D8;Lo;0;L;;;;;N;;;;; +140D9;EGYPTIAN HIEROGLYPH-140D9;Lo;0;L;;;;;N;;;;; +140DA;EGYPTIAN HIEROGLYPH-140DA;Lo;0;L;;;;;N;;;;; +140DB;EGYPTIAN HIEROGLYPH-140DB;Lo;0;L;;;;;N;;;;; +140DC;EGYPTIAN HIEROGLYPH-140DC;Lo;0;L;;;;;N;;;;; +140DD;EGYPTIAN HIEROGLYPH-140DD;Lo;0;L;;;;;N;;;;; +140DE;EGYPTIAN HIEROGLYPH-140DE;Lo;0;L;;;;;N;;;;; +140DF;EGYPTIAN HIEROGLYPH-140DF;Lo;0;L;;;;;N;;;;; +140E0;EGYPTIAN HIEROGLYPH-140E0;Lo;0;L;;;;;N;;;;; +140E1;EGYPTIAN HIEROGLYPH-140E1;Lo;0;L;;;;;N;;;;; +140E2;EGYPTIAN HIEROGLYPH-140E2;Lo;0;L;;;;;N;;;;; +140E3;EGYPTIAN HIEROGLYPH-140E3;Lo;0;L;;;;;N;;;;; +140E4;EGYPTIAN HIEROGLYPH-140E4;Lo;0;L;;;;;N;;;;; +140E5;EGYPTIAN HIEROGLYPH-140E5;Lo;0;L;;;;;N;;;;; +140E6;EGYPTIAN HIEROGLYPH-140E6;Lo;0;L;;;;;N;;;;; +140E7;EGYPTIAN HIEROGLYPH-140E7;Lo;0;L;;;;;N;;;;; +140E8;EGYPTIAN HIEROGLYPH-140E8;Lo;0;L;;;;;N;;;;; +140E9;EGYPTIAN HIEROGLYPH-140E9;Lo;0;L;;;;;N;;;;; +140EA;EGYPTIAN HIEROGLYPH-140EA;Lo;0;L;;;;;N;;;;; +140EB;EGYPTIAN HIEROGLYPH-140EB;Lo;0;L;;;;;N;;;;; +140EC;EGYPTIAN HIEROGLYPH-140EC;Lo;0;L;;;;;N;;;;; +140ED;EGYPTIAN HIEROGLYPH-140ED;Lo;0;L;;;;;N;;;;; +140EE;EGYPTIAN HIEROGLYPH-140EE;Lo;0;L;;;;;N;;;;; +140EF;EGYPTIAN HIEROGLYPH-140EF;Lo;0;L;;;;;N;;;;; +140F0;EGYPTIAN HIEROGLYPH-140F0;Lo;0;L;;;;;N;;;;; +140F1;EGYPTIAN HIEROGLYPH-140F1;Lo;0;L;;;;;N;;;;; +140F2;EGYPTIAN HIEROGLYPH-140F2;Lo;0;L;;;;;N;;;;; +140F3;EGYPTIAN HIEROGLYPH-140F3;Lo;0;L;;;;;N;;;;; +140F4;EGYPTIAN HIEROGLYPH-140F4;Lo;0;L;;;;;N;;;;; +140F5;EGYPTIAN HIEROGLYPH-140F5;Lo;0;L;;;;;N;;;;; +140F6;EGYPTIAN HIEROGLYPH-140F6;Lo;0;L;;;;;N;;;;; +140F7;EGYPTIAN HIEROGLYPH-140F7;Lo;0;L;;;;;N;;;;; +140F8;EGYPTIAN HIEROGLYPH-140F8;Lo;0;L;;;;;N;;;;; +140F9;EGYPTIAN HIEROGLYPH-140F9;Lo;0;L;;;;;N;;;;; +140FA;EGYPTIAN HIEROGLYPH-140FA;Lo;0;L;;;;;N;;;;; +140FB;EGYPTIAN HIEROGLYPH-140FB;Lo;0;L;;;;;N;;;;; +140FC;EGYPTIAN HIEROGLYPH-140FC;Lo;0;L;;;;;N;;;;; +140FD;EGYPTIAN HIEROGLYPH-140FD;Lo;0;L;;;;;N;;;;; +140FE;EGYPTIAN HIEROGLYPH-140FE;Lo;0;L;;;;;N;;;;; +140FF;EGYPTIAN HIEROGLYPH-140FF;Lo;0;L;;;;;N;;;;; +14100;EGYPTIAN HIEROGLYPH-14100;Lo;0;L;;;;;N;;;;; +14101;EGYPTIAN HIEROGLYPH-14101;Lo;0;L;;;;;N;;;;; +14102;EGYPTIAN HIEROGLYPH-14102;Lo;0;L;;;;;N;;;;; +14103;EGYPTIAN HIEROGLYPH-14103;Lo;0;L;;;;;N;;;;; +14104;EGYPTIAN HIEROGLYPH-14104;Lo;0;L;;;;;N;;;;; +14105;EGYPTIAN HIEROGLYPH-14105;Lo;0;L;;;;;N;;;;; +14106;EGYPTIAN HIEROGLYPH-14106;Lo;0;L;;;;;N;;;;; +14107;EGYPTIAN HIEROGLYPH-14107;Lo;0;L;;;;;N;;;;; +14108;EGYPTIAN HIEROGLYPH-14108;Lo;0;L;;;;;N;;;;; +14109;EGYPTIAN HIEROGLYPH-14109;Lo;0;L;;;;;N;;;;; +1410A;EGYPTIAN HIEROGLYPH-1410A;Lo;0;L;;;;;N;;;;; +1410B;EGYPTIAN HIEROGLYPH-1410B;Lo;0;L;;;;;N;;;;; +1410C;EGYPTIAN HIEROGLYPH-1410C;Lo;0;L;;;;;N;;;;; +1410D;EGYPTIAN HIEROGLYPH-1410D;Lo;0;L;;;;;N;;;;; +1410E;EGYPTIAN HIEROGLYPH-1410E;Lo;0;L;;;;;N;;;;; +1410F;EGYPTIAN HIEROGLYPH-1410F;Lo;0;L;;;;;N;;;;; +14110;EGYPTIAN HIEROGLYPH-14110;Lo;0;L;;;;;N;;;;; +14111;EGYPTIAN HIEROGLYPH-14111;Lo;0;L;;;;;N;;;;; +14112;EGYPTIAN HIEROGLYPH-14112;Lo;0;L;;;;;N;;;;; +14113;EGYPTIAN HIEROGLYPH-14113;Lo;0;L;;;;;N;;;;; +14114;EGYPTIAN HIEROGLYPH-14114;Lo;0;L;;;;;N;;;;; +14115;EGYPTIAN HIEROGLYPH-14115;Lo;0;L;;;;;N;;;;; +14116;EGYPTIAN HIEROGLYPH-14116;Lo;0;L;;;;;N;;;;; +14117;EGYPTIAN HIEROGLYPH-14117;Lo;0;L;;;;;N;;;;; +14118;EGYPTIAN HIEROGLYPH-14118;Lo;0;L;;;;;N;;;;; +14119;EGYPTIAN HIEROGLYPH-14119;Lo;0;L;;;;;N;;;;; +1411A;EGYPTIAN HIEROGLYPH-1411A;Lo;0;L;;;;;N;;;;; +1411B;EGYPTIAN HIEROGLYPH-1411B;Lo;0;L;;;;;N;;;;; +1411C;EGYPTIAN HIEROGLYPH-1411C;Lo;0;L;;;;;N;;;;; +1411D;EGYPTIAN HIEROGLYPH-1411D;Lo;0;L;;;;;N;;;;; +1411E;EGYPTIAN HIEROGLYPH-1411E;Lo;0;L;;;;;N;;;;; +1411F;EGYPTIAN HIEROGLYPH-1411F;Lo;0;L;;;;;N;;;;; +14120;EGYPTIAN HIEROGLYPH-14120;Lo;0;L;;;;;N;;;;; +14121;EGYPTIAN HIEROGLYPH-14121;Lo;0;L;;;;;N;;;;; +14122;EGYPTIAN HIEROGLYPH-14122;Lo;0;L;;;;;N;;;;; +14123;EGYPTIAN HIEROGLYPH-14123;Lo;0;L;;;;;N;;;;; +14124;EGYPTIAN HIEROGLYPH-14124;Lo;0;L;;;;;N;;;;; +14125;EGYPTIAN HIEROGLYPH-14125;Lo;0;L;;;;;N;;;;; +14126;EGYPTIAN HIEROGLYPH-14126;Lo;0;L;;;;;N;;;;; +14127;EGYPTIAN HIEROGLYPH-14127;Lo;0;L;;;;;N;;;;; +14128;EGYPTIAN HIEROGLYPH-14128;Lo;0;L;;;;;N;;;;; +14129;EGYPTIAN HIEROGLYPH-14129;Lo;0;L;;;;;N;;;;; +1412A;EGYPTIAN HIEROGLYPH-1412A;Lo;0;L;;;;;N;;;;; +1412B;EGYPTIAN HIEROGLYPH-1412B;Lo;0;L;;;;;N;;;;; +1412C;EGYPTIAN HIEROGLYPH-1412C;Lo;0;L;;;;;N;;;;; +1412D;EGYPTIAN HIEROGLYPH-1412D;Lo;0;L;;;;;N;;;;; +1412E;EGYPTIAN HIEROGLYPH-1412E;Lo;0;L;;;;;N;;;;; +1412F;EGYPTIAN HIEROGLYPH-1412F;Lo;0;L;;;;;N;;;;; +14130;EGYPTIAN HIEROGLYPH-14130;Lo;0;L;;;;;N;;;;; +14131;EGYPTIAN HIEROGLYPH-14131;Lo;0;L;;;;;N;;;;; +14132;EGYPTIAN HIEROGLYPH-14132;Lo;0;L;;;;;N;;;;; +14133;EGYPTIAN HIEROGLYPH-14133;Lo;0;L;;;;;N;;;;; +14134;EGYPTIAN HIEROGLYPH-14134;Lo;0;L;;;;;N;;;;; +14135;EGYPTIAN HIEROGLYPH-14135;Lo;0;L;;;;;N;;;;; +14136;EGYPTIAN HIEROGLYPH-14136;Lo;0;L;;;;;N;;;;; +14137;EGYPTIAN HIEROGLYPH-14137;Lo;0;L;;;;;N;;;;; +14138;EGYPTIAN HIEROGLYPH-14138;Lo;0;L;;;;;N;;;;; +14139;EGYPTIAN HIEROGLYPH-14139;Lo;0;L;;;;;N;;;;; +1413A;EGYPTIAN HIEROGLYPH-1413A;Lo;0;L;;;;;N;;;;; +1413B;EGYPTIAN HIEROGLYPH-1413B;Lo;0;L;;;;;N;;;;; +1413C;EGYPTIAN HIEROGLYPH-1413C;Lo;0;L;;;;;N;;;;; +1413D;EGYPTIAN HIEROGLYPH-1413D;Lo;0;L;;;;;N;;;;; +1413E;EGYPTIAN HIEROGLYPH-1413E;Lo;0;L;;;;;N;;;;; +1413F;EGYPTIAN HIEROGLYPH-1413F;Lo;0;L;;;;;N;;;;; +14140;EGYPTIAN HIEROGLYPH-14140;Lo;0;L;;;;;N;;;;; +14141;EGYPTIAN HIEROGLYPH-14141;Lo;0;L;;;;;N;;;;; +14142;EGYPTIAN HIEROGLYPH-14142;Lo;0;L;;;;;N;;;;; +14143;EGYPTIAN HIEROGLYPH-14143;Lo;0;L;;;;;N;;;;; +14144;EGYPTIAN HIEROGLYPH-14144;Lo;0;L;;;;;N;;;;; +14145;EGYPTIAN HIEROGLYPH-14145;Lo;0;L;;;;;N;;;;; +14146;EGYPTIAN HIEROGLYPH-14146;Lo;0;L;;;;;N;;;;; +14147;EGYPTIAN HIEROGLYPH-14147;Lo;0;L;;;;;N;;;;; +14148;EGYPTIAN HIEROGLYPH-14148;Lo;0;L;;;;;N;;;;; +14149;EGYPTIAN HIEROGLYPH-14149;Lo;0;L;;;;;N;;;;; +1414A;EGYPTIAN HIEROGLYPH-1414A;Lo;0;L;;;;;N;;;;; +1414B;EGYPTIAN HIEROGLYPH-1414B;Lo;0;L;;;;;N;;;;; +1414C;EGYPTIAN HIEROGLYPH-1414C;Lo;0;L;;;;;N;;;;; +1414D;EGYPTIAN HIEROGLYPH-1414D;Lo;0;L;;;;;N;;;;; +1414E;EGYPTIAN HIEROGLYPH-1414E;Lo;0;L;;;;;N;;;;; +1414F;EGYPTIAN HIEROGLYPH-1414F;Lo;0;L;;;;;N;;;;; +14150;EGYPTIAN HIEROGLYPH-14150;Lo;0;L;;;;;N;;;;; +14151;EGYPTIAN HIEROGLYPH-14151;Lo;0;L;;;;;N;;;;; +14152;EGYPTIAN HIEROGLYPH-14152;Lo;0;L;;;;;N;;;;; +14153;EGYPTIAN HIEROGLYPH-14153;Lo;0;L;;;;;N;;;;; +14154;EGYPTIAN HIEROGLYPH-14154;Lo;0;L;;;;;N;;;;; +14155;EGYPTIAN HIEROGLYPH-14155;Lo;0;L;;;;;N;;;;; +14156;EGYPTIAN HIEROGLYPH-14156;Lo;0;L;;;;;N;;;;; +14157;EGYPTIAN HIEROGLYPH-14157;Lo;0;L;;;;;N;;;;; +14158;EGYPTIAN HIEROGLYPH-14158;Lo;0;L;;;;;N;;;;; +14159;EGYPTIAN HIEROGLYPH-14159;Lo;0;L;;;;;N;;;;; +1415A;EGYPTIAN HIEROGLYPH-1415A;Lo;0;L;;;;;N;;;;; +1415B;EGYPTIAN HIEROGLYPH-1415B;Lo;0;L;;;;;N;;;;; +1415C;EGYPTIAN HIEROGLYPH-1415C;Lo;0;L;;;;;N;;;;; +1415D;EGYPTIAN HIEROGLYPH-1415D;Lo;0;L;;;;;N;;;;; +1415E;EGYPTIAN HIEROGLYPH-1415E;Lo;0;L;;;;;N;;;;; +1415F;EGYPTIAN HIEROGLYPH-1415F;Lo;0;L;;;;;N;;;;; +14160;EGYPTIAN HIEROGLYPH-14160;Lo;0;L;;;;;N;;;;; +14161;EGYPTIAN HIEROGLYPH-14161;Lo;0;L;;;;;N;;;;; +14162;EGYPTIAN HIEROGLYPH-14162;Lo;0;L;;;;;N;;;;; +14163;EGYPTIAN HIEROGLYPH-14163;Lo;0;L;;;;;N;;;;; +14164;EGYPTIAN HIEROGLYPH-14164;Lo;0;L;;;;;N;;;;; +14165;EGYPTIAN HIEROGLYPH-14165;Lo;0;L;;;;;N;;;;; +14166;EGYPTIAN HIEROGLYPH-14166;Lo;0;L;;;;;N;;;;; +14167;EGYPTIAN HIEROGLYPH-14167;Lo;0;L;;;;;N;;;;; +14168;EGYPTIAN HIEROGLYPH-14168;Lo;0;L;;;;;N;;;;; +14169;EGYPTIAN HIEROGLYPH-14169;Lo;0;L;;;;;N;;;;; +1416A;EGYPTIAN HIEROGLYPH-1416A;Lo;0;L;;;;;N;;;;; +1416B;EGYPTIAN HIEROGLYPH-1416B;Lo;0;L;;;;;N;;;;; +1416C;EGYPTIAN HIEROGLYPH-1416C;Lo;0;L;;;;;N;;;;; +1416D;EGYPTIAN HIEROGLYPH-1416D;Lo;0;L;;;;;N;;;;; +1416E;EGYPTIAN HIEROGLYPH-1416E;Lo;0;L;;;;;N;;;;; +1416F;EGYPTIAN HIEROGLYPH-1416F;Lo;0;L;;;;;N;;;;; +14170;EGYPTIAN HIEROGLYPH-14170;Lo;0;L;;;;;N;;;;; +14171;EGYPTIAN HIEROGLYPH-14171;Lo;0;L;;;;;N;;;;; +14172;EGYPTIAN HIEROGLYPH-14172;Lo;0;L;;;;;N;;;;; +14173;EGYPTIAN HIEROGLYPH-14173;Lo;0;L;;;;;N;;;;; +14174;EGYPTIAN HIEROGLYPH-14174;Lo;0;L;;;;;N;;;;; +14175;EGYPTIAN HIEROGLYPH-14175;Lo;0;L;;;;;N;;;;; +14176;EGYPTIAN HIEROGLYPH-14176;Lo;0;L;;;;;N;;;;; +14177;EGYPTIAN HIEROGLYPH-14177;Lo;0;L;;;;;N;;;;; +14178;EGYPTIAN HIEROGLYPH-14178;Lo;0;L;;;;;N;;;;; +14179;EGYPTIAN HIEROGLYPH-14179;Lo;0;L;;;;;N;;;;; +1417A;EGYPTIAN HIEROGLYPH-1417A;Lo;0;L;;;;;N;;;;; +1417B;EGYPTIAN HIEROGLYPH-1417B;Lo;0;L;;;;;N;;;;; +1417C;EGYPTIAN HIEROGLYPH-1417C;Lo;0;L;;;;;N;;;;; +1417D;EGYPTIAN HIEROGLYPH-1417D;Lo;0;L;;;;;N;;;;; +1417E;EGYPTIAN HIEROGLYPH-1417E;Lo;0;L;;;;;N;;;;; +1417F;EGYPTIAN HIEROGLYPH-1417F;Lo;0;L;;;;;N;;;;; +14180;EGYPTIAN HIEROGLYPH-14180;Lo;0;L;;;;;N;;;;; +14181;EGYPTIAN HIEROGLYPH-14181;Lo;0;L;;;;;N;;;;; +14182;EGYPTIAN HIEROGLYPH-14182;Lo;0;L;;;;;N;;;;; +14183;EGYPTIAN HIEROGLYPH-14183;Lo;0;L;;;;;N;;;;; +14184;EGYPTIAN HIEROGLYPH-14184;Lo;0;L;;;;;N;;;;; +14185;EGYPTIAN HIEROGLYPH-14185;Lo;0;L;;;;;N;;;;; +14186;EGYPTIAN HIEROGLYPH-14186;Lo;0;L;;;;;N;;;;; +14187;EGYPTIAN HIEROGLYPH-14187;Lo;0;L;;;;;N;;;;; +14188;EGYPTIAN HIEROGLYPH-14188;Lo;0;L;;;;;N;;;;; +14189;EGYPTIAN HIEROGLYPH-14189;Lo;0;L;;;;;N;;;;; +1418A;EGYPTIAN HIEROGLYPH-1418A;Lo;0;L;;;;;N;;;;; +1418B;EGYPTIAN HIEROGLYPH-1418B;Lo;0;L;;;;;N;;;;; +1418C;EGYPTIAN HIEROGLYPH-1418C;Lo;0;L;;;;;N;;;;; +1418D;EGYPTIAN HIEROGLYPH-1418D;Lo;0;L;;;;;N;;;;; +1418E;EGYPTIAN HIEROGLYPH-1418E;Lo;0;L;;;;;N;;;;; +1418F;EGYPTIAN HIEROGLYPH-1418F;Lo;0;L;;;;;N;;;;; +14190;EGYPTIAN HIEROGLYPH-14190;Lo;0;L;;;;;N;;;;; +14191;EGYPTIAN HIEROGLYPH-14191;Lo;0;L;;;;;N;;;;; +14192;EGYPTIAN HIEROGLYPH-14192;Lo;0;L;;;;;N;;;;; +14193;EGYPTIAN HIEROGLYPH-14193;Lo;0;L;;;;;N;;;;; +14194;EGYPTIAN HIEROGLYPH-14194;Lo;0;L;;;;;N;;;;; +14195;EGYPTIAN HIEROGLYPH-14195;Lo;0;L;;;;;N;;;;; +14196;EGYPTIAN HIEROGLYPH-14196;Lo;0;L;;;;;N;;;;; +14197;EGYPTIAN HIEROGLYPH-14197;Lo;0;L;;;;;N;;;;; +14198;EGYPTIAN HIEROGLYPH-14198;Lo;0;L;;;;;N;;;;; +14199;EGYPTIAN HIEROGLYPH-14199;Lo;0;L;;;;;N;;;;; +1419A;EGYPTIAN HIEROGLYPH-1419A;Lo;0;L;;;;;N;;;;; +1419B;EGYPTIAN HIEROGLYPH-1419B;Lo;0;L;;;;;N;;;;; +1419C;EGYPTIAN HIEROGLYPH-1419C;Lo;0;L;;;;;N;;;;; +1419D;EGYPTIAN HIEROGLYPH-1419D;Lo;0;L;;;;;N;;;;; +1419E;EGYPTIAN HIEROGLYPH-1419E;Lo;0;L;;;;;N;;;;; +1419F;EGYPTIAN HIEROGLYPH-1419F;Lo;0;L;;;;;N;;;;; +141A0;EGYPTIAN HIEROGLYPH-141A0;Lo;0;L;;;;;N;;;;; +141A1;EGYPTIAN HIEROGLYPH-141A1;Lo;0;L;;;;;N;;;;; +141A2;EGYPTIAN HIEROGLYPH-141A2;Lo;0;L;;;;;N;;;;; +141A3;EGYPTIAN HIEROGLYPH-141A3;Lo;0;L;;;;;N;;;;; +141A4;EGYPTIAN HIEROGLYPH-141A4;Lo;0;L;;;;;N;;;;; +141A5;EGYPTIAN HIEROGLYPH-141A5;Lo;0;L;;;;;N;;;;; +141A6;EGYPTIAN HIEROGLYPH-141A6;Lo;0;L;;;;;N;;;;; +141A7;EGYPTIAN HIEROGLYPH-141A7;Lo;0;L;;;;;N;;;;; +141A8;EGYPTIAN HIEROGLYPH-141A8;Lo;0;L;;;;;N;;;;; +141A9;EGYPTIAN HIEROGLYPH-141A9;Lo;0;L;;;;;N;;;;; +141AA;EGYPTIAN HIEROGLYPH-141AA;Lo;0;L;;;;;N;;;;; +141AB;EGYPTIAN HIEROGLYPH-141AB;Lo;0;L;;;;;N;;;;; +141AC;EGYPTIAN HIEROGLYPH-141AC;Lo;0;L;;;;;N;;;;; +141AD;EGYPTIAN HIEROGLYPH-141AD;Lo;0;L;;;;;N;;;;; +141AE;EGYPTIAN HIEROGLYPH-141AE;Lo;0;L;;;;;N;;;;; +141AF;EGYPTIAN HIEROGLYPH-141AF;Lo;0;L;;;;;N;;;;; +141B0;EGYPTIAN HIEROGLYPH-141B0;Lo;0;L;;;;;N;;;;; +141B1;EGYPTIAN HIEROGLYPH-141B1;Lo;0;L;;;;;N;;;;; +141B2;EGYPTIAN HIEROGLYPH-141B2;Lo;0;L;;;;;N;;;;; +141B3;EGYPTIAN HIEROGLYPH-141B3;Lo;0;L;;;;;N;;;;; +141B4;EGYPTIAN HIEROGLYPH-141B4;Lo;0;L;;;;;N;;;;; +141B5;EGYPTIAN HIEROGLYPH-141B5;Lo;0;L;;;;;N;;;;; +141B6;EGYPTIAN HIEROGLYPH-141B6;Lo;0;L;;;;;N;;;;; +141B7;EGYPTIAN HIEROGLYPH-141B7;Lo;0;L;;;;;N;;;;; +141B8;EGYPTIAN HIEROGLYPH-141B8;Lo;0;L;;;;;N;;;;; +141B9;EGYPTIAN HIEROGLYPH-141B9;Lo;0;L;;;;;N;;;;; +141BA;EGYPTIAN HIEROGLYPH-141BA;Lo;0;L;;;;;N;;;;; +141BB;EGYPTIAN HIEROGLYPH-141BB;Lo;0;L;;;;;N;;;;; +141BC;EGYPTIAN HIEROGLYPH-141BC;Lo;0;L;;;;;N;;;;; +141BD;EGYPTIAN HIEROGLYPH-141BD;Lo;0;L;;;;;N;;;;; +141BE;EGYPTIAN HIEROGLYPH-141BE;Lo;0;L;;;;;N;;;;; +141BF;EGYPTIAN HIEROGLYPH-141BF;Lo;0;L;;;;;N;;;;; +141C0;EGYPTIAN HIEROGLYPH-141C0;Lo;0;L;;;;;N;;;;; +141C1;EGYPTIAN HIEROGLYPH-141C1;Lo;0;L;;;;;N;;;;; +141C2;EGYPTIAN HIEROGLYPH-141C2;Lo;0;L;;;;;N;;;;; +141C3;EGYPTIAN HIEROGLYPH-141C3;Lo;0;L;;;;;N;;;;; +141C4;EGYPTIAN HIEROGLYPH-141C4;Lo;0;L;;;;;N;;;;; +141C5;EGYPTIAN HIEROGLYPH-141C5;Lo;0;L;;;;;N;;;;; +141C6;EGYPTIAN HIEROGLYPH-141C6;Lo;0;L;;;;;N;;;;; +141C7;EGYPTIAN HIEROGLYPH-141C7;Lo;0;L;;;;;N;;;;; +141C8;EGYPTIAN HIEROGLYPH-141C8;Lo;0;L;;;;;N;;;;; +141C9;EGYPTIAN HIEROGLYPH-141C9;Lo;0;L;;;;;N;;;;; +141CA;EGYPTIAN HIEROGLYPH-141CA;Lo;0;L;;;;;N;;;;; +141CB;EGYPTIAN HIEROGLYPH-141CB;Lo;0;L;;;;;N;;;;; +141CC;EGYPTIAN HIEROGLYPH-141CC;Lo;0;L;;;;;N;;;;; +141CD;EGYPTIAN HIEROGLYPH-141CD;Lo;0;L;;;;;N;;;;; +141CE;EGYPTIAN HIEROGLYPH-141CE;Lo;0;L;;;;;N;;;;; +141CF;EGYPTIAN HIEROGLYPH-141CF;Lo;0;L;;;;;N;;;;; +141D0;EGYPTIAN HIEROGLYPH-141D0;Lo;0;L;;;;;N;;;;; +141D1;EGYPTIAN HIEROGLYPH-141D1;Lo;0;L;;;;;N;;;;; +141D2;EGYPTIAN HIEROGLYPH-141D2;Lo;0;L;;;;;N;;;;; +141D3;EGYPTIAN HIEROGLYPH-141D3;Lo;0;L;;;;;N;;;;; +141D4;EGYPTIAN HIEROGLYPH-141D4;Lo;0;L;;;;;N;;;;; +141D5;EGYPTIAN HIEROGLYPH-141D5;Lo;0;L;;;;;N;;;;; +141D6;EGYPTIAN HIEROGLYPH-141D6;Lo;0;L;;;;;N;;;;; +141D7;EGYPTIAN HIEROGLYPH-141D7;Lo;0;L;;;;;N;;;;; +141D8;EGYPTIAN HIEROGLYPH-141D8;Lo;0;L;;;;;N;;;;; +141D9;EGYPTIAN HIEROGLYPH-141D9;Lo;0;L;;;;;N;;;;; +141DA;EGYPTIAN HIEROGLYPH-141DA;Lo;0;L;;;;;N;;;;; +141DB;EGYPTIAN HIEROGLYPH-141DB;Lo;0;L;;;;;N;;;;; +141DC;EGYPTIAN HIEROGLYPH-141DC;Lo;0;L;;;;;N;;;;; +141DD;EGYPTIAN HIEROGLYPH-141DD;Lo;0;L;;;;;N;;;;; +141DE;EGYPTIAN HIEROGLYPH-141DE;Lo;0;L;;;;;N;;;;; +141DF;EGYPTIAN HIEROGLYPH-141DF;Lo;0;L;;;;;N;;;;; +141E0;EGYPTIAN HIEROGLYPH-141E0;Lo;0;L;;;;;N;;;;; +141E1;EGYPTIAN HIEROGLYPH-141E1;Lo;0;L;;;;;N;;;;; +141E2;EGYPTIAN HIEROGLYPH-141E2;Lo;0;L;;;;;N;;;;; +141E3;EGYPTIAN HIEROGLYPH-141E3;Lo;0;L;;;;;N;;;;; +141E4;EGYPTIAN HIEROGLYPH-141E4;Lo;0;L;;;;;N;;;;; +141E5;EGYPTIAN HIEROGLYPH-141E5;Lo;0;L;;;;;N;;;;; +141E6;EGYPTIAN HIEROGLYPH-141E6;Lo;0;L;;;;;N;;;;; +141E7;EGYPTIAN HIEROGLYPH-141E7;Lo;0;L;;;;;N;;;;; +141E8;EGYPTIAN HIEROGLYPH-141E8;Lo;0;L;;;;;N;;;;; +141E9;EGYPTIAN HIEROGLYPH-141E9;Lo;0;L;;;;;N;;;;; +141EA;EGYPTIAN HIEROGLYPH-141EA;Lo;0;L;;;;;N;;;;; +141EB;EGYPTIAN HIEROGLYPH-141EB;Lo;0;L;;;;;N;;;;; +141EC;EGYPTIAN HIEROGLYPH-141EC;Lo;0;L;;;;;N;;;;; +141ED;EGYPTIAN HIEROGLYPH-141ED;Lo;0;L;;;;;N;;;;; +141EE;EGYPTIAN HIEROGLYPH-141EE;Lo;0;L;;;;;N;;;;; +141EF;EGYPTIAN HIEROGLYPH-141EF;Lo;0;L;;;;;N;;;;; +141F0;EGYPTIAN HIEROGLYPH-141F0;Lo;0;L;;;;;N;;;;; +141F1;EGYPTIAN HIEROGLYPH-141F1;Lo;0;L;;;;;N;;;;; +141F2;EGYPTIAN HIEROGLYPH-141F2;Lo;0;L;;;;;N;;;;; +141F3;EGYPTIAN HIEROGLYPH-141F3;Lo;0;L;;;;;N;;;;; +141F4;EGYPTIAN HIEROGLYPH-141F4;Lo;0;L;;;;;N;;;;; +141F5;EGYPTIAN HIEROGLYPH-141F5;Lo;0;L;;;;;N;;;;; +141F6;EGYPTIAN HIEROGLYPH-141F6;Lo;0;L;;;;;N;;;;; +141F7;EGYPTIAN HIEROGLYPH-141F7;Lo;0;L;;;;;N;;;;; +141F8;EGYPTIAN HIEROGLYPH-141F8;Lo;0;L;;;;;N;;;;; +141F9;EGYPTIAN HIEROGLYPH-141F9;Lo;0;L;;;;;N;;;;; +141FA;EGYPTIAN HIEROGLYPH-141FA;Lo;0;L;;;;;N;;;;; +141FB;EGYPTIAN HIEROGLYPH-141FB;Lo;0;L;;;;;N;;;;; +141FC;EGYPTIAN HIEROGLYPH-141FC;Lo;0;L;;;;;N;;;;; +141FD;EGYPTIAN HIEROGLYPH-141FD;Lo;0;L;;;;;N;;;;; +141FE;EGYPTIAN HIEROGLYPH-141FE;Lo;0;L;;;;;N;;;;; +141FF;EGYPTIAN HIEROGLYPH-141FF;Lo;0;L;;;;;N;;;;; +14200;EGYPTIAN HIEROGLYPH-14200;Lo;0;L;;;;;N;;;;; +14201;EGYPTIAN HIEROGLYPH-14201;Lo;0;L;;;;;N;;;;; +14202;EGYPTIAN HIEROGLYPH-14202;Lo;0;L;;;;;N;;;;; +14203;EGYPTIAN HIEROGLYPH-14203;Lo;0;L;;;;;N;;;;; +14204;EGYPTIAN HIEROGLYPH-14204;Lo;0;L;;;;;N;;;;; +14205;EGYPTIAN HIEROGLYPH-14205;Lo;0;L;;;;;N;;;;; +14206;EGYPTIAN HIEROGLYPH-14206;Lo;0;L;;;;;N;;;;; +14207;EGYPTIAN HIEROGLYPH-14207;Lo;0;L;;;;;N;;;;; +14208;EGYPTIAN HIEROGLYPH-14208;Lo;0;L;;;;;N;;;;; +14209;EGYPTIAN HIEROGLYPH-14209;Lo;0;L;;;;;N;;;;; +1420A;EGYPTIAN HIEROGLYPH-1420A;Lo;0;L;;;;;N;;;;; +1420B;EGYPTIAN HIEROGLYPH-1420B;Lo;0;L;;;;;N;;;;; +1420C;EGYPTIAN HIEROGLYPH-1420C;Lo;0;L;;;;;N;;;;; +1420D;EGYPTIAN HIEROGLYPH-1420D;Lo;0;L;;;;;N;;;;; +1420E;EGYPTIAN HIEROGLYPH-1420E;Lo;0;L;;;;;N;;;;; +1420F;EGYPTIAN HIEROGLYPH-1420F;Lo;0;L;;;;;N;;;;; +14210;EGYPTIAN HIEROGLYPH-14210;Lo;0;L;;;;;N;;;;; +14211;EGYPTIAN HIEROGLYPH-14211;Lo;0;L;;;;;N;;;;; +14212;EGYPTIAN HIEROGLYPH-14212;Lo;0;L;;;;;N;;;;; +14213;EGYPTIAN HIEROGLYPH-14213;Lo;0;L;;;;;N;;;;; +14214;EGYPTIAN HIEROGLYPH-14214;Lo;0;L;;;;;N;;;;; +14215;EGYPTIAN HIEROGLYPH-14215;Lo;0;L;;;;;N;;;;; +14216;EGYPTIAN HIEROGLYPH-14216;Lo;0;L;;;;;N;;;;; +14217;EGYPTIAN HIEROGLYPH-14217;Lo;0;L;;;;;N;;;;; +14218;EGYPTIAN HIEROGLYPH-14218;Lo;0;L;;;;;N;;;;; +14219;EGYPTIAN HIEROGLYPH-14219;Lo;0;L;;;;;N;;;;; +1421A;EGYPTIAN HIEROGLYPH-1421A;Lo;0;L;;;;;N;;;;; +1421B;EGYPTIAN HIEROGLYPH-1421B;Lo;0;L;;;;;N;;;;; +1421C;EGYPTIAN HIEROGLYPH-1421C;Lo;0;L;;;;;N;;;;; +1421D;EGYPTIAN HIEROGLYPH-1421D;Lo;0;L;;;;;N;;;;; +1421E;EGYPTIAN HIEROGLYPH-1421E;Lo;0;L;;;;;N;;;;; +1421F;EGYPTIAN HIEROGLYPH-1421F;Lo;0;L;;;;;N;;;;; +14220;EGYPTIAN HIEROGLYPH-14220;Lo;0;L;;;;;N;;;;; +14221;EGYPTIAN HIEROGLYPH-14221;Lo;0;L;;;;;N;;;;; +14222;EGYPTIAN HIEROGLYPH-14222;Lo;0;L;;;;;N;;;;; +14223;EGYPTIAN HIEROGLYPH-14223;Lo;0;L;;;;;N;;;;; +14224;EGYPTIAN HIEROGLYPH-14224;Lo;0;L;;;;;N;;;;; +14225;EGYPTIAN HIEROGLYPH-14225;Lo;0;L;;;;;N;;;;; +14226;EGYPTIAN HIEROGLYPH-14226;Lo;0;L;;;;;N;;;;; +14227;EGYPTIAN HIEROGLYPH-14227;Lo;0;L;;;;;N;;;;; +14228;EGYPTIAN HIEROGLYPH-14228;Lo;0;L;;;;;N;;;;; +14229;EGYPTIAN HIEROGLYPH-14229;Lo;0;L;;;;;N;;;;; +1422A;EGYPTIAN HIEROGLYPH-1422A;Lo;0;L;;;;;N;;;;; +1422B;EGYPTIAN HIEROGLYPH-1422B;Lo;0;L;;;;;N;;;;; +1422C;EGYPTIAN HIEROGLYPH-1422C;Lo;0;L;;;;;N;;;;; +1422D;EGYPTIAN HIEROGLYPH-1422D;Lo;0;L;;;;;N;;;;; +1422E;EGYPTIAN HIEROGLYPH-1422E;Lo;0;L;;;;;N;;;;; +1422F;EGYPTIAN HIEROGLYPH-1422F;Lo;0;L;;;;;N;;;;; +14230;EGYPTIAN HIEROGLYPH-14230;Lo;0;L;;;;;N;;;;; +14231;EGYPTIAN HIEROGLYPH-14231;Lo;0;L;;;;;N;;;;; +14232;EGYPTIAN HIEROGLYPH-14232;Lo;0;L;;;;;N;;;;; +14233;EGYPTIAN HIEROGLYPH-14233;Lo;0;L;;;;;N;;;;; +14234;EGYPTIAN HIEROGLYPH-14234;Lo;0;L;;;;;N;;;;; +14235;EGYPTIAN HIEROGLYPH-14235;Lo;0;L;;;;;N;;;;; +14236;EGYPTIAN HIEROGLYPH-14236;Lo;0;L;;;;;N;;;;; +14237;EGYPTIAN HIEROGLYPH-14237;Lo;0;L;;;;;N;;;;; +14238;EGYPTIAN HIEROGLYPH-14238;Lo;0;L;;;;;N;;;;; +14239;EGYPTIAN HIEROGLYPH-14239;Lo;0;L;;;;;N;;;;; +1423A;EGYPTIAN HIEROGLYPH-1423A;Lo;0;L;;;;;N;;;;; +1423B;EGYPTIAN HIEROGLYPH-1423B;Lo;0;L;;;;;N;;;;; +1423C;EGYPTIAN HIEROGLYPH-1423C;Lo;0;L;;;;;N;;;;; +1423D;EGYPTIAN HIEROGLYPH-1423D;Lo;0;L;;;;;N;;;;; +1423E;EGYPTIAN HIEROGLYPH-1423E;Lo;0;L;;;;;N;;;;; +1423F;EGYPTIAN HIEROGLYPH-1423F;Lo;0;L;;;;;N;;;;; +14240;EGYPTIAN HIEROGLYPH-14240;Lo;0;L;;;;;N;;;;; +14241;EGYPTIAN HIEROGLYPH-14241;Lo;0;L;;;;;N;;;;; +14242;EGYPTIAN HIEROGLYPH-14242;Lo;0;L;;;;;N;;;;; +14243;EGYPTIAN HIEROGLYPH-14243;Lo;0;L;;;;;N;;;;; +14244;EGYPTIAN HIEROGLYPH-14244;Lo;0;L;;;;;N;;;;; +14245;EGYPTIAN HIEROGLYPH-14245;Lo;0;L;;;;;N;;;;; +14246;EGYPTIAN HIEROGLYPH-14246;Lo;0;L;;;;;N;;;;; +14247;EGYPTIAN HIEROGLYPH-14247;Lo;0;L;;;;;N;;;;; +14248;EGYPTIAN HIEROGLYPH-14248;Lo;0;L;;;;;N;;;;; +14249;EGYPTIAN HIEROGLYPH-14249;Lo;0;L;;;;;N;;;;; +1424A;EGYPTIAN HIEROGLYPH-1424A;Lo;0;L;;;;;N;;;;; +1424B;EGYPTIAN HIEROGLYPH-1424B;Lo;0;L;;;;;N;;;;; +1424C;EGYPTIAN HIEROGLYPH-1424C;Lo;0;L;;;;;N;;;;; +1424D;EGYPTIAN HIEROGLYPH-1424D;Lo;0;L;;;;;N;;;;; +1424E;EGYPTIAN HIEROGLYPH-1424E;Lo;0;L;;;;;N;;;;; +1424F;EGYPTIAN HIEROGLYPH-1424F;Lo;0;L;;;;;N;;;;; +14250;EGYPTIAN HIEROGLYPH-14250;Lo;0;L;;;;;N;;;;; +14251;EGYPTIAN HIEROGLYPH-14251;Lo;0;L;;;;;N;;;;; +14252;EGYPTIAN HIEROGLYPH-14252;Lo;0;L;;;;;N;;;;; +14253;EGYPTIAN HIEROGLYPH-14253;Lo;0;L;;;;;N;;;;; +14254;EGYPTIAN HIEROGLYPH-14254;Lo;0;L;;;;;N;;;;; +14255;EGYPTIAN HIEROGLYPH-14255;Lo;0;L;;;;;N;;;;; +14256;EGYPTIAN HIEROGLYPH-14256;Lo;0;L;;;;;N;;;;; +14257;EGYPTIAN HIEROGLYPH-14257;Lo;0;L;;;;;N;;;;; +14258;EGYPTIAN HIEROGLYPH-14258;Lo;0;L;;;;;N;;;;; +14259;EGYPTIAN HIEROGLYPH-14259;Lo;0;L;;;;;N;;;;; +1425A;EGYPTIAN HIEROGLYPH-1425A;Lo;0;L;;;;;N;;;;; +1425B;EGYPTIAN HIEROGLYPH-1425B;Lo;0;L;;;;;N;;;;; +1425C;EGYPTIAN HIEROGLYPH-1425C;Lo;0;L;;;;;N;;;;; +1425D;EGYPTIAN HIEROGLYPH-1425D;Lo;0;L;;;;;N;;;;; +1425E;EGYPTIAN HIEROGLYPH-1425E;Lo;0;L;;;;;N;;;;; +1425F;EGYPTIAN HIEROGLYPH-1425F;Lo;0;L;;;;;N;;;;; +14260;EGYPTIAN HIEROGLYPH-14260;Lo;0;L;;;;;N;;;;; +14261;EGYPTIAN HIEROGLYPH-14261;Lo;0;L;;;;;N;;;;; +14262;EGYPTIAN HIEROGLYPH-14262;Lo;0;L;;;;;N;;;;; +14263;EGYPTIAN HIEROGLYPH-14263;Lo;0;L;;;;;N;;;;; +14264;EGYPTIAN HIEROGLYPH-14264;Lo;0;L;;;;;N;;;;; +14265;EGYPTIAN HIEROGLYPH-14265;Lo;0;L;;;;;N;;;;; +14266;EGYPTIAN HIEROGLYPH-14266;Lo;0;L;;;;;N;;;;; +14267;EGYPTIAN HIEROGLYPH-14267;Lo;0;L;;;;;N;;;;; +14268;EGYPTIAN HIEROGLYPH-14268;Lo;0;L;;;;;N;;;;; +14269;EGYPTIAN HIEROGLYPH-14269;Lo;0;L;;;;;N;;;;; +1426A;EGYPTIAN HIEROGLYPH-1426A;Lo;0;L;;;;;N;;;;; +1426B;EGYPTIAN HIEROGLYPH-1426B;Lo;0;L;;;;;N;;;;; +1426C;EGYPTIAN HIEROGLYPH-1426C;Lo;0;L;;;;;N;;;;; +1426D;EGYPTIAN HIEROGLYPH-1426D;Lo;0;L;;;;;N;;;;; +1426E;EGYPTIAN HIEROGLYPH-1426E;Lo;0;L;;;;;N;;;;; +1426F;EGYPTIAN HIEROGLYPH-1426F;Lo;0;L;;;;;N;;;;; +14270;EGYPTIAN HIEROGLYPH-14270;Lo;0;L;;;;;N;;;;; +14271;EGYPTIAN HIEROGLYPH-14271;Lo;0;L;;;;;N;;;;; +14272;EGYPTIAN HIEROGLYPH-14272;Lo;0;L;;;;;N;;;;; +14273;EGYPTIAN HIEROGLYPH-14273;Lo;0;L;;;;;N;;;;; +14274;EGYPTIAN HIEROGLYPH-14274;Lo;0;L;;;;;N;;;;; +14275;EGYPTIAN HIEROGLYPH-14275;Lo;0;L;;;;;N;;;;; +14276;EGYPTIAN HIEROGLYPH-14276;Lo;0;L;;;;;N;;;;; +14277;EGYPTIAN HIEROGLYPH-14277;Lo;0;L;;;;;N;;;;; +14278;EGYPTIAN HIEROGLYPH-14278;Lo;0;L;;;;;N;;;;; +14279;EGYPTIAN HIEROGLYPH-14279;Lo;0;L;;;;;N;;;;; +1427A;EGYPTIAN HIEROGLYPH-1427A;Lo;0;L;;;;;N;;;;; +1427B;EGYPTIAN HIEROGLYPH-1427B;Lo;0;L;;;;;N;;;;; +1427C;EGYPTIAN HIEROGLYPH-1427C;Lo;0;L;;;;;N;;;;; +1427D;EGYPTIAN HIEROGLYPH-1427D;Lo;0;L;;;;;N;;;;; +1427E;EGYPTIAN HIEROGLYPH-1427E;Lo;0;L;;;;;N;;;;; +1427F;EGYPTIAN HIEROGLYPH-1427F;Lo;0;L;;;;;N;;;;; +14280;EGYPTIAN HIEROGLYPH-14280;Lo;0;L;;;;;N;;;;; +14281;EGYPTIAN HIEROGLYPH-14281;Lo;0;L;;;;;N;;;;; +14282;EGYPTIAN HIEROGLYPH-14282;Lo;0;L;;;;;N;;;;; +14283;EGYPTIAN HIEROGLYPH-14283;Lo;0;L;;;;;N;;;;; +14284;EGYPTIAN HIEROGLYPH-14284;Lo;0;L;;;;;N;;;;; +14285;EGYPTIAN HIEROGLYPH-14285;Lo;0;L;;;;;N;;;;; +14286;EGYPTIAN HIEROGLYPH-14286;Lo;0;L;;;;;N;;;;; +14287;EGYPTIAN HIEROGLYPH-14287;Lo;0;L;;;;;N;;;;; +14288;EGYPTIAN HIEROGLYPH-14288;Lo;0;L;;;;;N;;;;; +14289;EGYPTIAN HIEROGLYPH-14289;Lo;0;L;;;;;N;;;;; +1428A;EGYPTIAN HIEROGLYPH-1428A;Lo;0;L;;;;;N;;;;; +1428B;EGYPTIAN HIEROGLYPH-1428B;Lo;0;L;;;;;N;;;;; +1428C;EGYPTIAN HIEROGLYPH-1428C;Lo;0;L;;;;;N;;;;; +1428D;EGYPTIAN HIEROGLYPH-1428D;Lo;0;L;;;;;N;;;;; +1428E;EGYPTIAN HIEROGLYPH-1428E;Lo;0;L;;;;;N;;;;; +1428F;EGYPTIAN HIEROGLYPH-1428F;Lo;0;L;;;;;N;;;;; +14290;EGYPTIAN HIEROGLYPH-14290;Lo;0;L;;;;;N;;;;; +14291;EGYPTIAN HIEROGLYPH-14291;Lo;0;L;;;;;N;;;;; +14292;EGYPTIAN HIEROGLYPH-14292;Lo;0;L;;;;;N;;;;; +14293;EGYPTIAN HIEROGLYPH-14293;Lo;0;L;;;;;N;;;;; +14294;EGYPTIAN HIEROGLYPH-14294;Lo;0;L;;;;;N;;;;; +14295;EGYPTIAN HIEROGLYPH-14295;Lo;0;L;;;;;N;;;;; +14296;EGYPTIAN HIEROGLYPH-14296;Lo;0;L;;;;;N;;;;; +14297;EGYPTIAN HIEROGLYPH-14297;Lo;0;L;;;;;N;;;;; +14298;EGYPTIAN HIEROGLYPH-14298;Lo;0;L;;;;;N;;;;; +14299;EGYPTIAN HIEROGLYPH-14299;Lo;0;L;;;;;N;;;;; +1429A;EGYPTIAN HIEROGLYPH-1429A;Lo;0;L;;;;;N;;;;; +1429B;EGYPTIAN HIEROGLYPH-1429B;Lo;0;L;;;;;N;;;;; +1429C;EGYPTIAN HIEROGLYPH-1429C;Lo;0;L;;;;;N;;;;; +1429D;EGYPTIAN HIEROGLYPH-1429D;Lo;0;L;;;;;N;;;;; +1429E;EGYPTIAN HIEROGLYPH-1429E;Lo;0;L;;;;;N;;;;; +1429F;EGYPTIAN HIEROGLYPH-1429F;Lo;0;L;;;;;N;;;;; +142A0;EGYPTIAN HIEROGLYPH-142A0;Lo;0;L;;;;;N;;;;; +142A1;EGYPTIAN HIEROGLYPH-142A1;Lo;0;L;;;;;N;;;;; +142A2;EGYPTIAN HIEROGLYPH-142A2;Lo;0;L;;;;;N;;;;; +142A3;EGYPTIAN HIEROGLYPH-142A3;Lo;0;L;;;;;N;;;;; +142A4;EGYPTIAN HIEROGLYPH-142A4;Lo;0;L;;;;;N;;;;; +142A5;EGYPTIAN HIEROGLYPH-142A5;Lo;0;L;;;;;N;;;;; +142A6;EGYPTIAN HIEROGLYPH-142A6;Lo;0;L;;;;;N;;;;; +142A7;EGYPTIAN HIEROGLYPH-142A7;Lo;0;L;;;;;N;;;;; +142A8;EGYPTIAN HIEROGLYPH-142A8;Lo;0;L;;;;;N;;;;; +142A9;EGYPTIAN HIEROGLYPH-142A9;Lo;0;L;;;;;N;;;;; +142AA;EGYPTIAN HIEROGLYPH-142AA;Lo;0;L;;;;;N;;;;; +142AB;EGYPTIAN HIEROGLYPH-142AB;Lo;0;L;;;;;N;;;;; +142AC;EGYPTIAN HIEROGLYPH-142AC;Lo;0;L;;;;;N;;;;; +142AD;EGYPTIAN HIEROGLYPH-142AD;Lo;0;L;;;;;N;;;;; +142AE;EGYPTIAN HIEROGLYPH-142AE;Lo;0;L;;;;;N;;;;; +142AF;EGYPTIAN HIEROGLYPH-142AF;Lo;0;L;;;;;N;;;;; +142B0;EGYPTIAN HIEROGLYPH-142B0;Lo;0;L;;;;;N;;;;; +142B1;EGYPTIAN HIEROGLYPH-142B1;Lo;0;L;;;;;N;;;;; +142B2;EGYPTIAN HIEROGLYPH-142B2;Lo;0;L;;;;;N;;;;; +142B3;EGYPTIAN HIEROGLYPH-142B3;Lo;0;L;;;;;N;;;;; +142B4;EGYPTIAN HIEROGLYPH-142B4;Lo;0;L;;;;;N;;;;; +142B5;EGYPTIAN HIEROGLYPH-142B5;Lo;0;L;;;;;N;;;;; +142B6;EGYPTIAN HIEROGLYPH-142B6;Lo;0;L;;;;;N;;;;; +142B7;EGYPTIAN HIEROGLYPH-142B7;Lo;0;L;;;;;N;;;;; +142B8;EGYPTIAN HIEROGLYPH-142B8;Lo;0;L;;;;;N;;;;; +142B9;EGYPTIAN HIEROGLYPH-142B9;Lo;0;L;;;;;N;;;;; +142BA;EGYPTIAN HIEROGLYPH-142BA;Lo;0;L;;;;;N;;;;; +142BB;EGYPTIAN HIEROGLYPH-142BB;Lo;0;L;;;;;N;;;;; +142BC;EGYPTIAN HIEROGLYPH-142BC;Lo;0;L;;;;;N;;;;; +142BD;EGYPTIAN HIEROGLYPH-142BD;Lo;0;L;;;;;N;;;;; +142BE;EGYPTIAN HIEROGLYPH-142BE;Lo;0;L;;;;;N;;;;; +142BF;EGYPTIAN HIEROGLYPH-142BF;Lo;0;L;;;;;N;;;;; +142C0;EGYPTIAN HIEROGLYPH-142C0;Lo;0;L;;;;;N;;;;; +142C1;EGYPTIAN HIEROGLYPH-142C1;Lo;0;L;;;;;N;;;;; +142C2;EGYPTIAN HIEROGLYPH-142C2;Lo;0;L;;;;;N;;;;; +142C3;EGYPTIAN HIEROGLYPH-142C3;Lo;0;L;;;;;N;;;;; +142C4;EGYPTIAN HIEROGLYPH-142C4;Lo;0;L;;;;;N;;;;; +142C5;EGYPTIAN HIEROGLYPH-142C5;Lo;0;L;;;;;N;;;;; +142C6;EGYPTIAN HIEROGLYPH-142C6;Lo;0;L;;;;;N;;;;; +142C7;EGYPTIAN HIEROGLYPH-142C7;Lo;0;L;;;;;N;;;;; +142C8;EGYPTIAN HIEROGLYPH-142C8;Lo;0;L;;;;;N;;;;; +142C9;EGYPTIAN HIEROGLYPH-142C9;Lo;0;L;;;;;N;;;;; +142CA;EGYPTIAN HIEROGLYPH-142CA;Lo;0;L;;;;;N;;;;; +142CB;EGYPTIAN HIEROGLYPH-142CB;Lo;0;L;;;;;N;;;;; +142CC;EGYPTIAN HIEROGLYPH-142CC;Lo;0;L;;;;;N;;;;; +142CD;EGYPTIAN HIEROGLYPH-142CD;Lo;0;L;;;;;N;;;;; +142CE;EGYPTIAN HIEROGLYPH-142CE;Lo;0;L;;;;;N;;;;; +142CF;EGYPTIAN HIEROGLYPH-142CF;Lo;0;L;;;;;N;;;;; +142D0;EGYPTIAN HIEROGLYPH-142D0;Lo;0;L;;;;;N;;;;; +142D1;EGYPTIAN HIEROGLYPH-142D1;Lo;0;L;;;;;N;;;;; +142D2;EGYPTIAN HIEROGLYPH-142D2;Lo;0;L;;;;;N;;;;; +142D3;EGYPTIAN HIEROGLYPH-142D3;Lo;0;L;;;;;N;;;;; +142D4;EGYPTIAN HIEROGLYPH-142D4;Lo;0;L;;;;;N;;;;; +142D5;EGYPTIAN HIEROGLYPH-142D5;Lo;0;L;;;;;N;;;;; +142D6;EGYPTIAN HIEROGLYPH-142D6;Lo;0;L;;;;;N;;;;; +142D7;EGYPTIAN HIEROGLYPH-142D7;Lo;0;L;;;;;N;;;;; +142D8;EGYPTIAN HIEROGLYPH-142D8;Lo;0;L;;;;;N;;;;; +142D9;EGYPTIAN HIEROGLYPH-142D9;Lo;0;L;;;;;N;;;;; +142DA;EGYPTIAN HIEROGLYPH-142DA;Lo;0;L;;;;;N;;;;; +142DB;EGYPTIAN HIEROGLYPH-142DB;Lo;0;L;;;;;N;;;;; +142DC;EGYPTIAN HIEROGLYPH-142DC;Lo;0;L;;;;;N;;;;; +142DD;EGYPTIAN HIEROGLYPH-142DD;Lo;0;L;;;;;N;;;;; +142DE;EGYPTIAN HIEROGLYPH-142DE;Lo;0;L;;;;;N;;;;; +142DF;EGYPTIAN HIEROGLYPH-142DF;Lo;0;L;;;;;N;;;;; +142E0;EGYPTIAN HIEROGLYPH-142E0;Lo;0;L;;;;;N;;;;; +142E1;EGYPTIAN HIEROGLYPH-142E1;Lo;0;L;;;;;N;;;;; +142E2;EGYPTIAN HIEROGLYPH-142E2;Lo;0;L;;;;;N;;;;; +142E3;EGYPTIAN HIEROGLYPH-142E3;Lo;0;L;;;;;N;;;;; +142E4;EGYPTIAN HIEROGLYPH-142E4;Lo;0;L;;;;;N;;;;; +142E5;EGYPTIAN HIEROGLYPH-142E5;Lo;0;L;;;;;N;;;;; +142E6;EGYPTIAN HIEROGLYPH-142E6;Lo;0;L;;;;;N;;;;; +142E7;EGYPTIAN HIEROGLYPH-142E7;Lo;0;L;;;;;N;;;;; +142E8;EGYPTIAN HIEROGLYPH-142E8;Lo;0;L;;;;;N;;;;; +142E9;EGYPTIAN HIEROGLYPH-142E9;Lo;0;L;;;;;N;;;;; +142EA;EGYPTIAN HIEROGLYPH-142EA;Lo;0;L;;;;;N;;;;; +142EB;EGYPTIAN HIEROGLYPH-142EB;Lo;0;L;;;;;N;;;;; +142EC;EGYPTIAN HIEROGLYPH-142EC;Lo;0;L;;;;;N;;;;; +142ED;EGYPTIAN HIEROGLYPH-142ED;Lo;0;L;;;;;N;;;;; +142EE;EGYPTIAN HIEROGLYPH-142EE;Lo;0;L;;;;;N;;;;; +142EF;EGYPTIAN HIEROGLYPH-142EF;Lo;0;L;;;;;N;;;;; +142F0;EGYPTIAN HIEROGLYPH-142F0;Lo;0;L;;;;;N;;;;; +142F1;EGYPTIAN HIEROGLYPH-142F1;Lo;0;L;;;;;N;;;;; +142F2;EGYPTIAN HIEROGLYPH-142F2;Lo;0;L;;;;;N;;;;; +142F3;EGYPTIAN HIEROGLYPH-142F3;Lo;0;L;;;;;N;;;;; +142F4;EGYPTIAN HIEROGLYPH-142F4;Lo;0;L;;;;;N;;;;; +142F5;EGYPTIAN HIEROGLYPH-142F5;Lo;0;L;;;;;N;;;;; +142F6;EGYPTIAN HIEROGLYPH-142F6;Lo;0;L;;;;;N;;;;; +142F7;EGYPTIAN HIEROGLYPH-142F7;Lo;0;L;;;;;N;;;;; +142F8;EGYPTIAN HIEROGLYPH-142F8;Lo;0;L;;;;;N;;;;; +142F9;EGYPTIAN HIEROGLYPH-142F9;Lo;0;L;;;;;N;;;;; +142FA;EGYPTIAN HIEROGLYPH-142FA;Lo;0;L;;;;;N;;;;; +142FB;EGYPTIAN HIEROGLYPH-142FB;Lo;0;L;;;;;N;;;;; +142FC;EGYPTIAN HIEROGLYPH-142FC;Lo;0;L;;;;;N;;;;; +142FD;EGYPTIAN HIEROGLYPH-142FD;Lo;0;L;;;;;N;;;;; +142FE;EGYPTIAN HIEROGLYPH-142FE;Lo;0;L;;;;;N;;;;; +142FF;EGYPTIAN HIEROGLYPH-142FF;Lo;0;L;;;;;N;;;;; +14300;EGYPTIAN HIEROGLYPH-14300;Lo;0;L;;;;;N;;;;; +14301;EGYPTIAN HIEROGLYPH-14301;Lo;0;L;;;;;N;;;;; +14302;EGYPTIAN HIEROGLYPH-14302;Lo;0;L;;;;;N;;;;; +14303;EGYPTIAN HIEROGLYPH-14303;Lo;0;L;;;;;N;;;;; +14304;EGYPTIAN HIEROGLYPH-14304;Lo;0;L;;;;;N;;;;; +14305;EGYPTIAN HIEROGLYPH-14305;Lo;0;L;;;;;N;;;;; +14306;EGYPTIAN HIEROGLYPH-14306;Lo;0;L;;;;;N;;;;; +14307;EGYPTIAN HIEROGLYPH-14307;Lo;0;L;;;;;N;;;;; +14308;EGYPTIAN HIEROGLYPH-14308;Lo;0;L;;;;;N;;;;; +14309;EGYPTIAN HIEROGLYPH-14309;Lo;0;L;;;;;N;;;;; +1430A;EGYPTIAN HIEROGLYPH-1430A;Lo;0;L;;;;;N;;;;; +1430B;EGYPTIAN HIEROGLYPH-1430B;Lo;0;L;;;;;N;;;;; +1430C;EGYPTIAN HIEROGLYPH-1430C;Lo;0;L;;;;;N;;;;; +1430D;EGYPTIAN HIEROGLYPH-1430D;Lo;0;L;;;;;N;;;;; +1430E;EGYPTIAN HIEROGLYPH-1430E;Lo;0;L;;;;;N;;;;; +1430F;EGYPTIAN HIEROGLYPH-1430F;Lo;0;L;;;;;N;;;;; +14310;EGYPTIAN HIEROGLYPH-14310;Lo;0;L;;;;;N;;;;; +14311;EGYPTIAN HIEROGLYPH-14311;Lo;0;L;;;;;N;;;;; +14312;EGYPTIAN HIEROGLYPH-14312;Lo;0;L;;;;;N;;;;; +14313;EGYPTIAN HIEROGLYPH-14313;Lo;0;L;;;;;N;;;;; +14314;EGYPTIAN HIEROGLYPH-14314;Lo;0;L;;;;;N;;;;; +14315;EGYPTIAN HIEROGLYPH-14315;Lo;0;L;;;;;N;;;;; +14316;EGYPTIAN HIEROGLYPH-14316;Lo;0;L;;;;;N;;;;; +14317;EGYPTIAN HIEROGLYPH-14317;Lo;0;L;;;;;N;;;;; +14318;EGYPTIAN HIEROGLYPH-14318;Lo;0;L;;;;;N;;;;; +14319;EGYPTIAN HIEROGLYPH-14319;Lo;0;L;;;;;N;;;;; +1431A;EGYPTIAN HIEROGLYPH-1431A;Lo;0;L;;;;;N;;;;; +1431B;EGYPTIAN HIEROGLYPH-1431B;Lo;0;L;;;;;N;;;;; +1431C;EGYPTIAN HIEROGLYPH-1431C;Lo;0;L;;;;;N;;;;; +1431D;EGYPTIAN HIEROGLYPH-1431D;Lo;0;L;;;;;N;;;;; +1431E;EGYPTIAN HIEROGLYPH-1431E;Lo;0;L;;;;;N;;;;; +1431F;EGYPTIAN HIEROGLYPH-1431F;Lo;0;L;;;;;N;;;;; +14320;EGYPTIAN HIEROGLYPH-14320;Lo;0;L;;;;;N;;;;; +14321;EGYPTIAN HIEROGLYPH-14321;Lo;0;L;;;;;N;;;;; +14322;EGYPTIAN HIEROGLYPH-14322;Lo;0;L;;;;;N;;;;; +14323;EGYPTIAN HIEROGLYPH-14323;Lo;0;L;;;;;N;;;;; +14324;EGYPTIAN HIEROGLYPH-14324;Lo;0;L;;;;;N;;;;; +14325;EGYPTIAN HIEROGLYPH-14325;Lo;0;L;;;;;N;;;;; +14326;EGYPTIAN HIEROGLYPH-14326;Lo;0;L;;;;;N;;;;; +14327;EGYPTIAN HIEROGLYPH-14327;Lo;0;L;;;;;N;;;;; +14328;EGYPTIAN HIEROGLYPH-14328;Lo;0;L;;;;;N;;;;; +14329;EGYPTIAN HIEROGLYPH-14329;Lo;0;L;;;;;N;;;;; +1432A;EGYPTIAN HIEROGLYPH-1432A;Lo;0;L;;;;;N;;;;; +1432B;EGYPTIAN HIEROGLYPH-1432B;Lo;0;L;;;;;N;;;;; +1432C;EGYPTIAN HIEROGLYPH-1432C;Lo;0;L;;;;;N;;;;; +1432D;EGYPTIAN HIEROGLYPH-1432D;Lo;0;L;;;;;N;;;;; +1432E;EGYPTIAN HIEROGLYPH-1432E;Lo;0;L;;;;;N;;;;; +1432F;EGYPTIAN HIEROGLYPH-1432F;Lo;0;L;;;;;N;;;;; +14330;EGYPTIAN HIEROGLYPH-14330;Lo;0;L;;;;;N;;;;; +14331;EGYPTIAN HIEROGLYPH-14331;Lo;0;L;;;;;N;;;;; +14332;EGYPTIAN HIEROGLYPH-14332;Lo;0;L;;;;;N;;;;; +14333;EGYPTIAN HIEROGLYPH-14333;Lo;0;L;;;;;N;;;;; +14334;EGYPTIAN HIEROGLYPH-14334;Lo;0;L;;;;;N;;;;; +14335;EGYPTIAN HIEROGLYPH-14335;Lo;0;L;;;;;N;;;;; +14336;EGYPTIAN HIEROGLYPH-14336;Lo;0;L;;;;;N;;;;; +14337;EGYPTIAN HIEROGLYPH-14337;Lo;0;L;;;;;N;;;;; +14338;EGYPTIAN HIEROGLYPH-14338;Lo;0;L;;;;;N;;;;; +14339;EGYPTIAN HIEROGLYPH-14339;Lo;0;L;;;;;N;;;;; +1433A;EGYPTIAN HIEROGLYPH-1433A;Lo;0;L;;;;;N;;;;; +1433B;EGYPTIAN HIEROGLYPH-1433B;Lo;0;L;;;;;N;;;;; +1433C;EGYPTIAN HIEROGLYPH-1433C;Lo;0;L;;;;;N;;;;; +1433D;EGYPTIAN HIEROGLYPH-1433D;Lo;0;L;;;;;N;;;;; +1433E;EGYPTIAN HIEROGLYPH-1433E;Lo;0;L;;;;;N;;;;; +1433F;EGYPTIAN HIEROGLYPH-1433F;Lo;0;L;;;;;N;;;;; +14340;EGYPTIAN HIEROGLYPH-14340;Lo;0;L;;;;;N;;;;; +14341;EGYPTIAN HIEROGLYPH-14341;Lo;0;L;;;;;N;;;;; +14342;EGYPTIAN HIEROGLYPH-14342;Lo;0;L;;;;;N;;;;; +14343;EGYPTIAN HIEROGLYPH-14343;Lo;0;L;;;;;N;;;;; +14344;EGYPTIAN HIEROGLYPH-14344;Lo;0;L;;;;;N;;;;; +14345;EGYPTIAN HIEROGLYPH-14345;Lo;0;L;;;;;N;;;;; +14346;EGYPTIAN HIEROGLYPH-14346;Lo;0;L;;;;;N;;;;; +14347;EGYPTIAN HIEROGLYPH-14347;Lo;0;L;;;;;N;;;;; +14348;EGYPTIAN HIEROGLYPH-14348;Lo;0;L;;;;;N;;;;; +14349;EGYPTIAN HIEROGLYPH-14349;Lo;0;L;;;;;N;;;;; +1434A;EGYPTIAN HIEROGLYPH-1434A;Lo;0;L;;;;;N;;;;; +1434B;EGYPTIAN HIEROGLYPH-1434B;Lo;0;L;;;;;N;;;;; +1434C;EGYPTIAN HIEROGLYPH-1434C;Lo;0;L;;;;;N;;;;; +1434D;EGYPTIAN HIEROGLYPH-1434D;Lo;0;L;;;;;N;;;;; +1434E;EGYPTIAN HIEROGLYPH-1434E;Lo;0;L;;;;;N;;;;; +1434F;EGYPTIAN HIEROGLYPH-1434F;Lo;0;L;;;;;N;;;;; +14350;EGYPTIAN HIEROGLYPH-14350;Lo;0;L;;;;;N;;;;; +14351;EGYPTIAN HIEROGLYPH-14351;Lo;0;L;;;;;N;;;;; +14352;EGYPTIAN HIEROGLYPH-14352;Lo;0;L;;;;;N;;;;; +14353;EGYPTIAN HIEROGLYPH-14353;Lo;0;L;;;;;N;;;;; +14354;EGYPTIAN HIEROGLYPH-14354;Lo;0;L;;;;;N;;;;; +14355;EGYPTIAN HIEROGLYPH-14355;Lo;0;L;;;;;N;;;;; +14356;EGYPTIAN HIEROGLYPH-14356;Lo;0;L;;;;;N;;;;; +14357;EGYPTIAN HIEROGLYPH-14357;Lo;0;L;;;;;N;;;;; +14358;EGYPTIAN HIEROGLYPH-14358;Lo;0;L;;;;;N;;;;; +14359;EGYPTIAN HIEROGLYPH-14359;Lo;0;L;;;;;N;;;;; +1435A;EGYPTIAN HIEROGLYPH-1435A;Lo;0;L;;;;;N;;;;; +1435B;EGYPTIAN HIEROGLYPH-1435B;Lo;0;L;;;;;N;;;;; +1435C;EGYPTIAN HIEROGLYPH-1435C;Lo;0;L;;;;;N;;;;; +1435D;EGYPTIAN HIEROGLYPH-1435D;Lo;0;L;;;;;N;;;;; +1435E;EGYPTIAN HIEROGLYPH-1435E;Lo;0;L;;;;;N;;;;; +1435F;EGYPTIAN HIEROGLYPH-1435F;Lo;0;L;;;;;N;;;;; +14360;EGYPTIAN HIEROGLYPH-14360;Lo;0;L;;;;;N;;;;; +14361;EGYPTIAN HIEROGLYPH-14361;Lo;0;L;;;;;N;;;;; +14362;EGYPTIAN HIEROGLYPH-14362;Lo;0;L;;;;;N;;;;; +14363;EGYPTIAN HIEROGLYPH-14363;Lo;0;L;;;;;N;;;;; +14364;EGYPTIAN HIEROGLYPH-14364;Lo;0;L;;;;;N;;;;; +14365;EGYPTIAN HIEROGLYPH-14365;Lo;0;L;;;;;N;;;;; +14366;EGYPTIAN HIEROGLYPH-14366;Lo;0;L;;;;;N;;;;; +14367;EGYPTIAN HIEROGLYPH-14367;Lo;0;L;;;;;N;;;;; +14368;EGYPTIAN HIEROGLYPH-14368;Lo;0;L;;;;;N;;;;; +14369;EGYPTIAN HIEROGLYPH-14369;Lo;0;L;;;;;N;;;;; +1436A;EGYPTIAN HIEROGLYPH-1436A;Lo;0;L;;;;;N;;;;; +1436B;EGYPTIAN HIEROGLYPH-1436B;Lo;0;L;;;;;N;;;;; +1436C;EGYPTIAN HIEROGLYPH-1436C;Lo;0;L;;;;;N;;;;; +1436D;EGYPTIAN HIEROGLYPH-1436D;Lo;0;L;;;;;N;;;;; +1436E;EGYPTIAN HIEROGLYPH-1436E;Lo;0;L;;;;;N;;;;; +1436F;EGYPTIAN HIEROGLYPH-1436F;Lo;0;L;;;;;N;;;;; +14370;EGYPTIAN HIEROGLYPH-14370;Lo;0;L;;;;;N;;;;; +14371;EGYPTIAN HIEROGLYPH-14371;Lo;0;L;;;;;N;;;;; +14372;EGYPTIAN HIEROGLYPH-14372;Lo;0;L;;;;;N;;;;; +14373;EGYPTIAN HIEROGLYPH-14373;Lo;0;L;;;;;N;;;;; +14374;EGYPTIAN HIEROGLYPH-14374;Lo;0;L;;;;;N;;;;; +14375;EGYPTIAN HIEROGLYPH-14375;Lo;0;L;;;;;N;;;;; +14376;EGYPTIAN HIEROGLYPH-14376;Lo;0;L;;;;;N;;;;; +14377;EGYPTIAN HIEROGLYPH-14377;Lo;0;L;;;;;N;;;;; +14378;EGYPTIAN HIEROGLYPH-14378;Lo;0;L;;;;;N;;;;; +14379;EGYPTIAN HIEROGLYPH-14379;Lo;0;L;;;;;N;;;;; +1437A;EGYPTIAN HIEROGLYPH-1437A;Lo;0;L;;;;;N;;;;; +1437B;EGYPTIAN HIEROGLYPH-1437B;Lo;0;L;;;;;N;;;;; +1437C;EGYPTIAN HIEROGLYPH-1437C;Lo;0;L;;;;;N;;;;; +1437D;EGYPTIAN HIEROGLYPH-1437D;Lo;0;L;;;;;N;;;;; +1437E;EGYPTIAN HIEROGLYPH-1437E;Lo;0;L;;;;;N;;;;; +1437F;EGYPTIAN HIEROGLYPH-1437F;Lo;0;L;;;;;N;;;;; +14380;EGYPTIAN HIEROGLYPH-14380;Lo;0;L;;;;;N;;;;; +14381;EGYPTIAN HIEROGLYPH-14381;Lo;0;L;;;;;N;;;;; +14382;EGYPTIAN HIEROGLYPH-14382;Lo;0;L;;;;;N;;;;; +14383;EGYPTIAN HIEROGLYPH-14383;Lo;0;L;;;;;N;;;;; +14384;EGYPTIAN HIEROGLYPH-14384;Lo;0;L;;;;;N;;;;; +14385;EGYPTIAN HIEROGLYPH-14385;Lo;0;L;;;;;N;;;;; +14386;EGYPTIAN HIEROGLYPH-14386;Lo;0;L;;;;;N;;;;; +14387;EGYPTIAN HIEROGLYPH-14387;Lo;0;L;;;;;N;;;;; +14388;EGYPTIAN HIEROGLYPH-14388;Lo;0;L;;;;;N;;;;; +14389;EGYPTIAN HIEROGLYPH-14389;Lo;0;L;;;;;N;;;;; +1438A;EGYPTIAN HIEROGLYPH-1438A;Lo;0;L;;;;;N;;;;; +1438B;EGYPTIAN HIEROGLYPH-1438B;Lo;0;L;;;;;N;;;;; +1438C;EGYPTIAN HIEROGLYPH-1438C;Lo;0;L;;;;;N;;;;; +1438D;EGYPTIAN HIEROGLYPH-1438D;Lo;0;L;;;;;N;;;;; +1438E;EGYPTIAN HIEROGLYPH-1438E;Lo;0;L;;;;;N;;;;; +1438F;EGYPTIAN HIEROGLYPH-1438F;Lo;0;L;;;;;N;;;;; +14390;EGYPTIAN HIEROGLYPH-14390;Lo;0;L;;;;;N;;;;; +14391;EGYPTIAN HIEROGLYPH-14391;Lo;0;L;;;;;N;;;;; +14392;EGYPTIAN HIEROGLYPH-14392;Lo;0;L;;;;;N;;;;; +14393;EGYPTIAN HIEROGLYPH-14393;Lo;0;L;;;;;N;;;;; +14394;EGYPTIAN HIEROGLYPH-14394;Lo;0;L;;;;;N;;;;; +14395;EGYPTIAN HIEROGLYPH-14395;Lo;0;L;;;;;N;;;;; +14396;EGYPTIAN HIEROGLYPH-14396;Lo;0;L;;;;;N;;;;; +14397;EGYPTIAN HIEROGLYPH-14397;Lo;0;L;;;;;N;;;;; +14398;EGYPTIAN HIEROGLYPH-14398;Lo;0;L;;;;;N;;;;; +14399;EGYPTIAN HIEROGLYPH-14399;Lo;0;L;;;;;N;;;;; +1439A;EGYPTIAN HIEROGLYPH-1439A;Lo;0;L;;;;;N;;;;; +1439B;EGYPTIAN HIEROGLYPH-1439B;Lo;0;L;;;;;N;;;;; +1439C;EGYPTIAN HIEROGLYPH-1439C;Lo;0;L;;;;;N;;;;; +1439D;EGYPTIAN HIEROGLYPH-1439D;Lo;0;L;;;;;N;;;;; +1439E;EGYPTIAN HIEROGLYPH-1439E;Lo;0;L;;;;;N;;;;; +1439F;EGYPTIAN HIEROGLYPH-1439F;Lo;0;L;;;;;N;;;;; +143A0;EGYPTIAN HIEROGLYPH-143A0;Lo;0;L;;;;;N;;;;; +143A1;EGYPTIAN HIEROGLYPH-143A1;Lo;0;L;;;;;N;;;;; +143A2;EGYPTIAN HIEROGLYPH-143A2;Lo;0;L;;;;;N;;;;; +143A3;EGYPTIAN HIEROGLYPH-143A3;Lo;0;L;;;;;N;;;;; +143A4;EGYPTIAN HIEROGLYPH-143A4;Lo;0;L;;;;;N;;;;; +143A5;EGYPTIAN HIEROGLYPH-143A5;Lo;0;L;;;;;N;;;;; +143A6;EGYPTIAN HIEROGLYPH-143A6;Lo;0;L;;;;;N;;;;; +143A7;EGYPTIAN HIEROGLYPH-143A7;Lo;0;L;;;;;N;;;;; +143A8;EGYPTIAN HIEROGLYPH-143A8;Lo;0;L;;;;;N;;;;; +143A9;EGYPTIAN HIEROGLYPH-143A9;Lo;0;L;;;;;N;;;;; +143AA;EGYPTIAN HIEROGLYPH-143AA;Lo;0;L;;;;;N;;;;; +143AB;EGYPTIAN HIEROGLYPH-143AB;Lo;0;L;;;;;N;;;;; +143AC;EGYPTIAN HIEROGLYPH-143AC;Lo;0;L;;;;;N;;;;; +143AD;EGYPTIAN HIEROGLYPH-143AD;Lo;0;L;;;;;N;;;;; +143AE;EGYPTIAN HIEROGLYPH-143AE;Lo;0;L;;;;;N;;;;; +143AF;EGYPTIAN HIEROGLYPH-143AF;Lo;0;L;;;;;N;;;;; +143B0;EGYPTIAN HIEROGLYPH-143B0;Lo;0;L;;;;;N;;;;; +143B1;EGYPTIAN HIEROGLYPH-143B1;Lo;0;L;;;;;N;;;;; +143B2;EGYPTIAN HIEROGLYPH-143B2;Lo;0;L;;;;;N;;;;; +143B3;EGYPTIAN HIEROGLYPH-143B3;Lo;0;L;;;;;N;;;;; +143B4;EGYPTIAN HIEROGLYPH-143B4;Lo;0;L;;;;;N;;;;; +143B5;EGYPTIAN HIEROGLYPH-143B5;Lo;0;L;;;;;N;;;;; +143B6;EGYPTIAN HIEROGLYPH-143B6;Lo;0;L;;;;;N;;;;; +143B7;EGYPTIAN HIEROGLYPH-143B7;Lo;0;L;;;;;N;;;;; +143B8;EGYPTIAN HIEROGLYPH-143B8;Lo;0;L;;;;;N;;;;; +143B9;EGYPTIAN HIEROGLYPH-143B9;Lo;0;L;;;;;N;;;;; +143BA;EGYPTIAN HIEROGLYPH-143BA;Lo;0;L;;;;;N;;;;; +143BB;EGYPTIAN HIEROGLYPH-143BB;Lo;0;L;;;;;N;;;;; +143BC;EGYPTIAN HIEROGLYPH-143BC;Lo;0;L;;;;;N;;;;; +143BD;EGYPTIAN HIEROGLYPH-143BD;Lo;0;L;;;;;N;;;;; +143BE;EGYPTIAN HIEROGLYPH-143BE;Lo;0;L;;;;;N;;;;; +143BF;EGYPTIAN HIEROGLYPH-143BF;Lo;0;L;;;;;N;;;;; +143C0;EGYPTIAN HIEROGLYPH-143C0;Lo;0;L;;;;;N;;;;; +143C1;EGYPTIAN HIEROGLYPH-143C1;Lo;0;L;;;;;N;;;;; +143C2;EGYPTIAN HIEROGLYPH-143C2;Lo;0;L;;;;;N;;;;; +143C3;EGYPTIAN HIEROGLYPH-143C3;Lo;0;L;;;;;N;;;;; +143C4;EGYPTIAN HIEROGLYPH-143C4;Lo;0;L;;;;;N;;;;; +143C5;EGYPTIAN HIEROGLYPH-143C5;Lo;0;L;;;;;N;;;;; +143C6;EGYPTIAN HIEROGLYPH-143C6;Lo;0;L;;;;;N;;;;; +143C7;EGYPTIAN HIEROGLYPH-143C7;Lo;0;L;;;;;N;;;;; +143C8;EGYPTIAN HIEROGLYPH-143C8;Lo;0;L;;;;;N;;;;; +143C9;EGYPTIAN HIEROGLYPH-143C9;Lo;0;L;;;;;N;;;;; +143CA;EGYPTIAN HIEROGLYPH-143CA;Lo;0;L;;;;;N;;;;; +143CB;EGYPTIAN HIEROGLYPH-143CB;Lo;0;L;;;;;N;;;;; +143CC;EGYPTIAN HIEROGLYPH-143CC;Lo;0;L;;;;;N;;;;; +143CD;EGYPTIAN HIEROGLYPH-143CD;Lo;0;L;;;;;N;;;;; +143CE;EGYPTIAN HIEROGLYPH-143CE;Lo;0;L;;;;;N;;;;; +143CF;EGYPTIAN HIEROGLYPH-143CF;Lo;0;L;;;;;N;;;;; +143D0;EGYPTIAN HIEROGLYPH-143D0;Lo;0;L;;;;;N;;;;; +143D1;EGYPTIAN HIEROGLYPH-143D1;Lo;0;L;;;;;N;;;;; +143D2;EGYPTIAN HIEROGLYPH-143D2;Lo;0;L;;;;;N;;;;; +143D3;EGYPTIAN HIEROGLYPH-143D3;Lo;0;L;;;;;N;;;;; +143D4;EGYPTIAN HIEROGLYPH-143D4;Lo;0;L;;;;;N;;;;; +143D5;EGYPTIAN HIEROGLYPH-143D5;Lo;0;L;;;;;N;;;;; +143D6;EGYPTIAN HIEROGLYPH-143D6;Lo;0;L;;;;;N;;;;; +143D7;EGYPTIAN HIEROGLYPH-143D7;Lo;0;L;;;;;N;;;;; +143D8;EGYPTIAN HIEROGLYPH-143D8;Lo;0;L;;;;;N;;;;; +143D9;EGYPTIAN HIEROGLYPH-143D9;Lo;0;L;;;;;N;;;;; +143DA;EGYPTIAN HIEROGLYPH-143DA;Lo;0;L;;;;;N;;;;; +143DB;EGYPTIAN HIEROGLYPH-143DB;Lo;0;L;;;;;N;;;;; +143DC;EGYPTIAN HIEROGLYPH-143DC;Lo;0;L;;;;;N;;;;; +143DD;EGYPTIAN HIEROGLYPH-143DD;Lo;0;L;;;;;N;;;;; +143DE;EGYPTIAN HIEROGLYPH-143DE;Lo;0;L;;;;;N;;;;; +143DF;EGYPTIAN HIEROGLYPH-143DF;Lo;0;L;;;;;N;;;;; +143E0;EGYPTIAN HIEROGLYPH-143E0;Lo;0;L;;;;;N;;;;; +143E1;EGYPTIAN HIEROGLYPH-143E1;Lo;0;L;;;;;N;;;;; +143E2;EGYPTIAN HIEROGLYPH-143E2;Lo;0;L;;;;;N;;;;; +143E3;EGYPTIAN HIEROGLYPH-143E3;Lo;0;L;;;;;N;;;;; +143E4;EGYPTIAN HIEROGLYPH-143E4;Lo;0;L;;;;;N;;;;; +143E5;EGYPTIAN HIEROGLYPH-143E5;Lo;0;L;;;;;N;;;;; +143E6;EGYPTIAN HIEROGLYPH-143E6;Lo;0;L;;;;;N;;;;; +143E7;EGYPTIAN HIEROGLYPH-143E7;Lo;0;L;;;;;N;;;;; +143E8;EGYPTIAN HIEROGLYPH-143E8;Lo;0;L;;;;;N;;;;; +143E9;EGYPTIAN HIEROGLYPH-143E9;Lo;0;L;;;;;N;;;;; +143EA;EGYPTIAN HIEROGLYPH-143EA;Lo;0;L;;;;;N;;;;; +143EB;EGYPTIAN HIEROGLYPH-143EB;Lo;0;L;;;;;N;;;;; +143EC;EGYPTIAN HIEROGLYPH-143EC;Lo;0;L;;;;;N;;;;; +143ED;EGYPTIAN HIEROGLYPH-143ED;Lo;0;L;;;;;N;;;;; +143EE;EGYPTIAN HIEROGLYPH-143EE;Lo;0;L;;;;;N;;;;; +143EF;EGYPTIAN HIEROGLYPH-143EF;Lo;0;L;;;;;N;;;;; +143F0;EGYPTIAN HIEROGLYPH-143F0;Lo;0;L;;;;;N;;;;; +143F1;EGYPTIAN HIEROGLYPH-143F1;Lo;0;L;;;;;N;;;;; +143F2;EGYPTIAN HIEROGLYPH-143F2;Lo;0;L;;;;;N;;;;; +143F3;EGYPTIAN HIEROGLYPH-143F3;Lo;0;L;;;;;N;;;;; +143F4;EGYPTIAN HIEROGLYPH-143F4;Lo;0;L;;;;;N;;;;; +143F5;EGYPTIAN HIEROGLYPH-143F5;Lo;0;L;;;;;N;;;;; +143F6;EGYPTIAN HIEROGLYPH-143F6;Lo;0;L;;;;;N;;;;; +143F7;EGYPTIAN HIEROGLYPH-143F7;Lo;0;L;;;;;N;;;;; +143F8;EGYPTIAN HIEROGLYPH-143F8;Lo;0;L;;;;;N;;;;; +143F9;EGYPTIAN HIEROGLYPH-143F9;Lo;0;L;;;;;N;;;;; +143FA;EGYPTIAN HIEROGLYPH-143FA;Lo;0;L;;;;;N;;;;; +14400;ANATOLIAN HIEROGLYPH A001;Lo;0;L;;;;;N;;;;; +14401;ANATOLIAN HIEROGLYPH A002;Lo;0;L;;;;;N;;;;; +14402;ANATOLIAN HIEROGLYPH A003;Lo;0;L;;;;;N;;;;; +14403;ANATOLIAN HIEROGLYPH A004;Lo;0;L;;;;;N;;;;; +14404;ANATOLIAN HIEROGLYPH A005;Lo;0;L;;;;;N;;;;; +14405;ANATOLIAN HIEROGLYPH A006;Lo;0;L;;;;;N;;;;; +14406;ANATOLIAN HIEROGLYPH A007;Lo;0;L;;;;;N;;;;; +14407;ANATOLIAN HIEROGLYPH A008;Lo;0;L;;;;;N;;;;; +14408;ANATOLIAN HIEROGLYPH A009;Lo;0;L;;;;;N;;;;; +14409;ANATOLIAN HIEROGLYPH A010;Lo;0;L;;;;;N;;;;; +1440A;ANATOLIAN HIEROGLYPH A010A;Lo;0;L;;;;;N;;;;; +1440B;ANATOLIAN HIEROGLYPH A011;Lo;0;L;;;;;N;;;;; +1440C;ANATOLIAN HIEROGLYPH A012;Lo;0;L;;;;;N;;;;; +1440D;ANATOLIAN HIEROGLYPH A013;Lo;0;L;;;;;N;;;;; +1440E;ANATOLIAN HIEROGLYPH A014;Lo;0;L;;;;;N;;;;; +1440F;ANATOLIAN HIEROGLYPH A015;Lo;0;L;;;;;N;;;;; +14410;ANATOLIAN HIEROGLYPH A016;Lo;0;L;;;;;N;;;;; +14411;ANATOLIAN HIEROGLYPH A017;Lo;0;L;;;;;N;;;;; +14412;ANATOLIAN HIEROGLYPH A018;Lo;0;L;;;;;N;;;;; +14413;ANATOLIAN HIEROGLYPH A019;Lo;0;L;;;;;N;;;;; +14414;ANATOLIAN HIEROGLYPH A020;Lo;0;L;;;;;N;;;;; +14415;ANATOLIAN HIEROGLYPH A021;Lo;0;L;;;;;N;;;;; +14416;ANATOLIAN HIEROGLYPH A022;Lo;0;L;;;;;N;;;;; +14417;ANATOLIAN HIEROGLYPH A023;Lo;0;L;;;;;N;;;;; +14418;ANATOLIAN HIEROGLYPH A024;Lo;0;L;;;;;N;;;;; +14419;ANATOLIAN HIEROGLYPH A025;Lo;0;L;;;;;N;;;;; +1441A;ANATOLIAN HIEROGLYPH A026;Lo;0;L;;;;;N;;;;; +1441B;ANATOLIAN HIEROGLYPH A026A;Lo;0;L;;;;;N;;;;; +1441C;ANATOLIAN HIEROGLYPH A027;Lo;0;L;;;;;N;;;;; +1441D;ANATOLIAN HIEROGLYPH A028;Lo;0;L;;;;;N;;;;; +1441E;ANATOLIAN HIEROGLYPH A029;Lo;0;L;;;;;N;;;;; +1441F;ANATOLIAN HIEROGLYPH A030;Lo;0;L;;;;;N;;;;; +14420;ANATOLIAN HIEROGLYPH A031;Lo;0;L;;;;;N;;;;; +14421;ANATOLIAN HIEROGLYPH A032;Lo;0;L;;;;;N;;;;; +14422;ANATOLIAN HIEROGLYPH A033;Lo;0;L;;;;;N;;;;; +14423;ANATOLIAN HIEROGLYPH A034;Lo;0;L;;;;;N;;;;; +14424;ANATOLIAN HIEROGLYPH A035;Lo;0;L;;;;;N;;;;; +14425;ANATOLIAN HIEROGLYPH A036;Lo;0;L;;;;;N;;;;; +14426;ANATOLIAN HIEROGLYPH A037;Lo;0;L;;;;;N;;;;; +14427;ANATOLIAN HIEROGLYPH A038;Lo;0;L;;;;;N;;;;; +14428;ANATOLIAN HIEROGLYPH A039;Lo;0;L;;;;;N;;;;; +14429;ANATOLIAN HIEROGLYPH A039A;Lo;0;L;;;;;N;;;;; +1442A;ANATOLIAN HIEROGLYPH A040;Lo;0;L;;;;;N;;;;; +1442B;ANATOLIAN HIEROGLYPH A041;Lo;0;L;;;;;N;;;;; +1442C;ANATOLIAN HIEROGLYPH A041A;Lo;0;L;;;;;N;;;;; +1442D;ANATOLIAN HIEROGLYPH A042;Lo;0;L;;;;;N;;;;; +1442E;ANATOLIAN HIEROGLYPH A043;Lo;0;L;;;;;N;;;;; +1442F;ANATOLIAN HIEROGLYPH A044;Lo;0;L;;;;;N;;;;; +14430;ANATOLIAN HIEROGLYPH A045;Lo;0;L;;;;;N;;;;; +14431;ANATOLIAN HIEROGLYPH A045A;Lo;0;L;;;;;N;;;;; +14432;ANATOLIAN HIEROGLYPH A046;Lo;0;L;;;;;N;;;;; +14433;ANATOLIAN HIEROGLYPH A046A;Lo;0;L;;;;;N;;;;; +14434;ANATOLIAN HIEROGLYPH A046B;Lo;0;L;;;;;N;;;;; +14435;ANATOLIAN HIEROGLYPH A047;Lo;0;L;;;;;N;;;;; +14436;ANATOLIAN HIEROGLYPH A048;Lo;0;L;;;;;N;;;;; +14437;ANATOLIAN HIEROGLYPH A049;Lo;0;L;;;;;N;;;;; +14438;ANATOLIAN HIEROGLYPH A050;Lo;0;L;;;;;N;;;;; +14439;ANATOLIAN HIEROGLYPH A051;Lo;0;L;;;;;N;;;;; +1443A;ANATOLIAN HIEROGLYPH A052;Lo;0;L;;;;;N;;;;; +1443B;ANATOLIAN HIEROGLYPH A053;Lo;0;L;;;;;N;;;;; +1443C;ANATOLIAN HIEROGLYPH A054;Lo;0;L;;;;;N;;;;; +1443D;ANATOLIAN HIEROGLYPH A055;Lo;0;L;;;;;N;;;;; +1443E;ANATOLIAN HIEROGLYPH A056;Lo;0;L;;;;;N;;;;; +1443F;ANATOLIAN HIEROGLYPH A057;Lo;0;L;;;;;N;;;;; +14440;ANATOLIAN HIEROGLYPH A058;Lo;0;L;;;;;N;;;;; +14441;ANATOLIAN HIEROGLYPH A059;Lo;0;L;;;;;N;;;;; +14442;ANATOLIAN HIEROGLYPH A060;Lo;0;L;;;;;N;;;;; +14443;ANATOLIAN HIEROGLYPH A061;Lo;0;L;;;;;N;;;;; +14444;ANATOLIAN HIEROGLYPH A062;Lo;0;L;;;;;N;;;;; +14445;ANATOLIAN HIEROGLYPH A063;Lo;0;L;;;;;N;;;;; +14446;ANATOLIAN HIEROGLYPH A064;Lo;0;L;;;;;N;;;;; +14447;ANATOLIAN HIEROGLYPH A065;Lo;0;L;;;;;N;;;;; +14448;ANATOLIAN HIEROGLYPH A066;Lo;0;L;;;;;N;;;;; +14449;ANATOLIAN HIEROGLYPH A066A;Lo;0;L;;;;;N;;;;; +1444A;ANATOLIAN HIEROGLYPH A066B;Lo;0;L;;;;;N;;;;; +1444B;ANATOLIAN HIEROGLYPH A066C;Lo;0;L;;;;;N;;;;; +1444C;ANATOLIAN HIEROGLYPH A067;Lo;0;L;;;;;N;;;;; +1444D;ANATOLIAN HIEROGLYPH A068;Lo;0;L;;;;;N;;;;; +1444E;ANATOLIAN HIEROGLYPH A069;Lo;0;L;;;;;N;;;;; +1444F;ANATOLIAN HIEROGLYPH A070;Lo;0;L;;;;;N;;;;; +14450;ANATOLIAN HIEROGLYPH A071;Lo;0;L;;;;;N;;;;; +14451;ANATOLIAN HIEROGLYPH A072;Lo;0;L;;;;;N;;;;; +14452;ANATOLIAN HIEROGLYPH A073;Lo;0;L;;;;;N;;;;; +14453;ANATOLIAN HIEROGLYPH A074;Lo;0;L;;;;;N;;;;; +14454;ANATOLIAN HIEROGLYPH A075;Lo;0;L;;;;;N;;;;; +14455;ANATOLIAN HIEROGLYPH A076;Lo;0;L;;;;;N;;;;; +14456;ANATOLIAN HIEROGLYPH A077;Lo;0;L;;;;;N;;;;; +14457;ANATOLIAN HIEROGLYPH A078;Lo;0;L;;;;;N;;;;; +14458;ANATOLIAN HIEROGLYPH A079;Lo;0;L;;;;;N;;;;; +14459;ANATOLIAN HIEROGLYPH A080;Lo;0;L;;;;;N;;;;; +1445A;ANATOLIAN HIEROGLYPH A081;Lo;0;L;;;;;N;;;;; +1445B;ANATOLIAN HIEROGLYPH A082;Lo;0;L;;;;;N;;;;; +1445C;ANATOLIAN HIEROGLYPH A083;Lo;0;L;;;;;N;;;;; +1445D;ANATOLIAN HIEROGLYPH A084;Lo;0;L;;;;;N;;;;; +1445E;ANATOLIAN HIEROGLYPH A085;Lo;0;L;;;;;N;;;;; +1445F;ANATOLIAN HIEROGLYPH A086;Lo;0;L;;;;;N;;;;; +14460;ANATOLIAN HIEROGLYPH A087;Lo;0;L;;;;;N;;;;; +14461;ANATOLIAN HIEROGLYPH A088;Lo;0;L;;;;;N;;;;; +14462;ANATOLIAN HIEROGLYPH A089;Lo;0;L;;;;;N;;;;; +14463;ANATOLIAN HIEROGLYPH A090;Lo;0;L;;;;;N;;;;; +14464;ANATOLIAN HIEROGLYPH A091;Lo;0;L;;;;;N;;;;; +14465;ANATOLIAN HIEROGLYPH A092;Lo;0;L;;;;;N;;;;; +14466;ANATOLIAN HIEROGLYPH A093;Lo;0;L;;;;;N;;;;; +14467;ANATOLIAN HIEROGLYPH A094;Lo;0;L;;;;;N;;;;; +14468;ANATOLIAN HIEROGLYPH A095;Lo;0;L;;;;;N;;;;; +14469;ANATOLIAN HIEROGLYPH A096;Lo;0;L;;;;;N;;;;; +1446A;ANATOLIAN HIEROGLYPH A097;Lo;0;L;;;;;N;;;;; +1446B;ANATOLIAN HIEROGLYPH A097A;Lo;0;L;;;;;N;;;;; +1446C;ANATOLIAN HIEROGLYPH A098;Lo;0;L;;;;;N;;;;; +1446D;ANATOLIAN HIEROGLYPH A098A;Lo;0;L;;;;;N;;;;; +1446E;ANATOLIAN HIEROGLYPH A099;Lo;0;L;;;;;N;;;;; +1446F;ANATOLIAN HIEROGLYPH A100;Lo;0;L;;;;;N;;;;; +14470;ANATOLIAN HIEROGLYPH A100A;Lo;0;L;;;;;N;;;;; +14471;ANATOLIAN HIEROGLYPH A101;Lo;0;L;;;;;N;;;;; +14472;ANATOLIAN HIEROGLYPH A101A;Lo;0;L;;;;;N;;;;; +14473;ANATOLIAN HIEROGLYPH A102;Lo;0;L;;;;;N;;;;; +14474;ANATOLIAN HIEROGLYPH A102A;Lo;0;L;;;;;N;;;;; +14475;ANATOLIAN HIEROGLYPH A103;Lo;0;L;;;;;N;;;;; +14476;ANATOLIAN HIEROGLYPH A104;Lo;0;L;;;;;N;;;;; +14477;ANATOLIAN HIEROGLYPH A104A;Lo;0;L;;;;;N;;;;; +14478;ANATOLIAN HIEROGLYPH A104B;Lo;0;L;;;;;N;;;;; +14479;ANATOLIAN HIEROGLYPH A104C;Lo;0;L;;;;;N;;;;; +1447A;ANATOLIAN HIEROGLYPH A105;Lo;0;L;;;;;N;;;;; +1447B;ANATOLIAN HIEROGLYPH A105A;Lo;0;L;;;;;N;;;;; +1447C;ANATOLIAN HIEROGLYPH A105B;Lo;0;L;;;;;N;;;;; +1447D;ANATOLIAN HIEROGLYPH A106;Lo;0;L;;;;;N;;;;; +1447E;ANATOLIAN HIEROGLYPH A107;Lo;0;L;;;;;N;;;;; +1447F;ANATOLIAN HIEROGLYPH A107A;Lo;0;L;;;;;N;;;;; +14480;ANATOLIAN HIEROGLYPH A107B;Lo;0;L;;;;;N;;;;; +14481;ANATOLIAN HIEROGLYPH A107C;Lo;0;L;;;;;N;;;;; +14482;ANATOLIAN HIEROGLYPH A108;Lo;0;L;;;;;N;;;;; +14483;ANATOLIAN HIEROGLYPH A109;Lo;0;L;;;;;N;;;;; +14484;ANATOLIAN HIEROGLYPH A110;Lo;0;L;;;;;N;;;;; +14485;ANATOLIAN HIEROGLYPH A110A;Lo;0;L;;;;;N;;;;; +14486;ANATOLIAN HIEROGLYPH A110B;Lo;0;L;;;;;N;;;;; +14487;ANATOLIAN HIEROGLYPH A111;Lo;0;L;;;;;N;;;;; +14488;ANATOLIAN HIEROGLYPH A112;Lo;0;L;;;;;N;;;;; +14489;ANATOLIAN HIEROGLYPH A113;Lo;0;L;;;;;N;;;;; +1448A;ANATOLIAN HIEROGLYPH A114;Lo;0;L;;;;;N;;;;; +1448B;ANATOLIAN HIEROGLYPH A115;Lo;0;L;;;;;N;;;;; +1448C;ANATOLIAN HIEROGLYPH A115A;Lo;0;L;;;;;N;;;;; +1448D;ANATOLIAN HIEROGLYPH A116;Lo;0;L;;;;;N;;;;; +1448E;ANATOLIAN HIEROGLYPH A117;Lo;0;L;;;;;N;;;;; +1448F;ANATOLIAN HIEROGLYPH A118;Lo;0;L;;;;;N;;;;; +14490;ANATOLIAN HIEROGLYPH A119;Lo;0;L;;;;;N;;;;; +14491;ANATOLIAN HIEROGLYPH A120;Lo;0;L;;;;;N;;;;; +14492;ANATOLIAN HIEROGLYPH A121;Lo;0;L;;;;;N;;;;; +14493;ANATOLIAN HIEROGLYPH A122;Lo;0;L;;;;;N;;;;; +14494;ANATOLIAN HIEROGLYPH A123;Lo;0;L;;;;;N;;;;; +14495;ANATOLIAN HIEROGLYPH A124;Lo;0;L;;;;;N;;;;; +14496;ANATOLIAN HIEROGLYPH A125;Lo;0;L;;;;;N;;;;; +14497;ANATOLIAN HIEROGLYPH A125A;Lo;0;L;;;;;N;;;;; +14498;ANATOLIAN HIEROGLYPH A126;Lo;0;L;;;;;N;;;;; +14499;ANATOLIAN HIEROGLYPH A127;Lo;0;L;;;;;N;;;;; +1449A;ANATOLIAN HIEROGLYPH A128;Lo;0;L;;;;;N;;;;; +1449B;ANATOLIAN HIEROGLYPH A129;Lo;0;L;;;;;N;;;;; +1449C;ANATOLIAN HIEROGLYPH A130;Lo;0;L;;;;;N;;;;; +1449D;ANATOLIAN HIEROGLYPH A131;Lo;0;L;;;;;N;;;;; +1449E;ANATOLIAN HIEROGLYPH A132;Lo;0;L;;;;;N;;;;; +1449F;ANATOLIAN HIEROGLYPH A133;Lo;0;L;;;;;N;;;;; +144A0;ANATOLIAN HIEROGLYPH A134;Lo;0;L;;;;;N;;;;; +144A1;ANATOLIAN HIEROGLYPH A135;Lo;0;L;;;;;N;;;;; +144A2;ANATOLIAN HIEROGLYPH A135A;Lo;0;L;;;;;N;;;;; +144A3;ANATOLIAN HIEROGLYPH A136;Lo;0;L;;;;;N;;;;; +144A4;ANATOLIAN HIEROGLYPH A137;Lo;0;L;;;;;N;;;;; +144A5;ANATOLIAN HIEROGLYPH A138;Lo;0;L;;;;;N;;;;; +144A6;ANATOLIAN HIEROGLYPH A139;Lo;0;L;;;;;N;;;;; +144A7;ANATOLIAN HIEROGLYPH A140;Lo;0;L;;;;;N;;;;; +144A8;ANATOLIAN HIEROGLYPH A141;Lo;0;L;;;;;N;;;;; +144A9;ANATOLIAN HIEROGLYPH A142;Lo;0;L;;;;;N;;;;; +144AA;ANATOLIAN HIEROGLYPH A143;Lo;0;L;;;;;N;;;;; +144AB;ANATOLIAN HIEROGLYPH A144;Lo;0;L;;;;;N;;;;; +144AC;ANATOLIAN HIEROGLYPH A145;Lo;0;L;;;;;N;;;;; +144AD;ANATOLIAN HIEROGLYPH A146;Lo;0;L;;;;;N;;;;; +144AE;ANATOLIAN HIEROGLYPH A147;Lo;0;L;;;;;N;;;;; +144AF;ANATOLIAN HIEROGLYPH A148;Lo;0;L;;;;;N;;;;; +144B0;ANATOLIAN HIEROGLYPH A149;Lo;0;L;;;;;N;;;;; +144B1;ANATOLIAN HIEROGLYPH A150;Lo;0;L;;;;;N;;;;; +144B2;ANATOLIAN HIEROGLYPH A151;Lo;0;L;;;;;N;;;;; +144B3;ANATOLIAN HIEROGLYPH A152;Lo;0;L;;;;;N;;;;; +144B4;ANATOLIAN HIEROGLYPH A153;Lo;0;L;;;;;N;;;;; +144B5;ANATOLIAN HIEROGLYPH A154;Lo;0;L;;;;;N;;;;; +144B6;ANATOLIAN HIEROGLYPH A155;Lo;0;L;;;;;N;;;;; +144B7;ANATOLIAN HIEROGLYPH A156;Lo;0;L;;;;;N;;;;; +144B8;ANATOLIAN HIEROGLYPH A157;Lo;0;L;;;;;N;;;;; +144B9;ANATOLIAN HIEROGLYPH A158;Lo;0;L;;;;;N;;;;; +144BA;ANATOLIAN HIEROGLYPH A159;Lo;0;L;;;;;N;;;;; +144BB;ANATOLIAN HIEROGLYPH A160;Lo;0;L;;;;;N;;;;; +144BC;ANATOLIAN HIEROGLYPH A161;Lo;0;L;;;;;N;;;;; +144BD;ANATOLIAN HIEROGLYPH A162;Lo;0;L;;;;;N;;;;; +144BE;ANATOLIAN HIEROGLYPH A163;Lo;0;L;;;;;N;;;;; +144BF;ANATOLIAN HIEROGLYPH A164;Lo;0;L;;;;;N;;;;; +144C0;ANATOLIAN HIEROGLYPH A165;Lo;0;L;;;;;N;;;;; +144C1;ANATOLIAN HIEROGLYPH A166;Lo;0;L;;;;;N;;;;; +144C2;ANATOLIAN HIEROGLYPH A167;Lo;0;L;;;;;N;;;;; +144C3;ANATOLIAN HIEROGLYPH A168;Lo;0;L;;;;;N;;;;; +144C4;ANATOLIAN HIEROGLYPH A169;Lo;0;L;;;;;N;;;;; +144C5;ANATOLIAN HIEROGLYPH A170;Lo;0;L;;;;;N;;;;; +144C6;ANATOLIAN HIEROGLYPH A171;Lo;0;L;;;;;N;;;;; +144C7;ANATOLIAN HIEROGLYPH A172;Lo;0;L;;;;;N;;;;; +144C8;ANATOLIAN HIEROGLYPH A173;Lo;0;L;;;;;N;;;;; +144C9;ANATOLIAN HIEROGLYPH A174;Lo;0;L;;;;;N;;;;; +144CA;ANATOLIAN HIEROGLYPH A175;Lo;0;L;;;;;N;;;;; +144CB;ANATOLIAN HIEROGLYPH A176;Lo;0;L;;;;;N;;;;; +144CC;ANATOLIAN HIEROGLYPH A177;Lo;0;L;;;;;N;;;;; +144CD;ANATOLIAN HIEROGLYPH A178;Lo;0;L;;;;;N;;;;; +144CE;ANATOLIAN HIEROGLYPH A179;Lo;0;L;;;;;N;;;;; +144CF;ANATOLIAN HIEROGLYPH A180;Lo;0;L;;;;;N;;;;; +144D0;ANATOLIAN HIEROGLYPH A181;Lo;0;L;;;;;N;;;;; +144D1;ANATOLIAN HIEROGLYPH A182;Lo;0;L;;;;;N;;;;; +144D2;ANATOLIAN HIEROGLYPH A183;Lo;0;L;;;;;N;;;;; +144D3;ANATOLIAN HIEROGLYPH A184;Lo;0;L;;;;;N;;;;; +144D4;ANATOLIAN HIEROGLYPH A185;Lo;0;L;;;;;N;;;;; +144D5;ANATOLIAN HIEROGLYPH A186;Lo;0;L;;;;;N;;;;; +144D6;ANATOLIAN HIEROGLYPH A187;Lo;0;L;;;;;N;;;;; +144D7;ANATOLIAN HIEROGLYPH A188;Lo;0;L;;;;;N;;;;; +144D8;ANATOLIAN HIEROGLYPH A189;Lo;0;L;;;;;N;;;;; +144D9;ANATOLIAN HIEROGLYPH A190;Lo;0;L;;;;;N;;;;; +144DA;ANATOLIAN HIEROGLYPH A191;Lo;0;L;;;;;N;;;;; +144DB;ANATOLIAN HIEROGLYPH A192;Lo;0;L;;;;;N;;;;; +144DC;ANATOLIAN HIEROGLYPH A193;Lo;0;L;;;;;N;;;;; +144DD;ANATOLIAN HIEROGLYPH A194;Lo;0;L;;;;;N;;;;; +144DE;ANATOLIAN HIEROGLYPH A195;Lo;0;L;;;;;N;;;;; +144DF;ANATOLIAN HIEROGLYPH A196;Lo;0;L;;;;;N;;;;; +144E0;ANATOLIAN HIEROGLYPH A197;Lo;0;L;;;;;N;;;;; +144E1;ANATOLIAN HIEROGLYPH A198;Lo;0;L;;;;;N;;;;; +144E2;ANATOLIAN HIEROGLYPH A199;Lo;0;L;;;;;N;;;;; +144E3;ANATOLIAN HIEROGLYPH A200;Lo;0;L;;;;;N;;;;; +144E4;ANATOLIAN HIEROGLYPH A201;Lo;0;L;;;;;N;;;;; +144E5;ANATOLIAN HIEROGLYPH A202;Lo;0;L;;;;;N;;;;; +144E6;ANATOLIAN HIEROGLYPH A202A;Lo;0;L;;;;;N;;;;; +144E7;ANATOLIAN HIEROGLYPH A202B;Lo;0;L;;;;;N;;;;; +144E8;ANATOLIAN HIEROGLYPH A203;Lo;0;L;;;;;N;;;;; +144E9;ANATOLIAN HIEROGLYPH A204;Lo;0;L;;;;;N;;;;; +144EA;ANATOLIAN HIEROGLYPH A205;Lo;0;L;;;;;N;;;;; +144EB;ANATOLIAN HIEROGLYPH A206;Lo;0;L;;;;;N;;;;; +144EC;ANATOLIAN HIEROGLYPH A207;Lo;0;L;;;;;N;;;;; +144ED;ANATOLIAN HIEROGLYPH A207A;Lo;0;L;;;;;N;;;;; +144EE;ANATOLIAN HIEROGLYPH A208;Lo;0;L;;;;;N;;;;; +144EF;ANATOLIAN HIEROGLYPH A209;Lo;0;L;;;;;N;;;;; +144F0;ANATOLIAN HIEROGLYPH A209A;Lo;0;L;;;;;N;;;;; +144F1;ANATOLIAN HIEROGLYPH A210;Lo;0;L;;;;;N;;;;; +144F2;ANATOLIAN HIEROGLYPH A211;Lo;0;L;;;;;N;;;;; +144F3;ANATOLIAN HIEROGLYPH A212;Lo;0;L;;;;;N;;;;; +144F4;ANATOLIAN HIEROGLYPH A213;Lo;0;L;;;;;N;;;;; +144F5;ANATOLIAN HIEROGLYPH A214;Lo;0;L;;;;;N;;;;; +144F6;ANATOLIAN HIEROGLYPH A215;Lo;0;L;;;;;N;;;;; +144F7;ANATOLIAN HIEROGLYPH A215A;Lo;0;L;;;;;N;;;;; +144F8;ANATOLIAN HIEROGLYPH A216;Lo;0;L;;;;;N;;;;; +144F9;ANATOLIAN HIEROGLYPH A216A;Lo;0;L;;;;;N;;;;; +144FA;ANATOLIAN HIEROGLYPH A217;Lo;0;L;;;;;N;;;;; +144FB;ANATOLIAN HIEROGLYPH A218;Lo;0;L;;;;;N;;;;; +144FC;ANATOLIAN HIEROGLYPH A219;Lo;0;L;;;;;N;;;;; +144FD;ANATOLIAN HIEROGLYPH A220;Lo;0;L;;;;;N;;;;; +144FE;ANATOLIAN HIEROGLYPH A221;Lo;0;L;;;;;N;;;;; +144FF;ANATOLIAN HIEROGLYPH A222;Lo;0;L;;;;;N;;;;; +14500;ANATOLIAN HIEROGLYPH A223;Lo;0;L;;;;;N;;;;; +14501;ANATOLIAN HIEROGLYPH A224;Lo;0;L;;;;;N;;;;; +14502;ANATOLIAN HIEROGLYPH A225;Lo;0;L;;;;;N;;;;; +14503;ANATOLIAN HIEROGLYPH A226;Lo;0;L;;;;;N;;;;; +14504;ANATOLIAN HIEROGLYPH A227;Lo;0;L;;;;;N;;;;; +14505;ANATOLIAN HIEROGLYPH A227A;Lo;0;L;;;;;N;;;;; +14506;ANATOLIAN HIEROGLYPH A228;Lo;0;L;;;;;N;;;;; +14507;ANATOLIAN HIEROGLYPH A229;Lo;0;L;;;;;N;;;;; +14508;ANATOLIAN HIEROGLYPH A230;Lo;0;L;;;;;N;;;;; +14509;ANATOLIAN HIEROGLYPH A231;Lo;0;L;;;;;N;;;;; +1450A;ANATOLIAN HIEROGLYPH A232;Lo;0;L;;;;;N;;;;; +1450B;ANATOLIAN HIEROGLYPH A233;Lo;0;L;;;;;N;;;;; +1450C;ANATOLIAN HIEROGLYPH A234;Lo;0;L;;;;;N;;;;; +1450D;ANATOLIAN HIEROGLYPH A235;Lo;0;L;;;;;N;;;;; +1450E;ANATOLIAN HIEROGLYPH A236;Lo;0;L;;;;;N;;;;; +1450F;ANATOLIAN HIEROGLYPH A237;Lo;0;L;;;;;N;;;;; +14510;ANATOLIAN HIEROGLYPH A238;Lo;0;L;;;;;N;;;;; +14511;ANATOLIAN HIEROGLYPH A239;Lo;0;L;;;;;N;;;;; +14512;ANATOLIAN HIEROGLYPH A240;Lo;0;L;;;;;N;;;;; +14513;ANATOLIAN HIEROGLYPH A241;Lo;0;L;;;;;N;;;;; +14514;ANATOLIAN HIEROGLYPH A242;Lo;0;L;;;;;N;;;;; +14515;ANATOLIAN HIEROGLYPH A243;Lo;0;L;;;;;N;;;;; +14516;ANATOLIAN HIEROGLYPH A244;Lo;0;L;;;;;N;;;;; +14517;ANATOLIAN HIEROGLYPH A245;Lo;0;L;;;;;N;;;;; +14518;ANATOLIAN HIEROGLYPH A246;Lo;0;L;;;;;N;;;;; +14519;ANATOLIAN HIEROGLYPH A247;Lo;0;L;;;;;N;;;;; +1451A;ANATOLIAN HIEROGLYPH A248;Lo;0;L;;;;;N;;;;; +1451B;ANATOLIAN HIEROGLYPH A249;Lo;0;L;;;;;N;;;;; +1451C;ANATOLIAN HIEROGLYPH A250;Lo;0;L;;;;;N;;;;; +1451D;ANATOLIAN HIEROGLYPH A251;Lo;0;L;;;;;N;;;;; +1451E;ANATOLIAN HIEROGLYPH A252;Lo;0;L;;;;;N;;;;; +1451F;ANATOLIAN HIEROGLYPH A253;Lo;0;L;;;;;N;;;;; +14520;ANATOLIAN HIEROGLYPH A254;Lo;0;L;;;;;N;;;;; +14521;ANATOLIAN HIEROGLYPH A255;Lo;0;L;;;;;N;;;;; +14522;ANATOLIAN HIEROGLYPH A256;Lo;0;L;;;;;N;;;;; +14523;ANATOLIAN HIEROGLYPH A257;Lo;0;L;;;;;N;;;;; +14524;ANATOLIAN HIEROGLYPH A258;Lo;0;L;;;;;N;;;;; +14525;ANATOLIAN HIEROGLYPH A259;Lo;0;L;;;;;N;;;;; +14526;ANATOLIAN HIEROGLYPH A260;Lo;0;L;;;;;N;;;;; +14527;ANATOLIAN HIEROGLYPH A261;Lo;0;L;;;;;N;;;;; +14528;ANATOLIAN HIEROGLYPH A262;Lo;0;L;;;;;N;;;;; +14529;ANATOLIAN HIEROGLYPH A263;Lo;0;L;;;;;N;;;;; +1452A;ANATOLIAN HIEROGLYPH A264;Lo;0;L;;;;;N;;;;; +1452B;ANATOLIAN HIEROGLYPH A265;Lo;0;L;;;;;N;;;;; +1452C;ANATOLIAN HIEROGLYPH A266;Lo;0;L;;;;;N;;;;; +1452D;ANATOLIAN HIEROGLYPH A267;Lo;0;L;;;;;N;;;;; +1452E;ANATOLIAN HIEROGLYPH A267A;Lo;0;L;;;;;N;;;;; +1452F;ANATOLIAN HIEROGLYPH A268;Lo;0;L;;;;;N;;;;; +14530;ANATOLIAN HIEROGLYPH A269;Lo;0;L;;;;;N;;;;; +14531;ANATOLIAN HIEROGLYPH A270;Lo;0;L;;;;;N;;;;; +14532;ANATOLIAN HIEROGLYPH A271;Lo;0;L;;;;;N;;;;; +14533;ANATOLIAN HIEROGLYPH A272;Lo;0;L;;;;;N;;;;; +14534;ANATOLIAN HIEROGLYPH A273;Lo;0;L;;;;;N;;;;; +14535;ANATOLIAN HIEROGLYPH A274;Lo;0;L;;;;;N;;;;; +14536;ANATOLIAN HIEROGLYPH A275;Lo;0;L;;;;;N;;;;; +14537;ANATOLIAN HIEROGLYPH A276;Lo;0;L;;;;;N;;;;; +14538;ANATOLIAN HIEROGLYPH A277;Lo;0;L;;;;;N;;;;; +14539;ANATOLIAN HIEROGLYPH A278;Lo;0;L;;;;;N;;;;; +1453A;ANATOLIAN HIEROGLYPH A279;Lo;0;L;;;;;N;;;;; +1453B;ANATOLIAN HIEROGLYPH A280;Lo;0;L;;;;;N;;;;; +1453C;ANATOLIAN HIEROGLYPH A281;Lo;0;L;;;;;N;;;;; +1453D;ANATOLIAN HIEROGLYPH A282;Lo;0;L;;;;;N;;;;; +1453E;ANATOLIAN HIEROGLYPH A283;Lo;0;L;;;;;N;;;;; +1453F;ANATOLIAN HIEROGLYPH A284;Lo;0;L;;;;;N;;;;; +14540;ANATOLIAN HIEROGLYPH A285;Lo;0;L;;;;;N;;;;; +14541;ANATOLIAN HIEROGLYPH A286;Lo;0;L;;;;;N;;;;; +14542;ANATOLIAN HIEROGLYPH A287;Lo;0;L;;;;;N;;;;; +14543;ANATOLIAN HIEROGLYPH A288;Lo;0;L;;;;;N;;;;; +14544;ANATOLIAN HIEROGLYPH A289;Lo;0;L;;;;;N;;;;; +14545;ANATOLIAN HIEROGLYPH A289A;Lo;0;L;;;;;N;;;;; +14546;ANATOLIAN HIEROGLYPH A290;Lo;0;L;;;;;N;;;;; +14547;ANATOLIAN HIEROGLYPH A291;Lo;0;L;;;;;N;;;;; +14548;ANATOLIAN HIEROGLYPH A292;Lo;0;L;;;;;N;;;;; +14549;ANATOLIAN HIEROGLYPH A293;Lo;0;L;;;;;N;;;;; +1454A;ANATOLIAN HIEROGLYPH A294;Lo;0;L;;;;;N;;;;; +1454B;ANATOLIAN HIEROGLYPH A294A;Lo;0;L;;;;;N;;;;; +1454C;ANATOLIAN HIEROGLYPH A295;Lo;0;L;;;;;N;;;;; +1454D;ANATOLIAN HIEROGLYPH A296;Lo;0;L;;;;;N;;;;; +1454E;ANATOLIAN HIEROGLYPH A297;Lo;0;L;;;;;N;;;;; +1454F;ANATOLIAN HIEROGLYPH A298;Lo;0;L;;;;;N;;;;; +14550;ANATOLIAN HIEROGLYPH A299;Lo;0;L;;;;;N;;;;; +14551;ANATOLIAN HIEROGLYPH A299A;Lo;0;L;;;;;N;;;;; +14552;ANATOLIAN HIEROGLYPH A300;Lo;0;L;;;;;N;;;;; +14553;ANATOLIAN HIEROGLYPH A301;Lo;0;L;;;;;N;;;;; +14554;ANATOLIAN HIEROGLYPH A302;Lo;0;L;;;;;N;;;;; +14555;ANATOLIAN HIEROGLYPH A303;Lo;0;L;;;;;N;;;;; +14556;ANATOLIAN HIEROGLYPH A304;Lo;0;L;;;;;N;;;;; +14557;ANATOLIAN HIEROGLYPH A305;Lo;0;L;;;;;N;;;;; +14558;ANATOLIAN HIEROGLYPH A306;Lo;0;L;;;;;N;;;;; +14559;ANATOLIAN HIEROGLYPH A307;Lo;0;L;;;;;N;;;;; +1455A;ANATOLIAN HIEROGLYPH A308;Lo;0;L;;;;;N;;;;; +1455B;ANATOLIAN HIEROGLYPH A309;Lo;0;L;;;;;N;;;;; +1455C;ANATOLIAN HIEROGLYPH A309A;Lo;0;L;;;;;N;;;;; +1455D;ANATOLIAN HIEROGLYPH A310;Lo;0;L;;;;;N;;;;; +1455E;ANATOLIAN HIEROGLYPH A311;Lo;0;L;;;;;N;;;;; +1455F;ANATOLIAN HIEROGLYPH A312;Lo;0;L;;;;;N;;;;; +14560;ANATOLIAN HIEROGLYPH A313;Lo;0;L;;;;;N;;;;; +14561;ANATOLIAN HIEROGLYPH A314;Lo;0;L;;;;;N;;;;; +14562;ANATOLIAN HIEROGLYPH A315;Lo;0;L;;;;;N;;;;; +14563;ANATOLIAN HIEROGLYPH A316;Lo;0;L;;;;;N;;;;; +14564;ANATOLIAN HIEROGLYPH A317;Lo;0;L;;;;;N;;;;; +14565;ANATOLIAN HIEROGLYPH A318;Lo;0;L;;;;;N;;;;; +14566;ANATOLIAN HIEROGLYPH A319;Lo;0;L;;;;;N;;;;; +14567;ANATOLIAN HIEROGLYPH A320;Lo;0;L;;;;;N;;;;; +14568;ANATOLIAN HIEROGLYPH A321;Lo;0;L;;;;;N;;;;; +14569;ANATOLIAN HIEROGLYPH A322;Lo;0;L;;;;;N;;;;; +1456A;ANATOLIAN HIEROGLYPH A323;Lo;0;L;;;;;N;;;;; +1456B;ANATOLIAN HIEROGLYPH A324;Lo;0;L;;;;;N;;;;; +1456C;ANATOLIAN HIEROGLYPH A325;Lo;0;L;;;;;N;;;;; +1456D;ANATOLIAN HIEROGLYPH A326;Lo;0;L;;;;;N;;;;; +1456E;ANATOLIAN HIEROGLYPH A327;Lo;0;L;;;;;N;;;;; +1456F;ANATOLIAN HIEROGLYPH A328;Lo;0;L;;;;;N;;;;; +14570;ANATOLIAN HIEROGLYPH A329;Lo;0;L;;;;;N;;;;; +14571;ANATOLIAN HIEROGLYPH A329A;Lo;0;L;;;;;N;;;;; +14572;ANATOLIAN HIEROGLYPH A330;Lo;0;L;;;;;N;;;;; +14573;ANATOLIAN HIEROGLYPH A331;Lo;0;L;;;;;N;;;;; +14574;ANATOLIAN HIEROGLYPH A332A;Lo;0;L;;;;;N;;;;; +14575;ANATOLIAN HIEROGLYPH A332B;Lo;0;L;;;;;N;;;;; +14576;ANATOLIAN HIEROGLYPH A332C;Lo;0;L;;;;;N;;;;; +14577;ANATOLIAN HIEROGLYPH A333;Lo;0;L;;;;;N;;;;; +14578;ANATOLIAN HIEROGLYPH A334;Lo;0;L;;;;;N;;;;; +14579;ANATOLIAN HIEROGLYPH A335;Lo;0;L;;;;;N;;;;; +1457A;ANATOLIAN HIEROGLYPH A336;Lo;0;L;;;;;N;;;;; +1457B;ANATOLIAN HIEROGLYPH A336A;Lo;0;L;;;;;N;;;;; +1457C;ANATOLIAN HIEROGLYPH A336B;Lo;0;L;;;;;N;;;;; +1457D;ANATOLIAN HIEROGLYPH A336C;Lo;0;L;;;;;N;;;;; +1457E;ANATOLIAN HIEROGLYPH A337;Lo;0;L;;;;;N;;;;; +1457F;ANATOLIAN HIEROGLYPH A338;Lo;0;L;;;;;N;;;;; +14580;ANATOLIAN HIEROGLYPH A339;Lo;0;L;;;;;N;;;;; +14581;ANATOLIAN HIEROGLYPH A340;Lo;0;L;;;;;N;;;;; +14582;ANATOLIAN HIEROGLYPH A341;Lo;0;L;;;;;N;;;;; +14583;ANATOLIAN HIEROGLYPH A342;Lo;0;L;;;;;N;;;;; +14584;ANATOLIAN HIEROGLYPH A343;Lo;0;L;;;;;N;;;;; +14585;ANATOLIAN HIEROGLYPH A344;Lo;0;L;;;;;N;;;;; +14586;ANATOLIAN HIEROGLYPH A345;Lo;0;L;;;;;N;;;;; +14587;ANATOLIAN HIEROGLYPH A346;Lo;0;L;;;;;N;;;;; +14588;ANATOLIAN HIEROGLYPH A347;Lo;0;L;;;;;N;;;;; +14589;ANATOLIAN HIEROGLYPH A348;Lo;0;L;;;;;N;;;;; +1458A;ANATOLIAN HIEROGLYPH A349;Lo;0;L;;;;;N;;;;; +1458B;ANATOLIAN HIEROGLYPH A350;Lo;0;L;;;;;N;;;;; +1458C;ANATOLIAN HIEROGLYPH A351;Lo;0;L;;;;;N;;;;; +1458D;ANATOLIAN HIEROGLYPH A352;Lo;0;L;;;;;N;;;;; +1458E;ANATOLIAN HIEROGLYPH A353;Lo;0;L;;;;;N;;;;; +1458F;ANATOLIAN HIEROGLYPH A354;Lo;0;L;;;;;N;;;;; +14590;ANATOLIAN HIEROGLYPH A355;Lo;0;L;;;;;N;;;;; +14591;ANATOLIAN HIEROGLYPH A356;Lo;0;L;;;;;N;;;;; +14592;ANATOLIAN HIEROGLYPH A357;Lo;0;L;;;;;N;;;;; +14593;ANATOLIAN HIEROGLYPH A358;Lo;0;L;;;;;N;;;;; +14594;ANATOLIAN HIEROGLYPH A359;Lo;0;L;;;;;N;;;;; +14595;ANATOLIAN HIEROGLYPH A359A;Lo;0;L;;;;;N;;;;; +14596;ANATOLIAN HIEROGLYPH A360;Lo;0;L;;;;;N;;;;; +14597;ANATOLIAN HIEROGLYPH A361;Lo;0;L;;;;;N;;;;; +14598;ANATOLIAN HIEROGLYPH A362;Lo;0;L;;;;;N;;;;; +14599;ANATOLIAN HIEROGLYPH A363;Lo;0;L;;;;;N;;;;; +1459A;ANATOLIAN HIEROGLYPH A364;Lo;0;L;;;;;N;;;;; +1459B;ANATOLIAN HIEROGLYPH A364A;Lo;0;L;;;;;N;;;;; +1459C;ANATOLIAN HIEROGLYPH A365;Lo;0;L;;;;;N;;;;; +1459D;ANATOLIAN HIEROGLYPH A366;Lo;0;L;;;;;N;;;;; +1459E;ANATOLIAN HIEROGLYPH A367;Lo;0;L;;;;;N;;;;; +1459F;ANATOLIAN HIEROGLYPH A368;Lo;0;L;;;;;N;;;;; +145A0;ANATOLIAN HIEROGLYPH A368A;Lo;0;L;;;;;N;;;;; +145A1;ANATOLIAN HIEROGLYPH A369;Lo;0;L;;;;;N;;;;; +145A2;ANATOLIAN HIEROGLYPH A370;Lo;0;L;;;;;N;;;;; +145A3;ANATOLIAN HIEROGLYPH A371;Lo;0;L;;;;;N;;;;; +145A4;ANATOLIAN HIEROGLYPH A371A;Lo;0;L;;;;;N;;;;; +145A5;ANATOLIAN HIEROGLYPH A372;Lo;0;L;;;;;N;;;;; +145A6;ANATOLIAN HIEROGLYPH A373;Lo;0;L;;;;;N;;;;; +145A7;ANATOLIAN HIEROGLYPH A374;Lo;0;L;;;;;N;;;;; +145A8;ANATOLIAN HIEROGLYPH A375;Lo;0;L;;;;;N;;;;; +145A9;ANATOLIAN HIEROGLYPH A376;Lo;0;L;;;;;N;;;;; +145AA;ANATOLIAN HIEROGLYPH A377;Lo;0;L;;;;;N;;;;; +145AB;ANATOLIAN HIEROGLYPH A378;Lo;0;L;;;;;N;;;;; +145AC;ANATOLIAN HIEROGLYPH A379;Lo;0;L;;;;;N;;;;; +145AD;ANATOLIAN HIEROGLYPH A380;Lo;0;L;;;;;N;;;;; +145AE;ANATOLIAN HIEROGLYPH A381;Lo;0;L;;;;;N;;;;; +145AF;ANATOLIAN HIEROGLYPH A381A;Lo;0;L;;;;;N;;;;; +145B0;ANATOLIAN HIEROGLYPH A382;Lo;0;L;;;;;N;;;;; +145B1;ANATOLIAN HIEROGLYPH A383 RA OR RI;Lo;0;L;;;;;N;;;;; +145B2;ANATOLIAN HIEROGLYPH A383A;Lo;0;L;;;;;N;;;;; +145B3;ANATOLIAN HIEROGLYPH A384;Lo;0;L;;;;;N;;;;; +145B4;ANATOLIAN HIEROGLYPH A385;Lo;0;L;;;;;N;;;;; +145B5;ANATOLIAN HIEROGLYPH A386;Lo;0;L;;;;;N;;;;; +145B6;ANATOLIAN HIEROGLYPH A386A;Lo;0;L;;;;;N;;;;; +145B7;ANATOLIAN HIEROGLYPH A387;Lo;0;L;;;;;N;;;;; +145B8;ANATOLIAN HIEROGLYPH A388;Lo;0;L;;;;;N;;;;; +145B9;ANATOLIAN HIEROGLYPH A389;Lo;0;L;;;;;N;;;;; +145BA;ANATOLIAN HIEROGLYPH A390;Lo;0;L;;;;;N;;;;; +145BB;ANATOLIAN HIEROGLYPH A391;Lo;0;L;;;;;N;;;;; +145BC;ANATOLIAN HIEROGLYPH A392;Lo;0;L;;;;;N;;;;; +145BD;ANATOLIAN HIEROGLYPH A393 EIGHT;Lo;0;L;;;;;N;;;;; +145BE;ANATOLIAN HIEROGLYPH A394;Lo;0;L;;;;;N;;;;; +145BF;ANATOLIAN HIEROGLYPH A395;Lo;0;L;;;;;N;;;;; +145C0;ANATOLIAN HIEROGLYPH A396;Lo;0;L;;;;;N;;;;; +145C1;ANATOLIAN HIEROGLYPH A397;Lo;0;L;;;;;N;;;;; +145C2;ANATOLIAN HIEROGLYPH A398;Lo;0;L;;;;;N;;;;; +145C3;ANATOLIAN HIEROGLYPH A399;Lo;0;L;;;;;N;;;;; +145C4;ANATOLIAN HIEROGLYPH A400;Lo;0;L;;;;;N;;;;; +145C5;ANATOLIAN HIEROGLYPH A401;Lo;0;L;;;;;N;;;;; +145C6;ANATOLIAN HIEROGLYPH A402;Lo;0;L;;;;;N;;;;; +145C7;ANATOLIAN HIEROGLYPH A403;Lo;0;L;;;;;N;;;;; +145C8;ANATOLIAN HIEROGLYPH A404;Lo;0;L;;;;;N;;;;; +145C9;ANATOLIAN HIEROGLYPH A405;Lo;0;L;;;;;N;;;;; +145CA;ANATOLIAN HIEROGLYPH A406;Lo;0;L;;;;;N;;;;; +145CB;ANATOLIAN HIEROGLYPH A407;Lo;0;L;;;;;N;;;;; +145CC;ANATOLIAN HIEROGLYPH A408;Lo;0;L;;;;;N;;;;; +145CD;ANATOLIAN HIEROGLYPH A409;Lo;0;L;;;;;N;;;;; +145CE;ANATOLIAN HIEROGLYPH A410 BEGIN LOGOGRAM MARK;Lo;0;L;;;;;N;;;;; +145CF;ANATOLIAN HIEROGLYPH A410A END LOGOGRAM MARK;Lo;0;L;;;;;N;;;;; +145D0;ANATOLIAN HIEROGLYPH A411;Lo;0;L;;;;;N;;;;; +145D1;ANATOLIAN HIEROGLYPH A412;Lo;0;L;;;;;N;;;;; +145D2;ANATOLIAN HIEROGLYPH A413;Lo;0;L;;;;;N;;;;; +145D3;ANATOLIAN HIEROGLYPH A414;Lo;0;L;;;;;N;;;;; +145D4;ANATOLIAN HIEROGLYPH A415;Lo;0;L;;;;;N;;;;; +145D5;ANATOLIAN HIEROGLYPH A416;Lo;0;L;;;;;N;;;;; +145D6;ANATOLIAN HIEROGLYPH A417;Lo;0;L;;;;;N;;;;; +145D7;ANATOLIAN HIEROGLYPH A418;Lo;0;L;;;;;N;;;;; +145D8;ANATOLIAN HIEROGLYPH A419;Lo;0;L;;;;;N;;;;; +145D9;ANATOLIAN HIEROGLYPH A420;Lo;0;L;;;;;N;;;;; +145DA;ANATOLIAN HIEROGLYPH A421;Lo;0;L;;;;;N;;;;; +145DB;ANATOLIAN HIEROGLYPH A422;Lo;0;L;;;;;N;;;;; +145DC;ANATOLIAN HIEROGLYPH A423;Lo;0;L;;;;;N;;;;; +145DD;ANATOLIAN HIEROGLYPH A424;Lo;0;L;;;;;N;;;;; +145DE;ANATOLIAN HIEROGLYPH A425;Lo;0;L;;;;;N;;;;; +145DF;ANATOLIAN HIEROGLYPH A426;Lo;0;L;;;;;N;;;;; +145E0;ANATOLIAN HIEROGLYPH A427;Lo;0;L;;;;;N;;;;; +145E1;ANATOLIAN HIEROGLYPH A428;Lo;0;L;;;;;N;;;;; +145E2;ANATOLIAN HIEROGLYPH A429;Lo;0;L;;;;;N;;;;; +145E3;ANATOLIAN HIEROGLYPH A430;Lo;0;L;;;;;N;;;;; +145E4;ANATOLIAN HIEROGLYPH A431;Lo;0;L;;;;;N;;;;; +145E5;ANATOLIAN HIEROGLYPH A432;Lo;0;L;;;;;N;;;;; +145E6;ANATOLIAN HIEROGLYPH A433;Lo;0;L;;;;;N;;;;; +145E7;ANATOLIAN HIEROGLYPH A434;Lo;0;L;;;;;N;;;;; +145E8;ANATOLIAN HIEROGLYPH A435;Lo;0;L;;;;;N;;;;; +145E9;ANATOLIAN HIEROGLYPH A436;Lo;0;L;;;;;N;;;;; +145EA;ANATOLIAN HIEROGLYPH A437;Lo;0;L;;;;;N;;;;; +145EB;ANATOLIAN HIEROGLYPH A438;Lo;0;L;;;;;N;;;;; +145EC;ANATOLIAN HIEROGLYPH A439;Lo;0;L;;;;;N;;;;; +145ED;ANATOLIAN HIEROGLYPH A440;Lo;0;L;;;;;N;;;;; +145EE;ANATOLIAN HIEROGLYPH A441;Lo;0;L;;;;;N;;;;; +145EF;ANATOLIAN HIEROGLYPH A442;Lo;0;L;;;;;N;;;;; +145F0;ANATOLIAN HIEROGLYPH A443;Lo;0;L;;;;;N;;;;; +145F1;ANATOLIAN HIEROGLYPH A444;Lo;0;L;;;;;N;;;;; +145F2;ANATOLIAN HIEROGLYPH A445;Lo;0;L;;;;;N;;;;; +145F3;ANATOLIAN HIEROGLYPH A446;Lo;0;L;;;;;N;;;;; +145F4;ANATOLIAN HIEROGLYPH A447;Lo;0;L;;;;;N;;;;; +145F5;ANATOLIAN HIEROGLYPH A448;Lo;0;L;;;;;N;;;;; +145F6;ANATOLIAN HIEROGLYPH A449;Lo;0;L;;;;;N;;;;; +145F7;ANATOLIAN HIEROGLYPH A450;Lo;0;L;;;;;N;;;;; +145F8;ANATOLIAN HIEROGLYPH A450A;Lo;0;L;;;;;N;;;;; +145F9;ANATOLIAN HIEROGLYPH A451;Lo;0;L;;;;;N;;;;; +145FA;ANATOLIAN HIEROGLYPH A452;Lo;0;L;;;;;N;;;;; +145FB;ANATOLIAN HIEROGLYPH A453;Lo;0;L;;;;;N;;;;; +145FC;ANATOLIAN HIEROGLYPH A454;Lo;0;L;;;;;N;;;;; +145FD;ANATOLIAN HIEROGLYPH A455;Lo;0;L;;;;;N;;;;; +145FE;ANATOLIAN HIEROGLYPH A456;Lo;0;L;;;;;N;;;;; +145FF;ANATOLIAN HIEROGLYPH A457;Lo;0;L;;;;;N;;;;; +14600;ANATOLIAN HIEROGLYPH A457A;Lo;0;L;;;;;N;;;;; +14601;ANATOLIAN HIEROGLYPH A458;Lo;0;L;;;;;N;;;;; +14602;ANATOLIAN HIEROGLYPH A459;Lo;0;L;;;;;N;;;;; +14603;ANATOLIAN HIEROGLYPH A460;Lo;0;L;;;;;N;;;;; +14604;ANATOLIAN HIEROGLYPH A461;Lo;0;L;;;;;N;;;;; +14605;ANATOLIAN HIEROGLYPH A462;Lo;0;L;;;;;N;;;;; +14606;ANATOLIAN HIEROGLYPH A463;Lo;0;L;;;;;N;;;;; +14607;ANATOLIAN HIEROGLYPH A464;Lo;0;L;;;;;N;;;;; +14608;ANATOLIAN HIEROGLYPH A465;Lo;0;L;;;;;N;;;;; +14609;ANATOLIAN HIEROGLYPH A466;Lo;0;L;;;;;N;;;;; +1460A;ANATOLIAN HIEROGLYPH A467;Lo;0;L;;;;;N;;;;; +1460B;ANATOLIAN HIEROGLYPH A468;Lo;0;L;;;;;N;;;;; +1460C;ANATOLIAN HIEROGLYPH A469;Lo;0;L;;;;;N;;;;; +1460D;ANATOLIAN HIEROGLYPH A470;Lo;0;L;;;;;N;;;;; +1460E;ANATOLIAN HIEROGLYPH A471;Lo;0;L;;;;;N;;;;; +1460F;ANATOLIAN HIEROGLYPH A472;Lo;0;L;;;;;N;;;;; +14610;ANATOLIAN HIEROGLYPH A473;Lo;0;L;;;;;N;;;;; +14611;ANATOLIAN HIEROGLYPH A474;Lo;0;L;;;;;N;;;;; +14612;ANATOLIAN HIEROGLYPH A475;Lo;0;L;;;;;N;;;;; +14613;ANATOLIAN HIEROGLYPH A476;Lo;0;L;;;;;N;;;;; +14614;ANATOLIAN HIEROGLYPH A477;Lo;0;L;;;;;N;;;;; +14615;ANATOLIAN HIEROGLYPH A478;Lo;0;L;;;;;N;;;;; +14616;ANATOLIAN HIEROGLYPH A479;Lo;0;L;;;;;N;;;;; +14617;ANATOLIAN HIEROGLYPH A480;Lo;0;L;;;;;N;;;;; +14618;ANATOLIAN HIEROGLYPH A481;Lo;0;L;;;;;N;;;;; +14619;ANATOLIAN HIEROGLYPH A482;Lo;0;L;;;;;N;;;;; +1461A;ANATOLIAN HIEROGLYPH A483;Lo;0;L;;;;;N;;;;; +1461B;ANATOLIAN HIEROGLYPH A484;Lo;0;L;;;;;N;;;;; +1461C;ANATOLIAN HIEROGLYPH A485;Lo;0;L;;;;;N;;;;; +1461D;ANATOLIAN HIEROGLYPH A486;Lo;0;L;;;;;N;;;;; +1461E;ANATOLIAN HIEROGLYPH A487;Lo;0;L;;;;;N;;;;; +1461F;ANATOLIAN HIEROGLYPH A488;Lo;0;L;;;;;N;;;;; +14620;ANATOLIAN HIEROGLYPH A489;Lo;0;L;;;;;N;;;;; +14621;ANATOLIAN HIEROGLYPH A490;Lo;0;L;;;;;N;;;;; +14622;ANATOLIAN HIEROGLYPH A491;Lo;0;L;;;;;N;;;;; +14623;ANATOLIAN HIEROGLYPH A492;Lo;0;L;;;;;N;;;;; +14624;ANATOLIAN HIEROGLYPH A493;Lo;0;L;;;;;N;;;;; +14625;ANATOLIAN HIEROGLYPH A494;Lo;0;L;;;;;N;;;;; +14626;ANATOLIAN HIEROGLYPH A495;Lo;0;L;;;;;N;;;;; +14627;ANATOLIAN HIEROGLYPH A496;Lo;0;L;;;;;N;;;;; +14628;ANATOLIAN HIEROGLYPH A497;Lo;0;L;;;;;N;;;;; +14629;ANATOLIAN HIEROGLYPH A501;Lo;0;L;;;;;N;;;;; +1462A;ANATOLIAN HIEROGLYPH A502;Lo;0;L;;;;;N;;;;; +1462B;ANATOLIAN HIEROGLYPH A503;Lo;0;L;;;;;N;;;;; +1462C;ANATOLIAN HIEROGLYPH A504;Lo;0;L;;;;;N;;;;; +1462D;ANATOLIAN HIEROGLYPH A505;Lo;0;L;;;;;N;;;;; +1462E;ANATOLIAN HIEROGLYPH A506;Lo;0;L;;;;;N;;;;; +1462F;ANATOLIAN HIEROGLYPH A507;Lo;0;L;;;;;N;;;;; +14630;ANATOLIAN HIEROGLYPH A508;Lo;0;L;;;;;N;;;;; +14631;ANATOLIAN HIEROGLYPH A509;Lo;0;L;;;;;N;;;;; +14632;ANATOLIAN HIEROGLYPH A510;Lo;0;L;;;;;N;;;;; +14633;ANATOLIAN HIEROGLYPH A511;Lo;0;L;;;;;N;;;;; +14634;ANATOLIAN HIEROGLYPH A512;Lo;0;L;;;;;N;;;;; +14635;ANATOLIAN HIEROGLYPH A513;Lo;0;L;;;;;N;;;;; +14636;ANATOLIAN HIEROGLYPH A514;Lo;0;L;;;;;N;;;;; +14637;ANATOLIAN HIEROGLYPH A515;Lo;0;L;;;;;N;;;;; +14638;ANATOLIAN HIEROGLYPH A516;Lo;0;L;;;;;N;;;;; +14639;ANATOLIAN HIEROGLYPH A517;Lo;0;L;;;;;N;;;;; +1463A;ANATOLIAN HIEROGLYPH A518;Lo;0;L;;;;;N;;;;; +1463B;ANATOLIAN HIEROGLYPH A519;Lo;0;L;;;;;N;;;;; +1463C;ANATOLIAN HIEROGLYPH A520;Lo;0;L;;;;;N;;;;; +1463D;ANATOLIAN HIEROGLYPH A521;Lo;0;L;;;;;N;;;;; +1463E;ANATOLIAN HIEROGLYPH A522;Lo;0;L;;;;;N;;;;; +1463F;ANATOLIAN HIEROGLYPH A523;Lo;0;L;;;;;N;;;;; +14640;ANATOLIAN HIEROGLYPH A524;Lo;0;L;;;;;N;;;;; +14641;ANATOLIAN HIEROGLYPH A525;Lo;0;L;;;;;N;;;;; +14642;ANATOLIAN HIEROGLYPH A526;Lo;0;L;;;;;N;;;;; +14643;ANATOLIAN HIEROGLYPH A527;Lo;0;L;;;;;N;;;;; +14644;ANATOLIAN HIEROGLYPH A528;Lo;0;L;;;;;N;;;;; +14645;ANATOLIAN HIEROGLYPH A529;Lo;0;L;;;;;N;;;;; +14646;ANATOLIAN HIEROGLYPH A530;Lo;0;L;;;;;N;;;;; +16100;GURUNG KHEMA LETTER A;Lo;0;L;;;;;N;;;;; +16101;GURUNG KHEMA LETTER KA;Lo;0;L;;;;;N;;;;; +16102;GURUNG KHEMA LETTER KHA;Lo;0;L;;;;;N;;;;; +16103;GURUNG KHEMA LETTER GA;Lo;0;L;;;;;N;;;;; +16104;GURUNG KHEMA LETTER GHA;Lo;0;L;;;;;N;;;;; +16105;GURUNG KHEMA LETTER NGA;Lo;0;L;;;;;N;;;;; +16106;GURUNG KHEMA LETTER CA;Lo;0;L;;;;;N;;;;; +16107;GURUNG KHEMA LETTER CHA;Lo;0;L;;;;;N;;;;; +16108;GURUNG KHEMA LETTER JA;Lo;0;L;;;;;N;;;;; +16109;GURUNG KHEMA LETTER JHA;Lo;0;L;;;;;N;;;;; +1610A;GURUNG KHEMA LETTER HA;Lo;0;L;;;;;N;;;;; +1610B;GURUNG KHEMA LETTER TTA;Lo;0;L;;;;;N;;;;; +1610C;GURUNG KHEMA LETTER TTHA;Lo;0;L;;;;;N;;;;; +1610D;GURUNG KHEMA LETTER DDA;Lo;0;L;;;;;N;;;;; +1610E;GURUNG KHEMA LETTER DDHA;Lo;0;L;;;;;N;;;;; +1610F;GURUNG KHEMA LETTER VA;Lo;0;L;;;;;N;;;;; +16110;GURUNG KHEMA LETTER TA;Lo;0;L;;;;;N;;;;; +16111;GURUNG KHEMA LETTER THA;Lo;0;L;;;;;N;;;;; +16112;GURUNG KHEMA LETTER DA;Lo;0;L;;;;;N;;;;; +16113;GURUNG KHEMA LETTER DHA;Lo;0;L;;;;;N;;;;; +16114;GURUNG KHEMA LETTER NA;Lo;0;L;;;;;N;;;;; +16115;GURUNG KHEMA LETTER PA;Lo;0;L;;;;;N;;;;; +16116;GURUNG KHEMA LETTER PHA;Lo;0;L;;;;;N;;;;; +16117;GURUNG KHEMA LETTER BA;Lo;0;L;;;;;N;;;;; +16118;GURUNG KHEMA LETTER BHA;Lo;0;L;;;;;N;;;;; +16119;GURUNG KHEMA LETTER MA;Lo;0;L;;;;;N;;;;; +1611A;GURUNG KHEMA LETTER YA;Lo;0;L;;;;;N;;;;; +1611B;GURUNG KHEMA LETTER RA;Lo;0;L;;;;;N;;;;; +1611C;GURUNG KHEMA LETTER LA;Lo;0;L;;;;;N;;;;; +1611D;GURUNG KHEMA LETTER SA;Lo;0;L;;;;;N;;;;; +1611E;GURUNG KHEMA VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; +1611F;GURUNG KHEMA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +16120;GURUNG KHEMA VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +16121;GURUNG KHEMA VOWEL SIGN U;Mn;0;NSM;1611E 1611E;;;;N;;;;; +16122;GURUNG KHEMA VOWEL SIGN UU;Mn;0;NSM;1611E 16129;;;;N;;;;; +16123;GURUNG KHEMA VOWEL SIGN E;Mn;0;NSM;1611E 1611F;;;;N;;;;; +16124;GURUNG KHEMA VOWEL SIGN EE;Mn;0;NSM;16129 1611F;;;;N;;;;; +16125;GURUNG KHEMA VOWEL SIGN AI;Mn;0;NSM;1611E 16120;;;;N;;;;; +16126;GURUNG KHEMA VOWEL SIGN O;Mn;0;NSM;16121 1611F;;;;N;;;;; +16127;GURUNG KHEMA VOWEL SIGN OO;Mn;0;NSM;16122 1611F;;;;N;;;;; +16128;GURUNG KHEMA VOWEL SIGN AU;Mn;0;NSM;16121 16120;;;;N;;;;; +16129;GURUNG KHEMA VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;; +1612A;GURUNG KHEMA CONSONANT SIGN MEDIAL YA;Mc;0;L;;;;;N;;;;; +1612B;GURUNG KHEMA CONSONANT SIGN MEDIAL VA;Mc;0;L;;;;;N;;;;; +1612C;GURUNG KHEMA CONSONANT SIGN MEDIAL HA;Mc;0;L;;;;;N;;;;; +1612D;GURUNG KHEMA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +1612E;GURUNG KHEMA CONSONANT SIGN MEDIAL RA;Mn;0;NSM;;;;;N;;;;; +1612F;GURUNG KHEMA SIGN THOLHOMA;Mn;9;NSM;;;;;N;;;;; +16130;GURUNG KHEMA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +16131;GURUNG KHEMA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +16132;GURUNG KHEMA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +16133;GURUNG KHEMA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +16134;GURUNG KHEMA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +16135;GURUNG KHEMA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +16136;GURUNG KHEMA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +16137;GURUNG KHEMA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +16138;GURUNG KHEMA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +16139;GURUNG KHEMA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +16800;BAMUM LETTER PHASE-A NGKUE MFON;Lo;0;L;;;;;N;;;;; +16801;BAMUM LETTER PHASE-A GBIEE FON;Lo;0;L;;;;;N;;;;; +16802;BAMUM LETTER PHASE-A PON MFON PIPAEMGBIEE;Lo;0;L;;;;;N;;;;; +16803;BAMUM LETTER PHASE-A PON MFON PIPAEMBA;Lo;0;L;;;;;N;;;;; +16804;BAMUM LETTER PHASE-A NAA MFON;Lo;0;L;;;;;N;;;;; +16805;BAMUM LETTER PHASE-A SHUENSHUET;Lo;0;L;;;;;N;;;;; +16806;BAMUM LETTER PHASE-A TITA MFON;Lo;0;L;;;;;N;;;;; +16807;BAMUM LETTER PHASE-A NZA MFON;Lo;0;L;;;;;N;;;;; +16808;BAMUM LETTER PHASE-A SHINDA PA NJI;Lo;0;L;;;;;N;;;;; +16809;BAMUM LETTER PHASE-A PON PA NJI PIPAEMGBIEE;Lo;0;L;;;;;N;;;;; +1680A;BAMUM LETTER PHASE-A PON PA NJI PIPAEMBA;Lo;0;L;;;;;N;;;;; +1680B;BAMUM LETTER PHASE-A MAEMBGBIEE;Lo;0;L;;;;;N;;;;; +1680C;BAMUM LETTER PHASE-A TU MAEMBA;Lo;0;L;;;;;N;;;;; +1680D;BAMUM LETTER PHASE-A NGANGU;Lo;0;L;;;;;N;;;;; +1680E;BAMUM LETTER PHASE-A MAEMVEUX;Lo;0;L;;;;;N;;;;; +1680F;BAMUM LETTER PHASE-A MANSUAE;Lo;0;L;;;;;N;;;;; +16810;BAMUM LETTER PHASE-A MVEUAENGAM;Lo;0;L;;;;;N;;;;; +16811;BAMUM LETTER PHASE-A SEUNYAM;Lo;0;L;;;;;N;;;;; +16812;BAMUM LETTER PHASE-A NTOQPEN;Lo;0;L;;;;;N;;;;; +16813;BAMUM LETTER PHASE-A KEUKEUTNDA;Lo;0;L;;;;;N;;;;; +16814;BAMUM LETTER PHASE-A NKINDI;Lo;0;L;;;;;N;;;;; +16815;BAMUM LETTER PHASE-A SUU;Lo;0;L;;;;;N;;;;; +16816;BAMUM LETTER PHASE-A NGKUENZEUM;Lo;0;L;;;;;N;;;;; +16817;BAMUM LETTER PHASE-A LAPAQ;Lo;0;L;;;;;N;;;;; +16818;BAMUM LETTER PHASE-A LET KUT;Lo;0;L;;;;;N;;;;; +16819;BAMUM LETTER PHASE-A NTAP MFAA;Lo;0;L;;;;;N;;;;; +1681A;BAMUM LETTER PHASE-A MAEKEUP;Lo;0;L;;;;;N;;;;; +1681B;BAMUM LETTER PHASE-A PASHAE;Lo;0;L;;;;;N;;;;; +1681C;BAMUM LETTER PHASE-A GHEUAERAE;Lo;0;L;;;;;N;;;;; +1681D;BAMUM LETTER PHASE-A PAMSHAE;Lo;0;L;;;;;N;;;;; +1681E;BAMUM LETTER PHASE-A MON NGGEUAET;Lo;0;L;;;;;N;;;;; +1681F;BAMUM LETTER PHASE-A NZUN MEUT;Lo;0;L;;;;;N;;;;; +16820;BAMUM LETTER PHASE-A U YUQ NAE;Lo;0;L;;;;;N;;;;; +16821;BAMUM LETTER PHASE-A GHEUAEGHEUAE;Lo;0;L;;;;;N;;;;; +16822;BAMUM LETTER PHASE-A NTAP NTAA;Lo;0;L;;;;;N;;;;; +16823;BAMUM LETTER PHASE-A SISA;Lo;0;L;;;;;N;;;;; +16824;BAMUM LETTER PHASE-A MGBASA;Lo;0;L;;;;;N;;;;; +16825;BAMUM LETTER PHASE-A MEUNJOMNDEUQ;Lo;0;L;;;;;N;;;;; +16826;BAMUM LETTER PHASE-A MOOMPUQ;Lo;0;L;;;;;N;;;;; +16827;BAMUM LETTER PHASE-A KAFA;Lo;0;L;;;;;N;;;;; +16828;BAMUM LETTER PHASE-A PA LEERAEWA;Lo;0;L;;;;;N;;;;; +16829;BAMUM LETTER PHASE-A NDA LEERAEWA;Lo;0;L;;;;;N;;;;; +1682A;BAMUM LETTER PHASE-A PET;Lo;0;L;;;;;N;;;;; +1682B;BAMUM LETTER PHASE-A MAEMKPEN;Lo;0;L;;;;;N;;;;; +1682C;BAMUM LETTER PHASE-A NIKA;Lo;0;L;;;;;N;;;;; +1682D;BAMUM LETTER PHASE-A PUP;Lo;0;L;;;;;N;;;;; +1682E;BAMUM LETTER PHASE-A TUAEP;Lo;0;L;;;;;N;;;;; +1682F;BAMUM LETTER PHASE-A LUAEP;Lo;0;L;;;;;N;;;;; +16830;BAMUM LETTER PHASE-A SONJAM;Lo;0;L;;;;;N;;;;; +16831;BAMUM LETTER PHASE-A TEUTEUWEN;Lo;0;L;;;;;N;;;;; +16832;BAMUM LETTER PHASE-A MAENYI;Lo;0;L;;;;;N;;;;; +16833;BAMUM LETTER PHASE-A KET;Lo;0;L;;;;;N;;;;; +16834;BAMUM LETTER PHASE-A NDAANGGEUAET;Lo;0;L;;;;;N;;;;; +16835;BAMUM LETTER PHASE-A KUOQ;Lo;0;L;;;;;N;;;;; +16836;BAMUM LETTER PHASE-A MOOMEUT;Lo;0;L;;;;;N;;;;; +16837;BAMUM LETTER PHASE-A SHUM;Lo;0;L;;;;;N;;;;; +16838;BAMUM LETTER PHASE-A LOMMAE;Lo;0;L;;;;;N;;;;; +16839;BAMUM LETTER PHASE-A FIRI;Lo;0;L;;;;;N;;;;; +1683A;BAMUM LETTER PHASE-A ROM;Lo;0;L;;;;;N;;;;; +1683B;BAMUM LETTER PHASE-A KPOQ;Lo;0;L;;;;;N;;;;; +1683C;BAMUM LETTER PHASE-A SOQ;Lo;0;L;;;;;N;;;;; +1683D;BAMUM LETTER PHASE-A MAP PIEET;Lo;0;L;;;;;N;;;;; +1683E;BAMUM LETTER PHASE-A SHIRAE;Lo;0;L;;;;;N;;;;; +1683F;BAMUM LETTER PHASE-A NTAP;Lo;0;L;;;;;N;;;;; +16840;BAMUM LETTER PHASE-A SHOQ NSHUT YUM;Lo;0;L;;;;;N;;;;; +16841;BAMUM LETTER PHASE-A NYIT MONGKEUAEQ;Lo;0;L;;;;;N;;;;; +16842;BAMUM LETTER PHASE-A PAARAE;Lo;0;L;;;;;N;;;;; +16843;BAMUM LETTER PHASE-A NKAARAE;Lo;0;L;;;;;N;;;;; +16844;BAMUM LETTER PHASE-A UNKNOWN;Lo;0;L;;;;;N;;;;; +16845;BAMUM LETTER PHASE-A NGGEN;Lo;0;L;;;;;N;;;;; +16846;BAMUM LETTER PHASE-A MAESI;Lo;0;L;;;;;N;;;;; +16847;BAMUM LETTER PHASE-A NJAM;Lo;0;L;;;;;N;;;;; +16848;BAMUM LETTER PHASE-A MBANYI;Lo;0;L;;;;;N;;;;; +16849;BAMUM LETTER PHASE-A NYET;Lo;0;L;;;;;N;;;;; +1684A;BAMUM LETTER PHASE-A TEUAEN;Lo;0;L;;;;;N;;;;; +1684B;BAMUM LETTER PHASE-A SOT;Lo;0;L;;;;;N;;;;; +1684C;BAMUM LETTER PHASE-A PAAM;Lo;0;L;;;;;N;;;;; +1684D;BAMUM LETTER PHASE-A NSHIEE;Lo;0;L;;;;;N;;;;; +1684E;BAMUM LETTER PHASE-A MAEM;Lo;0;L;;;;;N;;;;; +1684F;BAMUM LETTER PHASE-A NYI;Lo;0;L;;;;;N;;;;; +16850;BAMUM LETTER PHASE-A KAQ;Lo;0;L;;;;;N;;;;; +16851;BAMUM LETTER PHASE-A NSHA;Lo;0;L;;;;;N;;;;; +16852;BAMUM LETTER PHASE-A VEE;Lo;0;L;;;;;N;;;;; +16853;BAMUM LETTER PHASE-A LU;Lo;0;L;;;;;N;;;;; +16854;BAMUM LETTER PHASE-A NEN;Lo;0;L;;;;;N;;;;; +16855;BAMUM LETTER PHASE-A NAQ;Lo;0;L;;;;;N;;;;; +16856;BAMUM LETTER PHASE-A MBAQ;Lo;0;L;;;;;N;;;;; +16857;BAMUM LETTER PHASE-B NSHUET;Lo;0;L;;;;;N;;;;; +16858;BAMUM LETTER PHASE-B TU MAEMGBIEE;Lo;0;L;;;;;N;;;;; +16859;BAMUM LETTER PHASE-B SIEE;Lo;0;L;;;;;N;;;;; +1685A;BAMUM LETTER PHASE-B SET TU;Lo;0;L;;;;;N;;;;; +1685B;BAMUM LETTER PHASE-B LOM NTEUM;Lo;0;L;;;;;N;;;;; +1685C;BAMUM LETTER PHASE-B MBA MAELEE;Lo;0;L;;;;;N;;;;; +1685D;BAMUM LETTER PHASE-B KIEEM;Lo;0;L;;;;;N;;;;; +1685E;BAMUM LETTER PHASE-B YEURAE;Lo;0;L;;;;;N;;;;; +1685F;BAMUM LETTER PHASE-B MBAARAE;Lo;0;L;;;;;N;;;;; +16860;BAMUM LETTER PHASE-B KAM;Lo;0;L;;;;;N;;;;; +16861;BAMUM LETTER PHASE-B PEESHI;Lo;0;L;;;;;N;;;;; +16862;BAMUM LETTER PHASE-B YAFU LEERAEWA;Lo;0;L;;;;;N;;;;; +16863;BAMUM LETTER PHASE-B LAM NSHUT NYAM;Lo;0;L;;;;;N;;;;; +16864;BAMUM LETTER PHASE-B NTIEE SHEUOQ;Lo;0;L;;;;;N;;;;; +16865;BAMUM LETTER PHASE-B NDU NJAA;Lo;0;L;;;;;N;;;;; +16866;BAMUM LETTER PHASE-B GHEUGHEUAEM;Lo;0;L;;;;;N;;;;; +16867;BAMUM LETTER PHASE-B PIT;Lo;0;L;;;;;N;;;;; +16868;BAMUM LETTER PHASE-B TU NSIEE;Lo;0;L;;;;;N;;;;; +16869;BAMUM LETTER PHASE-B SHET NJAQ;Lo;0;L;;;;;N;;;;; +1686A;BAMUM LETTER PHASE-B SHEUAEQTU;Lo;0;L;;;;;N;;;;; +1686B;BAMUM LETTER PHASE-B MFON TEUAEQ;Lo;0;L;;;;;N;;;;; +1686C;BAMUM LETTER PHASE-B MBIT MBAAKET;Lo;0;L;;;;;N;;;;; +1686D;BAMUM LETTER PHASE-B NYI NTEUM;Lo;0;L;;;;;N;;;;; +1686E;BAMUM LETTER PHASE-B KEUPUQ;Lo;0;L;;;;;N;;;;; +1686F;BAMUM LETTER PHASE-B GHEUGHEN;Lo;0;L;;;;;N;;;;; +16870;BAMUM LETTER PHASE-B KEUYEUX;Lo;0;L;;;;;N;;;;; +16871;BAMUM LETTER PHASE-B LAANAE;Lo;0;L;;;;;N;;;;; +16872;BAMUM LETTER PHASE-B PARUM;Lo;0;L;;;;;N;;;;; +16873;BAMUM LETTER PHASE-B VEUM;Lo;0;L;;;;;N;;;;; +16874;BAMUM LETTER PHASE-B NGKINDI MVOP;Lo;0;L;;;;;N;;;;; +16875;BAMUM LETTER PHASE-B NGGEU MBU;Lo;0;L;;;;;N;;;;; +16876;BAMUM LETTER PHASE-B WUAET;Lo;0;L;;;;;N;;;;; +16877;BAMUM LETTER PHASE-B SAKEUAE;Lo;0;L;;;;;N;;;;; +16878;BAMUM LETTER PHASE-B TAAM;Lo;0;L;;;;;N;;;;; +16879;BAMUM LETTER PHASE-B MEUQ;Lo;0;L;;;;;N;;;;; +1687A;BAMUM LETTER PHASE-B NGGUOQ;Lo;0;L;;;;;N;;;;; +1687B;BAMUM LETTER PHASE-B NGGUOQ LARGE;Lo;0;L;;;;;N;;;;; +1687C;BAMUM LETTER PHASE-B MFIYAQ;Lo;0;L;;;;;N;;;;; +1687D;BAMUM LETTER PHASE-B SUE;Lo;0;L;;;;;N;;;;; +1687E;BAMUM LETTER PHASE-B MBEURI;Lo;0;L;;;;;N;;;;; +1687F;BAMUM LETTER PHASE-B MONTIEEN;Lo;0;L;;;;;N;;;;; +16880;BAMUM LETTER PHASE-B NYAEMAE;Lo;0;L;;;;;N;;;;; +16881;BAMUM LETTER PHASE-B PUNGAAM;Lo;0;L;;;;;N;;;;; +16882;BAMUM LETTER PHASE-B MEUT NGGEET;Lo;0;L;;;;;N;;;;; +16883;BAMUM LETTER PHASE-B FEUX;Lo;0;L;;;;;N;;;;; +16884;BAMUM LETTER PHASE-B MBUOQ;Lo;0;L;;;;;N;;;;; +16885;BAMUM LETTER PHASE-B FEE;Lo;0;L;;;;;N;;;;; +16886;BAMUM LETTER PHASE-B KEUAEM;Lo;0;L;;;;;N;;;;; +16887;BAMUM LETTER PHASE-B MA NJEUAENA;Lo;0;L;;;;;N;;;;; +16888;BAMUM LETTER PHASE-B MA NJUQA;Lo;0;L;;;;;N;;;;; +16889;BAMUM LETTER PHASE-B LET;Lo;0;L;;;;;N;;;;; +1688A;BAMUM LETTER PHASE-B NGGAAM;Lo;0;L;;;;;N;;;;; +1688B;BAMUM LETTER PHASE-B NSEN;Lo;0;L;;;;;N;;;;; +1688C;BAMUM LETTER PHASE-B MA;Lo;0;L;;;;;N;;;;; +1688D;BAMUM LETTER PHASE-B KIQ;Lo;0;L;;;;;N;;;;; +1688E;BAMUM LETTER PHASE-B NGOM;Lo;0;L;;;;;N;;;;; +1688F;BAMUM LETTER PHASE-C NGKUE MAEMBA;Lo;0;L;;;;;N;;;;; +16890;BAMUM LETTER PHASE-C NZA;Lo;0;L;;;;;N;;;;; +16891;BAMUM LETTER PHASE-C YUM;Lo;0;L;;;;;N;;;;; +16892;BAMUM LETTER PHASE-C WANGKUOQ;Lo;0;L;;;;;N;;;;; +16893;BAMUM LETTER PHASE-C NGGEN;Lo;0;L;;;;;N;;;;; +16894;BAMUM LETTER PHASE-C NDEUAEREE;Lo;0;L;;;;;N;;;;; +16895;BAMUM LETTER PHASE-C NGKAQ;Lo;0;L;;;;;N;;;;; +16896;BAMUM LETTER PHASE-C GHARAE;Lo;0;L;;;;;N;;;;; +16897;BAMUM LETTER PHASE-C MBEEKEET;Lo;0;L;;;;;N;;;;; +16898;BAMUM LETTER PHASE-C GBAYI;Lo;0;L;;;;;N;;;;; +16899;BAMUM LETTER PHASE-C NYIR MKPARAQ MEUN;Lo;0;L;;;;;N;;;;; +1689A;BAMUM LETTER PHASE-C NTU MBIT;Lo;0;L;;;;;N;;;;; +1689B;BAMUM LETTER PHASE-C MBEUM;Lo;0;L;;;;;N;;;;; +1689C;BAMUM LETTER PHASE-C PIRIEEN;Lo;0;L;;;;;N;;;;; +1689D;BAMUM LETTER PHASE-C NDOMBU;Lo;0;L;;;;;N;;;;; +1689E;BAMUM LETTER PHASE-C MBAA CABBAGE-TREE;Lo;0;L;;;;;N;;;;; +1689F;BAMUM LETTER PHASE-C KEUSHEUAEP;Lo;0;L;;;;;N;;;;; +168A0;BAMUM LETTER PHASE-C GHAP;Lo;0;L;;;;;N;;;;; +168A1;BAMUM LETTER PHASE-C KEUKAQ;Lo;0;L;;;;;N;;;;; +168A2;BAMUM LETTER PHASE-C YU MUOMAE;Lo;0;L;;;;;N;;;;; +168A3;BAMUM LETTER PHASE-C NZEUM;Lo;0;L;;;;;N;;;;; +168A4;BAMUM LETTER PHASE-C MBUE;Lo;0;L;;;;;N;;;;; +168A5;BAMUM LETTER PHASE-C NSEUAEN;Lo;0;L;;;;;N;;;;; +168A6;BAMUM LETTER PHASE-C MBIT;Lo;0;L;;;;;N;;;;; +168A7;BAMUM LETTER PHASE-C YEUQ;Lo;0;L;;;;;N;;;;; +168A8;BAMUM LETTER PHASE-C KPARAQ;Lo;0;L;;;;;N;;;;; +168A9;BAMUM LETTER PHASE-C KAA;Lo;0;L;;;;;N;;;;; +168AA;BAMUM LETTER PHASE-C SEUX;Lo;0;L;;;;;N;;;;; +168AB;BAMUM LETTER PHASE-C NDIDA;Lo;0;L;;;;;N;;;;; +168AC;BAMUM LETTER PHASE-C TAASHAE;Lo;0;L;;;;;N;;;;; +168AD;BAMUM LETTER PHASE-C NJUEQ;Lo;0;L;;;;;N;;;;; +168AE;BAMUM LETTER PHASE-C TITA YUE;Lo;0;L;;;;;N;;;;; +168AF;BAMUM LETTER PHASE-C SUAET;Lo;0;L;;;;;N;;;;; +168B0;BAMUM LETTER PHASE-C NGGUAEN NYAM;Lo;0;L;;;;;N;;;;; +168B1;BAMUM LETTER PHASE-C VEUX;Lo;0;L;;;;;N;;;;; +168B2;BAMUM LETTER PHASE-C NANSANAQ;Lo;0;L;;;;;N;;;;; +168B3;BAMUM LETTER PHASE-C MA KEUAERI;Lo;0;L;;;;;N;;;;; +168B4;BAMUM LETTER PHASE-C NTAA;Lo;0;L;;;;;N;;;;; +168B5;BAMUM LETTER PHASE-C NGGUON;Lo;0;L;;;;;N;;;;; +168B6;BAMUM LETTER PHASE-C LAP;Lo;0;L;;;;;N;;;;; +168B7;BAMUM LETTER PHASE-C MBIRIEEN;Lo;0;L;;;;;N;;;;; +168B8;BAMUM LETTER PHASE-C MGBASAQ;Lo;0;L;;;;;N;;;;; +168B9;BAMUM LETTER PHASE-C NTEUNGBA;Lo;0;L;;;;;N;;;;; +168BA;BAMUM LETTER PHASE-C TEUTEUX;Lo;0;L;;;;;N;;;;; +168BB;BAMUM LETTER PHASE-C NGGUM;Lo;0;L;;;;;N;;;;; +168BC;BAMUM LETTER PHASE-C FUE;Lo;0;L;;;;;N;;;;; +168BD;BAMUM LETTER PHASE-C NDEUT;Lo;0;L;;;;;N;;;;; +168BE;BAMUM LETTER PHASE-C NSA;Lo;0;L;;;;;N;;;;; +168BF;BAMUM LETTER PHASE-C NSHAQ;Lo;0;L;;;;;N;;;;; +168C0;BAMUM LETTER PHASE-C BUNG;Lo;0;L;;;;;N;;;;; +168C1;BAMUM LETTER PHASE-C VEUAEPEN;Lo;0;L;;;;;N;;;;; +168C2;BAMUM LETTER PHASE-C MBERAE;Lo;0;L;;;;;N;;;;; +168C3;BAMUM LETTER PHASE-C RU;Lo;0;L;;;;;N;;;;; +168C4;BAMUM LETTER PHASE-C NJAEM;Lo;0;L;;;;;N;;;;; +168C5;BAMUM LETTER PHASE-C LAM;Lo;0;L;;;;;N;;;;; +168C6;BAMUM LETTER PHASE-C TITUAEP;Lo;0;L;;;;;N;;;;; +168C7;BAMUM LETTER PHASE-C NSUOT NGOM;Lo;0;L;;;;;N;;;;; +168C8;BAMUM LETTER PHASE-C NJEEEE;Lo;0;L;;;;;N;;;;; +168C9;BAMUM LETTER PHASE-C KET;Lo;0;L;;;;;N;;;;; +168CA;BAMUM LETTER PHASE-C NGGU;Lo;0;L;;;;;N;;;;; +168CB;BAMUM LETTER PHASE-C MAESI;Lo;0;L;;;;;N;;;;; +168CC;BAMUM LETTER PHASE-C MBUAEM;Lo;0;L;;;;;N;;;;; +168CD;BAMUM LETTER PHASE-C LU;Lo;0;L;;;;;N;;;;; +168CE;BAMUM LETTER PHASE-C KUT;Lo;0;L;;;;;N;;;;; +168CF;BAMUM LETTER PHASE-C NJAM;Lo;0;L;;;;;N;;;;; +168D0;BAMUM LETTER PHASE-C NGOM;Lo;0;L;;;;;N;;;;; +168D1;BAMUM LETTER PHASE-C WUP;Lo;0;L;;;;;N;;;;; +168D2;BAMUM LETTER PHASE-C NGGUEET;Lo;0;L;;;;;N;;;;; +168D3;BAMUM LETTER PHASE-C NSOM;Lo;0;L;;;;;N;;;;; +168D4;BAMUM LETTER PHASE-C NTEN;Lo;0;L;;;;;N;;;;; +168D5;BAMUM LETTER PHASE-C KUOP NKAARAE;Lo;0;L;;;;;N;;;;; +168D6;BAMUM LETTER PHASE-C NSUN;Lo;0;L;;;;;N;;;;; +168D7;BAMUM LETTER PHASE-C NDAM;Lo;0;L;;;;;N;;;;; +168D8;BAMUM LETTER PHASE-C MA NSIEE;Lo;0;L;;;;;N;;;;; +168D9;BAMUM LETTER PHASE-C YAA;Lo;0;L;;;;;N;;;;; +168DA;BAMUM LETTER PHASE-C NDAP;Lo;0;L;;;;;N;;;;; +168DB;BAMUM LETTER PHASE-C SHUEQ;Lo;0;L;;;;;N;;;;; +168DC;BAMUM LETTER PHASE-C SETFON;Lo;0;L;;;;;N;;;;; +168DD;BAMUM LETTER PHASE-C MBI;Lo;0;L;;;;;N;;;;; +168DE;BAMUM LETTER PHASE-C MAEMBA;Lo;0;L;;;;;N;;;;; +168DF;BAMUM LETTER PHASE-C MBANYI;Lo;0;L;;;;;N;;;;; +168E0;BAMUM LETTER PHASE-C KEUSEUX;Lo;0;L;;;;;N;;;;; +168E1;BAMUM LETTER PHASE-C MBEUX;Lo;0;L;;;;;N;;;;; +168E2;BAMUM LETTER PHASE-C KEUM;Lo;0;L;;;;;N;;;;; +168E3;BAMUM LETTER PHASE-C MBAA PICKET;Lo;0;L;;;;;N;;;;; +168E4;BAMUM LETTER PHASE-C YUWOQ;Lo;0;L;;;;;N;;;;; +168E5;BAMUM LETTER PHASE-C NJEUX;Lo;0;L;;;;;N;;;;; +168E6;BAMUM LETTER PHASE-C MIEE;Lo;0;L;;;;;N;;;;; +168E7;BAMUM LETTER PHASE-C MUAE;Lo;0;L;;;;;N;;;;; +168E8;BAMUM LETTER PHASE-C SHIQ;Lo;0;L;;;;;N;;;;; +168E9;BAMUM LETTER PHASE-C KEN LAW;Lo;0;L;;;;;N;;;;; +168EA;BAMUM LETTER PHASE-C KEN FATIGUE;Lo;0;L;;;;;N;;;;; +168EB;BAMUM LETTER PHASE-C NGAQ;Lo;0;L;;;;;N;;;;; +168EC;BAMUM LETTER PHASE-C NAQ;Lo;0;L;;;;;N;;;;; +168ED;BAMUM LETTER PHASE-C LIQ;Lo;0;L;;;;;N;;;;; +168EE;BAMUM LETTER PHASE-C PIN;Lo;0;L;;;;;N;;;;; +168EF;BAMUM LETTER PHASE-C PEN;Lo;0;L;;;;;N;;;;; +168F0;BAMUM LETTER PHASE-C TET;Lo;0;L;;;;;N;;;;; +168F1;BAMUM LETTER PHASE-D MBUO;Lo;0;L;;;;;N;;;;; +168F2;BAMUM LETTER PHASE-D WAP;Lo;0;L;;;;;N;;;;; +168F3;BAMUM LETTER PHASE-D NJI;Lo;0;L;;;;;N;;;;; +168F4;BAMUM LETTER PHASE-D MFON;Lo;0;L;;;;;N;;;;; +168F5;BAMUM LETTER PHASE-D NJIEE;Lo;0;L;;;;;N;;;;; +168F6;BAMUM LETTER PHASE-D LIEE;Lo;0;L;;;;;N;;;;; +168F7;BAMUM LETTER PHASE-D NJEUT;Lo;0;L;;;;;N;;;;; +168F8;BAMUM LETTER PHASE-D NSHEE;Lo;0;L;;;;;N;;;;; +168F9;BAMUM LETTER PHASE-D NGGAAMAE;Lo;0;L;;;;;N;;;;; +168FA;BAMUM LETTER PHASE-D NYAM;Lo;0;L;;;;;N;;;;; +168FB;BAMUM LETTER PHASE-D WUAEN;Lo;0;L;;;;;N;;;;; +168FC;BAMUM LETTER PHASE-D NGKUN;Lo;0;L;;;;;N;;;;; +168FD;BAMUM LETTER PHASE-D SHEE;Lo;0;L;;;;;N;;;;; +168FE;BAMUM LETTER PHASE-D NGKAP;Lo;0;L;;;;;N;;;;; +168FF;BAMUM LETTER PHASE-D KEUAETMEUN;Lo;0;L;;;;;N;;;;; +16900;BAMUM LETTER PHASE-D TEUT;Lo;0;L;;;;;N;;;;; +16901;BAMUM LETTER PHASE-D SHEUAE;Lo;0;L;;;;;N;;;;; +16902;BAMUM LETTER PHASE-D NJAP;Lo;0;L;;;;;N;;;;; +16903;BAMUM LETTER PHASE-D SUE;Lo;0;L;;;;;N;;;;; +16904;BAMUM LETTER PHASE-D KET;Lo;0;L;;;;;N;;;;; +16905;BAMUM LETTER PHASE-D YAEMMAE;Lo;0;L;;;;;N;;;;; +16906;BAMUM LETTER PHASE-D KUOM;Lo;0;L;;;;;N;;;;; +16907;BAMUM LETTER PHASE-D SAP;Lo;0;L;;;;;N;;;;; +16908;BAMUM LETTER PHASE-D MFEUT;Lo;0;L;;;;;N;;;;; +16909;BAMUM LETTER PHASE-D NDEUX;Lo;0;L;;;;;N;;;;; +1690A;BAMUM LETTER PHASE-D MALEERI;Lo;0;L;;;;;N;;;;; +1690B;BAMUM LETTER PHASE-D MEUT;Lo;0;L;;;;;N;;;;; +1690C;BAMUM LETTER PHASE-D SEUAEQ;Lo;0;L;;;;;N;;;;; +1690D;BAMUM LETTER PHASE-D YEN;Lo;0;L;;;;;N;;;;; +1690E;BAMUM LETTER PHASE-D NJEUAEM;Lo;0;L;;;;;N;;;;; +1690F;BAMUM LETTER PHASE-D KEUOT MBUAE;Lo;0;L;;;;;N;;;;; +16910;BAMUM LETTER PHASE-D NGKEURI;Lo;0;L;;;;;N;;;;; +16911;BAMUM LETTER PHASE-D TU;Lo;0;L;;;;;N;;;;; +16912;BAMUM LETTER PHASE-D GHAA;Lo;0;L;;;;;N;;;;; +16913;BAMUM LETTER PHASE-D NGKYEE;Lo;0;L;;;;;N;;;;; +16914;BAMUM LETTER PHASE-D FEUFEUAET;Lo;0;L;;;;;N;;;;; +16915;BAMUM LETTER PHASE-D NDEE;Lo;0;L;;;;;N;;;;; +16916;BAMUM LETTER PHASE-D MGBOFUM;Lo;0;L;;;;;N;;;;; +16917;BAMUM LETTER PHASE-D LEUAEP;Lo;0;L;;;;;N;;;;; +16918;BAMUM LETTER PHASE-D NDON;Lo;0;L;;;;;N;;;;; +16919;BAMUM LETTER PHASE-D MONI;Lo;0;L;;;;;N;;;;; +1691A;BAMUM LETTER PHASE-D MGBEUN;Lo;0;L;;;;;N;;;;; +1691B;BAMUM LETTER PHASE-D PUUT;Lo;0;L;;;;;N;;;;; +1691C;BAMUM LETTER PHASE-D MGBIEE;Lo;0;L;;;;;N;;;;; +1691D;BAMUM LETTER PHASE-D MFO;Lo;0;L;;;;;N;;;;; +1691E;BAMUM LETTER PHASE-D LUM;Lo;0;L;;;;;N;;;;; +1691F;BAMUM LETTER PHASE-D NSIEEP;Lo;0;L;;;;;N;;;;; +16920;BAMUM LETTER PHASE-D MBAA;Lo;0;L;;;;;N;;;;; +16921;BAMUM LETTER PHASE-D KWAET;Lo;0;L;;;;;N;;;;; +16922;BAMUM LETTER PHASE-D NYET;Lo;0;L;;;;;N;;;;; +16923;BAMUM LETTER PHASE-D TEUAEN;Lo;0;L;;;;;N;;;;; +16924;BAMUM LETTER PHASE-D SOT;Lo;0;L;;;;;N;;;;; +16925;BAMUM LETTER PHASE-D YUWOQ;Lo;0;L;;;;;N;;;;; +16926;BAMUM LETTER PHASE-D KEUM;Lo;0;L;;;;;N;;;;; +16927;BAMUM LETTER PHASE-D RAEM;Lo;0;L;;;;;N;;;;; +16928;BAMUM LETTER PHASE-D TEEEE;Lo;0;L;;;;;N;;;;; +16929;BAMUM LETTER PHASE-D NGKEUAEQ;Lo;0;L;;;;;N;;;;; +1692A;BAMUM LETTER PHASE-D MFEUAE;Lo;0;L;;;;;N;;;;; +1692B;BAMUM LETTER PHASE-D NSIEET;Lo;0;L;;;;;N;;;;; +1692C;BAMUM LETTER PHASE-D KEUP;Lo;0;L;;;;;N;;;;; +1692D;BAMUM LETTER PHASE-D PIP;Lo;0;L;;;;;N;;;;; +1692E;BAMUM LETTER PHASE-D PEUTAE;Lo;0;L;;;;;N;;;;; +1692F;BAMUM LETTER PHASE-D NYUE;Lo;0;L;;;;;N;;;;; +16930;BAMUM LETTER PHASE-D LET;Lo;0;L;;;;;N;;;;; +16931;BAMUM LETTER PHASE-D NGGAAM;Lo;0;L;;;;;N;;;;; +16932;BAMUM LETTER PHASE-D MFIEE;Lo;0;L;;;;;N;;;;; +16933;BAMUM LETTER PHASE-D NGGWAEN;Lo;0;L;;;;;N;;;;; +16934;BAMUM LETTER PHASE-D YUOM;Lo;0;L;;;;;N;;;;; +16935;BAMUM LETTER PHASE-D PAP;Lo;0;L;;;;;N;;;;; +16936;BAMUM LETTER PHASE-D YUOP;Lo;0;L;;;;;N;;;;; +16937;BAMUM LETTER PHASE-D NDAM;Lo;0;L;;;;;N;;;;; +16938;BAMUM LETTER PHASE-D NTEUM;Lo;0;L;;;;;N;;;;; +16939;BAMUM LETTER PHASE-D SUAE;Lo;0;L;;;;;N;;;;; +1693A;BAMUM LETTER PHASE-D KUN;Lo;0;L;;;;;N;;;;; +1693B;BAMUM LETTER PHASE-D NGGEUX;Lo;0;L;;;;;N;;;;; +1693C;BAMUM LETTER PHASE-D NGKIEE;Lo;0;L;;;;;N;;;;; +1693D;BAMUM LETTER PHASE-D TUOT;Lo;0;L;;;;;N;;;;; +1693E;BAMUM LETTER PHASE-D MEUN;Lo;0;L;;;;;N;;;;; +1693F;BAMUM LETTER PHASE-D KUQ;Lo;0;L;;;;;N;;;;; +16940;BAMUM LETTER PHASE-D NSUM;Lo;0;L;;;;;N;;;;; +16941;BAMUM LETTER PHASE-D TEUN;Lo;0;L;;;;;N;;;;; +16942;BAMUM LETTER PHASE-D MAENJET;Lo;0;L;;;;;N;;;;; +16943;BAMUM LETTER PHASE-D NGGAP;Lo;0;L;;;;;N;;;;; +16944;BAMUM LETTER PHASE-D LEUM;Lo;0;L;;;;;N;;;;; +16945;BAMUM LETTER PHASE-D NGGUOM;Lo;0;L;;;;;N;;;;; +16946;BAMUM LETTER PHASE-D NSHUT;Lo;0;L;;;;;N;;;;; +16947;BAMUM LETTER PHASE-D NJUEQ;Lo;0;L;;;;;N;;;;; +16948;BAMUM LETTER PHASE-D GHEUAE;Lo;0;L;;;;;N;;;;; +16949;BAMUM LETTER PHASE-D KU;Lo;0;L;;;;;N;;;;; +1694A;BAMUM LETTER PHASE-D REN OLD;Lo;0;L;;;;;N;;;;; +1694B;BAMUM LETTER PHASE-D TAE;Lo;0;L;;;;;N;;;;; +1694C;BAMUM LETTER PHASE-D TOQ;Lo;0;L;;;;;N;;;;; +1694D;BAMUM LETTER PHASE-D NYI;Lo;0;L;;;;;N;;;;; +1694E;BAMUM LETTER PHASE-D RII;Lo;0;L;;;;;N;;;;; +1694F;BAMUM LETTER PHASE-D LEEEE;Lo;0;L;;;;;N;;;;; +16950;BAMUM LETTER PHASE-D MEEEE;Lo;0;L;;;;;N;;;;; +16951;BAMUM LETTER PHASE-D M;Lo;0;L;;;;;N;;;;; +16952;BAMUM LETTER PHASE-D SUU;Lo;0;L;;;;;N;;;;; +16953;BAMUM LETTER PHASE-D MU;Lo;0;L;;;;;N;;;;; +16954;BAMUM LETTER PHASE-D SHII;Lo;0;L;;;;;N;;;;; +16955;BAMUM LETTER PHASE-D SHEUX;Lo;0;L;;;;;N;;;;; +16956;BAMUM LETTER PHASE-D KYEE;Lo;0;L;;;;;N;;;;; +16957;BAMUM LETTER PHASE-D NU;Lo;0;L;;;;;N;;;;; +16958;BAMUM LETTER PHASE-D SHU;Lo;0;L;;;;;N;;;;; +16959;BAMUM LETTER PHASE-D NTEE;Lo;0;L;;;;;N;;;;; +1695A;BAMUM LETTER PHASE-D PEE;Lo;0;L;;;;;N;;;;; +1695B;BAMUM LETTER PHASE-D NI;Lo;0;L;;;;;N;;;;; +1695C;BAMUM LETTER PHASE-D SHOQ;Lo;0;L;;;;;N;;;;; +1695D;BAMUM LETTER PHASE-D PUQ;Lo;0;L;;;;;N;;;;; +1695E;BAMUM LETTER PHASE-D MVOP;Lo;0;L;;;;;N;;;;; +1695F;BAMUM LETTER PHASE-D LOQ;Lo;0;L;;;;;N;;;;; +16960;BAMUM LETTER PHASE-D REN MUCH;Lo;0;L;;;;;N;;;;; +16961;BAMUM LETTER PHASE-D TI;Lo;0;L;;;;;N;;;;; +16962;BAMUM LETTER PHASE-D NTUU;Lo;0;L;;;;;N;;;;; +16963;BAMUM LETTER PHASE-D MBAA SEVEN;Lo;0;L;;;;;N;;;;; +16964;BAMUM LETTER PHASE-D SAQ;Lo;0;L;;;;;N;;;;; +16965;BAMUM LETTER PHASE-D FAA;Lo;0;L;;;;;N;;;;; +16966;BAMUM LETTER PHASE-E NDAP;Lo;0;L;;;;;N;;;;; +16967;BAMUM LETTER PHASE-E TOON;Lo;0;L;;;;;N;;;;; +16968;BAMUM LETTER PHASE-E MBEUM;Lo;0;L;;;;;N;;;;; +16969;BAMUM LETTER PHASE-E LAP;Lo;0;L;;;;;N;;;;; +1696A;BAMUM LETTER PHASE-E VOM;Lo;0;L;;;;;N;;;;; +1696B;BAMUM LETTER PHASE-E LOON;Lo;0;L;;;;;N;;;;; +1696C;BAMUM LETTER PHASE-E PAA;Lo;0;L;;;;;N;;;;; +1696D;BAMUM LETTER PHASE-E SOM;Lo;0;L;;;;;N;;;;; +1696E;BAMUM LETTER PHASE-E RAQ;Lo;0;L;;;;;N;;;;; +1696F;BAMUM LETTER PHASE-E NSHUOP;Lo;0;L;;;;;N;;;;; +16970;BAMUM LETTER PHASE-E NDUN;Lo;0;L;;;;;N;;;;; +16971;BAMUM LETTER PHASE-E PUAE;Lo;0;L;;;;;N;;;;; +16972;BAMUM LETTER PHASE-E TAM;Lo;0;L;;;;;N;;;;; +16973;BAMUM LETTER PHASE-E NGKA;Lo;0;L;;;;;N;;;;; +16974;BAMUM LETTER PHASE-E KPEUX;Lo;0;L;;;;;N;;;;; +16975;BAMUM LETTER PHASE-E WUO;Lo;0;L;;;;;N;;;;; +16976;BAMUM LETTER PHASE-E SEE;Lo;0;L;;;;;N;;;;; +16977;BAMUM LETTER PHASE-E NGGEUAET;Lo;0;L;;;;;N;;;;; +16978;BAMUM LETTER PHASE-E PAAM;Lo;0;L;;;;;N;;;;; +16979;BAMUM LETTER PHASE-E TOO;Lo;0;L;;;;;N;;;;; +1697A;BAMUM LETTER PHASE-E KUOP;Lo;0;L;;;;;N;;;;; +1697B;BAMUM LETTER PHASE-E LOM;Lo;0;L;;;;;N;;;;; +1697C;BAMUM LETTER PHASE-E NSHIEE;Lo;0;L;;;;;N;;;;; +1697D;BAMUM LETTER PHASE-E NGOP;Lo;0;L;;;;;N;;;;; +1697E;BAMUM LETTER PHASE-E MAEM;Lo;0;L;;;;;N;;;;; +1697F;BAMUM LETTER PHASE-E NGKEUX;Lo;0;L;;;;;N;;;;; +16980;BAMUM LETTER PHASE-E NGOQ;Lo;0;L;;;;;N;;;;; +16981;BAMUM LETTER PHASE-E NSHUE;Lo;0;L;;;;;N;;;;; +16982;BAMUM LETTER PHASE-E RIMGBA;Lo;0;L;;;;;N;;;;; +16983;BAMUM LETTER PHASE-E NJEUX;Lo;0;L;;;;;N;;;;; +16984;BAMUM LETTER PHASE-E PEEM;Lo;0;L;;;;;N;;;;; +16985;BAMUM LETTER PHASE-E SAA;Lo;0;L;;;;;N;;;;; +16986;BAMUM LETTER PHASE-E NGGURAE;Lo;0;L;;;;;N;;;;; +16987;BAMUM LETTER PHASE-E MGBA;Lo;0;L;;;;;N;;;;; +16988;BAMUM LETTER PHASE-E GHEUX;Lo;0;L;;;;;N;;;;; +16989;BAMUM LETTER PHASE-E NGKEUAEM;Lo;0;L;;;;;N;;;;; +1698A;BAMUM LETTER PHASE-E NJAEMLI;Lo;0;L;;;;;N;;;;; +1698B;BAMUM LETTER PHASE-E MAP;Lo;0;L;;;;;N;;;;; +1698C;BAMUM LETTER PHASE-E LOOT;Lo;0;L;;;;;N;;;;; +1698D;BAMUM LETTER PHASE-E NGGEEEE;Lo;0;L;;;;;N;;;;; +1698E;BAMUM LETTER PHASE-E NDIQ;Lo;0;L;;;;;N;;;;; +1698F;BAMUM LETTER PHASE-E TAEN NTEUM;Lo;0;L;;;;;N;;;;; +16990;BAMUM LETTER PHASE-E SET;Lo;0;L;;;;;N;;;;; +16991;BAMUM LETTER PHASE-E PUM;Lo;0;L;;;;;N;;;;; +16992;BAMUM LETTER PHASE-E NDAA SOFTNESS;Lo;0;L;;;;;N;;;;; +16993;BAMUM LETTER PHASE-E NGGUAESHAE NYAM;Lo;0;L;;;;;N;;;;; +16994;BAMUM LETTER PHASE-E YIEE;Lo;0;L;;;;;N;;;;; +16995;BAMUM LETTER PHASE-E GHEUN;Lo;0;L;;;;;N;;;;; +16996;BAMUM LETTER PHASE-E TUAE;Lo;0;L;;;;;N;;;;; +16997;BAMUM LETTER PHASE-E YEUAE;Lo;0;L;;;;;N;;;;; +16998;BAMUM LETTER PHASE-E PO;Lo;0;L;;;;;N;;;;; +16999;BAMUM LETTER PHASE-E TUMAE;Lo;0;L;;;;;N;;;;; +1699A;BAMUM LETTER PHASE-E KEUAE;Lo;0;L;;;;;N;;;;; +1699B;BAMUM LETTER PHASE-E SUAEN;Lo;0;L;;;;;N;;;;; +1699C;BAMUM LETTER PHASE-E TEUAEQ;Lo;0;L;;;;;N;;;;; +1699D;BAMUM LETTER PHASE-E VEUAE;Lo;0;L;;;;;N;;;;; +1699E;BAMUM LETTER PHASE-E WEUX;Lo;0;L;;;;;N;;;;; +1699F;BAMUM LETTER PHASE-E LAAM;Lo;0;L;;;;;N;;;;; +169A0;BAMUM LETTER PHASE-E PU;Lo;0;L;;;;;N;;;;; +169A1;BAMUM LETTER PHASE-E TAAQ;Lo;0;L;;;;;N;;;;; +169A2;BAMUM LETTER PHASE-E GHAAMAE;Lo;0;L;;;;;N;;;;; +169A3;BAMUM LETTER PHASE-E NGEUREUT;Lo;0;L;;;;;N;;;;; +169A4;BAMUM LETTER PHASE-E SHEUAEQ;Lo;0;L;;;;;N;;;;; +169A5;BAMUM LETTER PHASE-E MGBEN;Lo;0;L;;;;;N;;;;; +169A6;BAMUM LETTER PHASE-E MBEE;Lo;0;L;;;;;N;;;;; +169A7;BAMUM LETTER PHASE-E NZAQ;Lo;0;L;;;;;N;;;;; +169A8;BAMUM LETTER PHASE-E NKOM;Lo;0;L;;;;;N;;;;; +169A9;BAMUM LETTER PHASE-E GBET;Lo;0;L;;;;;N;;;;; +169AA;BAMUM LETTER PHASE-E TUM;Lo;0;L;;;;;N;;;;; +169AB;BAMUM LETTER PHASE-E KUET;Lo;0;L;;;;;N;;;;; +169AC;BAMUM LETTER PHASE-E YAP;Lo;0;L;;;;;N;;;;; +169AD;BAMUM LETTER PHASE-E NYI CLEAVER;Lo;0;L;;;;;N;;;;; +169AE;BAMUM LETTER PHASE-E YIT;Lo;0;L;;;;;N;;;;; +169AF;BAMUM LETTER PHASE-E MFEUQ;Lo;0;L;;;;;N;;;;; +169B0;BAMUM LETTER PHASE-E NDIAQ;Lo;0;L;;;;;N;;;;; +169B1;BAMUM LETTER PHASE-E PIEEQ;Lo;0;L;;;;;N;;;;; +169B2;BAMUM LETTER PHASE-E YUEQ;Lo;0;L;;;;;N;;;;; +169B3;BAMUM LETTER PHASE-E LEUAEM;Lo;0;L;;;;;N;;;;; +169B4;BAMUM LETTER PHASE-E FUE;Lo;0;L;;;;;N;;;;; +169B5;BAMUM LETTER PHASE-E GBEUX;Lo;0;L;;;;;N;;;;; +169B6;BAMUM LETTER PHASE-E NGKUP;Lo;0;L;;;;;N;;;;; +169B7;BAMUM LETTER PHASE-E KET;Lo;0;L;;;;;N;;;;; +169B8;BAMUM LETTER PHASE-E MAE;Lo;0;L;;;;;N;;;;; +169B9;BAMUM LETTER PHASE-E NGKAAMI;Lo;0;L;;;;;N;;;;; +169BA;BAMUM LETTER PHASE-E GHET;Lo;0;L;;;;;N;;;;; +169BB;BAMUM LETTER PHASE-E FA;Lo;0;L;;;;;N;;;;; +169BC;BAMUM LETTER PHASE-E NTUM;Lo;0;L;;;;;N;;;;; +169BD;BAMUM LETTER PHASE-E PEUT;Lo;0;L;;;;;N;;;;; +169BE;BAMUM LETTER PHASE-E YEUM;Lo;0;L;;;;;N;;;;; +169BF;BAMUM LETTER PHASE-E NGGEUAE;Lo;0;L;;;;;N;;;;; +169C0;BAMUM LETTER PHASE-E NYI BETWEEN;Lo;0;L;;;;;N;;;;; +169C1;BAMUM LETTER PHASE-E NZUQ;Lo;0;L;;;;;N;;;;; +169C2;BAMUM LETTER PHASE-E POON;Lo;0;L;;;;;N;;;;; +169C3;BAMUM LETTER PHASE-E MIEE;Lo;0;L;;;;;N;;;;; +169C4;BAMUM LETTER PHASE-E FUET;Lo;0;L;;;;;N;;;;; +169C5;BAMUM LETTER PHASE-E NAE;Lo;0;L;;;;;N;;;;; +169C6;BAMUM LETTER PHASE-E MUAE;Lo;0;L;;;;;N;;;;; +169C7;BAMUM LETTER PHASE-E GHEUAE;Lo;0;L;;;;;N;;;;; +169C8;BAMUM LETTER PHASE-E FU I;Lo;0;L;;;;;N;;;;; +169C9;BAMUM LETTER PHASE-E MVI;Lo;0;L;;;;;N;;;;; +169CA;BAMUM LETTER PHASE-E PUAQ;Lo;0;L;;;;;N;;;;; +169CB;BAMUM LETTER PHASE-E NGKUM;Lo;0;L;;;;;N;;;;; +169CC;BAMUM LETTER PHASE-E KUT;Lo;0;L;;;;;N;;;;; +169CD;BAMUM LETTER PHASE-E PIET;Lo;0;L;;;;;N;;;;; +169CE;BAMUM LETTER PHASE-E NTAP;Lo;0;L;;;;;N;;;;; +169CF;BAMUM LETTER PHASE-E YEUAET;Lo;0;L;;;;;N;;;;; +169D0;BAMUM LETTER PHASE-E NGGUP;Lo;0;L;;;;;N;;;;; +169D1;BAMUM LETTER PHASE-E PA PEOPLE;Lo;0;L;;;;;N;;;;; +169D2;BAMUM LETTER PHASE-E FU CALL;Lo;0;L;;;;;N;;;;; +169D3;BAMUM LETTER PHASE-E FOM;Lo;0;L;;;;;N;;;;; +169D4;BAMUM LETTER PHASE-E NJEE;Lo;0;L;;;;;N;;;;; +169D5;BAMUM LETTER PHASE-E A;Lo;0;L;;;;;N;;;;; +169D6;BAMUM LETTER PHASE-E TOQ;Lo;0;L;;;;;N;;;;; +169D7;BAMUM LETTER PHASE-E O;Lo;0;L;;;;;N;;;;; +169D8;BAMUM LETTER PHASE-E I;Lo;0;L;;;;;N;;;;; +169D9;BAMUM LETTER PHASE-E LAQ;Lo;0;L;;;;;N;;;;; +169DA;BAMUM LETTER PHASE-E PA PLURAL;Lo;0;L;;;;;N;;;;; +169DB;BAMUM LETTER PHASE-E TAA;Lo;0;L;;;;;N;;;;; +169DC;BAMUM LETTER PHASE-E TAQ;Lo;0;L;;;;;N;;;;; +169DD;BAMUM LETTER PHASE-E NDAA MY HOUSE;Lo;0;L;;;;;N;;;;; +169DE;BAMUM LETTER PHASE-E SHIQ;Lo;0;L;;;;;N;;;;; +169DF;BAMUM LETTER PHASE-E YEUX;Lo;0;L;;;;;N;;;;; +169E0;BAMUM LETTER PHASE-E NGUAE;Lo;0;L;;;;;N;;;;; +169E1;BAMUM LETTER PHASE-E YUAEN;Lo;0;L;;;;;N;;;;; +169E2;BAMUM LETTER PHASE-E YOQ SWIMMING;Lo;0;L;;;;;N;;;;; +169E3;BAMUM LETTER PHASE-E YOQ COVER;Lo;0;L;;;;;N;;;;; +169E4;BAMUM LETTER PHASE-E YUQ;Lo;0;L;;;;;N;;;;; +169E5;BAMUM LETTER PHASE-E YUN;Lo;0;L;;;;;N;;;;; +169E6;BAMUM LETTER PHASE-E KEUX;Lo;0;L;;;;;N;;;;; +169E7;BAMUM LETTER PHASE-E PEUX;Lo;0;L;;;;;N;;;;; +169E8;BAMUM LETTER PHASE-E NJEE EPOCH;Lo;0;L;;;;;N;;;;; +169E9;BAMUM LETTER PHASE-E PUE;Lo;0;L;;;;;N;;;;; +169EA;BAMUM LETTER PHASE-E WUE;Lo;0;L;;;;;N;;;;; +169EB;BAMUM LETTER PHASE-E FEE;Lo;0;L;;;;;N;;;;; +169EC;BAMUM LETTER PHASE-E VEE;Lo;0;L;;;;;N;;;;; +169ED;BAMUM LETTER PHASE-E LU;Lo;0;L;;;;;N;;;;; +169EE;BAMUM LETTER PHASE-E MI;Lo;0;L;;;;;N;;;;; +169EF;BAMUM LETTER PHASE-E REUX;Lo;0;L;;;;;N;;;;; +169F0;BAMUM LETTER PHASE-E RAE;Lo;0;L;;;;;N;;;;; +169F1;BAMUM LETTER PHASE-E NGUAET;Lo;0;L;;;;;N;;;;; +169F2;BAMUM LETTER PHASE-E NGA;Lo;0;L;;;;;N;;;;; +169F3;BAMUM LETTER PHASE-E SHO;Lo;0;L;;;;;N;;;;; +169F4;BAMUM LETTER PHASE-E SHOQ;Lo;0;L;;;;;N;;;;; +169F5;BAMUM LETTER PHASE-E FU REMEDY;Lo;0;L;;;;;N;;;;; +169F6;BAMUM LETTER PHASE-E NA;Lo;0;L;;;;;N;;;;; +169F7;BAMUM LETTER PHASE-E PI;Lo;0;L;;;;;N;;;;; +169F8;BAMUM LETTER PHASE-E LOQ;Lo;0;L;;;;;N;;;;; +169F9;BAMUM LETTER PHASE-E KO;Lo;0;L;;;;;N;;;;; +169FA;BAMUM LETTER PHASE-E MEN;Lo;0;L;;;;;N;;;;; +169FB;BAMUM LETTER PHASE-E MA;Lo;0;L;;;;;N;;;;; +169FC;BAMUM LETTER PHASE-E MAQ;Lo;0;L;;;;;N;;;;; +169FD;BAMUM LETTER PHASE-E TEU;Lo;0;L;;;;;N;;;;; +169FE;BAMUM LETTER PHASE-E KI;Lo;0;L;;;;;N;;;;; +169FF;BAMUM LETTER PHASE-E MON;Lo;0;L;;;;;N;;;;; +16A00;BAMUM LETTER PHASE-E TEN;Lo;0;L;;;;;N;;;;; +16A01;BAMUM LETTER PHASE-E FAQ;Lo;0;L;;;;;N;;;;; +16A02;BAMUM LETTER PHASE-E GHOM;Lo;0;L;;;;;N;;;;; +16A03;BAMUM LETTER PHASE-F KA;Lo;0;L;;;;;N;;;;; +16A04;BAMUM LETTER PHASE-F U;Lo;0;L;;;;;N;;;;; +16A05;BAMUM LETTER PHASE-F KU;Lo;0;L;;;;;N;;;;; +16A06;BAMUM LETTER PHASE-F EE;Lo;0;L;;;;;N;;;;; +16A07;BAMUM LETTER PHASE-F REE;Lo;0;L;;;;;N;;;;; +16A08;BAMUM LETTER PHASE-F TAE;Lo;0;L;;;;;N;;;;; +16A09;BAMUM LETTER PHASE-F NYI;Lo;0;L;;;;;N;;;;; +16A0A;BAMUM LETTER PHASE-F LA;Lo;0;L;;;;;N;;;;; +16A0B;BAMUM LETTER PHASE-F RII;Lo;0;L;;;;;N;;;;; +16A0C;BAMUM LETTER PHASE-F RIEE;Lo;0;L;;;;;N;;;;; +16A0D;BAMUM LETTER PHASE-F MEEEE;Lo;0;L;;;;;N;;;;; +16A0E;BAMUM LETTER PHASE-F TAA;Lo;0;L;;;;;N;;;;; +16A0F;BAMUM LETTER PHASE-F NDAA;Lo;0;L;;;;;N;;;;; +16A10;BAMUM LETTER PHASE-F NJAEM;Lo;0;L;;;;;N;;;;; +16A11;BAMUM LETTER PHASE-F M;Lo;0;L;;;;;N;;;;; +16A12;BAMUM LETTER PHASE-F SUU;Lo;0;L;;;;;N;;;;; +16A13;BAMUM LETTER PHASE-F SHII;Lo;0;L;;;;;N;;;;; +16A14;BAMUM LETTER PHASE-F SI;Lo;0;L;;;;;N;;;;; +16A15;BAMUM LETTER PHASE-F SEUX;Lo;0;L;;;;;N;;;;; +16A16;BAMUM LETTER PHASE-F KYEE;Lo;0;L;;;;;N;;;;; +16A17;BAMUM LETTER PHASE-F KET;Lo;0;L;;;;;N;;;;; +16A18;BAMUM LETTER PHASE-F NUAE;Lo;0;L;;;;;N;;;;; +16A19;BAMUM LETTER PHASE-F NU;Lo;0;L;;;;;N;;;;; +16A1A;BAMUM LETTER PHASE-F NJUAE;Lo;0;L;;;;;N;;;;; +16A1B;BAMUM LETTER PHASE-F YOQ;Lo;0;L;;;;;N;;;;; +16A1C;BAMUM LETTER PHASE-F SHU;Lo;0;L;;;;;N;;;;; +16A1D;BAMUM LETTER PHASE-F YA;Lo;0;L;;;;;N;;;;; +16A1E;BAMUM LETTER PHASE-F NSHA;Lo;0;L;;;;;N;;;;; +16A1F;BAMUM LETTER PHASE-F PEUX;Lo;0;L;;;;;N;;;;; +16A20;BAMUM LETTER PHASE-F NTEE;Lo;0;L;;;;;N;;;;; +16A21;BAMUM LETTER PHASE-F WUE;Lo;0;L;;;;;N;;;;; +16A22;BAMUM LETTER PHASE-F PEE;Lo;0;L;;;;;N;;;;; +16A23;BAMUM LETTER PHASE-F RU;Lo;0;L;;;;;N;;;;; +16A24;BAMUM LETTER PHASE-F NI;Lo;0;L;;;;;N;;;;; +16A25;BAMUM LETTER PHASE-F REUX;Lo;0;L;;;;;N;;;;; +16A26;BAMUM LETTER PHASE-F KEN;Lo;0;L;;;;;N;;;;; +16A27;BAMUM LETTER PHASE-F NGKWAEN;Lo;0;L;;;;;N;;;;; +16A28;BAMUM LETTER PHASE-F NGGA;Lo;0;L;;;;;N;;;;; +16A29;BAMUM LETTER PHASE-F SHO;Lo;0;L;;;;;N;;;;; +16A2A;BAMUM LETTER PHASE-F PUAE;Lo;0;L;;;;;N;;;;; +16A2B;BAMUM LETTER PHASE-F FOM;Lo;0;L;;;;;N;;;;; +16A2C;BAMUM LETTER PHASE-F WA;Lo;0;L;;;;;N;;;;; +16A2D;BAMUM LETTER PHASE-F LI;Lo;0;L;;;;;N;;;;; +16A2E;BAMUM LETTER PHASE-F LOQ;Lo;0;L;;;;;N;;;;; +16A2F;BAMUM LETTER PHASE-F KO;Lo;0;L;;;;;N;;;;; +16A30;BAMUM LETTER PHASE-F MBEN;Lo;0;L;;;;;N;;;;; +16A31;BAMUM LETTER PHASE-F REN;Lo;0;L;;;;;N;;;;; +16A32;BAMUM LETTER PHASE-F MA;Lo;0;L;;;;;N;;;;; +16A33;BAMUM LETTER PHASE-F MO;Lo;0;L;;;;;N;;;;; +16A34;BAMUM LETTER PHASE-F MBAA;Lo;0;L;;;;;N;;;;; +16A35;BAMUM LETTER PHASE-F TET;Lo;0;L;;;;;N;;;;; +16A36;BAMUM LETTER PHASE-F KPA;Lo;0;L;;;;;N;;;;; +16A37;BAMUM LETTER PHASE-F SAMBA;Lo;0;L;;;;;N;;;;; +16A38;BAMUM LETTER PHASE-F VUEQ;Lo;0;L;;;;;N;;;;; +16A40;MRO LETTER TA;Lo;0;L;;;;;N;;;;; +16A41;MRO LETTER NGI;Lo;0;L;;;;;N;;;;; +16A42;MRO LETTER YO;Lo;0;L;;;;;N;;;;; +16A43;MRO LETTER MIM;Lo;0;L;;;;;N;;;;; +16A44;MRO LETTER BA;Lo;0;L;;;;;N;;;;; +16A45;MRO LETTER DA;Lo;0;L;;;;;N;;;;; +16A46;MRO LETTER A;Lo;0;L;;;;;N;;;;; +16A47;MRO LETTER PHI;Lo;0;L;;;;;N;;;;; +16A48;MRO LETTER KHAI;Lo;0;L;;;;;N;;;;; +16A49;MRO LETTER HAO;Lo;0;L;;;;;N;;;;; +16A4A;MRO LETTER DAI;Lo;0;L;;;;;N;;;;; +16A4B;MRO LETTER CHU;Lo;0;L;;;;;N;;;;; +16A4C;MRO LETTER KEAAE;Lo;0;L;;;;;N;;;;; +16A4D;MRO LETTER OL;Lo;0;L;;;;;N;;;;; +16A4E;MRO LETTER MAEM;Lo;0;L;;;;;N;;;;; +16A4F;MRO LETTER NIN;Lo;0;L;;;;;N;;;;; +16A50;MRO LETTER PA;Lo;0;L;;;;;N;;;;; +16A51;MRO LETTER OO;Lo;0;L;;;;;N;;;;; +16A52;MRO LETTER O;Lo;0;L;;;;;N;;;;; +16A53;MRO LETTER RO;Lo;0;L;;;;;N;;;;; +16A54;MRO LETTER SHI;Lo;0;L;;;;;N;;;;; +16A55;MRO LETTER THEA;Lo;0;L;;;;;N;;;;; +16A56;MRO LETTER EA;Lo;0;L;;;;;N;;;;; +16A57;MRO LETTER WA;Lo;0;L;;;;;N;;;;; +16A58;MRO LETTER E;Lo;0;L;;;;;N;;;;; +16A59;MRO LETTER KO;Lo;0;L;;;;;N;;;;; +16A5A;MRO LETTER LAN;Lo;0;L;;;;;N;;;;; +16A5B;MRO LETTER LA;Lo;0;L;;;;;N;;;;; +16A5C;MRO LETTER HAI;Lo;0;L;;;;;N;;;;; +16A5D;MRO LETTER RI;Lo;0;L;;;;;N;;;;; +16A5E;MRO LETTER TEK;Lo;0;L;;;;;N;;;;; +16A60;MRO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +16A61;MRO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +16A62;MRO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +16A63;MRO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +16A64;MRO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +16A65;MRO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +16A66;MRO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +16A67;MRO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +16A68;MRO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +16A69;MRO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +16A6E;MRO DANDA;Po;0;L;;;;;N;;;;; +16A6F;MRO DOUBLE DANDA;Po;0;L;;;;;N;;;;; +16A70;TANGSA LETTER OZ;Lo;0;L;;;;;N;;;;; +16A71;TANGSA LETTER OC;Lo;0;L;;;;;N;;;;; +16A72;TANGSA LETTER OQ;Lo;0;L;;;;;N;;;;; +16A73;TANGSA LETTER OX;Lo;0;L;;;;;N;;;;; +16A74;TANGSA LETTER AZ;Lo;0;L;;;;;N;;;;; +16A75;TANGSA LETTER AC;Lo;0;L;;;;;N;;;;; +16A76;TANGSA LETTER AQ;Lo;0;L;;;;;N;;;;; +16A77;TANGSA LETTER AX;Lo;0;L;;;;;N;;;;; +16A78;TANGSA LETTER VZ;Lo;0;L;;;;;N;;;;; +16A79;TANGSA LETTER VC;Lo;0;L;;;;;N;;;;; +16A7A;TANGSA LETTER VQ;Lo;0;L;;;;;N;;;;; +16A7B;TANGSA LETTER VX;Lo;0;L;;;;;N;;;;; +16A7C;TANGSA LETTER EZ;Lo;0;L;;;;;N;;;;; +16A7D;TANGSA LETTER EC;Lo;0;L;;;;;N;;;;; +16A7E;TANGSA LETTER EQ;Lo;0;L;;;;;N;;;;; +16A7F;TANGSA LETTER EX;Lo;0;L;;;;;N;;;;; +16A80;TANGSA LETTER IZ;Lo;0;L;;;;;N;;;;; +16A81;TANGSA LETTER IC;Lo;0;L;;;;;N;;;;; +16A82;TANGSA LETTER IQ;Lo;0;L;;;;;N;;;;; +16A83;TANGSA LETTER IX;Lo;0;L;;;;;N;;;;; +16A84;TANGSA LETTER UZ;Lo;0;L;;;;;N;;;;; +16A85;TANGSA LETTER UC;Lo;0;L;;;;;N;;;;; +16A86;TANGSA LETTER UQ;Lo;0;L;;;;;N;;;;; +16A87;TANGSA LETTER UX;Lo;0;L;;;;;N;;;;; +16A88;TANGSA LETTER AWZ;Lo;0;L;;;;;N;;;;; +16A89;TANGSA LETTER AWC;Lo;0;L;;;;;N;;;;; +16A8A;TANGSA LETTER AWQ;Lo;0;L;;;;;N;;;;; +16A8B;TANGSA LETTER AWX;Lo;0;L;;;;;N;;;;; +16A8C;TANGSA LETTER UIZ;Lo;0;L;;;;;N;;;;; +16A8D;TANGSA LETTER UIC;Lo;0;L;;;;;N;;;;; +16A8E;TANGSA LETTER UIQ;Lo;0;L;;;;;N;;;;; +16A8F;TANGSA LETTER UIX;Lo;0;L;;;;;N;;;;; +16A90;TANGSA LETTER FINAL NG;Lo;0;L;;;;;N;;;;; +16A91;TANGSA LETTER LONG UEX;Lo;0;L;;;;;N;;;;; +16A92;TANGSA LETTER SHORT UEZ;Lo;0;L;;;;;N;;;;; +16A93;TANGSA LETTER SHORT AWX;Lo;0;L;;;;;N;;;;; +16A94;TANGSA LETTER UEC;Lo;0;L;;;;;N;;;;; +16A95;TANGSA LETTER UEZ;Lo;0;L;;;;;N;;;;; +16A96;TANGSA LETTER UEQ;Lo;0;L;;;;;N;;;;; +16A97;TANGSA LETTER UEX;Lo;0;L;;;;;N;;;;; +16A98;TANGSA LETTER UIUZ;Lo;0;L;;;;;N;;;;; +16A99;TANGSA LETTER UIUC;Lo;0;L;;;;;N;;;;; +16A9A;TANGSA LETTER UIUQ;Lo;0;L;;;;;N;;;;; +16A9B;TANGSA LETTER UIUX;Lo;0;L;;;;;N;;;;; +16A9C;TANGSA LETTER MZ;Lo;0;L;;;;;N;;;;; +16A9D;TANGSA LETTER MC;Lo;0;L;;;;;N;;;;; +16A9E;TANGSA LETTER MQ;Lo;0;L;;;;;N;;;;; +16A9F;TANGSA LETTER MX;Lo;0;L;;;;;N;;;;; +16AA0;TANGSA LETTER KA;Lo;0;L;;;;;N;;;;; +16AA1;TANGSA LETTER KHA;Lo;0;L;;;;;N;;;;; +16AA2;TANGSA LETTER GA;Lo;0;L;;;;;N;;;;; +16AA3;TANGSA LETTER NGA;Lo;0;L;;;;;N;;;;; +16AA4;TANGSA LETTER SA;Lo;0;L;;;;;N;;;;; +16AA5;TANGSA LETTER YA;Lo;0;L;;;;;N;;;;; +16AA6;TANGSA LETTER WA;Lo;0;L;;;;;N;;;;; +16AA7;TANGSA LETTER PA;Lo;0;L;;;;;N;;;;; +16AA8;TANGSA LETTER NYA;Lo;0;L;;;;;N;;;;; +16AA9;TANGSA LETTER PHA;Lo;0;L;;;;;N;;;;; +16AAA;TANGSA LETTER BA;Lo;0;L;;;;;N;;;;; +16AAB;TANGSA LETTER MA;Lo;0;L;;;;;N;;;;; +16AAC;TANGSA LETTER NA;Lo;0;L;;;;;N;;;;; +16AAD;TANGSA LETTER HA;Lo;0;L;;;;;N;;;;; +16AAE;TANGSA LETTER LA;Lo;0;L;;;;;N;;;;; +16AAF;TANGSA LETTER HTA;Lo;0;L;;;;;N;;;;; +16AB0;TANGSA LETTER TA;Lo;0;L;;;;;N;;;;; +16AB1;TANGSA LETTER DA;Lo;0;L;;;;;N;;;;; +16AB2;TANGSA LETTER RA;Lo;0;L;;;;;N;;;;; +16AB3;TANGSA LETTER NHA;Lo;0;L;;;;;N;;;;; +16AB4;TANGSA LETTER SHA;Lo;0;L;;;;;N;;;;; +16AB5;TANGSA LETTER CA;Lo;0;L;;;;;N;;;;; +16AB6;TANGSA LETTER TSA;Lo;0;L;;;;;N;;;;; +16AB7;TANGSA LETTER GHA;Lo;0;L;;;;;N;;;;; +16AB8;TANGSA LETTER HTTA;Lo;0;L;;;;;N;;;;; +16AB9;TANGSA LETTER THA;Lo;0;L;;;;;N;;;;; +16ABA;TANGSA LETTER XA;Lo;0;L;;;;;N;;;;; +16ABB;TANGSA LETTER FA;Lo;0;L;;;;;N;;;;; +16ABC;TANGSA LETTER DHA;Lo;0;L;;;;;N;;;;; +16ABD;TANGSA LETTER CHA;Lo;0;L;;;;;N;;;;; +16ABE;TANGSA LETTER ZA;Lo;0;L;;;;;N;;;;; +16AC0;TANGSA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +16AC1;TANGSA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +16AC2;TANGSA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +16AC3;TANGSA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +16AC4;TANGSA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +16AC5;TANGSA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +16AC6;TANGSA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +16AC7;TANGSA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +16AC8;TANGSA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +16AC9;TANGSA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +16AD0;BASSA VAH LETTER ENNI;Lo;0;L;;;;;N;;;;; +16AD1;BASSA VAH LETTER KA;Lo;0;L;;;;;N;;;;; +16AD2;BASSA VAH LETTER SE;Lo;0;L;;;;;N;;;;; +16AD3;BASSA VAH LETTER FA;Lo;0;L;;;;;N;;;;; +16AD4;BASSA VAH LETTER MBE;Lo;0;L;;;;;N;;;;; +16AD5;BASSA VAH LETTER YIE;Lo;0;L;;;;;N;;;;; +16AD6;BASSA VAH LETTER GAH;Lo;0;L;;;;;N;;;;; +16AD7;BASSA VAH LETTER DHII;Lo;0;L;;;;;N;;;;; +16AD8;BASSA VAH LETTER KPAH;Lo;0;L;;;;;N;;;;; +16AD9;BASSA VAH LETTER JO;Lo;0;L;;;;;N;;;;; +16ADA;BASSA VAH LETTER HWAH;Lo;0;L;;;;;N;;;;; +16ADB;BASSA VAH LETTER WA;Lo;0;L;;;;;N;;;;; +16ADC;BASSA VAH LETTER ZO;Lo;0;L;;;;;N;;;;; +16ADD;BASSA VAH LETTER GBU;Lo;0;L;;;;;N;;;;; +16ADE;BASSA VAH LETTER DO;Lo;0;L;;;;;N;;;;; +16ADF;BASSA VAH LETTER CE;Lo;0;L;;;;;N;;;;; +16AE0;BASSA VAH LETTER UWU;Lo;0;L;;;;;N;;;;; +16AE1;BASSA VAH LETTER TO;Lo;0;L;;;;;N;;;;; +16AE2;BASSA VAH LETTER BA;Lo;0;L;;;;;N;;;;; +16AE3;BASSA VAH LETTER VU;Lo;0;L;;;;;N;;;;; +16AE4;BASSA VAH LETTER YEIN;Lo;0;L;;;;;N;;;;; +16AE5;BASSA VAH LETTER PA;Lo;0;L;;;;;N;;;;; +16AE6;BASSA VAH LETTER WADDA;Lo;0;L;;;;;N;;;;; +16AE7;BASSA VAH LETTER A;Lo;0;L;;;;;N;;;;; +16AE8;BASSA VAH LETTER O;Lo;0;L;;;;;N;;;;; +16AE9;BASSA VAH LETTER OO;Lo;0;L;;;;;N;;;;; +16AEA;BASSA VAH LETTER U;Lo;0;L;;;;;N;;;;; +16AEB;BASSA VAH LETTER EE;Lo;0;L;;;;;N;;;;; +16AEC;BASSA VAH LETTER E;Lo;0;L;;;;;N;;;;; +16AED;BASSA VAH LETTER I;Lo;0;L;;;;;N;;;;; +16AF0;BASSA VAH COMBINING HIGH TONE;Mn;1;NSM;;;;;N;;;;; +16AF1;BASSA VAH COMBINING LOW TONE;Mn;1;NSM;;;;;N;;;;; +16AF2;BASSA VAH COMBINING MID TONE;Mn;1;NSM;;;;;N;;;;; +16AF3;BASSA VAH COMBINING LOW-MID TONE;Mn;1;NSM;;;;;N;;;;; +16AF4;BASSA VAH COMBINING HIGH-LOW TONE;Mn;1;NSM;;;;;N;;;;; +16AF5;BASSA VAH FULL STOP;Po;0;L;;;;;N;;;;; +16B00;PAHAWH HMONG VOWEL KEEB;Lo;0;L;;;;;N;;;;; +16B01;PAHAWH HMONG VOWEL KEEV;Lo;0;L;;;;;N;;;;; +16B02;PAHAWH HMONG VOWEL KIB;Lo;0;L;;;;;N;;;;; +16B03;PAHAWH HMONG VOWEL KIV;Lo;0;L;;;;;N;;;;; +16B04;PAHAWH HMONG VOWEL KAUB;Lo;0;L;;;;;N;;;;; +16B05;PAHAWH HMONG VOWEL KAUV;Lo;0;L;;;;;N;;;;; +16B06;PAHAWH HMONG VOWEL KUB;Lo;0;L;;;;;N;;;;; +16B07;PAHAWH HMONG VOWEL KUV;Lo;0;L;;;;;N;;;;; +16B08;PAHAWH HMONG VOWEL KEB;Lo;0;L;;;;;N;;;;; +16B09;PAHAWH HMONG VOWEL KEV;Lo;0;L;;;;;N;;;;; +16B0A;PAHAWH HMONG VOWEL KAIB;Lo;0;L;;;;;N;;;;; +16B0B;PAHAWH HMONG VOWEL KAIV;Lo;0;L;;;;;N;;;;; +16B0C;PAHAWH HMONG VOWEL KOOB;Lo;0;L;;;;;N;;;;; +16B0D;PAHAWH HMONG VOWEL KOOV;Lo;0;L;;;;;N;;;;; +16B0E;PAHAWH HMONG VOWEL KAWB;Lo;0;L;;;;;N;;;;; +16B0F;PAHAWH HMONG VOWEL KAWV;Lo;0;L;;;;;N;;;;; +16B10;PAHAWH HMONG VOWEL KUAB;Lo;0;L;;;;;N;;;;; +16B11;PAHAWH HMONG VOWEL KUAV;Lo;0;L;;;;;N;;;;; +16B12;PAHAWH HMONG VOWEL KOB;Lo;0;L;;;;;N;;;;; +16B13;PAHAWH HMONG VOWEL KOV;Lo;0;L;;;;;N;;;;; +16B14;PAHAWH HMONG VOWEL KIAB;Lo;0;L;;;;;N;;;;; +16B15;PAHAWH HMONG VOWEL KIAV;Lo;0;L;;;;;N;;;;; +16B16;PAHAWH HMONG VOWEL KAB;Lo;0;L;;;;;N;;;;; +16B17;PAHAWH HMONG VOWEL KAV;Lo;0;L;;;;;N;;;;; +16B18;PAHAWH HMONG VOWEL KWB;Lo;0;L;;;;;N;;;;; +16B19;PAHAWH HMONG VOWEL KWV;Lo;0;L;;;;;N;;;;; +16B1A;PAHAWH HMONG VOWEL KAAB;Lo;0;L;;;;;N;;;;; +16B1B;PAHAWH HMONG VOWEL KAAV;Lo;0;L;;;;;N;;;;; +16B1C;PAHAWH HMONG CONSONANT VAU;Lo;0;L;;;;;N;;;;; +16B1D;PAHAWH HMONG CONSONANT NTSAU;Lo;0;L;;;;;N;;;;; +16B1E;PAHAWH HMONG CONSONANT LAU;Lo;0;L;;;;;N;;;;; +16B1F;PAHAWH HMONG CONSONANT HAU;Lo;0;L;;;;;N;;;;; +16B20;PAHAWH HMONG CONSONANT NLAU;Lo;0;L;;;;;N;;;;; +16B21;PAHAWH HMONG CONSONANT RAU;Lo;0;L;;;;;N;;;;; +16B22;PAHAWH HMONG CONSONANT NKAU;Lo;0;L;;;;;N;;;;; +16B23;PAHAWH HMONG CONSONANT QHAU;Lo;0;L;;;;;N;;;;; +16B24;PAHAWH HMONG CONSONANT YAU;Lo;0;L;;;;;N;;;;; +16B25;PAHAWH HMONG CONSONANT HLAU;Lo;0;L;;;;;N;;;;; +16B26;PAHAWH HMONG CONSONANT MAU;Lo;0;L;;;;;N;;;;; +16B27;PAHAWH HMONG CONSONANT CHAU;Lo;0;L;;;;;N;;;;; +16B28;PAHAWH HMONG CONSONANT NCHAU;Lo;0;L;;;;;N;;;;; +16B29;PAHAWH HMONG CONSONANT HNAU;Lo;0;L;;;;;N;;;;; +16B2A;PAHAWH HMONG CONSONANT PLHAU;Lo;0;L;;;;;N;;;;; +16B2B;PAHAWH HMONG CONSONANT NTHAU;Lo;0;L;;;;;N;;;;; +16B2C;PAHAWH HMONG CONSONANT NAU;Lo;0;L;;;;;N;;;;; +16B2D;PAHAWH HMONG CONSONANT AU;Lo;0;L;;;;;N;;;;; +16B2E;PAHAWH HMONG CONSONANT XAU;Lo;0;L;;;;;N;;;;; +16B2F;PAHAWH HMONG CONSONANT CAU;Lo;0;L;;;;;N;;;;; +16B30;PAHAWH HMONG MARK CIM TUB;Mn;230;NSM;;;;;N;;;;; +16B31;PAHAWH HMONG MARK CIM SO;Mn;230;NSM;;;;;N;;;;; +16B32;PAHAWH HMONG MARK CIM KES;Mn;230;NSM;;;;;N;;;;; +16B33;PAHAWH HMONG MARK CIM KHAV;Mn;230;NSM;;;;;N;;;;; +16B34;PAHAWH HMONG MARK CIM SUAM;Mn;230;NSM;;;;;N;;;;; +16B35;PAHAWH HMONG MARK CIM HOM;Mn;230;NSM;;;;;N;;;;; +16B36;PAHAWH HMONG MARK CIM TAUM;Mn;230;NSM;;;;;N;;;;; +16B37;PAHAWH HMONG SIGN VOS THOM;Po;0;L;;;;;N;;;;; +16B38;PAHAWH HMONG SIGN VOS TSHAB CEEB;Po;0;L;;;;;N;;;;; +16B39;PAHAWH HMONG SIGN CIM CHEEM;Po;0;L;;;;;N;;;;; +16B3A;PAHAWH HMONG SIGN VOS THIAB;Po;0;L;;;;;N;;;;; +16B3B;PAHAWH HMONG SIGN VOS FEEM;Po;0;L;;;;;N;;;;; +16B3C;PAHAWH HMONG SIGN XYEEM NTXIV;So;0;L;;;;;N;;;;; +16B3D;PAHAWH HMONG SIGN XYEEM RHO;So;0;L;;;;;N;;;;; +16B3E;PAHAWH HMONG SIGN XYEEM TOV;So;0;L;;;;;N;;;;; +16B3F;PAHAWH HMONG SIGN XYEEM FAIB;So;0;L;;;;;N;;;;; +16B40;PAHAWH HMONG SIGN VOS SEEV;Lm;0;L;;;;;N;;;;; +16B41;PAHAWH HMONG SIGN MEEJ SUAB;Lm;0;L;;;;;N;;;;; +16B42;PAHAWH HMONG SIGN VOS NRUA;Lm;0;L;;;;;N;;;;; +16B43;PAHAWH HMONG SIGN IB YAM;Lm;0;L;;;;;N;;;;; +16B44;PAHAWH HMONG SIGN XAUS;Po;0;L;;;;;N;;;;; +16B45;PAHAWH HMONG SIGN CIM TSOV ROG;So;0;L;;;;;N;;;;; +16B50;PAHAWH HMONG DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +16B51;PAHAWH HMONG DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +16B52;PAHAWH HMONG DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +16B53;PAHAWH HMONG DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +16B54;PAHAWH HMONG DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +16B55;PAHAWH HMONG DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +16B56;PAHAWH HMONG DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +16B57;PAHAWH HMONG DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +16B58;PAHAWH HMONG DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +16B59;PAHAWH HMONG DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +16B5B;PAHAWH HMONG NUMBER TENS;No;0;L;;;;10;N;;;;; +16B5C;PAHAWH HMONG NUMBER HUNDREDS;No;0;L;;;;100;N;;;;; +16B5D;PAHAWH HMONG NUMBER TEN THOUSANDS;No;0;L;;;;10000;N;;;;; +16B5E;PAHAWH HMONG NUMBER MILLIONS;No;0;L;;;;1000000;N;;;;; +16B5F;PAHAWH HMONG NUMBER HUNDRED MILLIONS;No;0;L;;;;100000000;N;;;;; +16B60;PAHAWH HMONG NUMBER TEN BILLIONS;No;0;L;;;;10000000000;N;;;;; +16B61;PAHAWH HMONG NUMBER TRILLIONS;No;0;L;;;;1000000000000;N;;;;; +16B63;PAHAWH HMONG SIGN VOS LUB;Lo;0;L;;;;;N;;;;; +16B64;PAHAWH HMONG SIGN XYOO;Lo;0;L;;;;;N;;;;; +16B65;PAHAWH HMONG SIGN HLI;Lo;0;L;;;;;N;;;;; +16B66;PAHAWH HMONG SIGN THIRD-STAGE HLI;Lo;0;L;;;;;N;;;;; +16B67;PAHAWH HMONG SIGN ZWJ THAJ;Lo;0;L;;;;;N;;;;; +16B68;PAHAWH HMONG SIGN HNUB;Lo;0;L;;;;;N;;;;; +16B69;PAHAWH HMONG SIGN NQIG;Lo;0;L;;;;;N;;;;; +16B6A;PAHAWH HMONG SIGN XIAB;Lo;0;L;;;;;N;;;;; +16B6B;PAHAWH HMONG SIGN NTUJ;Lo;0;L;;;;;N;;;;; +16B6C;PAHAWH HMONG SIGN AV;Lo;0;L;;;;;N;;;;; +16B6D;PAHAWH HMONG SIGN TXHEEJ CEEV;Lo;0;L;;;;;N;;;;; +16B6E;PAHAWH HMONG SIGN MEEJ TSEEB;Lo;0;L;;;;;N;;;;; +16B6F;PAHAWH HMONG SIGN TAU;Lo;0;L;;;;;N;;;;; +16B70;PAHAWH HMONG SIGN LOS;Lo;0;L;;;;;N;;;;; +16B71;PAHAWH HMONG SIGN MUS;Lo;0;L;;;;;N;;;;; +16B72;PAHAWH HMONG SIGN CIM HAIS LUS NTOG NTOG;Lo;0;L;;;;;N;;;;; +16B73;PAHAWH HMONG SIGN CIM CUAM TSHOOJ;Lo;0;L;;;;;N;;;;; +16B74;PAHAWH HMONG SIGN CIM TXWV;Lo;0;L;;;;;N;;;;; +16B75;PAHAWH HMONG SIGN CIM TXWV CHWV;Lo;0;L;;;;;N;;;;; +16B76;PAHAWH HMONG SIGN CIM PUB DAWB;Lo;0;L;;;;;N;;;;; +16B77;PAHAWH HMONG SIGN CIM NRES TOS;Lo;0;L;;;;;N;;;;; +16B7D;PAHAWH HMONG CLAN SIGN TSHEEJ;Lo;0;L;;;;;N;;;;; +16B7E;PAHAWH HMONG CLAN SIGN YEEG;Lo;0;L;;;;;N;;;;; +16B7F;PAHAWH HMONG CLAN SIGN LIS;Lo;0;L;;;;;N;;;;; +16B80;PAHAWH HMONG CLAN SIGN LAUJ;Lo;0;L;;;;;N;;;;; +16B81;PAHAWH HMONG CLAN SIGN XYOOJ;Lo;0;L;;;;;N;;;;; +16B82;PAHAWH HMONG CLAN SIGN KOO;Lo;0;L;;;;;N;;;;; +16B83;PAHAWH HMONG CLAN SIGN HAWJ;Lo;0;L;;;;;N;;;;; +16B84;PAHAWH HMONG CLAN SIGN MUAS;Lo;0;L;;;;;N;;;;; +16B85;PAHAWH HMONG CLAN SIGN THOJ;Lo;0;L;;;;;N;;;;; +16B86;PAHAWH HMONG CLAN SIGN TSAB;Lo;0;L;;;;;N;;;;; +16B87;PAHAWH HMONG CLAN SIGN PHAB;Lo;0;L;;;;;N;;;;; +16B88;PAHAWH HMONG CLAN SIGN KHAB;Lo;0;L;;;;;N;;;;; +16B89;PAHAWH HMONG CLAN SIGN HAM;Lo;0;L;;;;;N;;;;; +16B8A;PAHAWH HMONG CLAN SIGN VAJ;Lo;0;L;;;;;N;;;;; +16B8B;PAHAWH HMONG CLAN SIGN FAJ;Lo;0;L;;;;;N;;;;; +16B8C;PAHAWH HMONG CLAN SIGN YAJ;Lo;0;L;;;;;N;;;;; +16B8D;PAHAWH HMONG CLAN SIGN TSWB;Lo;0;L;;;;;N;;;;; +16B8E;PAHAWH HMONG CLAN SIGN KWM;Lo;0;L;;;;;N;;;;; +16B8F;PAHAWH HMONG CLAN SIGN VWJ;Lo;0;L;;;;;N;;;;; +16D40;KIRAT RAI SIGN ANUSVARA;Lm;0;L;;;;;N;;;;; +16D41;KIRAT RAI SIGN TONPI;Lm;0;L;;;;;N;;;;; +16D42;KIRAT RAI SIGN VISARGA;Lm;0;L;;;;;N;;;;; +16D43;KIRAT RAI LETTER A;Lo;0;L;;;;;N;;;;; +16D44;KIRAT RAI LETTER KA;Lo;0;L;;;;;N;;;;; +16D45;KIRAT RAI LETTER KHA;Lo;0;L;;;;;N;;;;; +16D46;KIRAT RAI LETTER GA;Lo;0;L;;;;;N;;;;; +16D47;KIRAT RAI LETTER GHA;Lo;0;L;;;;;N;;;;; +16D48;KIRAT RAI LETTER NGA;Lo;0;L;;;;;N;;;;; +16D49;KIRAT RAI LETTER CA;Lo;0;L;;;;;N;;;;; +16D4A;KIRAT RAI LETTER CHA;Lo;0;L;;;;;N;;;;; +16D4B;KIRAT RAI LETTER JA;Lo;0;L;;;;;N;;;;; +16D4C;KIRAT RAI LETTER JHA;Lo;0;L;;;;;N;;;;; +16D4D;KIRAT RAI LETTER NYA;Lo;0;L;;;;;N;;;;; +16D4E;KIRAT RAI LETTER TTA;Lo;0;L;;;;;N;;;;; +16D4F;KIRAT RAI LETTER TTHA;Lo;0;L;;;;;N;;;;; +16D50;KIRAT RAI LETTER DDA;Lo;0;L;;;;;N;;;;; +16D51;KIRAT RAI LETTER DDHA;Lo;0;L;;;;;N;;;;; +16D52;KIRAT RAI LETTER TA;Lo;0;L;;;;;N;;;;; +16D53;KIRAT RAI LETTER THA;Lo;0;L;;;;;N;;;;; +16D54;KIRAT RAI LETTER DA;Lo;0;L;;;;;N;;;;; +16D55;KIRAT RAI LETTER DHA;Lo;0;L;;;;;N;;;;; +16D56;KIRAT RAI LETTER NA;Lo;0;L;;;;;N;;;;; +16D57;KIRAT RAI LETTER PA;Lo;0;L;;;;;N;;;;; +16D58;KIRAT RAI LETTER PHA;Lo;0;L;;;;;N;;;;; +16D59;KIRAT RAI LETTER BA;Lo;0;L;;;;;N;;;;; +16D5A;KIRAT RAI LETTER BHA;Lo;0;L;;;;;N;;;;; +16D5B;KIRAT RAI LETTER MA;Lo;0;L;;;;;N;;;;; +16D5C;KIRAT RAI LETTER YA;Lo;0;L;;;;;N;;;;; +16D5D;KIRAT RAI LETTER RA;Lo;0;L;;;;;N;;;;; +16D5E;KIRAT RAI LETTER LA;Lo;0;L;;;;;N;;;;; +16D5F;KIRAT RAI LETTER VA;Lo;0;L;;;;;N;;;;; +16D60;KIRAT RAI LETTER SA;Lo;0;L;;;;;N;;;;; +16D61;KIRAT RAI LETTER SHA;Lo;0;L;;;;;N;;;;; +16D62;KIRAT RAI LETTER HA;Lo;0;L;;;;;N;;;;; +16D63;KIRAT RAI VOWEL SIGN AA;Lo;0;L;;;;;N;;;;; +16D64;KIRAT RAI VOWEL SIGN I;Lo;0;L;;;;;N;;;;; +16D65;KIRAT RAI VOWEL SIGN U;Lo;0;L;;;;;N;;;;; +16D66;KIRAT RAI VOWEL SIGN UE;Lo;0;L;;;;;N;;;;; +16D67;KIRAT RAI VOWEL SIGN E;Lo;0;L;;;;;N;;;;; +16D68;KIRAT RAI VOWEL SIGN AI;Lo;0;L;16D67 16D67;;;;N;;;;; +16D69;KIRAT RAI VOWEL SIGN O;Lo;0;L;16D63 16D67;;;;N;;;;; +16D6A;KIRAT RAI VOWEL SIGN AU;Lo;0;L;16D69 16D67;;;;N;;;;; +16D6B;KIRAT RAI SIGN VIRAMA;Lm;0;L;;;;;N;;;;; +16D6C;KIRAT RAI SIGN SAAT;Lm;0;L;;;;;N;;;;; +16D6D;KIRAT RAI SIGN YUPI;Po;0;L;;;;;N;;;;; +16D6E;KIRAT RAI DANDA;Po;0;L;;;;;N;;;;; +16D6F;KIRAT RAI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +16D70;KIRAT RAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +16D71;KIRAT RAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +16D72;KIRAT RAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +16D73;KIRAT RAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +16D74;KIRAT RAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +16D75;KIRAT RAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +16D76;KIRAT RAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +16D77;KIRAT RAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +16D78;KIRAT RAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +16D79;KIRAT RAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +16E40;MEDEFAIDRIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;16E60; +16E41;MEDEFAIDRIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;16E61; +16E42;MEDEFAIDRIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;16E62; +16E43;MEDEFAIDRIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;16E63; +16E44;MEDEFAIDRIN CAPITAL LETTER ATIU;Lu;0;L;;;;;N;;;;16E64; +16E45;MEDEFAIDRIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;16E65; +16E46;MEDEFAIDRIN CAPITAL LETTER KP;Lu;0;L;;;;;N;;;;16E66; +16E47;MEDEFAIDRIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;16E67; +16E48;MEDEFAIDRIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;16E68; +16E49;MEDEFAIDRIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;16E69; +16E4A;MEDEFAIDRIN CAPITAL LETTER F;Lu;0;L;;;;;N;;;;16E6A; +16E4B;MEDEFAIDRIN CAPITAL LETTER I;Lu;0;L;;;;;N;;;;16E6B; +16E4C;MEDEFAIDRIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;16E6C; +16E4D;MEDEFAIDRIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;16E6D; +16E4E;MEDEFAIDRIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;16E6E; +16E4F;MEDEFAIDRIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;16E6F; +16E50;MEDEFAIDRIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;16E70; +16E51;MEDEFAIDRIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;16E71; +16E52;MEDEFAIDRIN CAPITAL LETTER U;Lu;0;L;;;;;N;;;;16E72; +16E53;MEDEFAIDRIN CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;16E73; +16E54;MEDEFAIDRIN CAPITAL LETTER L;Lu;0;L;;;;;N;;;;16E74; +16E55;MEDEFAIDRIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;16E75; +16E56;MEDEFAIDRIN CAPITAL LETTER HP;Lu;0;L;;;;;N;;;;16E76; +16E57;MEDEFAIDRIN CAPITAL LETTER NY;Lu;0;L;;;;;N;;;;16E77; +16E58;MEDEFAIDRIN CAPITAL LETTER X;Lu;0;L;;;;;N;;;;16E78; +16E59;MEDEFAIDRIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;16E79; +16E5A;MEDEFAIDRIN CAPITAL LETTER OE;Lu;0;L;;;;;N;;;;16E7A; +16E5B;MEDEFAIDRIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;16E7B; +16E5C;MEDEFAIDRIN CAPITAL LETTER R;Lu;0;L;;;;;N;;;;16E7C; +16E5D;MEDEFAIDRIN CAPITAL LETTER O;Lu;0;L;;;;;N;;;;16E7D; +16E5E;MEDEFAIDRIN CAPITAL LETTER AI;Lu;0;L;;;;;N;;;;16E7E; +16E5F;MEDEFAIDRIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;16E7F; +16E60;MEDEFAIDRIN SMALL LETTER M;Ll;0;L;;;;;N;;;16E40;;16E40 +16E61;MEDEFAIDRIN SMALL LETTER S;Ll;0;L;;;;;N;;;16E41;;16E41 +16E62;MEDEFAIDRIN SMALL LETTER V;Ll;0;L;;;;;N;;;16E42;;16E42 +16E63;MEDEFAIDRIN SMALL LETTER W;Ll;0;L;;;;;N;;;16E43;;16E43 +16E64;MEDEFAIDRIN SMALL LETTER ATIU;Ll;0;L;;;;;N;;;16E44;;16E44 +16E65;MEDEFAIDRIN SMALL LETTER Z;Ll;0;L;;;;;N;;;16E45;;16E45 +16E66;MEDEFAIDRIN SMALL LETTER KP;Ll;0;L;;;;;N;;;16E46;;16E46 +16E67;MEDEFAIDRIN SMALL LETTER P;Ll;0;L;;;;;N;;;16E47;;16E47 +16E68;MEDEFAIDRIN SMALL LETTER T;Ll;0;L;;;;;N;;;16E48;;16E48 +16E69;MEDEFAIDRIN SMALL LETTER G;Ll;0;L;;;;;N;;;16E49;;16E49 +16E6A;MEDEFAIDRIN SMALL LETTER F;Ll;0;L;;;;;N;;;16E4A;;16E4A +16E6B;MEDEFAIDRIN SMALL LETTER I;Ll;0;L;;;;;N;;;16E4B;;16E4B +16E6C;MEDEFAIDRIN SMALL LETTER K;Ll;0;L;;;;;N;;;16E4C;;16E4C +16E6D;MEDEFAIDRIN SMALL LETTER A;Ll;0;L;;;;;N;;;16E4D;;16E4D +16E6E;MEDEFAIDRIN SMALL LETTER J;Ll;0;L;;;;;N;;;16E4E;;16E4E +16E6F;MEDEFAIDRIN SMALL LETTER E;Ll;0;L;;;;;N;;;16E4F;;16E4F +16E70;MEDEFAIDRIN SMALL LETTER B;Ll;0;L;;;;;N;;;16E50;;16E50 +16E71;MEDEFAIDRIN SMALL LETTER C;Ll;0;L;;;;;N;;;16E51;;16E51 +16E72;MEDEFAIDRIN SMALL LETTER U;Ll;0;L;;;;;N;;;16E52;;16E52 +16E73;MEDEFAIDRIN SMALL LETTER YU;Ll;0;L;;;;;N;;;16E53;;16E53 +16E74;MEDEFAIDRIN SMALL LETTER L;Ll;0;L;;;;;N;;;16E54;;16E54 +16E75;MEDEFAIDRIN SMALL LETTER Q;Ll;0;L;;;;;N;;;16E55;;16E55 +16E76;MEDEFAIDRIN SMALL LETTER HP;Ll;0;L;;;;;N;;;16E56;;16E56 +16E77;MEDEFAIDRIN SMALL LETTER NY;Ll;0;L;;;;;N;;;16E57;;16E57 +16E78;MEDEFAIDRIN SMALL LETTER X;Ll;0;L;;;;;N;;;16E58;;16E58 +16E79;MEDEFAIDRIN SMALL LETTER D;Ll;0;L;;;;;N;;;16E59;;16E59 +16E7A;MEDEFAIDRIN SMALL LETTER OE;Ll;0;L;;;;;N;;;16E5A;;16E5A +16E7B;MEDEFAIDRIN SMALL LETTER N;Ll;0;L;;;;;N;;;16E5B;;16E5B +16E7C;MEDEFAIDRIN SMALL LETTER R;Ll;0;L;;;;;N;;;16E5C;;16E5C +16E7D;MEDEFAIDRIN SMALL LETTER O;Ll;0;L;;;;;N;;;16E5D;;16E5D +16E7E;MEDEFAIDRIN SMALL LETTER AI;Ll;0;L;;;;;N;;;16E5E;;16E5E +16E7F;MEDEFAIDRIN SMALL LETTER Y;Ll;0;L;;;;;N;;;16E5F;;16E5F +16E80;MEDEFAIDRIN DIGIT ZERO;No;0;L;;;;0;N;;;;; +16E81;MEDEFAIDRIN DIGIT ONE;No;0;L;;;;1;N;;;;; +16E82;MEDEFAIDRIN DIGIT TWO;No;0;L;;;;2;N;;;;; +16E83;MEDEFAIDRIN DIGIT THREE;No;0;L;;;;3;N;;;;; +16E84;MEDEFAIDRIN DIGIT FOUR;No;0;L;;;;4;N;;;;; +16E85;MEDEFAIDRIN DIGIT FIVE;No;0;L;;;;5;N;;;;; +16E86;MEDEFAIDRIN DIGIT SIX;No;0;L;;;;6;N;;;;; +16E87;MEDEFAIDRIN DIGIT SEVEN;No;0;L;;;;7;N;;;;; +16E88;MEDEFAIDRIN DIGIT EIGHT;No;0;L;;;;8;N;;;;; +16E89;MEDEFAIDRIN DIGIT NINE;No;0;L;;;;9;N;;;;; +16E8A;MEDEFAIDRIN NUMBER TEN;No;0;L;;;;10;N;;;;; +16E8B;MEDEFAIDRIN NUMBER ELEVEN;No;0;L;;;;11;N;;;;; +16E8C;MEDEFAIDRIN NUMBER TWELVE;No;0;L;;;;12;N;;;;; +16E8D;MEDEFAIDRIN NUMBER THIRTEEN;No;0;L;;;;13;N;;;;; +16E8E;MEDEFAIDRIN NUMBER FOURTEEN;No;0;L;;;;14;N;;;;; +16E8F;MEDEFAIDRIN NUMBER FIFTEEN;No;0;L;;;;15;N;;;;; +16E90;MEDEFAIDRIN NUMBER SIXTEEN;No;0;L;;;;16;N;;;;; +16E91;MEDEFAIDRIN NUMBER SEVENTEEN;No;0;L;;;;17;N;;;;; +16E92;MEDEFAIDRIN NUMBER EIGHTEEN;No;0;L;;;;18;N;;;;; +16E93;MEDEFAIDRIN NUMBER NINETEEN;No;0;L;;;;19;N;;;;; +16E94;MEDEFAIDRIN DIGIT ONE ALTERNATE FORM;No;0;L;;;;1;N;;;;; +16E95;MEDEFAIDRIN DIGIT TWO ALTERNATE FORM;No;0;L;;;;2;N;;;;; +16E96;MEDEFAIDRIN DIGIT THREE ALTERNATE FORM;No;0;L;;;;3;N;;;;; +16E97;MEDEFAIDRIN COMMA;Po;0;L;;;;;N;;;;; +16E98;MEDEFAIDRIN FULL STOP;Po;0;L;;;;;N;;;;; +16E99;MEDEFAIDRIN SYMBOL AIVA;Po;0;L;;;;;N;;;;; +16E9A;MEDEFAIDRIN EXCLAMATION OH;Po;0;L;;;;;N;;;;; +16EA0;BERIA ERFE CAPITAL LETTER ARKAB;Lu;0;L;;;;;N;;;;16EBB; +16EA1;BERIA ERFE CAPITAL LETTER BASIGNA;Lu;0;L;;;;;N;;;;16EBC; +16EA2;BERIA ERFE CAPITAL LETTER DARBAI;Lu;0;L;;;;;N;;;;16EBD; +16EA3;BERIA ERFE CAPITAL LETTER EH;Lu;0;L;;;;;N;;;;16EBE; +16EA4;BERIA ERFE CAPITAL LETTER FITKO;Lu;0;L;;;;;N;;;;16EBF; +16EA5;BERIA ERFE CAPITAL LETTER GOWAY;Lu;0;L;;;;;N;;;;16EC0; +16EA6;BERIA ERFE CAPITAL LETTER HIRDEABO;Lu;0;L;;;;;N;;;;16EC1; +16EA7;BERIA ERFE CAPITAL LETTER I;Lu;0;L;;;;;N;;;;16EC2; +16EA8;BERIA ERFE CAPITAL LETTER DJAI;Lu;0;L;;;;;N;;;;16EC3; +16EA9;BERIA ERFE CAPITAL LETTER KOBO;Lu;0;L;;;;;N;;;;16EC4; +16EAA;BERIA ERFE CAPITAL LETTER LAKKO;Lu;0;L;;;;;N;;;;16EC5; +16EAB;BERIA ERFE CAPITAL LETTER MERI;Lu;0;L;;;;;N;;;;16EC6; +16EAC;BERIA ERFE CAPITAL LETTER NINI;Lu;0;L;;;;;N;;;;16EC7; +16EAD;BERIA ERFE CAPITAL LETTER GNA;Lu;0;L;;;;;N;;;;16EC8; +16EAE;BERIA ERFE CAPITAL LETTER NGAY;Lu;0;L;;;;;N;;;;16EC9; +16EAF;BERIA ERFE CAPITAL LETTER OI;Lu;0;L;;;;;N;;;;16ECA; +16EB0;BERIA ERFE CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;16ECB; +16EB1;BERIA ERFE CAPITAL LETTER ERIGO;Lu;0;L;;;;;N;;;;16ECC; +16EB2;BERIA ERFE CAPITAL LETTER ERIGO TAMURA;Lu;0;L;;;;;N;;;;16ECD; +16EB3;BERIA ERFE CAPITAL LETTER SERI;Lu;0;L;;;;;N;;;;16ECE; +16EB4;BERIA ERFE CAPITAL LETTER SHEP;Lu;0;L;;;;;N;;;;16ECF; +16EB5;BERIA ERFE CAPITAL LETTER TATASOUE;Lu;0;L;;;;;N;;;;16ED0; +16EB6;BERIA ERFE CAPITAL LETTER UI;Lu;0;L;;;;;N;;;;16ED1; +16EB7;BERIA ERFE CAPITAL LETTER WASSE;Lu;0;L;;;;;N;;;;16ED2; +16EB8;BERIA ERFE CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;16ED3; +16EBB;BERIA ERFE SMALL LETTER ARKAB;Ll;0;L;;;;;N;;;16EA0;;16EA0 +16EBC;BERIA ERFE SMALL LETTER BASIGNA;Ll;0;L;;;;;N;;;16EA1;;16EA1 +16EBD;BERIA ERFE SMALL LETTER DARBAI;Ll;0;L;;;;;N;;;16EA2;;16EA2 +16EBE;BERIA ERFE SMALL LETTER EH;Ll;0;L;;;;;N;;;16EA3;;16EA3 +16EBF;BERIA ERFE SMALL LETTER FITKO;Ll;0;L;;;;;N;;;16EA4;;16EA4 +16EC0;BERIA ERFE SMALL LETTER GOWAY;Ll;0;L;;;;;N;;;16EA5;;16EA5 +16EC1;BERIA ERFE SMALL LETTER HIRDEABO;Ll;0;L;;;;;N;;;16EA6;;16EA6 +16EC2;BERIA ERFE SMALL LETTER I;Ll;0;L;;;;;N;;;16EA7;;16EA7 +16EC3;BERIA ERFE SMALL LETTER DJAI;Ll;0;L;;;;;N;;;16EA8;;16EA8 +16EC4;BERIA ERFE SMALL LETTER KOBO;Ll;0;L;;;;;N;;;16EA9;;16EA9 +16EC5;BERIA ERFE SMALL LETTER LAKKO;Ll;0;L;;;;;N;;;16EAA;;16EAA +16EC6;BERIA ERFE SMALL LETTER MERI;Ll;0;L;;;;;N;;;16EAB;;16EAB +16EC7;BERIA ERFE SMALL LETTER NINI;Ll;0;L;;;;;N;;;16EAC;;16EAC +16EC8;BERIA ERFE SMALL LETTER GNA;Ll;0;L;;;;;N;;;16EAD;;16EAD +16EC9;BERIA ERFE SMALL LETTER NGAY;Ll;0;L;;;;;N;;;16EAE;;16EAE +16ECA;BERIA ERFE SMALL LETTER OI;Ll;0;L;;;;;N;;;16EAF;;16EAF +16ECB;BERIA ERFE SMALL LETTER PI;Ll;0;L;;;;;N;;;16EB0;;16EB0 +16ECC;BERIA ERFE SMALL LETTER ERIGO;Ll;0;L;;;;;N;;;16EB1;;16EB1 +16ECD;BERIA ERFE SMALL LETTER ERIGO TAMURA;Ll;0;L;;;;;N;;;16EB2;;16EB2 +16ECE;BERIA ERFE SMALL LETTER SERI;Ll;0;L;;;;;N;;;16EB3;;16EB3 +16ECF;BERIA ERFE SMALL LETTER SHEP;Ll;0;L;;;;;N;;;16EB4;;16EB4 +16ED0;BERIA ERFE SMALL LETTER TATASOUE;Ll;0;L;;;;;N;;;16EB5;;16EB5 +16ED1;BERIA ERFE SMALL LETTER UI;Ll;0;L;;;;;N;;;16EB6;;16EB6 +16ED2;BERIA ERFE SMALL LETTER WASSE;Ll;0;L;;;;;N;;;16EB7;;16EB7 +16ED3;BERIA ERFE SMALL LETTER AY;Ll;0;L;;;;;N;;;16EB8;;16EB8 +16F00;MIAO LETTER PA;Lo;0;L;;;;;N;;;;; +16F01;MIAO LETTER BA;Lo;0;L;;;;;N;;;;; +16F02;MIAO LETTER YI PA;Lo;0;L;;;;;N;;;;; +16F03;MIAO LETTER PLA;Lo;0;L;;;;;N;;;;; +16F04;MIAO LETTER MA;Lo;0;L;;;;;N;;;;; +16F05;MIAO LETTER MHA;Lo;0;L;;;;;N;;;;; +16F06;MIAO LETTER ARCHAIC MA;Lo;0;L;;;;;N;;;;; +16F07;MIAO LETTER FA;Lo;0;L;;;;;N;;;;; +16F08;MIAO LETTER VA;Lo;0;L;;;;;N;;;;; +16F09;MIAO LETTER VFA;Lo;0;L;;;;;N;;;;; +16F0A;MIAO LETTER TA;Lo;0;L;;;;;N;;;;; +16F0B;MIAO LETTER DA;Lo;0;L;;;;;N;;;;; +16F0C;MIAO LETTER YI TTA;Lo;0;L;;;;;N;;;;; +16F0D;MIAO LETTER YI TA;Lo;0;L;;;;;N;;;;; +16F0E;MIAO LETTER TTA;Lo;0;L;;;;;N;;;;; +16F0F;MIAO LETTER DDA;Lo;0;L;;;;;N;;;;; +16F10;MIAO LETTER NA;Lo;0;L;;;;;N;;;;; +16F11;MIAO LETTER NHA;Lo;0;L;;;;;N;;;;; +16F12;MIAO LETTER YI NNA;Lo;0;L;;;;;N;;;;; +16F13;MIAO LETTER ARCHAIC NA;Lo;0;L;;;;;N;;;;; +16F14;MIAO LETTER NNA;Lo;0;L;;;;;N;;;;; +16F15;MIAO LETTER NNHA;Lo;0;L;;;;;N;;;;; +16F16;MIAO LETTER LA;Lo;0;L;;;;;N;;;;; +16F17;MIAO LETTER LYA;Lo;0;L;;;;;N;;;;; +16F18;MIAO LETTER LHA;Lo;0;L;;;;;N;;;;; +16F19;MIAO LETTER LHYA;Lo;0;L;;;;;N;;;;; +16F1A;MIAO LETTER TLHA;Lo;0;L;;;;;N;;;;; +16F1B;MIAO LETTER DLHA;Lo;0;L;;;;;N;;;;; +16F1C;MIAO LETTER TLHYA;Lo;0;L;;;;;N;;;;; +16F1D;MIAO LETTER DLHYA;Lo;0;L;;;;;N;;;;; +16F1E;MIAO LETTER KA;Lo;0;L;;;;;N;;;;; +16F1F;MIAO LETTER GA;Lo;0;L;;;;;N;;;;; +16F20;MIAO LETTER YI KA;Lo;0;L;;;;;N;;;;; +16F21;MIAO LETTER QA;Lo;0;L;;;;;N;;;;; +16F22;MIAO LETTER QGA;Lo;0;L;;;;;N;;;;; +16F23;MIAO LETTER NGA;Lo;0;L;;;;;N;;;;; +16F24;MIAO LETTER NGHA;Lo;0;L;;;;;N;;;;; +16F25;MIAO LETTER ARCHAIC NGA;Lo;0;L;;;;;N;;;;; +16F26;MIAO LETTER HA;Lo;0;L;;;;;N;;;;; +16F27;MIAO LETTER XA;Lo;0;L;;;;;N;;;;; +16F28;MIAO LETTER GHA;Lo;0;L;;;;;N;;;;; +16F29;MIAO LETTER GHHA;Lo;0;L;;;;;N;;;;; +16F2A;MIAO LETTER TSSA;Lo;0;L;;;;;N;;;;; +16F2B;MIAO LETTER DZZA;Lo;0;L;;;;;N;;;;; +16F2C;MIAO LETTER NYA;Lo;0;L;;;;;N;;;;; +16F2D;MIAO LETTER NYHA;Lo;0;L;;;;;N;;;;; +16F2E;MIAO LETTER TSHA;Lo;0;L;;;;;N;;;;; +16F2F;MIAO LETTER DZHA;Lo;0;L;;;;;N;;;;; +16F30;MIAO LETTER YI TSHA;Lo;0;L;;;;;N;;;;; +16F31;MIAO LETTER YI DZHA;Lo;0;L;;;;;N;;;;; +16F32;MIAO LETTER REFORMED TSHA;Lo;0;L;;;;;N;;;;; +16F33;MIAO LETTER SHA;Lo;0;L;;;;;N;;;;; +16F34;MIAO LETTER SSA;Lo;0;L;;;;;N;;;;; +16F35;MIAO LETTER ZHA;Lo;0;L;;;;;N;;;;; +16F36;MIAO LETTER ZSHA;Lo;0;L;;;;;N;;;;; +16F37;MIAO LETTER TSA;Lo;0;L;;;;;N;;;;; +16F38;MIAO LETTER DZA;Lo;0;L;;;;;N;;;;; +16F39;MIAO LETTER YI TSA;Lo;0;L;;;;;N;;;;; +16F3A;MIAO LETTER SA;Lo;0;L;;;;;N;;;;; +16F3B;MIAO LETTER ZA;Lo;0;L;;;;;N;;;;; +16F3C;MIAO LETTER ZSA;Lo;0;L;;;;;N;;;;; +16F3D;MIAO LETTER ZZA;Lo;0;L;;;;;N;;;;; +16F3E;MIAO LETTER ZZSA;Lo;0;L;;;;;N;;;;; +16F3F;MIAO LETTER ARCHAIC ZZA;Lo;0;L;;;;;N;;;;; +16F40;MIAO LETTER ZZYA;Lo;0;L;;;;;N;;;;; +16F41;MIAO LETTER ZZSYA;Lo;0;L;;;;;N;;;;; +16F42;MIAO LETTER WA;Lo;0;L;;;;;N;;;;; +16F43;MIAO LETTER AH;Lo;0;L;;;;;N;;;;; +16F44;MIAO LETTER HHA;Lo;0;L;;;;;N;;;;; +16F45;MIAO LETTER BRI;Lo;0;L;;;;;N;;;;; +16F46;MIAO LETTER SYI;Lo;0;L;;;;;N;;;;; +16F47;MIAO LETTER DZYI;Lo;0;L;;;;;N;;;;; +16F48;MIAO LETTER TE;Lo;0;L;;;;;N;;;;; +16F49;MIAO LETTER TSE;Lo;0;L;;;;;N;;;;; +16F4A;MIAO LETTER RTE;Lo;0;L;;;;;N;;;;; +16F4F;MIAO SIGN CONSONANT MODIFIER BAR;Mn;0;NSM;;;;;N;;;;; +16F50;MIAO LETTER NASALIZATION;Lo;0;L;;;;;N;;;;; +16F51;MIAO SIGN ASPIRATION;Mc;0;L;;;;;N;;;;; +16F52;MIAO SIGN REFORMED VOICING;Mc;0;L;;;;;N;;;;; +16F53;MIAO SIGN REFORMED ASPIRATION;Mc;0;L;;;;;N;;;;; +16F54;MIAO VOWEL SIGN A;Mc;0;L;;;;;N;;;;; +16F55;MIAO VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +16F56;MIAO VOWEL SIGN AHH;Mc;0;L;;;;;N;;;;; +16F57;MIAO VOWEL SIGN AN;Mc;0;L;;;;;N;;;;; +16F58;MIAO VOWEL SIGN ANG;Mc;0;L;;;;;N;;;;; +16F59;MIAO VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +16F5A;MIAO VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; +16F5B;MIAO VOWEL SIGN WO;Mc;0;L;;;;;N;;;;; +16F5C;MIAO VOWEL SIGN W;Mc;0;L;;;;;N;;;;; +16F5D;MIAO VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +16F5E;MIAO VOWEL SIGN EN;Mc;0;L;;;;;N;;;;; +16F5F;MIAO VOWEL SIGN ENG;Mc;0;L;;;;;N;;;;; +16F60;MIAO VOWEL SIGN OEY;Mc;0;L;;;;;N;;;;; +16F61;MIAO VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +16F62;MIAO VOWEL SIGN IA;Mc;0;L;;;;;N;;;;; +16F63;MIAO VOWEL SIGN IAN;Mc;0;L;;;;;N;;;;; +16F64;MIAO VOWEL SIGN IANG;Mc;0;L;;;;;N;;;;; +16F65;MIAO VOWEL SIGN IO;Mc;0;L;;;;;N;;;;; +16F66;MIAO VOWEL SIGN IE;Mc;0;L;;;;;N;;;;; +16F67;MIAO VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +16F68;MIAO VOWEL SIGN IU;Mc;0;L;;;;;N;;;;; +16F69;MIAO VOWEL SIGN ING;Mc;0;L;;;;;N;;;;; +16F6A;MIAO VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +16F6B;MIAO VOWEL SIGN UA;Mc;0;L;;;;;N;;;;; +16F6C;MIAO VOWEL SIGN UAN;Mc;0;L;;;;;N;;;;; +16F6D;MIAO VOWEL SIGN UANG;Mc;0;L;;;;;N;;;;; +16F6E;MIAO VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +16F6F;MIAO VOWEL SIGN UEI;Mc;0;L;;;;;N;;;;; +16F70;MIAO VOWEL SIGN UNG;Mc;0;L;;;;;N;;;;; +16F71;MIAO VOWEL SIGN Y;Mc;0;L;;;;;N;;;;; +16F72;MIAO VOWEL SIGN YI;Mc;0;L;;;;;N;;;;; +16F73;MIAO VOWEL SIGN AE;Mc;0;L;;;;;N;;;;; +16F74;MIAO VOWEL SIGN AEE;Mc;0;L;;;;;N;;;;; +16F75;MIAO VOWEL SIGN ERR;Mc;0;L;;;;;N;;;;; +16F76;MIAO VOWEL SIGN ROUNDED ERR;Mc;0;L;;;;;N;;;;; +16F77;MIAO VOWEL SIGN ER;Mc;0;L;;;;;N;;;;; +16F78;MIAO VOWEL SIGN ROUNDED ER;Mc;0;L;;;;;N;;;;; +16F79;MIAO VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +16F7A;MIAO VOWEL SIGN EI;Mc;0;L;;;;;N;;;;; +16F7B;MIAO VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +16F7C;MIAO VOWEL SIGN OU;Mc;0;L;;;;;N;;;;; +16F7D;MIAO VOWEL SIGN N;Mc;0;L;;;;;N;;;;; +16F7E;MIAO VOWEL SIGN NG;Mc;0;L;;;;;N;;;;; +16F7F;MIAO VOWEL SIGN UOG;Mc;0;L;;;;;N;;;;; +16F80;MIAO VOWEL SIGN YUI;Mc;0;L;;;;;N;;;;; +16F81;MIAO VOWEL SIGN OG;Mc;0;L;;;;;N;;;;; +16F82;MIAO VOWEL SIGN OER;Mc;0;L;;;;;N;;;;; +16F83;MIAO VOWEL SIGN VW;Mc;0;L;;;;;N;;;;; +16F84;MIAO VOWEL SIGN IG;Mc;0;L;;;;;N;;;;; +16F85;MIAO VOWEL SIGN EA;Mc;0;L;;;;;N;;;;; +16F86;MIAO VOWEL SIGN IONG;Mc;0;L;;;;;N;;;;; +16F87;MIAO VOWEL SIGN UI;Mc;0;L;;;;;N;;;;; +16F8F;MIAO TONE RIGHT;Mn;0;NSM;;;;;N;;;;; +16F90;MIAO TONE TOP RIGHT;Mn;0;NSM;;;;;N;;;;; +16F91;MIAO TONE ABOVE;Mn;0;NSM;;;;;N;;;;; +16F92;MIAO TONE BELOW;Mn;0;NSM;;;;;N;;;;; +16F93;MIAO LETTER TONE-2;Lm;0;L;;;;;N;;;;; +16F94;MIAO LETTER TONE-3;Lm;0;L;;;;;N;;;;; +16F95;MIAO LETTER TONE-4;Lm;0;L;;;;;N;;;;; +16F96;MIAO LETTER TONE-5;Lm;0;L;;;;;N;;;;; +16F97;MIAO LETTER TONE-6;Lm;0;L;;;;;N;;;;; +16F98;MIAO LETTER TONE-7;Lm;0;L;;;;;N;;;;; +16F99;MIAO LETTER TONE-8;Lm;0;L;;;;;N;;;;; +16F9A;MIAO LETTER REFORMED TONE-1;Lm;0;L;;;;;N;;;;; +16F9B;MIAO LETTER REFORMED TONE-2;Lm;0;L;;;;;N;;;;; +16F9C;MIAO LETTER REFORMED TONE-4;Lm;0;L;;;;;N;;;;; +16F9D;MIAO LETTER REFORMED TONE-5;Lm;0;L;;;;;N;;;;; +16F9E;MIAO LETTER REFORMED TONE-6;Lm;0;L;;;;;N;;;;; +16F9F;MIAO LETTER REFORMED TONE-8;Lm;0;L;;;;;N;;;;; +16FE0;TANGUT ITERATION MARK;Lm;0;L;;;;;N;;;;; +16FE1;NUSHU ITERATION MARK;Lm;0;L;;;;;N;;;;; +16FE2;OLD CHINESE HOOK MARK;Po;0;ON;;;;;N;;;;; +16FE3;OLD CHINESE ITERATION MARK;Lm;0;L;;;;;N;;;;; +16FE4;KHITAN SMALL SCRIPT FILLER;Mn;0;NSM;;;;;N;;;;; +16FF0;VIETNAMESE ALTERNATE READING MARK CA;Mc;6;L;;;;;N;;;;; +16FF1;VIETNAMESE ALTERNATE READING MARK NHAY;Mc;6;L;;;;;N;;;;; +16FF2;CHINESE SMALL SIMPLIFIED ER;Lm;0;L;;;;;N;;;;; +16FF3;CHINESE SMALL TRADITIONAL ER;Lm;0;L;;;;;N;;;;; +16FF4;YANGQIN SIGN SLOW ONE BEAT;Nl;0;L;;;;1;N;;;;; +16FF5;YANGQIN SIGN SLOW THREE HALF BEATS;Nl;0;L;;;;3/2;N;;;;; +16FF6;YANGQIN SIGN SLOW TWO BEATS;Nl;0;L;;;;2;N;;;;; +17000;;Lo;0;L;;;;;N;;;;; +187FF;;Lo;0;L;;;;;N;;;;; +18800;TANGUT COMPONENT-001;Lo;0;L;;;;;N;;;;; +18801;TANGUT COMPONENT-002;Lo;0;L;;;;;N;;;;; +18802;TANGUT COMPONENT-003;Lo;0;L;;;;;N;;;;; +18803;TANGUT COMPONENT-004;Lo;0;L;;;;;N;;;;; +18804;TANGUT COMPONENT-005;Lo;0;L;;;;;N;;;;; +18805;TANGUT COMPONENT-006;Lo;0;L;;;;;N;;;;; +18806;TANGUT COMPONENT-007;Lo;0;L;;;;;N;;;;; +18807;TANGUT COMPONENT-008;Lo;0;L;;;;;N;;;;; +18808;TANGUT COMPONENT-009;Lo;0;L;;;;;N;;;;; +18809;TANGUT COMPONENT-010;Lo;0;L;;;;;N;;;;; +1880A;TANGUT COMPONENT-011;Lo;0;L;;;;;N;;;;; +1880B;TANGUT COMPONENT-012;Lo;0;L;;;;;N;;;;; +1880C;TANGUT COMPONENT-013;Lo;0;L;;;;;N;;;;; +1880D;TANGUT COMPONENT-014;Lo;0;L;;;;;N;;;;; +1880E;TANGUT COMPONENT-015;Lo;0;L;;;;;N;;;;; +1880F;TANGUT COMPONENT-016;Lo;0;L;;;;;N;;;;; +18810;TANGUT COMPONENT-017;Lo;0;L;;;;;N;;;;; +18811;TANGUT COMPONENT-018;Lo;0;L;;;;;N;;;;; +18812;TANGUT COMPONENT-019;Lo;0;L;;;;;N;;;;; +18813;TANGUT COMPONENT-020;Lo;0;L;;;;;N;;;;; +18814;TANGUT COMPONENT-021;Lo;0;L;;;;;N;;;;; +18815;TANGUT COMPONENT-022;Lo;0;L;;;;;N;;;;; +18816;TANGUT COMPONENT-023;Lo;0;L;;;;;N;;;;; +18817;TANGUT COMPONENT-024;Lo;0;L;;;;;N;;;;; +18818;TANGUT COMPONENT-025;Lo;0;L;;;;;N;;;;; +18819;TANGUT COMPONENT-026;Lo;0;L;;;;;N;;;;; +1881A;TANGUT COMPONENT-027;Lo;0;L;;;;;N;;;;; +1881B;TANGUT COMPONENT-028;Lo;0;L;;;;;N;;;;; +1881C;TANGUT COMPONENT-029;Lo;0;L;;;;;N;;;;; +1881D;TANGUT COMPONENT-030;Lo;0;L;;;;;N;;;;; +1881E;TANGUT COMPONENT-031;Lo;0;L;;;;;N;;;;; +1881F;TANGUT COMPONENT-032;Lo;0;L;;;;;N;;;;; +18820;TANGUT COMPONENT-033;Lo;0;L;;;;;N;;;;; +18821;TANGUT COMPONENT-034;Lo;0;L;;;;;N;;;;; +18822;TANGUT COMPONENT-035;Lo;0;L;;;;;N;;;;; +18823;TANGUT COMPONENT-036;Lo;0;L;;;;;N;;;;; +18824;TANGUT COMPONENT-037;Lo;0;L;;;;;N;;;;; +18825;TANGUT COMPONENT-038;Lo;0;L;;;;;N;;;;; +18826;TANGUT COMPONENT-039;Lo;0;L;;;;;N;;;;; +18827;TANGUT COMPONENT-040;Lo;0;L;;;;;N;;;;; +18828;TANGUT COMPONENT-041;Lo;0;L;;;;;N;;;;; +18829;TANGUT COMPONENT-042;Lo;0;L;;;;;N;;;;; +1882A;TANGUT COMPONENT-043;Lo;0;L;;;;;N;;;;; +1882B;TANGUT COMPONENT-044;Lo;0;L;;;;;N;;;;; +1882C;TANGUT COMPONENT-045;Lo;0;L;;;;;N;;;;; +1882D;TANGUT COMPONENT-046;Lo;0;L;;;;;N;;;;; +1882E;TANGUT COMPONENT-047;Lo;0;L;;;;;N;;;;; +1882F;TANGUT COMPONENT-048;Lo;0;L;;;;;N;;;;; +18830;TANGUT COMPONENT-049;Lo;0;L;;;;;N;;;;; +18831;TANGUT COMPONENT-050;Lo;0;L;;;;;N;;;;; +18832;TANGUT COMPONENT-051;Lo;0;L;;;;;N;;;;; +18833;TANGUT COMPONENT-052;Lo;0;L;;;;;N;;;;; +18834;TANGUT COMPONENT-053;Lo;0;L;;;;;N;;;;; +18835;TANGUT COMPONENT-054;Lo;0;L;;;;;N;;;;; +18836;TANGUT COMPONENT-055;Lo;0;L;;;;;N;;;;; +18837;TANGUT COMPONENT-056;Lo;0;L;;;;;N;;;;; +18838;TANGUT COMPONENT-057;Lo;0;L;;;;;N;;;;; +18839;TANGUT COMPONENT-058;Lo;0;L;;;;;N;;;;; +1883A;TANGUT COMPONENT-059;Lo;0;L;;;;;N;;;;; +1883B;TANGUT COMPONENT-060;Lo;0;L;;;;;N;;;;; +1883C;TANGUT COMPONENT-061;Lo;0;L;;;;;N;;;;; +1883D;TANGUT COMPONENT-062;Lo;0;L;;;;;N;;;;; +1883E;TANGUT COMPONENT-063;Lo;0;L;;;;;N;;;;; +1883F;TANGUT COMPONENT-064;Lo;0;L;;;;;N;;;;; +18840;TANGUT COMPONENT-065;Lo;0;L;;;;;N;;;;; +18841;TANGUT COMPONENT-066;Lo;0;L;;;;;N;;;;; +18842;TANGUT COMPONENT-067;Lo;0;L;;;;;N;;;;; +18843;TANGUT COMPONENT-068;Lo;0;L;;;;;N;;;;; +18844;TANGUT COMPONENT-069;Lo;0;L;;;;;N;;;;; +18845;TANGUT COMPONENT-070;Lo;0;L;;;;;N;;;;; +18846;TANGUT COMPONENT-071;Lo;0;L;;;;;N;;;;; +18847;TANGUT COMPONENT-072;Lo;0;L;;;;;N;;;;; +18848;TANGUT COMPONENT-073;Lo;0;L;;;;;N;;;;; +18849;TANGUT COMPONENT-074;Lo;0;L;;;;;N;;;;; +1884A;TANGUT COMPONENT-075;Lo;0;L;;;;;N;;;;; +1884B;TANGUT COMPONENT-076;Lo;0;L;;;;;N;;;;; +1884C;TANGUT COMPONENT-077;Lo;0;L;;;;;N;;;;; +1884D;TANGUT COMPONENT-078;Lo;0;L;;;;;N;;;;; +1884E;TANGUT COMPONENT-079;Lo;0;L;;;;;N;;;;; +1884F;TANGUT COMPONENT-080;Lo;0;L;;;;;N;;;;; +18850;TANGUT COMPONENT-081;Lo;0;L;;;;;N;;;;; +18851;TANGUT COMPONENT-082;Lo;0;L;;;;;N;;;;; +18852;TANGUT COMPONENT-083;Lo;0;L;;;;;N;;;;; +18853;TANGUT COMPONENT-084;Lo;0;L;;;;;N;;;;; +18854;TANGUT COMPONENT-085;Lo;0;L;;;;;N;;;;; +18855;TANGUT COMPONENT-086;Lo;0;L;;;;;N;;;;; +18856;TANGUT COMPONENT-087;Lo;0;L;;;;;N;;;;; +18857;TANGUT COMPONENT-088;Lo;0;L;;;;;N;;;;; +18858;TANGUT COMPONENT-089;Lo;0;L;;;;;N;;;;; +18859;TANGUT COMPONENT-090;Lo;0;L;;;;;N;;;;; +1885A;TANGUT COMPONENT-091;Lo;0;L;;;;;N;;;;; +1885B;TANGUT COMPONENT-092;Lo;0;L;;;;;N;;;;; +1885C;TANGUT COMPONENT-093;Lo;0;L;;;;;N;;;;; +1885D;TANGUT COMPONENT-094;Lo;0;L;;;;;N;;;;; +1885E;TANGUT COMPONENT-095;Lo;0;L;;;;;N;;;;; +1885F;TANGUT COMPONENT-096;Lo;0;L;;;;;N;;;;; +18860;TANGUT COMPONENT-097;Lo;0;L;;;;;N;;;;; +18861;TANGUT COMPONENT-098;Lo;0;L;;;;;N;;;;; +18862;TANGUT COMPONENT-099;Lo;0;L;;;;;N;;;;; +18863;TANGUT COMPONENT-100;Lo;0;L;;;;;N;;;;; +18864;TANGUT COMPONENT-101;Lo;0;L;;;;;N;;;;; +18865;TANGUT COMPONENT-102;Lo;0;L;;;;;N;;;;; +18866;TANGUT COMPONENT-103;Lo;0;L;;;;;N;;;;; +18867;TANGUT COMPONENT-104;Lo;0;L;;;;;N;;;;; +18868;TANGUT COMPONENT-105;Lo;0;L;;;;;N;;;;; +18869;TANGUT COMPONENT-106;Lo;0;L;;;;;N;;;;; +1886A;TANGUT COMPONENT-107;Lo;0;L;;;;;N;;;;; +1886B;TANGUT COMPONENT-108;Lo;0;L;;;;;N;;;;; +1886C;TANGUT COMPONENT-109;Lo;0;L;;;;;N;;;;; +1886D;TANGUT COMPONENT-110;Lo;0;L;;;;;N;;;;; +1886E;TANGUT COMPONENT-111;Lo;0;L;;;;;N;;;;; +1886F;TANGUT COMPONENT-112;Lo;0;L;;;;;N;;;;; +18870;TANGUT COMPONENT-113;Lo;0;L;;;;;N;;;;; +18871;TANGUT COMPONENT-114;Lo;0;L;;;;;N;;;;; +18872;TANGUT COMPONENT-115;Lo;0;L;;;;;N;;;;; +18873;TANGUT COMPONENT-116;Lo;0;L;;;;;N;;;;; +18874;TANGUT COMPONENT-117;Lo;0;L;;;;;N;;;;; +18875;TANGUT COMPONENT-118;Lo;0;L;;;;;N;;;;; +18876;TANGUT COMPONENT-119;Lo;0;L;;;;;N;;;;; +18877;TANGUT COMPONENT-120;Lo;0;L;;;;;N;;;;; +18878;TANGUT COMPONENT-121;Lo;0;L;;;;;N;;;;; +18879;TANGUT COMPONENT-122;Lo;0;L;;;;;N;;;;; +1887A;TANGUT COMPONENT-123;Lo;0;L;;;;;N;;;;; +1887B;TANGUT COMPONENT-124;Lo;0;L;;;;;N;;;;; +1887C;TANGUT COMPONENT-125;Lo;0;L;;;;;N;;;;; +1887D;TANGUT COMPONENT-126;Lo;0;L;;;;;N;;;;; +1887E;TANGUT COMPONENT-127;Lo;0;L;;;;;N;;;;; +1887F;TANGUT COMPONENT-128;Lo;0;L;;;;;N;;;;; +18880;TANGUT COMPONENT-129;Lo;0;L;;;;;N;;;;; +18881;TANGUT COMPONENT-130;Lo;0;L;;;;;N;;;;; +18882;TANGUT COMPONENT-131;Lo;0;L;;;;;N;;;;; +18883;TANGUT COMPONENT-132;Lo;0;L;;;;;N;;;;; +18884;TANGUT COMPONENT-133;Lo;0;L;;;;;N;;;;; +18885;TANGUT COMPONENT-134;Lo;0;L;;;;;N;;;;; +18886;TANGUT COMPONENT-135;Lo;0;L;;;;;N;;;;; +18887;TANGUT COMPONENT-136;Lo;0;L;;;;;N;;;;; +18888;TANGUT COMPONENT-137;Lo;0;L;;;;;N;;;;; +18889;TANGUT COMPONENT-138;Lo;0;L;;;;;N;;;;; +1888A;TANGUT COMPONENT-139;Lo;0;L;;;;;N;;;;; +1888B;TANGUT COMPONENT-140;Lo;0;L;;;;;N;;;;; +1888C;TANGUT COMPONENT-141;Lo;0;L;;;;;N;;;;; +1888D;TANGUT COMPONENT-142;Lo;0;L;;;;;N;;;;; +1888E;TANGUT COMPONENT-143;Lo;0;L;;;;;N;;;;; +1888F;TANGUT COMPONENT-144;Lo;0;L;;;;;N;;;;; +18890;TANGUT COMPONENT-145;Lo;0;L;;;;;N;;;;; +18891;TANGUT COMPONENT-146;Lo;0;L;;;;;N;;;;; +18892;TANGUT COMPONENT-147;Lo;0;L;;;;;N;;;;; +18893;TANGUT COMPONENT-148;Lo;0;L;;;;;N;;;;; +18894;TANGUT COMPONENT-149;Lo;0;L;;;;;N;;;;; +18895;TANGUT COMPONENT-150;Lo;0;L;;;;;N;;;;; +18896;TANGUT COMPONENT-151;Lo;0;L;;;;;N;;;;; +18897;TANGUT COMPONENT-152;Lo;0;L;;;;;N;;;;; +18898;TANGUT COMPONENT-153;Lo;0;L;;;;;N;;;;; +18899;TANGUT COMPONENT-154;Lo;0;L;;;;;N;;;;; +1889A;TANGUT COMPONENT-155;Lo;0;L;;;;;N;;;;; +1889B;TANGUT COMPONENT-156;Lo;0;L;;;;;N;;;;; +1889C;TANGUT COMPONENT-157;Lo;0;L;;;;;N;;;;; +1889D;TANGUT COMPONENT-158;Lo;0;L;;;;;N;;;;; +1889E;TANGUT COMPONENT-159;Lo;0;L;;;;;N;;;;; +1889F;TANGUT COMPONENT-160;Lo;0;L;;;;;N;;;;; +188A0;TANGUT COMPONENT-161;Lo;0;L;;;;;N;;;;; +188A1;TANGUT COMPONENT-162;Lo;0;L;;;;;N;;;;; +188A2;TANGUT COMPONENT-163;Lo;0;L;;;;;N;;;;; +188A3;TANGUT COMPONENT-164;Lo;0;L;;;;;N;;;;; +188A4;TANGUT COMPONENT-165;Lo;0;L;;;;;N;;;;; +188A5;TANGUT COMPONENT-166;Lo;0;L;;;;;N;;;;; +188A6;TANGUT COMPONENT-167;Lo;0;L;;;;;N;;;;; +188A7;TANGUT COMPONENT-168;Lo;0;L;;;;;N;;;;; +188A8;TANGUT COMPONENT-169;Lo;0;L;;;;;N;;;;; +188A9;TANGUT COMPONENT-170;Lo;0;L;;;;;N;;;;; +188AA;TANGUT COMPONENT-171;Lo;0;L;;;;;N;;;;; +188AB;TANGUT COMPONENT-172;Lo;0;L;;;;;N;;;;; +188AC;TANGUT COMPONENT-173;Lo;0;L;;;;;N;;;;; +188AD;TANGUT COMPONENT-174;Lo;0;L;;;;;N;;;;; +188AE;TANGUT COMPONENT-175;Lo;0;L;;;;;N;;;;; +188AF;TANGUT COMPONENT-176;Lo;0;L;;;;;N;;;;; +188B0;TANGUT COMPONENT-177;Lo;0;L;;;;;N;;;;; +188B1;TANGUT COMPONENT-178;Lo;0;L;;;;;N;;;;; +188B2;TANGUT COMPONENT-179;Lo;0;L;;;;;N;;;;; +188B3;TANGUT COMPONENT-180;Lo;0;L;;;;;N;;;;; +188B4;TANGUT COMPONENT-181;Lo;0;L;;;;;N;;;;; +188B5;TANGUT COMPONENT-182;Lo;0;L;;;;;N;;;;; +188B6;TANGUT COMPONENT-183;Lo;0;L;;;;;N;;;;; +188B7;TANGUT COMPONENT-184;Lo;0;L;;;;;N;;;;; +188B8;TANGUT COMPONENT-185;Lo;0;L;;;;;N;;;;; +188B9;TANGUT COMPONENT-186;Lo;0;L;;;;;N;;;;; +188BA;TANGUT COMPONENT-187;Lo;0;L;;;;;N;;;;; +188BB;TANGUT COMPONENT-188;Lo;0;L;;;;;N;;;;; +188BC;TANGUT COMPONENT-189;Lo;0;L;;;;;N;;;;; +188BD;TANGUT COMPONENT-190;Lo;0;L;;;;;N;;;;; +188BE;TANGUT COMPONENT-191;Lo;0;L;;;;;N;;;;; +188BF;TANGUT COMPONENT-192;Lo;0;L;;;;;N;;;;; +188C0;TANGUT COMPONENT-193;Lo;0;L;;;;;N;;;;; +188C1;TANGUT COMPONENT-194;Lo;0;L;;;;;N;;;;; +188C2;TANGUT COMPONENT-195;Lo;0;L;;;;;N;;;;; +188C3;TANGUT COMPONENT-196;Lo;0;L;;;;;N;;;;; +188C4;TANGUT COMPONENT-197;Lo;0;L;;;;;N;;;;; +188C5;TANGUT COMPONENT-198;Lo;0;L;;;;;N;;;;; +188C6;TANGUT COMPONENT-199;Lo;0;L;;;;;N;;;;; +188C7;TANGUT COMPONENT-200;Lo;0;L;;;;;N;;;;; +188C8;TANGUT COMPONENT-201;Lo;0;L;;;;;N;;;;; +188C9;TANGUT COMPONENT-202;Lo;0;L;;;;;N;;;;; +188CA;TANGUT COMPONENT-203;Lo;0;L;;;;;N;;;;; +188CB;TANGUT COMPONENT-204;Lo;0;L;;;;;N;;;;; +188CC;TANGUT COMPONENT-205;Lo;0;L;;;;;N;;;;; +188CD;TANGUT COMPONENT-206;Lo;0;L;;;;;N;;;;; +188CE;TANGUT COMPONENT-207;Lo;0;L;;;;;N;;;;; +188CF;TANGUT COMPONENT-208;Lo;0;L;;;;;N;;;;; +188D0;TANGUT COMPONENT-209;Lo;0;L;;;;;N;;;;; +188D1;TANGUT COMPONENT-210;Lo;0;L;;;;;N;;;;; +188D2;TANGUT COMPONENT-211;Lo;0;L;;;;;N;;;;; +188D3;TANGUT COMPONENT-212;Lo;0;L;;;;;N;;;;; +188D4;TANGUT COMPONENT-213;Lo;0;L;;;;;N;;;;; +188D5;TANGUT COMPONENT-214;Lo;0;L;;;;;N;;;;; +188D6;TANGUT COMPONENT-215;Lo;0;L;;;;;N;;;;; +188D7;TANGUT COMPONENT-216;Lo;0;L;;;;;N;;;;; +188D8;TANGUT COMPONENT-217;Lo;0;L;;;;;N;;;;; +188D9;TANGUT COMPONENT-218;Lo;0;L;;;;;N;;;;; +188DA;TANGUT COMPONENT-219;Lo;0;L;;;;;N;;;;; +188DB;TANGUT COMPONENT-220;Lo;0;L;;;;;N;;;;; +188DC;TANGUT COMPONENT-221;Lo;0;L;;;;;N;;;;; +188DD;TANGUT COMPONENT-222;Lo;0;L;;;;;N;;;;; +188DE;TANGUT COMPONENT-223;Lo;0;L;;;;;N;;;;; +188DF;TANGUT COMPONENT-224;Lo;0;L;;;;;N;;;;; +188E0;TANGUT COMPONENT-225;Lo;0;L;;;;;N;;;;; +188E1;TANGUT COMPONENT-226;Lo;0;L;;;;;N;;;;; +188E2;TANGUT COMPONENT-227;Lo;0;L;;;;;N;;;;; +188E3;TANGUT COMPONENT-228;Lo;0;L;;;;;N;;;;; +188E4;TANGUT COMPONENT-229;Lo;0;L;;;;;N;;;;; +188E5;TANGUT COMPONENT-230;Lo;0;L;;;;;N;;;;; +188E6;TANGUT COMPONENT-231;Lo;0;L;;;;;N;;;;; +188E7;TANGUT COMPONENT-232;Lo;0;L;;;;;N;;;;; +188E8;TANGUT COMPONENT-233;Lo;0;L;;;;;N;;;;; +188E9;TANGUT COMPONENT-234;Lo;0;L;;;;;N;;;;; +188EA;TANGUT COMPONENT-235;Lo;0;L;;;;;N;;;;; +188EB;TANGUT COMPONENT-236;Lo;0;L;;;;;N;;;;; +188EC;TANGUT COMPONENT-237;Lo;0;L;;;;;N;;;;; +188ED;TANGUT COMPONENT-238;Lo;0;L;;;;;N;;;;; +188EE;TANGUT COMPONENT-239;Lo;0;L;;;;;N;;;;; +188EF;TANGUT COMPONENT-240;Lo;0;L;;;;;N;;;;; +188F0;TANGUT COMPONENT-241;Lo;0;L;;;;;N;;;;; +188F1;TANGUT COMPONENT-242;Lo;0;L;;;;;N;;;;; +188F2;TANGUT COMPONENT-243;Lo;0;L;;;;;N;;;;; +188F3;TANGUT COMPONENT-244;Lo;0;L;;;;;N;;;;; +188F4;TANGUT COMPONENT-245;Lo;0;L;;;;;N;;;;; +188F5;TANGUT COMPONENT-246;Lo;0;L;;;;;N;;;;; +188F6;TANGUT COMPONENT-247;Lo;0;L;;;;;N;;;;; +188F7;TANGUT COMPONENT-248;Lo;0;L;;;;;N;;;;; +188F8;TANGUT COMPONENT-249;Lo;0;L;;;;;N;;;;; +188F9;TANGUT COMPONENT-250;Lo;0;L;;;;;N;;;;; +188FA;TANGUT COMPONENT-251;Lo;0;L;;;;;N;;;;; +188FB;TANGUT COMPONENT-252;Lo;0;L;;;;;N;;;;; +188FC;TANGUT COMPONENT-253;Lo;0;L;;;;;N;;;;; +188FD;TANGUT COMPONENT-254;Lo;0;L;;;;;N;;;;; +188FE;TANGUT COMPONENT-255;Lo;0;L;;;;;N;;;;; +188FF;TANGUT COMPONENT-256;Lo;0;L;;;;;N;;;;; +18900;TANGUT COMPONENT-257;Lo;0;L;;;;;N;;;;; +18901;TANGUT COMPONENT-258;Lo;0;L;;;;;N;;;;; +18902;TANGUT COMPONENT-259;Lo;0;L;;;;;N;;;;; +18903;TANGUT COMPONENT-260;Lo;0;L;;;;;N;;;;; +18904;TANGUT COMPONENT-261;Lo;0;L;;;;;N;;;;; +18905;TANGUT COMPONENT-262;Lo;0;L;;;;;N;;;;; +18906;TANGUT COMPONENT-263;Lo;0;L;;;;;N;;;;; +18907;TANGUT COMPONENT-264;Lo;0;L;;;;;N;;;;; +18908;TANGUT COMPONENT-265;Lo;0;L;;;;;N;;;;; +18909;TANGUT COMPONENT-266;Lo;0;L;;;;;N;;;;; +1890A;TANGUT COMPONENT-267;Lo;0;L;;;;;N;;;;; +1890B;TANGUT COMPONENT-268;Lo;0;L;;;;;N;;;;; +1890C;TANGUT COMPONENT-269;Lo;0;L;;;;;N;;;;; +1890D;TANGUT COMPONENT-270;Lo;0;L;;;;;N;;;;; +1890E;TANGUT COMPONENT-271;Lo;0;L;;;;;N;;;;; +1890F;TANGUT COMPONENT-272;Lo;0;L;;;;;N;;;;; +18910;TANGUT COMPONENT-273;Lo;0;L;;;;;N;;;;; +18911;TANGUT COMPONENT-274;Lo;0;L;;;;;N;;;;; +18912;TANGUT COMPONENT-275;Lo;0;L;;;;;N;;;;; +18913;TANGUT COMPONENT-276;Lo;0;L;;;;;N;;;;; +18914;TANGUT COMPONENT-277;Lo;0;L;;;;;N;;;;; +18915;TANGUT COMPONENT-278;Lo;0;L;;;;;N;;;;; +18916;TANGUT COMPONENT-279;Lo;0;L;;;;;N;;;;; +18917;TANGUT COMPONENT-280;Lo;0;L;;;;;N;;;;; +18918;TANGUT COMPONENT-281;Lo;0;L;;;;;N;;;;; +18919;TANGUT COMPONENT-282;Lo;0;L;;;;;N;;;;; +1891A;TANGUT COMPONENT-283;Lo;0;L;;;;;N;;;;; +1891B;TANGUT COMPONENT-284;Lo;0;L;;;;;N;;;;; +1891C;TANGUT COMPONENT-285;Lo;0;L;;;;;N;;;;; +1891D;TANGUT COMPONENT-286;Lo;0;L;;;;;N;;;;; +1891E;TANGUT COMPONENT-287;Lo;0;L;;;;;N;;;;; +1891F;TANGUT COMPONENT-288;Lo;0;L;;;;;N;;;;; +18920;TANGUT COMPONENT-289;Lo;0;L;;;;;N;;;;; +18921;TANGUT COMPONENT-290;Lo;0;L;;;;;N;;;;; +18922;TANGUT COMPONENT-291;Lo;0;L;;;;;N;;;;; +18923;TANGUT COMPONENT-292;Lo;0;L;;;;;N;;;;; +18924;TANGUT COMPONENT-293;Lo;0;L;;;;;N;;;;; +18925;TANGUT COMPONENT-294;Lo;0;L;;;;;N;;;;; +18926;TANGUT COMPONENT-295;Lo;0;L;;;;;N;;;;; +18927;TANGUT COMPONENT-296;Lo;0;L;;;;;N;;;;; +18928;TANGUT COMPONENT-297;Lo;0;L;;;;;N;;;;; +18929;TANGUT COMPONENT-298;Lo;0;L;;;;;N;;;;; +1892A;TANGUT COMPONENT-299;Lo;0;L;;;;;N;;;;; +1892B;TANGUT COMPONENT-300;Lo;0;L;;;;;N;;;;; +1892C;TANGUT COMPONENT-301;Lo;0;L;;;;;N;;;;; +1892D;TANGUT COMPONENT-302;Lo;0;L;;;;;N;;;;; +1892E;TANGUT COMPONENT-303;Lo;0;L;;;;;N;;;;; +1892F;TANGUT COMPONENT-304;Lo;0;L;;;;;N;;;;; +18930;TANGUT COMPONENT-305;Lo;0;L;;;;;N;;;;; +18931;TANGUT COMPONENT-306;Lo;0;L;;;;;N;;;;; +18932;TANGUT COMPONENT-307;Lo;0;L;;;;;N;;;;; +18933;TANGUT COMPONENT-308;Lo;0;L;;;;;N;;;;; +18934;TANGUT COMPONENT-309;Lo;0;L;;;;;N;;;;; +18935;TANGUT COMPONENT-310;Lo;0;L;;;;;N;;;;; +18936;TANGUT COMPONENT-311;Lo;0;L;;;;;N;;;;; +18937;TANGUT COMPONENT-312;Lo;0;L;;;;;N;;;;; +18938;TANGUT COMPONENT-313;Lo;0;L;;;;;N;;;;; +18939;TANGUT COMPONENT-314;Lo;0;L;;;;;N;;;;; +1893A;TANGUT COMPONENT-315;Lo;0;L;;;;;N;;;;; +1893B;TANGUT COMPONENT-316;Lo;0;L;;;;;N;;;;; +1893C;TANGUT COMPONENT-317;Lo;0;L;;;;;N;;;;; +1893D;TANGUT COMPONENT-318;Lo;0;L;;;;;N;;;;; +1893E;TANGUT COMPONENT-319;Lo;0;L;;;;;N;;;;; +1893F;TANGUT COMPONENT-320;Lo;0;L;;;;;N;;;;; +18940;TANGUT COMPONENT-321;Lo;0;L;;;;;N;;;;; +18941;TANGUT COMPONENT-322;Lo;0;L;;;;;N;;;;; +18942;TANGUT COMPONENT-323;Lo;0;L;;;;;N;;;;; +18943;TANGUT COMPONENT-324;Lo;0;L;;;;;N;;;;; +18944;TANGUT COMPONENT-325;Lo;0;L;;;;;N;;;;; +18945;TANGUT COMPONENT-326;Lo;0;L;;;;;N;;;;; +18946;TANGUT COMPONENT-327;Lo;0;L;;;;;N;;;;; +18947;TANGUT COMPONENT-328;Lo;0;L;;;;;N;;;;; +18948;TANGUT COMPONENT-329;Lo;0;L;;;;;N;;;;; +18949;TANGUT COMPONENT-330;Lo;0;L;;;;;N;;;;; +1894A;TANGUT COMPONENT-331;Lo;0;L;;;;;N;;;;; +1894B;TANGUT COMPONENT-332;Lo;0;L;;;;;N;;;;; +1894C;TANGUT COMPONENT-333;Lo;0;L;;;;;N;;;;; +1894D;TANGUT COMPONENT-334;Lo;0;L;;;;;N;;;;; +1894E;TANGUT COMPONENT-335;Lo;0;L;;;;;N;;;;; +1894F;TANGUT COMPONENT-336;Lo;0;L;;;;;N;;;;; +18950;TANGUT COMPONENT-337;Lo;0;L;;;;;N;;;;; +18951;TANGUT COMPONENT-338;Lo;0;L;;;;;N;;;;; +18952;TANGUT COMPONENT-339;Lo;0;L;;;;;N;;;;; +18953;TANGUT COMPONENT-340;Lo;0;L;;;;;N;;;;; +18954;TANGUT COMPONENT-341;Lo;0;L;;;;;N;;;;; +18955;TANGUT COMPONENT-342;Lo;0;L;;;;;N;;;;; +18956;TANGUT COMPONENT-343;Lo;0;L;;;;;N;;;;; +18957;TANGUT COMPONENT-344;Lo;0;L;;;;;N;;;;; +18958;TANGUT COMPONENT-345;Lo;0;L;;;;;N;;;;; +18959;TANGUT COMPONENT-346;Lo;0;L;;;;;N;;;;; +1895A;TANGUT COMPONENT-347;Lo;0;L;;;;;N;;;;; +1895B;TANGUT COMPONENT-348;Lo;0;L;;;;;N;;;;; +1895C;TANGUT COMPONENT-349;Lo;0;L;;;;;N;;;;; +1895D;TANGUT COMPONENT-350;Lo;0;L;;;;;N;;;;; +1895E;TANGUT COMPONENT-351;Lo;0;L;;;;;N;;;;; +1895F;TANGUT COMPONENT-352;Lo;0;L;;;;;N;;;;; +18960;TANGUT COMPONENT-353;Lo;0;L;;;;;N;;;;; +18961;TANGUT COMPONENT-354;Lo;0;L;;;;;N;;;;; +18962;TANGUT COMPONENT-355;Lo;0;L;;;;;N;;;;; +18963;TANGUT COMPONENT-356;Lo;0;L;;;;;N;;;;; +18964;TANGUT COMPONENT-357;Lo;0;L;;;;;N;;;;; +18965;TANGUT COMPONENT-358;Lo;0;L;;;;;N;;;;; +18966;TANGUT COMPONENT-359;Lo;0;L;;;;;N;;;;; +18967;TANGUT COMPONENT-360;Lo;0;L;;;;;N;;;;; +18968;TANGUT COMPONENT-361;Lo;0;L;;;;;N;;;;; +18969;TANGUT COMPONENT-362;Lo;0;L;;;;;N;;;;; +1896A;TANGUT COMPONENT-363;Lo;0;L;;;;;N;;;;; +1896B;TANGUT COMPONENT-364;Lo;0;L;;;;;N;;;;; +1896C;TANGUT COMPONENT-365;Lo;0;L;;;;;N;;;;; +1896D;TANGUT COMPONENT-366;Lo;0;L;;;;;N;;;;; +1896E;TANGUT COMPONENT-367;Lo;0;L;;;;;N;;;;; +1896F;TANGUT COMPONENT-368;Lo;0;L;;;;;N;;;;; +18970;TANGUT COMPONENT-369;Lo;0;L;;;;;N;;;;; +18971;TANGUT COMPONENT-370;Lo;0;L;;;;;N;;;;; +18972;TANGUT COMPONENT-371;Lo;0;L;;;;;N;;;;; +18973;TANGUT COMPONENT-372;Lo;0;L;;;;;N;;;;; +18974;TANGUT COMPONENT-373;Lo;0;L;;;;;N;;;;; +18975;TANGUT COMPONENT-374;Lo;0;L;;;;;N;;;;; +18976;TANGUT COMPONENT-375;Lo;0;L;;;;;N;;;;; +18977;TANGUT COMPONENT-376;Lo;0;L;;;;;N;;;;; +18978;TANGUT COMPONENT-377;Lo;0;L;;;;;N;;;;; +18979;TANGUT COMPONENT-378;Lo;0;L;;;;;N;;;;; +1897A;TANGUT COMPONENT-379;Lo;0;L;;;;;N;;;;; +1897B;TANGUT COMPONENT-380;Lo;0;L;;;;;N;;;;; +1897C;TANGUT COMPONENT-381;Lo;0;L;;;;;N;;;;; +1897D;TANGUT COMPONENT-382;Lo;0;L;;;;;N;;;;; +1897E;TANGUT COMPONENT-383;Lo;0;L;;;;;N;;;;; +1897F;TANGUT COMPONENT-384;Lo;0;L;;;;;N;;;;; +18980;TANGUT COMPONENT-385;Lo;0;L;;;;;N;;;;; +18981;TANGUT COMPONENT-386;Lo;0;L;;;;;N;;;;; +18982;TANGUT COMPONENT-387;Lo;0;L;;;;;N;;;;; +18983;TANGUT COMPONENT-388;Lo;0;L;;;;;N;;;;; +18984;TANGUT COMPONENT-389;Lo;0;L;;;;;N;;;;; +18985;TANGUT COMPONENT-390;Lo;0;L;;;;;N;;;;; +18986;TANGUT COMPONENT-391;Lo;0;L;;;;;N;;;;; +18987;TANGUT COMPONENT-392;Lo;0;L;;;;;N;;;;; +18988;TANGUT COMPONENT-393;Lo;0;L;;;;;N;;;;; +18989;TANGUT COMPONENT-394;Lo;0;L;;;;;N;;;;; +1898A;TANGUT COMPONENT-395;Lo;0;L;;;;;N;;;;; +1898B;TANGUT COMPONENT-396;Lo;0;L;;;;;N;;;;; +1898C;TANGUT COMPONENT-397;Lo;0;L;;;;;N;;;;; +1898D;TANGUT COMPONENT-398;Lo;0;L;;;;;N;;;;; +1898E;TANGUT COMPONENT-399;Lo;0;L;;;;;N;;;;; +1898F;TANGUT COMPONENT-400;Lo;0;L;;;;;N;;;;; +18990;TANGUT COMPONENT-401;Lo;0;L;;;;;N;;;;; +18991;TANGUT COMPONENT-402;Lo;0;L;;;;;N;;;;; +18992;TANGUT COMPONENT-403;Lo;0;L;;;;;N;;;;; +18993;TANGUT COMPONENT-404;Lo;0;L;;;;;N;;;;; +18994;TANGUT COMPONENT-405;Lo;0;L;;;;;N;;;;; +18995;TANGUT COMPONENT-406;Lo;0;L;;;;;N;;;;; +18996;TANGUT COMPONENT-407;Lo;0;L;;;;;N;;;;; +18997;TANGUT COMPONENT-408;Lo;0;L;;;;;N;;;;; +18998;TANGUT COMPONENT-409;Lo;0;L;;;;;N;;;;; +18999;TANGUT COMPONENT-410;Lo;0;L;;;;;N;;;;; +1899A;TANGUT COMPONENT-411;Lo;0;L;;;;;N;;;;; +1899B;TANGUT COMPONENT-412;Lo;0;L;;;;;N;;;;; +1899C;TANGUT COMPONENT-413;Lo;0;L;;;;;N;;;;; +1899D;TANGUT COMPONENT-414;Lo;0;L;;;;;N;;;;; +1899E;TANGUT COMPONENT-415;Lo;0;L;;;;;N;;;;; +1899F;TANGUT COMPONENT-416;Lo;0;L;;;;;N;;;;; +189A0;TANGUT COMPONENT-417;Lo;0;L;;;;;N;;;;; +189A1;TANGUT COMPONENT-418;Lo;0;L;;;;;N;;;;; +189A2;TANGUT COMPONENT-419;Lo;0;L;;;;;N;;;;; +189A3;TANGUT COMPONENT-420;Lo;0;L;;;;;N;;;;; +189A4;TANGUT COMPONENT-421;Lo;0;L;;;;;N;;;;; +189A5;TANGUT COMPONENT-422;Lo;0;L;;;;;N;;;;; +189A6;TANGUT COMPONENT-423;Lo;0;L;;;;;N;;;;; +189A7;TANGUT COMPONENT-424;Lo;0;L;;;;;N;;;;; +189A8;TANGUT COMPONENT-425;Lo;0;L;;;;;N;;;;; +189A9;TANGUT COMPONENT-426;Lo;0;L;;;;;N;;;;; +189AA;TANGUT COMPONENT-427;Lo;0;L;;;;;N;;;;; +189AB;TANGUT COMPONENT-428;Lo;0;L;;;;;N;;;;; +189AC;TANGUT COMPONENT-429;Lo;0;L;;;;;N;;;;; +189AD;TANGUT COMPONENT-430;Lo;0;L;;;;;N;;;;; +189AE;TANGUT COMPONENT-431;Lo;0;L;;;;;N;;;;; +189AF;TANGUT COMPONENT-432;Lo;0;L;;;;;N;;;;; +189B0;TANGUT COMPONENT-433;Lo;0;L;;;;;N;;;;; +189B1;TANGUT COMPONENT-434;Lo;0;L;;;;;N;;;;; +189B2;TANGUT COMPONENT-435;Lo;0;L;;;;;N;;;;; +189B3;TANGUT COMPONENT-436;Lo;0;L;;;;;N;;;;; +189B4;TANGUT COMPONENT-437;Lo;0;L;;;;;N;;;;; +189B5;TANGUT COMPONENT-438;Lo;0;L;;;;;N;;;;; +189B6;TANGUT COMPONENT-439;Lo;0;L;;;;;N;;;;; +189B7;TANGUT COMPONENT-440;Lo;0;L;;;;;N;;;;; +189B8;TANGUT COMPONENT-441;Lo;0;L;;;;;N;;;;; +189B9;TANGUT COMPONENT-442;Lo;0;L;;;;;N;;;;; +189BA;TANGUT COMPONENT-443;Lo;0;L;;;;;N;;;;; +189BB;TANGUT COMPONENT-444;Lo;0;L;;;;;N;;;;; +189BC;TANGUT COMPONENT-445;Lo;0;L;;;;;N;;;;; +189BD;TANGUT COMPONENT-446;Lo;0;L;;;;;N;;;;; +189BE;TANGUT COMPONENT-447;Lo;0;L;;;;;N;;;;; +189BF;TANGUT COMPONENT-448;Lo;0;L;;;;;N;;;;; +189C0;TANGUT COMPONENT-449;Lo;0;L;;;;;N;;;;; +189C1;TANGUT COMPONENT-450;Lo;0;L;;;;;N;;;;; +189C2;TANGUT COMPONENT-451;Lo;0;L;;;;;N;;;;; +189C3;TANGUT COMPONENT-452;Lo;0;L;;;;;N;;;;; +189C4;TANGUT COMPONENT-453;Lo;0;L;;;;;N;;;;; +189C5;TANGUT COMPONENT-454;Lo;0;L;;;;;N;;;;; +189C6;TANGUT COMPONENT-455;Lo;0;L;;;;;N;;;;; +189C7;TANGUT COMPONENT-456;Lo;0;L;;;;;N;;;;; +189C8;TANGUT COMPONENT-457;Lo;0;L;;;;;N;;;;; +189C9;TANGUT COMPONENT-458;Lo;0;L;;;;;N;;;;; +189CA;TANGUT COMPONENT-459;Lo;0;L;;;;;N;;;;; +189CB;TANGUT COMPONENT-460;Lo;0;L;;;;;N;;;;; +189CC;TANGUT COMPONENT-461;Lo;0;L;;;;;N;;;;; +189CD;TANGUT COMPONENT-462;Lo;0;L;;;;;N;;;;; +189CE;TANGUT COMPONENT-463;Lo;0;L;;;;;N;;;;; +189CF;TANGUT COMPONENT-464;Lo;0;L;;;;;N;;;;; +189D0;TANGUT COMPONENT-465;Lo;0;L;;;;;N;;;;; +189D1;TANGUT COMPONENT-466;Lo;0;L;;;;;N;;;;; +189D2;TANGUT COMPONENT-467;Lo;0;L;;;;;N;;;;; +189D3;TANGUT COMPONENT-468;Lo;0;L;;;;;N;;;;; +189D4;TANGUT COMPONENT-469;Lo;0;L;;;;;N;;;;; +189D5;TANGUT COMPONENT-470;Lo;0;L;;;;;N;;;;; +189D6;TANGUT COMPONENT-471;Lo;0;L;;;;;N;;;;; +189D7;TANGUT COMPONENT-472;Lo;0;L;;;;;N;;;;; +189D8;TANGUT COMPONENT-473;Lo;0;L;;;;;N;;;;; +189D9;TANGUT COMPONENT-474;Lo;0;L;;;;;N;;;;; +189DA;TANGUT COMPONENT-475;Lo;0;L;;;;;N;;;;; +189DB;TANGUT COMPONENT-476;Lo;0;L;;;;;N;;;;; +189DC;TANGUT COMPONENT-477;Lo;0;L;;;;;N;;;;; +189DD;TANGUT COMPONENT-478;Lo;0;L;;;;;N;;;;; +189DE;TANGUT COMPONENT-479;Lo;0;L;;;;;N;;;;; +189DF;TANGUT COMPONENT-480;Lo;0;L;;;;;N;;;;; +189E0;TANGUT COMPONENT-481;Lo;0;L;;;;;N;;;;; +189E1;TANGUT COMPONENT-482;Lo;0;L;;;;;N;;;;; +189E2;TANGUT COMPONENT-483;Lo;0;L;;;;;N;;;;; +189E3;TANGUT COMPONENT-484;Lo;0;L;;;;;N;;;;; +189E4;TANGUT COMPONENT-485;Lo;0;L;;;;;N;;;;; +189E5;TANGUT COMPONENT-486;Lo;0;L;;;;;N;;;;; +189E6;TANGUT COMPONENT-487;Lo;0;L;;;;;N;;;;; +189E7;TANGUT COMPONENT-488;Lo;0;L;;;;;N;;;;; +189E8;TANGUT COMPONENT-489;Lo;0;L;;;;;N;;;;; +189E9;TANGUT COMPONENT-490;Lo;0;L;;;;;N;;;;; +189EA;TANGUT COMPONENT-491;Lo;0;L;;;;;N;;;;; +189EB;TANGUT COMPONENT-492;Lo;0;L;;;;;N;;;;; +189EC;TANGUT COMPONENT-493;Lo;0;L;;;;;N;;;;; +189ED;TANGUT COMPONENT-494;Lo;0;L;;;;;N;;;;; +189EE;TANGUT COMPONENT-495;Lo;0;L;;;;;N;;;;; +189EF;TANGUT COMPONENT-496;Lo;0;L;;;;;N;;;;; +189F0;TANGUT COMPONENT-497;Lo;0;L;;;;;N;;;;; +189F1;TANGUT COMPONENT-498;Lo;0;L;;;;;N;;;;; +189F2;TANGUT COMPONENT-499;Lo;0;L;;;;;N;;;;; +189F3;TANGUT COMPONENT-500;Lo;0;L;;;;;N;;;;; +189F4;TANGUT COMPONENT-501;Lo;0;L;;;;;N;;;;; +189F5;TANGUT COMPONENT-502;Lo;0;L;;;;;N;;;;; +189F6;TANGUT COMPONENT-503;Lo;0;L;;;;;N;;;;; +189F7;TANGUT COMPONENT-504;Lo;0;L;;;;;N;;;;; +189F8;TANGUT COMPONENT-505;Lo;0;L;;;;;N;;;;; +189F9;TANGUT COMPONENT-506;Lo;0;L;;;;;N;;;;; +189FA;TANGUT COMPONENT-507;Lo;0;L;;;;;N;;;;; +189FB;TANGUT COMPONENT-508;Lo;0;L;;;;;N;;;;; +189FC;TANGUT COMPONENT-509;Lo;0;L;;;;;N;;;;; +189FD;TANGUT COMPONENT-510;Lo;0;L;;;;;N;;;;; +189FE;TANGUT COMPONENT-511;Lo;0;L;;;;;N;;;;; +189FF;TANGUT COMPONENT-512;Lo;0;L;;;;;N;;;;; +18A00;TANGUT COMPONENT-513;Lo;0;L;;;;;N;;;;; +18A01;TANGUT COMPONENT-514;Lo;0;L;;;;;N;;;;; +18A02;TANGUT COMPONENT-515;Lo;0;L;;;;;N;;;;; +18A03;TANGUT COMPONENT-516;Lo;0;L;;;;;N;;;;; +18A04;TANGUT COMPONENT-517;Lo;0;L;;;;;N;;;;; +18A05;TANGUT COMPONENT-518;Lo;0;L;;;;;N;;;;; +18A06;TANGUT COMPONENT-519;Lo;0;L;;;;;N;;;;; +18A07;TANGUT COMPONENT-520;Lo;0;L;;;;;N;;;;; +18A08;TANGUT COMPONENT-521;Lo;0;L;;;;;N;;;;; +18A09;TANGUT COMPONENT-522;Lo;0;L;;;;;N;;;;; +18A0A;TANGUT COMPONENT-523;Lo;0;L;;;;;N;;;;; +18A0B;TANGUT COMPONENT-524;Lo;0;L;;;;;N;;;;; +18A0C;TANGUT COMPONENT-525;Lo;0;L;;;;;N;;;;; +18A0D;TANGUT COMPONENT-526;Lo;0;L;;;;;N;;;;; +18A0E;TANGUT COMPONENT-527;Lo;0;L;;;;;N;;;;; +18A0F;TANGUT COMPONENT-528;Lo;0;L;;;;;N;;;;; +18A10;TANGUT COMPONENT-529;Lo;0;L;;;;;N;;;;; +18A11;TANGUT COMPONENT-530;Lo;0;L;;;;;N;;;;; +18A12;TANGUT COMPONENT-531;Lo;0;L;;;;;N;;;;; +18A13;TANGUT COMPONENT-532;Lo;0;L;;;;;N;;;;; +18A14;TANGUT COMPONENT-533;Lo;0;L;;;;;N;;;;; +18A15;TANGUT COMPONENT-534;Lo;0;L;;;;;N;;;;; +18A16;TANGUT COMPONENT-535;Lo;0;L;;;;;N;;;;; +18A17;TANGUT COMPONENT-536;Lo;0;L;;;;;N;;;;; +18A18;TANGUT COMPONENT-537;Lo;0;L;;;;;N;;;;; +18A19;TANGUT COMPONENT-538;Lo;0;L;;;;;N;;;;; +18A1A;TANGUT COMPONENT-539;Lo;0;L;;;;;N;;;;; +18A1B;TANGUT COMPONENT-540;Lo;0;L;;;;;N;;;;; +18A1C;TANGUT COMPONENT-541;Lo;0;L;;;;;N;;;;; +18A1D;TANGUT COMPONENT-542;Lo;0;L;;;;;N;;;;; +18A1E;TANGUT COMPONENT-543;Lo;0;L;;;;;N;;;;; +18A1F;TANGUT COMPONENT-544;Lo;0;L;;;;;N;;;;; +18A20;TANGUT COMPONENT-545;Lo;0;L;;;;;N;;;;; +18A21;TANGUT COMPONENT-546;Lo;0;L;;;;;N;;;;; +18A22;TANGUT COMPONENT-547;Lo;0;L;;;;;N;;;;; +18A23;TANGUT COMPONENT-548;Lo;0;L;;;;;N;;;;; +18A24;TANGUT COMPONENT-549;Lo;0;L;;;;;N;;;;; +18A25;TANGUT COMPONENT-550;Lo;0;L;;;;;N;;;;; +18A26;TANGUT COMPONENT-551;Lo;0;L;;;;;N;;;;; +18A27;TANGUT COMPONENT-552;Lo;0;L;;;;;N;;;;; +18A28;TANGUT COMPONENT-553;Lo;0;L;;;;;N;;;;; +18A29;TANGUT COMPONENT-554;Lo;0;L;;;;;N;;;;; +18A2A;TANGUT COMPONENT-555;Lo;0;L;;;;;N;;;;; +18A2B;TANGUT COMPONENT-556;Lo;0;L;;;;;N;;;;; +18A2C;TANGUT COMPONENT-557;Lo;0;L;;;;;N;;;;; +18A2D;TANGUT COMPONENT-558;Lo;0;L;;;;;N;;;;; +18A2E;TANGUT COMPONENT-559;Lo;0;L;;;;;N;;;;; +18A2F;TANGUT COMPONENT-560;Lo;0;L;;;;;N;;;;; +18A30;TANGUT COMPONENT-561;Lo;0;L;;;;;N;;;;; +18A31;TANGUT COMPONENT-562;Lo;0;L;;;;;N;;;;; +18A32;TANGUT COMPONENT-563;Lo;0;L;;;;;N;;;;; +18A33;TANGUT COMPONENT-564;Lo;0;L;;;;;N;;;;; +18A34;TANGUT COMPONENT-565;Lo;0;L;;;;;N;;;;; +18A35;TANGUT COMPONENT-566;Lo;0;L;;;;;N;;;;; +18A36;TANGUT COMPONENT-567;Lo;0;L;;;;;N;;;;; +18A37;TANGUT COMPONENT-568;Lo;0;L;;;;;N;;;;; +18A38;TANGUT COMPONENT-569;Lo;0;L;;;;;N;;;;; +18A39;TANGUT COMPONENT-570;Lo;0;L;;;;;N;;;;; +18A3A;TANGUT COMPONENT-571;Lo;0;L;;;;;N;;;;; +18A3B;TANGUT COMPONENT-572;Lo;0;L;;;;;N;;;;; +18A3C;TANGUT COMPONENT-573;Lo;0;L;;;;;N;;;;; +18A3D;TANGUT COMPONENT-574;Lo;0;L;;;;;N;;;;; +18A3E;TANGUT COMPONENT-575;Lo;0;L;;;;;N;;;;; +18A3F;TANGUT COMPONENT-576;Lo;0;L;;;;;N;;;;; +18A40;TANGUT COMPONENT-577;Lo;0;L;;;;;N;;;;; +18A41;TANGUT COMPONENT-578;Lo;0;L;;;;;N;;;;; +18A42;TANGUT COMPONENT-579;Lo;0;L;;;;;N;;;;; +18A43;TANGUT COMPONENT-580;Lo;0;L;;;;;N;;;;; +18A44;TANGUT COMPONENT-581;Lo;0;L;;;;;N;;;;; +18A45;TANGUT COMPONENT-582;Lo;0;L;;;;;N;;;;; +18A46;TANGUT COMPONENT-583;Lo;0;L;;;;;N;;;;; +18A47;TANGUT COMPONENT-584;Lo;0;L;;;;;N;;;;; +18A48;TANGUT COMPONENT-585;Lo;0;L;;;;;N;;;;; +18A49;TANGUT COMPONENT-586;Lo;0;L;;;;;N;;;;; +18A4A;TANGUT COMPONENT-587;Lo;0;L;;;;;N;;;;; +18A4B;TANGUT COMPONENT-588;Lo;0;L;;;;;N;;;;; +18A4C;TANGUT COMPONENT-589;Lo;0;L;;;;;N;;;;; +18A4D;TANGUT COMPONENT-590;Lo;0;L;;;;;N;;;;; +18A4E;TANGUT COMPONENT-591;Lo;0;L;;;;;N;;;;; +18A4F;TANGUT COMPONENT-592;Lo;0;L;;;;;N;;;;; +18A50;TANGUT COMPONENT-593;Lo;0;L;;;;;N;;;;; +18A51;TANGUT COMPONENT-594;Lo;0;L;;;;;N;;;;; +18A52;TANGUT COMPONENT-595;Lo;0;L;;;;;N;;;;; +18A53;TANGUT COMPONENT-596;Lo;0;L;;;;;N;;;;; +18A54;TANGUT COMPONENT-597;Lo;0;L;;;;;N;;;;; +18A55;TANGUT COMPONENT-598;Lo;0;L;;;;;N;;;;; +18A56;TANGUT COMPONENT-599;Lo;0;L;;;;;N;;;;; +18A57;TANGUT COMPONENT-600;Lo;0;L;;;;;N;;;;; +18A58;TANGUT COMPONENT-601;Lo;0;L;;;;;N;;;;; +18A59;TANGUT COMPONENT-602;Lo;0;L;;;;;N;;;;; +18A5A;TANGUT COMPONENT-603;Lo;0;L;;;;;N;;;;; +18A5B;TANGUT COMPONENT-604;Lo;0;L;;;;;N;;;;; +18A5C;TANGUT COMPONENT-605;Lo;0;L;;;;;N;;;;; +18A5D;TANGUT COMPONENT-606;Lo;0;L;;;;;N;;;;; +18A5E;TANGUT COMPONENT-607;Lo;0;L;;;;;N;;;;; +18A5F;TANGUT COMPONENT-608;Lo;0;L;;;;;N;;;;; +18A60;TANGUT COMPONENT-609;Lo;0;L;;;;;N;;;;; +18A61;TANGUT COMPONENT-610;Lo;0;L;;;;;N;;;;; +18A62;TANGUT COMPONENT-611;Lo;0;L;;;;;N;;;;; +18A63;TANGUT COMPONENT-612;Lo;0;L;;;;;N;;;;; +18A64;TANGUT COMPONENT-613;Lo;0;L;;;;;N;;;;; +18A65;TANGUT COMPONENT-614;Lo;0;L;;;;;N;;;;; +18A66;TANGUT COMPONENT-615;Lo;0;L;;;;;N;;;;; +18A67;TANGUT COMPONENT-616;Lo;0;L;;;;;N;;;;; +18A68;TANGUT COMPONENT-617;Lo;0;L;;;;;N;;;;; +18A69;TANGUT COMPONENT-618;Lo;0;L;;;;;N;;;;; +18A6A;TANGUT COMPONENT-619;Lo;0;L;;;;;N;;;;; +18A6B;TANGUT COMPONENT-620;Lo;0;L;;;;;N;;;;; +18A6C;TANGUT COMPONENT-621;Lo;0;L;;;;;N;;;;; +18A6D;TANGUT COMPONENT-622;Lo;0;L;;;;;N;;;;; +18A6E;TANGUT COMPONENT-623;Lo;0;L;;;;;N;;;;; +18A6F;TANGUT COMPONENT-624;Lo;0;L;;;;;N;;;;; +18A70;TANGUT COMPONENT-625;Lo;0;L;;;;;N;;;;; +18A71;TANGUT COMPONENT-626;Lo;0;L;;;;;N;;;;; +18A72;TANGUT COMPONENT-627;Lo;0;L;;;;;N;;;;; +18A73;TANGUT COMPONENT-628;Lo;0;L;;;;;N;;;;; +18A74;TANGUT COMPONENT-629;Lo;0;L;;;;;N;;;;; +18A75;TANGUT COMPONENT-630;Lo;0;L;;;;;N;;;;; +18A76;TANGUT COMPONENT-631;Lo;0;L;;;;;N;;;;; +18A77;TANGUT COMPONENT-632;Lo;0;L;;;;;N;;;;; +18A78;TANGUT COMPONENT-633;Lo;0;L;;;;;N;;;;; +18A79;TANGUT COMPONENT-634;Lo;0;L;;;;;N;;;;; +18A7A;TANGUT COMPONENT-635;Lo;0;L;;;;;N;;;;; +18A7B;TANGUT COMPONENT-636;Lo;0;L;;;;;N;;;;; +18A7C;TANGUT COMPONENT-637;Lo;0;L;;;;;N;;;;; +18A7D;TANGUT COMPONENT-638;Lo;0;L;;;;;N;;;;; +18A7E;TANGUT COMPONENT-639;Lo;0;L;;;;;N;;;;; +18A7F;TANGUT COMPONENT-640;Lo;0;L;;;;;N;;;;; +18A80;TANGUT COMPONENT-641;Lo;0;L;;;;;N;;;;; +18A81;TANGUT COMPONENT-642;Lo;0;L;;;;;N;;;;; +18A82;TANGUT COMPONENT-643;Lo;0;L;;;;;N;;;;; +18A83;TANGUT COMPONENT-644;Lo;0;L;;;;;N;;;;; +18A84;TANGUT COMPONENT-645;Lo;0;L;;;;;N;;;;; +18A85;TANGUT COMPONENT-646;Lo;0;L;;;;;N;;;;; +18A86;TANGUT COMPONENT-647;Lo;0;L;;;;;N;;;;; +18A87;TANGUT COMPONENT-648;Lo;0;L;;;;;N;;;;; +18A88;TANGUT COMPONENT-649;Lo;0;L;;;;;N;;;;; +18A89;TANGUT COMPONENT-650;Lo;0;L;;;;;N;;;;; +18A8A;TANGUT COMPONENT-651;Lo;0;L;;;;;N;;;;; +18A8B;TANGUT COMPONENT-652;Lo;0;L;;;;;N;;;;; +18A8C;TANGUT COMPONENT-653;Lo;0;L;;;;;N;;;;; +18A8D;TANGUT COMPONENT-654;Lo;0;L;;;;;N;;;;; +18A8E;TANGUT COMPONENT-655;Lo;0;L;;;;;N;;;;; +18A8F;TANGUT COMPONENT-656;Lo;0;L;;;;;N;;;;; +18A90;TANGUT COMPONENT-657;Lo;0;L;;;;;N;;;;; +18A91;TANGUT COMPONENT-658;Lo;0;L;;;;;N;;;;; +18A92;TANGUT COMPONENT-659;Lo;0;L;;;;;N;;;;; +18A93;TANGUT COMPONENT-660;Lo;0;L;;;;;N;;;;; +18A94;TANGUT COMPONENT-661;Lo;0;L;;;;;N;;;;; +18A95;TANGUT COMPONENT-662;Lo;0;L;;;;;N;;;;; +18A96;TANGUT COMPONENT-663;Lo;0;L;;;;;N;;;;; +18A97;TANGUT COMPONENT-664;Lo;0;L;;;;;N;;;;; +18A98;TANGUT COMPONENT-665;Lo;0;L;;;;;N;;;;; +18A99;TANGUT COMPONENT-666;Lo;0;L;;;;;N;;;;; +18A9A;TANGUT COMPONENT-667;Lo;0;L;;;;;N;;;;; +18A9B;TANGUT COMPONENT-668;Lo;0;L;;;;;N;;;;; +18A9C;TANGUT COMPONENT-669;Lo;0;L;;;;;N;;;;; +18A9D;TANGUT COMPONENT-670;Lo;0;L;;;;;N;;;;; +18A9E;TANGUT COMPONENT-671;Lo;0;L;;;;;N;;;;; +18A9F;TANGUT COMPONENT-672;Lo;0;L;;;;;N;;;;; +18AA0;TANGUT COMPONENT-673;Lo;0;L;;;;;N;;;;; +18AA1;TANGUT COMPONENT-674;Lo;0;L;;;;;N;;;;; +18AA2;TANGUT COMPONENT-675;Lo;0;L;;;;;N;;;;; +18AA3;TANGUT COMPONENT-676;Lo;0;L;;;;;N;;;;; +18AA4;TANGUT COMPONENT-677;Lo;0;L;;;;;N;;;;; +18AA5;TANGUT COMPONENT-678;Lo;0;L;;;;;N;;;;; +18AA6;TANGUT COMPONENT-679;Lo;0;L;;;;;N;;;;; +18AA7;TANGUT COMPONENT-680;Lo;0;L;;;;;N;;;;; +18AA8;TANGUT COMPONENT-681;Lo;0;L;;;;;N;;;;; +18AA9;TANGUT COMPONENT-682;Lo;0;L;;;;;N;;;;; +18AAA;TANGUT COMPONENT-683;Lo;0;L;;;;;N;;;;; +18AAB;TANGUT COMPONENT-684;Lo;0;L;;;;;N;;;;; +18AAC;TANGUT COMPONENT-685;Lo;0;L;;;;;N;;;;; +18AAD;TANGUT COMPONENT-686;Lo;0;L;;;;;N;;;;; +18AAE;TANGUT COMPONENT-687;Lo;0;L;;;;;N;;;;; +18AAF;TANGUT COMPONENT-688;Lo;0;L;;;;;N;;;;; +18AB0;TANGUT COMPONENT-689;Lo;0;L;;;;;N;;;;; +18AB1;TANGUT COMPONENT-690;Lo;0;L;;;;;N;;;;; +18AB2;TANGUT COMPONENT-691;Lo;0;L;;;;;N;;;;; +18AB3;TANGUT COMPONENT-692;Lo;0;L;;;;;N;;;;; +18AB4;TANGUT COMPONENT-693;Lo;0;L;;;;;N;;;;; +18AB5;TANGUT COMPONENT-694;Lo;0;L;;;;;N;;;;; +18AB6;TANGUT COMPONENT-695;Lo;0;L;;;;;N;;;;; +18AB7;TANGUT COMPONENT-696;Lo;0;L;;;;;N;;;;; +18AB8;TANGUT COMPONENT-697;Lo;0;L;;;;;N;;;;; +18AB9;TANGUT COMPONENT-698;Lo;0;L;;;;;N;;;;; +18ABA;TANGUT COMPONENT-699;Lo;0;L;;;;;N;;;;; +18ABB;TANGUT COMPONENT-700;Lo;0;L;;;;;N;;;;; +18ABC;TANGUT COMPONENT-701;Lo;0;L;;;;;N;;;;; +18ABD;TANGUT COMPONENT-702;Lo;0;L;;;;;N;;;;; +18ABE;TANGUT COMPONENT-703;Lo;0;L;;;;;N;;;;; +18ABF;TANGUT COMPONENT-704;Lo;0;L;;;;;N;;;;; +18AC0;TANGUT COMPONENT-705;Lo;0;L;;;;;N;;;;; +18AC1;TANGUT COMPONENT-706;Lo;0;L;;;;;N;;;;; +18AC2;TANGUT COMPONENT-707;Lo;0;L;;;;;N;;;;; +18AC3;TANGUT COMPONENT-708;Lo;0;L;;;;;N;;;;; +18AC4;TANGUT COMPONENT-709;Lo;0;L;;;;;N;;;;; +18AC5;TANGUT COMPONENT-710;Lo;0;L;;;;;N;;;;; +18AC6;TANGUT COMPONENT-711;Lo;0;L;;;;;N;;;;; +18AC7;TANGUT COMPONENT-712;Lo;0;L;;;;;N;;;;; +18AC8;TANGUT COMPONENT-713;Lo;0;L;;;;;N;;;;; +18AC9;TANGUT COMPONENT-714;Lo;0;L;;;;;N;;;;; +18ACA;TANGUT COMPONENT-715;Lo;0;L;;;;;N;;;;; +18ACB;TANGUT COMPONENT-716;Lo;0;L;;;;;N;;;;; +18ACC;TANGUT COMPONENT-717;Lo;0;L;;;;;N;;;;; +18ACD;TANGUT COMPONENT-718;Lo;0;L;;;;;N;;;;; +18ACE;TANGUT COMPONENT-719;Lo;0;L;;;;;N;;;;; +18ACF;TANGUT COMPONENT-720;Lo;0;L;;;;;N;;;;; +18AD0;TANGUT COMPONENT-721;Lo;0;L;;;;;N;;;;; +18AD1;TANGUT COMPONENT-722;Lo;0;L;;;;;N;;;;; +18AD2;TANGUT COMPONENT-723;Lo;0;L;;;;;N;;;;; +18AD3;TANGUT COMPONENT-724;Lo;0;L;;;;;N;;;;; +18AD4;TANGUT COMPONENT-725;Lo;0;L;;;;;N;;;;; +18AD5;TANGUT COMPONENT-726;Lo;0;L;;;;;N;;;;; +18AD6;TANGUT COMPONENT-727;Lo;0;L;;;;;N;;;;; +18AD7;TANGUT COMPONENT-728;Lo;0;L;;;;;N;;;;; +18AD8;TANGUT COMPONENT-729;Lo;0;L;;;;;N;;;;; +18AD9;TANGUT COMPONENT-730;Lo;0;L;;;;;N;;;;; +18ADA;TANGUT COMPONENT-731;Lo;0;L;;;;;N;;;;; +18ADB;TANGUT COMPONENT-732;Lo;0;L;;;;;N;;;;; +18ADC;TANGUT COMPONENT-733;Lo;0;L;;;;;N;;;;; +18ADD;TANGUT COMPONENT-734;Lo;0;L;;;;;N;;;;; +18ADE;TANGUT COMPONENT-735;Lo;0;L;;;;;N;;;;; +18ADF;TANGUT COMPONENT-736;Lo;0;L;;;;;N;;;;; +18AE0;TANGUT COMPONENT-737;Lo;0;L;;;;;N;;;;; +18AE1;TANGUT COMPONENT-738;Lo;0;L;;;;;N;;;;; +18AE2;TANGUT COMPONENT-739;Lo;0;L;;;;;N;;;;; +18AE3;TANGUT COMPONENT-740;Lo;0;L;;;;;N;;;;; +18AE4;TANGUT COMPONENT-741;Lo;0;L;;;;;N;;;;; +18AE5;TANGUT COMPONENT-742;Lo;0;L;;;;;N;;;;; +18AE6;TANGUT COMPONENT-743;Lo;0;L;;;;;N;;;;; +18AE7;TANGUT COMPONENT-744;Lo;0;L;;;;;N;;;;; +18AE8;TANGUT COMPONENT-745;Lo;0;L;;;;;N;;;;; +18AE9;TANGUT COMPONENT-746;Lo;0;L;;;;;N;;;;; +18AEA;TANGUT COMPONENT-747;Lo;0;L;;;;;N;;;;; +18AEB;TANGUT COMPONENT-748;Lo;0;L;;;;;N;;;;; +18AEC;TANGUT COMPONENT-749;Lo;0;L;;;;;N;;;;; +18AED;TANGUT COMPONENT-750;Lo;0;L;;;;;N;;;;; +18AEE;TANGUT COMPONENT-751;Lo;0;L;;;;;N;;;;; +18AEF;TANGUT COMPONENT-752;Lo;0;L;;;;;N;;;;; +18AF0;TANGUT COMPONENT-753;Lo;0;L;;;;;N;;;;; +18AF1;TANGUT COMPONENT-754;Lo;0;L;;;;;N;;;;; +18AF2;TANGUT COMPONENT-755;Lo;0;L;;;;;N;;;;; +18AF3;TANGUT COMPONENT-756;Lo;0;L;;;;;N;;;;; +18AF4;TANGUT COMPONENT-757;Lo;0;L;;;;;N;;;;; +18AF5;TANGUT COMPONENT-758;Lo;0;L;;;;;N;;;;; +18AF6;TANGUT COMPONENT-759;Lo;0;L;;;;;N;;;;; +18AF7;TANGUT COMPONENT-760;Lo;0;L;;;;;N;;;;; +18AF8;TANGUT COMPONENT-761;Lo;0;L;;;;;N;;;;; +18AF9;TANGUT COMPONENT-762;Lo;0;L;;;;;N;;;;; +18AFA;TANGUT COMPONENT-763;Lo;0;L;;;;;N;;;;; +18AFB;TANGUT COMPONENT-764;Lo;0;L;;;;;N;;;;; +18AFC;TANGUT COMPONENT-765;Lo;0;L;;;;;N;;;;; +18AFD;TANGUT COMPONENT-766;Lo;0;L;;;;;N;;;;; +18AFE;TANGUT COMPONENT-767;Lo;0;L;;;;;N;;;;; +18AFF;TANGUT COMPONENT-768;Lo;0;L;;;;;N;;;;; +18B00;KHITAN SMALL SCRIPT CHARACTER-18B00;Lo;0;L;;;;;N;;;;; +18B01;KHITAN SMALL SCRIPT CHARACTER-18B01;Lo;0;L;;;;;N;;;;; +18B02;KHITAN SMALL SCRIPT CHARACTER-18B02;Lo;0;L;;;;;N;;;;; +18B03;KHITAN SMALL SCRIPT CHARACTER-18B03;Lo;0;L;;;;;N;;;;; +18B04;KHITAN SMALL SCRIPT CHARACTER-18B04;Lo;0;L;;;;;N;;;;; +18B05;KHITAN SMALL SCRIPT CHARACTER-18B05;Lo;0;L;;;;;N;;;;; +18B06;KHITAN SMALL SCRIPT CHARACTER-18B06;Lo;0;L;;;;;N;;;;; +18B07;KHITAN SMALL SCRIPT CHARACTER-18B07;Lo;0;L;;;;;N;;;;; +18B08;KHITAN SMALL SCRIPT CHARACTER-18B08;Lo;0;L;;;;;N;;;;; +18B09;KHITAN SMALL SCRIPT CHARACTER-18B09;Lo;0;L;;;;;N;;;;; +18B0A;KHITAN SMALL SCRIPT CHARACTER-18B0A;Lo;0;L;;;;;N;;;;; +18B0B;KHITAN SMALL SCRIPT CHARACTER-18B0B;Lo;0;L;;;;;N;;;;; +18B0C;KHITAN SMALL SCRIPT CHARACTER-18B0C;Lo;0;L;;;;;N;;;;; +18B0D;KHITAN SMALL SCRIPT CHARACTER-18B0D;Lo;0;L;;;;;N;;;;; +18B0E;KHITAN SMALL SCRIPT CHARACTER-18B0E;Lo;0;L;;;;;N;;;;; +18B0F;KHITAN SMALL SCRIPT CHARACTER-18B0F;Lo;0;L;;;;;N;;;;; +18B10;KHITAN SMALL SCRIPT CHARACTER-18B10;Lo;0;L;;;;;N;;;;; +18B11;KHITAN SMALL SCRIPT CHARACTER-18B11;Lo;0;L;;;;;N;;;;; +18B12;KHITAN SMALL SCRIPT CHARACTER-18B12;Lo;0;L;;;;;N;;;;; +18B13;KHITAN SMALL SCRIPT CHARACTER-18B13;Lo;0;L;;;;;N;;;;; +18B14;KHITAN SMALL SCRIPT CHARACTER-18B14;Lo;0;L;;;;;N;;;;; +18B15;KHITAN SMALL SCRIPT CHARACTER-18B15;Lo;0;L;;;;;N;;;;; +18B16;KHITAN SMALL SCRIPT CHARACTER-18B16;Lo;0;L;;;;;N;;;;; +18B17;KHITAN SMALL SCRIPT CHARACTER-18B17;Lo;0;L;;;;;N;;;;; +18B18;KHITAN SMALL SCRIPT CHARACTER-18B18;Lo;0;L;;;;;N;;;;; +18B19;KHITAN SMALL SCRIPT CHARACTER-18B19;Lo;0;L;;;;;N;;;;; +18B1A;KHITAN SMALL SCRIPT CHARACTER-18B1A;Lo;0;L;;;;;N;;;;; +18B1B;KHITAN SMALL SCRIPT CHARACTER-18B1B;Lo;0;L;;;;;N;;;;; +18B1C;KHITAN SMALL SCRIPT CHARACTER-18B1C;Lo;0;L;;;;;N;;;;; +18B1D;KHITAN SMALL SCRIPT CHARACTER-18B1D;Lo;0;L;;;;;N;;;;; +18B1E;KHITAN SMALL SCRIPT CHARACTER-18B1E;Lo;0;L;;;;;N;;;;; +18B1F;KHITAN SMALL SCRIPT CHARACTER-18B1F;Lo;0;L;;;;;N;;;;; +18B20;KHITAN SMALL SCRIPT CHARACTER-18B20;Lo;0;L;;;;;N;;;;; +18B21;KHITAN SMALL SCRIPT CHARACTER-18B21;Lo;0;L;;;;;N;;;;; +18B22;KHITAN SMALL SCRIPT CHARACTER-18B22;Lo;0;L;;;;;N;;;;; +18B23;KHITAN SMALL SCRIPT CHARACTER-18B23;Lo;0;L;;;;;N;;;;; +18B24;KHITAN SMALL SCRIPT CHARACTER-18B24;Lo;0;L;;;;;N;;;;; +18B25;KHITAN SMALL SCRIPT CHARACTER-18B25;Lo;0;L;;;;;N;;;;; +18B26;KHITAN SMALL SCRIPT CHARACTER-18B26;Lo;0;L;;;;;N;;;;; +18B27;KHITAN SMALL SCRIPT CHARACTER-18B27;Lo;0;L;;;;;N;;;;; +18B28;KHITAN SMALL SCRIPT CHARACTER-18B28;Lo;0;L;;;;;N;;;;; +18B29;KHITAN SMALL SCRIPT CHARACTER-18B29;Lo;0;L;;;;;N;;;;; +18B2A;KHITAN SMALL SCRIPT CHARACTER-18B2A;Lo;0;L;;;;;N;;;;; +18B2B;KHITAN SMALL SCRIPT CHARACTER-18B2B;Lo;0;L;;;;;N;;;;; +18B2C;KHITAN SMALL SCRIPT CHARACTER-18B2C;Lo;0;L;;;;;N;;;;; +18B2D;KHITAN SMALL SCRIPT CHARACTER-18B2D;Lo;0;L;;;;;N;;;;; +18B2E;KHITAN SMALL SCRIPT CHARACTER-18B2E;Lo;0;L;;;;;N;;;;; +18B2F;KHITAN SMALL SCRIPT CHARACTER-18B2F;Lo;0;L;;;;;N;;;;; +18B30;KHITAN SMALL SCRIPT CHARACTER-18B30;Lo;0;L;;;;;N;;;;; +18B31;KHITAN SMALL SCRIPT CHARACTER-18B31;Lo;0;L;;;;;N;;;;; +18B32;KHITAN SMALL SCRIPT CHARACTER-18B32;Lo;0;L;;;;;N;;;;; +18B33;KHITAN SMALL SCRIPT CHARACTER-18B33;Lo;0;L;;;;;N;;;;; +18B34;KHITAN SMALL SCRIPT CHARACTER-18B34;Lo;0;L;;;;;N;;;;; +18B35;KHITAN SMALL SCRIPT CHARACTER-18B35;Lo;0;L;;;;;N;;;;; +18B36;KHITAN SMALL SCRIPT CHARACTER-18B36;Lo;0;L;;;;;N;;;;; +18B37;KHITAN SMALL SCRIPT CHARACTER-18B37;Lo;0;L;;;;;N;;;;; +18B38;KHITAN SMALL SCRIPT CHARACTER-18B38;Lo;0;L;;;;;N;;;;; +18B39;KHITAN SMALL SCRIPT CHARACTER-18B39;Lo;0;L;;;;;N;;;;; +18B3A;KHITAN SMALL SCRIPT CHARACTER-18B3A;Lo;0;L;;;;;N;;;;; +18B3B;KHITAN SMALL SCRIPT CHARACTER-18B3B;Lo;0;L;;;;;N;;;;; +18B3C;KHITAN SMALL SCRIPT CHARACTER-18B3C;Lo;0;L;;;;;N;;;;; +18B3D;KHITAN SMALL SCRIPT CHARACTER-18B3D;Lo;0;L;;;;;N;;;;; +18B3E;KHITAN SMALL SCRIPT CHARACTER-18B3E;Lo;0;L;;;;;N;;;;; +18B3F;KHITAN SMALL SCRIPT CHARACTER-18B3F;Lo;0;L;;;;;N;;;;; +18B40;KHITAN SMALL SCRIPT CHARACTER-18B40;Lo;0;L;;;;;N;;;;; +18B41;KHITAN SMALL SCRIPT CHARACTER-18B41;Lo;0;L;;;;;N;;;;; +18B42;KHITAN SMALL SCRIPT CHARACTER-18B42;Lo;0;L;;;;;N;;;;; +18B43;KHITAN SMALL SCRIPT CHARACTER-18B43;Lo;0;L;;;;;N;;;;; +18B44;KHITAN SMALL SCRIPT CHARACTER-18B44;Lo;0;L;;;;;N;;;;; +18B45;KHITAN SMALL SCRIPT CHARACTER-18B45;Lo;0;L;;;;;N;;;;; +18B46;KHITAN SMALL SCRIPT CHARACTER-18B46;Lo;0;L;;;;;N;;;;; +18B47;KHITAN SMALL SCRIPT CHARACTER-18B47;Lo;0;L;;;;;N;;;;; +18B48;KHITAN SMALL SCRIPT CHARACTER-18B48;Lo;0;L;;;;;N;;;;; +18B49;KHITAN SMALL SCRIPT CHARACTER-18B49;Lo;0;L;;;;;N;;;;; +18B4A;KHITAN SMALL SCRIPT CHARACTER-18B4A;Lo;0;L;;;;;N;;;;; +18B4B;KHITAN SMALL SCRIPT CHARACTER-18B4B;Lo;0;L;;;;;N;;;;; +18B4C;KHITAN SMALL SCRIPT CHARACTER-18B4C;Lo;0;L;;;;;N;;;;; +18B4D;KHITAN SMALL SCRIPT CHARACTER-18B4D;Lo;0;L;;;;;N;;;;; +18B4E;KHITAN SMALL SCRIPT CHARACTER-18B4E;Lo;0;L;;;;;N;;;;; +18B4F;KHITAN SMALL SCRIPT CHARACTER-18B4F;Lo;0;L;;;;;N;;;;; +18B50;KHITAN SMALL SCRIPT CHARACTER-18B50;Lo;0;L;;;;;N;;;;; +18B51;KHITAN SMALL SCRIPT CHARACTER-18B51;Lo;0;L;;;;;N;;;;; +18B52;KHITAN SMALL SCRIPT CHARACTER-18B52;Lo;0;L;;;;;N;;;;; +18B53;KHITAN SMALL SCRIPT CHARACTER-18B53;Lo;0;L;;;;;N;;;;; +18B54;KHITAN SMALL SCRIPT CHARACTER-18B54;Lo;0;L;;;;;N;;;;; +18B55;KHITAN SMALL SCRIPT CHARACTER-18B55;Lo;0;L;;;;;N;;;;; +18B56;KHITAN SMALL SCRIPT CHARACTER-18B56;Lo;0;L;;;;;N;;;;; +18B57;KHITAN SMALL SCRIPT CHARACTER-18B57;Lo;0;L;;;;;N;;;;; +18B58;KHITAN SMALL SCRIPT CHARACTER-18B58;Lo;0;L;;;;;N;;;;; +18B59;KHITAN SMALL SCRIPT CHARACTER-18B59;Lo;0;L;;;;;N;;;;; +18B5A;KHITAN SMALL SCRIPT CHARACTER-18B5A;Lo;0;L;;;;;N;;;;; +18B5B;KHITAN SMALL SCRIPT CHARACTER-18B5B;Lo;0;L;;;;;N;;;;; +18B5C;KHITAN SMALL SCRIPT CHARACTER-18B5C;Lo;0;L;;;;;N;;;;; +18B5D;KHITAN SMALL SCRIPT CHARACTER-18B5D;Lo;0;L;;;;;N;;;;; +18B5E;KHITAN SMALL SCRIPT CHARACTER-18B5E;Lo;0;L;;;;;N;;;;; +18B5F;KHITAN SMALL SCRIPT CHARACTER-18B5F;Lo;0;L;;;;;N;;;;; +18B60;KHITAN SMALL SCRIPT CHARACTER-18B60;Lo;0;L;;;;;N;;;;; +18B61;KHITAN SMALL SCRIPT CHARACTER-18B61;Lo;0;L;;;;;N;;;;; +18B62;KHITAN SMALL SCRIPT CHARACTER-18B62;Lo;0;L;;;;;N;;;;; +18B63;KHITAN SMALL SCRIPT CHARACTER-18B63;Lo;0;L;;;;;N;;;;; +18B64;KHITAN SMALL SCRIPT CHARACTER-18B64;Lo;0;L;;;;;N;;;;; +18B65;KHITAN SMALL SCRIPT CHARACTER-18B65;Lo;0;L;;;;;N;;;;; +18B66;KHITAN SMALL SCRIPT CHARACTER-18B66;Lo;0;L;;;;;N;;;;; +18B67;KHITAN SMALL SCRIPT CHARACTER-18B67;Lo;0;L;;;;;N;;;;; +18B68;KHITAN SMALL SCRIPT CHARACTER-18B68;Lo;0;L;;;;;N;;;;; +18B69;KHITAN SMALL SCRIPT CHARACTER-18B69;Lo;0;L;;;;;N;;;;; +18B6A;KHITAN SMALL SCRIPT CHARACTER-18B6A;Lo;0;L;;;;;N;;;;; +18B6B;KHITAN SMALL SCRIPT CHARACTER-18B6B;Lo;0;L;;;;;N;;;;; +18B6C;KHITAN SMALL SCRIPT CHARACTER-18B6C;Lo;0;L;;;;;N;;;;; +18B6D;KHITAN SMALL SCRIPT CHARACTER-18B6D;Lo;0;L;;;;;N;;;;; +18B6E;KHITAN SMALL SCRIPT CHARACTER-18B6E;Lo;0;L;;;;;N;;;;; +18B6F;KHITAN SMALL SCRIPT CHARACTER-18B6F;Lo;0;L;;;;;N;;;;; +18B70;KHITAN SMALL SCRIPT CHARACTER-18B70;Lo;0;L;;;;;N;;;;; +18B71;KHITAN SMALL SCRIPT CHARACTER-18B71;Lo;0;L;;;;;N;;;;; +18B72;KHITAN SMALL SCRIPT CHARACTER-18B72;Lo;0;L;;;;;N;;;;; +18B73;KHITAN SMALL SCRIPT CHARACTER-18B73;Lo;0;L;;;;;N;;;;; +18B74;KHITAN SMALL SCRIPT CHARACTER-18B74;Lo;0;L;;;;;N;;;;; +18B75;KHITAN SMALL SCRIPT CHARACTER-18B75;Lo;0;L;;;;;N;;;;; +18B76;KHITAN SMALL SCRIPT CHARACTER-18B76;Lo;0;L;;;;;N;;;;; +18B77;KHITAN SMALL SCRIPT CHARACTER-18B77;Lo;0;L;;;;;N;;;;; +18B78;KHITAN SMALL SCRIPT CHARACTER-18B78;Lo;0;L;;;;;N;;;;; +18B79;KHITAN SMALL SCRIPT CHARACTER-18B79;Lo;0;L;;;;;N;;;;; +18B7A;KHITAN SMALL SCRIPT CHARACTER-18B7A;Lo;0;L;;;;;N;;;;; +18B7B;KHITAN SMALL SCRIPT CHARACTER-18B7B;Lo;0;L;;;;;N;;;;; +18B7C;KHITAN SMALL SCRIPT CHARACTER-18B7C;Lo;0;L;;;;;N;;;;; +18B7D;KHITAN SMALL SCRIPT CHARACTER-18B7D;Lo;0;L;;;;;N;;;;; +18B7E;KHITAN SMALL SCRIPT CHARACTER-18B7E;Lo;0;L;;;;;N;;;;; +18B7F;KHITAN SMALL SCRIPT CHARACTER-18B7F;Lo;0;L;;;;;N;;;;; +18B80;KHITAN SMALL SCRIPT CHARACTER-18B80;Lo;0;L;;;;;N;;;;; +18B81;KHITAN SMALL SCRIPT CHARACTER-18B81;Lo;0;L;;;;;N;;;;; +18B82;KHITAN SMALL SCRIPT CHARACTER-18B82;Lo;0;L;;;;;N;;;;; +18B83;KHITAN SMALL SCRIPT CHARACTER-18B83;Lo;0;L;;;;;N;;;;; +18B84;KHITAN SMALL SCRIPT CHARACTER-18B84;Lo;0;L;;;;;N;;;;; +18B85;KHITAN SMALL SCRIPT CHARACTER-18B85;Lo;0;L;;;;;N;;;;; +18B86;KHITAN SMALL SCRIPT CHARACTER-18B86;Lo;0;L;;;;;N;;;;; +18B87;KHITAN SMALL SCRIPT CHARACTER-18B87;Lo;0;L;;;;;N;;;;; +18B88;KHITAN SMALL SCRIPT CHARACTER-18B88;Lo;0;L;;;;;N;;;;; +18B89;KHITAN SMALL SCRIPT CHARACTER-18B89;Lo;0;L;;;;;N;;;;; +18B8A;KHITAN SMALL SCRIPT CHARACTER-18B8A;Lo;0;L;;;;;N;;;;; +18B8B;KHITAN SMALL SCRIPT CHARACTER-18B8B;Lo;0;L;;;;;N;;;;; +18B8C;KHITAN SMALL SCRIPT CHARACTER-18B8C;Lo;0;L;;;;;N;;;;; +18B8D;KHITAN SMALL SCRIPT CHARACTER-18B8D;Lo;0;L;;;;;N;;;;; +18B8E;KHITAN SMALL SCRIPT CHARACTER-18B8E;Lo;0;L;;;;;N;;;;; +18B8F;KHITAN SMALL SCRIPT CHARACTER-18B8F;Lo;0;L;;;;;N;;;;; +18B90;KHITAN SMALL SCRIPT CHARACTER-18B90;Lo;0;L;;;;;N;;;;; +18B91;KHITAN SMALL SCRIPT CHARACTER-18B91;Lo;0;L;;;;;N;;;;; +18B92;KHITAN SMALL SCRIPT CHARACTER-18B92;Lo;0;L;;;;;N;;;;; +18B93;KHITAN SMALL SCRIPT CHARACTER-18B93;Lo;0;L;;;;;N;;;;; +18B94;KHITAN SMALL SCRIPT CHARACTER-18B94;Lo;0;L;;;;;N;;;;; +18B95;KHITAN SMALL SCRIPT CHARACTER-18B95;Lo;0;L;;;;;N;;;;; +18B96;KHITAN SMALL SCRIPT CHARACTER-18B96;Lo;0;L;;;;;N;;;;; +18B97;KHITAN SMALL SCRIPT CHARACTER-18B97;Lo;0;L;;;;;N;;;;; +18B98;KHITAN SMALL SCRIPT CHARACTER-18B98;Lo;0;L;;;;;N;;;;; +18B99;KHITAN SMALL SCRIPT CHARACTER-18B99;Lo;0;L;;;;;N;;;;; +18B9A;KHITAN SMALL SCRIPT CHARACTER-18B9A;Lo;0;L;;;;;N;;;;; +18B9B;KHITAN SMALL SCRIPT CHARACTER-18B9B;Lo;0;L;;;;;N;;;;; +18B9C;KHITAN SMALL SCRIPT CHARACTER-18B9C;Lo;0;L;;;;;N;;;;; +18B9D;KHITAN SMALL SCRIPT CHARACTER-18B9D;Lo;0;L;;;;;N;;;;; +18B9E;KHITAN SMALL SCRIPT CHARACTER-18B9E;Lo;0;L;;;;;N;;;;; +18B9F;KHITAN SMALL SCRIPT CHARACTER-18B9F;Lo;0;L;;;;;N;;;;; +18BA0;KHITAN SMALL SCRIPT CHARACTER-18BA0;Lo;0;L;;;;;N;;;;; +18BA1;KHITAN SMALL SCRIPT CHARACTER-18BA1;Lo;0;L;;;;;N;;;;; +18BA2;KHITAN SMALL SCRIPT CHARACTER-18BA2;Lo;0;L;;;;;N;;;;; +18BA3;KHITAN SMALL SCRIPT CHARACTER-18BA3;Lo;0;L;;;;;N;;;;; +18BA4;KHITAN SMALL SCRIPT CHARACTER-18BA4;Lo;0;L;;;;;N;;;;; +18BA5;KHITAN SMALL SCRIPT CHARACTER-18BA5;Lo;0;L;;;;;N;;;;; +18BA6;KHITAN SMALL SCRIPT CHARACTER-18BA6;Lo;0;L;;;;;N;;;;; +18BA7;KHITAN SMALL SCRIPT CHARACTER-18BA7;Lo;0;L;;;;;N;;;;; +18BA8;KHITAN SMALL SCRIPT CHARACTER-18BA8;Lo;0;L;;;;;N;;;;; +18BA9;KHITAN SMALL SCRIPT CHARACTER-18BA9;Lo;0;L;;;;;N;;;;; +18BAA;KHITAN SMALL SCRIPT CHARACTER-18BAA;Lo;0;L;;;;;N;;;;; +18BAB;KHITAN SMALL SCRIPT CHARACTER-18BAB;Lo;0;L;;;;;N;;;;; +18BAC;KHITAN SMALL SCRIPT CHARACTER-18BAC;Lo;0;L;;;;;N;;;;; +18BAD;KHITAN SMALL SCRIPT CHARACTER-18BAD;Lo;0;L;;;;;N;;;;; +18BAE;KHITAN SMALL SCRIPT CHARACTER-18BAE;Lo;0;L;;;;;N;;;;; +18BAF;KHITAN SMALL SCRIPT CHARACTER-18BAF;Lo;0;L;;;;;N;;;;; +18BB0;KHITAN SMALL SCRIPT CHARACTER-18BB0;Lo;0;L;;;;;N;;;;; +18BB1;KHITAN SMALL SCRIPT CHARACTER-18BB1;Lo;0;L;;;;;N;;;;; +18BB2;KHITAN SMALL SCRIPT CHARACTER-18BB2;Lo;0;L;;;;;N;;;;; +18BB3;KHITAN SMALL SCRIPT CHARACTER-18BB3;Lo;0;L;;;;;N;;;;; +18BB4;KHITAN SMALL SCRIPT CHARACTER-18BB4;Lo;0;L;;;;;N;;;;; +18BB5;KHITAN SMALL SCRIPT CHARACTER-18BB5;Lo;0;L;;;;;N;;;;; +18BB6;KHITAN SMALL SCRIPT CHARACTER-18BB6;Lo;0;L;;;;;N;;;;; +18BB7;KHITAN SMALL SCRIPT CHARACTER-18BB7;Lo;0;L;;;;;N;;;;; +18BB8;KHITAN SMALL SCRIPT CHARACTER-18BB8;Lo;0;L;;;;;N;;;;; +18BB9;KHITAN SMALL SCRIPT CHARACTER-18BB9;Lo;0;L;;;;;N;;;;; +18BBA;KHITAN SMALL SCRIPT CHARACTER-18BBA;Lo;0;L;;;;;N;;;;; +18BBB;KHITAN SMALL SCRIPT CHARACTER-18BBB;Lo;0;L;;;;;N;;;;; +18BBC;KHITAN SMALL SCRIPT CHARACTER-18BBC;Lo;0;L;;;;;N;;;;; +18BBD;KHITAN SMALL SCRIPT CHARACTER-18BBD;Lo;0;L;;;;;N;;;;; +18BBE;KHITAN SMALL SCRIPT CHARACTER-18BBE;Lo;0;L;;;;;N;;;;; +18BBF;KHITAN SMALL SCRIPT CHARACTER-18BBF;Lo;0;L;;;;;N;;;;; +18BC0;KHITAN SMALL SCRIPT CHARACTER-18BC0;Lo;0;L;;;;;N;;;;; +18BC1;KHITAN SMALL SCRIPT CHARACTER-18BC1;Lo;0;L;;;;;N;;;;; +18BC2;KHITAN SMALL SCRIPT CHARACTER-18BC2;Lo;0;L;;;;;N;;;;; +18BC3;KHITAN SMALL SCRIPT CHARACTER-18BC3;Lo;0;L;;;;;N;;;;; +18BC4;KHITAN SMALL SCRIPT CHARACTER-18BC4;Lo;0;L;;;;;N;;;;; +18BC5;KHITAN SMALL SCRIPT CHARACTER-18BC5;Lo;0;L;;;;;N;;;;; +18BC6;KHITAN SMALL SCRIPT CHARACTER-18BC6;Lo;0;L;;;;;N;;;;; +18BC7;KHITAN SMALL SCRIPT CHARACTER-18BC7;Lo;0;L;;;;;N;;;;; +18BC8;KHITAN SMALL SCRIPT CHARACTER-18BC8;Lo;0;L;;;;;N;;;;; +18BC9;KHITAN SMALL SCRIPT CHARACTER-18BC9;Lo;0;L;;;;;N;;;;; +18BCA;KHITAN SMALL SCRIPT CHARACTER-18BCA;Lo;0;L;;;;;N;;;;; +18BCB;KHITAN SMALL SCRIPT CHARACTER-18BCB;Lo;0;L;;;;;N;;;;; +18BCC;KHITAN SMALL SCRIPT CHARACTER-18BCC;Lo;0;L;;;;;N;;;;; +18BCD;KHITAN SMALL SCRIPT CHARACTER-18BCD;Lo;0;L;;;;;N;;;;; +18BCE;KHITAN SMALL SCRIPT CHARACTER-18BCE;Lo;0;L;;;;;N;;;;; +18BCF;KHITAN SMALL SCRIPT CHARACTER-18BCF;Lo;0;L;;;;;N;;;;; +18BD0;KHITAN SMALL SCRIPT CHARACTER-18BD0;Lo;0;L;;;;;N;;;;; +18BD1;KHITAN SMALL SCRIPT CHARACTER-18BD1;Lo;0;L;;;;;N;;;;; +18BD2;KHITAN SMALL SCRIPT CHARACTER-18BD2;Lo;0;L;;;;;N;;;;; +18BD3;KHITAN SMALL SCRIPT CHARACTER-18BD3;Lo;0;L;;;;;N;;;;; +18BD4;KHITAN SMALL SCRIPT CHARACTER-18BD4;Lo;0;L;;;;;N;;;;; +18BD5;KHITAN SMALL SCRIPT CHARACTER-18BD5;Lo;0;L;;;;;N;;;;; +18BD6;KHITAN SMALL SCRIPT CHARACTER-18BD6;Lo;0;L;;;;;N;;;;; +18BD7;KHITAN SMALL SCRIPT CHARACTER-18BD7;Lo;0;L;;;;;N;;;;; +18BD8;KHITAN SMALL SCRIPT CHARACTER-18BD8;Lo;0;L;;;;;N;;;;; +18BD9;KHITAN SMALL SCRIPT CHARACTER-18BD9;Lo;0;L;;;;;N;;;;; +18BDA;KHITAN SMALL SCRIPT CHARACTER-18BDA;Lo;0;L;;;;;N;;;;; +18BDB;KHITAN SMALL SCRIPT CHARACTER-18BDB;Lo;0;L;;;;;N;;;;; +18BDC;KHITAN SMALL SCRIPT CHARACTER-18BDC;Lo;0;L;;;;;N;;;;; +18BDD;KHITAN SMALL SCRIPT CHARACTER-18BDD;Lo;0;L;;;;;N;;;;; +18BDE;KHITAN SMALL SCRIPT CHARACTER-18BDE;Lo;0;L;;;;;N;;;;; +18BDF;KHITAN SMALL SCRIPT CHARACTER-18BDF;Lo;0;L;;;;;N;;;;; +18BE0;KHITAN SMALL SCRIPT CHARACTER-18BE0;Lo;0;L;;;;;N;;;;; +18BE1;KHITAN SMALL SCRIPT CHARACTER-18BE1;Lo;0;L;;;;;N;;;;; +18BE2;KHITAN SMALL SCRIPT CHARACTER-18BE2;Lo;0;L;;;;;N;;;;; +18BE3;KHITAN SMALL SCRIPT CHARACTER-18BE3;Lo;0;L;;;;;N;;;;; +18BE4;KHITAN SMALL SCRIPT CHARACTER-18BE4;Lo;0;L;;;;;N;;;;; +18BE5;KHITAN SMALL SCRIPT CHARACTER-18BE5;Lo;0;L;;;;;N;;;;; +18BE6;KHITAN SMALL SCRIPT CHARACTER-18BE6;Lo;0;L;;;;;N;;;;; +18BE7;KHITAN SMALL SCRIPT CHARACTER-18BE7;Lo;0;L;;;;;N;;;;; +18BE8;KHITAN SMALL SCRIPT CHARACTER-18BE8;Lo;0;L;;;;;N;;;;; +18BE9;KHITAN SMALL SCRIPT CHARACTER-18BE9;Lo;0;L;;;;;N;;;;; +18BEA;KHITAN SMALL SCRIPT CHARACTER-18BEA;Lo;0;L;;;;;N;;;;; +18BEB;KHITAN SMALL SCRIPT CHARACTER-18BEB;Lo;0;L;;;;;N;;;;; +18BEC;KHITAN SMALL SCRIPT CHARACTER-18BEC;Lo;0;L;;;;;N;;;;; +18BED;KHITAN SMALL SCRIPT CHARACTER-18BED;Lo;0;L;;;;;N;;;;; +18BEE;KHITAN SMALL SCRIPT CHARACTER-18BEE;Lo;0;L;;;;;N;;;;; +18BEF;KHITAN SMALL SCRIPT CHARACTER-18BEF;Lo;0;L;;;;;N;;;;; +18BF0;KHITAN SMALL SCRIPT CHARACTER-18BF0;Lo;0;L;;;;;N;;;;; +18BF1;KHITAN SMALL SCRIPT CHARACTER-18BF1;Lo;0;L;;;;;N;;;;; +18BF2;KHITAN SMALL SCRIPT CHARACTER-18BF2;Lo;0;L;;;;;N;;;;; +18BF3;KHITAN SMALL SCRIPT CHARACTER-18BF3;Lo;0;L;;;;;N;;;;; +18BF4;KHITAN SMALL SCRIPT CHARACTER-18BF4;Lo;0;L;;;;;N;;;;; +18BF5;KHITAN SMALL SCRIPT CHARACTER-18BF5;Lo;0;L;;;;;N;;;;; +18BF6;KHITAN SMALL SCRIPT CHARACTER-18BF6;Lo;0;L;;;;;N;;;;; +18BF7;KHITAN SMALL SCRIPT CHARACTER-18BF7;Lo;0;L;;;;;N;;;;; +18BF8;KHITAN SMALL SCRIPT CHARACTER-18BF8;Lo;0;L;;;;;N;;;;; +18BF9;KHITAN SMALL SCRIPT CHARACTER-18BF9;Lo;0;L;;;;;N;;;;; +18BFA;KHITAN SMALL SCRIPT CHARACTER-18BFA;Lo;0;L;;;;;N;;;;; +18BFB;KHITAN SMALL SCRIPT CHARACTER-18BFB;Lo;0;L;;;;;N;;;;; +18BFC;KHITAN SMALL SCRIPT CHARACTER-18BFC;Lo;0;L;;;;;N;;;;; +18BFD;KHITAN SMALL SCRIPT CHARACTER-18BFD;Lo;0;L;;;;;N;;;;; +18BFE;KHITAN SMALL SCRIPT CHARACTER-18BFE;Lo;0;L;;;;;N;;;;; +18BFF;KHITAN SMALL SCRIPT CHARACTER-18BFF;Lo;0;L;;;;;N;;;;; +18C00;KHITAN SMALL SCRIPT CHARACTER-18C00;Lo;0;L;;;;;N;;;;; +18C01;KHITAN SMALL SCRIPT CHARACTER-18C01;Lo;0;L;;;;;N;;;;; +18C02;KHITAN SMALL SCRIPT CHARACTER-18C02;Lo;0;L;;;;;N;;;;; +18C03;KHITAN SMALL SCRIPT CHARACTER-18C03;Lo;0;L;;;;;N;;;;; +18C04;KHITAN SMALL SCRIPT CHARACTER-18C04;Lo;0;L;;;;;N;;;;; +18C05;KHITAN SMALL SCRIPT CHARACTER-18C05;Lo;0;L;;;;;N;;;;; +18C06;KHITAN SMALL SCRIPT CHARACTER-18C06;Lo;0;L;;;;;N;;;;; +18C07;KHITAN SMALL SCRIPT CHARACTER-18C07;Lo;0;L;;;;;N;;;;; +18C08;KHITAN SMALL SCRIPT CHARACTER-18C08;Lo;0;L;;;;;N;;;;; +18C09;KHITAN SMALL SCRIPT CHARACTER-18C09;Lo;0;L;;;;;N;;;;; +18C0A;KHITAN SMALL SCRIPT CHARACTER-18C0A;Lo;0;L;;;;;N;;;;; +18C0B;KHITAN SMALL SCRIPT CHARACTER-18C0B;Lo;0;L;;;;;N;;;;; +18C0C;KHITAN SMALL SCRIPT CHARACTER-18C0C;Lo;0;L;;;;;N;;;;; +18C0D;KHITAN SMALL SCRIPT CHARACTER-18C0D;Lo;0;L;;;;;N;;;;; +18C0E;KHITAN SMALL SCRIPT CHARACTER-18C0E;Lo;0;L;;;;;N;;;;; +18C0F;KHITAN SMALL SCRIPT CHARACTER-18C0F;Lo;0;L;;;;;N;;;;; +18C10;KHITAN SMALL SCRIPT CHARACTER-18C10;Lo;0;L;;;;;N;;;;; +18C11;KHITAN SMALL SCRIPT CHARACTER-18C11;Lo;0;L;;;;;N;;;;; +18C12;KHITAN SMALL SCRIPT CHARACTER-18C12;Lo;0;L;;;;;N;;;;; +18C13;KHITAN SMALL SCRIPT CHARACTER-18C13;Lo;0;L;;;;;N;;;;; +18C14;KHITAN SMALL SCRIPT CHARACTER-18C14;Lo;0;L;;;;;N;;;;; +18C15;KHITAN SMALL SCRIPT CHARACTER-18C15;Lo;0;L;;;;;N;;;;; +18C16;KHITAN SMALL SCRIPT CHARACTER-18C16;Lo;0;L;;;;;N;;;;; +18C17;KHITAN SMALL SCRIPT CHARACTER-18C17;Lo;0;L;;;;;N;;;;; +18C18;KHITAN SMALL SCRIPT CHARACTER-18C18;Lo;0;L;;;;;N;;;;; +18C19;KHITAN SMALL SCRIPT CHARACTER-18C19;Lo;0;L;;;;;N;;;;; +18C1A;KHITAN SMALL SCRIPT CHARACTER-18C1A;Lo;0;L;;;;;N;;;;; +18C1B;KHITAN SMALL SCRIPT CHARACTER-18C1B;Lo;0;L;;;;;N;;;;; +18C1C;KHITAN SMALL SCRIPT CHARACTER-18C1C;Lo;0;L;;;;;N;;;;; +18C1D;KHITAN SMALL SCRIPT CHARACTER-18C1D;Lo;0;L;;;;;N;;;;; +18C1E;KHITAN SMALL SCRIPT CHARACTER-18C1E;Lo;0;L;;;;;N;;;;; +18C1F;KHITAN SMALL SCRIPT CHARACTER-18C1F;Lo;0;L;;;;;N;;;;; +18C20;KHITAN SMALL SCRIPT CHARACTER-18C20;Lo;0;L;;;;;N;;;;; +18C21;KHITAN SMALL SCRIPT CHARACTER-18C21;Lo;0;L;;;;;N;;;;; +18C22;KHITAN SMALL SCRIPT CHARACTER-18C22;Lo;0;L;;;;;N;;;;; +18C23;KHITAN SMALL SCRIPT CHARACTER-18C23;Lo;0;L;;;;;N;;;;; +18C24;KHITAN SMALL SCRIPT CHARACTER-18C24;Lo;0;L;;;;;N;;;;; +18C25;KHITAN SMALL SCRIPT CHARACTER-18C25;Lo;0;L;;;;;N;;;;; +18C26;KHITAN SMALL SCRIPT CHARACTER-18C26;Lo;0;L;;;;;N;;;;; +18C27;KHITAN SMALL SCRIPT CHARACTER-18C27;Lo;0;L;;;;;N;;;;; +18C28;KHITAN SMALL SCRIPT CHARACTER-18C28;Lo;0;L;;;;;N;;;;; +18C29;KHITAN SMALL SCRIPT CHARACTER-18C29;Lo;0;L;;;;;N;;;;; +18C2A;KHITAN SMALL SCRIPT CHARACTER-18C2A;Lo;0;L;;;;;N;;;;; +18C2B;KHITAN SMALL SCRIPT CHARACTER-18C2B;Lo;0;L;;;;;N;;;;; +18C2C;KHITAN SMALL SCRIPT CHARACTER-18C2C;Lo;0;L;;;;;N;;;;; +18C2D;KHITAN SMALL SCRIPT CHARACTER-18C2D;Lo;0;L;;;;;N;;;;; +18C2E;KHITAN SMALL SCRIPT CHARACTER-18C2E;Lo;0;L;;;;;N;;;;; +18C2F;KHITAN SMALL SCRIPT CHARACTER-18C2F;Lo;0;L;;;;;N;;;;; +18C30;KHITAN SMALL SCRIPT CHARACTER-18C30;Lo;0;L;;;;;N;;;;; +18C31;KHITAN SMALL SCRIPT CHARACTER-18C31;Lo;0;L;;;;;N;;;;; +18C32;KHITAN SMALL SCRIPT CHARACTER-18C32;Lo;0;L;;;;;N;;;;; +18C33;KHITAN SMALL SCRIPT CHARACTER-18C33;Lo;0;L;;;;;N;;;;; +18C34;KHITAN SMALL SCRIPT CHARACTER-18C34;Lo;0;L;;;;;N;;;;; +18C35;KHITAN SMALL SCRIPT CHARACTER-18C35;Lo;0;L;;;;;N;;;;; +18C36;KHITAN SMALL SCRIPT CHARACTER-18C36;Lo;0;L;;;;;N;;;;; +18C37;KHITAN SMALL SCRIPT CHARACTER-18C37;Lo;0;L;;;;;N;;;;; +18C38;KHITAN SMALL SCRIPT CHARACTER-18C38;Lo;0;L;;;;;N;;;;; +18C39;KHITAN SMALL SCRIPT CHARACTER-18C39;Lo;0;L;;;;;N;;;;; +18C3A;KHITAN SMALL SCRIPT CHARACTER-18C3A;Lo;0;L;;;;;N;;;;; +18C3B;KHITAN SMALL SCRIPT CHARACTER-18C3B;Lo;0;L;;;;;N;;;;; +18C3C;KHITAN SMALL SCRIPT CHARACTER-18C3C;Lo;0;L;;;;;N;;;;; +18C3D;KHITAN SMALL SCRIPT CHARACTER-18C3D;Lo;0;L;;;;;N;;;;; +18C3E;KHITAN SMALL SCRIPT CHARACTER-18C3E;Lo;0;L;;;;;N;;;;; +18C3F;KHITAN SMALL SCRIPT CHARACTER-18C3F;Lo;0;L;;;;;N;;;;; +18C40;KHITAN SMALL SCRIPT CHARACTER-18C40;Lo;0;L;;;;;N;;;;; +18C41;KHITAN SMALL SCRIPT CHARACTER-18C41;Lo;0;L;;;;;N;;;;; +18C42;KHITAN SMALL SCRIPT CHARACTER-18C42;Lo;0;L;;;;;N;;;;; +18C43;KHITAN SMALL SCRIPT CHARACTER-18C43;Lo;0;L;;;;;N;;;;; +18C44;KHITAN SMALL SCRIPT CHARACTER-18C44;Lo;0;L;;;;;N;;;;; +18C45;KHITAN SMALL SCRIPT CHARACTER-18C45;Lo;0;L;;;;;N;;;;; +18C46;KHITAN SMALL SCRIPT CHARACTER-18C46;Lo;0;L;;;;;N;;;;; +18C47;KHITAN SMALL SCRIPT CHARACTER-18C47;Lo;0;L;;;;;N;;;;; +18C48;KHITAN SMALL SCRIPT CHARACTER-18C48;Lo;0;L;;;;;N;;;;; +18C49;KHITAN SMALL SCRIPT CHARACTER-18C49;Lo;0;L;;;;;N;;;;; +18C4A;KHITAN SMALL SCRIPT CHARACTER-18C4A;Lo;0;L;;;;;N;;;;; +18C4B;KHITAN SMALL SCRIPT CHARACTER-18C4B;Lo;0;L;;;;;N;;;;; +18C4C;KHITAN SMALL SCRIPT CHARACTER-18C4C;Lo;0;L;;;;;N;;;;; +18C4D;KHITAN SMALL SCRIPT CHARACTER-18C4D;Lo;0;L;;;;;N;;;;; +18C4E;KHITAN SMALL SCRIPT CHARACTER-18C4E;Lo;0;L;;;;;N;;;;; +18C4F;KHITAN SMALL SCRIPT CHARACTER-18C4F;Lo;0;L;;;;;N;;;;; +18C50;KHITAN SMALL SCRIPT CHARACTER-18C50;Lo;0;L;;;;;N;;;;; +18C51;KHITAN SMALL SCRIPT CHARACTER-18C51;Lo;0;L;;;;;N;;;;; +18C52;KHITAN SMALL SCRIPT CHARACTER-18C52;Lo;0;L;;;;;N;;;;; +18C53;KHITAN SMALL SCRIPT CHARACTER-18C53;Lo;0;L;;;;;N;;;;; +18C54;KHITAN SMALL SCRIPT CHARACTER-18C54;Lo;0;L;;;;;N;;;;; +18C55;KHITAN SMALL SCRIPT CHARACTER-18C55;Lo;0;L;;;;;N;;;;; +18C56;KHITAN SMALL SCRIPT CHARACTER-18C56;Lo;0;L;;;;;N;;;;; +18C57;KHITAN SMALL SCRIPT CHARACTER-18C57;Lo;0;L;;;;;N;;;;; +18C58;KHITAN SMALL SCRIPT CHARACTER-18C58;Lo;0;L;;;;;N;;;;; +18C59;KHITAN SMALL SCRIPT CHARACTER-18C59;Lo;0;L;;;;;N;;;;; +18C5A;KHITAN SMALL SCRIPT CHARACTER-18C5A;Lo;0;L;;;;;N;;;;; +18C5B;KHITAN SMALL SCRIPT CHARACTER-18C5B;Lo;0;L;;;;;N;;;;; +18C5C;KHITAN SMALL SCRIPT CHARACTER-18C5C;Lo;0;L;;;;;N;;;;; +18C5D;KHITAN SMALL SCRIPT CHARACTER-18C5D;Lo;0;L;;;;;N;;;;; +18C5E;KHITAN SMALL SCRIPT CHARACTER-18C5E;Lo;0;L;;;;;N;;;;; +18C5F;KHITAN SMALL SCRIPT CHARACTER-18C5F;Lo;0;L;;;;;N;;;;; +18C60;KHITAN SMALL SCRIPT CHARACTER-18C60;Lo;0;L;;;;;N;;;;; +18C61;KHITAN SMALL SCRIPT CHARACTER-18C61;Lo;0;L;;;;;N;;;;; +18C62;KHITAN SMALL SCRIPT CHARACTER-18C62;Lo;0;L;;;;;N;;;;; +18C63;KHITAN SMALL SCRIPT CHARACTER-18C63;Lo;0;L;;;;;N;;;;; +18C64;KHITAN SMALL SCRIPT CHARACTER-18C64;Lo;0;L;;;;;N;;;;; +18C65;KHITAN SMALL SCRIPT CHARACTER-18C65;Lo;0;L;;;;;N;;;;; +18C66;KHITAN SMALL SCRIPT CHARACTER-18C66;Lo;0;L;;;;;N;;;;; +18C67;KHITAN SMALL SCRIPT CHARACTER-18C67;Lo;0;L;;;;;N;;;;; +18C68;KHITAN SMALL SCRIPT CHARACTER-18C68;Lo;0;L;;;;;N;;;;; +18C69;KHITAN SMALL SCRIPT CHARACTER-18C69;Lo;0;L;;;;;N;;;;; +18C6A;KHITAN SMALL SCRIPT CHARACTER-18C6A;Lo;0;L;;;;;N;;;;; +18C6B;KHITAN SMALL SCRIPT CHARACTER-18C6B;Lo;0;L;;;;;N;;;;; +18C6C;KHITAN SMALL SCRIPT CHARACTER-18C6C;Lo;0;L;;;;;N;;;;; +18C6D;KHITAN SMALL SCRIPT CHARACTER-18C6D;Lo;0;L;;;;;N;;;;; +18C6E;KHITAN SMALL SCRIPT CHARACTER-18C6E;Lo;0;L;;;;;N;;;;; +18C6F;KHITAN SMALL SCRIPT CHARACTER-18C6F;Lo;0;L;;;;;N;;;;; +18C70;KHITAN SMALL SCRIPT CHARACTER-18C70;Lo;0;L;;;;;N;;;;; +18C71;KHITAN SMALL SCRIPT CHARACTER-18C71;Lo;0;L;;;;;N;;;;; +18C72;KHITAN SMALL SCRIPT CHARACTER-18C72;Lo;0;L;;;;;N;;;;; +18C73;KHITAN SMALL SCRIPT CHARACTER-18C73;Lo;0;L;;;;;N;;;;; +18C74;KHITAN SMALL SCRIPT CHARACTER-18C74;Lo;0;L;;;;;N;;;;; +18C75;KHITAN SMALL SCRIPT CHARACTER-18C75;Lo;0;L;;;;;N;;;;; +18C76;KHITAN SMALL SCRIPT CHARACTER-18C76;Lo;0;L;;;;;N;;;;; +18C77;KHITAN SMALL SCRIPT CHARACTER-18C77;Lo;0;L;;;;;N;;;;; +18C78;KHITAN SMALL SCRIPT CHARACTER-18C78;Lo;0;L;;;;;N;;;;; +18C79;KHITAN SMALL SCRIPT CHARACTER-18C79;Lo;0;L;;;;;N;;;;; +18C7A;KHITAN SMALL SCRIPT CHARACTER-18C7A;Lo;0;L;;;;;N;;;;; +18C7B;KHITAN SMALL SCRIPT CHARACTER-18C7B;Lo;0;L;;;;;N;;;;; +18C7C;KHITAN SMALL SCRIPT CHARACTER-18C7C;Lo;0;L;;;;;N;;;;; +18C7D;KHITAN SMALL SCRIPT CHARACTER-18C7D;Lo;0;L;;;;;N;;;;; +18C7E;KHITAN SMALL SCRIPT CHARACTER-18C7E;Lo;0;L;;;;;N;;;;; +18C7F;KHITAN SMALL SCRIPT CHARACTER-18C7F;Lo;0;L;;;;;N;;;;; +18C80;KHITAN SMALL SCRIPT CHARACTER-18C80;Lo;0;L;;;;;N;;;;; +18C81;KHITAN SMALL SCRIPT CHARACTER-18C81;Lo;0;L;;;;;N;;;;; +18C82;KHITAN SMALL SCRIPT CHARACTER-18C82;Lo;0;L;;;;;N;;;;; +18C83;KHITAN SMALL SCRIPT CHARACTER-18C83;Lo;0;L;;;;;N;;;;; +18C84;KHITAN SMALL SCRIPT CHARACTER-18C84;Lo;0;L;;;;;N;;;;; +18C85;KHITAN SMALL SCRIPT CHARACTER-18C85;Lo;0;L;;;;;N;;;;; +18C86;KHITAN SMALL SCRIPT CHARACTER-18C86;Lo;0;L;;;;;N;;;;; +18C87;KHITAN SMALL SCRIPT CHARACTER-18C87;Lo;0;L;;;;;N;;;;; +18C88;KHITAN SMALL SCRIPT CHARACTER-18C88;Lo;0;L;;;;;N;;;;; +18C89;KHITAN SMALL SCRIPT CHARACTER-18C89;Lo;0;L;;;;;N;;;;; +18C8A;KHITAN SMALL SCRIPT CHARACTER-18C8A;Lo;0;L;;;;;N;;;;; +18C8B;KHITAN SMALL SCRIPT CHARACTER-18C8B;Lo;0;L;;;;;N;;;;; +18C8C;KHITAN SMALL SCRIPT CHARACTER-18C8C;Lo;0;L;;;;;N;;;;; +18C8D;KHITAN SMALL SCRIPT CHARACTER-18C8D;Lo;0;L;;;;;N;;;;; +18C8E;KHITAN SMALL SCRIPT CHARACTER-18C8E;Lo;0;L;;;;;N;;;;; +18C8F;KHITAN SMALL SCRIPT CHARACTER-18C8F;Lo;0;L;;;;;N;;;;; +18C90;KHITAN SMALL SCRIPT CHARACTER-18C90;Lo;0;L;;;;;N;;;;; +18C91;KHITAN SMALL SCRIPT CHARACTER-18C91;Lo;0;L;;;;;N;;;;; +18C92;KHITAN SMALL SCRIPT CHARACTER-18C92;Lo;0;L;;;;;N;;;;; +18C93;KHITAN SMALL SCRIPT CHARACTER-18C93;Lo;0;L;;;;;N;;;;; +18C94;KHITAN SMALL SCRIPT CHARACTER-18C94;Lo;0;L;;;;;N;;;;; +18C95;KHITAN SMALL SCRIPT CHARACTER-18C95;Lo;0;L;;;;;N;;;;; +18C96;KHITAN SMALL SCRIPT CHARACTER-18C96;Lo;0;L;;;;;N;;;;; +18C97;KHITAN SMALL SCRIPT CHARACTER-18C97;Lo;0;L;;;;;N;;;;; +18C98;KHITAN SMALL SCRIPT CHARACTER-18C98;Lo;0;L;;;;;N;;;;; +18C99;KHITAN SMALL SCRIPT CHARACTER-18C99;Lo;0;L;;;;;N;;;;; +18C9A;KHITAN SMALL SCRIPT CHARACTER-18C9A;Lo;0;L;;;;;N;;;;; +18C9B;KHITAN SMALL SCRIPT CHARACTER-18C9B;Lo;0;L;;;;;N;;;;; +18C9C;KHITAN SMALL SCRIPT CHARACTER-18C9C;Lo;0;L;;;;;N;;;;; +18C9D;KHITAN SMALL SCRIPT CHARACTER-18C9D;Lo;0;L;;;;;N;;;;; +18C9E;KHITAN SMALL SCRIPT CHARACTER-18C9E;Lo;0;L;;;;;N;;;;; +18C9F;KHITAN SMALL SCRIPT CHARACTER-18C9F;Lo;0;L;;;;;N;;;;; +18CA0;KHITAN SMALL SCRIPT CHARACTER-18CA0;Lo;0;L;;;;;N;;;;; +18CA1;KHITAN SMALL SCRIPT CHARACTER-18CA1;Lo;0;L;;;;;N;;;;; +18CA2;KHITAN SMALL SCRIPT CHARACTER-18CA2;Lo;0;L;;;;;N;;;;; +18CA3;KHITAN SMALL SCRIPT CHARACTER-18CA3;Lo;0;L;;;;;N;;;;; +18CA4;KHITAN SMALL SCRIPT CHARACTER-18CA4;Lo;0;L;;;;;N;;;;; +18CA5;KHITAN SMALL SCRIPT CHARACTER-18CA5;Lo;0;L;;;;;N;;;;; +18CA6;KHITAN SMALL SCRIPT CHARACTER-18CA6;Lo;0;L;;;;;N;;;;; +18CA7;KHITAN SMALL SCRIPT CHARACTER-18CA7;Lo;0;L;;;;;N;;;;; +18CA8;KHITAN SMALL SCRIPT CHARACTER-18CA8;Lo;0;L;;;;;N;;;;; +18CA9;KHITAN SMALL SCRIPT CHARACTER-18CA9;Lo;0;L;;;;;N;;;;; +18CAA;KHITAN SMALL SCRIPT CHARACTER-18CAA;Lo;0;L;;;;;N;;;;; +18CAB;KHITAN SMALL SCRIPT CHARACTER-18CAB;Lo;0;L;;;;;N;;;;; +18CAC;KHITAN SMALL SCRIPT CHARACTER-18CAC;Lo;0;L;;;;;N;;;;; +18CAD;KHITAN SMALL SCRIPT CHARACTER-18CAD;Lo;0;L;;;;;N;;;;; +18CAE;KHITAN SMALL SCRIPT CHARACTER-18CAE;Lo;0;L;;;;;N;;;;; +18CAF;KHITAN SMALL SCRIPT CHARACTER-18CAF;Lo;0;L;;;;;N;;;;; +18CB0;KHITAN SMALL SCRIPT CHARACTER-18CB0;Lo;0;L;;;;;N;;;;; +18CB1;KHITAN SMALL SCRIPT CHARACTER-18CB1;Lo;0;L;;;;;N;;;;; +18CB2;KHITAN SMALL SCRIPT CHARACTER-18CB2;Lo;0;L;;;;;N;;;;; +18CB3;KHITAN SMALL SCRIPT CHARACTER-18CB3;Lo;0;L;;;;;N;;;;; +18CB4;KHITAN SMALL SCRIPT CHARACTER-18CB4;Lo;0;L;;;;;N;;;;; +18CB5;KHITAN SMALL SCRIPT CHARACTER-18CB5;Lo;0;L;;;;;N;;;;; +18CB6;KHITAN SMALL SCRIPT CHARACTER-18CB6;Lo;0;L;;;;;N;;;;; +18CB7;KHITAN SMALL SCRIPT CHARACTER-18CB7;Lo;0;L;;;;;N;;;;; +18CB8;KHITAN SMALL SCRIPT CHARACTER-18CB8;Lo;0;L;;;;;N;;;;; +18CB9;KHITAN SMALL SCRIPT CHARACTER-18CB9;Lo;0;L;;;;;N;;;;; +18CBA;KHITAN SMALL SCRIPT CHARACTER-18CBA;Lo;0;L;;;;;N;;;;; +18CBB;KHITAN SMALL SCRIPT CHARACTER-18CBB;Lo;0;L;;;;;N;;;;; +18CBC;KHITAN SMALL SCRIPT CHARACTER-18CBC;Lo;0;L;;;;;N;;;;; +18CBD;KHITAN SMALL SCRIPT CHARACTER-18CBD;Lo;0;L;;;;;N;;;;; +18CBE;KHITAN SMALL SCRIPT CHARACTER-18CBE;Lo;0;L;;;;;N;;;;; +18CBF;KHITAN SMALL SCRIPT CHARACTER-18CBF;Lo;0;L;;;;;N;;;;; +18CC0;KHITAN SMALL SCRIPT CHARACTER-18CC0;Lo;0;L;;;;;N;;;;; +18CC1;KHITAN SMALL SCRIPT CHARACTER-18CC1;Lo;0;L;;;;;N;;;;; +18CC2;KHITAN SMALL SCRIPT CHARACTER-18CC2;Lo;0;L;;;;;N;;;;; +18CC3;KHITAN SMALL SCRIPT CHARACTER-18CC3;Lo;0;L;;;;;N;;;;; +18CC4;KHITAN SMALL SCRIPT CHARACTER-18CC4;Lo;0;L;;;;;N;;;;; +18CC5;KHITAN SMALL SCRIPT CHARACTER-18CC5;Lo;0;L;;;;;N;;;;; +18CC6;KHITAN SMALL SCRIPT CHARACTER-18CC6;Lo;0;L;;;;;N;;;;; +18CC7;KHITAN SMALL SCRIPT CHARACTER-18CC7;Lo;0;L;;;;;N;;;;; +18CC8;KHITAN SMALL SCRIPT CHARACTER-18CC8;Lo;0;L;;;;;N;;;;; +18CC9;KHITAN SMALL SCRIPT CHARACTER-18CC9;Lo;0;L;;;;;N;;;;; +18CCA;KHITAN SMALL SCRIPT CHARACTER-18CCA;Lo;0;L;;;;;N;;;;; +18CCB;KHITAN SMALL SCRIPT CHARACTER-18CCB;Lo;0;L;;;;;N;;;;; +18CCC;KHITAN SMALL SCRIPT CHARACTER-18CCC;Lo;0;L;;;;;N;;;;; +18CCD;KHITAN SMALL SCRIPT CHARACTER-18CCD;Lo;0;L;;;;;N;;;;; +18CCE;KHITAN SMALL SCRIPT CHARACTER-18CCE;Lo;0;L;;;;;N;;;;; +18CCF;KHITAN SMALL SCRIPT CHARACTER-18CCF;Lo;0;L;;;;;N;;;;; +18CD0;KHITAN SMALL SCRIPT CHARACTER-18CD0;Lo;0;L;;;;;N;;;;; +18CD1;KHITAN SMALL SCRIPT CHARACTER-18CD1;Lo;0;L;;;;;N;;;;; +18CD2;KHITAN SMALL SCRIPT CHARACTER-18CD2;Lo;0;L;;;;;N;;;;; +18CD3;KHITAN SMALL SCRIPT CHARACTER-18CD3;Lo;0;L;;;;;N;;;;; +18CD4;KHITAN SMALL SCRIPT CHARACTER-18CD4;Lo;0;L;;;;;N;;;;; +18CD5;KHITAN SMALL SCRIPT CHARACTER-18CD5;Lo;0;L;;;;;N;;;;; +18CFF;KHITAN SMALL SCRIPT CHARACTER-18CFF;Lo;0;L;;;;;N;;;;; +18D00;;Lo;0;L;;;;;N;;;;; +18D1E;;Lo;0;L;;;;;N;;;;; +18D80;TANGUT COMPONENT-769;Lo;0;L;;;;;N;;;;; +18D81;TANGUT COMPONENT-770;Lo;0;L;;;;;N;;;;; +18D82;TANGUT COMPONENT-771;Lo;0;L;;;;;N;;;;; +18D83;TANGUT COMPONENT-772;Lo;0;L;;;;;N;;;;; +18D84;TANGUT COMPONENT-773;Lo;0;L;;;;;N;;;;; +18D85;TANGUT COMPONENT-774;Lo;0;L;;;;;N;;;;; +18D86;TANGUT COMPONENT-775;Lo;0;L;;;;;N;;;;; +18D87;TANGUT COMPONENT-776;Lo;0;L;;;;;N;;;;; +18D88;TANGUT COMPONENT-777;Lo;0;L;;;;;N;;;;; +18D89;TANGUT COMPONENT-778;Lo;0;L;;;;;N;;;;; +18D8A;TANGUT COMPONENT-779;Lo;0;L;;;;;N;;;;; +18D8B;TANGUT COMPONENT-780;Lo;0;L;;;;;N;;;;; +18D8C;TANGUT COMPONENT-781;Lo;0;L;;;;;N;;;;; +18D8D;TANGUT COMPONENT-782;Lo;0;L;;;;;N;;;;; +18D8E;TANGUT COMPONENT-783;Lo;0;L;;;;;N;;;;; +18D8F;TANGUT COMPONENT-784;Lo;0;L;;;;;N;;;;; +18D90;TANGUT COMPONENT-785;Lo;0;L;;;;;N;;;;; +18D91;TANGUT COMPONENT-786;Lo;0;L;;;;;N;;;;; +18D92;TANGUT COMPONENT-787;Lo;0;L;;;;;N;;;;; +18D93;TANGUT COMPONENT-788;Lo;0;L;;;;;N;;;;; +18D94;TANGUT COMPONENT-789;Lo;0;L;;;;;N;;;;; +18D95;TANGUT COMPONENT-790;Lo;0;L;;;;;N;;;;; +18D96;TANGUT COMPONENT-791;Lo;0;L;;;;;N;;;;; +18D97;TANGUT COMPONENT-792;Lo;0;L;;;;;N;;;;; +18D98;TANGUT COMPONENT-793;Lo;0;L;;;;;N;;;;; +18D99;TANGUT COMPONENT-794;Lo;0;L;;;;;N;;;;; +18D9A;TANGUT COMPONENT-795;Lo;0;L;;;;;N;;;;; +18D9B;TANGUT COMPONENT-796;Lo;0;L;;;;;N;;;;; +18D9C;TANGUT COMPONENT-797;Lo;0;L;;;;;N;;;;; +18D9D;TANGUT COMPONENT-798;Lo;0;L;;;;;N;;;;; +18D9E;TANGUT COMPONENT-799;Lo;0;L;;;;;N;;;;; +18D9F;TANGUT COMPONENT-800;Lo;0;L;;;;;N;;;;; +18DA0;TANGUT COMPONENT-801;Lo;0;L;;;;;N;;;;; +18DA1;TANGUT COMPONENT-802;Lo;0;L;;;;;N;;;;; +18DA2;TANGUT COMPONENT-803;Lo;0;L;;;;;N;;;;; +18DA3;TANGUT COMPONENT-804;Lo;0;L;;;;;N;;;;; +18DA4;TANGUT COMPONENT-805;Lo;0;L;;;;;N;;;;; +18DA5;TANGUT COMPONENT-806;Lo;0;L;;;;;N;;;;; +18DA6;TANGUT COMPONENT-807;Lo;0;L;;;;;N;;;;; +18DA7;TANGUT COMPONENT-808;Lo;0;L;;;;;N;;;;; +18DA8;TANGUT COMPONENT-809;Lo;0;L;;;;;N;;;;; +18DA9;TANGUT COMPONENT-810;Lo;0;L;;;;;N;;;;; +18DAA;TANGUT COMPONENT-811;Lo;0;L;;;;;N;;;;; +18DAB;TANGUT COMPONENT-812;Lo;0;L;;;;;N;;;;; +18DAC;TANGUT COMPONENT-813;Lo;0;L;;;;;N;;;;; +18DAD;TANGUT COMPONENT-814;Lo;0;L;;;;;N;;;;; +18DAE;TANGUT COMPONENT-815;Lo;0;L;;;;;N;;;;; +18DAF;TANGUT COMPONENT-816;Lo;0;L;;;;;N;;;;; +18DB0;TANGUT COMPONENT-817;Lo;0;L;;;;;N;;;;; +18DB1;TANGUT COMPONENT-818;Lo;0;L;;;;;N;;;;; +18DB2;TANGUT COMPONENT-819;Lo;0;L;;;;;N;;;;; +18DB3;TANGUT COMPONENT-820;Lo;0;L;;;;;N;;;;; +18DB4;TANGUT COMPONENT-821;Lo;0;L;;;;;N;;;;; +18DB5;TANGUT COMPONENT-822;Lo;0;L;;;;;N;;;;; +18DB6;TANGUT COMPONENT-823;Lo;0;L;;;;;N;;;;; +18DB7;TANGUT COMPONENT-824;Lo;0;L;;;;;N;;;;; +18DB8;TANGUT COMPONENT-825;Lo;0;L;;;;;N;;;;; +18DB9;TANGUT COMPONENT-826;Lo;0;L;;;;;N;;;;; +18DBA;TANGUT COMPONENT-827;Lo;0;L;;;;;N;;;;; +18DBB;TANGUT COMPONENT-828;Lo;0;L;;;;;N;;;;; +18DBC;TANGUT COMPONENT-829;Lo;0;L;;;;;N;;;;; +18DBD;TANGUT COMPONENT-830;Lo;0;L;;;;;N;;;;; +18DBE;TANGUT COMPONENT-831;Lo;0;L;;;;;N;;;;; +18DBF;TANGUT COMPONENT-832;Lo;0;L;;;;;N;;;;; +18DC0;TANGUT COMPONENT-833;Lo;0;L;;;;;N;;;;; +18DC1;TANGUT COMPONENT-834;Lo;0;L;;;;;N;;;;; +18DC2;TANGUT COMPONENT-835;Lo;0;L;;;;;N;;;;; +18DC3;TANGUT COMPONENT-836;Lo;0;L;;;;;N;;;;; +18DC4;TANGUT COMPONENT-837;Lo;0;L;;;;;N;;;;; +18DC5;TANGUT COMPONENT-838;Lo;0;L;;;;;N;;;;; +18DC6;TANGUT COMPONENT-839;Lo;0;L;;;;;N;;;;; +18DC7;TANGUT COMPONENT-840;Lo;0;L;;;;;N;;;;; +18DC8;TANGUT COMPONENT-841;Lo;0;L;;;;;N;;;;; +18DC9;TANGUT COMPONENT-842;Lo;0;L;;;;;N;;;;; +18DCA;TANGUT COMPONENT-843;Lo;0;L;;;;;N;;;;; +18DCB;TANGUT COMPONENT-844;Lo;0;L;;;;;N;;;;; +18DCC;TANGUT COMPONENT-845;Lo;0;L;;;;;N;;;;; +18DCD;TANGUT COMPONENT-846;Lo;0;L;;;;;N;;;;; +18DCE;TANGUT COMPONENT-847;Lo;0;L;;;;;N;;;;; +18DCF;TANGUT COMPONENT-848;Lo;0;L;;;;;N;;;;; +18DD0;TANGUT COMPONENT-849;Lo;0;L;;;;;N;;;;; +18DD1;TANGUT COMPONENT-850;Lo;0;L;;;;;N;;;;; +18DD2;TANGUT COMPONENT-851;Lo;0;L;;;;;N;;;;; +18DD3;TANGUT COMPONENT-852;Lo;0;L;;;;;N;;;;; +18DD4;TANGUT COMPONENT-853;Lo;0;L;;;;;N;;;;; +18DD5;TANGUT COMPONENT-854;Lo;0;L;;;;;N;;;;; +18DD6;TANGUT COMPONENT-855;Lo;0;L;;;;;N;;;;; +18DD7;TANGUT COMPONENT-856;Lo;0;L;;;;;N;;;;; +18DD8;TANGUT COMPONENT-857;Lo;0;L;;;;;N;;;;; +18DD9;TANGUT COMPONENT-858;Lo;0;L;;;;;N;;;;; +18DDA;TANGUT COMPONENT-859;Lo;0;L;;;;;N;;;;; +18DDB;TANGUT COMPONENT-860;Lo;0;L;;;;;N;;;;; +18DDC;TANGUT COMPONENT-861;Lo;0;L;;;;;N;;;;; +18DDD;TANGUT COMPONENT-862;Lo;0;L;;;;;N;;;;; +18DDE;TANGUT COMPONENT-863;Lo;0;L;;;;;N;;;;; +18DDF;TANGUT COMPONENT-864;Lo;0;L;;;;;N;;;;; +18DE0;TANGUT COMPONENT-865;Lo;0;L;;;;;N;;;;; +18DE1;TANGUT COMPONENT-866;Lo;0;L;;;;;N;;;;; +18DE2;TANGUT COMPONENT-867;Lo;0;L;;;;;N;;;;; +18DE3;TANGUT COMPONENT-868;Lo;0;L;;;;;N;;;;; +18DE4;TANGUT COMPONENT-869;Lo;0;L;;;;;N;;;;; +18DE5;TANGUT COMPONENT-870;Lo;0;L;;;;;N;;;;; +18DE6;TANGUT COMPONENT-871;Lo;0;L;;;;;N;;;;; +18DE7;TANGUT COMPONENT-872;Lo;0;L;;;;;N;;;;; +18DE8;TANGUT COMPONENT-873;Lo;0;L;;;;;N;;;;; +18DE9;TANGUT COMPONENT-874;Lo;0;L;;;;;N;;;;; +18DEA;TANGUT COMPONENT-875;Lo;0;L;;;;;N;;;;; +18DEB;TANGUT COMPONENT-876;Lo;0;L;;;;;N;;;;; +18DEC;TANGUT COMPONENT-877;Lo;0;L;;;;;N;;;;; +18DED;TANGUT COMPONENT-878;Lo;0;L;;;;;N;;;;; +18DEE;TANGUT COMPONENT-879;Lo;0;L;;;;;N;;;;; +18DEF;TANGUT COMPONENT-880;Lo;0;L;;;;;N;;;;; +18DF0;TANGUT COMPONENT-881;Lo;0;L;;;;;N;;;;; +18DF1;TANGUT COMPONENT-882;Lo;0;L;;;;;N;;;;; +18DF2;TANGUT COMPONENT-883;Lo;0;L;;;;;N;;;;; +1AFF0;KATAKANA LETTER MINNAN TONE-2;Lm;0;L;;;;;N;;;;; +1AFF1;KATAKANA LETTER MINNAN TONE-3;Lm;0;L;;;;;N;;;;; +1AFF2;KATAKANA LETTER MINNAN TONE-4;Lm;0;L;;;;;N;;;;; +1AFF3;KATAKANA LETTER MINNAN TONE-5;Lm;0;L;;;;;N;;;;; +1AFF5;KATAKANA LETTER MINNAN TONE-7;Lm;0;L;;;;;N;;;;; +1AFF6;KATAKANA LETTER MINNAN TONE-8;Lm;0;L;;;;;N;;;;; +1AFF7;KATAKANA LETTER MINNAN NASALIZED TONE-1;Lm;0;L;;;;;N;;;;; +1AFF8;KATAKANA LETTER MINNAN NASALIZED TONE-2;Lm;0;L;;;;;N;;;;; +1AFF9;KATAKANA LETTER MINNAN NASALIZED TONE-3;Lm;0;L;;;;;N;;;;; +1AFFA;KATAKANA LETTER MINNAN NASALIZED TONE-4;Lm;0;L;;;;;N;;;;; +1AFFB;KATAKANA LETTER MINNAN NASALIZED TONE-5;Lm;0;L;;;;;N;;;;; +1AFFD;KATAKANA LETTER MINNAN NASALIZED TONE-7;Lm;0;L;;;;;N;;;;; +1AFFE;KATAKANA LETTER MINNAN NASALIZED TONE-8;Lm;0;L;;;;;N;;;;; +1B000;KATAKANA LETTER ARCHAIC E;Lo;0;L;;;;;N;;;;; +1B001;HIRAGANA LETTER ARCHAIC YE;Lo;0;L;;;;;N;;;;; +1B002;HENTAIGANA LETTER A-1;Lo;0;L;;;;;N;;;;; +1B003;HENTAIGANA LETTER A-2;Lo;0;L;;;;;N;;;;; +1B004;HENTAIGANA LETTER A-3;Lo;0;L;;;;;N;;;;; +1B005;HENTAIGANA LETTER A-WO;Lo;0;L;;;;;N;;;;; +1B006;HENTAIGANA LETTER I-1;Lo;0;L;;;;;N;;;;; +1B007;HENTAIGANA LETTER I-2;Lo;0;L;;;;;N;;;;; +1B008;HENTAIGANA LETTER I-3;Lo;0;L;;;;;N;;;;; +1B009;HENTAIGANA LETTER I-4;Lo;0;L;;;;;N;;;;; +1B00A;HENTAIGANA LETTER U-1;Lo;0;L;;;;;N;;;;; +1B00B;HENTAIGANA LETTER U-2;Lo;0;L;;;;;N;;;;; +1B00C;HENTAIGANA LETTER U-3;Lo;0;L;;;;;N;;;;; +1B00D;HENTAIGANA LETTER U-4;Lo;0;L;;;;;N;;;;; +1B00E;HENTAIGANA LETTER U-5;Lo;0;L;;;;;N;;;;; +1B00F;HENTAIGANA LETTER E-2;Lo;0;L;;;;;N;;;;; +1B010;HENTAIGANA LETTER E-3;Lo;0;L;;;;;N;;;;; +1B011;HENTAIGANA LETTER E-4;Lo;0;L;;;;;N;;;;; +1B012;HENTAIGANA LETTER E-5;Lo;0;L;;;;;N;;;;; +1B013;HENTAIGANA LETTER E-6;Lo;0;L;;;;;N;;;;; +1B014;HENTAIGANA LETTER O-1;Lo;0;L;;;;;N;;;;; +1B015;HENTAIGANA LETTER O-2;Lo;0;L;;;;;N;;;;; +1B016;HENTAIGANA LETTER O-3;Lo;0;L;;;;;N;;;;; +1B017;HENTAIGANA LETTER KA-1;Lo;0;L;;;;;N;;;;; +1B018;HENTAIGANA LETTER KA-2;Lo;0;L;;;;;N;;;;; +1B019;HENTAIGANA LETTER KA-3;Lo;0;L;;;;;N;;;;; +1B01A;HENTAIGANA LETTER KA-4;Lo;0;L;;;;;N;;;;; +1B01B;HENTAIGANA LETTER KA-5;Lo;0;L;;;;;N;;;;; +1B01C;HENTAIGANA LETTER KA-6;Lo;0;L;;;;;N;;;;; +1B01D;HENTAIGANA LETTER KA-7;Lo;0;L;;;;;N;;;;; +1B01E;HENTAIGANA LETTER KA-8;Lo;0;L;;;;;N;;;;; +1B01F;HENTAIGANA LETTER KA-9;Lo;0;L;;;;;N;;;;; +1B020;HENTAIGANA LETTER KA-10;Lo;0;L;;;;;N;;;;; +1B021;HENTAIGANA LETTER KA-11;Lo;0;L;;;;;N;;;;; +1B022;HENTAIGANA LETTER KA-KE;Lo;0;L;;;;;N;;;;; +1B023;HENTAIGANA LETTER KI-1;Lo;0;L;;;;;N;;;;; +1B024;HENTAIGANA LETTER KI-2;Lo;0;L;;;;;N;;;;; +1B025;HENTAIGANA LETTER KI-3;Lo;0;L;;;;;N;;;;; +1B026;HENTAIGANA LETTER KI-4;Lo;0;L;;;;;N;;;;; +1B027;HENTAIGANA LETTER KI-5;Lo;0;L;;;;;N;;;;; +1B028;HENTAIGANA LETTER KI-6;Lo;0;L;;;;;N;;;;; +1B029;HENTAIGANA LETTER KI-7;Lo;0;L;;;;;N;;;;; +1B02A;HENTAIGANA LETTER KI-8;Lo;0;L;;;;;N;;;;; +1B02B;HENTAIGANA LETTER KU-1;Lo;0;L;;;;;N;;;;; +1B02C;HENTAIGANA LETTER KU-2;Lo;0;L;;;;;N;;;;; +1B02D;HENTAIGANA LETTER KU-3;Lo;0;L;;;;;N;;;;; +1B02E;HENTAIGANA LETTER KU-4;Lo;0;L;;;;;N;;;;; +1B02F;HENTAIGANA LETTER KU-5;Lo;0;L;;;;;N;;;;; +1B030;HENTAIGANA LETTER KU-6;Lo;0;L;;;;;N;;;;; +1B031;HENTAIGANA LETTER KU-7;Lo;0;L;;;;;N;;;;; +1B032;HENTAIGANA LETTER KE-1;Lo;0;L;;;;;N;;;;; +1B033;HENTAIGANA LETTER KE-2;Lo;0;L;;;;;N;;;;; +1B034;HENTAIGANA LETTER KE-3;Lo;0;L;;;;;N;;;;; +1B035;HENTAIGANA LETTER KE-4;Lo;0;L;;;;;N;;;;; +1B036;HENTAIGANA LETTER KE-5;Lo;0;L;;;;;N;;;;; +1B037;HENTAIGANA LETTER KE-6;Lo;0;L;;;;;N;;;;; +1B038;HENTAIGANA LETTER KO-1;Lo;0;L;;;;;N;;;;; +1B039;HENTAIGANA LETTER KO-2;Lo;0;L;;;;;N;;;;; +1B03A;HENTAIGANA LETTER KO-3;Lo;0;L;;;;;N;;;;; +1B03B;HENTAIGANA LETTER KO-KI;Lo;0;L;;;;;N;;;;; +1B03C;HENTAIGANA LETTER SA-1;Lo;0;L;;;;;N;;;;; +1B03D;HENTAIGANA LETTER SA-2;Lo;0;L;;;;;N;;;;; +1B03E;HENTAIGANA LETTER SA-3;Lo;0;L;;;;;N;;;;; +1B03F;HENTAIGANA LETTER SA-4;Lo;0;L;;;;;N;;;;; +1B040;HENTAIGANA LETTER SA-5;Lo;0;L;;;;;N;;;;; +1B041;HENTAIGANA LETTER SA-6;Lo;0;L;;;;;N;;;;; +1B042;HENTAIGANA LETTER SA-7;Lo;0;L;;;;;N;;;;; +1B043;HENTAIGANA LETTER SA-8;Lo;0;L;;;;;N;;;;; +1B044;HENTAIGANA LETTER SI-1;Lo;0;L;;;;;N;;;;; +1B045;HENTAIGANA LETTER SI-2;Lo;0;L;;;;;N;;;;; +1B046;HENTAIGANA LETTER SI-3;Lo;0;L;;;;;N;;;;; +1B047;HENTAIGANA LETTER SI-4;Lo;0;L;;;;;N;;;;; +1B048;HENTAIGANA LETTER SI-5;Lo;0;L;;;;;N;;;;; +1B049;HENTAIGANA LETTER SI-6;Lo;0;L;;;;;N;;;;; +1B04A;HENTAIGANA LETTER SU-1;Lo;0;L;;;;;N;;;;; +1B04B;HENTAIGANA LETTER SU-2;Lo;0;L;;;;;N;;;;; +1B04C;HENTAIGANA LETTER SU-3;Lo;0;L;;;;;N;;;;; +1B04D;HENTAIGANA LETTER SU-4;Lo;0;L;;;;;N;;;;; +1B04E;HENTAIGANA LETTER SU-5;Lo;0;L;;;;;N;;;;; +1B04F;HENTAIGANA LETTER SU-6;Lo;0;L;;;;;N;;;;; +1B050;HENTAIGANA LETTER SU-7;Lo;0;L;;;;;N;;;;; +1B051;HENTAIGANA LETTER SU-8;Lo;0;L;;;;;N;;;;; +1B052;HENTAIGANA LETTER SE-1;Lo;0;L;;;;;N;;;;; +1B053;HENTAIGANA LETTER SE-2;Lo;0;L;;;;;N;;;;; +1B054;HENTAIGANA LETTER SE-3;Lo;0;L;;;;;N;;;;; +1B055;HENTAIGANA LETTER SE-4;Lo;0;L;;;;;N;;;;; +1B056;HENTAIGANA LETTER SE-5;Lo;0;L;;;;;N;;;;; +1B057;HENTAIGANA LETTER SO-1;Lo;0;L;;;;;N;;;;; +1B058;HENTAIGANA LETTER SO-2;Lo;0;L;;;;;N;;;;; +1B059;HENTAIGANA LETTER SO-3;Lo;0;L;;;;;N;;;;; +1B05A;HENTAIGANA LETTER SO-4;Lo;0;L;;;;;N;;;;; +1B05B;HENTAIGANA LETTER SO-5;Lo;0;L;;;;;N;;;;; +1B05C;HENTAIGANA LETTER SO-6;Lo;0;L;;;;;N;;;;; +1B05D;HENTAIGANA LETTER SO-7;Lo;0;L;;;;;N;;;;; +1B05E;HENTAIGANA LETTER TA-1;Lo;0;L;;;;;N;;;;; +1B05F;HENTAIGANA LETTER TA-2;Lo;0;L;;;;;N;;;;; +1B060;HENTAIGANA LETTER TA-3;Lo;0;L;;;;;N;;;;; +1B061;HENTAIGANA LETTER TA-4;Lo;0;L;;;;;N;;;;; +1B062;HENTAIGANA LETTER TI-1;Lo;0;L;;;;;N;;;;; +1B063;HENTAIGANA LETTER TI-2;Lo;0;L;;;;;N;;;;; +1B064;HENTAIGANA LETTER TI-3;Lo;0;L;;;;;N;;;;; +1B065;HENTAIGANA LETTER TI-4;Lo;0;L;;;;;N;;;;; +1B066;HENTAIGANA LETTER TI-5;Lo;0;L;;;;;N;;;;; +1B067;HENTAIGANA LETTER TI-6;Lo;0;L;;;;;N;;;;; +1B068;HENTAIGANA LETTER TI-7;Lo;0;L;;;;;N;;;;; +1B069;HENTAIGANA LETTER TU-1;Lo;0;L;;;;;N;;;;; +1B06A;HENTAIGANA LETTER TU-2;Lo;0;L;;;;;N;;;;; +1B06B;HENTAIGANA LETTER TU-3;Lo;0;L;;;;;N;;;;; +1B06C;HENTAIGANA LETTER TU-4;Lo;0;L;;;;;N;;;;; +1B06D;HENTAIGANA LETTER TU-TO;Lo;0;L;;;;;N;;;;; +1B06E;HENTAIGANA LETTER TE-1;Lo;0;L;;;;;N;;;;; +1B06F;HENTAIGANA LETTER TE-2;Lo;0;L;;;;;N;;;;; +1B070;HENTAIGANA LETTER TE-3;Lo;0;L;;;;;N;;;;; +1B071;HENTAIGANA LETTER TE-4;Lo;0;L;;;;;N;;;;; +1B072;HENTAIGANA LETTER TE-5;Lo;0;L;;;;;N;;;;; +1B073;HENTAIGANA LETTER TE-6;Lo;0;L;;;;;N;;;;; +1B074;HENTAIGANA LETTER TE-7;Lo;0;L;;;;;N;;;;; +1B075;HENTAIGANA LETTER TE-8;Lo;0;L;;;;;N;;;;; +1B076;HENTAIGANA LETTER TE-9;Lo;0;L;;;;;N;;;;; +1B077;HENTAIGANA LETTER TO-1;Lo;0;L;;;;;N;;;;; +1B078;HENTAIGANA LETTER TO-2;Lo;0;L;;;;;N;;;;; +1B079;HENTAIGANA LETTER TO-3;Lo;0;L;;;;;N;;;;; +1B07A;HENTAIGANA LETTER TO-4;Lo;0;L;;;;;N;;;;; +1B07B;HENTAIGANA LETTER TO-5;Lo;0;L;;;;;N;;;;; +1B07C;HENTAIGANA LETTER TO-6;Lo;0;L;;;;;N;;;;; +1B07D;HENTAIGANA LETTER TO-RA;Lo;0;L;;;;;N;;;;; +1B07E;HENTAIGANA LETTER NA-1;Lo;0;L;;;;;N;;;;; +1B07F;HENTAIGANA LETTER NA-2;Lo;0;L;;;;;N;;;;; +1B080;HENTAIGANA LETTER NA-3;Lo;0;L;;;;;N;;;;; +1B081;HENTAIGANA LETTER NA-4;Lo;0;L;;;;;N;;;;; +1B082;HENTAIGANA LETTER NA-5;Lo;0;L;;;;;N;;;;; +1B083;HENTAIGANA LETTER NA-6;Lo;0;L;;;;;N;;;;; +1B084;HENTAIGANA LETTER NA-7;Lo;0;L;;;;;N;;;;; +1B085;HENTAIGANA LETTER NA-8;Lo;0;L;;;;;N;;;;; +1B086;HENTAIGANA LETTER NA-9;Lo;0;L;;;;;N;;;;; +1B087;HENTAIGANA LETTER NI-1;Lo;0;L;;;;;N;;;;; +1B088;HENTAIGANA LETTER NI-2;Lo;0;L;;;;;N;;;;; +1B089;HENTAIGANA LETTER NI-3;Lo;0;L;;;;;N;;;;; +1B08A;HENTAIGANA LETTER NI-4;Lo;0;L;;;;;N;;;;; +1B08B;HENTAIGANA LETTER NI-5;Lo;0;L;;;;;N;;;;; +1B08C;HENTAIGANA LETTER NI-6;Lo;0;L;;;;;N;;;;; +1B08D;HENTAIGANA LETTER NI-7;Lo;0;L;;;;;N;;;;; +1B08E;HENTAIGANA LETTER NI-TE;Lo;0;L;;;;;N;;;;; +1B08F;HENTAIGANA LETTER NU-1;Lo;0;L;;;;;N;;;;; +1B090;HENTAIGANA LETTER NU-2;Lo;0;L;;;;;N;;;;; +1B091;HENTAIGANA LETTER NU-3;Lo;0;L;;;;;N;;;;; +1B092;HENTAIGANA LETTER NE-1;Lo;0;L;;;;;N;;;;; +1B093;HENTAIGANA LETTER NE-2;Lo;0;L;;;;;N;;;;; +1B094;HENTAIGANA LETTER NE-3;Lo;0;L;;;;;N;;;;; +1B095;HENTAIGANA LETTER NE-4;Lo;0;L;;;;;N;;;;; +1B096;HENTAIGANA LETTER NE-5;Lo;0;L;;;;;N;;;;; +1B097;HENTAIGANA LETTER NE-6;Lo;0;L;;;;;N;;;;; +1B098;HENTAIGANA LETTER NE-KO;Lo;0;L;;;;;N;;;;; +1B099;HENTAIGANA LETTER NO-1;Lo;0;L;;;;;N;;;;; +1B09A;HENTAIGANA LETTER NO-2;Lo;0;L;;;;;N;;;;; +1B09B;HENTAIGANA LETTER NO-3;Lo;0;L;;;;;N;;;;; +1B09C;HENTAIGANA LETTER NO-4;Lo;0;L;;;;;N;;;;; +1B09D;HENTAIGANA LETTER NO-5;Lo;0;L;;;;;N;;;;; +1B09E;HENTAIGANA LETTER HA-1;Lo;0;L;;;;;N;;;;; +1B09F;HENTAIGANA LETTER HA-2;Lo;0;L;;;;;N;;;;; +1B0A0;HENTAIGANA LETTER HA-3;Lo;0;L;;;;;N;;;;; +1B0A1;HENTAIGANA LETTER HA-4;Lo;0;L;;;;;N;;;;; +1B0A2;HENTAIGANA LETTER HA-5;Lo;0;L;;;;;N;;;;; +1B0A3;HENTAIGANA LETTER HA-6;Lo;0;L;;;;;N;;;;; +1B0A4;HENTAIGANA LETTER HA-7;Lo;0;L;;;;;N;;;;; +1B0A5;HENTAIGANA LETTER HA-8;Lo;0;L;;;;;N;;;;; +1B0A6;HENTAIGANA LETTER HA-9;Lo;0;L;;;;;N;;;;; +1B0A7;HENTAIGANA LETTER HA-10;Lo;0;L;;;;;N;;;;; +1B0A8;HENTAIGANA LETTER HA-11;Lo;0;L;;;;;N;;;;; +1B0A9;HENTAIGANA LETTER HI-1;Lo;0;L;;;;;N;;;;; +1B0AA;HENTAIGANA LETTER HI-2;Lo;0;L;;;;;N;;;;; +1B0AB;HENTAIGANA LETTER HI-3;Lo;0;L;;;;;N;;;;; +1B0AC;HENTAIGANA LETTER HI-4;Lo;0;L;;;;;N;;;;; +1B0AD;HENTAIGANA LETTER HI-5;Lo;0;L;;;;;N;;;;; +1B0AE;HENTAIGANA LETTER HI-6;Lo;0;L;;;;;N;;;;; +1B0AF;HENTAIGANA LETTER HI-7;Lo;0;L;;;;;N;;;;; +1B0B0;HENTAIGANA LETTER HU-1;Lo;0;L;;;;;N;;;;; +1B0B1;HENTAIGANA LETTER HU-2;Lo;0;L;;;;;N;;;;; +1B0B2;HENTAIGANA LETTER HU-3;Lo;0;L;;;;;N;;;;; +1B0B3;HENTAIGANA LETTER HE-1;Lo;0;L;;;;;N;;;;; +1B0B4;HENTAIGANA LETTER HE-2;Lo;0;L;;;;;N;;;;; +1B0B5;HENTAIGANA LETTER HE-3;Lo;0;L;;;;;N;;;;; +1B0B6;HENTAIGANA LETTER HE-4;Lo;0;L;;;;;N;;;;; +1B0B7;HENTAIGANA LETTER HE-5;Lo;0;L;;;;;N;;;;; +1B0B8;HENTAIGANA LETTER HE-6;Lo;0;L;;;;;N;;;;; +1B0B9;HENTAIGANA LETTER HE-7;Lo;0;L;;;;;N;;;;; +1B0BA;HENTAIGANA LETTER HO-1;Lo;0;L;;;;;N;;;;; +1B0BB;HENTAIGANA LETTER HO-2;Lo;0;L;;;;;N;;;;; +1B0BC;HENTAIGANA LETTER HO-3;Lo;0;L;;;;;N;;;;; +1B0BD;HENTAIGANA LETTER HO-4;Lo;0;L;;;;;N;;;;; +1B0BE;HENTAIGANA LETTER HO-5;Lo;0;L;;;;;N;;;;; +1B0BF;HENTAIGANA LETTER HO-6;Lo;0;L;;;;;N;;;;; +1B0C0;HENTAIGANA LETTER HO-7;Lo;0;L;;;;;N;;;;; +1B0C1;HENTAIGANA LETTER HO-8;Lo;0;L;;;;;N;;;;; +1B0C2;HENTAIGANA LETTER MA-1;Lo;0;L;;;;;N;;;;; +1B0C3;HENTAIGANA LETTER MA-2;Lo;0;L;;;;;N;;;;; +1B0C4;HENTAIGANA LETTER MA-3;Lo;0;L;;;;;N;;;;; +1B0C5;HENTAIGANA LETTER MA-4;Lo;0;L;;;;;N;;;;; +1B0C6;HENTAIGANA LETTER MA-5;Lo;0;L;;;;;N;;;;; +1B0C7;HENTAIGANA LETTER MA-6;Lo;0;L;;;;;N;;;;; +1B0C8;HENTAIGANA LETTER MA-7;Lo;0;L;;;;;N;;;;; +1B0C9;HENTAIGANA LETTER MI-1;Lo;0;L;;;;;N;;;;; +1B0CA;HENTAIGANA LETTER MI-2;Lo;0;L;;;;;N;;;;; +1B0CB;HENTAIGANA LETTER MI-3;Lo;0;L;;;;;N;;;;; +1B0CC;HENTAIGANA LETTER MI-4;Lo;0;L;;;;;N;;;;; +1B0CD;HENTAIGANA LETTER MI-5;Lo;0;L;;;;;N;;;;; +1B0CE;HENTAIGANA LETTER MI-6;Lo;0;L;;;;;N;;;;; +1B0CF;HENTAIGANA LETTER MI-7;Lo;0;L;;;;;N;;;;; +1B0D0;HENTAIGANA LETTER MU-1;Lo;0;L;;;;;N;;;;; +1B0D1;HENTAIGANA LETTER MU-2;Lo;0;L;;;;;N;;;;; +1B0D2;HENTAIGANA LETTER MU-3;Lo;0;L;;;;;N;;;;; +1B0D3;HENTAIGANA LETTER MU-4;Lo;0;L;;;;;N;;;;; +1B0D4;HENTAIGANA LETTER ME-1;Lo;0;L;;;;;N;;;;; +1B0D5;HENTAIGANA LETTER ME-2;Lo;0;L;;;;;N;;;;; +1B0D6;HENTAIGANA LETTER ME-MA;Lo;0;L;;;;;N;;;;; +1B0D7;HENTAIGANA LETTER MO-1;Lo;0;L;;;;;N;;;;; +1B0D8;HENTAIGANA LETTER MO-2;Lo;0;L;;;;;N;;;;; +1B0D9;HENTAIGANA LETTER MO-3;Lo;0;L;;;;;N;;;;; +1B0DA;HENTAIGANA LETTER MO-4;Lo;0;L;;;;;N;;;;; +1B0DB;HENTAIGANA LETTER MO-5;Lo;0;L;;;;;N;;;;; +1B0DC;HENTAIGANA LETTER MO-6;Lo;0;L;;;;;N;;;;; +1B0DD;HENTAIGANA LETTER YA-1;Lo;0;L;;;;;N;;;;; +1B0DE;HENTAIGANA LETTER YA-2;Lo;0;L;;;;;N;;;;; +1B0DF;HENTAIGANA LETTER YA-3;Lo;0;L;;;;;N;;;;; +1B0E0;HENTAIGANA LETTER YA-4;Lo;0;L;;;;;N;;;;; +1B0E1;HENTAIGANA LETTER YA-5;Lo;0;L;;;;;N;;;;; +1B0E2;HENTAIGANA LETTER YA-YO;Lo;0;L;;;;;N;;;;; +1B0E3;HENTAIGANA LETTER YU-1;Lo;0;L;;;;;N;;;;; +1B0E4;HENTAIGANA LETTER YU-2;Lo;0;L;;;;;N;;;;; +1B0E5;HENTAIGANA LETTER YU-3;Lo;0;L;;;;;N;;;;; +1B0E6;HENTAIGANA LETTER YU-4;Lo;0;L;;;;;N;;;;; +1B0E7;HENTAIGANA LETTER YO-1;Lo;0;L;;;;;N;;;;; +1B0E8;HENTAIGANA LETTER YO-2;Lo;0;L;;;;;N;;;;; +1B0E9;HENTAIGANA LETTER YO-3;Lo;0;L;;;;;N;;;;; +1B0EA;HENTAIGANA LETTER YO-4;Lo;0;L;;;;;N;;;;; +1B0EB;HENTAIGANA LETTER YO-5;Lo;0;L;;;;;N;;;;; +1B0EC;HENTAIGANA LETTER YO-6;Lo;0;L;;;;;N;;;;; +1B0ED;HENTAIGANA LETTER RA-1;Lo;0;L;;;;;N;;;;; +1B0EE;HENTAIGANA LETTER RA-2;Lo;0;L;;;;;N;;;;; +1B0EF;HENTAIGANA LETTER RA-3;Lo;0;L;;;;;N;;;;; +1B0F0;HENTAIGANA LETTER RA-4;Lo;0;L;;;;;N;;;;; +1B0F1;HENTAIGANA LETTER RI-1;Lo;0;L;;;;;N;;;;; +1B0F2;HENTAIGANA LETTER RI-2;Lo;0;L;;;;;N;;;;; +1B0F3;HENTAIGANA LETTER RI-3;Lo;0;L;;;;;N;;;;; +1B0F4;HENTAIGANA LETTER RI-4;Lo;0;L;;;;;N;;;;; +1B0F5;HENTAIGANA LETTER RI-5;Lo;0;L;;;;;N;;;;; +1B0F6;HENTAIGANA LETTER RI-6;Lo;0;L;;;;;N;;;;; +1B0F7;HENTAIGANA LETTER RI-7;Lo;0;L;;;;;N;;;;; +1B0F8;HENTAIGANA LETTER RU-1;Lo;0;L;;;;;N;;;;; +1B0F9;HENTAIGANA LETTER RU-2;Lo;0;L;;;;;N;;;;; +1B0FA;HENTAIGANA LETTER RU-3;Lo;0;L;;;;;N;;;;; +1B0FB;HENTAIGANA LETTER RU-4;Lo;0;L;;;;;N;;;;; +1B0FC;HENTAIGANA LETTER RU-5;Lo;0;L;;;;;N;;;;; +1B0FD;HENTAIGANA LETTER RU-6;Lo;0;L;;;;;N;;;;; +1B0FE;HENTAIGANA LETTER RE-1;Lo;0;L;;;;;N;;;;; +1B0FF;HENTAIGANA LETTER RE-2;Lo;0;L;;;;;N;;;;; +1B100;HENTAIGANA LETTER RE-3;Lo;0;L;;;;;N;;;;; +1B101;HENTAIGANA LETTER RE-4;Lo;0;L;;;;;N;;;;; +1B102;HENTAIGANA LETTER RO-1;Lo;0;L;;;;;N;;;;; +1B103;HENTAIGANA LETTER RO-2;Lo;0;L;;;;;N;;;;; +1B104;HENTAIGANA LETTER RO-3;Lo;0;L;;;;;N;;;;; +1B105;HENTAIGANA LETTER RO-4;Lo;0;L;;;;;N;;;;; +1B106;HENTAIGANA LETTER RO-5;Lo;0;L;;;;;N;;;;; +1B107;HENTAIGANA LETTER RO-6;Lo;0;L;;;;;N;;;;; +1B108;HENTAIGANA LETTER WA-1;Lo;0;L;;;;;N;;;;; +1B109;HENTAIGANA LETTER WA-2;Lo;0;L;;;;;N;;;;; +1B10A;HENTAIGANA LETTER WA-3;Lo;0;L;;;;;N;;;;; +1B10B;HENTAIGANA LETTER WA-4;Lo;0;L;;;;;N;;;;; +1B10C;HENTAIGANA LETTER WA-5;Lo;0;L;;;;;N;;;;; +1B10D;HENTAIGANA LETTER WI-1;Lo;0;L;;;;;N;;;;; +1B10E;HENTAIGANA LETTER WI-2;Lo;0;L;;;;;N;;;;; +1B10F;HENTAIGANA LETTER WI-3;Lo;0;L;;;;;N;;;;; +1B110;HENTAIGANA LETTER WI-4;Lo;0;L;;;;;N;;;;; +1B111;HENTAIGANA LETTER WI-5;Lo;0;L;;;;;N;;;;; +1B112;HENTAIGANA LETTER WE-1;Lo;0;L;;;;;N;;;;; +1B113;HENTAIGANA LETTER WE-2;Lo;0;L;;;;;N;;;;; +1B114;HENTAIGANA LETTER WE-3;Lo;0;L;;;;;N;;;;; +1B115;HENTAIGANA LETTER WE-4;Lo;0;L;;;;;N;;;;; +1B116;HENTAIGANA LETTER WO-1;Lo;0;L;;;;;N;;;;; +1B117;HENTAIGANA LETTER WO-2;Lo;0;L;;;;;N;;;;; +1B118;HENTAIGANA LETTER WO-3;Lo;0;L;;;;;N;;;;; +1B119;HENTAIGANA LETTER WO-4;Lo;0;L;;;;;N;;;;; +1B11A;HENTAIGANA LETTER WO-5;Lo;0;L;;;;;N;;;;; +1B11B;HENTAIGANA LETTER WO-6;Lo;0;L;;;;;N;;;;; +1B11C;HENTAIGANA LETTER WO-7;Lo;0;L;;;;;N;;;;; +1B11D;HENTAIGANA LETTER N-MU-MO-1;Lo;0;L;;;;;N;;;;; +1B11E;HENTAIGANA LETTER N-MU-MO-2;Lo;0;L;;;;;N;;;;; +1B11F;HIRAGANA LETTER ARCHAIC WU;Lo;0;L;;;;;N;;;;; +1B120;KATAKANA LETTER ARCHAIC YI;Lo;0;L;;;;;N;;;;; +1B121;KATAKANA LETTER ARCHAIC YE;Lo;0;L;;;;;N;;;;; +1B122;KATAKANA LETTER ARCHAIC WU;Lo;0;L;;;;;N;;;;; +1B132;HIRAGANA LETTER SMALL KO;Lo;0;L;;;;;N;;;;; +1B150;HIRAGANA LETTER SMALL WI;Lo;0;L;;;;;N;;;;; +1B151;HIRAGANA LETTER SMALL WE;Lo;0;L;;;;;N;;;;; +1B152;HIRAGANA LETTER SMALL WO;Lo;0;L;;;;;N;;;;; +1B155;KATAKANA LETTER SMALL KO;Lo;0;L;;;;;N;;;;; +1B164;KATAKANA LETTER SMALL WI;Lo;0;L;;;;;N;;;;; +1B165;KATAKANA LETTER SMALL WE;Lo;0;L;;;;;N;;;;; +1B166;KATAKANA LETTER SMALL WO;Lo;0;L;;;;;N;;;;; +1B167;KATAKANA LETTER SMALL N;Lo;0;L;;;;;N;;;;; +1B170;NUSHU CHARACTER-1B170;Lo;0;L;;;;;N;;;;; +1B171;NUSHU CHARACTER-1B171;Lo;0;L;;;;;N;;;;; +1B172;NUSHU CHARACTER-1B172;Lo;0;L;;;;;N;;;;; +1B173;NUSHU CHARACTER-1B173;Lo;0;L;;;;;N;;;;; +1B174;NUSHU CHARACTER-1B174;Lo;0;L;;;;;N;;;;; +1B175;NUSHU CHARACTER-1B175;Lo;0;L;;;;;N;;;;; +1B176;NUSHU CHARACTER-1B176;Lo;0;L;;;;;N;;;;; +1B177;NUSHU CHARACTER-1B177;Lo;0;L;;;;;N;;;;; +1B178;NUSHU CHARACTER-1B178;Lo;0;L;;;;;N;;;;; +1B179;NUSHU CHARACTER-1B179;Lo;0;L;;;;;N;;;;; +1B17A;NUSHU CHARACTER-1B17A;Lo;0;L;;;;;N;;;;; +1B17B;NUSHU CHARACTER-1B17B;Lo;0;L;;;;;N;;;;; +1B17C;NUSHU CHARACTER-1B17C;Lo;0;L;;;;;N;;;;; +1B17D;NUSHU CHARACTER-1B17D;Lo;0;L;;;;;N;;;;; +1B17E;NUSHU CHARACTER-1B17E;Lo;0;L;;;;;N;;;;; +1B17F;NUSHU CHARACTER-1B17F;Lo;0;L;;;;;N;;;;; +1B180;NUSHU CHARACTER-1B180;Lo;0;L;;;;;N;;;;; +1B181;NUSHU CHARACTER-1B181;Lo;0;L;;;;;N;;;;; +1B182;NUSHU CHARACTER-1B182;Lo;0;L;;;;;N;;;;; +1B183;NUSHU CHARACTER-1B183;Lo;0;L;;;;;N;;;;; +1B184;NUSHU CHARACTER-1B184;Lo;0;L;;;;;N;;;;; +1B185;NUSHU CHARACTER-1B185;Lo;0;L;;;;;N;;;;; +1B186;NUSHU CHARACTER-1B186;Lo;0;L;;;;;N;;;;; +1B187;NUSHU CHARACTER-1B187;Lo;0;L;;;;;N;;;;; +1B188;NUSHU CHARACTER-1B188;Lo;0;L;;;;;N;;;;; +1B189;NUSHU CHARACTER-1B189;Lo;0;L;;;;;N;;;;; +1B18A;NUSHU CHARACTER-1B18A;Lo;0;L;;;;;N;;;;; +1B18B;NUSHU CHARACTER-1B18B;Lo;0;L;;;;;N;;;;; +1B18C;NUSHU CHARACTER-1B18C;Lo;0;L;;;;;N;;;;; +1B18D;NUSHU CHARACTER-1B18D;Lo;0;L;;;;;N;;;;; +1B18E;NUSHU CHARACTER-1B18E;Lo;0;L;;;;;N;;;;; +1B18F;NUSHU CHARACTER-1B18F;Lo;0;L;;;;;N;;;;; +1B190;NUSHU CHARACTER-1B190;Lo;0;L;;;;;N;;;;; +1B191;NUSHU CHARACTER-1B191;Lo;0;L;;;;;N;;;;; +1B192;NUSHU CHARACTER-1B192;Lo;0;L;;;;;N;;;;; +1B193;NUSHU CHARACTER-1B193;Lo;0;L;;;;;N;;;;; +1B194;NUSHU CHARACTER-1B194;Lo;0;L;;;;;N;;;;; +1B195;NUSHU CHARACTER-1B195;Lo;0;L;;;;;N;;;;; +1B196;NUSHU CHARACTER-1B196;Lo;0;L;;;;;N;;;;; +1B197;NUSHU CHARACTER-1B197;Lo;0;L;;;;;N;;;;; +1B198;NUSHU CHARACTER-1B198;Lo;0;L;;;;;N;;;;; +1B199;NUSHU CHARACTER-1B199;Lo;0;L;;;;;N;;;;; +1B19A;NUSHU CHARACTER-1B19A;Lo;0;L;;;;;N;;;;; +1B19B;NUSHU CHARACTER-1B19B;Lo;0;L;;;;;N;;;;; +1B19C;NUSHU CHARACTER-1B19C;Lo;0;L;;;;;N;;;;; +1B19D;NUSHU CHARACTER-1B19D;Lo;0;L;;;;;N;;;;; +1B19E;NUSHU CHARACTER-1B19E;Lo;0;L;;;;;N;;;;; +1B19F;NUSHU CHARACTER-1B19F;Lo;0;L;;;;;N;;;;; +1B1A0;NUSHU CHARACTER-1B1A0;Lo;0;L;;;;;N;;;;; +1B1A1;NUSHU CHARACTER-1B1A1;Lo;0;L;;;;;N;;;;; +1B1A2;NUSHU CHARACTER-1B1A2;Lo;0;L;;;;;N;;;;; +1B1A3;NUSHU CHARACTER-1B1A3;Lo;0;L;;;;;N;;;;; +1B1A4;NUSHU CHARACTER-1B1A4;Lo;0;L;;;;;N;;;;; +1B1A5;NUSHU CHARACTER-1B1A5;Lo;0;L;;;;;N;;;;; +1B1A6;NUSHU CHARACTER-1B1A6;Lo;0;L;;;;;N;;;;; +1B1A7;NUSHU CHARACTER-1B1A7;Lo;0;L;;;;;N;;;;; +1B1A8;NUSHU CHARACTER-1B1A8;Lo;0;L;;;;;N;;;;; +1B1A9;NUSHU CHARACTER-1B1A9;Lo;0;L;;;;;N;;;;; +1B1AA;NUSHU CHARACTER-1B1AA;Lo;0;L;;;;;N;;;;; +1B1AB;NUSHU CHARACTER-1B1AB;Lo;0;L;;;;;N;;;;; +1B1AC;NUSHU CHARACTER-1B1AC;Lo;0;L;;;;;N;;;;; +1B1AD;NUSHU CHARACTER-1B1AD;Lo;0;L;;;;;N;;;;; +1B1AE;NUSHU CHARACTER-1B1AE;Lo;0;L;;;;;N;;;;; +1B1AF;NUSHU CHARACTER-1B1AF;Lo;0;L;;;;;N;;;;; +1B1B0;NUSHU CHARACTER-1B1B0;Lo;0;L;;;;;N;;;;; +1B1B1;NUSHU CHARACTER-1B1B1;Lo;0;L;;;;;N;;;;; +1B1B2;NUSHU CHARACTER-1B1B2;Lo;0;L;;;;;N;;;;; +1B1B3;NUSHU CHARACTER-1B1B3;Lo;0;L;;;;;N;;;;; +1B1B4;NUSHU CHARACTER-1B1B4;Lo;0;L;;;;;N;;;;; +1B1B5;NUSHU CHARACTER-1B1B5;Lo;0;L;;;;;N;;;;; +1B1B6;NUSHU CHARACTER-1B1B6;Lo;0;L;;;;;N;;;;; +1B1B7;NUSHU CHARACTER-1B1B7;Lo;0;L;;;;;N;;;;; +1B1B8;NUSHU CHARACTER-1B1B8;Lo;0;L;;;;;N;;;;; +1B1B9;NUSHU CHARACTER-1B1B9;Lo;0;L;;;;;N;;;;; +1B1BA;NUSHU CHARACTER-1B1BA;Lo;0;L;;;;;N;;;;; +1B1BB;NUSHU CHARACTER-1B1BB;Lo;0;L;;;;;N;;;;; +1B1BC;NUSHU CHARACTER-1B1BC;Lo;0;L;;;;;N;;;;; +1B1BD;NUSHU CHARACTER-1B1BD;Lo;0;L;;;;;N;;;;; +1B1BE;NUSHU CHARACTER-1B1BE;Lo;0;L;;;;;N;;;;; +1B1BF;NUSHU CHARACTER-1B1BF;Lo;0;L;;;;;N;;;;; +1B1C0;NUSHU CHARACTER-1B1C0;Lo;0;L;;;;;N;;;;; +1B1C1;NUSHU CHARACTER-1B1C1;Lo;0;L;;;;;N;;;;; +1B1C2;NUSHU CHARACTER-1B1C2;Lo;0;L;;;;;N;;;;; +1B1C3;NUSHU CHARACTER-1B1C3;Lo;0;L;;;;;N;;;;; +1B1C4;NUSHU CHARACTER-1B1C4;Lo;0;L;;;;;N;;;;; +1B1C5;NUSHU CHARACTER-1B1C5;Lo;0;L;;;;;N;;;;; +1B1C6;NUSHU CHARACTER-1B1C6;Lo;0;L;;;;;N;;;;; +1B1C7;NUSHU CHARACTER-1B1C7;Lo;0;L;;;;;N;;;;; +1B1C8;NUSHU CHARACTER-1B1C8;Lo;0;L;;;;;N;;;;; +1B1C9;NUSHU CHARACTER-1B1C9;Lo;0;L;;;;;N;;;;; +1B1CA;NUSHU CHARACTER-1B1CA;Lo;0;L;;;;;N;;;;; +1B1CB;NUSHU CHARACTER-1B1CB;Lo;0;L;;;;;N;;;;; +1B1CC;NUSHU CHARACTER-1B1CC;Lo;0;L;;;;;N;;;;; +1B1CD;NUSHU CHARACTER-1B1CD;Lo;0;L;;;;;N;;;;; +1B1CE;NUSHU CHARACTER-1B1CE;Lo;0;L;;;;;N;;;;; +1B1CF;NUSHU CHARACTER-1B1CF;Lo;0;L;;;;;N;;;;; +1B1D0;NUSHU CHARACTER-1B1D0;Lo;0;L;;;;;N;;;;; +1B1D1;NUSHU CHARACTER-1B1D1;Lo;0;L;;;;;N;;;;; +1B1D2;NUSHU CHARACTER-1B1D2;Lo;0;L;;;;;N;;;;; +1B1D3;NUSHU CHARACTER-1B1D3;Lo;0;L;;;;;N;;;;; +1B1D4;NUSHU CHARACTER-1B1D4;Lo;0;L;;;;;N;;;;; +1B1D5;NUSHU CHARACTER-1B1D5;Lo;0;L;;;;;N;;;;; +1B1D6;NUSHU CHARACTER-1B1D6;Lo;0;L;;;;;N;;;;; +1B1D7;NUSHU CHARACTER-1B1D7;Lo;0;L;;;;;N;;;;; +1B1D8;NUSHU CHARACTER-1B1D8;Lo;0;L;;;;;N;;;;; +1B1D9;NUSHU CHARACTER-1B1D9;Lo;0;L;;;;;N;;;;; +1B1DA;NUSHU CHARACTER-1B1DA;Lo;0;L;;;;;N;;;;; +1B1DB;NUSHU CHARACTER-1B1DB;Lo;0;L;;;;;N;;;;; +1B1DC;NUSHU CHARACTER-1B1DC;Lo;0;L;;;;;N;;;;; +1B1DD;NUSHU CHARACTER-1B1DD;Lo;0;L;;;;;N;;;;; +1B1DE;NUSHU CHARACTER-1B1DE;Lo;0;L;;;;;N;;;;; +1B1DF;NUSHU CHARACTER-1B1DF;Lo;0;L;;;;;N;;;;; +1B1E0;NUSHU CHARACTER-1B1E0;Lo;0;L;;;;;N;;;;; +1B1E1;NUSHU CHARACTER-1B1E1;Lo;0;L;;;;;N;;;;; +1B1E2;NUSHU CHARACTER-1B1E2;Lo;0;L;;;;;N;;;;; +1B1E3;NUSHU CHARACTER-1B1E3;Lo;0;L;;;;;N;;;;; +1B1E4;NUSHU CHARACTER-1B1E4;Lo;0;L;;;;;N;;;;; +1B1E5;NUSHU CHARACTER-1B1E5;Lo;0;L;;;;;N;;;;; +1B1E6;NUSHU CHARACTER-1B1E6;Lo;0;L;;;;;N;;;;; +1B1E7;NUSHU CHARACTER-1B1E7;Lo;0;L;;;;;N;;;;; +1B1E8;NUSHU CHARACTER-1B1E8;Lo;0;L;;;;;N;;;;; +1B1E9;NUSHU CHARACTER-1B1E9;Lo;0;L;;;;;N;;;;; +1B1EA;NUSHU CHARACTER-1B1EA;Lo;0;L;;;;;N;;;;; +1B1EB;NUSHU CHARACTER-1B1EB;Lo;0;L;;;;;N;;;;; +1B1EC;NUSHU CHARACTER-1B1EC;Lo;0;L;;;;;N;;;;; +1B1ED;NUSHU CHARACTER-1B1ED;Lo;0;L;;;;;N;;;;; +1B1EE;NUSHU CHARACTER-1B1EE;Lo;0;L;;;;;N;;;;; +1B1EF;NUSHU CHARACTER-1B1EF;Lo;0;L;;;;;N;;;;; +1B1F0;NUSHU CHARACTER-1B1F0;Lo;0;L;;;;;N;;;;; +1B1F1;NUSHU CHARACTER-1B1F1;Lo;0;L;;;;;N;;;;; +1B1F2;NUSHU CHARACTER-1B1F2;Lo;0;L;;;;;N;;;;; +1B1F3;NUSHU CHARACTER-1B1F3;Lo;0;L;;;;;N;;;;; +1B1F4;NUSHU CHARACTER-1B1F4;Lo;0;L;;;;;N;;;;; +1B1F5;NUSHU CHARACTER-1B1F5;Lo;0;L;;;;;N;;;;; +1B1F6;NUSHU CHARACTER-1B1F6;Lo;0;L;;;;;N;;;;; +1B1F7;NUSHU CHARACTER-1B1F7;Lo;0;L;;;;;N;;;;; +1B1F8;NUSHU CHARACTER-1B1F8;Lo;0;L;;;;;N;;;;; +1B1F9;NUSHU CHARACTER-1B1F9;Lo;0;L;;;;;N;;;;; +1B1FA;NUSHU CHARACTER-1B1FA;Lo;0;L;;;;;N;;;;; +1B1FB;NUSHU CHARACTER-1B1FB;Lo;0;L;;;;;N;;;;; +1B1FC;NUSHU CHARACTER-1B1FC;Lo;0;L;;;;;N;;;;; +1B1FD;NUSHU CHARACTER-1B1FD;Lo;0;L;;;;;N;;;;; +1B1FE;NUSHU CHARACTER-1B1FE;Lo;0;L;;;;;N;;;;; +1B1FF;NUSHU CHARACTER-1B1FF;Lo;0;L;;;;;N;;;;; +1B200;NUSHU CHARACTER-1B200;Lo;0;L;;;;;N;;;;; +1B201;NUSHU CHARACTER-1B201;Lo;0;L;;;;;N;;;;; +1B202;NUSHU CHARACTER-1B202;Lo;0;L;;;;;N;;;;; +1B203;NUSHU CHARACTER-1B203;Lo;0;L;;;;;N;;;;; +1B204;NUSHU CHARACTER-1B204;Lo;0;L;;;;;N;;;;; +1B205;NUSHU CHARACTER-1B205;Lo;0;L;;;;;N;;;;; +1B206;NUSHU CHARACTER-1B206;Lo;0;L;;;;;N;;;;; +1B207;NUSHU CHARACTER-1B207;Lo;0;L;;;;;N;;;;; +1B208;NUSHU CHARACTER-1B208;Lo;0;L;;;;;N;;;;; +1B209;NUSHU CHARACTER-1B209;Lo;0;L;;;;;N;;;;; +1B20A;NUSHU CHARACTER-1B20A;Lo;0;L;;;;;N;;;;; +1B20B;NUSHU CHARACTER-1B20B;Lo;0;L;;;;;N;;;;; +1B20C;NUSHU CHARACTER-1B20C;Lo;0;L;;;;;N;;;;; +1B20D;NUSHU CHARACTER-1B20D;Lo;0;L;;;;;N;;;;; +1B20E;NUSHU CHARACTER-1B20E;Lo;0;L;;;;;N;;;;; +1B20F;NUSHU CHARACTER-1B20F;Lo;0;L;;;;;N;;;;; +1B210;NUSHU CHARACTER-1B210;Lo;0;L;;;;;N;;;;; +1B211;NUSHU CHARACTER-1B211;Lo;0;L;;;;;N;;;;; +1B212;NUSHU CHARACTER-1B212;Lo;0;L;;;;;N;;;;; +1B213;NUSHU CHARACTER-1B213;Lo;0;L;;;;;N;;;;; +1B214;NUSHU CHARACTER-1B214;Lo;0;L;;;;;N;;;;; +1B215;NUSHU CHARACTER-1B215;Lo;0;L;;;;;N;;;;; +1B216;NUSHU CHARACTER-1B216;Lo;0;L;;;;;N;;;;; +1B217;NUSHU CHARACTER-1B217;Lo;0;L;;;;;N;;;;; +1B218;NUSHU CHARACTER-1B218;Lo;0;L;;;;;N;;;;; +1B219;NUSHU CHARACTER-1B219;Lo;0;L;;;;;N;;;;; +1B21A;NUSHU CHARACTER-1B21A;Lo;0;L;;;;;N;;;;; +1B21B;NUSHU CHARACTER-1B21B;Lo;0;L;;;;;N;;;;; +1B21C;NUSHU CHARACTER-1B21C;Lo;0;L;;;;;N;;;;; +1B21D;NUSHU CHARACTER-1B21D;Lo;0;L;;;;;N;;;;; +1B21E;NUSHU CHARACTER-1B21E;Lo;0;L;;;;;N;;;;; +1B21F;NUSHU CHARACTER-1B21F;Lo;0;L;;;;;N;;;;; +1B220;NUSHU CHARACTER-1B220;Lo;0;L;;;;;N;;;;; +1B221;NUSHU CHARACTER-1B221;Lo;0;L;;;;;N;;;;; +1B222;NUSHU CHARACTER-1B222;Lo;0;L;;;;;N;;;;; +1B223;NUSHU CHARACTER-1B223;Lo;0;L;;;;;N;;;;; +1B224;NUSHU CHARACTER-1B224;Lo;0;L;;;;;N;;;;; +1B225;NUSHU CHARACTER-1B225;Lo;0;L;;;;;N;;;;; +1B226;NUSHU CHARACTER-1B226;Lo;0;L;;;;;N;;;;; +1B227;NUSHU CHARACTER-1B227;Lo;0;L;;;;;N;;;;; +1B228;NUSHU CHARACTER-1B228;Lo;0;L;;;;;N;;;;; +1B229;NUSHU CHARACTER-1B229;Lo;0;L;;;;;N;;;;; +1B22A;NUSHU CHARACTER-1B22A;Lo;0;L;;;;;N;;;;; +1B22B;NUSHU CHARACTER-1B22B;Lo;0;L;;;;;N;;;;; +1B22C;NUSHU CHARACTER-1B22C;Lo;0;L;;;;;N;;;;; +1B22D;NUSHU CHARACTER-1B22D;Lo;0;L;;;;;N;;;;; +1B22E;NUSHU CHARACTER-1B22E;Lo;0;L;;;;;N;;;;; +1B22F;NUSHU CHARACTER-1B22F;Lo;0;L;;;;;N;;;;; +1B230;NUSHU CHARACTER-1B230;Lo;0;L;;;;;N;;;;; +1B231;NUSHU CHARACTER-1B231;Lo;0;L;;;;;N;;;;; +1B232;NUSHU CHARACTER-1B232;Lo;0;L;;;;;N;;;;; +1B233;NUSHU CHARACTER-1B233;Lo;0;L;;;;;N;;;;; +1B234;NUSHU CHARACTER-1B234;Lo;0;L;;;;;N;;;;; +1B235;NUSHU CHARACTER-1B235;Lo;0;L;;;;;N;;;;; +1B236;NUSHU CHARACTER-1B236;Lo;0;L;;;;;N;;;;; +1B237;NUSHU CHARACTER-1B237;Lo;0;L;;;;;N;;;;; +1B238;NUSHU CHARACTER-1B238;Lo;0;L;;;;;N;;;;; +1B239;NUSHU CHARACTER-1B239;Lo;0;L;;;;;N;;;;; +1B23A;NUSHU CHARACTER-1B23A;Lo;0;L;;;;;N;;;;; +1B23B;NUSHU CHARACTER-1B23B;Lo;0;L;;;;;N;;;;; +1B23C;NUSHU CHARACTER-1B23C;Lo;0;L;;;;;N;;;;; +1B23D;NUSHU CHARACTER-1B23D;Lo;0;L;;;;;N;;;;; +1B23E;NUSHU CHARACTER-1B23E;Lo;0;L;;;;;N;;;;; +1B23F;NUSHU CHARACTER-1B23F;Lo;0;L;;;;;N;;;;; +1B240;NUSHU CHARACTER-1B240;Lo;0;L;;;;;N;;;;; +1B241;NUSHU CHARACTER-1B241;Lo;0;L;;;;;N;;;;; +1B242;NUSHU CHARACTER-1B242;Lo;0;L;;;;;N;;;;; +1B243;NUSHU CHARACTER-1B243;Lo;0;L;;;;;N;;;;; +1B244;NUSHU CHARACTER-1B244;Lo;0;L;;;;;N;;;;; +1B245;NUSHU CHARACTER-1B245;Lo;0;L;;;;;N;;;;; +1B246;NUSHU CHARACTER-1B246;Lo;0;L;;;;;N;;;;; +1B247;NUSHU CHARACTER-1B247;Lo;0;L;;;;;N;;;;; +1B248;NUSHU CHARACTER-1B248;Lo;0;L;;;;;N;;;;; +1B249;NUSHU CHARACTER-1B249;Lo;0;L;;;;;N;;;;; +1B24A;NUSHU CHARACTER-1B24A;Lo;0;L;;;;;N;;;;; +1B24B;NUSHU CHARACTER-1B24B;Lo;0;L;;;;;N;;;;; +1B24C;NUSHU CHARACTER-1B24C;Lo;0;L;;;;;N;;;;; +1B24D;NUSHU CHARACTER-1B24D;Lo;0;L;;;;;N;;;;; +1B24E;NUSHU CHARACTER-1B24E;Lo;0;L;;;;;N;;;;; +1B24F;NUSHU CHARACTER-1B24F;Lo;0;L;;;;;N;;;;; +1B250;NUSHU CHARACTER-1B250;Lo;0;L;;;;;N;;;;; +1B251;NUSHU CHARACTER-1B251;Lo;0;L;;;;;N;;;;; +1B252;NUSHU CHARACTER-1B252;Lo;0;L;;;;;N;;;;; +1B253;NUSHU CHARACTER-1B253;Lo;0;L;;;;;N;;;;; +1B254;NUSHU CHARACTER-1B254;Lo;0;L;;;;;N;;;;; +1B255;NUSHU CHARACTER-1B255;Lo;0;L;;;;;N;;;;; +1B256;NUSHU CHARACTER-1B256;Lo;0;L;;;;;N;;;;; +1B257;NUSHU CHARACTER-1B257;Lo;0;L;;;;;N;;;;; +1B258;NUSHU CHARACTER-1B258;Lo;0;L;;;;;N;;;;; +1B259;NUSHU CHARACTER-1B259;Lo;0;L;;;;;N;;;;; +1B25A;NUSHU CHARACTER-1B25A;Lo;0;L;;;;;N;;;;; +1B25B;NUSHU CHARACTER-1B25B;Lo;0;L;;;;;N;;;;; +1B25C;NUSHU CHARACTER-1B25C;Lo;0;L;;;;;N;;;;; +1B25D;NUSHU CHARACTER-1B25D;Lo;0;L;;;;;N;;;;; +1B25E;NUSHU CHARACTER-1B25E;Lo;0;L;;;;;N;;;;; +1B25F;NUSHU CHARACTER-1B25F;Lo;0;L;;;;;N;;;;; +1B260;NUSHU CHARACTER-1B260;Lo;0;L;;;;;N;;;;; +1B261;NUSHU CHARACTER-1B261;Lo;0;L;;;;;N;;;;; +1B262;NUSHU CHARACTER-1B262;Lo;0;L;;;;;N;;;;; +1B263;NUSHU CHARACTER-1B263;Lo;0;L;;;;;N;;;;; +1B264;NUSHU CHARACTER-1B264;Lo;0;L;;;;;N;;;;; +1B265;NUSHU CHARACTER-1B265;Lo;0;L;;;;;N;;;;; +1B266;NUSHU CHARACTER-1B266;Lo;0;L;;;;;N;;;;; +1B267;NUSHU CHARACTER-1B267;Lo;0;L;;;;;N;;;;; +1B268;NUSHU CHARACTER-1B268;Lo;0;L;;;;;N;;;;; +1B269;NUSHU CHARACTER-1B269;Lo;0;L;;;;;N;;;;; +1B26A;NUSHU CHARACTER-1B26A;Lo;0;L;;;;;N;;;;; +1B26B;NUSHU CHARACTER-1B26B;Lo;0;L;;;;;N;;;;; +1B26C;NUSHU CHARACTER-1B26C;Lo;0;L;;;;;N;;;;; +1B26D;NUSHU CHARACTER-1B26D;Lo;0;L;;;;;N;;;;; +1B26E;NUSHU CHARACTER-1B26E;Lo;0;L;;;;;N;;;;; +1B26F;NUSHU CHARACTER-1B26F;Lo;0;L;;;;;N;;;;; +1B270;NUSHU CHARACTER-1B270;Lo;0;L;;;;;N;;;;; +1B271;NUSHU CHARACTER-1B271;Lo;0;L;;;;;N;;;;; +1B272;NUSHU CHARACTER-1B272;Lo;0;L;;;;;N;;;;; +1B273;NUSHU CHARACTER-1B273;Lo;0;L;;;;;N;;;;; +1B274;NUSHU CHARACTER-1B274;Lo;0;L;;;;;N;;;;; +1B275;NUSHU CHARACTER-1B275;Lo;0;L;;;;;N;;;;; +1B276;NUSHU CHARACTER-1B276;Lo;0;L;;;;;N;;;;; +1B277;NUSHU CHARACTER-1B277;Lo;0;L;;;;;N;;;;; +1B278;NUSHU CHARACTER-1B278;Lo;0;L;;;;;N;;;;; +1B279;NUSHU CHARACTER-1B279;Lo;0;L;;;;;N;;;;; +1B27A;NUSHU CHARACTER-1B27A;Lo;0;L;;;;;N;;;;; +1B27B;NUSHU CHARACTER-1B27B;Lo;0;L;;;;;N;;;;; +1B27C;NUSHU CHARACTER-1B27C;Lo;0;L;;;;;N;;;;; +1B27D;NUSHU CHARACTER-1B27D;Lo;0;L;;;;;N;;;;; +1B27E;NUSHU CHARACTER-1B27E;Lo;0;L;;;;;N;;;;; +1B27F;NUSHU CHARACTER-1B27F;Lo;0;L;;;;;N;;;;; +1B280;NUSHU CHARACTER-1B280;Lo;0;L;;;;;N;;;;; +1B281;NUSHU CHARACTER-1B281;Lo;0;L;;;;;N;;;;; +1B282;NUSHU CHARACTER-1B282;Lo;0;L;;;;;N;;;;; +1B283;NUSHU CHARACTER-1B283;Lo;0;L;;;;;N;;;;; +1B284;NUSHU CHARACTER-1B284;Lo;0;L;;;;;N;;;;; +1B285;NUSHU CHARACTER-1B285;Lo;0;L;;;;;N;;;;; +1B286;NUSHU CHARACTER-1B286;Lo;0;L;;;;;N;;;;; +1B287;NUSHU CHARACTER-1B287;Lo;0;L;;;;;N;;;;; +1B288;NUSHU CHARACTER-1B288;Lo;0;L;;;;;N;;;;; +1B289;NUSHU CHARACTER-1B289;Lo;0;L;;;;;N;;;;; +1B28A;NUSHU CHARACTER-1B28A;Lo;0;L;;;;;N;;;;; +1B28B;NUSHU CHARACTER-1B28B;Lo;0;L;;;;;N;;;;; +1B28C;NUSHU CHARACTER-1B28C;Lo;0;L;;;;;N;;;;; +1B28D;NUSHU CHARACTER-1B28D;Lo;0;L;;;;;N;;;;; +1B28E;NUSHU CHARACTER-1B28E;Lo;0;L;;;;;N;;;;; +1B28F;NUSHU CHARACTER-1B28F;Lo;0;L;;;;;N;;;;; +1B290;NUSHU CHARACTER-1B290;Lo;0;L;;;;;N;;;;; +1B291;NUSHU CHARACTER-1B291;Lo;0;L;;;;;N;;;;; +1B292;NUSHU CHARACTER-1B292;Lo;0;L;;;;;N;;;;; +1B293;NUSHU CHARACTER-1B293;Lo;0;L;;;;;N;;;;; +1B294;NUSHU CHARACTER-1B294;Lo;0;L;;;;;N;;;;; +1B295;NUSHU CHARACTER-1B295;Lo;0;L;;;;;N;;;;; +1B296;NUSHU CHARACTER-1B296;Lo;0;L;;;;;N;;;;; +1B297;NUSHU CHARACTER-1B297;Lo;0;L;;;;;N;;;;; +1B298;NUSHU CHARACTER-1B298;Lo;0;L;;;;;N;;;;; +1B299;NUSHU CHARACTER-1B299;Lo;0;L;;;;;N;;;;; +1B29A;NUSHU CHARACTER-1B29A;Lo;0;L;;;;;N;;;;; +1B29B;NUSHU CHARACTER-1B29B;Lo;0;L;;;;;N;;;;; +1B29C;NUSHU CHARACTER-1B29C;Lo;0;L;;;;;N;;;;; +1B29D;NUSHU CHARACTER-1B29D;Lo;0;L;;;;;N;;;;; +1B29E;NUSHU CHARACTER-1B29E;Lo;0;L;;;;;N;;;;; +1B29F;NUSHU CHARACTER-1B29F;Lo;0;L;;;;;N;;;;; +1B2A0;NUSHU CHARACTER-1B2A0;Lo;0;L;;;;;N;;;;; +1B2A1;NUSHU CHARACTER-1B2A1;Lo;0;L;;;;;N;;;;; +1B2A2;NUSHU CHARACTER-1B2A2;Lo;0;L;;;;;N;;;;; +1B2A3;NUSHU CHARACTER-1B2A3;Lo;0;L;;;;;N;;;;; +1B2A4;NUSHU CHARACTER-1B2A4;Lo;0;L;;;;;N;;;;; +1B2A5;NUSHU CHARACTER-1B2A5;Lo;0;L;;;;;N;;;;; +1B2A6;NUSHU CHARACTER-1B2A6;Lo;0;L;;;;;N;;;;; +1B2A7;NUSHU CHARACTER-1B2A7;Lo;0;L;;;;;N;;;;; +1B2A8;NUSHU CHARACTER-1B2A8;Lo;0;L;;;;;N;;;;; +1B2A9;NUSHU CHARACTER-1B2A9;Lo;0;L;;;;;N;;;;; +1B2AA;NUSHU CHARACTER-1B2AA;Lo;0;L;;;;;N;;;;; +1B2AB;NUSHU CHARACTER-1B2AB;Lo;0;L;;;;;N;;;;; +1B2AC;NUSHU CHARACTER-1B2AC;Lo;0;L;;;;;N;;;;; +1B2AD;NUSHU CHARACTER-1B2AD;Lo;0;L;;;;;N;;;;; +1B2AE;NUSHU CHARACTER-1B2AE;Lo;0;L;;;;;N;;;;; +1B2AF;NUSHU CHARACTER-1B2AF;Lo;0;L;;;;;N;;;;; +1B2B0;NUSHU CHARACTER-1B2B0;Lo;0;L;;;;;N;;;;; +1B2B1;NUSHU CHARACTER-1B2B1;Lo;0;L;;;;;N;;;;; +1B2B2;NUSHU CHARACTER-1B2B2;Lo;0;L;;;;;N;;;;; +1B2B3;NUSHU CHARACTER-1B2B3;Lo;0;L;;;;;N;;;;; +1B2B4;NUSHU CHARACTER-1B2B4;Lo;0;L;;;;;N;;;;; +1B2B5;NUSHU CHARACTER-1B2B5;Lo;0;L;;;;;N;;;;; +1B2B6;NUSHU CHARACTER-1B2B6;Lo;0;L;;;;;N;;;;; +1B2B7;NUSHU CHARACTER-1B2B7;Lo;0;L;;;;;N;;;;; +1B2B8;NUSHU CHARACTER-1B2B8;Lo;0;L;;;;;N;;;;; +1B2B9;NUSHU CHARACTER-1B2B9;Lo;0;L;;;;;N;;;;; +1B2BA;NUSHU CHARACTER-1B2BA;Lo;0;L;;;;;N;;;;; +1B2BB;NUSHU CHARACTER-1B2BB;Lo;0;L;;;;;N;;;;; +1B2BC;NUSHU CHARACTER-1B2BC;Lo;0;L;;;;;N;;;;; +1B2BD;NUSHU CHARACTER-1B2BD;Lo;0;L;;;;;N;;;;; +1B2BE;NUSHU CHARACTER-1B2BE;Lo;0;L;;;;;N;;;;; +1B2BF;NUSHU CHARACTER-1B2BF;Lo;0;L;;;;;N;;;;; +1B2C0;NUSHU CHARACTER-1B2C0;Lo;0;L;;;;;N;;;;; +1B2C1;NUSHU CHARACTER-1B2C1;Lo;0;L;;;;;N;;;;; +1B2C2;NUSHU CHARACTER-1B2C2;Lo;0;L;;;;;N;;;;; +1B2C3;NUSHU CHARACTER-1B2C3;Lo;0;L;;;;;N;;;;; +1B2C4;NUSHU CHARACTER-1B2C4;Lo;0;L;;;;;N;;;;; +1B2C5;NUSHU CHARACTER-1B2C5;Lo;0;L;;;;;N;;;;; +1B2C6;NUSHU CHARACTER-1B2C6;Lo;0;L;;;;;N;;;;; +1B2C7;NUSHU CHARACTER-1B2C7;Lo;0;L;;;;;N;;;;; +1B2C8;NUSHU CHARACTER-1B2C8;Lo;0;L;;;;;N;;;;; +1B2C9;NUSHU CHARACTER-1B2C9;Lo;0;L;;;;;N;;;;; +1B2CA;NUSHU CHARACTER-1B2CA;Lo;0;L;;;;;N;;;;; +1B2CB;NUSHU CHARACTER-1B2CB;Lo;0;L;;;;;N;;;;; +1B2CC;NUSHU CHARACTER-1B2CC;Lo;0;L;;;;;N;;;;; +1B2CD;NUSHU CHARACTER-1B2CD;Lo;0;L;;;;;N;;;;; +1B2CE;NUSHU CHARACTER-1B2CE;Lo;0;L;;;;;N;;;;; +1B2CF;NUSHU CHARACTER-1B2CF;Lo;0;L;;;;;N;;;;; +1B2D0;NUSHU CHARACTER-1B2D0;Lo;0;L;;;;;N;;;;; +1B2D1;NUSHU CHARACTER-1B2D1;Lo;0;L;;;;;N;;;;; +1B2D2;NUSHU CHARACTER-1B2D2;Lo;0;L;;;;;N;;;;; +1B2D3;NUSHU CHARACTER-1B2D3;Lo;0;L;;;;;N;;;;; +1B2D4;NUSHU CHARACTER-1B2D4;Lo;0;L;;;;;N;;;;; +1B2D5;NUSHU CHARACTER-1B2D5;Lo;0;L;;;;;N;;;;; +1B2D6;NUSHU CHARACTER-1B2D6;Lo;0;L;;;;;N;;;;; +1B2D7;NUSHU CHARACTER-1B2D7;Lo;0;L;;;;;N;;;;; +1B2D8;NUSHU CHARACTER-1B2D8;Lo;0;L;;;;;N;;;;; +1B2D9;NUSHU CHARACTER-1B2D9;Lo;0;L;;;;;N;;;;; +1B2DA;NUSHU CHARACTER-1B2DA;Lo;0;L;;;;;N;;;;; +1B2DB;NUSHU CHARACTER-1B2DB;Lo;0;L;;;;;N;;;;; +1B2DC;NUSHU CHARACTER-1B2DC;Lo;0;L;;;;;N;;;;; +1B2DD;NUSHU CHARACTER-1B2DD;Lo;0;L;;;;;N;;;;; +1B2DE;NUSHU CHARACTER-1B2DE;Lo;0;L;;;;;N;;;;; +1B2DF;NUSHU CHARACTER-1B2DF;Lo;0;L;;;;;N;;;;; +1B2E0;NUSHU CHARACTER-1B2E0;Lo;0;L;;;;;N;;;;; +1B2E1;NUSHU CHARACTER-1B2E1;Lo;0;L;;;;;N;;;;; +1B2E2;NUSHU CHARACTER-1B2E2;Lo;0;L;;;;;N;;;;; +1B2E3;NUSHU CHARACTER-1B2E3;Lo;0;L;;;;;N;;;;; +1B2E4;NUSHU CHARACTER-1B2E4;Lo;0;L;;;;;N;;;;; +1B2E5;NUSHU CHARACTER-1B2E5;Lo;0;L;;;;;N;;;;; +1B2E6;NUSHU CHARACTER-1B2E6;Lo;0;L;;;;;N;;;;; +1B2E7;NUSHU CHARACTER-1B2E7;Lo;0;L;;;;;N;;;;; +1B2E8;NUSHU CHARACTER-1B2E8;Lo;0;L;;;;;N;;;;; +1B2E9;NUSHU CHARACTER-1B2E9;Lo;0;L;;;;;N;;;;; +1B2EA;NUSHU CHARACTER-1B2EA;Lo;0;L;;;;;N;;;;; +1B2EB;NUSHU CHARACTER-1B2EB;Lo;0;L;;;;;N;;;;; +1B2EC;NUSHU CHARACTER-1B2EC;Lo;0;L;;;;;N;;;;; +1B2ED;NUSHU CHARACTER-1B2ED;Lo;0;L;;;;;N;;;;; +1B2EE;NUSHU CHARACTER-1B2EE;Lo;0;L;;;;;N;;;;; +1B2EF;NUSHU CHARACTER-1B2EF;Lo;0;L;;;;;N;;;;; +1B2F0;NUSHU CHARACTER-1B2F0;Lo;0;L;;;;;N;;;;; +1B2F1;NUSHU CHARACTER-1B2F1;Lo;0;L;;;;;N;;;;; +1B2F2;NUSHU CHARACTER-1B2F2;Lo;0;L;;;;;N;;;;; +1B2F3;NUSHU CHARACTER-1B2F3;Lo;0;L;;;;;N;;;;; +1B2F4;NUSHU CHARACTER-1B2F4;Lo;0;L;;;;;N;;;;; +1B2F5;NUSHU CHARACTER-1B2F5;Lo;0;L;;;;;N;;;;; +1B2F6;NUSHU CHARACTER-1B2F6;Lo;0;L;;;;;N;;;;; +1B2F7;NUSHU CHARACTER-1B2F7;Lo;0;L;;;;;N;;;;; +1B2F8;NUSHU CHARACTER-1B2F8;Lo;0;L;;;;;N;;;;; +1B2F9;NUSHU CHARACTER-1B2F9;Lo;0;L;;;;;N;;;;; +1B2FA;NUSHU CHARACTER-1B2FA;Lo;0;L;;;;;N;;;;; +1B2FB;NUSHU CHARACTER-1B2FB;Lo;0;L;;;;;N;;;;; +1BC00;DUPLOYAN LETTER H;Lo;0;L;;;;;N;;;;; +1BC01;DUPLOYAN LETTER X;Lo;0;L;;;;;N;;;;; +1BC02;DUPLOYAN LETTER P;Lo;0;L;;;;;N;;;;; +1BC03;DUPLOYAN LETTER T;Lo;0;L;;;;;N;;;;; +1BC04;DUPLOYAN LETTER F;Lo;0;L;;;;;N;;;;; +1BC05;DUPLOYAN LETTER K;Lo;0;L;;;;;N;;;;; +1BC06;DUPLOYAN LETTER L;Lo;0;L;;;;;N;;;;; +1BC07;DUPLOYAN LETTER B;Lo;0;L;;;;;N;;;;; +1BC08;DUPLOYAN LETTER D;Lo;0;L;;;;;N;;;;; +1BC09;DUPLOYAN LETTER V;Lo;0;L;;;;;N;;;;; +1BC0A;DUPLOYAN LETTER G;Lo;0;L;;;;;N;;;;; +1BC0B;DUPLOYAN LETTER R;Lo;0;L;;;;;N;;;;; +1BC0C;DUPLOYAN LETTER P N;Lo;0;L;;;;;N;;;;; +1BC0D;DUPLOYAN LETTER D S;Lo;0;L;;;;;N;;;;; +1BC0E;DUPLOYAN LETTER F N;Lo;0;L;;;;;N;;;;; +1BC0F;DUPLOYAN LETTER K M;Lo;0;L;;;;;N;;;;; +1BC10;DUPLOYAN LETTER R S;Lo;0;L;;;;;N;;;;; +1BC11;DUPLOYAN LETTER TH;Lo;0;L;;;;;N;;;;; +1BC12;DUPLOYAN LETTER SLOAN DH;Lo;0;L;;;;;N;;;;; +1BC13;DUPLOYAN LETTER DH;Lo;0;L;;;;;N;;;;; +1BC14;DUPLOYAN LETTER KK;Lo;0;L;;;;;N;;;;; +1BC15;DUPLOYAN LETTER SLOAN J;Lo;0;L;;;;;N;;;;; +1BC16;DUPLOYAN LETTER HL;Lo;0;L;;;;;N;;;;; +1BC17;DUPLOYAN LETTER LH;Lo;0;L;;;;;N;;;;; +1BC18;DUPLOYAN LETTER RH;Lo;0;L;;;;;N;;;;; +1BC19;DUPLOYAN LETTER M;Lo;0;L;;;;;N;;;;; +1BC1A;DUPLOYAN LETTER N;Lo;0;L;;;;;N;;;;; +1BC1B;DUPLOYAN LETTER J;Lo;0;L;;;;;N;;;;; +1BC1C;DUPLOYAN LETTER S;Lo;0;L;;;;;N;;;;; +1BC1D;DUPLOYAN LETTER M N;Lo;0;L;;;;;N;;;;; +1BC1E;DUPLOYAN LETTER N M;Lo;0;L;;;;;N;;;;; +1BC1F;DUPLOYAN LETTER J M;Lo;0;L;;;;;N;;;;; +1BC20;DUPLOYAN LETTER S J;Lo;0;L;;;;;N;;;;; +1BC21;DUPLOYAN LETTER M WITH DOT;Lo;0;L;;;;;N;;;;; +1BC22;DUPLOYAN LETTER N WITH DOT;Lo;0;L;;;;;N;;;;; +1BC23;DUPLOYAN LETTER J WITH DOT;Lo;0;L;;;;;N;;;;; +1BC24;DUPLOYAN LETTER J WITH DOTS INSIDE AND ABOVE;Lo;0;L;;;;;N;;;;; +1BC25;DUPLOYAN LETTER S WITH DOT;Lo;0;L;;;;;N;;;;; +1BC26;DUPLOYAN LETTER S WITH DOT BELOW;Lo;0;L;;;;;N;;;;; +1BC27;DUPLOYAN LETTER M S;Lo;0;L;;;;;N;;;;; +1BC28;DUPLOYAN LETTER N S;Lo;0;L;;;;;N;;;;; +1BC29;DUPLOYAN LETTER J S;Lo;0;L;;;;;N;;;;; +1BC2A;DUPLOYAN LETTER S S;Lo;0;L;;;;;N;;;;; +1BC2B;DUPLOYAN LETTER M N S;Lo;0;L;;;;;N;;;;; +1BC2C;DUPLOYAN LETTER N M S;Lo;0;L;;;;;N;;;;; +1BC2D;DUPLOYAN LETTER J M S;Lo;0;L;;;;;N;;;;; +1BC2E;DUPLOYAN LETTER S J S;Lo;0;L;;;;;N;;;;; +1BC2F;DUPLOYAN LETTER J S WITH DOT;Lo;0;L;;;;;N;;;;; +1BC30;DUPLOYAN LETTER J N;Lo;0;L;;;;;N;;;;; +1BC31;DUPLOYAN LETTER J N S;Lo;0;L;;;;;N;;;;; +1BC32;DUPLOYAN LETTER S T;Lo;0;L;;;;;N;;;;; +1BC33;DUPLOYAN LETTER S T R;Lo;0;L;;;;;N;;;;; +1BC34;DUPLOYAN LETTER S P;Lo;0;L;;;;;N;;;;; +1BC35;DUPLOYAN LETTER S P R;Lo;0;L;;;;;N;;;;; +1BC36;DUPLOYAN LETTER T S;Lo;0;L;;;;;N;;;;; +1BC37;DUPLOYAN LETTER T R S;Lo;0;L;;;;;N;;;;; +1BC38;DUPLOYAN LETTER W;Lo;0;L;;;;;N;;;;; +1BC39;DUPLOYAN LETTER WH;Lo;0;L;;;;;N;;;;; +1BC3A;DUPLOYAN LETTER W R;Lo;0;L;;;;;N;;;;; +1BC3B;DUPLOYAN LETTER S N;Lo;0;L;;;;;N;;;;; +1BC3C;DUPLOYAN LETTER S M;Lo;0;L;;;;;N;;;;; +1BC3D;DUPLOYAN LETTER K R S;Lo;0;L;;;;;N;;;;; +1BC3E;DUPLOYAN LETTER G R S;Lo;0;L;;;;;N;;;;; +1BC3F;DUPLOYAN LETTER S K;Lo;0;L;;;;;N;;;;; +1BC40;DUPLOYAN LETTER S K R;Lo;0;L;;;;;N;;;;; +1BC41;DUPLOYAN LETTER A;Lo;0;L;;;;;N;;;;; +1BC42;DUPLOYAN LETTER SLOAN OW;Lo;0;L;;;;;N;;;;; +1BC43;DUPLOYAN LETTER OA;Lo;0;L;;;;;N;;;;; +1BC44;DUPLOYAN LETTER O;Lo;0;L;;;;;N;;;;; +1BC45;DUPLOYAN LETTER AOU;Lo;0;L;;;;;N;;;;; +1BC46;DUPLOYAN LETTER I;Lo;0;L;;;;;N;;;;; +1BC47;DUPLOYAN LETTER E;Lo;0;L;;;;;N;;;;; +1BC48;DUPLOYAN LETTER IE;Lo;0;L;;;;;N;;;;; +1BC49;DUPLOYAN LETTER SHORT I;Lo;0;L;;;;;N;;;;; +1BC4A;DUPLOYAN LETTER UI;Lo;0;L;;;;;N;;;;; +1BC4B;DUPLOYAN LETTER EE;Lo;0;L;;;;;N;;;;; +1BC4C;DUPLOYAN LETTER SLOAN EH;Lo;0;L;;;;;N;;;;; +1BC4D;DUPLOYAN LETTER ROMANIAN I;Lo;0;L;;;;;N;;;;; +1BC4E;DUPLOYAN LETTER SLOAN EE;Lo;0;L;;;;;N;;;;; +1BC4F;DUPLOYAN LETTER LONG I;Lo;0;L;;;;;N;;;;; +1BC50;DUPLOYAN LETTER YE;Lo;0;L;;;;;N;;;;; +1BC51;DUPLOYAN LETTER U;Lo;0;L;;;;;N;;;;; +1BC52;DUPLOYAN LETTER EU;Lo;0;L;;;;;N;;;;; +1BC53;DUPLOYAN LETTER XW;Lo;0;L;;;;;N;;;;; +1BC54;DUPLOYAN LETTER U N;Lo;0;L;;;;;N;;;;; +1BC55;DUPLOYAN LETTER LONG U;Lo;0;L;;;;;N;;;;; +1BC56;DUPLOYAN LETTER ROMANIAN U;Lo;0;L;;;;;N;;;;; +1BC57;DUPLOYAN LETTER UH;Lo;0;L;;;;;N;;;;; +1BC58;DUPLOYAN LETTER SLOAN U;Lo;0;L;;;;;N;;;;; +1BC59;DUPLOYAN LETTER OOH;Lo;0;L;;;;;N;;;;; +1BC5A;DUPLOYAN LETTER OW;Lo;0;L;;;;;N;;;;; +1BC5B;DUPLOYAN LETTER OU;Lo;0;L;;;;;N;;;;; +1BC5C;DUPLOYAN LETTER WA;Lo;0;L;;;;;N;;;;; +1BC5D;DUPLOYAN LETTER WO;Lo;0;L;;;;;N;;;;; +1BC5E;DUPLOYAN LETTER WI;Lo;0;L;;;;;N;;;;; +1BC5F;DUPLOYAN LETTER WEI;Lo;0;L;;;;;N;;;;; +1BC60;DUPLOYAN LETTER WOW;Lo;0;L;;;;;N;;;;; +1BC61;DUPLOYAN LETTER NASAL U;Lo;0;L;;;;;N;;;;; +1BC62;DUPLOYAN LETTER NASAL O;Lo;0;L;;;;;N;;;;; +1BC63;DUPLOYAN LETTER NASAL I;Lo;0;L;;;;;N;;;;; +1BC64;DUPLOYAN LETTER NASAL A;Lo;0;L;;;;;N;;;;; +1BC65;DUPLOYAN LETTER PERNIN AN;Lo;0;L;;;;;N;;;;; +1BC66;DUPLOYAN LETTER PERNIN AM;Lo;0;L;;;;;N;;;;; +1BC67;DUPLOYAN LETTER SLOAN EN;Lo;0;L;;;;;N;;;;; +1BC68;DUPLOYAN LETTER SLOAN AN;Lo;0;L;;;;;N;;;;; +1BC69;DUPLOYAN LETTER SLOAN ON;Lo;0;L;;;;;N;;;;; +1BC6A;DUPLOYAN LETTER VOCALIC M;Lo;0;L;;;;;N;;;;; +1BC70;DUPLOYAN AFFIX LEFT HORIZONTAL SECANT;Lo;0;L;;;;;N;;;;; +1BC71;DUPLOYAN AFFIX MID HORIZONTAL SECANT;Lo;0;L;;;;;N;;;;; +1BC72;DUPLOYAN AFFIX RIGHT HORIZONTAL SECANT;Lo;0;L;;;;;N;;;;; +1BC73;DUPLOYAN AFFIX LOW VERTICAL SECANT;Lo;0;L;;;;;N;;;;; +1BC74;DUPLOYAN AFFIX MID VERTICAL SECANT;Lo;0;L;;;;;N;;;;; +1BC75;DUPLOYAN AFFIX HIGH VERTICAL SECANT;Lo;0;L;;;;;N;;;;; +1BC76;DUPLOYAN AFFIX ATTACHED SECANT;Lo;0;L;;;;;N;;;;; +1BC77;DUPLOYAN AFFIX ATTACHED LEFT-TO-RIGHT SECANT;Lo;0;L;;;;;N;;;;; +1BC78;DUPLOYAN AFFIX ATTACHED TANGENT;Lo;0;L;;;;;N;;;;; +1BC79;DUPLOYAN AFFIX ATTACHED TAIL;Lo;0;L;;;;;N;;;;; +1BC7A;DUPLOYAN AFFIX ATTACHED E HOOK;Lo;0;L;;;;;N;;;;; +1BC7B;DUPLOYAN AFFIX ATTACHED I HOOK;Lo;0;L;;;;;N;;;;; +1BC7C;DUPLOYAN AFFIX ATTACHED TANGENT HOOK;Lo;0;L;;;;;N;;;;; +1BC80;DUPLOYAN AFFIX HIGH ACUTE;Lo;0;L;;;;;N;;;;; +1BC81;DUPLOYAN AFFIX HIGH TIGHT ACUTE;Lo;0;L;;;;;N;;;;; +1BC82;DUPLOYAN AFFIX HIGH GRAVE;Lo;0;L;;;;;N;;;;; +1BC83;DUPLOYAN AFFIX HIGH LONG GRAVE;Lo;0;L;;;;;N;;;;; +1BC84;DUPLOYAN AFFIX HIGH DOT;Lo;0;L;;;;;N;;;;; +1BC85;DUPLOYAN AFFIX HIGH CIRCLE;Lo;0;L;;;;;N;;;;; +1BC86;DUPLOYAN AFFIX HIGH LINE;Lo;0;L;;;;;N;;;;; +1BC87;DUPLOYAN AFFIX HIGH WAVE;Lo;0;L;;;;;N;;;;; +1BC88;DUPLOYAN AFFIX HIGH VERTICAL;Lo;0;L;;;;;N;;;;; +1BC90;DUPLOYAN AFFIX LOW ACUTE;Lo;0;L;;;;;N;;;;; +1BC91;DUPLOYAN AFFIX LOW TIGHT ACUTE;Lo;0;L;;;;;N;;;;; +1BC92;DUPLOYAN AFFIX LOW GRAVE;Lo;0;L;;;;;N;;;;; +1BC93;DUPLOYAN AFFIX LOW LONG GRAVE;Lo;0;L;;;;;N;;;;; +1BC94;DUPLOYAN AFFIX LOW DOT;Lo;0;L;;;;;N;;;;; +1BC95;DUPLOYAN AFFIX LOW CIRCLE;Lo;0;L;;;;;N;;;;; +1BC96;DUPLOYAN AFFIX LOW LINE;Lo;0;L;;;;;N;;;;; +1BC97;DUPLOYAN AFFIX LOW WAVE;Lo;0;L;;;;;N;;;;; +1BC98;DUPLOYAN AFFIX LOW VERTICAL;Lo;0;L;;;;;N;;;;; +1BC99;DUPLOYAN AFFIX LOW ARROW;Lo;0;L;;;;;N;;;;; +1BC9C;DUPLOYAN SIGN O WITH CROSS;So;0;L;;;;;N;;;;; +1BC9D;DUPLOYAN THICK LETTER SELECTOR;Mn;0;NSM;;;;;N;;;;; +1BC9E;DUPLOYAN DOUBLE MARK;Mn;1;NSM;;;;;N;;;;; +1BC9F;DUPLOYAN PUNCTUATION CHINOOK FULL STOP;Po;0;L;;;;;N;;;;; +1BCA0;SHORTHAND FORMAT LETTER OVERLAP;Cf;0;BN;;;;;N;;;;; +1BCA1;SHORTHAND FORMAT CONTINUING OVERLAP;Cf;0;BN;;;;;N;;;;; +1BCA2;SHORTHAND FORMAT DOWN STEP;Cf;0;BN;;;;;N;;;;; +1BCA3;SHORTHAND FORMAT UP STEP;Cf;0;BN;;;;;N;;;;; +1CC00;UP-POINTING GO-KART;So;0;ON;;;;;N;;;;; +1CC01;RIGHT-POINTING GO-KART;So;0;ON;;;;;N;;;;; +1CC02;LEFT-POINTING STICK FIGURE;So;0;ON;;;;;N;;;;; +1CC03;RIGHT-POINTING STICK FIGURE;So;0;ON;;;;;N;;;;; +1CC04;DOWN-POINTING STICK FIGURE;So;0;ON;;;;;N;;;;; +1CC05;LOWER HORIZONTAL RULER SEGMENT;So;0;ON;;;;;N;;;;; +1CC06;RIGHT VERTICAL RULER SEGMENT;So;0;ON;;;;;N;;;;; +1CC07;LOWER RIGHT RULER SEGMENT;So;0;ON;;;;;N;;;;; +1CC08;ANTENNA;So;0;ON;;;;;N;;;;; +1CC09;HORIZONTAL RESISTOR SEGMENT;So;0;ON;;;;;N;;;;; +1CC0A;VERTICAL RESISTOR SEGMENT;So;0;ON;;;;;N;;;;; +1CC0B;LEFT THIRD INDUCTOR;So;0;ON;;;;;N;;;;; +1CC0C;MIDDLE THIRD INDUCTOR;So;0;ON;;;;;N;;;;; +1CC0D;RIGHT THIRD INDUCTOR;So;0;ON;;;;;N;;;;; +1CC0E;LEFT-POINTING DIODE;So;0;ON;;;;;N;;;;; +1CC0F;RIGHT-POINTING DIODE;So;0;ON;;;;;N;;;;; +1CC10;NPN TRANSISTOR;So;0;ON;;;;;N;;;;; +1CC11;PNP TRANSISTOR;So;0;ON;;;;;N;;;;; +1CC12;RECEPTACLE;So;0;ON;;;;;N;;;;; +1CC13;HORIZONTAL CAPACITOR;So;0;ON;;;;;N;;;;; +1CC14;VERTICAL CAPACITOR;So;0;ON;;;;;N;;;;; +1CC15;LOGIC GATE OR;So;0;ON;;;;;N;;;;; +1CC16;LOGIC GATE AND;So;0;ON;;;;;N;;;;; +1CC17;LOGIC GATE INVERTED INPUTS;So;0;ON;;;;;N;;;;; +1CC18;LOGIC GATE INVERTED OUTPUT;So;0;ON;;;;;N;;;;; +1CC19;LOGIC GATE BUFFER;So;0;ON;;;;;N;;;;; +1CC1A;LOGIC GATE BUFFER WITH INVERTED INPUT;So;0;ON;;;;;N;;;;; +1CC1B;BOX DRAWINGS LIGHT HORIZONTAL AND UPPER RIGHT;So;0;ON;;;;;N;;;;; +1CC1C;BOX DRAWINGS LIGHT HORIZONTAL AND LOWER RIGHT;So;0;ON;;;;;N;;;;; +1CC1D;BOX DRAWINGS LIGHT TOP AND UPPER LEFT;So;0;ON;;;;;N;;;;; +1CC1E;BOX DRAWINGS LIGHT BOTTOM AND LOWER LEFT;So;0;ON;;;;;N;;;;; +1CC1F;BOX DRAWINGS DOUBLE DIAGONAL UPPER RIGHT TO LOWER LEFT;So;0;ON;;;;;N;;;;; +1CC20;BOX DRAWINGS DOUBLE DIAGONAL UPPER LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;; +1CC21;SEPARATED BLOCK QUADRANT-1;So;0;ON;;;;;N;;;;; +1CC22;SEPARATED BLOCK QUADRANT-2;So;0;ON;;;;;N;;;;; +1CC23;SEPARATED BLOCK QUADRANT-12;So;0;ON;;;;;N;;;;; +1CC24;SEPARATED BLOCK QUADRANT-3;So;0;ON;;;;;N;;;;; +1CC25;SEPARATED BLOCK QUADRANT-13;So;0;ON;;;;;N;;;;; +1CC26;SEPARATED BLOCK QUADRANT-23;So;0;ON;;;;;N;;;;; +1CC27;SEPARATED BLOCK QUADRANT-123;So;0;ON;;;;;N;;;;; +1CC28;SEPARATED BLOCK QUADRANT-4;So;0;ON;;;;;N;;;;; +1CC29;SEPARATED BLOCK QUADRANT-14;So;0;ON;;;;;N;;;;; +1CC2A;SEPARATED BLOCK QUADRANT-24;So;0;ON;;;;;N;;;;; +1CC2B;SEPARATED BLOCK QUADRANT-124;So;0;ON;;;;;N;;;;; +1CC2C;SEPARATED BLOCK QUADRANT-34;So;0;ON;;;;;N;;;;; +1CC2D;SEPARATED BLOCK QUADRANT-134;So;0;ON;;;;;N;;;;; +1CC2E;SEPARATED BLOCK QUADRANT-234;So;0;ON;;;;;N;;;;; +1CC2F;SEPARATED BLOCK QUADRANT-1234;So;0;ON;;;;;N;;;;; +1CC30;UPPER LEFT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;; +1CC31;UPPER CENTRE LEFT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;; +1CC32;UPPER CENTRE RIGHT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;; +1CC33;UPPER RIGHT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;; +1CC34;UPPER MIDDLE LEFT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;; +1CC35;UPPER LEFT QUARTER CIRCLE;So;0;ON;;;;;N;;;;; +1CC36;UPPER RIGHT QUARTER CIRCLE;So;0;ON;;;;;N;;;;; +1CC37;UPPER MIDDLE RIGHT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;; +1CC38;LOWER MIDDLE LEFT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;; +1CC39;LOWER LEFT QUARTER CIRCLE;So;0;ON;;;;;N;;;;; +1CC3A;LOWER RIGHT QUARTER CIRCLE;So;0;ON;;;;;N;;;;; +1CC3B;LOWER MIDDLE RIGHT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;; +1CC3C;LOWER LEFT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;; +1CC3D;LOWER CENTRE LEFT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;; +1CC3E;LOWER CENTRE RIGHT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;; +1CC3F;LOWER RIGHT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;; +1CC40;SPARSE HORIZONTAL FILL;So;0;ON;;;;;N;;;;; +1CC41;SPARSE VERTICAL FILL;So;0;ON;;;;;N;;;;; +1CC42;ORTHOGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;; +1CC43;DIAGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;; +1CC44;DENSE VERTICAL FILL;So;0;ON;;;;;N;;;;; +1CC45;DENSE HORIZONTAL FILL;So;0;ON;;;;;N;;;;; +1CC46;SPECKLE FILL FRAME-1;So;0;ON;;;;;N;;;;; +1CC47;SPECKLE FILL FRAME-2;So;0;ON;;;;;N;;;;; +1CC48;LEFT-FACING BASSINET;So;0;ON;;;;;N;;;;; +1CC49;RIGHT-FACING BASSINET;So;0;ON;;;;;N;;;;; +1CC4A;FLYING SAUCER WITH BEAMS;So;0;ON;;;;;N;;;;; +1CC4B;FLYING SAUCER WITHOUT BEAMS;So;0;ON;;;;;N;;;;; +1CC4C;ALIEN MONSTER OPEN JAWS;So;0;ON;;;;;N;;;;; +1CC4D;ALIEN MONSTER CLOSED JAWS;So;0;ON;;;;;N;;;;; +1CC4E;ALIEN SQUID OPEN TENTACLES;So;0;ON;;;;;N;;;;; +1CC4F;ALIEN SQUID CLOSED TENTACLES;So;0;ON;;;;;N;;;;; +1CC50;ALIEN CRAB STEPPING RIGHT;So;0;ON;;;;;N;;;;; +1CC51;ALIEN CRAB STEPPING LEFT;So;0;ON;;;;;N;;;;; +1CC52;ALIEN SPIDER CROUCHING;So;0;ON;;;;;N;;;;; +1CC53;ALIEN SPIDER SPREAD;So;0;ON;;;;;N;;;;; +1CC54;ALIEN MONSTER STEP-1;So;0;ON;;;;;N;;;;; +1CC55;ALIEN MONSTER STEP-2;So;0;ON;;;;;N;;;;; +1CC56;LEFT-POINTING ROCKET SHIP;So;0;ON;;;;;N;;;;; +1CC57;UP-POINTING ROCKET SHIP;So;0;ON;;;;;N;;;;; +1CC58;RIGHT-POINTING ROCKET SHIP;So;0;ON;;;;;N;;;;; +1CC59;DOWN-POINTING ROCKET SHIP;So;0;ON;;;;;N;;;;; +1CC5A;TOP HALF LEFT-FACING ROBOT;So;0;ON;;;;;N;;;;; +1CC5B;TOP HALF FORWARD-FACING ROBOT;So;0;ON;;;;;N;;;;; +1CC5C;TOP HALF RIGHT-FACING ROBOT;So;0;ON;;;;;N;;;;; +1CC5D;BOTTOM HALF LEFT-FACING ROBOT;So;0;ON;;;;;N;;;;; +1CC5E;BOTTOM HALF FORWARD-FACING ROBOT;So;0;ON;;;;;N;;;;; +1CC5F;BOTTOM HALF RIGHT-FACING ROBOT;So;0;ON;;;;;N;;;;; +1CC60;LEFT-POINTING ATOMIC BOMB;So;0;ON;;;;;N;;;;; +1CC61;UP-POINTING ATOMIC BOMB;So;0;ON;;;;;N;;;;; +1CC62;RIGHT-POINTING ATOMIC BOMB;So;0;ON;;;;;N;;;;; +1CC63;DOWN-POINTING ATOMIC BOMB;So;0;ON;;;;;N;;;;; +1CC64;MUSHROOM CLOUD;So;0;ON;;;;;N;;;;; +1CC65;LEFT-POINTING RIFLE;So;0;ON;;;;;N;;;;; +1CC66;UP-POINTING RIFLE;So;0;ON;;;;;N;;;;; +1CC67;RIGHT-POINTING RIFLE;So;0;ON;;;;;N;;;;; +1CC68;DOWN-POINTING RIFLE;So;0;ON;;;;;N;;;;; +1CC69;EIGHT RAYS INWARD;So;0;ON;;;;;N;;;;; +1CC6A;EIGHT RAYS OUTWARD;So;0;ON;;;;;N;;;;; +1CC6B;BLACK LARGE CIRCLE MINUS LEFT QUARTER SECTION;So;0;ON;;;;;N;;;;; +1CC6C;BLACK LARGE CIRCLE MINUS UPPER QUARTER SECTION;So;0;ON;;;;;N;;;;; +1CC6D;BLACK LARGE CIRCLE MINUS RIGHT QUARTER SECTION;So;0;ON;;;;;N;;;;; +1CC6E;BLACK LARGE CIRCLE MINUS LOWER QUARTER SECTION;So;0;ON;;;;;N;;;;; +1CC6F;BLACK NEUTRAL FACE;So;0;ON;;;;;N;;;;; +1CC70;LEFT-FACING SNAKE HEAD WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; +1CC71;UP-FACING SNAKE HEAD WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; +1CC72;RIGHT-FACING SNAKE HEAD WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; +1CC73;DOWN-FACING SNAKE HEAD WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; +1CC74;LEFT-FACING SNAKE HEAD WITH CLOSED MOUTH;So;0;ON;;;;;N;;;;; +1CC75;UP-FACING SNAKE HEAD WITH CLOSED MOUTH;So;0;ON;;;;;N;;;;; +1CC76;RIGHT-FACING SNAKE HEAD WITH CLOSED MOUTH;So;0;ON;;;;;N;;;;; +1CC77;DOWN-FACING SNAKE HEAD WITH CLOSED MOUTH;So;0;ON;;;;;N;;;;; +1CC78;LEFT-POINTING ENERGY WAVE;So;0;ON;;;;;N;;;;; +1CC79;UP-POINTING ENERGY WAVE;So;0;ON;;;;;N;;;;; +1CC7A;RIGHT-POINTING ENERGY WAVE;So;0;ON;;;;;N;;;;; +1CC7B;DOWN-POINTING ENERGY WAVE;So;0;ON;;;;;N;;;;; +1CC7C;SQUARE SPIRAL FROM TOP LEFT;So;0;ON;;;;;N;;;;; +1CC7D;SQUARE SPIRAL FROM TOP RIGHT;So;0;ON;;;;;N;;;;; +1CC7E;SQUARE SPIRAL FROM BOTTOM RIGHT;So;0;ON;;;;;N;;;;; +1CC7F;SQUARE SPIRAL FROM BOTTOM LEFT;So;0;ON;;;;;N;;;;; +1CC80;STRIPED LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; +1CC81;STRIPED UP-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; +1CC82;STRIPED RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; +1CC83;STRIPED DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; +1CC84;VERTICAL LADDER;So;0;ON;;;;;N;;;;; +1CC85;HORIZONTAL LADDER;So;0;ON;;;;;N;;;;; +1CC86;WHITE LOWER LEFT POINTER;So;0;ON;;;;;N;;;;; +1CC87;WHITE LOWER RIGHT POINTER;So;0;ON;;;;;N;;;;; +1CC88;TWO RINGS ALIGNED HORIZONTALLY;So;0;ON;;;;;N;;;;; +1CC89;SQUARE FOUR CORNER SALTIRES;So;0;ON;;;;;N;;;;; +1CC8A;SQUARE FOUR CORNER DIAGONALS;So;0;ON;;;;;N;;;;; +1CC8B;SQUARE FOUR CORNER BLACK TRIANGLES;So;0;ON;;;;;N;;;;; +1CC8C;SQUARE APERTURE;So;0;ON;;;;;N;;;;; +1CC8D;INVERSE BLACK DIAMOND;So;0;ON;;;;;N;;;;; +1CC8E;LEFT AND UPPER ONE EIGHTH BLOCK CONTAINING BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;; +1CC8F;INVERSE BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;; +1CC90;VERTICAL LINE WITH FOUR TICK MARKS;So;0;ON;;;;;N;;;;; +1CC91;HORIZONTAL LINE WITH FOUR TICK MARKS;So;0;ON;;;;;N;;;;; +1CC92;LEFT-FACING FISH;So;0;ON;;;;;N;;;;; +1CC93;RIGHT-FACING FISH;So;0;ON;;;;;N;;;;; +1CC94;LEFT-FACING FISH WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; +1CC95;RIGHT-FACING FISH WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; +1CC96;FLAPPING BIRD;So;0;ON;;;;;N;;;;; +1CC97;LEFT-POINTING RACING CAR;So;0;ON;;;;;N;;;;; +1CC98;UP-POINTING RACING CAR;So;0;ON;;;;;N;;;;; +1CC99;RIGHT-POINTING RACING CAR;So;0;ON;;;;;N;;;;; +1CC9A;DOWN-POINTING RACING CAR;So;0;ON;;;;;N;;;;; +1CC9B;HORIZONTAL RACING CAR;So;0;ON;;;;;N;;;;; +1CC9C;VERTICAL RACING CAR;So;0;ON;;;;;N;;;;; +1CC9D;VERTICAL GO-KART;So;0;ON;;;;;N;;;;; +1CC9E;LEFT-POINTING TANK;So;0;ON;;;;;N;;;;; +1CC9F;RIGHT-POINTING TANK;So;0;ON;;;;;N;;;;; +1CCA0;LEFT-POINTING ROCKET BOOSTER;So;0;ON;;;;;N;;;;; +1CCA1;RIGHT-POINTING ROCKET BOOSTER;So;0;ON;;;;;N;;;;; +1CCA2;LEFT-POINTING ROLLER COASTER CAR;So;0;ON;;;;;N;;;;; +1CCA3;RIGHT-POINTING ROLLER COASTER CAR;So;0;ON;;;;;N;;;;; +1CCA4;LEFT HALF FLYING SAUCER;So;0;ON;;;;;N;;;;; +1CCA5;RIGHT HALF FLYING SAUCER;So;0;ON;;;;;N;;;;; +1CCA6;UPPER LEFT QUADRANT FACE WITH OPEN EYES;So;0;ON;;;;;N;;;;; +1CCA7;UPPER RIGHT QUADRANT FACE WITH OPEN EYES;So;0;ON;;;;;N;;;;; +1CCA8;UPPER LEFT QUADRANT FACE WITH CLOSED EYES;So;0;ON;;;;;N;;;;; +1CCA9;UPPER RIGHT QUADRANT FACE WITH CLOSED EYES;So;0;ON;;;;;N;;;;; +1CCAA;LOWER LEFT QUADRANT SMILING FACE;So;0;ON;;;;;N;;;;; +1CCAB;LOWER RIGHT QUADRANT SMILING FACE;So;0;ON;;;;;N;;;;; +1CCAC;LOWER LEFT QUADRANT NEUTRAL FACE;So;0;ON;;;;;N;;;;; +1CCAD;LOWER RIGHT QUADRANT NEUTRAL FACE;So;0;ON;;;;;N;;;;; +1CCAE;LOWER LEFT QUADRANT FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; +1CCAF;LOWER RIGHT QUADRANT FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; +1CCB0;LOWER LEFT QUADRANT FROWNING FACE;So;0;ON;;;;;N;;;;; +1CCB1;LOWER RIGHT QUADRANT FROWNING FACE;So;0;ON;;;;;N;;;;; +1CCB2;UPPER LEFT QUADRANT TELEVISION;So;0;ON;;;;;N;;;;; +1CCB3;UPPER RIGHT QUADRANT TELEVISION;So;0;ON;;;;;N;;;;; +1CCB4;LOWER LEFT QUADRANT TELEVISION;So;0;ON;;;;;N;;;;; +1CCB5;LOWER RIGHT QUADRANT TELEVISION;So;0;ON;;;;;N;;;;; +1CCB6;UPPER LEFT QUADRANT MICROCOMPUTER;So;0;ON;;;;;N;;;;; +1CCB7;UPPER RIGHT QUADRANT MICROCOMPUTER;So;0;ON;;;;;N;;;;; +1CCB8;LOWER LEFT QUADRANT MICROCOMPUTER;So;0;ON;;;;;N;;;;; +1CCB9;LOWER RIGHT QUADRANT MICROCOMPUTER;So;0;ON;;;;;N;;;;; +1CCBA;UPPER LEFT QUADRANT CHESS KING;So;0;ON;;;;;N;;;;; +1CCBB;UPPER RIGHT QUADRANT CHESS KING;So;0;ON;;;;;N;;;;; +1CCBC;LOWER LEFT QUADRANT CHESS KING;So;0;ON;;;;;N;;;;; +1CCBD;LOWER RIGHT QUADRANT CHESS KING;So;0;ON;;;;;N;;;;; +1CCBE;UPPER LEFT QUADRANT CHESS QUEEN;So;0;ON;;;;;N;;;;; +1CCBF;UPPER RIGHT QUADRANT CHESS QUEEN;So;0;ON;;;;;N;;;;; +1CCC0;LOWER LEFT QUADRANT CHESS QUEEN;So;0;ON;;;;;N;;;;; +1CCC1;LOWER RIGHT QUADRANT CHESS QUEEN;So;0;ON;;;;;N;;;;; +1CCC2;UPPER LEFT QUADRANT CHESS ROOK;So;0;ON;;;;;N;;;;; +1CCC3;UPPER RIGHT QUADRANT CHESS ROOK;So;0;ON;;;;;N;;;;; +1CCC4;LOWER LEFT QUADRANT CHESS ROOK;So;0;ON;;;;;N;;;;; +1CCC5;LOWER RIGHT QUADRANT CHESS ROOK;So;0;ON;;;;;N;;;;; +1CCC6;UPPER LEFT QUADRANT CHESS BISHOP;So;0;ON;;;;;N;;;;; +1CCC7;UPPER RIGHT QUADRANT CHESS BISHOP;So;0;ON;;;;;N;;;;; +1CCC8;LOWER LEFT QUADRANT CHESS BISHOP;So;0;ON;;;;;N;;;;; +1CCC9;LOWER RIGHT QUADRANT CHESS BISHOP;So;0;ON;;;;;N;;;;; +1CCCA;UPPER LEFT QUADRANT CHESS KNIGHT;So;0;ON;;;;;N;;;;; +1CCCB;UPPER RIGHT QUADRANT CHESS KNIGHT;So;0;ON;;;;;N;;;;; +1CCCC;LOWER LEFT QUADRANT CHESS KNIGHT;So;0;ON;;;;;N;;;;; +1CCCD;LOWER RIGHT QUADRANT CHESS KNIGHT;So;0;ON;;;;;N;;;;; +1CCCE;UPPER LEFT QUADRANT CHESS PAWN;So;0;ON;;;;;N;;;;; +1CCCF;UPPER RIGHT QUADRANT CHESS PAWN;So;0;ON;;;;;N;;;;; +1CCD0;LOWER LEFT QUADRANT CHESS PAWN;So;0;ON;;;;;N;;;;; +1CCD1;LOWER RIGHT QUADRANT CHESS PAWN;So;0;ON;;;;;N;;;;; +1CCD2;UPPER LEFT QUADRANT STANDING KNIGHT;So;0;ON;;;;;N;;;;; +1CCD3;UPPER RIGHT QUADRANT STANDING KNIGHT;So;0;ON;;;;;N;;;;; +1CCD4;LOWER LEFT QUADRANT STANDING KNIGHT;So;0;ON;;;;;N;;;;; +1CCD5;LOWER RIGHT QUADRANT STANDING KNIGHT;So;0;ON;;;;;N;;;;; +1CCD6;OUTLINED LATIN CAPITAL LETTER A;So;0;L; 0041;;;;N;;;;; +1CCD7;OUTLINED LATIN CAPITAL LETTER B;So;0;L; 0042;;;;N;;;;; +1CCD8;OUTLINED LATIN CAPITAL LETTER C;So;0;L; 0043;;;;N;;;;; +1CCD9;OUTLINED LATIN CAPITAL LETTER D;So;0;L; 0044;;;;N;;;;; +1CCDA;OUTLINED LATIN CAPITAL LETTER E;So;0;L; 0045;;;;N;;;;; +1CCDB;OUTLINED LATIN CAPITAL LETTER F;So;0;L; 0046;;;;N;;;;; +1CCDC;OUTLINED LATIN CAPITAL LETTER G;So;0;L; 0047;;;;N;;;;; +1CCDD;OUTLINED LATIN CAPITAL LETTER H;So;0;L; 0048;;;;N;;;;; +1CCDE;OUTLINED LATIN CAPITAL LETTER I;So;0;L; 0049;;;;N;;;;; +1CCDF;OUTLINED LATIN CAPITAL LETTER J;So;0;L; 004A;;;;N;;;;; +1CCE0;OUTLINED LATIN CAPITAL LETTER K;So;0;L; 004B;;;;N;;;;; +1CCE1;OUTLINED LATIN CAPITAL LETTER L;So;0;L; 004C;;;;N;;;;; +1CCE2;OUTLINED LATIN CAPITAL LETTER M;So;0;L; 004D;;;;N;;;;; +1CCE3;OUTLINED LATIN CAPITAL LETTER N;So;0;L; 004E;;;;N;;;;; +1CCE4;OUTLINED LATIN CAPITAL LETTER O;So;0;L; 004F;;;;N;;;;; +1CCE5;OUTLINED LATIN CAPITAL LETTER P;So;0;L; 0050;;;;N;;;;; +1CCE6;OUTLINED LATIN CAPITAL LETTER Q;So;0;L; 0051;;;;N;;;;; +1CCE7;OUTLINED LATIN CAPITAL LETTER R;So;0;L; 0052;;;;N;;;;; +1CCE8;OUTLINED LATIN CAPITAL LETTER S;So;0;L; 0053;;;;N;;;;; +1CCE9;OUTLINED LATIN CAPITAL LETTER T;So;0;L; 0054;;;;N;;;;; +1CCEA;OUTLINED LATIN CAPITAL LETTER U;So;0;L; 0055;;;;N;;;;; +1CCEB;OUTLINED LATIN CAPITAL LETTER V;So;0;L; 0056;;;;N;;;;; +1CCEC;OUTLINED LATIN CAPITAL LETTER W;So;0;L; 0057;;;;N;;;;; +1CCED;OUTLINED LATIN CAPITAL LETTER X;So;0;L; 0058;;;;N;;;;; +1CCEE;OUTLINED LATIN CAPITAL LETTER Y;So;0;L; 0059;;;;N;;;;; +1CCEF;OUTLINED LATIN CAPITAL LETTER Z;So;0;L; 005A;;;;N;;;;; +1CCF0;OUTLINED DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; +1CCF1;OUTLINED DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; +1CCF2;OUTLINED DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; +1CCF3;OUTLINED DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; +1CCF4;OUTLINED DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; +1CCF5;OUTLINED DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; +1CCF6;OUTLINED DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; +1CCF7;OUTLINED DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; +1CCF8;OUTLINED DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; +1CCF9;OUTLINED DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +1CCFA;SNAKE SYMBOL;So;0;ON;;;;;N;;;;; +1CCFB;FLYING SAUCER SYMBOL;So;0;ON;;;;;N;;;;; +1CCFC;NOSE SYMBOL;So;0;ON;;;;;N;;;;; +1CD00;BLOCK OCTANT-3;So;0;ON;;;;;N;;;;; +1CD01;BLOCK OCTANT-23;So;0;ON;;;;;N;;;;; +1CD02;BLOCK OCTANT-123;So;0;ON;;;;;N;;;;; +1CD03;BLOCK OCTANT-4;So;0;ON;;;;;N;;;;; +1CD04;BLOCK OCTANT-14;So;0;ON;;;;;N;;;;; +1CD05;BLOCK OCTANT-124;So;0;ON;;;;;N;;;;; +1CD06;BLOCK OCTANT-34;So;0;ON;;;;;N;;;;; +1CD07;BLOCK OCTANT-134;So;0;ON;;;;;N;;;;; +1CD08;BLOCK OCTANT-234;So;0;ON;;;;;N;;;;; +1CD09;BLOCK OCTANT-5;So;0;ON;;;;;N;;;;; +1CD0A;BLOCK OCTANT-15;So;0;ON;;;;;N;;;;; +1CD0B;BLOCK OCTANT-25;So;0;ON;;;;;N;;;;; +1CD0C;BLOCK OCTANT-125;So;0;ON;;;;;N;;;;; +1CD0D;BLOCK OCTANT-135;So;0;ON;;;;;N;;;;; +1CD0E;BLOCK OCTANT-235;So;0;ON;;;;;N;;;;; +1CD0F;BLOCK OCTANT-1235;So;0;ON;;;;;N;;;;; +1CD10;BLOCK OCTANT-45;So;0;ON;;;;;N;;;;; +1CD11;BLOCK OCTANT-145;So;0;ON;;;;;N;;;;; +1CD12;BLOCK OCTANT-245;So;0;ON;;;;;N;;;;; +1CD13;BLOCK OCTANT-1245;So;0;ON;;;;;N;;;;; +1CD14;BLOCK OCTANT-345;So;0;ON;;;;;N;;;;; +1CD15;BLOCK OCTANT-1345;So;0;ON;;;;;N;;;;; +1CD16;BLOCK OCTANT-2345;So;0;ON;;;;;N;;;;; +1CD17;BLOCK OCTANT-12345;So;0;ON;;;;;N;;;;; +1CD18;BLOCK OCTANT-6;So;0;ON;;;;;N;;;;; +1CD19;BLOCK OCTANT-16;So;0;ON;;;;;N;;;;; +1CD1A;BLOCK OCTANT-26;So;0;ON;;;;;N;;;;; +1CD1B;BLOCK OCTANT-126;So;0;ON;;;;;N;;;;; +1CD1C;BLOCK OCTANT-36;So;0;ON;;;;;N;;;;; +1CD1D;BLOCK OCTANT-136;So;0;ON;;;;;N;;;;; +1CD1E;BLOCK OCTANT-236;So;0;ON;;;;;N;;;;; +1CD1F;BLOCK OCTANT-1236;So;0;ON;;;;;N;;;;; +1CD20;BLOCK OCTANT-146;So;0;ON;;;;;N;;;;; +1CD21;BLOCK OCTANT-246;So;0;ON;;;;;N;;;;; +1CD22;BLOCK OCTANT-1246;So;0;ON;;;;;N;;;;; +1CD23;BLOCK OCTANT-346;So;0;ON;;;;;N;;;;; +1CD24;BLOCK OCTANT-1346;So;0;ON;;;;;N;;;;; +1CD25;BLOCK OCTANT-2346;So;0;ON;;;;;N;;;;; +1CD26;BLOCK OCTANT-12346;So;0;ON;;;;;N;;;;; +1CD27;BLOCK OCTANT-56;So;0;ON;;;;;N;;;;; +1CD28;BLOCK OCTANT-156;So;0;ON;;;;;N;;;;; +1CD29;BLOCK OCTANT-256;So;0;ON;;;;;N;;;;; +1CD2A;BLOCK OCTANT-1256;So;0;ON;;;;;N;;;;; +1CD2B;BLOCK OCTANT-356;So;0;ON;;;;;N;;;;; +1CD2C;BLOCK OCTANT-1356;So;0;ON;;;;;N;;;;; +1CD2D;BLOCK OCTANT-2356;So;0;ON;;;;;N;;;;; +1CD2E;BLOCK OCTANT-12356;So;0;ON;;;;;N;;;;; +1CD2F;BLOCK OCTANT-456;So;0;ON;;;;;N;;;;; +1CD30;BLOCK OCTANT-1456;So;0;ON;;;;;N;;;;; +1CD31;BLOCK OCTANT-2456;So;0;ON;;;;;N;;;;; +1CD32;BLOCK OCTANT-12456;So;0;ON;;;;;N;;;;; +1CD33;BLOCK OCTANT-3456;So;0;ON;;;;;N;;;;; +1CD34;BLOCK OCTANT-13456;So;0;ON;;;;;N;;;;; +1CD35;BLOCK OCTANT-23456;So;0;ON;;;;;N;;;;; +1CD36;BLOCK OCTANT-17;So;0;ON;;;;;N;;;;; +1CD37;BLOCK OCTANT-27;So;0;ON;;;;;N;;;;; +1CD38;BLOCK OCTANT-127;So;0;ON;;;;;N;;;;; +1CD39;BLOCK OCTANT-37;So;0;ON;;;;;N;;;;; +1CD3A;BLOCK OCTANT-137;So;0;ON;;;;;N;;;;; +1CD3B;BLOCK OCTANT-237;So;0;ON;;;;;N;;;;; +1CD3C;BLOCK OCTANT-1237;So;0;ON;;;;;N;;;;; +1CD3D;BLOCK OCTANT-47;So;0;ON;;;;;N;;;;; +1CD3E;BLOCK OCTANT-147;So;0;ON;;;;;N;;;;; +1CD3F;BLOCK OCTANT-247;So;0;ON;;;;;N;;;;; +1CD40;BLOCK OCTANT-1247;So;0;ON;;;;;N;;;;; +1CD41;BLOCK OCTANT-347;So;0;ON;;;;;N;;;;; +1CD42;BLOCK OCTANT-1347;So;0;ON;;;;;N;;;;; +1CD43;BLOCK OCTANT-2347;So;0;ON;;;;;N;;;;; +1CD44;BLOCK OCTANT-12347;So;0;ON;;;;;N;;;;; +1CD45;BLOCK OCTANT-157;So;0;ON;;;;;N;;;;; +1CD46;BLOCK OCTANT-257;So;0;ON;;;;;N;;;;; +1CD47;BLOCK OCTANT-1257;So;0;ON;;;;;N;;;;; +1CD48;BLOCK OCTANT-357;So;0;ON;;;;;N;;;;; +1CD49;BLOCK OCTANT-2357;So;0;ON;;;;;N;;;;; +1CD4A;BLOCK OCTANT-12357;So;0;ON;;;;;N;;;;; +1CD4B;BLOCK OCTANT-457;So;0;ON;;;;;N;;;;; +1CD4C;BLOCK OCTANT-1457;So;0;ON;;;;;N;;;;; +1CD4D;BLOCK OCTANT-12457;So;0;ON;;;;;N;;;;; +1CD4E;BLOCK OCTANT-3457;So;0;ON;;;;;N;;;;; +1CD4F;BLOCK OCTANT-13457;So;0;ON;;;;;N;;;;; +1CD50;BLOCK OCTANT-23457;So;0;ON;;;;;N;;;;; +1CD51;BLOCK OCTANT-67;So;0;ON;;;;;N;;;;; +1CD52;BLOCK OCTANT-167;So;0;ON;;;;;N;;;;; +1CD53;BLOCK OCTANT-267;So;0;ON;;;;;N;;;;; +1CD54;BLOCK OCTANT-1267;So;0;ON;;;;;N;;;;; +1CD55;BLOCK OCTANT-367;So;0;ON;;;;;N;;;;; +1CD56;BLOCK OCTANT-1367;So;0;ON;;;;;N;;;;; +1CD57;BLOCK OCTANT-2367;So;0;ON;;;;;N;;;;; +1CD58;BLOCK OCTANT-12367;So;0;ON;;;;;N;;;;; +1CD59;BLOCK OCTANT-467;So;0;ON;;;;;N;;;;; +1CD5A;BLOCK OCTANT-1467;So;0;ON;;;;;N;;;;; +1CD5B;BLOCK OCTANT-2467;So;0;ON;;;;;N;;;;; +1CD5C;BLOCK OCTANT-12467;So;0;ON;;;;;N;;;;; +1CD5D;BLOCK OCTANT-3467;So;0;ON;;;;;N;;;;; +1CD5E;BLOCK OCTANT-13467;So;0;ON;;;;;N;;;;; +1CD5F;BLOCK OCTANT-23467;So;0;ON;;;;;N;;;;; +1CD60;BLOCK OCTANT-123467;So;0;ON;;;;;N;;;;; +1CD61;BLOCK OCTANT-567;So;0;ON;;;;;N;;;;; +1CD62;BLOCK OCTANT-1567;So;0;ON;;;;;N;;;;; +1CD63;BLOCK OCTANT-2567;So;0;ON;;;;;N;;;;; +1CD64;BLOCK OCTANT-12567;So;0;ON;;;;;N;;;;; +1CD65;BLOCK OCTANT-3567;So;0;ON;;;;;N;;;;; +1CD66;BLOCK OCTANT-13567;So;0;ON;;;;;N;;;;; +1CD67;BLOCK OCTANT-23567;So;0;ON;;;;;N;;;;; +1CD68;BLOCK OCTANT-123567;So;0;ON;;;;;N;;;;; +1CD69;BLOCK OCTANT-4567;So;0;ON;;;;;N;;;;; +1CD6A;BLOCK OCTANT-14567;So;0;ON;;;;;N;;;;; +1CD6B;BLOCK OCTANT-24567;So;0;ON;;;;;N;;;;; +1CD6C;BLOCK OCTANT-124567;So;0;ON;;;;;N;;;;; +1CD6D;BLOCK OCTANT-34567;So;0;ON;;;;;N;;;;; +1CD6E;BLOCK OCTANT-134567;So;0;ON;;;;;N;;;;; +1CD6F;BLOCK OCTANT-234567;So;0;ON;;;;;N;;;;; +1CD70;BLOCK OCTANT-1234567;So;0;ON;;;;;N;;;;; +1CD71;BLOCK OCTANT-18;So;0;ON;;;;;N;;;;; +1CD72;BLOCK OCTANT-28;So;0;ON;;;;;N;;;;; +1CD73;BLOCK OCTANT-128;So;0;ON;;;;;N;;;;; +1CD74;BLOCK OCTANT-38;So;0;ON;;;;;N;;;;; +1CD75;BLOCK OCTANT-138;So;0;ON;;;;;N;;;;; +1CD76;BLOCK OCTANT-238;So;0;ON;;;;;N;;;;; +1CD77;BLOCK OCTANT-1238;So;0;ON;;;;;N;;;;; +1CD78;BLOCK OCTANT-48;So;0;ON;;;;;N;;;;; +1CD79;BLOCK OCTANT-148;So;0;ON;;;;;N;;;;; +1CD7A;BLOCK OCTANT-248;So;0;ON;;;;;N;;;;; +1CD7B;BLOCK OCTANT-1248;So;0;ON;;;;;N;;;;; +1CD7C;BLOCK OCTANT-348;So;0;ON;;;;;N;;;;; +1CD7D;BLOCK OCTANT-1348;So;0;ON;;;;;N;;;;; +1CD7E;BLOCK OCTANT-2348;So;0;ON;;;;;N;;;;; +1CD7F;BLOCK OCTANT-12348;So;0;ON;;;;;N;;;;; +1CD80;BLOCK OCTANT-58;So;0;ON;;;;;N;;;;; +1CD81;BLOCK OCTANT-158;So;0;ON;;;;;N;;;;; +1CD82;BLOCK OCTANT-258;So;0;ON;;;;;N;;;;; +1CD83;BLOCK OCTANT-1258;So;0;ON;;;;;N;;;;; +1CD84;BLOCK OCTANT-358;So;0;ON;;;;;N;;;;; +1CD85;BLOCK OCTANT-1358;So;0;ON;;;;;N;;;;; +1CD86;BLOCK OCTANT-2358;So;0;ON;;;;;N;;;;; +1CD87;BLOCK OCTANT-12358;So;0;ON;;;;;N;;;;; +1CD88;BLOCK OCTANT-458;So;0;ON;;;;;N;;;;; +1CD89;BLOCK OCTANT-1458;So;0;ON;;;;;N;;;;; +1CD8A;BLOCK OCTANT-2458;So;0;ON;;;;;N;;;;; +1CD8B;BLOCK OCTANT-12458;So;0;ON;;;;;N;;;;; +1CD8C;BLOCK OCTANT-3458;So;0;ON;;;;;N;;;;; +1CD8D;BLOCK OCTANT-13458;So;0;ON;;;;;N;;;;; +1CD8E;BLOCK OCTANT-23458;So;0;ON;;;;;N;;;;; +1CD8F;BLOCK OCTANT-123458;So;0;ON;;;;;N;;;;; +1CD90;BLOCK OCTANT-168;So;0;ON;;;;;N;;;;; +1CD91;BLOCK OCTANT-268;So;0;ON;;;;;N;;;;; +1CD92;BLOCK OCTANT-1268;So;0;ON;;;;;N;;;;; +1CD93;BLOCK OCTANT-368;So;0;ON;;;;;N;;;;; +1CD94;BLOCK OCTANT-2368;So;0;ON;;;;;N;;;;; +1CD95;BLOCK OCTANT-12368;So;0;ON;;;;;N;;;;; +1CD96;BLOCK OCTANT-468;So;0;ON;;;;;N;;;;; +1CD97;BLOCK OCTANT-1468;So;0;ON;;;;;N;;;;; +1CD98;BLOCK OCTANT-12468;So;0;ON;;;;;N;;;;; +1CD99;BLOCK OCTANT-3468;So;0;ON;;;;;N;;;;; +1CD9A;BLOCK OCTANT-13468;So;0;ON;;;;;N;;;;; +1CD9B;BLOCK OCTANT-23468;So;0;ON;;;;;N;;;;; +1CD9C;BLOCK OCTANT-568;So;0;ON;;;;;N;;;;; +1CD9D;BLOCK OCTANT-1568;So;0;ON;;;;;N;;;;; +1CD9E;BLOCK OCTANT-2568;So;0;ON;;;;;N;;;;; +1CD9F;BLOCK OCTANT-12568;So;0;ON;;;;;N;;;;; +1CDA0;BLOCK OCTANT-3568;So;0;ON;;;;;N;;;;; +1CDA1;BLOCK OCTANT-13568;So;0;ON;;;;;N;;;;; +1CDA2;BLOCK OCTANT-23568;So;0;ON;;;;;N;;;;; +1CDA3;BLOCK OCTANT-123568;So;0;ON;;;;;N;;;;; +1CDA4;BLOCK OCTANT-4568;So;0;ON;;;;;N;;;;; +1CDA5;BLOCK OCTANT-14568;So;0;ON;;;;;N;;;;; +1CDA6;BLOCK OCTANT-24568;So;0;ON;;;;;N;;;;; +1CDA7;BLOCK OCTANT-124568;So;0;ON;;;;;N;;;;; +1CDA8;BLOCK OCTANT-34568;So;0;ON;;;;;N;;;;; +1CDA9;BLOCK OCTANT-134568;So;0;ON;;;;;N;;;;; +1CDAA;BLOCK OCTANT-234568;So;0;ON;;;;;N;;;;; +1CDAB;BLOCK OCTANT-1234568;So;0;ON;;;;;N;;;;; +1CDAC;BLOCK OCTANT-178;So;0;ON;;;;;N;;;;; +1CDAD;BLOCK OCTANT-278;So;0;ON;;;;;N;;;;; +1CDAE;BLOCK OCTANT-1278;So;0;ON;;;;;N;;;;; +1CDAF;BLOCK OCTANT-378;So;0;ON;;;;;N;;;;; +1CDB0;BLOCK OCTANT-1378;So;0;ON;;;;;N;;;;; +1CDB1;BLOCK OCTANT-2378;So;0;ON;;;;;N;;;;; +1CDB2;BLOCK OCTANT-12378;So;0;ON;;;;;N;;;;; +1CDB3;BLOCK OCTANT-478;So;0;ON;;;;;N;;;;; +1CDB4;BLOCK OCTANT-1478;So;0;ON;;;;;N;;;;; +1CDB5;BLOCK OCTANT-2478;So;0;ON;;;;;N;;;;; +1CDB6;BLOCK OCTANT-12478;So;0;ON;;;;;N;;;;; +1CDB7;BLOCK OCTANT-3478;So;0;ON;;;;;N;;;;; +1CDB8;BLOCK OCTANT-13478;So;0;ON;;;;;N;;;;; +1CDB9;BLOCK OCTANT-23478;So;0;ON;;;;;N;;;;; +1CDBA;BLOCK OCTANT-123478;So;0;ON;;;;;N;;;;; +1CDBB;BLOCK OCTANT-578;So;0;ON;;;;;N;;;;; +1CDBC;BLOCK OCTANT-1578;So;0;ON;;;;;N;;;;; +1CDBD;BLOCK OCTANT-2578;So;0;ON;;;;;N;;;;; +1CDBE;BLOCK OCTANT-12578;So;0;ON;;;;;N;;;;; +1CDBF;BLOCK OCTANT-3578;So;0;ON;;;;;N;;;;; +1CDC0;BLOCK OCTANT-13578;So;0;ON;;;;;N;;;;; +1CDC1;BLOCK OCTANT-23578;So;0;ON;;;;;N;;;;; +1CDC2;BLOCK OCTANT-123578;So;0;ON;;;;;N;;;;; +1CDC3;BLOCK OCTANT-4578;So;0;ON;;;;;N;;;;; +1CDC4;BLOCK OCTANT-14578;So;0;ON;;;;;N;;;;; +1CDC5;BLOCK OCTANT-24578;So;0;ON;;;;;N;;;;; +1CDC6;BLOCK OCTANT-124578;So;0;ON;;;;;N;;;;; +1CDC7;BLOCK OCTANT-34578;So;0;ON;;;;;N;;;;; +1CDC8;BLOCK OCTANT-134578;So;0;ON;;;;;N;;;;; +1CDC9;BLOCK OCTANT-234578;So;0;ON;;;;;N;;;;; +1CDCA;BLOCK OCTANT-1234578;So;0;ON;;;;;N;;;;; +1CDCB;BLOCK OCTANT-678;So;0;ON;;;;;N;;;;; +1CDCC;BLOCK OCTANT-1678;So;0;ON;;;;;N;;;;; +1CDCD;BLOCK OCTANT-2678;So;0;ON;;;;;N;;;;; +1CDCE;BLOCK OCTANT-12678;So;0;ON;;;;;N;;;;; +1CDCF;BLOCK OCTANT-3678;So;0;ON;;;;;N;;;;; +1CDD0;BLOCK OCTANT-13678;So;0;ON;;;;;N;;;;; +1CDD1;BLOCK OCTANT-23678;So;0;ON;;;;;N;;;;; +1CDD2;BLOCK OCTANT-123678;So;0;ON;;;;;N;;;;; +1CDD3;BLOCK OCTANT-4678;So;0;ON;;;;;N;;;;; +1CDD4;BLOCK OCTANT-14678;So;0;ON;;;;;N;;;;; +1CDD5;BLOCK OCTANT-24678;So;0;ON;;;;;N;;;;; +1CDD6;BLOCK OCTANT-124678;So;0;ON;;;;;N;;;;; +1CDD7;BLOCK OCTANT-34678;So;0;ON;;;;;N;;;;; +1CDD8;BLOCK OCTANT-134678;So;0;ON;;;;;N;;;;; +1CDD9;BLOCK OCTANT-234678;So;0;ON;;;;;N;;;;; +1CDDA;BLOCK OCTANT-1234678;So;0;ON;;;;;N;;;;; +1CDDB;BLOCK OCTANT-15678;So;0;ON;;;;;N;;;;; +1CDDC;BLOCK OCTANT-25678;So;0;ON;;;;;N;;;;; +1CDDD;BLOCK OCTANT-125678;So;0;ON;;;;;N;;;;; +1CDDE;BLOCK OCTANT-35678;So;0;ON;;;;;N;;;;; +1CDDF;BLOCK OCTANT-235678;So;0;ON;;;;;N;;;;; +1CDE0;BLOCK OCTANT-1235678;So;0;ON;;;;;N;;;;; +1CDE1;BLOCK OCTANT-45678;So;0;ON;;;;;N;;;;; +1CDE2;BLOCK OCTANT-145678;So;0;ON;;;;;N;;;;; +1CDE3;BLOCK OCTANT-1245678;So;0;ON;;;;;N;;;;; +1CDE4;BLOCK OCTANT-1345678;So;0;ON;;;;;N;;;;; +1CDE5;BLOCK OCTANT-2345678;So;0;ON;;;;;N;;;;; +1CDE6;TOP HALF STANDING PERSON;So;0;ON;;;;;N;;;;; +1CDE7;BOTTOM HALF STANDING PERSON;So;0;ON;;;;;N;;;;; +1CDE8;TOP HALF RIGHT-FACING RUNNER FRAME-1;So;0;ON;;;;;N;;;;; +1CDE9;BOTTOM HALF RIGHT-FACING RUNNER FRAME-1;So;0;ON;;;;;N;;;;; +1CDEA;TOP HALF RIGHT-FACING RUNNER FRAME-2;So;0;ON;;;;;N;;;;; +1CDEB;BOTTOM HALF RIGHT-FACING RUNNER FRAME-2;So;0;ON;;;;;N;;;;; +1CDEC;TOP HALF LEFT-FACING RUNNER FRAME-1;So;0;ON;;;;;N;;;;; +1CDED;BOTTOM HALF LEFT-FACING RUNNER FRAME-1;So;0;ON;;;;;N;;;;; +1CDEE;TOP HALF LEFT-FACING RUNNER FRAME-2;So;0;ON;;;;;N;;;;; +1CDEF;BOTTOM HALF LEFT-FACING RUNNER FRAME-2;So;0;ON;;;;;N;;;;; +1CDF0;TOP HALF FORWARD-FACING RUNNER;So;0;ON;;;;;N;;;;; +1CDF1;BOTTOM HALF FORWARD-FACING RUNNER FRAME-1;So;0;ON;;;;;N;;;;; +1CDF2;BOTTOM HALF FORWARD-FACING RUNNER FRAME-2;So;0;ON;;;;;N;;;;; +1CDF3;BOTTOM HALF FORWARD-FACING RUNNER FRAME-3;So;0;ON;;;;;N;;;;; +1CDF4;BOTTOM HALF FORWARD-FACING RUNNER FRAME-4;So;0;ON;;;;;N;;;;; +1CDF5;MOON LANDER;So;0;ON;;;;;N;;;;; +1CDF6;TOP HALF FLAILING ROBOT FRAME-1;So;0;ON;;;;;N;;;;; +1CDF7;TOP HALF FLAILING ROBOT FRAME-2;So;0;ON;;;;;N;;;;; +1CDF8;DOWN-POINTING AIRPLANE;So;0;ON;;;;;N;;;;; +1CDF9;LEFT-POINTING AIRPLANE;So;0;ON;;;;;N;;;;; +1CDFA;SMALL UP-POINTING AIRPLANE;So;0;ON;;;;;N;;;;; +1CDFB;UP-POINTING FROG;So;0;ON;;;;;N;;;;; +1CDFC;DOWN-POINTING FROG;So;0;ON;;;;;N;;;;; +1CDFD;EXPLOSION FRAME-1;So;0;ON;;;;;N;;;;; +1CDFE;EXPLOSION FRAME-2;So;0;ON;;;;;N;;;;; +1CDFF;EXPLOSION FRAME-3;So;0;ON;;;;;N;;;;; +1CE00;RIGHT HALF AND LEFT HALF WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1CE01;LOWER HALF AND UPPER HALF WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1CE02;EXPLOSION AT HORIZON;So;0;ON;;;;;N;;;;; +1CE03;UPPER HALF HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;; +1CE04;LOWER HALF HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;; +1CE05;HEAVY WHITE SQUARE CONTAINING BLACK VERY SMALL SQUARE;So;0;ON;;;;;N;;;;; +1CE06;WHITE VERTICAL RECTANGLE WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;; +1CE07;TOP LEFT BLACK LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;;;;; +1CE08;FUNNEL;So;0;ON;;;;;N;;;;; +1CE09;BOX DRAWINGS DOUBLE DIAGONAL LOWER LEFT TO MIDDLE CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;; +1CE0A;BOX DRAWINGS DOUBLE DIAGONAL UPPER LEFT TO MIDDLE CENTRE TO UPPER RIGHT;So;0;ON;;;;;N;;;;; +1CE0B;LEFT HALF WHITE ELLIPSE;So;0;ON;;;;;N;;;;; +1CE0C;RIGHT HALF WHITE ELLIPSE;So;0;ON;;;;;N;;;;; +1CE0D;LEFT HALF TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;;;;; +1CE0E;RIGHT HALF TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;;;;; +1CE0F;HORIZONTAL LINE WITH TICK MARK;So;0;ON;;;;;N;;;;; +1CE10;LEFT HALF HORIZONTAL LINE WITH THREE TICK MARKS;So;0;ON;;;;;N;;;;; +1CE11;RIGHT HALF HORIZONTAL LINE WITH THREE TICK MARKS;So;0;ON;;;;;N;;;;; +1CE12;HORIZONTAL LINE WITH THREE TICK MARKS;So;0;ON;;;;;N;;;;; +1CE13;LOWER HALF VERTICAL LINE WITH THREE TICK MARKS;So;0;ON;;;;;N;;;;; +1CE14;UPPER HALF VERTICAL LINE WITH THREE TICK MARKS;So;0;ON;;;;;N;;;;; +1CE15;VERTICAL LINE WITH THREE TICK MARKS;So;0;ON;;;;;N;;;;; +1CE16;BOX DRAWINGS LIGHT VERTICAL AND TOP RIGHT;So;0;ON;;;;;N;;;;; +1CE17;BOX DRAWINGS LIGHT VERTICAL AND BOTTOM RIGHT;So;0;ON;;;;;N;;;;; +1CE18;BOX DRAWINGS LIGHT VERTICAL AND TOP LEFT;So;0;ON;;;;;N;;;;; +1CE19;BOX DRAWINGS LIGHT VERTICAL AND BOTTOM LEFT;So;0;ON;;;;;N;;;;; +1CE1A;LARGE TYPE PIECE UPPER LEFT ARC;So;0;ON;;;;;N;;;;; +1CE1B;LARGE TYPE PIECE UPPER LEFT CORNER;So;0;ON;;;;;N;;;;; +1CE1C;LARGE TYPE PIECE UPPER TERMINAL;So;0;ON;;;;;N;;;;; +1CE1D;LARGE TYPE PIECE UPPER LEFT CROTCH;So;0;ON;;;;;N;;;;; +1CE1E;LARGE TYPE PIECE LEFT ARM;So;0;ON;;;;;N;;;;; +1CE1F;LARGE TYPE PIECE CROSSBAR;So;0;ON;;;;;N;;;;; +1CE20;LARGE TYPE PIECE CROSSBAR WITH LOWER STEM;So;0;ON;;;;;N;;;;; +1CE21;LARGE TYPE PIECE UPPER HALF VERTEX OF M;So;0;ON;;;;;N;;;;; +1CE22;LARGE TYPE PIECE DIAGONAL LOWER LEFT;So;0;ON;;;;;N;;;;; +1CE23;LARGE TYPE PIECE SHORT UPPER TERMINAL;So;0;ON;;;;;N;;;;; +1CE24;LARGE TYPE PIECE UPPER RIGHT ARC;So;0;ON;;;;;N;;;;; +1CE25;LARGE TYPE PIECE RIGHT ARM;So;0;ON;;;;;N;;;;; +1CE26;LARGE TYPE PIECE UPPER RIGHT CROTCH;So;0;ON;;;;;N;;;;; +1CE27;LARGE TYPE PIECE UPPER RIGHT CORNER;So;0;ON;;;;;N;;;;; +1CE28;LARGE TYPE PIECE STEM WITH RIGHT CROSSBAR;So;0;ON;;;;;N;;;;; +1CE29;LARGE TYPE PIECE STEM;So;0;ON;;;;;N;;;;; +1CE2A;LARGE TYPE PIECE DIAGONAL UPPER RIGHT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; +1CE2B;LARGE TYPE PIECE DIAGONAL UPPER RIGHT;So;0;ON;;;;;N;;;;; +1CE2C;LARGE TYPE PIECE DIAGONAL LOWER RIGHT;So;0;ON;;;;;N;;;;; +1CE2D;LARGE TYPE PIECE SHORT LOWER TERMINAL;So;0;ON;;;;;N;;;;; +1CE2E;LARGE TYPE PIECE LOWER LEFT AND UPPER LEFT ARC;So;0;ON;;;;;N;;;;; +1CE2F;LARGE TYPE PIECE CENTRE OF K;So;0;ON;;;;;N;;;;; +1CE30;LARGE TYPE PIECE LOWER HALF VERTEX OF M;So;0;ON;;;;;N;;;;; +1CE31;LARGE TYPE PIECE UPPER HALF VERTEX OF W;So;0;ON;;;;;N;;;;; +1CE32;LARGE TYPE PIECE CENTRE OF X;So;0;ON;;;;;N;;;;; +1CE33;LARGE TYPE PIECE CENTRE OF Y;So;0;ON;;;;;N;;;;; +1CE34;LARGE TYPE PIECE CENTRE OF Z WITH CROSSBAR;So;0;ON;;;;;N;;;;; +1CE35;LARGE TYPE PIECE RAISED UPPER LEFT ARC;So;0;ON;;;;;N;;;;; +1CE36;LARGE TYPE PIECE STEM WITH LEFT CROSSBAR;So;0;ON;;;;;N;;;;; +1CE37;LARGE TYPE PIECE LOWER RIGHT AND UPPER RIGHT ARC;So;0;ON;;;;;N;;;;; +1CE38;LARGE TYPE PIECE DIAGONAL UPPER LEFT AND LOWER LEFT;So;0;ON;;;;;N;;;;; +1CE39;LARGE TYPE PIECE STEM WITH LEFT JOINT;So;0;ON;;;;;N;;;;; +1CE3A;LARGE TYPE PIECE STEM WITH CROSSBAR;So;0;ON;;;;;N;;;;; +1CE3B;LARGE TYPE PIECE DIAGONAL UPPER LEFT;So;0;ON;;;;;N;;;;; +1CE3C;LARGE TYPE PIECE LOWER TERMINAL;So;0;ON;;;;;N;;;;; +1CE3D;LARGE TYPE PIECE LOWER LEFT CORNER;So;0;ON;;;;;N;;;;; +1CE3E;LARGE TYPE PIECE LOWER LEFT ARC;So;0;ON;;;;;N;;;;; +1CE3F;LARGE TYPE PIECE LOWER LEFT CROTCH;So;0;ON;;;;;N;;;;; +1CE40;LARGE TYPE PIECE CROSSBAR WITH UPPER STEM;So;0;ON;;;;;N;;;;; +1CE41;LARGE TYPE PIECE VERTEX OF V;So;0;ON;;;;;N;;;;; +1CE42;LARGE TYPE PIECE LOWER HALF VERTEX OF W;So;0;ON;;;;;N;;;;; +1CE43;LARGE TYPE PIECE LOWER RIGHT ARC;So;0;ON;;;;;N;;;;; +1CE44;LARGE TYPE PIECE LOWER RIGHT CORNER;So;0;ON;;;;;N;;;;; +1CE45;LARGE TYPE PIECE LOWER RIGHT ARC WITH TAIL;So;0;ON;;;;;N;;;;; +1CE46;LARGE TYPE PIECE LOWER RIGHT CROTCH;So;0;ON;;;;;N;;;;; +1CE47;LARGE TYPE PIECE STEM-45;So;0;ON;;;;;N;;;;; +1CE48;LARGE TYPE PIECE STEM-2345;So;0;ON;;;;;N;;;;; +1CE49;LARGE TYPE PIECE STEM-4;So;0;ON;;;;;N;;;;; +1CE4A;LARGE TYPE PIECE STEM-34;So;0;ON;;;;;N;;;;; +1CE4B;LARGE TYPE PIECE STEM-234;So;0;ON;;;;;N;;;;; +1CE4C;LARGE TYPE PIECE STEM-1234;So;0;ON;;;;;N;;;;; +1CE4D;LARGE TYPE PIECE STEM-3;So;0;ON;;;;;N;;;;; +1CE4E;LARGE TYPE PIECE STEM-23;So;0;ON;;;;;N;;;;; +1CE4F;LARGE TYPE PIECE STEM-2;So;0;ON;;;;;N;;;;; +1CE50;LARGE TYPE PIECE STEM-12;So;0;ON;;;;;N;;;;; +1CE51;SEPARATED BLOCK SEXTANT-1;So;0;ON;;;;;N;;;;; +1CE52;SEPARATED BLOCK SEXTANT-2;So;0;ON;;;;;N;;;;; +1CE53;SEPARATED BLOCK SEXTANT-12;So;0;ON;;;;;N;;;;; +1CE54;SEPARATED BLOCK SEXTANT-3;So;0;ON;;;;;N;;;;; +1CE55;SEPARATED BLOCK SEXTANT-13;So;0;ON;;;;;N;;;;; +1CE56;SEPARATED BLOCK SEXTANT-23;So;0;ON;;;;;N;;;;; +1CE57;SEPARATED BLOCK SEXTANT-123;So;0;ON;;;;;N;;;;; +1CE58;SEPARATED BLOCK SEXTANT-4;So;0;ON;;;;;N;;;;; +1CE59;SEPARATED BLOCK SEXTANT-14;So;0;ON;;;;;N;;;;; +1CE5A;SEPARATED BLOCK SEXTANT-24;So;0;ON;;;;;N;;;;; +1CE5B;SEPARATED BLOCK SEXTANT-124;So;0;ON;;;;;N;;;;; +1CE5C;SEPARATED BLOCK SEXTANT-34;So;0;ON;;;;;N;;;;; +1CE5D;SEPARATED BLOCK SEXTANT-134;So;0;ON;;;;;N;;;;; +1CE5E;SEPARATED BLOCK SEXTANT-234;So;0;ON;;;;;N;;;;; +1CE5F;SEPARATED BLOCK SEXTANT-1234;So;0;ON;;;;;N;;;;; +1CE60;SEPARATED BLOCK SEXTANT-5;So;0;ON;;;;;N;;;;; +1CE61;SEPARATED BLOCK SEXTANT-15;So;0;ON;;;;;N;;;;; +1CE62;SEPARATED BLOCK SEXTANT-25;So;0;ON;;;;;N;;;;; +1CE63;SEPARATED BLOCK SEXTANT-125;So;0;ON;;;;;N;;;;; +1CE64;SEPARATED BLOCK SEXTANT-35;So;0;ON;;;;;N;;;;; +1CE65;SEPARATED BLOCK SEXTANT-135;So;0;ON;;;;;N;;;;; +1CE66;SEPARATED BLOCK SEXTANT-235;So;0;ON;;;;;N;;;;; +1CE67;SEPARATED BLOCK SEXTANT-1235;So;0;ON;;;;;N;;;;; +1CE68;SEPARATED BLOCK SEXTANT-45;So;0;ON;;;;;N;;;;; +1CE69;SEPARATED BLOCK SEXTANT-145;So;0;ON;;;;;N;;;;; +1CE6A;SEPARATED BLOCK SEXTANT-245;So;0;ON;;;;;N;;;;; +1CE6B;SEPARATED BLOCK SEXTANT-1245;So;0;ON;;;;;N;;;;; +1CE6C;SEPARATED BLOCK SEXTANT-345;So;0;ON;;;;;N;;;;; +1CE6D;SEPARATED BLOCK SEXTANT-1345;So;0;ON;;;;;N;;;;; +1CE6E;SEPARATED BLOCK SEXTANT-2345;So;0;ON;;;;;N;;;;; +1CE6F;SEPARATED BLOCK SEXTANT-12345;So;0;ON;;;;;N;;;;; +1CE70;SEPARATED BLOCK SEXTANT-6;So;0;ON;;;;;N;;;;; +1CE71;SEPARATED BLOCK SEXTANT-16;So;0;ON;;;;;N;;;;; +1CE72;SEPARATED BLOCK SEXTANT-26;So;0;ON;;;;;N;;;;; +1CE73;SEPARATED BLOCK SEXTANT-126;So;0;ON;;;;;N;;;;; +1CE74;SEPARATED BLOCK SEXTANT-36;So;0;ON;;;;;N;;;;; +1CE75;SEPARATED BLOCK SEXTANT-136;So;0;ON;;;;;N;;;;; +1CE76;SEPARATED BLOCK SEXTANT-236;So;0;ON;;;;;N;;;;; +1CE77;SEPARATED BLOCK SEXTANT-1236;So;0;ON;;;;;N;;;;; +1CE78;SEPARATED BLOCK SEXTANT-46;So;0;ON;;;;;N;;;;; +1CE79;SEPARATED BLOCK SEXTANT-146;So;0;ON;;;;;N;;;;; +1CE7A;SEPARATED BLOCK SEXTANT-246;So;0;ON;;;;;N;;;;; +1CE7B;SEPARATED BLOCK SEXTANT-1246;So;0;ON;;;;;N;;;;; +1CE7C;SEPARATED BLOCK SEXTANT-346;So;0;ON;;;;;N;;;;; +1CE7D;SEPARATED BLOCK SEXTANT-1346;So;0;ON;;;;;N;;;;; +1CE7E;SEPARATED BLOCK SEXTANT-2346;So;0;ON;;;;;N;;;;; +1CE7F;SEPARATED BLOCK SEXTANT-12346;So;0;ON;;;;;N;;;;; +1CE80;SEPARATED BLOCK SEXTANT-56;So;0;ON;;;;;N;;;;; +1CE81;SEPARATED BLOCK SEXTANT-156;So;0;ON;;;;;N;;;;; +1CE82;SEPARATED BLOCK SEXTANT-256;So;0;ON;;;;;N;;;;; +1CE83;SEPARATED BLOCK SEXTANT-1256;So;0;ON;;;;;N;;;;; +1CE84;SEPARATED BLOCK SEXTANT-356;So;0;ON;;;;;N;;;;; +1CE85;SEPARATED BLOCK SEXTANT-1356;So;0;ON;;;;;N;;;;; +1CE86;SEPARATED BLOCK SEXTANT-2356;So;0;ON;;;;;N;;;;; +1CE87;SEPARATED BLOCK SEXTANT-12356;So;0;ON;;;;;N;;;;; +1CE88;SEPARATED BLOCK SEXTANT-456;So;0;ON;;;;;N;;;;; +1CE89;SEPARATED BLOCK SEXTANT-1456;So;0;ON;;;;;N;;;;; +1CE8A;SEPARATED BLOCK SEXTANT-2456;So;0;ON;;;;;N;;;;; +1CE8B;SEPARATED BLOCK SEXTANT-12456;So;0;ON;;;;;N;;;;; +1CE8C;SEPARATED BLOCK SEXTANT-3456;So;0;ON;;;;;N;;;;; +1CE8D;SEPARATED BLOCK SEXTANT-13456;So;0;ON;;;;;N;;;;; +1CE8E;SEPARATED BLOCK SEXTANT-23456;So;0;ON;;;;;N;;;;; +1CE8F;SEPARATED BLOCK SEXTANT-123456;So;0;ON;;;;;N;;;;; +1CE90;UPPER LEFT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;; +1CE91;UPPER CENTRE LEFT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;; +1CE92;UPPER CENTRE RIGHT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;; +1CE93;UPPER RIGHT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;; +1CE94;UPPER MIDDLE LEFT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;; +1CE95;UPPER MIDDLE CENTRE LEFT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;; +1CE96;UPPER MIDDLE CENTRE RIGHT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;; +1CE97;UPPER MIDDLE RIGHT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;; +1CE98;LOWER MIDDLE LEFT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;; +1CE99;LOWER MIDDLE CENTRE LEFT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;; +1CE9A;LOWER MIDDLE CENTRE RIGHT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;; +1CE9B;LOWER MIDDLE RIGHT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;; +1CE9C;LOWER LEFT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;; +1CE9D;LOWER CENTRE LEFT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;; +1CE9E;LOWER CENTRE RIGHT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;; +1CE9F;LOWER RIGHT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;; +1CEA0;RIGHT HALF LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1CEA1;RIGHT THREE QUARTERS LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1CEA2;LEFT THREE QUARTERS LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1CEA3;LEFT HALF LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1CEA4;LOWER HALF LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1CEA5;LOWER THREE QUARTERS LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1CEA6;UPPER THREE QUARTERS LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1CEA7;UPPER HALF LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1CEA8;LEFT HALF UPPER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1CEA9;LEFT THREE QUARTERS UPPER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1CEAA;RIGHT THREE QUARTERS UPPER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1CEAB;RIGHT HALF UPPER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1CEAC;UPPER HALF RIGHT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1CEAD;UPPER THREE QUARTERS RIGHT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1CEAE;LOWER THREE QUARTERS RIGHT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1CEAF;LOWER HALF RIGHT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1CEB0;HORIZONTAL ZIGZAG LINE;So;0;ON;;;;;N;;;;; +1CEB1;KEYHOLE;So;0;ON;;;;;N;;;;; +1CEB2;OLD PERSONAL COMPUTER WITH MONITOR IN PORTRAIT ORIENTATION;So;0;ON;;;;;N;;;;; +1CEB3;BLACK RIGHT TRIANGLE CARET;So;0;ON;;;;;N;;;;; +1CEBA;FRAGILE SYMBOL;So;0;ON;;;;;N;;;;; +1CEBB;OFFICE BUILDING SYMBOL;So;0;ON;;;;;N;;;;; +1CEBC;TREE SYMBOL;So;0;ON;;;;;N;;;;; +1CEBD;APPLE SYMBOL;So;0;ON;;;;;N;;;;; +1CEBE;CHERRY SYMBOL;So;0;ON;;;;;N;;;;; +1CEBF;STRAWBERRY SYMBOL;So;0;ON;;;;;N;;;;; +1CEC0;HEBE;So;0;ON;;;;;N;;;;; +1CEC1;IRIS;So;0;ON;;;;;N;;;;; +1CEC2;FLORA;So;0;ON;;;;;N;;;;; +1CEC3;METIS;So;0;ON;;;;;N;;;;; +1CEC4;PARTHENOPE;So;0;ON;;;;;N;;;;; +1CEC5;VICTORIA;So;0;ON;;;;;N;;;;; +1CEC6;EGERIA;So;0;ON;;;;;N;;;;; +1CEC7;IRENE;So;0;ON;;;;;N;;;;; +1CEC8;EUNOMIA;So;0;ON;;;;;N;;;;; +1CEC9;PSYCHE;So;0;ON;;;;;N;;;;; +1CECA;THETIS;So;0;ON;;;;;N;;;;; +1CECB;MELPOMENE;So;0;ON;;;;;N;;;;; +1CECC;FORTUNA;So;0;ON;;;;;N;;;;; +1CECD;ASTRONOMICAL SYMBOL FOR ASTEROID PROSERPINA;So;0;ON;;;;;N;;;;; +1CECE;BELLONA;So;0;ON;;;;;N;;;;; +1CECF;AMPHITRITE;So;0;ON;;;;;N;;;;; +1CED0;LEUKOTHEA;So;0;ON;;;;;N;;;;; +1CEE0;GEOMANTIC FIGURE POPULUS;So;0;ON;;;;;N;;;;; +1CEE1;GEOMANTIC FIGURE TRISTITIA;So;0;ON;;;;;N;;;;; +1CEE2;GEOMANTIC FIGURE ALBUS;So;0;ON;;;;;N;;;;; +1CEE3;GEOMANTIC FIGURE FORTUNA MAJOR;So;0;ON;;;;;N;;;;; +1CEE4;GEOMANTIC FIGURE RUBEUS;So;0;ON;;;;;N;;;;; +1CEE5;GEOMANTIC FIGURE ACQUISITIO;So;0;ON;;;;;N;;;;; +1CEE6;GEOMANTIC FIGURE CONJUNCTIO;So;0;ON;;;;;N;;;;; +1CEE7;GEOMANTIC FIGURE CAPUT DRACONIS;So;0;ON;;;;;N;;;;; +1CEE8;GEOMANTIC FIGURE LAETITIA;So;0;ON;;;;;N;;;;; +1CEE9;GEOMANTIC FIGURE CARCER;So;0;ON;;;;;N;;;;; +1CEEA;GEOMANTIC FIGURE AMISSIO;So;0;ON;;;;;N;;;;; +1CEEB;GEOMANTIC FIGURE PUELLA;So;0;ON;;;;;N;;;;; +1CEEC;GEOMANTIC FIGURE FORTUNA MINOR;So;0;ON;;;;;N;;;;; +1CEED;GEOMANTIC FIGURE PUER;So;0;ON;;;;;N;;;;; +1CEEE;GEOMANTIC FIGURE CAUDA DRACONIS;So;0;ON;;;;;N;;;;; +1CEEF;GEOMANTIC FIGURE VIA;So;0;ON;;;;;N;;;;; +1CEF0;MEDIUM SMALL WHITE CIRCLE WITH HORIZONTAL BAR;Sm;0;ON;;;;;N;;;;; +1CF00;ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF01;ZNAMENNY COMBINING MARK NIZKO S KRYZHEM ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF02;ZNAMENNY COMBINING MARK TSATA ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF03;ZNAMENNY COMBINING MARK GORAZDO NIZKO ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF04;ZNAMENNY COMBINING MARK NIZKO ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF05;ZNAMENNY COMBINING MARK SREDNE ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF06;ZNAMENNY COMBINING MARK MALO POVYSHE ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF07;ZNAMENNY COMBINING MARK POVYSHE ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF08;ZNAMENNY COMBINING MARK VYSOKO ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF09;ZNAMENNY COMBINING MARK MALO POVYSHE S KHOKHLOM ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF0A;ZNAMENNY COMBINING MARK POVYSHE S KHOKHLOM ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF0B;ZNAMENNY COMBINING MARK VYSOKO S KHOKHLOM ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF0C;ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF0D;ZNAMENNY COMBINING MARK NIZKO S KRYZHEM ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF0E;ZNAMENNY COMBINING MARK TSATA ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF0F;ZNAMENNY COMBINING MARK GORAZDO NIZKO ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF10;ZNAMENNY COMBINING MARK NIZKO ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF11;ZNAMENNY COMBINING MARK SREDNE ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF12;ZNAMENNY COMBINING MARK MALO POVYSHE ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF13;ZNAMENNY COMBINING MARK POVYSHE ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF14;ZNAMENNY COMBINING MARK VYSOKO ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF15;ZNAMENNY COMBINING MARK MALO POVYSHE S KHOKHLOM ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF16;ZNAMENNY COMBINING MARK POVYSHE S KHOKHLOM ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF17;ZNAMENNY COMBINING MARK VYSOKO S KHOKHLOM ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF18;ZNAMENNY COMBINING MARK TSATA S KRYZHEM;Mn;0;NSM;;;;;N;;;;; +1CF19;ZNAMENNY COMBINING MARK MALO POVYSHE S KRYZHEM;Mn;0;NSM;;;;;N;;;;; +1CF1A;ZNAMENNY COMBINING MARK STRANNO MALO POVYSHE;Mn;0;NSM;;;;;N;;;;; +1CF1B;ZNAMENNY COMBINING MARK POVYSHE S KRYZHEM;Mn;0;NSM;;;;;N;;;;; +1CF1C;ZNAMENNY COMBINING MARK POVYSHE STRANNO;Mn;0;NSM;;;;;N;;;;; +1CF1D;ZNAMENNY COMBINING MARK VYSOKO S KRYZHEM;Mn;0;NSM;;;;;N;;;;; +1CF1E;ZNAMENNY COMBINING MARK MALO POVYSHE STRANNO;Mn;0;NSM;;;;;N;;;;; +1CF1F;ZNAMENNY COMBINING MARK GORAZDO VYSOKO;Mn;0;NSM;;;;;N;;;;; +1CF20;ZNAMENNY COMBINING MARK ZELO;Mn;0;NSM;;;;;N;;;;; +1CF21;ZNAMENNY COMBINING MARK ON;Mn;0;NSM;;;;;N;;;;; +1CF22;ZNAMENNY COMBINING MARK RAVNO;Mn;0;NSM;;;;;N;;;;; +1CF23;ZNAMENNY COMBINING MARK TIKHAYA;Mn;0;NSM;;;;;N;;;;; +1CF24;ZNAMENNY COMBINING MARK BORZAYA;Mn;0;NSM;;;;;N;;;;; +1CF25;ZNAMENNY COMBINING MARK UDARKA;Mn;0;NSM;;;;;N;;;;; +1CF26;ZNAMENNY COMBINING MARK PODVERTKA;Mn;0;NSM;;;;;N;;;;; +1CF27;ZNAMENNY COMBINING MARK LOMKA;Mn;0;NSM;;;;;N;;;;; +1CF28;ZNAMENNY COMBINING MARK KUPNAYA;Mn;0;NSM;;;;;N;;;;; +1CF29;ZNAMENNY COMBINING MARK KACHKA;Mn;0;NSM;;;;;N;;;;; +1CF2A;ZNAMENNY COMBINING MARK ZEVOK;Mn;0;NSM;;;;;N;;;;; +1CF2B;ZNAMENNY COMBINING MARK SKOBA;Mn;0;NSM;;;;;N;;;;; +1CF2C;ZNAMENNY COMBINING MARK RAZSEKA;Mn;0;NSM;;;;;N;;;;; +1CF2D;ZNAMENNY COMBINING MARK KRYZH ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF30;ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO;Mn;0;NSM;;;;;N;;;;; +1CF31;ZNAMENNY COMBINING TONAL RANGE MARK SVETLO;Mn;0;NSM;;;;;N;;;;; +1CF32;ZNAMENNY COMBINING TONAL RANGE MARK TRESVETLO;Mn;0;NSM;;;;;N;;;;; +1CF33;ZNAMENNY COMBINING MARK ZADERZHKA;Mn;0;NSM;;;;;N;;;;; +1CF34;ZNAMENNY COMBINING MARK DEMESTVENNY ZADERZHKA;Mn;0;NSM;;;;;N;;;;; +1CF35;ZNAMENNY COMBINING MARK OTSECHKA;Mn;0;NSM;;;;;N;;;;; +1CF36;ZNAMENNY COMBINING MARK PODCHASHIE;Mn;0;NSM;;;;;N;;;;; +1CF37;ZNAMENNY COMBINING MARK PODCHASHIE WITH VERTICAL STROKE;Mn;0;NSM;;;;;N;;;;; +1CF38;ZNAMENNY COMBINING MARK CHASHKA;Mn;0;NSM;;;;;N;;;;; +1CF39;ZNAMENNY COMBINING MARK CHASHKA POLNAYA;Mn;0;NSM;;;;;N;;;;; +1CF3A;ZNAMENNY COMBINING MARK OBLACHKO;Mn;0;NSM;;;;;N;;;;; +1CF3B;ZNAMENNY COMBINING MARK SOROCHYA NOZHKA;Mn;0;NSM;;;;;N;;;;; +1CF3C;ZNAMENNY COMBINING MARK TOCHKA;Mn;0;NSM;;;;;N;;;;; +1CF3D;ZNAMENNY COMBINING MARK DVOETOCHIE;Mn;0;NSM;;;;;N;;;;; +1CF3E;ZNAMENNY COMBINING ATTACHING VERTICAL OMET;Mn;0;NSM;;;;;N;;;;; +1CF3F;ZNAMENNY COMBINING MARK CURVED OMET;Mn;0;NSM;;;;;N;;;;; +1CF40;ZNAMENNY COMBINING MARK KRYZH;Mn;0;NSM;;;;;N;;;;; +1CF41;ZNAMENNY COMBINING LOWER TONAL RANGE INDICATOR;Mn;0;NSM;;;;;N;;;;; +1CF42;ZNAMENNY PRIZNAK MODIFIER LEVEL-2;Mn;0;NSM;;;;;N;;;;; +1CF43;ZNAMENNY PRIZNAK MODIFIER LEVEL-3;Mn;0;NSM;;;;;N;;;;; +1CF44;ZNAMENNY PRIZNAK MODIFIER DIRECTION FLIP;Mn;0;NSM;;;;;N;;;;; +1CF45;ZNAMENNY PRIZNAK MODIFIER KRYZH;Mn;0;NSM;;;;;N;;;;; +1CF46;ZNAMENNY PRIZNAK MODIFIER ROG;Mn;0;NSM;;;;;N;;;;; +1CF50;ZNAMENNY NEUME KRYUK;So;0;L;;;;;N;;;;; +1CF51;ZNAMENNY NEUME KRYUK TIKHY;So;0;L;;;;;N;;;;; +1CF52;ZNAMENNY NEUME PARAKLIT;So;0;L;;;;;N;;;;; +1CF53;ZNAMENNY NEUME DVA V CHELNU;So;0;L;;;;;N;;;;; +1CF54;ZNAMENNY NEUME KLYUCH;So;0;L;;;;;N;;;;; +1CF55;ZNAMENNY NEUME ZANOZHEK;So;0;L;;;;;N;;;;; +1CF56;ZNAMENNY NEUME STOPITSA;So;0;L;;;;;N;;;;; +1CF57;ZNAMENNY NEUME STOPITSA S OCHKOM;So;0;L;;;;;N;;;;; +1CF58;ZNAMENNY NEUME PEREVODKA;So;0;L;;;;;N;;;;; +1CF59;ZNAMENNY NEUME PEREVODKA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;; +1CF5A;ZNAMENNY NEUME STOPITSA WITH SOROCHYA NOZHKA;So;0;L;;;;;N;;;;; +1CF5B;ZNAMENNY NEUME CHELYUSTKA;So;0;L;;;;;N;;;;; +1CF5C;ZNAMENNY NEUME PALKA;So;0;L;;;;;N;;;;; +1CF5D;ZNAMENNY NEUME ZAPYATAYA;So;0;L;;;;;N;;;;; +1CF5E;ZNAMENNY NEUME GOLUBCHIK BORZY;So;0;L;;;;;N;;;;; +1CF5F;ZNAMENNY NEUME GOLUBCHIK TIKHY;So;0;L;;;;;N;;;;; +1CF60;ZNAMENNY NEUME GOLUBCHIK MRACHNY;So;0;L;;;;;N;;;;; +1CF61;ZNAMENNY NEUME GOLUBCHIK SVETLY;So;0;L;;;;;N;;;;; +1CF62;ZNAMENNY NEUME GOLUBCHIK TRESVETLY;So;0;L;;;;;N;;;;; +1CF63;ZNAMENNY NEUME VRAKHIYA PROSTAYA;So;0;L;;;;;N;;;;; +1CF64;ZNAMENNY NEUME VRAKHIYA MRACHNAYA;So;0;L;;;;;N;;;;; +1CF65;ZNAMENNY NEUME VRAKHIYA SVETLAYA;So;0;L;;;;;N;;;;; +1CF66;ZNAMENNY NEUME VRAKHIYA TRESVETLAYA;So;0;L;;;;;N;;;;; +1CF67;ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA PROSTAYA;So;0;L;;;;;N;;;;; +1CF68;ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA MRACHNAYA;So;0;L;;;;;N;;;;; +1CF69;ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA SVETLAYA;So;0;L;;;;;N;;;;; +1CF6A;ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA TRESVETLAYA;So;0;L;;;;;N;;;;; +1CF6B;ZNAMENNY NEUME DOUBLE ZAPYATAYA;So;0;L;;;;;N;;;;; +1CF6C;ZNAMENNY NEUME REVERSED CHELYUSTKA;So;0;L;;;;;N;;;;; +1CF6D;ZNAMENNY NEUME DERBITSA;So;0;L;;;;;N;;;;; +1CF6E;ZNAMENNY NEUME KHAMILO;So;0;L;;;;;N;;;;; +1CF6F;ZNAMENNY NEUME CHASHKA;So;0;L;;;;;N;;;;; +1CF70;ZNAMENNY NEUME PODCHASHIE;So;0;L;;;;;N;;;;; +1CF71;ZNAMENNY NEUME SKAMEYTSA MRACHNAYA;So;0;L;;;;;N;;;;; +1CF72;ZNAMENNY NEUME SKAMEYTSA SVETLAYA;So;0;L;;;;;N;;;;; +1CF73;ZNAMENNY NEUME SKAMEYTSA TRESVETLAYA;So;0;L;;;;;N;;;;; +1CF74;ZNAMENNY NEUME SKAMEYTSA TIKHAYA;So;0;L;;;;;N;;;;; +1CF75;ZNAMENNY NEUME DEMESTVENNY KLYUCH;So;0;L;;;;;N;;;;; +1CF76;ZNAMENNY NEUME SKAMEYTSA KLYUCHEVAYA SVETLAYA;So;0;L;;;;;N;;;;; +1CF77;ZNAMENNY NEUME SKAMEYTSA KLYUCHENEPOSTOYANNAYA;So;0;L;;;;;N;;;;; +1CF78;ZNAMENNY NEUME SKAMEYTSA KLYUCHEVAYA TIKHAYA;So;0;L;;;;;N;;;;; +1CF79;ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA PROSTAYA;So;0;L;;;;;N;;;;; +1CF7A;ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA SVETLAYA;So;0;L;;;;;N;;;;; +1CF7B;ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;; +1CF7C;ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA KLYUCHEVAYA;So;0;L;;;;;N;;;;; +1CF7D;ZNAMENNY NEUME SLOZHITIE;So;0;L;;;;;N;;;;; +1CF7E;ZNAMENNY NEUME SLOZHITIE S ZAPYATOY;So;0;L;;;;;N;;;;; +1CF7F;ZNAMENNY NEUME SLOZHITIE ZAKRYTOE;So;0;L;;;;;N;;;;; +1CF80;ZNAMENNY NEUME SLOZHITIE S KRYZHEM;So;0;L;;;;;N;;;;; +1CF81;ZNAMENNY NEUME KRYZH;So;0;L;;;;;N;;;;; +1CF82;ZNAMENNY NEUME ROG;So;0;L;;;;;N;;;;; +1CF83;ZNAMENNY NEUME FITA;So;0;L;;;;;N;;;;; +1CF84;ZNAMENNY NEUME KOBYLA;So;0;L;;;;;N;;;;; +1CF85;ZNAMENNY NEUME ZMEYTSA;So;0;L;;;;;N;;;;; +1CF86;ZNAMENNY NEUME STATYA;So;0;L;;;;;N;;;;; +1CF87;ZNAMENNY NEUME STATYA S ZAPYATOY;So;0;L;;;;;N;;;;; +1CF88;ZNAMENNY NEUME STATYA S KRYZHEM;So;0;L;;;;;N;;;;; +1CF89;ZNAMENNY NEUME STATYA S ZAPYATOY I KRYZHEM;So;0;L;;;;;N;;;;; +1CF8A;ZNAMENNY NEUME STATYA S KRYZHEM I ZAPYATOY;So;0;L;;;;;N;;;;; +1CF8B;ZNAMENNY NEUME STATYA ZAKRYTAYA;So;0;L;;;;;N;;;;; +1CF8C;ZNAMENNY NEUME STATYA ZAKRYTAYA S ZAPYATOY;So;0;L;;;;;N;;;;; +1CF8D;ZNAMENNY NEUME STATYA S ROGOM;So;0;L;;;;;N;;;;; +1CF8E;ZNAMENNY NEUME STATYA S DVUMYA ZAPYATYMI;So;0;L;;;;;N;;;;; +1CF8F;ZNAMENNY NEUME STATYA S ZAPYATOY I PODCHASHIEM;So;0;L;;;;;N;;;;; +1CF90;ZNAMENNY NEUME POLKULIZMY;So;0;L;;;;;N;;;;; +1CF91;ZNAMENNY NEUME STATYA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;; +1CF92;ZNAMENNY NEUME STRELA PROSTAYA;So;0;L;;;;;N;;;;; +1CF93;ZNAMENNY NEUME STRELA MRACHNOTIKHAYA;So;0;L;;;;;N;;;;; +1CF94;ZNAMENNY NEUME STRELA KRYZHEVAYA;So;0;L;;;;;N;;;;; +1CF95;ZNAMENNY NEUME STRELA POLUPOVODNAYA;So;0;L;;;;;N;;;;; +1CF96;ZNAMENNY NEUME STRELA POVODNAYA;So;0;L;;;;;N;;;;; +1CF97;ZNAMENNY NEUME STRELA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;; +1CF98;ZNAMENNY NEUME STRELA KLYUCHEPOVODNAYA;So;0;L;;;;;N;;;;; +1CF99;ZNAMENNY NEUME STRELA KLYUCHENEPOSTOYANNAYA;So;0;L;;;;;N;;;;; +1CF9A;ZNAMENNY NEUME STRELA TIKHAYA PUTNAYA;So;0;L;;;;;N;;;;; +1CF9B;ZNAMENNY NEUME STRELA DVOECHELNAYA;So;0;L;;;;;N;;;;; +1CF9C;ZNAMENNY NEUME STRELA DVOECHELNOKRYZHEVAYA;So;0;L;;;;;N;;;;; +1CF9D;ZNAMENNY NEUME STRELA DVOECHELNOPOVODNAYA;So;0;L;;;;;N;;;;; +1CF9E;ZNAMENNY NEUME STRELA DVOECHELNAYA KLYUCHEVAYA;So;0;L;;;;;N;;;;; +1CF9F;ZNAMENNY NEUME STRELA DVOECHELNOPOVODNAYA KLYUCHEVAYA;So;0;L;;;;;N;;;;; +1CFA0;ZNAMENNY NEUME STRELA GROMNAYA WITH SINGLE ZAPYATAYA;So;0;L;;;;;N;;;;; +1CFA1;ZNAMENNY NEUME STRELA GROMOPOVODNAYA WITH SINGLE ZAPYATAYA;So;0;L;;;;;N;;;;; +1CFA2;ZNAMENNY NEUME STRELA GROMNAYA;So;0;L;;;;;N;;;;; +1CFA3;ZNAMENNY NEUME STRELA GROMOPOVODNAYA;So;0;L;;;;;N;;;;; +1CFA4;ZNAMENNY NEUME STRELA GROMOPOVODNAYA WITH DOUBLE ZAPYATAYA;So;0;L;;;;;N;;;;; +1CFA5;ZNAMENNY NEUME STRELA GROMOKRYZHEVAYA;So;0;L;;;;;N;;;;; +1CFA6;ZNAMENNY NEUME STRELA GROMOKRYZHEVAYA POVODNAYA;So;0;L;;;;;N;;;;; +1CFA7;ZNAMENNY NEUME MECHIK;So;0;L;;;;;N;;;;; +1CFA8;ZNAMENNY NEUME MECHIK POVODNY;So;0;L;;;;;N;;;;; +1CFA9;ZNAMENNY NEUME MECHIK KLYUCHEVOY;So;0;L;;;;;N;;;;; +1CFAA;ZNAMENNY NEUME MECHIK KLYUCHEPOVODNY;So;0;L;;;;;N;;;;; +1CFAB;ZNAMENNY NEUME MECHIK KLYUCHENEPOSTOYANNY;So;0;L;;;;;N;;;;; +1CFAC;ZNAMENNY NEUME STRELA TRYASOGLASNAYA;So;0;L;;;;;N;;;;; +1CFAD;ZNAMENNY NEUME STRELA TRYASOPOVODNAYA;So;0;L;;;;;N;;;;; +1CFAE;ZNAMENNY NEUME STRELA TRYASOSTRELNAYA;So;0;L;;;;;N;;;;; +1CFAF;ZNAMENNY NEUME OSOKA;So;0;L;;;;;N;;;;; +1CFB0;ZNAMENNY NEUME OSOKA SVETLAYA;So;0;L;;;;;N;;;;; +1CFB1;ZNAMENNY NEUME OSOKA TRESVETLAYA;So;0;L;;;;;N;;;;; +1CFB2;ZNAMENNY NEUME OSOKA KRYUKOVAYA SVETLAYA;So;0;L;;;;;N;;;;; +1CFB3;ZNAMENNY NEUME OSOKA KLYUCHEVAYA SVETLAYA;So;0;L;;;;;N;;;;; +1CFB4;ZNAMENNY NEUME OSOKA KLYUCHEVAYA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;; +1CFB5;ZNAMENNY NEUME STRELA KRYUKOVAYA;So;0;L;;;;;N;;;;; +1CFB6;ZNAMENNY NEUME STRELA KRYUKOVAYA POVODNAYA;So;0;L;;;;;N;;;;; +1CFB7;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMNAYA WITH SINGLE ZAPYATAYA;So;0;L;;;;;N;;;;; +1CFB8;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYA WITH SINGLE ZAPYATAYA;So;0;L;;;;;N;;;;; +1CFB9;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMNAYA;So;0;L;;;;;N;;;;; +1CFBA;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYA;So;0;L;;;;;N;;;;; +1CFBB;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYA WITH DOUBLE ZAPYATAYA;So;0;L;;;;;N;;;;; +1CFBC;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOKRYZHEVAYA;So;0;L;;;;;N;;;;; +1CFBD;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOKRYZHEVAYA POVODNAYA;So;0;L;;;;;N;;;;; +1CFBE;ZNAMENNY NEUME STRELA KRYUKOVAYA TRYASKA;So;0;L;;;;;N;;;;; +1CFBF;ZNAMENNY NEUME KUFISMA;So;0;L;;;;;N;;;;; +1CFC0;ZNAMENNY NEUME OBLAKO;So;0;L;;;;;N;;;;; +1CFC1;ZNAMENNY NEUME DUDA;So;0;L;;;;;N;;;;; +1CFC2;ZNAMENNY NEUME NEMKA;So;0;L;;;;;N;;;;; +1CFC3;ZNAMENNY NEUME PAUK;So;0;L;;;;;N;;;;; +1D000;BYZANTINE MUSICAL SYMBOL PSILI;So;0;L;;;;;N;;;;; +1D001;BYZANTINE MUSICAL SYMBOL DASEIA;So;0;L;;;;;N;;;;; +1D002;BYZANTINE MUSICAL SYMBOL PERISPOMENI;So;0;L;;;;;N;;;;; +1D003;BYZANTINE MUSICAL SYMBOL OXEIA EKFONITIKON;So;0;L;;;;;N;;;;; +1D004;BYZANTINE MUSICAL SYMBOL OXEIA DIPLI;So;0;L;;;;;N;;;;; +1D005;BYZANTINE MUSICAL SYMBOL VAREIA EKFONITIKON;So;0;L;;;;;N;;;;; +1D006;BYZANTINE MUSICAL SYMBOL VAREIA DIPLI;So;0;L;;;;;N;;;;; +1D007;BYZANTINE MUSICAL SYMBOL KATHISTI;So;0;L;;;;;N;;;;; +1D008;BYZANTINE MUSICAL SYMBOL SYRMATIKI;So;0;L;;;;;N;;;;; +1D009;BYZANTINE MUSICAL SYMBOL PARAKLITIKI;So;0;L;;;;;N;;;;; +1D00A;BYZANTINE MUSICAL SYMBOL YPOKRISIS;So;0;L;;;;;N;;;;; +1D00B;BYZANTINE MUSICAL SYMBOL YPOKRISIS DIPLI;So;0;L;;;;;N;;;;; +1D00C;BYZANTINE MUSICAL SYMBOL KREMASTI;So;0;L;;;;;N;;;;; +1D00D;BYZANTINE MUSICAL SYMBOL APESO EKFONITIKON;So;0;L;;;;;N;;;;; +1D00E;BYZANTINE MUSICAL SYMBOL EXO EKFONITIKON;So;0;L;;;;;N;;;;; +1D00F;BYZANTINE MUSICAL SYMBOL TELEIA;So;0;L;;;;;N;;;;; +1D010;BYZANTINE MUSICAL SYMBOL KENTIMATA;So;0;L;;;;;N;;;;; +1D011;BYZANTINE MUSICAL SYMBOL APOSTROFOS;So;0;L;;;;;N;;;;; +1D012;BYZANTINE MUSICAL SYMBOL APOSTROFOS DIPLI;So;0;L;;;;;N;;;;; +1D013;BYZANTINE MUSICAL SYMBOL SYNEVMA;So;0;L;;;;;N;;;;; +1D014;BYZANTINE MUSICAL SYMBOL THITA;So;0;L;;;;;N;;;;; +1D015;BYZANTINE MUSICAL SYMBOL OLIGON ARCHAION;So;0;L;;;;;N;;;;; +1D016;BYZANTINE MUSICAL SYMBOL GORGON ARCHAION;So;0;L;;;;;N;;;;; +1D017;BYZANTINE MUSICAL SYMBOL PSILON;So;0;L;;;;;N;;;;; +1D018;BYZANTINE MUSICAL SYMBOL CHAMILON;So;0;L;;;;;N;;;;; +1D019;BYZANTINE MUSICAL SYMBOL VATHY;So;0;L;;;;;N;;;;; +1D01A;BYZANTINE MUSICAL SYMBOL ISON ARCHAION;So;0;L;;;;;N;;;;; +1D01B;BYZANTINE MUSICAL SYMBOL KENTIMA ARCHAION;So;0;L;;;;;N;;;;; +1D01C;BYZANTINE MUSICAL SYMBOL KENTIMATA ARCHAION;So;0;L;;;;;N;;;;; +1D01D;BYZANTINE MUSICAL SYMBOL SAXIMATA;So;0;L;;;;;N;;;;; +1D01E;BYZANTINE MUSICAL SYMBOL PARICHON;So;0;L;;;;;N;;;;; +1D01F;BYZANTINE MUSICAL SYMBOL STAVROS APODEXIA;So;0;L;;;;;N;;;;; +1D020;BYZANTINE MUSICAL SYMBOL OXEIAI ARCHAION;So;0;L;;;;;N;;;;; +1D021;BYZANTINE MUSICAL SYMBOL VAREIAI ARCHAION;So;0;L;;;;;N;;;;; +1D022;BYZANTINE MUSICAL SYMBOL APODERMA ARCHAION;So;0;L;;;;;N;;;;; +1D023;BYZANTINE MUSICAL SYMBOL APOTHEMA;So;0;L;;;;;N;;;;; +1D024;BYZANTINE MUSICAL SYMBOL KLASMA;So;0;L;;;;;N;;;;; +1D025;BYZANTINE MUSICAL SYMBOL REVMA;So;0;L;;;;;N;;;;; +1D026;BYZANTINE MUSICAL SYMBOL PIASMA ARCHAION;So;0;L;;;;;N;;;;; +1D027;BYZANTINE MUSICAL SYMBOL TINAGMA;So;0;L;;;;;N;;;;; +1D028;BYZANTINE MUSICAL SYMBOL ANATRICHISMA;So;0;L;;;;;N;;;;; +1D029;BYZANTINE MUSICAL SYMBOL SEISMA;So;0;L;;;;;N;;;;; +1D02A;BYZANTINE MUSICAL SYMBOL SYNAGMA ARCHAION;So;0;L;;;;;N;;;;; +1D02B;BYZANTINE MUSICAL SYMBOL SYNAGMA META STAVROU;So;0;L;;;;;N;;;;; +1D02C;BYZANTINE MUSICAL SYMBOL OYRANISMA ARCHAION;So;0;L;;;;;N;;;;; +1D02D;BYZANTINE MUSICAL SYMBOL THEMA;So;0;L;;;;;N;;;;; +1D02E;BYZANTINE MUSICAL SYMBOL LEMOI;So;0;L;;;;;N;;;;; +1D02F;BYZANTINE MUSICAL SYMBOL DYO;So;0;L;;;;;N;;;;; +1D030;BYZANTINE MUSICAL SYMBOL TRIA;So;0;L;;;;;N;;;;; +1D031;BYZANTINE MUSICAL SYMBOL TESSERA;So;0;L;;;;;N;;;;; +1D032;BYZANTINE MUSICAL SYMBOL KRATIMATA;So;0;L;;;;;N;;;;; +1D033;BYZANTINE MUSICAL SYMBOL APESO EXO NEO;So;0;L;;;;;N;;;;; +1D034;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION;So;0;L;;;;;N;;;;; +1D035;BYZANTINE MUSICAL SYMBOL IMIFTHORA;So;0;L;;;;;N;;;;; +1D036;BYZANTINE MUSICAL SYMBOL TROMIKON ARCHAION;So;0;L;;;;;N;;;;; +1D037;BYZANTINE MUSICAL SYMBOL KATAVA TROMIKON;So;0;L;;;;;N;;;;; +1D038;BYZANTINE MUSICAL SYMBOL PELASTON;So;0;L;;;;;N;;;;; +1D039;BYZANTINE MUSICAL SYMBOL PSIFISTON;So;0;L;;;;;N;;;;; +1D03A;BYZANTINE MUSICAL SYMBOL KONTEVMA;So;0;L;;;;;N;;;;; +1D03B;BYZANTINE MUSICAL SYMBOL CHOREVMA ARCHAION;So;0;L;;;;;N;;;;; +1D03C;BYZANTINE MUSICAL SYMBOL RAPISMA;So;0;L;;;;;N;;;;; +1D03D;BYZANTINE MUSICAL SYMBOL PARAKALESMA ARCHAION;So;0;L;;;;;N;;;;; +1D03E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI ARCHAION;So;0;L;;;;;N;;;;; +1D03F;BYZANTINE MUSICAL SYMBOL ICHADIN;So;0;L;;;;;N;;;;; +1D040;BYZANTINE MUSICAL SYMBOL NANA;So;0;L;;;;;N;;;;; +1D041;BYZANTINE MUSICAL SYMBOL PETASMA;So;0;L;;;;;N;;;;; +1D042;BYZANTINE MUSICAL SYMBOL KONTEVMA ALLO;So;0;L;;;;;N;;;;; +1D043;BYZANTINE MUSICAL SYMBOL TROMIKON ALLO;So;0;L;;;;;N;;;;; +1D044;BYZANTINE MUSICAL SYMBOL STRAGGISMATA;So;0;L;;;;;N;;;;; +1D045;BYZANTINE MUSICAL SYMBOL GRONTHISMATA;So;0;L;;;;;N;;;;; +1D046;BYZANTINE MUSICAL SYMBOL ISON NEO;So;0;L;;;;;N;;;;; +1D047;BYZANTINE MUSICAL SYMBOL OLIGON NEO;So;0;L;;;;;N;;;;; +1D048;BYZANTINE MUSICAL SYMBOL OXEIA NEO;So;0;L;;;;;N;;;;; +1D049;BYZANTINE MUSICAL SYMBOL PETASTI;So;0;L;;;;;N;;;;; +1D04A;BYZANTINE MUSICAL SYMBOL KOUFISMA;So;0;L;;;;;N;;;;; +1D04B;BYZANTINE MUSICAL SYMBOL PETASTOKOUFISMA;So;0;L;;;;;N;;;;; +1D04C;BYZANTINE MUSICAL SYMBOL KRATIMOKOUFISMA;So;0;L;;;;;N;;;;; +1D04D;BYZANTINE MUSICAL SYMBOL PELASTON NEO;So;0;L;;;;;N;;;;; +1D04E;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO ANO;So;0;L;;;;;N;;;;; +1D04F;BYZANTINE MUSICAL SYMBOL KENTIMA NEO ANO;So;0;L;;;;;N;;;;; +1D050;BYZANTINE MUSICAL SYMBOL YPSILI;So;0;L;;;;;N;;;;; +1D051;BYZANTINE MUSICAL SYMBOL APOSTROFOS NEO;So;0;L;;;;;N;;;;; +1D052;BYZANTINE MUSICAL SYMBOL APOSTROFOI SYNDESMOS NEO;So;0;L;;;;;N;;;;; +1D053;BYZANTINE MUSICAL SYMBOL YPORROI;So;0;L;;;;;N;;;;; +1D054;BYZANTINE MUSICAL SYMBOL KRATIMOYPORROON;So;0;L;;;;;N;;;;; +1D055;BYZANTINE MUSICAL SYMBOL ELAFRON;So;0;L;;;;;N;;;;; +1D056;BYZANTINE MUSICAL SYMBOL CHAMILI;So;0;L;;;;;N;;;;; +1D057;BYZANTINE MUSICAL SYMBOL MIKRON ISON;So;0;L;;;;;N;;;;; +1D058;BYZANTINE MUSICAL SYMBOL VAREIA NEO;So;0;L;;;;;N;;;;; +1D059;BYZANTINE MUSICAL SYMBOL PIASMA NEO;So;0;L;;;;;N;;;;; +1D05A;BYZANTINE MUSICAL SYMBOL PSIFISTON NEO;So;0;L;;;;;N;;;;; +1D05B;BYZANTINE MUSICAL SYMBOL OMALON;So;0;L;;;;;N;;;;; +1D05C;BYZANTINE MUSICAL SYMBOL ANTIKENOMA;So;0;L;;;;;N;;;;; +1D05D;BYZANTINE MUSICAL SYMBOL LYGISMA;So;0;L;;;;;N;;;;; +1D05E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI NEO;So;0;L;;;;;N;;;;; +1D05F;BYZANTINE MUSICAL SYMBOL PARAKALESMA NEO;So;0;L;;;;;N;;;;; +1D060;BYZANTINE MUSICAL SYMBOL ETERON PARAKALESMA;So;0;L;;;;;N;;;;; +1D061;BYZANTINE MUSICAL SYMBOL KYLISMA;So;0;L;;;;;N;;;;; +1D062;BYZANTINE MUSICAL SYMBOL ANTIKENOKYLISMA;So;0;L;;;;;N;;;;; +1D063;BYZANTINE MUSICAL SYMBOL TROMIKON NEO;So;0;L;;;;;N;;;;; +1D064;BYZANTINE MUSICAL SYMBOL EKSTREPTON;So;0;L;;;;;N;;;;; +1D065;BYZANTINE MUSICAL SYMBOL SYNAGMA NEO;So;0;L;;;;;N;;;;; +1D066;BYZANTINE MUSICAL SYMBOL SYRMA;So;0;L;;;;;N;;;;; +1D067;BYZANTINE MUSICAL SYMBOL CHOREVMA NEO;So;0;L;;;;;N;;;;; +1D068;BYZANTINE MUSICAL SYMBOL EPEGERMA;So;0;L;;;;;N;;;;; +1D069;BYZANTINE MUSICAL SYMBOL SEISMA NEO;So;0;L;;;;;N;;;;; +1D06A;BYZANTINE MUSICAL SYMBOL XIRON KLASMA;So;0;L;;;;;N;;;;; +1D06B;BYZANTINE MUSICAL SYMBOL TROMIKOPSIFISTON;So;0;L;;;;;N;;;;; +1D06C;BYZANTINE MUSICAL SYMBOL PSIFISTOLYGISMA;So;0;L;;;;;N;;;;; +1D06D;BYZANTINE MUSICAL SYMBOL TROMIKOLYGISMA;So;0;L;;;;;N;;;;; +1D06E;BYZANTINE MUSICAL SYMBOL TROMIKOPARAKALESMA;So;0;L;;;;;N;;;;; +1D06F;BYZANTINE MUSICAL SYMBOL PSIFISTOPARAKALESMA;So;0;L;;;;;N;;;;; +1D070;BYZANTINE MUSICAL SYMBOL TROMIKOSYNAGMA;So;0;L;;;;;N;;;;; +1D071;BYZANTINE MUSICAL SYMBOL PSIFISTOSYNAGMA;So;0;L;;;;;N;;;;; +1D072;BYZANTINE MUSICAL SYMBOL GORGOSYNTHETON;So;0;L;;;;;N;;;;; +1D073;BYZANTINE MUSICAL SYMBOL ARGOSYNTHETON;So;0;L;;;;;N;;;;; +1D074;BYZANTINE MUSICAL SYMBOL ETERON ARGOSYNTHETON;So;0;L;;;;;N;;;;; +1D075;BYZANTINE MUSICAL SYMBOL OYRANISMA NEO;So;0;L;;;;;N;;;;; +1D076;BYZANTINE MUSICAL SYMBOL THEMATISMOS ESO;So;0;L;;;;;N;;;;; +1D077;BYZANTINE MUSICAL SYMBOL THEMATISMOS EXO;So;0;L;;;;;N;;;;; +1D078;BYZANTINE MUSICAL SYMBOL THEMA APLOUN;So;0;L;;;;;N;;;;; +1D079;BYZANTINE MUSICAL SYMBOL THES KAI APOTHES;So;0;L;;;;;N;;;;; +1D07A;BYZANTINE MUSICAL SYMBOL KATAVASMA;So;0;L;;;;;N;;;;; +1D07B;BYZANTINE MUSICAL SYMBOL ENDOFONON;So;0;L;;;;;N;;;;; +1D07C;BYZANTINE MUSICAL SYMBOL YFEN KATO;So;0;L;;;;;N;;;;; +1D07D;BYZANTINE MUSICAL SYMBOL YFEN ANO;So;0;L;;;;;N;;;;; +1D07E;BYZANTINE MUSICAL SYMBOL STAVROS;So;0;L;;;;;N;;;;; +1D07F;BYZANTINE MUSICAL SYMBOL KLASMA ANO;So;0;L;;;;;N;;;;; +1D080;BYZANTINE MUSICAL SYMBOL DIPLI ARCHAION;So;0;L;;;;;N;;;;; +1D081;BYZANTINE MUSICAL SYMBOL KRATIMA ARCHAION;So;0;L;;;;;N;;;;; +1D082;BYZANTINE MUSICAL SYMBOL KRATIMA ALLO;So;0;L;;;;;N;;;;; +1D083;BYZANTINE MUSICAL SYMBOL KRATIMA NEO;So;0;L;;;;;N;;;;; +1D084;BYZANTINE MUSICAL SYMBOL APODERMA NEO;So;0;L;;;;;N;;;;; +1D085;BYZANTINE MUSICAL SYMBOL APLI;So;0;L;;;;;N;;;;; +1D086;BYZANTINE MUSICAL SYMBOL DIPLI;So;0;L;;;;;N;;;;; +1D087;BYZANTINE MUSICAL SYMBOL TRIPLI;So;0;L;;;;;N;;;;; +1D088;BYZANTINE MUSICAL SYMBOL TETRAPLI;So;0;L;;;;;N;;;;; +1D089;BYZANTINE MUSICAL SYMBOL KORONIS;So;0;L;;;;;N;;;;; +1D08A;BYZANTINE MUSICAL SYMBOL LEIMMA ENOS CHRONOU;So;0;L;;;;;N;;;;; +1D08B;BYZANTINE MUSICAL SYMBOL LEIMMA DYO CHRONON;So;0;L;;;;;N;;;;; +1D08C;BYZANTINE MUSICAL SYMBOL LEIMMA TRION CHRONON;So;0;L;;;;;N;;;;; +1D08D;BYZANTINE MUSICAL SYMBOL LEIMMA TESSARON CHRONON;So;0;L;;;;;N;;;;; +1D08E;BYZANTINE MUSICAL SYMBOL LEIMMA IMISEOS CHRONOU;So;0;L;;;;;N;;;;; +1D08F;BYZANTINE MUSICAL SYMBOL GORGON NEO ANO;So;0;L;;;;;N;;;;; +1D090;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON ARISTERA;So;0;L;;;;;N;;;;; +1D091;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;; +1D092;BYZANTINE MUSICAL SYMBOL DIGORGON;So;0;L;;;;;N;;;;; +1D093;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA KATO;So;0;L;;;;;N;;;;; +1D094;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA ANO;So;0;L;;;;;N;;;;; +1D095;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;; +1D096;BYZANTINE MUSICAL SYMBOL TRIGORGON;So;0;L;;;;;N;;;;; +1D097;BYZANTINE MUSICAL SYMBOL ARGON;So;0;L;;;;;N;;;;; +1D098;BYZANTINE MUSICAL SYMBOL IMIDIARGON;So;0;L;;;;;N;;;;; +1D099;BYZANTINE MUSICAL SYMBOL DIARGON;So;0;L;;;;;N;;;;; +1D09A;BYZANTINE MUSICAL SYMBOL AGOGI POLI ARGI;So;0;L;;;;;N;;;;; +1D09B;BYZANTINE MUSICAL SYMBOL AGOGI ARGOTERI;So;0;L;;;;;N;;;;; +1D09C;BYZANTINE MUSICAL SYMBOL AGOGI ARGI;So;0;L;;;;;N;;;;; +1D09D;BYZANTINE MUSICAL SYMBOL AGOGI METRIA;So;0;L;;;;;N;;;;; +1D09E;BYZANTINE MUSICAL SYMBOL AGOGI MESI;So;0;L;;;;;N;;;;; +1D09F;BYZANTINE MUSICAL SYMBOL AGOGI GORGI;So;0;L;;;;;N;;;;; +1D0A0;BYZANTINE MUSICAL SYMBOL AGOGI GORGOTERI;So;0;L;;;;;N;;;;; +1D0A1;BYZANTINE MUSICAL SYMBOL AGOGI POLI GORGI;So;0;L;;;;;N;;;;; +1D0A2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOS ICHOS;So;0;L;;;;;N;;;;; +1D0A3;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI PROTOS ICHOS;So;0;L;;;;;N;;;;; +1D0A4;BYZANTINE MUSICAL SYMBOL MARTYRIA DEYTEROS ICHOS;So;0;L;;;;;N;;;;; +1D0A5;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI DEYTEROS ICHOS;So;0;L;;;;;N;;;;; +1D0A6;BYZANTINE MUSICAL SYMBOL MARTYRIA TRITOS ICHOS;So;0;L;;;;;N;;;;; +1D0A7;BYZANTINE MUSICAL SYMBOL MARTYRIA TRIFONIAS;So;0;L;;;;;N;;;;; +1D0A8;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS ICHOS;So;0;L;;;;;N;;;;; +1D0A9;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS LEGETOS ICHOS;So;0;L;;;;;N;;;;; +1D0AA;BYZANTINE MUSICAL SYMBOL MARTYRIA LEGETOS ICHOS;So;0;L;;;;;N;;;;; +1D0AB;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS ICHOS;So;0;L;;;;;N;;;;; +1D0AC;BYZANTINE MUSICAL SYMBOL ISAKIA TELOUS ICHIMATOS;So;0;L;;;;;N;;;;; +1D0AD;BYZANTINE MUSICAL SYMBOL APOSTROFOI TELOUS ICHIMATOS;So;0;L;;;;;N;;;;; +1D0AE;BYZANTINE MUSICAL SYMBOL FANEROSIS TETRAFONIAS;So;0;L;;;;;N;;;;; +1D0AF;BYZANTINE MUSICAL SYMBOL FANEROSIS MONOFONIAS;So;0;L;;;;;N;;;;; +1D0B0;BYZANTINE MUSICAL SYMBOL FANEROSIS DIFONIAS;So;0;L;;;;;N;;;;; +1D0B1;BYZANTINE MUSICAL SYMBOL MARTYRIA VARYS ICHOS;So;0;L;;;;;N;;;;; +1D0B2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOVARYS ICHOS;So;0;L;;;;;N;;;;; +1D0B3;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS TETARTOS ICHOS;So;0;L;;;;;N;;;;; +1D0B4;BYZANTINE MUSICAL SYMBOL GORTHMIKON N APLOUN;So;0;L;;;;;N;;;;; +1D0B5;BYZANTINE MUSICAL SYMBOL GORTHMIKON N DIPLOUN;So;0;L;;;;;N;;;;; +1D0B6;BYZANTINE MUSICAL SYMBOL ENARXIS KAI FTHORA VOU;So;0;L;;;;;N;;;;; +1D0B7;BYZANTINE MUSICAL SYMBOL IMIFONON;So;0;L;;;;;N;;;;; +1D0B8;BYZANTINE MUSICAL SYMBOL IMIFTHORON;So;0;L;;;;;N;;;;; +1D0B9;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION DEYTEROU ICHOU;So;0;L;;;;;N;;;;; +1D0BA;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI PA;So;0;L;;;;;N;;;;; +1D0BB;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NANA;So;0;L;;;;;N;;;;; +1D0BC;BYZANTINE MUSICAL SYMBOL FTHORA NAOS ICHOS;So;0;L;;;;;N;;;;; +1D0BD;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI DI;So;0;L;;;;;N;;;;; +1D0BE;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON DIATONON DI;So;0;L;;;;;N;;;;; +1D0BF;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI KE;So;0;L;;;;;N;;;;; +1D0C0;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI ZO;So;0;L;;;;;N;;;;; +1D0C1;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI KATO;So;0;L;;;;;N;;;;; +1D0C2;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI ANO;So;0;L;;;;;N;;;;; +1D0C3;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA DIFONIAS;So;0;L;;;;;N;;;;; +1D0C4;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA MONOFONIAS;So;0;L;;;;;N;;;;; +1D0C5;BYZANTINE MUSICAL SYMBOL FHTORA SKLIRON CHROMA VASIS;So;0;L;;;;;N;;;;; +1D0C6;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA SYNAFI;So;0;L;;;;;N;;;;; +1D0C7;BYZANTINE MUSICAL SYMBOL FTHORA NENANO;So;0;L;;;;;N;;;;; +1D0C8;BYZANTINE MUSICAL SYMBOL CHROA ZYGOS;So;0;L;;;;;N;;;;; +1D0C9;BYZANTINE MUSICAL SYMBOL CHROA KLITON;So;0;L;;;;;N;;;;; +1D0CA;BYZANTINE MUSICAL SYMBOL CHROA SPATHI;So;0;L;;;;;N;;;;; +1D0CB;BYZANTINE MUSICAL SYMBOL FTHORA I YFESIS TETARTIMORION;So;0;L;;;;;N;;;;; +1D0CC;BYZANTINE MUSICAL SYMBOL FTHORA ENARMONIOS ANTIFONIA;So;0;L;;;;;N;;;;; +1D0CD;BYZANTINE MUSICAL SYMBOL YFESIS TRITIMORION;So;0;L;;;;;N;;;;; +1D0CE;BYZANTINE MUSICAL SYMBOL DIESIS TRITIMORION;So;0;L;;;;;N;;;;; +1D0CF;BYZANTINE MUSICAL SYMBOL DIESIS TETARTIMORION;So;0;L;;;;;N;;;;; +1D0D0;BYZANTINE MUSICAL SYMBOL DIESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;; +1D0D1;BYZANTINE MUSICAL SYMBOL DIESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;; +1D0D2;BYZANTINE MUSICAL SYMBOL DIESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;; +1D0D3;BYZANTINE MUSICAL SYMBOL DIESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;; +1D0D4;BYZANTINE MUSICAL SYMBOL YFESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;; +1D0D5;BYZANTINE MUSICAL SYMBOL YFESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;; +1D0D6;BYZANTINE MUSICAL SYMBOL YFESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;; +1D0D7;BYZANTINE MUSICAL SYMBOL YFESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;; +1D0D8;BYZANTINE MUSICAL SYMBOL GENIKI DIESIS;So;0;L;;;;;N;;;;; +1D0D9;BYZANTINE MUSICAL SYMBOL GENIKI YFESIS;So;0;L;;;;;N;;;;; +1D0DA;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MIKRI;So;0;L;;;;;N;;;;; +1D0DB;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MEGALI;So;0;L;;;;;N;;;;; +1D0DC;BYZANTINE MUSICAL SYMBOL DIASTOLI DIPLI;So;0;L;;;;;N;;;;; +1D0DD;BYZANTINE MUSICAL SYMBOL DIASTOLI THESEOS;So;0;L;;;;;N;;;;; +1D0DE;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS;So;0;L;;;;;N;;;;; +1D0DF;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS DISIMOU;So;0;L;;;;;N;;;;; +1D0E0;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TRISIMOU;So;0;L;;;;;N;;;;; +1D0E1;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TETRASIMOU;So;0;L;;;;;N;;;;; +1D0E2;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS;So;0;L;;;;;N;;;;; +1D0E3;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS DISIMOU;So;0;L;;;;;N;;;;; +1D0E4;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TRISIMOU;So;0;L;;;;;N;;;;; +1D0E5;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TETRASIMOU;So;0;L;;;;;N;;;;; +1D0E6;BYZANTINE MUSICAL SYMBOL DIGRAMMA GG;So;0;L;;;;;N;;;;; +1D0E7;BYZANTINE MUSICAL SYMBOL DIFTOGGOS OU;So;0;L;;;;;N;;;;; +1D0E8;BYZANTINE MUSICAL SYMBOL STIGMA;So;0;L;;;;;N;;;;; +1D0E9;BYZANTINE MUSICAL SYMBOL ARKTIKO PA;So;0;L;;;;;N;;;;; +1D0EA;BYZANTINE MUSICAL SYMBOL ARKTIKO VOU;So;0;L;;;;;N;;;;; +1D0EB;BYZANTINE MUSICAL SYMBOL ARKTIKO GA;So;0;L;;;;;N;;;;; +1D0EC;BYZANTINE MUSICAL SYMBOL ARKTIKO DI;So;0;L;;;;;N;;;;; +1D0ED;BYZANTINE MUSICAL SYMBOL ARKTIKO KE;So;0;L;;;;;N;;;;; +1D0EE;BYZANTINE MUSICAL SYMBOL ARKTIKO ZO;So;0;L;;;;;N;;;;; +1D0EF;BYZANTINE MUSICAL SYMBOL ARKTIKO NI;So;0;L;;;;;N;;;;; +1D0F0;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO MESO;So;0;L;;;;;N;;;;; +1D0F1;BYZANTINE MUSICAL SYMBOL KENTIMA NEO MESO;So;0;L;;;;;N;;;;; +1D0F2;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO KATO;So;0;L;;;;;N;;;;; +1D0F3;BYZANTINE MUSICAL SYMBOL KENTIMA NEO KATO;So;0;L;;;;;N;;;;; +1D0F4;BYZANTINE MUSICAL SYMBOL KLASMA KATO;So;0;L;;;;;N;;;;; +1D0F5;BYZANTINE MUSICAL SYMBOL GORGON NEO KATO;So;0;L;;;;;N;;;;; +1D100;MUSICAL SYMBOL SINGLE BARLINE;So;0;L;;;;;N;;;;; +1D101;MUSICAL SYMBOL DOUBLE BARLINE;So;0;L;;;;;N;;;;; +1D102;MUSICAL SYMBOL FINAL BARLINE;So;0;L;;;;;N;;;;; +1D103;MUSICAL SYMBOL REVERSE FINAL BARLINE;So;0;L;;;;;N;;;;; +1D104;MUSICAL SYMBOL DASHED BARLINE;So;0;L;;;;;N;;;;; +1D105;MUSICAL SYMBOL SHORT BARLINE;So;0;L;;;;;N;;;;; +1D106;MUSICAL SYMBOL LEFT REPEAT SIGN;So;0;L;;;;;N;;;;; +1D107;MUSICAL SYMBOL RIGHT REPEAT SIGN;So;0;L;;;;;N;;;;; +1D108;MUSICAL SYMBOL REPEAT DOTS;So;0;L;;;;;N;;;;; +1D109;MUSICAL SYMBOL DAL SEGNO;So;0;L;;;;;N;;;;; +1D10A;MUSICAL SYMBOL DA CAPO;So;0;L;;;;;N;;;;; +1D10B;MUSICAL SYMBOL SEGNO;So;0;L;;;;;N;;;;; +1D10C;MUSICAL SYMBOL CODA;So;0;L;;;;;N;;;;; +1D10D;MUSICAL SYMBOL REPEATED FIGURE-1;So;0;L;;;;;N;;;;; +1D10E;MUSICAL SYMBOL REPEATED FIGURE-2;So;0;L;;;;;N;;;;; +1D10F;MUSICAL SYMBOL REPEATED FIGURE-3;So;0;L;;;;;N;;;;; +1D110;MUSICAL SYMBOL FERMATA;So;0;L;;;;;N;;;;; +1D111;MUSICAL SYMBOL FERMATA BELOW;So;0;L;;;;;N;;;;; +1D112;MUSICAL SYMBOL BREATH MARK;So;0;L;;;;;N;;;;; +1D113;MUSICAL SYMBOL CAESURA;So;0;L;;;;;N;;;;; +1D114;MUSICAL SYMBOL BRACE;So;0;L;;;;;N;;;;; +1D115;MUSICAL SYMBOL BRACKET;So;0;L;;;;;N;;;;; +1D116;MUSICAL SYMBOL ONE-LINE STAFF;So;0;L;;;;;N;;;;; +1D117;MUSICAL SYMBOL TWO-LINE STAFF;So;0;L;;;;;N;;;;; +1D118;MUSICAL SYMBOL THREE-LINE STAFF;So;0;L;;;;;N;;;;; +1D119;MUSICAL SYMBOL FOUR-LINE STAFF;So;0;L;;;;;N;;;;; +1D11A;MUSICAL SYMBOL FIVE-LINE STAFF;So;0;L;;;;;N;;;;; +1D11B;MUSICAL SYMBOL SIX-LINE STAFF;So;0;L;;;;;N;;;;; +1D11C;MUSICAL SYMBOL SIX-STRING FRETBOARD;So;0;L;;;;;N;;;;; +1D11D;MUSICAL SYMBOL FOUR-STRING FRETBOARD;So;0;L;;;;;N;;;;; +1D11E;MUSICAL SYMBOL G CLEF;So;0;L;;;;;N;;;;; +1D11F;MUSICAL SYMBOL G CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;; +1D120;MUSICAL SYMBOL G CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;; +1D121;MUSICAL SYMBOL C CLEF;So;0;L;;;;;N;;;;; +1D122;MUSICAL SYMBOL F CLEF;So;0;L;;;;;N;;;;; +1D123;MUSICAL SYMBOL F CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;; +1D124;MUSICAL SYMBOL F CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;; +1D125;MUSICAL SYMBOL DRUM CLEF-1;So;0;L;;;;;N;;;;; +1D126;MUSICAL SYMBOL DRUM CLEF-2;So;0;L;;;;;N;;;;; +1D129;MUSICAL SYMBOL MULTIPLE MEASURE REST;So;0;L;;;;;N;;;;; +1D12A;MUSICAL SYMBOL DOUBLE SHARP;So;0;L;;;;;N;;;;; +1D12B;MUSICAL SYMBOL DOUBLE FLAT;So;0;L;;;;;N;;;;; +1D12C;MUSICAL SYMBOL FLAT UP;So;0;L;;;;;N;;;;; +1D12D;MUSICAL SYMBOL FLAT DOWN;So;0;L;;;;;N;;;;; +1D12E;MUSICAL SYMBOL NATURAL UP;So;0;L;;;;;N;;;;; +1D12F;MUSICAL SYMBOL NATURAL DOWN;So;0;L;;;;;N;;;;; +1D130;MUSICAL SYMBOL SHARP UP;So;0;L;;;;;N;;;;; +1D131;MUSICAL SYMBOL SHARP DOWN;So;0;L;;;;;N;;;;; +1D132;MUSICAL SYMBOL QUARTER TONE SHARP;So;0;L;;;;;N;;;;; +1D133;MUSICAL SYMBOL QUARTER TONE FLAT;So;0;L;;;;;N;;;;; +1D134;MUSICAL SYMBOL COMMON TIME;So;0;L;;;;;N;;;;; +1D135;MUSICAL SYMBOL CUT TIME;So;0;L;;;;;N;;;;; +1D136;MUSICAL SYMBOL OTTAVA ALTA;So;0;L;;;;;N;;;;; +1D137;MUSICAL SYMBOL OTTAVA BASSA;So;0;L;;;;;N;;;;; +1D138;MUSICAL SYMBOL QUINDICESIMA ALTA;So;0;L;;;;;N;;;;; +1D139;MUSICAL SYMBOL QUINDICESIMA BASSA;So;0;L;;;;;N;;;;; +1D13A;MUSICAL SYMBOL MULTI REST;So;0;L;;;;;N;;;;; +1D13B;MUSICAL SYMBOL WHOLE REST;So;0;L;;;;;N;;;;; +1D13C;MUSICAL SYMBOL HALF REST;So;0;L;;;;;N;;;;; +1D13D;MUSICAL SYMBOL QUARTER REST;So;0;L;;;;;N;;;;; +1D13E;MUSICAL SYMBOL EIGHTH REST;So;0;L;;;;;N;;;;; +1D13F;MUSICAL SYMBOL SIXTEENTH REST;So;0;L;;;;;N;;;;; +1D140;MUSICAL SYMBOL THIRTY-SECOND REST;So;0;L;;;;;N;;;;; +1D141;MUSICAL SYMBOL SIXTY-FOURTH REST;So;0;L;;;;;N;;;;; +1D142;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH REST;So;0;L;;;;;N;;;;; +1D143;MUSICAL SYMBOL X NOTEHEAD;So;0;L;;;;;N;;;;; +1D144;MUSICAL SYMBOL PLUS NOTEHEAD;So;0;L;;;;;N;;;;; +1D145;MUSICAL SYMBOL CIRCLE X NOTEHEAD;So;0;L;;;;;N;;;;; +1D146;MUSICAL SYMBOL SQUARE NOTEHEAD WHITE;So;0;L;;;;;N;;;;; +1D147;MUSICAL SYMBOL SQUARE NOTEHEAD BLACK;So;0;L;;;;;N;;;;; +1D148;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP WHITE;So;0;L;;;;;N;;;;; +1D149;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP BLACK;So;0;L;;;;;N;;;;; +1D14A;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT WHITE;So;0;L;;;;;N;;;;; +1D14B;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT BLACK;So;0;L;;;;;N;;;;; +1D14C;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT WHITE;So;0;L;;;;;N;;;;; +1D14D;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT BLACK;So;0;L;;;;;N;;;;; +1D14E;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;; +1D14F;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;; +1D150;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT WHITE;So;0;L;;;;;N;;;;; +1D151;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT BLACK;So;0;L;;;;;N;;;;; +1D152;MUSICAL SYMBOL MOON NOTEHEAD WHITE;So;0;L;;;;;N;;;;; +1D153;MUSICAL SYMBOL MOON NOTEHEAD BLACK;So;0;L;;;;;N;;;;; +1D154;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;; +1D155;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;; +1D156;MUSICAL SYMBOL PARENTHESIS NOTEHEAD;So;0;L;;;;;N;;;;; +1D157;MUSICAL SYMBOL VOID NOTEHEAD;So;0;L;;;;;N;;;;; +1D158;MUSICAL SYMBOL NOTEHEAD BLACK;So;0;L;;;;;N;;;;; +1D159;MUSICAL SYMBOL NULL NOTEHEAD;So;0;L;;;;;N;;;;; +1D15A;MUSICAL SYMBOL CLUSTER NOTEHEAD WHITE;So;0;L;;;;;N;;;;; +1D15B;MUSICAL SYMBOL CLUSTER NOTEHEAD BLACK;So;0;L;;;;;N;;;;; +1D15C;MUSICAL SYMBOL BREVE;So;0;L;;;;;N;;;;; +1D15D;MUSICAL SYMBOL WHOLE NOTE;So;0;L;;;;;N;;;;; +1D15E;MUSICAL SYMBOL HALF NOTE;So;0;L;1D157 1D165;;;;N;;;;; +1D15F;MUSICAL SYMBOL QUARTER NOTE;So;0;L;1D158 1D165;;;;N;;;;; +1D160;MUSICAL SYMBOL EIGHTH NOTE;So;0;L;1D15F 1D16E;;;;N;;;;; +1D161;MUSICAL SYMBOL SIXTEENTH NOTE;So;0;L;1D15F 1D16F;;;;N;;;;; +1D162;MUSICAL SYMBOL THIRTY-SECOND NOTE;So;0;L;1D15F 1D170;;;;N;;;;; +1D163;MUSICAL SYMBOL SIXTY-FOURTH NOTE;So;0;L;1D15F 1D171;;;;N;;;;; +1D164;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE;So;0;L;1D15F 1D172;;;;N;;;;; +1D165;MUSICAL SYMBOL COMBINING STEM;Mc;216;L;;;;;N;;;;; +1D166;MUSICAL SYMBOL COMBINING SPRECHGESANG STEM;Mc;216;L;;;;;N;;;;; +1D167;MUSICAL SYMBOL COMBINING TREMOLO-1;Mn;1;NSM;;;;;N;;;;; +1D168;MUSICAL SYMBOL COMBINING TREMOLO-2;Mn;1;NSM;;;;;N;;;;; +1D169;MUSICAL SYMBOL COMBINING TREMOLO-3;Mn;1;NSM;;;;;N;;;;; +1D16A;MUSICAL SYMBOL FINGERED TREMOLO-1;So;0;L;;;;;N;;;;; +1D16B;MUSICAL SYMBOL FINGERED TREMOLO-2;So;0;L;;;;;N;;;;; +1D16C;MUSICAL SYMBOL FINGERED TREMOLO-3;So;0;L;;;;;N;;;;; +1D16D;MUSICAL SYMBOL COMBINING AUGMENTATION DOT;Mc;226;L;;;;;N;;;;; +1D16E;MUSICAL SYMBOL COMBINING FLAG-1;Mc;216;L;;;;;N;;;;; +1D16F;MUSICAL SYMBOL COMBINING FLAG-2;Mc;216;L;;;;;N;;;;; +1D170;MUSICAL SYMBOL COMBINING FLAG-3;Mc;216;L;;;;;N;;;;; +1D171;MUSICAL SYMBOL COMBINING FLAG-4;Mc;216;L;;;;;N;;;;; +1D172;MUSICAL SYMBOL COMBINING FLAG-5;Mc;216;L;;;;;N;;;;; +1D173;MUSICAL SYMBOL BEGIN BEAM;Cf;0;BN;;;;;N;;;;; +1D174;MUSICAL SYMBOL END BEAM;Cf;0;BN;;;;;N;;;;; +1D175;MUSICAL SYMBOL BEGIN TIE;Cf;0;BN;;;;;N;;;;; +1D176;MUSICAL SYMBOL END TIE;Cf;0;BN;;;;;N;;;;; +1D177;MUSICAL SYMBOL BEGIN SLUR;Cf;0;BN;;;;;N;;;;; +1D178;MUSICAL SYMBOL END SLUR;Cf;0;BN;;;;;N;;;;; +1D179;MUSICAL SYMBOL BEGIN PHRASE;Cf;0;BN;;;;;N;;;;; +1D17A;MUSICAL SYMBOL END PHRASE;Cf;0;BN;;;;;N;;;;; +1D17B;MUSICAL SYMBOL COMBINING ACCENT;Mn;220;NSM;;;;;N;;;;; +1D17C;MUSICAL SYMBOL COMBINING STACCATO;Mn;220;NSM;;;;;N;;;;; +1D17D;MUSICAL SYMBOL COMBINING TENUTO;Mn;220;NSM;;;;;N;;;;; +1D17E;MUSICAL SYMBOL COMBINING STACCATISSIMO;Mn;220;NSM;;;;;N;;;;; +1D17F;MUSICAL SYMBOL COMBINING MARCATO;Mn;220;NSM;;;;;N;;;;; +1D180;MUSICAL SYMBOL COMBINING MARCATO-STACCATO;Mn;220;NSM;;;;;N;;;;; +1D181;MUSICAL SYMBOL COMBINING ACCENT-STACCATO;Mn;220;NSM;;;;;N;;;;; +1D182;MUSICAL SYMBOL COMBINING LOURE;Mn;220;NSM;;;;;N;;;;; +1D183;MUSICAL SYMBOL ARPEGGIATO UP;So;0;L;;;;;N;;;;; +1D184;MUSICAL SYMBOL ARPEGGIATO DOWN;So;0;L;;;;;N;;;;; +1D185;MUSICAL SYMBOL COMBINING DOIT;Mn;230;NSM;;;;;N;;;;; +1D186;MUSICAL SYMBOL COMBINING RIP;Mn;230;NSM;;;;;N;;;;; +1D187;MUSICAL SYMBOL COMBINING FLIP;Mn;230;NSM;;;;;N;;;;; +1D188;MUSICAL SYMBOL COMBINING SMEAR;Mn;230;NSM;;;;;N;;;;; +1D189;MUSICAL SYMBOL COMBINING BEND;Mn;230;NSM;;;;;N;;;;; +1D18A;MUSICAL SYMBOL COMBINING DOUBLE TONGUE;Mn;220;NSM;;;;;N;;;;; +1D18B;MUSICAL SYMBOL COMBINING TRIPLE TONGUE;Mn;220;NSM;;;;;N;;;;; +1D18C;MUSICAL SYMBOL RINFORZANDO;So;0;L;;;;;N;;;;; +1D18D;MUSICAL SYMBOL SUBITO;So;0;L;;;;;N;;;;; +1D18E;MUSICAL SYMBOL Z;So;0;L;;;;;N;;;;; +1D18F;MUSICAL SYMBOL PIANO;So;0;L;;;;;N;;;;; +1D190;MUSICAL SYMBOL MEZZO;So;0;L;;;;;N;;;;; +1D191;MUSICAL SYMBOL FORTE;So;0;L;;;;;N;;;;; +1D192;MUSICAL SYMBOL CRESCENDO;So;0;L;;;;;N;;;;; +1D193;MUSICAL SYMBOL DECRESCENDO;So;0;L;;;;;N;;;;; +1D194;MUSICAL SYMBOL GRACE NOTE SLASH;So;0;L;;;;;N;;;;; +1D195;MUSICAL SYMBOL GRACE NOTE NO SLASH;So;0;L;;;;;N;;;;; +1D196;MUSICAL SYMBOL TR;So;0;L;;;;;N;;;;; +1D197;MUSICAL SYMBOL TURN;So;0;L;;;;;N;;;;; +1D198;MUSICAL SYMBOL INVERTED TURN;So;0;L;;;;;N;;;;; +1D199;MUSICAL SYMBOL TURN SLASH;So;0;L;;;;;N;;;;; +1D19A;MUSICAL SYMBOL TURN UP;So;0;L;;;;;N;;;;; +1D19B;MUSICAL SYMBOL ORNAMENT STROKE-1;So;0;L;;;;;N;;;;; +1D19C;MUSICAL SYMBOL ORNAMENT STROKE-2;So;0;L;;;;;N;;;;; +1D19D;MUSICAL SYMBOL ORNAMENT STROKE-3;So;0;L;;;;;N;;;;; +1D19E;MUSICAL SYMBOL ORNAMENT STROKE-4;So;0;L;;;;;N;;;;; +1D19F;MUSICAL SYMBOL ORNAMENT STROKE-5;So;0;L;;;;;N;;;;; +1D1A0;MUSICAL SYMBOL ORNAMENT STROKE-6;So;0;L;;;;;N;;;;; +1D1A1;MUSICAL SYMBOL ORNAMENT STROKE-7;So;0;L;;;;;N;;;;; +1D1A2;MUSICAL SYMBOL ORNAMENT STROKE-8;So;0;L;;;;;N;;;;; +1D1A3;MUSICAL SYMBOL ORNAMENT STROKE-9;So;0;L;;;;;N;;;;; +1D1A4;MUSICAL SYMBOL ORNAMENT STROKE-10;So;0;L;;;;;N;;;;; +1D1A5;MUSICAL SYMBOL ORNAMENT STROKE-11;So;0;L;;;;;N;;;;; +1D1A6;MUSICAL SYMBOL HAUPTSTIMME;So;0;L;;;;;N;;;;; +1D1A7;MUSICAL SYMBOL NEBENSTIMME;So;0;L;;;;;N;;;;; +1D1A8;MUSICAL SYMBOL END OF STIMME;So;0;L;;;;;N;;;;; +1D1A9;MUSICAL SYMBOL DEGREE SLASH;So;0;L;;;;;N;;;;; +1D1AA;MUSICAL SYMBOL COMBINING DOWN BOW;Mn;230;NSM;;;;;N;;;;; +1D1AB;MUSICAL SYMBOL COMBINING UP BOW;Mn;230;NSM;;;;;N;;;;; +1D1AC;MUSICAL SYMBOL COMBINING HARMONIC;Mn;230;NSM;;;;;N;;;;; +1D1AD;MUSICAL SYMBOL COMBINING SNAP PIZZICATO;Mn;230;NSM;;;;;N;;;;; +1D1AE;MUSICAL SYMBOL PEDAL MARK;So;0;L;;;;;N;;;;; +1D1AF;MUSICAL SYMBOL PEDAL UP MARK;So;0;L;;;;;N;;;;; +1D1B0;MUSICAL SYMBOL HALF PEDAL MARK;So;0;L;;;;;N;;;;; +1D1B1;MUSICAL SYMBOL GLISSANDO UP;So;0;L;;;;;N;;;;; +1D1B2;MUSICAL SYMBOL GLISSANDO DOWN;So;0;L;;;;;N;;;;; +1D1B3;MUSICAL SYMBOL WITH FINGERNAILS;So;0;L;;;;;N;;;;; +1D1B4;MUSICAL SYMBOL DAMP;So;0;L;;;;;N;;;;; +1D1B5;MUSICAL SYMBOL DAMP ALL;So;0;L;;;;;N;;;;; +1D1B6;MUSICAL SYMBOL MAXIMA;So;0;L;;;;;N;;;;; +1D1B7;MUSICAL SYMBOL LONGA;So;0;L;;;;;N;;;;; +1D1B8;MUSICAL SYMBOL BREVIS;So;0;L;;;;;N;;;;; +1D1B9;MUSICAL SYMBOL SEMIBREVIS WHITE;So;0;L;;;;;N;;;;; +1D1BA;MUSICAL SYMBOL SEMIBREVIS BLACK;So;0;L;;;;;N;;;;; +1D1BB;MUSICAL SYMBOL MINIMA;So;0;L;1D1B9 1D165;;;;N;;;;; +1D1BC;MUSICAL SYMBOL MINIMA BLACK;So;0;L;1D1BA 1D165;;;;N;;;;; +1D1BD;MUSICAL SYMBOL SEMIMINIMA WHITE;So;0;L;1D1BB 1D16E;;;;N;;;;; +1D1BE;MUSICAL SYMBOL SEMIMINIMA BLACK;So;0;L;1D1BC 1D16E;;;;N;;;;; +1D1BF;MUSICAL SYMBOL FUSA WHITE;So;0;L;1D1BB 1D16F;;;;N;;;;; +1D1C0;MUSICAL SYMBOL FUSA BLACK;So;0;L;1D1BC 1D16F;;;;N;;;;; +1D1C1;MUSICAL SYMBOL LONGA PERFECTA REST;So;0;L;;;;;N;;;;; +1D1C2;MUSICAL SYMBOL LONGA IMPERFECTA REST;So;0;L;;;;;N;;;;; +1D1C3;MUSICAL SYMBOL BREVIS REST;So;0;L;;;;;N;;;;; +1D1C4;MUSICAL SYMBOL SEMIBREVIS REST;So;0;L;;;;;N;;;;; +1D1C5;MUSICAL SYMBOL MINIMA REST;So;0;L;;;;;N;;;;; +1D1C6;MUSICAL SYMBOL SEMIMINIMA REST;So;0;L;;;;;N;;;;; +1D1C7;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;; +1D1C8;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;; +1D1C9;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;; +1D1CA;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;; +1D1CB;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;; +1D1CC;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;; +1D1CD;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-2;So;0;L;;;;;N;;;;; +1D1CE;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-3;So;0;L;;;;;N;;;;; +1D1CF;MUSICAL SYMBOL CROIX;So;0;L;;;;;N;;;;; +1D1D0;MUSICAL SYMBOL GREGORIAN C CLEF;So;0;L;;;;;N;;;;; +1D1D1;MUSICAL SYMBOL GREGORIAN F CLEF;So;0;L;;;;;N;;;;; +1D1D2;MUSICAL SYMBOL SQUARE B;So;0;L;;;;;N;;;;; +1D1D3;MUSICAL SYMBOL VIRGA;So;0;L;;;;;N;;;;; +1D1D4;MUSICAL SYMBOL PODATUS;So;0;L;;;;;N;;;;; +1D1D5;MUSICAL SYMBOL CLIVIS;So;0;L;;;;;N;;;;; +1D1D6;MUSICAL SYMBOL SCANDICUS;So;0;L;;;;;N;;;;; +1D1D7;MUSICAL SYMBOL CLIMACUS;So;0;L;;;;;N;;;;; +1D1D8;MUSICAL SYMBOL TORCULUS;So;0;L;;;;;N;;;;; +1D1D9;MUSICAL SYMBOL PORRECTUS;So;0;L;;;;;N;;;;; +1D1DA;MUSICAL SYMBOL PORRECTUS FLEXUS;So;0;L;;;;;N;;;;; +1D1DB;MUSICAL SYMBOL SCANDICUS FLEXUS;So;0;L;;;;;N;;;;; +1D1DC;MUSICAL SYMBOL TORCULUS RESUPINUS;So;0;L;;;;;N;;;;; +1D1DD;MUSICAL SYMBOL PES SUBPUNCTIS;So;0;L;;;;;N;;;;; +1D1DE;MUSICAL SYMBOL KIEVAN C CLEF;So;0;L;;;;;N;;;;; +1D1DF;MUSICAL SYMBOL KIEVAN END OF PIECE;So;0;L;;;;;N;;;;; +1D1E0;MUSICAL SYMBOL KIEVAN FINAL NOTE;So;0;L;;;;;N;;;;; +1D1E1;MUSICAL SYMBOL KIEVAN RECITATIVE MARK;So;0;L;;;;;N;;;;; +1D1E2;MUSICAL SYMBOL KIEVAN WHOLE NOTE;So;0;L;;;;;N;;;;; +1D1E3;MUSICAL SYMBOL KIEVAN HALF NOTE;So;0;L;;;;;N;;;;; +1D1E4;MUSICAL SYMBOL KIEVAN QUARTER NOTE STEM DOWN;So;0;L;;;;;N;;;;; +1D1E5;MUSICAL SYMBOL KIEVAN QUARTER NOTE STEM UP;So;0;L;;;;;N;;;;; +1D1E6;MUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM DOWN;So;0;L;;;;;N;;;;; +1D1E7;MUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM UP;So;0;L;;;;;N;;;;; +1D1E8;MUSICAL SYMBOL KIEVAN FLAT SIGN;So;0;L;;;;;N;;;;; +1D1E9;MUSICAL SYMBOL SORI;So;0;ON;;;;;N;;;;; +1D1EA;MUSICAL SYMBOL KORON;So;0;ON;;;;;N;;;;; +1D200;GREEK VOCAL NOTATION SYMBOL-1;So;0;ON;;;;;N;;;;; +1D201;GREEK VOCAL NOTATION SYMBOL-2;So;0;ON;;;;;N;;;;; +1D202;GREEK VOCAL NOTATION SYMBOL-3;So;0;ON;;;;;N;;;;; +1D203;GREEK VOCAL NOTATION SYMBOL-4;So;0;ON;;;;;N;;;;; +1D204;GREEK VOCAL NOTATION SYMBOL-5;So;0;ON;;;;;N;;;;; +1D205;GREEK VOCAL NOTATION SYMBOL-6;So;0;ON;;;;;N;;;;; +1D206;GREEK VOCAL NOTATION SYMBOL-7;So;0;ON;;;;;N;;;;; +1D207;GREEK VOCAL NOTATION SYMBOL-8;So;0;ON;;;;;N;;;;; +1D208;GREEK VOCAL NOTATION SYMBOL-9;So;0;ON;;;;;N;;;;; +1D209;GREEK VOCAL NOTATION SYMBOL-10;So;0;ON;;;;;N;;;;; +1D20A;GREEK VOCAL NOTATION SYMBOL-11;So;0;ON;;;;;N;;;;; +1D20B;GREEK VOCAL NOTATION SYMBOL-12;So;0;ON;;;;;N;;;;; +1D20C;GREEK VOCAL NOTATION SYMBOL-13;So;0;ON;;;;;N;;;;; +1D20D;GREEK VOCAL NOTATION SYMBOL-14;So;0;ON;;;;;N;;;;; +1D20E;GREEK VOCAL NOTATION SYMBOL-15;So;0;ON;;;;;N;;;;; +1D20F;GREEK VOCAL NOTATION SYMBOL-16;So;0;ON;;;;;N;;;;; +1D210;GREEK VOCAL NOTATION SYMBOL-17;So;0;ON;;;;;N;;;;; +1D211;GREEK VOCAL NOTATION SYMBOL-18;So;0;ON;;;;;N;;;;; +1D212;GREEK VOCAL NOTATION SYMBOL-19;So;0;ON;;;;;N;;;;; +1D213;GREEK VOCAL NOTATION SYMBOL-20;So;0;ON;;;;;N;;;;; +1D214;GREEK VOCAL NOTATION SYMBOL-21;So;0;ON;;;;;N;;;;; +1D215;GREEK VOCAL NOTATION SYMBOL-22;So;0;ON;;;;;N;;;;; +1D216;GREEK VOCAL NOTATION SYMBOL-23;So;0;ON;;;;;N;;;;; +1D217;GREEK VOCAL NOTATION SYMBOL-24;So;0;ON;;;;;N;;;;; +1D218;GREEK VOCAL NOTATION SYMBOL-50;So;0;ON;;;;;N;;;;; +1D219;GREEK VOCAL NOTATION SYMBOL-51;So;0;ON;;;;;N;;;;; +1D21A;GREEK VOCAL NOTATION SYMBOL-52;So;0;ON;;;;;N;;;;; +1D21B;GREEK VOCAL NOTATION SYMBOL-53;So;0;ON;;;;;N;;;;; +1D21C;GREEK VOCAL NOTATION SYMBOL-54;So;0;ON;;;;;N;;;;; +1D21D;GREEK INSTRUMENTAL NOTATION SYMBOL-1;So;0;ON;;;;;N;;;;; +1D21E;GREEK INSTRUMENTAL NOTATION SYMBOL-2;So;0;ON;;;;;N;;;;; +1D21F;GREEK INSTRUMENTAL NOTATION SYMBOL-4;So;0;ON;;;;;N;;;;; +1D220;GREEK INSTRUMENTAL NOTATION SYMBOL-5;So;0;ON;;;;;N;;;;; +1D221;GREEK INSTRUMENTAL NOTATION SYMBOL-7;So;0;ON;;;;;N;;;;; +1D222;GREEK INSTRUMENTAL NOTATION SYMBOL-8;So;0;ON;;;;;N;;;;; +1D223;GREEK INSTRUMENTAL NOTATION SYMBOL-11;So;0;ON;;;;;N;;;;; +1D224;GREEK INSTRUMENTAL NOTATION SYMBOL-12;So;0;ON;;;;;N;;;;; +1D225;GREEK INSTRUMENTAL NOTATION SYMBOL-13;So;0;ON;;;;;N;;;;; +1D226;GREEK INSTRUMENTAL NOTATION SYMBOL-14;So;0;ON;;;;;N;;;;; +1D227;GREEK INSTRUMENTAL NOTATION SYMBOL-17;So;0;ON;;;;;N;;;;; +1D228;GREEK INSTRUMENTAL NOTATION SYMBOL-18;So;0;ON;;;;;N;;;;; +1D229;GREEK INSTRUMENTAL NOTATION SYMBOL-19;So;0;ON;;;;;N;;;;; +1D22A;GREEK INSTRUMENTAL NOTATION SYMBOL-23;So;0;ON;;;;;N;;;;; +1D22B;GREEK INSTRUMENTAL NOTATION SYMBOL-24;So;0;ON;;;;;N;;;;; +1D22C;GREEK INSTRUMENTAL NOTATION SYMBOL-25;So;0;ON;;;;;N;;;;; +1D22D;GREEK INSTRUMENTAL NOTATION SYMBOL-26;So;0;ON;;;;;N;;;;; +1D22E;GREEK INSTRUMENTAL NOTATION SYMBOL-27;So;0;ON;;;;;N;;;;; +1D22F;GREEK INSTRUMENTAL NOTATION SYMBOL-29;So;0;ON;;;;;N;;;;; +1D230;GREEK INSTRUMENTAL NOTATION SYMBOL-30;So;0;ON;;;;;N;;;;; +1D231;GREEK INSTRUMENTAL NOTATION SYMBOL-32;So;0;ON;;;;;N;;;;; +1D232;GREEK INSTRUMENTAL NOTATION SYMBOL-36;So;0;ON;;;;;N;;;;; +1D233;GREEK INSTRUMENTAL NOTATION SYMBOL-37;So;0;ON;;;;;N;;;;; +1D234;GREEK INSTRUMENTAL NOTATION SYMBOL-38;So;0;ON;;;;;N;;;;; +1D235;GREEK INSTRUMENTAL NOTATION SYMBOL-39;So;0;ON;;;;;N;;;;; +1D236;GREEK INSTRUMENTAL NOTATION SYMBOL-40;So;0;ON;;;;;N;;;;; +1D237;GREEK INSTRUMENTAL NOTATION SYMBOL-42;So;0;ON;;;;;N;;;;; +1D238;GREEK INSTRUMENTAL NOTATION SYMBOL-43;So;0;ON;;;;;N;;;;; +1D239;GREEK INSTRUMENTAL NOTATION SYMBOL-45;So;0;ON;;;;;N;;;;; +1D23A;GREEK INSTRUMENTAL NOTATION SYMBOL-47;So;0;ON;;;;;N;;;;; +1D23B;GREEK INSTRUMENTAL NOTATION SYMBOL-48;So;0;ON;;;;;N;;;;; +1D23C;GREEK INSTRUMENTAL NOTATION SYMBOL-49;So;0;ON;;;;;N;;;;; +1D23D;GREEK INSTRUMENTAL NOTATION SYMBOL-50;So;0;ON;;;;;N;;;;; +1D23E;GREEK INSTRUMENTAL NOTATION SYMBOL-51;So;0;ON;;;;;N;;;;; +1D23F;GREEK INSTRUMENTAL NOTATION SYMBOL-52;So;0;ON;;;;;N;;;;; +1D240;GREEK INSTRUMENTAL NOTATION SYMBOL-53;So;0;ON;;;;;N;;;;; +1D241;GREEK INSTRUMENTAL NOTATION SYMBOL-54;So;0;ON;;;;;N;;;;; +1D242;COMBINING GREEK MUSICAL TRISEME;Mn;230;NSM;;;;;N;;;;; +1D243;COMBINING GREEK MUSICAL TETRASEME;Mn;230;NSM;;;;;N;;;;; +1D244;COMBINING GREEK MUSICAL PENTASEME;Mn;230;NSM;;;;;N;;;;; +1D245;GREEK MUSICAL LEIMMA;So;0;ON;;;;;N;;;;; +1D2C0;KAKTOVIK NUMERAL ZERO;No;0;L;;;;0;N;;;;; +1D2C1;KAKTOVIK NUMERAL ONE;No;0;L;;;;1;N;;;;; +1D2C2;KAKTOVIK NUMERAL TWO;No;0;L;;;;2;N;;;;; +1D2C3;KAKTOVIK NUMERAL THREE;No;0;L;;;;3;N;;;;; +1D2C4;KAKTOVIK NUMERAL FOUR;No;0;L;;;;4;N;;;;; +1D2C5;KAKTOVIK NUMERAL FIVE;No;0;L;;;;5;N;;;;; +1D2C6;KAKTOVIK NUMERAL SIX;No;0;L;;;;6;N;;;;; +1D2C7;KAKTOVIK NUMERAL SEVEN;No;0;L;;;;7;N;;;;; +1D2C8;KAKTOVIK NUMERAL EIGHT;No;0;L;;;;8;N;;;;; +1D2C9;KAKTOVIK NUMERAL NINE;No;0;L;;;;9;N;;;;; +1D2CA;KAKTOVIK NUMERAL TEN;No;0;L;;;;10;N;;;;; +1D2CB;KAKTOVIK NUMERAL ELEVEN;No;0;L;;;;11;N;;;;; +1D2CC;KAKTOVIK NUMERAL TWELVE;No;0;L;;;;12;N;;;;; +1D2CD;KAKTOVIK NUMERAL THIRTEEN;No;0;L;;;;13;N;;;;; +1D2CE;KAKTOVIK NUMERAL FOURTEEN;No;0;L;;;;14;N;;;;; +1D2CF;KAKTOVIK NUMERAL FIFTEEN;No;0;L;;;;15;N;;;;; +1D2D0;KAKTOVIK NUMERAL SIXTEEN;No;0;L;;;;16;N;;;;; +1D2D1;KAKTOVIK NUMERAL SEVENTEEN;No;0;L;;;;17;N;;;;; +1D2D2;KAKTOVIK NUMERAL EIGHTEEN;No;0;L;;;;18;N;;;;; +1D2D3;KAKTOVIK NUMERAL NINETEEN;No;0;L;;;;19;N;;;;; +1D2E0;MAYAN NUMERAL ZERO;No;0;L;;;;0;N;;;;; +1D2E1;MAYAN NUMERAL ONE;No;0;L;;;;1;N;;;;; +1D2E2;MAYAN NUMERAL TWO;No;0;L;;;;2;N;;;;; +1D2E3;MAYAN NUMERAL THREE;No;0;L;;;;3;N;;;;; +1D2E4;MAYAN NUMERAL FOUR;No;0;L;;;;4;N;;;;; +1D2E5;MAYAN NUMERAL FIVE;No;0;L;;;;5;N;;;;; +1D2E6;MAYAN NUMERAL SIX;No;0;L;;;;6;N;;;;; +1D2E7;MAYAN NUMERAL SEVEN;No;0;L;;;;7;N;;;;; +1D2E8;MAYAN NUMERAL EIGHT;No;0;L;;;;8;N;;;;; +1D2E9;MAYAN NUMERAL NINE;No;0;L;;;;9;N;;;;; +1D2EA;MAYAN NUMERAL TEN;No;0;L;;;;10;N;;;;; +1D2EB;MAYAN NUMERAL ELEVEN;No;0;L;;;;11;N;;;;; +1D2EC;MAYAN NUMERAL TWELVE;No;0;L;;;;12;N;;;;; +1D2ED;MAYAN NUMERAL THIRTEEN;No;0;L;;;;13;N;;;;; +1D2EE;MAYAN NUMERAL FOURTEEN;No;0;L;;;;14;N;;;;; +1D2EF;MAYAN NUMERAL FIFTEEN;No;0;L;;;;15;N;;;;; +1D2F0;MAYAN NUMERAL SIXTEEN;No;0;L;;;;16;N;;;;; +1D2F1;MAYAN NUMERAL SEVENTEEN;No;0;L;;;;17;N;;;;; +1D2F2;MAYAN NUMERAL EIGHTEEN;No;0;L;;;;18;N;;;;; +1D2F3;MAYAN NUMERAL NINETEEN;No;0;L;;;;19;N;;;;; +1D300;MONOGRAM FOR EARTH;So;0;ON;;;;;N;;;;; +1D301;DIGRAM FOR HEAVENLY EARTH;So;0;ON;;;;;N;;;;; +1D302;DIGRAM FOR HUMAN EARTH;So;0;ON;;;;;N;;;;; +1D303;DIGRAM FOR EARTHLY HEAVEN;So;0;ON;;;;;N;;;;; +1D304;DIGRAM FOR EARTHLY HUMAN;So;0;ON;;;;;N;;;;; +1D305;DIGRAM FOR EARTH;So;0;ON;;;;;N;;;;; +1D306;TETRAGRAM FOR CENTRE;So;0;ON;;;;;N;;;;; +1D307;TETRAGRAM FOR FULL CIRCLE;So;0;ON;;;;;N;;;;; +1D308;TETRAGRAM FOR MIRED;So;0;ON;;;;;N;;;;; +1D309;TETRAGRAM FOR BARRIER;So;0;ON;;;;;N;;;;; +1D30A;TETRAGRAM FOR KEEPING SMALL;So;0;ON;;;;;N;;;;; +1D30B;TETRAGRAM FOR CONTRARIETY;So;0;ON;;;;;N;;;;; +1D30C;TETRAGRAM FOR ASCENT;So;0;ON;;;;;N;;;;; +1D30D;TETRAGRAM FOR OPPOSITION;So;0;ON;;;;;N;;;;; +1D30E;TETRAGRAM FOR BRANCHING OUT;So;0;ON;;;;;N;;;;; +1D30F;TETRAGRAM FOR DEFECTIVENESS OR DISTORTION;So;0;ON;;;;;N;;;;; +1D310;TETRAGRAM FOR DIVERGENCE;So;0;ON;;;;;N;;;;; +1D311;TETRAGRAM FOR YOUTHFULNESS;So;0;ON;;;;;N;;;;; +1D312;TETRAGRAM FOR INCREASE;So;0;ON;;;;;N;;;;; +1D313;TETRAGRAM FOR PENETRATION;So;0;ON;;;;;N;;;;; +1D314;TETRAGRAM FOR REACH;So;0;ON;;;;;N;;;;; +1D315;TETRAGRAM FOR CONTACT;So;0;ON;;;;;N;;;;; +1D316;TETRAGRAM FOR HOLDING BACK;So;0;ON;;;;;N;;;;; +1D317;TETRAGRAM FOR WAITING;So;0;ON;;;;;N;;;;; +1D318;TETRAGRAM FOR FOLLOWING;So;0;ON;;;;;N;;;;; +1D319;TETRAGRAM FOR ADVANCE;So;0;ON;;;;;N;;;;; +1D31A;TETRAGRAM FOR RELEASE;So;0;ON;;;;;N;;;;; +1D31B;TETRAGRAM FOR RESISTANCE;So;0;ON;;;;;N;;;;; +1D31C;TETRAGRAM FOR EASE;So;0;ON;;;;;N;;;;; +1D31D;TETRAGRAM FOR JOY;So;0;ON;;;;;N;;;;; +1D31E;TETRAGRAM FOR CONTENTION;So;0;ON;;;;;N;;;;; +1D31F;TETRAGRAM FOR ENDEAVOUR;So;0;ON;;;;;N;;;;; +1D320;TETRAGRAM FOR DUTIES;So;0;ON;;;;;N;;;;; +1D321;TETRAGRAM FOR CHANGE;So;0;ON;;;;;N;;;;; +1D322;TETRAGRAM FOR DECISIVENESS;So;0;ON;;;;;N;;;;; +1D323;TETRAGRAM FOR BOLD RESOLUTION;So;0;ON;;;;;N;;;;; +1D324;TETRAGRAM FOR PACKING;So;0;ON;;;;;N;;;;; +1D325;TETRAGRAM FOR LEGION;So;0;ON;;;;;N;;;;; +1D326;TETRAGRAM FOR CLOSENESS;So;0;ON;;;;;N;;;;; +1D327;TETRAGRAM FOR KINSHIP;So;0;ON;;;;;N;;;;; +1D328;TETRAGRAM FOR GATHERING;So;0;ON;;;;;N;;;;; +1D329;TETRAGRAM FOR STRENGTH;So;0;ON;;;;;N;;;;; +1D32A;TETRAGRAM FOR PURITY;So;0;ON;;;;;N;;;;; +1D32B;TETRAGRAM FOR FULLNESS;So;0;ON;;;;;N;;;;; +1D32C;TETRAGRAM FOR RESIDENCE;So;0;ON;;;;;N;;;;; +1D32D;TETRAGRAM FOR LAW OR MODEL;So;0;ON;;;;;N;;;;; +1D32E;TETRAGRAM FOR RESPONSE;So;0;ON;;;;;N;;;;; +1D32F;TETRAGRAM FOR GOING TO MEET;So;0;ON;;;;;N;;;;; +1D330;TETRAGRAM FOR ENCOUNTERS;So;0;ON;;;;;N;;;;; +1D331;TETRAGRAM FOR STOVE;So;0;ON;;;;;N;;;;; +1D332;TETRAGRAM FOR GREATNESS;So;0;ON;;;;;N;;;;; +1D333;TETRAGRAM FOR ENLARGEMENT;So;0;ON;;;;;N;;;;; +1D334;TETRAGRAM FOR PATTERN;So;0;ON;;;;;N;;;;; +1D335;TETRAGRAM FOR RITUAL;So;0;ON;;;;;N;;;;; +1D336;TETRAGRAM FOR FLIGHT;So;0;ON;;;;;N;;;;; +1D337;TETRAGRAM FOR VASTNESS OR WASTING;So;0;ON;;;;;N;;;;; +1D338;TETRAGRAM FOR CONSTANCY;So;0;ON;;;;;N;;;;; +1D339;TETRAGRAM FOR MEASURE;So;0;ON;;;;;N;;;;; +1D33A;TETRAGRAM FOR ETERNITY;So;0;ON;;;;;N;;;;; +1D33B;TETRAGRAM FOR UNITY;So;0;ON;;;;;N;;;;; +1D33C;TETRAGRAM FOR DIMINISHMENT;So;0;ON;;;;;N;;;;; +1D33D;TETRAGRAM FOR CLOSED MOUTH;So;0;ON;;;;;N;;;;; +1D33E;TETRAGRAM FOR GUARDEDNESS;So;0;ON;;;;;N;;;;; +1D33F;TETRAGRAM FOR GATHERING IN;So;0;ON;;;;;N;;;;; +1D340;TETRAGRAM FOR MASSING;So;0;ON;;;;;N;;;;; +1D341;TETRAGRAM FOR ACCUMULATION;So;0;ON;;;;;N;;;;; +1D342;TETRAGRAM FOR EMBELLISHMENT;So;0;ON;;;;;N;;;;; +1D343;TETRAGRAM FOR DOUBT;So;0;ON;;;;;N;;;;; +1D344;TETRAGRAM FOR WATCH;So;0;ON;;;;;N;;;;; +1D345;TETRAGRAM FOR SINKING;So;0;ON;;;;;N;;;;; +1D346;TETRAGRAM FOR INNER;So;0;ON;;;;;N;;;;; +1D347;TETRAGRAM FOR DEPARTURE;So;0;ON;;;;;N;;;;; +1D348;TETRAGRAM FOR DARKENING;So;0;ON;;;;;N;;;;; +1D349;TETRAGRAM FOR DIMMING;So;0;ON;;;;;N;;;;; +1D34A;TETRAGRAM FOR EXHAUSTION;So;0;ON;;;;;N;;;;; +1D34B;TETRAGRAM FOR SEVERANCE;So;0;ON;;;;;N;;;;; +1D34C;TETRAGRAM FOR STOPPAGE;So;0;ON;;;;;N;;;;; +1D34D;TETRAGRAM FOR HARDNESS;So;0;ON;;;;;N;;;;; +1D34E;TETRAGRAM FOR COMPLETION;So;0;ON;;;;;N;;;;; +1D34F;TETRAGRAM FOR CLOSURE;So;0;ON;;;;;N;;;;; +1D350;TETRAGRAM FOR FAILURE;So;0;ON;;;;;N;;;;; +1D351;TETRAGRAM FOR AGGRAVATION;So;0;ON;;;;;N;;;;; +1D352;TETRAGRAM FOR COMPLIANCE;So;0;ON;;;;;N;;;;; +1D353;TETRAGRAM FOR ON THE VERGE;So;0;ON;;;;;N;;;;; +1D354;TETRAGRAM FOR DIFFICULTIES;So;0;ON;;;;;N;;;;; +1D355;TETRAGRAM FOR LABOURING;So;0;ON;;;;;N;;;;; +1D356;TETRAGRAM FOR FOSTERING;So;0;ON;;;;;N;;;;; +1D360;COUNTING ROD UNIT DIGIT ONE;No;0;L;;;;1;N;;;;; +1D361;COUNTING ROD UNIT DIGIT TWO;No;0;L;;;;2;N;;;;; +1D362;COUNTING ROD UNIT DIGIT THREE;No;0;L;;;;3;N;;;;; +1D363;COUNTING ROD UNIT DIGIT FOUR;No;0;L;;;;4;N;;;;; +1D364;COUNTING ROD UNIT DIGIT FIVE;No;0;L;;;;5;N;;;;; +1D365;COUNTING ROD UNIT DIGIT SIX;No;0;L;;;;6;N;;;;; +1D366;COUNTING ROD UNIT DIGIT SEVEN;No;0;L;;;;7;N;;;;; +1D367;COUNTING ROD UNIT DIGIT EIGHT;No;0;L;;;;8;N;;;;; +1D368;COUNTING ROD UNIT DIGIT NINE;No;0;L;;;;9;N;;;;; +1D369;COUNTING ROD TENS DIGIT ONE;No;0;L;;;;10;N;;;;; +1D36A;COUNTING ROD TENS DIGIT TWO;No;0;L;;;;20;N;;;;; +1D36B;COUNTING ROD TENS DIGIT THREE;No;0;L;;;;30;N;;;;; +1D36C;COUNTING ROD TENS DIGIT FOUR;No;0;L;;;;40;N;;;;; +1D36D;COUNTING ROD TENS DIGIT FIVE;No;0;L;;;;50;N;;;;; +1D36E;COUNTING ROD TENS DIGIT SIX;No;0;L;;;;60;N;;;;; +1D36F;COUNTING ROD TENS DIGIT SEVEN;No;0;L;;;;70;N;;;;; +1D370;COUNTING ROD TENS DIGIT EIGHT;No;0;L;;;;80;N;;;;; +1D371;COUNTING ROD TENS DIGIT NINE;No;0;L;;;;90;N;;;;; +1D372;IDEOGRAPHIC TALLY MARK ONE;No;0;L;;;;1;N;;;;; +1D373;IDEOGRAPHIC TALLY MARK TWO;No;0;L;;;;2;N;;;;; +1D374;IDEOGRAPHIC TALLY MARK THREE;No;0;L;;;;3;N;;;;; +1D375;IDEOGRAPHIC TALLY MARK FOUR;No;0;L;;;;4;N;;;;; +1D376;IDEOGRAPHIC TALLY MARK FIVE;No;0;L;;;;5;N;;;;; +1D377;TALLY MARK ONE;No;0;L;;;;1;N;;;;; +1D378;TALLY MARK FIVE;No;0;L;;;;5;N;;;;; +1D400;MATHEMATICAL BOLD CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D401;MATHEMATICAL BOLD CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D402;MATHEMATICAL BOLD CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D403;MATHEMATICAL BOLD CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D404;MATHEMATICAL BOLD CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D405;MATHEMATICAL BOLD CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D406;MATHEMATICAL BOLD CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D407;MATHEMATICAL BOLD CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D408;MATHEMATICAL BOLD CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D409;MATHEMATICAL BOLD CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D40A;MATHEMATICAL BOLD CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D40B;MATHEMATICAL BOLD CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D40C;MATHEMATICAL BOLD CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D40D;MATHEMATICAL BOLD CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D40E;MATHEMATICAL BOLD CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D40F;MATHEMATICAL BOLD CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D410;MATHEMATICAL BOLD CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D411;MATHEMATICAL BOLD CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D412;MATHEMATICAL BOLD CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D413;MATHEMATICAL BOLD CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D414;MATHEMATICAL BOLD CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D415;MATHEMATICAL BOLD CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D416;MATHEMATICAL BOLD CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D417;MATHEMATICAL BOLD CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D418;MATHEMATICAL BOLD CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D419;MATHEMATICAL BOLD CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D41A;MATHEMATICAL BOLD SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D41B;MATHEMATICAL BOLD SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D41C;MATHEMATICAL BOLD SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D41D;MATHEMATICAL BOLD SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D41E;MATHEMATICAL BOLD SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D41F;MATHEMATICAL BOLD SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D420;MATHEMATICAL BOLD SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D421;MATHEMATICAL BOLD SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D422;MATHEMATICAL BOLD SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D423;MATHEMATICAL BOLD SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D424;MATHEMATICAL BOLD SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D425;MATHEMATICAL BOLD SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D426;MATHEMATICAL BOLD SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D427;MATHEMATICAL BOLD SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D428;MATHEMATICAL BOLD SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D429;MATHEMATICAL BOLD SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D42A;MATHEMATICAL BOLD SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D42B;MATHEMATICAL BOLD SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D42C;MATHEMATICAL BOLD SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D42D;MATHEMATICAL BOLD SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D42E;MATHEMATICAL BOLD SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D42F;MATHEMATICAL BOLD SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D430;MATHEMATICAL BOLD SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D431;MATHEMATICAL BOLD SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D432;MATHEMATICAL BOLD SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D433;MATHEMATICAL BOLD SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D434;MATHEMATICAL ITALIC CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D435;MATHEMATICAL ITALIC CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D436;MATHEMATICAL ITALIC CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D437;MATHEMATICAL ITALIC CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D438;MATHEMATICAL ITALIC CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D439;MATHEMATICAL ITALIC CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D43A;MATHEMATICAL ITALIC CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D43B;MATHEMATICAL ITALIC CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D43C;MATHEMATICAL ITALIC CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D43D;MATHEMATICAL ITALIC CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D43E;MATHEMATICAL ITALIC CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D43F;MATHEMATICAL ITALIC CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D440;MATHEMATICAL ITALIC CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D441;MATHEMATICAL ITALIC CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D442;MATHEMATICAL ITALIC CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D443;MATHEMATICAL ITALIC CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D444;MATHEMATICAL ITALIC CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D445;MATHEMATICAL ITALIC CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D446;MATHEMATICAL ITALIC CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D447;MATHEMATICAL ITALIC CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D448;MATHEMATICAL ITALIC CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D449;MATHEMATICAL ITALIC CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D44A;MATHEMATICAL ITALIC CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D44B;MATHEMATICAL ITALIC CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D44C;MATHEMATICAL ITALIC CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D44D;MATHEMATICAL ITALIC CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D44E;MATHEMATICAL ITALIC SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D44F;MATHEMATICAL ITALIC SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D450;MATHEMATICAL ITALIC SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D451;MATHEMATICAL ITALIC SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D452;MATHEMATICAL ITALIC SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D453;MATHEMATICAL ITALIC SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D454;MATHEMATICAL ITALIC SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D456;MATHEMATICAL ITALIC SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D457;MATHEMATICAL ITALIC SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D458;MATHEMATICAL ITALIC SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D459;MATHEMATICAL ITALIC SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D45A;MATHEMATICAL ITALIC SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D45B;MATHEMATICAL ITALIC SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D45C;MATHEMATICAL ITALIC SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D45D;MATHEMATICAL ITALIC SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D45E;MATHEMATICAL ITALIC SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D45F;MATHEMATICAL ITALIC SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D460;MATHEMATICAL ITALIC SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D461;MATHEMATICAL ITALIC SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D462;MATHEMATICAL ITALIC SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D463;MATHEMATICAL ITALIC SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D464;MATHEMATICAL ITALIC SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D465;MATHEMATICAL ITALIC SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D466;MATHEMATICAL ITALIC SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D467;MATHEMATICAL ITALIC SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D468;MATHEMATICAL BOLD ITALIC CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D469;MATHEMATICAL BOLD ITALIC CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D46A;MATHEMATICAL BOLD ITALIC CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D46B;MATHEMATICAL BOLD ITALIC CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D46C;MATHEMATICAL BOLD ITALIC CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D46D;MATHEMATICAL BOLD ITALIC CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D46E;MATHEMATICAL BOLD ITALIC CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D46F;MATHEMATICAL BOLD ITALIC CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D470;MATHEMATICAL BOLD ITALIC CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D471;MATHEMATICAL BOLD ITALIC CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D472;MATHEMATICAL BOLD ITALIC CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D473;MATHEMATICAL BOLD ITALIC CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D474;MATHEMATICAL BOLD ITALIC CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D475;MATHEMATICAL BOLD ITALIC CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D476;MATHEMATICAL BOLD ITALIC CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D477;MATHEMATICAL BOLD ITALIC CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D478;MATHEMATICAL BOLD ITALIC CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D479;MATHEMATICAL BOLD ITALIC CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D47A;MATHEMATICAL BOLD ITALIC CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D47B;MATHEMATICAL BOLD ITALIC CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D47C;MATHEMATICAL BOLD ITALIC CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D47D;MATHEMATICAL BOLD ITALIC CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D47E;MATHEMATICAL BOLD ITALIC CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D47F;MATHEMATICAL BOLD ITALIC CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D480;MATHEMATICAL BOLD ITALIC CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D481;MATHEMATICAL BOLD ITALIC CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D482;MATHEMATICAL BOLD ITALIC SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D483;MATHEMATICAL BOLD ITALIC SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D484;MATHEMATICAL BOLD ITALIC SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D485;MATHEMATICAL BOLD ITALIC SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D486;MATHEMATICAL BOLD ITALIC SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D487;MATHEMATICAL BOLD ITALIC SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D488;MATHEMATICAL BOLD ITALIC SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D489;MATHEMATICAL BOLD ITALIC SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D48A;MATHEMATICAL BOLD ITALIC SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D48B;MATHEMATICAL BOLD ITALIC SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D48C;MATHEMATICAL BOLD ITALIC SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D48D;MATHEMATICAL BOLD ITALIC SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D48E;MATHEMATICAL BOLD ITALIC SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D48F;MATHEMATICAL BOLD ITALIC SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D490;MATHEMATICAL BOLD ITALIC SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D491;MATHEMATICAL BOLD ITALIC SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D492;MATHEMATICAL BOLD ITALIC SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D493;MATHEMATICAL BOLD ITALIC SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D494;MATHEMATICAL BOLD ITALIC SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D495;MATHEMATICAL BOLD ITALIC SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D496;MATHEMATICAL BOLD ITALIC SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D497;MATHEMATICAL BOLD ITALIC SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D498;MATHEMATICAL BOLD ITALIC SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D499;MATHEMATICAL BOLD ITALIC SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D49A;MATHEMATICAL BOLD ITALIC SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D49B;MATHEMATICAL BOLD ITALIC SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D49C;MATHEMATICAL SCRIPT CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D49E;MATHEMATICAL SCRIPT CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D49F;MATHEMATICAL SCRIPT CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D4A2;MATHEMATICAL SCRIPT CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D4A5;MATHEMATICAL SCRIPT CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D4A6;MATHEMATICAL SCRIPT CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D4A9;MATHEMATICAL SCRIPT CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D4AA;MATHEMATICAL SCRIPT CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D4AB;MATHEMATICAL SCRIPT CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D4AC;MATHEMATICAL SCRIPT CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D4AE;MATHEMATICAL SCRIPT CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D4AF;MATHEMATICAL SCRIPT CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D4B0;MATHEMATICAL SCRIPT CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D4B1;MATHEMATICAL SCRIPT CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D4B2;MATHEMATICAL SCRIPT CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D4B3;MATHEMATICAL SCRIPT CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D4B4;MATHEMATICAL SCRIPT CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D4B5;MATHEMATICAL SCRIPT CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D4B6;MATHEMATICAL SCRIPT SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D4B7;MATHEMATICAL SCRIPT SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D4B8;MATHEMATICAL SCRIPT SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D4B9;MATHEMATICAL SCRIPT SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D4BB;MATHEMATICAL SCRIPT SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D4BD;MATHEMATICAL SCRIPT SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D4BE;MATHEMATICAL SCRIPT SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D4BF;MATHEMATICAL SCRIPT SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D4C0;MATHEMATICAL SCRIPT SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D4C1;MATHEMATICAL SCRIPT SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D4C2;MATHEMATICAL SCRIPT SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D4C3;MATHEMATICAL SCRIPT SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D4C5;MATHEMATICAL SCRIPT SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D4C6;MATHEMATICAL SCRIPT SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D4C7;MATHEMATICAL SCRIPT SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D4C8;MATHEMATICAL SCRIPT SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D4C9;MATHEMATICAL SCRIPT SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D4CA;MATHEMATICAL SCRIPT SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D4CB;MATHEMATICAL SCRIPT SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D4CC;MATHEMATICAL SCRIPT SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D4CD;MATHEMATICAL SCRIPT SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D4CE;MATHEMATICAL SCRIPT SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D4CF;MATHEMATICAL SCRIPT SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D4D0;MATHEMATICAL BOLD SCRIPT CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D4D1;MATHEMATICAL BOLD SCRIPT CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D4D2;MATHEMATICAL BOLD SCRIPT CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D4D3;MATHEMATICAL BOLD SCRIPT CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D4D4;MATHEMATICAL BOLD SCRIPT CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D4D5;MATHEMATICAL BOLD SCRIPT CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D4D6;MATHEMATICAL BOLD SCRIPT CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D4D7;MATHEMATICAL BOLD SCRIPT CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D4D8;MATHEMATICAL BOLD SCRIPT CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D4D9;MATHEMATICAL BOLD SCRIPT CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D4DA;MATHEMATICAL BOLD SCRIPT CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D4DB;MATHEMATICAL BOLD SCRIPT CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D4DC;MATHEMATICAL BOLD SCRIPT CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D4DD;MATHEMATICAL BOLD SCRIPT CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D4DE;MATHEMATICAL BOLD SCRIPT CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D4DF;MATHEMATICAL BOLD SCRIPT CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D4E0;MATHEMATICAL BOLD SCRIPT CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D4E1;MATHEMATICAL BOLD SCRIPT CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D4E2;MATHEMATICAL BOLD SCRIPT CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D4E3;MATHEMATICAL BOLD SCRIPT CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D4E4;MATHEMATICAL BOLD SCRIPT CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D4E5;MATHEMATICAL BOLD SCRIPT CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D4E6;MATHEMATICAL BOLD SCRIPT CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D4E7;MATHEMATICAL BOLD SCRIPT CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D4E8;MATHEMATICAL BOLD SCRIPT CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D4E9;MATHEMATICAL BOLD SCRIPT CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D4EA;MATHEMATICAL BOLD SCRIPT SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D4EB;MATHEMATICAL BOLD SCRIPT SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D4EC;MATHEMATICAL BOLD SCRIPT SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D4ED;MATHEMATICAL BOLD SCRIPT SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D4EE;MATHEMATICAL BOLD SCRIPT SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D4EF;MATHEMATICAL BOLD SCRIPT SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D4F0;MATHEMATICAL BOLD SCRIPT SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D4F1;MATHEMATICAL BOLD SCRIPT SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D4F2;MATHEMATICAL BOLD SCRIPT SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D4F3;MATHEMATICAL BOLD SCRIPT SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D4F4;MATHEMATICAL BOLD SCRIPT SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D4F5;MATHEMATICAL BOLD SCRIPT SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D4F6;MATHEMATICAL BOLD SCRIPT SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D4F7;MATHEMATICAL BOLD SCRIPT SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D4F8;MATHEMATICAL BOLD SCRIPT SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D4F9;MATHEMATICAL BOLD SCRIPT SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D4FA;MATHEMATICAL BOLD SCRIPT SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D4FB;MATHEMATICAL BOLD SCRIPT SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D4FC;MATHEMATICAL BOLD SCRIPT SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D4FD;MATHEMATICAL BOLD SCRIPT SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D4FE;MATHEMATICAL BOLD SCRIPT SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D4FF;MATHEMATICAL BOLD SCRIPT SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D500;MATHEMATICAL BOLD SCRIPT SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D501;MATHEMATICAL BOLD SCRIPT SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D502;MATHEMATICAL BOLD SCRIPT SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D503;MATHEMATICAL BOLD SCRIPT SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D504;MATHEMATICAL FRAKTUR CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D505;MATHEMATICAL FRAKTUR CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D507;MATHEMATICAL FRAKTUR CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D508;MATHEMATICAL FRAKTUR CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D509;MATHEMATICAL FRAKTUR CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D50A;MATHEMATICAL FRAKTUR CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D50D;MATHEMATICAL FRAKTUR CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D50E;MATHEMATICAL FRAKTUR CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D50F;MATHEMATICAL FRAKTUR CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D510;MATHEMATICAL FRAKTUR CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D511;MATHEMATICAL FRAKTUR CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D512;MATHEMATICAL FRAKTUR CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D513;MATHEMATICAL FRAKTUR CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D514;MATHEMATICAL FRAKTUR CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D516;MATHEMATICAL FRAKTUR CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D517;MATHEMATICAL FRAKTUR CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D518;MATHEMATICAL FRAKTUR CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D519;MATHEMATICAL FRAKTUR CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D51A;MATHEMATICAL FRAKTUR CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D51B;MATHEMATICAL FRAKTUR CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D51C;MATHEMATICAL FRAKTUR CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D51E;MATHEMATICAL FRAKTUR SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D51F;MATHEMATICAL FRAKTUR SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D520;MATHEMATICAL FRAKTUR SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D521;MATHEMATICAL FRAKTUR SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D522;MATHEMATICAL FRAKTUR SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D523;MATHEMATICAL FRAKTUR SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D524;MATHEMATICAL FRAKTUR SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D525;MATHEMATICAL FRAKTUR SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D526;MATHEMATICAL FRAKTUR SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D527;MATHEMATICAL FRAKTUR SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D528;MATHEMATICAL FRAKTUR SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D529;MATHEMATICAL FRAKTUR SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D52A;MATHEMATICAL FRAKTUR SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D52B;MATHEMATICAL FRAKTUR SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D52C;MATHEMATICAL FRAKTUR SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D52D;MATHEMATICAL FRAKTUR SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D52E;MATHEMATICAL FRAKTUR SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D52F;MATHEMATICAL FRAKTUR SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D530;MATHEMATICAL FRAKTUR SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D531;MATHEMATICAL FRAKTUR SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D532;MATHEMATICAL FRAKTUR SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D533;MATHEMATICAL FRAKTUR SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D534;MATHEMATICAL FRAKTUR SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D535;MATHEMATICAL FRAKTUR SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D536;MATHEMATICAL FRAKTUR SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D537;MATHEMATICAL FRAKTUR SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D538;MATHEMATICAL DOUBLE-STRUCK CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D539;MATHEMATICAL DOUBLE-STRUCK CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D53B;MATHEMATICAL DOUBLE-STRUCK CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D53C;MATHEMATICAL DOUBLE-STRUCK CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D53D;MATHEMATICAL DOUBLE-STRUCK CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D53E;MATHEMATICAL DOUBLE-STRUCK CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D540;MATHEMATICAL DOUBLE-STRUCK CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D541;MATHEMATICAL DOUBLE-STRUCK CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D542;MATHEMATICAL DOUBLE-STRUCK CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D543;MATHEMATICAL DOUBLE-STRUCK CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D544;MATHEMATICAL DOUBLE-STRUCK CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D546;MATHEMATICAL DOUBLE-STRUCK CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D54A;MATHEMATICAL DOUBLE-STRUCK CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D54B;MATHEMATICAL DOUBLE-STRUCK CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D54C;MATHEMATICAL DOUBLE-STRUCK CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D54D;MATHEMATICAL DOUBLE-STRUCK CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D54E;MATHEMATICAL DOUBLE-STRUCK CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D54F;MATHEMATICAL DOUBLE-STRUCK CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D550;MATHEMATICAL DOUBLE-STRUCK CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D552;MATHEMATICAL DOUBLE-STRUCK SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D553;MATHEMATICAL DOUBLE-STRUCK SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D554;MATHEMATICAL DOUBLE-STRUCK SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D555;MATHEMATICAL DOUBLE-STRUCK SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D556;MATHEMATICAL DOUBLE-STRUCK SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D557;MATHEMATICAL DOUBLE-STRUCK SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D558;MATHEMATICAL DOUBLE-STRUCK SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D559;MATHEMATICAL DOUBLE-STRUCK SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D55A;MATHEMATICAL DOUBLE-STRUCK SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D55B;MATHEMATICAL DOUBLE-STRUCK SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D55C;MATHEMATICAL DOUBLE-STRUCK SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D55D;MATHEMATICAL DOUBLE-STRUCK SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D55E;MATHEMATICAL DOUBLE-STRUCK SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D55F;MATHEMATICAL DOUBLE-STRUCK SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D560;MATHEMATICAL DOUBLE-STRUCK SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D561;MATHEMATICAL DOUBLE-STRUCK SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D562;MATHEMATICAL DOUBLE-STRUCK SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D563;MATHEMATICAL DOUBLE-STRUCK SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D564;MATHEMATICAL DOUBLE-STRUCK SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D565;MATHEMATICAL DOUBLE-STRUCK SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D566;MATHEMATICAL DOUBLE-STRUCK SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D567;MATHEMATICAL DOUBLE-STRUCK SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D568;MATHEMATICAL DOUBLE-STRUCK SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D569;MATHEMATICAL DOUBLE-STRUCK SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D56A;MATHEMATICAL DOUBLE-STRUCK SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D56B;MATHEMATICAL DOUBLE-STRUCK SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D56C;MATHEMATICAL BOLD FRAKTUR CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D56D;MATHEMATICAL BOLD FRAKTUR CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D56E;MATHEMATICAL BOLD FRAKTUR CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D56F;MATHEMATICAL BOLD FRAKTUR CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D570;MATHEMATICAL BOLD FRAKTUR CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D571;MATHEMATICAL BOLD FRAKTUR CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D572;MATHEMATICAL BOLD FRAKTUR CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D573;MATHEMATICAL BOLD FRAKTUR CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D574;MATHEMATICAL BOLD FRAKTUR CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D575;MATHEMATICAL BOLD FRAKTUR CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D576;MATHEMATICAL BOLD FRAKTUR CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D577;MATHEMATICAL BOLD FRAKTUR CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D578;MATHEMATICAL BOLD FRAKTUR CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D579;MATHEMATICAL BOLD FRAKTUR CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D57A;MATHEMATICAL BOLD FRAKTUR CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D57B;MATHEMATICAL BOLD FRAKTUR CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D57C;MATHEMATICAL BOLD FRAKTUR CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D57D;MATHEMATICAL BOLD FRAKTUR CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D57E;MATHEMATICAL BOLD FRAKTUR CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D57F;MATHEMATICAL BOLD FRAKTUR CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D580;MATHEMATICAL BOLD FRAKTUR CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D581;MATHEMATICAL BOLD FRAKTUR CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D582;MATHEMATICAL BOLD FRAKTUR CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D583;MATHEMATICAL BOLD FRAKTUR CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D584;MATHEMATICAL BOLD FRAKTUR CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D585;MATHEMATICAL BOLD FRAKTUR CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D586;MATHEMATICAL BOLD FRAKTUR SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D587;MATHEMATICAL BOLD FRAKTUR SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D588;MATHEMATICAL BOLD FRAKTUR SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D589;MATHEMATICAL BOLD FRAKTUR SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D58A;MATHEMATICAL BOLD FRAKTUR SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D58B;MATHEMATICAL BOLD FRAKTUR SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D58C;MATHEMATICAL BOLD FRAKTUR SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D58D;MATHEMATICAL BOLD FRAKTUR SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D58E;MATHEMATICAL BOLD FRAKTUR SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D58F;MATHEMATICAL BOLD FRAKTUR SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D590;MATHEMATICAL BOLD FRAKTUR SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D591;MATHEMATICAL BOLD FRAKTUR SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D592;MATHEMATICAL BOLD FRAKTUR SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D593;MATHEMATICAL BOLD FRAKTUR SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D594;MATHEMATICAL BOLD FRAKTUR SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D595;MATHEMATICAL BOLD FRAKTUR SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D596;MATHEMATICAL BOLD FRAKTUR SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D597;MATHEMATICAL BOLD FRAKTUR SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D598;MATHEMATICAL BOLD FRAKTUR SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D599;MATHEMATICAL BOLD FRAKTUR SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D59A;MATHEMATICAL BOLD FRAKTUR SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D59B;MATHEMATICAL BOLD FRAKTUR SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D59C;MATHEMATICAL BOLD FRAKTUR SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D59D;MATHEMATICAL BOLD FRAKTUR SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D59E;MATHEMATICAL BOLD FRAKTUR SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D59F;MATHEMATICAL BOLD FRAKTUR SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D5A0;MATHEMATICAL SANS-SERIF CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D5A1;MATHEMATICAL SANS-SERIF CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D5A2;MATHEMATICAL SANS-SERIF CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D5A3;MATHEMATICAL SANS-SERIF CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D5A4;MATHEMATICAL SANS-SERIF CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D5A5;MATHEMATICAL SANS-SERIF CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D5A6;MATHEMATICAL SANS-SERIF CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D5A7;MATHEMATICAL SANS-SERIF CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D5A8;MATHEMATICAL SANS-SERIF CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D5A9;MATHEMATICAL SANS-SERIF CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D5AA;MATHEMATICAL SANS-SERIF CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D5AB;MATHEMATICAL SANS-SERIF CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D5AC;MATHEMATICAL SANS-SERIF CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D5AD;MATHEMATICAL SANS-SERIF CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D5AE;MATHEMATICAL SANS-SERIF CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D5AF;MATHEMATICAL SANS-SERIF CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D5B0;MATHEMATICAL SANS-SERIF CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D5B1;MATHEMATICAL SANS-SERIF CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D5B2;MATHEMATICAL SANS-SERIF CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D5B3;MATHEMATICAL SANS-SERIF CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D5B4;MATHEMATICAL SANS-SERIF CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D5B5;MATHEMATICAL SANS-SERIF CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D5B6;MATHEMATICAL SANS-SERIF CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D5B7;MATHEMATICAL SANS-SERIF CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D5B8;MATHEMATICAL SANS-SERIF CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D5B9;MATHEMATICAL SANS-SERIF CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D5BA;MATHEMATICAL SANS-SERIF SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D5BB;MATHEMATICAL SANS-SERIF SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D5BC;MATHEMATICAL SANS-SERIF SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D5BD;MATHEMATICAL SANS-SERIF SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D5BE;MATHEMATICAL SANS-SERIF SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D5BF;MATHEMATICAL SANS-SERIF SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D5C0;MATHEMATICAL SANS-SERIF SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D5C1;MATHEMATICAL SANS-SERIF SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D5C2;MATHEMATICAL SANS-SERIF SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D5C3;MATHEMATICAL SANS-SERIF SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D5C4;MATHEMATICAL SANS-SERIF SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D5C5;MATHEMATICAL SANS-SERIF SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D5C6;MATHEMATICAL SANS-SERIF SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D5C7;MATHEMATICAL SANS-SERIF SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D5C8;MATHEMATICAL SANS-SERIF SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D5C9;MATHEMATICAL SANS-SERIF SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D5CA;MATHEMATICAL SANS-SERIF SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D5CB;MATHEMATICAL SANS-SERIF SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D5CC;MATHEMATICAL SANS-SERIF SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D5CD;MATHEMATICAL SANS-SERIF SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D5CE;MATHEMATICAL SANS-SERIF SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D5CF;MATHEMATICAL SANS-SERIF SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D5D0;MATHEMATICAL SANS-SERIF SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D5D1;MATHEMATICAL SANS-SERIF SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D5D2;MATHEMATICAL SANS-SERIF SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D5D3;MATHEMATICAL SANS-SERIF SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D5D4;MATHEMATICAL SANS-SERIF BOLD CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D5D5;MATHEMATICAL SANS-SERIF BOLD CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D5D6;MATHEMATICAL SANS-SERIF BOLD CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D5D7;MATHEMATICAL SANS-SERIF BOLD CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D5D8;MATHEMATICAL SANS-SERIF BOLD CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D5D9;MATHEMATICAL SANS-SERIF BOLD CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D5DA;MATHEMATICAL SANS-SERIF BOLD CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D5DB;MATHEMATICAL SANS-SERIF BOLD CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D5DC;MATHEMATICAL SANS-SERIF BOLD CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D5DD;MATHEMATICAL SANS-SERIF BOLD CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D5DE;MATHEMATICAL SANS-SERIF BOLD CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D5DF;MATHEMATICAL SANS-SERIF BOLD CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D5E0;MATHEMATICAL SANS-SERIF BOLD CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D5E1;MATHEMATICAL SANS-SERIF BOLD CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D5E2;MATHEMATICAL SANS-SERIF BOLD CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D5E3;MATHEMATICAL SANS-SERIF BOLD CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D5E4;MATHEMATICAL SANS-SERIF BOLD CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D5E5;MATHEMATICAL SANS-SERIF BOLD CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D5E6;MATHEMATICAL SANS-SERIF BOLD CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D5E7;MATHEMATICAL SANS-SERIF BOLD CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D5E8;MATHEMATICAL SANS-SERIF BOLD CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D5E9;MATHEMATICAL SANS-SERIF BOLD CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D5EA;MATHEMATICAL SANS-SERIF BOLD CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D5EB;MATHEMATICAL SANS-SERIF BOLD CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D5EC;MATHEMATICAL SANS-SERIF BOLD CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D5ED;MATHEMATICAL SANS-SERIF BOLD CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D5EE;MATHEMATICAL SANS-SERIF BOLD SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D5EF;MATHEMATICAL SANS-SERIF BOLD SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D5F0;MATHEMATICAL SANS-SERIF BOLD SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D5F1;MATHEMATICAL SANS-SERIF BOLD SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D5F2;MATHEMATICAL SANS-SERIF BOLD SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D5F3;MATHEMATICAL SANS-SERIF BOLD SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D5F4;MATHEMATICAL SANS-SERIF BOLD SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D5F5;MATHEMATICAL SANS-SERIF BOLD SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D5F6;MATHEMATICAL SANS-SERIF BOLD SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D5F7;MATHEMATICAL SANS-SERIF BOLD SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D5F8;MATHEMATICAL SANS-SERIF BOLD SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D5F9;MATHEMATICAL SANS-SERIF BOLD SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D5FA;MATHEMATICAL SANS-SERIF BOLD SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D5FB;MATHEMATICAL SANS-SERIF BOLD SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D5FC;MATHEMATICAL SANS-SERIF BOLD SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D5FD;MATHEMATICAL SANS-SERIF BOLD SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D5FE;MATHEMATICAL SANS-SERIF BOLD SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D5FF;MATHEMATICAL SANS-SERIF BOLD SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D600;MATHEMATICAL SANS-SERIF BOLD SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D601;MATHEMATICAL SANS-SERIF BOLD SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D602;MATHEMATICAL SANS-SERIF BOLD SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D603;MATHEMATICAL SANS-SERIF BOLD SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D604;MATHEMATICAL SANS-SERIF BOLD SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D605;MATHEMATICAL SANS-SERIF BOLD SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D606;MATHEMATICAL SANS-SERIF BOLD SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D607;MATHEMATICAL SANS-SERIF BOLD SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D608;MATHEMATICAL SANS-SERIF ITALIC CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D609;MATHEMATICAL SANS-SERIF ITALIC CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D60A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D60B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D60C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D60D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D60E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D60F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D610;MATHEMATICAL SANS-SERIF ITALIC CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D611;MATHEMATICAL SANS-SERIF ITALIC CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D612;MATHEMATICAL SANS-SERIF ITALIC CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D613;MATHEMATICAL SANS-SERIF ITALIC CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D614;MATHEMATICAL SANS-SERIF ITALIC CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D615;MATHEMATICAL SANS-SERIF ITALIC CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D616;MATHEMATICAL SANS-SERIF ITALIC CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D617;MATHEMATICAL SANS-SERIF ITALIC CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D618;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D619;MATHEMATICAL SANS-SERIF ITALIC CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D61A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D61B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D61C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D61D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D61E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D61F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D620;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D621;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D622;MATHEMATICAL SANS-SERIF ITALIC SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D623;MATHEMATICAL SANS-SERIF ITALIC SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D624;MATHEMATICAL SANS-SERIF ITALIC SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D625;MATHEMATICAL SANS-SERIF ITALIC SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D626;MATHEMATICAL SANS-SERIF ITALIC SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D627;MATHEMATICAL SANS-SERIF ITALIC SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D628;MATHEMATICAL SANS-SERIF ITALIC SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D629;MATHEMATICAL SANS-SERIF ITALIC SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D62A;MATHEMATICAL SANS-SERIF ITALIC SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D62B;MATHEMATICAL SANS-SERIF ITALIC SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D62C;MATHEMATICAL SANS-SERIF ITALIC SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D62D;MATHEMATICAL SANS-SERIF ITALIC SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D62E;MATHEMATICAL SANS-SERIF ITALIC SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D62F;MATHEMATICAL SANS-SERIF ITALIC SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D630;MATHEMATICAL SANS-SERIF ITALIC SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D631;MATHEMATICAL SANS-SERIF ITALIC SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D632;MATHEMATICAL SANS-SERIF ITALIC SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D633;MATHEMATICAL SANS-SERIF ITALIC SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D634;MATHEMATICAL SANS-SERIF ITALIC SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D635;MATHEMATICAL SANS-SERIF ITALIC SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D636;MATHEMATICAL SANS-SERIF ITALIC SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D637;MATHEMATICAL SANS-SERIF ITALIC SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D638;MATHEMATICAL SANS-SERIF ITALIC SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D639;MATHEMATICAL SANS-SERIF ITALIC SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D63A;MATHEMATICAL SANS-SERIF ITALIC SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D63B;MATHEMATICAL SANS-SERIF ITALIC SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D63C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D63D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D63E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D63F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D640;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D641;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D642;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D643;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D644;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D645;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D646;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D647;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D648;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D649;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D64A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D64B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D64C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D64D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D64E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D64F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D650;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D651;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D652;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D653;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D654;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D655;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D656;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D657;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D658;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D659;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D65A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D65B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D65C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D65D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D65E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D65F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D660;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D661;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D662;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D663;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D664;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D665;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D666;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D667;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D668;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D669;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D66A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D66B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D66C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D66D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D66E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D66F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D670;MATHEMATICAL MONOSPACE CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D671;MATHEMATICAL MONOSPACE CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D672;MATHEMATICAL MONOSPACE CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D673;MATHEMATICAL MONOSPACE CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D674;MATHEMATICAL MONOSPACE CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D675;MATHEMATICAL MONOSPACE CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D676;MATHEMATICAL MONOSPACE CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D677;MATHEMATICAL MONOSPACE CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D678;MATHEMATICAL MONOSPACE CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D679;MATHEMATICAL MONOSPACE CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D67A;MATHEMATICAL MONOSPACE CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D67B;MATHEMATICAL MONOSPACE CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D67C;MATHEMATICAL MONOSPACE CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D67D;MATHEMATICAL MONOSPACE CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D67E;MATHEMATICAL MONOSPACE CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D67F;MATHEMATICAL MONOSPACE CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D680;MATHEMATICAL MONOSPACE CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D681;MATHEMATICAL MONOSPACE CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D682;MATHEMATICAL MONOSPACE CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D683;MATHEMATICAL MONOSPACE CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D684;MATHEMATICAL MONOSPACE CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D685;MATHEMATICAL MONOSPACE CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D686;MATHEMATICAL MONOSPACE CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D687;MATHEMATICAL MONOSPACE CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D688;MATHEMATICAL MONOSPACE CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D689;MATHEMATICAL MONOSPACE CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D68A;MATHEMATICAL MONOSPACE SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D68B;MATHEMATICAL MONOSPACE SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D68C;MATHEMATICAL MONOSPACE SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D68D;MATHEMATICAL MONOSPACE SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D68E;MATHEMATICAL MONOSPACE SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D68F;MATHEMATICAL MONOSPACE SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D690;MATHEMATICAL MONOSPACE SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D691;MATHEMATICAL MONOSPACE SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D692;MATHEMATICAL MONOSPACE SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D693;MATHEMATICAL MONOSPACE SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D694;MATHEMATICAL MONOSPACE SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D695;MATHEMATICAL MONOSPACE SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D696;MATHEMATICAL MONOSPACE SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D697;MATHEMATICAL MONOSPACE SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D698;MATHEMATICAL MONOSPACE SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D699;MATHEMATICAL MONOSPACE SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D69A;MATHEMATICAL MONOSPACE SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D69B;MATHEMATICAL MONOSPACE SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D69C;MATHEMATICAL MONOSPACE SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D69D;MATHEMATICAL MONOSPACE SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D69E;MATHEMATICAL MONOSPACE SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D69F;MATHEMATICAL MONOSPACE SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D6A0;MATHEMATICAL MONOSPACE SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D6A1;MATHEMATICAL MONOSPACE SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D6A2;MATHEMATICAL MONOSPACE SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D6A3;MATHEMATICAL MONOSPACE SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D6A4;MATHEMATICAL ITALIC SMALL DOTLESS I;Ll;0;L; 0131;;;;N;;;;; +1D6A5;MATHEMATICAL ITALIC SMALL DOTLESS J;Ll;0;L; 0237;;;;N;;;;; +1D6A8;MATHEMATICAL BOLD CAPITAL ALPHA;Lu;0;L; 0391;;;;N;;;;; +1D6A9;MATHEMATICAL BOLD CAPITAL BETA;Lu;0;L; 0392;;;;N;;;;; +1D6AA;MATHEMATICAL BOLD CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; +1D6AB;MATHEMATICAL BOLD CAPITAL DELTA;Lu;0;L; 0394;;;;N;;;;; +1D6AC;MATHEMATICAL BOLD CAPITAL EPSILON;Lu;0;L; 0395;;;;N;;;;; +1D6AD;MATHEMATICAL BOLD CAPITAL ZETA;Lu;0;L; 0396;;;;N;;;;; +1D6AE;MATHEMATICAL BOLD CAPITAL ETA;Lu;0;L; 0397;;;;N;;;;; +1D6AF;MATHEMATICAL BOLD CAPITAL THETA;Lu;0;L; 0398;;;;N;;;;; +1D6B0;MATHEMATICAL BOLD CAPITAL IOTA;Lu;0;L; 0399;;;;N;;;;; +1D6B1;MATHEMATICAL BOLD CAPITAL KAPPA;Lu;0;L; 039A;;;;N;;;;; +1D6B2;MATHEMATICAL BOLD CAPITAL LAMDA;Lu;0;L; 039B;;;;N;;;;; +1D6B3;MATHEMATICAL BOLD CAPITAL MU;Lu;0;L; 039C;;;;N;;;;; +1D6B4;MATHEMATICAL BOLD CAPITAL NU;Lu;0;L; 039D;;;;N;;;;; +1D6B5;MATHEMATICAL BOLD CAPITAL XI;Lu;0;L; 039E;;;;N;;;;; +1D6B6;MATHEMATICAL BOLD CAPITAL OMICRON;Lu;0;L; 039F;;;;N;;;;; +1D6B7;MATHEMATICAL BOLD CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; +1D6B8;MATHEMATICAL BOLD CAPITAL RHO;Lu;0;L; 03A1;;;;N;;;;; +1D6B9;MATHEMATICAL BOLD CAPITAL THETA SYMBOL;Lu;0;L; 03F4;;;;N;;;;; +1D6BA;MATHEMATICAL BOLD CAPITAL SIGMA;Lu;0;L; 03A3;;;;N;;;;; +1D6BB;MATHEMATICAL BOLD CAPITAL TAU;Lu;0;L; 03A4;;;;N;;;;; +1D6BC;MATHEMATICAL BOLD CAPITAL UPSILON;Lu;0;L; 03A5;;;;N;;;;; +1D6BD;MATHEMATICAL BOLD CAPITAL PHI;Lu;0;L; 03A6;;;;N;;;;; +1D6BE;MATHEMATICAL BOLD CAPITAL CHI;Lu;0;L; 03A7;;;;N;;;;; +1D6BF;MATHEMATICAL BOLD CAPITAL PSI;Lu;0;L; 03A8;;;;N;;;;; +1D6C0;MATHEMATICAL BOLD CAPITAL OMEGA;Lu;0;L; 03A9;;;;N;;;;; +1D6C1;MATHEMATICAL BOLD NABLA;Sm;0;ON; 2207;;;;N;;;;; +1D6C2;MATHEMATICAL BOLD SMALL ALPHA;Ll;0;L; 03B1;;;;N;;;;; +1D6C3;MATHEMATICAL BOLD SMALL BETA;Ll;0;L; 03B2;;;;N;;;;; +1D6C4;MATHEMATICAL BOLD SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; +1D6C5;MATHEMATICAL BOLD SMALL DELTA;Ll;0;L; 03B4;;;;N;;;;; +1D6C6;MATHEMATICAL BOLD SMALL EPSILON;Ll;0;L; 03B5;;;;N;;;;; +1D6C7;MATHEMATICAL BOLD SMALL ZETA;Ll;0;L; 03B6;;;;N;;;;; +1D6C8;MATHEMATICAL BOLD SMALL ETA;Ll;0;L; 03B7;;;;N;;;;; +1D6C9;MATHEMATICAL BOLD SMALL THETA;Ll;0;L; 03B8;;;;N;;;;; +1D6CA;MATHEMATICAL BOLD SMALL IOTA;Ll;0;L; 03B9;;;;N;;;;; +1D6CB;MATHEMATICAL BOLD SMALL KAPPA;Ll;0;L; 03BA;;;;N;;;;; +1D6CC;MATHEMATICAL BOLD SMALL LAMDA;Ll;0;L; 03BB;;;;N;;;;; +1D6CD;MATHEMATICAL BOLD SMALL MU;Ll;0;L; 03BC;;;;N;;;;; +1D6CE;MATHEMATICAL BOLD SMALL NU;Ll;0;L; 03BD;;;;N;;;;; +1D6CF;MATHEMATICAL BOLD SMALL XI;Ll;0;L; 03BE;;;;N;;;;; +1D6D0;MATHEMATICAL BOLD SMALL OMICRON;Ll;0;L; 03BF;;;;N;;;;; +1D6D1;MATHEMATICAL BOLD SMALL PI;Ll;0;L; 03C0;;;;N;;;;; +1D6D2;MATHEMATICAL BOLD SMALL RHO;Ll;0;L; 03C1;;;;N;;;;; +1D6D3;MATHEMATICAL BOLD SMALL FINAL SIGMA;Ll;0;L; 03C2;;;;N;;;;; +1D6D4;MATHEMATICAL BOLD SMALL SIGMA;Ll;0;L; 03C3;;;;N;;;;; +1D6D5;MATHEMATICAL BOLD SMALL TAU;Ll;0;L; 03C4;;;;N;;;;; +1D6D6;MATHEMATICAL BOLD SMALL UPSILON;Ll;0;L; 03C5;;;;N;;;;; +1D6D7;MATHEMATICAL BOLD SMALL PHI;Ll;0;L; 03C6;;;;N;;;;; +1D6D8;MATHEMATICAL BOLD SMALL CHI;Ll;0;L; 03C7;;;;N;;;;; +1D6D9;MATHEMATICAL BOLD SMALL PSI;Ll;0;L; 03C8;;;;N;;;;; +1D6DA;MATHEMATICAL BOLD SMALL OMEGA;Ll;0;L; 03C9;;;;N;;;;; +1D6DB;MATHEMATICAL BOLD PARTIAL DIFFERENTIAL;Sm;0;ON; 2202;;;;Y;;;;; +1D6DC;MATHEMATICAL BOLD EPSILON SYMBOL;Ll;0;L; 03F5;;;;N;;;;; +1D6DD;MATHEMATICAL BOLD THETA SYMBOL;Ll;0;L; 03D1;;;;N;;;;; +1D6DE;MATHEMATICAL BOLD KAPPA SYMBOL;Ll;0;L; 03F0;;;;N;;;;; +1D6DF;MATHEMATICAL BOLD PHI SYMBOL;Ll;0;L; 03D5;;;;N;;;;; +1D6E0;MATHEMATICAL BOLD RHO SYMBOL;Ll;0;L; 03F1;;;;N;;;;; +1D6E1;MATHEMATICAL BOLD PI SYMBOL;Ll;0;L; 03D6;;;;N;;;;; +1D6E2;MATHEMATICAL ITALIC CAPITAL ALPHA;Lu;0;L; 0391;;;;N;;;;; +1D6E3;MATHEMATICAL ITALIC CAPITAL BETA;Lu;0;L; 0392;;;;N;;;;; +1D6E4;MATHEMATICAL ITALIC CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; +1D6E5;MATHEMATICAL ITALIC CAPITAL DELTA;Lu;0;L; 0394;;;;N;;;;; +1D6E6;MATHEMATICAL ITALIC CAPITAL EPSILON;Lu;0;L; 0395;;;;N;;;;; +1D6E7;MATHEMATICAL ITALIC CAPITAL ZETA;Lu;0;L; 0396;;;;N;;;;; +1D6E8;MATHEMATICAL ITALIC CAPITAL ETA;Lu;0;L; 0397;;;;N;;;;; +1D6E9;MATHEMATICAL ITALIC CAPITAL THETA;Lu;0;L; 0398;;;;N;;;;; +1D6EA;MATHEMATICAL ITALIC CAPITAL IOTA;Lu;0;L; 0399;;;;N;;;;; +1D6EB;MATHEMATICAL ITALIC CAPITAL KAPPA;Lu;0;L; 039A;;;;N;;;;; +1D6EC;MATHEMATICAL ITALIC CAPITAL LAMDA;Lu;0;L; 039B;;;;N;;;;; +1D6ED;MATHEMATICAL ITALIC CAPITAL MU;Lu;0;L; 039C;;;;N;;;;; +1D6EE;MATHEMATICAL ITALIC CAPITAL NU;Lu;0;L; 039D;;;;N;;;;; +1D6EF;MATHEMATICAL ITALIC CAPITAL XI;Lu;0;L; 039E;;;;N;;;;; +1D6F0;MATHEMATICAL ITALIC CAPITAL OMICRON;Lu;0;L; 039F;;;;N;;;;; +1D6F1;MATHEMATICAL ITALIC CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; +1D6F2;MATHEMATICAL ITALIC CAPITAL RHO;Lu;0;L; 03A1;;;;N;;;;; +1D6F3;MATHEMATICAL ITALIC CAPITAL THETA SYMBOL;Lu;0;L; 03F4;;;;N;;;;; +1D6F4;MATHEMATICAL ITALIC CAPITAL SIGMA;Lu;0;L; 03A3;;;;N;;;;; +1D6F5;MATHEMATICAL ITALIC CAPITAL TAU;Lu;0;L; 03A4;;;;N;;;;; +1D6F6;MATHEMATICAL ITALIC CAPITAL UPSILON;Lu;0;L; 03A5;;;;N;;;;; +1D6F7;MATHEMATICAL ITALIC CAPITAL PHI;Lu;0;L; 03A6;;;;N;;;;; +1D6F8;MATHEMATICAL ITALIC CAPITAL CHI;Lu;0;L; 03A7;;;;N;;;;; +1D6F9;MATHEMATICAL ITALIC CAPITAL PSI;Lu;0;L; 03A8;;;;N;;;;; +1D6FA;MATHEMATICAL ITALIC CAPITAL OMEGA;Lu;0;L; 03A9;;;;N;;;;; +1D6FB;MATHEMATICAL ITALIC NABLA;Sm;0;ON; 2207;;;;N;;;;; +1D6FC;MATHEMATICAL ITALIC SMALL ALPHA;Ll;0;L; 03B1;;;;N;;;;; +1D6FD;MATHEMATICAL ITALIC SMALL BETA;Ll;0;L; 03B2;;;;N;;;;; +1D6FE;MATHEMATICAL ITALIC SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; +1D6FF;MATHEMATICAL ITALIC SMALL DELTA;Ll;0;L; 03B4;;;;N;;;;; +1D700;MATHEMATICAL ITALIC SMALL EPSILON;Ll;0;L; 03B5;;;;N;;;;; +1D701;MATHEMATICAL ITALIC SMALL ZETA;Ll;0;L; 03B6;;;;N;;;;; +1D702;MATHEMATICAL ITALIC SMALL ETA;Ll;0;L; 03B7;;;;N;;;;; +1D703;MATHEMATICAL ITALIC SMALL THETA;Ll;0;L; 03B8;;;;N;;;;; +1D704;MATHEMATICAL ITALIC SMALL IOTA;Ll;0;L; 03B9;;;;N;;;;; +1D705;MATHEMATICAL ITALIC SMALL KAPPA;Ll;0;L; 03BA;;;;N;;;;; +1D706;MATHEMATICAL ITALIC SMALL LAMDA;Ll;0;L; 03BB;;;;N;;;;; +1D707;MATHEMATICAL ITALIC SMALL MU;Ll;0;L; 03BC;;;;N;;;;; +1D708;MATHEMATICAL ITALIC SMALL NU;Ll;0;L; 03BD;;;;N;;;;; +1D709;MATHEMATICAL ITALIC SMALL XI;Ll;0;L; 03BE;;;;N;;;;; +1D70A;MATHEMATICAL ITALIC SMALL OMICRON;Ll;0;L; 03BF;;;;N;;;;; +1D70B;MATHEMATICAL ITALIC SMALL PI;Ll;0;L; 03C0;;;;N;;;;; +1D70C;MATHEMATICAL ITALIC SMALL RHO;Ll;0;L; 03C1;;;;N;;;;; +1D70D;MATHEMATICAL ITALIC SMALL FINAL SIGMA;Ll;0;L; 03C2;;;;N;;;;; +1D70E;MATHEMATICAL ITALIC SMALL SIGMA;Ll;0;L; 03C3;;;;N;;;;; +1D70F;MATHEMATICAL ITALIC SMALL TAU;Ll;0;L; 03C4;;;;N;;;;; +1D710;MATHEMATICAL ITALIC SMALL UPSILON;Ll;0;L; 03C5;;;;N;;;;; +1D711;MATHEMATICAL ITALIC SMALL PHI;Ll;0;L; 03C6;;;;N;;;;; +1D712;MATHEMATICAL ITALIC SMALL CHI;Ll;0;L; 03C7;;;;N;;;;; +1D713;MATHEMATICAL ITALIC SMALL PSI;Ll;0;L; 03C8;;;;N;;;;; +1D714;MATHEMATICAL ITALIC SMALL OMEGA;Ll;0;L; 03C9;;;;N;;;;; +1D715;MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL;Sm;0;ON; 2202;;;;Y;;;;; +1D716;MATHEMATICAL ITALIC EPSILON SYMBOL;Ll;0;L; 03F5;;;;N;;;;; +1D717;MATHEMATICAL ITALIC THETA SYMBOL;Ll;0;L; 03D1;;;;N;;;;; +1D718;MATHEMATICAL ITALIC KAPPA SYMBOL;Ll;0;L; 03F0;;;;N;;;;; +1D719;MATHEMATICAL ITALIC PHI SYMBOL;Ll;0;L; 03D5;;;;N;;;;; +1D71A;MATHEMATICAL ITALIC RHO SYMBOL;Ll;0;L; 03F1;;;;N;;;;; +1D71B;MATHEMATICAL ITALIC PI SYMBOL;Ll;0;L; 03D6;;;;N;;;;; +1D71C;MATHEMATICAL BOLD ITALIC CAPITAL ALPHA;Lu;0;L; 0391;;;;N;;;;; +1D71D;MATHEMATICAL BOLD ITALIC CAPITAL BETA;Lu;0;L; 0392;;;;N;;;;; +1D71E;MATHEMATICAL BOLD ITALIC CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; +1D71F;MATHEMATICAL BOLD ITALIC CAPITAL DELTA;Lu;0;L; 0394;;;;N;;;;; +1D720;MATHEMATICAL BOLD ITALIC CAPITAL EPSILON;Lu;0;L; 0395;;;;N;;;;; +1D721;MATHEMATICAL BOLD ITALIC CAPITAL ZETA;Lu;0;L; 0396;;;;N;;;;; +1D722;MATHEMATICAL BOLD ITALIC CAPITAL ETA;Lu;0;L; 0397;;;;N;;;;; +1D723;MATHEMATICAL BOLD ITALIC CAPITAL THETA;Lu;0;L; 0398;;;;N;;;;; +1D724;MATHEMATICAL BOLD ITALIC CAPITAL IOTA;Lu;0;L; 0399;;;;N;;;;; +1D725;MATHEMATICAL BOLD ITALIC CAPITAL KAPPA;Lu;0;L; 039A;;;;N;;;;; +1D726;MATHEMATICAL BOLD ITALIC CAPITAL LAMDA;Lu;0;L; 039B;;;;N;;;;; +1D727;MATHEMATICAL BOLD ITALIC CAPITAL MU;Lu;0;L; 039C;;;;N;;;;; +1D728;MATHEMATICAL BOLD ITALIC CAPITAL NU;Lu;0;L; 039D;;;;N;;;;; +1D729;MATHEMATICAL BOLD ITALIC CAPITAL XI;Lu;0;L; 039E;;;;N;;;;; +1D72A;MATHEMATICAL BOLD ITALIC CAPITAL OMICRON;Lu;0;L; 039F;;;;N;;;;; +1D72B;MATHEMATICAL BOLD ITALIC CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; +1D72C;MATHEMATICAL BOLD ITALIC CAPITAL RHO;Lu;0;L; 03A1;;;;N;;;;; +1D72D;MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L; 03F4;;;;N;;;;; +1D72E;MATHEMATICAL BOLD ITALIC CAPITAL SIGMA;Lu;0;L; 03A3;;;;N;;;;; +1D72F;MATHEMATICAL BOLD ITALIC CAPITAL TAU;Lu;0;L; 03A4;;;;N;;;;; +1D730;MATHEMATICAL BOLD ITALIC CAPITAL UPSILON;Lu;0;L; 03A5;;;;N;;;;; +1D731;MATHEMATICAL BOLD ITALIC CAPITAL PHI;Lu;0;L; 03A6;;;;N;;;;; +1D732;MATHEMATICAL BOLD ITALIC CAPITAL CHI;Lu;0;L; 03A7;;;;N;;;;; +1D733;MATHEMATICAL BOLD ITALIC CAPITAL PSI;Lu;0;L; 03A8;;;;N;;;;; +1D734;MATHEMATICAL BOLD ITALIC CAPITAL OMEGA;Lu;0;L; 03A9;;;;N;;;;; +1D735;MATHEMATICAL BOLD ITALIC NABLA;Sm;0;ON; 2207;;;;N;;;;; +1D736;MATHEMATICAL BOLD ITALIC SMALL ALPHA;Ll;0;L; 03B1;;;;N;;;;; +1D737;MATHEMATICAL BOLD ITALIC SMALL BETA;Ll;0;L; 03B2;;;;N;;;;; +1D738;MATHEMATICAL BOLD ITALIC SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; +1D739;MATHEMATICAL BOLD ITALIC SMALL DELTA;Ll;0;L; 03B4;;;;N;;;;; +1D73A;MATHEMATICAL BOLD ITALIC SMALL EPSILON;Ll;0;L; 03B5;;;;N;;;;; +1D73B;MATHEMATICAL BOLD ITALIC SMALL ZETA;Ll;0;L; 03B6;;;;N;;;;; +1D73C;MATHEMATICAL BOLD ITALIC SMALL ETA;Ll;0;L; 03B7;;;;N;;;;; +1D73D;MATHEMATICAL BOLD ITALIC SMALL THETA;Ll;0;L; 03B8;;;;N;;;;; +1D73E;MATHEMATICAL BOLD ITALIC SMALL IOTA;Ll;0;L; 03B9;;;;N;;;;; +1D73F;MATHEMATICAL BOLD ITALIC SMALL KAPPA;Ll;0;L; 03BA;;;;N;;;;; +1D740;MATHEMATICAL BOLD ITALIC SMALL LAMDA;Ll;0;L; 03BB;;;;N;;;;; +1D741;MATHEMATICAL BOLD ITALIC SMALL MU;Ll;0;L; 03BC;;;;N;;;;; +1D742;MATHEMATICAL BOLD ITALIC SMALL NU;Ll;0;L; 03BD;;;;N;;;;; +1D743;MATHEMATICAL BOLD ITALIC SMALL XI;Ll;0;L; 03BE;;;;N;;;;; +1D744;MATHEMATICAL BOLD ITALIC SMALL OMICRON;Ll;0;L; 03BF;;;;N;;;;; +1D745;MATHEMATICAL BOLD ITALIC SMALL PI;Ll;0;L; 03C0;;;;N;;;;; +1D746;MATHEMATICAL BOLD ITALIC SMALL RHO;Ll;0;L; 03C1;;;;N;;;;; +1D747;MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L; 03C2;;;;N;;;;; +1D748;MATHEMATICAL BOLD ITALIC SMALL SIGMA;Ll;0;L; 03C3;;;;N;;;;; +1D749;MATHEMATICAL BOLD ITALIC SMALL TAU;Ll;0;L; 03C4;;;;N;;;;; +1D74A;MATHEMATICAL BOLD ITALIC SMALL UPSILON;Ll;0;L; 03C5;;;;N;;;;; +1D74B;MATHEMATICAL BOLD ITALIC SMALL PHI;Ll;0;L; 03C6;;;;N;;;;; +1D74C;MATHEMATICAL BOLD ITALIC SMALL CHI;Ll;0;L; 03C7;;;;N;;;;; +1D74D;MATHEMATICAL BOLD ITALIC SMALL PSI;Ll;0;L; 03C8;;;;N;;;;; +1D74E;MATHEMATICAL BOLD ITALIC SMALL OMEGA;Ll;0;L; 03C9;;;;N;;;;; +1D74F;MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;ON; 2202;;;;Y;;;;; +1D750;MATHEMATICAL BOLD ITALIC EPSILON SYMBOL;Ll;0;L; 03F5;;;;N;;;;; +1D751;MATHEMATICAL BOLD ITALIC THETA SYMBOL;Ll;0;L; 03D1;;;;N;;;;; +1D752;MATHEMATICAL BOLD ITALIC KAPPA SYMBOL;Ll;0;L; 03F0;;;;N;;;;; +1D753;MATHEMATICAL BOLD ITALIC PHI SYMBOL;Ll;0;L; 03D5;;;;N;;;;; +1D754;MATHEMATICAL BOLD ITALIC RHO SYMBOL;Ll;0;L; 03F1;;;;N;;;;; +1D755;MATHEMATICAL BOLD ITALIC PI SYMBOL;Ll;0;L; 03D6;;;;N;;;;; +1D756;MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA;Lu;0;L; 0391;;;;N;;;;; +1D757;MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA;Lu;0;L; 0392;;;;N;;;;; +1D758;MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; +1D759;MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA;Lu;0;L; 0394;;;;N;;;;; +1D75A;MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON;Lu;0;L; 0395;;;;N;;;;; +1D75B;MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA;Lu;0;L; 0396;;;;N;;;;; +1D75C;MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA;Lu;0;L; 0397;;;;N;;;;; +1D75D;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA;Lu;0;L; 0398;;;;N;;;;; +1D75E;MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA;Lu;0;L; 0399;;;;N;;;;; +1D75F;MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA;Lu;0;L; 039A;;;;N;;;;; +1D760;MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA;Lu;0;L; 039B;;;;N;;;;; +1D761;MATHEMATICAL SANS-SERIF BOLD CAPITAL MU;Lu;0;L; 039C;;;;N;;;;; +1D762;MATHEMATICAL SANS-SERIF BOLD CAPITAL NU;Lu;0;L; 039D;;;;N;;;;; +1D763;MATHEMATICAL SANS-SERIF BOLD CAPITAL XI;Lu;0;L; 039E;;;;N;;;;; +1D764;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON;Lu;0;L; 039F;;;;N;;;;; +1D765;MATHEMATICAL SANS-SERIF BOLD CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; +1D766;MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO;Lu;0;L; 03A1;;;;N;;;;; +1D767;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL;Lu;0;L; 03F4;;;;N;;;;; +1D768;MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA;Lu;0;L; 03A3;;;;N;;;;; +1D769;MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU;Lu;0;L; 03A4;;;;N;;;;; +1D76A;MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON;Lu;0;L; 03A5;;;;N;;;;; +1D76B;MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI;Lu;0;L; 03A6;;;;N;;;;; +1D76C;MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI;Lu;0;L; 03A7;;;;N;;;;; +1D76D;MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI;Lu;0;L; 03A8;;;;N;;;;; +1D76E;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA;Lu;0;L; 03A9;;;;N;;;;; +1D76F;MATHEMATICAL SANS-SERIF BOLD NABLA;Sm;0;ON; 2207;;;;N;;;;; +1D770;MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA;Ll;0;L; 03B1;;;;N;;;;; +1D771;MATHEMATICAL SANS-SERIF BOLD SMALL BETA;Ll;0;L; 03B2;;;;N;;;;; +1D772;MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; +1D773;MATHEMATICAL SANS-SERIF BOLD SMALL DELTA;Ll;0;L; 03B4;;;;N;;;;; +1D774;MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON;Ll;0;L; 03B5;;;;N;;;;; +1D775;MATHEMATICAL SANS-SERIF BOLD SMALL ZETA;Ll;0;L; 03B6;;;;N;;;;; +1D776;MATHEMATICAL SANS-SERIF BOLD SMALL ETA;Ll;0;L; 03B7;;;;N;;;;; +1D777;MATHEMATICAL SANS-SERIF BOLD SMALL THETA;Ll;0;L; 03B8;;;;N;;;;; +1D778;MATHEMATICAL SANS-SERIF BOLD SMALL IOTA;Ll;0;L; 03B9;;;;N;;;;; +1D779;MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA;Ll;0;L; 03BA;;;;N;;;;; +1D77A;MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA;Ll;0;L; 03BB;;;;N;;;;; +1D77B;MATHEMATICAL SANS-SERIF BOLD SMALL MU;Ll;0;L; 03BC;;;;N;;;;; +1D77C;MATHEMATICAL SANS-SERIF BOLD SMALL NU;Ll;0;L; 03BD;;;;N;;;;; +1D77D;MATHEMATICAL SANS-SERIF BOLD SMALL XI;Ll;0;L; 03BE;;;;N;;;;; +1D77E;MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON;Ll;0;L; 03BF;;;;N;;;;; +1D77F;MATHEMATICAL SANS-SERIF BOLD SMALL PI;Ll;0;L; 03C0;;;;N;;;;; +1D780;MATHEMATICAL SANS-SERIF BOLD SMALL RHO;Ll;0;L; 03C1;;;;N;;;;; +1D781;MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA;Ll;0;L; 03C2;;;;N;;;;; +1D782;MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA;Ll;0;L; 03C3;;;;N;;;;; +1D783;MATHEMATICAL SANS-SERIF BOLD SMALL TAU;Ll;0;L; 03C4;;;;N;;;;; +1D784;MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON;Ll;0;L; 03C5;;;;N;;;;; +1D785;MATHEMATICAL SANS-SERIF BOLD SMALL PHI;Ll;0;L; 03C6;;;;N;;;;; +1D786;MATHEMATICAL SANS-SERIF BOLD SMALL CHI;Ll;0;L; 03C7;;;;N;;;;; +1D787;MATHEMATICAL SANS-SERIF BOLD SMALL PSI;Ll;0;L; 03C8;;;;N;;;;; +1D788;MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA;Ll;0;L; 03C9;;;;N;;;;; +1D789;MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL;Sm;0;ON; 2202;;;;Y;;;;; +1D78A;MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL;Ll;0;L; 03F5;;;;N;;;;; +1D78B;MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL;Ll;0;L; 03D1;;;;N;;;;; +1D78C;MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL;Ll;0;L; 03F0;;;;N;;;;; +1D78D;MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL;Ll;0;L; 03D5;;;;N;;;;; +1D78E;MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL;Ll;0;L; 03F1;;;;N;;;;; +1D78F;MATHEMATICAL SANS-SERIF BOLD PI SYMBOL;Ll;0;L; 03D6;;;;N;;;;; +1D790;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA;Lu;0;L; 0391;;;;N;;;;; +1D791;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA;Lu;0;L; 0392;;;;N;;;;; +1D792;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; +1D793;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA;Lu;0;L; 0394;;;;N;;;;; +1D794;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON;Lu;0;L; 0395;;;;N;;;;; +1D795;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA;Lu;0;L; 0396;;;;N;;;;; +1D796;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA;Lu;0;L; 0397;;;;N;;;;; +1D797;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA;Lu;0;L; 0398;;;;N;;;;; +1D798;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA;Lu;0;L; 0399;;;;N;;;;; +1D799;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA;Lu;0;L; 039A;;;;N;;;;; +1D79A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA;Lu;0;L; 039B;;;;N;;;;; +1D79B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU;Lu;0;L; 039C;;;;N;;;;; +1D79C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU;Lu;0;L; 039D;;;;N;;;;; +1D79D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI;Lu;0;L; 039E;;;;N;;;;; +1D79E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON;Lu;0;L; 039F;;;;N;;;;; +1D79F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; +1D7A0;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO;Lu;0;L; 03A1;;;;N;;;;; +1D7A1;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L; 03F4;;;;N;;;;; +1D7A2;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA;Lu;0;L; 03A3;;;;N;;;;; +1D7A3;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU;Lu;0;L; 03A4;;;;N;;;;; +1D7A4;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON;Lu;0;L; 03A5;;;;N;;;;; +1D7A5;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI;Lu;0;L; 03A6;;;;N;;;;; +1D7A6;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI;Lu;0;L; 03A7;;;;N;;;;; +1D7A7;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI;Lu;0;L; 03A8;;;;N;;;;; +1D7A8;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA;Lu;0;L; 03A9;;;;N;;;;; +1D7A9;MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA;Sm;0;ON; 2207;;;;N;;;;; +1D7AA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA;Ll;0;L; 03B1;;;;N;;;;; +1D7AB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA;Ll;0;L; 03B2;;;;N;;;;; +1D7AC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; +1D7AD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA;Ll;0;L; 03B4;;;;N;;;;; +1D7AE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON;Ll;0;L; 03B5;;;;N;;;;; +1D7AF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA;Ll;0;L; 03B6;;;;N;;;;; +1D7B0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA;Ll;0;L; 03B7;;;;N;;;;; +1D7B1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA;Ll;0;L; 03B8;;;;N;;;;; +1D7B2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA;Ll;0;L; 03B9;;;;N;;;;; +1D7B3;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA;Ll;0;L; 03BA;;;;N;;;;; +1D7B4;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA;Ll;0;L; 03BB;;;;N;;;;; +1D7B5;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU;Ll;0;L; 03BC;;;;N;;;;; +1D7B6;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU;Ll;0;L; 03BD;;;;N;;;;; +1D7B7;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI;Ll;0;L; 03BE;;;;N;;;;; +1D7B8;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON;Ll;0;L; 03BF;;;;N;;;;; +1D7B9;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI;Ll;0;L; 03C0;;;;N;;;;; +1D7BA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO;Ll;0;L; 03C1;;;;N;;;;; +1D7BB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L; 03C2;;;;N;;;;; +1D7BC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA;Ll;0;L; 03C3;;;;N;;;;; +1D7BD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU;Ll;0;L; 03C4;;;;N;;;;; +1D7BE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON;Ll;0;L; 03C5;;;;N;;;;; +1D7BF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI;Ll;0;L; 03C6;;;;N;;;;; +1D7C0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI;Ll;0;L; 03C7;;;;N;;;;; +1D7C1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI;Ll;0;L; 03C8;;;;N;;;;; +1D7C2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA;Ll;0;L; 03C9;;;;N;;;;; +1D7C3;MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;ON; 2202;;;;Y;;;;; +1D7C4;MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL;Ll;0;L; 03F5;;;;N;;;;; +1D7C5;MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL;Ll;0;L; 03D1;;;;N;;;;; +1D7C6;MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL;Ll;0;L; 03F0;;;;N;;;;; +1D7C7;MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL;Ll;0;L; 03D5;;;;N;;;;; +1D7C8;MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL;Ll;0;L; 03F1;;;;N;;;;; +1D7C9;MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL;Ll;0;L; 03D6;;;;N;;;;; +1D7CA;MATHEMATICAL BOLD CAPITAL DIGAMMA;Lu;0;L; 03DC;;;;N;;;;; +1D7CB;MATHEMATICAL BOLD SMALL DIGAMMA;Ll;0;L; 03DD;;;;N;;;;; +1D7CE;MATHEMATICAL BOLD DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; +1D7CF;MATHEMATICAL BOLD DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; +1D7D0;MATHEMATICAL BOLD DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; +1D7D1;MATHEMATICAL BOLD DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; +1D7D2;MATHEMATICAL BOLD DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; +1D7D3;MATHEMATICAL BOLD DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; +1D7D4;MATHEMATICAL BOLD DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; +1D7D5;MATHEMATICAL BOLD DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; +1D7D6;MATHEMATICAL BOLD DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; +1D7D7;MATHEMATICAL BOLD DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +1D7D8;MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; +1D7D9;MATHEMATICAL DOUBLE-STRUCK DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; +1D7DA;MATHEMATICAL DOUBLE-STRUCK DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; +1D7DB;MATHEMATICAL DOUBLE-STRUCK DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; +1D7DC;MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; +1D7DD;MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; +1D7DE;MATHEMATICAL DOUBLE-STRUCK DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; +1D7DF;MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; +1D7E0;MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; +1D7E1;MATHEMATICAL DOUBLE-STRUCK DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +1D7E2;MATHEMATICAL SANS-SERIF DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; +1D7E3;MATHEMATICAL SANS-SERIF DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; +1D7E4;MATHEMATICAL SANS-SERIF DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; +1D7E5;MATHEMATICAL SANS-SERIF DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; +1D7E6;MATHEMATICAL SANS-SERIF DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; +1D7E7;MATHEMATICAL SANS-SERIF DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; +1D7E8;MATHEMATICAL SANS-SERIF DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; +1D7E9;MATHEMATICAL SANS-SERIF DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; +1D7EA;MATHEMATICAL SANS-SERIF DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; +1D7EB;MATHEMATICAL SANS-SERIF DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +1D7EC;MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; +1D7ED;MATHEMATICAL SANS-SERIF BOLD DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; +1D7EE;MATHEMATICAL SANS-SERIF BOLD DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; +1D7EF;MATHEMATICAL SANS-SERIF BOLD DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; +1D7F0;MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; +1D7F1;MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; +1D7F2;MATHEMATICAL SANS-SERIF BOLD DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; +1D7F3;MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; +1D7F4;MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; +1D7F5;MATHEMATICAL SANS-SERIF BOLD DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +1D7F6;MATHEMATICAL MONOSPACE DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; +1D7F7;MATHEMATICAL MONOSPACE DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; +1D7F8;MATHEMATICAL MONOSPACE DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; +1D7F9;MATHEMATICAL MONOSPACE DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; +1D7FA;MATHEMATICAL MONOSPACE DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; +1D7FB;MATHEMATICAL MONOSPACE DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; +1D7FC;MATHEMATICAL MONOSPACE DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; +1D7FD;MATHEMATICAL MONOSPACE DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; +1D7FE;MATHEMATICAL MONOSPACE DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; +1D7FF;MATHEMATICAL MONOSPACE DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +1D800;SIGNWRITING HAND-FIST INDEX;So;0;L;;;;;N;;;;; +1D801;SIGNWRITING HAND-CIRCLE INDEX;So;0;L;;;;;N;;;;; +1D802;SIGNWRITING HAND-CUP INDEX;So;0;L;;;;;N;;;;; +1D803;SIGNWRITING HAND-OVAL INDEX;So;0;L;;;;;N;;;;; +1D804;SIGNWRITING HAND-HINGE INDEX;So;0;L;;;;;N;;;;; +1D805;SIGNWRITING HAND-ANGLE INDEX;So;0;L;;;;;N;;;;; +1D806;SIGNWRITING HAND-FIST INDEX BENT;So;0;L;;;;;N;;;;; +1D807;SIGNWRITING HAND-CIRCLE INDEX BENT;So;0;L;;;;;N;;;;; +1D808;SIGNWRITING HAND-FIST THUMB UNDER INDEX BENT;So;0;L;;;;;N;;;;; +1D809;SIGNWRITING HAND-FIST INDEX RAISED KNUCKLE;So;0;L;;;;;N;;;;; +1D80A;SIGNWRITING HAND-FIST INDEX CUPPED;So;0;L;;;;;N;;;;; +1D80B;SIGNWRITING HAND-FIST INDEX HINGED;So;0;L;;;;;N;;;;; +1D80C;SIGNWRITING HAND-FIST INDEX HINGED LOW;So;0;L;;;;;N;;;;; +1D80D;SIGNWRITING HAND-CIRCLE INDEX HINGE;So;0;L;;;;;N;;;;; +1D80E;SIGNWRITING HAND-FIST INDEX MIDDLE;So;0;L;;;;;N;;;;; +1D80F;SIGNWRITING HAND-CIRCLE INDEX MIDDLE;So;0;L;;;;;N;;;;; +1D810;SIGNWRITING HAND-FIST INDEX MIDDLE BENT;So;0;L;;;;;N;;;;; +1D811;SIGNWRITING HAND-FIST INDEX MIDDLE RAISED KNUCKLES;So;0;L;;;;;N;;;;; +1D812;SIGNWRITING HAND-FIST INDEX MIDDLE HINGED;So;0;L;;;;;N;;;;; +1D813;SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED;So;0;L;;;;;N;;;;; +1D814;SIGNWRITING HAND-FIST INDEX HINGED MIDDLE UP;So;0;L;;;;;N;;;;; +1D815;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED;So;0;L;;;;;N;;;;; +1D816;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED INDEX BENT;So;0;L;;;;;N;;;;; +1D817;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED MIDDLE BENT;So;0;L;;;;;N;;;;; +1D818;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED CUPPED;So;0;L;;;;;N;;;;; +1D819;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED HINGED;So;0;L;;;;;N;;;;; +1D81A;SIGNWRITING HAND-FIST INDEX MIDDLE CROSSED;So;0;L;;;;;N;;;;; +1D81B;SIGNWRITING HAND-CIRCLE INDEX MIDDLE CROSSED;So;0;L;;;;;N;;;;; +1D81C;SIGNWRITING HAND-FIST MIDDLE BENT OVER INDEX;So;0;L;;;;;N;;;;; +1D81D;SIGNWRITING HAND-FIST INDEX BENT OVER MIDDLE;So;0;L;;;;;N;;;;; +1D81E;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB;So;0;L;;;;;N;;;;; +1D81F;SIGNWRITING HAND-CIRCLE INDEX MIDDLE THUMB;So;0;L;;;;;N;;;;; +1D820;SIGNWRITING HAND-FIST INDEX MIDDLE STRAIGHT THUMB BENT;So;0;L;;;;;N;;;;; +1D821;SIGNWRITING HAND-FIST INDEX MIDDLE BENT THUMB STRAIGHT;So;0;L;;;;;N;;;;; +1D822;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB BENT;So;0;L;;;;;N;;;;; +1D823;SIGNWRITING HAND-FIST INDEX MIDDLE HINGED SPREAD THUMB SIDE;So;0;L;;;;;N;;;;; +1D824;SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED THUMB SIDE;So;0;L;;;;;N;;;;; +1D825;SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED THUMB CONJOINED;So;0;L;;;;;N;;;;; +1D826;SIGNWRITING HAND-FIST INDEX HINGED MIDDLE UP THUMB SIDE;So;0;L;;;;;N;;;;; +1D827;SIGNWRITING HAND-FIST INDEX MIDDLE UP SPREAD THUMB FORWARD;So;0;L;;;;;N;;;;; +1D828;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CUPPED;So;0;L;;;;;N;;;;; +1D829;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CIRCLED;So;0;L;;;;;N;;;;; +1D82A;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB HOOKED;So;0;L;;;;;N;;;;; +1D82B;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB HINGED;So;0;L;;;;;N;;;;; +1D82C;SIGNWRITING HAND-FIST THUMB BETWEEN INDEX MIDDLE STRAIGHT;So;0;L;;;;;N;;;;; +1D82D;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE;So;0;L;;;;;N;;;;; +1D82E;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE CONJOINED;So;0;L;;;;;N;;;;; +1D82F;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE BENT;So;0;L;;;;;N;;;;; +1D830;SIGNWRITING HAND-FIST MIDDLE THUMB HOOKED INDEX UP;So;0;L;;;;;N;;;;; +1D831;SIGNWRITING HAND-FIST INDEX THUMB HOOKED MIDDLE UP;So;0;L;;;;;N;;;;; +1D832;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED HINGED THUMB SIDE;So;0;L;;;;;N;;;;; +1D833;SIGNWRITING HAND-FIST INDEX MIDDLE CROSSED THUMB SIDE;So;0;L;;;;;N;;;;; +1D834;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB FORWARD;So;0;L;;;;;N;;;;; +1D835;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED CUPPED THUMB FORWARD;So;0;L;;;;;N;;;;; +1D836;SIGNWRITING HAND-FIST MIDDLE THUMB CUPPED INDEX UP;So;0;L;;;;;N;;;;; +1D837;SIGNWRITING HAND-FIST INDEX THUMB CUPPED MIDDLE UP;So;0;L;;;;;N;;;;; +1D838;SIGNWRITING HAND-FIST MIDDLE THUMB CIRCLED INDEX UP;So;0;L;;;;;N;;;;; +1D839;SIGNWRITING HAND-FIST MIDDLE THUMB CIRCLED INDEX HINGED;So;0;L;;;;;N;;;;; +1D83A;SIGNWRITING HAND-FIST INDEX THUMB ANGLED OUT MIDDLE UP;So;0;L;;;;;N;;;;; +1D83B;SIGNWRITING HAND-FIST INDEX THUMB ANGLED IN MIDDLE UP;So;0;L;;;;;N;;;;; +1D83C;SIGNWRITING HAND-FIST INDEX THUMB CIRCLED MIDDLE UP;So;0;L;;;;;N;;;;; +1D83D;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CONJOINED HINGED;So;0;L;;;;;N;;;;; +1D83E;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB ANGLED OUT;So;0;L;;;;;N;;;;; +1D83F;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB ANGLED;So;0;L;;;;;N;;;;; +1D840;SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED OUT INDEX UP;So;0;L;;;;;N;;;;; +1D841;SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED OUT INDEX CROSSED;So;0;L;;;;;N;;;;; +1D842;SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED INDEX UP;So;0;L;;;;;N;;;;; +1D843;SIGNWRITING HAND-FIST INDEX THUMB HOOKED MIDDLE HINGED;So;0;L;;;;;N;;;;; +1D844;SIGNWRITING HAND-FLAT FOUR FINGERS;So;0;L;;;;;N;;;;; +1D845;SIGNWRITING HAND-FLAT FOUR FINGERS BENT;So;0;L;;;;;N;;;;; +1D846;SIGNWRITING HAND-FLAT FOUR FINGERS HINGED;So;0;L;;;;;N;;;;; +1D847;SIGNWRITING HAND-FLAT FOUR FINGERS CONJOINED;So;0;L;;;;;N;;;;; +1D848;SIGNWRITING HAND-FLAT FOUR FINGERS CONJOINED SPLIT;So;0;L;;;;;N;;;;; +1D849;SIGNWRITING HAND-CLAW FOUR FINGERS CONJOINED;So;0;L;;;;;N;;;;; +1D84A;SIGNWRITING HAND-FIST FOUR FINGERS CONJOINED BENT;So;0;L;;;;;N;;;;; +1D84B;SIGNWRITING HAND-HINGE FOUR FINGERS CONJOINED;So;0;L;;;;;N;;;;; +1D84C;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;; +1D84D;SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;; +1D84E;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD FOUR BENT;So;0;L;;;;;N;;;;; +1D84F;SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD FOUR BENT;So;0;L;;;;;N;;;;; +1D850;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD BENT;So;0;L;;;;;N;;;;; +1D851;SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD BENT;So;0;L;;;;;N;;;;; +1D852;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD THUMB FORWARD;So;0;L;;;;;N;;;;; +1D853;SIGNWRITING HAND-CUP FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;; +1D854;SIGNWRITING HAND-CUP FIVE FINGERS SPREAD OPEN;So;0;L;;;;;N;;;;; +1D855;SIGNWRITING HAND-HINGE FIVE FINGERS SPREAD OPEN;So;0;L;;;;;N;;;;; +1D856;SIGNWRITING HAND-OVAL FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;; +1D857;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED;So;0;L;;;;;N;;;;; +1D858;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED THUMB SIDE;So;0;L;;;;;N;;;;; +1D859;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED NO THUMB;So;0;L;;;;;N;;;;; +1D85A;SIGNWRITING HAND-FLAT;So;0;L;;;;;N;;;;; +1D85B;SIGNWRITING HAND-FLAT BETWEEN PALM FACINGS;So;0;L;;;;;N;;;;; +1D85C;SIGNWRITING HAND-FLAT HEEL;So;0;L;;;;;N;;;;; +1D85D;SIGNWRITING HAND-FLAT THUMB SIDE;So;0;L;;;;;N;;;;; +1D85E;SIGNWRITING HAND-FLAT HEEL THUMB SIDE;So;0;L;;;;;N;;;;; +1D85F;SIGNWRITING HAND-FLAT THUMB BENT;So;0;L;;;;;N;;;;; +1D860;SIGNWRITING HAND-FLAT THUMB FORWARD;So;0;L;;;;;N;;;;; +1D861;SIGNWRITING HAND-FLAT SPLIT INDEX THUMB SIDE;So;0;L;;;;;N;;;;; +1D862;SIGNWRITING HAND-FLAT SPLIT CENTRE;So;0;L;;;;;N;;;;; +1D863;SIGNWRITING HAND-FLAT SPLIT CENTRE THUMB SIDE;So;0;L;;;;;N;;;;; +1D864;SIGNWRITING HAND-FLAT SPLIT CENTRE THUMB SIDE BENT;So;0;L;;;;;N;;;;; +1D865;SIGNWRITING HAND-FLAT SPLIT LITTLE;So;0;L;;;;;N;;;;; +1D866;SIGNWRITING HAND-CLAW;So;0;L;;;;;N;;;;; +1D867;SIGNWRITING HAND-CLAW THUMB SIDE;So;0;L;;;;;N;;;;; +1D868;SIGNWRITING HAND-CLAW NO THUMB;So;0;L;;;;;N;;;;; +1D869;SIGNWRITING HAND-CLAW THUMB FORWARD;So;0;L;;;;;N;;;;; +1D86A;SIGNWRITING HAND-HOOK CURLICUE;So;0;L;;;;;N;;;;; +1D86B;SIGNWRITING HAND-HOOK;So;0;L;;;;;N;;;;; +1D86C;SIGNWRITING HAND-CUP OPEN;So;0;L;;;;;N;;;;; +1D86D;SIGNWRITING HAND-CUP;So;0;L;;;;;N;;;;; +1D86E;SIGNWRITING HAND-CUP OPEN THUMB SIDE;So;0;L;;;;;N;;;;; +1D86F;SIGNWRITING HAND-CUP THUMB SIDE;So;0;L;;;;;N;;;;; +1D870;SIGNWRITING HAND-CUP OPEN NO THUMB;So;0;L;;;;;N;;;;; +1D871;SIGNWRITING HAND-CUP NO THUMB;So;0;L;;;;;N;;;;; +1D872;SIGNWRITING HAND-CUP OPEN THUMB FORWARD;So;0;L;;;;;N;;;;; +1D873;SIGNWRITING HAND-CUP THUMB FORWARD;So;0;L;;;;;N;;;;; +1D874;SIGNWRITING HAND-CURLICUE OPEN;So;0;L;;;;;N;;;;; +1D875;SIGNWRITING HAND-CURLICUE;So;0;L;;;;;N;;;;; +1D876;SIGNWRITING HAND-CIRCLE;So;0;L;;;;;N;;;;; +1D877;SIGNWRITING HAND-OVAL;So;0;L;;;;;N;;;;; +1D878;SIGNWRITING HAND-OVAL THUMB SIDE;So;0;L;;;;;N;;;;; +1D879;SIGNWRITING HAND-OVAL NO THUMB;So;0;L;;;;;N;;;;; +1D87A;SIGNWRITING HAND-OVAL THUMB FORWARD;So;0;L;;;;;N;;;;; +1D87B;SIGNWRITING HAND-HINGE OPEN;So;0;L;;;;;N;;;;; +1D87C;SIGNWRITING HAND-HINGE OPEN THUMB FORWARD;So;0;L;;;;;N;;;;; +1D87D;SIGNWRITING HAND-HINGE;So;0;L;;;;;N;;;;; +1D87E;SIGNWRITING HAND-HINGE SMALL;So;0;L;;;;;N;;;;; +1D87F;SIGNWRITING HAND-HINGE OPEN THUMB SIDE;So;0;L;;;;;N;;;;; +1D880;SIGNWRITING HAND-HINGE THUMB SIDE;So;0;L;;;;;N;;;;; +1D881;SIGNWRITING HAND-HINGE OPEN NO THUMB;So;0;L;;;;;N;;;;; +1D882;SIGNWRITING HAND-HINGE NO THUMB;So;0;L;;;;;N;;;;; +1D883;SIGNWRITING HAND-HINGE THUMB SIDE TOUCHING INDEX;So;0;L;;;;;N;;;;; +1D884;SIGNWRITING HAND-HINGE THUMB BETWEEN MIDDLE RING;So;0;L;;;;;N;;;;; +1D885;SIGNWRITING HAND-ANGLE;So;0;L;;;;;N;;;;; +1D886;SIGNWRITING HAND-FIST INDEX MIDDLE RING;So;0;L;;;;;N;;;;; +1D887;SIGNWRITING HAND-CIRCLE INDEX MIDDLE RING;So;0;L;;;;;N;;;;; +1D888;SIGNWRITING HAND-HINGE INDEX MIDDLE RING;So;0;L;;;;;N;;;;; +1D889;SIGNWRITING HAND-ANGLE INDEX MIDDLE RING;So;0;L;;;;;N;;;;; +1D88A;SIGNWRITING HAND-HINGE LITTLE;So;0;L;;;;;N;;;;; +1D88B;SIGNWRITING HAND-FIST INDEX MIDDLE RING BENT;So;0;L;;;;;N;;;;; +1D88C;SIGNWRITING HAND-FIST INDEX MIDDLE RING CONJOINED;So;0;L;;;;;N;;;;; +1D88D;SIGNWRITING HAND-HINGE INDEX MIDDLE RING CONJOINED;So;0;L;;;;;N;;;;; +1D88E;SIGNWRITING HAND-FIST LITTLE DOWN;So;0;L;;;;;N;;;;; +1D88F;SIGNWRITING HAND-FIST LITTLE DOWN RIPPLE STRAIGHT;So;0;L;;;;;N;;;;; +1D890;SIGNWRITING HAND-FIST LITTLE DOWN RIPPLE CURVED;So;0;L;;;;;N;;;;; +1D891;SIGNWRITING HAND-FIST LITTLE DOWN OTHERS CIRCLED;So;0;L;;;;;N;;;;; +1D892;SIGNWRITING HAND-FIST LITTLE UP;So;0;L;;;;;N;;;;; +1D893;SIGNWRITING HAND-FIST THUMB UNDER LITTLE UP;So;0;L;;;;;N;;;;; +1D894;SIGNWRITING HAND-CIRCLE LITTLE UP;So;0;L;;;;;N;;;;; +1D895;SIGNWRITING HAND-OVAL LITTLE UP;So;0;L;;;;;N;;;;; +1D896;SIGNWRITING HAND-ANGLE LITTLE UP;So;0;L;;;;;N;;;;; +1D897;SIGNWRITING HAND-FIST LITTLE RAISED KNUCKLE;So;0;L;;;;;N;;;;; +1D898;SIGNWRITING HAND-FIST LITTLE BENT;So;0;L;;;;;N;;;;; +1D899;SIGNWRITING HAND-FIST LITTLE TOUCHES THUMB;So;0;L;;;;;N;;;;; +1D89A;SIGNWRITING HAND-FIST LITTLE THUMB;So;0;L;;;;;N;;;;; +1D89B;SIGNWRITING HAND-HINGE LITTLE THUMB;So;0;L;;;;;N;;;;; +1D89C;SIGNWRITING HAND-FIST LITTLE INDEX THUMB;So;0;L;;;;;N;;;;; +1D89D;SIGNWRITING HAND-HINGE LITTLE INDEX THUMB;So;0;L;;;;;N;;;;; +1D89E;SIGNWRITING HAND-ANGLE LITTLE INDEX THUMB INDEX THUMB OUT;So;0;L;;;;;N;;;;; +1D89F;SIGNWRITING HAND-ANGLE LITTLE INDEX THUMB INDEX THUMB;So;0;L;;;;;N;;;;; +1D8A0;SIGNWRITING HAND-FIST LITTLE INDEX;So;0;L;;;;;N;;;;; +1D8A1;SIGNWRITING HAND-CIRCLE LITTLE INDEX;So;0;L;;;;;N;;;;; +1D8A2;SIGNWRITING HAND-HINGE LITTLE INDEX;So;0;L;;;;;N;;;;; +1D8A3;SIGNWRITING HAND-ANGLE LITTLE INDEX;So;0;L;;;;;N;;;;; +1D8A4;SIGNWRITING HAND-FIST INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;; +1D8A5;SIGNWRITING HAND-CIRCLE INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;; +1D8A6;SIGNWRITING HAND-HINGE INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;; +1D8A7;SIGNWRITING HAND-HINGE RING;So;0;L;;;;;N;;;;; +1D8A8;SIGNWRITING HAND-ANGLE INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;; +1D8A9;SIGNWRITING HAND-FIST INDEX MIDDLE CROSS LITTLE;So;0;L;;;;;N;;;;; +1D8AA;SIGNWRITING HAND-CIRCLE INDEX MIDDLE CROSS LITTLE;So;0;L;;;;;N;;;;; +1D8AB;SIGNWRITING HAND-FIST RING DOWN;So;0;L;;;;;N;;;;; +1D8AC;SIGNWRITING HAND-HINGE RING DOWN INDEX THUMB HOOK MIDDLE;So;0;L;;;;;N;;;;; +1D8AD;SIGNWRITING HAND-ANGLE RING DOWN MIDDLE THUMB INDEX CROSS;So;0;L;;;;;N;;;;; +1D8AE;SIGNWRITING HAND-FIST RING UP;So;0;L;;;;;N;;;;; +1D8AF;SIGNWRITING HAND-FIST RING RAISED KNUCKLE;So;0;L;;;;;N;;;;; +1D8B0;SIGNWRITING HAND-FIST RING LITTLE;So;0;L;;;;;N;;;;; +1D8B1;SIGNWRITING HAND-CIRCLE RING LITTLE;So;0;L;;;;;N;;;;; +1D8B2;SIGNWRITING HAND-OVAL RING LITTLE;So;0;L;;;;;N;;;;; +1D8B3;SIGNWRITING HAND-ANGLE RING LITTLE;So;0;L;;;;;N;;;;; +1D8B4;SIGNWRITING HAND-FIST RING MIDDLE;So;0;L;;;;;N;;;;; +1D8B5;SIGNWRITING HAND-FIST RING MIDDLE CONJOINED;So;0;L;;;;;N;;;;; +1D8B6;SIGNWRITING HAND-FIST RING MIDDLE RAISED KNUCKLES;So;0;L;;;;;N;;;;; +1D8B7;SIGNWRITING HAND-FIST RING INDEX;So;0;L;;;;;N;;;;; +1D8B8;SIGNWRITING HAND-FIST RING THUMB;So;0;L;;;;;N;;;;; +1D8B9;SIGNWRITING HAND-HOOK RING THUMB;So;0;L;;;;;N;;;;; +1D8BA;SIGNWRITING HAND-FIST INDEX RING LITTLE;So;0;L;;;;;N;;;;; +1D8BB;SIGNWRITING HAND-CIRCLE INDEX RING LITTLE;So;0;L;;;;;N;;;;; +1D8BC;SIGNWRITING HAND-CURLICUE INDEX RING LITTLE ON;So;0;L;;;;;N;;;;; +1D8BD;SIGNWRITING HAND-HOOK INDEX RING LITTLE OUT;So;0;L;;;;;N;;;;; +1D8BE;SIGNWRITING HAND-HOOK INDEX RING LITTLE IN;So;0;L;;;;;N;;;;; +1D8BF;SIGNWRITING HAND-HOOK INDEX RING LITTLE UNDER;So;0;L;;;;;N;;;;; +1D8C0;SIGNWRITING HAND-CUP INDEX RING LITTLE;So;0;L;;;;;N;;;;; +1D8C1;SIGNWRITING HAND-HINGE INDEX RING LITTLE;So;0;L;;;;;N;;;;; +1D8C2;SIGNWRITING HAND-ANGLE INDEX RING LITTLE OUT;So;0;L;;;;;N;;;;; +1D8C3;SIGNWRITING HAND-ANGLE INDEX RING LITTLE;So;0;L;;;;;N;;;;; +1D8C4;SIGNWRITING HAND-FIST MIDDLE DOWN;So;0;L;;;;;N;;;;; +1D8C5;SIGNWRITING HAND-HINGE MIDDLE;So;0;L;;;;;N;;;;; +1D8C6;SIGNWRITING HAND-FIST MIDDLE UP;So;0;L;;;;;N;;;;; +1D8C7;SIGNWRITING HAND-CIRCLE MIDDLE UP;So;0;L;;;;;N;;;;; +1D8C8;SIGNWRITING HAND-FIST MIDDLE RAISED KNUCKLE;So;0;L;;;;;N;;;;; +1D8C9;SIGNWRITING HAND-FIST MIDDLE UP THUMB SIDE;So;0;L;;;;;N;;;;; +1D8CA;SIGNWRITING HAND-HOOK MIDDLE THUMB;So;0;L;;;;;N;;;;; +1D8CB;SIGNWRITING HAND-FIST MIDDLE THUMB LITTLE;So;0;L;;;;;N;;;;; +1D8CC;SIGNWRITING HAND-FIST MIDDLE LITTLE;So;0;L;;;;;N;;;;; +1D8CD;SIGNWRITING HAND-FIST MIDDLE RING LITTLE;So;0;L;;;;;N;;;;; +1D8CE;SIGNWRITING HAND-CIRCLE MIDDLE RING LITTLE;So;0;L;;;;;N;;;;; +1D8CF;SIGNWRITING HAND-CURLICUE MIDDLE RING LITTLE ON;So;0;L;;;;;N;;;;; +1D8D0;SIGNWRITING HAND-CUP MIDDLE RING LITTLE;So;0;L;;;;;N;;;;; +1D8D1;SIGNWRITING HAND-HINGE MIDDLE RING LITTLE;So;0;L;;;;;N;;;;; +1D8D2;SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE OUT;So;0;L;;;;;N;;;;; +1D8D3;SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE IN;So;0;L;;;;;N;;;;; +1D8D4;SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE;So;0;L;;;;;N;;;;; +1D8D5;SIGNWRITING HAND-CIRCLE MIDDLE RING LITTLE BENT;So;0;L;;;;;N;;;;; +1D8D6;SIGNWRITING HAND-CLAW MIDDLE RING LITTLE CONJOINED;So;0;L;;;;;N;;;;; +1D8D7;SIGNWRITING HAND-CLAW MIDDLE RING LITTLE CONJOINED SIDE;So;0;L;;;;;N;;;;; +1D8D8;SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED OUT;So;0;L;;;;;N;;;;; +1D8D9;SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED IN;So;0;L;;;;;N;;;;; +1D8DA;SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED;So;0;L;;;;;N;;;;; +1D8DB;SIGNWRITING HAND-HINGE INDEX HINGED;So;0;L;;;;;N;;;;; +1D8DC;SIGNWRITING HAND-FIST INDEX THUMB SIDE;So;0;L;;;;;N;;;;; +1D8DD;SIGNWRITING HAND-HINGE INDEX THUMB SIDE;So;0;L;;;;;N;;;;; +1D8DE;SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB DIAGONAL;So;0;L;;;;;N;;;;; +1D8DF;SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB CONJOINED;So;0;L;;;;;N;;;;; +1D8E0;SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB BENT;So;0;L;;;;;N;;;;; +1D8E1;SIGNWRITING HAND-FIST INDEX THUMB SIDE INDEX BENT;So;0;L;;;;;N;;;;; +1D8E2;SIGNWRITING HAND-FIST INDEX THUMB SIDE BOTH BENT;So;0;L;;;;;N;;;;; +1D8E3;SIGNWRITING HAND-FIST INDEX THUMB SIDE INDEX HINGE;So;0;L;;;;;N;;;;; +1D8E4;SIGNWRITING HAND-FIST INDEX THUMB FORWARD INDEX STRAIGHT;So;0;L;;;;;N;;;;; +1D8E5;SIGNWRITING HAND-FIST INDEX THUMB FORWARD INDEX BENT;So;0;L;;;;;N;;;;; +1D8E6;SIGNWRITING HAND-FIST INDEX THUMB HOOK;So;0;L;;;;;N;;;;; +1D8E7;SIGNWRITING HAND-FIST INDEX THUMB CURLICUE;So;0;L;;;;;N;;;;; +1D8E8;SIGNWRITING HAND-FIST INDEX THUMB CURVE THUMB INSIDE;So;0;L;;;;;N;;;;; +1D8E9;SIGNWRITING HAND-CLAW INDEX THUMB CURVE THUMB INSIDE;So;0;L;;;;;N;;;;; +1D8EA;SIGNWRITING HAND-FIST INDEX THUMB CURVE THUMB UNDER;So;0;L;;;;;N;;;;; +1D8EB;SIGNWRITING HAND-FIST INDEX THUMB CIRCLE;So;0;L;;;;;N;;;;; +1D8EC;SIGNWRITING HAND-CUP INDEX THUMB;So;0;L;;;;;N;;;;; +1D8ED;SIGNWRITING HAND-CUP INDEX THUMB OPEN;So;0;L;;;;;N;;;;; +1D8EE;SIGNWRITING HAND-HINGE INDEX THUMB OPEN;So;0;L;;;;;N;;;;; +1D8EF;SIGNWRITING HAND-HINGE INDEX THUMB LARGE;So;0;L;;;;;N;;;;; +1D8F0;SIGNWRITING HAND-HINGE INDEX THUMB;So;0;L;;;;;N;;;;; +1D8F1;SIGNWRITING HAND-HINGE INDEX THUMB SMALL;So;0;L;;;;;N;;;;; +1D8F2;SIGNWRITING HAND-ANGLE INDEX THUMB OUT;So;0;L;;;;;N;;;;; +1D8F3;SIGNWRITING HAND-ANGLE INDEX THUMB IN;So;0;L;;;;;N;;;;; +1D8F4;SIGNWRITING HAND-ANGLE INDEX THUMB;So;0;L;;;;;N;;;;; +1D8F5;SIGNWRITING HAND-FIST THUMB;So;0;L;;;;;N;;;;; +1D8F6;SIGNWRITING HAND-FIST THUMB HEEL;So;0;L;;;;;N;;;;; +1D8F7;SIGNWRITING HAND-FIST THUMB SIDE DIAGONAL;So;0;L;;;;;N;;;;; +1D8F8;SIGNWRITING HAND-FIST THUMB SIDE CONJOINED;So;0;L;;;;;N;;;;; +1D8F9;SIGNWRITING HAND-FIST THUMB SIDE BENT;So;0;L;;;;;N;;;;; +1D8FA;SIGNWRITING HAND-FIST THUMB FORWARD;So;0;L;;;;;N;;;;; +1D8FB;SIGNWRITING HAND-FIST THUMB BETWEEN INDEX MIDDLE;So;0;L;;;;;N;;;;; +1D8FC;SIGNWRITING HAND-FIST THUMB BETWEEN MIDDLE RING;So;0;L;;;;;N;;;;; +1D8FD;SIGNWRITING HAND-FIST THUMB BETWEEN RING LITTLE;So;0;L;;;;;N;;;;; +1D8FE;SIGNWRITING HAND-FIST THUMB UNDER TWO FINGERS;So;0;L;;;;;N;;;;; +1D8FF;SIGNWRITING HAND-FIST THUMB OVER TWO FINGERS;So;0;L;;;;;N;;;;; +1D900;SIGNWRITING HAND-FIST THUMB UNDER THREE FINGERS;So;0;L;;;;;N;;;;; +1D901;SIGNWRITING HAND-FIST THUMB UNDER FOUR FINGERS;So;0;L;;;;;N;;;;; +1D902;SIGNWRITING HAND-FIST THUMB OVER FOUR RAISED KNUCKLES;So;0;L;;;;;N;;;;; +1D903;SIGNWRITING HAND-FIST;So;0;L;;;;;N;;;;; +1D904;SIGNWRITING HAND-FIST HEEL;So;0;L;;;;;N;;;;; +1D905;SIGNWRITING TOUCH SINGLE;So;0;L;;;;;N;;;;; +1D906;SIGNWRITING TOUCH MULTIPLE;So;0;L;;;;;N;;;;; +1D907;SIGNWRITING TOUCH BETWEEN;So;0;L;;;;;N;;;;; +1D908;SIGNWRITING GRASP SINGLE;So;0;L;;;;;N;;;;; +1D909;SIGNWRITING GRASP MULTIPLE;So;0;L;;;;;N;;;;; +1D90A;SIGNWRITING GRASP BETWEEN;So;0;L;;;;;N;;;;; +1D90B;SIGNWRITING STRIKE SINGLE;So;0;L;;;;;N;;;;; +1D90C;SIGNWRITING STRIKE MULTIPLE;So;0;L;;;;;N;;;;; +1D90D;SIGNWRITING STRIKE BETWEEN;So;0;L;;;;;N;;;;; +1D90E;SIGNWRITING BRUSH SINGLE;So;0;L;;;;;N;;;;; +1D90F;SIGNWRITING BRUSH MULTIPLE;So;0;L;;;;;N;;;;; +1D910;SIGNWRITING BRUSH BETWEEN;So;0;L;;;;;N;;;;; +1D911;SIGNWRITING RUB SINGLE;So;0;L;;;;;N;;;;; +1D912;SIGNWRITING RUB MULTIPLE;So;0;L;;;;;N;;;;; +1D913;SIGNWRITING RUB BETWEEN;So;0;L;;;;;N;;;;; +1D914;SIGNWRITING SURFACE SYMBOLS;So;0;L;;;;;N;;;;; +1D915;SIGNWRITING SURFACE BETWEEN;So;0;L;;;;;N;;;;; +1D916;SIGNWRITING SQUEEZE LARGE SINGLE;So;0;L;;;;;N;;;;; +1D917;SIGNWRITING SQUEEZE SMALL SINGLE;So;0;L;;;;;N;;;;; +1D918;SIGNWRITING SQUEEZE LARGE MULTIPLE;So;0;L;;;;;N;;;;; +1D919;SIGNWRITING SQUEEZE SMALL MULTIPLE;So;0;L;;;;;N;;;;; +1D91A;SIGNWRITING SQUEEZE SEQUENTIAL;So;0;L;;;;;N;;;;; +1D91B;SIGNWRITING FLICK LARGE SINGLE;So;0;L;;;;;N;;;;; +1D91C;SIGNWRITING FLICK SMALL SINGLE;So;0;L;;;;;N;;;;; +1D91D;SIGNWRITING FLICK LARGE MULTIPLE;So;0;L;;;;;N;;;;; +1D91E;SIGNWRITING FLICK SMALL MULTIPLE;So;0;L;;;;;N;;;;; +1D91F;SIGNWRITING FLICK SEQUENTIAL;So;0;L;;;;;N;;;;; +1D920;SIGNWRITING SQUEEZE FLICK ALTERNATING;So;0;L;;;;;N;;;;; +1D921;SIGNWRITING MOVEMENT-HINGE UP DOWN LARGE;So;0;L;;;;;N;;;;; +1D922;SIGNWRITING MOVEMENT-HINGE UP DOWN SMALL;So;0;L;;;;;N;;;;; +1D923;SIGNWRITING MOVEMENT-HINGE UP SEQUENTIAL;So;0;L;;;;;N;;;;; +1D924;SIGNWRITING MOVEMENT-HINGE DOWN SEQUENTIAL;So;0;L;;;;;N;;;;; +1D925;SIGNWRITING MOVEMENT-HINGE UP DOWN ALTERNATING LARGE;So;0;L;;;;;N;;;;; +1D926;SIGNWRITING MOVEMENT-HINGE UP DOWN ALTERNATING SMALL;So;0;L;;;;;N;;;;; +1D927;SIGNWRITING MOVEMENT-HINGE SIDE TO SIDE SCISSORS;So;0;L;;;;;N;;;;; +1D928;SIGNWRITING MOVEMENT-WALLPLANE FINGER CONTACT;So;0;L;;;;;N;;;;; +1D929;SIGNWRITING MOVEMENT-FLOORPLANE FINGER CONTACT;So;0;L;;;;;N;;;;; +1D92A;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT SMALL;So;0;L;;;;;N;;;;; +1D92B;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT MEDIUM;So;0;L;;;;;N;;;;; +1D92C;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT LARGE;So;0;L;;;;;N;;;;; +1D92D;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT LARGEST;So;0;L;;;;;N;;;;; +1D92E;SIGNWRITING MOVEMENT-WALLPLANE SINGLE WRIST FLEX;So;0;L;;;;;N;;;;; +1D92F;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE STRAIGHT;So;0;L;;;;;N;;;;; +1D930;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE WRIST FLEX;So;0;L;;;;;N;;;;; +1D931;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE ALTERNATING;So;0;L;;;;;N;;;;; +1D932;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;; +1D933;SIGNWRITING MOVEMENT-WALLPLANE CROSS;So;0;L;;;;;N;;;;; +1D934;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE STRAIGHT MOVEMENT;So;0;L;;;;;N;;;;; +1D935;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE WRIST FLEX;So;0;L;;;;;N;;;;; +1D936;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE ALTERNATING;So;0;L;;;;;N;;;;; +1D937;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;; +1D938;SIGNWRITING MOVEMENT-WALLPLANE BEND SMALL;So;0;L;;;;;N;;;;; +1D939;SIGNWRITING MOVEMENT-WALLPLANE BEND MEDIUM;So;0;L;;;;;N;;;;; +1D93A;SIGNWRITING MOVEMENT-WALLPLANE BEND LARGE;So;0;L;;;;;N;;;;; +1D93B;SIGNWRITING MOVEMENT-WALLPLANE CORNER SMALL;So;0;L;;;;;N;;;;; +1D93C;SIGNWRITING MOVEMENT-WALLPLANE CORNER MEDIUM;So;0;L;;;;;N;;;;; +1D93D;SIGNWRITING MOVEMENT-WALLPLANE CORNER LARGE;So;0;L;;;;;N;;;;; +1D93E;SIGNWRITING MOVEMENT-WALLPLANE CORNER ROTATION;So;0;L;;;;;N;;;;; +1D93F;SIGNWRITING MOVEMENT-WALLPLANE CHECK SMALL;So;0;L;;;;;N;;;;; +1D940;SIGNWRITING MOVEMENT-WALLPLANE CHECK MEDIUM;So;0;L;;;;;N;;;;; +1D941;SIGNWRITING MOVEMENT-WALLPLANE CHECK LARGE;So;0;L;;;;;N;;;;; +1D942;SIGNWRITING MOVEMENT-WALLPLANE BOX SMALL;So;0;L;;;;;N;;;;; +1D943;SIGNWRITING MOVEMENT-WALLPLANE BOX MEDIUM;So;0;L;;;;;N;;;;; +1D944;SIGNWRITING MOVEMENT-WALLPLANE BOX LARGE;So;0;L;;;;;N;;;;; +1D945;SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG SMALL;So;0;L;;;;;N;;;;; +1D946;SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG MEDIUM;So;0;L;;;;;N;;;;; +1D947;SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG LARGE;So;0;L;;;;;N;;;;; +1D948;SIGNWRITING MOVEMENT-WALLPLANE PEAKS SMALL;So;0;L;;;;;N;;;;; +1D949;SIGNWRITING MOVEMENT-WALLPLANE PEAKS MEDIUM;So;0;L;;;;;N;;;;; +1D94A;SIGNWRITING MOVEMENT-WALLPLANE PEAKS LARGE;So;0;L;;;;;N;;;;; +1D94B;SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE SINGLE;So;0;L;;;;;N;;;;; +1D94C;SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE DOUBLE;So;0;L;;;;;N;;;;; +1D94D;SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE ALTERNATING;So;0;L;;;;;N;;;;; +1D94E;SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE SINGLE;So;0;L;;;;;N;;;;; +1D94F;SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE DOUBLE;So;0;L;;;;;N;;;;; +1D950;SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE ALTERNATING;So;0;L;;;;;N;;;;; +1D951;SIGNWRITING TRAVEL-WALLPLANE SHAKING;So;0;L;;;;;N;;;;; +1D952;SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL SINGLE;So;0;L;;;;;N;;;;; +1D953;SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL DOUBLE;So;0;L;;;;;N;;;;; +1D954;SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL TRIPLE;So;0;L;;;;;N;;;;; +1D955;SIGNWRITING MOVEMENT-DIAGONAL AWAY SMALL;So;0;L;;;;;N;;;;; +1D956;SIGNWRITING MOVEMENT-DIAGONAL AWAY MEDIUM;So;0;L;;;;;N;;;;; +1D957;SIGNWRITING MOVEMENT-DIAGONAL AWAY LARGE;So;0;L;;;;;N;;;;; +1D958;SIGNWRITING MOVEMENT-DIAGONAL AWAY LARGEST;So;0;L;;;;;N;;;;; +1D959;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS SMALL;So;0;L;;;;;N;;;;; +1D95A;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS MEDIUM;So;0;L;;;;;N;;;;; +1D95B;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS LARGE;So;0;L;;;;;N;;;;; +1D95C;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS LARGEST;So;0;L;;;;;N;;;;; +1D95D;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY SMALL;So;0;L;;;;;N;;;;; +1D95E;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY MEDIUM;So;0;L;;;;;N;;;;; +1D95F;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY LARGE;So;0;L;;;;;N;;;;; +1D960;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY LARGEST;So;0;L;;;;;N;;;;; +1D961;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS SMALL;So;0;L;;;;;N;;;;; +1D962;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS MEDIUM;So;0;L;;;;;N;;;;; +1D963;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS LARGE;So;0;L;;;;;N;;;;; +1D964;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS LARGEST;So;0;L;;;;;N;;;;; +1D965;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT SMALL;So;0;L;;;;;N;;;;; +1D966;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT MEDIUM;So;0;L;;;;;N;;;;; +1D967;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT LARGE;So;0;L;;;;;N;;;;; +1D968;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT LARGEST;So;0;L;;;;;N;;;;; +1D969;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE WRIST FLEX;So;0;L;;;;;N;;;;; +1D96A;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE STRAIGHT;So;0;L;;;;;N;;;;; +1D96B;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE WRIST FLEX;So;0;L;;;;;N;;;;; +1D96C;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE ALTERNATING;So;0;L;;;;;N;;;;; +1D96D;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;; +1D96E;SIGNWRITING MOVEMENT-FLOORPLANE CROSS;So;0;L;;;;;N;;;;; +1D96F;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE STRAIGHT MOVEMENT;So;0;L;;;;;N;;;;; +1D970;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE WRIST FLEX;So;0;L;;;;;N;;;;; +1D971;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE ALTERNATING MOVEMENT;So;0;L;;;;;N;;;;; +1D972;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;; +1D973;SIGNWRITING MOVEMENT-FLOORPLANE BEND;So;0;L;;;;;N;;;;; +1D974;SIGNWRITING MOVEMENT-FLOORPLANE CORNER SMALL;So;0;L;;;;;N;;;;; +1D975;SIGNWRITING MOVEMENT-FLOORPLANE CORNER MEDIUM;So;0;L;;;;;N;;;;; +1D976;SIGNWRITING MOVEMENT-FLOORPLANE CORNER LARGE;So;0;L;;;;;N;;;;; +1D977;SIGNWRITING MOVEMENT-FLOORPLANE CHECK;So;0;L;;;;;N;;;;; +1D978;SIGNWRITING MOVEMENT-FLOORPLANE BOX SMALL;So;0;L;;;;;N;;;;; +1D979;SIGNWRITING MOVEMENT-FLOORPLANE BOX MEDIUM;So;0;L;;;;;N;;;;; +1D97A;SIGNWRITING MOVEMENT-FLOORPLANE BOX LARGE;So;0;L;;;;;N;;;;; +1D97B;SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG SMALL;So;0;L;;;;;N;;;;; +1D97C;SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG MEDIUM;So;0;L;;;;;N;;;;; +1D97D;SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG LARGE;So;0;L;;;;;N;;;;; +1D97E;SIGNWRITING MOVEMENT-FLOORPLANE PEAKS SMALL;So;0;L;;;;;N;;;;; +1D97F;SIGNWRITING MOVEMENT-FLOORPLANE PEAKS MEDIUM;So;0;L;;;;;N;;;;; +1D980;SIGNWRITING MOVEMENT-FLOORPLANE PEAKS LARGE;So;0;L;;;;;N;;;;; +1D981;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE SINGLE;So;0;L;;;;;N;;;;; +1D982;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE DOUBLE;So;0;L;;;;;N;;;;; +1D983;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE ALTERNATING;So;0;L;;;;;N;;;;; +1D984;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE SINGLE;So;0;L;;;;;N;;;;; +1D985;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE DOUBLE;So;0;L;;;;;N;;;;; +1D986;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE ALTERNATING;So;0;L;;;;;N;;;;; +1D987;SIGNWRITING TRAVEL-FLOORPLANE SHAKING;So;0;L;;;;;N;;;;; +1D988;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER SMALL;So;0;L;;;;;N;;;;; +1D989;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER MEDIUM;So;0;L;;;;;N;;;;; +1D98A;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER LARGE;So;0;L;;;;;N;;;;; +1D98B;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER LARGEST;So;0;L;;;;;N;;;;; +1D98C;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE SMALL;So;0;L;;;;;N;;;;; +1D98D;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE MEDIUM;So;0;L;;;;;N;;;;; +1D98E;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE LARGE;So;0;L;;;;;N;;;;; +1D98F;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE LARGEST;So;0;L;;;;;N;;;;; +1D990;SIGNWRITING MOVEMENT-WALLPLANE CURVE THREE-QUARTER CIRCLE SMALL;So;0;L;;;;;N;;;;; +1D991;SIGNWRITING MOVEMENT-WALLPLANE CURVE THREE-QUARTER CIRCLE MEDIUM;So;0;L;;;;;N;;;;; +1D992;SIGNWRITING MOVEMENT-WALLPLANE HUMP SMALL;So;0;L;;;;;N;;;;; +1D993;SIGNWRITING MOVEMENT-WALLPLANE HUMP MEDIUM;So;0;L;;;;;N;;;;; +1D994;SIGNWRITING MOVEMENT-WALLPLANE HUMP LARGE;So;0;L;;;;;N;;;;; +1D995;SIGNWRITING MOVEMENT-WALLPLANE LOOP SMALL;So;0;L;;;;;N;;;;; +1D996;SIGNWRITING MOVEMENT-WALLPLANE LOOP MEDIUM;So;0;L;;;;;N;;;;; +1D997;SIGNWRITING MOVEMENT-WALLPLANE LOOP LARGE;So;0;L;;;;;N;;;;; +1D998;SIGNWRITING MOVEMENT-WALLPLANE LOOP SMALL DOUBLE;So;0;L;;;;;N;;;;; +1D999;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE SMALL;So;0;L;;;;;N;;;;; +1D99A;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE MEDIUM;So;0;L;;;;;N;;;;; +1D99B;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE LARGE;So;0;L;;;;;N;;;;; +1D99C;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE SMALL;So;0;L;;;;;N;;;;; +1D99D;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE MEDIUM;So;0;L;;;;;N;;;;; +1D99E;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE LARGE;So;0;L;;;;;N;;;;; +1D99F;SIGNWRITING MOVEMENT-WALLPLANE CURVE THEN STRAIGHT;So;0;L;;;;;N;;;;; +1D9A0;SIGNWRITING MOVEMENT-WALLPLANE CURVED CROSS SMALL;So;0;L;;;;;N;;;;; +1D9A1;SIGNWRITING MOVEMENT-WALLPLANE CURVED CROSS MEDIUM;So;0;L;;;;;N;;;;; +1D9A2;SIGNWRITING ROTATION-WALLPLANE SINGLE;So;0;L;;;;;N;;;;; +1D9A3;SIGNWRITING ROTATION-WALLPLANE DOUBLE;So;0;L;;;;;N;;;;; +1D9A4;SIGNWRITING ROTATION-WALLPLANE ALTERNATE;So;0;L;;;;;N;;;;; +1D9A5;SIGNWRITING MOVEMENT-WALLPLANE SHAKING;So;0;L;;;;;N;;;;; +1D9A6;SIGNWRITING MOVEMENT-WALLPLANE CURVE HITTING FRONT WALL;So;0;L;;;;;N;;;;; +1D9A7;SIGNWRITING MOVEMENT-WALLPLANE HUMP HITTING FRONT WALL;So;0;L;;;;;N;;;;; +1D9A8;SIGNWRITING MOVEMENT-WALLPLANE LOOP HITTING FRONT WALL;So;0;L;;;;;N;;;;; +1D9A9;SIGNWRITING MOVEMENT-WALLPLANE WAVE HITTING FRONT WALL;So;0;L;;;;;N;;;;; +1D9AA;SIGNWRITING ROTATION-WALLPLANE SINGLE HITTING FRONT WALL;So;0;L;;;;;N;;;;; +1D9AB;SIGNWRITING ROTATION-WALLPLANE DOUBLE HITTING FRONT WALL;So;0;L;;;;;N;;;;; +1D9AC;SIGNWRITING ROTATION-WALLPLANE ALTERNATING HITTING FRONT WALL;So;0;L;;;;;N;;;;; +1D9AD;SIGNWRITING MOVEMENT-WALLPLANE CURVE HITTING CHEST;So;0;L;;;;;N;;;;; +1D9AE;SIGNWRITING MOVEMENT-WALLPLANE HUMP HITTING CHEST;So;0;L;;;;;N;;;;; +1D9AF;SIGNWRITING MOVEMENT-WALLPLANE LOOP HITTING CHEST;So;0;L;;;;;N;;;;; +1D9B0;SIGNWRITING MOVEMENT-WALLPLANE WAVE HITTING CHEST;So;0;L;;;;;N;;;;; +1D9B1;SIGNWRITING ROTATION-WALLPLANE SINGLE HITTING CHEST;So;0;L;;;;;N;;;;; +1D9B2;SIGNWRITING ROTATION-WALLPLANE DOUBLE HITTING CHEST;So;0;L;;;;;N;;;;; +1D9B3;SIGNWRITING ROTATION-WALLPLANE ALTERNATING HITTING CHEST;So;0;L;;;;;N;;;;; +1D9B4;SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH SMALL;So;0;L;;;;;N;;;;; +1D9B5;SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH MEDIUM;So;0;L;;;;;N;;;;; +1D9B6;SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH LARGE;So;0;L;;;;;N;;;;; +1D9B7;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING CEILING SMALL;So;0;L;;;;;N;;;;; +1D9B8;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING CEILING LARGE;So;0;L;;;;;N;;;;; +1D9B9;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING SMALL DOUBLE;So;0;L;;;;;N;;;;; +1D9BA;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING LARGE DOUBLE;So;0;L;;;;;N;;;;; +1D9BB;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING SMALL TRIPLE;So;0;L;;;;;N;;;;; +1D9BC;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING LARGE TRIPLE;So;0;L;;;;;N;;;;; +1D9BD;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING SMALL SINGLE;So;0;L;;;;;N;;;;; +1D9BE;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING LARGE SINGLE;So;0;L;;;;;N;;;;; +1D9BF;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING SMALL DOUBLE;So;0;L;;;;;N;;;;; +1D9C0;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING LARGE DOUBLE;So;0;L;;;;;N;;;;; +1D9C1;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING CEILING SMALL;So;0;L;;;;;N;;;;; +1D9C2;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING CEILING LARGE;So;0;L;;;;;N;;;;; +1D9C3;SIGNWRITING ROTATION-FLOORPLANE SINGLE HITTING CEILING;So;0;L;;;;;N;;;;; +1D9C4;SIGNWRITING ROTATION-FLOORPLANE DOUBLE HITTING CEILING;So;0;L;;;;;N;;;;; +1D9C5;SIGNWRITING ROTATION-FLOORPLANE ALTERNATING HITTING CEILING;So;0;L;;;;;N;;;;; +1D9C6;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING FLOOR SMALL;So;0;L;;;;;N;;;;; +1D9C7;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING FLOOR LARGE;So;0;L;;;;;N;;;;; +1D9C8;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR SMALL DOUBLE;So;0;L;;;;;N;;;;; +1D9C9;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR LARGE DOUBLE;So;0;L;;;;;N;;;;; +1D9CA;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR TRIPLE SMALL TRIPLE;So;0;L;;;;;N;;;;; +1D9CB;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR TRIPLE LARGE TRIPLE;So;0;L;;;;;N;;;;; +1D9CC;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR SMALL SINGLE;So;0;L;;;;;N;;;;; +1D9CD;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR LARGE SINGLE;So;0;L;;;;;N;;;;; +1D9CE;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR SMALL DOUBLE;So;0;L;;;;;N;;;;; +1D9CF;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR LARGE DOUBLE;So;0;L;;;;;N;;;;; +1D9D0;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING FLOOR SMALL;So;0;L;;;;;N;;;;; +1D9D1;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING FLOOR LARGE;So;0;L;;;;;N;;;;; +1D9D2;SIGNWRITING ROTATION-FLOORPLANE SINGLE HITTING FLOOR;So;0;L;;;;;N;;;;; +1D9D3;SIGNWRITING ROTATION-FLOORPLANE DOUBLE HITTING FLOOR;So;0;L;;;;;N;;;;; +1D9D4;SIGNWRITING ROTATION-FLOORPLANE ALTERNATING HITTING FLOOR;So;0;L;;;;;N;;;;; +1D9D5;SIGNWRITING MOVEMENT-FLOORPLANE CURVE SMALL;So;0;L;;;;;N;;;;; +1D9D6;SIGNWRITING MOVEMENT-FLOORPLANE CURVE MEDIUM;So;0;L;;;;;N;;;;; +1D9D7;SIGNWRITING MOVEMENT-FLOORPLANE CURVE LARGE;So;0;L;;;;;N;;;;; +1D9D8;SIGNWRITING MOVEMENT-FLOORPLANE CURVE LARGEST;So;0;L;;;;;N;;;;; +1D9D9;SIGNWRITING MOVEMENT-FLOORPLANE CURVE COMBINED;So;0;L;;;;;N;;;;; +1D9DA;SIGNWRITING MOVEMENT-FLOORPLANE HUMP SMALL;So;0;L;;;;;N;;;;; +1D9DB;SIGNWRITING MOVEMENT-FLOORPLANE LOOP SMALL;So;0;L;;;;;N;;;;; +1D9DC;SIGNWRITING MOVEMENT-FLOORPLANE WAVE SNAKE;So;0;L;;;;;N;;;;; +1D9DD;SIGNWRITING MOVEMENT-FLOORPLANE WAVE SMALL;So;0;L;;;;;N;;;;; +1D9DE;SIGNWRITING MOVEMENT-FLOORPLANE WAVE LARGE;So;0;L;;;;;N;;;;; +1D9DF;SIGNWRITING ROTATION-FLOORPLANE SINGLE;So;0;L;;;;;N;;;;; +1D9E0;SIGNWRITING ROTATION-FLOORPLANE DOUBLE;So;0;L;;;;;N;;;;; +1D9E1;SIGNWRITING ROTATION-FLOORPLANE ALTERNATING;So;0;L;;;;;N;;;;; +1D9E2;SIGNWRITING MOVEMENT-FLOORPLANE SHAKING PARALLEL;So;0;L;;;;;N;;;;; +1D9E3;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE SMALL SINGLE;So;0;L;;;;;N;;;;; +1D9E4;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE MEDIUM SINGLE;So;0;L;;;;;N;;;;; +1D9E5;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE SMALL DOUBLE;So;0;L;;;;;N;;;;; +1D9E6;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE MEDIUM DOUBLE;So;0;L;;;;;N;;;;; +1D9E7;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL SMALL SINGLE;So;0;L;;;;;N;;;;; +1D9E8;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL MEDIUM SINGLE;So;0;L;;;;;N;;;;; +1D9E9;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL LARGE SINGLE;So;0;L;;;;;N;;;;; +1D9EA;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL SMALL DOUBLE;So;0;L;;;;;N;;;;; +1D9EB;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL MEDIUM DOUBLE;So;0;L;;;;;N;;;;; +1D9EC;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL LARGE DOUBLE;So;0;L;;;;;N;;;;; +1D9ED;SIGNWRITING MOVEMENT-WALLPLANE WRIST CIRCLE FRONT SINGLE;So;0;L;;;;;N;;;;; +1D9EE;SIGNWRITING MOVEMENT-WALLPLANE WRIST CIRCLE FRONT DOUBLE;So;0;L;;;;;N;;;;; +1D9EF;SIGNWRITING MOVEMENT-FLOORPLANE WRIST CIRCLE HITTING WALL SINGLE;So;0;L;;;;;N;;;;; +1D9F0;SIGNWRITING MOVEMENT-FLOORPLANE WRIST CIRCLE HITTING WALL DOUBLE;So;0;L;;;;;N;;;;; +1D9F1;SIGNWRITING MOVEMENT-WALLPLANE FINGER CIRCLES SINGLE;So;0;L;;;;;N;;;;; +1D9F2;SIGNWRITING MOVEMENT-WALLPLANE FINGER CIRCLES DOUBLE;So;0;L;;;;;N;;;;; +1D9F3;SIGNWRITING MOVEMENT-FLOORPLANE FINGER CIRCLES HITTING WALL SINGLE;So;0;L;;;;;N;;;;; +1D9F4;SIGNWRITING MOVEMENT-FLOORPLANE FINGER CIRCLES HITTING WALL DOUBLE;So;0;L;;;;;N;;;;; +1D9F5;SIGNWRITING DYNAMIC ARROWHEAD SMALL;So;0;L;;;;;N;;;;; +1D9F6;SIGNWRITING DYNAMIC ARROWHEAD LARGE;So;0;L;;;;;N;;;;; +1D9F7;SIGNWRITING DYNAMIC FAST;So;0;L;;;;;N;;;;; +1D9F8;SIGNWRITING DYNAMIC SLOW;So;0;L;;;;;N;;;;; +1D9F9;SIGNWRITING DYNAMIC TENSE;So;0;L;;;;;N;;;;; +1D9FA;SIGNWRITING DYNAMIC RELAXED;So;0;L;;;;;N;;;;; +1D9FB;SIGNWRITING DYNAMIC SIMULTANEOUS;So;0;L;;;;;N;;;;; +1D9FC;SIGNWRITING DYNAMIC SIMULTANEOUS ALTERNATING;So;0;L;;;;;N;;;;; +1D9FD;SIGNWRITING DYNAMIC EVERY OTHER TIME;So;0;L;;;;;N;;;;; +1D9FE;SIGNWRITING DYNAMIC GRADUAL;So;0;L;;;;;N;;;;; +1D9FF;SIGNWRITING HEAD;So;0;L;;;;;N;;;;; +1DA00;SIGNWRITING HEAD RIM;Mn;0;NSM;;;;;N;;;;; +1DA01;SIGNWRITING HEAD MOVEMENT-WALLPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;; +1DA02;SIGNWRITING HEAD MOVEMENT-WALLPLANE TILT;Mn;0;NSM;;;;;N;;;;; +1DA03;SIGNWRITING HEAD MOVEMENT-FLOORPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;; +1DA04;SIGNWRITING HEAD MOVEMENT-WALLPLANE CURVE;Mn;0;NSM;;;;;N;;;;; +1DA05;SIGNWRITING HEAD MOVEMENT-FLOORPLANE CURVE;Mn;0;NSM;;;;;N;;;;; +1DA06;SIGNWRITING HEAD MOVEMENT CIRCLE;Mn;0;NSM;;;;;N;;;;; +1DA07;SIGNWRITING FACE DIRECTION POSITION NOSE FORWARD TILTING;Mn;0;NSM;;;;;N;;;;; +1DA08;SIGNWRITING FACE DIRECTION POSITION NOSE UP OR DOWN;Mn;0;NSM;;;;;N;;;;; +1DA09;SIGNWRITING FACE DIRECTION POSITION NOSE UP OR DOWN TILTING;Mn;0;NSM;;;;;N;;;;; +1DA0A;SIGNWRITING EYEBROWS STRAIGHT UP;Mn;0;NSM;;;;;N;;;;; +1DA0B;SIGNWRITING EYEBROWS STRAIGHT NEUTRAL;Mn;0;NSM;;;;;N;;;;; +1DA0C;SIGNWRITING EYEBROWS STRAIGHT DOWN;Mn;0;NSM;;;;;N;;;;; +1DA0D;SIGNWRITING DREAMY EYEBROWS NEUTRAL DOWN;Mn;0;NSM;;;;;N;;;;; +1DA0E;SIGNWRITING DREAMY EYEBROWS DOWN NEUTRAL;Mn;0;NSM;;;;;N;;;;; +1DA0F;SIGNWRITING DREAMY EYEBROWS UP NEUTRAL;Mn;0;NSM;;;;;N;;;;; +1DA10;SIGNWRITING DREAMY EYEBROWS NEUTRAL UP;Mn;0;NSM;;;;;N;;;;; +1DA11;SIGNWRITING FOREHEAD NEUTRAL;Mn;0;NSM;;;;;N;;;;; +1DA12;SIGNWRITING FOREHEAD CONTACT;Mn;0;NSM;;;;;N;;;;; +1DA13;SIGNWRITING FOREHEAD WRINKLED;Mn;0;NSM;;;;;N;;;;; +1DA14;SIGNWRITING EYES OPEN;Mn;0;NSM;;;;;N;;;;; +1DA15;SIGNWRITING EYES SQUEEZED;Mn;0;NSM;;;;;N;;;;; +1DA16;SIGNWRITING EYES CLOSED;Mn;0;NSM;;;;;N;;;;; +1DA17;SIGNWRITING EYE BLINK SINGLE;Mn;0;NSM;;;;;N;;;;; +1DA18;SIGNWRITING EYE BLINK MULTIPLE;Mn;0;NSM;;;;;N;;;;; +1DA19;SIGNWRITING EYES HALF OPEN;Mn;0;NSM;;;;;N;;;;; +1DA1A;SIGNWRITING EYES WIDE OPEN;Mn;0;NSM;;;;;N;;;;; +1DA1B;SIGNWRITING EYES HALF CLOSED;Mn;0;NSM;;;;;N;;;;; +1DA1C;SIGNWRITING EYES WIDENING MOVEMENT;Mn;0;NSM;;;;;N;;;;; +1DA1D;SIGNWRITING EYE WINK;Mn;0;NSM;;;;;N;;;;; +1DA1E;SIGNWRITING EYELASHES UP;Mn;0;NSM;;;;;N;;;;; +1DA1F;SIGNWRITING EYELASHES DOWN;Mn;0;NSM;;;;;N;;;;; +1DA20;SIGNWRITING EYELASHES FLUTTERING;Mn;0;NSM;;;;;N;;;;; +1DA21;SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;; +1DA22;SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT DOUBLE;Mn;0;NSM;;;;;N;;;;; +1DA23;SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT ALTERNATING;Mn;0;NSM;;;;;N;;;;; +1DA24;SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;; +1DA25;SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT DOUBLE;Mn;0;NSM;;;;;N;;;;; +1DA26;SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT ALTERNATING;Mn;0;NSM;;;;;N;;;;; +1DA27;SIGNWRITING EYEGAZE-WALLPLANE CURVED;Mn;0;NSM;;;;;N;;;;; +1DA28;SIGNWRITING EYEGAZE-FLOORPLANE CURVED;Mn;0;NSM;;;;;N;;;;; +1DA29;SIGNWRITING EYEGAZE-WALLPLANE CIRCLING;Mn;0;NSM;;;;;N;;;;; +1DA2A;SIGNWRITING CHEEKS PUFFED;Mn;0;NSM;;;;;N;;;;; +1DA2B;SIGNWRITING CHEEKS NEUTRAL;Mn;0;NSM;;;;;N;;;;; +1DA2C;SIGNWRITING CHEEKS SUCKED;Mn;0;NSM;;;;;N;;;;; +1DA2D;SIGNWRITING TENSE CHEEKS HIGH;Mn;0;NSM;;;;;N;;;;; +1DA2E;SIGNWRITING TENSE CHEEKS MIDDLE;Mn;0;NSM;;;;;N;;;;; +1DA2F;SIGNWRITING TENSE CHEEKS LOW;Mn;0;NSM;;;;;N;;;;; +1DA30;SIGNWRITING EARS;Mn;0;NSM;;;;;N;;;;; +1DA31;SIGNWRITING NOSE NEUTRAL;Mn;0;NSM;;;;;N;;;;; +1DA32;SIGNWRITING NOSE CONTACT;Mn;0;NSM;;;;;N;;;;; +1DA33;SIGNWRITING NOSE WRINKLES;Mn;0;NSM;;;;;N;;;;; +1DA34;SIGNWRITING NOSE WIGGLES;Mn;0;NSM;;;;;N;;;;; +1DA35;SIGNWRITING AIR BLOWING OUT;Mn;0;NSM;;;;;N;;;;; +1DA36;SIGNWRITING AIR SUCKING IN;Mn;0;NSM;;;;;N;;;;; +1DA37;SIGNWRITING AIR BLOW SMALL ROTATIONS;So;0;L;;;;;N;;;;; +1DA38;SIGNWRITING AIR SUCK SMALL ROTATIONS;So;0;L;;;;;N;;;;; +1DA39;SIGNWRITING BREATH INHALE;So;0;L;;;;;N;;;;; +1DA3A;SIGNWRITING BREATH EXHALE;So;0;L;;;;;N;;;;; +1DA3B;SIGNWRITING MOUTH CLOSED NEUTRAL;Mn;0;NSM;;;;;N;;;;; +1DA3C;SIGNWRITING MOUTH CLOSED FORWARD;Mn;0;NSM;;;;;N;;;;; +1DA3D;SIGNWRITING MOUTH CLOSED CONTACT;Mn;0;NSM;;;;;N;;;;; +1DA3E;SIGNWRITING MOUTH SMILE;Mn;0;NSM;;;;;N;;;;; +1DA3F;SIGNWRITING MOUTH SMILE WRINKLED;Mn;0;NSM;;;;;N;;;;; +1DA40;SIGNWRITING MOUTH SMILE OPEN;Mn;0;NSM;;;;;N;;;;; +1DA41;SIGNWRITING MOUTH FROWN;Mn;0;NSM;;;;;N;;;;; +1DA42;SIGNWRITING MOUTH FROWN WRINKLED;Mn;0;NSM;;;;;N;;;;; +1DA43;SIGNWRITING MOUTH FROWN OPEN;Mn;0;NSM;;;;;N;;;;; +1DA44;SIGNWRITING MOUTH OPEN CIRCLE;Mn;0;NSM;;;;;N;;;;; +1DA45;SIGNWRITING MOUTH OPEN FORWARD;Mn;0;NSM;;;;;N;;;;; +1DA46;SIGNWRITING MOUTH OPEN WRINKLED;Mn;0;NSM;;;;;N;;;;; +1DA47;SIGNWRITING MOUTH OPEN OVAL;Mn;0;NSM;;;;;N;;;;; +1DA48;SIGNWRITING MOUTH OPEN OVAL WRINKLED;Mn;0;NSM;;;;;N;;;;; +1DA49;SIGNWRITING MOUTH OPEN OVAL YAWN;Mn;0;NSM;;;;;N;;;;; +1DA4A;SIGNWRITING MOUTH OPEN RECTANGLE;Mn;0;NSM;;;;;N;;;;; +1DA4B;SIGNWRITING MOUTH OPEN RECTANGLE WRINKLED;Mn;0;NSM;;;;;N;;;;; +1DA4C;SIGNWRITING MOUTH OPEN RECTANGLE YAWN;Mn;0;NSM;;;;;N;;;;; +1DA4D;SIGNWRITING MOUTH KISS;Mn;0;NSM;;;;;N;;;;; +1DA4E;SIGNWRITING MOUTH KISS FORWARD;Mn;0;NSM;;;;;N;;;;; +1DA4F;SIGNWRITING MOUTH KISS WRINKLED;Mn;0;NSM;;;;;N;;;;; +1DA50;SIGNWRITING MOUTH TENSE;Mn;0;NSM;;;;;N;;;;; +1DA51;SIGNWRITING MOUTH TENSE FORWARD;Mn;0;NSM;;;;;N;;;;; +1DA52;SIGNWRITING MOUTH TENSE SUCKED;Mn;0;NSM;;;;;N;;;;; +1DA53;SIGNWRITING LIPS PRESSED TOGETHER;Mn;0;NSM;;;;;N;;;;; +1DA54;SIGNWRITING LIP LOWER OVER UPPER;Mn;0;NSM;;;;;N;;;;; +1DA55;SIGNWRITING LIP UPPER OVER LOWER;Mn;0;NSM;;;;;N;;;;; +1DA56;SIGNWRITING MOUTH CORNERS;Mn;0;NSM;;;;;N;;;;; +1DA57;SIGNWRITING MOUTH WRINKLES SINGLE;Mn;0;NSM;;;;;N;;;;; +1DA58;SIGNWRITING MOUTH WRINKLES DOUBLE;Mn;0;NSM;;;;;N;;;;; +1DA59;SIGNWRITING TONGUE STICKING OUT FAR;Mn;0;NSM;;;;;N;;;;; +1DA5A;SIGNWRITING TONGUE LICKING LIPS;Mn;0;NSM;;;;;N;;;;; +1DA5B;SIGNWRITING TONGUE TIP BETWEEN LIPS;Mn;0;NSM;;;;;N;;;;; +1DA5C;SIGNWRITING TONGUE TIP TOUCHING INSIDE MOUTH;Mn;0;NSM;;;;;N;;;;; +1DA5D;SIGNWRITING TONGUE INSIDE MOUTH RELAXED;Mn;0;NSM;;;;;N;;;;; +1DA5E;SIGNWRITING TONGUE MOVES AGAINST CHEEK;Mn;0;NSM;;;;;N;;;;; +1DA5F;SIGNWRITING TONGUE CENTRE STICKING OUT;Mn;0;NSM;;;;;N;;;;; +1DA60;SIGNWRITING TONGUE CENTRE INSIDE MOUTH;Mn;0;NSM;;;;;N;;;;; +1DA61;SIGNWRITING TEETH;Mn;0;NSM;;;;;N;;;;; +1DA62;SIGNWRITING TEETH MOVEMENT;Mn;0;NSM;;;;;N;;;;; +1DA63;SIGNWRITING TEETH ON TONGUE;Mn;0;NSM;;;;;N;;;;; +1DA64;SIGNWRITING TEETH ON TONGUE MOVEMENT;Mn;0;NSM;;;;;N;;;;; +1DA65;SIGNWRITING TEETH ON LIPS;Mn;0;NSM;;;;;N;;;;; +1DA66;SIGNWRITING TEETH ON LIPS MOVEMENT;Mn;0;NSM;;;;;N;;;;; +1DA67;SIGNWRITING TEETH BITE LIPS;Mn;0;NSM;;;;;N;;;;; +1DA68;SIGNWRITING MOVEMENT-WALLPLANE JAW;Mn;0;NSM;;;;;N;;;;; +1DA69;SIGNWRITING MOVEMENT-FLOORPLANE JAW;Mn;0;NSM;;;;;N;;;;; +1DA6A;SIGNWRITING NECK;Mn;0;NSM;;;;;N;;;;; +1DA6B;SIGNWRITING HAIR;Mn;0;NSM;;;;;N;;;;; +1DA6C;SIGNWRITING EXCITEMENT;Mn;0;NSM;;;;;N;;;;; +1DA6D;SIGNWRITING SHOULDER HIP SPINE;So;0;L;;;;;N;;;;; +1DA6E;SIGNWRITING SHOULDER HIP POSITIONS;So;0;L;;;;;N;;;;; +1DA6F;SIGNWRITING WALLPLANE SHOULDER HIP MOVE;So;0;L;;;;;N;;;;; +1DA70;SIGNWRITING FLOORPLANE SHOULDER HIP MOVE;So;0;L;;;;;N;;;;; +1DA71;SIGNWRITING SHOULDER TILTING FROM WAIST;So;0;L;;;;;N;;;;; +1DA72;SIGNWRITING TORSO-WALLPLANE STRAIGHT STRETCH;So;0;L;;;;;N;;;;; +1DA73;SIGNWRITING TORSO-WALLPLANE CURVED BEND;So;0;L;;;;;N;;;;; +1DA74;SIGNWRITING TORSO-FLOORPLANE TWISTING;So;0;L;;;;;N;;;;; +1DA75;SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS;Mn;0;NSM;;;;;N;;;;; +1DA76;SIGNWRITING LIMB COMBINATION;So;0;L;;;;;N;;;;; +1DA77;SIGNWRITING LIMB LENGTH-1;So;0;L;;;;;N;;;;; +1DA78;SIGNWRITING LIMB LENGTH-2;So;0;L;;;;;N;;;;; +1DA79;SIGNWRITING LIMB LENGTH-3;So;0;L;;;;;N;;;;; +1DA7A;SIGNWRITING LIMB LENGTH-4;So;0;L;;;;;N;;;;; +1DA7B;SIGNWRITING LIMB LENGTH-5;So;0;L;;;;;N;;;;; +1DA7C;SIGNWRITING LIMB LENGTH-6;So;0;L;;;;;N;;;;; +1DA7D;SIGNWRITING LIMB LENGTH-7;So;0;L;;;;;N;;;;; +1DA7E;SIGNWRITING FINGER;So;0;L;;;;;N;;;;; +1DA7F;SIGNWRITING LOCATION-WALLPLANE SPACE;So;0;L;;;;;N;;;;; +1DA80;SIGNWRITING LOCATION-FLOORPLANE SPACE;So;0;L;;;;;N;;;;; +1DA81;SIGNWRITING LOCATION HEIGHT;So;0;L;;;;;N;;;;; +1DA82;SIGNWRITING LOCATION WIDTH;So;0;L;;;;;N;;;;; +1DA83;SIGNWRITING LOCATION DEPTH;So;0;L;;;;;N;;;;; +1DA84;SIGNWRITING LOCATION HEAD NECK;Mn;0;NSM;;;;;N;;;;; +1DA85;SIGNWRITING LOCATION TORSO;So;0;L;;;;;N;;;;; +1DA86;SIGNWRITING LOCATION LIMBS DIGITS;So;0;L;;;;;N;;;;; +1DA87;SIGNWRITING COMMA;Po;0;L;;;;;N;;;;; +1DA88;SIGNWRITING FULL STOP;Po;0;L;;;;;N;;;;; +1DA89;SIGNWRITING SEMICOLON;Po;0;L;;;;;N;;;;; +1DA8A;SIGNWRITING COLON;Po;0;L;;;;;N;;;;; +1DA8B;SIGNWRITING PARENTHESIS;Po;0;L;;;;;N;;;;; +1DA9B;SIGNWRITING FILL MODIFIER-2;Mn;0;NSM;;;;;N;;;;; +1DA9C;SIGNWRITING FILL MODIFIER-3;Mn;0;NSM;;;;;N;;;;; +1DA9D;SIGNWRITING FILL MODIFIER-4;Mn;0;NSM;;;;;N;;;;; +1DA9E;SIGNWRITING FILL MODIFIER-5;Mn;0;NSM;;;;;N;;;;; +1DA9F;SIGNWRITING FILL MODIFIER-6;Mn;0;NSM;;;;;N;;;;; +1DAA1;SIGNWRITING ROTATION MODIFIER-2;Mn;0;NSM;;;;;N;;;;; +1DAA2;SIGNWRITING ROTATION MODIFIER-3;Mn;0;NSM;;;;;N;;;;; +1DAA3;SIGNWRITING ROTATION MODIFIER-4;Mn;0;NSM;;;;;N;;;;; +1DAA4;SIGNWRITING ROTATION MODIFIER-5;Mn;0;NSM;;;;;N;;;;; +1DAA5;SIGNWRITING ROTATION MODIFIER-6;Mn;0;NSM;;;;;N;;;;; +1DAA6;SIGNWRITING ROTATION MODIFIER-7;Mn;0;NSM;;;;;N;;;;; +1DAA7;SIGNWRITING ROTATION MODIFIER-8;Mn;0;NSM;;;;;N;;;;; +1DAA8;SIGNWRITING ROTATION MODIFIER-9;Mn;0;NSM;;;;;N;;;;; +1DAA9;SIGNWRITING ROTATION MODIFIER-10;Mn;0;NSM;;;;;N;;;;; +1DAAA;SIGNWRITING ROTATION MODIFIER-11;Mn;0;NSM;;;;;N;;;;; +1DAAB;SIGNWRITING ROTATION MODIFIER-12;Mn;0;NSM;;;;;N;;;;; +1DAAC;SIGNWRITING ROTATION MODIFIER-13;Mn;0;NSM;;;;;N;;;;; +1DAAD;SIGNWRITING ROTATION MODIFIER-14;Mn;0;NSM;;;;;N;;;;; +1DAAE;SIGNWRITING ROTATION MODIFIER-15;Mn;0;NSM;;;;;N;;;;; +1DAAF;SIGNWRITING ROTATION MODIFIER-16;Mn;0;NSM;;;;;N;;;;; +1DF00;LATIN SMALL LETTER FENG DIGRAPH WITH TRILL;Ll;0;L;;;;;N;;;;; +1DF01;LATIN SMALL LETTER REVERSED SCRIPT G;Ll;0;L;;;;;N;;;;; +1DF02;LATIN LETTER SMALL CAPITAL TURNED G;Ll;0;L;;;;;N;;;;; +1DF03;LATIN SMALL LETTER REVERSED K;Ll;0;L;;;;;N;;;;; +1DF04;LATIN LETTER SMALL CAPITAL L WITH BELT;Ll;0;L;;;;;N;;;;; +1DF05;LATIN SMALL LETTER LEZH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1DF06;LATIN SMALL LETTER TURNED Y WITH BELT;Ll;0;L;;;;;N;;;;; +1DF07;LATIN SMALL LETTER REVERSED ENG;Ll;0;L;;;;;N;;;;; +1DF08;LATIN SMALL LETTER TURNED R WITH LONG LEG AND RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1DF09;LATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1DF0A;LATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOK;Lo;0;L;;;;;N;;;;; +1DF0B;LATIN SMALL LETTER ESH WITH DOUBLE BAR;Ll;0;L;;;;;N;;;;; +1DF0C;LATIN SMALL LETTER ESH WITH DOUBLE BAR AND CURL;Ll;0;L;;;;;N;;;;; +1DF0D;LATIN SMALL LETTER TURNED T WITH CURL;Ll;0;L;;;;;N;;;;; +1DF0E;LATIN LETTER INVERTED GLOTTAL STOP WITH CURL;Ll;0;L;;;;;N;;;;; +1DF0F;LATIN LETTER STRETCHED C WITH CURL;Ll;0;L;;;;;N;;;;; +1DF10;LATIN LETTER SMALL CAPITAL TURNED K;Ll;0;L;;;;;N;;;;; +1DF11;LATIN SMALL LETTER L WITH FISHHOOK;Ll;0;L;;;;;N;;;;; +1DF12;LATIN SMALL LETTER DEZH DIGRAPH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1DF13;LATIN SMALL LETTER L WITH BELT AND PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1DF14;LATIN SMALL LETTER ENG WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1DF15;LATIN SMALL LETTER TURNED R WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1DF16;LATIN SMALL LETTER R WITH FISHHOOK AND PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1DF17;LATIN SMALL LETTER TESH DIGRAPH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1DF18;LATIN SMALL LETTER EZH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1DF19;LATIN SMALL LETTER DEZH DIGRAPH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1DF1A;LATIN SMALL LETTER I WITH STROKE AND RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1DF1B;LATIN SMALL LETTER O WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1DF1C;LATIN SMALL LETTER TESH DIGRAPH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1DF1D;LATIN SMALL LETTER C WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1DF1E;LATIN SMALL LETTER S WITH CURL;Ll;0;L;;;;;N;;;;; +1DF25;LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; +1DF26;LATIN SMALL LETTER L WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; +1DF27;LATIN SMALL LETTER N WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; +1DF28;LATIN SMALL LETTER R WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; +1DF29;LATIN SMALL LETTER S WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; +1DF2A;LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; +1E000;COMBINING GLAGOLITIC LETTER AZU;Mn;230;NSM;;;;;N;;;;; +1E001;COMBINING GLAGOLITIC LETTER BUKY;Mn;230;NSM;;;;;N;;;;; +1E002;COMBINING GLAGOLITIC LETTER VEDE;Mn;230;NSM;;;;;N;;;;; +1E003;COMBINING GLAGOLITIC LETTER GLAGOLI;Mn;230;NSM;;;;;N;;;;; +1E004;COMBINING GLAGOLITIC LETTER DOBRO;Mn;230;NSM;;;;;N;;;;; +1E005;COMBINING GLAGOLITIC LETTER YESTU;Mn;230;NSM;;;;;N;;;;; +1E006;COMBINING GLAGOLITIC LETTER ZHIVETE;Mn;230;NSM;;;;;N;;;;; +1E008;COMBINING GLAGOLITIC LETTER ZEMLJA;Mn;230;NSM;;;;;N;;;;; +1E009;COMBINING GLAGOLITIC LETTER IZHE;Mn;230;NSM;;;;;N;;;;; +1E00A;COMBINING GLAGOLITIC LETTER INITIAL IZHE;Mn;230;NSM;;;;;N;;;;; +1E00B;COMBINING GLAGOLITIC LETTER I;Mn;230;NSM;;;;;N;;;;; +1E00C;COMBINING GLAGOLITIC LETTER DJERVI;Mn;230;NSM;;;;;N;;;;; +1E00D;COMBINING GLAGOLITIC LETTER KAKO;Mn;230;NSM;;;;;N;;;;; +1E00E;COMBINING GLAGOLITIC LETTER LJUDIJE;Mn;230;NSM;;;;;N;;;;; +1E00F;COMBINING GLAGOLITIC LETTER MYSLITE;Mn;230;NSM;;;;;N;;;;; +1E010;COMBINING GLAGOLITIC LETTER NASHI;Mn;230;NSM;;;;;N;;;;; +1E011;COMBINING GLAGOLITIC LETTER ONU;Mn;230;NSM;;;;;N;;;;; +1E012;COMBINING GLAGOLITIC LETTER POKOJI;Mn;230;NSM;;;;;N;;;;; +1E013;COMBINING GLAGOLITIC LETTER RITSI;Mn;230;NSM;;;;;N;;;;; +1E014;COMBINING GLAGOLITIC LETTER SLOVO;Mn;230;NSM;;;;;N;;;;; +1E015;COMBINING GLAGOLITIC LETTER TVRIDO;Mn;230;NSM;;;;;N;;;;; +1E016;COMBINING GLAGOLITIC LETTER UKU;Mn;230;NSM;;;;;N;;;;; +1E017;COMBINING GLAGOLITIC LETTER FRITU;Mn;230;NSM;;;;;N;;;;; +1E018;COMBINING GLAGOLITIC LETTER HERU;Mn;230;NSM;;;;;N;;;;; +1E01B;COMBINING GLAGOLITIC LETTER SHTA;Mn;230;NSM;;;;;N;;;;; +1E01C;COMBINING GLAGOLITIC LETTER TSI;Mn;230;NSM;;;;;N;;;;; +1E01D;COMBINING GLAGOLITIC LETTER CHRIVI;Mn;230;NSM;;;;;N;;;;; +1E01E;COMBINING GLAGOLITIC LETTER SHA;Mn;230;NSM;;;;;N;;;;; +1E01F;COMBINING GLAGOLITIC LETTER YERU;Mn;230;NSM;;;;;N;;;;; +1E020;COMBINING GLAGOLITIC LETTER YERI;Mn;230;NSM;;;;;N;;;;; +1E021;COMBINING GLAGOLITIC LETTER YATI;Mn;230;NSM;;;;;N;;;;; +1E023;COMBINING GLAGOLITIC LETTER YU;Mn;230;NSM;;;;;N;;;;; +1E024;COMBINING GLAGOLITIC LETTER SMALL YUS;Mn;230;NSM;;;;;N;;;;; +1E026;COMBINING GLAGOLITIC LETTER YO;Mn;230;NSM;;;;;N;;;;; +1E027;COMBINING GLAGOLITIC LETTER IOTATED SMALL YUS;Mn;230;NSM;;;;;N;;;;; +1E028;COMBINING GLAGOLITIC LETTER BIG YUS;Mn;230;NSM;;;;;N;;;;; +1E029;COMBINING GLAGOLITIC LETTER IOTATED BIG YUS;Mn;230;NSM;;;;;N;;;;; +1E02A;COMBINING GLAGOLITIC LETTER FITA;Mn;230;NSM;;;;;N;;;;; +1E030;MODIFIER LETTER CYRILLIC SMALL A;Lm;0;L; 0430;;;;N;;;;; +1E031;MODIFIER LETTER CYRILLIC SMALL BE;Lm;0;L; 0431;;;;N;;;;; +1E032;MODIFIER LETTER CYRILLIC SMALL VE;Lm;0;L; 0432;;;;N;;;;; +1E033;MODIFIER LETTER CYRILLIC SMALL GHE;Lm;0;L; 0433;;;;N;;;;; +1E034;MODIFIER LETTER CYRILLIC SMALL DE;Lm;0;L; 0434;;;;N;;;;; +1E035;MODIFIER LETTER CYRILLIC SMALL IE;Lm;0;L; 0435;;;;N;;;;; +1E036;MODIFIER LETTER CYRILLIC SMALL ZHE;Lm;0;L; 0436;;;;N;;;;; +1E037;MODIFIER LETTER CYRILLIC SMALL ZE;Lm;0;L; 0437;;;;N;;;;; +1E038;MODIFIER LETTER CYRILLIC SMALL I;Lm;0;L; 0438;;;;N;;;;; +1E039;MODIFIER LETTER CYRILLIC SMALL KA;Lm;0;L; 043A;;;;N;;;;; +1E03A;MODIFIER LETTER CYRILLIC SMALL EL;Lm;0;L; 043B;;;;N;;;;; +1E03B;MODIFIER LETTER CYRILLIC SMALL EM;Lm;0;L; 043C;;;;N;;;;; +1E03C;MODIFIER LETTER CYRILLIC SMALL O;Lm;0;L; 043E;;;;N;;;;; +1E03D;MODIFIER LETTER CYRILLIC SMALL PE;Lm;0;L; 043F;;;;N;;;;; +1E03E;MODIFIER LETTER CYRILLIC SMALL ER;Lm;0;L; 0440;;;;N;;;;; +1E03F;MODIFIER LETTER CYRILLIC SMALL ES;Lm;0;L; 0441;;;;N;;;;; +1E040;MODIFIER LETTER CYRILLIC SMALL TE;Lm;0;L; 0442;;;;N;;;;; +1E041;MODIFIER LETTER CYRILLIC SMALL U;Lm;0;L; 0443;;;;N;;;;; +1E042;MODIFIER LETTER CYRILLIC SMALL EF;Lm;0;L; 0444;;;;N;;;;; +1E043;MODIFIER LETTER CYRILLIC SMALL HA;Lm;0;L; 0445;;;;N;;;;; +1E044;MODIFIER LETTER CYRILLIC SMALL TSE;Lm;0;L; 0446;;;;N;;;;; +1E045;MODIFIER LETTER CYRILLIC SMALL CHE;Lm;0;L; 0447;;;;N;;;;; +1E046;MODIFIER LETTER CYRILLIC SMALL SHA;Lm;0;L; 0448;;;;N;;;;; +1E047;MODIFIER LETTER CYRILLIC SMALL YERU;Lm;0;L; 044B;;;;N;;;;; +1E048;MODIFIER LETTER CYRILLIC SMALL E;Lm;0;L; 044D;;;;N;;;;; +1E049;MODIFIER LETTER CYRILLIC SMALL YU;Lm;0;L; 044E;;;;N;;;;; +1E04A;MODIFIER LETTER CYRILLIC SMALL DZZE;Lm;0;L; A689;;;;N;;;;; +1E04B;MODIFIER LETTER CYRILLIC SMALL SCHWA;Lm;0;L; 04D9;;;;N;;;;; +1E04C;MODIFIER LETTER CYRILLIC SMALL BYELORUSSIAN-UKRAINIAN I;Lm;0;L; 0456;;;;N;;;;; +1E04D;MODIFIER LETTER CYRILLIC SMALL JE;Lm;0;L; 0458;;;;N;;;;; +1E04E;MODIFIER LETTER CYRILLIC SMALL BARRED O;Lm;0;L; 04E9;;;;N;;;;; +1E04F;MODIFIER LETTER CYRILLIC SMALL STRAIGHT U;Lm;0;L; 04AF;;;;N;;;;; +1E050;MODIFIER LETTER CYRILLIC SMALL PALOCHKA;Lm;0;L; 04CF;;;;N;;;;; +1E051;CYRILLIC SUBSCRIPT SMALL LETTER A;Lm;0;L; 0430;;;;N;;;;; +1E052;CYRILLIC SUBSCRIPT SMALL LETTER BE;Lm;0;L; 0431;;;;N;;;;; +1E053;CYRILLIC SUBSCRIPT SMALL LETTER VE;Lm;0;L; 0432;;;;N;;;;; +1E054;CYRILLIC SUBSCRIPT SMALL LETTER GHE;Lm;0;L; 0433;;;;N;;;;; +1E055;CYRILLIC SUBSCRIPT SMALL LETTER DE;Lm;0;L; 0434;;;;N;;;;; +1E056;CYRILLIC SUBSCRIPT SMALL LETTER IE;Lm;0;L; 0435;;;;N;;;;; +1E057;CYRILLIC SUBSCRIPT SMALL LETTER ZHE;Lm;0;L; 0436;;;;N;;;;; +1E058;CYRILLIC SUBSCRIPT SMALL LETTER ZE;Lm;0;L; 0437;;;;N;;;;; +1E059;CYRILLIC SUBSCRIPT SMALL LETTER I;Lm;0;L; 0438;;;;N;;;;; +1E05A;CYRILLIC SUBSCRIPT SMALL LETTER KA;Lm;0;L; 043A;;;;N;;;;; +1E05B;CYRILLIC SUBSCRIPT SMALL LETTER EL;Lm;0;L; 043B;;;;N;;;;; +1E05C;CYRILLIC SUBSCRIPT SMALL LETTER O;Lm;0;L; 043E;;;;N;;;;; +1E05D;CYRILLIC SUBSCRIPT SMALL LETTER PE;Lm;0;L; 043F;;;;N;;;;; +1E05E;CYRILLIC SUBSCRIPT SMALL LETTER ES;Lm;0;L; 0441;;;;N;;;;; +1E05F;CYRILLIC SUBSCRIPT SMALL LETTER U;Lm;0;L; 0443;;;;N;;;;; +1E060;CYRILLIC SUBSCRIPT SMALL LETTER EF;Lm;0;L; 0444;;;;N;;;;; +1E061;CYRILLIC SUBSCRIPT SMALL LETTER HA;Lm;0;L; 0445;;;;N;;;;; +1E062;CYRILLIC SUBSCRIPT SMALL LETTER TSE;Lm;0;L; 0446;;;;N;;;;; +1E063;CYRILLIC SUBSCRIPT SMALL LETTER CHE;Lm;0;L; 0447;;;;N;;;;; +1E064;CYRILLIC SUBSCRIPT SMALL LETTER SHA;Lm;0;L; 0448;;;;N;;;;; +1E065;CYRILLIC SUBSCRIPT SMALL LETTER HARD SIGN;Lm;0;L; 044A;;;;N;;;;; +1E066;CYRILLIC SUBSCRIPT SMALL LETTER YERU;Lm;0;L; 044B;;;;N;;;;; +1E067;CYRILLIC SUBSCRIPT SMALL LETTER GHE WITH UPTURN;Lm;0;L; 0491;;;;N;;;;; +1E068;CYRILLIC SUBSCRIPT SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Lm;0;L; 0456;;;;N;;;;; +1E069;CYRILLIC SUBSCRIPT SMALL LETTER DZE;Lm;0;L; 0455;;;;N;;;;; +1E06A;CYRILLIC SUBSCRIPT SMALL LETTER DZHE;Lm;0;L; 045F;;;;N;;;;; +1E06B;MODIFIER LETTER CYRILLIC SMALL ES WITH DESCENDER;Lm;0;L; 04AB;;;;N;;;;; +1E06C;MODIFIER LETTER CYRILLIC SMALL YERU WITH BACK YER;Lm;0;L; A651;;;;N;;;;; +1E06D;MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE;Lm;0;L; 04B1;;;;N;;;;; +1E08F;COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Mn;230;NSM;;;;;N;;;;; +1E100;NYIAKENG PUACHUE HMONG LETTER MA;Lo;0;L;;;;;N;;;;; +1E101;NYIAKENG PUACHUE HMONG LETTER TSA;Lo;0;L;;;;;N;;;;; +1E102;NYIAKENG PUACHUE HMONG LETTER NTA;Lo;0;L;;;;;N;;;;; +1E103;NYIAKENG PUACHUE HMONG LETTER TA;Lo;0;L;;;;;N;;;;; +1E104;NYIAKENG PUACHUE HMONG LETTER HA;Lo;0;L;;;;;N;;;;; +1E105;NYIAKENG PUACHUE HMONG LETTER NA;Lo;0;L;;;;;N;;;;; +1E106;NYIAKENG PUACHUE HMONG LETTER XA;Lo;0;L;;;;;N;;;;; +1E107;NYIAKENG PUACHUE HMONG LETTER NKA;Lo;0;L;;;;;N;;;;; +1E108;NYIAKENG PUACHUE HMONG LETTER CA;Lo;0;L;;;;;N;;;;; +1E109;NYIAKENG PUACHUE HMONG LETTER LA;Lo;0;L;;;;;N;;;;; +1E10A;NYIAKENG PUACHUE HMONG LETTER SA;Lo;0;L;;;;;N;;;;; +1E10B;NYIAKENG PUACHUE HMONG LETTER ZA;Lo;0;L;;;;;N;;;;; +1E10C;NYIAKENG PUACHUE HMONG LETTER NCA;Lo;0;L;;;;;N;;;;; +1E10D;NYIAKENG PUACHUE HMONG LETTER NTSA;Lo;0;L;;;;;N;;;;; +1E10E;NYIAKENG PUACHUE HMONG LETTER KA;Lo;0;L;;;;;N;;;;; +1E10F;NYIAKENG PUACHUE HMONG LETTER DA;Lo;0;L;;;;;N;;;;; +1E110;NYIAKENG PUACHUE HMONG LETTER NYA;Lo;0;L;;;;;N;;;;; +1E111;NYIAKENG PUACHUE HMONG LETTER NRA;Lo;0;L;;;;;N;;;;; +1E112;NYIAKENG PUACHUE HMONG LETTER VA;Lo;0;L;;;;;N;;;;; +1E113;NYIAKENG PUACHUE HMONG LETTER NTXA;Lo;0;L;;;;;N;;;;; +1E114;NYIAKENG PUACHUE HMONG LETTER TXA;Lo;0;L;;;;;N;;;;; +1E115;NYIAKENG PUACHUE HMONG LETTER FA;Lo;0;L;;;;;N;;;;; +1E116;NYIAKENG PUACHUE HMONG LETTER RA;Lo;0;L;;;;;N;;;;; +1E117;NYIAKENG PUACHUE HMONG LETTER QA;Lo;0;L;;;;;N;;;;; +1E118;NYIAKENG PUACHUE HMONG LETTER YA;Lo;0;L;;;;;N;;;;; +1E119;NYIAKENG PUACHUE HMONG LETTER NQA;Lo;0;L;;;;;N;;;;; +1E11A;NYIAKENG PUACHUE HMONG LETTER PA;Lo;0;L;;;;;N;;;;; +1E11B;NYIAKENG PUACHUE HMONG LETTER XYA;Lo;0;L;;;;;N;;;;; +1E11C;NYIAKENG PUACHUE HMONG LETTER NPA;Lo;0;L;;;;;N;;;;; +1E11D;NYIAKENG PUACHUE HMONG LETTER DLA;Lo;0;L;;;;;N;;;;; +1E11E;NYIAKENG PUACHUE HMONG LETTER NPLA;Lo;0;L;;;;;N;;;;; +1E11F;NYIAKENG PUACHUE HMONG LETTER HAH;Lo;0;L;;;;;N;;;;; +1E120;NYIAKENG PUACHUE HMONG LETTER MLA;Lo;0;L;;;;;N;;;;; +1E121;NYIAKENG PUACHUE HMONG LETTER PLA;Lo;0;L;;;;;N;;;;; +1E122;NYIAKENG PUACHUE HMONG LETTER GA;Lo;0;L;;;;;N;;;;; +1E123;NYIAKENG PUACHUE HMONG LETTER RRA;Lo;0;L;;;;;N;;;;; +1E124;NYIAKENG PUACHUE HMONG LETTER A;Lo;0;L;;;;;N;;;;; +1E125;NYIAKENG PUACHUE HMONG LETTER AA;Lo;0;L;;;;;N;;;;; +1E126;NYIAKENG PUACHUE HMONG LETTER I;Lo;0;L;;;;;N;;;;; +1E127;NYIAKENG PUACHUE HMONG LETTER U;Lo;0;L;;;;;N;;;;; +1E128;NYIAKENG PUACHUE HMONG LETTER O;Lo;0;L;;;;;N;;;;; +1E129;NYIAKENG PUACHUE HMONG LETTER OO;Lo;0;L;;;;;N;;;;; +1E12A;NYIAKENG PUACHUE HMONG LETTER E;Lo;0;L;;;;;N;;;;; +1E12B;NYIAKENG PUACHUE HMONG LETTER EE;Lo;0;L;;;;;N;;;;; +1E12C;NYIAKENG PUACHUE HMONG LETTER W;Lo;0;L;;;;;N;;;;; +1E130;NYIAKENG PUACHUE HMONG TONE-B;Mn;230;NSM;;;;;N;;;;; +1E131;NYIAKENG PUACHUE HMONG TONE-M;Mn;230;NSM;;;;;N;;;;; +1E132;NYIAKENG PUACHUE HMONG TONE-J;Mn;230;NSM;;;;;N;;;;; +1E133;NYIAKENG PUACHUE HMONG TONE-V;Mn;230;NSM;;;;;N;;;;; +1E134;NYIAKENG PUACHUE HMONG TONE-S;Mn;230;NSM;;;;;N;;;;; +1E135;NYIAKENG PUACHUE HMONG TONE-G;Mn;230;NSM;;;;;N;;;;; +1E136;NYIAKENG PUACHUE HMONG TONE-D;Mn;230;NSM;;;;;N;;;;; +1E137;NYIAKENG PUACHUE HMONG SIGN FOR PERSON;Lm;0;L;;;;;N;;;;; +1E138;NYIAKENG PUACHUE HMONG SIGN FOR THING;Lm;0;L;;;;;N;;;;; +1E139;NYIAKENG PUACHUE HMONG SIGN FOR LOCATION;Lm;0;L;;;;;N;;;;; +1E13A;NYIAKENG PUACHUE HMONG SIGN FOR ANIMAL;Lm;0;L;;;;;N;;;;; +1E13B;NYIAKENG PUACHUE HMONG SIGN FOR INVERTEBRATE;Lm;0;L;;;;;N;;;;; +1E13C;NYIAKENG PUACHUE HMONG SIGN XW XW;Lm;0;L;;;;;N;;;;; +1E13D;NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER;Lm;0;L;;;;;N;;;;; +1E140;NYIAKENG PUACHUE HMONG DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1E141;NYIAKENG PUACHUE HMONG DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1E142;NYIAKENG PUACHUE HMONG DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1E143;NYIAKENG PUACHUE HMONG DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1E144;NYIAKENG PUACHUE HMONG DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1E145;NYIAKENG PUACHUE HMONG DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1E146;NYIAKENG PUACHUE HMONG DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1E147;NYIAKENG PUACHUE HMONG DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1E148;NYIAKENG PUACHUE HMONG DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1E149;NYIAKENG PUACHUE HMONG DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1E14E;NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ;Lo;0;L;;;;;N;;;;; +1E14F;NYIAKENG PUACHUE HMONG CIRCLED CA;So;0;L;;;;;N;;;;; +1E290;TOTO LETTER PA;Lo;0;L;;;;;N;;;;; +1E291;TOTO LETTER BA;Lo;0;L;;;;;N;;;;; +1E292;TOTO LETTER TA;Lo;0;L;;;;;N;;;;; +1E293;TOTO LETTER DA;Lo;0;L;;;;;N;;;;; +1E294;TOTO LETTER KA;Lo;0;L;;;;;N;;;;; +1E295;TOTO LETTER GA;Lo;0;L;;;;;N;;;;; +1E296;TOTO LETTER MA;Lo;0;L;;;;;N;;;;; +1E297;TOTO LETTER NA;Lo;0;L;;;;;N;;;;; +1E298;TOTO LETTER NGA;Lo;0;L;;;;;N;;;;; +1E299;TOTO LETTER SA;Lo;0;L;;;;;N;;;;; +1E29A;TOTO LETTER CHA;Lo;0;L;;;;;N;;;;; +1E29B;TOTO LETTER YA;Lo;0;L;;;;;N;;;;; +1E29C;TOTO LETTER WA;Lo;0;L;;;;;N;;;;; +1E29D;TOTO LETTER JA;Lo;0;L;;;;;N;;;;; +1E29E;TOTO LETTER HA;Lo;0;L;;;;;N;;;;; +1E29F;TOTO LETTER RA;Lo;0;L;;;;;N;;;;; +1E2A0;TOTO LETTER LA;Lo;0;L;;;;;N;;;;; +1E2A1;TOTO LETTER I;Lo;0;L;;;;;N;;;;; +1E2A2;TOTO LETTER BREATHY I;Lo;0;L;;;;;N;;;;; +1E2A3;TOTO LETTER IU;Lo;0;L;;;;;N;;;;; +1E2A4;TOTO LETTER BREATHY IU;Lo;0;L;;;;;N;;;;; +1E2A5;TOTO LETTER U;Lo;0;L;;;;;N;;;;; +1E2A6;TOTO LETTER E;Lo;0;L;;;;;N;;;;; +1E2A7;TOTO LETTER BREATHY E;Lo;0;L;;;;;N;;;;; +1E2A8;TOTO LETTER EO;Lo;0;L;;;;;N;;;;; +1E2A9;TOTO LETTER BREATHY EO;Lo;0;L;;;;;N;;;;; +1E2AA;TOTO LETTER O;Lo;0;L;;;;;N;;;;; +1E2AB;TOTO LETTER AE;Lo;0;L;;;;;N;;;;; +1E2AC;TOTO LETTER BREATHY AE;Lo;0;L;;;;;N;;;;; +1E2AD;TOTO LETTER A;Lo;0;L;;;;;N;;;;; +1E2AE;TOTO SIGN RISING TONE;Mn;230;NSM;;;;;N;;;;; +1E2C0;WANCHO LETTER AA;Lo;0;L;;;;;N;;;;; +1E2C1;WANCHO LETTER A;Lo;0;L;;;;;N;;;;; +1E2C2;WANCHO LETTER BA;Lo;0;L;;;;;N;;;;; +1E2C3;WANCHO LETTER CA;Lo;0;L;;;;;N;;;;; +1E2C4;WANCHO LETTER DA;Lo;0;L;;;;;N;;;;; +1E2C5;WANCHO LETTER GA;Lo;0;L;;;;;N;;;;; +1E2C6;WANCHO LETTER YA;Lo;0;L;;;;;N;;;;; +1E2C7;WANCHO LETTER PHA;Lo;0;L;;;;;N;;;;; +1E2C8;WANCHO LETTER LA;Lo;0;L;;;;;N;;;;; +1E2C9;WANCHO LETTER NA;Lo;0;L;;;;;N;;;;; +1E2CA;WANCHO LETTER PA;Lo;0;L;;;;;N;;;;; +1E2CB;WANCHO LETTER TA;Lo;0;L;;;;;N;;;;; +1E2CC;WANCHO LETTER THA;Lo;0;L;;;;;N;;;;; +1E2CD;WANCHO LETTER FA;Lo;0;L;;;;;N;;;;; +1E2CE;WANCHO LETTER SA;Lo;0;L;;;;;N;;;;; +1E2CF;WANCHO LETTER SHA;Lo;0;L;;;;;N;;;;; +1E2D0;WANCHO LETTER JA;Lo;0;L;;;;;N;;;;; +1E2D1;WANCHO LETTER ZA;Lo;0;L;;;;;N;;;;; +1E2D2;WANCHO LETTER WA;Lo;0;L;;;;;N;;;;; +1E2D3;WANCHO LETTER VA;Lo;0;L;;;;;N;;;;; +1E2D4;WANCHO LETTER KA;Lo;0;L;;;;;N;;;;; +1E2D5;WANCHO LETTER O;Lo;0;L;;;;;N;;;;; +1E2D6;WANCHO LETTER AU;Lo;0;L;;;;;N;;;;; +1E2D7;WANCHO LETTER RA;Lo;0;L;;;;;N;;;;; +1E2D8;WANCHO LETTER MA;Lo;0;L;;;;;N;;;;; +1E2D9;WANCHO LETTER KHA;Lo;0;L;;;;;N;;;;; +1E2DA;WANCHO LETTER HA;Lo;0;L;;;;;N;;;;; +1E2DB;WANCHO LETTER E;Lo;0;L;;;;;N;;;;; +1E2DC;WANCHO LETTER I;Lo;0;L;;;;;N;;;;; +1E2DD;WANCHO LETTER NGA;Lo;0;L;;;;;N;;;;; +1E2DE;WANCHO LETTER U;Lo;0;L;;;;;N;;;;; +1E2DF;WANCHO LETTER LLHA;Lo;0;L;;;;;N;;;;; +1E2E0;WANCHO LETTER TSA;Lo;0;L;;;;;N;;;;; +1E2E1;WANCHO LETTER TRA;Lo;0;L;;;;;N;;;;; +1E2E2;WANCHO LETTER ONG;Lo;0;L;;;;;N;;;;; +1E2E3;WANCHO LETTER AANG;Lo;0;L;;;;;N;;;;; +1E2E4;WANCHO LETTER ANG;Lo;0;L;;;;;N;;;;; +1E2E5;WANCHO LETTER ING;Lo;0;L;;;;;N;;;;; +1E2E6;WANCHO LETTER ON;Lo;0;L;;;;;N;;;;; +1E2E7;WANCHO LETTER EN;Lo;0;L;;;;;N;;;;; +1E2E8;WANCHO LETTER AAN;Lo;0;L;;;;;N;;;;; +1E2E9;WANCHO LETTER NYA;Lo;0;L;;;;;N;;;;; +1E2EA;WANCHO LETTER UEN;Lo;0;L;;;;;N;;;;; +1E2EB;WANCHO LETTER YIH;Lo;0;L;;;;;N;;;;; +1E2EC;WANCHO TONE TUP;Mn;230;NSM;;;;;N;;;;; +1E2ED;WANCHO TONE TUPNI;Mn;230;NSM;;;;;N;;;;; +1E2EE;WANCHO TONE KOI;Mn;230;NSM;;;;;N;;;;; +1E2EF;WANCHO TONE KOINI;Mn;230;NSM;;;;;N;;;;; +1E2F0;WANCHO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1E2F1;WANCHO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1E2F2;WANCHO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1E2F3;WANCHO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1E2F4;WANCHO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1E2F5;WANCHO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1E2F6;WANCHO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1E2F7;WANCHO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1E2F8;WANCHO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1E2F9;WANCHO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1E2FF;WANCHO NGUN SIGN;Sc;0;ET;;;;;N;;;;; +1E4D0;NAG MUNDARI LETTER O;Lo;0;L;;;;;N;;;;; +1E4D1;NAG MUNDARI LETTER OP;Lo;0;L;;;;;N;;;;; +1E4D2;NAG MUNDARI LETTER OL;Lo;0;L;;;;;N;;;;; +1E4D3;NAG MUNDARI LETTER OY;Lo;0;L;;;;;N;;;;; +1E4D4;NAG MUNDARI LETTER ONG;Lo;0;L;;;;;N;;;;; +1E4D5;NAG MUNDARI LETTER A;Lo;0;L;;;;;N;;;;; +1E4D6;NAG MUNDARI LETTER AJ;Lo;0;L;;;;;N;;;;; +1E4D7;NAG MUNDARI LETTER AB;Lo;0;L;;;;;N;;;;; +1E4D8;NAG MUNDARI LETTER ANY;Lo;0;L;;;;;N;;;;; +1E4D9;NAG MUNDARI LETTER AH;Lo;0;L;;;;;N;;;;; +1E4DA;NAG MUNDARI LETTER I;Lo;0;L;;;;;N;;;;; +1E4DB;NAG MUNDARI LETTER IS;Lo;0;L;;;;;N;;;;; +1E4DC;NAG MUNDARI LETTER IDD;Lo;0;L;;;;;N;;;;; +1E4DD;NAG MUNDARI LETTER IT;Lo;0;L;;;;;N;;;;; +1E4DE;NAG MUNDARI LETTER IH;Lo;0;L;;;;;N;;;;; +1E4DF;NAG MUNDARI LETTER U;Lo;0;L;;;;;N;;;;; +1E4E0;NAG MUNDARI LETTER UC;Lo;0;L;;;;;N;;;;; +1E4E1;NAG MUNDARI LETTER UD;Lo;0;L;;;;;N;;;;; +1E4E2;NAG MUNDARI LETTER UK;Lo;0;L;;;;;N;;;;; +1E4E3;NAG MUNDARI LETTER UR;Lo;0;L;;;;;N;;;;; +1E4E4;NAG MUNDARI LETTER E;Lo;0;L;;;;;N;;;;; +1E4E5;NAG MUNDARI LETTER ENN;Lo;0;L;;;;;N;;;;; +1E4E6;NAG MUNDARI LETTER EG;Lo;0;L;;;;;N;;;;; +1E4E7;NAG MUNDARI LETTER EM;Lo;0;L;;;;;N;;;;; +1E4E8;NAG MUNDARI LETTER EN;Lo;0;L;;;;;N;;;;; +1E4E9;NAG MUNDARI LETTER ETT;Lo;0;L;;;;;N;;;;; +1E4EA;NAG MUNDARI LETTER ELL;Lo;0;L;;;;;N;;;;; +1E4EB;NAG MUNDARI SIGN OJOD;Lm;0;L;;;;;N;;;;; +1E4EC;NAG MUNDARI SIGN MUHOR;Mn;232;NSM;;;;;N;;;;; +1E4ED;NAG MUNDARI SIGN TOYOR;Mn;232;NSM;;;;;N;;;;; +1E4EE;NAG MUNDARI SIGN IKIR;Mn;220;NSM;;;;;N;;;;; +1E4EF;NAG MUNDARI SIGN SUTUH;Mn;230;NSM;;;;;N;;;;; +1E4F0;NAG MUNDARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1E4F1;NAG MUNDARI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1E4F2;NAG MUNDARI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1E4F3;NAG MUNDARI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1E4F4;NAG MUNDARI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1E4F5;NAG MUNDARI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1E4F6;NAG MUNDARI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1E4F7;NAG MUNDARI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1E4F8;NAG MUNDARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1E4F9;NAG MUNDARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1E5D0;OL ONAL LETTER O;Lo;0;L;;;;;N;;;;; +1E5D1;OL ONAL LETTER OM;Lo;0;L;;;;;N;;;;; +1E5D2;OL ONAL LETTER ONG;Lo;0;L;;;;;N;;;;; +1E5D3;OL ONAL LETTER ORR;Lo;0;L;;;;;N;;;;; +1E5D4;OL ONAL LETTER OO;Lo;0;L;;;;;N;;;;; +1E5D5;OL ONAL LETTER OY;Lo;0;L;;;;;N;;;;; +1E5D6;OL ONAL LETTER A;Lo;0;L;;;;;N;;;;; +1E5D7;OL ONAL LETTER AD;Lo;0;L;;;;;N;;;;; +1E5D8;OL ONAL LETTER AB;Lo;0;L;;;;;N;;;;; +1E5D9;OL ONAL LETTER AH;Lo;0;L;;;;;N;;;;; +1E5DA;OL ONAL LETTER AL;Lo;0;L;;;;;N;;;;; +1E5DB;OL ONAL LETTER AW;Lo;0;L;;;;;N;;;;; +1E5DC;OL ONAL LETTER I;Lo;0;L;;;;;N;;;;; +1E5DD;OL ONAL LETTER IT;Lo;0;L;;;;;N;;;;; +1E5DE;OL ONAL LETTER IP;Lo;0;L;;;;;N;;;;; +1E5DF;OL ONAL LETTER ITT;Lo;0;L;;;;;N;;;;; +1E5E0;OL ONAL LETTER ID;Lo;0;L;;;;;N;;;;; +1E5E1;OL ONAL LETTER IN;Lo;0;L;;;;;N;;;;; +1E5E2;OL ONAL LETTER U;Lo;0;L;;;;;N;;;;; +1E5E3;OL ONAL LETTER UK;Lo;0;L;;;;;N;;;;; +1E5E4;OL ONAL LETTER UDD;Lo;0;L;;;;;N;;;;; +1E5E5;OL ONAL LETTER UJ;Lo;0;L;;;;;N;;;;; +1E5E6;OL ONAL LETTER UNY;Lo;0;L;;;;;N;;;;; +1E5E7;OL ONAL LETTER UR;Lo;0;L;;;;;N;;;;; +1E5E8;OL ONAL LETTER E;Lo;0;L;;;;;N;;;;; +1E5E9;OL ONAL LETTER ES;Lo;0;L;;;;;N;;;;; +1E5EA;OL ONAL LETTER EH;Lo;0;L;;;;;N;;;;; +1E5EB;OL ONAL LETTER EC;Lo;0;L;;;;;N;;;;; +1E5EC;OL ONAL LETTER ENN;Lo;0;L;;;;;N;;;;; +1E5ED;OL ONAL LETTER EG;Lo;0;L;;;;;N;;;;; +1E5EE;OL ONAL SIGN MU;Mn;230;NSM;;;;;N;;;;; +1E5EF;OL ONAL SIGN IKIR;Mn;220;NSM;;;;;N;;;;; +1E5F0;OL ONAL SIGN HODDOND;Lo;0;L;;;;;N;;;;; +1E5F1;OL ONAL DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1E5F2;OL ONAL DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1E5F3;OL ONAL DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1E5F4;OL ONAL DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1E5F5;OL ONAL DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1E5F6;OL ONAL DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1E5F7;OL ONAL DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1E5F8;OL ONAL DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1E5F9;OL ONAL DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1E5FA;OL ONAL DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1E5FF;OL ONAL ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +1E6C0;TAI YO LETTER LOW KO;Lo;0;L;;;;;N;;;;; +1E6C1;TAI YO LETTER HIGH KO;Lo;0;L;;;;;N;;;;; +1E6C2;TAI YO LETTER LOW KHO;Lo;0;L;;;;;N;;;;; +1E6C3;TAI YO LETTER HIGH KHO;Lo;0;L;;;;;N;;;;; +1E6C4;TAI YO LETTER GO;Lo;0;L;;;;;N;;;;; +1E6C5;TAI YO LETTER NGO;Lo;0;L;;;;;N;;;;; +1E6C6;TAI YO LETTER CO;Lo;0;L;;;;;N;;;;; +1E6C7;TAI YO LETTER LOW XO;Lo;0;L;;;;;N;;;;; +1E6C8;TAI YO LETTER HIGH XO;Lo;0;L;;;;;N;;;;; +1E6C9;TAI YO LETTER LOW NYO;Lo;0;L;;;;;N;;;;; +1E6CA;TAI YO LETTER HIGH NYO;Lo;0;L;;;;;N;;;;; +1E6CB;TAI YO LETTER DO;Lo;0;L;;;;;N;;;;; +1E6CC;TAI YO LETTER LOW TO;Lo;0;L;;;;;N;;;;; +1E6CD;TAI YO LETTER HIGH TO;Lo;0;L;;;;;N;;;;; +1E6CE;TAI YO LETTER THO;Lo;0;L;;;;;N;;;;; +1E6CF;TAI YO LETTER NO;Lo;0;L;;;;;N;;;;; +1E6D0;TAI YO LETTER BO;Lo;0;L;;;;;N;;;;; +1E6D1;TAI YO LETTER LOW PO;Lo;0;L;;;;;N;;;;; +1E6D2;TAI YO LETTER HIGH PO;Lo;0;L;;;;;N;;;;; +1E6D3;TAI YO LETTER PHO;Lo;0;L;;;;;N;;;;; +1E6D4;TAI YO LETTER LOW FO;Lo;0;L;;;;;N;;;;; +1E6D5;TAI YO LETTER HIGH FO;Lo;0;L;;;;;N;;;;; +1E6D6;TAI YO LETTER MO;Lo;0;L;;;;;N;;;;; +1E6D7;TAI YO LETTER YO;Lo;0;L;;;;;N;;;;; +1E6D8;TAI YO LETTER LO;Lo;0;L;;;;;N;;;;; +1E6D9;TAI YO LETTER VO;Lo;0;L;;;;;N;;;;; +1E6DA;TAI YO LETTER LOW HO;Lo;0;L;;;;;N;;;;; +1E6DB;TAI YO LETTER HIGH HO;Lo;0;L;;;;;N;;;;; +1E6DC;TAI YO LETTER QO;Lo;0;L;;;;;N;;;;; +1E6DD;TAI YO LETTER LOW KVO;Lo;0;L;;;;;N;;;;; +1E6DE;TAI YO LETTER HIGH KVO;Lo;0;L;;;;;N;;;;; +1E6E0;TAI YO LETTER AA;Lo;0;L;;;;;N;;;;; +1E6E1;TAI YO LETTER I;Lo;0;L;;;;;N;;;;; +1E6E2;TAI YO LETTER UE;Lo;0;L;;;;;N;;;;; +1E6E3;TAI YO SIGN UE;Mn;230;NSM;;;;;N;;;;; +1E6E4;TAI YO LETTER U;Lo;0;L;;;;;N;;;;; +1E6E5;TAI YO LETTER AE;Lo;0;L;;;;;N;;;;; +1E6E6;TAI YO SIGN AU;Mn;230;NSM;;;;;N;;;;; +1E6E7;TAI YO LETTER O;Lo;0;L;;;;;N;;;;; +1E6E8;TAI YO LETTER E;Lo;0;L;;;;;N;;;;; +1E6E9;TAI YO LETTER IA;Lo;0;L;;;;;N;;;;; +1E6EA;TAI YO LETTER UEA;Lo;0;L;;;;;N;;;;; +1E6EB;TAI YO LETTER UA;Lo;0;L;;;;;N;;;;; +1E6EC;TAI YO LETTER OO;Lo;0;L;;;;;N;;;;; +1E6ED;TAI YO LETTER AUE;Lo;0;L;;;;;N;;;;; +1E6EE;TAI YO SIGN AY;Mn;230;NSM;;;;;N;;;;; +1E6EF;TAI YO SIGN ANG;Mn;230;NSM;;;;;N;;;;; +1E6F0;TAI YO LETTER AN;Lo;0;L;;;;;N;;;;; +1E6F1;TAI YO LETTER AM;Lo;0;L;;;;;N;;;;; +1E6F2;TAI YO LETTER AK;Lo;0;L;;;;;N;;;;; +1E6F3;TAI YO LETTER AT;Lo;0;L;;;;;N;;;;; +1E6F4;TAI YO LETTER AP;Lo;0;L;;;;;N;;;;; +1E6F5;TAI YO SIGN OM;Mn;230;NSM;;;;;N;;;;; +1E6FE;TAI YO SYMBOL MUEANG;Lo;0;L;;;;;N;;;;; +1E6FF;TAI YO XAM LAI;Lm;0;L;;;;;N;;;;; +1E7E0;ETHIOPIC SYLLABLE HHYA;Lo;0;L;;;;;N;;;;; +1E7E1;ETHIOPIC SYLLABLE HHYU;Lo;0;L;;;;;N;;;;; +1E7E2;ETHIOPIC SYLLABLE HHYI;Lo;0;L;;;;;N;;;;; +1E7E3;ETHIOPIC SYLLABLE HHYAA;Lo;0;L;;;;;N;;;;; +1E7E4;ETHIOPIC SYLLABLE HHYEE;Lo;0;L;;;;;N;;;;; +1E7E5;ETHIOPIC SYLLABLE HHYE;Lo;0;L;;;;;N;;;;; +1E7E6;ETHIOPIC SYLLABLE HHYO;Lo;0;L;;;;;N;;;;; +1E7E8;ETHIOPIC SYLLABLE GURAGE HHWA;Lo;0;L;;;;;N;;;;; +1E7E9;ETHIOPIC SYLLABLE HHWI;Lo;0;L;;;;;N;;;;; +1E7EA;ETHIOPIC SYLLABLE HHWEE;Lo;0;L;;;;;N;;;;; +1E7EB;ETHIOPIC SYLLABLE HHWE;Lo;0;L;;;;;N;;;;; +1E7ED;ETHIOPIC SYLLABLE GURAGE MWI;Lo;0;L;;;;;N;;;;; +1E7EE;ETHIOPIC SYLLABLE GURAGE MWEE;Lo;0;L;;;;;N;;;;; +1E7F0;ETHIOPIC SYLLABLE GURAGE QWI;Lo;0;L;;;;;N;;;;; +1E7F1;ETHIOPIC SYLLABLE GURAGE QWEE;Lo;0;L;;;;;N;;;;; +1E7F2;ETHIOPIC SYLLABLE GURAGE QWE;Lo;0;L;;;;;N;;;;; +1E7F3;ETHIOPIC SYLLABLE GURAGE BWI;Lo;0;L;;;;;N;;;;; +1E7F4;ETHIOPIC SYLLABLE GURAGE BWEE;Lo;0;L;;;;;N;;;;; +1E7F5;ETHIOPIC SYLLABLE GURAGE KWI;Lo;0;L;;;;;N;;;;; +1E7F6;ETHIOPIC SYLLABLE GURAGE KWEE;Lo;0;L;;;;;N;;;;; +1E7F7;ETHIOPIC SYLLABLE GURAGE KWE;Lo;0;L;;;;;N;;;;; +1E7F8;ETHIOPIC SYLLABLE GURAGE GWI;Lo;0;L;;;;;N;;;;; +1E7F9;ETHIOPIC SYLLABLE GURAGE GWEE;Lo;0;L;;;;;N;;;;; +1E7FA;ETHIOPIC SYLLABLE GURAGE GWE;Lo;0;L;;;;;N;;;;; +1E7FB;ETHIOPIC SYLLABLE GURAGE FWI;Lo;0;L;;;;;N;;;;; +1E7FC;ETHIOPIC SYLLABLE GURAGE FWEE;Lo;0;L;;;;;N;;;;; +1E7FD;ETHIOPIC SYLLABLE GURAGE PWI;Lo;0;L;;;;;N;;;;; +1E7FE;ETHIOPIC SYLLABLE GURAGE PWEE;Lo;0;L;;;;;N;;;;; +1E800;MENDE KIKAKUI SYLLABLE M001 KI;Lo;0;R;;;;;N;;;;; +1E801;MENDE KIKAKUI SYLLABLE M002 KA;Lo;0;R;;;;;N;;;;; +1E802;MENDE KIKAKUI SYLLABLE M003 KU;Lo;0;R;;;;;N;;;;; +1E803;MENDE KIKAKUI SYLLABLE M065 KEE;Lo;0;R;;;;;N;;;;; +1E804;MENDE KIKAKUI SYLLABLE M095 KE;Lo;0;R;;;;;N;;;;; +1E805;MENDE KIKAKUI SYLLABLE M076 KOO;Lo;0;R;;;;;N;;;;; +1E806;MENDE KIKAKUI SYLLABLE M048 KO;Lo;0;R;;;;;N;;;;; +1E807;MENDE KIKAKUI SYLLABLE M179 KUA;Lo;0;R;;;;;N;;;;; +1E808;MENDE KIKAKUI SYLLABLE M004 WI;Lo;0;R;;;;;N;;;;; +1E809;MENDE KIKAKUI SYLLABLE M005 WA;Lo;0;R;;;;;N;;;;; +1E80A;MENDE KIKAKUI SYLLABLE M006 WU;Lo;0;R;;;;;N;;;;; +1E80B;MENDE KIKAKUI SYLLABLE M126 WEE;Lo;0;R;;;;;N;;;;; +1E80C;MENDE KIKAKUI SYLLABLE M118 WE;Lo;0;R;;;;;N;;;;; +1E80D;MENDE KIKAKUI SYLLABLE M114 WOO;Lo;0;R;;;;;N;;;;; +1E80E;MENDE KIKAKUI SYLLABLE M045 WO;Lo;0;R;;;;;N;;;;; +1E80F;MENDE KIKAKUI SYLLABLE M194 WUI;Lo;0;R;;;;;N;;;;; +1E810;MENDE KIKAKUI SYLLABLE M143 WEI;Lo;0;R;;;;;N;;;;; +1E811;MENDE KIKAKUI SYLLABLE M061 WVI;Lo;0;R;;;;;N;;;;; +1E812;MENDE KIKAKUI SYLLABLE M049 WVA;Lo;0;R;;;;;N;;;;; +1E813;MENDE KIKAKUI SYLLABLE M139 WVE;Lo;0;R;;;;;N;;;;; +1E814;MENDE KIKAKUI SYLLABLE M007 MIN;Lo;0;R;;;;;N;;;;; +1E815;MENDE KIKAKUI SYLLABLE M008 MAN;Lo;0;R;;;;;N;;;;; +1E816;MENDE KIKAKUI SYLLABLE M009 MUN;Lo;0;R;;;;;N;;;;; +1E817;MENDE KIKAKUI SYLLABLE M059 MEN;Lo;0;R;;;;;N;;;;; +1E818;MENDE KIKAKUI SYLLABLE M094 MON;Lo;0;R;;;;;N;;;;; +1E819;MENDE KIKAKUI SYLLABLE M154 MUAN;Lo;0;R;;;;;N;;;;; +1E81A;MENDE KIKAKUI SYLLABLE M189 MUEN;Lo;0;R;;;;;N;;;;; +1E81B;MENDE KIKAKUI SYLLABLE M010 BI;Lo;0;R;;;;;N;;;;; +1E81C;MENDE KIKAKUI SYLLABLE M011 BA;Lo;0;R;;;;;N;;;;; +1E81D;MENDE KIKAKUI SYLLABLE M012 BU;Lo;0;R;;;;;N;;;;; +1E81E;MENDE KIKAKUI SYLLABLE M150 BEE;Lo;0;R;;;;;N;;;;; +1E81F;MENDE KIKAKUI SYLLABLE M097 BE;Lo;0;R;;;;;N;;;;; +1E820;MENDE KIKAKUI SYLLABLE M103 BOO;Lo;0;R;;;;;N;;;;; +1E821;MENDE KIKAKUI SYLLABLE M138 BO;Lo;0;R;;;;;N;;;;; +1E822;MENDE KIKAKUI SYLLABLE M013 I;Lo;0;R;;;;;N;;;;; +1E823;MENDE KIKAKUI SYLLABLE M014 A;Lo;0;R;;;;;N;;;;; +1E824;MENDE KIKAKUI SYLLABLE M015 U;Lo;0;R;;;;;N;;;;; +1E825;MENDE KIKAKUI SYLLABLE M163 EE;Lo;0;R;;;;;N;;;;; +1E826;MENDE KIKAKUI SYLLABLE M100 E;Lo;0;R;;;;;N;;;;; +1E827;MENDE KIKAKUI SYLLABLE M165 OO;Lo;0;R;;;;;N;;;;; +1E828;MENDE KIKAKUI SYLLABLE M147 O;Lo;0;R;;;;;N;;;;; +1E829;MENDE KIKAKUI SYLLABLE M137 EI;Lo;0;R;;;;;N;;;;; +1E82A;MENDE KIKAKUI SYLLABLE M131 IN;Lo;0;R;;;;;N;;;;; +1E82B;MENDE KIKAKUI SYLLABLE M135 IN;Lo;0;R;;;;;N;;;;; +1E82C;MENDE KIKAKUI SYLLABLE M195 AN;Lo;0;R;;;;;N;;;;; +1E82D;MENDE KIKAKUI SYLLABLE M178 EN;Lo;0;R;;;;;N;;;;; +1E82E;MENDE KIKAKUI SYLLABLE M019 SI;Lo;0;R;;;;;N;;;;; +1E82F;MENDE KIKAKUI SYLLABLE M020 SA;Lo;0;R;;;;;N;;;;; +1E830;MENDE KIKAKUI SYLLABLE M021 SU;Lo;0;R;;;;;N;;;;; +1E831;MENDE KIKAKUI SYLLABLE M162 SEE;Lo;0;R;;;;;N;;;;; +1E832;MENDE KIKAKUI SYLLABLE M116 SE;Lo;0;R;;;;;N;;;;; +1E833;MENDE KIKAKUI SYLLABLE M136 SOO;Lo;0;R;;;;;N;;;;; +1E834;MENDE KIKAKUI SYLLABLE M079 SO;Lo;0;R;;;;;N;;;;; +1E835;MENDE KIKAKUI SYLLABLE M196 SIA;Lo;0;R;;;;;N;;;;; +1E836;MENDE KIKAKUI SYLLABLE M025 LI;Lo;0;R;;;;;N;;;;; +1E837;MENDE KIKAKUI SYLLABLE M026 LA;Lo;0;R;;;;;N;;;;; +1E838;MENDE KIKAKUI SYLLABLE M027 LU;Lo;0;R;;;;;N;;;;; +1E839;MENDE KIKAKUI SYLLABLE M084 LEE;Lo;0;R;;;;;N;;;;; +1E83A;MENDE KIKAKUI SYLLABLE M073 LE;Lo;0;R;;;;;N;;;;; +1E83B;MENDE KIKAKUI SYLLABLE M054 LOO;Lo;0;R;;;;;N;;;;; +1E83C;MENDE KIKAKUI SYLLABLE M153 LO;Lo;0;R;;;;;N;;;;; +1E83D;MENDE KIKAKUI SYLLABLE M110 LONG LE;Lo;0;R;;;;;N;;;;; +1E83E;MENDE KIKAKUI SYLLABLE M016 DI;Lo;0;R;;;;;N;;;;; +1E83F;MENDE KIKAKUI SYLLABLE M017 DA;Lo;0;R;;;;;N;;;;; +1E840;MENDE KIKAKUI SYLLABLE M018 DU;Lo;0;R;;;;;N;;;;; +1E841;MENDE KIKAKUI SYLLABLE M089 DEE;Lo;0;R;;;;;N;;;;; +1E842;MENDE KIKAKUI SYLLABLE M180 DOO;Lo;0;R;;;;;N;;;;; +1E843;MENDE KIKAKUI SYLLABLE M181 DO;Lo;0;R;;;;;N;;;;; +1E844;MENDE KIKAKUI SYLLABLE M022 TI;Lo;0;R;;;;;N;;;;; +1E845;MENDE KIKAKUI SYLLABLE M023 TA;Lo;0;R;;;;;N;;;;; +1E846;MENDE KIKAKUI SYLLABLE M024 TU;Lo;0;R;;;;;N;;;;; +1E847;MENDE KIKAKUI SYLLABLE M091 TEE;Lo;0;R;;;;;N;;;;; +1E848;MENDE KIKAKUI SYLLABLE M055 TE;Lo;0;R;;;;;N;;;;; +1E849;MENDE KIKAKUI SYLLABLE M104 TOO;Lo;0;R;;;;;N;;;;; +1E84A;MENDE KIKAKUI SYLLABLE M069 TO;Lo;0;R;;;;;N;;;;; +1E84B;MENDE KIKAKUI SYLLABLE M028 JI;Lo;0;R;;;;;N;;;;; +1E84C;MENDE KIKAKUI SYLLABLE M029 JA;Lo;0;R;;;;;N;;;;; +1E84D;MENDE KIKAKUI SYLLABLE M030 JU;Lo;0;R;;;;;N;;;;; +1E84E;MENDE KIKAKUI SYLLABLE M157 JEE;Lo;0;R;;;;;N;;;;; +1E84F;MENDE KIKAKUI SYLLABLE M113 JE;Lo;0;R;;;;;N;;;;; +1E850;MENDE KIKAKUI SYLLABLE M160 JOO;Lo;0;R;;;;;N;;;;; +1E851;MENDE KIKAKUI SYLLABLE M063 JO;Lo;0;R;;;;;N;;;;; +1E852;MENDE KIKAKUI SYLLABLE M175 LONG JO;Lo;0;R;;;;;N;;;;; +1E853;MENDE KIKAKUI SYLLABLE M031 YI;Lo;0;R;;;;;N;;;;; +1E854;MENDE KIKAKUI SYLLABLE M032 YA;Lo;0;R;;;;;N;;;;; +1E855;MENDE KIKAKUI SYLLABLE M033 YU;Lo;0;R;;;;;N;;;;; +1E856;MENDE KIKAKUI SYLLABLE M109 YEE;Lo;0;R;;;;;N;;;;; +1E857;MENDE KIKAKUI SYLLABLE M080 YE;Lo;0;R;;;;;N;;;;; +1E858;MENDE KIKAKUI SYLLABLE M141 YOO;Lo;0;R;;;;;N;;;;; +1E859;MENDE KIKAKUI SYLLABLE M121 YO;Lo;0;R;;;;;N;;;;; +1E85A;MENDE KIKAKUI SYLLABLE M034 FI;Lo;0;R;;;;;N;;;;; +1E85B;MENDE KIKAKUI SYLLABLE M035 FA;Lo;0;R;;;;;N;;;;; +1E85C;MENDE KIKAKUI SYLLABLE M036 FU;Lo;0;R;;;;;N;;;;; +1E85D;MENDE KIKAKUI SYLLABLE M078 FEE;Lo;0;R;;;;;N;;;;; +1E85E;MENDE KIKAKUI SYLLABLE M075 FE;Lo;0;R;;;;;N;;;;; +1E85F;MENDE KIKAKUI SYLLABLE M133 FOO;Lo;0;R;;;;;N;;;;; +1E860;MENDE KIKAKUI SYLLABLE M088 FO;Lo;0;R;;;;;N;;;;; +1E861;MENDE KIKAKUI SYLLABLE M197 FUA;Lo;0;R;;;;;N;;;;; +1E862;MENDE KIKAKUI SYLLABLE M101 FAN;Lo;0;R;;;;;N;;;;; +1E863;MENDE KIKAKUI SYLLABLE M037 NIN;Lo;0;R;;;;;N;;;;; +1E864;MENDE KIKAKUI SYLLABLE M038 NAN;Lo;0;R;;;;;N;;;;; +1E865;MENDE KIKAKUI SYLLABLE M039 NUN;Lo;0;R;;;;;N;;;;; +1E866;MENDE KIKAKUI SYLLABLE M117 NEN;Lo;0;R;;;;;N;;;;; +1E867;MENDE KIKAKUI SYLLABLE M169 NON;Lo;0;R;;;;;N;;;;; +1E868;MENDE KIKAKUI SYLLABLE M176 HI;Lo;0;R;;;;;N;;;;; +1E869;MENDE KIKAKUI SYLLABLE M041 HA;Lo;0;R;;;;;N;;;;; +1E86A;MENDE KIKAKUI SYLLABLE M186 HU;Lo;0;R;;;;;N;;;;; +1E86B;MENDE KIKAKUI SYLLABLE M040 HEE;Lo;0;R;;;;;N;;;;; +1E86C;MENDE KIKAKUI SYLLABLE M096 HE;Lo;0;R;;;;;N;;;;; +1E86D;MENDE KIKAKUI SYLLABLE M042 HOO;Lo;0;R;;;;;N;;;;; +1E86E;MENDE KIKAKUI SYLLABLE M140 HO;Lo;0;R;;;;;N;;;;; +1E86F;MENDE KIKAKUI SYLLABLE M083 HEEI;Lo;0;R;;;;;N;;;;; +1E870;MENDE KIKAKUI SYLLABLE M128 HOOU;Lo;0;R;;;;;N;;;;; +1E871;MENDE KIKAKUI SYLLABLE M053 HIN;Lo;0;R;;;;;N;;;;; +1E872;MENDE KIKAKUI SYLLABLE M130 HAN;Lo;0;R;;;;;N;;;;; +1E873;MENDE KIKAKUI SYLLABLE M087 HUN;Lo;0;R;;;;;N;;;;; +1E874;MENDE KIKAKUI SYLLABLE M052 HEN;Lo;0;R;;;;;N;;;;; +1E875;MENDE KIKAKUI SYLLABLE M193 HON;Lo;0;R;;;;;N;;;;; +1E876;MENDE KIKAKUI SYLLABLE M046 HUAN;Lo;0;R;;;;;N;;;;; +1E877;MENDE KIKAKUI SYLLABLE M090 NGGI;Lo;0;R;;;;;N;;;;; +1E878;MENDE KIKAKUI SYLLABLE M043 NGGA;Lo;0;R;;;;;N;;;;; +1E879;MENDE KIKAKUI SYLLABLE M082 NGGU;Lo;0;R;;;;;N;;;;; +1E87A;MENDE KIKAKUI SYLLABLE M115 NGGEE;Lo;0;R;;;;;N;;;;; +1E87B;MENDE KIKAKUI SYLLABLE M146 NGGE;Lo;0;R;;;;;N;;;;; +1E87C;MENDE KIKAKUI SYLLABLE M156 NGGOO;Lo;0;R;;;;;N;;;;; +1E87D;MENDE KIKAKUI SYLLABLE M120 NGGO;Lo;0;R;;;;;N;;;;; +1E87E;MENDE KIKAKUI SYLLABLE M159 NGGAA;Lo;0;R;;;;;N;;;;; +1E87F;MENDE KIKAKUI SYLLABLE M127 NGGUA;Lo;0;R;;;;;N;;;;; +1E880;MENDE KIKAKUI SYLLABLE M086 LONG NGGE;Lo;0;R;;;;;N;;;;; +1E881;MENDE KIKAKUI SYLLABLE M106 LONG NGGOO;Lo;0;R;;;;;N;;;;; +1E882;MENDE KIKAKUI SYLLABLE M183 LONG NGGO;Lo;0;R;;;;;N;;;;; +1E883;MENDE KIKAKUI SYLLABLE M155 GI;Lo;0;R;;;;;N;;;;; +1E884;MENDE KIKAKUI SYLLABLE M111 GA;Lo;0;R;;;;;N;;;;; +1E885;MENDE KIKAKUI SYLLABLE M168 GU;Lo;0;R;;;;;N;;;;; +1E886;MENDE KIKAKUI SYLLABLE M190 GEE;Lo;0;R;;;;;N;;;;; +1E887;MENDE KIKAKUI SYLLABLE M166 GUEI;Lo;0;R;;;;;N;;;;; +1E888;MENDE KIKAKUI SYLLABLE M167 GUAN;Lo;0;R;;;;;N;;;;; +1E889;MENDE KIKAKUI SYLLABLE M184 NGEN;Lo;0;R;;;;;N;;;;; +1E88A;MENDE KIKAKUI SYLLABLE M057 NGON;Lo;0;R;;;;;N;;;;; +1E88B;MENDE KIKAKUI SYLLABLE M177 NGUAN;Lo;0;R;;;;;N;;;;; +1E88C;MENDE KIKAKUI SYLLABLE M068 PI;Lo;0;R;;;;;N;;;;; +1E88D;MENDE KIKAKUI SYLLABLE M099 PA;Lo;0;R;;;;;N;;;;; +1E88E;MENDE KIKAKUI SYLLABLE M050 PU;Lo;0;R;;;;;N;;;;; +1E88F;MENDE KIKAKUI SYLLABLE M081 PEE;Lo;0;R;;;;;N;;;;; +1E890;MENDE KIKAKUI SYLLABLE M051 PE;Lo;0;R;;;;;N;;;;; +1E891;MENDE KIKAKUI SYLLABLE M102 POO;Lo;0;R;;;;;N;;;;; +1E892;MENDE KIKAKUI SYLLABLE M066 PO;Lo;0;R;;;;;N;;;;; +1E893;MENDE KIKAKUI SYLLABLE M145 MBI;Lo;0;R;;;;;N;;;;; +1E894;MENDE KIKAKUI SYLLABLE M062 MBA;Lo;0;R;;;;;N;;;;; +1E895;MENDE KIKAKUI SYLLABLE M122 MBU;Lo;0;R;;;;;N;;;;; +1E896;MENDE KIKAKUI SYLLABLE M047 MBEE;Lo;0;R;;;;;N;;;;; +1E897;MENDE KIKAKUI SYLLABLE M188 MBEE;Lo;0;R;;;;;N;;;;; +1E898;MENDE KIKAKUI SYLLABLE M072 MBE;Lo;0;R;;;;;N;;;;; +1E899;MENDE KIKAKUI SYLLABLE M172 MBOO;Lo;0;R;;;;;N;;;;; +1E89A;MENDE KIKAKUI SYLLABLE M174 MBO;Lo;0;R;;;;;N;;;;; +1E89B;MENDE KIKAKUI SYLLABLE M187 MBUU;Lo;0;R;;;;;N;;;;; +1E89C;MENDE KIKAKUI SYLLABLE M161 LONG MBE;Lo;0;R;;;;;N;;;;; +1E89D;MENDE KIKAKUI SYLLABLE M105 LONG MBOO;Lo;0;R;;;;;N;;;;; +1E89E;MENDE KIKAKUI SYLLABLE M142 LONG MBO;Lo;0;R;;;;;N;;;;; +1E89F;MENDE KIKAKUI SYLLABLE M132 KPI;Lo;0;R;;;;;N;;;;; +1E8A0;MENDE KIKAKUI SYLLABLE M092 KPA;Lo;0;R;;;;;N;;;;; +1E8A1;MENDE KIKAKUI SYLLABLE M074 KPU;Lo;0;R;;;;;N;;;;; +1E8A2;MENDE KIKAKUI SYLLABLE M044 KPEE;Lo;0;R;;;;;N;;;;; +1E8A3;MENDE KIKAKUI SYLLABLE M108 KPE;Lo;0;R;;;;;N;;;;; +1E8A4;MENDE KIKAKUI SYLLABLE M112 KPOO;Lo;0;R;;;;;N;;;;; +1E8A5;MENDE KIKAKUI SYLLABLE M158 KPO;Lo;0;R;;;;;N;;;;; +1E8A6;MENDE KIKAKUI SYLLABLE M124 GBI;Lo;0;R;;;;;N;;;;; +1E8A7;MENDE KIKAKUI SYLLABLE M056 GBA;Lo;0;R;;;;;N;;;;; +1E8A8;MENDE KIKAKUI SYLLABLE M148 GBU;Lo;0;R;;;;;N;;;;; +1E8A9;MENDE KIKAKUI SYLLABLE M093 GBEE;Lo;0;R;;;;;N;;;;; +1E8AA;MENDE KIKAKUI SYLLABLE M107 GBE;Lo;0;R;;;;;N;;;;; +1E8AB;MENDE KIKAKUI SYLLABLE M071 GBOO;Lo;0;R;;;;;N;;;;; +1E8AC;MENDE KIKAKUI SYLLABLE M070 GBO;Lo;0;R;;;;;N;;;;; +1E8AD;MENDE KIKAKUI SYLLABLE M171 RA;Lo;0;R;;;;;N;;;;; +1E8AE;MENDE KIKAKUI SYLLABLE M123 NDI;Lo;0;R;;;;;N;;;;; +1E8AF;MENDE KIKAKUI SYLLABLE M129 NDA;Lo;0;R;;;;;N;;;;; +1E8B0;MENDE KIKAKUI SYLLABLE M125 NDU;Lo;0;R;;;;;N;;;;; +1E8B1;MENDE KIKAKUI SYLLABLE M191 NDEE;Lo;0;R;;;;;N;;;;; +1E8B2;MENDE KIKAKUI SYLLABLE M119 NDE;Lo;0;R;;;;;N;;;;; +1E8B3;MENDE KIKAKUI SYLLABLE M067 NDOO;Lo;0;R;;;;;N;;;;; +1E8B4;MENDE KIKAKUI SYLLABLE M064 NDO;Lo;0;R;;;;;N;;;;; +1E8B5;MENDE KIKAKUI SYLLABLE M152 NJA;Lo;0;R;;;;;N;;;;; +1E8B6;MENDE KIKAKUI SYLLABLE M192 NJU;Lo;0;R;;;;;N;;;;; +1E8B7;MENDE KIKAKUI SYLLABLE M149 NJEE;Lo;0;R;;;;;N;;;;; +1E8B8;MENDE KIKAKUI SYLLABLE M134 NJOO;Lo;0;R;;;;;N;;;;; +1E8B9;MENDE KIKAKUI SYLLABLE M182 VI;Lo;0;R;;;;;N;;;;; +1E8BA;MENDE KIKAKUI SYLLABLE M185 VA;Lo;0;R;;;;;N;;;;; +1E8BB;MENDE KIKAKUI SYLLABLE M151 VU;Lo;0;R;;;;;N;;;;; +1E8BC;MENDE KIKAKUI SYLLABLE M173 VEE;Lo;0;R;;;;;N;;;;; +1E8BD;MENDE KIKAKUI SYLLABLE M085 VE;Lo;0;R;;;;;N;;;;; +1E8BE;MENDE KIKAKUI SYLLABLE M144 VOO;Lo;0;R;;;;;N;;;;; +1E8BF;MENDE KIKAKUI SYLLABLE M077 VO;Lo;0;R;;;;;N;;;;; +1E8C0;MENDE KIKAKUI SYLLABLE M164 NYIN;Lo;0;R;;;;;N;;;;; +1E8C1;MENDE KIKAKUI SYLLABLE M058 NYAN;Lo;0;R;;;;;N;;;;; +1E8C2;MENDE KIKAKUI SYLLABLE M170 NYUN;Lo;0;R;;;;;N;;;;; +1E8C3;MENDE KIKAKUI SYLLABLE M098 NYEN;Lo;0;R;;;;;N;;;;; +1E8C4;MENDE KIKAKUI SYLLABLE M060 NYON;Lo;0;R;;;;;N;;;;; +1E8C7;MENDE KIKAKUI DIGIT ONE;No;0;R;;;;1;N;;;;; +1E8C8;MENDE KIKAKUI DIGIT TWO;No;0;R;;;;2;N;;;;; +1E8C9;MENDE KIKAKUI DIGIT THREE;No;0;R;;;;3;N;;;;; +1E8CA;MENDE KIKAKUI DIGIT FOUR;No;0;R;;;;4;N;;;;; +1E8CB;MENDE KIKAKUI DIGIT FIVE;No;0;R;;;;5;N;;;;; +1E8CC;MENDE KIKAKUI DIGIT SIX;No;0;R;;;;6;N;;;;; +1E8CD;MENDE KIKAKUI DIGIT SEVEN;No;0;R;;;;7;N;;;;; +1E8CE;MENDE KIKAKUI DIGIT EIGHT;No;0;R;;;;8;N;;;;; +1E8CF;MENDE KIKAKUI DIGIT NINE;No;0;R;;;;9;N;;;;; +1E8D0;MENDE KIKAKUI COMBINING NUMBER TEENS;Mn;220;NSM;;;;;N;;;;; +1E8D1;MENDE KIKAKUI COMBINING NUMBER TENS;Mn;220;NSM;;;;;N;;;;; +1E8D2;MENDE KIKAKUI COMBINING NUMBER HUNDREDS;Mn;220;NSM;;;;;N;;;;; +1E8D3;MENDE KIKAKUI COMBINING NUMBER THOUSANDS;Mn;220;NSM;;;;;N;;;;; +1E8D4;MENDE KIKAKUI COMBINING NUMBER TEN THOUSANDS;Mn;220;NSM;;;;;N;;;;; +1E8D5;MENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDS;Mn;220;NSM;;;;;N;;;;; +1E8D6;MENDE KIKAKUI COMBINING NUMBER MILLIONS;Mn;220;NSM;;;;;N;;;;; +1E900;ADLAM CAPITAL LETTER ALIF;Lu;0;R;;;;;N;;;;1E922; +1E901;ADLAM CAPITAL LETTER DAALI;Lu;0;R;;;;;N;;;;1E923; +1E902;ADLAM CAPITAL LETTER LAAM;Lu;0;R;;;;;N;;;;1E924; +1E903;ADLAM CAPITAL LETTER MIIM;Lu;0;R;;;;;N;;;;1E925; +1E904;ADLAM CAPITAL LETTER BA;Lu;0;R;;;;;N;;;;1E926; +1E905;ADLAM CAPITAL LETTER SINNYIIYHE;Lu;0;R;;;;;N;;;;1E927; +1E906;ADLAM CAPITAL LETTER PE;Lu;0;R;;;;;N;;;;1E928; +1E907;ADLAM CAPITAL LETTER BHE;Lu;0;R;;;;;N;;;;1E929; +1E908;ADLAM CAPITAL LETTER RA;Lu;0;R;;;;;N;;;;1E92A; +1E909;ADLAM CAPITAL LETTER E;Lu;0;R;;;;;N;;;;1E92B; +1E90A;ADLAM CAPITAL LETTER FA;Lu;0;R;;;;;N;;;;1E92C; +1E90B;ADLAM CAPITAL LETTER I;Lu;0;R;;;;;N;;;;1E92D; +1E90C;ADLAM CAPITAL LETTER O;Lu;0;R;;;;;N;;;;1E92E; +1E90D;ADLAM CAPITAL LETTER DHA;Lu;0;R;;;;;N;;;;1E92F; +1E90E;ADLAM CAPITAL LETTER YHE;Lu;0;R;;;;;N;;;;1E930; +1E90F;ADLAM CAPITAL LETTER WAW;Lu;0;R;;;;;N;;;;1E931; +1E910;ADLAM CAPITAL LETTER NUN;Lu;0;R;;;;;N;;;;1E932; +1E911;ADLAM CAPITAL LETTER KAF;Lu;0;R;;;;;N;;;;1E933; +1E912;ADLAM CAPITAL LETTER YA;Lu;0;R;;;;;N;;;;1E934; +1E913;ADLAM CAPITAL LETTER U;Lu;0;R;;;;;N;;;;1E935; +1E914;ADLAM CAPITAL LETTER JIIM;Lu;0;R;;;;;N;;;;1E936; +1E915;ADLAM CAPITAL LETTER CHI;Lu;0;R;;;;;N;;;;1E937; +1E916;ADLAM CAPITAL LETTER HA;Lu;0;R;;;;;N;;;;1E938; +1E917;ADLAM CAPITAL LETTER QAAF;Lu;0;R;;;;;N;;;;1E939; +1E918;ADLAM CAPITAL LETTER GA;Lu;0;R;;;;;N;;;;1E93A; +1E919;ADLAM CAPITAL LETTER NYA;Lu;0;R;;;;;N;;;;1E93B; +1E91A;ADLAM CAPITAL LETTER TU;Lu;0;R;;;;;N;;;;1E93C; +1E91B;ADLAM CAPITAL LETTER NHA;Lu;0;R;;;;;N;;;;1E93D; +1E91C;ADLAM CAPITAL LETTER VA;Lu;0;R;;;;;N;;;;1E93E; +1E91D;ADLAM CAPITAL LETTER KHA;Lu;0;R;;;;;N;;;;1E93F; +1E91E;ADLAM CAPITAL LETTER GBE;Lu;0;R;;;;;N;;;;1E940; +1E91F;ADLAM CAPITAL LETTER ZAL;Lu;0;R;;;;;N;;;;1E941; +1E920;ADLAM CAPITAL LETTER KPO;Lu;0;R;;;;;N;;;;1E942; +1E921;ADLAM CAPITAL LETTER SHA;Lu;0;R;;;;;N;;;;1E943; +1E922;ADLAM SMALL LETTER ALIF;Ll;0;R;;;;;N;;;1E900;;1E900 +1E923;ADLAM SMALL LETTER DAALI;Ll;0;R;;;;;N;;;1E901;;1E901 +1E924;ADLAM SMALL LETTER LAAM;Ll;0;R;;;;;N;;;1E902;;1E902 +1E925;ADLAM SMALL LETTER MIIM;Ll;0;R;;;;;N;;;1E903;;1E903 +1E926;ADLAM SMALL LETTER BA;Ll;0;R;;;;;N;;;1E904;;1E904 +1E927;ADLAM SMALL LETTER SINNYIIYHE;Ll;0;R;;;;;N;;;1E905;;1E905 +1E928;ADLAM SMALL LETTER PE;Ll;0;R;;;;;N;;;1E906;;1E906 +1E929;ADLAM SMALL LETTER BHE;Ll;0;R;;;;;N;;;1E907;;1E907 +1E92A;ADLAM SMALL LETTER RA;Ll;0;R;;;;;N;;;1E908;;1E908 +1E92B;ADLAM SMALL LETTER E;Ll;0;R;;;;;N;;;1E909;;1E909 +1E92C;ADLAM SMALL LETTER FA;Ll;0;R;;;;;N;;;1E90A;;1E90A +1E92D;ADLAM SMALL LETTER I;Ll;0;R;;;;;N;;;1E90B;;1E90B +1E92E;ADLAM SMALL LETTER O;Ll;0;R;;;;;N;;;1E90C;;1E90C +1E92F;ADLAM SMALL LETTER DHA;Ll;0;R;;;;;N;;;1E90D;;1E90D +1E930;ADLAM SMALL LETTER YHE;Ll;0;R;;;;;N;;;1E90E;;1E90E +1E931;ADLAM SMALL LETTER WAW;Ll;0;R;;;;;N;;;1E90F;;1E90F +1E932;ADLAM SMALL LETTER NUN;Ll;0;R;;;;;N;;;1E910;;1E910 +1E933;ADLAM SMALL LETTER KAF;Ll;0;R;;;;;N;;;1E911;;1E911 +1E934;ADLAM SMALL LETTER YA;Ll;0;R;;;;;N;;;1E912;;1E912 +1E935;ADLAM SMALL LETTER U;Ll;0;R;;;;;N;;;1E913;;1E913 +1E936;ADLAM SMALL LETTER JIIM;Ll;0;R;;;;;N;;;1E914;;1E914 +1E937;ADLAM SMALL LETTER CHI;Ll;0;R;;;;;N;;;1E915;;1E915 +1E938;ADLAM SMALL LETTER HA;Ll;0;R;;;;;N;;;1E916;;1E916 +1E939;ADLAM SMALL LETTER QAAF;Ll;0;R;;;;;N;;;1E917;;1E917 +1E93A;ADLAM SMALL LETTER GA;Ll;0;R;;;;;N;;;1E918;;1E918 +1E93B;ADLAM SMALL LETTER NYA;Ll;0;R;;;;;N;;;1E919;;1E919 +1E93C;ADLAM SMALL LETTER TU;Ll;0;R;;;;;N;;;1E91A;;1E91A +1E93D;ADLAM SMALL LETTER NHA;Ll;0;R;;;;;N;;;1E91B;;1E91B +1E93E;ADLAM SMALL LETTER VA;Ll;0;R;;;;;N;;;1E91C;;1E91C +1E93F;ADLAM SMALL LETTER KHA;Ll;0;R;;;;;N;;;1E91D;;1E91D +1E940;ADLAM SMALL LETTER GBE;Ll;0;R;;;;;N;;;1E91E;;1E91E +1E941;ADLAM SMALL LETTER ZAL;Ll;0;R;;;;;N;;;1E91F;;1E91F +1E942;ADLAM SMALL LETTER KPO;Ll;0;R;;;;;N;;;1E920;;1E920 +1E943;ADLAM SMALL LETTER SHA;Ll;0;R;;;;;N;;;1E921;;1E921 +1E944;ADLAM ALIF LENGTHENER;Mn;230;NSM;;;;;N;;;;; +1E945;ADLAM VOWEL LENGTHENER;Mn;230;NSM;;;;;N;;;;; +1E946;ADLAM GEMINATION MARK;Mn;230;NSM;;;;;N;;;;; +1E947;ADLAM HAMZA;Mn;230;NSM;;;;;N;;;;; +1E948;ADLAM CONSONANT MODIFIER;Mn;230;NSM;;;;;N;;;;; +1E949;ADLAM GEMINATE CONSONANT MODIFIER;Mn;230;NSM;;;;;N;;;;; +1E94A;ADLAM NUKTA;Mn;7;NSM;;;;;N;;;;; +1E94B;ADLAM NASALIZATION MARK;Lm;0;R;;;;;N;;;;; +1E950;ADLAM DIGIT ZERO;Nd;0;R;;0;0;0;N;;;;; +1E951;ADLAM DIGIT ONE;Nd;0;R;;1;1;1;N;;;;; +1E952;ADLAM DIGIT TWO;Nd;0;R;;2;2;2;N;;;;; +1E953;ADLAM DIGIT THREE;Nd;0;R;;3;3;3;N;;;;; +1E954;ADLAM DIGIT FOUR;Nd;0;R;;4;4;4;N;;;;; +1E955;ADLAM DIGIT FIVE;Nd;0;R;;5;5;5;N;;;;; +1E956;ADLAM DIGIT SIX;Nd;0;R;;6;6;6;N;;;;; +1E957;ADLAM DIGIT SEVEN;Nd;0;R;;7;7;7;N;;;;; +1E958;ADLAM DIGIT EIGHT;Nd;0;R;;8;8;8;N;;;;; +1E959;ADLAM DIGIT NINE;Nd;0;R;;9;9;9;N;;;;; +1E95E;ADLAM INITIAL EXCLAMATION MARK;Po;0;R;;;;;N;;;;; +1E95F;ADLAM INITIAL QUESTION MARK;Po;0;R;;;;;N;;;;; +1EC71;INDIC SIYAQ NUMBER ONE;No;0;AL;;;;1;N;;;;; +1EC72;INDIC SIYAQ NUMBER TWO;No;0;AL;;;;2;N;;;;; +1EC73;INDIC SIYAQ NUMBER THREE;No;0;AL;;;;3;N;;;;; +1EC74;INDIC SIYAQ NUMBER FOUR;No;0;AL;;;;4;N;;;;; +1EC75;INDIC SIYAQ NUMBER FIVE;No;0;AL;;;;5;N;;;;; +1EC76;INDIC SIYAQ NUMBER SIX;No;0;AL;;;;6;N;;;;; +1EC77;INDIC SIYAQ NUMBER SEVEN;No;0;AL;;;;7;N;;;;; +1EC78;INDIC SIYAQ NUMBER EIGHT;No;0;AL;;;;8;N;;;;; +1EC79;INDIC SIYAQ NUMBER NINE;No;0;AL;;;;9;N;;;;; +1EC7A;INDIC SIYAQ NUMBER TEN;No;0;AL;;;;10;N;;;;; +1EC7B;INDIC SIYAQ NUMBER TWENTY;No;0;AL;;;;20;N;;;;; +1EC7C;INDIC SIYAQ NUMBER THIRTY;No;0;AL;;;;30;N;;;;; +1EC7D;INDIC SIYAQ NUMBER FORTY;No;0;AL;;;;40;N;;;;; +1EC7E;INDIC SIYAQ NUMBER FIFTY;No;0;AL;;;;50;N;;;;; +1EC7F;INDIC SIYAQ NUMBER SIXTY;No;0;AL;;;;60;N;;;;; +1EC80;INDIC SIYAQ NUMBER SEVENTY;No;0;AL;;;;70;N;;;;; +1EC81;INDIC SIYAQ NUMBER EIGHTY;No;0;AL;;;;80;N;;;;; +1EC82;INDIC SIYAQ NUMBER NINETY;No;0;AL;;;;90;N;;;;; +1EC83;INDIC SIYAQ NUMBER ONE HUNDRED;No;0;AL;;;;100;N;;;;; +1EC84;INDIC SIYAQ NUMBER TWO HUNDRED;No;0;AL;;;;200;N;;;;; +1EC85;INDIC SIYAQ NUMBER THREE HUNDRED;No;0;AL;;;;300;N;;;;; +1EC86;INDIC SIYAQ NUMBER FOUR HUNDRED;No;0;AL;;;;400;N;;;;; +1EC87;INDIC SIYAQ NUMBER FIVE HUNDRED;No;0;AL;;;;500;N;;;;; +1EC88;INDIC SIYAQ NUMBER SIX HUNDRED;No;0;AL;;;;600;N;;;;; +1EC89;INDIC SIYAQ NUMBER SEVEN HUNDRED;No;0;AL;;;;700;N;;;;; +1EC8A;INDIC SIYAQ NUMBER EIGHT HUNDRED;No;0;AL;;;;800;N;;;;; +1EC8B;INDIC SIYAQ NUMBER NINE HUNDRED;No;0;AL;;;;900;N;;;;; +1EC8C;INDIC SIYAQ NUMBER ONE THOUSAND;No;0;AL;;;;1000;N;;;;; +1EC8D;INDIC SIYAQ NUMBER TWO THOUSAND;No;0;AL;;;;2000;N;;;;; +1EC8E;INDIC SIYAQ NUMBER THREE THOUSAND;No;0;AL;;;;3000;N;;;;; +1EC8F;INDIC SIYAQ NUMBER FOUR THOUSAND;No;0;AL;;;;4000;N;;;;; +1EC90;INDIC SIYAQ NUMBER FIVE THOUSAND;No;0;AL;;;;5000;N;;;;; +1EC91;INDIC SIYAQ NUMBER SIX THOUSAND;No;0;AL;;;;6000;N;;;;; +1EC92;INDIC SIYAQ NUMBER SEVEN THOUSAND;No;0;AL;;;;7000;N;;;;; +1EC93;INDIC SIYAQ NUMBER EIGHT THOUSAND;No;0;AL;;;;8000;N;;;;; +1EC94;INDIC SIYAQ NUMBER NINE THOUSAND;No;0;AL;;;;9000;N;;;;; +1EC95;INDIC SIYAQ NUMBER TEN THOUSAND;No;0;AL;;;;10000;N;;;;; +1EC96;INDIC SIYAQ NUMBER TWENTY THOUSAND;No;0;AL;;;;20000;N;;;;; +1EC97;INDIC SIYAQ NUMBER THIRTY THOUSAND;No;0;AL;;;;30000;N;;;;; +1EC98;INDIC SIYAQ NUMBER FORTY THOUSAND;No;0;AL;;;;40000;N;;;;; +1EC99;INDIC SIYAQ NUMBER FIFTY THOUSAND;No;0;AL;;;;50000;N;;;;; +1EC9A;INDIC SIYAQ NUMBER SIXTY THOUSAND;No;0;AL;;;;60000;N;;;;; +1EC9B;INDIC SIYAQ NUMBER SEVENTY THOUSAND;No;0;AL;;;;70000;N;;;;; +1EC9C;INDIC SIYAQ NUMBER EIGHTY THOUSAND;No;0;AL;;;;80000;N;;;;; +1EC9D;INDIC SIYAQ NUMBER NINETY THOUSAND;No;0;AL;;;;90000;N;;;;; +1EC9E;INDIC SIYAQ NUMBER LAKH;No;0;AL;;;;100000;N;;;;; +1EC9F;INDIC SIYAQ NUMBER LAKHAN;No;0;AL;;;;200000;N;;;;; +1ECA0;INDIC SIYAQ LAKH MARK;No;0;AL;;;;100000;N;;;;; +1ECA1;INDIC SIYAQ NUMBER KAROR;No;0;AL;;;;10000000;N;;;;; +1ECA2;INDIC SIYAQ NUMBER KARORAN;No;0;AL;;;;20000000;N;;;;; +1ECA3;INDIC SIYAQ NUMBER PREFIXED ONE;No;0;AL;;;;1;N;;;;; +1ECA4;INDIC SIYAQ NUMBER PREFIXED TWO;No;0;AL;;;;2;N;;;;; +1ECA5;INDIC SIYAQ NUMBER PREFIXED THREE;No;0;AL;;;;3;N;;;;; +1ECA6;INDIC SIYAQ NUMBER PREFIXED FOUR;No;0;AL;;;;4;N;;;;; +1ECA7;INDIC SIYAQ NUMBER PREFIXED FIVE;No;0;AL;;;;5;N;;;;; +1ECA8;INDIC SIYAQ NUMBER PREFIXED SIX;No;0;AL;;;;6;N;;;;; +1ECA9;INDIC SIYAQ NUMBER PREFIXED SEVEN;No;0;AL;;;;7;N;;;;; +1ECAA;INDIC SIYAQ NUMBER PREFIXED EIGHT;No;0;AL;;;;8;N;;;;; +1ECAB;INDIC SIYAQ NUMBER PREFIXED NINE;No;0;AL;;;;9;N;;;;; +1ECAC;INDIC SIYAQ PLACEHOLDER;So;0;AL;;;;;N;;;;; +1ECAD;INDIC SIYAQ FRACTION ONE QUARTER;No;0;AL;;;;1/4;N;;;;; +1ECAE;INDIC SIYAQ FRACTION ONE HALF;No;0;AL;;;;1/2;N;;;;; +1ECAF;INDIC SIYAQ FRACTION THREE QUARTERS;No;0;AL;;;;3/4;N;;;;; +1ECB0;INDIC SIYAQ RUPEE MARK;Sc;0;AL;;;;;N;;;;; +1ECB1;INDIC SIYAQ NUMBER ALTERNATE ONE;No;0;AL;;;;1;N;;;;; +1ECB2;INDIC SIYAQ NUMBER ALTERNATE TWO;No;0;AL;;;;2;N;;;;; +1ECB3;INDIC SIYAQ NUMBER ALTERNATE TEN THOUSAND;No;0;AL;;;;10000;N;;;;; +1ECB4;INDIC SIYAQ ALTERNATE LAKH MARK;No;0;AL;;;;100000;N;;;;; +1ED01;OTTOMAN SIYAQ NUMBER ONE;No;0;AL;;;;1;N;;;;; +1ED02;OTTOMAN SIYAQ NUMBER TWO;No;0;AL;;;;2;N;;;;; +1ED03;OTTOMAN SIYAQ NUMBER THREE;No;0;AL;;;;3;N;;;;; +1ED04;OTTOMAN SIYAQ NUMBER FOUR;No;0;AL;;;;4;N;;;;; +1ED05;OTTOMAN SIYAQ NUMBER FIVE;No;0;AL;;;;5;N;;;;; +1ED06;OTTOMAN SIYAQ NUMBER SIX;No;0;AL;;;;6;N;;;;; +1ED07;OTTOMAN SIYAQ NUMBER SEVEN;No;0;AL;;;;7;N;;;;; +1ED08;OTTOMAN SIYAQ NUMBER EIGHT;No;0;AL;;;;8;N;;;;; +1ED09;OTTOMAN SIYAQ NUMBER NINE;No;0;AL;;;;9;N;;;;; +1ED0A;OTTOMAN SIYAQ NUMBER TEN;No;0;AL;;;;10;N;;;;; +1ED0B;OTTOMAN SIYAQ NUMBER TWENTY;No;0;AL;;;;20;N;;;;; +1ED0C;OTTOMAN SIYAQ NUMBER THIRTY;No;0;AL;;;;30;N;;;;; +1ED0D;OTTOMAN SIYAQ NUMBER FORTY;No;0;AL;;;;40;N;;;;; +1ED0E;OTTOMAN SIYAQ NUMBER FIFTY;No;0;AL;;;;50;N;;;;; +1ED0F;OTTOMAN SIYAQ NUMBER SIXTY;No;0;AL;;;;60;N;;;;; +1ED10;OTTOMAN SIYAQ NUMBER SEVENTY;No;0;AL;;;;70;N;;;;; +1ED11;OTTOMAN SIYAQ NUMBER EIGHTY;No;0;AL;;;;80;N;;;;; +1ED12;OTTOMAN SIYAQ NUMBER NINETY;No;0;AL;;;;90;N;;;;; +1ED13;OTTOMAN SIYAQ NUMBER ONE HUNDRED;No;0;AL;;;;100;N;;;;; +1ED14;OTTOMAN SIYAQ NUMBER TWO HUNDRED;No;0;AL;;;;200;N;;;;; +1ED15;OTTOMAN SIYAQ NUMBER THREE HUNDRED;No;0;AL;;;;300;N;;;;; +1ED16;OTTOMAN SIYAQ NUMBER FOUR HUNDRED;No;0;AL;;;;400;N;;;;; +1ED17;OTTOMAN SIYAQ NUMBER FIVE HUNDRED;No;0;AL;;;;500;N;;;;; +1ED18;OTTOMAN SIYAQ NUMBER SIX HUNDRED;No;0;AL;;;;600;N;;;;; +1ED19;OTTOMAN SIYAQ NUMBER SEVEN HUNDRED;No;0;AL;;;;700;N;;;;; +1ED1A;OTTOMAN SIYAQ NUMBER EIGHT HUNDRED;No;0;AL;;;;800;N;;;;; +1ED1B;OTTOMAN SIYAQ NUMBER NINE HUNDRED;No;0;AL;;;;900;N;;;;; +1ED1C;OTTOMAN SIYAQ NUMBER ONE THOUSAND;No;0;AL;;;;1000;N;;;;; +1ED1D;OTTOMAN SIYAQ NUMBER TWO THOUSAND;No;0;AL;;;;2000;N;;;;; +1ED1E;OTTOMAN SIYAQ NUMBER THREE THOUSAND;No;0;AL;;;;3000;N;;;;; +1ED1F;OTTOMAN SIYAQ NUMBER FOUR THOUSAND;No;0;AL;;;;4000;N;;;;; +1ED20;OTTOMAN SIYAQ NUMBER FIVE THOUSAND;No;0;AL;;;;5000;N;;;;; +1ED21;OTTOMAN SIYAQ NUMBER SIX THOUSAND;No;0;AL;;;;6000;N;;;;; +1ED22;OTTOMAN SIYAQ NUMBER SEVEN THOUSAND;No;0;AL;;;;7000;N;;;;; +1ED23;OTTOMAN SIYAQ NUMBER EIGHT THOUSAND;No;0;AL;;;;8000;N;;;;; +1ED24;OTTOMAN SIYAQ NUMBER NINE THOUSAND;No;0;AL;;;;9000;N;;;;; +1ED25;OTTOMAN SIYAQ NUMBER TEN THOUSAND;No;0;AL;;;;10000;N;;;;; +1ED26;OTTOMAN SIYAQ NUMBER TWENTY THOUSAND;No;0;AL;;;;20000;N;;;;; +1ED27;OTTOMAN SIYAQ NUMBER THIRTY THOUSAND;No;0;AL;;;;30000;N;;;;; +1ED28;OTTOMAN SIYAQ NUMBER FORTY THOUSAND;No;0;AL;;;;40000;N;;;;; +1ED29;OTTOMAN SIYAQ NUMBER FIFTY THOUSAND;No;0;AL;;;;50000;N;;;;; +1ED2A;OTTOMAN SIYAQ NUMBER SIXTY THOUSAND;No;0;AL;;;;60000;N;;;;; +1ED2B;OTTOMAN SIYAQ NUMBER SEVENTY THOUSAND;No;0;AL;;;;70000;N;;;;; +1ED2C;OTTOMAN SIYAQ NUMBER EIGHTY THOUSAND;No;0;AL;;;;80000;N;;;;; +1ED2D;OTTOMAN SIYAQ NUMBER NINETY THOUSAND;No;0;AL;;;;90000;N;;;;; +1ED2E;OTTOMAN SIYAQ MARRATAN;So;0;AL;;;;;N;;;;; +1ED2F;OTTOMAN SIYAQ ALTERNATE NUMBER TWO;No;0;AL;;;;2;N;;;;; +1ED30;OTTOMAN SIYAQ ALTERNATE NUMBER THREE;No;0;AL;;;;3;N;;;;; +1ED31;OTTOMAN SIYAQ ALTERNATE NUMBER FOUR;No;0;AL;;;;4;N;;;;; +1ED32;OTTOMAN SIYAQ ALTERNATE NUMBER FIVE;No;0;AL;;;;5;N;;;;; +1ED33;OTTOMAN SIYAQ ALTERNATE NUMBER SIX;No;0;AL;;;;6;N;;;;; +1ED34;OTTOMAN SIYAQ ALTERNATE NUMBER SEVEN;No;0;AL;;;;7;N;;;;; +1ED35;OTTOMAN SIYAQ ALTERNATE NUMBER EIGHT;No;0;AL;;;;8;N;;;;; +1ED36;OTTOMAN SIYAQ ALTERNATE NUMBER NINE;No;0;AL;;;;9;N;;;;; +1ED37;OTTOMAN SIYAQ ALTERNATE NUMBER TEN;No;0;AL;;;;10;N;;;;; +1ED38;OTTOMAN SIYAQ ALTERNATE NUMBER FOUR HUNDRED;No;0;AL;;;;400;N;;;;; +1ED39;OTTOMAN SIYAQ ALTERNATE NUMBER SIX HUNDRED;No;0;AL;;;;600;N;;;;; +1ED3A;OTTOMAN SIYAQ ALTERNATE NUMBER TWO THOUSAND;No;0;AL;;;;2000;N;;;;; +1ED3B;OTTOMAN SIYAQ ALTERNATE NUMBER TEN THOUSAND;No;0;AL;;;;10000;N;;;;; +1ED3C;OTTOMAN SIYAQ FRACTION ONE HALF;No;0;AL;;;;1/2;N;;;;; +1ED3D;OTTOMAN SIYAQ FRACTION ONE SIXTH;No;0;AL;;;;1/6;N;;;;; +1EE00;ARABIC MATHEMATICAL ALEF;Lo;0;AL; 0627;;;;N;;;;; +1EE01;ARABIC MATHEMATICAL BEH;Lo;0;AL; 0628;;;;N;;;;; +1EE02;ARABIC MATHEMATICAL JEEM;Lo;0;AL; 062C;;;;N;;;;; +1EE03;ARABIC MATHEMATICAL DAL;Lo;0;AL; 062F;;;;N;;;;; +1EE05;ARABIC MATHEMATICAL WAW;Lo;0;AL; 0648;;;;N;;;;; +1EE06;ARABIC MATHEMATICAL ZAIN;Lo;0;AL; 0632;;;;N;;;;; +1EE07;ARABIC MATHEMATICAL HAH;Lo;0;AL; 062D;;;;N;;;;; +1EE08;ARABIC MATHEMATICAL TAH;Lo;0;AL; 0637;;;;N;;;;; +1EE09;ARABIC MATHEMATICAL YEH;Lo;0;AL; 064A;;;;N;;;;; +1EE0A;ARABIC MATHEMATICAL KAF;Lo;0;AL; 0643;;;;N;;;;; +1EE0B;ARABIC MATHEMATICAL LAM;Lo;0;AL; 0644;;;;N;;;;; +1EE0C;ARABIC MATHEMATICAL MEEM;Lo;0;AL; 0645;;;;N;;;;; +1EE0D;ARABIC MATHEMATICAL NOON;Lo;0;AL; 0646;;;;N;;;;; +1EE0E;ARABIC MATHEMATICAL SEEN;Lo;0;AL; 0633;;;;N;;;;; +1EE0F;ARABIC MATHEMATICAL AIN;Lo;0;AL; 0639;;;;N;;;;; +1EE10;ARABIC MATHEMATICAL FEH;Lo;0;AL; 0641;;;;N;;;;; +1EE11;ARABIC MATHEMATICAL SAD;Lo;0;AL; 0635;;;;N;;;;; +1EE12;ARABIC MATHEMATICAL QAF;Lo;0;AL; 0642;;;;N;;;;; +1EE13;ARABIC MATHEMATICAL REH;Lo;0;AL; 0631;;;;N;;;;; +1EE14;ARABIC MATHEMATICAL SHEEN;Lo;0;AL; 0634;;;;N;;;;; +1EE15;ARABIC MATHEMATICAL TEH;Lo;0;AL; 062A;;;;N;;;;; +1EE16;ARABIC MATHEMATICAL THEH;Lo;0;AL; 062B;;;;N;;;;; +1EE17;ARABIC MATHEMATICAL KHAH;Lo;0;AL; 062E;;;;N;;;;; +1EE18;ARABIC MATHEMATICAL THAL;Lo;0;AL; 0630;;;;N;;;;; +1EE19;ARABIC MATHEMATICAL DAD;Lo;0;AL; 0636;;;;N;;;;; +1EE1A;ARABIC MATHEMATICAL ZAH;Lo;0;AL; 0638;;;;N;;;;; +1EE1B;ARABIC MATHEMATICAL GHAIN;Lo;0;AL; 063A;;;;N;;;;; +1EE1C;ARABIC MATHEMATICAL DOTLESS BEH;Lo;0;AL; 066E;;;;N;;;;; +1EE1D;ARABIC MATHEMATICAL DOTLESS NOON;Lo;0;AL; 06BA;;;;N;;;;; +1EE1E;ARABIC MATHEMATICAL DOTLESS FEH;Lo;0;AL; 06A1;;;;N;;;;; +1EE1F;ARABIC MATHEMATICAL DOTLESS QAF;Lo;0;AL; 066F;;;;N;;;;; +1EE21;ARABIC MATHEMATICAL INITIAL BEH;Lo;0;AL; 0628;;;;N;;;;; +1EE22;ARABIC MATHEMATICAL INITIAL JEEM;Lo;0;AL; 062C;;;;N;;;;; +1EE24;ARABIC MATHEMATICAL INITIAL HEH;Lo;0;AL; 0647;;;;N;;;;; +1EE27;ARABIC MATHEMATICAL INITIAL HAH;Lo;0;AL; 062D;;;;N;;;;; +1EE29;ARABIC MATHEMATICAL INITIAL YEH;Lo;0;AL; 064A;;;;N;;;;; +1EE2A;ARABIC MATHEMATICAL INITIAL KAF;Lo;0;AL; 0643;;;;N;;;;; +1EE2B;ARABIC MATHEMATICAL INITIAL LAM;Lo;0;AL; 0644;;;;N;;;;; +1EE2C;ARABIC MATHEMATICAL INITIAL MEEM;Lo;0;AL; 0645;;;;N;;;;; +1EE2D;ARABIC MATHEMATICAL INITIAL NOON;Lo;0;AL; 0646;;;;N;;;;; +1EE2E;ARABIC MATHEMATICAL INITIAL SEEN;Lo;0;AL; 0633;;;;N;;;;; +1EE2F;ARABIC MATHEMATICAL INITIAL AIN;Lo;0;AL; 0639;;;;N;;;;; +1EE30;ARABIC MATHEMATICAL INITIAL FEH;Lo;0;AL; 0641;;;;N;;;;; +1EE31;ARABIC MATHEMATICAL INITIAL SAD;Lo;0;AL; 0635;;;;N;;;;; +1EE32;ARABIC MATHEMATICAL INITIAL QAF;Lo;0;AL; 0642;;;;N;;;;; +1EE34;ARABIC MATHEMATICAL INITIAL SHEEN;Lo;0;AL; 0634;;;;N;;;;; +1EE35;ARABIC MATHEMATICAL INITIAL TEH;Lo;0;AL; 062A;;;;N;;;;; +1EE36;ARABIC MATHEMATICAL INITIAL THEH;Lo;0;AL; 062B;;;;N;;;;; +1EE37;ARABIC MATHEMATICAL INITIAL KHAH;Lo;0;AL; 062E;;;;N;;;;; +1EE39;ARABIC MATHEMATICAL INITIAL DAD;Lo;0;AL; 0636;;;;N;;;;; +1EE3B;ARABIC MATHEMATICAL INITIAL GHAIN;Lo;0;AL; 063A;;;;N;;;;; +1EE42;ARABIC MATHEMATICAL TAILED JEEM;Lo;0;AL; 062C;;;;N;;;;; +1EE47;ARABIC MATHEMATICAL TAILED HAH;Lo;0;AL; 062D;;;;N;;;;; +1EE49;ARABIC MATHEMATICAL TAILED YEH;Lo;0;AL; 064A;;;;N;;;;; +1EE4B;ARABIC MATHEMATICAL TAILED LAM;Lo;0;AL; 0644;;;;N;;;;; +1EE4D;ARABIC MATHEMATICAL TAILED NOON;Lo;0;AL; 0646;;;;N;;;;; +1EE4E;ARABIC MATHEMATICAL TAILED SEEN;Lo;0;AL; 0633;;;;N;;;;; +1EE4F;ARABIC MATHEMATICAL TAILED AIN;Lo;0;AL; 0639;;;;N;;;;; +1EE51;ARABIC MATHEMATICAL TAILED SAD;Lo;0;AL; 0635;;;;N;;;;; +1EE52;ARABIC MATHEMATICAL TAILED QAF;Lo;0;AL; 0642;;;;N;;;;; +1EE54;ARABIC MATHEMATICAL TAILED SHEEN;Lo;0;AL; 0634;;;;N;;;;; +1EE57;ARABIC MATHEMATICAL TAILED KHAH;Lo;0;AL; 062E;;;;N;;;;; +1EE59;ARABIC MATHEMATICAL TAILED DAD;Lo;0;AL; 0636;;;;N;;;;; +1EE5B;ARABIC MATHEMATICAL TAILED GHAIN;Lo;0;AL; 063A;;;;N;;;;; +1EE5D;ARABIC MATHEMATICAL TAILED DOTLESS NOON;Lo;0;AL; 06BA;;;;N;;;;; +1EE5F;ARABIC MATHEMATICAL TAILED DOTLESS QAF;Lo;0;AL; 066F;;;;N;;;;; +1EE61;ARABIC MATHEMATICAL STRETCHED BEH;Lo;0;AL; 0628;;;;N;;;;; +1EE62;ARABIC MATHEMATICAL STRETCHED JEEM;Lo;0;AL; 062C;;;;N;;;;; +1EE64;ARABIC MATHEMATICAL STRETCHED HEH;Lo;0;AL; 0647;;;;N;;;;; +1EE67;ARABIC MATHEMATICAL STRETCHED HAH;Lo;0;AL; 062D;;;;N;;;;; +1EE68;ARABIC MATHEMATICAL STRETCHED TAH;Lo;0;AL; 0637;;;;N;;;;; +1EE69;ARABIC MATHEMATICAL STRETCHED YEH;Lo;0;AL; 064A;;;;N;;;;; +1EE6A;ARABIC MATHEMATICAL STRETCHED KAF;Lo;0;AL; 0643;;;;N;;;;; +1EE6C;ARABIC MATHEMATICAL STRETCHED MEEM;Lo;0;AL; 0645;;;;N;;;;; +1EE6D;ARABIC MATHEMATICAL STRETCHED NOON;Lo;0;AL; 0646;;;;N;;;;; +1EE6E;ARABIC MATHEMATICAL STRETCHED SEEN;Lo;0;AL; 0633;;;;N;;;;; +1EE6F;ARABIC MATHEMATICAL STRETCHED AIN;Lo;0;AL; 0639;;;;N;;;;; +1EE70;ARABIC MATHEMATICAL STRETCHED FEH;Lo;0;AL; 0641;;;;N;;;;; +1EE71;ARABIC MATHEMATICAL STRETCHED SAD;Lo;0;AL; 0635;;;;N;;;;; +1EE72;ARABIC MATHEMATICAL STRETCHED QAF;Lo;0;AL; 0642;;;;N;;;;; +1EE74;ARABIC MATHEMATICAL STRETCHED SHEEN;Lo;0;AL; 0634;;;;N;;;;; +1EE75;ARABIC MATHEMATICAL STRETCHED TEH;Lo;0;AL; 062A;;;;N;;;;; +1EE76;ARABIC MATHEMATICAL STRETCHED THEH;Lo;0;AL; 062B;;;;N;;;;; +1EE77;ARABIC MATHEMATICAL STRETCHED KHAH;Lo;0;AL; 062E;;;;N;;;;; +1EE79;ARABIC MATHEMATICAL STRETCHED DAD;Lo;0;AL; 0636;;;;N;;;;; +1EE7A;ARABIC MATHEMATICAL STRETCHED ZAH;Lo;0;AL; 0638;;;;N;;;;; +1EE7B;ARABIC MATHEMATICAL STRETCHED GHAIN;Lo;0;AL; 063A;;;;N;;;;; +1EE7C;ARABIC MATHEMATICAL STRETCHED DOTLESS BEH;Lo;0;AL; 066E;;;;N;;;;; +1EE7E;ARABIC MATHEMATICAL STRETCHED DOTLESS FEH;Lo;0;AL; 06A1;;;;N;;;;; +1EE80;ARABIC MATHEMATICAL LOOPED ALEF;Lo;0;AL; 0627;;;;N;;;;; +1EE81;ARABIC MATHEMATICAL LOOPED BEH;Lo;0;AL; 0628;;;;N;;;;; +1EE82;ARABIC MATHEMATICAL LOOPED JEEM;Lo;0;AL; 062C;;;;N;;;;; +1EE83;ARABIC MATHEMATICAL LOOPED DAL;Lo;0;AL; 062F;;;;N;;;;; +1EE84;ARABIC MATHEMATICAL LOOPED HEH;Lo;0;AL; 0647;;;;N;;;;; +1EE85;ARABIC MATHEMATICAL LOOPED WAW;Lo;0;AL; 0648;;;;N;;;;; +1EE86;ARABIC MATHEMATICAL LOOPED ZAIN;Lo;0;AL; 0632;;;;N;;;;; +1EE87;ARABIC MATHEMATICAL LOOPED HAH;Lo;0;AL; 062D;;;;N;;;;; +1EE88;ARABIC MATHEMATICAL LOOPED TAH;Lo;0;AL; 0637;;;;N;;;;; +1EE89;ARABIC MATHEMATICAL LOOPED YEH;Lo;0;AL; 064A;;;;N;;;;; +1EE8B;ARABIC MATHEMATICAL LOOPED LAM;Lo;0;AL; 0644;;;;N;;;;; +1EE8C;ARABIC MATHEMATICAL LOOPED MEEM;Lo;0;AL; 0645;;;;N;;;;; +1EE8D;ARABIC MATHEMATICAL LOOPED NOON;Lo;0;AL; 0646;;;;N;;;;; +1EE8E;ARABIC MATHEMATICAL LOOPED SEEN;Lo;0;AL; 0633;;;;N;;;;; +1EE8F;ARABIC MATHEMATICAL LOOPED AIN;Lo;0;AL; 0639;;;;N;;;;; +1EE90;ARABIC MATHEMATICAL LOOPED FEH;Lo;0;AL; 0641;;;;N;;;;; +1EE91;ARABIC MATHEMATICAL LOOPED SAD;Lo;0;AL; 0635;;;;N;;;;; +1EE92;ARABIC MATHEMATICAL LOOPED QAF;Lo;0;AL; 0642;;;;N;;;;; +1EE93;ARABIC MATHEMATICAL LOOPED REH;Lo;0;AL; 0631;;;;N;;;;; +1EE94;ARABIC MATHEMATICAL LOOPED SHEEN;Lo;0;AL; 0634;;;;N;;;;; +1EE95;ARABIC MATHEMATICAL LOOPED TEH;Lo;0;AL; 062A;;;;N;;;;; +1EE96;ARABIC MATHEMATICAL LOOPED THEH;Lo;0;AL; 062B;;;;N;;;;; +1EE97;ARABIC MATHEMATICAL LOOPED KHAH;Lo;0;AL; 062E;;;;N;;;;; +1EE98;ARABIC MATHEMATICAL LOOPED THAL;Lo;0;AL; 0630;;;;N;;;;; +1EE99;ARABIC MATHEMATICAL LOOPED DAD;Lo;0;AL; 0636;;;;N;;;;; +1EE9A;ARABIC MATHEMATICAL LOOPED ZAH;Lo;0;AL; 0638;;;;N;;;;; +1EE9B;ARABIC MATHEMATICAL LOOPED GHAIN;Lo;0;AL; 063A;;;;N;;;;; +1EEA1;ARABIC MATHEMATICAL DOUBLE-STRUCK BEH;Lo;0;AL; 0628;;;;N;;;;; +1EEA2;ARABIC MATHEMATICAL DOUBLE-STRUCK JEEM;Lo;0;AL; 062C;;;;N;;;;; +1EEA3;ARABIC MATHEMATICAL DOUBLE-STRUCK DAL;Lo;0;AL; 062F;;;;N;;;;; +1EEA5;ARABIC MATHEMATICAL DOUBLE-STRUCK WAW;Lo;0;AL; 0648;;;;N;;;;; +1EEA6;ARABIC MATHEMATICAL DOUBLE-STRUCK ZAIN;Lo;0;AL; 0632;;;;N;;;;; +1EEA7;ARABIC MATHEMATICAL DOUBLE-STRUCK HAH;Lo;0;AL; 062D;;;;N;;;;; +1EEA8;ARABIC MATHEMATICAL DOUBLE-STRUCK TAH;Lo;0;AL; 0637;;;;N;;;;; +1EEA9;ARABIC MATHEMATICAL DOUBLE-STRUCK YEH;Lo;0;AL; 064A;;;;N;;;;; +1EEAB;ARABIC MATHEMATICAL DOUBLE-STRUCK LAM;Lo;0;AL; 0644;;;;N;;;;; +1EEAC;ARABIC MATHEMATICAL DOUBLE-STRUCK MEEM;Lo;0;AL; 0645;;;;N;;;;; +1EEAD;ARABIC MATHEMATICAL DOUBLE-STRUCK NOON;Lo;0;AL; 0646;;;;N;;;;; +1EEAE;ARABIC MATHEMATICAL DOUBLE-STRUCK SEEN;Lo;0;AL; 0633;;;;N;;;;; +1EEAF;ARABIC MATHEMATICAL DOUBLE-STRUCK AIN;Lo;0;AL; 0639;;;;N;;;;; +1EEB0;ARABIC MATHEMATICAL DOUBLE-STRUCK FEH;Lo;0;AL; 0641;;;;N;;;;; +1EEB1;ARABIC MATHEMATICAL DOUBLE-STRUCK SAD;Lo;0;AL; 0635;;;;N;;;;; +1EEB2;ARABIC MATHEMATICAL DOUBLE-STRUCK QAF;Lo;0;AL; 0642;;;;N;;;;; +1EEB3;ARABIC MATHEMATICAL DOUBLE-STRUCK REH;Lo;0;AL; 0631;;;;N;;;;; +1EEB4;ARABIC MATHEMATICAL DOUBLE-STRUCK SHEEN;Lo;0;AL; 0634;;;;N;;;;; +1EEB5;ARABIC MATHEMATICAL DOUBLE-STRUCK TEH;Lo;0;AL; 062A;;;;N;;;;; +1EEB6;ARABIC MATHEMATICAL DOUBLE-STRUCK THEH;Lo;0;AL; 062B;;;;N;;;;; +1EEB7;ARABIC MATHEMATICAL DOUBLE-STRUCK KHAH;Lo;0;AL; 062E;;;;N;;;;; +1EEB8;ARABIC MATHEMATICAL DOUBLE-STRUCK THAL;Lo;0;AL; 0630;;;;N;;;;; +1EEB9;ARABIC MATHEMATICAL DOUBLE-STRUCK DAD;Lo;0;AL; 0636;;;;N;;;;; +1EEBA;ARABIC MATHEMATICAL DOUBLE-STRUCK ZAH;Lo;0;AL; 0638;;;;N;;;;; +1EEBB;ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN;Lo;0;AL; 063A;;;;N;;;;; +1EEF0;ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL;Sm;0;ON;;;;;N;;;;; +1EEF1;ARABIC MATHEMATICAL OPERATOR HAH WITH DAL;Sm;0;ON;;;;;N;;;;; +1F000;MAHJONG TILE EAST WIND;So;0;ON;;;;;N;;;;; +1F001;MAHJONG TILE SOUTH WIND;So;0;ON;;;;;N;;;;; +1F002;MAHJONG TILE WEST WIND;So;0;ON;;;;;N;;;;; +1F003;MAHJONG TILE NORTH WIND;So;0;ON;;;;;N;;;;; +1F004;MAHJONG TILE RED DRAGON;So;0;ON;;;;;N;;;;; +1F005;MAHJONG TILE GREEN DRAGON;So;0;ON;;;;;N;;;;; +1F006;MAHJONG TILE WHITE DRAGON;So;0;ON;;;;;N;;;;; +1F007;MAHJONG TILE ONE OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F008;MAHJONG TILE TWO OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F009;MAHJONG TILE THREE OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F00A;MAHJONG TILE FOUR OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F00B;MAHJONG TILE FIVE OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F00C;MAHJONG TILE SIX OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F00D;MAHJONG TILE SEVEN OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F00E;MAHJONG TILE EIGHT OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F00F;MAHJONG TILE NINE OF CHARACTERS;So;0;ON;;;;;N;;;;; +1F010;MAHJONG TILE ONE OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F011;MAHJONG TILE TWO OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F012;MAHJONG TILE THREE OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F013;MAHJONG TILE FOUR OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F014;MAHJONG TILE FIVE OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F015;MAHJONG TILE SIX OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F016;MAHJONG TILE SEVEN OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F017;MAHJONG TILE EIGHT OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F018;MAHJONG TILE NINE OF BAMBOOS;So;0;ON;;;;;N;;;;; +1F019;MAHJONG TILE ONE OF CIRCLES;So;0;ON;;;;;N;;;;; +1F01A;MAHJONG TILE TWO OF CIRCLES;So;0;ON;;;;;N;;;;; +1F01B;MAHJONG TILE THREE OF CIRCLES;So;0;ON;;;;;N;;;;; +1F01C;MAHJONG TILE FOUR OF CIRCLES;So;0;ON;;;;;N;;;;; +1F01D;MAHJONG TILE FIVE OF CIRCLES;So;0;ON;;;;;N;;;;; +1F01E;MAHJONG TILE SIX OF CIRCLES;So;0;ON;;;;;N;;;;; +1F01F;MAHJONG TILE SEVEN OF CIRCLES;So;0;ON;;;;;N;;;;; +1F020;MAHJONG TILE EIGHT OF CIRCLES;So;0;ON;;;;;N;;;;; +1F021;MAHJONG TILE NINE OF CIRCLES;So;0;ON;;;;;N;;;;; +1F022;MAHJONG TILE PLUM;So;0;ON;;;;;N;;;;; +1F023;MAHJONG TILE ORCHID;So;0;ON;;;;;N;;;;; +1F024;MAHJONG TILE BAMBOO;So;0;ON;;;;;N;;;;; +1F025;MAHJONG TILE CHRYSANTHEMUM;So;0;ON;;;;;N;;;;; +1F026;MAHJONG TILE SPRING;So;0;ON;;;;;N;;;;; +1F027;MAHJONG TILE SUMMER;So;0;ON;;;;;N;;;;; +1F028;MAHJONG TILE AUTUMN;So;0;ON;;;;;N;;;;; +1F029;MAHJONG TILE WINTER;So;0;ON;;;;;N;;;;; +1F02A;MAHJONG TILE JOKER;So;0;ON;;;;;N;;;;; +1F02B;MAHJONG TILE BACK;So;0;ON;;;;;N;;;;; +1F030;DOMINO TILE HORIZONTAL BACK;So;0;ON;;;;;N;;;;; +1F031;DOMINO TILE HORIZONTAL-00-00;So;0;ON;;;;;N;;;;; +1F032;DOMINO TILE HORIZONTAL-00-01;So;0;ON;;;;;N;;;;; +1F033;DOMINO TILE HORIZONTAL-00-02;So;0;ON;;;;;N;;;;; +1F034;DOMINO TILE HORIZONTAL-00-03;So;0;ON;;;;;N;;;;; +1F035;DOMINO TILE HORIZONTAL-00-04;So;0;ON;;;;;N;;;;; +1F036;DOMINO TILE HORIZONTAL-00-05;So;0;ON;;;;;N;;;;; +1F037;DOMINO TILE HORIZONTAL-00-06;So;0;ON;;;;;N;;;;; +1F038;DOMINO TILE HORIZONTAL-01-00;So;0;ON;;;;;N;;;;; +1F039;DOMINO TILE HORIZONTAL-01-01;So;0;ON;;;;;N;;;;; +1F03A;DOMINO TILE HORIZONTAL-01-02;So;0;ON;;;;;N;;;;; +1F03B;DOMINO TILE HORIZONTAL-01-03;So;0;ON;;;;;N;;;;; +1F03C;DOMINO TILE HORIZONTAL-01-04;So;0;ON;;;;;N;;;;; +1F03D;DOMINO TILE HORIZONTAL-01-05;So;0;ON;;;;;N;;;;; +1F03E;DOMINO TILE HORIZONTAL-01-06;So;0;ON;;;;;N;;;;; +1F03F;DOMINO TILE HORIZONTAL-02-00;So;0;ON;;;;;N;;;;; +1F040;DOMINO TILE HORIZONTAL-02-01;So;0;ON;;;;;N;;;;; +1F041;DOMINO TILE HORIZONTAL-02-02;So;0;ON;;;;;N;;;;; +1F042;DOMINO TILE HORIZONTAL-02-03;So;0;ON;;;;;N;;;;; +1F043;DOMINO TILE HORIZONTAL-02-04;So;0;ON;;;;;N;;;;; +1F044;DOMINO TILE HORIZONTAL-02-05;So;0;ON;;;;;N;;;;; +1F045;DOMINO TILE HORIZONTAL-02-06;So;0;ON;;;;;N;;;;; +1F046;DOMINO TILE HORIZONTAL-03-00;So;0;ON;;;;;N;;;;; +1F047;DOMINO TILE HORIZONTAL-03-01;So;0;ON;;;;;N;;;;; +1F048;DOMINO TILE HORIZONTAL-03-02;So;0;ON;;;;;N;;;;; +1F049;DOMINO TILE HORIZONTAL-03-03;So;0;ON;;;;;N;;;;; +1F04A;DOMINO TILE HORIZONTAL-03-04;So;0;ON;;;;;N;;;;; +1F04B;DOMINO TILE HORIZONTAL-03-05;So;0;ON;;;;;N;;;;; +1F04C;DOMINO TILE HORIZONTAL-03-06;So;0;ON;;;;;N;;;;; +1F04D;DOMINO TILE HORIZONTAL-04-00;So;0;ON;;;;;N;;;;; +1F04E;DOMINO TILE HORIZONTAL-04-01;So;0;ON;;;;;N;;;;; +1F04F;DOMINO TILE HORIZONTAL-04-02;So;0;ON;;;;;N;;;;; +1F050;DOMINO TILE HORIZONTAL-04-03;So;0;ON;;;;;N;;;;; +1F051;DOMINO TILE HORIZONTAL-04-04;So;0;ON;;;;;N;;;;; +1F052;DOMINO TILE HORIZONTAL-04-05;So;0;ON;;;;;N;;;;; +1F053;DOMINO TILE HORIZONTAL-04-06;So;0;ON;;;;;N;;;;; +1F054;DOMINO TILE HORIZONTAL-05-00;So;0;ON;;;;;N;;;;; +1F055;DOMINO TILE HORIZONTAL-05-01;So;0;ON;;;;;N;;;;; +1F056;DOMINO TILE HORIZONTAL-05-02;So;0;ON;;;;;N;;;;; +1F057;DOMINO TILE HORIZONTAL-05-03;So;0;ON;;;;;N;;;;; +1F058;DOMINO TILE HORIZONTAL-05-04;So;0;ON;;;;;N;;;;; +1F059;DOMINO TILE HORIZONTAL-05-05;So;0;ON;;;;;N;;;;; +1F05A;DOMINO TILE HORIZONTAL-05-06;So;0;ON;;;;;N;;;;; +1F05B;DOMINO TILE HORIZONTAL-06-00;So;0;ON;;;;;N;;;;; +1F05C;DOMINO TILE HORIZONTAL-06-01;So;0;ON;;;;;N;;;;; +1F05D;DOMINO TILE HORIZONTAL-06-02;So;0;ON;;;;;N;;;;; +1F05E;DOMINO TILE HORIZONTAL-06-03;So;0;ON;;;;;N;;;;; +1F05F;DOMINO TILE HORIZONTAL-06-04;So;0;ON;;;;;N;;;;; +1F060;DOMINO TILE HORIZONTAL-06-05;So;0;ON;;;;;N;;;;; +1F061;DOMINO TILE HORIZONTAL-06-06;So;0;ON;;;;;N;;;;; +1F062;DOMINO TILE VERTICAL BACK;So;0;ON;;;;;N;;;;; +1F063;DOMINO TILE VERTICAL-00-00;So;0;ON;;;;;N;;;;; +1F064;DOMINO TILE VERTICAL-00-01;So;0;ON;;;;;N;;;;; +1F065;DOMINO TILE VERTICAL-00-02;So;0;ON;;;;;N;;;;; +1F066;DOMINO TILE VERTICAL-00-03;So;0;ON;;;;;N;;;;; +1F067;DOMINO TILE VERTICAL-00-04;So;0;ON;;;;;N;;;;; +1F068;DOMINO TILE VERTICAL-00-05;So;0;ON;;;;;N;;;;; +1F069;DOMINO TILE VERTICAL-00-06;So;0;ON;;;;;N;;;;; +1F06A;DOMINO TILE VERTICAL-01-00;So;0;ON;;;;;N;;;;; +1F06B;DOMINO TILE VERTICAL-01-01;So;0;ON;;;;;N;;;;; +1F06C;DOMINO TILE VERTICAL-01-02;So;0;ON;;;;;N;;;;; +1F06D;DOMINO TILE VERTICAL-01-03;So;0;ON;;;;;N;;;;; +1F06E;DOMINO TILE VERTICAL-01-04;So;0;ON;;;;;N;;;;; +1F06F;DOMINO TILE VERTICAL-01-05;So;0;ON;;;;;N;;;;; +1F070;DOMINO TILE VERTICAL-01-06;So;0;ON;;;;;N;;;;; +1F071;DOMINO TILE VERTICAL-02-00;So;0;ON;;;;;N;;;;; +1F072;DOMINO TILE VERTICAL-02-01;So;0;ON;;;;;N;;;;; +1F073;DOMINO TILE VERTICAL-02-02;So;0;ON;;;;;N;;;;; +1F074;DOMINO TILE VERTICAL-02-03;So;0;ON;;;;;N;;;;; +1F075;DOMINO TILE VERTICAL-02-04;So;0;ON;;;;;N;;;;; +1F076;DOMINO TILE VERTICAL-02-05;So;0;ON;;;;;N;;;;; +1F077;DOMINO TILE VERTICAL-02-06;So;0;ON;;;;;N;;;;; +1F078;DOMINO TILE VERTICAL-03-00;So;0;ON;;;;;N;;;;; +1F079;DOMINO TILE VERTICAL-03-01;So;0;ON;;;;;N;;;;; +1F07A;DOMINO TILE VERTICAL-03-02;So;0;ON;;;;;N;;;;; +1F07B;DOMINO TILE VERTICAL-03-03;So;0;ON;;;;;N;;;;; +1F07C;DOMINO TILE VERTICAL-03-04;So;0;ON;;;;;N;;;;; +1F07D;DOMINO TILE VERTICAL-03-05;So;0;ON;;;;;N;;;;; +1F07E;DOMINO TILE VERTICAL-03-06;So;0;ON;;;;;N;;;;; +1F07F;DOMINO TILE VERTICAL-04-00;So;0;ON;;;;;N;;;;; +1F080;DOMINO TILE VERTICAL-04-01;So;0;ON;;;;;N;;;;; +1F081;DOMINO TILE VERTICAL-04-02;So;0;ON;;;;;N;;;;; +1F082;DOMINO TILE VERTICAL-04-03;So;0;ON;;;;;N;;;;; +1F083;DOMINO TILE VERTICAL-04-04;So;0;ON;;;;;N;;;;; +1F084;DOMINO TILE VERTICAL-04-05;So;0;ON;;;;;N;;;;; +1F085;DOMINO TILE VERTICAL-04-06;So;0;ON;;;;;N;;;;; +1F086;DOMINO TILE VERTICAL-05-00;So;0;ON;;;;;N;;;;; +1F087;DOMINO TILE VERTICAL-05-01;So;0;ON;;;;;N;;;;; +1F088;DOMINO TILE VERTICAL-05-02;So;0;ON;;;;;N;;;;; +1F089;DOMINO TILE VERTICAL-05-03;So;0;ON;;;;;N;;;;; +1F08A;DOMINO TILE VERTICAL-05-04;So;0;ON;;;;;N;;;;; +1F08B;DOMINO TILE VERTICAL-05-05;So;0;ON;;;;;N;;;;; +1F08C;DOMINO TILE VERTICAL-05-06;So;0;ON;;;;;N;;;;; +1F08D;DOMINO TILE VERTICAL-06-00;So;0;ON;;;;;N;;;;; +1F08E;DOMINO TILE VERTICAL-06-01;So;0;ON;;;;;N;;;;; +1F08F;DOMINO TILE VERTICAL-06-02;So;0;ON;;;;;N;;;;; +1F090;DOMINO TILE VERTICAL-06-03;So;0;ON;;;;;N;;;;; +1F091;DOMINO TILE VERTICAL-06-04;So;0;ON;;;;;N;;;;; +1F092;DOMINO TILE VERTICAL-06-05;So;0;ON;;;;;N;;;;; +1F093;DOMINO TILE VERTICAL-06-06;So;0;ON;;;;;N;;;;; +1F0A0;PLAYING CARD BACK;So;0;ON;;;;;N;;;;; +1F0A1;PLAYING CARD ACE OF SPADES;So;0;ON;;;;;N;;;;; +1F0A2;PLAYING CARD TWO OF SPADES;So;0;ON;;;;;N;;;;; +1F0A3;PLAYING CARD THREE OF SPADES;So;0;ON;;;;;N;;;;; +1F0A4;PLAYING CARD FOUR OF SPADES;So;0;ON;;;;;N;;;;; +1F0A5;PLAYING CARD FIVE OF SPADES;So;0;ON;;;;;N;;;;; +1F0A6;PLAYING CARD SIX OF SPADES;So;0;ON;;;;;N;;;;; +1F0A7;PLAYING CARD SEVEN OF SPADES;So;0;ON;;;;;N;;;;; +1F0A8;PLAYING CARD EIGHT OF SPADES;So;0;ON;;;;;N;;;;; +1F0A9;PLAYING CARD NINE OF SPADES;So;0;ON;;;;;N;;;;; +1F0AA;PLAYING CARD TEN OF SPADES;So;0;ON;;;;;N;;;;; +1F0AB;PLAYING CARD JACK OF SPADES;So;0;ON;;;;;N;;;;; +1F0AC;PLAYING CARD KNIGHT OF SPADES;So;0;ON;;;;;N;;;;; +1F0AD;PLAYING CARD QUEEN OF SPADES;So;0;ON;;;;;N;;;;; +1F0AE;PLAYING CARD KING OF SPADES;So;0;ON;;;;;N;;;;; +1F0B1;PLAYING CARD ACE OF HEARTS;So;0;ON;;;;;N;;;;; +1F0B2;PLAYING CARD TWO OF HEARTS;So;0;ON;;;;;N;;;;; +1F0B3;PLAYING CARD THREE OF HEARTS;So;0;ON;;;;;N;;;;; +1F0B4;PLAYING CARD FOUR OF HEARTS;So;0;ON;;;;;N;;;;; +1F0B5;PLAYING CARD FIVE OF HEARTS;So;0;ON;;;;;N;;;;; +1F0B6;PLAYING CARD SIX OF HEARTS;So;0;ON;;;;;N;;;;; +1F0B7;PLAYING CARD SEVEN OF HEARTS;So;0;ON;;;;;N;;;;; +1F0B8;PLAYING CARD EIGHT OF HEARTS;So;0;ON;;;;;N;;;;; +1F0B9;PLAYING CARD NINE OF HEARTS;So;0;ON;;;;;N;;;;; +1F0BA;PLAYING CARD TEN OF HEARTS;So;0;ON;;;;;N;;;;; +1F0BB;PLAYING CARD JACK OF HEARTS;So;0;ON;;;;;N;;;;; +1F0BC;PLAYING CARD KNIGHT OF HEARTS;So;0;ON;;;;;N;;;;; +1F0BD;PLAYING CARD QUEEN OF HEARTS;So;0;ON;;;;;N;;;;; +1F0BE;PLAYING CARD KING OF HEARTS;So;0;ON;;;;;N;;;;; +1F0BF;PLAYING CARD RED JOKER;So;0;ON;;;;;N;;;;; +1F0C1;PLAYING CARD ACE OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0C2;PLAYING CARD TWO OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0C3;PLAYING CARD THREE OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0C4;PLAYING CARD FOUR OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0C5;PLAYING CARD FIVE OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0C6;PLAYING CARD SIX OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0C7;PLAYING CARD SEVEN OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0C8;PLAYING CARD EIGHT OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0C9;PLAYING CARD NINE OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0CA;PLAYING CARD TEN OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0CB;PLAYING CARD JACK OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0CC;PLAYING CARD KNIGHT OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0CD;PLAYING CARD QUEEN OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0CE;PLAYING CARD KING OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0CF;PLAYING CARD BLACK JOKER;So;0;ON;;;;;N;;;;; +1F0D1;PLAYING CARD ACE OF CLUBS;So;0;ON;;;;;N;;;;; +1F0D2;PLAYING CARD TWO OF CLUBS;So;0;ON;;;;;N;;;;; +1F0D3;PLAYING CARD THREE OF CLUBS;So;0;ON;;;;;N;;;;; +1F0D4;PLAYING CARD FOUR OF CLUBS;So;0;ON;;;;;N;;;;; +1F0D5;PLAYING CARD FIVE OF CLUBS;So;0;ON;;;;;N;;;;; +1F0D6;PLAYING CARD SIX OF CLUBS;So;0;ON;;;;;N;;;;; +1F0D7;PLAYING CARD SEVEN OF CLUBS;So;0;ON;;;;;N;;;;; +1F0D8;PLAYING CARD EIGHT OF CLUBS;So;0;ON;;;;;N;;;;; +1F0D9;PLAYING CARD NINE OF CLUBS;So;0;ON;;;;;N;;;;; +1F0DA;PLAYING CARD TEN OF CLUBS;So;0;ON;;;;;N;;;;; +1F0DB;PLAYING CARD JACK OF CLUBS;So;0;ON;;;;;N;;;;; +1F0DC;PLAYING CARD KNIGHT OF CLUBS;So;0;ON;;;;;N;;;;; +1F0DD;PLAYING CARD QUEEN OF CLUBS;So;0;ON;;;;;N;;;;; +1F0DE;PLAYING CARD KING OF CLUBS;So;0;ON;;;;;N;;;;; +1F0DF;PLAYING CARD WHITE JOKER;So;0;ON;;;;;N;;;;; +1F0E0;PLAYING CARD FOOL;So;0;ON;;;;;N;;;;; +1F0E1;PLAYING CARD TRUMP-1;So;0;ON;;;;;N;;;;; +1F0E2;PLAYING CARD TRUMP-2;So;0;ON;;;;;N;;;;; +1F0E3;PLAYING CARD TRUMP-3;So;0;ON;;;;;N;;;;; +1F0E4;PLAYING CARD TRUMP-4;So;0;ON;;;;;N;;;;; +1F0E5;PLAYING CARD TRUMP-5;So;0;ON;;;;;N;;;;; +1F0E6;PLAYING CARD TRUMP-6;So;0;ON;;;;;N;;;;; +1F0E7;PLAYING CARD TRUMP-7;So;0;ON;;;;;N;;;;; +1F0E8;PLAYING CARD TRUMP-8;So;0;ON;;;;;N;;;;; +1F0E9;PLAYING CARD TRUMP-9;So;0;ON;;;;;N;;;;; +1F0EA;PLAYING CARD TRUMP-10;So;0;ON;;;;;N;;;;; +1F0EB;PLAYING CARD TRUMP-11;So;0;ON;;;;;N;;;;; +1F0EC;PLAYING CARD TRUMP-12;So;0;ON;;;;;N;;;;; +1F0ED;PLAYING CARD TRUMP-13;So;0;ON;;;;;N;;;;; +1F0EE;PLAYING CARD TRUMP-14;So;0;ON;;;;;N;;;;; +1F0EF;PLAYING CARD TRUMP-15;So;0;ON;;;;;N;;;;; +1F0F0;PLAYING CARD TRUMP-16;So;0;ON;;;;;N;;;;; +1F0F1;PLAYING CARD TRUMP-17;So;0;ON;;;;;N;;;;; +1F0F2;PLAYING CARD TRUMP-18;So;0;ON;;;;;N;;;;; +1F0F3;PLAYING CARD TRUMP-19;So;0;ON;;;;;N;;;;; +1F0F4;PLAYING CARD TRUMP-20;So;0;ON;;;;;N;;;;; +1F0F5;PLAYING CARD TRUMP-21;So;0;ON;;;;;N;;;;; +1F100;DIGIT ZERO FULL STOP;No;0;EN; 0030 002E;;0;0;N;;;;; +1F101;DIGIT ZERO COMMA;No;0;EN; 0030 002C;;0;0;N;;;;; +1F102;DIGIT ONE COMMA;No;0;EN; 0031 002C;;1;1;N;;;;; +1F103;DIGIT TWO COMMA;No;0;EN; 0032 002C;;2;2;N;;;;; +1F104;DIGIT THREE COMMA;No;0;EN; 0033 002C;;3;3;N;;;;; +1F105;DIGIT FOUR COMMA;No;0;EN; 0034 002C;;4;4;N;;;;; +1F106;DIGIT FIVE COMMA;No;0;EN; 0035 002C;;5;5;N;;;;; +1F107;DIGIT SIX COMMA;No;0;EN; 0036 002C;;6;6;N;;;;; +1F108;DIGIT SEVEN COMMA;No;0;EN; 0037 002C;;7;7;N;;;;; +1F109;DIGIT EIGHT COMMA;No;0;EN; 0038 002C;;8;8;N;;;;; +1F10A;DIGIT NINE COMMA;No;0;EN; 0039 002C;;9;9;N;;;;; +1F10B;DINGBAT CIRCLED SANS-SERIF DIGIT ZERO;No;0;ON;;;;0;N;;;;; +1F10C;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO;No;0;ON;;;;0;N;;;;; +1F10D;CIRCLED ZERO WITH SLASH;So;0;ON;;;;;N;;;;; +1F10E;CIRCLED ANTICLOCKWISE ARROW;So;0;ON;;;;;N;;;;; +1F10F;CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH;So;0;ON;;;;;N;;;;; +1F110;PARENTHESIZED LATIN CAPITAL LETTER A;So;0;L; 0028 0041 0029;;;;N;;;;; +1F111;PARENTHESIZED LATIN CAPITAL LETTER B;So;0;L; 0028 0042 0029;;;;N;;;;; +1F112;PARENTHESIZED LATIN CAPITAL LETTER C;So;0;L; 0028 0043 0029;;;;N;;;;; +1F113;PARENTHESIZED LATIN CAPITAL LETTER D;So;0;L; 0028 0044 0029;;;;N;;;;; +1F114;PARENTHESIZED LATIN CAPITAL LETTER E;So;0;L; 0028 0045 0029;;;;N;;;;; +1F115;PARENTHESIZED LATIN CAPITAL LETTER F;So;0;L; 0028 0046 0029;;;;N;;;;; +1F116;PARENTHESIZED LATIN CAPITAL LETTER G;So;0;L; 0028 0047 0029;;;;N;;;;; +1F117;PARENTHESIZED LATIN CAPITAL LETTER H;So;0;L; 0028 0048 0029;;;;N;;;;; +1F118;PARENTHESIZED LATIN CAPITAL LETTER I;So;0;L; 0028 0049 0029;;;;N;;;;; +1F119;PARENTHESIZED LATIN CAPITAL LETTER J;So;0;L; 0028 004A 0029;;;;N;;;;; +1F11A;PARENTHESIZED LATIN CAPITAL LETTER K;So;0;L; 0028 004B 0029;;;;N;;;;; +1F11B;PARENTHESIZED LATIN CAPITAL LETTER L;So;0;L; 0028 004C 0029;;;;N;;;;; +1F11C;PARENTHESIZED LATIN CAPITAL LETTER M;So;0;L; 0028 004D 0029;;;;N;;;;; +1F11D;PARENTHESIZED LATIN CAPITAL LETTER N;So;0;L; 0028 004E 0029;;;;N;;;;; +1F11E;PARENTHESIZED LATIN CAPITAL LETTER O;So;0;L; 0028 004F 0029;;;;N;;;;; +1F11F;PARENTHESIZED LATIN CAPITAL LETTER P;So;0;L; 0028 0050 0029;;;;N;;;;; +1F120;PARENTHESIZED LATIN CAPITAL LETTER Q;So;0;L; 0028 0051 0029;;;;N;;;;; +1F121;PARENTHESIZED LATIN CAPITAL LETTER R;So;0;L; 0028 0052 0029;;;;N;;;;; +1F122;PARENTHESIZED LATIN CAPITAL LETTER S;So;0;L; 0028 0053 0029;;;;N;;;;; +1F123;PARENTHESIZED LATIN CAPITAL LETTER T;So;0;L; 0028 0054 0029;;;;N;;;;; +1F124;PARENTHESIZED LATIN CAPITAL LETTER U;So;0;L; 0028 0055 0029;;;;N;;;;; +1F125;PARENTHESIZED LATIN CAPITAL LETTER V;So;0;L; 0028 0056 0029;;;;N;;;;; +1F126;PARENTHESIZED LATIN CAPITAL LETTER W;So;0;L; 0028 0057 0029;;;;N;;;;; +1F127;PARENTHESIZED LATIN CAPITAL LETTER X;So;0;L; 0028 0058 0029;;;;N;;;;; +1F128;PARENTHESIZED LATIN CAPITAL LETTER Y;So;0;L; 0028 0059 0029;;;;N;;;;; +1F129;PARENTHESIZED LATIN CAPITAL LETTER Z;So;0;L; 0028 005A 0029;;;;N;;;;; +1F12A;TORTOISE SHELL BRACKETED LATIN CAPITAL LETTER S;So;0;L; 3014 0053 3015;;;;N;;;;; +1F12B;CIRCLED ITALIC LATIN CAPITAL LETTER C;So;0;L; 0043;;;;N;;;;; +1F12C;CIRCLED ITALIC LATIN CAPITAL LETTER R;So;0;L; 0052;;;;N;;;;; +1F12D;CIRCLED CD;So;0;L; 0043 0044;;;;N;;;;; +1F12E;CIRCLED WZ;So;0;L; 0057 005A;;;;N;;;;; +1F12F;COPYLEFT SYMBOL;So;0;ON;;;;;N;;;;; +1F130;SQUARED LATIN CAPITAL LETTER A;So;0;L; 0041;;;;N;;;;; +1F131;SQUARED LATIN CAPITAL LETTER B;So;0;L; 0042;;;;N;;;;; +1F132;SQUARED LATIN CAPITAL LETTER C;So;0;L; 0043;;;;N;;;;; +1F133;SQUARED LATIN CAPITAL LETTER D;So;0;L; 0044;;;;N;;;;; +1F134;SQUARED LATIN CAPITAL LETTER E;So;0;L; 0045;;;;N;;;;; +1F135;SQUARED LATIN CAPITAL LETTER F;So;0;L; 0046;;;;N;;;;; +1F136;SQUARED LATIN CAPITAL LETTER G;So;0;L; 0047;;;;N;;;;; +1F137;SQUARED LATIN CAPITAL LETTER H;So;0;L; 0048;;;;N;;;;; +1F138;SQUARED LATIN CAPITAL LETTER I;So;0;L; 0049;;;;N;;;;; +1F139;SQUARED LATIN CAPITAL LETTER J;So;0;L; 004A;;;;N;;;;; +1F13A;SQUARED LATIN CAPITAL LETTER K;So;0;L; 004B;;;;N;;;;; +1F13B;SQUARED LATIN CAPITAL LETTER L;So;0;L; 004C;;;;N;;;;; +1F13C;SQUARED LATIN CAPITAL LETTER M;So;0;L; 004D;;;;N;;;;; +1F13D;SQUARED LATIN CAPITAL LETTER N;So;0;L; 004E;;;;N;;;;; +1F13E;SQUARED LATIN CAPITAL LETTER O;So;0;L; 004F;;;;N;;;;; +1F13F;SQUARED LATIN CAPITAL LETTER P;So;0;L; 0050;;;;N;;;;; +1F140;SQUARED LATIN CAPITAL LETTER Q;So;0;L; 0051;;;;N;;;;; +1F141;SQUARED LATIN CAPITAL LETTER R;So;0;L; 0052;;;;N;;;;; +1F142;SQUARED LATIN CAPITAL LETTER S;So;0;L; 0053;;;;N;;;;; +1F143;SQUARED LATIN CAPITAL LETTER T;So;0;L; 0054;;;;N;;;;; +1F144;SQUARED LATIN CAPITAL LETTER U;So;0;L; 0055;;;;N;;;;; +1F145;SQUARED LATIN CAPITAL LETTER V;So;0;L; 0056;;;;N;;;;; +1F146;SQUARED LATIN CAPITAL LETTER W;So;0;L; 0057;;;;N;;;;; +1F147;SQUARED LATIN CAPITAL LETTER X;So;0;L; 0058;;;;N;;;;; +1F148;SQUARED LATIN CAPITAL LETTER Y;So;0;L; 0059;;;;N;;;;; +1F149;SQUARED LATIN CAPITAL LETTER Z;So;0;L; 005A;;;;N;;;;; +1F14A;SQUARED HV;So;0;L; 0048 0056;;;;N;;;;; +1F14B;SQUARED MV;So;0;L; 004D 0056;;;;N;;;;; +1F14C;SQUARED SD;So;0;L; 0053 0044;;;;N;;;;; +1F14D;SQUARED SS;So;0;L; 0053 0053;;;;N;;;;; +1F14E;SQUARED PPV;So;0;L; 0050 0050 0056;;;;N;;;;; +1F14F;SQUARED WC;So;0;L; 0057 0043;;;;N;;;;; +1F150;NEGATIVE CIRCLED LATIN CAPITAL LETTER A;So;0;L;;;;;N;;;;; +1F151;NEGATIVE CIRCLED LATIN CAPITAL LETTER B;So;0;L;;;;;N;;;;; +1F152;NEGATIVE CIRCLED LATIN CAPITAL LETTER C;So;0;L;;;;;N;;;;; +1F153;NEGATIVE CIRCLED LATIN CAPITAL LETTER D;So;0;L;;;;;N;;;;; +1F154;NEGATIVE CIRCLED LATIN CAPITAL LETTER E;So;0;L;;;;;N;;;;; +1F155;NEGATIVE CIRCLED LATIN CAPITAL LETTER F;So;0;L;;;;;N;;;;; +1F156;NEGATIVE CIRCLED LATIN CAPITAL LETTER G;So;0;L;;;;;N;;;;; +1F157;NEGATIVE CIRCLED LATIN CAPITAL LETTER H;So;0;L;;;;;N;;;;; +1F158;NEGATIVE CIRCLED LATIN CAPITAL LETTER I;So;0;L;;;;;N;;;;; +1F159;NEGATIVE CIRCLED LATIN CAPITAL LETTER J;So;0;L;;;;;N;;;;; +1F15A;NEGATIVE CIRCLED LATIN CAPITAL LETTER K;So;0;L;;;;;N;;;;; +1F15B;NEGATIVE CIRCLED LATIN CAPITAL LETTER L;So;0;L;;;;;N;;;;; +1F15C;NEGATIVE CIRCLED LATIN CAPITAL LETTER M;So;0;L;;;;;N;;;;; +1F15D;NEGATIVE CIRCLED LATIN CAPITAL LETTER N;So;0;L;;;;;N;;;;; +1F15E;NEGATIVE CIRCLED LATIN CAPITAL LETTER O;So;0;L;;;;;N;;;;; +1F15F;NEGATIVE CIRCLED LATIN CAPITAL LETTER P;So;0;L;;;;;N;;;;; +1F160;NEGATIVE CIRCLED LATIN CAPITAL LETTER Q;So;0;L;;;;;N;;;;; +1F161;NEGATIVE CIRCLED LATIN CAPITAL LETTER R;So;0;L;;;;;N;;;;; +1F162;NEGATIVE CIRCLED LATIN CAPITAL LETTER S;So;0;L;;;;;N;;;;; +1F163;NEGATIVE CIRCLED LATIN CAPITAL LETTER T;So;0;L;;;;;N;;;;; +1F164;NEGATIVE CIRCLED LATIN CAPITAL LETTER U;So;0;L;;;;;N;;;;; +1F165;NEGATIVE CIRCLED LATIN CAPITAL LETTER V;So;0;L;;;;;N;;;;; +1F166;NEGATIVE CIRCLED LATIN CAPITAL LETTER W;So;0;L;;;;;N;;;;; +1F167;NEGATIVE CIRCLED LATIN CAPITAL LETTER X;So;0;L;;;;;N;;;;; +1F168;NEGATIVE CIRCLED LATIN CAPITAL LETTER Y;So;0;L;;;;;N;;;;; +1F169;NEGATIVE CIRCLED LATIN CAPITAL LETTER Z;So;0;L;;;;;N;;;;; +1F16A;RAISED MC SIGN;So;0;ON; 004D 0043;;;;N;;;;; +1F16B;RAISED MD SIGN;So;0;ON; 004D 0044;;;;N;;;;; +1F16C;RAISED MR SIGN;So;0;ON; 004D 0052;;;;N;;;;; +1F16D;CIRCLED CC;So;0;ON;;;;;N;;;;; +1F16E;CIRCLED C WITH OVERLAID BACKSLASH;So;0;ON;;;;;N;;;;; +1F16F;CIRCLED HUMAN FIGURE;So;0;ON;;;;;N;;;;; +1F170;NEGATIVE SQUARED LATIN CAPITAL LETTER A;So;0;L;;;;;N;;;;; +1F171;NEGATIVE SQUARED LATIN CAPITAL LETTER B;So;0;L;;;;;N;;;;; +1F172;NEGATIVE SQUARED LATIN CAPITAL LETTER C;So;0;L;;;;;N;;;;; +1F173;NEGATIVE SQUARED LATIN CAPITAL LETTER D;So;0;L;;;;;N;;;;; +1F174;NEGATIVE SQUARED LATIN CAPITAL LETTER E;So;0;L;;;;;N;;;;; +1F175;NEGATIVE SQUARED LATIN CAPITAL LETTER F;So;0;L;;;;;N;;;;; +1F176;NEGATIVE SQUARED LATIN CAPITAL LETTER G;So;0;L;;;;;N;;;;; +1F177;NEGATIVE SQUARED LATIN CAPITAL LETTER H;So;0;L;;;;;N;;;;; +1F178;NEGATIVE SQUARED LATIN CAPITAL LETTER I;So;0;L;;;;;N;;;;; +1F179;NEGATIVE SQUARED LATIN CAPITAL LETTER J;So;0;L;;;;;N;;;;; +1F17A;NEGATIVE SQUARED LATIN CAPITAL LETTER K;So;0;L;;;;;N;;;;; +1F17B;NEGATIVE SQUARED LATIN CAPITAL LETTER L;So;0;L;;;;;N;;;;; +1F17C;NEGATIVE SQUARED LATIN CAPITAL LETTER M;So;0;L;;;;;N;;;;; +1F17D;NEGATIVE SQUARED LATIN CAPITAL LETTER N;So;0;L;;;;;N;;;;; +1F17E;NEGATIVE SQUARED LATIN CAPITAL LETTER O;So;0;L;;;;;N;;;;; +1F17F;NEGATIVE SQUARED LATIN CAPITAL LETTER P;So;0;L;;;;;N;;;;; +1F180;NEGATIVE SQUARED LATIN CAPITAL LETTER Q;So;0;L;;;;;N;;;;; +1F181;NEGATIVE SQUARED LATIN CAPITAL LETTER R;So;0;L;;;;;N;;;;; +1F182;NEGATIVE SQUARED LATIN CAPITAL LETTER S;So;0;L;;;;;N;;;;; +1F183;NEGATIVE SQUARED LATIN CAPITAL LETTER T;So;0;L;;;;;N;;;;; +1F184;NEGATIVE SQUARED LATIN CAPITAL LETTER U;So;0;L;;;;;N;;;;; +1F185;NEGATIVE SQUARED LATIN CAPITAL LETTER V;So;0;L;;;;;N;;;;; +1F186;NEGATIVE SQUARED LATIN CAPITAL LETTER W;So;0;L;;;;;N;;;;; +1F187;NEGATIVE SQUARED LATIN CAPITAL LETTER X;So;0;L;;;;;N;;;;; +1F188;NEGATIVE SQUARED LATIN CAPITAL LETTER Y;So;0;L;;;;;N;;;;; +1F189;NEGATIVE SQUARED LATIN CAPITAL LETTER Z;So;0;L;;;;;N;;;;; +1F18A;CROSSED NEGATIVE SQUARED LATIN CAPITAL LETTER P;So;0;L;;;;;N;;;;; +1F18B;NEGATIVE SQUARED IC;So;0;L;;;;;N;;;;; +1F18C;NEGATIVE SQUARED PA;So;0;L;;;;;N;;;;; +1F18D;NEGATIVE SQUARED SA;So;0;L;;;;;N;;;;; +1F18E;NEGATIVE SQUARED AB;So;0;L;;;;;N;;;;; +1F18F;NEGATIVE SQUARED WC;So;0;L;;;;;N;;;;; +1F190;SQUARE DJ;So;0;L; 0044 004A;;;;N;;;;; +1F191;SQUARED CL;So;0;L;;;;;N;;;;; +1F192;SQUARED COOL;So;0;L;;;;;N;;;;; +1F193;SQUARED FREE;So;0;L;;;;;N;;;;; +1F194;SQUARED ID;So;0;L;;;;;N;;;;; +1F195;SQUARED NEW;So;0;L;;;;;N;;;;; +1F196;SQUARED NG;So;0;L;;;;;N;;;;; +1F197;SQUARED OK;So;0;L;;;;;N;;;;; +1F198;SQUARED SOS;So;0;L;;;;;N;;;;; +1F199;SQUARED UP WITH EXCLAMATION MARK;So;0;L;;;;;N;;;;; +1F19A;SQUARED VS;So;0;L;;;;;N;;;;; +1F19B;SQUARED THREE D;So;0;L;;;;;N;;;;; +1F19C;SQUARED SECOND SCREEN;So;0;L;;;;;N;;;;; +1F19D;SQUARED TWO K;So;0;L;;;;;N;;;;; +1F19E;SQUARED FOUR K;So;0;L;;;;;N;;;;; +1F19F;SQUARED EIGHT K;So;0;L;;;;;N;;;;; +1F1A0;SQUARED FIVE POINT ONE;So;0;L;;;;;N;;;;; +1F1A1;SQUARED SEVEN POINT ONE;So;0;L;;;;;N;;;;; +1F1A2;SQUARED TWENTY-TWO POINT TWO;So;0;L;;;;;N;;;;; +1F1A3;SQUARED SIXTY P;So;0;L;;;;;N;;;;; +1F1A4;SQUARED ONE HUNDRED TWENTY P;So;0;L;;;;;N;;;;; +1F1A5;SQUARED LATIN SMALL LETTER D;So;0;L;;;;;N;;;;; +1F1A6;SQUARED HC;So;0;L;;;;;N;;;;; +1F1A7;SQUARED HDR;So;0;L;;;;;N;;;;; +1F1A8;SQUARED HI-RES;So;0;L;;;;;N;;;;; +1F1A9;SQUARED LOSSLESS;So;0;L;;;;;N;;;;; +1F1AA;SQUARED SHV;So;0;L;;;;;N;;;;; +1F1AB;SQUARED UHD;So;0;L;;;;;N;;;;; +1F1AC;SQUARED VOD;So;0;L;;;;;N;;;;; +1F1AD;MASK WORK SYMBOL;So;0;ON;;;;;N;;;;; +1F1E6;REGIONAL INDICATOR SYMBOL LETTER A;So;0;L;;;;;N;;;;; +1F1E7;REGIONAL INDICATOR SYMBOL LETTER B;So;0;L;;;;;N;;;;; +1F1E8;REGIONAL INDICATOR SYMBOL LETTER C;So;0;L;;;;;N;;;;; +1F1E9;REGIONAL INDICATOR SYMBOL LETTER D;So;0;L;;;;;N;;;;; +1F1EA;REGIONAL INDICATOR SYMBOL LETTER E;So;0;L;;;;;N;;;;; +1F1EB;REGIONAL INDICATOR SYMBOL LETTER F;So;0;L;;;;;N;;;;; +1F1EC;REGIONAL INDICATOR SYMBOL LETTER G;So;0;L;;;;;N;;;;; +1F1ED;REGIONAL INDICATOR SYMBOL LETTER H;So;0;L;;;;;N;;;;; +1F1EE;REGIONAL INDICATOR SYMBOL LETTER I;So;0;L;;;;;N;;;;; +1F1EF;REGIONAL INDICATOR SYMBOL LETTER J;So;0;L;;;;;N;;;;; +1F1F0;REGIONAL INDICATOR SYMBOL LETTER K;So;0;L;;;;;N;;;;; +1F1F1;REGIONAL INDICATOR SYMBOL LETTER L;So;0;L;;;;;N;;;;; +1F1F2;REGIONAL INDICATOR SYMBOL LETTER M;So;0;L;;;;;N;;;;; +1F1F3;REGIONAL INDICATOR SYMBOL LETTER N;So;0;L;;;;;N;;;;; +1F1F4;REGIONAL INDICATOR SYMBOL LETTER O;So;0;L;;;;;N;;;;; +1F1F5;REGIONAL INDICATOR SYMBOL LETTER P;So;0;L;;;;;N;;;;; +1F1F6;REGIONAL INDICATOR SYMBOL LETTER Q;So;0;L;;;;;N;;;;; +1F1F7;REGIONAL INDICATOR SYMBOL LETTER R;So;0;L;;;;;N;;;;; +1F1F8;REGIONAL INDICATOR SYMBOL LETTER S;So;0;L;;;;;N;;;;; +1F1F9;REGIONAL INDICATOR SYMBOL LETTER T;So;0;L;;;;;N;;;;; +1F1FA;REGIONAL INDICATOR SYMBOL LETTER U;So;0;L;;;;;N;;;;; +1F1FB;REGIONAL INDICATOR SYMBOL LETTER V;So;0;L;;;;;N;;;;; +1F1FC;REGIONAL INDICATOR SYMBOL LETTER W;So;0;L;;;;;N;;;;; +1F1FD;REGIONAL INDICATOR SYMBOL LETTER X;So;0;L;;;;;N;;;;; +1F1FE;REGIONAL INDICATOR SYMBOL LETTER Y;So;0;L;;;;;N;;;;; +1F1FF;REGIONAL INDICATOR SYMBOL LETTER Z;So;0;L;;;;;N;;;;; +1F200;SQUARE HIRAGANA HOKA;So;0;L; 307B 304B;;;;N;;;;; +1F201;SQUARED KATAKANA KOKO;So;0;L; 30B3 30B3;;;;N;;;;; +1F202;SQUARED KATAKANA SA;So;0;L; 30B5;;;;N;;;;; +1F210;SQUARED CJK UNIFIED IDEOGRAPH-624B;So;0;L; 624B;;;;N;;;;; +1F211;SQUARED CJK UNIFIED IDEOGRAPH-5B57;So;0;L; 5B57;;;;N;;;;; +1F212;SQUARED CJK UNIFIED IDEOGRAPH-53CC;So;0;L; 53CC;;;;N;;;;; +1F213;SQUARED KATAKANA DE;So;0;L; 30C7;;;;N;;;;; +1F214;SQUARED CJK UNIFIED IDEOGRAPH-4E8C;So;0;L; 4E8C;;;;N;;;;; +1F215;SQUARED CJK UNIFIED IDEOGRAPH-591A;So;0;L; 591A;;;;N;;;;; +1F216;SQUARED CJK UNIFIED IDEOGRAPH-89E3;So;0;L; 89E3;;;;N;;;;; +1F217;SQUARED CJK UNIFIED IDEOGRAPH-5929;So;0;L; 5929;;;;N;;;;; +1F218;SQUARED CJK UNIFIED IDEOGRAPH-4EA4;So;0;L; 4EA4;;;;N;;;;; +1F219;SQUARED CJK UNIFIED IDEOGRAPH-6620;So;0;L; 6620;;;;N;;;;; +1F21A;SQUARED CJK UNIFIED IDEOGRAPH-7121;So;0;L; 7121;;;;N;;;;; +1F21B;SQUARED CJK UNIFIED IDEOGRAPH-6599;So;0;L; 6599;;;;N;;;;; +1F21C;SQUARED CJK UNIFIED IDEOGRAPH-524D;So;0;L; 524D;;;;N;;;;; +1F21D;SQUARED CJK UNIFIED IDEOGRAPH-5F8C;So;0;L; 5F8C;;;;N;;;;; +1F21E;SQUARED CJK UNIFIED IDEOGRAPH-518D;So;0;L; 518D;;;;N;;;;; +1F21F;SQUARED CJK UNIFIED IDEOGRAPH-65B0;So;0;L; 65B0;;;;N;;;;; +1F220;SQUARED CJK UNIFIED IDEOGRAPH-521D;So;0;L; 521D;;;;N;;;;; +1F221;SQUARED CJK UNIFIED IDEOGRAPH-7D42;So;0;L; 7D42;;;;N;;;;; +1F222;SQUARED CJK UNIFIED IDEOGRAPH-751F;So;0;L; 751F;;;;N;;;;; +1F223;SQUARED CJK UNIFIED IDEOGRAPH-8CA9;So;0;L; 8CA9;;;;N;;;;; +1F224;SQUARED CJK UNIFIED IDEOGRAPH-58F0;So;0;L; 58F0;;;;N;;;;; +1F225;SQUARED CJK UNIFIED IDEOGRAPH-5439;So;0;L; 5439;;;;N;;;;; +1F226;SQUARED CJK UNIFIED IDEOGRAPH-6F14;So;0;L; 6F14;;;;N;;;;; +1F227;SQUARED CJK UNIFIED IDEOGRAPH-6295;So;0;L; 6295;;;;N;;;;; +1F228;SQUARED CJK UNIFIED IDEOGRAPH-6355;So;0;L; 6355;;;;N;;;;; +1F229;SQUARED CJK UNIFIED IDEOGRAPH-4E00;So;0;L; 4E00;;;;N;;;;; +1F22A;SQUARED CJK UNIFIED IDEOGRAPH-4E09;So;0;L; 4E09;;;;N;;;;; +1F22B;SQUARED CJK UNIFIED IDEOGRAPH-904A;So;0;L; 904A;;;;N;;;;; +1F22C;SQUARED CJK UNIFIED IDEOGRAPH-5DE6;So;0;L; 5DE6;;;;N;;;;; +1F22D;SQUARED CJK UNIFIED IDEOGRAPH-4E2D;So;0;L; 4E2D;;;;N;;;;; +1F22E;SQUARED CJK UNIFIED IDEOGRAPH-53F3;So;0;L; 53F3;;;;N;;;;; +1F22F;SQUARED CJK UNIFIED IDEOGRAPH-6307;So;0;L; 6307;;;;N;;;;; +1F230;SQUARED CJK UNIFIED IDEOGRAPH-8D70;So;0;L; 8D70;;;;N;;;;; +1F231;SQUARED CJK UNIFIED IDEOGRAPH-6253;So;0;L; 6253;;;;N;;;;; +1F232;SQUARED CJK UNIFIED IDEOGRAPH-7981;So;0;L; 7981;;;;N;;;;; +1F233;SQUARED CJK UNIFIED IDEOGRAPH-7A7A;So;0;L; 7A7A;;;;N;;;;; +1F234;SQUARED CJK UNIFIED IDEOGRAPH-5408;So;0;L; 5408;;;;N;;;;; +1F235;SQUARED CJK UNIFIED IDEOGRAPH-6E80;So;0;L; 6E80;;;;N;;;;; +1F236;SQUARED CJK UNIFIED IDEOGRAPH-6709;So;0;L; 6709;;;;N;;;;; +1F237;SQUARED CJK UNIFIED IDEOGRAPH-6708;So;0;L; 6708;;;;N;;;;; +1F238;SQUARED CJK UNIFIED IDEOGRAPH-7533;So;0;L; 7533;;;;N;;;;; +1F239;SQUARED CJK UNIFIED IDEOGRAPH-5272;So;0;L; 5272;;;;N;;;;; +1F23A;SQUARED CJK UNIFIED IDEOGRAPH-55B6;So;0;L; 55B6;;;;N;;;;; +1F23B;SQUARED CJK UNIFIED IDEOGRAPH-914D;So;0;L; 914D;;;;N;;;;; +1F240;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C;So;0;L; 3014 672C 3015;;;;N;;;;; +1F241;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E09;So;0;L; 3014 4E09 3015;;;;N;;;;; +1F242;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E8C;So;0;L; 3014 4E8C 3015;;;;N;;;;; +1F243;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-5B89;So;0;L; 3014 5B89 3015;;;;N;;;;; +1F244;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-70B9;So;0;L; 3014 70B9 3015;;;;N;;;;; +1F245;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6253;So;0;L; 3014 6253 3015;;;;N;;;;; +1F246;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-76D7;So;0;L; 3014 76D7 3015;;;;N;;;;; +1F247;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-52DD;So;0;L; 3014 52DD 3015;;;;N;;;;; +1F248;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557;So;0;L; 3014 6557 3015;;;;N;;;;; +1F250;CIRCLED IDEOGRAPH ADVANTAGE;So;0;L; 5F97;;;;N;;;;; +1F251;CIRCLED IDEOGRAPH ACCEPT;So;0;L; 53EF;;;;N;;;;; +1F260;ROUNDED SYMBOL FOR FU;So;0;ON;;;;;N;;;;; +1F261;ROUNDED SYMBOL FOR LU;So;0;ON;;;;;N;;;;; +1F262;ROUNDED SYMBOL FOR SHOU;So;0;ON;;;;;N;;;;; +1F263;ROUNDED SYMBOL FOR XI;So;0;ON;;;;;N;;;;; +1F264;ROUNDED SYMBOL FOR SHUANGXI;So;0;ON;;;;;N;;;;; +1F265;ROUNDED SYMBOL FOR CAI;So;0;ON;;;;;N;;;;; +1F300;CYCLONE;So;0;ON;;;;;N;;;;; +1F301;FOGGY;So;0;ON;;;;;N;;;;; +1F302;CLOSED UMBRELLA;So;0;ON;;;;;N;;;;; +1F303;NIGHT WITH STARS;So;0;ON;;;;;N;;;;; +1F304;SUNRISE OVER MOUNTAINS;So;0;ON;;;;;N;;;;; +1F305;SUNRISE;So;0;ON;;;;;N;;;;; +1F306;CITYSCAPE AT DUSK;So;0;ON;;;;;N;;;;; +1F307;SUNSET OVER BUILDINGS;So;0;ON;;;;;N;;;;; +1F308;RAINBOW;So;0;ON;;;;;N;;;;; +1F309;BRIDGE AT NIGHT;So;0;ON;;;;;N;;;;; +1F30A;WATER WAVE;So;0;ON;;;;;N;;;;; +1F30B;VOLCANO;So;0;ON;;;;;N;;;;; +1F30C;MILKY WAY;So;0;ON;;;;;N;;;;; +1F30D;EARTH GLOBE EUROPE-AFRICA;So;0;ON;;;;;N;;;;; +1F30E;EARTH GLOBE AMERICAS;So;0;ON;;;;;N;;;;; +1F30F;EARTH GLOBE ASIA-AUSTRALIA;So;0;ON;;;;;N;;;;; +1F310;GLOBE WITH MERIDIANS;So;0;ON;;;;;N;;;;; +1F311;NEW MOON SYMBOL;So;0;ON;;;;;N;;;;; +1F312;WAXING CRESCENT MOON SYMBOL;So;0;ON;;;;;N;;;;; +1F313;FIRST QUARTER MOON SYMBOL;So;0;ON;;;;;N;;;;; +1F314;WAXING GIBBOUS MOON SYMBOL;So;0;ON;;;;;N;;;;; +1F315;FULL MOON SYMBOL;So;0;ON;;;;;N;;;;; +1F316;WANING GIBBOUS MOON SYMBOL;So;0;ON;;;;;N;;;;; +1F317;LAST QUARTER MOON SYMBOL;So;0;ON;;;;;N;;;;; +1F318;WANING CRESCENT MOON SYMBOL;So;0;ON;;;;;N;;;;; +1F319;CRESCENT MOON;So;0;ON;;;;;N;;;;; +1F31A;NEW MOON WITH FACE;So;0;ON;;;;;N;;;;; +1F31B;FIRST QUARTER MOON WITH FACE;So;0;ON;;;;;N;;;;; +1F31C;LAST QUARTER MOON WITH FACE;So;0;ON;;;;;N;;;;; +1F31D;FULL MOON WITH FACE;So;0;ON;;;;;N;;;;; +1F31E;SUN WITH FACE;So;0;ON;;;;;N;;;;; +1F31F;GLOWING STAR;So;0;ON;;;;;N;;;;; +1F320;SHOOTING STAR;So;0;ON;;;;;N;;;;; +1F321;THERMOMETER;So;0;ON;;;;;N;;;;; +1F322;BLACK DROPLET;So;0;ON;;;;;N;;;;; +1F323;WHITE SUN;So;0;ON;;;;;N;;;;; +1F324;WHITE SUN WITH SMALL CLOUD;So;0;ON;;;;;N;;;;; +1F325;WHITE SUN BEHIND CLOUD;So;0;ON;;;;;N;;;;; +1F326;WHITE SUN BEHIND CLOUD WITH RAIN;So;0;ON;;;;;N;;;;; +1F327;CLOUD WITH RAIN;So;0;ON;;;;;N;;;;; +1F328;CLOUD WITH SNOW;So;0;ON;;;;;N;;;;; +1F329;CLOUD WITH LIGHTNING;So;0;ON;;;;;N;;;;; +1F32A;CLOUD WITH TORNADO;So;0;ON;;;;;N;;;;; +1F32B;FOG;So;0;ON;;;;;N;;;;; +1F32C;WIND BLOWING FACE;So;0;ON;;;;;N;;;;; +1F32D;HOT DOG;So;0;ON;;;;;N;;;;; +1F32E;TACO;So;0;ON;;;;;N;;;;; +1F32F;BURRITO;So;0;ON;;;;;N;;;;; +1F330;CHESTNUT;So;0;ON;;;;;N;;;;; +1F331;SEEDLING;So;0;ON;;;;;N;;;;; +1F332;EVERGREEN TREE;So;0;ON;;;;;N;;;;; +1F333;DECIDUOUS TREE;So;0;ON;;;;;N;;;;; +1F334;PALM TREE;So;0;ON;;;;;N;;;;; +1F335;CACTUS;So;0;ON;;;;;N;;;;; +1F336;HOT PEPPER;So;0;ON;;;;;N;;;;; +1F337;TULIP;So;0;ON;;;;;N;;;;; +1F338;CHERRY BLOSSOM;So;0;ON;;;;;N;;;;; +1F339;ROSE;So;0;ON;;;;;N;;;;; +1F33A;HIBISCUS;So;0;ON;;;;;N;;;;; +1F33B;SUNFLOWER;So;0;ON;;;;;N;;;;; +1F33C;BLOSSOM;So;0;ON;;;;;N;;;;; +1F33D;EAR OF MAIZE;So;0;ON;;;;;N;;;;; +1F33E;EAR OF RICE;So;0;ON;;;;;N;;;;; +1F33F;HERB;So;0;ON;;;;;N;;;;; +1F340;FOUR LEAF CLOVER;So;0;ON;;;;;N;;;;; +1F341;MAPLE LEAF;So;0;ON;;;;;N;;;;; +1F342;FALLEN LEAF;So;0;ON;;;;;N;;;;; +1F343;LEAF FLUTTERING IN WIND;So;0;ON;;;;;N;;;;; +1F344;MUSHROOM;So;0;ON;;;;;N;;;;; +1F345;TOMATO;So;0;ON;;;;;N;;;;; +1F346;AUBERGINE;So;0;ON;;;;;N;;;;; +1F347;GRAPES;So;0;ON;;;;;N;;;;; +1F348;MELON;So;0;ON;;;;;N;;;;; +1F349;WATERMELON;So;0;ON;;;;;N;;;;; +1F34A;TANGERINE;So;0;ON;;;;;N;;;;; +1F34B;LEMON;So;0;ON;;;;;N;;;;; +1F34C;BANANA;So;0;ON;;;;;N;;;;; +1F34D;PINEAPPLE;So;0;ON;;;;;N;;;;; +1F34E;RED APPLE;So;0;ON;;;;;N;;;;; +1F34F;GREEN APPLE;So;0;ON;;;;;N;;;;; +1F350;PEAR;So;0;ON;;;;;N;;;;; +1F351;PEACH;So;0;ON;;;;;N;;;;; +1F352;CHERRIES;So;0;ON;;;;;N;;;;; +1F353;STRAWBERRY;So;0;ON;;;;;N;;;;; +1F354;HAMBURGER;So;0;ON;;;;;N;;;;; +1F355;SLICE OF PIZZA;So;0;ON;;;;;N;;;;; +1F356;MEAT ON BONE;So;0;ON;;;;;N;;;;; +1F357;POULTRY LEG;So;0;ON;;;;;N;;;;; +1F358;RICE CRACKER;So;0;ON;;;;;N;;;;; +1F359;RICE BALL;So;0;ON;;;;;N;;;;; +1F35A;COOKED RICE;So;0;ON;;;;;N;;;;; +1F35B;CURRY AND RICE;So;0;ON;;;;;N;;;;; +1F35C;STEAMING BOWL;So;0;ON;;;;;N;;;;; +1F35D;SPAGHETTI;So;0;ON;;;;;N;;;;; +1F35E;BREAD;So;0;ON;;;;;N;;;;; +1F35F;FRENCH FRIES;So;0;ON;;;;;N;;;;; +1F360;ROASTED SWEET POTATO;So;0;ON;;;;;N;;;;; +1F361;DANGO;So;0;ON;;;;;N;;;;; +1F362;ODEN;So;0;ON;;;;;N;;;;; +1F363;SUSHI;So;0;ON;;;;;N;;;;; +1F364;FRIED SHRIMP;So;0;ON;;;;;N;;;;; +1F365;FISH CAKE WITH SWIRL DESIGN;So;0;ON;;;;;N;;;;; +1F366;SOFT ICE CREAM;So;0;ON;;;;;N;;;;; +1F367;SHAVED ICE;So;0;ON;;;;;N;;;;; +1F368;ICE CREAM;So;0;ON;;;;;N;;;;; +1F369;DOUGHNUT;So;0;ON;;;;;N;;;;; +1F36A;COOKIE;So;0;ON;;;;;N;;;;; +1F36B;CHOCOLATE BAR;So;0;ON;;;;;N;;;;; +1F36C;CANDY;So;0;ON;;;;;N;;;;; +1F36D;LOLLIPOP;So;0;ON;;;;;N;;;;; +1F36E;CUSTARD;So;0;ON;;;;;N;;;;; +1F36F;HONEY POT;So;0;ON;;;;;N;;;;; +1F370;SHORTCAKE;So;0;ON;;;;;N;;;;; +1F371;BENTO BOX;So;0;ON;;;;;N;;;;; +1F372;POT OF FOOD;So;0;ON;;;;;N;;;;; +1F373;COOKING;So;0;ON;;;;;N;;;;; +1F374;FORK AND KNIFE;So;0;ON;;;;;N;;;;; +1F375;TEACUP WITHOUT HANDLE;So;0;ON;;;;;N;;;;; +1F376;SAKE BOTTLE AND CUP;So;0;ON;;;;;N;;;;; +1F377;WINE GLASS;So;0;ON;;;;;N;;;;; +1F378;COCKTAIL GLASS;So;0;ON;;;;;N;;;;; +1F379;TROPICAL DRINK;So;0;ON;;;;;N;;;;; +1F37A;BEER MUG;So;0;ON;;;;;N;;;;; +1F37B;CLINKING BEER MUGS;So;0;ON;;;;;N;;;;; +1F37C;BABY BOTTLE;So;0;ON;;;;;N;;;;; +1F37D;FORK AND KNIFE WITH PLATE;So;0;ON;;;;;N;;;;; +1F37E;BOTTLE WITH POPPING CORK;So;0;ON;;;;;N;;;;; +1F37F;POPCORN;So;0;ON;;;;;N;;;;; +1F380;RIBBON;So;0;ON;;;;;N;;;;; +1F381;WRAPPED PRESENT;So;0;ON;;;;;N;;;;; +1F382;BIRTHDAY CAKE;So;0;ON;;;;;N;;;;; +1F383;JACK-O-LANTERN;So;0;ON;;;;;N;;;;; +1F384;CHRISTMAS TREE;So;0;ON;;;;;N;;;;; +1F385;FATHER CHRISTMAS;So;0;ON;;;;;N;;;;; +1F386;FIREWORKS;So;0;ON;;;;;N;;;;; +1F387;FIREWORK SPARKLER;So;0;ON;;;;;N;;;;; +1F388;BALLOON;So;0;ON;;;;;N;;;;; +1F389;PARTY POPPER;So;0;ON;;;;;N;;;;; +1F38A;CONFETTI BALL;So;0;ON;;;;;N;;;;; +1F38B;TANABATA TREE;So;0;ON;;;;;N;;;;; +1F38C;CROSSED FLAGS;So;0;ON;;;;;N;;;;; +1F38D;PINE DECORATION;So;0;ON;;;;;N;;;;; +1F38E;JAPANESE DOLLS;So;0;ON;;;;;N;;;;; +1F38F;CARP STREAMER;So;0;ON;;;;;N;;;;; +1F390;WIND CHIME;So;0;ON;;;;;N;;;;; +1F391;MOON VIEWING CEREMONY;So;0;ON;;;;;N;;;;; +1F392;SCHOOL SATCHEL;So;0;ON;;;;;N;;;;; +1F393;GRADUATION CAP;So;0;ON;;;;;N;;;;; +1F394;HEART WITH TIP ON THE LEFT;So;0;ON;;;;;N;;;;; +1F395;BOUQUET OF FLOWERS;So;0;ON;;;;;N;;;;; +1F396;MILITARY MEDAL;So;0;ON;;;;;N;;;;; +1F397;REMINDER RIBBON;So;0;ON;;;;;N;;;;; +1F398;MUSICAL KEYBOARD WITH JACKS;So;0;ON;;;;;N;;;;; +1F399;STUDIO MICROPHONE;So;0;ON;;;;;N;;;;; +1F39A;LEVEL SLIDER;So;0;ON;;;;;N;;;;; +1F39B;CONTROL KNOBS;So;0;ON;;;;;N;;;;; +1F39C;BEAMED ASCENDING MUSICAL NOTES;So;0;ON;;;;;N;;;;; +1F39D;BEAMED DESCENDING MUSICAL NOTES;So;0;ON;;;;;N;;;;; +1F39E;FILM FRAMES;So;0;ON;;;;;N;;;;; +1F39F;ADMISSION TICKETS;So;0;ON;;;;;N;;;;; +1F3A0;CAROUSEL HORSE;So;0;ON;;;;;N;;;;; +1F3A1;FERRIS WHEEL;So;0;ON;;;;;N;;;;; +1F3A2;ROLLER COASTER;So;0;ON;;;;;N;;;;; +1F3A3;FISHING POLE AND FISH;So;0;ON;;;;;N;;;;; +1F3A4;MICROPHONE;So;0;ON;;;;;N;;;;; +1F3A5;MOVIE CAMERA;So;0;ON;;;;;N;;;;; +1F3A6;CINEMA;So;0;ON;;;;;N;;;;; +1F3A7;HEADPHONE;So;0;ON;;;;;N;;;;; +1F3A8;ARTIST PALETTE;So;0;ON;;;;;N;;;;; +1F3A9;TOP HAT;So;0;ON;;;;;N;;;;; +1F3AA;CIRCUS TENT;So;0;ON;;;;;N;;;;; +1F3AB;TICKET;So;0;ON;;;;;N;;;;; +1F3AC;CLAPPER BOARD;So;0;ON;;;;;N;;;;; +1F3AD;PERFORMING ARTS;So;0;ON;;;;;N;;;;; +1F3AE;VIDEO GAME;So;0;ON;;;;;N;;;;; +1F3AF;DIRECT HIT;So;0;ON;;;;;N;;;;; +1F3B0;SLOT MACHINE;So;0;ON;;;;;N;;;;; +1F3B1;BILLIARDS;So;0;ON;;;;;N;;;;; +1F3B2;GAME DIE;So;0;ON;;;;;N;;;;; +1F3B3;BOWLING;So;0;ON;;;;;N;;;;; +1F3B4;FLOWER PLAYING CARDS;So;0;ON;;;;;N;;;;; +1F3B5;MUSICAL NOTE;So;0;ON;;;;;N;;;;; +1F3B6;MULTIPLE MUSICAL NOTES;So;0;ON;;;;;N;;;;; +1F3B7;SAXOPHONE;So;0;ON;;;;;N;;;;; +1F3B8;GUITAR;So;0;ON;;;;;N;;;;; +1F3B9;MUSICAL KEYBOARD;So;0;ON;;;;;N;;;;; +1F3BA;TRUMPET;So;0;ON;;;;;N;;;;; +1F3BB;VIOLIN;So;0;ON;;;;;N;;;;; +1F3BC;MUSICAL SCORE;So;0;ON;;;;;N;;;;; +1F3BD;RUNNING SHIRT WITH SASH;So;0;ON;;;;;N;;;;; +1F3BE;TENNIS RACQUET AND BALL;So;0;ON;;;;;N;;;;; +1F3BF;SKI AND SKI BOOT;So;0;ON;;;;;N;;;;; +1F3C0;BASKETBALL AND HOOP;So;0;ON;;;;;N;;;;; +1F3C1;CHEQUERED FLAG;So;0;ON;;;;;N;;;;; +1F3C2;SNOWBOARDER;So;0;ON;;;;;N;;;;; +1F3C3;RUNNER;So;0;ON;;;;;N;;;;; +1F3C4;SURFER;So;0;ON;;;;;N;;;;; +1F3C5;SPORTS MEDAL;So;0;ON;;;;;N;;;;; +1F3C6;TROPHY;So;0;ON;;;;;N;;;;; +1F3C7;HORSE RACING;So;0;ON;;;;;N;;;;; +1F3C8;AMERICAN FOOTBALL;So;0;ON;;;;;N;;;;; +1F3C9;RUGBY FOOTBALL;So;0;ON;;;;;N;;;;; +1F3CA;SWIMMER;So;0;ON;;;;;N;;;;; +1F3CB;WEIGHT LIFTER;So;0;ON;;;;;N;;;;; +1F3CC;GOLFER;So;0;ON;;;;;N;;;;; +1F3CD;RACING MOTORCYCLE;So;0;ON;;;;;N;;;;; +1F3CE;RACING CAR;So;0;ON;;;;;N;;;;; +1F3CF;CRICKET BAT AND BALL;So;0;ON;;;;;N;;;;; +1F3D0;VOLLEYBALL;So;0;ON;;;;;N;;;;; +1F3D1;FIELD HOCKEY STICK AND BALL;So;0;ON;;;;;N;;;;; +1F3D2;ICE HOCKEY STICK AND PUCK;So;0;ON;;;;;N;;;;; +1F3D3;TABLE TENNIS PADDLE AND BALL;So;0;ON;;;;;N;;;;; +1F3D4;SNOW CAPPED MOUNTAIN;So;0;ON;;;;;N;;;;; +1F3D5;CAMPING;So;0;ON;;;;;N;;;;; +1F3D6;BEACH WITH UMBRELLA;So;0;ON;;;;;N;;;;; +1F3D7;BUILDING CONSTRUCTION;So;0;ON;;;;;N;;;;; +1F3D8;HOUSE BUILDINGS;So;0;ON;;;;;N;;;;; +1F3D9;CITYSCAPE;So;0;ON;;;;;N;;;;; +1F3DA;DERELICT HOUSE BUILDING;So;0;ON;;;;;N;;;;; +1F3DB;CLASSICAL BUILDING;So;0;ON;;;;;N;;;;; +1F3DC;DESERT;So;0;ON;;;;;N;;;;; +1F3DD;DESERT ISLAND;So;0;ON;;;;;N;;;;; +1F3DE;NATIONAL PARK;So;0;ON;;;;;N;;;;; +1F3DF;STADIUM;So;0;ON;;;;;N;;;;; +1F3E0;HOUSE BUILDING;So;0;ON;;;;;N;;;;; +1F3E1;HOUSE WITH GARDEN;So;0;ON;;;;;N;;;;; +1F3E2;OFFICE BUILDING;So;0;ON;;;;;N;;;;; +1F3E3;JAPANESE POST OFFICE;So;0;ON;;;;;N;;;;; +1F3E4;EUROPEAN POST OFFICE;So;0;ON;;;;;N;;;;; +1F3E5;HOSPITAL;So;0;ON;;;;;N;;;;; +1F3E6;BANK;So;0;ON;;;;;N;;;;; +1F3E7;AUTOMATED TELLER MACHINE;So;0;ON;;;;;N;;;;; +1F3E8;HOTEL;So;0;ON;;;;;N;;;;; +1F3E9;LOVE HOTEL;So;0;ON;;;;;N;;;;; +1F3EA;CONVENIENCE STORE;So;0;ON;;;;;N;;;;; +1F3EB;SCHOOL;So;0;ON;;;;;N;;;;; +1F3EC;DEPARTMENT STORE;So;0;ON;;;;;N;;;;; +1F3ED;FACTORY;So;0;ON;;;;;N;;;;; +1F3EE;IZAKAYA LANTERN;So;0;ON;;;;;N;;;;; +1F3EF;JAPANESE CASTLE;So;0;ON;;;;;N;;;;; +1F3F0;EUROPEAN CASTLE;So;0;ON;;;;;N;;;;; +1F3F1;WHITE PENNANT;So;0;ON;;;;;N;;;;; +1F3F2;BLACK PENNANT;So;0;ON;;;;;N;;;;; +1F3F3;WAVING WHITE FLAG;So;0;ON;;;;;N;;;;; +1F3F4;WAVING BLACK FLAG;So;0;ON;;;;;N;;;;; +1F3F5;ROSETTE;So;0;ON;;;;;N;;;;; +1F3F6;BLACK ROSETTE;So;0;ON;;;;;N;;;;; +1F3F7;LABEL;So;0;ON;;;;;N;;;;; +1F3F8;BADMINTON RACQUET AND SHUTTLECOCK;So;0;ON;;;;;N;;;;; +1F3F9;BOW AND ARROW;So;0;ON;;;;;N;;;;; +1F3FA;AMPHORA;So;0;ON;;;;;N;;;;; +1F3FB;EMOJI MODIFIER FITZPATRICK TYPE-1-2;Sk;0;ON;;;;;N;;;;; +1F3FC;EMOJI MODIFIER FITZPATRICK TYPE-3;Sk;0;ON;;;;;N;;;;; +1F3FD;EMOJI MODIFIER FITZPATRICK TYPE-4;Sk;0;ON;;;;;N;;;;; +1F3FE;EMOJI MODIFIER FITZPATRICK TYPE-5;Sk;0;ON;;;;;N;;;;; +1F3FF;EMOJI MODIFIER FITZPATRICK TYPE-6;Sk;0;ON;;;;;N;;;;; +1F400;RAT;So;0;ON;;;;;N;;;;; +1F401;MOUSE;So;0;ON;;;;;N;;;;; +1F402;OX;So;0;ON;;;;;N;;;;; +1F403;WATER BUFFALO;So;0;ON;;;;;N;;;;; +1F404;COW;So;0;ON;;;;;N;;;;; +1F405;TIGER;So;0;ON;;;;;N;;;;; +1F406;LEOPARD;So;0;ON;;;;;N;;;;; +1F407;RABBIT;So;0;ON;;;;;N;;;;; +1F408;CAT;So;0;ON;;;;;N;;;;; +1F409;DRAGON;So;0;ON;;;;;N;;;;; +1F40A;CROCODILE;So;0;ON;;;;;N;;;;; +1F40B;WHALE;So;0;ON;;;;;N;;;;; +1F40C;SNAIL;So;0;ON;;;;;N;;;;; +1F40D;SNAKE;So;0;ON;;;;;N;;;;; +1F40E;HORSE;So;0;ON;;;;;N;;;;; +1F40F;RAM;So;0;ON;;;;;N;;;;; +1F410;GOAT;So;0;ON;;;;;N;;;;; +1F411;SHEEP;So;0;ON;;;;;N;;;;; +1F412;MONKEY;So;0;ON;;;;;N;;;;; +1F413;ROOSTER;So;0;ON;;;;;N;;;;; +1F414;CHICKEN;So;0;ON;;;;;N;;;;; +1F415;DOG;So;0;ON;;;;;N;;;;; +1F416;PIG;So;0;ON;;;;;N;;;;; +1F417;BOAR;So;0;ON;;;;;N;;;;; +1F418;ELEPHANT;So;0;ON;;;;;N;;;;; +1F419;OCTOPUS;So;0;ON;;;;;N;;;;; +1F41A;SPIRAL SHELL;So;0;ON;;;;;N;;;;; +1F41B;BUG;So;0;ON;;;;;N;;;;; +1F41C;ANT;So;0;ON;;;;;N;;;;; +1F41D;HONEYBEE;So;0;ON;;;;;N;;;;; +1F41E;LADY BEETLE;So;0;ON;;;;;N;;;;; +1F41F;FISH;So;0;ON;;;;;N;;;;; +1F420;TROPICAL FISH;So;0;ON;;;;;N;;;;; +1F421;BLOWFISH;So;0;ON;;;;;N;;;;; +1F422;TURTLE;So;0;ON;;;;;N;;;;; +1F423;HATCHING CHICK;So;0;ON;;;;;N;;;;; +1F424;BABY CHICK;So;0;ON;;;;;N;;;;; +1F425;FRONT-FACING BABY CHICK;So;0;ON;;;;;N;;;;; +1F426;BIRD;So;0;ON;;;;;N;;;;; +1F427;PENGUIN;So;0;ON;;;;;N;;;;; +1F428;KOALA;So;0;ON;;;;;N;;;;; +1F429;POODLE;So;0;ON;;;;;N;;;;; +1F42A;DROMEDARY CAMEL;So;0;ON;;;;;N;;;;; +1F42B;BACTRIAN CAMEL;So;0;ON;;;;;N;;;;; +1F42C;DOLPHIN;So;0;ON;;;;;N;;;;; +1F42D;MOUSE FACE;So;0;ON;;;;;N;;;;; +1F42E;COW FACE;So;0;ON;;;;;N;;;;; +1F42F;TIGER FACE;So;0;ON;;;;;N;;;;; +1F430;RABBIT FACE;So;0;ON;;;;;N;;;;; +1F431;CAT FACE;So;0;ON;;;;;N;;;;; +1F432;DRAGON FACE;So;0;ON;;;;;N;;;;; +1F433;SPOUTING WHALE;So;0;ON;;;;;N;;;;; +1F434;HORSE FACE;So;0;ON;;;;;N;;;;; +1F435;MONKEY FACE;So;0;ON;;;;;N;;;;; +1F436;DOG FACE;So;0;ON;;;;;N;;;;; +1F437;PIG FACE;So;0;ON;;;;;N;;;;; +1F438;FROG FACE;So;0;ON;;;;;N;;;;; +1F439;HAMSTER FACE;So;0;ON;;;;;N;;;;; +1F43A;WOLF FACE;So;0;ON;;;;;N;;;;; +1F43B;BEAR FACE;So;0;ON;;;;;N;;;;; +1F43C;PANDA FACE;So;0;ON;;;;;N;;;;; +1F43D;PIG NOSE;So;0;ON;;;;;N;;;;; +1F43E;PAW PRINTS;So;0;ON;;;;;N;;;;; +1F43F;CHIPMUNK;So;0;ON;;;;;N;;;;; +1F440;EYES;So;0;ON;;;;;N;;;;; +1F441;EYE;So;0;ON;;;;;N;;;;; +1F442;EAR;So;0;ON;;;;;N;;;;; +1F443;NOSE;So;0;ON;;;;;N;;;;; +1F444;MOUTH;So;0;ON;;;;;N;;;;; +1F445;TONGUE;So;0;ON;;;;;N;;;;; +1F446;WHITE UP POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F447;WHITE DOWN POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F448;WHITE LEFT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F449;WHITE RIGHT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F44A;FISTED HAND SIGN;So;0;ON;;;;;N;;;;; +1F44B;WAVING HAND SIGN;So;0;ON;;;;;N;;;;; +1F44C;OK HAND SIGN;So;0;ON;;;;;N;;;;; +1F44D;THUMBS UP SIGN;So;0;ON;;;;;N;;;;; +1F44E;THUMBS DOWN SIGN;So;0;ON;;;;;N;;;;; +1F44F;CLAPPING HANDS SIGN;So;0;ON;;;;;N;;;;; +1F450;OPEN HANDS SIGN;So;0;ON;;;;;N;;;;; +1F451;CROWN;So;0;ON;;;;;N;;;;; +1F452;WOMANS HAT;So;0;ON;;;;;N;;;;; +1F453;EYEGLASSES;So;0;ON;;;;;N;;;;; +1F454;NECKTIE;So;0;ON;;;;;N;;;;; +1F455;T-SHIRT;So;0;ON;;;;;N;;;;; +1F456;JEANS;So;0;ON;;;;;N;;;;; +1F457;DRESS;So;0;ON;;;;;N;;;;; +1F458;KIMONO;So;0;ON;;;;;N;;;;; +1F459;BIKINI;So;0;ON;;;;;N;;;;; +1F45A;WOMANS CLOTHES;So;0;ON;;;;;N;;;;; +1F45B;PURSE;So;0;ON;;;;;N;;;;; +1F45C;HANDBAG;So;0;ON;;;;;N;;;;; +1F45D;POUCH;So;0;ON;;;;;N;;;;; +1F45E;MANS SHOE;So;0;ON;;;;;N;;;;; +1F45F;ATHLETIC SHOE;So;0;ON;;;;;N;;;;; +1F460;HIGH-HEELED SHOE;So;0;ON;;;;;N;;;;; +1F461;WOMANS SANDAL;So;0;ON;;;;;N;;;;; +1F462;WOMANS BOOTS;So;0;ON;;;;;N;;;;; +1F463;FOOTPRINTS;So;0;ON;;;;;N;;;;; +1F464;BUST IN SILHOUETTE;So;0;ON;;;;;N;;;;; +1F465;BUSTS IN SILHOUETTE;So;0;ON;;;;;N;;;;; +1F466;BOY;So;0;ON;;;;;N;;;;; +1F467;GIRL;So;0;ON;;;;;N;;;;; +1F468;MAN;So;0;ON;;;;;N;;;;; +1F469;WOMAN;So;0;ON;;;;;N;;;;; +1F46A;FAMILY;So;0;ON;;;;;N;;;;; +1F46B;MAN AND WOMAN HOLDING HANDS;So;0;ON;;;;;N;;;;; +1F46C;TWO MEN HOLDING HANDS;So;0;ON;;;;;N;;;;; +1F46D;TWO WOMEN HOLDING HANDS;So;0;ON;;;;;N;;;;; +1F46E;POLICE OFFICER;So;0;ON;;;;;N;;;;; +1F46F;WOMAN WITH BUNNY EARS;So;0;ON;;;;;N;;;;; +1F470;BRIDE WITH VEIL;So;0;ON;;;;;N;;;;; +1F471;PERSON WITH BLOND HAIR;So;0;ON;;;;;N;;;;; +1F472;MAN WITH GUA PI MAO;So;0;ON;;;;;N;;;;; +1F473;MAN WITH TURBAN;So;0;ON;;;;;N;;;;; +1F474;OLDER MAN;So;0;ON;;;;;N;;;;; +1F475;OLDER WOMAN;So;0;ON;;;;;N;;;;; +1F476;BABY;So;0;ON;;;;;N;;;;; +1F477;CONSTRUCTION WORKER;So;0;ON;;;;;N;;;;; +1F478;PRINCESS;So;0;ON;;;;;N;;;;; +1F479;JAPANESE OGRE;So;0;ON;;;;;N;;;;; +1F47A;JAPANESE GOBLIN;So;0;ON;;;;;N;;;;; +1F47B;GHOST;So;0;ON;;;;;N;;;;; +1F47C;BABY ANGEL;So;0;ON;;;;;N;;;;; +1F47D;EXTRATERRESTRIAL ALIEN;So;0;ON;;;;;N;;;;; +1F47E;ALIEN MONSTER;So;0;ON;;;;;N;;;;; +1F47F;IMP;So;0;ON;;;;;N;;;;; +1F480;SKULL;So;0;ON;;;;;N;;;;; +1F481;INFORMATION DESK PERSON;So;0;ON;;;;;N;;;;; +1F482;GUARDSMAN;So;0;ON;;;;;N;;;;; +1F483;DANCER;So;0;ON;;;;;N;;;;; +1F484;LIPSTICK;So;0;ON;;;;;N;;;;; +1F485;NAIL POLISH;So;0;ON;;;;;N;;;;; +1F486;FACE MASSAGE;So;0;ON;;;;;N;;;;; +1F487;HAIRCUT;So;0;ON;;;;;N;;;;; +1F488;BARBER POLE;So;0;ON;;;;;N;;;;; +1F489;SYRINGE;So;0;ON;;;;;N;;;;; +1F48A;PILL;So;0;ON;;;;;N;;;;; +1F48B;KISS MARK;So;0;ON;;;;;N;;;;; +1F48C;LOVE LETTER;So;0;ON;;;;;N;;;;; +1F48D;RING;So;0;ON;;;;;N;;;;; +1F48E;GEM STONE;So;0;ON;;;;;N;;;;; +1F48F;KISS;So;0;ON;;;;;N;;;;; +1F490;BOUQUET;So;0;ON;;;;;N;;;;; +1F491;COUPLE WITH HEART;So;0;ON;;;;;N;;;;; +1F492;WEDDING;So;0;ON;;;;;N;;;;; +1F493;BEATING HEART;So;0;ON;;;;;N;;;;; +1F494;BROKEN HEART;So;0;ON;;;;;N;;;;; +1F495;TWO HEARTS;So;0;ON;;;;;N;;;;; +1F496;SPARKLING HEART;So;0;ON;;;;;N;;;;; +1F497;GROWING HEART;So;0;ON;;;;;N;;;;; +1F498;HEART WITH ARROW;So;0;ON;;;;;N;;;;; +1F499;BLUE HEART;So;0;ON;;;;;N;;;;; +1F49A;GREEN HEART;So;0;ON;;;;;N;;;;; +1F49B;YELLOW HEART;So;0;ON;;;;;N;;;;; +1F49C;PURPLE HEART;So;0;ON;;;;;N;;;;; +1F49D;HEART WITH RIBBON;So;0;ON;;;;;N;;;;; +1F49E;REVOLVING HEARTS;So;0;ON;;;;;N;;;;; +1F49F;HEART DECORATION;So;0;ON;;;;;N;;;;; +1F4A0;DIAMOND SHAPE WITH A DOT INSIDE;So;0;ON;;;;;N;;;;; +1F4A1;ELECTRIC LIGHT BULB;So;0;ON;;;;;N;;;;; +1F4A2;ANGER SYMBOL;So;0;ON;;;;;N;;;;; +1F4A3;BOMB;So;0;ON;;;;;N;;;;; +1F4A4;SLEEPING SYMBOL;So;0;ON;;;;;N;;;;; +1F4A5;COLLISION SYMBOL;So;0;ON;;;;;N;;;;; +1F4A6;SPLASHING SWEAT SYMBOL;So;0;ON;;;;;N;;;;; +1F4A7;DROPLET;So;0;ON;;;;;N;;;;; +1F4A8;DASH SYMBOL;So;0;ON;;;;;N;;;;; +1F4A9;PILE OF POO;So;0;ON;;;;;N;;;;; +1F4AA;FLEXED BICEPS;So;0;ON;;;;;N;;;;; +1F4AB;DIZZY SYMBOL;So;0;ON;;;;;N;;;;; +1F4AC;SPEECH BALLOON;So;0;ON;;;;;N;;;;; +1F4AD;THOUGHT BALLOON;So;0;ON;;;;;N;;;;; +1F4AE;WHITE FLOWER;So;0;ON;;;;;N;;;;; +1F4AF;HUNDRED POINTS SYMBOL;So;0;ON;;;;;N;;;;; +1F4B0;MONEY BAG;So;0;ON;;;;;N;;;;; +1F4B1;CURRENCY EXCHANGE;So;0;ON;;;;;N;;;;; +1F4B2;HEAVY DOLLAR SIGN;So;0;ON;;;;;N;;;;; +1F4B3;CREDIT CARD;So;0;ON;;;;;N;;;;; +1F4B4;BANKNOTE WITH YEN SIGN;So;0;ON;;;;;N;;;;; +1F4B5;BANKNOTE WITH DOLLAR SIGN;So;0;ON;;;;;N;;;;; +1F4B6;BANKNOTE WITH EURO SIGN;So;0;ON;;;;;N;;;;; +1F4B7;BANKNOTE WITH POUND SIGN;So;0;ON;;;;;N;;;;; +1F4B8;MONEY WITH WINGS;So;0;ON;;;;;N;;;;; +1F4B9;CHART WITH UPWARDS TREND AND YEN SIGN;So;0;ON;;;;;N;;;;; +1F4BA;SEAT;So;0;ON;;;;;N;;;;; +1F4BB;PERSONAL COMPUTER;So;0;ON;;;;;N;;;;; +1F4BC;BRIEFCASE;So;0;ON;;;;;N;;;;; +1F4BD;MINIDISC;So;0;ON;;;;;N;;;;; +1F4BE;FLOPPY DISK;So;0;ON;;;;;N;;;;; +1F4BF;OPTICAL DISC;So;0;ON;;;;;N;;;;; +1F4C0;DVD;So;0;ON;;;;;N;;;;; +1F4C1;FILE FOLDER;So;0;ON;;;;;N;;;;; +1F4C2;OPEN FILE FOLDER;So;0;ON;;;;;N;;;;; +1F4C3;PAGE WITH CURL;So;0;ON;;;;;N;;;;; +1F4C4;PAGE FACING UP;So;0;ON;;;;;N;;;;; +1F4C5;CALENDAR;So;0;ON;;;;;N;;;;; +1F4C6;TEAR-OFF CALENDAR;So;0;ON;;;;;N;;;;; +1F4C7;CARD INDEX;So;0;ON;;;;;N;;;;; +1F4C8;CHART WITH UPWARDS TREND;So;0;ON;;;;;N;;;;; +1F4C9;CHART WITH DOWNWARDS TREND;So;0;ON;;;;;N;;;;; +1F4CA;BAR CHART;So;0;ON;;;;;N;;;;; +1F4CB;CLIPBOARD;So;0;ON;;;;;N;;;;; +1F4CC;PUSHPIN;So;0;ON;;;;;N;;;;; +1F4CD;ROUND PUSHPIN;So;0;ON;;;;;N;;;;; +1F4CE;PAPERCLIP;So;0;ON;;;;;N;;;;; +1F4CF;STRAIGHT RULER;So;0;ON;;;;;N;;;;; +1F4D0;TRIANGULAR RULER;So;0;ON;;;;;N;;;;; +1F4D1;BOOKMARK TABS;So;0;ON;;;;;N;;;;; +1F4D2;LEDGER;So;0;ON;;;;;N;;;;; +1F4D3;NOTEBOOK;So;0;ON;;;;;N;;;;; +1F4D4;NOTEBOOK WITH DECORATIVE COVER;So;0;ON;;;;;N;;;;; +1F4D5;CLOSED BOOK;So;0;ON;;;;;N;;;;; +1F4D6;OPEN BOOK;So;0;ON;;;;;N;;;;; +1F4D7;GREEN BOOK;So;0;ON;;;;;N;;;;; +1F4D8;BLUE BOOK;So;0;ON;;;;;N;;;;; +1F4D9;ORANGE BOOK;So;0;ON;;;;;N;;;;; +1F4DA;BOOKS;So;0;ON;;;;;N;;;;; +1F4DB;NAME BADGE;So;0;ON;;;;;N;;;;; +1F4DC;SCROLL;So;0;ON;;;;;N;;;;; +1F4DD;MEMO;So;0;ON;;;;;N;;;;; +1F4DE;TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;; +1F4DF;PAGER;So;0;ON;;;;;N;;;;; +1F4E0;FAX MACHINE;So;0;ON;;;;;N;;;;; +1F4E1;SATELLITE ANTENNA;So;0;ON;;;;;N;;;;; +1F4E2;PUBLIC ADDRESS LOUDSPEAKER;So;0;ON;;;;;N;;;;; +1F4E3;CHEERING MEGAPHONE;So;0;ON;;;;;N;;;;; +1F4E4;OUTBOX TRAY;So;0;ON;;;;;N;;;;; +1F4E5;INBOX TRAY;So;0;ON;;;;;N;;;;; +1F4E6;PACKAGE;So;0;ON;;;;;N;;;;; +1F4E7;E-MAIL SYMBOL;So;0;ON;;;;;N;;;;; +1F4E8;INCOMING ENVELOPE;So;0;ON;;;;;N;;;;; +1F4E9;ENVELOPE WITH DOWNWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;; +1F4EA;CLOSED MAILBOX WITH LOWERED FLAG;So;0;ON;;;;;N;;;;; +1F4EB;CLOSED MAILBOX WITH RAISED FLAG;So;0;ON;;;;;N;;;;; +1F4EC;OPEN MAILBOX WITH RAISED FLAG;So;0;ON;;;;;N;;;;; +1F4ED;OPEN MAILBOX WITH LOWERED FLAG;So;0;ON;;;;;N;;;;; +1F4EE;POSTBOX;So;0;ON;;;;;N;;;;; +1F4EF;POSTAL HORN;So;0;ON;;;;;N;;;;; +1F4F0;NEWSPAPER;So;0;ON;;;;;N;;;;; +1F4F1;MOBILE PHONE;So;0;ON;;;;;N;;;;; +1F4F2;MOBILE PHONE WITH RIGHTWARDS ARROW AT LEFT;So;0;ON;;;;;N;;;;; +1F4F3;VIBRATION MODE;So;0;ON;;;;;N;;;;; +1F4F4;MOBILE PHONE OFF;So;0;ON;;;;;N;;;;; +1F4F5;NO MOBILE PHONES;So;0;ON;;;;;N;;;;; +1F4F6;ANTENNA WITH BARS;So;0;ON;;;;;N;;;;; +1F4F7;CAMERA;So;0;ON;;;;;N;;;;; +1F4F8;CAMERA WITH FLASH;So;0;ON;;;;;N;;;;; +1F4F9;VIDEO CAMERA;So;0;ON;;;;;N;;;;; +1F4FA;TELEVISION;So;0;ON;;;;;N;;;;; +1F4FB;RADIO;So;0;ON;;;;;N;;;;; +1F4FC;VIDEOCASSETTE;So;0;ON;;;;;N;;;;; +1F4FD;FILM PROJECTOR;So;0;ON;;;;;N;;;;; +1F4FE;PORTABLE STEREO;So;0;ON;;;;;N;;;;; +1F4FF;PRAYER BEADS;So;0;ON;;;;;N;;;;; +1F500;TWISTED RIGHTWARDS ARROWS;So;0;ON;;;;;N;;;;; +1F501;CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;; +1F502;CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS WITH CIRCLED ONE OVERLAY;So;0;ON;;;;;N;;;;; +1F503;CLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;; +1F504;ANTICLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;; +1F505;LOW BRIGHTNESS SYMBOL;So;0;ON;;;;;N;;;;; +1F506;HIGH BRIGHTNESS SYMBOL;So;0;ON;;;;;N;;;;; +1F507;SPEAKER WITH CANCELLATION STROKE;So;0;ON;;;;;N;;;;; +1F508;SPEAKER;So;0;ON;;;;;N;;;;; +1F509;SPEAKER WITH ONE SOUND WAVE;So;0;ON;;;;;N;;;;; +1F50A;SPEAKER WITH THREE SOUND WAVES;So;0;ON;;;;;N;;;;; +1F50B;BATTERY;So;0;ON;;;;;N;;;;; +1F50C;ELECTRIC PLUG;So;0;ON;;;;;N;;;;; +1F50D;LEFT-POINTING MAGNIFYING GLASS;So;0;ON;;;;;N;;;;; +1F50E;RIGHT-POINTING MAGNIFYING GLASS;So;0;ON;;;;;N;;;;; +1F50F;LOCK WITH INK PEN;So;0;ON;;;;;N;;;;; +1F510;CLOSED LOCK WITH KEY;So;0;ON;;;;;N;;;;; +1F511;KEY;So;0;ON;;;;;N;;;;; +1F512;LOCK;So;0;ON;;;;;N;;;;; +1F513;OPEN LOCK;So;0;ON;;;;;N;;;;; +1F514;BELL;So;0;ON;;;;;N;;;;; +1F515;BELL WITH CANCELLATION STROKE;So;0;ON;;;;;N;;;;; +1F516;BOOKMARK;So;0;ON;;;;;N;;;;; +1F517;LINK SYMBOL;So;0;ON;;;;;N;;;;; +1F518;RADIO BUTTON;So;0;ON;;;;;N;;;;; +1F519;BACK WITH LEFTWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;; +1F51A;END WITH LEFTWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;; +1F51B;ON WITH EXCLAMATION MARK WITH LEFT RIGHT ARROW ABOVE;So;0;ON;;;;;N;;;;; +1F51C;SOON WITH RIGHTWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;; +1F51D;TOP WITH UPWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;; +1F51E;NO ONE UNDER EIGHTEEN SYMBOL;So;0;ON;;;;;N;;;;; +1F51F;KEYCAP TEN;So;0;ON;;;;;N;;;;; +1F520;INPUT SYMBOL FOR LATIN CAPITAL LETTERS;So;0;ON;;;;;N;;;;; +1F521;INPUT SYMBOL FOR LATIN SMALL LETTERS;So;0;ON;;;;;N;;;;; +1F522;INPUT SYMBOL FOR NUMBERS;So;0;ON;;;;;N;;;;; +1F523;INPUT SYMBOL FOR SYMBOLS;So;0;ON;;;;;N;;;;; +1F524;INPUT SYMBOL FOR LATIN LETTERS;So;0;ON;;;;;N;;;;; +1F525;FIRE;So;0;ON;;;;;N;;;;; +1F526;ELECTRIC TORCH;So;0;ON;;;;;N;;;;; +1F527;WRENCH;So;0;ON;;;;;N;;;;; +1F528;HAMMER;So;0;ON;;;;;N;;;;; +1F529;NUT AND BOLT;So;0;ON;;;;;N;;;;; +1F52A;HOCHO;So;0;ON;;;;;N;;;;; +1F52B;PISTOL;So;0;ON;;;;;N;;;;; +1F52C;MICROSCOPE;So;0;ON;;;;;N;;;;; +1F52D;TELESCOPE;So;0;ON;;;;;N;;;;; +1F52E;CRYSTAL BALL;So;0;ON;;;;;N;;;;; +1F52F;SIX POINTED STAR WITH MIDDLE DOT;So;0;ON;;;;;N;;;;; +1F530;JAPANESE SYMBOL FOR BEGINNER;So;0;ON;;;;;N;;;;; +1F531;TRIDENT EMBLEM;So;0;ON;;;;;N;;;;; +1F532;BLACK SQUARE BUTTON;So;0;ON;;;;;N;;;;; +1F533;WHITE SQUARE BUTTON;So;0;ON;;;;;N;;;;; +1F534;LARGE RED CIRCLE;So;0;ON;;;;;N;;;;; +1F535;LARGE BLUE CIRCLE;So;0;ON;;;;;N;;;;; +1F536;LARGE ORANGE DIAMOND;So;0;ON;;;;;N;;;;; +1F537;LARGE BLUE DIAMOND;So;0;ON;;;;;N;;;;; +1F538;SMALL ORANGE DIAMOND;So;0;ON;;;;;N;;;;; +1F539;SMALL BLUE DIAMOND;So;0;ON;;;;;N;;;;; +1F53A;UP-POINTING RED TRIANGLE;So;0;ON;;;;;N;;;;; +1F53B;DOWN-POINTING RED TRIANGLE;So;0;ON;;;;;N;;;;; +1F53C;UP-POINTING SMALL RED TRIANGLE;So;0;ON;;;;;N;;;;; +1F53D;DOWN-POINTING SMALL RED TRIANGLE;So;0;ON;;;;;N;;;;; +1F53E;LOWER RIGHT SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1F53F;UPPER RIGHT SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1F540;CIRCLED CROSS POMMEE;So;0;ON;;;;;N;;;;; +1F541;CROSS POMMEE WITH HALF-CIRCLE BELOW;So;0;ON;;;;;N;;;;; +1F542;CROSS POMMEE;So;0;ON;;;;;N;;;;; +1F543;NOTCHED LEFT SEMICIRCLE WITH THREE DOTS;So;0;ON;;;;;N;;;;; +1F544;NOTCHED RIGHT SEMICIRCLE WITH THREE DOTS;So;0;ON;;;;;N;;;;; +1F545;SYMBOL FOR MARKS CHAPTER;So;0;ON;;;;;N;;;;; +1F546;WHITE LATIN CROSS;So;0;ON;;;;;N;;;;; +1F547;HEAVY LATIN CROSS;So;0;ON;;;;;N;;;;; +1F548;CELTIC CROSS;So;0;ON;;;;;N;;;;; +1F549;OM SYMBOL;So;0;ON;;;;;N;;;;; +1F54A;DOVE OF PEACE;So;0;ON;;;;;N;;;;; +1F54B;KAABA;So;0;ON;;;;;N;;;;; +1F54C;MOSQUE;So;0;ON;;;;;N;;;;; +1F54D;SYNAGOGUE;So;0;ON;;;;;N;;;;; +1F54E;MENORAH WITH NINE BRANCHES;So;0;ON;;;;;N;;;;; +1F54F;BOWL OF HYGIEIA;So;0;ON;;;;;N;;;;; +1F550;CLOCK FACE ONE OCLOCK;So;0;ON;;;;;N;;;;; +1F551;CLOCK FACE TWO OCLOCK;So;0;ON;;;;;N;;;;; +1F552;CLOCK FACE THREE OCLOCK;So;0;ON;;;;;N;;;;; +1F553;CLOCK FACE FOUR OCLOCK;So;0;ON;;;;;N;;;;; +1F554;CLOCK FACE FIVE OCLOCK;So;0;ON;;;;;N;;;;; +1F555;CLOCK FACE SIX OCLOCK;So;0;ON;;;;;N;;;;; +1F556;CLOCK FACE SEVEN OCLOCK;So;0;ON;;;;;N;;;;; +1F557;CLOCK FACE EIGHT OCLOCK;So;0;ON;;;;;N;;;;; +1F558;CLOCK FACE NINE OCLOCK;So;0;ON;;;;;N;;;;; +1F559;CLOCK FACE TEN OCLOCK;So;0;ON;;;;;N;;;;; +1F55A;CLOCK FACE ELEVEN OCLOCK;So;0;ON;;;;;N;;;;; +1F55B;CLOCK FACE TWELVE OCLOCK;So;0;ON;;;;;N;;;;; +1F55C;CLOCK FACE ONE-THIRTY;So;0;ON;;;;;N;;;;; +1F55D;CLOCK FACE TWO-THIRTY;So;0;ON;;;;;N;;;;; +1F55E;CLOCK FACE THREE-THIRTY;So;0;ON;;;;;N;;;;; +1F55F;CLOCK FACE FOUR-THIRTY;So;0;ON;;;;;N;;;;; +1F560;CLOCK FACE FIVE-THIRTY;So;0;ON;;;;;N;;;;; +1F561;CLOCK FACE SIX-THIRTY;So;0;ON;;;;;N;;;;; +1F562;CLOCK FACE SEVEN-THIRTY;So;0;ON;;;;;N;;;;; +1F563;CLOCK FACE EIGHT-THIRTY;So;0;ON;;;;;N;;;;; +1F564;CLOCK FACE NINE-THIRTY;So;0;ON;;;;;N;;;;; +1F565;CLOCK FACE TEN-THIRTY;So;0;ON;;;;;N;;;;; +1F566;CLOCK FACE ELEVEN-THIRTY;So;0;ON;;;;;N;;;;; +1F567;CLOCK FACE TWELVE-THIRTY;So;0;ON;;;;;N;;;;; +1F568;RIGHT SPEAKER;So;0;ON;;;;;N;;;;; +1F569;RIGHT SPEAKER WITH ONE SOUND WAVE;So;0;ON;;;;;N;;;;; +1F56A;RIGHT SPEAKER WITH THREE SOUND WAVES;So;0;ON;;;;;N;;;;; +1F56B;BULLHORN;So;0;ON;;;;;N;;;;; +1F56C;BULLHORN WITH SOUND WAVES;So;0;ON;;;;;N;;;;; +1F56D;RINGING BELL;So;0;ON;;;;;N;;;;; +1F56E;BOOK;So;0;ON;;;;;N;;;;; +1F56F;CANDLE;So;0;ON;;;;;N;;;;; +1F570;MANTELPIECE CLOCK;So;0;ON;;;;;N;;;;; +1F571;BLACK SKULL AND CROSSBONES;So;0;ON;;;;;N;;;;; +1F572;NO PIRACY;So;0;ON;;;;;N;;;;; +1F573;HOLE;So;0;ON;;;;;N;;;;; +1F574;MAN IN BUSINESS SUIT LEVITATING;So;0;ON;;;;;N;;;;; +1F575;SLEUTH OR SPY;So;0;ON;;;;;N;;;;; +1F576;DARK SUNGLASSES;So;0;ON;;;;;N;;;;; +1F577;SPIDER;So;0;ON;;;;;N;;;;; +1F578;SPIDER WEB;So;0;ON;;;;;N;;;;; +1F579;JOYSTICK;So;0;ON;;;;;N;;;;; +1F57A;MAN DANCING;So;0;ON;;;;;N;;;;; +1F57B;LEFT HAND TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;; +1F57C;TELEPHONE RECEIVER WITH PAGE;So;0;ON;;;;;N;;;;; +1F57D;RIGHT HAND TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;; +1F57E;WHITE TOUCHTONE TELEPHONE;So;0;ON;;;;;N;;;;; +1F57F;BLACK TOUCHTONE TELEPHONE;So;0;ON;;;;;N;;;;; +1F580;TELEPHONE ON TOP OF MODEM;So;0;ON;;;;;N;;;;; +1F581;CLAMSHELL MOBILE PHONE;So;0;ON;;;;;N;;;;; +1F582;BACK OF ENVELOPE;So;0;ON;;;;;N;;;;; +1F583;STAMPED ENVELOPE;So;0;ON;;;;;N;;;;; +1F584;ENVELOPE WITH LIGHTNING;So;0;ON;;;;;N;;;;; +1F585;FLYING ENVELOPE;So;0;ON;;;;;N;;;;; +1F586;PEN OVER STAMPED ENVELOPE;So;0;ON;;;;;N;;;;; +1F587;LINKED PAPERCLIPS;So;0;ON;;;;;N;;;;; +1F588;BLACK PUSHPIN;So;0;ON;;;;;N;;;;; +1F589;LOWER LEFT PENCIL;So;0;ON;;;;;N;;;;; +1F58A;LOWER LEFT BALLPOINT PEN;So;0;ON;;;;;N;;;;; +1F58B;LOWER LEFT FOUNTAIN PEN;So;0;ON;;;;;N;;;;; +1F58C;LOWER LEFT PAINTBRUSH;So;0;ON;;;;;N;;;;; +1F58D;LOWER LEFT CRAYON;So;0;ON;;;;;N;;;;; +1F58E;LEFT WRITING HAND;So;0;ON;;;;;N;;;;; +1F58F;TURNED OK HAND SIGN;So;0;ON;;;;;N;;;;; +1F590;RAISED HAND WITH FINGERS SPLAYED;So;0;ON;;;;;N;;;;; +1F591;REVERSED RAISED HAND WITH FINGERS SPLAYED;So;0;ON;;;;;N;;;;; +1F592;REVERSED THUMBS UP SIGN;So;0;ON;;;;;N;;;;; +1F593;REVERSED THUMBS DOWN SIGN;So;0;ON;;;;;N;;;;; +1F594;REVERSED VICTORY HAND;So;0;ON;;;;;N;;;;; +1F595;REVERSED HAND WITH MIDDLE FINGER EXTENDED;So;0;ON;;;;;N;;;;; +1F596;RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS;So;0;ON;;;;;N;;;;; +1F597;WHITE DOWN POINTING LEFT HAND INDEX;So;0;ON;;;;;N;;;;; +1F598;SIDEWAYS WHITE LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; +1F599;SIDEWAYS WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; +1F59A;SIDEWAYS BLACK LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; +1F59B;SIDEWAYS BLACK RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; +1F59C;BLACK LEFT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F59D;BLACK RIGHT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F59E;SIDEWAYS WHITE UP POINTING INDEX;So;0;ON;;;;;N;;;;; +1F59F;SIDEWAYS WHITE DOWN POINTING INDEX;So;0;ON;;;;;N;;;;; +1F5A0;SIDEWAYS BLACK UP POINTING INDEX;So;0;ON;;;;;N;;;;; +1F5A1;SIDEWAYS BLACK DOWN POINTING INDEX;So;0;ON;;;;;N;;;;; +1F5A2;BLACK UP POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F5A3;BLACK DOWN POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F5A4;BLACK HEART;So;0;ON;;;;;N;;;;; +1F5A5;DESKTOP COMPUTER;So;0;ON;;;;;N;;;;; +1F5A6;KEYBOARD AND MOUSE;So;0;ON;;;;;N;;;;; +1F5A7;THREE NETWORKED COMPUTERS;So;0;ON;;;;;N;;;;; +1F5A8;PRINTER;So;0;ON;;;;;N;;;;; +1F5A9;POCKET CALCULATOR;So;0;ON;;;;;N;;;;; +1F5AA;BLACK HARD SHELL FLOPPY DISK;So;0;ON;;;;;N;;;;; +1F5AB;WHITE HARD SHELL FLOPPY DISK;So;0;ON;;;;;N;;;;; +1F5AC;SOFT SHELL FLOPPY DISK;So;0;ON;;;;;N;;;;; +1F5AD;TAPE CARTRIDGE;So;0;ON;;;;;N;;;;; +1F5AE;WIRED KEYBOARD;So;0;ON;;;;;N;;;;; +1F5AF;ONE BUTTON MOUSE;So;0;ON;;;;;N;;;;; +1F5B0;TWO BUTTON MOUSE;So;0;ON;;;;;N;;;;; +1F5B1;THREE BUTTON MOUSE;So;0;ON;;;;;N;;;;; +1F5B2;TRACKBALL;So;0;ON;;;;;N;;;;; +1F5B3;OLD PERSONAL COMPUTER;So;0;ON;;;;;N;;;;; +1F5B4;HARD DISK;So;0;ON;;;;;N;;;;; +1F5B5;SCREEN;So;0;ON;;;;;N;;;;; +1F5B6;PRINTER ICON;So;0;ON;;;;;N;;;;; +1F5B7;FAX ICON;So;0;ON;;;;;N;;;;; +1F5B8;OPTICAL DISC ICON;So;0;ON;;;;;N;;;;; +1F5B9;DOCUMENT WITH TEXT;So;0;ON;;;;;N;;;;; +1F5BA;DOCUMENT WITH TEXT AND PICTURE;So;0;ON;;;;;N;;;;; +1F5BB;DOCUMENT WITH PICTURE;So;0;ON;;;;;N;;;;; +1F5BC;FRAME WITH PICTURE;So;0;ON;;;;;N;;;;; +1F5BD;FRAME WITH TILES;So;0;ON;;;;;N;;;;; +1F5BE;FRAME WITH AN X;So;0;ON;;;;;N;;;;; +1F5BF;BLACK FOLDER;So;0;ON;;;;;N;;;;; +1F5C0;FOLDER;So;0;ON;;;;;N;;;;; +1F5C1;OPEN FOLDER;So;0;ON;;;;;N;;;;; +1F5C2;CARD INDEX DIVIDERS;So;0;ON;;;;;N;;;;; +1F5C3;CARD FILE BOX;So;0;ON;;;;;N;;;;; +1F5C4;FILE CABINET;So;0;ON;;;;;N;;;;; +1F5C5;EMPTY NOTE;So;0;ON;;;;;N;;;;; +1F5C6;EMPTY NOTE PAGE;So;0;ON;;;;;N;;;;; +1F5C7;EMPTY NOTE PAD;So;0;ON;;;;;N;;;;; +1F5C8;NOTE;So;0;ON;;;;;N;;;;; +1F5C9;NOTE PAGE;So;0;ON;;;;;N;;;;; +1F5CA;NOTE PAD;So;0;ON;;;;;N;;;;; +1F5CB;EMPTY DOCUMENT;So;0;ON;;;;;N;;;;; +1F5CC;EMPTY PAGE;So;0;ON;;;;;N;;;;; +1F5CD;EMPTY PAGES;So;0;ON;;;;;N;;;;; +1F5CE;DOCUMENT;So;0;ON;;;;;N;;;;; +1F5CF;PAGE;So;0;ON;;;;;N;;;;; +1F5D0;PAGES;So;0;ON;;;;;N;;;;; +1F5D1;WASTEBASKET;So;0;ON;;;;;N;;;;; +1F5D2;SPIRAL NOTE PAD;So;0;ON;;;;;N;;;;; +1F5D3;SPIRAL CALENDAR PAD;So;0;ON;;;;;N;;;;; +1F5D4;DESKTOP WINDOW;So;0;ON;;;;;N;;;;; +1F5D5;MINIMIZE;So;0;ON;;;;;N;;;;; +1F5D6;MAXIMIZE;So;0;ON;;;;;N;;;;; +1F5D7;OVERLAP;So;0;ON;;;;;N;;;;; +1F5D8;CLOCKWISE RIGHT AND LEFT SEMICIRCLE ARROWS;So;0;ON;;;;;N;;;;; +1F5D9;CANCELLATION X;So;0;ON;;;;;N;;;;; +1F5DA;INCREASE FONT SIZE SYMBOL;So;0;ON;;;;;N;;;;; +1F5DB;DECREASE FONT SIZE SYMBOL;So;0;ON;;;;;N;;;;; +1F5DC;COMPRESSION;So;0;ON;;;;;N;;;;; +1F5DD;OLD KEY;So;0;ON;;;;;N;;;;; +1F5DE;ROLLED-UP NEWSPAPER;So;0;ON;;;;;N;;;;; +1F5DF;PAGE WITH CIRCLED TEXT;So;0;ON;;;;;N;;;;; +1F5E0;STOCK CHART;So;0;ON;;;;;N;;;;; +1F5E1;DAGGER KNIFE;So;0;ON;;;;;N;;;;; +1F5E2;LIPS;So;0;ON;;;;;N;;;;; +1F5E3;SPEAKING HEAD IN SILHOUETTE;So;0;ON;;;;;N;;;;; +1F5E4;THREE RAYS ABOVE;So;0;ON;;;;;N;;;;; +1F5E5;THREE RAYS BELOW;So;0;ON;;;;;N;;;;; +1F5E6;THREE RAYS LEFT;So;0;ON;;;;;N;;;;; +1F5E7;THREE RAYS RIGHT;So;0;ON;;;;;N;;;;; +1F5E8;LEFT SPEECH BUBBLE;So;0;ON;;;;;N;;;;; +1F5E9;RIGHT SPEECH BUBBLE;So;0;ON;;;;;N;;;;; +1F5EA;TWO SPEECH BUBBLES;So;0;ON;;;;;N;;;;; +1F5EB;THREE SPEECH BUBBLES;So;0;ON;;;;;N;;;;; +1F5EC;LEFT THOUGHT BUBBLE;So;0;ON;;;;;N;;;;; +1F5ED;RIGHT THOUGHT BUBBLE;So;0;ON;;;;;N;;;;; +1F5EE;LEFT ANGER BUBBLE;So;0;ON;;;;;N;;;;; +1F5EF;RIGHT ANGER BUBBLE;So;0;ON;;;;;N;;;;; +1F5F0;MOOD BUBBLE;So;0;ON;;;;;N;;;;; +1F5F1;LIGHTNING MOOD BUBBLE;So;0;ON;;;;;N;;;;; +1F5F2;LIGHTNING MOOD;So;0;ON;;;;;N;;;;; +1F5F3;BALLOT BOX WITH BALLOT;So;0;ON;;;;;N;;;;; +1F5F4;BALLOT SCRIPT X;So;0;ON;;;;;N;;;;; +1F5F5;BALLOT BOX WITH SCRIPT X;So;0;ON;;;;;N;;;;; +1F5F6;BALLOT BOLD SCRIPT X;So;0;ON;;;;;N;;;;; +1F5F7;BALLOT BOX WITH BOLD SCRIPT X;So;0;ON;;;;;N;;;;; +1F5F8;LIGHT CHECK MARK;So;0;ON;;;;;N;;;;; +1F5F9;BALLOT BOX WITH BOLD CHECK;So;0;ON;;;;;N;;;;; +1F5FA;WORLD MAP;So;0;ON;;;;;N;;;;; +1F5FB;MOUNT FUJI;So;0;ON;;;;;N;;;;; +1F5FC;TOKYO TOWER;So;0;ON;;;;;N;;;;; +1F5FD;STATUE OF LIBERTY;So;0;ON;;;;;N;;;;; +1F5FE;SILHOUETTE OF JAPAN;So;0;ON;;;;;N;;;;; +1F5FF;MOYAI;So;0;ON;;;;;N;;;;; +1F600;GRINNING FACE;So;0;ON;;;;;N;;;;; +1F601;GRINNING FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;; +1F602;FACE WITH TEARS OF JOY;So;0;ON;;;;;N;;;;; +1F603;SMILING FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; +1F604;SMILING FACE WITH OPEN MOUTH AND SMILING EYES;So;0;ON;;;;;N;;;;; +1F605;SMILING FACE WITH OPEN MOUTH AND COLD SWEAT;So;0;ON;;;;;N;;;;; +1F606;SMILING FACE WITH OPEN MOUTH AND TIGHTLY-CLOSED EYES;So;0;ON;;;;;N;;;;; +1F607;SMILING FACE WITH HALO;So;0;ON;;;;;N;;;;; +1F608;SMILING FACE WITH HORNS;So;0;ON;;;;;N;;;;; +1F609;WINKING FACE;So;0;ON;;;;;N;;;;; +1F60A;SMILING FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;; +1F60B;FACE SAVOURING DELICIOUS FOOD;So;0;ON;;;;;N;;;;; +1F60C;RELIEVED FACE;So;0;ON;;;;;N;;;;; +1F60D;SMILING FACE WITH HEART-SHAPED EYES;So;0;ON;;;;;N;;;;; +1F60E;SMILING FACE WITH SUNGLASSES;So;0;ON;;;;;N;;;;; +1F60F;SMIRKING FACE;So;0;ON;;;;;N;;;;; +1F610;NEUTRAL FACE;So;0;ON;;;;;N;;;;; +1F611;EXPRESSIONLESS FACE;So;0;ON;;;;;N;;;;; +1F612;UNAMUSED FACE;So;0;ON;;;;;N;;;;; +1F613;FACE WITH COLD SWEAT;So;0;ON;;;;;N;;;;; +1F614;PENSIVE FACE;So;0;ON;;;;;N;;;;; +1F615;CONFUSED FACE;So;0;ON;;;;;N;;;;; +1F616;CONFOUNDED FACE;So;0;ON;;;;;N;;;;; +1F617;KISSING FACE;So;0;ON;;;;;N;;;;; +1F618;FACE THROWING A KISS;So;0;ON;;;;;N;;;;; +1F619;KISSING FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;; +1F61A;KISSING FACE WITH CLOSED EYES;So;0;ON;;;;;N;;;;; +1F61B;FACE WITH STUCK-OUT TONGUE;So;0;ON;;;;;N;;;;; +1F61C;FACE WITH STUCK-OUT TONGUE AND WINKING EYE;So;0;ON;;;;;N;;;;; +1F61D;FACE WITH STUCK-OUT TONGUE AND TIGHTLY-CLOSED EYES;So;0;ON;;;;;N;;;;; +1F61E;DISAPPOINTED FACE;So;0;ON;;;;;N;;;;; +1F61F;WORRIED FACE;So;0;ON;;;;;N;;;;; +1F620;ANGRY FACE;So;0;ON;;;;;N;;;;; +1F621;POUTING FACE;So;0;ON;;;;;N;;;;; +1F622;CRYING FACE;So;0;ON;;;;;N;;;;; +1F623;PERSEVERING FACE;So;0;ON;;;;;N;;;;; +1F624;FACE WITH LOOK OF TRIUMPH;So;0;ON;;;;;N;;;;; +1F625;DISAPPOINTED BUT RELIEVED FACE;So;0;ON;;;;;N;;;;; +1F626;FROWNING FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; +1F627;ANGUISHED FACE;So;0;ON;;;;;N;;;;; +1F628;FEARFUL FACE;So;0;ON;;;;;N;;;;; +1F629;WEARY FACE;So;0;ON;;;;;N;;;;; +1F62A;SLEEPY FACE;So;0;ON;;;;;N;;;;; +1F62B;TIRED FACE;So;0;ON;;;;;N;;;;; +1F62C;GRIMACING FACE;So;0;ON;;;;;N;;;;; +1F62D;LOUDLY CRYING FACE;So;0;ON;;;;;N;;;;; +1F62E;FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; +1F62F;HUSHED FACE;So;0;ON;;;;;N;;;;; +1F630;FACE WITH OPEN MOUTH AND COLD SWEAT;So;0;ON;;;;;N;;;;; +1F631;FACE SCREAMING IN FEAR;So;0;ON;;;;;N;;;;; +1F632;ASTONISHED FACE;So;0;ON;;;;;N;;;;; +1F633;FLUSHED FACE;So;0;ON;;;;;N;;;;; +1F634;SLEEPING FACE;So;0;ON;;;;;N;;;;; +1F635;DIZZY FACE;So;0;ON;;;;;N;;;;; +1F636;FACE WITHOUT MOUTH;So;0;ON;;;;;N;;;;; +1F637;FACE WITH MEDICAL MASK;So;0;ON;;;;;N;;;;; +1F638;GRINNING CAT FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;; +1F639;CAT FACE WITH TEARS OF JOY;So;0;ON;;;;;N;;;;; +1F63A;SMILING CAT FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; +1F63B;SMILING CAT FACE WITH HEART-SHAPED EYES;So;0;ON;;;;;N;;;;; +1F63C;CAT FACE WITH WRY SMILE;So;0;ON;;;;;N;;;;; +1F63D;KISSING CAT FACE WITH CLOSED EYES;So;0;ON;;;;;N;;;;; +1F63E;POUTING CAT FACE;So;0;ON;;;;;N;;;;; +1F63F;CRYING CAT FACE;So;0;ON;;;;;N;;;;; +1F640;WEARY CAT FACE;So;0;ON;;;;;N;;;;; +1F641;SLIGHTLY FROWNING FACE;So;0;ON;;;;;N;;;;; +1F642;SLIGHTLY SMILING FACE;So;0;ON;;;;;N;;;;; +1F643;UPSIDE-DOWN FACE;So;0;ON;;;;;N;;;;; +1F644;FACE WITH ROLLING EYES;So;0;ON;;;;;N;;;;; +1F645;FACE WITH NO GOOD GESTURE;So;0;ON;;;;;N;;;;; +1F646;FACE WITH OK GESTURE;So;0;ON;;;;;N;;;;; +1F647;PERSON BOWING DEEPLY;So;0;ON;;;;;N;;;;; +1F648;SEE-NO-EVIL MONKEY;So;0;ON;;;;;N;;;;; +1F649;HEAR-NO-EVIL MONKEY;So;0;ON;;;;;N;;;;; +1F64A;SPEAK-NO-EVIL MONKEY;So;0;ON;;;;;N;;;;; +1F64B;HAPPY PERSON RAISING ONE HAND;So;0;ON;;;;;N;;;;; +1F64C;PERSON RAISING BOTH HANDS IN CELEBRATION;So;0;ON;;;;;N;;;;; +1F64D;PERSON FROWNING;So;0;ON;;;;;N;;;;; +1F64E;PERSON WITH POUTING FACE;So;0;ON;;;;;N;;;;; +1F64F;PERSON WITH FOLDED HANDS;So;0;ON;;;;;N;;;;; +1F650;NORTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;; +1F651;SOUTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;; +1F652;NORTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;; +1F653;SOUTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;; +1F654;TURNED NORTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;; +1F655;TURNED SOUTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;; +1F656;TURNED NORTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;; +1F657;TURNED SOUTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;; +1F658;NORTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; +1F659;SOUTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; +1F65A;NORTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; +1F65B;SOUTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; +1F65C;HEAVY NORTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; +1F65D;HEAVY SOUTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; +1F65E;HEAVY NORTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; +1F65F;HEAVY SOUTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; +1F660;NORTH WEST POINTING BUD;So;0;ON;;;;;N;;;;; +1F661;SOUTH WEST POINTING BUD;So;0;ON;;;;;N;;;;; +1F662;NORTH EAST POINTING BUD;So;0;ON;;;;;N;;;;; +1F663;SOUTH EAST POINTING BUD;So;0;ON;;;;;N;;;;; +1F664;HEAVY NORTH WEST POINTING BUD;So;0;ON;;;;;N;;;;; +1F665;HEAVY SOUTH WEST POINTING BUD;So;0;ON;;;;;N;;;;; +1F666;HEAVY NORTH EAST POINTING BUD;So;0;ON;;;;;N;;;;; +1F667;HEAVY SOUTH EAST POINTING BUD;So;0;ON;;;;;N;;;;; +1F668;HOLLOW QUILT SQUARE ORNAMENT;So;0;ON;;;;;N;;;;; +1F669;HOLLOW QUILT SQUARE ORNAMENT IN BLACK SQUARE;So;0;ON;;;;;N;;;;; +1F66A;SOLID QUILT SQUARE ORNAMENT;So;0;ON;;;;;N;;;;; +1F66B;SOLID QUILT SQUARE ORNAMENT IN BLACK SQUARE;So;0;ON;;;;;N;;;;; +1F66C;LEFTWARDS ROCKET;So;0;ON;;;;;N;;;;; +1F66D;UPWARDS ROCKET;So;0;ON;;;;;N;;;;; +1F66E;RIGHTWARDS ROCKET;So;0;ON;;;;;N;;;;; +1F66F;DOWNWARDS ROCKET;So;0;ON;;;;;N;;;;; +1F670;SCRIPT LIGATURE ET ORNAMENT;So;0;ON;;;;;N;;;;; +1F671;HEAVY SCRIPT LIGATURE ET ORNAMENT;So;0;ON;;;;;N;;;;; +1F672;LIGATURE OPEN ET ORNAMENT;So;0;ON;;;;;N;;;;; +1F673;HEAVY LIGATURE OPEN ET ORNAMENT;So;0;ON;;;;;N;;;;; +1F674;HEAVY AMPERSAND ORNAMENT;So;0;ON;;;;;N;;;;; +1F675;SWASH AMPERSAND ORNAMENT;So;0;ON;;;;;N;;;;; +1F676;SANS-SERIF HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +1F677;SANS-SERIF HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +1F678;SANS-SERIF HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +1F679;HEAVY INTERROBANG ORNAMENT;So;0;ON;;;;;N;;;;; +1F67A;SANS-SERIF INTERROBANG ORNAMENT;So;0;ON;;;;;N;;;;; +1F67B;HEAVY SANS-SERIF INTERROBANG ORNAMENT;So;0;ON;;;;;N;;;;; +1F67C;VERY HEAVY SOLIDUS;So;0;ON;;;;;N;;;;; +1F67D;VERY HEAVY REVERSE SOLIDUS;So;0;ON;;;;;N;;;;; +1F67E;CHECKER BOARD;So;0;ON;;;;;N;;;;; +1F67F;REVERSE CHECKER BOARD;So;0;ON;;;;;N;;;;; +1F680;ROCKET;So;0;ON;;;;;N;;;;; +1F681;HELICOPTER;So;0;ON;;;;;N;;;;; +1F682;STEAM LOCOMOTIVE;So;0;ON;;;;;N;;;;; +1F683;RAILWAY CAR;So;0;ON;;;;;N;;;;; +1F684;HIGH-SPEED TRAIN;So;0;ON;;;;;N;;;;; +1F685;HIGH-SPEED TRAIN WITH BULLET NOSE;So;0;ON;;;;;N;;;;; +1F686;TRAIN;So;0;ON;;;;;N;;;;; +1F687;METRO;So;0;ON;;;;;N;;;;; +1F688;LIGHT RAIL;So;0;ON;;;;;N;;;;; +1F689;STATION;So;0;ON;;;;;N;;;;; +1F68A;TRAM;So;0;ON;;;;;N;;;;; +1F68B;TRAM CAR;So;0;ON;;;;;N;;;;; +1F68C;BUS;So;0;ON;;;;;N;;;;; +1F68D;ONCOMING BUS;So;0;ON;;;;;N;;;;; +1F68E;TROLLEYBUS;So;0;ON;;;;;N;;;;; +1F68F;BUS STOP;So;0;ON;;;;;N;;;;; +1F690;MINIBUS;So;0;ON;;;;;N;;;;; +1F691;AMBULANCE;So;0;ON;;;;;N;;;;; +1F692;FIRE ENGINE;So;0;ON;;;;;N;;;;; +1F693;POLICE CAR;So;0;ON;;;;;N;;;;; +1F694;ONCOMING POLICE CAR;So;0;ON;;;;;N;;;;; +1F695;TAXI;So;0;ON;;;;;N;;;;; +1F696;ONCOMING TAXI;So;0;ON;;;;;N;;;;; +1F697;AUTOMOBILE;So;0;ON;;;;;N;;;;; +1F698;ONCOMING AUTOMOBILE;So;0;ON;;;;;N;;;;; +1F699;RECREATIONAL VEHICLE;So;0;ON;;;;;N;;;;; +1F69A;DELIVERY TRUCK;So;0;ON;;;;;N;;;;; +1F69B;ARTICULATED LORRY;So;0;ON;;;;;N;;;;; +1F69C;TRACTOR;So;0;ON;;;;;N;;;;; +1F69D;MONORAIL;So;0;ON;;;;;N;;;;; +1F69E;MOUNTAIN RAILWAY;So;0;ON;;;;;N;;;;; +1F69F;SUSPENSION RAILWAY;So;0;ON;;;;;N;;;;; +1F6A0;MOUNTAIN CABLEWAY;So;0;ON;;;;;N;;;;; +1F6A1;AERIAL TRAMWAY;So;0;ON;;;;;N;;;;; +1F6A2;SHIP;So;0;ON;;;;;N;;;;; +1F6A3;ROWBOAT;So;0;ON;;;;;N;;;;; +1F6A4;SPEEDBOAT;So;0;ON;;;;;N;;;;; +1F6A5;HORIZONTAL TRAFFIC LIGHT;So;0;ON;;;;;N;;;;; +1F6A6;VERTICAL TRAFFIC LIGHT;So;0;ON;;;;;N;;;;; +1F6A7;CONSTRUCTION SIGN;So;0;ON;;;;;N;;;;; +1F6A8;POLICE CARS REVOLVING LIGHT;So;0;ON;;;;;N;;;;; +1F6A9;TRIANGULAR FLAG ON POST;So;0;ON;;;;;N;;;;; +1F6AA;DOOR;So;0;ON;;;;;N;;;;; +1F6AB;NO ENTRY SIGN;So;0;ON;;;;;N;;;;; +1F6AC;SMOKING SYMBOL;So;0;ON;;;;;N;;;;; +1F6AD;NO SMOKING SYMBOL;So;0;ON;;;;;N;;;;; +1F6AE;PUT LITTER IN ITS PLACE SYMBOL;So;0;ON;;;;;N;;;;; +1F6AF;DO NOT LITTER SYMBOL;So;0;ON;;;;;N;;;;; +1F6B0;POTABLE WATER SYMBOL;So;0;ON;;;;;N;;;;; +1F6B1;NON-POTABLE WATER SYMBOL;So;0;ON;;;;;N;;;;; +1F6B2;BICYCLE;So;0;ON;;;;;N;;;;; +1F6B3;NO BICYCLES;So;0;ON;;;;;N;;;;; +1F6B4;BICYCLIST;So;0;ON;;;;;N;;;;; +1F6B5;MOUNTAIN BICYCLIST;So;0;ON;;;;;N;;;;; +1F6B6;PEDESTRIAN;So;0;ON;;;;;N;;;;; +1F6B7;NO PEDESTRIANS;So;0;ON;;;;;N;;;;; +1F6B8;CHILDREN CROSSING;So;0;ON;;;;;N;;;;; +1F6B9;MENS SYMBOL;So;0;ON;;;;;N;;;;; +1F6BA;WOMENS SYMBOL;So;0;ON;;;;;N;;;;; +1F6BB;RESTROOM;So;0;ON;;;;;N;;;;; +1F6BC;BABY SYMBOL;So;0;ON;;;;;N;;;;; +1F6BD;TOILET;So;0;ON;;;;;N;;;;; +1F6BE;WATER CLOSET;So;0;ON;;;;;N;;;;; +1F6BF;SHOWER;So;0;ON;;;;;N;;;;; +1F6C0;BATH;So;0;ON;;;;;N;;;;; +1F6C1;BATHTUB;So;0;ON;;;;;N;;;;; +1F6C2;PASSPORT CONTROL;So;0;ON;;;;;N;;;;; +1F6C3;CUSTOMS;So;0;ON;;;;;N;;;;; +1F6C4;BAGGAGE CLAIM;So;0;ON;;;;;N;;;;; +1F6C5;LEFT LUGGAGE;So;0;ON;;;;;N;;;;; +1F6C6;TRIANGLE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;; +1F6C7;PROHIBITED SIGN;So;0;ON;;;;;N;;;;; +1F6C8;CIRCLED INFORMATION SOURCE;So;0;ON;;;;;N;;;;; +1F6C9;BOYS SYMBOL;So;0;ON;;;;;N;;;;; +1F6CA;GIRLS SYMBOL;So;0;ON;;;;;N;;;;; +1F6CB;COUCH AND LAMP;So;0;ON;;;;;N;;;;; +1F6CC;SLEEPING ACCOMMODATION;So;0;ON;;;;;N;;;;; +1F6CD;SHOPPING BAGS;So;0;ON;;;;;N;;;;; +1F6CE;BELLHOP BELL;So;0;ON;;;;;N;;;;; +1F6CF;BED;So;0;ON;;;;;N;;;;; +1F6D0;PLACE OF WORSHIP;So;0;ON;;;;;N;;;;; +1F6D1;OCTAGONAL SIGN;So;0;ON;;;;;N;;;;; +1F6D2;SHOPPING TROLLEY;So;0;ON;;;;;N;;;;; +1F6D3;STUPA;So;0;ON;;;;;N;;;;; +1F6D4;PAGODA;So;0;ON;;;;;N;;;;; +1F6D5;HINDU TEMPLE;So;0;ON;;;;;N;;;;; +1F6D6;HUT;So;0;ON;;;;;N;;;;; +1F6D7;ELEVATOR;So;0;ON;;;;;N;;;;; +1F6D8;LANDSLIDE;So;0;ON;;;;;N;;;;; +1F6DC;WIRELESS;So;0;ON;;;;;N;;;;; +1F6DD;PLAYGROUND SLIDE;So;0;ON;;;;;N;;;;; +1F6DE;WHEEL;So;0;ON;;;;;N;;;;; +1F6DF;RING BUOY;So;0;ON;;;;;N;;;;; +1F6E0;HAMMER AND WRENCH;So;0;ON;;;;;N;;;;; +1F6E1;SHIELD;So;0;ON;;;;;N;;;;; +1F6E2;OIL DRUM;So;0;ON;;;;;N;;;;; +1F6E3;MOTORWAY;So;0;ON;;;;;N;;;;; +1F6E4;RAILWAY TRACK;So;0;ON;;;;;N;;;;; +1F6E5;MOTOR BOAT;So;0;ON;;;;;N;;;;; +1F6E6;UP-POINTING MILITARY AIRPLANE;So;0;ON;;;;;N;;;;; +1F6E7;UP-POINTING AIRPLANE;So;0;ON;;;;;N;;;;; +1F6E8;UP-POINTING SMALL AIRPLANE;So;0;ON;;;;;N;;;;; +1F6E9;SMALL AIRPLANE;So;0;ON;;;;;N;;;;; +1F6EA;NORTHEAST-POINTING AIRPLANE;So;0;ON;;;;;N;;;;; +1F6EB;AIRPLANE DEPARTURE;So;0;ON;;;;;N;;;;; +1F6EC;AIRPLANE ARRIVING;So;0;ON;;;;;N;;;;; +1F6F0;SATELLITE;So;0;ON;;;;;N;;;;; +1F6F1;ONCOMING FIRE ENGINE;So;0;ON;;;;;N;;;;; +1F6F2;DIESEL LOCOMOTIVE;So;0;ON;;;;;N;;;;; +1F6F3;PASSENGER SHIP;So;0;ON;;;;;N;;;;; +1F6F4;SCOOTER;So;0;ON;;;;;N;;;;; +1F6F5;MOTOR SCOOTER;So;0;ON;;;;;N;;;;; +1F6F6;CANOE;So;0;ON;;;;;N;;;;; +1F6F7;SLED;So;0;ON;;;;;N;;;;; +1F6F8;FLYING SAUCER;So;0;ON;;;;;N;;;;; +1F6F9;SKATEBOARD;So;0;ON;;;;;N;;;;; +1F6FA;AUTO RICKSHAW;So;0;ON;;;;;N;;;;; +1F6FB;PICKUP TRUCK;So;0;ON;;;;;N;;;;; +1F6FC;ROLLER SKATE;So;0;ON;;;;;N;;;;; +1F700;ALCHEMICAL SYMBOL FOR QUINTESSENCE;So;0;ON;;;;;N;;;;; +1F701;ALCHEMICAL SYMBOL FOR AIR;So;0;ON;;;;;N;;;;; +1F702;ALCHEMICAL SYMBOL FOR FIRE;So;0;ON;;;;;N;;;;; +1F703;ALCHEMICAL SYMBOL FOR EARTH;So;0;ON;;;;;N;;;;; +1F704;ALCHEMICAL SYMBOL FOR WATER;So;0;ON;;;;;N;;;;; +1F705;ALCHEMICAL SYMBOL FOR AQUAFORTIS;So;0;ON;;;;;N;;;;; +1F706;ALCHEMICAL SYMBOL FOR AQUA REGIA;So;0;ON;;;;;N;;;;; +1F707;ALCHEMICAL SYMBOL FOR AQUA REGIA-2;So;0;ON;;;;;N;;;;; +1F708;ALCHEMICAL SYMBOL FOR AQUA VITAE;So;0;ON;;;;;N;;;;; +1F709;ALCHEMICAL SYMBOL FOR AQUA VITAE-2;So;0;ON;;;;;N;;;;; +1F70A;ALCHEMICAL SYMBOL FOR VINEGAR;So;0;ON;;;;;N;;;;; +1F70B;ALCHEMICAL SYMBOL FOR VINEGAR-2;So;0;ON;;;;;N;;;;; +1F70C;ALCHEMICAL SYMBOL FOR VINEGAR-3;So;0;ON;;;;;N;;;;; +1F70D;ALCHEMICAL SYMBOL FOR SULFUR;So;0;ON;;;;;N;;;;; +1F70E;ALCHEMICAL SYMBOL FOR PHILOSOPHERS SULFUR;So;0;ON;;;;;N;;;;; +1F70F;ALCHEMICAL SYMBOL FOR BLACK SULFUR;So;0;ON;;;;;N;;;;; +1F710;ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE;So;0;ON;;;;;N;;;;; +1F711;ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE-2;So;0;ON;;;;;N;;;;; +1F712;ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE-3;So;0;ON;;;;;N;;;;; +1F713;ALCHEMICAL SYMBOL FOR CINNABAR;So;0;ON;;;;;N;;;;; +1F714;ALCHEMICAL SYMBOL FOR SALT;So;0;ON;;;;;N;;;;; +1F715;ALCHEMICAL SYMBOL FOR NITRE;So;0;ON;;;;;N;;;;; +1F716;ALCHEMICAL SYMBOL FOR VITRIOL;So;0;ON;;;;;N;;;;; +1F717;ALCHEMICAL SYMBOL FOR VITRIOL-2;So;0;ON;;;;;N;;;;; +1F718;ALCHEMICAL SYMBOL FOR ROCK SALT;So;0;ON;;;;;N;;;;; +1F719;ALCHEMICAL SYMBOL FOR ROCK SALT-2;So;0;ON;;;;;N;;;;; +1F71A;ALCHEMICAL SYMBOL FOR GOLD;So;0;ON;;;;;N;;;;; +1F71B;ALCHEMICAL SYMBOL FOR SILVER;So;0;ON;;;;;N;;;;; +1F71C;ALCHEMICAL SYMBOL FOR IRON ORE;So;0;ON;;;;;N;;;;; +1F71D;ALCHEMICAL SYMBOL FOR IRON ORE-2;So;0;ON;;;;;N;;;;; +1F71E;ALCHEMICAL SYMBOL FOR CROCUS OF IRON;So;0;ON;;;;;N;;;;; +1F71F;ALCHEMICAL SYMBOL FOR REGULUS OF IRON;So;0;ON;;;;;N;;;;; +1F720;ALCHEMICAL SYMBOL FOR COPPER ORE;So;0;ON;;;;;N;;;;; +1F721;ALCHEMICAL SYMBOL FOR IRON-COPPER ORE;So;0;ON;;;;;N;;;;; +1F722;ALCHEMICAL SYMBOL FOR SUBLIMATE OF COPPER;So;0;ON;;;;;N;;;;; +1F723;ALCHEMICAL SYMBOL FOR CROCUS OF COPPER;So;0;ON;;;;;N;;;;; +1F724;ALCHEMICAL SYMBOL FOR CROCUS OF COPPER-2;So;0;ON;;;;;N;;;;; +1F725;ALCHEMICAL SYMBOL FOR COPPER ANTIMONIATE;So;0;ON;;;;;N;;;;; +1F726;ALCHEMICAL SYMBOL FOR SALT OF COPPER ANTIMONIATE;So;0;ON;;;;;N;;;;; +1F727;ALCHEMICAL SYMBOL FOR SUBLIMATE OF SALT OF COPPER;So;0;ON;;;;;N;;;;; +1F728;ALCHEMICAL SYMBOL FOR VERDIGRIS;So;0;ON;;;;;N;;;;; +1F729;ALCHEMICAL SYMBOL FOR TIN ORE;So;0;ON;;;;;N;;;;; +1F72A;ALCHEMICAL SYMBOL FOR LEAD ORE;So;0;ON;;;;;N;;;;; +1F72B;ALCHEMICAL SYMBOL FOR ANTIMONY ORE;So;0;ON;;;;;N;;;;; +1F72C;ALCHEMICAL SYMBOL FOR SUBLIMATE OF ANTIMONY;So;0;ON;;;;;N;;;;; +1F72D;ALCHEMICAL SYMBOL FOR SALT OF ANTIMONY;So;0;ON;;;;;N;;;;; +1F72E;ALCHEMICAL SYMBOL FOR SUBLIMATE OF SALT OF ANTIMONY;So;0;ON;;;;;N;;;;; +1F72F;ALCHEMICAL SYMBOL FOR VINEGAR OF ANTIMONY;So;0;ON;;;;;N;;;;; +1F730;ALCHEMICAL SYMBOL FOR REGULUS OF ANTIMONY;So;0;ON;;;;;N;;;;; +1F731;ALCHEMICAL SYMBOL FOR REGULUS OF ANTIMONY-2;So;0;ON;;;;;N;;;;; +1F732;ALCHEMICAL SYMBOL FOR REGULUS;So;0;ON;;;;;N;;;;; +1F733;ALCHEMICAL SYMBOL FOR REGULUS-2;So;0;ON;;;;;N;;;;; +1F734;ALCHEMICAL SYMBOL FOR REGULUS-3;So;0;ON;;;;;N;;;;; +1F735;ALCHEMICAL SYMBOL FOR REGULUS-4;So;0;ON;;;;;N;;;;; +1F736;ALCHEMICAL SYMBOL FOR ALKALI;So;0;ON;;;;;N;;;;; +1F737;ALCHEMICAL SYMBOL FOR ALKALI-2;So;0;ON;;;;;N;;;;; +1F738;ALCHEMICAL SYMBOL FOR MARCASITE;So;0;ON;;;;;N;;;;; +1F739;ALCHEMICAL SYMBOL FOR SAL-AMMONIAC;So;0;ON;;;;;N;;;;; +1F73A;ALCHEMICAL SYMBOL FOR ARSENIC;So;0;ON;;;;;N;;;;; +1F73B;ALCHEMICAL SYMBOL FOR REALGAR;So;0;ON;;;;;N;;;;; +1F73C;ALCHEMICAL SYMBOL FOR REALGAR-2;So;0;ON;;;;;N;;;;; +1F73D;ALCHEMICAL SYMBOL FOR AURIPIGMENT;So;0;ON;;;;;N;;;;; +1F73E;ALCHEMICAL SYMBOL FOR BISMUTH ORE;So;0;ON;;;;;N;;;;; +1F73F;ALCHEMICAL SYMBOL FOR TARTAR;So;0;ON;;;;;N;;;;; +1F740;ALCHEMICAL SYMBOL FOR TARTAR-2;So;0;ON;;;;;N;;;;; +1F741;ALCHEMICAL SYMBOL FOR QUICK LIME;So;0;ON;;;;;N;;;;; +1F742;ALCHEMICAL SYMBOL FOR BORAX;So;0;ON;;;;;N;;;;; +1F743;ALCHEMICAL SYMBOL FOR BORAX-2;So;0;ON;;;;;N;;;;; +1F744;ALCHEMICAL SYMBOL FOR BORAX-3;So;0;ON;;;;;N;;;;; +1F745;ALCHEMICAL SYMBOL FOR ALUM;So;0;ON;;;;;N;;;;; +1F746;ALCHEMICAL SYMBOL FOR OIL;So;0;ON;;;;;N;;;;; +1F747;ALCHEMICAL SYMBOL FOR SPIRIT;So;0;ON;;;;;N;;;;; +1F748;ALCHEMICAL SYMBOL FOR TINCTURE;So;0;ON;;;;;N;;;;; +1F749;ALCHEMICAL SYMBOL FOR GUM;So;0;ON;;;;;N;;;;; +1F74A;ALCHEMICAL SYMBOL FOR WAX;So;0;ON;;;;;N;;;;; +1F74B;ALCHEMICAL SYMBOL FOR POWDER;So;0;ON;;;;;N;;;;; +1F74C;ALCHEMICAL SYMBOL FOR CALX;So;0;ON;;;;;N;;;;; +1F74D;ALCHEMICAL SYMBOL FOR TUTTY;So;0;ON;;;;;N;;;;; +1F74E;ALCHEMICAL SYMBOL FOR CAPUT MORTUUM;So;0;ON;;;;;N;;;;; +1F74F;ALCHEMICAL SYMBOL FOR SCEPTER OF JOVE;So;0;ON;;;;;N;;;;; +1F750;ALCHEMICAL SYMBOL FOR CADUCEUS;So;0;ON;;;;;N;;;;; +1F751;ALCHEMICAL SYMBOL FOR TRIDENT;So;0;ON;;;;;N;;;;; +1F752;ALCHEMICAL SYMBOL FOR STARRED TRIDENT;So;0;ON;;;;;N;;;;; +1F753;ALCHEMICAL SYMBOL FOR LODESTONE;So;0;ON;;;;;N;;;;; +1F754;ALCHEMICAL SYMBOL FOR SOAP;So;0;ON;;;;;N;;;;; +1F755;ALCHEMICAL SYMBOL FOR URINE;So;0;ON;;;;;N;;;;; +1F756;ALCHEMICAL SYMBOL FOR HORSE DUNG;So;0;ON;;;;;N;;;;; +1F757;ALCHEMICAL SYMBOL FOR ASHES;So;0;ON;;;;;N;;;;; +1F758;ALCHEMICAL SYMBOL FOR POT ASHES;So;0;ON;;;;;N;;;;; +1F759;ALCHEMICAL SYMBOL FOR BRICK;So;0;ON;;;;;N;;;;; +1F75A;ALCHEMICAL SYMBOL FOR POWDERED BRICK;So;0;ON;;;;;N;;;;; +1F75B;ALCHEMICAL SYMBOL FOR AMALGAM;So;0;ON;;;;;N;;;;; +1F75C;ALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUM;So;0;ON;;;;;N;;;;; +1F75D;ALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUM-2;So;0;ON;;;;;N;;;;; +1F75E;ALCHEMICAL SYMBOL FOR SUBLIMATION;So;0;ON;;;;;N;;;;; +1F75F;ALCHEMICAL SYMBOL FOR PRECIPITATE;So;0;ON;;;;;N;;;;; +1F760;ALCHEMICAL SYMBOL FOR DISTILL;So;0;ON;;;;;N;;;;; +1F761;ALCHEMICAL SYMBOL FOR DISSOLVE;So;0;ON;;;;;N;;;;; +1F762;ALCHEMICAL SYMBOL FOR DISSOLVE-2;So;0;ON;;;;;N;;;;; +1F763;ALCHEMICAL SYMBOL FOR PURIFY;So;0;ON;;;;;N;;;;; +1F764;ALCHEMICAL SYMBOL FOR PUTREFACTION;So;0;ON;;;;;N;;;;; +1F765;ALCHEMICAL SYMBOL FOR CRUCIBLE;So;0;ON;;;;;N;;;;; +1F766;ALCHEMICAL SYMBOL FOR CRUCIBLE-2;So;0;ON;;;;;N;;;;; +1F767;ALCHEMICAL SYMBOL FOR CRUCIBLE-3;So;0;ON;;;;;N;;;;; +1F768;ALCHEMICAL SYMBOL FOR CRUCIBLE-4;So;0;ON;;;;;N;;;;; +1F769;ALCHEMICAL SYMBOL FOR CRUCIBLE-5;So;0;ON;;;;;N;;;;; +1F76A;ALCHEMICAL SYMBOL FOR ALEMBIC;So;0;ON;;;;;N;;;;; +1F76B;ALCHEMICAL SYMBOL FOR BATH OF MARY;So;0;ON;;;;;N;;;;; +1F76C;ALCHEMICAL SYMBOL FOR BATH OF VAPOURS;So;0;ON;;;;;N;;;;; +1F76D;ALCHEMICAL SYMBOL FOR RETORT;So;0;ON;;;;;N;;;;; +1F76E;ALCHEMICAL SYMBOL FOR HOUR;So;0;ON;;;;;N;;;;; +1F76F;ALCHEMICAL SYMBOL FOR NIGHT;So;0;ON;;;;;N;;;;; +1F770;ALCHEMICAL SYMBOL FOR DAY-NIGHT;So;0;ON;;;;;N;;;;; +1F771;ALCHEMICAL SYMBOL FOR MONTH;So;0;ON;;;;;N;;;;; +1F772;ALCHEMICAL SYMBOL FOR HALF DRAM;So;0;ON;;;;;N;;;;; +1F773;ALCHEMICAL SYMBOL FOR HALF OUNCE;So;0;ON;;;;;N;;;;; +1F774;LOT OF FORTUNE;So;0;ON;;;;;N;;;;; +1F775;OCCULTATION;So;0;ON;;;;;N;;;;; +1F776;LUNAR ECLIPSE;So;0;ON;;;;;N;;;;; +1F777;VESTA FORM TWO;So;0;ON;;;;;N;;;;; +1F778;ASTRAEA FORM TWO;So;0;ON;;;;;N;;;;; +1F779;HYGIEA FORM TWO;So;0;ON;;;;;N;;;;; +1F77A;PARTHENOPE FORM TWO;So;0;ON;;;;;N;;;;; +1F77B;HAUMEA;So;0;ON;;;;;N;;;;; +1F77C;MAKEMAKE;So;0;ON;;;;;N;;;;; +1F77D;GONGGONG;So;0;ON;;;;;N;;;;; +1F77E;QUAOAR;So;0;ON;;;;;N;;;;; +1F77F;ORCUS;So;0;ON;;;;;N;;;;; +1F780;BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; +1F781;BLACK UP-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; +1F782;BLACK RIGHT-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; +1F783;BLACK DOWN-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; +1F784;BLACK SLIGHTLY SMALL CIRCLE;So;0;ON;;;;;N;;;;; +1F785;MEDIUM BOLD WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1F786;BOLD WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1F787;HEAVY WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1F788;VERY HEAVY WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1F789;EXTREMELY HEAVY WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1F78A;WHITE CIRCLE CONTAINING BLACK SMALL CIRCLE;So;0;ON;;;;;N;;;;; +1F78B;ROUND TARGET;So;0;ON;;;;;N;;;;; +1F78C;BLACK TINY SQUARE;So;0;ON;;;;;N;;;;; +1F78D;BLACK SLIGHTLY SMALL SQUARE;So;0;ON;;;;;N;;;;; +1F78E;LIGHT WHITE SQUARE;So;0;ON;;;;;N;;;;; +1F78F;MEDIUM WHITE SQUARE;So;0;ON;;;;;N;;;;; +1F790;BOLD WHITE SQUARE;So;0;ON;;;;;N;;;;; +1F791;HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;; +1F792;VERY HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;; +1F793;EXTREMELY HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;; +1F794;WHITE SQUARE CONTAINING BLACK VERY SMALL SQUARE;So;0;ON;;;;;N;;;;; +1F795;WHITE SQUARE CONTAINING BLACK MEDIUM SQUARE;So;0;ON;;;;;N;;;;; +1F796;SQUARE TARGET;So;0;ON;;;;;N;;;;; +1F797;BLACK TINY DIAMOND;So;0;ON;;;;;N;;;;; +1F798;BLACK VERY SMALL DIAMOND;So;0;ON;;;;;N;;;;; +1F799;BLACK MEDIUM SMALL DIAMOND;So;0;ON;;;;;N;;;;; +1F79A;WHITE DIAMOND CONTAINING BLACK VERY SMALL DIAMOND;So;0;ON;;;;;N;;;;; +1F79B;WHITE DIAMOND CONTAINING BLACK MEDIUM DIAMOND;So;0;ON;;;;;N;;;;; +1F79C;DIAMOND TARGET;So;0;ON;;;;;N;;;;; +1F79D;BLACK TINY LOZENGE;So;0;ON;;;;;N;;;;; +1F79E;BLACK VERY SMALL LOZENGE;So;0;ON;;;;;N;;;;; +1F79F;BLACK MEDIUM SMALL LOZENGE;So;0;ON;;;;;N;;;;; +1F7A0;WHITE LOZENGE CONTAINING BLACK SMALL LOZENGE;So;0;ON;;;;;N;;;;; +1F7A1;THIN GREEK CROSS;So;0;ON;;;;;N;;;;; +1F7A2;LIGHT GREEK CROSS;So;0;ON;;;;;N;;;;; +1F7A3;MEDIUM GREEK CROSS;So;0;ON;;;;;N;;;;; +1F7A4;BOLD GREEK CROSS;So;0;ON;;;;;N;;;;; +1F7A5;VERY BOLD GREEK CROSS;So;0;ON;;;;;N;;;;; +1F7A6;VERY HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;; +1F7A7;EXTREMELY HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;; +1F7A8;THIN SALTIRE;So;0;ON;;;;;N;;;;; +1F7A9;LIGHT SALTIRE;So;0;ON;;;;;N;;;;; +1F7AA;MEDIUM SALTIRE;So;0;ON;;;;;N;;;;; +1F7AB;BOLD SALTIRE;So;0;ON;;;;;N;;;;; +1F7AC;HEAVY SALTIRE;So;0;ON;;;;;N;;;;; +1F7AD;VERY HEAVY SALTIRE;So;0;ON;;;;;N;;;;; +1F7AE;EXTREMELY HEAVY SALTIRE;So;0;ON;;;;;N;;;;; +1F7AF;LIGHT FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B0;MEDIUM FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B1;BOLD FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B2;HEAVY FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B3;VERY HEAVY FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B4;EXTREMELY HEAVY FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B5;LIGHT SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B6;MEDIUM SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B7;BOLD SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B8;HEAVY SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B9;VERY HEAVY SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7BA;EXTREMELY HEAVY SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7BB;LIGHT EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7BC;MEDIUM EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7BD;BOLD EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7BE;HEAVY EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7BF;VERY HEAVY EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7C0;LIGHT THREE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7C1;MEDIUM THREE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7C2;THREE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7C3;MEDIUM THREE POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; +1F7C4;LIGHT FOUR POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7C5;MEDIUM FOUR POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7C6;FOUR POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7C7;MEDIUM FOUR POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; +1F7C8;REVERSE LIGHT FOUR POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; +1F7C9;LIGHT FIVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7CA;HEAVY FIVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7CB;MEDIUM SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7CC;HEAVY SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7CD;SIX POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; +1F7CE;MEDIUM EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7CF;HEAVY EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7D0;VERY HEAVY EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7D1;HEAVY EIGHT POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; +1F7D2;LIGHT TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7D3;HEAVY TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7D4;HEAVY TWELVE POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; +1F7D5;CIRCLED TRIANGLE;So;0;ON;;;;;N;;;;; +1F7D6;NEGATIVE CIRCLED TRIANGLE;So;0;ON;;;;;N;;;;; +1F7D7;CIRCLED SQUARE;So;0;ON;;;;;N;;;;; +1F7D8;NEGATIVE CIRCLED SQUARE;So;0;ON;;;;;N;;;;; +1F7D9;NINE POINTED WHITE STAR;So;0;ON;;;;;N;;;;; +1F7E0;LARGE ORANGE CIRCLE;So;0;ON;;;;;N;;;;; +1F7E1;LARGE YELLOW CIRCLE;So;0;ON;;;;;N;;;;; +1F7E2;LARGE GREEN CIRCLE;So;0;ON;;;;;N;;;;; +1F7E3;LARGE PURPLE CIRCLE;So;0;ON;;;;;N;;;;; +1F7E4;LARGE BROWN CIRCLE;So;0;ON;;;;;N;;;;; +1F7E5;LARGE RED SQUARE;So;0;ON;;;;;N;;;;; +1F7E6;LARGE BLUE SQUARE;So;0;ON;;;;;N;;;;; +1F7E7;LARGE ORANGE SQUARE;So;0;ON;;;;;N;;;;; +1F7E8;LARGE YELLOW SQUARE;So;0;ON;;;;;N;;;;; +1F7E9;LARGE GREEN SQUARE;So;0;ON;;;;;N;;;;; +1F7EA;LARGE PURPLE SQUARE;So;0;ON;;;;;N;;;;; +1F7EB;LARGE BROWN SQUARE;So;0;ON;;;;;N;;;;; +1F7F0;HEAVY EQUALS SIGN;So;0;ON;;;;;N;;;;; +1F800;LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F801;UPWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F802;RIGHTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F803;DOWNWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F804;LEFTWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F805;UPWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F806;RIGHTWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F807;DOWNWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F808;LEFTWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F809;UPWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F80A;RIGHTWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F80B;DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F810;LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F811;UPWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F812;RIGHTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F813;DOWNWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F814;LEFTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F815;UPWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F816;RIGHTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F817;DOWNWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F818;HEAVY LEFTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F819;HEAVY UPWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F81A;HEAVY RIGHTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F81B;HEAVY DOWNWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F81C;HEAVY LEFTWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F81D;HEAVY UPWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F81E;HEAVY RIGHTWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F81F;HEAVY DOWNWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F820;LEFTWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;; +1F821;UPWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;; +1F822;RIGHTWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;; +1F823;DOWNWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;; +1F824;LEFTWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;; +1F825;UPWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;; +1F826;RIGHTWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;; +1F827;DOWNWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;; +1F828;LEFTWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;; +1F829;UPWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;; +1F82A;RIGHTWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;; +1F82B;DOWNWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;; +1F82C;LEFTWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;; +1F82D;UPWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;; +1F82E;RIGHTWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;; +1F82F;DOWNWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;; +1F830;LEFTWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;; +1F831;UPWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;; +1F832;RIGHTWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;; +1F833;DOWNWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;; +1F834;LEFTWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;; +1F835;UPWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;; +1F836;RIGHTWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;; +1F837;DOWNWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;; +1F838;LEFTWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;; +1F839;UPWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;; +1F83A;RIGHTWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;; +1F83B;DOWNWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;; +1F83C;LEFTWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;; +1F83D;UPWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;; +1F83E;RIGHTWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;; +1F83F;DOWNWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;; +1F840;LEFTWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;; +1F841;UPWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;; +1F842;RIGHTWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;; +1F843;DOWNWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;; +1F844;LEFTWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;; +1F845;UPWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;; +1F846;RIGHTWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;; +1F847;DOWNWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;; +1F850;LEFTWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F851;UPWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F852;RIGHTWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F853;DOWNWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F854;NORTH WEST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F855;NORTH EAST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F856;SOUTH EAST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F857;SOUTH WEST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F858;LEFT RIGHT SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F859;UP DOWN SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F860;WIDE-HEADED LEFTWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; +1F861;WIDE-HEADED UPWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; +1F862;WIDE-HEADED RIGHTWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; +1F863;WIDE-HEADED DOWNWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; +1F864;WIDE-HEADED NORTH WEST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; +1F865;WIDE-HEADED NORTH EAST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; +1F866;WIDE-HEADED SOUTH EAST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; +1F867;WIDE-HEADED SOUTH WEST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; +1F868;WIDE-HEADED LEFTWARDS BARB ARROW;So;0;ON;;;;;N;;;;; +1F869;WIDE-HEADED UPWARDS BARB ARROW;So;0;ON;;;;;N;;;;; +1F86A;WIDE-HEADED RIGHTWARDS BARB ARROW;So;0;ON;;;;;N;;;;; +1F86B;WIDE-HEADED DOWNWARDS BARB ARROW;So;0;ON;;;;;N;;;;; +1F86C;WIDE-HEADED NORTH WEST BARB ARROW;So;0;ON;;;;;N;;;;; +1F86D;WIDE-HEADED NORTH EAST BARB ARROW;So;0;ON;;;;;N;;;;; +1F86E;WIDE-HEADED SOUTH EAST BARB ARROW;So;0;ON;;;;;N;;;;; +1F86F;WIDE-HEADED SOUTH WEST BARB ARROW;So;0;ON;;;;;N;;;;; +1F870;WIDE-HEADED LEFTWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; +1F871;WIDE-HEADED UPWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; +1F872;WIDE-HEADED RIGHTWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; +1F873;WIDE-HEADED DOWNWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; +1F874;WIDE-HEADED NORTH WEST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; +1F875;WIDE-HEADED NORTH EAST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; +1F876;WIDE-HEADED SOUTH EAST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; +1F877;WIDE-HEADED SOUTH WEST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; +1F878;WIDE-HEADED LEFTWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F879;WIDE-HEADED UPWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F87A;WIDE-HEADED RIGHTWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F87B;WIDE-HEADED DOWNWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F87C;WIDE-HEADED NORTH WEST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F87D;WIDE-HEADED NORTH EAST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F87E;WIDE-HEADED SOUTH EAST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F87F;WIDE-HEADED SOUTH WEST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F880;WIDE-HEADED LEFTWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F881;WIDE-HEADED UPWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F882;WIDE-HEADED RIGHTWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F883;WIDE-HEADED DOWNWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F884;WIDE-HEADED NORTH WEST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F885;WIDE-HEADED NORTH EAST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F886;WIDE-HEADED SOUTH EAST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F887;WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F890;LEFTWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F891;UPWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F892;RIGHTWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F893;DOWNWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F894;LEFTWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F895;UPWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F896;RIGHTWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F897;DOWNWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F898;LEFTWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;; +1F899;UPWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;; +1F89A;RIGHTWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;; +1F89B;DOWNWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;; +1F89C;HEAVY ARROW SHAFT WIDTH ONE;So;0;ON;;;;;N;;;;; +1F89D;HEAVY ARROW SHAFT WIDTH TWO THIRDS;So;0;ON;;;;;N;;;;; +1F89E;HEAVY ARROW SHAFT WIDTH ONE HALF;So;0;ON;;;;;N;;;;; +1F89F;HEAVY ARROW SHAFT WIDTH ONE THIRD;So;0;ON;;;;;N;;;;; +1F8A0;LEFTWARDS BOTTOM-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A1;RIGHTWARDS BOTTOM SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A2;LEFTWARDS TOP SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A3;RIGHTWARDS TOP SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A4;LEFTWARDS LEFT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A5;RIGHTWARDS RIGHT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A6;LEFTWARDS RIGHT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A7;RIGHTWARDS LEFT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A8;LEFTWARDS BACK-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A9;RIGHTWARDS BACK-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8AA;LEFTWARDS FRONT-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8AB;RIGHTWARDS FRONT-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8AC;WHITE ARROW SHAFT WIDTH ONE;So;0;ON;;;;;N;;;;; +1F8AD;WHITE ARROW SHAFT WIDTH TWO THIRDS;So;0;ON;;;;;N;;;;; +1F8B0;ARROW POINTING UPWARDS THEN NORTH WEST;So;0;ON;;;;;N;;;;; +1F8B1;ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST;So;0;ON;;;;;N;;;;; +1F8B2;RIGHTWARDS ARROW WITH LOWER HOOK;So;0;ON;;;;;N;;;;; +1F8B3;DOWNWARDS BLACK ARROW TO BAR;So;0;ON;;;;;N;;;;; +1F8B4;NEGATIVE SQUARED LEFTWARDS ARROW;So;0;ON;;;;;N;;;;; +1F8B5;NEGATIVE SQUARED UPWARDS ARROW;So;0;ON;;;;;N;;;;; +1F8B6;NEGATIVE SQUARED RIGHTWARDS ARROW;So;0;ON;;;;;N;;;;; +1F8B7;NEGATIVE SQUARED DOWNWARDS ARROW;So;0;ON;;;;;N;;;;; +1F8B8;NORTH WEST ARROW FROM BAR;So;0;ON;;;;;N;;;;; +1F8B9;NORTH EAST ARROW FROM BAR;So;0;ON;;;;;N;;;;; +1F8BA;SOUTH EAST ARROW FROM BAR;So;0;ON;;;;;N;;;;; +1F8BB;SOUTH WEST ARROW FROM BAR;So;0;ON;;;;;N;;;;; +1F8C0;LEFTWARDS ARROW FROM DOWNWARDS ARROW;So;0;ON;;;;;N;;;;; +1F8C1;RIGHTWARDS ARROW FROM DOWNWARDS ARROW;So;0;ON;;;;;N;;;;; +1F8D0;LONG RIGHTWARDS ARROW OVER LONG LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +1F8D1;LONG RIGHTWARDS HARPOON OVER LONG LEFTWARDS HARPOON;Sm;0;ON;;;;;N;;;;; +1F8D2;LONG RIGHTWARDS HARPOON ABOVE SHORT LEFTWARDS HARPOON;Sm;0;ON;;;;;N;;;;; +1F8D3;SHORT RIGHTWARDS HARPOON ABOVE LONG LEFTWARDS HARPOON;Sm;0;ON;;;;;N;;;;; +1F8D4;LONG LEFTWARDS HARPOON ABOVE SHORT RIGHTWARDS HARPOON;Sm;0;ON;;;;;N;;;;; +1F8D5;SHORT LEFTWARDS HARPOON ABOVE LONG RIGHTWARDS HARPOON;Sm;0;ON;;;;;N;;;;; +1F8D6;LONG RIGHTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;; +1F8D7;LONG RIGHTWARDS ARROW WITH DOUBLE SLASH;Sm;0;ON;;;;;N;;;;; +1F8D8;LONG LEFT RIGHT ARROW WITH DEPENDENT LOBE;Sm;0;ON;;;;;N;;;;; +1F900;CIRCLED CROSS FORMEE WITH FOUR DOTS;So;0;ON;;;;;N;;;;; +1F901;CIRCLED CROSS FORMEE WITH TWO DOTS;So;0;ON;;;;;N;;;;; +1F902;CIRCLED CROSS FORMEE;So;0;ON;;;;;N;;;;; +1F903;LEFT HALF CIRCLE WITH FOUR DOTS;So;0;ON;;;;;N;;;;; +1F904;LEFT HALF CIRCLE WITH THREE DOTS;So;0;ON;;;;;N;;;;; +1F905;LEFT HALF CIRCLE WITH TWO DOTS;So;0;ON;;;;;N;;;;; +1F906;LEFT HALF CIRCLE WITH DOT;So;0;ON;;;;;N;;;;; +1F907;LEFT HALF CIRCLE;So;0;ON;;;;;N;;;;; +1F908;DOWNWARD FACING HOOK;So;0;ON;;;;;N;;;;; +1F909;DOWNWARD FACING NOTCHED HOOK;So;0;ON;;;;;N;;;;; +1F90A;DOWNWARD FACING HOOK WITH DOT;So;0;ON;;;;;N;;;;; +1F90B;DOWNWARD FACING NOTCHED HOOK WITH DOT;So;0;ON;;;;;N;;;;; +1F90C;PINCHED FINGERS;So;0;ON;;;;;N;;;;; +1F90D;WHITE HEART;So;0;ON;;;;;N;;;;; +1F90E;BROWN HEART;So;0;ON;;;;;N;;;;; +1F90F;PINCHING HAND;So;0;ON;;;;;N;;;;; +1F910;ZIPPER-MOUTH FACE;So;0;ON;;;;;N;;;;; +1F911;MONEY-MOUTH FACE;So;0;ON;;;;;N;;;;; +1F912;FACE WITH THERMOMETER;So;0;ON;;;;;N;;;;; +1F913;NERD FACE;So;0;ON;;;;;N;;;;; +1F914;THINKING FACE;So;0;ON;;;;;N;;;;; +1F915;FACE WITH HEAD-BANDAGE;So;0;ON;;;;;N;;;;; +1F916;ROBOT FACE;So;0;ON;;;;;N;;;;; +1F917;HUGGING FACE;So;0;ON;;;;;N;;;;; +1F918;SIGN OF THE HORNS;So;0;ON;;;;;N;;;;; +1F919;CALL ME HAND;So;0;ON;;;;;N;;;;; +1F91A;RAISED BACK OF HAND;So;0;ON;;;;;N;;;;; +1F91B;LEFT-FACING FIST;So;0;ON;;;;;N;;;;; +1F91C;RIGHT-FACING FIST;So;0;ON;;;;;N;;;;; +1F91D;HANDSHAKE;So;0;ON;;;;;N;;;;; +1F91E;HAND WITH INDEX AND MIDDLE FINGERS CROSSED;So;0;ON;;;;;N;;;;; +1F91F;I LOVE YOU HAND SIGN;So;0;ON;;;;;N;;;;; +1F920;FACE WITH COWBOY HAT;So;0;ON;;;;;N;;;;; +1F921;CLOWN FACE;So;0;ON;;;;;N;;;;; +1F922;NAUSEATED FACE;So;0;ON;;;;;N;;;;; +1F923;ROLLING ON THE FLOOR LAUGHING;So;0;ON;;;;;N;;;;; +1F924;DROOLING FACE;So;0;ON;;;;;N;;;;; +1F925;LYING FACE;So;0;ON;;;;;N;;;;; +1F926;FACE PALM;So;0;ON;;;;;N;;;;; +1F927;SNEEZING FACE;So;0;ON;;;;;N;;;;; +1F928;FACE WITH ONE EYEBROW RAISED;So;0;ON;;;;;N;;;;; +1F929;GRINNING FACE WITH STAR EYES;So;0;ON;;;;;N;;;;; +1F92A;GRINNING FACE WITH ONE LARGE AND ONE SMALL EYE;So;0;ON;;;;;N;;;;; +1F92B;FACE WITH FINGER COVERING CLOSED LIPS;So;0;ON;;;;;N;;;;; +1F92C;SERIOUS FACE WITH SYMBOLS COVERING MOUTH;So;0;ON;;;;;N;;;;; +1F92D;SMILING FACE WITH SMILING EYES AND HAND COVERING MOUTH;So;0;ON;;;;;N;;;;; +1F92E;FACE WITH OPEN MOUTH VOMITING;So;0;ON;;;;;N;;;;; +1F92F;SHOCKED FACE WITH EXPLODING HEAD;So;0;ON;;;;;N;;;;; +1F930;PREGNANT WOMAN;So;0;ON;;;;;N;;;;; +1F931;BREAST-FEEDING;So;0;ON;;;;;N;;;;; +1F932;PALMS UP TOGETHER;So;0;ON;;;;;N;;;;; +1F933;SELFIE;So;0;ON;;;;;N;;;;; +1F934;PRINCE;So;0;ON;;;;;N;;;;; +1F935;MAN IN TUXEDO;So;0;ON;;;;;N;;;;; +1F936;MOTHER CHRISTMAS;So;0;ON;;;;;N;;;;; +1F937;SHRUG;So;0;ON;;;;;N;;;;; +1F938;PERSON DOING CARTWHEEL;So;0;ON;;;;;N;;;;; +1F939;JUGGLING;So;0;ON;;;;;N;;;;; +1F93A;FENCER;So;0;ON;;;;;N;;;;; +1F93B;MODERN PENTATHLON;So;0;ON;;;;;N;;;;; +1F93C;WRESTLERS;So;0;ON;;;;;N;;;;; +1F93D;WATER POLO;So;0;ON;;;;;N;;;;; +1F93E;HANDBALL;So;0;ON;;;;;N;;;;; +1F93F;DIVING MASK;So;0;ON;;;;;N;;;;; +1F940;WILTED FLOWER;So;0;ON;;;;;N;;;;; +1F941;DRUM WITH DRUMSTICKS;So;0;ON;;;;;N;;;;; +1F942;CLINKING GLASSES;So;0;ON;;;;;N;;;;; +1F943;TUMBLER GLASS;So;0;ON;;;;;N;;;;; +1F944;SPOON;So;0;ON;;;;;N;;;;; +1F945;GOAL NET;So;0;ON;;;;;N;;;;; +1F946;RIFLE;So;0;ON;;;;;N;;;;; +1F947;FIRST PLACE MEDAL;So;0;ON;;;;;N;;;;; +1F948;SECOND PLACE MEDAL;So;0;ON;;;;;N;;;;; +1F949;THIRD PLACE MEDAL;So;0;ON;;;;;N;;;;; +1F94A;BOXING GLOVE;So;0;ON;;;;;N;;;;; +1F94B;MARTIAL ARTS UNIFORM;So;0;ON;;;;;N;;;;; +1F94C;CURLING STONE;So;0;ON;;;;;N;;;;; +1F94D;LACROSSE STICK AND BALL;So;0;ON;;;;;N;;;;; +1F94E;SOFTBALL;So;0;ON;;;;;N;;;;; +1F94F;FLYING DISC;So;0;ON;;;;;N;;;;; +1F950;CROISSANT;So;0;ON;;;;;N;;;;; +1F951;AVOCADO;So;0;ON;;;;;N;;;;; +1F952;CUCUMBER;So;0;ON;;;;;N;;;;; +1F953;BACON;So;0;ON;;;;;N;;;;; +1F954;POTATO;So;0;ON;;;;;N;;;;; +1F955;CARROT;So;0;ON;;;;;N;;;;; +1F956;BAGUETTE BREAD;So;0;ON;;;;;N;;;;; +1F957;GREEN SALAD;So;0;ON;;;;;N;;;;; +1F958;SHALLOW PAN OF FOOD;So;0;ON;;;;;N;;;;; +1F959;STUFFED FLATBREAD;So;0;ON;;;;;N;;;;; +1F95A;EGG;So;0;ON;;;;;N;;;;; +1F95B;GLASS OF MILK;So;0;ON;;;;;N;;;;; +1F95C;PEANUTS;So;0;ON;;;;;N;;;;; +1F95D;KIWIFRUIT;So;0;ON;;;;;N;;;;; +1F95E;PANCAKES;So;0;ON;;;;;N;;;;; +1F95F;DUMPLING;So;0;ON;;;;;N;;;;; +1F960;FORTUNE COOKIE;So;0;ON;;;;;N;;;;; +1F961;TAKEOUT BOX;So;0;ON;;;;;N;;;;; +1F962;CHOPSTICKS;So;0;ON;;;;;N;;;;; +1F963;BOWL WITH SPOON;So;0;ON;;;;;N;;;;; +1F964;CUP WITH STRAW;So;0;ON;;;;;N;;;;; +1F965;COCONUT;So;0;ON;;;;;N;;;;; +1F966;BROCCOLI;So;0;ON;;;;;N;;;;; +1F967;PIE;So;0;ON;;;;;N;;;;; +1F968;PRETZEL;So;0;ON;;;;;N;;;;; +1F969;CUT OF MEAT;So;0;ON;;;;;N;;;;; +1F96A;SANDWICH;So;0;ON;;;;;N;;;;; +1F96B;CANNED FOOD;So;0;ON;;;;;N;;;;; +1F96C;LEAFY GREEN;So;0;ON;;;;;N;;;;; +1F96D;MANGO;So;0;ON;;;;;N;;;;; +1F96E;MOON CAKE;So;0;ON;;;;;N;;;;; +1F96F;BAGEL;So;0;ON;;;;;N;;;;; +1F970;SMILING FACE WITH SMILING EYES AND THREE HEARTS;So;0;ON;;;;;N;;;;; +1F971;YAWNING FACE;So;0;ON;;;;;N;;;;; +1F972;SMILING FACE WITH TEAR;So;0;ON;;;;;N;;;;; +1F973;FACE WITH PARTY HORN AND PARTY HAT;So;0;ON;;;;;N;;;;; +1F974;FACE WITH UNEVEN EYES AND WAVY MOUTH;So;0;ON;;;;;N;;;;; +1F975;OVERHEATED FACE;So;0;ON;;;;;N;;;;; +1F976;FREEZING FACE;So;0;ON;;;;;N;;;;; +1F977;NINJA;So;0;ON;;;;;N;;;;; +1F978;DISGUISED FACE;So;0;ON;;;;;N;;;;; +1F979;FACE HOLDING BACK TEARS;So;0;ON;;;;;N;;;;; +1F97A;FACE WITH PLEADING EYES;So;0;ON;;;;;N;;;;; +1F97B;SARI;So;0;ON;;;;;N;;;;; +1F97C;LAB COAT;So;0;ON;;;;;N;;;;; +1F97D;GOGGLES;So;0;ON;;;;;N;;;;; +1F97E;HIKING BOOT;So;0;ON;;;;;N;;;;; +1F97F;FLAT SHOE;So;0;ON;;;;;N;;;;; +1F980;CRAB;So;0;ON;;;;;N;;;;; +1F981;LION FACE;So;0;ON;;;;;N;;;;; +1F982;SCORPION;So;0;ON;;;;;N;;;;; +1F983;TURKEY;So;0;ON;;;;;N;;;;; +1F984;UNICORN FACE;So;0;ON;;;;;N;;;;; +1F985;EAGLE;So;0;ON;;;;;N;;;;; +1F986;DUCK;So;0;ON;;;;;N;;;;; +1F987;BAT;So;0;ON;;;;;N;;;;; +1F988;SHARK;So;0;ON;;;;;N;;;;; +1F989;OWL;So;0;ON;;;;;N;;;;; +1F98A;FOX FACE;So;0;ON;;;;;N;;;;; +1F98B;BUTTERFLY;So;0;ON;;;;;N;;;;; +1F98C;DEER;So;0;ON;;;;;N;;;;; +1F98D;GORILLA;So;0;ON;;;;;N;;;;; +1F98E;LIZARD;So;0;ON;;;;;N;;;;; +1F98F;RHINOCEROS;So;0;ON;;;;;N;;;;; +1F990;SHRIMP;So;0;ON;;;;;N;;;;; +1F991;SQUID;So;0;ON;;;;;N;;;;; +1F992;GIRAFFE FACE;So;0;ON;;;;;N;;;;; +1F993;ZEBRA FACE;So;0;ON;;;;;N;;;;; +1F994;HEDGEHOG;So;0;ON;;;;;N;;;;; +1F995;SAUROPOD;So;0;ON;;;;;N;;;;; +1F996;T-REX;So;0;ON;;;;;N;;;;; +1F997;CRICKET;So;0;ON;;;;;N;;;;; +1F998;KANGAROO;So;0;ON;;;;;N;;;;; +1F999;LLAMA;So;0;ON;;;;;N;;;;; +1F99A;PEACOCK;So;0;ON;;;;;N;;;;; +1F99B;HIPPOPOTAMUS;So;0;ON;;;;;N;;;;; +1F99C;PARROT;So;0;ON;;;;;N;;;;; +1F99D;RACCOON;So;0;ON;;;;;N;;;;; +1F99E;LOBSTER;So;0;ON;;;;;N;;;;; +1F99F;MOSQUITO;So;0;ON;;;;;N;;;;; +1F9A0;MICROBE;So;0;ON;;;;;N;;;;; +1F9A1;BADGER;So;0;ON;;;;;N;;;;; +1F9A2;SWAN;So;0;ON;;;;;N;;;;; +1F9A3;MAMMOTH;So;0;ON;;;;;N;;;;; +1F9A4;DODO;So;0;ON;;;;;N;;;;; +1F9A5;SLOTH;So;0;ON;;;;;N;;;;; +1F9A6;OTTER;So;0;ON;;;;;N;;;;; +1F9A7;ORANGUTAN;So;0;ON;;;;;N;;;;; +1F9A8;SKUNK;So;0;ON;;;;;N;;;;; +1F9A9;FLAMINGO;So;0;ON;;;;;N;;;;; +1F9AA;OYSTER;So;0;ON;;;;;N;;;;; +1F9AB;BEAVER;So;0;ON;;;;;N;;;;; +1F9AC;BISON;So;0;ON;;;;;N;;;;; +1F9AD;SEAL;So;0;ON;;;;;N;;;;; +1F9AE;GUIDE DOG;So;0;ON;;;;;N;;;;; +1F9AF;PROBING CANE;So;0;ON;;;;;N;;;;; +1F9B0;EMOJI COMPONENT RED HAIR;So;0;ON;;;;;N;;;;; +1F9B1;EMOJI COMPONENT CURLY HAIR;So;0;ON;;;;;N;;;;; +1F9B2;EMOJI COMPONENT BALD;So;0;ON;;;;;N;;;;; +1F9B3;EMOJI COMPONENT WHITE HAIR;So;0;ON;;;;;N;;;;; +1F9B4;BONE;So;0;ON;;;;;N;;;;; +1F9B5;LEG;So;0;ON;;;;;N;;;;; +1F9B6;FOOT;So;0;ON;;;;;N;;;;; +1F9B7;TOOTH;So;0;ON;;;;;N;;;;; +1F9B8;SUPERHERO;So;0;ON;;;;;N;;;;; +1F9B9;SUPERVILLAIN;So;0;ON;;;;;N;;;;; +1F9BA;SAFETY VEST;So;0;ON;;;;;N;;;;; +1F9BB;EAR WITH HEARING AID;So;0;ON;;;;;N;;;;; +1F9BC;MOTORIZED WHEELCHAIR;So;0;ON;;;;;N;;;;; +1F9BD;MANUAL WHEELCHAIR;So;0;ON;;;;;N;;;;; +1F9BE;MECHANICAL ARM;So;0;ON;;;;;N;;;;; +1F9BF;MECHANICAL LEG;So;0;ON;;;;;N;;;;; +1F9C0;CHEESE WEDGE;So;0;ON;;;;;N;;;;; +1F9C1;CUPCAKE;So;0;ON;;;;;N;;;;; +1F9C2;SALT SHAKER;So;0;ON;;;;;N;;;;; +1F9C3;BEVERAGE BOX;So;0;ON;;;;;N;;;;; +1F9C4;GARLIC;So;0;ON;;;;;N;;;;; +1F9C5;ONION;So;0;ON;;;;;N;;;;; +1F9C6;FALAFEL;So;0;ON;;;;;N;;;;; +1F9C7;WAFFLE;So;0;ON;;;;;N;;;;; +1F9C8;BUTTER;So;0;ON;;;;;N;;;;; +1F9C9;MATE DRINK;So;0;ON;;;;;N;;;;; +1F9CA;ICE CUBE;So;0;ON;;;;;N;;;;; +1F9CB;BUBBLE TEA;So;0;ON;;;;;N;;;;; +1F9CC;TROLL;So;0;ON;;;;;N;;;;; +1F9CD;STANDING PERSON;So;0;ON;;;;;N;;;;; +1F9CE;KNEELING PERSON;So;0;ON;;;;;N;;;;; +1F9CF;DEAF PERSON;So;0;ON;;;;;N;;;;; +1F9D0;FACE WITH MONOCLE;So;0;ON;;;;;N;;;;; +1F9D1;ADULT;So;0;ON;;;;;N;;;;; +1F9D2;CHILD;So;0;ON;;;;;N;;;;; +1F9D3;OLDER ADULT;So;0;ON;;;;;N;;;;; +1F9D4;BEARDED PERSON;So;0;ON;;;;;N;;;;; +1F9D5;PERSON WITH HEADSCARF;So;0;ON;;;;;N;;;;; +1F9D6;PERSON IN STEAMY ROOM;So;0;ON;;;;;N;;;;; +1F9D7;PERSON CLIMBING;So;0;ON;;;;;N;;;;; +1F9D8;PERSON IN LOTUS POSITION;So;0;ON;;;;;N;;;;; +1F9D9;MAGE;So;0;ON;;;;;N;;;;; +1F9DA;FAIRY;So;0;ON;;;;;N;;;;; +1F9DB;VAMPIRE;So;0;ON;;;;;N;;;;; +1F9DC;MERPERSON;So;0;ON;;;;;N;;;;; +1F9DD;ELF;So;0;ON;;;;;N;;;;; +1F9DE;GENIE;So;0;ON;;;;;N;;;;; +1F9DF;ZOMBIE;So;0;ON;;;;;N;;;;; +1F9E0;BRAIN;So;0;ON;;;;;N;;;;; +1F9E1;ORANGE HEART;So;0;ON;;;;;N;;;;; +1F9E2;BILLED CAP;So;0;ON;;;;;N;;;;; +1F9E3;SCARF;So;0;ON;;;;;N;;;;; +1F9E4;GLOVES;So;0;ON;;;;;N;;;;; +1F9E5;COAT;So;0;ON;;;;;N;;;;; +1F9E6;SOCKS;So;0;ON;;;;;N;;;;; +1F9E7;RED GIFT ENVELOPE;So;0;ON;;;;;N;;;;; +1F9E8;FIRECRACKER;So;0;ON;;;;;N;;;;; +1F9E9;JIGSAW PUZZLE PIECE;So;0;ON;;;;;N;;;;; +1F9EA;TEST TUBE;So;0;ON;;;;;N;;;;; +1F9EB;PETRI DISH;So;0;ON;;;;;N;;;;; +1F9EC;DNA DOUBLE HELIX;So;0;ON;;;;;N;;;;; +1F9ED;COMPASS;So;0;ON;;;;;N;;;;; +1F9EE;ABACUS;So;0;ON;;;;;N;;;;; +1F9EF;FIRE EXTINGUISHER;So;0;ON;;;;;N;;;;; +1F9F0;TOOLBOX;So;0;ON;;;;;N;;;;; +1F9F1;BRICK;So;0;ON;;;;;N;;;;; +1F9F2;MAGNET;So;0;ON;;;;;N;;;;; +1F9F3;LUGGAGE;So;0;ON;;;;;N;;;;; +1F9F4;LOTION BOTTLE;So;0;ON;;;;;N;;;;; +1F9F5;SPOOL OF THREAD;So;0;ON;;;;;N;;;;; +1F9F6;BALL OF YARN;So;0;ON;;;;;N;;;;; +1F9F7;SAFETY PIN;So;0;ON;;;;;N;;;;; +1F9F8;TEDDY BEAR;So;0;ON;;;;;N;;;;; +1F9F9;BROOM;So;0;ON;;;;;N;;;;; +1F9FA;BASKET;So;0;ON;;;;;N;;;;; +1F9FB;ROLL OF PAPER;So;0;ON;;;;;N;;;;; +1F9FC;BAR OF SOAP;So;0;ON;;;;;N;;;;; +1F9FD;SPONGE;So;0;ON;;;;;N;;;;; +1F9FE;RECEIPT;So;0;ON;;;;;N;;;;; +1F9FF;NAZAR AMULET;So;0;ON;;;;;N;;;;; +1FA00;NEUTRAL CHESS KING;So;0;ON;;;;;N;;;;; +1FA01;NEUTRAL CHESS QUEEN;So;0;ON;;;;;N;;;;; +1FA02;NEUTRAL CHESS ROOK;So;0;ON;;;;;N;;;;; +1FA03;NEUTRAL CHESS BISHOP;So;0;ON;;;;;N;;;;; +1FA04;NEUTRAL CHESS KNIGHT;So;0;ON;;;;;N;;;;; +1FA05;NEUTRAL CHESS PAWN;So;0;ON;;;;;N;;;;; +1FA06;WHITE CHESS KNIGHT ROTATED FORTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; +1FA07;BLACK CHESS KNIGHT ROTATED FORTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; +1FA08;NEUTRAL CHESS KNIGHT ROTATED FORTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; +1FA09;WHITE CHESS KING ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA0A;WHITE CHESS QUEEN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA0B;WHITE CHESS ROOK ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA0C;WHITE CHESS BISHOP ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA0D;WHITE CHESS KNIGHT ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA0E;WHITE CHESS PAWN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA0F;BLACK CHESS KING ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA10;BLACK CHESS QUEEN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA11;BLACK CHESS ROOK ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA12;BLACK CHESS BISHOP ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA13;BLACK CHESS KNIGHT ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA14;BLACK CHESS PAWN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA15;NEUTRAL CHESS KING ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA16;NEUTRAL CHESS QUEEN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA17;NEUTRAL CHESS ROOK ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA18;NEUTRAL CHESS BISHOP ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA19;NEUTRAL CHESS KNIGHT ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA1A;NEUTRAL CHESS PAWN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA1B;WHITE CHESS KNIGHT ROTATED ONE HUNDRED THIRTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; +1FA1C;BLACK CHESS KNIGHT ROTATED ONE HUNDRED THIRTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; +1FA1D;NEUTRAL CHESS KNIGHT ROTATED ONE HUNDRED THIRTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; +1FA1E;WHITE CHESS TURNED KING;So;0;ON;;;;;N;;;;; +1FA1F;WHITE CHESS TURNED QUEEN;So;0;ON;;;;;N;;;;; +1FA20;WHITE CHESS TURNED ROOK;So;0;ON;;;;;N;;;;; +1FA21;WHITE CHESS TURNED BISHOP;So;0;ON;;;;;N;;;;; +1FA22;WHITE CHESS TURNED KNIGHT;So;0;ON;;;;;N;;;;; +1FA23;WHITE CHESS TURNED PAWN;So;0;ON;;;;;N;;;;; +1FA24;BLACK CHESS TURNED KING;So;0;ON;;;;;N;;;;; +1FA25;BLACK CHESS TURNED QUEEN;So;0;ON;;;;;N;;;;; +1FA26;BLACK CHESS TURNED ROOK;So;0;ON;;;;;N;;;;; +1FA27;BLACK CHESS TURNED BISHOP;So;0;ON;;;;;N;;;;; +1FA28;BLACK CHESS TURNED KNIGHT;So;0;ON;;;;;N;;;;; +1FA29;BLACK CHESS TURNED PAWN;So;0;ON;;;;;N;;;;; +1FA2A;NEUTRAL CHESS TURNED KING;So;0;ON;;;;;N;;;;; +1FA2B;NEUTRAL CHESS TURNED QUEEN;So;0;ON;;;;;N;;;;; +1FA2C;NEUTRAL CHESS TURNED ROOK;So;0;ON;;;;;N;;;;; +1FA2D;NEUTRAL CHESS TURNED BISHOP;So;0;ON;;;;;N;;;;; +1FA2E;NEUTRAL CHESS TURNED KNIGHT;So;0;ON;;;;;N;;;;; +1FA2F;NEUTRAL CHESS TURNED PAWN;So;0;ON;;;;;N;;;;; +1FA30;WHITE CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; +1FA31;BLACK CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; +1FA32;NEUTRAL CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; +1FA33;WHITE CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA34;WHITE CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA35;WHITE CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA36;WHITE CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA37;WHITE CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA38;WHITE CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA39;BLACK CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA3A;BLACK CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA3B;BLACK CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA3C;BLACK CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA3D;BLACK CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA3E;BLACK CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA3F;NEUTRAL CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA40;NEUTRAL CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA41;NEUTRAL CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA42;NEUTRAL CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA43;NEUTRAL CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA44;NEUTRAL CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; +1FA45;WHITE CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREES;So;0;ON;;;;;N;;;;; +1FA46;BLACK CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREES;So;0;ON;;;;;N;;;;; +1FA47;NEUTRAL CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREES;So;0;ON;;;;;N;;;;; +1FA48;WHITE CHESS EQUIHOPPER;So;0;ON;;;;;N;;;;; +1FA49;BLACK CHESS EQUIHOPPER;So;0;ON;;;;;N;;;;; +1FA4A;NEUTRAL CHESS EQUIHOPPER;So;0;ON;;;;;N;;;;; +1FA4B;WHITE CHESS EQUIHOPPER ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA4C;BLACK CHESS EQUIHOPPER ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA4D;NEUTRAL CHESS EQUIHOPPER ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; +1FA4E;WHITE CHESS KNIGHT-QUEEN;So;0;ON;;;;;N;;;;; +1FA4F;WHITE CHESS KNIGHT-ROOK;So;0;ON;;;;;N;;;;; +1FA50;WHITE CHESS KNIGHT-BISHOP;So;0;ON;;;;;N;;;;; +1FA51;BLACK CHESS KNIGHT-QUEEN;So;0;ON;;;;;N;;;;; +1FA52;BLACK CHESS KNIGHT-ROOK;So;0;ON;;;;;N;;;;; +1FA53;BLACK CHESS KNIGHT-BISHOP;So;0;ON;;;;;N;;;;; +1FA54;WHITE CHESS FERZ;So;0;ON;;;;;N;;;;; +1FA55;WHITE CHESS ALFIL;So;0;ON;;;;;N;;;;; +1FA56;BLACK CHESS FERZ;So;0;ON;;;;;N;;;;; +1FA57;BLACK CHESS ALFIL;So;0;ON;;;;;N;;;;; +1FA60;XIANGQI RED GENERAL;So;0;ON;;;;;N;;;;; +1FA61;XIANGQI RED MANDARIN;So;0;ON;;;;;N;;;;; +1FA62;XIANGQI RED ELEPHANT;So;0;ON;;;;;N;;;;; +1FA63;XIANGQI RED HORSE;So;0;ON;;;;;N;;;;; +1FA64;XIANGQI RED CHARIOT;So;0;ON;;;;;N;;;;; +1FA65;XIANGQI RED CANNON;So;0;ON;;;;;N;;;;; +1FA66;XIANGQI RED SOLDIER;So;0;ON;;;;;N;;;;; +1FA67;XIANGQI BLACK GENERAL;So;0;ON;;;;;N;;;;; +1FA68;XIANGQI BLACK MANDARIN;So;0;ON;;;;;N;;;;; +1FA69;XIANGQI BLACK ELEPHANT;So;0;ON;;;;;N;;;;; +1FA6A;XIANGQI BLACK HORSE;So;0;ON;;;;;N;;;;; +1FA6B;XIANGQI BLACK CHARIOT;So;0;ON;;;;;N;;;;; +1FA6C;XIANGQI BLACK CANNON;So;0;ON;;;;;N;;;;; +1FA6D;XIANGQI BLACK SOLDIER;So;0;ON;;;;;N;;;;; +1FA70;BALLET SHOES;So;0;ON;;;;;N;;;;; +1FA71;ONE-PIECE SWIMSUIT;So;0;ON;;;;;N;;;;; +1FA72;BRIEFS;So;0;ON;;;;;N;;;;; +1FA73;SHORTS;So;0;ON;;;;;N;;;;; +1FA74;THONG SANDAL;So;0;ON;;;;;N;;;;; +1FA75;LIGHT BLUE HEART;So;0;ON;;;;;N;;;;; +1FA76;GREY HEART;So;0;ON;;;;;N;;;;; +1FA77;PINK HEART;So;0;ON;;;;;N;;;;; +1FA78;DROP OF BLOOD;So;0;ON;;;;;N;;;;; +1FA79;ADHESIVE BANDAGE;So;0;ON;;;;;N;;;;; +1FA7A;STETHOSCOPE;So;0;ON;;;;;N;;;;; +1FA7B;X-RAY;So;0;ON;;;;;N;;;;; +1FA7C;CRUTCH;So;0;ON;;;;;N;;;;; +1FA80;YO-YO;So;0;ON;;;;;N;;;;; +1FA81;KITE;So;0;ON;;;;;N;;;;; +1FA82;PARACHUTE;So;0;ON;;;;;N;;;;; +1FA83;BOOMERANG;So;0;ON;;;;;N;;;;; +1FA84;MAGIC WAND;So;0;ON;;;;;N;;;;; +1FA85;PINATA;So;0;ON;;;;;N;;;;; +1FA86;NESTING DOLLS;So;0;ON;;;;;N;;;;; +1FA87;MARACAS;So;0;ON;;;;;N;;;;; +1FA88;FLUTE;So;0;ON;;;;;N;;;;; +1FA89;HARP;So;0;ON;;;;;N;;;;; +1FA8A;TROMBONE;So;0;ON;;;;;N;;;;; +1FA8E;TREASURE CHEST;So;0;ON;;;;;N;;;;; +1FA8F;SHOVEL;So;0;ON;;;;;N;;;;; +1FA90;RINGED PLANET;So;0;ON;;;;;N;;;;; +1FA91;CHAIR;So;0;ON;;;;;N;;;;; +1FA92;RAZOR;So;0;ON;;;;;N;;;;; +1FA93;AXE;So;0;ON;;;;;N;;;;; +1FA94;DIYA LAMP;So;0;ON;;;;;N;;;;; +1FA95;BANJO;So;0;ON;;;;;N;;;;; +1FA96;MILITARY HELMET;So;0;ON;;;;;N;;;;; +1FA97;ACCORDION;So;0;ON;;;;;N;;;;; +1FA98;LONG DRUM;So;0;ON;;;;;N;;;;; +1FA99;COIN;So;0;ON;;;;;N;;;;; +1FA9A;CARPENTRY SAW;So;0;ON;;;;;N;;;;; +1FA9B;SCREWDRIVER;So;0;ON;;;;;N;;;;; +1FA9C;LADDER;So;0;ON;;;;;N;;;;; +1FA9D;HOOK;So;0;ON;;;;;N;;;;; +1FA9E;MIRROR;So;0;ON;;;;;N;;;;; +1FA9F;WINDOW;So;0;ON;;;;;N;;;;; +1FAA0;PLUNGER;So;0;ON;;;;;N;;;;; +1FAA1;SEWING NEEDLE;So;0;ON;;;;;N;;;;; +1FAA2;KNOT;So;0;ON;;;;;N;;;;; +1FAA3;BUCKET;So;0;ON;;;;;N;;;;; +1FAA4;MOUSE TRAP;So;0;ON;;;;;N;;;;; +1FAA5;TOOTHBRUSH;So;0;ON;;;;;N;;;;; +1FAA6;HEADSTONE;So;0;ON;;;;;N;;;;; +1FAA7;PLACARD;So;0;ON;;;;;N;;;;; +1FAA8;ROCK;So;0;ON;;;;;N;;;;; +1FAA9;MIRROR BALL;So;0;ON;;;;;N;;;;; +1FAAA;IDENTIFICATION CARD;So;0;ON;;;;;N;;;;; +1FAAB;LOW BATTERY;So;0;ON;;;;;N;;;;; +1FAAC;HAMSA;So;0;ON;;;;;N;;;;; +1FAAD;FOLDING HAND FAN;So;0;ON;;;;;N;;;;; +1FAAE;HAIR PICK;So;0;ON;;;;;N;;;;; +1FAAF;KHANDA;So;0;ON;;;;;N;;;;; +1FAB0;FLY;So;0;ON;;;;;N;;;;; +1FAB1;WORM;So;0;ON;;;;;N;;;;; +1FAB2;BEETLE;So;0;ON;;;;;N;;;;; +1FAB3;COCKROACH;So;0;ON;;;;;N;;;;; +1FAB4;POTTED PLANT;So;0;ON;;;;;N;;;;; +1FAB5;WOOD;So;0;ON;;;;;N;;;;; +1FAB6;FEATHER;So;0;ON;;;;;N;;;;; +1FAB7;LOTUS;So;0;ON;;;;;N;;;;; +1FAB8;CORAL;So;0;ON;;;;;N;;;;; +1FAB9;EMPTY NEST;So;0;ON;;;;;N;;;;; +1FABA;NEST WITH EGGS;So;0;ON;;;;;N;;;;; +1FABB;HYACINTH;So;0;ON;;;;;N;;;;; +1FABC;JELLYFISH;So;0;ON;;;;;N;;;;; +1FABD;WING;So;0;ON;;;;;N;;;;; +1FABE;LEAFLESS TREE;So;0;ON;;;;;N;;;;; +1FABF;GOOSE;So;0;ON;;;;;N;;;;; +1FAC0;ANATOMICAL HEART;So;0;ON;;;;;N;;;;; +1FAC1;LUNGS;So;0;ON;;;;;N;;;;; +1FAC2;PEOPLE HUGGING;So;0;ON;;;;;N;;;;; +1FAC3;PREGNANT MAN;So;0;ON;;;;;N;;;;; +1FAC4;PREGNANT PERSON;So;0;ON;;;;;N;;;;; +1FAC5;PERSON WITH CROWN;So;0;ON;;;;;N;;;;; +1FAC6;FINGERPRINT;So;0;ON;;;;;N;;;;; +1FAC8;HAIRY CREATURE;So;0;ON;;;;;N;;;;; +1FACD;ORCA;So;0;ON;;;;;N;;;;; +1FACE;MOOSE;So;0;ON;;;;;N;;;;; +1FACF;DONKEY;So;0;ON;;;;;N;;;;; +1FAD0;BLUEBERRIES;So;0;ON;;;;;N;;;;; +1FAD1;BELL PEPPER;So;0;ON;;;;;N;;;;; +1FAD2;OLIVE;So;0;ON;;;;;N;;;;; +1FAD3;FLATBREAD;So;0;ON;;;;;N;;;;; +1FAD4;TAMALE;So;0;ON;;;;;N;;;;; +1FAD5;FONDUE;So;0;ON;;;;;N;;;;; +1FAD6;TEAPOT;So;0;ON;;;;;N;;;;; +1FAD7;POURING LIQUID;So;0;ON;;;;;N;;;;; +1FAD8;BEANS;So;0;ON;;;;;N;;;;; +1FAD9;JAR;So;0;ON;;;;;N;;;;; +1FADA;GINGER ROOT;So;0;ON;;;;;N;;;;; +1FADB;PEA POD;So;0;ON;;;;;N;;;;; +1FADC;ROOT VEGETABLE;So;0;ON;;;;;N;;;;; +1FADF;SPLATTER;So;0;ON;;;;;N;;;;; +1FAE0;MELTING FACE;So;0;ON;;;;;N;;;;; +1FAE1;SALUTING FACE;So;0;ON;;;;;N;;;;; +1FAE2;FACE WITH OPEN EYES AND HAND OVER MOUTH;So;0;ON;;;;;N;;;;; +1FAE3;FACE WITH PEEKING EYE;So;0;ON;;;;;N;;;;; +1FAE4;FACE WITH DIAGONAL MOUTH;So;0;ON;;;;;N;;;;; +1FAE5;DOTTED LINE FACE;So;0;ON;;;;;N;;;;; +1FAE6;BITING LIP;So;0;ON;;;;;N;;;;; +1FAE7;BUBBLES;So;0;ON;;;;;N;;;;; +1FAE8;SHAKING FACE;So;0;ON;;;;;N;;;;; +1FAE9;FACE WITH BAGS UNDER EYES;So;0;ON;;;;;N;;;;; +1FAEA;DISTORTED FACE;So;0;ON;;;;;N;;;;; +1FAEF;FIGHT CLOUD;So;0;ON;;;;;N;;;;; +1FAF0;HAND WITH INDEX FINGER AND THUMB CROSSED;So;0;ON;;;;;N;;;;; +1FAF1;RIGHTWARDS HAND;So;0;ON;;;;;N;;;;; +1FAF2;LEFTWARDS HAND;So;0;ON;;;;;N;;;;; +1FAF3;PALM DOWN HAND;So;0;ON;;;;;N;;;;; +1FAF4;PALM UP HAND;So;0;ON;;;;;N;;;;; +1FAF5;INDEX POINTING AT THE VIEWER;So;0;ON;;;;;N;;;;; +1FAF6;HEART HANDS;So;0;ON;;;;;N;;;;; +1FAF7;LEFTWARDS PUSHING HAND;So;0;ON;;;;;N;;;;; +1FAF8;RIGHTWARDS PUSHING HAND;So;0;ON;;;;;N;;;;; +1FB00;BLOCK SEXTANT-1;So;0;ON;;;;;N;;;;; +1FB01;BLOCK SEXTANT-2;So;0;ON;;;;;N;;;;; +1FB02;BLOCK SEXTANT-12;So;0;ON;;;;;N;;;;; +1FB03;BLOCK SEXTANT-3;So;0;ON;;;;;N;;;;; +1FB04;BLOCK SEXTANT-13;So;0;ON;;;;;N;;;;; +1FB05;BLOCK SEXTANT-23;So;0;ON;;;;;N;;;;; +1FB06;BLOCK SEXTANT-123;So;0;ON;;;;;N;;;;; +1FB07;BLOCK SEXTANT-4;So;0;ON;;;;;N;;;;; +1FB08;BLOCK SEXTANT-14;So;0;ON;;;;;N;;;;; +1FB09;BLOCK SEXTANT-24;So;0;ON;;;;;N;;;;; +1FB0A;BLOCK SEXTANT-124;So;0;ON;;;;;N;;;;; +1FB0B;BLOCK SEXTANT-34;So;0;ON;;;;;N;;;;; +1FB0C;BLOCK SEXTANT-134;So;0;ON;;;;;N;;;;; +1FB0D;BLOCK SEXTANT-234;So;0;ON;;;;;N;;;;; +1FB0E;BLOCK SEXTANT-1234;So;0;ON;;;;;N;;;;; +1FB0F;BLOCK SEXTANT-5;So;0;ON;;;;;N;;;;; +1FB10;BLOCK SEXTANT-15;So;0;ON;;;;;N;;;;; +1FB11;BLOCK SEXTANT-25;So;0;ON;;;;;N;;;;; +1FB12;BLOCK SEXTANT-125;So;0;ON;;;;;N;;;;; +1FB13;BLOCK SEXTANT-35;So;0;ON;;;;;N;;;;; +1FB14;BLOCK SEXTANT-235;So;0;ON;;;;;N;;;;; +1FB15;BLOCK SEXTANT-1235;So;0;ON;;;;;N;;;;; +1FB16;BLOCK SEXTANT-45;So;0;ON;;;;;N;;;;; +1FB17;BLOCK SEXTANT-145;So;0;ON;;;;;N;;;;; +1FB18;BLOCK SEXTANT-245;So;0;ON;;;;;N;;;;; +1FB19;BLOCK SEXTANT-1245;So;0;ON;;;;;N;;;;; +1FB1A;BLOCK SEXTANT-345;So;0;ON;;;;;N;;;;; +1FB1B;BLOCK SEXTANT-1345;So;0;ON;;;;;N;;;;; +1FB1C;BLOCK SEXTANT-2345;So;0;ON;;;;;N;;;;; +1FB1D;BLOCK SEXTANT-12345;So;0;ON;;;;;N;;;;; +1FB1E;BLOCK SEXTANT-6;So;0;ON;;;;;N;;;;; +1FB1F;BLOCK SEXTANT-16;So;0;ON;;;;;N;;;;; +1FB20;BLOCK SEXTANT-26;So;0;ON;;;;;N;;;;; +1FB21;BLOCK SEXTANT-126;So;0;ON;;;;;N;;;;; +1FB22;BLOCK SEXTANT-36;So;0;ON;;;;;N;;;;; +1FB23;BLOCK SEXTANT-136;So;0;ON;;;;;N;;;;; +1FB24;BLOCK SEXTANT-236;So;0;ON;;;;;N;;;;; +1FB25;BLOCK SEXTANT-1236;So;0;ON;;;;;N;;;;; +1FB26;BLOCK SEXTANT-46;So;0;ON;;;;;N;;;;; +1FB27;BLOCK SEXTANT-146;So;0;ON;;;;;N;;;;; +1FB28;BLOCK SEXTANT-1246;So;0;ON;;;;;N;;;;; +1FB29;BLOCK SEXTANT-346;So;0;ON;;;;;N;;;;; +1FB2A;BLOCK SEXTANT-1346;So;0;ON;;;;;N;;;;; +1FB2B;BLOCK SEXTANT-2346;So;0;ON;;;;;N;;;;; +1FB2C;BLOCK SEXTANT-12346;So;0;ON;;;;;N;;;;; +1FB2D;BLOCK SEXTANT-56;So;0;ON;;;;;N;;;;; +1FB2E;BLOCK SEXTANT-156;So;0;ON;;;;;N;;;;; +1FB2F;BLOCK SEXTANT-256;So;0;ON;;;;;N;;;;; +1FB30;BLOCK SEXTANT-1256;So;0;ON;;;;;N;;;;; +1FB31;BLOCK SEXTANT-356;So;0;ON;;;;;N;;;;; +1FB32;BLOCK SEXTANT-1356;So;0;ON;;;;;N;;;;; +1FB33;BLOCK SEXTANT-2356;So;0;ON;;;;;N;;;;; +1FB34;BLOCK SEXTANT-12356;So;0;ON;;;;;N;;;;; +1FB35;BLOCK SEXTANT-456;So;0;ON;;;;;N;;;;; +1FB36;BLOCK SEXTANT-1456;So;0;ON;;;;;N;;;;; +1FB37;BLOCK SEXTANT-2456;So;0;ON;;;;;N;;;;; +1FB38;BLOCK SEXTANT-12456;So;0;ON;;;;;N;;;;; +1FB39;BLOCK SEXTANT-3456;So;0;ON;;;;;N;;;;; +1FB3A;BLOCK SEXTANT-13456;So;0;ON;;;;;N;;;;; +1FB3B;BLOCK SEXTANT-23456;So;0;ON;;;;;N;;;;; +1FB3C;LOWER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FB3D;LOWER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;; +1FB3E;LOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FB3F;LOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;; +1FB40;LOWER LEFT BLOCK DIAGONAL UPPER LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FB41;LOWER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;; +1FB42;LOWER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER RIGHT;So;0;ON;;;;;N;;;;; +1FB43;LOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;; +1FB44;LOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER RIGHT;So;0;ON;;;;;N;;;;; +1FB45;LOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;; +1FB46;LOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB47;LOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB48;LOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB49;LOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB4A;LOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB4B;LOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO UPPER RIGHT;So;0;ON;;;;;N;;;;; +1FB4C;LOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB4D;LOWER LEFT BLOCK DIAGONAL UPPER LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB4E;LOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB4F;LOWER LEFT BLOCK DIAGONAL UPPER LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB50;LOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;; +1FB51;LOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB52;UPPER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FB53;UPPER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;; +1FB54;UPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FB55;UPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;; +1FB56;UPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FB57;UPPER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;; +1FB58;UPPER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER RIGHT;So;0;ON;;;;;N;;;;; +1FB59;UPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;; +1FB5A;UPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER RIGHT;So;0;ON;;;;;N;;;;; +1FB5B;UPPER LEFT BLOCK DIAGONAL LOWER LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;; +1FB5C;UPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB5D;UPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB5E;UPPER LEFT BLOCK DIAGONAL LOWER LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB5F;UPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB60;UPPER LEFT BLOCK DIAGONAL LOWER LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB61;UPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO UPPER RIGHT;So;0;ON;;;;;N;;;;; +1FB62;UPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB63;UPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB64;UPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB65;UPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB66;UPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;; +1FB67;UPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FB68;UPPER AND RIGHT AND LOWER TRIANGULAR THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;; +1FB69;LEFT AND LOWER AND RIGHT TRIANGULAR THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;; +1FB6A;UPPER AND LEFT AND LOWER TRIANGULAR THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;; +1FB6B;LEFT AND UPPER AND RIGHT TRIANGULAR THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;; +1FB6C;LEFT TRIANGULAR ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1FB6D;UPPER TRIANGULAR ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1FB6E;RIGHT TRIANGULAR ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1FB6F;LOWER TRIANGULAR ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1FB70;VERTICAL ONE EIGHTH BLOCK-2;So;0;ON;;;;;N;;;;; +1FB71;VERTICAL ONE EIGHTH BLOCK-3;So;0;ON;;;;;N;;;;; +1FB72;VERTICAL ONE EIGHTH BLOCK-4;So;0;ON;;;;;N;;;;; +1FB73;VERTICAL ONE EIGHTH BLOCK-5;So;0;ON;;;;;N;;;;; +1FB74;VERTICAL ONE EIGHTH BLOCK-6;So;0;ON;;;;;N;;;;; +1FB75;VERTICAL ONE EIGHTH BLOCK-7;So;0;ON;;;;;N;;;;; +1FB76;HORIZONTAL ONE EIGHTH BLOCK-2;So;0;ON;;;;;N;;;;; +1FB77;HORIZONTAL ONE EIGHTH BLOCK-3;So;0;ON;;;;;N;;;;; +1FB78;HORIZONTAL ONE EIGHTH BLOCK-4;So;0;ON;;;;;N;;;;; +1FB79;HORIZONTAL ONE EIGHTH BLOCK-5;So;0;ON;;;;;N;;;;; +1FB7A;HORIZONTAL ONE EIGHTH BLOCK-6;So;0;ON;;;;;N;;;;; +1FB7B;HORIZONTAL ONE EIGHTH BLOCK-7;So;0;ON;;;;;N;;;;; +1FB7C;LEFT AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +1FB7D;LEFT AND UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +1FB7E;RIGHT AND UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +1FB7F;RIGHT AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +1FB80;UPPER AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +1FB81;HORIZONTAL ONE EIGHTH BLOCK-1358;So;0;ON;;;;;N;;;;; +1FB82;UPPER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1FB83;UPPER THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +1FB84;UPPER FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +1FB85;UPPER THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;; +1FB86;UPPER SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +1FB87;RIGHT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1FB88;RIGHT THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +1FB89;RIGHT FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +1FB8A;RIGHT THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;; +1FB8B;RIGHT SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +1FB8C;LEFT HALF MEDIUM SHADE;So;0;ON;;;;;N;;;;; +1FB8D;RIGHT HALF MEDIUM SHADE;So;0;ON;;;;;N;;;;; +1FB8E;UPPER HALF MEDIUM SHADE;So;0;ON;;;;;N;;;;; +1FB8F;LOWER HALF MEDIUM SHADE;So;0;ON;;;;;N;;;;; +1FB90;INVERSE MEDIUM SHADE;So;0;ON;;;;;N;;;;; +1FB91;UPPER HALF BLOCK AND LOWER HALF INVERSE MEDIUM SHADE;So;0;ON;;;;;N;;;;; +1FB92;UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK;So;0;ON;;;;;N;;;;; +1FB94;LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK;So;0;ON;;;;;N;;;;; +1FB95;CHECKER BOARD FILL;So;0;ON;;;;;N;;;;; +1FB96;INVERSE CHECKER BOARD FILL;So;0;ON;;;;;N;;;;; +1FB97;HEAVY HORIZONTAL FILL;So;0;ON;;;;;N;;;;; +1FB98;UPPER LEFT TO LOWER RIGHT FILL;So;0;ON;;;;;N;;;;; +1FB99;UPPER RIGHT TO LOWER LEFT FILL;So;0;ON;;;;;N;;;;; +1FB9A;UPPER AND LOWER TRIANGULAR HALF BLOCK;So;0;ON;;;;;N;;;;; +1FB9B;LEFT AND RIGHT TRIANGULAR HALF BLOCK;So;0;ON;;;;;N;;;;; +1FB9C;UPPER LEFT TRIANGULAR MEDIUM SHADE;So;0;ON;;;;;N;;;;; +1FB9D;UPPER RIGHT TRIANGULAR MEDIUM SHADE;So;0;ON;;;;;N;;;;; +1FB9E;LOWER RIGHT TRIANGULAR MEDIUM SHADE;So;0;ON;;;;;N;;;;; +1FB9F;LOWER LEFT TRIANGULAR MEDIUM SHADE;So;0;ON;;;;;N;;;;; +1FBA0;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT;So;0;ON;;;;;N;;;;; +1FBA1;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FBA2;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FBA3;BOX DRAWINGS LIGHT DIAGONAL MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FBA4;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FBA5;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FBA6;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO LOWER CENTRE TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FBA7;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO UPPER CENTRE TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FBA8;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT AND MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FBA9;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT AND MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FBAA;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTRE TO MIDDLE LEFT;So;0;ON;;;;;N;;;;; +1FBAB;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTRE TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FBAC;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FBAD;BOX DRAWINGS LIGHT DIAGONAL MIDDLE RIGHT TO UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FBAE;BOX DRAWINGS LIGHT DIAGONAL DIAMOND;So;0;ON;;;;;N;;;;; +1FBAF;BOX DRAWINGS LIGHT HORIZONTAL WITH VERTICAL STROKE;So;0;ON;;;;;N;;;;; +1FBB0;ARROWHEAD-SHAPED POINTER;So;0;ON;;;;;N;;;;; +1FBB1;INVERSE CHECK MARK;So;0;ON;;;;;N;;;;; +1FBB2;LEFT HALF RUNNING MAN;So;0;ON;;;;;N;;;;; +1FBB3;RIGHT HALF RUNNING MAN;So;0;ON;;;;;N;;;;; +1FBB4;INVERSE DOWNWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;;;;; +1FBB5;LEFTWARDS ARROW AND UPPER AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +1FBB6;RIGHTWARDS ARROW AND UPPER AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +1FBB7;DOWNWARDS ARROW AND RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +1FBB8;UPWARDS ARROW AND RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +1FBB9;LEFT HALF FOLDER;So;0;ON;;;;;N;;;;; +1FBBA;RIGHT HALF FOLDER;So;0;ON;;;;;N;;;;; +1FBBB;VOIDED GREEK CROSS;So;0;ON;;;;;N;;;;; +1FBBC;RIGHT OPEN SQUARED DOT;So;0;ON;;;;;N;;;;; +1FBBD;NEGATIVE DIAGONAL CROSS;So;0;ON;;;;;N;;;;; +1FBBE;NEGATIVE DIAGONAL MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FBBF;NEGATIVE DIAGONAL DIAMOND;So;0;ON;;;;;N;;;;; +1FBC0;WHITE HEAVY SALTIRE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;; +1FBC1;LEFT THIRD WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; +1FBC2;MIDDLE THIRD WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; +1FBC3;RIGHT THIRD WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; +1FBC4;NEGATIVE SQUARED QUESTION MARK;So;0;ON;;;;;N;;;;; +1FBC5;STICK FIGURE;So;0;ON;;;;;N;;;;; +1FBC6;STICK FIGURE WITH ARMS RAISED;So;0;ON;;;;;N;;;;; +1FBC7;STICK FIGURE LEANING LEFT;So;0;ON;;;;;N;;;;; +1FBC8;STICK FIGURE LEANING RIGHT;So;0;ON;;;;;N;;;;; +1FBC9;STICK FIGURE WITH DRESS;So;0;ON;;;;;N;;;;; +1FBCA;WHITE UP-POINTING CHEVRON;So;0;ON;;;;;N;;;;; +1FBCB;WHITE CROSS MARK;So;0;ON;;;;;N;;;;; +1FBCC;RAISED SMALL LEFT SQUARE BRACKET;So;0;ON;;;;;N;;;;; +1FBCD;BLACK SMALL UP-POINTING CHEVRON;So;0;ON;;;;;N;;;;; +1FBCE;LEFT TWO THIRDS BLOCK;So;0;ON;;;;;N;;;;; +1FBCF;LEFT ONE THIRD BLOCK;So;0;ON;;;;;N;;;;; +1FBD0;BOX DRAWINGS LIGHT DIAGONAL MIDDLE RIGHT TO LOWER LEFT;So;0;ON;;;;;N;;;;; +1FBD1;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO MIDDLE LEFT;So;0;ON;;;;;N;;;;; +1FBD2;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;; +1FBD3;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;; +1FBD4;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FBD5;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;; +1FBD6;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; +1FBD7;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO LOWER LEFT;So;0;ON;;;;;N;;;;; +1FBD8;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO MIDDLE CENTRE TO UPPER RIGHT;So;0;ON;;;;;N;;;;; +1FBD9;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO MIDDLE CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;; +1FBDA;BOX DRAWINGS LIGHT DIAGONAL LOWER LEFT TO MIDDLE CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;; +1FBDB;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO MIDDLE CENTRE TO LOWER LEFT;So;0;ON;;;;;N;;;;; +1FBDC;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER CENTRE TO UPPER RIGHT;So;0;ON;;;;;N;;;;; +1FBDD;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;; +1FBDE;BOX DRAWINGS LIGHT DIAGONAL LOWER LEFT TO UPPER CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;; +1FBDF;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO MIDDLE RIGHT TO LOWER LEFT;So;0;ON;;;;;N;;;;; +1FBE0;TOP JUSTIFIED LOWER HALF WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1FBE1;RIGHT JUSTIFIED LEFT HALF WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1FBE2;BOTTOM JUSTIFIED UPPER HALF WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1FBE3;LEFT JUSTIFIED RIGHT HALF WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1FBE4;UPPER CENTRE ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1FBE5;LOWER CENTRE ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1FBE6;MIDDLE LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1FBE7;MIDDLE RIGHT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +1FBE8;TOP JUSTIFIED LOWER HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; +1FBE9;RIGHT JUSTIFIED LEFT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; +1FBEA;BOTTOM JUSTIFIED UPPER HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; +1FBEB;LEFT JUSTIFIED RIGHT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; +1FBEC;TOP RIGHT JUSTIFIED LOWER LEFT QUARTER BLACK CIRCLE;So;0;ON;;;;;N;;;;; +1FBED;BOTTOM LEFT JUSTIFIED UPPER RIGHT QUARTER BLACK CIRCLE;So;0;ON;;;;;N;;;;; +1FBEE;BOTTOM RIGHT JUSTIFIED UPPER LEFT QUARTER BLACK CIRCLE;So;0;ON;;;;;N;;;;; +1FBEF;TOP LEFT JUSTIFIED LOWER RIGHT QUARTER BLACK CIRCLE;So;0;ON;;;;;N;;;;; +1FBF0;SEGMENTED DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; +1FBF1;SEGMENTED DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; +1FBF2;SEGMENTED DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; +1FBF3;SEGMENTED DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; +1FBF4;SEGMENTED DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; +1FBF5;SEGMENTED DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; +1FBF6;SEGMENTED DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; +1FBF7;SEGMENTED DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; +1FBF8;SEGMENTED DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; +1FBF9;SEGMENTED DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +1FBFA;ALARM BELL SYMBOL;So;0;ON;;;;;N;;;;; +20000;;Lo;0;L;;;;;N;;;;; +2A6DF;;Lo;0;L;;;;;N;;;;; +2A700;;Lo;0;L;;;;;N;;;;; +2B73F;;Lo;0;L;;;;;N;;;;; +2B740;;Lo;0;L;;;;;N;;;;; +2B81D;;Lo;0;L;;;;;N;;;;; +2B820;;Lo;0;L;;;;;N;;;;; +2CEAD;;Lo;0;L;;;;;N;;;;; +2CEB0;;Lo;0;L;;;;;N;;;;; +2EBE0;;Lo;0;L;;;;;N;;;;; +2EBF0;;Lo;0;L;;;;;N;;;;; +2EE5D;;Lo;0;L;;;;;N;;;;; +2F800;CJK COMPATIBILITY IDEOGRAPH-2F800;Lo;0;L;4E3D;;;;N;;;;; +2F801;CJK COMPATIBILITY IDEOGRAPH-2F801;Lo;0;L;4E38;;;;N;;;;; +2F802;CJK COMPATIBILITY IDEOGRAPH-2F802;Lo;0;L;4E41;;;;N;;;;; +2F803;CJK COMPATIBILITY IDEOGRAPH-2F803;Lo;0;L;20122;;;;N;;;;; +2F804;CJK COMPATIBILITY IDEOGRAPH-2F804;Lo;0;L;4F60;;;;N;;;;; +2F805;CJK COMPATIBILITY IDEOGRAPH-2F805;Lo;0;L;4FAE;;;;N;;;;; +2F806;CJK COMPATIBILITY IDEOGRAPH-2F806;Lo;0;L;4FBB;;;;N;;;;; +2F807;CJK COMPATIBILITY IDEOGRAPH-2F807;Lo;0;L;5002;;;;N;;;;; +2F808;CJK COMPATIBILITY IDEOGRAPH-2F808;Lo;0;L;507A;;;;N;;;;; +2F809;CJK COMPATIBILITY IDEOGRAPH-2F809;Lo;0;L;5099;;;;N;;;;; +2F80A;CJK COMPATIBILITY IDEOGRAPH-2F80A;Lo;0;L;50E7;;;;N;;;;; +2F80B;CJK COMPATIBILITY IDEOGRAPH-2F80B;Lo;0;L;50CF;;;;N;;;;; +2F80C;CJK COMPATIBILITY IDEOGRAPH-2F80C;Lo;0;L;349E;;;;N;;;;; +2F80D;CJK COMPATIBILITY IDEOGRAPH-2F80D;Lo;0;L;2063A;;;;N;;;;; +2F80E;CJK COMPATIBILITY IDEOGRAPH-2F80E;Lo;0;L;514D;;;;N;;;;; +2F80F;CJK COMPATIBILITY IDEOGRAPH-2F80F;Lo;0;L;5154;;;;N;;;;; +2F810;CJK COMPATIBILITY IDEOGRAPH-2F810;Lo;0;L;5164;;;;N;;;;; +2F811;CJK COMPATIBILITY IDEOGRAPH-2F811;Lo;0;L;5177;;;;N;;;;; +2F812;CJK COMPATIBILITY IDEOGRAPH-2F812;Lo;0;L;2051C;;;;N;;;;; +2F813;CJK COMPATIBILITY IDEOGRAPH-2F813;Lo;0;L;34B9;;;;N;;;;; +2F814;CJK COMPATIBILITY IDEOGRAPH-2F814;Lo;0;L;5167;;;;N;;;;; +2F815;CJK COMPATIBILITY IDEOGRAPH-2F815;Lo;0;L;518D;;;;N;;;;; +2F816;CJK COMPATIBILITY IDEOGRAPH-2F816;Lo;0;L;2054B;;;;N;;;;; +2F817;CJK COMPATIBILITY IDEOGRAPH-2F817;Lo;0;L;5197;;;;N;;;;; +2F818;CJK COMPATIBILITY IDEOGRAPH-2F818;Lo;0;L;51A4;;;;N;;;;; +2F819;CJK COMPATIBILITY IDEOGRAPH-2F819;Lo;0;L;4ECC;;;;N;;;;; +2F81A;CJK COMPATIBILITY IDEOGRAPH-2F81A;Lo;0;L;51AC;;;;N;;;;; +2F81B;CJK COMPATIBILITY IDEOGRAPH-2F81B;Lo;0;L;51B5;;;;N;;;;; +2F81C;CJK COMPATIBILITY IDEOGRAPH-2F81C;Lo;0;L;291DF;;;;N;;;;; +2F81D;CJK COMPATIBILITY IDEOGRAPH-2F81D;Lo;0;L;51F5;;;;N;;;;; +2F81E;CJK COMPATIBILITY IDEOGRAPH-2F81E;Lo;0;L;5203;;;;N;;;;; +2F81F;CJK COMPATIBILITY IDEOGRAPH-2F81F;Lo;0;L;34DF;;;;N;;;;; +2F820;CJK COMPATIBILITY IDEOGRAPH-2F820;Lo;0;L;523B;;;;N;;;;; +2F821;CJK COMPATIBILITY IDEOGRAPH-2F821;Lo;0;L;5246;;;;N;;;;; +2F822;CJK COMPATIBILITY IDEOGRAPH-2F822;Lo;0;L;5272;;;;N;;;;; +2F823;CJK COMPATIBILITY IDEOGRAPH-2F823;Lo;0;L;5277;;;;N;;;;; +2F824;CJK COMPATIBILITY IDEOGRAPH-2F824;Lo;0;L;3515;;;;N;;;;; +2F825;CJK COMPATIBILITY IDEOGRAPH-2F825;Lo;0;L;52C7;;;;N;;;;; +2F826;CJK COMPATIBILITY IDEOGRAPH-2F826;Lo;0;L;52C9;;;;N;;;;; +2F827;CJK COMPATIBILITY IDEOGRAPH-2F827;Lo;0;L;52E4;;;;N;;;;; +2F828;CJK COMPATIBILITY IDEOGRAPH-2F828;Lo;0;L;52FA;;;;N;;;;; +2F829;CJK COMPATIBILITY IDEOGRAPH-2F829;Lo;0;L;5305;;;;N;;;;; +2F82A;CJK COMPATIBILITY IDEOGRAPH-2F82A;Lo;0;L;5306;;;;N;;;;; +2F82B;CJK COMPATIBILITY IDEOGRAPH-2F82B;Lo;0;L;5317;;;;N;;;;; +2F82C;CJK COMPATIBILITY IDEOGRAPH-2F82C;Lo;0;L;5349;;;;N;;;;; +2F82D;CJK COMPATIBILITY IDEOGRAPH-2F82D;Lo;0;L;5351;;;;N;;;;; +2F82E;CJK COMPATIBILITY IDEOGRAPH-2F82E;Lo;0;L;535A;;;;N;;;;; +2F82F;CJK COMPATIBILITY IDEOGRAPH-2F82F;Lo;0;L;5373;;;;N;;;;; +2F830;CJK COMPATIBILITY IDEOGRAPH-2F830;Lo;0;L;537D;;;;N;;;;; +2F831;CJK COMPATIBILITY IDEOGRAPH-2F831;Lo;0;L;537F;;;;N;;;;; +2F832;CJK COMPATIBILITY IDEOGRAPH-2F832;Lo;0;L;537F;;;;N;;;;; +2F833;CJK COMPATIBILITY IDEOGRAPH-2F833;Lo;0;L;537F;;;;N;;;;; +2F834;CJK COMPATIBILITY IDEOGRAPH-2F834;Lo;0;L;20A2C;;;;N;;;;; +2F835;CJK COMPATIBILITY IDEOGRAPH-2F835;Lo;0;L;7070;;;;N;;;;; +2F836;CJK COMPATIBILITY IDEOGRAPH-2F836;Lo;0;L;53CA;;;;N;;;;; +2F837;CJK COMPATIBILITY IDEOGRAPH-2F837;Lo;0;L;53DF;;;;N;;;;; +2F838;CJK COMPATIBILITY IDEOGRAPH-2F838;Lo;0;L;20B63;;;;N;;;;; +2F839;CJK COMPATIBILITY IDEOGRAPH-2F839;Lo;0;L;53EB;;;;N;;;;; +2F83A;CJK COMPATIBILITY IDEOGRAPH-2F83A;Lo;0;L;53F1;;;;N;;;;; +2F83B;CJK COMPATIBILITY IDEOGRAPH-2F83B;Lo;0;L;5406;;;;N;;;;; +2F83C;CJK COMPATIBILITY IDEOGRAPH-2F83C;Lo;0;L;549E;;;;N;;;;; +2F83D;CJK COMPATIBILITY IDEOGRAPH-2F83D;Lo;0;L;5438;;;;N;;;;; +2F83E;CJK COMPATIBILITY IDEOGRAPH-2F83E;Lo;0;L;5448;;;;N;;;;; +2F83F;CJK COMPATIBILITY IDEOGRAPH-2F83F;Lo;0;L;5468;;;;N;;;;; +2F840;CJK COMPATIBILITY IDEOGRAPH-2F840;Lo;0;L;54A2;;;;N;;;;; +2F841;CJK COMPATIBILITY IDEOGRAPH-2F841;Lo;0;L;54F6;;;;N;;;;; +2F842;CJK COMPATIBILITY IDEOGRAPH-2F842;Lo;0;L;5510;;;;N;;;;; +2F843;CJK COMPATIBILITY IDEOGRAPH-2F843;Lo;0;L;5553;;;;N;;;;; +2F844;CJK COMPATIBILITY IDEOGRAPH-2F844;Lo;0;L;5563;;;;N;;;;; +2F845;CJK COMPATIBILITY IDEOGRAPH-2F845;Lo;0;L;5584;;;;N;;;;; +2F846;CJK COMPATIBILITY IDEOGRAPH-2F846;Lo;0;L;5584;;;;N;;;;; +2F847;CJK COMPATIBILITY IDEOGRAPH-2F847;Lo;0;L;5599;;;;N;;;;; +2F848;CJK COMPATIBILITY IDEOGRAPH-2F848;Lo;0;L;55AB;;;;N;;;;; +2F849;CJK COMPATIBILITY IDEOGRAPH-2F849;Lo;0;L;55B3;;;;N;;;;; +2F84A;CJK COMPATIBILITY IDEOGRAPH-2F84A;Lo;0;L;55C2;;;;N;;;;; +2F84B;CJK COMPATIBILITY IDEOGRAPH-2F84B;Lo;0;L;5716;;;;N;;;;; +2F84C;CJK COMPATIBILITY IDEOGRAPH-2F84C;Lo;0;L;5606;;;;N;;;;; +2F84D;CJK COMPATIBILITY IDEOGRAPH-2F84D;Lo;0;L;5717;;;;N;;;;; +2F84E;CJK COMPATIBILITY IDEOGRAPH-2F84E;Lo;0;L;5651;;;;N;;;;; +2F84F;CJK COMPATIBILITY IDEOGRAPH-2F84F;Lo;0;L;5674;;;;N;;;;; +2F850;CJK COMPATIBILITY IDEOGRAPH-2F850;Lo;0;L;5207;;;;N;;;;; +2F851;CJK COMPATIBILITY IDEOGRAPH-2F851;Lo;0;L;58EE;;;;N;;;;; +2F852;CJK COMPATIBILITY IDEOGRAPH-2F852;Lo;0;L;57CE;;;;N;;;;; +2F853;CJK COMPATIBILITY IDEOGRAPH-2F853;Lo;0;L;57F4;;;;N;;;;; +2F854;CJK COMPATIBILITY IDEOGRAPH-2F854;Lo;0;L;580D;;;;N;;;;; +2F855;CJK COMPATIBILITY IDEOGRAPH-2F855;Lo;0;L;578B;;;;N;;;;; +2F856;CJK COMPATIBILITY IDEOGRAPH-2F856;Lo;0;L;5832;;;;N;;;;; +2F857;CJK COMPATIBILITY IDEOGRAPH-2F857;Lo;0;L;5831;;;;N;;;;; +2F858;CJK COMPATIBILITY IDEOGRAPH-2F858;Lo;0;L;58AC;;;;N;;;;; +2F859;CJK COMPATIBILITY IDEOGRAPH-2F859;Lo;0;L;214E4;;;;N;;;;; +2F85A;CJK COMPATIBILITY IDEOGRAPH-2F85A;Lo;0;L;58F2;;;;N;;;;; +2F85B;CJK COMPATIBILITY IDEOGRAPH-2F85B;Lo;0;L;58F7;;;;N;;;;; +2F85C;CJK COMPATIBILITY IDEOGRAPH-2F85C;Lo;0;L;5906;;;;N;;;;; +2F85D;CJK COMPATIBILITY IDEOGRAPH-2F85D;Lo;0;L;591A;;;;N;;;;; +2F85E;CJK COMPATIBILITY IDEOGRAPH-2F85E;Lo;0;L;5922;;;;N;;;;; +2F85F;CJK COMPATIBILITY IDEOGRAPH-2F85F;Lo;0;L;5962;;;;N;;;;; +2F860;CJK COMPATIBILITY IDEOGRAPH-2F860;Lo;0;L;216A8;;;;N;;;;; +2F861;CJK COMPATIBILITY IDEOGRAPH-2F861;Lo;0;L;216EA;;;;N;;;;; +2F862;CJK COMPATIBILITY IDEOGRAPH-2F862;Lo;0;L;59EC;;;;N;;;;; +2F863;CJK COMPATIBILITY IDEOGRAPH-2F863;Lo;0;L;5A1B;;;;N;;;;; +2F864;CJK COMPATIBILITY IDEOGRAPH-2F864;Lo;0;L;5A27;;;;N;;;;; +2F865;CJK COMPATIBILITY IDEOGRAPH-2F865;Lo;0;L;59D8;;;;N;;;;; +2F866;CJK COMPATIBILITY IDEOGRAPH-2F866;Lo;0;L;5A66;;;;N;;;;; +2F867;CJK COMPATIBILITY IDEOGRAPH-2F867;Lo;0;L;36EE;;;;N;;;;; +2F868;CJK COMPATIBILITY IDEOGRAPH-2F868;Lo;0;L;36FC;;;;N;;;;; +2F869;CJK COMPATIBILITY IDEOGRAPH-2F869;Lo;0;L;5B08;;;;N;;;;; +2F86A;CJK COMPATIBILITY IDEOGRAPH-2F86A;Lo;0;L;5B3E;;;;N;;;;; +2F86B;CJK COMPATIBILITY IDEOGRAPH-2F86B;Lo;0;L;5B3E;;;;N;;;;; +2F86C;CJK COMPATIBILITY IDEOGRAPH-2F86C;Lo;0;L;219C8;;;;N;;;;; +2F86D;CJK COMPATIBILITY IDEOGRAPH-2F86D;Lo;0;L;5BC3;;;;N;;;;; +2F86E;CJK COMPATIBILITY IDEOGRAPH-2F86E;Lo;0;L;5BD8;;;;N;;;;; +2F86F;CJK COMPATIBILITY IDEOGRAPH-2F86F;Lo;0;L;5BE7;;;;N;;;;; +2F870;CJK COMPATIBILITY IDEOGRAPH-2F870;Lo;0;L;5BF3;;;;N;;;;; +2F871;CJK COMPATIBILITY IDEOGRAPH-2F871;Lo;0;L;21B18;;;;N;;;;; +2F872;CJK COMPATIBILITY IDEOGRAPH-2F872;Lo;0;L;5BFF;;;;N;;;;; +2F873;CJK COMPATIBILITY IDEOGRAPH-2F873;Lo;0;L;5C06;;;;N;;;;; +2F874;CJK COMPATIBILITY IDEOGRAPH-2F874;Lo;0;L;5F53;;;;N;;;;; +2F875;CJK COMPATIBILITY IDEOGRAPH-2F875;Lo;0;L;5C22;;;;N;;;;; +2F876;CJK COMPATIBILITY IDEOGRAPH-2F876;Lo;0;L;3781;;;;N;;;;; +2F877;CJK COMPATIBILITY IDEOGRAPH-2F877;Lo;0;L;5C60;;;;N;;;;; +2F878;CJK COMPATIBILITY IDEOGRAPH-2F878;Lo;0;L;5C6E;;;;N;;;;; +2F879;CJK COMPATIBILITY IDEOGRAPH-2F879;Lo;0;L;5CC0;;;;N;;;;; +2F87A;CJK COMPATIBILITY IDEOGRAPH-2F87A;Lo;0;L;5C8D;;;;N;;;;; +2F87B;CJK COMPATIBILITY IDEOGRAPH-2F87B;Lo;0;L;21DE4;;;;N;;;;; +2F87C;CJK COMPATIBILITY IDEOGRAPH-2F87C;Lo;0;L;5D43;;;;N;;;;; +2F87D;CJK COMPATIBILITY IDEOGRAPH-2F87D;Lo;0;L;21DE6;;;;N;;;;; +2F87E;CJK COMPATIBILITY IDEOGRAPH-2F87E;Lo;0;L;5D6E;;;;N;;;;; +2F87F;CJK COMPATIBILITY IDEOGRAPH-2F87F;Lo;0;L;5D6B;;;;N;;;;; +2F880;CJK COMPATIBILITY IDEOGRAPH-2F880;Lo;0;L;5D7C;;;;N;;;;; +2F881;CJK COMPATIBILITY IDEOGRAPH-2F881;Lo;0;L;5DE1;;;;N;;;;; +2F882;CJK COMPATIBILITY IDEOGRAPH-2F882;Lo;0;L;5DE2;;;;N;;;;; +2F883;CJK COMPATIBILITY IDEOGRAPH-2F883;Lo;0;L;382F;;;;N;;;;; +2F884;CJK COMPATIBILITY IDEOGRAPH-2F884;Lo;0;L;5DFD;;;;N;;;;; +2F885;CJK COMPATIBILITY IDEOGRAPH-2F885;Lo;0;L;5E28;;;;N;;;;; +2F886;CJK COMPATIBILITY IDEOGRAPH-2F886;Lo;0;L;5E3D;;;;N;;;;; +2F887;CJK COMPATIBILITY IDEOGRAPH-2F887;Lo;0;L;5E69;;;;N;;;;; +2F888;CJK COMPATIBILITY IDEOGRAPH-2F888;Lo;0;L;3862;;;;N;;;;; +2F889;CJK COMPATIBILITY IDEOGRAPH-2F889;Lo;0;L;22183;;;;N;;;;; +2F88A;CJK COMPATIBILITY IDEOGRAPH-2F88A;Lo;0;L;387C;;;;N;;;;; +2F88B;CJK COMPATIBILITY IDEOGRAPH-2F88B;Lo;0;L;5EB0;;;;N;;;;; +2F88C;CJK COMPATIBILITY IDEOGRAPH-2F88C;Lo;0;L;5EB3;;;;N;;;;; +2F88D;CJK COMPATIBILITY IDEOGRAPH-2F88D;Lo;0;L;5EB6;;;;N;;;;; +2F88E;CJK COMPATIBILITY IDEOGRAPH-2F88E;Lo;0;L;5ECA;;;;N;;;;; +2F88F;CJK COMPATIBILITY IDEOGRAPH-2F88F;Lo;0;L;2A392;;;;N;;;;; +2F890;CJK COMPATIBILITY IDEOGRAPH-2F890;Lo;0;L;5EFE;;;9;N;;;;; +2F891;CJK COMPATIBILITY IDEOGRAPH-2F891;Lo;0;L;22331;;;;N;;;;; +2F892;CJK COMPATIBILITY IDEOGRAPH-2F892;Lo;0;L;22331;;;;N;;;;; +2F893;CJK COMPATIBILITY IDEOGRAPH-2F893;Lo;0;L;8201;;;;N;;;;; +2F894;CJK COMPATIBILITY IDEOGRAPH-2F894;Lo;0;L;5F22;;;;N;;;;; +2F895;CJK COMPATIBILITY IDEOGRAPH-2F895;Lo;0;L;5F22;;;;N;;;;; +2F896;CJK COMPATIBILITY IDEOGRAPH-2F896;Lo;0;L;38C7;;;;N;;;;; +2F897;CJK COMPATIBILITY IDEOGRAPH-2F897;Lo;0;L;232B8;;;;N;;;;; +2F898;CJK COMPATIBILITY IDEOGRAPH-2F898;Lo;0;L;261DA;;;;N;;;;; +2F899;CJK COMPATIBILITY IDEOGRAPH-2F899;Lo;0;L;5F62;;;;N;;;;; +2F89A;CJK COMPATIBILITY IDEOGRAPH-2F89A;Lo;0;L;5F6B;;;;N;;;;; +2F89B;CJK COMPATIBILITY IDEOGRAPH-2F89B;Lo;0;L;38E3;;;;N;;;;; +2F89C;CJK COMPATIBILITY IDEOGRAPH-2F89C;Lo;0;L;5F9A;;;;N;;;;; +2F89D;CJK COMPATIBILITY IDEOGRAPH-2F89D;Lo;0;L;5FCD;;;;N;;;;; +2F89E;CJK COMPATIBILITY IDEOGRAPH-2F89E;Lo;0;L;5FD7;;;;N;;;;; +2F89F;CJK COMPATIBILITY IDEOGRAPH-2F89F;Lo;0;L;5FF9;;;;N;;;;; +2F8A0;CJK COMPATIBILITY IDEOGRAPH-2F8A0;Lo;0;L;6081;;;;N;;;;; +2F8A1;CJK COMPATIBILITY IDEOGRAPH-2F8A1;Lo;0;L;393A;;;;N;;;;; +2F8A2;CJK COMPATIBILITY IDEOGRAPH-2F8A2;Lo;0;L;391C;;;;N;;;;; +2F8A3;CJK COMPATIBILITY IDEOGRAPH-2F8A3;Lo;0;L;6094;;;;N;;;;; +2F8A4;CJK COMPATIBILITY IDEOGRAPH-2F8A4;Lo;0;L;226D4;;;;N;;;;; +2F8A5;CJK COMPATIBILITY IDEOGRAPH-2F8A5;Lo;0;L;60C7;;;;N;;;;; +2F8A6;CJK COMPATIBILITY IDEOGRAPH-2F8A6;Lo;0;L;6148;;;;N;;;;; +2F8A7;CJK COMPATIBILITY IDEOGRAPH-2F8A7;Lo;0;L;614C;;;;N;;;;; +2F8A8;CJK COMPATIBILITY IDEOGRAPH-2F8A8;Lo;0;L;614E;;;;N;;;;; +2F8A9;CJK COMPATIBILITY IDEOGRAPH-2F8A9;Lo;0;L;614C;;;;N;;;;; +2F8AA;CJK COMPATIBILITY IDEOGRAPH-2F8AA;Lo;0;L;617A;;;;N;;;;; +2F8AB;CJK COMPATIBILITY IDEOGRAPH-2F8AB;Lo;0;L;618E;;;;N;;;;; +2F8AC;CJK COMPATIBILITY IDEOGRAPH-2F8AC;Lo;0;L;61B2;;;;N;;;;; +2F8AD;CJK COMPATIBILITY IDEOGRAPH-2F8AD;Lo;0;L;61A4;;;;N;;;;; +2F8AE;CJK COMPATIBILITY IDEOGRAPH-2F8AE;Lo;0;L;61AF;;;;N;;;;; +2F8AF;CJK COMPATIBILITY IDEOGRAPH-2F8AF;Lo;0;L;61DE;;;;N;;;;; +2F8B0;CJK COMPATIBILITY IDEOGRAPH-2F8B0;Lo;0;L;61F2;;;;N;;;;; +2F8B1;CJK COMPATIBILITY IDEOGRAPH-2F8B1;Lo;0;L;61F6;;;;N;;;;; +2F8B2;CJK COMPATIBILITY IDEOGRAPH-2F8B2;Lo;0;L;6210;;;;N;;;;; +2F8B3;CJK COMPATIBILITY IDEOGRAPH-2F8B3;Lo;0;L;621B;;;;N;;;;; +2F8B4;CJK COMPATIBILITY IDEOGRAPH-2F8B4;Lo;0;L;625D;;;;N;;;;; +2F8B5;CJK COMPATIBILITY IDEOGRAPH-2F8B5;Lo;0;L;62B1;;;;N;;;;; +2F8B6;CJK COMPATIBILITY IDEOGRAPH-2F8B6;Lo;0;L;62D4;;;;N;;;;; +2F8B7;CJK COMPATIBILITY IDEOGRAPH-2F8B7;Lo;0;L;6350;;;;N;;;;; +2F8B8;CJK COMPATIBILITY IDEOGRAPH-2F8B8;Lo;0;L;22B0C;;;;N;;;;; +2F8B9;CJK COMPATIBILITY IDEOGRAPH-2F8B9;Lo;0;L;633D;;;;N;;;;; +2F8BA;CJK COMPATIBILITY IDEOGRAPH-2F8BA;Lo;0;L;62FC;;;;N;;;;; +2F8BB;CJK COMPATIBILITY IDEOGRAPH-2F8BB;Lo;0;L;6368;;;;N;;;;; +2F8BC;CJK COMPATIBILITY IDEOGRAPH-2F8BC;Lo;0;L;6383;;;;N;;;;; +2F8BD;CJK COMPATIBILITY IDEOGRAPH-2F8BD;Lo;0;L;63E4;;;;N;;;;; +2F8BE;CJK COMPATIBILITY IDEOGRAPH-2F8BE;Lo;0;L;22BF1;;;;N;;;;; +2F8BF;CJK COMPATIBILITY IDEOGRAPH-2F8BF;Lo;0;L;6422;;;;N;;;;; +2F8C0;CJK COMPATIBILITY IDEOGRAPH-2F8C0;Lo;0;L;63C5;;;;N;;;;; +2F8C1;CJK COMPATIBILITY IDEOGRAPH-2F8C1;Lo;0;L;63A9;;;;N;;;;; +2F8C2;CJK COMPATIBILITY IDEOGRAPH-2F8C2;Lo;0;L;3A2E;;;;N;;;;; +2F8C3;CJK COMPATIBILITY IDEOGRAPH-2F8C3;Lo;0;L;6469;;;;N;;;;; +2F8C4;CJK COMPATIBILITY IDEOGRAPH-2F8C4;Lo;0;L;647E;;;;N;;;;; +2F8C5;CJK COMPATIBILITY IDEOGRAPH-2F8C5;Lo;0;L;649D;;;;N;;;;; +2F8C6;CJK COMPATIBILITY IDEOGRAPH-2F8C6;Lo;0;L;6477;;;;N;;;;; +2F8C7;CJK COMPATIBILITY IDEOGRAPH-2F8C7;Lo;0;L;3A6C;;;;N;;;;; +2F8C8;CJK COMPATIBILITY IDEOGRAPH-2F8C8;Lo;0;L;654F;;;;N;;;;; +2F8C9;CJK COMPATIBILITY IDEOGRAPH-2F8C9;Lo;0;L;656C;;;;N;;;;; +2F8CA;CJK COMPATIBILITY IDEOGRAPH-2F8CA;Lo;0;L;2300A;;;;N;;;;; +2F8CB;CJK COMPATIBILITY IDEOGRAPH-2F8CB;Lo;0;L;65E3;;;;N;;;;; +2F8CC;CJK COMPATIBILITY IDEOGRAPH-2F8CC;Lo;0;L;66F8;;;;N;;;;; +2F8CD;CJK COMPATIBILITY IDEOGRAPH-2F8CD;Lo;0;L;6649;;;;N;;;;; +2F8CE;CJK COMPATIBILITY IDEOGRAPH-2F8CE;Lo;0;L;3B19;;;;N;;;;; +2F8CF;CJK COMPATIBILITY IDEOGRAPH-2F8CF;Lo;0;L;6691;;;;N;;;;; +2F8D0;CJK COMPATIBILITY IDEOGRAPH-2F8D0;Lo;0;L;3B08;;;;N;;;;; +2F8D1;CJK COMPATIBILITY IDEOGRAPH-2F8D1;Lo;0;L;3AE4;;;;N;;;;; +2F8D2;CJK COMPATIBILITY IDEOGRAPH-2F8D2;Lo;0;L;5192;;;;N;;;;; +2F8D3;CJK COMPATIBILITY IDEOGRAPH-2F8D3;Lo;0;L;5195;;;;N;;;;; +2F8D4;CJK COMPATIBILITY IDEOGRAPH-2F8D4;Lo;0;L;6700;;;;N;;;;; +2F8D5;CJK COMPATIBILITY IDEOGRAPH-2F8D5;Lo;0;L;669C;;;;N;;;;; +2F8D6;CJK COMPATIBILITY IDEOGRAPH-2F8D6;Lo;0;L;80AD;;;;N;;;;; +2F8D7;CJK COMPATIBILITY IDEOGRAPH-2F8D7;Lo;0;L;43D9;;;;N;;;;; +2F8D8;CJK COMPATIBILITY IDEOGRAPH-2F8D8;Lo;0;L;6717;;;;N;;;;; +2F8D9;CJK COMPATIBILITY IDEOGRAPH-2F8D9;Lo;0;L;671B;;;;N;;;;; +2F8DA;CJK COMPATIBILITY IDEOGRAPH-2F8DA;Lo;0;L;6721;;;;N;;;;; +2F8DB;CJK COMPATIBILITY IDEOGRAPH-2F8DB;Lo;0;L;675E;;;;N;;;;; +2F8DC;CJK COMPATIBILITY IDEOGRAPH-2F8DC;Lo;0;L;6753;;;;N;;;;; +2F8DD;CJK COMPATIBILITY IDEOGRAPH-2F8DD;Lo;0;L;233C3;;;;N;;;;; +2F8DE;CJK COMPATIBILITY IDEOGRAPH-2F8DE;Lo;0;L;3B49;;;;N;;;;; +2F8DF;CJK COMPATIBILITY IDEOGRAPH-2F8DF;Lo;0;L;67FA;;;;N;;;;; +2F8E0;CJK COMPATIBILITY IDEOGRAPH-2F8E0;Lo;0;L;6785;;;;N;;;;; +2F8E1;CJK COMPATIBILITY IDEOGRAPH-2F8E1;Lo;0;L;6852;;;;N;;;;; +2F8E2;CJK COMPATIBILITY IDEOGRAPH-2F8E2;Lo;0;L;6885;;;;N;;;;; +2F8E3;CJK COMPATIBILITY IDEOGRAPH-2F8E3;Lo;0;L;2346D;;;;N;;;;; +2F8E4;CJK COMPATIBILITY IDEOGRAPH-2F8E4;Lo;0;L;688E;;;;N;;;;; +2F8E5;CJK COMPATIBILITY IDEOGRAPH-2F8E5;Lo;0;L;681F;;;;N;;;;; +2F8E6;CJK COMPATIBILITY IDEOGRAPH-2F8E6;Lo;0;L;6914;;;;N;;;;; +2F8E7;CJK COMPATIBILITY IDEOGRAPH-2F8E7;Lo;0;L;3B9D;;;;N;;;;; +2F8E8;CJK COMPATIBILITY IDEOGRAPH-2F8E8;Lo;0;L;6942;;;;N;;;;; +2F8E9;CJK COMPATIBILITY IDEOGRAPH-2F8E9;Lo;0;L;69A3;;;;N;;;;; +2F8EA;CJK COMPATIBILITY IDEOGRAPH-2F8EA;Lo;0;L;69EA;;;;N;;;;; +2F8EB;CJK COMPATIBILITY IDEOGRAPH-2F8EB;Lo;0;L;6AA8;;;;N;;;;; +2F8EC;CJK COMPATIBILITY IDEOGRAPH-2F8EC;Lo;0;L;236A3;;;;N;;;;; +2F8ED;CJK COMPATIBILITY IDEOGRAPH-2F8ED;Lo;0;L;6ADB;;;;N;;;;; +2F8EE;CJK COMPATIBILITY IDEOGRAPH-2F8EE;Lo;0;L;3C18;;;;N;;;;; +2F8EF;CJK COMPATIBILITY IDEOGRAPH-2F8EF;Lo;0;L;6B21;;;;N;;;;; +2F8F0;CJK COMPATIBILITY IDEOGRAPH-2F8F0;Lo;0;L;238A7;;;;N;;;;; +2F8F1;CJK COMPATIBILITY IDEOGRAPH-2F8F1;Lo;0;L;6B54;;;;N;;;;; +2F8F2;CJK COMPATIBILITY IDEOGRAPH-2F8F2;Lo;0;L;3C4E;;;;N;;;;; +2F8F3;CJK COMPATIBILITY IDEOGRAPH-2F8F3;Lo;0;L;6B72;;;;N;;;;; +2F8F4;CJK COMPATIBILITY IDEOGRAPH-2F8F4;Lo;0;L;6B9F;;;;N;;;;; +2F8F5;CJK COMPATIBILITY IDEOGRAPH-2F8F5;Lo;0;L;6BBA;;;;N;;;;; +2F8F6;CJK COMPATIBILITY IDEOGRAPH-2F8F6;Lo;0;L;6BBB;;;;N;;;;; +2F8F7;CJK COMPATIBILITY IDEOGRAPH-2F8F7;Lo;0;L;23A8D;;;;N;;;;; +2F8F8;CJK COMPATIBILITY IDEOGRAPH-2F8F8;Lo;0;L;21D0B;;;;N;;;;; +2F8F9;CJK COMPATIBILITY IDEOGRAPH-2F8F9;Lo;0;L;23AFA;;;;N;;;;; +2F8FA;CJK COMPATIBILITY IDEOGRAPH-2F8FA;Lo;0;L;6C4E;;;;N;;;;; +2F8FB;CJK COMPATIBILITY IDEOGRAPH-2F8FB;Lo;0;L;23CBC;;;;N;;;;; +2F8FC;CJK COMPATIBILITY IDEOGRAPH-2F8FC;Lo;0;L;6CBF;;;;N;;;;; +2F8FD;CJK COMPATIBILITY IDEOGRAPH-2F8FD;Lo;0;L;6CCD;;;;N;;;;; +2F8FE;CJK COMPATIBILITY IDEOGRAPH-2F8FE;Lo;0;L;6C67;;;;N;;;;; +2F8FF;CJK COMPATIBILITY IDEOGRAPH-2F8FF;Lo;0;L;6D16;;;;N;;;;; +2F900;CJK COMPATIBILITY IDEOGRAPH-2F900;Lo;0;L;6D3E;;;;N;;;;; +2F901;CJK COMPATIBILITY IDEOGRAPH-2F901;Lo;0;L;6D77;;;;N;;;;; +2F902;CJK COMPATIBILITY IDEOGRAPH-2F902;Lo;0;L;6D41;;;;N;;;;; +2F903;CJK COMPATIBILITY IDEOGRAPH-2F903;Lo;0;L;6D69;;;;N;;;;; +2F904;CJK COMPATIBILITY IDEOGRAPH-2F904;Lo;0;L;6D78;;;;N;;;;; +2F905;CJK COMPATIBILITY IDEOGRAPH-2F905;Lo;0;L;6D85;;;;N;;;;; +2F906;CJK COMPATIBILITY IDEOGRAPH-2F906;Lo;0;L;23D1E;;;;N;;;;; +2F907;CJK COMPATIBILITY IDEOGRAPH-2F907;Lo;0;L;6D34;;;;N;;;;; +2F908;CJK COMPATIBILITY IDEOGRAPH-2F908;Lo;0;L;6E2F;;;;N;;;;; +2F909;CJK COMPATIBILITY IDEOGRAPH-2F909;Lo;0;L;6E6E;;;;N;;;;; +2F90A;CJK COMPATIBILITY IDEOGRAPH-2F90A;Lo;0;L;3D33;;;;N;;;;; +2F90B;CJK COMPATIBILITY IDEOGRAPH-2F90B;Lo;0;L;6ECB;;;;N;;;;; +2F90C;CJK COMPATIBILITY IDEOGRAPH-2F90C;Lo;0;L;6EC7;;;;N;;;;; +2F90D;CJK COMPATIBILITY IDEOGRAPH-2F90D;Lo;0;L;23ED1;;;;N;;;;; +2F90E;CJK COMPATIBILITY IDEOGRAPH-2F90E;Lo;0;L;6DF9;;;;N;;;;; +2F90F;CJK COMPATIBILITY IDEOGRAPH-2F90F;Lo;0;L;6F6E;;;;N;;;;; +2F910;CJK COMPATIBILITY IDEOGRAPH-2F910;Lo;0;L;23F5E;;;;N;;;;; +2F911;CJK COMPATIBILITY IDEOGRAPH-2F911;Lo;0;L;23F8E;;;;N;;;;; +2F912;CJK COMPATIBILITY IDEOGRAPH-2F912;Lo;0;L;6FC6;;;;N;;;;; +2F913;CJK COMPATIBILITY IDEOGRAPH-2F913;Lo;0;L;7039;;;;N;;;;; +2F914;CJK COMPATIBILITY IDEOGRAPH-2F914;Lo;0;L;701E;;;;N;;;;; +2F915;CJK COMPATIBILITY IDEOGRAPH-2F915;Lo;0;L;701B;;;;N;;;;; +2F916;CJK COMPATIBILITY IDEOGRAPH-2F916;Lo;0;L;3D96;;;;N;;;;; +2F917;CJK COMPATIBILITY IDEOGRAPH-2F917;Lo;0;L;704A;;;;N;;;;; +2F918;CJK COMPATIBILITY IDEOGRAPH-2F918;Lo;0;L;707D;;;;N;;;;; +2F919;CJK COMPATIBILITY IDEOGRAPH-2F919;Lo;0;L;7077;;;;N;;;;; +2F91A;CJK COMPATIBILITY IDEOGRAPH-2F91A;Lo;0;L;70AD;;;;N;;;;; +2F91B;CJK COMPATIBILITY IDEOGRAPH-2F91B;Lo;0;L;20525;;;;N;;;;; +2F91C;CJK COMPATIBILITY IDEOGRAPH-2F91C;Lo;0;L;7145;;;;N;;;;; +2F91D;CJK COMPATIBILITY IDEOGRAPH-2F91D;Lo;0;L;24263;;;;N;;;;; +2F91E;CJK COMPATIBILITY IDEOGRAPH-2F91E;Lo;0;L;719C;;;;N;;;;; +2F91F;CJK COMPATIBILITY IDEOGRAPH-2F91F;Lo;0;L;243AB;;;;N;;;;; +2F920;CJK COMPATIBILITY IDEOGRAPH-2F920;Lo;0;L;7228;;;;N;;;;; +2F921;CJK COMPATIBILITY IDEOGRAPH-2F921;Lo;0;L;7235;;;;N;;;;; +2F922;CJK COMPATIBILITY IDEOGRAPH-2F922;Lo;0;L;7250;;;;N;;;;; +2F923;CJK COMPATIBILITY IDEOGRAPH-2F923;Lo;0;L;24608;;;;N;;;;; +2F924;CJK COMPATIBILITY IDEOGRAPH-2F924;Lo;0;L;7280;;;;N;;;;; +2F925;CJK COMPATIBILITY IDEOGRAPH-2F925;Lo;0;L;7295;;;;N;;;;; +2F926;CJK COMPATIBILITY IDEOGRAPH-2F926;Lo;0;L;24735;;;;N;;;;; +2F927;CJK COMPATIBILITY IDEOGRAPH-2F927;Lo;0;L;24814;;;;N;;;;; +2F928;CJK COMPATIBILITY IDEOGRAPH-2F928;Lo;0;L;737A;;;;N;;;;; +2F929;CJK COMPATIBILITY IDEOGRAPH-2F929;Lo;0;L;738B;;;;N;;;;; +2F92A;CJK COMPATIBILITY IDEOGRAPH-2F92A;Lo;0;L;3EAC;;;;N;;;;; +2F92B;CJK COMPATIBILITY IDEOGRAPH-2F92B;Lo;0;L;73A5;;;;N;;;;; +2F92C;CJK COMPATIBILITY IDEOGRAPH-2F92C;Lo;0;L;3EB8;;;;N;;;;; +2F92D;CJK COMPATIBILITY IDEOGRAPH-2F92D;Lo;0;L;3EB8;;;;N;;;;; +2F92E;CJK COMPATIBILITY IDEOGRAPH-2F92E;Lo;0;L;7447;;;;N;;;;; +2F92F;CJK COMPATIBILITY IDEOGRAPH-2F92F;Lo;0;L;745C;;;;N;;;;; +2F930;CJK COMPATIBILITY IDEOGRAPH-2F930;Lo;0;L;7471;;;;N;;;;; +2F931;CJK COMPATIBILITY IDEOGRAPH-2F931;Lo;0;L;7485;;;;N;;;;; +2F932;CJK COMPATIBILITY IDEOGRAPH-2F932;Lo;0;L;74CA;;;;N;;;;; +2F933;CJK COMPATIBILITY IDEOGRAPH-2F933;Lo;0;L;3F1B;;;;N;;;;; +2F934;CJK COMPATIBILITY IDEOGRAPH-2F934;Lo;0;L;7524;;;;N;;;;; +2F935;CJK COMPATIBILITY IDEOGRAPH-2F935;Lo;0;L;24C36;;;;N;;;;; +2F936;CJK COMPATIBILITY IDEOGRAPH-2F936;Lo;0;L;753E;;;;N;;;;; +2F937;CJK COMPATIBILITY IDEOGRAPH-2F937;Lo;0;L;24C92;;;;N;;;;; +2F938;CJK COMPATIBILITY IDEOGRAPH-2F938;Lo;0;L;7570;;;;N;;;;; +2F939;CJK COMPATIBILITY IDEOGRAPH-2F939;Lo;0;L;2219F;;;;N;;;;; +2F93A;CJK COMPATIBILITY IDEOGRAPH-2F93A;Lo;0;L;7610;;;;N;;;;; +2F93B;CJK COMPATIBILITY IDEOGRAPH-2F93B;Lo;0;L;24FA1;;;;N;;;;; +2F93C;CJK COMPATIBILITY IDEOGRAPH-2F93C;Lo;0;L;24FB8;;;;N;;;;; +2F93D;CJK COMPATIBILITY IDEOGRAPH-2F93D;Lo;0;L;25044;;;;N;;;;; +2F93E;CJK COMPATIBILITY IDEOGRAPH-2F93E;Lo;0;L;3FFC;;;;N;;;;; +2F93F;CJK COMPATIBILITY IDEOGRAPH-2F93F;Lo;0;L;4008;;;;N;;;;; +2F940;CJK COMPATIBILITY IDEOGRAPH-2F940;Lo;0;L;76F4;;;;N;;;;; +2F941;CJK COMPATIBILITY IDEOGRAPH-2F941;Lo;0;L;250F3;;;;N;;;;; +2F942;CJK COMPATIBILITY IDEOGRAPH-2F942;Lo;0;L;250F2;;;;N;;;;; +2F943;CJK COMPATIBILITY IDEOGRAPH-2F943;Lo;0;L;25119;;;;N;;;;; +2F944;CJK COMPATIBILITY IDEOGRAPH-2F944;Lo;0;L;25133;;;;N;;;;; +2F945;CJK COMPATIBILITY IDEOGRAPH-2F945;Lo;0;L;771E;;;;N;;;;; +2F946;CJK COMPATIBILITY IDEOGRAPH-2F946;Lo;0;L;771F;;;;N;;;;; +2F947;CJK COMPATIBILITY IDEOGRAPH-2F947;Lo;0;L;771F;;;;N;;;;; +2F948;CJK COMPATIBILITY IDEOGRAPH-2F948;Lo;0;L;774A;;;;N;;;;; +2F949;CJK COMPATIBILITY IDEOGRAPH-2F949;Lo;0;L;4039;;;;N;;;;; +2F94A;CJK COMPATIBILITY IDEOGRAPH-2F94A;Lo;0;L;778B;;;;N;;;;; +2F94B;CJK COMPATIBILITY IDEOGRAPH-2F94B;Lo;0;L;4046;;;;N;;;;; +2F94C;CJK COMPATIBILITY IDEOGRAPH-2F94C;Lo;0;L;4096;;;;N;;;;; +2F94D;CJK COMPATIBILITY IDEOGRAPH-2F94D;Lo;0;L;2541D;;;;N;;;;; +2F94E;CJK COMPATIBILITY IDEOGRAPH-2F94E;Lo;0;L;784E;;;;N;;;;; +2F94F;CJK COMPATIBILITY IDEOGRAPH-2F94F;Lo;0;L;788C;;;;N;;;;; +2F950;CJK COMPATIBILITY IDEOGRAPH-2F950;Lo;0;L;78CC;;;;N;;;;; +2F951;CJK COMPATIBILITY IDEOGRAPH-2F951;Lo;0;L;40E3;;;;N;;;;; +2F952;CJK COMPATIBILITY IDEOGRAPH-2F952;Lo;0;L;25626;;;;N;;;;; +2F953;CJK COMPATIBILITY IDEOGRAPH-2F953;Lo;0;L;7956;;;;N;;;;; +2F954;CJK COMPATIBILITY IDEOGRAPH-2F954;Lo;0;L;2569A;;;;N;;;;; +2F955;CJK COMPATIBILITY IDEOGRAPH-2F955;Lo;0;L;256C5;;;;N;;;;; +2F956;CJK COMPATIBILITY IDEOGRAPH-2F956;Lo;0;L;798F;;;;N;;;;; +2F957;CJK COMPATIBILITY IDEOGRAPH-2F957;Lo;0;L;79EB;;;;N;;;;; +2F958;CJK COMPATIBILITY IDEOGRAPH-2F958;Lo;0;L;412F;;;;N;;;;; +2F959;CJK COMPATIBILITY IDEOGRAPH-2F959;Lo;0;L;7A40;;;;N;;;;; +2F95A;CJK COMPATIBILITY IDEOGRAPH-2F95A;Lo;0;L;7A4A;;;;N;;;;; +2F95B;CJK COMPATIBILITY IDEOGRAPH-2F95B;Lo;0;L;7A4F;;;;N;;;;; +2F95C;CJK COMPATIBILITY IDEOGRAPH-2F95C;Lo;0;L;2597C;;;;N;;;;; +2F95D;CJK COMPATIBILITY IDEOGRAPH-2F95D;Lo;0;L;25AA7;;;;N;;;;; +2F95E;CJK COMPATIBILITY IDEOGRAPH-2F95E;Lo;0;L;25AA7;;;;N;;;;; +2F95F;CJK COMPATIBILITY IDEOGRAPH-2F95F;Lo;0;L;7AEE;;;;N;;;;; +2F960;CJK COMPATIBILITY IDEOGRAPH-2F960;Lo;0;L;4202;;;;N;;;;; +2F961;CJK COMPATIBILITY IDEOGRAPH-2F961;Lo;0;L;25BAB;;;;N;;;;; +2F962;CJK COMPATIBILITY IDEOGRAPH-2F962;Lo;0;L;7BC6;;;;N;;;;; +2F963;CJK COMPATIBILITY IDEOGRAPH-2F963;Lo;0;L;7BC9;;;;N;;;;; +2F964;CJK COMPATIBILITY IDEOGRAPH-2F964;Lo;0;L;4227;;;;N;;;;; +2F965;CJK COMPATIBILITY IDEOGRAPH-2F965;Lo;0;L;25C80;;;;N;;;;; +2F966;CJK COMPATIBILITY IDEOGRAPH-2F966;Lo;0;L;7CD2;;;;N;;;;; +2F967;CJK COMPATIBILITY IDEOGRAPH-2F967;Lo;0;L;42A0;;;;N;;;;; +2F968;CJK COMPATIBILITY IDEOGRAPH-2F968;Lo;0;L;7CE8;;;;N;;;;; +2F969;CJK COMPATIBILITY IDEOGRAPH-2F969;Lo;0;L;7CE3;;;;N;;;;; +2F96A;CJK COMPATIBILITY IDEOGRAPH-2F96A;Lo;0;L;7D00;;;;N;;;;; +2F96B;CJK COMPATIBILITY IDEOGRAPH-2F96B;Lo;0;L;25F86;;;;N;;;;; +2F96C;CJK COMPATIBILITY IDEOGRAPH-2F96C;Lo;0;L;7D63;;;;N;;;;; +2F96D;CJK COMPATIBILITY IDEOGRAPH-2F96D;Lo;0;L;4301;;;;N;;;;; +2F96E;CJK COMPATIBILITY IDEOGRAPH-2F96E;Lo;0;L;7DC7;;;;N;;;;; +2F96F;CJK COMPATIBILITY IDEOGRAPH-2F96F;Lo;0;L;7E02;;;;N;;;;; +2F970;CJK COMPATIBILITY IDEOGRAPH-2F970;Lo;0;L;7E45;;;;N;;;;; +2F971;CJK COMPATIBILITY IDEOGRAPH-2F971;Lo;0;L;4334;;;;N;;;;; +2F972;CJK COMPATIBILITY IDEOGRAPH-2F972;Lo;0;L;26228;;;;N;;;;; +2F973;CJK COMPATIBILITY IDEOGRAPH-2F973;Lo;0;L;26247;;;;N;;;;; +2F974;CJK COMPATIBILITY IDEOGRAPH-2F974;Lo;0;L;4359;;;;N;;;;; +2F975;CJK COMPATIBILITY IDEOGRAPH-2F975;Lo;0;L;262D9;;;;N;;;;; +2F976;CJK COMPATIBILITY IDEOGRAPH-2F976;Lo;0;L;7F7A;;;;N;;;;; +2F977;CJK COMPATIBILITY IDEOGRAPH-2F977;Lo;0;L;2633E;;;;N;;;;; +2F978;CJK COMPATIBILITY IDEOGRAPH-2F978;Lo;0;L;7F95;;;;N;;;;; +2F979;CJK COMPATIBILITY IDEOGRAPH-2F979;Lo;0;L;7FFA;;;;N;;;;; +2F97A;CJK COMPATIBILITY IDEOGRAPH-2F97A;Lo;0;L;8005;;;;N;;;;; +2F97B;CJK COMPATIBILITY IDEOGRAPH-2F97B;Lo;0;L;264DA;;;;N;;;;; +2F97C;CJK COMPATIBILITY IDEOGRAPH-2F97C;Lo;0;L;26523;;;;N;;;;; +2F97D;CJK COMPATIBILITY IDEOGRAPH-2F97D;Lo;0;L;8060;;;;N;;;;; +2F97E;CJK COMPATIBILITY IDEOGRAPH-2F97E;Lo;0;L;265A8;;;;N;;;;; +2F97F;CJK COMPATIBILITY IDEOGRAPH-2F97F;Lo;0;L;8070;;;;N;;;;; +2F980;CJK COMPATIBILITY IDEOGRAPH-2F980;Lo;0;L;2335F;;;;N;;;;; +2F981;CJK COMPATIBILITY IDEOGRAPH-2F981;Lo;0;L;43D5;;;;N;;;;; +2F982;CJK COMPATIBILITY IDEOGRAPH-2F982;Lo;0;L;80B2;;;;N;;;;; +2F983;CJK COMPATIBILITY IDEOGRAPH-2F983;Lo;0;L;8103;;;;N;;;;; +2F984;CJK COMPATIBILITY IDEOGRAPH-2F984;Lo;0;L;440B;;;;N;;;;; +2F985;CJK COMPATIBILITY IDEOGRAPH-2F985;Lo;0;L;813E;;;;N;;;;; +2F986;CJK COMPATIBILITY IDEOGRAPH-2F986;Lo;0;L;5AB5;;;;N;;;;; +2F987;CJK COMPATIBILITY IDEOGRAPH-2F987;Lo;0;L;267A7;;;;N;;;;; +2F988;CJK COMPATIBILITY IDEOGRAPH-2F988;Lo;0;L;267B5;;;;N;;;;; +2F989;CJK COMPATIBILITY IDEOGRAPH-2F989;Lo;0;L;23393;;;;N;;;;; +2F98A;CJK COMPATIBILITY IDEOGRAPH-2F98A;Lo;0;L;2339C;;;;N;;;;; +2F98B;CJK COMPATIBILITY IDEOGRAPH-2F98B;Lo;0;L;8201;;;;N;;;;; +2F98C;CJK COMPATIBILITY IDEOGRAPH-2F98C;Lo;0;L;8204;;;;N;;;;; +2F98D;CJK COMPATIBILITY IDEOGRAPH-2F98D;Lo;0;L;8F9E;;;;N;;;;; +2F98E;CJK COMPATIBILITY IDEOGRAPH-2F98E;Lo;0;L;446B;;;;N;;;;; +2F98F;CJK COMPATIBILITY IDEOGRAPH-2F98F;Lo;0;L;8291;;;;N;;;;; +2F990;CJK COMPATIBILITY IDEOGRAPH-2F990;Lo;0;L;828B;;;;N;;;;; +2F991;CJK COMPATIBILITY IDEOGRAPH-2F991;Lo;0;L;829D;;;;N;;;;; +2F992;CJK COMPATIBILITY IDEOGRAPH-2F992;Lo;0;L;52B3;;;;N;;;;; +2F993;CJK COMPATIBILITY IDEOGRAPH-2F993;Lo;0;L;82B1;;;;N;;;;; +2F994;CJK COMPATIBILITY IDEOGRAPH-2F994;Lo;0;L;82B3;;;;N;;;;; +2F995;CJK COMPATIBILITY IDEOGRAPH-2F995;Lo;0;L;82BD;;;;N;;;;; +2F996;CJK COMPATIBILITY IDEOGRAPH-2F996;Lo;0;L;82E6;;;;N;;;;; +2F997;CJK COMPATIBILITY IDEOGRAPH-2F997;Lo;0;L;26B3C;;;;N;;;;; +2F998;CJK COMPATIBILITY IDEOGRAPH-2F998;Lo;0;L;82E5;;;;N;;;;; +2F999;CJK COMPATIBILITY IDEOGRAPH-2F999;Lo;0;L;831D;;;;N;;;;; +2F99A;CJK COMPATIBILITY IDEOGRAPH-2F99A;Lo;0;L;8363;;;;N;;;;; +2F99B;CJK COMPATIBILITY IDEOGRAPH-2F99B;Lo;0;L;83AD;;;;N;;;;; +2F99C;CJK COMPATIBILITY IDEOGRAPH-2F99C;Lo;0;L;8323;;;;N;;;;; +2F99D;CJK COMPATIBILITY IDEOGRAPH-2F99D;Lo;0;L;83BD;;;;N;;;;; +2F99E;CJK COMPATIBILITY IDEOGRAPH-2F99E;Lo;0;L;83E7;;;;N;;;;; +2F99F;CJK COMPATIBILITY IDEOGRAPH-2F99F;Lo;0;L;8457;;;;N;;;;; +2F9A0;CJK COMPATIBILITY IDEOGRAPH-2F9A0;Lo;0;L;8353;;;;N;;;;; +2F9A1;CJK COMPATIBILITY IDEOGRAPH-2F9A1;Lo;0;L;83CA;;;;N;;;;; +2F9A2;CJK COMPATIBILITY IDEOGRAPH-2F9A2;Lo;0;L;83CC;;;;N;;;;; +2F9A3;CJK COMPATIBILITY IDEOGRAPH-2F9A3;Lo;0;L;83DC;;;;N;;;;; +2F9A4;CJK COMPATIBILITY IDEOGRAPH-2F9A4;Lo;0;L;26C36;;;;N;;;;; +2F9A5;CJK COMPATIBILITY IDEOGRAPH-2F9A5;Lo;0;L;26D6B;;;;N;;;;; +2F9A6;CJK COMPATIBILITY IDEOGRAPH-2F9A6;Lo;0;L;26CD5;;;;N;;;;; +2F9A7;CJK COMPATIBILITY IDEOGRAPH-2F9A7;Lo;0;L;452B;;;;N;;;;; +2F9A8;CJK COMPATIBILITY IDEOGRAPH-2F9A8;Lo;0;L;84F1;;;;N;;;;; +2F9A9;CJK COMPATIBILITY IDEOGRAPH-2F9A9;Lo;0;L;84F3;;;;N;;;;; +2F9AA;CJK COMPATIBILITY IDEOGRAPH-2F9AA;Lo;0;L;8516;;;;N;;;;; +2F9AB;CJK COMPATIBILITY IDEOGRAPH-2F9AB;Lo;0;L;273CA;;;;N;;;;; +2F9AC;CJK COMPATIBILITY IDEOGRAPH-2F9AC;Lo;0;L;8564;;;;N;;;;; +2F9AD;CJK COMPATIBILITY IDEOGRAPH-2F9AD;Lo;0;L;26F2C;;;;N;;;;; +2F9AE;CJK COMPATIBILITY IDEOGRAPH-2F9AE;Lo;0;L;455D;;;;N;;;;; +2F9AF;CJK COMPATIBILITY IDEOGRAPH-2F9AF;Lo;0;L;4561;;;;N;;;;; +2F9B0;CJK COMPATIBILITY IDEOGRAPH-2F9B0;Lo;0;L;26FB1;;;;N;;;;; +2F9B1;CJK COMPATIBILITY IDEOGRAPH-2F9B1;Lo;0;L;270D2;;;;N;;;;; +2F9B2;CJK COMPATIBILITY IDEOGRAPH-2F9B2;Lo;0;L;456B;;;;N;;;;; +2F9B3;CJK COMPATIBILITY IDEOGRAPH-2F9B3;Lo;0;L;8650;;;;N;;;;; +2F9B4;CJK COMPATIBILITY IDEOGRAPH-2F9B4;Lo;0;L;865C;;;;N;;;;; +2F9B5;CJK COMPATIBILITY IDEOGRAPH-2F9B5;Lo;0;L;8667;;;;N;;;;; +2F9B6;CJK COMPATIBILITY IDEOGRAPH-2F9B6;Lo;0;L;8669;;;;N;;;;; +2F9B7;CJK COMPATIBILITY IDEOGRAPH-2F9B7;Lo;0;L;86A9;;;;N;;;;; +2F9B8;CJK COMPATIBILITY IDEOGRAPH-2F9B8;Lo;0;L;8688;;;;N;;;;; +2F9B9;CJK COMPATIBILITY IDEOGRAPH-2F9B9;Lo;0;L;870E;;;;N;;;;; +2F9BA;CJK COMPATIBILITY IDEOGRAPH-2F9BA;Lo;0;L;86E2;;;;N;;;;; +2F9BB;CJK COMPATIBILITY IDEOGRAPH-2F9BB;Lo;0;L;8779;;;;N;;;;; +2F9BC;CJK COMPATIBILITY IDEOGRAPH-2F9BC;Lo;0;L;8728;;;;N;;;;; +2F9BD;CJK COMPATIBILITY IDEOGRAPH-2F9BD;Lo;0;L;876B;;;;N;;;;; +2F9BE;CJK COMPATIBILITY IDEOGRAPH-2F9BE;Lo;0;L;8786;;;;N;;;;; +2F9BF;CJK COMPATIBILITY IDEOGRAPH-2F9BF;Lo;0;L;45D7;;;;N;;;;; +2F9C0;CJK COMPATIBILITY IDEOGRAPH-2F9C0;Lo;0;L;87E1;;;;N;;;;; +2F9C1;CJK COMPATIBILITY IDEOGRAPH-2F9C1;Lo;0;L;8801;;;;N;;;;; +2F9C2;CJK COMPATIBILITY IDEOGRAPH-2F9C2;Lo;0;L;45F9;;;;N;;;;; +2F9C3;CJK COMPATIBILITY IDEOGRAPH-2F9C3;Lo;0;L;8860;;;;N;;;;; +2F9C4;CJK COMPATIBILITY IDEOGRAPH-2F9C4;Lo;0;L;8863;;;;N;;;;; +2F9C5;CJK COMPATIBILITY IDEOGRAPH-2F9C5;Lo;0;L;27667;;;;N;;;;; +2F9C6;CJK COMPATIBILITY IDEOGRAPH-2F9C6;Lo;0;L;88D7;;;;N;;;;; +2F9C7;CJK COMPATIBILITY IDEOGRAPH-2F9C7;Lo;0;L;88DE;;;;N;;;;; +2F9C8;CJK COMPATIBILITY IDEOGRAPH-2F9C8;Lo;0;L;4635;;;;N;;;;; +2F9C9;CJK COMPATIBILITY IDEOGRAPH-2F9C9;Lo;0;L;88FA;;;;N;;;;; +2F9CA;CJK COMPATIBILITY IDEOGRAPH-2F9CA;Lo;0;L;34BB;;;;N;;;;; +2F9CB;CJK COMPATIBILITY IDEOGRAPH-2F9CB;Lo;0;L;278AE;;;;N;;;;; +2F9CC;CJK COMPATIBILITY IDEOGRAPH-2F9CC;Lo;0;L;27966;;;;N;;;;; +2F9CD;CJK COMPATIBILITY IDEOGRAPH-2F9CD;Lo;0;L;46BE;;;;N;;;;; +2F9CE;CJK COMPATIBILITY IDEOGRAPH-2F9CE;Lo;0;L;46C7;;;;N;;;;; +2F9CF;CJK COMPATIBILITY IDEOGRAPH-2F9CF;Lo;0;L;8AA0;;;;N;;;;; +2F9D0;CJK COMPATIBILITY IDEOGRAPH-2F9D0;Lo;0;L;8AED;;;;N;;;;; +2F9D1;CJK COMPATIBILITY IDEOGRAPH-2F9D1;Lo;0;L;8B8A;;;;N;;;;; +2F9D2;CJK COMPATIBILITY IDEOGRAPH-2F9D2;Lo;0;L;8C55;;;;N;;;;; +2F9D3;CJK COMPATIBILITY IDEOGRAPH-2F9D3;Lo;0;L;27CA8;;;;N;;;;; +2F9D4;CJK COMPATIBILITY IDEOGRAPH-2F9D4;Lo;0;L;8CAB;;;;N;;;;; +2F9D5;CJK COMPATIBILITY IDEOGRAPH-2F9D5;Lo;0;L;8CC1;;;;N;;;;; +2F9D6;CJK COMPATIBILITY IDEOGRAPH-2F9D6;Lo;0;L;8D1B;;;;N;;;;; +2F9D7;CJK COMPATIBILITY IDEOGRAPH-2F9D7;Lo;0;L;8D77;;;;N;;;;; +2F9D8;CJK COMPATIBILITY IDEOGRAPH-2F9D8;Lo;0;L;27F2F;;;;N;;;;; +2F9D9;CJK COMPATIBILITY IDEOGRAPH-2F9D9;Lo;0;L;20804;;;;N;;;;; +2F9DA;CJK COMPATIBILITY IDEOGRAPH-2F9DA;Lo;0;L;8DCB;;;;N;;;;; +2F9DB;CJK COMPATIBILITY IDEOGRAPH-2F9DB;Lo;0;L;8DBC;;;;N;;;;; +2F9DC;CJK COMPATIBILITY IDEOGRAPH-2F9DC;Lo;0;L;8DF0;;;;N;;;;; +2F9DD;CJK COMPATIBILITY IDEOGRAPH-2F9DD;Lo;0;L;208DE;;;;N;;;;; +2F9DE;CJK COMPATIBILITY IDEOGRAPH-2F9DE;Lo;0;L;8ED4;;;;N;;;;; +2F9DF;CJK COMPATIBILITY IDEOGRAPH-2F9DF;Lo;0;L;8F38;;;;N;;;;; +2F9E0;CJK COMPATIBILITY IDEOGRAPH-2F9E0;Lo;0;L;285D2;;;;N;;;;; +2F9E1;CJK COMPATIBILITY IDEOGRAPH-2F9E1;Lo;0;L;285ED;;;;N;;;;; +2F9E2;CJK COMPATIBILITY IDEOGRAPH-2F9E2;Lo;0;L;9094;;;;N;;;;; +2F9E3;CJK COMPATIBILITY IDEOGRAPH-2F9E3;Lo;0;L;90F1;;;;N;;;;; +2F9E4;CJK COMPATIBILITY IDEOGRAPH-2F9E4;Lo;0;L;9111;;;;N;;;;; +2F9E5;CJK COMPATIBILITY IDEOGRAPH-2F9E5;Lo;0;L;2872E;;;;N;;;;; +2F9E6;CJK COMPATIBILITY IDEOGRAPH-2F9E6;Lo;0;L;911B;;;;N;;;;; +2F9E7;CJK COMPATIBILITY IDEOGRAPH-2F9E7;Lo;0;L;9238;;;;N;;;;; +2F9E8;CJK COMPATIBILITY IDEOGRAPH-2F9E8;Lo;0;L;92D7;;;;N;;;;; +2F9E9;CJK COMPATIBILITY IDEOGRAPH-2F9E9;Lo;0;L;92D8;;;;N;;;;; +2F9EA;CJK COMPATIBILITY IDEOGRAPH-2F9EA;Lo;0;L;927C;;;;N;;;;; +2F9EB;CJK COMPATIBILITY IDEOGRAPH-2F9EB;Lo;0;L;93F9;;;;N;;;;; +2F9EC;CJK COMPATIBILITY IDEOGRAPH-2F9EC;Lo;0;L;9415;;;;N;;;;; +2F9ED;CJK COMPATIBILITY IDEOGRAPH-2F9ED;Lo;0;L;28BFA;;;;N;;;;; +2F9EE;CJK COMPATIBILITY IDEOGRAPH-2F9EE;Lo;0;L;958B;;;;N;;;;; +2F9EF;CJK COMPATIBILITY IDEOGRAPH-2F9EF;Lo;0;L;4995;;;;N;;;;; +2F9F0;CJK COMPATIBILITY IDEOGRAPH-2F9F0;Lo;0;L;95B7;;;;N;;;;; +2F9F1;CJK COMPATIBILITY IDEOGRAPH-2F9F1;Lo;0;L;28D77;;;;N;;;;; +2F9F2;CJK COMPATIBILITY IDEOGRAPH-2F9F2;Lo;0;L;49E6;;;;N;;;;; +2F9F3;CJK COMPATIBILITY IDEOGRAPH-2F9F3;Lo;0;L;96C3;;;;N;;;;; +2F9F4;CJK COMPATIBILITY IDEOGRAPH-2F9F4;Lo;0;L;5DB2;;;;N;;;;; +2F9F5;CJK COMPATIBILITY IDEOGRAPH-2F9F5;Lo;0;L;9723;;;;N;;;;; +2F9F6;CJK COMPATIBILITY IDEOGRAPH-2F9F6;Lo;0;L;29145;;;;N;;;;; +2F9F7;CJK COMPATIBILITY IDEOGRAPH-2F9F7;Lo;0;L;2921A;;;;N;;;;; +2F9F8;CJK COMPATIBILITY IDEOGRAPH-2F9F8;Lo;0;L;4A6E;;;;N;;;;; +2F9F9;CJK COMPATIBILITY IDEOGRAPH-2F9F9;Lo;0;L;4A76;;;;N;;;;; +2F9FA;CJK COMPATIBILITY IDEOGRAPH-2F9FA;Lo;0;L;97E0;;;;N;;;;; +2F9FB;CJK COMPATIBILITY IDEOGRAPH-2F9FB;Lo;0;L;2940A;;;;N;;;;; +2F9FC;CJK COMPATIBILITY IDEOGRAPH-2F9FC;Lo;0;L;4AB2;;;;N;;;;; +2F9FD;CJK COMPATIBILITY IDEOGRAPH-2F9FD;Lo;0;L;29496;;;;N;;;;; +2F9FE;CJK COMPATIBILITY IDEOGRAPH-2F9FE;Lo;0;L;980B;;;;N;;;;; +2F9FF;CJK COMPATIBILITY IDEOGRAPH-2F9FF;Lo;0;L;980B;;;;N;;;;; +2FA00;CJK COMPATIBILITY IDEOGRAPH-2FA00;Lo;0;L;9829;;;;N;;;;; +2FA01;CJK COMPATIBILITY IDEOGRAPH-2FA01;Lo;0;L;295B6;;;;N;;;;; +2FA02;CJK COMPATIBILITY IDEOGRAPH-2FA02;Lo;0;L;98E2;;;;N;;;;; +2FA03;CJK COMPATIBILITY IDEOGRAPH-2FA03;Lo;0;L;4B33;;;;N;;;;; +2FA04;CJK COMPATIBILITY IDEOGRAPH-2FA04;Lo;0;L;9929;;;;N;;;;; +2FA05;CJK COMPATIBILITY IDEOGRAPH-2FA05;Lo;0;L;99A7;;;;N;;;;; +2FA06;CJK COMPATIBILITY IDEOGRAPH-2FA06;Lo;0;L;99C2;;;;N;;;;; +2FA07;CJK COMPATIBILITY IDEOGRAPH-2FA07;Lo;0;L;99FE;;;;N;;;;; +2FA08;CJK COMPATIBILITY IDEOGRAPH-2FA08;Lo;0;L;4BCE;;;;N;;;;; +2FA09;CJK COMPATIBILITY IDEOGRAPH-2FA09;Lo;0;L;29B30;;;;N;;;;; +2FA0A;CJK COMPATIBILITY IDEOGRAPH-2FA0A;Lo;0;L;9B12;;;;N;;;;; +2FA0B;CJK COMPATIBILITY IDEOGRAPH-2FA0B;Lo;0;L;9C40;;;;N;;;;; +2FA0C;CJK COMPATIBILITY IDEOGRAPH-2FA0C;Lo;0;L;9CFD;;;;N;;;;; +2FA0D;CJK COMPATIBILITY IDEOGRAPH-2FA0D;Lo;0;L;4CCE;;;;N;;;;; +2FA0E;CJK COMPATIBILITY IDEOGRAPH-2FA0E;Lo;0;L;4CED;;;;N;;;;; +2FA0F;CJK COMPATIBILITY IDEOGRAPH-2FA0F;Lo;0;L;9D67;;;;N;;;;; +2FA10;CJK COMPATIBILITY IDEOGRAPH-2FA10;Lo;0;L;2A0CE;;;;N;;;;; +2FA11;CJK COMPATIBILITY IDEOGRAPH-2FA11;Lo;0;L;4CF8;;;;N;;;;; +2FA12;CJK COMPATIBILITY IDEOGRAPH-2FA12;Lo;0;L;2A105;;;;N;;;;; +2FA13;CJK COMPATIBILITY IDEOGRAPH-2FA13;Lo;0;L;2A20E;;;;N;;;;; +2FA14;CJK COMPATIBILITY IDEOGRAPH-2FA14;Lo;0;L;2A291;;;;N;;;;; +2FA15;CJK COMPATIBILITY IDEOGRAPH-2FA15;Lo;0;L;9EBB;;;;N;;;;; +2FA16;CJK COMPATIBILITY IDEOGRAPH-2FA16;Lo;0;L;4D56;;;;N;;;;; +2FA17;CJK COMPATIBILITY IDEOGRAPH-2FA17;Lo;0;L;9EF9;;;;N;;;;; +2FA18;CJK COMPATIBILITY IDEOGRAPH-2FA18;Lo;0;L;9EFE;;;;N;;;;; +2FA19;CJK COMPATIBILITY IDEOGRAPH-2FA19;Lo;0;L;9F05;;;;N;;;;; +2FA1A;CJK COMPATIBILITY IDEOGRAPH-2FA1A;Lo;0;L;9F0F;;;;N;;;;; +2FA1B;CJK COMPATIBILITY IDEOGRAPH-2FA1B;Lo;0;L;9F16;;;;N;;;;; +2FA1C;CJK COMPATIBILITY IDEOGRAPH-2FA1C;Lo;0;L;9F3B;;;;N;;;;; +2FA1D;CJK COMPATIBILITY IDEOGRAPH-2FA1D;Lo;0;L;2A600;;;;N;;;;; +30000;;Lo;0;L;;;;;N;;;;; +3134A;;Lo;0;L;;;;;N;;;;; +31350;;Lo;0;L;;;;;N;;;;; +323AF;;Lo;0;L;;;;;N;;;;; +323B0;;Lo;0;L;;;;;N;;;;; +33479;;Lo;0;L;;;;;N;;;;; +E0001;LANGUAGE TAG;Cf;0;BN;;;;;N;;;;; +E0020;TAG SPACE;Cf;0;BN;;;;;N;;;;; +E0021;TAG EXCLAMATION MARK;Cf;0;BN;;;;;N;;;;; +E0022;TAG QUOTATION MARK;Cf;0;BN;;;;;N;;;;; +E0023;TAG NUMBER SIGN;Cf;0;BN;;;;;N;;;;; +E0024;TAG DOLLAR SIGN;Cf;0;BN;;;;;N;;;;; +E0025;TAG PERCENT SIGN;Cf;0;BN;;;;;N;;;;; +E0026;TAG AMPERSAND;Cf;0;BN;;;;;N;;;;; +E0027;TAG APOSTROPHE;Cf;0;BN;;;;;N;;;;; +E0028;TAG LEFT PARENTHESIS;Cf;0;BN;;;;;N;;;;; +E0029;TAG RIGHT PARENTHESIS;Cf;0;BN;;;;;N;;;;; +E002A;TAG ASTERISK;Cf;0;BN;;;;;N;;;;; +E002B;TAG PLUS SIGN;Cf;0;BN;;;;;N;;;;; +E002C;TAG COMMA;Cf;0;BN;;;;;N;;;;; +E002D;TAG HYPHEN-MINUS;Cf;0;BN;;;;;N;;;;; +E002E;TAG FULL STOP;Cf;0;BN;;;;;N;;;;; +E002F;TAG SOLIDUS;Cf;0;BN;;;;;N;;;;; +E0030;TAG DIGIT ZERO;Cf;0;BN;;;;;N;;;;; +E0031;TAG DIGIT ONE;Cf;0;BN;;;;;N;;;;; +E0032;TAG DIGIT TWO;Cf;0;BN;;;;;N;;;;; +E0033;TAG DIGIT THREE;Cf;0;BN;;;;;N;;;;; +E0034;TAG DIGIT FOUR;Cf;0;BN;;;;;N;;;;; +E0035;TAG DIGIT FIVE;Cf;0;BN;;;;;N;;;;; +E0036;TAG DIGIT SIX;Cf;0;BN;;;;;N;;;;; +E0037;TAG DIGIT SEVEN;Cf;0;BN;;;;;N;;;;; +E0038;TAG DIGIT EIGHT;Cf;0;BN;;;;;N;;;;; +E0039;TAG DIGIT NINE;Cf;0;BN;;;;;N;;;;; +E003A;TAG COLON;Cf;0;BN;;;;;N;;;;; +E003B;TAG SEMICOLON;Cf;0;BN;;;;;N;;;;; +E003C;TAG LESS-THAN SIGN;Cf;0;BN;;;;;N;;;;; +E003D;TAG EQUALS SIGN;Cf;0;BN;;;;;N;;;;; +E003E;TAG GREATER-THAN SIGN;Cf;0;BN;;;;;N;;;;; +E003F;TAG QUESTION MARK;Cf;0;BN;;;;;N;;;;; +E0040;TAG COMMERCIAL AT;Cf;0;BN;;;;;N;;;;; +E0041;TAG LATIN CAPITAL LETTER A;Cf;0;BN;;;;;N;;;;; +E0042;TAG LATIN CAPITAL LETTER B;Cf;0;BN;;;;;N;;;;; +E0043;TAG LATIN CAPITAL LETTER C;Cf;0;BN;;;;;N;;;;; +E0044;TAG LATIN CAPITAL LETTER D;Cf;0;BN;;;;;N;;;;; +E0045;TAG LATIN CAPITAL LETTER E;Cf;0;BN;;;;;N;;;;; +E0046;TAG LATIN CAPITAL LETTER F;Cf;0;BN;;;;;N;;;;; +E0047;TAG LATIN CAPITAL LETTER G;Cf;0;BN;;;;;N;;;;; +E0048;TAG LATIN CAPITAL LETTER H;Cf;0;BN;;;;;N;;;;; +E0049;TAG LATIN CAPITAL LETTER I;Cf;0;BN;;;;;N;;;;; +E004A;TAG LATIN CAPITAL LETTER J;Cf;0;BN;;;;;N;;;;; +E004B;TAG LATIN CAPITAL LETTER K;Cf;0;BN;;;;;N;;;;; +E004C;TAG LATIN CAPITAL LETTER L;Cf;0;BN;;;;;N;;;;; +E004D;TAG LATIN CAPITAL LETTER M;Cf;0;BN;;;;;N;;;;; +E004E;TAG LATIN CAPITAL LETTER N;Cf;0;BN;;;;;N;;;;; +E004F;TAG LATIN CAPITAL LETTER O;Cf;0;BN;;;;;N;;;;; +E0050;TAG LATIN CAPITAL LETTER P;Cf;0;BN;;;;;N;;;;; +E0051;TAG LATIN CAPITAL LETTER Q;Cf;0;BN;;;;;N;;;;; +E0052;TAG LATIN CAPITAL LETTER R;Cf;0;BN;;;;;N;;;;; +E0053;TAG LATIN CAPITAL LETTER S;Cf;0;BN;;;;;N;;;;; +E0054;TAG LATIN CAPITAL LETTER T;Cf;0;BN;;;;;N;;;;; +E0055;TAG LATIN CAPITAL LETTER U;Cf;0;BN;;;;;N;;;;; +E0056;TAG LATIN CAPITAL LETTER V;Cf;0;BN;;;;;N;;;;; +E0057;TAG LATIN CAPITAL LETTER W;Cf;0;BN;;;;;N;;;;; +E0058;TAG LATIN CAPITAL LETTER X;Cf;0;BN;;;;;N;;;;; +E0059;TAG LATIN CAPITAL LETTER Y;Cf;0;BN;;;;;N;;;;; +E005A;TAG LATIN CAPITAL LETTER Z;Cf;0;BN;;;;;N;;;;; +E005B;TAG LEFT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;; +E005C;TAG REVERSE SOLIDUS;Cf;0;BN;;;;;N;;;;; +E005D;TAG RIGHT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;; +E005E;TAG CIRCUMFLEX ACCENT;Cf;0;BN;;;;;N;;;;; +E005F;TAG LOW LINE;Cf;0;BN;;;;;N;;;;; +E0060;TAG GRAVE ACCENT;Cf;0;BN;;;;;N;;;;; +E0061;TAG LATIN SMALL LETTER A;Cf;0;BN;;;;;N;;;;; +E0062;TAG LATIN SMALL LETTER B;Cf;0;BN;;;;;N;;;;; +E0063;TAG LATIN SMALL LETTER C;Cf;0;BN;;;;;N;;;;; +E0064;TAG LATIN SMALL LETTER D;Cf;0;BN;;;;;N;;;;; +E0065;TAG LATIN SMALL LETTER E;Cf;0;BN;;;;;N;;;;; +E0066;TAG LATIN SMALL LETTER F;Cf;0;BN;;;;;N;;;;; +E0067;TAG LATIN SMALL LETTER G;Cf;0;BN;;;;;N;;;;; +E0068;TAG LATIN SMALL LETTER H;Cf;0;BN;;;;;N;;;;; +E0069;TAG LATIN SMALL LETTER I;Cf;0;BN;;;;;N;;;;; +E006A;TAG LATIN SMALL LETTER J;Cf;0;BN;;;;;N;;;;; +E006B;TAG LATIN SMALL LETTER K;Cf;0;BN;;;;;N;;;;; +E006C;TAG LATIN SMALL LETTER L;Cf;0;BN;;;;;N;;;;; +E006D;TAG LATIN SMALL LETTER M;Cf;0;BN;;;;;N;;;;; +E006E;TAG LATIN SMALL LETTER N;Cf;0;BN;;;;;N;;;;; +E006F;TAG LATIN SMALL LETTER O;Cf;0;BN;;;;;N;;;;; +E0070;TAG LATIN SMALL LETTER P;Cf;0;BN;;;;;N;;;;; +E0071;TAG LATIN SMALL LETTER Q;Cf;0;BN;;;;;N;;;;; +E0072;TAG LATIN SMALL LETTER R;Cf;0;BN;;;;;N;;;;; +E0073;TAG LATIN SMALL LETTER S;Cf;0;BN;;;;;N;;;;; +E0074;TAG LATIN SMALL LETTER T;Cf;0;BN;;;;;N;;;;; +E0075;TAG LATIN SMALL LETTER U;Cf;0;BN;;;;;N;;;;; +E0076;TAG LATIN SMALL LETTER V;Cf;0;BN;;;;;N;;;;; +E0077;TAG LATIN SMALL LETTER W;Cf;0;BN;;;;;N;;;;; +E0078;TAG LATIN SMALL LETTER X;Cf;0;BN;;;;;N;;;;; +E0079;TAG LATIN SMALL LETTER Y;Cf;0;BN;;;;;N;;;;; +E007A;TAG LATIN SMALL LETTER Z;Cf;0;BN;;;;;N;;;;; +E007B;TAG LEFT CURLY BRACKET;Cf;0;BN;;;;;N;;;;; +E007C;TAG VERTICAL LINE;Cf;0;BN;;;;;N;;;;; +E007D;TAG RIGHT CURLY BRACKET;Cf;0;BN;;;;;N;;;;; +E007E;TAG TILDE;Cf;0;BN;;;;;N;;;;; +E007F;CANCEL TAG;Cf;0;BN;;;;;N;;;;; +E0100;VARIATION SELECTOR-17;Mn;0;NSM;;;;;N;;;;; +E0101;VARIATION SELECTOR-18;Mn;0;NSM;;;;;N;;;;; +E0102;VARIATION SELECTOR-19;Mn;0;NSM;;;;;N;;;;; +E0103;VARIATION SELECTOR-20;Mn;0;NSM;;;;;N;;;;; +E0104;VARIATION SELECTOR-21;Mn;0;NSM;;;;;N;;;;; +E0105;VARIATION SELECTOR-22;Mn;0;NSM;;;;;N;;;;; +E0106;VARIATION SELECTOR-23;Mn;0;NSM;;;;;N;;;;; +E0107;VARIATION SELECTOR-24;Mn;0;NSM;;;;;N;;;;; +E0108;VARIATION SELECTOR-25;Mn;0;NSM;;;;;N;;;;; +E0109;VARIATION SELECTOR-26;Mn;0;NSM;;;;;N;;;;; +E010A;VARIATION SELECTOR-27;Mn;0;NSM;;;;;N;;;;; +E010B;VARIATION SELECTOR-28;Mn;0;NSM;;;;;N;;;;; +E010C;VARIATION SELECTOR-29;Mn;0;NSM;;;;;N;;;;; +E010D;VARIATION SELECTOR-30;Mn;0;NSM;;;;;N;;;;; +E010E;VARIATION SELECTOR-31;Mn;0;NSM;;;;;N;;;;; +E010F;VARIATION SELECTOR-32;Mn;0;NSM;;;;;N;;;;; +E0110;VARIATION SELECTOR-33;Mn;0;NSM;;;;;N;;;;; +E0111;VARIATION SELECTOR-34;Mn;0;NSM;;;;;N;;;;; +E0112;VARIATION SELECTOR-35;Mn;0;NSM;;;;;N;;;;; +E0113;VARIATION SELECTOR-36;Mn;0;NSM;;;;;N;;;;; +E0114;VARIATION SELECTOR-37;Mn;0;NSM;;;;;N;;;;; +E0115;VARIATION SELECTOR-38;Mn;0;NSM;;;;;N;;;;; +E0116;VARIATION SELECTOR-39;Mn;0;NSM;;;;;N;;;;; +E0117;VARIATION SELECTOR-40;Mn;0;NSM;;;;;N;;;;; +E0118;VARIATION SELECTOR-41;Mn;0;NSM;;;;;N;;;;; +E0119;VARIATION SELECTOR-42;Mn;0;NSM;;;;;N;;;;; +E011A;VARIATION SELECTOR-43;Mn;0;NSM;;;;;N;;;;; +E011B;VARIATION SELECTOR-44;Mn;0;NSM;;;;;N;;;;; +E011C;VARIATION SELECTOR-45;Mn;0;NSM;;;;;N;;;;; +E011D;VARIATION SELECTOR-46;Mn;0;NSM;;;;;N;;;;; +E011E;VARIATION SELECTOR-47;Mn;0;NSM;;;;;N;;;;; +E011F;VARIATION SELECTOR-48;Mn;0;NSM;;;;;N;;;;; +E0120;VARIATION SELECTOR-49;Mn;0;NSM;;;;;N;;;;; +E0121;VARIATION SELECTOR-50;Mn;0;NSM;;;;;N;;;;; +E0122;VARIATION SELECTOR-51;Mn;0;NSM;;;;;N;;;;; +E0123;VARIATION SELECTOR-52;Mn;0;NSM;;;;;N;;;;; +E0124;VARIATION SELECTOR-53;Mn;0;NSM;;;;;N;;;;; +E0125;VARIATION SELECTOR-54;Mn;0;NSM;;;;;N;;;;; +E0126;VARIATION SELECTOR-55;Mn;0;NSM;;;;;N;;;;; +E0127;VARIATION SELECTOR-56;Mn;0;NSM;;;;;N;;;;; +E0128;VARIATION SELECTOR-57;Mn;0;NSM;;;;;N;;;;; +E0129;VARIATION SELECTOR-58;Mn;0;NSM;;;;;N;;;;; +E012A;VARIATION SELECTOR-59;Mn;0;NSM;;;;;N;;;;; +E012B;VARIATION SELECTOR-60;Mn;0;NSM;;;;;N;;;;; +E012C;VARIATION SELECTOR-61;Mn;0;NSM;;;;;N;;;;; +E012D;VARIATION SELECTOR-62;Mn;0;NSM;;;;;N;;;;; +E012E;VARIATION SELECTOR-63;Mn;0;NSM;;;;;N;;;;; +E012F;VARIATION SELECTOR-64;Mn;0;NSM;;;;;N;;;;; +E0130;VARIATION SELECTOR-65;Mn;0;NSM;;;;;N;;;;; +E0131;VARIATION SELECTOR-66;Mn;0;NSM;;;;;N;;;;; +E0132;VARIATION SELECTOR-67;Mn;0;NSM;;;;;N;;;;; +E0133;VARIATION SELECTOR-68;Mn;0;NSM;;;;;N;;;;; +E0134;VARIATION SELECTOR-69;Mn;0;NSM;;;;;N;;;;; +E0135;VARIATION SELECTOR-70;Mn;0;NSM;;;;;N;;;;; +E0136;VARIATION SELECTOR-71;Mn;0;NSM;;;;;N;;;;; +E0137;VARIATION SELECTOR-72;Mn;0;NSM;;;;;N;;;;; +E0138;VARIATION SELECTOR-73;Mn;0;NSM;;;;;N;;;;; +E0139;VARIATION SELECTOR-74;Mn;0;NSM;;;;;N;;;;; +E013A;VARIATION SELECTOR-75;Mn;0;NSM;;;;;N;;;;; +E013B;VARIATION SELECTOR-76;Mn;0;NSM;;;;;N;;;;; +E013C;VARIATION SELECTOR-77;Mn;0;NSM;;;;;N;;;;; +E013D;VARIATION SELECTOR-78;Mn;0;NSM;;;;;N;;;;; +E013E;VARIATION SELECTOR-79;Mn;0;NSM;;;;;N;;;;; +E013F;VARIATION SELECTOR-80;Mn;0;NSM;;;;;N;;;;; +E0140;VARIATION SELECTOR-81;Mn;0;NSM;;;;;N;;;;; +E0141;VARIATION SELECTOR-82;Mn;0;NSM;;;;;N;;;;; +E0142;VARIATION SELECTOR-83;Mn;0;NSM;;;;;N;;;;; +E0143;VARIATION SELECTOR-84;Mn;0;NSM;;;;;N;;;;; +E0144;VARIATION SELECTOR-85;Mn;0;NSM;;;;;N;;;;; +E0145;VARIATION SELECTOR-86;Mn;0;NSM;;;;;N;;;;; +E0146;VARIATION SELECTOR-87;Mn;0;NSM;;;;;N;;;;; +E0147;VARIATION SELECTOR-88;Mn;0;NSM;;;;;N;;;;; +E0148;VARIATION SELECTOR-89;Mn;0;NSM;;;;;N;;;;; +E0149;VARIATION SELECTOR-90;Mn;0;NSM;;;;;N;;;;; +E014A;VARIATION SELECTOR-91;Mn;0;NSM;;;;;N;;;;; +E014B;VARIATION SELECTOR-92;Mn;0;NSM;;;;;N;;;;; +E014C;VARIATION SELECTOR-93;Mn;0;NSM;;;;;N;;;;; +E014D;VARIATION SELECTOR-94;Mn;0;NSM;;;;;N;;;;; +E014E;VARIATION SELECTOR-95;Mn;0;NSM;;;;;N;;;;; +E014F;VARIATION SELECTOR-96;Mn;0;NSM;;;;;N;;;;; +E0150;VARIATION SELECTOR-97;Mn;0;NSM;;;;;N;;;;; +E0151;VARIATION SELECTOR-98;Mn;0;NSM;;;;;N;;;;; +E0152;VARIATION SELECTOR-99;Mn;0;NSM;;;;;N;;;;; +E0153;VARIATION SELECTOR-100;Mn;0;NSM;;;;;N;;;;; +E0154;VARIATION SELECTOR-101;Mn;0;NSM;;;;;N;;;;; +E0155;VARIATION SELECTOR-102;Mn;0;NSM;;;;;N;;;;; +E0156;VARIATION SELECTOR-103;Mn;0;NSM;;;;;N;;;;; +E0157;VARIATION SELECTOR-104;Mn;0;NSM;;;;;N;;;;; +E0158;VARIATION SELECTOR-105;Mn;0;NSM;;;;;N;;;;; +E0159;VARIATION SELECTOR-106;Mn;0;NSM;;;;;N;;;;; +E015A;VARIATION SELECTOR-107;Mn;0;NSM;;;;;N;;;;; +E015B;VARIATION SELECTOR-108;Mn;0;NSM;;;;;N;;;;; +E015C;VARIATION SELECTOR-109;Mn;0;NSM;;;;;N;;;;; +E015D;VARIATION SELECTOR-110;Mn;0;NSM;;;;;N;;;;; +E015E;VARIATION SELECTOR-111;Mn;0;NSM;;;;;N;;;;; +E015F;VARIATION SELECTOR-112;Mn;0;NSM;;;;;N;;;;; +E0160;VARIATION SELECTOR-113;Mn;0;NSM;;;;;N;;;;; +E0161;VARIATION SELECTOR-114;Mn;0;NSM;;;;;N;;;;; +E0162;VARIATION SELECTOR-115;Mn;0;NSM;;;;;N;;;;; +E0163;VARIATION SELECTOR-116;Mn;0;NSM;;;;;N;;;;; +E0164;VARIATION SELECTOR-117;Mn;0;NSM;;;;;N;;;;; +E0165;VARIATION SELECTOR-118;Mn;0;NSM;;;;;N;;;;; +E0166;VARIATION SELECTOR-119;Mn;0;NSM;;;;;N;;;;; +E0167;VARIATION SELECTOR-120;Mn;0;NSM;;;;;N;;;;; +E0168;VARIATION SELECTOR-121;Mn;0;NSM;;;;;N;;;;; +E0169;VARIATION SELECTOR-122;Mn;0;NSM;;;;;N;;;;; +E016A;VARIATION SELECTOR-123;Mn;0;NSM;;;;;N;;;;; +E016B;VARIATION SELECTOR-124;Mn;0;NSM;;;;;N;;;;; +E016C;VARIATION SELECTOR-125;Mn;0;NSM;;;;;N;;;;; +E016D;VARIATION SELECTOR-126;Mn;0;NSM;;;;;N;;;;; +E016E;VARIATION SELECTOR-127;Mn;0;NSM;;;;;N;;;;; +E016F;VARIATION SELECTOR-128;Mn;0;NSM;;;;;N;;;;; +E0170;VARIATION SELECTOR-129;Mn;0;NSM;;;;;N;;;;; +E0171;VARIATION SELECTOR-130;Mn;0;NSM;;;;;N;;;;; +E0172;VARIATION SELECTOR-131;Mn;0;NSM;;;;;N;;;;; +E0173;VARIATION SELECTOR-132;Mn;0;NSM;;;;;N;;;;; +E0174;VARIATION SELECTOR-133;Mn;0;NSM;;;;;N;;;;; +E0175;VARIATION SELECTOR-134;Mn;0;NSM;;;;;N;;;;; +E0176;VARIATION SELECTOR-135;Mn;0;NSM;;;;;N;;;;; +E0177;VARIATION SELECTOR-136;Mn;0;NSM;;;;;N;;;;; +E0178;VARIATION SELECTOR-137;Mn;0;NSM;;;;;N;;;;; +E0179;VARIATION SELECTOR-138;Mn;0;NSM;;;;;N;;;;; +E017A;VARIATION SELECTOR-139;Mn;0;NSM;;;;;N;;;;; +E017B;VARIATION SELECTOR-140;Mn;0;NSM;;;;;N;;;;; +E017C;VARIATION SELECTOR-141;Mn;0;NSM;;;;;N;;;;; +E017D;VARIATION SELECTOR-142;Mn;0;NSM;;;;;N;;;;; +E017E;VARIATION SELECTOR-143;Mn;0;NSM;;;;;N;;;;; +E017F;VARIATION SELECTOR-144;Mn;0;NSM;;;;;N;;;;; +E0180;VARIATION SELECTOR-145;Mn;0;NSM;;;;;N;;;;; +E0181;VARIATION SELECTOR-146;Mn;0;NSM;;;;;N;;;;; +E0182;VARIATION SELECTOR-147;Mn;0;NSM;;;;;N;;;;; +E0183;VARIATION SELECTOR-148;Mn;0;NSM;;;;;N;;;;; +E0184;VARIATION SELECTOR-149;Mn;0;NSM;;;;;N;;;;; +E0185;VARIATION SELECTOR-150;Mn;0;NSM;;;;;N;;;;; +E0186;VARIATION SELECTOR-151;Mn;0;NSM;;;;;N;;;;; +E0187;VARIATION SELECTOR-152;Mn;0;NSM;;;;;N;;;;; +E0188;VARIATION SELECTOR-153;Mn;0;NSM;;;;;N;;;;; +E0189;VARIATION SELECTOR-154;Mn;0;NSM;;;;;N;;;;; +E018A;VARIATION SELECTOR-155;Mn;0;NSM;;;;;N;;;;; +E018B;VARIATION SELECTOR-156;Mn;0;NSM;;;;;N;;;;; +E018C;VARIATION SELECTOR-157;Mn;0;NSM;;;;;N;;;;; +E018D;VARIATION SELECTOR-158;Mn;0;NSM;;;;;N;;;;; +E018E;VARIATION SELECTOR-159;Mn;0;NSM;;;;;N;;;;; +E018F;VARIATION SELECTOR-160;Mn;0;NSM;;;;;N;;;;; +E0190;VARIATION SELECTOR-161;Mn;0;NSM;;;;;N;;;;; +E0191;VARIATION SELECTOR-162;Mn;0;NSM;;;;;N;;;;; +E0192;VARIATION SELECTOR-163;Mn;0;NSM;;;;;N;;;;; +E0193;VARIATION SELECTOR-164;Mn;0;NSM;;;;;N;;;;; +E0194;VARIATION SELECTOR-165;Mn;0;NSM;;;;;N;;;;; +E0195;VARIATION SELECTOR-166;Mn;0;NSM;;;;;N;;;;; +E0196;VARIATION SELECTOR-167;Mn;0;NSM;;;;;N;;;;; +E0197;VARIATION SELECTOR-168;Mn;0;NSM;;;;;N;;;;; +E0198;VARIATION SELECTOR-169;Mn;0;NSM;;;;;N;;;;; +E0199;VARIATION SELECTOR-170;Mn;0;NSM;;;;;N;;;;; +E019A;VARIATION SELECTOR-171;Mn;0;NSM;;;;;N;;;;; +E019B;VARIATION SELECTOR-172;Mn;0;NSM;;;;;N;;;;; +E019C;VARIATION SELECTOR-173;Mn;0;NSM;;;;;N;;;;; +E019D;VARIATION SELECTOR-174;Mn;0;NSM;;;;;N;;;;; +E019E;VARIATION SELECTOR-175;Mn;0;NSM;;;;;N;;;;; +E019F;VARIATION SELECTOR-176;Mn;0;NSM;;;;;N;;;;; +E01A0;VARIATION SELECTOR-177;Mn;0;NSM;;;;;N;;;;; +E01A1;VARIATION SELECTOR-178;Mn;0;NSM;;;;;N;;;;; +E01A2;VARIATION SELECTOR-179;Mn;0;NSM;;;;;N;;;;; +E01A3;VARIATION SELECTOR-180;Mn;0;NSM;;;;;N;;;;; +E01A4;VARIATION SELECTOR-181;Mn;0;NSM;;;;;N;;;;; +E01A5;VARIATION SELECTOR-182;Mn;0;NSM;;;;;N;;;;; +E01A6;VARIATION SELECTOR-183;Mn;0;NSM;;;;;N;;;;; +E01A7;VARIATION SELECTOR-184;Mn;0;NSM;;;;;N;;;;; +E01A8;VARIATION SELECTOR-185;Mn;0;NSM;;;;;N;;;;; +E01A9;VARIATION SELECTOR-186;Mn;0;NSM;;;;;N;;;;; +E01AA;VARIATION SELECTOR-187;Mn;0;NSM;;;;;N;;;;; +E01AB;VARIATION SELECTOR-188;Mn;0;NSM;;;;;N;;;;; +E01AC;VARIATION SELECTOR-189;Mn;0;NSM;;;;;N;;;;; +E01AD;VARIATION SELECTOR-190;Mn;0;NSM;;;;;N;;;;; +E01AE;VARIATION SELECTOR-191;Mn;0;NSM;;;;;N;;;;; +E01AF;VARIATION SELECTOR-192;Mn;0;NSM;;;;;N;;;;; +E01B0;VARIATION SELECTOR-193;Mn;0;NSM;;;;;N;;;;; +E01B1;VARIATION SELECTOR-194;Mn;0;NSM;;;;;N;;;;; +E01B2;VARIATION SELECTOR-195;Mn;0;NSM;;;;;N;;;;; +E01B3;VARIATION SELECTOR-196;Mn;0;NSM;;;;;N;;;;; +E01B4;VARIATION SELECTOR-197;Mn;0;NSM;;;;;N;;;;; +E01B5;VARIATION SELECTOR-198;Mn;0;NSM;;;;;N;;;;; +E01B6;VARIATION SELECTOR-199;Mn;0;NSM;;;;;N;;;;; +E01B7;VARIATION SELECTOR-200;Mn;0;NSM;;;;;N;;;;; +E01B8;VARIATION SELECTOR-201;Mn;0;NSM;;;;;N;;;;; +E01B9;VARIATION SELECTOR-202;Mn;0;NSM;;;;;N;;;;; +E01BA;VARIATION SELECTOR-203;Mn;0;NSM;;;;;N;;;;; +E01BB;VARIATION SELECTOR-204;Mn;0;NSM;;;;;N;;;;; +E01BC;VARIATION SELECTOR-205;Mn;0;NSM;;;;;N;;;;; +E01BD;VARIATION SELECTOR-206;Mn;0;NSM;;;;;N;;;;; +E01BE;VARIATION SELECTOR-207;Mn;0;NSM;;;;;N;;;;; +E01BF;VARIATION SELECTOR-208;Mn;0;NSM;;;;;N;;;;; +E01C0;VARIATION SELECTOR-209;Mn;0;NSM;;;;;N;;;;; +E01C1;VARIATION SELECTOR-210;Mn;0;NSM;;;;;N;;;;; +E01C2;VARIATION SELECTOR-211;Mn;0;NSM;;;;;N;;;;; +E01C3;VARIATION SELECTOR-212;Mn;0;NSM;;;;;N;;;;; +E01C4;VARIATION SELECTOR-213;Mn;0;NSM;;;;;N;;;;; +E01C5;VARIATION SELECTOR-214;Mn;0;NSM;;;;;N;;;;; +E01C6;VARIATION SELECTOR-215;Mn;0;NSM;;;;;N;;;;; +E01C7;VARIATION SELECTOR-216;Mn;0;NSM;;;;;N;;;;; +E01C8;VARIATION SELECTOR-217;Mn;0;NSM;;;;;N;;;;; +E01C9;VARIATION SELECTOR-218;Mn;0;NSM;;;;;N;;;;; +E01CA;VARIATION SELECTOR-219;Mn;0;NSM;;;;;N;;;;; +E01CB;VARIATION SELECTOR-220;Mn;0;NSM;;;;;N;;;;; +E01CC;VARIATION SELECTOR-221;Mn;0;NSM;;;;;N;;;;; +E01CD;VARIATION SELECTOR-222;Mn;0;NSM;;;;;N;;;;; +E01CE;VARIATION SELECTOR-223;Mn;0;NSM;;;;;N;;;;; +E01CF;VARIATION SELECTOR-224;Mn;0;NSM;;;;;N;;;;; +E01D0;VARIATION SELECTOR-225;Mn;0;NSM;;;;;N;;;;; +E01D1;VARIATION SELECTOR-226;Mn;0;NSM;;;;;N;;;;; +E01D2;VARIATION SELECTOR-227;Mn;0;NSM;;;;;N;;;;; +E01D3;VARIATION SELECTOR-228;Mn;0;NSM;;;;;N;;;;; +E01D4;VARIATION SELECTOR-229;Mn;0;NSM;;;;;N;;;;; +E01D5;VARIATION SELECTOR-230;Mn;0;NSM;;;;;N;;;;; +E01D6;VARIATION SELECTOR-231;Mn;0;NSM;;;;;N;;;;; +E01D7;VARIATION SELECTOR-232;Mn;0;NSM;;;;;N;;;;; +E01D8;VARIATION SELECTOR-233;Mn;0;NSM;;;;;N;;;;; +E01D9;VARIATION SELECTOR-234;Mn;0;NSM;;;;;N;;;;; +E01DA;VARIATION SELECTOR-235;Mn;0;NSM;;;;;N;;;;; +E01DB;VARIATION SELECTOR-236;Mn;0;NSM;;;;;N;;;;; +E01DC;VARIATION SELECTOR-237;Mn;0;NSM;;;;;N;;;;; +E01DD;VARIATION SELECTOR-238;Mn;0;NSM;;;;;N;;;;; +E01DE;VARIATION SELECTOR-239;Mn;0;NSM;;;;;N;;;;; +E01DF;VARIATION SELECTOR-240;Mn;0;NSM;;;;;N;;;;; +E01E0;VARIATION SELECTOR-241;Mn;0;NSM;;;;;N;;;;; +E01E1;VARIATION SELECTOR-242;Mn;0;NSM;;;;;N;;;;; +E01E2;VARIATION SELECTOR-243;Mn;0;NSM;;;;;N;;;;; +E01E3;VARIATION SELECTOR-244;Mn;0;NSM;;;;;N;;;;; +E01E4;VARIATION SELECTOR-245;Mn;0;NSM;;;;;N;;;;; +E01E5;VARIATION SELECTOR-246;Mn;0;NSM;;;;;N;;;;; +E01E6;VARIATION SELECTOR-247;Mn;0;NSM;;;;;N;;;;; +E01E7;VARIATION SELECTOR-248;Mn;0;NSM;;;;;N;;;;; +E01E8;VARIATION SELECTOR-249;Mn;0;NSM;;;;;N;;;;; +E01E9;VARIATION SELECTOR-250;Mn;0;NSM;;;;;N;;;;; +E01EA;VARIATION SELECTOR-251;Mn;0;NSM;;;;;N;;;;; +E01EB;VARIATION SELECTOR-252;Mn;0;NSM;;;;;N;;;;; +E01EC;VARIATION SELECTOR-253;Mn;0;NSM;;;;;N;;;;; +E01ED;VARIATION SELECTOR-254;Mn;0;NSM;;;;;N;;;;; +E01EE;VARIATION SELECTOR-255;Mn;0;NSM;;;;;N;;;;; +E01EF;VARIATION SELECTOR-256;Mn;0;NSM;;;;;N;;;;; +F0000;;Co;0;L;;;;;N;;;;; +FFFFD;;Co;0;L;;;;;N;;;;; +100000;;Co;0;L;;;;;N;;;;; +10FFFD;;Co;0;L;;;;;N;;;;; diff --git a/tests/core/assets/UCD/license.txt b/tests/core/assets/UCD/license.txt new file mode 100644 index 000000000..56da58912 --- /dev/null +++ b/tests/core/assets/UCD/license.txt @@ -0,0 +1,39 @@ +UNICODE LICENSE V3 + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2026 Unicode, Inc. + +NOTICE TO USER: Carefully read the following legal agreement. BY +DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR +SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT +DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of data files and any associated documentation (the "Data Files") or +software and any associated documentation (the "Software") to deal in the +Data Files or Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, and/or sell +copies of the Data Files or Software, and to permit persons to whom the +Data Files or Software are furnished to do so, provided that either (a) +this copyright and permission notice appear with all copies of the Data +Files or Software, or (b) this copyright and permission notice appear in +associated Documentation. + +THE DATA FILES AND SOFTWARE ARE 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 OF +THIRD PARTY RIGHTS. + +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE +BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA +FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in these Data Files or Software without prior written +authorization of the copyright holder. diff --git a/tests/core/assets/Wycheproof/.gitignore b/tests/core/assets/Wycheproof/.gitignore new file mode 100644 index 000000000..94a2dd146 --- /dev/null +++ b/tests/core/assets/Wycheproof/.gitignore @@ -0,0 +1 @@ +*.json \ No newline at end of file diff --git a/tests/core/container/test_core_handle_map.odin b/tests/core/container/test_core_handle_map.odin new file mode 100644 index 000000000..1753ee91b --- /dev/null +++ b/tests/core/container/test_core_handle_map.odin @@ -0,0 +1,141 @@ +package test_core_container + +import hm "core:container/handle_map" +import "core:container/xar" +import "core:testing" + +Item :: struct { + v: int, + p: ^Item, + handle: hm.Handle32, + my_idx: u16, +} + +@test +test_dynamic_handle_map :: proc(t: ^testing.T) { + dhm: hm.Dynamic_Handle_Map(Item, hm.Handle32) + hm.dynamic_init(&dhm, context.allocator) + defer hm.dynamic_destroy(&dhm) + + items: [dynamic]Item + defer delete(items) + + N :: 512 + for i in 1..=N { + h, add_err := hm.dynamic_add(&dhm, Item{v = i * 10 + 1}) + assert(add_err == nil) + + item := hm.dynamic_get(&dhm, h) + item.handle = h + item.p = item + item.my_idx = h.idx + + append(&items, item^) + } + + testing.expect(t, hm.dynamic_len(dhm) == N) + testing.expect(t, hm.dynamic_cap(dhm) >= N) + + for v in items { + item := hm.dynamic_get(&dhm, v.handle) + assert(item^ == v) + + // Remove half of the items + if item.handle.idx & 1 == 0 { + found, found_err := hm.dynamic_remove(&dhm, v.handle) + assert(found && found_err == nil) + + // These removed handles should no longer be valid + assert(!hm.dynamic_is_valid(&dhm, v.handle)) + } else { + // Non-removed handles should still be valid + assert(hm.dynamic_is_valid(&dhm, v.handle)) + } + } + + testing.expect(t, hm.dynamic_len(dhm) == N / 2) + testing.expect(t, hm.dynamic_cap(dhm) >= N / 2) + testing.expect(t, xar.len(dhm.unused_items) == N / 2) + + it := hm.dynamic_iterator_make(&dhm) + for v, handle in hm.iterate(&it) { + assert(v.handle.idx & 1 == 1) + assert(hm.dynamic_is_valid(&dhm, handle)) + + item := hm.dynamic_get(&dhm, handle) + assert(item.my_idx == v.handle.idx) + } + + for i in 1..=N / 2 { + h, add_err := hm.dynamic_add(&dhm, Item{v = i * 10 + 1}) + assert(add_err == nil) + assert(h.gen == 2) + } + + hm.dynamic_clear(&dhm) + testing.expect(t, hm.dynamic_len(dhm) == 0) + testing.expect(t, hm.dynamic_cap(dhm) >= N) +} + +test_static_handle_map :: proc(t: ^testing.T) { + N :: 512 + + shm: hm.Static_Handle_Map(N, Item, hm.Handle32) + + items: [dynamic]Item + defer delete(items) + + + for i in 1..=N { + h, add_ok := hm.static_add(&shm, Item{v = i * 10 + 1}) + assert(add_ok) + + item := hm.static_get(&shm, h) + item.handle = h + item.p = item + item.my_idx = h.idx + + append(&items, item^) + } + + testing.expect(t, hm.static_len(shm) == N) + testing.expect(t, hm.static_cap(shm) >= N) + + for v in items { + item := hm.static_get(&shm, v.handle) + assert(item^ == v) + + // Remove half of the items + if item.handle.idx & 1 == 0 { + assert(hm.static_remove(&shm, v.handle)) + + // These removed handles should no longer be valid + assert(!hm.static_is_valid(shm, v.handle)) + } else { + // Non-removed handles should still be valid + assert(hm.static_is_valid(shm, v.handle)) + } + } + + testing.expect(t, hm.static_len(shm) == N / 2) + testing.expect(t, hm.static_cap(shm) >= N / 2) + + it := hm.static_iterator_make(&shm) + for v, handle in hm.iterate(&it) { + assert(v.handle.idx & 1 == 1) + assert(hm.static_is_valid(shm, handle)) + + item := hm.static_get(&shm, handle) + assert(item.my_idx == v.handle.idx) + } + + for i in 1..=N / 2 { + h, add_ok := hm.static_add(&shm, Item{v = i * 10 + 1}) + assert(add_ok) + assert(h.gen == 2) + } + + hm.static_clear(&shm) + testing.expect(t, hm.static_len(shm) == 0) + testing.expect(t, hm.static_cap(shm) == N) +} \ No newline at end of file diff --git a/tests/core/container/test_core_priority_queue.odin b/tests/core/container/test_core_priority_queue.odin new file mode 100644 index 000000000..417056d48 --- /dev/null +++ b/tests/core/container/test_core_priority_queue.odin @@ -0,0 +1,113 @@ +package test_core_container + +import "base:runtime" +import pq "core:container/priority_queue" +import "core:math/rand" +import "core:testing" + +@test +test_priority_queue :: proc(t: ^testing.T) { + q: pq.Priority_Queue(int) + pq.init(&q, proc(a, b: int) -> bool { + return a < b + }, pq.default_swap_proc(int)) + defer pq.destroy(&q) + + assert(pq.cap(q) == pq.DEFAULT_CAPACITY) + + pq.push(&q, 42) + assert(pq.len(q) == 1) + assert(pq.peek(q) == 42) + + v := pq.pop(&q) + assert(v == 42) + assert(pq.len(q) == 0) + + ok: bool + v, ok = pq.peek_safe(q) + assert(v == 0 && ok == false) + + v, ok = pq.pop_safe(&q) + assert(v == 0 && ok == false) + + N :: 15 + for _ in 0.. 0 { + v = pq.pop(&q) + assert(v >= last) + last = v + } + + vals := []int{6, 15, 3, 9, 12} + for _v in vals { + pq.push(&q, _v) + } + // Break ordering and fix it + q.queue[3] = 42 + pq.fix(&q, 3) + + last = 0 + for pq.len(q) > 0 { + v = pq.pop(&q) + assert(v >= last) + last = v + } + + assert(pq.len(q) == 0) + + for _v in vals { + pq.push(&q, _v) + } + + // Break ordering again, but this time delete that index + q.queue[3] = 42 + v, ok = pq.remove(&q, 3) + assert(v == 42 && ok == true) + + last = 0 + for pq.len(q) > 0 { + v = pq.pop(&q) + assert(v >= last && v != 42) + last = v + } +} + +@(test) +test_pq_init_from_dynamic_array :: proc(t: ^testing.T) { + N :: 50_000 + + arr := make_dynamic_array_len_cap([dynamic]u64, N, N, context.allocator) + assert(runtime.random_generator_read_ptr(context.random_generator, raw_data(arr), N * size_of(u64))) + + q: pq.Priority_Queue(u64) + pq.init_from_dynamic_array( + pq = &q, + queue = arr, + less = proc(a, b: u64) -> bool { return a < b }, + swap = pq.default_swap_proc(u64), + ) + defer pq.destroy(&q) + + assert(pq.len(q) == N) + + last: u64 + for pq.len(q) > 0 { + v := pq.pop(&q) + assert(v >= last) + last = v + } + + assert(pq.len(q) == 0) + assert(pq.cap(q) == N) + + pq.reserve(&q, N + 12) + assert(pq.cap(q) == N + 12) + +} \ No newline at end of file diff --git a/tests/core/container/queue.odin b/tests/core/container/test_core_queue.odin similarity index 100% rename from tests/core/container/queue.odin rename to tests/core/container/test_core_queue.odin diff --git a/tests/core/container/test_core_rbtree.odin b/tests/core/container/test_core_rbtree.odin index d220b7ed6..78d710b7f 100644 --- a/tests/core/container/test_core_rbtree.odin +++ b/tests/core/container/test_core_rbtree.odin @@ -4,22 +4,15 @@ import rb "core:container/rbtree" import "core:math/rand" import "core:testing" import "base:intrinsics" -import "core:mem" import "core:slice" import "core:log" test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { - track: mem.Tracking_Allocator - mem.tracking_allocator_init(&track, context.allocator) - track.bad_free_callback = mem.tracking_allocator_bad_free_callback_add_to_array - defer mem.tracking_allocator_destroy(&track) - context.allocator = mem.tracking_allocator(&track) - log.infof("Testing Red-Black Tree($Key=%v,$Value=%v) using random seed %v.", type_info_of(Key), type_info_of(Value), t.seed) tree: rb.Tree(Key, Value) rb.init(&tree) - testing.expect(t, rb.len(&tree) == 0, "empty: len should be 0") + testing.expect(t, rb.len(tree) == 0, "empty: len should be 0") testing.expect(t, rb.first(&tree) == nil, "empty: first should be nil") testing.expect(t, rb.last(&tree) == nil, "empty: last should be nil") iter := rb.iterator(&tree, .Forward) @@ -48,7 +41,7 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { } entry_count := len(inserted_map) - testing.expect(t, rb.len(&tree) == entry_count, "insert: len after") + testing.expect(t, rb.len(tree) == entry_count, "insert: len after") validate_rbtree(t, &tree) first := rb.first(&tree) @@ -58,8 +51,8 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { // Ensure that all entries can be found. for k, v in inserted_map { - testing.expect(t, v == rb.find(&tree, k), "Find(): Node") - testing.expect(t, k == v.key, "Find(): Node key") + testing.expect(t, v == rb.find(tree, k), "Find(): Node") + testing.expect(t, k == v.key, "Find(): Node key") } // Test the forward/backward iterators. @@ -97,17 +90,17 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { (^int)(user_data)^ -= 1 } for k, i in inserted_keys { - node := rb.find(&tree, k) + node := rb.find(tree, k) testing.expect(t, node != nil, "remove: find (pre)") ok := rb.remove(&tree, k) testing.expect(t, ok, "remove: succeeds") - testing.expect(t, entry_count - (i + 1) == rb.len(&tree), "remove: len (post)") + testing.expect(t, entry_count - (i + 1) == rb.len(tree), "remove: len (post)") validate_rbtree(t, &tree) - testing.expect(t, nil == rb.find(&tree, k), "remove: find (post") + testing.expect(t, nil == rb.find(tree, k), "remove: find (post") } - testing.expect(t, rb.len(&tree) == 0, "remove: len should be 0") + testing.expect(t, rb.len(tree) == 0, "remove: len should be 0") testing.expectf(t, callback_count == 0, "remove: on_remove should've been called %v times, it was %v", entry_count, callback_count) testing.expect(t, rb.first(&tree) == nil, "remove: first should be nil") testing.expect(t, rb.last(&tree) == nil, "remove: last should be nil") @@ -129,28 +122,25 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { ok = rb.iterator_remove(&iter) testing.expect(t, !ok, "iterator/remove: redundant removes should fail") - testing.expect(t, rb.find(&tree, k) == nil, "iterator/remove: node should be gone") + testing.expect(t, rb.find(tree, k) == nil, "iterator/remove: node should be gone") testing.expect(t, rb.iterator_get(&iter) == nil, "iterator/remove: get should return nil") // Ensure that iterator_next still works. node, ok = rb.iterator_next(&iter) - testing.expect(t, ok == (rb.len(&tree) > 0), "iterator/remove: next should return false") + testing.expect(t, ok == (rb.len(tree) > 0), "iterator/remove: next should return false") testing.expect(t, node == rb.first(&tree), "iterator/remove: next should return first") validate_rbtree(t, &tree) } - testing.expect(t, rb.len(&tree) == entry_count - 1, "iterator/remove: len should drop by 1") + testing.expect(t, rb.len(tree) == entry_count - 1, "iterator/remove: len should drop by 1") rb.destroy(&tree) - testing.expect(t, rb.len(&tree) == 0, "destroy: len should be 0") + testing.expect(t, rb.len(tree) == 0, "destroy: len should be 0") testing.expectf(t, callback_count == 0, "remove: on_remove should've been called %v times, it was %v", entry_count, callback_count) // print_tree_node(tree._root) delete(inserted_map) delete(inserted_keys) - testing.expectf(t, len(track.allocation_map) == 0, "Expected 0 leaks, have %v", len(track.allocation_map)) - testing.expectf(t, len(track.bad_free_array) == 0, "Expected 0 bad frees, have %v", len(track.bad_free_array)) - return } @(test) diff --git a/tests/core/container/test_core_xar.odin b/tests/core/container/test_core_xar.odin new file mode 100644 index 000000000..ee9318097 --- /dev/null +++ b/tests/core/container/test_core_xar.odin @@ -0,0 +1,39 @@ +package test_core_container + +import "core:container/xar" +import "core:testing" + +@test +test_xar_pointer_stability :: proc(t: ^testing.T) { + Value :: struct { + v: int, + p: ^int, + } + + x: xar.Array(int, 4) + defer xar.destroy(&x) + + values: [dynamic]Value + defer delete(values) + + N :: 512 + for i in 1..=N { + v := i * 10 + 1 + xar.push_back(&x, v) + ptr := xar.get_ptr(&x, i - 1) + append(&values, Value{v = v, p = ptr}) + } + + assert(xar.len(x) == N) + assert(xar.cap(x) >= N) + + for value, i in values { + ptr := xar.get_ptr(&x, i) + assert(ptr == value.p) + assert(ptr^ == value.v) + } + + xar.clear(&x) + assert(xar.len(x) == 0) + assert(xar.cap(x) >= N) +} \ No newline at end of file diff --git a/tests/core/crypto/test_core_crypto_ecdh.odin b/tests/core/crypto/test_core_crypto_ecdh.odin new file mode 100644 index 000000000..e34671c84 --- /dev/null +++ b/tests/core/crypto/test_core_crypto_ecdh.odin @@ -0,0 +1,167 @@ +package test_core_crypto + +import "core:encoding/hex" +import "core:testing" + +import "core:crypto/ecdh" + +@(test) +test_ecdh :: proc(t: ^testing.T) { + test_vectors := []struct { + curve: ecdh.Curve, + scalar: string, + point: string, + product: string, + } { + // X25519 Test vectors from RFC 7748 + { + .X25519, + "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4", + "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c", + "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552", + }, + { + .X25519, + "4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d", + "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493", + "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957", + }, + // X448 Test vectors from RFC 7748 + { + .X448, + "3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3", + "06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086", + "ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f", + }, + { + .X448, + "203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f", + "0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db", + "884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d", + }, + // secp256r1 Test vectors (subset) from NIST CAVP + { + .SECP256R1, + "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534", + "04700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac", + "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b", + }, + { + .SECP256R1, + "38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5", + "04809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7aeb29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3", + "057d636096cb80b67a8c038c890e887d1adfa4195e9b3ce241c8a778c59cda67", + }, + // secp384r1 Test vectors (subset) from NIST CAVP + { + .SECP384R1, + "3cc3122a68f0d95027ad38c067916ba0eb8c38894d22e1b15618b6818a661774ad463b205da88cf699ab4d43c9cf98a1", + "04a7c76b970c3b5fe8b05d2838ae04ab47697b9eaf52e764592efda27fe7513272734466b400091adbf2d68c58e0c50066ac68f19f2e1cb879aed43a9969b91a0839c4c38a49749b661efedf243451915ed0905a32b060992b468c64766fc8437a", + "5f9d29dc5e31a163060356213669c8ce132e22f57c9a04f40ba7fcead493b457e5621e766c40a2e3d4d6a04b25e533f1", + }, + { + .SECP384R1, + "92860c21bde06165f8e900c687f8ef0a05d14f290b3f07d8b3a8cc6404366e5d5119cd6d03fb12dc58e89f13df9cd783", + "0430f43fcf2b6b00de53f624f1543090681839717d53c7c955d1d69efaf0349b7363acb447240101cbb3af6641ce4b88e025e46c0c54f0162a77efcc27b6ea792002ae2ba82714299c860857a68153ab62e525ec0530d81b5aa15897981e858757", + "a23742a2c267d7425fda94b93f93bbcc24791ac51cd8fd501a238d40812f4cbfc59aac9520d758cf789c76300c69d2ff", + }, + } + + for v, _ in test_vectors { + raw_scalar, _ := hex.decode(transmute([]byte)(v.scalar), context.temp_allocator) + raw_point, _ := hex.decode(transmute([]byte)(v.point), context.temp_allocator) + + pub_key: ecdh.Public_Key + priv_key: ecdh.Private_Key + + ok := ecdh.private_key_set_bytes(&priv_key, v.curve, raw_scalar) + testing.expectf(t, ok, "failed to deserialize private key: %v %x", v.curve, raw_scalar) + + ok = ecdh.public_key_set_bytes(&pub_key, v.curve, raw_point) + testing.expectf(t, ok, "failed to deserialize public key: %v %x", v.curve, raw_scalar) + + shared_secret := make([]byte, ecdh.shared_secret_size(&pub_key), context.temp_allocator) + ok = ecdh.ecdh(&priv_key, &pub_key, shared_secret) + testing.expectf(t, ok, "ecdh failed: %v %v %v", v.curve, &priv_key, &pub_key) + + ss_str := string(hex.encode(shared_secret, context.temp_allocator)) + testing.expectf( + t, + ss_str == v.product, + "Expected %s for %v %s * %s, but got %s instead", + v.product, + v.curve, + v.scalar, + v.point, + ss_str, + ) + } +} + +@(test) +test_ecdh_scalar_basemult :: proc(t: ^testing.T) { + test_vectors := []struct { + curve: ecdh.Curve, + scalar : string, + point: string, + } { + // X25519 from RFC 7748 6.1 + { + .X25519, + "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a", + "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a", + }, + { + .X25519, + "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb", + "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f", + }, + // X448 from RFC 7748 6.2 + { + .X448, + "9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b", + "9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0", + }, + { + .X448, + "1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d", + "3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609", + }, + // secp256r1 Test vectors (subset) from NIST CAVP + { + .SECP256R1, + "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534", + "04ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b23028af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141", + }, + { + .SECP256R1, + "38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5", + "04119f2f047902782ab0c9e27a54aff5eb9b964829ca99c06b02ddba95b0a3f6d08f52b726664cac366fc98ac7a012b2682cbd962e5acb544671d41b9445704d1d", + }, + } + + for v, _ in test_vectors { + raw_scalar, _ := hex.decode(transmute([]byte)(v.scalar), context.temp_allocator) + + priv_key: ecdh.Private_Key + pub_key: ecdh.Public_Key + + ok := ecdh.private_key_set_bytes(&priv_key, v.curve, raw_scalar) + testing.expectf(t, ok, "failed to deserialize private key: %v %x", v.curve, raw_scalar) + + ecdh.public_key_set_priv(&pub_key, &priv_key) + b := make([]byte, ecdh.key_size(&pub_key), context.temp_allocator) + ecdh.public_key_bytes(&pub_key, b) + + pub_str := string(hex.encode(b, context.temp_allocator)) + testing.expectf( + t, + pub_str == v.point, + "Expected %s for %v %s * G, but got %s instead", + v.point, + v.curve, + v.scalar, + pub_str, + ) + } +} \ No newline at end of file diff --git a/tests/core/crypto/test_core_crypto_edwards.odin b/tests/core/crypto/test_core_crypto_edwards.odin index 61933c00f..2983e6cbb 100644 --- a/tests/core/crypto/test_core_crypto_edwards.odin +++ b/tests/core/crypto/test_core_crypto_edwards.odin @@ -4,13 +4,10 @@ import "core:encoding/hex" import "core:testing" import field "core:crypto/_fiat/field_curve25519" -import "core:crypto/ed25519" import "core:crypto/ristretto255" -import "core:crypto/x25519" -import "core:crypto/x448" @(test) -test_sqrt_ratio_m1 :: proc(t: ^testing.T) { +test_edwards25519_sqrt_ratio_m1 :: proc(t: ^testing.T) { test_vectors := []struct { u: string, v: string, @@ -320,443 +317,16 @@ test_ristretto255 :: proc(t: ^testing.T) { } } -@(test) -test_ed25519 :: proc(t: ^testing.T) { - test_vectors_rfc := []struct { - priv_key: string, - pub_key: string, - msg: string, - sig: string, - } { - // Test vectors from RFC 8032 - { - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", - "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", - "", - "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b", - }, - { - "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb", - "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c", - "72", - "92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00", - }, - { - "c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7", - "fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025", - "af82", - "6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a", - }, - // TEST 1024 omitted for brevity, because all that does is add more to SHA-512 - { - "833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42", - "ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf", - "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", - "dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b58909351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704", - }, - } - for v, _ in test_vectors_rfc { - priv_bytes, _ := hex.decode(transmute([]byte)(v.priv_key), context.temp_allocator) - pub_bytes, _ := hex.decode(transmute([]byte)(v.pub_key), context.temp_allocator) - msg_bytes, _ := hex.decode(transmute([]byte)(v.msg), context.temp_allocator) - sig_bytes, _ := hex.decode(transmute([]byte)(v.sig), context.temp_allocator) - - priv_key: ed25519.Private_Key - ok := ed25519.private_key_set_bytes(&priv_key, priv_bytes) - testing.expectf( - t, - ok, - "Expected %s to be a valid private key", - v.priv_key, - ) - - key_bytes: [32]byte - ed25519.private_key_bytes(&priv_key, key_bytes[:]) - testing.expectf( - t, - ok, - "Expected private key %s round-trip, got %s", - v.priv_key, - string(hex.encode(key_bytes[:], context.temp_allocator)), - ) - - pub_key: ed25519.Public_Key - ok = ed25519.public_key_set_bytes(&pub_key, pub_bytes) - testing.expectf( - t, - ok, - "Expected %s to be a valid public key (priv->pub: %s)", - v.pub_key, - string(hex.encode(priv_key._pub_key._b[:], context.temp_allocator)), - ) - - ed25519.public_key_bytes(&pub_key, key_bytes[:]) - testing.expectf( - t, - ok, - "Expected public key %s round-trip, got %s", - v.pub_key, - string(hex.encode(key_bytes[:], context.temp_allocator)), - ) - - sig: [ed25519.SIGNATURE_SIZE]byte - ed25519.sign(&priv_key, msg_bytes, sig[:]) - x := string(hex.encode(sig[:], context.temp_allocator)) - testing.expectf( - t, - x == v.sig, - "Expected %s for sign(%s, %s), got %s", - v.sig, - v.priv_key, - v.msg, - x, - ) - - ok = ed25519.verify(&pub_key, msg_bytes, sig_bytes) - testing.expectf( - t, - ok, - "Expected true for verify(%s, %s, %s)", - v.pub_key, - v.msg, - v.sig, - ) - - ok = ed25519.verify(&priv_key._pub_key, msg_bytes, sig_bytes) - testing.expectf( - t, - ok, - "Expected true for verify(pub(%s), %s %s)", - v.priv_key, - v.msg, - v.sig, - ) - - // Corrupt the message and make sure verification fails. - switch len(msg_bytes) { - case 0: - tmp_msg := []byte{69} - msg_bytes = tmp_msg[:] - case: - msg_bytes[0] = msg_bytes[0] ~ 69 - } - ok = ed25519.verify(&pub_key, msg_bytes, sig_bytes) - testing.expectf( - t, - ok == false, - "Expected false for verify(%s, %s (corrupted), %s)", - v.pub_key, - v.msg, - v.sig, - ) - } - - // Test cases from "Taming the many EdDSAs", which aim to exercise - // all of the ed25519 edge cases/implementation differences. - // - // - https://eprint.iacr.org/2020/1244 - // - https://github.com/novifinancial/ed25519-speccheck - test_vectors_speccheck := []struct { - pub_key: string, - msg: string, - sig: string, - pub_key_ok: bool, - sig_ok: bool, - sig_ok_relaxed: bool, // Ok if the small-order A check is relaxed. - } { - // S = 0, small-order A, small-order R - { - "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", - "8c93255d71dcab10e8f379c26200f3c7bd5f09d9bc3068d3ef4edeb4853022b6", - "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", - true, - false, - true, - }, - // 0 < S < L, small-order A, mixed-order R - { - "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", - "9bd9f44f4dcc75bd531b56b2cd280b0bb38fc1cd6d1230e14861d861de092e79", - "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43a5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04", - true, - false, - true, - }, - // 0 < S < L, mixed-order A, small-order R - { - "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43", - "aebf3f2601a0c8c5d39cc7d8911642f740b78168218da8471772b35f9d35b9ab", - "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa8c4bd45aecaca5b24fb97bc10ac27ac8751a7dfe1baff8b953ec9f5833ca260e", - true, - true, - true, - }, - // 0 < S < L, mixed-order A, mixed-order R - { - "cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d", - "9bd9f44f4dcc75bd531b56b2cd280b0bb38fc1cd6d1230e14861d861de092e79", - "9046a64750444938de19f227bb80485e92b83fdb4b6506c160484c016cc1852f87909e14428a7a1d62e9f22f3d3ad7802db02eb2e688b6c52fcd6648a98bd009", - true, - true, - true, - }, - // 0 < S < L, mixed-order A, mixed-order R - { - "cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d", - "e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec4011eaccd55b53f56c", - "160a1cb0dc9c0258cd0a7d23e94d8fa878bcb1925f2c64246b2dee1796bed5125ec6bc982a269b723e0668e540911a9a6a58921d6925e434ab10aa7940551a09", - true, - true, // cofactored-only - true, - }, - // 0 < S < L, mixed-order A, L-order R - { - "cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d", - "e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec4011eaccd55b53f56c", - "21122a84e0b5fca4052f5b1235c80a537878b38f3142356b2c2384ebad4668b7e40bc836dac0f71076f9abe3a53f9c03c1ceeeddb658d0030494ace586687405", - true, - true, // cofactored only, (fail if 8h is pre-reduced) - true, - }, - // S > L, L-order A, L-order R - { - "442aad9f089ad9e14647b1ef9099a1ff4798d78589e66f28eca69c11f582a623", - "85e241a07d148b41e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec40", - "e96f66be976d82e60150baecff9906684aebb1ef181f67a7189ac78ea23b6c0e547f7690a0e2ddcd04d87dbc3490dc19b3b3052f7ff0538cb68afb369ba3a514", - true, - false, - false, - }, - // S >> L, L-order A, L-order R - { - "442aad9f089ad9e14647b1ef9099a1ff4798d78589e66f28eca69c11f582a623", - "85e241a07d148b41e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec40", - "8ce5b96c8f26d0ab6c47958c9e68b937104cd36e13c33566acd2fe8d38aa19427e71f98a473474f2f13f06f97c20d58cc3f54b8bd0d272f42b695dd7e89a8c22", - true, - false, - false, - }, - // 0 < S < L, mixed-order A, small-order R (non-canonical R, reduced for hash) - { - "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43", - "9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41", - "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03be9678ac102edcd92b0210bb34d7428d12ffc5df5f37e359941266a4e35f0f", - true, - false, - false, - }, - // 0 < S < L, mixed-order A, small-order R (non-canonical R, not reduced for hash) - { - "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43", - "9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41", - "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffca8c5b64cd208982aa38d4936621a4775aa233aa0505711d8fdcfdaa943d4908", - true, - false, - false, - }, - // 0 < S < L, small-order A, mixed-order R (non-canonical A, reduced for hash) - { - "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "e96b7021eb39c1a163b6da4e3093dcd3f21387da4cc4572be588fafae23c155b", - "a9d55260f765261eb9b84e106f665e00b867287a761990d7135963ee0a7d59dca5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04", - false, - false, - false, - }, - // 0 < S < L, small-order A, mixed-order R (non-canonical A, not reduced for hash) - { - "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "39a591f5321bbe07fd5a23dc2f39d025d74526615746727ceefd6e82ae65c06f", - "a9d55260f765261eb9b84e106f665e00b867287a761990d7135963ee0a7d59dca5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04", - false, - false, - false, - }, - } - for v, i in test_vectors_speccheck { - pub_bytes, _ := hex.decode(transmute([]byte)(v.pub_key), context.temp_allocator) - msg_bytes, _ := hex.decode(transmute([]byte)(v.msg), context.temp_allocator) - sig_bytes, _ := hex.decode(transmute([]byte)(v.sig), context.temp_allocator) - - pub_key: ed25519.Public_Key - ok := ed25519.public_key_set_bytes(&pub_key, pub_bytes) - testing.expectf( - t, - ok == v.pub_key_ok, - "speccheck/%d: Expected %s to be a (in)valid public key, got %v", - i, - v.pub_key, - ok, - ) - - // If A is rejected for being non-canonical, skip signature check. - if !v.pub_key_ok { - continue - } - - ok = ed25519.verify(&pub_key, msg_bytes, sig_bytes) - testing.expectf( - t, - ok == v.sig_ok, - "speccheck/%d Expected %v for verify(%s, %s, %s)", - i, - v.sig_ok, - v.pub_key, - v.msg, - v.sig, - ) - - // If the signature is accepted, skip the relaxed signature check. - if v.sig_ok { - continue - } - - ok = ed25519.verify(&pub_key, msg_bytes, sig_bytes, true) - testing.expectf( - t, - ok == v.sig_ok_relaxed, - "speccheck/%d Expected %v for verify(%s, %s, %s, true)", - i, - v.sig_ok_relaxed, - v.pub_key, - v.msg, - v.sig, - ) - } -} - -@(test) -test_x25519 :: proc(t: ^testing.T) { - // Local copy of this so that the base point doesn't need to be exported. - _BASE_POINT: [32]byte = { - 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - } - - test_vectors := []struct { - scalar: string, - point: string, - product: string, - } { - // Test vectors from RFC 7748 - { - "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4", - "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c", - "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552", - }, - { - "4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d", - "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493", - "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957", - }, - } - for v, _ in test_vectors { - scalar, _ := hex.decode(transmute([]byte)(v.scalar), context.temp_allocator) - point, _ := hex.decode(transmute([]byte)(v.point), context.temp_allocator) - - derived_point: [x25519.POINT_SIZE]byte - x25519.scalarmult(derived_point[:], scalar[:], point[:]) - derived_point_str := string(hex.encode(derived_point[:], context.temp_allocator)) - - testing.expectf( - t, - derived_point_str == v.product, - "Expected %s for %s * %s, but got %s instead", - v.product, - v.scalar, - v.point, - derived_point_str, - ) - - // Abuse the test vectors to sanity-check the scalar-basepoint multiply. - p1, p2: [x25519.POINT_SIZE]byte - x25519.scalarmult_basepoint(p1[:], scalar[:]) - x25519.scalarmult(p2[:], scalar[:], _BASE_POINT[:]) - p1_str := string(hex.encode(p1[:], context.temp_allocator)) - p2_str := string(hex.encode(p2[:], context.temp_allocator)) - testing.expectf( - t, - p1_str == p2_str, - "Expected %s for %s * basepoint, but got %s instead", - p2_str, - v.scalar, - p1_str, - ) - } -} - -@(test) -test_x448 :: proc(t: ^testing.T) { - // Local copy of this so that the base point doesn't need to be exported. - _BASE_POINT: [56]byte = { - 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - } - - test_vectors := []struct { - scalar: string, - point: string, - product: string, - } { - // Test vectors from RFC 7748 - { - "3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3", - "06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086", - "ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f", - }, - { - "203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f", - "0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db", - "884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d", - }, - } - for v, _ in test_vectors { - scalar, _ := hex.decode(transmute([]byte)(v.scalar), context.temp_allocator) - point, _ := hex.decode(transmute([]byte)(v.point), context.temp_allocator) - - derived_point: [x448.POINT_SIZE]byte - x448.scalarmult(derived_point[:], scalar[:], point[:]) - derived_point_str := string(hex.encode(derived_point[:], context.temp_allocator)) - - testing.expectf( - t, - derived_point_str == v.product, - "Expected %s for %s * %s, but got %s instead", - v.product, - v.scalar, - v.point, - derived_point_str, - ) - - // Abuse the test vectors to sanity-check the scalar-basepoint multiply. - p1, p2: [x448.POINT_SIZE]byte - x448.scalarmult_basepoint(p1[:], scalar[:]) - x448.scalarmult(p2[:], scalar[:], _BASE_POINT[:]) - p1_str := string(hex.encode(p1[:], context.temp_allocator)) - p2_str := string(hex.encode(p2[:], context.temp_allocator)) - testing.expectf( - t, - p1_str == p2_str, - "Expected %s for %s * basepoint, but got %s instead", - p2_str, - v.scalar, - p1_str, - ) - } -} - -@(private) +@(private="file") ge_str :: proc(ge: ^ristretto255.Group_Element) -> string { b: [ristretto255.ELEMENT_SIZE]byte ristretto255.ge_bytes(ge, b[:]) return string(hex.encode(b[:], context.temp_allocator)) } -@(private) +@(private="file") fe_str :: proc(fe: ^field.Tight_Field_Element) -> string { b: [32]byte field.fe_to_bytes(&b, fe) return string(hex.encode(b[:], context.temp_allocator)) -} \ No newline at end of file +} diff --git a/tests/core/crypto/test_core_crypto_exdsa.odin b/tests/core/crypto/test_core_crypto_exdsa.odin new file mode 100644 index 000000000..944f8747a --- /dev/null +++ b/tests/core/crypto/test_core_crypto_exdsa.odin @@ -0,0 +1,568 @@ +package test_core_crypto + +import "core:bytes" +import "core:encoding/hex" +import "core:testing" + +import "core:crypto" +import "core:crypto/ecdsa" +import "core:crypto/ed25519" +import "core:crypto/hash" + +@(test) +test_ecdsa :: proc(t: ^testing.T) { + test_vectors_deterministic := []struct{ + curve: ecdsa.Curve, + hash: hash.Algorithm, + priv_key: string, + pub_key: string, + msg: string, + sig_raw: string, + } { + // Test vectors from RFC 6979 + { + .SECP256R1, + .SHA256, + "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", + "0460fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb67903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299", + "sample", + "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8", + }, + { + .SECP256R1, + .SHA384, + "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", + "0460fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb67903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299", + "sample", + "0eafea039b20e9b42309fb1d89e213057cbf973dc0cfc8f129edddc800ef77194861f0491e6998b9455193e34e7b0d284ddd7149a74b95b9261f13abde940954", + }, + { + .SECP256R1, + .SHA512, + "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", + "0460fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb67903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299", + "sample", + "8496a60b5e9b47c825488827e0495b0e3fa109ec4568fd3f8d1097678eb97f002362ab1adbe2b8adf9cb9edab740ea6049c028114f2460f96554f61fae3302fe", + }, + { + .SECP256R1, + .SHA256, + "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", + "0460fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb67903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299", + "test", + "f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367019f4113742a2b14bd25926b49c649155f267e60d3814b4c0cc84250e46f0083", + }, + { + .SECP256R1, + .SHA384, + "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", + "0460fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb67903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299", + "test", + "83910e8b48bb0c74244ebdf7f07a1c5413d61472bd941ef3920e623fbccebeb68ddbec54cf8cd5874883841d712142a56a8d0f218f5003cb0296b6b509619f2c", + }, + { + .SECP256R1, + .SHA512, + "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", + "0460fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb67903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299", + "test", + "461d93f31b6540894788fd206c07cfa0cc35f46fa3c91816fff1040ad1581a0439af9f15de0db8d97e72719c74820d304ce5226e32dedae67519e840d1194e55", + }, + { + .SECP384R1, + .SHA384, + "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d896d5724e4c70a825f872c9ea60d2edf5", + "04ec3a4e415b4e19a4568618029f427fa5da9a8bc4ae92e02e06aae5286b300c64def8f0ea9055866064a254515480bc138015d9b72d7d57244ea8ef9ac0c621896708a59367f9dfb9f54ca84b3f1c9db1288b231c3ae0d4fe7344fd2533264720", + "sample", + "94edbb92a5ecb8aad4736e56c691916b3f88140666ce9fa73d64c4ea95ad133c81a648152e44acf96e36dd1e80fabe4699ef4aeb15f178cea1fe40db2603138f130e740a19624526203b6351d0a3a94fa329c145786e679e7b82c71a38628ac8", + }, + { + .SECP384R1, + .SHA512, + "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d896d5724e4c70a825f872c9ea60d2edf5", + "04ec3a4e415b4e19a4568618029f427fa5da9a8bc4ae92e02e06aae5286b300c64def8f0ea9055866064a254515480bc138015d9b72d7d57244ea8ef9ac0c621896708a59367f9dfb9f54ca84b3f1c9db1288b231c3ae0d4fe7344fd2533264720", + "sample", + "ed0959d5880ab2d869ae7f6c2915c6d60f96507f9cb3e047c0046861da4a799cfe30f35cc900056d7c99cd7882433709512c8cceee3890a84058ce1e22dbc2198f42323ce8aca9135329f03c068e5112dc7cc3ef3446defceb01a45c2667fdd5", + }, + { + .SECP384R1, + .SHA384, + "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d896d5724e4c70a825f872c9ea60d2edf5", + "04ec3a4e415b4e19a4568618029f427fa5da9a8bc4ae92e02e06aae5286b300c64def8f0ea9055866064a254515480bc138015d9b72d7d57244ea8ef9ac0c621896708a59367f9dfb9f54ca84b3f1c9db1288b231c3ae0d4fe7344fd2533264720", + "test", + "8203b63d3c853e8d77227fb377bcf7b7b772e97892a80f36ab775d509d7a5feb0542a7f0812998da8f1dd3ca3cf023dbddd0760448d42d8a43af45af836fce4de8be06b485e9b61b827c2f13173923e06a739f040649a667bf3b828246baa5a5", + }, + { + .SECP384R1, + .SHA512, + "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d896d5724e4c70a825f872c9ea60d2edf5", + "04ec3a4e415b4e19a4568618029f427fa5da9a8bc4ae92e02e06aae5286b300c64def8f0ea9055866064a254515480bc138015d9b72d7d57244ea8ef9ac0c621896708a59367f9dfb9f54ca84b3f1c9db1288b231c3ae0d4fe7344fd2533264720", + "test", + "a0d5d090c9980faf3c2ce57b7ae951d31977dd11c775d314af55f76c676447d06fb6495cd21b4b6e340fc236584fb277976984e59b4c77b0e8e4460dca3d9f20e07b9bb1f63beefaf576f6b2e8b224634a2092cd3792e0159ad9cee37659c736", + }, + // Special case that exercises the rejection sampling. + // https://github.com/C2SP/CCTV/tree/main/RFC6979 + { + .SECP256R1, + .SHA256, + "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", + "0460fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb67903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299", + "wv[vnX", + "efd9073b652e76da1b5a019c0e4a2e3fa529b035a6abb91ef67f0ed7a1f212343db4706c9d9f4a4fe13bb5e08ef0fab53a57dbab2061c83a35fa411c68d2ba33", + }, + } + for v, _ in test_vectors_deterministic { + priv_bytes, _ := hex.decode(transmute([]byte)(v.priv_key), context.temp_allocator) + pub_bytes, _ := hex.decode(transmute([]byte)(v.pub_key), context.temp_allocator) + msg_bytes := bytes.clone(transmute([]byte)(v.msg), context.temp_allocator) + sig_bytes, _ := hex.decode(transmute([]byte)(v.sig_raw), context.temp_allocator) + + priv_key: ecdsa.Private_Key + ok := ecdsa.private_key_set_bytes(&priv_key, v.curve, priv_bytes) + testing.expectf( + t, + ok, + "Expected %s to be a valid %v private key", + v.priv_key, + v.curve, + ) + + priv_key_bytes := make([]byte, ecdsa.PRIVATE_KEY_SIZES[v.curve], context.temp_allocator) + ecdsa.private_key_bytes(&priv_key, priv_key_bytes) + priv_s := string(hex.encode(priv_key_bytes, context.temp_allocator)) + testing.expectf( + t, + priv_s == v.priv_key, + "Expected private key %s round-trip, got %s", + v.priv_key, + priv_s, + ) + + pub_key: ecdsa.Public_Key + ok = ecdsa.public_key_set_bytes(&pub_key, v.curve, pub_bytes) + testing.expectf( + t, + ok, + "Expected %s to be a valid %s public key", + v.pub_key, + v.curve, + ) + + pub_key_bytes := make([]byte, ecdsa.PUBLIC_KEY_SIZES[v.curve], context.temp_allocator) + ecdsa.public_key_bytes(&pub_key, pub_key_bytes) + pub_s := string(hex.encode(pub_key_bytes, context.temp_allocator)) + testing.expectf( + t, + pub_s == v.pub_key, + "Expected public key %s round-trip, got %s", + v.pub_key, + pub_s, + ) + + priv_pub_key: ecdsa.Public_Key + ecdsa.public_key_set_priv(&priv_pub_key, &priv_key) + ok = ecdsa.public_key_equal(&pub_key, &priv_pub_key) + testing.expectf( + t, + ok, + "Expected %v to be %s's public key", + &priv_pub_key, + v.priv_key, + ) + + ok = ecdsa.verify_raw(&pub_key, v.hash, msg_bytes, sig_bytes) + testing.expectf( + t, + ok, + "Expected true for verify(%s, %v, %s, %s)", + v.pub_key, + v.hash, + v.msg, + v.sig_raw, + ) + + // Signatures are deterministic for these test cases. + sig := make([]byte, ecdsa.RAW_SIGNATURE_SIZES[v.curve], context.temp_allocator) + ok = ecdsa.sign_raw(&priv_key, v.hash, msg_bytes, sig, true) + x := string(hex.encode(sig[:], context.temp_allocator)) + testing.expectf( + t, + ok && x == v.sig_raw, + "Expected %s for sign(%s, %v, %s), got %s", + v.sig_raw, + v.priv_key, + v.hash, + v.msg, + x, + ) + + // But when possible, we also add entropy by default. + when crypto.HAS_RAND_BYTES { + ok = ecdsa.sign_raw(&priv_key, v.hash, msg_bytes, sig) + x = string(hex.encode(sig[:], context.temp_allocator)) + testing.expectf( + t, + ok && x != v.sig_raw, + "Expected not %s for sign(%s, %v, %s), got %s", + v.sig_raw, + v.priv_key, + v.hash, + v.msg, + x, + ) + } + + // Corrupt the message and make sure verification fails. + msg_bytes[0] ~= 0x69 + ok = ecdsa.verify_raw(&pub_key, v.hash, msg_bytes, sig_bytes) + testing.expectf( + t, + ok == false, + "Expected false for verify(%s, %v %s (corrupted), %s)", + v.pub_key, + v.hash, + v.msg, + v.sig_raw, + ) + } + + // ASN.1 tests requires entorpy. + when crypto.HAS_RAND_BYTES == false { + return + } + msg_str : string : "Feed the Fire. Let the Last Cinders Burn." + for _ in 0 ..< 1000 { + msg := transmute([]byte)(msg_str) + + priv_key: ecdsa.Private_Key + ok := ecdsa.private_key_generate(&priv_key, .SECP256R1) + testing.expectf(t, ok, "Failed to generate private key") + + sig: []byte + sig, ok = ecdsa.sign_asn1(&priv_key, .SHA256, msg, context.temp_allocator) + testing.expectf( + t, + ok && len(sig) > 0, + "Failed for sign(%v, secp256r1/SHA256, %s)", + priv_key, + msg, + ) + + pub_key := &priv_key._pub_key + ok = ecdsa.verify_asn1(pub_key, .SHA256, msg, sig) + testing.expectf( + t, + ok, + "Expected true for verify(%v, SHA256, %s, %x)", + pub_key, + msg, + sig, + ) + } +} + +@(test) +test_ed25519 :: proc(t: ^testing.T) { + test_vectors_rfc := []struct { + priv_key: string, + pub_key: string, + msg: string, + sig: string, + } { + // Test vectors from RFC 8032 + { + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", + "", + "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b", + }, + { + "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb", + "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c", + "72", + "92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00", + }, + { + "c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7", + "fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025", + "af82", + "6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a", + }, + // TEST 1024 omitted for brevity, because all that does is add more to SHA-512 + { + "833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42", + "ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf", + "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", + "dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b58909351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704", + }, + } + for v, _ in test_vectors_rfc { + priv_bytes, _ := hex.decode(transmute([]byte)(v.priv_key), context.temp_allocator) + pub_bytes, _ := hex.decode(transmute([]byte)(v.pub_key), context.temp_allocator) + msg_bytes, _ := hex.decode(transmute([]byte)(v.msg), context.temp_allocator) + sig_bytes, _ := hex.decode(transmute([]byte)(v.sig), context.temp_allocator) + + priv_key: ed25519.Private_Key + ok := ed25519.private_key_set_bytes(&priv_key, priv_bytes) + testing.expectf( + t, + ok, + "Expected %s to be a valid private key", + v.priv_key, + ) + + key_bytes: [32]byte + ed25519.private_key_bytes(&priv_key, key_bytes[:]) + priv_s := string(hex.encode(key_bytes[:], context.temp_allocator)) + testing.expectf( + t, + priv_s == v.priv_key, + "Expected private key %s round-trip, got %s", + v.priv_key, + priv_s, + ) + + pub_key: ed25519.Public_Key + ok = ed25519.public_key_set_bytes(&pub_key, pub_bytes) + testing.expectf( + t, + ok, + "Expected %s to be a valid public key (priv->pub: %s)", + v.pub_key, + ) + + ed25519.public_key_bytes(&pub_key, key_bytes[:]) + pub_s := string(hex.encode(priv_key._pub_key._b[:], context.temp_allocator)) + testing.expectf( + t, + pub_s == v.pub_key, + "Expected public key %s round-trip, got %s", + v.pub_key, + pub_s, + ) + + sig: [ed25519.SIGNATURE_SIZE]byte + ed25519.sign(&priv_key, msg_bytes, sig[:]) + x := string(hex.encode(sig[:], context.temp_allocator)) + testing.expectf( + t, + x == v.sig, + "Expected %s for sign(%s, %s), got %s", + v.sig, + v.priv_key, + v.msg, + x, + ) + + ok = ed25519.verify(&pub_key, msg_bytes, sig_bytes) + testing.expectf( + t, + ok, + "Expected true for verify(%s, %s, %s)", + v.pub_key, + v.msg, + v.sig, + ) + + ok = ed25519.verify(&priv_key._pub_key, msg_bytes, sig_bytes) + testing.expectf( + t, + ok, + "Expected true for verify(pub(%s), %s %s)", + v.priv_key, + v.msg, + v.sig, + ) + + // Corrupt the message and make sure verification fails. + switch len(msg_bytes) { + case 0: + tmp_msg := []byte{69} + msg_bytes = tmp_msg[:] + case: + msg_bytes[0] = msg_bytes[0] ~ 69 + } + ok = ed25519.verify(&pub_key, msg_bytes, sig_bytes) + testing.expectf( + t, + ok == false, + "Expected false for verify(%s, %s (corrupted), %s)", + v.pub_key, + v.msg, + v.sig, + ) + } + + // Test cases from "Taming the many EdDSAs", which aim to exercise + // all of the ed25519 edge cases/implementation differences. + // + // - https://eprint.iacr.org/2020/1244 + // - https://github.com/novifinancial/ed25519-speccheck + test_vectors_speccheck := []struct { + pub_key: string, + msg: string, + sig: string, + pub_key_ok: bool, + sig_ok: bool, + sig_ok_relaxed: bool, // Ok if the small-order A check is relaxed. + } { + // S = 0, small-order A, small-order R + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "8c93255d71dcab10e8f379c26200f3c7bd5f09d9bc3068d3ef4edeb4853022b6", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + true, + false, + true, + }, + // 0 < S < L, small-order A, mixed-order R + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "9bd9f44f4dcc75bd531b56b2cd280b0bb38fc1cd6d1230e14861d861de092e79", + "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43a5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04", + true, + false, + true, + }, + // 0 < S < L, mixed-order A, small-order R + { + "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43", + "aebf3f2601a0c8c5d39cc7d8911642f740b78168218da8471772b35f9d35b9ab", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa8c4bd45aecaca5b24fb97bc10ac27ac8751a7dfe1baff8b953ec9f5833ca260e", + true, + true, + true, + }, + // 0 < S < L, mixed-order A, mixed-order R + { + "cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d", + "9bd9f44f4dcc75bd531b56b2cd280b0bb38fc1cd6d1230e14861d861de092e79", + "9046a64750444938de19f227bb80485e92b83fdb4b6506c160484c016cc1852f87909e14428a7a1d62e9f22f3d3ad7802db02eb2e688b6c52fcd6648a98bd009", + true, + true, + true, + }, + // 0 < S < L, mixed-order A, mixed-order R + { + "cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d", + "e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec4011eaccd55b53f56c", + "160a1cb0dc9c0258cd0a7d23e94d8fa878bcb1925f2c64246b2dee1796bed5125ec6bc982a269b723e0668e540911a9a6a58921d6925e434ab10aa7940551a09", + true, + true, // cofactored-only + true, + }, + // 0 < S < L, mixed-order A, L-order R + { + "cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d", + "e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec4011eaccd55b53f56c", + "21122a84e0b5fca4052f5b1235c80a537878b38f3142356b2c2384ebad4668b7e40bc836dac0f71076f9abe3a53f9c03c1ceeeddb658d0030494ace586687405", + true, + true, // cofactored only, (fail if 8h is pre-reduced) + true, + }, + // S > L, L-order A, L-order R + { + "442aad9f089ad9e14647b1ef9099a1ff4798d78589e66f28eca69c11f582a623", + "85e241a07d148b41e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec40", + "e96f66be976d82e60150baecff9906684aebb1ef181f67a7189ac78ea23b6c0e547f7690a0e2ddcd04d87dbc3490dc19b3b3052f7ff0538cb68afb369ba3a514", + true, + false, + false, + }, + // S >> L, L-order A, L-order R + { + "442aad9f089ad9e14647b1ef9099a1ff4798d78589e66f28eca69c11f582a623", + "85e241a07d148b41e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec40", + "8ce5b96c8f26d0ab6c47958c9e68b937104cd36e13c33566acd2fe8d38aa19427e71f98a473474f2f13f06f97c20d58cc3f54b8bd0d272f42b695dd7e89a8c22", + true, + false, + false, + }, + // 0 < S < L, mixed-order A, small-order R (non-canonical R, reduced for hash) + { + "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43", + "9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03be9678ac102edcd92b0210bb34d7428d12ffc5df5f37e359941266a4e35f0f", + true, + false, + false, + }, + // 0 < S < L, mixed-order A, small-order R (non-canonical R, not reduced for hash) + { + "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43", + "9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffca8c5b64cd208982aa38d4936621a4775aa233aa0505711d8fdcfdaa943d4908", + true, + false, + false, + }, + // 0 < S < L, small-order A, mixed-order R (non-canonical A, reduced for hash) + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "e96b7021eb39c1a163b6da4e3093dcd3f21387da4cc4572be588fafae23c155b", + "a9d55260f765261eb9b84e106f665e00b867287a761990d7135963ee0a7d59dca5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04", + false, + false, + false, + }, + // 0 < S < L, small-order A, mixed-order R (non-canonical A, not reduced for hash) + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "39a591f5321bbe07fd5a23dc2f39d025d74526615746727ceefd6e82ae65c06f", + "a9d55260f765261eb9b84e106f665e00b867287a761990d7135963ee0a7d59dca5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04", + false, + false, + false, + }, + } + for v, i in test_vectors_speccheck { + pub_bytes, _ := hex.decode(transmute([]byte)(v.pub_key), context.temp_allocator) + msg_bytes, _ := hex.decode(transmute([]byte)(v.msg), context.temp_allocator) + sig_bytes, _ := hex.decode(transmute([]byte)(v.sig), context.temp_allocator) + + pub_key: ed25519.Public_Key + ok := ed25519.public_key_set_bytes(&pub_key, pub_bytes) + testing.expectf( + t, + ok == v.pub_key_ok, + "speccheck/%d: Expected %s to be a (in)valid public key, got %v", + i, + v.pub_key, + ok, + ) + + // If A is rejected for being non-canonical, skip signature check. + if !v.pub_key_ok { + continue + } + + ok = ed25519.verify(&pub_key, msg_bytes, sig_bytes) + testing.expectf( + t, + ok == v.sig_ok, + "speccheck/%d Expected %v for verify(%s, %s, %s)", + i, + v.sig_ok, + v.pub_key, + v.msg, + v.sig, + ) + + // If the signature is accepted, skip the relaxed signature check. + if v.sig_ok { + continue + } + + ok = ed25519.verify(&pub_key, msg_bytes, sig_bytes, true) + testing.expectf( + t, + ok == v.sig_ok_relaxed, + "speccheck/%d Expected %v for verify(%s, %s, %s, true)", + i, + v.sig_ok_relaxed, + v.pub_key, + v.msg, + v.sig, + ) + } +} diff --git a/tests/core/crypto/test_core_crypto_hash.odin b/tests/core/crypto/test_core_crypto_hash.odin index 9a9d0cc76..76c2aef6a 100644 --- a/tests/core/crypto/test_core_crypto_hash.odin +++ b/tests/core/crypto/test_core_crypto_hash.odin @@ -5,6 +5,9 @@ import "core:bytes" import "core:encoding/hex" import "core:strings" import "core:testing" + +import "core:crypto/blake2b" +import "core:crypto/blake2s" import "core:crypto/hash" @(test) @@ -596,4 +599,139 @@ test_hash :: proc(t: ^testing.T) { c_str, ) } -} \ No newline at end of file +} + +@(private="file") +selftest_seq :: proc(dst: []byte, seed: u32) { + a := 0xdead4bad * seed + b: u32 = 1 + + for i in 0 ..< len(dst) { + a, b = b, a + b + dst[i] = byte(b >> 24) + } +} + +@(test) +test_blake2b_self :: proc(t: ^testing.T) { + expected := []byte{ + 0xC2, 0x3A, 0x78, 0x00, 0xD9, 0x81, 0x23, 0xBD, + 0x10, 0xF5, 0x06, 0xC6, 0x1E, 0x29, 0xDA, 0x56, + 0x03, 0xD7, 0x63, 0xB8, 0xBB, 0xAD, 0x2E, 0x73, + 0x7F, 0x5E, 0x76, 0x5A, 0x7B, 0xCC, 0xD4, 0x75, + } + md_lens := []int{20, 32, 48, 64} + src_lens := []int{0, 3, 128, 129, 255, 1024} + + b2b := proc(dst, src: []byte) { + ctx: blake2b.Context + + blake2b.init(&ctx, len(dst)) + blake2b.update(&ctx, src) + blake2b.final(&ctx, dst) + } + b2b_keyed := proc(dst, key, src: []byte) { + ctx: blake2b.Context + + blake2b.init_mac(&ctx, key, len(dst)) + blake2b.update(&ctx, src) + blake2b.final(&ctx, dst) + } + + buf: [1024]byte + md, key: [64]byte + + ctx: blake2b.Context + blake2b.init(&ctx, 32) + + for md_len in md_lens { + dst := md[:md_len] + for src_len in src_lens { + src := buf[:src_len] + + selftest_seq(src, u32(src_len)) + b2b(dst, src) + blake2b.update(&ctx, dst) + + k := key[:md_len] + selftest_seq(k, u32(md_len)) + b2b_keyed(dst, k, src) + blake2b.update(&ctx, dst) + } + } + + blake2b.final(&ctx, md[:32]) + + expected_str := string(hex.encode(expected, context.temp_allocator)) + actual_str := string(hex.encode(md[:32], context.temp_allocator)) + + testing.expectf( + t, + expected_str == actual_str, + "blake2b/self-test: Expected: %s Got %s", + expected_str, + actual_str, + ) +} + +@(test) +test_blake2s_self :: proc(t: ^testing.T) { + expected := []byte{ + 0x6A, 0x41, 0x1F, 0x08, 0xCE, 0x25, 0xAD, 0xCD, + 0xFB, 0x02, 0xAB, 0xA6, 0x41, 0x45, 0x1C, 0xEC, + 0x53, 0xC5, 0x98, 0xB2, 0x4F, 0x4F, 0xC7, 0x87, + 0xFB, 0xDC, 0x88, 0x79, 0x7F, 0x4C, 0x1D, 0xFE, + } + md_lens := []int{16, 20, 28, 32} + src_lens := []int{0, 3, 64, 65, 255, 1024} + + b2s := proc(dst, src: []byte) { + ctx: blake2s.Context + + blake2s.init(&ctx, len(dst)) + blake2s.update(&ctx, src) + blake2s.final(&ctx, dst) + } + b2s_keyed := proc(dst, key, src: []byte) { + ctx: blake2s.Context + + blake2s.init_mac(&ctx, key, len(dst)) + blake2s.update(&ctx, src) + blake2s.final(&ctx, dst) + } + + buf: [1024]byte + md, key: [32]byte + + ctx: blake2s.Context + blake2s.init(&ctx) + + for md_len in md_lens { + dst := md[:md_len] + for src_len in src_lens { + src := buf[:src_len] + + selftest_seq(src, u32(src_len)) + b2s(dst, src) + blake2s.update(&ctx, dst) + + k := key[:md_len] + selftest_seq(k, u32(md_len)) + b2s_keyed(dst, k, src) + blake2s.update(&ctx, dst) + } + } + + blake2s.final(&ctx, md[:]) + + expected_str := string(hex.encode(expected, context.temp_allocator)) + actual_str := string(hex.encode(md[:], context.temp_allocator)) + + testing.expectf( + t, + expected_str == actual_str, + "blake2s/self-test: Expected: %s Got %s", + expected_str, + actual_str, + ) +} diff --git a/tests/core/crypto/test_core_crypto_kdf.odin b/tests/core/crypto/test_core_crypto_kdf.odin index c15dc2206..d0266e4d1 100644 --- a/tests/core/crypto/test_core_crypto_kdf.odin +++ b/tests/core/crypto/test_core_crypto_kdf.odin @@ -3,10 +3,63 @@ package test_core_crypto import "base:runtime" import "core:encoding/hex" import "core:testing" +import "core:crypto/argon2id" import "core:crypto/hash" import "core:crypto/hkdf" import "core:crypto/pbkdf2" +@(test) +test_argon2id :: proc(t: ^testing.T) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + + test_vectors := []struct { + params: ^argon2id.Parameters, + password: string, + salt: string, + secret: string, + ad: string, + tag: string, + } { + // RFC 9106 5.3. + { + &argon2id.Parameters{ + 32, + 3, + 4, + }, + "0101010101010101010101010101010101010101010101010101010101010101", + "02020202020202020202020202020202", + "0303030303030303", + "040404040404040404040404", + "0d640df58d78766c08c037a34a8b53c9d01ef0452d75b65eb52520e96b01e659", + }, + } + for v, _ in test_vectors { + tag := make([]byte, len(v.tag)/2, context.temp_allocator) + + password, _ := hex.decode(transmute([]byte)(v.password), context.temp_allocator) + salt, _ := hex.decode(transmute([]byte)(v.salt), context.temp_allocator) + secret, _ := hex.decode(transmute([]byte)(v.secret), context.temp_allocator) + ad, _ := hex.decode(transmute([]byte)(v.ad), context.temp_allocator) + + _ = argon2id.derive(v.params, password, salt, tag, secret, ad) + + tag_str := string(hex.encode(tag, context.temp_allocator)) + + testing.expectf( + t, + tag_str == v.tag, + "argon2id: Expected: %s for input of (%s, %s, %s, %s), but got %s instead", + v.tag, + v.password, + v.salt, + v.secret, + v.ad, + tag_str, + ) + } +} + @(test) test_hkdf :: proc(t: ^testing.T) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() diff --git a/tests/core/crypto/test_core_crypto_weierstrass.odin b/tests/core/crypto/test_core_crypto_weierstrass.odin new file mode 100644 index 000000000..dcb17aa3d --- /dev/null +++ b/tests/core/crypto/test_core_crypto_weierstrass.odin @@ -0,0 +1,950 @@ +package test_core_crypto + +import "core:crypto" +import ec "core:crypto/_weierstrass" +import "core:encoding/hex" +import "core:math/big" +import "core:testing" + +@(private="file") +P256_G_X : string : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296" +@(private="file") +P256_G_Y : string : "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5" +@(private="file") +P256_G_UNCOMPRESSED :: "04" + P256_G_X + P256_G_Y + +@(private="file") +P384_G_X : string : "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7" +@(private="file") +P384_G_Y : string : "3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f" + +@(test) +test_p256_a :: proc(t: ^testing.T) { + a_str := "ffffffff00000001000000000000000000000000fffffffffffffffffffffffc" + + fe, a_fe: ec.Field_Element_p256r1 + ec.fe_a(&fe) + ec.fe_a(&a_fe) + + b: [32]byte + ec.fe_bytes(b[:], &fe) + + s := (string)(hex.encode(b[:], context.temp_allocator)) + + testing.expect(t, s == a_str) + + b_, _ := hex.decode(transmute([]byte)(a_str), context.temp_allocator) + ec.fe_zero(&fe) + ec.fe_set_bytes(&fe, b_) + + testing.expectf(t, ec.fe_equal(&fe, &a_fe) == 1, "%v", &fe) +} + +@(test) +test_p384_a :: proc(t: ^testing.T) { + a_str := "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc" + fe, a_fe: ec.Field_Element_p384r1 + ec.fe_a(&fe) + ec.fe_a(&a_fe) + + b: [48]byte + ec.fe_bytes(b[:], &fe) + + s := (string)(hex.encode(b[:], context.temp_allocator)) + + testing.expect(t, s == a_str) + + b_, _ := hex.decode(transmute([]byte)(a_str), context.temp_allocator) + ec.fe_zero(&fe) + ec.fe_set_bytes(&fe, b_) + + testing.expectf(t, ec.fe_equal(&fe, &a_fe) == 1, "%v", &fe) +} + +@(test) +test_p256_b :: proc(t: ^testing.T) { + b_str := "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b" + + fe, b_fe: ec.Field_Element_p256r1 + ec.fe_b(&fe) + ec.fe_b(&b_fe) + + b: [32]byte + ec.fe_bytes(b[:], &fe) + + s := (string)(hex.encode(b[:], context.temp_allocator)) + + testing.expect(t, s == b_str) + + b_, _ := hex.decode(transmute([]byte)(b_str), context.temp_allocator) + ec.fe_zero(&fe) + ec.fe_set_bytes(&fe, b_) + + testing.expectf(t, ec.fe_equal(&fe, &b_fe) == 1, "%v", &fe) +} + +@(test) +test_p384_b :: proc(t: ^testing.T) { + b_str := "b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef" + fe, b_fe: ec.Field_Element_p384r1 + ec.fe_b(&fe) + ec.fe_b(&b_fe) + + b: [48]byte + ec.fe_bytes(b[:], &fe) + + s := (string)(hex.encode(b[:], context.temp_allocator)) + + testing.expect(t, s == b_str) + + b_, _ := hex.decode(transmute([]byte)(b_str), context.temp_allocator) + ec.fe_zero(&fe) + ec.fe_set_bytes(&fe, b_) + + testing.expectf(t, ec.fe_equal(&fe, &b_fe) == 1, "%v", &fe) +} + +@(test) +test_p256_g_x :: proc(t: ^testing.T) { + fe, x_fe: ec.Field_Element_p256r1 + ec.fe_gen_x(&fe) + ec.fe_gen_x(&x_fe) + + b: [32]byte + ec.fe_bytes(b[:], &fe) + + s := (string)(hex.encode(b[:], context.temp_allocator)) + testing.expect(t, s == P256_G_X) + + b_, _ := hex.decode(transmute([]byte)(P256_G_X), context.temp_allocator) + ec.fe_zero(&fe) + ec.fe_set_bytes(&fe, b_) + + testing.expectf(t, ec.fe_equal(&fe, &x_fe) == 1, "%v", &fe) +} + +@(test) +test_p384_g_x :: proc(t: ^testing.T) { + fe, x_fe: ec.Field_Element_p384r1 + ec.fe_gen_x(&fe) + ec.fe_gen_x(&x_fe) + + b: [48]byte + ec.fe_bytes(b[:], &fe) + + s := (string)(hex.encode(b[:], context.temp_allocator)) + testing.expect(t, s == P384_G_X) + + b_, _ := hex.decode(transmute([]byte)(P384_G_X), context.temp_allocator) + ec.fe_zero(&fe) + ec.fe_set_bytes(&fe, b_) + + testing.expectf(t, ec.fe_equal(&fe, &x_fe) == 1, "%v", &fe) +} + +@(test) +test_p256_g_y :: proc(t: ^testing.T) { + fe, y_fe: ec.Field_Element_p256r1 + ec.fe_gen_y(&fe) + ec.fe_gen_y(&y_fe) + + b: [32]byte + ec.fe_bytes(b[:], &fe) + + s := (string)(hex.encode(b[:], context.temp_allocator)) + testing.expect(t, s == P256_G_Y) + + b_, _ := hex.decode(transmute([]byte)(P256_G_Y), context.temp_allocator) + ec.fe_zero(&fe) + ec.fe_set_bytes(&fe, b_) + + testing.expectf(t, ec.fe_equal(&fe, &y_fe) == 1, "%v", &fe) +} + +@(test) +test_p384_g_y :: proc(t: ^testing.T) { + fe, y_fe: ec.Field_Element_p384r1 + ec.fe_gen_y(&fe) + ec.fe_gen_y(&y_fe) + + b: [48]byte + ec.fe_bytes(b[:], &fe) + + s := (string)(hex.encode(b[:], context.temp_allocator)) + testing.expect(t, s == P384_G_Y) + + b_, _ := hex.decode(transmute([]byte)(P384_G_Y), context.temp_allocator) + ec.fe_zero(&fe) + ec.fe_set_bytes(&fe, b_) + + testing.expectf(t, ec.fe_equal(&fe, &y_fe) == 1, "%v", &fe) +} + +@(test) +test_p256_scalar_reduce :: proc(t: ^testing.T) { + test_vectors := []struct { + raw: string, + reduced: string, + } { + // n + { + "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + "0000000000000000000000000000000000000000000000000000000000000000", + }, + // n + 1 + { + "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552", + "0000000000000000000000000000000000000000000000000000000000000001", + }, + // 2^384 (Sage) + { + "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "431905529c0166ce652e96b7ccca0a99679b73e19ad16947f01cf013fc632551", + }, + // SHA384 odin-linux-amd64-dev-2026-01.tar.gz (Sage) + { + "87622f79b4b0e76001f9c99b0337b61a0bcd2b5a8e9a3937176825ad75ef0fe8742a348a251dd2682d711f76b33df3e6", + "f66db86e28d903033d1e17d818c0eb13fe3d1ae095b4d2ecbcd1a1eccf9f2f8c", + }, + // SHA512 odin-linux-amd64-dev-2026-01.tar.gz (Sage) + { + "6f85507cec3a35fdb3d4f40d23583681144561e77bc4ea88ab0ea219d5c17b7c9178f5f5a6296a2d18eddd4bdf19e61830fc85d7de23fd4fbde31c4cf6694719", + "3217ecbee32c8b0dfcca0f10a884fe43658fbe91458f25d0f1bf2075759c5ebe", + }, + } + + for v, _ in test_vectors { + raw_bytes, _ := hex.decode(transmute([]byte)(v.raw), context.temp_allocator) + + sc: ec.Scalar_p256r1 + _ = ec.sc_set_bytes(&sc, raw_bytes) + + b: [ec.SC_SIZE_P256R1]byte + ec.sc_bytes(b[:], &sc) + s := (string)(hex.encode(b[:], context.temp_allocator)) + + testing.expectf(t, v.reduced == s, "sc: raw %s reduced: %s, expected: %s", v.raw, s, v.reduced) + } +} + +@(test) +test_p384_scalar_reduce :: proc(t: ^testing.T) { + test_vectors := []struct { + raw: string, + reduced: string, + } { + // n + { + "ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + // n + 1 + { + "ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52974", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + }, + // SHA384 odin-linux-amd64-dev-2026-01.tar.gz + { + "87622f79b4b0e76001f9c99b0337b61a0bcd2b5a8e9a3937176825ad75ef0fe8742a348a251dd2682d711f76b33df3e6", + "87622f79b4b0e76001f9c99b0337b61a0bcd2b5a8e9a3937176825ad75ef0fe8742a348a251dd2682d711f76b33df3e6", + }, + // SHA512 odin-linux-amd64-dev-2026-01.tar.gz (Sage) + { + "6f85507cec3a35fdb3d4f40d23583681144561e77bc4ea88ab0ea219d5c17b7c9178f5f5a6296a2d18eddd4bdf19e61830fc85d7de23fd4fbde31c4cf6694719", + "144561e77bc4ea88c3b80eb3d044daa78b2dd5878dca766578e9c1aad3dba0d211ec862c36d2a7412917b70237c92226", + }, + } + + for v, _ in test_vectors { + raw_bytes, _ := hex.decode(transmute([]byte)(v.raw), context.temp_allocator) + + sc: ec.Scalar_p384r1 + _ = ec.sc_set_bytes(&sc, raw_bytes) + + b: [ec.SC_SIZE_P384R1]byte + ec.sc_bytes(b[:], &sc) + s := (string)(hex.encode(b[:], context.temp_allocator)) + + testing.expectf(t, v.reduced == s, "sc: raw %s reduced: %s (%v), expected: %s", v.raw, s, &sc, v.reduced) + } +} + +@(test) +test_p256_scalar_mul :: proc(t: ^testing.T) { + test_vectors := []struct { + scalar: string, // NOTE: Base 10 + x, y: string, + } { + // Test vectors from http://point-at-infinity.org/ecc/nisttv + { + "1", + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", + + }, + { + "2", + "7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC47669978", + "07775510DB8ED040293D9AC69F7430DBBA7DADE63CE982299E04B79D227873D1", + }, + { + "3", + "5ECBE4D1A6330A44C8F7EF951D4BF165E6C6B721EFADA985FB41661BC6E7FD6C", + "8734640C4998FF7E374B06CE1A64A2ECD82AB036384FB83D9A79B127A27D5032", + }, + { + "4", + "E2534A3532D08FBBA02DDE659EE62BD0031FE2DB785596EF509302446B030852", + "E0F1575A4C633CC719DFEE5FDA862D764EFC96C3F30EE0055C42C23F184ED8C6", + }, + { + "5", + "51590B7A515140D2D784C85608668FDFEF8C82FD1F5BE52421554A0DC3D033ED", + "E0C17DA8904A727D8AE1BF36BF8A79260D012F00D4D80888D1D0BB44FDA16DA4", + }, + { + "6", + "B01A172A76A4602C92D3242CB897DDE3024C740DEBB215B4C6B0AAE93C2291A9", + "E85C10743237DAD56FEC0E2DFBA703791C00F7701C7E16BDFD7C48538FC77FE2", + }, + { + "7", + "8E533B6FA0BF7B4625BB30667C01FB607EF9F8B8A80FEF5B300628703187B2A3", + "73EB1DBDE03318366D069F83A6F5900053C73633CB041B21C55E1A86C1F400B4", + }, + { + "8", + "62D9779DBEE9B0534042742D3AB54CADC1D238980FCE97DBB4DD9DC1DB6FB393", + "AD5ACCBD91E9D8244FF15D771167CEE0A2ED51F6BBE76A78DA540A6A0F09957E", + }, + { + "9", + "EA68D7B6FEDF0B71878938D51D71F8729E0ACB8C2C6DF8B3D79E8A4B90949EE0", + "2A2744C972C9FCE787014A964A8EA0C84D714FEAA4DE823FE85A224A4DD048FA", + }, + { + "10", + "CEF66D6B2A3A993E591214D1EA223FB545CA6C471C48306E4C36069404C5723F", + "878662A229AAAE906E123CDD9D3B4C10590DED29FE751EEECA34BBAA44AF0773", + }, + { + "11", + "3ED113B7883B4C590638379DB0C21CDA16742ED0255048BF433391D374BC21D1", + "9099209ACCC4C8A224C843AFA4F4C68A090D04DA5E9889DAE2F8EEFCE82A3740", + }, + { + "12", + "741DD5BDA817D95E4626537320E5D55179983028B2F82C99D500C5EE8624E3C4", + "0770B46A9C385FDC567383554887B1548EEB912C35BA5CA71995FF22CD4481D3", + }, + { + "13", + "177C837AE0AC495A61805DF2D85EE2FC792E284B65EAD58A98E15D9D46072C01", + "63BB58CD4EBEA558A24091ADB40F4E7226EE14C3A1FB4DF39C43BBE2EFC7BFD8", + }, + { + "14", + "54E77A001C3862B97A76647F4336DF3CF126ACBE7A069C5E5709277324D2920B", + "F599F1BB29F4317542121F8C05A2E7C37171EA77735090081BA7C82F60D0B375", + }, + { + "15", + "F0454DC6971ABAE7ADFB378999888265AE03AF92DE3A0EF163668C63E59B9D5F", + "B5B93EE3592E2D1F4E6594E51F9643E62A3B21CE75B5FA3F47E59CDE0D034F36", + }, + { + "16", + "76A94D138A6B41858B821C629836315FCD28392EFF6CA038A5EB4787E1277C6E", + "A985FE61341F260E6CB0A1B5E11E87208599A0040FC78BAA0E9DDD724B8C5110", + }, + { + "17", + "47776904C0F1CC3A9C0984B66F75301A5FA68678F0D64AF8BA1ABCE34738A73E", + "AA005EE6B5B957286231856577648E8381B2804428D5733F32F787FF71F1FCDC", + }, + { + "18", + "1057E0AB5780F470DEFC9378D1C7C87437BB4C6F9EA55C63D936266DBD781FDA", + "F6F1645A15CBE5DC9FA9B7DFD96EE5A7DCC11B5C5EF4F1F78D83B3393C6A45A2", + }, + { + "19", + "CB6D2861102C0C25CE39B7C17108C507782C452257884895C1FC7B74AB03ED83", + "58D7614B24D9EF515C35E7100D6D6CE4A496716E30FA3E03E39150752BCECDAA", + }, + { + "20", + "83A01A9378395BAB9BCD6A0AD03CC56D56E6B19250465A94A234DC4C6B28DA9A", + "76E49B6DE2F73234AE6A5EB9D612B75C9F2202BB6923F54FF8240AAA86F640B8", + }, + { + "112233445566778899", + "339150844EC15234807FE862A86BE77977DBFB3AE3D96F4C22795513AEAAB82F", + "B1C14DDFDC8EC1B2583F51E85A5EB3A155840F2034730E9B5ADA38B674336A21", + }, + { + "112233445566778899112233445566778899", + "1B7E046A076CC25E6D7FA5003F6729F665CC3241B5ADAB12B498CD32F2803264", + "BFEA79BE2B666B073DB69A2A241ADAB0738FE9D2DD28B5604EB8C8CF097C457B", + }, + { + "029852220098221261079183923314599206100666902414330245206392788703677545185283", + "9EACE8F4B071E677C5350B02F2BB2B384AAE89D58AA72CA97A170572E0FB222F", + "1BBDAEC2430B09B93F7CB08678636CE12EAAFD58390699B5FD2F6E1188FC2A78", + }, + { + "057896042899961394862005778464643882389978449576758748073725983489954366354431", + "878F22CC6DB6048D2B767268F22FFAD8E56AB8E2DC615F7BD89F1E350500DD8D", + "714A5D7BB901C9C5853400D12341A892EF45D87FC553786756C4F0C9391D763E", + }, + { + "57896042899961394862005778464643882389978449576758748073725983489954366354431", + "878F22CC6DB6048D2B767268F22FFAD8E56AB8E2DC615F7BD89F1E350500DD8D", + "714A5D7BB901C9C5853400D12341A892EF45D87FC553786756C4F0C9391D763E", + }, + { + "1766845392945710151501889105729049882997660004824848915955419660366636031", + "659A379625AB122F2512B8DADA02C6348D53B54452DFF67AC7ACE4E8856295CA", + "49D81AB97B648464D0B4A288BD7818FAB41A16426E943527C4FED8736C53D0F6", + }, + { + "28948025760307534517734791687894775804466072615242963443097661355606862201087", + "CBCEAAA8A4DD44BBCE58E8DB7740A5510EC2CB7EA8DA8D8F036B3FB04CDA4DE4", + "4BD7AA301A80D7F59FD983FEDBE59BB7B2863FE46494935E3745B360E32332FA", + }, + { + "113078210460870548944811695960290644973229224625838436424477095834645696384", + "F0C4A0576154FF3A33A3460D42EAED806E854DFA37125221D37935124BA462A4", + "5B392FA964434D29EEC6C9DBC261CF116796864AA2FAADB984A2DF38D1AEF7A3", + }, + { + "12078056106883488161242983286051341125085761470677906721917479268909056", + "5E6C8524B6369530B12C62D31EC53E0288173BD662BDF680B53A41ECBCAD00CC", + "447FE742C2BFEF4D0DB14B5B83A2682309B5618E0064A94804E9282179FE089F", + }, + { + "57782969857385448082319957860328652998540760998293976083718804450708503920639", + "03792E541BC209076A3D7920A915021ECD396A6EB5C3960024BE5575F3223484", + "FC774AE092403101563B712F68170312304F20C80B40C06282063DB25F268DE4", + }, + { + "57896017119460046759583662757090100341435943767777707906455551163257755533312", + "2379FF85AB693CDF901D6CE6F2473F39C04A2FE3DCD842CE7AAB0E002095BCF8", + "F8B476530A634589D5129E46F322B02FBC610A703D80875EE70D7CE1877436A1", + }, + { + "452312848374287284681282171017647412726433684238464212999305864837160993279", + "C1E4072C529BF2F44DA769EFC934472848003B3AF2C0F5AA8F8DDBD53E12ED7C", + "39A6EE77812BB37E8079CD01ED649D3830FCA46F718C1D3993E4A591824ABCDB", + }, + { + "904571339174065134293634407946054000774746055866917729876676367558469746684", + "34DFBC09404C21E250A9B40FA8772897AC63A094877DB65862B61BD1507B34F3", + "CF6F8A876C6F99CEAEC87148F18C7E1E0DA6E165FFC8ED82ABB65955215F77D3", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044349", + "83A01A9378395BAB9BCD6A0AD03CC56D56E6B19250465A94A234DC4C6B28DA9A", + "891B64911D08CDCC5195A14629ED48A360DDFD4596DC0AB007DBF5557909BF47", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044350", + "CB6D2861102C0C25CE39B7C17108C507782C452257884895C1FC7B74AB03ED83", + "A7289EB3DB2610AFA3CA18EFF292931B5B698E92CF05C1FC1C6EAF8AD4313255", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044351", + "1057E0AB5780F470DEFC9378D1C7C87437BB4C6F9EA55C63D936266DBD781FDA", + "090E9BA4EA341A246056482026911A58233EE4A4A10B0E08727C4CC6C395BA5D", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044352", + "47776904C0F1CC3A9C0984B66F75301A5FA68678F0D64AF8BA1ABCE34738A73E", + "55FFA1184A46A8D89DCE7A9A889B717C7E4D7FBCD72A8CC0CD0878008E0E0323", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044353", + "76A94D138A6B41858B821C629836315FCD28392EFF6CA038A5EB4787E1277C6E", + "567A019DCBE0D9F2934F5E4A1EE178DF7A665FFCF0387455F162228DB473AEEF", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044354", + "F0454DC6971ABAE7ADFB378999888265AE03AF92DE3A0EF163668C63E59B9D5F", + "4A46C11BA6D1D2E1B19A6B1AE069BC19D5C4DE328A4A05C0B81A6321F2FCB0C9", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044355", + "54E77A001C3862B97A76647F4336DF3CF126ACBE7A069C5E5709277324D2920B", + "0A660E43D60BCE8BBDEDE073FA5D183C8E8E15898CAF6FF7E45837D09F2F4C8A", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044356", + "177C837AE0AC495A61805DF2D85EE2FC792E284B65EAD58A98E15D9D46072C01", + "9C44A731B1415AA85DBF6E524BF0B18DD911EB3D5E04B20C63BC441D10384027", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044357", + "741DD5BDA817D95E4626537320E5D55179983028B2F82C99D500C5EE8624E3C4", + "F88F4B9463C7A024A98C7CAAB7784EAB71146ED4CA45A358E66A00DD32BB7E2C", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044358", + "3ED113B7883B4C590638379DB0C21CDA16742ED0255048BF433391D374BC21D1", + "6F66DF64333B375EDB37BC505B0B3975F6F2FB26A16776251D07110317D5C8BF", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044359", + "CEF66D6B2A3A993E591214D1EA223FB545CA6C471C48306E4C36069404C5723F", + "78799D5CD655517091EDC32262C4B3EFA6F212D7018AE11135CB4455BB50F88C", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044360", + "EA68D7B6FEDF0B71878938D51D71F8729E0ACB8C2C6DF8B3D79E8A4B90949EE0", + "D5D8BB358D36031978FEB569B5715F37B28EB0165B217DC017A5DDB5B22FB705", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044361", + "62D9779DBEE9B0534042742D3AB54CADC1D238980FCE97DBB4DD9DC1DB6FB393", + "52A533416E1627DCB00EA288EE98311F5D12AE0A4418958725ABF595F0F66A81", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044362", + "8E533B6FA0BF7B4625BB30667C01FB607EF9F8B8A80FEF5B300628703187B2A3", + "8C14E2411FCCE7CA92F9607C590A6FFFAC38C9CD34FBE4DE3AA1E5793E0BFF4B", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044363", + "B01A172A76A4602C92D3242CB897DDE3024C740DEBB215B4C6B0AAE93C2291A9", + "17A3EF8ACDC8252B9013F1D20458FC86E3FF0890E381E9420283B7AC7038801D", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044364", + "51590B7A515140D2D784C85608668FDFEF8C82FD1F5BE52421554A0DC3D033ED", + "1F3E82566FB58D83751E40C9407586D9F2FED1002B27F7772E2F44BB025E925B", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044365", + "E2534A3532D08FBBA02DDE659EE62BD0031FE2DB785596EF509302446B030852", + "1F0EA8A4B39CC339E62011A02579D289B103693D0CF11FFAA3BD3DC0E7B12739", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044366", + "5ECBE4D1A6330A44C8F7EF951D4BF165E6C6B721EFADA985FB41661BC6E7FD6C", + "78CB9BF2B6670082C8B4F931E59B5D1327D54FCAC7B047C265864ED85D82AFCD", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044367", + "7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC47669978", + "F888AAEE24712FC0D6C26539608BCF244582521AC3167DD661FB4862DD878C2E", + }, + { + "115792089210356248762697446949407573529996955224135760342422259061068512044368", + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", + "B01CBD1C01E58065711814B583F061E9D431CCA994CEA1313449BF97C840AE0A", + }, + } + + for v, _ in test_vectors { + x_bytes, _ := hex.decode(transmute([]byte)(v.x), context.temp_allocator) + y_bytes, _ := hex.decode(transmute([]byte)(v.y), context.temp_allocator) + + k_big: big.Int + err := big.set(&k_big, v.scalar, 10, context.temp_allocator) + testing.expectf(t, err == nil, "failed to parse k", err) + + k_sz: int + k_sz, err = big.int_to_bytes_size(&k_big, allocator = context.temp_allocator) + testing.expect(t, err == nil) + + k_bytes := make([]byte, k_sz, context.temp_allocator) + err = big.int_to_bytes_big(&k_big, k_bytes, allocator = context.temp_allocator) + + p, q, expected, g: ec.Point_p256r1 + sc: ec.Scalar_p256r1 + + _ = ec.sc_set_bytes(&sc, k_bytes) + + ec.pt_generator(&g) + ok := ec.pt_set_xy_bytes(&expected, x_bytes, y_bytes) + testing.expectf(t, ok, "failed to set point; %s, %s", v.x, v.y) + + ec.pt_scalar_mul(&p, &g, &sc) + ec.pt_scalar_mul_generator(&q, &sc) + ec.pt_rescale(&p, &p) + ec.pt_rescale(&q, &q) + + testing.expect(t, ec.pt_equal(&p, &q) == 1) + testing.expectf(t, ec.pt_equal(&p, &expected) == 1, "sc: %s actual: %v expected: %v", v.scalar, &p, &expected) + } +} + +@(test) +test_p384_scalar_mul :: proc(t: ^testing.T) { + test_vectors := []struct { + scalar: string, // NOTE: Base 10 + x, y: string, + } { + // Test vectors from http://point-at-infinity.org/ecc/nisttv + { + "1", + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", + }, + { + "2", + "08D999057BA3D2D969260045C55B97F089025959A6F434D651D207D19FB96E9E4FE0E86EBE0E64F85B96A9C75295DF61", + "8E80F1FA5B1B3CEDB7BFE8DFFD6DBA74B275D875BC6CC43E904E505F256AB4255FFD43E94D39E22D61501E700A940E80", + }, + { + "3", + "077A41D4606FFA1464793C7E5FDC7D98CB9D3910202DCD06BEA4F240D3566DA6B408BBAE5026580D02D7E5C70500C831", + "C995F7CA0B0C42837D0BBE9602A9FC998520B41C85115AA5F7684C0EDC111EACC24ABD6BE4B5D298B65F28600A2F1DF1", + }, + { + "4", + "138251CD52AC9298C1C8AAD977321DEB97E709BD0B4CA0ACA55DC8AD51DCFC9D1589A1597E3A5120E1EFD631C63E1835", + "CACAE29869A62E1631E8A28181AB56616DC45D918ABC09F3AB0E63CF792AA4DCED7387BE37BBA569549F1C02B270ED67", + }, + { + "5", + "11DE24A2C251C777573CAC5EA025E467F208E51DBFF98FC54F6661CBE56583B037882F4A1CA297E60ABCDBC3836D84BC", + "8FA696C77440F92D0F5837E90A00E7C5284B447754D5DEE88C986533B6901AEB3177686D0AE8FB33184414ABE6C1713A", + }, + { + "6", + "627BE1ACD064D2B2226FE0D26F2D15D3C33EBCBB7F0F5DA51CBD41F26257383021317D7202FF30E50937F0854E35C5DF", + "09766A4CB3F8B1C21BE6DDA6C14F1575B2C95352644F774C99864F613715441604C45B8D84E165311733A408D3F0F934", + }, + { + "7", + "283C1D7365CE4788F29F8EBF234EDFFEAD6FE997FBEA5FFA2D58CC9DFA7B1C508B05526F55B9EBB2040F05B48FB6D0E1", + "9475C99061E41B88BA52EFDB8C1690471A61D867ED799729D9C92CD01DBD225630D84EDE32A78F9E64664CDAC512EF8C", + }, + { + "8", + "1692778EA596E0BE75114297A6FA383445BF227FBE58190A900C3C73256F11FB5A3258D6F403D5ECE6E9B269D822C87D", + "DCD2365700D4106A835388BA3DB8FD0E22554ADC6D521CD4BD1C30C2EC0EEC196BADE1E9CDD1708D6F6ABFA4022B0AD2", + }, + { + "9", + "8F0A39A4049BCB3EF1BF29B8B025B78F2216F7291E6FD3BAC6CB1EE285FB6E21C388528BFEE2B9535C55E4461079118B", + "62C77E1438B601D6452C4A5322C3A9799A9B3D7CA3C400C6B7678854AED9B3029E743EFEDFD51B68262DA4F9AC664AF8", + }, + { + "10", + "A669C5563BD67EEC678D29D6EF4FDE864F372D90B79B9E88931D5C29291238CCED8E85AB507BF91AA9CB2D13186658FB", + "A988B72AE7C1279F22D9083DB5F0ECDDF70119550C183C31C502DF78C3B705A8296D8195248288D997784F6AB73A21DD", + }, + { + "11", + "099056E27DA7B998DA1EEEC2904816C57FE935ED5837C37456C9FD14892D3F8C4749B66E3AFB81D626356F3B55B4DDD8", + "2E4C0C234E30AB96688505544AC5E0396FC4EED8DFC363FD43FF93F41B52A3255466D51263AAFF357D5DBA8138C5E0BB", + }, + { + "12", + "952A7A349BD49289AB3AC421DCF683D08C2ED5E41F6D0E21648AF2691A481406DA4A5E22DA817CB466DA2EA77D2A7022", + "A0320FAF84B5BC0563052DEAE6F66F2E09FB8036CE18A0EBB9028B096196B50D031AA64589743E229EF6BACCE21BD16E", + }, + { + "13", + "A567BA97B67AEA5BAFDAF5002FFCC6AB9632BFF9F01F873F6267BCD1F0F11C139EE5F441ABD99F1BAAF1CA1E3B5CBCE7", + "DE1B38B3989F3318644E4147AF164ECC5185595046932EC086329BE057857D66776BCB8272218A7D6423A12736F429CC", + }, + { + "14", + "E8C8F94D44FBC2396BBEAC481B89D2B0877B1DFFD23E7DC95DE541EB651CCA2C41ABA24DBC02DE6637209ACCF0F59EA0", + "891AE44356FC8AE0932BCBF6DE52C8A933B86191E7728D79C8319413A09D0F48FC468BA05509DE22D7EE5C9E1B67B888", + }, + { + "15", + "B3D13FC8B32B01058CC15C11D813525522A94156FFF01C205B21F9F7DA7C4E9CA849557A10B6383B4B88701A9606860B", + "152919E7DF9162A61B049B2536164B1BEEBAC4A11D749AF484D1114373DFBFD9838D24F8B284AF50985D588D33F7BD62", + }, + { + "16", + "D5D89C3B5282369C5FBD88E2B231511A6B80DFF0E5152CF6A464FA9428A8583BAC8EBC773D157811A462B892401DAFCF", + "D815229DE12906D241816D5E9A9448F1D41D4FC40E2A3BDB9CABA57E440A7ABAD1210CB8F49BF2236822B755EBAB3673", + }, + { + "17", + "4099952208B4889600A5EBBCB13E1A32692BEFB0733B41E6DCC614E42E5805F817012A991AF1F486CAF3A9ADD9FFCC03", + "5ECF94777833059839474594AF603598163AD3F8008AD0CD9B797D277F2388B304DA4D2FAA9680ECFA650EF5E23B09A0", + }, + { + "18", + "DFB1FE3A40F7AC9B64C41D39360A7423828B97CB088A4903315E402A7089FA0F8B6C2355169CC9C99DFB44692A9B93DD", + "453ACA1243B5EC6B423A68A25587E1613A634C1C42D2EE7E6C57F449A1C91DC89168B7036EC0A7F37A366185233EC522", + }, + { + "19", + "8D481DAB912BC8AB16858A211D750B77E07DBECCA86CD9B012390B430467AABF59C8651060801C0E9599E68713F5D41B", + "A1592FF0121460857BE99F2A60669050B2291B68A1039AA0594B32FD7ADC0E8C11FFBA5608004E646995B07E75E52245", + }, + { + "20", + "605508EC02C534BCEEE9484C86086D2139849E2B11C1A9CA1E2808DEC2EAF161AC8A105D70D4F85C50599BE5800A623F", + "5158EE87962AC6B81F00A103B8543A07381B7639A3A65F1353AEF11B733106DDE92E99B78DE367B48E238C38DAD8EEDD", + }, + { + "112233445566778899", + "A499EFE48839BC3ABCD1C5CEDBDD51904F9514DB44F4686DB918983B0C9DC3AEE05A88B72433E9515F91A329F5F4FA60", + "3B7CA28EF31F809C2F1BA24AAED847D0F8B406A4B8968542DE139DB5828CA410E615D1182E25B91B1131E230B727D36A", + }, + { + "112233445566778899112233445566778899", + "90A0B1CAC601676B083F21E07BC7090A3390FE1B9C7F61D842D27FA315FB38D83667A11A71438773E483F2A114836B24", + "3197D3C6123F0D6CD65D5F0DE106FEF36656CB16DC7CD1A6817EB1D51510135A8F492F72665CFD1053F75ED03A7D04C9", + }, + { + "10158184112867540819754776755819761756724522948540419979637868435924061464745859402573149498125806098880003248619520", + "F2A066BD332DC59BBC3D01DA1B124C687D8BB44611186422DE94C1DA4ECF150E664D353CCDB5CB2652685F8EB4D2CD49", + "D6ED0BF75FDD8E53D87765FA746835B673881D6D1907163A2C43990D75B454294F942EC571AD5AAE1806CAF2BB8E9A4A", + }, + { + "9850501551105991028245052605056992139810094908912799254115847683881357749738726091734403950439157209401153690566655", + "5C7F9845D1C4AA44747F9137B6F9C39B36B26B8A62E8AF97290434D5F3B214F5A0131550ADB19058DC4C8780C4165C4A", + "712F7FCCC86F647E70DB8798228CB16344AF3D00B139B6F8502939C2A965AF0EB4E39E2E16AB8F597B8D5630A50C9D85", + }, + { + "9850502723405747097317271194763310482462751455185699630571661657946308788426092983270628740691202018691293898608608", + "DD5838F7EC3B8ACF1BECFD746F8B668C577107E93548ED93ED0D254C112E76B10F053109EF8428BFCD50D38C4C030C57", + "33244F479CDAC34F160D9E4CE2D19D2FF0E3305B5BF0EEF29E91E9DE6E28F678C61B773AA7E3C03740E1A49D1AA2493C", + }, + { + "1146189371817832990947611400450889406070215735255370280811736587845016396640969656447803207438173695115264", + "CB8ED893530BFBA04B4CA655923AAAD109A62BC8411D5925316C32D33602459C33057A1FBCB5F70AEB295D90F9165FBC", + "426AEE3E91B08420F9B357B66D5AFCBCF3956590BF5564DBF9086042EB880493D19DA39AAA6436C6B5FC66CE5596B43F", + }, + { + "9619341438217097641865390297189708858938017986426152622639500179774624579127744608993294698873437325090751520764", + "67F714012B6B070182122DDD435CC1C2262A1AB88939BC6A2906CB2B4137C5E82B4582160F6403CAB887ACDF5786A268", + "90E31CF398CE2F8C5897C7380BF541075D1B4D3CB70547262B7095731252F181AC0597C66AF8311C7780DB39DEC0BD32", + }, + { + "1231307996623833742387400352380172566077927415136813282735641918395585376659282194317590461518639141730493780722175", + "55A79DF7B53A99D31462C7E1A5ED5623970715BB1021098CB973A7520CBD6365E613E4B2467486FB37E86E01CEE09B8F", + "B95AEB71693189911661B709A886A1867F056A0EFE401EE11C06030E46F7A87731DA4575863178012208707DD666727C", + }, + { + "587118838854683800942906722504810343086699021451906946003274128973058942197377013128840514404789143516741631", + "9539A968CF819A0E52E10EEA3BACA1B6480D7E4DF69BC07002C568569047110EE4FE72FCA423FDD5179D6E0E19C44844", + "A7728F37A0AE0DF2716061900D83A4DA149144129F89A214A8260464BAB609BB322E4E67DE5E4C4C6CB8D25983EC19B0", + }, + { + "153914077530671739663795070876894766451466019374644150541452557147890542143280855693795882295846834387672681660416", + "933FC13276672AB360D909161CD02D830B1628935DF0D800C6ED602C59D575A86A8A97E3A2D697E3ED06BE741C0097D6", + "F35296BD7A6B4C6C025ED6D84338CCCC7522A45C5D4FBDB1442556CAEFB598128FA188793ADA510EB5F44E90A4E4BEF1", + }, + { + "75148784606135150476268171850082176256856776750560539466196504390587921789283134009866871754361028131485122560", + "0CE31E1C4A937071E6EBACA026A93D783848BCC0C1585DAF639518125FCD1F1629D63041ABFB11FFC8F03FA8B6FCF6BF", + "A69EA55BE4BEAB2D5224050FEBFFBDFCFD614624C3B4F228909EB80012F003756D1C377E52F04FA539237F24DD080E2E", + }, + { + "19691383761310193665095292424754807745686799029814707849273381514021788371252213000473497648851202400395528761229312", + "6842CFE3589AC268818291F31D44177A9168DCBC19F321ED66D81ECF59E31B54CCA0DDFD4C4136780171748D69A91C54", + "E3A5ECD5AC725F13DBC631F358C6E817EDCF3A613B83832741A9DB591A0BAE767FC714F70C2E7EA891E4312047DECCC0", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942623", + "605508EC02C534BCEEE9484C86086D2139849E2B11C1A9CA1E2808DEC2EAF161AC8A105D70D4F85C50599BE5800A623F", + "AEA7117869D53947E0FF5EFC47ABC5F8C7E489C65C59A0ECAC510EE48CCEF92116D16647721C984B71DC73C825271122", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942624", + "8D481DAB912BC8AB16858A211D750B77E07DBECCA86CD9B012390B430467AABF59C8651060801C0E9599E68713F5D41B", + "5EA6D00FEDEB9F7A841660D59F996FAF4DD6E4975EFC655FA6B4CD028523F172EE0045A8F7FFB19B966A4F828A1ADDBA", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942625", + "DFB1FE3A40F7AC9B64C41D39360A7423828B97CB088A4903315E402A7089FA0F8B6C2355169CC9C99DFB44692A9B93DD", + "BAC535EDBC4A1394BDC5975DAA781E9EC59CB3E3BD2D118193A80BB65E36E2366E9748FB913F580C85C99E7BDCC13ADD", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942626", + "4099952208B4889600A5EBBCB13E1A32692BEFB0733B41E6DCC614E42E5805F817012A991AF1F486CAF3A9ADD9FFCC03", + "A1306B8887CCFA67C6B8BA6B509FCA67E9C52C07FF752F32648682D880DC774BFB25B2CF55697F13059AF10B1DC4F65F", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942627", + "D5D89C3B5282369C5FBD88E2B231511A6B80DFF0E5152CF6A464FA9428A8583BAC8EBC773D157811A462B892401DAFCF", + "27EADD621ED6F92DBE7E92A1656BB70E2BE2B03BF1D5C42463545A81BBF585442EDEF3460B640DDC97DD48AB1454C98C", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942628", + "B3D13FC8B32B01058CC15C11D813525522A94156FFF01C205B21F9F7DA7C4E9CA849557A10B6383B4B88701A9606860B", + "EAD6E618206E9D59E4FB64DAC9E9B4E411453B5EE28B650B7B2EEEBC8C2040257C72DB064D7B50AF67A2A773CC08429D", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942629", + "E8C8F94D44FBC2396BBEAC481B89D2B0877B1DFFD23E7DC95DE541EB651CCA2C41ABA24DBC02DE6637209ACCF0F59EA0", + "76E51BBCA903751F6CD4340921AD3756CC479E6E188D728637CE6BEC5F62F0B603B9745EAAF621DD2811A362E4984777", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942630", + "A567BA97B67AEA5BAFDAF5002FFCC6AB9632BFF9F01F873F6267BCD1F0F11C139EE5F441ABD99F1BAAF1CA1E3B5CBCE7", + "21E4C74C6760CCE79BB1BEB850E9B133AE7AA6AFB96CD13F79CD641FA87A82988894347C8DDE75829BDC5ED9C90BD633", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942631", + "952A7A349BD49289AB3AC421DCF683D08C2ED5E41F6D0E21648AF2691A481406DA4A5E22DA817CB466DA2EA77D2A7022", + "5FCDF0507B4A43FA9CFAD215190990D1F6047FC931E75F1446FD74F69E694AF1FCE559B9768BC1DD610945341DE42E91", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942632", + "099056E27DA7B998DA1EEEC2904816C57FE935ED5837C37456C9FD14892D3F8C4749B66E3AFB81D626356F3B55B4DDD8", + "D1B3F3DCB1CF5469977AFAABB53A1FC6903B1127203C9C02BC006C0BE4AD5CD9AB992AEC9C5500CA82A2457FC73A1F44", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942633", + "A669C5563BD67EEC678D29D6EF4FDE864F372D90B79B9E88931D5C29291238CCED8E85AB507BF91AA9CB2D13186658FB", + "567748D5183ED860DD26F7C24A0F132208FEE6AAF3E7C3CE3AFD20873C48FA56D6927E69DB7D77266887B09648C5DE22", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942634", + "8F0A39A4049BCB3EF1BF29B8B025B78F2216F7291E6FD3BAC6CB1EE285FB6E21C388528BFEE2B9535C55E4461079118B", + "9D3881EBC749FE29BAD3B5ACDD3C56866564C2835C3BFF39489877AB51264CFC618BC100202AE497D9D25B075399B507", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942635", + "1692778EA596E0BE75114297A6FA383445BF227FBE58190A900C3C73256F11FB5A3258D6F403D5ECE6E9B269D822C87D", + "232DC9A8FF2BEF957CAC7745C24702F1DDAAB52392ADE32B42E3CF3D13F113E594521E15322E8F729095405CFDD4F52D", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942636", + "283C1D7365CE4788F29F8EBF234EDFFEAD6FE997FBEA5FFA2D58CC9DFA7B1C508B05526F55B9EBB2040F05B48FB6D0E1", + "6B8A366F9E1BE47745AD102473E96FB8E59E2798128668D62636D32FE242DDA8CF27B120CD5870619B99B3263AED1073", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942637", + "627BE1ACD064D2B2226FE0D26F2D15D3C33EBCBB7F0F5DA51CBD41F26257383021317D7202FF30E50937F0854E35C5DF", + "F68995B34C074E3DE41922593EB0EA8A4D36ACAD9BB088B36679B09EC8EABBE8FB3BA4717B1E9ACEE8CC5BF82C0F06CB", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942638", + "11DE24A2C251C777573CAC5EA025E467F208E51DBFF98FC54F6661CBE56583B037882F4A1CA297E60ABCDBC3836D84BC", + "705969388BBF06D2F0A7C816F5FF183AD7B4BB88AB2A211773679ACC496FE513CE889791F51704CCE7BBEB55193E8EC5", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942639", + "138251CD52AC9298C1C8AAD977321DEB97E709BD0B4CA0ACA55DC8AD51DCFC9D1589A1597E3A5120E1EFD631C63E1835", + "35351D679659D1E9CE175D7E7E54A99E923BA26E7543F60C54F19C3086D55B22128C7840C8445A96AB60E3FE4D8F1298", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942640", + "077A41D4606FFA1464793C7E5FDC7D98CB9D3910202DCD06BEA4F240D3566DA6B408BBAE5026580D02D7E5C70500C831", + "366A0835F4F3BD7C82F44169FD5603667ADF4BE37AEEA55A0897B3F123EEE1523DB542931B4A2D6749A0D7A0F5D0E20E", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942641", + "08D999057BA3D2D969260045C55B97F089025959A6F434D651D207D19FB96E9E4FE0E86EBE0E64F85B96A9C75295DF61", + "717F0E05A4E4C312484017200292458B4D8A278A43933BC16FB1AFA0DA954BD9A002BC15B2C61DD29EAFE190F56BF17F", + }, + { + "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942642", + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", + "C9E821B569D9D390A26167406D6D23D6070BE242D765EB831625CEEC4A0F473EF59F4E30E2817E6285BCE2846F15F1A0", + }, + } + + for v, _ in test_vectors { + x_bytes, _ := hex.decode(transmute([]byte)(v.x), context.temp_allocator) + y_bytes, _ := hex.decode(transmute([]byte)(v.y), context.temp_allocator) + + k_big: big.Int + err := big.set(&k_big, v.scalar, 10, context.temp_allocator) + testing.expectf(t, err == nil, "failed to parse k", err) + + k_sz: int + k_sz, err = big.int_to_bytes_size(&k_big, allocator = context.temp_allocator) + testing.expect(t, err == nil) + + k_bytes := make([]byte, k_sz, context.temp_allocator) + err = big.int_to_bytes_big(&k_big, k_bytes, allocator = context.temp_allocator) + + p, q, expected, g: ec.Point_p384r1 + sc: ec.Scalar_p384r1 + + _ = ec.sc_set_bytes(&sc, k_bytes) + + ec.pt_generator(&g) + ok := ec.pt_set_xy_bytes(&expected, x_bytes, y_bytes) + testing.expectf(t, ok, "failed to set point; %s, %s", v.x, v.y) + + ec.pt_scalar_mul(&p, &g, &sc) + ec.pt_scalar_mul_generator(&q, &sc) + ec.pt_rescale(&p, &p) + ec.pt_rescale(&q, &q) + + testing.expect(t, ec.pt_equal(&p, &q) == 1) + testing.expectf(t, ec.pt_equal(&p, &expected) == 1, "sc: %s actual: %v expected: %v", v.scalar, &p, &expected) + } +} + +@(test) +test_p256_s11n_sec_identity :: proc(t: ^testing.T) { + p: ec.Point_p256r1 + + ec.pt_generator(&p) + ok := ec.pt_set_sec_bytes(&p, []byte{0x00}) + testing.expect(t, ok) + testing.expectf(t, ec.pt_is_identity(&p) == 1, "%v", p) + + b := []byte{0xff} + ok = ec.pt_sec_bytes(b, &p, true) + testing.expect(t, ok) + testing.expect(t, b[0] == 0x00) + + b = []byte{0xff} + ok = ec.pt_sec_bytes(b, &p, false) + testing.expect(t, ok) + testing.expect(t, b[0] == 0x00) +} + +@(test) +test_p256_s11n_sec_generator :: proc(t: ^testing.T) { + p, g: ec.Point_p256r1 + + ec.pt_generator(&g) + ec.pt_identity(&p) + + b: [65]byte + ok := ec.pt_sec_bytes(b[:], &g, false) + testing.expect(t, ok) + s := (string)(hex.encode(b[:], context.temp_allocator)) + testing.expectf(t, s == P256_G_UNCOMPRESSED, "g: %v bytes: %v, %v", g, P256_G_UNCOMPRESSED, s) + + ok = ec.pt_set_sec_bytes(&p, b[:]) + testing.expectf(t, ok, "%s", s) + testing.expect(t, ec.pt_equal(&g, &p) == 1) +} + +@(test) +test_p256_sc_inv :: proc(t: ^testing.T) { + if crypto.HAS_RAND_BYTES == false { + return + } + + sc, sc_inv, sc_prod, sc_one: ec.Scalar_p256r1 + ec.sc_set_random(&sc) + ec.sc_inv(&sc_inv, &sc) + ec.sc_one(&sc_one) + + ec.sc_mul(&sc_prod, &sc, &sc_inv) + testing.expect(t, ec.sc_equal(&sc_prod, &sc_one) == 1) +} + +@(test) +test_p384_sc_inv :: proc(t: ^testing.T) { + if crypto.HAS_RAND_BYTES == false { + return + } + + sc, sc_inv, sc_prod, sc_one: ec.Scalar_p384r1 + ec.sc_set_random(&sc) + ec.sc_inv(&sc_inv, &sc) + ec.sc_one(&sc_one) + + ec.sc_mul(&sc_prod, &sc, &sc_inv) + testing.expect(t, ec.sc_equal(&sc_prod, &sc_one) == 1) +} \ No newline at end of file diff --git a/tests/core/crypto/wycheproof/README.md b/tests/core/crypto/wycheproof/README.md new file mode 100644 index 000000000..29381c9c0 --- /dev/null +++ b/tests/core/crypto/wycheproof/README.md @@ -0,0 +1,13 @@ +### odin-wycheproof - Odin core/crypto tests +#### Yawning Angel (yawning at schwanenlied dot me) + +This is a test harness that exercises the [Odin][1] `core/crypto` +library with corpus from [Wycheproof][2]. + +``` +$ odin build . -o:speed +$ ./odin-wycheproof ../wycheproof +``` + +[1]: https://odin-lang.org +[2]: https://github.com/C2SP/wycheproof diff --git a/tests/core/crypto/wycheproof/helpers.odin b/tests/core/crypto/wycheproof/helpers.odin new file mode 100644 index 000000000..fb6b3ddf9 --- /dev/null +++ b/tests/core/crypto/wycheproof/helpers.odin @@ -0,0 +1,76 @@ +package test_wycheproof + +import "core:crypto/hash" +import "core:fmt" +import "core:strings" + +panic_fn :: proc(arg: any) + +hash_name_to_algorithm :: proc(alg_str: string) -> (hash.Algorithm, bool) { + alg_enums := [][hash.Algorithm]string { + hash.ALGORITHM_NAMES, + // The HMAC test vectors omit `-`. + #partial [hash.Algorithm]string { + .SHA224 = "SHA224", + .SHA256 = "SHA256", + .SHA384 = "SHA384", + .SHA512 = "SHA512", + .SHA512_256 = "SHA512/256", + .Insecure_SHA1 = "SHA1", + }, + } + for &e in alg_enums { + for n, alg in e { + if n == alg_str { + return alg, true + } + } + } + + return .Invalid, false +} + +MAC_ALGORITHM :: enum { + Invalid, + HMAC, + KMAC128, + KMAC256, + SIPHASH_1_3, + SIPHASH_2_4, + SIPHASH_4_8, +} + +mac_algorithm :: proc(alg_str: string) -> (MAC_ALGORITHM, hash.Algorithm, string, bool) { + PREFIX_HMAC :: "HMAC" + + if strings.has_prefix(alg_str, PREFIX_HMAC) { + alg_str_ := strings.trim_prefix(alg_str, PREFIX_HMAC) + alg, ok := hash_name_to_algorithm(alg_str_) + alg_str_ = fmt.aprintf("hmac/%s", strings.to_lower(alg_str_)) + return .HMAC, alg, alg_str_, ok + } + + ALG_KMAC128 :: "KMAC128" + ALG_KMAC256 :: "KMAC256" + ALG_SIPHASH_1_3 :: "SipHash-1-3" + ALG_SIPHASH_2_4 :: "SipHash-2-4" + ALG_SIPHASH_4_8 :: "SipHash-4-8" + + mac_alg := MAC_ALGORITHM.Invalid + ok := true + switch alg_str { + case ALG_KMAC128: + mac_alg = .KMAC128 + case ALG_KMAC256: + mac_alg = .KMAC256 + case ALG_SIPHASH_1_3: + mac_alg = .SIPHASH_1_3 + case ALG_SIPHASH_2_4: + mac_alg = .SIPHASH_2_4 + case ALG_SIPHASH_4_8: + mac_alg = .SIPHASH_4_8 + case: + ok = false + } + return mac_alg, .Invalid, strings.to_lower(alg_str), ok +} \ No newline at end of file diff --git a/tests/core/crypto/wycheproof/helpers_generic.odin b/tests/core/crypto/wycheproof/helpers_generic.odin new file mode 100644 index 000000000..381005dfa --- /dev/null +++ b/tests/core/crypto/wycheproof/helpers_generic.odin @@ -0,0 +1,10 @@ +#+build !linux +package test_wycheproof + +case_should_panic :: proc(fn: panic_fn, fn_arg: any, panic_str: string) -> bool { + panic("helpers: testing for panic is unsupported on this target") +} + +can_test_panic :: proc() -> bool { + return false +} diff --git a/tests/core/crypto/wycheproof/helpers_linux.odin b/tests/core/crypto/wycheproof/helpers_linux.odin new file mode 100644 index 000000000..b9f1c0632 --- /dev/null +++ b/tests/core/crypto/wycheproof/helpers_linux.odin @@ -0,0 +1,71 @@ +#+build linux +package test_wycheproof + +import "core:log" +import "core:os" +import "core:strings" +import "core:sys/linux" + +@(private) +PIPE_BUF :: 4096 + +case_should_panic :: proc(fn: panic_fn, fn_arg: any, panic_str: string) -> bool { + stderr_pipe: [2]linux.Fd + + if err := linux.pipe2(&stderr_pipe, linux.Open_Flags{}); err != .NONE { + log.errorf("panic_case: failed to create pipe: %v", err) + return false + } + + pid, err := linux.fork() + switch { + case err != .NONE: + log.errorf("panic_case: failed to fork: %v", err) + return false + case pid == 0: + // In the child, redirect stderr to the pipe, run the function that + // is supposed to panic, and exit normally. + linux.dup2(stderr_pipe[1], 2) + fn(fn_arg) + os.exit(0) + } + + // Parent. + defer linux.close(stderr_pipe[0]) + defer linux.close(stderr_pipe[1]) + + // Wait for the child to terminate, and ensure it terminated + // abnormally (SIGILL/SIGTRAP). + wait_status: u32 + linux.wait4(pid, &wait_status, linux.Wait_Options{}, nil) + if !linux.WIFSIGNALED(wait_status) { + log.errorf("panic_case: child did not terminate via signal: %x", wait_status) + return false + } + term_sig := linux.Signal(linux.WTERMSIG(wait_status)) + if term_sig != .SIGILL && term_sig != .SIGTRAP { + log.errorf("panic_case: child terminated via wrong signal: %v", term_sig) + return false + } + + // Consume the child's stderr output from the pipe buffer. + // + // Note: POSIX requires PIPE_BUF be >= 512 bytes, Linux defaults + // to 4096 bytes. Either is sufficient to buffer output for our + // test cases. + buf: [PIPE_BUF]byte + n, _ := linux.read(stderr_pipe[0], buf[:]) + if n == 0 { + log.errorf("panic_case: child stderr empty") + return false + } + s := string(buf[:n]) + + log.debugf("panic case: child stderr: '%s'", s) + + return strings.contains(s, panic_str) +} + +can_test_panic :: proc() -> bool { + return true +} diff --git a/tests/core/crypto/wycheproof/main.odin b/tests/core/crypto/wycheproof/main.odin new file mode 100644 index 000000000..a75a6cd54 --- /dev/null +++ b/tests/core/crypto/wycheproof/main.odin @@ -0,0 +1,1402 @@ +package test_wycheproof + +import "core:encoding/hex" +import "core:log" +import "core:mem" +import "core:os" +import "core:slice" +import "core:strings" +import "core:testing" + +import chacha_simd128 "core:crypto/_chacha20/simd128" +import chacha_simd256 "core:crypto/_chacha20/simd256" +import "core:crypto/aegis" +import "core:crypto/aes" +import "core:crypto/chacha20" +import "core:crypto/chacha20poly1305" +import "core:crypto/ecdh" +import "core:crypto/ecdsa" +import "core:crypto/ed25519" +import "core:crypto/hash" +import "core:crypto/hkdf" +import "core:crypto/hmac" +import "core:crypto/kmac" +import "core:crypto/pbkdf2" +import "core:crypto/siphash" +import "core:crypto/deoxysii" + +// Covered: +// - crypto/aegis +// - aegis128L_test.json +// - aegis256_test.json +// - crypto/aes +// - aes_gcm_test.json +// - crypto/chacha20poly1305 +// - chacha20_poly1305_test.json +// - xchacha20_poly1305_test.json +// - crypto/ed25519 +// - ed25519_test.json +// - crypto/hkdf +// - hkdf_sha1_test.json +// - hkdf_sha256_test.json +// - hkdf_sha384_test.json +// - hkdf_sha512_test.json +// - crypto/hmac (Note: We do not implement SHA-512/224) +// - hmac_sha1_test.json +// - hmac_sha224_test.json +// - hmac_sha256_test.json +// - hmac_sha3_224_test.json +// - hmac_sha3_256_test.json +// - hmac_sha3_384_test.json +// - hmac_sha3_512_test.json +// - hmac_sha384_test.json +// - hmac_sha512_224_test.json +// - hmac_sha512_256_test.json +// - hmac_sha512_test.json +// - hmac_sm3_test.json +// - crypto/kmac +// - kmac128_no_customization_test.json +// - kmac256_no_customization_test.json +// - crypto/pbkdf2 +// - pbkdf2_hmacsha1_test.json +// - pbkdf2_hmacsha224_test.json +// - pbkdf2_hmacsha256_test.json +// - pbkdf2_hmacsha384_test.json +// - pbkdf2_hmacsha512_test.json +// - crypto/siphash +// - siphash_1_3_test.json +// - siphash_2_4_test.json +// - siphash_4_8_test.json +// - crypto/x25519 +// - x25519_test.json +// - crypto/x448 +// - x448_test.json +// - crypto/_weierstrass +// - ecdh_secp256r1_ecpoint_test.json +// - ecdh_secp384r1_ecpoint_test.json +// - ecdsa_secp256r1_sha256_test.json +// - ecdsa_secp256r1_sha512_test.json +// - ecdsa_secp384r1_sha384_test.json +// +// Not covered (not in wycheproof): +// - crypto/blake2b +// - crypto/blake2s +// - crypto/legacy/keccak +// - crypto/legacy/md5 +// - crypto/tuplehash + +ARENA_SIZE :: 4 * 1024 * 1024 // There is no kill like overkill. + +BASE_PATH :: ODIN_ROOT + "tests/core/assets/Wycheproof" +SUFFIX_TEST_JSON :: "_test.json" + +@(test) +print_test_vector_path :: proc(t: ^testing.T) { + log.infof("wycheproof path: %s", BASE_PATH) +} + +test_proc :: proc(_: string) -> bool + +supported_aegis_impls :: proc() -> [dynamic]aes.Implementation { + impls := make([dynamic]aes.Implementation, 0, 2, context.temp_allocator) + append(&impls, aes.Implementation.Portable) + if aegis.is_hardware_accelerated() { + append(&impls, aes.Implementation.Hardware) + } + + return impls +} + +@(test) +test_aead_aegis :: proc(t: ^testing.T) { + arena: mem.Arena + arena_backing := make([]byte, ARENA_SIZE) + defer delete(arena_backing) + mem.arena_init(&arena, arena_backing) + context.allocator = mem.arena_allocator(&arena) + + files := []string { + "aegis128L_test.json", + "aegis256_test.json", + } + + log.debug("aead/aegis: starting") + + for f in files { + mem.free_all() // Probably don't need this, but be safe. + + fn, _ := os.join_path([]string{BASE_PATH, f}, context.allocator) + + test_vectors: Test_Vectors(Aead_Test_Group) + load_ok := load(&test_vectors, fn) + testing.expectf(t, load_ok, "Unable to load {}", f) + if !load_ok { + continue + } + + for impl in supported_aegis_impls() { + testing.expectf(t, test_aead_aegis_impl(&test_vectors, impl), "impl {} failed", impl) + } + } +} + +test_aead_aegis_impl :: proc( + test_vectors: ^Test_Vectors(Aead_Test_Group), + impl: aes.Implementation, +) -> bool { + log.debug("aead/aegis/%v: starting", impl) + + num_ran, num_passed, num_failed, num_skipped: int + for &test_group in test_vectors.test_groups { + for &test_vector in test_group.tests { + num_ran += 1 + + if comment := test_vector.comment; comment != "" { + log.debugf( + "aead/aegis/%v/%d: %s: %+v", + impl, + test_vector.tc_id, + comment, + test_vector.flags, + ) + } else { + log.debugf("aead/aegis/%v/%d: %+v", + impl, + test_vector.tc_id, + test_vector.flags, + ) + } + + key := hexbytes_decode(test_vector.key) + iv := hexbytes_decode(test_vector.iv) + aad := hexbytes_decode(test_vector.aad) + msg := hexbytes_decode(test_vector.msg) + ct := hexbytes_decode(test_vector.ct) + tag := hexbytes_decode(test_vector.tag) + + if len(iv) == 0 { + log.infof( + "aead/aegis/%v/%d: skipped, invalid IVs panic", + impl, + test_vector.tc_id, + ) + num_skipped += 1 + continue + } + + ctx: aegis.Context + aegis.init(&ctx, key, impl) + + if result_is_valid(test_vector.result) { + ct_ := make([]byte, len(ct)) + tag_ := make([]byte, len(tag)) + aegis.seal(&ctx, ct_, tag_, iv, aad, msg) + + ok := hexbytes_compare(test_vector.ct, ct_) + if !result_check(test_vector.result, ok) { + x := transmute(string)(hex.encode(ct_)) + log.errorf( + "aead/aegis/%v/%d: ciphertext: expected %s actual %s", + impl, + test_vector.tc_id, + test_vector.ct, + x, + ) + num_failed += 1 + continue + } + + ok = hexbytes_compare(test_vector.tag, tag_) + if !result_check(test_vector.result, ok) { + x := transmute(string)(hex.encode(tag_)) + log.errorf( + "aead/aegis/%v/%d: tag: expected %s actual %s", + impl, + test_vector.tc_id, + test_vector.tag, + x, + ) + num_failed += 1 + continue + } + } + + msg_ := make([]byte, len(msg)) + ok := aegis.open(&ctx, msg_, iv, aad, ct, tag) + if !result_check(test_vector.result, ok) { + log.errorf("aead/aegis/%v/%d: decrypt failed", impl, test_vector.tc_id) + num_failed += 1 + continue + } + + if ok && !hexbytes_compare(test_vector.msg, msg_) { + x := transmute(string)(hex.encode(msg_)) + log.errorf( + "aead/aegis/%v/%d: decrypt msg: expected %s actual %s", + impl, + test_vector.tc_id, + test_vector.msg, + x, + ) + num_failed += 1 + continue + } + + num_passed += 1 + } + } + + assert(num_ran == test_vectors.number_of_tests) + assert(num_passed + num_failed + num_skipped == num_ran) + + log.infof( + "aead/aegis: ran %d, passed %d, failed %d, skipped %d", + num_ran, + num_passed, + num_failed, + num_skipped, + ) + + return num_failed == 0 +} + +supported_aes_impls :: proc() -> [dynamic]aes.Implementation { + impls := make([dynamic]aes.Implementation, 0, 2) + append(&impls, aes.Implementation.Portable) + if aes.is_hardware_accelerated() { + append(&impls, aes.Implementation.Hardware) + } + + return impls +} + +@(test) +test_aead_aes_gcm :: proc(t: ^testing.T) { + arena: mem.Arena + arena_backing := make([]byte, ARENA_SIZE) + defer delete(arena_backing) + mem.arena_init(&arena, arena_backing) + context.allocator = mem.arena_allocator(&arena) + + fn, _ := os.join_path([]string{BASE_PATH, "aes_gcm_test.json"}, context.allocator) + + log.debug("aead/aes-gcm: starting") + + test_vectors: Test_Vectors(Aead_Test_Group) + assert(load(&test_vectors, fn)) + + for impl in supported_aes_impls() { + testing.expectf(t, test_aead_aes_gcm_impl(&test_vectors, impl), "impl {} failed", impl) + } +} + +test_aead_aes_gcm_impl :: proc( + test_vectors: ^Test_Vectors(Aead_Test_Group), + impl: aes.Implementation, +) -> bool { + log.debug("aead/aes-gcm/%v: starting", impl) + + num_ran, num_passed, num_failed, num_skipped: int + for &test_group in test_vectors.test_groups { + for &test_vector in test_group.tests { + num_ran += 1 + + if comment := test_vector.comment; comment != "" { + log.debugf( + "aead/aes-gcm/%v/%d: %s: %+v", + impl, + test_vector.tc_id, + comment, + test_vector.flags, + ) + } else { + log.debugf("aead/aes-gcm/%v/%d: %+v", + impl, + test_vector.tc_id, + test_vector.flags, + ) + } + + key := hexbytes_decode(test_vector.key) + iv := hexbytes_decode(test_vector.iv) + aad := hexbytes_decode(test_vector.aad) + msg := hexbytes_decode(test_vector.msg) + ct := hexbytes_decode(test_vector.ct) + tag := hexbytes_decode(test_vector.tag) + + if len(iv) == 0 { + log.infof( + "aead/aes-gcm/%v/%d: skipped, invalid IVs panic", + impl, + test_vector.tc_id, + ) + num_skipped += 1 + continue + } + + ctx: aes.Context_GCM + aes.init_gcm(&ctx, key, impl) + + if result_is_valid(test_vector.result) { + ct_ := make([]byte, len(ct)) + tag_ := make([]byte, len(tag)) + aes.seal_gcm(&ctx, ct_, tag_, iv, aad, msg) + + ok := hexbytes_compare(test_vector.ct, ct_) + if !result_check(test_vector.result, ok) { + x := transmute(string)(hex.encode(ct_)) + log.errorf( + "aead/aes-gcm/%v/%d: ciphertext: expected %s actual %s", + impl, + test_vector.tc_id, + test_vector.ct, + x, + ) + num_failed += 1 + continue + } + + ok = hexbytes_compare(test_vector.tag, tag_) + if !result_check(test_vector.result, ok) { + x := transmute(string)(hex.encode(tag_)) + log.errorf( + "aead/aes-gcm/%v/%d: tag: expected %s actual %s", + impl, + test_vector.tc_id, + test_vector.tag, + x, + ) + num_failed += 1 + continue + } + } + + msg_ := make([]byte, len(msg)) + ok := aes.open_gcm(&ctx, msg_, iv, aad, ct, tag) + if !result_check(test_vector.result, ok) { + log.errorf("aead/aes-gcm/%v/%d: decrypt failed", impl, test_vector.tc_id) + num_failed += 1 + continue + } + + if ok && !hexbytes_compare(test_vector.msg, msg_) { + x := transmute(string)(hex.encode(msg_)) + log.errorf( + "aead/aes-gcm/%v/%d: decrypt msg: expected %s actual %s", + impl, + test_vector.tc_id, + test_vector.msg, + x, + ) + num_failed += 1 + continue + } + + num_passed += 1 + } + } + + assert(num_ran == test_vectors.number_of_tests) + assert(num_passed + num_failed + num_skipped == num_ran) + + log.infof( + "aead/aes-gcm: ran %d, passed %d, failed %d, skipped %d", + num_ran, + num_passed, + num_failed, + num_skipped, + ) + + return num_failed == 0 +} + +supported_chacha_impls :: proc() -> [dynamic]chacha20.Implementation { + impls := make([dynamic]chacha20.Implementation, 0, 3) + append(&impls, chacha20.Implementation.Portable) + if chacha_simd128.is_performant() { + append(&impls, chacha20.Implementation.Simd128) + } + if chacha_simd256.is_performant() { + append(&impls, chacha20.Implementation.Simd256) + } + + return impls +} + +@(test) +test_aead_chacha20_poly1305 :: proc(t: ^testing.T) { + arena: mem.Arena + arena_backing := make([]byte, ARENA_SIZE) + defer delete(arena_backing) + mem.arena_init(&arena, arena_backing) + context.allocator = mem.arena_allocator(&arena) + + files := []string { + "chacha20_poly1305_test.json", + "xchacha20_poly1305_test.json", + } + + log.debug("aead/(x)chacha20poly1305: starting") + + for f, i in files { + mem.free_all() // Probably don't need this, but be safe. + + fn, _ := os.join_path([]string{BASE_PATH, f}, context.allocator) + + test_vectors: Test_Vectors(Aead_Test_Group) + load_ok := load(&test_vectors, fn) + testing.expectf(t, load_ok, "Unable to load {}", f) + if !load_ok { + continue + } + + for impl in supported_chacha_impls() { + testing.expectf(t, test_aead_chacha20_poly1305_impl(&test_vectors, i == 1, impl), "impl {} failed", impl) + } + } +} + +test_aead_chacha20_poly1305_impl :: proc( + test_vectors: ^Test_Vectors(Aead_Test_Group), + is_xchacha: bool, + impl: chacha20.Implementation, +) -> bool { + FLAG_INVALID_NONCE_SIZE :: "InvalidNonceSize" + + alg_str := is_xchacha ? "xchacha20poly1305" : "chacha20poly1305" + + num_ran, num_passed, num_failed, num_skipped: int + for &test_group in test_vectors.test_groups { + for &test_vector in test_group.tests { + num_ran += 1 + + if comment := test_vector.comment; comment != "" { + log.debugf( + "aead/%s/%v/%d: %s: %+v", + alg_str, + impl, + test_vector.tc_id, + comment, + test_vector.flags, + ) + } else { + log.debugf("aead/%s/%v/%d: %+v", + alg_str, + impl, + test_vector.tc_id, + test_vector.flags, + ) + } + + key := hexbytes_decode(test_vector.key) + iv := hexbytes_decode(test_vector.iv) + aad := hexbytes_decode(test_vector.aad) + msg := hexbytes_decode(test_vector.msg) + ct := hexbytes_decode(test_vector.ct) + tag := hexbytes_decode(test_vector.tag) + + if slice.contains(test_vector.flags, FLAG_INVALID_NONCE_SIZE) { + log.infof( + "aead/%s/%v/%d: skipped, invalid nonces panic", + alg_str, + impl, + test_vector.tc_id, + ) + num_skipped += 1 + continue + } + + ctx: chacha20poly1305.Context + switch is_xchacha { + case true: + chacha20poly1305.init_xchacha(&ctx, key, impl) + case false: + chacha20poly1305.init(&ctx, key, impl) + } + + if result_is_valid(test_vector.result) { + ct_ := make([]byte, len(ct)) + tag_ := make([]byte, len(tag)) + chacha20poly1305.seal(&ctx, ct_, tag_, iv, aad, msg) + + ok := hexbytes_compare(test_vector.ct, ct_) + if !result_check(test_vector.result, ok) { + x := transmute(string)(hex.encode(ct_)) + log.errorf( + "aead/%s/%v/%d: ciphertext: expected %s actual %s", + alg_str, + impl, + test_vector.tc_id, + test_vector.ct, + x, + ) + num_failed += 1 + continue + } + + ok = hexbytes_compare(test_vector.tag, tag_) + if !result_check(test_vector.result, ok) { + x := transmute(string)(hex.encode(tag_)) + log.errorf( + "aead/%s/%v/%d: tag: expected %s actual %s", + alg_str, + impl, + test_vector.tc_id, + test_vector.tag, + x, + ) + num_failed += 1 + continue + } + } + + msg_ := make([]byte, len(msg)) + ok := chacha20poly1305.open(&ctx, msg_, iv, aad, ct, tag) + if !result_check(test_vector.result, ok) { + log.errorf("aead/%s/%v/%d: decrypt failed", + alg_str, + impl, + test_vector.tc_id, + ) + num_failed += 1 + continue + } + + if ok && !hexbytes_compare(test_vector.msg, msg_) { + x := transmute(string)(hex.encode(msg_)) + log.errorf( + "aead/%s/%v/%d: decrypt msg: expected %s actual %s", + alg_str, + impl, + test_vector.tc_id, + test_vector.msg, + x, + ) + num_failed += 1 + continue + } + + num_passed += 1 + } + } + + assert(num_ran == test_vectors.number_of_tests) + assert(num_passed + num_failed + num_skipped == num_ran) + + log.infof( + "aead/%s/%v: ran %d, passed %d, failed %d, skipped %d", + alg_str, + impl, + num_ran, + num_passed, + num_failed, + num_skipped, + ) + + return num_failed == 0 +} + +@(test) +test_aead_deoxysii :: proc(t: ^testing.T) { + ctx: deoxysii.Context + + key: [deoxysii.KEY_SIZE]byte + iv: [deoxysii.IV_SIZE]byte + tag: [deoxysii.TAG_SIZE]byte + buf: [4096]byte + + deoxysii.init(&ctx, key[:]) + deoxysii.seal(&ctx, buf[:], tag[:], iv[:], nil, buf[:]) + assert(deoxysii.open(&ctx, buf[:], iv[:], nil, buf[:], tag[:])) +} + +@(test) +test_eddsa_ed25519 :: proc(t: ^testing.T) { + arena: mem.Arena + arena_backing := make([]byte, ARENA_SIZE) + defer delete(arena_backing) + mem.arena_init(&arena, arena_backing) + context.allocator = mem.arena_allocator(&arena) + + fn_, _ := os.join_path([]string{BASE_PATH, "ed25519_test.json"}, context.allocator) + + log.debug("eddsa/ed25519: starting") + + test_vectors: Test_Vectors(Eddsa_Test_Group) + assert(load(&test_vectors, fn_)) + + num_ran, num_passed, num_failed, num_skipped: int + for &test_group, i in test_vectors.test_groups { + mem.free_all() // Probably don't need this, but be safe. + pk_bytes := hexbytes_decode(test_group.public_key.pk) + + pk: ed25519.Public_Key + pk_ok := ed25519.public_key_set_bytes(&pk, pk_bytes) + testing.expectf(t, pk_ok, "eddsa/ed25519/%d: invalid public key: %s", i, test_group.public_key.pk) + if !pk_ok { + num_failed += len(test_group.tests) + continue + } + + for &test_vector in test_group.tests { + num_ran += 1 + + if comment := test_vector.comment; comment != "" { + log.debugf( + "eddsa/ed25519/%d: %s: %+v", + test_vector.tc_id, + comment, + test_vector.flags, + ) + } else { + log.debugf("eddsa/ed25519/%d: %+v", test_vector.tc_id, test_vector.flags) + } + + msg := hexbytes_decode(test_vector.msg) + sig := hexbytes_decode(test_vector.sig) + + verify_ok := ed25519.verify(&pk, msg, sig) + result_ok := result_check(test_vector.result, verify_ok) + testing.expectf( + t, + result_ok, + "eddsa/ed25519/%d: verify failed: expected %s actual %v", + test_vector.tc_id, + test_vector.result, + verify_ok, + ) + if !result_ok { + num_failed += 1 + continue + } + num_passed += 1 + } + } + + assert(num_ran == test_vectors.number_of_tests) + assert(num_passed + num_failed + num_skipped == num_ran) + + log.infof( + "eddsa/ed25519: ran %d, passed %d, failed %d, skipped %d", + num_ran, + num_passed, + num_failed, + num_skipped, + ) +} + +@(test) +test_ecdsa :: proc(t: ^testing.T) { + arena: mem.Arena + arena_backing := make([]byte, ARENA_SIZE) + defer delete(arena_backing) + mem.arena_init(&arena, arena_backing) + context.allocator = mem.arena_allocator(&arena) + + log.debug("ecdsa: starting") + + files := []string { + "ecdsa_secp256r1_sha256_test.json", + "ecdsa_secp256r1_sha512_test.json", + "ecdsa_secp384r1_sha384_test.json", + } + + for f in files { + mem.free_all() // Probably don't need this, but be safe. + + fn, _ := os.join_path([]string{BASE_PATH, f}, context.allocator) + + test_vectors: Test_Vectors(Ecdsa_Test_Group) + load_ok := load(&test_vectors, fn) + testing.expectf(t, load_ok, "Unable to load {}", f) + if !load_ok { + continue + } + + testing.expectf(t, test_ecdsa_impl(t, &test_vectors), "ecdsa failed") + } +} + +test_ecdsa_impl :: proc(t: ^testing.T, test_vectors: ^Test_Vectors(Ecdsa_Test_Group)) -> bool { + curve_str := test_vectors.test_groups[0].public_key.curve + hash_str := test_vectors.test_groups[0].sha + + curve_alg: ecdsa.Curve + switch curve_str { + case "secp256r1": + curve_alg = .SECP256R1 + case "secp384r1": + curve_alg = .SECP384R1 + case: + log.errorf("ecdsa: unsupported curve: %s", curve_str) + } + + hash_alg: hash.Algorithm + switch hash_str { + case "SHA-256": + hash_alg = .SHA256 + case "SHA-384": + hash_alg = .SHA384 + case "SHA-512": + hash_alg = .SHA512 + case: + log.errorf("ecdsa: unsupported hash: %s", hash_str) + } + + log.debugf("ecdsa/%s/%s: starting", curve_str, hash_str) + + num_ran, num_passed, num_failed, num_skipped: int + for &test_group, i in test_vectors.test_groups { + pk_bytes := hexbytes_decode(test_group.public_key.uncompressed) + + pk: ecdsa.Public_Key + pk_ok := ecdsa.public_key_set_bytes(&pk, curve_alg, pk_bytes) + testing.expectf(t, pk_ok, "ecdsa/%s/%s/%d: invalid public key: %s", curve_str, hash_str, i, test_group.public_key.uncompressed) + if !pk_ok { + num_failed += len(test_group.tests) + continue + } + + for &test_vector in test_group.tests { + num_ran += 1 + + if comment := test_vector.comment; comment != "" { + log.debugf( + "ecda/%s/%s/%d: %s: %+v", + curve_str, + hash_str, + test_vector.tc_id, + comment, + test_vector.flags, + ) + } else { + log.debugf("ecdsa/%s/%s/%d: %+v", curve_str, hash_str, test_vector.tc_id, test_vector.flags) + } + + msg := hexbytes_decode(test_vector.msg) + sig := hexbytes_decode(test_vector.sig) + + verify_ok := ecdsa.verify_asn1(&pk, hash_alg, msg, sig) + result_ok := result_check(test_vector.result, verify_ok) + testing.expectf( + t, + result_ok, + "ecdsa/%s/%s/%d: verify failed: expected %s actual %v", + curve_str, + hash_str, + test_vector.tc_id, + test_vector.result, + verify_ok, + ) + if !result_ok { + num_failed += 1 + continue + } + + num_passed += 1 + } + } + + assert(num_ran == test_vectors.number_of_tests) + assert(num_passed + num_failed + num_skipped == num_ran) + + log.infof( + "ecdsa/%s/%s: ran %d, passed %d, failed %d, skipped %d", + curve_str, + hash_str, + num_ran, + num_passed, + num_failed, + num_skipped, + ) + + return num_failed == 0 +} + +@(test) +test_hkdf :: proc(t: ^testing.T) { + arena: mem.Arena + arena_backing := make([]byte, ARENA_SIZE) + defer delete(arena_backing) + mem.arena_init(&arena, arena_backing) + context.allocator = mem.arena_allocator(&arena) + + log.debug("hkdf: starting") + + files := []string { + "hkdf_sha1_test.json", + "hkdf_sha256_test.json", + "hkdf_sha384_test.json", + "hkdf_sha512_test.json", + } + + for f in files { + mem.free_all() // Probably don't need this, but be safe. + + fn, _ := os.join_path([]string{BASE_PATH, f}, context.allocator) + + test_vectors: Test_Vectors(Hkdf_Test_Group) + load_ok := load(&test_vectors, fn) + testing.expectf(t, load_ok, "Unable to load {}", f) + if !load_ok { + continue + } + + testing.expectf(t, test_hkdf_impl(&test_vectors), "hkdf failed") + } +} + +test_hkdf_impl :: proc(test_vectors: ^Test_Vectors(Hkdf_Test_Group)) -> bool { + PREFIX_HKDF :: "HKDF-" + FLAG_SIZE_TOO_LARGE :: "SizeTooLarge" + + alg_str := strings.trim_prefix(test_vectors.algorithm, PREFIX_HKDF) + alg, ok := hash_name_to_algorithm(alg_str) + if !ok { + return false + } + alg_str = strings.to_lower(alg_str) + + log.debugf("hkdf/%s: starting", alg_str) + + num_ran, num_passed, num_failed, num_skipped: int + for &test_group in test_vectors.test_groups { + for &test_vector in test_group.tests { + num_ran += 1 + + if comment := test_vector.comment; comment != "" { + log.debugf( + "hkdf/%s/%d: %s: %+v", + alg_str, + test_vector.tc_id, + comment, + test_vector.flags, + ) + } else { + log.debugf("hkdf/%s/%d: %+v", alg_str, test_vector.tc_id, test_vector.flags) + } + + ikm := hexbytes_decode(test_vector.ikm) + salt := hexbytes_decode(test_vector.salt) + info := hexbytes_decode(test_vector.info) + + if slice.contains(test_vector.flags, FLAG_SIZE_TOO_LARGE) { + log.infof( + "hkdf/%s/%d: skipped, oversized outputs panic", + alg_str, + test_vector.tc_id, + ) + num_skipped += 1 + continue + } + + okm_ := make([]byte, test_vector.size) + hkdf.extract_and_expand(alg, salt, ikm, info, okm_) + + ok = hexbytes_compare(test_vector.okm, okm_) + if !result_check(test_vector.result, ok) { + x := transmute(string)(hex.encode(okm_)) + log.errorf( + "hkdf/%s/%d: shared: expected %s actual %s", + alg_str, + test_vector.tc_id, + test_vector.okm, + x, + ) + num_failed += 1 + continue + } + + num_passed += 1 + } + } + + assert(num_ran == test_vectors.number_of_tests) + assert(num_passed + num_failed + num_skipped == num_ran) + + log.infof( + "hkdf/%s: ran %d, passed %d, failed %d, skipped %d", + alg_str, + num_ran, + num_passed, + num_failed, + num_skipped, + ) + + return num_failed == 0 +} + +@(test) +test_mac :: proc(t: ^testing.T) { + arena: mem.Arena + arena_backing := make([]byte, ARENA_SIZE) + defer delete(arena_backing) + mem.arena_init(&arena, arena_backing) + context.allocator = mem.arena_allocator(&arena) + + log.debug("mac: starting") + + files := []string { + "hmac_sha1_test.json", + "hmac_sha224_test.json", + "hmac_sha256_test.json", + "hmac_sha3_224_test.json", + "hmac_sha3_256_test.json", + "hmac_sha3_384_test.json", + "hmac_sha3_512_test.json", + "hmac_sha384_test.json", + // "hmac_sha512_224_test.json", + "hmac_sha512_256_test.json", + "hmac_sha512_test.json", + "hmac_sm3_test.json", + "kmac128_no_customization_test.json", + "kmac256_no_customization_test.json", + "siphash_1_3_test.json", + "siphash_2_4_test.json", + "siphash_4_8_test.json", + } + + for f in files { + mem.free_all() // Probably don't need this, but be safe. + + fn, _ := os.join_path([]string{BASE_PATH, f}, context.allocator) + + test_vectors: Test_Vectors(Mac_Test_Group) + load_ok := load(&test_vectors, fn) + testing.expectf(t, load_ok, "Unable to load {}", f) + if !load_ok { + continue + } + + testing.expectf(t, test_mac_impl(&test_vectors), "hkdf failed") + } +} + +test_mac_impl :: proc(test_vectors: ^Test_Vectors(Mac_Test_Group)) -> bool { + PREFIX_HMAC :: "HMAC" + PREFIX_KMAC :: "KMAC" + + mac_alg, hmac_alg, alg_str, ok := mac_algorithm(test_vectors.algorithm) + if !ok { + log.errorf("mac: unsupported algorith: %s", test_vectors.algorithm) + return false + } + + log.debugf("%s: starting", alg_str) + + num_ran, num_passed, num_failed, num_skipped: int + for &test_group in test_vectors.test_groups { + for &test_vector in test_group.tests { + num_ran += 1 + + if comment := test_vector.comment; comment != "" { + log.debugf( + "%s/%d: %s: %+v", + alg_str, + test_vector.tc_id, + comment, + test_vector.flags, + ) + } else { + log.debugf("%s/%d: %+v", alg_str, test_vector.tc_id, test_vector.flags) + } + + key := hexbytes_decode(test_vector.key) + msg := hexbytes_decode(test_vector.msg) + + tag_ := make([]byte, len(test_vector.tag) / 2) + + #partial switch mac_alg { + case .HMAC: + ctx: hmac.Context + hmac.init(&ctx, hmac_alg, key) + hmac.update(&ctx, msg) + if l := hmac.tag_size(&ctx); l == len(tag_) { + hmac.final(&ctx, tag_) + } else { + // Our hmac package does not support truncation. + tmp := make([]byte, l) + hmac.final(&ctx, tmp) + copy(tag_, tmp) + } + case .KMAC128, .KMAC256: + ctx: kmac.Context + #partial switch mac_alg { + case .KMAC128: + kmac.init_128(&ctx, key, nil) + case .KMAC256: + kmac.init_256(&ctx, key, nil) + } + kmac.update(&ctx, msg) + kmac.final(&ctx, tag_) + case .SIPHASH_1_3: + siphash.sum_1_3(msg, key, tag_) + case .SIPHASH_2_4: + siphash.sum_2_4(msg, key, tag_) + case .SIPHASH_4_8: + siphash.sum_4_8(msg, key, tag_) + } + + ok = hexbytes_compare(test_vector.tag, tag_) + if !result_check(test_vector.result, ok) { + x := transmute(string)(hex.encode(tag_)) + log.errorf( + "%s/%d: tag: expected %s actual %s", + alg_str, + test_vector.tc_id, + test_vector.tag, + x, + ) + num_failed += 1 + continue + } + + num_passed += 1 + } + } + + assert(num_ran == test_vectors.number_of_tests) + assert(num_passed + num_failed + num_skipped == num_ran) + + log.infof( + "%s: ran %d, passed %d, failed %d, skipped %d", + alg_str, + num_ran, + num_passed, + num_failed, + num_skipped, + ) + + return num_failed == 0 +} + +@(test) +test_pbkdf2 :: proc(t: ^testing.T) { + arena: mem.Arena + arena_backing := make([]byte, ARENA_SIZE) + defer delete(arena_backing) + mem.arena_init(&arena, arena_backing) + context.allocator = mem.arena_allocator(&arena) + + log.debug("pbkdf2: starting") + + files := []string { + "pbkdf2_hmacsha1_test.json", + "pbkdf2_hmacsha224_test.json", + "pbkdf2_hmacsha256_test.json", + "pbkdf2_hmacsha384_test.json", + "pbkdf2_hmacsha512_test.json", + } + + for f in files { + mem.free_all() // Probably don't need this, but be safe. + + fn, _ := os.join_path([]string{BASE_PATH, f}, context.allocator) + + test_vectors: Test_Vectors(Pbkdf_Test_Group) + load_ok := load(&test_vectors, fn) + testing.expectf(t, load_ok, "Unable to load {}", f) + if !load_ok { + continue + } + + testing.expectf(t, test_pbkdf2_impl(&test_vectors), "pbkdf2 failed") + } +} + +test_pbkdf2_impl :: proc( + test_vectors: ^Test_Vectors(Pbkdf_Test_Group), +) -> bool { + PREFIX_PBKDF_HMAC :: "PBKDF2-HMAC" + FLAG_LARGE_ITERATION_COUNT :: "LargeIterationCount" + + alg_str := strings.trim_prefix(test_vectors.algorithm, PREFIX_PBKDF_HMAC) + alg, ok := hash_name_to_algorithm(alg_str) + if !ok { + return false + } + alg_str = strings.to_lower(alg_str) + + log.debugf("pbkdf2/hmac-%s: starting", alg_str) + + num_ran, num_passed, num_failed, num_skipped: int + for &test_group in test_vectors.test_groups { + for &test_vector in test_group.tests { + num_ran += 1 + + if comment := test_vector.comment; comment != "" { + log.debugf( + "pbkdf2/hmac-%s/%d: %s: %+v", + alg_str, + test_vector.tc_id, + comment, + test_vector.flags, + ) + } else { + log.debugf("pbkdf2/hmac-%s/%d: %+v", alg_str, test_vector.tc_id, test_vector.flags) + } + + if slice.contains(test_vector.flags, FLAG_LARGE_ITERATION_COUNT) { + log.infof( + "pbkdf2/hmac-%s/%d: skipped, takes fucking forever", + alg_str, + test_vector.tc_id, + ) + num_skipped += 1 + continue + } + + password := hexbytes_decode(test_vector.password) + salt := hexbytes_decode(test_vector.salt) + + dk_ := make([]byte, test_vector.dk_len) + pbkdf2.derive(alg, password, salt, test_vector.iteration_count, dk_) + + ok = hexbytes_compare(test_vector.dk, dk_) + if !result_check(test_vector.result, ok) { + x := transmute(string)(hex.encode(dk_)) + log.errorf( + "pbkdf2/hmac-%s/%d: shared: expected %s actual %s", + alg_str, + test_vector.tc_id, + test_vector.dk, + x, + ) + num_failed += 1 + continue + } + + num_passed += 1 + } + } + + assert(num_ran == test_vectors.number_of_tests) + assert(num_passed + num_failed + num_skipped == num_ran) + + log.infof( + "pbkdf2/%s: ran %d, passed %d, failed %d, skipped %d", + alg_str, + num_ran, + num_passed, + num_failed, + num_skipped, + ) + + return num_failed == 0 +} + +@(test) +test_ecdh :: proc(t: ^testing.T) { + arena: mem.Arena + arena_backing := make([]byte, ARENA_SIZE) + defer delete(arena_backing) + mem.arena_init(&arena, arena_backing) + context.allocator = mem.arena_allocator(&arena) + + PREFIX_TEST_ECDH :: "ecdh_" + SUFFIX_TEST_ECPOINT :: "_ecpoint" + + files := []string { + "ecdh_secp256r1_ecpoint_test.json", + "ecdh_secp384r1_ecpoint_test.json", + "x25519_test.json", + "x448_test.json", + } + + log.debug("ecdh: starting") + + for f in files { + mem.free_all() // Probably don't need this, but be safe. + + fn, _ := os.join_path([]string{BASE_PATH, f}, context.allocator) + + test_vectors: Test_Vectors(Ecdh_Test_Group) + load_ok := load(&test_vectors, fn) + testing.expectf(t, load_ok, "Unable to load {}", f) + if !load_ok { + continue + } + + alg_str := strings.trim_suffix(f, SUFFIX_TEST_JSON) + alg_str = strings.trim_suffix(alg_str, SUFFIX_TEST_ECPOINT) + alg_str = strings.trim_prefix(alg_str, PREFIX_TEST_ECDH) + testing.expectf(t, test_ecdh_impl(&test_vectors, alg_str), "alg {} failed", alg_str) + } +} + +test_ecdh_impl :: proc( + test_vectors: ^Test_Vectors(Ecdh_Test_Group), + alg_str: string, +) -> bool { + ALG_P256 :: "secp256r1" + ALG_P384 :: "secp384r1" + ALG_X25519 :: "x25519" + ALG_X448 :: "x448" + + // XDH exceptions + FLAG_PUBLIC_KEY_TOO_LONG :: "PublicKeyTooLong" + FLAG_ZERO_SHARED_SECRET :: "ZeroSharedSecret" + + // ECDH exceptions + FLAG_COMPRESSED_POINT :: "CompressedPoint" + FLAG_INVALID_CURVE :: "InvalidCurveAttack" + FLAG_INVALID_ENCODING :: "InvalidEncoding" + + log.debugf("ecdh/%s: starting", alg_str) + + num_ran, num_passed, num_failed, num_skipped: int + for &test_group in test_vectors.test_groups { + for &test_vector in test_group.tests { + num_ran += 1 + + if comment := test_vector.comment; comment != "" { + log.debugf("ecdh/%s/%d: %s: %+v", alg_str, test_vector.tc_id, comment, test_vector.flags) + } else { + log.debugf("ecdh/%s/%d: %+v", alg_str, test_vector.tc_id, test_vector.flags) + } + + raw_pub := hexbytes_decode(test_vector.public) + raw_priv := hexbytes_decode(test_vector.private) + + curve: ecdh.Curve + priv_key: ecdh.Private_Key + pub_key: ecdh.Public_Key + + is_nist, is_xdh: bool + switch alg_str { + case ALG_P256: + curve = .SECP256R1 + // Ugh, ASN.1 :( + l := len(raw_priv) + if l == 33 { + if raw_priv[0] == 0 { + raw_priv = raw_priv[1:] + } + } else if l < 32 { + // left-pad.odin + tmp := make([]byte, 32) + copy(tmp[32-l:], raw_priv) + raw_priv = tmp + } + is_nist = true + case ALG_P384: + curve = .SECP384R1 + // Ugh, ASN.1 :( + l := len(raw_priv) + if l == 49 { + if raw_priv[0] == 0 { + raw_priv = raw_priv[1:] + } + } else if l < 48 { + // left-pad.odin + tmp := make([]byte, 48) + copy(tmp[48-l:], raw_priv) + raw_priv = tmp + } + is_nist = true + case ALG_X25519: + curve = .X25519 + is_xdh = true + case ALG_X448: + curve = .X448 + is_xdh = true + case: + log.errorf("ecdh: unsupported algorithm: %s", alg_str) + return false + } + + if ok := ecdh.private_key_set_bytes(&priv_key, curve, raw_priv); !ok { + log.errorf( + "ecdh/%s/%d: failed to deserialize private_key: %s %d %x", + alg_str, + test_vector.tc_id, + test_vector.private, + len(raw_priv), + raw_priv, + ) + num_failed += 1 + continue + } + + if ok := ecdh.public_key_set_bytes(&pub_key, curve, raw_pub); !ok { + if is_nist { + if slice.contains(test_vector.flags, FLAG_COMPRESSED_POINT) { + num_passed += 1 + continue + } + if slice.contains(test_vector.flags, FLAG_INVALID_CURVE) { + num_passed += 1 + continue + } + if slice.contains(test_vector.flags, FLAG_INVALID_ENCODING) { + num_passed += 1 + continue + } + } + if slice.contains(test_vector.flags, FLAG_PUBLIC_KEY_TOO_LONG) { + num_passed += 1 + continue + } + + log.errorf( + "ecdh/%s/%d: failed to deserialize public_key: %s", + alg_str, + test_vector.tc_id, + test_vector.public, + ) + num_failed += 1 + continue + } + + shared := make([]byte, ecdh.SHARED_SECRET_SIZES[curve]) + + ok := ecdh.ecdh(&priv_key, &pub_key, shared) + if !ok { + if is_xdh && slice.contains(test_vector.flags, FLAG_ZERO_SHARED_SECRET) { + num_passed += 1 + continue + } + // unused: x := transmute(string)(hex.encode(shared)) + log.errorf( + "ecdh/%s/%d: ecdh failed", + alg_str, + test_vector.tc_id, + ) + num_failed += 1 + continue + } + + ok = hexbytes_compare(test_vector.shared, shared) + // "acceptable" results are fine from here because we have + // checked for the all-zero shared secret XDH case already. + if !result_check(test_vector.result, ok, false) { + x := transmute(string)(hex.encode(shared)) + log.errorf( + "ecdh/%s/%d: shared: expected %s actual %s", + alg_str, + test_vector.tc_id, + test_vector.shared, + x, + ) + num_failed += 1 + continue + } + + num_passed += 1 + } + } + + assert(num_ran == test_vectors.number_of_tests) + assert(num_passed + num_failed + num_skipped == num_ran) + + log.infof( + "ecdh/%s: ran %d, passed %d, failed %d, skipped %d", + alg_str, + num_ran, + num_passed, + num_failed, + num_skipped, + ) + + return num_failed == 0 +} diff --git a/tests/core/crypto/wycheproof/schemas.odin b/tests/core/crypto/wycheproof/schemas.odin new file mode 100644 index 000000000..a07186dcc --- /dev/null +++ b/tests/core/crypto/wycheproof/schemas.odin @@ -0,0 +1,218 @@ +package test_wycheproof + +import "core:bytes" +import "core:encoding/hex" +@(require) import "core:encoding/json" +@(require) import "core:log" +@(require) import "core:os" + +Hex_Bytes :: string + +hexbytes_compare :: proc(x: Hex_Bytes, b: []byte, allocator := context.allocator) -> bool { + dst := hexbytes_decode(x) + defer delete(dst) + + return bytes.equal(dst, b) +} + +hexbytes_decode :: proc(x: Hex_Bytes, allocator := context.allocator) -> []byte { + dst, ok := hex.decode(transmute([]byte)(x), allocator) + if !ok { + panic("wycheproof/common/Hex_Bytes: invalid hex encoding") + } + + return dst +} + +Result :: string + +result_check :: proc(r: Result, ok: bool, is_strict := true) -> bool { + switch r { + case "valid": + return ok + case "invalid": + return !ok + case "acceptable": + return !is_strict && ok + case: + panic("wycheproof/common/Result: invalid result string") + } +} + +result_is_valid :: proc(r: Result) -> bool { + return r == "valid" +} + +result_is_invalid :: proc(r: Result) -> bool { + return r == "invalid" +} + + +// The type namings are not following Odin convention, to better match +// the schema, though the fields do. + +load :: proc(tvs: ^$T/Test_Vectors, fn: string) -> bool { + raw_json, err := os.read_entire_file_from_path(fn, context.allocator) + if err != os.ERROR_NONE { + log.error("failed to load raw JSON") + return false + } + + if err := json.unmarshal(raw_json, tvs); err != nil { + log.errorf("failed to parse JSON: %v", err) + return false + } + + return true +} + +Test_Vectors :: struct($Test_Group: typeid) { + algorithm: string `json:"algorithm"`, + generator_version: string `json:"generatorVersion"`, + number_of_tests: int `json:"numberOfTests"`, + header: []string `json:"header"`, + notes: map[string]Test_Vectors_Note `json:"notes"`, + schema: string `json:"schema"`, + test_groups: []Test_Group `json:"testGroups"`, +} + +Test_Vectors_Note :: struct { + bug_type: string `json:"bugType"`, + description: string `json:"description"`, + links: []string `json:"links"`, +} + +Aead_Test_Group :: struct { + iv_size: int `json:"ivSize"`, + key_size: int `json:"keySize"`, + tag_size: int `json:"tagSize"`, + tests: []Aead_Test_Vector `json:"tests"`, +} + +Aead_Test_Vector :: struct { + tc_id: int `json:"tcId"`, + comment: string `json:"comment"`, + key: Hex_Bytes `json:"key"`, + iv: Hex_Bytes `json:"iv"`, + aad: Hex_Bytes `json:"aad"`, + msg: Hex_Bytes `json:"msg"`, + ct: Hex_Bytes `json:"ct"`, + tag: Hex_Bytes `json:"tag"`, + result: Result `json:"result"`, + flags: []string `json:"flags"`, +} + +Hkdf_Test_Group :: struct { + key_size: int `json:"keySize"`, + tests: []Hkdf_Test_Vector `json:"tests"`, +} + +Hkdf_Test_Vector :: struct { + tc_id: int `json:"tcId"`, + comment: string `json:"comment"`, + ikm: Hex_Bytes `json:"ikm"`, + salt: Hex_Bytes `json:"salt"`, + info: Hex_Bytes `json:"info"`, + size: int `json:"size"`, + okm: Hex_Bytes `json:"okm"`, + result: Result `json:"result"`, + flags: []string `json:"flags"`, +} + +Mac_Test_Group :: struct { + key_size: int `json:"keySize"`, + tag_size: int `json:"tagSize"`, + tests: []Mac_Test_Vector `json:"tests"`, +} + +Mac_Test_Vector :: struct { + tc_id: int `json:"tcId"`, + comment: string `json:"comment"`, + key: Hex_Bytes `json:"key"`, + msg: Hex_Bytes `json:"msg"`, + tag: Hex_Bytes `json:"tag"`, + result: Result `json:"result"`, + flags: []string `json:"flags"`, +} + +Ecdh_Test_Group :: struct { + curve: string `json:"curve"`, + tests: []Ecdh_Test_Vector `json:"tests"`, +} + +Ecdh_Test_Vector :: struct { + tc_id: int `json:"tcId"`, + comment: string `json:"comment"`, + public: Hex_Bytes `json:"public"`, + private: Hex_Bytes `json:"private"`, + shared: Hex_Bytes `json:"shared"`, + result: Result `json:"result"`, + flags: []string `json:"flags"`, +} + +Eddsa_Test_Group :: struct { + public_key: Eddsa_Key `json:"publicKey"`, + public_key_der: Hex_Bytes `json:"publicKeyDer"`, + public_key_pem: string `json:"publicKeyPem"`, + public_key_jwk: Eddsa_Jwk `json:"publicKeyJwk"`, + type: string `json:"type"`, + tests: []Dsa_Test_Vector `json:"tests"`, +} + +Eddsa_Key :: struct { + type: string `json:"type"`, + curve: string `json:"curve"`, + key_size: int `json:"keySize"`, + pk: Hex_Bytes `json:"pk"`, +} + +Eddsa_Jwk :: struct { + kid: string `json:"kid"`, + crv: string `json:"crv"`, + kty: string `json:"kty"`, + x: string `json:"x"`, +} + +Ecdsa_Key :: struct { + type: string `json:"type"`, + curve: string `json:"curve"`, + key_size: int `json:"keySize"`, + uncompressed: Hex_Bytes `json:"uncompressed"`, + wx: Hex_Bytes `json:"wx"`, + wy: Hex_Bytes `json:"wy"`, +} + +Ecdsa_Test_Group :: struct { + public_key: Ecdsa_Key `json:"publicKey"`, + public_key_der: Hex_Bytes `json:"publicKeyDer"`, + public_key_pem: string `json:"publicKeyPem"`, + type: string `json:"type"`, + sha: string `json:"sha"`, + tests: []Dsa_Test_Vector `json:"tests"`, +} + +Dsa_Test_Vector :: struct { + tc_id: int `json:"tcId"`, + comment: string `json:"comment"`, + msg: Hex_Bytes `json:"msg"`, + sig: Hex_Bytes `json:"sig"`, + result: Result `json:"result"`, + flags: []string `json:"flags"`, +} + +Pbkdf_Test_Group :: struct { + type: string `json:"type"`, + tests: []Pbkdf_Test_Vector `json:"tests"`, +} + +Pbkdf_Test_Vector :: struct { + tc_id: int `json:"tcId"`, + comment: string `json:"comment"`, + password: Hex_Bytes `json:"password"`, + salt: Hex_Bytes `json:"salt"`, + iteration_count: u32 `json:"iterationCount"`, + dk_len: int `json:"dkLen"`, + dk: Hex_Bytes `json:"dk"`, + result: Result `json:"result"`, + flags: []string `json:"flags"`, +} diff --git a/tests/core/download_assets.py b/tests/core/download_assets.py index b39aa059e..46a6c0e86 100644 --- a/tests/core/download_assets.py +++ b/tests/core/download_assets.py @@ -6,9 +6,11 @@ import os import zipfile import hashlib import hmac +import sys +import io +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') -TEST_SUITES = ['PNG', 'XML', 'BMP', 'JPG'] -DOWNLOAD_BASE_PATH = sys.argv[1] + "/{}" +TEST_SUITES = ['PNG', 'XML', 'BMP', 'JPG', 'Wycheproof'] ASSETS_BASE_URL = "https://raw.githubusercontent.com/odin-lang/test-assets/master/{}/{}" HMAC_KEY = "https://odin-lang.org" HMAC_HASH = hashlib.sha3_512 @@ -284,7 +286,345 @@ HMAC_DIGESTS = { 'emblem-1024-progressive.jpg': "7a6f4b112bd7189320c58dcddb9129968bcf268798c1e0c4f2243c10b3e3d9a6962c9f142d9fd65f8fb31e9a1e899008cae22b3ffde713250d315499b412e160", 'emblem-1024-gray.jpg': "4c25aaab92451e0452cdb165833b2b5a51978c2571de9d053950944667847666ba198d3001291615acda098ebe45b7d2d53c210c492f077b04a6bfe386f8a5fd", - 'unicode.xml': "e0cdc94f07fdbb15eea811ed2ae6dcf494a83d197dafe6580c740270feb0d8f5f7146d4a7d4c2d2ea25f8bd9678bc986123484b39399819a6b7262687959d1ae", + 'unicode.xml': "ba3a0f730efd6cbb89a54dafddf8902ace1b4e22e96d5c8e47cfcd1b9b79705d1985ea4abd25c5ede1c47a5a7d9456b25b093c1ec9d7705f0c6bf52a515c9aa9", + + 'a128cbc_hs256_test.json': "4d2c8e5c9c669dba8f4ca88398efaa03003a1f0350a50df6ad94fbc5d93cb9b9ab6f96b727e1bf85298e98b5d5cf2538d38fab745ceca65cd35bf8dd7562ce87", + 'a192cbc_hs384_test.json': "3de5725108dc43dfe49571de089488de035631ff378c7708bd51fcdc854f306ca47cf731c65e45662759c8aed232f5111101d6c33836d9c2f8f700e775b8aa82", + 'a256cbc_hs512_test.json': "ea178a43c0bdf5ba8be435364424829e6d507bd90d5fd946b7c0f95190377f97de9b54c000049ca380d71d64b5e28e3d8977132143243e05559d878311c84c02", + 'aead_aes_siv_cmac_test.json': "b6de9c2559952f0eef286c1d28fd03c2cad4b73f006d3f74fc9f3de9a2c6d213c1851e126d29aa2d40ead31a01caaf301e00bacda7febbf303eabc76097396b4", + 'aegis128L_test.json': "be6f45c99c7814626c108f668aff5577196e8f9500074b3bef2541b16396c6444116108aecb61f0a1fa043a45e9216319fe4e82794eed93c95838e491b1d5571", + 'aegis128_test.json': "334996ec6b297bcb3410d13cfe10d63d884c8e90219a958d50b05adb0ff45acf80a215ca34de92756964f4cadf487734bd8443d67f668e292edd24228e55a8cc", + 'aegis256_test.json': "e134580630fa642024f7b8666f05d53b7e013c6f34614f9e5df1fa272348c8cf30e9ec34d1c7fffcb0c40f13e6a2ac1273e54670ecb6a6851e1ae59f0b6dc623", + 'aes_cbc_pkcs5_test.json': "42ad3d7ccc3409521db3b7d4bcc812b56d5656b0425f93a8d22ada118ee5a1b55c644b162d8074db36dd69b97dce27c8099b0571724eacf0b34bbbb59b4d9e79", + 'aes_ccm_test.json': "ad1585b5fe8a5ba90f5ae825f7c318da47d82ad63e98440ecb981ebad9746fdb2139e7801f6f714b3971e5f97a917714d857cda38e66d5b19eb718c404419c8c", + 'aes_cmac_test.json': "dfcf3e6effe5c7e2a44c4bd7c39fbff2b3537064f39e1407c28e47e5d4ee7fa29ef4225e44ed83b6b4ef24b87e4cecb84342528ff4d0ec28db529a8d3a1b47e4", + 'aes_eax_test.json': "b6ed02c28bd5945feef804ce9af8145f4313bbe6e5c0c4bd09e4138a1b618fe4a48f4fb80359f4dec41e26657840f3e8a9a333fd5edc8a0201924ee49a9b1d37", + 'aes_ff1_base10_test.json': "24c3d89a097b993902fe7913d92d1250f11a4371d2376c6715db1f7ca5e958a4bf52bff70b86c0cd6001acd7d12737d67e8ce78548a9c5b8e628bf7cff004a49", + 'aes_ff1_base16_test.json': "cd4eb61faee16b09f6f6fc99bfbe29439dec618a710b2a4de291ae44c1c8692f6084910abcc0e1445f022942c22b1078cc860b4696b2aab6e4379e8e63dc6188", + 'aes_ff1_base26_test.json': "6f3e6239ce0c0e5213d1c706082989a31519e9198d4f72f2cce8029e2b91aefd5bc522e2040fe807581bc026da659a7cd1c93095382441c3f40bbbeb4ada7f74", + 'aes_ff1_base32_test.json': "84b725e1b89ef9e6e28dd3915b5dd5a6d8858cb119cc5e5c91a94311ebe6c68b833005af227ef50987347a1b9f853ede7aa3b250ba9127ee74cbe0f1ee3d8c31", + 'aes_ff1_base36_test.json': "f1189ce66cfb610520eb0d9383d2dddf39a2ba04b82eae803c31b59cbddab42bd82f18a1aaacc8206f3ff7bb1dd9a75095534d6f3295baa3a9560f85f279dac2", + 'aes_ff1_base45_test.json': "bf370df32834cafe7e71e638d1c034f4540221f052d1a57d8e4ed7e0cbce0dc04d9752246909befcaef8bde6bd43c4336af9d36b2899bfb158becc60bd1b3e35", + 'aes_ff1_base62_test.json': "2f74c4f052e9eb70fbc52229a9e7d73313cf7ffa8ece832d4bbe6923a662e2efe549f1c6959440e2aef32cb682d44dbc3d25afe9f46cf60f3cb49494b94cecc9", + 'aes_ff1_base64_test.json': "284ce27d4903d94d6e5216290460388749e959f34ab7a4cc5080634f1067fe6c2fadcc9f65aa716793a21e3828b5fa364b5172428b48ae08a38b74c217a89053", + 'aes_ff1_base85_test.json': "81c67c4547a39b95db863fe6115d5258d59b345c29f9714f863666b578092a985a1c3af6e140b811c0a501fb70fb5ff23fb3688cd4f31bb47b471a8e4a46ca6e", + 'aes_ff1_radix10_test.json': "121ffd39b271aa4ba33d0cca7c8d53a5854825c6c03d91c115b8c0072f50219e60ccfc039297693b2f38cb0878a2198847f212d4f6401c56adc58c2b3b4693d3", + 'aes_ff1_radix16_test.json': "d77f9ca3f0e31192c932e8efe2995ce08ae29c214f811220ca817937643d44c71f66ee3775a7b28a5f6cfcff087d864e91077dcec1294c8e7e56a5913c824c67", + 'aes_ff1_radix255_test.json': "59201883feddf63968ba6cb685704345ef4a265451e617059df854089e299b6540e32f02171ed84a4d3321eb68da3730f3e2fc0c42d694dd3570f4e3c6ccdf9f", + 'aes_ff1_radix256_test.json': "d89f6b91c278af43634db849a981551aad2b8ec9012cb787cb37cf08a5c0e37569202220cbbc9f68857c01f2b307b3ec6a9c255bb5349dd733a5262d402601c5", + 'aes_ff1_radix26_test.json': "e21360f98d3bb6fb3e810a844a71e7870dc9892d14c9aa72e9e1c2158a7bae0f2458cc430aca4143f5fdd801a3d0ba256503a7e39a0aba9829e12a6fc4c6135a", + 'aes_ff1_radix32_test.json': "b5c74059593c85e902b76eca70bb43683503c7a510f964548830fefb07c71875a79ed0d8bc57df3ff19d3fc0aa6ca383d7a640419c00827bd9a3a44bbc38a541", + 'aes_ff1_radix36_test.json': "ca8e530579bcdbba9edad518bf9487bc8cecdbb0f41a523e292cbf1edbd4d48135b04cbc956b46bcdc2ce4749af3a1d223a69622cd1897ae28c03b4a42cf5f3b", + 'aes_ff1_radix45_test.json': "6711c5ec7e5bb9d855d12f8dc2b2f863b1d22de03322fda7878ad9350834985e134fda6157adbf87f3284111ff34bde9ca325e155e2f779ac5f32f0ec86d01d1", + 'aes_ff1_radix62_test.json': "ded71ce5521e8603b7cefeeadbf448dca6d80394bb73e037e31c7f2018b55c2d1fad727a0969d94d40a3ab3d4d080ce0617b28bc7f2acdfd239e0e281d6420a2", + 'aes_ff1_radix64_test.json': "8f663baf03b24e4d81441a5bee3421c268054c4ae175683698e7410a031275d42f25c13e0d0843c6da53e71abd201ce2e53ad4a928e82ff3eaffa2011ba967ef", + 'aes_ff1_radix65535_test.json': "9260f514add588a56391bd485b8ce97ebb0592e86bc09b050572368681be7f737f1aedd6ab4ad4bb72fb1a5c2168658243d12da0c167eb16c92e361301393721", + 'aes_ff1_radix65536_test.json': "2ffe5c12f6f55c363a3fc5d030d5c2eb7d8d71c14184f069bed0b3d349321831043eb23a35e5a9b79e3f04a8de196bd37438824534a1ba9afeb5ecf29aaa5869", + 'aes_ff1_radix85_test.json': "ba5be98fdf9154ac0d7c1369ea7bdd570c7959e45a1be960e6681974f52e4c77ad71eafe68a86c35974e5ec42accdafb35e638a522298fa4ed146f5c3b31cfbb", + 'aes_gcm_siv_test.json': "fbd2c29f40d396a247f1c5aa2e8823a6d00e1ceaa390bf0900fa99b793801fa2f3b44a8558d8b178a720fdd003a31ecab8598c7d4c709b783cf29d4a1f1c1fee", + 'aes_gcm_test.json': "5a41e50d865cf2e4a206bf96e05bb4f67d74ecd519480ca372d662c64d26dbc954f530c65fd477992de3600c978d3a6447b9e9dbf511a9b2c2ffdac28fbb1d95", + 'aes_gmac_test.json': "3226a4f531c8427a9604591e4486e4fb706ab0b57488ef53415303a503b5409c0f4852add453895434cc94771f59a87604dd15d47c861fd904d4bee0e0921b5c", + 'aes_kwp_test.json': "f9473060ba0e4e24c0b1938a38d1aed9333ae32109132c0c69701d9e706a8c21579444c046546e218d6982d3d90d5cafc2a99d31e3be432b13dda0b9f627a635", + 'aes_siv_cmac_test.json': "a5025be2398884ef5d6b2431db6bb90b9096dbde77f06c353b78d1b35e82f6d5a8e701a025685f95d8412998800293498643017ddc792cee3360c943bbe6590c", + 'aes_wrap_test.json': "b569c6aaac4e01df7e91f2ec942f4a32ea17ec789efe50ba640be5596519e1533dd15aba1dfd3aa2ff29077cfd800caf76adc15e1d8e5f31b10492a96a06175e", + 'aes_xts_test.json': "66ba73b3270436f8706f32e8d7fdb7e47f5638d10db83cf9311feecf70ac3ff1d66ff9aea528250b92e01177786f90fd06e8df72404de2e5c14ecf4aabc6e790", + 'aria_cbc_pkcs5_test.json': "9e8c33fc364d6fec2b541c542d6f822354c3deab61afc37b3c0881388e82e9b1e9c87f28fb6caa639edc765ba362fb98324a232c7f2f7492f6cc794bf57d66a0", + 'aria_ccm_test.json': "28bf6139961f41c8bfedf130cf327ac3012c1116f4dbf820416a912f4928ac8e1e4bf9aa0d7681f9ea43de264125fcd3fdb29d4f9ab9d27a0a72287a85d890bd", + 'aria_cmac_test.json': "1de6a919708adf65b96ade5dbb29a95e894e904f7f6f1a58cba08da927460982bae16ae8fa167f89a3a2889458b6adfba2a39e07990b0c589db06dbea26b6941", + 'aria_gcm_test.json': "663770e79111916abc82309245e64d90a2a75e409aefc17e6965cd183dc843fd810d61f49a3ae8ceaa216cfb9d44782130796f579c5eac75efbe43875678d891", + 'aria_kwp_test.json': "65db98e93fc0a7f4bedb3d8056c5bebf35de24e7bf7059299298e520791e232799e5b8dd733d928c349d6345f74b45c5c44f207a3cf1027d2c7c172ca8eeacb5", + 'aria_wrap_test.json': "4f1ad34ef5819383d5b999abf3fdaaf66c5801d851e83425162aa77d9873478fbab30be31a23955a1e279052e147ab6984de9c48f63d4d5c9732defb5f15e9a6", + 'ascon128a_test.json': "6ee774046ff065ad60c56bffe644ee97b6c617b62a8e291c476854895eb5c49e8c83bcf85fe86a0ad0656e0564bd90bf4ce812e0870c463c2fa50e6fe5672fec", + 'ascon128_test.json': "73d81b184dd53fee8f479d99478943349e5a2dbb997c4aa37482fa17d128e4f8664f8f06a0c2ac7f9668b0ab12b2d1378808c6d2b3b96f01225dc41a83366b0d", + 'ascon80pq_test.json': "dc2d8093cc93537e11d2672508035b4a366878a8b1e3b2d6bdd6bcd87915cff4835c704ced257e841dbc459e223ad8b5e3db21862626263fe9666e7bdfdc6841", + 'camellia_cbc_pkcs5_test.json': "01951132ec42955ce8eb74c1f431f7104212be90e345d16cc01a3cd4639e882f00947fa1009d8500d5b73a76b288cff2ebed7e176662cc862fbe8ddeb3a0fae8", + 'camellia_ccm_test.json': "1ac5a769ace83143ec341d4205e42c8dca037c6242af631c04f6590ecf6895420a14ed70910119bdbe1a9272fb703a7cf4df97943087b2db42775cc78fb189a5", + 'camellia_cmac_test.json': "ce8ca04c8b8316c56076ea913befa8d468d5a92266d3f381930b5fba4832d7be72046ce9c988ef8103ac0c350187ec8c146ef090a21540df6933dd1c31bab78a", + 'camellia_wrap_test.json': "6d261b753a88a10cb813ed9b4ebb25265306582f36998a6761dfa930293d4d3508df609b117aa0d278167fa9ab2e4327165adeff57835935964ecfec5c07307e", + 'chacha20_poly1305_test.json': "4edc434f10a9b026c98901aa7a48933e0de03d24f2445ecd9cb30c2e063390f97ff7e0b58b12135a231845e5771cc38c22b07ae814f85cee14f62d6a68ceeaac", + 'dsa_2048_224_sha224_p1363_test.json': "3de70432fb46585a0d980b124f33fb15ad5bb700d417ee2d051d00a1521507454ee9d1c41ccac04d79a3a76ae4442f4511cfbbfee66c092348d7c9762309d83c", + 'dsa_2048_224_sha224_test.json': "27149b08174f990da4152ff6efefe12c0008e8d24d3385c743d7d5bcaaa97b948da14703156c4142aacdfb324a276f87c1ccffd051fc6261ebc3deec4e9fa101", + 'dsa_2048_224_sha256_p1363_test.json': "7605f35381b9802104810b95e34835de72863ed4898cb56d004d55e7523fa5e12552460594ab0bd62c69ac8156113bffccb3118bfeb78f22566e3a210d96bf75", + 'dsa_2048_224_sha256_test.json': "c57b50d45969cfbe3ec80fb315179887e48e3b743e4d0c9c0384fb4a19220a7159c4033fc077d98266dde50424a0e186faec875408bfbe80d8c63b5bf00bfece", + 'dsa_2048_256_sha256_p1363_test.json': "4ca9c67c5bd4f220025d5725e06b63fb66f2b761f47fac94c84dfb97d433097c6138bd0868ccefa53f5da73d1020e1287dc7152143b125ca141ad27cb5b46c07", + 'dsa_2048_256_sha256_test.json': "67d1860659160aee1d13a2008f370db7afdea022278733b6c64e5204efe6aeefb175cb2e4b4f02fbcb845c010e1041757c37386016fc30143c9f13bc55ff8330", + 'dsa_3072_256_sha256_p1363_test.json': "806d22e4676f4890be78517f64279ba94b2a4d723985ec6002ed05deddda8610518588422a424410d32f3ed4c93b6ea7b0e8b2dfdc0eab8658b88e47041f9374", + 'dsa_3072_256_sha256_test.json': "2a24217dd91e159657c7ab24e26b6f9869a77208ef1c898433d9e10bbb5fd1f00b69e6a3b0ba4c336a8c02fa9208723b5ff782395baf1cd9d7556897cce93975", + 'ecdh_brainpoolP224r1_test.json': "0b654d630ad6bf1faf177631daea94b6d68a17fce1e5da0ab0e12702e206b7fc982aff4d331c6b0e55da536f2b648f06dfea0f10cec7b9d5c7845b1da0591732", + 'ecdh_brainpoolP256r1_test.json': "3df7d06433c5f85bcc834e598d63ba7ca611f859b1102bcdb0363421f0e8bb60154b13dd3639020504dc80ef44ec1aaa72529467ed503d646ec49b3d566b8b0d", + 'ecdh_brainpoolP320r1_test.json': "e3a8cc1e2e028d0cf5926dd507825c863c24ebcbfee685430d80277300bcaca3eb37a1a937b47007e4479bac69bdcd80e83cf3ab583566024b2c15add713311d", + 'ecdh_brainpoolP384r1_test.json': "8161986b7d3d061647a051b176306ca7f5f6a7ed55af77a676e3711b8ce9b4c036ddb65aac3a1789c5366fcb4b048946f4c8611fa0fc8af7deb37ec24ea97fa7", + 'ecdh_brainpoolP512r1_test.json': "0cec6745113ff9e5b79649470dbfaa95e059cf46cce4cc4ebf5f41ec93bd10974ca17e12aba54f75ea9691ccc50a1f8a031f7dc22cc03c17606e2a9258d8b3bc", + 'ecdh_secp224r1_ecpoint_test.json': "63ffedb647198fd97a2aa532175472442169d2c002aac88c8327625fcbe85631614431b5b24172a069311ebbe6ae0aff55f71ac601ec706066caf5268dcd639c", + 'ecdh_secp224r1_pem_test.json': "50e094fde7bb6077e7f378be72b03067ab9509aad6e4d473e982d5d3e710236889e81f10158240d9ea74a835b3f4c1cc6a17ef2deaa8715e1b23b77296f1567b", + 'ecdh_secp224r1_test.json': "ed1d7c38f5203df529252f01ad7a29c91beb1ea8724d46b7e5c819f9447f9dd28575b97802e17fb12ed9b65f72c10aacdb83e10c5b30c43486a4f37b6440a365", + 'ecdh_secp256k1_test.json': "efdde98724a6aa908fb588d79c0ad0dee83534105368b281964223c12e775f947adca5e910dfe457d3da84d8393549c0d753763f4a9461589b60d8adc1b88943", + 'ecdh_secp256k1_webcrypto_test.json': "d019b26616a43bbcb9ae42057b6526cdea94025572d141a0644d20547175b845326328dcfef320a9b66b6a6d18e644932336d958372a7be6cc6677c06a3393bd", + 'ecdh_secp256r1_ecpoint_test.json': "08a3a91f8269082f1557275e14ddd10270d03d04a2e394a1951c7364042f1ab66c7679df4e86869444fa7704d4f546d8ccae597992532539e53e405a080be7cc", + 'ecdh_secp256r1_pem_test.json': "adda0a1ba574fa2e27279d2ab796816dc57c2479ac389c83db2e9467ec3a727d10cb8f05e04741e7cbfcc4966c075ed56ee6f038d3afc09b6e5377b7b035a27d", + 'ecdh_secp256r1_test.json': "89eeee692fe4b898530e25c07d4417287cf326f1cafd0a4f1b3e3a206f4faba8a571a6805d31c7106424c597d8131b5201a5f4e0fd64dfa2cb73775f657066be", + 'ecdh_secp256r1_webcrypto_test.json': "ab289f42fa6a031ee8569f0a67bba6035f43616a369ae3ea88b5b43356a629b739e8fad3b01fe3055d0f8ba1322f25f94fbfbc8942eaa1a69e0766911dd77401", + 'ecdh_secp384r1_ecpoint_test.json': "fc8568f074fa963489d205db2ae25061b725128755b822821d52b2995750882ae1b9be9f5c5daf53b1ff6ae8de223d22d96a64ec5e336c4e671300ad6450cbc0", + 'ecdh_secp384r1_pem_test.json': "b9560104ddb35aa7d2454d140dbf71266af689b0298a77d86092766e950fc1a6c99adeaa875be8c5c27fc0ebaf9d4d97f2dc77c45032f7b1d4de030a8f552eb5", + 'ecdh_secp384r1_test.json': "60c50e940f92bad9b6ceb4e8cb98cba97774e6bbe62490b4fef53a81a8bf1eac0e8ff18b8250413e7b395dd607bf3946f296adc3e2274747c04481a0ace8158f", + 'ecdh_secp384r1_webcrypto_test.json': "db910d22b74b63b0a94f5ce4cf5231d80fde50410a7c118c2ca23f1ef41bf29bb43045d48890871df8ac6a90de0fd58133277acf63ab0524ffacc447e113616e", + 'ecdh_secp521r1_ecpoint_test.json': "54cfaa89c2c7716fdb89e38734ab1300496bb4b1794f789a837553f1c4112c65c2498572f101ce16d0000e4ee5e1f1d39a1e1135749101a7c165df8c502b1a2a", + 'ecdh_secp521r1_pem_test.json': "076b10984795e5e74da179f5d33807707ce305f877c27dbb67cc7009d09ab678ffa2eb730d445121a152566481a040e6a2f8c6b371262694e95ee632268eb8ca", + 'ecdh_secp521r1_test.json': "2c578c3588b0dded23bc1f6b2c3c5cd44824d1d955e92eab77c4d107bfa60965991cc74424a2270a182f92e1c0bd22dd30c1e9dede574eae78f7ee1c17d396d6", + 'ecdh_secp521r1_webcrypto_test.json': "3e9c1d6dcf3cfde667a6a0d4c389a7bcb8308095d0f062fb5a633c0a78695789d79f5f8e637dde866cbaa49a7038e690ae7516aa707fd65320feb2b959c32c80", + 'ecdh_sect283k1_test.json': "54607e398d77eccf7526d8aff7d5243b238dc00c06c072a1c30c9ad2226d8d6da659b83194a2e4dd0a62369f27f8f44c9a50bc716780bf26bb5869a529835df7", + 'ecdh_sect283r1_test.json': "295c73b9daba0acc13fca624d2210c5247b704396b2fe8004d8c62bc5e5434dbda478b547b8b9a7176132de88aba46e1917efb45291561bf8251e284bbf3f257", + 'ecdh_sect409k1_test.json': "161840a74cdb562acf49e3e389f743779aac773f2ea3a4e2920b427617211532514cc83788513533cae8487e486787c89e5fe50066e104b43af15aaf46dddc6a", + 'ecdh_sect409r1_test.json': "f43791e15318478221f6692558115c31590567a8b969d55e648711023e4164ce60b1998585fc89a1b07f8922722203cc36c48069565710f0d7897d5c8dcc7d0d", + 'ecdh_sect571k1_test.json': "b944b9de3b6d3954aeeea4b3ef6b9c7e12cbb25bff6acb385062ec8a35c4e7052384d4c14285f8feb870e9b1042237fbc2e7138db013b5b65edd78f795fb695e", + 'ecdh_sect571r1_test.json': "3baa06212ebaef756daee791abbec499ea145dcdbc54758519503550efa2836ea89717b740e59cfc044a61e88ddc2e3892a168f27c27679a1f89701a66999283", + 'ecdsa_brainpoolP224r1_sha224_p1363_test.json': "b5f9fec57916ab49d1373cbf55ef441edc481825993fae3b07c42a38c3646e90d28075b8b1cc35157928be74b875fdc990bfda582f83ac8a68009bb9804890f6", + 'ecdsa_brainpoolP224r1_sha224_test.json': "f352487bb90f666b6adca5e9c41d48f09c28c69404a884fbff3c6780ded73681e31fdaaf0da1d53a9d8fe964ab4678170ab4f5085e5f551f5e56adab2c9a8e2e", + 'ecdsa_brainpoolP224r1_sha3_224_test.json': "ca83567e3e2d62417974066b5cad977b12627418baccdf4dfe9c9a1972af83de6d3869e25a66a986a062862e5cbdfcef2642b72bcc5deb9b78cbbfa3e8d5cef9", + 'ecdsa_brainpoolP256r1_sha256_p1363_test.json': "9a41d67ee9f2353bf9d54928564db3f0804c4704838bc67af33eb70a1dbce4af70e449fcc74f98192bca9ab2eb0879604bac34bb87e832a7984fcb12c6d4cdfd", + 'ecdsa_brainpoolP256r1_sha256_test.json': "94a6da4a541efc83e29758a2f321d4acc937dff585a9f33ce170f66c0f46c8459db12643e56b41bdbe388d0ea0ad3f6b9a7d3d0cbd58aadc81e66eca4ca68210", + 'ecdsa_brainpoolP256r1_sha3_256_test.json': "efca09da2c39791e634fa5910d9ed4fedf9ec22f6858bc65976e4bdfdcf9eb4af2efe793cc39273d2001ed1f5b394826df91a4ee30d37e4f50aec3451b167aff", + 'ecdsa_brainpoolP320r1_sha384_p1363_test.json': "a3483693f6dbaf99e0c7669602b64a5f19a14e3451b84558f8aff6a73988b48b46c02c9b95cd17263dad25e32721f602898eb2369c607dd6debf64eb294dfa36", + 'ecdsa_brainpoolP320r1_sha384_test.json': "bd2b3290124ca707ac214d0ab0b2f7df44cbe33910f5c690485814333c0fb9df95de39eee99ae392e89dfd151aa1389c89248c5e89e5c9fb9002d159159068e7", + 'ecdsa_brainpoolP320r1_sha3_384_test.json': "02ecf9b37ed128edc759b5ee0530960d719bd724fe7ea7f02fd70486e5cb01d9a51e50f9a7cce9e33ac6c053d7b3b6949011863dad17442e5d642825a2004f71", + 'ecdsa_brainpoolP384r1_sha384_p1363_test.json': "05b23eb103e9d9ad92e015db8871edc6f0ae88ac02a2f7e9a582328a75779ee09dbc5e30aadf3f0bc8f6ae28ddbda90d4bd2502fd33e4bc60cf6ce99b5e76c97", + 'ecdsa_brainpoolP384r1_sha384_test.json': "62c3d506c42a25915cfa8ccc3a7a4d17efe4c725ec95caa94973b30257b08009622035d751d676f857f2e8a2923360db1cfc63c5fcc00963ba877d077d39b2fb", + 'ecdsa_brainpoolP384r1_sha3_384_test.json': "91bdc6d6b1374d688ab0da4be495a8b3ffa5e7834422ce9f27a7256dd9ec1b76488c9a1b3949713784a531a06bd49692b721ecd36f88431b90ea03313f07682a", + 'ecdsa_brainpoolP512r1_sha3_512_test.json': "5ddb3f9b65409291a26567ebf28953f788d6dd5f70b0af39153cb7f20e8cd80a23db9c11362bc86a92697f0d9a77903ad528b16fe23b8cfcf310730d71ba24b2", + 'ecdsa_brainpoolP512r1_sha512_p1363_test.json': "e5383f4df48561e5ff91fe87c67a0a002b14c4d0fd70f345933acd6bed23f9dce35ec92c4cfc5c7d4be5bab2b64780e2de3c8147e00b8ce9140e4c2b39e587c6", + 'ecdsa_brainpoolP512r1_sha512_test.json': "bdacf47247e475e0a259c87b96a77032be653c2fc9489534197a80fc736f16ef0f48f4736c45eafbb875f266a4ef0cfd08f0566d6382ba1abb16ffb4ac741dfc", + 'ecdsa_secp160k1_sha256_p1363_test.json': "56b607a6e9faf19e14c27f4f70d64f9786e3c0de50924ad6715bef65bfd5156b1cd401695ca1c3486227a4d3b9de49d81d70900e07169ad36170c38d2e8a53f1", + 'ecdsa_secp160k1_sha256_test.json': "e48c03f62d45e39d2572097282574421447953bed47168928b930b32680bd68be5aaf7ef0ac6c7632c7ef3887985f0bc1788167299c42e5cbabe5925fb5eeaa5", + 'ecdsa_secp160r1_sha256_p1363_test.json': "0ba341b6a70732017971c0ab38c48b264808bb5aab563bb3c66ef31e685f2491abebe3a3f114d541ac3bcc503b59e7f02e8f35536b9ce781b8f6b9c57c72a731", + 'ecdsa_secp160r1_sha256_test.json': "70b593c449b671b3da62d1224a1c7fc372cc34d5a067fb87f70a65d14a236a47121bef499b072acc9ab2c4c70d3a4305c90b89059719ad41dd2473d5fcb7a14b", + 'ecdsa_secp160r2_sha256_p1363_test.json': "277067478dd5b6f3d81da3bdd706a68429d7d8b0ad85d3c0843ab7bf022a0857df05ca628c61e92358162e75c4a505fedf7c0c643382279bf6ac47e7cf2864c0", + 'ecdsa_secp160r2_sha256_test.json': "2f1b0d917d703e0acdfe863078d46f5dd0a51d9e2fa07b2fa34180aa6ca4b175e6a14f6972b9a2eab3523b5c1d11adacec8c92c969671b379f30ef0b9185ba67", + 'ecdsa_secp192k1_sha256_p1363_test.json': "dc703ac1ee295c20df496009c8beaf6b1f1ebf00654c76f335dcd983ce0a19d3e8c2136be3f78ef2294a58b4f953dba53c8da97786064d66ea8e7d85ec77ff0b", + 'ecdsa_secp192k1_sha256_test.json': "132c2a1656a03397d1334048be3bf3d4825c6e08096196b8d5d1c11843b4e543f0a8c898bb7812355ea8774a979f749c8b8f9e5062e1d91c22d7220c678f8846", + 'ecdsa_secp192r1_sha256_p1363_test.json': "4669db3e1921dacab450e901612cc219ea681941f2b18a0f8c874a018dbccb30edfd421ff167b685180cd6e9ba87c684cb6f0a18d6da467b5f2167fcffc94b5a", + 'ecdsa_secp192r1_sha256_test.json': "9d03dc6a28e9e131ec37a2dbcc66b0d7beabd8b8e43af314b2a1bd5b8e731fb4d0706233d17a4a9b5260e638c1c4b5b7e5cd69357eadd1f02ac19f47b82f7cbf", + 'ecdsa_secp224k1_sha224_p1363_test.json': "28417835fc6237dea10e8f747b2a12d3276409a1746994771562d66d80374c571408eb27dcf907adde920748dded41b00482a26ba1b1a00b07efa4b6939467e9", + 'ecdsa_secp224k1_sha224_test.json': "693254ce147e24c082e913862231c2dec907ef280c95543de17cd22893bb5ba47f5fa0b83854848e583941e60e93bf24d925af26f020e743a6ab6a63e73076b6", + 'ecdsa_secp224k1_sha256_p1363_test.json': "971a6632780defc1022a4138b3df8a8335e2b92e91ecf8971404dc4e71a35ac136b2eb1f4d54fa8474bbaff7a67d918a52fb34ab6101cf7d775766d024f06221", + 'ecdsa_secp224k1_sha256_test.json': "79b739ae824a532c5eedd62de60ce14e11a7b7f5ad0550bc7f97bea21e2db9492c0b0538edfa170e40493ae6dca0fa9b0f9f7e182c5bb503405b246de3d06c2a", + 'ecdsa_secp224r1_sha224_p1363_test.json': "5014189fd6535307640f56df4bb4b11ecc040c95cfde90e8d0da92a55fbd6861257566849b899874106171ed40579981a98f1dfa482b72d021c9dbb409bef254", + 'ecdsa_secp224r1_sha224_test.json': "d81458ba50f06d0157e42abb441f12b0be4c409b1430bdee9d6cf8aba2985d596534b606ec17caa3f176d4c2c9a95fea3aa52a3b3dfa136f287c30348f429c5b", + 'ecdsa_secp224r1_sha256_p1363_test.json': "7b8e4264ce143ada9ab97576c63000629701e602a94ca47045b750f55876a68b9502ee6d4adcb03533c58bf9cb78b3ef4ae8c91361543dc02d29acc210c3804e", + 'ecdsa_secp224r1_sha256_test.json': "6e6aca400c5b5c49a9412aec7263fa75b76577abe19a9decdbe350e580211b9ad08b8a757c74b5674f4d3427f95e452fdac1e8551056c8cc37fc0622be3375ba", + 'ecdsa_secp224r1_sha3_224_test.json': "0468c5c71ff3a7a1e8942e570552f718077a54d83e698cffe7635342fe121935358ad70c7c6f8b69bdfc8454204cc3d772367fdb42302262418d867d8683dee8", + 'ecdsa_secp224r1_sha3_256_test.json': "e423747bd477797d04b3196b4d1690751e045e737b4030010a3662a584eef0ce213562e8c204883a5b8901a970d2d6a736a740161793f6ca73bb5d8469f95381", + 'ecdsa_secp224r1_sha3_512_test.json': "094d0d96b38b87f7060cc28cae6158a0a14092648eab4c85b9e701f5c08e0c9a312a500c452cc0cffdfe46482e5c65ee9973643f3a144902557adca00962d5b4", + 'ecdsa_secp224r1_sha512_p1363_test.json': "02c1d323331ad22eb82ddb44d3f29b48285b3cfcfca43d28a2694f912762188f5dbecd968c0bd3ce7a552641e49502db679eba8044c1a0c5fa9c054273384f5c", + 'ecdsa_secp224r1_sha512_test.json': "9bd69463d1e24c9a086cddba4323a1eed6fe34ebc6d0b087c5e40d067260bda62c07250bf4ab8069b95eff2826fdf4abadc01f5f34d9c37a218bb0f77625d151", + 'ecdsa_secp224r1_shake128_p1363_test.json': "4d675b55466f79ae3308a082b07c3631296ffb947c2cbe8033cb52a3ac3f8a83db484f2f22b4c70d5aa345e1140fcab48ab1067d75e3feb2de260a3bc4ef2baa", + 'ecdsa_secp224r1_shake128_test.json': "4b9ea752fce41061c8de045b33127f665d7a53f627c687c82462775f7b2d9e1fc5e531fb3bdf735218a309afa40d4894ac092c2c8620e3ca1c50f300eb26f6d4", + 'ecdsa_secp256k1_sha256_bitcoin_test.json': "88f6be4d25f879097e12cfdad377c2d77a20189e4b5effd8ea866092e2477e8b48e51e4ba8ce55332ca223edecb30fea69b3a3d8748976d28aed98869e80cf21", + 'ecdsa_secp256k1_sha256_p1363_test.json': "38adcb33ea8cd18ceec78a1c0a7c36d3d8ef47303906751fedea0207f4c3cb1fc57fefc109612c30b61c75b3f9eb91cfb56713a745175d0834841cd660cae327", + 'ecdsa_secp256k1_sha256_test.json': "86a211d21b7bd9d6db3e8aa81ad769373f6e18c3fd05c519af217a5a4304c02abc36b70dd306094c7fddfa6489a9c9b5a3e9cedcea28c4081441db1800ff6aec", + 'ecdsa_secp256k1_sha3_256_test.json': "7d649655e9a1aa67b6c275e2547a7dbee605ec487ab292f2f1c67fa8881cdeca841a82a8093217c521ec2bba36cc9c6e05c0cdc4ce64679fa6654a68c76c3782", + 'ecdsa_secp256k1_sha3_512_test.json': "38e1a39e8aa538f33d4facbef07b9fd9793a95c9c5270c2c41dd9a0da9d2b32cd84dd525fd379de94348794cbd82c8feae1a925b0ff323d260cb01f58eb16f3f", + 'ecdsa_secp256k1_sha512_p1363_test.json': "7bfa57b2accc0071db8c849685769eaa0e20c0a35f18469a284d0e27e340a3f7f1198898d5268500b053b60a0e019308a3b9c536a27c95dde581490a5215c438", + 'ecdsa_secp256k1_sha512_test.json': "1c1b635cbd9a56e910959f3a4551247d1c8a42930a418cf0fa8a686d6370c8730a274ff56cfa4b3e338c9321fb94ee5adaf76dd30ac312db0c7ce74c0457c55a", + 'ecdsa_secp256k1_shake128_p1363_test.json': "ddf80ba820144a9d55775d4ef2ff65117f462943988d0e9be4cdf0dc9a013604d8ad0f638866caa66643f6bb3837480270d528eb4c86ca3233d7b70ac1089e03", + 'ecdsa_secp256k1_shake128_test.json': "da83dc544d289622eede109b35c148715e92e36cedf8146b5c5856431302c0bf2696179122e0d4eda54e8cd2447b78d2198c4dd7a1e38ce436a57e6b9298323c", + 'ecdsa_secp256k1_shake256_p1363_test.json': "d3b27fadc3e13ce29c285d50b579f0552175bb7af62b7982fabd4185c114da01581bde46652beb0c5374ad6fa63217d85a3686fdfcd8a04ac524f5779c995bee", + 'ecdsa_secp256k1_shake256_test.json': "f6a04a4e3706be7c85f5186842c193b030d4e4f7359c71e8b3ce3d78f33b62513f68e76aa841caef9c2de4140755cc5227572bab1d5c978b1585036b2c08d4e3", + 'ecdsa_secp256r1_sha256_p1363_test.json': "b69438a1c52b7848c14d42b5497864e028a00ab2b6bd9535c7ccdda8250a71d4fa6aa8efa133de9d04b2f7e8d4e882955dda5b818a87748a6c42e105deb7a9d7", + 'ecdsa_secp256r1_sha256_test.json': "f3bf0aa82757e24bc0a7ff310d070b41beed993fd6ca83712761a398914783c86d76f4a4aad5bac678f980425ce5f4c1cab05c48de5fdaa22261682789ede7b5", + 'ecdsa_secp256r1_sha3_256_test.json': "c95bd5bf590fec6e7e942dde5ef9736cdaa1f4751bb7ef3898e4cd36fba2f27425ca59d239e653cba9757f531e9ba057966d016f30a0b569b24bd5190cdabbc4", + 'ecdsa_secp256r1_sha3_512_test.json': "3f77e25e3d2c0a9ad73d67ed499adce02b98521acb1bcf4b51c8fda545e849bdca0625789ad635846e1691a175101f6749e0c3885f657e8dd34eb416e3935fe0", + 'ecdsa_secp256r1_sha512_p1363_test.json': "4f0e573b4f56cf770cc64e552b86aeee9503a65aa51f6e6faafef5b81646fa773be21b0bdd0e055bfd607c81dc07ad813860461e3bedde9b7b31be33c16d2f71", + 'ecdsa_secp256r1_sha512_test.json': "542bfa5f83b4a44b497859e114f4d326548743d7955ce627fa8583af1ab704f5ba4e219a87154e41bc43cd4896d375070e95b2f76f5292a28ab6947b92d79254", + 'ecdsa_secp256r1_shake128_p1363_test.json': "91d7684cdf93f62aadcbbceab1f925d0fe383081f99232a6894235c662bfbab7142f097593c290e6a2fd6528d5ba6db9c1a0960f81e5481c89e99a27bee19a1b", + 'ecdsa_secp256r1_shake128_test.json': "5a42bb44f2e5a1671a584110f1664806050ad644631e6f1a67ed3beb6c788e5ba8e9e4933e58a11ddad2006d86d4ab02795b6d58236df15e92d4b268ea995336", + 'ecdsa_secp384r1_sha256_test.json': "b19291081e85e8d5411c01feafa3cd75abfea1e81a12ad90ea5f8d54f0c116c1e79b79be9175e8c9ada21aef5826349e417a0ef93a092339c42562b6192c137f", + 'ecdsa_secp384r1_sha384_p1363_test.json': "fe2204047f88ae726ed5188916110296e59930787b5db8b243cc296b96e449b6e4336ca16c20ef464add1a7712d8775aa9eb149e2460b56ebd73d674ef115984", + 'ecdsa_secp384r1_sha384_test.json': "b34934d80b603f5f1c56eeb341015f91e36ace086479aa677e7e32f5cecc5e25d6e2b8e5901968d9c041173bd828e23e06fa264f1ec5d8c7a242b3bdc7dd060f", + 'ecdsa_secp384r1_sha3_384_test.json': "146a5ff3d62dd4a8a75822e435c55913b7b9c8e40fb93447e65c11471034068783dfe4e5af600280a367988aa1b4b73212d98da6e3f720741b03011829afcda0", + 'ecdsa_secp384r1_sha3_512_test.json': "514de7b81e7b466adc3e255583543eb039d9a9254ce112df48509bae2819d77ab828ead9072484f699c7c0343a6688ec69c1764c3a90b15b4d83c23c99649a95", + 'ecdsa_secp384r1_sha512_p1363_test.json': "1e199e57c2c9529e9b719c63791387b0ce58977603853e10a6ebc77b1a8bae38977d6149a5b9ec8a2d34e99aa6be96c0fefae141250410018d0ccc9241bf46f7", + 'ecdsa_secp384r1_sha512_test.json': "e168ce7aa71cb3456a412ba4dcf370ec0d85b683e588e3aaf43e400a374f848fc508c8a6cccf667e64aa6db5811d7bf7614dbb6b20feee0bab410236c730516b", + 'ecdsa_secp384r1_shake256_p1363_test.json': "9c1e9d8f2366c8a166754bb5966829b97bcf7ce24a138df5af98a5f9b9d1cabd8fcaa5588600fe550362b3a43a0eab01b8d240020bbfffeda1b3cf3954c79709", + 'ecdsa_secp384r1_shake256_test.json': "216fc6a38b2cd11c72dbca9a0c91033bfcd08b9d644d2890aabc56f75993928b1d1be42f9d2e516b8e7f91a76c7284ee9a0a7e3cd3a72a2724cfe262021f88b3", + 'ecdsa_secp521r1_sha3_512_test.json': "1d22bd1409174eca101e466bd145b72d24f7d0a3581b748517d7bf715534f6d785cbaf1c5f3f8c340cc3e3577c23e7e34cb0051d6e45690225e0e91cdcf4ab3d", + 'ecdsa_secp521r1_sha512_p1363_test.json': "d69715e60aecc95138071d9d1f3465aa37a98cd8b2d5eb3a7e49a8dd5a9dcd96ff04e61e45eed576eb391aa4eaec48381cd497b85588a11b2f6d6db5222b2eb9", + 'ecdsa_secp521r1_sha512_test.json': "1014452d732f9a33b6acf340a6fd6ad37457059ce97b0e1c3b2f0f6f39bcf2590cbad459a201571da14305b02fcc847c756afd389cd76103fd99ed973dec693c", + 'ecdsa_secp521r1_shake256_p1363_test.json': "b3aa4a85832cdba635d0b55204e71612af4055ab6eccbff575a16ae9645dd8b70da988c8e176ea9f951c157b48c92f04594e9d61a56eeebbf87b80066ad2ab26", + 'ecdsa_secp521r1_shake256_test.json': "26a3cdc7a24e31efd1d5a6818617d6b68865c04b1ecae8214805b1440d0b691564bb0042cce9635fbdc8d3ef6536a175cd6feea883fdd4bc44cabb07f0486a8a", + 'ec_prime_order_curves_test.json': "e736e7353d810e499290d340ac922faa7f1906018279f3127f4383265f6fbe97f84b4c334b20807666a20608bdb6182ab289cef4ddbf192fbc2a2f49d3e71e73", + 'ed25519_test.json': "c3429b58132268803f3766b686a2e15ef52d9e59a3b1d0462c9d8c2ece0ae8d6d9b41d051ab37ea72388519bab78312500ea7e2052b7fce00271c2a86adf9645", + 'ed448_test.json': "63d02608e45125f3b9e72235a465cc4b050e30ac9914befb17f2cd0478791cef2fb5ac5c36773b836b51c1dac3ce3688b90f69e8dd3a404388cc18379ba447be", + 'hkdf_sha1_test.json': "037187bfb616b1938eb11a0b9afcc0152aa806d9fe1dd944d2524660a9d2c6474059d38265e838de0677bb6b993ab40e1a6ad18c70ca0efaf1cbefde7bfe588c", + 'hkdf_sha256_test.json': "b8d9854b418d79a265b890aec7436f9a6856bed22d7a31506699874e0505b251f5547cf064f9960f56c955a0f95f73ce39011a3ac9e2787a9beb3f5049b3414a", + 'hkdf_sha384_test.json': "424ca85042c09305ff0ff7c1c95ae8bc621a135ff28da42792ea8ec7758d4d3d096fb4a9c01dac8a0359717a4e1f043ff28992e7b19f5d6b2fd4c13e4a5dd0c0", + 'hkdf_sha512_test.json': "ad0988cd4d049284694686c32f350c39ea18c20c4b926d0b5653432d463e3183847387e37fd612cd65376301fad9b8755dc1de577262715adf46869321ebc97a", + 'hmac_sha1_test.json': "b99d895f358207ebca2d9109162d848d94b32ea4eeb71a7a5b10841695020bd2656c9f413b2d42b3fa1926a7edc6330f240d55463e674942e0dfe17ee37116fa", + 'hmac_sha224_test.json': "c3e3d603df286caa065111875550b6713a5e35b7756aafd491b537b5330304293005f62ed535e30ab5f8970803b85e8f1436a6ac4c0d49db33550804cb0b5185", + 'hmac_sha256_test.json': "f763fb3cc36280c67abde9d8cd7182e4762d4eb27708e213dd09f37ef4a88b371169f4b8675b0c4a6ec72fabc6c07823ec9c05e51a36c24eb408e71526123ea4", + 'hmac_sha384_test.json': "c263583f6775713024323e3b2d0ad5f7da811476b002bc835131b5d36f86d9a1271309a2fb06371b451ef08ff65380188fcec4508f829c61d75b25518d03d631", + 'hmac_sha3_224_test.json': "96b3e8b2f1687256c29d781f413eae5566b9769289f78b93676d57ab224cd2e70ff03f1ffefeb6fe5877b75d92609d5dcb6e5ca7331e24d12c3f88f25577890d", + 'hmac_sha3_256_test.json': "ed3d16591015756c72ff09823d87dc36221fbc483190387f129816653b9c96d8797d134e50ad7765197913b04a60a301418f12040b55c51947ca75f0392af745", + 'hmac_sha3_384_test.json': "5bb6387eabfb602060f4e2a7483111a83e0be37d5507b443c5f484ef91c717d2b5af71d8316eada168ebe81a47c0d399e503050928093f424000f92899c73d95", + 'hmac_sha3_512_test.json': "b40c162f68e2878b39c8ee15a7cb381f99e2103346b115d73830cd15531f19c6d607a0327d78cca46788db37e2936b1bcade6739515e951e7e0e79e38e51f7f1", + 'hmac_sha512_224_test.json': "88278c017075ff186dce6aa9a3500cb40a2053cef4bae8ff634aabce422125a199909f50f2dcbdc213098307c8a81fee9efce193d909de213b7342955c411a32", + 'hmac_sha512_256_test.json': "eec3fa84e6bb73505f9e4e76f06443ed6d6c4874fd495f3bc038a04c56e74c5b8e070542c2360a7db383468e15e9479413665113fd7fd10001f77cbaf528f468", + 'hmac_sha512_test.json': "47a25df89a8030c5f9845fadfee5e22fb17902488f85f32e90eed2d87b4251c78b1c98494a1a563d89c52a9312c06f13fdecff6f4db6fa191a47fe5cd887165a", + 'hmac_sm3_test.json': "d3299c5d21c99f2f9da28ee4e348fac2c5fbd69f23f224db74f77db1972f4a2a6813c00cea22a9472cc5a2944b3560a44320eb11b4a6a66a930f5c614cb424f6", + 'json_web_crypto_test.json': "6e7f5c6218b460255560f547bd5f730e9be43d64702f1f42bfbda74eb8b043f9da51a0c8569b5433305793aa6942bbb8af3f83ee33e5677b0adcce911dc2c9bc", + 'json_web_encryption_test.json': "ba8f4ce4c48102e32662e655ccace79ab6413be8c6292df85c7be32978892f5e280ecbb23c2f5bebbf18d2581458e2ddcf0d38a92513a4482f779b28da0a80a7", + 'json_web_key_test.json': "35ce8c596fdede766bbf60bcf3cd2be5e8cc2a874fb5545722374817234da3a4dd2e5462645dbbddd7ca346884c5c9064e13ee12eb57dd013c87874e029c24af", + 'json_web_signature_test.json': "f57e6dd1ec52fe8f4412a5622310813d44c2c5b0ecc12c58ec68527fe433b4d4096a314319aee90b981a0a350676f186a25ca059fc35ed6ead30b3b6dfe20677", + 'kmac128_no_customization_test.json': "f746e985e40d65cb05f16b27dcb89749cc8aa8789a1eb298acd27bab186c5c4e2214806b1b31cb4eedb7bd9fbec5c58cf506988e1838d36d3489d4b46890f35d", + 'kmac256_no_customization_test.json': "93c31894cbe055881484ee79da9b64f79314d91edcf139c58395c7550ea92ff0fb8928b583f9967da850e01abcc49f651f78d10732cc67f0791cd9cd4fab4d3b", + 'LICENSE': "8cf5c2279c45d0b1215be0b06a332782695ffaa810f93ee90a60c9aba8694dcb5ae798ea8e58743b82e60f134db0e2d91fd9c5ccb29417150368ab61c6f0af60", + 'mldsa_44_sign_noseed_test.json': "5e06e259dd15cde1ce7fd724ed22e15701e772f7a7e14aece0917b03862cec5a9302111adcf2f7e9d3e6e87ff50dcd577c1d3acbb8924dc0287a33861cd3c7bf", + 'mldsa_44_sign_seed_test.json': "fbbd614f6550b55da045eb28f6e91db41e9f184d8c79de5b8eb83e61641a916c8fe530a96ca3bdb48eabd4748c682d95f4652e4e3b02a538f7b0eefd01cffa1f", + 'mldsa_44_verify_test.json': "0d883abc079a4a984407f339ff2eb0e8d98ab640e00fb92c941d1179ed9e36a5835572dd2a6fa8a998f60a253b7253b5ae27b7f12bc461cdd4a2e1c3dc08fa69", + 'mldsa_65_sign_noseed_test.json': "c189879c24a3e30df55c987ae902499a582d00514e1e512b421ef1a1f1615c651bbd7e58c12c6fb2f59c3c918170c1d6f04511fbd13b78fad1df422f14f6ca0a", + 'mldsa_65_sign_seed_test.json': "459251fd096b4c93f2ae7dfcc99464da1704ed969a9c929a6b48a1e8ee709bee77b2d275b3333278a52d881011ed4d7af129f92dc94f4d2a37a34a369c0fd717", + 'mldsa_65_verify_test.json': "6e34eec8e7604e77d18d23e418089ddc2b650d44584e62a57ec9353ce0a305933ef34a1a60f196e5d1ce190241800e74a10a94ce93818170bc2144cce8ff929c", + 'mldsa_87_sign_noseed_test.json': "82ea848426d521804cddffd8cb9a9ec1834a039e2363111fb5996ce3a82709670119dc5ef55f18e4e0b65896d054176c69fa555133d629f6bb2a75cfedf4be27", + 'mldsa_87_sign_seed_test.json': "aeef0e74488b1b0625853fa87b9f1021180352d674203bdfa505f1ad40322ec8a30a8545405c3a5a8976c77375220fd434e3fb7f20b895271bb4695029dfe850", + 'mldsa_87_verify_test.json': "e0fdbdb42b5936a92fe9c0a61ecfda7d10e78f991b66b6a9c3a1409cccbe544023444a8db338086ed8015bf0078f7f7769bc244a404ba2473c54be9b5f5018be", + 'mlkem_1024_encaps_test.json': "40e081ea7406909aeb38b4ecf7469c546036d15a1f7d3709420fefafbea2895ba1eddf6e568b220507bb1888047e8c8f1729d34252ffbeed056f6f17d996c05e", + 'mlkem_1024_keygen_seed_test.json': "fb401e343275356717a7a0ee6d6f2d9c68ebb5ed16726c25daf42aab88cab4daad51ae025b9fb5483e7582d70cc7e3c0167968d351f8a8a386e2b54eeed18f9d", + 'mlkem_1024_semi_expanded_decaps_test.json': "75b300e5a60151b46469c6aaaf24910db60bd463cec418fb699fcdb45ecb01bbf8febfc66c7e725073564934435d3a4e6f79ce0f1cb7e6bb96e5b94c8b7e28ad", + 'mlkem_1024_test.json': "610ccae8443178f81dbf3e73d53710daf9935a6179cf19208c5083a9def2bf37e99988822bba2956e9fd8bcaf5947b3ab0636272c1798c9ca2fc734d74a568a8", + 'mlkem_512_encaps_test.json': "c1a658f023b982063868f0bf8c3d7b63f7835d8312c07d92f35eadc8010fc48bed541d95903275cfc9d77199e375c7aed2ef6f79e256e5da0361bc289d9dff68", + 'mlkem_512_keygen_seed_test.json': "7b69a209c5489bd99b5b4c18af14a1a1c23d4e6d92c7ad9ca159043a80a28095114bd6411c20676fc377a516562c17e11559d4859dc8f2a6e3a0d15347199226", + 'mlkem_512_semi_expanded_decaps_test.json': "aa7005a88e19fa6e32235324774fd1b4511fa6c5d57c661258d9aaa259b74138b02b5ab6bf5caaa73282279ace6952896c0e501b274172742ad65a488d842498", + 'mlkem_512_test.json': "69b6ac80f6e9a342177ccfcd89cf9e63859319e8e00239789f694bd1d66232bb983acd738d4b09220f595e703ceb515901fa683d3740ad6a3fdfff05478a31b5", + 'mlkem_768_encaps_test.json': "fa4bf9229ea60af13175c37f729d59cdcb6429e489b75d4f63e892f57f4e6e03533f2e2e0d7e019f4822ed16b0aed453490558a836a64e1a6c1a821853f33677", + 'mlkem_768_keygen_seed_test.json': "238d5a7e0d7177df2976e8ea0ceb5261caaf02966cd6b0cb828567678b13b6daf2f73fa48eab6b8597b1e4b237f40d82e0c2411d834d156f852a128852d6dd27", + 'mlkem_768_semi_expanded_decaps_test.json': "34472ce67ee1bf722e887baf6aa64510dd89b71cd58b98abf19dbb63993a8a40800fcbdffae1eef6993390a8a96ad082fe82bd241520bfb9ea62393a40d95bf9", + 'mlkem_768_test.json': "33c51ac42f702b0d8258184fbd7b8716e2cce53efcf19a408596f1b406c2fdbd4b80e638e869289794253264ad29c253b0bb57f10471dcee911e6b5a36949cca", + 'morus1280_test.json': "1bd1c271807b26e06cf33b7f50de1c7406efa38dd91966838400e296076451f1dd3ada4308098aa185b3962a91be3286d62344472305472def5fe0aefd5b5695", + 'morus640_test.json': "2619a079189ca8c4ad79071a80f9cb0dc5af4330b25490b03432af12997be48b046cd6949a1dc4f76ca1d93159d2b0229de89ce1bf19055a47e38a06789cd05d", + 'pbes2_hmacsha1_aes_128_test.json': "4dcd8511a36a39cf8ebf36dfc921c1bbb79b0d5dff179dddd2a37ed79b58bb8f45aa1bcb3fd7a02024580458df1813c7d1c87a63df46c9285ba99c3318d479fc", + 'pbes2_hmacsha1_aes_192_test.json': "65e072bc0faea0d0ef649c1eaf82984a241a139d91414b636679c661f4539c16aa4e9ba3852ea22e42da366450507fc3c1ee61b0c78263a59897de1b003617dd", + 'pbes2_hmacsha1_aes_256_test.json': "8a56690029fa28e8df80bb5a95389a72d1c5d23fb76ccadeb767f3e40cf2b06fa7506e7a01abe63912c13bc94123aba540aa0e0c92a43b8e6dc48ca972b5ab72", + 'pbes2_hmacsha224_aes_128_test.json': "98a5c1f874d4e85c964d23be4c46ead32f157c6231002ae0b9aa03b1a4d7833fee2719715ecae31ecd4265b44237beb409fcda197422cb6d25ef3bfce88d55a3", + 'pbes2_hmacsha224_aes_192_test.json': "f3e099e0e0f8fc8b3bfe3a6c67b28c54567f50d2d35fc845e7cc34d6c7366eaa78a48074290714a01213faf57407eb24a3b2d614823d49458dd63d4900aa0e45", + 'pbes2_hmacsha224_aes_256_test.json': "fb149363b319dfff8bd9b44453f62620af662e7e59d12e37d01c65c1504f0ab076414c475634525d6549f362da208e6dc1c0f445a92d1020af4d020b29d8f04d", + 'pbes2_hmacsha256_aes_128_test.json': "9791d10cac4cfe6aa13e955d9a1f606231455d27b13a48184eedd1cec587b4c20fec516a969b8fe82de1ed6e653d325b1d230c926e0365230e8321a535fff164", + 'pbes2_hmacsha256_aes_192_test.json': "ee31846af4512fc081c2a520a6900abfe70488341ed3b94c591dd65ebbf75c806b2d362b6d3aea04985a7b55515da07e52208aff5684be4108a0a40a5444223b", + 'pbes2_hmacsha256_aes_256_test.json': "3319746609c74a8678e2c02393da33b7b8e4f5cc9f122a79aced3d3f829d12368fd667d273b90ea3be3abf27eaf12b3ff7034f5a2c124b647d2ade0709212d65", + 'pbes2_hmacsha384_aes_128_test.json': "4734268d3045cd6c1c3d001152bceb91045ca367e998e94c2b8123bae1c0bc6e40a646b05566ebb8e27ff21c07f96a2d34b71b29cf7ba47a41af1327a12a0817", + 'pbes2_hmacsha384_aes_192_test.json': "5c415d4a16b3b0646ef2e288ce230fde3b41016b3d2ffdd42f1dab576c519087ba89cbe087abd1dc6841ed3e86e87f8e0896ccc55fb37aa4d8b91dde47e97612", + 'pbes2_hmacsha384_aes_256_test.json': "7499b1e8faa06f155dedd282d49baaf1c3103d92a90d9fd9ea9d43342ee7f037cd61ec6db11c758eefc8a2ab37aaac0c0cad946979dd90d89b0cab05c3e2e4f5", + 'pbes2_hmacsha512_aes_128_test.json': "ae7a8419b4080d1edcf051791dd162b21fbbde87671c692042d090fa7b0a3a50e740ad1ff600efe16b669e29a0a8cc76c70168ac595fddfa15358f44ffed2b43", + 'pbes2_hmacsha512_aes_192_test.json': "018312ddd664d54d1f61887c5b2eca6c53445ad687c541a112f4e01214f4bdfca3c1c040a4f58073e25bab81f9cc16594b325126ed094f25947d6736cf2dae68", + 'pbes2_hmacsha512_aes_256_test.json': "88a6744e681e932bc88cba92707dd4175d7628b28722650e583bb88996a4359cd3bfd9bf6e7d7251bacb6f6ec3f373c89a8726a7941b0fddf80950ae3853be29", + 'pbkdf2_hmacsha1_test.json': "ef7f30803bb875100f03243a4ecdaa828c931727d987b02ccdf5e11c016a9d39b701a104f139249070c0c9608bfa21094f12c1288a154146a4d5d445d6a414d4", + 'pbkdf2_hmacsha224_test.json': "c76b458adb68d4298d4488c9298e22660b88d339663bd916d4a4dca16a6c45b3deece24670f93822893fd82f1ed4fcd83320a2bd17dbd01eab4b6bd424f421c1", + 'pbkdf2_hmacsha256_test.json': "68266130cf691a7de55812ffe8467c5af0d925dd7e51a1bf7bf37920dfabb63ebbf4d63e7726c6e7c0d62267391d73225af3788d63c2aa4108d34d53ebb774b2", + 'pbkdf2_hmacsha384_test.json': "7258ded76df3f3afa2ae644fabb61ca31e2adff87a3dfb7735ffa269fdc4c84154c561292a1bcf0a604e8757390243cab30b021b65bef0a61ee368dfc0c340f3", + 'pbkdf2_hmacsha512_test.json': "acf31741f9fd073b2de96fcc054d2740b05a72d5bf28e96238bf7eaf74e036ebf1920bfa97060b572ea625ed243d62e6586f31a6e6fe79a18d7e82cc677283fd", + 'primality_test.json': "f67b59682c44c867b39ad8de4db11ae3cec54903d3ae5664665d0176c09d6247a9a759e3ddaf74557a0d463aef33e096c3c3bafb0d86ec9e84a42372d47be228", + 'rsa_oaep_2048_sha1_mgf1sha1_test.json': "11b5bdfe2e8b182188f5afc85ba9f2a90805f47f9160e9a7a09e7cbacbd09dcd50034b64cf4586f3c1dc8a5740f6961a654849f33e83843a243a8db90320efed", + 'rsa_oaep_2048_sha224_mgf1sha1_test.json': "25d839c8e212bc5c4edb42ffe782e7047d96720a5de72939e2a1ade18c6a1b7fc65aea03568c6343dd193e97c3220232c6a2ad482bd553a87a9c10f5391690a2", + 'rsa_oaep_2048_sha224_mgf1sha224_test.json': "ee36d3b23f5b30e6e2b53de9f96eb21642011dbe43082ea68f6f367e640ad278f6fb315d0159f6cfa9dfb7d65ffff3934ef97c80f83f6732dc8542afee373cc6", + 'rsa_oaep_2048_sha256_mgf1sha1_test.json': "afc711f13ff6e5b34630031fbc302eece309f132e3d31310cd43ef05f36605bc3a006a12412bca8ddff984fa358656a4a2666f2e1fcd0d6669a7be5b4c225adf", + 'rsa_oaep_2048_sha256_mgf1sha256_test.json': "3830a5ed60d6234996dd8fa336e7973c371ad5d6a3916d6e641e8bb2d1fce620db0aa68ad2a46747970a49d4215c09d649bb70fb0b67bc497c5e2c332c2bdc38", + 'rsa_oaep_2048_sha384_mgf1sha1_test.json': "8cffeb10a6b0ad360d0cb9fc598d6dbfe3e36ce905b2e5e11548b487b12cfbd962799bc58f31b106b1d4609ab7e36d1c4dda081a9f7b4c121b9c718b1ccffc96", + 'rsa_oaep_2048_sha384_mgf1sha384_test.json': "3b4295e01d8ecc5f3977639d6e83926bbeb718a5539223840eba3509f65ca03812ae704edc82b7b6b78322ce013ddc9e7f4c877b9609afdc4f50bd39ee59f5d2", + 'rsa_oaep_2048_sha512_224_mgf1sha1_test.json': "a2692a73b9f7106a6187fbee744bc95700afae8726c214b9e010f587df17cc7e15ee3a650335646c066311e948862d68b427d791f134f74acaab3af8684609c2", + 'rsa_oaep_2048_sha512_224_mgf1sha512_224_test.json': "fddfe64945f4658eaf2e2ab37dbc57684eb41374ab76634c74a9944612e0e12f18a31d82b45d47a106a5a48ff0cf5656248b09fdb05c45b8c9f8510b30e59d55", + 'rsa_oaep_2048_sha512_mgf1sha1_test.json': "06b6d80b295d82c298e7017a748ef40de6a2d7158d6720fbcf939d8402e1219e657dc78486b6a51f74ed5c1a24a8d9bae33a9a752afb86b68ac2a657734eae4f", + 'rsa_oaep_2048_sha512_mgf1sha512_test.json': "5f66c09045781395b6b0d0f34f6ed5a6a794536c6883f2e198c24ea4d2cb6fef12d96e5551ef36e9a6c09b3a5b97809a1d9d996072c65e9dbdf28690ee1f10ba", + 'rsa_oaep_3072_sha256_mgf1sha1_test.json': "6202abfba2b997f3d3f7601317bba95938230078a2edd4012ebf353169975ed788f273c841c18ed88399c167a2d089b383c0f16de6777cfa68c2d131e967a7ca", + 'rsa_oaep_3072_sha256_mgf1sha256_test.json': "893470dd1ae0fc4d943eae9f2f7bb3518ed2e075cae7817962e75e0892540ffc40c6a1eae937f0a4fa8bf26a0a0ff59b08842c30e02813dbaff32a8c7c16eaa4", + 'rsa_oaep_3072_sha512_256_mgf1sha1_test.json': "e8a98b51883b223923daf500ac36d97b727e146c877d37e70ded077e2158c320535ee9fa06faefc4139b87288def292b95738a20cbada659dc32b113f7688a68", + 'rsa_oaep_3072_sha512_256_mgf1sha512_256_test.json': "8553b7ae98101c4f01f916e4523684611ef03f94ffa069ad4361cad6f7e0603a1d7327488b5aa60c7a85f044228f97b7396e318014d274028c62f74e6faf5ae3", + 'rsa_oaep_3072_sha512_mgf1sha1_test.json': "6373311f8465bb8b93086a2fee08e80221b26fec6727e2e758f54645a7ec19642c5d16340d581cdecf0e90bb34d13412e8e3a3c020b6fbcb3fbb3263a5a025e2", + 'rsa_oaep_3072_sha512_mgf1sha512_test.json': "16e04b37123ef54cfac757e5654176f90a9b085ea822116221edbd3ad5afc7d8352dc4c18f4d60abdca6ba0d050872f5f9bcddbb45862839c998876e746cc800", + 'rsa_oaep_4096_sha256_mgf1sha1_test.json': "48ea4b20873c1bea93bb9e322ef038d805000b1d54a24f387f825c42544c204bd2a4ae2e7bf6c368443505611e9fb5ab0d524461dc94e4432c0016a450f88762", + 'rsa_oaep_4096_sha256_mgf1sha256_test.json': "b490d0aea765ae739715a91f4adccd6ab75822eeea2aa77ea25961a5b11208b77b20a445d6cd5833fb4a384bf490a3f37472492219e7d638f2101757529e555c", + 'rsa_oaep_4096_sha512_mgf1sha1_test.json': "b9849c95be878f3b5b1831f42c45a56d8a46b92e2b187dee3f2be87c376a5c3d4e9fd3c6f0242ebbc2944c62740f56aca21b508a19c8d1915cffb91deb82292c", + 'rsa_oaep_4096_sha512_mgf1sha512_test.json': "3d6dfcf28380a6395fa7908344e5e2bc6bdfadbebc64fe1d11fa2d519bfbd78f603f27a36e5310d4e76ebe7378d90f5965870ea2a542d966e58717f149410f4e", + 'rsa_oaep_misc_test.json': "c6b1b8563ee47e4079c8f1273242021fc61a2190b7f8d9d4facecff8905164235b28e64490bba35cdc2a80eaafc7a92f1d1c367f2e26bfee7b7318e03ee25f7a", + 'rsa_pkcs1_1024_sig_gen_test.json': "41f2989c6508e330f57c94fa336873734c90ce608e9bb884bdc58232db230dbd1ef10740ccbde8ce5d60251a307d9b47a9bc3d255f7775565fb3d38f72867186", + 'rsa_pkcs1_1536_sig_gen_test.json': "94aacc899097a50d0cdf361b36e7c8d94bdd115bcf9e8eb03fee0fdaf4380576ff9922f3d382208661234f3d515d763e7dfabce2aa50010dbda311cd37061a00", + 'rsa_pkcs1_2048_sig_gen_test.json': "94b8e6c8c215d66f467fc2b475982be0743fd7f9018277eaeddf231a34a1ef9fdf55b13d512ab15a6a0da1905e6c4b08fd2866b9953a2cd1f9712d5a7c06aa01", + 'rsa_pkcs1_2048_test.json': "e4afbe133355c2a726d4f2c5fefd4dfbd3318c6b337be32af129eaf0af4bab233c83f9314332cab919327a6d76a1819f15e6a0a33484fa11cfa4b9315a2ce50f", + 'rsa_pkcs1_3072_sig_gen_test.json': "662d1d04eb6ed436ea1eef20cf9ba05ed45aed7e45266e847f2fcd999bddfd465458ec352fe2355d806ce7b347324b3d8a13b74dabd37aa88989368926a4cbfe", + 'rsa_pkcs1_3072_test.json': "7164db87ed34cbc0dddfbddb3e1449b569ed48a9c53dd76f2c64cf38101c8c5d54bf1244c37ac0d94b7d11c1cc31fc7c76cc1d85801355bcc9a7eee17e95e0db", + 'rsa_pkcs1_4096_sig_gen_test.json': "709437bdd819439ea8c354bf15d894ef10b07db1da159e14b1d35d4a1c4c47e5d7b67e39d11be8b2b012517eacb609596939f652a78670ebaae12242f4958f3a", + 'rsa_pkcs1_4096_test.json': "e36e0d26558ea8f7b5f640d4b18cb6d2cd9758b5dacda1fe28f91032f6015ee8e03cf49d59e9c6d41eac691c37e330db862412e7fd7221f4c580f5aa7e452fa7", + 'rsa_pss_2048_sha1_mgf1_20_params_test.json': "cdbcefd215211d7dde12fc7c27de31cb2b771fb34f6a171ae902336525241e4685eba6150a773e669e845a7e8269b65ecd7e8e46e7350715abe838330cea2088", + 'rsa_pss_2048_sha1_mgf1_20_test.json': "e6469899ca6bc76ef2073a43b94ed3884aa76a3d9cba3cd49c32bf5ec0ca5e1a08c457fd4cd61a4d67dc837402024be37fa32338fb91261b9ebb0e81f6d73af9", + 'rsa_pss_2048_sha256_mgf1sha1_20_test.json': "fea4d48e541a65a1afd222f333961f78aa7bdc360cc702fce35d09a92f637103483e1bbae5d0c52de25fa19c979984803f82e22c29aa6ec5530611ed325a4196", + 'rsa_pss_2048_sha256_mgf1_0_params_test.json': "f5a8830bbaf9bb72f1e4efc695e8a34efcfe498f4602c0ea254f346c1ce8c278c33c3fdff2cc4a3c041100ef89aa675f57573df2a5c3a538dd367e6bbed6a3a1", + 'rsa_pss_2048_sha256_mgf1_0_test.json': "c847a70a03ba42f1e114fcc3f721d7aedd9dda5d4b792e617a329432da7a6c38f2e5910ee9477dafda0780a8a829de5d7a549e08ca4abdacfe3b801dd05f98d0", + 'rsa_pss_2048_sha256_mgf1_32_params_test.json': "833fbb7b9259401df2308eade2cb3d1351caee834c1cf68c8d51f152a049cbc31638e2c00d5c74ef85109f048b83ecba0d45d5ecbeeb342f496dd2aad0df2da6", + 'rsa_pss_2048_sha256_mgf1_32_test.json': "7baf1f5ddaffcd00f61cffb0c51ab65d4d2e1264609f1fcadf6d1f291b352c05b308ceb1e4cf9a7b8579858f816b47fe74220c9f8efddfdebfd8d2e2bfce8ca8", + 'rsa_pss_2048_sha384_mgf1_48_test.json': "b883cf86afc1a4b3ca926bea1279b5176926290c14e5e035c2d8f7cb5d3515b2077edec725ed2706c0f354f1fbe58ed3c850dab1969b6a52ceb8c56e3d0f5e5c", + 'rsa_pss_2048_sha512_224_mgf1_28_test.json': "d7aee7bcfabf5f9e2840ce29f56e7bb9674020a965c2825068caa7ed4ef2c0bf6b3f363530148f52081df339a954b62dd037a889980bd5b6db79f812fff921b5", + 'rsa_pss_2048_sha512_256_mgf1_32_test.json': "87b67c07d2246381774d8655ba55800cf1df881111e322312fb91f4c0138d70945bb664790ca9c8c29f267974d2d9278c7172aa22115760c9580e3bf13cd332b", + 'rsa_pss_2048_sha512_mgf1sha256_32_params_test.json': "84cc291697b82aad164b1cb39dd1a827355f962df606097f528d1c1fc55c9c965d56976c1eecfc83b04ffa7377fcb8ff5c59bef5d213b95a9f1791fa40a35eae", + 'rsa_pss_2048_shake128_test.json': "87e89755102a90496314e7daf254071486c222d3880b6dbf9f0600cc5325b96f0a405de46bcf4424605799fccb24414a929f0200fb9e98103cb273c10a406cc3", + 'rsa_pss_2048_shake256_test.json': "ac0ed3c4beb5ce6c3ece709bfc28a5ac8d189b622f59ee3920d6eb30f862b03128003b15fb814c05400570deafa8e91dcc6781dee424b9cc0615fa2a5b020082", + 'rsa_pss_3072_sha256_mgf1_32_params_test.json': "a15a20bc37a2090bfd47382510e8fda94e32819bab8b1f1c2a797786968845f1c840038e8852fdbaae5bb003e519acfbc5059913925fd4a6f4a2a386dfaea536", + 'rsa_pss_3072_sha256_mgf1_32_test.json': "308cf529b12f39e97b2ec10dacecdc06eace7a94dbec1f1aefac717a7da6d43375c9273b400ff3fdc392bd136920943012c3917069d0c4e99215202a4be70f9f", + 'rsa_pss_3072_shake128_test.json': "6417d966ddfb9e0862bcc9b02ab967421ff7aad2d2b13011cca1070c3281b5109a0c6ce1dd6ac0aa6e5ece4be5d2ce91bd40508403dd10a0dfe9268df937705e", + 'rsa_pss_3072_shake256_test.json': "ead39cf4877b98a79583ade599c7e0e118d3dd69ec6c82ef1590122f3621f6cf0f6d569df3d58c6bbe086102889feb685f964554aed2defd3f05639184231cc6", + 'rsa_pss_4096_sha256_mgf1_32_test.json': "1812b9988cb867f67bd975f940560751bd7317279bc6a08769b6060c453ce464ce420c6c5fdbb02df90e036ed3474b8f052eaf351c67cab0a21f911f156c69d2", + 'rsa_pss_4096_sha384_mgf1_48_test.json': "edcf2757d25e8824a33bf64fcc8622071ef510cd4ef21878002cb3b79c88d69a03e77dfa73d083cbdc62e8eb7accc12fcea447c9c2a805bac2492e7df7dea615", + 'rsa_pss_4096_sha512_mgf1_32_params_test.json': "fb5c743dafffae4fa96564d50be5decb8712d8247e4066f0e2eee040bc0fd0d458a803e72327151dc7eae93223455f162c6ef46d7c5650a1abc9e483c5f262ac", + 'rsa_pss_4096_sha512_mgf1_32_test.json': "b1e6ee3d4a7be1562237e8362450319df027318042111eb11add1bb0cc5e35db274962dc6f61718fcb83165a8ed8fe0adaf3d446b2e2b75486ddb948574e0d08", + 'rsa_pss_4096_sha512_mgf1_64_params_test.json': "61109281f59667eaec913bd98ba9dd5b84418fe697331a6dc9b53720833f98da64c8b561b57c853c797f7d5de8ae212554eb6836087d62d016f9208835844b05", + 'rsa_pss_4096_sha512_mgf1_64_test.json': "fb3632478e0d261741443865f5cbe7954103186ecf8098d5c52f88b2f85c870961a3c90599e256fe46185f8b6ab8b1c36b326aa30fea4090f5e55eb6b9ff3544", + 'rsa_pss_4096_shake256_test.json': "5add00e096f35b72f062f169a4c6cb11ea8f93235d9ff7ea72b4ab4d226fd8a470368dfd5335b4f7abf3a5cb3f81759a8c99ca8209c4891e0d7bc08ffaa4ab5a", + 'rsa_pss_misc_params_test.json': "aa871f1dcd047e116f67edf398a839ee9e93f301ba746592a4f718d1f351e1dfaa731501ae18881217ce48086258a7c0a107a85c900bf3ecff4d64f639f98a17", + 'rsa_pss_misc_test.json': "2ad28380f1455adf0048369df811c7c6d6a3c7002945e3f30ef889243f94b62f8602ad7f461f616dfbe0b75c96269eac86f99ad6288d842ddc3c9cc4fd7b3dd6", + 'rsa_signature_2048_sha224_test.json': "6601b34eaf82d03c3c3b1b4041a7009de8aaf2c4e3bf527519ce237ba94b38b848e3bbf04eaacd3d084d3bef9126f2f4ff9b678126fc3fdfa5429503a028f546", + 'rsa_signature_2048_sha256_test.json': "d5150fe23f6215406edc768682ea71070f49c8f4a718b2f3da113e9a5213577f2c79e1eff1d4506c8ba89fc42ecbb5fd301a47c26030490f4ac06f2feabc936e", + 'rsa_signature_2048_sha384_test.json': "cb045c76ad23f9fdb3abb38bcfa7a78cea1e13a7f512e777cd44b21f644d96ebe780d042435b4ed32f16582745c895fff4ddf9071b7f7c4bbbd0a71631b4f57d", + 'rsa_signature_2048_sha3_224_test.json': "527f64300e61defd85cbe2d4c4f4eab2c2a6baa0ea16ba918ecf399c51ea530bf3b63f4322b3e7a0eee15aaf50d1cc851cc076b30219c2bb0b2d28348006e3fb", + 'rsa_signature_2048_sha3_256_test.json': "1038614b3760b2d57017c266985e17527002eac224945c4584da572611c46d0ca2b58293b663b7709bbb27646802634dab8d4fb123f36fad01f5a74b1324e23d", + 'rsa_signature_2048_sha3_384_test.json': "d386a2a69d558f9a4f5d09795486d628044c5b56fe34c4d5d66063533133541594b4f5f9330541cdeebd1c1ab7a11488d96a852e5fd69ba9fa08c9157d102fd6", + 'rsa_signature_2048_sha3_512_test.json': "f5ea0d29bb0887f9401bafff3cdc35a45c0196070616df75e5ac8a12caaf5e238080eceb4265962aae4e299f991be73eb0e4fddead0bc795e32b023547160761", + 'rsa_signature_2048_sha512_224_test.json': "96e0032b3af2ae3a8d5626a79488a112926b599f1f9fc4e47d5d7941898a5dbb0afe689de16bc79dcf13656e0b32e052b6704bdec673ae2b99383b68285cdbd5", + 'rsa_signature_2048_sha512_256_test.json': "fe54c5821e526f3374d03e7c1313e3783cd986b07a4c9858bcf3aa20d8c85b27d898394b4c37c1483fc16ca1ac5b59681ace58fba625f84feb9af7455d38ab20", + 'rsa_signature_2048_sha512_test.json': "2b9f6c3da08266a40b7529443aa42738bf7fd23842ad3792cdee9a587fd6056bf7eb1ec72867d3006f1a98728a3e528575ffdd7229325e13fafd6f363edda0a7", + 'rsa_signature_3072_sha256_test.json': "17999b3add8f853b07d6ca9e24fd58b275abb725bca8f7203787f57d8af0c03f7bdc15a6eacee1337d9621b2d53a8cac86de7b2e6a444abe81da8139838a8c7e", + 'rsa_signature_3072_sha384_test.json': "9f9a8ee0d78bb6481d94c1f9e41eb77438f33308c163c1634ec122dffe133fdef9c5cf1eb8c7ce4b0161df651f2d04a0250fa25d7fc82deb9eea105fe69121f2", + 'rsa_signature_3072_sha3_256_test.json': "6f4b2e8ba2436fe4c21e3d19e4a8572227bae64e9860a55462fc1b439900e9f443fbea4c5294cf262805d35ff8360ce48ea6c80ec5e4d82ad70c193680c8e28e", + 'rsa_signature_3072_sha3_384_test.json': "05b4a8736086dd21af73e84240ecf2ae217d45aab051f5c65744ac95777e82ca45bd0026881e08b1d817e7e015ccd8372e7d4c83356e896914307242eabab0b0", + 'rsa_signature_3072_sha3_512_test.json': "f188eb1849e68f30fb8d7e925ec6c575702ef0b1b06db618db558f35a01c4e541e8dedcb10e4eeec416cff82a4136a086cb2fc3b9e37434e4a5d8b5d11004d4e", + 'rsa_signature_3072_sha512_256_test.json': "d9e04c0bb74c874f1a51219b1dcba0b23780f64fb552d810683a48d1e47809acb84a4b2ce54e17f77be15b1798bbef64eb44c0722920dd96deff9472f5262093", + 'rsa_signature_3072_sha512_test.json': "23b528243e764425738dcafdd598845c59a3d8bbaeeefe432fb25f8ade7fd611f4f336d3fa91e079b149ea125c1d9d889317606a351827fb73b93a2dc8301e09", + 'rsa_signature_4096_sha256_test.json': "13c86fcb11277e72dbb54cd1e4c4cfadbc5605eeba3672130827a593b6bb703d927138bafee5daa03ae30bae15a352bf22abcdf518cebacd0f5b55c08bdaeccb", + 'rsa_signature_4096_sha384_test.json': "8881628f3b4015a729d88167fa98b3be5eb9cbda23e6766d5ba45a4a00dfa684d60cd269662e6df54771b7393cf01ce0fecdd572395606ad2e9d129e0b992a0f", + 'rsa_signature_4096_sha512_256_test.json': "6cd08b03cba8779ac57782d4030dff7fe277393aa1e308a647c5be1a64066eb0faf43a3e5f526bc76706e8e0d808c5b37ee4a4e0046e61aa68b41f1b80306a43", + 'rsa_signature_4096_sha512_test.json': "021cb140c1f7f7f87c22cf891c40ae5544f1c92926e9c8ea7af838ea496bb4dba646c120fe6fe75d81808cdbb515799bcfc8df1b1c3cbb4f9561821891a6d92b", + 'rsa_signature_8192_sha256_test.json': "8dbea635f9123af876287f583849b29186030cd270b709dd08b272f03acf4cec0c3cc3e77d45542ad606d101e59cb7feafe8af094f2bc2b38bc3cf08d8169266", + 'rsa_signature_8192_sha384_test.json': "c518417449709d88f3ad7aa1307b60a5d17fb575754674523a848b5030fa89a0501b396fb5fdc77902eec3f000272cb28458efe3473a80a407dcea0de6a06a8f", + 'rsa_signature_8192_sha512_test.json': "1cd1800f716214697507df8c099c3c01f512491ef8c008003da8f83326e3d08476365c96c03f91e0f22395f99fc01aa750aeee254fa22f81dc903418f41784bb", + 'rsa_three_primes_oaep_2048_sha1_mgf1sha1_test.json': "c629e7997fcec21d05891d944ab5fffcd673e5f2eb26b3931885f900081d9cfd63dfc09e009e95972118e1f1096803ca108c425b996ae0f83b90e9ecf3277247", + 'rsa_three_primes_oaep_3072_sha224_mgf1sha224_test.json': "d74d361bae2e5516ae5595afd929dbab2dcb03802c89899a6d097b86b1a815cb2237a55cf5e54df6179f08ebff573a03f59815fe2869308b752f52812ce7f6b0", + 'rsa_three_primes_oaep_4096_sha256_mgf1sha256_test.json': "214c700242fc7bad97b8086b13b4c607c7a51e4fa6eb0ba0263741c97ecd7969cbdb85bf0359254080da13e112af458b8fd0a100178b10ef5881162ec3658345", + 'seed_ccm_test.json': "b9d61c16f439b9547ce15344b806d98f36da7030f31d4eab1c558029d4e3410470b97e8d471a27dc75eb74ecec99cdcfb7911b605e5f700b665e50d6a7ad42be", + 'seed_gcm_test.json': "422745f91d72d71d3d1238269ba1dc6234f2a5445d637988acd86d9a383bdfde5391bf5c3c3d4fa0f9fc415d371a9724b2f76f0535229eadc29bda0c01d2c812", + 'seed_wrap_test.json': "a87be3d6c8127970b617d67f35b95be529808273a078bf82f2d8b2bbde2a6608e21559c2a2ee276552745da6cb1f0a253eca67991af2b05b57ed7487ff2fed4f", + 'siphashx_2_4_test.json': "72d16dcd5b56f08079146c79918f3b80a442a17cdc62b2097c8c2956f799e90ba9cca9d80cc8b0220b7f1fb83b4a1e27b6658cc5cd24e2f5c42a57fc47e4cd64", + 'siphashx_4_8_test.json': "d183ba80de092cd66ff8443286b9d22d838d79214827d02aa5323081d578d9dab21485cdeb6c0dda59d151bb6d0596d50d8254836fd25d9278f1a795f5d807d4", + 'siphash_1_3_test.json': "ac056415a0d4e45d802179b7efeebd034a7fc2110fee14b293e16af1edf95448a12160a6e6c2d95b36fe937102ba33264b29c2b1eb452df2ac766fe29b368436", + 'siphash_2_4_test.json': "d7cff2d63f881285567f9aeaca23fc2c94ea465fb442687b0ea94e9647eddcfc05d1b36c2435482b1d492c32b21fc50636a258e2e9c62d9ae6ddbabc93564ca9", + 'siphash_4_8_test.json': "6e49e401186510df582b68df50f8b331ad67609e18fbffe4adb359eb8d9e8f727a6abf3f4d5de1f33f4efb82b86a07f004f49c52d2c5e775e9319fd2c7d969e7", + 'sm4_ccm_test.json': "e963c49fab1e0d8ee050658e797d8c5b2d80cce39fa338833d46a2d7bc5e54036a41610063c0c74644e56589d1697396e1bfa4925e7a5592fa2247cb983441f0", + 'sm4_gcm_test.json': "9f64992c6c5469827d281a55c1612b0029fe344322c8cd7a7f2cefecc597dfb0f3f7b6cf85153f79e12c3539d553d591a8e9a1d0d714a58fb967e6fdfdfebc30", + 'vmac_128_test.json': "9fc97358a5ad56d4badc2b2ba35c07cd4872cf3687da667fddc3f628765330e6a9fc179e55c9a28b87cc02c92b80461d4db99073637fb17b1cf2a74bd5347a68", + 'vmac_64_test.json': "835e384b5d53bef8680520fc2ddb94ecc5d30e8aa65cdf0c6a48615e93273850d6333e19670d0ad40eeee645ebfd5c139f377518987e37ea6f6e6b28a22d0bde", + 'x25519_asn_test.json': "d43e2003c96c50c616cb093b8bcc4f70ca8931d2be83b1ca860900acaf65cd25ab347100c1a6fcb2561f1f29eedb52ff3e1bde70b29a757d4f814daf3cad35db", + 'x25519_jwk_test.json': "2f7f54dccb9c0882ec4a5e9da7c7779d18b7551729e805d2db51bd84a16abd07dcc3b0d7c922dc322b2da05708f0e00c612cea1b2d0c6f567aca09d846629b7e", + 'x25519_pem_test.json': "73530bc171e3a9ab5d82236a8c9c2fa4e565d8e1c83169036920ed22aa29f1122dbda9cae1c33dc5366b2b21aeec377930d6c305e6f00404bf25c4e679572841", + 'x25519_test.json': "857144ffa55ca421df7231594b23a5ed5b83f0f04ac1a707177c6d80d3cf1f69f42436abd3d7b2551788064cdbf01a2e2e25e0272d1ca8bc4a943b981dccefd5", + 'x448_asn_test.json': "b4fe61c5b1a57a887e539afe815ed970afba6eca055b674cb615945df39da911aeb41092570fcf480b5ad347520cc678aa0baf93ae574b272ce2457b802d4dcd", + 'x448_jwk_test.json': "402813856f68470b39df34e160211b53f90cfeba63c6b32c8b49d4d4bfa60b68c94cd1a04fdc09f07676a8f2942bc227ef75165456f6055cc0df3cc1e4381cd4", + 'x448_pem_test.json': "718ef327a5e8cc3a34467974193a051efe89323352f32f248c874457f28f6a2836cb6c2c15f40044df96428051591766fc0b44771236145a17835e714360ca51", + 'x448_test.json': "ca811349ede46fc253d656c26b058e2fe903aae8a225d7f6703bef3dec122df4c48af190a070df4c4066690f50ed4996d69089794b5484b57f2c4233216f98f5", + 'xchacha20_poly1305_test.json': "5debf381018af54fa2f9041044a257f8faff85b9a2eda314f21a05a55de2aacd2767a4962ecc58f69ed65404dc7d2b1eb8526038e7641610ce3a988456838fce", } def try_download_file(url, out_file): @@ -295,63 +635,71 @@ def try_download_file(url, out_file): print("Could not download", url) return 1 -def try_download_and_unpack_zip(suite): +def try_download_and_unpack_zip(base_path, suite, debug): url = ASSETS_BASE_URL.format(suite, "{}.zip".format(suite)) - out_file = DOWNLOAD_BASE_PATH.format(suite) + "/{}.zip".format(suite) + out_file = base_path + "/{}.zip".format(suite) - print("\tDownloading {} to {}".format(url, out_file)) + print("Downloading {} to {}".format(url, out_file)) - if try_download_file(url, out_file) is not None: - print("Could not download ZIP file") - return 1 + try_download_file(url, out_file) # Try opening the ZIP file and extracting the test images #try: with zipfile.ZipFile(out_file) as z: - print("\tUnpacking and verifying using HMAC(\"{}\", data, {}):\n".format(HMAC_KEY, HMAC_HASH.__name__)) + print("Unpacking and verifying using HMAC(\"{}\", data, {}):\n".format(HMAC_KEY, HMAC_HASH.__name__)) for file in z.filelist: if file.filename not in HMAC_DIGESTS: print("Missing digest for {}".format(file.filename)) return 3 - extract_path = DOWNLOAD_BASE_PATH.format(suite) - z.extract(file, extract_path) + z.extract(file, base_path) - file_path = "{}/{}".format(extract_path, file.filename) + file_path = "{}/{}".format(base_path, file.filename) with open(file_path, "rb") as f: file_data = f.read() digest = hashlib.sha3_512(file_data).hexdigest() hmac_digest = hmac.new(HMAC_KEY.encode(), file_data, HMAC_HASH).hexdigest() - print("{} *{}".format(hmac_digest, file.filename)) if not hmac.compare_digest(hmac_digest, HMAC_DIGESTS[file.filename]): - print("FAIL! Expected: {}".format(HMAC_DIGESTS[file.filename])) + print("❌ Expected {}, got {} for {}".format(HMAC_DIGESTS[file.filename], hmac_digest, file.filename)) return 4 + else: + if debug: + print("✅ {} *{}".format(hmac_digest, file.filename)) + + if debug: + print("\n") #except: # print("Could not extract ZIP file") # return 2 def main(): - for suite in TEST_SUITES: - print("Downloading {} assets".format(suite)) + if len(sys.argv) < 2: + print("Usage: {} [debug]".format(sys.argv[0])) + return 1 + debug = False + if len(sys.argv) >= 3 and sys.argv[2] == "debug": + debug = True + + for suite in TEST_SUITES: + base_path = sys.argv[1] + "/{}".format(suite) # Make assets path try: - path = DOWNLOAD_BASE_PATH.format(suite) - os.makedirs(path) + os.makedirs(base_path) except FileExistsError: pass # Try downloading and unpacking the assets - r = try_download_and_unpack_zip(suite) + r = try_download_and_unpack_zip(base_path, suite, debug) if r is not None: return r # We could fall back on downloading the PNG files individually, but it's slow - print("\nDone downloading {} assets.".format(suite)) + print("Done downloading {} assets.\n".format(suite)) return 0 diff --git a/tests/core/encoding/base32/base32.odin b/tests/core/encoding/base32/base32.odin index f757e99e5..2abb244ca 100644 --- a/tests/core/encoding/base32/base32.odin +++ b/tests/core/encoding/base32/base32.odin @@ -1,4 +1,3 @@ -#+test package test_encoding_base32 import "core:testing" @@ -83,7 +82,16 @@ test_base32_decode_invalid :: proc(t: ^testing.T) { // Section 3.2 - Padding requirements { - // Padding must only be at end + // Padding in middle without trailing padding + input := "MZ===YTBMZXW6YTB" // '===' in middle, no trailing padding + output, err := base32.decode(input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.Malformed_Input) + } + { + // Padding must only be at end (with trailing padding) input := "MZ=Q====" output, err := base32.decode(input) if output != nil { @@ -228,4 +236,4 @@ test_base32_custom_alphabet :: proc(t: ^testing.T) { } testing.expect_value(t, err, Error.Invalid_Character) } -} \ No newline at end of file +} diff --git a/tests/core/encoding/base64/base64.odin b/tests/core/encoding/base64/base64.odin index ed1bee8af..93b3afb59 100644 --- a/tests/core/encoding/base64/base64.odin +++ b/tests/core/encoding/base64/base64.odin @@ -50,4 +50,19 @@ test_roundtrip :: proc(t: ^testing.T) { for v, i in decoded { testing.expect_value(t, v, values[i]) } -} \ No newline at end of file +} + +@(test) +test_base64url :: proc(t: ^testing.T) { + plain := ">>>" + url := "Pj4-" + + encoded := base64.encode(transmute([]byte)plain, base64.ENC_URL_TABLE) + defer delete(encoded) + testing.expect_value(t, encoded, url) + + decoded := string(base64.decode(url, base64.DEC_URL_TABLE)) + defer delete(decoded) + testing.expect_value(t, decoded, plain) + +} diff --git a/tests/core/encoding/cbor/test_core_cbor.odin b/tests/core/encoding/cbor/test_core_cbor.odin index 7bea69d2e..6e3312779 100644 --- a/tests/core/encoding/cbor/test_core_cbor.odin +++ b/tests/core/encoding/cbor/test_core_cbor.odin @@ -427,6 +427,7 @@ test_unmarshal_map_into_struct_partially :: proc(t: ^testing.T) { } Foo_More :: struct { + foo: bool, bar: struct { hello: string, world: string, @@ -436,6 +437,7 @@ test_unmarshal_map_into_struct_partially :: proc(t: ^testing.T) { baz: int, } more := Foo_More{ + foo = false, bar = { hello = "hello", world = "world", diff --git a/tests/core/encoding/hxa/test_core_hxa.odin b/tests/core/encoding/hxa/test_core_hxa.odin index a8f3e94f6..a4fee030c 100644 --- a/tests/core/encoding/hxa/test_core_hxa.odin +++ b/tests/core/encoding/hxa/test_core_hxa.odin @@ -1,6 +1,3 @@ -// Tests "core:encoding:hxa". -// Must be run with `-collection:tests=` flag, e.g. -// ./odin run tests/core/encoding/hxa/test_core_hxa.odin -out=tests/core/test_core_hxa -collection:tests=./tests package test_core_hxa import "core:encoding/hxa" @@ -13,13 +10,11 @@ import "core:os" @test test_read :: proc(t: ^testing.T) { - data, _ := os.read_entire_file(TEAPOT_PATH) - // file, err := hxa.read_from_file(TEAPOT_PATH) + data, _ := os.read_entire_file(TEAPOT_PATH, context.allocator) file, err := hxa.read(data) file.backing = data file.allocator = context.allocator hxa.file_destroy(file) - // fmt.printfln("%#v", file) e :: hxa.Read_Error.None testing.expectf(t, err == e, "read_from_file(%v) -> %v != %v", TEAPOT_PATH, err, e) diff --git a/tests/core/encoding/ini/test_core_ini.odin b/tests/core/encoding/ini/test_core_ini.odin index 6e6c8152e..8c554c6b5 100644 --- a/tests/core/encoding/ini/test_core_ini.odin +++ b/tests/core/encoding/ini/test_core_ini.odin @@ -1,8 +1,7 @@ +#+feature dynamic-literals package test_core_ini -import "base:runtime" import "core:encoding/ini" -import "core:mem/virtual" import "core:strings" import "core:testing" @@ -64,7 +63,7 @@ ini_to_string :: proc(t: ^testing.T) { testing.expectf( t, - strings.contains(str, "[LEVEL]LOG = debug"), + strings.contains(str, "[LEVEL]\nLOG = debug"), "Expected `ini.save_map_to_string` to return a string equal to \"[LEVEL]LOG = debug\", got %v", str, ) diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index 409a8c9c0..c03dfe29d 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -114,7 +114,7 @@ xml_test_entities :: proc(t: ^testing.T) { }, expected_doctype = "html", }, - crc32 = 0x48f41216, + crc32 = 0x98791215, }) } @@ -128,7 +128,7 @@ xml_test_entities_unbox :: proc(t: ^testing.T) { }, expected_doctype = "html", }, - crc32 = 0xd0567818, + crc32 = 0x5fd5ab4e, }) } @@ -142,7 +142,7 @@ xml_test_entities_unbox_decode :: proc(t: ^testing.T) { }, expected_doctype = "html", }, - crc32 = 0x68d2571e, + crc32 = 0xda1ac384, }) } @@ -186,7 +186,7 @@ xml_test_unicode :: proc(t: ^testing.T) { expected_doctype = "", }, err = .None, - crc32 = 0x73070b55, + crc32 = 0x738664b1, }) } @@ -298,4 +298,4 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) { print(strings.to_writer(&buf), doc) return strings.clone(strings.to_string(buf)) -} \ No newline at end of file +} diff --git a/tests/core/flags/test_core_flags.odin b/tests/core/flags/test_core_flags.odin index 0cfcf8e75..834f6b630 100644 --- a/tests/core/flags/test_core_flags.odin +++ b/tests/core/flags/test_core_flags.odin @@ -1,16 +1,16 @@ package test_core_flags -import "base:runtime" -import "core:bytes" -import "core:flags" -import "core:fmt" -@require import "core:log" -import "core:math" -@require import "core:net" -import "core:os" -import "core:strings" -import "core:testing" -import "core:time/datetime" +import "base:runtime" +import "core:bytes" +import "core:flags" +import "core:fmt" +@(require) import "core:log" +import "core:math" +@(require) import "core:net" +import "core:os" +import "core:strings" +import "core:testing" +import "core:time/datetime" Custom_Data :: struct { a: int, @@ -1249,7 +1249,7 @@ test_os_handle :: proc(t: ^testing.T) { test_data := "Hellope!" W :: struct { - outf: os.Handle `args:"file=cw"`, + outf: ^os.File `args:"file=cw"`, } w: W @@ -1263,7 +1263,7 @@ test_os_handle :: proc(t: ^testing.T) { os.write_string(w.outf, test_data) R :: struct { - inf: os.Handle `args:"file=r"`, + inf: ^os.File `args:"file=r"`, } r: R @@ -1274,8 +1274,8 @@ test_os_handle :: proc(t: ^testing.T) { return } defer os.close(r.inf) - data, read_ok := os.read_entire_file_from_handle(r.inf, context.temp_allocator) - testing.expect_value(t, read_ok, true) + data, read_err := os.read_entire_file(r.inf, context.temp_allocator) + testing.expect_value(t, read_err, nil) file_contents_equal := 0 == bytes.compare(transmute([]u8)test_data, data) testing.expectf(t, file_contents_equal, "expected file contents to be the same, got %v", data) } diff --git a/tests/core/io/test_core_io.odin b/tests/core/io/test_core_io.odin index 10c9550cb..728771b1b 100644 --- a/tests/core/io/test_core_io.odin +++ b/tests/core/io/test_core_io.odin @@ -5,7 +5,6 @@ import "core:bytes" import "core:io" import "core:log" import "core:os" -import "core:os/os2" import "core:strings" import "core:testing" @@ -552,12 +551,12 @@ test_os_file_stream :: proc(t: ^testing.T) { TEMPORARY_FILENAME :: "test_core_io_os_file_stream" - fd, open_err := os.open(TEMPORARY_FILENAME, os.O_RDWR | os.O_CREATE | os.O_TRUNC, 0o644) + fd, open_err := os.open(TEMPORARY_FILENAME, {.Read, .Write, .Create, .Trunc}) if !testing.expectf(t, open_err == nil, "error on opening %q: %v", TEMPORARY_FILENAME, open_err) { return } - - stream := os.stream_from_handle(fd) + + stream := os.to_stream(fd) bytes_written, write_err := io.write(stream, buf[:]) if !testing.expectf(t, bytes_written == len(buf) && write_err == nil, @@ -571,44 +570,7 @@ test_os_file_stream :: proc(t: ^testing.T) { return } - results, _ := _test_stream(t, stream, buf[:]) - - log.debugf("%#v", results) -} - -@test -test_os2_file_stream :: proc(t: ^testing.T) { - defer if !testing.failed(t) { - testing.expect_value(t, os2.remove(TEMPORARY_FILENAME), nil) - } - - buf: [32]u8 - for i in 0.. != len_buf<%v>, %v", bytes_written, len(buf), write_err) { - return - } - - flush_err := io.flush(stream) - if !testing.expectf(t, flush_err == nil, - "failed to Flush initial buffer: %v", write_err) { - return - } - - // os2 file stream proc close and destroy are the same. + // os file stream proc close and destroy are the same. results, _ := _test_stream(t, stream, buf[:], do_destroy = false) log.debugf("%#v", results) @@ -676,10 +638,10 @@ test_bufio_buffered_reader :: proc(t: ^testing.T) { @test test_bufio_buffered_read_writer :: proc(t: ^testing.T) { - // Using an os2.File as the backing stream for both reader & writer. + // Using an os.File as the backing stream for both reader & writer. defer if !testing.failed(t) { - testing.expect_value(t, os2.remove(TEMPORARY_FILENAME), nil) + testing.expect_value(t, os.remove(TEMPORARY_FILENAME), nil) } buf: [32]u8 @@ -687,15 +649,15 @@ test_bufio_buffered_read_writer :: proc(t: ^testing.T) { buf[i] = 'A' + i } - TEMPORARY_FILENAME :: "test_core_io_bufio_read_writer_os2_file_stream" + TEMPORARY_FILENAME :: "test_core_io_bufio_read_writer_os_file_stream" - fd, open_err := os2.open(TEMPORARY_FILENAME, {.Read, .Write, .Create, .Trunc}) + fd, open_err := os.open(TEMPORARY_FILENAME, {.Read, .Write, .Create, .Trunc}) if !testing.expectf(t, open_err == nil, "error on opening %q: %v", TEMPORARY_FILENAME, open_err) { return } - defer testing.expect_value(t, os2.close(fd), nil) + defer testing.expect_value(t, os.close(fd), nil) - stream := os2.to_stream(fd) + stream := os.to_stream(fd) bytes_written, write_err := io.write(stream, buf[:]) if !testing.expectf(t, bytes_written == len(buf) && write_err == nil, @@ -709,7 +671,7 @@ test_bufio_buffered_read_writer :: proc(t: ^testing.T) { return } - // bufio.Read_Writer isn't capable of seeking, so we have to reset the os2 + // bufio.Read_Writer isn't capable of seeking, so we have to reset the os // stream back to the start here. pos, seek_err := io.seek(stream, 0, .Start) if !testing.expectf(t, pos == 0 && seek_err == nil, diff --git a/tests/core/math/big/test_core_math_big.odin b/tests/core/math/big/test_core_math_big.odin index 1fde85093..ed9d1c206 100644 --- a/tests/core/math/big/test_core_math_big.odin +++ b/tests/core/math/big/test_core_math_big.odin @@ -151,7 +151,7 @@ test_big_math_vectors :: proc(t: ^testing.T) { err := big.pow(res, a, int(power)) testing.expect(t, err == vec.err) - expect_ab(t, "Expected pow(%v, %v) to be '%v', got %v", a, b, expected, res, err) + expect_ab(t, "Expected pow(%v, %v) to be %q, got %q", a, b, expected, res, err) case .Root: n, n_ok := strconv.parse_i64_of_base(vec.b, 16) @@ -160,7 +160,7 @@ test_big_math_vectors :: proc(t: ^testing.T) { err := big.root_n(res, a, int(n)) testing.expect(t, err == vec.err) - expect_ab(t, "Expected root_n(%v, %v) to be '%v', got %v", a, b, expected, res, err) + expect_ab(t, "Expected root_n(%v, %v) to be %q, got %q", a, b, expected, res, err) case .Shl: bits, bits_ok := strconv.parse_i64_of_base(vec.b, 16) @@ -169,7 +169,7 @@ test_big_math_vectors :: proc(t: ^testing.T) { err := big.internal_int_shl(res, a, int(bits)) testing.expect(t, err == vec.err) - expect_ab(t, "Expected internal_int_shl(%v, %v) to be '%v', got %v", a, b, expected, res, err) + expect_ab(t, "Expected internal_int_shl(%v, %v) to be %q, got %q", a, b, expected, res, err) case .Shr: bits, bits_ok := strconv.parse_i64_of_base(vec.b, 16) @@ -178,7 +178,7 @@ test_big_math_vectors :: proc(t: ^testing.T) { err := big.internal_int_shr(res, a, int(bits)) testing.expect(t, err == vec.err) - expect_ab(t, "Expected internal_int_shr(%v, %v) to be '%v', got %v", a, b, expected, res, err) + expect_ab(t, "Expected internal_int_shr(%v, %v) to be %q, got %q", a, b, expected, res, err) case .Shr_Signed: bits, bits_ok := strconv.parse_i64_of_base(vec.b, 16) @@ -188,7 +188,7 @@ test_big_math_vectors :: proc(t: ^testing.T) { err := big.internal_int_shr_signed(res, res, int(bits)) testing.expect(t, err == vec.err) - expect_ab(t, "Expected internal_int_shr_signed(%v, %v) to be '%v', got %v", a, b, expected, res, err) + expect_ab(t, "Expected internal_int_shr_signed(%v, %v) to be %q, got %q", a, b, expected, res, err) case .Factorial: n, n_ok := strconv.parse_i64_of_base(vec.a, 16) @@ -197,26 +197,26 @@ test_big_math_vectors :: proc(t: ^testing.T) { err := big.factorial(res, int(n)) testing.expect(t, err == vec.err) - expect_a(t, "Expected factorial(%v) to be '%v', got %v", a, expected, res, err) + expect_a(t, "Expected factorial(%v) to be %q, got %q", a, expected, res, err) case .Gcd: err := big.internal_int_gcd_lcm(res, nil, a, b) testing.expect(t, err == vec.err) - expect_ab(t, "Expected gcd(%v, %v) to be '%v', got %v", a, b, expected, res, err) + expect_ab(t, "Expected gcd(%v, %v) to be %q, got %q", a, b, expected, res, err) case .Lcm: err := big.internal_int_gcd_lcm(nil, res, a, b) testing.expect(t, err == vec.err) - expect_ab(t, "Expected lcm(%v, %v) to be '%v', got %v", a, b, expected, res, err) + expect_ab(t, "Expected lcm(%v, %v) to be %q, got %q", a, b, expected, res, err) case .Is_Square: square, err := big.internal_int_is_square(a) testing.expect(t, err == vec.err) big.set(res, 1 if square else 0) - expect_a(t, "Expected is_square(%v) to be '%v', got %v", a, expected, res, err) + expect_a(t, "Expected is_square(%v) to be %q, got %q", a, expected, res, err) case: log.assertf(false, "Unhandled op: %v", vec.op) diff --git a/tests/core/mem/test_core_mem.odin b/tests/core/mem/test_core_mem.odin index 9d64e50a3..3afd49a06 100644 --- a/tests/core/mem/test_core_mem.odin +++ b/tests/core/mem/test_core_mem.odin @@ -57,6 +57,33 @@ test_align_bumping_block_limit :: proc(t: ^testing.T) { testing.expect(t, len(data) == 896) } +@(test) +test_large_minimum_block_size :: proc(t: ^testing.T) { + a: virtual.Arena + defer virtual.arena_destroy(&a) + + init_err := virtual.arena_init_growing(&a, 16*mem.Megabyte) + testing.expect_value(t, init_err, nil) + + align : uint = 4 + for _ in 0..<6 { + data, err := virtual.arena_alloc(&a, 18874368, align) + testing.expect_value(t, err, nil) + testing.expect(t, len(data) == 18874368) + testing.expect(t, uintptr(raw_data(data)) & uintptr(align-1) == 0) + align *= 2 + virtual.arena_free_all(&a) + } + + align = 4 + for _ in 0..<32 { + data, err := virtual.arena_alloc(&a, 1048576, align) + testing.expect_value(t, err, nil) + testing.expect(t, len(data) == 1048576) + testing.expect(t, uintptr(raw_data(data)) & uintptr(align-1) == 0) + } +} + @(test) tlsf_test_overlap_and_zero :: proc(t: ^testing.T) { default_allocator := context.allocator diff --git a/tests/core/nbio/fs.odin b/tests/core/nbio/fs.odin new file mode 100644 index 000000000..1b10c03c9 --- /dev/null +++ b/tests/core/nbio/fs.odin @@ -0,0 +1,100 @@ +package tests_nbio + +import "core:nbio" +import "core:testing" +import "core:time" +import "core:os" + +@(test) +close_invalid_handle :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + nbio.close(max(nbio.Handle)) + + ev(t, nbio.run(), nil) + } +} + +@(test) +write_read_close :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + @static content := [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20} + @static result: [20]byte + + FILENAME :: "test_write_read_close" + + nbio.open_poly(FILENAME, t, on_open, mode={.Read, .Write, .Create, .Trunc}) + + on_open :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.open.err, nil) + + nbio.write_poly(op.open.handle, 0, content[:], t, on_write) + } + + on_write :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.write.err, nil) + ev(t, op.write.written, len(content)) + + nbio.read_poly(op.write.handle, 0, result[:], t, on_read, all=true) + } + + on_read :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.read.err, nil) + ev(t, op.read.read, len(result)) + ev(t, result, content) + + nbio.close_poly(op.read.handle, t, on_close) + } + + on_close :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.close.err, nil) + os.remove(FILENAME) + } + + ev(t, nbio.run(), nil) + } +} + +@(test) +read_empty_file :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + FILENAME :: "test_read_empty_file" + + handle, err := nbio.open_sync(FILENAME, mode={.Read, .Write, .Create, .Trunc}) + ev(t, err, nil) + + buf: [128]byte + nbio.read_poly(handle, 0, buf[:], t, proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.read.err, nbio.FS_Error.EOF) + ev(t, op.read.read, 0) + + nbio.close_poly(op.read.handle, t, proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.close.err, nil) + os.remove(FILENAME) + }) + }) + + ev(t, nbio.run(), nil) + } +} + +@(test) +read_entire_file :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + nbio.read_entire_file(#file, t, on_read) + + on_read :: proc(t: rawptr, data: []byte, err: nbio.Read_Entire_File_Error) { + t := (^testing.T)(t) + ev(t, err.value, nil) + ev(t, string(data), #load(#file, string)) + delete(data) + } + } +} diff --git a/tests/core/nbio/nbio.odin b/tests/core/nbio/nbio.odin new file mode 100644 index 000000000..6121d1ac7 --- /dev/null +++ b/tests/core/nbio/nbio.odin @@ -0,0 +1,305 @@ +package tests_nbio + +import "core:log" +import "core:nbio" +import "core:testing" +import "core:thread" +import "core:time" +import "core:os" + +ev :: testing.expect_value +e :: testing.expect + +@(deferred_in=event_loop_guard_exit) +event_loop_guard :: proc(t: ^testing.T) -> bool { + err := nbio.acquire_thread_event_loop() + if err == .Unsupported || !nbio.FULLY_SUPPORTED { + log.warn("nbio unsupported, skipping") + return false + } + + ev(t, err, nil) + return true +} + +event_loop_guard_exit :: proc(t: ^testing.T) { + ev(t, nbio.run(), nil) // Could have some things to clean up from a `defer` in the test. + nbio.release_thread_event_loop() +} + +// Tests that all poly variants are correctly passing through arguments, and that +// all procs eventually get their callback called. +// +// This is important because the poly procs are only checked when they are called, +// So this will also catch any typos in their implementations. +@(test) +all_poly_work :: proc(tt: ^testing.T) { + if event_loop_guard(tt) { + testing.set_fail_timeout(tt, time.Minute) + + @static t: ^testing.T + t = tt + + @static n: int + n = 0 + NUM_TESTS :: 39 + + UDP_SOCKET :: max(nbio.UDP_Socket) + TCP_SOCKET :: max(nbio.TCP_Socket) + + tmp, terr := os.create_temp_file("", "tests_nbio_poly*", {.Non_Blocking}) + ev(t, terr, nil) + defer os.close(tmp) + + HANDLE, aerr := nbio.associate_handle(os.fd(tmp)) + ev(t, aerr, nil) + + _buf: [1]byte + buf := _buf[:] + + one :: proc(op: ^nbio.Operation, one: int) { + n += 1 + ev(t, one, 1) + } + + two :: proc(op: ^nbio.Operation, one: int, two: int) { + n += 1 + ev(t, one, 1) + ev(t, two, 2) + } + + three :: proc(op: ^nbio.Operation, one: int, two: int, three: int) { + n += 1 + ev(t, one, 1) + ev(t, two, 2) + ev(t, three, 3) + } + + nbio.accept_poly(TCP_SOCKET, 1, one) + nbio.accept_poly2(TCP_SOCKET, 1, 2, two) + nbio.accept_poly3(TCP_SOCKET, 1, 2, 3, three) + + nbio.close_poly(max(nbio.Handle), 1, one) + nbio.close_poly2(max(nbio.Handle), 1, 2, two) + nbio.close_poly3(max(nbio.Handle), 1, 2, 3, three) + + nbio.dial_poly({nbio.IP4_Address{127, 0, 0, 1}, 0}, 1, one) + nbio.dial_poly2({nbio.IP4_Address{127, 0, 0, 1}, 0}, 1, 2, two) + nbio.dial_poly3({nbio.IP4_Address{127, 0, 0, 1}, 0}, 1, 2, 3, three) + + nbio.recv_poly(TCP_SOCKET, {buf}, 1, one) + nbio.recv_poly2(TCP_SOCKET, {buf}, 1, 2, two) + nbio.recv_poly3(TCP_SOCKET, {buf}, 1, 2, 3, three) + + nbio.send_poly(TCP_SOCKET, {buf}, 1, one) + nbio.send_poly2(TCP_SOCKET, {buf}, 1, 2, two) + nbio.send_poly3(TCP_SOCKET, {buf}, 1, 2, 3, three) + + nbio.sendfile_poly(TCP_SOCKET, HANDLE, 1, one) + nbio.sendfile_poly2(TCP_SOCKET, HANDLE, 1, 2, two) + nbio.sendfile_poly3(TCP_SOCKET, HANDLE, 1, 2, 3, three) + + nbio.read_poly(HANDLE, 0, buf, 1, one) + nbio.read_poly2(HANDLE, 0, buf, 1, 2, two) + nbio.read_poly3(HANDLE, 0, buf, 1, 2, 3, three) + + nbio.write_poly(HANDLE, 0, buf, 1, one) + nbio.write_poly2(HANDLE, 0, buf, 1, 2, two) + nbio.write_poly3(HANDLE, 0, buf, 1, 2, 3, three) + + nbio.next_tick_poly(1, one) + nbio.next_tick_poly2(1, 2, two) + nbio.next_tick_poly3(1, 2, 3, three) + + nbio.timeout_poly(1, 1, one) + nbio.timeout_poly2(1, 1, 2, two) + nbio.timeout_poly3(1, 1, 2, 3, three) + + nbio.poll_poly(TCP_SOCKET, .Receive, 1, one) + nbio.poll_poly2(TCP_SOCKET, .Receive, 1, 2, two) + nbio.poll_poly3(TCP_SOCKET, .Receive, 1, 2, 3, three) + + nbio.open_poly("", 1, one) + nbio.open_poly2("", 1, 2, two) + nbio.open_poly3("", 1, 2, 3, three) + + nbio.stat_poly(HANDLE, 1, one) + nbio.stat_poly2(HANDLE, 1, 2, two) + nbio.stat_poly3(HANDLE, 1, 2, 3, three) + + ev(t, n, 0) // Test that no callbacks are ran before the loop is ticked. + ev(t, nbio.run(), nil) + ev(t, n, NUM_TESTS) // Test that all callbacks have ran. + } +} + +@(test) +two_ops_at_the_same_time :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + server, err := nbio.create_udp_socket(.IP4) + ev(t, err, nil) + defer nbio.close(server) + + berr := nbio.bind(server, {nbio.IP4_Loopback, 0}) + ev(t, berr, nil) + ep, eperr := nbio.bound_endpoint(server) + ev(t, eperr, nil) + + // Server. + { + nbio.poll_poly(server, .Receive, t, on_poll) + + on_poll :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.poll.result, nbio.Poll_Result.Ready) + } + + buf: [128]byte + nbio.recv_poly(server, {buf[:]}, t, on_recv) + + on_recv :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.recv.err, nil) + } + } + + // Client. + { + sock, cerr := nbio.create_udp_socket(.IP4) + ev(t, cerr, nil) + + // Make sure the server would block. + nbio.timeout_poly3(time.Millisecond*10, t, sock, ep.port, on_timeout) + + on_timeout :: proc(op: ^nbio.Operation, t: ^testing.T, sock: nbio.UDP_Socket, port: int) { + nbio.send_poly(sock, {transmute([]byte)string("Hiya")}, t, on_send, {nbio.IP4_Loopback, port}) + } + + on_send :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.send.err, nil) + ev(t, op.send.sent, 4) + + // Do another send after a bit, some backends don't trigger both ops when one was enough to + // use up the socket. + nbio.timeout_poly3(time.Millisecond*10, t, op.send.socket.(nbio.UDP_Socket), op.send.endpoint.port, on_timeout2) + } + + on_timeout2 :: proc(op: ^nbio.Operation, t: ^testing.T, sock: nbio.UDP_Socket, port: int) { + nbio.send_poly(sock, {transmute([]byte)string("Hiya")}, t, on_send2, {nbio.IP4_Loopback, port}) + } + + on_send2 :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.send.err, nil) + ev(t, op.send.sent, 4) + + nbio.close(op.send.socket.(nbio.UDP_Socket)) + } + } + + ev(t, nbio.run(), nil) + } +} + +@(test) +timeout :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + start := time.now() + + nbio.timeout_poly2(time.Millisecond*20, t, start, on_timeout) + + on_timeout :: proc(op: ^nbio.Operation, t: ^testing.T, start: time.Time) { + since := time.since(start) + log.infof("timeout ran after: %v", since) + testing.expect(t, since >= time.Millisecond*19) // A ms grace, for some reason it is sometimes ran after 19.8ms. + if since < 20 { + log.warnf("timeout ran after: %v", since) + } + } + + ev(t, nbio.run(), nil) + } +} + +@(test) +wake_up :: proc(t: ^testing.T) { + testing.set_fail_timeout(t, time.Minute) + if event_loop_guard(t) { + for _ in 0..<2 { + sock, _ := open_next_available_local_port(t) + + // Add an accept, with nobody dialling this should block the event loop forever. + accept := nbio.accept(sock, proc(op: ^nbio.Operation) { + log.error("shouldn't be called") + }) + + // Make sure the accept is in progress. + ev(t, nbio.tick(timeout=0), nil) + + hit: bool + thr := thread.create_and_start_with_poly_data2(nbio.current_thread_event_loop(), &hit, proc(l: ^nbio.Event_Loop, hit: ^bool) { + hit^ = true + nbio.wake_up(l) + }, context) + defer thread.destroy(thr) + + // Should block forever until the thread calling wake_up will make it return. + ev(t, nbio.tick(), nil) + e(t, hit) + + nbio.remove(accept) + nbio.close(sock) + + ev(t, nbio.run(), nil) + ev(t, nbio.tick(timeout=0), nil) + } + } +} + +// Tests that if multiple accepts are queued, and a dial comes in which completes one of them, +// the rest are queued again properly. +@(test) +still_pending :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + sock, ep := open_next_available_local_port(t) + defer nbio.close(sock) + + N :: 3 + + State :: struct { + accepted: int, + } + state: State + + on_accept :: proc(op: ^nbio.Operation, t: ^testing.T, state: ^State) { + ev(t, op.accept.err, nil) + state.accepted += 1 + nbio.close(op.accept.client) + } + + on_dial :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.dial.err, nil) + nbio.close(op.dial.socket) + } + + for _ in 0.. (sock: net.TCP_Socket, ep: net.Endpoint) { + err: net.Network_Error + sock, err = nbio.listen_tcp({addr, 0}) + if err != nil { + log.errorf("listen_tcp: %v", err, location=loc) + return + } + + ep, err = net.bound_endpoint(sock) + if err != nil { + log.errorf("bound_endpoint: %v", err, location=loc) + } + + return +} + +@(test) +client_and_server_send_recv :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + server, ep := open_next_available_local_port(t) + + CONTENT :: [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20} + + State :: struct { + server: net.TCP_Socket, + server_client: net.TCP_Socket, + client: net.TCP_Socket, + recv_buf: [20]byte, + send_buf: [20]byte, + } + + state := State{ + server = server, + send_buf = CONTENT, + } + + close_ok :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.close.err, nil) + } + + // Server + { + nbio.accept_poly2(server, t, &state, on_accept) + + on_accept :: proc(op: ^nbio.Operation, t: ^testing.T, state: ^State) { + ev(t, op.accept.err, nil) + + state.server_client = op.accept.client + + log.debugf("accepted connection from: %v", op.accept.client_endpoint) + + nbio.recv_poly2(state.server_client, {state.recv_buf[:]}, t, state, on_recv) + } + + on_recv :: proc(op: ^nbio.Operation, t: ^testing.T, state: ^State) { + ev(t, op.recv.err, nil) + ev(t, op.recv.received, 20) + ev(t, state.recv_buf, CONTENT) + + nbio.close_poly(state.server_client, t, close_ok) + nbio.close_poly(state.server, t, close_ok) + } + + ev(t, nbio.tick(0), nil) + } + + // Client + { + nbio.dial_poly2(ep, t, &state, on_dial) + + on_dial :: proc(op: ^nbio.Operation, t: ^testing.T, state: ^State) { + ev(t, op.dial.err, nil) + + state.client = op.dial.socket + + nbio.send_poly2(state.client, {state.send_buf[:]}, t, state, on_send) + } + + on_send :: proc(op: ^nbio.Operation, t: ^testing.T, state: ^State) { + ev(t, op.send.err, nil) + ev(t, op.send.sent, 20) + + nbio.close_poly(state.client, t, close_ok) + } + } + + ev(t, nbio.run(), nil) + } +} + +@(test) +close_and_remove_accept :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + server, _ := open_next_available_local_port(t) + + accept := nbio.accept_poly(server, t, proc(_: ^nbio.Operation, t: ^testing.T) { + testing.fail_now(t) + }) + + ev(t, nbio.tick(0), nil) + + nbio.close_poly(server, t, proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.close.err, nil) + }) + + nbio.remove(accept) + ev(t, nbio.run(), nil) + } +} + +// Tests that when a client calls `close` on it's socket, `recv` returns with `0, nil` (connection closed). +@(test) +close_errors_recv :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + server, ep := open_next_available_local_port(t) + + // Server + { + nbio.accept_poly(server, t, on_accept) + + on_accept :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.accept.err, nil) + + bytes := make([]byte, 128, context.temp_allocator) + nbio.recv_poly(op.accept.client, {bytes}, t, on_recv) + } + + on_recv :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.recv.received, 0) + ev(t, op.recv.err, nil) + } + + ev(t, nbio.tick(0), nil) + } + + // Client + { + nbio.dial_poly(ep, t, on_dial) + + on_dial :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.dial.err, nil) + nbio.close_poly(op.dial.socket, t, on_close) + } + + on_close :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.close.err, nil) + } + } + + ev(t, nbio.run(), nil) + } +} + +@(test) +ipv6 :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + server, ep := open_next_available_local_port(t, net.IP6_Loopback) + + nbio.accept_poly(server, t, on_accept) + on_accept :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.accept.err, nil) + addr, is_ipv6 := op.accept.client_endpoint.address.(net.IP6_Address) + e(t, is_ipv6) + ev(t, addr, net.IP6_Loopback) + e(t, op.accept.client_endpoint.port != 0) + nbio.close(op.accept.client) + nbio.close(op.accept.socket) + } + + nbio.dial_poly(ep, t, on_dial) + on_dial :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.dial.err, nil) + nbio.close(op.dial.socket) + } + + ev(t, nbio.run(), nil) + } +} + +@(test) +accept_timeout :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + sock, _ := open_next_available_local_port(t) + + hit: bool + nbio.accept_poly2(sock, t, &hit, on_accept, timeout=time.Millisecond) + + on_accept :: proc(op: ^nbio.Operation, t: ^testing.T, hit: ^bool) { + hit^ = true + ev(t, op.accept.err, net.Accept_Error.Timeout) + nbio.close(op.accept.socket) + } + + ev(t, nbio.run(), nil) + + e(t, hit) + } +} + +@(test) +poll_timeout :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + sock, err := nbio.create_udp_socket(.IP4) + ev(t, err, nil) + berr := nbio.bind(sock, {nbio.IP4_Loopback, 0}) + ev(t, berr, nil) + + nbio.poll_poly(sock, .Receive, t, on_poll, time.Millisecond) + on_poll :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.poll.result, nbio.Poll_Result.Timeout) + } + + ev(t, nbio.run(), nil) + } +} + +/* +This test walks through the scenario where a user wants to `poll` in order to check if some other package (in this case `core:net`), +would be able to do an operation without blocking. + +It also tests whether a poll can be issues when it is already in a ready state. +And it tests big send/recv buffers being handled properly. +*/ +@(test) +poll :: proc(t: ^testing.T) { + if event_loop_guard(t) { +// testing.set_fail_timeout(t, time.Minute) + + can_recv: bool + + sock, ep := open_next_available_local_port(t) + + // Server + { + nbio.accept_poly2(sock, t, &can_recv, on_accept) + + on_accept :: proc(op: ^nbio.Operation, t: ^testing.T, can_recv: ^bool) { + ev(t, op.accept.err, nil) + + check_recv :: proc(op: ^nbio.Operation, t: ^testing.T, can_recv: ^bool, client: net.TCP_Socket) { + // Not ready to unblock the client yet, requeue for after 10ms. + if !can_recv^ { + nbio.timeout_poly3(time.Millisecond * 10, t, can_recv, client, check_recv) + return + } + + free_all(context.temp_allocator) + + // Connection was closed by client, close server. + if op.type == .Recv && op.recv.received == 0 && op.recv.err == nil { + nbio.close(client) + return + } + + if op.type == .Recv { + log.debugf("received %M this time", op.recv.received) + } + + // Receive some data to unblock the client, which should complete the poll it does, allowing it to send data again. + buf, mem_err := make([]byte, mem.Gigabyte, context.temp_allocator) + ev(t, mem_err, nil) + nbio.recv_poly3(client, {buf}, t, can_recv, client, check_recv) + } + nbio.timeout_poly3(time.Millisecond * 10, t, can_recv, op.accept.client, check_recv) + } + + ev(t, nbio.tick(0), nil) + } + + // Client + { + nbio.dial_poly2(ep, t, &can_recv, on_dial) + + on_dial :: proc(op: ^nbio.Operation, t: ^testing.T, can_recv: ^bool) { + ev(t, op.dial.err, nil) + + // Do a poll even though we know it's ready, so we can test that all implementations can handle that. + nbio.poll_poly2(op.dial.socket, .Send, t, can_recv, on_poll1) + } + + on_poll1 :: proc(op: ^nbio.Operation, t: ^testing.T, can_recv: ^bool) { + ev(t, op.poll.result, nil) + + // Send 4 GB of data, which in my experience causes a Would_Block error because we filled up the internal buffer. + buf, mem_err := make([]byte, mem.Gigabyte*4, context.temp_allocator) + ev(t, mem_err, nil) + + // Use `core:net` as example external code that doesn't care about the event loop. + net.set_blocking(op.poll.socket, false) + n, send_err := net.send(op.poll.socket, buf) + ev(t, send_err, net.TCP_Send_Error.Would_Block) + + log.debugf("blocking after %M", n) + + // Tell the server it can start issueing recv calls, so it unblocks us. + can_recv^ = true + + // Now poll again, when the server reads enough data it should complete, telling us we can send without blocking again. + nbio.poll_poly(op.poll.socket, .Send, t, on_poll2) + } + + on_poll2 :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.poll.result, nil) + + buf: [128]byte + bytes_written, send_err := net.send(op.poll.socket, buf[:]) + ev(t, bytes_written, 128) + ev(t, send_err, nil) + + nbio.close(op.poll.socket.(net.TCP_Socket)) + } + } + + ev(t, nbio.run(), nil) + nbio.close(sock) + ev(t, nbio.run(), nil) + } +} + +@(test) +sendfile :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + CONTENT :: #load(#file) + + sock, ep := open_next_available_local_port(t) + + // Server + { + nbio.accept_poly(sock, t, on_accept) + + on_accept :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.accept.err, nil) + e(t, op.accept.client != 0) + + log.debugf("connection from: %v", op.accept.client_endpoint) + nbio.open_poly3(#file, t, op.accept.socket, op.accept.client, on_open) + } + + on_open :: proc(op: ^nbio.Operation, t: ^testing.T, server, client: net.TCP_Socket) { + ev(t, op.open.err, nil) + + nbio.sendfile_poly2(client, op.open.handle, t, server, on_sendfile) + } + + on_sendfile :: proc(op: ^nbio.Operation, t: ^testing.T, server: net.TCP_Socket) { + ev(t, op.sendfile.err, nil) + ev(t, op.sendfile.sent, len(CONTENT)) + + nbio.close(op.sendfile.file) + nbio.close(op.sendfile.socket) + nbio.close(server) + } + } + + // Client + { + nbio.dial_poly(ep, t, on_dial) + + on_dial :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.dial.err, nil) + + buf := make([]byte, len(CONTENT), context.temp_allocator) + nbio.recv_poly(op.dial.socket, {buf}, t, on_recv, all=true) + } + + on_recv :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.recv.err, nil) + ev(t, op.recv.received, len(CONTENT)) + ev(t, string(op.recv.bufs[0]), string(CONTENT)) + + nbio.close(op.recv.socket.(net.TCP_Socket)) + } + } + + ev(t, nbio.run(), nil) + } +} + +@(test) +vectored :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + sock, ep := open_next_available_local_port(t) + + to_send := [?][]byte{ + {'H', 'e', 'l', 'l'}, + {'o', 'p', 'e'}, + {'!'}, + } + + to_recv := [?][]byte{ + {0, 0, 0, 0}, + {0, 0, 0}, + {0}, + } + + // Server + { + nbio.accept_poly2(sock, t, &to_send, on_accept) + + on_accept :: proc(op: ^nbio.Operation, t: ^testing.T, to_send: ^[3][]byte) { + ev(t, op.accept.err, nil) + e(t, op.accept.client != 0) + to_send_copy := to_send^[:] + nbio.send_poly3(op.accept.client, to_send_copy, t, op.accept.socket, to_send, on_send) + } + + on_send :: proc(op: ^nbio.Operation, t: ^testing.T, server: net.TCP_Socket, to_send: ^[3][]byte) { + ev(t, op.send.err, nil) + ev(t, op.send.sent, 8) + + expected := to_send^ + for buf, i in expected { + ev(t, string(op.send.bufs[i]), string(buf)) + } + + nbio.close(op.send.socket.(net.TCP_Socket)) + nbio.close(server) + } + } + + // Client + { + nbio.dial_poly3(ep, t, &to_recv, &to_send, on_dial) + + on_dial :: proc(op: ^nbio.Operation, t: ^testing.T, to_recv: ^[3][]byte, expected: ^[3][]byte) { + ev(t, op.dial.err, nil) + + to_recv_copy := to_recv^[:] + nbio.recv_poly2(op.dial.socket, to_recv_copy, t, expected, on_recv, all=true) + } + + on_recv :: proc(op: ^nbio.Operation, t: ^testing.T, expected: ^[3][]byte) { + ev(t, op.recv.err, nil) + ev(t, op.recv.received, 8) + + expected := expected^[:] + for buf, i in expected { + ev(t, string(op.recv.bufs[i]), string(buf)) + } + + nbio.close(op.recv.socket.(net.TCP_Socket)) + } + } + + ev(t, nbio.run(), nil) + } +} diff --git a/tests/core/nbio/remove.odin b/tests/core/nbio/remove.odin new file mode 100644 index 000000000..063c2cf58 --- /dev/null +++ b/tests/core/nbio/remove.odin @@ -0,0 +1,247 @@ +package tests_nbio + +import "core:nbio" +import "core:net" +import "core:testing" +import "core:time" +import "core:log" + +// Removals are pretty complex. + +@(test) +immediate_remove_of_sendfile :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + sock, ep := open_next_available_local_port(t) + + // Server + { + nbio.accept_poly(sock, t, on_accept) + + on_accept :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.accept.err, nil) + e(t, op.accept.client != 0) + + log.debugf("connection from: %v", op.accept.client_endpoint) + nbio.open_poly3(#file, t, op.accept.socket, op.accept.client, on_open) + } + + on_open :: proc(op: ^nbio.Operation, t: ^testing.T, server, client: net.TCP_Socket) { + ev(t, op.open.err, nil) + e(t, op.open.handle != 0) + + sendfile_op := nbio.sendfile_poly2(client, op.open.handle, t, server, on_sendfile) + + // oh no changed my mind. + nbio.remove(sendfile_op) + + nbio.close(op.open.handle) + nbio.close(client) + nbio.close(server) + } + + on_sendfile :: proc(op: ^nbio.Operation, t: ^testing.T, server: net.TCP_Socket) { + log.error("on_sendfile shouldn't be called") + } + } + + // Client + { + nbio.dial_poly(ep, t, on_dial) + + on_dial :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.dial.err, nil) + + buf := make([]byte, 128, context.temp_allocator) + nbio.recv_poly(op.dial.socket, {buf}, t, on_recv) + } + + on_recv :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.recv.err, nil) + + nbio.close(op.recv.socket.(net.TCP_Socket)) + } + } + + ev(t, nbio.run(), nil) + } +} + +@(test) +immediate_remove_of_sendfile_without_stat :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + sock, ep := open_next_available_local_port(t) + + // Server + { + nbio.accept_poly(sock, t, on_accept) + + on_accept :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.accept.err, nil) + e(t, op.accept.client != 0) + + log.debugf("connection from: %v", op.accept.client_endpoint) + nbio.open_poly3(#file, t, op.accept.socket, op.accept.client, on_open) + } + + on_open :: proc(op: ^nbio.Operation, t: ^testing.T, server, client: net.TCP_Socket) { + ev(t, op.open.err, nil) + e(t, op.open.handle != 0) + + nbio.stat_poly3(op.open.handle, t, server, client, on_stat) + } + + on_stat :: proc(op: ^nbio.Operation, t: ^testing.T, server, client: net.TCP_Socket) { + ev(t, op.stat.err, nil) + + sendfile_op := nbio.sendfile_poly2(client, op.stat.handle, t, server, on_sendfile, nbytes=int(op.stat.size)) + + // oh no changed my mind. + nbio.remove(sendfile_op) + + nbio.timeout_poly3(time.Millisecond * 10, op.stat.handle, client, server, proc(op: ^nbio.Operation, p1: nbio.Handle, p2, p3: net.TCP_Socket){ + nbio.close(p1) + nbio.close(p2) + nbio.close(p3) + }) + } + + on_sendfile :: proc(op: ^nbio.Operation, t: ^testing.T, server: net.TCP_Socket) { + log.error("on_sendfile shouldn't be called") + } + } + + // Client + { + nbio.dial_poly(ep, t, on_dial) + + on_dial :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.dial.err, nil) + + buf := make([]byte, 128, context.temp_allocator) + nbio.recv_poly(op.dial.socket, {buf}, t, on_recv) + } + + on_recv :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.recv.err, nil) + + nbio.close(op.recv.socket.(net.TCP_Socket)) + } + } + + ev(t, nbio.run(), nil) + } +} + +// Open should free the temporary memory allocated for the path when removed. +// Can't really test that though, so should be checked manually that the internal callback is called but not the external. +@(test) +remove_open :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + open := nbio.open(#file, on_open) + nbio.remove(open) + + on_open :: proc(op: ^nbio.Operation) { + log.error("on_open shouldn't be called") + } + + ev(t, nbio.run(), nil) + } +} + +// Dial should close the socket when removed. +// Can't really test that though, so should be checked manually that the internal callback is called but not the external. +@(test) +remove_dial :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + sock, ep := open_next_available_local_port(t) + defer nbio.close(sock) + + dial := nbio.dial(ep, on_dial) + nbio.remove(dial) + + on_dial :: proc(op: ^nbio.Operation) { + log.error("on_dial shouldn't be called") + } + + ev(t, nbio.run(), nil) + } +} + +@(test) +remove_next_tick :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + nt := nbio.next_tick_poly(t, proc(op: ^nbio.Operation, t: ^testing.T) { + log.error("shouldn't be called") + }) + nbio.remove(nt) + + ev(t, nbio.run(), nil) + } +} + +@(test) +remove_timeout :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + hit: bool + timeout := nbio.timeout_poly(time.Second, &hit, proc(_: ^nbio.Operation, hit: ^bool) { + hit^ = true + }) + + nbio.remove(timeout) + + ev(t, nbio.run(), nil) + + e(t, !hit) + } +} + +@(test) +remove_multiple_poll :: proc(t: ^testing.T) { + if event_loop_guard(t) { + testing.set_fail_timeout(t, time.Minute) + + sock, ep := open_next_available_local_port(t) + defer nbio.close(sock) + + hit: bool + + first := nbio.poll(sock, .Receive, on_poll) + nbio.poll_poly2(sock, .Receive, t, &hit, on_poll2) + + on_poll :: proc(op: ^nbio.Operation) { + log.error("shouldn't be called") + } + + on_poll2 :: proc(op: ^nbio.Operation, t: ^testing.T, hit: ^bool) { + ev(t, op.poll.result, nbio.Poll_Result.Ready) + hit^ = true + } + + ev(t, nbio.tick(0), nil) + + nbio.remove(first) + + ev(t, nbio.tick(0), nil) + + nbio.dial_poly(ep, t, on_dial) + + on_dial :: proc(op: ^nbio.Operation, t: ^testing.T) { + ev(t, op.dial.err, nil) + } + + ev(t, nbio.run(), nil) + e(t, hit) + } +} diff --git a/tests/core/net/test_core_net.odin b/tests/core/net/test_core_net.odin index ec45744f3..0b079f5b0 100644 --- a/tests/core/net/test_core_net.odin +++ b/tests/core/net/test_core_net.odin @@ -10,8 +10,6 @@ A test suite for `core:net` */ -#+build !netbsd -#+build !openbsd #+feature dynamic-literals package test_core_net @@ -593,7 +591,8 @@ test_dns_resolve :: proc(t: ^testing.T) { } ip6, ip6_ok := ep6.address.(net.IP6_Address) - if !testing.expect(t, ip6_ok, "Unable to resolve IP6") { + if !ip6_ok { + log.info("Unable to resolve IP6") return } @@ -624,6 +623,41 @@ test_nonblocking_option :: proc(t: ^testing.T) { } } +// Test that when the server closes it's connection, the client's next receive is `0, nil` to indicate a correct close. +@(test) +test_connection_close :: proc(t: ^testing.T) { + server, listen_err := net.listen_tcp({address=net.IP4_Address{127, 0, 0, 1}, port=0}) + testing.expect_value(t, listen_err, nil) + defer net.close(server) + + server_ep, bound_endpoint_err := net.bound_endpoint(server) + testing.expect_value(t, bound_endpoint_err, nil) + + client, dial_err := net.dial_tcp(server_ep) + testing.expect_value(t, dial_err, nil) + defer net.close(client) + + server_client, _, accept_err := net.accept_tcp(server) + testing.expect_value(t, accept_err, nil) + + send_buf: [512]byte = 1 + sent, send_err := net.send(server_client, send_buf[:]) + testing.expect_value(t, sent, 512) + testing.expect_value(t, send_err, nil) + net.close(server_client) + + recv_buf: [512]byte = --- + received, recv_err := net.recv(client, recv_buf[:]) + testing.expect_value(t, received, 512) + testing.expect_value(t, recv_err, nil) + + testing.expect_value(t, recv_buf, send_buf) + + received, recv_err = net.recv(client, recv_buf[:]) + testing.expect_value(t, received, 0) + testing.expect_value(t, recv_err, nil) +} + @(private) address_to_binstr :: proc(address: net.Address) -> (binstr: string) { switch t in address { diff --git a/tests/core/normal.odin b/tests/core/normal.odin index e8b61fee8..4708ed700 100644 --- a/tests/core/normal.odin +++ b/tests/core/normal.odin @@ -18,6 +18,7 @@ download_assets :: proc "contextless" () { @(require) import "encoding/cbor" @(require) import "encoding/hex" @(require) import "encoding/hxa" +@(require) import "encoding/ini" @(require) import "encoding/json" @(require) import "encoding/uuid" @(require) import "encoding/varint" @@ -32,11 +33,11 @@ download_assets :: proc "contextless" () { @(require) import "math/noise" @(require) import "math/rand" @(require) import "mem" +@(require) import "nbio" @(require) import "net" @(require) import "odin" @(require) import "os" -@(require) import "os/os2" -@(require) import "path/filepath" +@(require) import "os/old" @(require) import "reflect" @(require) import "runtime" @(require) import "slice" @@ -45,10 +46,11 @@ download_assets :: proc "contextless" () { @(require) import "sync" @(require) import "sync/chan" @(require) import "sys/posix" +@(require) import "sys/kqueue" @(require) import "sys/windows" @(require) import "text/i18n" @(require) import "text/match" @(require) import "text/regex" @(require) import "thread" @(require) import "time" -@(require) import "unicode" +@(require) import "unicode" \ No newline at end of file diff --git a/tests/core/os/os2/dir.odin b/tests/core/os/dir.odin similarity index 82% rename from tests/core/os/os2/dir.odin rename to tests/core/os/dir.odin index 8ef333219..464abed98 100644 --- a/tests/core/os/os2/dir.odin +++ b/tests/core/os/dir.odin @@ -1,14 +1,14 @@ -package tests_core_os_os2 +package tests_core_os -import os "core:os/os2" -import "core:log" -import "core:slice" -import "core:testing" -import "core:strings" +import "core:os" +import "core:log" +import "core:slice" +import "core:testing" +import "core:strings" @(test) test_read_dir :: proc(t: ^testing.T) { - path, err_join := os.join_path({#directory, "../dir"}, context.allocator) + path, err_join := os.join_path({#directory, "dir"}, context.allocator) defer delete(path) fis, err_read := os.read_all_directory_by_path(path, context.allocator) @@ -17,7 +17,7 @@ test_read_dir :: proc(t: ^testing.T) { slice.sort_by_key(fis, proc(fi: os.File_Info) -> string { return fi.name }) if err_read == .Unsupported { - log.warn("os2 directory functionality is unsupported, skipping test") + log.warn("core:os directory functionality is unsupported, skipping test") return } @@ -34,7 +34,7 @@ test_read_dir :: proc(t: ^testing.T) { @(test) test_walker :: proc(t: ^testing.T) { - path, err := os.join_path({#directory, "../dir"}, context.allocator) + path, err := os.join_path({#directory, "dir"}, context.allocator) defer delete(path) testing.expect_value(t, err, nil) @@ -46,7 +46,7 @@ test_walker :: proc(t: ^testing.T) { @(test) test_walker_file :: proc(t: ^testing.T) { - path, err_join := os.join_path({#directory, "../dir"}, context.allocator) + path, err_join := os.join_path({#directory, "dir"}, context.allocator) defer delete(path) testing.expect_value(t, err_join, nil) @@ -95,7 +95,7 @@ test_walker_internal :: proc(t: ^testing.T, w: ^os.Walker) { } if _, err := os.walker_error(w); err == .Unsupported { - log.warn("os2 directory functionality is unsupported, skipping test") + log.warn("core:os directory functionality is unsupported, skipping test") return } diff --git a/tests/core/os/os2/file.odin b/tests/core/os/file.odin similarity index 70% rename from tests/core/os/os2/file.odin rename to tests/core/os/file.odin index 0152a2008..99ae5b928 100644 --- a/tests/core/os/os2/file.odin +++ b/tests/core/os/file.odin @@ -1,14 +1,13 @@ -package tests_core_os_os2 +package tests_core_os -import os "core:os/os2" -import "core:testing" +import "core:os" +import "core:testing" @(test) test_clone :: proc(t: ^testing.T) { - joined, err := os.join_path({#directory, "file.odin"}, context.temp_allocator) - testing.expect_value(t, err, nil) - f: ^os.File - f, err = os.open(joined) + joined, j_err := os.join_path({#directory, "file.odin"}, context.temp_allocator) + testing.expect_value(t, j_err, nil) + f, err := os.open(joined) testing.expect_value(t, err, nil) testing.expect(t, f != nil) diff --git a/tests/core/os/os.odin b/tests/core/os/old/os.odin similarity index 97% rename from tests/core/os/os.odin rename to tests/core/os/old/os.odin index 1510bad31..9925cf708 100644 --- a/tests/core/os/os.odin +++ b/tests/core/os/old/os.odin @@ -1,8 +1,8 @@ -package test_core_os +package test_core_os_old import "core:c/libc" import win32 "core:sys/windows" -import "core:os" +import os "core:os/old" import "core:slice" import "core:testing" import "core:log" diff --git a/tests/core/os/os2/path.odin b/tests/core/os/path.odin similarity index 66% rename from tests/core/os/os2/path.odin rename to tests/core/os/path.odin index 7b1cb0146..3a7611757 100644 --- a/tests/core/os/os2/path.odin +++ b/tests/core/os/path.odin @@ -1,9 +1,11 @@ -package tests_core_os_os2 +package tests_core_os -import os "core:os/os2" -import "core:log" -import "core:testing" -import "core:strings" +import "core:fmt" +import "core:os" +import "core:log" +import "core:testing" +import "core:slice" +import "core:strings" @(test) test_executable :: proc(t: ^testing.T) { @@ -97,6 +99,26 @@ test_clean_path :: proc(t: ^testing.T) { } } +@(test) +replace_path_separators :: proc(t: ^testing.T) { + { + P :: "W:/Odin/core/os/path.odin" + + p1, _ := os.replace_path_separators(P, '😀', context.temp_allocator) + testing.expect_value(t, p1, "W:😀Odin😀core😀os😀path.odin") + + p2, _ := os.replace_path_separators(P, '|', context.temp_allocator) + testing.expect_value(t, p2, "W:|Odin|core|os|path.odin") + } + + { + P :: "W:/恥知らずなフクロウ/path.odin" + + p1, _ := os.replace_path_separators(P, '😀', context.temp_allocator) + testing.expect_value(t, p1, "W:😀恥知らずなフクロウ😀path.odin") + } +} + @(test) test_is_absolute_path :: proc(t: ^testing.T) { when ODIN_OS == .Windows { @@ -334,6 +356,77 @@ test_join_filename :: proc(t: ^testing.T) { } } +Glob_Test :: struct { + pattern: string, + matches: []string, + err: os.Error, +} + +glob_tests := []Glob_Test{ + { + pattern = ODIN_ROOT + "tests/core/os/*/*.txt", + matches = { + ODIN_ROOT + "tests/core/os/dir/b.txt", + }, + err = {}, + }, + { + pattern = ODIN_ROOT + "tests/core/os/*.odin", + matches = { + ODIN_ROOT + "tests/core/os/dir.odin", + ODIN_ROOT + "tests/core/os/file.odin", + ODIN_ROOT + "tests/core/os/path.odin", + ODIN_ROOT + "tests/core/os/process.odin", + }, + err = {}, + }, +} + +@(test) +test_glob :: proc(t: ^testing.T) { + compare_matches :: proc(t: ^testing.T, pattern: string, globbed, expected: []string) { + glob_fold := make([]string, len(globbed), context.temp_allocator) + expect_fold := make([]string, len(globbed), context.temp_allocator) + + for glob, i in globbed { + // If `glob` returned a path in response to a pattern, + // then `match` should consider that path a match, too, + // irrespective of `/` versus `\` presence. + no_match_msg := fmt.tprintf("Expected os.match(%q, %q) to be `true`, got `false`", pattern, glob) + match, _ := os.match(pattern, glob) + + f, _ := strings.replace_all(glob, `\`, `/`, context.temp_allocator) + glob_fold[i] = f + testing.expect(t, match, no_match_msg) + } + + for exp, i in expected { + f, _ := strings.replace_all(exp, `\`, `/`, context.temp_allocator) + expect_fold[i] = f + } + + slice.sort(glob_fold) + slice.sort(expect_fold) + + not_equal_msg := fmt.tprintf("Expected os.glob(%q) to return %v, got %v", pattern, glob_fold, expect_fold) + testing.expect(t, slice.equal(glob_fold, expect_fold), not_equal_msg) + } + + for glob in glob_tests { + globbed, err := os.glob(glob.pattern, context.allocator) + defer { + for file in globbed { + delete(file) + } + delete(globbed) + } + testing.expect_value(t, err, glob.err) + compare_matches(t, glob.pattern, globbed, glob.matches) + } +} + + +// TODO: merge this and `test_split_list` @(test) test_split_path_list :: proc(t: ^testing.T) { Test_Case :: struct { @@ -375,3 +468,115 @@ test_split_path_list :: proc(t: ^testing.T) { } } } + +@(test) +test_split_list :: proc(t: ^testing.T) { + when ODIN_OS == .Windows { + test_split_list_windows(t) + } else { + test_split_list_unix(t) + } +} + +test_split_list_windows :: proc(t: ^testing.T) { + Datum :: struct { + i: int, + v: string, + e: [3]string, + } + @static data := []Datum{ + { 0, "C:\\Odin;C:\\Visual Studio;\"C:\\Some Other\"", + [3]string{"C:\\Odin", "C:\\Visual Studio", "C:\\Some Other"} }, // Issue #1537 + { 1, "a;;b", [3]string{"a", "", "b"} }, + { 2, "a;b;", [3]string{"a", "b", ""} }, + { 3, ";a;b", [3]string{"", "a", "b"} }, + { 4, ";;", [3]string{"", "", ""} }, + { 5, "\"a;b\"c;d;\"f\"", [3]string{"a;bc", "d", "f"} }, + { 6, "\"a;b;c\";d\";e\";f", [3]string{"a;b;c", "d;e", "f"} }, + } + + for d, i in data { + assert(i == d.i, fmt.tprintf("wrong data index: i %d != d.i %d\n", i, d.i)) + r, err := os.split_path_list(d.v, context.allocator) + testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) + defer delete_split(r) + testing.expect(t, len(r) == len(d.e), fmt.tprintf("i:%d %s(%s) len(r) %d != len(d.e) %d", i, #procedure, d.v, len(r), len(d.e))) + if len(r) == len(d.e) { + for _, j in r { + testing.expect(t, r[j] == d.e[j], fmt.tprintf("i:%d %s(%v) -> %v[%d] != %v", i, #procedure, d.v, r[j], j, d.e[j])) + } + } + } + + { + v := "" + r, err := os.split_path_list(v, context.allocator) + testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) + defer delete_split(r) + testing.expect(t, r == nil, fmt.tprintf("%s(%s) -> %v != nil", #procedure, v, r)) + } + { + v := "a" + r, err := os.split_path_list(v, context.allocator) + testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) + defer delete_split(r) + testing.expect(t, len(r) == 1, fmt.tprintf("%s(%s) len(r) %d != 1", #procedure, v, len(r))) + if len(r) == 1 { + testing.expect(t, r[0] == "a", fmt.tprintf("%s(%v) -> %v[0] != a", #procedure, v, r[0])) + } + } +} + +test_split_list_unix :: proc(t: ^testing.T) { + Datum :: struct { + v: string, + e: [3]string, + } + @static data := []Datum{ + { "/opt/butler:/home/fancykillerpanda/Projects/Odin/Odin:/usr/local/sbin", + [3]string{"/opt/butler", "/home/fancykillerpanda/Projects/Odin/Odin", "/usr/local/sbin"} }, // Issue #1537 + { "a::b", [3]string{"a", "", "b"} }, + { "a:b:", [3]string{"a", "b", ""} }, + { ":a:b", [3]string{"", "a", "b"} }, + { "::", [3]string{"", "", ""} }, + { "\"a:b\"c:d:\"f\"", [3]string{"a:bc", "d", "f"} }, + { "\"a:b:c\":d\":e\":f", [3]string{"a:b:c", "d:e", "f"} }, + } + + for d in data { + r, err := os.split_path_list(d.v, context.allocator) + testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) + defer delete_split(r) + testing.expectf(t, len(r) == len(d.e), "%s len(r) %d != len(d.e) %d", d.v, len(r), len(d.e)) + if len(r) == len(d.e) { + for _, j in r { + testing.expectf(t, r[j] == d.e[j], "%v -> %v[%d] != %v", d.v, r[j], j, d.e[j]) + } + } + } + + { + v := "" + r, err := os.split_path_list(v, context.allocator) + testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) + testing.expectf(t, r == nil, "'%s' -> '%v' != nil", v, r) + } + { + v := "a" + r, err := os.split_path_list(v, context.allocator) + testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) + defer delete_split(r) + testing.expectf(t, len(r) == 1, "'%s' len(r) %d != 1", v, len(r)) + if len(r) == 1 { + testing.expectf(t, r[0] == "a", "'%v' -> %v[0] != a", v, r[0]) + } + } +} + +@(private) +delete_split :: proc(s: []string) { + for part in s { + delete(part) + } + delete(s) +} \ No newline at end of file diff --git a/tests/core/os/os2/process.odin b/tests/core/os/process.odin similarity index 84% rename from tests/core/os/os2/process.odin rename to tests/core/os/process.odin index c530b4c79..adb65e95f 100644 --- a/tests/core/os/os2/process.odin +++ b/tests/core/os/process.odin @@ -1,9 +1,9 @@ #+build !windows -package tests_core_os_os2 +package tests_core_os -import os "core:os/os2" -import "core:log" -import "core:testing" +import "core:os" +import "core:log" +import "core:testing" @(test) test_process_exec :: proc(t: ^testing.T) { diff --git a/tests/core/path/filepath/test_core_filepath.odin b/tests/core/path/filepath/test_core_filepath.odin index f0137f69b..61f87ad02 100644 --- a/tests/core/path/filepath/test_core_filepath.odin +++ b/tests/core/path/filepath/test_core_filepath.odin @@ -33,7 +33,7 @@ test_split_list_windows :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i, fmt.tprintf("wrong data index: i %d != d.i %d\n", i, d.i)) - r := filepath.split_list(d.v) + r, _ := filepath.split_list(d.v, context.allocator) defer delete_split(r) testing.expect(t, len(r) == len(d.e), fmt.tprintf("i:%d %s(%s) len(r) %d != len(d.e) %d", i, #procedure, d.v, len(r), len(d.e))) if len(r) == len(d.e) { @@ -45,13 +45,13 @@ test_split_list_windows :: proc(t: ^testing.T) { { v := "" - r := filepath.split_list(v) + r, _ := filepath.split_list(v, context.allocator) defer delete_split(r) testing.expect(t, r == nil, fmt.tprintf("%s(%s) -> %v != nil", #procedure, v, r)) } { v := "a" - r := filepath.split_list(v) + r, _ := filepath.split_list(v, context.allocator) defer delete_split(r) testing.expect(t, len(r) == 1, fmt.tprintf("%s(%s) len(r) %d != 1", #procedure, v, len(r))) if len(r) == 1 { @@ -77,7 +77,7 @@ test_split_list_unix :: proc(t: ^testing.T) { } for d in data { - r := filepath.split_list(d.v) + r, _ := filepath.split_list(d.v, context.allocator) defer delete_split(r) testing.expectf(t, len(r) == len(d.e), "%s len(r) %d != len(d.e) %d", d.v, len(r), len(d.e)) if len(r) == len(d.e) { @@ -89,12 +89,12 @@ test_split_list_unix :: proc(t: ^testing.T) { { v := "" - r := filepath.split_list(v) + r, _ := filepath.split_list(v, context.allocator) testing.expectf(t, r == nil, "'%s' -> '%v' != nil", v, r) } { v := "a" - r := filepath.split_list(v) + r, _ := filepath.split_list(v, context.allocator) defer delete_split(r) testing.expectf(t, len(r) == 1, "'%s' len(r) %d != 1", v, len(r)) if len(r) == 1 { @@ -109,4 +109,46 @@ delete_split :: proc(s: []string) { delete(part) } delete(s) +} + +@(test) +test_stem :: proc(t: ^testing.T) { + @static stem := [][2]string{ + {"builder.tar.gz", "builder.tar"}, + {"./builder.tar.gz", "builder.tar"}, + {"./builder/", ""}, + } + + @static short_stem := [][2]string{ + {"builder.tar", "builder"}, + {"./builder.tar", "builder"}, + {"./builder/", ""}, + } + + for d in stem { + testing.expect_value(t, filepath.stem(d[0]), d[1]) + } + + for d in short_stem { + testing.expect_value(t, filepath.short_stem(d[0]), d[1]) + } +} + +@(test) +test_dir :: proc(t: ^testing.T) { + when ODIN_OS == .Windows { + @static dirs := [][2]string{ + {"../bin/css", "..\\bin"}, + {"W:/Odin/odin", "W:\\Odin"}, + } + } else { + @static dirs := [][2]string{ + {"../bin/css", "../bin"}, + {"/bin/usr/", "/bin/usr"}, + } + } + + for d in dirs { + testing.expect_value(t, filepath.dir(d[0], context.temp_allocator), d[1]) + } } \ No newline at end of file diff --git a/tests/core/strings/test_core_strings.odin b/tests/core/strings/test_core_strings.odin index 140689468..a7502ab92 100644 --- a/tests/core/strings/test_core_strings.odin +++ b/tests/core/strings/test_core_strings.odin @@ -164,11 +164,16 @@ test_substring :: proc(t: ^testing.T) { {s = "Hello", end = len("Hello"), sub = "Hello", ok = true}, {s = "Hello", start = 1, end = len("Hello"), sub = "ello", ok = true}, {s = "Hello", start = 1, end = len("Hello") - 1, sub = "ell", ok = true}, + {s = "Hello", start = 0, end = 0, sub = "", ok = true}, + {s = "Hello", start = 3, end = 3, sub = "", ok = true}, + {s = "Hello", start = len("Hello"), end = len("Hello"), sub = "", ok = true}, {s = "Hello", end = len("Hello") + 1, sub = "Hello", ok = false}, {s = "小猫咪", start = 0, end = 3, sub = "小猫咪", ok = true}, {s = "小猫咪", start = 1, end = 3, sub = "猫咪", ok = true}, {s = "小猫咪", start = 1, end = 5, sub = "猫咪", ok = false}, {s = "小猫咪", start = 1, end = 1, sub = "", ok = true}, + {s = "小猫咪", start = 1, end = 1, sub = "", ok = true}, + {s = "小猫咪", start = 3, end = 3, sub = "", ok = true}, } for tc in cases { diff --git a/tests/core/sys/kqueue/structs.odin b/tests/core/sys/kqueue/structs.odin new file mode 100644 index 000000000..15ec3f841 --- /dev/null +++ b/tests/core/sys/kqueue/structs.odin @@ -0,0 +1,56 @@ +#+build darwin, freebsd, openbsd, netbsd +package tests_core_sys_kqueue + +import "core:strings" +import "core:testing" +import "core:os" + +@(test) +structs :: proc(t: ^testing.T) { + { + c_compiler := os.get_env("CC", context.temp_allocator) + if c_compiler == "" { + c_compiler = "clang" + } + + c_compilation, c_start_err := os.process_start({ + command = {c_compiler, #directory + "/structs/structs.c", "-o", #directory + "/structs/c_structs"}, + stdout = os.stdout, + stderr = os.stderr, + }) + testing.expect_value(t, c_start_err, nil) + + o_compilation, o_start_err := os.process_start({ + command = {ODIN_ROOT + "/odin", "build", #directory + "/structs", "-out:" + #directory + "/structs/odin_structs"}, + stdout = os.stdout, + stderr = os.stderr, + }) + testing.expect_value(t, o_start_err, nil) + + c_status, c_err := os.process_wait(c_compilation) + testing.expect_value(t, c_err, nil) + testing.expect_value(t, c_status.exit_code, 0) + + o_status, o_err := os.process_wait(o_compilation) + testing.expect_value(t, o_err, nil) + testing.expect_value(t, o_status.exit_code, 0) + } + + c_status, c_stdout, c_stderr, c_err := os.process_exec({command={#directory + "/structs/c_structs"}}, context.temp_allocator) + testing.expect_value(t, c_err, nil) + testing.expect_value(t, c_status.exit_code, 0) + testing.expect_value(t, string(c_stderr), "") + + o_status, o_stdout, o_stderr, o_err := os.process_exec({command={#directory + "/structs/odin_structs"}}, context.temp_allocator) + testing.expect_value(t, o_err, nil) + testing.expect_value(t, o_status.exit_code, 0) + testing.expect_value(t, string(o_stderr), "") + + testing.expect(t, strings.trim_space(string(c_stdout)) != "") + + testing.expect_value( + t, + strings.trim_space(string(o_stdout)), + strings.trim_space(string(c_stdout)), + ) +} diff --git a/tests/core/sys/kqueue/structs/structs.c b/tests/core/sys/kqueue/structs/structs.c new file mode 100644 index 000000000..e7620c994 --- /dev/null +++ b/tests/core/sys/kqueue/structs/structs.c @@ -0,0 +1,63 @@ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + printf("kevent %zu %zu\n", sizeof(struct kevent), _Alignof(struct kevent)); + printf("kevent.ident %zu\n", offsetof(struct kevent, ident)); + printf("kevent.filter %zu\n", offsetof(struct kevent, filter)); + printf("kevent.flags %zu\n", offsetof(struct kevent, flags)); + printf("kevent.fflags %zu\n", offsetof(struct kevent, fflags)); + printf("kevent.data %zu\n", offsetof(struct kevent, data)); + printf("kevent.udata %zu\n", offsetof(struct kevent, udata)); + + printf("EV_ADD %d\n", EV_ADD); + printf("EV_DELETE %d\n", EV_DELETE); + printf("EV_ENABLE %d\n", EV_ENABLE); + printf("EV_DISABLE %d\n", EV_DISABLE); + printf("EV_ONESHOT %d\n", EV_ONESHOT); + printf("EV_CLEAR %d\n", EV_CLEAR); + printf("EV_RECEIPT %d\n", EV_RECEIPT); + printf("EV_DISPATCH %d\n", EV_DISPATCH); + printf("EV_ERROR %d\n", EV_ERROR); + printf("EV_EOF %d\n", EV_EOF); + + printf("EVFILT_READ %d\n", EVFILT_READ); + printf("EVFILT_WRITE %d\n", EVFILT_WRITE); + printf("EVFILT_AIO %d\n", EVFILT_AIO); + printf("EVFILT_VNODE %d\n", EVFILT_VNODE); + printf("EVFILT_PROC %d\n", EVFILT_PROC); + printf("EVFILT_SIGNAL %d\n", EVFILT_SIGNAL); + printf("EVFILT_TIMER %d\n", EVFILT_TIMER); + printf("EVFILT_USER %d\n", EVFILT_USER); + + printf("NOTE_SECONDS %u\n", NOTE_SECONDS); + printf("NOTE_USECONDS %u\n", NOTE_USECONDS); + printf("NOTE_NSECONDS %u\n", NOTE_NSECONDS); +#if defined(NOTE_ABSOLUTE) + printf("NOTE_ABSOLUTE %u\n", NOTE_ABSOLUTE); +#else + printf("NOTE_ABSOLUTE %u\n", NOTE_ABSTIME); +#endif + + printf("NOTE_LOWAT %u\n", NOTE_LOWAT); + + printf("NOTE_DELETE %u\n", NOTE_DELETE); + printf("NOTE_WRITE %u\n", NOTE_WRITE); + printf("NOTE_EXTEND %u\n", NOTE_EXTEND); + printf("NOTE_ATTRIB %u\n", NOTE_ATTRIB); + printf("NOTE_LINK %u\n", NOTE_LINK); + printf("NOTE_RENAME %u\n", NOTE_RENAME); + printf("NOTE_REVOKE %u\n", NOTE_REVOKE); + + printf("NOTE_EXIT %u\n", NOTE_EXIT); + printf("NOTE_FORK %u\n", NOTE_FORK); + printf("NOTE_EXEC %u\n", NOTE_EXEC); + + printf("NOTE_TRIGGER %u\n", NOTE_TRIGGER); + printf("NOTE_FFAND %u\n", NOTE_FFAND); + printf("NOTE_FFOR %u\n", NOTE_FFOR); + printf("NOTE_FFCOPY %u\n", NOTE_FFCOPY); + return 0; +} diff --git a/tests/core/sys/kqueue/structs/structs.odin b/tests/core/sys/kqueue/structs/structs.odin new file mode 100644 index 000000000..4886f63e4 --- /dev/null +++ b/tests/core/sys/kqueue/structs/structs.odin @@ -0,0 +1,58 @@ +package main + +import "core:fmt" +import "core:sys/kqueue" + +main :: proc() { + fmt.println("kevent", size_of(kqueue.KEvent), align_of(kqueue.KEvent)) + fmt.println("kevent.ident", offset_of(kqueue.KEvent, ident)) + fmt.println("kevent.filter", offset_of(kqueue.KEvent, filter)) + fmt.println("kevent.flags", offset_of(kqueue.KEvent, flags)) + fmt.println("kevent.fflags", offset_of(kqueue.KEvent, fflags)) + fmt.println("kevent.data", offset_of(kqueue.KEvent, data)) + fmt.println("kevent.udata", offset_of(kqueue.KEvent, udata)) + + fmt.println("EV_ADD", transmute(kqueue._Flags_Backing)kqueue.Flags{.Add}) + fmt.println("EV_DELETE", transmute(kqueue._Flags_Backing)kqueue.Flags{.Delete}) + fmt.println("EV_ENABLE", transmute(kqueue._Flags_Backing)kqueue.Flags{.Enable}) + fmt.println("EV_DISABLE", transmute(kqueue._Flags_Backing)kqueue.Flags{.Disable}) + fmt.println("EV_ONESHOT", transmute(kqueue._Flags_Backing)kqueue.Flags{.One_Shot}) + fmt.println("EV_CLEAR", transmute(kqueue._Flags_Backing)kqueue.Flags{.Clear}) + fmt.println("EV_RECEIPT", transmute(kqueue._Flags_Backing)kqueue.Flags{.Receipt}) + fmt.println("EV_DISPATCH", transmute(kqueue._Flags_Backing)kqueue.Flags{.Dispatch}) + fmt.println("EV_ERROR", transmute(kqueue._Flags_Backing)kqueue.Flags{.Error}) + fmt.println("EV_EOF", transmute(kqueue._Flags_Backing)kqueue.Flags{.EOF}) + + fmt.println("EVFILT_READ", int(kqueue.Filter.Read)) + fmt.println("EVFILT_WRITE", int(kqueue.Filter.Write)) + fmt.println("EVFILT_AIO", int(kqueue.Filter.AIO)) + fmt.println("EVFILT_VNODE", int(kqueue.Filter.VNode)) + fmt.println("EVFILT_PROC", int(kqueue.Filter.Proc)) + fmt.println("EVFILT_SIGNAL", int(kqueue.Filter.Signal)) + fmt.println("EVFILT_TIMER", int(kqueue.Filter.Timer)) + fmt.println("EVFILT_USER", int(kqueue.Filter.User)) + + fmt.println("NOTE_SECONDS", transmute(u32)kqueue.Timer_Flags{.Seconds}) + fmt.println("NOTE_USECONDS", transmute(u32)kqueue.Timer_Flags{.USeconds}) + fmt.println("NOTE_NSECONDS", transmute(u32)kqueue.TIMER_FLAGS_NSECONDS) + fmt.println("NOTE_ABSOLUTE", transmute(u32)kqueue.Timer_Flags{.Absolute}) + + fmt.println("NOTE_LOWAT", transmute(u32)kqueue.RW_Flags{.Low_Water_Mark}) + + fmt.println("NOTE_DELETE", transmute(u32)kqueue.VNode_Flags{.Delete}) + fmt.println("NOTE_WRITE", transmute(u32)kqueue.VNode_Flags{.Write}) + fmt.println("NOTE_EXTEND", transmute(u32)kqueue.VNode_Flags{.Extend}) + fmt.println("NOTE_ATTRIB", transmute(u32)kqueue.VNode_Flags{.Attrib}) + fmt.println("NOTE_LINK", transmute(u32)kqueue.VNode_Flags{.Link}) + fmt.println("NOTE_RENAME", transmute(u32)kqueue.VNode_Flags{.Rename}) + fmt.println("NOTE_REVOKE", transmute(u32)kqueue.VNode_Flags{.Revoke}) + + fmt.println("NOTE_EXIT", transmute(u32)kqueue.Proc_Flags{.Exit}) + fmt.println("NOTE_FORK", transmute(u32)kqueue.Proc_Flags{.Fork}) + fmt.println("NOTE_EXEC", transmute(u32)kqueue.Proc_Flags{.Exec}) + + fmt.println("NOTE_TRIGGER", transmute(u32)kqueue.User_Flags{.Trigger}) + fmt.println("NOTE_FFAND", transmute(u32)kqueue.User_Flags{.FFAnd}) + fmt.println("NOTE_FFOR", transmute(u32)kqueue.User_Flags{.FFOr}) + fmt.println("NOTE_FFCOPY", transmute(u32)kqueue.USER_FLAGS_COPY) +} diff --git a/tests/core/sys/posix/structs/structs.c b/tests/core/sys/posix/structs/structs.c index ac771057e..6bb7df29e 100644 --- a/tests/core/sys/posix/structs/structs.c +++ b/tests/core/sys/posix/structs/structs.c @@ -74,6 +74,7 @@ int main(int argc, char *argv[]) printf("ai_canonname %zu\n", offsetof(struct addrinfo, ai_canonname)); printf("pollfd %zu %zu\n", sizeof(struct pollfd), _Alignof(struct pollfd)); + printf("nfds_t %zu %zu\n", sizeof(nfds_t), _Alignof(nfds_t)); printf("passwd %zu %zu\n", sizeof(struct passwd), _Alignof(struct passwd)); diff --git a/tests/core/sys/posix/structs/structs.odin b/tests/core/sys/posix/structs/structs.odin index 55369e386..64833c437 100644 --- a/tests/core/sys/posix/structs/structs.odin +++ b/tests/core/sys/posix/structs/structs.odin @@ -41,6 +41,8 @@ main :: proc() { fmt.println("ai_canonname", offset_of(posix.addrinfo, ai_canonname)) fmt.println("pollfd", size_of(posix.pollfd), align_of(posix.pollfd)) + fmt.println("nfds_t", size_of(posix.nfds_t), align_of(posix.nfds_t)) + fmt.println("passwd", size_of(posix.passwd), align_of(posix.passwd)) when ODIN_OS != .Haiku { diff --git a/tests/core/sys/windows/util.odin b/tests/core/sys/windows/util.odin index e2ab9cde0..777f85776 100644 --- a/tests/core/sys/windows/util.odin +++ b/tests/core/sys/windows/util.odin @@ -4,6 +4,7 @@ package test_core_sys_windows import "base:intrinsics" import "core:testing" import win32 "core:sys/windows" +import runtime "base:runtime" UTF16_Vector :: struct { wstr: win32.wstring, @@ -31,4 +32,223 @@ utf16_to_utf8_buf_test :: proc(t: ^testing.T) { res := win32.utf16_to_utf8_buf(buf[:], transmute([]u16)wstr) testing.expect_value(t, res, test.ustr) } -} \ No newline at end of file +} + +@(test) +utf8_to_utf16_buf_test :: proc(t: ^testing.T) { + buf : [100]u16 = --- + // Test everything with a dirty buffer! + reset_buffer :: proc(buf : []u16) { + for i in 0 ..< len(buf) { + buf[i] = cast(u16)(i + 1) + } + } + + result : []u16 + + reset_buffer(buf[:]) + result = win32.utf8_to_utf16_buf(buf[:], "Hello\x00, World!") + testing.expect_value(t, len(result), 14) + testing.expect_value(t, result[4], 'o') + testing.expect_value(t, result[5], 0) + testing.expect_value(t, result[6], ',') + testing.expect_value(t, result[13], '!') + + reset_buffer(buf[:]) + result = win32.utf8_to_utf16_buf(buf[:], "H\x00\x00") + testing.expect_value(t, len(result), 3) + testing.expect_value(t, result[1], 0) + testing.expect_value(t, result[2], 0) + + reset_buffer(buf[:]) + result = win32.utf8_to_utf16_buf(buf[:], "你好,世界!") + testing.expect_value(t, len(result), 6) + testing.expect_value(t, result[0], 0x4F60) + testing.expect_value(t, result[1], 0x597D) + testing.expect_value(t, result[2], 0xFF0C) + testing.expect_value(t, result[3], 0x4E16) + testing.expect_value(t, result[4], 0x754C) + testing.expect_value(t, result[5], 0xFF01) + + reset_buffer(buf[:]) + result = win32.utf8_to_utf16_buf(buf[:4], "Hello") + // Buffer too short. + testing.expect(t, result == nil) + + reset_buffer(buf[:]) + result = win32.utf8_to_utf16_buf(buf[:], "") + // Valid, but indistinguishable from an error. + testing.expect_value(t, len(result), 0) + + reset_buffer(buf[:]) + result = win32.utf8_to_utf16_buf(buf[:0], "Hello") + // Buffer too short. + testing.expect(t, result == nil) +} + +@(test) +utf8_to_wstring_buf_test :: proc(t : ^testing.T) { + buf : [100]u16 = --- + // Test everything with a dirty buffer! + reset_buffer :: proc(buf : []u16) { + for i in 0 ..< len(buf) { + buf[i] = cast(u16)(i + 1) + } + } + + result : win32.wstring + + reset_buffer(buf[:]) + result = win32.utf8_to_wstring_buf(buf[:], "Hello\x00, World!") + testing.expect(t, result != nil) + testing.expect_value(t, buf[13], '!') + testing.expect_value(t, buf[14], 0) + + reset_buffer(buf[:]) + result = win32.utf8_to_wstring_buf(buf[:], "H\x00\x00") + testing.expect(t, result != nil) + testing.expect_value(t, buf[1], 0) + + reset_buffer(buf[:]) + result = win32.utf8_to_wstring_buf(buf[:], "你好,世界!") + testing.expect(t, result != nil) + testing.expect_value(t, buf[0], 0x4F60) + testing.expect_value(t, buf[1], 0x597D) + testing.expect_value(t, buf[2], 0xFF0C) + testing.expect_value(t, buf[3], 0x4E16) + testing.expect_value(t, buf[4], 0x754C) + testing.expect_value(t, buf[5], 0xFF01) + testing.expect_value(t, buf[6], 0) + + reset_buffer(buf[:]) + result = win32.utf8_to_wstring_buf(buf[:5], "Hello") + // Buffer too short. + testing.expect_value(t, result, nil) + + reset_buffer(buf[:]) + result = win32.utf8_to_wstring_buf(buf[:6], "Hello") + // Buffer *just* long enough. + testing.expect(t, result != nil) + testing.expect_value(t, buf[4], 'o') + testing.expect_value(t, buf[5], 0) + + reset_buffer(buf[:]) + result = win32.utf8_to_wstring_buf(buf[:], "") + // Valid, and distinguishable from an error. + testing.expect(t, result != nil) + testing.expect_value(t, buf[0], 0) + + reset_buffer(buf[:]) + result = win32.utf8_to_wstring_buf(buf[:0], "Hello") + // Buffer too short. + testing.expect(t, result == nil) +} + +// Custom allocator proc that always returns dirty (non-zeroed) memory. +dirty_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode, + size, alignment: int, + old_memory: rawptr, old_size: int, + location: runtime.Source_Code_Location = #caller_location) -> ([]byte, runtime.Allocator_Error) { + real_allocator := cast(^runtime.Allocator)allocator_data + bytes, error := real_allocator.procedure(real_allocator.data, mode, + size, alignment, + old_memory, old_size, + location) + if error == .None { + for i in 0 ..< len(bytes) { + // This will yield a 0 byte on overflow, but that does not matter in this test suite. + bytes[i] = cast(byte)(i + 1) + } + } + return bytes, error +} + +@(test) +utf8_to_utf16_alloc_test :: proc(t : ^testing.T) { + // We want to ensure that everything works with dirty + // (non-zeroed) memory returned from the allocator. + real_allocator := context.temp_allocator + allocator := runtime.Allocator { + procedure = dirty_allocator_proc, + data = cast(rawptr)&real_allocator, + } + + // Test the dirty allocator. + allocator_test_slice := make([]u8, 100, allocator) + testing.expect_value(t, len(allocator_test_slice), 100) + for i in 0 ..< len(allocator_test_slice) { + testing.expect_value(t, allocator_test_slice[i], cast(u8)(i + 1)) + } + + result : []u16 + + result = win32.utf8_to_utf16_alloc("Hello\x00, World!", allocator) + testing.expect_value(t, len(result), 14) + testing.expect_value(t, result[4], 'o') + testing.expect_value(t, result[5], 0) + testing.expect_value(t, result[6], ',') + testing.expect_value(t, result[13], '!') + + result = win32.utf8_to_utf16_alloc("H\x00\x00", allocator) + testing.expect_value(t, len(result), 3) + testing.expect_value(t, result[1], 0) + testing.expect_value(t, result[2], 0) + + result = win32.utf8_to_utf16_alloc("你好,世界!", allocator) + testing.expect_value(t, len(result), 6) + testing.expect_value(t, result[0], 0x4F60) + testing.expect_value(t, result[1], 0x597D) + testing.expect_value(t, result[2], 0xFF0C) + testing.expect_value(t, result[3], 0x4E16) + testing.expect_value(t, result[4], 0x754C) + testing.expect_value(t, result[5], 0xFF01) + + result = win32.utf8_to_utf16_alloc("", allocator) + // Valid, but indistinguishable from an error. + testing.expect_value(t, len(result), 0) +} + +@(test) +utf8_to_wstring_alloc_test :: proc(t : ^testing.T) { + // We want to ensure that everything works with dirty + // (non-zeroed) memory returned from the allocator. + backing_allocator := context.temp_allocator + allocator := runtime.Allocator { + procedure = dirty_allocator_proc, + data = cast(rawptr)&backing_allocator, + } + + result : win32.wstring + buf : [^]u16 + + result = win32.utf8_to_wstring_alloc("Hello\x00, World!", allocator) + buf = transmute([^]u16)result + testing.expect(t, result != nil) + testing.expect_value(t, buf[4], 'o') + testing.expect_value(t, buf[5], 0) + testing.expect_value(t, buf[6], ',') + testing.expect_value(t, buf[13], '!') + testing.expect_value(t, buf[14], 0) + + result = win32.utf8_to_wstring_alloc("H\x00\x00", allocator) + buf = transmute([^]u16)result + testing.expect(t, result != nil) + testing.expect_value(t, buf[1], 0) + + result = win32.utf8_to_wstring_alloc("你好,世界!", allocator) + buf = transmute([^]u16)result + testing.expect(t, result != nil) + testing.expect_value(t, buf[0], 0x4F60) + testing.expect_value(t, buf[1], 0x597D) + testing.expect_value(t, buf[2], 0xFF0C) + testing.expect_value(t, buf[3], 0x4E16) + testing.expect_value(t, buf[4], 0x754C) + testing.expect_value(t, buf[5], 0xFF01) + testing.expect_value(t, buf[6], 0) + + result = win32.utf8_to_wstring_alloc("", allocator) + buf = transmute([^]u16)result + // Valid, and distinguishable from an error. + testing.expect(t, result != nil) + testing.expect_value(t, buf[0], 0) +} diff --git a/tests/core/text/regex/test_core_text_regex.odin b/tests/core/text/regex/test_core_text_regex.odin index 8369444b9..732a3d321 100644 --- a/tests/core/text/regex/test_core_text_regex.odin +++ b/tests/core/text/regex/test_core_text_regex.odin @@ -564,6 +564,10 @@ test_non_word_boundaries :: proc(t: ^testing.T) { EXPR :: `.+\B` check_expression(t, EXPR, "abc", "ab") } + { + EXPR :: `\B'` + check_expression(t, EXPR, "'", "'") + } } @test @@ -1270,6 +1274,16 @@ iterator_vectors := []Iterator_Test{ {pos = {{0, 2}}, groups = {"a\n"}}, }, }, + // https://github.com/odin-lang/Odin/issues/6323 + // Test `\b` in iterator + { + "can, can't, 'can't'", `\b[a-z0-9']+\b`, {}, + { + {pos = {{0, 3}}, groups = {"can"}}, + {pos = {{5, 10}}, groups = {"can't"}}, + {pos = {{13, 18}}, groups = {"can't"}}, + }, + }, } @test diff --git a/tests/core/time/test_core_time.odin b/tests/core/time/test_core_time.odin index cd2b19fb8..d1f83c0dc 100644 --- a/tests/core/time/test_core_time.odin +++ b/tests/core/time/test_core_time.odin @@ -2,6 +2,7 @@ package test_core_time import "core:testing" import "core:time" +@(require) import "core:log" import dt "core:time/datetime" import tz "core:time/timezone" @@ -15,8 +16,8 @@ test_time_and_date_formatting :: proc(t: ^testing.T) { d := time.Duration(now._nsec) testing.expect_value(t, time.to_string_hms (now, buf[:]), "00:12:44") - testing.expect_value(t, time.to_string_hms_12 (now, buf[:]), "00:12:44 am") - testing.expect_value(t, time.to_string_hms_12 (now, buf[:], {"㏂", "㏘"}), "00:12:44㏂") + testing.expect_value(t, time.to_string_hms_12 (now, buf[:]), "12:12:44 am") + testing.expect_value(t, time.to_string_hms_12 (now, buf[:], {"㏂", "㏘"}), "12:12:44㏂") testing.expect_value(t, time.to_string_hms (d, buf[:]), "00:12:44") testing.expect_value(t, time.to_string_yyyy_mm_dd(now, buf[:]), "1677-09-21") @@ -364,9 +365,10 @@ test_convert_timezone_roundtrip :: proc(t: ^testing.T) { std_dt, _ := dt.components_to_datetime(2024, 11, 4, 23, 47, 0) local_tz, local_load_ok := tz.region_load("local") - testing.expectf(t, local_load_ok, "Failed to load local timezone") defer tz.region_destroy(local_tz) + testing.expectf(t, local_load_ok, "Failed to load local timezone") + edm_tz, edm_load_ok := tz.region_load("America/Edmonton") testing.expectf(t, edm_load_ok, "Failed to load America/Edmonton timezone") defer tz.region_destroy(edm_tz) diff --git a/tests/documentation/documentation_tester.odin b/tests/documentation/documentation_tester.odin index 7b125d4e4..be59d9b4d 100644 --- a/tests/documentation/documentation_tester.odin +++ b/tests/documentation/documentation_tester.odin @@ -1,12 +1,11 @@ package documentation_tester -import "core:os" -import "core:io" -import "core:fmt" -import "core:strings" -import "core:odin/ast" -import "core:odin/parser" -import "core:c/libc" +import "core:os" +import "core:fmt" +import "core:strings" +import "core:odin/ast" +import "core:odin/parser" +import "core:c/libc" import doc "core:odin/doc-format" Example_Test :: struct { @@ -63,10 +62,11 @@ main :: proc() { errorf("expected path to odin executable") } g_path_to_odin = os.args[1] - data, ok := os.read_entire_file("all.odin-doc") - if !ok { + data, data_err := os.read_entire_file("all.odin-doc", context.allocator) + if data_err != nil { errorf("unable to read file: all.odin-doc") } + defer delete(data) err: doc.Reader_Error g_header, err = doc.read_from_bytes(data) switch err { @@ -257,8 +257,8 @@ find_and_add_examples :: proc(docs: string, package_name: string, entity_name: s write_test_suite :: proc(example_tests: []Example_Test) { TEST_SUITE_DIRECTORY :: "verify" - os.remove_directory(TEST_SUITE_DIRECTORY) - os.make_directory(TEST_SUITE_DIRECTORY) + os.remove_all(TEST_SUITE_DIRECTORY) + os.mkdir(TEST_SUITE_DIRECTORY) example_build := strings.builder_make() test_runner := strings.builder_make() @@ -276,9 +276,11 @@ import "core:sync" import "base:intrinsics" @(private="file") -_read_pipe: os.Handle +_read_pipe: ^os.File @(private="file") -_write_pipe: os.Handle +_write_pipe: ^os.File +@(private="file") +_old_stdout: ^os.File @(private="file") _pipe_reader_semaphore: sync.Sema @(private="file") @@ -286,20 +288,20 @@ _out_data: string @(private="file") _out_buffer: [mem.Megabyte]byte @(private="file") -_bad_test_found: bool +_bad_count: int +@(private="file") +_good_count: int @(private="file") _spawn_pipe_reader :: proc() { thread.run(proc() { - stream := os.stream_from_handle(_read_pipe) - reader := io.to_reader(stream) sync.post(&_pipe_reader_semaphore) // notify thread is ready for { n_read := 0 read_to_null_byte := 0 finished_reading := false for ! finished_reading { - just_read, err := io.read(reader, _out_buffer[n_read:], &n_read); if err != .None { + just_read, err := io.read(os.to_stream(_read_pipe), _out_buffer[n_read:], &n_read); if err != .None { panic("We got an IO error!") } for b in _out_buffer[n_read - just_read: n_read] { @@ -328,11 +330,14 @@ _check :: proc(test_name: string, expected: string) { if expected != output { fmt.eprintf("Test %q got unexpected output:\n%q\n", test_name, output) fmt.eprintf("Expected:\n%q\n", expected) - _bad_test_found = true + _bad_count += 1 + } else { + _good_count += 1 } } main :: proc() { + _old_stdout = os.stdout _read_pipe, _write_pipe, _ = os.pipe() os.stdout = _write_pipe _spawn_pipe_reader() @@ -445,24 +450,19 @@ main :: proc() { continue } defer os.close(test_file_handle) - stream := os.stream_from_handle(test_file_handle) - writer, ok := io.to_writer(stream); if ! ok { - fmt.eprintf("We could not make the writer for the path %q\n", save_path) - g_bad_doc = true - continue - } - fmt.wprintf(writer, "%v%v_%v", code_string[:index_of_proc_name], test.package_name, code_string[index_of_proc_name:]) + fmt.wprintf(os.to_stream(test_file_handle), "%v%v_%v", code_string[:index_of_proc_name], test.package_name, code_string[index_of_proc_name:]) fmt.println("Done") } strings.write_string(&test_runner, ` - if _bad_test_found { + fmt.wprintfln(os.to_stream(_old_stdout), "Passes: %v. Fails: %v", _good_count, _bad_count) + if _bad_count > 0 { fmt.eprintln("One or more tests failed") os.exit(1) } }`) - os.write_entire_file("verify/main.odin", transmute([]byte)strings.to_string(test_runner)) + _ = os.write_entire_file("verify/main.odin", transmute([]byte)strings.to_string(test_runner)) } run_test_suite :: proc() -> bool { diff --git a/tests/internal/test_fixed_capacity_dynamic_array.odin b/tests/internal/test_fixed_capacity_dynamic_array.odin new file mode 100644 index 000000000..49cf3a8f9 --- /dev/null +++ b/tests/internal/test_fixed_capacity_dynamic_array.odin @@ -0,0 +1,93 @@ +package test_internal + +import "core:testing" + +@(private="file") +slice_equal :: proc(a, b: []int) -> bool { + if len(a) != len(b) { + return false + } + + for a, i in a { + if b[i] != a { + return false + } + } + return true +} + + +@(test) +test_fixed_capacity_dynamic_array_removes :: proc(t: ^testing.T) { + array: [dynamic; 10]int + append(&array, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9) + + ordered_remove(&array, 0) + testing.expect(t, slice_equal(array[:], []int { 1, 2, 3, 4, 5, 6, 7, 8, 9 })) + ordered_remove(&array, 5) + testing.expect(t, slice_equal(array[:], []int { 1, 2, 3, 4, 5, 7, 8, 9 })) + ordered_remove(&array, 6) + testing.expect(t, slice_equal(array[:], []int { 1, 2, 3, 4, 5, 7, 9 })) + unordered_remove(&array, 0) + testing.expect(t, slice_equal(array[:], []int { 9, 2, 3, 4, 5, 7 })) + unordered_remove(&array, 2) + testing.expect(t, slice_equal(array[:], []int { 9, 2, 7, 4, 5 })) + unordered_remove(&array, 4) + testing.expect(t, slice_equal(array[:], []int { 9, 2, 7, 4 })) +} + +@(test) +test_fixed_capacity_dynamic_array_inject_at :: proc(t: ^testing.T) { + array: [dynamic; 13]int + append(&array, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9) + + testing.expect(t, inject_at(&array, 0, 0), "Expected to be able to inject into fixed capacity dynamic array") + testing.expect(t, slice_equal(array[:], []int { 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 })) + testing.expect(t, inject_at(&array, 0, 5), "Expected to be able to inject into fixed capacity dynamic array") + testing.expect(t, slice_equal(array[:], []int { 5, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 })) + testing.expect(t, inject_at(&array, len(array), 0), "Expected to be able to inject into fixed capacity dynamic array") + testing.expect(t, slice_equal(array[:], []int { 5, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 })) +} + +@(test) +test_fixed_capacity_dynamic_array_push_back_elems :: proc(t: ^testing.T) { + array: [dynamic; 2]int + testing.expect(t, slice_equal(array[:], []int { })) + testing.expect(t, append(&array, 0) == 1, "Expected to be able to append to empty fixed capacity dynamic array") + testing.expect(t, slice_equal(array[:], []int { 0 })) + testing.expect(t, append(&array, 1) == 1, "Expected to be able to append to fixed capacity dynamic array") + testing.expect(t, slice_equal(array[:], []int { 0, 1 })) + testing.expect(t, append(&array, 1, 2) == 0, "Expected to fail appending multiple elements beyond capacity of fixed capacity dynamic array") + clear(&array) + testing.expect(t, append(&array, 1) == 1, "Expected to be able to append to fixed capacity dynamic array") + testing.expect(t, append(&array, 2) == 1, "Expected to be able to append to fixed capacity dynamic array") + testing.expect(t, append(&array, 1) != 1, "Expected to fail appending to full fixed capacity dynamic array") + testing.expect(t, append(&array, 1, 2) != 2, "Expected to fail appending multiple elements to full fixed capacity dynamic array") + clear(&array) + testing.expect(t, slice_equal(array[:], []int { })) + testing.expect(t, append(&array, 1, 2, 3) != 3, "Expected to fail appending multiple elements to empty fixed capacity dynamic array") + testing.expect(t, slice_equal(array[:], []int { 1, 2 })) + clear(&array) + testing.expect(t, append(&array, 1, 2) == 2, "Expected to be able to append multiple elements to empty fixed capacity dynamic array") + testing.expect(t, slice_equal(array[:], []int { 1, 2 })) +} + +@(test) +test_fixed_capacity_dynamic_array_resize :: proc(t: ^testing.T) { + array: [dynamic; 4]int + + for i in 0..<4 { + append(&array, i+1) + } + testing.expect(t, slice_equal(array[:], []int{1, 2, 3, 4}), "Expected to initialize the array with 1, 2, 3, 4") + + clear(&array) + testing.expect(t, slice_equal(array[:], []int{}), "Expected to clear the array") + + non_zero_resize(&array, 4) + testing.expect(t, slice_equal(array[:], []int{1, 2, 3, 4}), "Expected non_zero_resize to set length 4 with previous values") + + clear(&array) + resize(&array, 4) + testing.expect(t, slice_equal(array[:], []int{0, 0, 0, 0}), "Expected resize to set length 4 with zeroed values") +} diff --git a/tests/internal/test_imported_proc_groups.odin b/tests/internal/test_imported_proc_groups.odin new file mode 100644 index 000000000..e91af4bf5 --- /dev/null +++ b/tests/internal/test_imported_proc_groups.odin @@ -0,0 +1,11 @@ +package test_internal + +import "core:testing" +import "test_imported_proc_groups" + +// https://github.com/odin-lang/Odin/pull/6119 +@test +test_use_imported_proc_group_as_argument :: proc(t: ^testing.T) { + use_proc :: proc(proc()) { } + use_proc(test_imported_proc_groups.proc_group) +} diff --git a/tests/internal/test_imported_proc_groups/proc_group.odin b/tests/internal/test_imported_proc_groups/proc_group.odin new file mode 100644 index 000000000..59519ab9c --- /dev/null +++ b/tests/internal/test_imported_proc_groups/proc_group.odin @@ -0,0 +1,4 @@ +package test_imported_proc_groups + +proc_group :: proc{empty_proc} +empty_proc :: proc() { } diff --git a/tests/issues/run.bat b/tests/issues/run.bat index bbd7cbc90..3db9d48c2 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -21,11 +21,17 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style -ignore-unused ..\..\..\odin test ..\test_issue_4210.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_4364.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_4584.odin %COMMON% || exit /b +..\..\..\odin build ..\test_issue_2395.odin %COMMON% 2>&1 | find /c "Error:" | findstr /x "2" || exit /b ..\..\..\odin build ..\test_issue_5043.odin %COMMON% || exit /b ..\..\..\odin build ..\test_issue_5097.odin %COMMON% || exit /b ..\..\..\odin build ..\test_issue_5097-2.odin %COMMON% || exit /b ..\..\..\odin build ..\test_issue_5265.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_5699.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_6068.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_6101.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_6165.odin %COMMON% || exit /b +..\..\..\odin build ..\test_issue_6240.odin %COMMON% 2>&1 | find /c "Error:" | findstr /x "3" || exit /b +..\..\..\odin build ..\test_issue_6401.odin %COMMON% 2>&1 | find /c "Error:" | findstr /x "3" || exit /b @echo off diff --git a/tests/issues/run.sh b/tests/issues/run.sh index a9a4bb88d..01e6a6a28 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -33,7 +33,22 @@ $ODIN build ../test_issue_5097.odin $COMMON $ODIN build ../test_issue_5097-2.odin $COMMON $ODIN build ../test_issue_5265.odin $COMMON $ODIN test ../test_issue_5699.odin $COMMON - +$ODIN test ../test_issue_6068.odin $COMMON +$ODIN test ../test_issue_6101.odin $COMMON +$ODIN test ../test_issue_6165.odin $COMMON +$ODIN test ../test_issue_6396.odin $COMMON +if [[ $($ODIN build ../test_issue_6240.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 3 ]] ; then + echo "SUCCESSFUL 1/1" +else + echo "SUCCESSFUL 0/1" + exit 1 +fi +if [[ $($ODIN build ../test_issue_6401.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 3 ]] ; then + echo "SUCCESSFUL 1/1" +else + echo "SUCCESSFUL 0/1" + exit 1 +fi set +x popd diff --git a/tests/issues/test_issue_6068.odin b/tests/issues/test_issue_6068.odin new file mode 100644 index 000000000..88a21ee27 --- /dev/null +++ b/tests/issues/test_issue_6068.odin @@ -0,0 +1,92 @@ +// Tests issue #6068 https://github.com/odin-lang/Odin/issues/6068 +package test_issues + +import "core:testing" + +@test +test_issue_6068 :: proc(t: ^testing.T) { + { + check_be : i128be = -1 + check_le : i128le = -1 + value := -1 + reverse := i128be(value) + + // test variable + testing.expect(t, i128be(value) == check_be) + testing.expect(t, i128be(-1) == check_be) + testing.expect(t, cast(i128be)value == check_be) + testing.expect(t, cast(i128be)-1 == check_be) + testing.expect(t, i128be(int(-1)) == check_be) + testing.expect(t, cast(i128be)int(-1) == check_be) + testing.expect(t, i128le(value) == check_le) + testing.expect(t, i128le(-1) == check_le) + testing.expect(t, cast(i128le)value == check_le) + testing.expect(t, cast(i128le)-1 == check_le) + testing.expect(t, i128le(int(-1)) == check_le) + testing.expect(t, cast(i128le)int(-1) == check_le) + testing.expect(t, i128le(reverse) == check_le) + testing.expect(t, cast(i128le)reverse == check_le) + + // test literal + testing.expect(t, i128be(value) == -1) + testing.expect(t, i128be(-1) == -1) + testing.expect(t, cast(i128be)value == -1) + testing.expect(t, cast(i128be)-1 == -1) + testing.expect(t, i128be(int(-1)) == -1) + testing.expect(t, cast(i128be)int(-1) == -1) + testing.expect(t, i128le(value) == -1) + testing.expect(t, i128le(-1) == -1) + testing.expect(t, cast(i128le)value == -1) + testing.expect(t, cast(i128le)-1 == -1) + testing.expect(t, i128le(int(-1)) == -1) + testing.expect(t, cast(i128le)int(-1) == -1) + testing.expect(t, i128le(reverse) == -1) + testing.expect(t, cast(i128le)reverse == -1) + } + + // NOTE(ske): [llvm_backend_const.cpp:lb_big_int_to_llvm] + // floats behaved wonky when I tested because I forgot to sign extend whole + // rop so I added more tests here to be safe + { + check_be : f64be = -1.234 + check_le : f64le = -1.234 + value : f64 = -1.234 + reverse := f64be(value) + + // test variable + testing.expect(t, f64be(value) == check_be) + testing.expect(t, f64be(-1.234) == check_be) + testing.expect(t, cast(f64be)value == check_be) + testing.expect(t, cast(f64be)-1.234 == check_be) + testing.expect(t, f64be(f64(-1.234)) == check_be) + testing.expect(t, cast(f64be)f64(-1.234) == check_be) + testing.expect(t, f64le(value) == check_le) + testing.expect(t, f64le(-1.234) == check_le) + testing.expect(t, cast(f64le)value == check_le) + testing.expect(t, cast(f64le)-1.234 == check_le) + testing.expect(t, f64le(f64(-1.234)) == check_le) + testing.expect(t, cast(f64le)f64(-1.234) == check_le) + testing.expect(t, f64le(reverse) == check_le) + testing.expect(t, cast(f64le)reverse == check_le) + + // test literal + testing.expect(t, f64be(value) == -1.234) + testing.expect(t, f64be(-1.234) == -1.234) + testing.expect(t, cast(f64be)value == -1.234) + testing.expect(t, cast(f64be)-1.234 == -1.234) + testing.expect(t, f64be(f64(-1.234)) == -1.234) + testing.expect(t, cast(f64be)f64(-1.234) == -1.234) + testing.expect(t, f64le(value) == -1.234) + testing.expect(t, f64le(-1.234) == -1.234) + testing.expect(t, cast(f64le)value == -1.234) + testing.expect(t, cast(f64le)-1.234 == -1.234) + testing.expect(t, f64le(f64(-1.234)) == -1.234) + testing.expect(t, cast(f64le)f64(-1.234) == -1.234) + testing.expect(t, f64le(reverse) == -1.234) + testing.expect(t, cast(f64le)reverse == -1.234) + } + + testing.expect(t, i64be(-1) + i64be(1) == 0) + testing.expect(t, i64le(-1) + i64le(i64be(1)) == 0) + testing.expect(t, i64be(-7) * i64be(7) == -49) +} diff --git a/tests/issues/test_issue_6101.odin b/tests/issues/test_issue_6101.odin new file mode 100644 index 000000000..9f24ade52 --- /dev/null +++ b/tests/issues/test_issue_6101.odin @@ -0,0 +1,23 @@ +// Tests issue #6101 https://github.com/odin-lang/Odin/issues/6101 +package test_issues + +import "core:testing" + +@(test) +test_issue_6101_bmp :: proc(t: ^testing.T) { + s := string16("\u732b") + testing.expect_value(t, len(s), 1) + + u := transmute([]u16)s + testing.expect_value(t, u[0], 0x732b) +} + +@(test) +test_issue_6101_non_bmp :: proc(t: ^testing.T) { + s := string16("\U0001F63A") + testing.expect_value(t, len(s), 2) + + u := transmute([]u16)s + testing.expect_value(t, u[0], 0xD83D) + testing.expect_value(t, u[1], 0xDE3A) +} diff --git a/tests/issues/test_issue_6165.odin b/tests/issues/test_issue_6165.odin new file mode 100644 index 000000000..b16995f0e --- /dev/null +++ b/tests/issues/test_issue_6165.odin @@ -0,0 +1,13 @@ +// Tests issue #6165 https://github.com/odin-lang/Odin/issues/6165 +package test_issues + +import "core:testing" + +@(test) +test_issue_6165 :: proc(t: ^testing.T) { + TXT :: #load(ODIN_ROOT + "LICENSE") + + // We don't really care about the length. The test is whether this compiles, or + // if the compiler says it can't find the file we know to exist. + assert(len(TXT) > 0) +} \ No newline at end of file diff --git a/tests/issues/test_issue_6240.odin b/tests/issues/test_issue_6240.odin new file mode 100644 index 000000000..a56f44f33 --- /dev/null +++ b/tests/issues/test_issue_6240.odin @@ -0,0 +1,14 @@ +// Tests issue #6240 https://github.com/odin-lang/Odin/issues/6240 +package test_issues + +// should error - N=10 does not match bit_set range 0..<5 +foo :: proc($N: int, b: $B/bit_set[0 ..< N]) {} + +// should error without segfaulting - undefined identifier in bit_set range +bar :: proc(b: $B/bit_set[0 ..< asdf]) {} + +main :: proc() { + b: bit_set[0 ..< 5] + foo(10, b) + bar(bit_set[0 ..< 1]{}) +} diff --git a/tests/issues/test_issue_6396.odin b/tests/issues/test_issue_6396.odin new file mode 100644 index 000000000..5a0e7527c --- /dev/null +++ b/tests/issues/test_issue_6396.odin @@ -0,0 +1,23 @@ +// Tests issue #6396 https://github.com/odin-lang/Odin/issues/6396 +package test_issues + +import "core:testing" + +Issue6396_Full_Width_Field :: bit_field u32 { + a: u32 | 32, +} + +@test +test_issue_6396_full_width_bit_field_literal :: proc(t: ^testing.T) { + f0: Issue6396_Full_Width_Field = {a = 7} + testing.expect_value(t, f0.a, u32(7)) + + f0 = {a = 3} + testing.expect_value(t, f0.a, u32(3)) + + f0 = Issue6396_Full_Width_Field{a = 11} + testing.expect_value(t, f0.a, u32(11)) + + f0.a = 12 + testing.expect_value(t, f0.a, u32(12)) +} diff --git a/tests/issues/test_issue_6401.odin b/tests/issues/test_issue_6401.odin new file mode 100644 index 000000000..0f7cd58b6 --- /dev/null +++ b/tests/issues/test_issue_6401.odin @@ -0,0 +1,16 @@ +// Tests issue #6401 https://github.com/odin-lang/Odin/issues/6401 +package test_issues + +Wrapper :: struct(T: typeid) { + value: T, +} + +A :: struct { + value: Wrapper(B), +} + +B :: struct { + value: A, +} + +main :: proc() {} diff --git a/vendor/OpenGL/helpers.odin b/vendor/OpenGL/helpers.odin index 84e3eae81..9c9c74d09 100644 --- a/vendor/OpenGL/helpers.odin +++ b/vendor/OpenGL/helpers.odin @@ -3,10 +3,11 @@ package vendor_gl // Helper for loading shaders into a program -import "core:os" -import "core:fmt" -import "core:strings" -import "base:runtime" +import "core:os" +import "core:fmt" +import "core:strings" +@(require) import "core:time" +import "base:runtime" _ :: fmt _ :: runtime @@ -150,7 +151,10 @@ create_and_link_program :: proc(shader_ids: []u32, binary_retrievable := false) } load_compute_file :: proc(filename: string, binary_retrievable := false) -> (program_id: u32, ok: bool) { - cs_data := os.read_entire_file(filename) or_return + cs_data, cs_data_err := os.read_entire_file(filename, context.allocator) + if cs_data_err != nil { + return 0, false + } defer delete(cs_data) // Create the shaders @@ -165,10 +169,16 @@ load_compute_source :: proc(cs_data: string, binary_retrievable := false) -> (pr } load_shaders_file :: proc(vs_filename, fs_filename: string, binary_retrievable := false) -> (program_id: u32, ok: bool) { - vs_data := os.read_entire_file(vs_filename) or_return + vs_data, vs_data_err := os.read_entire_file(vs_filename, context.allocator) + if vs_data_err != nil { + return 0, false + } defer delete(vs_data) - fs_data := os.read_entire_file(fs_filename) or_return + fs_data, fs_data_err := os.read_entire_file(fs_filename, context.allocator) + if fs_data_err != nil { + return 0, false + } defer delete(fs_data) return load_shaders_source(string(vs_data), string(fs_data), binary_retrievable) @@ -192,14 +202,14 @@ when ODIN_OS == .Windows { update_shader_if_changed :: proc( vertex_name, fragment_name: string, program: u32, - last_vertex_time, last_fragment_time: os.File_Time, + last_vertex_time, last_fragment_time: time.Time, ) -> ( old_program: u32, - current_vertex_time, current_fragment_time: os.File_Time, + current_vertex_time, current_fragment_time: time.Time, updated: bool, ) { - current_vertex_time, _ = os.last_write_time_by_name(vertex_name) - current_fragment_time, _ = os.last_write_time_by_name(fragment_name) + current_vertex_time, _ = os.modification_time_by_path(vertex_name) + current_fragment_time, _ = os.modification_time_by_path(fragment_name) old_program = program if current_vertex_time != last_vertex_time || current_fragment_time != last_fragment_time { @@ -220,13 +230,13 @@ when ODIN_OS == .Windows { update_shader_if_changed_compute :: proc( compute_name: string, program: u32, - last_compute_time: os.File_Time, + last_compute_time: time.Time, ) -> ( old_program: u32, - current_compute_time: os.File_Time, + current_compute_time: time.Time, updated: bool, ) { - current_compute_time, _ = os.last_write_time_by_name(compute_name) + current_compute_time, _ = os.modification_time_by_path(compute_name) old_program = program if current_compute_time != last_compute_time { diff --git a/vendor/box2d/box2d.odin b/vendor/box2d/box2d.odin index ad4670110..2cdfea191 100644 --- a/vendor/box2d/box2d.odin +++ b/vendor/box2d/box2d.odin @@ -4,6 +4,8 @@ package vendor_box2d import "base:intrinsics" import "core:c" +_ :: intrinsics + when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 { @(private) VECTOR_EXT :: "_simd" when #config(VENDOR_BOX2D_ENABLE_SIMD128, intrinsics.has_target_feature("simd128")) else "" } else { @@ -331,7 +333,7 @@ MakeOffsetProxy :: proc "c" (points: []Vec2, radius: f32, position: Vec2, rotati @(link_prefix="b2", default_calling_convention="c", require_results) foreign lib { // Perform a linear shape cast of shape B moving and shape A fixed. Determines the hit point, normal, and translation fraction. - // You may optionally supply an array to hold debug data. + // Initially touching shapes are treated as a miss. ShapeCast :: proc(#by_ptr input: ShapeCastPairInput) -> CastOutput --- // Evaluate the transform sweep at a specific time. @@ -481,12 +483,12 @@ foreign lib { */ @(require_results) -SolvePlanes :: proc(position: Vec2, planes: []CollisionPlane) -> PlaneSolverResult { +SolvePlanes :: proc(targetDelta: Vec2, planes: []CollisionPlane) -> PlaneSolverResult { foreign lib { - b2SolvePlanes :: proc "c" (position: Vec2, planes: [^]CollisionPlane, count: i32) -> PlaneSolverResult --- + b2SolvePlanes :: proc "c" (targetDelta: Vec2, planes: [^]CollisionPlane, count: i32) -> PlaneSolverResult --- } - return b2SolvePlanes(position, raw_data(planes), i32(len(planes))) + return b2SolvePlanes(targetDelta, raw_data(planes), i32(len(planes))) } @(require_results) @@ -550,7 +552,6 @@ foreign lib { // Cast a ray into the world to collect shapes in the path of the ray. // Your callback function controls whether you get the closest point, any point, or n-points. - // The ray-cast ignores shapes that contain the starting point. // @note The callback function may receive shapes in any order // @param worldId The world to cast the ray against // @param origin The start point of the ray @@ -561,7 +562,7 @@ foreign lib { // @return traversal performance counters World_CastRay :: proc(worldId: WorldId, origin: Vec2, translation: Vec2, filter: QueryFilter, fcn: CastResultFcn, ctx: rawptr) -> TreeStats --- - // Cast a ray into the world to collect the closest hit. This is a convenience function. + // Cast a ray into the world to collect the closest hit. This is a convenience function. Ignores initial overlap. // This is less general than b2World_CastRay() and does not allow for custom filtering. World_CastRayClosest :: proc(worldId: WorldId, origin: Vec2, translation: Vec2, filter: QueryFilter) -> RayResult --- @@ -637,13 +638,6 @@ foreign lib { // @note Advanced feature World_SetContactTuning :: proc(worldId: WorldId, hertz: f32, dampingRatio: f32, pushSpeed: f32) --- - // Adjust joint tuning parameters - // @param worldId The world id - // @param hertz The contact stiffness (cycles per second) - // @param dampingRatio The contact bounciness with 1 being critical damping (non-dimensional) - // @note Advanced feature - World_SetJointTuning :: proc(worldId: WorldId, hertz: f32, dampingRatio: f32) --- - // Set the maximum linear speed. Usually in m/s. World_SetMaximumLinearSpeed :: proc(worldId: WorldId, maximumLinearSpeed: f32) --- @@ -771,6 +765,7 @@ foreign lib { // Set the velocity to reach the given transform after a given time step. // The result will be close but maybe not exact. This is meant for kinematic bodies. + // The target is not applied if the velocity would be below the sleep threshold. // This will automatically wake the body if asleep. Body_SetTargetTransform :: proc(bodyId: BodyId, target: Transform, timeStep: f32) --- @@ -778,7 +773,7 @@ foreign lib { Body_GetLocalPointVelocity :: proc(bodyId: BodyId, localPoint: Vec2) -> Vec2 --- // Get the linear velocity of a world point attached to a body. Usually in meters per second. - GetWorldPointVelocity :: proc(bodyId: BodyId, worldPoint: Vec2) -> Vec2 --- + Body_GetWorldPointVelocity :: proc(bodyId: BodyId, worldPoint: Vec2) -> Vec2 --- // Apply a force at a world point. If the force is not applied at the center of mass, // it will generate a torque and affect the angular velocity. This optionally wakes up the body. @@ -1068,6 +1063,12 @@ foreign lib { // Get the shape material identifier Shape_GetMaterial :: proc(shapeId: ShapeId) -> c.int --- + // Set the shape surface material + Shape_SetSurfaceMaterial :: proc(shapeId: ShapeId, surfaceMaterial: SurfaceMaterial) --- + + // Get the shape surface material + Shape_GetSurfaceMaterial :: proc(shapeId: ShapeId) -> SurfaceMaterial --- + // Get the shape filter Shape_GetFilter :: proc(shapeId: ShapeId) -> Filter --- @@ -1258,12 +1259,30 @@ foreign lib { // Get the world that owns this joint Joint_GetWorld :: proc(jointId: JointId) -> WorldId --- + // Set the local anchor on bodyA + Joint_SetLocalAnchorA :: proc(jointId: JointId, localAnchor: Vec2) --- + // Get the local anchor on bodyA Joint_GetLocalAnchorA :: proc(jointId: JointId) -> Vec2 --- + // Set the local anchor on bodyB + Joint_SetLocalAnchorB :: proc(jointId: JointId, localAnchor: Vec2) --- + // Get the local anchor on bodyB Joint_GetLocalAnchorB :: proc(jointId: JointId) -> Vec2 --- + // Get the joint reference angle in radians (revolute, prismatic, and weld) + Joint_GetReferenceAngle :: proc(jointId: JointId) -> f32 --- + + // Set the joint reference angle in radians, must be in [-pi,pi]. (revolute, prismatic, and weld) + Joint_SetReferenceAngle :: proc(jointId: JointId, angleInRadians: f32) --- + + // Set the local axis on bodyA (prismatic and wheel) + Joint_SetLocalAxisA :: proc(jointId: JointId, localAxis: Vec2) --- + + // Get the local axis on bodyA (prismatic and wheel) + Joint_GetLocalAxisA :: proc(jointId: JointId) -> Vec2 --- + // Toggle collision between connected bodies Joint_SetCollideConnected :: proc(jointId: JointId, shouldCollide: bool) --- @@ -1285,6 +1304,21 @@ foreign lib { // Get the current constraint torque for this joint. Usually in Newton * meters. Joint_GetConstraintTorque :: proc(jointId: JointId) -> f32 --- + // Get the current linear separation error for this joint. Does not consider admissible movement. Usually in meters. + Joint_GetLinearSeparation :: proc(jointId: JointId) -> f32 --- + + // Get the current angular separation error for this joint. Does not consider admissible movement. Usually in meters. + Joint_GetAngularSeparation :: proc(jointId: JointId) -> f32 --- + + // Get the joint constraint tuning. Advanced feature. + Joint_GetConstraintTuning :: proc(jointId: JointId, hertz: ^f32, dampingRatio: ^f32) --- + + // Set the joint constraint tuning. Advanced feature. + // @param jointId the joint + // @param hertz the stiffness in Hertz (cycles per second) + // @param dampingRatio the non-dimensional damping ratio (one for critical damping) + Joint_SetConstraintTuning :: proc(jointId: JointId, hertz: f32, dampingRatio: f32) --- + /** * @defgroup distance_joint Distance Joint * @brief Functions for the distance joint. @@ -1379,7 +1413,8 @@ foreign lib { // Get the motor joint linear offset target MotorJoint_GetLinearOffset :: proc(jointId: JointId) -> Vec2 --- - // Set the motor joint angular offset target in radians + // Set the motor joint angular offset target in radians. This angle will be unwound + // so the motor will drive along the shortest arc. MotorJoint_SetAngularOffset :: proc(jointId: JointId, angularOffset: f32) --- // Get the motor joint angular offset target in radians @@ -1415,31 +1450,37 @@ foreign lib { // Create a mouse joint // @see b2MouseJointDef for details - CreateMouseJoint :: proc(worldId: WorldId, #by_ptr def: MouseJointDef) -> JointId --- + CreateMouseJoint :: proc(worldId: WorldId, #by_ptr def: MouseJointDef) -> JointId --- // Set the mouse joint target - MouseJoint_SetTarget :: proc(jointId: JointId, target: Vec2) --- + MouseJoint_SetTarget :: proc(jointId: JointId, target: Vec2) --- // Get the mouse joint target - MouseJoint_GetTarget :: proc(jointId: JointId) -> Vec2 --- + MouseJoint_GetTarget :: proc(jointId: JointId) -> Vec2 --- // Set the mouse joint spring stiffness in Hertz - MouseJoint_SetSpringHertz :: proc(jointId: JointId, hertz: f32) --- + MouseJoint_SetSpringHertz :: proc(jointId: JointId, hertz: f32) --- // Get the mouse joint spring stiffness in Hertz - MouseJoint_GetSpringHertz :: proc(jointId: JointId) -> f32 --- + MouseJoint_GetSpringHertz :: proc(jointId: JointId) -> f32 --- // Set the mouse joint spring damping ratio, non-dimensional - MouseJoint_SetSpringDampingRatio :: proc(jointId: JointId, dampingRatio: f32) --- + MouseJoint_SetSpringDampingRatio :: proc(jointId: JointId, dampingRatio: f32) --- // Get the mouse joint damping ratio, non-dimensional - MouseJoint_GetSpringDampingRatio :: proc(jointId: JointId) -> f32 --- + MouseJoint_GetSpringDampingRatio :: proc(jointId: JointId) -> f32 --- + + // Set the prismatic joint sprint target angle, usually in meters + PrismaticJoint_SetTargetTranslation :: proc(jointId: JointId, translation: f32) --- + + // Get the prismatic joint sprint target translation, usually in meters + PrismaticJoint_GetTargetTranslation :: proc(jointId: JointId) -> f32 --- // Set the mouse joint maximum force, usually in newtons - MouseJoint_SetMaxForce :: proc(jointId: JointId, maxForce: f32) --- + MouseJoint_SetMaxForce :: proc(jointId: JointId, maxForce: f32) --- // Get the mouse joint maximum force, usually in newtons - MouseJoint_GetMaxForce :: proc(jointId: JointId) -> f32 --- + MouseJoint_GetMaxForce :: proc(jointId: JointId) -> f32 --- /**@}*/ @@ -1585,7 +1626,7 @@ foreign lib { RevoluteJoint_GetUpperLimit :: proc(jointId: JointId) -> f32 --- // Set the revolute joint limits in radians. It is expected that lower <= upper - // and that -0.95 * B2_PI <= lower && upper <= -0.95 * B2_PI. + // and that -0.99 * B2_PI <= lower && upper <= -0.99 * B2_PI. RevoluteJoint_SetLimits :: proc(jointId: JointId, lower, upper: f32) --- // Enable/disable a revolute joint motor @@ -1625,12 +1666,6 @@ foreign lib { // @see b2WeldJointDef for details CreateWeldJoint :: proc(worldId: WorldId, #by_ptr def: WeldJointDef) -> JointId --- - // Get the weld joint reference angle in radians - WeldJoint_GetReferenceAngle :: proc(jointId: JointId) -> f32 --- - - // Set the weld joint reference angle in radians, must be in [-pi,pi]. - WeldJoint_SetReferenceAngle :: proc(jointId: JointId, angleInRadians: f32) --- - // Set the weld joint linear stiffness in Hertz. 0 is rigid. WeldJoint_SetLinearHertz :: proc(jointId: JointId, hertz: f32) --- diff --git a/vendor/box2d/box2d_wasm.odin b/vendor/box2d/box2d_wasm.odin index 0fcaf753f..1bbe9b8bc 100644 --- a/vendor/box2d/box2d_wasm.odin +++ b/vendor/box2d/box2d_wasm.odin @@ -1,4 +1,4 @@ #+build wasm32, wasm64p32 package vendor_box2d -@(require) import _ "vendor:libc" +@(require) import _ "vendor:libc-shim" diff --git a/vendor/box2d/build_box2d.sh b/vendor/box2d/build_box2d.sh index d6fb3888d..9c79ce009 100755 --- a/vendor/box2d/build_box2d.sh +++ b/vendor/box2d/build_box2d.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -eu -VERSION="3.1.0" +VERSION="3.1.1" RELEASE="https://github.com/erincatto/box2d/archive/refs/tags/v$VERSION.tar.gz" cd "$(dirname "$0")" diff --git a/vendor/box2d/collision.odin b/vendor/box2d/collision.odin index b29e2f946..9930e0549 100644 --- a/vendor/box2d/collision.odin +++ b/vendor/box2d/collision.odin @@ -49,7 +49,7 @@ ShapeCastInput :: struct { canEncroach: bool, } -// Low level ray cast or shape-cast output data +// Low level ray cast or shape-cast output data. Returns a zero fraction and normal in the case of initial overlap. CastOutput :: struct { // The surface normal at the hit point normal: Vec2, @@ -227,7 +227,7 @@ DistanceInput :: struct { DistanceOutput :: struct { pointA: Vec2, // Closest point on shapeA pointB: Vec2, // Closest point on shapeB - normal: Vec2, // Normal vector that points from A to B + normal: Vec2, // Normal vector that points from A to B. Invalid if distance is zero. distance: f32, // The final distance, zero if overlapped iterations: i32, // Number of GJK iterations used simplexCount: i32, // The number of simplexes stored in the simplex array @@ -459,6 +459,9 @@ PlaneResult :: struct { // The collision plane between the mover and convex shape plane: Plane, + // The collision point on the shape. + point: Vec2, + // Did the collision register a hit? If not this plane should be ignored. hit: bool, } @@ -482,8 +485,8 @@ CollisionPlane :: struct { // Result returned by b2SolvePlanes PlaneSolverResult :: struct { - // The final position of the mover - position: Vec2, + // The translation of the mover + translation: Vec2, // The number of iterations used by the plane solver. For diagnostics. iterationCount: i32, diff --git a/vendor/box2d/id.odin b/vendor/box2d/id.odin index cb530527a..d2465f7d7 100644 --- a/vendor/box2d/id.odin +++ b/vendor/box2d/id.odin @@ -86,3 +86,16 @@ ID_EQUALS :: #force_inline proc "c" (id1, id2: $T) -> bool intrinsics.type_has_field(T, "generation") { return id1.index1 == id2.index1 && id1.world0 == id2.world0 && id1.generation == id2.generation } + +// Store a world id into a u32. +StoreWorldId :: #force_inline proc "c" (id: WorldId) -> u32 { + return (u32(id.index1) << 16) | u32(id.generation) +} + +// Load a u32 into a world id. +LoadWorldId :: #force_inline proc "c" (x: u32) -> WorldId { + return { + u16(x >> 16), + u16(x), + } +} diff --git a/vendor/box2d/lib/box2d_darwin_amd64_avx2.a b/vendor/box2d/lib/box2d_darwin_amd64_avx2.a index f98e919a4..43a231303 100644 Binary files a/vendor/box2d/lib/box2d_darwin_amd64_avx2.a and b/vendor/box2d/lib/box2d_darwin_amd64_avx2.a differ diff --git a/vendor/box2d/lib/box2d_darwin_amd64_sse2.a b/vendor/box2d/lib/box2d_darwin_amd64_sse2.a index 3df91e852..c9afbb673 100644 Binary files a/vendor/box2d/lib/box2d_darwin_amd64_sse2.a and b/vendor/box2d/lib/box2d_darwin_amd64_sse2.a differ diff --git a/vendor/box2d/lib/box2d_darwin_arm64.a b/vendor/box2d/lib/box2d_darwin_arm64.a index c5d04fc73..0552cf8e6 100644 Binary files a/vendor/box2d/lib/box2d_darwin_arm64.a and b/vendor/box2d/lib/box2d_darwin_arm64.a differ diff --git a/vendor/box2d/lib/box2d_wasm.o b/vendor/box2d/lib/box2d_wasm.o index fc3ed1cbd..493df4a1c 100755 Binary files a/vendor/box2d/lib/box2d_wasm.o and b/vendor/box2d/lib/box2d_wasm.o differ diff --git a/vendor/box2d/lib/box2d_wasm_simd.o b/vendor/box2d/lib/box2d_wasm_simd.o index 8b70dcedd..d7150082e 100755 Binary files a/vendor/box2d/lib/box2d_wasm_simd.o and b/vendor/box2d/lib/box2d_wasm_simd.o differ diff --git a/vendor/box2d/lib/box2d_windows_amd64_avx2.lib b/vendor/box2d/lib/box2d_windows_amd64_avx2.lib index 7b8626b80..05e5b90a3 100644 Binary files a/vendor/box2d/lib/box2d_windows_amd64_avx2.lib and b/vendor/box2d/lib/box2d_windows_amd64_avx2.lib differ diff --git a/vendor/box2d/lib/box2d_windows_amd64_sse2.lib b/vendor/box2d/lib/box2d_windows_amd64_sse2.lib index f1442615f..21c9a4e2b 100644 Binary files a/vendor/box2d/lib/box2d_windows_amd64_sse2.lib and b/vendor/box2d/lib/box2d_windows_amd64_sse2.lib differ diff --git a/vendor/box2d/math_functions.odin b/vendor/box2d/math_functions.odin index c2d197f08..31c6d4090 100644 --- a/vendor/box2d/math_functions.odin +++ b/vendor/box2d/math_functions.odin @@ -415,31 +415,10 @@ RelativeAngle :: proc "c" (b, a: Rot) -> f32 { return Atan2(s, c) } -// Convert an angle in the range [-2*pi, 2*pi] into the range [-pi, pi] +// Convert any angle into the range [-pi, pi] @(require_results) UnwindAngle :: proc "c" (radians: f32) -> f32 { - if radians < -PI { - return radians + 2.0 * PI - } else if radians > PI { - return radians - 2.0 * PI - } - return radians -} - -// Convert any into the range [-pi, pi] (slow) -@(require_results) -UnwindLargeAngle :: proc "c" (radians: f32) -> f32 { - radians := radians - - for radians > PI { - radians -= 2. * PI - } - - for radians < -PI { - radians += 2. * PI - } - - return radians + return math.remainder(radians, 2. * PI) } // Rotate a vector @@ -563,6 +542,17 @@ AABB_Union :: proc "c" (a, b: AABB) -> (c: AABB) { return } +// Do a and b overlap +@(require_results) +AABB_Overlaps :: proc "c" (a, b: AABB) -> bool { + return !( + b.lowerBound.x > a.upperBound.x || + b.lowerBound.y > a.upperBound.y || + a.lowerBound.x > b.upperBound.x || + a.lowerBound.y > b.upperBound.y \ + ) +} + // Compute the bounding box of an array of circles @(require_results) MakeAABB :: proc "c" (points: []Vec2, radius: f32) -> AABB { @@ -625,3 +615,15 @@ IsValidPlane :: proc "c" (plane: Plane) -> bool { IsNormalized(plane.normal) or_return return true } + +// One-dimensional mass-spring-damper simulation. Returns the new velocity given the position and time step. +// You can then compute the new position using: +// position += timeStep * newVelocity +// This drives towards a zero position. By using implicit integration we get a stable solution +// that doesn't require transcendental functions. +@(require_results) +b2SpringDamper :: proc "c" (hertz, dampingRatio, position, velocity, timeStep: f32) -> f32 { + omega := 2. * PI * hertz + omegaH := omega * timeStep + return (velocity - omega * omegaH * position) / (1. + 2. * dampingRatio * omegaH + omegaH * omegaH) +} diff --git a/vendor/box2d/types.odin b/vendor/box2d/types.odin index 1ad7f379c..9e12aa1a1 100644 --- a/vendor/box2d/types.odin +++ b/vendor/box2d/types.odin @@ -50,6 +50,7 @@ FrictionCallback :: #type proc "c" (frictionA: f32, userMaterialIdA: i32, fricti RestitutionCallback :: #type proc "c" (restitutionA: f32, userMaterialIdA: i32, restitutionB: f32, userMaterialIdB: i32) -> f32 // Result from b2World_RayCastClosest +// If there is initial overlap the fraction and normal will be zero while the point is an arbitrary point in the overlap region. // @ingroup world RayResult :: struct { shapeId: ShapeId, @@ -87,12 +88,6 @@ WorldDef :: struct { // decreasing the damping ratio. maxContactPushSpeed: f32, - // Joint stiffness. Cycles per second. - jointHertz: f32, - - // Joint bounciness. Non-dimensional. - jointDampingRatio: f32, - // Maximum linear speed. Usually meters per second. maximumLinearSpeed: f32, @@ -660,6 +655,10 @@ PrismaticJointDef :: struct { // The constrained angle between the bodies: bodyB_angle - bodyA_angle referenceAngle: f32, + // The target translation for the joint in meters. The spring-damper will drive + // to this translation. + targetTranslation: f32, + // Enable a linear spring along the prismatic joint axis enableSpring: bool, @@ -743,10 +742,10 @@ RevoluteJointDef :: struct { // A flag to enable joint limits enableLimit: bool, - // The lower angle for the joint limit in radians. Minimum of -0.95*pi radians. + // The lower angle for the joint limit in radians. Minimum of -0.99*pi radians. lowerAngle: f32, - // The upper angle for the joint limit in radians. Maximum of 0.95*pi radians. + // The upper angle for the joint limit in radians. Maximum of 0.99*pi radians. upperAngle: f32, // A flag to enable the joint motor @@ -988,6 +987,7 @@ ContactEndTouchEvent :: struct { } // A hit touch event is generated when two shapes collide with a speed faster than the hit speed threshold. +// This may be reported for speculative contacts that have a confirmed impulse. ContactHitEvent :: struct { // Id of the first shape shapeIdA: ShapeId, @@ -995,7 +995,9 @@ ContactHitEvent :: struct { // Id of the second shape shapeIdB: ShapeId, - // Point where the shapes hit + // Point where the shapes hit at the beginning of the time step. + // This is a mid-point between the two surfaces. It could be at speculative + // point where the two shapes were not touching at the beginning of the time step. point: Vec2, // Normal vector pointing from shape A to shape B @@ -1103,17 +1105,18 @@ PreSolveFcn :: #type proc "c" (shapeIdA, shapeIdB: ShapeId, manifold: ^Manifold, // @ingroup world OverlapResultFcn :: #type proc "c" (shapeId: ShapeId, ctx: rawptr) -> bool -// Prototype callback for ray casts. +// Prototype callback for ray and shape casts. // Called for each shape found in the query. You control how the ray cast // proceeds by returning a f32: // return -1: ignore this shape and continue // return 0: terminate the ray cast // return fraction: clip the ray to this point // return 1: don't clip the ray and continue +// A cast with initial overlap will return a zero fraction and a zero normal. // @param shapeId the shape hit by the ray // @param point the point of initial intersection -// @param normal the normal vector at the point of intersection -// @param fraction the fraction along the ray at the point of intersection +// @param normal the normal vector at the point of intersection, zero for a shape cast with initial overlap +// @param fraction the fraction along the ray at the point of intersection, zero for a shape cast with initial overlap // @param context the user context // @return -1 to filter, 0 to terminate, fraction to clip the ray for closest hit, 1 to continue // @see b2World_CastRay diff --git a/vendor/box2d/wasm.Makefile b/vendor/box2d/wasm.Makefile index 74f4e4eff..5cce30ad1 100644 --- a/vendor/box2d/wasm.Makefile +++ b/vendor/box2d/wasm.Makefile @@ -7,11 +7,11 @@ # CC = $(shell brew --prefix llvm)/bin/clang # LD = $(shell brew --prefix llvm)/bin/wasm-ld -VERSION = 3.1.0 +VERSION = 3.1.1 SRCS = $(wildcard box2d-$(VERSION)/src/*.c) OBJS_SIMD = $(SRCS:.c=_simd.o) OBJS = $(SRCS:.c=.o) -SYSROOT = $(shell odin root)/vendor/libc +SYSROOT = $(shell odin root)/vendor/libc-shim CFLAGS = -Ibox2d-$(VERSION)/include --target=wasm32 -D__EMSCRIPTEN__ -DNDEBUG -O3 --sysroot=$(SYSROOT) all: lib/box2d_wasm.o lib/box2d_wasm_simd.o diff --git a/vendor/cgltf/cgltf.odin b/vendor/cgltf/cgltf.odin index aeceb14c5..db1d1c6c0 100644 --- a/vendor/cgltf/cgltf.odin +++ b/vendor/cgltf/cgltf.odin @@ -511,8 +511,8 @@ camera :: struct { name: cstring, type: camera_type, data: struct #raw_union { - perspective: camera_perspective, - orthographic: camera_orthographic, + perspective: camera_perspective `raw_union_tag:"type=.perspective"`, + orthographic: camera_orthographic `raw_union_tag:"type=.orthographic"`, }, extras: extras_t, extensions_count: uint, diff --git a/vendor/cgltf/cgltf_wasm.odin b/vendor/cgltf/cgltf_wasm.odin index fb612b2ac..1404fc592 100644 --- a/vendor/cgltf/cgltf_wasm.odin +++ b/vendor/cgltf/cgltf_wasm.odin @@ -1,4 +1,4 @@ #+build wasm32, wasm64p32 package cgltf -@(require) import _ "vendor:libc" +@(require) import _ "vendor:libc-shim" diff --git a/vendor/cgltf/src/Makefile b/vendor/cgltf/src/Makefile index 0dd450ce0..f4dc8c12c 100644 --- a/vendor/cgltf/src/Makefile +++ b/vendor/cgltf/src/Makefile @@ -8,7 +8,7 @@ endif wasm: mkdir -p ../lib - $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc cgltf.c -o ../lib/cgltf_wasm.o + $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc-shim cgltf.c -o ../lib/cgltf_wasm.o unix: mkdir -p ../lib diff --git a/vendor/commonmark/cmark.odin b/vendor/commonmark/cmark.odin index fd1be45fd..574b977e0 100644 --- a/vendor/commonmark/cmark.odin +++ b/vendor/commonmark/cmark.odin @@ -154,12 +154,12 @@ Node :: struct { flags: Node_Flags, as: struct #raw_union { - list: List, - code: Code, - heading: Heading, - link: Link, - custom: Custom, - html_block_type: c.int, + list: List `raw_union_tag:"type=.List"`, + code: Code `raw_union_tag:"type=.Code"`, + heading: Heading `raw_union_tag:"type=.Heading"`, + link: Link `raw_union_tag:"type=.Link"`, + custom: Custom `raw_union_tag:"type=.Custom"`, + html_block_type: c.int `raw_union_tag:"type=.HTML_Block"`, }, } diff --git a/vendor/compress/lz4/lz4.odin b/vendor/compress/lz4/lz4.odin index 35acaeb5a..f3b0fcb0d 100644 --- a/vendor/compress/lz4/lz4.odin +++ b/vendor/compress/lz4/lz4.odin @@ -3,7 +3,9 @@ package vendor_compress_lz4 when ODIN_OS == .Windows { @(extra_linker_flags="/NODEFAULTLIB:libcmt") - foreign import lib "lib/liblz4_static.lib" + foreign import lib { "lib/liblz4_static.lib", "system:ucrt.lib" } +} else { + foreign import lib "system:lz4" } import "core:c" diff --git a/vendor/curl/curl.odin b/vendor/curl/curl.odin index 073927dc6..41ecbcb75 100644 --- a/vendor/curl/curl.odin +++ b/vendor/curl/curl.odin @@ -14,15 +14,6 @@ when ODIN_OS == .Windows { "system:Ws2_32.lib", "system:iphlpapi.lib", } -} else when ODIN_OS == .Linux { - @(export) - foreign import lib { - "system:curl", - "system:mbedtls", - "system:mbedx509", - "system:mbedcrypto", - "system:z", - } } else when ODIN_OS == .Darwin { @(export) foreign import lib { @@ -32,6 +23,15 @@ when ODIN_OS == .Windows { "system:z", "system:SystemConfiguration.framework", } +} else { + @(export) + foreign import lib { + "system:curl", + "system:mbedtls", + "system:mbedx509", + "system:mbedcrypto", + "system:z", + } } off_t :: i64 @@ -2502,7 +2502,7 @@ foreign lib { * Appends a string to a linked list. If no list exists, it will be created * first. Returns the new list, after appending. */ - slist_append :: proc(list: ^slist, data: [^]byte) -> ^slist --- + slist_append :: proc(list: ^slist, data: cstring) -> ^slist --- /* * NAME curl_slist_free_all() @@ -2932,4 +2932,4 @@ foreign lib { userptr: rawptr) -> code --- -} \ No newline at end of file +} diff --git a/vendor/curl/curl_multi.odin b/vendor/curl/curl_multi.odin index 860c8dbc1..624078684 100644 --- a/vendor/curl/curl_multi.odin +++ b/vendor/curl/curl_multi.odin @@ -410,7 +410,7 @@ foreign lib { * * Returns: NULL on failure, otherwise a CURL **array pointer */ - multi_get_handles :: proc(multi_handle: ^CURLM) -> ^^CURL --- + multi_get_handles :: proc(multi_handle: ^CURLM) -> [^]^CURL --- /* * Name: curl_multi_get_offt() @@ -482,4 +482,4 @@ foreign lib { ufds: [^]waitfd, size: c.uint, fd_count: ^c.uint) -> Mcode --- -} \ No newline at end of file +} diff --git a/vendor/curl/curl_urlapi.odin b/vendor/curl/curl_urlapi.odin index c11f75c70..0b8171e34 100644 --- a/vendor/curl/curl_urlapi.odin +++ b/vendor/curl/curl_urlapi.odin @@ -130,7 +130,7 @@ foreign lib { * error code. The passed in string will be copied. Passing a NULL instead of * a part string, clears that part. */ - url_set :: proc(handle: ^CURLU, what: ^UPart, part: cstring, flags: UFlags) -> Ucode --- + url_set :: proc(handle: ^CURLU, what: UPart, part: cstring, flags: UFlags) -> Ucode --- /* * curl_url_strerror() turns a CURLUcode value into the equivalent human @@ -138,4 +138,4 @@ foreign lib { * messages. */ url_strerror :: proc(Ucode) -> cstring --- -} \ No newline at end of file +} diff --git a/vendor/darwin/QuartzCore/QuartzCore.odin b/vendor/darwin/QuartzCore/QuartzCore.odin index 0e54b3d30..64e8e66d3 100644 --- a/vendor/darwin/QuartzCore/QuartzCore.odin +++ b/vendor/darwin/QuartzCore/QuartzCore.odin @@ -47,6 +47,10 @@ MetalLayer_pixelFormat :: proc "c" (self: ^MetalLayer) -> MTL.PixelFormat { MetalLayer_setPixelFormat :: proc "c" (self: ^MetalLayer, pixelFormat: MTL.PixelFormat) { msgSend(nil, self, "setPixelFormat:", pixelFormat) } +@(objc_type=MetalLayer, objc_name="setColorSpace") +MetalLayer_setColorSpace :: proc "c" (self: ^MetalLayer, colorspace: NS.id) { + msgSend(nil, self, "setColorspace:", colorspace) +} @(objc_type=MetalLayer, objc_name="framebufferOnly") MetalLayer_framebufferOnly :: proc "c" (self: ^MetalLayer) -> NS.BOOL { @@ -126,3 +130,21 @@ MetalDrawable_addPresentedHandler :: proc "c" (self: ^MetalDrawable, block: Draw msgSend(nil, self, "addPresentedHandler:", block) } +@(objc_class="CATransaction") +Transaction :: struct { using _: NS.Object } + +@(objc_type=Transaction, objc_name="begin", objc_is_class_method=true) +transaction_begin :: proc() { + msgSend(nil, Transaction, "begin") +} + +@(objc_type=Transaction, objc_name="commit", objc_is_class_method=true) +transaction_commit :: proc() { + msgSend(nil, Transaction, "commit") +} + +@(objc_type=Transaction, objc_name="flush", objc_is_class_method=true) +transaction_flush :: proc() { + msgSend(nil, Transaction, "flush") +} + diff --git a/vendor/directx/d3d11/d3d11.odin b/vendor/directx/d3d11/d3d11.odin index 835655bbf..51e27ba21 100644 --- a/vendor/directx/d3d11/d3d11.odin +++ b/vendor/directx/d3d11/d3d11.odin @@ -4,7 +4,7 @@ package directx_d3d11 foreign import "system:d3d11.lib" import "../dxgi" -import "../d3d_compiler" +import "../d3d_common" import "core:sys/windows" IUnknown :: dxgi.IUnknown @@ -20,14 +20,13 @@ BOOL :: dxgi.BOOL UINT :: dxgi.UINT INT :: dxgi.INT +LPCSTR :: windows.LPCSTR LPCWSTR :: windows.LPCWSTR RECT :: dxgi.RECT SIZE :: dxgi.SIZE -IModuleInstance :: d3d_compiler.ID3D11ModuleInstance -IBlob :: d3d_compiler.ID3DBlob -IModule :: d3d_compiler.ID3D11Module +IBlob :: d3d_common.ID3DBlob @(default_calling_convention="system", link_prefix="D3D11") foreign d3d11 { @@ -950,7 +949,7 @@ INPUT_CLASSIFICATION :: enum i32 { } INPUT_ELEMENT_DESC :: struct { - SemanticName: cstring, + SemanticName: LPCSTR, SemanticIndex: u32, Format: dxgi.FORMAT, InputSlot: u32, @@ -972,7 +971,7 @@ CULL_MODE :: enum i32 { SO_DECLARATION_ENTRY :: struct { Stream: u32, - SemanticName: cstring, + SemanticName: LPCSTR, SemanticIndex: u32, StartComponent: u8, ComponentCount: u8, @@ -2172,8 +2171,8 @@ IClassLinkage :: struct #raw_union { } IClassLinkage_VTable :: struct { using id3d11devicechild_vtable: IDeviceChild_VTable, - GetClassInstance: proc "system" (this: ^IClassLinkage, pClassInstanceName: cstring, InstanceIndex: u32, ppInstance: ^^IClassInstance) -> HRESULT, - CreateClassInstance: proc "system" (this: ^IClassLinkage, pClassTypeName: cstring, ConstantBufferOffset: u32, ConstantVectorOffset: u32, TextureOffset: u32, SamplerOffset: u32, ppInstance: ^^IClassInstance) -> HRESULT, + GetClassInstance: proc "system" (this: ^IClassLinkage, pClassInstanceName: LPCSTR, InstanceIndex: u32, ppInstance: ^^IClassInstance) -> HRESULT, + CreateClassInstance: proc "system" (this: ^IClassLinkage, pClassTypeName: LPCSTR, ConstantBufferOffset: u32, ConstantVectorOffset: u32, TextureOffset: u32, SamplerOffset: u32, ppInstance: ^^IClassInstance) -> HRESULT, } @@ -3407,7 +3406,7 @@ SHADER_VERSION_TYPE :: enum i32 { } SIGNATURE_PARAMETER_DESC :: struct { - SemanticName: cstring, + SemanticName: LPCSTR, SemanticIndex: u32, Register: u32, SystemValueType: NAME, @@ -3421,7 +3420,7 @@ SIGNATURE_PARAMETER_DESC :: struct { } SHADER_BUFFER_DESC :: struct { - Name: cstring, + Name: LPCSTR, Type: CBUFFER_TYPE, Variables: u32, Size: u32, @@ -3429,7 +3428,7 @@ SHADER_BUFFER_DESC :: struct { } SHADER_VARIABLE_DESC :: struct { - Name: cstring, + Name: LPCSTR, StartOffset: u32, Size: u32, uFlags: SHADER_VARIABLE_FLAGS, @@ -3448,12 +3447,12 @@ SHADER_TYPE_DESC :: struct { Elements: u32, Members: u32, Offset: u32, - Name: cstring, + Name: LPCSTR, } SHADER_DESC :: struct { Version: u32, - Creator: cstring, + Creator: LPCSTR, Flags: u32, ConstantBuffers: u32, @@ -3496,7 +3495,7 @@ SHADER_DESC :: struct { } SHADER_INPUT_BIND_DESC :: struct { - Name: cstring, + Name: LPCSTR, Type: SHADER_INPUT_TYPE, BindPoint: u32, BindCount: u32, @@ -3508,14 +3507,14 @@ SHADER_INPUT_BIND_DESC :: struct { } LIBRARY_DESC :: struct { - Creator: cstring, + Creator: LPCSTR, Flags: u32, FunctionCount: u32, } FUNCTION_DESC :: struct { Version: u32, - Creator: cstring, + Creator: LPCSTR, Flags: u32, ConstantBuffers: u32, @@ -3545,7 +3544,7 @@ FUNCTION_DESC :: struct { MinFeatureLevel: FEATURE_LEVEL, RequiredFeatureFlags: SHADER_REQUIRES_FLAGS, - Name: cstring, + Name: LPCSTR, FunctionParameterCount: i32, HasReturn: BOOL, Has10Level9VertexShader: BOOL, @@ -3553,8 +3552,8 @@ FUNCTION_DESC :: struct { } PARAMETER_DESC :: struct { - Name: cstring, - SemanticName: cstring, + Name: LPCSTR, + SemanticName: LPCSTR, Type: SHADER_VARIABLE_TYPE, Class: SHADER_VARIABLE_CLASS, Rows: u32, @@ -3568,6 +3567,34 @@ PARAMETER_DESC :: struct { FirstOutComponent: u32, } +IModule :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d11module_vtable: ^IModule_VTable, +} +IModule_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + CreateInstance: proc "system" (this: ^IModule, pNamespace: LPCSTR, ppModuleInstance: ^^IModuleInstance) -> HRESULT, +} + +IModuleInstance :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d11moduleinstance_vtable: ^IModuleInstance_VTable, +} +IModuleInstance_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + BindConstantBuffer: proc "system" (this: ^IModuleInstance, uSrcSlot: u32, uDstSlot: u32, cbDstOffset: u32) -> HRESULT, + BindConstantBufferByName: proc "system" (this: ^IModuleInstance, pName: LPCSTR, uDstSlot: u32, cbDstOffset: u32) -> HRESULT, + BindResource: proc "system" (this: ^IModuleInstance, uSrcSlot: u32, uDstSlot: u32, uCount: u32) -> HRESULT, + BindResourceByName: proc "system" (this: ^IModuleInstance, pName: LPCSTR, uDstSlot: u32, uCount: u32) -> HRESULT, + BindSampler: proc "system" (this: ^IModuleInstance, uSrcSlot: u32, uDstSlot: u32, uCount: u32) -> HRESULT, + BindSamplerByName: proc "system" (this: ^IModuleInstance, pName: LPCSTR, uDstSlot: u32, uCount: u32) -> HRESULT, + BindUnorderedAccessView: proc "system" (this: ^IModuleInstance, uSrcSlot: u32, uDstSlot: u32, uCount: u32) -> HRESULT, + BindUnorderedAccessViewByName: proc "system" (this: ^IModuleInstance, pName: LPCSTR, uDstSlot: u32, uCount: u32) -> HRESULT, + BindResourceAsUnorderedAccessView: proc "system" (this: ^IModuleInstance, uSrcSrvSlot: u32, uDstUavSlot: u32, uCount: u32) -> HRESULT, + BindResourceAsUnorderedAccessViewByName: proc "system" (this: ^IModuleInstance, pSrvName: LPCSTR, uDstUavSlot: u32, uCount: u32) -> HRESULT, +} + + ID3D11ShaderReflectionType_UUID_STRING :: "6E6FFA6A-9BAE-4613-A51E-91652D508C21" ID3D11ShaderReflectionType_UUID := &IID{0x6E6FFA6A, 0x9BAE, 0x4613, {0xA5, 0x1E, 0x91, 0x65, 0x2D, 0x50, 0x8C, 0x21}} IShaderReflectionType :: struct { @@ -3576,8 +3603,8 @@ IShaderReflectionType :: struct { IShaderReflectionType_VTable :: struct { GetDesc: proc "system" (this: ^IShaderReflectionType, pDesc: ^SHADER_TYPE_DESC) -> HRESULT, GetMemberTypeByIndex: proc "system" (this: ^IShaderReflectionType, Index: u32) -> ^IShaderReflectionType, - GetMemberTypeByName: proc "system" (this: ^IShaderReflectionType, Name: cstring) -> ^IShaderReflectionType, - GetMemberTypeName: proc "system" (this: ^IShaderReflectionType, Index: u32) -> cstring, + GetMemberTypeByName: proc "system" (this: ^IShaderReflectionType, Name: LPCSTR) -> ^IShaderReflectionType, + GetMemberTypeName: proc "system" (this: ^IShaderReflectionType, Index: u32) -> LPCSTR, IsEqual: proc "system" (this: ^IShaderReflectionType, pType: ^IShaderReflectionType) -> HRESULT, GetSubType: proc "system" (this: ^IShaderReflectionType) -> ^IShaderReflectionType, GetBaseClass: proc "system" (this: ^IShaderReflectionType) -> ^IShaderReflectionType, @@ -3607,7 +3634,7 @@ IShaderReflectionConstantBuffer :: struct { IShaderReflectionConstantBuffer_VTable :: struct { GetDesc: proc "system" (this: ^IShaderReflectionConstantBuffer, pDesc: ^SHADER_BUFFER_DESC) -> HRESULT, GetVariableByIndex: proc "system" (this: ^IShaderReflectionConstantBuffer, Index: u32) -> ^IShaderReflectionVariable, - GetVariableByName: proc "system" (this: ^IShaderReflectionConstantBuffer, Name: cstring) -> ^IShaderReflectionVariable, + GetVariableByName: proc "system" (this: ^IShaderReflectionConstantBuffer, Name: LPCSTR) -> ^IShaderReflectionVariable, } @@ -3621,13 +3648,13 @@ IShaderReflection_VTable :: struct { using iunknown_vtable: IUnknown_VTable, GetDesc: proc "system" (this: ^IShaderReflection, pDesc: ^SHADER_DESC) -> HRESULT, GetConstantBufferByIndex: proc "system" (this: ^IShaderReflection, Index: u32) -> ^IShaderReflectionConstantBuffer, - GetConstantBufferByName: proc "system" (this: ^IShaderReflection, Name: cstring) -> ^IShaderReflectionConstantBuffer, + GetConstantBufferByName: proc "system" (this: ^IShaderReflection, Name: LPCSTR) -> ^IShaderReflectionConstantBuffer, GetResourceBindingDesc: proc "system" (this: ^IShaderReflection, ResourceIndex: u32, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, GetInputParameterDesc: proc "system" (this: ^IShaderReflection, ParameterIndex: u32, pDesc: ^SIGNATURE_PARAMETER_DESC) -> HRESULT, GetOutputParameterDesc: proc "system" (this: ^IShaderReflection, ParameterIndex: u32, pDesc: ^SIGNATURE_PARAMETER_DESC) -> HRESULT, GetPatchConstantParameterDesc: proc "system" (this: ^IShaderReflection, ParameterIndex: u32, pDesc: ^SIGNATURE_PARAMETER_DESC) -> HRESULT, - GetVariableByName: proc "system" (this: ^IShaderReflection, Name: cstring) -> ^IShaderReflectionVariable, - GetResourceBindingDescByName: proc "system" (this: ^IShaderReflection, Name: cstring, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, + GetVariableByName: proc "system" (this: ^IShaderReflection, Name: LPCSTR) -> ^IShaderReflectionVariable, + GetResourceBindingDescByName: proc "system" (this: ^IShaderReflection, Name: LPCSTR, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, GetMovInstructionCount: proc "system" (this: ^IShaderReflection) -> u32, GetMovcInstructionCount: proc "system" (this: ^IShaderReflection) -> u32, GetConversionInstructionCount: proc "system" (this: ^IShaderReflection) -> u32, @@ -3661,10 +3688,10 @@ IFunctionReflection :: struct { IFunctionReflection_VTable :: struct { GetDesc: proc "system" (this: ^IFunctionReflection, pDesc: ^FUNCTION_DESC) -> HRESULT, GetConstantBufferByIndex: proc "system" (this: ^IFunctionReflection, BufferIndex: u32) -> ^IShaderReflectionConstantBuffer, - GetConstantBufferByName: proc "system" (this: ^IFunctionReflection, Name: cstring) -> ^IShaderReflectionConstantBuffer, + GetConstantBufferByName: proc "system" (this: ^IFunctionReflection, Name: LPCSTR) -> ^IShaderReflectionConstantBuffer, GetResourceBindingDesc: proc "system" (this: ^IFunctionReflection, ResourceIndex: u32, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, - GetVariableByName: proc "system" (this: ^IFunctionReflection, Name: cstring) -> ^IShaderReflectionVariable, - GetResourceBindingDescByName: proc "system" (this: ^IFunctionReflection, Name: cstring, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, + GetVariableByName: proc "system" (this: ^IFunctionReflection, Name: LPCSTR) -> ^IShaderReflectionVariable, + GetResourceBindingDescByName: proc "system" (this: ^IFunctionReflection, Name: LPCSTR, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, GetFunctionParameter: proc "system" (this: ^IFunctionReflection, ParameterIndex: i32) -> ^IFunctionParameterReflection, } @@ -3691,7 +3718,7 @@ IFunctionLinkingGraph_VTable :: struct { CreateModuleInstance: proc "system" (this: ^IFunctionLinkingGraph, ppModuleInstance: ^^IModuleInstance, ppErrorBuffer: ^^IBlob) -> HRESULT, SetInputSignature: proc "system" (this: ^IFunctionLinkingGraph, pInputParameters: [^]PARAMETER_DESC, cInputParameters: u32, ppInputNode: ^^ILinkingNode) -> HRESULT, SetOutputSignature: proc "system" (this: ^IFunctionLinkingGraph, pOutputParameters: [^]PARAMETER_DESC, cOutputParameters: u32, ppOutputNode: ^^ILinkingNode) -> HRESULT, - CallFunction: proc "system" (this: ^IFunctionLinkingGraph, pModuleInstanceNamespace: cstring, pModuleWithFunctionPrototype: ^IModule, pFunctionName: cstring, ppCallNode: ^^ILinkingNode) -> HRESULT, + CallFunction: proc "system" (this: ^IFunctionLinkingGraph, pModuleInstanceNamespace: LPCSTR, pModuleWithFunctionPrototype: ^IModule, pFunctionName: LPCSTR, ppCallNode: ^^ILinkingNode) -> HRESULT, PassValue: proc "system" (this: ^IFunctionLinkingGraph, pSrcNode: ^ILinkingNode, SrcParameterIndex: i32, pDstNode: ^ILinkingNode, DstParameterIndex: i32) -> HRESULT, PassValueWithSwizzle: proc "system" (this: ^IFunctionLinkingGraph, pSrcNode: ^ILinkingNode, SrcParameterIndex: i32, pSrcSwizzle: ^u8, pDstNode: ^ILinkingNode, DstParameterIndex: i32, pDstSwizzle: ^u8) -> HRESULT, GetLastError: proc "system" (this: ^IFunctionLinkingGraph, ppErrorBuffer: ^^IBlob) -> HRESULT, @@ -3814,8 +3841,8 @@ IInfoQueue_VTable :: struct { PushRetrievalFilter: proc "system" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER) -> HRESULT, PopRetrievalFilter: proc "system" (this: ^IInfoQueue), GetRetrievalFilterStackSize: proc "system" (this: ^IInfoQueue) -> u64, - AddMessage: proc "system" (this: ^IInfoQueue, Category: MESSAGE_CATEGORY, Severity: MESSAGE_SEVERITY, ID: MESSAGE_ID, pDescription: cstring) -> HRESULT, - AddApplicationMessage: proc "system" (this: ^IInfoQueue, Severity: MESSAGE_SEVERITY, pDescription: cstring) -> HRESULT, + AddMessage: proc "system" (this: ^IInfoQueue, Category: MESSAGE_CATEGORY, Severity: MESSAGE_SEVERITY, ID: MESSAGE_ID, pDescription: LPCSTR) -> HRESULT, + AddApplicationMessage: proc "system" (this: ^IInfoQueue, Severity: MESSAGE_SEVERITY, pDescription: LPCSTR) -> HRESULT, SetBreakOnCategory: proc "system" (this: ^IInfoQueue, Category: MESSAGE_CATEGORY, bEnable: BOOL) -> HRESULT, SetBreakOnSeverity: proc "system" (this: ^IInfoQueue, Severity: MESSAGE_SEVERITY, bEnable: BOOL) -> HRESULT, SetBreakOnID: proc "system" (this: ^IInfoQueue, ID: MESSAGE_ID, bEnable: BOOL) -> HRESULT, diff --git a/vendor/directx/d3d12/d3d12.odin b/vendor/directx/d3d12/d3d12.odin index a0e020d1a..3519dafaf 100644 --- a/vendor/directx/d3d12/d3d12.odin +++ b/vendor/directx/d3d12/d3d12.odin @@ -4,7 +4,7 @@ package directx_d3d12 foreign import "system:d3d12.lib" import "../dxgi" -import "../d3d_compiler" +import "../d3d_common" import win32 "core:sys/windows" IUnknown :: dxgi.IUnknown @@ -23,11 +23,10 @@ BOOL :: dxgi.BOOL RECT :: dxgi.RECT +LPCSTR :: win32.LPCSTR LPCWSTR :: win32.LPCWSTR -IModuleInstance :: d3d_compiler.ID3D11ModuleInstance -IBlob :: d3d_compiler.ID3DBlob -IModule :: d3d_compiler.ID3D11Module +IBlob :: d3d_common.ID3DBlob @(default_calling_convention="system", link_prefix="D3D12") foreign d3d12 { @@ -175,19 +174,20 @@ PRIMITIVE :: enum i32 { } SRV_DIMENSION :: enum i32 { - UNKNOWN = 0, - BUFFER = 1, - TEXTURE1D = 2, - TEXTURE1DARRAY = 3, - TEXTURE2D = 4, - TEXTURE2DARRAY = 5, - TEXTURE2DMS = 6, - TEXTURE2DMSARRAY = 7, - TEXTURE3D = 8, - TEXTURECUBE = 9, - TEXTURECUBEARRAY = 10, - BUFFEREX = 11, + UNKNOWN = 0, + BUFFER = 1, + TEXTURE1D = 2, + TEXTURE1DARRAY = 3, + TEXTURE2D = 4, + TEXTURE2DARRAY = 5, + TEXTURE2DMS = 6, + TEXTURE2DMSARRAY = 7, + TEXTURE3D = 8, + TEXTURECUBE = 9, + TEXTURECUBEARRAY = 10, + BUFFEREX = 11, RAYTRACING_ACCELERATION_STRUCTURE = 11, + BUFFER_BYTE_OFFSET = 12, } PFN_DESTRUCTION_CALLBACK :: #type proc "c" (a0: rawptr) @@ -467,7 +467,7 @@ INPUT_CLASSIFICATION :: enum i32 { } INPUT_ELEMENT_DESC :: struct { - SemanticName: cstring, + SemanticName: LPCSTR, SemanticIndex: u32, Format: dxgi.FORMAT, InputSlot: u32, @@ -489,7 +489,7 @@ CULL_MODE :: enum i32 { SO_DECLARATION_ENTRY :: struct { Stream: u32, - SemanticName: cstring, + SemanticName: LPCSTR, SemanticIndex: u32, StartComponent: u8, ComponentCount: u8, @@ -859,6 +859,8 @@ FEATURE :: enum i32 { APPLICATION_SPECIFIC_DRIVER_STATE = 56, BYTECODE_BYPASS_HASH_SUPPORTED = 57, SHADER_CACHE_ABI_SUPPORT = 61, + BARRIER_LAYOUT = 64, + OPTIONS22 = 65, } SHADER_MIN_PRECISION_SUPPORT :: distinct bit_set[SHADER_MIN_PRECISION_SUPPORT_FLAG; u32] @@ -1235,7 +1237,7 @@ TRI_STATE :: enum i32 { UNKNOWN = -1, FALSE = 0, TRUE = 1, -} +} FEATURE_DATA_OPTIONS12 :: struct { MSPrimitivesPipelineStatisticIncludesCulledPrimitives: TRI_STATE, @@ -1312,6 +1314,13 @@ FEATURE_DATA_OPTIONS21 :: struct { ExtendedCommandInfoSupported: BOOL, } +FEATURE_DATA_OPTIONS22 :: struct { + ShaderExecutionReorderingActuallyReorders: BOOL, + CreateByteOffsetViewsSupported: BOOL, + Max1DDispatchSize: u32, + Max1DDispatchMeshSize: u32, +} + TIGHT_ALIGNMENT_TIER :: enum i32 { NOT_SUPPORTED = 0, _1 = NOT_SUPPORTED + 1, @@ -1810,6 +1819,13 @@ RAYTRACING_ACCELERATION_STRUCTURE_SRV :: struct { Location: GPU_VIRTUAL_ADDRESS, } +BUFFER_SRV_BYTE_OFFSET :: struct { + Offset: u64, + Size: u64, + StructureByteStride: u32, + Flags: BUFFER_SRV_FLAGS, +} + SHADER_RESOURCE_VIEW_DESC :: struct { Format: dxgi.FORMAT, ViewDimension: SRV_DIMENSION, @@ -1826,6 +1842,7 @@ SHADER_RESOURCE_VIEW_DESC :: struct { TextureCube: TEXCUBE_SRV, TextureCubeArray: TEXCUBE_ARRAY_SRV, RaytracingAccelerationStructure: RAYTRACING_ACCELERATION_STRUCTURE_SRV, + BufferByteOffset: BUFFER_SRV_BYTE_OFFSET, }, } @@ -1947,26 +1964,36 @@ TEX3D_UAV :: struct { WSize: u32, } +BUFFER_UAV_BYTE_OFFSET :: struct { + Offset: u64, + Size: u32, + StructureByteStride: u32, + CounterOffsetInBytes: u64, + Flags: BUFFER_UAV_FLAGS, +} + UAV_DIMENSION :: enum i32 { - UNKNOWN = 0, - BUFFER = 1, - TEXTURE1D = 2, - TEXTURE1DARRAY = 3, - TEXTURE2D = 4, - TEXTURE2DARRAY = 5, - TEXTURE3D = 8, + UNKNOWN = 0, + BUFFER = 1, + TEXTURE1D = 2, + TEXTURE1DARRAY = 3, + TEXTURE2D = 4, + TEXTURE2DARRAY = 5, + TEXTURE3D = 8, + BUFFER_BYTE_OFFSET = 9, } UNORDERED_ACCESS_VIEW_DESC :: struct { Format: dxgi.FORMAT, ViewDimension: UAV_DIMENSION, using _: struct #raw_union { - Buffer: BUFFER_UAV, - Texture1D: TEX1D_UAV, - Texture1DArray: TEX1D_ARRAY_UAV, - Texture2D: TEX2D_UAV, - Texture2DArray: TEX2D_ARRAY_UAV, - Texture3D: TEX3D_UAV, + Buffer: BUFFER_UAV, + Texture1D: TEX1D_UAV, + Texture1DArray: TEX1D_ARRAY_UAV, + Texture2D: TEX2D_UAV, + Texture2DArray: TEX2D_ARRAY_UAV, + Texture3D: TEX3D_UAV, + BufferByteOffset: BUFFER_UAV_BYTE_OFFSET, }, } @@ -2596,7 +2623,7 @@ IDescriptorHeap_VTable :: struct { GetDesc: proc "system" (this: ^IDescriptorHeap, desc: ^DESCRIPTOR_HEAP_DESC), GetCPUDescriptorHandleForHeapStart: proc "system" (this: ^IDescriptorHeap, handle: ^CPU_DESCRIPTOR_HANDLE), GetGPUDescriptorHandleForHeapStart: proc "system" (this: ^IDescriptorHeap, handle: ^GPU_DESCRIPTOR_HANDLE), -} +} IQueryHeap_UUID_STRING :: "0d9658ae-ed45-469e-a61d-970ec583cab4" IQueryHeap_UUID := &IID{0x0d9658ae, 0xed45, 0x469e, {0xa6, 0x1d, 0x97, 0x0e, 0xc5, 0x83, 0xca, 0xb4}} @@ -3153,13 +3180,13 @@ EXISTING_COLLECTION_DESC :: struct { SUBOBJECT_TO_EXPORTS_ASSOCIATION :: struct { pSubobjectToAssociate: ^STATE_SUBOBJECT, NumExports: u32, - pExports: [^]cstring16 `fmt:"v,NumExports"`, + pExports: [^]LPCWSTR `fmt:"v,NumExports"`, } DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION :: struct { - SubobjectToAssociate: cstring16, + SubobjectToAssociate: LPCWSTR, NumExports: u32, - pExports: [^]cstring16 `fmt:"v,NumExports"`, + pExports: [^]LPCWSTR `fmt:"v,NumExports"`, } HIT_GROUP_TYPE :: enum i32 { @@ -3168,11 +3195,11 @@ HIT_GROUP_TYPE :: enum i32 { } HIT_GROUP_DESC :: struct { - HitGroupExport: cstring16, + HitGroupExport: LPCWSTR, Type: HIT_GROUP_TYPE, - AnyHitShaderImport: cstring16, - ClosestHitShaderImport: cstring16, - IntersectionShaderImport: cstring16, + AnyHitShaderImport: LPCWSTR, + ClosestHitShaderImport: LPCWSTR, + IntersectionShaderImport: LPCWSTR, } RAYTRACING_SHADER_CONFIG :: struct { @@ -5222,8 +5249,8 @@ IInfoQueue_VTable :: struct { PushRetrievalFilter: proc "system" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER) -> HRESULT, PopRetrievalFilter: proc "system" (this: ^IInfoQueue), GetRetrievalFilterStackSize: proc "system" (this: ^IInfoQueue) -> u32, - AddMessage: proc "system" (this: ^IInfoQueue, Category: MESSAGE_CATEGORY, Severity: MESSAGE_SEVERITY, ID: MESSAGE_ID, pDescription: cstring) -> HRESULT, - AddApplicationMessage: proc "system" (this: ^IInfoQueue, Severity: MESSAGE_SEVERITY, pDescription: cstring) -> HRESULT, + AddMessage: proc "system" (this: ^IInfoQueue, Category: MESSAGE_CATEGORY, Severity: MESSAGE_SEVERITY, ID: MESSAGE_ID, pDescription: LPCSTR) -> HRESULT, + AddApplicationMessage: proc "system" (this: ^IInfoQueue, Severity: MESSAGE_SEVERITY, pDescription: LPCSTR) -> HRESULT, SetBreakOnCategory: proc "system" (this: ^IInfoQueue, Category: MESSAGE_CATEGORY, bEnable: BOOL) -> HRESULT, SetBreakOnSeverity: proc "system" (this: ^IInfoQueue, Severity: MESSAGE_SEVERITY, bEnable: BOOL) -> HRESULT, SetBreakOnID: proc "system" (this: ^IInfoQueue, ID: MESSAGE_ID, bEnable: BOOL) -> HRESULT, @@ -5239,7 +5266,7 @@ MESSAGE_CALLBACK_FLAG :: enum { IGNORE_FILTERS = 0, } -PFN_MESSAGE_CALLBACK :: #type proc "c" (Category: MESSAGE_CATEGORY, Severity: MESSAGE_SEVERITY, ID: MESSAGE_ID, pDescription: cstring, pContext: rawptr) +PFN_MESSAGE_CALLBACK :: #type proc "c" (Category: MESSAGE_CATEGORY, Severity: MESSAGE_SEVERITY, ID: MESSAGE_ID, pDescription: LPCSTR, pContext: rawptr) IInfoQueue1_UUID_STRING :: "2852dd88-b484-4c0c-b6b1-67168500e600" IInfoQueue1_UUID := &IID{0x2852dd88, 0xb484, 0x4c0c, {0xb6, 0xb1, 0x67, 0x16, 0x85, 0x00, 0xe6, 0x00}} @@ -5262,7 +5289,7 @@ ISDKConfiguration :: struct #raw_union { } ISDKConfiguration_VTable :: struct { using iunknown_vtable: IUnknown_VTable, - SetSDKVersion: proc "system" (this: ^ISDKConfiguration, SDKVersion: u32, SDKPath: cstring) -> HRESULT, + SetSDKVersion: proc "system" (this: ^ISDKConfiguration, SDKVersion: u32, SDKPath: LPCSTR) -> HRESULT, } @@ -5324,10 +5351,177 @@ IGraphicsCommandList6_VTable :: struct { DispatchMesh: proc "system" (this: ^IGraphicsCommandList6, ThreadGroupCountX: u32, ThreadGroupCountY: u32, ThreadGroupCountZ: u32), } + +BARRIER_LAYOUT :: enum u32 { + UNDEFINED = 0xffffffff, + COMMON = 0, + PRESENT = 0, + GENERIC_READ = 1, + RENDER_TARGET = 2, + UNORDERED_ACCESS = 3, + DEPTH_STENCIL_WRITE = 4, + DEPTH_STENCIL_READ = 5, + SHADER_RESOURCE = 6, + COPY_SOURCE = 7, + COPY_DEST = 8, + RESOLVE_SOURCE = 9, + RESOLVE_DEST = 10, + SHADING_RATE_SOURCE = 11, + VIDEO_DECODE_READ = 12, + VIDEO_DECODE_WRITE = 13, + VIDEO_PROCESS_READ = 14, + VIDEO_PROCESS_WRITE = 15, + VIDEO_ENCODE_READ = 16, + VIDEO_ENCODE_WRITE = 17, + DIRECT_QUEUE_COMMON = 18, + DIRECT_QUEUE_GENERIC_READ = 19, + DIRECT_QUEUE_UNORDERED_ACCESS = 20, + DIRECT_QUEUE_SHADER_RESOURCE = 21, + DIRECT_QUEUE_COPY_SOURCE = 22, + DIRECT_QUEUE_COPY_DEST = 23, + COMPUTE_QUEUE_COMMON = 24, + COMPUTE_QUEUE_GENERIC_READ = 25, + COMPUTE_QUEUE_UNORDERED_ACCESS = 26, + COMPUTE_QUEUE_SHADER_RESOURCE = 27, + COMPUTE_QUEUE_COPY_SOURCE = 28, + COMPUTE_QUEUE_COPY_DEST = 29, + DIRECT_QUEUE_GENERIC_READ_COMPUTE_QUEUE_ACCESSIBLE = 31, +} + +BARRIER_SYNC_FLAG :: enum u32 { + ALL = 0, // 0x1 + DRAW = 1, // 0x2 + INDEX_INPUT = 2, // 0x4 + VERTEX_SHADING = 3, // 0x8 + PIXEL_SHADING = 4, // 0x10 + DEPTH_STENCIL = 5, // 0x20 + RENDER_TARGET = 6, // 0x40 + COMPUTE_SHADING = 7, // 0x80 + RAYTRACING = 8, // 0x100 + COPY = 9, // 0x200 + RESOLVE = 10, // 0x400 + EXECUTE_INDIRECT = 11, // 0x800 + PREDICATION = 11, // 0x800 + ALL_SHADING = 12, // 0x1000 + NON_PIXEL_SHADING = 13, // 0x2000 + EMIT_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO = 14, // 0x4000 + CLEAR_UNORDERED_ACCESS_VIEW = 15, // 0x8000 + VIDEO_DECODE = 20, // 0x100000 + VIDEO_PROCESS = 21, // 0x200000 + VIDEO_ENCODE = 22, // 0x400000 + BUILD_RAYTRACING_ACCELERATION_STRUCTURE = 23, // 0x800000 + COPY_RAYTRACING_ACCELERATION_STRUCTURE = 24, // 0x1000000 + SPLIT = 31, // 0x80000000 +} + +BARRIER_SYNC_FLAGS :: bit_set[BARRIER_SYNC_FLAG; u32] + +BARRIER_ACCESS_FLAG :: enum u32 { + VERTEX_BUFFER = 0, // 0x1 + CONSTANT_BUFFER = 1, // 0x2 + INDEX_BUFFER = 2, // 0x4 + RENDER_TARGET = 3, // 0x8 + UNORDERED_ACCESS = 4, // 0x10 + DEPTH_STENCIL_WRITE = 5, // 0x20 + DEPTH_STENCIL_READ = 6, // 0x40 + SHADER_RESOURCE = 7, // 0x80 + STREAM_OUTPUT = 8, // 0x100 + INDIRECT_ARGUMENT = 9, // 0x200 + PREDICATION = 9, // 0x200 + COPY_DEST = 10, // 0x400 + COPY_SOURCE = 11, // 0x800 + RESOLVE_DEST = 12, // 0x1000 + RESOLVE_SOURCE = 13, // 0x2000 + RAYTRACING_ACCELERATION_STRUCTURE_READ = 14, // 0x4000 + RAYTRACING_ACCELERATION_STRUCTURE_WRITE = 15, // 0x8000 + SHADING_RATE_SOURCE = 16, // 0x10000 + VIDEO_DECODE_READ = 17, // 0x20000 + VIDEO_DECODE_WRITE = 18, // 0x40000 + VIDEO_PROCESS_READ = 19, // 0x80000 + VIDEO_PROCESS_WRITE = 20, // 0x100000 + VIDEO_ENCODE_READ = 21, // 0x200000 + VIDEO_ENCODE_WRITE = 22, // 0x400000 + NO_ACCESS = 31, // 0x80000000 +} + +BARRIER_ACCESS_FLAGS :: bit_set[BARRIER_ACCESS_FLAG; u32] + +BARRIER_TYPE :: enum i32 { + GLOBAL, + TEXTURE, + BUFFER, +} + +TEXTURE_BARRIER_FLAGS :: enum i32 { + NONE = 0x0, + DISCARD = 0x1, +} + +BARRIER_SUBRESOURCE_RANGE :: struct { + IndexOrFirstMipLevel: uint, + NumMipLevels: uint, + FirstArraySlice: uint, + NumArraySlices: uint, + FirstPlane: uint, + NumPlanes: uint, +} + +GLOBAL_BARRIER :: struct { + SyncBefore: BARRIER_SYNC_FLAGS, + SyncAfter: BARRIER_SYNC_FLAGS, + AccessBefore: BARRIER_ACCESS_FLAGS, + AccessAfter: BARRIER_ACCESS_FLAGS, +} + +TEXTURE_BARRIER :: struct { + SyncBefore: BARRIER_SYNC_FLAGS, + SyncAfter: BARRIER_SYNC_FLAGS, + AccessBefore: BARRIER_ACCESS_FLAGS, + AccessAfter: BARRIER_ACCESS_FLAGS, + LayoutBefore: BARRIER_LAYOUT, + LayoutAfter: BARRIER_LAYOUT, + pResource: ^IResource, + Subresources: BARRIER_SUBRESOURCE_RANGE, + Flags: TEXTURE_BARRIER_FLAGS, +} + +BUFFER_BARRIER :: struct { + SyncBefore: BARRIER_SYNC_FLAGS, + SyncAfter: BARRIER_SYNC_FLAGS, + AccessBefore: BARRIER_ACCESS_FLAGS, + AccessAfter: BARRIER_ACCESS_FLAGS, + pRessource: ^IResource, + Offset: u64, + Size: u64, +} + +BARRIER_GROUP :: struct { + Type: BARRIER_TYPE, + NumBarriers: u32, + using _: struct #raw_union { + pGlobalBarriers: [^]GLOBAL_BARRIER `raw_union_tag:"Type=GLOBAL"`, + pTextureBarriers: [^]TEXTURE_BARRIER `raw_union_tag:"Type=TEXTURE"`, + pBufferBarriers: [^]BUFFER_BARRIER `raw_union_tag:"Type=BARRIER"`, + }, +} + + +IGraphicsCommandList7_UUID_STRING :: "dd171223-8b61-4769-90e3-160ccde4e2c1" +IGraphicsCommandList7_UUID := &IID{0xdd171223, 0x8b61, 0x4769, {0x90, 0xe3, 0x16, 0x0c, 0xcd, 0xe4, 0xe2, 0xc1}} +IGraphicsCommandList7 :: struct #raw_union { + #subtype id3d12graphicscommandlist6: IGraphicsCommandList6, + using id3d12graphicscommandlist7_vtable: ^IGraphicsCommandList7_VTable, +} +IGraphicsCommandList7_VTable :: struct { + using id3d12graphicscommandlist6_vtable: IGraphicsCommandList6_VTable, + Barrier: proc "system" (this: ^IGraphicsCommandList7, NumBarrierGroups: u32, pBarrierGroups: [^]BARRIER_GROUP), +} + + SHADER_VERSION_TYPE :: enum u32 { PIXEL_SHADER = 0, VERTEX_SHADER = 1, - GEOMETRY_SHADER = 2, + GEOMETRY_SHADER = 2, HULL_SHADER = 3, DOMAIN_SHADER = 4, @@ -5361,7 +5555,7 @@ shver_get_minor :: proc "contextless" (version: u32) -> u8 { } SIGNATURE_PARAMETER_DESC :: struct { - SemanticName: cstring, + SemanticName: LPCSTR, SemanticIndex: u32, Register: u32, SystemValueType: NAME, @@ -5375,7 +5569,7 @@ SIGNATURE_PARAMETER_DESC :: struct { } SHADER_BUFFER_DESC :: struct { - Name: cstring, + Name: LPCSTR, Type: CBUFFER_TYPE, Variables: u32, Size: u32, @@ -5383,7 +5577,7 @@ SHADER_BUFFER_DESC :: struct { } SHADER_VARIABLE_DESC :: struct { - Name: cstring, + Name: LPCSTR, StartOffset: u32, Size: u32, uFlags: u32, @@ -5402,12 +5596,12 @@ SHADER_TYPE_DESC :: struct { Elements: u32, Members: u32, Offset: u32, - Name: cstring, + Name: LPCSTR, } SHADER_DESC :: struct { Version: u32, - Creator: cstring, + Creator: LPCSTR, Flags: u32, ConstantBuffers: u32, @@ -5450,7 +5644,7 @@ SHADER_DESC :: struct { } SHADER_INPUT_BIND_DESC :: struct { - Name: cstring, + Name: LPCSTR, Type: SHADER_INPUT_TYPE, BindPoint: u32, BindCount: u32, @@ -5497,14 +5691,14 @@ SHADER_REQUIRES :: enum u64 { } LIBRARY_DESC :: struct { - Creator: cstring, + Creator: LPCSTR, Flags: u32, FunctionCount: u32, } FUNCTION_DESC :: struct { Version: u32, - Creator: cstring, + Creator: LPCSTR, Flags: u32, ConstantBuffers: u32, @@ -5534,7 +5728,7 @@ FUNCTION_DESC :: struct { MinFeatureLevel: FEATURE_LEVEL, RequiredFeatureFlags: u64, - Name: cstring, + Name: LPCSTR, FunctionParameterCount: i32, HasReturn: BOOL, Has10Level9VertexShader: BOOL, @@ -5542,8 +5736,8 @@ FUNCTION_DESC :: struct { } PARAMETER_DESC :: struct { - Name: cstring, - SemanticName: cstring, + Name: LPCSTR, + SemanticName: LPCSTR, Type: SHADER_VARIABLE_TYPE, Class: SHADER_VARIABLE_CLASS, Rows: u32, @@ -5565,8 +5759,8 @@ IShaderReflectionType :: struct { IShaderReflectionType_VTable :: struct { GetDesc: proc "system" (this: ^IShaderReflectionType, pDesc: ^SHADER_TYPE_DESC) -> HRESULT, GetMemberTypeByIndex: proc "system" (this: ^IShaderReflectionType, Index: u32) -> ^IShaderReflectionType, - GetMemberTypeByName: proc "system" (this: ^IShaderReflectionType, Name: cstring) -> ^IShaderReflectionType, - GetMemberTypeName: proc "system" (this: ^IShaderReflectionType, Index: u32) -> cstring, + GetMemberTypeByName: proc "system" (this: ^IShaderReflectionType, Name: LPCSTR) -> ^IShaderReflectionType, + GetMemberTypeName: proc "system" (this: ^IShaderReflectionType, Index: u32) -> LPCSTR, IsEqual: proc "system" (this: ^IShaderReflectionType, pType: ^IShaderReflectionType) -> HRESULT, GetSubType: proc "system" (this: ^IShaderReflectionType) -> ^IShaderReflectionType, GetBaseClass: proc "system" (this: ^IShaderReflectionType) -> ^IShaderReflectionType, @@ -5596,7 +5790,7 @@ IShaderReflectionConstantBuffer :: struct { IShaderReflectionConstantBuffer_VTable :: struct { GetDesc: proc "system" (this: ^IShaderReflectionConstantBuffer, pDesc: ^SHADER_BUFFER_DESC) -> HRESULT, GetVariableByIndex: proc "system" (this: ^IShaderReflectionConstantBuffer, Index: u32) -> ^IShaderReflectionVariable, - GetVariableByName: proc "system" (this: ^IShaderReflectionConstantBuffer, Name: cstring) -> ^IShaderReflectionVariable, + GetVariableByName: proc "system" (this: ^IShaderReflectionConstantBuffer, Name: LPCSTR) -> ^IShaderReflectionVariable, } IShaderReflection_UUID_STRING :: "5A58797D-A72C-478D-8BA2-EFC6B0EFE88E" @@ -5609,13 +5803,13 @@ IShaderReflection_VTable :: struct { using iunknown_vtable: IUnknown_VTable, GetDesc: proc "system" (this: ^IShaderReflection, pDesc: ^SHADER_DESC) -> HRESULT, GetConstantBufferByIndex: proc "system" (this: ^IShaderReflection, Index: u32) -> ^IShaderReflectionConstantBuffer, - GetConstantBufferByName: proc "system" (this: ^IShaderReflection, Name: cstring) -> ^IShaderReflectionConstantBuffer, + GetConstantBufferByName: proc "system" (this: ^IShaderReflection, Name: LPCSTR) -> ^IShaderReflectionConstantBuffer, GetResourceBindingDesc: proc "system" (this: ^IShaderReflection, ResourceIndex: u32, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, GetInputParameterDesc: proc "system" (this: ^IShaderReflection, ParameterIndex: u32, pDesc: ^SIGNATURE_PARAMETER_DESC) -> HRESULT, GetOutputParameterDesc: proc "system" (this: ^IShaderReflection, ParameterIndex: u32, pDesc: ^SIGNATURE_PARAMETER_DESC) -> HRESULT, GetPatchConstantParameterDesc: proc "system" (this: ^IShaderReflection, ParameterIndex: u32, pDesc: ^SIGNATURE_PARAMETER_DESC) -> HRESULT, - GetVariableByName: proc "system" (this: ^IShaderReflection, Name: cstring) -> ^IShaderReflectionVariable, - GetResourceBindingDescByName: proc "system" (this: ^IShaderReflection, Name: cstring, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, + GetVariableByName: proc "system" (this: ^IShaderReflection, Name: LPCSTR) -> ^IShaderReflectionVariable, + GetResourceBindingDescByName: proc "system" (this: ^IShaderReflection, Name: LPCSTR, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, GetMovInstructionCount: proc "system" (this: ^IShaderReflection) -> u32, GetMovcInstructionCount: proc "system" (this: ^IShaderReflection) -> u32, GetConversionInstructionCount: proc "system" (this: ^IShaderReflection) -> u32, @@ -5648,10 +5842,10 @@ IFunctionReflection :: struct { IFunctionReflection_VTable :: struct { GetDesc: proc "system" (this: ^IFunctionReflection, pDesc: ^FUNCTION_DESC) -> HRESULT, GetConstantBufferByIndex: proc "system" (this: ^IFunctionReflection, BufferIndex: u32) -> ^IShaderReflectionConstantBuffer, - GetConstantBufferByName: proc "system" (this: ^IFunctionReflection, Name: cstring) -> ^IShaderReflectionConstantBuffer, + GetConstantBufferByName: proc "system" (this: ^IFunctionReflection, Name: LPCSTR) -> ^IShaderReflectionConstantBuffer, GetResourceBindingDesc: proc "system" (this: ^IFunctionReflection, ResourceIndex: u32, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, - GetVariableByName: proc "system" (this: ^IFunctionReflection, Name: cstring) -> ^IShaderReflectionVariable, - GetResourceBindingDescByName: proc "system" (this: ^IFunctionReflection, Name: cstring, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, + GetVariableByName: proc "system" (this: ^IFunctionReflection, Name: LPCSTR) -> ^IShaderReflectionVariable, + GetResourceBindingDescByName: proc "system" (this: ^IFunctionReflection, Name: LPCSTR, pDesc: ^SHADER_INPUT_BIND_DESC) -> HRESULT, GetFunctionParameter: proc "system" (this: ^IFunctionReflection, ParameterIndex: i32) -> ^IFunctionParameterReflection, } diff --git a/vendor/directx/d3d_common/d3d_common.odin b/vendor/directx/d3d_common/d3d_common.odin new file mode 100644 index 000000000..af3d09ec9 --- /dev/null +++ b/vendor/directx/d3d_common/d3d_common.odin @@ -0,0 +1,25 @@ +// Declarations shared between D3D versions. +// Based on d3dcommon.h +package d3d_common + +import "core:sys/windows" + +IID :: windows.IID +SIZE_T :: windows.SIZE_T +IUnknown :: windows.IUnknown +IUnknown_VTable :: windows.IUnknown_VTable + +ID3D10Blob_UUID_STRING :: "8BA5FB08-5195-40E2-AC58-0D989C3A0102" +ID3D10Blob_UUID := &IID{0x8BA5FB08, 0x5195, 0x40E2, {0xAC, 0x58, 0x0D, 0x98, 0x9C, 0x3A, 0x01, 0x02}} +ID3D10Blob :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d10blob_vtable: ^ID3D10Blob_VTable, +} +ID3D10Blob_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetBufferPointer: proc "system" (this: ^ID3D10Blob) -> rawptr, + GetBufferSize: proc "system" (this: ^ID3D10Blob) -> SIZE_T, +} + +ID3DBlob :: ID3D10Blob +ID3DBlob_VTable :: ID3D10Blob_VTable diff --git a/vendor/directx/d3d_compiler/d3d_compiler.odin b/vendor/directx/d3d_compiler/d3d_compiler.odin index 6f9f3fe89..85c5cb46c 100644 --- a/vendor/directx/d3d_compiler/d3d_compiler.odin +++ b/vendor/directx/d3d_compiler/d3d_compiler.odin @@ -2,12 +2,14 @@ package directx_d3d_compiler foreign import d3dcompiler "d3dcompiler_47.lib" +import win32 "core:sys/windows" D3DCOMPILER_DLL_A :: "d3dcompiler_47.dll" COMPILER_VERSION :: 47 - import "../dxgi" +import "../d3d11" +import "../d3d_common" BOOL :: dxgi.BOOL IID :: dxgi.IID @@ -16,21 +18,26 @@ HRESULT :: dxgi.HRESULT IUnknown :: dxgi.IUnknown IUnknown_VTable :: dxgi.IUnknown_VTable +ID3DBlob :: d3d_common.ID3DBlob + +LPCSTR :: win32.LPCSTR +LPCWSTR :: win32.LPCWSTR + @(default_calling_convention="system", link_prefix="D3D") foreign d3dcompiler { - ReadFileToBlob :: proc(pFileName: [^]u16, ppContents: ^^ID3DBlob) -> HRESULT --- - WriteBlobToFile :: proc(pBlob: ^ID3DBlob, pFileName: [^]u16, bOverwrite: BOOL) -> HRESULT --- - Compile :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, pSourceName: cstring, pDefines: ^SHADER_MACRO, pInclude: ^ID3DInclude, pEntrypoint: cstring, pTarget: cstring, Flags1: u32, Flags2: u32, ppCode: ^^ID3DBlob, ppErrorMsgs: ^^ID3DBlob) -> HRESULT --- - Compile2 :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, pSourceName: cstring, pDefines: ^SHADER_MACRO, pInclude: ^ID3DInclude, pEntrypoint: cstring, pTarget: cstring, Flags1: u32, Flags2: u32, SecondaryDataFlags: u32, pSecondaryData: rawptr, SecondaryDataSize: SIZE_T, ppCode: ^^ID3DBlob, ppErrorMsgs: ^^ID3DBlob) -> HRESULT --- - CompileFromFile :: proc(pFileName: [^]u16, pDefines: ^SHADER_MACRO, pInclude: ^ID3DInclude, pEntrypoint: cstring, pTarget: cstring, Flags1: u32, Flags2: u32, ppCode: ^^ID3DBlob, ppErrorMsgs: ^^ID3DBlob) -> HRESULT --- - Preprocess :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, pSourceName: cstring, pDefines: ^SHADER_MACRO, pInclude: ^ID3DInclude, ppCodeText: ^^ID3DBlob, ppErrorMsgs: ^^ID3DBlob) -> HRESULT --- + ReadFileToBlob :: proc(pFileName: LPCWSTR, ppContents: ^^ID3DBlob) -> HRESULT --- + WriteBlobToFile :: proc(pBlob: ^ID3DBlob, pFileName: LPCWSTR, bOverwrite: BOOL) -> HRESULT --- + Compile :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, pSourceName: LPCSTR, pDefines: ^SHADER_MACRO, pInclude: ^ID3DInclude, pEntrypoint: LPCSTR, pTarget: LPCSTR, Flags1: u32, Flags2: u32, ppCode: ^^ID3DBlob, ppErrorMsgs: ^^ID3DBlob) -> HRESULT --- + Compile2 :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, pSourceName: LPCSTR, pDefines: ^SHADER_MACRO, pInclude: ^ID3DInclude, pEntrypoint: LPCSTR, pTarget: LPCSTR, Flags1: u32, Flags2: u32, SecondaryDataFlags: u32, pSecondaryData: rawptr, SecondaryDataSize: SIZE_T, ppCode: ^^ID3DBlob, ppErrorMsgs: ^^ID3DBlob) -> HRESULT --- + CompileFromFile :: proc(pFileName: LPCWSTR, pDefines: ^SHADER_MACRO, pInclude: ^ID3DInclude, pEntrypoint: LPCSTR, pTarget: LPCSTR, Flags1: u32, Flags2: u32, ppCode: ^^ID3DBlob, ppErrorMsgs: ^^ID3DBlob) -> HRESULT --- + Preprocess :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, pSourceName: LPCSTR, pDefines: ^SHADER_MACRO, pInclude: ^ID3DInclude, ppCodeText: ^^ID3DBlob, ppErrorMsgs: ^^ID3DBlob) -> HRESULT --- GetDebugInfo :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, ppDebugInfo: ^^ID3DBlob) -> HRESULT --- Reflect :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, pInterface: ^IID, ppReflector: ^rawptr) -> HRESULT --- ReflectLibrary :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, riid: ^IID, ppReflector: ^rawptr) -> HRESULT --- - Disassemble :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, Flags: u32, szComments: cstring, ppDisassembly: ^^ID3DBlob) -> HRESULT --- - DisassembleRegion :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, Flags: u32, szComments: cstring, StartByteOffset: SIZE_T, NumInsts: SIZE_T, pFinishByteOffset: ^SIZE_T, ppDisassembly: ^^ID3DBlob) -> HRESULT --- + Disassemble :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, Flags: u32, szComments: LPCSTR, ppDisassembly: ^^ID3DBlob) -> HRESULT --- + DisassembleRegion :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, Flags: u32, szComments: LPCSTR, StartByteOffset: SIZE_T, NumInsts: SIZE_T, pFinishByteOffset: ^SIZE_T, ppDisassembly: ^^ID3DBlob) -> HRESULT --- CreateLinker :: proc(ppLinker: ^^ID3D11Linker) -> HRESULT --- - LoadModule :: proc(pSrcData: rawptr, cbSrcDataSize: SIZE_T, ppModule: ^^ID3D11Module) -> HRESULT --- + LoadModule :: proc(pSrcData: rawptr, cbSrcDataSize: SIZE_T, ppModule: ^^d3d11.IModule) -> HRESULT --- GetTraceInstructionOffsets :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, Flags: u32, StartInstIndex: SIZE_T, NumInsts: SIZE_T, pOffsets: ^SIZE_T, pTotalInsts: ^SIZE_T) -> HRESULT --- GetInputSignatureBlob :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, ppSignatureBlob: ^^ID3DBlob) -> HRESULT --- GetOutputSignatureBlob :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, ppSignatureBlob: ^^ID3DBlob) -> HRESULT --- @@ -113,40 +120,22 @@ GET_INST_OFFSETS_INCLUDE_NON_EXECUTABLE :: 0x00000001 COMPRESS_SHADER_KEEP_ALL_PARTS :: 0x00000001 SHADER_MACRO :: struct { - Name: cstring, - Definition: cstring, + Name: LPCSTR, + Definition: LPCSTR, } -ID3D10Blob_UUID_STRING :: "8BA5FB08-5195-40E2-AC58-0D989C3A0102" -ID3D10Blob_UUID := &IID{0x8BA5FB08, 0x5195, 0x40E2, {0xAC, 0x58, 0x0D, 0x98, 0x9C, 0x3A, 0x01, 0x02}} -ID3D10Blob :: struct #raw_union { - #subtype iunknown: IUnknown, - using id3d10blob_vtable: ^ID3D10Blob_VTable, -} -ID3D10Blob_VTable :: struct { - using iunknown_vtable: IUnknown_VTable, - GetBufferPointer: proc "system" (this: ^ID3D10Blob) -> rawptr, - GetBufferSize: proc "system" (this: ^ID3D10Blob) -> SIZE_T, -} - - -ID3DBlob :: ID3D10Blob -ID3DBlob_VTable :: ID3D10Blob_VTable - - INCLUDE_TYPE :: enum i32 { INCLUDE_LOCAL = 0, INCLUDE_SYSTEM = 1, _10_INCLUDE_LOCAL = 0, _10_INCLUDE_SYSTEM = 1, - INCLUDE_FORCE_DWORD = 2147483647, } ID3DInclude :: struct { vtable: ^ID3DInclude_VTable, } ID3DInclude_VTable :: struct { - Open: proc "system" (this: ^ID3DInclude, IncludeType: INCLUDE_TYPE, pFileName: cstring, pParentData: rawptr, ppData: ^rawptr, pBytes: ^u32) -> HRESULT, + Open: proc "system" (this: ^ID3DInclude, IncludeType: INCLUDE_TYPE, pFileName: LPCSTR, pParentData: rawptr, ppData: ^rawptr, pBytes: ^u32) -> HRESULT, Close: proc "system" (this: ^ID3DInclude, pData: rawptr) -> HRESULT, } @@ -154,50 +143,21 @@ ID3DInclude_VTable :: struct { D3DCOMPILE_STANDARD_FILE_INCLUDE :: (^ID3DInclude)(uintptr(1)) -ID3D11Module :: struct #raw_union { - #subtype iunknown: IUnknown, - using id3d11module_vtable: ^ID3D11Module_VTable, -} -ID3D11Module_VTable :: struct { - using iunknown_vtable: IUnknown_VTable, - CreateInstance: proc "system" (this: ^ID3D11Module, pNamespace: cstring, ppModuleInstance: ^^ID3D11ModuleInstance) -> HRESULT, -} - - -ID3D11ModuleInstance :: struct #raw_union { - #subtype iunknown: IUnknown, - using id3d11moduleinstance_vtable: ^ID3D11ModuleInstance_VTable, -} -ID3D11ModuleInstance_VTable :: struct { - using iunknown_vtable: IUnknown_VTable, - BindConstantBuffer: proc "system" (this: ^ID3D11ModuleInstance, uSrcSlot: u32, uDstSlot: u32, cbDstOffset: u32) -> HRESULT, - BindConstantBufferByName: proc "system" (this: ^ID3D11ModuleInstance, pName: cstring, uDstSlot: u32, cbDstOffset: u32) -> HRESULT, - BindResource: proc "system" (this: ^ID3D11ModuleInstance, uSrcSlot: u32, uDstSlot: u32, uCount: u32) -> HRESULT, - BindResourceByName: proc "system" (this: ^ID3D11ModuleInstance, pName: cstring, uDstSlot: u32, uCount: u32) -> HRESULT, - BindSampler: proc "system" (this: ^ID3D11ModuleInstance, uSrcSlot: u32, uDstSlot: u32, uCount: u32) -> HRESULT, - BindSamplerByName: proc "system" (this: ^ID3D11ModuleInstance, pName: cstring, uDstSlot: u32, uCount: u32) -> HRESULT, - BindUnorderedAccessView: proc "system" (this: ^ID3D11ModuleInstance, uSrcSlot: u32, uDstSlot: u32, uCount: u32) -> HRESULT, - BindUnorderedAccessViewByName: proc "system" (this: ^ID3D11ModuleInstance, pName: cstring, uDstSlot: u32, uCount: u32) -> HRESULT, - BindResourceAsUnorderedAccessView: proc "system" (this: ^ID3D11ModuleInstance, uSrcSrvSlot: u32, uDstUavSlot: u32, uCount: u32) -> HRESULT, - BindResourceAsUnorderedAccessViewByName: proc "system" (this: ^ID3D11ModuleInstance, pSrvName: cstring, uDstUavSlot: u32, uCount: u32) -> HRESULT, -} - - ID3D11Linker :: struct #raw_union { #subtype iunknown: IUnknown, using id3d11linker_vtable: ^ID3D11Linker_VTable, } ID3D11Linker_VTable :: struct { using iunknown_vtable: IUnknown_VTable, - Link: proc "system" (this: ^ID3D11Linker, pEntry: ^ID3D11ModuleInstance, pEntryName: cstring, pTargetName: cstring, uFlags: u32, ppShaderBlob: ^^ID3DBlob, ppErrorBuffer: ^^ID3DBlob) -> HRESULT, - UseLibrary: proc "system" (this: ^ID3D11Linker, pLibraryMI: ^ID3D11ModuleInstance) -> HRESULT, + Link: proc "system" (this: ^ID3D11Linker, pEntry: ^d3d11.IModuleInstance, pEntryName: LPCSTR, pTargetName: LPCSTR, uFlags: u32, ppShaderBlob: ^^ID3DBlob, ppErrorBuffer: ^^ID3DBlob) -> HRESULT, + UseLibrary: proc "system" (this: ^ID3D11Linker, pLibraryMI: ^d3d11.IModuleInstance) -> HRESULT, AddClipPlaneFromCBuffer: proc "system" (this: ^ID3D11Linker, uCBufferSlot: u32, uCBufferEntry: u32) -> HRESULT, } -pD3DCompile :: #type proc "c" (a0: rawptr, a1: SIZE_T, a2: cstring, a3: ^SHADER_MACRO, a4: ^ID3DInclude, a5: cstring, a6: cstring, a7: u32, a8: u32, a9: ^^ID3DBlob, a10: ^^ID3DBlob) -> HRESULT -pD3DPreprocess :: #type proc "c" (a0: rawptr, a1: SIZE_T, a2: cstring, a3: ^SHADER_MACRO, a4: ^ID3DInclude, a5: ^^ID3DBlob, a6: ^^ID3DBlob) -> HRESULT -pD3DDisassemble :: #type proc "c" (a0: rawptr, a1: SIZE_T, a2: u32, a3: cstring, a4: ^^ID3DBlob) -> HRESULT +pD3DCompile :: #type proc "c" (a0: rawptr, a1: SIZE_T, a2: LPCSTR, a3: ^SHADER_MACRO, a4: ^ID3DInclude, a5: LPCSTR, a6: LPCSTR, a7: u32, a8: u32, a9: ^^ID3DBlob, a10: ^^ID3DBlob) -> HRESULT +pD3DPreprocess :: #type proc "c" (a0: rawptr, a1: SIZE_T, a2: LPCSTR, a3: ^SHADER_MACRO, a4: ^ID3DInclude, a5: ^^ID3DBlob, a6: ^^ID3DBlob) -> HRESULT +pD3DDisassemble :: #type proc "c" (a0: rawptr, a1: SIZE_T, a2: u32, a3: LPCSTR, a4: ^^ID3DBlob) -> HRESULT D3DCOMPILER_STRIP_FLAGS :: distinct bit_set[D3DCOMPILER_STRIP_FLAG; u32] D3DCOMPILER_STRIP_FLAG :: enum u32 { diff --git a/vendor/directx/dxc/dxcapi.odin b/vendor/directx/dxc/dxcapi.odin index 1d3155feb..326d3b3f3 100644 --- a/vendor/directx/dxc/dxcapi.odin +++ b/vendor/directx/dxc/dxcapi.odin @@ -194,7 +194,7 @@ ICompiler :: struct #raw_union { ICompiler_VTable :: struct { using iunknown_vtable: IUnknown_VTable, Compile: proc "system" ( - this: ^ICompiler, + this: ^ICompiler, pSource: ^IBlob, pSourceName: wstring, pEntryPoint: wstring, @@ -206,7 +206,7 @@ ICompiler_VTable :: struct { pIncludeHandler: ^IIncludeHandler, ppResult: ^^IOperationResult) -> HRESULT, Preprocess: proc "system" ( - this: ^ICompiler, + this: ^ICompiler, pSource: ^IBlob, pSourceName: wstring, pArguments: [^]wstring, @@ -303,7 +303,6 @@ DXC_OUT_KIND :: enum u32 { REFLECTION = 8, ROOT_SIGNATURE = 9, EXTRA_OUTPUTS = 10, - FORCE_DWORD = 0xFFFFFFFF, } IResult_UUID_STRING :: "58346CDA-DDE7-4497-9461-6F87AF5E0659" diff --git a/vendor/directx/dxgi/dxgi.odin b/vendor/directx/dxgi/dxgi.odin index 05b3925ff..8865a5f7c 100644 --- a/vendor/directx/dxgi/dxgi.odin +++ b/vendor/directx/dxgi/dxgi.odin @@ -752,7 +752,6 @@ ALPHA_MODE :: enum i32 { PREMULTIPLIED = 1, STRAIGHT = 2, IGNORE = 3, - FORCE_DWORD = -1, } diff --git a/vendor/fontstash/fontstash.odin b/vendor/fontstash/fontstash.odin index 772e379f0..33e7b68de 100644 --- a/vendor/fontstash/fontstash.odin +++ b/vendor/fontstash/fontstash.odin @@ -1,5 +1,5 @@ // An Odin-native source port of [[ Fontstash ; https://github.com/memononen/fontstash ]]. -#+vet !using-param +#+feature using-stmt package fontstash import "base:runtime" diff --git a/vendor/fontstash/fontstash_os.odin b/vendor/fontstash/fontstash_os.odin index e510a4834..d04df044c 100644 --- a/vendor/fontstash/fontstash_os.odin +++ b/vendor/fontstash/fontstash_os.odin @@ -12,12 +12,11 @@ AddFontPath :: proc( path: string, fontIndex: int = 0, ) -> int { - data, ok := os.read_entire_file(path) + data, data_err := os.read_entire_file(path, context.allocator) - if !ok { + if data_err != nil { log.panicf("FONT: failed to read font at %s", path) } return AddFontMem(ctx, name, data, true, fontIndex) -} - +} \ No newline at end of file diff --git a/vendor/ggpo/ggpo.odin b/vendor/ggpo/ggpo.odin index 80b6a0d4a..01e03b6cb 100644 --- a/vendor/ggpo/ggpo.odin +++ b/vendor/ggpo/ggpo.odin @@ -59,11 +59,11 @@ Player :: struct { type: PlayerType, player_num: c.int, using u: struct #raw_union { - local: struct {}, + local: struct {} `raw_union_tag:"type=.LOCAL"`, remote: struct { ip_address: [32]byte, port: u16, - }, + } `raw_union_tag:"type=.REMOTE"`, }, } @@ -132,28 +132,28 @@ Event :: struct { using u: struct #raw_union { connected: struct { player: PlayerHandle, - }, + } `raw_union_tag:"code=.CONNECTED_TO_PEER"`, synchronizing: struct { player: PlayerHandle, count: c.int, total: c.int, - }, + } `raw_union_tag:"code=.SYNCHRONIZING_WITH_PEER"`, synchronized: struct { player: PlayerHandle, - }, + } `raw_union_tag:"code=.SYNCHRONIZED_WITH_PEER"`, disconnected: struct { player: PlayerHandle, - }, + } `raw_union_tag:"code=.DISCONNECTED_FROM_PEER"`, timesync: struct { frames_ahead: c.int, - }, + } `raw_union_tag:"code=.TIMESYNC"`, connection_interrupted: struct { player: PlayerHandle, disconnect_timeout: c.int, - }, + } `raw_union_tag:"code=.connection_interrupted"`, connection_resumed: struct { player: PlayerHandle, - }, + } `raw_union_tag:"code=.connection_resumed"`, }, } diff --git a/vendor/glfw/bindings/bindings.odin b/vendor/glfw/bindings/bindings.odin index abf6c2150..3f2f08237 100644 --- a/vendor/glfw/bindings/bindings.odin +++ b/vendor/glfw/bindings/bindings.odin @@ -212,9 +212,9 @@ foreign glfw { // Functions added in 3.4, Linux links against system glfw so we define these as weak to be able // to check at runtime if they are available. - @(linkage="weak") + @(linkage="strong" when ODIN_OS == .Windows else "weak") GetPlatform :: proc() -> c.int --- - @(linkage="weak") + @(linkage="strong" when ODIN_OS == .Windows else "weak") PlatformSupported :: proc(platform: c.int) -> b32 --- } diff --git a/vendor/kb_text_shape/doc.odin b/vendor/kb_text_shape/doc.odin new file mode 100644 index 000000000..685b0d5a0 --- /dev/null +++ b/vendor/kb_text_shape/doc.odin @@ -0,0 +1,57 @@ +/* + Bindings for [[ Jimmy Lefevre's Text Shape ; https://github.com/JimmyLefevre/kb ]] Unicode text segmentation and OpenType shaping. + + Example: + // Basic + OdinAllocator := context.allocator + + FontData, _ := os.read_entire_file("myfonts.ttf", OdinAllocator) + + Context := kbts.CreateShapeContext(kbts.AllocatorFromOdinAllocator(&OdinAllocator)) + kbts.ShapePushFontFromMemory(Context, FontData, 0) + + kbts.ShapeBegin(Context, .DONT_KNOW, .DONT_KNOW) + kbts.ShapeUtf8(Context, "Let's shape something!", .CODEPOINT_INDEX) + kbts.ShapeEnd(Context) + + CursorX, CursorY: c.int = 0, 0 + for Run in kbts.ShapeRun(Context) { + Run := Run + for Glyph in kbts.GlyphIteratorNext(&Run.Glyphs) { + GlyphX := CursorX + Glyph.OffsetX + GlyphY := CursorY + Glyph.OffsetY + + DisplayGlyph(Glyph.Id, GlyphX, GlyphY) + + CursorX += Glyph.AdvanceX + CursorY += Glyph.AdvanceY + } + } + + Example: + // Font collections + OdinAllocator := context.allocator + + FontData, _ := os.read_entire_file("myfonts.ttf", OdinAllocator) + Font := kbts.FontFromMemory(FontData, 0, kbts.AllocatorFromOdinAllocator(&OdinAllocator)) + + _ = kbts.ShapePushFont(Context, &Font) + + FontCount := kbts.FontCount(FontData) + for FontIndex in 1.. c.int --- + PlaceShapeContext :: proc(Allocator: allocator_function, AllocatorData: rawptr, Memory: rawptr) -> ^shape_context --- + CreateShapeContext :: proc(Allocator: allocator_function, AllocatorData: rawptr) -> ^shape_context --- + DestroyShapeContext :: proc(Context: ^shape_context) --- + ShapePushFont :: proc(Context: ^shape_context, Font: ^font) -> ^font --- + ShapePopFont :: proc(Context: ^shape_context) -> ^font --- + ShapeBegin :: proc(Context: ^shape_context, ParagraphDirection: direction, Language: language) --- + ShapeEnd :: proc(Context: ^shape_context) --- + ShapePushFeature :: proc(Context: ^shape_context, FeatureTag: feature_tag, Value: c.int) --- + ShapePopFeature :: proc(Context: ^shape_context, FeatureTag: feature_tag) -> b32 --- + ShapeCodepoint :: proc(Context: ^shape_context, Codepoint: rune) --- + ShapeCodepointWithUserId :: proc(Context: ^shape_context, Codepoint: rune, UserId: c.int) --- + ShapeError :: proc(Context: ^shape_context) -> shape_error --- + ShapeBeginManualRuns :: proc(Context: ^shape_context) --- + ShapeNextManualRun :: proc(Context: ^shape_context, Direction: direction, Script: script) --- + ShapeEndManualRuns :: proc(Context: ^shape_context) --- + ShapeManualBreak :: proc(Context: ^shape_context) --- +} + +@(require_results) +PlaceShapeContextFixedMemory :: proc "c" (Memory: []byte) -> ^shape_context { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_PlaceShapeContextFixedMemory :: proc(Memory: rawptr, Size: c.int) -> ^shape_context --- + } + return kbts_PlaceShapeContextFixedMemory(raw_data(Memory), c.int(len(Memory))) +} + +ShapePushFontFromMemory :: proc "c" (Context: ^shape_context, Memory: []byte, FontIndex: c.int) -> ^font { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_ShapePushFontFromMemory :: proc(Context: ^shape_context, Memory: rawptr, Size: c.int, FontIndex: c.int) -> ^font --- + } + return kbts_ShapePushFontFromMemory(Context, raw_data(Memory), c.int(len(Memory)), FontIndex) +} + +@(require_results) +ShapeRun :: proc "contextless" (Context: ^shape_context) -> (Run: run, Ok: b32) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_ShapeRun :: proc(Context: ^shape_context, Run: ^run) -> b32 --- + } + Ok = kbts_ShapeRun(Context, &Run) + return +} + +ShapeUtf32 :: proc "c" (Context: ^shape_context, Utf32: []rune) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_ShapeUtf32 :: proc(Context: ^shape_context, Utf32: [^]rune, Length: c.int) --- + } + kbts_ShapeUtf32(Context, raw_data(Utf32), c.int(len(Utf32))) +} +ShapeUtf32WithUserId :: proc "c" (Context: ^shape_context, Utf32: []rune, UserId: c.int, UserIdIncrement: c.int) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_ShapeUtf32WithUserId :: proc(Context: ^shape_context, Utf32: [^]rune, Length: c.int, UserId: c.int, UserIdIncrement: c.int) --- + } + kbts_ShapeUtf32WithUserId(Context, raw_data(Utf32), c.int(len(Utf32)), UserId, UserIdIncrement) +} + +ShapeUtf8 :: proc(Context: ^shape_context, Utf8: string, UserIdGenerationMode: user_id_generation_mode) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_ShapeUtf8 :: proc(Context: ^shape_context, Utf8: [^]byte, Length: c.int, UserIdGenerationMode: user_id_generation_mode) --- + } + kbts_ShapeUtf8(Context, raw_data(Utf8), c.int(len(Utf8)), UserIdGenerationMode) +} +ShapeUtf8WithUserId :: proc(Context: ^shape_context, Utf8: string, UserId: c.int, UserIdGenerationMode: user_id_generation_mode) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_ShapeUtf8WithUserId :: proc(Context: ^shape_context, Utf8: [^]byte, Length: c.int, UserId: c.int, UserIdGenerationMode: user_id_generation_mode) --- + } + kbts_ShapeUtf8WithUserId(Context, raw_data(Utf8), c.int(len(Utf8)), UserId, UserIdGenerationMode) +} + @(default_calling_convention="c", link_prefix="kbts_", require_results) foreign lib { - FeatureTagToId :: proc(Tag: feature_tag) -> feature_id --- - FeatureOverride :: proc(Id: feature_id, Alternate: b32, Value: u32) -> feature_override --- - FeatureOverrideFromTag :: proc(Tag: feature_tag, Alternate: b32, Value: u32) -> feature_override --- - GlyphConfigOverrideFeature :: proc(Config: ^glyph_config, Id: feature_id, Alternate: b32, Value: u32) -> b32 --- - GlyphConfigOverrideFeatureFromTag :: proc(Config: ^glyph_config, Tag: feature_tag, Alternate: b32, Value: u32) -> b32 --- + ShapeCurrentCodepointsIterator :: proc(Context: ^shape_context) -> shape_codepoint_iterator --- + ShapeCodepointIteratorIsValid :: proc(It: ^shape_codepoint_iterator) -> b32 --- + ShapeGetShapeCodepoint :: proc(Context: ^shape_context, CodepointIndex: c.int, Codepoint: ^shape_codepoint) -> b32 --- +} - FontIsValid :: proc(Font: ^font) -> b32 --- - SizeOfShapeState :: proc(Font: ^font) -> un --- +@(require_results) +ShapeCodepointIteratorNext :: proc "contextless" (It: ^shape_codepoint_iterator) -> (Codepoint: shape_codepoint, CodepointIndex: c.int, Ok: b32) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_ShapeCodepointIteratorNext :: proc(It: ^shape_codepoint_iterator, Codepoint: ^shape_codepoint, CodepointIndex: ^c.int) -> b32 --- + } + Ok = kbts_ShapeCodepointIteratorNext(It, &Codepoint, &CodepointIndex) + return +} - ResetShapeState :: proc(State: ^shape_state) --- - ShapeConfig :: proc(Font: ^font, Script: script, Language: language) -> shape_config --- - ShaperIsComplex :: proc(Shaper: shaper) -> b32 --- + +// +// Direct API +// +@(default_calling_convention="c", link_prefix="kbts_", require_results) +foreign lib { + FreeFont :: proc(Font: ^font) --- + FontIsValid :: proc(Font: ^font) -> b32 --- + PlaceBlob :: proc(Font: ^font, State: ^load_font_state, ScratchMemory: rawptr, OutputMemory: rawptr) -> load_font_error --- + GetFontInfo :: proc(Font: ^font, Info: ^font_info) --- + + // A shape_config is a bag of pre-computed data for a specific shaping setup. + SizeOfShapeConfig :: proc(Font: ^font, Script: script, Language: language) -> b32 --- + PlaceShapeConfig :: proc(Font: ^font, Script: script, Language: language, Memory: rawptr) -> ^shape_config --- + CreateShapeConfig :: proc(Font: ^font, Script: script, Language: language, Allocator: allocator_function, AllocatorData: rawptr) -> ^shape_config --- + DestroyShapeConfig :: proc(Config: ^shape_config) --- + + // A glyph_storage holds and recycles glyph data. + InitializeGlyphStorage :: proc(Storage: ^glyph_storage, Allocator: allocator_function, AllocatorData: rawptr) -> b32 --- + InitializeGlyphStorageFixedMemory :: proc(Storage: ^glyph_storage, Memory: rawptr, MemorySize: c.int) -> b32 --- + PushGlyph :: proc(Storage: ^glyph_storage, Font: ^font, Codepoint: rune, Config: ^glyph_config, UserId: c.int) -> ^glyph --- + ClearActiveGlyphs :: proc(Storage: ^glyph_storage) --- + FreeAllGlyphs :: proc(Storage: ^glyph_storage) --- + CodepointToGlyph :: proc(Font: ^font, Codepoint: rune, Config: ^glyph_config, UserId: c.int) -> glyph --- + CodepointToGlyphId :: proc(Font: ^font, Codepoint: rune) -> c.int --- + ActiveGlyphIterator :: proc(Storage: ^glyph_storage) -> glyph_iterator --- + + // A glyph_config specifies glyph-specific shaping parameters. + // A single glyph_config can be shared by multiple glyphs. + + DestroyGlyphConfig :: proc(Config: ^glyph_config) --- +} + +@(require_results) +LoadFont :: proc "contextless" (Font: ^font, State: ^load_font_state, FontData: []byte, FontIndex: c.int) -> (ScratchSize, OutputSize: c.int, Err: load_font_error) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_LoadFont :: proc(Font: ^font, State: ^load_font_state, FontData: rawptr, FontDataSize: c.int, FontIndex: c.int, ScratchSize_: ^c.int, OutputSize_: ^c.int) -> load_font_error --- + } + Err = kbts_LoadFont(Font, State, raw_data(FontData), c.int(len(FontData)), FontIndex, &ScratchSize, &OutputSize) + return +} + +@(require_results) +FontCount :: proc "c" (FileData: []byte) -> c.int { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_FontCount :: proc(FileData: rawptr, FileSize: c.int) -> c.int --- + } + return kbts_FontCount(raw_data(FileData), c.int(len(FileData))) +} + +@(require_results) +FontFromMemory :: proc "c" (FileData: []byte, FontIndex: c.int, Allocator: allocator_function, AllocatorData: rawptr) -> font { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_FontFromMemory :: proc(FileData: rawptr, FileSize: c.int, FontIndex: c.int, Allocator: allocator_function, AllocatorData: rawptr) -> font --- + } + return kbts_FontFromMemory(raw_data(FileData), c.int(len(FileData)), FontIndex, Allocator, AllocatorData) +} + + +@(require_results) +ShapeDirect :: proc "contextless" (Config: ^shape_config, Storage: ^glyph_storage, RunDirection: direction, Allocator: allocator_function, AllocatorData: rawptr) -> (Output: glyph_iterator, Err: shape_error) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_ShapeDirect :: proc(Config: ^shape_config, Storage: ^glyph_storage, RunDirection: direction, Allocator: allocator_function, AllocatorData: rawptr, Output: ^glyph_iterator) -> shape_error --- + } + Err = kbts_ShapeDirect(Config, Storage, RunDirection, Allocator, AllocatorData, &Output) + return +} + +@(require_results) +ShapeDirectFixedMemory :: proc "contextless" (Config: ^shape_config, Storage: ^glyph_storage, RunDirection: direction, Memory: rawptr, MemorySize: c.int) -> (Output: glyph_iterator, Err: shape_error) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_ShapeDirectFixedMemory :: proc(Config: ^shape_config, Storage: ^glyph_storage, RunDirection: direction, Memory: rawptr, MemorySize: c.int, Output: ^glyph_iterator) -> shape_error --- + } + Err = kbts_ShapeDirectFixedMemory(Config, Storage, RunDirection, Memory, MemorySize, &Output) + return +} + + +@(require_results) +SizeOfGlyphConfig :: proc "c" (Overrides: []feature_override) -> c.int { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_SizeOfGlyphConfig :: proc(Overrides: [^]feature_override, OverrideCount: c.int) -> c.int --- + } + return kbts_SizeOfGlyphConfig(raw_data(Overrides), c.int(len(Overrides))) +} + +@(require_results) +PlaceGlyphConfig :: proc "c" (Overrides: []feature_override, Memory: rawptr) -> ^glyph_config { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_PlaceGlyphConfig :: proc(Overrides: [^]feature_override, OverrideCount: c.int, Memory: rawptr) -> ^glyph_config --- + } + return kbts_PlaceGlyphConfig(raw_data(Overrides), c.int(len(Overrides)), Memory) +} + +@(require_results) +CreateGlyphConfig :: proc(Overrides: []feature_override, Allocator: allocator_function, AllocatorData: rawptr) -> ^glyph_config { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_CreateGlyphConfig :: proc(Overrides: [^]feature_override, OverrideCount: c.int, Allocator: allocator_function, AllocatorData: rawptr) -> ^glyph_config --- + } + return kbts_CreateGlyphConfig(raw_data(Overrides), c.int(len(Overrides)), Allocator, AllocatorData) +} + +@(default_calling_convention="c", link_prefix="kbts_", require_results) +foreign lib { + GlyphIteratorIsValid :: proc(It: ^glyph_iterator) -> b32 --- +} + +@(require_results) +GlyphIteratorNext :: proc "contextless" (It: ^glyph_iterator) -> (Glyph: ^glyph, Ok: b32) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_GlyphIteratorNext :: proc(It: ^glyph_iterator, Glyph: ^^glyph) -> b32 --- + } + Ok = kbts_GlyphIteratorNext(It, &Glyph) + return +} + + +// +// Segmentation +// +@(default_calling_convention="c", link_prefix="kbts_", require_results) +foreign lib { + BreakBegin :: proc(State: ^break_state, ParagraphDirection: direction, JapaneseLineBreakStyle: japanese_line_break_style, ConfigFlags: break_config_flags) --- + BreakAddCodepoint :: proc(State: ^break_state, Codepoint: rune, PositionIncrement: c.int, EndOfText: b32) --- + BreakEnd :: proc(State: ^break_state) --- +} + +@(require_results) +Break :: proc "contextless" (State: ^break_state) -> (Break: break_type, Ok: b32) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_Break :: proc(State: ^break_state, Break: ^break_type) -> b32 --- + } + Ok = kbts_Break(State, &Break) + return +} + + +BreakEntireString :: proc "c" (Direction: direction, JapaneseLineBreakStyle: japanese_line_break_style, ConfigFlags: break_config_flags, + Input: []byte, InputFormat: text_format, + Breaks: []break_type, BreakCount: ^c.int, + BreakFlags: []break_flags, BreakFlagCount: ^c.int) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_BreakEntireString :: proc(Direction: direction, JapaneseLineBreakStyle: japanese_line_break_style, ConfigFlags: break_config_flags, + Input: rawptr, InputSizeInBytes: c.int, InputFormat: text_format, + Breaks: [^]break_type, BreakCapacity: c.int, BreakCount: ^c.int, + BreakFlags: [^]break_flags, BreakFlagCapacity: c.int, BreakFlagCount: ^c.int) --- + } + kbts_BreakEntireString(Direction, JapaneseLineBreakStyle, ConfigFlags, raw_data(Input), c.int(len(Input)), InputFormat, raw_data(Breaks), c.int(len(Breaks)), BreakCount, raw_data(BreakFlags), c.int(len(BreakFlags)), BreakFlagCount) +} + +BreakEntireStringUtf32 :: proc "c" (Direction: direction, JapaneseLineBreakStyle: japanese_line_break_style, ConfigFlags: break_config_flags, + Utf32: []rune, + Breaks: []break_type, BreakCount: ^c.int, + BreakFlags: []break_flags, BreakFlagCount: ^c.int) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_BreakEntireStringUtf32 :: proc(Direction: direction, JapaneseLineBreakStyle: japanese_line_break_style, ConfigFlags: break_config_flags, + Utf32: [^]rune, Utf32Count: c.int, + Breaks: [^]break_type, BreakCapacity: c.int, BreakCount: ^c.int, + BreakFlags: [^]break_flags, BreakFlagCapacity: c.int, BreakFlagCount: ^c.int) --- + } + kbts_BreakEntireStringUtf32(Direction, JapaneseLineBreakStyle, ConfigFlags, raw_data(Utf32), c.int(len(Utf32)), raw_data(Breaks), c.int(len(Breaks)), BreakCount, raw_data(BreakFlags), c.int(len(BreakFlags)), BreakFlagCount) +} + +BreakEntireStringUtf8 :: proc "c" (Direction: direction, JapaneseLineBreakStyle: japanese_line_break_style, ConfigFlags: break_config_flags, + Utf8: string, + Breaks: []break_type, BreakCount: ^c.int, + BreakFlags: []break_flags, BreakFlagCount: ^c.int) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_BreakEntireStringUtf8 :: proc(Direction: direction, JapaneseLineBreakStyle: japanese_line_break_style, ConfigFlags: break_config_flags, + Utf8: [^]byte, Utf8Length: c.int, + Breaks: [^]break_type, BreakCapacity: c.int, BreakCount: ^c.int, + BreakFlags: [^]break_flags, BreakFlagCapacity: c.int, BreakFlagCount: ^c.int) --- + } + kbts_BreakEntireStringUtf8(Direction, JapaneseLineBreakStyle, ConfigFlags, raw_data(Utf8), c.int(len(Utf8)), raw_data(Breaks), c.int(len(Breaks)), BreakCount, raw_data(BreakFlags), c.int(len(BreakFlags)), BreakFlagCount) +} + + + +@(default_calling_convention="c", link_prefix="kbts_", require_results) +foreign lib { + // Quick test for font support of a sequence of codepoints. + FontCoverageTestBegin :: proc(Test: ^font_coverage_test, Font: ^font) --- + FontCoverageTestCodepoint :: proc(Test: ^font_coverage_test, Codepoint: rune) --- + FontCoverageTestEnd :: proc(Test: ^font_coverage_test) -> b32 --- + + ScriptDirection :: proc(Script: script) -> direction --- + ScriptIsComplex :: proc(Script: script) -> b32 --- ScriptTagToScript :: proc(Tag: script_tag) -> script --- - - Shape :: proc(State: ^shape_state, Config: ^shape_config, - MainDirection, RunDirection: direction, - Glyphs: [^]glyph, GlyphCount: ^u32, GlyphCapacity: u32) -> b32 --- - - Cursor :: proc(Direction: direction) -> cursor --- - BeginBreak :: proc(State: ^break_state, MainDirection: direction, JapaneseLineBreakStyle: japanese_line_break_style) --- - BreakStateIsValid :: proc(State: ^break_state) -> b32 --- - BreakAddCodepoint :: proc(State: ^break_state, Codepoint: rune, PositionIncrement: u32, EndOfText: b32) --- - BreakFlush :: proc(State: ^break_state) --- - Break :: proc(State: ^break_state, Break: ^break_type) -> b32 --- - CodepointToGlyph :: proc(Font: ^font, Codepoint: rune) -> glyph --- - InferScript :: proc(Direction: ^direction, Script: ^script, GlyphScript: script) --- -} - - -@(require_results) -GlyphConfig :: proc "c" (FeatureOverrides: []feature_override) -> glyph_config { - @(default_calling_convention="c", require_results) - foreign lib { - kbts_GlyphConfig :: proc(FeatureOverrides: [^]feature_override, FeatureOverrideCount: u32) -> glyph_config --- - } - return kbts_GlyphConfig(raw_data(FeatureOverrides), u32(len(FeatureOverrides))) - } @(require_results) -EmptyGlyphConfig :: proc(FeatureOverrides: []feature_override) -> glyph_config { - @(default_calling_convention="c", require_results) - foreign lib { - kbts_EmptyGlyphConfig :: proc(FeatureOverrides: [^]feature_override, FeatureOverrideCapacity: u32) -> glyph_config --- - } - return kbts_EmptyGlyphConfig(raw_data(FeatureOverrides), u32(len(FeatureOverrides))) +EncodeUtf8 :: proc "c" (Codepoint: rune) -> (Encoded: [4]u8, EncodedLength: c.int, Valid: b32) { + return expand_values(kbts_EncodeUtf8(Codepoint)) +} + +@(default_calling_convention="c", require_results) +foreign lib { + kbts_EncodeUtf8 :: proc(Codepoint: rune) -> encode_utf8 --- } @(require_results) -PlaceShapeState :: proc "c" (Memory: []byte) -> ^shape_state { - @(default_calling_convention="c", require_results) - foreign lib { - kbts_PlaceShapeState :: proc(Address: rawptr, Size: un) -> ^shape_state --- - } - - return kbts_PlaceShapeState(raw_data(Memory), un(len(Memory))) -} - -@(require_results) -DecodeUtf8 :: proc "contextless" (String: string) -> (Codepoint: rune, SourceCharactersConsumed: u32, Valid: bool) { - decode :: struct { - Codepoint: rune, - - SourceCharactersConsumed: u32, - Valid: b32, - } - +DecodeUtf8 :: proc "c" (Utf8: string) -> decode { @(default_calling_convention="c", require_results) foreign lib { kbts_DecodeUtf8 :: proc(Utf8: [^]byte, Length: un) -> decode --- } - - Decode := kbts_DecodeUtf8(raw_data(String), un(len(String))) - return Decode.Codepoint, Decode.SourceCharactersConsumed, bool(Decode.Valid) + return kbts_DecodeUtf8(raw_data(Utf8), un(len(Utf8))) } - +// This is a quick guess that stops at the first glyph that has a strong script/direction associated to it. +// It is convenient, but only works if you are sure your input text is mono-script and mono-direction. @(require_results) -ReadFontHeader :: proc "c" (Font: ^font, Data: []byte) -> un { +GuessTextProperties :: proc "contextless" (Text: []byte, Format: text_format) -> (Direction: direction, Script: script) { @(default_calling_convention="c", require_results) foreign lib { - kbts_ReadFontHeader :: proc(Font: ^font, Data: rawptr, Size: un) -> un --- + kbts_GuessTextProperties :: proc(Text: rawptr, TextSizeInBytes: c.int, Format: text_format, Direction: ^direction, Script: ^script) --- } - - return kbts_ReadFontHeader(Font, raw_data(Data), un(len(Data))) -} -@(require_results) -ReadFontData :: proc "c" (Font: ^font, Scratch: []byte) -> un { - @(default_calling_convention="c", require_results) - foreign lib { - kbts_ReadFontData :: proc(Font: ^font, Scratch: rawptr, ScratchSize: un) -> un --- - } - - return kbts_ReadFontData(Font, raw_data(Scratch), un(len(Scratch))) -} -@(require_results) -PostReadFontInitialize :: proc "c" (Font: ^font, Memory: []byte) -> b32 { - @(default_calling_convention="c", require_results) - foreign lib { - kbts_PostReadFontInitialize :: proc(Font: ^font, Memory: rawptr, MemorySize: un) -> b32 --- - } - - return kbts_PostReadFontInitialize(Font, raw_data(Memory), un(len(Memory))) -} - -@(require_results) -FontFromMemory :: proc(Data: []byte, allocator: mem.Allocator) -> (Result: font, Err: mem.Allocator_Error) { - ClonedData := mem.make_aligned([]byte, len(Data), 16, allocator) or_return - defer if Err != nil { - delete(ClonedData, allocator) - } - copy(ClonedData, Data) - - ScratchSize := ReadFontHeader(&Result, ClonedData) - Scratch := mem.make_aligned([]byte, ScratchSize, 16, allocator) or_return - MemorySize := ReadFontData(&Result, Scratch) - - Memory := Scratch - if MemorySize > ScratchSize { - delete(Scratch, allocator) - Memory = mem.make_aligned([]byte, MemorySize, 16, allocator) or_return - } - defer if Err != nil { - delete(Memory, allocator) - } - - _ = PostReadFontInitialize(&Result, Memory) - return - -} -FreeFont :: proc(Font: ^font, allocator: mem.Allocator) { - free(Font.FileBase, allocator) - free(Font.GlyphLookupMatrix, allocator) - Font^ = {} -} - -@(require_results) -CreateShapeState :: proc(Font: ^font, allocator: mem.Allocator) -> (Result: ^shape_state, Err: mem.Allocator_Error) { - Size := SizeOfShapeState(Font) - Memory := mem.make_aligned([]byte, Size, 16, allocator) or_return - Result = PlaceShapeState(Memory) - return -} -FreeShapeState :: proc(State: ^shape_state, allocator: mem.Allocator) { - free(State, allocator) -} - -@(require_results) -PositionGlyph :: proc(Cursor: ^cursor, Glyph: ^glyph) -> (X, Y: i32) { - @(default_calling_convention="c", require_results) - foreign lib { - kbts_PositionGlyph :: proc(Cursor: ^cursor, Glyph: ^glyph, X, Y: ^i32) --- - } - kbts_PositionGlyph(Cursor, Glyph, &X, &Y) + kbts_GuessTextProperties(raw_data(Text), c.int(len(Text)), Format, &Direction, &Script) return } +// This is a quick guess that stops at the first glyph that has a strong script/direction associated to it. +// It is convenient, but only works if you are sure your input text is mono-script and mono-direction. @(require_results) -ShapeDynamic :: proc(State: ^shape_state, Config: ^shape_config, - MainDirection, RunDirection: direction, - Glyphs: ^[dynamic]glyph) -> b32 { - GlyphCount := u32(len(Glyphs^)) - GlyphCapacity := u32(cap(Glyphs^)) - Res := Shape(State, Config, MainDirection, RunDirection, raw_data(Glyphs^), &GlyphCount, GlyphCapacity) - resize(Glyphs, int(GlyphCount)) - return Res -} \ No newline at end of file +GuessTextPropertiesUtf32 :: proc "contextless" (Utf32: []rune) -> (Direction: direction, Script: script) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_GuessTextPropertiesUtf32 :: proc(Utf32: [^]rune, Utf32Count: c.int, Direction: ^direction, Script: ^script) --- + } + kbts_GuessTextPropertiesUtf32(raw_data(Utf32), c.int(len(Utf32)), &Direction, &Script) + return +} + +// This is a quick guess that stops at the first glyph that has a strong script/direction associated to it. +// It is convenient, but only works if you are sure your input text is mono-script and mono-direction._results) +@(require_results) +GuessTextPropertiesUtf8 :: proc "contextless" (Utf8: string) -> (Direction: direction, Script: script) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_GuessTextPropertiesUtf8 :: proc(Utf8: cstring, Utf8Length: c.int, Direction: ^direction, Script: ^script) --- + } + kbts_GuessTextPropertiesUtf8(cstring(raw_data(Utf8)), c.int(len(Utf8)), &Direction, &Script) + return +} + + + + +@(require_results) +AllocatorFromOdinAllocator :: proc "contextless" (allocator: ^runtime.Allocator) -> (Allocator: allocator_function, AllocatorData: rawptr) { + allocator_function :: proc "c" (Data: rawptr, Op: ^allocator_op) { + if Data == nil { + return + } + context = runtime.default_context() + context.allocator = (^runtime.Allocator)(Data)^ + + switch Op.Kind { + case .NONE: + return + case .ALLOCATE: + res, _ := runtime.mem_alloc(int(Op.Allocate.Size), runtime.DEFAULT_ALIGNMENT) + Op.Allocate.Pointer = raw_data(res) + Op.Allocate.Size = u32(len(res)) + case .FREE: + _ = runtime.mem_free(Op.Free.Pointer) + } + } + + return allocator_function, rawptr(allocator) +} diff --git a/vendor/kb_text_shape/kb_text_shape_types.odin b/vendor/kb_text_shape/kb_text_shape_types.odin index 929af64d2..fa3c47f85 100644 --- a/vendor/kb_text_shape/kb_text_shape_types.odin +++ b/vendor/kb_text_shape/kb_text_shape_types.odin @@ -17,743 +17,693 @@ un :: distinct ( // i64 // ) -joining_feature :: enum u8 { - NONE, - ISOL, - FINA, - FIN2, - FIN3, - MEDI, - MED2, - INIT, -} - -reph_position :: enum u8 { - AFTER_POST, - BEFORE_POST, - BEFORE_SUBJOINED, - AFTER_SUBJOINED, - AFTER_MAIN, -} - -reph_encoding :: enum u8 { - IMPLICIT, - EXPLICIT, - LOGICAL_REPHA, - VISUAL_REPHA, -} - -syllabic_position :: enum u8 { - NONE, - - RA_TO_BECOME_REPH, - - PREBASE_MATRA, - PREBASE_CONSONANT, - - SYLLABLE_BASE, - AFTER_MAIN, - - ABOVEBASE_CONSONANT, - - BEFORE_SUBJOINED, - BELOWBASE_CONSONANT, - AFTER_SUBJOINED, - - BEFORE_POST, - POSTBASE_CONSONANT, - AFTER_POST, - - FINAL_CONSONANT, - SMVD, -} language :: enum u32 { DONT_KNOW = 0, - A_HMAO = ('H' | 'M'<<8 | 'D'<<16 | ' '<<24), - AARI = ('A' | 'R'<<8 | 'I'<<16 | ' '<<24), - ABAZA = ('A' | 'B'<<8 | 'A'<<16 | ' '<<24), - ABKHAZIAN = ('A' | 'B'<<8 | 'K'<<16 | ' '<<24), - ACHI = ('A' | 'C'<<8 | 'R'<<16 | ' '<<24), - ACHOLI = ('A' | 'C'<<8 | 'H'<<16 | ' '<<24), - ADYGHE = ('A' | 'D'<<8 | 'Y'<<16 | ' '<<24), - AFAR = ('A' | 'F'<<8 | 'R'<<16 | ' '<<24), - AFRIKAANS = ('A' | 'F'<<8 | 'K'<<16 | ' '<<24), - AGAW = ('A' | 'G'<<8 | 'W'<<16 | ' '<<24), - AITON = ('A' | 'I'<<8 | 'O'<<16 | ' '<<24), - AKAN = ('A' | 'K'<<8 | 'A'<<16 | ' '<<24), - ALBANIAN = ('S' | 'Q'<<8 | 'I'<<16 | ' '<<24), - ALSATIAN = ('A' | 'L'<<8 | 'S'<<16 | ' '<<24), - ALTAI = ('A' | 'L'<<8 | 'T'<<16 | ' '<<24), - ALUO = ('Y' | 'N'<<8 | 'A'<<16 | ' '<<24), - AMERICAN_PHONETIC = ('A' | 'P'<<8 | 'P'<<16 | 'H'<<24), - AMHARIC = ('A' | 'M'<<8 | 'H'<<16 | ' '<<24), - ANGLO_SAXON = ('A' | 'N'<<8 | 'G'<<16 | ' '<<24), - ARABIC = ('A' | 'R'<<8 | 'A'<<16 | ' '<<24), - ARAGONESE = ('A' | 'R'<<8 | 'G'<<16 | ' '<<24), - ARAKANESE = ('A' | 'R'<<8 | 'K'<<16 | ' '<<24), - ARAKWAL = ('R' | 'K'<<8 | 'W'<<16 | ' '<<24), - ARMENIAN = ('H' | 'Y'<<8 | 'E'<<16 | ' '<<24), - ARMENIAN_EAST = ('H' | 'Y'<<8 | 'E'<<16 | '0'<<24), - AROMANIAN = ('R' | 'U'<<8 | 'P'<<16 | ' '<<24), - ARPITAN = ('F' | 'R'<<8 | 'P'<<16 | ' '<<24), - ASSAMESE = ('A' | 'S'<<8 | 'M'<<16 | ' '<<24), - ASTURIAN = ('A' | 'S'<<8 | 'T'<<16 | ' '<<24), - ATHAPASKAN = ('A' | 'T'<<8 | 'H'<<16 | ' '<<24), - ATSINA = ('A' | 'T'<<8 | 'S'<<16 | ' '<<24), - AVAR = ('A' | 'V'<<8 | 'R'<<16 | ' '<<24), - AVATIME = ('A' | 'V'<<8 | 'N'<<16 | ' '<<24), - AWADHI = ('A' | 'W'<<8 | 'A'<<16 | ' '<<24), - AYMARA = ('A' | 'Y'<<8 | 'M'<<16 | ' '<<24), - AZERBAIDJANI = ('A' | 'Z'<<8 | 'E'<<16 | ' '<<24), - BADAGA = ('B' | 'A'<<8 | 'D'<<16 | ' '<<24), - BAGHELKHANDI = ('B' | 'A'<<8 | 'G'<<16 | ' '<<24), - BAGRI = ('B' | 'G'<<8 | 'Q'<<16 | ' '<<24), - BALANTE = ('B' | 'L'<<8 | 'N'<<16 | ' '<<24), - BALINESE = ('B' | 'A'<<8 | 'N'<<16 | ' '<<24), - BALKAR = ('B' | 'A'<<8 | 'L'<<16 | ' '<<24), - BALTI = ('B' | 'L'<<8 | 'T'<<16 | ' '<<24), - BALUCHI = ('B' | 'L'<<8 | 'I'<<16 | ' '<<24), - BAMBARA = ('B' | 'M'<<8 | 'B'<<16 | ' '<<24), - BAMILEKE = ('B' | 'M'<<8 | 'L'<<16 | ' '<<24), - BANDA = ('B' | 'A'<<8 | 'D'<<16 | '0'<<24), - BANDJALANG = ('B' | 'D'<<8 | 'Y'<<16 | ' '<<24), - BANGLA = ('B' | 'E'<<8 | 'N'<<16 | ' '<<24), - BASHKIR = ('B' | 'S'<<8 | 'H'<<16 | ' '<<24), - BASQUE = ('E' | 'U'<<8 | 'Q'<<16 | ' '<<24), - BATAK = ('B' | 'T'<<8 | 'K'<<16 | ' '<<24), - BATAK_ALAS_KLUET = ('B' | 'T'<<8 | 'Z'<<16 | ' '<<24), - BATAK_ANGKOLA = ('A' | 'K'<<8 | 'B'<<16 | ' '<<24), - BATAK_DAIRI = ('B' | 'T'<<8 | 'D'<<16 | ' '<<24), - BATAK_KARO = ('B' | 'T'<<8 | 'X'<<16 | ' '<<24), - BATAK_MANDAILING = ('B' | 'T'<<8 | 'M'<<16 | ' '<<24), - BATAK_SIMALUNGUN = ('B' | 'T'<<8 | 'S'<<16 | ' '<<24), - BATAK_TOBA = ('B' | 'B'<<8 | 'C'<<16 | ' '<<24), - BAULE = ('B' | 'A'<<8 | 'U'<<16 | ' '<<24), - BAVARIAN = ('B' | 'A'<<8 | 'R'<<16 | ' '<<24), - BELARUSIAN = ('B' | 'E'<<8 | 'L'<<16 | ' '<<24), - BEMBA = ('B' | 'E'<<8 | 'M'<<16 | ' '<<24), - BENCH = ('B' | 'C'<<8 | 'H'<<16 | ' '<<24), - BERBER = ('B' | 'B'<<8 | 'R'<<16 | ' '<<24), - BETI = ('B' | 'T'<<8 | 'I'<<16 | ' '<<24), - BETTE_KURUMA = ('X' | 'U'<<8 | 'B'<<16 | ' '<<24), - BHILI = ('B' | 'H'<<8 | 'I'<<16 | ' '<<24), - BHOJPURI = ('B' | 'H'<<8 | 'O'<<16 | ' '<<24), - BHUTANESE = ('D' | 'Z'<<8 | 'N'<<16 | ' '<<24), - BIBLE_CREE = ('B' | 'C'<<8 | 'R'<<16 | ' '<<24), - BIKOL = ('B' | 'I'<<8 | 'K'<<16 | ' '<<24), - BILEN = ('B' | 'I'<<8 | 'L'<<16 | ' '<<24), - BISHNUPRIYA_MANIPURI = ('B' | 'P'<<8 | 'Y'<<16 | ' '<<24), - BISLAMA = ('B' | 'I'<<8 | 'S'<<16 | ' '<<24), - BLACKFOOT = ('B' | 'K'<<8 | 'F'<<16 | ' '<<24), - BODO = ('B' | 'R'<<8 | 'X'<<16 | ' '<<24), - BOSNIAN = ('B' | 'O'<<8 | 'S'<<16 | ' '<<24), - BOUYEI = ('P' | 'C'<<8 | 'C'<<16 | ' '<<24), - BRAHUI = ('B' | 'R'<<8 | 'H'<<16 | ' '<<24), - BRAJ_BHASHA = ('B' | 'R'<<8 | 'I'<<16 | ' '<<24), - BRETON = ('B' | 'R'<<8 | 'E'<<16 | ' '<<24), - BUGIS = ('B' | 'U'<<8 | 'G'<<16 | ' '<<24), - BULGARIAN = ('B' | 'G'<<8 | 'R'<<16 | ' '<<24), - BUMTHANGKHA = ('K' | 'J'<<8 | 'Z'<<16 | ' '<<24), - BURMESE = ('B' | 'R'<<8 | 'M'<<16 | ' '<<24), - BURUSHASKI = ('B' | 'S'<<8 | 'K'<<16 | ' '<<24), - CAJUN_FRENCH = ('F' | 'R'<<8 | 'C'<<16 | ' '<<24), - CARRIER = ('C' | 'R'<<8 | 'R'<<16 | ' '<<24), - CATALAN = ('C' | 'A'<<8 | 'T'<<16 | ' '<<24), - CAYUGA = ('C' | 'A'<<8 | 'Y'<<16 | ' '<<24), - CEBUANO = ('C' | 'E'<<8 | 'B'<<16 | ' '<<24), - CENTRAL_YUPIK = ('E' | 'S'<<8 | 'U'<<16 | ' '<<24), - CHAHA_GURAGE = ('C' | 'H'<<8 | 'G'<<16 | ' '<<24), - CHAMORRO = ('C' | 'H'<<8 | 'A'<<16 | ' '<<24), - CHATTISGARHI = ('C' | 'H'<<8 | 'H'<<16 | ' '<<24), - CHECHEN = ('C' | 'H'<<8 | 'E'<<16 | ' '<<24), - CHEROKEE = ('C' | 'H'<<8 | 'R'<<16 | ' '<<24), - CHEYENNE = ('C' | 'H'<<8 | 'Y'<<16 | ' '<<24), - CHICHEWA = ('C' | 'H'<<8 | 'I'<<16 | ' '<<24), - CHIGA = ('C' | 'G'<<8 | 'G'<<16 | ' '<<24), - CHIMILA = ('C' | 'B'<<8 | 'G'<<16 | ' '<<24), - CHIN = ('Q' | 'I'<<8 | 'N'<<16 | ' '<<24), - CHINANTEC = ('C' | 'C'<<8 | 'H'<<16 | 'N'<<24), - CHINESE_PHONETIC = ('Z' | 'H'<<8 | 'P'<<16 | ' '<<24), - CHINESE_SIMPLIFIED = ('Z' | 'H'<<8 | 'S'<<16 | ' '<<24), - CHINESE_TRADITIONAL = ('Z' | 'H'<<8 | 'T'<<16 | ' '<<24), - CHINESE_TRADITIONAL_HONG_KONG = ('Z' | 'H'<<8 | 'H'<<16 | ' '<<24), - CHINESE_TRADITIONAL_MACAO = ('Z' | 'H'<<8 | 'T'<<16 | 'M'<<24), - CHIPEWYAN = ('C' | 'H'<<8 | 'P'<<16 | ' '<<24), - CHITTAGONIAN = ('C' | 'T'<<8 | 'G'<<16 | ' '<<24), - CHOCTAW = ('C' | 'H'<<8 | 'O'<<16 | ' '<<24), - CHUKCHI = ('C' | 'H'<<8 | 'K'<<16 | ' '<<24), - CHURCH_SLAVONIC = ('C' | 'S'<<8 | 'L'<<16 | ' '<<24), - CHUUKESE = ('C' | 'H'<<8 | 'K'<<16 | '0'<<24), - CHUVASH = ('C' | 'H'<<8 | 'U'<<16 | ' '<<24), - COMORIAN = ('C' | 'M'<<8 | 'R'<<16 | ' '<<24), - COMOX = ('C' | 'O'<<8 | 'O'<<16 | ' '<<24), - COPTIC = ('C' | 'O'<<8 | 'P'<<16 | ' '<<24), - CORNISH = ('C' | 'O'<<8 | 'R'<<16 | ' '<<24), - CORSICAN = ('C' | 'O'<<8 | 'S'<<16 | ' '<<24), - CREE = ('C' | 'R'<<8 | 'E'<<16 | ' '<<24), - CREOLES = ('C' | 'P'<<8 | 'P'<<16 | ' '<<24), - CRIMEAN_TATAR = ('C' | 'R'<<8 | 'T'<<16 | ' '<<24), - CRIOULO = ('K' | 'E'<<8 | 'A'<<16 | ' '<<24), - CROATIAN = ('H' | 'R'<<8 | 'V'<<16 | ' '<<24), - CYPRIOT_ARABIC = ('A' | 'C'<<8 | 'Y'<<16 | ' '<<24), - CZECH = ('C' | 'S'<<8 | 'Y'<<16 | ' '<<24), - DAGBANI = ('D' | 'A'<<8 | 'G'<<16 | ' '<<24), - DAN = ('D' | 'N'<<8 | 'J'<<16 | ' '<<24), - DANGME = ('D' | 'N'<<8 | 'G'<<16 | ' '<<24), - DANISH = ('D' | 'A'<<8 | 'N'<<16 | ' '<<24), - DARGWA = ('D' | 'A'<<8 | 'R'<<16 | ' '<<24), - DARI = ('D' | 'R'<<8 | 'I'<<16 | ' '<<24), - DAYI = ('D' | 'A'<<8 | 'X'<<16 | ' '<<24), - DEFAULT = ('d' | 'f'<<8 | 'l'<<16 | 't'<<24), // Can be DFLT too... - DEHONG_DAI = ('T' | 'D'<<8 | 'D'<<16 | ' '<<24), - DHANGU = ('D' | 'H'<<8 | 'G'<<16 | ' '<<24), - DHIVEHI = ('D' | 'I'<<8 | 'V'<<16 | ' '<<24), - DHUWAL = ('D' | 'U'<<8 | 'J'<<16 | ' '<<24), - DIMLI = ('D' | 'I'<<8 | 'Q'<<16 | ' '<<24), - DINKA = ('D' | 'N'<<8 | 'K'<<16 | ' '<<24), - DIVEHI = ('D' | 'I'<<8 | 'V'<<16 | ' '<<24), - DJAMBARRPUYNGU = ('D' | 'J'<<8 | 'R'<<16 | '0'<<24), - DOGRI = ('D' | 'G'<<8 | 'O'<<16 | ' '<<24), - DOGRI_MACROLANGUAGE = ('D' | 'G'<<8 | 'R'<<16 | ' '<<24), - DUNGAN = ('D' | 'U'<<8 | 'N'<<16 | ' '<<24), - DUTCH = ('N' | 'L'<<8 | 'D'<<16 | ' '<<24), - DZONGKHA = ('D' | 'Z'<<8 | 'N'<<16 | ' '<<24), - EASTERN_ABENAKI = ('A' | 'A'<<8 | 'Q'<<16 | ' '<<24), - EASTERN_CHAM = ('C' | 'J'<<8 | 'M'<<16 | ' '<<24), - EASTERN_CREE = ('E' | 'C'<<8 | 'R'<<16 | ' '<<24), - EASTERN_MANINKAKAN = ('E' | 'M'<<8 | 'K'<<16 | ' '<<24), - EASTERN_PWO_KAREN = ('K' | 'J'<<8 | 'P'<<16 | ' '<<24), - EBIRA = ('E' | 'B'<<8 | 'I'<<16 | ' '<<24), - EDO = ('E' | 'D'<<8 | 'O'<<16 | ' '<<24), - EFIK = ('E' | 'F'<<8 | 'I'<<16 | ' '<<24), - EMBERA_BAUDO = ('B' | 'D'<<8 | 'C'<<16 | ' '<<24), - EMBERA_CATIO = ('C' | 'T'<<8 | 'O'<<16 | ' '<<24), - EMBERA_CHAMI = ('C' | 'M'<<8 | 'I'<<16 | ' '<<24), - EMBERA_TADO = ('T' | 'D'<<8 | 'C'<<16 | ' '<<24), - ENGLISH = ('E' | 'N'<<8 | 'G'<<16 | ' '<<24), - EPENA = ('S' | 'J'<<8 | 'A'<<16 | ' '<<24), - ERZYA = ('E' | 'R'<<8 | 'Z'<<16 | ' '<<24), - KB_TEXT_SHAPEANTO = ('N' | 'T'<<8 | 'O'<<16 | ' '<<24), - ESTONIAN = ('E' | 'T'<<8 | 'I'<<16 | ' '<<24), - EVEN = ('E' | 'V'<<8 | 'N'<<16 | ' '<<24), - EVENKI = ('E' | 'V'<<8 | 'K'<<16 | ' '<<24), - EWE = ('E' | 'W'<<8 | 'E'<<16 | ' '<<24), - FALAM_CHIN = ('H' | 'A'<<8 | 'L'<<16 | ' '<<24), - FANG = ('F' | 'A'<<8 | 'N'<<16 | '0'<<24), - FANTI = ('F' | 'A'<<8 | 'T'<<16 | ' '<<24), - FAROESE = ('F' | 'O'<<8 | 'S'<<16 | ' '<<24), - FEFE = ('F' | 'M'<<8 | 'P'<<16 | ' '<<24), - FIJIAN = ('F' | 'J'<<8 | 'I'<<16 | ' '<<24), - FILIPINO = ('P' | 'I'<<8 | 'L'<<16 | ' '<<24), - FINNISH = ('F' | 'I'<<8 | 'N'<<16 | ' '<<24), - FLEMISH = ('F' | 'L'<<8 | 'E'<<16 | ' '<<24), - FON = ('F' | 'O'<<8 | 'N'<<16 | ' '<<24), - FOREST_ENETS = ('F' | 'N'<<8 | 'E'<<16 | ' '<<24), - FRENCH = ('F' | 'R'<<8 | 'A'<<16 | ' '<<24), - FRENCH_ANTILLEAN = ('F' | 'A'<<8 | 'N'<<16 | ' '<<24), - FRISIAN = ('F' | 'R'<<8 | 'I'<<16 | ' '<<24), - FRIULIAN = ('F' | 'R'<<8 | 'L'<<16 | ' '<<24), - FULAH = ('F' | 'U'<<8 | 'L'<<16 | ' '<<24), - FUTA = ('F' | 'T'<<8 | 'A'<<16 | ' '<<24), - GA = ('G' | 'A'<<8 | 'D'<<16 | ' '<<24), - GAGAUZ = ('G' | 'A'<<8 | 'G'<<16 | ' '<<24), - GALICIAN = ('G' | 'A'<<8 | 'L'<<16 | ' '<<24), - GANDA = ('L' | 'U'<<8 | 'G'<<16 | ' '<<24), - GARHWALI = ('G' | 'A'<<8 | 'W'<<16 | ' '<<24), - GARO = ('G' | 'R'<<8 | 'O'<<16 | ' '<<24), - GARSHUNI = ('G' | 'A'<<8 | 'R'<<16 | ' '<<24), - GEBA_KAREN = ('K' | 'V'<<8 | 'Q'<<16 | ' '<<24), - GEEZ = ('G' | 'E'<<8 | 'Z'<<16 | ' '<<24), - GEORGIAN = ('K' | 'A'<<8 | 'T'<<16 | ' '<<24), - GEPO = ('Y' | 'G'<<8 | 'P'<<16 | ' '<<24), - GERMAN = ('D' | 'E'<<8 | 'U'<<16 | ' '<<24), - GIKUYU = ('K' | 'I'<<8 | 'K'<<16 | ' '<<24), - GILAKI = ('G' | 'L'<<8 | 'K'<<16 | ' '<<24), - GILBERTESE = ('G' | 'I'<<8 | 'L'<<16 | '0'<<24), - GILYAK = ('G' | 'I'<<8 | 'L'<<16 | ' '<<24), - GITHABUL = ('G' | 'I'<<8 | 'H'<<16 | ' '<<24), - GOGO = ('G' | 'O'<<8 | 'G'<<16 | ' '<<24), - GONDI = ('G' | 'O'<<8 | 'N'<<16 | ' '<<24), - GREEK = ('E' | 'L'<<8 | 'L'<<16 | ' '<<24), - GREENLANDIC = ('G' | 'R'<<8 | 'N'<<16 | ' '<<24), - GUARANI = ('G' | 'U'<<8 | 'A'<<16 | ' '<<24), - GUINEA = ('G' | 'K'<<8 | 'P'<<16 | ' '<<24), - GUJARATI = ('G' | 'U'<<8 | 'J'<<16 | ' '<<24), - GUMATJ = ('G' | 'N'<<8 | 'N'<<16 | ' '<<24), - GUMUZ = ('G' | 'M'<<8 | 'Z'<<16 | ' '<<24), - GUPAPUYNGU = ('G' | 'U'<<8 | 'F'<<16 | ' '<<24), - GUSII = ('G' | 'U'<<8 | 'Z'<<16 | ' '<<24), - HAIDA = ('H' | 'A'<<8 | 'I'<<16 | '0'<<24), - HAITIAN_CREOLE = ('H' | 'A'<<8 | 'I'<<16 | ' '<<24), - HALKOMELEM = ('H' | 'U'<<8 | 'R'<<16 | ' '<<24), - HAMMER_BANNA = ('H' | 'B'<<8 | 'N'<<16 | ' '<<24), - HARARI = ('H' | 'R'<<8 | 'I'<<16 | ' '<<24), - HARAUTI = ('H' | 'A'<<8 | 'R'<<16 | ' '<<24), - HARYANVI = ('B' | 'G'<<8 | 'C'<<16 | ' '<<24), - HAUSA = ('H' | 'A'<<8 | 'U'<<16 | ' '<<24), - HAVASUPAI_WALAPAI_YAVAPAI = ('Y' | 'U'<<8 | 'F'<<16 | ' '<<24), - HAWAIIAN = ('H' | 'A'<<8 | 'W'<<16 | ' '<<24), - HAYA = ('H' | 'A'<<8 | 'Y'<<16 | ' '<<24), - HAZARAGI = ('H' | 'A'<<8 | 'Z'<<16 | ' '<<24), - HEBREW = ('I' | 'W'<<8 | 'R'<<16 | ' '<<24), - HEILTSUK = ('H' | 'E'<<8 | 'I'<<16 | ' '<<24), - HERERO = ('H' | 'E'<<8 | 'R'<<16 | ' '<<24), - HIGH_MARI = ('H' | 'M'<<8 | 'A'<<16 | ' '<<24), - HILIGAYNON = ('H' | 'I'<<8 | 'L'<<16 | ' '<<24), - HINDI = ('H' | 'I'<<8 | 'N'<<16 | ' '<<24), - HINDKO = ('H' | 'N'<<8 | 'D'<<16 | ' '<<24), - HIRI_MOTU = ('H' | 'M'<<8 | 'O'<<16 | ' '<<24), - HMONG = ('H' | 'M'<<8 | 'N'<<16 | ' '<<24), - HMONG_DAW = ('M' | 'W'<<8 | 'W'<<16 | ' '<<24), - HMONG_SHUAT = ('H' | 'M'<<8 | 'Z'<<16 | ' '<<24), - HO = ('H' | 'O'<<8 | ' '<<16 | ' '<<24), - HUNGARIAN = ('H' | 'U'<<8 | 'N'<<16 | ' '<<24), - IBAN = ('I' | 'B'<<8 | 'A'<<16 | ' '<<24), - IBIBIO = ('I' | 'B'<<8 | 'B'<<16 | ' '<<24), - ICELANDIC = ('I' | 'S'<<8 | 'L'<<16 | ' '<<24), - IDO = ('I' | 'D'<<8 | 'O'<<16 | ' '<<24), - IGBO = ('I' | 'B'<<8 | 'O'<<16 | ' '<<24), - IJO = ('I' | 'J'<<8 | 'O'<<16 | ' '<<24), - ILOKANO = ('I' | 'L'<<8 | 'O'<<16 | ' '<<24), - INARI_SAMI = ('I' | 'S'<<8 | 'M'<<16 | ' '<<24), - INDONESIAN = ('I' | 'N'<<8 | 'D'<<16 | ' '<<24), - INGUSH = ('I' | 'N'<<8 | 'G'<<16 | ' '<<24), - INTERLINGUA = ('I' | 'N'<<8 | 'A'<<16 | ' '<<24), - INTERLINGUE = ('I' | 'L'<<8 | 'E'<<16 | ' '<<24), - INUKTITUT = ('I' | 'N'<<8 | 'U'<<16 | ' '<<24), - INUPIAT = ('I' | 'P'<<8 | 'K'<<16 | ' '<<24), - IPA_PHONETIC = ('I' | 'P'<<8 | 'P'<<16 | ' '<<24), - IRISH = ('I' | 'R'<<8 | 'I'<<16 | ' '<<24), - IRISH_TRADITIONAL = ('I' | 'R'<<8 | 'T'<<16 | ' '<<24), - IRULA = ('I' | 'R'<<8 | 'U'<<16 | ' '<<24), - ITALIAN = ('I' | 'T'<<8 | 'A'<<16 | ' '<<24), - JAMAICAN_CREOLE = ('J' | 'A'<<8 | 'M'<<16 | ' '<<24), - JAPANESE = ('J' | 'A'<<8 | 'N'<<16 | ' '<<24), - JAVANESE = ('J' | 'A'<<8 | 'V'<<16 | ' '<<24), - JENNU_KURUMA = ('X' | 'U'<<8 | 'J'<<16 | ' '<<24), - JUDEO_TAT = ('J' | 'D'<<8 | 'T'<<16 | ' '<<24), - JULA = ('J' | 'U'<<8 | 'L'<<16 | ' '<<24), - KABARDIAN = ('K' | 'A'<<8 | 'B'<<16 | ' '<<24), - KABYLE = ('K' | 'A'<<8 | 'B'<<16 | '0'<<24), - KACHCHI = ('K' | 'A'<<8 | 'C'<<16 | ' '<<24), - KADIWEU = ('K' | 'B'<<8 | 'C'<<16 | ' '<<24), - KALENJIN = ('K' | 'A'<<8 | 'L'<<16 | ' '<<24), - KALMYK = ('K' | 'L'<<8 | 'M'<<16 | ' '<<24), - KAMBA = ('K' | 'M'<<8 | 'B'<<16 | ' '<<24), - KANAUJI = ('B' | 'J'<<8 | 'J'<<16 | ' '<<24), - KANNADA = ('K' | 'A'<<8 | 'N'<<16 | ' '<<24), - KANURI = ('K' | 'N'<<8 | 'R'<<16 | ' '<<24), - KAQCHIKEL = ('C' | 'A'<<8 | 'K'<<16 | ' '<<24), - KARACHAY = ('K' | 'A'<<8 | 'R'<<16 | ' '<<24), - KARAIM = ('K' | 'R'<<8 | 'M'<<16 | ' '<<24), - KARAKALPAK = ('K' | 'R'<<8 | 'K'<<16 | ' '<<24), - KARELIAN = ('K' | 'R'<<8 | 'L'<<16 | ' '<<24), - KAREN = ('K' | 'R'<<8 | 'N'<<16 | ' '<<24), - KASHMIRI = ('K' | 'S'<<8 | 'H'<<16 | ' '<<24), - KASHUBIAN = ('C' | 'S'<<8 | 'B'<<16 | ' '<<24), - KATE = ('K' | 'M'<<8 | 'G'<<16 | ' '<<24), - KAZAKH = ('K' | 'A'<<8 | 'Z'<<16 | ' '<<24), - KEBENA = ('K' | 'E'<<8 | 'B'<<16 | ' '<<24), - KEKCHI = ('K' | 'E'<<8 | 'K'<<16 | ' '<<24), - KHAKASS = ('K' | 'H'<<8 | 'A'<<16 | ' '<<24), - KHAMTI_SHAN = ('K' | 'H'<<8 | 'T'<<16 | ' '<<24), - KHAMYANG = ('K' | 'S'<<8 | 'U'<<16 | ' '<<24), - KHANTY_KAZIM = ('K' | 'H'<<8 | 'K'<<16 | ' '<<24), - KHANTY_SHURISHKAR = ('K' | 'H'<<8 | 'S'<<16 | ' '<<24), - KHANTY_VAKHI = ('K' | 'H'<<8 | 'V'<<16 | ' '<<24), - KHASI = ('K' | 'S'<<8 | 'I'<<16 | ' '<<24), - KHENGKHA = ('X' | 'K'<<8 | 'F'<<16 | ' '<<24), - KHINALUG = ('K' | 'J'<<8 | 'J'<<16 | ' '<<24), - KHMER = ('K' | 'H'<<8 | 'M'<<16 | ' '<<24), - KHORASANI_TURKIC = ('K' | 'M'<<8 | 'Z'<<16 | ' '<<24), - KHOWAR = ('K' | 'H'<<8 | 'W'<<16 | ' '<<24), - KHUTSURI_GEORGIAN = ('K' | 'G'<<8 | 'E'<<16 | ' '<<24), - KICHE = ('Q' | 'U'<<8 | 'C'<<16 | ' '<<24), - KIKONGO = ('K' | 'O'<<8 | 'N'<<16 | ' '<<24), - KILDIN_SAMI = ('K' | 'S'<<8 | 'M'<<16 | ' '<<24), - KINYARWANDA = ('R' | 'U'<<8 | 'A'<<16 | ' '<<24), - KIRMANJKI = ('K' | 'I'<<8 | 'U'<<16 | ' '<<24), - KISII = ('K' | 'I'<<8 | 'S'<<16 | ' '<<24), - KITUBA = ('M' | 'K'<<8 | 'W'<<16 | ' '<<24), - KODAGU = ('K' | 'O'<<8 | 'D'<<16 | ' '<<24), - KOKNI = ('K' | 'K'<<8 | 'N'<<16 | ' '<<24), - KOMI = ('K' | 'O'<<8 | 'M'<<16 | ' '<<24), - KOMI_PERMYAK = ('K' | 'O'<<8 | 'P'<<16 | ' '<<24), - KOMI_ZYRIAN = ('K' | 'O'<<8 | 'Z'<<16 | ' '<<24), - KOMO = ('K' | 'M'<<8 | 'O'<<16 | ' '<<24), - KOMSO = ('K' | 'M'<<8 | 'S'<<16 | ' '<<24), - KONGO = ('K' | 'O'<<8 | 'N'<<16 | '0'<<24), - KONKANI = ('K' | 'O'<<8 | 'K'<<16 | ' '<<24), - KOORETE = ('K' | 'R'<<8 | 'T'<<16 | ' '<<24), - KOREAN = ('K' | 'O'<<8 | 'R'<<16 | ' '<<24), - KOREAO_OLD_HANGUL = ('K' | 'O'<<8 | 'H'<<16 | ' '<<24), - KORYAK = ('K' | 'Y'<<8 | 'K'<<16 | ' '<<24), - KOSRAEAN = ('K' | 'O'<<8 | 'S'<<16 | ' '<<24), - KPELLE = ('K' | 'P'<<8 | 'L'<<16 | ' '<<24), - KPELLE_LIBERIA = ('X' | 'P'<<8 | 'E'<<16 | ' '<<24), - KRIO = ('K' | 'R'<<8 | 'I'<<16 | ' '<<24), - KRYMCHAK = ('J' | 'C'<<8 | 'T'<<16 | ' '<<24), - KUANYAMA = ('K' | 'U'<<8 | 'A'<<16 | ' '<<24), - KUBE = ('K' | 'G'<<8 | 'F'<<16 | ' '<<24), - KUI = ('K' | 'U'<<8 | 'I'<<16 | ' '<<24), - KULVI = ('K' | 'U'<<8 | 'K'<<16 | ' '<<24), - KUMAONI = ('K' | 'M'<<8 | 'N'<<16 | ' '<<24), - KUMYK = ('K' | 'U'<<8 | 'M'<<16 | ' '<<24), - KURDISH = ('K' | 'U'<<8 | 'R'<<16 | ' '<<24), - KURUKH = ('K' | 'U'<<8 | 'U'<<16 | ' '<<24), - KUY = ('K' | 'U'<<8 | 'Y'<<16 | ' '<<24), - KWAKWALA = ('K' | 'W'<<8 | 'K'<<16 | ' '<<24), - KYRGYZ = ('K' | 'I'<<8 | 'R'<<16 | ' '<<24), - L_CREE = ('L' | 'C'<<8 | 'R'<<16 | ' '<<24), - LADAKHI = ('L' | 'D'<<8 | 'K'<<16 | ' '<<24), - LADIN = ('L' | 'A'<<8 | 'D'<<16 | ' '<<24), - LADINO = ('J' | 'U'<<8 | 'D'<<16 | ' '<<24), - LAHULI = ('L' | 'A'<<8 | 'H'<<16 | ' '<<24), - LAK = ('L' | 'A'<<8 | 'K'<<16 | ' '<<24), - LAKI = ('L' | 'K'<<8 | 'I'<<16 | ' '<<24), - LAMBANI = ('L' | 'A'<<8 | 'M'<<16 | ' '<<24), - LAMPUNG = ('L' | 'J'<<8 | 'P'<<16 | ' '<<24), - LAO = ('L' | 'A'<<8 | 'O'<<16 | ' '<<24), - LATIN = ('L' | 'A'<<8 | 'T'<<16 | ' '<<24), - LATVIAN = ('L' | 'V'<<8 | 'I'<<16 | ' '<<24), - LAZ = ('L' | 'A'<<8 | 'Z'<<16 | ' '<<24), - LELEMI = ('L' | 'E'<<8 | 'F'<<16 | ' '<<24), - LEZGI = ('L' | 'E'<<8 | 'Z'<<16 | ' '<<24), - LIGURIAN = ('L' | 'I'<<8 | 'J'<<16 | ' '<<24), - LIMBU = ('L' | 'M'<<8 | 'B'<<16 | ' '<<24), - LIMBURGISH = ('L' | 'I'<<8 | 'M'<<16 | ' '<<24), - LINGALA = ('L' | 'I'<<8 | 'N'<<16 | ' '<<24), - LIPO = ('L' | 'P'<<8 | 'O'<<16 | ' '<<24), - LISU = ('L' | 'I'<<8 | 'S'<<16 | ' '<<24), - LITHUANIAN = ('L' | 'T'<<8 | 'H'<<16 | ' '<<24), - LIV = ('L' | 'I'<<8 | 'V'<<16 | ' '<<24), - LOJBAN = ('J' | 'B'<<8 | 'O'<<16 | ' '<<24), - LOMA = ('L' | 'O'<<8 | 'M'<<16 | ' '<<24), - LOMBARD = ('L' | 'M'<<8 | 'O'<<16 | ' '<<24), - LOMWE = ('L' | 'M'<<8 | 'W'<<16 | ' '<<24), - LOW_MARI = ('L' | 'M'<<8 | 'A'<<16 | ' '<<24), - LOW_SAXON = ('N' | 'D'<<8 | 'S'<<16 | ' '<<24), - LOWER_SORBIAN = ('L' | 'S'<<8 | 'B'<<16 | ' '<<24), - LU = ('X' | 'B'<<8 | 'D'<<16 | ' '<<24), - LUBA_KATANGA = ('L' | 'U'<<8 | 'B'<<16 | ' '<<24), - LUBA_LULUA = ('L' | 'U'<<8 | 'A'<<16 | ' '<<24), - LULE_SAMI = ('L' | 'S'<<8 | 'M'<<16 | ' '<<24), - LUO = ('L' | 'U'<<8 | 'O'<<16 | ' '<<24), - LURI = ('L' | 'R'<<8 | 'C'<<16 | ' '<<24), - LUSHOOTSEED = ('L' | 'U'<<8 | 'T'<<16 | ' '<<24), - LUXEMBOURGISH = ('L' | 'T'<<8 | 'Z'<<16 | ' '<<24), - LUYIA = ('L' | 'U'<<8 | 'H'<<16 | ' '<<24), - MACEDONIAN = ('M' | 'K'<<8 | 'D'<<16 | ' '<<24), - MADURA = ('M' | 'A'<<8 | 'D'<<16 | ' '<<24), - MAGAHI = ('M' | 'A'<<8 | 'G'<<16 | ' '<<24), - MAITHILI = ('M' | 'T'<<8 | 'H'<<16 | ' '<<24), - MAJANG = ('M' | 'A'<<8 | 'J'<<16 | ' '<<24), - MAKASAR = ('M' | 'K'<<8 | 'R'<<16 | ' '<<24), - MAKHUWA = ('M' | 'A'<<8 | 'K'<<16 | ' '<<24), - MAKONDE = ('K' | 'D'<<8 | 'E'<<16 | ' '<<24), - MALAGASY = ('M' | 'L'<<8 | 'G'<<16 | ' '<<24), - MALAY = ('M' | 'L'<<8 | 'Y'<<16 | ' '<<24), - MALAYALAM = ('M' | 'A'<<8 | 'L'<<16 | ' '<<24), - MALAYALAM_REFORMED = ('M' | 'L'<<8 | 'R'<<16 | ' '<<24), - MALE = ('M' | 'L'<<8 | 'E'<<16 | ' '<<24), - MALINKE = ('M' | 'L'<<8 | 'N'<<16 | ' '<<24), - MALTESE = ('M' | 'T'<<8 | 'S'<<16 | ' '<<24), - MAM = ('M' | 'A'<<8 | 'M'<<16 | ' '<<24), - MANCHU = ('M' | 'C'<<8 | 'H'<<16 | ' '<<24), - MANDAR = ('M' | 'D'<<8 | 'R'<<16 | ' '<<24), - MANDINKA = ('M' | 'N'<<8 | 'D'<<16 | ' '<<24), - MANINKA = ('M' | 'N'<<8 | 'K'<<16 | ' '<<24), - MANIPURI = ('M' | 'N'<<8 | 'I'<<16 | ' '<<24), - MANO = ('M' | 'E'<<8 | 'V'<<16 | ' '<<24), - MANSI = ('M' | 'A'<<8 | 'N'<<16 | ' '<<24), - MANX = ('M' | 'N'<<8 | 'X'<<16 | ' '<<24), - MAORI = ('M' | 'R'<<8 | 'I'<<16 | ' '<<24), - MAPUDUNGUN = ('M' | 'A'<<8 | 'P'<<16 | ' '<<24), - MARATHI = ('M' | 'A'<<8 | 'R'<<16 | ' '<<24), - MARSHALLESE = ('M' | 'A'<<8 | 'H'<<16 | ' '<<24), - MARWARI = ('M' | 'A'<<8 | 'W'<<16 | ' '<<24), - MAYAN = ('M' | 'Y'<<8 | 'N'<<16 | ' '<<24), - MAZANDERANI = ('M' | 'Z'<<8 | 'N'<<16 | ' '<<24), - MBEMBE_TIGON = ('N' | 'Z'<<8 | 'A'<<16 | ' '<<24), - MBO = ('M' | 'B'<<8 | 'O'<<16 | ' '<<24), - MBUNDU = ('M' | 'B'<<8 | 'N'<<16 | ' '<<24), - MEDUMBA = ('B' | 'Y'<<8 | 'V'<<16 | ' '<<24), - MEEN = ('M' | 'E'<<8 | 'N'<<16 | ' '<<24), - MENDE = ('M' | 'D'<<8 | 'E'<<16 | ' '<<24), - MERU = ('M' | 'E'<<8 | 'R'<<16 | ' '<<24), - MEWATI = ('W' | 'T'<<8 | 'M'<<16 | ' '<<24), - MINANGKABAU = ('M' | 'I'<<8 | 'N'<<16 | ' '<<24), - MINJANGBAL = ('X' | 'J'<<8 | 'B'<<16 | ' '<<24), - MIRANDESE = ('M' | 'W'<<8 | 'L'<<16 | ' '<<24), - MIZO = ('M' | 'I'<<8 | 'Z'<<16 | ' '<<24), - MOHAWK = ('M' | 'O'<<8 | 'H'<<16 | ' '<<24), - MOKSHA = ('M' | 'O'<<8 | 'K'<<16 | ' '<<24), - MOLDAVIAN = ('M' | 'O'<<8 | 'L'<<16 | ' '<<24), - MON = ('M' | 'O'<<8 | 'N'<<16 | ' '<<24), - MONGOLIAN = ('M' | 'N'<<8 | 'G'<<16 | ' '<<24), - MOOSE_CREE = ('M' | 'C'<<8 | 'R'<<16 | ' '<<24), - MORISYEN = ('M' | 'F'<<8 | 'E'<<16 | ' '<<24), - MOROCCAN = ('M' | 'O'<<8 | 'R'<<16 | ' '<<24), - MOSSI = ('M' | 'P'<<8 | 'S'<<16 | ' '<<24), - MUNDARI = ('M' | 'U'<<8 | 'N'<<16 | ' '<<24), - MUSCOGEE = ('M' | 'U'<<8 | 'S'<<16 | ' '<<24), - N_CREE = ('N' | 'C'<<8 | 'R'<<16 | ' '<<24), - NAGA_ASSAMESE = ('N' | 'A'<<8 | 'G'<<16 | ' '<<24), - NAGARI = ('N' | 'G'<<8 | 'R'<<16 | ' '<<24), - NAHUATL = ('N' | 'A'<<8 | 'H'<<16 | ' '<<24), - NANAI = ('N' | 'A'<<8 | 'N'<<16 | ' '<<24), - NASKAPI = ('N' | 'A'<<8 | 'S'<<16 | ' '<<24), - NAURUAN = ('N' | 'A'<<8 | 'U'<<16 | ' '<<24), - NAVAJO = ('N' | 'A'<<8 | 'V'<<16 | ' '<<24), - NDAU = ('N' | 'D'<<8 | 'C'<<16 | ' '<<24), - NDEBELE = ('N' | 'D'<<8 | 'B'<<16 | ' '<<24), - NDONGA = ('N' | 'D'<<8 | 'G'<<16 | ' '<<24), - NEAPOLITAN = ('N' | 'A'<<8 | 'P'<<16 | ' '<<24), - NEPALI = ('N' | 'E'<<8 | 'P'<<16 | ' '<<24), - NEWARI = ('N' | 'E'<<8 | 'W'<<16 | ' '<<24), - NGBAKA = ('N' | 'G'<<8 | 'A'<<16 | ' '<<24), - NIGERIAN_FULFULDE = ('F' | 'U'<<8 | 'V'<<16 | ' '<<24), - NIMADI = ('N' | 'O'<<8 | 'E'<<16 | ' '<<24), - NISI = ('N' | 'I'<<8 | 'S'<<16 | ' '<<24), - NIUEAN = ('N' | 'I'<<8 | 'U'<<16 | ' '<<24), - NKO = ('N' | 'K'<<8 | 'O'<<16 | ' '<<24), - NOGAI = ('N' | 'O'<<8 | 'G'<<16 | ' '<<24), - NORFOLK = ('P' | 'I'<<8 | 'H'<<16 | ' '<<24), - NORTH_SLAVEY = ('S' | 'C'<<8 | 'S'<<16 | ' '<<24), - NORTHERN_EMBERA = ('E' | 'M'<<8 | 'P'<<16 | ' '<<24), - NORTHERN_SAMI = ('N' | 'S'<<8 | 'M'<<16 | ' '<<24), - NORTHERN_SOTHO = ('N' | 'S'<<8 | 'O'<<16 | ' '<<24), - NORTHERN_TAI = ('N' | 'T'<<8 | 'A'<<16 | ' '<<24), - NORWAY_HOUSE_CREE = ('N' | 'H'<<8 | 'C'<<16 | ' '<<24), - NORWEGIAN = ('N' | 'O'<<8 | 'R'<<16 | ' '<<24), - NORWEGIAN_NYNORSK = ('N' | 'Y'<<8 | 'N'<<16 | ' '<<24), - NOVIAL = ('N' | 'O'<<8 | 'V'<<16 | ' '<<24), - NUMANGGANG = ('N' | 'O'<<8 | 'P'<<16 | ' '<<24), - NUNAVIK_INUKTITUT = ('I' | 'N'<<8 | 'U'<<16 | ' '<<24), - NUU_CHAH_NULTH = ('N' | 'U'<<8 | 'K'<<16 | ' '<<24), - NYAMWEZI = ('N' | 'Y'<<8 | 'M'<<16 | ' '<<24), - NYANKOLE = ('N' | 'K'<<8 | 'L'<<16 | ' '<<24), - OCCITAN = ('O' | 'C'<<8 | 'I'<<16 | ' '<<24), - ODIA = ('O' | 'R'<<8 | 'I'<<16 | ' '<<24), - OJI_CREE = ('O' | 'C'<<8 | 'R'<<16 | ' '<<24), - OJIBWAY = ('O' | 'J'<<8 | 'B'<<16 | ' '<<24), - OLD_IRISH = ('S' | 'G'<<8 | 'A'<<16 | ' '<<24), - OLD_JAVANESE = ('K' | 'A'<<8 | 'W'<<16 | ' '<<24), - ONEIDA = ('O' | 'N'<<8 | 'E'<<16 | ' '<<24), - ONONDAGA = ('O' | 'N'<<8 | 'O'<<16 | ' '<<24), - OROMO = ('O' | 'R'<<8 | 'O'<<16 | ' '<<24), - OSSETIAN = ('O' | 'S'<<8 | 'S'<<16 | ' '<<24), - PA_O_KAREN = ('B' | 'L'<<8 | 'K'<<16 | ' '<<24), - PALAUAN = ('P' | 'A'<<8 | 'U'<<16 | ' '<<24), - PALAUNG = ('P' | 'L'<<8 | 'G'<<16 | ' '<<24), - PALESTINIAN_ARAMAIC = ('P' | 'A'<<8 | 'A'<<16 | ' '<<24), - PALI = ('P' | 'A'<<8 | 'L'<<16 | ' '<<24), - PALPA = ('P' | 'A'<<8 | 'P'<<16 | ' '<<24), - PAMPANGAN = ('P' | 'A'<<8 | 'M'<<16 | ' '<<24), - PANGASINAN = ('P' | 'A'<<8 | 'G'<<16 | ' '<<24), - PAPIAMENTU = ('P' | 'A'<<8 | 'P'<<16 | '0'<<24), - PASHTO = ('P' | 'A'<<8 | 'S'<<16 | ' '<<24), - PATTANI_MALAY = ('M' | 'F'<<8 | 'A'<<16 | ' '<<24), - PENNSYLVANIA_GERMAN = ('P' | 'D'<<8 | 'C'<<16 | ' '<<24), - PERSIAN = ('F' | 'A'<<8 | 'R'<<16 | ' '<<24), - PHAKE = ('P' | 'J'<<8 | 'K'<<16 | ' '<<24), - PICARD = ('P' | 'C'<<8 | 'D'<<16 | ' '<<24), - PIEMONTESE = ('P' | 'M'<<8 | 'S'<<16 | ' '<<24), - PILAGA = ('P' | 'L'<<8 | 'G'<<16 | ' '<<24), - PITE_SAMI = ('S' | 'J'<<8 | 'E'<<16 | ' '<<24), - POCOMCHI = ('P' | 'O'<<8 | 'H'<<16 | ' '<<24), - POHNPEIAN = ('P' | 'O'<<8 | 'N'<<16 | ' '<<24), - POLISH = ('P' | 'L'<<8 | 'K'<<16 | ' '<<24), - POLYTONIC_GREEK = ('P' | 'G'<<8 | 'R'<<16 | ' '<<24), - PORTUGUESE = ('P' | 'T'<<8 | 'G'<<16 | ' '<<24), - PROVENCAL = ('P' | 'R'<<8 | 'O'<<16 | ' '<<24), - PUNJABI = ('P' | 'A'<<8 | 'N'<<16 | ' '<<24), - QUECHUA = ('Q' | 'U'<<8 | 'Z'<<16 | ' '<<24), - QUECHUA_BOLIVIA = ('Q' | 'U'<<8 | 'H'<<16 | ' '<<24), - QUECHUA_ECUADOR = ('Q' | 'V'<<8 | 'I'<<16 | ' '<<24), - QUECHUA_PERU = ('Q' | 'W'<<8 | 'H'<<16 | ' '<<24), - R_CREE = ('R' | 'C'<<8 | 'R'<<16 | ' '<<24), - RAJASTHANI = ('R' | 'A'<<8 | 'J'<<16 | ' '<<24), - RAKHINE = ('A' | 'R'<<8 | 'K'<<16 | ' '<<24), - RAROTONGAN = ('R' | 'A'<<8 | 'R'<<16 | ' '<<24), - REJANG = ('R' | 'E'<<8 | 'J'<<16 | ' '<<24), - RIANG = ('R' | 'I'<<8 | 'A'<<16 | ' '<<24), - RIPUARIAN = ('K' | 'S'<<8 | 'H'<<16 | ' '<<24), - RITARUNGO = ('R' | 'I'<<8 | 'T'<<16 | ' '<<24), - ROHINGYA = ('R' | 'H'<<8 | 'G'<<16 | ' '<<24), - ROMANIAN = ('R' | 'O'<<8 | 'M'<<16 | ' '<<24), - ROMANSH = ('R' | 'M'<<8 | 'S'<<16 | ' '<<24), - ROMANY = ('R' | 'O'<<8 | 'Y'<<16 | ' '<<24), - ROTUMAN = ('R' | 'T'<<8 | 'M'<<16 | ' '<<24), - RUNDI = ('R' | 'U'<<8 | 'N'<<16 | ' '<<24), - RUSSIAN = ('R' | 'U'<<8 | 'S'<<16 | ' '<<24), - RUSSIAN_BURIAT = ('R' | 'B'<<8 | 'U'<<16 | ' '<<24), - RUSYN = ('R' | 'S'<<8 | 'Y'<<16 | ' '<<24), - SADRI = ('S' | 'A'<<8 | 'D'<<16 | ' '<<24), - SAKHA = ('Y' | 'A'<<8 | 'K'<<16 | ' '<<24), - SAMOAN = ('S' | 'M'<<8 | 'O'<<16 | ' '<<24), - SAMOGITIAN = ('S' | 'G'<<8 | 'S'<<16 | ' '<<24), - SAN_BLAS_KUNA = ('C' | 'U'<<8 | 'K'<<16 | ' '<<24), - SANGO = ('S' | 'G'<<8 | 'O'<<16 | ' '<<24), - SANSKRIT = ('S' | 'A'<<8 | 'N'<<16 | ' '<<24), - SANTALI = ('S' | 'A'<<8 | 'T'<<16 | ' '<<24), - SARAIKI = ('S' | 'R'<<8 | 'K'<<16 | ' '<<24), - SARDINIAN = ('S' | 'R'<<8 | 'D'<<16 | ' '<<24), - SASAK = ('S' | 'A'<<8 | 'S'<<16 | ' '<<24), - SATERLAND_FRISIAN = ('S' | 'T'<<8 | 'Q'<<16 | ' '<<24), - SAYISI = ('S' | 'A'<<8 | 'Y'<<16 | ' '<<24), - SCOTS = ('S' | 'C'<<8 | 'I'<<16 | ' '<<24), - SCOTTISH_GAELIC = ('G' | 'A'<<8 | 'E'<<16 | ' '<<24), - SEKOTA = ('S' | 'E'<<8 | 'J'<<16 | ' '<<24), - SELKUP = ('S' | 'E'<<8 | 'L'<<16 | ' '<<24), - SENA = ('S' | 'N'<<8 | 'A'<<16 | ' '<<24), - SENECA = ('S' | 'E'<<8 | 'E'<<16 | ' '<<24), - SERBIAN = ('S' | 'R'<<8 | 'B'<<16 | ' '<<24), - SERER = ('S' | 'R'<<8 | 'R'<<16 | ' '<<24), - SGAW_KAREN = ('K' | 'S'<<8 | 'W'<<16 | ' '<<24), - SHAN = ('S' | 'H'<<8 | 'N'<<16 | ' '<<24), - SHONA = ('S' | 'N'<<8 | 'A'<<16 | ' '<<24), - SIBE = ('S' | 'I'<<8 | 'B'<<16 | ' '<<24), - SICILIAN = ('S' | 'C'<<8 | 'N'<<16 | ' '<<24), - SIDAMO = ('S' | 'I'<<8 | 'D'<<16 | ' '<<24), - SILESIAN = ('S' | 'Z'<<8 | 'L'<<16 | ' '<<24), - SILTE_GURAGE = ('S' | 'I'<<8 | 'G'<<16 | ' '<<24), - SINDHI = ('S' | 'N'<<8 | 'D'<<16 | ' '<<24), - SINHALA = ('S' | 'N'<<8 | 'H'<<16 | ' '<<24), - SKOLT_SAMI = ('S' | 'K'<<8 | 'S'<<16 | ' '<<24), - SLAVEY = ('S' | 'L'<<8 | 'A'<<16 | ' '<<24), - SLOVAK = ('S' | 'K'<<8 | 'Y'<<16 | ' '<<24), - SLOVENIAN = ('S' | 'L'<<8 | 'V'<<16 | ' '<<24), - SMALL_FLOWERY_MIAO = ('S' | 'F'<<8 | 'M'<<16 | ' '<<24), - SODO_GURAGE = ('S' | 'O'<<8 | 'G'<<16 | ' '<<24), - SOGA = ('X' | 'O'<<8 | 'G'<<16 | ' '<<24), - SOMALI = ('S' | 'M'<<8 | 'L'<<16 | ' '<<24), - SONGE = ('S' | 'O'<<8 | 'P'<<16 | ' '<<24), - SONINKE = ('S' | 'N'<<8 | 'K'<<16 | ' '<<24), - SOUTH_SLAVEY = ('S' | 'S'<<8 | 'L'<<16 | ' '<<24), - SOUTHERN_KIWAI = ('K' | 'J'<<8 | 'D'<<16 | ' '<<24), - SOUTHERN_SAMI = ('S' | 'S'<<8 | 'M'<<16 | ' '<<24), - SOUTHERN_SOTHO = ('S' | 'O'<<8 | 'T'<<16 | ' '<<24), - SPANISH = ('E' | 'S'<<8 | 'P'<<16 | ' '<<24), - STANDARD_MOROCCAN_TAMAZIGHT = ('Z' | 'G'<<8 | 'H'<<16 | ' '<<24), - STRAITS_SALISH = ('S' | 'T'<<8 | 'R'<<16 | ' '<<24), - SUKUMA = ('S' | 'U'<<8 | 'K'<<16 | ' '<<24), - SUNDANESE = ('S' | 'U'<<8 | 'N'<<16 | ' '<<24), - SURI = ('S' | 'U'<<8 | 'R'<<16 | ' '<<24), - SUTU = ('S' | 'X'<<8 | 'T'<<16 | ' '<<24), - SVAN = ('S' | 'V'<<8 | 'A'<<16 | ' '<<24), - SWADAYA_ARAMAIC = ('S' | 'W'<<8 | 'A'<<16 | ' '<<24), - SWAHILI = ('S' | 'W'<<8 | 'K'<<16 | ' '<<24), - SWATI = ('S' | 'W'<<8 | 'Z'<<16 | ' '<<24), - SWEDISH = ('S' | 'V'<<8 | 'E'<<16 | ' '<<24), - SYLHETI = ('S' | 'Y'<<8 | 'L'<<16 | ' '<<24), - SYRIAC = ('S' | 'Y'<<8 | 'R'<<16 | ' '<<24), - SYRIAC_EASTERN = ('S' | 'Y'<<8 | 'R'<<16 | 'N'<<24), - SYRIAC_ESTRANGELA = ('S' | 'Y'<<8 | 'R'<<16 | 'E'<<24), - SYRIAC_WESTERN = ('S' | 'Y'<<8 | 'R'<<16 | 'J'<<24), - TABASARAN = ('T' | 'A'<<8 | 'B'<<16 | ' '<<24), - TACHELHIT = ('S' | 'H'<<8 | 'I'<<16 | ' '<<24), - TAGALOG = ('T' | 'G'<<8 | 'L'<<16 | ' '<<24), - TAHAGGART_TAMAHAQ = ('T' | 'H'<<8 | 'V'<<16 | ' '<<24), - TAHITIAN = ('T' | 'H'<<8 | 'T'<<16 | ' '<<24), - TAI_LAING = ('T' | 'J'<<8 | 'L'<<16 | ' '<<24), - TAJIKI = ('T' | 'A'<<8 | 'J'<<16 | ' '<<24), - TALYSH = ('T' | 'L'<<8 | 'Y'<<16 | ' '<<24), - TAMASHEK = ('T' | 'M'<<8 | 'H'<<16 | ' '<<24), - TAMASHEQ = ('T' | 'A'<<8 | 'Q'<<16 | ' '<<24), - TAMAZIGHT = ('T' | 'Z'<<8 | 'M'<<16 | ' '<<24), - TAMIL = ('T' | 'A'<<8 | 'M'<<16 | ' '<<24), - TARIFIT = ('R' | 'I'<<8 | 'F'<<16 | ' '<<24), - TATAR = ('T' | 'A'<<8 | 'T'<<16 | ' '<<24), - TAWALLAMMAT_TAMAJAQ = ('T' | 'T'<<8 | 'Q'<<16 | ' '<<24), - TAY = ('T' | 'Y'<<8 | 'Z'<<16 | ' '<<24), - TAYART_TAMAJEQ = ('T' | 'H'<<8 | 'Z'<<16 | ' '<<24), - TELUGU = ('T' | 'E'<<8 | 'L'<<16 | ' '<<24), - TEMNE = ('T' | 'M'<<8 | 'N'<<16 | ' '<<24), - TETUM = ('T' | 'E'<<8 | 'T'<<16 | ' '<<24), - TH_CREE = ('T' | 'C'<<8 | 'R'<<16 | ' '<<24), - THAI = ('T' | 'H'<<8 | 'A'<<16 | ' '<<24), - THAILAND_MON = ('M' | 'O'<<8 | 'N'<<16 | 'T'<<24), - THOMPSON = ('T' | 'H'<<8 | 'P'<<16 | ' '<<24), - TIBETAN = ('T' | 'I'<<8 | 'B'<<16 | ' '<<24), - TIGRE = ('T' | 'G'<<8 | 'R'<<16 | ' '<<24), - TIGRINYA = ('T' | 'G'<<8 | 'Y'<<16 | ' '<<24), - TIV = ('T' | 'I'<<8 | 'V'<<16 | ' '<<24), - TLINGIT = ('T' | 'L'<<8 | 'I'<<16 | ' '<<24), - TOBO = ('T' | 'B'<<8 | 'V'<<16 | ' '<<24), - TODO = ('T' | 'O'<<8 | 'D'<<16 | ' '<<24), - TOK_PISIN = ('T' | 'P'<<8 | 'I'<<16 | ' '<<24), - TOMA = ('T' | 'O'<<8 | 'D'<<16 | '0'<<24), - TONGA = ('T' | 'N'<<8 | 'G'<<16 | ' '<<24), - TONGAN = ('T' | 'G'<<8 | 'N'<<16 | ' '<<24), - TORKI = ('A' | 'Z'<<8 | 'B'<<16 | ' '<<24), - TSHANGLA = ('T' | 'S'<<8 | 'J'<<16 | ' '<<24), - TSONGA = ('T' | 'S'<<8 | 'G'<<16 | ' '<<24), - TSWANA = ('T' | 'N'<<8 | 'A'<<16 | ' '<<24), - TULU = ('T' | 'U'<<8 | 'L'<<16 | ' '<<24), - TUMBUKA = ('T' | 'U'<<8 | 'M'<<16 | ' '<<24), - TUNDRA_ENETS = ('T' | 'N'<<8 | 'E'<<16 | ' '<<24), - TURKISH = ('T' | 'R'<<8 | 'K'<<16 | ' '<<24), - TURKMEN = ('T' | 'K'<<8 | 'M'<<16 | ' '<<24), - TUROYO_ARAMAIC = ('T' | 'U'<<8 | 'A'<<16 | ' '<<24), - TUSCARORA = ('T' | 'U'<<8 | 'S'<<16 | ' '<<24), - TUVALU = ('T' | 'V'<<8 | 'L'<<16 | ' '<<24), - TUVIN = ('T' | 'U'<<8 | 'V'<<16 | ' '<<24), - TWI = ('T' | 'W'<<8 | 'I'<<16 | ' '<<24), - TZOTZIL = ('T' | 'Z'<<8 | 'O'<<16 | ' '<<24), - UDI = ('U' | 'D'<<8 | 'I'<<16 | ' '<<24), - UDMURT = ('U' | 'D'<<8 | 'M'<<16 | ' '<<24), - UKRAINIAN = ('U' | 'K'<<8 | 'R'<<16 | ' '<<24), - UMBUNDU = ('U' | 'M'<<8 | 'B'<<16 | ' '<<24), - UME_SAMI = ('S' | 'J'<<8 | 'U'<<16 | ' '<<24), - UPPER_SAXON = ('S' | 'X'<<8 | 'U'<<16 | ' '<<24), - UPPER_SORBIAN = ('U' | 'S'<<8 | 'B'<<16 | ' '<<24), - URALIC_PHONETIC = ('U' | 'P'<<8 | 'P'<<16 | ' '<<24), - URDU = ('U' | 'R'<<8 | 'D'<<16 | ' '<<24), - UYGHUR = ('U' | 'Y'<<8 | 'G'<<16 | ' '<<24), - UZBEK = ('U' | 'Z'<<8 | 'B'<<16 | ' '<<24), - VENDA = ('V' | 'E'<<8 | 'N'<<16 | ' '<<24), - VENETIAN = ('V' | 'E'<<8 | 'C'<<16 | ' '<<24), - VIETNAMESE = ('V' | 'I'<<8 | 'T'<<16 | ' '<<24), - VLAX_ROMANI = ('R' | 'M'<<8 | 'Y'<<16 | ' '<<24), - VOLAPUK = ('V' | 'O'<<8 | 'L'<<16 | ' '<<24), - VORO = ('V' | 'R'<<8 | 'O'<<16 | ' '<<24), - WA = ('W' | 'A'<<8 | ' '<<16 | ' '<<24), - WACI_GBE = ('W' | 'C'<<8 | 'I'<<16 | ' '<<24), - WAGDI = ('W' | 'A'<<8 | 'G'<<16 | ' '<<24), - WAKHI = ('W' | 'B'<<8 | 'L'<<16 | ' '<<24), - WALLOON = ('W' | 'L'<<8 | 'N'<<16 | ' '<<24), - WARAY_WARAY = ('W' | 'A'<<8 | 'R'<<16 | ' '<<24), - WAYANAD_CHETTI = ('C' | 'T'<<8 | 'T'<<16 | ' '<<24), - WAYUU = ('G' | 'U'<<8 | 'C'<<16 | ' '<<24), - WELSH = ('W' | 'E'<<8 | 'L'<<16 | ' '<<24), - WENDAT = ('W' | 'D'<<8 | 'T'<<16 | ' '<<24), - WEST_CREE = ('W' | 'C'<<8 | 'R'<<16 | ' '<<24), - WESTERN_CHAM = ('C' | 'J'<<8 | 'A'<<16 | ' '<<24), - WESTERN_KAYAH = ('K' | 'Y'<<8 | 'U'<<16 | ' '<<24), - WESTERN_PANJABI = ('P' | 'N'<<8 | 'B'<<16 | ' '<<24), - WESTERN_PWO_KAREN = ('P' | 'W'<<8 | 'O'<<16 | ' '<<24), - WOLOF = ('W' | 'L'<<8 | 'F'<<16 | ' '<<24), - WOODS_CREE = ('D' | 'C'<<8 | 'R'<<16 | ' '<<24), - WUDING_LUQUAN_YI = ('Y' | 'W'<<8 | 'Q'<<16 | ' '<<24), - WYANDOT = ('W' | 'Y'<<8 | 'N'<<16 | ' '<<24), - XHOSA = ('X' | 'H'<<8 | 'S'<<16 | ' '<<24), - Y_CREE = ('Y' | 'C'<<8 | 'R'<<16 | ' '<<24), - YAO = ('Y' | 'A'<<8 | 'O'<<16 | ' '<<24), - YAPESE = ('Y' | 'A'<<8 | 'P'<<16 | ' '<<24), - YI_CLASSIC = ('Y' | 'I'<<8 | 'C'<<16 | ' '<<24), - YI_MODERN = ('Y' | 'I'<<8 | 'M'<<16 | ' '<<24), - YIDDISH = ('J' | 'I'<<8 | 'I'<<16 | ' '<<24), - YORUBA = ('Y' | 'B'<<8 | 'A'<<16 | ' '<<24), - ZAMBOANGA_CHAVACANO = ('C' | 'B'<<8 | 'K'<<16 | ' '<<24), - ZANDE = ('Z' | 'N'<<8 | 'D'<<16 | ' '<<24), - ZARMA = ('D' | 'J'<<8 | 'R'<<16 | ' '<<24), - ZAZAKI = ('Z' | 'Z'<<8 | 'A'<<16 | ' '<<24), - ZEALANDIC = ('Z' | 'E'<<8 | 'A'<<16 | ' '<<24), - ZHUANG = ('Z' | 'H'<<8 | 'A'<<16 | ' '<<24), - ZULU = ('Z' | 'U'<<8 | 'L'<<16 | ' '<<24), + A_HMAO = 'H' | 'M'<<8 | 'D'<<16 | ' '<<24, + AARI = 'A' | 'R'<<8 | 'I'<<16 | ' '<<24, + ABAZA = 'A' | 'B'<<8 | 'A'<<16 | ' '<<24, + ABKHAZIAN = 'A' | 'B'<<8 | 'K'<<16 | ' '<<24, + ACHI = 'A' | 'C'<<8 | 'R'<<16 | ' '<<24, + ACHOLI = 'A' | 'C'<<8 | 'H'<<16 | ' '<<24, + ADYGHE = 'A' | 'D'<<8 | 'Y'<<16 | ' '<<24, + AFAR = 'A' | 'F'<<8 | 'R'<<16 | ' '<<24, + AFRIKAANS = 'A' | 'F'<<8 | 'K'<<16 | ' '<<24, + AGAW = 'A' | 'G'<<8 | 'W'<<16 | ' '<<24, + AITON = 'A' | 'I'<<8 | 'O'<<16 | ' '<<24, + AKAN = 'A' | 'K'<<8 | 'A'<<16 | ' '<<24, + ALBANIAN = 'S' | 'Q'<<8 | 'I'<<16 | ' '<<24, + ALSATIAN = 'A' | 'L'<<8 | 'S'<<16 | ' '<<24, + ALTAI = 'A' | 'L'<<8 | 'T'<<16 | ' '<<24, + ALUO = 'Y' | 'N'<<8 | 'A'<<16 | ' '<<24, + AMERICAN_PHONETIC = 'A' | 'P'<<8 | 'P'<<16 | 'H'<<24, + AMHARIC = 'A' | 'M'<<8 | 'H'<<16 | ' '<<24, + ANGLO_SAXON = 'A' | 'N'<<8 | 'G'<<16 | ' '<<24, + ARABIC = 'A' | 'R'<<8 | 'A'<<16 | ' '<<24, + ARAGONESE = 'A' | 'R'<<8 | 'G'<<16 | ' '<<24, + ARAKANESE = 'A' | 'R'<<8 | 'K'<<16 | ' '<<24, + ARAKWAL = 'R' | 'K'<<8 | 'W'<<16 | ' '<<24, + ARMENIAN = 'H' | 'Y'<<8 | 'E'<<16 | ' '<<24, + ARMENIAN_EAST = 'H' | 'Y'<<8 | 'E'<<16 | '0'<<24, + AROMANIAN = 'R' | 'U'<<8 | 'P'<<16 | ' '<<24, + ARPITAN = 'F' | 'R'<<8 | 'P'<<16 | ' '<<24, + ASSAMESE = 'A' | 'S'<<8 | 'M'<<16 | ' '<<24, + ASTURIAN = 'A' | 'S'<<8 | 'T'<<16 | ' '<<24, + ATHAPASKAN = 'A' | 'T'<<8 | 'H'<<16 | ' '<<24, + ATSINA = 'A' | 'T'<<8 | 'S'<<16 | ' '<<24, + AVAR = 'A' | 'V'<<8 | 'R'<<16 | ' '<<24, + AVATIME = 'A' | 'V'<<8 | 'N'<<16 | ' '<<24, + AWADHI = 'A' | 'W'<<8 | 'A'<<16 | ' '<<24, + AYMARA = 'A' | 'Y'<<8 | 'M'<<16 | ' '<<24, + AZERBAIDJANI = 'A' | 'Z'<<8 | 'E'<<16 | ' '<<24, + BADAGA = 'B' | 'A'<<8 | 'D'<<16 | ' '<<24, + BAGHELKHANDI = 'B' | 'A'<<8 | 'G'<<16 | ' '<<24, + BAGRI = 'B' | 'G'<<8 | 'Q'<<16 | ' '<<24, + BALANTE = 'B' | 'L'<<8 | 'N'<<16 | ' '<<24, + BALINESE = 'B' | 'A'<<8 | 'N'<<16 | ' '<<24, + BALKAR = 'B' | 'A'<<8 | 'L'<<16 | ' '<<24, + BALTI = 'B' | 'L'<<8 | 'T'<<16 | ' '<<24, + BALUCHI = 'B' | 'L'<<8 | 'I'<<16 | ' '<<24, + BAMBARA = 'B' | 'M'<<8 | 'B'<<16 | ' '<<24, + BAMILEKE = 'B' | 'M'<<8 | 'L'<<16 | ' '<<24, + BANDA = 'B' | 'A'<<8 | 'D'<<16 | '0'<<24, + BANDJALANG = 'B' | 'D'<<8 | 'Y'<<16 | ' '<<24, + BANGLA = 'B' | 'E'<<8 | 'N'<<16 | ' '<<24, + BASHKIR = 'B' | 'S'<<8 | 'H'<<16 | ' '<<24, + BASQUE = 'E' | 'U'<<8 | 'Q'<<16 | ' '<<24, + BATAK = 'B' | 'T'<<8 | 'K'<<16 | ' '<<24, + BATAK_ALAS_KLUET = 'B' | 'T'<<8 | 'Z'<<16 | ' '<<24, + BATAK_ANGKOLA = 'A' | 'K'<<8 | 'B'<<16 | ' '<<24, + BATAK_DAIRI = 'B' | 'T'<<8 | 'D'<<16 | ' '<<24, + BATAK_KARO = 'B' | 'T'<<8 | 'X'<<16 | ' '<<24, + BATAK_MANDAILING = 'B' | 'T'<<8 | 'M'<<16 | ' '<<24, + BATAK_SIMALUNGUN = 'B' | 'T'<<8 | 'S'<<16 | ' '<<24, + BATAK_TOBA = 'B' | 'B'<<8 | 'C'<<16 | ' '<<24, + BAULE = 'B' | 'A'<<8 | 'U'<<16 | ' '<<24, + BAVARIAN = 'B' | 'A'<<8 | 'R'<<16 | ' '<<24, + BELARUSIAN = 'B' | 'E'<<8 | 'L'<<16 | ' '<<24, + BEMBA = 'B' | 'E'<<8 | 'M'<<16 | ' '<<24, + BENCH = 'B' | 'C'<<8 | 'H'<<16 | ' '<<24, + BERBER = 'B' | 'B'<<8 | 'R'<<16 | ' '<<24, + BETI = 'B' | 'T'<<8 | 'I'<<16 | ' '<<24, + BETTE_KURUMA = 'X' | 'U'<<8 | 'B'<<16 | ' '<<24, + BHILI = 'B' | 'H'<<8 | 'I'<<16 | ' '<<24, + BHOJPURI = 'B' | 'H'<<8 | 'O'<<16 | ' '<<24, + BHUTANESE = 'D' | 'Z'<<8 | 'N'<<16 | ' '<<24, + BIBLE_CREE = 'B' | 'C'<<8 | 'R'<<16 | ' '<<24, + BIKOL = 'B' | 'I'<<8 | 'K'<<16 | ' '<<24, + BILEN = 'B' | 'I'<<8 | 'L'<<16 | ' '<<24, + BISHNUPRIYA_MANIPURI = 'B' | 'P'<<8 | 'Y'<<16 | ' '<<24, + BISLAMA = 'B' | 'I'<<8 | 'S'<<16 | ' '<<24, + BLACKFOOT = 'B' | 'K'<<8 | 'F'<<16 | ' '<<24, + BODO = 'B' | 'R'<<8 | 'X'<<16 | ' '<<24, + BOSNIAN = 'B' | 'O'<<8 | 'S'<<16 | ' '<<24, + BOUYEI = 'P' | 'C'<<8 | 'C'<<16 | ' '<<24, + BRAHUI = 'B' | 'R'<<8 | 'H'<<16 | ' '<<24, + BRAJ_BHASHA = 'B' | 'R'<<8 | 'I'<<16 | ' '<<24, + BRETON = 'B' | 'R'<<8 | 'E'<<16 | ' '<<24, + BUGIS = 'B' | 'U'<<8 | 'G'<<16 | ' '<<24, + BULGARIAN = 'B' | 'G'<<8 | 'R'<<16 | ' '<<24, + BUMTHANGKHA = 'K' | 'J'<<8 | 'Z'<<16 | ' '<<24, + BURMESE = 'B' | 'R'<<8 | 'M'<<16 | ' '<<24, + BURUSHASKI = 'B' | 'S'<<8 | 'K'<<16 | ' '<<24, + CAJUN_FRENCH = 'F' | 'R'<<8 | 'C'<<16 | ' '<<24, + CARRIER = 'C' | 'R'<<8 | 'R'<<16 | ' '<<24, + CATALAN = 'C' | 'A'<<8 | 'T'<<16 | ' '<<24, + CAYUGA = 'C' | 'A'<<8 | 'Y'<<16 | ' '<<24, + CEBUANO = 'C' | 'E'<<8 | 'B'<<16 | ' '<<24, + CENTRAL_YUPIK = 'E' | 'S'<<8 | 'U'<<16 | ' '<<24, + CHAHA_GURAGE = 'C' | 'H'<<8 | 'G'<<16 | ' '<<24, + CHAMORRO = 'C' | 'H'<<8 | 'A'<<16 | ' '<<24, + CHATTISGARHI = 'C' | 'H'<<8 | 'H'<<16 | ' '<<24, + CHECHEN = 'C' | 'H'<<8 | 'E'<<16 | ' '<<24, + CHEROKEE = 'C' | 'H'<<8 | 'R'<<16 | ' '<<24, + CHEYENNE = 'C' | 'H'<<8 | 'Y'<<16 | ' '<<24, + CHICHEWA = 'C' | 'H'<<8 | 'I'<<16 | ' '<<24, + CHIGA = 'C' | 'G'<<8 | 'G'<<16 | ' '<<24, + CHIMILA = 'C' | 'B'<<8 | 'G'<<16 | ' '<<24, + CHIN = 'Q' | 'I'<<8 | 'N'<<16 | ' '<<24, + CHINANTEC = 'C' | 'C'<<8 | 'H'<<16 | 'N'<<24, + CHINESE_PHONETIC = 'Z' | 'H'<<8 | 'P'<<16 | ' '<<24, + CHINESE_SIMPLIFIED = 'Z' | 'H'<<8 | 'S'<<16 | ' '<<24, + CHINESE_TRADITIONAL = 'Z' | 'H'<<8 | 'T'<<16 | ' '<<24, + CHINESE_TRADITIONAL_HONG_KONG = 'Z' | 'H'<<8 | 'H'<<16 | ' '<<24, + CHINESE_TRADITIONAL_MACAO = 'Z' | 'H'<<8 | 'T'<<16 | 'M'<<24, + CHIPEWYAN = 'C' | 'H'<<8 | 'P'<<16 | ' '<<24, + CHITTAGONIAN = 'C' | 'T'<<8 | 'G'<<16 | ' '<<24, + CHOCTAW = 'C' | 'H'<<8 | 'O'<<16 | ' '<<24, + CHUKCHI = 'C' | 'H'<<8 | 'K'<<16 | ' '<<24, + CHURCH_SLAVONIC = 'C' | 'S'<<8 | 'L'<<16 | ' '<<24, + CHUUKESE = 'C' | 'H'<<8 | 'K'<<16 | '0'<<24, + CHUVASH = 'C' | 'H'<<8 | 'U'<<16 | ' '<<24, + COMORIAN = 'C' | 'M'<<8 | 'R'<<16 | ' '<<24, + COMOX = 'C' | 'O'<<8 | 'O'<<16 | ' '<<24, + COPTIC = 'C' | 'O'<<8 | 'P'<<16 | ' '<<24, + CORNISH = 'C' | 'O'<<8 | 'R'<<16 | ' '<<24, + CORSICAN = 'C' | 'O'<<8 | 'S'<<16 | ' '<<24, + CREE = 'C' | 'R'<<8 | 'E'<<16 | ' '<<24, + CREOLES = 'C' | 'P'<<8 | 'P'<<16 | ' '<<24, + CRIMEAN_TATAR = 'C' | 'R'<<8 | 'T'<<16 | ' '<<24, + CRIOULO = 'K' | 'E'<<8 | 'A'<<16 | ' '<<24, + CROATIAN = 'H' | 'R'<<8 | 'V'<<16 | ' '<<24, + CYPRIOT_ARABIC = 'A' | 'C'<<8 | 'Y'<<16 | ' '<<24, + CZECH = 'C' | 'S'<<8 | 'Y'<<16 | ' '<<24, + DAGBANI = 'D' | 'A'<<8 | 'G'<<16 | ' '<<24, + DAN = 'D' | 'N'<<8 | 'J'<<16 | ' '<<24, + DANGME = 'D' | 'N'<<8 | 'G'<<16 | ' '<<24, + DANISH = 'D' | 'A'<<8 | 'N'<<16 | ' '<<24, + DARGWA = 'D' | 'A'<<8 | 'R'<<16 | ' '<<24, + DARI = 'D' | 'R'<<8 | 'I'<<16 | ' '<<24, + DAYI = 'D' | 'A'<<8 | 'X'<<16 | ' '<<24, + DEFAULT = 'd' | 'f'<<8 | 'l'<<16 | 't'<<24, // Can be DFLT too. + DEHONG_DAI = 'T' | 'D'<<8 | 'D'<<16 | ' '<<24, + DHANGU = 'D' | 'H'<<8 | 'G'<<16 | ' '<<24, + DHIVEHI = 'D' | 'I'<<8 | 'V'<<16 | ' '<<24, + DHUWAL = 'D' | 'U'<<8 | 'J'<<16 | ' '<<24, + DIMLI = 'D' | 'I'<<8 | 'Q'<<16 | ' '<<24, + DINKA = 'D' | 'N'<<8 | 'K'<<16 | ' '<<24, + DIVEHI = 'D' | 'I'<<8 | 'V'<<16 | ' '<<24, + DJAMBARRPUYNGU = 'D' | 'J'<<8 | 'R'<<16 | '0'<<24, + DOGRI = 'D' | 'G'<<8 | 'O'<<16 | ' '<<24, + DOGRI_MACROLANGUAGE = 'D' | 'G'<<8 | 'R'<<16 | ' '<<24, + DUNGAN = 'D' | 'U'<<8 | 'N'<<16 | ' '<<24, + DUTCH = 'N' | 'L'<<8 | 'D'<<16 | ' '<<24, + DZONGKHA = 'D' | 'Z'<<8 | 'N'<<16 | ' '<<24, + EASTERN_ABENAKI = 'A' | 'A'<<8 | 'Q'<<16 | ' '<<24, + EASTERN_CHAM = 'C' | 'J'<<8 | 'M'<<16 | ' '<<24, + EASTERN_CREE = 'E' | 'C'<<8 | 'R'<<16 | ' '<<24, + EASTERN_MANINKAKAN = 'E' | 'M'<<8 | 'K'<<16 | ' '<<24, + EASTERN_PWO_KAREN = 'K' | 'J'<<8 | 'P'<<16 | ' '<<24, + EBIRA = 'E' | 'B'<<8 | 'I'<<16 | ' '<<24, + EDO = 'E' | 'D'<<8 | 'O'<<16 | ' '<<24, + EFIK = 'E' | 'F'<<8 | 'I'<<16 | ' '<<24, + EMBERA_BAUDO = 'B' | 'D'<<8 | 'C'<<16 | ' '<<24, + EMBERA_CATIO = 'C' | 'T'<<8 | 'O'<<16 | ' '<<24, + EMBERA_CHAMI = 'C' | 'M'<<8 | 'I'<<16 | ' '<<24, + EMBERA_TADO = 'T' | 'D'<<8 | 'C'<<16 | ' '<<24, + ENGLISH = 'E' | 'N'<<8 | 'G'<<16 | ' '<<24, + EPENA = 'S' | 'J'<<8 | 'A'<<16 | ' '<<24, + ERZYA = 'E' | 'R'<<8 | 'Z'<<16 | ' '<<24, + KB_TEXT_SHAPEANTO = 'N' | 'T'<<8 | 'O'<<16 | ' '<<24, + ESTONIAN = 'E' | 'T'<<8 | 'I'<<16 | ' '<<24, + EVEN = 'E' | 'V'<<8 | 'N'<<16 | ' '<<24, + EVENKI = 'E' | 'V'<<8 | 'K'<<16 | ' '<<24, + EWE = 'E' | 'W'<<8 | 'E'<<16 | ' '<<24, + FALAM_CHIN = 'H' | 'A'<<8 | 'L'<<16 | ' '<<24, + FANG = 'F' | 'A'<<8 | 'N'<<16 | '0'<<24, + FANTI = 'F' | 'A'<<8 | 'T'<<16 | ' '<<24, + FAROESE = 'F' | 'O'<<8 | 'S'<<16 | ' '<<24, + FEFE = 'F' | 'M'<<8 | 'P'<<16 | ' '<<24, + FIJIAN = 'F' | 'J'<<8 | 'I'<<16 | ' '<<24, + FILIPINO = 'P' | 'I'<<8 | 'L'<<16 | ' '<<24, + FINNISH = 'F' | 'I'<<8 | 'N'<<16 | ' '<<24, + FLEMISH = 'F' | 'L'<<8 | 'E'<<16 | ' '<<24, + FON = 'F' | 'O'<<8 | 'N'<<16 | ' '<<24, + FOREST_ENETS = 'F' | 'N'<<8 | 'E'<<16 | ' '<<24, + FRENCH = 'F' | 'R'<<8 | 'A'<<16 | ' '<<24, + FRENCH_ANTILLEAN = 'F' | 'A'<<8 | 'N'<<16 | ' '<<24, + FRISIAN = 'F' | 'R'<<8 | 'I'<<16 | ' '<<24, + FRIULIAN = 'F' | 'R'<<8 | 'L'<<16 | ' '<<24, + FULAH = 'F' | 'U'<<8 | 'L'<<16 | ' '<<24, + FUTA = 'F' | 'T'<<8 | 'A'<<16 | ' '<<24, + GA = 'G' | 'A'<<8 | 'D'<<16 | ' '<<24, + GAGAUZ = 'G' | 'A'<<8 | 'G'<<16 | ' '<<24, + GALICIAN = 'G' | 'A'<<8 | 'L'<<16 | ' '<<24, + GANDA = 'L' | 'U'<<8 | 'G'<<16 | ' '<<24, + GARHWALI = 'G' | 'A'<<8 | 'W'<<16 | ' '<<24, + GARO = 'G' | 'R'<<8 | 'O'<<16 | ' '<<24, + GARSHUNI = 'G' | 'A'<<8 | 'R'<<16 | ' '<<24, + GEBA_KAREN = 'K' | 'V'<<8 | 'Q'<<16 | ' '<<24, + GEEZ = 'G' | 'E'<<8 | 'Z'<<16 | ' '<<24, + GEORGIAN = 'K' | 'A'<<8 | 'T'<<16 | ' '<<24, + GEPO = 'Y' | 'G'<<8 | 'P'<<16 | ' '<<24, + GERMAN = 'D' | 'E'<<8 | 'U'<<16 | ' '<<24, + GIKUYU = 'K' | 'I'<<8 | 'K'<<16 | ' '<<24, + GILAKI = 'G' | 'L'<<8 | 'K'<<16 | ' '<<24, + GILBERTESE = 'G' | 'I'<<8 | 'L'<<16 | '0'<<24, + GILYAK = 'G' | 'I'<<8 | 'L'<<16 | ' '<<24, + GITHABUL = 'G' | 'I'<<8 | 'H'<<16 | ' '<<24, + GOGO = 'G' | 'O'<<8 | 'G'<<16 | ' '<<24, + GONDI = 'G' | 'O'<<8 | 'N'<<16 | ' '<<24, + GREEK = 'E' | 'L'<<8 | 'L'<<16 | ' '<<24, + GREENLANDIC = 'G' | 'R'<<8 | 'N'<<16 | ' '<<24, + GUARANI = 'G' | 'U'<<8 | 'A'<<16 | ' '<<24, + GUINEA = 'G' | 'K'<<8 | 'P'<<16 | ' '<<24, + GUJARATI = 'G' | 'U'<<8 | 'J'<<16 | ' '<<24, + GUMATJ = 'G' | 'N'<<8 | 'N'<<16 | ' '<<24, + GUMUZ = 'G' | 'M'<<8 | 'Z'<<16 | ' '<<24, + GUPAPUYNGU = 'G' | 'U'<<8 | 'F'<<16 | ' '<<24, + GUSII = 'G' | 'U'<<8 | 'Z'<<16 | ' '<<24, + HAIDA = 'H' | 'A'<<8 | 'I'<<16 | '0'<<24, + HAITIAN_CREOLE = 'H' | 'A'<<8 | 'I'<<16 | ' '<<24, + HALKOMELEM = 'H' | 'U'<<8 | 'R'<<16 | ' '<<24, + HAMMER_BANNA = 'H' | 'B'<<8 | 'N'<<16 | ' '<<24, + HARARI = 'H' | 'R'<<8 | 'I'<<16 | ' '<<24, + HARAUTI = 'H' | 'A'<<8 | 'R'<<16 | ' '<<24, + HARYANVI = 'B' | 'G'<<8 | 'C'<<16 | ' '<<24, + HAUSA = 'H' | 'A'<<8 | 'U'<<16 | ' '<<24, + HAVASUPAI_WALAPAI_YAVAPAI = 'Y' | 'U'<<8 | 'F'<<16 | ' '<<24, + HAWAIIAN = 'H' | 'A'<<8 | 'W'<<16 | ' '<<24, + HAYA = 'H' | 'A'<<8 | 'Y'<<16 | ' '<<24, + HAZARAGI = 'H' | 'A'<<8 | 'Z'<<16 | ' '<<24, + HEBREW = 'I' | 'W'<<8 | 'R'<<16 | ' '<<24, + HEILTSUK = 'H' | 'E'<<8 | 'I'<<16 | ' '<<24, + HERERO = 'H' | 'E'<<8 | 'R'<<16 | ' '<<24, + HIGH_MARI = 'H' | 'M'<<8 | 'A'<<16 | ' '<<24, + HILIGAYNON = 'H' | 'I'<<8 | 'L'<<16 | ' '<<24, + HINDI = 'H' | 'I'<<8 | 'N'<<16 | ' '<<24, + HINDKO = 'H' | 'N'<<8 | 'D'<<16 | ' '<<24, + HIRI_MOTU = 'H' | 'M'<<8 | 'O'<<16 | ' '<<24, + HMONG = 'H' | 'M'<<8 | 'N'<<16 | ' '<<24, + HMONG_DAW = 'M' | 'W'<<8 | 'W'<<16 | ' '<<24, + HMONG_SHUAT = 'H' | 'M'<<8 | 'Z'<<16 | ' '<<24, + HO = 'H' | 'O'<<8 | ' '<<16 | ' '<<24, + HUNGARIAN = 'H' | 'U'<<8 | 'N'<<16 | ' '<<24, + IBAN = 'I' | 'B'<<8 | 'A'<<16 | ' '<<24, + IBIBIO = 'I' | 'B'<<8 | 'B'<<16 | ' '<<24, + ICELANDIC = 'I' | 'S'<<8 | 'L'<<16 | ' '<<24, + IDO = 'I' | 'D'<<8 | 'O'<<16 | ' '<<24, + IGBO = 'I' | 'B'<<8 | 'O'<<16 | ' '<<24, + IJO = 'I' | 'J'<<8 | 'O'<<16 | ' '<<24, + ILOKANO = 'I' | 'L'<<8 | 'O'<<16 | ' '<<24, + INARI_SAMI = 'I' | 'S'<<8 | 'M'<<16 | ' '<<24, + INDONESIAN = 'I' | 'N'<<8 | 'D'<<16 | ' '<<24, + INGUSH = 'I' | 'N'<<8 | 'G'<<16 | ' '<<24, + INTERLINGUA = 'I' | 'N'<<8 | 'A'<<16 | ' '<<24, + INTERLINGUE = 'I' | 'L'<<8 | 'E'<<16 | ' '<<24, + INUKTITUT = 'I' | 'N'<<8 | 'U'<<16 | ' '<<24, + INUPIAT = 'I' | 'P'<<8 | 'K'<<16 | ' '<<24, + IPA_PHONETIC = 'I' | 'P'<<8 | 'P'<<16 | ' '<<24, + IRISH = 'I' | 'R'<<8 | 'I'<<16 | ' '<<24, + IRISH_TRADITIONAL = 'I' | 'R'<<8 | 'T'<<16 | ' '<<24, + IRULA = 'I' | 'R'<<8 | 'U'<<16 | ' '<<24, + ITALIAN = 'I' | 'T'<<8 | 'A'<<16 | ' '<<24, + JAMAICAN_CREOLE = 'J' | 'A'<<8 | 'M'<<16 | ' '<<24, + JAPANESE = 'J' | 'A'<<8 | 'N'<<16 | ' '<<24, + JAVANESE = 'J' | 'A'<<8 | 'V'<<16 | ' '<<24, + JENNU_KURUMA = 'X' | 'U'<<8 | 'J'<<16 | ' '<<24, + JUDEO_TAT = 'J' | 'D'<<8 | 'T'<<16 | ' '<<24, + JULA = 'J' | 'U'<<8 | 'L'<<16 | ' '<<24, + KABARDIAN = 'K' | 'A'<<8 | 'B'<<16 | ' '<<24, + KABYLE = 'K' | 'A'<<8 | 'B'<<16 | '0'<<24, + KACHCHI = 'K' | 'A'<<8 | 'C'<<16 | ' '<<24, + KADIWEU = 'K' | 'B'<<8 | 'C'<<16 | ' '<<24, + KALENJIN = 'K' | 'A'<<8 | 'L'<<16 | ' '<<24, + KALMYK = 'K' | 'L'<<8 | 'M'<<16 | ' '<<24, + KAMBA = 'K' | 'M'<<8 | 'B'<<16 | ' '<<24, + KANAUJI = 'B' | 'J'<<8 | 'J'<<16 | ' '<<24, + KANNADA = 'K' | 'A'<<8 | 'N'<<16 | ' '<<24, + KANURI = 'K' | 'N'<<8 | 'R'<<16 | ' '<<24, + KAQCHIKEL = 'C' | 'A'<<8 | 'K'<<16 | ' '<<24, + KARACHAY = 'K' | 'A'<<8 | 'R'<<16 | ' '<<24, + KARAIM = 'K' | 'R'<<8 | 'M'<<16 | ' '<<24, + KARAKALPAK = 'K' | 'R'<<8 | 'K'<<16 | ' '<<24, + KARELIAN = 'K' | 'R'<<8 | 'L'<<16 | ' '<<24, + KAREN = 'K' | 'R'<<8 | 'N'<<16 | ' '<<24, + KASHMIRI = 'K' | 'S'<<8 | 'H'<<16 | ' '<<24, + KASHUBIAN = 'C' | 'S'<<8 | 'B'<<16 | ' '<<24, + KATE = 'K' | 'M'<<8 | 'G'<<16 | ' '<<24, + KAZAKH = 'K' | 'A'<<8 | 'Z'<<16 | ' '<<24, + KEBENA = 'K' | 'E'<<8 | 'B'<<16 | ' '<<24, + KEKCHI = 'K' | 'E'<<8 | 'K'<<16 | ' '<<24, + KHAKASS = 'K' | 'H'<<8 | 'A'<<16 | ' '<<24, + KHAMTI_SHAN = 'K' | 'H'<<8 | 'T'<<16 | ' '<<24, + KHAMYANG = 'K' | 'S'<<8 | 'U'<<16 | ' '<<24, + KHANTY_KAZIM = 'K' | 'H'<<8 | 'K'<<16 | ' '<<24, + KHANTY_SHURISHKAR = 'K' | 'H'<<8 | 'S'<<16 | ' '<<24, + KHANTY_VAKHI = 'K' | 'H'<<8 | 'V'<<16 | ' '<<24, + KHASI = 'K' | 'S'<<8 | 'I'<<16 | ' '<<24, + KHENGKHA = 'X' | 'K'<<8 | 'F'<<16 | ' '<<24, + KHINALUG = 'K' | 'J'<<8 | 'J'<<16 | ' '<<24, + KHMER = 'K' | 'H'<<8 | 'M'<<16 | ' '<<24, + KHORASANI_TURKIC = 'K' | 'M'<<8 | 'Z'<<16 | ' '<<24, + KHOWAR = 'K' | 'H'<<8 | 'W'<<16 | ' '<<24, + KHUTSURI_GEORGIAN = 'K' | 'G'<<8 | 'E'<<16 | ' '<<24, + KICHE = 'Q' | 'U'<<8 | 'C'<<16 | ' '<<24, + KIKONGO = 'K' | 'O'<<8 | 'N'<<16 | ' '<<24, + KILDIN_SAMI = 'K' | 'S'<<8 | 'M'<<16 | ' '<<24, + KINYARWANDA = 'R' | 'U'<<8 | 'A'<<16 | ' '<<24, + KIRMANJKI = 'K' | 'I'<<8 | 'U'<<16 | ' '<<24, + KISII = 'K' | 'I'<<8 | 'S'<<16 | ' '<<24, + KITUBA = 'M' | 'K'<<8 | 'W'<<16 | ' '<<24, + KODAGU = 'K' | 'O'<<8 | 'D'<<16 | ' '<<24, + KOKNI = 'K' | 'K'<<8 | 'N'<<16 | ' '<<24, + KOMI = 'K' | 'O'<<8 | 'M'<<16 | ' '<<24, + KOMI_PERMYAK = 'K' | 'O'<<8 | 'P'<<16 | ' '<<24, + KOMI_ZYRIAN = 'K' | 'O'<<8 | 'Z'<<16 | ' '<<24, + KOMO = 'K' | 'M'<<8 | 'O'<<16 | ' '<<24, + KOMSO = 'K' | 'M'<<8 | 'S'<<16 | ' '<<24, + KONGO = 'K' | 'O'<<8 | 'N'<<16 | '0'<<24, + KONKANI = 'K' | 'O'<<8 | 'K'<<16 | ' '<<24, + KOORETE = 'K' | 'R'<<8 | 'T'<<16 | ' '<<24, + KOREAN = 'K' | 'O'<<8 | 'R'<<16 | ' '<<24, + KOREAO_OLD_HANGUL = 'K' | 'O'<<8 | 'H'<<16 | ' '<<24, + KORYAK = 'K' | 'Y'<<8 | 'K'<<16 | ' '<<24, + KOSRAEAN = 'K' | 'O'<<8 | 'S'<<16 | ' '<<24, + KPELLE = 'K' | 'P'<<8 | 'L'<<16 | ' '<<24, + KPELLE_LIBERIA = 'X' | 'P'<<8 | 'E'<<16 | ' '<<24, + KRIO = 'K' | 'R'<<8 | 'I'<<16 | ' '<<24, + KRYMCHAK = 'J' | 'C'<<8 | 'T'<<16 | ' '<<24, + KUANYAMA = 'K' | 'U'<<8 | 'A'<<16 | ' '<<24, + KUBE = 'K' | 'G'<<8 | 'F'<<16 | ' '<<24, + KUI = 'K' | 'U'<<8 | 'I'<<16 | ' '<<24, + KULVI = 'K' | 'U'<<8 | 'K'<<16 | ' '<<24, + KUMAONI = 'K' | 'M'<<8 | 'N'<<16 | ' '<<24, + KUMYK = 'K' | 'U'<<8 | 'M'<<16 | ' '<<24, + KURDISH = 'K' | 'U'<<8 | 'R'<<16 | ' '<<24, + KURUKH = 'K' | 'U'<<8 | 'U'<<16 | ' '<<24, + KUY = 'K' | 'U'<<8 | 'Y'<<16 | ' '<<24, + KWAKWALA = 'K' | 'W'<<8 | 'K'<<16 | ' '<<24, + KYRGYZ = 'K' | 'I'<<8 | 'R'<<16 | ' '<<24, + L_CREE = 'L' | 'C'<<8 | 'R'<<16 | ' '<<24, + LADAKHI = 'L' | 'D'<<8 | 'K'<<16 | ' '<<24, + LADIN = 'L' | 'A'<<8 | 'D'<<16 | ' '<<24, + LADINO = 'J' | 'U'<<8 | 'D'<<16 | ' '<<24, + LAHULI = 'L' | 'A'<<8 | 'H'<<16 | ' '<<24, + LAK = 'L' | 'A'<<8 | 'K'<<16 | ' '<<24, + LAKI = 'L' | 'K'<<8 | 'I'<<16 | ' '<<24, + LAMBANI = 'L' | 'A'<<8 | 'M'<<16 | ' '<<24, + LAMPUNG = 'L' | 'J'<<8 | 'P'<<16 | ' '<<24, + LAO = 'L' | 'A'<<8 | 'O'<<16 | ' '<<24, + LATIN = 'L' | 'A'<<8 | 'T'<<16 | ' '<<24, + LATVIAN = 'L' | 'V'<<8 | 'I'<<16 | ' '<<24, + LAZ = 'L' | 'A'<<8 | 'Z'<<16 | ' '<<24, + LELEMI = 'L' | 'E'<<8 | 'F'<<16 | ' '<<24, + LEZGI = 'L' | 'E'<<8 | 'Z'<<16 | ' '<<24, + LIGURIAN = 'L' | 'I'<<8 | 'J'<<16 | ' '<<24, + LIMBU = 'L' | 'M'<<8 | 'B'<<16 | ' '<<24, + LIMBURGISH = 'L' | 'I'<<8 | 'M'<<16 | ' '<<24, + LINGALA = 'L' | 'I'<<8 | 'N'<<16 | ' '<<24, + LIPO = 'L' | 'P'<<8 | 'O'<<16 | ' '<<24, + LISU = 'L' | 'I'<<8 | 'S'<<16 | ' '<<24, + LITHUANIAN = 'L' | 'T'<<8 | 'H'<<16 | ' '<<24, + LIV = 'L' | 'I'<<8 | 'V'<<16 | ' '<<24, + LOJBAN = 'J' | 'B'<<8 | 'O'<<16 | ' '<<24, + LOMA = 'L' | 'O'<<8 | 'M'<<16 | ' '<<24, + LOMBARD = 'L' | 'M'<<8 | 'O'<<16 | ' '<<24, + LOMWE = 'L' | 'M'<<8 | 'W'<<16 | ' '<<24, + LOW_MARI = 'L' | 'M'<<8 | 'A'<<16 | ' '<<24, + LOW_SAXON = 'N' | 'D'<<8 | 'S'<<16 | ' '<<24, + LOWER_SORBIAN = 'L' | 'S'<<8 | 'B'<<16 | ' '<<24, + LU = 'X' | 'B'<<8 | 'D'<<16 | ' '<<24, + LUBA_KATANGA = 'L' | 'U'<<8 | 'B'<<16 | ' '<<24, + LUBA_LULUA = 'L' | 'U'<<8 | 'A'<<16 | ' '<<24, + LULE_SAMI = 'L' | 'S'<<8 | 'M'<<16 | ' '<<24, + LUO = 'L' | 'U'<<8 | 'O'<<16 | ' '<<24, + LURI = 'L' | 'R'<<8 | 'C'<<16 | ' '<<24, + LUSHOOTSEED = 'L' | 'U'<<8 | 'T'<<16 | ' '<<24, + LUXEMBOURGISH = 'L' | 'T'<<8 | 'Z'<<16 | ' '<<24, + LUYIA = 'L' | 'U'<<8 | 'H'<<16 | ' '<<24, + MACEDONIAN = 'M' | 'K'<<8 | 'D'<<16 | ' '<<24, + MADURA = 'M' | 'A'<<8 | 'D'<<16 | ' '<<24, + MAGAHI = 'M' | 'A'<<8 | 'G'<<16 | ' '<<24, + MAITHILI = 'M' | 'T'<<8 | 'H'<<16 | ' '<<24, + MAJANG = 'M' | 'A'<<8 | 'J'<<16 | ' '<<24, + MAKASAR = 'M' | 'K'<<8 | 'R'<<16 | ' '<<24, + MAKHUWA = 'M' | 'A'<<8 | 'K'<<16 | ' '<<24, + MAKONDE = 'K' | 'D'<<8 | 'E'<<16 | ' '<<24, + MALAGASY = 'M' | 'L'<<8 | 'G'<<16 | ' '<<24, + MALAY = 'M' | 'L'<<8 | 'Y'<<16 | ' '<<24, + MALAYALAM = 'M' | 'A'<<8 | 'L'<<16 | ' '<<24, + MALAYALAM_REFORMED = 'M' | 'L'<<8 | 'R'<<16 | ' '<<24, + MALE = 'M' | 'L'<<8 | 'E'<<16 | ' '<<24, + MALINKE = 'M' | 'L'<<8 | 'N'<<16 | ' '<<24, + MALTESE = 'M' | 'T'<<8 | 'S'<<16 | ' '<<24, + MAM = 'M' | 'A'<<8 | 'M'<<16 | ' '<<24, + MANCHU = 'M' | 'C'<<8 | 'H'<<16 | ' '<<24, + MANDAR = 'M' | 'D'<<8 | 'R'<<16 | ' '<<24, + MANDINKA = 'M' | 'N'<<8 | 'D'<<16 | ' '<<24, + MANINKA = 'M' | 'N'<<8 | 'K'<<16 | ' '<<24, + MANIPURI = 'M' | 'N'<<8 | 'I'<<16 | ' '<<24, + MANO = 'M' | 'E'<<8 | 'V'<<16 | ' '<<24, + MANSI = 'M' | 'A'<<8 | 'N'<<16 | ' '<<24, + MANX = 'M' | 'N'<<8 | 'X'<<16 | ' '<<24, + MAORI = 'M' | 'R'<<8 | 'I'<<16 | ' '<<24, + MAPUDUNGUN = 'M' | 'A'<<8 | 'P'<<16 | ' '<<24, + MARATHI = 'M' | 'A'<<8 | 'R'<<16 | ' '<<24, + MARSHALLESE = 'M' | 'A'<<8 | 'H'<<16 | ' '<<24, + MARWARI = 'M' | 'A'<<8 | 'W'<<16 | ' '<<24, + MAYAN = 'M' | 'Y'<<8 | 'N'<<16 | ' '<<24, + MAZANDERANI = 'M' | 'Z'<<8 | 'N'<<16 | ' '<<24, + MBEMBE_TIGON = 'N' | 'Z'<<8 | 'A'<<16 | ' '<<24, + MBO = 'M' | 'B'<<8 | 'O'<<16 | ' '<<24, + MBUNDU = 'M' | 'B'<<8 | 'N'<<16 | ' '<<24, + MEDUMBA = 'B' | 'Y'<<8 | 'V'<<16 | ' '<<24, + MEEN = 'M' | 'E'<<8 | 'N'<<16 | ' '<<24, + MENDE = 'M' | 'D'<<8 | 'E'<<16 | ' '<<24, + MERU = 'M' | 'E'<<8 | 'R'<<16 | ' '<<24, + MEWATI = 'W' | 'T'<<8 | 'M'<<16 | ' '<<24, + MINANGKABAU = 'M' | 'I'<<8 | 'N'<<16 | ' '<<24, + MINJANGBAL = 'X' | 'J'<<8 | 'B'<<16 | ' '<<24, + MIRANDESE = 'M' | 'W'<<8 | 'L'<<16 | ' '<<24, + MIZO = 'M' | 'I'<<8 | 'Z'<<16 | ' '<<24, + MOHAWK = 'M' | 'O'<<8 | 'H'<<16 | ' '<<24, + MOKSHA = 'M' | 'O'<<8 | 'K'<<16 | ' '<<24, + MOLDAVIAN = 'M' | 'O'<<8 | 'L'<<16 | ' '<<24, + MON = 'M' | 'O'<<8 | 'N'<<16 | ' '<<24, + MONGOLIAN = 'M' | 'N'<<8 | 'G'<<16 | ' '<<24, + MOOSE_CREE = 'M' | 'C'<<8 | 'R'<<16 | ' '<<24, + MORISYEN = 'M' | 'F'<<8 | 'E'<<16 | ' '<<24, + MOROCCAN = 'M' | 'O'<<8 | 'R'<<16 | ' '<<24, + MOSSI = 'M' | 'P'<<8 | 'S'<<16 | ' '<<24, + MUNDARI = 'M' | 'U'<<8 | 'N'<<16 | ' '<<24, + MUSCOGEE = 'M' | 'U'<<8 | 'S'<<16 | ' '<<24, + N_CREE = 'N' | 'C'<<8 | 'R'<<16 | ' '<<24, + NAGA_ASSAMESE = 'N' | 'A'<<8 | 'G'<<16 | ' '<<24, + NAGARI = 'N' | 'G'<<8 | 'R'<<16 | ' '<<24, + NAHUATL = 'N' | 'A'<<8 | 'H'<<16 | ' '<<24, + NANAI = 'N' | 'A'<<8 | 'N'<<16 | ' '<<24, + NASKAPI = 'N' | 'A'<<8 | 'S'<<16 | ' '<<24, + NAURUAN = 'N' | 'A'<<8 | 'U'<<16 | ' '<<24, + NAVAJO = 'N' | 'A'<<8 | 'V'<<16 | ' '<<24, + NDAU = 'N' | 'D'<<8 | 'C'<<16 | ' '<<24, + NDEBELE = 'N' | 'D'<<8 | 'B'<<16 | ' '<<24, + NDONGA = 'N' | 'D'<<8 | 'G'<<16 | ' '<<24, + NEAPOLITAN = 'N' | 'A'<<8 | 'P'<<16 | ' '<<24, + NEPALI = 'N' | 'E'<<8 | 'P'<<16 | ' '<<24, + NEWARI = 'N' | 'E'<<8 | 'W'<<16 | ' '<<24, + NGBAKA = 'N' | 'G'<<8 | 'A'<<16 | ' '<<24, + NIGERIAN_FULFULDE = 'F' | 'U'<<8 | 'V'<<16 | ' '<<24, + NIMADI = 'N' | 'O'<<8 | 'E'<<16 | ' '<<24, + NISI = 'N' | 'I'<<8 | 'S'<<16 | ' '<<24, + NIUEAN = 'N' | 'I'<<8 | 'U'<<16 | ' '<<24, + NKO = 'N' | 'K'<<8 | 'O'<<16 | ' '<<24, + NOGAI = 'N' | 'O'<<8 | 'G'<<16 | ' '<<24, + NORFOLK = 'P' | 'I'<<8 | 'H'<<16 | ' '<<24, + NORTH_SLAVEY = 'S' | 'C'<<8 | 'S'<<16 | ' '<<24, + NORTHERN_EMBERA = 'E' | 'M'<<8 | 'P'<<16 | ' '<<24, + NORTHERN_SAMI = 'N' | 'S'<<8 | 'M'<<16 | ' '<<24, + NORTHERN_SOTHO = 'N' | 'S'<<8 | 'O'<<16 | ' '<<24, + NORTHERN_TAI = 'N' | 'T'<<8 | 'A'<<16 | ' '<<24, + NORWAY_HOUSE_CREE = 'N' | 'H'<<8 | 'C'<<16 | ' '<<24, + NORWEGIAN = 'N' | 'O'<<8 | 'R'<<16 | ' '<<24, + NORWEGIAN_NYNORSK = 'N' | 'Y'<<8 | 'N'<<16 | ' '<<24, + NOVIAL = 'N' | 'O'<<8 | 'V'<<16 | ' '<<24, + NUMANGGANG = 'N' | 'O'<<8 | 'P'<<16 | ' '<<24, + NUNAVIK_INUKTITUT = 'I' | 'N'<<8 | 'U'<<16 | ' '<<24, + NUU_CHAH_NULTH = 'N' | 'U'<<8 | 'K'<<16 | ' '<<24, + NYAMWEZI = 'N' | 'Y'<<8 | 'M'<<16 | ' '<<24, + NYANKOLE = 'N' | 'K'<<8 | 'L'<<16 | ' '<<24, + OCCITAN = 'O' | 'C'<<8 | 'I'<<16 | ' '<<24, + ODIA = 'O' | 'R'<<8 | 'I'<<16 | ' '<<24, + OJI_CREE = 'O' | 'C'<<8 | 'R'<<16 | ' '<<24, + OJIBWAY = 'O' | 'J'<<8 | 'B'<<16 | ' '<<24, + OLD_IRISH = 'S' | 'G'<<8 | 'A'<<16 | ' '<<24, + OLD_JAVANESE = 'K' | 'A'<<8 | 'W'<<16 | ' '<<24, + ONEIDA = 'O' | 'N'<<8 | 'E'<<16 | ' '<<24, + ONONDAGA = 'O' | 'N'<<8 | 'O'<<16 | ' '<<24, + OROMO = 'O' | 'R'<<8 | 'O'<<16 | ' '<<24, + OSSETIAN = 'O' | 'S'<<8 | 'S'<<16 | ' '<<24, + PA_O_KAREN = 'B' | 'L'<<8 | 'K'<<16 | ' '<<24, + PALAUAN = 'P' | 'A'<<8 | 'U'<<16 | ' '<<24, + PALAUNG = 'P' | 'L'<<8 | 'G'<<16 | ' '<<24, + PALESTINIAN_ARAMAIC = 'P' | 'A'<<8 | 'A'<<16 | ' '<<24, + PALI = 'P' | 'A'<<8 | 'L'<<16 | ' '<<24, + PALPA = 'P' | 'A'<<8 | 'P'<<16 | ' '<<24, + PAMPANGAN = 'P' | 'A'<<8 | 'M'<<16 | ' '<<24, + PANGASINAN = 'P' | 'A'<<8 | 'G'<<16 | ' '<<24, + PAPIAMENTU = 'P' | 'A'<<8 | 'P'<<16 | '0'<<24, + PASHTO = 'P' | 'A'<<8 | 'S'<<16 | ' '<<24, + PATTANI_MALAY = 'M' | 'F'<<8 | 'A'<<16 | ' '<<24, + PENNSYLVANIA_GERMAN = 'P' | 'D'<<8 | 'C'<<16 | ' '<<24, + PERSIAN = 'F' | 'A'<<8 | 'R'<<16 | ' '<<24, + PHAKE = 'P' | 'J'<<8 | 'K'<<16 | ' '<<24, + PICARD = 'P' | 'C'<<8 | 'D'<<16 | ' '<<24, + PIEMONTESE = 'P' | 'M'<<8 | 'S'<<16 | ' '<<24, + PILAGA = 'P' | 'L'<<8 | 'G'<<16 | ' '<<24, + PITE_SAMI = 'S' | 'J'<<8 | 'E'<<16 | ' '<<24, + POCOMCHI = 'P' | 'O'<<8 | 'H'<<16 | ' '<<24, + POHNPEIAN = 'P' | 'O'<<8 | 'N'<<16 | ' '<<24, + POLISH = 'P' | 'L'<<8 | 'K'<<16 | ' '<<24, + POLYTONIC_GREEK = 'P' | 'G'<<8 | 'R'<<16 | ' '<<24, + PORTUGUESE = 'P' | 'T'<<8 | 'G'<<16 | ' '<<24, + PROVENCAL = 'P' | 'R'<<8 | 'O'<<16 | ' '<<24, + PUNJABI = 'P' | 'A'<<8 | 'N'<<16 | ' '<<24, + QUECHUA = 'Q' | 'U'<<8 | 'Z'<<16 | ' '<<24, + QUECHUA_BOLIVIA = 'Q' | 'U'<<8 | 'H'<<16 | ' '<<24, + QUECHUA_ECUADOR = 'Q' | 'V'<<8 | 'I'<<16 | ' '<<24, + QUECHUA_PERU = 'Q' | 'W'<<8 | 'H'<<16 | ' '<<24, + R_CREE = 'R' | 'C'<<8 | 'R'<<16 | ' '<<24, + RAJASTHANI = 'R' | 'A'<<8 | 'J'<<16 | ' '<<24, + RAKHINE = 'A' | 'R'<<8 | 'K'<<16 | ' '<<24, + RAROTONGAN = 'R' | 'A'<<8 | 'R'<<16 | ' '<<24, + REJANG = 'R' | 'E'<<8 | 'J'<<16 | ' '<<24, + RIANG = 'R' | 'I'<<8 | 'A'<<16 | ' '<<24, + RIPUARIAN = 'K' | 'S'<<8 | 'H'<<16 | ' '<<24, + RITARUNGO = 'R' | 'I'<<8 | 'T'<<16 | ' '<<24, + ROHINGYA = 'R' | 'H'<<8 | 'G'<<16 | ' '<<24, + ROMANIAN = 'R' | 'O'<<8 | 'M'<<16 | ' '<<24, + ROMANSH = 'R' | 'M'<<8 | 'S'<<16 | ' '<<24, + ROMANY = 'R' | 'O'<<8 | 'Y'<<16 | ' '<<24, + ROTUMAN = 'R' | 'T'<<8 | 'M'<<16 | ' '<<24, + RUNDI = 'R' | 'U'<<8 | 'N'<<16 | ' '<<24, + RUSSIAN = 'R' | 'U'<<8 | 'S'<<16 | ' '<<24, + RUSSIAN_BURIAT = 'R' | 'B'<<8 | 'U'<<16 | ' '<<24, + RUSYN = 'R' | 'S'<<8 | 'Y'<<16 | ' '<<24, + SADRI = 'S' | 'A'<<8 | 'D'<<16 | ' '<<24, + SAKHA = 'Y' | 'A'<<8 | 'K'<<16 | ' '<<24, + SAMOAN = 'S' | 'M'<<8 | 'O'<<16 | ' '<<24, + SAMOGITIAN = 'S' | 'G'<<8 | 'S'<<16 | ' '<<24, + SAN_BLAS_KUNA = 'C' | 'U'<<8 | 'K'<<16 | ' '<<24, + SANGO = 'S' | 'G'<<8 | 'O'<<16 | ' '<<24, + SANSKRIT = 'S' | 'A'<<8 | 'N'<<16 | ' '<<24, + SANTALI = 'S' | 'A'<<8 | 'T'<<16 | ' '<<24, + SARAIKI = 'S' | 'R'<<8 | 'K'<<16 | ' '<<24, + SARDINIAN = 'S' | 'R'<<8 | 'D'<<16 | ' '<<24, + SASAK = 'S' | 'A'<<8 | 'S'<<16 | ' '<<24, + SATERLAND_FRISIAN = 'S' | 'T'<<8 | 'Q'<<16 | ' '<<24, + SAYISI = 'S' | 'A'<<8 | 'Y'<<16 | ' '<<24, + SCOTS = 'S' | 'C'<<8 | 'I'<<16 | ' '<<24, + SCOTTISH_GAELIC = 'G' | 'A'<<8 | 'E'<<16 | ' '<<24, + SEKOTA = 'S' | 'E'<<8 | 'J'<<16 | ' '<<24, + SELKUP = 'S' | 'E'<<8 | 'L'<<16 | ' '<<24, + SENA = 'S' | 'N'<<8 | 'A'<<16 | ' '<<24, + SENECA = 'S' | 'E'<<8 | 'E'<<16 | ' '<<24, + SERBIAN = 'S' | 'R'<<8 | 'B'<<16 | ' '<<24, + SERER = 'S' | 'R'<<8 | 'R'<<16 | ' '<<24, + SGAW_KAREN = 'K' | 'S'<<8 | 'W'<<16 | ' '<<24, + SHAN = 'S' | 'H'<<8 | 'N'<<16 | ' '<<24, + SHONA = 'S' | 'N'<<8 | 'A'<<16 | ' '<<24, + SIBE = 'S' | 'I'<<8 | 'B'<<16 | ' '<<24, + SICILIAN = 'S' | 'C'<<8 | 'N'<<16 | ' '<<24, + SIDAMO = 'S' | 'I'<<8 | 'D'<<16 | ' '<<24, + SILESIAN = 'S' | 'Z'<<8 | 'L'<<16 | ' '<<24, + SILTE_GURAGE = 'S' | 'I'<<8 | 'G'<<16 | ' '<<24, + SINDHI = 'S' | 'N'<<8 | 'D'<<16 | ' '<<24, + SINHALA = 'S' | 'N'<<8 | 'H'<<16 | ' '<<24, + SKOLT_SAMI = 'S' | 'K'<<8 | 'S'<<16 | ' '<<24, + SLAVEY = 'S' | 'L'<<8 | 'A'<<16 | ' '<<24, + SLOVAK = 'S' | 'K'<<8 | 'Y'<<16 | ' '<<24, + SLOVENIAN = 'S' | 'L'<<8 | 'V'<<16 | ' '<<24, + SMALL_FLOWERY_MIAO = 'S' | 'F'<<8 | 'M'<<16 | ' '<<24, + SODO_GURAGE = 'S' | 'O'<<8 | 'G'<<16 | ' '<<24, + SOGA = 'X' | 'O'<<8 | 'G'<<16 | ' '<<24, + SOMALI = 'S' | 'M'<<8 | 'L'<<16 | ' '<<24, + SONGE = 'S' | 'O'<<8 | 'P'<<16 | ' '<<24, + SONINKE = 'S' | 'N'<<8 | 'K'<<16 | ' '<<24, + SOUTH_SLAVEY = 'S' | 'S'<<8 | 'L'<<16 | ' '<<24, + SOUTHERN_KIWAI = 'K' | 'J'<<8 | 'D'<<16 | ' '<<24, + SOUTHERN_SAMI = 'S' | 'S'<<8 | 'M'<<16 | ' '<<24, + SOUTHERN_SOTHO = 'S' | 'O'<<8 | 'T'<<16 | ' '<<24, + SPANISH = 'E' | 'S'<<8 | 'P'<<16 | ' '<<24, + STANDARD_MOROCCAN_TAMAZIGHT = 'Z' | 'G'<<8 | 'H'<<16 | ' '<<24, + STRAITS_SALISH = 'S' | 'T'<<8 | 'R'<<16 | ' '<<24, + SUKUMA = 'S' | 'U'<<8 | 'K'<<16 | ' '<<24, + SUNDANESE = 'S' | 'U'<<8 | 'N'<<16 | ' '<<24, + SURI = 'S' | 'U'<<8 | 'R'<<16 | ' '<<24, + SUTU = 'S' | 'X'<<8 | 'T'<<16 | ' '<<24, + SVAN = 'S' | 'V'<<8 | 'A'<<16 | ' '<<24, + SWADAYA_ARAMAIC = 'S' | 'W'<<8 | 'A'<<16 | ' '<<24, + SWAHILI = 'S' | 'W'<<8 | 'K'<<16 | ' '<<24, + SWATI = 'S' | 'W'<<8 | 'Z'<<16 | ' '<<24, + SWEDISH = 'S' | 'V'<<8 | 'E'<<16 | ' '<<24, + SYLHETI = 'S' | 'Y'<<8 | 'L'<<16 | ' '<<24, + SYRIAC = 'S' | 'Y'<<8 | 'R'<<16 | ' '<<24, + SYRIAC_EASTERN = 'S' | 'Y'<<8 | 'R'<<16 | 'N'<<24, + SYRIAC_ESTRANGELA = 'S' | 'Y'<<8 | 'R'<<16 | 'E'<<24, + SYRIAC_WESTERN = 'S' | 'Y'<<8 | 'R'<<16 | 'J'<<24, + TABASARAN = 'T' | 'A'<<8 | 'B'<<16 | ' '<<24, + TACHELHIT = 'S' | 'H'<<8 | 'I'<<16 | ' '<<24, + TAGALOG = 'T' | 'G'<<8 | 'L'<<16 | ' '<<24, + TAHAGGART_TAMAHAQ = 'T' | 'H'<<8 | 'V'<<16 | ' '<<24, + TAHITIAN = 'T' | 'H'<<8 | 'T'<<16 | ' '<<24, + TAI_LAING = 'T' | 'J'<<8 | 'L'<<16 | ' '<<24, + TAJIKI = 'T' | 'A'<<8 | 'J'<<16 | ' '<<24, + TALYSH = 'T' | 'L'<<8 | 'Y'<<16 | ' '<<24, + TAMASHEK = 'T' | 'M'<<8 | 'H'<<16 | ' '<<24, + TAMASHEQ = 'T' | 'A'<<8 | 'Q'<<16 | ' '<<24, + TAMAZIGHT = 'T' | 'Z'<<8 | 'M'<<16 | ' '<<24, + TAMIL = 'T' | 'A'<<8 | 'M'<<16 | ' '<<24, + TARIFIT = 'R' | 'I'<<8 | 'F'<<16 | ' '<<24, + TATAR = 'T' | 'A'<<8 | 'T'<<16 | ' '<<24, + TAWALLAMMAT_TAMAJAQ = 'T' | 'T'<<8 | 'Q'<<16 | ' '<<24, + TAY = 'T' | 'Y'<<8 | 'Z'<<16 | ' '<<24, + TAYART_TAMAJEQ = 'T' | 'H'<<8 | 'Z'<<16 | ' '<<24, + TELUGU = 'T' | 'E'<<8 | 'L'<<16 | ' '<<24, + TEMNE = 'T' | 'M'<<8 | 'N'<<16 | ' '<<24, + TETUM = 'T' | 'E'<<8 | 'T'<<16 | ' '<<24, + TH_CREE = 'T' | 'C'<<8 | 'R'<<16 | ' '<<24, + THAI = 'T' | 'H'<<8 | 'A'<<16 | ' '<<24, + THAILAND_MON = 'M' | 'O'<<8 | 'N'<<16 | 'T'<<24, + THOMPSON = 'T' | 'H'<<8 | 'P'<<16 | ' '<<24, + TIBETAN = 'T' | 'I'<<8 | 'B'<<16 | ' '<<24, + TIGRE = 'T' | 'G'<<8 | 'R'<<16 | ' '<<24, + TIGRINYA = 'T' | 'G'<<8 | 'Y'<<16 | ' '<<24, + TIV = 'T' | 'I'<<8 | 'V'<<16 | ' '<<24, + TLINGIT = 'T' | 'L'<<8 | 'I'<<16 | ' '<<24, + TOBO = 'T' | 'B'<<8 | 'V'<<16 | ' '<<24, + TODO = 'T' | 'O'<<8 | 'D'<<16 | ' '<<24, + TOK_PISIN = 'T' | 'P'<<8 | 'I'<<16 | ' '<<24, + TOMA = 'T' | 'O'<<8 | 'D'<<16 | '0'<<24, + TONGA = 'T' | 'N'<<8 | 'G'<<16 | ' '<<24, + TONGAN = 'T' | 'G'<<8 | 'N'<<16 | ' '<<24, + TORKI = 'A' | 'Z'<<8 | 'B'<<16 | ' '<<24, + TSHANGLA = 'T' | 'S'<<8 | 'J'<<16 | ' '<<24, + TSONGA = 'T' | 'S'<<8 | 'G'<<16 | ' '<<24, + TSWANA = 'T' | 'N'<<8 | 'A'<<16 | ' '<<24, + TULU = 'T' | 'U'<<8 | 'L'<<16 | ' '<<24, + TUMBUKA = 'T' | 'U'<<8 | 'M'<<16 | ' '<<24, + TUNDRA_ENETS = 'T' | 'N'<<8 | 'E'<<16 | ' '<<24, + TURKISH = 'T' | 'R'<<8 | 'K'<<16 | ' '<<24, + TURKMEN = 'T' | 'K'<<8 | 'M'<<16 | ' '<<24, + TUROYO_ARAMAIC = 'T' | 'U'<<8 | 'A'<<16 | ' '<<24, + TUSCARORA = 'T' | 'U'<<8 | 'S'<<16 | ' '<<24, + TUVALU = 'T' | 'V'<<8 | 'L'<<16 | ' '<<24, + TUVIN = 'T' | 'U'<<8 | 'V'<<16 | ' '<<24, + TWI = 'T' | 'W'<<8 | 'I'<<16 | ' '<<24, + TZOTZIL = 'T' | 'Z'<<8 | 'O'<<16 | ' '<<24, + UDI = 'U' | 'D'<<8 | 'I'<<16 | ' '<<24, + UDMURT = 'U' | 'D'<<8 | 'M'<<16 | ' '<<24, + UKRAINIAN = 'U' | 'K'<<8 | 'R'<<16 | ' '<<24, + UMBUNDU = 'U' | 'M'<<8 | 'B'<<16 | ' '<<24, + UME_SAMI = 'S' | 'J'<<8 | 'U'<<16 | ' '<<24, + UPPER_SAXON = 'S' | 'X'<<8 | 'U'<<16 | ' '<<24, + UPPER_SORBIAN = 'U' | 'S'<<8 | 'B'<<16 | ' '<<24, + URALIC_PHONETIC = 'U' | 'P'<<8 | 'P'<<16 | ' '<<24, + URDU = 'U' | 'R'<<8 | 'D'<<16 | ' '<<24, + UYGHUR = 'U' | 'Y'<<8 | 'G'<<16 | ' '<<24, + UZBEK = 'U' | 'Z'<<8 | 'B'<<16 | ' '<<24, + VENDA = 'V' | 'E'<<8 | 'N'<<16 | ' '<<24, + VENETIAN = 'V' | 'E'<<8 | 'C'<<16 | ' '<<24, + VIETNAMESE = 'V' | 'I'<<8 | 'T'<<16 | ' '<<24, + VLAX_ROMANI = 'R' | 'M'<<8 | 'Y'<<16 | ' '<<24, + VOLAPUK = 'V' | 'O'<<8 | 'L'<<16 | ' '<<24, + VORO = 'V' | 'R'<<8 | 'O'<<16 | ' '<<24, + WA = 'W' | 'A'<<8 | ' '<<16 | ' '<<24, + WACI_GBE = 'W' | 'C'<<8 | 'I'<<16 | ' '<<24, + WAGDI = 'W' | 'A'<<8 | 'G'<<16 | ' '<<24, + WAKHI = 'W' | 'B'<<8 | 'L'<<16 | ' '<<24, + WALLOON = 'W' | 'L'<<8 | 'N'<<16 | ' '<<24, + WARAY_WARAY = 'W' | 'A'<<8 | 'R'<<16 | ' '<<24, + WAYANAD_CHETTI = 'C' | 'T'<<8 | 'T'<<16 | ' '<<24, + WAYUU = 'G' | 'U'<<8 | 'C'<<16 | ' '<<24, + WELSH = 'W' | 'E'<<8 | 'L'<<16 | ' '<<24, + WENDAT = 'W' | 'D'<<8 | 'T'<<16 | ' '<<24, + WEST_CREE = 'W' | 'C'<<8 | 'R'<<16 | ' '<<24, + WESTERN_CHAM = 'C' | 'J'<<8 | 'A'<<16 | ' '<<24, + WESTERN_KAYAH = 'K' | 'Y'<<8 | 'U'<<16 | ' '<<24, + WESTERN_PANJABI = 'P' | 'N'<<8 | 'B'<<16 | ' '<<24, + WESTERN_PWO_KAREN = 'P' | 'W'<<8 | 'O'<<16 | ' '<<24, + WOLOF = 'W' | 'L'<<8 | 'F'<<16 | ' '<<24, + WOODS_CREE = 'D' | 'C'<<8 | 'R'<<16 | ' '<<24, + WUDING_LUQUAN_YI = 'Y' | 'W'<<8 | 'Q'<<16 | ' '<<24, + WYANDOT = 'W' | 'Y'<<8 | 'N'<<16 | ' '<<24, + XHOSA = 'X' | 'H'<<8 | 'S'<<16 | ' '<<24, + Y_CREE = 'Y' | 'C'<<8 | 'R'<<16 | ' '<<24, + YAO = 'Y' | 'A'<<8 | 'O'<<16 | ' '<<24, + YAPESE = 'Y' | 'A'<<8 | 'P'<<16 | ' '<<24, + YI_CLASSIC = 'Y' | 'I'<<8 | 'C'<<16 | ' '<<24, + YI_MODERN = 'Y' | 'I'<<8 | 'M'<<16 | ' '<<24, + YIDDISH = 'J' | 'I'<<8 | 'I'<<16 | ' '<<24, + YORUBA = 'Y' | 'B'<<8 | 'A'<<16 | ' '<<24, + ZAMBOANGA_CHAVACANO = 'C' | 'B'<<8 | 'K'<<16 | ' '<<24, + ZANDE = 'Z' | 'N'<<8 | 'D'<<16 | ' '<<24, + ZARMA = 'D' | 'J'<<8 | 'R'<<16 | ' '<<24, + ZAZAKI = 'Z' | 'Z'<<8 | 'A'<<16 | ' '<<24, + ZEALANDIC = 'Z' | 'E'<<8 | 'A'<<16 | ' '<<24, + ZHUANG = 'Z' | 'H'<<8 | 'A'<<16 | ' '<<24, + ZULU = 'Z' | 'U'<<8 | 'L'<<16 | ' '<<24, } break_flags :: distinct bit_set[break_flag; u32] @@ -780,42 +730,173 @@ break_flag :: enum u32 { // (In Unicode, there is no meaningful distinction between a line and a paragraph. // a paragraph is pretty much just a line of text that can wrap.) LINE_HARD = 5, + // Used for manual segmentation in the context. + MANUAL = 6, + + PARAGRAPH_DIRECTION = 7, } -BREAK_FLAGS_DIRECTION :: break_flags{.DIRECTION} -BREAK_FLAGS_SCRIPT :: break_flags{.SCRIPT} -BREAK_FLAGS_GRAPHEME :: break_flags{.GRAPHEME} -BREAK_FLAGS_WORD :: break_flags{.WORD} -BREAK_FLAGS_LINE_SOFT :: break_flags{.LINE_SOFT} -BREAK_FLAGS_LINE_HARD :: break_flags{.LINE_HARD} -BREAK_FLAGS_LINE :: break_flags{.LINE_SOFT, .LINE_HARD} -BREAK_FLAGS_ANY :: break_flags{.DIRECTION, .SCRIPT, .GRAPHEME, .WORD, .LINE_SOFT, .LINE_HARD} +BREAK_FLAG_DIRECTION :: break_flags{.DIRECTION} +BREAK_FLAG_SCRIPT :: break_flags{.SCRIPT} +BREAK_FLAG_GRAPHEME :: break_flags{.GRAPHEME} +BREAK_FLAG_WORD :: break_flags{.WORD} +BREAK_FLAG_LINE_SOFT :: break_flags{.LINE_SOFT} +BREAK_FLAG_LINE_HARD :: break_flags{.LINE_HARD} +BREAK_FLAG_MANUAL :: break_flags{.MANUAL} +BREAK_FLAG_PARAGRAPH_DIRECTION :: break_flags{.PARAGRAPH_DIRECTION} + +BREAK_FLAG_LINE :: break_flags{.LINE_SOFT, .LINE_HARD} +BREAK_FLAG_ANY :: break_flags{.DIRECTION, .SCRIPT, .GRAPHEME, .WORD, .LINE_SOFT, .LINE_HARD} -op_kind :: enum u8 { - END, +// Japanese text contains "kinsoku" characters, around which breaking a line is forbidden. +// Exactly which characters are "kinsoku" or not depends on the context: +// - Strict style has the largest amount of kinsoku characters, which leads to longer lines. +// - Loose style has the smallest amount of kinsoku characters, which leads to smaller lines. +// - Normal style is somewhere in the middle. +// Note that, while the Unicode standard mentions all three of these styles, it does not mention +// any differences between the normal and loose styles. +// As such, normal and loose styles currently behave the same. +japanese_line_break_style :: enum u8 { + // The Unicode standard does not define what strict style is used for. + // Supposedly, it is used for anything that does not fall into the other two categories of text. + STRICT, - // Substitution ops. - PRE_NORMALIZE_DOTTED_CIRCLES, - NORMALIZE, - NORMALIZE_HANGUL, - FLAG_JOINING_LETTERS, - GSUB_FEATURES, - GSUB_FEATURES_WITH_USER, + // Normal style is used for books and documents. + NORMAL, - // Positioning ops. - GPOS_METRICS, - GPOS_FEATURES, + // Loose style is used for newspapers, and (I assume) any other narrow column format. + LOOSE, +} - POST_GPOS_FIXUP, - STCH_POSTPASS, +break_state_flags :: distinct bit_set[break_state_flag; u32] +break_state_flag :: enum u32 { + STARTED = 0, + END = 1, + + _ = 2, + + // Bidirectional flags + SAW_R_AFTER_L = 3, + SAW_AL_AFTER_LR = 4, + LAST_WAS_BRACKET = 5, } +text_format :: enum u32 { + NONE, + + UTF32, + UTF8, +} + +direction :: enum u32 { + DONT_KNOW, + KBTS_DIRECTION_LTR, + KBTS_DIRECTION_RTL, +} + +orientation :: enum u32 { + HORIZONTAL, + VERTICAL, +} + +shaping_table :: enum u8 { + GSUB, + GPOS, +} + +shape_error :: enum u32 { + NONE, + INVALID_FONT, + GAVE_TEXT_BEFORE_CALLING_BEGIN, + OUT_OF_MEMORY, +} + +allocator_op_kind :: enum u32 { + NONE, + ALLOCATE, + FREE, +} + +blob_table_id :: enum u32 { + NONE, + HEAD, + CMAP, + GDEF, + GSUB, + GPOS, + HHEA, + VHEA, + HMTX, + VMTX, + MAXP, + OS2, + NAME, +} + +load_font_error :: enum u32 { + NONE, + NEED_TO_CREATE_BLOB, + INVALID_FONT, + OUT_OF_MEMORY, + COULD_NOT_OPEN_FILE, + READ_ERROR, +} + +version :: enum u32 { + _1_X, + _2_0, + + CURRENT = _2_0, +} + +blob_version :: enum u32 { + INVALID, + INITIAL, + + CURRENT = INITIAL, +} + +font_style_flags :: distinct bit_set[font_style_flag; u32] +font_style_flag :: enum u32 { + REGULAR = 0, + ITALIC = 1, + BOLD = 2, +} + +font_weight :: enum u32 { + UNKNOWN, + + THIN, + EXTRA_LIGHT, + LIGHT, + NORMAL, + MEDIUM, + SEMI_BOLD, + BOLD, + EXTRA_BOLD, + BLACK, +} + +font_width :: enum u32 { + UNKNOWN, + + ULTRA_CONDENSED, + EXTRA_CONDENSED, + CONDENSED, + SEMI_CONDENSED, + NORMAL, + SEMI_EXPANDED, + EXPANDED, + EXTRA_EXPANDED, + ULTRA_EXPANDED, +} + glyph_flags :: distinct bit_set[glyph_flag; u32] glyph_flag :: enum u32 { - // These feature flags must coincide with joining_feature _and_ FEATURE_FLAG! + // These feature flags must coincide with kbts_joining_feature _and_ KBTS_FEATURE_FLAG! ISOL = 0, FINA = 1, FIN2 = 2, @@ -840,66 +921,60 @@ glyph_flag :: enum u32 { CFAR = 19, // These can be anything. - DO_NOT_DECOMPOSE = 21, + DO_NOT_DECOMPOSE = 21, FIRST_IN_MULTIPLE_SUBSTITUTION = 22, - NO_BREAK = 23, - CURSIVE = 24, - GENERATED_BY_GSUB = 25, - USED_IN_GPOS = 26, + NO_BREAK = 23, + CURSIVE = 24, + GENERATED_BY_GSUB = 25, + USED_IN_GPOS = 26, - STCH_ENDPOINT = 27, - STCH_EXTENSION = 28, + STCH_ENDPOINT = 27, + STCH_EXTENSION = 28, - LIGATURE = 29, - MULTIPLE_SUBSTITUTION = 30, + LIGATURE = 29, + MULTIPLE_SUBSTITUTION = 30, } -GLYPH_FEATURE_MASK :: glyph_flags{.ISOL, .FINA, .FIN2, .FIN3, .MEDI, .MED2, .INIT, .LJMO, .VJMO, .TJMO, .RPHF, .BLWF, .HALF, .PSTF, .ABVF, .PREF, .NUMR, .FRAC, .DNOM, .CFAR} - -// In USE, glyphs are mostly not pre-flagged for feature application. -// However, we do want to flag rphf/pref results for reordering, so we want to -// keep all of the flags as usual, and only use these feature flags for filtering. - -USE_GLYPH_FEATURE_MASK :: glyph_flags{ - .ISOL, .FINA, .FIN2, .FIN3, .MEDI, .MED2, .INIT, - .NUMR, .DNOM, .FRAC, -} - -JOINING_FEATURE_MASK :: glyph_flags{.ISOL, .FINA, .FIN2, .FIN3, .MEDI, .MED2, .INIT} - - -// Japanese text contains "kinsoku" characters, around which breaking a line is forbidden. -// Exactly which characters are "kinsoku" or not depends on the context: -// - Strict style has the largest amount of kinsoku characters, which leads to longer lines. -// - Loose style has the smallest amount of kinsoku characters, which leads to smaller lines. -// - Normal style is somewhere in the middle. -// Note that, while the Unicode standard mentions all three of these styles, it does not mention -// any differences between the normal and loose styles. -// As such, normal and loose styles currently behave the same. -japanese_line_break_style :: enum u8 { - // The Unicode standard does not define what strict style is used for. - // Supposedly, it is used for anything that does not fall into the other two categories of text. - STRICT, - - // Normal style is used for books and documents. - NORMAL, - - // Loose style is used for newspapers, and (I assume) any other narrow column format. - LOOSE, -} - - -orientation :: enum u32 { - HORIZONTAL, - VERTICAL, -} - -direction :: enum u32 { +joining_feature :: enum u8 { NONE, - LTR, - RTL, + + // These must correspond with glyph_flags and FEATURE_IDs. + ISOL, + FINA, + FIN2, + FIN3, + MEDI, + MED2, + INIT, } +user_id_generation_mode :: enum u32 { + CODEPOINT_INDEX, + SOURCE_INDEX, +} + +break_config_flags :: distinct bit_set[break_config_flag; u32] +break_config_flag :: enum u32 { + END_OF_TEXT_GENERATES_HARD_LINE_BREAK = 0, +} + +font_info_string_id :: enum u32 { + NONE, + COPYRIGHT, + FAMILY, + SUBFAMILY, + UID, + FULL_NAME, + VERSION, + POSTSCRIPT_NAME, + TRADEMARK, + MANUFACTURER, + DESIGNER, + TYPOGRAPHIC_FAMILY, + TYPOGRAPHIC_SUBFAMILY, +} + + unicode_joining_type :: enum u8 { NONE, LEFT, @@ -920,8 +995,18 @@ unicode_flag :: enum u8 { NON_SPACING_MARK = 6, } +UNICODE_FLAG_MODIFIER_COMBINING_MARK :: unicode_flags{.MODIFIER_COMBINING_MARK} +UNICODE_FLAG_DEFAULT_IGNORABLE :: unicode_flags{.DEFAULT_IGNORABLE} +UNICODE_FLAG_OPEN_BRACKET :: unicode_flags{.OPEN_BRACKET} +UNICODE_FLAG_CLOSE_BRACKET :: unicode_flags{.CLOSE_BRACKET} +UNICODE_FLAG_PART_OF_WORD :: unicode_flags{.PART_OF_WORD} +UNICODE_FLAG_DECIMAL_DIGIT :: unicode_flags{.DECIMAL_DIGIT} +UNICODE_FLAG_NON_SPACING_MARK :: unicode_flags{.NON_SPACING_MARK} +UNICODE_FLAG_MIRRORED :: unicode_flags{.OPEN_BRACKET, .CLOSE_BRACKET} + unicode_bidirectional_class :: enum u8 { NI, + BN, // Formatting characters need to be ignored. L, R, NSM, @@ -1068,177 +1153,180 @@ shaper :: enum u32 { USE, } +MAXIMUM_RECOMPOSITION_PARENTS :: 19 +MAXIMUM_CODEPOINT_SCRIPTS :: 23 + script_tag :: enum u32 { - DONT_KNOW = (' ' | ' '<<8 | ' '<<16 | ' '<<24), - ADLAM = ('a' | 'd'<<8 | 'l'<<16 | 'm'<<24), - AHOM = ('a' | 'h'<<8 | 'o'<<16 | 'm'<<24), - ANATOLIAN_HIEROGLYPHS = ('h' | 'l'<<8 | 'u'<<16 | 'w'<<24), - ARABIC = ('a' | 'r'<<8 | 'a'<<16 | 'b'<<24), - ARMENIAN = ('a' | 'r'<<8 | 'm'<<16 | 'n'<<24), - AVESTAN = ('a' | 'v'<<8 | 's'<<16 | 't'<<24), - BALINESE = ('b' | 'a'<<8 | 'l'<<16 | 'i'<<24), - BAMUM = ('b' | 'a'<<8 | 'm'<<16 | 'u'<<24), - BASSA_VAH = ('b' | 'a'<<8 | 's'<<16 | 's'<<24), - BATAK = ('b' | 'a'<<8 | 't'<<16 | 'k'<<24), - BENGALI = ('b' | 'n'<<8 | 'g'<<16 | '2'<<24), - BHAIKSUKI = ('b' | 'h'<<8 | 'k'<<16 | 's'<<24), - BOPOMOFO = ('b' | 'o'<<8 | 'p'<<16 | 'o'<<24), - BRAHMI = ('b' | 'r'<<8 | 'a'<<16 | 'h'<<24), - BUGINESE = ('b' | 'u'<<8 | 'g'<<16 | 'i'<<24), - BUHID = ('b' | 'u'<<8 | 'h'<<16 | 'd'<<24), - CANADIAN_SYLLABICS = ('c' | 'a'<<8 | 'n'<<16 | 's'<<24), - CARIAN = ('c' | 'a'<<8 | 'r'<<16 | 'i'<<24), - CAUCASIAN_ALBANIAN = ('a' | 'g'<<8 | 'h'<<16 | 'b'<<24), - CHAKMA = ('c' | 'a'<<8 | 'k'<<16 | 'm'<<24), - CHAM = ('c' | 'h'<<8 | 'a'<<16 | 'm'<<24), - CHEROKEE = ('c' | 'h'<<8 | 'e'<<16 | 'r'<<24), - CHORASMIAN = ('c' | 'h'<<8 | 'r'<<16 | 's'<<24), - CJK_IDEOGRAPHIC = ('h' | 'a'<<8 | 'n'<<16 | 'i'<<24), - COPTIC = ('c' | 'o'<<8 | 'p'<<16 | 't'<<24), - CYPRIOT_SYLLABARY = ('c' | 'p'<<8 | 'r'<<16 | 't'<<24), - CYPRO_MINOAN = ('c' | 'p'<<8 | 'm'<<16 | 'n'<<24), - CYRILLIC = ('c' | 'y'<<8 | 'r'<<16 | 'l'<<24), - DEFAULT = ('D' | 'F'<<8 | 'L'<<16 | 'T'<<24), - DEFAULT2 = ('D' | 'F'<<8 | 'L'<<16 | 'T'<<24), - DESERET = ('d' | 's'<<8 | 'r'<<16 | 't'<<24), - DEVANAGARI = ('d' | 'e'<<8 | 'v'<<16 | '2'<<24), - DIVES_AKURU = ('d' | 'i'<<8 | 'a'<<16 | 'k'<<24), - DOGRA = ('d' | 'o'<<8 | 'g'<<16 | 'r'<<24), - DUPLOYAN = ('d' | 'u'<<8 | 'p'<<16 | 'l'<<24), - EGYPTIAN_HIEROGLYPHS = ('e' | 'g'<<8 | 'y'<<16 | 'p'<<24), - ELBASAN = ('e' | 'l'<<8 | 'b'<<16 | 'a'<<24), - ELYMAIC = ('e' | 'l'<<8 | 'y'<<16 | 'm'<<24), - ETHIOPIC = ('e' | 't'<<8 | 'h'<<16 | 'i'<<24), - GARAY = ('g' | 'a'<<8 | 'r'<<16 | 'a'<<24), - GEORGIAN = ('g' | 'e'<<8 | 'o'<<16 | 'r'<<24), - GLAGOLITIC = ('g' | 'l'<<8 | 'a'<<16 | 'g'<<24), - GOTHIC = ('g' | 'o'<<8 | 't'<<16 | 'h'<<24), - GRANTHA = ('g' | 'r'<<8 | 'a'<<16 | 'n'<<24), - GREEK = ('g' | 'r'<<8 | 'e'<<16 | 'k'<<24), - GUJARATI = ('g' | 'j'<<8 | 'r'<<16 | '2'<<24), - GUNJALA_GONDI = ('g' | 'o'<<8 | 'n'<<16 | 'g'<<24), - GURMUKHI = ('g' | 'u'<<8 | 'r'<<16 | '2'<<24), - GURUNG_KHEMA = ('g' | 'u'<<8 | 'k'<<16 | 'h'<<24), - HANGUL = ('h' | 'a'<<8 | 'n'<<16 | 'g'<<24), - HANIFI_ROHINGYA = ('r' | 'o'<<8 | 'h'<<16 | 'g'<<24), - HANUNOO = ('h' | 'a'<<8 | 'n'<<16 | 'o'<<24), - HATRAN = ('h' | 'a'<<8 | 't'<<16 | 'r'<<24), - HEBREW = ('h' | 'e'<<8 | 'b'<<16 | 'r'<<24), - HIRAGANA = ('k' | 'a'<<8 | 'n'<<16 | 'a'<<24), - IMPERIAL_ARAMAIC = ('a' | 'r'<<8 | 'm'<<16 | 'i'<<24), - INSCRIPTIONAL_PAHLAVI = ('p' | 'h'<<8 | 'l'<<16 | 'i'<<24), - INSCRIPTIONAL_PARTHIAN = ('p' | 'r'<<8 | 't'<<16 | 'i'<<24), - JAVANESE = ('j' | 'a'<<8 | 'v'<<16 | 'a'<<24), - KAITHI = ('k' | 't'<<8 | 'h'<<16 | 'i'<<24), - KANNADA = ('k' | 'n'<<8 | 'd'<<16 | '2'<<24), - KATAKANA = ('k' | 'a'<<8 | 'n'<<16 | 'a'<<24), - KAWI = ('k' | 'a'<<8 | 'w'<<16 | 'i'<<24), - KAYAH_LI = ('k' | 'a'<<8 | 'l'<<16 | 'i'<<24), - KHAROSHTHI = ('k' | 'h'<<8 | 'a'<<16 | 'r'<<24), - KHITAN_SMALL_SCRIPT = ('k' | 'i'<<8 | 't'<<16 | 's'<<24), - KHMER = ('k' | 'h'<<8 | 'm'<<16 | 'r'<<24), - KHOJKI = ('k' | 'h'<<8 | 'o'<<16 | 'j'<<24), - KHUDAWADI = ('s' | 'i'<<8 | 'n'<<16 | 'd'<<24), - KIRAT_RAI = ('k' | 'r'<<8 | 'a'<<16 | 'i'<<24), - LAO = ('l' | 'a'<<8 | 'o'<<16 | ' '<<24), - LATIN = ('l' | 'a'<<8 | 't'<<16 | 'n'<<24), - LEPCHA = ('l' | 'e'<<8 | 'p'<<16 | 'c'<<24), - LIMBU = ('l' | 'i'<<8 | 'm'<<16 | 'b'<<24), - LINEAR_A = ('l' | 'i'<<8 | 'n'<<16 | 'a'<<24), - LINEAR_B = ('l' | 'i'<<8 | 'n'<<16 | 'b'<<24), - LISU = ('l' | 'i'<<8 | 's'<<16 | 'u'<<24), - LYCIAN = ('l' | 'y'<<8 | 'c'<<16 | 'i'<<24), - LYDIAN = ('l' | 'y'<<8 | 'd'<<16 | 'i'<<24), - MAHAJANI = ('m' | 'a'<<8 | 'h'<<16 | 'j'<<24), - MAKASAR = ('m' | 'a'<<8 | 'k'<<16 | 'a'<<24), - MALAYALAM = ('m' | 'l'<<8 | 'm'<<16 | '2'<<24), - MANDAIC = ('m' | 'a'<<8 | 'n'<<16 | 'd'<<24), - MANICHAEAN = ('m' | 'a'<<8 | 'n'<<16 | 'i'<<24), - MARCHEN = ('m' | 'a'<<8 | 'r'<<16 | 'c'<<24), - MASARAM_GONDI = ('g' | 'o'<<8 | 'n'<<16 | 'm'<<24), - MEDEFAIDRIN = ('m' | 'e'<<8 | 'd'<<16 | 'f'<<24), - MEETEI_MAYEK = ('m' | 't'<<8 | 'e'<<16 | 'i'<<24), - MENDE_KIKAKUI = ('m' | 'e'<<8 | 'n'<<16 | 'd'<<24), - MEROITIC_CURSIVE = ('m' | 'e'<<8 | 'r'<<16 | 'c'<<24), - MEROITIC_HIEROGLYPHS = ('m' | 'e'<<8 | 'r'<<16 | 'o'<<24), - MIAO = ('p' | 'l'<<8 | 'r'<<16 | 'd'<<24), - MODI = ('m' | 'o'<<8 | 'd'<<16 | 'i'<<24), - MONGOLIAN = ('m' | 'o'<<8 | 'n'<<16 | 'g'<<24), - MRO = ('m' | 'r'<<8 | 'o'<<16 | 'o'<<24), - MULTANI = ('m' | 'u'<<8 | 'l'<<16 | 't'<<24), - MYANMAR = ('m' | 'y'<<8 | 'm'<<16 | '2'<<24), - NABATAEAN = ('n' | 'b'<<8 | 'a'<<16 | 't'<<24), - NAG_MUNDARI = ('n' | 'a'<<8 | 'g'<<16 | 'm'<<24), - NANDINAGARI = ('n' | 'a'<<8 | 'n'<<16 | 'd'<<24), - NEWA = ('n' | 'e'<<8 | 'w'<<16 | 'a'<<24), - NEW_TAI_LUE = ('t' | 'a'<<8 | 'l'<<16 | 'u'<<24), - NKO = ('n' | 'k'<<8 | 'o'<<16 | ' '<<24), - NUSHU = ('n' | 's'<<8 | 'h'<<16 | 'u'<<24), - NYIAKENG_PUACHUE_HMONG = ('h' | 'm'<<8 | 'n'<<16 | 'p'<<24), - OGHAM = ('o' | 'g'<<8 | 'a'<<16 | 'm'<<24), - OL_CHIKI = ('o' | 'l'<<8 | 'c'<<16 | 'k'<<24), - OL_ONAL = ('o' | 'n'<<8 | 'a'<<16 | 'o'<<24), - OLD_ITALIC = ('i' | 't'<<8 | 'a'<<16 | 'l'<<24), - OLD_HUNGARIAN = ('h' | 'u'<<8 | 'n'<<16 | 'g'<<24), - OLD_NORTH_ARABIAN = ('n' | 'a'<<8 | 'r'<<16 | 'b'<<24), - OLD_PERMIC = ('p' | 'e'<<8 | 'r'<<16 | 'm'<<24), - OLD_PERSIAN_CUNEIFORM = ('x' | 'p'<<8 | 'e'<<16 | 'o'<<24), - OLD_SOGDIAN = ('s' | 'o'<<8 | 'g'<<16 | 'o'<<24), - OLD_SOUTH_ARABIAN = ('s' | 'a'<<8 | 'r'<<16 | 'b'<<24), - OLD_TURKIC = ('o' | 'r'<<8 | 'k'<<16 | 'h'<<24), - OLD_UYGHUR = ('o' | 'u'<<8 | 'g'<<16 | 'r'<<24), - ODIA = ('o' | 'r'<<8 | 'y'<<16 | '2'<<24), - OSAGE = ('o' | 's'<<8 | 'g'<<16 | 'e'<<24), - OSMANYA = ('o' | 's'<<8 | 'm'<<16 | 'a'<<24), - PAHAWH_HMONG = ('h' | 'm'<<8 | 'n'<<16 | 'g'<<24), - PALMYRENE = ('p' | 'a'<<8 | 'l'<<16 | 'm'<<24), - PAU_CIN_HAU = ('p' | 'a'<<8 | 'u'<<16 | 'c'<<24), - PHAGS_PA = ('p' | 'h'<<8 | 'a'<<16 | 'g'<<24), - PHOENICIAN = ('p' | 'h'<<8 | 'n'<<16 | 'x'<<24), - PSALTER_PAHLAVI = ('p' | 'h'<<8 | 'l'<<16 | 'p'<<24), - REJANG = ('r' | 'j'<<8 | 'n'<<16 | 'g'<<24), - RUNIC = ('r' | 'u'<<8 | 'n'<<16 | 'r'<<24), - SAMARITAN = ('s' | 'a'<<8 | 'm'<<16 | 'r'<<24), - SAURASHTRA = ('s' | 'a'<<8 | 'u'<<16 | 'r'<<24), - SHARADA = ('s' | 'h'<<8 | 'r'<<16 | 'd'<<24), - SHAVIAN = ('s' | 'h'<<8 | 'a'<<16 | 'w'<<24), - SIDDHAM = ('s' | 'i'<<8 | 'd'<<16 | 'd'<<24), - SIGN_WRITING = ('s' | 'g'<<8 | 'n'<<16 | 'w'<<24), - SOGDIAN = ('s' | 'o'<<8 | 'g'<<16 | 'd'<<24), - SINHALA = ('s' | 'i'<<8 | 'n'<<16 | 'h'<<24), - SORA_SOMPENG = ('s' | 'o'<<8 | 'r'<<16 | 'a'<<24), - SOYOMBO = ('s' | 'o'<<8 | 'y'<<16 | 'o'<<24), - SUMERO_AKKADIAN_CUNEIFORM = ('x' | 's'<<8 | 'u'<<16 | 'x'<<24), - SUNDANESE = ('s' | 'u'<<8 | 'n'<<16 | 'd'<<24), - SUNUWAR = ('s' | 'u'<<8 | 'n'<<16 | 'u'<<24), - SYLOTI_NAGRI = ('s' | 'y'<<8 | 'l'<<16 | 'o'<<24), - SYRIAC = ('s' | 'y'<<8 | 'r'<<16 | 'c'<<24), - TAGALOG = ('t' | 'g'<<8 | 'l'<<16 | 'g'<<24), - TAGBANWA = ('t' | 'a'<<8 | 'g'<<16 | 'b'<<24), - TAI_LE = ('t' | 'a'<<8 | 'l'<<16 | 'e'<<24), - TAI_THAM = ('l' | 'a'<<8 | 'n'<<16 | 'a'<<24), - TAI_VIET = ('t' | 'a'<<8 | 'v'<<16 | 't'<<24), - TAKRI = ('t' | 'a'<<8 | 'k'<<16 | 'r'<<24), - TAMIL = ('t' | 'm'<<8 | 'l'<<16 | '2'<<24), - TANGSA = ('t' | 'n'<<8 | 's'<<16 | 'a'<<24), - TANGUT = ('t' | 'a'<<8 | 'n'<<16 | 'g'<<24), - TELUGU = ('t' | 'e'<<8 | 'l'<<16 | '2'<<24), - THAANA = ('t' | 'h'<<8 | 'a'<<16 | 'a'<<24), - THAI = ('t' | 'h'<<8 | 'a'<<16 | 'i'<<24), - TIBETAN = ('t' | 'i'<<8 | 'b'<<16 | 't'<<24), - TIFINAGH = ('t' | 'f'<<8 | 'n'<<16 | 'g'<<24), - TIRHUTA = ('t' | 'i'<<8 | 'r'<<16 | 'h'<<24), - TODHRI = ('t' | 'o'<<8 | 'd'<<16 | 'r'<<24), - TOTO = ('t' | 'o'<<8 | 't'<<16 | 'o'<<24), - TULU_TIGALARI = ('t' | 'u'<<8 | 't'<<16 | 'g'<<24), - UGARITIC_CUNEIFORM = ('u' | 'g'<<8 | 'a'<<16 | 'r'<<24), - VAI = ('v' | 'a'<<8 | 'i'<<16 | ' '<<24), - VITHKUQI = ('v' | 'i'<<8 | 't'<<16 | 'h'<<24), - WANCHO = ('w' | 'c'<<8 | 'h'<<16 | 'o'<<24), - WARANG_CITI = ('w' | 'a'<<8 | 'r'<<16 | 'a'<<24), - YEZIDI = ('y' | 'e'<<8 | 'z'<<16 | 'i'<<24), - YI = ('y' | 'i'<<8 | ' '<<16 | ' '<<24), - ZANABAZAR_SQUARE = ('z' | 'a'<<8 | 'n'<<16 | 'b'<<24), + DONT_KNOW = ' ' | ' '<<8 | ' '<<16 | ' '<<24, + ADLAM = 'a' | 'd'<<8 | 'l'<<16 | 'm'<<24, + AHOM = 'a' | 'h'<<8 | 'o'<<16 | 'm'<<24, + ANATOLIAN_HIEROGLYPHS = 'h' | 'l'<<8 | 'u'<<16 | 'w'<<24, + ARABIC = 'a' | 'r'<<8 | 'a'<<16 | 'b'<<24, + ARMENIAN = 'a' | 'r'<<8 | 'm'<<16 | 'n'<<24, + AVESTAN = 'a' | 'v'<<8 | 's'<<16 | 't'<<24, + BALINESE = 'b' | 'a'<<8 | 'l'<<16 | 'i'<<24, + BAMUM = 'b' | 'a'<<8 | 'm'<<16 | 'u'<<24, + BASSA_VAH = 'b' | 'a'<<8 | 's'<<16 | 's'<<24, + BATAK = 'b' | 'a'<<8 | 't'<<16 | 'k'<<24, + BENGALI = 'b' | 'n'<<8 | 'g'<<16 | '2'<<24, + BHAIKSUKI = 'b' | 'h'<<8 | 'k'<<16 | 's'<<24, + BOPOMOFO = 'b' | 'o'<<8 | 'p'<<16 | 'o'<<24, + BRAHMI = 'b' | 'r'<<8 | 'a'<<16 | 'h'<<24, + BUGINESE = 'b' | 'u'<<8 | 'g'<<16 | 'i'<<24, + BUHID = 'b' | 'u'<<8 | 'h'<<16 | 'd'<<24, + CANADIAN_SYLLABICS = 'c' | 'a'<<8 | 'n'<<16 | 's'<<24, + CARIAN = 'c' | 'a'<<8 | 'r'<<16 | 'i'<<24, + CAUCASIAN_ALBANIAN = 'a' | 'g'<<8 | 'h'<<16 | 'b'<<24, + CHAKMA = 'c' | 'a'<<8 | 'k'<<16 | 'm'<<24, + CHAM = 'c' | 'h'<<8 | 'a'<<16 | 'm'<<24, + CHEROKEE = 'c' | 'h'<<8 | 'e'<<16 | 'r'<<24, + CHORASMIAN = 'c' | 'h'<<8 | 'r'<<16 | 's'<<24, + CJK_IDEOGRAPHIC = 'h' | 'a'<<8 | 'n'<<16 | 'i'<<24, + COPTIC = 'c' | 'o'<<8 | 'p'<<16 | 't'<<24, + CYPRIOT_SYLLABARY = 'c' | 'p'<<8 | 'r'<<16 | 't'<<24, + CYPRO_MINOAN = 'c' | 'p'<<8 | 'm'<<16 | 'n'<<24, + CYRILLIC = 'c' | 'y'<<8 | 'r'<<16 | 'l'<<24, + DEFAULT = 'D' | 'F'<<8 | 'L'<<16 | 'T'<<24, + DEFAULT2 = 'D' | 'F'<<8 | 'L'<<16 | 'T'<<24, + DESERET = 'd' | 's'<<8 | 'r'<<16 | 't'<<24, + DEVANAGARI = 'd' | 'e'<<8 | 'v'<<16 | '2'<<24, + DIVES_AKURU = 'd' | 'i'<<8 | 'a'<<16 | 'k'<<24, + DOGRA = 'd' | 'o'<<8 | 'g'<<16 | 'r'<<24, + DUPLOYAN = 'd' | 'u'<<8 | 'p'<<16 | 'l'<<24, + EGYPTIAN_HIEROGLYPHS = 'e' | 'g'<<8 | 'y'<<16 | 'p'<<24, + ELBASAN = 'e' | 'l'<<8 | 'b'<<16 | 'a'<<24, + ELYMAIC = 'e' | 'l'<<8 | 'y'<<16 | 'm'<<24, + ETHIOPIC = 'e' | 't'<<8 | 'h'<<16 | 'i'<<24, + GARAY = 'g' | 'a'<<8 | 'r'<<16 | 'a'<<24, + GEORGIAN = 'g' | 'e'<<8 | 'o'<<16 | 'r'<<24, + GLAGOLITIC = 'g' | 'l'<<8 | 'a'<<16 | 'g'<<24, + GOTHIC = 'g' | 'o'<<8 | 't'<<16 | 'h'<<24, + GRANTHA = 'g' | 'r'<<8 | 'a'<<16 | 'n'<<24, + GREEK = 'g' | 'r'<<8 | 'e'<<16 | 'k'<<24, + GUJARATI = 'g' | 'j'<<8 | 'r'<<16 | '2'<<24, + GUNJALA_GONDI = 'g' | 'o'<<8 | 'n'<<16 | 'g'<<24, + GURMUKHI = 'g' | 'u'<<8 | 'r'<<16 | '2'<<24, + GURUNG_KHEMA = 'g' | 'u'<<8 | 'k'<<16 | 'h'<<24, + HANGUL = 'h' | 'a'<<8 | 'n'<<16 | 'g'<<24, + HANIFI_ROHINGYA = 'r' | 'o'<<8 | 'h'<<16 | 'g'<<24, + HANUNOO = 'h' | 'a'<<8 | 'n'<<16 | 'o'<<24, + HATRAN = 'h' | 'a'<<8 | 't'<<16 | 'r'<<24, + HEBREW = 'h' | 'e'<<8 | 'b'<<16 | 'r'<<24, + HIRAGANA = 'k' | 'a'<<8 | 'n'<<16 | 'a'<<24, + IMPERIAL_ARAMAIC = 'a' | 'r'<<8 | 'm'<<16 | 'i'<<24, + INSCRIPTIONAL_PAHLAVI = 'p' | 'h'<<8 | 'l'<<16 | 'i'<<24, + INSCRIPTIONAL_PARTHIAN = 'p' | 'r'<<8 | 't'<<16 | 'i'<<24, + JAVANESE = 'j' | 'a'<<8 | 'v'<<16 | 'a'<<24, + KAITHI = 'k' | 't'<<8 | 'h'<<16 | 'i'<<24, + KANNADA = 'k' | 'n'<<8 | 'd'<<16 | '2'<<24, + KATAKANA = 'k' | 'a'<<8 | 'n'<<16 | 'a'<<24, + KAWI = 'k' | 'a'<<8 | 'w'<<16 | 'i'<<24, + KAYAH_LI = 'k' | 'a'<<8 | 'l'<<16 | 'i'<<24, + KHAROSHTHI = 'k' | 'h'<<8 | 'a'<<16 | 'r'<<24, + KHITAN_SMALL_SCRIPT = 'k' | 'i'<<8 | 't'<<16 | 's'<<24, + KHMER = 'k' | 'h'<<8 | 'm'<<16 | 'r'<<24, + KHOJKI = 'k' | 'h'<<8 | 'o'<<16 | 'j'<<24, + KHUDAWADI = 's' | 'i'<<8 | 'n'<<16 | 'd'<<24, + KIRAT_RAI = 'k' | 'r'<<8 | 'a'<<16 | 'i'<<24, + LAO = 'l' | 'a'<<8 | 'o'<<16 | ' '<<24, + LATIN = 'l' | 'a'<<8 | 't'<<16 | 'n'<<24, + LEPCHA = 'l' | 'e'<<8 | 'p'<<16 | 'c'<<24, + LIMBU = 'l' | 'i'<<8 | 'm'<<16 | 'b'<<24, + LINEAR_A = 'l' | 'i'<<8 | 'n'<<16 | 'a'<<24, + LINEAR_B = 'l' | 'i'<<8 | 'n'<<16 | 'b'<<24, + LISU = 'l' | 'i'<<8 | 's'<<16 | 'u'<<24, + LYCIAN = 'l' | 'y'<<8 | 'c'<<16 | 'i'<<24, + LYDIAN = 'l' | 'y'<<8 | 'd'<<16 | 'i'<<24, + MAHAJANI = 'm' | 'a'<<8 | 'h'<<16 | 'j'<<24, + MAKASAR = 'm' | 'a'<<8 | 'k'<<16 | 'a'<<24, + MALAYALAM = 'm' | 'l'<<8 | 'm'<<16 | '2'<<24, + MANDAIC = 'm' | 'a'<<8 | 'n'<<16 | 'd'<<24, + MANICHAEAN = 'm' | 'a'<<8 | 'n'<<16 | 'i'<<24, + MARCHEN = 'm' | 'a'<<8 | 'r'<<16 | 'c'<<24, + MASARAM_GONDI = 'g' | 'o'<<8 | 'n'<<16 | 'm'<<24, + MEDEFAIDRIN = 'm' | 'e'<<8 | 'd'<<16 | 'f'<<24, + MEETEI_MAYEK = 'm' | 't'<<8 | 'e'<<16 | 'i'<<24, + MENDE_KIKAKUI = 'm' | 'e'<<8 | 'n'<<16 | 'd'<<24, + MEROITIC_CURSIVE = 'm' | 'e'<<8 | 'r'<<16 | 'c'<<24, + MEROITIC_HIEROGLYPHS = 'm' | 'e'<<8 | 'r'<<16 | 'o'<<24, + MIAO = 'p' | 'l'<<8 | 'r'<<16 | 'd'<<24, + MODI = 'm' | 'o'<<8 | 'd'<<16 | 'i'<<24, + MONGOLIAN = 'm' | 'o'<<8 | 'n'<<16 | 'g'<<24, + MRO = 'm' | 'r'<<8 | 'o'<<16 | 'o'<<24, + MULTANI = 'm' | 'u'<<8 | 'l'<<16 | 't'<<24, + MYANMAR = 'm' | 'y'<<8 | 'm'<<16 | '2'<<24, + NABATAEAN = 'n' | 'b'<<8 | 'a'<<16 | 't'<<24, + NAG_MUNDARI = 'n' | 'a'<<8 | 'g'<<16 | 'm'<<24, + NANDINAGARI = 'n' | 'a'<<8 | 'n'<<16 | 'd'<<24, + NEWA = 'n' | 'e'<<8 | 'w'<<16 | 'a'<<24, + NEW_TAI_LUE = 't' | 'a'<<8 | 'l'<<16 | 'u'<<24, + NKO = 'n' | 'k'<<8 | 'o'<<16 | ' '<<24, + NUSHU = 'n' | 's'<<8 | 'h'<<16 | 'u'<<24, + NYIAKENG_PUACHUE_HMONG = 'h' | 'm'<<8 | 'n'<<16 | 'p'<<24, + OGHAM = 'o' | 'g'<<8 | 'a'<<16 | 'm'<<24, + OL_CHIKI = 'o' | 'l'<<8 | 'c'<<16 | 'k'<<24, + OL_ONAL = 'o' | 'n'<<8 | 'a'<<16 | 'o'<<24, + OLD_ITALIC = 'i' | 't'<<8 | 'a'<<16 | 'l'<<24, + OLD_HUNGARIAN = 'h' | 'u'<<8 | 'n'<<16 | 'g'<<24, + OLD_NORTH_ARABIAN = 'n' | 'a'<<8 | 'r'<<16 | 'b'<<24, + OLD_PERMIC = 'p' | 'e'<<8 | 'r'<<16 | 'm'<<24, + OLD_PERSIAN_CUNEIFORM = 'x' | 'p'<<8 | 'e'<<16 | 'o'<<24, + OLD_SOGDIAN = 's' | 'o'<<8 | 'g'<<16 | 'o'<<24, + OLD_SOUTH_ARABIAN = 's' | 'a'<<8 | 'r'<<16 | 'b'<<24, + OLD_TURKIC = 'o' | 'r'<<8 | 'k'<<16 | 'h'<<24, + OLD_UYGHUR = 'o' | 'u'<<8 | 'g'<<16 | 'r'<<24, + ODIA = 'o' | 'r'<<8 | 'y'<<16 | '2'<<24, + OSAGE = 'o' | 's'<<8 | 'g'<<16 | 'e'<<24, + OSMANYA = 'o' | 's'<<8 | 'm'<<16 | 'a'<<24, + PAHAWH_HMONG = 'h' | 'm'<<8 | 'n'<<16 | 'g'<<24, + PALMYRENE = 'p' | 'a'<<8 | 'l'<<16 | 'm'<<24, + PAU_CIN_HAU = 'p' | 'a'<<8 | 'u'<<16 | 'c'<<24, + PHAGS_PA = 'p' | 'h'<<8 | 'a'<<16 | 'g'<<24, + PHOENICIAN = 'p' | 'h'<<8 | 'n'<<16 | 'x'<<24, + PSALTER_PAHLAVI = 'p' | 'h'<<8 | 'l'<<16 | 'p'<<24, + REJANG = 'r' | 'j'<<8 | 'n'<<16 | 'g'<<24, + RUNIC = 'r' | 'u'<<8 | 'n'<<16 | 'r'<<24, + SAMARITAN = 's' | 'a'<<8 | 'm'<<16 | 'r'<<24, + SAURASHTRA = 's' | 'a'<<8 | 'u'<<16 | 'r'<<24, + SHARADA = 's' | 'h'<<8 | 'r'<<16 | 'd'<<24, + SHAVIAN = 's' | 'h'<<8 | 'a'<<16 | 'w'<<24, + SIDDHAM = 's' | 'i'<<8 | 'd'<<16 | 'd'<<24, + SIGN_WRITING = 's' | 'g'<<8 | 'n'<<16 | 'w'<<24, + SOGDIAN = 's' | 'o'<<8 | 'g'<<16 | 'd'<<24, + SINHALA = 's' | 'i'<<8 | 'n'<<16 | 'h'<<24, + SORA_SOMPENG = 's' | 'o'<<8 | 'r'<<16 | 'a'<<24, + SOYOMBO = 's' | 'o'<<8 | 'y'<<16 | 'o'<<24, + SUMERO_AKKADIAN_CUNEIFORM = 'x' | 's'<<8 | 'u'<<16 | 'x'<<24, + SUNDANESE = 's' | 'u'<<8 | 'n'<<16 | 'd'<<24, + SUNUWAR = 's' | 'u'<<8 | 'n'<<16 | 'u'<<24, + SYLOTI_NAGRI = 's' | 'y'<<8 | 'l'<<16 | 'o'<<24, + SYRIAC = 's' | 'y'<<8 | 'r'<<16 | 'c'<<24, + TAGALOG = 't' | 'g'<<8 | 'l'<<16 | 'g'<<24, + TAGBANWA = 't' | 'a'<<8 | 'g'<<16 | 'b'<<24, + TAI_LE = 't' | 'a'<<8 | 'l'<<16 | 'e'<<24, + TAI_THAM = 'l' | 'a'<<8 | 'n'<<16 | 'a'<<24, + TAI_VIET = 't' | 'a'<<8 | 'v'<<16 | 't'<<24, + TAKRI = 't' | 'a'<<8 | 'k'<<16 | 'r'<<24, + TAMIL = 't' | 'm'<<8 | 'l'<<16 | '2'<<24, + TANGSA = 't' | 'n'<<8 | 's'<<16 | 'a'<<24, + TANGUT = 't' | 'a'<<8 | 'n'<<16 | 'g'<<24, + TELUGU = 't' | 'e'<<8 | 'l'<<16 | '2'<<24, + THAANA = 't' | 'h'<<8 | 'a'<<16 | 'a'<<24, + THAI = 't' | 'h'<<8 | 'a'<<16 | 'i'<<24, + TIBETAN = 't' | 'i'<<8 | 'b'<<16 | 't'<<24, + TIFINAGH = 't' | 'f'<<8 | 'n'<<16 | 'g'<<24, + TIRHUTA = 't' | 'i'<<8 | 'r'<<16 | 'h'<<24, + TODHRI = 't' | 'o'<<8 | 'd'<<16 | 'r'<<24, + TOTO = 't' | 'o'<<8 | 't'<<16 | 'o'<<24, + TULU_TIGALARI = 't' | 'u'<<8 | 't'<<16 | 'g'<<24, + UGARITIC_CUNEIFORM = 'u' | 'g'<<8 | 'a'<<16 | 'r'<<24, + VAI = 'v' | 'a'<<8 | 'i'<<16 | ' '<<24, + VITHKUQI = 'v' | 'i'<<8 | 't'<<16 | 'h'<<24, + WANCHO = 'w' | 'c'<<8 | 'h'<<16 | 'o'<<24, + WARANG_CITI = 'w' | 'a'<<8 | 'r'<<16 | 'a'<<24, + YEZIDI = 'y' | 'e'<<8 | 'z'<<16 | 'i'<<24, + YI = 'y' | 'i'<<8 | ' '<<16 | ' '<<24, + ZANABAZAR_SQUARE = 'z' | 'a'<<8 | 'n'<<16 | 'b'<<24, } script :: enum u32 { @@ -1415,586 +1503,371 @@ script :: enum u32 { } feature_tag :: enum u32 { - UNREGISTERED = 0, - isol = ('i' | 's'<<8 | 'o'<<16 | 'l'<<24), /* Isolated Forms */ - fina = ('f' | 'i'<<8 | 'n'<<16 | 'a'<<24), /* Terminal Forms */ - fin2 = ('f' | 'i'<<8 | 'n'<<16 | '2'<<24), /* Terminal Forms #2 */ - fin3 = ('f' | 'i'<<8 | 'n'<<16 | '3'<<24), /* Terminal Forms #3 */ - medi = ('m' | 'e'<<8 | 'd'<<16 | 'i'<<24), /* Medial Forms */ - med2 = ('m' | 'e'<<8 | 'd'<<16 | '2'<<24), /* Medial Forms #2 */ - init = ('i' | 'n'<<8 | 'i'<<16 | 't'<<24), /* Initial Forms */ - ljmo = ('l' | 'j'<<8 | 'm'<<16 | 'o'<<24), /* Leading Jamo Forms */ - vjmo = ('v' | 'j'<<8 | 'm'<<16 | 'o'<<24), /* Vowel Jamo Forms */ - tjmo = ('t' | 'j'<<8 | 'm'<<16 | 'o'<<24), /* Trailing Jamo Forms */ - rphf = ('r' | 'p'<<8 | 'h'<<16 | 'f'<<24), /* Reph Form */ - blwf = ('b' | 'l'<<8 | 'w'<<16 | 'f'<<24), /* Below-base Forms */ - half = ('h' | 'a'<<8 | 'l'<<16 | 'f'<<24), /* Half Forms */ - pstf = ('p' | 's'<<8 | 't'<<16 | 'f'<<24), /* Post-base Forms */ - abvf = ('a' | 'b'<<8 | 'v'<<16 | 'f'<<24), /* Above-base Forms */ - pref = ('p' | 'r'<<8 | 'e'<<16 | 'f'<<24), /* Pre-base Forms */ - numr = ('n' | 'u'<<8 | 'm'<<16 | 'r'<<24), /* Numerators */ - frac = ('f' | 'r'<<8 | 'a'<<16 | 'c'<<24), /* Fractions */ - dnom = ('d' | 'n'<<8 | 'o'<<16 | 'm'<<24), /* Denominators */ - cfar = ('c' | 'f'<<8 | 'a'<<16 | 'r'<<24), /* Conjunct Form After Ro */ - aalt = ('a' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Access All Alternates */ - abvm = ('a' | 'b'<<8 | 'v'<<16 | 'm'<<24), /* Above-base Mark Positioning */ - abvs = ('a' | 'b'<<8 | 'v'<<16 | 's'<<24), /* Above-base Substitutions */ - afrc = ('a' | 'f'<<8 | 'r'<<16 | 'c'<<24), /* Alternative Fractions */ - akhn = ('a' | 'k'<<8 | 'h'<<16 | 'n'<<24), /* Akhand */ - apkn = ('a' | 'p'<<8 | 'k'<<16 | 'n'<<24), /* Kerning for Alternate Proportional Widths */ - blwm = ('b' | 'l'<<8 | 'w'<<16 | 'm'<<24), /* Below-base Mark Positioning */ - blws = ('b' | 'l'<<8 | 'w'<<16 | 's'<<24), /* Below-base Substitutions */ - calt = ('c' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Contextual Alternates */ - Case = ('c' | 'a'<<8 | 's'<<16 | 'e'<<24), /* Case-sensitive Forms */ - ccmp = ('c' | 'c'<<8 | 'm'<<16 | 'p'<<24), /* Glyph Composition / Decomposition */ - chws = ('c' | 'h'<<8 | 'w'<<16 | 's'<<24), /* Contextual Half-width Spacing */ - cjct = ('c' | 'j'<<8 | 'c'<<16 | 't'<<24), /* Conjunct Forms */ - clig = ('c' | 'l'<<8 | 'i'<<16 | 'g'<<24), /* Contextual Ligatures */ - cpct = ('c' | 'p'<<8 | 'c'<<16 | 't'<<24), /* Centered CJK Punctuation */ - cpsp = ('c' | 'p'<<8 | 's'<<16 | 'p'<<24), /* Capital Spacing */ - cswh = ('c' | 's'<<8 | 'w'<<16 | 'h'<<24), /* Contextual Swash */ - curs = ('c' | 'u'<<8 | 'r'<<16 | 's'<<24), /* Cursive Positioning */ - cv01 = ('c' | 'v'<<8 | '0'<<16 | '1'<<24), /* 'cv99' Character Variant 1 – Character Variant 99 */ - c2pc = ('c' | '2'<<8 | 'p'<<16 | 'c'<<24), /* Petite Capitals From Capitals */ - c2sc = ('c' | '2'<<8 | 's'<<16 | 'c'<<24), /* Small Capitals From Capitals */ - dist = ('d' | 'i'<<8 | 's'<<16 | 't'<<24), /* Distances */ - dlig = ('d' | 'l'<<8 | 'i'<<16 | 'g'<<24), /* Discretionary Ligatures */ - dtls = ('d' | 't'<<8 | 'l'<<16 | 's'<<24), /* Dotless Forms */ - expt = ('e' | 'x'<<8 | 'p'<<16 | 't'<<24), /* Expert Forms */ - falt = ('f' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Final Glyph on Line Alternates */ - flac = ('f' | 'l'<<8 | 'a'<<16 | 'c'<<24), /* Flattened Accent Forms */ - fwid = ('f' | 'w'<<8 | 'i'<<16 | 'd'<<24), /* Full Widths */ - haln = ('h' | 'a'<<8 | 'l'<<16 | 'n'<<24), /* Halant Forms */ - halt = ('h' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Alternate Half Widths */ - hist = ('h' | 'i'<<8 | 's'<<16 | 't'<<24), /* Historical Forms */ - hkna = ('h' | 'k'<<8 | 'n'<<16 | 'a'<<24), /* Horizontal Kana Alternates */ - hlig = ('h' | 'l'<<8 | 'i'<<16 | 'g'<<24), /* Historical Ligatures */ - hngl = ('h' | 'n'<<8 | 'g'<<16 | 'l'<<24), /* Hangul */ - hojo = ('h' | 'o'<<8 | 'j'<<16 | 'o'<<24), /* Hojo Kanji Forms (JIS X 0212-1990 Kanji Forms) */ - hwid = ('h' | 'w'<<8 | 'i'<<16 | 'd'<<24), /* Half Widths */ - ital = ('i' | 't'<<8 | 'a'<<16 | 'l'<<24), /* Italics */ - jalt = ('j' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Justification Alternates */ - jp78 = ('j' | 'p'<<8 | '7'<<16 | '8'<<24), /* JIS78 Forms */ - jp83 = ('j' | 'p'<<8 | '8'<<16 | '3'<<24), /* JIS83 Forms */ - jp90 = ('j' | 'p'<<8 | '9'<<16 | '0'<<24), /* JIS90 Forms */ - jp04 = ('j' | 'p'<<8 | '0'<<16 | '4'<<24), /* JIS2004 Forms */ - kern = ('k' | 'e'<<8 | 'r'<<16 | 'n'<<24), /* Kerning */ - lfbd = ('l' | 'f'<<8 | 'b'<<16 | 'd'<<24), /* Left Bounds */ - liga = ('l' | 'i'<<8 | 'g'<<16 | 'a'<<24), /* Standard Ligatures */ - lnum = ('l' | 'n'<<8 | 'u'<<16 | 'm'<<24), /* Lining Figures */ - locl = ('l' | 'o'<<8 | 'c'<<16 | 'l'<<24), /* Localized Forms */ - ltra = ('l' | 't'<<8 | 'r'<<16 | 'a'<<24), /* Left-to-right Alternates */ - ltrm = ('l' | 't'<<8 | 'r'<<16 | 'm'<<24), /* Left-to-right Mirrored Forms */ - mark = ('m' | 'a'<<8 | 'r'<<16 | 'k'<<24), /* Mark Positioning */ - mgrk = ('m' | 'g'<<8 | 'r'<<16 | 'k'<<24), /* Mathematical Greek */ - mkmk = ('m' | 'k'<<8 | 'm'<<16 | 'k'<<24), /* Mark to Mark Positioning */ - mset = ('m' | 's'<<8 | 'e'<<16 | 't'<<24), /* Mark Positioning via Substitution */ - nalt = ('n' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Alternate Annotation Forms */ - nlck = ('n' | 'l'<<8 | 'c'<<16 | 'k'<<24), /* NLC Kanji Forms */ - nukt = ('n' | 'u'<<8 | 'k'<<16 | 't'<<24), /* Nukta Forms */ - onum = ('o' | 'n'<<8 | 'u'<<16 | 'm'<<24), /* Oldstyle Figures */ - opbd = ('o' | 'p'<<8 | 'b'<<16 | 'd'<<24), /* Optical Bounds */ - ordn = ('o' | 'r'<<8 | 'd'<<16 | 'n'<<24), /* Ordinals */ - ornm = ('o' | 'r'<<8 | 'n'<<16 | 'm'<<24), /* Ornaments */ - palt = ('p' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Proportional Alternate Widths */ - pcap = ('p' | 'c'<<8 | 'a'<<16 | 'p'<<24), /* Petite Capitals */ - pkna = ('p' | 'k'<<8 | 'n'<<16 | 'a'<<24), /* Proportional Kana */ - pnum = ('p' | 'n'<<8 | 'u'<<16 | 'm'<<24), /* Proportional Figures */ - pres = ('p' | 'r'<<8 | 'e'<<16 | 's'<<24), /* Pre-base Substitutions */ - psts = ('p' | 's'<<8 | 't'<<16 | 's'<<24), /* Post-base Substitutions */ - pwid = ('p' | 'w'<<8 | 'i'<<16 | 'd'<<24), /* Proportional Widths */ - qwid = ('q' | 'w'<<8 | 'i'<<16 | 'd'<<24), /* Quarter Widths */ - rand = ('r' | 'a'<<8 | 'n'<<16 | 'd'<<24), /* Randomize */ - rclt = ('r' | 'c'<<8 | 'l'<<16 | 't'<<24), /* Required Contextual Alternates */ - rkrf = ('r' | 'k'<<8 | 'r'<<16 | 'f'<<24), /* Rakar Forms */ - rlig = ('r' | 'l'<<8 | 'i'<<16 | 'g'<<24), /* Required Ligatures */ - rtbd = ('r' | 't'<<8 | 'b'<<16 | 'd'<<24), /* Right Bounds */ - rtla = ('r' | 't'<<8 | 'l'<<16 | 'a'<<24), /* Right-to-left Alternates */ - rtlm = ('r' | 't'<<8 | 'l'<<16 | 'm'<<24), /* Right-to-left Mirrored Forms */ - ruby = ('r' | 'u'<<8 | 'b'<<16 | 'y'<<24), /* Ruby Notation Forms */ - rvrn = ('r' | 'v'<<8 | 'r'<<16 | 'n'<<24), /* Required Variation Alternates */ - salt = ('s' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Stylistic Alternates */ - sinf = ('s' | 'i'<<8 | 'n'<<16 | 'f'<<24), /* Scientific Inferiors */ - size = ('s' | 'i'<<8 | 'z'<<16 | 'e'<<24), /* Optical size */ - smcp = ('s' | 'm'<<8 | 'c'<<16 | 'p'<<24), /* Small Capitals */ - smpl = ('s' | 'm'<<8 | 'p'<<16 | 'l'<<24), /* Simplified Forms */ - ss01 = ('s' | 's'<<8 | '0'<<16 | '1'<<24), /* 'ss20' Stylistic Set 1 – Stylistic Set 20 */ - ssty = ('s' | 's'<<8 | 't'<<16 | 'y'<<24), /* Math Script-style Alternates */ - stch = ('s' | 't'<<8 | 'c'<<16 | 'h'<<24), /* Stretching Glyph Decomposition */ - subs = ('s' | 'u'<<8 | 'b'<<16 | 's'<<24), /* Subscript */ - sups = ('s' | 'u'<<8 | 'p'<<16 | 's'<<24), /* Superscript */ - swsh = ('s' | 'w'<<8 | 's'<<16 | 'h'<<24), /* Swash */ - test = ('t' | 'e'<<8 | 's'<<16 | 't'<<24), /* Test features, only for development */ - titl = ('t' | 'i'<<8 | 't'<<16 | 'l'<<24), /* Titling */ - tnam = ('t' | 'n'<<8 | 'a'<<16 | 'm'<<24), /* Traditional Name Forms */ - tnum = ('t' | 'n'<<8 | 'u'<<16 | 'm'<<24), /* Tabular Figures */ - trad = ('t' | 'r'<<8 | 'a'<<16 | 'd'<<24), /* Traditional Forms */ - twid = ('t' | 'w'<<8 | 'i'<<16 | 'd'<<24), /* Third Widths */ - unic = ('u' | 'n'<<8 | 'i'<<16 | 'c'<<24), /* Unicase */ - valt = ('v' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Alternate Vertical Metrics */ - vapk = ('v' | 'a'<<8 | 'p'<<16 | 'k'<<24), /* Kerning for Alternate Proportional Vertical Metrics */ - vatu = ('v' | 'a'<<8 | 't'<<16 | 'u'<<24), /* Vattu Variants */ - vchw = ('v' | 'c'<<8 | 'h'<<16 | 'w'<<24), /* Vertical Contextual Half-width Spacing */ - vert = ('v' | 'e'<<8 | 'r'<<16 | 't'<<24), /* Vertical Alternates */ - vhal = ('v' | 'h'<<8 | 'a'<<16 | 'l'<<24), /* Alternate Vertical Half Metrics */ - vkna = ('v' | 'k'<<8 | 'n'<<16 | 'a'<<24), /* Vertical Kana Alternates */ - vkrn = ('v' | 'k'<<8 | 'r'<<16 | 'n'<<24), /* Vertical Kerning */ - vpal = ('v' | 'p'<<8 | 'a'<<16 | 'l'<<24), /* Proportional Alternate Vertical Metrics */ - vrt2 = ('v' | 'r'<<8 | 't'<<16 | '2'<<24), /* Vertical Alternates and Rotation */ - vrtr = ('v' | 'r'<<8 | 't'<<16 | 'r'<<24), /* Vertical Alternates for Rotation */ - zero = ('z' | 'e'<<8 | 'r'<<16 | 'o'<<24), /* Slashed Zero */ + UNREGISTERED = 0, // Features that aren't pre-defined in the OpenType spec + isol = 'i' | 's'<<8 | 'o'<<16 | 'l'<<24, // Isolated Forms + fina = 'f' | 'i'<<8 | 'n'<<16 | 'a'<<24, // Terminal Forms + fin2 = 'f' | 'i'<<8 | 'n'<<16 | '2'<<24, // Terminal Forms #2 + fin3 = 'f' | 'i'<<8 | 'n'<<16 | '3'<<24, // Terminal Forms #3 + medi = 'm' | 'e'<<8 | 'd'<<16 | 'i'<<24, // Medial Forms + med2 = 'm' | 'e'<<8 | 'd'<<16 | '2'<<24, // Medial Forms #2 + init = 'i' | 'n'<<8 | 'i'<<16 | 't'<<24, // Initial Forms + ljmo = 'l' | 'j'<<8 | 'm'<<16 | 'o'<<24, // Leading Jamo Forms + vjmo = 'v' | 'j'<<8 | 'm'<<16 | 'o'<<24, // Vowel Jamo Forms + tjmo = 't' | 'j'<<8 | 'm'<<16 | 'o'<<24, // Trailing Jamo Forms + rphf = 'r' | 'p'<<8 | 'h'<<16 | 'f'<<24, // Reph Form + blwf = 'b' | 'l'<<8 | 'w'<<16 | 'f'<<24, // Below-base Forms + half = 'h' | 'a'<<8 | 'l'<<16 | 'f'<<24, // Half Forms + pstf = 'p' | 's'<<8 | 't'<<16 | 'f'<<24, // Post-base Forms + abvf = 'a' | 'b'<<8 | 'v'<<16 | 'f'<<24, // Above-base Forms + pref = 'p' | 'r'<<8 | 'e'<<16 | 'f'<<24, // Pre-base Forms + numr = 'n' | 'u'<<8 | 'm'<<16 | 'r'<<24, // Numerators + frac = 'f' | 'r'<<8 | 'a'<<16 | 'c'<<24, // Fractions + dnom = 'd' | 'n'<<8 | 'o'<<16 | 'm'<<24, // Denominators + cfar = 'c' | 'f'<<8 | 'a'<<16 | 'r'<<24, // Conjunct Form After Ro + aalt = 'a' | 'a'<<8 | 'l'<<16 | 't'<<24, // Access All Alternates + abvm = 'a' | 'b'<<8 | 'v'<<16 | 'm'<<24, // Above-base Mark Positioning + abvs = 'a' | 'b'<<8 | 'v'<<16 | 's'<<24, // Above-base Substitutions + afrc = 'a' | 'f'<<8 | 'r'<<16 | 'c'<<24, // Alternative Fractions + akhn = 'a' | 'k'<<8 | 'h'<<16 | 'n'<<24, // Akhand + apkn = 'a' | 'p'<<8 | 'k'<<16 | 'n'<<24, // Kerning for Alternate Proportional Widths + blwm = 'b' | 'l'<<8 | 'w'<<16 | 'm'<<24, // Below-base Mark Positioning + blws = 'b' | 'l'<<8 | 'w'<<16 | 's'<<24, // Below-base Substitutions + calt = 'c' | 'a'<<8 | 'l'<<16 | 't'<<24, // Contextual Alternates + Case = 'c' | 'a'<<8 | 's'<<16 | 'e'<<24, // Case-sensitive Forms + ccmp = 'c' | 'c'<<8 | 'm'<<16 | 'p'<<24, // Glyph Composition / Decomposition + chws = 'c' | 'h'<<8 | 'w'<<16 | 's'<<24, // Contextual Half-width Spacing + cjct = 'c' | 'j'<<8 | 'c'<<16 | 't'<<24, // Conjunct Forms + clig = 'c' | 'l'<<8 | 'i'<<16 | 'g'<<24, // Contextual Ligatures + cpct = 'c' | 'p'<<8 | 'c'<<16 | 't'<<24, // Centered CJK Punctuation + cpsp = 'c' | 'p'<<8 | 's'<<16 | 'p'<<24, // Capital Spacing + cswh = 'c' | 's'<<8 | 'w'<<16 | 'h'<<24, // Contextual Swash + curs = 'c' | 'u'<<8 | 'r'<<16 | 's'<<24, // Cursive Positioning + cv01 = 'c' | 'v'<<8 | '0'<<16 | '1'<<24, // Character Variant 1 + cv02 = 'c' | 'v'<<8 | '0'<<16 | '2'<<24, // Character Variant 2 + cv03 = 'c' | 'v'<<8 | '0'<<16 | '3'<<24, // Character Variant 3 + cv04 = 'c' | 'v'<<8 | '0'<<16 | '4'<<24, // Character Variant 4 + cv05 = 'c' | 'v'<<8 | '0'<<16 | '5'<<24, // Character Variant 5 + cv06 = 'c' | 'v'<<8 | '0'<<16 | '6'<<24, // Character Variant 6 + cv07 = 'c' | 'v'<<8 | '0'<<16 | '7'<<24, // Character Variant 7 + cv08 = 'c' | 'v'<<8 | '0'<<16 | '8'<<24, // Character Variant 8 + cv09 = 'c' | 'v'<<8 | '0'<<16 | '9'<<24, // Character Variant 9 + cv10 = 'c' | 'v'<<8 | '1'<<16 | '0'<<24, // Character Variant 10 + cv11 = 'c' | 'v'<<8 | '1'<<16 | '1'<<24, // Character Variant 11 + cv12 = 'c' | 'v'<<8 | '1'<<16 | '2'<<24, // Character Variant 12 + cv13 = 'c' | 'v'<<8 | '1'<<16 | '3'<<24, // Character Variant 13 + cv14 = 'c' | 'v'<<8 | '1'<<16 | '4'<<24, // Character Variant 14 + cv15 = 'c' | 'v'<<8 | '1'<<16 | '5'<<24, // Character Variant 15 + cv16 = 'c' | 'v'<<8 | '1'<<16 | '6'<<24, // Character Variant 16 + cv17 = 'c' | 'v'<<8 | '1'<<16 | '7'<<24, // Character Variant 17 + cv18 = 'c' | 'v'<<8 | '1'<<16 | '8'<<24, // Character Variant 18 + cv19 = 'c' | 'v'<<8 | '1'<<16 | '9'<<24, // Character Variant 19 + cv20 = 'c' | 'v'<<8 | '2'<<16 | '0'<<24, // Character Variant 20 + cv21 = 'c' | 'v'<<8 | '2'<<16 | '1'<<24, // Character Variant 21 + cv22 = 'c' | 'v'<<8 | '2'<<16 | '2'<<24, // Character Variant 22 + cv23 = 'c' | 'v'<<8 | '2'<<16 | '3'<<24, // Character Variant 23 + cv24 = 'c' | 'v'<<8 | '2'<<16 | '4'<<24, // Character Variant 24 + cv25 = 'c' | 'v'<<8 | '2'<<16 | '5'<<24, // Character Variant 25 + cv26 = 'c' | 'v'<<8 | '2'<<16 | '6'<<24, // Character Variant 26 + cv27 = 'c' | 'v'<<8 | '2'<<16 | '7'<<24, // Character Variant 27 + cv28 = 'c' | 'v'<<8 | '2'<<16 | '8'<<24, // Character Variant 28 + cv29 = 'c' | 'v'<<8 | '2'<<16 | '9'<<24, // Character Variant 29 + cv30 = 'c' | 'v'<<8 | '3'<<16 | '0'<<24, // Character Variant 30 + cv31 = 'c' | 'v'<<8 | '3'<<16 | '1'<<24, // Character Variant 31 + cv32 = 'c' | 'v'<<8 | '3'<<16 | '2'<<24, // Character Variant 32 + cv33 = 'c' | 'v'<<8 | '3'<<16 | '3'<<24, // Character Variant 33 + cv34 = 'c' | 'v'<<8 | '3'<<16 | '4'<<24, // Character Variant 34 + cv35 = 'c' | 'v'<<8 | '3'<<16 | '5'<<24, // Character Variant 35 + cv36 = 'c' | 'v'<<8 | '3'<<16 | '6'<<24, // Character Variant 36 + cv37 = 'c' | 'v'<<8 | '3'<<16 | '7'<<24, // Character Variant 37 + cv38 = 'c' | 'v'<<8 | '3'<<16 | '8'<<24, // Character Variant 38 + cv39 = 'c' | 'v'<<8 | '3'<<16 | '9'<<24, // Character Variant 39 + cv40 = 'c' | 'v'<<8 | '4'<<16 | '0'<<24, // Character Variant 40 + cv41 = 'c' | 'v'<<8 | '4'<<16 | '1'<<24, // Character Variant 41 + cv42 = 'c' | 'v'<<8 | '4'<<16 | '2'<<24, // Character Variant 42 + cv43 = 'c' | 'v'<<8 | '4'<<16 | '3'<<24, // Character Variant 43 + cv44 = 'c' | 'v'<<8 | '4'<<16 | '4'<<24, // Character Variant 44 + cv45 = 'c' | 'v'<<8 | '4'<<16 | '5'<<24, // Character Variant 45 + cv46 = 'c' | 'v'<<8 | '4'<<16 | '6'<<24, // Character Variant 46 + cv47 = 'c' | 'v'<<8 | '4'<<16 | '7'<<24, // Character Variant 47 + cv48 = 'c' | 'v'<<8 | '4'<<16 | '8'<<24, // Character Variant 48 + cv49 = 'c' | 'v'<<8 | '4'<<16 | '9'<<24, // Character Variant 49 + cv50 = 'c' | 'v'<<8 | '5'<<16 | '0'<<24, // Character Variant 50 + cv51 = 'c' | 'v'<<8 | '5'<<16 | '1'<<24, // Character Variant 51 + cv52 = 'c' | 'v'<<8 | '5'<<16 | '2'<<24, // Character Variant 52 + cv53 = 'c' | 'v'<<8 | '5'<<16 | '3'<<24, // Character Variant 53 + cv54 = 'c' | 'v'<<8 | '5'<<16 | '4'<<24, // Character Variant 54 + cv55 = 'c' | 'v'<<8 | '5'<<16 | '5'<<24, // Character Variant 55 + cv56 = 'c' | 'v'<<8 | '5'<<16 | '6'<<24, // Character Variant 56 + cv57 = 'c' | 'v'<<8 | '5'<<16 | '7'<<24, // Character Variant 57 + cv58 = 'c' | 'v'<<8 | '5'<<16 | '8'<<24, // Character Variant 58 + cv59 = 'c' | 'v'<<8 | '5'<<16 | '9'<<24, // Character Variant 59 + cv60 = 'c' | 'v'<<8 | '6'<<16 | '0'<<24, // Character Variant 60 + cv61 = 'c' | 'v'<<8 | '6'<<16 | '1'<<24, // Character Variant 61 + cv62 = 'c' | 'v'<<8 | '6'<<16 | '2'<<24, // Character Variant 62 + cv63 = 'c' | 'v'<<8 | '6'<<16 | '3'<<24, // Character Variant 63 + cv64 = 'c' | 'v'<<8 | '6'<<16 | '4'<<24, // Character Variant 64 + cv65 = 'c' | 'v'<<8 | '6'<<16 | '5'<<24, // Character Variant 65 + cv66 = 'c' | 'v'<<8 | '6'<<16 | '6'<<24, // Character Variant 66 + cv67 = 'c' | 'v'<<8 | '6'<<16 | '7'<<24, // Character Variant 67 + cv68 = 'c' | 'v'<<8 | '6'<<16 | '8'<<24, // Character Variant 68 + cv69 = 'c' | 'v'<<8 | '6'<<16 | '9'<<24, // Character Variant 69 + cv70 = 'c' | 'v'<<8 | '7'<<16 | '0'<<24, // Character Variant 70 + cv71 = 'c' | 'v'<<8 | '7'<<16 | '1'<<24, // Character Variant 71 + cv72 = 'c' | 'v'<<8 | '7'<<16 | '2'<<24, // Character Variant 72 + cv73 = 'c' | 'v'<<8 | '7'<<16 | '3'<<24, // Character Variant 73 + cv74 = 'c' | 'v'<<8 | '7'<<16 | '4'<<24, // Character Variant 74 + cv75 = 'c' | 'v'<<8 | '7'<<16 | '5'<<24, // Character Variant 75 + cv76 = 'c' | 'v'<<8 | '7'<<16 | '6'<<24, // Character Variant 76 + cv77 = 'c' | 'v'<<8 | '7'<<16 | '7'<<24, // Character Variant 77 + cv78 = 'c' | 'v'<<8 | '7'<<16 | '8'<<24, // Character Variant 78 + cv79 = 'c' | 'v'<<8 | '7'<<16 | '9'<<24, // Character Variant 79 + cv80 = 'c' | 'v'<<8 | '8'<<16 | '0'<<24, // Character Variant 80 + cv81 = 'c' | 'v'<<8 | '8'<<16 | '1'<<24, // Character Variant 81 + cv82 = 'c' | 'v'<<8 | '8'<<16 | '2'<<24, // Character Variant 82 + cv83 = 'c' | 'v'<<8 | '8'<<16 | '3'<<24, // Character Variant 83 + cv84 = 'c' | 'v'<<8 | '8'<<16 | '4'<<24, // Character Variant 84 + cv85 = 'c' | 'v'<<8 | '8'<<16 | '5'<<24, // Character Variant 85 + cv86 = 'c' | 'v'<<8 | '8'<<16 | '6'<<24, // Character Variant 86 + cv87 = 'c' | 'v'<<8 | '8'<<16 | '7'<<24, // Character Variant 87 + cv88 = 'c' | 'v'<<8 | '8'<<16 | '8'<<24, // Character Variant 88 + cv89 = 'c' | 'v'<<8 | '8'<<16 | '9'<<24, // Character Variant 89 + cv90 = 'c' | 'v'<<8 | '9'<<16 | '0'<<24, // Character Variant 90 + cv91 = 'c' | 'v'<<8 | '9'<<16 | '1'<<24, // Character Variant 91 + cv92 = 'c' | 'v'<<8 | '9'<<16 | '2'<<24, // Character Variant 92 + cv93 = 'c' | 'v'<<8 | '9'<<16 | '3'<<24, // Character Variant 93 + cv94 = 'c' | 'v'<<8 | '9'<<16 | '4'<<24, // Character Variant 94 + cv95 = 'c' | 'v'<<8 | '9'<<16 | '5'<<24, // Character Variant 95 + cv96 = 'c' | 'v'<<8 | '9'<<16 | '6'<<24, // Character Variant 96 + cv97 = 'c' | 'v'<<8 | '9'<<16 | '7'<<24, // Character Variant 97 + cv98 = 'c' | 'v'<<8 | '9'<<16 | '8'<<24, // Character Variant 98 + cv99 = 'c' | 'v'<<8 | '9'<<16 | '9'<<24, // Character Variant 99 + c2pc = 'c' | '2'<<8 | 'p'<<16 | 'c'<<24, // Petite Capitals From Capitals + c2sc = 'c' | '2'<<8 | 's'<<16 | 'c'<<24, // Small Capitals From Capitals + dist = 'd' | 'i'<<8 | 's'<<16 | 't'<<24, // Distances + dlig = 'd' | 'l'<<8 | 'i'<<16 | 'g'<<24, // Discretionary Ligatures + dtls = 'd' | 't'<<8 | 'l'<<16 | 's'<<24, // Dotless Forms + expt = 'e' | 'x'<<8 | 'p'<<16 | 't'<<24, // Expert Forms + falt = 'f' | 'a'<<8 | 'l'<<16 | 't'<<24, // Final Glyph on Line Alternates + flac = 'f' | 'l'<<8 | 'a'<<16 | 'c'<<24, // Flattened Accent Forms + fwid = 'f' | 'w'<<8 | 'i'<<16 | 'd'<<24, // Full Widths + haln = 'h' | 'a'<<8 | 'l'<<16 | 'n'<<24, // Halant Forms + halt = 'h' | 'a'<<8 | 'l'<<16 | 't'<<24, // Alternate Half Widths + hist = 'h' | 'i'<<8 | 's'<<16 | 't'<<24, // Historical Forms + hkna = 'h' | 'k'<<8 | 'n'<<16 | 'a'<<24, // Horizontal Kana Alternates + hlig = 'h' | 'l'<<8 | 'i'<<16 | 'g'<<24, // Historical Ligatures + hngl = 'h' | 'n'<<8 | 'g'<<16 | 'l'<<24, // Hangul + hojo = 'h' | 'o'<<8 | 'j'<<16 | 'o'<<24, // Hojo Kanji Forms (JIS X 0212-1990 Kanji Forms) + hwid = 'h' | 'w'<<8 | 'i'<<16 | 'd'<<24, // Half Widths + ital = 'i' | 't'<<8 | 'a'<<16 | 'l'<<24, // Italics + jalt = 'j' | 'a'<<8 | 'l'<<16 | 't'<<24, // Justification Alternates + jp78 = 'j' | 'p'<<8 | '7'<<16 | '8'<<24, // JIS78 Forms + jp83 = 'j' | 'p'<<8 | '8'<<16 | '3'<<24, // JIS83 Forms + jp90 = 'j' | 'p'<<8 | '9'<<16 | '0'<<24, // JIS90 Forms + jp04 = 'j' | 'p'<<8 | '0'<<16 | '4'<<24, // JIS2004 Forms + kern = 'k' | 'e'<<8 | 'r'<<16 | 'n'<<24, // Kerning + lfbd = 'l' | 'f'<<8 | 'b'<<16 | 'd'<<24, // Left Bounds + liga = 'l' | 'i'<<8 | 'g'<<16 | 'a'<<24, // Standard Ligatures + lnum = 'l' | 'n'<<8 | 'u'<<16 | 'm'<<24, // Lining Figures + locl = 'l' | 'o'<<8 | 'c'<<16 | 'l'<<24, // Localized Forms + ltra = 'l' | 't'<<8 | 'r'<<16 | 'a'<<24, // Left-to-right Alternates + ltrm = 'l' | 't'<<8 | 'r'<<16 | 'm'<<24, // Left-to-right Mirrored Forms + mark = 'm' | 'a'<<8 | 'r'<<16 | 'k'<<24, // Mark Positioning + mgrk = 'm' | 'g'<<8 | 'r'<<16 | 'k'<<24, // Mathematical Greek + mkmk = 'm' | 'k'<<8 | 'm'<<16 | 'k'<<24, // Mark to Mark Positioning + mset = 'm' | 's'<<8 | 'e'<<16 | 't'<<24, // Mark Positioning via Substitution + nalt = 'n' | 'a'<<8 | 'l'<<16 | 't'<<24, // Alternate Annotation Forms + nlck = 'n' | 'l'<<8 | 'c'<<16 | 'k'<<24, // NLC Kanji Forms + nukt = 'n' | 'u'<<8 | 'k'<<16 | 't'<<24, // Nukta Forms + onum = 'o' | 'n'<<8 | 'u'<<16 | 'm'<<24, // Oldstyle Figures + opbd = 'o' | 'p'<<8 | 'b'<<16 | 'd'<<24, // Optical Bounds + ordn = 'o' | 'r'<<8 | 'd'<<16 | 'n'<<24, // Ordinals + ornm = 'o' | 'r'<<8 | 'n'<<16 | 'm'<<24, // Ornaments + palt = 'p' | 'a'<<8 | 'l'<<16 | 't'<<24, // Proportional Alternate Widths + pcap = 'p' | 'c'<<8 | 'a'<<16 | 'p'<<24, // Petite Capitals + pkna = 'p' | 'k'<<8 | 'n'<<16 | 'a'<<24, // Proportional Kana + pnum = 'p' | 'n'<<8 | 'u'<<16 | 'm'<<24, // Proportional Figures + pres = 'p' | 'r'<<8 | 'e'<<16 | 's'<<24, // Pre-base Substitutions + psts = 'p' | 's'<<8 | 't'<<16 | 's'<<24, // Post-base Substitutions + pwid = 'p' | 'w'<<8 | 'i'<<16 | 'd'<<24, // Proportional Widths + qwid = 'q' | 'w'<<8 | 'i'<<16 | 'd'<<24, // Quarter Widths + rand = 'r' | 'a'<<8 | 'n'<<16 | 'd'<<24, // Randomize + rclt = 'r' | 'c'<<8 | 'l'<<16 | 't'<<24, // Required Contextual Alternates + rkrf = 'r' | 'k'<<8 | 'r'<<16 | 'f'<<24, // Rakar Forms + rlig = 'r' | 'l'<<8 | 'i'<<16 | 'g'<<24, // Required Ligatures + rtbd = 'r' | 't'<<8 | 'b'<<16 | 'd'<<24, // Right Bounds + rtla = 'r' | 't'<<8 | 'l'<<16 | 'a'<<24, // Right-to-left Alternates + rtlm = 'r' | 't'<<8 | 'l'<<16 | 'm'<<24, // Right-to-left Mirrored Forms + ruby = 'r' | 'u'<<8 | 'b'<<16 | 'y'<<24, // Ruby Notation Forms + rvrn = 'r' | 'v'<<8 | 'r'<<16 | 'n'<<24, // Required Variation Alternates + salt = 's' | 'a'<<8 | 'l'<<16 | 't'<<24, // Stylistic Alternates + sinf = 's' | 'i'<<8 | 'n'<<16 | 'f'<<24, // Scientific Inferiors + size = 's' | 'i'<<8 | 'z'<<16 | 'e'<<24, // Optical size + smcp = 's' | 'm'<<8 | 'c'<<16 | 'p'<<24, // Small Capitals + smpl = 's' | 'm'<<8 | 'p'<<16 | 'l'<<24, // Simplified Forms + ss01 = 's' | 's'<<8 | '0'<<16 | '1'<<24, // Stylistic Set 1 + ss02 = 's' | 's'<<8 | '0'<<16 | '2'<<24, // Stylistic Set 2 + ss03 = 's' | 's'<<8 | '0'<<16 | '3'<<24, // Stylistic Set 3 + ss04 = 's' | 's'<<8 | '0'<<16 | '4'<<24, // Stylistic Set 4 + ss05 = 's' | 's'<<8 | '0'<<16 | '5'<<24, // Stylistic Set 5 + ss06 = 's' | 's'<<8 | '0'<<16 | '6'<<24, // Stylistic Set 6 + ss07 = 's' | 's'<<8 | '0'<<16 | '7'<<24, // Stylistic Set 7 + ss08 = 's' | 's'<<8 | '0'<<16 | '8'<<24, // Stylistic Set 8 + ss09 = 's' | 's'<<8 | '0'<<16 | '9'<<24, // Stylistic Set 9 + ss10 = 's' | 's'<<8 | '1'<<16 | '0'<<24, // Stylistic Set 10 + ss11 = 's' | 's'<<8 | '1'<<16 | '1'<<24, // Stylistic Set 11 + ss12 = 's' | 's'<<8 | '1'<<16 | '2'<<24, // Stylistic Set 12 + ss13 = 's' | 's'<<8 | '1'<<16 | '3'<<24, // Stylistic Set 13 + ss14 = 's' | 's'<<8 | '1'<<16 | '4'<<24, // Stylistic Set 14 + ss15 = 's' | 's'<<8 | '1'<<16 | '5'<<24, // Stylistic Set 15 + ss16 = 's' | 's'<<8 | '1'<<16 | '6'<<24, // Stylistic Set 16 + ss17 = 's' | 's'<<8 | '1'<<16 | '7'<<24, // Stylistic Set 17 + ss18 = 's' | 's'<<8 | '1'<<16 | '8'<<24, // Stylistic Set 18 + ss19 = 's' | 's'<<8 | '1'<<16 | '9'<<24, // Stylistic Set 19 + ss20 = 's' | 's'<<8 | '2'<<16 | '0'<<24, // Stylistic Set 20 + ssty = 's' | 's'<<8 | 't'<<16 | 'y'<<24, // Math Script-style Alternates + stch = 's' | 't'<<8 | 'c'<<16 | 'h'<<24, // Stretching Glyph Decomposition + subs = 's' | 'u'<<8 | 'b'<<16 | 's'<<24, // Subscript + sups = 's' | 'u'<<8 | 'p'<<16 | 's'<<24, // Superscript + swsh = 's' | 'w'<<8 | 's'<<16 | 'h'<<24, // Swash + test = 't' | 'e'<<8 | 's'<<16 | 't'<<24, // Test features, only for development + titl = 't' | 'i'<<8 | 't'<<16 | 'l'<<24, // Titling + tnam = 't' | 'n'<<8 | 'a'<<16 | 'm'<<24, // Traditional Name Forms + tnum = 't' | 'n'<<8 | 'u'<<16 | 'm'<<24, // Tabular Figures + trad = 't' | 'r'<<8 | 'a'<<16 | 'd'<<24, // Traditional Forms + twid = 't' | 'w'<<8 | 'i'<<16 | 'd'<<24, // Third Widths + unic = 'u' | 'n'<<8 | 'i'<<16 | 'c'<<24, // Unicase + valt = 'v' | 'a'<<8 | 'l'<<16 | 't'<<24, // Alternate Vertical Metrics + vapk = 'v' | 'a'<<8 | 'p'<<16 | 'k'<<24, // Kerning for Alternate Proportional Vertical Metrics + vatu = 'v' | 'a'<<8 | 't'<<16 | 'u'<<24, // Vattu Variants + vchw = 'v' | 'c'<<8 | 'h'<<16 | 'w'<<24, // Vertical Contextual Half-width Spacing + vert = 'v' | 'e'<<8 | 'r'<<16 | 't'<<24, // Vertical Alternates + vhal = 'v' | 'h'<<8 | 'a'<<16 | 'l'<<24, // Alternate Vertical Half Metrics + vkna = 'v' | 'k'<<8 | 'n'<<16 | 'a'<<24, // Vertical Kana Alternates + vkrn = 'v' | 'k'<<8 | 'r'<<16 | 'n'<<24, // Vertical Kerning + vpal = 'v' | 'p'<<8 | 'a'<<16 | 'l'<<24, // Proportional Alternate Vertical Metrics + vrt2 = 'v' | 'r'<<8 | 't'<<16 | '2'<<24, // Vertical Alternates and Rotation + vrtr = 'v' | 'r'<<8 | 't'<<16 | 'r'<<24, // Vertical Alternates for Rotation + zero = 'z' | 'e'<<8 | 'r'<<16 | 'o'<<24, // Slashed Zero } -feature_id :: enum u32 { - UNREGISTERED = 0, - isol, /* Isolated Forms */ - fina, /* Terminal Forms */ - fin2, /* Terminal Forms #2 */ - fin3, /* Terminal Forms #3 */ - medi, /* Medial Forms */ - med2, /* Medial Forms #2 */ - init, /* Initial Forms */ - ljmo, /* Leading Jamo Forms */ - vjmo, /* Vowel Jamo Forms */ - tjmo, /* Trailing Jamo Forms */ - rphf, /* Reph Form */ - blwf, /* Below-base Forms */ - half, /* Half Forms */ - pstf, /* Post-base Forms */ - abvf, /* Above-base Forms */ - pref, /* Pre-base Forms */ - numr, /* Numerators */ - frac, /* Fractions */ - dnom, /* Denominators */ - cfar, /* Conjunct Form After Ro */ - aalt, /* Access All Alternates */ - abvm, /* Above-base Mark Positioning */ - abvs, /* Above-base Substitutions */ - afrc, /* Alternative Fractions */ - akhn, /* Akhand */ - apkn, /* Kerning for Alternate Proportional Widths */ - blwm, /* Below-base Mark Positioning */ - blws, /* Below-base Substitutions */ - calt, /* Contextual Alternates */ - Case, /* Case-sensitive Forms */ - ccmp, /* Glyph Composition / Decomposition */ - chws, /* Contextual Half-width Spacing */ - cjct, /* Conjunct Forms */ - clig, /* Contextual Ligatures */ - cpct, /* Centered CJK Punctuation */ - cpsp, /* Capital Spacing */ - cswh, /* Contextual Swash */ - curs, /* Cursive Positioning */ - cv01, /* 'cv99' Character Variant 1 – Character Variant 99 */ - c2pc, /* Petite Capitals From Capitals */ - c2sc, /* Small Capitals From Capitals */ - dist, /* Distances */ - dlig, /* Discretionary Ligatures */ - dtls, /* Dotless Forms */ - expt, /* Expert Forms */ - falt, /* Final Glyph on Line Alternates */ - flac, /* Flattened Accent Forms */ - fwid, /* Full Widths */ - haln, /* Halant Forms */ - halt, /* Alternate Half Widths */ - hist, /* Historical Forms */ - hkna, /* Horizontal Kana Alternates */ - hlig, /* Historical Ligatures */ - hngl, /* Hangul */ - hojo, /* Hojo Kanji Forms (JIS X 0212-1990 Kanji Forms) */ - hwid, /* Half Widths */ - ital, /* Italics */ - jalt, /* Justification Alternates */ - jp78, /* JIS78 Forms */ - jp83, /* JIS83 Forms */ - jp90, /* JIS90 Forms */ - jp04, /* JIS2004 Forms */ - kern, /* Kerning */ - lfbd, /* Left Bounds */ - liga, /* Standard Ligatures */ - lnum, /* Lining Figures */ - locl, /* Localized Forms */ - ltra, /* Left-to-right Alternates */ - ltrm, /* Left-to-right Mirrored Forms */ - mark, /* Mark Positioning */ - mgrk, /* Mathematical Greek */ - mkmk, /* Mark to Mark Positioning */ - mset, /* Mark Positioning via Substitution */ - nalt, /* Alternate Annotation Forms */ - nlck, /* NLC Kanji Forms */ - nukt, /* Nukta Forms */ - onum, /* Oldstyle Figures */ - opbd, /* Optical Bounds */ - ordn, /* Ordinals */ - ornm, /* Ornaments */ - palt, /* Proportional Alternate Widths */ - pcap, /* Petite Capitals */ - pkna, /* Proportional Kana */ - pnum, /* Proportional Figures */ - pres, /* Pre-base Substitutions */ - psts, /* Post-base Substitutions */ - pwid, /* Proportional Widths */ - qwid, /* Quarter Widths */ - rand, /* Randomize */ - rclt, /* Required Contextual Alternates */ - rkrf, /* Rakar Forms */ - rlig, /* Required Ligatures */ - rtbd, /* Right Bounds */ - rtla, /* Right-to-left Alternates */ - rtlm, /* Right-to-left Mirrored Forms */ - ruby, /* Ruby Notation Forms */ - rvrn, /* Required Variation Alternates */ - salt, /* Stylistic Alternates */ - sinf, /* Scientific Inferiors */ - size, /* Optical size */ - smcp, /* Small Capitals */ - smpl, /* Simplified Forms */ - ss01, /* 'ss20' Stylistic Set 1 – Stylistic Set 20 */ - ssty, /* Math Script-style Alternates */ - stch, /* Stretching Glyph Decomposition */ - subs, /* Subscript */ - sups, /* Superscript */ - swsh, /* Swash */ - test, /* Test features, only for development */ - titl, /* Titling */ - tnam, /* Traditional Name Forms */ - tnum, /* Tabular Figures */ - trad, /* Traditional Forms */ - twid, /* Third Widths */ - unic, /* Unicase */ - valt, /* Alternate Vertical Metrics */ - vapk, /* Kerning for Alternate Proportional Vertical Metrics */ - vatu, /* Vattu Variants */ - vchw, /* Vertical Contextual Half-width Spacing */ - vert, /* Vertical Alternates */ - vhal, /* Alternate Vertical Half Metrics */ - vkna, /* Vertical Kana Alternates */ - vkrn, /* Vertical Kerning */ - vpal, /* Proportional Alternate Vertical Metrics */ - vrt2, /* Vertical Alternates and Rotation */ - vrtr, /* Vertical Alternates for Rotation */ - zero, /* Slashed Zero */ -} - - -shaping_table :: enum u8 { - GSUB, - GPOS, -} - -lookup_info :: struct { - MaximumBacktrackWithoutSkippingGlyphs: u32, - MaximumLookaheadWithoutSkippingGlyphs: u32, - MaximumSubstitutionOutputSize: u32, - MaximumInputSequenceLength: u32, - MaximumLookupStackSize: u32, -} - -gdef :: struct {} -cmap_14 :: struct {} -gsub_gpos :: struct {} -maxp :: struct {} -hea :: struct {} -iterate_features :: struct {} +_gdef :: struct {} +_cmap_14 :: struct {} +_gsub_gpos :: struct {} +_maxp :: struct {} +_hea :: struct {} shaper_properties :: struct {} -feature :: struct {} -head :: struct {} +_feature :: struct {} +_head :: struct {} +_langsys :: struct {} +shape_config :: struct {} +glyph_config :: struct {} +shape_context :: struct {} + +allocator_op_allocate :: struct { + Pointer: rawptr, + Size: u32, +} + +allocator_op_free :: struct { + Pointer: rawptr, +} + +allocator_op :: struct { + Kind: allocator_op_kind, + + using op: struct #raw_union { + Allocate: allocator_op_allocate `raw_union_tag:"Kind=.ALLOCATE"`, + Free: allocator_op_free `raw_union_tag:"Kind=.FREE"`, + }, +} + +allocator_function :: #type proc "c" (Data: rawptr, Op: ^allocator_op) lookup_subtable_info :: struct { - MinimumBacktrackPlusOne: u32, - MinimumFollowupPlusOne: u32, + MinimumBacktrackPlusOne: u16, + MinimumFollowupPlusOne: u16, } -font :: struct { - FileBase: [^]byte, - FileSize: un, - Head: ^head, - Cmap: ^u16, - Gdef: ^gdef, - Cmap14: ^cmap_14, - ShapingTables: [shaping_table]^gsub_gpos, - Fvar: rawptr, - Maxp: ^maxp, +blob_table :: struct { + OffsetFromStartOfFile: u32, + Length: u32, +} - Hea: [orientation]^hea, - Mtx: [orientation]^u16, +load_font_state :: struct { + FontData: rawptr, + FontDataSize: u32, - LookupInfo: lookup_info, + Tables: [blob_table_id]blob_table, + LookupCount: u32, + LookupSubtableCount: u32, + GlyphCount: u32, + ScratchSize: u32, - GlyphCount: u32, - LookupCount: u32, - SubtableCount: u32, + GlyphLookupMatrixSizeInBytes: u32, + GlyphLookupSubtableMatrixSizeInBytes: u32, + TotalSize: u32, +} - GlyphLookupMatrix: [^]u32, // [LookupCount * GlyphCount] bitmap - GlyphLookupSubtableMatrix: [^]u32, // [LookupSubtableCount * GlyphCount] bitmap - LookupSubtableIndexOffsets: [^]u32, // [LookupCount] - SubtableInfos: [^]lookup_subtable_info, // [LookupSubtableCount] +blob_header :: struct { + Magic: u32, + Version: u32, + + LookupCount: u32, + LookupSubtableCount: u32, + GlyphCount: u32, GposLookupIndexOffset: u32, - Error: c.int, + GlyphLookupMatrixOffsetFromStartOfFile: u32, + GlyphLookupSubtableMatrixOffsetFromStartOfFile: u32, + LookupSubtableIndexOffsetsOffsetFromStartOfFile: u32, + SubtableInfosOffsetFromStartOfFile: u32, + + Tables: [blob_table_id]blob_table, } -glyph_classes :: struct { - Class: u16, - MarkAttachmentClass: u16, +font :: struct { + Allocator: allocator_function, + AllocatorData: rawptr, + + Blob: ^blob_header, + Cmap: ^u16, + Cmap14: ^_cmap_14, + + ShapingTables: [shaping_table]^_gsub_gpos, + + UserData: rawptr, + + Error: load_font_error, } -glyph_config :: struct { - EnabledFeatures: feature_set, - DisabledFeatures: feature_set, - FeatureOverrideCount: u32, - FeatureOverrideCapacity: u32, - RequiredFeatureOverrideCapacity: u32, - FeatureOverrides: [^]feature_override `fmt:"v,FeatureOverrideCount"`, -} +font_info :: struct { + Strings: [font_info_string_id]cstring, + StringLengths: [font_info_string_id]u16, -glyph :: struct { - Codepoint: rune, - Id: u16, // Glyph index. This is what you want to use to query outline data. - Uid: u16, - Classes: glyph_classes, - - Decomposition: u64, - - Config: ^glyph_config, - - Flags: glyph_flags, - - // These fields are the glyph's final positioning data. - // For normal usage, you should not have to use these directly yourself. - // In case you are curious or have a specific need, see kbts_PositionGlyph() to see how these are used. - OffsetX: i32, - OffsetY: i32, - AdvanceX: i32, - AdvanceY: i32, - - ParentInfo: u32, - - // This is set by GSUB and used by GPOS. - // A 0-index means that we should attach to the last component in the ligature. - // - // From the Microsoft docs: - // To correctly access the subtables, the client must keep track of the component associated with the mark. - // - // For a given mark assigned to a particular class, the appropriate base attachment point is determined by which - // ligature component the mark is associated with. This is dependent on the original character string and subsequent - // character- or glyph-sequence processing, not the font data alone. While a text-layout client is performing any - // character-based preprocessing or any glyph-substitution operations using the GSUB table, the text-layout client - // must keep track of associations of marks to particular ligature-glyph components. - LigatureUid: u16, - LigatureComponentIndexPlusOne: u16, - - // Earlier on, we used to assume that, if a glyph had no advance, or had the MARK glyph class, then - // it could be handled as a mark in layout operations. This is inaccurate. - // Unicode makes a distinction between attached marks and standalone marks. For our purposes, attached - // marks are marks that have found a valid base character to attach to. In practice, this means that the - // font contains a valid display position/configuration for it in the current context. - // In contrast, standalone marks are marks that aren't attached to anything. Fonts may still have glyphs - // for them, in which case we want to display those just like regular glyphs that take up horizontal space - // on the line. When fonts don't have glyphs for them, they simply stay around as zero-width glyphs. - // Standalone marks have notably different behavior compared to attached marks, and so, once we start - // applying positioning features, it becomes worthwhile to track exactly which glyph has attached to which. - AttachGlyphIndexPlusOne: u16, // Set by GPOS attachments. - - // Set in GSUB and used in GPOS, for STCH. - JoiningFeature: joining_feature, - - // Unicode properties filled in by CodepointToGlyph. - JoiningType: unicode_joining_type, - using ScriptBitField: bit_field u8 { - Script: script | 8, - }, - UnicodeFlags: unicode_flags, - SyllabicClass: u8, - SyllabicPosition: u8, - UseClass: u8, - CombiningClass: u8, - - MarkOrdering: u8, // Only used temporarily in NORMALIZE for Arabic mark reordering. -} - -glyph_array :: struct { - Glyphs: [^]glyph `fmt:"v,Count"`, - Count: u32, - TotalCount: u32, - Capacity: u32, - RequiredCapacity: u32, -} - -op_state_normalize :: struct { - CodepointsToDecomposeCount: un, - AboveBaseGlyphCount: un, -} - - -skip_flags :: distinct bit_set[skip_flag; u32] -skip_flag :: enum u32 { - ZWNJ = 0, - ZWJ = 1, -} - -op_state_gsub :: struct { - LookupFeatures: feature_set, - LookupIndex: un, - GlyphFilter: glyph_flags, - SkipFlags: skip_flags, -} - -op_state_normalize_hangul :: struct { - LvtGlyphs: [4]glyph `fmt:"v,LvtGlyphCount"`, - LvtGlyphCount: un, -} - -op_state_op_specific :: struct #raw_union { - Normalize: op_state_normalize, - Gsub: op_state_gsub, - NormalizeHangul: op_state_normalize_hangul, -} - -lookup_indices :: struct { - FeatureTag: feature_tag, - FeatureId: feature_id, - SkipFlags: skip_flags, - GlyphFilter: glyph_flags, - Count: u32, - Indices: [^]u16 `fmt:"v,Count"`, -} - -feature_set :: struct { - Flags: [(uint(len(feature_id)) + 63) / 64]u64, + StyleFlags: font_style_flags, + Weight: font_weight, + Width: font_width, } feature_override :: struct { - Id: feature_id, - Tag: feature_tag, - EnabledOrAlternatePlusOne: u32, -} - -op :: struct { - Kind: op_kind, - Features: feature_set, -} - -// This needs to be updated when we change the op lists! -MAX_SIMULTANEOUS_FEATURES :: 16 -op_state :: struct { - WrittenCount: un, - GlyphIndex: un, - FrameCount: u32, - ResumePoint: u32, - - FeatureCount: u32, - FeatureLookupIndices: [MAX_SIMULTANEOUS_FEATURES]lookup_indices `fmt:"v,FeatureCount"`, - - UnregisteredFeatureCount: u32, - UnregisteredFeatureTags: [MAX_SIMULTANEOUS_FEATURES]feature_tag `fmt:"v,UnregisteredFeatureCount"`, - - OpSpecific: op_state_op_specific, - - // Ops are free to use the following as they please: - // LeftoverMemory: [LeftoverMemorySize]u8, -} - -op_list :: struct { // TODO(bill): is this actually a slice? e.g. `op_list :: []op_kind` - Ops: [^]op_kind, - Length: un, -} - -indic_script_properties :: struct { - ViramaCodepoint: rune, - BlwfPostOnly: bool, // b8 - RephPosition: reph_position, - RephEncoding: reph_encoding, - RightSideMatraPosition: syllabic_position, - AboveBaseMatraPosition: syllabic_position, - BelowBaseMatraPosition: syllabic_position, -} - -langsys :: struct {} - -shape_config :: struct { - Font: ^font, - Script: script, - Language: language, - Langsys: [shaping_table]^langsys, - OpLists: [4]op_list, - - Features: ^feature_set, - - Shaper: shaper, - ShaperProperties: ^shaper_properties, - - IndicScriptProperties: indic_script_properties, - Blwf: ^feature, - Pref: ^feature, - Pstf: ^feature, - Locl: ^feature, - Rphf: ^feature, - Half: ^feature, - Vatu: ^feature, - - // Indic - Virama: glyph, - - DottedCircle: glyph, - Whitespace: glyph, - - // Thai - Nikhahit: glyph, - SaraAa: glyph, -} - -shape_state :: struct { - Op: op, - Config: ^shape_config, - MainDirection: direction, - RunDirection: direction, - - UserFeatures: feature_set, - - GlyphArray: glyph_array, - ClusterGlyphArray: glyph_array, - - DottedCircleInsertIndex: u32, - - GlyphCountStartingFromCurrentCluster: u32, - - At: u32, - ResumePoint: u32, - OpGlyphOffset: u32, - ClusterGlyphCount: u32, - Ip: u32, - NextGlyphUid: u32, - - RequiredGlyphCapacity: u32, - - RealCluster: c.int, - ClusterAtStartOfWord: c.int, - WordBreak: c.int, - - // This must always be the last member! - OpState: op_state, -} - -cursor :: struct { - Direction: direction, - LastAdvanceX: i32, - X: i32, - Y: i32, + Tag: feature_tag, + Value: c.int, } break_type :: struct { // The break code mostly works in relative positions, but we convert to absolute positions for the user. // That way, breaks can be trivially stored and compared and such and it just works. - Position: u32, - Flags: break_flags, - Direction: direction, // Only valid if (Flags & BREAK_FLAG_DIRECTION). - Script: script, // Only valid if (Flags & BREAK_FLAG_SCRIPT). + Position: c.int, + Flags: break_flags, + Direction: direction, // Only valid if (DIRECTION in Flags). + ParagraphDirection: direction, // Only valid if (PARAGRAPH_DIRECTION in Flags). + Script: script, // Only valid if (SCRIPT in Flags). } bracket :: struct { Codepoint: rune, + Position: u32, using DirectionBitField: bit_field u8 { Direction: direction | 8, }, @@ -2003,33 +1876,28 @@ bracket :: struct { }, } -break_state_flags :: distinct bit_set[break_state_flag; u32] -break_state_flag :: enum u32 { - STARTED = 0, - END = 1, - RAN_OUT_OF_REORDER_BUFFER_SPACE = 2, - - // Bidirectional flags - SAW_R_AFTER_L = 3, - SAW_AL_AFTER_LR = 4, - LAST_WAS_BRACKET = 5, -} - // In the worst case, a single call to BreakAddCodepoint would generate 4 breaks. // We buffer breaks to reorder them before returning them to the user. // This potentially requires infinite memory, which we don't have, so you may want to tweak this constant, // although, really, if the defaults don't work, then you have likely found very strange/adversarial text. -BREAK_REORDER_BUFFER_FLUSH_THRESHOLD :: 4 -BREAK_REORDER_BUFFER_SIZE :: BREAK_REORDER_BUFFER_FLUSH_THRESHOLD * 2 break_state :: struct { - Breaks: [BREAK_REORDER_BUFFER_SIZE]break_type `fmt:"v,Breaks"`, - BreakCount: u32, - MainDirection: direction, + Breaks: [8]break_type `fmt:"v,BreakCount"`, + BreakCount: u32, - LastFlushedBreakPosition: u32, - CurrentPosition: u32, + ParagraphDirection: direction, + UserParagraphDirection: direction, - LastScripts: [2]u8, + CurrentPosition: u32, + ParagraphStartPosition: u32, + + LastScriptBreakPosition: u32, + LastDirectionBreakPosition: u32, + LastScriptBreakScript: u8, + LastDirectionBreakDirection: u8, + + ScriptPositionOffset: i16, + ScriptCount: u32, + ScriptSet: [MAXIMUM_CODEPOINT_SCRIPTS]u8 `fmt:"v,ScriptCount"`, Brackets: [64]bracket `fmt:"v,BracketCount"`, BracketCount: u32, @@ -2068,7 +1936,12 @@ break_state :: struct { // Instead of staying synchronized with LineBreaks/LineUnbreaks, // this advances every character always. // (This is only needed because ZWJ can create an unbreak while simultaneously being ignored.) - LineUnbreaksAsync, + LineUnbreaksAsync: bit_field u64 { + _0: u64 | 16, + _1: u64 | 16, + _2: u64 | 16, + _3: u64 | 16, + }, LineUnbreaks: bit_field u64 { _0: u64 | 16, _1: u64 | 16, @@ -2076,10 +1949,10 @@ break_state :: struct { _3: u64 | 16, }, LineBreakHistory: bit_field u32 { - _0: u32 | 8, // break_flags - _1: u32 | 8, // break_flags - _2: u32 | 8, // break_flags - _3: u32 | 8, // break_flags + _0: u32 | 8, + _1: u32 | 8, + _2: u32 | 8, + _3: u32 | 8, }, LineBreak2PositionOffset: i16, LineBreak3PositionOffset: i16, @@ -2087,12 +1960,188 @@ break_state :: struct { using LastDirectionBitField: bit_field u8 { LastDirection: direction | 8, }, - BidirectionalClass2: unicode_bidirectional_class, - BidirectionalClass1: unicode_bidirectional_class, + BidirectionalClass2: u8, + BidirectionalClass1: u8, + Bidirectional1PositionOffset: i16, + Bidirectional2PositionOffset: i16, JapaneseLineBreakStyle: japanese_line_break_style, + ConfigFlags: break_config_flags, GraphemeBreakState: u8, - LastLineBreakClass: line_break_class, - LastWordBreakClass: word_break_class, - LastWordBreakClassIncludingIgnored: word_break_class, + LastLineBreakClass: u8, + LastWordBreakClass: u8, + LastWordBreakClassIncludingIgnored: u8, } + +decode :: struct { + Codepoint: rune, + + SourceCharactersConsumed: c.int, + Valid: b32, +} + +encode_utf8 :: struct { + Encoded: [4]u8 `fmt:"q,EncodedLength"`, + EncodedLength: c.int, + Valid: b32, +} + +glyph_classes :: struct { + Class: u16, + MarkAttachmentClass: u16, +} + +glyph :: struct { + Prev: ^glyph, + Next: ^glyph, + + Codepoint: rune, + Id: u16, // Glyph index. This is what you want to use to query outline data. + Uid: u16, + + // This field is kept and returned as-is throughout the shaping process. + // When you are using the context API, it contains a codepoint index always! + // To get the original user ID with the context API, you need to get the corresponding shape_codepoint + // with ShapeGetShapeCodepoint(Context, Glyph^.UserIdOrCodepointIndex, ...); + UserIdOrCodepointIndex: c.int, + + // Used by GPOS + OffsetX: i32, + OffsetY: i32, + AdvanceX: i32, + AdvanceY: i32, + + // Earlier on, we used to assume that, if a glyph had no advance, or had the MARK glyph class, then + // it could be handled as a mark in layout operations. This is inaccurate. + // Unicode makes a distinction between attached marks and standalone marks. For our purposes, attached + // marks are marks that have found a valid base character to attach to. In practice, this means that the + // font contains a valid display position/configuration for it in the current context. + // In contrast, standalone marks are marks that aren't attached to anything. Fonts may still have glyphs + // for them, in which case we want to display those just like regular glyphs that take up horizontal space + // on the line. When fonts don't have glyphs for them, they simply stay around as zero-width glyphs. + // Standalone marks have notably different behavior compared to attached marks, and so, once we start + // applying positioning features, it becomes worthwhile to track exactly which glyph has attached to which. + AttachGlyph: ^glyph, // Set by GPOS attachments. + + Config: ^glyph_config, + + Decomposition: u64, + + Classes: glyph_classes, + + Flags: glyph_flags, + + ParentInfo: u32, + + // This is set by GSUB and used by GPOS. + // A 0-index means that we should attach to the last component in the ligature. + // + // From the Microsoft docs: + // To correctly access the subtables, the client must keep track of the component associated with the mark. + // + // For a given mark assigned to a particular class, the appropriate base attachment point is determined by which + // ligature component the mark is associated with. This is dependent on the original character string and subsequent + // character- or glyph-sequence processing, not the font data alone. While a text-layout client is performing any + // character-based preprocessing or any glyph-substitution operations using the GSUB table, the text-layout client + // must keep track of associations of marks to particular ligature-glyph components. + LigatureUid: u16, + LigatureComponentIndexPlusOne: u16, + LigatureComponentCount: u16, + + // Set in GSUB and used in GPOS, for STCH. + JoiningFeature: joining_feature, + + // Unicode properties filled in by CodepointToGlyph. + JoiningType: unicode_joining_type, + UnicodeFlags: unicode_flags, + SyllabicClass: u8, + SyllabicPosition: u8, + UseClass: u8, + CombiningClass: u8, + + MarkOrdering: u8, // Only used temporarily in NORMALIZE for Arabic mark reordering. +} + +shape_codepoint :: struct { + Font: ^font, // Only set when (.GRAPHEME in BreakFlags) + Config: ^glyph_config, + + Codepoint: rune, + UserId: c.int, + + BreakFlags: break_flags, + Script: script, // Only set when (BreakFlags & KBTS_BREAK_FLAG_SCRIPT) != 0. + Direction: direction, // Only set when (BreakFlags & KBTS_BREAK_FLAG_DIRECTION) != 0. + ParagraphDirection: direction, // Only set when (BreakFlags & KBTS_BREAK_FLAG_PARAGRAPH_DIRECTION) != 0. +} + +shape_codepoint_iterator :: struct { + Codepoint: ^shape_codepoint, + Context: ^shape_context, + + EndBlockIndex: u32, + OnePastLastCodepointIndex: u32, + BlockIndex: u32, + CodepointIndex: u32, + CurrentBlockCodepointCount: u32, + FlatCodepointIndex: u32, +} + +glyph_iterator :: struct { + GlyphStorage: ^glyph_storage, + CurrentGlyph: ^glyph, + + LastAdvanceX: c.int, + X: c.int, + Y: c.int, +} + +arena_block_header :: struct { + Prev: ^arena_block_header, + Next: ^arena_block_header, +} + +arena :: struct { + Allocator: allocator_function, + AllocatorData: rawptr, + + BlockSentinel: arena_block_header, + FreeBlockSentinel: arena_block_header, + + Error: b32, +} + +glyph_storage :: struct { + Arena: arena, + + GlyphSentinel: glyph, + FreeGlyphSentinel: glyph, + + Error: b32, +} + +glyph_parent :: struct { + Decomposition: u64, + Codepoint: rune, +} + +font_coverage_test :: struct { + Font: ^font, + BaseCodepoint: rune, + + CurrentBaseError: b32, + Error: b32, + + BaseParents: [MAXIMUM_RECOMPOSITION_PARENTS]glyph_parent `fmt:"v,BaseParentCount"`, + BaseParentCount: u32, +} + +run :: struct { + Font: ^font, + Script: script, + ParagraphDirection: direction, + Direction: direction, + Flags: break_flags, + + Glyphs: glyph_iterator, +} \ No newline at end of file diff --git a/vendor/kb_text_shape/lib/kb_text_shape.lib b/vendor/kb_text_shape/lib/kb_text_shape.lib index 1c3b94779..6a48e9f87 100644 Binary files a/vendor/kb_text_shape/lib/kb_text_shape.lib and b/vendor/kb_text_shape/lib/kb_text_shape.lib differ diff --git a/vendor/kb_text_shape/src/kb_text_shape.h b/vendor/kb_text_shape/src/kb_text_shape.h index 57d3ca7a0..986bf3be6 100644 --- a/vendor/kb_text_shape/src/kb_text_shape.h +++ b/vendor/kb_text_shape/src/kb_text_shape.h @@ -1,313 +1,1215 @@ -/* kb_text_shape - v1.03 - text segmentation and shaping - by Jimmy Lefevre +/* kb_text_shape - v2.05 - text segmentation and shaping + by Jimmy Lefevre - SECURITY - This library provides NO SECURITY GUARANTEE whatsoever. - DO NOT use it on untrusted font files. + SECURITY + This library provides NO SECURITY GUARANTEE whatsoever. + DO NOT use it on untrusted font files. - FEATURE OVERVIEW - This library provides: - - Unicode segmentation - LTR/RTL breaking - Script breaking - Line breaking - Word breaking - Grapheme breaking - - OpenType text shaping - Open and parse TTF and OTF fonts - Extract glyph information - Apply OpenType features such as ligatures and contextual typographic rules - All OpenType shapers are supported, which means most languages in the world are supported - (see LANGUAGE_SUPPORT for known non-supported cases) + WHAT DOES THIS LIBRARY DO? + Before computers had monitors, the main way of inspecting the output of a command + was to print it out on real paper. When monitors appeared, most computer graphics + were text-based, meaning the display was arranged in a hardcoded grid in which each + cell could hold one of several hardcoded characters. As simple as it is, this kind + of text handling is sufficient for displaying almost any document written in the + Latin alphabet and a few other writing systems that happen to fit particularly well + on a grid, like Chinese and Japanese. + Handwritten Latin characters do not all have the same width, however. As computers + became more powerful, glyphs started having different widths to fit better together. + After that came kerning, which allows for packing glyphs closer together in pairs. + This is, of course, N-squared in the number of glyphs you want to handle, but this + is fine for the Latin alphabet, because there really aren't that many glyphs. + This is where TrueType stops: it is a good and simple, format for displaying text + using the Latin alphabet or writing systems that happen to work similarly to it. + All is well and good. - COMPILING & LINKING - This library uses declare-anywhere, so it will not compile as C89/VC6 C. - In one C/C++ file that #includes this file, do this: - #define KB_TEXT_SHAPE_IMPLEMENTATION - before the #include. That will create the implementation in that file. - If you also do this: - #define KB_TEXT_SHAPE_STATIC - then all functions will be declared as static. - If you do this: - #define KB_TEXT_SHAPE_NO_CRT - then we do not use the C runtime library. These functions are compiled out: - kbts_CreateShapeState() - kbts_FreeShapeState() - kbts_FontFromFile() - kbts_FreeFont() - Additionally, we call KBTS_MEMSET(), which defaults to memset(), including outside of NO_CRT code. - If you want to redirect it to your own function, you can do this: - #define KBTS_MEMSET my_awesome_memset + What about the rest of the writing systems? - API - Segmentation - kbts_BeginBreak() - kbts_BreakAddCodepoint() -- Feed a codepoint to the breaker. - You need to call Break() repeatedly after every call to BreakAddCodepoint(). - Something like: - kbts_BreakAddCodepoint(&BreakState, ...); - kbts_break Break; - while(kbts_Break(&BreakState, &Break)) {...} + Arabic is a cursive writing system. Much like when we write cursive ourselves, the + letters need to join together visually. Furthermore, a given letter in Arabic has + a different appearance depending on whether it is the first letter of a word, the + last letter of a word, or in the middle, and Unicode does not differenciate between + any of these. Also, Arabic features a beautiful set of marks that attach to letters, + much like accents in the Latin alphabet. You would usually want to align these marks + in some way depending on which other marks are present in the immediate vicinity. - When you call Break(), We guarantee that breaks are returned in-order. On our side, this means - that they are buffered and reordered. On your side, it means that there is a delay of a few - characters between your current position and the Break.Position that you will see. + Indic scripts, like Devanagari, have even less in common with Latin than Arabic does. - In some cases, our buffering might break. When that happens, we set - BREAK_STATE_FLAG_RAN_OUT_OF_REORDER_BUFFER_SPACE, and kbts_BreakStateIsValid() will return false. - This is a sticky error, so you can check it whenever you like. - To clear the error flag and start segmenting again, you will need to call BeginBreak(&BreakState), - which resets the entire state. + To try to support the plethora of writing systems out there, OpenType was introduced. + OpenType fonts contain rules that allow modifying a sequence of glyphs through pattern + matching. These rules can modify both the content of the sequence (ligatures replace + multiple glyphs with a single one, for instance) and its visual appearance by e.g. + attaching marks to letters. This is the meat of text shaping. - Note that the input configurations for which our buffering breaks should be, for all intents and - purposes, nonsensical. If you find legitimate text that we cannot segment without running out of - buffer space, then that is a bug. + OpenType rules have limitations, though. They don't work with mixed direction text, + because, when going from one text direction to the other, there is a visual jump that + breaks pattern matching. - The default buffer size is determined by the BREAK_REORDER_BUFFER_FLUSH_THRESHOLD. If you really - need a bigger buffer, then you might want to consider modifying this constant and recompiling - the library, although this should be viewed as an emergency solution and not a routine - configuration option. - kbts_BreakFlush() - kbts_Break() -- Call repeatedly to get breaks - kbts_BreakStateIsValid() - Easy font loading - kbts_FontFromFile() -- Open a font, byteswap it in place, and allocate auxiliary structures. - When you read a font with kb_text_shape, the library will byteswap its data in-place and perform - a bunch of other pre-computation passes to figure out memory limits and other useful information. - This means you cannot trivially pass our pointer to the font data to any other TTF library, since - they will expect the data to be in big endian format, which it won't be after we are done with it. + To illustrate, the logical string "0123456789" might have a display order like this: - You can expect font reading to be pretty slow. - On the other hand, you can expect shaping to be pretty fast. + 01234 765 89 + ^LTR ^RTL ^LTR continued - To open a font with your own IO and memory allocation, see "Manual Memory Management" below. - kbts_FreeFont() - kbts_FontIsValid() - Shaping - kbts_CreateShapeState() - kbts_FreeShapeState() - kbts_ShapeConfig() -- Bake a font/script-specific shaping configuration - kbts_CodepointToGlyph() - kbts_InferScript() -- Hacky script recognition for when no segmentation data is available - kbts_Shape() -- Returns 1 if more memory is needed, you should probably call this in a while(). - This is how you might call this in practice: - while(kbts_Shape(State, &Config, Direction, Direction, Glyphs, &GlyphCount, GlyphCapacity)) - { - Glyphs = realloc(Glyphs, sizeof(kbts_glyph) * State->RequiredGlyphCapacity); - GlyphCapacity = State->RequiredGlyphCapacity; - } - Once Shape() returns 0, you are done shaping. Glyph indices are in the kbts_glyph.Id field. - Please note that, while the glyphs do also contain a Codepoint field, this field will mostly - be meaningless whenever complex shaping operations occur. This is because fonts exclusively - work on glyph indices, and a lot of ligatures are obviously a combination of several codepoints - and do not have a corresponding codepoint in the Unicode world. - The same is true when a single glyph is split into multiple glyphs. A font might decide to - decompose a letter-with-accent into a letter glyph + an accent glyph. In that case, we will - know what the accent glyph's index is, but we are not told what its codepoint is. + As you can see, there is a visual jump from 4 all the way to 5, and similarly from + 7 to 8. + This kind of discontinuity cannot work with OpenType rules, which want to work with + "neighboring" glyphs in the visual sense. - There is currently no way to track where in the source text each glyph originates from. - One thing we might try is to have a "void *UserData" member on each glyph, and flow it through - the different substitutions, but I personally have not needed this yet and I do not have good - test cases for it. If you are interested, let me know! + OpenType rules don't work with mixed script text, either. They are designed to work with + a single writing system, and ideally a single language. A typographic rule that is correct + in writing system A might not be in writing system B, and vice versa. - Final positions are in font units and can be extracted with Cursor() and PositionGlyph(). - To convert font units to fractional pixels in FreeType: - (FontX * FtSizeMetrics.x_scale) >> 16 - (FontY * FtSizeMetrics.y_scale) >> 16 - This will give you 26.6 fractional pixel units. - See https://freetype.org/freetype2/docs/reference/ft2-sizing_and_scaling.html for more info. - kbts_ResetShapeState() - Shaping - feature control - kbts_FeatureOverride() -- Describe a manual override for a font feature - kbts_FeatureOverrideFromTag() -- This also works on features that do not have a kbts_feature_id, but they will be slower. - (Calling this with a feature that has a kbts_feature_id will not be slower.) - kbts_GlyphConfig() -- Bake per-glyph parameters (for now, only feature overrides) - Shaping - feature control - incremental API - With this API, you provide a buffer first, and gradually construct the glyph_config. - kbts_EmptyGlyphConfig() - kbts_GlyphConfigOverrideFeature() - kbts_GlyphConfigOverrideFeatureFromTag() - Layout - kbts_Cursor() - kbts_PositionGlyph() - Manual memory management - kbts_SizeOfShapeState() - kbts_PlaceShapeState() - kbts_ReadFontHeader() -- Read and byteswap the top of the file. - kbts_ReadFontData() -- Read and byteswap the rest. - kbts_PostReadFontInitialize() -- Initialize auxiliary structures - Example code for reading a font file with this API looks like this: - size_t ScratchSize = kbts_ReadFontHeader(&Font, Data, Size); - size_t PermanentMemorySize = kbts_ReadFontData(&Font, malloc(ScratchSize), ScratchSize); - kbts_PostReadFontInitialize(&Font, malloc(PermanentMemorySize), PermanentMemorySize); + So, for all of these reasons, we need to split our text before sending it to the shaper. + This is what the text processing pipeline looks like: - Please note that, AS SOON AS YOU CALL ReadFontHeader(), THE FONT DATA IS MODIFIED IN-PLACE. - AS SOON AS YOU CALL ReadFontHeader(), THE FONT DATA IS MODIFIED IN-PLACE. - AS SOON AS YOU CALL ReadFontHeader(), THE FONT DATA IS MODIFIED IN-PLACE. - AS SOON AS YOU CALL ReadFontHeader(), THE FONT DATA IS MODIFIED IN-PLACE! - If you need to open the same font with another library, you need to copy the data BEFORE - calling ReadFontHeader(). + Your text A Text runs with B Sequence of glyphs C + (Probably ------------> uniform direction ------------> ready to rasterize ------------> Pixels + UTF-8) and script - The buffer you pass to ReadFontData() is temporary and can be freed once the function returns. - The buffer you pass to PostReadFontInitialize() is persistent and can only be freed once you - are done with the font. - Utility, etc. - kbts_ShaperIsComplex() - kbts_ScriptIsComplex() - kbts_InferScript() -- Stupid script detection. Do not ship this! Use script breaks instead. - kbts_DecodeUtf8() - kbts_ScriptTagToScript() - kbts_FeatureTagToId() + We call arrow A text segmentation, arrow B text shaping, and arrow C rasterization. + This library does A and B. - EXAMPLE USAGE - Complete example: - const char *String = "..."; - size_t Length = strlen(String); - // Open a font file - kbts_font Font = kbts_FontFromFile("..."); - // Make some glyphs - kbts_glyph *Glyphs = (kbts_glyph *)malloc(sizeof(kbts_glyph) * Length); - uint32_t GlyphCount = 0; - kbts_script Script = KBTS_SCRIPT_DONT_KNOW; - kbts_direction Direction = KBTS_DIRECTION_NONE; - for(size_t StringAt = 0; StringAt < Length;) - { - kbts_decode Decode = kbts_DecodeUtf8(String + StringAt, Length - StringAt); - StringAt += Decode.SourceCharactersConsumed; - if(Decode.Valid) - { - kbts_glyph Glyph = kbts_CodepointToGlyph(&Font, Decode.Codepoint); - // Easy script inference for simple cases. (This is similar to hb_buffer_guess_segment_properties.) - // If you have already segmented String with our API, you already have a script! - // So no need to pass it in that case. - // Only use this as a shorthand, when you are pretty sure String is a single - // script. - kbts_InferScript(&Direction, &Script, Glyph.Script); - Glyphs[GlyphCount++] = Glyph; - } - } - // Shape - uint32_t GlyphCapacity = Length; - kbts_shape_state *State = kbts_CreateShapeState(&Font); - // A shape_config is immutable once created. You can freely share/hash it, etc. - kbts_shape_config Config = kbts_ShapeConfig(&Font, Script, KBTS_LANGUAGE_DONT_KNOW); - while(kbts_Shape(State, &Config, Direction, Direction, Glyphs, &GlyphCount, GlyphCapacity)) - { - Glyphs = realloc(Glyphs, sizeof(kbts_glyph) * State->RequiredGlyphCapacity); - GlyphCapacity = State->RequiredGlyphCapacity; - } - // Get final positions - kbts_cursor Cursor = kbts_Cursor(Direction); - for(size_t GlyphIndex = 0; GlyphIndex < GlyphCount; ++GlyphIndex) - { - int X, Y; - kbts_PositionGlyph(&Cursor, &Glyphs[GlyphIndex], &X, &Y); - } + FEATURE OVERVIEW + This library provides: + - Unicode segmentation + LTR/RTL breaking + Script breaking + Line breaking + Word breaking + Grapheme breaking + - OpenType text shaping + Open and parse TTF and OTF fonts + Apply OpenType features such as ligatures and contextual typographic rules + All OpenType shapers are supported, which means most languages in the world are supported + (see LANGUAGE_SUPPORT for known non-supported cases) - Breaking Unicode text - finding the end of the current line: - uint32_t LineLength = 0; - kbts_break_state BreakState; - kbts_BeginBreak(&BreakState, KBTS_DIRECTION_NONE, KBTS_JAPANESE_LINE_BREAK_STYLE_NORMAL); - for(size_t CodepointIndex = 0; (CodepointIndex < CodepointCount) && !LineLength; ++CodepointIndex) - { - // We use a fixed-width encoding (codepoints) -- just pass a PositionIncrement of 1. - // If we wanted to directly segment UTF-8 in-place, we would pass in however many bytes each UTF-8 character was. + COMPILING & LINKING + This library uses declare-anywhere, so it will not compile as C89/VC6 C. - // The last parameter to AddCodepoint is a boolean signifying the end of text. - // Alternatively, we could have written: - // kbts_BreakAddCodepoint(..., 0); - // if((CodepointIndex + 1) == CodepointCount) kbts_BreakFlush(); + In one C/C++ file that #includes this file, do this: + #define KB_TEXT_SHAPE_IMPLEMENTATION + before the #include. That will create the implementation in that file. - kbts_BreakAddCodepoint(&BreakState, Codepoints[CodepointIndex], 1, (CodepointIndex + 1) == CodepointCount); - kbts_break Break; - while(kbts_Break(&BreakState, &Break)) - { - // We could just as easily check for any other kind of break here. - // See kbts_break_flags for the kind of breaks we can find. - if(Break.Flags & KBTS_BREAK_FLAG_LINE_HARD) - { - LineLength = Break.Position; - } - } - } + If you also do this: + #define KB_TEXT_SHAPE_STATIC + then all functions will be declared as static. - Control which font features apply to which glyphs: - kbts_feature_override Ss03FeatureOverrides[] = { - kbts_FeatureOverride(KBTS_FEATURE_ID_ccmp, 0, 0), // Disable ccmp - kbts_FeatureOverride(KBTS_FEATURE_ID_ss03, 0, 1), // Enable ss03 - }; - kbts_glyph_config Ss03Config = kbts_GlyphConfig(Ss03FeatureOverrides, 2); - kbts_feature_override SaltFeatureOverrides[] = { - kbts_FeatureOverride(KBTS_FEATURE_ID_salt, 1, 3), // Pick alternate glyph number 3 from feature 'salt' - }; - kbts_glyph_config SaltConfig = kbts_GlyphConfig(SaltFeatureOverrides, 1); + If you do this: + #define KB_TEXT_SHAPE_NO_CRT + then we do not use the C runtime library. + In that case, these functions are compiled out: + kbts_ShapePushFontFromFile() + kbts_FontFromFile() + Additionally, there are some functions that you will want to #define yourself: + KBTS_MEMSET + defaults to memset otherwise. + KBTS_MEMCPY + defaults to memcpy otherwise. + You can redefine the default allocator by redefining these: + KBTS_MALLOC(AllocatorData, Size) + defaults to 0 if KB_TEXT_SHAPE_NO_CRT is defined, + defaults to malloc(Size) otherwise. + KBTS_FREE(AllocatorData, Pointer) + defaults to a no-op if KB_TEXT_SHAPE_NO_CRT is defined, + defaults to free(Pointer) otherwise. + In other words, + if you do not redefine the default allocator, and you #define KB_TEXT_SHAPE_NO_CRT, + then the default allocator always returns 0. - // Then, do this before calling kbts_Shape(): - MyGlyphs[0].Config = &Ss03Config; - MyGlyphs[1].Config = &SaltConfig; + EXAMPLES + Basic + kbts_shape_context *Context = kbts_CreateShapeContext(0, 0); + kbts_ShapePushFontFromFile(Context, "myfont.ttf", 0); - Open a font with your own memory: - kbts_font Font; - // Be careful: ReadFontHeader() and ReadFontData() both byteswap font data in-place! - size_t ScratchSize = kbts_ReadFontHeader(&Font, Data, Size); - size_t PermanentMemorySize = kbts_ReadFontData(&Font, malloc(ScratchSize), ScratchSize); - kbts_PostReadFontInitialize(&Font, malloc(PermanentMemorySize), PermanentMemorySize); - // At any point, you can call kbts_FontIsValid(&Font) to check if the read went well. - // You do not need to check for font validity in between API calls here; once a font is flagged - // with an error, subsequent API calls simply do nothing. - // If you have provided real font data, kbts_FontIsValid(&Font) will most likely be true. - // We may still fail to parse some technically valid fonts that contain very deeply-nested or - // self-referential lookups. - // In those cases, Harfbuzz might open the font, but, at the time of writing, it silently limits - // the recursion depth to 64 when applying the lookups anyway. + kbts_ShapeBegin(Context, KBTS_DIRECTION_DONT_KNOW, KBTS_LANGUAGE_DONT_KNOW); + kbts_ShapeUtf8(Context, "Let's shape something!", sizeof("Let's shape something!") - 1, KBTS_USER_ID_GENERATION_MODE_CODEPOINT_INDEX); + kbts_ShapeEnd(Context); - Allocate a shape_state with your own memory: - kbts_shape_state *State = kbts_PlaceShapeState(malloc(kbts_SizeOfShapeState(Font)), kbts_SizeOfShapeState(Font)); + // Layout runs naively left to right. + kbts_run Run; + int CursorX = 0, CursorY = 0; + while(kbts_ShapeRun(Context, &Run)) + { + kbts_glyph *Glyph; + while(kbts_GlyphIteratorNext(&Run.Glyphs, &Glyph)) + { + int GlyphX = CursorX + Glyph->OffsetX; + int GlyphY = CursorY + Glyph->OffsetY; - Use a single shape_state across multiple runs: - while(kbts_Shape(State, ...)) {...} - // If the previous shaping operation completed successfully, ResetShapeState is not necessary. - // If, for any reason, you have decided to stop shaping in the middle of an operation, though, - // you need to call it. - // (This is just setting a state counter, so this is very cheap.) - kbts_ResetShapeState(State); - while(kbts_Shape(State, ...)) {...} + DisplayGlyph(Glyph->Id, GlyphX, GlyphY); - Use a single shape_state across multiple fonts: - // Different fonts have different memory requirements for shaping. However, beyond that, there - // is nothing that ties a shape_state to a font. You may use it freely with multiple fonts, as - // long as it is large enough. - size_t Size0 = kbts_SizeOfShapeState(Font0); - size_t Size1 = kbts_SizeOfShapeState(Font1); - size_t Size = MAX(Size0, Size1) - kbts_shape_state *State = kbts_PlaceShapeState(malloc(Size), Size); + CursorX += Glyph->AdvanceX; + CursorY += Glyph->AdvanceY; + } + } - Use a single shape_config across multiple runs: - // Once a shape_config has been created, it is assumed to be immutable and can be trivially shared - // between runs/operations that have the same parameters. + Font collections + void *FontData; + int FontSize; + kbts_font Font = kbts_FontFromFile("myfonts.ttc", 0, 0, 0, &FontData, &FontSize); - PERFORMANCE - Just like most libraries that interact with font files, we use the file as an in-memory database. - There are a few issues with this approach: - - Font files can be arbitrarily complex, making it difficult to predict system behavior at runtime. - - Font files are encoded in big endian byte order, which is stupid and slow. - We compensate for this by pre-processing as much as we can when opening the file. Notably, we - byteswap everything we need in-place, we precompute some useful runtime memory bounds, and we - allocate a few auxiliary acceleration structures. + kbts_ShapePushFont(Context, &Font); - Since we byteswap everything in-place, you cannot pass the same font data to kbts and to another - library, because the other library will expect everything to be big endian. + int FontCount = kbts_FontCount(FontData, FontSize); + for(int FontIndex = 1; FontIndex < FontCount; ++FontIndex) + { + kbts_ShapePushFontFromMemory(Context, FontData, FontSize, FontIndex); + } - As a result of this approach, opening fonts is slow and shaping is fast. This is very much intentional. - At the time of writing (2025-07-13), on Harfbuzz's test suite, we are, on average, 4.5x faster than - Harfbuzz on my laptop (Ryzen 9 5900HX). As fonts are complex, and Harfbuzz's test suite is quite varied, - the speedup numbers are rather spread out: - Best: 22x - 10th percentile: 6.5x - Median: 4.5x - 90th percentile: 2.5x - Worst: 1.05x - So, aside from a few extreme cases, you should expect a small integer speedup factor compared to Harfbuzz. + Feature control + kbts_ShapeBegin(Context, KBTS_DIRECTION_DONT_KNOW, KBTS_LANGUAGE_DONT_KNOW); + + kbts_ShapePushFeature(Context, KBTS_FEATURE_TAG_kern, 0); + kbts_ShapeUtf8(Context, "Without kerning", sizeof("Without kerning") - 1, KBTS_USER_ID_GENERATION_MODE_CODEPOINT_INDEX); + kbts_ShapePopFeature(Context, KBTS_FEATURE_TAG_kern); + + kbts_ShapeUtf8(Context, "With kerning", sizeof("With kerning") - 1, KBTS_USER_ID_GENERATION_MODE_CODEPOINT_INDEX); + + kbts_ShapeEnd(Context); + + @Todo: Write more examples + + API + The shaping API is broken down into two parts: the context API and the direct API. + + The context API is the higher-level API of the two and is meant to be the default + API. + It exposes an immediate-mode, procedural interface somewhat inspired by Dear Imgui + and covers most of the functionality present in the library. It notably includes + automatic segmentation into paragraphs and runs, shaping, and font fallback. + + The direct API, in contrast, is all of the tools you can use to directly manage and + manipulate shaping data. With it, you can interact directly with the lower-level + parts of the library, giving you very granular control. It is also very explicit + about memory. As a result, it is also a lot more verbose than the context API. + + The library also contains several miscellaneous utility functions that are not + obviously part of any of the two aforementioned APIs. + + + In the documentation below, all functions (as well as some structs/enums) are + marked with "search tags". + As an example, this hypothetical function: + + int kbts_Foo(int X); + + Will be presented like this: + + :kbts_Foo + :Foo + int kbts_Foo(int X); + + Allowing you to easily search for its documentation by searching for either ":Foo" + or ":kbts_Foo". + + MEMORY MANAGEMENT + kb_text_shape takes manual memory management seriously, and tries to give the user as much + control over memory as possible. + + Whenever it is possible for you to pass your own buffer into a function, we allow it. + Whenever it is not possible, we allow specifying a custom allocator. + An allocator is simply a function that manages memory: + + :kbts_allocator_function + :allocator_function + typedef void kbts_allocator_function(void *Data, kbts_allocator_op *Op); + [Data] the custom data pointer you passed in along with your allocator. + [Op] the memory request. It is of this type: + + :kbts_allocator_op + :allocator_op + typedef struct kbts_allocator_op + { + kbts_allocator_op_kind Kind; + + union + { + kbts_allocator_op_allocate Allocate; + kbts_allocator_op_free Free; + }; + } kbts_allocator_op; + + And the possible op kinds are: + KBTS_ALLOCATOR_OP_KIND_ALLOCATE + KBTS_ALLOCATOR_OP_KIND_FREE + + ALLOCATE expects you to fill in Op->Allocate.Pointer. + The allocation does not need to be aligned. + FREE expects you to free Op->Free.Pointer. + + THE CONTEXT API + CONTEXT:CREATION + :kbts_SizeOfShapeContext + :SizeOfShapeContext + int kbts_SizeOfShapeContext() + Tells you how big of a buffer you need to provide to kbts_PlaceShapeContext. + + :kbts_PlaceShapeContext + :PlaceShapeContext + kbts_shape_context *kbts_PlaceShapeContext(kbts_allocator_function *Allocator, void *AllocatorData, void *Memory) + Places a context at Memory and initializes it. + [Allocator] will be used for subsequent allocations. + + :kbts_PlaceShapeContextFixedMemory + :PlaceShapeContextFixedMemory + kbts_shape_context *kbts_PlaceShapeContextFixedMemory(void *Memory, int Size) + Places a context at Memory and initializes it. + This context will only use the [Size] bytes located at [Memory] for its allocations. + + :kbts_CreateShapeContext + :CreateShapeContext + kbts_shape_context *kbts_CreateShapeContext(kbts_allocator_function *Allocator, void *AllocatorData) + Allocates a context using [Allocator] and initializes it. + + :kbts_DestroyShapeContext + :DestroyShapeContext + void kbts_DestroyShapeContext(kbts_shape_context *Context) + Frees all context memory. + If the Context was allocated by kbts_CreateShapeContext, then it is also freed. + + CONTEXT:FONT HANDLING + The context is capable of managing multiple fonts through a font stack. + The font stack will hold references to all fonts in use by the context. Whenever + you try to shape some text, the context will check to see if it is supported by + the font at the top of the stack. If it is not, it will try the next font down, + and so on, until all fonts have been tried. As such, you should push your fallback + fonts first, and your preferred fonts last. + + :kbts_ShapePushFontFromFile + :ShapePushFontFromFile + kbts_font *kbts_ShapePushFontFromFile(kbts_shape_context *Context, const char *FileName, int FontIndex) + (This function is not available if KB_TEXT_SHAPE_NO_CRT is defined.) + + Opens the file corresponding to [FileName], parses the [FontIndex]th font + within it, and, if successful, pushes the result onto the stack. + + A [return value] of 0 could mean that the stack is out of space (see + KBTS_CONTEXT_MAX_FONT_COUNT), that the file could not be found or opened, + or that the parse has failed. + + :kbts_ShapePushFontFromMemory + :ShapePushFontFromMemory + kbts_font *kbts_ShapePushFontFromMemory(kbts_shape_context *Context, void *Memory, int Size, int FontIndex) + Parses the [FontIndex]th font in [Memory] and pushes the result to the font + stack. + + A [return value] of 0 could mean that the stack is out of space (see + KBTS_CONTEXT_MAX_FONT_COUNT) or that the font could not be parsed. + + :kbts_ShapePushFont + :ShapePushFont + kbts_font *kbts_ShapePushFont(kbts_shape_context *Context, kbts_font *Font) + Pushes the pre-parsed [Font] onto the stack. + + A [return value] of 0 means that the stack has run out of space (see + KBTS_CONTEXT_MAX_FONT_COUNT). + + :kbts_ShapePopFont + :ShapePopFont + kbts_font *kbts_ShapePopFont(kbts_shape_context *Context) + Removes the topmost font from the stack. + + A [return value] of 0 means that there is no font to remove. + A non-null [return value] is the original font pointer that was pushed. + + If the context allocated the font itself, using kbts_ShapePushFontFromFile or + kbts_ShapePushFontFromMemory, then the pointer is still returned, but it points to + freed memory. + + CONTEXT:SHAPING + :kbts_ShapeBegin + :ShapeBegin + void kbts_ShapeBegin(kbts_shape_context *Context, kbts_direction ParagraphDirection, kbts_language Language) + Begins a shaping pass. + + [ParagraphDirection] is sometimes called the "document direction". It can significantly + affect segmentation. Bidirectionality in text works like a stack: the default direction + is at the bottom of the stack, and, sometimes, text can _temporarily_ take a different + direction. In the end, though, it will always go back to the document direction. + + To illustrate, a period followed by a space ". " typically ends up resetting the current + direction to the paragraph direction. This means that, if my paragraph direction is + left-to-right, and I am shaping Arabic text, then each Arabic sentence will be + right-to-left, but the sentences themselves will be sequenced left-to-right. If + [ParagraphDirection] is KBTS_DIRECTION_DONT_KNOW, then the context takes the first + directional hint in the text as the paragraph direction. + + [Language] is used to select which font rules are used. Knowing this allows access to + language-specific typographical features. If [Language] is KBTS_LANGUAGE_DONT_KNOW, then + the default, language-agnostic font rules are used. + + :kbts_ShapeEnd + :ShapeEnd + void kbts_ShapeEnd(kbts_shape_context *Context) + Ends a shaping pass. + + This means you are done providing input to the context, and, in turn, that + you can start getting results from it with kbts_ShapeRun(). + + :kbts_ShapeRun + :ShapeRun + int kbts_ShapeRun(kbts_shape_context *Context, kbts_run *Run) + Once you've called kbts_ShapeEnd, you can get the resulting runs by calling this + function repeatedly. + + !!! CAREFUL !!! Memory is reused from one run to the next, so you cannot + trivially store [Run] and reuse it later. Instead, you should traverse the + glyphs using the iterator provided in Run.Glyphs and extract whatever data + you need before calling kbts_ShapeRun again. + + The [return value] is non-zero if a run was shaped. + When there is no text left to shape, the [return value] is 0. + + kbts_ShapeEnd(Context); + kbts_run Run; + while(kbts_ShapeRun(Context, &Run)) + { + // Handle Run + } + + :kbts_ShapePushFeature + :ShapePushFeature + void kbts_ShapePushFeature(kbts_shape_context *Context, kbts_u32 FeatureTag, int Value) + The context has a feature stack that allows you to manipulate font features hierarchically. + When you give text to the context, it will apply all feature overrides that are on the + stack at the time. + If two feature overrides use the same tag, then only the latest one, i.e. the one higher + in the stack, is applied. + + :kbts_ShapePopFeature + :ShapePopFeature + int kbts_ShapePopFeature(kbts_shape_context *Context, kbts_u32 FeatureTag) + Removes the latest feature override with tag [FeatureTag]. + The [return value] is non-zero if an override was found and removed, 0 if not. + + :kbts_ShapeCodepointWithUserId + :ShapeCodepointWithUserId + void kbts_ShapeCodepointWithUserId(kbts_shape_context *Context, int Codepoint, int UserId) + Inputs a codepoint to shape. + [Codepoint] is a Unicode codepoint. + [UserId] is an arbitrary identifier that you will get back when reading the results. + This is often some kind of index into the input text so that you can perform hit-testing. + If an automatic codepoint index is fine for you, consider using kbts_ShapeCodepoint. + + :kbts_ShapeCodepoint + :ShapeCodepoint + void kbts_ShapeCodepoint(kbts_shape_context *Context, int Codepoint) + Inputs a codepoint to shape. + + The codepoint's user ID will be an implicit codepoint index assigned by the + context. + + :kbts_ShapeUtf32WithUserId + :ShapeUtf32WithUserId + void kbts_ShapeUtf32WithUserId(kbts_shape_context *Context, + int *Utf32, int Length, + int UserId, int UserIdIncrement); + Inputs a block of UTF-32 text to shape. + + User IDs for each codepoint start at [UserId] and increment by [UserIdIncrement] + for every codepoint. + + :kbts_ShapeUtf32 + :ShapeUtf32 + void kbts_ShapeUtf32(kbts_shape_context *Context, int *Utf32, int Length) + Same as kbts_ShapeUtf8WithUserId, but using the context's implicit user ID counter. + + :kbts_ShapeUtf8WithUserId + :ShapeUtf8WithUserId + void kbts_ShapeUtf8WithUserId(kbts_shape_context *Context, + const char *Utf8, int Length, + int UserId, kbts_user_id_generation_mode UserIdGenerationMode); + Inputs a block of UTF-8 text to shape. + + User IDs for the corresponding codepoints start at [UserId]. + If [UserIdGenerationMode] is KBTS_USER_ID_GENERATION_MODE_CODEPOINT_INDEX, + each codepoint will increment the user ID by 1. + If [UserIdGenerationMode] is KBTS_USER_ID_GENERATION_MODE_CODEPOINT_INDEX, + each codepoint will increment the user ID by the length of its encoding in + UTF-8. + + :kbts_ShapeUtf8 + :ShapeUtf8 + void kbts_ShapeUtf8(kbts_shape_context *Context, + const char *Utf8, int Length, + kbts_user_id_generation_mode UserIdGenerationMode) + Same as kbts_ShapeUtf8WithUserId, but using the context's implicit user ID + counter. + + User IDs for the corresponding codepoints start at the context's implicit + user ID counter. + If [UserIdGenerationMode] is KBTS_USER_ID_GENERATION_MODE_CODEPOINT_INDEX, + each codepoint will increment the user ID by 1. + If [UserIdGenerationMode] is KBTS_USER_ID_GENERATION_MODE_CODEPOINT_INDEX, + each codepoint will increment the user ID by the length of its encoding in + bytes in UTF-8. + + :kbts_ShapeCurrentCodepointsIterator + :ShapeCurrentCodepointsIterator + kbts_shape_codepoint_iterator kbts_ShapeCurrentCodepointsIterator(kbts_shape_context *Context) + The [return value] is an iterator that goes over all of the codepoints fed to + [Context] so far. + + These codepoints are tagged with user IDs, segmentation info and more. See + the definition of kbts_shape_codepoint for details. + + !!! WARNING !!! + Remember that segmentation is buffered, so, until you call kbts_ShapeEnd, + some codepoints might not be completely filled in yet! + + Call kbts_ShapeCodepointIteratorNext repeatedly to loop through the + corresponding codepoints. + + :kbts_ShapeCodepointIteratorIsValid + :ShapeCodepointIteratorIsValid + int kbts_ShapeCodepointIteratorIsValid(kbts_shape_codepoint_iterator *It) + The [return value] is non-zero if there is still a codepoint to iterate, + zero if not. + + :kbts_ShapeCodepointIteratorNext + :ShapeCodepointIteratorNext + int kbts_ShapeCodepointIteratorNext(kbts_shape_codepoint_iterator *It, kbts_shape_codepoint *Codepoint, int *CodepointIndex) + Gets the next codepoint from the context [It] was initialized from and writes + it to [Codepoint]. + + If [CodepointIndex] is non-zero, then it is filled with [Codepoint]'s index. + + The [return value] is non-zero if a codepoint was found, 0 if not. + + :kbts_ShapeGetShapeCodepoint + :ShapeGetShapeCodepoint + int kbts_ShapeGetShapeCodepoint(kbts_shape_context *Context, int CodepointIndex, kbts_shape_codepoint *Codepoint) + Gets the [CodepointIndex]th codepoint from [Context] and writes it to + [Codepoint]. + + If you are reading glyphs back from the context, then you can use the + UserIdOrCodepointIndex field of kbts_glyph here. + + !!! WARNING !!! + When using the context API, UserIdOrCodepointIndex will _always_ be a + codepoint index. To get your original user ID, you need to do: + + kbts_shape_codepoint ShapeCodepoint; + kbts_ShapeGetShapeCodepoint(Context, Glyph->UserIdOrCodepointIndex, &ShapeCodepoint); + int MyUserId = ShapeCodepoint.UserId; + + The [return value] is non-zero if [CodepointIndex] is in-bounds, 0 if not. + + CONTEXT:MISCELLANEOUS + :kbts_ShapeError + :ShapeError + kbts_shape_error kbts_ShapeError(kbts_shape_context *Context); + Get the first error that occurred on [Context]. + + Once a context is tagged with an error, most operations on it will do nothing. + Obviously, you can always destroy it. + + :kbts_ShapeManualBreak + :ShapeManualBreak + void kbts_ShapeManualBreak(kbts_shape_context *Context); + Forces a run break at the current position in the Context. + + This will flush the current segmentation state just like an end-of-text would, + and restart it as if it was at a start-of-text. + + This will also generate a KBTS_BREAK_FLAG_MANUAL at the current position. + + You do not need to be in manual break mode for this function to work. + + :kbts_ShapeBeginManualRuns + :ShapeBeginManualRuns + void kbts_ShapeBeginManualRuns(kbts_shape_context *Context); + Disables the context's automatic segmentation, and enters a manual break mode. + + :kbts_ShapeNextManualRun + :ShapeNextManualRun + void kbts_ShapeNextManualRun(kbts_shape_context *Context, kbts_direction Direction, kbts_script Script); + Add a run break at the current place in the input stream. + + Since the context's segmentation is disabled, it cannot know which direction + and script to use, so you need to provide them with [Direction] and [Script]. + + Outside of manual break mode, this function is a no-op. + + :kbts_ShapeEndManualRuns + :ShapeEndManualRuns + void kbts_ShapeEndManualRuns(kbts_shape_context *Context); + Ends manual break mode and re-enables the context's automatic segmentation. + + Note that this will force natural break barriers too, just like an end-of-text + would. + + Outside of manual break mode, this function is a no-op. + + DIRECT SHAPING API + When trying to shape things yourself, there are four main pieces of state you will need: + - Font data (kbts_font) + - A shaping configuration (kbts_shape_config) + A shaping configuration holds a bunch of precomputed data for a given combination of + font, script and language. + You can think of it as a pipeline state in a modern graphics API. + In practice, you are only ever shaping text with a single active configuration. + - Glyph storage (kbts_glyph_storage) + Glyph storage fills two roles: it allocates and holds glyph data, and it also manages + a set of active glyphs. + The active glyph set part is used by the library. As a user, you only need to care + about the memory allocation part. + - Scratch memory + Unfortunately, shaping can have a very unpredictable memory footprint, so all shaping + operations require some amount of scratch space that we cannot compute beforehand. + + The central function to call is this: + + :kbts_ShapeDirect + :ShapeDirect + kbts_shape_error kbts_ShapeDirect(kbts_shape_config *Config, kbts_glyph_storage *Storage, + kbts_direction RunDirection, + kbts_allocator_function *Allocator, void *AllocatorData, + kbts_glyph_iterator *Output) + [RunDirection] is the direction of the specific run being shaped. + If the [return value] is KBTS_SHAPE_ERROR_NONE, then the shaping operation + completed successfully. + + Shaping output is returned in [Output]. You can go through the resulting glyphs + with kbts_GlyphIteratorNext. + + Note that kbts_ShapeDirect does not care about the paragraph direction. + Glyphs are always returned in left-to-right order. In other words, RTL runs + are flipped so that visual order is consistent. + + + :kbts_ShapeDirectFixedMemory + :ShapeDirectFixedMemory + kbts_shape_error kbts_ShapeDirectFixedMemory(kbts_shape_config *Config, kbts_glyph_storage *Storage, + kbts_direction RunDirection, + void *Memory, int Size, + kbts_glyph_iterator *Output) + Same as kbts_ShapeDirect, but only uses the [Size] bytes at [Memory] for allocations. + + The rest of the direct API is more or less about preparing the data you need to call + kbts_ShapeDirect. + + DIRECT:FONT HANDLING + :kbts_FontCount + :FontCount + int kbts_FontCount(void *Data, int Size) + Parses the beginning of the file and returns the number of fonts contained + within the file data. + + While most font files contain single fonts, font collections contain + several. This function will return 0 if [Data] is invalid, 1 if it represents + a single font, and possibly more if it represents a collection. + + For all functions that require a font index, passing 0 is always safe no + matter the kind of file. + + :kbts_FontFromFile + :FontFromFile + kbts_font kbts_FontFromFile(const char *FileName, int FontIndex, + kbts_allocator_function *Allocator, void *AllocatorData, + void **FileData, int *FileSize) + (This function is not available if KB_TEXT_SHAPE_NO_CRT is defined.) + Opens the file at [FileName], parses it and returns the [FontIndex]th font. + You can call kbts_FontIsValid to check if the [return value] is usable. + + If [FileData] is non-zero, it is filled with a pointer to the file's contents. + This pointer is allocated using [Allocator]. If [FileData] is 0, it is freed + before the function returns. + If [FileSize] is non-zero, it is filled with the size of the file's contents. + + If [FontIndex] is out of range, the [return value] is invalid. + + :kbts_FontFromMemory + :FontFromMemory + kbts_font kbts_FontFromMemory(void *FileData, int FileSize, int FontIndex, + kbts_allocator_function *Allocator, void *AllocatorData) + Parses the [FontIndex]th font in [FileData]. + You can call kbts_FontIsValid to check if the [return value] is usable. + + :kbts_FontIsValid + :FontIsValid + int kbts_FontIsValid(kbts_font *Font) + Returns whether a font is usable. + + :kbts_LoadFont + :LoadFont + kbts_load_font_error kbts_LoadFont(kbts_font *Font, kbts_load_font_state *State, + void *FontData, int FontDataSize, int FontIndex, + int *ScratchSize, int *OutputSize) + Parses the [FontIndex]th font in [FontData] and puts the result into [Font] and [State]. + + [State] needs to be zeroed before calling this function. + + If the data represents a TrueType/OpenType font, we need to extract the data + we need and create some additional data structures. In this case, the [return + value] is KBTS_LOAD_FONT_ERROR_NEED_TO_CREATE_BLOB, and [ScratchSize] and + [OutputSize] are filled with the amount of memory we need to create our + blob. You can then initialize this blob with kbts_PlaceBlob. + + If the data represents a kbts blob, then nothing needs to be done, and [Font] is + immediately usable. + + Any value of [FontIndex] less than kbts_FontCount(FontData, FontDataSize) is + acceptable. + + If we could not find any useful font data, the [return value] is + KBTS_LOAD_FONT_ERROR_INVALID_FONT. + + :kbts_PlaceBlob + :PlaceBlob + kbts_load_font_error kbts_PlaceBlob(kbts_font *Font, kbts_load_font_state *State, + void *ScratchMemory, void *OutputMemory) + Creates a kbts blob from font data, and places it in [OutputMemory]. + [Font] is the resulting font. + [State] is the state you passed into kbts_LoadFont. + [ScratchMemory] needs to be as big as the [ScratchSize] returned by kbts_LoadFont. + You can free this buffer once this function returns. + [OutputMemory] needs to be as big as the [OutputSize] returned by kbts_LoadFont. + This buffer will be used by [Font] until it is freed by kbts_FreeFont. + + :kbts_FreeFont + :FreeFont + void kbts_FreeFont(kbts_font *Font) + If [Font] used allocators to allocate its data (for instance, if [Font] was + returned by kbts_FontFromFile), frees all of [Font]'s buffers. + Otherwise, does nothing. + + :kbts_GetFontInfo + :GetFontInfo + void kbts_GetFontInfo(kbts_font *Font, kbts_font_info *Info) + Writes a bunch of useful metadata about [Font] into [Info]. + You can use this function to extract styling, name and licensing information + from a font. + + We use a simplified representation for font weight and width that is fine for + classic font selection, e.g. "I need a bold font". OpenType fonts may feature + finer-grained metrics, and we currently do not expose/support those. + + :kbts_font_style_flags + :font_style_flags + [Info]->StyleFlags can be: + KBTS_FONT_STYLE_FLAG_NONE (no useful style flags have been found) + KBTS_FONT_STYLE_FLAG_REGULAR + KBTS_FONT_STYLE_FLAG_BOLD + KBTS_FONT_STYLE_FLAG_ITALIC + A given font can be bold and italic at the same time, but probably not regular + and bold and probably not regular and italic. + + If [Font] is not a valid font, then [Info] will be zeroed. + + DIRECT:SHAPE CONFIG + :kbts_SizeOfShapeConfig + :SizeOfShapeConfig + int kbts_SizeOfShapeConfig(kbts_font *Font, kbts_script Script, kbts_language Language) + Returns how large the buffer you pass into kbts_PlaceShapeConfig needs to be. + + :kbts_PlaceShapeConfig + :PlaceShapeConfig + kbts_shape_config *kbts_PlaceShapeConfig(kbts_font *Font, kbts_script Script, kbts_language Language, + void *Memory) + Writes a shape config into [Memory] and returns a pointer to it. + [Memory] needs to be at least kbts_SizeOfShapeConfig([Font], [Script], [Language]) bytes. + + :kbts_CreateShapeConfig + :CreateShapeConfig + kbts_shape_config *kbts_CreateShapeConfig(kbts_font *Font, kbts_script Script, kbts_language Language, + kbts_allocator_function *Allocator, void *AllocatorData) + Allocates and initializes a shape config. + + :kbts_DestroyShapeConfig + :DestroyShapeConfig + void kbts_DestroyShapeConfig(kbts_shape_config *Config) + If [Config] was allocated in kbts_CreateShapeConfig, frees all of [Config]'s data. + Otherwise, nothing is done. + + DIRECT:GLYPH STORAGE + kbts_glyph_storage is a public struct: + + :kbts_glyph_storage + :glyph_storage + typedef struct kbts_glyph_storage + { + kbts_arena Arena; + + kbts_glyph GlyphSentinel; + kbts_glyph FreeGlyphSentinel; + } kbts_glyph_storage; + + A zeroed kbts_glyph_storage will auto-initialize itself when you try to use it. + + Arena requires an allocator. By default, it will be initialized to KBTS_MALLOC + and KBTS_FREE. + You can specify your own allocator by writing to Arena.Allocator and + Arena.AllocatorData before trying to use a kbts_glyph_storage. + Alternatively, you can use kbts_InitializeGlyphStorage() to accomplish the + same thing. + + :kbts_InitializeGlyphStorage + :InitializeGlyphStorage + int kbts_InitializeGlyphStorage(kbts_glyph_storage *Storage, kbts_allocator_function *Allocator, void *AllocatorData) + Initializes [Storage] to use [Allocator] and [AllocatorData]. + + This is equivalent to setting [Storage]->Arena.Allocator and + [Storage]->Arena.AllocatorData, and setting all other members to 0. + + The [return value] is non-zero if [Storage] is non-null. + + :kbts_InitializeGlyphStorageFixedMemory + :InitializeGlyphStorageFixedMemory + int kbts_InitializeGlyphStorageFixedMemory(kbts_glyph_storage *Storage, void *Memory, int MemorySize) + Initializes [Storage] to use a fixed-size buffer of size [MemorySize] located at [Memory]. + If [Storage] needs more memory than [MemorySize], allocations will fail. + + The [return value] is non-zero if [Storage] is non-null and [MemorySize] is + large enough to initialize [Storage]'s arena. (Currently, this is 5 pointers' + worth of bytes.) + + :kbts_PushGlyph + :PushGlyph + kbts_glyph *kbts_PushGlyph(kbts_glyph_storage *Storage, + kbts_font *Font, int Codepoint, kbts_glyph_config *Config, int UserId) + Adds a glyph to [Storage]'s active glyph set and returns a pointer to it. + + [Font] is used to initialize the glyph's glyph ID. It is assumed that [Font] is + the same as the kbts_shape_config's Font field passed into kbts_ShapeDirect. + + [Config] is the glyph's configuration and needs to stay live until kbts_ShapeDirect + completes. See DIRECT:GLYPH CONFIG for more details. + + [UserId] is a user-provided unique identifier that you can get back once shaping + is done. + + The [return value] might be zero if [Storage]'s allocator fails. + + :kbts_ClearActiveGlyphs + :ClearActiveGlyphs + void kbts_ClearActiveGlyphs(kbts_glyph_storage *Storage) + Clears [Storage]'s active glyph set. + This does not free any memory; rather, it puts the active glyphs in a free list. + + :kbts_FreeAllGlyphs + :FreeAllGlyphs + void kbts_FreeAllGlyphs(kbts_glyph_storage *Storage) + Frees all memory allocated by [Storage]. + + :kbts_CodepointToGlyph + :CodepointToGlyph + kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, int Codepoint, kbts_glyph_config *Config, int UserId) + You can create glyphs without a glyph storage at all with this function. + + :kbts_CodepointToGlyphId + :CodepointToGlyphId + int kbts_CodepointToGlyphId(kbts_font *Font, int Codepoint) + Gets the glyph ID corresponding to [Codepoint] from [Font]. + A glyph ID of 0 means that the codepoint is not present in the font. + Note that this is not thorough enough to be a good font coverage test! + See OTHER:FONT COVERAGE TEST for this. + + :kbts_ActiveGlyphIterator + :ActiveGlyphIterator + kbts_glyph_iterator kbts_ActiveGlyphIterator(kbts_glyph_storage *Storage) + Returns an iterator to traverse [Storage]'s active glyph set. + + See OTHER:GLYPH ITERATION for more details on glyph iterators. + + DIRECT:GLYPH CONFIG + The shaper figures out most of the work it needs to do based on the writing system + it is shaping. + + However, some fonts support optional, toggleable features, like "make this text + smallcaps". For things like this, you will want to create a kbts_glyph_config. + You can then pass it to glyph creation functions or write it to the Config field + of a kbts_glyph. + + A kbts_glyph_config can hold any number of feature overrides. A feature override + is a feature tag and a value. Most of the time, you only care whether the value + is 0 or 1, but a few features actually care about the exact value. (You can think + of a feature that is like "when I am enabled, change this letter to one of these + alternatives". In that case, the value you provide in the feature override is used + as an index into the array of alternatives.) + + :kbts_SizeOfGlyphConfig + :SizeOfGlyphConfig + int kbts_SizeOfGlyphConfig(kbts_feature_override *Overrides, int OverrideCount) + Returns the buffer size needed to hold a kbts_glyph_config that describes [Overrides]. + This size can vary a lot depending on the kind of feature overrides you specify. + Built-in OpenType features with values of 0 or 1 are "free"; they are packed in a + fixed-size representation which does not change the config's memory footprint. + On the other hand, if you need non-binary values, or non-standard features, then + we need to store a description of the override itself, which requires memory. + + :kbts_PlaceGlyphConfig + :PlaceGlyphConfig + kbts_glyph_config *kbts_PlaceGlyphConfig(kbts_feature_override *Overrides, int OverrideCount, void *Memory) + Writes a kbts_glyph_config that describes [Overrides] into [Memory], and returns a + pointer to it. + The kbts_glyph_config uses its own representation for overrides, so you can modify + [Overrides] once this function returns. + + :kbts_CreateGlyphConfig + :CreateGlyphConfig + kbts_glyph_config *kbts_CreateGlyphConfig(kbts_feature_override *Overrides, int OverrideCount, kbts_allocator_function *Allocator, void *AllocatorData) + Allocates a kbts_glyph_config that describes [Overrides] and returns a pointer to + it. + The kbts_glyph_config uses its own representation for overrides, so you can modify + [Overrides] once this function returns. + + :kbts_DestroyGlyphConfig + :DestroyGlyphConfig + void kbts_DestroyGlyphConfig(kbts_glyph_config *Config) + If [Config] was allocated in kbts_CreateGlyphConfig, frees all of its data. + Otherwise, does nothing. + + DIRECT:SEGMENTATION + kbts_break_state is the central struct used for segmentation. It contains all of the state + needed to perform fixed-memory segmentation of text. + + :kbts_BreakBegin + :BreakBegin + void kbts_BreakBegin(kbts_break_state *State, + kbts_direction ParagraphDirection, + kbts_japanese_line_break_style JapaneseLineBreakStyle, + kbts_break_config_flags ConfigFlags) + Initializes [State] for segmentation. + + [ParagraphDirection] is the top-level flow direction of your document or layout. + If [ParagraphDirection] is KBTS_DIRECTION_DONT_KNOW, then [State]'s + ParagraphDirection will be initialized to the first direction we find + while segmenting. + + :kbts_japanese_line_break_style + :japanese_line_break_style + [JapaneseLineBreakStyle] can be one of the following: + + KBTS_JAPANESE_LINE_BREAK_STYLE_STRICT + KBTS_JAPANESE_LINE_BREAK_STYLE_NORMAL + KBTS_JAPANESE_LINE_BREAK_STYLE_LOOSE + + Japanese text contains "kinsoku" characters, around which breaking a line is + forbidden. Exactly which characters are "kinsoku" or not depends on the context: + + - Strict style has the largest amount of kinsoku characters, which leads to + longer lines. + The Unicode standard does not define what strict style is used for. + Supposedly, it is used for anything that does not fall into the other + two categories of text. + + - Loose style has the smallest amount of kinsoku characters, which leads + to smaller lines. + According to the Unicode standard, loose style is used for newspapers. + I assume it is also used for any other narrow column format. + + - Normal style is somewhere in the middle. + According to the Unicode standard, normal style is used for books and + documents. + + Note that, while the Unicode standard mentions all three of these styles, it + does not mention any differences between the normal and loose styles. As such, + normal and loose styles currently behave the same. + + :kbts_kbts_break_config_flags + :kbts_break_config_flags + [ConfigFlags] can be a combination of the following: + + KBTS_BREAK_CONFIG_FLAG_END_OF_TEXT_GENERATES_HARD_LINE_BREAK + The Unicode standard specifies that the end of a text should generate a + hard line break. However, this is an awkward rule to uphold in practical + contexts, because it makes the case where the text ends in a newline + ambiguous. So, by default, we disable it. + + Without this flag (default behavior): + \n generates a hard line break at position 1 + A generates no hard line break + + With this flag (Unicode behavior): + \n generates a hard line break at position 1 + A generates a hard line break at position 1 + + :kbts_BreakAddCodepoint + :BreakAddCodepoint + void kbts_BreakAddCodepoint(kbts_break_state *State, int Codepoint, int PositionIncrement, int EndOfText) + Feeds [Codepoint] to [State]. + + [PositionIncrement] is used to update an internal cursor and fill out + kbts_break's Position field. If you only care about codepoint indices, pass + 1. Maybe you want to pass in the number of bytes it took to decode the + codepoint, though, to be able to directly index UTF-8 text. + + If [EndOfText] is non-zero, kbts_BreakEnd is called after adding [Codepoint]. + + Every time you call kbts_BreakAddCodepoint, you need to empty the break + buffer by calling kbts_Break repeatedly. + + :kbts_BreakEnd + :BreakEnd + void kbts_BreakEnd(kbts_break_state *State) + Flushes all pending breaks and finishes segmentation. + + You then obtain breaks by repeatedly calling kbts_Break, just as you would + after kbts_BreakAddCodepoint. + + :kbts_Break + :Break + int kbts_Break(kbts_break_state *State, kbts_break *Break) + If any breaks have been found, writes one to [Break] and returns a non-zero + value. If not, returns 0. + + kbts_break looks like this: + + typedef struct kbts_break + { + int Position; + kbts_break_flags Flags; + kbts_direction Direction; // Only valid if (Flags & KBTS_BREAK_FLAG_DIRECTION). + kbts_script Script; // Only valid if (Flags & KBTS_BREAK_FLAG_SCRIPT). + } kbts_break; + + Position is the position of the break, informed by the PositionIncrement + you passed to kbts_BreakAddCodepoint. + + Flags can be any combination of: + KBTS_BREAK_FLAG_DIRECTION + Indicates a change of direction. + + KBTS_BREAK_FLAG_SCRIPT + Indicates a change of script. + + KBTS_BREAK_FLAG_GRAPHEME + Indicates the start of a grapheme. + Unicode describes a grapheme as a visual unit. In practice, you care about + graphemes for font coverage testing and caret positioning. + + The way you do grapheme-aware font coverage testing is you split your text + into graphemes, then, for each grapheme, check if it is supported by your + font. Grapheme boundaries are nice because they group codepoints that may + want to combine together, but it separates codepoints that probably won't + recombine, so they work as an synchronization point for font coverage. + + Caret positioning typically works in graphemes, too. When the user presses + the right arrow, you would go to the next grapheme boundary instead of + naively going to the next codepoint. + + KBTS_BREAK_FLAG_WORD + Indicates the start of a word. + + KBTS_BREAK_FLAG_LINE_SOFT + A soft line break tells you where you are able to break lines. + In Unicode land, you cannot break a line without one of these! + + KBTS_BREAK_FLAG_LINE_HARD + A hard line break should always be respected. + + KBTS_BREAK_FLAG_MANUAL + This is used internally by the kbts_shape_context for manual segmentation. + (See kbts_ShapeBeginManualRuns for more details.) + + !CAREFUL! For a given break type, breaks are guaranteed to be returned in order. + However, there is no such ordering guarantee between different types + of breaks. Each type of break is processed separately, and the + corresponding Unicode algorithms all require some kind of buffering + scheme to work in fixed memory, so, while any given buffer is consistent + with itself, we cannot order multiple buffers together. + + :kbts_BreakEntireString + :BreakEntireString + void kbts_BreakEntireString(kbts_direction ParagraphDirection, + kbts_japanese_line_break_style JapaneseLineBreakStyle, + kbts_break_config_flags ConfigFlags, + void *Input, int InputSizeInBytes, kbts_text_format InputFormat, + kbts_break *Breaks, int BreakCapacity, int *BreakCount, + kbts_break_flags *BreakFlags, int BreakFlagCapacity, int *BreakFlagCount) + Goes through the entire buffer at [Input] and finds all breaks. + [Input] is of type [InputFormat], which can be one of: + KBTS_TEXT_FORMAT_UTF32 + KBTS_TEXT_FORMAT_UTF8 + + Breaks will be written to [Breaks], up to [BreakCapacity]. Regardless of + whether [BreakCapacity] is large enough or not, the amount of breaks found + will be written to [BreakCount]. Unlike kbts_Break, here, [Breaks] are + guaranteed to be ordered. + + [BreakFlags] is a parallel array to the input sequence. If a break is found + at position X, then BreakFlags[X] will be filled with the appropriate flags, + up to [BreakFlagCapacity]. Regardless of whether [BreakFlagCapacity] is large + enough or not, the required capacity is written to [BreakFlagCount]. + + :kbts_BreakEntireStringUtf32 + :BreakEntireStringUtf32 + void kbts_BreakEntireStringUtf32(kbts_direction ParagraphDirection, + kbts_japanese_line_break_style JapaneseLineBreakStyle, + kbts_break_config_flags ConfigFlags, + int *Utf32, int Utf32Count, + kbts_break *Breaks, int BreakCapacity, int *BreakCount, + kbts_break_flags *BreakFlags, int BreakFlagCapacity, int *BreakFlagCount) + Convenience wrapper for kbts_BreakEntireString for UTF-32 text. + + :kbts_BreakEntireStringUtf8 + :BreakEntireStringUtf8 + void kbts_BreakEntireStringUtf8(kbts_direction ParagraphDirection, + kbts_japanese_line_break_style JapaneseLineBreakStyle, + kbts_break_config_flags ConfigFlags, + const char *Utf8, int Utf8Length, + kbts_break *Breaks, int BreakCapacity, int *BreakCount, + kbts_break_flags *BreakFlags, int BreakFlagCapacity, int *BreakFlagCount) + Convenience wrapper for kbts_BreakEntireString for UTF-8 text. + + This wrapper passes the amount of bytes used to decode each codepoint into + kbts_BreakAddCodepoint's PositionIncrement argument. This means that break + positions written to [Breaks] point into the UTF-8 stream. + + :kbts_GuessTextProperties + :GuessTextProperties + void kbts_GuessTextProperties(void *Text, int TextSizeInBytes, kbts_text_format Format, + kbts_direction *Direction, kbts_script *Script) + Goes through the input sequence at [Text], finds the first direction and + script, and writes them to [Direction] and [Script] respectively. + + This is a quick-and-dirty way of finding out simple facts about your text. + However, the results only really make sense when you know [Input] is + mono-script and mono-direction. + + :kbts_GuessTextPropertiesUtf32 + :GuessTextPropertiesUtf32 + void kbts_GuessTextPropertiesUtf32(const int *Utf32, int Utf32Count, + kbts_direction *Direction, kbts_script *Script) + Convenience wrapper for kbts_GuessTextProperties for UTF-32 text. + + :kbts_GuessTextPropertiesUtf8 + :GuessTextPropertiesUtf8 + void kbts_GuessTextPropertiesUtf8(const char *Utf8, int Utf8Length, + kbts_direction *Direction, kbts_script *Script) + Convenience wrapper for kbts_GuessTextProperties for UTF-8 text. + + OTHER APIS + OTHER:GLYPH ITERATION + :kbts_GlyphIteratorNext + :GlyphIteratorNext + int kbts_GlyphIteratorNext(kbts_glyph_iterator *It, kbts_glyph **Glyph) + Writes the next glyph to iterate over in [Glyph]. + + Once shaping is done, the interesting members of a glyph are: + - Id: the glyph index/id in the font. + - UserId: the user ID you passed in when creating the glyph. + This is typically some kind of codepoint index you can use to trace back + the glyph to your source text. + - AdvanceX/Y and OffsetX/Y: positioning data. + Here is how you might use them: + + kbts_glyph *Glyph; + int CursorX = 0, CursorY = 0; + while(kbts_GlyphIteratorNext(&It, &Glyph)) + { + int GlyphX = CursorX + Glyph->OffsetX; + int GlyphY = CursorY + Glyph->OffsetY; + + CursorX += Glyph->AdvanceX; + CursorY += Glyph->AdvanceY; + } + + You cannot assume that [Glyph] will stay valid if you free its glyph storage, + begin another shaping operation using the same glyph storage, or do any kind + of manipulation involving the glyph storage that holds this glyph. Likewise, + you should probably not assume that [Glyph] will stay valid after the next + call to kbts_GlyphIteratorNext. + + The [return value] is 1 if we found a glyph to return, and 0 if we did not. + Once kbts_GlyphIteratorNext has returned 0, you can keep calling it and + it will keep returning 0. + + :kbts_GlyphIteratorIsValid + :GlyphIteratorIsValid + int kbts_GlyphIteratorIsValid(kbts_glyph_iterator *It) + Returns whether there are still glyphs left to iterate over. + + If this returns a non-zero value, then the next call to + kbts_GlyphIteratorNext will also return a non-zero value and write a valid + glyph. + + OTHER:FONT COVERAGE TEST + To implement font fallback, you need to be able to know if a given span of text + is supported by a given font. However, this process is not as simple as it sounds. + Some Unicode codepoints have "canonical decompositions" and "canonical + recompositions" that are meant to describe different ways to represent the same + text, but with different codepoints. At the beginning of the shaping process, + shapers try all combinations until one is found that is fully supported by the + font. A font coverage test does this within a fixed memory footprint. + + :kbts_FontCoverageTestBegin + :FontCoverageTestBegin + void kbts_FontCoverageTestBegin(kbts_font_coverage_test *Test, kbts_font *Font) + Initializes [Test] to test coverage with [Font]. + + :kbts_FontCoverageTestCodepoint + :FontCoverageTestCodepoint + void kbts_FontCoverageTestCodepoint(kbts_font_coverage_test *Test, int Codepoint) + Feeds [Codepoint] into [Test] and updates coverage information. + + :kbts_FontCoverageTestEnd + :FontCoverageTestEnd + int kbts_FontCoverageTestEnd(kbts_font_coverage_test *Test) + Flushes the pending combinations not yet tested by [Test] and ends the coverage + test. + The [return value] is non-zero if the text is fully supported by the font, + whereas it is 0 if any glyph was not supported. + You can also check Test->Error to see if any glyph was unsupported. + + OTHER:OTHER OTHER:MISC + :kbts_DecodeUtf8 + :DecodeUtf8 + kbts_decode kbts_DecodeUtf8(const char *Utf8, kbts_un Length) + Tries to decode a single codepoint from [Utf8]. + kbts_decode looks like this: + + typedef struct kbts_decode + { + int Codepoint; + + int SourceCharactersConsumed; + int Valid; + } kbts_decode; + + Codepoint is the decoded codepoint. + SourceCharactersConsumed is the amount of bytes that were read from [Utf8]. + If decoding was successful, Valid is non-zero. Otherwise, it is zero. + Valid is zero if we run out of characters, or if the characters in [Utf8] + are invalid. + + :kbts_EncodeUtf8 + :EncodeUtf8 + kbts_encode_utf8 kbts_EncodeUtf8(int Codepoint) + Tries to encode a single codepoint into a UTF-8 sequence of bytes. + kbts_encode looks like this: + + typedef struct kbts_encode_utf8 + { + char Encoded[4]; + int EncodedLength; + int Valid; + } kbts_encode_utf8; + + Encoded is the encoded sequence. + EncodedLength is the number of bytes needed to encode [Codepoint]. + Valid is whether or not [Codepoint] is a valid codepoint to encode. + (All codepoints up to 0x10FFFF inclusive can be encoded.) + When Valid is 0, EncodedLength is also 0. + + :kbts_ScriptDirection + :ScriptDirection + kbts_direction kbts_ScriptDirection(kbts_script Script) + Returns the default direction for a given script. + + :kbts_ScriptIsComplex + :ScriptIsComplex + int kbts_ScriptIsComplex(kbts_script Script) + Returns whether a script is complex, i.e. if it requires complex shaper + support. + + :kbts_ScriptTagToScript + :ScriptTagToScript + kbts_script kbts_ScriptTagToScript(kbts_script_tag Tag) + Returns a given script from a four-character tag. + A kbts_script_tag can be obtained either through the KBTS_SCRIPT_TAG_* + constants, or through the KBTS_FOURCC() macro, which creates a tag from + four characters. LANGUAGE SUPPORT Shaping is NOT supported for the following scripts: @@ -317,7 +1219,6 @@ Word breaking is NOT supported for languages that require word dictionaries, like CJK. FONT SUPPORT - Font collections (.ttc) are not supported. Indic fonts using the Indic1 shaping model are not supported. e.g., 'bng2' will work, but 'beng' will not. The Indic v2 shaping model was released with OpenType 1.5 in May 2008. @@ -344,6 +1245,19 @@ See https://unicode.org/reports/tr9 for more information. VERSION HISTORY + 2.05 - Fix custom allocator initialization for kbts_shape_context.PermanentArena. + 2.04 - Fix Indic syllable logic for small/single-character syllables. + Fix wrong indirection in pointer code in Indic syllable logic. + 2.03 - Fix loading blobs directly, fix a parsing edge case in GPOS format 2 subtables. + 2.02 - Improve globbing of cursive attachments. + 2.01 - Add kbts_InitializeGlyphStorage and kbts_ScriptDirection. + Rename some private functions for better namespacing. + Delete some deprecated functions. + Bounds check in kbts_ScriptIsComplex. + Fix a couple pointer iteration bugs. + Fix some pedantic MSVC warnings. + Extend mirroring logic from brackets to any codepoint that has a Unicode mirror. + 2.0 - Completely new API and implementation. 1.03 - New functions: kbts_FeatureTagToId(), kbts_FeatureOverrideFromTag(), kbts_EmptyGlyphConfig(), kbts_GlyphConfigOverrideFeature(), kbts_GlyphConfigOverrideFeatureFromTag(), kbts_ScriptTagToScript() Unregistered features can now be overriden using their tags. This is slower than overriding registered features, i.e. those that have a kbts_feature_id. @@ -359,8 +1273,6 @@ TODO Word dictionaries for word breaking: CJK, etc. 'stch' feature. - Precompute GPOS nesting in advance and replace recursion with explicit frames. - (Either that or limit to a hard depth for now.) LICENSE zlib License @@ -384,7 +1296,6 @@ 3. This notice may not be removed or altered from any source distribution. */ - #ifndef KB_TEXT_SHAPE_INCLUDED # define KB_TEXT_SHAPE_INCLUDED @@ -462,6 +1373,7 @@ # ifdef _MSC_VER # define KBTS_INLINE static __forceinline # define KBTS_NOINLINE static __declspec(noinline) +# define KBTS_ALIGNOF __alignof # else # ifdef __has_attribute # if __has_attribute(always_inline) @@ -471,6 +1383,7 @@ # define KBTS_NOINLINE static __attribute__((noinline)) # endif # endif +# define KBTS_ALIGNOF __alignof__ # endif # ifndef KBTS_INLINE # define KBTS_INLINE static inline @@ -478,75 +1391,6 @@ # define KBTS_FOURCC(A, B, C, D) ((A) | ((B) << 8) | ((C) << 16) | ((D) << 24)) -typedef kbts_u8 kbts_joining_feature; -enum kbts_joining_feature_enum -{ - KBTS_JOINING_FEATURE_NONE, - - // These must correspond with glyph_flags and FEATURE_IDs. - KBTS_JOINING_FEATURE_ISOL, - KBTS_JOINING_FEATURE_FINA, - KBTS_JOINING_FEATURE_FIN2, - KBTS_JOINING_FEATURE_FIN3, - KBTS_JOINING_FEATURE_MEDI, - KBTS_JOINING_FEATURE_MED2, - KBTS_JOINING_FEATURE_INIT, - - KBTS_JOINING_FEATURE_COUNT, -}; - -typedef kbts_u8 kbts_reph_position; -enum kbts_reph_position_enum -{ - KBTS_REPH_POSITION_AFTER_POST, - KBTS_REPH_POSITION_BEFORE_POST, - KBTS_REPH_POSITION_BEFORE_SUBJOINED, - KBTS_REPH_POSITION_AFTER_SUBJOINED, - KBTS_REPH_POSITION_AFTER_MAIN, - - KBTS_REPH_POSITION_COUNT, -}; - -typedef kbts_u8 kbts_reph_encoding; -enum kbts_reph_encoding_enum -{ - KBTS_REPH_ENCODING_IMPLICIT, - KBTS_REPH_ENCODING_EXPLICIT, - KBTS_REPH_ENCODING_LOGICAL_REPHA, - KBTS_REPH_ENCODING_VISUAL_REPHA, - - KBTS_REPH_ENCODING_COUNT, -}; - -typedef kbts_u8 kbts_syllabic_position; -enum kbts_syllabic_position_enum -{ - KBTS_SYLLABIC_POSITION_NONE, - - KBTS_SYLLABIC_POSITION_RA_TO_BECOME_REPH, - - KBTS_SYLLABIC_POSITION_PREBASE_MATRA, - KBTS_SYLLABIC_POSITION_PREBASE_CONSONANT, - - KBTS_SYLLABIC_POSITION_SYLLABLE_BASE, - KBTS_SYLLABIC_POSITION_AFTER_MAIN, - - KBTS_SYLLABIC_POSITION_ABOVEBASE_CONSONANT, - - KBTS_SYLLABIC_POSITION_BEFORE_SUBJOINED, - KBTS_SYLLABIC_POSITION_BELOWBASE_CONSONANT, - KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED, - - KBTS_SYLLABIC_POSITION_BEFORE_POST, - KBTS_SYLLABIC_POSITION_POSTBASE_CONSONANT, - KBTS_SYLLABIC_POSITION_AFTER_POST, - - KBTS_SYLLABIC_POSITION_FINAL_CONSONANT, - KBTS_SYLLABIC_POSITION_SMVD, - - KBTS_SYLLABIC_POSITION_COUNT, -}; - typedef kbts_u32 kbts_language; enum kbts_language_enum { @@ -1262,32 +2106,205 @@ enum kbts_break_flags_enum // (In Unicode, there is no meaningful distinction between a line and a paragraph. // a paragraph is pretty much just a line of text that can wrap.) KBTS_BREAK_FLAG_LINE_HARD = 1 << 5, + // Used for manual segmentation in the context. + KBTS_BREAK_FLAG_MANUAL = 1 << 6, + + KBTS_BREAK_FLAG_PARAGRAPH_DIRECTION = 1 << 7, KBTS_BREAK_FLAG_LINE = KBTS_BREAK_FLAG_LINE_SOFT | KBTS_BREAK_FLAG_LINE_HARD, KBTS_BREAK_FLAG_ANY = KBTS_BREAK_FLAG_DIRECTION | KBTS_BREAK_FLAG_SCRIPT | KBTS_BREAK_FLAG_GRAPHEME | KBTS_BREAK_FLAG_WORD | KBTS_BREAK_FLAG_LINE_SOFT | KBTS_BREAK_FLAG_LINE_HARD, }; -typedef kbts_u8 kbts_op_kind; -enum kbts_op_kind_enum +// Japanese text contains "kinsoku" characters, around which breaking a line is forbidden. +// Exactly which characters are "kinsoku" or not depends on the context: +// - Strict style has the largest amount of kinsoku characters, which leads to longer lines. +// - Loose style has the smallest amount of kinsoku characters, which leads to smaller lines. +// - Normal style is somewhere in the middle. +// Note that, while the Unicode standard mentions all three of these styles, it does not mention +// any differences between the normal and loose styles. +// As such, normal and loose styles currently behave the same. +typedef kbts_u8 kbts_japanese_line_break_style; +enum kbts_japanese_line_break_style_enum { - KBTS_OP_KIND_END, + // The Unicode standard does not define what strict style is used for. + // Supposedly, it is used for anything that does not fall into the other two categories of text. + KBTS_JAPANESE_LINE_BREAK_STYLE_STRICT, - // Substitution ops. - KBTS_OP_KIND_PRE_NORMALIZE_DOTTED_CIRCLES, - KBTS_OP_KIND_NORMALIZE, - KBTS_OP_KIND_NORMALIZE_HANGUL, - KBTS_OP_KIND_FLAG_JOINING_LETTERS, - KBTS_OP_KIND_GSUB_FEATURES, - KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, + // Normal style is used for books and documents. + KBTS_JAPANESE_LINE_BREAK_STYLE_NORMAL, - // Positioning ops. - KBTS_OP_KIND_GPOS_METRICS, - KBTS_OP_KIND_GPOS_FEATURES, + // Loose style is used for newspapers, and (I assume) any other narrow column format. + KBTS_JAPANESE_LINE_BREAK_STYLE_LOOSE, - KBTS_OP_KIND_POST_GPOS_FIXUP, - KBTS_OP_KIND_STCH_POSTPASS, + KBTS_JAPANESE_LINE_BREAK_STYLE_COUNT, +}; - KBTS_OP_KIND_COUNT, +typedef kbts_u32 kbts_break_state_flags; +enum kbts_break_state_flags_enum +{ + KBTS_BREAK_STATE_FLAG_STARTED = 1, + KBTS_BREAK_STATE_FLAG_END = 2, + + // Bidirectional flags + KBTS_BREAK_STATE_FLAG_SAW_R_AFTER_L = 8, + KBTS_BREAK_STATE_FLAG_SAW_AL_AFTER_LR = 0x10, + KBTS_BREAK_STATE_FLAG_LAST_WAS_BRACKET = 0x20, +}; + +typedef kbts_u32 kbts_text_format; +enum kbts_text_format_enum +{ + KBTS_TEXT_FORMAT_NONE, + + KBTS_TEXT_FORMAT_UTF32, + KBTS_TEXT_FORMAT_UTF8, + + KBTS_TEXT_FORMAT_COUNT, +}; + +typedef kbts_u32 kbts_direction; +enum kbts_direction_enum +{ + KBTS_DIRECTION_DONT_KNOW, + KBTS_DIRECTION_LTR, + KBTS_DIRECTION_RTL, + + KBTS_DIRECTION_COUNT, +}; + +typedef kbts_u32 kbts_orientation; +enum kbts_orientation_enum +{ + KBTS_ORIENTATION_HORIZONTAL, + KBTS_ORIENTATION_VERTICAL, + + KBTS_ORIENTATION_COUNT, +}; + +typedef kbts_u8 kbts_shaping_table; +enum kbts_shaping_table_enum +{ + KBTS_SHAPING_TABLE_GSUB, + KBTS_SHAPING_TABLE_GPOS, + KBTS_SHAPING_TABLE_COUNT, +}; + +typedef kbts_u32 kbts_shape_error; +enum kbts_shape_error_enum +{ + KBTS_SHAPE_ERROR_NONE, + KBTS_SHAPE_ERROR_INVALID_FONT, + KBTS_SHAPE_ERROR_GAVE_TEXT_BEFORE_CALLING_BEGIN, + KBTS_SHAPE_ERROR_OUT_OF_MEMORY, + + KBTS_SHAPE_ERROR_COUNT, +}; + +typedef kbts_u32 kbts_allocator_op_kind; +enum kbts_allocator_op_kind_enum +{ + KBTS_ALLOCATOR_OP_KIND_NONE, + KBTS_ALLOCATOR_OP_KIND_ALLOCATE, + KBTS_ALLOCATOR_OP_KIND_FREE, + + KBTS_ALLOCATOR_OP_KIND_COUNT, +}; + +typedef kbts_u32 kbts_blob_table_id; +enum kbts_blob_table_id_enum +{ + KBTS_BLOB_TABLE_ID_NONE, + KBTS_BLOB_TABLE_ID_HEAD, + KBTS_BLOB_TABLE_ID_CMAP, + KBTS_BLOB_TABLE_ID_GDEF, + KBTS_BLOB_TABLE_ID_GSUB, + KBTS_BLOB_TABLE_ID_GPOS, + KBTS_BLOB_TABLE_ID_HHEA, + KBTS_BLOB_TABLE_ID_VHEA, + KBTS_BLOB_TABLE_ID_HMTX, + KBTS_BLOB_TABLE_ID_VMTX, + KBTS_BLOB_TABLE_ID_MAXP, + KBTS_BLOB_TABLE_ID_OS2, + KBTS_BLOB_TABLE_ID_NAME, + + KBTS_BLOB_TABLE_ID_COUNT, +}; + +typedef kbts_u32 kbts_load_font_error; +enum kbts_load_font_error_enum +{ + KBTS_LOAD_FONT_ERROR_NONE, + KBTS_LOAD_FONT_ERROR_NEED_TO_CREATE_BLOB, + KBTS_LOAD_FONT_ERROR_INVALID_FONT, + KBTS_LOAD_FONT_ERROR_OUT_OF_MEMORY, + KBTS_LOAD_FONT_ERROR_COULD_NOT_OPEN_FILE, + KBTS_LOAD_FONT_ERROR_READ_ERROR, + + KBTS_LOAD_FONT_ERROR_COUNT, +}; + +typedef kbts_u32 kbts_version; +enum kbts_version_enum +{ + KBTS_VERSION_1_X, + KBTS_VERSION_2_0, + + KBTS_VERSION_CURRENT = KBTS_VERSION_2_0, +}; + +typedef kbts_u32 kbts_blob_version; +enum kbts_blob_version_enum +{ + KBTS_BLOB_VERSION_INVALID, + KBTS_BLOB_VERSION_INITIAL, + + KBTS_BLOB_VERSION_CURRENT = KBTS_BLOB_VERSION_INITIAL, +}; + +typedef kbts_u32 kbts_font_style_flags; +enum kbts_font_style_flags_enum +{ + KBTS_FONT_STYLE_FLAG_NONE, + + KBTS_FONT_STYLE_FLAG_REGULAR = (1 << 0), + KBTS_FONT_STYLE_FLAG_ITALIC = (1 << 1), + KBTS_FONT_STYLE_FLAG_BOLD = (1 << 2), +}; + +typedef kbts_u32 kbts_font_weight; +enum kbts_font_weight_enum +{ + KBTS_FONT_WEIGHT_UNKNOWN, + + KBTS_FONT_WEIGHT_THIN, + KBTS_FONT_WEIGHT_EXTRA_LIGHT, + KBTS_FONT_WEIGHT_LIGHT, + KBTS_FONT_WEIGHT_NORMAL, + KBTS_FONT_WEIGHT_MEDIUM, + KBTS_FONT_WEIGHT_SEMI_BOLD, + KBTS_FONT_WEIGHT_BOLD, + KBTS_FONT_WEIGHT_EXTRA_BOLD, + KBTS_FONT_WEIGHT_BLACK, + + KBTS_FONT_WEIGHT_COUNT, +}; + +typedef kbts_u32 kbts_font_width; +enum kbts_font_width_enum +{ + KBTS_FONT_WIDTH_UNKNOWN, + + KBTS_FONT_WIDTH_ULTRA_CONDENSED, + KBTS_FONT_WIDTH_EXTRA_CONDENSED, + KBTS_FONT_WIDTH_CONDENSED, + KBTS_FONT_WIDTH_SEMI_CONDENSED, + KBTS_FONT_WIDTH_NORMAL, + KBTS_FONT_WIDTH_SEMI_EXPANDED, + KBTS_FONT_WIDTH_EXPANDED, + KBTS_FONT_WIDTH_EXTRA_EXPANDED, + KBTS_FONT_WIDTH_ULTRA_EXPANDED, + + KBTS_FONT_WIDTH_COUNT, }; typedef kbts_u32 kbts_glyph_flags; @@ -1331,60 +2348,62 @@ enum kbts_glyph_flags_enum KBTS_GLYPH_FLAG_LIGATURE = (1 << 29), KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION = (1 << 30), }; -#define KBTS_GLYPH_FEATURE_MASK ((KBTS_GLYPH_FLAG_CFAR << 1) - 1) -// In USE, glyphs are mostly not pre-flagged for feature application. -// However, we do want to flag rphf/pref results for reordering, so we want to -// keep all of the flags as usual, and only use these feature flags for filtering. -#define KBTS_USE_GLYPH_FEATURE_MASK (KBTS_GLYPH_FLAG_ISOL | KBTS_GLYPH_FLAG_FINA | KBTS_GLYPH_FLAG_FIN2 | KBTS_GLYPH_FLAG_FIN3 | \ - KBTS_GLYPH_FLAG_MEDI | KBTS_GLYPH_FLAG_MED2 | KBTS_GLYPH_FLAG_INIT | KBTS_GLYPH_FLAG_NUMR | \ - KBTS_GLYPH_FLAG_DNOM | KBTS_GLYPH_FLAG_FRAC) -#define KBTS_JOINING_FEATURE_MASK (KBTS_GLYPH_FLAG_ISOL | KBTS_GLYPH_FLAG_FINA | KBTS_GLYPH_FLAG_FIN2 | KBTS_GLYPH_FLAG_FIN3 | \ - KBTS_GLYPH_FLAG_MEDI | KBTS_GLYPH_FLAG_MED2 | KBTS_GLYPH_FLAG_INIT) -#define KBTS_JOINING_FEATURE_TO_GLYPH_FLAG(Feature) (1 << ((Feature) - 1)) -// Japanese text contains "kinsoku" characters, around which breaking a line is forbidden. -// Exactly which characters are "kinsoku" or not depends on the context: -// - Strict style has the largest amount of kinsoku characters, which leads to longer lines. -// - Loose style has the smallest amount of kinsoku characters, which leads to smaller lines. -// - Normal style is somewhere in the middle. -// Note that, while the Unicode standard mentions all three of these styles, it does not mention -// any differences between the normal and loose styles. -// As such, normal and loose styles currently behave the same. -typedef kbts_u8 kbts_japanese_line_break_style; -enum kbts_japanese_line_break_style_enum +typedef kbts_u8 kbts_joining_feature; +enum kbts_joining_feature_enum { - // The Unicode standard does not define what strict style is used for. - // Supposedly, it is used for anything that does not fall into the other two categories of text. - KBTS_JAPANESE_LINE_BREAK_STYLE_STRICT, + KBTS_JOINING_FEATURE_NONE, - // Normal style is used for books and documents. - KBTS_JAPANESE_LINE_BREAK_STYLE_NORMAL, + // These must correspond with glyph_flags and FEATURE_IDs. + KBTS_JOINING_FEATURE_ISOL, + KBTS_JOINING_FEATURE_FINA, + KBTS_JOINING_FEATURE_FIN2, + KBTS_JOINING_FEATURE_FIN3, + KBTS_JOINING_FEATURE_MEDI, + KBTS_JOINING_FEATURE_MED2, + KBTS_JOINING_FEATURE_INIT, - // Loose style is used for newspapers, and (I assume) any other narrow column format. - KBTS_JAPANESE_LINE_BREAK_STYLE_LOOSE, - - KBTS_JAPANESE_LINE_BREAK_STYLE_COUNT, + KBTS_JOINING_FEATURE_COUNT, }; -typedef kbts_u32 kbts_orientation; -enum kbts_orientation_enum +typedef kbts_u32 kbts_user_id_generation_mode; +enum kbts_user_id_generation_mode_enum { - KBTS_ORIENTATION_HORIZONTAL, - KBTS_ORIENTATION_VERTICAL, + KBTS_USER_ID_GENERATION_MODE_CODEPOINT_INDEX, + KBTS_USER_ID_GENERATION_MODE_SOURCE_INDEX, - KBTS_ORIENTATION_COUNT, + KBTS_USER_ID_GENERATION_MODE_COUNT, }; -typedef kbts_u32 kbts_direction; -enum kbts_direction_enum +typedef kbts_u32 kbts_break_config_flags; +enum kbts_break_config_flags_enum { - KBTS_DIRECTION_NONE, - KBTS_DIRECTION_LTR, - KBTS_DIRECTION_RTL, + KBTS_BREAK_CONFIG_FLAG_NONE, - KBTS_DIRECTION_COUNT, + KBTS_BREAK_CONFIG_FLAG_END_OF_TEXT_GENERATES_HARD_LINE_BREAK = 1, }; +typedef kbts_u32 kbts_font_info_string_id; +enum kbts_font_info_string_id_enum +{ + KBTS_FONT_INFO_STRING_ID_NONE, + KBTS_FONT_INFO_STRING_ID_COPYRIGHT, + KBTS_FONT_INFO_STRING_ID_FAMILY, + KBTS_FONT_INFO_STRING_ID_SUBFAMILY, + KBTS_FONT_INFO_STRING_ID_UID, + KBTS_FONT_INFO_STRING_ID_FULL_NAME, + KBTS_FONT_INFO_STRING_ID_VERSION, + KBTS_FONT_INFO_STRING_ID_POSTSCRIPT_NAME, + KBTS_FONT_INFO_STRING_ID_TRADEMARK, + KBTS_FONT_INFO_STRING_ID_MANUFACTURER, + KBTS_FONT_INFO_STRING_ID_DESIGNER, + KBTS_FONT_INFO_STRING_ID_TYPOGRAPHIC_FAMILY, + KBTS_FONT_INFO_STRING_ID_TYPOGRAPHIC_SUBFAMILY, + + KBTS_FONT_INFO_STRING_ID_COUNT, +}; + + typedef kbts_u8 kbts_unicode_joining_type; enum kbts_unicode_joining_type_enum { @@ -1407,12 +2426,15 @@ enum kbts_unicode_flag_enum KBTS_UNICODE_FLAG_PART_OF_WORD = (1 << 4), KBTS_UNICODE_FLAG_DECIMAL_DIGIT = (1 << 5), KBTS_UNICODE_FLAG_NON_SPACING_MARK = (1 << 6), + + KBTS_UNICODE_FLAG_MIRRORED = KBTS_UNICODE_FLAG_OPEN_BRACKET | KBTS_UNICODE_FLAG_CLOSE_BRACKET, }; typedef kbts_u8 kbts_unicode_bidirectional_class; enum kbts_unicode_bidirectional_class_enum { KBTS_UNICODE_BIDIRECTIONAL_CLASS_NI, + KBTS_UNICODE_BIDIRECTIONAL_CLASS_BN, // Formatting characters need to be ignored. KBTS_UNICODE_BIDIRECTIONAL_CLASS_L, KBTS_UNICODE_BIDIRECTIONAL_CLASS_R, KBTS_UNICODE_BIDIRECTIONAL_CLASS_NSM, @@ -1567,6 +2589,8 @@ enum kbts_shaper_enum KBTS_SHAPER_COUNT, }; +#define KBTS_MAXIMUM_RECOMPOSITION_PARENTS 19 +#define KBTS_MAXIMUM_CODEPOINT_SCRIPTS 23 typedef kbts_u32 kbts_script_tag; enum kbts_script_tag_enum { @@ -2168,624 +3192,166 @@ enum kbts_feature_tag_enum KBTS_FEATURE_TAG_zero = KBTS_FOURCC('z', 'e', 'r', 'o'), // Slashed Zero }; -typedef kbts_u32 kbts_feature_id; -enum kbts_feature_id_enum -{ - KBTS_FEATURE_ID_UNREGISTERED, // Features that aren't pre-defined in the OpenType spec - KBTS_FEATURE_ID_isol, // Isolated Forms - KBTS_FEATURE_ID_fina, // Terminal Forms - KBTS_FEATURE_ID_fin2, // Terminal Forms #2 - KBTS_FEATURE_ID_fin3, // Terminal Forms #3 - KBTS_FEATURE_ID_medi, // Medial Forms - KBTS_FEATURE_ID_med2, // Medial Forms #2 - KBTS_FEATURE_ID_init, // Initial Forms - KBTS_FEATURE_ID_ljmo, // Leading Jamo Forms - KBTS_FEATURE_ID_vjmo, // Vowel Jamo Forms - KBTS_FEATURE_ID_tjmo, // Trailing Jamo Forms - KBTS_FEATURE_ID_rphf, // Reph Form - KBTS_FEATURE_ID_blwf, // Below-base Forms - KBTS_FEATURE_ID_half, // Half Forms - KBTS_FEATURE_ID_pstf, // Post-base Forms - KBTS_FEATURE_ID_abvf, // Above-base Forms - KBTS_FEATURE_ID_pref, // Pre-base Forms - KBTS_FEATURE_ID_numr, // Numerators - KBTS_FEATURE_ID_frac, // Fractions - KBTS_FEATURE_ID_dnom, // Denominators - KBTS_FEATURE_ID_cfar, // Conjunct Form After Ro - KBTS_FEATURE_ID_aalt, // Access All Alternates - KBTS_FEATURE_ID_abvm, // Above-base Mark Positioning - KBTS_FEATURE_ID_abvs, // Above-base Substitutions - KBTS_FEATURE_ID_afrc, // Alternative Fractions - KBTS_FEATURE_ID_akhn, // Akhand - KBTS_FEATURE_ID_apkn, // Kerning for Alternate Proportional Widths - KBTS_FEATURE_ID_blwm, // Below-base Mark Positioning - KBTS_FEATURE_ID_blws, // Below-base Substitutions - KBTS_FEATURE_ID_calt, // Contextual Alternates - KBTS_FEATURE_ID_case, // Case-sensitive Forms - KBTS_FEATURE_ID_ccmp, // Glyph Composition / Decomposition - KBTS_FEATURE_ID_chws, // Contextual Half-width Spacing - KBTS_FEATURE_ID_cjct, // Conjunct Forms - KBTS_FEATURE_ID_clig, // Contextual Ligatures - KBTS_FEATURE_ID_cpct, // Centered CJK Punctuation - KBTS_FEATURE_ID_cpsp, // Capital Spacing - KBTS_FEATURE_ID_cswh, // Contextual Swash - KBTS_FEATURE_ID_curs, // Cursive Positioning - KBTS_FEATURE_ID_cv01, // Character Variant 1 - KBTS_FEATURE_ID_cv02, // Character Variant 2 - KBTS_FEATURE_ID_cv03, // Character Variant 3 - KBTS_FEATURE_ID_cv04, // Character Variant 4 - KBTS_FEATURE_ID_cv05, // Character Variant 5 - KBTS_FEATURE_ID_cv06, // Character Variant 6 - KBTS_FEATURE_ID_cv07, // Character Variant 7 - KBTS_FEATURE_ID_cv08, // Character Variant 8 - KBTS_FEATURE_ID_cv09, // Character Variant 9 - KBTS_FEATURE_ID_cv10, // Character Variant 10 - KBTS_FEATURE_ID_cv11, // Character Variant 11 - KBTS_FEATURE_ID_cv12, // Character Variant 12 - KBTS_FEATURE_ID_cv13, // Character Variant 13 - KBTS_FEATURE_ID_cv14, // Character Variant 14 - KBTS_FEATURE_ID_cv15, // Character Variant 15 - KBTS_FEATURE_ID_cv16, // Character Variant 16 - KBTS_FEATURE_ID_cv17, // Character Variant 17 - KBTS_FEATURE_ID_cv18, // Character Variant 18 - KBTS_FEATURE_ID_cv19, // Character Variant 19 - KBTS_FEATURE_ID_cv20, // Character Variant 20 - KBTS_FEATURE_ID_cv21, // Character Variant 21 - KBTS_FEATURE_ID_cv22, // Character Variant 22 - KBTS_FEATURE_ID_cv23, // Character Variant 23 - KBTS_FEATURE_ID_cv24, // Character Variant 24 - KBTS_FEATURE_ID_cv25, // Character Variant 25 - KBTS_FEATURE_ID_cv26, // Character Variant 26 - KBTS_FEATURE_ID_cv27, // Character Variant 27 - KBTS_FEATURE_ID_cv28, // Character Variant 28 - KBTS_FEATURE_ID_cv29, // Character Variant 29 - KBTS_FEATURE_ID_cv30, // Character Variant 30 - KBTS_FEATURE_ID_cv31, // Character Variant 31 - KBTS_FEATURE_ID_cv32, // Character Variant 32 - KBTS_FEATURE_ID_cv33, // Character Variant 33 - KBTS_FEATURE_ID_cv34, // Character Variant 34 - KBTS_FEATURE_ID_cv35, // Character Variant 35 - KBTS_FEATURE_ID_cv36, // Character Variant 36 - KBTS_FEATURE_ID_cv37, // Character Variant 37 - KBTS_FEATURE_ID_cv38, // Character Variant 38 - KBTS_FEATURE_ID_cv39, // Character Variant 39 - KBTS_FEATURE_ID_cv40, // Character Variant 40 - KBTS_FEATURE_ID_cv41, // Character Variant 41 - KBTS_FEATURE_ID_cv42, // Character Variant 42 - KBTS_FEATURE_ID_cv43, // Character Variant 43 - KBTS_FEATURE_ID_cv44, // Character Variant 44 - KBTS_FEATURE_ID_cv45, // Character Variant 45 - KBTS_FEATURE_ID_cv46, // Character Variant 46 - KBTS_FEATURE_ID_cv47, // Character Variant 47 - KBTS_FEATURE_ID_cv48, // Character Variant 48 - KBTS_FEATURE_ID_cv49, // Character Variant 49 - KBTS_FEATURE_ID_cv50, // Character Variant 50 - KBTS_FEATURE_ID_cv51, // Character Variant 51 - KBTS_FEATURE_ID_cv52, // Character Variant 52 - KBTS_FEATURE_ID_cv53, // Character Variant 53 - KBTS_FEATURE_ID_cv54, // Character Variant 54 - KBTS_FEATURE_ID_cv55, // Character Variant 55 - KBTS_FEATURE_ID_cv56, // Character Variant 56 - KBTS_FEATURE_ID_cv57, // Character Variant 57 - KBTS_FEATURE_ID_cv58, // Character Variant 58 - KBTS_FEATURE_ID_cv59, // Character Variant 59 - KBTS_FEATURE_ID_cv60, // Character Variant 60 - KBTS_FEATURE_ID_cv61, // Character Variant 61 - KBTS_FEATURE_ID_cv62, // Character Variant 62 - KBTS_FEATURE_ID_cv63, // Character Variant 63 - KBTS_FEATURE_ID_cv64, // Character Variant 64 - KBTS_FEATURE_ID_cv65, // Character Variant 65 - KBTS_FEATURE_ID_cv66, // Character Variant 66 - KBTS_FEATURE_ID_cv67, // Character Variant 67 - KBTS_FEATURE_ID_cv68, // Character Variant 68 - KBTS_FEATURE_ID_cv69, // Character Variant 69 - KBTS_FEATURE_ID_cv70, // Character Variant 70 - KBTS_FEATURE_ID_cv71, // Character Variant 71 - KBTS_FEATURE_ID_cv72, // Character Variant 72 - KBTS_FEATURE_ID_cv73, // Character Variant 73 - KBTS_FEATURE_ID_cv74, // Character Variant 74 - KBTS_FEATURE_ID_cv75, // Character Variant 75 - KBTS_FEATURE_ID_cv76, // Character Variant 76 - KBTS_FEATURE_ID_cv77, // Character Variant 77 - KBTS_FEATURE_ID_cv78, // Character Variant 78 - KBTS_FEATURE_ID_cv79, // Character Variant 79 - KBTS_FEATURE_ID_cv80, // Character Variant 80 - KBTS_FEATURE_ID_cv81, // Character Variant 81 - KBTS_FEATURE_ID_cv82, // Character Variant 82 - KBTS_FEATURE_ID_cv83, // Character Variant 83 - KBTS_FEATURE_ID_cv84, // Character Variant 84 - KBTS_FEATURE_ID_cv85, // Character Variant 85 - KBTS_FEATURE_ID_cv86, // Character Variant 86 - KBTS_FEATURE_ID_cv87, // Character Variant 87 - KBTS_FEATURE_ID_cv88, // Character Variant 88 - KBTS_FEATURE_ID_cv89, // Character Variant 89 - KBTS_FEATURE_ID_cv90, // Character Variant 90 - KBTS_FEATURE_ID_cv91, // Character Variant 91 - KBTS_FEATURE_ID_cv92, // Character Variant 92 - KBTS_FEATURE_ID_cv93, // Character Variant 93 - KBTS_FEATURE_ID_cv94, // Character Variant 94 - KBTS_FEATURE_ID_cv95, // Character Variant 95 - KBTS_FEATURE_ID_cv96, // Character Variant 96 - KBTS_FEATURE_ID_cv97, // Character Variant 97 - KBTS_FEATURE_ID_cv98, // Character Variant 98 - KBTS_FEATURE_ID_cv99, // Character Variant 99 - KBTS_FEATURE_ID_c2pc, // Petite Capitals From Capitals - KBTS_FEATURE_ID_c2sc, // Small Capitals From Capitals - KBTS_FEATURE_ID_dist, // Distances - KBTS_FEATURE_ID_dlig, // Discretionary Ligatures - KBTS_FEATURE_ID_dtls, // Dotless Forms - KBTS_FEATURE_ID_expt, // Expert Forms - KBTS_FEATURE_ID_falt, // Final Glyph on Line Alternates - KBTS_FEATURE_ID_flac, // Flattened Accent Forms - KBTS_FEATURE_ID_fwid, // Full Widths - KBTS_FEATURE_ID_haln, // Halant Forms - KBTS_FEATURE_ID_halt, // Alternate Half Widths - KBTS_FEATURE_ID_hist, // Historical Forms - KBTS_FEATURE_ID_hkna, // Horizontal Kana Alternates - KBTS_FEATURE_ID_hlig, // Historical Ligatures - KBTS_FEATURE_ID_hngl, // Hangul - KBTS_FEATURE_ID_hojo, // Hojo Kanji Forms (JIS X 0212-1990 Kanji Forms) - KBTS_FEATURE_ID_hwid, // Half Widths - KBTS_FEATURE_ID_ital, // Italics - KBTS_FEATURE_ID_jalt, // Justification Alternates - KBTS_FEATURE_ID_jp78, // JIS78 Forms - KBTS_FEATURE_ID_jp83, // JIS83 Forms - KBTS_FEATURE_ID_jp90, // JIS90 Forms - KBTS_FEATURE_ID_jp04, // JIS2004 Forms - KBTS_FEATURE_ID_kern, // Kerning - KBTS_FEATURE_ID_lfbd, // Left Bounds - KBTS_FEATURE_ID_liga, // Standard Ligatures - KBTS_FEATURE_ID_lnum, // Lining Figures - KBTS_FEATURE_ID_locl, // Localized Forms - KBTS_FEATURE_ID_ltra, // Left-to-right Alternates - KBTS_FEATURE_ID_ltrm, // Left-to-right Mirrored Forms - KBTS_FEATURE_ID_mark, // Mark Positioning - KBTS_FEATURE_ID_mgrk, // Mathematical Greek - KBTS_FEATURE_ID_mkmk, // Mark to Mark Positioning - KBTS_FEATURE_ID_mset, // Mark Positioning via Substitution - KBTS_FEATURE_ID_nalt, // Alternate Annotation Forms - KBTS_FEATURE_ID_nlck, // NLC Kanji Forms - KBTS_FEATURE_ID_nukt, // Nukta Forms - KBTS_FEATURE_ID_onum, // Oldstyle Figures - KBTS_FEATURE_ID_opbd, // Optical Bounds - KBTS_FEATURE_ID_ordn, // Ordinals - KBTS_FEATURE_ID_ornm, // Ornaments - KBTS_FEATURE_ID_palt, // Proportional Alternate Widths - KBTS_FEATURE_ID_pcap, // Petite Capitals - KBTS_FEATURE_ID_pkna, // Proportional Kana - KBTS_FEATURE_ID_pnum, // Proportional Figures - KBTS_FEATURE_ID_pres, // Pre-base Substitutions - KBTS_FEATURE_ID_psts, // Post-base Substitutions - KBTS_FEATURE_ID_pwid, // Proportional Widths - KBTS_FEATURE_ID_qwid, // Quarter Widths - KBTS_FEATURE_ID_rand, // Randomize - KBTS_FEATURE_ID_rclt, // Required Contextual Alternates - KBTS_FEATURE_ID_rkrf, // Rakar Forms - KBTS_FEATURE_ID_rlig, // Required Ligatures - KBTS_FEATURE_ID_rtbd, // Right Bounds - KBTS_FEATURE_ID_rtla, // Right-to-left Alternates - KBTS_FEATURE_ID_rtlm, // Right-to-left Mirrored Forms - KBTS_FEATURE_ID_ruby, // Ruby Notation Forms - KBTS_FEATURE_ID_rvrn, // Required Variation Alternates - KBTS_FEATURE_ID_salt, // Stylistic Alternates - KBTS_FEATURE_ID_sinf, // Scientific Inferiors - KBTS_FEATURE_ID_size, // Optical size - KBTS_FEATURE_ID_smcp, // Small Capitals - KBTS_FEATURE_ID_smpl, // Simplified Forms - KBTS_FEATURE_ID_ss01, // Stylistic Set 1 - KBTS_FEATURE_ID_ss02, // Stylistic Set 2 - KBTS_FEATURE_ID_ss03, // Stylistic Set 3 - KBTS_FEATURE_ID_ss04, // Stylistic Set 4 - KBTS_FEATURE_ID_ss05, // Stylistic Set 5 - KBTS_FEATURE_ID_ss06, // Stylistic Set 6 - KBTS_FEATURE_ID_ss07, // Stylistic Set 7 - KBTS_FEATURE_ID_ss08, // Stylistic Set 8 - KBTS_FEATURE_ID_ss09, // Stylistic Set 9 - KBTS_FEATURE_ID_ss10, // Stylistic Set 10 - KBTS_FEATURE_ID_ss11, // Stylistic Set 11 - KBTS_FEATURE_ID_ss12, // Stylistic Set 12 - KBTS_FEATURE_ID_ss13, // Stylistic Set 13 - KBTS_FEATURE_ID_ss14, // Stylistic Set 14 - KBTS_FEATURE_ID_ss15, // Stylistic Set 15 - KBTS_FEATURE_ID_ss16, // Stylistic Set 16 - KBTS_FEATURE_ID_ss17, // Stylistic Set 17 - KBTS_FEATURE_ID_ss18, // Stylistic Set 18 - KBTS_FEATURE_ID_ss19, // Stylistic Set 19 - KBTS_FEATURE_ID_ss20, // Stylistic Set 20 - KBTS_FEATURE_ID_ssty, // Math Script-style Alternates - KBTS_FEATURE_ID_stch, // Stretching Glyph Decomposition - KBTS_FEATURE_ID_subs, // Subscript - KBTS_FEATURE_ID_sups, // Superscript - KBTS_FEATURE_ID_swsh, // Swash - KBTS_FEATURE_ID_test, // Test features, only for development - KBTS_FEATURE_ID_titl, // Titling - KBTS_FEATURE_ID_tnam, // Traditional Name Forms - KBTS_FEATURE_ID_tnum, // Tabular Figures - KBTS_FEATURE_ID_trad, // Traditional Forms - KBTS_FEATURE_ID_twid, // Third Widths - KBTS_FEATURE_ID_unic, // Unicase - KBTS_FEATURE_ID_valt, // Alternate Vertical Metrics - KBTS_FEATURE_ID_vapk, // Kerning for Alternate Proportional Vertical Metrics - KBTS_FEATURE_ID_vatu, // Vattu Variants - KBTS_FEATURE_ID_vchw, // Vertical Contextual Half-width Spacing - KBTS_FEATURE_ID_vert, // Vertical Alternates - KBTS_FEATURE_ID_vhal, // Alternate Vertical Half Metrics - KBTS_FEATURE_ID_vkna, // Vertical Kana Alternates - KBTS_FEATURE_ID_vkrn, // Vertical Kerning - KBTS_FEATURE_ID_vpal, // Proportional Alternate Vertical Metrics - KBTS_FEATURE_ID_vrt2, // Vertical Alternates and Rotation - KBTS_FEATURE_ID_vrtr, // Vertical Alternates for Rotation - KBTS_FEATURE_ID_zero, // Slashed Zero - KBTS_FEATURE_ID_COUNT, -}; - -typedef kbts_u8 kbts_shaping_table; -enum kbts_shaping_table_enum -{ - KBTS_SHAPING_TABLE_GSUB, - KBTS_SHAPING_TABLE_GPOS, - KBTS_SHAPING_TABLE_COUNT, -}; - -typedef struct kbts_lookup_info -{ - kbts_u32 MaximumBacktrackWithoutSkippingGlyphs; - kbts_u32 MaximumLookaheadWithoutSkippingGlyphs; - kbts_u32 MaximumSubstitutionOutputSize; - kbts_u32 MaximumInputSequenceLength; - kbts_u32 MaximumLookupStackSize; -} kbts_lookup_info; - -typedef struct kbts_op_state kbts_op_state; -typedef struct kbts_gdef kbts_gdef; -typedef struct kbts_cmap_14 kbts_cmap_14; -typedef struct kbts_gsub_gpos kbts_gsub_gpos; -typedef struct kbts_maxp kbts_maxp; -typedef struct kbts_hea kbts_hea; -typedef struct kbts_iterate_features kbts_iterate_features; -typedef struct kbts_shape_state kbts_shape_state; +typedef struct kbts__gdef kbts__gdef; +typedef struct kbts__cmap_14 kbts__cmap_14; +typedef struct kbts__gsub_gpos kbts__gsub_gpos; +typedef struct kbts__maxp kbts__maxp; +typedef struct kbts__hea kbts__hea; typedef struct kbts_shaper_properties kbts_shaper_properties; -typedef struct kbts_feature kbts_feature; -typedef struct kbts_head kbts_head; +typedef struct kbts__feature kbts__feature; +typedef struct kbts__head kbts__head; +typedef struct kbts__langsys kbts__langsys; +typedef struct kbts_shape_config kbts_shape_config; +typedef struct kbts_glyph kbts_glyph; +typedef struct kbts_glyph_config kbts_glyph_config; +typedef struct kbts_shape_context kbts_shape_context; +typedef struct kbts_glyph_storage kbts_glyph_storage; + +typedef struct kbts_allocator_op_allocate +{ + void *Pointer; + kbts_u32 Size; +} kbts_allocator_op_allocate; + +typedef struct kbts_allocator_op_free +{ + void *Pointer; +} kbts_allocator_op_free; + +typedef struct kbts_allocator_op +{ + kbts_allocator_op_kind Kind; + + union + { + kbts_allocator_op_allocate Allocate; + kbts_allocator_op_free Free; + }; +} kbts_allocator_op; + +typedef void kbts_allocator_function(void *Data, kbts_allocator_op *Op); typedef struct kbts_lookup_subtable_info { - kbts_u32 MinimumBacktrackPlusOne; - kbts_u32 MinimumFollowupPlusOne; + kbts_u16 MinimumBacktrackPlusOne; + kbts_u16 MinimumFollowupPlusOne; } kbts_lookup_subtable_info; +typedef struct kbts_blob_table +{ + kbts_u32 OffsetFromStartOfFile; + kbts_u32 Length; +} kbts_blob_table; + +typedef struct kbts_load_font_state +{ + void *FontData; + kbts_u32 FontDataSize; + + kbts_blob_table Tables[KBTS_BLOB_TABLE_ID_COUNT]; + kbts_u32 LookupCount; + kbts_u32 LookupSubtableCount; + kbts_u32 GlyphCount; + kbts_u32 ScratchSize; + + kbts_u32 GlyphLookupMatrixSizeInBytes; + kbts_u32 GlyphLookupSubtableMatrixSizeInBytes; + kbts_u32 TotalSize; +} kbts_load_font_state; + +typedef struct kbts_blob_header +{ + kbts_u32 Magic; + kbts_u32 Version; + + kbts_u32 LookupCount; + kbts_u32 LookupSubtableCount; + kbts_u32 GlyphCount; + + kbts_u32 GposLookupIndexOffset; + + kbts_u32 GlyphLookupMatrixOffsetFromStartOfFile; + kbts_u32 GlyphLookupSubtableMatrixOffsetFromStartOfFile; + kbts_u32 LookupSubtableIndexOffsetsOffsetFromStartOfFile; + kbts_u32 SubtableInfosOffsetFromStartOfFile; + + kbts_blob_table Tables[KBTS_BLOB_TABLE_ID_COUNT]; +} kbts_blob_header; + typedef struct kbts_font { - char *FileBase; - kbts_un FileSize; - kbts_head *Head; + kbts_allocator_function *Allocator; + void *AllocatorData; + + kbts_blob_header *Blob; kbts_u16 *Cmap; - kbts_gdef *Gdef; - kbts_cmap_14 *Cmap14; - kbts_gsub_gpos *ShapingTables[KBTS_SHAPING_TABLE_COUNT]; - void *Fvar; - kbts_maxp *Maxp; + kbts__cmap_14 *Cmap14; - kbts_hea *Hea[KBTS_ORIENTATION_COUNT]; - kbts_u16 *Mtx[KBTS_ORIENTATION_COUNT]; + kbts__gsub_gpos *ShapingTables[KBTS_SHAPING_TABLE_COUNT]; - kbts_lookup_info LookupInfo; + void *UserData; - kbts_u32 GlyphCount; - kbts_u32 LookupCount; - kbts_u32 SubtableCount; - - kbts_u32 *GlyphLookupMatrix; // [LookupCount * GlyphCount] bitmap - kbts_u32 *GlyphLookupSubtableMatrix; // [LookupSubtableCount * GlyphCount] bitmap - kbts_u32 *LookupSubtableIndexOffsets; // [LookupCount] - kbts_lookup_subtable_info *SubtableInfos; // [LookupSubtableCount] - kbts_u32 GposLookupIndexOffset; - - int Error; + kbts_load_font_error Error; } kbts_font; -typedef struct kbts_glyph_classes +typedef struct kbts_font_info { - kbts_u16 Class; - kbts_u16 MarkAttachmentClass; -} kbts_glyph_classes; + char *Strings[KBTS_FONT_INFO_STRING_ID_COUNT]; + kbts_u16 StringLengths[KBTS_FONT_INFO_STRING_ID_COUNT]; -typedef struct kbts_feature_set -{ - kbts_u64 Flags[(KBTS_FEATURE_ID_COUNT + 63) / 64]; -} kbts_feature_set; + kbts_font_style_flags StyleFlags; + kbts_font_weight Weight; + kbts_font_width Width; +} kbts_font_info; typedef struct kbts_feature_override { - kbts_feature_id Id; kbts_feature_tag Tag; - kbts_u32 EnabledOrAlternatePlusOne; + int Value; } kbts_feature_override; -typedef struct kbts_glyph_config -{ - kbts_feature_set EnabledFeatures; - kbts_feature_set DisabledFeatures; - kbts_u32 FeatureOverrideCount; - kbts_u32 FeatureOverrideCapacity; - kbts_u32 RequiredFeatureOverrideCapacity; - kbts_feature_override *FeatureOverrides; // [FeatureOverrideCount] -} kbts_glyph_config; - -typedef struct kbts_glyph -{ - kbts_u32 Codepoint; - kbts_u16 Id; // Glyph index. This is what you want to use to query outline data. - kbts_u16 Uid; - kbts_glyph_classes Classes; - - kbts_u64 Decomposition; - - kbts_glyph_config *Config; - - kbts_glyph_flags Flags; - - // These fields are the glyph's final positioning data. - // For normal usage, you should not have to use these directly yourself. - // In case you are curious or have a specific need, see kbts_PositionGlyph() to see how these are used. - kbts_s32 OffsetX; - kbts_s32 OffsetY; - kbts_s32 AdvanceX; - kbts_s32 AdvanceY; - - kbts_u32 ParentInfo; - - // This is set by GSUB and used by GPOS. - // A 0-index means that we should attach to the last component in the ligature. - // - // From the Microsoft docs: - // To correctly access the subtables, the client must keep track of the component associated with the mark. - // - // For a given mark assigned to a particular class, the appropriate base attachment point is determined by which - // ligature component the mark is associated with. This is dependent on the original character string and subsequent - // character- or glyph-sequence processing, not the font data alone. While a text-layout client is performing any - // character-based preprocessing or any glyph-substitution operations using the GSUB table, the text-layout client - // must keep track of associations of marks to particular ligature-glyph components. - kbts_u16 LigatureUid; - kbts_u16 LigatureComponentIndexPlusOne; - - // Earlier on, we used to assume that, if a glyph had no advance, or had the MARK glyph class, then - // it could be handled as a mark in layout operations. This is inaccurate. - // Unicode makes a distinction between attached marks and standalone marks. For our purposes, attached - // marks are marks that have found a valid base character to attach to. In practice, this means that the - // font contains a valid display position/configuration for it in the current context. - // In contrast, standalone marks are marks that aren't attached to anything. Fonts may still have glyphs - // for them, in which case we want to display those just like regular glyphs that take up horizontal space - // on the line. When fonts don't have glyphs for them, they simply stay around as zero-width glyphs. - // Standalone marks have notably different behavior compared to attached marks, and so, once we start - // applying positioning features, it becomes worthwhile to track exactly which glyph has attached to which. - kbts_u16 AttachGlyphIndexPlusOne; // Set by GPOS attachments. - - // Set in GSUB and used in GPOS, for STCH. - kbts_joining_feature JoiningFeature; - - // Unicode properties filled in by CodepointToGlyph. - kbts_unicode_joining_type JoiningType; - kbts_u8 Script; - kbts_u8 UnicodeFlags; - kbts_u8 SyllabicClass; - kbts_u8 SyllabicPosition; - kbts_u8 UseClass; - kbts_u8 CombiningClass; - - kbts_u8 MarkOrdering; // Only used temporarily in NORMALIZE for Arabic mark reordering. -} kbts_glyph; - -typedef struct kbts_glyph_array -{ - kbts_glyph *Glyphs; - kbts_u32 Count; - kbts_u32 TotalCount; - kbts_u32 Capacity; - kbts_u32 RequiredCapacity; -} kbts_glyph_array; - -typedef struct kbts_op_state_normalize -{ - kbts_un CodepointsToDecomposeCount; - kbts_un AboveBaseGlyphCount; -} kbts_op_state_normalize; - -typedef struct kbts_op_state_gsub -{ - kbts_feature_set LookupFeatures; - kbts_un LookupIndex; - kbts_u32 GlyphFilter; - kbts_u32 SkipFlags; -} kbts_op_state_gsub; - -typedef struct kbts_op_state_normalize_hangul -{ - kbts_glyph LvtGlyphs[4]; - kbts_un LvtGlyphCount; -} kbts_op_state_normalize_hangul; - -typedef union kbts_op_state_op_specific -{ - kbts_op_state_normalize Normalize; - kbts_op_state_gsub Gsub; - kbts_op_state_normalize_hangul NormalizeHangul; -} kbts_op_state_op_specific; - -typedef struct kbts_lookup_indices -{ - kbts_u32 FeatureTag; - kbts_u32 FeatureId; - kbts_u32 SkipFlags; - kbts_u32 GlyphFilter; - kbts_u32 Count; - kbts_u16 *Indices; -} kbts_lookup_indices; - -typedef struct kbts_op -{ - kbts_op_kind Kind; - kbts_feature_set Features; -} kbts_op; - -// This needs to be updated when we change the op lists! -#define KBTS_MAX_SIMULTANEOUS_FEATURES 16 -typedef struct kbts_op_state -{ - kbts_un WrittenCount; - kbts_un GlyphIndex; - kbts_u32 FrameCount; - kbts_u32 ResumePoint; - - kbts_u32 FeatureCount; - kbts_lookup_indices FeatureLookupIndices[KBTS_MAX_SIMULTANEOUS_FEATURES]; - kbts_u32 UnregisteredFeatureCount; - kbts_feature_tag UnregisteredFeatureTags[KBTS_MAX_SIMULTANEOUS_FEATURES]; - - kbts_op_state_op_specific OpSpecific; - - // Ops are free to use the following as they please: - // kbts_u8 LeftoverMemory[LeftoverMemorySize]; -} kbts_op_state; - -typedef struct kbts_op_list -{ - kbts_u8 *Ops; - kbts_un Length; -} kbts_op_list; - -typedef struct kbts_indic_script_properties -{ - kbts_u32 ViramaCodepoint; - kbts_u8 BlwfPostOnly; - kbts_reph_position RephPosition; - kbts_reph_encoding RephEncoding; - kbts_syllabic_position RightSideMatraPosition; - kbts_syllabic_position AboveBaseMatraPosition; - kbts_syllabic_position BelowBaseMatraPosition; -} kbts_indic_script_properties; - -typedef struct kbts_langsys kbts_langsys; -typedef struct kbts_shape_config -{ - kbts_font *Font; - kbts_script Script; - kbts_language Language; - kbts_langsys *Langsys[KBTS_SHAPING_TABLE_COUNT]; - kbts_op_list OpLists[4]; - - kbts_feature_set *Features; - - kbts_shaper Shaper; - kbts_shaper_properties *ShaperProperties; - - kbts_indic_script_properties IndicScriptProperties; - kbts_feature *Blwf; - kbts_feature *Pref; - kbts_feature *Pstf; - kbts_feature *Locl; - kbts_feature *Rphf; - kbts_feature *Half; - kbts_feature *Vatu; - - // Indic - kbts_glyph Virama; - - kbts_glyph DottedCircle; - kbts_glyph Whitespace; - - // Thai - kbts_glyph Nikhahit; - kbts_glyph SaraAa; -} kbts_shape_config; - -typedef struct kbts_shape_state -{ - kbts_op Op; - kbts_shape_config *Config; - kbts_direction MainDirection; - kbts_direction RunDirection; - - kbts_feature_set UserFeatures; - - kbts_glyph_array GlyphArray; - kbts_glyph_array ClusterGlyphArray; - - kbts_u32 DottedCircleInsertIndex; - - kbts_u32 GlyphCountStartingFromCurrentCluster; - - kbts_u32 At; - kbts_u32 ResumePoint; - kbts_u32 OpGlyphOffset; - kbts_u32 ClusterGlyphCount; - kbts_u32 Ip; - kbts_u32 NextGlyphUid; - - kbts_u32 RequiredGlyphCapacity; - - int RealCluster; - int ClusterAtStartOfWord; - int WordBreak; - - // This must always be the last member! - kbts_op_state OpState; -} kbts_shape_state; - -typedef struct kbts_cursor -{ - kbts_direction Direction; - kbts_s32 LastAdvanceX; - kbts_s32 X; - kbts_s32 Y; -} kbts_cursor; - typedef struct kbts_break { // The break code mostly works in relative positions, but we convert to absolute positions for the user. // That way, breaks can be trivially stored and compared and such and it just works. - kbts_u32 Position; + int Position; kbts_break_flags Flags; kbts_direction Direction; // Only valid if (Flags & KBTS_BREAK_FLAG_DIRECTION). + kbts_direction ParagraphDirection; // Only valid if (Flags & KBTS_BREAK_FLAG_PARAGRAPH_DIRECTION). kbts_script Script; // Only valid if (Flags & KBTS_BREAK_FLAG_SCRIPT). } kbts_break; typedef struct kbts_bracket { kbts_u32 Codepoint; + kbts_u32 Position; kbts_u8 Direction; kbts_u8 Script; } kbts_bracket; -typedef kbts_u32 kbts_break_state_flags; -enum kbts_break_state_flags_enum -{ - KBTS_BREAK_STATE_FLAG_STARTED = 1, - KBTS_BREAK_STATE_FLAG_END = 2, - KBTS_BREAK_STATE_FLAG_RAN_OUT_OF_REORDER_BUFFER_SPACE = 4, - - // Bidirectional flags - KBTS_BREAK_STATE_FLAG_SAW_R_AFTER_L = 8, - KBTS_BREAK_STATE_FLAG_SAW_AL_AFTER_LR = 0x10, - KBTS_BREAK_STATE_FLAG_LAST_WAS_BRACKET = 0x20, -}; - // In the worst case, a single call to BreakAddCodepoint would generate 4 breaks. // We buffer breaks to reorder them before returning them to the user. // This potentially requires infinite memory, which we don't have, so you may want to tweak this constant, // although, really, if the defaults don't work, then you have likely found very strange/adversarial text. -#define KBTS_BREAK_REORDER_BUFFER_FLUSH_THRESHOLD 4 -#define KBTS_BREAK_REORDER_BUFFER_SIZE (KBTS_BREAK_REORDER_BUFFER_FLUSH_THRESHOLD * 2) typedef struct kbts_break_state { - kbts_break Breaks[KBTS_BREAK_REORDER_BUFFER_SIZE]; + kbts_break Breaks[8]; kbts_u32 BreakCount; - kbts_direction MainDirection; - kbts_u32 LastFlushedBreakPosition; + kbts_direction ParagraphDirection; + kbts_direction UserParagraphDirection; + kbts_u32 CurrentPosition; + kbts_u32 ParagraphStartPosition; - kbts_u8 LastScripts[2]; + kbts_u32 LastScriptBreakPosition; + kbts_u32 LastDirectionBreakPosition; + kbts_u8 LastScriptBreakScript; + kbts_u8 LastDirectionBreakDirection; + + kbts_s16 ScriptPositionOffset; + kbts_u32 ScriptCount; + kbts_u8 ScriptSet[KBTS_MAXIMUM_CODEPOINT_SCRIPTS]; kbts_bracket Brackets[64]; kbts_u32 BracketCount; @@ -2813,8 +3379,11 @@ typedef struct kbts_break_state kbts_u8 LastDirection; kbts_u8 BidirectionalClass2; kbts_u8 BidirectionalClass1; + kbts_s16 Bidirectional1PositionOffset; + kbts_s16 Bidirectional2PositionOffset; kbts_japanese_line_break_style JapaneseLineBreakStyle; + kbts_break_config_flags ConfigFlags; kbts_u8 GraphemeBreakState; kbts_u8 LastLineBreakClass; kbts_u8 LastWordBreakClass; @@ -2823,84 +3392,352 @@ typedef struct kbts_break_state typedef struct kbts_decode { - kbts_u32 Codepoint; + int Codepoint; - kbts_u32 SourceCharactersConsumed; - kbts_u32 Valid; + int SourceCharactersConsumed; + int Valid; } kbts_decode; +typedef struct kbts_encode_utf8 +{ + char Encoded[4]; + int EncodedLength; + int Valid; +} kbts_encode_utf8; + +typedef struct kbts_glyph_classes +{ + kbts_u16 Class; + kbts_u16 MarkAttachmentClass; +} kbts_glyph_classes; + +typedef struct kbts_glyph +{ + kbts_glyph *Prev; + kbts_glyph *Next; + + kbts_u32 Codepoint; + kbts_u16 Id; // Glyph index. This is what you want to use to query outline data. + kbts_u16 Uid; + + // This field is kept and returned as-is throughout the shaping process. + // When you are using the context API, it contains a codepoint index always! + // To get the original user ID with the context API, you need to get the corresponding kbts_shape_codepoint + // with kbts_ShapeGetShapeCodepoint(Context, Glyph->UserIdOrCodepointIndex, ...); + int UserIdOrCodepointIndex; + + // Used by GPOS + kbts_s32 OffsetX; + kbts_s32 OffsetY; + kbts_s32 AdvanceX; + kbts_s32 AdvanceY; + + // Earlier on, we used to assume that, if a glyph had no advance, or had the MARK glyph class, then + // it could be handled as a mark in layout operations. This is inaccurate. + // Unicode makes a distinction between attached marks and standalone marks. For our purposes, attached + // marks are marks that have found a valid base character to attach to. In practice, this means that the + // font contains a valid display position/configuration for it in the current context. + // In contrast, standalone marks are marks that aren't attached to anything. Fonts may still have glyphs + // for them, in which case we want to display those just like regular glyphs that take up horizontal space + // on the line. When fonts don't have glyphs for them, they simply stay around as zero-width glyphs. + // Standalone marks have notably different behavior compared to attached marks, and so, once we start + // applying positioning features, it becomes worthwhile to track exactly which glyph has attached to which. + struct kbts_glyph *AttachGlyph; // Set by GPOS attachments. + + kbts_glyph_config *Config; + + kbts_u64 Decomposition; + + kbts_glyph_classes Classes; + + kbts_glyph_flags Flags; + + kbts_u32 ParentInfo; + + // This is set by GSUB and used by GPOS. + // A 0-index means that we should attach to the last component in the ligature. + // + // From the Microsoft docs: + // To correctly access the subtables, the client must keep track of the component associated with the mark. + // + // For a given mark assigned to a particular class, the appropriate base attachment point is determined by which + // ligature component the mark is associated with. This is dependent on the original character string and subsequent + // character- or glyph-sequence processing, not the font data alone. While a text-layout client is performing any + // character-based preprocessing or any glyph-substitution operations using the GSUB table, the text-layout client + // must keep track of associations of marks to particular ligature-glyph components. + kbts_u16 LigatureUid; + kbts_u16 LigatureComponentIndexPlusOne; + kbts_u16 LigatureComponentCount; + + // Set in GSUB and used in GPOS, for STCH. + kbts_joining_feature JoiningFeature; + + // Unicode properties filled in by CodepointToGlyph. + kbts_unicode_joining_type JoiningType; + kbts_u8 UnicodeFlags; + kbts_u8 SyllabicClass; + kbts_u8 SyllabicPosition; + kbts_u8 UseClass; + kbts_u8 CombiningClass; + + kbts_u8 MarkOrdering; // Only used temporarily in NORMALIZE for Arabic mark reordering. +} kbts_glyph; + +typedef struct kbts_shape_codepoint +{ + kbts_font *Font; // Only set when (BreakFlags & KBTS_BREAK_FLAG_GRAPHEME) != 0. + kbts_glyph_config *Config; + + int Codepoint; + int UserId; + + kbts_break_flags BreakFlags; + kbts_script Script; // Only set when (BreakFlags & KBTS_BREAK_FLAG_SCRIPT) != 0. + kbts_direction Direction; // Only set when (BreakFlags & KBTS_BREAK_FLAG_DIRECTION) != 0. + kbts_direction ParagraphDirection; // Only set when (BreakFlags & KBTS_BREAK_FLAG_PARAGRAPH_DIRECTION) != 0. +} kbts_shape_codepoint; + +typedef struct kbts_shape_codepoint_iterator +{ + kbts_shape_codepoint *Codepoint; + kbts_shape_context *Context; + + kbts_u32 EndBlockIndex; + kbts_u32 OnePastLastCodepointIndex; + kbts_u32 BlockIndex; + kbts_u32 CodepointIndex; + kbts_u32 CurrentBlockCodepointCount; + kbts_u32 FlatCodepointIndex; +} kbts_shape_codepoint_iterator; + +typedef struct kbts_glyph_iterator +{ + kbts_glyph_storage *GlyphStorage; + kbts_glyph *CurrentGlyph; + + int LastAdvanceX; + int X; + int Y; +} kbts_glyph_iterator; + +typedef struct kbts_arena_block_header +{ + struct kbts_arena_block_header *Prev; + struct kbts_arena_block_header *Next; +} kbts_arena_block_header; + +typedef struct kbts_arena +{ + kbts_allocator_function *Allocator; + void *AllocatorData; + + kbts_arena_block_header BlockSentinel; + kbts_arena_block_header FreeBlockSentinel; + + int Error; +} kbts_arena; + +typedef struct kbts_glyph_storage +{ + kbts_arena Arena; + + kbts_glyph GlyphSentinel; + kbts_glyph FreeGlyphSentinel; + + int Error; +} kbts_glyph_storage; + +typedef struct kbts_glyph_parent +{ + kbts_u64 Decomposition; + kbts_u32 Codepoint; +} kbts_glyph_parent; + +typedef struct kbts_font_coverage_test +{ + kbts_font *Font; + kbts_u32 BaseCodepoint; + + int CurrentBaseError; + int Error; + + kbts_glyph_parent BaseParents[KBTS_MAXIMUM_RECOMPOSITION_PARENTS]; + kbts_u32 BaseParentCount; +} kbts_font_coverage_test; + +typedef struct kbts_run +{ + kbts_font *Font; + kbts_script Script; + kbts_direction ParagraphDirection; + kbts_direction Direction; + kbts_break_flags Flags; + + kbts_glyph_iterator Glyphs; +} kbts_run; + +// +// Context API +// The context can do everything for you. It is pretty convenient! +// + +KBTS_EXPORT int kbts_SizeOfShapeContext(void); +KBTS_EXPORT kbts_shape_context *kbts_PlaceShapeContext(kbts_allocator_function *Allocator, void *AllocatorData, void *Memory); +KBTS_EXPORT kbts_shape_context *kbts_PlaceShapeContextFixedMemory(void *Memory, int Size); +KBTS_EXPORT kbts_shape_context *kbts_CreateShapeContext(kbts_allocator_function *Allocator, void *AllocatorData); +KBTS_EXPORT void kbts_DestroyShapeContext(kbts_shape_context *Context); #ifndef KB_TEXT_SHAPE_NO_CRT -KBTS_EXPORT kbts_font kbts_FontFromFile(const char *FileName); -KBTS_EXPORT void kbts_FreeFont(kbts_font *Font); -KBTS_EXPORT kbts_shape_state *kbts_CreateShapeState(kbts_font *Font); -KBTS_EXPORT void kbts_FreeShapeState(kbts_shape_state *State); +KBTS_EXPORT kbts_font *kbts_ShapePushFontFromFile(kbts_shape_context *Context, const char *FileName, int FontIndex); #endif -KBTS_EXPORT kbts_feature_id kbts_FeatureTagToId(kbts_feature_tag Tag); -KBTS_EXPORT kbts_feature_override kbts_FeatureOverride(kbts_feature_id Id, int Alternate, kbts_u32 Value); -KBTS_EXPORT kbts_feature_override kbts_FeatureOverrideFromTag(kbts_feature_tag Tag, int Alternate, kbts_u32 Value); -KBTS_EXPORT kbts_glyph_config kbts_GlyphConfig(kbts_feature_override *FeatureOverrides, kbts_u32 FeatureOverrideCount); -KBTS_EXPORT kbts_glyph_config kbts_EmptyGlyphConfig(kbts_feature_override *FeatureOverrides, kbts_u32 FeatureOverrideCapacity); -KBTS_EXPORT int kbts_GlyphConfigOverrideFeature(kbts_glyph_config *Config, kbts_feature_id Id, int Alternate, kbts_u32 Value); -KBTS_EXPORT int kbts_GlyphConfigOverrideFeatureFromTag(kbts_glyph_config *Config, kbts_feature_tag Tag, int Alternate, kbts_u32 Value); +KBTS_EXPORT kbts_font *kbts_ShapePushFontFromMemory(kbts_shape_context *Context, void *Memory, int Size, int FontIndex); +KBTS_EXPORT kbts_font *kbts_ShapePushFont(kbts_shape_context *Context, kbts_font *Font); +KBTS_EXPORT kbts_font *kbts_ShapePopFont(kbts_shape_context *Context); +KBTS_EXPORT void kbts_ShapeBegin(kbts_shape_context *Context, kbts_direction ParagraphDirection, kbts_language Language); +KBTS_EXPORT void kbts_ShapeEnd(kbts_shape_context *Context); +KBTS_EXPORT int kbts_ShapeRun(kbts_shape_context *Context, kbts_run *Run); +KBTS_EXPORT void kbts_ShapePushFeature(kbts_shape_context *Context, kbts_u32 FeatureTag, int Value); +KBTS_EXPORT int kbts_ShapePopFeature(kbts_shape_context *Context, kbts_u32 FeatureTag); +KBTS_EXPORT void kbts_ShapeCodepoint(kbts_shape_context *Context, int Codepoint); +KBTS_EXPORT void kbts_ShapeCodepointWithUserId(kbts_shape_context *Context, int Codepoint, int UserId); +KBTS_EXPORT void kbts_ShapeUtf32(kbts_shape_context *Context, int *Utf32, int Length); +KBTS_EXPORT void kbts_ShapeUtf32WithUserId(kbts_shape_context *Context, int *Utf32, int Length, int UserId, int UserIdIncrement); +KBTS_EXPORT void kbts_ShapeUtf8(kbts_shape_context *Context, const char *Utf8, int Length, kbts_user_id_generation_mode UserIdGenerationMode); +KBTS_EXPORT void kbts_ShapeUtf8WithUserId(kbts_shape_context *Context, const char *Utf8, int Length, int UserId, kbts_user_id_generation_mode UserIdGenerationMode); +KBTS_EXPORT kbts_shape_error kbts_ShapeError(kbts_shape_context *Context); +KBTS_EXPORT void kbts_ShapeBeginManualRuns(kbts_shape_context *Context); +KBTS_EXPORT void kbts_ShapeNextManualRun(kbts_shape_context *Context, kbts_direction Direction, kbts_script Script); +KBTS_EXPORT void kbts_ShapeEndManualRuns(kbts_shape_context *Context); +KBTS_EXPORT void kbts_ShapeManualBreak(kbts_shape_context *Context); +KBTS_EXPORT kbts_shape_codepoint_iterator kbts_ShapeCurrentCodepointsIterator(kbts_shape_context *Context); +KBTS_EXPORT int kbts_ShapeCodepointIteratorIsValid(kbts_shape_codepoint_iterator *It); +KBTS_EXPORT int kbts_ShapeCodepointIteratorNext(kbts_shape_codepoint_iterator *It, kbts_shape_codepoint *Codepoint, int *CodepointIndex); +KBTS_EXPORT int kbts_ShapeGetShapeCodepoint(kbts_shape_context *Context, int CodepointIndex, kbts_shape_codepoint *Codepoint); + +// +// Direct API +// + +KBTS_EXPORT kbts_shape_error kbts_ShapeDirect(kbts_shape_config *Config, kbts_glyph_storage *Storage, kbts_direction RunDirection, kbts_allocator_function *Allocator, void *AllocatorData, kbts_glyph_iterator *Output); +KBTS_EXPORT kbts_shape_error kbts_ShapeDirectFixedMemory(kbts_shape_config *Config, kbts_glyph_storage *Storage, kbts_direction RunDirection, void *Memory, int MemorySize, kbts_glyph_iterator *Output); + +// A font holds all data that corresponds to a given font file. +#ifndef KB_TEXT_SHAPE_NO_CRT +KBTS_EXPORT kbts_font kbts_FontFromFile(const char *FileName, int FontIndex, kbts_allocator_function *Allocator, void *AllocatorData, void **FileData, int *FileSize); +#endif +KBTS_EXPORT int kbts_FontCount(void *FileData, int FileSize); +KBTS_EXPORT kbts_font kbts_FontFromMemory(void *FileData, int FileSize, int FontIndex, kbts_allocator_function *Allocator, void *AllocatorData); +KBTS_EXPORT void kbts_FreeFont(kbts_font *Font); KBTS_EXPORT int kbts_FontIsValid(kbts_font *Font); -KBTS_EXPORT kbts_un kbts_ReadFontHeader(kbts_font *Font, void *Data, kbts_un Size); -KBTS_EXPORT kbts_un kbts_ReadFontData(kbts_font *Font, void *Scratch, kbts_un ScratchSize); -KBTS_EXPORT int kbts_PostReadFontInitialize(kbts_font *Font, void *Memory, kbts_un MemorySize); -KBTS_EXPORT kbts_un kbts_SizeOfShapeState(kbts_font *Font); -KBTS_EXPORT kbts_shape_state *kbts_PlaceShapeState(void *Address, kbts_un Size); -KBTS_EXPORT void kbts_ResetShapeState(kbts_shape_state *State); -KBTS_EXPORT kbts_shape_config kbts_ShapeConfig(kbts_font *Font, kbts_script Script, kbts_language Language); -KBTS_EXPORT int kbts_ShaperIsComplex(kbts_shaper Shaper); -KBTS_EXPORT int kbts_Shape(kbts_shape_state *State, kbts_shape_config *Config, kbts_direction MainDirection, kbts_direction RunDirection, kbts_glyph *Glyphs, kbts_u32 *GlyphCount, kbts_u32 GlyphCapacity); -KBTS_EXPORT kbts_cursor kbts_Cursor(kbts_direction Direction); -KBTS_EXPORT void kbts_PositionGlyph(kbts_cursor *Cursor, kbts_glyph *Glyph, kbts_s32 *X, kbts_s32 *Y); -KBTS_EXPORT void kbts_BeginBreak(kbts_break_state *State, kbts_direction MainDirection, kbts_japanese_line_break_style JapaneseLineBreakStyle); -KBTS_EXPORT int kbts_BreakStateIsValid(kbts_break_state *State); -KBTS_EXPORT void kbts_BreakAddCodepoint(kbts_break_state *State, kbts_u32 Codepoint, kbts_u32 PositionIncrement, int EndOfText); -KBTS_EXPORT void kbts_BreakFlush(kbts_break_state *State); +KBTS_EXPORT kbts_load_font_error kbts_LoadFont(kbts_font *Font, kbts_load_font_state *State, void *FontData, int FontDataSize, int FontIndex, int *ScratchSize_, int *OutputSize_); +KBTS_EXPORT kbts_load_font_error kbts_PlaceBlob(kbts_font *Font, kbts_load_font_state *State, void *ScratchMemory, void *OutputMemory); +KBTS_EXPORT void kbts_GetFontInfo(kbts_font *Font, kbts_font_info *Info); + +// A shape_config is a bag of pre-computed data for a specific shaping setup. +KBTS_EXPORT int kbts_SizeOfShapeConfig(kbts_font *Font, kbts_script Script, kbts_language Language); +KBTS_EXPORT kbts_shape_config *kbts_PlaceShapeConfig(kbts_font *Font, kbts_script Script, kbts_language Language, void *Memory); +KBTS_EXPORT kbts_shape_config *kbts_CreateShapeConfig(kbts_font *Font, kbts_script Script, kbts_language Language, kbts_allocator_function *Allocator, void *AllocatorData); +KBTS_EXPORT void kbts_DestroyShapeConfig(kbts_shape_config *Config); + +// A glyph_storage holds and recycles glyph data. +KBTS_EXPORT int kbts_InitializeGlyphStorage(kbts_glyph_storage *Storage, kbts_allocator_function *Allocator, void *AllocatorData); +KBTS_EXPORT int kbts_InitializeGlyphStorageFixedMemory(kbts_glyph_storage *Storage, void *Memory, int MemorySize); +KBTS_EXPORT kbts_glyph *kbts_PushGlyph(kbts_glyph_storage *Storage, kbts_font *Font, int Codepoint, kbts_glyph_config *Config, int UserId); +KBTS_EXPORT void kbts_ClearActiveGlyphs(kbts_glyph_storage *Storage); +KBTS_EXPORT void kbts_FreeAllGlyphs(kbts_glyph_storage *Storage); +KBTS_EXPORT kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, int Codepoint, kbts_glyph_config *Config, int UserId); +KBTS_EXPORT int kbts_CodepointToGlyphId(kbts_font *Font, int Codepoint); +KBTS_EXPORT kbts_glyph_iterator kbts_ActiveGlyphIterator(kbts_glyph_storage *Storage); + +// A glyph_config specifies glyph-specific shaping parameters. +// A single glyph_config can be shared by multiple glyphs. +KBTS_EXPORT int kbts_SizeOfGlyphConfig(kbts_feature_override *Overrides, int OverrideCount); +KBTS_EXPORT kbts_glyph_config *kbts_PlaceGlyphConfig(kbts_feature_override *Overrides, int OverrideCount, void *Memory); +KBTS_EXPORT kbts_glyph_config *kbts_CreateGlyphConfig(kbts_feature_override *Overrides, int OverrideCount, kbts_allocator_function *Allocator, void *AllocatorData); +KBTS_EXPORT void kbts_DestroyGlyphConfig(kbts_glyph_config *Config); + +// +// Glyph iterator +// + +KBTS_EXPORT int kbts_GlyphIteratorNext(kbts_glyph_iterator *It, kbts_glyph **Glyph); +KBTS_EXPORT int kbts_GlyphIteratorIsValid(kbts_glyph_iterator *It); + +// +// Segmentation +// + +// This is a quick guess that stops at the first glyph that has a strong script/direction associated to it. +// It is convenient, but only works if you are sure your input text is mono-script and mono-direction. +KBTS_EXPORT void kbts_GuessTextProperties(void *Text, int TextSizeInBytes, kbts_text_format Format, kbts_direction *Direction, kbts_script *Script); +KBTS_EXPORT void kbts_GuessTextPropertiesUtf32(const int *Utf32, int Utf32Count, kbts_direction *Direction, kbts_script *Script); +KBTS_EXPORT void kbts_GuessTextPropertiesUtf8(const char *Utf8, int Utf8Length, kbts_direction *Direction, kbts_script *Script); + +KBTS_EXPORT void kbts_BreakBegin(kbts_break_state *State, kbts_direction ParagraphDirection, kbts_japanese_line_break_style JapaneseLineBreakStyle, kbts_break_config_flags ConfigFlags); +KBTS_EXPORT void kbts_BreakAddCodepoint(kbts_break_state *State, int Codepoint, int PositionIncrement, int EndOfText); +KBTS_EXPORT void kbts_BreakEnd(kbts_break_state *State); KBTS_EXPORT int kbts_Break(kbts_break_state *State, kbts_break *Break); +KBTS_EXPORT void kbts_BreakEntireString(kbts_direction Direction, kbts_japanese_line_break_style JapaneseLineBreakStyle, kbts_break_config_flags ConfigFlags, const void *Input, int InputSizeInBytes, kbts_text_format InputFormat, kbts_break *Breaks, int BreakCapacity, int *BreakCount, kbts_break_flags *BreakFlags, int BreakFlagCapacity, int *BreakFlagCount); +KBTS_EXPORT void kbts_BreakEntireStringUtf32(kbts_direction Direction, kbts_japanese_line_break_style JapaneseLineBreakStyle, kbts_break_config_flags ConfigFlags, const int *Utf32, int Utf32Count, kbts_break *Breaks, int BreakCapacity, int *BreakCount, kbts_break_flags *BreakFlags, int BreakFlagCapacity, int *BreakFlagCount); +KBTS_EXPORT void kbts_BreakEntireStringUtf8(kbts_direction Direction, kbts_japanese_line_break_style JapaneseLineBreakStyle, kbts_break_config_flags ConfigFlags, const char *Utf8, int Utf8Length, kbts_break *Breaks, int BreakCapacity, int *BreakCount, kbts_break_flags *BreakFlags, int BreakFlagCapacity, int *BreakFlagCount); + +// +// Other stuff +// + +// Quick test for font support of a sequence of codepoints. +KBTS_EXPORT void kbts_FontCoverageTestBegin(kbts_font_coverage_test *Test, kbts_font *Font); +KBTS_EXPORT void kbts_FontCoverageTestCodepoint(kbts_font_coverage_test *Test, int Codepoint); +KBTS_EXPORT int kbts_FontCoverageTestEnd(kbts_font_coverage_test *Test); + KBTS_EXPORT kbts_decode kbts_DecodeUtf8(const char *Utf8, kbts_un Length); -KBTS_EXPORT kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, kbts_u32 Codepoint); -KBTS_EXPORT void kbts_InferScript(kbts_direction *Direction, kbts_script *Script, kbts_script GlyphScript); +KBTS_EXPORT kbts_encode_utf8 kbts_EncodeUtf8(int Codepoint); +KBTS_EXPORT kbts_direction kbts_ScriptDirection(kbts_script Script); KBTS_EXPORT int kbts_ScriptIsComplex(kbts_script Script); KBTS_EXPORT kbts_script kbts_ScriptTagToScript(kbts_script_tag Tag); + #endif #ifdef KB_TEXT_SHAPE_IMPLEMENTATION #ifdef _MSC_VER -#define KBTS_UNUSED(X) (void)sizeof((X)) +#define KBTS__UNUSED(X) (void)sizeof((X)) #else -#define KBTS_UNUSED(X) (void)(X) +#define KBTS__UNUSED(X) (void)(X) #endif -# define KBTS_FOR(I, Start, End) for(kbts_un I = (Start); I < (End); ++I) +# define KBTS__FOR(I, Start, End) for(kbts_un I = (Start); I < (End); ++I) # ifdef __cplusplus -# define KBTS_ZERO {} -# define KBTS_ZERO_TYPE(T) T{} +# define KBTS__ZERO {} +# define KBTS__ZERO_TYPE(T) T{} # else -# define KBTS_ZERO {0} -# define KBTS_ZERO_TYPE(T) (T){0} +# define KBTS__ZERO {0} +# define KBTS__ZERO_TYPE(T) (T){0} # endif -# define KBTS_MAX(A, B) (((A) < (B)) ? (B) : (A)) -# define KBTS_MIN(A, B) (((A) < (B)) ? (A) : (B)) -# define KBTS_ARRAY_LENGTH(A) (sizeof(A)/sizeof(*(A))) -# define KBTS_POINTER_AFTER(Type, X) ((Type *)((X) + 1)) -# define KBTS_POINTER_OFFSET(Type, Base, Offset) ((Type *)((char *)(Base) + (Offset))) -# define KBTS_POINTER_DIFF32(Pointer, Base) ((kbts_u32)((char *)(Pointer) - (char *)(Base))) -# define KBTS_PASTE_1(A, B) A##B -# define KBTS_PASTE_0(A, B) KBTS_PASTE_1(A, B) -# define KBTS_PASTE(A, B) KBTS_PASTE_0(A, B) -# define KBTS_IN_SET(X, Set) ((1u << (X)) & (Set)) -# define KBTS_SET32_0(Arg) | (1u << (Arg)) KBTS_SET32_1 -# define KBTS_SET32_1(Arg) | (1u << (Arg)) KBTS_SET32_0 -# define KBTS_SET32_0End -# define KBTS_SET32_1End -# define KBTS_SET32(Args) (0u KBTS_PASTE(KBTS_SET32_0 Args, End)) -# define KBTS_IN_SET64(X, Set) ((1ull << (X)) & (Set)) -# define KBTS_SET64_0(Arg) | (1ull << (Arg)) KBTS_SET64_1 -# define KBTS_SET64_1(Arg) | (1ull << (Arg)) KBTS_SET64_0 -# define KBTS_SET64_0End -# define KBTS_SET64_1End -# define KBTS_SET64(Args) (0u KBTS_PASTE(KBTS_SET64_0 Args, End)) +# define KBTS__MAX(A, B) (((A) < (B)) ? (B) : (A)) +# define KBTS__MIN(A, B) (((A) < (B)) ? (A) : (B)) +# define KBTS__ARRAY_LENGTH(A) (sizeof(A)/sizeof(*(A))) +# define KBTS__POINTER_AFTER(Type, X) ((Type *)((X) + 1)) +# define KBTS__POINTER_OFFSET(Type, Base, Offset) ((Type *)((char *)(Base) + (Offset))) +# define KBTS__POINTER_DIFF32(Pointer, Base) ((kbts_u32)((char *)(Pointer) - (char *)(Base))) +# define KBTS__POINTER_DIFF(Pointer, Base) ((kbts_un)((char *)(Pointer) - (char *)(Base))) +# define KBTS__ALIGN_POINTER(Type, Pointer, Align) (Type *)(((kbts_un)(Pointer) + ((Align) - 1)) & ~((Align) - 1)) +# define KBTS__PASTE_1(A, B) A##B +# define KBTS__PASTE_0(A, B) KBTS__PASTE_1(A, B) +# define KBTS__PASTE(A, B) KBTS__PASTE_0(A, B) +# define KBTS__IN_SET(X, Set) ((1u << (X)) & (Set)) +# define KBTS__SET32_0(Arg) | (1u << (Arg)) KBTS__SET32_1 +# define KBTS__SET32_1(Arg) | (1u << (Arg)) KBTS__SET32_0 +# define KBTS__SET32_0End +# define KBTS__SET32_1End +# define KBTS__SET32(Args) (0u KBTS__PASTE(KBTS__SET32_0 Args, End)) +# define KBTS__IN_SET64(X, Set) ((1ull << (X)) & (Set)) +# define KBTS__SET64_0(Arg) | (1ull << (Arg)) KBTS__SET64_1 +# define KBTS__SET64_1(Arg) | (1ull << (Arg)) KBTS__SET64_0 +# define KBTS__SET64_0End +# define KBTS__SET64_1End +# define KBTS__SET64(Args) (0u KBTS__PASTE(KBTS__SET64_0 Args, End)) +#define KBTS__U32BE(X) kbts__ByteSwap32((X)) +#define KBTS__U32LE(X) (X) + +#define KBTS_LOOKUP_STACK_SIZE 64 # ifndef KBTS_ASSERT #ifndef KB_TEXT_SHAPE_NO_CRT @@ -2920,47 +3757,706 @@ KBTS_EXPORT kbts_script kbts_ScriptTagToScript(kbts_script_tag Tag); #define KBTS_MEMSET memset #endif -#ifndef kbts_ByteSwap16 +#ifndef KBTS_MEMCPY +#include +#define KBTS_MEMCPY memcpy +#endif + +#ifndef KB_TEXT_SHAPE_NO_CRT +#ifndef KBTS_MALLOC +#include +#define KBTS_MALLOC(Data, Size) malloc((Size)) +#define KBTS_FREE(Data, Pointer) free((Pointer)) +#endif +#else +#ifndef KBTS_MALLOC +// Nerf the default allocator to a null allocator. +#define KBTS_MALLOC(Data, Size) 0 +#define KBTS_FREE(Data, Pointer) +#endif +#endif + +#ifndef kbts__ByteSwap16 # if defined(_MSC_VER) && !defined(__clang__) -# define kbts_ByteSwap16(X) _byteswap_ushort(X) -# define kbts_ByteSwap32(X) _byteswap_ulong(X) -# define kbts_PopCount32(X) (kbts_un)__popcnt(X) +#include +KBTS_INLINE kbts_u16 kbts__ByteSwap16(kbts_u16 X) +{ + kbts_u16 Result = (kbts_u16)((X >> 8) | (X << 8)); + return Result; +} +KBTS_INLINE kbts_u32 kbts__ByteSwap32(kbts_u32 X) +{ + kbts_u32 Result = (X >> 24) | + ((X & 0xFF0000) >> 8) | + ((X & 0xFF00) << 8) | + ((X & 0xFF) << 24); + return Result; +} +# define kbts__PopCount32(X) (kbts_un)__popcnt(X) # elif defined(__clang__) || defined(__GNUC__) -# define kbts_ByteSwap16(X) __builtin_bswap16(X) -# define kbts_ByteSwap32(X) __builtin_bswap32(X) -# define kbts_PopCount32(X) (kbts_un)__builtin_popcount(X) +# define kbts__ByteSwap16(X) __builtin_bswap16(X) +# define kbts__ByteSwap32(X) __builtin_bswap32(X) +# define kbts__PopCount32(X) (kbts_un)__builtin_popcount(X) # else # error Unsupported compiler! # endif #endif -#define KBTS_FEATURE_FLAG0(Feature) (1ull << KBTS_FEATURE_ID_##Feature) -#define KBTS_FEATURE_FLAG1(Feature) (1ull << (KBTS_FEATURE_ID_##Feature - 64)) -#define KBTS_FEATURE_FLAG2(Feature) (1ull << (KBTS_FEATURE_ID_##Feature - 128)) -#define KBTS_FEATURE_FLAG3(Feature) (1ull << (KBTS_FEATURE_ID_##Feature - 192)) +#ifndef kbts__MsbPositionOrZero32 +# if defined(_MSC_VER) && !defined(__clang__) +#include +KBTS_INLINE kbts_u32 kbts__MsbPositionOrZero32(kbts_u32 X) +{ + unsigned long Result; + if(!_BitScanReverse(&Result, X)) + { + Result = 0; + } + return (kbts_u32)Result; +} +# elif defined(__clang__) || defined(__GNUC__) +KBTS_INLINE kbts_u32 kbts__MsbPositionOrZero32(kbts_u32 X) +{ + kbts_u32 Result = 0; + if(X) + { + Result = 31 - __builtin_clz(X); + } + return Result; +} +# else +# error Unsupported compiler! +# endif +#endif + +#define KBTS__FEATURE_FLAG0(Feature) (1ull << KBTS__FEATURE_ID_##Feature) +#define KBTS__FEATURE_FLAG1(Feature) (1ull << (KBTS__FEATURE_ID_##Feature - 64)) +#define KBTS__FEATURE_FLAG2(Feature) (1ull << (KBTS__FEATURE_ID_##Feature - 128)) +#define KBTS__FEATURE_FLAG3(Feature) (1ull << (KBTS__FEATURE_ID_##Feature - 192)) + +// #define KBTS_SANITY_CHECK +// #define KBTS_DUMP -// # define KBTS_DUMP # ifdef KBTS_DUMP # define KBTS_DUMPF(...) printf(__VA_ARGS__), fflush(stdout) # else # define KBTS_DUMPF(...) # endif -# define KBTS_GROW_BUFFER_MARGIN 16 - #ifndef KBTS_INSTRUMENT_BLOCK_BEGIN #define KBTS_INSTRUMENT_BLOCK_BEGIN(Name) +#define KBTS_INSTRUMENT_BLOCK_END(Name) #define KBTS_INSTRUMENT_FUNCTION_BEGIN -#define KBTS_INSTRUMENT_END +#define KBTS_INSTRUMENT_FUNCTION_END #endif -#define KBTS_MAXIMUM_DECOMPOSITION_CODEPOINTS 6 -typedef struct kbts_script_properties { +#define KBTS__GLYPH_FEATURE_MASK ((KBTS_GLYPH_FLAG_CFAR << 1) - 1) +// In USE, glyphs are mostly not pre-flagged for feature application. +// However, we do want to flag rphf/pref results for reordering, so we want to +// keep all of the flags as usual, and only use these feature flags for filtering. +#define KBTS__USE_GLYPH_FEATURE_MASK (KBTS_GLYPH_FLAG_ISOL | KBTS_GLYPH_FLAG_FINA | KBTS_GLYPH_FLAG_FIN2 | KBTS_GLYPH_FLAG_FIN3 | \ + KBTS_GLYPH_FLAG_MEDI | KBTS_GLYPH_FLAG_MED2 | KBTS_GLYPH_FLAG_INIT | KBTS_GLYPH_FLAG_NUMR | \ + KBTS_GLYPH_FLAG_DNOM | KBTS_GLYPH_FLAG_FRAC) +#define KBTS__JOINING_FEATURE_MASK (KBTS_GLYPH_FLAG_ISOL | KBTS_GLYPH_FLAG_FINA | KBTS_GLYPH_FLAG_FIN2 | KBTS_GLYPH_FLAG_FIN3 | \ + KBTS_GLYPH_FLAG_MEDI | KBTS_GLYPH_FLAG_MED2 | KBTS_GLYPH_FLAG_INIT) +#define KBTS__JOINING_FEATURE_TO_GLYPH_FLAG(Feature) (1 << ((Feature) - 1)) + +typedef kbts_u8 kbts__reph_position; +enum kbts__reph_position_enum +{ + KBTS__REPH_POSITION_AFTER_POST, + KBTS__REPH_POSITION_BEFORE_POST, + KBTS__REPH_POSITION_BEFORE_SUBJOINED, + KBTS__REPH_POSITION_AFTER_SUBJOINED, + KBTS__REPH_POSITION_AFTER_MAIN, + + KBTS__REPH_POSITION_COUNT, +}; + +typedef kbts_u8 kbts__reph_encoding; +enum kbts__reph_encoding_enum +{ + KBTS__REPH_ENCODING_IMPLICIT, + KBTS__REPH_ENCODING_EXPLICIT, + KBTS__REPH_ENCODING_LOGICAL_REPHA, + KBTS__REPH_ENCODING_VISUAL_REPHA, + + KBTS__REPH_ENCODING_COUNT, +}; + +typedef kbts_u8 kbts__syllabic_position; +enum kbts__syllabic_position_enum +{ + KBTS__SYLLABIC_POSITION_NONE, + + KBTS__SYLLABIC_POSITION_RA_TO_BECOME_REPH, + + KBTS__SYLLABIC_POSITION_PREBASE_MATRA, + KBTS__SYLLABIC_POSITION_PREBASE_CONSONANT, + + KBTS__SYLLABIC_POSITION_SYLLABLE_BASE, + KBTS__SYLLABIC_POSITION_AFTER_MAIN, + + KBTS__SYLLABIC_POSITION_ABOVEBASE_CONSONANT, + + KBTS__SYLLABIC_POSITION_BEFORE_SUBJOINED, + KBTS__SYLLABIC_POSITION_BELOWBASE_CONSONANT, + KBTS__SYLLABIC_POSITION_AFTER_SUBJOINED, + + KBTS__SYLLABIC_POSITION_BEFORE_POST, + KBTS__SYLLABIC_POSITION_POSTBASE_CONSONANT, + KBTS__SYLLABIC_POSITION_AFTER_POST, + + KBTS__SYLLABIC_POSITION_FINAL_CONSONANT, + KBTS__SYLLABIC_POSITION_SMVD, + + KBTS__SYLLABIC_POSITION_COUNT, +}; + + +typedef kbts_u32 kbts__feature_id; +enum kbts__feature_id_enum +{ + KBTS__FEATURE_ID_UNREGISTERED, // Features that aren't pre-defined in the OpenType spec + KBTS__FEATURE_ID_isol, // Isolated Forms + KBTS__FEATURE_ID_fina, // Terminal Forms + KBTS__FEATURE_ID_fin2, // Terminal Forms #2 + KBTS__FEATURE_ID_fin3, // Terminal Forms #3 + KBTS__FEATURE_ID_medi, // Medial Forms + KBTS__FEATURE_ID_med2, // Medial Forms #2 + KBTS__FEATURE_ID_init, // Initial Forms + KBTS__FEATURE_ID_ljmo, // Leading Jamo Forms + KBTS__FEATURE_ID_vjmo, // Vowel Jamo Forms + KBTS__FEATURE_ID_tjmo, // Trailing Jamo Forms + KBTS__FEATURE_ID_rphf, // Reph Form + KBTS__FEATURE_ID_blwf, // Below-base Forms + KBTS__FEATURE_ID_half, // Half Forms + KBTS__FEATURE_ID_pstf, // Post-base Forms + KBTS__FEATURE_ID_abvf, // Above-base Forms + KBTS__FEATURE_ID_pref, // Pre-base Forms + KBTS__FEATURE_ID_numr, // Numerators + KBTS__FEATURE_ID_frac, // Fractions + KBTS__FEATURE_ID_dnom, // Denominators + KBTS__FEATURE_ID_cfar, // Conjunct Form After Ro + KBTS__FEATURE_ID_aalt, // Access All Alternates + KBTS__FEATURE_ID_abvm, // Above-base Mark Positioning + KBTS__FEATURE_ID_abvs, // Above-base Substitutions + KBTS__FEATURE_ID_afrc, // Alternative Fractions + KBTS__FEATURE_ID_akhn, // Akhand + KBTS__FEATURE_ID_apkn, // Kerning for Alternate Proportional Widths + KBTS__FEATURE_ID_blwm, // Below-base Mark Positioning + KBTS__FEATURE_ID_blws, // Below-base Substitutions + KBTS__FEATURE_ID_calt, // Contextual Alternates + KBTS__FEATURE_ID_case, // Case-sensitive Forms + KBTS__FEATURE_ID_ccmp, // Glyph Composition / Decomposition + KBTS__FEATURE_ID_chws, // Contextual Half-width Spacing + KBTS__FEATURE_ID_cjct, // Conjunct Forms + KBTS__FEATURE_ID_clig, // Contextual Ligatures + KBTS__FEATURE_ID_cpct, // Centered CJK Punctuation + KBTS__FEATURE_ID_cpsp, // Capital Spacing + KBTS__FEATURE_ID_cswh, // Contextual Swash + KBTS__FEATURE_ID_curs, // Cursive Positioning + KBTS__FEATURE_ID_cv01, // Character Variant 1 + KBTS__FEATURE_ID_cv02, // Character Variant 2 + KBTS__FEATURE_ID_cv03, // Character Variant 3 + KBTS__FEATURE_ID_cv04, // Character Variant 4 + KBTS__FEATURE_ID_cv05, // Character Variant 5 + KBTS__FEATURE_ID_cv06, // Character Variant 6 + KBTS__FEATURE_ID_cv07, // Character Variant 7 + KBTS__FEATURE_ID_cv08, // Character Variant 8 + KBTS__FEATURE_ID_cv09, // Character Variant 9 + KBTS__FEATURE_ID_cv10, // Character Variant 10 + KBTS__FEATURE_ID_cv11, // Character Variant 11 + KBTS__FEATURE_ID_cv12, // Character Variant 12 + KBTS__FEATURE_ID_cv13, // Character Variant 13 + KBTS__FEATURE_ID_cv14, // Character Variant 14 + KBTS__FEATURE_ID_cv15, // Character Variant 15 + KBTS__FEATURE_ID_cv16, // Character Variant 16 + KBTS__FEATURE_ID_cv17, // Character Variant 17 + KBTS__FEATURE_ID_cv18, // Character Variant 18 + KBTS__FEATURE_ID_cv19, // Character Variant 19 + KBTS__FEATURE_ID_cv20, // Character Variant 20 + KBTS__FEATURE_ID_cv21, // Character Variant 21 + KBTS__FEATURE_ID_cv22, // Character Variant 22 + KBTS__FEATURE_ID_cv23, // Character Variant 23 + KBTS__FEATURE_ID_cv24, // Character Variant 24 + KBTS__FEATURE_ID_cv25, // Character Variant 25 + KBTS__FEATURE_ID_cv26, // Character Variant 26 + KBTS__FEATURE_ID_cv27, // Character Variant 27 + KBTS__FEATURE_ID_cv28, // Character Variant 28 + KBTS__FEATURE_ID_cv29, // Character Variant 29 + KBTS__FEATURE_ID_cv30, // Character Variant 30 + KBTS__FEATURE_ID_cv31, // Character Variant 31 + KBTS__FEATURE_ID_cv32, // Character Variant 32 + KBTS__FEATURE_ID_cv33, // Character Variant 33 + KBTS__FEATURE_ID_cv34, // Character Variant 34 + KBTS__FEATURE_ID_cv35, // Character Variant 35 + KBTS__FEATURE_ID_cv36, // Character Variant 36 + KBTS__FEATURE_ID_cv37, // Character Variant 37 + KBTS__FEATURE_ID_cv38, // Character Variant 38 + KBTS__FEATURE_ID_cv39, // Character Variant 39 + KBTS__FEATURE_ID_cv40, // Character Variant 40 + KBTS__FEATURE_ID_cv41, // Character Variant 41 + KBTS__FEATURE_ID_cv42, // Character Variant 42 + KBTS__FEATURE_ID_cv43, // Character Variant 43 + KBTS__FEATURE_ID_cv44, // Character Variant 44 + KBTS__FEATURE_ID_cv45, // Character Variant 45 + KBTS__FEATURE_ID_cv46, // Character Variant 46 + KBTS__FEATURE_ID_cv47, // Character Variant 47 + KBTS__FEATURE_ID_cv48, // Character Variant 48 + KBTS__FEATURE_ID_cv49, // Character Variant 49 + KBTS__FEATURE_ID_cv50, // Character Variant 50 + KBTS__FEATURE_ID_cv51, // Character Variant 51 + KBTS__FEATURE_ID_cv52, // Character Variant 52 + KBTS__FEATURE_ID_cv53, // Character Variant 53 + KBTS__FEATURE_ID_cv54, // Character Variant 54 + KBTS__FEATURE_ID_cv55, // Character Variant 55 + KBTS__FEATURE_ID_cv56, // Character Variant 56 + KBTS__FEATURE_ID_cv57, // Character Variant 57 + KBTS__FEATURE_ID_cv58, // Character Variant 58 + KBTS__FEATURE_ID_cv59, // Character Variant 59 + KBTS__FEATURE_ID_cv60, // Character Variant 60 + KBTS__FEATURE_ID_cv61, // Character Variant 61 + KBTS__FEATURE_ID_cv62, // Character Variant 62 + KBTS__FEATURE_ID_cv63, // Character Variant 63 + KBTS__FEATURE_ID_cv64, // Character Variant 64 + KBTS__FEATURE_ID_cv65, // Character Variant 65 + KBTS__FEATURE_ID_cv66, // Character Variant 66 + KBTS__FEATURE_ID_cv67, // Character Variant 67 + KBTS__FEATURE_ID_cv68, // Character Variant 68 + KBTS__FEATURE_ID_cv69, // Character Variant 69 + KBTS__FEATURE_ID_cv70, // Character Variant 70 + KBTS__FEATURE_ID_cv71, // Character Variant 71 + KBTS__FEATURE_ID_cv72, // Character Variant 72 + KBTS__FEATURE_ID_cv73, // Character Variant 73 + KBTS__FEATURE_ID_cv74, // Character Variant 74 + KBTS__FEATURE_ID_cv75, // Character Variant 75 + KBTS__FEATURE_ID_cv76, // Character Variant 76 + KBTS__FEATURE_ID_cv77, // Character Variant 77 + KBTS__FEATURE_ID_cv78, // Character Variant 78 + KBTS__FEATURE_ID_cv79, // Character Variant 79 + KBTS__FEATURE_ID_cv80, // Character Variant 80 + KBTS__FEATURE_ID_cv81, // Character Variant 81 + KBTS__FEATURE_ID_cv82, // Character Variant 82 + KBTS__FEATURE_ID_cv83, // Character Variant 83 + KBTS__FEATURE_ID_cv84, // Character Variant 84 + KBTS__FEATURE_ID_cv85, // Character Variant 85 + KBTS__FEATURE_ID_cv86, // Character Variant 86 + KBTS__FEATURE_ID_cv87, // Character Variant 87 + KBTS__FEATURE_ID_cv88, // Character Variant 88 + KBTS__FEATURE_ID_cv89, // Character Variant 89 + KBTS__FEATURE_ID_cv90, // Character Variant 90 + KBTS__FEATURE_ID_cv91, // Character Variant 91 + KBTS__FEATURE_ID_cv92, // Character Variant 92 + KBTS__FEATURE_ID_cv93, // Character Variant 93 + KBTS__FEATURE_ID_cv94, // Character Variant 94 + KBTS__FEATURE_ID_cv95, // Character Variant 95 + KBTS__FEATURE_ID_cv96, // Character Variant 96 + KBTS__FEATURE_ID_cv97, // Character Variant 97 + KBTS__FEATURE_ID_cv98, // Character Variant 98 + KBTS__FEATURE_ID_cv99, // Character Variant 99 + KBTS__FEATURE_ID_c2pc, // Petite Capitals From Capitals + KBTS__FEATURE_ID_c2sc, // Small Capitals From Capitals + KBTS__FEATURE_ID_dist, // Distances + KBTS__FEATURE_ID_dlig, // Discretionary Ligatures + KBTS__FEATURE_ID_dtls, // Dotless Forms + KBTS__FEATURE_ID_expt, // Expert Forms + KBTS__FEATURE_ID_falt, // Final Glyph on Line Alternates + KBTS__FEATURE_ID_flac, // Flattened Accent Forms + KBTS__FEATURE_ID_fwid, // Full Widths + KBTS__FEATURE_ID_haln, // Halant Forms + KBTS__FEATURE_ID_halt, // Alternate Half Widths + KBTS__FEATURE_ID_hist, // Historical Forms + KBTS__FEATURE_ID_hkna, // Horizontal Kana Alternates + KBTS__FEATURE_ID_hlig, // Historical Ligatures + KBTS__FEATURE_ID_hngl, // Hangul + KBTS__FEATURE_ID_hojo, // Hojo Kanji Forms (JIS X 0212-1990 Kanji Forms) + KBTS__FEATURE_ID_hwid, // Half Widths + KBTS__FEATURE_ID_ital, // Italics + KBTS__FEATURE_ID_jalt, // Justification Alternates + KBTS__FEATURE_ID_jp78, // JIS78 Forms + KBTS__FEATURE_ID_jp83, // JIS83 Forms + KBTS__FEATURE_ID_jp90, // JIS90 Forms + KBTS__FEATURE_ID_jp04, // JIS2004 Forms + KBTS__FEATURE_ID_kern, // Kerning + KBTS__FEATURE_ID_lfbd, // Left Bounds + KBTS__FEATURE_ID_liga, // Standard Ligatures + KBTS__FEATURE_ID_lnum, // Lining Figures + KBTS__FEATURE_ID_locl, // Localized Forms + KBTS__FEATURE_ID_ltra, // Left-to-right Alternates + KBTS__FEATURE_ID_ltrm, // Left-to-right Mirrored Forms + KBTS__FEATURE_ID_mark, // Mark Positioning + KBTS__FEATURE_ID_mgrk, // Mathematical Greek + KBTS__FEATURE_ID_mkmk, // Mark to Mark Positioning + KBTS__FEATURE_ID_mset, // Mark Positioning via Substitution + KBTS__FEATURE_ID_nalt, // Alternate Annotation Forms + KBTS__FEATURE_ID_nlck, // NLC Kanji Forms + KBTS__FEATURE_ID_nukt, // Nukta Forms + KBTS__FEATURE_ID_onum, // Oldstyle Figures + KBTS__FEATURE_ID_opbd, // Optical Bounds + KBTS__FEATURE_ID_ordn, // Ordinals + KBTS__FEATURE_ID_ornm, // Ornaments + KBTS__FEATURE_ID_palt, // Proportional Alternate Widths + KBTS__FEATURE_ID_pcap, // Petite Capitals + KBTS__FEATURE_ID_pkna, // Proportional Kana + KBTS__FEATURE_ID_pnum, // Proportional Figures + KBTS__FEATURE_ID_pres, // Pre-base Substitutions + KBTS__FEATURE_ID_psts, // Post-base Substitutions + KBTS__FEATURE_ID_pwid, // Proportional Widths + KBTS__FEATURE_ID_qwid, // Quarter Widths + KBTS__FEATURE_ID_rand, // Randomize + KBTS__FEATURE_ID_rclt, // Required Contextual Alternates + KBTS__FEATURE_ID_rkrf, // Rakar Forms + KBTS__FEATURE_ID_rlig, // Required Ligatures + KBTS__FEATURE_ID_rtbd, // Right Bounds + KBTS__FEATURE_ID_rtla, // Right-to-left Alternates + KBTS__FEATURE_ID_rtlm, // Right-to-left Mirrored Forms + KBTS__FEATURE_ID_ruby, // Ruby Notation Forms + KBTS__FEATURE_ID_rvrn, // Required Variation Alternates + KBTS__FEATURE_ID_salt, // Stylistic Alternates + KBTS__FEATURE_ID_sinf, // Scientific Inferiors + KBTS__FEATURE_ID_size, // Optical size + KBTS__FEATURE_ID_smcp, // Small Capitals + KBTS__FEATURE_ID_smpl, // Simplified Forms + KBTS__FEATURE_ID_ss01, // Stylistic Set 1 + KBTS__FEATURE_ID_ss02, // Stylistic Set 2 + KBTS__FEATURE_ID_ss03, // Stylistic Set 3 + KBTS__FEATURE_ID_ss04, // Stylistic Set 4 + KBTS__FEATURE_ID_ss05, // Stylistic Set 5 + KBTS__FEATURE_ID_ss06, // Stylistic Set 6 + KBTS__FEATURE_ID_ss07, // Stylistic Set 7 + KBTS__FEATURE_ID_ss08, // Stylistic Set 8 + KBTS__FEATURE_ID_ss09, // Stylistic Set 9 + KBTS__FEATURE_ID_ss10, // Stylistic Set 10 + KBTS__FEATURE_ID_ss11, // Stylistic Set 11 + KBTS__FEATURE_ID_ss12, // Stylistic Set 12 + KBTS__FEATURE_ID_ss13, // Stylistic Set 13 + KBTS__FEATURE_ID_ss14, // Stylistic Set 14 + KBTS__FEATURE_ID_ss15, // Stylistic Set 15 + KBTS__FEATURE_ID_ss16, // Stylistic Set 16 + KBTS__FEATURE_ID_ss17, // Stylistic Set 17 + KBTS__FEATURE_ID_ss18, // Stylistic Set 18 + KBTS__FEATURE_ID_ss19, // Stylistic Set 19 + KBTS__FEATURE_ID_ss20, // Stylistic Set 20 + KBTS__FEATURE_ID_ssty, // Math Script-style Alternates + KBTS__FEATURE_ID_stch, // Stretching Glyph Decomposition + KBTS__FEATURE_ID_subs, // Subscript + KBTS__FEATURE_ID_sups, // Superscript + KBTS__FEATURE_ID_swsh, // Swash + KBTS__FEATURE_ID_test, // Test features, only for development + KBTS__FEATURE_ID_titl, // Titling + KBTS__FEATURE_ID_tnam, // Traditional Name Forms + KBTS__FEATURE_ID_tnum, // Tabular Figures + KBTS__FEATURE_ID_trad, // Traditional Forms + KBTS__FEATURE_ID_twid, // Third Widths + KBTS__FEATURE_ID_unic, // Unicase + KBTS__FEATURE_ID_valt, // Alternate Vertical Metrics + KBTS__FEATURE_ID_vapk, // Kerning for Alternate Proportional Vertical Metrics + KBTS__FEATURE_ID_vatu, // Vattu Variants + KBTS__FEATURE_ID_vchw, // Vertical Contextual Half-width Spacing + KBTS__FEATURE_ID_vert, // Vertical Alternates + KBTS__FEATURE_ID_vhal, // Alternate Vertical Half Metrics + KBTS__FEATURE_ID_vkna, // Vertical Kana Alternates + KBTS__FEATURE_ID_vkrn, // Vertical Kerning + KBTS__FEATURE_ID_vpal, // Proportional Alternate Vertical Metrics + KBTS__FEATURE_ID_vrt2, // Vertical Alternates and Rotation + KBTS__FEATURE_ID_vrtr, // Vertical Alternates for Rotation + KBTS__FEATURE_ID_zero, // Slashed Zero + KBTS__FEATURE_ID_COUNT, +}; + +typedef struct kbts__feature_set +{ + kbts_u64 Flags[(KBTS__FEATURE_ID_COUNT + 63) / 64]; +} kbts__feature_set; +typedef kbts_u8 kbts__op_kind; +enum kbts__op_kind_enum +{ + KBTS__OP_KIND_END, + KBTS__OP_KIND_PRE_NORMALIZE_DOTTED_CIRCLES, + KBTS__OP_KIND_NORMALIZE, + KBTS__OP_KIND_NORMALIZE_HANGUL, + KBTS__OP_KIND_FLAG_JOINING_LETTERS, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES_WITH_USER, + KBTS__OP_KIND_GPOS_METRICS, + KBTS__OP_KIND_GPOS_FEATURES, + KBTS__OP_KIND_POST_GPOS_FIXUP, + KBTS__OP_KIND_STCH_POSTPASS, + KBTS__OP_KIND_BEGIN_CLUSTER, + KBTS__OP_KIND_END_CLUSTER, + KBTS__OP_KIND_END_SYLLABLE, + KBTS__OP_KIND_COUNT, +}; +typedef struct kbts__feature_stage +{ + kbts_u32 FeatureCount; + kbts__feature_set Features; +} kbts__feature_stage; +typedef struct kbts__op_list +{ + kbts_u32 TotalFeatureCount; + kbts_u32 FeatureStageCount; + kbts__feature_stage *FeatureStages; + kbts_u32 OpCount; + kbts__op_kind *Ops; +} kbts__op_list; +static kbts__op_kind kbts__Ops_Default[] = { + KBTS__OP_KIND_NORMALIZE, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES_WITH_USER, + KBTS__OP_KIND_GPOS_METRICS, + KBTS__OP_KIND_GPOS_FEATURES, + KBTS__OP_KIND_POST_GPOS_FIXUP, +}; +static kbts__feature_stage kbts__FeatureStages_Default[] = { + {1, {{0ull, 0ull, 0ull, 0ull | KBTS__FEATURE_FLAG3(rvrn)}}}, + {12, {{0ull | KBTS__FEATURE_FLAG0(frac) | KBTS__FEATURE_FLAG0(numr) | KBTS__FEATURE_FLAG0(dnom) | KBTS__FEATURE_FLAG0(ccmp) | KBTS__FEATURE_FLAG0(clig) | KBTS__FEATURE_FLAG0(calt), 0ull, 0ull | KBTS__FEATURE_FLAG2(ltra) | KBTS__FEATURE_FLAG2(ltrm) | KBTS__FEATURE_FLAG2(locl) | KBTS__FEATURE_FLAG2(rlig) | KBTS__FEATURE_FLAG2(liga) | KBTS__FEATURE_FLAG2(rclt), 0ull}}}, + {7, {{0ull | KBTS__FEATURE_FLAG0(abvm) | KBTS__FEATURE_FLAG0(blwm) | KBTS__FEATURE_FLAG0(curs), 0ull, 0ull | KBTS__FEATURE_FLAG2(mark) | KBTS__FEATURE_FLAG2(mkmk) | KBTS__FEATURE_FLAG2(dist) | KBTS__FEATURE_FLAG2(kern), 0ull}}}, +}; +static kbts__op_list kbts__OpList_Default = {20, KBTS__ARRAY_LENGTH(kbts__FeatureStages_Default), kbts__FeatureStages_Default, KBTS__ARRAY_LENGTH(kbts__Ops_Default), kbts__Ops_Default}; +static kbts__op_kind kbts__Ops_Hangul[] = { + KBTS__OP_KIND_NORMALIZE, + KBTS__OP_KIND_NORMALIZE_HANGUL, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES_WITH_USER, + KBTS__OP_KIND_GPOS_METRICS, + KBTS__OP_KIND_GPOS_FEATURES, + KBTS__OP_KIND_POST_GPOS_FIXUP, +}; +static kbts__feature_stage kbts__FeatureStages_Hangul[] = { + {1, {{0ull, 0ull, 0ull, 0ull | KBTS__FEATURE_FLAG3(rvrn)}}}, + {14, {{0ull | KBTS__FEATURE_FLAG0(frac) | KBTS__FEATURE_FLAG0(numr) | KBTS__FEATURE_FLAG0(dnom) | KBTS__FEATURE_FLAG0(ljmo) | KBTS__FEATURE_FLAG0(vjmo) | KBTS__FEATURE_FLAG0(tjmo) | KBTS__FEATURE_FLAG0(ccmp) | KBTS__FEATURE_FLAG0(clig), 0ull, 0ull | KBTS__FEATURE_FLAG2(ltra) | KBTS__FEATURE_FLAG2(ltrm) | KBTS__FEATURE_FLAG2(rlig) | KBTS__FEATURE_FLAG2(liga) | KBTS__FEATURE_FLAG2(locl) | KBTS__FEATURE_FLAG2(rclt), 0ull}}}, + {7, {{0ull | KBTS__FEATURE_FLAG0(abvm) | KBTS__FEATURE_FLAG0(blwm) | KBTS__FEATURE_FLAG0(curs), 0ull, 0ull | KBTS__FEATURE_FLAG2(mkmk) | KBTS__FEATURE_FLAG2(mark) | KBTS__FEATURE_FLAG2(dist) | KBTS__FEATURE_FLAG2(kern), 0ull}}}, +}; +static kbts__op_list kbts__OpList_Hangul = {22, KBTS__ARRAY_LENGTH(kbts__FeatureStages_Hangul), kbts__FeatureStages_Hangul, KBTS__ARRAY_LENGTH(kbts__Ops_Hangul), kbts__Ops_Hangul}; +static kbts__op_kind kbts__Ops_ArabicRclt[] = { + KBTS__OP_KIND_NORMALIZE, + KBTS__OP_KIND_FLAG_JOINING_LETTERS, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES_WITH_USER, + KBTS__OP_KIND_GPOS_METRICS, + KBTS__OP_KIND_GPOS_FEATURES, + KBTS__OP_KIND_STCH_POSTPASS, + KBTS__OP_KIND_POST_GPOS_FIXUP, +}; +static kbts__feature_stage kbts__FeatureStages_ArabicRclt[] = { + {1, {{0ull, 0ull, 0ull, 0ull | KBTS__FEATURE_FLAG3(rvrn)}}}, + {5, {{0ull | KBTS__FEATURE_FLAG0(frac) | KBTS__FEATURE_FLAG0(numr) | KBTS__FEATURE_FLAG0(dnom), 0ull, 0ull, 0ull | KBTS__FEATURE_FLAG3(rtla) | KBTS__FEATURE_FLAG3(rtlm)}}}, + {1, {{0ull, 0ull, 0ull, 0ull | KBTS__FEATURE_FLAG3(stch)}}}, + {2, {{0ull | KBTS__FEATURE_FLAG0(ccmp), 0ull, 0ull | KBTS__FEATURE_FLAG2(locl), 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(isol), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(fina), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(fin2), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(fin3), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(medi), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(med2), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(init), 0ull, 0ull, 0ull}}}, + {1, {{0ull, 0ull, 0ull | KBTS__FEATURE_FLAG2(rlig), 0ull}}}, + {5, {{0ull | KBTS__FEATURE_FLAG0(calt) | KBTS__FEATURE_FLAG0(clig), 0ull, 0ull | KBTS__FEATURE_FLAG2(liga) | KBTS__FEATURE_FLAG2(mset) | KBTS__FEATURE_FLAG2(rclt), 0ull}}}, + {7, {{0ull | KBTS__FEATURE_FLAG0(abvm) | KBTS__FEATURE_FLAG0(blwm) | KBTS__FEATURE_FLAG0(curs), 0ull, 0ull | KBTS__FEATURE_FLAG2(mark) | KBTS__FEATURE_FLAG2(mkmk) | KBTS__FEATURE_FLAG2(dist) | KBTS__FEATURE_FLAG2(kern), 0ull}}}, +}; +static kbts__op_list kbts__OpList_ArabicRclt = {29, KBTS__ARRAY_LENGTH(kbts__FeatureStages_ArabicRclt), kbts__FeatureStages_ArabicRclt, KBTS__ARRAY_LENGTH(kbts__Ops_ArabicRclt), kbts__Ops_ArabicRclt}; +static kbts__op_kind kbts__Ops_ArabicNoRclt[] = { + KBTS__OP_KIND_NORMALIZE, + KBTS__OP_KIND_FLAG_JOINING_LETTERS, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES_WITH_USER, + KBTS__OP_KIND_GPOS_METRICS, + KBTS__OP_KIND_GPOS_FEATURES, + KBTS__OP_KIND_STCH_POSTPASS, + KBTS__OP_KIND_POST_GPOS_FIXUP, +}; +static kbts__feature_stage kbts__FeatureStages_ArabicNoRclt[] = { + {1, {{0ull, 0ull, 0ull, 0ull | KBTS__FEATURE_FLAG3(rvrn)}}}, + {5, {{0ull | KBTS__FEATURE_FLAG0(frac) | KBTS__FEATURE_FLAG0(numr) | KBTS__FEATURE_FLAG0(dnom), 0ull, 0ull, 0ull | KBTS__FEATURE_FLAG3(rtla) | KBTS__FEATURE_FLAG3(rtlm)}}}, + {1, {{0ull, 0ull, 0ull, 0ull | KBTS__FEATURE_FLAG3(stch)}}}, + {2, {{0ull | KBTS__FEATURE_FLAG0(ccmp), 0ull, 0ull | KBTS__FEATURE_FLAG2(locl), 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(isol), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(fina), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(fin2), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(fin3), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(medi), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(med2), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(init), 0ull, 0ull, 0ull}}}, + {1, {{0ull, 0ull, 0ull | KBTS__FEATURE_FLAG2(rlig), 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(calt), 0ull, 0ull, 0ull}}}, + {3, {{0ull | KBTS__FEATURE_FLAG0(clig), 0ull, 0ull | KBTS__FEATURE_FLAG2(liga) | KBTS__FEATURE_FLAG2(mset), 0ull}}}, + {7, {{0ull | KBTS__FEATURE_FLAG0(abvm) | KBTS__FEATURE_FLAG0(blwm) | KBTS__FEATURE_FLAG0(curs), 0ull, 0ull | KBTS__FEATURE_FLAG2(mark) | KBTS__FEATURE_FLAG2(mkmk) | KBTS__FEATURE_FLAG2(dist) | KBTS__FEATURE_FLAG2(kern), 0ull}}}, +}; +static kbts__op_list kbts__OpList_ArabicNoRclt = {28, KBTS__ARRAY_LENGTH(kbts__FeatureStages_ArabicNoRclt), kbts__FeatureStages_ArabicNoRclt, KBTS__ARRAY_LENGTH(kbts__Ops_ArabicNoRclt), kbts__Ops_ArabicNoRclt}; +static kbts__op_kind kbts__Ops_Indic[] = { + KBTS__OP_KIND_PRE_NORMALIZE_DOTTED_CIRCLES, + KBTS__OP_KIND_NORMALIZE, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_BEGIN_CLUSTER, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_END_CLUSTER, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_END_SYLLABLE, + KBTS__OP_KIND_GSUB_FEATURES_WITH_USER, + KBTS__OP_KIND_GPOS_METRICS, + KBTS__OP_KIND_GPOS_FEATURES, + KBTS__OP_KIND_POST_GPOS_FIXUP, +}; +static kbts__feature_stage kbts__FeatureStages_Indic[] = { + {1, {{0ull, 0ull, 0ull, 0ull | KBTS__FEATURE_FLAG3(rvrn)}}}, + {5, {{0ull | KBTS__FEATURE_FLAG0(frac) | KBTS__FEATURE_FLAG0(numr) | KBTS__FEATURE_FLAG0(dnom), 0ull, 0ull | KBTS__FEATURE_FLAG2(ltra) | KBTS__FEATURE_FLAG2(ltrm), 0ull}}}, + {1, {{0ull, 0ull, 0ull | KBTS__FEATURE_FLAG2(nukt), 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(akhn), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(rphf), 0ull, 0ull, 0ull}}}, + {1, {{0ull, 0ull, 0ull | KBTS__FEATURE_FLAG2(rkrf), 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(pref), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(blwf), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(abvf), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(half), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(pstf), 0ull, 0ull, 0ull}}}, + {1, {{0ull, 0ull, 0ull, 0ull | KBTS__FEATURE_FLAG3(vatu)}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(cjct), 0ull, 0ull, 0ull}}}, + {6, {{0ull | KBTS__FEATURE_FLAG0(abvs) | KBTS__FEATURE_FLAG0(blws) | KBTS__FEATURE_FLAG0(init), 0ull, 0ull | KBTS__FEATURE_FLAG2(haln) | KBTS__FEATURE_FLAG2(pres) | KBTS__FEATURE_FLAG2(psts), 0ull}}}, + {5, {{0ull | KBTS__FEATURE_FLAG0(calt) | KBTS__FEATURE_FLAG0(clig), 0ull, 0ull | KBTS__FEATURE_FLAG2(locl) | KBTS__FEATURE_FLAG2(rlig) | KBTS__FEATURE_FLAG2(rclt), 0ull}}}, + {7, {{0ull | KBTS__FEATURE_FLAG0(abvm) | KBTS__FEATURE_FLAG0(blwm) | KBTS__FEATURE_FLAG0(curs), 0ull, 0ull | KBTS__FEATURE_FLAG2(mark) | KBTS__FEATURE_FLAG2(mkmk) | KBTS__FEATURE_FLAG2(dist) | KBTS__FEATURE_FLAG2(kern), 0ull}}}, +}; +static kbts__op_list kbts__OpList_Indic = {35, KBTS__ARRAY_LENGTH(kbts__FeatureStages_Indic), kbts__FeatureStages_Indic, KBTS__ARRAY_LENGTH(kbts__Ops_Indic), kbts__Ops_Indic}; +static kbts__op_kind kbts__Ops_Khmer[] = { + KBTS__OP_KIND_PRE_NORMALIZE_DOTTED_CIRCLES, + KBTS__OP_KIND_NORMALIZE, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_BEGIN_CLUSTER, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_END_CLUSTER, + KBTS__OP_KIND_END_SYLLABLE, + KBTS__OP_KIND_GSUB_FEATURES_WITH_USER, + KBTS__OP_KIND_GPOS_METRICS, + KBTS__OP_KIND_GPOS_FEATURES, + KBTS__OP_KIND_POST_GPOS_FIXUP, +}; +static kbts__feature_stage kbts__FeatureStages_Khmer[] = { + {1, {{0ull, 0ull, 0ull, 0ull | KBTS__FEATURE_FLAG3(rvrn)}}}, + {5, {{0ull | KBTS__FEATURE_FLAG0(frac) | KBTS__FEATURE_FLAG0(numr) | KBTS__FEATURE_FLAG0(dnom), 0ull, 0ull | KBTS__FEATURE_FLAG2(ltra) | KBTS__FEATURE_FLAG2(ltrm), 0ull}}}, + {7, {{0ull | KBTS__FEATURE_FLAG0(ccmp) | KBTS__FEATURE_FLAG0(pref) | KBTS__FEATURE_FLAG0(blwf) | KBTS__FEATURE_FLAG0(abvf) | KBTS__FEATURE_FLAG0(pstf) | KBTS__FEATURE_FLAG0(cfar), 0ull, 0ull | KBTS__FEATURE_FLAG2(locl), 0ull}}}, + {8, {{0ull | KBTS__FEATURE_FLAG0(abvs) | KBTS__FEATURE_FLAG0(blws) | KBTS__FEATURE_FLAG0(calt) | KBTS__FEATURE_FLAG0(clig), 0ull, 0ull | KBTS__FEATURE_FLAG2(pres) | KBTS__FEATURE_FLAG2(psts) | KBTS__FEATURE_FLAG2(rclt) | KBTS__FEATURE_FLAG2(rlig), 0ull}}}, + {7, {{0ull | KBTS__FEATURE_FLAG0(abvm) | KBTS__FEATURE_FLAG0(blwm) | KBTS__FEATURE_FLAG0(curs), 0ull, 0ull | KBTS__FEATURE_FLAG2(dist) | KBTS__FEATURE_FLAG2(kern) | KBTS__FEATURE_FLAG2(mark) | KBTS__FEATURE_FLAG2(mkmk), 0ull}}}, +}; +static kbts__op_list kbts__OpList_Khmer = {28, KBTS__ARRAY_LENGTH(kbts__FeatureStages_Khmer), kbts__FeatureStages_Khmer, KBTS__ARRAY_LENGTH(kbts__Ops_Khmer), kbts__Ops_Khmer}; +static kbts__op_kind kbts__Ops_Myanmar[] = { + KBTS__OP_KIND_PRE_NORMALIZE_DOTTED_CIRCLES, + KBTS__OP_KIND_NORMALIZE, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_BEGIN_CLUSTER, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_END_CLUSTER, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_END_SYLLABLE, + KBTS__OP_KIND_GSUB_FEATURES_WITH_USER, + KBTS__OP_KIND_GPOS_METRICS, + KBTS__OP_KIND_GPOS_FEATURES, + KBTS__OP_KIND_POST_GPOS_FIXUP, +}; +static kbts__feature_stage kbts__FeatureStages_Myanmar[] = { + {1, {{0ull, 0ull, 0ull, 0ull | KBTS__FEATURE_FLAG3(rvrn)}}}, + {5, {{0ull | KBTS__FEATURE_FLAG0(frac) | KBTS__FEATURE_FLAG0(numr) | KBTS__FEATURE_FLAG0(dnom), 0ull, 0ull | KBTS__FEATURE_FLAG2(ltra) | KBTS__FEATURE_FLAG2(ltrm), 0ull}}}, + {2, {{0ull | KBTS__FEATURE_FLAG0(ccmp), 0ull, 0ull | KBTS__FEATURE_FLAG2(locl), 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(rphf), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(pref), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(blwf), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(pstf), 0ull, 0ull, 0ull}}}, + {9, {{0ull | KBTS__FEATURE_FLAG0(abvs) | KBTS__FEATURE_FLAG0(blws) | KBTS__FEATURE_FLAG0(calt) | KBTS__FEATURE_FLAG0(clig), 0ull, 0ull | KBTS__FEATURE_FLAG2(pres) | KBTS__FEATURE_FLAG2(psts) | KBTS__FEATURE_FLAG2(rlig) | KBTS__FEATURE_FLAG2(liga) | KBTS__FEATURE_FLAG2(rclt), 0ull}}}, + {7, {{0ull | KBTS__FEATURE_FLAG0(abvm) | KBTS__FEATURE_FLAG0(blwm) | KBTS__FEATURE_FLAG0(curs), 0ull, 0ull | KBTS__FEATURE_FLAG2(dist) | KBTS__FEATURE_FLAG2(kern) | KBTS__FEATURE_FLAG2(mark) | KBTS__FEATURE_FLAG2(mkmk), 0ull}}}, +}; +static kbts__op_list kbts__OpList_Myanmar = {28, KBTS__ARRAY_LENGTH(kbts__FeatureStages_Myanmar), kbts__FeatureStages_Myanmar, KBTS__ARRAY_LENGTH(kbts__Ops_Myanmar), kbts__Ops_Myanmar}; +static kbts__op_kind kbts__Ops_Tibetan[] = { + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES_WITH_USER, + KBTS__OP_KIND_GPOS_METRICS, + KBTS__OP_KIND_GPOS_FEATURES, + KBTS__OP_KIND_POST_GPOS_FIXUP, +}; +static kbts__feature_stage kbts__FeatureStages_Tibetan[] = { + {1, {{0ull, 0ull, 0ull | KBTS__FEATURE_FLAG2(locl), 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(ccmp), 0ull, 0ull, 0ull}}}, + {4, {{0ull | KBTS__FEATURE_FLAG0(abvs) | KBTS__FEATURE_FLAG0(blws) | KBTS__FEATURE_FLAG0(calt), 0ull, 0ull | KBTS__FEATURE_FLAG2(liga), 0ull}}}, + {4, {{0ull | KBTS__FEATURE_FLAG0(abvm) | KBTS__FEATURE_FLAG0(blwm), 0ull, 0ull | KBTS__FEATURE_FLAG2(kern) | KBTS__FEATURE_FLAG2(mkmk), 0ull}}}, +}; +static kbts__op_list kbts__OpList_Tibetan = {10, KBTS__ARRAY_LENGTH(kbts__FeatureStages_Tibetan), kbts__FeatureStages_Tibetan, KBTS__ARRAY_LENGTH(kbts__Ops_Tibetan), kbts__Ops_Tibetan}; +static kbts__op_kind kbts__Ops_Use[] = { + KBTS__OP_KIND_PRE_NORMALIZE_DOTTED_CIRCLES, + KBTS__OP_KIND_NORMALIZE, + KBTS__OP_KIND_FLAG_JOINING_LETTERS, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_BEGIN_CLUSTER, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_END_CLUSTER, + KBTS__OP_KIND_END_SYLLABLE, + KBTS__OP_KIND_GSUB_FEATURES, + KBTS__OP_KIND_GSUB_FEATURES_WITH_USER, + KBTS__OP_KIND_GPOS_METRICS, + KBTS__OP_KIND_GPOS_FEATURES, + KBTS__OP_KIND_POST_GPOS_FIXUP, +}; +static kbts__feature_stage kbts__FeatureStages_Use[] = { + {1, {{0ull, 0ull, 0ull, 0ull | KBTS__FEATURE_FLAG3(rvrn)}}}, + {5, {{0ull | KBTS__FEATURE_FLAG0(frac) | KBTS__FEATURE_FLAG0(numr) | KBTS__FEATURE_FLAG0(dnom), 0ull, 0ull | KBTS__FEATURE_FLAG2(ltra) | KBTS__FEATURE_FLAG2(ltrm), 0ull}}}, + {4, {{0ull | KBTS__FEATURE_FLAG0(ccmp) | KBTS__FEATURE_FLAG0(akhn), 0ull, 0ull | KBTS__FEATURE_FLAG2(locl) | KBTS__FEATURE_FLAG2(nukt), 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(rphf), 0ull, 0ull, 0ull}}}, + {1, {{0ull | KBTS__FEATURE_FLAG0(pref), 0ull, 0ull, 0ull}}}, + {7, {{0ull | KBTS__FEATURE_FLAG0(abvf) | KBTS__FEATURE_FLAG0(blwf) | KBTS__FEATURE_FLAG0(cjct) | KBTS__FEATURE_FLAG0(half) | KBTS__FEATURE_FLAG0(pstf), 0ull, 0ull | KBTS__FEATURE_FLAG2(rkrf), 0ull | KBTS__FEATURE_FLAG3(vatu)}}}, + {4, {{0ull | KBTS__FEATURE_FLAG0(fina) | KBTS__FEATURE_FLAG0(init) | KBTS__FEATURE_FLAG0(isol) | KBTS__FEATURE_FLAG0(medi), 0ull, 0ull, 0ull}}}, + {10, {{0ull | KBTS__FEATURE_FLAG0(abvs) | KBTS__FEATURE_FLAG0(blws) | KBTS__FEATURE_FLAG0(calt) | KBTS__FEATURE_FLAG0(clig), 0ull, 0ull | KBTS__FEATURE_FLAG2(haln) | KBTS__FEATURE_FLAG2(pres) | KBTS__FEATURE_FLAG2(psts) | KBTS__FEATURE_FLAG2(liga) | KBTS__FEATURE_FLAG2(rclt) | KBTS__FEATURE_FLAG2(rlig), 0ull}}}, + {7, {{0ull | KBTS__FEATURE_FLAG0(abvm) | KBTS__FEATURE_FLAG0(blwm) | KBTS__FEATURE_FLAG0(curs), 0ull, 0ull | KBTS__FEATURE_FLAG2(dist) | KBTS__FEATURE_FLAG2(kern) | KBTS__FEATURE_FLAG2(mark) | KBTS__FEATURE_FLAG2(mkmk), 0ull}}}, +}; +static kbts__op_list kbts__OpList_Use = {40, KBTS__ARRAY_LENGTH(kbts__FeatureStages_Use), kbts__FeatureStages_Use, KBTS__ARRAY_LENGTH(kbts__Ops_Use), kbts__Ops_Use}; +#define KBTS__MAXIMUM_DECOMPOSITION_CODEPOINTS 6 +typedef struct kbts__script_properties { kbts_u32 Tag; kbts_shaper Shaper; -} kbts_script_properties; +} kbts__script_properties; -static kbts_script_properties kbts_ScriptProperties[KBTS_SCRIPT_COUNT] = { +static kbts__script_properties kbts__ScriptProperties[KBTS_SCRIPT_COUNT] = { {KBTS_FOURCC(' ', ' ', ' ', ' '), KBTS_SHAPER_DEFAULT}, {KBTS_FOURCC('a', 'd', 'l', 'm'), KBTS_SHAPER_USE}, {KBTS_FOURCC('a', 'h', 'o', 'm'), KBTS_SHAPER_USE}, @@ -3311,261 +4807,261 @@ KBTS_EXPORT kbts_script kbts_ScriptTagToScript(kbts_script_tag Tag) return Result; } -KBTS_EXPORT kbts_feature_id kbts_FeatureTagToId(kbts_feature_tag Tag) +static kbts__feature_id kbts__FeatureTagToId(kbts_feature_tag Tag) { - kbts_feature_id Result = 0; + kbts__feature_id Result = 0; switch(Tag) { - case KBTS_FEATURE_TAG_isol: Result = KBTS_FEATURE_ID_isol; break; - case KBTS_FEATURE_TAG_fina: Result = KBTS_FEATURE_ID_fina; break; - case KBTS_FEATURE_TAG_fin2: Result = KBTS_FEATURE_ID_fin2; break; - case KBTS_FEATURE_TAG_fin3: Result = KBTS_FEATURE_ID_fin3; break; - case KBTS_FEATURE_TAG_medi: Result = KBTS_FEATURE_ID_medi; break; - case KBTS_FEATURE_TAG_med2: Result = KBTS_FEATURE_ID_med2; break; - case KBTS_FEATURE_TAG_init: Result = KBTS_FEATURE_ID_init; break; - case KBTS_FEATURE_TAG_ljmo: Result = KBTS_FEATURE_ID_ljmo; break; - case KBTS_FEATURE_TAG_vjmo: Result = KBTS_FEATURE_ID_vjmo; break; - case KBTS_FEATURE_TAG_tjmo: Result = KBTS_FEATURE_ID_tjmo; break; - case KBTS_FEATURE_TAG_rphf: Result = KBTS_FEATURE_ID_rphf; break; - case KBTS_FEATURE_TAG_blwf: Result = KBTS_FEATURE_ID_blwf; break; - case KBTS_FEATURE_TAG_half: Result = KBTS_FEATURE_ID_half; break; - case KBTS_FEATURE_TAG_pstf: Result = KBTS_FEATURE_ID_pstf; break; - case KBTS_FEATURE_TAG_abvf: Result = KBTS_FEATURE_ID_abvf; break; - case KBTS_FEATURE_TAG_pref: Result = KBTS_FEATURE_ID_pref; break; - case KBTS_FEATURE_TAG_numr: Result = KBTS_FEATURE_ID_numr; break; - case KBTS_FEATURE_TAG_frac: Result = KBTS_FEATURE_ID_frac; break; - case KBTS_FEATURE_TAG_dnom: Result = KBTS_FEATURE_ID_dnom; break; - case KBTS_FEATURE_TAG_cfar: Result = KBTS_FEATURE_ID_cfar; break; - case KBTS_FEATURE_TAG_aalt: Result = KBTS_FEATURE_ID_aalt; break; - case KBTS_FEATURE_TAG_abvm: Result = KBTS_FEATURE_ID_abvm; break; - case KBTS_FEATURE_TAG_abvs: Result = KBTS_FEATURE_ID_abvs; break; - case KBTS_FEATURE_TAG_afrc: Result = KBTS_FEATURE_ID_afrc; break; - case KBTS_FEATURE_TAG_akhn: Result = KBTS_FEATURE_ID_akhn; break; - case KBTS_FEATURE_TAG_apkn: Result = KBTS_FEATURE_ID_apkn; break; - case KBTS_FEATURE_TAG_blwm: Result = KBTS_FEATURE_ID_blwm; break; - case KBTS_FEATURE_TAG_blws: Result = KBTS_FEATURE_ID_blws; break; - case KBTS_FEATURE_TAG_calt: Result = KBTS_FEATURE_ID_calt; break; - case KBTS_FEATURE_TAG_case: Result = KBTS_FEATURE_ID_case; break; - case KBTS_FEATURE_TAG_ccmp: Result = KBTS_FEATURE_ID_ccmp; break; - case KBTS_FEATURE_TAG_chws: Result = KBTS_FEATURE_ID_chws; break; - case KBTS_FEATURE_TAG_cjct: Result = KBTS_FEATURE_ID_cjct; break; - case KBTS_FEATURE_TAG_clig: Result = KBTS_FEATURE_ID_clig; break; - case KBTS_FEATURE_TAG_cpct: Result = KBTS_FEATURE_ID_cpct; break; - case KBTS_FEATURE_TAG_cpsp: Result = KBTS_FEATURE_ID_cpsp; break; - case KBTS_FEATURE_TAG_cswh: Result = KBTS_FEATURE_ID_cswh; break; - case KBTS_FEATURE_TAG_curs: Result = KBTS_FEATURE_ID_curs; break; - case KBTS_FEATURE_TAG_cv01: Result = KBTS_FEATURE_ID_cv01; break; - case KBTS_FEATURE_TAG_cv02: Result = KBTS_FEATURE_ID_cv02; break; - case KBTS_FEATURE_TAG_cv03: Result = KBTS_FEATURE_ID_cv03; break; - case KBTS_FEATURE_TAG_cv04: Result = KBTS_FEATURE_ID_cv04; break; - case KBTS_FEATURE_TAG_cv05: Result = KBTS_FEATURE_ID_cv05; break; - case KBTS_FEATURE_TAG_cv06: Result = KBTS_FEATURE_ID_cv06; break; - case KBTS_FEATURE_TAG_cv07: Result = KBTS_FEATURE_ID_cv07; break; - case KBTS_FEATURE_TAG_cv08: Result = KBTS_FEATURE_ID_cv08; break; - case KBTS_FEATURE_TAG_cv09: Result = KBTS_FEATURE_ID_cv09; break; - case KBTS_FEATURE_TAG_cv10: Result = KBTS_FEATURE_ID_cv10; break; - case KBTS_FEATURE_TAG_cv11: Result = KBTS_FEATURE_ID_cv11; break; - case KBTS_FEATURE_TAG_cv12: Result = KBTS_FEATURE_ID_cv12; break; - case KBTS_FEATURE_TAG_cv13: Result = KBTS_FEATURE_ID_cv13; break; - case KBTS_FEATURE_TAG_cv14: Result = KBTS_FEATURE_ID_cv14; break; - case KBTS_FEATURE_TAG_cv15: Result = KBTS_FEATURE_ID_cv15; break; - case KBTS_FEATURE_TAG_cv16: Result = KBTS_FEATURE_ID_cv16; break; - case KBTS_FEATURE_TAG_cv17: Result = KBTS_FEATURE_ID_cv17; break; - case KBTS_FEATURE_TAG_cv18: Result = KBTS_FEATURE_ID_cv18; break; - case KBTS_FEATURE_TAG_cv19: Result = KBTS_FEATURE_ID_cv19; break; - case KBTS_FEATURE_TAG_cv20: Result = KBTS_FEATURE_ID_cv20; break; - case KBTS_FEATURE_TAG_cv21: Result = KBTS_FEATURE_ID_cv21; break; - case KBTS_FEATURE_TAG_cv22: Result = KBTS_FEATURE_ID_cv22; break; - case KBTS_FEATURE_TAG_cv23: Result = KBTS_FEATURE_ID_cv23; break; - case KBTS_FEATURE_TAG_cv24: Result = KBTS_FEATURE_ID_cv24; break; - case KBTS_FEATURE_TAG_cv25: Result = KBTS_FEATURE_ID_cv25; break; - case KBTS_FEATURE_TAG_cv26: Result = KBTS_FEATURE_ID_cv26; break; - case KBTS_FEATURE_TAG_cv27: Result = KBTS_FEATURE_ID_cv27; break; - case KBTS_FEATURE_TAG_cv28: Result = KBTS_FEATURE_ID_cv28; break; - case KBTS_FEATURE_TAG_cv29: Result = KBTS_FEATURE_ID_cv29; break; - case KBTS_FEATURE_TAG_cv30: Result = KBTS_FEATURE_ID_cv30; break; - case KBTS_FEATURE_TAG_cv31: Result = KBTS_FEATURE_ID_cv31; break; - case KBTS_FEATURE_TAG_cv32: Result = KBTS_FEATURE_ID_cv32; break; - case KBTS_FEATURE_TAG_cv33: Result = KBTS_FEATURE_ID_cv33; break; - case KBTS_FEATURE_TAG_cv34: Result = KBTS_FEATURE_ID_cv34; break; - case KBTS_FEATURE_TAG_cv35: Result = KBTS_FEATURE_ID_cv35; break; - case KBTS_FEATURE_TAG_cv36: Result = KBTS_FEATURE_ID_cv36; break; - case KBTS_FEATURE_TAG_cv37: Result = KBTS_FEATURE_ID_cv37; break; - case KBTS_FEATURE_TAG_cv38: Result = KBTS_FEATURE_ID_cv38; break; - case KBTS_FEATURE_TAG_cv39: Result = KBTS_FEATURE_ID_cv39; break; - case KBTS_FEATURE_TAG_cv40: Result = KBTS_FEATURE_ID_cv40; break; - case KBTS_FEATURE_TAG_cv41: Result = KBTS_FEATURE_ID_cv41; break; - case KBTS_FEATURE_TAG_cv42: Result = KBTS_FEATURE_ID_cv42; break; - case KBTS_FEATURE_TAG_cv43: Result = KBTS_FEATURE_ID_cv43; break; - case KBTS_FEATURE_TAG_cv44: Result = KBTS_FEATURE_ID_cv44; break; - case KBTS_FEATURE_TAG_cv45: Result = KBTS_FEATURE_ID_cv45; break; - case KBTS_FEATURE_TAG_cv46: Result = KBTS_FEATURE_ID_cv46; break; - case KBTS_FEATURE_TAG_cv47: Result = KBTS_FEATURE_ID_cv47; break; - case KBTS_FEATURE_TAG_cv48: Result = KBTS_FEATURE_ID_cv48; break; - case KBTS_FEATURE_TAG_cv49: Result = KBTS_FEATURE_ID_cv49; break; - case KBTS_FEATURE_TAG_cv50: Result = KBTS_FEATURE_ID_cv50; break; - case KBTS_FEATURE_TAG_cv51: Result = KBTS_FEATURE_ID_cv51; break; - case KBTS_FEATURE_TAG_cv52: Result = KBTS_FEATURE_ID_cv52; break; - case KBTS_FEATURE_TAG_cv53: Result = KBTS_FEATURE_ID_cv53; break; - case KBTS_FEATURE_TAG_cv54: Result = KBTS_FEATURE_ID_cv54; break; - case KBTS_FEATURE_TAG_cv55: Result = KBTS_FEATURE_ID_cv55; break; - case KBTS_FEATURE_TAG_cv56: Result = KBTS_FEATURE_ID_cv56; break; - case KBTS_FEATURE_TAG_cv57: Result = KBTS_FEATURE_ID_cv57; break; - case KBTS_FEATURE_TAG_cv58: Result = KBTS_FEATURE_ID_cv58; break; - case KBTS_FEATURE_TAG_cv59: Result = KBTS_FEATURE_ID_cv59; break; - case KBTS_FEATURE_TAG_cv60: Result = KBTS_FEATURE_ID_cv60; break; - case KBTS_FEATURE_TAG_cv61: Result = KBTS_FEATURE_ID_cv61; break; - case KBTS_FEATURE_TAG_cv62: Result = KBTS_FEATURE_ID_cv62; break; - case KBTS_FEATURE_TAG_cv63: Result = KBTS_FEATURE_ID_cv63; break; - case KBTS_FEATURE_TAG_cv64: Result = KBTS_FEATURE_ID_cv64; break; - case KBTS_FEATURE_TAG_cv65: Result = KBTS_FEATURE_ID_cv65; break; - case KBTS_FEATURE_TAG_cv66: Result = KBTS_FEATURE_ID_cv66; break; - case KBTS_FEATURE_TAG_cv67: Result = KBTS_FEATURE_ID_cv67; break; - case KBTS_FEATURE_TAG_cv68: Result = KBTS_FEATURE_ID_cv68; break; - case KBTS_FEATURE_TAG_cv69: Result = KBTS_FEATURE_ID_cv69; break; - case KBTS_FEATURE_TAG_cv70: Result = KBTS_FEATURE_ID_cv70; break; - case KBTS_FEATURE_TAG_cv71: Result = KBTS_FEATURE_ID_cv71; break; - case KBTS_FEATURE_TAG_cv72: Result = KBTS_FEATURE_ID_cv72; break; - case KBTS_FEATURE_TAG_cv73: Result = KBTS_FEATURE_ID_cv73; break; - case KBTS_FEATURE_TAG_cv74: Result = KBTS_FEATURE_ID_cv74; break; - case KBTS_FEATURE_TAG_cv75: Result = KBTS_FEATURE_ID_cv75; break; - case KBTS_FEATURE_TAG_cv76: Result = KBTS_FEATURE_ID_cv76; break; - case KBTS_FEATURE_TAG_cv77: Result = KBTS_FEATURE_ID_cv77; break; - case KBTS_FEATURE_TAG_cv78: Result = KBTS_FEATURE_ID_cv78; break; - case KBTS_FEATURE_TAG_cv79: Result = KBTS_FEATURE_ID_cv79; break; - case KBTS_FEATURE_TAG_cv80: Result = KBTS_FEATURE_ID_cv80; break; - case KBTS_FEATURE_TAG_cv81: Result = KBTS_FEATURE_ID_cv81; break; - case KBTS_FEATURE_TAG_cv82: Result = KBTS_FEATURE_ID_cv82; break; - case KBTS_FEATURE_TAG_cv83: Result = KBTS_FEATURE_ID_cv83; break; - case KBTS_FEATURE_TAG_cv84: Result = KBTS_FEATURE_ID_cv84; break; - case KBTS_FEATURE_TAG_cv85: Result = KBTS_FEATURE_ID_cv85; break; - case KBTS_FEATURE_TAG_cv86: Result = KBTS_FEATURE_ID_cv86; break; - case KBTS_FEATURE_TAG_cv87: Result = KBTS_FEATURE_ID_cv87; break; - case KBTS_FEATURE_TAG_cv88: Result = KBTS_FEATURE_ID_cv88; break; - case KBTS_FEATURE_TAG_cv89: Result = KBTS_FEATURE_ID_cv89; break; - case KBTS_FEATURE_TAG_cv90: Result = KBTS_FEATURE_ID_cv90; break; - case KBTS_FEATURE_TAG_cv91: Result = KBTS_FEATURE_ID_cv91; break; - case KBTS_FEATURE_TAG_cv92: Result = KBTS_FEATURE_ID_cv92; break; - case KBTS_FEATURE_TAG_cv93: Result = KBTS_FEATURE_ID_cv93; break; - case KBTS_FEATURE_TAG_cv94: Result = KBTS_FEATURE_ID_cv94; break; - case KBTS_FEATURE_TAG_cv95: Result = KBTS_FEATURE_ID_cv95; break; - case KBTS_FEATURE_TAG_cv96: Result = KBTS_FEATURE_ID_cv96; break; - case KBTS_FEATURE_TAG_cv97: Result = KBTS_FEATURE_ID_cv97; break; - case KBTS_FEATURE_TAG_cv98: Result = KBTS_FEATURE_ID_cv98; break; - case KBTS_FEATURE_TAG_cv99: Result = KBTS_FEATURE_ID_cv99; break; - case KBTS_FEATURE_TAG_c2pc: Result = KBTS_FEATURE_ID_c2pc; break; - case KBTS_FEATURE_TAG_c2sc: Result = KBTS_FEATURE_ID_c2sc; break; - case KBTS_FEATURE_TAG_dist: Result = KBTS_FEATURE_ID_dist; break; - case KBTS_FEATURE_TAG_dlig: Result = KBTS_FEATURE_ID_dlig; break; - case KBTS_FEATURE_TAG_dtls: Result = KBTS_FEATURE_ID_dtls; break; - case KBTS_FEATURE_TAG_expt: Result = KBTS_FEATURE_ID_expt; break; - case KBTS_FEATURE_TAG_falt: Result = KBTS_FEATURE_ID_falt; break; - case KBTS_FEATURE_TAG_flac: Result = KBTS_FEATURE_ID_flac; break; - case KBTS_FEATURE_TAG_fwid: Result = KBTS_FEATURE_ID_fwid; break; - case KBTS_FEATURE_TAG_haln: Result = KBTS_FEATURE_ID_haln; break; - case KBTS_FEATURE_TAG_halt: Result = KBTS_FEATURE_ID_halt; break; - case KBTS_FEATURE_TAG_hist: Result = KBTS_FEATURE_ID_hist; break; - case KBTS_FEATURE_TAG_hkna: Result = KBTS_FEATURE_ID_hkna; break; - case KBTS_FEATURE_TAG_hlig: Result = KBTS_FEATURE_ID_hlig; break; - case KBTS_FEATURE_TAG_hngl: Result = KBTS_FEATURE_ID_hngl; break; - case KBTS_FEATURE_TAG_hojo: Result = KBTS_FEATURE_ID_hojo; break; - case KBTS_FEATURE_TAG_hwid: Result = KBTS_FEATURE_ID_hwid; break; - case KBTS_FEATURE_TAG_ital: Result = KBTS_FEATURE_ID_ital; break; - case KBTS_FEATURE_TAG_jalt: Result = KBTS_FEATURE_ID_jalt; break; - case KBTS_FEATURE_TAG_jp78: Result = KBTS_FEATURE_ID_jp78; break; - case KBTS_FEATURE_TAG_jp83: Result = KBTS_FEATURE_ID_jp83; break; - case KBTS_FEATURE_TAG_jp90: Result = KBTS_FEATURE_ID_jp90; break; - case KBTS_FEATURE_TAG_jp04: Result = KBTS_FEATURE_ID_jp04; break; - case KBTS_FEATURE_TAG_kern: Result = KBTS_FEATURE_ID_kern; break; - case KBTS_FEATURE_TAG_lfbd: Result = KBTS_FEATURE_ID_lfbd; break; - case KBTS_FEATURE_TAG_liga: Result = KBTS_FEATURE_ID_liga; break; - case KBTS_FEATURE_TAG_lnum: Result = KBTS_FEATURE_ID_lnum; break; - case KBTS_FEATURE_TAG_locl: Result = KBTS_FEATURE_ID_locl; break; - case KBTS_FEATURE_TAG_ltra: Result = KBTS_FEATURE_ID_ltra; break; - case KBTS_FEATURE_TAG_ltrm: Result = KBTS_FEATURE_ID_ltrm; break; - case KBTS_FEATURE_TAG_mark: Result = KBTS_FEATURE_ID_mark; break; - case KBTS_FEATURE_TAG_mgrk: Result = KBTS_FEATURE_ID_mgrk; break; - case KBTS_FEATURE_TAG_mkmk: Result = KBTS_FEATURE_ID_mkmk; break; - case KBTS_FEATURE_TAG_mset: Result = KBTS_FEATURE_ID_mset; break; - case KBTS_FEATURE_TAG_nalt: Result = KBTS_FEATURE_ID_nalt; break; - case KBTS_FEATURE_TAG_nlck: Result = KBTS_FEATURE_ID_nlck; break; - case KBTS_FEATURE_TAG_nukt: Result = KBTS_FEATURE_ID_nukt; break; - case KBTS_FEATURE_TAG_onum: Result = KBTS_FEATURE_ID_onum; break; - case KBTS_FEATURE_TAG_opbd: Result = KBTS_FEATURE_ID_opbd; break; - case KBTS_FEATURE_TAG_ordn: Result = KBTS_FEATURE_ID_ordn; break; - case KBTS_FEATURE_TAG_ornm: Result = KBTS_FEATURE_ID_ornm; break; - case KBTS_FEATURE_TAG_palt: Result = KBTS_FEATURE_ID_palt; break; - case KBTS_FEATURE_TAG_pcap: Result = KBTS_FEATURE_ID_pcap; break; - case KBTS_FEATURE_TAG_pkna: Result = KBTS_FEATURE_ID_pkna; break; - case KBTS_FEATURE_TAG_pnum: Result = KBTS_FEATURE_ID_pnum; break; - case KBTS_FEATURE_TAG_pres: Result = KBTS_FEATURE_ID_pres; break; - case KBTS_FEATURE_TAG_psts: Result = KBTS_FEATURE_ID_psts; break; - case KBTS_FEATURE_TAG_pwid: Result = KBTS_FEATURE_ID_pwid; break; - case KBTS_FEATURE_TAG_qwid: Result = KBTS_FEATURE_ID_qwid; break; - case KBTS_FEATURE_TAG_rand: Result = KBTS_FEATURE_ID_rand; break; - case KBTS_FEATURE_TAG_rclt: Result = KBTS_FEATURE_ID_rclt; break; - case KBTS_FEATURE_TAG_rkrf: Result = KBTS_FEATURE_ID_rkrf; break; - case KBTS_FEATURE_TAG_rlig: Result = KBTS_FEATURE_ID_rlig; break; - case KBTS_FEATURE_TAG_rtbd: Result = KBTS_FEATURE_ID_rtbd; break; - case KBTS_FEATURE_TAG_rtla: Result = KBTS_FEATURE_ID_rtla; break; - case KBTS_FEATURE_TAG_rtlm: Result = KBTS_FEATURE_ID_rtlm; break; - case KBTS_FEATURE_TAG_ruby: Result = KBTS_FEATURE_ID_ruby; break; - case KBTS_FEATURE_TAG_rvrn: Result = KBTS_FEATURE_ID_rvrn; break; - case KBTS_FEATURE_TAG_salt: Result = KBTS_FEATURE_ID_salt; break; - case KBTS_FEATURE_TAG_sinf: Result = KBTS_FEATURE_ID_sinf; break; - case KBTS_FEATURE_TAG_size: Result = KBTS_FEATURE_ID_size; break; - case KBTS_FEATURE_TAG_smcp: Result = KBTS_FEATURE_ID_smcp; break; - case KBTS_FEATURE_TAG_smpl: Result = KBTS_FEATURE_ID_smpl; break; - case KBTS_FEATURE_TAG_ss01: Result = KBTS_FEATURE_ID_ss01; break; - case KBTS_FEATURE_TAG_ss02: Result = KBTS_FEATURE_ID_ss02; break; - case KBTS_FEATURE_TAG_ss03: Result = KBTS_FEATURE_ID_ss03; break; - case KBTS_FEATURE_TAG_ss04: Result = KBTS_FEATURE_ID_ss04; break; - case KBTS_FEATURE_TAG_ss05: Result = KBTS_FEATURE_ID_ss05; break; - case KBTS_FEATURE_TAG_ss06: Result = KBTS_FEATURE_ID_ss06; break; - case KBTS_FEATURE_TAG_ss07: Result = KBTS_FEATURE_ID_ss07; break; - case KBTS_FEATURE_TAG_ss08: Result = KBTS_FEATURE_ID_ss08; break; - case KBTS_FEATURE_TAG_ss09: Result = KBTS_FEATURE_ID_ss09; break; - case KBTS_FEATURE_TAG_ss10: Result = KBTS_FEATURE_ID_ss10; break; - case KBTS_FEATURE_TAG_ss11: Result = KBTS_FEATURE_ID_ss11; break; - case KBTS_FEATURE_TAG_ss12: Result = KBTS_FEATURE_ID_ss12; break; - case KBTS_FEATURE_TAG_ss13: Result = KBTS_FEATURE_ID_ss13; break; - case KBTS_FEATURE_TAG_ss14: Result = KBTS_FEATURE_ID_ss14; break; - case KBTS_FEATURE_TAG_ss15: Result = KBTS_FEATURE_ID_ss15; break; - case KBTS_FEATURE_TAG_ss16: Result = KBTS_FEATURE_ID_ss16; break; - case KBTS_FEATURE_TAG_ss17: Result = KBTS_FEATURE_ID_ss17; break; - case KBTS_FEATURE_TAG_ss18: Result = KBTS_FEATURE_ID_ss18; break; - case KBTS_FEATURE_TAG_ss19: Result = KBTS_FEATURE_ID_ss19; break; - case KBTS_FEATURE_TAG_ss20: Result = KBTS_FEATURE_ID_ss20; break; - case KBTS_FEATURE_TAG_ssty: Result = KBTS_FEATURE_ID_ssty; break; - case KBTS_FEATURE_TAG_stch: Result = KBTS_FEATURE_ID_stch; break; - case KBTS_FEATURE_TAG_subs: Result = KBTS_FEATURE_ID_subs; break; - case KBTS_FEATURE_TAG_sups: Result = KBTS_FEATURE_ID_sups; break; - case KBTS_FEATURE_TAG_swsh: Result = KBTS_FEATURE_ID_swsh; break; - case KBTS_FEATURE_TAG_test: Result = KBTS_FEATURE_ID_test; break; - case KBTS_FEATURE_TAG_titl: Result = KBTS_FEATURE_ID_titl; break; - case KBTS_FEATURE_TAG_tnam: Result = KBTS_FEATURE_ID_tnam; break; - case KBTS_FEATURE_TAG_tnum: Result = KBTS_FEATURE_ID_tnum; break; - case KBTS_FEATURE_TAG_trad: Result = KBTS_FEATURE_ID_trad; break; - case KBTS_FEATURE_TAG_twid: Result = KBTS_FEATURE_ID_twid; break; - case KBTS_FEATURE_TAG_unic: Result = KBTS_FEATURE_ID_unic; break; - case KBTS_FEATURE_TAG_valt: Result = KBTS_FEATURE_ID_valt; break; - case KBTS_FEATURE_TAG_vapk: Result = KBTS_FEATURE_ID_vapk; break; - case KBTS_FEATURE_TAG_vatu: Result = KBTS_FEATURE_ID_vatu; break; - case KBTS_FEATURE_TAG_vchw: Result = KBTS_FEATURE_ID_vchw; break; - case KBTS_FEATURE_TAG_vert: Result = KBTS_FEATURE_ID_vert; break; - case KBTS_FEATURE_TAG_vhal: Result = KBTS_FEATURE_ID_vhal; break; - case KBTS_FEATURE_TAG_vkna: Result = KBTS_FEATURE_ID_vkna; break; - case KBTS_FEATURE_TAG_vkrn: Result = KBTS_FEATURE_ID_vkrn; break; - case KBTS_FEATURE_TAG_vpal: Result = KBTS_FEATURE_ID_vpal; break; - case KBTS_FEATURE_TAG_vrt2: Result = KBTS_FEATURE_ID_vrt2; break; - case KBTS_FEATURE_TAG_vrtr: Result = KBTS_FEATURE_ID_vrtr; break; - case KBTS_FEATURE_TAG_zero: Result = KBTS_FEATURE_ID_zero; break; + case KBTS_FEATURE_TAG_isol: Result = KBTS__FEATURE_ID_isol; break; + case KBTS_FEATURE_TAG_fina: Result = KBTS__FEATURE_ID_fina; break; + case KBTS_FEATURE_TAG_fin2: Result = KBTS__FEATURE_ID_fin2; break; + case KBTS_FEATURE_TAG_fin3: Result = KBTS__FEATURE_ID_fin3; break; + case KBTS_FEATURE_TAG_medi: Result = KBTS__FEATURE_ID_medi; break; + case KBTS_FEATURE_TAG_med2: Result = KBTS__FEATURE_ID_med2; break; + case KBTS_FEATURE_TAG_init: Result = KBTS__FEATURE_ID_init; break; + case KBTS_FEATURE_TAG_ljmo: Result = KBTS__FEATURE_ID_ljmo; break; + case KBTS_FEATURE_TAG_vjmo: Result = KBTS__FEATURE_ID_vjmo; break; + case KBTS_FEATURE_TAG_tjmo: Result = KBTS__FEATURE_ID_tjmo; break; + case KBTS_FEATURE_TAG_rphf: Result = KBTS__FEATURE_ID_rphf; break; + case KBTS_FEATURE_TAG_blwf: Result = KBTS__FEATURE_ID_blwf; break; + case KBTS_FEATURE_TAG_half: Result = KBTS__FEATURE_ID_half; break; + case KBTS_FEATURE_TAG_pstf: Result = KBTS__FEATURE_ID_pstf; break; + case KBTS_FEATURE_TAG_abvf: Result = KBTS__FEATURE_ID_abvf; break; + case KBTS_FEATURE_TAG_pref: Result = KBTS__FEATURE_ID_pref; break; + case KBTS_FEATURE_TAG_numr: Result = KBTS__FEATURE_ID_numr; break; + case KBTS_FEATURE_TAG_frac: Result = KBTS__FEATURE_ID_frac; break; + case KBTS_FEATURE_TAG_dnom: Result = KBTS__FEATURE_ID_dnom; break; + case KBTS_FEATURE_TAG_cfar: Result = KBTS__FEATURE_ID_cfar; break; + case KBTS_FEATURE_TAG_aalt: Result = KBTS__FEATURE_ID_aalt; break; + case KBTS_FEATURE_TAG_abvm: Result = KBTS__FEATURE_ID_abvm; break; + case KBTS_FEATURE_TAG_abvs: Result = KBTS__FEATURE_ID_abvs; break; + case KBTS_FEATURE_TAG_afrc: Result = KBTS__FEATURE_ID_afrc; break; + case KBTS_FEATURE_TAG_akhn: Result = KBTS__FEATURE_ID_akhn; break; + case KBTS_FEATURE_TAG_apkn: Result = KBTS__FEATURE_ID_apkn; break; + case KBTS_FEATURE_TAG_blwm: Result = KBTS__FEATURE_ID_blwm; break; + case KBTS_FEATURE_TAG_blws: Result = KBTS__FEATURE_ID_blws; break; + case KBTS_FEATURE_TAG_calt: Result = KBTS__FEATURE_ID_calt; break; + case KBTS_FEATURE_TAG_case: Result = KBTS__FEATURE_ID_case; break; + case KBTS_FEATURE_TAG_ccmp: Result = KBTS__FEATURE_ID_ccmp; break; + case KBTS_FEATURE_TAG_chws: Result = KBTS__FEATURE_ID_chws; break; + case KBTS_FEATURE_TAG_cjct: Result = KBTS__FEATURE_ID_cjct; break; + case KBTS_FEATURE_TAG_clig: Result = KBTS__FEATURE_ID_clig; break; + case KBTS_FEATURE_TAG_cpct: Result = KBTS__FEATURE_ID_cpct; break; + case KBTS_FEATURE_TAG_cpsp: Result = KBTS__FEATURE_ID_cpsp; break; + case KBTS_FEATURE_TAG_cswh: Result = KBTS__FEATURE_ID_cswh; break; + case KBTS_FEATURE_TAG_curs: Result = KBTS__FEATURE_ID_curs; break; + case KBTS_FEATURE_TAG_cv01: Result = KBTS__FEATURE_ID_cv01; break; + case KBTS_FEATURE_TAG_cv02: Result = KBTS__FEATURE_ID_cv02; break; + case KBTS_FEATURE_TAG_cv03: Result = KBTS__FEATURE_ID_cv03; break; + case KBTS_FEATURE_TAG_cv04: Result = KBTS__FEATURE_ID_cv04; break; + case KBTS_FEATURE_TAG_cv05: Result = KBTS__FEATURE_ID_cv05; break; + case KBTS_FEATURE_TAG_cv06: Result = KBTS__FEATURE_ID_cv06; break; + case KBTS_FEATURE_TAG_cv07: Result = KBTS__FEATURE_ID_cv07; break; + case KBTS_FEATURE_TAG_cv08: Result = KBTS__FEATURE_ID_cv08; break; + case KBTS_FEATURE_TAG_cv09: Result = KBTS__FEATURE_ID_cv09; break; + case KBTS_FEATURE_TAG_cv10: Result = KBTS__FEATURE_ID_cv10; break; + case KBTS_FEATURE_TAG_cv11: Result = KBTS__FEATURE_ID_cv11; break; + case KBTS_FEATURE_TAG_cv12: Result = KBTS__FEATURE_ID_cv12; break; + case KBTS_FEATURE_TAG_cv13: Result = KBTS__FEATURE_ID_cv13; break; + case KBTS_FEATURE_TAG_cv14: Result = KBTS__FEATURE_ID_cv14; break; + case KBTS_FEATURE_TAG_cv15: Result = KBTS__FEATURE_ID_cv15; break; + case KBTS_FEATURE_TAG_cv16: Result = KBTS__FEATURE_ID_cv16; break; + case KBTS_FEATURE_TAG_cv17: Result = KBTS__FEATURE_ID_cv17; break; + case KBTS_FEATURE_TAG_cv18: Result = KBTS__FEATURE_ID_cv18; break; + case KBTS_FEATURE_TAG_cv19: Result = KBTS__FEATURE_ID_cv19; break; + case KBTS_FEATURE_TAG_cv20: Result = KBTS__FEATURE_ID_cv20; break; + case KBTS_FEATURE_TAG_cv21: Result = KBTS__FEATURE_ID_cv21; break; + case KBTS_FEATURE_TAG_cv22: Result = KBTS__FEATURE_ID_cv22; break; + case KBTS_FEATURE_TAG_cv23: Result = KBTS__FEATURE_ID_cv23; break; + case KBTS_FEATURE_TAG_cv24: Result = KBTS__FEATURE_ID_cv24; break; + case KBTS_FEATURE_TAG_cv25: Result = KBTS__FEATURE_ID_cv25; break; + case KBTS_FEATURE_TAG_cv26: Result = KBTS__FEATURE_ID_cv26; break; + case KBTS_FEATURE_TAG_cv27: Result = KBTS__FEATURE_ID_cv27; break; + case KBTS_FEATURE_TAG_cv28: Result = KBTS__FEATURE_ID_cv28; break; + case KBTS_FEATURE_TAG_cv29: Result = KBTS__FEATURE_ID_cv29; break; + case KBTS_FEATURE_TAG_cv30: Result = KBTS__FEATURE_ID_cv30; break; + case KBTS_FEATURE_TAG_cv31: Result = KBTS__FEATURE_ID_cv31; break; + case KBTS_FEATURE_TAG_cv32: Result = KBTS__FEATURE_ID_cv32; break; + case KBTS_FEATURE_TAG_cv33: Result = KBTS__FEATURE_ID_cv33; break; + case KBTS_FEATURE_TAG_cv34: Result = KBTS__FEATURE_ID_cv34; break; + case KBTS_FEATURE_TAG_cv35: Result = KBTS__FEATURE_ID_cv35; break; + case KBTS_FEATURE_TAG_cv36: Result = KBTS__FEATURE_ID_cv36; break; + case KBTS_FEATURE_TAG_cv37: Result = KBTS__FEATURE_ID_cv37; break; + case KBTS_FEATURE_TAG_cv38: Result = KBTS__FEATURE_ID_cv38; break; + case KBTS_FEATURE_TAG_cv39: Result = KBTS__FEATURE_ID_cv39; break; + case KBTS_FEATURE_TAG_cv40: Result = KBTS__FEATURE_ID_cv40; break; + case KBTS_FEATURE_TAG_cv41: Result = KBTS__FEATURE_ID_cv41; break; + case KBTS_FEATURE_TAG_cv42: Result = KBTS__FEATURE_ID_cv42; break; + case KBTS_FEATURE_TAG_cv43: Result = KBTS__FEATURE_ID_cv43; break; + case KBTS_FEATURE_TAG_cv44: Result = KBTS__FEATURE_ID_cv44; break; + case KBTS_FEATURE_TAG_cv45: Result = KBTS__FEATURE_ID_cv45; break; + case KBTS_FEATURE_TAG_cv46: Result = KBTS__FEATURE_ID_cv46; break; + case KBTS_FEATURE_TAG_cv47: Result = KBTS__FEATURE_ID_cv47; break; + case KBTS_FEATURE_TAG_cv48: Result = KBTS__FEATURE_ID_cv48; break; + case KBTS_FEATURE_TAG_cv49: Result = KBTS__FEATURE_ID_cv49; break; + case KBTS_FEATURE_TAG_cv50: Result = KBTS__FEATURE_ID_cv50; break; + case KBTS_FEATURE_TAG_cv51: Result = KBTS__FEATURE_ID_cv51; break; + case KBTS_FEATURE_TAG_cv52: Result = KBTS__FEATURE_ID_cv52; break; + case KBTS_FEATURE_TAG_cv53: Result = KBTS__FEATURE_ID_cv53; break; + case KBTS_FEATURE_TAG_cv54: Result = KBTS__FEATURE_ID_cv54; break; + case KBTS_FEATURE_TAG_cv55: Result = KBTS__FEATURE_ID_cv55; break; + case KBTS_FEATURE_TAG_cv56: Result = KBTS__FEATURE_ID_cv56; break; + case KBTS_FEATURE_TAG_cv57: Result = KBTS__FEATURE_ID_cv57; break; + case KBTS_FEATURE_TAG_cv58: Result = KBTS__FEATURE_ID_cv58; break; + case KBTS_FEATURE_TAG_cv59: Result = KBTS__FEATURE_ID_cv59; break; + case KBTS_FEATURE_TAG_cv60: Result = KBTS__FEATURE_ID_cv60; break; + case KBTS_FEATURE_TAG_cv61: Result = KBTS__FEATURE_ID_cv61; break; + case KBTS_FEATURE_TAG_cv62: Result = KBTS__FEATURE_ID_cv62; break; + case KBTS_FEATURE_TAG_cv63: Result = KBTS__FEATURE_ID_cv63; break; + case KBTS_FEATURE_TAG_cv64: Result = KBTS__FEATURE_ID_cv64; break; + case KBTS_FEATURE_TAG_cv65: Result = KBTS__FEATURE_ID_cv65; break; + case KBTS_FEATURE_TAG_cv66: Result = KBTS__FEATURE_ID_cv66; break; + case KBTS_FEATURE_TAG_cv67: Result = KBTS__FEATURE_ID_cv67; break; + case KBTS_FEATURE_TAG_cv68: Result = KBTS__FEATURE_ID_cv68; break; + case KBTS_FEATURE_TAG_cv69: Result = KBTS__FEATURE_ID_cv69; break; + case KBTS_FEATURE_TAG_cv70: Result = KBTS__FEATURE_ID_cv70; break; + case KBTS_FEATURE_TAG_cv71: Result = KBTS__FEATURE_ID_cv71; break; + case KBTS_FEATURE_TAG_cv72: Result = KBTS__FEATURE_ID_cv72; break; + case KBTS_FEATURE_TAG_cv73: Result = KBTS__FEATURE_ID_cv73; break; + case KBTS_FEATURE_TAG_cv74: Result = KBTS__FEATURE_ID_cv74; break; + case KBTS_FEATURE_TAG_cv75: Result = KBTS__FEATURE_ID_cv75; break; + case KBTS_FEATURE_TAG_cv76: Result = KBTS__FEATURE_ID_cv76; break; + case KBTS_FEATURE_TAG_cv77: Result = KBTS__FEATURE_ID_cv77; break; + case KBTS_FEATURE_TAG_cv78: Result = KBTS__FEATURE_ID_cv78; break; + case KBTS_FEATURE_TAG_cv79: Result = KBTS__FEATURE_ID_cv79; break; + case KBTS_FEATURE_TAG_cv80: Result = KBTS__FEATURE_ID_cv80; break; + case KBTS_FEATURE_TAG_cv81: Result = KBTS__FEATURE_ID_cv81; break; + case KBTS_FEATURE_TAG_cv82: Result = KBTS__FEATURE_ID_cv82; break; + case KBTS_FEATURE_TAG_cv83: Result = KBTS__FEATURE_ID_cv83; break; + case KBTS_FEATURE_TAG_cv84: Result = KBTS__FEATURE_ID_cv84; break; + case KBTS_FEATURE_TAG_cv85: Result = KBTS__FEATURE_ID_cv85; break; + case KBTS_FEATURE_TAG_cv86: Result = KBTS__FEATURE_ID_cv86; break; + case KBTS_FEATURE_TAG_cv87: Result = KBTS__FEATURE_ID_cv87; break; + case KBTS_FEATURE_TAG_cv88: Result = KBTS__FEATURE_ID_cv88; break; + case KBTS_FEATURE_TAG_cv89: Result = KBTS__FEATURE_ID_cv89; break; + case KBTS_FEATURE_TAG_cv90: Result = KBTS__FEATURE_ID_cv90; break; + case KBTS_FEATURE_TAG_cv91: Result = KBTS__FEATURE_ID_cv91; break; + case KBTS_FEATURE_TAG_cv92: Result = KBTS__FEATURE_ID_cv92; break; + case KBTS_FEATURE_TAG_cv93: Result = KBTS__FEATURE_ID_cv93; break; + case KBTS_FEATURE_TAG_cv94: Result = KBTS__FEATURE_ID_cv94; break; + case KBTS_FEATURE_TAG_cv95: Result = KBTS__FEATURE_ID_cv95; break; + case KBTS_FEATURE_TAG_cv96: Result = KBTS__FEATURE_ID_cv96; break; + case KBTS_FEATURE_TAG_cv97: Result = KBTS__FEATURE_ID_cv97; break; + case KBTS_FEATURE_TAG_cv98: Result = KBTS__FEATURE_ID_cv98; break; + case KBTS_FEATURE_TAG_cv99: Result = KBTS__FEATURE_ID_cv99; break; + case KBTS_FEATURE_TAG_c2pc: Result = KBTS__FEATURE_ID_c2pc; break; + case KBTS_FEATURE_TAG_c2sc: Result = KBTS__FEATURE_ID_c2sc; break; + case KBTS_FEATURE_TAG_dist: Result = KBTS__FEATURE_ID_dist; break; + case KBTS_FEATURE_TAG_dlig: Result = KBTS__FEATURE_ID_dlig; break; + case KBTS_FEATURE_TAG_dtls: Result = KBTS__FEATURE_ID_dtls; break; + case KBTS_FEATURE_TAG_expt: Result = KBTS__FEATURE_ID_expt; break; + case KBTS_FEATURE_TAG_falt: Result = KBTS__FEATURE_ID_falt; break; + case KBTS_FEATURE_TAG_flac: Result = KBTS__FEATURE_ID_flac; break; + case KBTS_FEATURE_TAG_fwid: Result = KBTS__FEATURE_ID_fwid; break; + case KBTS_FEATURE_TAG_haln: Result = KBTS__FEATURE_ID_haln; break; + case KBTS_FEATURE_TAG_halt: Result = KBTS__FEATURE_ID_halt; break; + case KBTS_FEATURE_TAG_hist: Result = KBTS__FEATURE_ID_hist; break; + case KBTS_FEATURE_TAG_hkna: Result = KBTS__FEATURE_ID_hkna; break; + case KBTS_FEATURE_TAG_hlig: Result = KBTS__FEATURE_ID_hlig; break; + case KBTS_FEATURE_TAG_hngl: Result = KBTS__FEATURE_ID_hngl; break; + case KBTS_FEATURE_TAG_hojo: Result = KBTS__FEATURE_ID_hojo; break; + case KBTS_FEATURE_TAG_hwid: Result = KBTS__FEATURE_ID_hwid; break; + case KBTS_FEATURE_TAG_ital: Result = KBTS__FEATURE_ID_ital; break; + case KBTS_FEATURE_TAG_jalt: Result = KBTS__FEATURE_ID_jalt; break; + case KBTS_FEATURE_TAG_jp78: Result = KBTS__FEATURE_ID_jp78; break; + case KBTS_FEATURE_TAG_jp83: Result = KBTS__FEATURE_ID_jp83; break; + case KBTS_FEATURE_TAG_jp90: Result = KBTS__FEATURE_ID_jp90; break; + case KBTS_FEATURE_TAG_jp04: Result = KBTS__FEATURE_ID_jp04; break; + case KBTS_FEATURE_TAG_kern: Result = KBTS__FEATURE_ID_kern; break; + case KBTS_FEATURE_TAG_lfbd: Result = KBTS__FEATURE_ID_lfbd; break; + case KBTS_FEATURE_TAG_liga: Result = KBTS__FEATURE_ID_liga; break; + case KBTS_FEATURE_TAG_lnum: Result = KBTS__FEATURE_ID_lnum; break; + case KBTS_FEATURE_TAG_locl: Result = KBTS__FEATURE_ID_locl; break; + case KBTS_FEATURE_TAG_ltra: Result = KBTS__FEATURE_ID_ltra; break; + case KBTS_FEATURE_TAG_ltrm: Result = KBTS__FEATURE_ID_ltrm; break; + case KBTS_FEATURE_TAG_mark: Result = KBTS__FEATURE_ID_mark; break; + case KBTS_FEATURE_TAG_mgrk: Result = KBTS__FEATURE_ID_mgrk; break; + case KBTS_FEATURE_TAG_mkmk: Result = KBTS__FEATURE_ID_mkmk; break; + case KBTS_FEATURE_TAG_mset: Result = KBTS__FEATURE_ID_mset; break; + case KBTS_FEATURE_TAG_nalt: Result = KBTS__FEATURE_ID_nalt; break; + case KBTS_FEATURE_TAG_nlck: Result = KBTS__FEATURE_ID_nlck; break; + case KBTS_FEATURE_TAG_nukt: Result = KBTS__FEATURE_ID_nukt; break; + case KBTS_FEATURE_TAG_onum: Result = KBTS__FEATURE_ID_onum; break; + case KBTS_FEATURE_TAG_opbd: Result = KBTS__FEATURE_ID_opbd; break; + case KBTS_FEATURE_TAG_ordn: Result = KBTS__FEATURE_ID_ordn; break; + case KBTS_FEATURE_TAG_ornm: Result = KBTS__FEATURE_ID_ornm; break; + case KBTS_FEATURE_TAG_palt: Result = KBTS__FEATURE_ID_palt; break; + case KBTS_FEATURE_TAG_pcap: Result = KBTS__FEATURE_ID_pcap; break; + case KBTS_FEATURE_TAG_pkna: Result = KBTS__FEATURE_ID_pkna; break; + case KBTS_FEATURE_TAG_pnum: Result = KBTS__FEATURE_ID_pnum; break; + case KBTS_FEATURE_TAG_pres: Result = KBTS__FEATURE_ID_pres; break; + case KBTS_FEATURE_TAG_psts: Result = KBTS__FEATURE_ID_psts; break; + case KBTS_FEATURE_TAG_pwid: Result = KBTS__FEATURE_ID_pwid; break; + case KBTS_FEATURE_TAG_qwid: Result = KBTS__FEATURE_ID_qwid; break; + case KBTS_FEATURE_TAG_rand: Result = KBTS__FEATURE_ID_rand; break; + case KBTS_FEATURE_TAG_rclt: Result = KBTS__FEATURE_ID_rclt; break; + case KBTS_FEATURE_TAG_rkrf: Result = KBTS__FEATURE_ID_rkrf; break; + case KBTS_FEATURE_TAG_rlig: Result = KBTS__FEATURE_ID_rlig; break; + case KBTS_FEATURE_TAG_rtbd: Result = KBTS__FEATURE_ID_rtbd; break; + case KBTS_FEATURE_TAG_rtla: Result = KBTS__FEATURE_ID_rtla; break; + case KBTS_FEATURE_TAG_rtlm: Result = KBTS__FEATURE_ID_rtlm; break; + case KBTS_FEATURE_TAG_ruby: Result = KBTS__FEATURE_ID_ruby; break; + case KBTS_FEATURE_TAG_rvrn: Result = KBTS__FEATURE_ID_rvrn; break; + case KBTS_FEATURE_TAG_salt: Result = KBTS__FEATURE_ID_salt; break; + case KBTS_FEATURE_TAG_sinf: Result = KBTS__FEATURE_ID_sinf; break; + case KBTS_FEATURE_TAG_size: Result = KBTS__FEATURE_ID_size; break; + case KBTS_FEATURE_TAG_smcp: Result = KBTS__FEATURE_ID_smcp; break; + case KBTS_FEATURE_TAG_smpl: Result = KBTS__FEATURE_ID_smpl; break; + case KBTS_FEATURE_TAG_ss01: Result = KBTS__FEATURE_ID_ss01; break; + case KBTS_FEATURE_TAG_ss02: Result = KBTS__FEATURE_ID_ss02; break; + case KBTS_FEATURE_TAG_ss03: Result = KBTS__FEATURE_ID_ss03; break; + case KBTS_FEATURE_TAG_ss04: Result = KBTS__FEATURE_ID_ss04; break; + case KBTS_FEATURE_TAG_ss05: Result = KBTS__FEATURE_ID_ss05; break; + case KBTS_FEATURE_TAG_ss06: Result = KBTS__FEATURE_ID_ss06; break; + case KBTS_FEATURE_TAG_ss07: Result = KBTS__FEATURE_ID_ss07; break; + case KBTS_FEATURE_TAG_ss08: Result = KBTS__FEATURE_ID_ss08; break; + case KBTS_FEATURE_TAG_ss09: Result = KBTS__FEATURE_ID_ss09; break; + case KBTS_FEATURE_TAG_ss10: Result = KBTS__FEATURE_ID_ss10; break; + case KBTS_FEATURE_TAG_ss11: Result = KBTS__FEATURE_ID_ss11; break; + case KBTS_FEATURE_TAG_ss12: Result = KBTS__FEATURE_ID_ss12; break; + case KBTS_FEATURE_TAG_ss13: Result = KBTS__FEATURE_ID_ss13; break; + case KBTS_FEATURE_TAG_ss14: Result = KBTS__FEATURE_ID_ss14; break; + case KBTS_FEATURE_TAG_ss15: Result = KBTS__FEATURE_ID_ss15; break; + case KBTS_FEATURE_TAG_ss16: Result = KBTS__FEATURE_ID_ss16; break; + case KBTS_FEATURE_TAG_ss17: Result = KBTS__FEATURE_ID_ss17; break; + case KBTS_FEATURE_TAG_ss18: Result = KBTS__FEATURE_ID_ss18; break; + case KBTS_FEATURE_TAG_ss19: Result = KBTS__FEATURE_ID_ss19; break; + case KBTS_FEATURE_TAG_ss20: Result = KBTS__FEATURE_ID_ss20; break; + case KBTS_FEATURE_TAG_ssty: Result = KBTS__FEATURE_ID_ssty; break; + case KBTS_FEATURE_TAG_stch: Result = KBTS__FEATURE_ID_stch; break; + case KBTS_FEATURE_TAG_subs: Result = KBTS__FEATURE_ID_subs; break; + case KBTS_FEATURE_TAG_sups: Result = KBTS__FEATURE_ID_sups; break; + case KBTS_FEATURE_TAG_swsh: Result = KBTS__FEATURE_ID_swsh; break; + case KBTS_FEATURE_TAG_test: Result = KBTS__FEATURE_ID_test; break; + case KBTS_FEATURE_TAG_titl: Result = KBTS__FEATURE_ID_titl; break; + case KBTS_FEATURE_TAG_tnam: Result = KBTS__FEATURE_ID_tnam; break; + case KBTS_FEATURE_TAG_tnum: Result = KBTS__FEATURE_ID_tnum; break; + case KBTS_FEATURE_TAG_trad: Result = KBTS__FEATURE_ID_trad; break; + case KBTS_FEATURE_TAG_twid: Result = KBTS__FEATURE_ID_twid; break; + case KBTS_FEATURE_TAG_unic: Result = KBTS__FEATURE_ID_unic; break; + case KBTS_FEATURE_TAG_valt: Result = KBTS__FEATURE_ID_valt; break; + case KBTS_FEATURE_TAG_vapk: Result = KBTS__FEATURE_ID_vapk; break; + case KBTS_FEATURE_TAG_vatu: Result = KBTS__FEATURE_ID_vatu; break; + case KBTS_FEATURE_TAG_vchw: Result = KBTS__FEATURE_ID_vchw; break; + case KBTS_FEATURE_TAG_vert: Result = KBTS__FEATURE_ID_vert; break; + case KBTS_FEATURE_TAG_vhal: Result = KBTS__FEATURE_ID_vhal; break; + case KBTS_FEATURE_TAG_vkna: Result = KBTS__FEATURE_ID_vkna; break; + case KBTS_FEATURE_TAG_vkrn: Result = KBTS__FEATURE_ID_vkrn; break; + case KBTS_FEATURE_TAG_vpal: Result = KBTS__FEATURE_ID_vpal; break; + case KBTS_FEATURE_TAG_vrt2: Result = KBTS__FEATURE_ID_vrt2; break; + case KBTS_FEATURE_TAG_vrtr: Result = KBTS__FEATURE_ID_vrtr; break; + case KBTS_FEATURE_TAG_zero: Result = KBTS__FEATURE_ID_zero; break; default: break; } return Result; } -static kbts_s32 kbts_UnicodeParentDeltas[1679] = { +static kbts_s32 kbts__UnicodeParentDeltas[1679] = { 132,133,134,135,244,246,248,250,252,254,315,351,416,418,7678,7680,7682,7792,7794,132,133,134,135,275,277,279,281,283,285,346,382,447, 449,7709,7711,7713,7823,7825,131,132,133,134,174,176,178,180,182,416,418,452,7604,7606,7764,7766,7768,131,132,133,134,205,207,209,211,213, 447,449,483,7635,7637,7795,7797,7799,127,128,129,130,131,132,160,162,164,365,416,418,454,7584,7744,7746,127,128,129,130,131,132,191,193, @@ -3621,7 +5117,24 @@ static kbts_s32 kbts_UnicodeParentDeltas[1679] = { 180071,180102,180152,180175,180238,180262,180308,180469,180588,180601,181007,181056,181082,181102,181519, }; -static kbts_u8 kbts_UnicodeDecomposition_PageIndices[17407] = { +static kbts_u8 kbts__ScriptExtensions[447] = { + 6,18,24,25,35,37,41,42,43,45,47,72,79,80,112,132,11,28,32,72,77,155,160,13,72,72,155,22,25,28,45,72, + 112,141,146,22,28,45,72,119,141,146,159,22,28,72,157,42,72,141,143,155,19,22,25,28,43,45,72,119,143,157,159,25, + 37,42,43,62,72,25,35,54,72,112,143,146,157,159,5,28,35,43,45,54,72,112,143,146,35,72,143,22,28,72,119,22, + 72,146,39,72,28,72,159,45,72,112,159,22,35,62,72,143,22,35,72,143,22,72,143,19,22,43,72,141,155,19,72,159, + 25,45,28,112,28,42,5,41,42,4,40,51,103,143,154,167,4,143,154,1,4,40,51,103,143,154,167,1,4,51,83,84, + 117,126,135,143,4,154,167,11,32,44,46,48,61,72,82,118,131,150,153,158,11,32,44,46,48,61,72,82,118,150,153,158, + 11,32,34,44,46,47,48,61,69,80,82,86,100,108,118,136,142,149,150,153,158,11,32,34,44,46,47,48,49,61,69,74, + 80,82,86,100,108,118,136,142,149,150,153,158,32,34,60,80,11,20,142,48,96,46,68,44,150,61,100,161,20,97,146,41, + 42,72,16,52,144,145,94,124,11,32,44,61,32,131,32,61,82,118,150,153,32,100,11,32,44,61,82,100,118,136,153,158, + 161,32,44,61,161,28,72,143,72,94,124,18,41,42,78,110,116,18,45,91,110,32,44,72,25,72,6,116,6,18,41,60, + 79,110,129,1,4,110,24,152,13,24,50,55,62,94,168,13,24,50,55,62,94,124,168,13,24,50,55,62,94,156,168,13, + 24,50,55,62,77,94,156,168,13,24,50,55,62,168,24,55,62,24,72,32,34,46,48,60,61,68,69,80,82,93,100,131, + 149,158,161,32,34,46,48,60,61,68,69,80,93,100,131,149,158,161,32,34,46,48,60,68,69,80,93,149,158,32,34,46, + 48,60,68,69,80,93,131,149,158,11,32,161,32,150,64,72,97,15,59,4,103,26,27,76,26,76,26,75,76,4,25, +}; + +static kbts_u8 kbts__UnicodeDecomposition_PageIndices[17407] = { 0,1,1,2,3,4,5,6,7,1,1,1,1,8,9,10,11,12,1,13,1,1,1,1,14,1,1,15,1,1,1,1, 1,1,1,1,16,17,1,18,19,20,1,1,1,21,1,22,1,23,1,24,1,25,1,26,1,1,1,1,1,27,28,1, 29,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,30,31, @@ -4168,9 +5681,9 @@ static kbts_u8 kbts_UnicodeDecomposition_PageIndices[17407] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, }; -static kbts_u64 kbts_UnicodeDecomposition_Data[5632] = { +static kbts_u64 kbts__UnicodeDecomposition_Data[5632] = { 52776558133248ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, - 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,343932928ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, 6442451206ull,6450839814ull,6459228422ull,6467617030ull,6509560070ull,6526337286ull,0ull,6769606926ull,6442451222ull,6450839830ull,6459228438ull,6509560086ull,6442451238ull,6450839846ull,6459228454ull,6509560102ull,0ull,6467617082ull,6442451262ull,6450839870ull,6459228478ull,6467617086ull,6509560126ull,0ull,0ull,6442451286ull,6450839894ull,6459228502ull,6509560150ull,6450839910ull,0ull,0ull, @@ -4347,12 +5860,12 @@ static kbts_u64 kbts_UnicodeDecomposition_Data[5632] = { 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, }; -KBTS_INLINE kbts_u64 kbts_GetUnicodeDecomposition(kbts_u32 Codepoint) +KBTS_INLINE kbts_u64 kbts__GetUnicodeDecomposition(kbts_u32 Codepoint) { - return kbts_UnicodeDecomposition_Data[((kbts_un)kbts_UnicodeDecomposition_PageIndices[Codepoint/64] * 64) | (Codepoint & 63)]; + return (Codepoint < 1114110) ? kbts__UnicodeDecomposition_Data[((kbts_un)kbts__UnicodeDecomposition_PageIndices[Codepoint/64] * 64) | (Codepoint & 63)] : 0; } -static kbts_u8 kbts_UnicodeWordBreakClass_PageIndices[8703] = { +static kbts_u8 kbts__UnicodeWordBreakClass_PageIndices[8703] = { 0,1,2,2,2,3,4,5,2,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,2,2,31,32,33,34,35,2,2,2,36,37,38,39,40,41,42,43,44,45,46,47,48,49,2,50,2,2,51,52, 53,54,55,56,57,57,58,59,57,60,57,61,62,63,64,65,57,57,66,57,57,57,67,57,2,68,69,70,71,57,57,57, @@ -4627,7 +6140,7 @@ static kbts_u8 kbts_UnicodeWordBreakClass_PageIndices[8703] = { 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, }; -static kbts_u8 kbts_UnicodeWordBreakClass_Data[27648] = { +static kbts_u8 kbts__UnicodeWordBreakClass_Data[27648] = { 0,0,0,0,0,0,0,0,0,0,3,4,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,14,0,0,0,0,13,0,0,0,0,17,0,15,0,18,18,18,18,18,18,18,18,18,18,16,17,0,0,0,0, 0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,19,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0, 0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,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,11,0,0,8,1,0,0,0,0,0,0,11,0,16,0,0,11,0,0,0,0,0, @@ -5062,12 +6575,12 @@ static kbts_u8 kbts_UnicodeWordBreakClass_Data[27648] = { 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, }; -KBTS_INLINE kbts_u8 kbts_GetUnicodeWordBreakClass(kbts_u32 Codepoint) +KBTS_INLINE kbts_u8 kbts__GetUnicodeWordBreakClass(kbts_u32 Codepoint) { - return kbts_UnicodeWordBreakClass_Data[((kbts_un)kbts_UnicodeWordBreakClass_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; + return (Codepoint < 1114110) ? kbts__UnicodeWordBreakClass_Data[((kbts_un)kbts__UnicodeWordBreakClass_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)] : 0; } -static kbts_u8 kbts_UnicodeLineBreakClass_PageIndices[8703] = { +static kbts_u8 kbts__UnicodeLineBreakClass_PageIndices[8703] = { 0,1,2,2,2,3,4,2,2,5,2,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,2,2,31,2,32,2,2,2,2,33,34,35,36,37,38,39,40,41,42,43,44,45,2,46,2,2,2,47, 48,49,50,2,51,52,53,54,2,2,2,55,56,57,58,59,2,2,2,60,2,2,61,2,2,62,63,64,65,66,67,68, @@ -5342,7 +6855,7 @@ static kbts_u8 kbts_UnicodeLineBreakClass_PageIndices[8703] = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, }; -static kbts_u8 kbts_UnicodeLineBreakClass_Data[26752] = { +static kbts_u8 kbts__UnicodeLineBreakClass_Data[26752] = { 63,63,63,63,63,63,63,63,63,19,5,3,3,4,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,7,16,23,37,40,48,37,23,21,14,37,40,26,31,26,18,39,39,39,39,39,39,39,39,39,39,26,26,37,37,37,16, 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,21,40,14,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,21,19,12,37,63, 63,63,63,63,63,6,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,10,21,48,40,40,40,37,37,37,37,37,24,37,19,37,37,48,40,37,37,35,37,37,37,37,37,37,25,37,37,37,21, @@ -5763,12 +7276,12 @@ static kbts_u8 kbts_UnicodeLineBreakClass_Data[26752] = { 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, }; -KBTS_INLINE kbts_u8 kbts_GetUnicodeLineBreakClass(kbts_u32 Codepoint) +KBTS_INLINE kbts_u8 kbts__GetUnicodeLineBreakClass(kbts_u32 Codepoint) { - return kbts_UnicodeLineBreakClass_Data[((kbts_un)kbts_UnicodeLineBreakClass_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; + return (Codepoint < 1114110) ? kbts__UnicodeLineBreakClass_Data[((kbts_un)kbts__UnicodeLineBreakClass_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)] : 0; } -static kbts_u8 kbts_UnicodeGraphemeBreakClass_PageIndices[8703] = { +static kbts_u8 kbts__UnicodeGraphemeBreakClass_PageIndices[8703] = { 0,1,2,2,2,2,3,2,2,4,2,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,2,2,30,2,2,2,2,2,2,2,31,32,33,34,35,2,36,37,38,39,40,41,2,42,2,2,2,2, 43,44,45,46,2,2,47,48,2,49,2,50,51,52,53,54,2,2,55,2,2,2,56,2,2,57,58,59,2,2,2,2, @@ -6043,7 +7556,7 @@ static kbts_u8 kbts_UnicodeGraphemeBreakClass_PageIndices[8703] = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, }; -static kbts_u8 kbts_UnicodeGraphemeBreakClass_Data[20096] = { +static kbts_u8 kbts__UnicodeGraphemeBreakClass_Data[20096] = { 3,3,3,3,3,3,3,3,3,3,2,0,3,1,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,16,0,0,0,3,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -6360,12 +7873,12 @@ static kbts_u8 kbts_UnicodeGraphemeBreakClass_Data[20096] = { 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, }; -KBTS_INLINE kbts_u8 kbts_GetUnicodeGraphemeBreakClass(kbts_u32 Codepoint) +KBTS_INLINE kbts_u8 kbts__GetUnicodeGraphemeBreakClass(kbts_u32 Codepoint) { - return kbts_UnicodeGraphemeBreakClass_Data[((kbts_un)kbts_UnicodeGraphemeBreakClass_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; + return (Codepoint < 1114110) ? kbts__UnicodeGraphemeBreakClass_Data[((kbts_un)kbts__UnicodeGraphemeBreakClass_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)] : 0; } -static kbts_u8 kbts_UnicodeSyllabicInfo_PageIndices[8703] = { +static kbts_u8 kbts__UnicodeSyllabicInfo_PageIndices[8703] = { 0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,3,4,2,5,6,7,8,9,10,11,12,13,14,15,16,17,18, 19,20,2,2,2,2,2,2,2,2,2,2,2,2,21,22,23,24,25,26,27,28,29,30,31,32,2,33,2,2,2,2, 34,35,2,2,2,2,2,2,2,2,2,36,2,2,2,2,2,2,2,2,2,2,2,2,2,2,37,2,2,2,2,2, @@ -6640,7 +8153,7 @@ static kbts_u8 kbts_UnicodeSyllabicInfo_PageIndices[8703] = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, }; -static kbts_u16 kbts_UnicodeSyllabicInfo_Data[12160] = { +static kbts_u16 kbts__UnicodeSyllabicInfo_Data[12160] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,1034,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -7023,816 +8536,45 @@ static kbts_u16 kbts_UnicodeSyllabicInfo_Data[12160] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, }; -KBTS_INLINE kbts_u16 kbts_GetUnicodeSyllabicInfo(kbts_u32 Codepoint) +KBTS_INLINE kbts_u16 kbts__GetUnicodeSyllabicInfo(kbts_u32 Codepoint) { - return kbts_UnicodeSyllabicInfo_Data[((kbts_un)kbts_UnicodeSyllabicInfo_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; + return (Codepoint < 1114110) ? kbts__UnicodeSyllabicInfo_Data[((kbts_un)kbts__UnicodeSyllabicInfo_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)] : 0; } -static kbts_u8 kbts_UnicodeScript_PageIndices[8703] = { - 0,1,2,2,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,32,33,34,35,36,37,37,37,37,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,2,2,53,54, - 55,56,57,58,59,59,59,59,60,59,59,59,59,59,59,59,61,61,59,59,59,59,62,63,64,65,66,67,68,61,61,69, - 70,71,72,73,74,75,76,59,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,77,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 78,78,78,78,78,78,78,78,78,79,80,80,81,82,83,84,85,86,87,88,89,90,91,92,32,32,32,32,32,32,32,32, - 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, - 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, - 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,93,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,94,95,96,96,97,98,99,100,101,102, - 103,104,105,106,61,107,108,109,110,111,112,113,114,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132, - 133,134,135,136,137,138,139,140,141,142,61,143,144,145,146,61,147,148,149,150,151,152,153,154,155,156,157,158,61,159,160,161, - 162,162,162,162,162,162,162,163,164,162,165,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,166, - 167,167,167,167,167,167,167,167,168,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, - 167,167,167,167,167,167,167,169,170,170,170,170,171,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,172,61,61,61,61,61,61,61,61,61,61,61,61,61,173,173,173,173,174,175,176,177,61,61,178,61,179,180,181,182, - 183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, - 183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,184,183,183,183,183,183,183,185,185,185,186,187,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,188, - 189,190,191,192,192,193,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,194,195,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,59,196,59,59,59,197,198,199, - 59,200,201,202,203,204,205,61,206,207,208,59,59,209,59,210,211,211,211,211,211,212,61,61,61,61,61,61,61,61,213,61, - 214,215,216,61,61,217,61,61,61,218,61,219,61,61,61,220,221,222,223,61,61,61,61,61,224,225,226,61,227,228,61,61, - 229,230,59,231,232,61,59,59,59,59,59,59,59,233,234,235,236,237,59,59,238,239,59,240,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 241,61,242,243,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, -}; - -static kbts_u8 kbts_UnicodeScript_Data[31232] = { - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,29,29,29,29,29,29,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,72,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,72,29,29,29,29,29, - 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,29,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,29,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,72,72,72,72,72,29,29,29,29,29,13,13,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, - 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,45,45,45,45,29,45,45,45,0,0,45,45,45,45,29,45, - 0,0,0,0,45,29,45,29,45,45,45,0,45,0,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,0,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, - 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,25,25,25,25,25,25,25,25,25,25,25,25,25,25,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, - 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, - 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, - 28,28,28,28,28,30,30,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, - 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, - 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,0,0,5,5,5,0,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54, - 54,54,54,54,54,54,54,54,0,0,0,0,0,0,0,0,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,0,0,0,0,54,54,54,54,54,54,0,0,0,0,0,0,0,0,0,0,0, - 4,4,4,4,4,29,4,4,4,4,4,4,29,4,4,4,4,4,4,4,4,4,4,4,4,4,4,29,4,4,4,29,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 29,4,4,4,4,4,4,4,4,4,4,30,30,30,30,30,30,30,30,30,30,30,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,30,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,29,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 143,143,143,143,143,143,143,143,143,143,143,143,143,143,0,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, - 143,143,143,143,143,143,143,143,143,143,143,0,0,143,143,143,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,0,0,103,103,103, - 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,0,0,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,0, - 83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,0,0,83,0,143,143,143,143,143,143,143,143,143,143,143,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,4,4,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,29,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, - 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,30,30,30,30,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,29,29,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, - 11,11,11,11,0,11,11,11,11,11,11,11,11,0,0,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,11,0,0,0,11,11,11,11,0,0,11,11,11,11, - 11,11,11,11,11,0,0,11,11,0,0,11,11,11,11,0,0,0,0,0,0,0,0,11,0,0,0,0,11,11,0,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0, - 0,48,48,48,0,48,48,48,48,48,48,0,0,0,0,48,48,0,0,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,0,48,48,48,48,48,48,48,0,48,48,0,48,48,0,48,48,0,0,48,0,48,48, - 48,48,48,0,0,0,0,48,48,0,0,48,48,48,0,0,0,48,0,0,0,0,0,0,0,48,48,48,48,0,48,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,0,0, - 0,46,46,46,0,46,46,46,46,46,46,46,46,46,0,46,46,46,0,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,0,46,46,46,46,46,46,46,0,46,46,0,46,46,46,46,46,0,0,46,46,46,46, - 46,46,46,46,46,46,0,46,46,46,0,46,46,46,0,0,46,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,46,46,46,46,0,0,46,46,46,46,46,46,46,46,46,46,46,46,0,0,0,0,0,0,0,46,46,46,46,46,46,46, - 0,118,118,118,0,118,118,118,118,118,118,118,118,0,0,118,118,0,0,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,0,118,118,118,118,118,118,118,0,118,118,0,118,118,118,118,118,0,0,118,118,118,118, - 118,118,118,118,118,0,0,118,118,0,0,118,118,118,0,0,0,0,0,0,0,118,118,118,0,0,0,0,118,118,0,118,118,118,118,118,0,0,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,0,0,0,0,0,0,0,0, - 0,0,150,150,0,150,150,150,150,150,150,0,0,0,150,150,150,0,150,150,150,150,0,0,0,150,150,0,150,0,150,150,0,0,0,150,150,0,0,0,150,150,150,0,0,0,150,150,150,150,150,150,150,150,150,150,150,150,0,0,0,0,150,150, - 150,150,150,0,0,0,150,150,150,0,150,150,150,150,0,0,150,0,0,0,0,0,0,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,0,0,0,0,0, - 153,153,153,153,153,153,153,153,153,153,153,153,153,0,153,153,153,0,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,0,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,0,0,153,153,153,153, - 153,153,153,153,153,0,153,153,153,0,153,153,153,153,0,0,0,0,0,0,0,153,153,0,153,153,153,0,0,153,0,0,153,153,153,153,0,0,153,153,153,153,153,153,153,153,153,153,0,0,0,0,0,0,0,153,153,153,153,153,153,153,153,153, - 61,61,61,61,61,61,61,61,61,61,61,61,61,0,61,61,61,0,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,0,61,61,61,61,61,61,61,61,61,61,0,61,61,61,61,61,0,0,61,61,61,61, - 61,61,61,61,61,0,61,61,61,0,61,61,61,61,0,0,0,0,0,0,0,61,61,0,0,0,0,0,0,61,61,0,61,61,61,61,0,0,61,61,61,61,61,61,61,61,61,61,0,61,61,61,0,0,0,0,0,0,0,0,0,0,0,0, - 82,82,82,82,82,82,82,82,82,82,82,82,82,0,82,82,82,0,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82, - 82,82,82,82,82,0,82,82,82,0,82,82,82,82,82,82,0,0,0,0,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,0,0,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82, - 0,136,136,136,0,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,0,0,0,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,0,136,136,136,136,136,136,136,136,136,0,136,0,0, - 136,136,136,136,136,136,136,0,0,0,136,0,0,0,0,136,136,136,136,136,136,0,136,0,136,136,136,136,136,136,136,136,0,0,0,0,0,0,136,136,136,136,136,136,136,136,136,136,0,0,136,136,136,0,0,0,0,0,0,0,0,0,0,0, - 0,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,0,0,0,0,29, - 155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,71,71,0,71,0,71,71,71,71,71,0,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,0,71,0,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,0,0, - 71,71,71,71,71,0,71,0,71,71,71,71,71,71,71,0,71,71,71,71,71,71,71,71,71,71,0,0,71,71,71,71,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, - 156,156,156,156,156,156,156,156,0,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,0,0,0,0,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, - 156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,0,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,0,156,156, - 156,156,156,156,156,156,156,156,156,156,156,156,156,0,156,156,156,156,156,156,156,29,29,29,29,156,156,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, - 97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, - 97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41, - 41,41,41,41,41,41,0,41,0,0,0,0,0,41,0,0,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,29,41,41,41,41, - 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, - 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, - 39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39, - 39,39,39,39,39,39,39,39,39,0,39,39,39,39,0,0,39,39,39,39,39,39,39,0,39,0,39,39,39,39,0,0,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39, - 39,39,39,39,39,39,39,39,39,0,39,39,39,39,0,0,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,0,39,39,39,39,0,0,39,39,39,39,39,39,39,0, - 39,0,39,39,39,39,0,0,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,0,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39, - 39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,0,39,39,39,39,0,0,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39, - 39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,0,0,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,0,0,0, - 39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,0,0,0,0,0,0,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, - 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,0,0,22,22,22,22,22,22,0,0, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,0,0,0,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,29,29,29,128,128,128,128,128,128,128,128,128,128,128,0,0,0,0,0,0,0, - 144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,0,0,0,0,0,0,0,0,0,144,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,29,29,0,0,0,0,0,0,0,0,0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,0,145,145,145,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0, - 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, - 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,0,0,67,67,67,67,67,67,67,67,67,67,0,0,0,0,0,0,67,67,67,67,67,67,67,67,67,67,0,0,0,0,0,0, - 94,94,29,29,94,29,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,0,0,0,0,0,0,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94, - 94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,0,0,0,0,0,0,0, - 94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,0,0,0,0,0,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,0,0, - 74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,0,74,74,74,74,74,74,74,74,74,74,74,74,0,0,0,0,74,74,74,74,74,74,74,74,74,74,74,74,0,0,0,0, - 74,0,0,0,74,74,74,74,74,74,74,74,74,74,74,74,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,0,0,146,146,146,146,146,0,0,0,0,0,0,0,0,0,0,0, - 102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,0,0,0,0,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, - 102,102,102,102,102,102,102,102,102,102,0,0,0,0,0,0,102,102,102,102,102,102,102,102,102,102,102,0,0,0,102,102,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, - 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,0,0,15,15,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, - 147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,0,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,0,0,147, - 147,147,147,147,147,147,147,147,147,147,0,0,0,0,0,0,147,147,147,147,147,147,147,147,147,147,0,0,0,0,0,0,147,147,147,147,147,147,147,147,147,147,147,147,147,147,0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, - 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, - 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,0,0,0,0,0,0,0,0,10,10,10,10, - 73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,0,0,0,73,73,73,73,73, - 73,73,73,73,73,73,73,73,73,73,0,0,0,73,73,73,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, - 28,28,28,28,28,28,28,28,28,28,28,0,0,0,0,0,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,0,0,41,41,41, - 140,140,140,140,140,140,140,140,0,0,0,0,0,0,0,0,30,30,30,29,30,30,30,30,30,30,30,30,30,30,30,30,30,29,30,30,30,30,30,30,30,29,29,29,29,30,29,29,29,29,29,29,30,29,29,29,30,30,29,0,0,0,0,0, - 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,45,45,45,45,45,28,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,45,45,45,45,45,72,72,72,72,45,45,45,45,45,72,72,72,72,72,72,72,72,72,72,72,72,72,28,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,45, - 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, - 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,0,0,45,45,45,45,45,45,0,0,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, - 45,45,45,45,45,45,0,0,45,45,45,45,45,45,0,0,45,45,45,45,45,45,45,45,0,45,0,45,0,45,0,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,0,0, - 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,0,45,45,45,45,45,45,45,45,45,45, - 45,45,45,45,45,0,45,45,45,45,45,45,45,45,45,45,45,45,45,45,0,0,45,45,45,45,45,45,0,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,0,0,45,45,45,0,45,45,45,45,45,45,45,45,45,0, - 29,29,29,29,29,29,29,29,29,29,29,29,30,30,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,72,0,0,29,29,29,29,29,29,29,29,29,29,29,72, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,72,72,72,72,72,72,72,72,72,72,72,72,72,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,45,29,29,29,72,72,29,29,29,29,29,29,72,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,72,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,29,29,29,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42, - 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, - 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, - 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,0,0,0,0,0,25,25,25,25,25,25,25, - 41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,0,41,0,0,0,0,0,41,0,0,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, - 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,0,0,0,0,0,0,0,157,157,0,0,0,0,0,0,0,0,0,0,0,0,0,0,157, - 39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,0,0,0,0,0,0,0,0,0,39,39,39,39,39,39,39,0,39,39,39,39,39,39,39,0,39,39,39,39,39,39,39,0,39,39,39,39,39,39,39,0, - 39,39,39,39,39,39,39,0,39,39,39,39,39,39,39,0,39,39,39,39,39,39,39,0,39,39,39,39,39,39,39,0,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,0,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,30,30,30,30,50,50,29,29,29,29,29,29,29,29,0,0,0,0,29,29,29,29, - 0,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, - 55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,0,0,30,30,29,29,55,55,55,29,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62, - 62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,29,29,62,62,62, - 0,0,0,0,0,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,0,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, - 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, - 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,29,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62, - 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,29, - 62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62, - 62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, - 168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, - 168,168,168,168,168,168,168,168,168,168,168,168,168,0,0,0,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, - 168,168,168,168,168,168,168,0,0,0,0,0,0,0,0,0,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, - 163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, - 163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, - 163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, - 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,0,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,29,29,29,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72,72,72,0,0,72,72,0,72,0,72,72,72,72,72,72,72,72,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,72,72,72,72,72,72,72,72,72,72,72,72,72, - 142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,0,0,0,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0, - 124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,0,0,0,0,0,0,0,0, - 130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, - 130,130,130,130,130,130,0,0,0,0,0,0,0,0,130,130,130,130,130,130,130,130,130,130,130,130,0,0,0,0,0,0,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, - 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,29,64,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127, - 127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,0,0,0,0,0,0,0,0,0,0,0,127,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,0,0,0, - 59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59, - 59,59,59,59,59,59,59,59,59,59,59,59,59,59,0,29,59,59,59,59,59,59,59,59,59,59,0,0,0,0,59,59,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,0, - 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,0,0,0,0,0,0,0,0,0, - 21,21,21,21,21,21,21,21,21,21,21,21,21,21,0,0,21,21,21,21,21,21,21,21,21,21,0,0,21,21,21,21,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, - 148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, - 148,148,148,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,148,148,148,148,148,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,0,0,0,0,0,0,0,0,0, - 0,39,39,39,39,39,39,0,0,39,39,39,39,39,39,0,0,39,39,39,39,39,39,0,0,0,0,0,0,0,0,0,39,39,39,39,39,39,39,0,39,39,39,39,39,39,39,0,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,29,72,72,72,72,72,72,72,72,72,45,72,72,72,72,29,29,0,0,0,0,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, - 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, - 88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,0,0,88,88,88,88,88,88,88,88,88,88,0,0,0,0,0,0, - 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,0,0,0,0,0,0,0,0,0,0,0,0,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, - 50,50,50,50,50,50,50,0,0,0,0,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,0,0,0,0, - 72,72,72,72,72,72,72,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,0,0,0,0,0,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,0,54,54,54,54,54,0,54,0, - 54,54,0,54,54,0,54,54,54,54,54,54,54,54,54,54,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,29,29, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,29,29,0,0,0,0,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,29, - 0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,29,29,29,29,29, - 29,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,29,29,29,29,29,29,29,29,29,29,29,62,62,62,62,62,62,62,62,62,62,29,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62, - 62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,29,29,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,0, - 0,0,50,50,50,50,50,50,0,0,50,50,50,50,50,50,0,0,50,50,50,50,50,50,0,0,50,50,50,0,0,0,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,0,0, - 76,76,76,76,76,76,76,76,76,76,76,76,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,0,76,76,0,76, - 76,76,76,76,76,76,76,76,76,76,76,76,76,76,0,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, - 76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,0,0,0,0,0, - 29,29,29,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,29,29,29,29,29,29,29,29,29, - 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, - 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,0,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,30,0,0, - 78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,0,0,0,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0, - 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,0,0,0,0,0,0,0,0,0,109,109,109,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, - 43,43,43,43,43,43,43,43,43,43,43,0,0,0,0,0,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,0,0,0,0,0, - 162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,0,162,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, - 113,113,113,113,0,0,0,0,113,113,113,113,113,113,113,113,113,113,113,113,113,113,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31, - 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, - 120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,0,0,120,120,120,120,120,120,120,120,120,120,0,0,0,0,0,0,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, - 119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,0,0,0,0,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,0,0,0,0, - 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,0,0,0,0,0,0,0,0,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,0,0,0,0,0,0,0,0,0,0,0,19,164,164,164,164,164,164,164,164,164,164,164,0,164,164,164,164, - 164,164,164,164,164,164,164,164,164,164,164,0,164,164,164,164,164,164,164,0,164,164,0,164,164,164,164,164,164,164,164,164,164,164,0,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,0,164,164,164,164,164,164,164,0,164,164,0,0,0, - 159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,0,0,0,0,0,0,0,0,0,0,0,0, - 75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, - 75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, - 75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,0,0,0,0,0,0,0,0,0, - 75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,0,0,0,0,0,0,0,0,0,0,75,75,75,75,75,75,75,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 72,72,72,72,72,72,0,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,0,72,72,72,72,72,72,72,72,72,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 26,26,26,26,26,26,0,0,26,0,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,0,26,26,0,0,0,26,0,0,26, - 56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,0,56,56,56,56,56,56,56,56,56,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122, - 98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,0,0,0,0,0,0,0,0,98,98,98,98,98,98,98,98,98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,0,53,53,0,0,0,0,0,53,53,53,53,53, - 125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,0,0,0,125,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,0,0,0,0,0,79, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,0,0,0,0,90,90,90,90, - 90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,0,0,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90, - 65,65,65,65,0,65,65,0,0,0,0,0,65,65,65,65,65,65,65,65,0,65,65,65,0,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,0,0,65,65,65,0,0,0,0,65, - 65,65,65,65,65,65,65,65,65,0,0,0,0,0,0,0,65,65,65,65,65,65,65,65,65,0,0,0,0,0,0,0,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115, - 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,0,0,0,0,84,84,84,84,84,84,84,84,84,84,84,84,0,0,0,0,0,0,0,0,0, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0,0,0,6,6,6,6,6,6,6, - 58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,0,0,58,58,58,58,58,58,58,58,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,0,0,0,0,0,57,57,57,57,57,57,57,57, - 126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,0,0,0,0,0,0,0,126,126,126,126,0,0,0,0,0,0,0,0,0,0,0,0,126,126,126,126,126,126,126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, - 116,116,116,116,116,116,116,116,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,0,0,0,0,0,0,0,0,0,0,0,0,0, - 110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,0,0,0,0,0,0,0,110,110,110,110,110,110, - 51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,0,0,0,0,0,0,0,0,51,51,51,51,51,51,51,51,51,51,0,0,0,0,0,0, - 40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,0,0,0,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40, - 40,40,40,40,40,40,0,0,0,0,0,0,0,0,40,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0, - 167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,0,167,167,167,0,0,167,167,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4, - 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,0,0,0,0,0,0,0,0,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, - 135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, - 117,117,117,117,117,117,117,117,117,117,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, - 23,23,23,23,23,23,23,23,23,23,23,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,0,0,0,0,0,0,0,0,0, - 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, - 14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,14, - 60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60, - 60,60,60,0,0,0,0,0,0,0,0,0,0,60,0,0,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,0,0,0,0,0,0,0,137,137,137,137,137,137,137,137,137,137,0,0,0,0,0,0, - 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,0,20,20,20,20,20,20,20,20,20,20, - 20,20,20,20,20,20,20,20,0,0,0,0,0,0,0,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,0,0,0,0,0,0,0,0,0, - 131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, - 131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,0,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,0,0,0,0,0,0,0,0,0,0,0, - 68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,0,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, - 68,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 96,96,96,96,96,96,96,0,96,0,96,96,96,96,0,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,0,96,96,96,96,96,96,96,96,96,96,96,0,0,0,0,0,0,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69, - 69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,0,0,0,0,0,69,69,69,69,69,69,69,69,69,69,0,0,0,0,0,0, - 44,44,44,44,0,44,44,44,44,44,44,44,44,0,0,44,44,0,0,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,0,44,44,44,44,44,44,44,0,44,44,0,44,44,44,44,44,0,30,44,44,44,44, - 44,44,44,44,44,0,0,44,44,0,0,44,44,44,0,0,44,0,0,0,0,0,0,44,0,0,0,0,0,44,44,44,44,44,44,44,0,0,44,44,44,44,44,44,44,0,0,0,44,44,44,44,44,0,0,0,0,0,0,0,0,0,0,0, - 161,161,161,161,161,161,161,161,161,161,0,161,0,0,161,0,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,0,161,161,161,161,161,161,161,161,161, - 161,0,161,0,0,161,0,161,161,161,161,0,161,161,161,161,161,161,161,161,161,161,0,161,161,0,0,0,0,0,0,0,0,161,161,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, - 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,0,101,101,101,101,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, - 158,158,158,158,158,158,158,158,0,0,0,0,0,0,0,0,158,158,158,158,158,158,158,158,158,158,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,0,0,133,133,133,133,133,133,133,133, - 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93, - 93,93,93,93,93,0,0,0,0,0,0,0,0,0,0,0,93,93,93,93,93,93,93,93,93,93,0,0,0,0,0,0,94,94,94,94,94,94,94,94,94,94,94,94,94,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,0,0,0,0,0,0, - 149,149,149,149,149,149,149,149,149,149,0,0,0,0,0,0,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, - 166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,0,0,0,0,0,0,0,0,0,0,0,0,166, - 33,33,33,33,33,33,33,0,0,33,0,0,33,33,33,33,33,33,33,33,0,33,33,0,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,0,33,33,0,0,33,33,33,33,33, - 33,33,33,33,33,33,33,0,0,0,0,0,0,0,0,0,33,33,33,33,33,33,33,33,33,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,100,100,100,100,100,100,100,0,0,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, - 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,0,0,100,100,100,100,100,100,100,100,100,100,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, - 169,169,169,169,169,169,169,169,0,0,0,0,0,0,0,0,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, - 138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,0,0,0,0,0,0,0, - 32,32,32,32,32,32,32,32,32,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,0,0,0,0,0,0,0,0,0,0,0,0,0,0,141,141,141,141,141,141,141,141,141,141,0,0,0,0,0,0, - 12,12,12,12,12,12,12,12,12,0,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,0,12,12,12,12,12,12,12,12, - 12,12,12,12,12,12,0,0,0,0,0,0,0,0,0,0,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,0,0,0,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, - 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,0,0,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,0,85,85,85,85,85,85,85,85,85,85,85,85,85,85,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 86,86,86,86,86,86,86,0,86,86,0,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,0,0,0,86,0,86,86,0,86, - 86,86,86,86,86,86,86,86,0,0,0,0,0,0,0,0,86,86,86,86,86,86,86,86,86,86,0,0,0,0,0,0,47,47,47,47,47,47,0,47,47,0,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47, - 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,0,47,47,0,47,47,47,47,47,47,0,0,0,0,0,0,0,47,47,47,47,47,47,47,47,47,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,0,0,0,0,0,0,0, - 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,0,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,0,0,0,63,63, - 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,0,0,0,0,0,0,0,0,0,0,0,0,0,150, - 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, - 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, - 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, - 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,0,139,139,139,139,139,0,0,0,0,0,0,0,0,0,0,0, - 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, - 139,139,139,139,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27, - 27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,0,0,0,0,0,0,0,0,0,0,0,0,0, - 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, - 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, - 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, - 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,0,0,0,0,0,0,0,0,0,0,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, - 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, - 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,0,0,0,0,0, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,0,0,0,0,0,0,0, - 95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,0,95,95,95,95,95,95,95,95,95,95,0,0,0,0,95,95,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, - 151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,0, - 151,151,151,151,151,151,151,151,151,151,0,0,0,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0, - 121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, - 121,121,121,121,121,121,0,0,0,0,0,0,0,0,0,0,121,121,121,121,121,121,121,121,121,121,0,121,121,121,121,121,121,121,0,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,0,0,0,0,0,121,121,121, - 121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87, - 87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, - 92,92,92,92,92,92,92,92,92,92,92,0,0,0,0,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, - 92,92,92,92,92,92,92,92,0,0,0,0,0,0,0,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,152,104,0,0,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, - 152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, - 152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, - 152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,0,0,0,0,0,0,0,0, - 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, - 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, - 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, - 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66, - 152,152,152,152,152,152,152,152,152,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,62,62,62,0,62,62,62,62,62,62,62,0,62,62,0, - 62,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, - 55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, - 55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, - 55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, - 55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,62,62,62,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,55,55,0,0,62,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,62,62,62,0,0,0,0,0,0,0,0,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, - 104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, - 104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, - 104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, - 104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,0,0,0,0, - 35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35, - 35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,0,0,0,0,0,35,35,35,35,35,35,35,35,35,35,35,35,35,0,0,0, - 35,35,35,35,35,35,35,35,35,0,0,0,0,0,0,0,35,35,35,35,35,35,35,35,35,35,0,0,35,35,35,35,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, - 30,30,30,30,30,30,30,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,30,30,30,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,30,30,30,30,30, - 30,30,30,29,29,30,30,30,30,30,30,30,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,30,30,30,30,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, - 45,45,45,45,45,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,0,0,29,0,0,29,29,0,0,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,0,29,0,29,29,29, - 29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,0,29,29,29,29,0,0,29,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,29,29,0, - 29,29,29,29,29,0,29,0,0,0,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, - 134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, - 134,134,134,134,134,134,134,134,134,134,134,134,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,134,134,134,134,134,0,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,0,0,0,0,0,0,72,72,72,72,72,72,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 42,42,42,42,42,42,42,0,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,0,0,42,42,42,42,42,42,42,0,42,42,0,42,42,42,42,42,0,0,0,0,0,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, - 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,0,0,0,105,105,105,105,105,105,105,105,105,105,105,105,105,105,0,0, - 105,105,105,105,105,105,105,105,105,105,0,0,0,0,105,105,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,0,0,0,0,0,165, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,0,0,0,0,108, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,39,39,39,39,39,39,0,39,39,39,39,0,39,39,0,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,0, - 89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, - 89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, - 89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, - 89,89,89,89,89,0,0,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,4,4,0,4,0,0,4,0,4,4,4,4,4,4,4,4,4,4,0,4,4,4,4,0,4,0,4,0,0,0,0, - 0,0,4,0,0,0,0,4,0,4,0,4,0,4,4,4,0,4,4,0,4,0,0,4,0,4,0,4,0,4,0,4,0,4,4,0,4,0,0,4,4,4,4,0,4,4,4,4,4,4,4,0,4,4,4,4,0,4,4,4,4,0,4,0, - 4,4,4,4,4,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,4,4,4,0,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 55,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0, - 29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0, - 29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0, - 29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0, - 0,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, - 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, - 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, - 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -}; - -KBTS_INLINE kbts_u8 kbts_GetUnicodeScript(kbts_u32 Codepoint) -{ - return kbts_UnicodeScript_Data[((kbts_un)kbts_UnicodeScript_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; -} - -static kbts_u8 kbts_UnicodeFlags_PageIndices[8703] = { +static kbts_u8 kbts__UnicodeFlags_PageIndices[8703] = { 0,1,2,3,2,4,5,6,2,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,33,33,33,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,2,2,2,55, - 56,57,58,59,33,33,60,33,61,33,33,33,33,33,62,63,33,33,33,64,33,33,65,66,67,68,69,70,71,72,33,73, - 74,75,76,77,78,33,33,33,79,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,80,79,2,2,2, + 56,57,58,59,60,61,62,33,63,33,33,33,33,33,64,65,33,33,33,66,67,68,69,70,71,72,73,74,75,76,33,77, + 78,79,80,81,82,33,33,33,83,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,84,83,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,81, - 33,33,33,33,33,33,33,33,33,82,33,33,83,84,85,86,87,88,89,90,91,92,93,94,79,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,85, + 33,33,33,33,33,33,33,33,33,86,33,33,87,88,89,90,91,92,93,94,95,96,97,98,83,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,95,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 79,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,81,33,33,96,97,98,99,33,33,100,101,102,103,104,105, - 106,107,108,109,2,110,111,112,113,114,115,116,33,33,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134, - 135,136,137,138,139,140,141,142,143,144,2,145,146,147,148,2,149,150,151,152,153,154,2,155,156,157,158,159,2,160,161,162, - 33,33,33,33,33,33,33,37,163,33,164,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,165, - 33,33,33,33,33,33,33,33,166,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, - 33,33,33,33,33,33,33,107,33,33,33,33,167,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,99,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 83,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,85,33,33,100,101,102,103,33,33,104,105,106,107,108,109, + 110,111,112,113,2,114,115,116,117,118,119,120,33,33,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138, + 139,140,141,142,143,144,145,146,147,148,2,149,150,151,152,2,153,154,155,156,157,158,2,159,160,161,162,163,2,164,165,166, + 33,33,33,33,33,33,33,37,167,33,168,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,169, + 33,33,33,33,33,33,33,33,170,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, + 33,33,33,33,33,33,33,111,33,33,33,33,171,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,168,2,2,2,2,2,2,2,2,2,2,2,2,2,33,33,33,33,169,170,171,172,2,2,173,2,2,174,175,176, - 79,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,177,33,33,33,33,33,33,33,33,33,178,179,2,2,2,2,2, + 2,2,172,2,2,2,2,2,2,2,2,2,2,2,2,2,33,33,33,33,173,174,175,176,2,2,177,2,2,178,179,180, + 83,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,181,33,33,33,33,33,33,33,33,33,182,183,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,180, - 33,33,181,33,33,182,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,183,184,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,33,185,33,33,33,186,187,164, - 33,188,189,190,191,192,193,2,2,2,2,2,2,194,195,196,33,33,33,33,197,198,2,2,2,2,2,2,2,2,199,2, - 200,201,202,2,2,203,2,2,2,204,2,205,2,2,2,206,33,207,208,2,2,2,2,2,209,210,211,2,212,213,2,2, - 214,215,33,216,217,2,33,33,33,33,33,33,33,218,219,220,221,222,33,33,223,224,33,225,2,2,2,2,2,2,2,2, - 79,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,184, + 33,33,185,33,33,186,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,187,188,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,33,189,33,33,33,190,191,168, + 33,192,193,194,195,196,197,2,2,2,2,2,2,198,199,200,33,33,33,33,201,202,2,2,2,2,2,2,2,2,203,2, + 204,205,206,2,2,207,2,2,2,208,2,209,2,2,2,210,33,211,212,2,2,2,2,2,213,214,215,2,216,217,2,2, + 218,219,33,220,221,2,33,33,33,33,33,33,33,222,223,224,225,226,33,33,227,228,33,229,2,2,2,2,2,2,2,2, + 83,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, @@ -7842,15 +8584,15 @@ static kbts_u8 kbts_UnicodeFlags_PageIndices[8703] = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,226,79,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,227,2,228,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,229,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,230,83,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,231,2,232,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,233,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,230,2,2,2,2,231,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,33,33,33,33,232,2,2,2,2,2,2,2,2,2,2,2, - 79,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,233,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,234,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,234,2,2,2,2,235,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,33,33,33,33,236,2,2,2,2,2,2,2,2,2,2,2, + 83,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,237,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,238,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, @@ -8024,7 +8766,7 @@ static kbts_u8 kbts_UnicodeFlags_PageIndices[8703] = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 235,235,236,237,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 239,239,240,241,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, @@ -8040,7 +8782,7 @@ static kbts_u8 kbts_UnicodeFlags_PageIndices[8703] = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 79,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 83,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, @@ -8055,8 +8797,8 @@ static kbts_u8 kbts_UnicodeFlags_PageIndices[8703] = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,238, - 79,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,242, + 83,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, @@ -8074,10 +8816,10 @@ static kbts_u8 kbts_UnicodeFlags_PageIndices[8703] = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, }; -static kbts_u8 kbts_UnicodeFlags_Data[30592] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,4,0,0,16,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,16,16,16,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,16,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,0,16,16,16,0,16,2,16,16,16,16,16,16,16,0,0,0,16,16,16,0,16,16,16,0, +static kbts_u8 kbts__UnicodeFlags_Data[31104] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,4,8,0,16,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,28,16,28,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,8,16,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,16,8,16,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,0,16,16,16,12,16,2,16,16,16,16,16,16,16,0,0,0,16,16,16,12,16,16,16,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -8131,7 +8873,7 @@ static kbts_u8 kbts_UnicodeFlags_Data[30592] = { 16,16,16,16,16,16,16,80,80,80,80,80,80,80,80,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,16,16,0,16,0,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,0,16,16,16,16,16,16,16,16,16,16,80,16,16,80,80,80,80,80,80,80,80,80,16,0,0, 16,16,16,16,16,0,16,0,80,80,80,80,80,80,80,0,48,48,48,48,48,48,48,48,48,48,0,0,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,16,16,16,80,80,16,16,16,16,16,16,48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,16,16,16,16,16,16,80,16,80,16,80,0,0,0,0,16,16, + 16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,16,16,16,80,80,16,16,16,16,16,16,48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,16,16,16,16,16,16,80,16,80,16,80,4,8,4,8,16,16, 16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,16, 80,80,80,80,80,0,80,80,16,16,16,16,16,80,80,80,80,80,80,80,80,80,80,80,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,0,16,16, 16,16,16,16,16,16,80,16,16,16,16,16,16,0,16,16,0,0,0,0,0,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -8155,7 +8897,7 @@ static kbts_u8 kbts_UnicodeFlags_Data[30592] = { 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,4,8,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,16,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,16,0,0,0,0,0,0,0,0,0,0,0, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,0,80,80,0,0,0,0,0,0,0,0,0,0,0,0, @@ -8187,28 +8929,36 @@ static kbts_u8 kbts_UnicodeFlags_Data[30592] = { 80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,16, 16,16,0,0,0,0,0,0,0,0,0,0,0,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0, - 0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,16,16,0,0,16,16,16,16,16,16,16,16,16,0,0,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0, + 0,0,0,0,16,4,8,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,16,16,0,0,16,16,16,16,16,16,16,16,16,4,8,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,4,8,0,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,80,80,80,80,80,80,80,80,80,80,80,80,16,16,16,16,80,16,16,16,80,80,80,80,80,80,80,80,80,80,80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 16,16,0,16,16,16,16,0,16,16,0,0,0,0,0,0,0,0,0,0,16,0,16,16,16,0,0,0,0,0,16,16,16,16,16,16,0,16,0,16,0,16,0,0,0,0,16,0,0,0,0,0,0,16,16,16,16,0,16,16,0,0,0,0, 16,16,16,16,16,0,0,0,0,0,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,0,0,16,16,16,16,16,16,16,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,28,28,28,28,28,28,16,16,16,16,16,16,16,28,16,16,16,16,16,16,16,16,16,28,28,28,28,16,28,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,28,28,16,16, + 16,16,16,28,16,28,16,16,16,16,16,16,28,16,16,16,16,16,28,28,28,28,16,16,16,16,16,16,16,16,16,16,16,16,16,16,28,28,28,28,28,28,28,28,16,16,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 28,28,28,28,28,28,28,28,28,28,28,28,16,16,16,28,28,28,28,16,16,16,16,16,28,16,16,16,16,16,16,16,16,16,28,28,16,16,28,16,28,28,16,28,16,16,16,16,28,28,28,28,28,28,28,28,28,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,28,28,28,28,28,16,16,28,28,16,16,16,16,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,16,16,28,28,28,28,28,16,28,28,16,16,28,28,28,28,28,16, + 16,16,16,16,16,16,16,16,4,8,4,8,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,4,8,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,4,8,4,8,4,8,4,8,4,8,4,8,4,8,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16, + 16,16,16,28,28,4,8,16,28,28,16,28,16,28,16,16,16,16,16,16,16,28,28,16,16,16,16,16,28,28,28,16,16,16,28,28,28,28,4,8,4,8,4,8,4,8,4,8,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,4,8,4,8,4,8,4,8,4,8,4,8,4,8,4,8,4,8,4,8,4,8,16,16,28,16,16,16,16,28,16,16,28,28,28,16,16,28,28,28,28,28,28,28,28,16,16,16,16,16,16,16,16,28,16,16,16,16,16,16,16, + 28,28,16,16,28,28,16,16,16,16,16,16,16,16,16,28,28,28,28,16,28,28,16,16,4,8,4,8,16,16,16,16,16,16,16,16,16,16,16,16,28,28,16,16,16,16,16,16,16,16,16,16,16,28,16,16,28,28,16,16,4,8,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,28,28,28,28,16,16,16,16,16,28,28,16,16,16,16,16,16,28,28,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,28,28,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,28,28,28,28,28,28,28, + 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,16,16,16,28,28,28,28,28,28,28,28,16,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,16,16,16,16,16,16,16,28,16,16,16,16,28,28,28,16,16,16,16,16,16,28,28,28,16,16,16,16,16,16,16,16,28,28,28,28,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,28,16, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -8217,13 +8967,13 @@ static kbts_u8 kbts_UnicodeFlags_Data[30592] = { 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0, 16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,12,12,12,12,0,0,0,12,12,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,12,12,4,8,4,8,4,8,4,8,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,4,8,4,8,4,8,4,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0,0,0,0,16,16,16,16,0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,80,80,80,80,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16, + 0,0,0,0,16,16,16,16,4,8,4,8,4,8,4,8,4,8,16,16,4,8,4,8,4,8,4,8,0,0,0,0,16,16,16,16,16,16,16,16,16,16,80,80,80,80,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16, 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,80,80,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16, @@ -8280,11 +9030,11 @@ static kbts_u8 kbts_UnicodeFlags_Data[30592] = { 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,16,16,16,0,0,16,0,0,0,0,0,0,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,4,8,4,8,0,0,0,16,0,28,28,16,0,0,16,0,0,0,0,0,0,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,2, - 0,0,0,0,16,0,0,0,0,0,0,16,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0, - 16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,16,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0,0,0,0,16,0,0,0,4,8,0,16,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,28,16,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,8,16,0, + 16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,16,8,16,4,8,0,4,8,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0, 0,0,16,16,16,16,16,16,0,0,16,16,16,16,16,16,0,0,16,16,16,16,16,16,0,0,16,16,16,0,0,0,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,2,2,2,2,2,2,2,2,2,0,0,0,16,16,0,0, 16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,0,16, @@ -8555,12 +9305,12 @@ static kbts_u8 kbts_UnicodeFlags_Data[30592] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0, }; -KBTS_INLINE kbts_u8 kbts_GetUnicodeFlags(kbts_u32 Codepoint) +KBTS_INLINE kbts_u8 kbts__GetUnicodeFlags(kbts_u32 Codepoint) { - return kbts_UnicodeFlags_Data[((kbts_un)kbts_UnicodeFlags_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; + return (Codepoint < 1114110) ? kbts__UnicodeFlags_Data[((kbts_un)kbts__UnicodeFlags_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)] : 0; } -static kbts_u8 kbts_UnicodeBidirectionalClass_PageIndices[8703] = { +static kbts_u8 kbts__UnicodeBidirectionalClass_PageIndices[8703] = { 0,1,2,2,2,3,4,5,2,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,2,2,31,32,33,34,35,2,2,2,2,36,37,38,39,40,41,42,43,44,45,46,47,48,2,49,2,2,50,51, 52,53,54,55,56,57,58,59,57,60,57,57,57,61,57,57,2,2,57,57,57,57,57,57,2,62,63,64,57,57,57,57, @@ -8785,7 +9535,7 @@ static kbts_u8 kbts_UnicodeBidirectionalClass_PageIndices[8703] = { 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, - 57,57,228,229,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 228,57,229,230,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, @@ -8816,7 +9566,7 @@ static kbts_u8 kbts_UnicodeBidirectionalClass_PageIndices[8703] = { 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, - 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,230, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,231, 73,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, @@ -8835,477 +9585,479 @@ static kbts_u8 kbts_UnicodeBidirectionalClass_PageIndices[8703] = { 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, }; -static kbts_u8 kbts_UnicodeBidirectionalClass_Data[29568] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,8,8,0,0,0,0,0,7,9,7,9,9,6,6,6,6,6,6,6,6,6,6,9,0,0,0,0,0, - 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,8,8,8,8,0,0,0,0,1,0,0,0,0,0,8,8,6,6,0,1,0,0,0,6,1,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1, - 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,0,0,1,1,0,0,1,1,1,1,0,1, - 0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, - 1,1,1,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,8,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3, - 2,3,3,2,3,3,2,3,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0, - 5,5,5,5,5,5,0,0,4,8,8,4,9,4,0,0,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,5,5,5,5,5,5,5,5,5,5,8,5,5,4,4,4,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +static kbts_u8 kbts__UnicodeBidirectionalClass_Data[29696] = { + 1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,9,9,9,0,0,0,0,0,8,10,8,10,10,7,7,7,7,7,7,7,7,7,7,10,0,0,0,0,0, + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1, + 1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,10,0,9,9,9,9,0,0,0,0,2,0,0,1,0,0,9,9,7,7,0,2,0,0,0,7,2,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2, + 2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,5,0,3,3,3,3,3,3,4,4,3,3,0,3,3,3,3,4,4,6,6,6,6,6,6,6,6,6,6,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,4,4,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,2,2,0,0,0,0,2,0,0,3,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,2,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,3,3,3,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,0,0,2,0,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,5,5,0,0,0,0,0,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,5,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1, - 1,3,3,3,3,3,3,3,3,1,1,1,1,3,1,1,1,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,3,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,1,0,0,3,1,1,1, - 1,3,3,3,3,0,0,1,1,0,0,1,1,3,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,0,1,1,1,3,3,0,0,1,1,1,1,1,1,1,1,1,1,1,1,8,8,1,1,1,1,1,1,1,8,1,1,3,0, - 0,3,3,1,0,1,1,1,1,1,1,0,0,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0,0,3,0,1,1, - 1,3,3,0,0,0,0,3,3,0,0,3,3,3,0,0,0,3,0,0,0,0,0,0,0,1,1,1,1,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,3,1,0,0,0,0,0,0,0,0,0, - 0,3,3,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,0,3,1,1,1, - 1,3,3,3,3,3,0,3,3,1,0,1,1,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,3,3,0,0,1,1,1,1,1,1,1,1,1,1,1,8,0,0,0,0,0,0,0,1,3,3,3,3,3,3, - 0,3,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,0,3,1,1,3, - 1,3,3,3,3,0,0,1,1,0,0,1,1,3,0,0,0,0,0,0,0,3,3,1,0,0,0,0,1,1,0,1,1,1,3,3,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, - 0,0,3,1,0,1,1,1,1,1,1,0,0,0,1,1,1,0,1,1,1,1,0,0,0,1,1,0,1,0,1,1,0,0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1, - 3,1,1,0,0,0,1,1,1,0,1,1,1,3,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,8,0,0,0,0,0,0, - 3,1,1,1,3,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3,1,3,3, - 3,1,1,1,1,0,3,3,3,0,3,3,3,3,0,0,0,0,0,0,0,3,3,0,1,1,1,0,0,1,0,0,1,1,3,3,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, - 1,3,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,3,1,1,1, - 1,1,1,1,1,0,1,1,1,0,1,1,3,3,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,1,1,3,3,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, - 3,3,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1, - 1,3,3,3,3,0,1,1,1,0,1,1,1,3,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,3,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,0, - 1,1,1,1,1,1,1,0,0,0,3,0,0,0,0,1,1,1,3,3,3,0,3,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0, - 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,3,3,3,3,3,3,3,0,0,0,0,8, - 1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,3,1,1,3,3,3,3,3,3,3,3,3,1,0,0, - 1,1,1,1,1,0,1,0,3,3,3,3,3,3,3,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,3,0,0,0,0,1,1, - 1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1, - 3,3,3,3,3,1,3,3,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,1,1, - 1,1,1,1,1,1,3,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,1,3,3,3,3,3,3,1,3,3,1,1,3,3,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1, - 1,1,3,1,1,3,3,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,0,1,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, - 1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0, - 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,3,3,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,3,3,3,3,3,3,3,1,1, - 1,1,1,1,1,1,3,1,1,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,8,1,3,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,3,3,3,0,3,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, - 1,1,1,1,1,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,3,3,3,1,1,1,1,3,3,1,1,1,0,0,0,0,1,1,3,1,1,1,1,1,1,3,3,3,0,0,0,0, - 0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,3,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,3,3,3,3,3,3,0,3,1,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,0,0,3, - 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,3,3,3,3,1,3,1,1,1, - 1,1,3,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1, - 3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,1,1,3,3,1,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,3,1,1,1,3,1,3,3,3,1,1,0,0,0,0,0,0,0,0,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,3,3,0,0,0,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1, - 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,1,1,1,1,3,1,1,1,1,1,1,3,1,1,1,3,3,1,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0, - 0,0,1,1,1,0,1,1,1,1,1,1,1,0,0,0,1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,8,8,8,8,8,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,1,0,0,6,6,6,6,6,6,7,7,0,0,0,1, - 6,6,6,6,6,6,6,6,6,6,7,7,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,1,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1,0,1,0,1,0,1,1,1,1,8,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1, - 0,0,0,0,0,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,3,3,3,1,1,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0, - 1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 0,0,0,0,0,1,1,1,0,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,1,1,1,1,1,1,1,1,3,3,3,3,1,1,0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0, - 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3,3,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1, - 0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, - 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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, - 1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,1,1,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,3,1,1,1,3,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,0,0,0,0,3,0,0,0,1,1,1,1,1,1,1,1,8,8,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,3,3,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,3, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0, - 3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,3,3,3,3,1,1,3,3,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,1,1,3,3,1,1,3,3,0,0,0,0,0,0,0,0,0, - 1,1,1,3,1,1,1,1,1,1,1,1,3,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,3,3,1,1,3,3,1,1,1,1,1,3,3, - 1,3,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,1,1,1,1,3,0,0,0,0,0,0,0,0,0, - 0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,3,1,1,1,1,3,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, - 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,2,3,2,2,2,2,2,2,2,2,2,2,7,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,0,2,0, - 2,2,0,2,2,0,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,9,0,0,9,0,0,0,0,0,0,0,0,0,8,0,0,7,7,0,0,0,0,0,8,8,0,0,0,0,0,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0, - 0,0,0,8,8,8,0,0,0,0,0,7,9,7,9,9,6,6,6,6,6,6,6,6,6,6,9,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, - 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, - 0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,0,0,0,8,8,0,0,0,8,8,0,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,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, - 1,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,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,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 2,2,2,2,2,2,0,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,0,2,0,0,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,0,0,0,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,2, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,3,3,3,0,3,3,0,0,0,0,0,3,3,3,3,2,2,2,2,0,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,3,3,3,0,0,0,0,3, - 2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2,2,2,2,0,0,2,2,0,0,2,2,2,2,0,2, + 0,0,0,0,0,0,2,0,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2, + 2,2,2,4,4,4,4,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,9,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,4, + 3,4,4,3,4,4,3,4,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0, + 6,6,6,6,6,6,0,0,5,9,9,5,10,5,0,0,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,6,6,6,6,9,6,6,5,5,5,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,6,0,4,4,4,4,4,4,5,5,4,4,0,4,4,4,4,5,5,7,7,7,7,7,7,7,7,7,7,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,3,3,0,0,0,0,3,0,0,4,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,3,4,4,4,4,4,4,4,4,4,3,4,4,4,3,4,4,4,4,4,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,0,0,3,0,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,6,6,0,0,0,0,0,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,6,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,4,2,2,2, + 2,4,4,4,4,4,4,4,4,2,2,2,2,4,2,2,2,4,4,4,4,4,4,4,2,2,2,2,2,2,2,2,2,2,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,4,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,0,0,0,2,2,2,2,0,0,4,2,2,2, + 2,4,4,4,4,0,0,2,2,0,0,2,2,4,2,0,0,0,0,0,0,0,0,2,0,0,0,0,2,2,0,2,2,2,4,4,0,0,2,2,2,2,2,2,2,2,2,2,2,2,9,9,2,2,2,2,2,2,2,9,2,2,4,0, + 0,4,4,2,0,2,2,2,2,2,2,0,0,0,0,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,0,2,2,0,2,2,0,0,4,0,2,2, + 2,4,4,0,0,0,0,4,4,0,0,4,4,4,0,0,0,4,0,0,0,0,0,0,0,2,2,2,2,0,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,4,4,2,2,2,4,2,0,0,0,0,0,0,0,0,0, + 0,4,4,2,0,2,2,2,2,2,2,2,2,2,0,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,0,2,2,2,2,2,0,0,4,2,2,2, + 2,4,4,4,4,4,0,4,4,2,0,2,2,4,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,4,4,0,0,2,2,2,2,2,2,2,2,2,2,2,9,0,0,0,0,0,0,0,2,4,4,4,4,4,4, + 0,4,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,0,2,2,2,2,2,0,0,4,2,2,4, + 2,4,4,4,4,0,0,2,2,0,0,2,2,4,0,0,0,0,0,0,0,4,4,2,0,0,0,0,2,2,0,2,2,2,4,4,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0, + 0,0,4,2,0,2,2,2,2,2,2,0,0,0,2,2,2,0,2,2,2,2,0,0,0,2,2,0,2,0,2,2,0,0,0,2,2,0,0,0,2,2,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2, + 4,2,2,0,0,0,2,2,2,0,2,2,2,4,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,9,0,0,0,0,0,0, + 4,2,2,2,4,2,2,2,2,2,2,2,2,0,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,4,2,4,4, + 4,2,2,2,2,0,4,4,4,0,4,4,4,4,0,0,0,0,0,0,0,4,4,0,2,2,2,0,0,2,0,0,2,2,4,4,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,2, + 2,4,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,0,0,4,2,2,2, + 2,2,2,2,2,0,2,2,2,0,2,2,4,4,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,2,2,0,2,2,4,4,0,0,2,2,2,2,2,2,2,2,2,2,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0, + 4,4,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,2,2,2, + 2,4,4,4,4,0,2,2,2,0,2,2,2,4,2,2,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,4,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,0,0, + 2,2,2,2,2,2,2,0,0,0,4,0,0,0,0,2,2,2,4,4,4,0,4,0,2,2,2,2,2,2,2,2,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0, + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,2,4,4,4,4,4,4,4,0,0,0,0,9, + 2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,2,2,0,2,0,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,4,2,2,4,4,4,4,4,4,4,4,4,2,0,0, + 2,2,2,2,2,0,2,0,4,4,4,4,4,4,4,0,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,4,2,4,0,0,0,0,2,2, + 2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2, + 4,4,4,4,4,2,4,4,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,2,2, + 2,2,2,2,2,2,4,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,2,4,4,4,4,4,4,2,4,4,2,2,4,4,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,2,2,2,2,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,2,2,2,2,2,2,2,2,2,2,2, + 2,2,4,2,2,4,4,2,2,2,2,2,2,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,0,2,0,0,0,0,0,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,0,2,2,2,2,0,0,2,2,2,2,2,2,2,0,2,0,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,0,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,0,0,2,2,2,2,2,2,2,0, + 2,0,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,0, + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,2,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,2,2,2,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,2,4,4,4,4,4,4,4,2,2, + 2,2,2,2,2,2,4,2,2,4,4,4,4,4,4,4,4,4,4,4,2,2,2,2,2,2,2,9,2,4,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,4,4,4,1,4,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0, + 2,2,2,2,2,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,4,4,4,2,2,2,2,4,4,2,2,2,0,0,0,0,2,2,4,2,2,2,2,2,2,4,4,4,0,0,0,0, + 0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,2,2,4,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,4,4,4,4,4,4,4,0,4,2,4,2,2,4,4,4,4,4,4,4,4,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,0,0,4, + 2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 4,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,4,4,4,4,4,2,4,2,2,2, + 2,2,4,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2, + 4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,2,2,4,4,2,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,4,4,2,2,2,4,2,4,4,4,2,2,0,0,0,0,0,0,0,0,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,2,2,4,4,0,0,0,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2, + 2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,4,4,4,2,4,4,4,4,4,4,4,4,4,4,4,4,4,2,4,4,4,4,4,4,4,2,2,2,2,4,2,2,2,2,2,2,4,2,2,2,4,4,2,0,0,0,0,0, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,0,2,0,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,0, + 0,0,2,2,2,0,2,2,2,2,2,2,2,0,0,0,2,2,2,2,0,0,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,2,2,2,0,2,2,2,2,2,2,2,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,1,1,1,2,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,10,0,0,0,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,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,7,2,0,0,7,7,7,7,7,7,8,8,0,0,0,2, + 7,7,7,7,7,7,7,7,7,7,8,8,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,2,0,0,0,0,2,0,0,2,2,2,2,2,2,2,2,2,2,0,2,0,0,0,2,2,2,2,2,0,0,0,0,0,0,2,0,2,0,2,0,2,2,2,2,9,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2, + 0,0,0,0,0,2,2,2,2,2,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,2,2,2,2,4,4,4,2,2,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,0,0,0,0,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0, + 2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,4,4,4,4,2,2,0,2,2,2,2,2,0,0,2,2,2,2,2,0,0,0, + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,4,4,0,0,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2, + 0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, + 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,2,2,2,2,2,2,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,0,2,0,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,4,2,2,2,4,2,2,2,2,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,2,0,0,0,0,4,0,0,0,2,2,2,2,2,2,2,2,9,9,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,4,4,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,4, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,2,2,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0, + 4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,2,4,4,4,4,2,2,4,4,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,2,2,4,4,2,2,4,4,0,0,0,0,0,0,0,0,0, + 2,2,2,4,2,2,2,2,2,2,2,2,4,2,0,0,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,4,4,4,2,2,4,4,2,2,2,2,2,4,4, + 2,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,2,2,2,2,2,2,2,2,4,0,0,0,0,0,0,0,0,0, + 0,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,2,4,2,2,2,2,4,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0, + 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,0,0,0,0,0,3,4,3,3,3,3,3,3,3,3,3,3,8,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,3,3,0,3,0, + 3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,3,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,10,0,0,10,0,0,0,0,0,0,0,0,0,9,0,0,8,8,0,0,0,0,0,9,9,0,0,0,0,0,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,1, + 0,0,0,9,9,9,0,0,0,0,0,8,10,8,10,10,7,7,7,7,7,7,7,7,7,7,10,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0, + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, + 0,0,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,0,2,2,2,0,0,0,9,9,0,0,0,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0, + 2,0,2,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2,2,2,2,2, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,0,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,3,3,3,3,0,0,3,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,0,0,0,3,0,0,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,0,0,0,0,0,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,3, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,4,4,4,0,4,4,0,0,0,0,0,4,4,4,4,3,3,3,3,0,3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,4,4,4,0,0,0,0,4, + 3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,3,3,3,3,3,3, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,0,0,0,0,0,0,0,0,6,6,6,6,6,6,6,6,6,6,0,0,0,0,0,0, + 6,6,6,6,6,6,6,6,6,6,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,4,4,4,4,4,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,0,0,0,0,0,0,0,0,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,4,4,3,0,0,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,4,4,4,4,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0, + 2,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,4,2,2,4,4,2,0,0,0,0,0,0,0,0,0,4, + 4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,2,2,4,4,2,2,2,2,2, + 2,2,4,0,0,0,0,0,0,0,0,0,0,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0, + 4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,2,4,4,4,4,4,4,4,4,0,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,2,2,0,0,0,0,0,0,0,0,0, + 4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,2, + 2,2,2,2,2,2,2,2,2,4,4,4,4,2,2,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,2,2,4,2,4,4,2,2,2,2,2,2,4,2, + 2,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,0,2,0,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,2,2,4,4,4,4,4,4,4,4,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0, + 4,4,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,0,2,2,2,2,2,0,4,4,2,2,2, + 4,2,2,2,2,0,0,2,2,0,0,2,2,2,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,2,2,2,2,2,2,2,0,0,4,4,4,4,4,4,4,0,0,0,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,0,2,0,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,4,4,4,4,4, + 4,0,2,0,0,2,0,2,2,2,2,0,2,2,4,2,4,2,4,2,2,2,0,2,2,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4, + 2,2,4,4,4,2,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,4,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,2,4,2,2,2,2,4, + 4,2,4,4,2,2,2,2,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,0,0,2,2,2,2,4,4,2,4, + 4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,2,2,4,2,4, + 4,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,4,2,2,4,4,4,4,4,4,2,4,2,2,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,4,2,4,2,2,4,4,4,4,2,4,4,4,4,4,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,2,4,4,2,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,2, + 2,2,2,2,2,2,2,0,0,2,0,0,2,2,2,2,2,2,2,2,0,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,4,4,2,4,2, + 2,2,2,4,2,2,2,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,0,0,4,4,2,2,2,2,4,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,4,4,4,4,4,4,2,2,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,2,2,4,4,4,4,2, + 2,2,2,2,2,2,2,4,0,0,0,0,0,0,0,0,2,4,4,4,4,4,4,2,2,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,2,4,4,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,0,4,4,4,4,4,4,2,2, + 2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,2,4,4,4,4,4,4,4,2,4,4,2,4,4,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,0,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,0,0,0,4,0,4,4,0,4, + 4,4,4,4,4,4,2,4,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,2,2,2,2,2,2,0,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,4,4,0,2,2,4,2,4,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,2,2,2,2,0,0,0,0,0,0,0, + 4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,0,0,0,2,2, + 4,2,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0, - 5,5,5,5,5,5,5,5,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,3,3,3,3,3,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,3,3,2,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,3,3,3,3,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0, - 1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,1,1,1,1,1,1,1,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,1,1,1,1,1,1,1,1,1,3,1,1,3,3,1,0,0,0,0,0,0,0,0,0,3, - 3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,1,1,3,3,1,1,1,1,1, - 1,1,3,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, - 3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,1,3,3,3,3,3,3,3,3,0,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,0,0,0,0,0,0,0,0,0, - 3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1, - 1,1,1,1,1,1,1,1,1,3,3,3,3,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,1,1,3,1,3,3,1,1,1,1,1,1,3,1, - 1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,3,3,3,3,3,3,3,3,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, - 3,3,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,3,3,1,1,1, - 3,1,1,1,1,0,0,1,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,3,3,3,3,3,3,3,0,0,0,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,3,3,3,3,3, - 3,0,1,0,0,1,0,1,1,1,1,0,1,1,3,1,3,1,3,1,1,1,0,1,1,0,0,0,0,0,0,0,0,3,3,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3, - 1,1,3,3,3,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,3,1,1,1,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,1,1,1,1,3, - 3,1,3,3,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,0,0,1,1,1,1,3,3,1,3, - 3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,3,1,3, - 3,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,3,3,3,3,3,3,1,3,1,1,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3,1,3,1,1,3,3,3,3,1,3,3,3,3,3,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,3,3,1,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1, - 1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,3,3,1,3,1, - 1,1,1,3,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,0,0,3,3,1,1,1,1,3,1,1,1,1,0,0,0,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,3,3,3,3,3,3,1,1,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,1,1,3,3,3,3,1, - 1,1,1,1,1,1,1,3,0,0,0,0,0,0,0,0,1,3,3,3,3,3,3,1,1,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,0,3,3,3,3,3,3,1,1, - 1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,1,3,3,3,3,3,3,3,1,3,3,1,3,3,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,0,0,0,3,0,3,3,0,3, - 3,3,3,3,3,3,1,3,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,3,3,0,1,1,3,1,3,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,0,0,0,0,0,0,0, - 3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,0,0,0,1,1, - 3,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,8,8,8,8,0,0,0,0,0,0,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, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, - 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,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,1,0,1,3,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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, - 1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,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,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0, - 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,6,6,6,6,6,6,6,6,6,6,0,0,0,0,0,0, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,3,3,3,3,3, - 3,3,3,1,1,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1, - 1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0, - 1,1,1,1,1,0,1,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,0,1,1,1,1,1,1,1,1,0,0,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,3,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 3,3,3,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,3,3,3,3,3,3,0,3,3,0,3,3,3,3,3,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,3,3,3,3,3,3,3,1,1,1,1,1,1,1,0,0, - 1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,8, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 4,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,2,2,2,4,4,4,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, + 2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,4,4,4,4,4,2,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,3,3,3,3,3,3,3,2,0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,4,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,2,4,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,4,4,0,4,0,0,4,0,4,4,4,4,4,4,4,4,4,4,0,4,4,4,4,0,4,0,4,0,0,0,0, - 0,0,4,0,0,0,0,4,0,4,0,4,0,4,4,4,0,4,4,0,4,0,0,4,0,4,0,4,0,4,0,4,0,4,4,0,4,0,0,4,4,4,4,0,4,4,4,4,4,4,4,0,4,4,4,4,0,4,4,4,4,0,4,0, - 4,4,4,4,4,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,4,4,4,0,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 6,6,6,6,6,6,6,6,6,6,6,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, - 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,6,6,6,6,6,6,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,0, - 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,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,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2, + 2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,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,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0, + 2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,0,2,4,4,2,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,4,4,4,4,4, + 4,4,4,2,2,4,4,4,4,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,2,0,0,2,2,0,0,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2, + 2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,0,2,2,2,2,0,0,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,0, + 2,2,2,2,2,0,2,0,0,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,0,2,2,2,2,2,2,2,2,0,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2,2,2,2,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2,2,2,2,2,2,2,2,4,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,4,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 4,4,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,4,4,4,4,4,4,4,0,4,4,0,4,4,4,4,4,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,4,4,4,4,4,4,4,2,2,2,2,2,2,2,0,0, + 2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,9, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,0,2,2,2,2,0,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,3,3,3,0,0,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,4,4,4,4,4,4,4,3,0,0,0,0,3,3,3,3,3,3,3,3,3,3,0,0,0,0,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,0,5,0,0,5,0,5,5,5,5,5,5,5,5,5,5,0,5,5,5,5,0,5,0,5,0,0,0,0, + 0,0,5,0,0,0,0,5,0,5,0,5,0,5,5,5,0,5,5,0,5,0,0,5,0,5,0,5,0,5,0,5,0,5,5,0,5,0,0,5,5,5,5,0,5,5,5,5,5,5,5,0,5,5,5,5,0,5,5,5,5,0,5,0, + 5,5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,5,5,5,0,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0, + 2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0, + 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0, }; -KBTS_INLINE kbts_u8 kbts_GetUnicodeBidirectionalClass(kbts_u32 Codepoint) +KBTS_INLINE kbts_u8 kbts__GetUnicodeBidirectionalClass(kbts_u32 Codepoint) { - return kbts_UnicodeBidirectionalClass_Data[((kbts_un)kbts_UnicodeBidirectionalClass_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; + return (Codepoint < 1114110) ? kbts__UnicodeBidirectionalClass_Data[((kbts_un)kbts__UnicodeBidirectionalClass_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)] : 0; } -static kbts_u8 kbts_UnicodeJoiningType_PageIndices[8703] = { +static kbts_u8 kbts__UnicodeJoiningType_PageIndices[8703] = { 0,1,0,0,0,0,2,0,0,3,0,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, 25,26,0,0,0,0,27,0,0,0,0,0,0,0,28,29,30,31,32,0,33,34,35,36,37,38,0,39,0,0,0,0, 40,41,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42,43,44,0,0,0,0, @@ -9580,7 +10332,7 @@ static kbts_u8 kbts_UnicodeJoiningType_PageIndices[8703] = { 0,0,0,0,0,0,0,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 kbts_u8 kbts_UnicodeJoiningType_Data[14848] = { +static kbts_u8 kbts__UnicodeJoiningType_Data[14848] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -9815,12 +10567,12 @@ static kbts_u8 kbts_UnicodeJoiningType_Data[14848] = { 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, }; -KBTS_INLINE kbts_u8 kbts_GetUnicodeJoiningType(kbts_u32 Codepoint) +KBTS_INLINE kbts_u8 kbts__GetUnicodeJoiningType(kbts_u32 Codepoint) { - return kbts_UnicodeJoiningType_Data[((kbts_un)kbts_UnicodeJoiningType_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; + return (Codepoint < 1114110) ? kbts__UnicodeJoiningType_Data[((kbts_un)kbts__UnicodeJoiningType_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)] : 0; } -static kbts_u8 kbts_UnicodeCombiningClass_PageIndices[8703] = { +static kbts_u8 kbts__UnicodeCombiningClass_PageIndices[8703] = { 0,0,0,0,0,0,1,0,0,2,0,3,4,5,6,7,8,9,10,11,12,12,12,13,14,12,15,16,17,18,19,20, 21,22,0,0,0,0,23,0,0,0,0,0,0,0,24,25,0,26,27,0,28,29,30,31,32,33,0,34,0,0,0,0, 0,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,37,38,0,0,0,0, @@ -10095,7 +10847,7 @@ static kbts_u8 kbts_UnicodeCombiningClass_PageIndices[8703] = { 0,0,0,0,0,0,0,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 kbts_u8 kbts_UnicodeCombiningClass_Data[12288] = { +static kbts_u8 kbts__UnicodeCombiningClass_Data[12288] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,232,220,220,220,220,232,216,220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220,220,220,220,220,220,220,220,220,1,1,1,1,1,220,220,220,220,230,230,230, @@ -10290,12 +11042,12 @@ static kbts_u8 kbts_UnicodeCombiningClass_Data[12288] = { 0,0,0,0,230,230,230,230,230,230,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, }; -KBTS_INLINE kbts_u8 kbts_GetUnicodeCombiningClass(kbts_u32 Codepoint) +KBTS_INLINE kbts_u8 kbts__GetUnicodeCombiningClass(kbts_u32 Codepoint) { - return kbts_UnicodeCombiningClass_Data[((kbts_un)kbts_UnicodeCombiningClass_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; + return (Codepoint < 1114110) ? kbts__UnicodeCombiningClass_Data[((kbts_un)kbts__UnicodeCombiningClass_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)] : 0; } -static kbts_u16 kbts_UnicodeParentInfo_PageIndices[34815] = { +static kbts_u16 kbts__UnicodeParentInfo_PageIndices[34815] = { 0,1,2,3,0,4,5,6,7,0,8,9,0,10,0,11,0,12,0,0,13,14,0,0,15,0,0,0,16,17,18,0, 19,20,21,22,0,0,23,24,0,0,0,0,0,0,25,26,0,27,28,0,0,0,29,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,30,31,0,0,0,32,33,0,34,35,0,0,0,0,0,0,0,36,37,0,0,0,38,0, @@ -11386,7 +12138,7 @@ static kbts_u16 kbts_UnicodeParentInfo_PageIndices[34815] = { 0,0,0,0,0,0,0,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 kbts_u32 kbts_UnicodeParentInfo_Data[20960] = { +static kbts_u32 kbts__UnicodeParentInfo_Data[20960] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66400,66423,66421,66422,0, 0,1048664,197177,328094,393598,1114167,66418,459018,459046,983176,65810,393556,393562,197183,590017,1048696,131720,0,524539,459032,459067,1245203,131728,393604,131730,590026,393592,0,0,0,0,0, @@ -12044,12 +12796,12 @@ static kbts_u32 kbts_UnicodeParentInfo_Data[20960] = { 66424,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, }; -KBTS_INLINE kbts_u32 kbts_GetUnicodeParentInfo(kbts_u32 Codepoint) +KBTS_INLINE kbts_u32 kbts__GetUnicodeParentInfo(kbts_u32 Codepoint) { - return kbts_UnicodeParentInfo_Data[((kbts_un)kbts_UnicodeParentInfo_PageIndices[Codepoint/32] * 32) | (Codepoint & 31)]; + return (Codepoint < 1114110) ? kbts__UnicodeParentInfo_Data[((kbts_un)kbts__UnicodeParentInfo_PageIndices[Codepoint/32] * 32) | (Codepoint & 31)] : 0; } -static kbts_u8 kbts_UnicodeUseClass_PageIndices[4351] = { +static kbts_u8 kbts__UnicodeUseClass_PageIndices[4351] = { 0,1,1,1,1,1,2,3,4,5,6,7,8,9,10,11,12,1,1,1,1,1,1,13,14,15,16,17,18,19,1,1, 20,1,1,1,1,21,1,22,1,1,1,1,1,23,24,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, @@ -12188,7 +12940,7 @@ static kbts_u8 kbts_UnicodeUseClass_PageIndices[4351] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, }; -static kbts_u8 kbts_UnicodeUseClass_Data[16896] = { +static kbts_u8 kbts__UnicodeUseClass_Data[16896] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,21,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0, @@ -12455,53 +13207,1679 @@ static kbts_u8 kbts_UnicodeUseClass_Data[16896] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, }; -KBTS_INLINE kbts_u8 kbts_GetUnicodeUseClass(kbts_u32 Codepoint) +KBTS_INLINE kbts_u8 kbts__GetUnicodeUseClass(kbts_u32 Codepoint) { - return kbts_UnicodeUseClass_Data[((kbts_un)kbts_UnicodeUseClass_PageIndices[Codepoint/256] * 256) | (Codepoint & 255)]; + return (Codepoint < 1114110) ? kbts__UnicodeUseClass_Data[((kbts_un)kbts__UnicodeUseClass_PageIndices[Codepoint/256] * 256) | (Codepoint & 255)] : 0; } -KBTS_INLINE kbts_u32 kbts_GetDecompositionSize(kbts_u64 Decomposition) +static kbts_u8 kbts__UnicodeScriptExtension_PageIndices[8703] = { + 0,1,2,2,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,32,33,34,35,36,37,37,37,37,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,2,2,53,54, + 55,56,57,58,59,59,59,59,60,59,59,59,59,59,59,59,61,61,59,59,59,59,62,63,64,65,66,67,68,61,61,69, + 70,71,72,73,74,75,76,77,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,78,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 79,79,79,79,79,79,79,79,79,80,81,81,82,83,84,85,86,87,88,89,90,91,92,93,32,32,32,32,32,32,32,32, + 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, + 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, + 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,94,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,95,96,97,97,98,99,100,101,102,103, + 104,105,106,107,61,108,109,110,111,112,113,114,115,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133, + 134,135,136,137,138,139,140,141,142,143,61,144,145,146,147,61,148,149,150,151,152,153,154,155,156,157,158,159,61,160,161,162, + 163,163,163,163,163,163,163,164,165,163,166,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,167, + 168,168,168,168,168,168,168,168,169,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, + 168,168,168,168,168,168,168,170,171,171,171,171,172,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,173,61,61,61,61,61,61,61,61,61,61,61,61,61,174,174,174,174,175,176,177,178,61,61,179,61,180,181,182,183, + 184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, + 184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,185,184,184,184,184,184,184,186,186,186,187,188,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,189, + 190,191,192,193,193,194,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,195,196,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,59,197,59,59,59,198,199,200, + 59,201,202,203,204,205,206,61,207,208,209,59,59,210,59,211,212,212,212,212,212,213,61,61,61,61,61,61,61,61,214,61, + 215,216,217,61,61,218,61,61,61,219,61,220,61,61,61,221,222,223,224,61,61,61,61,61,225,226,227,61,228,229,61,61, + 230,231,59,232,233,61,59,59,59,59,59,59,59,234,235,236,237,238,59,59,239,240,59,241,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 242,61,243,244,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, +}; + +static kbts_u16 kbts__UnicodeScriptExtension_Data[31360] = { + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,929,929,929,929,929, + 929,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,2305,929,929,929,929,929,929,929,929,929,929,929,929,16,929,929,2305,929,929,929,929,929, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,929,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,929,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,929,929,929,519,929,929,929, + 929,929,929,929,929,929,929,738,929,738,738,738,929,610,929,929,929,929,929,929,929,929,929,802,929,738,929,929,929,929,929,929, + 2305,2305,2305,2305,2305,929,929,929,929,929,417,417,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 872,1128,1380,1509,1675,2022,932,2217,2506,1442,2819,2916,3043,1538,3138,961,1538,3203,961,3300,961,961,961,961,961,961,961,961,961,961,961,961, + 2850,961,961,3429,3588,2850,961,961,961,961,961,961,961,1539,2850,961,3715,3814,961,961,961,961,961,961,961,961,961,961,961,961,961,961, + 961,961,1441,961,961,1441,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,1218,961,961,961,961,961,4003,961, + 961,961,961,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,1441,1441,1441,1441,4098,4098,1441,1441,1,1,1441,1441,1441,1441,929,1441, + 1,1,1,1,1441,929,1441,929,1441,1441,1441,1,1441,1,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441, + 1441,1441,1,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441, + 1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441, + 1441,1441,801,801,801,801,801,801,801,801,801,801,801,801,801,801,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441, + 897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897, + 897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897, + 897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897, + 897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897, + 897,897,897,4162,4226,1410,1410,4226,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897, + 897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897, + 897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897, + 897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897, + 897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897, + 897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,1,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, + 161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,1,1,161,161,161,161,161,161,161, + 161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, + 161,161,161,161,161,161,161,161,161,4291,161,1,1,161,161,161,1,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729, + 1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729, + 1729,1729,1729,1729,1729,1729,1729,1729,1,1,1,1,1,1,1,1,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729, + 1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1,1,1,1,1729,1729,1729,1729,1729,1729,1,1,1,1,1,1,1,1,1,1,1, + 129,129,129,129,129,929,129,129,129,129,129,129,4391,129,129,129,129,129,129,129,129,129,129,129,129,129,129,4391,4611,129,129,4712, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 4969,129,129,129,129,129,129,129,129,129,129,4610,4610,4610,4610,4610,4610,4610,4610,4610,4610,4610,129,129,129,129,129,129,129,129,129,129, + 5251,5251,5251,5251,5251,5251,5251,5251,5251,5251,129,129,129,129,129,129,4610,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,4994,129,129,129,129,129,129,129,129,929,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,1,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577, + 4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577, + 4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,1,1,4577,4577,4577,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929, + 4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,4929,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297, + 3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,3297,1,1,3297,3297,3297, + 4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129, + 4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,1,1,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,4129,1, + 2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,2657,1,1,2657,1, + 4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,4577,1,1,1,1,1,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,1,129,129,1,1,1,1,1,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,929,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,5357,5772,961,961,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,6165,6839,7556,7556,7556,7556,7556,7556,7556,7556,7556,7556,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 353,353,353,353,1,353,353,353,353,353,353,353,353,1,1,353,353,1,1,353,353,353,353,353,353,353,353,353,353,353,353,353, + 353,353,353,353,353,353,353,353,353,1,353,353,353,353,353,353,353,1,353,1,1,1,353,353,353,353,1,1,353,353,353,353, + 353,353,353,353,353,1,1,353,353,1,1,353,353,353,353,1,1,1,1,1,1,1,1,353,1,1,1,1,353,353,1,353, + 353,353,353,353,1,1,7683,7683,7683,7683,7683,7683,7683,7683,7683,7683,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,1, + 1,1537,1537,1537,1,1537,1537,1537,1537,1537,1537,1,1,1,1,1537,1537,1,1,1537,1537,1537,1537,1537,1537,1537,1537,1537,1537,1537,1537,1537, + 1537,1537,1537,1537,1537,1537,1537,1537,1537,1,1537,1537,1537,1537,1537,1537,1537,1,1537,1537,1,1537,1537,1,1537,1537,1,1,1537,1,1537,1537, + 1537,1537,1537,1,1,1,1,1537,1537,1,1,1537,1537,1537,1,1,1,1537,1,1,1,1,1,1,1,1537,1537,1537,1537,1,1537,1, + 1,1,1,1,1,1,7778,7778,7778,7778,7778,7778,7778,7778,7778,7778,1537,1537,1537,1537,1537,1537,1537,1,1,1,1,1,1,1,1,1, + 1,1473,1473,1473,1,1473,1473,1473,1473,1473,1473,1473,1473,1473,1,1473,1473,1473,1,1473,1473,1473,1473,1473,1473,1473,1473,1473,1473,1473,1473,1473, + 1473,1473,1473,1473,1473,1473,1473,1473,1473,1,1473,1473,1473,1473,1473,1473,1473,1,1473,1473,1,1473,1473,1473,1473,1473,1,1,1473,1473,1473,1473, + 1473,1473,1473,1473,1473,1473,1,1473,1473,1473,1,1473,1473,1473,1,1,1473,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1473,1473,1473,1473,1,1,7842,7842,7842,7842,7842,7842,7842,7842,7842,7842,1473,1473,1,1,1,1,1,1,1,1473,1473,1473,1473,1473,1473,1473, + 1,3777,3777,3777,1,3777,3777,3777,3777,3777,3777,3777,3777,1,1,3777,3777,1,1,3777,3777,3777,3777,3777,3777,3777,3777,3777,3777,3777,3777,3777, + 3777,3777,3777,3777,3777,3777,3777,3777,3777,1,3777,3777,3777,3777,3777,3777,3777,1,3777,3777,1,3777,3777,3777,3777,3777,1,1,3777,3777,3777,3777, + 3777,3777,3777,3777,3777,1,1,3777,3777,1,1,3777,3777,3777,1,1,1,1,1,1,1,3777,3777,3777,1,1,1,1,3777,3777,1,3777, + 3777,3777,3777,3777,1,1,3777,3777,3777,3777,3777,3777,3777,3777,3777,3777,3777,3777,3777,3777,3777,3777,3777,3777,1,1,1,1,1,1,1,1, + 1,1,4801,4801,1,4801,4801,4801,4801,4801,4801,1,1,1,4801,4801,4801,1,4801,4801,4801,4801,1,1,1,4801,4801,1,4801,1,4801,4801, + 1,1,1,4801,4801,1,1,1,4801,4801,4801,1,1,1,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,1,1,1,1,4801,4801, + 4801,4801,4801,1,1,1,4801,4801,4801,1,4801,4801,4801,4801,1,1,4801,1,1,1,1,1,1,4801,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,7906,7906,7906,7906,7906,7906,7906,7906,7906,7906,7906,7906,7906,7906,4801,4801,4801,4801,4801,4801,4801,1,1,1,1,1, + 4897,4897,4897,4897,4897,4897,4897,4897,4897,4897,4897,4897,4897,1,4897,4897,4897,1,4897,4897,4897,4897,4897,4897,4897,4897,4897,4897,4897,4897,4897,4897, + 4897,4897,4897,4897,4897,4897,4897,4897,4897,1,4897,4897,4897,4897,4897,4897,4897,4897,4897,4897,4897,4897,4897,4897,4897,4897,1,1,4897,4897,4897,4897, + 4897,4897,4897,4897,4897,1,4897,4897,4897,1,4897,4897,4897,4897,1,1,1,1,1,1,1,4897,4897,1,4897,4897,4897,1,1,4897,1,1, + 4897,4897,4897,4897,1,1,4897,4897,4897,4897,4897,4897,4897,4897,4897,4897,1,1,1,1,1,1,1,4897,4897,4897,4897,4897,4897,4897,4897,4897, + 1953,1953,1953,1953,1953,1953,1953,1953,1953,1953,1953,1953,1953,1,1953,1953,1953,1,1953,1953,1953,1953,1953,1953,1953,1953,1953,1953,1953,1953,1953,1953, + 1953,1953,1953,1953,1953,1953,1953,1953,1953,1,1953,1953,1953,1953,1953,1953,1953,1953,1953,1953,1,1953,1953,1953,1953,1953,1,1,1953,1953,1953,1953, + 1953,1953,1953,1953,1953,1,1953,1953,1953,1,1953,1953,1953,1953,1,1,1,1,1,1,1,1953,1953,1,1,1,1,1,1,1953,1953,1, + 1953,1953,1953,1953,1,1,7971,7971,7971,7971,7971,7971,7971,7971,7971,7971,1,1953,1953,1953,1,1,1,1,1,1,1,1,1,1,1,1, + 2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,1,2625,2625,2625,1,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625, + 2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625, + 2625,2625,2625,2625,2625,1,2625,2625,2625,1,2625,2625,2625,2625,2625,2625,1,1,1,1,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625, + 2625,2625,2625,2625,1,1,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625,2625, + 1,4353,4353,4353,1,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,1,1,1,4353,4353,4353,4353,4353,4353, + 4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,1,4353,4353,4353,4353,4353,4353,4353,4353,4353,1,4353,1,1, + 4353,4353,4353,4353,4353,4353,4353,1,1,1,4353,1,1,1,1,4353,4353,4353,4353,4353,4353,1,4353,1,4353,4353,4353,4353,4353,4353,4353,4353, + 1,1,1,1,1,1,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,1,1,4353,4353,4353,1,1,1,1,1,1,1,1,1,1,1, + 1,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961, + 4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,1,1,1,1,929, + 4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,4961,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,2273,2273,1,2273,1,2273,2273,2273,2273,2273,1,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273, + 2273,2273,2273,2273,1,2273,1,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,1,1, + 2273,2273,2273,2273,2273,1,2273,1,2273,2273,2273,2273,2273,2273,2273,1,2273,2273,2273,2273,2273,2273,2273,2273,2273,2273,1,1,2273,2273,2273,2273, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993, + 4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993, + 4993,4993,4993,4993,4993,4993,4993,4993,1,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993, + 4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,1,1,1,1,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993, + 4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,1,4993,4993,4993,4993,4993,4993,4993, + 4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,1,4993,4993, + 4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,1,4993,4993,4993,4993,4993,4993,4993,929,929,929,929,4993,4993,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105, + 3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105, + 8067,8067,8067,8067,8067,8067,8067,8067,8067,8067,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105, + 3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105, + 3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105, + 1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313, + 1313,1313,1313,1313,1313,1313,1,1313,1,1,1,1,1,1313,1,1,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313, + 1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,8163,1313,1313,1313,1313, + 1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601, + 1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601, + 1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601, + 1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601, + 1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249, + 1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249, + 1249,1249,1249,1249,1249,1249,1249,1249,1249,1,1249,1249,1249,1249,1,1,1249,1249,1249,1249,1249,1249,1249,1,1249,1,1249,1249,1249,1249,1,1, + 1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249, + 1249,1249,1249,1249,1249,1249,1249,1249,1249,1,1249,1249,1249,1249,1,1,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249, + 1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1,1249,1249,1249,1249,1,1,1249,1249,1249,1249,1249,1249,1249,1, + 1249,1,1249,1249,1249,1249,1,1,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1,1249,1249,1249,1249,1249,1249,1249,1249, + 1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249, + 1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1,1249,1249,1249,1249,1,1,1249,1249,1249,1249,1249,1249,1249,1249, + 1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249, + 1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1,1,1249,1249,1249, + 1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1,1,1, + 1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1,1,1,1,1,1, + 705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705, + 705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705, + 705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,1,1,705,705,705,705,705,705,1,1, + 545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545, + 545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545, + 545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545, + 545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545, + 3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,3393,1,1,1, + 4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097, + 4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097, + 4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,4097,1,1,1,1,1,1,1, + 4609,4609,4609,4609,4609,4609,4609,4609,4609,4609,4609,4609,4609,4609,4609,4609,4609,4609,4609,4609,4609,4609,1,1,1,1,1,1,1,1,1,4609, + 1665,1665,1665,1665,1665,1665,1665,1665,1665,1665,1665,1665,1665,1665,1665,1665,1665,1665,1665,1665,1665,8260,8260,1,1,1,1,1,1,1,1,1, + 513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,1,1,1,1,1,1,1,1,1,1,1,1, + 4641,4641,4641,4641,4641,4641,4641,4641,4641,4641,4641,4641,4641,1,4641,4641,4641,1,4641,4641,1,1,1,1,1,1,1,1,1,1,1,1, + 2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145, + 2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145, + 2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,1,1, + 2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,1,1,1,1,1,1,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,1,1,1,1,1,1, + 3009,3009,8386,8386,3009,8386,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,1,1,1,1,1,1, + 3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009, + 3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009, + 3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,1,1,1,1,1,1,1, + 3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009, + 3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,1,1,1,1,1,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545, + 545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545, + 545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,1,1,1,1,1,1,1,1,1,1, + 2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,1, + 2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,1,1,1,1,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,1,1,1,1, + 2369,1,1,1,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,2369,4673,4673,4673,4673,4673,4673,4673,4673,4673,4673,4673,4673,4673,4673,4673,4673, + 4673,4673,4673,4673,4673,4673,4673,4673,4673,4673,4673,4673,4673,4673,1,1,4673,4673,4673,4673,4673,1,1,1,1,1,1,1,1,1,1,1, + 3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265, + 3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,1,1,1,1,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265, + 3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,1,1,1,1,1,1,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,3265,1,1,1,3265,3265, + 2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145,2145, + 481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,1,1,481,481, + 4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705, + 4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,1, + 4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,1,1,4705, + 4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,1,1,1,1,1,1,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,1,1,1,1,1,1, + 4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,4705,1,1,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961, + 961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, + 225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, + 225,225,225,225,225,225,225,225,225,225,225,225,225,1,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, + 225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, + 4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481, + 4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481,4481, + 321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321, + 321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,1,1,1,1,1,1,1,1,321,321,321,321, + 2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337, + 2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,1,1,1,2337,2337,2337,2337,2337, + 2337,2337,2337,2337,2337,2337,2337,2337,2337,2337,1,1,1,2337,2337,2337,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425, + 3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425,3425, + 897,897,897,897,897,897,897,897,897,897,897,1,1,1,1,1,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313, + 1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1,1,1313,1313,1313, + 4481,4481,4481,4481,4481,4481,4481,4481,1,1,1,1,1,1,1,1,8452,1025,8452,8483,1025,5346,5346,8578,5346,8578,8646,1025,8578,8578,1025,1025, + 8578,5346,1025,1025,1025,1025,1025,1025,1025,8834,5346,1025,1025,5346,1025,1025,1025,1025,8907,5378,9252,5346,5346,353,5378,5378,3201,1,1,1,1,1, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,1441,1441,1441,1441,1441,897,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,1441,1441,1441, + 1441,1441,2305,2305,2305,2305,1441,1441,1441,1441,1441,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,897,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,1441, + 1441,1441,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961, + 961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,9379,961,4577,961,961,961,961,961, + 1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1,1,1441,1441,1441,1441,1441,1441,1,1, + 1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441, + 1441,1441,1441,1441,1441,1441,1,1,1441,1441,1441,1441,1441,1441,1,1,1441,1441,1441,1441,1441,1441,1441,1441,1,1441,1,1441,1,1441,1,1441, + 1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1,1, + 1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441, + 1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441, + 1441,1441,1441,1441,1441,1,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1,1,1441,1441,1441,1441,1441,1441,1,1441,1441,1441, + 1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1,1,1441,1441,1441,1,1441,1441,1441,1441,1441,1441,1441,1441,1441,1, + 929,929,929,929,929,929,929,929,929,929,929,929,961,961,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,9475,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,4706,929,929,929,929,929,929,929,929,929,929,9574,929,929,9764,929,929, + 929,929,929,929,929,1,929,929,929,929,929,929,929,929,929,929,929,2305,1,1,929,929,929,929,929,929,929,929,929,929,929,2305, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961, + 961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,9891,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,1441,929,929,929,2305,2305,929,929,929,929,929,929,2305,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,2305,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,929,929,929,1,1,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345, + 1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345, + 1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801, + 801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801, + 801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801, + 801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,1,1,1,1,1,801,801,801,801,801,801,801, + 1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313, + 1313,1313,1313,1313,1313,1313,1,1313,1,1,1,1,1,1313,1,1,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025, + 5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025,5025, + 5025,5025,5025,5025,5025,5025,5025,5025,1,1,1,1,1,1,1,5025,5025,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5025, + 1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1,1,1,1,1,1,1,1,1, + 1249,1249,1249,1249,1249,1249,1249,1,1249,1249,1249,1249,1249,1249,1249,1,1249,1249,1249,1249,1249,1249,1249,1,1249,1249,1249,1249,1249,1249,1249,1, + 1249,1249,1249,1249,1249,1249,1249,1,1249,1249,1249,1249,1249,1249,1249,1,1249,1249,1249,1249,1249,1249,1249,1,1249,1249,1249,1249,1249,1249,1249,1, + 897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,9986,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,10050,10119,929,929,929,929,929,929,929,929,929,929,1121,929,929,929, + 929,10339,929,4226,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,10434,10434,10434,10434,10434,10434,10434,10434,10434,10434,10434,10434,10434,10434,10434,10434, + 929,10503,10728,10501,929,1,769,1,10984,10984,11241,11241,11526,11526,11526,11526,11526,11526,929,10501,11526,11526,11526,11526,11526,11526,11526,11526,10501,10501,10501,10501, + 929,1,1,1,1,1,1,1,1,1,10498,10498,10498,10498,1601,1601,10501,10594,10594,10594,10594,10594,929,10501,1,1,1,1,11715,11715,769,769, + 1,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761, + 1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761, + 1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1,1,10594,10594,10594,10594,1761,1761,1761, + 10594,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985, + 1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985, + 1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,11526,10594,1985,1985,1985, + 1,1,1,1,1,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417, + 417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,1,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601, + 1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601, + 1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601, + 1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769, + 417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417, + 769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769, + 769,769,769,769,769,769,1,1,1,1,1,1,1,1,1,10434,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985, + 1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1, + 769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769, + 769,769,769,769,769,769,769,769,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,929, + 769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769, + 769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 769,769,769,769,769,769,769,769,769,769,769,769,929,929,929,929,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985, + 1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,769, + 1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985, + 1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985, + 1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,769,769,769,769,769,769,769,769, + 769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,929,929,929,929,929,929,929,929,929,929,769,769,769,769,769, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,929, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377, + 5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377, + 5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377, + 5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377, + 5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,1,1,1,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377, + 5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377,5377, + 5377,5377,5377,5377,5377,5377,5377,1,1,1,1,1,1,1,1,1,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465, + 2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465,2465, + 5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217, + 5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217, + 5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217, + 5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217, + 5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217, + 5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,5217,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897, + 897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,4226,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897, + 897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897, + 257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257, + 257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257, + 257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,1,1,1,1,1,1,1,1, + 11810,11810,11810,11810,11810,11810,11810,11810,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,929,929,929,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,1,1,2305,2305,1,2305,1,2305,2305,2305,2305,2305,2305,2305,2305,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545, + 4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,4545,1,1,1,11888,11888,11888,12399,12399,12399,12875,12875,13228,12875,1,1,1,1,1,1, + 3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969, + 3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,3969,1,1,1,1,1,1,1,1, + 4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161, + 4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161, + 4161,4161,4161,4161,4161,4161,1,1,1,1,1,1,1,1,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,4161,1,1,1,1,1,1, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,13603,1025,13698,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049, + 2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,2049,13763,2049,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065, + 4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,4065,1,1,1,1,1,1,1,1,1,1,1,4065, + 1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1,1,1, + 1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889, + 1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889, + 1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1,13858,1889,1889,1889,1889,1889,1889,1889,1889,1889,1889,1,1,1,1,1889,1889, + 3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,1, + 673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673, + 673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,1,1,1,1,1,1,1,1,1, + 673,673,673,673,673,673,673,673,673,673,673,673,673,673,1,1,673,673,673,673,673,673,673,673,673,673,1,1,673,673,673,673, + 3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105, + 4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737, + 4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737,4737, + 4737,4737,4737,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4737,4737,4737,4737,4737, + 2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,1,1,1,1,1,1,1,1,1, + 1,1249,1249,1249,1249,1249,1249,1,1,1249,1249,1249,1249,1249,1249,1,1,1249,1249,1249,1249,1249,1249,1,1,1,1,1,1,1,1,1, + 1249,1249,1249,1249,1249,1249,1249,1,1249,1249,1249,1249,1249,1249,1249,1,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,929,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,1441,2305,2305,2305,2305,929,929,1,1,1,1,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705, + 705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705, + 705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705, + 2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817, + 2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,1,1,2817,2817,2817,2817,2817,2817,2817,2817,2817,2817,1,1,1,1,1,1, + 1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601, + 1601,1601,1601,1601,1,1,1,1,1,1,1,1,1,1,1,1,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601, + 1601,1601,1601,1601,1601,1601,1601,1,1,1,1,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601, + 1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1,1,1,1, + 2305,2305,2305,2305,2305,2305,2305,1,1,1,1,1,1,1,1,1,1,1,1,161,161,161,161,161,1,1,1,1,1,1729,1729,1729, + 1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,1,1729,1729,1729,1729,1729,1,1729,1, + 1729,1729,1,1729,1729,1,1729,1729,1729,1729,1729,1729,1729,1729,1729,1729,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,13922,13922, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,1,1,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,1,1,1,1,1,1,1,129,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,129,129,5250,129,129,129,129,129,129,129,129,129,129,5250,129,129, + 961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1, + 961,961,961,961,961,961,961,961,961,961,961,961,961,961,897,897,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,10501,10501,929,929,929,929,929,929,929,929,929,929,929,929,1,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,1,929,929,929,929,1,1,1,1,129,129,129,129,129,1,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,1,1,929, + 1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,929,929,929,929,929, + 929,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,929,929,929,929,929, + 929,11526,11526,11526,11526,11526,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,10594,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985, + 1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,1985,10594,10594, + 1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1601,1, + 1,1,1601,1601,1601,1601,1601,1601,1,1,1601,1601,1601,1601,1601,1601,1,1,1601,1601,1601,1601,1601,1601,1,1,1601,1601,1601,1,1,1, + 929,929,929,929,929,929,929,1,929,929,929,929,929,929,929,1,1,1,1,1,1,1,1,1,1,929,929,929,929,929,1,1, + 2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,1,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433, + 2433,2433,2433,2433,2433,2433,2433,1,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,1,2433,2433,1,2433, + 2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,1,1,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433, + 2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433, + 2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433, + 2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,2433,1,1,1,1,1, + 13987,13987,14082,1,1,1,1,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147, + 14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,14147,1,1,1,14082,14082,14082,14082,14082,14082,14082,14082,14082, + 1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441, + 1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441, + 1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1, + 1441,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,961,1,1, + 2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,2497,1,1,1, + 577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577, + 577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,14242,1,1,1,1, + 3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489,3489, + 3489,3489,3489,3489,1,1,1,1,1,1,1,1,1,3489,3489,3489,1377,1377,1377,1377,1377,1377,1377,1377,1377,1377,1377,1377,1377,1377,1377,1377, + 1377,1377,1377,1377,1377,1377,1377,1377,1377,1377,1377,1,1,1,1,1,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585, + 3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,3585,1,1,1,1,1, + 5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,5185,1,5185, + 3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617, + 3617,3617,3617,3617,1,1,1,1,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,3617,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993, + 993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993, + 993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225, + 4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225,4225, + 3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,1,1, + 3841,3841,3841,3841,3841,3841,3841,3841,3841,3841,1,1,1,1,1,1,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809, + 3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,1,1,1,1,3809,3809,3809,3809,3809,3809,3809,3809, + 3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,3809,1,1,1,1, + 1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185,1185, + 1185,1185,1185,1185,1185,1185,1185,1185,1,1,1,1,1,1,1,1,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609, + 609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609, + 609,609,609,609,1,1,1,1,1,1,1,1,1,1,1,609,5249,5249,5249,5249,5249,5249,5249,5249,5249,5249,5249,1,5249,5249,5249,5249, + 5249,5249,5249,5249,5249,5249,5249,5249,5249,5249,5249,1,5249,5249,5249,5249,5249,5249,5249,1,5249,5249,1,5249,5249,5249,5249,5249,5249,5249,5249,5249, + 5249,5249,1,5249,5249,5249,5249,5249,5249,5249,5249,5249,5249,5249,5249,5249,5249,5249,1,5249,5249,5249,5249,5249,5249,5249,1,5249,5249,1,1,1, + 5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089, + 5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,5089,1,1,1,1,1,1,1,1,1,1,1,1, + 2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401, + 2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401, + 2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401, + 2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401, + 2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401, + 2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,1,1,1,1,1,1,1,1,1, + 2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,2401,1,1,1,1,1,1,1,1,1,1, + 2401,2401,2401,2401,2401,2401,2401,2401,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2305,2305,2305,2305,2305,2305,1,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,1,2305,2305,2305,2305,2305,2305,2305,2305,2305,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 833,833,833,833,833,833,1,1,833,1,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833, + 833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,1,833,833,1,1,1,833,1,1,833, + 1793,1793,1793,1793,1793,1793,1793,1793,1793,1793,1793,1793,1793,1793,1793,1793,1793,1793,1793,1793,1793,1793,1,1793,1793,1793,1793,1793,1793,1793,1793,1793, + 3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905,3905, + 3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,3137,1, + 1,1,1,1,1,1,1,3137,3137,3137,3137,3137,3137,3137,3137,3137,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1697,1697,1697,1697,1697,1697,1697,1697,1697,1697,1697,1697,1697,1697,1697,1697,1697,1697,1697,1,1697,1697,1,1,1,1,1,1697,1697,1697,1697,1697, + 4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,4001,1,1,1,4001, + 2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,2529,1,1,1,1,1,2529, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913,2913, + 2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,1,1,1,1,2881,2881,2881,2881, + 2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,1,1,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881, + 2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881,2881, + 2081,2081,2081,2081,1,2081,2081,1,1,1,1,1,2081,2081,2081,2081,2081,2081,2081,2081,1,2081,2081,2081,1,2081,2081,2081,2081,2081,2081,2081, + 2081,2081,2081,2081,2081,2081,2081,2081,2081,2081,2081,2081,2081,2081,2081,2081,2081,2081,2081,2081,2081,2081,1,1,2081,2081,2081,1,1,1,1,2081, + 2081,2081,2081,2081,2081,2081,2081,2081,2081,1,1,1,1,1,1,1,2081,2081,2081,2081,2081,2081,2081,2081,2081,1,1,1,1,1,1,1, + 3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681,3681, + 3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553,3553, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689,2689, + 2689,2689,2689,2689,2689,2689,2689,1,1,1,1,2689,2689,2689,2689,2689,2689,2689,5090,2689,2689,2689,2689,1,1,1,1,1,1,1,1,1, + 193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, + 193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,1,1,1,193,193,193,193,193,193,193, + 1857,1857,1857,1857,1857,1857,1857,1857,1857,1857,1857,1857,1857,1857,1857,1857,1857,1857,1857,1857,1857,1857,1,1,1857,1857,1857,1857,1857,1857,1857,1857, + 1825,1825,1825,1825,1825,1825,1825,1825,1825,1825,1825,1825,1825,1825,1825,1825,1825,1825,1825,1,1,1,1,1,1825,1825,1825,1825,1825,1825,1825,1825, + 4033,4033,4033,4033,4033,4033,4033,4033,4033,4033,4033,4033,4033,4033,4033,4033,4033,4033,1,1,1,1,1,1,1,4033,4033,4033,4033,1,1,1, + 1,1,1,1,1,1,1,1,1,4033,4033,4033,4033,4033,4033,4033,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713, + 3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713,3713, + 3713,3713,3713,3713,3713,3713,3713,3713,3713,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521, + 3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,1,1,1,1,1,1,1,1,1,1,1,1,1, + 3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521, + 3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,3521,1,1,1,1,1,1,1,3521,3521,3521,3521,3521,3521, + 1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633, + 1633,1633,1633,1633,1633,1633,1633,1633,1,1,1,1,1,1,1,1,1633,1633,1633,1633,1633,1633,1633,1633,1633,1633,1,1,1,1,1,1, + 1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281, + 1281,1281,1281,1281,1281,1281,1,1,1,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281, + 1281,1281,1281,1281,1281,1281,1,1,1,1,1,1,1,1,1281,1281,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,1, + 5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,5345, + 5345,5345,5345,5345,5345,5345,5345,5345,5345,5345,1,5345,5345,5345,1,1,5345,5345,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,129,129,129,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,129,129,129,129, + 3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649,3649, + 3649,3649,3649,3649,3649,3649,3649,3649,1,1,1,1,1,1,1,1,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321, + 4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,4321,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3745,3745,3745,3745,3745,3745,3745,3745,3745,3745,3745,3745,3745,3745,3745,3745, + 3745,3745,3745,3745,3745,3745,3745,3745,3745,3745,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,737,737,737,737,737,737,737,737,737,737,737,737,737,737,737,737, + 737,737,737,737,737,737,737,737,737,737,737,737,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1217,1217,1217,1217,1217,1217,1217,1217,1217,1217,1217,1217,1217,1217,1217,1217,1217,1217,1217,1217,1217,1217,1217,1,1,1,1,1,1,1,1,1, + 449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449, + 449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449, + 449,449,449,449,449,449,449,449,449,449,449,449,449,449,1,1,1,1,449,449,449,449,449,449,449,449,449,449,449,449,449,449, + 449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,1,1,1,1,1,1,1,1,1,449, + 1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921, + 1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921,1921, + 1921,1921,1921,1,1,1,1,1,1,1,1,1,1,1921,1,1,4385,4385,4385,4385,4385,4385,4385,4385,4385,4385,4385,4385,4385,4385,4385,4385, + 4385,4385,4385,4385,4385,4385,4385,4385,4385,1,1,1,1,1,1,1,4385,4385,4385,4385,4385,4385,4385,4385,4385,4385,1,1,1,1,1,1, + 641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641, + 641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,1,641,641,641,641,641,641,641,641,641,641, + 641,641,641,641,641,641,641,641,1,1,1,1,1,1,1,1,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561, + 2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,2561,1,1,1,1,1,1,1,1,1, + 4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193, + 4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193, + 4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193,4193, + 1,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,4353,1,1,1,1,1,1,1,1,1,1,1, + 2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,1,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177, + 2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177,2177, + 2177,2177,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 3073,3073,3073,3073,3073,3073,3073,1,3073,1,3073,3073,3073,3073,1,3073,3073,3073,3073,3073,3073,3073,3073,3073,3073,3073,3073,3073,3073,3073,1,3073, + 3073,3073,3073,3073,3073,3073,3073,3073,3073,3073,1,1,1,1,1,1,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209, + 2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209, + 2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,1,1,1,1,1,2209,2209,2209,2209,2209,2209,2209,2209,2209,2209,1,1,1,1,1,1, + 1409,7906,1409,7906,1,1409,1409,1409,1409,1409,1409,1409,1409,1,1,1409,1409,1,1,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409, + 1409,1409,1409,1409,1409,1409,1409,1409,1409,1,1409,1409,1409,1409,1409,1409,1409,1,1409,1409,1,1409,1409,1409,1409,1409,1,7906,7906,1409,1409,1409, + 1409,1409,1409,1409,1409,1,1,1409,1409,1,1,1409,1409,1409,1,1,1409,1,1,1,1,1,1,1409,1,1,1,1,1,1409,1409,1409, + 1409,1409,1409,1409,1,1,1409,1409,1409,1409,1409,1409,1409,1,1,1,1409,1409,1409,1409,1409,1,1,1,1,1,1,1,1,1,1,1, + 5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,1,5153,1,1,5153,1,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153, + 5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,1,5153,5153,5153,5153,5153,5153,5153,5153,5153, + 5153,1,5153,1,1,5153,1,5153,5153,5153,5153,1,5153,5153,5153,5153,5153,5153,5153,5153,5153,5153,1,5153,5153,1,1,1,1,1,1,1, + 1,5153,5153,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233, + 3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233, + 3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,3233,1,3233,3233,3233, + 3233,3233,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057, + 5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057, + 5057,5057,5057,5057,5057,5057,5057,5057,1,1,1,1,1,1,1,1,5057,5057,5057,5057,5057,5057,5057,5057,5057,5057,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257, + 4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,1,1,4257,4257,4257,4257,4257,4257,4257,4257, + 4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,4257,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977, + 2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977, + 2977,2977,2977,2977,2977,1,1,1,1,1,1,1,1,1,1,1,2977,2977,2977,2977,2977,2977,2977,2977,2977,2977,1,1,1,1,1,1, + 3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,3009,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769, + 4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,1,1,1,1,1,1, + 4769,4769,4769,4769,4769,4769,4769,4769,4769,4769,1,1,1,1,1,1,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105,3105, + 3105,3105,3105,3105,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,1,1,65,65,65, + 65,65,65,65,65,65,65,65,65,65,65,65,1,1,1,1,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089, + 1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313, + 5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313, + 5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,5313,1,1,1,1,1,1,1,1,1,1,1,1,5313, + 1057,1057,1057,1057,1057,1057,1057,1,1,1057,1,1,1057,1057,1057,1057,1057,1057,1057,1057,1,1057,1057,1,1057,1057,1057,1057,1057,1057,1057,1057, + 1057,1057,1057,1057,1057,1057,1057,1057,1057,1057,1057,1057,1057,1057,1057,1057,1057,1057,1057,1057,1057,1057,1,1057,1057,1,1,1057,1057,1057,1057,1057, + 1057,1057,1057,1057,1057,1057,1057,1,1,1,1,1,1,1,1,1,1057,1057,1057,1057,1057,1057,1057,1057,1057,1057,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 3201,3201,3201,3201,3201,3201,3201,3201,1,1,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201, + 3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,3201,1,1,3201,3201,3201,3201,3201,3201, + 3201,3201,3201,3201,3201,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409, + 5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409,5409, + 5409,5409,5409,5409,5409,5409,5409,5409,1,1,1,1,1,1,1,1,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417, + 4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417, + 4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417,4417, + 4417,4417,4417,1,1,1,1,1,1,1,1,1,1,1,1,1,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545, + 3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937, + 3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,3937,1,1,1,1,1,1,1, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513, + 4513,4513,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4513,4513,4513,4513,4513,4513,4513,4513,4513,4513,1,1,1,1,1,1, + 385,385,385,385,385,385,385,385,385,1,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385, + 385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,1,385,385,385,385,385,385,385,385, + 385,385,385,385,385,385,1,1,1,1,1,1,1,1,1,1,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385,385, + 385,385,385,385,385,385,385,385,385,385,385,385,385,1,1,1,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721, + 2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,1,1,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721, + 2721,2721,2721,2721,2721,2721,2721,2721,1,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,2721,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2753,2753,2753,2753,2753,2753,2753,1,2753,2753,1,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753, + 2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,1,1,1,2753,1,2753,2753,1,2753, + 2753,2753,2753,2753,2753,2753,2753,2753,1,1,1,1,1,1,1,1,2753,2753,2753,2753,2753,2753,2753,2753,2753,2753,1,1,1,1,1,1, + 1505,1505,1505,1505,1505,1505,1,1505,1505,1,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505, + 1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1,1505,1505,1,1505,1505,1505,1505,1505,1505,1,1,1,1,1,1,1, + 1505,1505,1505,1505,1505,1505,1505,1505,1505,1505,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2593,2593,2593,2593,2593,2593,2593,2593,2593,2593,2593,2593,2593,2593,2593,2593,2593,2593,2593,2593,2593,2593,2593,2593,2593,1,1,1,1,1,1,1, + 2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,1,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017, + 2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,1,1,1,2017,2017, + 2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2465,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,7906,7906,4801,7906,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801, + 4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,4801,1,1,1,1,1,1,1,1,1,1,1,1,1,4801, + 4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449, + 4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449, + 4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449, + 4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449, + 4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449, + 4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449, + 4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449, + 4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,1,4449,4449,4449,4449,4449,1,1,1,1,1,1,1,1,1,1,1, + 4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449, + 4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449,4449, + 4449,4449,4449,4449,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865, + 865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865, + 865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865, + 865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,865,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153, + 1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153, + 1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153, + 1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153, + 1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153, + 1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153, + 1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1,1,1,1,1,1,1,1,1,1, + 1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153, + 1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153, + 1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153, + 1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153, + 1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1153,1,1,1,1,1, + 97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, + 97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, + 97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, + 97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, + 97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, + 97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, + 97,97,97,97,97,97,97,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569, + 1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1569,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257, + 257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257, + 257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257, + 257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257, + 257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257, + 257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,257,1,1,1,1,1,1,1, + 3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,1, + 3041,3041,3041,3041,3041,3041,3041,3041,3041,3041,1,1,1,1,3041,3041,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833, + 4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833, + 4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,1, + 4833,4833,4833,4833,4833,4833,4833,4833,4833,4833,1,1,1,1,1,1,289,289,289,289,289,289,289,289,289,289,289,289,289,289,289,289, + 289,289,289,289,289,289,289,289,289,289,289,289,289,289,1,1,289,289,289,289,289,289,1,1,1,1,1,1,1,1,1,1, + 3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873, + 3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873, + 3873,3873,3873,3873,3873,3873,1,1,1,1,1,1,1,1,1,1,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,1,3873,3873,3873,3873,3873, + 3873,3873,1,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,1,1,1,1,1,3873,3873,3873, + 3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,3873,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241, + 2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,2241,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785, + 2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785, + 2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,2785,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945, + 2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945, + 2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,1,1,1,1,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945, + 2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945, + 2945,2945,2945,2945,2945,2945,2945,2945,1,1,1,1,1,1,1,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945,2945, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 4865,3329,1,1,2113,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865, + 4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865, + 4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865, + 4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865, + 4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865, + 4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865, + 4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865, + 4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,4865,1,1,1,1,1,1,1,1, + 2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113, + 2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113, + 2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113, + 2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113, + 2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113, + 2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113, + 2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,2113,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2113, + 4865,4865,4865,4865,4865,4865,4865,4865,4865,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1985,1985,1985,1985,1,1985,1985,1985,1985,1985,1985,1985,1,1985,1985,1, + 1985,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761, + 1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761, + 1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761, + 1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761, + 1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761, + 1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761, + 1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761, + 1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761, + 1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761,1761, + 1985,1985,1985,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1761,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1761,1761,1761,1,1,1985,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1985,1985,1985,1985,1,1,1,1,1,1,1,1,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329, + 3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329, + 3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329, + 3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329, + 3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329, + 3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329, + 3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329, + 3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329, + 3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,3329,1,1,1,1, + 1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121, + 1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121, + 1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121, + 1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1,1,1,1,1,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1,1,1, + 1121,1121,1121,1121,1121,1121,1121,1121,1121,1,1,1,1,1,1,1,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1,1,1121,1121,1121,1121, + 1121,1121,1121,1121,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961, + 961,961,961,961,961,961,961,961,961,961,961,961,961,961,1,1,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961, + 961,961,961,961,961,961,961,1,1,1,1,1,1,1,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,961,961,961,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,961,961,961,961,961, + 961,961,961,929,929,961,961,961,961,961,961,961,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,961,961,961,961,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441, + 1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441,1441, + 1441,1441,1441,1441,1441,1441,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1,1,1,1, + 769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,769,929,929,929,929,929,929,929,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,929,929, + 1,1,929,1,1,929,929,1,1,929,929,929,929,1,929,929,929,929,929,929,929,929,929,929,929,929,1,929,1,929,929,929, + 929,929,929,929,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,1,929,929,929,929,1,1,929,929,929,929,929,929,929,929,1,929,929,929,929,929,929,929,1,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,929,929,929,929,1, + 929,929,929,929,929,1,929,1,1,1,929,929,929,929,929,929,929,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289, + 4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289, + 4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289, + 4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289, + 4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4289,4289,4289,4289,4289, + 1,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,4289,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,2305,1, + 1,1,1,1,1,2305,2305,2305,2305,2305,2305,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1345,1345,1345,1345,1345,1345,1345,1,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1345,1,1,1345,1345,1345,1345,1345, + 1345,1345,1,1345,1345,1,1345,1345,1345,1345,1345,1,1,1,1,1,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897, + 897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897, + 897,897,897,897,897,897,897,897,897,897,897,897,897,897,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,897,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361, + 3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,1,1,1,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,1,1, + 3361,3361,3361,3361,3361,3361,3361,3361,3361,3361,1,1,1,1,3361,3361,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5121,5121,5121,5121,5121,5121,5121,5121,5121,5121,5121,5121,5121,5121,5121,5121, + 5121,5121,5121,5121,5121,5121,5121,5121,5121,5121,5121,5121,5121,5121,5121,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281, + 5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,5281,1,1,1,1,1,5281, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169, + 3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,3169,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457, + 3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,3457,1,1,1,1,3457, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1249,1249,1249,1249,1249,1249,1249,1,1249,1249,1249,1249,1,1249,1249,1,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1, + 2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849, + 2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849, + 2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849, + 2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849, + 2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849, + 2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849, + 2849,2849,2849,2849,2849,1,1,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,2849,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, + 33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, + 33,33,33,33,33,33,33,33,33,33,33,33,1,1,1,1,33,33,33,33,33,33,33,33,33,33,1,1,1,1,33,33, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 129,129,129,129,1,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 1,129,129,1,129,1,1,129,1,129,129,129,129,129,129,129,129,129,129,1,129,129,129,129,1,129,1,129,1,1,1,1, + 1,1,129,1,1,1,1,129,1,129,1,129,1,129,129,129,1,129,129,1,129,1,1,129,1,129,1,129,1,129,1,129, + 1,129,129,1,129,1,1,129,129,129,129,1,129,129,129,129,129,129,129,1,129,129,129,129,1,129,129,129,129,1,129,1, + 129,129,129,129,129,129,129,129,129,129,1,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,1,1,1,1, + 1,129,129,129,1,129,129,129,129,129,1,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,129,129,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 1761,929,929,1,1,1,1,1,1,1,1,1,1,1,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1, + 929,929,929,929,929,929,929,929,929,1,1,1,1,1,1,1,769,769,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,929,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,1,1,1,1,1,1,1,1,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,1,1,1,1,1,1,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1, + 929,929,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1, + 929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,1,1,1,1,1,1,1,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,929, + 929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,1,1,1,1,1,1, + 1,929,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929, + 961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961, + 961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961, + 961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961, + 961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961, + 961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961, + 961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961, + 961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961, + 961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +}; + +KBTS_INLINE kbts_u16 kbts__GetUnicodeScriptExtension(kbts_u32 Codepoint) +{ + return (Codepoint < 1114110) ? kbts__UnicodeScriptExtension_Data[((kbts_un)kbts__UnicodeScriptExtension_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)] : 0; +} + +static kbts_u8 kbts__UnicodeMirrorCodepoint_PageIndices[8703] = { + 0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 5,6,2,2,7,8,9,2,2,2,2,2,2,2,10,11,2,2,2,12,13,14,2,15,2,2,2,2,16,2,2,2, + 17,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,18,2,19,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +}; + +static kbts_u32 kbts__UnicodeMirrorCodepoint_Data[2560] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,41,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,0,60,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,93,0,91,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,125,0,123,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,171,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3899,3898,3901,3900,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5788,5787,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8250,8249,0,0,0,0,0, + 0,0,0,0,0,8262,8261,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8318,8317,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,8334,8333,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,8715,8716,8717,8712,8713,8714,0,0,0,0,0,0,0,10741,0,0,0,0,0,0,0,0,0,11262, + 10659,10651,10656,0,10990,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8765,8764,0,0, + 0,0,0,8909,0,8780,0,0,0,0,0,0,8773,0,0,0,0,0,8787,8786,8789,8788,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,8805,8804,8807,8806,8809,8808,8811,8810,0,0,8815,8814,8817,8816,8819,8818,8821,8820,8823,8822,8825,8824,8827,8826,8829,8828,8831,8830, + 8833,8832,8835,8834,8837,8836,8839,8838,8841,8840,8843,8842,0,0,0,8848,8847,8850,8849,0,0,0,0,0,10680,0,0,0,0,0,0,0, + 0,0,8867,8866,0,0,10974,0,10980,10979,0,10981,0,0,0,0,8881,8880,8883,8882,8885,8884,8887,8886,10204,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,8906,8905,8908,8907,8771,0,0,8913,8912,0,0,0,0,8919,8918,8921,8920,8923,8922,8925,8924,8927,8926, + 8929,8928,8931,8930,8933,8932,8935,8934,8937,8936,8939,8938,8941,8940,0,0,8945,8944,8954,8955,8956,0,8957,8958,0,0,8946,8947,8948,8950,8951,0, + 0,0,0,0,0,0,0,0,8969,8968,8971,8970,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,9002,9001,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,10089,10088,10091,10090,10093,10092,10095,10094,10097,10096,10099,10098,10101,10100,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,10180,10179,10182,10181,0,10185,10184,0,10189,0,10187,0,0,0,0,0,0,0,10198,10197,0,0,0,0,0,8888,10206,10205,0, + 0,0,10211,10210,10213,10212,10215,10214,10217,10216,10219,10218,10221,10220,10223,10222,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,10628,10627,10630,10629,10632,10631,10634,10633,10636,10635,10640,10639,10638,10637,10642,10641,10644,10643,10646,10645,10648,10647,0,0,8737,0,0,0,0, + 8738,0,0,8736,10661,10660,0,0,10665,10664,10667,10666,10669,10668,10671,10670,0,0,0,0,0,0,0,0,8856,0,0,0,0,0,0,0, + 10689,10688,0,0,10693,10692,0,0,0,0,0,0,0,0,0,10704,10703,10706,10705,0,10709,10708,0,0,10713,10712,10715,10714,0,0,0,0, + 0,0,0,0,0,0,0,0,10729,10728,0,0,0,0,0,0,0,0,0,0,0,8725,0,0,10745,10744,0,0,10749,10748,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,10796,10795,10798,10797,0,0,0,0,0,10805,10804,0,0,0,0,0,0,10813,10812,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,10853,10852,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10874,10873,10876,10875,10878,10877,10880, + 10879,10882,10881,10884,10883,10886,10885,10888,10887,10890,10889,10892,10891,10894,10893,10896,10895,10898,10897,10900,10899,10902,10901,10904,10903,10906,10905,10908,10907,10910,10909,10912, + 10911,10914,10913,0,0,0,10919,10918,10921,10920,10923,10922,10925,10924,0,10928,10927,10930,10929,10932,10931,10934,10933,10936,10935,10938,10937,10940,10939,10942,10941,10944, + 10943,10946,10945,10948,10947,10950,10949,10952,10951,10954,10953,10956,10955,10958,10957,10960,10959,10962,10961,10964,10963,10966,10965,0,0,0,0,0,0,0,8870,0, + 0,0,0,8873,8872,8875,0,0,0,0,0,0,10989,10988,8740,0,0,0,0,0,0,0,0,11000,10999,11002,11001,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8735,0, + 0,0,11779,11778,11781,11780,0,0,0,11786,11785,0,11789,11788,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11805,11804,0,0, + 11809,11808,11811,11810,11813,11812,11815,11814,11817,11816,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11862,11861,11864,11863,11866,11865,11868,11867,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,12297,12296,12299,12298,12301,12300,12303,12302,12305,12304,0,0,12309,12308,12311,12310,12313,12312,12315,12314,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65114,65113,65116,65115,65118,65117,0, + 0,0,0,0,65125,65124,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,65289,65288,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65310,0,65308,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65341,0,65339,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65373,0,65371,0,65376, + 65375,0,65379,65378,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +KBTS_INLINE kbts_u32 kbts__GetUnicodeMirrorCodepoint(kbts_u32 Codepoint) +{ + return (Codepoint < 1114110) ? kbts__UnicodeMirrorCodepoint_Data[((kbts_un)kbts__UnicodeMirrorCodepoint_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)] : 0; +} + +KBTS_INLINE kbts_u32 kbts__GetDecompositionSize(kbts_u64 Decomposition) { return Decomposition & 3; } -KBTS_INLINE kbts_u32 kbts_GetDecompositionCodepoint(kbts_u64 Decomposition, kbts_un Index){ +KBTS_INLINE kbts_u32 kbts__GetDecompositionCodepoint(kbts_u64 Decomposition, kbts_un Index){ return (Decomposition >> (Index ? 23 : 2)) & 0x1FFFFF; } #define KBTS_UNICODE_DECOMPOSITION_DO_NOT_RECURSE0 (1ull << 44) #define KBTS_UNICODE_DECOMPOSITION_DO_NOT_RECURSE1 (1ull << 45) -KBTS_INLINE kbts_u32 kbts_GetMatchingBracket(kbts_u64 Decomposition) -{ - return (Decomposition >> 23) & 0x1FFFFF; -} - -KBTS_INLINE kbts_u32 kbts_GetUnicodeMatchingBracket(kbts_u32 Codepoint) -{ - kbts_u64 Decomposition = kbts_GetUnicodeDecomposition(Codepoint); return (Decomposition >> 23) & 0x1FFFFF; -} - -KBTS_INLINE kbts_u8 kbts_GetSyllabicClass(kbts_u16 SyllabicInfo) +KBTS_INLINE kbts_u8 kbts__GetSyllabicClass(kbts_u16 SyllabicInfo) { return SyllabicInfo & 0xFF; } -KBTS_INLINE kbts_u8 kbts_GetSyllabicPosition(kbts_u16 SyllabicInfo) +KBTS_INLINE kbts_u8 kbts__GetSyllabicPosition(kbts_u16 SyllabicInfo) { return SyllabicInfo >> 8; } -KBTS_INLINE kbts_s32 *kbts_GetParentInfoDeltas(kbts_u32 ParentInfo) +KBTS_INLINE kbts_s32 *kbts__GetParentInfoDeltas(kbts_u32 ParentInfo) { - return kbts_UnicodeParentDeltas + (ParentInfo & 0xFFFF); + return kbts__UnicodeParentDeltas + (ParentInfo & 0xFFFF); } -KBTS_INLINE kbts_un kbts_GetParentInfoCount(kbts_u32 ParentInfo) +KBTS_INLINE kbts_un kbts__GetParentInfoCount(kbts_u32 ParentInfo) { return ParentInfo >> 16; } +KBTS_INLINE kbts_un kbts__ScriptExtensionCount(kbts_u16 ScriptExtension) +{ + return (ScriptExtension & 0x1f); +} + +KBTS_INLINE kbts_un kbts__ScriptExtensionOffset(kbts_u16 ScriptExtension) +{ + return (ScriptExtension >> 5); +} + typedef kbts_u8 kbts_grapheme_break_class; enum kbts_grapheme_break_class_enum { /* 0 */ KBTS_GRAPHEME_BREAK_CLASS_DEFAULT, @@ -12836,56 +15214,423 @@ static kbts_u8 kbts_UseTransition[KBTS_USE_SYLLABIC_CLASS_COUNT][KBTS_USE_STATE_ /* p */ {13,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,}, }; -static const kbts_u8 kbts_CmapFormatPrecedence[14] = {1, 0, 1, 0, 2, 0, 1, 0, 3, 0, 3, 0, 4, 5}; +KBTS_EXPORT void kbts_FontCoverageTestBegin(kbts_font_coverage_test *Test, kbts_font *Font) +{ + Test->Font = Font; + Test->BaseParentCount = 0; + Test->BaseCodepoint = 0; + Test->CurrentBaseError = 0; + Test->Error = 0; +} -static int kbts_ShaperClearsMarkAdvancesInPostGposFixup(kbts_u32 Shaper) +KBTS_EXPORT void kbts_FontCoverageTestCodepoint(kbts_font_coverage_test *Test, int Codepoint) +{ + if(!Test->Error) + { + kbts_u32 UCodepoint = (kbts_u32)Codepoint; + int RecomposeBase = 0; + + if(!kbts__GetUnicodeCombiningClass(UCodepoint)) + { + Test->Error |= Test->CurrentBaseError; + Test->CurrentBaseError = 0; + Test->BaseCodepoint = UCodepoint; + + RecomposeBase = 1; + } + else + { + kbts_u16 Id = (kbts_u16)kbts_CodepointToGlyphId(Test->Font, Codepoint); + + if(!Id) + { + KBTS__FOR(ParentIndex, 0, Test->BaseParentCount) + { + kbts_glyph_parent *Parent = &Test->BaseParents[ParentIndex]; + + if(kbts__GetDecompositionCodepoint(Parent->Decomposition, 1) == UCodepoint) + { + Test->BaseCodepoint = Parent->Codepoint; + RecomposeBase = 1; + + break; + } + } + + if(!RecomposeBase) + { + Test->Error = 1; + } + } + } + + if(RecomposeBase) + { + kbts_u32 BaseCodepoint = Test->BaseCodepoint; + kbts_u16 BaseId = (kbts_u16)kbts_CodepointToGlyphId(Test->Font, (int)Test->BaseCodepoint); + kbts_un BaseParentCount = 0; + + int Done = 0; + while(!Done) + { + kbts_u32 ParentInfo = kbts__GetUnicodeParentInfo(BaseCodepoint); + kbts_s32 *ParentDeltas = kbts__GetParentInfoDeltas(ParentInfo); + + BaseParentCount = 0; + + Done = 1; + + KBTS__FOR(ParentIndex, 0, BaseParentCount) + { + kbts_glyph_parent Parent = KBTS__ZERO; + Parent.Codepoint = BaseCodepoint + (kbts_u32)ParentDeltas[ParentIndex]; + Parent.Decomposition = kbts__GetUnicodeDecomposition(Parent.Codepoint); + kbts_u16 RecompositionId = (kbts_u16)kbts_CodepointToGlyphId(Test->Font, (int)Parent.Codepoint); + + if(RecompositionId) + { + if(kbts__GetDecompositionSize(Parent.Decomposition) == 1) + { + BaseCodepoint = Parent.Codepoint; + BaseId = RecompositionId; + + Done = 0; + + break; + } + else + { + Test->BaseParents[BaseParentCount++] = Parent; + } + } + } + } + + Test->BaseCodepoint = BaseCodepoint; + Test->BaseParentCount = (kbts_u32)BaseParentCount; + + if(!BaseId) + { + Test->CurrentBaseError = 1; + } + } + } +} + +KBTS_EXPORT int kbts_FontCoverageTestEnd(kbts_font_coverage_test *Test) +{ + int Result = Test->CurrentBaseError | Test->Error; + Test->Error = Result; + return !Result; +} + +typedef struct kbts__feature_override_header +{ + struct kbts__feature_override_header *Prev; + struct kbts__feature_override_header *Next; +} kbts__feature_override_header; + +typedef struct kbts__feature_override +{ + kbts__feature_override_header Header; + + kbts_u32 Tag; + int Value; +} kbts__feature_override; + +typedef struct kbts_glyph_config +{ + kbts__feature_set EnabledFeatures; + kbts__feature_set DisabledFeatures; + + kbts_u32 ExtraOverrideCount; + + kbts_allocator_function *Allocator; + void *AllocatorData; + + kbts__feature_override_header FeatureOverrideSentinel; +} kbts_glyph_config; + +typedef struct kbts__arena_block +{ + kbts_arena_block_header Header; + void *BaseAllocation; // For freeing + + kbts_un Size; + kbts_un Used; + + // char Memory[Size]; // if Memory is NULL +} kbts__arena_block; + +typedef struct kbts__arena_lifetime +{ + kbts_arena *Arena; + kbts_arena_block_header *BlockHeader; + kbts_un Used; +} kbts__arena_lifetime; + +typedef struct kbts__glyph_list +{ + kbts_glyph *SentinelPrev; + kbts_glyph *SentinelNext; + kbts_glyph *OneBeforeFirst; + kbts_glyph *OnePastLast; +} kbts__glyph_list; + +typedef struct kbts__baked_feature +{ + kbts_u16 *Indices; + kbts_u32 Count; + kbts_u32 FeatureTag; + kbts_u32 FeatureId; + kbts_u32 SkipFlags; + kbts_u32 GlyphFilter; +} kbts__baked_feature; + +typedef struct kbts__baked_feature_stage +{ + kbts_u16 FeatureCount; + kbts_u16 FeatureIndexCount; + kbts__baked_feature *Features; // [FeatureCount] + kbts_u16 *FeatureIndices; // [FeatureIndexCount] +} kbts__baked_feature_stage; + +#define KBTS_MAX_SIMULTANEOUS_FEATURES 32 +typedef struct kbts__shape_scratchpad +{ + kbts_arena *Arena; + + kbts__feature_set LookupFeatures; + kbts__feature_set UserFeatures; + kbts__feature_set ScratchFeatures; + + kbts__glyph_list Cluster; + int RealCluster; + int ClusterAtStartOfWord; + + kbts_glyph *LookupOnePastLastGlyph; + kbts_u32 LookupOnePastLastGlyphIndex; + + kbts_u32 NextGlyphUid; + + kbts_u32 Ip; + kbts__op_kind OpKind; + kbts__feature_set *OpFeatures; + + kbts_direction RunDirection; + + kbts_u32 FeatureIndexIndex; + kbts_u32 FeatureStagesRead; + kbts_u16 BakedLookupSubtablesRead[KBTS_MAX_SIMULTANEOUS_FEATURES]; + + kbts_u32 UnregisteredFeatureCount; + kbts_feature_tag UnregisteredFeatureTags[KBTS_MAX_SIMULTANEOUS_FEATURES]; + + kbts_shape_error Error; +} kbts__shape_scratchpad; + +#define KBTS_CONTEXT_MAX_FONT_COUNT 32 + +typedef struct kbts__config_params +{ + kbts_u32 FontIndex; + kbts_script Script; + kbts_language Language; +} kbts__config_params; + +#define KBTS__INPUT_CODEPOINT_FIRST_BLOCK_MSB 6 +#define KBTS__INPUT_CODEPOINT_ONE_PAST_LAST_BLOCK_MSB 27 + +typedef struct kbts__existing_shape_config +{ + kbts_shape_config *Config; + + kbts_font *Font; + kbts_script Script; +} kbts__existing_shape_config; + +typedef kbts_u32 kbts__context_flags; +enum kbts__context_flags_enum +{ + KBTS__CONTEXT_FLAG_NONE, + + KBTS__CONTEXT_FLAG_MANUAL_SEGMENTATION = 1, + KBTS__CONTEXT_FLAG_START_OF_MANUAL_RUN = 2, + KBTS__CONTEXT_FLAG_USE_MANUAL_BREAK_INFO = 4, +}; + +typedef struct kbts__context_font +{ + kbts_font *Font; + kbts__arena_lifetime Lifetime; +} kbts__context_font; + +typedef struct kbts_shape_context +{ + kbts_arena PermanentArena; + kbts_arena FontArena; + kbts_arena ConfigArena; + kbts_arena ScratchArena; + + kbts_allocator_function *SelfAllocator; + void *SelfAllocatorData; + + kbts_shape_codepoint *LastGraphemeBreak; + kbts_u32 LastGraphemeBreakIndex; + kbts_u32 LastLineBreakIndex; + kbts_u32 BreakStartIndex; + + kbts_u32 FontCount; + kbts__context_font Fonts[KBTS_CONTEXT_MAX_FONT_COUNT]; + + kbts__config_params *ConfigTableKeys; + kbts_shape_config **ConfigTable; + + kbts__feature_override_header FeatureOverrideSentinel; + kbts__feature_override_header FreeFeatureOverrideSentinel; + + kbts_un InputCodepointCount; + int NextUserId; + kbts_shape_codepoint *InputBlocks[KBTS__INPUT_CODEPOINT_ONE_PAST_LAST_BLOCK_MSB - KBTS__INPUT_CODEPOINT_FIRST_BLOCK_MSB]; + + kbts_glyph_storage GlyphStorage; + + kbts__context_flags Flags; + kbts_direction ManualRunDirection; + kbts_script ManualRunScript; + + kbts_u32 BeginClusterIp; + kbts_u32 BeginClusterFeatureStagesRead; + kbts_glyph *TopLevelGlyph; + + kbts__feature_set *OpFeatures; + kbts__feature_set ScratchFeatures; + kbts__feature_set UserFeatures; + kbts__feature_set UserFeaturesEnabled; + + kbts_glyph_config *CurrentGlyphConfig; + int NeedNewGlyphConfig; + + kbts_direction ParagraphDirection; + kbts_language Language; + + kbts_font *RunFont; + kbts_script RunScript; + // This may be different from ParagraphDirection if ParagraphDirection == KBTS_DIRECTION_DONT_KNOW. + kbts_direction RunParagraphDirection; + kbts_direction RunDirection; + kbts_shape_codepoint_iterator RunCodepointIterator; + int DoneShapingRuns; + + kbts_u32 ExistingShapeConfigCount; + kbts__existing_shape_config ExistingShapeConfigs[32]; + + kbts_break_state BreakState; + + kbts_u32 FrameCount; + + kbts_shape_error Error; +} kbts_shape_context; + +typedef struct kbts__indic_script_properties +{ + kbts_u32 ViramaCodepoint; + kbts_u8 BlwfPostOnly; + kbts__reph_position RephPosition; + kbts__reph_encoding RephEncoding; + kbts__syllabic_position RightSideMatraPosition; + kbts__syllabic_position AboveBaseMatraPosition; + kbts__syllabic_position BelowBaseMatraPosition; +} kbts__indic_script_properties; + +typedef struct kbts_shape_config +{ + kbts_allocator_function *Allocator; + void *AllocatorData; + + kbts_font *Font; + kbts_script Script; + kbts_language Language; + kbts__langsys *Langsys[KBTS_SHAPING_TABLE_COUNT]; + kbts__op_list OpList; + + kbts__feature_set Features; + + kbts_shaper Shaper; + kbts_shaper_properties *ShaperProperties; + + kbts__indic_script_properties IndicScriptProperties; + kbts__feature *Blwf; + kbts__feature *Pref; + kbts__feature *Pstf; + kbts__feature *Locl; + kbts__feature *Rphf; + kbts__feature *Half; + kbts__feature *Vatu; + + // Indic + kbts_glyph Virama; + + kbts_glyph DottedCircle; + kbts_glyph Whitespace; + + // Thai + kbts_glyph Nikhahit; + kbts_glyph SaraAa; + + kbts__baked_feature_stage *FeatureStages; // [OpList.FeatureStageCount] +} kbts_shape_config; + +static const kbts_u8 kbts__CmapFormatPrecedence[14] = {1, 0, 1, 0, 2, 0, 1, 0, 3, 0, 3, 0, 4, 5}; + +static int kbts__ShaperClearsMarkAdvancesInPostGposFixup(kbts_u32 Shaper) { int Result = (1 << Shaper) & ((1 << KBTS_SHAPER_ARABIC) | (1 << KBTS_SHAPER_DEFAULT) | (1 << KBTS_SHAPER_HEBREW)); return Result; } -static kbts_indic_script_properties kbts_IndicScriptProperties(kbts_u32 Script) +static kbts__indic_script_properties kbts__IndicScriptProperties(kbts_u32 Script) { - kbts_indic_script_properties Result = KBTS_ZERO; + kbts__indic_script_properties Result = KBTS__ZERO; switch(Script) { case KBTS_SCRIPT_DEVANAGARI: { Result.ViramaCodepoint = 0x94D; - Result.RephPosition = KBTS_REPH_POSITION_BEFORE_POST; - Result.RightSideMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED; - Result.AboveBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED; - Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED; + Result.RephPosition = KBTS__REPH_POSITION_BEFORE_POST; + Result.RightSideMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_SUBJOINED; + Result.AboveBaseMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_SUBJOINED; + Result.BelowBaseMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_SUBJOINED; } break; case KBTS_SCRIPT_BENGALI: { Result.ViramaCodepoint = 0x9CD; - Result.RephPosition = KBTS_REPH_POSITION_AFTER_SUBJOINED; - Result.RightSideMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; - Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED; + Result.RephPosition = KBTS__REPH_POSITION_AFTER_SUBJOINED; + Result.RightSideMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_POST; + Result.BelowBaseMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_SUBJOINED; } break; case KBTS_SCRIPT_GUJARATI: { Result.ViramaCodepoint = 0xACD; - Result.RephPosition = KBTS_REPH_POSITION_BEFORE_POST; - Result.RightSideMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; - Result.AboveBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED; - Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; + Result.RephPosition = KBTS__REPH_POSITION_BEFORE_POST; + Result.RightSideMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_POST; + Result.AboveBaseMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_SUBJOINED; + Result.BelowBaseMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_POST; } break; case KBTS_SCRIPT_GURMUKHI: { Result.ViramaCodepoint = 0xA4D; - Result.RephPosition = KBTS_REPH_POSITION_BEFORE_SUBJOINED; - Result.RightSideMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; - Result.AboveBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; - Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; + Result.RephPosition = KBTS__REPH_POSITION_BEFORE_SUBJOINED; + Result.RightSideMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_POST; + Result.AboveBaseMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_POST; + Result.BelowBaseMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_POST; } break; @@ -12893,47 +15638,47 @@ static kbts_indic_script_properties kbts_IndicScriptProperties(kbts_u32 Script) { Result.ViramaCodepoint = 0xCCD; Result.BlwfPostOnly = 1; - Result.AboveBaseMatraPosition = KBTS_SYLLABIC_POSITION_BEFORE_SUBJOINED; - Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_BEFORE_SUBJOINED; + Result.AboveBaseMatraPosition = KBTS__SYLLABIC_POSITION_BEFORE_SUBJOINED; + Result.BelowBaseMatraPosition = KBTS__SYLLABIC_POSITION_BEFORE_SUBJOINED; } break; case KBTS_SCRIPT_MALAYALAM: { Result.ViramaCodepoint = 0xD4D; - Result.RephPosition = KBTS_REPH_POSITION_AFTER_MAIN; - Result.RephEncoding = KBTS_REPH_ENCODING_LOGICAL_REPHA; - Result.RightSideMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; - Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; + Result.RephPosition = KBTS__REPH_POSITION_AFTER_MAIN; + Result.RephEncoding = KBTS__REPH_ENCODING_LOGICAL_REPHA; + Result.RightSideMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_POST; + Result.BelowBaseMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_POST; } break; case KBTS_SCRIPT_ODIA: { Result.ViramaCodepoint = 0xB4D; - Result.RephPosition = KBTS_REPH_POSITION_AFTER_MAIN; - Result.RightSideMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; - Result.AboveBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_MAIN; - Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED; + Result.RephPosition = KBTS__REPH_POSITION_AFTER_MAIN; + Result.RightSideMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_POST; + Result.AboveBaseMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_MAIN; + Result.BelowBaseMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_SUBJOINED; } break; case KBTS_SCRIPT_TAMIL: { Result.ViramaCodepoint = 0xBCD; - Result.RightSideMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; - Result.AboveBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED; - Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; + Result.RightSideMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_POST; + Result.AboveBaseMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_SUBJOINED; + Result.BelowBaseMatraPosition = KBTS__SYLLABIC_POSITION_AFTER_POST; } break; case KBTS_SCRIPT_TELUGU: { Result.ViramaCodepoint = 0xC4D; - Result.RephEncoding = KBTS_REPH_ENCODING_EXPLICIT; + Result.RephEncoding = KBTS__REPH_ENCODING_EXPLICIT; Result.BlwfPostOnly = 1; - Result.AboveBaseMatraPosition = KBTS_SYLLABIC_POSITION_BEFORE_SUBJOINED; - Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_BEFORE_SUBJOINED; + Result.AboveBaseMatraPosition = KBTS__SYLLABIC_POSITION_BEFORE_SUBJOINED; + Result.BelowBaseMatraPosition = KBTS__SYLLABIC_POSITION_BEFORE_SUBJOINED; } break; } @@ -12941,45 +15686,46 @@ static kbts_indic_script_properties kbts_IndicScriptProperties(kbts_u32 Script) return Result; } -static void kbts_ByteSwapArray16Unchecked(kbts_u16 *Array, kbts_un Count) +static void kbts__ByteSwapArray16Unchecked(kbts_u16 *Array, kbts_un Count) { - KBTS_FOR(It, 0, Count) + KBTS__FOR(It, 0, Count) { - Array[It] = kbts_ByteSwap16(Array[It]); + Array[It] = kbts__ByteSwap16(Array[It]); } } -static int kbts_ByteSwapArray16(kbts_u16 *Array, kbts_un Count, char *End) +static int kbts__ByteSwapArray16(kbts_u16 *Array, kbts_un Count, char *End) { int Result = 0; if((char *)(Array + Count) <= End) { - kbts_ByteSwapArray16Unchecked(Array, Count); + kbts__ByteSwapArray16Unchecked(Array, Count); + Result = 1; + } + + return Result; +} + +static void kbts__ByteSwapArray32Unchecked(kbts_u32 *Array, kbts_un Count) +{ + KBTS__FOR(It, 0, Count) + { + Array[It] = kbts__ByteSwap32(Array[It]); + } +} + +static int kbts__ByteSwapArray32(kbts_u32 *Array, kbts_un Count, char *End) +{ + int Result = 0; + if((char *)(Array + Count) <= End) + { + kbts__ByteSwapArray32Unchecked(Array, Count); Result = 1; } return Result; } -static void kbts_ByteSwapArray32Unchecked(kbts_u32 *Array, kbts_un Count) -{ - KBTS_FOR(It, 0, Count) - { - Array[It] = kbts_ByteSwap32(Array[It]); - } -} - -static int kbts_ByteSwapArray32(kbts_u32 *Array, kbts_un Count, char *End) -{ - int Result = 0; - if((char *)(Array + Count) <= End) - { - kbts_ByteSwapArray32Unchecked(Array, Count); - Result = 1; - } - return Result; -} - -static kbts_u64 kbts_ContainsFeature(kbts_feature_set *Set, kbts_feature_id Id) +static kbts_u64 kbts__ContainsFeature(kbts__feature_set *Set, kbts__feature_id Id) { kbts_un WordIndex = Id / 64; kbts_un BitIndex = Id % 64; @@ -12988,7 +15734,7 @@ static kbts_u64 kbts_ContainsFeature(kbts_feature_set *Set, kbts_feature_id Id) return Result; } -static void kbts_AddFeature(kbts_feature_set *Set, kbts_feature_id Id) +static void kbts__AddFeature(kbts__feature_set *Set, kbts__feature_id Id) { kbts_un WordIndex = Id / 64; kbts_un BitIndex = Id % 64; @@ -12996,202 +15742,123 @@ static void kbts_AddFeature(kbts_feature_set *Set, kbts_feature_id Id) Set->Flags[WordIndex] |= 1ull << BitIndex; } -static kbts_feature_override kbts_FeatureOverrideBase(kbts_feature_id Id, kbts_feature_tag Tag, int Alternate, kbts_u32 Value) -{ - kbts_feature_override Result = KBTS_ZERO; - Result.Id = Id; - Result.Tag = Tag; - - if(Alternate) - { - Result.EnabledOrAlternatePlusOne = Value + 1; - } - else - { - Result.EnabledOrAlternatePlusOne = Value; - } - - return Result; -} -KBTS_EXPORT kbts_feature_override kbts_FeatureOverrideFromTag(kbts_feature_tag Tag, int Alternate, kbts_u32 Value) -{ - kbts_feature_override Result = kbts_FeatureOverrideBase(kbts_FeatureTagToId(Tag), Tag, Alternate, Value); - return Result; -} -KBTS_EXPORT kbts_feature_override kbts_FeatureOverride(kbts_feature_id Id, int Alternate, kbts_u32 Value) -{ - kbts_feature_override Result = kbts_FeatureOverrideBase(Id, 0, Alternate, Value); - return Result; -} - -KBTS_EXPORT kbts_glyph_config kbts_GlyphConfig(kbts_feature_override *FeatureOverrides, kbts_u32 FeatureOverrideCount) -{ - kbts_glyph_config Result = KBTS_ZERO; - Result.FeatureOverrides = FeatureOverrides; - Result.FeatureOverrideCount = FeatureOverrideCount; - - KBTS_FOR(FeatureOverrideIndex, 0, FeatureOverrideCount) - { - kbts_feature_override *Override = &FeatureOverrides[FeatureOverrideIndex]; - if(Override->EnabledOrAlternatePlusOne) - { - kbts_AddFeature(&Result.EnabledFeatures, FeatureOverrides[FeatureOverrideIndex].Id); - } - else - { - kbts_AddFeature(&Result.DisabledFeatures, FeatureOverrides[FeatureOverrideIndex].Id); - } - } - - return Result; -} - -KBTS_EXPORT kbts_glyph_config kbts_EmptyGlyphConfig(kbts_feature_override *FeatureOverrides, kbts_u32 FeatureOverrideCapacity) -{ - kbts_glyph_config Result = KBTS_ZERO; - Result.FeatureOverrides = FeatureOverrides; - Result.FeatureOverrideCapacity = FeatureOverrideCapacity; - return Result; -} - -static int kbts_GlyphConfigOverrideFeatureBase(kbts_glyph_config *Config, kbts_feature_id Id, kbts_feature_tag Tag, int Alternate, kbts_u32 Value) -{ - kbts_feature_set *Set = &Config->EnabledFeatures; - if(!Value) - { - Set = &Config->DisabledFeatures; - } - kbts_AddFeature(Set, Id); - - if(!Id || Alternate) - { - if(Config->FeatureOverrideCount < Config->FeatureOverrideCapacity) - { - kbts_feature_override Override = kbts_FeatureOverrideFromTag(Tag, Alternate, Value); - Config->FeatureOverrides[Config->FeatureOverrideCount++] = Override; - } - Config->RequiredFeatureOverrideCapacity += 1; - } - - int Result = Config->RequiredFeatureOverrideCapacity <= Config->FeatureOverrideCapacity; - return Result; -} -KBTS_EXPORT int kbts_GlyphConfigOverrideFeature(kbts_glyph_config *Config, kbts_feature_id Id, int Alternate, kbts_u32 Value) -{ - int Result = kbts_GlyphConfigOverrideFeatureBase(Config, Id, 0, Alternate, Value); - return Result; -} -KBTS_EXPORT int kbts_GlyphConfigOverrideFeatureFromTag(kbts_glyph_config *Config, kbts_feature_tag Tag, int Alternate, kbts_u32 Value) -{ - int Result = kbts_GlyphConfigOverrideFeatureBase(Config, kbts_FeatureTagToId(Tag), Tag, Alternate, Value); - return Result; -} - // // TTF struct definitions. // enum { - KBTS_GLYPH_CLASS_BASE = 1, - KBTS_GLYPH_CLASS_LIGATURE = 2, - KBTS_GLYPH_CLASS_MARK = 3, - KBTS_GLYPH_CLASS_COMPONENT = 4, + KBTS__GLYPH_CLASS_BASE = 1, + KBTS__GLYPH_CLASS_LIGATURE = 2, + KBTS__GLYPH_CLASS_MARK = 3, + KBTS__GLYPH_CLASS_COMPONENT = 4, }; enum { - KBTS_LOOKUP_FLAG_RIGHT_TO_LEFT = 1 << 0, - KBTS_LOOKUP_FLAG_IGNORE_BASE_GLYPHS = 1 << 1, - KBTS_LOOKUP_FLAG_IGNORE_LIGATURES = 1 << 2, - KBTS_LOOKUP_FLAG_IGNORE_MARKS = 1 << 3, - KBTS_LOOKUP_FLAG_USE_MARK_FILTERING_SET = 1 << 4, + KBTS__LOOKUP_FLAG_RIGHT_TO_LEFT = 1 << 0, + KBTS__LOOKUP_FLAG_IGNORE_BASE_GLYPHS = 1 << 1, + KBTS__LOOKUP_FLAG_IGNORE_LIGATURES = 1 << 2, + KBTS__LOOKUP_FLAG_IGNORE_MARKS = 1 << 3, + KBTS__LOOKUP_FLAG_USE_MARK_FILTERING_SET = 1 << 4, - KBTS_LOOKUP_FLAG_MARK_ATTACHMENT_CLASS_FILTER = 0xFF00, + KBTS__LOOKUP_FLAG_MARK_ATTACHMENT_CLASS_FILTER = 0xFF00, }; enum { - KBTS_VALUE_FORMAT_X_PLACEMENT = 1 << 0, - KBTS_VALUE_FORMAT_Y_PLACEMENT = 1 << 1, - KBTS_VALUE_FORMAT_X_ADVANCE = 1 << 2, - KBTS_VALUE_FORMAT_Y_ADVANCE = 1 << 3, - KBTS_VALUE_FORMAT_X_PLACEMENT_DEVICE = 1 << 4, - KBTS_VALUE_FORMAT_Y_PLACEMENT_DEVICE = 1 << 5, - KBTS_VALUE_FORMAT_X_ADVANCE_DEVICE = 1 << 6, - KBTS_VALUE_FORMAT_Y_ADVANCE_DEVICE = 1 << 7, + KBTS__OS2_WIDTH_ULTRA_CONDENSED = 1, + KBTS__OS2_WIDTH_EXTRA_CONDENSED = 2, + KBTS__OS2_WIDTH_CONDENSED = 3, + KBTS__OS2_WIDTH_SEMI_CONDENSED = 4, + KBTS__OS2_WIDTH_MEDIUM = 5, + KBTS__OS2_WIDTH_SEMI_EXPANDED = 6, + KBTS__OS2_WIDTH_EXPANDED = 7, + KBTS__OS2_WIDTH_EXTRA_EXPANDED = 8, + KBTS__OS2_WIDTH_ULTRA_EXPANDED = 9, }; enum { - KBTS_DELTA_FORMAT_2_BIT = 1, - KBTS_DELTA_FORMAT_4_BIT = 2, - KBTS_DELTA_FORMAT_8_BIT = 3, - KBTS_DELTA_FORMAT_VARIATION_INDEX = 0x8000, + KBTS__VALUE_FORMAT_X_PLACEMENT = 1 << 0, + KBTS__VALUE_FORMAT_Y_PLACEMENT = 1 << 1, + KBTS__VALUE_FORMAT_X_ADVANCE = 1 << 2, + KBTS__VALUE_FORMAT_Y_ADVANCE = 1 << 3, + KBTS__VALUE_FORMAT_X_PLACEMENT_DEVICE = 1 << 4, + KBTS__VALUE_FORMAT_Y_PLACEMENT_DEVICE = 1 << 5, + KBTS__VALUE_FORMAT_X_ADVANCE_DEVICE = 1 << 6, + KBTS__VALUE_FORMAT_Y_ADVANCE_DEVICE = 1 << 7, +}; + +enum +{ + KBTS__OS2_SELECTION_FLAG_NONE, + + KBTS__OS2_SELECTION_FLAG_ITALIC = (1 << 0), + KBTS__OS2_SELECTION_FLAG_UNDERSCORE = (1 << 1), + KBTS__OS2_SELECTION_FLAG_NEGATIVE = (1 << 2), + KBTS__OS2_SELECTION_FLAG_OUTLINED = (1 << 3), + KBTS__OS2_SELECTION_FLAG_STRIKEOUT = (1 << 4), + KBTS__OS2_SELECTION_FLAG_BOLD = (1 << 5), + KBTS__OS2_SELECTION_FLAG_REGULAR = (1 << 6), + KBTS__OS2_SELECTION_FLAG_USE_TYPO_METRICS = (1 << 7), + KBTS__OS2_SELECTION_FLAG_WWS = (1 << 8), + KBTS__OS2_SELECTION_FLAG_OBLIQUE = (1 << 9), }; # pragma pack(push, 1) -typedef struct kbts_glyph_header -{ - kbts_s16 ContourCount; - kbts_s16 MinX; - kbts_s16 MinY; - kbts_s16 MaxX; - kbts_s16 MaxY; -} kbts_glyph_header; - -typedef struct kbts_script_record +typedef struct kbts__script_record { kbts_u32 Tag; kbts_u16 Offset; -} kbts_script_record; +} kbts__script_record; -typedef struct kbts_script_list +typedef struct kbts__script_list { kbts_u16 Count; - // kbts_script_record Records[Count]; -} kbts_script_list; + // kbts__script_record Records[Count]; +} kbts__script_list; -typedef struct kbts_ot_script +typedef struct kbts__ot_script { kbts_u16 DefaultLangsysOffset; kbts_u16 Count; - // kbts_langsys_record Records[Count]; -} kbts_ot_script; + // kbts__langsys_record Records[Count]; +} kbts__ot_script; -typedef struct kbts_langsys_record +typedef struct kbts__langsys_record { kbts_u32 Tag; kbts_u16 Offset; -} kbts_langsys_record; +} kbts__langsys_record; -typedef struct kbts_langsys +typedef struct kbts__langsys { kbts_u16 LookupOrderOffset; // reserved kbts_u16 RequiredFeatureIndex; kbts_u16 FeatureIndexCount; // kbts_u16 FeatureIndices[FeatureIndexCount]; -} kbts_langsys; +} kbts__langsys; -typedef struct kbts_feature_list +typedef struct kbts__feature_list { kbts_u16 Count; - // kbts_feature_record Records[Count]; -} kbts_feature_list; + // kbts__feature_record Records[Count]; +} kbts__feature_list; -typedef struct kbts_feature_record +typedef struct kbts__feature_record { kbts_u32 Tag; kbts_u16 Offset; -} kbts_feature_record; +} kbts__feature_record; -typedef struct kbts_feature +typedef struct kbts__feature { kbts_u16 FeatureParamsOffset; kbts_u16 LookupIndexCount; // kbts_u16 LookupIndices[LookupIndexCount]; -} kbts_feature; +} kbts__feature; typedef struct kbts_lookup_list { @@ -13201,7 +15868,7 @@ typedef struct kbts_lookup_list // Lookups are used both in GSUB and GPOS. // Type means either GSUB Lookup Type, or GPOS Lookup Type, depending on the table we are parsing. -typedef struct kbts_lookup +typedef struct kbts__lookup { kbts_u16 Type; kbts_u16 Flag; @@ -13209,122 +15876,122 @@ typedef struct kbts_lookup // kbts_u16 SubtableOffsets[SubtableCount]; // If USE_MARK_FILTERING_SET: // kbts_u16 MarkFilteringSet; -} kbts_lookup; +} kbts__lookup; -typedef struct kbts_coverage +typedef struct kbts__coverage { kbts_u16 Format; kbts_u16 Count; // If Format == 1: // kbts_u16 GlyphArray[Count]; // If Format == 2: - // kbts_range_record Ranges[Count]; -} kbts_coverage; + // kbts__range_record Ranges[Count]; +} kbts__coverage; -typedef struct kbts_range_record +typedef struct kbts__range_record { kbts_u16 StartGlyphId; kbts_u16 EndGlyphId; kbts_u16 StartCoverageIndex; -} kbts_range_record; +} kbts__range_record; -typedef struct kbts_class_definition_1 +typedef struct kbts__class_definition_1 { kbts_u16 Format; kbts_u16 StartGlyphId; kbts_u16 GlyphCount; // kbts_u16 ClassValues[GlyphCount]; -} kbts_class_definition_1; +} kbts__class_definition_1; -typedef struct kbts_class_definition_2 +typedef struct kbts__class_definition_2 { kbts_u16 Format; kbts_u16 Count; - // kbts_class_range_record Ranges[Count]; -} kbts_class_definition_2; + // kbts__class_range_record Ranges[Count]; +} kbts__class_definition_2; -typedef struct kbts_class_range_record +typedef struct kbts__class_range_record { kbts_u16 StartGlyphId; kbts_u16 EndGlyphId; kbts_u16 Class; -} kbts_class_range_record; +} kbts__class_range_record; -typedef struct kbts_sequence_lookup_record +typedef struct kbts__sequence_lookup_record { kbts_u16 SequenceIndex; kbts_u16 LookupListIndex; -} kbts_sequence_lookup_record; +} kbts__sequence_lookup_record; -typedef struct kbts_sequence_rule +typedef struct kbts__sequence_rule { kbts_u16 GlyphCount; kbts_u16 SequenceLookupCount; // kbts_u16 InputSequence[GlyphCount - 1]; - // kbts_sequence_lookup_record SequenceLookupRecords[SequenceLookupCount]; -} kbts_sequence_rule; + // kbts__sequence_lookup_record SequenceLookupRecords[SequenceLookupCount]; +} kbts__sequence_rule; -typedef struct kbts_sequence_rule_set +typedef struct kbts__sequence_rule_set { kbts_u16 Count; // kbts_u16 Offsets[Count]; -} kbts_sequence_rule_set; +} kbts__sequence_rule_set; -typedef struct kbts_sequence_context_1 +typedef struct kbts__sequence_context_1 { kbts_u16 Format; kbts_u16 CoverageOffset; kbts_u16 SeqRuleSetCount; // kbts_u16 SeqRuleSetOffsets[]; -} kbts_sequence_context_1; +} kbts__sequence_context_1; -typedef struct kbts_sequence_context_2 +typedef struct kbts__sequence_context_2 { kbts_u16 Format; kbts_u16 CoverageOffset; kbts_u16 ClassDefOffset; kbts_u16 ClassSequenceRuleSetCount; // kbts_u16 ClassSequenceRuleSetOffsets[ClassSequenceRuleSetCount]; May be NULL! -} kbts_sequence_context_2; +} kbts__sequence_context_2; -typedef struct kbts_class_sequence_rule_set +typedef struct kbts__class_sequence_rule_set { kbts_u16 Count; // kbts_u16 ClassSequenceRuleOffsets[Count]; -} kbts_class_sequence_rule_set; +} kbts__class_sequence_rule_set; -typedef struct kbts_class_sequence_rule +typedef struct kbts__class_sequence_rule { kbts_u16 GlyphCount; kbts_u16 SequenceLookupCount; // kbts_u16 InputSequence[GlyphCount-1]; - // kbts_sequence_lookup_record SequenceLookupRecords[SequenceLookupCount]; -} kbts_class_sequence_rule; + // kbts__sequence_lookup_record SequenceLookupRecords[SequenceLookupCount]; +} kbts__class_sequence_rule; -typedef struct kbts_sequence_context_3 +typedef struct kbts__sequence_context_3 { kbts_u16 Format; kbts_u16 GlyphCount; kbts_u16 SequenceLookupCount; // kbts_u16 CoverageOffsets[GlyphCount]; - // kbts_sequence_lookup_record SequenceLookupRecords[SequenceLookupCount]; -} kbts_sequence_context_3; + // kbts__sequence_lookup_record SequenceLookupRecords[SequenceLookupCount]; +} kbts__sequence_context_3; -typedef struct kbts_chained_sequence_context_1 +typedef struct kbts__chained_sequence_context_1 { kbts_u16 Format; kbts_u16 CoverageOffset; kbts_u16 ChainedSequenceRuleSetCount; // kbts_u16 ChainedSequenceRuleSetOffsets[ChainedSequenceRuleSetCount]; -} kbts_chained_sequence_context_1; +} kbts__chained_sequence_context_1; -typedef struct kbts_chained_sequence_rule_set +typedef struct kbts__chained_sequence_rule_set { kbts_u16 Count; // kbts_u16 Offsets[Count]; -} kbts_chained_sequence_rule_set; +} kbts__chained_sequence_rule_set; -typedef struct kbts_chained_sequence_rule +typedef struct kbts__chained_sequence_rule { kbts_u16 BacktrackGlyphCount; // kbts_u16 BacktrackSequence[BacktrackCount]; @@ -13333,10 +16000,10 @@ typedef struct kbts_chained_sequence_rule // kbts_u16 LookaheadGlyphCount; // kbts_u16 LookaheadSequence[LookaheadGlyphCount]; // kbts_u16 SequenceLookupCount; - // kbts_sequence_lookup_record SequenceLookupRecords[SequenceLookupCount]; -} kbts_chained_sequence_rule; + // kbts__sequence_lookup_record SequenceLookupRecords[SequenceLookupCount]; +} kbts__chained_sequence_rule; -typedef struct kbts_chained_sequence_context_2 +typedef struct kbts__chained_sequence_context_2 { kbts_u16 Format; kbts_u16 CoverageOffset; @@ -13345,9 +16012,9 @@ typedef struct kbts_chained_sequence_context_2 kbts_u16 LookaheadClassDefOffset; kbts_u16 ChainedClassSequenceRuleSetCount; // kbts_u16 ChainedClassSequenceRuleSetOffsets[ChainedClassSequenceRuleSetCount]; -} kbts_chained_sequence_context_2; +} kbts__chained_sequence_context_2; -typedef struct kbts_chained_sequence_context_3 +typedef struct kbts__chained_sequence_context_3 { kbts_u16 Format; kbts_u16 BacktrackGlyphCount; @@ -13357,10 +16024,10 @@ typedef struct kbts_chained_sequence_context_3 // kbts_u16 LookaheadGlyphCount; // kbts_u16 LookaheadCoverageOffsets[LookaheadGlyphCount]; // kbts_u16 SequenceLookupCount; - // kbts_sequence_lookup_record SequenceLookupRecords[SequenceLookupCount]; -} kbts_chained_sequence_context_3; + // kbts__sequence_lookup_record SequenceLookupRecords[SequenceLookupCount]; +} kbts__chained_sequence_context_3; -typedef struct kbts_device +typedef struct kbts__device { union { @@ -13378,81 +16045,95 @@ typedef struct kbts_device } U; kbts_u16 DeltaFormat; // kbts_u16 DeltaValue[]; -} kbts_device; +} kbts__device; -typedef struct kbts_feature_variations +typedef struct kbts__feature_variations { kbts_u16 Major; kbts_u16 Minor; kbts_u32 RecordCount; - // kbts_feature_variation_record Records[RecordCount]; -} kbts_feature_variations; + // kbts__feature_variation_record Records[RecordCount]; +} kbts__feature_variations; -typedef struct kbts_feature_variation_record +typedef struct kbts__feature_variation_record { kbts_u32 ConditionSetOffset; kbts_u32 FeatureTableSubstitutionOffset; -} kbts_feature_variation_record; +} kbts__feature_variation_record; -typedef struct kbts_condition_set +typedef struct kbts__condition_set { kbts_u16 Count; // kbts_u32 Offsets[Count]; -} kbts_condition_set; +} kbts__condition_set; -typedef struct kbts_condition_1 +typedef struct kbts__condition_1 { kbts_u16 Format; kbts_u16 AxisIndex; kbts_u16 FilterRangeMinValue; kbts_u16 FilterRangeMaxValue; -} kbts_condition_1; +} kbts__condition_1; -typedef struct kbts_feature_table_substitution +typedef struct kbts__feature_table_substitution { kbts_u16 Major; kbts_u16 Minor; kbts_u16 Count; - // kbts_feature_table_substitution_record Records[Count]; -} kbts_feature_table_substitution; + // kbts__feature_table_substitution_record Records[Count]; +} kbts__feature_table_substitution; -typedef struct kbts_feature_table_substitution_record +typedef struct kbts__feature_table_substitution_record { kbts_u16 FeatureIndex; kbts_u32 AlternateFeatureOffset; -} kbts_feature_table_substitution_record; +} kbts__feature_table_substitution_record; -typedef struct kbts_table_directory +typedef struct kbts__ttc_header +{ + kbts_u32 Magic; // ttcf + kbts_u16 Major; + kbts_u16 Minor; + kbts_u32 FontCount; + // kbts_u32 TableDirectoryOffsets[FontCount]; + + // If Major == 2: + // kbts_u32 DsigTag; + // kbts_u32 DsigLength; + // kbts_u32 DsigOffset; +} kbts__ttc_header; + +typedef struct kbts__table_directory { kbts_u32 Version; kbts_u16 TableCount; kbts_u16 SearchRange; kbts_u16 EntrySelector; kbts_u16 RangeShift; - // kbts_table_record Records[TableCount]; -} kbts_table_directory; + // kbts__table_record Records[TableCount]; +} kbts__table_directory; -typedef struct kbts_table_record +typedef struct kbts__table_record { kbts_u32 Tag; kbts_u32 Checksum; kbts_u32 Offset; kbts_u32 Length; -} kbts_table_record; +} kbts__table_record; -typedef struct kbts_cmap +typedef struct kbts__cmap { kbts_u16 Version; kbts_u16 TableCount; - // kbts_encoding_record Records[TableCount]; -} kbts_cmap; + // kbts__encoding_record Records[TableCount]; +} kbts__cmap; -typedef struct kbts_encoding_record +typedef struct kbts__encoding_record { kbts_u16 PlatformId; kbts_u16 EncodingId; kbts_u32 SubtableOffset; -} kbts_encoding_record; +} kbts__encoding_record; /* Precedence rules for cmap tables: - Tables are mutually exclusive, except for format 14 which completes the others. @@ -13464,33 +16145,33 @@ typedef struct kbts_encoding_record - There can be Unicode and Windows tables with the same formats. In that case, we prefer the Windows tables. */ -typedef struct kbts_cmap_0 +typedef struct kbts__cmap_0 { kbts_u16 Format; kbts_u16 Length; kbts_u16 Language; kbts_u8 GlyphIdArray[256]; -} kbts_cmap_0; +} kbts__cmap_0; -typedef struct kbts_cmap_2 +typedef struct kbts__cmap_2 { kbts_u16 Format; kbts_u16 Length; kbts_u16 Language; kbts_u16 SubHeaderKeys[256]; - // kbts_sub_header SubHeaders[]; + // kbts__sub_header SubHeaders[]; // kbts_u16 GlyphIdArray[]; -} kbts_cmap_2; +} kbts__cmap_2; -typedef struct kbts_sub_header +typedef struct kbts__sub_header { kbts_u16 FirstCode; kbts_u16 EntryCount; kbts_s16 IdDelta; kbts_u16 IdRangeOffset; -} kbts_sub_header; +} kbts__sub_header; -typedef struct kbts_cmap_4 +typedef struct kbts__cmap_4 { kbts_u16 Format; kbts_u16 Length; @@ -13505,9 +16186,9 @@ typedef struct kbts_cmap_4 // kbts_s16 IdDelta[SegmentCount]; // kbts_u16 IdRangeOffsets[SegmentCount]; // kbts_u16 GlyphIdArray[]; -} kbts_cmap_4; +} kbts__cmap_4; -typedef struct kbts_cmap_6 +typedef struct kbts__cmap_6 { kbts_u16 Format; kbts_u16 Length; @@ -13515,65 +16196,65 @@ typedef struct kbts_cmap_6 kbts_u16 FirstCode; kbts_u16 EntryCount; // kbts_u16 GlyphIdArray[EntryCount]; -} kbts_cmap_6; +} kbts__cmap_6; -typedef struct kbts_cmap_12_13 +typedef struct kbts__cmap_12_13 { kbts_u16 Format; kbts_u16 Reserved; kbts_u32 Length; kbts_u32 Language; kbts_u32 GroupCount; - // kbts_sequential_map_group Groups[GroupCount]; -} kbts_cmap_12_13; + // kbts__sequential_map_group Groups[GroupCount]; +} kbts__cmap_12_13; -typedef struct kbts_sequential_map_group +typedef struct kbts__sequential_map_group { kbts_u32 StartCharacterCode; kbts_u32 EndCharacterCode; kbts_u32 StartGlyphId; -} kbts_sequential_map_group; +} kbts__sequential_map_group; -typedef struct kbts_cmap_14 +typedef struct kbts__cmap_14 { kbts_u16 Format; kbts_u32 Length; kbts_u32 SelectorCount; - // kbts_variation_selector Selectors[SelectorCount]; -} kbts_cmap_14; + // kbts__variation_selector Selectors[SelectorCount]; +} kbts__cmap_14; -typedef struct kbts_variation_selector +typedef struct kbts__variation_selector { kbts_u8 Selector[3]; kbts_u32 DefaultUvsOffset; kbts_u32 NonDefaultUvsOffset; -} kbts_variation_selector; +} kbts__variation_selector; -typedef struct kbts_default_uvs +typedef struct kbts__default_uvs { kbts_u32 RangeCount; - // kbts_unicode_range Ranges[RangeCount]; -} kbts_default_uvs; + // kbts__unicode_range Ranges[RangeCount]; +} kbts__default_uvs; -typedef struct kbts_unicode_range +typedef struct kbts__unicode_range { kbts_u8 Start[3]; kbts_u8 Count; -} kbts_unicode_range; +} kbts__unicode_range; -typedef struct kbts_non_default_uvs +typedef struct kbts__non_default_uvs { kbts_u32 MappingCount; - // kbts_uvs_mapping Mappings[MappingCount]; -} kbts_non_default_uvs; + // kbts__uvs_mapping Mappings[MappingCount]; +} kbts__non_default_uvs; -typedef struct kbts_uvs_mapping +typedef struct kbts__uvs_mapping { kbts_u8 UnicodeValue[3]; kbts_u16 GlyphId; -} kbts_uvs_mapping; +} kbts__uvs_mapping; -typedef struct kbts_gsub_gpos +typedef struct kbts__gsub_gpos { kbts_u16 Major; kbts_u16 Minor; @@ -13581,9 +16262,9 @@ typedef struct kbts_gsub_gpos kbts_u16 FeatureListOffset; kbts_u16 LookupListOffset; kbts_u32 FeatureVariationsOffset; // Only present in v1.1 -} kbts_gsub_gpos; +} kbts__gsub_gpos; -typedef struct kbts_single_substitution +typedef struct kbts__single_substitution { kbts_u16 Format; kbts_u16 CoverageOffset; @@ -13594,65 +16275,65 @@ typedef struct kbts_single_substitution } DeltaOrCount; // If Format == 2: // kbts_u16 SubstituteGlyphIds[GlyphCount]; -} kbts_single_substitution; +} kbts__single_substitution; -typedef struct kbts_multiple_substitution +typedef struct kbts__multiple_substitution { kbts_u16 Format; kbts_u16 CoverageOffset; kbts_u16 SequenceCount; // kbts_u16 SequenceOffsets[SequenceCount]; -} kbts_multiple_substitution; +} kbts__multiple_substitution; -typedef struct kbts_sequence +typedef struct kbts__sequence { kbts_u16 GlyphCount; // kbts_u16 SubstituteGlyphIds[GlyphCount]; -} kbts_sequence; +} kbts__sequence; -typedef struct kbts_alternate_substitution +typedef struct kbts__alternate_substitution { kbts_u16 Format; kbts_u16 CoverageOffset; kbts_u16 AlternateSetCount; // kbts_u16 AlternateSetOffsets[AlternateSetCount]; -} kbts_alternate_substitution; +} kbts__alternate_substitution; -typedef struct kbts_alternate_set +typedef struct kbts__alternate_set { kbts_u16 GlyphCount; // kbts_u16 AlternateGlyphIds[GlyphCount]; -} kbts_alternate_set; +} kbts__alternate_set; -typedef struct kbts_ligature_substitution +typedef struct kbts__ligature_substitution { kbts_u16 Format; kbts_u16 CoverageOffset; kbts_u16 LigatureSetCount; // kbts_u16 LigatureSetOffsets[LigatureSetCount]; -} kbts_ligature_substitution; +} kbts__ligature_substitution; -typedef struct kbts_ligature_set +typedef struct kbts__ligature_set { kbts_u16 Count; // kbts_u16 Offsets[Count]; -} kbts_ligature_set; +} kbts__ligature_set; -typedef struct kbts_ligature +typedef struct kbts__ligature { kbts_u16 Glyph; kbts_u16 ComponentCount; // kbts_u16 ComponentGlyphIds[ComponentCount - 1]; -} kbts_ligature; +} kbts__ligature; -typedef struct kbts_extension +typedef struct kbts__extension { kbts_u16 Format; kbts_u16 LookupType; kbts_u32 Offset; -} kbts_extension; +} kbts__extension; -typedef struct kbts_reverse_chain_substitution +typedef struct kbts__reverse_chain_substitution { kbts_u16 Format; kbts_u16 CoverageOffset; @@ -13662,16 +16343,16 @@ typedef struct kbts_reverse_chain_substitution // kbts_u16 LookaheadCoverageOffsets[LookaheadGlyphCount]; // kbts_u16 GlyphCount; // kbts_u16 SubstituteGlyphIds[GlyphCount]; -} kbts_reverse_chain_substitution; +} kbts__reverse_chain_substitution; -typedef struct kbts_mark_glyph_sets +typedef struct kbts__mark_glyph_sets { kbts_u16 Format; kbts_u16 MarkGlyphSetCount; // kbts_u32 CoverageOffsets[MarkGlyphSetCount]; -} kbts_mark_glyph_sets; +} kbts__mark_glyph_sets; -typedef struct kbts_gdef +typedef struct kbts__gdef { kbts_u16 Major; kbts_u16 Minor; @@ -13681,9 +16362,9 @@ typedef struct kbts_gdef kbts_u16 MarkAttachmentClassDefinitionOffset; // May be 0 kbts_u16 MarkGlyphSetsDefinitionOffset; // v1.2 and up; may be 0 kbts_u32 ItemVariationStoreOffset; // v1.3 and up; may be 0 -} kbts_gdef; +} kbts__gdef; -typedef struct kbts_anchor +typedef struct kbts__anchor { kbts_u16 Format; kbts_s16 X; @@ -13694,51 +16375,51 @@ typedef struct kbts_anchor kbts_u16 XDeviceOffset; // If Format == 3 } U; kbts_u16 YDeviceOffset; // If Format == 3 -} kbts_anchor; +} kbts__anchor; -typedef struct kbts_mark_record +typedef struct kbts__mark_record { kbts_u16 Class; kbts_u16 AnchorOffset; -} kbts_mark_record; +} kbts__mark_record; -typedef struct kbts_mark_array +typedef struct kbts__mark_array { kbts_u16 Count; - // kbts_mark_record Records[Count]; -} kbts_mark_array; + // kbts__mark_record Records[Count]; +} kbts__mark_array; -typedef struct kbts_single_adjustment_1 +typedef struct kbts__single_adjustment_1 { kbts_u16 Format; kbts_u16 CoverageOffset; kbts_u16 ValueFormat; // ValueRecord; -} kbts_single_adjustment_1; +} kbts__single_adjustment_1; -typedef struct kbts_single_adjustment_2 +typedef struct kbts__single_adjustment_2 { kbts_u16 Format; kbts_u16 CoverageOffset; kbts_u16 ValueFormat; kbts_u16 RecordCount; // ValueRecord Records[RecordCount]; -} kbts_single_adjustment_2; +} kbts__single_adjustment_2; -typedef struct kbts_pair_value_record +typedef struct kbts__pair_value_record { kbts_u16 SecondGlyph; // ValueRecord Record1; // ValueRecord Record2; -} kbts_pair_value_record; +} kbts__pair_value_record; -typedef struct kbts_pair_set +typedef struct kbts__pair_set { kbts_u16 Count; - // kbts_pair_value_record PairValueRecords[Count]; -} kbts_pair_set; + // kbts__pair_value_record PairValueRecords[Count]; +} kbts__pair_set; -typedef struct kbts_pair_adjustment_1 +typedef struct kbts__pair_adjustment_1 { kbts_u16 Format; kbts_u16 CoverageOffset; @@ -13746,9 +16427,9 @@ typedef struct kbts_pair_adjustment_1 kbts_u16 ValueFormat2; // May be 0 kbts_u16 SetCount; // kbts_u16 SetOffsets[PairSetCount]; -} kbts_pair_adjustment_1; +} kbts__pair_adjustment_1; -typedef struct kbts_pair_adjustment_2 +typedef struct kbts__pair_adjustment_2 { kbts_u16 Format; kbts_u16 CoverageOffset; @@ -13759,29 +16440,29 @@ typedef struct kbts_pair_adjustment_2 kbts_u16 Class1Count; kbts_u16 Class2Count; // ValueRecord ValueRecords[Class1Count][Class2Count][2]; -} kbts_pair_adjustment_2; +} kbts__pair_adjustment_2; -typedef struct kbts_entry_exit +typedef struct kbts__entry_exit { kbts_u16 EntryAnchorOffset; kbts_u16 ExitAnchorOffset; -} kbts_entry_exit; +} kbts__entry_exit; -typedef struct kbts_cursive_attachment +typedef struct kbts__cursive_attachment { kbts_u16 Format; kbts_u16 CoverageOffset; kbts_u16 EntryExitCount; - // kbts_entry_exit Records[EntryExitCount]; -} kbts_cursive_attachment; + // kbts__entry_exit Records[EntryExitCount]; +} kbts__cursive_attachment; -typedef struct kbts_base_array +typedef struct kbts__base_array { kbts_u16 BaseCount; // kbts_u16 BaseAnchorOffsets[BaseCount][MarkClassCount]; // May be NULL -} kbts_base_array; +} kbts__base_array; -typedef struct kbts_mark_to_base_attachment +typedef struct kbts__mark_to_base_attachment { kbts_u16 Format; kbts_u16 MarkCoverageOffset; @@ -13789,21 +16470,21 @@ typedef struct kbts_mark_to_base_attachment kbts_u16 MarkClassCount; kbts_u16 MarkArrayOffset; kbts_u16 BaseArrayOffset; -} kbts_mark_to_base_attachment; +} kbts__mark_to_base_attachment; -typedef struct kbts_ligature_attach +typedef struct kbts__ligature_attach { kbts_u16 Count; // kbts_u16 LigatureAnchorOffsets[Count][MarkClassCount]; // May be NULL -} kbts_ligature_attach; +} kbts__ligature_attach; -typedef struct kbts_ligature_array +typedef struct kbts__ligature_array { kbts_u16 Count; // kbts_u16 LigatureAttachOffsets[Count]; -} kbts_ligature_array; +} kbts__ligature_array; -typedef struct kbts_mark_to_ligature_attachment +typedef struct kbts__mark_to_ligature_attachment { kbts_u16 Format; kbts_u16 MarkCoverageOffset; @@ -13811,15 +16492,15 @@ typedef struct kbts_mark_to_ligature_attachment kbts_u16 MarkClassCount; kbts_u16 MarkArrayOffset; kbts_u16 LigatureArrayOffset; -} kbts_mark_to_ligature_attachment; +} kbts__mark_to_ligature_attachment; -typedef struct kbts_long_mtx +typedef struct kbts__long_mtx { kbts_u16 Advance; kbts_s16 PreviousSideBearing; -} kbts_long_mtx; +} kbts__long_mtx; -struct kbts_head +struct kbts__head { kbts_u16 Major; kbts_u16 Minor; @@ -13841,7 +16522,7 @@ struct kbts_head kbts_s16 GlyphDataFormat; // Only 0 is defined. }; -typedef struct kbts_hea +typedef struct kbts__hea { kbts_u16 Major; kbts_u16 Minor; @@ -13865,9 +16546,84 @@ typedef struct kbts_hea kbts_s16 MetricDataFormat; kbts_u16 MetricCount; -} kbts_hea; +} kbts__hea; -typedef struct kbts_maxp +typedef struct kbts__os2 +{ + kbts_u16 Version; + kbts_s16 AverageCharacterWidth; + kbts_u16 WeightClass; + kbts_u16 WidthClass; + kbts_u16 Type; + kbts_s16 SubscriptXSize; + kbts_s16 SubscriptYSize; + kbts_s16 SubscriptXOffset; + kbts_s16 SubscriptYOffset; + kbts_s16 SuperscriptXSize; + kbts_s16 SuperscriptYSize; + kbts_s16 SuperscriptXOffset; + kbts_s16 SuperscriptYOffset; + kbts_s16 StrikeoutSize; + kbts_s16 StrikeoutPosition; + kbts_s16 FamilyClass; + kbts_u8 Panose[10]; + kbts_u32 UnicodeRange[4]; + kbts_u32 VendorId; + kbts_u16 Selection; + kbts_u16 FirstCharacterIndex; + kbts_u16 LastCharacterIndex; + + // Some version 0 fonts support this, others do not. + kbts_s16 TypoAscender; + kbts_s16 TypoDescender; + kbts_s16 TypoLineGap; + kbts_u16 WinAscent; + kbts_u16 WinDescent; + + // If Version >= 1: + kbts_u32 CodePageRange[2]; + + // If Version >= 2: + kbts_s16 Height; + kbts_s16 CapHeight; + kbts_u16 DefaultChar; + kbts_u16 BreakChar; + kbts_u16 MaxContext; + + // If Version >= 5: + kbts_u16 LowerOpticalPointSize; + kbts_u16 UpperOpticalPointSize; +} kbts__os2; + +typedef struct kbts__lang_tag_record +{ + kbts_u16 Length; + kbts_u16 LangTagOffset; +} kbts__lang_tag_record; + +typedef struct kbts__name_record +{ + kbts_u16 PlatformId; + kbts_u16 EncodingId; + kbts_u16 LanguageId; + kbts_u16 NameId; + kbts_u16 Length; + kbts_u16 StringOffset; +} kbts__name_record; + +typedef struct kbts__name +{ + kbts_u16 Version; + kbts_u16 Count; + kbts_u16 StringStorageOffset; + // kbts__name_record Records[Count]; + + // If Version == 1: + // kbts_u16 LangTagCount; + // kbts__lang_tag_record LangTags[LangTagCount]; +} kbts__name; + +typedef struct kbts__maxp { kbts_u16 Major; kbts_u16 Minor; @@ -13887,7 +16643,7 @@ typedef struct kbts_maxp kbts_u16 MaximumInstructionSize; kbts_u16 MaximumTopLevelComponentCount; kbts_u16 MaximumComponentDepth; -} kbts_maxp; +} kbts__maxp; # pragma pack(pop) @@ -13895,70 +16651,70 @@ typedef struct kbts_maxp // Unpack functions for TTF structs. // -typedef struct kbts_script_pointer +typedef struct kbts__script_pointer { kbts_u32 Tag; - kbts_ot_script *Script; -} kbts_script_pointer; + kbts__ot_script *Script; +} kbts__script_pointer; -typedef struct kbts_langsys_pointer +typedef struct kbts__langsys_pointer { kbts_u32 Tag; - kbts_langsys *Langsys; -} kbts_langsys_pointer; + kbts__langsys *Langsys; +} kbts__langsys_pointer; -typedef struct kbts_feature_pointer +typedef struct kbts__feature_pointer { kbts_u32 Tag; - kbts_feature *Feature; -} kbts_feature_pointer; + kbts__feature *Feature; +} kbts__feature_pointer; -typedef struct kbts_feature_variation_pointer +typedef struct kbts__feature_variation_pointer { - kbts_condition_set *ConditionSet; - kbts_feature_table_substitution *FeatureTableSubstitution; -} kbts_feature_variation_pointer; + kbts__condition_set *ConditionSet; + kbts__feature_table_substitution *FeatureTableSubstitution; +} kbts__feature_variation_pointer; -typedef struct kbts_feature_substitution_pointer +typedef struct kbts__feature_substitution_pointer { kbts_u16 SubstitutedFeatureIndex; - kbts_feature *AlternateFeature; -} kbts_feature_substitution_pointer; + kbts__feature *AlternateFeature; +} kbts__feature_substitution_pointer; -typedef struct kbts_cmap_subtable_pointer +typedef struct kbts__cmap_subtable_pointer { kbts_u16 PlatformId; kbts_u16 EncodingId; kbts_u16 *Subtable; -} kbts_cmap_subtable_pointer; +} kbts__cmap_subtable_pointer; -typedef struct kbts_unpacked_chained_sequence_rule +typedef struct kbts__unpacked_chained_sequence_rule { kbts_u16 *Input; kbts_u16 *Backtrack; kbts_u16 *Lookahead; - kbts_sequence_lookup_record *Records; + kbts__sequence_lookup_record *Records; kbts_u16 BacktrackCount; kbts_u16 InputCount; kbts_u16 LookaheadCount; kbts_u16 RecordCount; -} kbts_unpacked_chained_sequence_rule; +} kbts__unpacked_chained_sequence_rule; -typedef struct kbts_unpacked_chained_sequence_context_3 +typedef struct kbts__unpacked_chained_sequence_context_3 { kbts_u16 *BacktrackCoverageOffsets; kbts_u16 *InputCoverageOffsets; kbts_u16 *LookaheadCoverageOffsets; - kbts_sequence_lookup_record *Records; + kbts__sequence_lookup_record *Records; kbts_u16 BacktrackCount; kbts_u16 InputCount; kbts_u16 LookaheadCount; kbts_u16 RecordCount; -} kbts_unpacked_chained_sequence_context_3; +} kbts__unpacked_chained_sequence_context_3; -typedef struct kbts_unpacked_reverse_chain_substitution +typedef struct kbts__unpacked_reverse_chain_substitution { kbts_u16 *BacktrackCoverageOffsets; kbts_u16 *LookaheadCoverageOffsets; @@ -13967,9 +16723,9 @@ typedef struct kbts_unpacked_reverse_chain_substitution kbts_u16 BacktrackCount; kbts_u16 LookaheadCount; kbts_u16 GlyphCount; -} kbts_unpacked_reverse_chain_substitution; +} kbts__unpacked_reverse_chain_substitution; -typedef struct kbts_unpacked_value_record +typedef struct kbts__unpacked_value_record { kbts_u16 Size; @@ -13977,68 +16733,68 @@ typedef struct kbts_unpacked_value_record kbts_s16 PlacementY; kbts_s16 AdvanceX; kbts_s16 AdvanceY; - kbts_device *PlacementXDevice; - kbts_device *PlacementYDevice; - kbts_device *AdvanceXDevice; - kbts_device *AdvanceYDevice; -} kbts_unpacked_value_record; + kbts__device *PlacementXDevice; + kbts__device *PlacementYDevice; + kbts__device *AdvanceXDevice; + kbts__device *AdvanceYDevice; +} kbts__unpacked_value_record; -static kbts_unpacked_value_record kbts_UnpackValueRecord(void *Parent, kbts_u16 Format, kbts_u16 *Record) +static kbts__unpacked_value_record kbts__UnpackValueRecord(void *Parent, kbts_u16 Format, kbts_u16 *Record) { - kbts_unpacked_value_record Result = KBTS_ZERO; + kbts__unpacked_value_record Result = KBTS__ZERO; kbts_u16 *At = Record; - if(Format & KBTS_VALUE_FORMAT_X_PLACEMENT) + if(Format & KBTS__VALUE_FORMAT_X_PLACEMENT) { Result.PlacementX = (kbts_s16)*At++; } - if(Format & KBTS_VALUE_FORMAT_Y_PLACEMENT) + if(Format & KBTS__VALUE_FORMAT_Y_PLACEMENT) { Result.PlacementY = (kbts_s16)*At++; } - if(Format & KBTS_VALUE_FORMAT_X_ADVANCE) + if(Format & KBTS__VALUE_FORMAT_X_ADVANCE) { Result.AdvanceX = (kbts_s16)*At++; } - if(Format & KBTS_VALUE_FORMAT_Y_ADVANCE) + if(Format & KBTS__VALUE_FORMAT_Y_ADVANCE) { Result.AdvanceY = (kbts_s16)*At++; } - if(Format & KBTS_VALUE_FORMAT_X_PLACEMENT_DEVICE) + if(Format & KBTS__VALUE_FORMAT_X_PLACEMENT_DEVICE) { kbts_u16 Offset = *At++; if(Offset) { - Result.PlacementXDevice = KBTS_POINTER_OFFSET(kbts_device, Parent, Offset); + Result.PlacementXDevice = KBTS__POINTER_OFFSET(kbts__device, Parent, Offset); } } - if(Format & KBTS_VALUE_FORMAT_Y_PLACEMENT_DEVICE) + if(Format & KBTS__VALUE_FORMAT_Y_PLACEMENT_DEVICE) { kbts_u16 Offset = *At++; if(Offset) { - Result.PlacementYDevice = KBTS_POINTER_OFFSET(kbts_device, Parent, Offset); + Result.PlacementYDevice = KBTS__POINTER_OFFSET(kbts__device, Parent, Offset); } } - if(Format & KBTS_VALUE_FORMAT_X_ADVANCE_DEVICE) + if(Format & KBTS__VALUE_FORMAT_X_ADVANCE_DEVICE) { kbts_u16 Offset = *At++; if(Offset) { - Result.AdvanceXDevice = KBTS_POINTER_OFFSET(kbts_device, Parent, Offset); + Result.AdvanceXDevice = KBTS__POINTER_OFFSET(kbts__device, Parent, Offset); } } - if(Format & KBTS_VALUE_FORMAT_Y_ADVANCE_DEVICE) + if(Format & KBTS__VALUE_FORMAT_Y_ADVANCE_DEVICE) { kbts_u16 Offset = *At++; if(Offset) { - Result.AdvanceYDevice = KBTS_POINTER_OFFSET(kbts_device, Parent, Offset); + Result.AdvanceYDevice = KBTS__POINTER_OFFSET(kbts__device, Parent, Offset); } } @@ -14047,131 +16803,131 @@ static kbts_unpacked_value_record kbts_UnpackValueRecord(void *Parent, kbts_u16 return Result; } -static kbts_unpacked_reverse_chain_substitution kbts_UnpackReverseChainSubstitution(kbts_reverse_chain_substitution *Subst, int ByteSwap) +static kbts__unpacked_reverse_chain_substitution kbts__UnpackReverseChainSubstitution(kbts__reverse_chain_substitution *Subst, int ByteSwap) { - kbts_unpacked_reverse_chain_substitution Result; + kbts__unpacked_reverse_chain_substitution Result; - Result.BacktrackCoverageOffsets = KBTS_POINTER_AFTER(kbts_u16, Subst); + Result.BacktrackCoverageOffsets = KBTS__POINTER_AFTER(kbts_u16, Subst); Result.BacktrackCount = Subst->BacktrackGlyphCount; if(ByteSwap) { - Result.BacktrackCount = kbts_ByteSwap16(Result.BacktrackCount); + Result.BacktrackCount = kbts__ByteSwap16(Result.BacktrackCount); } Result.LookaheadCoverageOffsets = Result.BacktrackCoverageOffsets + Result.BacktrackCount + 1; Result.LookaheadCount = Result.BacktrackCoverageOffsets[Result.BacktrackCount]; if(ByteSwap) { - Result.LookaheadCount = kbts_ByteSwap16(Result.LookaheadCount); + Result.LookaheadCount = kbts__ByteSwap16(Result.LookaheadCount); } Result.SubstituteGlyphIds = Result.LookaheadCoverageOffsets + Result.LookaheadCount + 1; Result.GlyphCount = Result.LookaheadCoverageOffsets[Result.LookaheadCount]; if(ByteSwap) { - Result.GlyphCount = kbts_ByteSwap16(Result.GlyphCount); + Result.GlyphCount = kbts__ByteSwap16(Result.GlyphCount); } return Result; } -static kbts_unpacked_chained_sequence_rule kbts_UnpackChainedSequenceRule(kbts_chained_sequence_rule *Rule, int ByteSwap) +static kbts__unpacked_chained_sequence_rule kbts__UnpackChainedSequenceRule(kbts__chained_sequence_rule *Rule, int ByteSwap) { - kbts_unpacked_chained_sequence_rule Result; + kbts__unpacked_chained_sequence_rule Result; - Result.Backtrack = KBTS_POINTER_AFTER(kbts_u16, Rule); + Result.Backtrack = KBTS__POINTER_AFTER(kbts_u16, Rule); Result.BacktrackCount = Rule->BacktrackGlyphCount; if(ByteSwap) { - Result.BacktrackCount = kbts_ByteSwap16(Result.BacktrackCount); + Result.BacktrackCount = kbts__ByteSwap16(Result.BacktrackCount); } Result.Input = Result.Backtrack + Result.BacktrackCount + 1; Result.InputCount = Result.Backtrack[Result.BacktrackCount]; if(ByteSwap) { - Result.InputCount = kbts_ByteSwap16(Result.InputCount); + Result.InputCount = kbts__ByteSwap16(Result.InputCount); } Result.Lookahead = Result.Input + Result.InputCount; Result.LookaheadCount = Result.Input[Result.InputCount - 1]; if(ByteSwap) { - Result.LookaheadCount = kbts_ByteSwap16(Result.LookaheadCount); + Result.LookaheadCount = kbts__ByteSwap16(Result.LookaheadCount); } - Result.Records = (kbts_sequence_lookup_record *)(Result.Lookahead + Result.LookaheadCount + 1); + Result.Records = (kbts__sequence_lookup_record *)(Result.Lookahead + Result.LookaheadCount + 1); Result.RecordCount = Result.Lookahead[Result.LookaheadCount]; if(ByteSwap) { - Result.RecordCount = kbts_ByteSwap16(Result.RecordCount); + Result.RecordCount = kbts__ByteSwap16(Result.RecordCount); } return Result; } -static kbts_unpacked_chained_sequence_context_3 kbts_UnpackChainedSequenceContext3(kbts_chained_sequence_context_3 *Subst, int ByteSwap) +static kbts__unpacked_chained_sequence_context_3 kbts__UnpackChainedSequenceContext3(kbts__chained_sequence_context_3 *Subst, int ByteSwap) { - kbts_unpacked_chained_sequence_context_3 Result; + kbts__unpacked_chained_sequence_context_3 Result; - Result.BacktrackCoverageOffsets = KBTS_POINTER_AFTER(kbts_u16, Subst); + Result.BacktrackCoverageOffsets = KBTS__POINTER_AFTER(kbts_u16, Subst); Result.BacktrackCount = Subst->BacktrackGlyphCount; if(ByteSwap) { - Result.BacktrackCount = kbts_ByteSwap16(Result.BacktrackCount); + Result.BacktrackCount = kbts__ByteSwap16(Result.BacktrackCount); } Result.InputCoverageOffsets = Result.BacktrackCoverageOffsets + Result.BacktrackCount + 1; Result.InputCount = Result.BacktrackCoverageOffsets[Result.BacktrackCount]; if(ByteSwap) { - Result.InputCount = kbts_ByteSwap16(Result.InputCount); + Result.InputCount = kbts__ByteSwap16(Result.InputCount); } Result.LookaheadCoverageOffsets = Result.InputCoverageOffsets + Result.InputCount + 1; Result.LookaheadCount = Result.InputCoverageOffsets[Result.InputCount]; if(ByteSwap) { - Result.LookaheadCount = kbts_ByteSwap16(Result.LookaheadCount); + Result.LookaheadCount = kbts__ByteSwap16(Result.LookaheadCount); } - Result.Records = (kbts_sequence_lookup_record *)(Result.LookaheadCoverageOffsets + Result.LookaheadCount + 1); + Result.Records = (kbts__sequence_lookup_record *)(Result.LookaheadCoverageOffsets + Result.LookaheadCount + 1); Result.RecordCount = Result.LookaheadCoverageOffsets[Result.LookaheadCount]; if(ByteSwap) { - Result.RecordCount = kbts_ByteSwap16(Result.RecordCount); + Result.RecordCount = kbts__ByteSwap16(Result.RecordCount); } return Result; } -typedef struct kbts_unpacked_lookup +typedef struct kbts__unpacked_lookup { kbts_u16 *SubtableOffsets; - kbts_coverage *MarkFilteringSet; + kbts__coverage *MarkFilteringSet; kbts_u16 Type; kbts_u16 Flags; kbts_u16 SubtableCount; -} kbts_unpacked_lookup; +} kbts__unpacked_lookup; -static kbts_unpacked_lookup kbts_UnpackLookup(kbts_gdef *Gdef, kbts_lookup *Lookup) +static kbts__unpacked_lookup kbts__UnpackLookup(kbts__gdef *Gdef, kbts__lookup *Lookup) { - kbts_unpacked_lookup Result = KBTS_ZERO; + kbts__unpacked_lookup Result = KBTS__ZERO; Result.Type = Lookup->Type; Result.Flags = Lookup->Flag; Result.SubtableCount = Lookup->SubtableCount; - Result.SubtableOffsets = KBTS_POINTER_AFTER(kbts_u16, Lookup); - if(Result.Flags & KBTS_LOOKUP_FLAG_USE_MARK_FILTERING_SET) + Result.SubtableOffsets = KBTS__POINTER_AFTER(kbts_u16, Lookup); + if(Result.Flags & KBTS__LOOKUP_FLAG_USE_MARK_FILTERING_SET) { kbts_u16 MarkFilteringSetIndex = Result.SubtableOffsets[Result.SubtableCount]; if(Gdef && Gdef->MarkGlyphSetsDefinitionOffset) { - kbts_mark_glyph_sets *MarkGlyphSets = KBTS_POINTER_OFFSET(kbts_mark_glyph_sets, Gdef, Gdef->MarkGlyphSetsDefinitionOffset); + kbts__mark_glyph_sets *MarkGlyphSets = KBTS__POINTER_OFFSET(kbts__mark_glyph_sets, Gdef, Gdef->MarkGlyphSetsDefinitionOffset); if(MarkGlyphSets->MarkGlyphSetCount > MarkFilteringSetIndex) { - kbts_u32 *CoverageOffsets = KBTS_POINTER_AFTER(kbts_u32, MarkGlyphSets); - Result.MarkFilteringSet = KBTS_POINTER_OFFSET(kbts_coverage, MarkGlyphSets, CoverageOffsets[MarkFilteringSetIndex]); + kbts_u32 *CoverageOffsets = KBTS__POINTER_AFTER(kbts_u32, MarkGlyphSets); + Result.MarkFilteringSet = KBTS__POINTER_OFFSET(kbts__coverage, MarkGlyphSets, CoverageOffsets[MarkFilteringSetIndex]); } } } @@ -14179,248 +16935,248 @@ static kbts_unpacked_lookup kbts_UnpackLookup(kbts_gdef *Gdef, kbts_lookup *Look return Result; } -static kbts_script_pointer kbts_GetScript(kbts_script_list *List, kbts_un Index) +static kbts__script_pointer kbts__GetScript(kbts__script_list *List, kbts_un Index) { - kbts_script_record *Records = (kbts_script_record *)(List + 1); - kbts_script_record *Record = &Records[Index]; + kbts__script_record *Records = (kbts__script_record *)(List + 1); + kbts__script_record *Record = &Records[Index]; - kbts_script_pointer Result; + kbts__script_pointer Result; Result.Tag = Record->Tag; - Result.Script = (kbts_ot_script *)((char *)List + Record->Offset); + Result.Script = (kbts__ot_script *)((char *)List + Record->Offset); return Result; } -static kbts_langsys *kbts_GetDefaultLangsys(kbts_ot_script *Script) +static kbts__langsys *kbts__GetDefaultLangsys(kbts__ot_script *Script) { - kbts_langsys *Result = Script->DefaultLangsysOffset ? KBTS_POINTER_OFFSET(kbts_langsys, Script, Script->DefaultLangsysOffset) : 0; + kbts__langsys *Result = Script->DefaultLangsysOffset ? KBTS__POINTER_OFFSET(kbts__langsys, Script, Script->DefaultLangsysOffset) : 0; return Result; } -static kbts_langsys_pointer kbts_GetLangsys(kbts_ot_script *Script, kbts_un Index) +static kbts__langsys_pointer kbts__GetLangsys(kbts__ot_script *Script, kbts_un Index) { - kbts_langsys_record *Records = (kbts_langsys_record *)(Script + 1); - kbts_langsys_record *Record = &Records[Index]; + kbts__langsys_record *Records = (kbts__langsys_record *)(Script + 1); + kbts__langsys_record *Record = &Records[Index]; - kbts_langsys_pointer Result; + kbts__langsys_pointer Result; Result.Tag = Record->Tag; - Result.Langsys = KBTS_POINTER_OFFSET(kbts_langsys, Script, Record->Offset); + Result.Langsys = KBTS__POINTER_OFFSET(kbts__langsys, Script, Record->Offset); return Result; } -static kbts_feature_pointer kbts_GetFeature(kbts_feature_list *List, kbts_un Index) +static kbts__feature_pointer kbts__GetFeature(kbts__feature_list *List, kbts_un Index) { - kbts_feature_record *Records = (kbts_feature_record *)(List + 1); - kbts_feature_record *Record = &Records[Index]; + kbts__feature_record *Records = (kbts__feature_record *)(List + 1); + kbts__feature_record *Record = &Records[Index]; - kbts_feature_pointer Result; + kbts__feature_pointer Result; Result.Tag = Record->Tag; - Result.Feature = KBTS_POINTER_OFFSET(kbts_feature, List, Record->Offset); + Result.Feature = KBTS__POINTER_OFFSET(kbts__feature, List, Record->Offset); return Result; } -static kbts_lookup_list *kbts_GetLookupList(kbts_gsub_gpos *GsubGpos) +static kbts_lookup_list *kbts__GetLookupList(kbts__gsub_gpos *GsubGpos) { kbts_lookup_list *Result = 0; if(GsubGpos) { - Result = KBTS_POINTER_OFFSET(kbts_lookup_list, GsubGpos, GsubGpos->LookupListOffset); + Result = KBTS__POINTER_OFFSET(kbts_lookup_list, GsubGpos, GsubGpos->LookupListOffset); } return Result; } -static kbts_lookup *kbts_GetLookup(kbts_lookup_list *List, kbts_un Index) +static kbts__lookup *kbts__GetLookup(kbts_lookup_list *List, kbts_un Index) { KBTS_ASSERT(Index < List->Count); kbts_u16 *Offsets = (kbts_u16 *)(List + 1); - kbts_lookup *Result = KBTS_POINTER_OFFSET(kbts_lookup, List, Offsets[Index]); + kbts__lookup *Result = KBTS__POINTER_OFFSET(kbts__lookup, List, Offsets[Index]); return Result; } -static kbts_sequence_rule_set *kbts_GetSequenceRuleSet(kbts_sequence_context_1 *Context, kbts_un Index) +static kbts__sequence_rule_set *kbts__GetSequenceRuleSet(kbts__sequence_context_1 *Context, kbts_un Index) { KBTS_ASSERT(Index < Context->SeqRuleSetCount); kbts_u16 *Offsets = (kbts_u16 *)(Context + 1); kbts_u16 Offset = Offsets[Index]; - kbts_sequence_rule_set *Result = Offset ? KBTS_POINTER_OFFSET(kbts_sequence_rule_set, Context, Offsets[Index]) : 0; + kbts__sequence_rule_set *Result = Offset ? KBTS__POINTER_OFFSET(kbts__sequence_rule_set, Context, Offsets[Index]) : 0; return Result; } -static kbts_sequence_rule *kbts_GetSequenceRule(kbts_sequence_rule_set *Set, kbts_un Index) +static kbts__sequence_rule *kbts__GetSequenceRule(kbts__sequence_rule_set *Set, kbts_un Index) { KBTS_ASSERT(Index < Set->Count); kbts_u16 *Offsets = (kbts_u16 *)(Set + 1); - kbts_sequence_rule *Result = KBTS_POINTER_OFFSET(kbts_sequence_rule, Set, Offsets[Index]); + kbts__sequence_rule *Result = KBTS__POINTER_OFFSET(kbts__sequence_rule, Set, Offsets[Index]); return Result; } // A single class definition table can be used by multiple lookups, so it is possible // (and valid) to get an out-of-bounds glyph class. -static kbts_class_sequence_rule_set *kbts_GetClassSequenceRuleSet(kbts_sequence_context_2 *Context, kbts_un Index) +static kbts__class_sequence_rule_set *kbts__GetClassSequenceRuleSet(kbts__sequence_context_2 *Context, kbts_un Index) { - kbts_class_sequence_rule_set *Result = 0; + kbts__class_sequence_rule_set *Result = 0; if(Index < Context->ClassSequenceRuleSetCount) { kbts_u16 *Offsets = (kbts_u16 *)(Context + 1); - Result = Offsets[Index] ? KBTS_POINTER_OFFSET(kbts_class_sequence_rule_set, Context, Offsets[Index]) : 0; + Result = Offsets[Index] ? KBTS__POINTER_OFFSET(kbts__class_sequence_rule_set, Context, Offsets[Index]) : 0; } return Result; } -static kbts_class_sequence_rule *kbts_GetClassSequenceRule(kbts_class_sequence_rule_set *Set, kbts_un Index) +static kbts__class_sequence_rule *kbts__GetClassSequenceRule(kbts__class_sequence_rule_set *Set, kbts_un Index) { KBTS_ASSERT(Index < Set->Count); kbts_u16 *Offsets = (kbts_u16 *)(Set + 1); - kbts_class_sequence_rule *Result = KBTS_POINTER_OFFSET(kbts_class_sequence_rule, Set, Offsets[Index]); + kbts__class_sequence_rule *Result = KBTS__POINTER_OFFSET(kbts__class_sequence_rule, Set, Offsets[Index]); return Result; } -static kbts_chained_sequence_rule_set *kbts_GetChainedSequenceRuleSet(kbts_chained_sequence_context_1 *Context, kbts_un Index) +static kbts__chained_sequence_rule_set *kbts__GetChainedSequenceRuleSet(kbts__chained_sequence_context_1 *Context, kbts_un Index) { kbts_u16 *Offsets = (kbts_u16 *)(Context + 1); - kbts_chained_sequence_rule_set *Result = Offsets[Index] ? KBTS_POINTER_OFFSET(kbts_chained_sequence_rule_set, Context, Offsets[Index]) : 0; + kbts__chained_sequence_rule_set *Result = Offsets[Index] ? KBTS__POINTER_OFFSET(kbts__chained_sequence_rule_set, Context, Offsets[Index]) : 0; return Result; } -static kbts_chained_sequence_rule *kbts_GetChainedSequenceRule(kbts_chained_sequence_rule_set *Set, kbts_un Index) +static kbts__chained_sequence_rule *kbts__GetChainedSequenceRule(kbts__chained_sequence_rule_set *Set, kbts_un Index) { kbts_u16 *Offsets = (kbts_u16 *)(Set + 1); - kbts_chained_sequence_rule *Result = KBTS_POINTER_OFFSET(kbts_chained_sequence_rule, Set, Offsets[Index]); + kbts__chained_sequence_rule *Result = KBTS__POINTER_OFFSET(kbts__chained_sequence_rule, Set, Offsets[Index]); return Result; } -static kbts_chained_sequence_rule_set *kbts_GetChainedClassSequenceRuleSet(kbts_chained_sequence_context_2 *Context, kbts_un Index) +static kbts__chained_sequence_rule_set *kbts__GetChainedClassSequenceRuleSet(kbts__chained_sequence_context_2 *Context, kbts_un Index) { kbts_u16 *Offsets = (kbts_u16 *)(Context + 1); kbts_u16 Offset = Offsets[Index]; - kbts_chained_sequence_rule_set *Result = Offset ? KBTS_POINTER_OFFSET(kbts_chained_sequence_rule_set, Context, Offset) : NULL; + kbts__chained_sequence_rule_set *Result = Offset ? KBTS__POINTER_OFFSET(kbts__chained_sequence_rule_set, Context, Offset) : NULL; return Result; } -static kbts_chained_sequence_rule *kbts_GetChainedClassSequenceRule(kbts_chained_sequence_rule_set *Set, kbts_un Index) +static kbts__chained_sequence_rule *kbts__GetChainedClassSequenceRule(kbts__chained_sequence_rule_set *Set, kbts_un Index) { kbts_u16 *Offsets = (kbts_u16 *)(Set + 1); - kbts_chained_sequence_rule *Result = KBTS_POINTER_OFFSET(kbts_chained_sequence_rule, Set, Offsets[Index]); + kbts__chained_sequence_rule *Result = KBTS__POINTER_OFFSET(kbts__chained_sequence_rule, Set, Offsets[Index]); return Result; } #if 0 // @Incomplete -static kbts_feature_variation_pointer kbts_GetFeatureVariation(kbts_feature_variations *Variations, kbts_un Index) +static kbts__feature_variation_pointer kbts__GetFeatureVariation(kbts__feature_variations *Variations, kbts_un Index) { - kbts_feature_variation_record *Records = (kbts_feature_variation_record *)(Variations + 1); - kbts_feature_variation_record *Record = &Records[Index]; + kbts__feature_variation_record *Records = (kbts__feature_variation_record *)(Variations + 1); + kbts__feature_variation_record *Record = &Records[Index]; - kbts_feature_variation_pointer Result; - Result.ConditionSet = KBTS_POINTER_OFFSET(kbts_condition_set, Variations, Record->ConditionSetOffset); - Result.FeatureTableSubstitution = KBTS_POINTER_OFFSET(kbts_feature_table_substitution, Variations, Record->FeatureTableSubstitutionOffset); + kbts__feature_variation_pointer Result; + Result.ConditionSet = KBTS__POINTER_OFFSET(kbts__condition_set, Variations, Record->ConditionSetOffset); + Result.FeatureTableSubstitution = KBTS__POINTER_OFFSET(kbts__feature_table_substitution, Variations, Record->FeatureTableSubstitutionOffset); return Result; } -static kbts_condition_1 *kbts_GetCondition(kbts_condition_set *Set, kbts_un Index) +static kbts__condition_1 *kbts__GetCondition(kbts__condition_set *Set, kbts_un Index) { kbts_u32 *Offsets = (kbts_u32 *)(Set + 1); - kbts_condition_1 *Result = KBTS_POINTER_OFFSET(kbts_condition_1, Set, Offsets[Index]); + kbts__condition_1 *Result = KBTS__POINTER_OFFSET(kbts__condition_1, Set, Offsets[Index]); return Result; } -static kbts_feature_substitution_pointer kbts_GetFeatureSubstitution(kbts_feature_table_substitution *Table, kbts_un Index) +static kbts__feature_substitution_pointer kbts__GetFeatureSubstitution(kbts__feature_table_substitution *Table, kbts_un Index) { - kbts_feature_table_substitution_record *Records = (kbts_feature_table_substitution_record *)(Table + 1); - kbts_feature_table_substitution_record *Record = &Records[Index]; + kbts__feature_table_substitution_record *Records = (kbts__feature_table_substitution_record *)(Table + 1); + kbts__feature_table_substitution_record *Record = &Records[Index]; - kbts_feature_substitution_pointer Result; + kbts__feature_substitution_pointer Result; Result.SubstitutedFeatureIndex = Record->FeatureIndex; - Result.AlternateFeature = KBTS_POINTER_OFFSET(kbts_feature, Table, Record->AlternateFeatureOffset); + Result.AlternateFeature = KBTS__POINTER_OFFSET(kbts__feature, Table, Record->AlternateFeatureOffset); return Result; } #endif -static kbts_cmap_subtable_pointer kbts_GetCmapSubtable(kbts_cmap *Cmap, kbts_un Index) +static kbts__cmap_subtable_pointer kbts__GetCmapSubtable(kbts__cmap *Cmap, kbts_un Index) { - kbts_encoding_record *Records = (kbts_encoding_record *)(Cmap + 1); - kbts_encoding_record *Record = &Records[Index]; + kbts__encoding_record *Records = (kbts__encoding_record *)(Cmap + 1); + kbts__encoding_record *Record = &Records[Index]; - kbts_cmap_subtable_pointer Result; + kbts__cmap_subtable_pointer Result; Result.PlatformId = Record->PlatformId; Result.EncodingId = Record->EncodingId; - Result.Subtable = KBTS_POINTER_OFFSET(kbts_u16, Cmap, Record->SubtableOffset); + Result.Subtable = KBTS__POINTER_OFFSET(kbts_u16, Cmap, Record->SubtableOffset); return Result; } -static kbts_sequence *kbts_GetSequence(kbts_multiple_substitution *Subst, kbts_un Index) +static kbts__sequence *kbts__GetSequence(kbts__multiple_substitution *Subst, kbts_un Index) { kbts_u16 *Offsets = (kbts_u16 *)(Subst + 1); - kbts_sequence *Result = KBTS_POINTER_OFFSET(kbts_sequence, Subst, Offsets[Index]); + kbts__sequence *Result = KBTS__POINTER_OFFSET(kbts__sequence, Subst, Offsets[Index]); return Result; } -static kbts_alternate_set *kbts_GetAlternateSet(kbts_alternate_substitution *Subst, kbts_un Index) +static kbts__alternate_set *kbts__GetAlternateSet(kbts__alternate_substitution *Subst, kbts_un Index) { kbts_u16 *Offsets = (kbts_u16 *)(Subst + 1); - kbts_alternate_set *Result = KBTS_POINTER_OFFSET(kbts_alternate_set, Subst, Offsets[Index]); + kbts__alternate_set *Result = KBTS__POINTER_OFFSET(kbts__alternate_set, Subst, Offsets[Index]); return Result; } -static kbts_ligature_set *kbts_GetLigatureSet(kbts_ligature_substitution *Subst, kbts_un Index) +static kbts__ligature_set *kbts__GetLigatureSet(kbts__ligature_substitution *Subst, kbts_un Index) { kbts_u16 *Offsets = (kbts_u16 *)(Subst + 1); - kbts_ligature_set *Result = KBTS_POINTER_OFFSET(kbts_ligature_set, Subst, Offsets[Index]); + kbts__ligature_set *Result = KBTS__POINTER_OFFSET(kbts__ligature_set, Subst, Offsets[Index]); return Result; } -static kbts_ligature *kbts_GetLigature(kbts_ligature_set *Set, kbts_un Index) +static kbts__ligature *kbts__GetLigature(kbts__ligature_set *Set, kbts_un Index) { kbts_u16 *Offsets = (kbts_u16 *)(Set + 1); - kbts_ligature *Result = KBTS_POINTER_OFFSET(kbts_ligature, Set, Offsets[Index]); + kbts__ligature *Result = KBTS__POINTER_OFFSET(kbts__ligature, Set, Offsets[Index]); return Result; } -static kbts_mark_record *kbts_GetMarkRecord(kbts_mark_array *Array, kbts_un Index) +static kbts__mark_record *kbts__GetMarkRecord(kbts__mark_array *Array, kbts_un Index) { - kbts_mark_record *Records = KBTS_POINTER_AFTER(kbts_mark_record, Array); - kbts_mark_record *Result = &Records[Index]; + kbts__mark_record *Records = KBTS__POINTER_AFTER(kbts__mark_record, Array); + kbts__mark_record *Result = &Records[Index]; return Result; } -static kbts_ligature_attach *kbts_GetLigatureAttach(kbts_ligature_array *Array, kbts_un Index) +static kbts__ligature_attach *kbts__GetLigatureAttach(kbts__ligature_array *Array, kbts_un Index) { - kbts_u16 *Offsets = KBTS_POINTER_AFTER(kbts_u16, Array); - kbts_ligature_attach *Result = KBTS_POINTER_OFFSET(kbts_ligature_attach, Array, Offsets[Index]); + kbts_u16 *Offsets = KBTS__POINTER_AFTER(kbts_u16, Array); + kbts__ligature_attach *Result = KBTS__POINTER_OFFSET(kbts__ligature_attach, Array, Offsets[Index]); return Result; } -static kbts_anchor *kbts_GetLigatureAttachAnchor(kbts_mark_to_ligature_attachment *Adjust, kbts_ligature_attach *Attach, kbts_u16 MarkClass, kbts_un ComponentIndex) +static kbts__anchor *kbts__GetLigatureAttachAnchor(kbts__mark_to_ligature_attachment *Adjust, kbts__ligature_attach *Attach, kbts_u16 MarkClass, kbts_un ComponentIndex) { - kbts_u16 *Offsets = KBTS_POINTER_AFTER(kbts_u16, Attach); + kbts_u16 *Offsets = KBTS__POINTER_AFTER(kbts_u16, Attach); kbts_u16 Offset = Offsets[ComponentIndex * Adjust->MarkClassCount + MarkClass]; - kbts_anchor *Result = 0; + kbts__anchor *Result = 0; if(Offset) { - Result = KBTS_POINTER_OFFSET(kbts_anchor, Attach, Offset); + Result = KBTS__POINTER_OFFSET(kbts__anchor, Attach, Offset); } return Result; } -typedef struct kbts_mark_info +typedef struct kbts__mark_info { - kbts_mark_array *Array; - kbts_mark_record *Record; - kbts_anchor *Anchor; -} kbts_mark_info; + kbts__mark_array *Array; + kbts__mark_record *Record; + kbts__anchor *Anchor; +} kbts__mark_info; -static kbts_mark_info kbts_GetMarkInfo(void *Subtable, kbts_un SubtableOffsetToMarkArray, kbts_un CoverageIndex) +static kbts__mark_info kbts__GetMarkInfo(void *Subtable, kbts_un SubtableOffsetToMarkArray, kbts_un CoverageIndex) { - kbts_mark_info Result = KBTS_ZERO; + kbts__mark_info Result = KBTS__ZERO; - Result.Array = KBTS_POINTER_OFFSET(kbts_mark_array, Subtable, SubtableOffsetToMarkArray); - Result.Record = kbts_GetMarkRecord(Result.Array, CoverageIndex); - Result.Anchor = KBTS_POINTER_OFFSET(kbts_anchor, Result.Array, Result.Record->AnchorOffset); + Result.Array = KBTS__POINTER_OFFSET(kbts__mark_array, Subtable, SubtableOffsetToMarkArray); + Result.Record = kbts__GetMarkRecord(Result.Array, CoverageIndex); + Result.Anchor = KBTS__POINTER_OFFSET(kbts__anchor, Result.Array, Result.Record->AnchorOffset); return Result; } @@ -14429,7 +17185,7 @@ static kbts_mark_info kbts_GetMarkInfo(void *Subtable, kbts_un SubtableOffsetToM // // -typedef struct kbts_byteswap_context +typedef struct kbts__byteswap_context { char *FileBase; char *FileEnd; @@ -14438,29 +17194,29 @@ typedef struct kbts_byteswap_context kbts_un PointerCount; int Error; -} kbts_byteswap_context; +} kbts__byteswap_context; -static int kbts_ByteSwapArray16Context(kbts_u16 *Array, kbts_un Count, kbts_byteswap_context *Context) +static int kbts__ByteSwapArray16Context(kbts_u16 *Array, kbts_un Count, kbts__byteswap_context *Context) { - int Result = kbts_ByteSwapArray16(Array, Count, Context->FileEnd); + int Result = kbts__ByteSwapArray16(Array, Count, Context->FileEnd); Context->Error |= !Result; return Result; } -static int kbts_ByteSwapArray32Context(kbts_u32 *Array, kbts_un Count, kbts_byteswap_context *Context) +static int kbts__ByteSwapArray32Context(kbts_u32 *Array, kbts_un Count, kbts__byteswap_context *Context) { - int Result = kbts_ByteSwapArray32(Array, Count, Context->FileEnd); + int Result = kbts__ByteSwapArray32(Array, Count, Context->FileEnd); Context->Error |= !Result; return Result; } -typedef struct kbts_cover_glyph_result +typedef struct kbts__cover_glyph_result { - kbts_u32 Valid; + int Valid; kbts_u32 Index; -} kbts_cover_glyph_result; +} kbts__cover_glyph_result; -static int kbts_LookupBeginsWithCoverage(kbts_shaping_table ShapingTable, kbts_u16 LookupType, kbts_u16 Format) +static int kbts__LookupBeginsWithCoverage(kbts_shaping_table ShapingTable, kbts_u16 LookupType, kbts_u16 Format) { int Result = 0; if(ShapingTable == KBTS_SHAPING_TABLE_GSUB) @@ -14475,56 +17231,26 @@ static int kbts_LookupBeginsWithCoverage(kbts_shaping_table ShapingTable, kbts_u } // Except for lookup tables 5.3, 6.3 and 7, all tables begin with (kbts_u16 Format, kbts_u16 CoverageOffset). -KBTS_INLINE int kbts_GsubLookupBeginsWithCoverage(kbts_u16 LookupType, kbts_u16 Format) +KBTS_INLINE int kbts__GsubLookupBeginsWithCoverage(kbts_u16 LookupType, kbts_u16 Format) { - int Result = kbts_LookupBeginsWithCoverage(KBTS_SHAPING_TABLE_GSUB, LookupType, Format); + int Result = kbts__LookupBeginsWithCoverage(KBTS_SHAPING_TABLE_GSUB, LookupType, Format); return Result; } -KBTS_INLINE int kbts_GposLookupBeginsWithCoverage(kbts_u16 LookupType, kbts_u16 Format) +KBTS_INLINE int kbts__GposLookupBeginsWithCoverage(kbts_u16 LookupType, kbts_u16 Format) { - int Result = kbts_LookupBeginsWithCoverage(KBTS_SHAPING_TABLE_GPOS, LookupType, Format); + int Result = kbts__LookupBeginsWithCoverage(KBTS_SHAPING_TABLE_GPOS, LookupType, Format); return Result; } -typedef struct kbts_lookup_info_frame -{ - kbts_u16 *Base; - kbts_u16 LookupType; - kbts_u32 LookaheadOffset; - kbts_u32 StackSize; -} kbts_lookup_info_frame; - -static int kbts_PushLookup(kbts_gdef *Gdef, kbts_lookup_info_frame *Frames, kbts_un *FrameCount, kbts_un FrameCapacity, kbts_lookup *PackedLookup, kbts_u32 LookaheadOffset, kbts_un StackSize) -{ - int Result = 0; - kbts_unpacked_lookup Lookup = kbts_UnpackLookup(Gdef, PackedLookup); - - if((*FrameCount + Lookup.SubtableCount) <= FrameCapacity) - { - KBTS_FOR(SubtableIndex, 0, Lookup.SubtableCount) - { - kbts_lookup_info_frame *Frame = &Frames[(*FrameCount)++]; - Frame->Base = KBTS_POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[SubtableIndex]); - Frame->LookupType = Lookup.Type; - Frame->LookaheadOffset = LookaheadOffset; - Frame->StackSize = (kbts_u32)StackSize; - } - - Result = 1; - } - - return Result; -} - -static int kbts_AlreadyVisited(kbts_byteswap_context *Context, void *Pointer) +static int kbts__AlreadyVisited(kbts__byteswap_context *Context, void *Pointer) { int Result = !Pointer || Context->Error; if(!Result) { kbts_u32 *Pointers = Context->Pointers; - kbts_u32 Pointer32 = KBTS_POINTER_DIFF32(Pointer, Context->FileBase); + kbts_u32 Pointer32 = KBTS__POINTER_DIFF32(Pointer, Context->FileBase); kbts_un Index = 0; if(Context->PointerCount) @@ -14558,20 +17284,20 @@ static int kbts_AlreadyVisited(kbts_byteswap_context *Context, void *Pointer) return Result; } -static void kbts_ByteSwapFeature(kbts_byteswap_context *Context, kbts_feature *Feature) +static void kbts__ByteSwapFeature(kbts__byteswap_context *Context, kbts__feature *Feature) { - if(!kbts_AlreadyVisited(Context, Feature)) + if(!kbts__AlreadyVisited(Context, Feature)) { - kbts_u16 *LookupIndices = KBTS_POINTER_AFTER(kbts_u16, Feature); - Context->Error |= !kbts_ByteSwapArray16(&Feature->FeatureParamsOffset, 2, Context->FileEnd); - Context->Error |= !kbts_ByteSwapArray16(LookupIndices, Feature->LookupIndexCount, Context->FileEnd); + kbts_u16 *LookupIndices = KBTS__POINTER_AFTER(kbts_u16, Feature); + Context->Error |= !kbts__ByteSwapArray16(&Feature->FeatureParamsOffset, 2, Context->FileEnd); + Context->Error |= !kbts__ByteSwapArray16(LookupIndices, Feature->LookupIndexCount, Context->FileEnd); // We require lookup indices to be sorted per feature for the lookup application order to match Harfbuzz. // Lookup indices are _typically_ sorted per feature, but we can't assume it is always the case. kbts_un LookupIndexCount = Feature->LookupIndexCount; - KBTS_FOR(Iter, 0, LookupIndexCount) + KBTS__FOR(Iter, 0, LookupIndexCount) { - KBTS_FOR(IndexIndex, 1, LookupIndexCount) + KBTS__FOR(IndexIndex, 1, LookupIndexCount) { kbts_u16 Left = LookupIndices[IndexIndex - 1]; kbts_u16 Right = LookupIndices[IndexIndex]; @@ -14586,63 +17312,63 @@ static void kbts_ByteSwapFeature(kbts_byteswap_context *Context, kbts_feature *F } # ifdef KBTS_DUMP - kbts_u16 *LookupIndices = KBTS_POINTER_AFTER(kbts_u16, Feature); - KBTS_FOR(LookupIndexIndex, 0, Feature->LookupIndexCount) + kbts_u16 *LookupIndices = KBTS__POINTER_AFTER(kbts_u16, Feature); + KBTS__FOR(LookupIndexIndex, 0, Feature->LookupIndexCount) { KBTS_DUMPF(" Lookup index %u\n", LookupIndices[LookupIndexIndex]); } # endif } -static void kbts_ByteSwapGsubGposCommon(kbts_byteswap_context *Context, kbts_gsub_gpos *Header) +static void kbts__ByteSwapGsubGposCommon(kbts__byteswap_context *Context, kbts__gsub_gpos *Header) { - kbts_ByteSwapArray16Context(&Header->Major, 5, Context); + kbts__ByteSwapArray16Context(&Header->Major, 5, Context); if(Header->Minor == 1) { - Header->FeatureVariationsOffset = kbts_ByteSwap32(Header->FeatureVariationsOffset); + Header->FeatureVariationsOffset = kbts__ByteSwap32(Header->FeatureVariationsOffset); } - kbts_script_list *ScriptList = KBTS_POINTER_OFFSET(kbts_script_list, Header, Header->ScriptListOffset); - if(!kbts_AlreadyVisited(Context, ScriptList)) + kbts__script_list *ScriptList = KBTS__POINTER_OFFSET(kbts__script_list, Header, Header->ScriptListOffset); + if(!kbts__AlreadyVisited(Context, ScriptList)) { - ScriptList->Count = kbts_ByteSwap16(ScriptList->Count); + ScriptList->Count = kbts__ByteSwap16(ScriptList->Count); - kbts_script_record *ScriptRecords = KBTS_POINTER_AFTER(kbts_script_record, ScriptList); - KBTS_FOR(It, 0, ScriptList->Count) + kbts__script_record *ScriptRecords = KBTS__POINTER_AFTER(kbts__script_record, ScriptList); + KBTS__FOR(It, 0, ScriptList->Count) { - kbts_script_record *Record = &ScriptRecords[It]; + kbts__script_record *Record = &ScriptRecords[It]; - Record->Offset = kbts_ByteSwap16(Record->Offset); + Record->Offset = kbts__ByteSwap16(Record->Offset); KBTS_DUMPF("Script %.4s\n", (char *)&Record->Tag); - kbts_ot_script *Script = KBTS_POINTER_OFFSET(kbts_ot_script, ScriptList, Record->Offset); - if(!kbts_AlreadyVisited(Context, Script)) + kbts__ot_script *Script = KBTS__POINTER_OFFSET(kbts__ot_script, ScriptList, Record->Offset); + if(!kbts__AlreadyVisited(Context, Script)) { - Script->DefaultLangsysOffset = kbts_ByteSwap16(Script->DefaultLangsysOffset); - Script->Count = kbts_ByteSwap16(Script->Count); + Script->DefaultLangsysOffset = kbts__ByteSwap16(Script->DefaultLangsysOffset); + Script->Count = kbts__ByteSwap16(Script->Count); - kbts_langsys *DefaultLangsys = kbts_GetDefaultLangsys(Script); + kbts__langsys *DefaultLangsys = kbts__GetDefaultLangsys(Script); - if(DefaultLangsys && !kbts_AlreadyVisited(Context, DefaultLangsys)) + if(DefaultLangsys && !kbts__AlreadyVisited(Context, DefaultLangsys)) { - kbts_ByteSwapArray16Context(&DefaultLangsys->LookupOrderOffset, 3, Context); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, DefaultLangsys), DefaultLangsys->FeatureIndexCount, Context); + kbts__ByteSwapArray16Context(&DefaultLangsys->LookupOrderOffset, 3, Context); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, DefaultLangsys), DefaultLangsys->FeatureIndexCount, Context); } - kbts_langsys_record *LangsysRecords = KBTS_POINTER_AFTER(kbts_langsys_record, Script); - KBTS_FOR(LangsysIndex, 0, Script->Count) + kbts__langsys_record *LangsysRecords = KBTS__POINTER_AFTER(kbts__langsys_record, Script); + KBTS__FOR(LangsysIndex, 0, Script->Count) { - kbts_langsys_record *LangsysRecord = &LangsysRecords[LangsysIndex]; + kbts__langsys_record *LangsysRecord = &LangsysRecords[LangsysIndex]; - LangsysRecord->Offset = kbts_ByteSwap16(LangsysRecord->Offset); + LangsysRecord->Offset = kbts__ByteSwap16(LangsysRecord->Offset); - kbts_langsys *Langsys = KBTS_POINTER_OFFSET(kbts_langsys, Script, LangsysRecord->Offset); - if(!kbts_AlreadyVisited(Context, Langsys)) + kbts__langsys *Langsys = KBTS__POINTER_OFFSET(kbts__langsys, Script, LangsysRecord->Offset); + if(!kbts__AlreadyVisited(Context, Langsys)) { - kbts_ByteSwapArray16Context(&Langsys->LookupOrderOffset, 3, Context); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Langsys), Langsys->FeatureIndexCount, Context); + kbts__ByteSwapArray16Context(&Langsys->LookupOrderOffset, 3, Context); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Langsys), Langsys->FeatureIndexCount, Context); } } @@ -14652,23 +17378,23 @@ static void kbts_ByteSwapGsubGposCommon(kbts_byteswap_context *Context, kbts_gsu KBTS_DUMPF(" Default langsys @ %zu\n", (char *)DefaultLangsys - Context->FileBase); KBTS_DUMPF(" Lookup order offset %u\n", DefaultLangsys->LookupOrderOffset); KBTS_DUMPF(" Required feature %u\n", DefaultLangsys->RequiredFeatureIndex); - kbts_u16 *FeatureIndices = KBTS_POINTER_AFTER(kbts_u16, DefaultLangsys); - KBTS_FOR(FeatureIndexIndex, 0, DefaultLangsys->FeatureIndexCount) + kbts_u16 *FeatureIndices = KBTS__POINTER_AFTER(kbts_u16, DefaultLangsys); + KBTS__FOR(FeatureIndexIndex, 0, DefaultLangsys->FeatureIndexCount) { KBTS_DUMPF(" Feature %u\n", FeatureIndices[FeatureIndexIndex]); } } - KBTS_FOR(LangsysIndex, 0, Script->Count) + KBTS__FOR(LangsysIndex, 0, Script->Count) { - kbts_langsys_record *LangsysRecord = &LangsysRecords[LangsysIndex]; - kbts_langsys *Langsys = KBTS_POINTER_OFFSET(kbts_langsys, Script, LangsysRecord->Offset); + kbts__langsys_record *LangsysRecord = &LangsysRecords[LangsysIndex]; + kbts__langsys *Langsys = KBTS__POINTER_OFFSET(kbts__langsys, Script, LangsysRecord->Offset); KBTS_DUMPF(" Langsys %.4s @ %zu\n", (char *)&LangsysRecord->Tag, (char *)Script + LangsysRecord->Offset - Context->FileBase); KBTS_DUMPF(" Lookup order offset %u\n" " Required feature %u\n", Langsys->LookupOrderOffset, Langsys->RequiredFeatureIndex); - kbts_u16 *FeatureIndices = KBTS_POINTER_AFTER(kbts_u16, Langsys); - KBTS_FOR(FeatureIndexIndex, 0, Langsys->FeatureIndexCount) + kbts_u16 *FeatureIndices = KBTS__POINTER_AFTER(kbts_u16, Langsys); + KBTS__FOR(FeatureIndexIndex, 0, Langsys->FeatureIndexCount) { KBTS_DUMPF(" Feature %u\n", FeatureIndices[FeatureIndexIndex]); } @@ -14677,55 +17403,58 @@ static void kbts_ByteSwapGsubGposCommon(kbts_byteswap_context *Context, kbts_gsu } } + // @Incomplete if((Header->Minor == 1) && Header->FeatureVariationsOffset) { - kbts_feature_variations *FeatureVariations = KBTS_POINTER_OFFSET(kbts_feature_variations, Header, Header->FeatureVariationsOffset); + kbts__feature_variations *FeatureVariations = KBTS__POINTER_OFFSET(kbts__feature_variations, Header, Header->FeatureVariationsOffset); - if(!kbts_AlreadyVisited(Context, FeatureVariations)) + if(!kbts__AlreadyVisited(Context, FeatureVariations)) { - kbts_ByteSwapArray16Context(&FeatureVariations->Major, 2, Context); - FeatureVariations->RecordCount = kbts_ByteSwap32(FeatureVariations->RecordCount); + kbts__ByteSwapArray16Context(&FeatureVariations->Major, 2, Context); + FeatureVariations->RecordCount = kbts__ByteSwap32(FeatureVariations->RecordCount); - kbts_feature_variation_record *Records = KBTS_POINTER_AFTER(kbts_feature_variation_record, FeatureVariations); - KBTS_FOR(VariationIndex, 0, FeatureVariations->RecordCount) + kbts__feature_variation_record *Records = KBTS__POINTER_AFTER(kbts__feature_variation_record, FeatureVariations); + KBTS__FOR(VariationIndex, 0, FeatureVariations->RecordCount) { - kbts_feature_variation_record *Record = &Records[VariationIndex]; + kbts__feature_variation_record *Record = &Records[VariationIndex]; - kbts_ByteSwapArray32Context(&Record->ConditionSetOffset, 2, Context); + kbts__ByteSwapArray32Context(&Record->ConditionSetOffset, 2, Context); - kbts_condition_set *Set = KBTS_POINTER_OFFSET(kbts_condition_set, FeatureVariations, Record->ConditionSetOffset); + kbts__condition_set *Set = KBTS__POINTER_OFFSET(kbts__condition_set, FeatureVariations, Record->ConditionSetOffset); - if(!kbts_AlreadyVisited(Context, Set)) + if(!kbts__AlreadyVisited(Context, Set)) { - Set->Count = kbts_ByteSwap16(Set->Count); + Set->Count = kbts__ByteSwap16(Set->Count); - kbts_u32 *ConditionOffsets = KBTS_POINTER_AFTER(kbts_u32, Set); - kbts_ByteSwapArray32Context(ConditionOffsets, Set->Count, Context); + kbts_u32 *ConditionOffsets = KBTS__POINTER_AFTER(kbts_u32, Set); + kbts__ByteSwapArray32Context(ConditionOffsets, Set->Count, Context); - KBTS_FOR(ConditionIndex, 0, Set->Count) + KBTS__FOR(ConditionIndex, 0, Set->Count) { - kbts_condition_1 *Condition = KBTS_POINTER_OFFSET(kbts_condition_1, Set, ConditionOffsets[ConditionIndex]); + kbts__condition_1 *Condition = KBTS__POINTER_OFFSET(kbts__condition_1, Set, ConditionOffsets[ConditionIndex]); - if(!kbts_AlreadyVisited(Context, Condition)) + if(!kbts__AlreadyVisited(Context, Condition)) { - kbts_ByteSwapArray16Context(&Condition->Format, 4, Context); + kbts__ByteSwapArray16Context(&Condition->Format, 4, Context); } } - kbts_feature_table_substitution *FeatureSubst = KBTS_POINTER_OFFSET(kbts_feature_table_substitution, FeatureVariations, Record->FeatureTableSubstitutionOffset); + // @Incomplete + kbts__feature_table_substitution *FeatureSubst = KBTS__POINTER_OFFSET(kbts__feature_table_substitution, FeatureVariations, Record->FeatureTableSubstitutionOffset); - if(!kbts_AlreadyVisited(Context, FeatureSubst)) + if(!kbts__AlreadyVisited(Context, FeatureSubst)) { - kbts_ByteSwapArray16Context(&FeatureSubst->Major, 3, Context); + kbts__ByteSwapArray16Context(&FeatureSubst->Major, 3, Context); - kbts_feature_table_substitution_record *SubstRecords = KBTS_POINTER_AFTER(kbts_feature_table_substitution_record, FeatureSubst); - KBTS_FOR(SubstRecordIndex, 0, FeatureSubst->Count) + kbts__feature_table_substitution_record *SubstRecords = KBTS__POINTER_AFTER(kbts__feature_table_substitution_record, FeatureSubst); + KBTS__FOR(SubstRecordIndex, 0, FeatureSubst->Count) { - kbts_feature_table_substitution_record *SubstRecord = &SubstRecords[SubstRecordIndex]; - SubstRecord->FeatureIndex = kbts_ByteSwap16(SubstRecord->FeatureIndex); + kbts__feature_table_substitution_record *SubstRecord = &SubstRecords[SubstRecordIndex]; + SubstRecord->FeatureIndex = kbts__ByteSwap16(SubstRecord->FeatureIndex); + SubstRecord->AlternateFeatureOffset = kbts__ByteSwap32(SubstRecord->AlternateFeatureOffset); - kbts_feature *Feature = KBTS_POINTER_OFFSET(kbts_feature, FeatureSubst, SubstRecord->AlternateFeatureOffset); - kbts_ByteSwapFeature(Context, Feature); + kbts__feature *Feature = KBTS__POINTER_OFFSET(kbts__feature, FeatureSubst, SubstRecord->AlternateFeatureOffset); + kbts__ByteSwapFeature(Context, Feature); } } } @@ -14734,55 +17463,55 @@ static void kbts_ByteSwapGsubGposCommon(kbts_byteswap_context *Context, kbts_gsu } } - kbts_feature_list *FeatureList = KBTS_POINTER_OFFSET(kbts_feature_list, Header, Header->FeatureListOffset); - if(!kbts_AlreadyVisited(Context, FeatureList)) + kbts__feature_list *FeatureList = KBTS__POINTER_OFFSET(kbts__feature_list, Header, Header->FeatureListOffset); + if(!kbts__AlreadyVisited(Context, FeatureList)) { - FeatureList->Count = kbts_ByteSwap16(FeatureList->Count); - kbts_feature_record *FeatureRecords = KBTS_POINTER_AFTER(kbts_feature_record, FeatureList); - KBTS_FOR(FeatureRecordIndex, 0, FeatureList->Count) + FeatureList->Count = kbts__ByteSwap16(FeatureList->Count); + kbts__feature_record *FeatureRecords = KBTS__POINTER_AFTER(kbts__feature_record, FeatureList); + KBTS__FOR(FeatureRecordIndex, 0, FeatureList->Count) { - kbts_feature_record *FeatureRecord = &FeatureRecords[FeatureRecordIndex]; + kbts__feature_record *FeatureRecord = &FeatureRecords[FeatureRecordIndex]; KBTS_DUMPF("Feature %llu %.4s\n", FeatureRecordIndex, (char *)&FeatureRecord->Tag); - if(!kbts_AlreadyVisited(Context, FeatureRecord)) + if(!kbts__AlreadyVisited(Context, FeatureRecord)) { - FeatureRecord->Offset = kbts_ByteSwap16(FeatureRecord->Offset); + FeatureRecord->Offset = kbts__ByteSwap16(FeatureRecord->Offset); - kbts_feature *Feature = KBTS_POINTER_OFFSET(kbts_feature, FeatureList, FeatureRecord->Offset); - kbts_ByteSwapFeature(Context, Feature); + kbts__feature *Feature = KBTS__POINTER_OFFSET(kbts__feature, FeatureList, FeatureRecord->Offset); + kbts__ByteSwapFeature(Context, Feature); } } } } -static int kbts_ByteSwapLookup(kbts_byteswap_context *Context, kbts_lookup *Lookup) +static int kbts__ByteSwapLookup(kbts__byteswap_context *Context, kbts__lookup *Lookup) { int Result = 0; - if(!kbts_AlreadyVisited(Context, Lookup)) + if(!kbts__AlreadyVisited(Context, Lookup)) { Result = 1; - kbts_ByteSwapArray16Context(&Lookup->Type, 3, Context); - kbts_u16 *SubtableOffsets = KBTS_POINTER_AFTER(kbts_u16, Lookup); + kbts__ByteSwapArray16Context(&Lookup->Type, 3, Context); + kbts_u16 *SubtableOffsets = KBTS__POINTER_AFTER(kbts_u16, Lookup); kbts_un U16Count = Lookup->SubtableCount; - if(Lookup->Flag & KBTS_LOOKUP_FLAG_USE_MARK_FILTERING_SET) + if(Lookup->Flag & KBTS__LOOKUP_FLAG_USE_MARK_FILTERING_SET) { U16Count += 1; } - kbts_ByteSwapArray16Context(SubtableOffsets, U16Count, Context); + kbts__ByteSwapArray16Context(SubtableOffsets, U16Count, Context); } return Result; } -static void kbts_ByteSwapCoverage(kbts_byteswap_context *Context, kbts_coverage *Coverage) +static void kbts__ByteSwapCoverage(kbts__byteswap_context *Context, kbts__coverage *Coverage) { - if(!kbts_AlreadyVisited(Context, Coverage)) + if(!kbts__AlreadyVisited(Context, Coverage)) { - kbts_ByteSwapArray16Context(&Coverage->Format, 2, Context); + kbts__ByteSwapArray16Context(&Coverage->Format, 2, Context); kbts_un U16Count = 0; if(Coverage->Format == 1) @@ -14794,15 +17523,15 @@ static void kbts_ByteSwapCoverage(kbts_byteswap_context *Context, kbts_coverage U16Count = Coverage->Count * 3; } - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Coverage), U16Count, Context); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Coverage), U16Count, Context); } } -static void kbts_ByteSwapAnchor(kbts_byteswap_context *Context, kbts_anchor *Anchor) +static void kbts__ByteSwapAnchor(kbts__byteswap_context *Context, kbts__anchor *Anchor) { - if(!kbts_AlreadyVisited(Context, Anchor)) + if(!kbts__AlreadyVisited(Context, Anchor)) { - Anchor->Format = kbts_ByteSwap16(Anchor->Format); + Anchor->Format = kbts__ByteSwap16(Anchor->Format); kbts_un U16Count = 2; if(Anchor->Format == 2) @@ -14814,36 +17543,36 @@ static void kbts_ByteSwapAnchor(kbts_byteswap_context *Context, kbts_anchor *Anc U16Count = 4; } - kbts_ByteSwapArray16Context((kbts_u16 *)&Anchor->X, U16Count, Context); + kbts__ByteSwapArray16Context((kbts_u16 *)&Anchor->X, U16Count, Context); } } -static void kbts_ByteSwapBaseArray(kbts_byteswap_context *Context, kbts_u16 MarkClassCount, kbts_base_array *Array) +static void kbts__ByteSwapBaseArray(kbts__byteswap_context *Context, kbts_u16 MarkClassCount, kbts__base_array *Array) { - if(!kbts_AlreadyVisited(Context, Array)) + if(!kbts__AlreadyVisited(Context, Array)) { - Array->BaseCount = kbts_ByteSwap16(Array->BaseCount); + Array->BaseCount = kbts__ByteSwap16(Array->BaseCount); - kbts_u16 *BaseAnchorOffsets = KBTS_POINTER_AFTER(kbts_u16, Array); - kbts_ByteSwapArray16Context(BaseAnchorOffsets, Array->BaseCount * MarkClassCount, Context); + kbts_u16 *BaseAnchorOffsets = KBTS__POINTER_AFTER(kbts_u16, Array); + kbts__ByteSwapArray16Context(BaseAnchorOffsets, Array->BaseCount * MarkClassCount, Context); - KBTS_FOR(OffsetIndex, 0, (kbts_un)Array->BaseCount * MarkClassCount) + KBTS__FOR(OffsetIndex, 0, (kbts_un)Array->BaseCount * MarkClassCount) { kbts_u16 Offset = BaseAnchorOffsets[OffsetIndex]; if(Offset) { - kbts_ByteSwapAnchor(Context, KBTS_POINTER_OFFSET(kbts_anchor, Array, Offset)); + kbts__ByteSwapAnchor(Context, KBTS__POINTER_OFFSET(kbts__anchor, Array, Offset)); } } } } -static void kbts_ByteSwapDevice(kbts_byteswap_context *Context, kbts_device *Device) +static void kbts__ByteSwapDevice(kbts__byteswap_context *Context, kbts__device *Device) { - if(!kbts_AlreadyVisited(Context, Device)) + if(!kbts__AlreadyVisited(Context, Device)) { - kbts_ByteSwapArray16Context(&Device->U.Device.StartSize, 3, Context); + kbts__ByteSwapArray16Context(&Device->U.Device.StartSize, 3, Context); if(Device->DeltaFormat <= 3) { @@ -14852,85 +17581,85 @@ static void kbts_ByteSwapDevice(kbts_byteswap_context *Context, kbts_device *Dev } } -static kbts_unpacked_value_record kbts_ByteSwapValueRecord(kbts_byteswap_context *Context, void *Parent, kbts_u16 ValueFormat, kbts_u16 *Record) +static kbts__unpacked_value_record kbts_ByteSwapValueRecord(kbts__byteswap_context *Context, void *Parent, kbts_u16 ValueFormat, kbts_u16 *Record) { - kbts_unpacked_value_record Result = KBTS_ZERO; + kbts__unpacked_value_record Result = KBTS__ZERO; if(ValueFormat) { - kbts_un U16Count = kbts_PopCount32(ValueFormat); + kbts_un U16Count = kbts__PopCount32(ValueFormat); - kbts_ByteSwapArray16Context(Record, U16Count, Context); + kbts__ByteSwapArray16Context(Record, U16Count, Context); - Result = kbts_UnpackValueRecord(Parent, ValueFormat, Record); + Result = kbts__UnpackValueRecord(Parent, ValueFormat, Record); - kbts_ByteSwapDevice(Context, Result.PlacementXDevice); - kbts_ByteSwapDevice(Context, Result.PlacementYDevice); - kbts_ByteSwapDevice(Context, Result.AdvanceXDevice); - kbts_ByteSwapDevice(Context, Result.AdvanceYDevice); + kbts__ByteSwapDevice(Context, Result.PlacementXDevice); + kbts__ByteSwapDevice(Context, Result.PlacementYDevice); + kbts__ByteSwapDevice(Context, Result.AdvanceXDevice); + kbts__ByteSwapDevice(Context, Result.AdvanceYDevice); } return Result; } -static void kbts_ByteSwapMarkArray(kbts_byteswap_context *Context, kbts_mark_array *MarkArray) +static void kbts__ByteSwapMarkArray(kbts__byteswap_context *Context, kbts__mark_array *MarkArray) { - if(!kbts_AlreadyVisited(Context, MarkArray)) + if(!kbts__AlreadyVisited(Context, MarkArray)) { - MarkArray->Count = kbts_ByteSwap16(MarkArray->Count); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, MarkArray), MarkArray->Count * 2, Context); + MarkArray->Count = kbts__ByteSwap16(MarkArray->Count); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, MarkArray), MarkArray->Count * 2, Context); - kbts_mark_record *MarkRecords = KBTS_POINTER_AFTER(kbts_mark_record, MarkArray); - KBTS_FOR(MarkRecordIndex, 0, MarkArray->Count) + kbts__mark_record *MarkRecords = KBTS__POINTER_AFTER(kbts__mark_record, MarkArray); + KBTS__FOR(MarkRecordIndex, 0, MarkArray->Count) { - kbts_mark_record *MarkRecord = &MarkRecords[MarkRecordIndex]; + kbts__mark_record *MarkRecord = &MarkRecords[MarkRecordIndex]; - kbts_ByteSwapAnchor(Context, KBTS_POINTER_OFFSET(kbts_anchor, MarkArray, MarkRecord->AnchorOffset)); + kbts__ByteSwapAnchor(Context, KBTS__POINTER_OFFSET(kbts__anchor, MarkArray, MarkRecord->AnchorOffset)); } } } -static void kbts_ByteSwapChainedSequenceRuleSet(kbts_byteswap_context *Context, kbts_chained_sequence_rule_set *Set) +static void kbts__ByteSwapChainedSequenceRuleSet(kbts__byteswap_context *Context, kbts__chained_sequence_rule_set *Set) { - if(Set && !kbts_AlreadyVisited(Context, Set)) + if(Set && !kbts__AlreadyVisited(Context, Set)) { - Set->Count = kbts_ByteSwap16(Set->Count); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Set), Set->Count, Context); + Set->Count = kbts__ByteSwap16(Set->Count); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Set), Set->Count, Context); - KBTS_FOR(RuleIndex, 0, Set->Count) + KBTS__FOR(RuleIndex, 0, Set->Count) { - kbts_chained_sequence_rule *Rule = kbts_GetChainedSequenceRule(Set, RuleIndex); + kbts__chained_sequence_rule *Rule = kbts__GetChainedSequenceRule(Set, RuleIndex); - if(!kbts_AlreadyVisited(Context, Rule)) + if(!kbts__AlreadyVisited(Context, Rule)) { - kbts_unpacked_chained_sequence_rule Unpacked = kbts_UnpackChainedSequenceRule(Rule, 1); + kbts__unpacked_chained_sequence_rule Unpacked = kbts__UnpackChainedSequenceRule(Rule, 1); kbts_un U16Count = Unpacked.BacktrackCount + Unpacked.InputCount + Unpacked.LookaheadCount + Unpacked.RecordCount * 2 + 3; - kbts_ByteSwapArray16Context(&Rule->BacktrackGlyphCount, U16Count, Context); + kbts__ByteSwapArray16Context(&Rule->BacktrackGlyphCount, U16Count, Context); } } } } #ifdef KBTS_DUMP -static void kbts_DumpClassDefinition(kbts_u16 *Base) +static void kbts__DumpClassDefinition(kbts_u16 *Base) { if(*Base == 1) { - kbts_class_definition_1 *ClassDef = (kbts_class_definition_1 *)Base; - kbts_u16 *ClassValues = KBTS_POINTER_AFTER(kbts_u16, ClassDef); - KBTS_FOR(GlyphIndex, 0, ClassDef->GlyphCount) + kbts__class_definition_1 *ClassDef = (kbts__class_definition_1 *)Base; + kbts_u16 *ClassValues = KBTS__POINTER_AFTER(kbts_u16, ClassDef); + KBTS__FOR(GlyphIndex, 0, ClassDef->GlyphCount) { KBTS_DUMPF("%llx -> %u\n", ClassDef->StartGlyphId + GlyphIndex, ClassValues[GlyphIndex]); } } else if(*Base == 2) { - kbts_class_definition_2 *ClassDef = (kbts_class_definition_2 *)Base; - kbts_class_range_record *Ranges = KBTS_POINTER_AFTER(kbts_class_range_record, ClassDef); - KBTS_FOR(RangeIndex, 0, ClassDef->Count) + kbts__class_definition_2 *ClassDef = (kbts__class_definition_2 *)Base; + kbts__class_range_record *Ranges = KBTS__POINTER_AFTER(kbts__class_range_record, ClassDef); + KBTS__FOR(RangeIndex, 0, ClassDef->Count) { - kbts_class_range_record *Range = &Ranges[RangeIndex]; + kbts__class_range_record *Range = &Ranges[RangeIndex]; KBTS_DUMPF("[%x..%x] -> %u\n", Range->StartGlyphId, Range->EndGlyphId, Range->Class); } @@ -14938,37 +17667,37 @@ static void kbts_DumpClassDefinition(kbts_u16 *Base) } #endif -static void kbts_ByteSwapClassDefinition(kbts_byteswap_context *Context, kbts_u16 *Base) +static void kbts__ByteSwapClassDefinition(kbts__byteswap_context *Context, kbts_u16 *Base) { - if(!kbts_AlreadyVisited(Context, Base)) + if(!kbts__AlreadyVisited(Context, Base)) { - *Base = kbts_ByteSwap16(*Base); + *Base = kbts__ByteSwap16(*Base); if(*Base == 1) { - kbts_class_definition_1 *ClassDef = (kbts_class_definition_1 *)Base; - kbts_ByteSwapArray16Context(&ClassDef->StartGlyphId, 2, Context); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, ClassDef), ClassDef->GlyphCount, Context); + kbts__class_definition_1 *ClassDef = (kbts__class_definition_1 *)Base; + kbts__ByteSwapArray16Context(&ClassDef->StartGlyphId, 2, Context); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, ClassDef), ClassDef->GlyphCount, Context); } else if(*Base == 2) { - kbts_class_definition_2 *ClassDef = (kbts_class_definition_2 *)Base; - ClassDef->Count = kbts_ByteSwap16(ClassDef->Count); + kbts__class_definition_2 *ClassDef = (kbts__class_definition_2 *)Base; + ClassDef->Count = kbts__ByteSwap16(ClassDef->Count); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, ClassDef), ClassDef->Count * 3, Context); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, ClassDef), ClassDef->Count * 3, Context); } } } -typedef struct kbts_glyph_class_from_table_result +typedef struct kbts__glyph_class_from_table_result { int Found; kbts_u16 Class; -} kbts_glyph_class_from_table_result; +} kbts__glyph_class_from_table_result; -static kbts_glyph_class_from_table_result kbts_GlyphClassFromTable(kbts_u16 *ClassDefinitionBase, kbts_un Id) +static kbts__glyph_class_from_table_result kbts__GlyphClassFromTable(kbts_u16 *ClassDefinitionBase, kbts_un Id) { - kbts_glyph_class_from_table_result Result = KBTS_ZERO; + kbts__glyph_class_from_table_result Result = KBTS__ZERO; // From the Microsoft docs: // There is one offset to a ChainedClassSequenceRuleSet subtable for each class defined in the input sequence @@ -14982,8 +17711,8 @@ static kbts_glyph_class_from_table_result kbts_GlyphClassFromTable(kbts_u16 *Cla if(*ClassDefinitionBase == 1) { - kbts_class_definition_1 *ClassDef = (kbts_class_definition_1 *)ClassDefinitionBase; - kbts_u16 *GlyphClasses = KBTS_POINTER_AFTER(kbts_u16, ClassDef); + kbts__class_definition_1 *ClassDef = (kbts__class_definition_1 *)ClassDefinitionBase; + kbts_u16 *GlyphClasses = KBTS__POINTER_AFTER(kbts_u16, ClassDef); kbts_un Offset = Id - ClassDef->StartGlyphId; if(Offset < ClassDef->GlyphCount) @@ -14994,8 +17723,8 @@ static kbts_glyph_class_from_table_result kbts_GlyphClassFromTable(kbts_u16 *Cla } else if(*ClassDefinitionBase == 2) { - kbts_class_definition_2 *ClassDef = (kbts_class_definition_2 *)ClassDefinitionBase; - kbts_class_range_record *Ranges = KBTS_POINTER_AFTER(kbts_class_range_record, ClassDef); + kbts__class_definition_2 *ClassDef = (kbts__class_definition_2 *)ClassDefinitionBase; + kbts__class_range_record *Ranges = KBTS__POINTER_AFTER(kbts__class_range_record, ClassDef); kbts_un RangeCount = ClassDef->Count; if(RangeCount) @@ -15017,17 +17746,17 @@ static kbts_glyph_class_from_table_result kbts_GlyphClassFromTable(kbts_u16 *Cla return Result; } -static kbts_cover_glyph_result kbts_CoverGlyph(kbts_coverage *Coverage, kbts_u32 GlyphId) +static kbts__cover_glyph_result kbts__CoverGlyph(kbts__coverage *Coverage, kbts_u32 GlyphId) { - KBTS_INSTRUMENT_FUNCTION_BEGIN - kbts_cover_glyph_result Result = KBTS_ZERO; + KBTS_INSTRUMENT_FUNCTION_BEGIN; + kbts__cover_glyph_result Result = KBTS__ZERO; kbts_un Count = Coverage->Count; if(Count) { if(Coverage->Format == 1) { - kbts_u16 *GlyphIds = KBTS_POINTER_AFTER(kbts_u16, Coverage); + kbts_u16 *GlyphIds = KBTS__POINTER_AFTER(kbts_u16, Coverage); while(Count > 1) { @@ -15039,12 +17768,12 @@ static kbts_cover_glyph_result kbts_CoverGlyph(kbts_coverage *Coverage, kbts_u32 if(GlyphId == *GlyphIds) { Result.Valid = 1; - Result.Index = (kbts_u32)(GlyphIds - KBTS_POINTER_AFTER(kbts_u16, Coverage)); + Result.Index = (kbts_u32)(GlyphIds - KBTS__POINTER_AFTER(kbts_u16, Coverage)); } } else if(Coverage->Format == 2) { - kbts_range_record *Ranges = KBTS_POINTER_AFTER(kbts_range_record, Coverage); + kbts__range_record *Ranges = KBTS__POINTER_AFTER(kbts__range_record, Coverage); while(Count > 1) { @@ -15060,35 +17789,35 @@ static kbts_cover_glyph_result kbts_CoverGlyph(kbts_coverage *Coverage, kbts_u32 } } - KBTS_INSTRUMENT_END + KBTS_INSTRUMENT_FUNCTION_END; return Result; } -static void kbts_ByteSwapSequenceContextSubtable(kbts_byteswap_context *Context, kbts_u16 *Base) +static void kbts__ByteSwapSequenceContextSubtable(kbts__byteswap_context *Context, kbts_u16 *Base) { if(Base[0] == 1) { - kbts_sequence_context_1 *Subst = (kbts_sequence_context_1 *)Base; - Subst->SeqRuleSetCount = kbts_ByteSwap16(Subst->SeqRuleSetCount); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Subst), Subst->SeqRuleSetCount, Context); + kbts__sequence_context_1 *Subst = (kbts__sequence_context_1 *)Base; + Subst->SeqRuleSetCount = kbts__ByteSwap16(Subst->SeqRuleSetCount); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Subst), Subst->SeqRuleSetCount, Context); - KBTS_FOR(SetIndex, 0, Subst->SeqRuleSetCount) + KBTS__FOR(SetIndex, 0, Subst->SeqRuleSetCount) { - kbts_sequence_rule_set *Set = kbts_GetSequenceRuleSet(Subst, SetIndex); + kbts__sequence_rule_set *Set = kbts__GetSequenceRuleSet(Subst, SetIndex); - if(Set && !kbts_AlreadyVisited(Context, Set)) + if(Set && !kbts__AlreadyVisited(Context, Set)) { - Set->Count = kbts_ByteSwap16(Set->Count); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Set), Set->Count, Context); + Set->Count = kbts__ByteSwap16(Set->Count); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Set), Set->Count, Context); - KBTS_FOR(RuleIndex, 0, Set->Count) + KBTS__FOR(RuleIndex, 0, Set->Count) { - kbts_sequence_rule *Rule = kbts_GetSequenceRule(Set, RuleIndex); + kbts__sequence_rule *Rule = kbts__GetSequenceRule(Set, RuleIndex); - if(!kbts_AlreadyVisited(Context, Rule)) + if(!kbts__AlreadyVisited(Context, Rule)) { - kbts_ByteSwapArray16Context(&Rule->GlyphCount, 2, Context); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Rule), (kbts_un)Rule->GlyphCount - 1 + (kbts_un)Rule->SequenceLookupCount * 2, Context); + kbts__ByteSwapArray16Context(&Rule->GlyphCount, 2, Context); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Rule), (kbts_un)Rule->GlyphCount - 1 + (kbts_un)Rule->SequenceLookupCount * 2, Context); } } } @@ -15096,57 +17825,57 @@ static void kbts_ByteSwapSequenceContextSubtable(kbts_byteswap_context *Context, } else if(Base[0] == 2) { - kbts_sequence_context_2 *Subst = (kbts_sequence_context_2 *)Base; - kbts_ByteSwapArray16Context(&Subst->ClassDefOffset, 2, Context); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Subst), Subst->ClassSequenceRuleSetCount, Context); + kbts__sequence_context_2 *Subst = (kbts__sequence_context_2 *)Base; + kbts__ByteSwapArray16Context(&Subst->ClassDefOffset, 2, Context); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Subst), Subst->ClassSequenceRuleSetCount, Context); - kbts_u16 *ClassDefBase = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->ClassDefOffset); - kbts_ByteSwapClassDefinition(Context, ClassDefBase); + kbts_u16 *ClassDefBase = KBTS__POINTER_OFFSET(kbts_u16, Subst, Subst->ClassDefOffset); + kbts__ByteSwapClassDefinition(Context, ClassDefBase); - KBTS_FOR(SetIndex, 0, Subst->ClassSequenceRuleSetCount) + KBTS__FOR(SetIndex, 0, Subst->ClassSequenceRuleSetCount) { - kbts_class_sequence_rule_set *Set = kbts_GetClassSequenceRuleSet(Subst, SetIndex); + kbts__class_sequence_rule_set *Set = kbts__GetClassSequenceRuleSet(Subst, SetIndex); - if(Set && !kbts_AlreadyVisited(Context, Set)) + if(Set && !kbts__AlreadyVisited(Context, Set)) { - Set->Count = kbts_ByteSwap16(Set->Count); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Set), Set->Count, Context); + Set->Count = kbts__ByteSwap16(Set->Count); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Set), Set->Count, Context); - KBTS_FOR(RuleIndex, 0, Set->Count) + KBTS__FOR(RuleIndex, 0, Set->Count) { - kbts_class_sequence_rule *Rule = kbts_GetClassSequenceRule(Set, RuleIndex); + kbts__class_sequence_rule *Rule = kbts__GetClassSequenceRule(Set, RuleIndex); - if(!kbts_AlreadyVisited(Context, Rule)) + if(!kbts__AlreadyVisited(Context, Rule)) { - kbts_ByteSwapArray16Context(&Rule->GlyphCount, 2, Context); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Rule), Rule->GlyphCount - 1 + 2 * Rule->SequenceLookupCount, Context); + kbts__ByteSwapArray16Context(&Rule->GlyphCount, 2, Context); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Rule), Rule->GlyphCount - 1 + 2 * Rule->SequenceLookupCount, Context); } } } } #ifdef KBTS_DUMP - kbts_DumpClassDefinition(ClassDefBase); - KBTS_FOR(SetIndex, 0, Subst->ClassSequenceRuleSetCount) + kbts__DumpClassDefinition(ClassDefBase); + KBTS__FOR(SetIndex, 0, Subst->ClassSequenceRuleSetCount) { - kbts_class_sequence_rule_set *Set = kbts_GetClassSequenceRuleSet(Subst, SetIndex); + kbts__class_sequence_rule_set *Set = kbts__GetClassSequenceRuleSet(Subst, SetIndex); if(Set) { - KBTS_FOR(RuleIndex, 0, Set->Count) + KBTS__FOR(RuleIndex, 0, Set->Count) { - kbts_class_sequence_rule *Rule = kbts_GetClassSequenceRule(Set, RuleIndex); - kbts_u16 *InputSequence = KBTS_POINTER_AFTER(kbts_u16, Rule); - kbts_sequence_lookup_record *Records = (kbts_sequence_lookup_record *)(InputSequence + Rule->GlyphCount - 1); + kbts__class_sequence_rule *Rule = kbts__GetClassSequenceRule(Set, RuleIndex); + kbts_u16 *InputSequence = KBTS__POINTER_AFTER(kbts_u16, Rule); + kbts__sequence_lookup_record *Records = (kbts__sequence_lookup_record *)(InputSequence + Rule->GlyphCount - 1); KBTS_DUMPF("Input: ["); - KBTS_FOR(GlyphIndex, 1, Rule->GlyphCount) + KBTS__FOR(GlyphIndex, 1, Rule->GlyphCount) { KBTS_DUMPF(", %x", InputSequence[GlyphIndex - 1]); } KBTS_DUMPF("]\nRecords: ["); - KBTS_FOR(RecordIndex, 0, Rule->SequenceLookupCount) + KBTS__FOR(RecordIndex, 0, Rule->SequenceLookupCount) { - kbts_sequence_lookup_record *Record = &Records[RecordIndex]; + kbts__sequence_lookup_record *Record = &Records[RecordIndex]; if(RecordIndex) KBTS_DUMPF(", "); KBTS_DUMPF("%u@%u", Record->LookupListIndex, Record->SequenceIndex); } @@ -15158,111 +17887,127 @@ static void kbts_ByteSwapSequenceContextSubtable(kbts_byteswap_context *Context, } else if(Base[0] == 3) { - kbts_sequence_context_3 *Subst = (kbts_sequence_context_3 *)Base; - kbts_ByteSwapArray16Context(&Subst->GlyphCount, 2, Context); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Subst), Subst->GlyphCount + 2 * Subst->SequenceLookupCount, Context); + kbts__sequence_context_3 *Subst = (kbts__sequence_context_3 *)Base; + kbts__ByteSwapArray16Context(&Subst->GlyphCount, 2, Context); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Subst), Subst->GlyphCount + 2 * Subst->SequenceLookupCount, Context); - kbts_u16 *CoverageOffsets = KBTS_POINTER_AFTER(kbts_u16, Subst); - KBTS_FOR(CoverageIndex, 0, Subst->GlyphCount) + kbts_u16 *CoverageOffsets = KBTS__POINTER_AFTER(kbts_u16, Subst); + KBTS__FOR(CoverageIndex, 0, Subst->GlyphCount) { - kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, CoverageOffsets[CoverageIndex]); + kbts__coverage *Coverage = KBTS__POINTER_OFFSET(kbts__coverage, Subst, CoverageOffsets[CoverageIndex]); - kbts_ByteSwapCoverage(Context, Coverage); + kbts__ByteSwapCoverage(Context, Coverage); } } } -typedef kbts_u32 kbts_skip_flags; -enum kbts_skip_flags_enum +typedef kbts_u32 kbts__skip_flags; +enum kbts__skip_flags_enum { - KBTS_SKIP_FLAG_NONE, - KBTS_SKIP_FLAG_ZWNJ = (1 << 0), - KBTS_SKIP_FLAG_ZWJ = (1 << 1), + KBTS__SKIP_FLAG_NONE, + KBTS__SKIP_FLAG_ZWNJ = (1 << 0), + KBTS__SKIP_FLAG_ZWJ = (1 << 1), }; // The Harfbuzz behavior is: // - GPOS lookups always skip ZWNJ. // - Sequence lookups always skip ZWJ. // - GSUB sequence lookups skip ZWNJ when requested. // - Regular lookups skip ZWJ when requested. -#define KBTS_SKIP_FLAGS_GSUB_REGULAR(RequestedFlags) ((RequestedFlags) & KBTS_SKIP_FLAG_ZWJ) -#define KBTS_SKIP_FLAGS_GSUB_SEQUENCE(RequestedFlags) (KBTS_SKIP_FLAG_ZWJ | ((RequestedFlags) & KBTS_SKIP_FLAG_ZWNJ)) -#define KBTS_SKIP_FLAGS_GPOS_REGULAR(RequestedFlags) (((RequestedFlags) & KBTS_SKIP_FLAG_ZWJ) | KBTS_SKIP_FLAG_ZWNJ) -#define KBTS_SKIP_FLAGS_GPOS_SEQUENCE(RequestedFlags) (KBTS_SKIP_FLAG_ZWJ | KBTS_SKIP_FLAG_ZWNJ) +#define KBTS__SKIP_FLAGS_GSUB_REGULAR(RequestedFlags) ((RequestedFlags) & KBTS__SKIP_FLAG_ZWJ) +#define KBTS__SKIP_FLAGS_GSUB_SEQUENCE(RequestedFlags) (KBTS__SKIP_FLAG_ZWJ | ((RequestedFlags) & KBTS__SKIP_FLAG_ZWNJ)) +#define KBTS__SKIP_FLAGS_GPOS_REGULAR(RequestedFlags) (((RequestedFlags) & KBTS__SKIP_FLAG_ZWJ) | KBTS__SKIP_FLAG_ZWNJ) +#define KBTS__SKIP_FLAGS_GPOS_SEQUENCE(RequestedFlags) (KBTS__SKIP_FLAG_ZWJ | KBTS__SKIP_FLAG_ZWNJ) -static kbts_skip_flags kbts_SkipFlags(kbts_feature_id FeatureId, kbts_shaper Shaper) +static kbts__skip_flags kbts__SkipFlags(kbts__feature_id FeatureId, kbts_shaper Shaper) { - kbts_skip_flags Result = 0; + kbts__skip_flags Result = 0; switch(FeatureId) { - case KBTS_FEATURE_ID_nukt: - case KBTS_FEATURE_ID_akhn: - case KBTS_FEATURE_ID_rphf: - case KBTS_FEATURE_ID_rkrf: - case KBTS_FEATURE_ID_pref: - case KBTS_FEATURE_ID_blwf: - case KBTS_FEATURE_ID_abvf: - case KBTS_FEATURE_ID_half: - case KBTS_FEATURE_ID_pstf: - case KBTS_FEATURE_ID_vatu: - case KBTS_FEATURE_ID_cjct: - case KBTS_FEATURE_ID_pres: - case KBTS_FEATURE_ID_abvs: - case KBTS_FEATURE_ID_blws: - case KBTS_FEATURE_ID_psts: - case KBTS_FEATURE_ID_haln: - Result = (Shaper == KBTS_SHAPER_INDIC) ? 0 : KBTS_SKIP_FLAG_ZWNJ | KBTS_SKIP_FLAG_ZWJ; + case KBTS__FEATURE_ID_nukt: + case KBTS__FEATURE_ID_akhn: + case KBTS__FEATURE_ID_rphf: + case KBTS__FEATURE_ID_rkrf: + case KBTS__FEATURE_ID_pref: + case KBTS__FEATURE_ID_blwf: + case KBTS__FEATURE_ID_abvf: + case KBTS__FEATURE_ID_half: + case KBTS__FEATURE_ID_pstf: + case KBTS__FEATURE_ID_vatu: + case KBTS__FEATURE_ID_cjct: + case KBTS__FEATURE_ID_pres: + case KBTS__FEATURE_ID_abvs: + case KBTS__FEATURE_ID_blws: + case KBTS__FEATURE_ID_psts: + case KBTS__FEATURE_ID_haln: + case KBTS__FEATURE_ID_cfar: + if(Shaper == KBTS_SHAPER_USE) + { + Result = KBTS__SKIP_FLAG_ZWNJ; + } + else if((Shaper == KBTS_SHAPER_INDIC) || + (Shaper == KBTS_SHAPER_KHMER)) + { + Result = 0; + } + else + { + Result = KBTS__SKIP_FLAG_ZWNJ | KBTS__SKIP_FLAG_ZWJ; + } break; - case KBTS_FEATURE_ID_init: + case KBTS__FEATURE_ID_init: if (Shaper == KBTS_SHAPER_INDIC) {Result = 0;} - else if(Shaper == KBTS_SHAPER_ARABIC) {Result = KBTS_SKIP_FLAG_ZWNJ;} - else {Result = KBTS_SKIP_FLAG_ZWNJ | KBTS_SKIP_FLAG_ZWJ;} + else if(Shaper == KBTS_SHAPER_ARABIC) {Result = KBTS__SKIP_FLAG_ZWNJ;} + else {Result = KBTS__SKIP_FLAG_ZWNJ | KBTS__SKIP_FLAG_ZWJ;} break; - case KBTS_FEATURE_ID_ccmp: - case KBTS_FEATURE_ID_locl: - case KBTS_FEATURE_ID_isol: - case KBTS_FEATURE_ID_fina: - case KBTS_FEATURE_ID_fin2: - case KBTS_FEATURE_ID_fin3: - case KBTS_FEATURE_ID_medi: - case KBTS_FEATURE_ID_med2: - case KBTS_FEATURE_ID_calt: - case KBTS_FEATURE_ID_liga: - case KBTS_FEATURE_ID_clig: - case KBTS_FEATURE_ID_rlig: - case KBTS_FEATURE_ID_mset: - Result = (Shaper == KBTS_SHAPER_ARABIC) ? KBTS_SKIP_FLAG_ZWNJ : KBTS_SKIP_FLAG_ZWNJ | KBTS_SKIP_FLAG_ZWJ; + case KBTS__FEATURE_ID_ccmp: + case KBTS__FEATURE_ID_locl: + case KBTS__FEATURE_ID_isol: + case KBTS__FEATURE_ID_fina: + case KBTS__FEATURE_ID_fin2: + case KBTS__FEATURE_ID_fin3: + case KBTS__FEATURE_ID_medi: + case KBTS__FEATURE_ID_med2: + case KBTS__FEATURE_ID_calt: + case KBTS__FEATURE_ID_liga: + case KBTS__FEATURE_ID_clig: + case KBTS__FEATURE_ID_rlig: + case KBTS__FEATURE_ID_mset: + Result = (Shaper == KBTS_SHAPER_ARABIC) ? KBTS__SKIP_FLAG_ZWNJ : KBTS__SKIP_FLAG_ZWNJ | KBTS__SKIP_FLAG_ZWJ; break; - case KBTS_FEATURE_ID_mark: - case KBTS_FEATURE_ID_mkmk: + case KBTS__FEATURE_ID_mark: + case KBTS__FEATURE_ID_mkmk: Result = 0; break; default: - Result = KBTS_SKIP_FLAG_ZWNJ | KBTS_SKIP_FLAG_ZWJ; + Result = KBTS__SKIP_FLAG_ZWNJ | KBTS__SKIP_FLAG_ZWJ; break; } return Result; } -static kbts_u32 kbts_GlyphIncludedInLookup(kbts_font *Font, int Gpos, kbts_un LookupIndex, kbts_u32 Id) +static kbts_u32 kbts__GlyphIncludedInLookup(kbts_font *Font, int Gpos, kbts_un LookupIndex, kbts_u32 Id) { kbts_u32 Result = 1; - if(Font->GlyphLookupMatrix && (Id < Font->GlyphCount)) + kbts_u32 GlyphCount = Font->Blob->GlyphCount; + if(Font->Blob->GlyphLookupMatrixOffsetFromStartOfFile && (Id < GlyphCount)) { - kbts_un FlatLookupIndex = (Gpos ? Font->GposLookupIndexOffset : 0) + LookupIndex; - kbts_un FlatIndex = FlatLookupIndex * Font->Maxp->GlyphCount + Id; + kbts_u32 *GlyphLookupMatrix = KBTS__POINTER_OFFSET(kbts_u32, Font->Blob, Font->Blob->GlyphLookupMatrixOffsetFromStartOfFile); + + kbts_un FlatLookupIndex = (Gpos ? Font->Blob->GposLookupIndexOffset : 0) + LookupIndex; + kbts_un FlatIndex = FlatLookupIndex * Font->Blob->GlyphCount + Id; kbts_un WordIndex = FlatIndex / 32; kbts_un BitIndex = FlatIndex % 32; - Result = Font->GlyphLookupMatrix[WordIndex] & (1 << BitIndex); + Result = GlyphLookupMatrix[WordIndex] & (1 << BitIndex); } return Result; } -static int kbts_GlyphPassesLookupFilter(kbts_glyph *Glyph, kbts_unpacked_lookup *Lookup) +static int kbts__GlyphPassesLookupFilter(kbts_glyph *Glyph, kbts__unpacked_lookup *Lookup) { int Result = 1; kbts_u16 Class = Glyph->Classes.Class; @@ -15272,9 +18017,9 @@ static int kbts_GlyphPassesLookupFilter(kbts_glyph *Glyph, kbts_unpacked_lookup Result = 0; } - if(Result && (Class == KBTS_GLYPH_CLASS_MARK)) + if(Result && (Class == KBTS__GLYPH_CLASS_MARK)) { - if(Lookup->Flags & KBTS_LOOKUP_FLAG_MARK_ATTACHMENT_CLASS_FILTER) + if(Lookup->Flags & KBTS__LOOKUP_FLAG_MARK_ATTACHMENT_CLASS_FILTER) { kbts_u32 DesiredMarkAttachmentClass = Lookup->Flags >> 8; @@ -15287,7 +18032,7 @@ static int kbts_GlyphPassesLookupFilter(kbts_glyph *Glyph, kbts_unpacked_lookup if(Result && Lookup->MarkFilteringSet) { // @Speed: We may want to save the result of the last mark filtering test on the glyph itself. - kbts_cover_glyph_result Cover = kbts_CoverGlyph(Lookup->MarkFilteringSet, Glyph->Id); + kbts__cover_glyph_result Cover = kbts__CoverGlyph(Lookup->MarkFilteringSet, Glyph->Id); if(!Cover.Valid) { Result = 0; @@ -15298,108 +18043,131 @@ static int kbts_GlyphPassesLookupFilter(kbts_glyph *Glyph, kbts_unpacked_lookup return Result; } -static int kbts_SkipGlyph(kbts_glyph *Glyph, kbts_unpacked_lookup *Lookup, kbts_skip_flags SkipFlags, kbts_u32 SkipUnicodeFlags) +static int kbts__SkipGlyph(kbts_glyph *Glyph, kbts__unpacked_lookup *Lookup, kbts__skip_flags SkipFlags, kbts_u32 SkipUnicodeFlags) { int Result = (Glyph->UnicodeFlags & SkipUnicodeFlags) || - ((SkipFlags & KBTS_SKIP_FLAG_ZWNJ) && (Glyph->Codepoint == 0x200C)) || - ((SkipFlags & KBTS_SKIP_FLAG_ZWJ) && (Glyph->Codepoint == 0x200D)) || - !kbts_GlyphPassesLookupFilter(Glyph, Lookup); + ((SkipFlags & KBTS__SKIP_FLAG_ZWNJ) && (Glyph->Codepoint == 0x200C)) || + ((SkipFlags & KBTS__SKIP_FLAG_ZWJ) && (Glyph->Codepoint == 0x200D)) || + !kbts__GlyphPassesLookupFilter(Glyph, Lookup); return Result; } -static int kbts_GlyphsIncludedInLookupSubtable(kbts_font *Font, int Gpos, kbts_unpacked_lookup *Lookup, kbts_un LookupIndex, kbts_un SubtableIndex, kbts_glyph_array *Array, kbts_un CurrentGlyphIndex, kbts_skip_flags SkipFlags, kbts_unicode_flags SkipUnicodeFlags) +static int kbts__GlyphIsValid(kbts_glyph_storage *Storage, kbts_glyph *Glyph) { - if(Font->GlyphLookupSubtableMatrix) + int Result = Glyph != &Storage->GlyphSentinel; + return Result; +} + +typedef struct kbts__matrix_index +{ + kbts_un WordIndex; + kbts_un BitIndex; +} kbts__matrix_index; + +static kbts__matrix_index kbts__GlyphLookupMatrixIndex(kbts_un LookupIndex, kbts_un GlyphIndex, kbts_un GlyphCount) +{ + kbts_un FlatIndex = LookupIndex * GlyphCount + GlyphIndex; + + kbts__matrix_index Result = KBTS__ZERO; + Result.WordIndex = FlatIndex / 32; + Result.BitIndex = FlatIndex % 32; + + return Result; +} + +static kbts__matrix_index kbts__GlyphLookupSubtableMatrixIndex(kbts_un SubtableIndex, kbts_un SubtableCount, kbts_un GlyphIndex) +{ + // Since we try many subtables in a row against the same glyphs, the rows are glyph-wise and the columns subtable-wise. + kbts_un FlatIndex = GlyphIndex * SubtableCount + SubtableIndex; + + kbts__matrix_index Result = KBTS__ZERO; + Result.WordIndex = FlatIndex / 32; + Result.BitIndex = FlatIndex % 32; + return Result; +} + +static int kbts__GlyphsIncludedInLookupSubtable(kbts_glyph_storage *Storage, kbts_font *Font, int Gpos, kbts__unpacked_lookup *Lookup, kbts_un LookupIndex, kbts_un SubtableIndex, kbts_glyph *AtGlyph, kbts__skip_flags SkipFlags, kbts_unicode_flags SkipUnicodeFlags) +{ + if(Font->Blob->GlyphLookupSubtableMatrixOffsetFromStartOfFile) { - kbts_un FlatLookupIndex = (Gpos ? Font->GposLookupIndexOffset : 0) + LookupIndex; - kbts_un FlatSubtableIndex = Font->LookupSubtableIndexOffsets[FlatLookupIndex] + SubtableIndex; - kbts_un MatrixRowOffset = FlatSubtableIndex * Font->Maxp->GlyphCount; - kbts_lookup_subtable_info *Info = &Font->SubtableInfos[FlatSubtableIndex]; + kbts_u32 *GlyphLookupSubtableMatrix = KBTS__POINTER_OFFSET(kbts_u32, Font->Blob, Font->Blob->GlyphLookupSubtableMatrixOffsetFromStartOfFile); + kbts_u32 *LookupSubtableIndexOffsets = KBTS__POINTER_OFFSET(kbts_u32, Font->Blob, Font->Blob->LookupSubtableIndexOffsetsOffsetFromStartOfFile); + kbts_lookup_subtable_info *SubtableInfos = KBTS__POINTER_OFFSET(kbts_lookup_subtable_info, Font->Blob, Font->Blob->SubtableInfosOffsetFromStartOfFile); + kbts_un GlyphCount = Font->Blob->GlyphCount; + kbts_un SubtableCount = Font->Blob->LookupSubtableCount; + + kbts_un FlatLookupIndex = (Gpos ? Font->Blob->GposLookupIndexOffset : 0) + LookupIndex; + kbts_un FlatSubtableIndex = LookupSubtableIndexOffsets[FlatLookupIndex] + SubtableIndex; + kbts_lookup_subtable_info *Info = &SubtableInfos[FlatSubtableIndex]; kbts_un MinimumBacktrack = (Info->MinimumBacktrackPlusOne) ? Info->MinimumBacktrackPlusOne - 1 : 0; kbts_un MinimumFollowup = (Info->MinimumFollowupPlusOne) ? Info->MinimumFollowupPlusOne - 1 : 0; - kbts_un GlyphCount = Font->GlyphCount; - - if((MinimumBacktrack <= CurrentGlyphIndex) && (MinimumFollowup <= (Array->Count - CurrentGlyphIndex))) - { - { // Check the current glyph. - kbts_un Id = Array->Glyphs[CurrentGlyphIndex].Id; - kbts_un FlatIndex = MatrixRowOffset + Id; - kbts_un WordIndex = FlatIndex / 32; - kbts_un BitIndex = FlatIndex % 32; - if(Id >= GlyphCount) - { - return 1; - } - else if(!(Font->GlyphLookupSubtableMatrix[WordIndex] & (1 << BitIndex))) - { - return 0; - } - } + { // Check the current glyph. + kbts_un Id = AtGlyph->Id; + kbts__matrix_index MatrixIndex = kbts__GlyphLookupSubtableMatrixIndex(FlatSubtableIndex, SubtableCount, Id); + if(Id >= GlyphCount) { - kbts_un BacktrackCounter = 0; - kbts_glyph *BacktrackGlyph = &Array->Glyphs[CurrentGlyphIndex - 1]; - while((BacktrackGlyph >= Array->Glyphs) && (BacktrackCounter < MinimumBacktrack)) - { - kbts_un FlatIndex = MatrixRowOffset + BacktrackGlyph->Id; - kbts_un WordIndex = FlatIndex / 32; - kbts_un BitIndex = FlatIndex % 32; - if(BacktrackGlyph->Id >= GlyphCount) - { - return 1; - } - else if(Font->GlyphLookupSubtableMatrix[WordIndex] & (1 << BitIndex)) - { - BacktrackCounter += 1; - } - else if(!kbts_SkipGlyph(BacktrackGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) - { - return 0; - } - - BacktrackGlyph -= 1; - } - - if(BacktrackCounter < MinimumBacktrack) - { - return 0; - } + return 1; } - + else if(!(GlyphLookupSubtableMatrix[MatrixIndex.WordIndex] & (1 << MatrixIndex.BitIndex))) { - kbts_un LookaheadCounter = 0; - kbts_glyph *LookaheadGlyph = &Array->Glyphs[CurrentGlyphIndex + 1]; - kbts_glyph *OnePastLastGlyph = Array->Glyphs + Array->Count; - while((LookaheadGlyph < OnePastLastGlyph) && (LookaheadCounter < MinimumFollowup)) - { - kbts_un FlatIndex = MatrixRowOffset + LookaheadGlyph->Id; - kbts_un WordIndex = FlatIndex / 32; - kbts_un BitIndex = FlatIndex % 32; - if(LookaheadGlyph->Id >= GlyphCount) - { - return 1; - } - else if(Font->GlyphLookupSubtableMatrix[WordIndex] & (1 << BitIndex)) - { - LookaheadCounter += 1; - } - else if(!kbts_SkipGlyph(LookaheadGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) - { - return 0; - } - - LookaheadGlyph += 1; - } - - if(LookaheadCounter < MinimumFollowup) - { - return 0; - } + return 0; } } - else + { - return 0; + kbts_un BacktrackCounter = 0; + kbts_glyph *BacktrackGlyph = AtGlyph->Prev; + while(kbts__GlyphIsValid(Storage, BacktrackGlyph) && + (BacktrackCounter < MinimumBacktrack)) + { + kbts__matrix_index MatrixIndex = kbts__GlyphLookupSubtableMatrixIndex(FlatSubtableIndex, SubtableCount, BacktrackGlyph->Id); + + if((BacktrackGlyph->Id >= GlyphCount) || + kbts__SkipGlyph(BacktrackGlyph, Lookup, SkipFlags, SkipUnicodeFlags) || + GlyphLookupSubtableMatrix[MatrixIndex.WordIndex] & (1 << MatrixIndex.BitIndex)) + { + BacktrackCounter += 1; + } + else + { + return 0; + } + + BacktrackGlyph = BacktrackGlyph->Prev; + } + + if(BacktrackCounter < MinimumBacktrack) + { + return 0; + } + } + + { + kbts_un LookaheadCounter = 0; + kbts_glyph *LookaheadGlyph = AtGlyph->Next; + while(kbts__GlyphIsValid(Storage, LookaheadGlyph) && (LookaheadCounter < MinimumFollowup)) + { + kbts__matrix_index MatrixIndex = kbts__GlyphLookupSubtableMatrixIndex(FlatSubtableIndex, SubtableCount, LookaheadGlyph->Id); + + if((LookaheadGlyph->Id >= GlyphCount) || + kbts__SkipGlyph(LookaheadGlyph, Lookup, SkipFlags, SkipUnicodeFlags) || + GlyphLookupSubtableMatrix[MatrixIndex.WordIndex] & (1 << MatrixIndex.BitIndex)) + { + LookaheadCounter += 1; + } + else + { + return 0; + } + + LookaheadGlyph = LookaheadGlyph->Next; + } + + if(LookaheadCounter < MinimumFollowup) + { + return 0; + } } } @@ -15407,23 +18175,23 @@ static int kbts_GlyphsIncludedInLookupSubtable(kbts_font *Font, int Gpos, kbts_u } # ifdef KBTS_DUMP -static void kbts_DumpCoverage(kbts_coverage *Coverage) +static void kbts__DumpCoverage(kbts__coverage *Coverage) { KBTS_DUMPF("["); if(Coverage->Format == 1) { - kbts_u16 *GlyphIds = KBTS_POINTER_AFTER(kbts_u16, Coverage); - KBTS_FOR(GlyphIndex, 0, Coverage->Count) + kbts_u16 *GlyphIds = KBTS__POINTER_AFTER(kbts_u16, Coverage); + KBTS__FOR(GlyphIndex, 0, Coverage->Count) { KBTS_DUMPF("%x,", GlyphIds[GlyphIndex]); } } else if(Coverage->Format == 2) { - kbts_range_record *Ranges = KBTS_POINTER_AFTER(kbts_range_record, Coverage); - KBTS_FOR(RangeIndex, 0, Coverage->Count) + kbts__range_record *Ranges = KBTS__POINTER_AFTER(kbts__range_record, Coverage); + KBTS__FOR(RangeIndex, 0, Coverage->Count) { - kbts_range_record *Range = &Ranges[RangeIndex]; + kbts__range_record *Range = &Ranges[RangeIndex]; KBTS_DUMPF("%x..%x @ %u,", Range->StartGlyphId, Range->EndGlyphId, Range->StartCoverageIndex); } } @@ -15431,81 +18199,81 @@ static void kbts_DumpCoverage(kbts_coverage *Coverage) } # endif -static void kbts_ByteSwapChainedSequenceContextSubtable(kbts_byteswap_context *Context, kbts_u16 *Base) +static void kbts__ByteSwapChainedSequenceContextSubtable(kbts__byteswap_context *Context, kbts_u16 *Base) { if(Base[0] == 1) { - kbts_chained_sequence_context_1 *Subst = (kbts_chained_sequence_context_1 *)Base; - Subst->ChainedSequenceRuleSetCount = kbts_ByteSwap16(Subst->ChainedSequenceRuleSetCount); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Subst), Subst->ChainedSequenceRuleSetCount, Context); + kbts__chained_sequence_context_1 *Subst = (kbts__chained_sequence_context_1 *)Base; + Subst->ChainedSequenceRuleSetCount = kbts__ByteSwap16(Subst->ChainedSequenceRuleSetCount); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Subst), Subst->ChainedSequenceRuleSetCount, Context); - KBTS_FOR(SetIndex, 0, Subst->ChainedSequenceRuleSetCount) + KBTS__FOR(SetIndex, 0, Subst->ChainedSequenceRuleSetCount) { - kbts_ByteSwapChainedSequenceRuleSet(Context, kbts_GetChainedSequenceRuleSet(Subst, SetIndex)); + kbts__ByteSwapChainedSequenceRuleSet(Context, kbts__GetChainedSequenceRuleSet(Subst, SetIndex)); } } else if(Base[0] == 2) { - kbts_chained_sequence_context_2 *Subst = (kbts_chained_sequence_context_2 *)Base; - kbts_ByteSwapArray16Context(&Subst->BacktrackClassDefOffset, 4, Context); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Subst), Subst->ChainedClassSequenceRuleSetCount, Context); + kbts__chained_sequence_context_2 *Subst = (kbts__chained_sequence_context_2 *)Base; + kbts__ByteSwapArray16Context(&Subst->BacktrackClassDefOffset, 4, Context); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Subst), Subst->ChainedClassSequenceRuleSetCount, Context); - kbts_u16 *BacktrackClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->BacktrackClassDefOffset); - kbts_ByteSwapClassDefinition(Context, BacktrackClassDefinition); + kbts_u16 *BacktrackClassDefinition = KBTS__POINTER_OFFSET(kbts_u16, Subst, Subst->BacktrackClassDefOffset); + kbts__ByteSwapClassDefinition(Context, BacktrackClassDefinition); - kbts_u16 *InputClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->InputClassDefOffset); - kbts_ByteSwapClassDefinition(Context, InputClassDefinition); + kbts_u16 *InputClassDefinition = KBTS__POINTER_OFFSET(kbts_u16, Subst, Subst->InputClassDefOffset); + kbts__ByteSwapClassDefinition(Context, InputClassDefinition); - kbts_u16 *LookaheadClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->LookaheadClassDefOffset); - kbts_ByteSwapClassDefinition(Context, LookaheadClassDefinition); + kbts_u16 *LookaheadClassDefinition = KBTS__POINTER_OFFSET(kbts_u16, Subst, Subst->LookaheadClassDefOffset); + kbts__ByteSwapClassDefinition(Context, LookaheadClassDefinition); #ifdef KBTS_DUMP KBTS_DUMPF("Backtrack classes:\n"); - // kbts_DumpClassDefinition(BacktrackClassDefinition); + // kbts__DumpClassDefinition(BacktrackClassDefinition); KBTS_DUMPF("Input classes:\n"); - // kbts_DumpClassDefinition(InputClassDefinition); + // kbts__DumpClassDefinition(InputClassDefinition); KBTS_DUMPF("Lookahead classes:\n"); - // kbts_DumpClassDefinition(LookaheadClassDefinition); + // kbts__DumpClassDefinition(LookaheadClassDefinition); #endif - KBTS_FOR(SetIndex, 0, Subst->ChainedClassSequenceRuleSetCount) + KBTS__FOR(SetIndex, 0, Subst->ChainedClassSequenceRuleSetCount) { - kbts_chained_sequence_rule_set *Set = kbts_GetChainedClassSequenceRuleSet(Subst, SetIndex); - kbts_ByteSwapChainedSequenceRuleSet(Context, Set); + kbts__chained_sequence_rule_set *Set = kbts__GetChainedClassSequenceRuleSet(Subst, SetIndex); + kbts__ByteSwapChainedSequenceRuleSet(Context, Set); #ifdef KBTS_DUMP if(Set) { - KBTS_FOR(RuleIndex, 0, Set->Count) + KBTS__FOR(RuleIndex, 0, Set->Count) { - kbts_chained_sequence_rule *Rule = kbts_GetChainedClassSequenceRule(Set, RuleIndex); - kbts_unpacked_chained_sequence_rule Unpacked = kbts_UnpackChainedSequenceRule(Rule, 0); + kbts__chained_sequence_rule *Rule = kbts__GetChainedClassSequenceRule(Set, RuleIndex); + kbts__unpacked_chained_sequence_rule Unpacked = kbts__UnpackChainedSequenceRule(Rule, 0); KBTS_DUMPF("Backtrack: ["); - KBTS_FOR(BacktrackIndex, 0, Unpacked.BacktrackCount) + KBTS__FOR(BacktrackIndex, 0, Unpacked.BacktrackCount) { if(BacktrackIndex) KBTS_DUMPF(", "); KBTS_DUMPF("%u", Unpacked.Backtrack[BacktrackIndex]); } KBTS_DUMPF("]\n" "Input: ["); - KBTS_FOR(InputIndex, 1, Unpacked.InputCount) + KBTS__FOR(InputIndex, 1, Unpacked.InputCount) { if(InputIndex) KBTS_DUMPF(", "); KBTS_DUMPF("%u", Unpacked.Input[InputIndex - 1]); } KBTS_DUMPF("]\n" "Lookahead: ["); - KBTS_FOR(LookaheadIndex, 0, Unpacked.LookaheadCount) + KBTS__FOR(LookaheadIndex, 0, Unpacked.LookaheadCount) { if(LookaheadIndex) KBTS_DUMPF(", "); KBTS_DUMPF("%u", Unpacked.Lookahead[LookaheadIndex]); } KBTS_DUMPF("]\n" "Records: ["); - KBTS_FOR(RecordIndex, 0, Unpacked.RecordCount) + KBTS__FOR(RecordIndex, 0, Unpacked.RecordCount) { - kbts_sequence_lookup_record *Record = &Unpacked.Records[RecordIndex]; + kbts__sequence_lookup_record *Record = &Unpacked.Records[RecordIndex]; if(RecordIndex) KBTS_DUMPF(", "); KBTS_DUMPF("%u@%u", Record->LookupListIndex, Record->SequenceIndex); } @@ -15517,53 +18285,53 @@ static void kbts_ByteSwapChainedSequenceContextSubtable(kbts_byteswap_context *C } else if(Base[0] == 3) { - kbts_chained_sequence_context_3 *Subst = (kbts_chained_sequence_context_3 *)Base; - kbts_unpacked_chained_sequence_context_3 Unpacked = kbts_UnpackChainedSequenceContext3(Subst, 1); + kbts__chained_sequence_context_3 *Subst = (kbts__chained_sequence_context_3 *)Base; + kbts__unpacked_chained_sequence_context_3 Unpacked = kbts__UnpackChainedSequenceContext3(Subst, 1); kbts_un U16Count = Unpacked.BacktrackCount + Unpacked.InputCount + Unpacked.LookaheadCount + Unpacked.RecordCount * 2 + 4; - kbts_ByteSwapArray16Context(&Subst->BacktrackGlyphCount, U16Count, Context); + kbts__ByteSwapArray16Context(&Subst->BacktrackGlyphCount, U16Count, Context); - KBTS_FOR(BacktrackCoverageIndex, 0, Unpacked.BacktrackCount) + KBTS__FOR(BacktrackCoverageIndex, 0, Unpacked.BacktrackCount) { - kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.BacktrackCoverageOffsets[BacktrackCoverageIndex]); + kbts__coverage *Coverage = KBTS__POINTER_OFFSET(kbts__coverage, Subst, Unpacked.BacktrackCoverageOffsets[BacktrackCoverageIndex]); - kbts_ByteSwapCoverage(Context, Coverage); + kbts__ByteSwapCoverage(Context, Coverage); } - KBTS_FOR(InputCoverageIndex, 0, Unpacked.InputCount) + KBTS__FOR(InputCoverageIndex, 0, Unpacked.InputCount) { - kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.InputCoverageOffsets[InputCoverageIndex]); + kbts__coverage *Coverage = KBTS__POINTER_OFFSET(kbts__coverage, Subst, Unpacked.InputCoverageOffsets[InputCoverageIndex]); - kbts_ByteSwapCoverage(Context, Coverage); + kbts__ByteSwapCoverage(Context, Coverage); } - KBTS_FOR(LookaheadCoverageIndex, 0, Unpacked.LookaheadCount) + KBTS__FOR(LookaheadCoverageIndex, 0, Unpacked.LookaheadCount) { - kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.LookaheadCoverageOffsets[LookaheadCoverageIndex]); + kbts__coverage *Coverage = KBTS__POINTER_OFFSET(kbts__coverage, Subst, Unpacked.LookaheadCoverageOffsets[LookaheadCoverageIndex]); - kbts_ByteSwapCoverage(Context, Coverage); + kbts__ByteSwapCoverage(Context, Coverage); } # ifdef KBTS_DUMP KBTS_DUMPF(" Backtrack: "); - KBTS_FOR(BacktrackCoverageIndex, 0, Unpacked.BacktrackCount) + KBTS__FOR(BacktrackCoverageIndex, 0, Unpacked.BacktrackCount) { - kbts_DumpCoverage(KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.BacktrackCoverageOffsets[BacktrackCoverageIndex])); + kbts__DumpCoverage(KBTS__POINTER_OFFSET(kbts__coverage, Subst, Unpacked.BacktrackCoverageOffsets[BacktrackCoverageIndex])); } KBTS_DUMPF("\n Input: "); - KBTS_FOR(InputCoverageIndex, 0, Unpacked.InputCount) + KBTS__FOR(InputCoverageIndex, 0, Unpacked.InputCount) { - kbts_DumpCoverage(KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.InputCoverageOffsets[InputCoverageIndex])); + kbts__DumpCoverage(KBTS__POINTER_OFFSET(kbts__coverage, Subst, Unpacked.InputCoverageOffsets[InputCoverageIndex])); } KBTS_DUMPF("\n Lookahead: "); - KBTS_FOR(LookaheadCoverageIndex, 0, Unpacked.LookaheadCount) + KBTS__FOR(LookaheadCoverageIndex, 0, Unpacked.LookaheadCount) { - kbts_DumpCoverage(KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.LookaheadCoverageOffsets[LookaheadCoverageIndex])); + kbts__DumpCoverage(KBTS__POINTER_OFFSET(kbts__coverage, Subst, Unpacked.LookaheadCoverageOffsets[LookaheadCoverageIndex])); } KBTS_DUMPF("\n Lookups: ["); - KBTS_FOR(RecordIndex, 0, Unpacked.RecordCount) + KBTS__FOR(RecordIndex, 0, Unpacked.RecordCount) { - kbts_sequence_lookup_record *Record = &Unpacked.Records[RecordIndex]; + kbts__sequence_lookup_record *Record = &Unpacked.Records[RecordIndex]; KBTS_DUMPF("%u@%u,", Record->LookupListIndex, Record->SequenceIndex); } @@ -15572,58 +18340,58 @@ static void kbts_ByteSwapChainedSequenceContextSubtable(kbts_byteswap_context *C } } -static void kbts_ByteSwapGsubLookupSubtable(kbts_byteswap_context *Context, kbts_u16 LookupType, kbts_u16 *Base) +static void kbts__ByteSwapGsubLookupSubtable(kbts__byteswap_context *Context, kbts_u16 LookupType, kbts_u16 *Base) { - int Swap = !kbts_AlreadyVisited(Context, Base); + int Swap = !kbts__AlreadyVisited(Context, Base); while(Swap && (LookupType == 7)) { - kbts_extension *Subst = (kbts_extension *)Base; - Subst->Format = kbts_ByteSwap16(Subst->Format); - Subst->LookupType = kbts_ByteSwap16(Subst->LookupType); - Subst->Offset = kbts_ByteSwap32(Subst->Offset); + kbts__extension *Subst = (kbts__extension *)Base; + Subst->Format = kbts__ByteSwap16(Subst->Format); + Subst->LookupType = kbts__ByteSwap16(Subst->LookupType); + Subst->Offset = kbts__ByteSwap32(Subst->Offset); KBTS_DUMPF(" Type 7.1\n" " Offset %zu\n" " -> %zu\n", (char *)Base - Context->FileBase, (char *)Subst + Subst->Offset - Context->FileBase); - Base = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->Offset); + Base = KBTS__POINTER_OFFSET(kbts_u16, Subst, Subst->Offset); LookupType = Subst->LookupType; - Swap = !kbts_AlreadyVisited(Context, Base); + Swap = !kbts__AlreadyVisited(Context, Base); } if(Swap) { - *Base = kbts_ByteSwap16(*Base); + *Base = kbts__ByteSwap16(*Base); KBTS_DUMPF(" Type %u.%u\n" " Offset %zu\n", LookupType, *Base, (char *)Base - Context->FileBase); - if(kbts_GsubLookupBeginsWithCoverage(LookupType, Base[0])) + if(kbts__GsubLookupBeginsWithCoverage(LookupType, Base[0])) { - Base[1] = kbts_ByteSwap16(Base[1]); - kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Base, Base[1]); + Base[1] = kbts__ByteSwap16(Base[1]); + kbts__coverage *Coverage = KBTS__POINTER_OFFSET(kbts__coverage, Base, Base[1]); - kbts_ByteSwapCoverage(Context, Coverage); + kbts__ByteSwapCoverage(Context, Coverage); # ifdef KBTS_DUMP KBTS_DUMPF(" Coverage %u\n", Coverage->Format); if(Coverage->Format == 1) { - kbts_u16 *GlyphIds = KBTS_POINTER_AFTER(kbts_u16, Coverage); - KBTS_FOR(GlyphIndex, 0, Coverage->Count) + kbts_u16 *GlyphIds = KBTS__POINTER_AFTER(kbts_u16, Coverage); + KBTS__FOR(GlyphIndex, 0, Coverage->Count) { KBTS_DUMPF(" %x\n", GlyphIds[GlyphIndex]); } } else if(Coverage->Format == 2) { - kbts_range_record *Ranges = KBTS_POINTER_AFTER(kbts_range_record, Coverage); - KBTS_FOR(RangeIndex, 0, Coverage->Count) + kbts__range_record *Ranges = KBTS__POINTER_AFTER(kbts__range_record, Coverage); + KBTS__FOR(RangeIndex, 0, Coverage->Count) { - kbts_range_record Range = Ranges[RangeIndex]; + kbts__range_record Range = Ranges[RangeIndex]; KBTS_DUMPF(" %x..%x@%u..%u\n", Range.StartGlyphId, Range.EndGlyphId, Range.StartCoverageIndex, Range.StartCoverageIndex + (Range.EndGlyphId - Range.StartGlyphId)); } } @@ -15634,8 +18402,8 @@ static void kbts_ByteSwapGsubLookupSubtable(kbts_byteswap_context *Context, kbts { case 1: { - kbts_single_substitution *Subst = (kbts_single_substitution *)Base; - Subst->DeltaOrCount.GlyphCount = kbts_ByteSwap16(Subst->DeltaOrCount.GlyphCount); + kbts__single_substitution *Subst = (kbts__single_substitution *)Base; + Subst->DeltaOrCount.GlyphCount = kbts__ByteSwap16(Subst->DeltaOrCount.GlyphCount); # ifdef KBTS_DUMP if(Subst->Format == 1) @@ -15646,12 +18414,12 @@ static void kbts_ByteSwapGsubLookupSubtable(kbts_byteswap_context *Context, kbts if(Subst->Format == 2) { - kbts_u16 *GlyphIds = KBTS_POINTER_AFTER(kbts_u16, Subst); - kbts_ByteSwapArray16Context(GlyphIds, Subst->DeltaOrCount.GlyphCount, Context); + kbts_u16 *GlyphIds = KBTS__POINTER_AFTER(kbts_u16, Subst); + kbts__ByteSwapArray16Context(GlyphIds, Subst->DeltaOrCount.GlyphCount, Context); #ifdef KBTS_DUMP KBTS_DUMPF(" ["); - KBTS_FOR(IdIndex, 0, Subst->DeltaOrCount.GlyphCount) + KBTS__FOR(IdIndex, 0, Subst->DeltaOrCount.GlyphCount) { if(IdIndex) KBTS_DUMPF(" "); KBTS_DUMPF("%x", GlyphIds[IdIndex]); @@ -15664,25 +18432,25 @@ static void kbts_ByteSwapGsubLookupSubtable(kbts_byteswap_context *Context, kbts case 2: { - kbts_multiple_substitution *Subst = (kbts_multiple_substitution *)Base; - Subst->SequenceCount = kbts_ByteSwap16(Subst->SequenceCount); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Subst), Subst->SequenceCount, Context); + kbts__multiple_substitution *Subst = (kbts__multiple_substitution *)Base; + Subst->SequenceCount = kbts__ByteSwap16(Subst->SequenceCount); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Subst), Subst->SequenceCount, Context); - KBTS_FOR(SequenceIndex, 0, Subst->SequenceCount) + KBTS__FOR(SequenceIndex, 0, Subst->SequenceCount) { - kbts_sequence *Sequence = kbts_GetSequence(Subst, SequenceIndex); + kbts__sequence *Sequence = kbts__GetSequence(Subst, SequenceIndex); - if(!kbts_AlreadyVisited(Context, Sequence)) + if(!kbts__AlreadyVisited(Context, Sequence)) { - Sequence->GlyphCount = kbts_ByteSwap16(Sequence->GlyphCount); + Sequence->GlyphCount = kbts__ByteSwap16(Sequence->GlyphCount); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Sequence), Sequence->GlyphCount, Context); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Sequence), Sequence->GlyphCount, Context); } #ifdef KBTS_DUMP KBTS_DUMPF(" ["); - kbts_u16 *SequenceGlyphIds = KBTS_POINTER_AFTER(kbts_u16, Sequence); - KBTS_FOR(SequenceGlyphIndex, 0, Sequence->GlyphCount) + kbts_u16 *SequenceGlyphIds = KBTS__POINTER_AFTER(kbts_u16, Sequence); + KBTS__FOR(SequenceGlyphIndex, 0, Sequence->GlyphCount) { if(SequenceGlyphIndex) KBTS_DUMPF(" "); KBTS_DUMPF("%x", SequenceGlyphIds[SequenceGlyphIndex]); @@ -15695,25 +18463,25 @@ static void kbts_ByteSwapGsubLookupSubtable(kbts_byteswap_context *Context, kbts case 3: { - kbts_alternate_substitution *Subst = (kbts_alternate_substitution *)Base; - Subst->AlternateSetCount = kbts_ByteSwap16(Subst->AlternateSetCount); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Subst), Subst->AlternateSetCount, Context); + kbts__alternate_substitution *Subst = (kbts__alternate_substitution *)Base; + Subst->AlternateSetCount = kbts__ByteSwap16(Subst->AlternateSetCount); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Subst), Subst->AlternateSetCount, Context); - KBTS_FOR(SetIndex, 0, Subst->AlternateSetCount) + KBTS__FOR(SetIndex, 0, Subst->AlternateSetCount) { - kbts_alternate_set *Set = kbts_GetAlternateSet(Subst, SetIndex); + kbts__alternate_set *Set = kbts__GetAlternateSet(Subst, SetIndex); - if(!kbts_AlreadyVisited(Context, Set)) + if(!kbts__AlreadyVisited(Context, Set)) { - Set->GlyphCount = kbts_ByteSwap16(Set->GlyphCount); + Set->GlyphCount = kbts__ByteSwap16(Set->GlyphCount); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Set), Set->GlyphCount, Context); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Set), Set->GlyphCount, Context); } #ifdef KBTS_DUMP KBTS_DUMPF(" ["); - kbts_u16 *SetGlyphIds = KBTS_POINTER_AFTER(kbts_u16, Set); - KBTS_FOR(SetGlyphIndex, 0, Set->GlyphCount) + kbts_u16 *SetGlyphIds = KBTS__POINTER_AFTER(kbts_u16, Set); + KBTS__FOR(SetGlyphIndex, 0, Set->GlyphCount) { if(SetGlyphIndex) KBTS_DUMPF(" "); KBTS_DUMPF("%x", SetGlyphIds[SetGlyphIndex]); @@ -15726,32 +18494,32 @@ static void kbts_ByteSwapGsubLookupSubtable(kbts_byteswap_context *Context, kbts case 4: { - kbts_ligature_substitution *Subst = (kbts_ligature_substitution *)Base; - Subst->LigatureSetCount = kbts_ByteSwap16(Subst->LigatureSetCount); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Subst), Subst->LigatureSetCount, Context); + kbts__ligature_substitution *Subst = (kbts__ligature_substitution *)Base; + Subst->LigatureSetCount = kbts__ByteSwap16(Subst->LigatureSetCount); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Subst), Subst->LigatureSetCount, Context); - KBTS_FOR(SetIndex, 0, Subst->LigatureSetCount) + KBTS__FOR(SetIndex, 0, Subst->LigatureSetCount) { - kbts_ligature_set *Set = kbts_GetLigatureSet(Subst, SetIndex); + kbts__ligature_set *Set = kbts__GetLigatureSet(Subst, SetIndex); - if(!kbts_AlreadyVisited(Context, Set)) + if(!kbts__AlreadyVisited(Context, Set)) { - Set->Count = kbts_ByteSwap16(Set->Count); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Set), Set->Count, Context); + Set->Count = kbts__ByteSwap16(Set->Count); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Set), Set->Count, Context); - KBTS_FOR(LigatureIndex, 0, Set->Count) + KBTS__FOR(LigatureIndex, 0, Set->Count) { - kbts_ligature *Ligature = kbts_GetLigature(Set, LigatureIndex); + kbts__ligature *Ligature = kbts__GetLigature(Set, LigatureIndex); - if(!kbts_AlreadyVisited(Context, Ligature)) + if(!kbts__AlreadyVisited(Context, Ligature)) { - kbts_ByteSwapArray16Context(&Ligature->Glyph, 2, Context); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Ligature), Ligature->ComponentCount - 1, Context); + kbts__ByteSwapArray16Context(&Ligature->Glyph, 2, Context); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Ligature), Ligature->ComponentCount - 1, Context); # ifdef KBTS_DUMP KBTS_DUMPF("ligature: ["); - kbts_u16 *ComponentIds = KBTS_POINTER_AFTER(kbts_u16, Ligature); - KBTS_FOR(ComponentIndex, 1, Ligature->ComponentCount) + kbts_u16 *ComponentIds = KBTS__POINTER_AFTER(kbts_u16, Ligature); + KBTS__FOR(ComponentIndex, 1, Ligature->ComponentCount) { KBTS_DUMPF("%x,", ComponentIds[ComponentIndex - 1]); } @@ -15770,31 +18538,31 @@ static void kbts_ByteSwapGsubLookupSubtable(kbts_byteswap_context *Context, kbts case 5: { - kbts_ByteSwapSequenceContextSubtable(Context, Base); + kbts__ByteSwapSequenceContextSubtable(Context, Base); } break; case 6: { - kbts_ByteSwapChainedSequenceContextSubtable(Context, Base); + kbts__ByteSwapChainedSequenceContextSubtable(Context, Base); } break; case 8: { - kbts_reverse_chain_substitution *Subst = (kbts_reverse_chain_substitution *)Base; - kbts_unpacked_reverse_chain_substitution Unpacked = kbts_UnpackReverseChainSubstitution(Subst, 1); + kbts__reverse_chain_substitution *Subst = (kbts__reverse_chain_substitution *)Base; + kbts__unpacked_reverse_chain_substitution Unpacked = kbts__UnpackReverseChainSubstitution(Subst, 1); kbts_un U16Count = Unpacked.BacktrackCount + Unpacked.GlyphCount + Unpacked.LookaheadCount + 3; - kbts_ByteSwapArray16Context(&Subst->BacktrackGlyphCount, U16Count, Context); + kbts__ByteSwapArray16Context(&Subst->BacktrackGlyphCount, U16Count, Context); - KBTS_FOR(BacktrackCoverageIndex, 0, Unpacked.BacktrackCount) + KBTS__FOR(BacktrackCoverageIndex, 0, Unpacked.BacktrackCount) { - kbts_ByteSwapCoverage(Context, KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.BacktrackCoverageOffsets[BacktrackCoverageIndex])); + kbts__ByteSwapCoverage(Context, KBTS__POINTER_OFFSET(kbts__coverage, Subst, Unpacked.BacktrackCoverageOffsets[BacktrackCoverageIndex])); } - KBTS_FOR(LookaheadCoverageIndex, 0, Unpacked.LookaheadCount) + KBTS__FOR(LookaheadCoverageIndex, 0, Unpacked.LookaheadCount) { - kbts_ByteSwapCoverage(Context, KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.LookaheadCoverageOffsets[LookaheadCoverageIndex])); + kbts__ByteSwapCoverage(Context, KBTS__POINTER_OFFSET(kbts__coverage, Subst, Unpacked.LookaheadCoverageOffsets[LookaheadCoverageIndex])); } } break; @@ -15802,43 +18570,43 @@ static void kbts_ByteSwapGsubLookupSubtable(kbts_byteswap_context *Context, kbts } } -static void kbts_ByteSwapGposLookupSubtable(kbts_byteswap_context *Context, kbts_lookup_list *LookupList, kbts_u16 LookupType, kbts_u16 *Base) +static void kbts__ByteSwapGposLookupSubtable(kbts__byteswap_context *Context, kbts_lookup_list *LookupList, kbts_u16 LookupType, kbts_u16 *Base) { - if(!kbts_AlreadyVisited(Context, Base)) + if(!kbts__AlreadyVisited(Context, Base)) { - *Base = kbts_ByteSwap16(*Base); + *Base = kbts__ByteSwap16(*Base); KBTS_DUMPF(" GPOS subtable %u.%u\n", LookupType, *Base); - if(kbts_GposLookupBeginsWithCoverage(LookupType, *Base)) + if(kbts__GposLookupBeginsWithCoverage(LookupType, *Base)) { kbts_u16 *CoverageOffset = &Base[1]; - *CoverageOffset = kbts_ByteSwap16(*CoverageOffset); + *CoverageOffset = kbts__ByteSwap16(*CoverageOffset); - kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Base, *CoverageOffset); - kbts_ByteSwapCoverage(Context, Coverage); + kbts__coverage *Coverage = KBTS__POINTER_OFFSET(kbts__coverage, Base, *CoverageOffset); + kbts__ByteSwapCoverage(Context, Coverage); } switch(LookupType) { case 1: { - kbts_single_adjustment_1 *Adjust = (kbts_single_adjustment_1 *)Base; - Adjust->ValueFormat = kbts_ByteSwap16(Adjust->ValueFormat); + kbts__single_adjustment_1 *Adjust = (kbts__single_adjustment_1 *)Base; + Adjust->ValueFormat = kbts__ByteSwap16(Adjust->ValueFormat); if(Adjust->Format == 1) { - kbts_ByteSwapValueRecord(Context, Adjust, Adjust->ValueFormat, KBTS_POINTER_AFTER(kbts_u16, Adjust)); + kbts_ByteSwapValueRecord(Context, Adjust, Adjust->ValueFormat, KBTS__POINTER_AFTER(kbts_u16, Adjust)); } else if(Adjust->Format == 2) { - kbts_single_adjustment_2 *Adjust2 = (kbts_single_adjustment_2 *)Base; - Adjust2->RecordCount = kbts_ByteSwap16(Adjust2->RecordCount); + kbts__single_adjustment_2 *Adjust2 = (kbts__single_adjustment_2 *)Base; + Adjust2->RecordCount = kbts__ByteSwap16(Adjust2->RecordCount); - kbts_u16 *At = KBTS_POINTER_AFTER(kbts_u16, Adjust2); - KBTS_FOR(RecordIndex, 0, Adjust2->RecordCount) + kbts_u16 *At = KBTS__POINTER_AFTER(kbts_u16, Adjust2); + KBTS__FOR(RecordIndex, 0, Adjust2->RecordCount) { - kbts_unpacked_value_record Unpacked = kbts_ByteSwapValueRecord(Context, Adjust2, Adjust2->ValueFormat, At); + kbts__unpacked_value_record Unpacked = kbts_ByteSwapValueRecord(Context, Adjust2, Adjust2->ValueFormat, At); At += Unpacked.Size; } @@ -15850,55 +18618,55 @@ static void kbts_ByteSwapGposLookupSubtable(kbts_byteswap_context *Context, kbts { if(*Base == 1) { - kbts_pair_adjustment_1 *Adjust = (kbts_pair_adjustment_1 *)Base; - kbts_ByteSwapArray16Context(&Adjust->ValueFormat1, 3, Context); + kbts__pair_adjustment_1 *Adjust = (kbts__pair_adjustment_1 *)Base; + kbts__ByteSwapArray16Context(&Adjust->ValueFormat1, 3, Context); - kbts_u16 *SetOffsets = KBTS_POINTER_AFTER(kbts_u16, Adjust); - kbts_ByteSwapArray16Context(SetOffsets, Adjust->SetCount, Context); + kbts_u16 *SetOffsets = KBTS__POINTER_AFTER(kbts_u16, Adjust); + kbts__ByteSwapArray16Context(SetOffsets, Adjust->SetCount, Context); - kbts_un Size1 = kbts_PopCount32(Adjust->ValueFormat1); - kbts_un Size2 = kbts_PopCount32(Adjust->ValueFormat2); + kbts_un Size1 = kbts__PopCount32(Adjust->ValueFormat1); + kbts_un Size2 = kbts__PopCount32(Adjust->ValueFormat2); kbts_un PairRecordSize = Size1 + Size2 + 1; - KBTS_FOR(SetIndex, 0, Adjust->SetCount) + KBTS__FOR(SetIndex, 0, Adjust->SetCount) { - kbts_pair_set *Set = KBTS_POINTER_OFFSET(kbts_pair_set, Adjust, SetOffsets[SetIndex]); + kbts__pair_set *Set = KBTS__POINTER_OFFSET(kbts__pair_set, Adjust, SetOffsets[SetIndex]); - if(!kbts_AlreadyVisited(Context, Set)) + if(!kbts__AlreadyVisited(Context, Set)) { - Set->Count = kbts_ByteSwap16(Set->Count); + Set->Count = kbts__ByteSwap16(Set->Count); - kbts_u16 *At = KBTS_POINTER_AFTER(kbts_u16, Set); + kbts_u16 *At = KBTS__POINTER_AFTER(kbts_u16, Set); - KBTS_FOR(RecordIndex, 0, Set->Count) + KBTS__FOR(RecordIndex, 0, Set->Count) { - kbts_pair_value_record *PairRecord = (kbts_pair_value_record *)(At + RecordIndex * PairRecordSize); + kbts__pair_value_record *PairRecord = (kbts__pair_value_record *)(At + RecordIndex * PairRecordSize); - PairRecord->SecondGlyph = kbts_ByteSwap16(PairRecord->SecondGlyph); - kbts_u16 *Record = KBTS_POINTER_AFTER(kbts_u16, PairRecord); + PairRecord->SecondGlyph = kbts__ByteSwap16(PairRecord->SecondGlyph); + kbts_u16 *Record = KBTS__POINTER_AFTER(kbts_u16, PairRecord); - kbts_unpacked_value_record Unpacked1 = kbts_ByteSwapValueRecord(Context, Record, Adjust->ValueFormat1, Record); + kbts__unpacked_value_record Unpacked1 = kbts_ByteSwapValueRecord(Context, Set, Adjust->ValueFormat1, Record); Record += Unpacked1.Size; - kbts_ByteSwapValueRecord(Context, Record, Adjust->ValueFormat2, Record); + kbts_ByteSwapValueRecord(Context, Set, Adjust->ValueFormat2, Record); } } } } else if(*Base == 2) { - kbts_pair_adjustment_2 *Adjust = (kbts_pair_adjustment_2 *)Base; - kbts_ByteSwapArray16Context(&Adjust->ValueFormat1, 6, Context); + kbts__pair_adjustment_2 *Adjust = (kbts__pair_adjustment_2 *)Base; + kbts__ByteSwapArray16Context(&Adjust->ValueFormat1, 6, Context); - kbts_ByteSwapClassDefinition(Context, KBTS_POINTER_OFFSET(kbts_u16, Adjust, Adjust->ClassDefinition1Offset)); - kbts_ByteSwapClassDefinition(Context, KBTS_POINTER_OFFSET(kbts_u16, Adjust, Adjust->ClassDefinition2Offset)); + kbts__ByteSwapClassDefinition(Context, KBTS__POINTER_OFFSET(kbts_u16, Adjust, Adjust->ClassDefinition1Offset)); + kbts__ByteSwapClassDefinition(Context, KBTS__POINTER_OFFSET(kbts_u16, Adjust, Adjust->ClassDefinition2Offset)); - kbts_u16 *Records = KBTS_POINTER_AFTER(kbts_u16, Adjust); + kbts_u16 *Records = KBTS__POINTER_AFTER(kbts_u16, Adjust); - kbts_un Size1 = kbts_PopCount32(Adjust->ValueFormat1); - kbts_un Size2 = kbts_PopCount32(Adjust->ValueFormat2); + kbts_un Size1 = kbts__PopCount32(Adjust->ValueFormat1); + kbts_un Size2 = kbts__PopCount32(Adjust->ValueFormat2); kbts_u16 *RecordPair = Records; - KBTS_FOR(RecordIndex, 0, (kbts_un)Adjust->Class1Count * (kbts_un)Adjust->Class2Count) + KBTS__FOR(RecordIndex, 0, (kbts_un)Adjust->Class1Count * (kbts_un)Adjust->Class2Count) { kbts_ByteSwapValueRecord(Context, Adjust, Adjust->ValueFormat1, RecordPair); RecordPair += Size1; @@ -15912,23 +18680,23 @@ static void kbts_ByteSwapGposLookupSubtable(kbts_byteswap_context *Context, kbts case 3: { - kbts_cursive_attachment *Adjust = (kbts_cursive_attachment *)Base; - Adjust->EntryExitCount = kbts_ByteSwap16(Adjust->EntryExitCount); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Adjust), Adjust->EntryExitCount * 2, Context); + kbts__cursive_attachment *Adjust = (kbts__cursive_attachment *)Base; + Adjust->EntryExitCount = kbts__ByteSwap16(Adjust->EntryExitCount); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, Adjust), Adjust->EntryExitCount * 2, Context); - kbts_entry_exit *EntryExits = KBTS_POINTER_AFTER(kbts_entry_exit, Adjust); - KBTS_FOR(EntryExitIndex, 0, Adjust->EntryExitCount) + kbts__entry_exit *EntryExits = KBTS__POINTER_AFTER(kbts__entry_exit, Adjust); + KBTS__FOR(EntryExitIndex, 0, Adjust->EntryExitCount) { - kbts_entry_exit *EntryExit = &EntryExits[EntryExitIndex]; + kbts__entry_exit *EntryExit = &EntryExits[EntryExitIndex]; if(EntryExit->EntryAnchorOffset) { - kbts_ByteSwapAnchor(Context, KBTS_POINTER_OFFSET(kbts_anchor, Adjust, EntryExit->EntryAnchorOffset)); + kbts__ByteSwapAnchor(Context, KBTS__POINTER_OFFSET(kbts__anchor, Adjust, EntryExit->EntryAnchorOffset)); } if(EntryExit->ExitAnchorOffset) { - kbts_ByteSwapAnchor(Context, KBTS_POINTER_OFFSET(kbts_anchor, Adjust, EntryExit->ExitAnchorOffset)); + kbts__ByteSwapAnchor(Context, KBTS__POINTER_OFFSET(kbts__anchor, Adjust, EntryExit->ExitAnchorOffset)); } } } @@ -15937,47 +18705,47 @@ static void kbts_ByteSwapGposLookupSubtable(kbts_byteswap_context *Context, kbts case 4: case 6: { - kbts_mark_to_base_attachment *Adjust = (kbts_mark_to_base_attachment *)Base; - kbts_ByteSwapArray16Context(&Adjust->BaseCoverageOffset, 4, Context); + kbts__mark_to_base_attachment *Adjust = (kbts__mark_to_base_attachment *)Base; + kbts__ByteSwapArray16Context(&Adjust->BaseCoverageOffset, 4, Context); - kbts_ByteSwapCoverage(Context, KBTS_POINTER_OFFSET(kbts_coverage, Adjust, Adjust->BaseCoverageOffset)); - kbts_ByteSwapMarkArray(Context, KBTS_POINTER_OFFSET(kbts_mark_array, Adjust, Adjust->MarkArrayOffset)); - kbts_ByteSwapBaseArray(Context, Adjust->MarkClassCount, KBTS_POINTER_OFFSET(kbts_base_array, Adjust, Adjust->BaseArrayOffset)); + kbts__ByteSwapCoverage(Context, KBTS__POINTER_OFFSET(kbts__coverage, Adjust, Adjust->BaseCoverageOffset)); + kbts__ByteSwapMarkArray(Context, KBTS__POINTER_OFFSET(kbts__mark_array, Adjust, Adjust->MarkArrayOffset)); + kbts__ByteSwapBaseArray(Context, Adjust->MarkClassCount, KBTS__POINTER_OFFSET(kbts__base_array, Adjust, Adjust->BaseArrayOffset)); } break; case 5: { - kbts_mark_to_ligature_attachment *Adjust = (kbts_mark_to_ligature_attachment *)Base; - kbts_ByteSwapArray16Context(&Adjust->LigatureCoverageOffset, 4, Context); + kbts__mark_to_ligature_attachment *Adjust = (kbts__mark_to_ligature_attachment *)Base; + kbts__ByteSwapArray16Context(&Adjust->LigatureCoverageOffset, 4, Context); - kbts_ByteSwapCoverage(Context, KBTS_POINTER_OFFSET(kbts_coverage, Adjust, Adjust->LigatureCoverageOffset)); - kbts_ByteSwapMarkArray(Context, KBTS_POINTER_OFFSET(kbts_mark_array, Adjust, Adjust->MarkArrayOffset)); + kbts__ByteSwapCoverage(Context, KBTS__POINTER_OFFSET(kbts__coverage, Adjust, Adjust->LigatureCoverageOffset)); + kbts__ByteSwapMarkArray(Context, KBTS__POINTER_OFFSET(kbts__mark_array, Adjust, Adjust->MarkArrayOffset)); - kbts_ligature_array *LigatureArray = KBTS_POINTER_OFFSET(kbts_ligature_array, Adjust, Adjust->LigatureArrayOffset); - if(!kbts_AlreadyVisited(Context, LigatureArray)) + kbts__ligature_array *LigatureArray = KBTS__POINTER_OFFSET(kbts__ligature_array, Adjust, Adjust->LigatureArrayOffset); + if(!kbts__AlreadyVisited(Context, LigatureArray)) { - LigatureArray->Count = kbts_ByteSwap16(LigatureArray->Count); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, LigatureArray), LigatureArray->Count, Context); + LigatureArray->Count = kbts__ByteSwap16(LigatureArray->Count); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, LigatureArray), LigatureArray->Count, Context); - KBTS_FOR(AttachIndex, 0, LigatureArray->Count) + KBTS__FOR(AttachIndex, 0, LigatureArray->Count) { - kbts_ligature_attach *Attach = kbts_GetLigatureAttach(LigatureArray, AttachIndex); + kbts__ligature_attach *Attach = kbts__GetLigatureAttach(LigatureArray, AttachIndex); - if(!kbts_AlreadyVisited(Context, Attach)) + if(!kbts__AlreadyVisited(Context, Attach)) { - Attach->Count = kbts_ByteSwap16(Attach->Count); + Attach->Count = kbts__ByteSwap16(Attach->Count); - kbts_u16 *AttachAnchorOffsets = KBTS_POINTER_AFTER(kbts_u16, Attach); - kbts_ByteSwapArray16Context(AttachAnchorOffsets, Attach->Count * Adjust->MarkClassCount, Context); + kbts_u16 *AttachAnchorOffsets = KBTS__POINTER_AFTER(kbts_u16, Attach); + kbts__ByteSwapArray16Context(AttachAnchorOffsets, Attach->Count * Adjust->MarkClassCount, Context); - KBTS_FOR(ComponentIndex, 0, Attach->Count) + KBTS__FOR(ComponentIndex, 0, Attach->Count) { - KBTS_FOR(MarkClass, 0, Adjust->MarkClassCount) + KBTS__FOR(MarkClass, 0, Adjust->MarkClassCount) { - kbts_anchor *Anchor = kbts_GetLigatureAttachAnchor(Adjust, Attach, (kbts_u16)MarkClass, ComponentIndex); + kbts__anchor *Anchor = kbts__GetLigatureAttachAnchor(Adjust, Attach, (kbts_u16)MarkClass, ComponentIndex); - kbts_ByteSwapAnchor(Context, Anchor); + kbts__ByteSwapAnchor(Context, Anchor); } } } @@ -15988,101 +18756,85 @@ static void kbts_ByteSwapGposLookupSubtable(kbts_byteswap_context *Context, kbts case 7: { - kbts_ByteSwapSequenceContextSubtable(Context, Base); + kbts__ByteSwapSequenceContextSubtable(Context, Base); } break; case 8: { - kbts_ByteSwapChainedSequenceContextSubtable(Context, Base); + kbts__ByteSwapChainedSequenceContextSubtable(Context, Base); } break; case 9: { // @Cleanup: Replace recursion with a loop at the start of this function! - kbts_extension *Adjust = (kbts_extension *)Base; + kbts__extension *Adjust = (kbts__extension *)Base; - Adjust->LookupType = kbts_ByteSwap16(Adjust->LookupType); - Adjust->Offset = kbts_ByteSwap32(Adjust->Offset); + Adjust->LookupType = kbts__ByteSwap16(Adjust->LookupType); + Adjust->Offset = kbts__ByteSwap32(Adjust->Offset); - kbts_ByteSwapGposLookupSubtable(Context, LookupList, Adjust->LookupType, KBTS_POINTER_OFFSET(kbts_u16, Adjust, Adjust->Offset)); + kbts__ByteSwapGposLookupSubtable(Context, LookupList, Adjust->LookupType, KBTS__POINTER_OFFSET(kbts_u16, Adjust, Adjust->Offset)); } break; } } } -static kbts_glyph_classes kbts_GlyphClasses(kbts_font *Font, kbts_u32 Id) +static void *kbts__BlobTableData(kbts_blob_header *Header, kbts_blob_table_id TableId) { - kbts_glyph_classes Result = KBTS_ZERO; + void *Result = 0; + kbts_blob_table *Table = &Header->Tables[TableId]; + + if(Table->Length) + { + Result = KBTS__POINTER_OFFSET(void, Header, Table->OffsetFromStartOfFile); + } + + return Result; +} +#define kbts__BlobTableDataType(Header, TableId, Type) (Type *)kbts__BlobTableData((Header), (TableId)) + +static kbts_glyph_classes kbts__GlyphClasses(kbts_font *Font, kbts_u32 Id) +{ + kbts_glyph_classes Result = KBTS__ZERO; // Look up all glyph classes. - kbts_gdef *Gdef = Font->Gdef; + kbts__gdef *Gdef = kbts__BlobTableDataType(Font->Blob, KBTS_BLOB_TABLE_ID_GDEF, kbts__gdef); if(Gdef) { if(Gdef->ClassDefinitionOffset) { - kbts_u16 *ClassDefBase = KBTS_POINTER_OFFSET(kbts_u16, Gdef, Gdef->ClassDefinitionOffset); - Result.Class = kbts_GlyphClassFromTable(ClassDefBase, Id).Class; + kbts_u16 *ClassDefBase = KBTS__POINTER_OFFSET(kbts_u16, Gdef, Gdef->ClassDefinitionOffset); + Result.Class = kbts__GlyphClassFromTable(ClassDefBase, Id).Class; } - if(Gdef->MarkAttachmentClassDefinitionOffset && (Result.Class == KBTS_GLYPH_CLASS_MARK)) + if(Gdef->MarkAttachmentClassDefinitionOffset && (Result.Class == KBTS__GLYPH_CLASS_MARK)) { - kbts_u16 *MarkAttachmentClassDefBase = KBTS_POINTER_OFFSET(kbts_u16, Gdef, Gdef->MarkAttachmentClassDefinitionOffset); - Result.MarkAttachmentClass = kbts_GlyphClassFromTable(MarkAttachmentClassDefBase, Id).Class; + kbts_u16 *MarkAttachmentClassDefBase = KBTS__POINTER_OFFSET(kbts_u16, Gdef, Gdef->MarkAttachmentClassDefinitionOffset); + Result.MarkAttachmentClass = kbts__GlyphClassFromTable(MarkAttachmentClassDefBase, Id).Class; } } return Result; } -static int kbts_ScriptIsWeak(kbts_script Script) +static int kbts__ScriptIsWeak(kbts_script Script) { int Result = (Script == KBTS_SCRIPT_DONT_KNOW) || (Script == KBTS_SCRIPT_DEFAULT) || (Script == KBTS_SCRIPT_DEFAULT2); return Result; } -static int kbts_ShaperRtl(kbts_shaper Shaper) +static int kbts__ShaperRtl(kbts_shaper Shaper) { int Result = (Shaper == KBTS_SHAPER_ARABIC) || (Shaper == KBTS_SHAPER_HEBREW); return Result; } -// Easy shorthand for determining scripts in simple cases. -// Do not ship this! You should use script breaks instead. -KBTS_EXPORT void kbts_InferScript(kbts_direction *Direction, kbts_script *Script, kbts_script GlyphScript) +KBTS_EXPORT int kbts_CodepointToGlyphId(kbts_font *Font, int ICodepoint) { - if(Script) - { - if(kbts_ScriptIsWeak(*Script) && !kbts_ScriptIsWeak(GlyphScript)) - { - *Script = GlyphScript; - if(Direction && (!*Direction)) - { - kbts_script_properties *Properties = &kbts_ScriptProperties[GlyphScript]; - *Direction = kbts_ShaperRtl(Properties->Shaper) ? KBTS_DIRECTION_RTL : KBTS_DIRECTION_LTR; - } - } - } -} - -KBTS_EXPORT kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, kbts_u32 Codepoint) -{ - kbts_glyph Result = KBTS_ZERO; - Result.Codepoint = Codepoint; - - // Look up Unicode properties. - Result.Decomposition = kbts_GetUnicodeDecomposition(Codepoint); - Result.JoiningType = kbts_GetUnicodeJoiningType(Codepoint); - Result.UnicodeFlags = kbts_GetUnicodeFlags(Codepoint); - kbts_u16 SyllabicInfo = kbts_GetUnicodeSyllabicInfo(Codepoint); - Result.SyllabicClass = kbts_GetSyllabicClass(SyllabicInfo); - Result.SyllabicPosition = kbts_GetSyllabicPosition(SyllabicInfo); - Result.CombiningClass = kbts_GetUnicodeCombiningClass(Codepoint); - Result.UseClass = kbts_GetUnicodeUseClass(Codepoint); - Result.Script = kbts_GetUnicodeScript(Codepoint); - Result.ParentInfo = kbts_GetUnicodeParentInfo(Codepoint); + int Result = 0; + kbts_u32 Codepoint = (kbts_u32)ICodepoint; kbts_u16 *CmapBase = Font->Cmap; if(CmapBase) @@ -16091,18 +18843,18 @@ KBTS_EXPORT kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, kbts_u32 Codepoint { case 0: { - kbts_cmap_0 *Cmap0 = (kbts_cmap_0 *)CmapBase; + kbts__cmap_0 *Cmap0 = (kbts__cmap_0 *)CmapBase; - if((kbts_un)Codepoint < KBTS_ARRAY_LENGTH(Cmap0->GlyphIdArray)) + if((kbts_un)Codepoint < KBTS__ARRAY_LENGTH(Cmap0->GlyphIdArray)) { - Result.Id = Cmap0->GlyphIdArray[Codepoint]; + Result = Cmap0->GlyphIdArray[Codepoint]; } } break; case 2: { - kbts_cmap_2 *Cmap2 = (kbts_cmap_2 *)CmapBase; - kbts_sub_header *SubHeaders = KBTS_POINTER_AFTER(kbts_sub_header, Cmap2); + kbts__cmap_2 *Cmap2 = (kbts__cmap_2 *)CmapBase; + kbts__sub_header *SubHeaders = KBTS__POINTER_AFTER(kbts__sub_header, Cmap2); kbts_u32 High = (Codepoint >> 8) & 0xFF; @@ -16114,7 +18866,7 @@ KBTS_EXPORT kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, kbts_u32 Codepoint // The Microsoft documentation doesn't mention that the SubHeaderKeys are indices multiplied by 8, for some // reason..! The Apple documentation does. kbts_u16 SubHeaderIndex = Cmap2->SubHeaderKeys[High] / 8; - kbts_sub_header *SubHeader = &SubHeaders[SubHeaderIndex]; + kbts__sub_header *SubHeader = &SubHeaders[SubHeaderIndex]; if(!SubHeaderIndex) { @@ -16129,22 +18881,22 @@ KBTS_EXPORT kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, kbts_u32 Codepoint kbts_u32 Offset = Codepoint - SubHeader->FirstCode; if(Offset < SubHeader->EntryCount) { - kbts_u16 *GlyphIds = KBTS_POINTER_OFFSET(kbts_u16, &SubHeader->IdRangeOffset, SubHeader->IdRangeOffset); + kbts_u16 *GlyphIds = KBTS__POINTER_OFFSET(kbts_u16, &SubHeader->IdRangeOffset, SubHeader->IdRangeOffset); kbts_u16 GlyphId = GlyphIds[Offset]; if(GlyphId) { GlyphId += SubHeader->IdDelta; } - Result.Id = GlyphId; + Result = GlyphId; } } break; case 4: { - kbts_cmap_4 *Cmap4 = (kbts_cmap_4 *)CmapBase; + kbts__cmap_4 *Cmap4 = (kbts__cmap_4 *)CmapBase; kbts_un SegmentCount = Cmap4->SegmentCountTimesTwo / 2; - kbts_u16 *EndCodes = KBTS_POINTER_AFTER(kbts_u16, Cmap4); + kbts_u16 *EndCodes = KBTS__POINTER_AFTER(kbts_u16, Cmap4); kbts_u16 *StartCodes = EndCodes + SegmentCount + 1; kbts_s16 *IdDeltas = (kbts_s16 *)(StartCodes + SegmentCount); kbts_u16 *IdRangeOffsets = (kbts_u16 *)(IdDeltas + SegmentCount); @@ -16175,26 +18927,26 @@ KBTS_EXPORT kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, kbts_u32 Codepoint { GlyphId += (kbts_u16)(Codepoint); } - Result.Id = GlyphId; + Result = GlyphId; } } break; case 6: { - kbts_cmap_6 *Cmap6 = (kbts_cmap_6 *)CmapBase; - kbts_u16 *GlyphIds = KBTS_POINTER_AFTER(kbts_u16, Cmap6); + kbts__cmap_6 *Cmap6 = (kbts__cmap_6 *)CmapBase; + kbts_u16 *GlyphIds = KBTS__POINTER_AFTER(kbts_u16, Cmap6); kbts_un Offset = Codepoint - Cmap6->FirstCode; if(Offset < Cmap6->EntryCount) { - Result.Id = GlyphIds[Offset]; + Result = GlyphIds[Offset]; } } break; case 12: { - kbts_cmap_12_13 *Cmap12 = (kbts_cmap_12_13 *)CmapBase; - kbts_sequential_map_group *Groups = KBTS_POINTER_AFTER(kbts_sequential_map_group, Cmap12); + kbts__cmap_12_13 *Cmap12 = (kbts__cmap_12_13 *)CmapBase; + kbts__sequential_map_group *Groups = KBTS__POINTER_AFTER(kbts__sequential_map_group, Cmap12); kbts_un GlyphId = 0; kbts_un GroupCount = Cmap12->GroupCount; @@ -16214,62 +18966,89 @@ KBTS_EXPORT kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, kbts_u32 Codepoint GlyphId = Groups->StartGlyphId + Offset; } - Result.Id = (kbts_u16)GlyphId; + Result = (int)GlyphId; } break; } } - if(Font->Gdef) - { - Result.Classes = kbts_GlyphClasses(Font, Result.Id); - } - else - { - // @Cleanup: This is garbage compatibility-with-broken-fonts code. I would very much like to get rid of it. - if((Result.UnicodeFlags & KBTS_UNICODE_FLAG_DEFAULT_IGNORABLE) || !(Result.UnicodeFlags & KBTS_UNICODE_FLAG_NON_SPACING_MARK)) - { - Result.Classes.Class = KBTS_GLYPH_CLASS_BASE; - } - else - { - Result.Classes.Class = KBTS_GLYPH_CLASS_MARK; - } - } - return Result; } -typedef struct kbts_iterate_features +KBTS_EXPORT kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, int ICodepoint, kbts_glyph_config *Config, int UserId) { - kbts_gsub_gpos *Header; - kbts_feature_list *FeatureList; - // @Incomplete - // kbts_feature_variations *FeatureVariations; - kbts_langsys *Langsys; + kbts_u32 Codepoint = (kbts_u32)ICodepoint; - kbts_feature_set EnabledFeatures; + kbts_glyph Result = KBTS__ZERO; + Result.Codepoint = Codepoint; + Result.Config = Config; + Result.UserIdOrCodepointIndex = UserId; + + // Look up Unicode properties. + Result.Decomposition = kbts__GetUnicodeDecomposition(Codepoint); + Result.JoiningType = kbts__GetUnicodeJoiningType(Codepoint); + Result.UnicodeFlags = kbts__GetUnicodeFlags(Codepoint); + kbts_u16 SyllabicInfo = kbts__GetUnicodeSyllabicInfo(Codepoint); + Result.SyllabicClass = kbts__GetSyllabicClass(SyllabicInfo); + Result.SyllabicPosition = kbts__GetSyllabicPosition(SyllabicInfo); + Result.CombiningClass = kbts__GetUnicodeCombiningClass(Codepoint); + Result.UseClass = kbts__GetUnicodeUseClass(Codepoint); + Result.ParentInfo = kbts__GetUnicodeParentInfo(Codepoint); + + Result.Id = (kbts_u16)kbts_CodepointToGlyphId(Font, ICodepoint); + + if(Font->Blob->Tables[KBTS_BLOB_TABLE_ID_GDEF].Length) + { + Result.Classes = kbts__GlyphClasses(Font, Result.Id); + } + else + { + // @Cleanup: This is garbage compatibility-with-broken-fonts code. I would very much like to get rid of it. + if((Result.UnicodeFlags & KBTS_UNICODE_FLAG_DEFAULT_IGNORABLE) || !(Result.UnicodeFlags & KBTS_UNICODE_FLAG_NON_SPACING_MARK)) + { + Result.Classes.Class = KBTS__GLYPH_CLASS_BASE; + } + else + { + Result.Classes.Class = KBTS__GLYPH_CLASS_MARK; + } + } + + return Result; +} + +typedef struct kbts__iterate_features +{ + kbts__gsub_gpos *Header; + kbts__feature_list *FeatureList; + // @Incomplete + // kbts__feature_variations *FeatureVariations; + kbts__langsys *Langsys; + + kbts__feature_set EnabledFeatures; kbts_u32 CurrentFeatureTag; kbts_u32 CurrentFeatureFlag; kbts_u32 FeatureIndex; - kbts_feature *Feature; -} kbts_iterate_features; + kbts__feature *Feature; +} kbts__iterate_features; -static kbts_iterate_features kbts_IterateFeatures(kbts_shape_config *Config, kbts_shaping_table ShapingTable, kbts_feature_set EnabledFeatures) +static kbts__iterate_features kbts__IterateFeatures(kbts_shape_config *Config, kbts_shaping_table ShapingTable, kbts__feature_set EnabledFeatures) { - kbts_iterate_features Result = KBTS_ZERO; + kbts__iterate_features Result = KBTS__ZERO; - kbts_gsub_gpos *Header = Config->Font->ShapingTables[ShapingTable]; + kbts_blob_table_id TableId = (ShapingTable == KBTS_SHAPING_TABLE_GSUB) ? KBTS_BLOB_TABLE_ID_GSUB : KBTS_BLOB_TABLE_ID_GPOS; + + kbts__gsub_gpos *Header = kbts__BlobTableDataType(Config->Font->Blob, TableId, kbts__gsub_gpos); if(Header) { // @Incomplete // if(Header->Minor == 1) // { - // Result.FeatureVariations = KBTS_POINTER_OFFSET(kbts_feature_variations, Header, Header->FeatureVariationsOffset); + // Result.FeatureVariations = KBTS__POINTER_OFFSET(kbts__feature_variations, Header, Header->FeatureVariationsOffset); // } - Result.FeatureList = KBTS_POINTER_OFFSET(kbts_feature_list, Header, Header->FeatureListOffset); + Result.FeatureList = KBTS__POINTER_OFFSET(kbts__feature_list, Header, Header->FeatureListOffset); Result.Header = Header; Result.Langsys = Config->Langsys[ShapingTable]; Result.EnabledFeatures = EnabledFeatures; @@ -16278,37 +19057,37 @@ static kbts_iterate_features kbts_IterateFeatures(kbts_shape_config *Config, kbt return Result; } -static kbts_u32 kbts_IsValidFeatureIteration(kbts_iterate_features *It) +static int kbts__IsValidFeatureIteration(kbts__iterate_features *It) { - kbts_u32 Result = It->Langsys != 0; + int Result = It->Langsys != 0; return Result; } -static kbts_u32 kbts_NextFeature(kbts_iterate_features *It) +static int kbts__NextFeature(kbts__iterate_features *It) { - kbts_u32 Result = 0; + int Result = 0; It->Feature = 0; - if(kbts_IsValidFeatureIteration(It)) + if(kbts__IsValidFeatureIteration(It)) { - kbts_u16 *FeatureIndices = KBTS_POINTER_AFTER(kbts_u16, It->Langsys); + kbts_u16 *FeatureIndices = KBTS__POINTER_AFTER(kbts_u16, It->Langsys); // @Incomplete - // kbts_feature_variations *FeatureVariations = It->FeatureVariations; + // kbts__feature_variations *FeatureVariations = It->FeatureVariations; while(It->FeatureIndex < It->Langsys->FeatureIndexCount) { - kbts_feature_pointer Feature = kbts_GetFeature(It->FeatureList, FeatureIndices[It->FeatureIndex]); + kbts__feature_pointer Feature = kbts__GetFeature(It->FeatureList, FeatureIndices[It->FeatureIndex]); // We might need to swap out this feature with another. // Check for variations. // @Incomplete //if(FeatureVariations) //{ - // KBTS_FOR(VariationIndex, 0, FeatureVariations->RecordCount) + // KBTS__FOR(VariationIndex, 0, FeatureVariations->RecordCount) // { - // kbts_feature_variation_pointer Variation = kbts_GetFeatureVariation(FeatureVariations, VariationIndex); - // KBTS_FOR(ConditionIndex, 0, Variation.ConditionSet->Count) + // kbts__feature_variation_pointer Variation = kbts__GetFeatureVariation(FeatureVariations, VariationIndex); + // KBTS__FOR(ConditionIndex, 0, Variation.ConditionSet->Count) // { - // kbts_condition_1 *Condition = kbts_GetCondition(Variation.ConditionSet, ConditionIndex); + // kbts__condition_1 *Condition = kbts__GetCondition(Variation.ConditionSet, ConditionIndex); // KBTS_ASSERT(0); // } // } @@ -16316,14 +19095,14 @@ static kbts_u32 kbts_NextFeature(kbts_iterate_features *It) It->FeatureIndex += 1; - kbts_u32 FeatureId = kbts_FeatureTagToId(Feature.Tag); - if(kbts_ContainsFeature(&It->EnabledFeatures, FeatureId)) + kbts_u32 FeatureId = kbts__FeatureTagToId(Feature.Tag); + if(kbts__ContainsFeature(&It->EnabledFeatures, FeatureId)) { It->Feature = Feature.Feature; It->CurrentFeatureTag = Feature.Tag; if(FeatureId && (FeatureId <= 32)) { - It->CurrentFeatureFlag = (1 << (FeatureId - 1)) & KBTS_GLYPH_FEATURE_MASK; + It->CurrentFeatureFlag = (1 << (FeatureId - 1)) & KBTS__GLYPH_FEATURE_MASK; } Result = 1; @@ -16335,37 +19114,37 @@ static kbts_u32 kbts_NextFeature(kbts_iterate_features *It) return Result; } -typedef struct kbts_iterate_lookups +typedef struct kbts__iterate_lookups { kbts_lookup_list *LookupList; - kbts_feature *Feature; + kbts__feature *Feature; - kbts_lookup *Lookup; + kbts__lookup *Lookup; kbts_u16 LookupIndex; kbts_u32 LookupIndexIndex; -} kbts_iterate_lookups; +} kbts__iterate_lookups; -static kbts_iterate_lookups kbts_IterateLookups(kbts_lookup_list *List, kbts_feature *Feature) +static kbts__iterate_lookups kbts__IterateLookups(kbts_lookup_list *List, kbts__feature *Feature) { - kbts_iterate_lookups Result = KBTS_ZERO; + kbts__iterate_lookups Result = KBTS__ZERO; Result.LookupList = List; Result.Feature = Feature; return Result; } -static kbts_u32 kbts_NextLookup(kbts_iterate_lookups *It) +static int kbts__NextLookup(kbts__iterate_lookups *It) { - kbts_u32 Result = 0; - kbts_feature *Feature = It->Feature; + int Result = 0; + kbts__feature *Feature = It->Feature; if(It->LookupList && Feature && (It->LookupIndexIndex < Feature->LookupIndexCount)) { - kbts_u16 *LookupIndices = KBTS_POINTER_AFTER(kbts_u16, Feature); + kbts_u16 *LookupIndices = KBTS__POINTER_AFTER(kbts_u16, Feature); It->LookupIndex = LookupIndices[It->LookupIndexIndex]; - It->Lookup = kbts_GetLookup(It->LookupList, It->LookupIndex); + It->Lookup = kbts__GetLookup(It->LookupList, It->LookupIndex); Result = 1; It->LookupIndexIndex += 1; @@ -16374,522 +19153,581 @@ static kbts_u32 kbts_NextLookup(kbts_iterate_lookups *It) return Result; } -KBTS_INLINE void kbts_GsubMutate(kbts_font *Font, kbts_glyph *Glyph, kbts_u16 NewId, kbts_u32 Flags) +KBTS_INLINE void kbts__GsubMutate(kbts_font *Font, kbts_glyph *Glyph, kbts_u16 NewId, kbts_u32 Flags) { Glyph->Id = NewId; - Glyph->Classes = kbts_GlyphClasses(Font, NewId); + Glyph->Classes = kbts__GlyphClasses(Font, NewId); Glyph->Flags = (Glyph->Flags & ~KBTS_GLYPH_FLAG_FIRST_IN_MULTIPLE_SUBSTITUTION) | Flags; } -typedef struct kbts_do_single_substitution_result +static kbts__op_list *kbts__ShaperOpLists[KBTS_SHAPER_COUNT] = { + /* DEFAULT, */ &kbts__OpList_Default, + /* ARABIC, */ &kbts__OpList_ArabicRclt, + /* HANGUL, */ &kbts__OpList_Hangul, + /* HEBREW, */ &kbts__OpList_Default, + /* INDIC, */ &kbts__OpList_Indic, + /* KHMER, */ &kbts__OpList_Khmer, + /* MYANMAR, */ &kbts__OpList_Myanmar, + /* TIBETAN, */ &kbts__OpList_Tibetan, + /* USE, */ &kbts__OpList_Use, +}; + +typedef struct kbts__gsub_frame { - kbts_u32 ConsumedGlyphCount; - kbts_u32 WrittenGlyphCount; - kbts_u32 PerformedSubstitution; -} kbts_do_single_substitution_result; + kbts_glyph *InputGlyph; -static kbts_feature_set kbts_ShaperFeatures[] = { - /* KBTS_SHAPER_DEFAULT */ {{KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm) | KBTS_FEATURE_FLAG0(curs) | - KBTS_FEATURE_FLAG0(frac) | KBTS_FEATURE_FLAG0(numr) | KBTS_FEATURE_FLAG0(dnom) | KBTS_FEATURE_FLAG0(ccmp) | - KBTS_FEATURE_FLAG0(clig) | KBTS_FEATURE_FLAG0(calt), - 0, - KBTS_FEATURE_FLAG2(locl) | KBTS_FEATURE_FLAG2(ltra) | KBTS_FEATURE_FLAG2(ltrm) | KBTS_FEATURE_FLAG2(liga) | - KBTS_FEATURE_FLAG2(rlig) | KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(dist) | KBTS_FEATURE_FLAG2(kern) | - KBTS_FEATURE_FLAG2(mark) | KBTS_FEATURE_FLAG2(mkmk), - KBTS_FEATURE_FLAG3(rvrn)}}, - /* KBTS_SHAPER_ARABIC */ {{KBTS_FEATURE_FLAG0(frac) | KBTS_FEATURE_FLAG0(numr) | KBTS_FEATURE_FLAG0(dnom) | KBTS_FEATURE_FLAG0(ccmp) | - KBTS_FEATURE_FLAG0(isol) | KBTS_FEATURE_FLAG0(fina) | KBTS_FEATURE_FLAG0(fin2) | KBTS_FEATURE_FLAG0(fin3) | - KBTS_FEATURE_FLAG0(medi) | KBTS_FEATURE_FLAG0(med2) | KBTS_FEATURE_FLAG0(init) | KBTS_FEATURE_FLAG0(calt) | - KBTS_FEATURE_FLAG0(clig) | KBTS_FEATURE_FLAG2(mset) | KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm) | - KBTS_FEATURE_FLAG0(curs), - 0, - KBTS_FEATURE_FLAG2(rlig) | KBTS_FEATURE_FLAG2(liga) | KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(mark) | - KBTS_FEATURE_FLAG2(mkmk) | KBTS_FEATURE_FLAG2(dist) | KBTS_FEATURE_FLAG2(kern) | KBTS_FEATURE_FLAG2(locl), - KBTS_FEATURE_FLAG3(rvrn) | KBTS_FEATURE_FLAG3(rtlm) | KBTS_FEATURE_FLAG3(stch) | KBTS_FEATURE_FLAG3(rtla)}}, - /* KBTS_SHAPER_HANGUL */ {{KBTS_FEATURE_FLAG0(frac) | KBTS_FEATURE_FLAG0(numr) | KBTS_FEATURE_FLAG0(dnom) | KBTS_FEATURE_FLAG0(ljmo) | - KBTS_FEATURE_FLAG0(vjmo) | KBTS_FEATURE_FLAG0(tjmo) | KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm) | - KBTS_FEATURE_FLAG0(ccmp) | KBTS_FEATURE_FLAG0(clig) | KBTS_FEATURE_FLAG0(curs), - 0, - KBTS_FEATURE_FLAG2(ltra) | KBTS_FEATURE_FLAG2(ltrm) | KBTS_FEATURE_FLAG2(dist) | KBTS_FEATURE_FLAG2(kern) | - KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(locl) | KBTS_FEATURE_FLAG2(mark) | KBTS_FEATURE_FLAG2(mkmk) | - KBTS_FEATURE_FLAG2(rlig) | KBTS_FEATURE_FLAG2(liga), - KBTS_FEATURE_FLAG3(rvrn)}}, - /* KBTS_SHAPER_HEBREW */ {{KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm) | KBTS_FEATURE_FLAG0(curs) | - KBTS_FEATURE_FLAG0(frac) | KBTS_FEATURE_FLAG0(numr) | KBTS_FEATURE_FLAG0(dnom) | KBTS_FEATURE_FLAG0(ccmp) | - KBTS_FEATURE_FLAG0(clig) | KBTS_FEATURE_FLAG0(calt), - 0, - KBTS_FEATURE_FLAG2(locl) | KBTS_FEATURE_FLAG2(ltra) | KBTS_FEATURE_FLAG2(ltrm) | KBTS_FEATURE_FLAG2(liga) | - KBTS_FEATURE_FLAG2(rlig) | KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(dist) | KBTS_FEATURE_FLAG2(kern) | - KBTS_FEATURE_FLAG2(mark) | KBTS_FEATURE_FLAG2(mkmk), - KBTS_FEATURE_FLAG3(rvrn)}}, // (Same as DEFAULT) - /* KBTS_SHAPER_INDIC */ {{KBTS_FEATURE_FLAG0(frac) | KBTS_FEATURE_FLAG0(numr) | KBTS_FEATURE_FLAG0(dnom) | KBTS_FEATURE_FLAG0(akhn) | - KBTS_FEATURE_FLAG0(rphf) | KBTS_FEATURE_FLAG0(pref) | KBTS_FEATURE_FLAG0(blwf) | KBTS_FEATURE_FLAG0(abvf) | - KBTS_FEATURE_FLAG0(half) | KBTS_FEATURE_FLAG0(pstf) | KBTS_FEATURE_FLAG0(cjct) | KBTS_FEATURE_FLAG0(abvs) | - KBTS_FEATURE_FLAG0(blws) | KBTS_FEATURE_FLAG0(init) | KBTS_FEATURE_FLAG0(calt) | KBTS_FEATURE_FLAG0(clig) | - KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm) | KBTS_FEATURE_FLAG0(curs), - 0, - KBTS_FEATURE_FLAG2(ltra) | KBTS_FEATURE_FLAG2(ltrm) | KBTS_FEATURE_FLAG2(nukt) | KBTS_FEATURE_FLAG2(rkrf) | - KBTS_FEATURE_FLAG2(pres) | KBTS_FEATURE_FLAG2(psts) | KBTS_FEATURE_FLAG2(locl) | KBTS_FEATURE_FLAG2(rlig) | - KBTS_FEATURE_FLAG2(dist) | KBTS_FEATURE_FLAG2(haln) | KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(mark) | - KBTS_FEATURE_FLAG2(mkmk) | KBTS_FEATURE_FLAG2(kern), - KBTS_FEATURE_FLAG3(rvrn) | KBTS_FEATURE_FLAG3(vatu),}}, - /* KBTS_SHAPER_KHMER */ {{KBTS_FEATURE_FLAG0(frac) | KBTS_FEATURE_FLAG0(numr) | KBTS_FEATURE_FLAG0(dnom) | KBTS_FEATURE_FLAG0(ccmp) | - KBTS_FEATURE_FLAG0(pref) | KBTS_FEATURE_FLAG0(blwf) | KBTS_FEATURE_FLAG0(abvf) | KBTS_FEATURE_FLAG0(pstf) | - KBTS_FEATURE_FLAG0(cfar) | KBTS_FEATURE_FLAG0(abvs) | KBTS_FEATURE_FLAG0(blws) | KBTS_FEATURE_FLAG0(calt) | - KBTS_FEATURE_FLAG0(clig) | KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm) | KBTS_FEATURE_FLAG0(curs), - 0, - KBTS_FEATURE_FLAG2(dist) | KBTS_FEATURE_FLAG2(kern) | KBTS_FEATURE_FLAG2(mark) | KBTS_FEATURE_FLAG2(mkmk) | - KBTS_FEATURE_FLAG2(pres) | KBTS_FEATURE_FLAG2(ltra) | KBTS_FEATURE_FLAG2(ltrm) | KBTS_FEATURE_FLAG2(locl) | - KBTS_FEATURE_FLAG2(psts) | KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(rlig), - KBTS_FEATURE_FLAG3(rvrn)}}, - /* KBTS_SHAPER_MYANMAR */ {{KBTS_FEATURE_FLAG0(rphf) | KBTS_FEATURE_FLAG0(pref) | KBTS_FEATURE_FLAG0(blwf) | KBTS_FEATURE_FLAG0(pstf) | - KBTS_FEATURE_FLAG0(frac) | KBTS_FEATURE_FLAG0(numr) | KBTS_FEATURE_FLAG0(dnom) | KBTS_FEATURE_FLAG0(ccmp) | - KBTS_FEATURE_FLAG0(abvs) | KBTS_FEATURE_FLAG0(blws) | KBTS_FEATURE_FLAG0(calt) | KBTS_FEATURE_FLAG0(clig) | - KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm) | KBTS_FEATURE_FLAG0(curs), - 0, - KBTS_FEATURE_FLAG2(mark) | KBTS_FEATURE_FLAG2(mkmk) | KBTS_FEATURE_FLAG2(ltra) | KBTS_FEATURE_FLAG2(ltrm) | - KBTS_FEATURE_FLAG2(locl) | KBTS_FEATURE_FLAG2(psts) | KBTS_FEATURE_FLAG2(rlig) | KBTS_FEATURE_FLAG2(pres) | - KBTS_FEATURE_FLAG2(liga) | KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(dist) | KBTS_FEATURE_FLAG2(kern), - KBTS_FEATURE_FLAG3(rvrn)}}, - /* KBTS_SHAPER_TIBETAN */ {{KBTS_FEATURE_FLAG0(ccmp) | KBTS_FEATURE_FLAG0(abvs) | KBTS_FEATURE_FLAG0(blws) | KBTS_FEATURE_FLAG0(calt) | - KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm), - 0, - KBTS_FEATURE_FLAG2(locl) | KBTS_FEATURE_FLAG2(liga) | KBTS_FEATURE_FLAG2(kern) | KBTS_FEATURE_FLAG2(mkmk), - 0}}, - /* KBTS_SHAPER_USE */ {{KBTS_FEATURE_FLAG0(frac) | KBTS_FEATURE_FLAG0(numr) | KBTS_FEATURE_FLAG0(dnom) | KBTS_FEATURE_FLAG0(ccmp) | - KBTS_FEATURE_FLAG0(akhn) | KBTS_FEATURE_FLAG0(rphf) | KBTS_FEATURE_FLAG0(pref) | KBTS_FEATURE_FLAG0(abvf) | - KBTS_FEATURE_FLAG0(blwf) | KBTS_FEATURE_FLAG0(cjct) | KBTS_FEATURE_FLAG0(half) | KBTS_FEATURE_FLAG0(pstf) | - KBTS_FEATURE_FLAG0(fina) | KBTS_FEATURE_FLAG0(init) | KBTS_FEATURE_FLAG0(isol) | KBTS_FEATURE_FLAG0(medi) | - KBTS_FEATURE_FLAG0(abvs) | KBTS_FEATURE_FLAG0(blws) | KBTS_FEATURE_FLAG0(calt) | KBTS_FEATURE_FLAG0(clig) | - KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm) | KBTS_FEATURE_FLAG0(curs), - 0, - KBTS_FEATURE_FLAG2(ltra) | KBTS_FEATURE_FLAG2(ltrm) | KBTS_FEATURE_FLAG2(locl) | KBTS_FEATURE_FLAG2(nukt) | - KBTS_FEATURE_FLAG2(rkrf) | KBTS_FEATURE_FLAG2(rlig) | KBTS_FEATURE_FLAG2(dist) | KBTS_FEATURE_FLAG2(kern) | - KBTS_FEATURE_FLAG2(mark) | KBTS_FEATURE_FLAG2(mkmk) | KBTS_FEATURE_FLAG2(haln) | KBTS_FEATURE_FLAG2(liga) | - KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(pres) | KBTS_FEATURE_FLAG2(psts), - KBTS_FEATURE_FLAG3(rvrn) | KBTS_FEATURE_FLAG3(vatu)}}, -}; + // This isn't really an index into anything, per se. + // It is just an offset that allows reordering for ShapeState->LookupOnePastLastGlyph. + kbts_u32 StartIndex; -// Make sure that these fit KBTS_MAX_SIMULTANEOUS_FEATURES! -static kbts_u8 kbts_Ops_Default[] = { - KBTS_OP_KIND_NORMALIZE, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rvrn, - KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, 12, KBTS_FEATURE_ID_frac, KBTS_FEATURE_ID_numr, KBTS_FEATURE_ID_dnom, KBTS_FEATURE_ID_ltra, KBTS_FEATURE_ID_ltrm, - KBTS_FEATURE_ID_liga, KBTS_FEATURE_ID_ccmp, KBTS_FEATURE_ID_locl, KBTS_FEATURE_ID_rlig, KBTS_FEATURE_ID_clig, - KBTS_FEATURE_ID_calt, KBTS_FEATURE_ID_rclt, - KBTS_OP_KIND_GPOS_METRICS, - KBTS_OP_KIND_GPOS_FEATURES, 7, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_mark, KBTS_FEATURE_ID_mkmk, KBTS_FEATURE_ID_curs, - KBTS_FEATURE_ID_dist, KBTS_FEATURE_ID_kern, - KBTS_OP_KIND_POST_GPOS_FIXUP, -}; - -/* @Incomplete: Vertical text. -static kbts_u8 kbts_Ops_DefaultTtbBtt[] = { - KBTS_OP_KIND_NORMALIZE, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rvrn, - KBTS_OP_KIND_GSUB_FEATURES, 3, KBTS_FEATURE_ID_frac, KBTS_FEATURE_ID_numr, KBTS_FEATURE_ID_dnom, - KBTS_OP_KIND_GPOS_METRICS, - KBTS_OP_KIND_GPOS_FEATURES, 10, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_ccmp, KBTS_FEATURE_ID_locl, KBTS_FEATURE_ID_mark, - KBTS_FEATURE_ID_mkmk, KBTS_FEATURE_ID_rlig, KBTS_FEATURE_ID_calt, KBTS_FEATURE_ID_liga, KBTS_FEATURE_ID_vert, - KBTS_OP_KIND_POST_GPOS_FIXUP, -}; -*/ -static kbts_u8 kbts_Ops_Hangul[] = { - KBTS_OP_KIND_NORMALIZE, KBTS_OP_KIND_NORMALIZE_HANGUL, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rvrn, - KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, 8, KBTS_FEATURE_ID_frac, KBTS_FEATURE_ID_numr, KBTS_FEATURE_ID_dnom, KBTS_FEATURE_ID_ltra, KBTS_FEATURE_ID_ltrm, - KBTS_FEATURE_ID_ljmo, KBTS_FEATURE_ID_vjmo, KBTS_FEATURE_ID_tjmo, - KBTS_OP_KIND_GPOS_METRICS, - KBTS_OP_KIND_GPOS_FEATURES, 13, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_ccmp, KBTS_FEATURE_ID_locl, KBTS_FEATURE_ID_mark, - KBTS_FEATURE_ID_mkmk, KBTS_FEATURE_ID_rlig, KBTS_FEATURE_ID_liga, KBTS_FEATURE_ID_clig, KBTS_FEATURE_ID_curs, - KBTS_FEATURE_ID_dist, KBTS_FEATURE_ID_kern, KBTS_FEATURE_ID_rclt, - KBTS_OP_KIND_POST_GPOS_FIXUP, -}; -static kbts_u8 kbts_Ops_ArabicRclt[] = { - KBTS_OP_KIND_NORMALIZE, KBTS_OP_KIND_FLAG_JOINING_LETTERS, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rvrn, - KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, 5, KBTS_FEATURE_ID_frac, KBTS_FEATURE_ID_numr, KBTS_FEATURE_ID_dnom, KBTS_FEATURE_ID_rtla, KBTS_FEATURE_ID_rtlm, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_stch, - KBTS_OP_KIND_GSUB_FEATURES, 2, KBTS_FEATURE_ID_ccmp, KBTS_FEATURE_ID_locl, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_isol, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_fina, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_fin2, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_fin3, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_medi, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_med2, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_init, - // @Incomplete: In Arabic rlig, ZWJ should not be skipped in lookups (i.e. it should block ligatures). - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rlig, - // @Incomplete: In non-Arabic scripts, e.g. Syriac, Harfbuzz does not pause here. - KBTS_OP_KIND_GSUB_FEATURES, 5, KBTS_FEATURE_ID_calt, KBTS_FEATURE_ID_liga, KBTS_FEATURE_ID_clig, KBTS_FEATURE_ID_mset, KBTS_FEATURE_ID_rclt, - KBTS_OP_KIND_GPOS_METRICS, - KBTS_OP_KIND_GPOS_FEATURES, 7, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_mark, KBTS_FEATURE_ID_mkmk, KBTS_FEATURE_ID_curs, - KBTS_FEATURE_ID_dist, KBTS_FEATURE_ID_kern, - KBTS_OP_KIND_STCH_POSTPASS, - KBTS_OP_KIND_POST_GPOS_FIXUP, -}; -static kbts_u8 kbts_Ops_ArabicNoRclt[] = { - KBTS_OP_KIND_NORMALIZE, KBTS_OP_KIND_FLAG_JOINING_LETTERS, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rvrn, - KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, 5, KBTS_FEATURE_ID_frac, KBTS_FEATURE_ID_numr, KBTS_FEATURE_ID_dnom, KBTS_FEATURE_ID_rtla, KBTS_FEATURE_ID_rtlm, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_stch, - KBTS_OP_KIND_GSUB_FEATURES, 2, KBTS_FEATURE_ID_ccmp, KBTS_FEATURE_ID_locl, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_isol, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_fina, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_fin2, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_fin3, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_medi, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_med2, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_init, - // @Incomplete: In Arabic rlig, ZWJ should not be skipped in lookups (i.e. it should block ligatures). - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rlig, - // @Incomplete: In non-Arabic scripts, e.g. Syriac, Harfbuzz does not pause here. - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_calt, - // When the font does not contain rclt, Uniscribe puts calt in its own pass, and so we pause here. - KBTS_OP_KIND_GSUB_FEATURES, 4, KBTS_FEATURE_ID_liga, KBTS_FEATURE_ID_clig, KBTS_FEATURE_ID_mset, KBTS_FEATURE_ID_rclt, - KBTS_OP_KIND_GPOS_METRICS, - KBTS_OP_KIND_GPOS_FEATURES, 7, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_mark, KBTS_FEATURE_ID_mkmk, KBTS_FEATURE_ID_curs, - KBTS_FEATURE_ID_dist, KBTS_FEATURE_ID_kern, - KBTS_OP_KIND_STCH_POSTPASS, - KBTS_OP_KIND_POST_GPOS_FIXUP, -}; -static kbts_u8 kbts_Ops_Indic0[] = { - KBTS_OP_KIND_PRE_NORMALIZE_DOTTED_CIRCLES, KBTS_OP_KIND_NORMALIZE, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rvrn, - KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, 5, KBTS_FEATURE_ID_frac, KBTS_FEATURE_ID_numr, KBTS_FEATURE_ID_dnom, KBTS_FEATURE_ID_ltra, KBTS_FEATURE_ID_ltrm, -}; -// After BeginCluster. -static kbts_u8 kbts_Ops_Indic1[] = { - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_nukt, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_akhn, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rphf, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rkrf, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_pref, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_blwf, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_abvf, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_half, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_pstf, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_vatu, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_cjct, -}; -// After EndCluster. -static kbts_u8 kbts_Ops_Indic2[] = { - KBTS_OP_KIND_GSUB_FEATURES, 6, KBTS_FEATURE_ID_abvs, KBTS_FEATURE_ID_blws, KBTS_FEATURE_ID_haln, KBTS_FEATURE_ID_init, KBTS_FEATURE_ID_pres, - KBTS_FEATURE_ID_psts, -}; -// After syllable processing. -static kbts_u8 kbts_Ops_Indic3[] = { - KBTS_OP_KIND_GSUB_FEATURES, 5, KBTS_FEATURE_ID_locl, KBTS_FEATURE_ID_rlig, KBTS_FEATURE_ID_calt, KBTS_FEATURE_ID_clig, KBTS_FEATURE_ID_rclt, - KBTS_OP_KIND_GPOS_METRICS, - KBTS_OP_KIND_GPOS_FEATURES, 7, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_mark, KBTS_FEATURE_ID_mkmk, KBTS_FEATURE_ID_curs, - KBTS_FEATURE_ID_dist, KBTS_FEATURE_ID_kern, - KBTS_OP_KIND_POST_GPOS_FIXUP, -}; -static kbts_u8 kbts_Ops_Use0[] = { - KBTS_OP_KIND_PRE_NORMALIZE_DOTTED_CIRCLES, KBTS_OP_KIND_NORMALIZE, KBTS_OP_KIND_FLAG_JOINING_LETTERS, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rvrn, - KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, 5, KBTS_FEATURE_ID_frac, KBTS_FEATURE_ID_numr, KBTS_FEATURE_ID_dnom, KBTS_FEATURE_ID_ltra, KBTS_FEATURE_ID_ltrm, -}; -static kbts_u8 kbts_Ops_Use1[] = { - KBTS_OP_KIND_GSUB_FEATURES, 4, KBTS_FEATURE_ID_locl, KBTS_FEATURE_ID_ccmp, KBTS_FEATURE_ID_nukt, KBTS_FEATURE_ID_akhn, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rphf, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_pref, - KBTS_OP_KIND_GSUB_FEATURES, 7, KBTS_FEATURE_ID_abvf, KBTS_FEATURE_ID_blwf, KBTS_FEATURE_ID_cjct, KBTS_FEATURE_ID_half, KBTS_FEATURE_ID_pstf, - KBTS_FEATURE_ID_rkrf, KBTS_FEATURE_ID_vatu, -}; -// There is no kbts_Ops_Use2, because there are no features that apply per syllable after reordering. -static kbts_u8 kbts_Ops_Use3[] = { - KBTS_OP_KIND_GSUB_FEATURES, 4, KBTS_FEATURE_ID_fina, KBTS_FEATURE_ID_init, KBTS_FEATURE_ID_isol, KBTS_FEATURE_ID_medi, - KBTS_OP_KIND_GSUB_FEATURES,10, KBTS_FEATURE_ID_abvs, KBTS_FEATURE_ID_blws, KBTS_FEATURE_ID_haln, KBTS_FEATURE_ID_pres, KBTS_FEATURE_ID_psts, - KBTS_FEATURE_ID_calt, KBTS_FEATURE_ID_clig, KBTS_FEATURE_ID_liga, KBTS_FEATURE_ID_rclt, KBTS_FEATURE_ID_rlig, - KBTS_OP_KIND_GPOS_METRICS, - KBTS_OP_KIND_GPOS_FEATURES, 7, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_curs, KBTS_FEATURE_ID_dist, KBTS_FEATURE_ID_kern, - KBTS_FEATURE_ID_mark, KBTS_FEATURE_ID_mkmk, - KBTS_OP_KIND_POST_GPOS_FIXUP, -}; -static kbts_u8 kbts_Ops_Tibetan[] = { - KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, 1, KBTS_FEATURE_ID_locl, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_ccmp, - KBTS_OP_KIND_GSUB_FEATURES, 4, KBTS_FEATURE_ID_abvs, KBTS_FEATURE_ID_blws, KBTS_FEATURE_ID_calt, KBTS_FEATURE_ID_liga, - KBTS_OP_KIND_GPOS_METRICS, - KBTS_OP_KIND_GPOS_FEATURES, 4, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_kern, KBTS_FEATURE_ID_mkmk, - KBTS_OP_KIND_POST_GPOS_FIXUP, -}; -static kbts_u8 kbts_Ops_Khmer0[] = { - KBTS_OP_KIND_PRE_NORMALIZE_DOTTED_CIRCLES, KBTS_OP_KIND_NORMALIZE, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rvrn, - KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, 5, KBTS_FEATURE_ID_frac, KBTS_FEATURE_ID_numr, KBTS_FEATURE_ID_dnom, KBTS_FEATURE_ID_ltra, KBTS_FEATURE_ID_ltrm, -}; -static kbts_u8 kbts_Ops_Khmer1[] = { - KBTS_OP_KIND_GSUB_FEATURES, 7, KBTS_FEATURE_ID_locl, KBTS_FEATURE_ID_ccmp, KBTS_FEATURE_ID_pref, KBTS_FEATURE_ID_blwf, KBTS_FEATURE_ID_abvf, - KBTS_FEATURE_ID_pstf, KBTS_FEATURE_ID_cfar, -}; -static kbts_u8 kbts_Ops_Khmer3[] = { - KBTS_OP_KIND_GSUB_FEATURES, 8, KBTS_FEATURE_ID_pres, KBTS_FEATURE_ID_abvs, KBTS_FEATURE_ID_blws, KBTS_FEATURE_ID_psts, KBTS_FEATURE_ID_calt, - KBTS_FEATURE_ID_rclt, KBTS_FEATURE_ID_rlig, KBTS_FEATURE_ID_clig, - KBTS_OP_KIND_GPOS_METRICS, - KBTS_OP_KIND_GPOS_FEATURES, 7, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_curs, KBTS_FEATURE_ID_dist, KBTS_FEATURE_ID_kern, - KBTS_FEATURE_ID_mark, KBTS_FEATURE_ID_mkmk, - KBTS_OP_KIND_POST_GPOS_FIXUP, -}; -#define kbts_Ops_Myanmar0 kbts_Ops_Khmer0 -static kbts_u8 kbts_Ops_Myanmar1[] = { - KBTS_OP_KIND_GSUB_FEATURES, 2, KBTS_FEATURE_ID_locl, KBTS_FEATURE_ID_ccmp, -}; -static kbts_u8 kbts_Ops_Myanmar2[] = { - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rphf, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_pref, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_blwf, - KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_pstf, -}; -static kbts_u8 kbts_Ops_Myanmar3[] = { - KBTS_OP_KIND_GSUB_FEATURES, 9, KBTS_FEATURE_ID_pres, KBTS_FEATURE_ID_abvs, KBTS_FEATURE_ID_blws, KBTS_FEATURE_ID_psts, KBTS_FEATURE_ID_rlig, - KBTS_FEATURE_ID_calt, KBTS_FEATURE_ID_clig, KBTS_FEATURE_ID_liga, KBTS_FEATURE_ID_rclt, - KBTS_OP_KIND_GPOS_METRICS, - KBTS_OP_KIND_GPOS_FEATURES, 7, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_curs, KBTS_FEATURE_ID_dist, KBTS_FEATURE_ID_kern, - KBTS_FEATURE_ID_mark, KBTS_FEATURE_ID_mkmk, - KBTS_OP_KIND_POST_GPOS_FIXUP, -}; - -static kbts_op_list kbts_ShaperOpLists[KBTS_SHAPER_COUNT] = { - /* DEFAULT, */ {kbts_Ops_Default, KBTS_ARRAY_LENGTH(kbts_Ops_Default)}, - /* ARABIC, */ {kbts_Ops_ArabicRclt, KBTS_ARRAY_LENGTH(kbts_Ops_ArabicRclt)}, - /* HANGUL, */ {kbts_Ops_Hangul, KBTS_ARRAY_LENGTH(kbts_Ops_Hangul)}, - /* HEBREW, */ {kbts_Ops_Default, KBTS_ARRAY_LENGTH(kbts_Ops_Default)}, - /* INDIC, */ {kbts_Ops_Indic0, KBTS_ARRAY_LENGTH(kbts_Ops_Indic0)}, - /* KHMER, */ {kbts_Ops_Khmer0, KBTS_ARRAY_LENGTH(kbts_Ops_Khmer0)}, - /* MYANMAR, */ {kbts_Ops_Myanmar0, KBTS_ARRAY_LENGTH(kbts_Ops_Myanmar0)}, - /* TIBETAN, */ {kbts_Ops_Tibetan, KBTS_ARRAY_LENGTH(kbts_Ops_Tibetan)}, - /* USE, */ {kbts_Ops_Use0, KBTS_ARRAY_LENGTH(kbts_Ops_Use0)}, -}; - -typedef struct kbts_gsub_frame -{ kbts_u16 LookupIndex; kbts_u16 SubtableIndex; - kbts_u16 InputGlyphIndex; - kbts_u16 InputGlyphCount; - // Defined for nested lookups. - kbts_sequence_lookup_record *Records; + kbts__sequence_lookup_record *Records; kbts_u16 RecordCount; kbts_u16 RecordIndex; -} kbts_gsub_frame; +} kbts__gsub_frame; -KBTS_EXPORT kbts_un kbts_SizeOfShapeState(kbts_font *Font) +#define KBTS__DLLIST_REMOVE(Node) do {(Node)->Prev->Next = (Node)->Next; (Node)->Next->Prev = (Node)->Prev;} while(0) +#define KBTS__DLLIST_INSERT_BEFORE(A, B) do{(A)->Next = (B); (A)->Prev = (B)->Prev; (A)->Prev->Next = (A)->Next->Prev = (A);} while(0) +#define KBTS__DLLIST_INSERT_AFTER(A, B) do{(A)->Prev = (B); (A)->Next = (B)->Next; (A)->Prev->Next = (A)->Next->Prev = (A);} while(0) +#define KBTS__DLLIST_SENTINEL_INIT(Sentinel) do{(Sentinel)->Prev = (Sentinel)->Next = (Sentinel);} while(0) +#define KBTS__DLLIST_SORT(First, OnePastLast, Member) \ + do \ + { \ + kbts_glyph *DllistSort_OneBeforeFirst = (First)->Prev; \ + kbts_glyph *DllistSort_OnePastLast = (OnePastLast); \ + for(int DllistSort_Swapped = 1; \ + DllistSort_Swapped; \ + ) \ + { \ + DllistSort_Swapped = 0; \ + kbts_glyph *DllistSort_Glyph0 = DllistSort_OneBeforeFirst->Next; \ + kbts_glyph *DllistSort_Glyph1 = DllistSort_Glyph0->Next; \ + while(DllistSort_Glyph1 != DllistSort_OnePastLast) \ + { \ + kbts_glyph *DllistSort_Next = DllistSort_Glyph1->Next; \ + \ + if(DllistSort_Glyph0->Member > DllistSort_Glyph1->Member) \ + { \ + KBTS__DLLIST_SWAP(DllistSort_Glyph0, DllistSort_Glyph1); \ + DllistSort_Swapped = 1; \ + } \ + else \ + { \ + DllistSort_Glyph0 = DllistSort_Glyph1; \ + } \ + \ + DllistSort_Glyph1 = DllistSort_Next; \ + } \ + } \ + } while(0) + +#define KBTS__FOR_GLYPH(Storage, GlyphName) \ + for(kbts_glyph *GlyphName = (Storage)->GlyphSentinel.Next; \ + GlyphName != (kbts_glyph *)&(Storage)->GlyphSentinel; \ + GlyphName = GlyphName->Next) + +static void KBTS__DLLIST_SWAP(kbts_glyph *A, kbts_glyph *B) { - kbts_un GsubMemorySize = Font->LookupInfo.MaximumLookupStackSize * sizeof(kbts_gsub_frame); - kbts_un NormalizationMemorySize = KBTS_MAXIMUM_DECOMPOSITION_CODEPOINTS * sizeof(kbts_glyph); - kbts_un LeftoverMemorySize = KBTS_MAX(GsubMemorySize, NormalizationMemorySize); + kbts_glyph *APrev = A->Prev; + kbts_glyph *ANext = A->Next; + kbts_glyph *BPrev = B->Prev; + kbts_glyph *BNext = B->Next; - kbts_un Result = sizeof(kbts_shape_state) + LeftoverMemorySize; - return Result; + A->Prev = (BPrev == A) ? B : BPrev; + A->Next = (BNext == A) ? B : BNext; + B->Prev = (APrev == B) ? A : APrev; + B->Next = (ANext == B) ? A : ANext; + + A->Prev->Next = A->Next->Prev = A; + B->Prev->Next = B->Next->Prev = B; } -KBTS_EXPORT kbts_shape_state *kbts_PlaceShapeState(void *Address, kbts_un Size) +static void kbts__NullAllocator(void *Data, kbts_allocator_op *Op) { - kbts_shape_state *State = (kbts_shape_state *)Address; - KBTS_MEMSET(State, 0, Size); - - return State; + KBTS__UNUSED(Data); + KBTS__UNUSED(Op); } -#ifndef KB_TEXT_SHAPE_NO_CRT -KBTS_EXPORT kbts_shape_state *kbts_CreateShapeState(kbts_font *Font) +static void kbts__DefaultAllocator(void *Data, kbts_allocator_op *Op) { - kbts_un Size = kbts_SizeOfShapeState(Font); - void *Memory = malloc(Size); - kbts_shape_state *Result = kbts_PlaceShapeState(Memory, Size); + KBTS__UNUSED(Data); - return Result; -} - -KBTS_EXPORT void kbts_FreeShapeState(kbts_shape_state *State) -{ - if(State) + switch(Op->Kind) { - free(State); - } -} -#endif - -KBTS_EXPORT void kbts_ResetShapeState(kbts_shape_state *State) -{ - State->ResumePoint = 0; -} - -static kbts_glyph_array kbts_ClipGlyphArray(kbts_glyph_array *Source, kbts_un Count) -{ - kbts_glyph_array Result = KBTS_ZERO; - Result.Glyphs = Source->Glyphs; - Result.Count = (kbts_u32)Count; - Result.TotalCount = (kbts_u32)Count; - Result.Capacity = (kbts_u32)Count; - return Result; -} - -static void kbts_TransferGrowRequest(kbts_glyph_array *From, kbts_glyph_array *To) -{ - if(From->RequiredCapacity > From->Capacity) + case KBTS_ALLOCATOR_OP_KIND_ALLOCATE: { - To->RequiredCapacity = To->Capacity + From->RequiredCapacity - From->Capacity; + Op->Allocate.Pointer = KBTS_MALLOC(Data, Op->Allocate.Size); + } break; + + case KBTS_ALLOCATOR_OP_KIND_FREE: + { + KBTS_FREE(Data, Op->Free.Pointer); + } break; } } -static kbts_glyph_array kbts_GlyphSubArray(kbts_glyph_array *Source, kbts_un FromIndex) +static void *kbts__AllocatorAllocate(kbts_allocator_function *Allocator, void *AllocatorData, kbts_un Size) { - kbts_glyph_array Result = KBTS_ZERO; - Result.Glyphs = Source->Glyphs + FromIndex; - Result.Count = (kbts_u32)(Source->Count - FromIndex); - Result.TotalCount = (kbts_u32)(Source->TotalCount - FromIndex); - Result.Capacity = (kbts_u32)(Source->Capacity - FromIndex); - return Result; -} + kbts_allocator_op AllocatorOp = KBTS__ZERO; + AllocatorOp.Kind = KBTS_ALLOCATOR_OP_KIND_ALLOCATE; + AllocatorOp.Allocate.Size = (kbts_u32)Size; -static kbts_glyph_array kbts_GlyphArray(kbts_glyph *Glyphs, kbts_un Count, kbts_un TotalCount, kbts_un Capacity) -{ - kbts_glyph_array Result = KBTS_ZERO; - Result.Glyphs = Glyphs; - Result.Count = (kbts_u32)Count; - Result.TotalCount = (kbts_u32)TotalCount; - Result.Capacity = (kbts_u32)Capacity; - return Result; -} - -static int kbts_GrowGlyphArray(kbts_u32 *ResumePoint_, kbts_glyph_array *Array, kbts_un InsertIndex, kbts_un GrowCount, kbts_u32 ResumePoint, int DoNotModifyGlyphCounts) -{ - int Result = 0; - kbts_un TotalCount = Array->TotalCount; - kbts_un NewTotalCount = TotalCount + GrowCount; - - if(NewTotalCount <= Array->Capacity) + if(!Allocator) { - if(NewTotalCount > TotalCount) + Allocator = kbts__DefaultAllocator; + } + + Allocator(AllocatorData, &AllocatorOp); + + void *Result = AllocatorOp.Allocate.Pointer; + return Result; +} +#define kbts__AllocatorAllocateType(Allocator, AllocatorData, Type) (Type *)kbts_AllocatorAllocate((Allocator), (AllocatorData), sizeof(Type)) +#define kbts__AllocatorAllocateArray(Allocator, AllocatorData, Type, Count) (Type *)kbts_AllocatorAllocate((Allocator), (AllocatorData), sizeof(Type) * (Count)) + +static void kbts__AllocatorFree(kbts_allocator_function *Allocator, void *AllocatorData, void *Pointer) +{ + if(Pointer) + { + kbts_allocator_op AllocatorOp = KBTS__ZERO; + AllocatorOp.Kind = KBTS_ALLOCATOR_OP_KIND_FREE; + AllocatorOp.Free.Pointer = Pointer; + + if(!Allocator) { - for(kbts_un ToIndex = NewTotalCount; ToIndex > InsertIndex + GrowCount; --ToIndex) + Allocator = kbts__DefaultAllocator; + } + + Allocator(AllocatorData, &AllocatorOp); + } +} + +static void kbts__EnsureArenaInitialized(kbts_arena *Arena) +{ + if(!Arena->BlockSentinel.Next) + { + KBTS__DLLIST_SENTINEL_INIT(&Arena->BlockSentinel); + KBTS__DLLIST_SENTINEL_INIT(&Arena->FreeBlockSentinel); + + if(!Arena->Allocator) + { + Arena->Allocator = kbts__DefaultAllocator; + } + } +} + +#define KBTS_ARENA_MIN_BLOCK_SIZE 4096 +static kbts__arena_block *kbts__ArenaPushBlock(kbts_arena *Arena, kbts_un Size, kbts_un Align) +{ + kbts__arena_block *Result = (kbts__arena_block *)&Arena->BlockSentinel; + + if(!Arena->Error) + { + kbts_un BlockSize = sizeof(kbts__arena_block) + Size + KBTS_ALIGNOF(kbts__arena_block) + Align - 1; + if(BlockSize < KBTS_ARENA_MIN_BLOCK_SIZE) + { + BlockSize = KBTS_ARENA_MIN_BLOCK_SIZE; + } + + Result = (kbts__arena_block *)Arena->FreeBlockSentinel.Prev; + if((Result == (kbts__arena_block *)&Arena->FreeBlockSentinel) || + ((Result->Size + sizeof(kbts__arena_block)) < BlockSize)) + { + void *Base = kbts__AllocatorAllocate(Arena->Allocator, Arena->AllocatorData, BlockSize); + + if(Base) { - Array->Glyphs[ToIndex - 1] = Array->Glyphs[ToIndex - 1 - GrowCount]; + Result = KBTS__ALIGN_POINTER(kbts__arena_block, Base, KBTS_ALIGNOF(kbts__arena_block)); + KBTS_MEMSET(Result, 0, sizeof(*Result)); + Result->BaseAllocation = Base; + Result->Size = (kbts_un)(KBTS__POINTER_OFFSET(char, Base, BlockSize) - KBTS__POINTER_AFTER(char, Result)); + } + else + { + Result = (kbts__arena_block *)&Arena->BlockSentinel; + Arena->Error = 1; } } - else if(NewTotalCount < TotalCount) + else { - // Multiple substitutions that generate 0 glyphs exist. In that case, GrowCount will be negative. - KBTS_FOR(ToIndex, InsertIndex, NewTotalCount) + KBTS__DLLIST_REMOVE(&Result->Header); + } + + KBTS__DLLIST_INSERT_BEFORE(&Result->Header, &Arena->BlockSentinel); + + Result->Used = 0; + } + + return Result; +} + +static int kbts__ArenaBlockIsValid(kbts_arena *Arena, kbts__arena_block *Block) +{ + int Result = Block && (&Block->Header != &Arena->BlockSentinel); + return Result; +} + +static void kbts__ClearArena(kbts_arena *Arena) +{ + kbts__EnsureArenaInitialized(Arena); + + kbts_arena_block_header *First = Arena->BlockSentinel.Next; + kbts_arena_block_header *Last = Arena->BlockSentinel.Prev; + + if(kbts__ArenaBlockIsValid(Arena, (kbts__arena_block *)First)) + { + First->Prev = Arena->FreeBlockSentinel.Prev; + Last->Next = &Arena->FreeBlockSentinel; + + First->Prev->Next = First; + Last->Next->Prev = Last; + + KBTS__DLLIST_SENTINEL_INIT(&Arena->BlockSentinel); + } +} + +static void *kbts__PushSize(kbts_arena *Arena, kbts_un Size, kbts_un Align) +{ + kbts__EnsureArenaInitialized(Arena); + void *Result = 0; + + if(!Arena->Error) + { + kbts__arena_block *Block = (kbts__arena_block *)Arena->BlockSentinel.Prev; + char *BlockMemory = KBTS__POINTER_AFTER(char, Block); + + if(kbts__ArenaBlockIsValid(Arena, Block)) + { + char *Top = BlockMemory + Block->Used; + char *TopAligned = KBTS__ALIGN_POINTER(char, Top, Align); + + if((kbts_un)((TopAligned + Size) - BlockMemory) <= Block->Size) { - Array->Glyphs[ToIndex] = Array->Glyphs[ToIndex - GrowCount]; + Result = TopAligned; } } - if(!DoNotModifyGlyphCounts) + if(!Result) { - Array->Count += GrowCount; - Array->TotalCount = (kbts_u32)NewTotalCount; + Block = kbts__ArenaPushBlock(Arena, Size, Align); + + if(kbts__ArenaBlockIsValid(Arena, Block)) + { + BlockMemory = KBTS__POINTER_AFTER(char, Block); + char *Top = BlockMemory + Block->Used; + char *TopAligned = KBTS__ALIGN_POINTER(char, Top, Align); + + Result = TopAligned; + } } - Result = 1; + + if(Result) + { + Block->Used = (kbts_un)((char *)Result + Size - BlockMemory); + KBTS_ASSERT(Block->Used <= Block->Size); + } + } + + return Result; +} +#define kbts__PushType(Arena, Type) (Type *)kbts__PushSize((Arena), sizeof(Type), KBTS_ALIGNOF(Type)) +#define kbts__PushArray(Arena, Type, Count) (Type *)kbts__PushSize((Arena), sizeof(Type) * (Count), KBTS_ALIGNOF(Type)) + +static kbts__arena_lifetime kbts__BeginLifetime(kbts_arena *Arena) +{ + kbts__arena_block *Block = (kbts__arena_block *)Arena->BlockSentinel.Prev; + kbts_un Used = 0; + + if(!Block) + { + Block = (kbts__arena_block *)&Arena->BlockSentinel; + } + + if(kbts__ArenaBlockIsValid(Arena, Block)) + { + Used = Block->Used; + } + + kbts__arena_lifetime Result = KBTS__ZERO; + Result.Arena = Arena; + Result.BlockHeader = &Block->Header; + Result.Used = Used; + return Result; +} + +static void kbts__EndLifetime(kbts__arena_lifetime *Lifetime) +{ + kbts_arena *Arena = Lifetime->Arena; + if(Arena && !Arena->Error) + { + kbts__arena_block *Block = (kbts__arena_block *)Lifetime->BlockHeader; + + if(kbts__ArenaBlockIsValid(Lifetime->Arena, Block)) + { + Block->Used = Lifetime->Used; + } + + // This works even if Block is the sentinel. + for(kbts_arena_block_header *Header = Block->Header.Next; + kbts__ArenaBlockIsValid(Arena, (kbts__arena_block *)Header); + ) + { + kbts_arena_block_header *Next = Header->Next; + + KBTS__DLLIST_REMOVE(Header); + KBTS__DLLIST_INSERT_BEFORE(Header, &Arena->FreeBlockSentinel); + + Header = Next; + } + } +} + +static void kbts__MoveArena(kbts_arena *To, kbts_arena *From) +{ + *To = *From; + + if(To->BlockSentinel.Next != &From->BlockSentinel) + { + To->BlockSentinel.Next->Prev = To->BlockSentinel.Prev->Next = &To->BlockSentinel; } else { - Array->RequiredCapacity = (kbts_u32)(NewTotalCount + KBTS_GROW_BUFFER_MARGIN); - if(ResumePoint_) *ResumePoint_ = ResumePoint; + KBTS__DLLIST_SENTINEL_INIT(&To->BlockSentinel); + } + + if(To->FreeBlockSentinel.Next != &From->FreeBlockSentinel) + { + To->FreeBlockSentinel.Next->Prev = To->FreeBlockSentinel.Prev->Next = &To->FreeBlockSentinel; + } + else + { + KBTS__DLLIST_SENTINEL_INIT(&To->FreeBlockSentinel); + } +} + +static void kbts__FreeArena(kbts_arena *Arena) +{ + kbts__EnsureArenaInitialized(Arena); + + kbts_arena StackArena; + kbts__MoveArena(&StackArena, Arena); + + kbts_arena_block_header *Sentinels[2] = {&StackArena.BlockSentinel, &StackArena.FreeBlockSentinel}; + + KBTS__FOR(SentinelIndex, 0, KBTS__ARRAY_LENGTH(Sentinels)) + { + kbts_arena_block_header *Sentinel = Sentinels[SentinelIndex]; + + for(kbts_arena_block_header *Header = Sentinel->Next; + Header != Sentinel; + ) + { + kbts_arena_block_header *Next = Header->Next; + kbts__arena_block *Block = (kbts__arena_block *)Header; + + kbts__AllocatorFree(StackArena.Allocator, StackArena.AllocatorData, Block->BaseAllocation); + + Header = Next; + } + } +} + +static void kbts__ArenaAllocator(void *Data, kbts_allocator_op *Op) +{ + kbts_arena *Arena = (kbts_arena *)Data; + + if(Op->Kind == KBTS_ALLOCATOR_OP_KIND_ALLOCATE) + { + Op->Allocate.Pointer = kbts__PushSize(Arena, Op->Allocate.Size, 8); + } + // No free! +} + +static int kbts__InitializeFixedMemoryArena(kbts_arena *Arena, void *Memory, kbts_un MemorySize) +{ + int Result = 0; + KBTS_MEMSET(Arena, 0, sizeof(*Arena)); + Arena->Allocator = kbts__NullAllocator; + kbts__EnsureArenaInitialized(Arena); + + char *BaseAligned = KBTS__ALIGN_POINTER(char, Memory, KBTS_ALIGNOF(kbts__arena_block)); + char *End = (char *)Memory + MemorySize; + kbts_un TotalBlockSize = (kbts_un)(End - BaseAligned); + + if(TotalBlockSize >= sizeof(kbts__arena_block)) + { + kbts__arena_block *Block = (kbts__arena_block *)BaseAligned; + + Block->Header.Prev = Block->Header.Next = &Arena->BlockSentinel; + Block->Header.Prev->Next = Block->Header.Next->Prev = &Block->Header; + Block->BaseAllocation = 0; + Block->Size = TotalBlockSize - sizeof(kbts__arena_block); + Block->Used = 0; + + Result = 1; } return Result; } -static void kbts_BeginFeatures(kbts_op_state *State, kbts_shape_config *Config, kbts_shaping_table ShapingTable, kbts_feature_set EnabledFeatures) +static kbts_glyph *kbts__InsertGlyph(kbts_glyph_storage *Storage, kbts_glyph *Anchor, int InsertBeforeAnchor, kbts_glyph *BaseGlyph) { - kbts_un FeatureCount = 0; - kbts_gsub_gpos *Header = Config->Font->ShapingTables[ShapingTable]; - kbts_langsys *Langsys = Config->Langsys[ShapingTable]; - if(Header && Langsys) + kbts_glyph *Result = Storage->FreeGlyphSentinel.Next; + + if(Result != &Storage->FreeGlyphSentinel) { - kbts_feature_list *FeatureList = KBTS_POINTER_OFFSET(kbts_feature_list, Header, Header->FeatureListOffset); - kbts_u16 *FeatureIndices = KBTS_POINTER_AFTER(kbts_u16, Langsys); - // @Incomplete - // if(Header->Minor == 1) - // { - // kbts_feature_variations *FeatureVariations = KBTS_POINTER_OFFSET(kbts_feature_variations, Header, Header->FeatureVariationsOffset); - // } - - KBTS_FOR(FeatureIndexIndex, 0, Langsys->FeatureIndexCount) - { - kbts_un FeatureIndex = FeatureIndices[FeatureIndexIndex]; - kbts_feature_pointer Feature = kbts_GetFeature(FeatureList, FeatureIndex); - // @Incomplete - //if(FeatureVariations) - //{ - // KBTS_FOR(VariationIndex, 0, FeatureVariations->RecordCount) - // { - // kbts_feature_variation_pointer Variation = kbts_GetFeatureVariation(FeatureVariations, VariationIndex); - // KBTS_FOR(ConditionIndex, 0, Variation.ConditionSet->Count) - // { - // kbts_condition_1 *Condition = kbts_GetCondition(Variation.ConditionSet, ConditionIndex); - // KBTS_ASSERT(0); - // } - // } - //} - - kbts_u32 FeatureId = kbts_FeatureTagToId(Feature.Tag); - if(Feature.Feature->LookupIndexCount && kbts_ContainsFeature(&EnabledFeatures, FeatureId)) - { - kbts_lookup_indices LookupIndices = KBTS_ZERO; - LookupIndices.FeatureTag = Feature.Tag; - LookupIndices.FeatureId = FeatureId; - LookupIndices.SkipFlags = kbts_SkipFlags(FeatureId, Config->Shaper); - // For Myanmar, we could try and tag glyphs depending on their Indic properties in BeginCluster, just like we do for - // Indic scripts. - // However, Harfbuzz does _not_ do this, so it seems like a bunch of work that would, at best, make us diverge from - // Harfbuzz more often. - if((Config->Shaper != KBTS_SHAPER_MYANMAR) && (FeatureId >= 1) && (FeatureId <= 32)) - { - // These must properly map KBTS_FEATURE_ID to kbts_glyph_flags! - LookupIndices.GlyphFilter = (1 << (FeatureId - 1)) & KBTS_GLYPH_FEATURE_MASK; - } - LookupIndices.Count = Feature.Feature->LookupIndexCount; - LookupIndices.Indices = KBTS_POINTER_AFTER(kbts_u16, Feature.Feature); - State->FeatureLookupIndices[FeatureCount++] = LookupIndices; - } - } + KBTS__DLLIST_REMOVE(Result); } - State->FeatureCount = (kbts_u32)FeatureCount; + else + { + Result = kbts__PushType(&Storage->Arena, kbts_glyph); + } + + if(Result) + { + if(BaseGlyph) + { + *Result = *BaseGlyph; + } + + if(InsertBeforeAnchor) + { + Result->Next = Anchor; + Result->Prev = Anchor->Prev; + } + else + { + Result->Prev = Anchor; + Result->Next = Anchor->Next; + } + + Result->Prev->Next = Result->Next->Prev = Result; + } + else + { + Storage->Error = 1; + } + + return Result; +} +static kbts_glyph *kbts__InsertGlyphBefore(kbts_glyph_storage *Storage, kbts_glyph *Anchor, kbts_glyph *BaseGlyph) +{ + kbts_glyph *Result = kbts__InsertGlyph(Storage, Anchor, 1, BaseGlyph); + return Result; +} +static kbts_glyph *kbts__InsertGlyphAfter(kbts_glyph_storage *Storage, kbts_glyph *Anchor, kbts_glyph *BaseGlyph) +{ + kbts_glyph *Result = kbts__InsertGlyph(Storage, Anchor, 0, BaseGlyph); + return Result; } -typedef struct kbts_sequence_lookup_result +static kbts_glyph *kbts__FreeGlyph(kbts__shape_scratchpad *Scratchpad, kbts_glyph_storage *Storage, kbts_glyph *Glyph) { - kbts_sequence_lookup_record *Records; + if(Glyph == Scratchpad->LookupOnePastLastGlyph) + { + Scratchpad->LookupOnePastLastGlyph = Glyph->Next; + } + if(Glyph == Scratchpad->Cluster.SentinelPrev) + { + Scratchpad->Cluster.SentinelPrev = Glyph->Prev; + } + if(Glyph == Scratchpad->Cluster.SentinelNext) + { + Scratchpad->Cluster.SentinelNext = Glyph->Next; + } + + KBTS__DLLIST_REMOVE(Glyph); + KBTS__DLLIST_INSERT_BEFORE(Glyph, (kbts_glyph *)&Storage->FreeGlyphSentinel); + + return Glyph; +} + +static kbts_glyph *kbts__SetGlyphPreserveLinksAndUserId(kbts_glyph *Dest, kbts_glyph *Source) +{ + kbts_glyph *Prev = Dest->Prev; + kbts_glyph *Next = Dest->Next; + int UserId = Dest->UserIdOrCodepointIndex; + + *Dest = *Source; + + Dest->Prev = Prev; + Dest->Next = Next; + Dest->UserIdOrCodepointIndex = UserId; + + return Dest; +} + +static int kbts__BeginFeatures(kbts__shape_scratchpad *Scratchpad, kbts_shape_config *Config, kbts_shaping_table ShapingTable) +{ + int Result = 0; + kbts_blob_table_id TableId = (ShapingTable == KBTS_SHAPING_TABLE_GSUB) ? KBTS_BLOB_TABLE_ID_GSUB : KBTS_BLOB_TABLE_ID_GPOS; + kbts__gsub_gpos *GsubGpos = kbts__BlobTableDataType(Config->Font->Blob, TableId, kbts__gsub_gpos); + kbts__langsys *Langsys = Config->Langsys[ShapingTable]; + kbts_un FeatureStageIndex = Scratchpad->FeatureStagesRead - 1; + + Scratchpad->FeatureIndexIndex = 0; + + if(GsubGpos && Langsys && (FeatureStageIndex < Config->OpList.FeatureStageCount)) + { + kbts__baked_feature_stage *BakedFeatureStage = &Config->FeatureStages[FeatureStageIndex]; + + // @Incomplete + // if(GsubGpos->Minor == 1) + // { + // kbts__feature_variations *FeatureVariations = KBTS__POINTER_OFFSET(kbts__feature_variations, GsubGpos, GsubGpos->FeatureVariationsOffset); + // } + + + KBTS__FOR(FeatureIndex, 0, BakedFeatureStage->FeatureCount) + { + Scratchpad->BakedLookupSubtablesRead[FeatureIndex] = 0; + } + + Result = 1; + } + + return Result; +} + +typedef struct kbts__sequence_lookup_result +{ + kbts__sequence_lookup_record *Records; kbts_un RecordCount; kbts_un InputSequenceCountIncludingSkippedGlyphs; + kbts_glyph *OnePastLastGlyphMatched; + // This is specified _nowhere_ in the docs, BUT some sequence lookups have 0 records, and exist just to prevent the // next lookups from executing. // So, checking if we got any records is not enough to figure out whether we need to "apply" this lookup. // We need to have an explicit bool as well. // Sigh. int Matched; -} kbts_sequence_lookup_result; +} kbts__sequence_lookup_result; -typedef struct kbts_sequence_match +typedef struct kbts__sequence_match { kbts_un MatchCount; kbts_un MatchOrSkipCount; -} kbts_sequence_match; + kbts_glyph *OnePastMatchGlyph; +} kbts__sequence_match; -static kbts_sequence_match kbts_MatchCoverageSequence(kbts_unpacked_lookup *Lookup, kbts_u32 SkipFlags, kbts_u32 SkipUnicodeFlags, +static kbts__sequence_match kbts__MatchCoverageSequence(kbts_glyph_storage *Storage, kbts__unpacked_lookup *Lookup, kbts_u32 SkipFlags, kbts_u32 SkipUnicodeFlags, void *Base, kbts_u16 *CoverageOffsets, kbts_un CoverageCount, - kbts_glyph_array *GlyphArray, kbts_un GlyphStartIndex, kbts_un GlyphIndexIncrement) + kbts_glyph *AtGlyph, int Backward) { kbts_un CoverageIndex = 0; kbts_un GlyphCounter = 0; - kbts_un GlyphIndex = GlyphStartIndex; - while((GlyphCounter < GlyphArray->Count) && (CoverageIndex < CoverageCount)) + while(kbts__GlyphIsValid(Storage, AtGlyph) && (CoverageIndex < CoverageCount)) { - kbts_glyph *Glyph = &GlyphArray->Glyphs[GlyphIndex]; - kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Base, CoverageOffsets[CoverageIndex]); + kbts__coverage *Coverage = KBTS__POINTER_OFFSET(kbts__coverage, Base, CoverageOffsets[CoverageIndex]); - if(!kbts_SkipGlyph(Glyph, Lookup, SkipFlags, SkipUnicodeFlags)) + if(!kbts__SkipGlyph(AtGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) { - kbts_cover_glyph_result Cover = kbts_CoverGlyph(Coverage, Glyph->Id); + kbts__cover_glyph_result Cover = kbts__CoverGlyph(Coverage, AtGlyph->Id); if(Cover.Valid) { @@ -16901,41 +19739,38 @@ static kbts_sequence_match kbts_MatchCoverageSequence(kbts_unpacked_lookup *Look } } - GlyphIndex += GlyphIndexIncrement; + AtGlyph = Backward ? AtGlyph->Prev : AtGlyph->Next; GlyphCounter += 1; } - kbts_sequence_match Result = KBTS_ZERO; + kbts__sequence_match Result = KBTS__ZERO; Result.MatchCount = CoverageIndex; Result.MatchOrSkipCount = GlyphCounter; + Result.OnePastMatchGlyph = AtGlyph; return Result; } -static int kbts_BranchlessCompareArray16(kbts_u16 *A, kbts_u16 *B, kbts_un Count) +static int kbts__BranchlessCompareArray16(kbts_u16 *A, kbts_u16 *B, kbts_un Count) { kbts_u16 DifferenceMask = 0; - KBTS_FOR(Index, 0, Count) + KBTS__FOR(Index, 0, Count) { DifferenceMask |= A[Index] ^ B[Index]; } return (int)DifferenceMask; } -static kbts_sequence_lookup_result kbts_DoSequenceLookup(kbts_unpacked_lookup *Lookup, kbts_u16 *Base, kbts_cover_glyph_result Cover, - kbts_glyph_array *GlyphArray, kbts_un InputGlyphOffset, kbts_skip_flags SkipFlags, kbts_u32 SkipUnicodeFlags) +static kbts__sequence_lookup_result kbts__DoSequenceLookup(kbts_glyph_storage *Storage, kbts__unpacked_lookup *Lookup, kbts_u16 *Base, kbts__cover_glyph_result Cover, + kbts_glyph *AtGlyph, kbts__skip_flags SkipFlags, kbts_u32 SkipUnicodeFlags) { - KBTS_INSTRUMENT_FUNCTION_BEGIN - kbts_sequence_lookup_result Result = KBTS_ZERO; + KBTS_INSTRUMENT_FUNCTION_BEGIN; + kbts__sequence_lookup_result Result = KBTS__ZERO; + Result.OnePastLastGlyphMatched = AtGlyph->Next; - kbts_glyph_array BacktrackGlyphs = kbts_ClipGlyphArray(GlyphArray, InputGlyphOffset); - kbts_glyph_array InputGlyphs = kbts_GlyphSubArray(GlyphArray, InputGlyphOffset); - kbts_glyph_array FollowupGlyphs = kbts_GlyphSubArray(&InputGlyphs, 1); - - kbts_glyph *FirstGlyph = &GlyphArray->Glyphs[0]; - kbts_glyph *CurrentGlyph = &GlyphArray->Glyphs[InputGlyphOffset]; - kbts_glyph *InputGlyph = &GlyphArray->Glyphs[InputGlyphOffset + 1]; - kbts_glyph *OnePastLastGlyph = &GlyphArray->Glyphs[GlyphArray->Count]; - kbts_glyph *BacktrackGlyph = &GlyphArray->Glyphs[InputGlyphOffset - 1]; + kbts_glyph *CurrentGlyph = AtGlyph; + kbts_glyph *InputGlyph = AtGlyph->Next; + kbts_un InputGlyphsTraversed = 1; + kbts_glyph *BacktrackGlyph = AtGlyph->Prev; // Lookup types 7 and 8 are dispatch mechanisms. They do not substitute anything by themselves, they only point to // other rules. @@ -16949,43 +19784,47 @@ static kbts_sequence_lookup_result kbts_DoSequenceLookup(kbts_unpacked_lookup *L case 0x50001: case 0x70001: { - kbts_sequence_context_1 *Subst = (kbts_sequence_context_1 *)Base; - kbts_sequence_rule_set *Set = kbts_GetSequenceRuleSet(Subst, Cover.Index); + kbts__sequence_context_1 *Subst = (kbts__sequence_context_1 *)Base; + kbts__sequence_rule_set *Set = kbts__GetSequenceRuleSet(Subst, Cover.Index); if(Set) { kbts_u16 Ids[64]; // @Hardcoded - kbts_u16 GlyphOffsets[64]; + kbts_u16 InputGlyphOffsets[64]; + kbts_glyph *InputGlyphs[64]; kbts_un IdCount = 0; - KBTS_FOR(RuleIndex, 0, Set->Count) + KBTS__FOR(RuleIndex, 0, Set->Count) { - kbts_sequence_rule *Rule = kbts_GetSequenceRule(Set, RuleIndex); - kbts_u16 *InputSequence = KBTS_POINTER_AFTER(kbts_u16, Rule); + kbts__sequence_rule *Rule = kbts__GetSequenceRule(Set, RuleIndex); + kbts_u16 *InputSequence = KBTS__POINTER_AFTER(kbts_u16, Rule); // @Hardcoded! KBTS_ASSERT(Rule->GlyphCount <= 64); - while((InputGlyph < OnePastLastGlyph) && ((IdCount + 1) < Rule->GlyphCount)) + while(kbts__GlyphIsValid(Storage, InputGlyph) && ((IdCount + 1) < Rule->GlyphCount)) { - if(!kbts_SkipGlyph(InputGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) + if(!kbts__SkipGlyph(InputGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) { - GlyphOffsets[IdCount] = (kbts_u16)(InputGlyph - CurrentGlyph); + InputGlyphOffsets[IdCount] = (kbts_u16)InputGlyphsTraversed; + InputGlyphs[IdCount] = InputGlyph; Ids[IdCount++] = InputGlyph->Id; } - InputGlyph += 1; + InputGlyph = InputGlyph->Next; + InputGlyphsTraversed += 1; } if(((IdCount + 1) >= Rule->GlyphCount) && - !kbts_BranchlessCompareArray16(Ids, InputSequence, Rule->GlyphCount - 1)) + !kbts__BranchlessCompareArray16(Ids, InputSequence, Rule->GlyphCount - 1)) { - Result.Records = (kbts_sequence_lookup_record *)(InputSequence + Rule->GlyphCount - 1); + Result.Records = (kbts__sequence_lookup_record *)(InputSequence + Rule->GlyphCount - 1); Result.RecordCount = Rule->SequenceLookupCount; Result.InputSequenceCountIncludingSkippedGlyphs = 1; if(Rule->GlyphCount > 1) { - Result.InputSequenceCountIncludingSkippedGlyphs = GlyphOffsets[Rule->GlyphCount - 2] + 1; + Result.InputSequenceCountIncludingSkippedGlyphs = InputGlyphOffsets[Rule->GlyphCount - 2] + 1; + Result.OnePastLastGlyphMatched = InputGlyphs[Rule->GlyphCount - 2]->Next; } Result.Matched = 1; @@ -16999,48 +19838,52 @@ static kbts_sequence_lookup_result kbts_DoSequenceLookup(kbts_unpacked_lookup *L case 0x50002: case 0x70002: { - kbts_sequence_context_2 *Subst = (kbts_sequence_context_2 *)Base; - kbts_u16 *ClassDefinitionBase = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->ClassDefOffset); + kbts__sequence_context_2 *Subst = (kbts__sequence_context_2 *)Base; + kbts_u16 *ClassDefinitionBase = KBTS__POINTER_OFFSET(kbts_u16, Subst, Subst->ClassDefOffset); // @Hardcoded! kbts_u16 InputClasses[64]; kbts_u16 InputOffsets[64]; + kbts_glyph *InputGlyphs[64]; kbts_un InputCount = 0; // For class-based contexts, the coverage index is not used. // Instead, we know which set to use based on the current glyph's class. // From the Microsoft docs: // The class value is used as the index into an array of offsets to ClassSequenceRuleSet tables. - kbts_glyph_class_from_table_result CurrentGlyphClass = kbts_GlyphClassFromTable(ClassDefinitionBase, CurrentGlyph->Id); - kbts_class_sequence_rule_set *Set = kbts_GetClassSequenceRuleSet(Subst, CurrentGlyphClass.Class); + kbts__glyph_class_from_table_result CurrentGlyphClass = kbts__GlyphClassFromTable(ClassDefinitionBase, CurrentGlyph->Id); + kbts__class_sequence_rule_set *Set = kbts__GetClassSequenceRuleSet(Subst, CurrentGlyphClass.Class); if((CurrentGlyphClass.Class < Subst->ClassSequenceRuleSetCount) && Set) { - KBTS_FOR(RuleIndex, 0, Set->Count) + KBTS__FOR(RuleIndex, 0, Set->Count) { - kbts_class_sequence_rule *Rule = kbts_GetClassSequenceRule(Set, RuleIndex); - kbts_u16 *InputSequence = KBTS_POINTER_AFTER(kbts_u16, Rule); + kbts__class_sequence_rule *Rule = kbts__GetClassSequenceRule(Set, RuleIndex); + kbts_u16 *InputSequence = KBTS__POINTER_AFTER(kbts_u16, Rule); - while((InputGlyph < OnePastLastGlyph) && ((InputCount + 1) < Rule->GlyphCount)) + while(kbts__GlyphIsValid(Storage, InputGlyph) && ((InputCount + 1) < Rule->GlyphCount)) { - if(!kbts_SkipGlyph(InputGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) + if(!kbts__SkipGlyph(InputGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) { - InputOffsets[InputCount] = (kbts_u16)(InputGlyph - CurrentGlyph); - InputClasses[InputCount++] = kbts_GlyphClassFromTable(ClassDefinitionBase, InputGlyph->Id).Class; + InputOffsets[InputCount] = (kbts_u16)InputGlyphsTraversed; + InputGlyphs[InputCount] = InputGlyph; + InputClasses[InputCount++] = kbts__GlyphClassFromTable(ClassDefinitionBase, InputGlyph->Id).Class; } - InputGlyph += 1; + InputGlyph = InputGlyph->Next; + InputGlyphsTraversed += 1; } if(((InputCount + 1) >= Rule->GlyphCount) && - !kbts_BranchlessCompareArray16(InputClasses, InputSequence, Rule->GlyphCount - 1)) + !kbts__BranchlessCompareArray16(InputClasses, InputSequence, Rule->GlyphCount - 1)) { - Result.Records = (kbts_sequence_lookup_record *)(InputSequence + Rule->GlyphCount - 1); + Result.Records = (kbts__sequence_lookup_record *)(InputSequence + Rule->GlyphCount - 1); Result.RecordCount = Rule->SequenceLookupCount; Result.InputSequenceCountIncludingSkippedGlyphs = 1; if(Rule->GlyphCount > 1) { Result.InputSequenceCountIncludingSkippedGlyphs = InputOffsets[Rule->GlyphCount - 2] + 1; + Result.OnePastLastGlyphMatched = InputGlyphs[Rule->GlyphCount - 2]->Next; } Result.Matched = 1; @@ -17054,16 +19897,17 @@ static kbts_sequence_lookup_result kbts_DoSequenceLookup(kbts_unpacked_lookup *L case 0x50003: case 0x70003: { - kbts_sequence_context_3 *Subst = (kbts_sequence_context_3 *)Base; - kbts_u16 *CoverageOffsets = KBTS_POINTER_AFTER(kbts_u16, Subst); + kbts__sequence_context_3 *Subst = (kbts__sequence_context_3 *)Base; + kbts_u16 *CoverageOffsets = KBTS__POINTER_AFTER(kbts_u16, Subst); - kbts_sequence_match InputMatch = kbts_MatchCoverageSequence(Lookup, SkipFlags, SkipUnicodeFlags, Subst, CoverageOffsets, Subst->GlyphCount, &InputGlyphs, 0, 1); + kbts__sequence_match InputMatch = kbts__MatchCoverageSequence(Storage, Lookup, SkipFlags, SkipUnicodeFlags, Subst, CoverageOffsets, Subst->GlyphCount, AtGlyph, 0); if(InputMatch.MatchCount == Subst->GlyphCount) { - Result.Records = (kbts_sequence_lookup_record *)(CoverageOffsets + Subst->GlyphCount); + Result.Records = (kbts__sequence_lookup_record *)(CoverageOffsets + Subst->GlyphCount); Result.RecordCount = Subst->SequenceLookupCount; Result.InputSequenceCountIncludingSkippedGlyphs = InputMatch.MatchOrSkipCount; + Result.OnePastLastGlyphMatched = InputMatch.OnePastMatchGlyph; Result.Matched = 1; } } @@ -17072,8 +19916,8 @@ static kbts_sequence_lookup_result kbts_DoSequenceLookup(kbts_unpacked_lookup *L case 0x60001: case 0x80001: { - kbts_chained_sequence_context_1 *Subst = (kbts_chained_sequence_context_1 *)Base; - kbts_chained_sequence_rule_set *Set = kbts_GetChainedSequenceRuleSet(Subst, Cover.Index); + kbts__chained_sequence_context_1 *Subst = (kbts__chained_sequence_context_1 *)Base; + kbts__chained_sequence_rule_set *Set = kbts__GetChainedSequenceRuleSet(Subst, Cover.Index); if(Set) { @@ -17081,38 +19925,43 @@ static kbts_sequence_lookup_result kbts_DoSequenceLookup(kbts_unpacked_lookup *L kbts_u16 BacktrackIds[64]; kbts_u16 InputIds[64]; kbts_u16 InputOffsets[64]; + kbts_glyph *InputGlyphs[64]; kbts_un BacktrackCount = 0; kbts_un InputCount = 0; - KBTS_FOR(RuleIndex, 0, Set->Count) + KBTS__FOR(RuleIndex, 0, Set->Count) { - kbts_chained_sequence_rule *Rule = kbts_GetChainedSequenceRule(Set, RuleIndex); - kbts_unpacked_chained_sequence_rule Unpacked = kbts_UnpackChainedSequenceRule(Rule, 0); + kbts__chained_sequence_rule *Rule = kbts__GetChainedSequenceRule(Set, RuleIndex); + kbts__unpacked_chained_sequence_rule Unpacked = kbts__UnpackChainedSequenceRule(Rule, 0); - while((BacktrackGlyph >= FirstGlyph) && (BacktrackCount < Unpacked.BacktrackCount)) + while(kbts__GlyphIsValid(Storage, BacktrackGlyph) && (BacktrackCount < Unpacked.BacktrackCount)) { - if(!kbts_SkipGlyph(BacktrackGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) + if(!kbts__SkipGlyph(BacktrackGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) { BacktrackIds[BacktrackCount++] = BacktrackGlyph->Id; } - BacktrackGlyph -= 1; + + BacktrackGlyph = BacktrackGlyph->Prev; } kbts_un TotalInputGlyphsRequired = Unpacked.InputCount - 1 + Unpacked.LookaheadCount; - while((InputGlyph < OnePastLastGlyph) && (InputCount < TotalInputGlyphsRequired)) + while(kbts__GlyphIsValid(Storage, InputGlyph) && (InputCount < TotalInputGlyphsRequired)) { - if(!kbts_SkipGlyph(InputGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) + if(!kbts__SkipGlyph(InputGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) { - InputOffsets[InputCount] = (kbts_u16)(InputGlyph - CurrentGlyph); + InputGlyphs[InputCount] = InputGlyph; + InputOffsets[InputCount] = (kbts_u16)InputGlyphsTraversed; InputIds[InputCount++] = InputGlyph->Id; } - InputGlyph += 1; + + InputGlyph = InputGlyph->Next; + InputGlyphsTraversed += 1; } if((BacktrackCount >= Unpacked.BacktrackCount) && (InputCount >= TotalInputGlyphsRequired) && - !kbts_BranchlessCompareArray16(BacktrackIds, Unpacked.Backtrack, Unpacked.BacktrackCount) && - !kbts_BranchlessCompareArray16(InputIds, Unpacked.Input, Unpacked.InputCount - 1) && - !kbts_BranchlessCompareArray16(InputIds + Unpacked.InputCount - 1, Unpacked.Lookahead, Unpacked.LookaheadCount)) + !kbts__BranchlessCompareArray16(BacktrackIds, Unpacked.Backtrack, Unpacked.BacktrackCount) && + !kbts__BranchlessCompareArray16(InputIds, Unpacked.Input, Unpacked.InputCount - 1) && + !kbts__BranchlessCompareArray16(InputIds + Unpacked.InputCount - 1, Unpacked.Lookahead, Unpacked.LookaheadCount)) { Result.Records = Unpacked.Records; Result.RecordCount = Unpacked.RecordCount; @@ -17120,6 +19969,7 @@ static kbts_sequence_lookup_result kbts_DoSequenceLookup(kbts_unpacked_lookup *L if(Unpacked.InputCount > 1) { Result.InputSequenceCountIncludingSkippedGlyphs = InputOffsets[Unpacked.InputCount - 2] + 1; + Result.OnePastLastGlyphMatched = InputGlyphs[Unpacked.InputCount - 2]->Next; } Result.Matched = 1; @@ -17133,10 +19983,10 @@ static kbts_sequence_lookup_result kbts_DoSequenceLookup(kbts_unpacked_lookup *L case 0x60002: case 0x80002: { - kbts_chained_sequence_context_2 *Subst = (kbts_chained_sequence_context_2 *)Base; - kbts_u16 *BacktrackClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->BacktrackClassDefOffset); - kbts_u16 *InputClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->InputClassDefOffset); - kbts_u16 *LookaheadClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->LookaheadClassDefOffset); + kbts__chained_sequence_context_2 *Subst = (kbts__chained_sequence_context_2 *)Base; + kbts_u16 *BacktrackClassDefinition = KBTS__POINTER_OFFSET(kbts_u16, Subst, Subst->BacktrackClassDefOffset); + kbts_u16 *InputClassDefinition = KBTS__POINTER_OFFSET(kbts_u16, Subst, Subst->InputClassDefOffset); + kbts_u16 *LookaheadClassDefinition = KBTS__POINTER_OFFSET(kbts_u16, Subst, Subst->LookaheadClassDefOffset); // @Incomplete: Do this with all sequence types! @@ -17144,6 +19994,7 @@ static kbts_sequence_lookup_result kbts_DoSequenceLookup(kbts_unpacked_lookup *L kbts_u16 BacktrackClasses[64]; kbts_u16 InputClasses[64]; kbts_u16 InputClassOffsets[64]; + kbts_glyph *InputGlyphs[64]; kbts_u16 LookaheadClasses[64]; kbts_un BacktrackClassCount = 0; kbts_un InputClassCount = 0; @@ -17154,8 +20005,8 @@ static kbts_sequence_lookup_result kbts_DoSequenceLookup(kbts_unpacked_lookup *L // current glyph. The class value is used as the index into an array of offsets to ChainedClassSequenceRuleSet // tables. // - kbts_u16 CurrentGlyphClass = kbts_GlyphClassFromTable(InputClassDefinition, CurrentGlyph->Id).Class; - kbts_chained_sequence_rule_set *Set = kbts_GetChainedClassSequenceRuleSet(Subst, CurrentGlyphClass); + kbts_u16 CurrentGlyphClass = kbts__GlyphClassFromTable(InputClassDefinition, CurrentGlyph->Id).Class; + kbts__chained_sequence_rule_set *Set = kbts__GetChainedClassSequenceRuleSet(Subst, CurrentGlyphClass); // If the glyph was contained in the coverage table, then it should have a valid class. // Nevertheless, one Harfbuzz test font did not remove out-of-bounds glyph classes from the class definition // table here, so we double-check it here. @@ -17163,59 +20014,61 @@ static kbts_sequence_lookup_result kbts_DoSequenceLookup(kbts_unpacked_lookup *L // in which case ignoring these classes becomes a feature.) if((CurrentGlyphClass < Subst->ChainedClassSequenceRuleSetCount) && Set) { - KBTS_FOR(RuleIndex, 0, Set->Count) + KBTS__FOR(RuleIndex, 0, Set->Count) { - kbts_chained_sequence_rule *Rule = kbts_GetChainedClassSequenceRule(Set, RuleIndex); - kbts_unpacked_chained_sequence_rule Unpacked = kbts_UnpackChainedSequenceRule(Rule, 0); + kbts__chained_sequence_rule *Rule = kbts__GetChainedClassSequenceRule(Set, RuleIndex); + kbts__unpacked_chained_sequence_rule Unpacked = kbts__UnpackChainedSequenceRule(Rule, 0); // @Hardcoded KBTS_ASSERT(Unpacked.BacktrackCount <= 64); KBTS_ASSERT(Unpacked.InputCount <= 64); KBTS_ASSERT(Unpacked.LookaheadCount <= 64); - while((BacktrackGlyph >= FirstGlyph) && (BacktrackClassCount < Unpacked.BacktrackCount)) + while(kbts__GlyphIsValid(Storage, BacktrackGlyph) && (BacktrackClassCount < Unpacked.BacktrackCount)) { - if(!kbts_SkipGlyph(BacktrackGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) + if(!kbts__SkipGlyph(BacktrackGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) { // @Robustness: Do we want to break if we don't find a class? - kbts_glyph_class_from_table_result Class = kbts_GlyphClassFromTable(BacktrackClassDefinition, BacktrackGlyph->Id); + kbts__glyph_class_from_table_result Class = kbts__GlyphClassFromTable(BacktrackClassDefinition, BacktrackGlyph->Id); BacktrackClasses[BacktrackClassCount++] = Class.Class; } - BacktrackGlyph -= 1; + BacktrackGlyph = BacktrackGlyph->Prev; } kbts_un InputClassCountRequired = Unpacked.InputCount - 1 + Unpacked.LookaheadCount; - while((InputGlyph < OnePastLastGlyph) && (InputClassCount < InputClassCountRequired)) + while(kbts__GlyphIsValid(Storage, InputGlyph) && (InputClassCount < InputClassCountRequired)) { - if(!kbts_SkipGlyph(InputGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) + if(!kbts__SkipGlyph(InputGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) { - kbts_glyph_class_from_table_result InputClass = kbts_GlyphClassFromTable(InputClassDefinition, InputGlyph->Id); + kbts__glyph_class_from_table_result InputClass = kbts__GlyphClassFromTable(InputClassDefinition, InputGlyph->Id); // In many cases, the font designer just wants to match "a set of glyphs" forward, // and it doesn't matter whether those glyphs are in the input sequence or part of the lookahead. // This happens often enough that we care to special-case it. - kbts_glyph_class_from_table_result LookaheadClass = InputClass; + kbts__glyph_class_from_table_result LookaheadClass = InputClass; if(LookaheadClassDefinition != InputClassDefinition) { - LookaheadClass = kbts_GlyphClassFromTable(LookaheadClassDefinition, InputGlyph->Id); + LookaheadClass = kbts__GlyphClassFromTable(LookaheadClassDefinition, InputGlyph->Id); } // @Robustness: Do we want to break if we don't find a class? - InputClassOffsets[InputClassCount] = (kbts_u16)(InputGlyph - CurrentGlyph); + InputGlyphs[InputClassCount] = InputGlyph; + InputClassOffsets[InputClassCount] = (kbts_u16)InputGlyphsTraversed; InputClasses[InputClassCount] = InputClass.Class; LookaheadClasses[InputClassCount] = LookaheadClass.Class; InputClassCount += 1; } - InputGlyph += 1; + InputGlyph = InputGlyph->Next; + InputGlyphsTraversed += 1; } if((BacktrackClassCount >= Unpacked.BacktrackCount) && (InputClassCount >= InputClassCountRequired) && - !kbts_BranchlessCompareArray16(BacktrackClasses, Unpacked.Backtrack, Unpacked.BacktrackCount) && - !kbts_BranchlessCompareArray16(InputClasses, Unpacked.Input, Unpacked.InputCount - 1) && - !kbts_BranchlessCompareArray16(LookaheadClasses + Unpacked.InputCount - 1, Unpacked.Lookahead, Unpacked.LookaheadCount)) + !kbts__BranchlessCompareArray16(BacktrackClasses, Unpacked.Backtrack, Unpacked.BacktrackCount) && + !kbts__BranchlessCompareArray16(InputClasses, Unpacked.Input, Unpacked.InputCount - 1) && + !kbts__BranchlessCompareArray16(LookaheadClasses + Unpacked.InputCount - 1, Unpacked.Lookahead, Unpacked.LookaheadCount)) { Result.Records = Unpacked.Records; Result.RecordCount = Unpacked.RecordCount; @@ -17223,6 +20076,7 @@ static kbts_sequence_lookup_result kbts_DoSequenceLookup(kbts_unpacked_lookup *L if(Unpacked.InputCount > 1) { Result.InputSequenceCountIncludingSkippedGlyphs = InputClassOffsets[Unpacked.InputCount - 2] + 1; + Result.OnePastLastGlyphMatched = InputGlyphs[Unpacked.InputCount - 2]->Next; } Result.Matched = 1; @@ -17236,36 +20090,36 @@ static kbts_sequence_lookup_result kbts_DoSequenceLookup(kbts_unpacked_lookup *L case 0x60003: case 0x80003: { - kbts_chained_sequence_context_3 *Subst = (kbts_chained_sequence_context_3 *)Base; - kbts_unpacked_chained_sequence_context_3 Unpacked = kbts_UnpackChainedSequenceContext3(Subst, 0); + kbts__chained_sequence_context_3 *Subst = (kbts__chained_sequence_context_3 *)Base; + kbts__unpacked_chained_sequence_context_3 Unpacked = kbts__UnpackChainedSequenceContext3(Subst, 0); // Since chained sequence contexts roll the coverage for the first glyph into an array, you'd think that // the matching logic for the first glyph would be the same as for any other glyph in that array. // You'd be wrong! // The first glyph does _not_ have to pass glyph filtering logic. It just has to pass the coverage test. // Every other input glyph still does, though. - kbts_cover_glyph_result CurrentCover = KBTS_ZERO; - CurrentCover.Valid = !Unpacked.InputCount || kbts_GlyphPassesLookupFilter(InputGlyphs.Glyphs, Lookup); + kbts__cover_glyph_result CurrentCover = KBTS__ZERO; + CurrentCover.Valid = !Unpacked.InputCount || kbts__GlyphPassesLookupFilter(CurrentGlyph, Lookup); if(Unpacked.InputCount) { - kbts_coverage *CurrentCoverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.InputCoverageOffsets[0]); - CurrentCover = kbts_CoverGlyph(CurrentCoverage, InputGlyphs.Glyphs[0].Id); + kbts__coverage *CurrentCoverage = KBTS__POINTER_OFFSET(kbts__coverage, Subst, Unpacked.InputCoverageOffsets[0]); + CurrentCover = kbts__CoverGlyph(CurrentCoverage, CurrentGlyph->Id); } if(CurrentCover.Valid) { - kbts_sequence_match BacktrackMatch = kbts_MatchCoverageSequence(Lookup, SkipFlags, SkipUnicodeFlags, Subst, Unpacked.BacktrackCoverageOffsets, Unpacked.BacktrackCount, &BacktrackGlyphs, BacktrackGlyphs.Count - 1, -1); - kbts_sequence_match InputMatch = kbts_MatchCoverageSequence(Lookup, SkipFlags, SkipUnicodeFlags, Subst, Unpacked.InputCoverageOffsets + 1, Unpacked.InputCount - 1, &FollowupGlyphs, 0, 1); + kbts__sequence_match BacktrackMatch = kbts__MatchCoverageSequence(Storage, Lookup, SkipFlags, SkipUnicodeFlags, Subst, Unpacked.BacktrackCoverageOffsets, Unpacked.BacktrackCount, BacktrackGlyph, 1); + kbts__sequence_match InputMatch = kbts__MatchCoverageSequence(Storage, Lookup, SkipFlags, SkipUnicodeFlags, Subst, Unpacked.InputCoverageOffsets + 1, Unpacked.InputCount - 1, InputGlyph, 0); kbts_un MatchingInputGlyphCount = 1 + InputMatch.MatchCount; kbts_un MatchedOrSkippedInputGlyphCount = 1 + InputMatch.MatchOrSkipCount; - kbts_glyph_array LookaheadGlyphs = kbts_GlyphSubArray(&InputGlyphs, MatchedOrSkippedInputGlyphCount); - kbts_sequence_match LookaheadMatch = kbts_MatchCoverageSequence(Lookup, SkipFlags, SkipUnicodeFlags, Subst, Unpacked.LookaheadCoverageOffsets, Unpacked.LookaheadCount, &LookaheadGlyphs, 0, 1); + kbts__sequence_match LookaheadMatch = kbts__MatchCoverageSequence(Storage, Lookup, SkipFlags, SkipUnicodeFlags, Subst, Unpacked.LookaheadCoverageOffsets, Unpacked.LookaheadCount, InputMatch.OnePastMatchGlyph, 0); if((BacktrackMatch.MatchCount == Unpacked.BacktrackCount) && ((MatchingInputGlyphCount) == Unpacked.InputCount) && (LookaheadMatch.MatchCount == Unpacked.LookaheadCount)) { Result.Records = Unpacked.Records; Result.RecordCount = Unpacked.RecordCount; Result.InputSequenceCountIncludingSkippedGlyphs = MatchedOrSkippedInputGlyphCount; + Result.OnePastLastGlyphMatched = InputMatch.OnePastMatchGlyph; Result.Matched = 1; break; @@ -17275,11 +20129,11 @@ static kbts_sequence_lookup_result kbts_DoSequenceLookup(kbts_unpacked_lookup *L break; } - KBTS_INSTRUMENT_END + KBTS_INSTRUMENT_FUNCTION_END; return Result; } -static void kbts_ApplyValueRecord(kbts_glyph *Glyph, kbts_unpacked_value_record *Unpacked) +static void kbts__ApplyValueRecord(kbts_glyph *Glyph, kbts__unpacked_value_record *Unpacked) { Glyph->OffsetX += Unpacked->PlacementX; Glyph->OffsetY += Unpacked->PlacementY; @@ -17288,38 +20142,28 @@ static void kbts_ApplyValueRecord(kbts_glyph *Glyph, kbts_unpacked_value_record Glyph->AdvanceY += Unpacked->AdvanceY; } -typedef struct kbts_indexed_glyph -{ - kbts_glyph *Glyph; - kbts_un Index; -} kbts_indexed_glyph; - -static int kbts_NextGlyph(kbts_unpacked_lookup *Lookup, kbts_glyph *InputGlyphs, kbts_un CurrentIndex, kbts_un InputGlyphCount, kbts_skip_flags SkipFlags, kbts_u32 SkipUnicodeFlags, kbts_indexed_glyph *IndexedGlyph) +static int kbts__NextGlyph(kbts_glyph_storage *Storage, kbts__unpacked_lookup *Lookup, kbts_glyph *AtGlyph, kbts__skip_flags SkipFlags, kbts_u32 SkipUnicodeFlags, kbts_glyph **Match, int Backward) { kbts_glyph *MatchingGlyph = 0; - kbts_un GlyphIndex = CurrentIndex; - while(GlyphIndex < InputGlyphCount) + while(kbts__GlyphIsValid(Storage, AtGlyph)) { - kbts_glyph *Glyph = &InputGlyphs[GlyphIndex]; - - if(!kbts_SkipGlyph(Glyph, Lookup, SkipFlags, SkipUnicodeFlags)) + if(!kbts__SkipGlyph(AtGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) { - MatchingGlyph = Glyph; + MatchingGlyph = AtGlyph; break; } else { - GlyphIndex += 1; + AtGlyph = Backward ? AtGlyph->Prev : AtGlyph->Next; } } - IndexedGlyph->Glyph = MatchingGlyph; - IndexedGlyph->Index = GlyphIndex; + *Match = MatchingGlyph; return MatchingGlyph != 0; } -static void kbts_AttachGlyph(kbts_glyph_array *GlyphArray, kbts_glyph *Parent, kbts_glyph *Child, kbts_s32 X, kbts_s32 Y) +static void kbts__AttachGlyph(kbts_glyph_storage *Storage, kbts_glyph *Parent, kbts_glyph *Child, kbts_s32 X, kbts_s32 Y) { kbts_s32 DeltaOffsetX = X - Child->OffsetX; kbts_s32 DeltaOffsetY = Y - Child->OffsetY; @@ -17327,11 +20171,13 @@ static void kbts_AttachGlyph(kbts_glyph_array *GlyphArray, kbts_glyph *Parent, k Child->OffsetX = X; Child->OffsetY = Y; Child->Flags |= KBTS_GLYPH_FLAG_USED_IN_GPOS; - Child->AttachGlyphIndexPlusOne = (kbts_u16)(Parent - GlyphArray->Glyphs + 1); + Child->AttachGlyph = Parent; Parent->Flags |= KBTS_GLYPH_FLAG_USED_IN_GPOS; - for(kbts_glyph *MiddleGlyph = Parent + 1; MiddleGlyph < Child; ++MiddleGlyph) + for(kbts_glyph *MiddleGlyph = Parent->Next; + MiddleGlyph != Child; + MiddleGlyph = MiddleGlyph->Next) { MiddleGlyph->Flags |= KBTS_GLYPH_FLAG_NO_BREAK; } @@ -17339,144 +20185,167 @@ static void kbts_AttachGlyph(kbts_glyph_array *GlyphArray, kbts_glyph *Parent, k // @Speed: Fuck this. // Attachments can happen in anti-topological order, so we have to fix them up here. // We should store glyph parent/child indices instead of traversing all glyphs. - kbts_un ChildIndex = (kbts_un)(Child - GlyphArray->Glyphs); - KBTS_FOR(PostGlyphIndex, ChildIndex + 1, GlyphArray->Count) + for(kbts_glyph *PostGlyph = Child->Next; + kbts__GlyphIsValid(Storage, PostGlyph); + PostGlyph = PostGlyph->Next) { - kbts_glyph *Glyph = &GlyphArray->Glyphs[PostGlyphIndex]; - - if(Glyph->AttachGlyphIndexPlusOne == (ChildIndex + 1)) + if(PostGlyph->AttachGlyph == Child) { - Glyph->OffsetX += DeltaOffsetX; - Glyph->OffsetY += DeltaOffsetY; + PostGlyph->OffsetX += DeltaOffsetX; + PostGlyph->OffsetY += DeltaOffsetY; } } } -typedef struct kbts_do_single_adjustment_result +static void kbts__SetLookupOnePastLastGlyph(kbts__shape_scratchpad *Scratchpad, kbts_un Index, kbts_glyph *Glyph) { - kbts_un PositionedGlyphCount; - kbts_u32 PerformedAdjustment; -} kbts_do_single_adjustment_result; -static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_config *Config, kbts_lookup_list *LookupList, kbts_un LookupIndex, kbts_un SubtableIndex, kbts_unpacked_lookup *Lookup, kbts_u16 *Base, - kbts_glyph_array *GlyphArray, kbts_un CurrentGlyphIndex, kbts_skip_flags RequestedSkipFlags) -{ - KBTS_INSTRUMENT_FUNCTION_BEGIN - kbts_unicode_flags SkipUnicodeFlags = KBTS_UNICODE_FLAG_DEFAULT_IGNORABLE; - kbts_skip_flags RegularSkipFlags = KBTS_SKIP_FLAGS_GPOS_REGULAR(RequestedSkipFlags); - kbts_skip_flags SequenceSkipFlags = KBTS_SKIP_FLAGS_GPOS_SEQUENCE(RequestedSkipFlags); - kbts_do_single_adjustment_result Result = KBTS_ZERO; - kbts_glyph *CurrentGlyph = &GlyphArray->Glyphs[CurrentGlyphIndex]; - - if(kbts_GlyphsIncludedInLookupSubtable(Config->Font, 1, Lookup, LookupIndex, SubtableIndex, GlyphArray, CurrentGlyphIndex, SequenceSkipFlags, SkipUnicodeFlags)) + if(Index > Scratchpad->LookupOnePastLastGlyphIndex) { - Result.PerformedAdjustment = 1; + Scratchpad->LookupOnePastLastGlyphIndex = (kbts_u32)Index; + Scratchpad->LookupOnePastLastGlyph = Glyph; + } +} - // CAREFUL: We want kbts_unpacked_lookup to be a useful bag-of-arguments type, but, for extension +typedef kbts_u32 kbts__cursive_flags; +enum kbts__cursive_flags_enum +{ + KBTS__CURSIVE_FLAG_NONE, + KBTS__CURSIVE_FLAG_START = (1 << 0), + KBTS__CURSIVE_FLAG_END = (1 << 1), +}; + +KBTS_INLINE kbts__cursive_flags kbts__GetCursiveFlags(kbts_glyph *Glyph) +{ + kbts__cursive_flags Result = (kbts__cursive_flags)Glyph->MarkOrdering; + return Result; +} + +KBTS_INLINE void kbts__SetCursiveFlags(kbts_glyph *Glyph, kbts__cursive_flags CursiveFlags) +{ + Glyph->MarkOrdering = (kbts_u8)CursiveFlags; +} + +static int kbts__DoSingleAdjustment(kbts__shape_scratchpad *Scratchpad, kbts_shape_config *Config, kbts_glyph_storage *Storage, + kbts_lookup_list *LookupList, kbts_un LookupIndex, kbts_un SubtableIndex, kbts__unpacked_lookup *Lookup, kbts_u16 *Base, + kbts_glyph *CurrentGlyph, kbts_un StartIndex, kbts__skip_flags RequestedSkipFlags) +{ + KBTS_INSTRUMENT_FUNCTION_BEGIN; + kbts_unicode_flags SkipUnicodeFlags = KBTS_UNICODE_FLAG_DEFAULT_IGNORABLE; + kbts__skip_flags RegularSkipFlags = KBTS__SKIP_FLAGS_GPOS_REGULAR(RequestedSkipFlags); + kbts__skip_flags SequenceSkipFlags = KBTS__SKIP_FLAGS_GPOS_SEQUENCE(RequestedSkipFlags); + + int Result = 0; + + kbts_un OnePastLastGlyphIndex = StartIndex + 1; + kbts_glyph *OnePastLastGlyph = CurrentGlyph->Next; + + if(kbts__GlyphsIncludedInLookupSubtable(Storage, Config->Font, 1, Lookup, LookupIndex, SubtableIndex, CurrentGlyph, SequenceSkipFlags, SkipUnicodeFlags)) + { + // CAREFUL: We want kbts__unpacked_lookup to be a useful bag-of-arguments type, but, for extension // lookups, each subtable may specify its own lookup type, so we save it here and restore it at // the end of this function. kbts_u16 OriginalLookupType = Lookup->Type; while(Lookup->Type == 9) { - kbts_extension *Extension = (kbts_extension *)Base; + kbts__extension *Extension = (kbts__extension *)Base; Lookup->Type = Extension->LookupType; - Base = KBTS_POINTER_OFFSET(kbts_u16, Extension, Extension->Offset); + Base = KBTS__POINTER_OFFSET(kbts_u16, Extension, Extension->Offset); } - kbts_glyph *InputGlyphs = GlyphArray->Glyphs + CurrentGlyphIndex; - kbts_un InputGlyphCount = GlyphArray->Count - CurrentGlyphIndex; - - kbts_cover_glyph_result Cover = KBTS_ZERO; - Cover.Valid = kbts_GlyphPassesLookupFilter(CurrentGlyph, Lookup); - kbts_coverage *Coverage = 0; - if(Cover.Valid && kbts_GposLookupBeginsWithCoverage(Lookup->Type, Base[0])) + kbts__cover_glyph_result Cover = KBTS__ZERO; + Cover.Valid = kbts__GlyphPassesLookupFilter(CurrentGlyph, Lookup); + kbts__coverage *Coverage = 0; + if(Cover.Valid && kbts__GposLookupBeginsWithCoverage(Lookup->Type, Base[0])) { kbts_u16 *CoverageOffset = Base + 1; - Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Base, *CoverageOffset); - Cover = kbts_CoverGlyph(Coverage, CurrentGlyph->Id); + Coverage = KBTS__POINTER_OFFSET(kbts__coverage, Base, *CoverageOffset); + Cover = kbts__CoverGlyph(Coverage, CurrentGlyph->Id); } if(Cover.Valid) { + kbts_un OnePastLastGlyphOffset = 0; + switch(Lookup->Type) { case 1: { - kbts_unpacked_value_record Unpacked = KBTS_ZERO; + kbts__unpacked_value_record Unpacked = KBTS__ZERO; if(Base[0] == 1) { - kbts_single_adjustment_1 *Adjust = (kbts_single_adjustment_1 *)Base; + kbts__single_adjustment_1 *Adjust = (kbts__single_adjustment_1 *)Base; - Unpacked = kbts_UnpackValueRecord(Adjust, Adjust->ValueFormat, KBTS_POINTER_AFTER(kbts_u16, Adjust)); + Unpacked = kbts__UnpackValueRecord(Adjust, Adjust->ValueFormat, KBTS__POINTER_AFTER(kbts_u16, Adjust)); } else if(Base[0] == 2) { - kbts_single_adjustment_2 *Adjust = (kbts_single_adjustment_2 *)Base; + kbts__single_adjustment_2 *Adjust = (kbts__single_adjustment_2 *)Base; - kbts_un RecordSize = kbts_PopCount32(Adjust->ValueFormat); - kbts_u16 *Records = KBTS_POINTER_AFTER(kbts_u16, Adjust); + kbts_un RecordSize = kbts__PopCount32(Adjust->ValueFormat); + kbts_u16 *Records = KBTS__POINTER_AFTER(kbts_u16, Adjust); kbts_u16 *Record = Records + RecordSize * Cover.Index; - Unpacked = kbts_UnpackValueRecord(Adjust, Adjust->ValueFormat, Record); + Unpacked = kbts__UnpackValueRecord(Adjust, Adjust->ValueFormat, Record); } - kbts_ApplyValueRecord(CurrentGlyph, &Unpacked); + kbts__ApplyValueRecord(CurrentGlyph, &Unpacked); CurrentGlyph->Flags |= KBTS_GLYPH_FLAG_USED_IN_GPOS; - Result.PositionedGlyphCount = 1; + Result = 1; } break; case 2: { - kbts_indexed_glyph NextGlyph; - if(kbts_NextGlyph(Lookup, InputGlyphs, 1, InputGlyphCount, RegularSkipFlags, SkipUnicodeFlags, &NextGlyph)) + kbts_glyph *NextGlyph; + if(kbts__NextGlyph(Storage, Lookup, CurrentGlyph->Next, RegularSkipFlags, SkipUnicodeFlags, &NextGlyph, 0)) { - kbts_u32 NextGlyphId = NextGlyph.Glyph->Id; + kbts_u32 NextGlyphId = NextGlyph->Id; - kbts_unpacked_value_record Unpacked1 = KBTS_ZERO; - kbts_unpacked_value_record Unpacked2 = KBTS_ZERO; + kbts__unpacked_value_record Unpacked1 = KBTS__ZERO; + kbts__unpacked_value_record Unpacked2 = KBTS__ZERO; int Valid = 0; if(Base[0] == 1) { - kbts_pair_adjustment_1 *Adjust = (kbts_pair_adjustment_1 *)Base; + kbts__pair_adjustment_1 *Adjust = (kbts__pair_adjustment_1 *)Base; - kbts_un Size1 = kbts_PopCount32(Adjust->ValueFormat1); - kbts_un Size2 = kbts_PopCount32(Adjust->ValueFormat2); + kbts_un Size1 = kbts__PopCount32(Adjust->ValueFormat1); + kbts_un Size2 = kbts__PopCount32(Adjust->ValueFormat2); - kbts_u16 *SetOffsets = KBTS_POINTER_AFTER(kbts_u16, Adjust); - kbts_pair_set *Set = KBTS_POINTER_OFFSET(kbts_pair_set, Adjust, SetOffsets[Cover.Index]); + kbts_u16 *SetOffsets = KBTS__POINTER_AFTER(kbts_u16, Adjust); + kbts__pair_set *Set = KBTS__POINTER_OFFSET(kbts__pair_set, Adjust, SetOffsets[Cover.Index]); kbts_un PairRecordSize = Size1 + Size2 + 1; // + 1 because each pair stores the next glyph ID. - kbts_pair_value_record *PairRecords = KBTS_POINTER_AFTER(kbts_pair_value_record, Set); - KBTS_FOR(PairIndex, 0, Set->Count) + kbts__pair_value_record *PairRecords = KBTS__POINTER_AFTER(kbts__pair_value_record, Set); + KBTS__FOR(PairIndex, 0, Set->Count) { - kbts_pair_value_record *PairRecord = PairRecords + PairRecordSize * PairIndex; + kbts__pair_value_record *PairRecord = PairRecords + PairRecordSize * PairIndex; if(PairRecord->SecondGlyph == NextGlyphId) { - kbts_u16 *Records = KBTS_POINTER_AFTER(kbts_u16, PairRecord); + kbts_u16 *Records = KBTS__POINTER_AFTER(kbts_u16, PairRecord); - Unpacked1 = kbts_UnpackValueRecord(Adjust, Adjust->ValueFormat1, Records); + Unpacked1 = kbts__UnpackValueRecord(Adjust, Adjust->ValueFormat1, Records); Records += Unpacked1.Size; - Unpacked2 = kbts_UnpackValueRecord(Adjust, Adjust->ValueFormat2, Records); + Unpacked2 = kbts__UnpackValueRecord(Adjust, Adjust->ValueFormat2, Records); Valid = 1; } } } else if(Base[0] == 2) { - kbts_pair_adjustment_2 *Adjust = (kbts_pair_adjustment_2 *)Base; - kbts_u16 *ClassDef1 = KBTS_POINTER_OFFSET(kbts_u16, Adjust, Adjust->ClassDefinition1Offset); - kbts_u16 *ClassDef2 = KBTS_POINTER_OFFSET(kbts_u16, Adjust, Adjust->ClassDefinition2Offset); + kbts__pair_adjustment_2 *Adjust = (kbts__pair_adjustment_2 *)Base; + kbts_u16 *ClassDef1 = KBTS__POINTER_OFFSET(kbts_u16, Adjust, Adjust->ClassDefinition1Offset); + kbts_u16 *ClassDef2 = KBTS__POINTER_OFFSET(kbts_u16, Adjust, Adjust->ClassDefinition2Offset); - kbts_un Size1 = kbts_PopCount32(Adjust->ValueFormat1); - kbts_un Size2 = kbts_PopCount32(Adjust->ValueFormat2); + kbts_un Size1 = kbts__PopCount32(Adjust->ValueFormat1); + kbts_un Size2 = kbts__PopCount32(Adjust->ValueFormat2); kbts_un PairRecordSize = Size1 + Size2; - kbts_u16 *PairRecords = KBTS_POINTER_AFTER(kbts_u16, Adjust); + kbts_u16 *PairRecords = KBTS__POINTER_AFTER(kbts_u16, Adjust); // From the Microsoft docs: // PairPosFormat2 requires that each glyph in all pairs be assigned to a class, which is @@ -17485,16 +20354,16 @@ static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_confi // class definition table, then we should skip the lookup. // However, this seems wrong in practice. Undefined classes seem to just default to 0, and then // the bounds check takes care of deciding whether the lookup is okay to apply or not. - kbts_glyph_class_from_table_result Class1 = kbts_GlyphClassFromTable(ClassDef1, CurrentGlyph->Id); - kbts_glyph_class_from_table_result Class2 = kbts_GlyphClassFromTable(ClassDef2, NextGlyphId); + kbts__glyph_class_from_table_result Class1 = kbts__GlyphClassFromTable(ClassDef1, CurrentGlyph->Id); + kbts__glyph_class_from_table_result Class2 = kbts__GlyphClassFromTable(ClassDef2, NextGlyphId); if((Class1.Class < Adjust->Class1Count) && (Class2.Class < Adjust->Class2Count)) { kbts_u16 *PairRecord = PairRecords + Class1.Class * PairRecordSize * Adjust->Class2Count + Class2.Class * PairRecordSize; - Unpacked1 = kbts_UnpackValueRecord(Adjust, Adjust->ValueFormat1, PairRecord); + Unpacked1 = kbts__UnpackValueRecord(Adjust, Adjust->ValueFormat1, PairRecord); PairRecord += Size1; - Unpacked2 = kbts_UnpackValueRecord(Adjust, Adjust->ValueFormat2, PairRecord); + Unpacked2 = kbts__UnpackValueRecord(Adjust, Adjust->ValueFormat2, PairRecord); PairRecord += Size2; Valid = 1; } @@ -17502,17 +20371,14 @@ static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_confi if(Valid) { - kbts_ApplyValueRecord(CurrentGlyph, &Unpacked1); + kbts__ApplyValueRecord(CurrentGlyph, &Unpacked1); CurrentGlyph->Flags |= KBTS_GLYPH_FLAG_USED_IN_GPOS; - kbts_ApplyValueRecord(&InputGlyphs[NextGlyph.Index], &Unpacked2); - NextGlyph.Glyph->Flags |= KBTS_GLYPH_FLAG_USED_IN_GPOS; + kbts__ApplyValueRecord(NextGlyph, &Unpacked2); + NextGlyph->Flags |= KBTS_GLYPH_FLAG_USED_IN_GPOS; - Result.PositionedGlyphCount = 2; - if(!Unpacked2.Size) - { - Result.PositionedGlyphCount = 1; - } + Result = 1; + OnePastLastGlyph = Unpacked2.Size ? NextGlyph->Next : CurrentGlyph->Next; } } } @@ -17521,35 +20387,25 @@ static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_confi // All three types of attachment (cursive, mark-to-base, mark-to-ligature) look backward instead of forward. case 3: { - kbts_cursive_attachment *Adjust = (kbts_cursive_attachment *)Base; - kbts_entry_exit *EntryExits = KBTS_POINTER_AFTER(kbts_entry_exit, Adjust); + kbts__cursive_attachment *Adjust = (kbts__cursive_attachment *)Base; + kbts__entry_exit *EntryExits = KBTS__POINTER_AFTER(kbts__entry_exit, Adjust); - kbts_glyph *Prev = 0; - for(kbts_un PrevIndex = CurrentGlyphIndex; PrevIndex > 0; --PrevIndex) - { - kbts_glyph *PrevGlyph = &GlyphArray->Glyphs[PrevIndex - 1]; - if(!kbts_SkipGlyph(PrevGlyph, Lookup, RegularSkipFlags, SkipUnicodeFlags)) - { - Prev = PrevGlyph; - break; - } - } - - if(Prev) + kbts_glyph *Prev; + if(kbts__NextGlyph(Storage, Lookup, CurrentGlyph->Prev, RegularSkipFlags, SkipUnicodeFlags, &Prev, 1)) { // For two cursive glyphs to be aligned, they both need to be defined by the same cursive attachment table. - kbts_cover_glyph_result PrevCover = kbts_CoverGlyph(Coverage, Prev->Id); + kbts__cover_glyph_result PrevCover = kbts__CoverGlyph(Coverage, Prev->Id); if(PrevCover.Valid) { // Get anchor points for both glyphs. - kbts_entry_exit *PrevEntryExit = &EntryExits[PrevCover.Index]; - kbts_entry_exit *EntryExit = &EntryExits[Cover.Index]; + kbts__entry_exit *PrevEntryExit = &EntryExits[PrevCover.Index]; + kbts__entry_exit *EntryExit = &EntryExits[Cover.Index]; if(PrevEntryExit->ExitAnchorOffset && EntryExit->EntryAnchorOffset) { - kbts_anchor *PrevExitAnchor = KBTS_POINTER_OFFSET(kbts_anchor, Adjust, PrevEntryExit->ExitAnchorOffset); - kbts_anchor *EntryAnchor = KBTS_POINTER_OFFSET(kbts_anchor, Adjust, EntryExit->EntryAnchorOffset); + kbts__anchor *PrevExitAnchor = KBTS__POINTER_OFFSET(kbts__anchor, Adjust, PrevEntryExit->ExitAnchorOffset); + kbts__anchor *EntryAnchor = KBTS__POINTER_OFFSET(kbts__anchor, Adjust, EntryExit->EntryAnchorOffset); kbts_s32 Anchor0X = PrevExitAnchor->X; kbts_s32 Anchor0Y = PrevExitAnchor->Y; kbts_s32 Anchor1X = EntryAnchor->X; @@ -17597,7 +20453,7 @@ static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_confi // invalid positions. The hope is that this does not matter in practice, because 'mark' is applied after // 'curs', and font designers are expected to know that and to know never to apply mark attachments // before cursive positioning, I guess. - if(!kbts_ShaperRtl(Config->Shaper)) + if(!kbts__ShaperRtl(Config->Shaper)) { Advance0X = Offset0X + Anchor0X; kbts_s32 Dx = -Anchor1X - Offset1X; @@ -17615,13 +20471,18 @@ static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_confi Prev->AdvanceX = Advance0X; Prev->OffsetX = Offset0X; Prev->Flags |= (KBTS_GLYPH_FLAG_CURSIVE | KBTS_GLYPH_FLAG_USED_IN_GPOS | KBTS_GLYPH_FLAG_NO_BREAK); + kbts__SetCursiveFlags(Prev, KBTS__CURSIVE_FLAG_START); CurrentGlyph->AdvanceX = Advance1X; CurrentGlyph->OffsetX = Offset1X; - CurrentGlyph->Flags |= (KBTS_GLYPH_FLAG_CURSIVE | KBTS_GLYPH_FLAG_USED_IN_GPOS); + CurrentGlyph->Flags |= KBTS_GLYPH_FLAG_CURSIVE | KBTS_GLYPH_FLAG_USED_IN_GPOS; + kbts__SetCursiveFlags(CurrentGlyph, KBTS__CURSIVE_FLAG_END); - for(kbts_glyph *CursiveGlyph = Prev + 1; CursiveGlyph < CurrentGlyph; ++CursiveGlyph) + for(kbts_glyph *CursiveGlyph = Prev->Next; + CursiveGlyph != CurrentGlyph; + CursiveGlyph = CursiveGlyph->Next) { CursiveGlyph->Flags |= KBTS_GLYPH_FLAG_NO_BREAK; + kbts__SetCursiveFlags(CursiveGlyph, 0); } // The second part is aligning the newly-formed cursive cluster to the "baseline". It is trickier than you'd expect. @@ -17639,10 +20500,11 @@ static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_confi // matters insofar as we need to align every other cursive glyph in its direction. kbts_s32 CursiveDy = 0; - kbts_un CursiveStartIndex = CurrentGlyphIndex; - kbts_un DIndex = 1; + kbts_glyph *CursiveGlyph = CurrentGlyph; + int Backward = 0; + kbts_u32 AdjustNearbyGlyphs = (CurrentGlyph->Flags & KBTS_GLYPH_FLAG_CURSIVE); - if(!(Lookup->Flags & KBTS_LOOKUP_FLAG_RIGHT_TO_LEFT)) + if(!(Lookup->Flags & KBTS__LOOKUP_FLAG_RIGHT_TO_LEFT)) { kbts_s32 NewOffset1Y = Offset0Y + Anchor0Y - Anchor1Y; CursiveDy = NewOffset1Y - Offset1Y; @@ -17651,25 +20513,42 @@ static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_confi { kbts_s32 NewOffset0Y = Offset1Y + Anchor1Y - Anchor0Y; CursiveDy = NewOffset0Y - Offset0Y; - DIndex = -1; - CursiveStartIndex = (kbts_un)(Prev - GlyphArray->Glyphs); + Backward = 1; + CursiveGlyph = Prev; + AdjustNearbyGlyphs = 1; } - for(kbts_un CursiveGlyphIndex = CursiveStartIndex; CursiveGlyphIndex < GlyphArray->Count; CursiveGlyphIndex += DIndex) + CursiveGlyph->OffsetY += CursiveDy; + + if(AdjustNearbyGlyphs) { - kbts_glyph *CursiveGlyph = &GlyphArray->Glyphs[CursiveGlyphIndex]; + kbts__SetCursiveFlags(CursiveGlyph, 0); + CursiveGlyph = Backward ? CursiveGlyph->Prev : CursiveGlyph->Next; - if(CursiveGlyph->Flags & KBTS_GLYPH_FLAG_CURSIVE) + kbts__cursive_flags StopFlag = Backward ? KBTS__CURSIVE_FLAG_END : KBTS__CURSIVE_FLAG_START; + + while(kbts__GlyphIsValid(Storage, CursiveGlyph)) { - CursiveGlyph->OffsetY += CursiveDy; - } - else if(CursiveGlyph->AdvanceX | CursiveGlyph->AdvanceY) // Ignore marks. - { - break; + kbts__cursive_flags CursiveFlags = kbts__GetCursiveFlags(CursiveGlyph); + + if(CursiveFlags & StopFlag) + { + break; + } + else if(CursiveGlyph->Flags & KBTS_GLYPH_FLAG_CURSIVE) + { + CursiveGlyph->OffsetY += CursiveDy; + } + else if(!(CursiveGlyph->Classes.Class & KBTS__GLYPH_CLASS_MARK)) // Ignore marks. + { + break; + } + + CursiveGlyph = Backward ? CursiveGlyph->Prev : CursiveGlyph->Next; } } - Result.PositionedGlyphCount = 1; + Result = 1; } } } @@ -17679,7 +20558,7 @@ static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_confi case 4: case 6: { - kbts_mark_to_base_attachment *Adjust = (kbts_mark_to_base_attachment *)Base; + kbts__mark_to_base_attachment *Adjust = (kbts__mark_to_base_attachment *)Base; // We want to know which glyph to attach to, and how far that glyph is from us. // To do that, we add up all advances between it and us. @@ -17688,27 +20567,51 @@ static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_confi // We have to take that into account here, and only accumulate mark advances for shapers that // don't do that zeroing at the end (either because they do it at the beginning of GPOS, or // because they don't do it at all). - int CountMarkAdvances = !kbts_ShaperClearsMarkAdvancesInPostGposFixup(Config->Shaper); + int CountMarkAdvances = !kbts__ShaperClearsMarkAdvancesInPostGposFixup(Config->Shaper); + kbts__coverage *BaseCoverage = KBTS__POINTER_OFFSET(kbts__coverage, Adjust, Adjust->BaseCoverageOffset); kbts_s32 AdvanceSinceBaseX = 0; kbts_s32 AdvanceSinceBaseY = 0; - kbts_u32 BaseClasses = Lookup->Type == 6 ? (1 << KBTS_GLYPH_CLASS_MARK) : (1 | (1 << KBTS_GLYPH_CLASS_BASE) | (1 << KBTS_GLYPH_CLASS_LIGATURE) | (1 << KBTS_GLYPH_CLASS_COMPONENT)); + kbts_u32 BaseClasses = Lookup->Type == 6 ? (1 << KBTS__GLYPH_CLASS_MARK) : (1 | (1 << KBTS__GLYPH_CLASS_BASE) | (1 << KBTS__GLYPH_CLASS_LIGATURE) | (1 << KBTS__GLYPH_CLASS_COMPONENT)); kbts_glyph *BaseGlyph = 0; - for(kbts_un PrevGlyphIndex = CurrentGlyphIndex; PrevGlyphIndex; --PrevGlyphIndex) + for(kbts_glyph *PrevGlyph = CurrentGlyph->Prev; kbts__GlyphIsValid(Storage, PrevGlyph); PrevGlyph = PrevGlyph->Prev) { - kbts_glyph *PrevGlyph = &GlyphArray->Glyphs[PrevGlyphIndex - 1]; - - if(CountMarkAdvances || (PrevGlyph->Classes.Class != KBTS_GLYPH_CLASS_MARK)) + if(CountMarkAdvances || (PrevGlyph->Classes.Class != KBTS__GLYPH_CLASS_MARK)) { AdvanceSinceBaseX += PrevGlyph->AdvanceX; AdvanceSinceBaseY += PrevGlyph->AdvanceY; } - if(!kbts_SkipGlyph(PrevGlyph, Lookup, RegularSkipFlags, SkipUnicodeFlags)) + if(!kbts__SkipGlyph(PrevGlyph, Lookup, RegularSkipFlags, SkipUnicodeFlags)) { if((1 << PrevGlyph->Classes.Class) & BaseClasses) { - BaseGlyph = PrevGlyph; - break; + // :MultipleSubstSadness + // There is some sadness when we have to look for bases here... + // In multiple substitutions, we allow skipping covered glyphs if they are: + // - Not the first in the multiple substitution + // - Not preceded by a mark + // + // More details on the sadness can be found here: + // https://github.com/harfbuzz/harfbuzz/issues/740 + // https://github.com/harfbuzz/harfbuzz/issues/1020 + // https://github.com/harfbuzz/harfbuzz/issues/4124 + if((Lookup->Type == 4) && + ((PrevGlyph->Flags & (KBTS_GLYPH_FLAG_FIRST_IN_MULTIPLE_SUBSTITUTION | KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION)) == KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION) && // Stop if we see the first of a multiple substitution. + (PrevGlyph->Prev->Classes.Class != KBTS__GLYPH_CLASS_MARK)) // Stop if we see any mark. + { + // Otherwise, we allow skipping uncovered glyphs. + kbts__cover_glyph_result BaseCover = kbts__CoverGlyph(BaseCoverage, PrevGlyph->Id); + if(BaseCover.Valid) + { + BaseGlyph = PrevGlyph; + break; + } + } + else + { + BaseGlyph = PrevGlyph; + break; + } } else if(Lookup->Type == 6) { @@ -17725,18 +20628,19 @@ static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_confi ((BaseGlyph->Flags | CurrentGlyph->Flags) & KBTS_GLYPH_FLAG_LIGATURE); // This is a mark-to-mark attachment, and either mark was created by a ligature substitution if(Ok) { - kbts_cover_glyph_result BaseCover = kbts_CoverGlyph(KBTS_POINTER_OFFSET(kbts_coverage, Adjust, Adjust->BaseCoverageOffset), BaseGlyph->Id); + // @Speed: This is duplicating work in the :MultipleSubstSadness case. + kbts__cover_glyph_result BaseCover = kbts__CoverGlyph(BaseCoverage, BaseGlyph->Id); if(BaseCover.Valid) { - kbts_base_array *BaseArray = KBTS_POINTER_OFFSET(kbts_base_array, Adjust, Adjust->BaseArrayOffset); - kbts_u16 *BaseAnchorOffsets = KBTS_POINTER_AFTER(kbts_u16, BaseArray) + BaseCover.Index * Adjust->MarkClassCount; - kbts_mark_info MarkInfo = kbts_GetMarkInfo(Adjust, Adjust->MarkArrayOffset, Cover.Index); + kbts__base_array *BaseArray = KBTS__POINTER_OFFSET(kbts__base_array, Adjust, Adjust->BaseArrayOffset); + kbts_u16 *BaseAnchorOffsets = KBTS__POINTER_AFTER(kbts_u16, BaseArray) + BaseCover.Index * Adjust->MarkClassCount; + kbts__mark_info MarkInfo = kbts__GetMarkInfo(Adjust, Adjust->MarkArrayOffset, Cover.Index); kbts_u16 BaseAnchorOffset = BaseAnchorOffsets[MarkInfo.Record->Class]; if(BaseAnchorOffset) { - kbts_anchor *BaseAnchor = KBTS_POINTER_OFFSET(kbts_anchor, BaseArray, BaseAnchorOffset); + kbts__anchor *BaseAnchor = KBTS__POINTER_OFFSET(kbts__anchor, BaseArray, BaseAnchorOffset); /* From the Microsoft docs: When a mark is combined with a given base, the mark placement is adjusted so that the mark anchor is @@ -17747,9 +20651,9 @@ static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_confi kbts_s32 NewOffsetX = BaseGlyph->OffsetX - AdvanceSinceBaseX + (BaseAnchor->X - MarkInfo.Anchor->X); kbts_s32 NewOffsetY = BaseGlyph->OffsetY - AdvanceSinceBaseY + (BaseAnchor->Y - MarkInfo.Anchor->Y); - kbts_AttachGlyph(GlyphArray, BaseGlyph, CurrentGlyph, NewOffsetX, NewOffsetY); + kbts__AttachGlyph(Storage, BaseGlyph, CurrentGlyph, NewOffsetX, NewOffsetY); - Result.PositionedGlyphCount = 1; + Result = 1; } } } @@ -17759,18 +20663,19 @@ static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_confi case 5: { - kbts_mark_to_ligature_attachment *Adjust = (kbts_mark_to_ligature_attachment *)Base; + kbts__mark_to_ligature_attachment *Adjust = (kbts__mark_to_ligature_attachment *)Base; kbts_s32 AdvanceSinceBaseX = 0; kbts_s32 AdvanceSinceBaseY = 0; - kbts_u32 BaseClasses = (1 | (1 << KBTS_GLYPH_CLASS_BASE) | (1 << KBTS_GLYPH_CLASS_LIGATURE) | (1 << KBTS_GLYPH_CLASS_COMPONENT)); + kbts_u32 BaseClasses = (1 | (1 << KBTS__GLYPH_CLASS_BASE) | (1 << KBTS__GLYPH_CLASS_LIGATURE) | (1 << KBTS__GLYPH_CLASS_COMPONENT)); kbts_glyph *LigatureGlyph = 0; - for(kbts_un PrevGlyphIndex = CurrentGlyphIndex; PrevGlyphIndex; --PrevGlyphIndex) + for(kbts_glyph *PrevGlyph = CurrentGlyph->Prev; + kbts__GlyphIsValid(Storage, PrevGlyph); + PrevGlyph = PrevGlyph->Prev) { - kbts_glyph *PrevGlyph = &GlyphArray->Glyphs[PrevGlyphIndex - 1]; AdvanceSinceBaseX += PrevGlyph->AdvanceX; AdvanceSinceBaseY += PrevGlyph->AdvanceY; - if(!kbts_SkipGlyph(PrevGlyph, Lookup, RegularSkipFlags, SkipUnicodeFlags) && ((1 << PrevGlyph->Classes.Class) & BaseClasses)) + if(!kbts__SkipGlyph(PrevGlyph, Lookup, RegularSkipFlags, SkipUnicodeFlags) && ((1 << PrevGlyph->Classes.Class) & BaseClasses)) { LigatureGlyph = PrevGlyph; break; @@ -17779,25 +20684,25 @@ static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_confi if(LigatureGlyph) { - kbts_cover_glyph_result LigatureCover = kbts_CoverGlyph(KBTS_POINTER_OFFSET(kbts_coverage, Adjust, Adjust->LigatureCoverageOffset), + kbts__cover_glyph_result LigatureCover = kbts__CoverGlyph(KBTS__POINTER_OFFSET(kbts__coverage, Adjust, Adjust->LigatureCoverageOffset), LigatureGlyph->Id); if(LigatureCover.Valid) { - kbts_ligature_array *LigatureArray = KBTS_POINTER_OFFSET(kbts_ligature_array, Adjust, Adjust->LigatureArrayOffset); - kbts_ligature_attach *LigatureAttach = kbts_GetLigatureAttach(LigatureArray, LigatureCover.Index); - kbts_mark_info MarkInfo = kbts_GetMarkInfo(Adjust, Adjust->MarkArrayOffset, Cover.Index); - kbts_un LigatureComponentIndex = CurrentGlyph->LigatureComponentIndexPlusOne; + kbts__ligature_array *LigatureArray = KBTS__POINTER_OFFSET(kbts__ligature_array, Adjust, Adjust->LigatureArrayOffset); + kbts__ligature_attach *LigatureAttach = kbts__GetLigatureAttach(LigatureArray, LigatureCover.Index); + kbts__mark_info MarkInfo = kbts__GetMarkInfo(Adjust, Adjust->MarkArrayOffset, Cover.Index); + kbts_un LigatureComponentIndexPlusOne = CurrentGlyph->LigatureComponentIndexPlusOne; if(CurrentGlyph->LigatureUid != LigatureGlyph->Uid) { // If the mark is not yet attached to the ligature, attach it now. // Apparently, in this case, the mark should be considered part of the _last_ component of the ligature. - LigatureComponentIndex = LigatureAttach->Count; + LigatureComponentIndexPlusOne = LigatureAttach->Count; } - if(CurrentGlyph->LigatureComponentIndexPlusOne <= LigatureAttach->Count) + if(LigatureComponentIndexPlusOne <= LigatureAttach->Count) { - kbts_un AnchorIndex = LigatureComponentIndex; + kbts_un AnchorIndex = LigatureComponentIndexPlusOne; if(AnchorIndex) { AnchorIndex -= 1; @@ -17807,26 +20712,28 @@ static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_confi AnchorIndex = LigatureAttach->Count - 1; } - kbts_anchor *LigatureAnchor = kbts_GetLigatureAttachAnchor(Adjust, LigatureAttach, MarkInfo.Record->Class, AnchorIndex); + kbts__anchor *LigatureAnchor = kbts__GetLigatureAttachAnchor(Adjust, LigatureAttach, MarkInfo.Record->Class, AnchorIndex); kbts_s32 NewOffsetX = LigatureGlyph->OffsetX - AdvanceSinceBaseX + (LigatureAnchor->X - MarkInfo.Anchor->X); kbts_s32 NewOffsetY = LigatureGlyph->OffsetY - AdvanceSinceBaseY + (LigatureAnchor->Y - MarkInfo.Anchor->Y); - kbts_AttachGlyph(GlyphArray, LigatureGlyph, CurrentGlyph, NewOffsetX, NewOffsetY); + kbts__AttachGlyph(Storage, LigatureGlyph, CurrentGlyph, NewOffsetX, NewOffsetY); - CurrentGlyph->LigatureComponentIndexPlusOne = (kbts_u16)LigatureComponentIndex; + CurrentGlyph->LigatureComponentIndexPlusOne = (kbts_u16)LigatureComponentIndexPlusOne; CurrentGlyph->LigatureUid = LigatureGlyph->Uid; // I'm not sure why, but Harfbuzz only clears this in mark-to-ligature substitutions, and not in mark-to-base or // mark-to-mark. CurrentGlyph->AdvanceX = 0; CurrentGlyph->AdvanceY = 0; - for(kbts_glyph *MiddleGlyph = LigatureGlyph + 1; MiddleGlyph < CurrentGlyph; ++MiddleGlyph) + for(kbts_glyph *MiddleGlyph = LigatureGlyph->Next; + MiddleGlyph != CurrentGlyph; + MiddleGlyph = MiddleGlyph->Next) { MiddleGlyph->Flags |= KBTS_GLYPH_FLAG_NO_BREAK; } - Result.PositionedGlyphCount = 1; + Result = 1; } } } @@ -17836,265 +20743,257 @@ static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_confi case 7: case 8: { - kbts_sequence_lookup_result SequenceLookup = kbts_DoSequenceLookup(Lookup, Base, Cover, GlyphArray, CurrentGlyphIndex, SequenceSkipFlags, SkipUnicodeFlags); + kbts__sequence_lookup_result SequenceLookup = kbts__DoSequenceLookup(Storage, Lookup, Base, Cover, CurrentGlyph, SequenceSkipFlags, SkipUnicodeFlags); if(SequenceLookup.RecordCount) { - KBTS_FOR(RecordIndex, 0, SequenceLookup.RecordCount) + KBTS__FOR(RecordIndex, 0, SequenceLookup.RecordCount) { - kbts_sequence_lookup_record *Record = &SequenceLookup.Records[RecordIndex]; - kbts_lookup *PackedRecordLookup = kbts_GetLookup(LookupList, Record->LookupListIndex); - kbts_unpacked_lookup RecordLookup = kbts_UnpackLookup(Config->Font->Gdef, PackedRecordLookup); + kbts__sequence_lookup_record *Record = &SequenceLookup.Records[RecordIndex]; + kbts__lookup *PackedRecordLookup = kbts__GetLookup(LookupList, Record->LookupListIndex); + kbts__unpacked_lookup RecordLookup = kbts__UnpackLookup(kbts__BlobTableDataType(Config->Font->Blob, KBTS_BLOB_TABLE_ID_GDEF, kbts__gdef), PackedRecordLookup); - kbts_un NestedCurrentGlyphIndex = CurrentGlyphIndex; + kbts_glyph *NestedCurrentGlyph = CurrentGlyph; + kbts_un NestedCurrentGlyphIndex = 0; { // Figure out where in the input sequence we need to apply the lookup. kbts_un SequenceIndex = 0; - KBTS_FOR(InputGlyphIndex, 0, InputGlyphCount) + for(kbts_glyph *Glyph = CurrentGlyph; + kbts__GlyphIsValid(Storage, Glyph); + Glyph = Glyph->Next) { - kbts_un NestedIndex = CurrentGlyphIndex + InputGlyphIndex; - kbts_glyph *Glyph = &GlyphArray->Glyphs[NestedIndex]; - - if(!kbts_SkipGlyph(Glyph, Lookup, SequenceSkipFlags, SkipUnicodeFlags)) + if(!kbts__SkipGlyph(Glyph, Lookup, SequenceSkipFlags, SkipUnicodeFlags)) { if(SequenceIndex == Record->SequenceIndex) { - NestedCurrentGlyphIndex = NestedIndex; + NestedCurrentGlyph = Glyph; break; } SequenceIndex += 1; } + + NestedCurrentGlyphIndex += 1; } } - KBTS_FOR(NestedSubtableIndex, 0, RecordLookup.SubtableCount) + KBTS__FOR(NestedSubtableIndex, 0, RecordLookup.SubtableCount) { - kbts_u16 *NestedBase = KBTS_POINTER_OFFSET(kbts_u16, PackedRecordLookup, RecordLookup.SubtableOffsets[NestedSubtableIndex]); + kbts_u16 *NestedBase = KBTS__POINTER_OFFSET(kbts_u16, PackedRecordLookup, RecordLookup.SubtableOffsets[NestedSubtableIndex]); - kbts_DoSingleAdjustment(Config, LookupList, Record->LookupListIndex, NestedSubtableIndex, &RecordLookup, NestedBase, GlyphArray, NestedCurrentGlyphIndex, RequestedSkipFlags); + kbts__DoSingleAdjustment(Scratchpad, Config, Storage, LookupList, + Record->LookupListIndex, NestedSubtableIndex, &RecordLookup, NestedBase, + NestedCurrentGlyph, StartIndex + NestedCurrentGlyphIndex, RequestedSkipFlags); } } - Result.PositionedGlyphCount = SequenceLookup.InputSequenceCountIncludingSkippedGlyphs; + OnePastLastGlyphIndex = StartIndex + SequenceLookup.InputSequenceCountIncludingSkippedGlyphs; + OnePastLastGlyph = SequenceLookup.OnePastLastGlyphMatched; } } break; } + + kbts__SetLookupOnePastLastGlyph(Scratchpad, OnePastLastGlyphIndex + OnePastLastGlyphOffset, OnePastLastGlyph); } Lookup->Type = OriginalLookupType; } - if(!Result.PositionedGlyphCount) - { - Result.PositionedGlyphCount = 1; - Result.PerformedAdjustment = 0; - } - - KBTS_INSTRUMENT_END + KBTS_INSTRUMENT_FUNCTION_END; return Result; } -typedef kbts_u32 kbts_mcm_sequence_state; -enum kbts_mcm_sequence_state_enum +typedef kbts_u32 kbts__mcm_sequence_state; +enum kbts__mcm_sequence_state_enum { - KBTS_MCM_SEQUENCE_STATE_NONE, - KBTS_MCM_SEQUENCE_STATE_OUT, - KBTS_MCM_SEQUENCE_STATE_IN, + KBTS__MCM_SEQUENCE_STATE_NONE, + KBTS__MCM_SEQUENCE_STATE_OUT, + KBTS__MCM_SEQUENCE_STATE_IN, }; -typedef kbts_u32 kbts_hangul_syllable_type; -enum kbts_hangul_syllable_type_enum +typedef kbts_u32 kbts__hangul_syllable_type; +enum kbts__hangul_syllable_type_enum { - KBTS_HANGUL_SYLLABLE_TYPE_NONE, + KBTS__HANGUL_SYLLABLE_TYPE_NONE, - KBTS_HANGUL_SYLLABLE_TYPE_L, - KBTS_HANGUL_SYLLABLE_TYPE_V, - KBTS_HANGUL_SYLLABLE_TYPE_T, - KBTS_HANGUL_SYLLABLE_TYPE_LV, - KBTS_HANGUL_SYLLABLE_TYPE_LVT, + KBTS__HANGUL_SYLLABLE_TYPE_L, + KBTS__HANGUL_SYLLABLE_TYPE_V, + KBTS__HANGUL_SYLLABLE_TYPE_T, + KBTS__HANGUL_SYLLABLE_TYPE_LV, + KBTS__HANGUL_SYLLABLE_TYPE_LVT, - KBTS_HANGUL_SYLLABLE_TYPE_COUNT, + KBTS__HANGUL_SYLLABLE_TYPE_COUNT, }; -typedef struct kbts_hangul_syllable_info +typedef struct kbts__hangul_syllable_info { - kbts_hangul_syllable_type Type; + kbts__hangul_syllable_type Type; kbts_u32 Composable; -} kbts_hangul_syllable_info; +} kbts__hangul_syllable_info; -static kbts_hangul_syllable_info kbts_HangulSyllableInfo(kbts_u32 Codepoint) +static kbts__hangul_syllable_info kbts__HangulSyllableInfo(kbts_u32 Codepoint) { - kbts_hangul_syllable_info Result = KBTS_ZERO; + kbts__hangul_syllable_info Result = KBTS__ZERO; if((Codepoint >= 0x1100) && (Codepoint <= 0x115F)) { - Result.Type = KBTS_HANGUL_SYLLABLE_TYPE_L; + Result.Type = KBTS__HANGUL_SYLLABLE_TYPE_L; Result.Composable = (Codepoint < 0x1113); } else if((Codepoint >= 0x1160) && (Codepoint <= 0x11A7)) { - Result.Type = KBTS_HANGUL_SYLLABLE_TYPE_V; + Result.Type = KBTS__HANGUL_SYLLABLE_TYPE_V; Result.Composable = ((Codepoint >= 0x1161) & (Codepoint <= 0x1175)); } else if((Codepoint >= 0x11A8) && (Codepoint <= 0x11FF)) { - Result.Type = KBTS_HANGUL_SYLLABLE_TYPE_T; + Result.Type = KBTS__HANGUL_SYLLABLE_TYPE_T; Result.Composable = (Codepoint < 0x11C3); } else if((Codepoint >= 0xA960) && (Codepoint <= 0xA97C)) { - Result.Type = KBTS_HANGUL_SYLLABLE_TYPE_L; + Result.Type = KBTS__HANGUL_SYLLABLE_TYPE_L; } else if((Codepoint == 0xAC00) && (Codepoint <= 0xD7A3)) { - Result.Type = KBTS_HANGUL_SYLLABLE_TYPE_LVT; + Result.Type = KBTS__HANGUL_SYLLABLE_TYPE_LVT; if(!((Codepoint - 0xAC00) % 28)) { - Result.Type = KBTS_HANGUL_SYLLABLE_TYPE_LV; + Result.Type = KBTS__HANGUL_SYLLABLE_TYPE_LV; } } else if((Codepoint >= 0xD7B0) && (Codepoint <= 0xD7C6)) { - Result.Type = KBTS_HANGUL_SYLLABLE_TYPE_V; + Result.Type = KBTS__HANGUL_SYLLABLE_TYPE_V; } else if((Codepoint >= 0xD7CB) && (Codepoint <= 0xD7FB)) { - Result.Type = KBTS_HANGUL_SYLLABLE_TYPE_T; + Result.Type = KBTS__HANGUL_SYLLABLE_TYPE_T; } return Result; } -KBTS_INLINE kbts_u32 kbts_SyllabicClassIsConsonant(kbts_indic_syllabic_class Class) +KBTS_INLINE kbts_u32 kbts__SyllabicClassIsConsonant(kbts_indic_syllabic_class Class) { kbts_u32 Result = - KBTS_IN_SET(Class, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_CONSONANT)(KBTS_INDIC_SYLLABIC_CLASS_RA)(KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_WITH_STACKER)(KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_MEDIAL))); + KBTS__IN_SET(Class, KBTS__SET32((KBTS_INDIC_SYLLABIC_CLASS_CONSONANT)(KBTS_INDIC_SYLLABIC_CLASS_RA)(KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_WITH_STACKER)(KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_MEDIAL))); return Result; } enum { - KBTS_FEATURE_MATCH_FLAG_KA_JA = (1 << 0), - KBTS_FEATURE_MATCH_FLAG_SSA_NYA = (1 << 1), - KBTS_FEATURE_MATCH_FLAG_RA_HA_VA = (1 << 2), - KBTS_FEATURE_MATCH_FLAG_YA = (1 << 3), - KBTS_FEATURE_MATCH_FLAG_CONSONANT = (1 << 4), - KBTS_FEATURE_MATCH_FLAG_NUKTA = (1 << 5), - KBTS_FEATURE_MATCH_FLAG_HALANT = (1 << 6), - KBTS_FEATURE_MATCH_FLAG_ZWJ = (1 << 7), - KBTS_FEATURE_MATCH_FLAG_ZWNJ = (1 << 8), - KBTS_FEATURE_MATCH_FLAG_INITIAL = (1 << 10), - KBTS_FEATURE_MATCH_FLAG_POST_BASE = (1 << 11), + KBTS__FEATURE_MATCH_FLAG_KA_JA = (1 << 0), + KBTS__FEATURE_MATCH_FLAG_SSA_NYA = (1 << 1), + KBTS__FEATURE_MATCH_FLAG_RA_HA_VA = (1 << 2), + KBTS__FEATURE_MATCH_FLAG_YA = (1 << 3), + KBTS__FEATURE_MATCH_FLAG_CONSONANT = (1 << 4), + KBTS__FEATURE_MATCH_FLAG_NUKTA = (1 << 5), + KBTS__FEATURE_MATCH_FLAG_HALANT = (1 << 6), + KBTS__FEATURE_MATCH_FLAG_ZWJ = (1 << 7), + KBTS__FEATURE_MATCH_FLAG_ZWNJ = (1 << 8), + KBTS__FEATURE_MATCH_FLAG_INITIAL = (1 << 10), + KBTS__FEATURE_MATCH_FLAG_POST_BASE = (1 << 11), - KBTS_FEATURE_MATCH_FLAG_RPHF = KBTS_FEATURE_FLAG0(rphf), + KBTS__FEATURE_MATCH_FLAG_RPHF = KBTS__FEATURE_FLAG0(rphf), }; -# define KBTS_FEATURE_MATCH_MASK(W0, W1, W2, W3) (((kbts_u64)(W0) << 48) | ((kbts_u64)(W1) << 32) | ((kbts_u64)(W0) << 16) | (kbts_u64)(W0)) -# define KBTS_FEATURE_MATCH_MASK_AKHN KBTS_FEATURE_MATCH_MASK(0, KBTS_FEATURE_MATCH_FLAG_KA_JA, KBTS_FEATURE_MATCH_FLAG_HALANT, KBTS_FEATURE_MATCH_FLAG_SSA_NYA) -# define KBTS_FEATURE_MATCH_MASK_BLWF_PRE KBTS_FEATURE_MATCH_MASK(0, 0, KBTS_FEATURE_MATCH_FLAG_RA_HA_VA | KBTS_FEATURE_MATCH_FLAG_INITIAL, KBTS_FEATURE_MATCH_FLAG_HALANT) -# define KBTS_FEATURE_MATCH_MASK_BLWF_PRE_OK KBTS_FEATURE_MATCH_MASK(0, 0, KBTS_FEATURE_MATCH_FLAG_RA_HA_VA, KBTS_FEATURE_MATCH_FLAG_HALANT) -# define KBTS_FEATURE_MATCH_MASK_BLWF_POST KBTS_FEATURE_MATCH_MASK(0, 0, KBTS_FEATURE_MATCH_FLAG_HALANT, KBTS_FEATURE_MATCH_FLAG_RA_HA_VA) -# define KBTS_FEATURE_MATCH_MASK_CJCT KBTS_FEATURE_MATCH_MASK(0, KBTS_FEATURE_MATCH_FLAG_CONSONANT, KBTS_FEATURE_MATCH_FLAG_HALANT, KBTS_FEATURE_MATCH_FLAG_CONSONANT) -# define KBTS_FEATURE_MATCH_MASK_HALF KBTS_FEATURE_MATCH_MASK(KBTS_FEATURE_MATCH_FLAG_CONSONANT | KBTS_FEATURE_MATCH_FLAG_RPHF | KBTS_FEATURE_MATCH_FLAG_POST_BASE, KBTS_FEATURE_MATCH_FLAG_HALANT, KBTS_FEATURE_MATCH_FLAG_ZWNJ, KBTS_FEATURE_MATCH_FLAG_CONSONANT) -# define KBTS_FEATURE_MATCH_MASK_HALF_OK KBTS_FEATURE_MATCH_MASK(KBTS_FEATURE_MATCH_FLAG_CONSONANT, KBTS_FEATURE_MATCH_FLAG_HALANT, 0, 0) -# define KBTS_FEATURE_MATCH_MASK_NUKT KBTS_FEATURE_MATCH_MASK(0, 0, KBTS_FEATURE_MATCH_FLAG_CONSONANT, KBTS_FEATURE_MATCH_FLAG_HALANT) -# define KBTS_FEATURE_MATCH_MASK_PSTF KBTS_FEATURE_MATCH_MASK(0, 0, KBTS_FEATURE_MATCH_FLAG_HALANT | KBTS_FEATURE_MATCH_FLAG_INITIAL, KBTS_FEATURE_MATCH_FLAG_YA) -# define KBTS_FEATURE_MATCH_MASK_VATU KBTS_FEATURE_MATCH_MASK(0, KBTS_FEATURE_MATCH_FLAG_CONSONANT, KBTS_FEATURE_MATCH_FLAG_HALANT, KBTS_FEATURE_MATCH_FLAG_RA_HA_VA) +# define KBTS__FEATURE_MATCH_MASK(W0, W1, W2, W3) (((kbts_u64)(W0) << 48) | ((kbts_u64)(W1) << 32) | ((kbts_u64)(W0) << 16) | (kbts_u64)(W0)) +# define KBTS__FEATURE_MATCH_MASK_AKHN KBTS__FEATURE_MATCH_MASK(0, KBTS__FEATURE_MATCH_FLAG_KA_JA, KBTS__FEATURE_MATCH_FLAG_HALANT, KBTS__FEATURE_MATCH_FLAG_SSA_NYA) +# define KBTS__FEATURE_MATCH_MASK_BLWF_PRE KBTS__FEATURE_MATCH_MASK(0, 0, KBTS__FEATURE_MATCH_FLAG_RA_HA_VA | KBTS__FEATURE_MATCH_FLAG_INITIAL, KBTS__FEATURE_MATCH_FLAG_HALANT) +# define KBTS__FEATURE_MATCH_MASK_BLWF_PRE_OK KBTS__FEATURE_MATCH_MASK(0, 0, KBTS__FEATURE_MATCH_FLAG_RA_HA_VA, KBTS__FEATURE_MATCH_FLAG_HALANT) +# define KBTS__FEATURE_MATCH_MASK_BLWF_POST KBTS__FEATURE_MATCH_MASK(0, 0, KBTS__FEATURE_MATCH_FLAG_HALANT, KBTS__FEATURE_MATCH_FLAG_RA_HA_VA) +# define KBTS__FEATURE_MATCH_MASK_CJCT KBTS__FEATURE_MATCH_MASK(0, KBTS__FEATURE_MATCH_FLAG_CONSONANT, KBTS__FEATURE_MATCH_FLAG_HALANT, KBTS__FEATURE_MATCH_FLAG_CONSONANT) +# define KBTS__FEATURE_MATCH_MASK_HALF KBTS__FEATURE_MATCH_MASK(KBTS__FEATURE_MATCH_FLAG_CONSONANT | KBTS__FEATURE_MATCH_FLAG_RPHF | KBTS__FEATURE_MATCH_FLAG_POST_BASE, KBTS__FEATURE_MATCH_FLAG_HALANT, KBTS__FEATURE_MATCH_FLAG_ZWNJ, KBTS__FEATURE_MATCH_FLAG_CONSONANT) +# define KBTS__FEATURE_MATCH_MASK_HALF_OK KBTS__FEATURE_MATCH_MASK(KBTS__FEATURE_MATCH_FLAG_CONSONANT, KBTS__FEATURE_MATCH_FLAG_HALANT, 0, 0) +# define KBTS__FEATURE_MATCH_MASK_NUKT KBTS__FEATURE_MATCH_MASK(0, 0, KBTS__FEATURE_MATCH_FLAG_CONSONANT, KBTS__FEATURE_MATCH_FLAG_HALANT) +# define KBTS__FEATURE_MATCH_MASK_PSTF KBTS__FEATURE_MATCH_MASK(0, 0, KBTS__FEATURE_MATCH_FLAG_HALANT | KBTS__FEATURE_MATCH_FLAG_INITIAL, KBTS__FEATURE_MATCH_FLAG_YA) +# define KBTS__FEATURE_MATCH_MASK_VATU KBTS__FEATURE_MATCH_MASK(0, KBTS__FEATURE_MATCH_FLAG_CONSONANT, KBTS__FEATURE_MATCH_FLAG_HALANT, KBTS__FEATURE_MATCH_FLAG_RA_HA_VA) -typedef kbts_u32 kbts_substitution_result_flags; -enum kbts_substitution_result_flags_enum +typedef kbts_u32 kbts__substitution_result_flags; +enum kbts__substitution_result_flags_enum { - KBTS_SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION = (1 << 0), - KBTS_SUBSTITUTION_RESULT_FLAG_GROW_BUFFER = (1 << 1), + KBTS__SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION = (1 << 0), + KBTS__SUBSTITUTION_RESULT_FLAG_TRIED_TO_INSERT_WHILE_CHECK_ONLY = (1 << 1), }; -static kbts_substitution_result_flags kbts_DoSubstitution(kbts_shape_state *ShapeState, kbts_lookup_list *LookupList, kbts_gsub_frame *Frames, kbts_u32 *FrameCount_, - kbts_glyph_array *GlyphArray, kbts_u32 CheckOnly, kbts_skip_flags RequestedSkipFlags, kbts_u32 GeneratedGlyphFlags) +static void kbts__BeginLookupApplication(kbts__shape_scratchpad *Scratchpad, kbts_glyph *Glyph) { - kbts_substitution_result_flags Result = 0; - kbts_font *Font = ShapeState->Config->Font; - kbts_glyph *Glyphs = GlyphArray->Glyphs; + Scratchpad->LookupOnePastLastGlyph = Glyph->Next; + Scratchpad->LookupOnePastLastGlyphIndex = 0; +} + +static kbts_glyph *kbts__EndLookupApplication(kbts__shape_scratchpad *Scratchpad) +{ + kbts_glyph *Result = Scratchpad->LookupOnePastLastGlyph; + return Result; +} + +static kbts__substitution_result_flags kbts__DoSubstitution(kbts__shape_scratchpad *Scratchpad, kbts_shape_config *Config, kbts_glyph_storage *Storage, + kbts_lookup_list *LookupList, kbts__gsub_frame *Frames, kbts_un *FrameCount_, + int CheckOnly, kbts__skip_flags RequestedSkipFlags, kbts_u32 GeneratedGlyphFlags) +{ + kbts__substitution_result_flags Result = 0; + kbts_font *Font = Config->Font; kbts_unicode_flags SkipUnicodeFlags = 0; // @Incomplete - kbts_skip_flags RegularSkipFlags = KBTS_SKIP_FLAGS_GSUB_REGULAR(RequestedSkipFlags); - kbts_skip_flags SequenceSkipFlags = KBTS_SKIP_FLAGS_GSUB_SEQUENCE(RequestedSkipFlags); + kbts__skip_flags RegularSkipFlags = KBTS__SKIP_FLAGS_GSUB_REGULAR(RequestedSkipFlags); + kbts__skip_flags SequenceSkipFlags = KBTS__SKIP_FLAGS_GSUB_SEQUENCE(RequestedSkipFlags); GeneratedGlyphFlags |= KBTS_GLYPH_FLAG_GENERATED_BY_GSUB; kbts_un FrameCount = *FrameCount_; - kbts_gsub_frame *Frame = &Frames[FrameCount - 1]; + kbts__gsub_frame *Frame = &Frames[FrameCount - 1]; - kbts_lookup *PackedLookup = kbts_GetLookup(LookupList, Frame->LookupIndex); - kbts_unpacked_lookup Lookup = kbts_UnpackLookup(Font->Gdef, PackedLookup); + kbts__lookup *PackedLookup = kbts__GetLookup(LookupList, Frame->LookupIndex); + kbts__unpacked_lookup Lookup = kbts__UnpackLookup(kbts__BlobTableDataType(Font->Blob, KBTS_BLOB_TABLE_ID_GDEF, kbts__gdef), PackedLookup); kbts_u16 BaseLookupType = Lookup.Type; while(Frame->SubtableIndex < Lookup.SubtableCount) { - kbts_u16 *Subtable = KBTS_POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[Frame->SubtableIndex]); + kbts_u16 *Subtable = KBTS__POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[Frame->SubtableIndex]); // In a type-7 lookup, each subtable can specify a different lookup type. - // We still want to pass kbts_unpacked_lookup around as a useful bag of arguments, though. + // We still want to pass kbts__unpacked_lookup around as a useful bag of arguments, though. // So, we restore the original lookup's type here before resolving each subtable. Lookup.Type = BaseLookupType; while(Lookup.Type == 7) { - kbts_extension *Extension = (kbts_extension *)Subtable; + kbts__extension *Extension = (kbts__extension *)Subtable; Lookup.Type = Extension->LookupType; - Subtable = KBTS_POINTER_OFFSET(kbts_u16, Extension, Extension->Offset); + Subtable = KBTS__POINTER_OFFSET(kbts_u16, Extension, Extension->Offset); } - // :ReverseChaining - // From the Microsoft docs: - // In processing a reverse chaining substitution, i begins at the logical end of the string and moves to the beginning. - // This comment only makes sense when the reverse chaining substitution happens at the top level. - // When it _is_ at the top level, we know we are just doing a linear scan through the string, and since this is a single - // substitution (i.e. one glyph -> one glyph), we know the size of the buffer won't change throughout the scan. - // Given all of this, handling the reverse-scanning nature of this lookup actually becomes very easy: - if((Lookup.Type == 8) && (FrameCount == 1)) - { - Frame->InputGlyphIndex = (kbts_u16)(GlyphArray->Count - 1 - Frame->InputGlyphIndex); - } + kbts_glyph *CurrentGlyph = Frame->InputGlyph; - kbts_glyph *CurrentGlyph = &Glyphs[Frame->InputGlyphIndex]; - kbts_glyph_array InputGlyphs = kbts_GlyphSubArray(GlyphArray, Frame->InputGlyphIndex); - - kbts_skip_flags SkipFlags = (Lookup.Type >= 5) ? SequenceSkipFlags : RegularSkipFlags; - if(kbts_GlyphsIncludedInLookupSubtable(Font, 0, &Lookup, Frame->LookupIndex, Frame->SubtableIndex, GlyphArray, Frame->InputGlyphIndex, SkipFlags, SkipUnicodeFlags)) + kbts__skip_flags SkipFlags = (Lookup.Type >= 5) ? SequenceSkipFlags : RegularSkipFlags; + if(kbts__GlyphsIncludedInLookupSubtable(Storage, Font, 0, &Lookup, Frame->LookupIndex, Frame->SubtableIndex, CurrentGlyph, SkipFlags, SkipUnicodeFlags)) { - kbts_cover_glyph_result Cover = KBTS_ZERO; - Cover.Valid = kbts_GlyphPassesLookupFilter(CurrentGlyph, &Lookup); - if(Cover.Valid && kbts_GsubLookupBeginsWithCoverage(Lookup.Type, Subtable[0])) + kbts__cover_glyph_result Cover = KBTS__ZERO; + Cover.Valid = kbts__GlyphPassesLookupFilter(CurrentGlyph, &Lookup); + if(Cover.Valid && kbts__GsubLookupBeginsWithCoverage(Lookup.Type, Subtable[0])) { - kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subtable, Subtable[1]); - Cover = kbts_CoverGlyph(Coverage, CurrentGlyph->Id); + kbts__coverage *Coverage = KBTS__POINTER_OFFSET(kbts__coverage, Subtable, Subtable[1]); + Cover = kbts__CoverGlyph(Coverage, CurrentGlyph->Id); } if(Cover.Valid) { - kbts_un DeltaGlyphCount = 0; + kbts_un OnePastLastGlyphOffset = 1; + kbts_glyph *OnePastLastGlyph = CurrentGlyph->Next; if((Lookup.Type == 5) || (Lookup.Type == 6)) { - kbts_sequence_lookup_result SequenceLookup = kbts_DoSequenceLookup(&Lookup, Subtable, Cover, GlyphArray, Frame->InputGlyphIndex, SequenceSkipFlags, SkipUnicodeFlags); + kbts__sequence_lookup_result SequenceLookup = kbts__DoSequenceLookup(Storage, &Lookup, Subtable, Cover, CurrentGlyph, SequenceSkipFlags, SkipUnicodeFlags); if(SequenceLookup.Matched) { - KBTS_FOR(FrameIndex, 0, FrameCount - 1) - { - kbts_gsub_frame *ParentFrame = &Frames[FrameIndex]; - - if((ParentFrame->InputGlyphIndex < (Frame->InputGlyphIndex + SequenceLookup.InputSequenceCountIncludingSkippedGlyphs)) && - ((ParentFrame->InputGlyphIndex + ParentFrame->InputGlyphCount) > Frame->InputGlyphIndex)) - { - ParentFrame->InputGlyphCount += (kbts_u16)(SequenceLookup.InputSequenceCountIncludingSkippedGlyphs - Frame->InputGlyphCount); - } - } - - Frame->InputGlyphCount = (kbts_u16)SequenceLookup.InputSequenceCountIncludingSkippedGlyphs; Frame->Records = SequenceLookup.Records; Frame->RecordCount = (kbts_u16)SequenceLookup.RecordCount; Frame->RecordIndex = 0; Frame->SubtableIndex = 0xFFFE; + + OnePastLastGlyphOffset = SequenceLookup.InputSequenceCountIncludingSkippedGlyphs; + OnePastLastGlyph = SequenceLookup.OnePastLastGlyphMatched; } } else @@ -18105,11 +21004,11 @@ static kbts_substitution_result_flags kbts_DoSubstitution(kbts_shape_state *Shap { case 1: { - Result |= KBTS_SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION; + Result |= KBTS__SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION; if(!CheckOnly) { - kbts_single_substitution *Subst = (kbts_single_substitution *)Subtable; + kbts__single_substitution *Subst = (kbts__single_substitution *)Subtable; kbts_u16 NewId = 0; if(Subst->Format == 1) @@ -18120,88 +21019,101 @@ static kbts_substitution_result_flags kbts_DoSubstitution(kbts_shape_state *Shap } else if(Subst->Format == 2) { - kbts_u16 *SubstituteGlyphIds = KBTS_POINTER_AFTER(kbts_u16, Subst); + kbts_u16 *SubstituteGlyphIds = KBTS__POINTER_AFTER(kbts_u16, Subst); NewId = SubstituteGlyphIds[Cover.Index]; } - kbts_GsubMutate(Font, CurrentGlyph, NewId, GeneratedGlyphFlags); + kbts__GsubMutate(Font, CurrentGlyph, NewId, GeneratedGlyphFlags); } } break; case 2: { - Result |= KBTS_SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION; + kbts__multiple_substitution *Subst = (kbts__multiple_substitution *)Subtable; + kbts__sequence *Sequence = kbts__GetSequence(Subst, Cover.Index); + Result |= KBTS__SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION; if(!CheckOnly) { - kbts_multiple_substitution *Subst = (kbts_multiple_substitution *)Subtable; - kbts_sequence *Sequence = kbts_GetSequence(Subst, Cover.Index); - kbts_u16 *SubstGlyphIds = KBTS_POINTER_AFTER(kbts_u16, Sequence); + kbts_u16 *SubstGlyphIds = KBTS__POINTER_AFTER(kbts_u16, Sequence); kbts_un GrowCount = Sequence->GlyphCount - 1; - if(!kbts_GrowGlyphArray(0, &InputGlyphs, 0, GrowCount, 0, 0)) - { - Result |= KBTS_SUBSTITUTION_RESULT_FLAG_GROW_BUFFER; - kbts_TransferGrowRequest(&InputGlyphs, GlyphArray); - goto Cleanup; + if(Sequence->GlyphCount) + { + kbts_glyph OriginalGlyph = *CurrentGlyph; + kbts_glyph *LastInsert = CurrentGlyph; + KBTS__FOR(SubstGlyphIndex, 0, Sequence->GlyphCount) + { + kbts_u32 NewGlyphFlags = GeneratedGlyphFlags | KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION; + + kbts_glyph *NewGlyph = CurrentGlyph; + if(SubstGlyphIndex) + { + NewGlyph = kbts__InsertGlyphAfter(Storage, LastInsert, &OriginalGlyph); + + if(!NewGlyph) + { + Scratchpad->Error = KBTS_SHAPE_ERROR_OUT_OF_MEMORY; + return Result; + } + + NewGlyph->Uid = (kbts_u16)++Scratchpad->NextGlyphUid; + } + else + { + NewGlyphFlags |= KBTS_GLYPH_FLAG_FIRST_IN_MULTIPLE_SUBSTITUTION; + } + + kbts__GsubMutate(Font, NewGlyph, SubstGlyphIds[SubstGlyphIndex], GeneratedGlyphFlags | NewGlyphFlags); + LastInsert = NewGlyph; + } + + OnePastLastGlyph = LastInsert->Next; } - DeltaGlyphCount += GrowCount; - - kbts_glyph OriginalGlyph = *CurrentGlyph; - KBTS_FOR(SubstGlyphIndex, 0, Sequence->GlyphCount) + else { - kbts_glyph NewGlyph = OriginalGlyph; - kbts_GsubMutate(Font, &NewGlyph, SubstGlyphIds[SubstGlyphIndex], GeneratedGlyphFlags | KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION); - if(SubstGlyphIndex) - { - NewGlyph.Uid = (kbts_u16)++ShapeState->NextGlyphUid; - } - else - { - NewGlyph.Flags |= KBTS_GLYPH_FLAG_FIRST_IN_MULTIPLE_SUBSTITUTION; - } - Glyphs[Frame->InputGlyphIndex + SubstGlyphIndex] = NewGlyph; + kbts__FreeGlyph(Scratchpad, Storage, CurrentGlyph); } - Frame->InputGlyphCount = Sequence->GlyphCount; + OnePastLastGlyphOffset = 1 + GrowCount; // Shift other frames' input cursors. - KBTS_FOR(FrameIndex, 0, FrameCount - 1) + KBTS__FOR(FrameIndex, 0, FrameCount - 1) { - kbts_gsub_frame *OtherFrame = &Frames[FrameIndex]; + kbts__gsub_frame *OtherFrame = &Frames[FrameIndex]; - if(OtherFrame->InputGlyphIndex > Frame->InputGlyphIndex) + if(OtherFrame->StartIndex > Frame->StartIndex) { - OtherFrame->InputGlyphIndex = (kbts_u16)(OtherFrame->InputGlyphIndex + GrowCount); - } - else if((OtherFrame->InputGlyphIndex + OtherFrame->InputGlyphCount) > Frame->InputGlyphIndex) - { - OtherFrame->InputGlyphCount = (kbts_u16)(OtherFrame->InputGlyphCount + GrowCount); + OtherFrame->StartIndex = (kbts_u16)(OtherFrame->StartIndex + GrowCount); } } } + else if(Sequence->GlyphCount > 1) + { + Result |= KBTS__SUBSTITUTION_RESULT_FLAG_TRIED_TO_INSERT_WHILE_CHECK_ONLY; + } } break; case 3: { - Result |= KBTS_SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION; + Result |= KBTS__SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION; if(!CheckOnly) { - kbts_alternate_substitution *Subst = (kbts_alternate_substitution *)Subtable; - kbts_alternate_set *Set = kbts_GetAlternateSet(Subst, Cover.Index); - kbts_u16 *AltGlyphIds = KBTS_POINTER_AFTER(kbts_u16, Set); + kbts__alternate_substitution *Subst = (kbts__alternate_substitution *)Subtable; + kbts__alternate_set *Set = kbts__GetAlternateSet(Subst, Cover.Index); + kbts_u16 *AltGlyphIds = KBTS__POINTER_AFTER(kbts_u16, Set); kbts_un AlternateIndex = 0; { - kbts_feature_set *ShaperFeatures = ShapeState->Config->Features; + kbts__feature_set *ShaperFeatures = &Config->Features; kbts_glyph_config *GlyphConfig = CurrentGlyph->Config; if(GlyphConfig) { int HasOverride = 0; - KBTS_FOR(WordIndex, 0, KBTS_ARRAY_LENGTH(GlyphConfig->EnabledFeatures.Flags)) + KBTS__FOR(WordIndex, 0, KBTS__ARRAY_LENGTH(GlyphConfig->EnabledFeatures.Flags)) { kbts_u64 Flags = GlyphConfig->EnabledFeatures.Flags[WordIndex] & ShaperFeatures->Flags[WordIndex]; if(Flags) @@ -18213,22 +21125,25 @@ static kbts_substitution_result_flags kbts_DoSubstitution(kbts_shape_state *Shap if(HasOverride) { - kbts_op_state_gsub *Gsub = &ShapeState->OpState.OpSpecific.Gsub; - KBTS_FOR(OverrideIndex, 0, GlyphConfig->FeatureOverrideCount) + for(kbts__feature_override_header *OverrideHeader = GlyphConfig->FeatureOverrideSentinel.Next; + OverrideHeader != &GlyphConfig->FeatureOverrideSentinel; + OverrideHeader = OverrideHeader->Next) { - kbts_feature_override *Override = &GlyphConfig->FeatureOverrides[OverrideIndex]; - kbts_u32 EnabledOrAlternatePlusOne = Override->EnabledOrAlternatePlusOne; + kbts__feature_override *Override = (kbts__feature_override *)OverrideHeader; + int Value = Override->Value; + kbts__feature_id Id = kbts__FeatureTagToId(Override->Tag); - if(EnabledOrAlternatePlusOne && kbts_ContainsFeature(&Gsub->LookupFeatures, Override->Id)) + if(Value && + kbts__ContainsFeature(&Scratchpad->LookupFeatures, Id)) { int Match = 1; - if(!Override->Id) + if(!Id) { // Slow path for unregistered features. Match = 0; - KBTS_FOR(UnregisteredFeatureIndex, 0, ShapeState->OpState.UnregisteredFeatureCount) + KBTS__FOR(UnregisteredFeatureIndex, 0, Scratchpad->UnregisteredFeatureCount) { - if(Override->Tag == ShapeState->OpState.UnregisteredFeatureTags[UnregisteredFeatureIndex]) + if(Override->Tag == Scratchpad->UnregisteredFeatureTags[UnregisteredFeatureIndex]) { Match = 1; break; @@ -18238,7 +21153,8 @@ static kbts_substitution_result_flags kbts_DoSubstitution(kbts_shape_state *Shap if(Match) { - AlternateIndex = EnabledOrAlternatePlusOne - 1; + AlternateIndex = (kbts_un)(Value - 1); + break; } } @@ -18253,157 +21169,204 @@ static kbts_substitution_result_flags kbts_DoSubstitution(kbts_shape_state *Shap } kbts_u16 NewId = AltGlyphIds[AlternateIndex]; - kbts_GsubMutate(Font, CurrentGlyph, NewId, GeneratedGlyphFlags); + kbts__GsubMutate(Font, CurrentGlyph, NewId, GeneratedGlyphFlags); } } break; case 4: { - kbts_ligature_substitution *Subst = (kbts_ligature_substitution *)Subtable; - kbts_ligature_set *Set = kbts_GetLigatureSet(Subst, Cover.Index); + kbts__ligature_substitution *Subst = (kbts__ligature_substitution *)Subtable; + kbts__ligature_set *Set = kbts__GetLigatureSet(Subst, Cover.Index); - KBTS_FOR(LigatureIndex, 0, Set->Count) + KBTS__FOR(LigatureIndex, 0, Set->Count) { - kbts_ligature *Ligature = kbts_GetLigature(Set, LigatureIndex); - kbts_u16 *ComponentIds = KBTS_POINTER_AFTER(kbts_u16, Ligature); + kbts__ligature *Ligature = kbts__GetLigature(Set, LigatureIndex); + kbts_u16 *ComponentIds = KBTS__POINTER_AFTER(kbts_u16, Ligature); + + kbts_un MatchingGlyphCount = 1; - if(Ligature->ComponentCount <= InputGlyphs.Count) { - kbts_un MatchingGlyphCount = 1; - + kbts_glyph *LigatureGlyphCursor = CurrentGlyph->Next; + while(kbts__GlyphIsValid(Storage, LigatureGlyphCursor) && (MatchingGlyphCount < Ligature->ComponentCount)) { - kbts_un InputIndex = 1; - while((InputIndex < InputGlyphs.Count) && (MatchingGlyphCount < Ligature->ComponentCount)) + // A ligature may contain an explicit ZWJ, which SkipGlyph() would probably skip. + // The expected behavior in that case is to assume the font designer knows what they are doing + // and match the ZWJ. + if(LigatureGlyphCursor->Id == ComponentIds[MatchingGlyphCount - 1]) { - kbts_glyph *Glyph = &InputGlyphs.Glyphs[InputIndex]; - // A ligature may contain an explicit ZWJ, which SkipGlyph() would probably skip. - // The expected behavior in that case is to assume the font designer knows what they are doing - // and match the ZWJ. - if(Glyph->Id == ComponentIds[MatchingGlyphCount - 1]) - { - MatchingGlyphCount += 1; - } - else if(!kbts_SkipGlyph(Glyph, &Lookup, RegularSkipFlags, SkipUnicodeFlags)) - { - break; - } - InputIndex += 1; + MatchingGlyphCount += 1; } - } - - if(MatchingGlyphCount == Ligature->ComponentCount) - { - Result |= KBTS_SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION; - - if(!CheckOnly) + else if(!kbts__SkipGlyph(LigatureGlyphCursor, &Lookup, RegularSkipFlags, SkipUnicodeFlags)) { - kbts_u32 LigatureUid = ++ShapeState->NextGlyphUid; + break; + } - { // For glyphs that aren't part of the ligature, store which component it is attached to. - // For glyphs that _are_, eat them. - kbts_un LigatureGlyphCount = 1; - kbts_un ReadCursor = 1; - kbts_un WriteCursor = 1; + LigatureGlyphCursor = LigatureGlyphCursor->Next; + } + } - while((LigatureGlyphCount < InputGlyphs.Count) && (LigatureGlyphCount < Ligature->ComponentCount) && (ReadCursor < InputGlyphs.Count)) + if(MatchingGlyphCount == Ligature->ComponentCount) + { + Result |= KBTS__SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION; + + if(!CheckOnly) + { + kbts_u32 LigatureUid = ++Scratchpad->NextGlyphUid; + kbts_un ComponentCount = Ligature->ComponentCount; + + { // For glyphs that aren't part of the ligature, store which component it is attached to. + // For glyphs that _are_, eat them. + kbts_un LigatureGlyphCount = 1; + kbts_un GrowCount = 0; + + // Consider this example: + // ABCD -> DB (A and C form a ligature) + // DB -> DEB (E is inserted in whatever way) + // DEB -> FB (D and E form a ligature) + // In that case, 'B' was supposed to be attached to D, but D does not exist anymore. + // To handle this case, we go through the ligature, counting the total flattened components + // and the ligature info of the last glyph that is part of the ligature. + // Then, all trailing marks get are re-attached to the new ligature, and their component indices + // are adjusted to take into account the new (flattened) component count. + // (I say 'flattened' here because a previous ligature glyph counts as multiple components.) + kbts_un PreviousLigatureUid = CurrentGlyph->LigatureUid; + kbts_un PreviousComponentCount = CurrentGlyph->LigatureComponentCount; + if(!PreviousComponentCount) + { + PreviousComponentCount = 1; + } + kbts_un RunningComponentCount = PreviousComponentCount; + + kbts_glyph *LigatureGlyphCursor = CurrentGlyph->Next; + while(kbts__GlyphIsValid(Storage, LigatureGlyphCursor) && (LigatureGlyphCount < ComponentCount)) + { + kbts_glyph *Next = LigatureGlyphCursor->Next; + + if(LigatureGlyphCursor->Id == ComponentIds[LigatureGlyphCount - 1]) { - kbts_glyph *Glyph = &InputGlyphs.Glyphs[ReadCursor]; - - if(Glyph->Id == ComponentIds[LigatureGlyphCount - 1]) + PreviousLigatureUid = LigatureGlyphCursor->LigatureUid; + PreviousComponentCount = LigatureGlyphCursor->LigatureComponentCount; + if(!PreviousComponentCount) { - LigatureGlyphCount += 1; - ReadCursor += 1; + PreviousComponentCount = 1; } - else if(kbts_SkipGlyph(Glyph, &Lookup, RegularSkipFlags, SkipUnicodeFlags)) - { - Glyph->LigatureComponentIndexPlusOne = (kbts_u16)LigatureGlyphCount; - Glyph->LigatureUid = (kbts_u16)LigatureUid; + RunningComponentCount += PreviousComponentCount; - InputGlyphs.Glyphs[WriteCursor++] = InputGlyphs.Glyphs[ReadCursor++]; + LigatureGlyphCount += 1; + + // Eat! + kbts__FreeGlyph(Scratchpad, Storage, LigatureGlyphCursor); + GrowCount -= 1; + } + else if(kbts__SkipGlyph(LigatureGlyphCursor, &Lookup, RegularSkipFlags, SkipUnicodeFlags)) + { + LigatureGlyphCursor->LigatureComponentIndexPlusOne = (kbts_u16)LigatureGlyphCount; + LigatureGlyphCursor->LigatureUid = (kbts_u16)LigatureUid; + LigatureGlyphCursor->LigatureComponentCount = (kbts_u16)ComponentCount; + } + else + { + break; + } + + LigatureGlyphCursor = Next; + } + + OnePastLastGlyph = CurrentGlyph->Next; + + // Re-attach trailing marks that were part of a component ligature to the new ligature. + if(PreviousLigatureUid) + { + kbts_un DeltaComponentCount = RunningComponentCount - PreviousComponentCount; + + while(kbts__GlyphIsValid(Storage, LigatureGlyphCursor)) + { + kbts_un PreviousComponentIndexPlusOne = LigatureGlyphCursor->LigatureComponentIndexPlusOne; + + if((LigatureGlyphCursor->Classes.Class == KBTS__GLYPH_CLASS_MARK) && + (LigatureGlyphCursor->LigatureUid == PreviousLigatureUid) && + PreviousComponentIndexPlusOne) + { + if(PreviousComponentIndexPlusOne > PreviousComponentCount) + { + PreviousComponentIndexPlusOne = PreviousComponentCount; + } + + kbts_un NewComponentIndexPlusOne = PreviousComponentIndexPlusOne + DeltaComponentCount; + + LigatureGlyphCursor->LigatureUid = (kbts_u16)LigatureUid; + LigatureGlyphCursor->LigatureComponentIndexPlusOne = (kbts_u16)NewComponentIndexPlusOne; } else { break; } - } - // Finish moving all non-ligature glyphs in their place. - // We are effectively shrinking the whole buffer here, so we have to touch - // glyphs outside of our own cluster. - kbts_un GrowCount = WriteCursor - ReadCursor; // Negative - kbts_GrowGlyphArray(0, &InputGlyphs, WriteCursor, GrowCount, 0, 0); - DeltaGlyphCount += GrowCount; - - // Update frame input cursors. - KBTS_FOR(FrameIndex, 0, FrameCount - 1) - { - kbts_gsub_frame *OtherFrame = &Frames[FrameIndex]; - - if(OtherFrame->InputGlyphIndex >= Frame->InputGlyphIndex) - { - kbts_un OtherInputIndex = OtherFrame->InputGlyphIndex + GrowCount; - OtherInputIndex = KBTS_MAX(OtherInputIndex, Frame->InputGlyphIndex); - OtherFrame->InputGlyphIndex = (kbts_u16)OtherInputIndex; - } - else - { - kbts_un End = OtherFrame->InputGlyphIndex + OtherFrame->InputGlyphCount; - End = KBTS_MIN(End, GlyphArray->TotalCount); - OtherFrame->InputGlyphCount = (kbts_u16)(End - OtherFrame->InputGlyphIndex); - } + LigatureGlyphCursor = LigatureGlyphCursor->Next; } } - // Currently, we only take the main glyph's config into account while making the ligature's config. - // Maybe we should merge all of the components' configs into one instead? - kbts_GsubMutate(Font, CurrentGlyph, Ligature->Glyph, GeneratedGlyphFlags | KBTS_GLYPH_FLAG_LIGATURE); - CurrentGlyph->Uid = (kbts_u16)LigatureUid; - // Harfbuzz does this, because Uniscribe does this, and so we do the same. Sigh. - CurrentGlyph->Flags &= ~KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION; + // Update frame input cursors. + KBTS__FOR(FrameIndex, 0, FrameCount - 1) + { + kbts__gsub_frame *OtherFrame = &Frames[FrameIndex]; + + if(OtherFrame->StartIndex >= Frame->StartIndex) + { + OtherFrame->StartIndex += (kbts_u16)GrowCount; + } + } } - break; + // Currently, we only take the main glyph's config into account while making the ligature's config. + // Maybe we should merge all of the components' configs into one instead? + kbts__GsubMutate(Font, CurrentGlyph, Ligature->Glyph, GeneratedGlyphFlags | KBTS_GLYPH_FLAG_LIGATURE); + CurrentGlyph->Uid = (kbts_u16)LigatureUid; + CurrentGlyph->LigatureUid = (kbts_u16)LigatureUid; + CurrentGlyph->LigatureComponentCount = (kbts_u16)ComponentCount; + + // Harfbuzz does this, because Uniscribe does this, and so we do the same. Sigh. + CurrentGlyph->Flags &= ~KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION; } + + break; } } } break; case 8: { - kbts_reverse_chain_substitution *Subst = (kbts_reverse_chain_substitution *)Subtable; - kbts_unpacked_reverse_chain_substitution Unpacked = kbts_UnpackReverseChainSubstitution(Subst, 0); + kbts__reverse_chain_substitution *Subst = (kbts__reverse_chain_substitution *)Subtable; + kbts__unpacked_reverse_chain_substitution Unpacked = kbts__UnpackReverseChainSubstitution(Subst, 0); // :BoundsChecking if(Cover.Index < Unpacked.GlyphCount) { // Should we use regular or sequence skip flags here? - kbts_glyph_array BacktrackGlyphs = kbts_ClipGlyphArray(GlyphArray, Frame->InputGlyphIndex); - kbts_sequence_match BacktrackMatch = kbts_MatchCoverageSequence(&Lookup, RegularSkipFlags, SkipUnicodeFlags, Subst, Unpacked.BacktrackCoverageOffsets, Unpacked.BacktrackCount, - &BacktrackGlyphs, (kbts_un)Frame->InputGlyphIndex - 1, -1); - kbts_glyph_array FollowupGlyphs = kbts_GlyphSubArray(&InputGlyphs, 1); - kbts_sequence_match LookaheadMatch = kbts_MatchCoverageSequence(&Lookup, RegularSkipFlags, SkipUnicodeFlags, Subst, Unpacked.LookaheadCoverageOffsets, Unpacked.LookaheadCount, - &FollowupGlyphs, 0, 1); + kbts__sequence_match BacktrackMatch = kbts__MatchCoverageSequence(Storage, &Lookup, RegularSkipFlags, SkipUnicodeFlags, Subst, Unpacked.BacktrackCoverageOffsets, Unpacked.BacktrackCount, + CurrentGlyph->Prev, 1); + kbts__sequence_match LookaheadMatch = kbts__MatchCoverageSequence(Storage, &Lookup, RegularSkipFlags, SkipUnicodeFlags, Subst, Unpacked.LookaheadCoverageOffsets, Unpacked.LookaheadCount, + CurrentGlyph->Next, 0); if((BacktrackMatch.MatchCount == Unpacked.BacktrackCount) && (LookaheadMatch.MatchCount == Unpacked.LookaheadCount)) { - Result |= KBTS_SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION; - kbts_GsubMutate(Font, CurrentGlyph, Unpacked.SubstituteGlyphIds[Cover.Index], GeneratedGlyphFlags); + Result |= KBTS__SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION; + kbts__GsubMutate(Font, CurrentGlyph, Unpacked.SubstituteGlyphIds[Cover.Index], GeneratedGlyphFlags); } } } break; } - if(Result & KBTS_SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION) + if(Result & KBTS__SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION) { Frame->SubtableIndex = 0xFFFE; // From the Microsoft docs: // To move to the “next” glyph, the client skips all the glyphs that participated in the lookup operation: // glyphs that were substituted/positioned as well as any other glyphs in the matched input sequence. - - GlyphArray->Count += DeltaGlyphCount; - GlyphArray->TotalCount += DeltaGlyphCount; } } + + kbts__SetLookupOnePastLastGlyph(Scratchpad, Frame->StartIndex + OnePastLastGlyphOffset, OnePastLastGlyph); } } @@ -18412,39 +21375,43 @@ static kbts_substitution_result_flags kbts_DoSubstitution(kbts_shape_state *Shap if(Frame->RecordIndex < Frame->RecordCount) { - kbts_sequence_lookup_record *SequenceRecord = &Frame->Records[Frame->RecordIndex++]; + kbts__sequence_lookup_record *SequenceRecord = &Frame->Records[Frame->RecordIndex++]; - kbts_gsub_frame NewFrame = KBTS_ZERO; - NewFrame.LookupIndex = SequenceRecord->LookupListIndex; - NewFrame.SubtableIndex = 0; - NewFrame.InputGlyphIndex = Frame->InputGlyphIndex; - - if(SequenceRecord->SequenceIndex) + if(FrameCount < KBTS_LOOKUP_STACK_SIZE) { - // @Speed: Re-scan the sequence to find where we are in the _filtered_ sequence. - kbts_un SequenceInputIndex = 0; - KBTS_FOR(FilterAt, Frame->InputGlyphIndex + 1, GlyphArray->Count) + kbts__gsub_frame NewFrame = KBTS__ZERO; + NewFrame.LookupIndex = SequenceRecord->LookupListIndex; + NewFrame.StartIndex = Frame->StartIndex; + NewFrame.InputGlyph = Frame->InputGlyph; + + if(SequenceRecord->SequenceIndex) { - kbts_glyph *FilterGlyph = &Glyphs[FilterAt]; - - // @Incomplete: SequenceSkipFlags? 0? - // What do we use here? - if(!kbts_SkipGlyph(FilterGlyph, &Lookup, 0, SkipUnicodeFlags)) + // @Speed: Re-scan the sequence to find where we are in the _filtered_ sequence. + kbts_un SequenceInputIndex = 0; + for(kbts_glyph *FilterGlyph = Frame->InputGlyph->Next; + kbts__GlyphIsValid(Storage, FilterGlyph); + FilterGlyph = FilterGlyph->Next) { - SequenceInputIndex += 1; - - if(SequenceInputIndex == SequenceRecord->SequenceIndex) + // @Incomplete: SequenceSkipFlags? 0? + // What do we use here? + if(!kbts__SkipGlyph(FilterGlyph, &Lookup, 0, SkipUnicodeFlags)) { - NewFrame.InputGlyphIndex = (kbts_u16)FilterAt; + SequenceInputIndex += 1; - break; + if(SequenceInputIndex == SequenceRecord->SequenceIndex) + { + NewFrame.InputGlyph = FilterGlyph; + + break; + } } + + NewFrame.StartIndex += 1; } } - } - NewFrame.InputGlyphCount = 1; - Frames[FrameCount++] = NewFrame; + Frames[FrameCount++] = NewFrame; + } } // Only actually pop the frame if we haven't pushed anything else in the meantime. @@ -18453,101 +21420,175 @@ static kbts_substitution_result_flags kbts_DoSubstitution(kbts_shape_state *Shap FrameCount -= 1; } -Cleanup:; - *FrameCount_ = (kbts_u32)FrameCount; + *FrameCount_ = FrameCount; return Result; } -static kbts_u32 kbts_WouldSubstitute(kbts_shape_state *ShapeState, kbts_lookup_list *LookupList, kbts_gsub_frame *Frames, kbts_feature *Feature, kbts_skip_flags SkipFlags, kbts_glyph *Glyphs, kbts_un GlyphCount) +static kbts__glyph_list kbts__PushGlyphList(kbts_glyph_storage *Storage, kbts_glyph *First, kbts_glyph *Last) { - kbts_u32 Result = 0; - kbts_glyph_array GlyphArray = kbts_GlyphArray(Glyphs, GlyphCount, GlyphCount, GlyphCount); + kbts__glyph_list Result = KBTS__ZERO; - kbts_iterate_lookups IterateLookups = kbts_IterateLookups(LookupList, Feature); - while(kbts_NextLookup(&IterateLookups)) + Result.SentinelPrev = Storage->GlyphSentinel.Prev; + Result.SentinelNext = Storage->GlyphSentinel.Next; + Result.OneBeforeFirst = First->Prev; + Result.OnePastLast = Last->Next; + + First->Prev = Last->Next = (kbts_glyph *)&Storage->GlyphSentinel; + First->Prev->Next = First; + Last->Next->Prev = Last; + + return Result; +} + +static void kbts__PopGlyphList(kbts_glyph_storage *Storage, kbts__glyph_list *List) +{ + List->OneBeforeFirst->Next = Storage->GlyphSentinel.Next; + List->OnePastLast->Prev = Storage->GlyphSentinel.Prev; + + // Storage->GlyphSentinel.Prev->Next = Storage->GlyphSentinel.Next->Prev = &Storage->GlyphSentinel; + + if((kbts_glyph *)&Storage->GlyphSentinel != List->OneBeforeFirst) { - kbts_un GlyphIndex = 0; + Storage->GlyphSentinel.Next = List->SentinelNext; + } + if((kbts_glyph *)&Storage->GlyphSentinel != List->OnePastLast) + { + Storage->GlyphSentinel.Prev = List->SentinelPrev; + } - while(GlyphIndex < GlyphCount) + Storage->GlyphSentinel.Prev->Next = Storage->GlyphSentinel.Next->Prev = (kbts_glyph *)&Storage->GlyphSentinel; + + *List = KBTS__ZERO_TYPE(kbts__glyph_list); +} + +static int kbts__WouldSubstitute(kbts__shape_scratchpad *Scratchpad, kbts_shape_config *Config, kbts_glyph_storage *Storage, + kbts_lookup_list *LookupList, + kbts__gsub_frame *Frames, kbts__feature *Feature, kbts__skip_flags SkipFlags, + kbts_glyph *Glyphs, kbts_un GlyphCount) +{ + int Result = 0; + + KBTS_ASSERT(GlyphCount <= 4); + kbts_glyph TempSentinel; + kbts_glyph Scratch[4]; + + KBTS__FOR(GlyphIndex, 0, GlyphCount) + { + kbts_glyph *ScratchGlyph = &Scratch[GlyphIndex]; + + // Glyphs is assumed to be in-order on the stack or something. + // This is one of the rare places where we manipulate arrays. + *ScratchGlyph = Glyphs[GlyphIndex]; + ScratchGlyph->Prev = ScratchGlyph - 1; + ScratchGlyph->Next = ScratchGlyph + 1; + } + Scratch[0].Prev = &TempSentinel; + Scratch[GlyphCount - 1].Next = &TempSentinel; + TempSentinel.Next = &Scratch[0]; + TempSentinel.Prev = &Scratch[GlyphCount - 1]; + + kbts__glyph_list OldList = kbts__PushGlyphList(Storage, &Scratch[0], &Scratch[GlyphCount - 1]); + + kbts__iterate_lookups IterateLookups = kbts__IterateLookups(LookupList, Feature); + while(kbts__NextLookup(&IterateLookups)) + { + kbts_glyph *CurrentGlyph = &Scratch[0]; + while(kbts__GlyphIsValid(Storage, CurrentGlyph)) { - kbts_gsub_frame *Frame = &Frames[0]; + kbts__gsub_frame *Frame = &Frames[0]; + *Frame = KBTS__ZERO_TYPE(kbts__gsub_frame); Frame->LookupIndex = IterateLookups.LookupIndex; Frame->SubtableIndex = 0; - Frame->InputGlyphIndex = 0; - Frame->InputGlyphCount = 1; - kbts_u32 FrameCount = 1; + Frame->StartIndex = 0; + Frame->InputGlyph = CurrentGlyph; + kbts_un FrameCount = 1; + + kbts__BeginLookupApplication(Scratchpad, CurrentGlyph); while(FrameCount) { - kbts_substitution_result_flags SubstitutionResult = kbts_DoSubstitution(ShapeState, LookupList, Frames, &FrameCount, &GlyphArray, 1, SkipFlags, 0); + kbts__substitution_result_flags SubstitutionResult = kbts__DoSubstitution(Scratchpad, Config, Storage, LookupList, Frames, &FrameCount, 1, SkipFlags, 0); - if(SubstitutionResult & KBTS_SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION) + if(SubstitutionResult & KBTS__SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION) { Result = 1; goto Done; } } - GlyphIndex += Frames[0].InputGlyphCount; + CurrentGlyph = kbts__EndLookupApplication(Scratchpad); } } Done:; + kbts__PopGlyphList(Storage, &OldList); + return Result; } -static int kbts_NextLookupIndex(kbts_op_state *S, kbts_un *LookupIndex, kbts_u32 *SkipFlags_, kbts_u32 *GlyphFilter_, kbts_feature_set *FeatureSet_) +static int kbts__NextLookupIndex(kbts__shape_scratchpad *Scratchpad, kbts_shape_config *Config, kbts_un *LookupIndex_, kbts_u32 *SkipFlags_, kbts_u32 *GlyphFilter_, kbts__feature_set *FeatureSet_) { - kbts_un LowestIndex = 0xFFFFFFFF; - KBTS_FOR(FeatureIndex, 0, S->FeatureCount) - { - kbts_lookup_indices *Indices = &S->FeatureLookupIndices[FeatureIndex]; - kbts_un Index = Indices->Indices[0]; - if(Index < LowestIndex) - { - LowestIndex = Index; - } - } + int Result = 0; - kbts_feature_set FeatureSet = KBTS_ZERO; - kbts_skip_flags SkipFlags = 0; + kbts_un FeatureStageIndex = Scratchpad->FeatureStagesRead - 1; + kbts_u32 SkipFlags = 0; kbts_u32 GlyphFilter = 0; - kbts_un UnregisteredFeatureCount = 0; - KBTS_FOR(FeatureIndex, 0, S->FeatureCount) + Scratchpad->UnregisteredFeatureCount = 0; + kbts_un ResultLookupIndex = 0; + kbts__baked_feature_stage *FeatureStage = &Config->FeatureStages[FeatureStageIndex]; + + *FeatureSet_ = KBTS__ZERO_TYPE(kbts__feature_set); + + while(Scratchpad->FeatureIndexIndex < FeatureStage->FeatureIndexCount) { - kbts_lookup_indices *Indices = &S->FeatureLookupIndices[FeatureIndex]; - kbts_un Index = Indices->Indices[0]; - if(Index == LowestIndex) + KBTS_ASSERT(Scratchpad->FeatureIndexIndex < FeatureStage->FeatureIndexCount); + + kbts_u16 FeatureIndex = FeatureStage->FeatureIndices[Scratchpad->FeatureIndexIndex]; + KBTS_ASSERT(FeatureIndex < FeatureStage->FeatureIndexCount); + + kbts__baked_feature *Feature = &FeatureStage->Features[FeatureIndex]; + kbts_un Offset = Scratchpad->BakedLookupSubtablesRead[FeatureIndex]; + + KBTS_ASSERT(Offset < Feature->Count); + kbts_un LookupIndex = Feature->Indices[Offset]; + + if(!Result) { - SkipFlags |= Indices->SkipFlags; - GlyphFilter |= Indices->GlyphFilter; - kbts_AddFeature(&FeatureSet, Indices->FeatureId); + ResultLookupIndex = LookupIndex; + Result = 1; + } - if(!Indices->FeatureId && (UnregisteredFeatureCount < KBTS_MAX_SIMULTANEOUS_FEATURES)) + if(LookupIndex == ResultLookupIndex) + { + kbts__AddFeature(FeatureSet_, Feature->FeatureId); + SkipFlags |= Feature->SkipFlags; + GlyphFilter |= Feature->GlyphFilter; + + if(!Feature->FeatureId && (Scratchpad->UnregisteredFeatureCount < KBTS_MAX_SIMULTANEOUS_FEATURES)) { - S->UnregisteredFeatureTags[UnregisteredFeatureCount++] = Indices->FeatureTag; + Scratchpad->UnregisteredFeatureTags[Scratchpad->UnregisteredFeatureCount++] = Feature->FeatureTag; } - ++Indices->Indices; --Indices->Count; - if(!Indices->Count) - { - S->FeatureLookupIndices[FeatureIndex--] = S->FeatureLookupIndices[--S->FeatureCount]; - } + Scratchpad->FeatureIndexIndex += 1; + Scratchpad->BakedLookupSubtablesRead[FeatureIndex] += 1; + } + else + { + break; } } - S->UnregisteredFeatureCount = (kbts_u32)UnregisteredFeatureCount; - *LookupIndex = LowestIndex; + *LookupIndex_ = ResultLookupIndex; *SkipFlags_ = SkipFlags; *GlyphFilter_ = GlyphFilter; - *FeatureSet_ = FeatureSet; - return LowestIndex != 0xFFFFFFFF; + + return Result; } -static int kbts_ConfigAllowsFeatures(kbts_op_state *S, kbts_shape_config *Config, kbts_glyph_config *GlyphConfig, kbts_feature_set *Features) +static int kbts__ConfigAllowsFeatures(kbts__shape_scratchpad *Scratchpad, kbts_shape_config *Config, kbts_glyph_config *GlyphConfig, kbts__feature_set *Features) { - kbts_glyph_config DummyGlyphConfig = KBTS_ZERO; + kbts_glyph_config DummyGlyphConfig = KBTS__ZERO; kbts_u64 UserEnabled = 0; // Whether the user enabled _any_ feature corresponding to this lookup. kbts_u64 UserDisabled = 1; // Whether the user disabled _all_ features corresponding to this lookup. kbts_u64 DefaultEnabled = 0; // Whether any feature is non-user. @@ -18558,686 +21599,793 @@ static int kbts_ConfigAllowsFeatures(kbts_op_state *S, kbts_shape_config *Config } kbts_u64 Mask = 1; // Ignore unregistered features in the broad pass. - KBTS_FOR(WordIndex, 0, KBTS_ARRAY_LENGTH(GlyphConfig->EnabledFeatures.Flags)) + KBTS__FOR(WordIndex, 0, KBTS__ARRAY_LENGTH(GlyphConfig->EnabledFeatures.Flags)) { kbts_u64 LookupFeatureFlags = Features->Flags[WordIndex] & ~Mask; Mask = 0; UserEnabled |= GlyphConfig->EnabledFeatures.Flags[WordIndex] & LookupFeatureFlags; UserDisabled &= (GlyphConfig->DisabledFeatures.Flags[WordIndex] & LookupFeatureFlags) == LookupFeatureFlags; - DefaultEnabled |= Features->Flags[WordIndex] & Config->Features->Flags[WordIndex]; + DefaultEnabled |= Features->Flags[WordIndex] & Config->Features.Flags[WordIndex]; } - if(Features->Flags[0] & (GlyphConfig->EnabledFeatures.Flags[0] | GlyphConfig->DisabledFeatures.Flags[0]) & KBTS_FEATURE_FLAG0(UNREGISTERED)) + if(Features->Flags[0] & (GlyphConfig->EnabledFeatures.Flags[0] | GlyphConfig->DisabledFeatures.Flags[0]) & KBTS__FEATURE_FLAG0(UNREGISTERED)) { // Slow path for unregistered features. - KBTS_FOR(FeatureOverrideIndex, 0, GlyphConfig->FeatureOverrideCount) + for(kbts__feature_override_header *Header = GlyphConfig->FeatureOverrideSentinel.Next; + Header != &GlyphConfig->FeatureOverrideSentinel; + Header = Header->Next) { - kbts_feature_override *Override = &GlyphConfig->FeatureOverrides[FeatureOverrideIndex]; - if(Override->Id == KBTS_FEATURE_ID_UNREGISTERED) + kbts__feature_override *Override = (kbts__feature_override *)Header; + kbts__feature_id Id = kbts__FeatureTagToId(Override->Tag); + + if(Id == KBTS__FEATURE_ID_UNREGISTERED) { kbts_feature_tag OverrideTag = Override->Tag; - KBTS_FOR(UnregisteredFeatureIndex, 0, S->UnregisteredFeatureCount) + + KBTS__FOR(UnregisteredFeatureIndex, 0, Scratchpad->UnregisteredFeatureCount) { - if(OverrideTag == S->UnregisteredFeatureTags[UnregisteredFeatureIndex]) + if(OverrideTag == Scratchpad->UnregisteredFeatureTags[UnregisteredFeatureIndex]) { - UserEnabled |= Override->EnabledOrAlternatePlusOne; - UserDisabled &= !Override->EnabledOrAlternatePlusOne; + UserEnabled |= (kbts_u32)Override->Value; + UserDisabled &= !Override->Value; break; } } } } } + int Result = (!UserDisabled && (DefaultEnabled || UserEnabled)); + return Result; } -static kbts_u32 kbts_ExecuteOp(kbts_shape_state *ShapeState, kbts_glyph_array *GlyphArray) +static void kbts__DllistReverseSublist(kbts_glyph *First, kbts_glyph *OnePastLast) { - KBTS_INSTRUMENT_FUNCTION_BEGIN - kbts_shape_config *Config = ShapeState->Config; - kbts_font *Font = Config->Font; - kbts_op *Op = &ShapeState->Op; - kbts_op_state *S = &ShapeState->OpState; - kbts_glyph *Glyphs = GlyphArray->Glyphs; + kbts_glyph *OneBeforeFirst = First->Prev; + kbts_glyph *Last = First; - kbts_u32 ResumePoint = S->ResumePoint; - S->ResumePoint = 0; - switch(ResumePoint) + for(kbts_glyph *Glyph = First; + ; + ) { - case 1: goto ResumePoint1; break; - case 2: goto ResumePoint2; break; - case 3: goto ResumePoint3; break; - case 4: goto ResumePoint4; break; - case 5: goto ResumePoint5; break; + kbts_glyph *Next = Glyph->Next; + + Glyph->Next = Glyph->Prev; + Glyph->Prev = Next; + + Last = Glyph; + Glyph = Next; + if(Glyph == OnePastLast) + { + break; + } } - S->WrittenCount = 0; + if(First != OnePastLast) + { + Last->Prev = OneBeforeFirst; + Last->Prev->Next = Last; + First->Next = OnePastLast; + First->Next->Prev = First; + } +} - switch(Op->Kind) +static void kbts__ExecuteOp(kbts__shape_scratchpad *Scratchpad, kbts_shape_config *Config, kbts_glyph_storage *Storage) +{ + KBTS_INSTRUMENT_FUNCTION_BEGIN; + + if(Config) { - case KBTS_OP_KIND_PRE_NORMALIZE_DOTTED_CIRCLES: - { - KBTS_INSTRUMENT_BLOCK_BEGIN("PRE_NORMALIZE_DOTTED_CIRCLES") - // Before even trying to normalize anything, there are some _exceptions_ we have to take care of. - // The USE spec gives us a list of codepoint sequences which necessitate insertion of a dotted circle. - // These sequences are from IndicShapingInvalidClusters.txt. - S->GlyphIndex = 0; - kbts_u64 Codepoints; Codepoints = 0; // 0xABBBBBCCCCCDDDDD - for(; S->GlyphIndex < GlyphArray->Count; ++S->GlyphIndex) + kbts_font *Font = Config->Font; + kbts__op_kind OpKind = Scratchpad->OpKind; + + switch(OpKind) { - kbts_u32 NewCodepoint; NewCodepoint = Glyphs[S->GlyphIndex].Codepoint & 0x1FFFFF; - Codepoints = (Codepoints << 21) | NewCodepoint; + case KBTS__OP_KIND_PRE_NORMALIZE_DOTTED_CIRCLES: + { + KBTS_INSTRUMENT_BLOCK_BEGIN(PRE_NORMALIZE_DOTTED_CIRCLES); - // This switch is faster than any table lookup I could come up with in my tests. - #define KBTS_C2(A, B) case (((kbts_u64)(A) << 21) | (kbts_u64)(B)): - switch(Codepoints & (((kbts_u64)1 << 42) - 1)) + // Before even trying to normalize anything, there are some _exceptions_ we have to take care of. + // The USE spec gives us a list of codepoint sequences which necessitate insertion of a dotted circle. + // These sequences are from IndicShapingInvalidClusters.txt. + kbts_u64 Codepoints; Codepoints = 0; // 0xABBBBBCCCCCDDDDD + KBTS__FOR_GLYPH(Storage, Glyph) { - default: - if((Codepoints & (((kbts_u64)1 << 63) - 1)) == (((kbts_u64)0x930 << 42) | ((kbts_u64)0x94D << 21) | ((kbts_u64)0x907))) + kbts_u32 NewCodepoint; NewCodepoint = Glyph->Codepoint & 0x1FFFFF; + Codepoints = (Codepoints << 21) | NewCodepoint; + + // This switch is faster than any table lookup I could come up with in my tests. + #define KBTS_C2(A, B) case (((kbts_u64)(A) << 21) | (kbts_u64)(B)): + switch(Codepoints & (((kbts_u64)1 << 42) - 1)) { - if(0) + default: + if((Codepoints & (((kbts_u64)1 << 63) - 1)) == (((kbts_u64)0x930 << 42) | ((kbts_u64)0x94D << 21) | ((kbts_u64)0x907))) { - ResumePoint4:; - Codepoints = 0; - } - KBTS_C2(0x905, 0x93A) - KBTS_C2(0x905, 0x93B) - KBTS_C2(0x905, 0x93E) - KBTS_C2(0x905, 0x945) - KBTS_C2(0x905, 0x946) - KBTS_C2(0x905, 0x949) - KBTS_C2(0x905, 0x94A) - KBTS_C2(0x905, 0x94B) - KBTS_C2(0x905, 0x94C) - KBTS_C2(0x905, 0x94F) - KBTS_C2(0x905, 0x956) - KBTS_C2(0x905, 0x957) - KBTS_C2(0x906, 0x93A) - KBTS_C2(0x906, 0x945) - KBTS_C2(0x906, 0x946) - KBTS_C2(0x906, 0x947) - KBTS_C2(0x906, 0x948) - KBTS_C2(0x909, 0x941) - KBTS_C2(0x90F, 0x945) - KBTS_C2(0x90F, 0x946) - KBTS_C2(0x90F, 0x947) - KBTS_C2(0x985, 0x9BE) - KBTS_C2(0x98B, 0x9C3) - KBTS_C2(0x98C, 0x9E2) - KBTS_C2(0xA05, 0xA3E) - KBTS_C2(0xA05, 0xA48) - KBTS_C2(0xA05, 0xA4C) - KBTS_C2(0xA72, 0xA3F) - KBTS_C2(0xA72, 0xA40) - KBTS_C2(0xA72, 0xA47) - KBTS_C2(0xA73, 0xA41) - KBTS_C2(0xA73, 0xA42) - KBTS_C2(0xA73, 0xA4B) - KBTS_C2(0xA85, 0xABE) - KBTS_C2(0xA85, 0xAC5) - KBTS_C2(0xA85, 0xAC7) - KBTS_C2(0xA85, 0xAC8) - KBTS_C2(0xA85, 0xAC9) - KBTS_C2(0xA85, 0xACB) - KBTS_C2(0xA85, 0xACC) - KBTS_C2(0xAC5, 0xABE) - KBTS_C2(0xB05, 0xB3E) - KBTS_C2(0xB0F, 0xB57) - KBTS_C2(0xB13, 0xB57) - KBTS_C2(0xB85, 0xBC2) - KBTS_C2(0xC12, 0xC4C) - KBTS_C2(0xC12, 0xC55) - KBTS_C2(0xC3F, 0xC55) - KBTS_C2(0xC46, 0xC55) - KBTS_C2(0xC4A, 0xC55) - KBTS_C2(0xC89, 0xCBE) - KBTS_C2(0xC8B, 0xCBE) - KBTS_C2(0xC92, 0xCCC) - KBTS_C2(0xD07, 0xD57) - KBTS_C2(0xD09, 0xD57) - KBTS_C2(0xD0E, 0xD46) - KBTS_C2(0xD12, 0xD3E) - KBTS_C2(0xD12, 0xD57) - KBTS_C2(0xD85, 0xDCF) - KBTS_C2(0xD85, 0xDD0) - KBTS_C2(0xD85, 0xDD1) - KBTS_C2(0xD8B, 0xDDF) - KBTS_C2(0xD8D, 0xDD8) - KBTS_C2(0xD8F, 0xDDF) - KBTS_C2(0xD91, 0xDCA) - KBTS_C2(0xD91, 0xDD9) - KBTS_C2(0xD91, 0xDDA) - KBTS_C2(0xD91, 0xDDC) - KBTS_C2(0xD91, 0xDDD) - KBTS_C2(0xD91, 0xDDE) - KBTS_C2(0xD94, 0xDDF) - KBTS_C2(0x11005, 0x11038) - KBTS_C2(0x1100B, 0x1103E) - KBTS_C2(0x1100F, 0x11042) - KBTS_C2(0x11200, 0x1122C) - KBTS_C2(0x11200, 0x11231) - KBTS_C2(0x11200, 0x11233) - KBTS_C2(0x11206, 0x1122C) - KBTS_C2(0x1122C, 0x11230) - KBTS_C2(0x1122C, 0x11231) - KBTS_C2(0x11240, 0x1122E) - KBTS_C2(0x112B0, 0x112E0) - KBTS_C2(0x112B0, 0x112E5) - KBTS_C2(0x112B0, 0x112E6) - KBTS_C2(0x112B0, 0x112E7) - KBTS_C2(0x112B0, 0x112E8) - KBTS_C2(0x11481, 0x114B0) - KBTS_C2(0x1148B, 0x114BA) - KBTS_C2(0x1148D, 0x114BA) - KBTS_C2(0x114AA, 0x114B5) - KBTS_C2(0x114AA, 0x114B6) - KBTS_C2(0x11600, 0x11639) - KBTS_C2(0x11600, 0x1163A) - KBTS_C2(0x11601, 0x11639) - KBTS_C2(0x11601, 0x1163A) - KBTS_C2(0x11680, 0x116AD) - KBTS_C2(0x11680, 0x116B4) - KBTS_C2(0x11680, 0x116B5) - KBTS_C2(0x11686, 0x116B2) - if(!kbts_GrowGlyphArray(&S->ResumePoint, GlyphArray, S->GlyphIndex, 1, 4, 0)) + KBTS_C2(0x905, 0x93A) + KBTS_C2(0x905, 0x93B) + KBTS_C2(0x905, 0x93E) + KBTS_C2(0x905, 0x945) + KBTS_C2(0x905, 0x946) + KBTS_C2(0x905, 0x949) + KBTS_C2(0x905, 0x94A) + KBTS_C2(0x905, 0x94B) + KBTS_C2(0x905, 0x94C) + KBTS_C2(0x905, 0x94F) + KBTS_C2(0x905, 0x956) + KBTS_C2(0x905, 0x957) + KBTS_C2(0x906, 0x93A) + KBTS_C2(0x906, 0x945) + KBTS_C2(0x906, 0x946) + KBTS_C2(0x906, 0x947) + KBTS_C2(0x906, 0x948) + KBTS_C2(0x909, 0x941) + KBTS_C2(0x90F, 0x945) + KBTS_C2(0x90F, 0x946) + KBTS_C2(0x90F, 0x947) + KBTS_C2(0x985, 0x9BE) + KBTS_C2(0x98B, 0x9C3) + KBTS_C2(0x98C, 0x9E2) + KBTS_C2(0xA05, 0xA3E) + KBTS_C2(0xA05, 0xA48) + KBTS_C2(0xA05, 0xA4C) + KBTS_C2(0xA72, 0xA3F) + KBTS_C2(0xA72, 0xA40) + KBTS_C2(0xA72, 0xA47) + KBTS_C2(0xA73, 0xA41) + KBTS_C2(0xA73, 0xA42) + KBTS_C2(0xA73, 0xA4B) + KBTS_C2(0xA85, 0xABE) + KBTS_C2(0xA85, 0xAC5) + KBTS_C2(0xA85, 0xAC7) + KBTS_C2(0xA85, 0xAC8) + KBTS_C2(0xA85, 0xAC9) + KBTS_C2(0xA85, 0xACB) + KBTS_C2(0xA85, 0xACC) + KBTS_C2(0xAC5, 0xABE) + KBTS_C2(0xB05, 0xB3E) + KBTS_C2(0xB0F, 0xB57) + KBTS_C2(0xB13, 0xB57) + KBTS_C2(0xB85, 0xBC2) + KBTS_C2(0xC12, 0xC4C) + KBTS_C2(0xC12, 0xC55) + KBTS_C2(0xC3F, 0xC55) + KBTS_C2(0xC46, 0xC55) + KBTS_C2(0xC4A, 0xC55) + KBTS_C2(0xC89, 0xCBE) + KBTS_C2(0xC8B, 0xCBE) + KBTS_C2(0xC92, 0xCCC) + KBTS_C2(0xD07, 0xD57) + KBTS_C2(0xD09, 0xD57) + KBTS_C2(0xD0E, 0xD46) + KBTS_C2(0xD12, 0xD3E) + KBTS_C2(0xD12, 0xD57) + KBTS_C2(0xD85, 0xDCF) + KBTS_C2(0xD85, 0xDD0) + KBTS_C2(0xD85, 0xDD1) + KBTS_C2(0xD8B, 0xDDF) + KBTS_C2(0xD8D, 0xDD8) + KBTS_C2(0xD8F, 0xDDF) + KBTS_C2(0xD91, 0xDCA) + KBTS_C2(0xD91, 0xDD9) + KBTS_C2(0xD91, 0xDDA) + KBTS_C2(0xD91, 0xDDC) + KBTS_C2(0xD91, 0xDDD) + KBTS_C2(0xD91, 0xDDE) + KBTS_C2(0xD94, 0xDDF) + KBTS_C2(0x11005, 0x11038) + KBTS_C2(0x1100B, 0x1103E) + KBTS_C2(0x1100F, 0x11042) + KBTS_C2(0x11200, 0x1122C) + KBTS_C2(0x11200, 0x11231) + KBTS_C2(0x11200, 0x11233) + KBTS_C2(0x11206, 0x1122C) + KBTS_C2(0x1122C, 0x11230) + KBTS_C2(0x1122C, 0x11231) + KBTS_C2(0x11240, 0x1122E) + KBTS_C2(0x112B0, 0x112E0) + KBTS_C2(0x112B0, 0x112E5) + KBTS_C2(0x112B0, 0x112E6) + KBTS_C2(0x112B0, 0x112E7) + KBTS_C2(0x112B0, 0x112E8) + KBTS_C2(0x11481, 0x114B0) + KBTS_C2(0x1148B, 0x114BA) + KBTS_C2(0x1148D, 0x114BA) + KBTS_C2(0x114AA, 0x114B5) + KBTS_C2(0x114AA, 0x114B6) + KBTS_C2(0x11600, 0x11639) + KBTS_C2(0x11600, 0x1163A) + KBTS_C2(0x11601, 0x11639) + KBTS_C2(0x11601, 0x1163A) + KBTS_C2(0x11680, 0x116AD) + KBTS_C2(0x11680, 0x116B4) + KBTS_C2(0x11680, 0x116B5) + KBTS_C2(0x11686, 0x116B2) { - KBTS_INSTRUMENT_END - return 1; - } - GlyphArray->Glyphs[S->GlyphIndex] = Config->DottedCircle; - } - } - #undef KBTS_C2 - } - - S->WrittenCount = GlyphArray->TotalCount; - KBTS_INSTRUMENT_END - } break; - - case KBTS_OP_KIND_NORMALIZE: - { - KBTS_INSTRUMENT_BLOCK_BEGIN("NORMALIZE") - // @Incomplete: We need to honor this. - // HB_OT_SHAPE_NORMALIZATION_MODE_NONE, - // HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, - // HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* Always fully decomposes and then recompose back */ - // - // hangul: HB_OT_SHAPE_NORMALIZATION_MODE_NONE, - // arabic: HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, - // default: HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, - // hebrew: HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, - // thai: HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, - // indic: HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, - // khmer: HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, - // myanmar: HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, - // use: HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, - - { // Full NFD decomposition - kbts_glyph *DecompositionGlyphs; DecompositionGlyphs = KBTS_POINTER_AFTER(kbts_glyph, S); - for(S->GlyphIndex = 0; S->GlyphIndex < GlyphArray->Count; ++S->GlyphIndex) - { - DecompositionGlyphs[0] = Glyphs[S->GlyphIndex]; - S->OpSpecific.Normalize.CodepointsToDecomposeCount = 1; - - while(S->OpSpecific.Normalize.CodepointsToDecomposeCount) - { - if(0) - { - ResumePoint1:; - DecompositionGlyphs = KBTS_POINTER_AFTER(kbts_glyph, S); - } - - kbts_glyph GlyphToDecompose = DecompositionGlyphs[--S->OpSpecific.Normalize.CodepointsToDecomposeCount]; - kbts_u64 Decomposition = 0; - kbts_u32 DecompositionSize = 0; - kbts_u32 AnyUnsupported = 0; - kbts_glyph Decomposed[2]; - - if(!(GlyphToDecompose.Flags & KBTS_GLYPH_FLAG_DO_NOT_DECOMPOSE)) - { - Decomposition = GlyphToDecompose.Decomposition; - DecompositionSize = kbts_GetDecompositionSize(Decomposition); - - // Only decompose when the font supports the decomposed form. - KBTS_FOR(DecompositionIndex, 0, DecompositionSize) + kbts_glyph *NewGlyph = kbts__InsertGlyphBefore(Storage, Glyph, &Config->DottedCircle); + if(!NewGlyph) { - kbts_glyph DecompositionGlyph = kbts_CodepointToGlyph(Font, kbts_GetDecompositionCodepoint(Decomposition, DecompositionIndex)); - DecompositionGlyph.Config = GlyphToDecompose.Config; - - AnyUnsupported |= !DecompositionGlyph.Id; - Decomposed[DecompositionIndex] = DecompositionGlyph; + goto OutOfMemory; } + } break; } + } + #undef KBTS_C2 + } - if(AnyUnsupported | !DecompositionSize) + KBTS_INSTRUMENT_BLOCK_END(PRE_NORMALIZE_DOTTED_CIRCLES); + } break; + + case KBTS__OP_KIND_NORMALIZE: + { + KBTS_INSTRUMENT_BLOCK_BEGIN(NORMALIZE); + // @Incomplete: We need to honor this. + // HB_OT_SHAPE_NORMALIZATION_MODE_NONE, + // HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, + // HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* Always fully decomposes and then recompose back */ + // + // hangul: HB_OT_SHAPE_NORMALIZATION_MODE_NONE, + // arabic: HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, + // default: HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, + // hebrew: HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, + // thai: HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, + // indic: HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, + // khmer: HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, + // myanmar: HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, + // use: HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, + + KBTS_INSTRUMENT_BLOCK_BEGIN(Decompose); + { // Full NFD decomposition + kbts__arena_lifetime Lifetime = kbts__BeginLifetime(Scratchpad->Arena); + kbts_glyph *DecompositionGlyphs = kbts__PushArray(Scratchpad->Arena, kbts_glyph, KBTS__MAXIMUM_DECOMPOSITION_CODEPOINTS); + kbts_un CodepointsToDecomposeCount = 0; + + KBTS__FOR_GLYPH(Storage, Glyph) + { + if(kbts__GetDecompositionSize(Glyph->Decomposition)) { - if(S->WrittenCount > S->GlyphIndex) - { - if(!kbts_GrowGlyphArray(&S->ResumePoint, GlyphArray, S->WrittenCount, 1, 1, 0)) - { - S->OpSpecific.Normalize.CodepointsToDecomposeCount += 1; // Push the codepoint back on the stack. + kbts_glyph *PrevAnchor = Glyph->Prev; - KBTS_INSTRUMENT_END - return 1; + DecompositionGlyphs[0] = *Glyph; + CodepointsToDecomposeCount = 1; + + kbts__FreeGlyph(Scratchpad, Storage, Glyph); + + while(CodepointsToDecomposeCount) + { + kbts_glyph GlyphToDecompose = DecompositionGlyphs[--CodepointsToDecomposeCount]; + kbts_u64 Decomposition = 0; + kbts_u32 DecompositionSize = 0; + int AnyUnsupported = 0; + kbts_glyph Decomposed[2]; + + if(!(GlyphToDecompose.Flags & KBTS_GLYPH_FLAG_DO_NOT_DECOMPOSE)) + { + Decomposition = GlyphToDecompose.Decomposition; + DecompositionSize = kbts__GetDecompositionSize(Decomposition); + + // Only decompose when the font supports the decomposed form. + KBTS__FOR(DecompositionIndex, 0, DecompositionSize) + { + kbts_glyph DecompositionGlyph = kbts_CodepointToGlyph(Font, (int)kbts__GetDecompositionCodepoint(Decomposition, DecompositionIndex), 0, 0); + DecompositionGlyph.Config = GlyphToDecompose.Config; + DecompositionGlyph.UserIdOrCodepointIndex = GlyphToDecompose.UserIdOrCodepointIndex; + + AnyUnsupported |= !DecompositionGlyph.Id; + Decomposed[DecompositionIndex] = DecompositionGlyph; + } } - S->GlyphIndex += 1; - } - - Glyphs[S->WrittenCount++] = GlyphToDecompose; - } - else - { - KBTS_ASSERT((S->OpSpecific.Normalize.CodepointsToDecomposeCount + DecompositionSize) <= KBTS_MAXIMUM_DECOMPOSITION_CODEPOINTS); - - if(Decomposition & KBTS_UNICODE_DECOMPOSITION_DO_NOT_RECURSE0) - { - Decomposed[0].Flags |= KBTS_GLYPH_FLAG_DO_NOT_DECOMPOSE; - } - if(Decomposition & KBTS_UNICODE_DECOMPOSITION_DO_NOT_RECURSE1) - { - Decomposed[1].Flags |= KBTS_GLYPH_FLAG_DO_NOT_DECOMPOSE; - } - - KBTS_FOR(DecompositionIndex, 0, DecompositionSize) - { - // We reverse the glyphs here because we use a stack. - DecompositionGlyphs[S->OpSpecific.Normalize.CodepointsToDecomposeCount++] = Decomposed[DecompositionSize - 1 - DecompositionIndex]; - } - } - } - } - } - - { // Selective recomposition. - // The OpenType shaping documents say that Hebrew Alphabetic Presentation Form compositions aren't canonical, - // but looking at UnicodeData.txt, it seems like they totally are, so they are handled here. - kbts_glyph *LastBase = 0; - kbts_un LastBaseParentCount = 0; - kbts_s32 *LastBaseParentDeltas = 0; - kbts_un PreSlashDecimalDigitCount = 0; - kbts_un DecimalDigitCount = 0; - int InFraction = 0; - - kbts_u32 BeforeFractionSlashGlyphFlags = KBTS_GLYPH_FLAG_NUMR | KBTS_GLYPH_FLAG_FRAC; - kbts_u32 AfterFractionSlashGlyphFlags = KBTS_GLYPH_FLAG_DNOM | KBTS_GLYPH_FLAG_FRAC; - if(kbts_ShaperRtl(Config->Shaper)) - { - // RTL needs to invert NUMR and DNOM. - kbts_u32 Swap = BeforeFractionSlashGlyphFlags; - BeforeFractionSlashGlyphFlags = AfterFractionSlashGlyphFlags; - AfterFractionSlashGlyphFlags = Swap; - } - - // We also collate user features here. - kbts_feature_set UserFeatures = KBTS_ZERO; - kbts_feature_set *DefaultFeatures = Config->Features; - - KBTS_FOR(GlyphIndex, 0, S->WrittenCount) - { - kbts_glyph *Glyph = &Glyphs[GlyphIndex]; - Glyph->Uid = (kbts_u16)++ShapeState->NextGlyphUid; - - if(Glyph->Config) - { - kbts_glyph_config *GlyphConfig = Glyph->Config; - KBTS_FOR(WordIndex, 0, KBTS_ARRAY_LENGTH(UserFeatures.Flags)) - { - UserFeatures.Flags[WordIndex] |= GlyphConfig->EnabledFeatures.Flags[WordIndex] & ~DefaultFeatures->Flags[WordIndex]; - } - } - - kbts_un AvailableGlyphCount = 0; - if(!Glyph->CombiningClass) - { - LastBase = Glyph; - // From the Microsoft docs: - // USE decomposes split vowel characters belonging to UISC = Vowel_Dependent according to character - // decomposition mappings defined in UnicodeData.txt - // Cluster validation, is done based on the decomposed state of a split vowel. - // - // (Note: our Matra corresponds to Vowel_Dependent + Pure_Killer.) - if((Config->Shaper != KBTS_SHAPER_USE) || (Glyph->SyllabicClass != KBTS_INDIC_SYLLABIC_CLASS_MATRA)) - { - LastBaseParentDeltas = kbts_GetParentInfoDeltas(Glyph->ParentInfo); - LastBaseParentCount = kbts_GetParentInfoCount(Glyph->ParentInfo); - AvailableGlyphCount = 1; - } - else - { - LastBaseParentDeltas = 0; - LastBaseParentCount = 0; - } - } - else - { - if(LastBase) - { - AvailableGlyphCount = 2; - } - } - - KBTS_FOR(ParentIndex, 0, LastBaseParentCount) - { - kbts_u32 ParentCodepoint = LastBase->Codepoint + (kbts_u32)LastBaseParentDeltas[ParentIndex]; - kbts_glyph ParentGlyph = kbts_CodepointToGlyph(Font, ParentCodepoint); - kbts_u32 DecompositionSize = kbts_GetDecompositionSize(ParentGlyph.Decomposition); - - ParentGlyph.Uid = LastBase->Uid; - ParentGlyph.Config = LastBase->Config; - if((DecompositionSize == AvailableGlyphCount) && ParentGlyph.Id) - { - if(DecompositionSize == 2) - { - if(kbts_GetDecompositionCodepoint(ParentGlyph.Decomposition, 1) == Glyph->Codepoint) + if(AnyUnsupported | !DecompositionSize) { - // Both match. Reclaim space. - // @Speed: We should use separate read and write cursors instead. - KBTS_FOR(ShrinkIndex, GlyphIndex + 1, S->WrittenCount) + kbts_glyph *NewGlyph = kbts__InsertGlyphAfter(Storage, PrevAnchor, &GlyphToDecompose); + if(!NewGlyph) { - Glyphs[ShrinkIndex - 1] = Glyphs[ShrinkIndex]; + goto OutOfMemory; } - S->WrittenCount -= 1; + + PrevAnchor = NewGlyph; } else { - continue; + KBTS_ASSERT((CodepointsToDecomposeCount + DecompositionSize) <= KBTS__MAXIMUM_DECOMPOSITION_CODEPOINTS); + + if(Decomposition & KBTS_UNICODE_DECOMPOSITION_DO_NOT_RECURSE0) + { + Decomposed[0].Flags |= KBTS_GLYPH_FLAG_DO_NOT_DECOMPOSE; + } + if(Decomposition & KBTS_UNICODE_DECOMPOSITION_DO_NOT_RECURSE1) + { + Decomposed[1].Flags |= KBTS_GLYPH_FLAG_DO_NOT_DECOMPOSE; + } + + KBTS__FOR(DecompositionIndex, 0, DecompositionSize) + { + // We reverse the glyphs here because we use a stack. + DecompositionGlyphs[CodepointsToDecomposeCount++] = Decomposed[DecompositionSize - 1 - DecompositionIndex]; + } } } - *LastBase = ParentGlyph; - GlyphIndex = (kbts_un)((LastBase - Glyphs) - 1); // Handle recursive recomposition. + Glyph = PrevAnchor; + } + } + + kbts__EndLifetime(&Lifetime); + } + KBTS_INSTRUMENT_BLOCK_END(Decompose); + + KBTS_INSTRUMENT_BLOCK_BEGIN(Recompose); + { // Selective recomposition. + // The OpenType shaping documents say that Hebrew Alphabetic Presentation Form compositions aren't canonical, + // but looking at UnicodeData.txt, it seems like they totally are, so they are handled here. + kbts__arena_lifetime Lifetime = kbts__BeginLifetime(Scratchpad->Arena); + kbts_glyph *LastBase = 0; + kbts_un LastBaseParentCount = 0; + kbts_un PreSlashDecimalDigitCount = 0; + kbts_glyph *PreSlashGlyph = 0; + kbts_glyph *DigitGlyph = 0; + kbts_un DecimalDigitCount = 0; + int InFraction = 0; + kbts_u32 LastBaseParentsLoaded = 0; + kbts_glyph_parent LastBaseParents[KBTS_MAXIMUM_RECOMPOSITION_PARENTS]; + kbts_glyph *Parents = kbts__PushArray(Scratchpad->Arena, kbts_glyph, KBTS_MAXIMUM_RECOMPOSITION_PARENTS); + + kbts_u32 BeforeFractionSlashGlyphFlags = KBTS_GLYPH_FLAG_NUMR | KBTS_GLYPH_FLAG_FRAC; + kbts_u32 AfterFractionSlashGlyphFlags = KBTS_GLYPH_FLAG_DNOM | KBTS_GLYPH_FLAG_FRAC; + if(kbts__ShaperRtl(Config->Shaper)) + { + // RTL needs to invert NUMR and DNOM. + kbts_u32 Swap = BeforeFractionSlashGlyphFlags; + BeforeFractionSlashGlyphFlags = AfterFractionSlashGlyphFlags; + AfterFractionSlashGlyphFlags = Swap; + } + + // We also collate user features here. + kbts__feature_set UserFeatures = KBTS__ZERO; + kbts__feature_set *DefaultFeatures = &Config->Features; + + int ShouldFlip = (Scratchpad->RunDirection == KBTS_DIRECTION_RTL); + + KBTS__FOR_GLYPH(Storage, Glyph) + { + Glyph->Uid = (kbts_u16)++Scratchpad->NextGlyphUid; + + if(Glyph->Config) + { + kbts_glyph_config *GlyphConfig = Glyph->Config; + KBTS__FOR(WordIndex, 0, KBTS__ARRAY_LENGTH(UserFeatures.Flags)) + { + UserFeatures.Flags[WordIndex] |= GlyphConfig->EnabledFeatures.Flags[WordIndex] & ~DefaultFeatures->Flags[WordIndex]; + } + } + + // In RTL, mirror all glyphs when their mirror is covered. + if(ShouldFlip && + (Glyph->UnicodeFlags & KBTS_UNICODE_FLAG_MIRRORED)) + { + kbts_u32 MatchingBracketCodepoint = kbts__GetUnicodeMirrorCodepoint(Glyph->Codepoint); + kbts_glyph MatchingBracket = kbts_CodepointToGlyph(Font, (int)MatchingBracketCodepoint, 0, 0); + if(MatchingBracket.Id) + { + kbts__SetGlyphPreserveLinksAndUserId(Glyph, &MatchingBracket); + } + } + + kbts_u32 SingleRecompositionCodepoints[KBTS_MAXIMUM_RECOMPOSITION_PARENTS]; + kbts_un SingleRecompositionCodepointCount = 0; + kbts_un DoubleRecompositionCount = LastBaseParentCount; + + if(!Glyph->CombiningClass) + { + LastBase = Glyph; + // From the Microsoft docs: + // USE decomposes split vowel characters belonging to UISC = Vowel_Dependent according to character + // decomposition mappings defined in UnicodeData.txt + // Cluster validation, is done based on the decomposed state of a split vowel. + // + // (Note: our Matra corresponds to Vowel_Dependent + Pure_Killer.) + if((Config->Shaper != KBTS_SHAPER_USE) || (Glyph->SyllabicClass != KBTS_INDIC_SYLLABIC_CLASS_MATRA)) + { + kbts_s32 *LastBaseParentDeltas = kbts__GetParentInfoDeltas(Glyph->ParentInfo); + kbts_un ParentCount = kbts__GetParentInfoCount(Glyph->ParentInfo); + + kbts_un DoubleDecompositionCount = 0; + KBTS__FOR(ParentIndex, 0, ParentCount) + { + kbts_glyph_parent Parent = KBTS__ZERO; + Parent.Codepoint = Glyph->Codepoint + (kbts_u32)LastBaseParentDeltas[ParentIndex]; + Parent.Decomposition = kbts__GetUnicodeDecomposition(Parent.Codepoint); + + kbts_un DecompositionSize = kbts__GetDecompositionSize(Parent.Decomposition); + if(DecompositionSize == 1) + { + SingleRecompositionCodepoints[SingleRecompositionCodepointCount++] = Parent.Codepoint; + } + else + { + LastBaseParents[DoubleDecompositionCount++] = Parent; + } + } + + LastBaseParentCount = DoubleDecompositionCount; + LastBaseParentsLoaded = 0; + } + else + { + LastBaseParentCount = 0; + } + + DoubleRecompositionCount = 0; + } + + int Recomposed = 0; + + if(!Recomposed) + { + KBTS_INSTRUMENT_BLOCK_BEGIN(ParentNSquaredStupidity); + KBTS__FOR(ParentIndex, 0, DoubleRecompositionCount) + { + kbts_glyph_parent *Parent = &LastBaseParents[ParentIndex]; + kbts_u32 Codepoint1 = kbts__GetDecompositionCodepoint(Parent->Decomposition, 1); + + if(Glyph->Codepoint == Codepoint1) + { + kbts_glyph *ParentGlyph = &Parents[ParentIndex]; + if(!(LastBaseParentsLoaded & (1 << ParentIndex))) + { + *ParentGlyph = kbts_CodepointToGlyph(Font, (int)Parent->Codepoint, 0, 0); + ParentGlyph->Uid = LastBase->Uid; + ParentGlyph->UserIdOrCodepointIndex = LastBase->UserIdOrCodepointIndex; + ParentGlyph->Config = LastBase->Config; + } + + if(ParentGlyph->Id) + { + // Both match. Reclaim space. + kbts_glyph *Next = Glyph->Next; + KBTS__DLLIST_REMOVE(Glyph); + Glyph = Next; + + Recomposed = 1; + kbts__SetGlyphPreserveLinksAndUserId(LastBase, ParentGlyph); + + break; + } + else + { + // This glyph is never good. Forget it. + LastBaseParents[ParentIndex] = LastBaseParents[LastBaseParentCount - 1]; + Parents[ParentIndex] = Parents[LastBaseParentCount - 1]; + LastBaseParentsLoaded &= ~(1 << ParentIndex); + LastBaseParentsLoaded |= (LastBaseParentsLoaded & (1 << (LastBaseParentCount - 1))) >> (LastBaseParentCount - 1 - ParentIndex); + + LastBaseParentCount -= 1; + DoubleRecompositionCount -= 1; + ParentIndex -= 1; + } + } + } + KBTS_INSTRUMENT_BLOCK_END(ParentNSquaredStupidity); + } + + if(!Recomposed) + { + KBTS__FOR(SingleRecompositionIndex, 0, SingleRecompositionCodepointCount) + { + kbts_glyph ParentGlyph = kbts_CodepointToGlyph(Font, (int)SingleRecompositionCodepoints[SingleRecompositionIndex], 0, 0); + if(ParentGlyph.Id) + { + ParentGlyph.Config = Glyph->Config; + + kbts__SetGlyphPreserveLinksAndUserId(Glyph, &ParentGlyph); + Recomposed = 1; + break; + } + } + } + + // It is safe to look for fractions here, because decimal digits/the fraction slash are not marks or + // jamos, so they should not get reordered after this pass. + if(Glyph->UnicodeFlags & KBTS_UNICODE_FLAG_DECIMAL_DIGIT) + { + if(InFraction) + { + // We are in the post-slash part of the fraction. + Glyph->Flags |= AfterFractionSlashGlyphFlags; + // Only flag the pre-slash part of the fraction if there is a post-slash part. + KBTS__FOR(DecimalDigitIndex, 0, PreSlashDecimalDigitCount) + { + PreSlashGlyph->Flags |= BeforeFractionSlashGlyphFlags; + PreSlashGlyph = PreSlashGlyph->Next; + } + PreSlashDecimalDigitCount = 0; + } + if(!DecimalDigitCount) + { + DigitGlyph = Glyph; + } + DecimalDigitCount += 1; + } + else if((Glyph->Codepoint == 0x2044) && (!InFraction || DecimalDigitCount)) + { + // Fraction slash. + Glyph->Flags |= KBTS_GLYPH_FLAG_FRAC; + PreSlashDecimalDigitCount = DecimalDigitCount; + PreSlashGlyph = DigitGlyph; + InFraction = DecimalDigitCount != 0; + DecimalDigitCount = 0; + } + else + { + InFraction = 0; + } + + if(Recomposed) + { + // @Robustness: This doesn't work when LastBase != Glyph->Prev, does it? + Glyph = Glyph->Prev; // Handle recursive recomposition. + } + } + + // Ignore added features that are already part of the shaper. + kbts__feature_set *ShaperFeatures = &Config->Features; + KBTS__FOR(WordIndex, 0, KBTS__ARRAY_LENGTH(UserFeatures.Flags)) + { + UserFeatures.Flags[WordIndex] &= ~ShaperFeatures->Flags[WordIndex]; + } + + Scratchpad->UserFeatures = UserFeatures; + kbts__EndLifetime(&Lifetime); + } + KBTS_INSTRUMENT_BLOCK_END(Recompose); + + KBTS_INSTRUMENT_BLOCK_BEGIN(MarkReordering); + { // Unicode mark reordering. + for(kbts_glyph *Glyph = Storage->GlyphSentinel.Next; + kbts__GlyphIsValid(Storage, Glyph); + ) + { + kbts_u8 CombiningClass = Glyph->CombiningClass; + + if(CombiningClass) + { + Glyph->MarkOrdering = CombiningClass; + + kbts_glyph *SequenceGlyph = Glyph->Next; + for(; + kbts__GlyphIsValid(Storage, SequenceGlyph); + SequenceGlyph = SequenceGlyph->Next) + { + kbts_u8 SequenceGlyphCombiningClass = SequenceGlyph->CombiningClass; + if(SequenceGlyphCombiningClass) + { + SequenceGlyph->MarkOrdering = SequenceGlyphCombiningClass; + } + else + { + break; + } + } + + kbts_glyph *AfterSequence = SequenceGlyph; + if(kbts__GlyphIsValid(Storage, AfterSequence)) + { + AfterSequence = AfterSequence->Next; + } + + KBTS__DLLIST_SORT(Glyph, SequenceGlyph, MarkOrdering); + + #ifdef KBTS_SANITY_CHECK + { + kbts_glyph *Glyph0 = OneBeforeSequence->Next; + kbts_glyph *Glyph1 = Glyph0->Next; + KBTS__FOR(SequenceIndex, 1, MarkSequenceLength) + { + KBTS_ASSERT(Glyph0->MarkOrdering <= Glyph1->MarkOrdering); + + Glyph0 = Glyph0->Next; + Glyph1 = Glyph1->Next; + } + } + #endif + + Glyph = AfterSequence; + } + else + { + Glyph = Glyph->Next; + } + } + } + KBTS_INSTRUMENT_BLOCK_END(MarkReordering); + + if(Config->Script == KBTS_SCRIPT_ARABIC) + { + for(kbts_glyph *Glyph = Storage->GlyphSentinel.Next; + kbts__GlyphIsValid(Storage, Glyph); + ) + { + kbts_glyph *Next = Glyph->Next; + + // Find a mark sequence. + kbts_u8 CombiningClass = Glyph->CombiningClass; + + if(CombiningClass) + { + // Arabic: Reorder sequences of mark glyphs. + // + // From the Unicode standard: + // - Move any shadda characters (ccc=33) to the beginning of S. + // - If a sequence of ccc=230 characters begins with any MCM characters, move the sequence of such MCM + // characters + // to the beginning of S (before any characters with ccc=33). + // - If a sequence of ccc=220 characters begins with any MCM characters, move the sequence of such MCM + // characters + // to the beginning of S (before any MCM with ccc=230 or ccc=33). + // + // Final ordering: 220 230 shadda other + + kbts__mcm_sequence_state Mcm220SequenceState = 0; + kbts__mcm_sequence_state Mcm230SequenceState = 0; + + # define KBTS_REMAPPED_CCC_33 27 + + kbts_glyph *SequenceGlyph = Glyph; + for(; + kbts__GlyphIsValid(Storage, SequenceGlyph); + SequenceGlyph = SequenceGlyph->Next) + { + kbts_u16 SequenceGlyphCombiningClass = SequenceGlyph->CombiningClass; + kbts_u16 SequenceGlyphFlags = SequenceGlyph->UnicodeFlags; + + kbts_u8 MarkOrdering = 3; + + if(SequenceGlyphCombiningClass == KBTS_REMAPPED_CCC_33) + { + MarkOrdering = 2; + } + else if(SequenceGlyphCombiningClass == 220) + { + if(SequenceGlyphFlags & KBTS_UNICODE_FLAG_MODIFIER_COMBINING_MARK) + { + if(Mcm220SequenceState != KBTS__MCM_SEQUENCE_STATE_OUT) + { + Mcm220SequenceState = KBTS__MCM_SEQUENCE_STATE_IN; + } + } + else + { + Mcm220SequenceState = KBTS__MCM_SEQUENCE_STATE_OUT; + } + + if(Mcm220SequenceState == KBTS__MCM_SEQUENCE_STATE_IN) + { + MarkOrdering = 0; + } + + Mcm230SequenceState = KBTS__MCM_SEQUENCE_STATE_NONE; + } + else if(SequenceGlyphCombiningClass == 230) + { + if(SequenceGlyphFlags & KBTS_UNICODE_FLAG_MODIFIER_COMBINING_MARK) + { + if(Mcm230SequenceState != KBTS__MCM_SEQUENCE_STATE_OUT) + { + Mcm230SequenceState = KBTS__MCM_SEQUENCE_STATE_IN; + } + } + else + { + Mcm230SequenceState = KBTS__MCM_SEQUENCE_STATE_OUT; + } + + if(Mcm230SequenceState == KBTS__MCM_SEQUENCE_STATE_IN) + { + MarkOrdering = 1; + } + } + else if(SequenceGlyphCombiningClass) + { + Mcm220SequenceState = KBTS__MCM_SEQUENCE_STATE_NONE; + Mcm230SequenceState = KBTS__MCM_SEQUENCE_STATE_NONE; + } + else + { + break; + } + + SequenceGlyph->MarkOrdering = MarkOrdering; + } + + KBTS__DLLIST_SORT(Glyph, SequenceGlyph, MarkOrdering); + + #ifdef KBTS_SANITY_CHECK + { + kbts_glyph *Glyph0 = OneBeforeGlyph->Next; + for(kbts_glyph *Glyph1 = Glyph0->Next; + Glyph1 != SequenceGlyph; + Glyph1 = Glyph1->Next) + { + KBTS_ASSERT(Glyph0->MarkOrdering <= Glyph1->MarkOrdering); + Glyph0 = Glyph1; + } + } + #endif + + Next = SequenceGlyph; + } + + Glyph = Next; + } + } + else if((Config->Script == KBTS_SCRIPT_THAI) || (Config->Script == KBTS_SCRIPT_LAO)) + { + // Decompose sara/sala ams. + kbts_glyph *AboveBaseGlyph; AboveBaseGlyph = 0; + + KBTS__FOR_GLYPH(Storage, Glyph) + { + kbts_u32 Codepoint = Glyph->Codepoint; + + switch(Codepoint) + { + // Sara am/sala am. + // We match both because storing the sara am codepoint that corresponds to the current script + // doesn't seem that worthwhile, given that this is already a pretty big switch case. + // If we choose to use a unicode flag or indic syllabic category to notate above-base marks, + // then this loops gets a lot tighter and it would probably become the right call to pre-determine + // the sara am codepoint. + case 0xE33: case 0xEB3: // Sara am + { + kbts_glyph *NewGlyph = kbts__InsertGlyphBefore(Storage, AboveBaseGlyph, &Config->Nikhahit); + if(!NewGlyph) + { + goto OutOfMemory; + } + + kbts__SetGlyphPreserveLinksAndUserId(Glyph, &Config->SaraAa); + } break; + + case 0xE31: case 0xE34: case 0xE35: case 0xE36: case 0xE37: case 0xE3B: + case 0xE47: case 0xE48: case 0xE49: case 0xE4A: case 0xE4B: case 0xE4C: case 0xE4D: case 0xE4E: + case 0xEB1: case 0xEB4: case 0xEB5: case 0xEB6: case 0xEB7: case 0xEBB: + case 0xEC7: case 0xEC8: case 0xEC9: case 0xECA: case 0xECB: case 0xECC: case 0xECD: case 0xECE: + if(!AboveBaseGlyph) + { + AboveBaseGlyph = Glyph; + } + break; + + default: + AboveBaseGlyph = 0; break; } } - - // It is safe to look for fractions here, because decimal digits/the fraction slash are not marks or - // jamos, so they should not get reordered after this pass. - if(Glyph->UnicodeFlags & KBTS_UNICODE_FLAG_DECIMAL_DIGIT) - { - if(InFraction) - { - // We are in the post-slash part of the fraction. - Glyph->Flags |= AfterFractionSlashGlyphFlags; - // Only flag the pre-slash part of the fraction if there is a post-slash part. - KBTS_FOR(DecimalDigitIndex, 0, PreSlashDecimalDigitCount) - { - Glyphs[GlyphIndex - PreSlashDecimalDigitCount - 1 + DecimalDigitIndex].Flags |= BeforeFractionSlashGlyphFlags; - } - PreSlashDecimalDigitCount = 0; - } - DecimalDigitCount += 1; - } - else if((Glyph->Codepoint == 0x2044) && (!InFraction || DecimalDigitCount)) - { - // Fraction slash. - Glyph->Flags |= KBTS_GLYPH_FLAG_FRAC; - PreSlashDecimalDigitCount = DecimalDigitCount; - InFraction = DecimalDigitCount != 0; - DecimalDigitCount = 0; - } - else - { - InFraction = 0; - } } - // Ignore added features that are already part of the shaper. - kbts_feature_set *ShaperFeatures = Config->Features; - KBTS_FOR(WordIndex, 0, KBTS_ARRAY_LENGTH(UserFeatures.Flags)) - { - UserFeatures.Flags[WordIndex] &= ~ShaperFeatures->Flags[WordIndex]; - } + KBTS_INSTRUMENT_BLOCK_END(NORMALIZE); + } break; - ShapeState->UserFeatures = UserFeatures; - } - - { // Unicode mark reordering. - S->GlyphIndex = 0; - while(S->GlyphIndex < S->WrittenCount) - { - kbts_glyph *Glyph = &Glyphs[S->GlyphIndex]; - kbts_u8 CombiningClass = Glyph->CombiningClass; - - kbts_un IndexIncrement = 1; - - if(CombiningClass) - { - Glyph->MarkOrdering = CombiningClass; - kbts_un MarkSequenceLength = 1; - while((S->GlyphIndex + MarkSequenceLength) < S->WrittenCount) - { - kbts_glyph *SequenceGlyph = &Glyphs[S->GlyphIndex + MarkSequenceLength]; - kbts_u8 SequenceGlyphCombiningClass = SequenceGlyph->CombiningClass; - if(SequenceGlyphCombiningClass) - { - SequenceGlyph->MarkOrdering = SequenceGlyphCombiningClass; - MarkSequenceLength += 1; - } - else - { - break; - } - } - - KBTS_FOR(Iter, 0, MarkSequenceLength) - { - KBTS_FOR(SequenceIndex, 1, MarkSequenceLength) - { - kbts_glyph *Glyph0 = &Glyphs[S->GlyphIndex + SequenceIndex - 1]; - kbts_glyph *Glyph1 = &Glyphs[S->GlyphIndex + SequenceIndex]; - - if(Glyph0->MarkOrdering > Glyph1->MarkOrdering) - { - kbts_glyph Swap = *Glyph0; - *Glyph0 = *Glyph1; - *Glyph1 = Swap; - } - } - } - - IndexIncrement = MarkSequenceLength; - } - - S->GlyphIndex += IndexIncrement; - } - } - - if(Config->Script == KBTS_SCRIPT_ARABIC) + case KBTS__OP_KIND_NORMALIZE_HANGUL: { - S->GlyphIndex = 0; - while(S->GlyphIndex < S->WrittenCount) + KBTS_INSTRUMENT_BLOCK_BEGIN(NORMALIZE_HANGUL); + + for(kbts_glyph *Glyph = Storage->GlyphSentinel.Next; + kbts__GlyphIsValid(Storage, Glyph); + ) { - // Find a mark sequence. - kbts_glyph *Glyph = &Glyphs[S->GlyphIndex]; - kbts_u8 CombiningClass = Glyph->CombiningClass; + kbts_glyph *Next = Glyph->Next; - if(CombiningClass) - { - // Arabic: Reorder sequences of mark glyphs. - // - // From the Unicode standard: - // - Move any shadda characters (ccc=33) to the beginning of S. - // - If a sequence of ccc=230 characters begins with any MCM characters, move the sequence of such MCM - // characters - // to the beginning of S (before any characters with ccc=33). - // - If a sequence of ccc=220 characters begins with any MCM characters, move the sequence of such MCM - // characters - // to the beginning of S (before any MCM with ccc=230 or ccc=33). - // - // Final ordering: 220 230 shadda other - - kbts_mcm_sequence_state Mcm220SequenceState = 0; - kbts_mcm_sequence_state Mcm230SequenceState = 0; - - kbts_un SequenceStart = S->GlyphIndex; - -# define KBTS_REMAPPED_CCC_33 27 - - while(S->GlyphIndex < S->WrittenCount) - { - kbts_glyph *SequenceGlyph = &Glyphs[S->GlyphIndex]; - kbts_u16 SequenceGlyphCombiningClass = SequenceGlyph->CombiningClass; - kbts_u16 SequenceGlyphFlags = SequenceGlyph->UnicodeFlags; - - kbts_u8 MarkOrdering = 3; - - if(SequenceGlyphCombiningClass == KBTS_REMAPPED_CCC_33) - { - MarkOrdering = 2; - } - else if(SequenceGlyphCombiningClass == 220) - { - if(SequenceGlyphFlags & KBTS_UNICODE_FLAG_MODIFIER_COMBINING_MARK) - { - if(Mcm220SequenceState != KBTS_MCM_SEQUENCE_STATE_OUT) - { - Mcm220SequenceState = KBTS_MCM_SEQUENCE_STATE_IN; - } - } - else - { - Mcm220SequenceState = KBTS_MCM_SEQUENCE_STATE_OUT; - } - - if(Mcm220SequenceState == KBTS_MCM_SEQUENCE_STATE_IN) - { - MarkOrdering = 0; - } - - Mcm230SequenceState = KBTS_MCM_SEQUENCE_STATE_NONE; - } - else if(SequenceGlyphCombiningClass == 230) - { - if(SequenceGlyphFlags & KBTS_UNICODE_FLAG_MODIFIER_COMBINING_MARK) - { - if(Mcm230SequenceState != KBTS_MCM_SEQUENCE_STATE_OUT) - { - Mcm230SequenceState = KBTS_MCM_SEQUENCE_STATE_IN; - } - } - else - { - Mcm230SequenceState = KBTS_MCM_SEQUENCE_STATE_OUT; - } - - if(Mcm230SequenceState == KBTS_MCM_SEQUENCE_STATE_IN) - { - MarkOrdering = 1; - } - } - else if(SequenceGlyphCombiningClass) - { - Mcm220SequenceState = KBTS_MCM_SEQUENCE_STATE_NONE; - Mcm230SequenceState = KBTS_MCM_SEQUENCE_STATE_NONE; - } - else - { - break; - } - - SequenceGlyph->MarkOrdering = MarkOrdering; - S->GlyphIndex += 1; - } - - KBTS_FOR(Iter, SequenceStart, S->GlyphIndex) - { - KBTS_FOR(SortIndex, SequenceStart + 1, S->GlyphIndex) - { - kbts_glyph *Left = &Glyphs[SortIndex - 1]; - kbts_glyph *Right = &Glyphs[SortIndex]; - - if(Left->MarkOrdering > Right->MarkOrdering) - { - kbts_glyph Swap = *Left; - *Left = *Right; - *Right = Swap; - } - } - } - } - else - { - S->GlyphIndex += 1; - } - } - } - else if((Config->Script == KBTS_SCRIPT_THAI) || (Config->Script == KBTS_SCRIPT_LAO)) - { - // Decompose sara/sala ams. - kbts_un AboveBaseGlyphCount; AboveBaseGlyphCount = 0; - for(S->GlyphIndex = 0; S->GlyphIndex < S->WrittenCount; ++S->GlyphIndex) - { - if(0) - { - ResumePoint5:; - AboveBaseGlyphCount = S->OpSpecific.Normalize.AboveBaseGlyphCount; - } - kbts_glyph *Glyph = &Glyphs[S->GlyphIndex]; - kbts_u32 Codepoint = Glyph->Codepoint; - - switch(Codepoint) - { - // Sara am/sala am. - // We match both because storing the sara am codepoint that corresponds to the current script - // doesn't seem that worthwhile, given that this is already a pretty big switch case. - // If we choose to use a unicode flag or indic syllabic category to notate above-base marks, - // then this loops gets a lot tighter and it would probably become the right call to pre-determine - // the sara am codepoint. - case 0xE33: case 0xEB3: // Sara am - { - if(!kbts_GrowGlyphArray(&S->ResumePoint, GlyphArray, S->GlyphIndex, 1, 5, 0)) - { - S->OpSpecific.Normalize.AboveBaseGlyphCount = AboveBaseGlyphCount; - KBTS_INSTRUMENT_END - return 1; - } - - AboveBaseGlyphCount = S->OpSpecific.Normalize.AboveBaseGlyphCount; - for(kbts_un AboveBaseIndex = 0; AboveBaseIndex < AboveBaseGlyphCount; ++AboveBaseIndex) - { - Glyphs[S->GlyphIndex - AboveBaseIndex] = Glyphs[S->GlyphIndex - AboveBaseIndex - 1]; - } - Glyphs[S->GlyphIndex - AboveBaseGlyphCount] = Config->Nikhahit; - Glyphs[S->GlyphIndex + 1] = Config->SaraAa; - S->WrittenCount += 1; - } break; - - case 0xE31: case 0xE34: case 0xE35: case 0xE36: case 0xE37: case 0xE3B: - case 0xE47: case 0xE48: case 0xE49: case 0xE4A: case 0xE4B: case 0xE4C: case 0xE4D: case 0xE4E: - case 0xEB1: case 0xEB4: case 0xEB5: case 0xEB6: case 0xEB7: case 0xEBB: - case 0xEC7: case 0xEC8: case 0xEC9: case 0xECA: case 0xECB: case 0xECC: case 0xECD: case 0xECE: - AboveBaseGlyphCount += 1; - break; - - default: - AboveBaseGlyphCount = 0; - break; - } - } - } - - KBTS_INSTRUMENT_END - } - break; - - case KBTS_OP_KIND_NORMALIZE_HANGUL: - { - KBTS_INSTRUMENT_BLOCK_BEGIN("NORMALIZE_HANGUL") - kbts_op_state_normalize_hangul *NormalizeHangul; NormalizeHangul = &S->OpSpecific.NormalizeHangul; - S->GlyphIndex = 0; - while(S->GlyphIndex < GlyphArray->Count) - { - { - kbts_glyph *Glyph = &Glyphs[S->GlyphIndex]; kbts_un L = 0; kbts_un V = 0; kbts_un T = 0; + kbts_un LvtGlyphCount = 0; + kbts_glyph LvtGlyphs[4]; - kbts_hangul_syllable_info LInfo = kbts_HangulSyllableInfo(Glyph->Codepoint); - if(LInfo.Type >= KBTS_HANGUL_SYLLABLE_TYPE_LV) + kbts__hangul_syllable_info LInfo = kbts__HangulSyllableInfo(Glyph->Codepoint); + if(LInfo.Type >= KBTS__HANGUL_SYLLABLE_TYPE_LV) { kbts_un SIndex = (Glyph->Codepoint - 0xAC00); @@ -19250,64 +22398,60 @@ static kbts_u32 kbts_ExecuteOp(kbts_shape_state *ShapeState, kbts_glyph_array *G T = 0x11A7 + TIndex; } } - else if(LInfo.Type == KBTS_HANGUL_SYLLABLE_TYPE_L) + else if(LInfo.Type == KBTS__HANGUL_SYLLABLE_TYPE_L) { L = Glyph->Codepoint; } - S->GlyphIndex += 1; - if(L) { - kbts_hangul_syllable_info VInfo = KBTS_ZERO; + kbts__hangul_syllable_info VInfo = KBTS__ZERO; - if(!V && (S->GlyphIndex < GlyphArray->Count)) + if(!V && kbts__GlyphIsValid(Storage, Next)) { - kbts_u32 VCodepoint = Glyphs[S->GlyphIndex].Codepoint; + kbts_u32 VCodepoint = Next->Codepoint; - VInfo = kbts_HangulSyllableInfo(VCodepoint); + VInfo = kbts__HangulSyllableInfo(VCodepoint); - if(VInfo.Type == KBTS_HANGUL_SYLLABLE_TYPE_V) + if(VInfo.Type == KBTS__HANGUL_SYLLABLE_TYPE_V) { V = VCodepoint; - S->GlyphIndex += 1; + Next = Next->Next; } } if(V) { - kbts_hangul_syllable_info TInfo = KBTS_ZERO; + kbts__hangul_syllable_info TInfo = KBTS__ZERO; - if(!T && (S->GlyphIndex < GlyphArray->Count)) + if(!T && kbts__GlyphIsValid(Storage, Next)) { - kbts_u32 TCodepoint = Glyphs[S->GlyphIndex].Codepoint; + kbts_u32 TCodepoint = Next->Codepoint; - TInfo = kbts_HangulSyllableInfo(TCodepoint); + TInfo = kbts__HangulSyllableInfo(TCodepoint); - if(TInfo.Type == KBTS_HANGUL_SYLLABLE_TYPE_T) + if(TInfo.Type == KBTS__HANGUL_SYLLABLE_TYPE_T) { T = TCodepoint; - S->GlyphIndex += 1; + Next = Next->Next; } } - NormalizeHangul->LvtGlyphCount = 0; - // Check for any tone marks that we need to swap to the front of the syllable. // The OpenType shaping documents say that we need to do this after applying GSUB features, but // harfbuzz does it before, so it's probably fine to do it here? // It's also basically free to do here, which is nice. - if(S->GlyphIndex < GlyphArray->Count) + if(kbts__GlyphIsValid(Storage, Next)) { - kbts_u32 ToneMarkCodepoint = Glyphs[S->GlyphIndex].Codepoint; + kbts_u32 ToneMarkCodepoint = Next->Codepoint; if((ToneMarkCodepoint >= 0x302E) && (ToneMarkCodepoint <= 0x302F)) { - NormalizeHangul->LvtGlyphs[NormalizeHangul->LvtGlyphCount++] = kbts_CodepointToGlyph(Font, ToneMarkCodepoint); + LvtGlyphs[LvtGlyphCount++] = kbts_CodepointToGlyph(Font, (int)ToneMarkCodepoint, 0, 0); - S->GlyphIndex += 1; + Next = Next->Next; } } @@ -19316,570 +22460,570 @@ static kbts_u32 kbts_ExecuteOp(kbts_shape_state *ShapeState, kbts_glyph_array *G // Try LVT. kbts_un LvtCodepoint = 0xAC00 + (L - 0x1100) * 588 + (V - 0x1161) * 28 + (T - 0x11A7); - kbts_glyph LvtGlyph = kbts_CodepointToGlyph(Font, (kbts_u32)LvtCodepoint); + kbts_glyph LvtGlyph = kbts_CodepointToGlyph(Font, (int)LvtCodepoint, 0, 0); if(LvtGlyph.Id) { - NormalizeHangul->LvtGlyphs[NormalizeHangul->LvtGlyphCount++] = LvtGlyph; + LvtGlyphs[LvtGlyphCount++] = LvtGlyph; } } - if(!NormalizeHangul->LvtGlyphCount) + if(!LvtGlyphCount) { - kbts_glyph LvGlyph = KBTS_ZERO; + kbts_glyph LvGlyph = KBTS__ZERO; if(LInfo.Composable & VInfo.Composable) { // Try LV. kbts_un LvCodepoint = 0xAC00 + (L - 0x1100) * 588 + (V - 0x1161) * 28; - LvGlyph = kbts_CodepointToGlyph(Font, (kbts_u32)LvCodepoint); + LvGlyph = kbts_CodepointToGlyph(Font, (int)LvCodepoint, 0, 0); } if(LvGlyph.Id) { - NormalizeHangul->LvtGlyphs[NormalizeHangul->LvtGlyphCount++] = LvGlyph; + LvtGlyphs[LvtGlyphCount++] = LvGlyph; } else { // Do L-V. - kbts_glyph LGlyph = kbts_CodepointToGlyph(Font, (kbts_u32)L); + kbts_glyph LGlyph = kbts_CodepointToGlyph(Font, (int)L, 0, 0); LGlyph.Flags |= KBTS_GLYPH_FLAG_LJMO; - kbts_glyph VGlyph = kbts_CodepointToGlyph(Font, (kbts_u32)V); + kbts_glyph VGlyph = kbts_CodepointToGlyph(Font, (int)V, 0, 0); VGlyph.Flags |= KBTS_GLYPH_FLAG_VJMO; - NormalizeHangul->LvtGlyphs[NormalizeHangul->LvtGlyphCount++] = LGlyph; - NormalizeHangul->LvtGlyphs[NormalizeHangul->LvtGlyphCount++] = VGlyph; + LvtGlyphs[LvtGlyphCount++] = LGlyph; + LvtGlyphs[LvtGlyphCount++] = VGlyph; } if(T) { - kbts_glyph TGlyph = kbts_CodepointToGlyph(Font, (kbts_u32)T); + kbts_glyph TGlyph = kbts_CodepointToGlyph(Font, (int)T, 0, 0); TGlyph.Flags |= KBTS_GLYPH_FLAG_TJMO; - NormalizeHangul->LvtGlyphs[NormalizeHangul->LvtGlyphCount++] = TGlyph; + LvtGlyphs[LvtGlyphCount++] = TGlyph; } } } } - if(!NormalizeHangul->LvtGlyphCount) + if(!LvtGlyphCount) { - kbts_glyph NewGlyph = kbts_CodepointToGlyph(Font, Glyph->Codepoint); + kbts_glyph NewGlyph = kbts_CodepointToGlyph(Font, (int)Glyph->Codepoint, 0, 0); - NormalizeHangul->LvtGlyphs[NormalizeHangul->LvtGlyphCount++] = NewGlyph; + LvtGlyphs[LvtGlyphCount++] = NewGlyph; } - } - { // Insert the LVT glyphs. - ResumePoint3:; - NormalizeHangul = &S->OpSpecific.NormalizeHangul; + { // Insert the LVT glyphs. + kbts_glyph *LastConsumed = Next->Prev; - kbts_un NewWrittenCount = S->WrittenCount + NormalizeHangul->LvtGlyphCount; - if(NewWrittenCount > S->GlyphIndex) - { - if(!kbts_GrowGlyphArray(&S->ResumePoint, GlyphArray, S->WrittenCount, NormalizeHangul->LvtGlyphCount, 3, 0)) + // Remove the sub-list from the main list. + Glyph->Prev->Next = LastConsumed->Next; + LastConsumed->Next->Prev = Glyph->Prev; + + // Send it to the free list. + Glyph->Prev = (kbts_glyph *)&Storage->FreeGlyphSentinel; + LastConsumed->Next = Storage->FreeGlyphSentinel.Next; + Glyph->Prev->Next = Glyph; + LastConsumed->Next->Prev = LastConsumed; + + for(kbts_un LvtGlyphIndex = 0; + LvtGlyphIndex < LvtGlyphCount; + ++LvtGlyphIndex) { - KBTS_INSTRUMENT_END - return 1; - } - - S->GlyphIndex += NormalizeHangul->LvtGlyphCount; - } - - KBTS_FOR(LvtGlyphIndex, 0, NormalizeHangul->LvtGlyphCount) - { - Glyphs[S->WrittenCount++] = NormalizeHangul->LvtGlyphs[LvtGlyphIndex]; - } - } - } - KBTS_INSTRUMENT_END - } - break; - - case KBTS_OP_KIND_GSUB_FEATURES: - { - KBTS_INSTRUMENT_BLOCK_BEGIN("GSUB_FEATURES") - - kbts_gsub_gpos *FontGsub; FontGsub = Font->ShapingTables[KBTS_SHAPING_TABLE_GSUB]; - kbts_lookup_list *LookupList; LookupList = kbts_GetLookupList(FontGsub); - kbts_gsub_frame *Frames; Frames = KBTS_POINTER_AFTER(kbts_gsub_frame, S); - kbts_op_state_gsub *Gsub; Gsub = &S->OpSpecific.Gsub; - kbts_u32 GlyphFilter; - kbts_skip_flags SkipFlags; - kbts_feature_set LookupFeatures; - - kbts_BeginFeatures(S, Config, KBTS_SHAPING_TABLE_GSUB, Op->Features); - while(kbts_NextLookupIndex(S, &Gsub->LookupIndex, &SkipFlags, &GlyphFilter, &LookupFeatures)) - { - Gsub->LookupFeatures = LookupFeatures; - S->GlyphIndex = 0; - - // From the Microsoft docs: - // If a Lookup table has multiple subtables, the subtables are processed in order, testing the glyph sequence - // at the current glyph position for a match with the input sequence patterns specified by each subtable in - // turn. - // - // This means the subtable loop is _inside_ of the loop over our glyphs. - while(S->GlyphIndex < GlyphArray->Count) - { - Frames[0].InputGlyphCount = 1; - - { - kbts_u32 FilterMask = Config->Shaper == KBTS_SHAPER_USE ? KBTS_USE_GLYPH_FEATURE_MASK : KBTS_GLYPH_FEATURE_MASK; - kbts_u32 EffectiveGlyphFilter = GlyphFilter & FilterMask; - - // Reverse chaining substitutions are tricky. - // See the comment at :ReverseChaining. - // @Duplication: We just copy the top-level mirroring logic from DoSubstitution here for now. - kbts_lookup *Lookup = kbts_GetLookup(LookupList, Gsub->LookupIndex); - kbts_un CurrentGlyphIndex = (Lookup->Type == 8) ? GlyphArray->Count - 1 - S->GlyphIndex : S->GlyphIndex; - kbts_glyph *CurrentGlyph = &Glyphs[CurrentGlyphIndex]; - - if(kbts_GlyphIncludedInLookup(Config->Font, 0, Gsub->LookupIndex, CurrentGlyph->Id) && - ((CurrentGlyph->Flags & EffectiveGlyphFilter) == EffectiveGlyphFilter) && - kbts_ConfigAllowsFeatures(S, Config, CurrentGlyph->Config, &LookupFeatures)) - { - kbts_gsub_frame *Frame = &Frames[0]; - - Frame->LookupIndex = (kbts_u16)Gsub->LookupIndex; - Frame->SubtableIndex = 0; - Frame->InputGlyphIndex = (kbts_u16)S->GlyphIndex; - S->FrameCount = 1; - } - } - - while(S->FrameCount) - { - if(0) - { - ResumePoint2:; - FontGsub = Font->ShapingTables[KBTS_SHAPING_TABLE_GSUB]; - Gsub = &S->OpSpecific.Gsub; - LookupList = kbts_GetLookupList(FontGsub); - Frames = KBTS_POINTER_AFTER(kbts_gsub_frame, S); - LookupFeatures = Gsub->LookupFeatures; - GlyphFilter = Gsub->GlyphFilter; - SkipFlags = Gsub->SkipFlags; - } - - // These flags are used by USE. - kbts_u32 GeneratedGlyphFlags = GlyphFilter & (KBTS_GLYPH_FLAG_RPHF | KBTS_GLYPH_FLAG_PREF); - kbts_substitution_result_flags SubstitutionFlags = kbts_DoSubstitution(ShapeState, LookupList, Frames, &S->FrameCount, GlyphArray, 0, SkipFlags, GeneratedGlyphFlags); - if(SubstitutionFlags & KBTS_SUBSTITUTION_RESULT_FLAG_GROW_BUFFER) - { - Gsub->GlyphFilter = GlyphFilter; - Gsub->SkipFlags = SkipFlags; - S->ResumePoint = 2; - - KBTS_INSTRUMENT_END - return 1; - } - } - - S->GlyphIndex += Frames[0].InputGlyphCount; - } - } - - S->WrittenCount = GlyphArray->Count; - KBTS_INSTRUMENT_END - } - break; - - case KBTS_OP_KIND_FLAG_JOINING_LETTERS: - { - KBTS_INSTRUMENT_BLOCK_BEGIN("FLAG_JOINING_LETTERS") - kbts_u64 JoiningTypesMatchLookup = - (((1ull << KBTS_UNICODE_JOINING_TYPE_RIGHT) | (1ull << KBTS_UNICODE_JOINING_TYPE_DUAL) | (1ull << KBTS_UNICODE_JOINING_TYPE_FORCE)) << (8 * KBTS_UNICODE_JOINING_TYPE_LEFT)) | - (((1ull << KBTS_UNICODE_JOINING_TYPE_RIGHT) | (1ull << KBTS_UNICODE_JOINING_TYPE_DUAL) | (1ull << KBTS_UNICODE_JOINING_TYPE_FORCE)) << (8 * KBTS_UNICODE_JOINING_TYPE_DUAL)) | - (((1ull << KBTS_UNICODE_JOINING_TYPE_RIGHT) | (1ull << KBTS_UNICODE_JOINING_TYPE_DUAL) | (1ull << KBTS_UNICODE_JOINING_TYPE_FORCE)) << (8 * KBTS_UNICODE_JOINING_TYPE_FORCE)); - - kbts_u64 JoiningFeatureTransition = ((kbts_u64)KBTS_JOINING_FEATURE_INIT << (8 * KBTS_JOINING_FEATURE_ISOL)) | ((kbts_u64)KBTS_JOINING_FEATURE_MEDI << (8 * KBTS_JOINING_FEATURE_FINA)) | - ((kbts_u64)KBTS_JOINING_FEATURE_MEDI << (8 * KBTS_JOINING_FEATURE_MEDI)) | ((kbts_u64)KBTS_JOINING_FEATURE_MED2 << (8 * KBTS_JOINING_FEATURE_MED2)); - - // Tag letters for joining features. - kbts_glyph PreviousGlyph_ = KBTS_ZERO; - kbts_glyph *PreviousGlyph = &PreviousGlyph_; - KBTS_FOR(GlyphIndex, 0, GlyphArray->Count) - { - kbts_glyph *Glyph = &Glyphs[GlyphIndex]; - - if(Glyph->JoiningType != KBTS_UNICODE_JOINING_TYPE_TRANSPARENT) - { - Glyph->JoiningFeature = !PreviousGlyph->JoiningType ? KBTS_JOINING_FEATURE_INIT : KBTS_JOINING_FEATURE_FINA; - - if(JoiningTypesMatchLookup & (1ull << (Glyph->JoiningType + 8 * PreviousGlyph->JoiningType))) - { - PreviousGlyph->JoiningFeature = (JoiningFeatureTransition >> (8 * PreviousGlyph->JoiningFeature)) & 0xFF; - PreviousGlyph->Flags = (PreviousGlyph->Flags & ~KBTS_JOINING_FEATURE_MASK) | KBTS_JOINING_FEATURE_TO_GLYPH_FLAG(PreviousGlyph->JoiningFeature); - - Glyph->JoiningFeature = KBTS_JOINING_FEATURE_FINA; - } - else - { - Glyph->JoiningFeature = KBTS_JOINING_FEATURE_ISOL; - } - - if(Glyph->JoiningFeature) - { - // Be careful that this properly maps kbts_joining_feature to KBTS_GLYPH_FLAG! - Glyph->Flags = (Glyph->Flags & ~KBTS_JOINING_FEATURE_MASK) | KBTS_JOINING_FEATURE_TO_GLYPH_FLAG(Glyph->JoiningFeature); - } - - PreviousGlyph = Glyph; - } - } - - S->WrittenCount = GlyphArray->Count; - KBTS_INSTRUMENT_END - } - break; - - case KBTS_OP_KIND_GPOS_METRICS: - { - KBTS_INSTRUMENT_BLOCK_BEGIN("GPOS_METRICS") - // hmtx/vmtx pass. - int ClearMarkAdvances = (Config->Shaper == KBTS_SHAPER_MYANMAR) || (Config->Shaper == KBTS_SHAPER_USE); - kbts_u32 Orientation = KBTS_ORIENTATION_HORIZONTAL; // @Hardcoded - kbts_hea *Hea = Font->Hea[Orientation]; - kbts_u16 *Mtx = Font->Mtx[Orientation]; - - kbts_long_mtx *LongMetrics = 0; - kbts_s16 *ShortMetrics = 0; - if(Hea && Mtx) - { - LongMetrics = (kbts_long_mtx *)Mtx; - ShortMetrics = (kbts_s16 *)(LongMetrics + Hea->MetricCount); - } - - kbts_long_mtx DefaultMetric = {1024, 0}; - if(Font->Head) - { - DefaultMetric.Advance = Font->Head->UnitsPerEm; - if(Orientation == KBTS_ORIENTATION_HORIZONTAL) - { - DefaultMetric.Advance /= 2; - } - } - - KBTS_FOR(GlyphIndex, 0, GlyphArray->Count) - { - kbts_glyph *Glyph = &Glyphs[GlyphIndex]; - - kbts_long_mtx Metric = DefaultMetric; - if(LongMetrics) - { - kbts_u32 Id = Glyph->Id; - - // At the end of shaping, default ignorable glyphs that are not generated by GSUB are replaced with zero-width - // whitespace glyphs (or a zero-width empty glyph if no whitespace glyph is present). - // (By the way, we do this because Harfbuzz does it, and Harfbuzz does it probably because Uniscribe does it.) - // We handle this in two steps: - // - The first is here. We want cursive attachments, and mark-to-base attachments, and other relative placements - // to take the zero width into account, and zeroing the width right at the beginning of GPOS is the most - // straighforward way to accomplish this. - // (@Incomplete: It is likely that we also need to take the default ignorable case into account when accumulating - // cursive offsets.) - // - In POST_GPOS_FIXUP, we perform the glyph ID substitution. We have to wait until all GPOS features have been - // executed to do this because they might possibly match the original ID. - if(!(Glyph->Flags & KBTS_GLYPH_FLAG_GENERATED_BY_GSUB) && (Glyph->UnicodeFlags & KBTS_UNICODE_FLAG_DEFAULT_IGNORABLE)) - { - Metric.Advance = 0; - Metric.PreviousSideBearing = 0; - } - else if(Id < Hea->MetricCount) - { - Metric = LongMetrics[Id]; - } - else - { - Metric.Advance = LongMetrics[Hea->MetricCount - 1].Advance; - Metric.PreviousSideBearing = ShortMetrics[Id - Hea->MetricCount]; - } - } - - if(!ClearMarkAdvances | (Glyph->Classes.Class != KBTS_GLYPH_CLASS_MARK)) - { - if(Orientation == KBTS_ORIENTATION_HORIZONTAL) - { - // @Cleanup: Why does harfbuzz not take bearings into account in these tests? - // P.X += Metric.PreviousSideBearing; - Glyph->AdvanceX = Metric.Advance; - } - else - { - // @Cleanup: Why does harfbuzz not take bearings into account in these tests? - // P.Y += Metric.PreviousSideBearing; - Glyph->AdvanceY = Metric.Advance; - } - } - } - KBTS_INSTRUMENT_END - } - break; - - case KBTS_OP_KIND_GPOS_FEATURES: - { - KBTS_INSTRUMENT_BLOCK_BEGIN("GPOS_FEATURES") - kbts_gsub_gpos *Gpos = Font->ShapingTables[KBTS_SHAPING_TABLE_GPOS]; - kbts_BeginFeatures(S, Config, KBTS_SHAPING_TABLE_GPOS, Op->Features); - kbts_lookup_list *LookupList = kbts_GetLookupList(Gpos); - kbts_un LookupIndex; - kbts_skip_flags SkipFlags; - kbts_u32 GlyphFilter; - kbts_feature_set LookupFeatures; - while(kbts_NextLookupIndex(S, &LookupIndex, &SkipFlags, &GlyphFilter, &LookupFeatures)) - { - kbts_lookup *PackedLookup = kbts_GetLookup(LookupList, LookupIndex); - kbts_unpacked_lookup Lookup = kbts_UnpackLookup(Font->Gdef, PackedLookup); - - kbts_un PositionedGlyphCount = 0; - while(PositionedGlyphCount < GlyphArray->Count) - { - kbts_un DeltaGlyphIndex = 1; - - if(kbts_GlyphIncludedInLookup(Config->Font, 1, LookupIndex, GlyphArray->Glyphs[PositionedGlyphCount].Id) && - kbts_ConfigAllowsFeatures(S, Config, Glyphs[PositionedGlyphCount].Config, &LookupFeatures)) - { - KBTS_FOR(SubtableIndex, 0, Lookup.SubtableCount) - { - kbts_u16 *Subtable = KBTS_POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[SubtableIndex]); - kbts_do_single_adjustment_result Adjustment = kbts_DoSingleAdjustment(Config, LookupList, LookupIndex, SubtableIndex, &Lookup, Subtable, GlyphArray, PositionedGlyphCount, SkipFlags); - if(Adjustment.PerformedAdjustment) + kbts_glyph *LvtGlyph = &LvtGlyphs[LvtGlyphIndex]; + kbts_glyph *NewGlyph = kbts__InsertGlyphBefore(Storage, Next, LvtGlyph); + if(!NewGlyph) { - DeltaGlyphIndex = Adjustment.PositionedGlyphCount; - break; + goto OutOfMemory; } } } - PositionedGlyphCount += DeltaGlyphIndex; + Glyph = Next; } + // KBTS_INSTRUMENT_BLOCK_END(NORMALIZE_HANGUL); } - KBTS_INSTRUMENT_END - } - break; + break; - case KBTS_OP_KIND_POST_GPOS_FIXUP: - { - KBTS_INSTRUMENT_BLOCK_BEGIN("POST_GPOS_FIXUP") - kbts_un WriteAt = 0; - kbts_glyph WhitespaceGlyph = Config->Whitespace; - int ClearMarkAdvances = kbts_ShaperClearsMarkAdvancesInPostGposFixup(Config->Shaper); - - if(ShapeState->MainDirection != ShapeState->RunDirection) + case KBTS__OP_KIND_GSUB_FEATURES: { - // Flip direction. - // This might seem like a totally superfluous thing to do, because we have to do a bunch - // of work to reverse glyph order while still preserving their relative positions. - // However, for mainly LTR documents, the anchor position will naturally be left-aligned, - // while, in RTL documents, it will naturally right-align. - // As such, going through the glyph sequence and reversing it is needed _anyway_ at some point, - // and we might as well do it here, because this is where we can take resolve attachments - // for relatively cheap, since they are always back-looking. (The next paragraph explains this - // in more detail.) + KBTS_INSTRUMENT_BLOCK_BEGIN(GSUB_FEATURES); - // The unintuitive part about this pass is the glyph advances. - // Normally, when iterating over a sequence of glyphs, we see base glyphs before marks. Obviously. - // However, when flipping the sequence, we see the marks before seeing the bases, which means we - // won't have accumulated the base glyph's advance yet! So we have to go through the sequence here - // and compensate for missing advances by precomputing them and baking them into the marks. - // Another way to reach the same result would be to keep marks on the same side as their bases when - // flipping, but that is not what Harfbuzz does, and, the day we decide we want to diverge from Harfbuzz, - // we will very likely be better off not flipping the sequence at all and deleting all of this garbage code. - kbts_s32 MarkAttachAdvanceX = 0; - kbts_s32 MarkAttachAdvanceY = 0; - KBTS_FOR(GlyphIndex, 0, GlyphArray->Count) + kbts__gsub_gpos *FontGsub = kbts__BlobTableDataType(Font->Blob, KBTS_BLOB_TABLE_ID_GSUB, kbts__gsub_gpos); + kbts_lookup_list *LookupList; LookupList = kbts__GetLookupList(FontGsub); + kbts__arena_lifetime Lifetime = kbts__BeginLifetime(Scratchpad->Arena); + kbts__gsub_frame *Frames = kbts__PushArray(Scratchpad->Arena, kbts__gsub_frame, KBTS_LOOKUP_STACK_SIZE); + kbts_u32 GlyphFilter; + kbts__skip_flags SkipFlags; + kbts_un LookupIndex; + + if(kbts__BeginFeatures(Scratchpad, Config, KBTS_SHAPING_TABLE_GSUB)) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex]; - - if(Glyph->AttachGlyphIndexPlusOne) + while(kbts__NextLookupIndex(Scratchpad, Config, &LookupIndex, &SkipFlags, &GlyphFilter, &Scratchpad->LookupFeatures)) { - kbts_glyph *Attach = &Glyphs[Glyph->AttachGlyphIndexPlusOne - 1]; - kbts_s32 AttachAdvanceX = MarkAttachAdvanceX; - kbts_s32 AttachAdvanceY = MarkAttachAdvanceY; - if(Attach->Classes.Class != KBTS_GLYPH_CLASS_MARK) + kbts__lookup *Lookup = kbts__GetLookup(LookupList, LookupIndex); + + // From the Microsoft docs: + // If a Lookup table has multiple subtables, the subtables are processed in order, testing the glyph sequence + // at the current glyph position for a match with the input sequence patterns specified by each subtable in + // turn. + // + // This means the subtable loop is _inside_ of the loop over our glyphs. + + // Reverse chaining substitutions are tricky. + // See the comment at :ReverseChaining. + for(kbts_glyph *Glyph = (Lookup->Type == 8) ? Storage->GlyphSentinel.Prev : Storage->GlyphSentinel.Next; + kbts__GlyphIsValid(Storage, Glyph); + ) { - AttachAdvanceX = Attach->AdvanceX; - AttachAdvanceY = Attach->AdvanceY; + kbts__BeginLookupApplication(Scratchpad, Glyph); + kbts_un FrameCount = 0; + kbts_u32 FilterMask = Config->Shaper == KBTS_SHAPER_USE ? KBTS__USE_GLYPH_FEATURE_MASK : KBTS__GLYPH_FEATURE_MASK; + kbts_u32 EffectiveGlyphFilter = GlyphFilter & FilterMask; + + if(kbts__GlyphIncludedInLookup(Font, 0, LookupIndex, Glyph->Id) && + ((Glyph->Flags & EffectiveGlyphFilter) == EffectiveGlyphFilter) && + kbts__ConfigAllowsFeatures(Scratchpad, Config, Glyph->Config, &Scratchpad->LookupFeatures)) + { + kbts__gsub_frame FirstFrame = KBTS__ZERO; + FirstFrame.LookupIndex = (kbts_u16)LookupIndex; + FirstFrame.InputGlyph = Glyph; + + Frames[0] = FirstFrame; + FrameCount = 1; + + while(FrameCount) + { + // These flags are used by USE. + kbts_u32 GeneratedGlyphFlags = GlyphFilter & (KBTS_GLYPH_FLAG_RPHF | KBTS_GLYPH_FLAG_PREF); + kbts__DoSubstitution(Scratchpad, Config, Storage, LookupList, Frames, &FrameCount, 0, SkipFlags, GeneratedGlyphFlags); + } + } + + kbts_glyph *OnePastLast = kbts__EndLookupApplication(Scratchpad); + Glyph = (Lookup->Type == 8) ? Glyph->Prev : OnePastLast; } - Glyph->OffsetX += AttachAdvanceX; - Glyph->OffsetY += AttachAdvanceY; - MarkAttachAdvanceX = AttachAdvanceX; - MarkAttachAdvanceY = AttachAdvanceY; } } - kbts_un SwapCount = GlyphArray->Count / 2; - KBTS_FOR(LeftIndex, 0, SwapCount) - { - kbts_un RightIndex = GlyphArray->Count - 1 - LeftIndex; - - kbts_glyph SwapGlyph = Glyphs[LeftIndex]; - Glyphs[LeftIndex] = Glyphs[RightIndex]; - Glyphs[RightIndex] = SwapGlyph; - } + kbts__EndLifetime(&Lifetime); + KBTS_INSTRUMENT_BLOCK_END(GSUB_FEATURES); } + break; - // Make default ignorables that weren't explicitly created by the font invisible. - // - // It is tempting to put this loop inside of an if(WhitespaceGlyph.Id), just like we do - // for dotted circle insertion. However, Harfbuzz does not do this! - // When the font does not contain a dotted circle, nothing is inserted, but when the font - // does not contain a whitespace glyph, _we still insert an empty glyph_. - KBTS_FOR(GlyphIndex, 0, GlyphArray->Count) + case KBTS__OP_KIND_FLAG_JOINING_LETTERS: { - kbts_glyph Glyph = Glyphs[GlyphIndex]; - int Write = 0; + KBTS_INSTRUMENT_BLOCK_BEGIN(FLAG_JOINING_LETTERS); + kbts_u64 JoiningTypesMatchLookup = + (((1ull << KBTS_UNICODE_JOINING_TYPE_RIGHT) | (1ull << KBTS_UNICODE_JOINING_TYPE_DUAL) | (1ull << KBTS_UNICODE_JOINING_TYPE_FORCE)) << (8 * KBTS_UNICODE_JOINING_TYPE_LEFT)) | + (((1ull << KBTS_UNICODE_JOINING_TYPE_RIGHT) | (1ull << KBTS_UNICODE_JOINING_TYPE_DUAL) | (1ull << KBTS_UNICODE_JOINING_TYPE_FORCE)) << (8 * KBTS_UNICODE_JOINING_TYPE_DUAL)) | + (((1ull << KBTS_UNICODE_JOINING_TYPE_RIGHT) | (1ull << KBTS_UNICODE_JOINING_TYPE_DUAL) | (1ull << KBTS_UNICODE_JOINING_TYPE_FORCE)) << (8 * KBTS_UNICODE_JOINING_TYPE_FORCE)); - // It might be tempting to keep glyphs that were used in GPOS, but Harfbuzz doesn't care. - if(!(Glyph.Flags & KBTS_GLYPH_FLAG_GENERATED_BY_GSUB) && (Glyph.UnicodeFlags & KBTS_UNICODE_FLAG_DEFAULT_IGNORABLE)) + kbts_u64 JoiningFeatureTransition = ((kbts_u64)KBTS_JOINING_FEATURE_INIT << (8 * KBTS_JOINING_FEATURE_ISOL)) | ((kbts_u64)KBTS_JOINING_FEATURE_MEDI << (8 * KBTS_JOINING_FEATURE_FINA)) | + ((kbts_u64)KBTS_JOINING_FEATURE_MEDI << (8 * KBTS_JOINING_FEATURE_MEDI)) | ((kbts_u64)KBTS_JOINING_FEATURE_MED2 << (8 * KBTS_JOINING_FEATURE_MED2)); + + // Tag letters for joining features. + kbts_glyph PreviousGlyph_ = KBTS__ZERO; + kbts_glyph *PreviousGlyph = &PreviousGlyph_; + KBTS__FOR_GLYPH(Storage, Glyph) { - // This glyph is default ignorable and should be ignored. - if(WhitespaceGlyph.Id) + if(Glyph->JoiningType != KBTS_UNICODE_JOINING_TYPE_TRANSPARENT) { - Write = 1; - Glyph = WhitespaceGlyph; - } - } - else - { - if(ClearMarkAdvances && (Glyph.Classes.Class == KBTS_GLYPH_CLASS_MARK)) - { - Glyph.AdvanceX = Glyph.AdvanceY = 0; - } - Write = 1; - } + Glyph->JoiningFeature = (kbts_joining_feature)(!PreviousGlyph->JoiningType ? KBTS_JOINING_FEATURE_INIT : KBTS_JOINING_FEATURE_FINA); - if(Write) - { - Glyphs[WriteAt++] = Glyph; - } - } - - GlyphArray->Count = (kbts_u32)WriteAt; - GlyphArray->TotalCount = GlyphArray->Count; - KBTS_INSTRUMENT_END - } - break; - - case KBTS_OP_KIND_STCH_POSTPASS: - { - KBTS_FOR(GlyphIndex, 0, GlyphArray->Count) - { - kbts_glyph *Glyph = &Glyphs[GlyphIndex]; - - if(Glyph->Flags & (KBTS_GLYPH_FLAG_STCH_ENDPOINT | KBTS_GLYPH_FLAG_STCH_EXTENSION)) - { - kbts_un At = GlyphIndex; - - kbts_un ExtensionIndex = At; - kbts_u32 SawExtension = 0; - - kbts_s32 EndpointWidth = 0; - kbts_s32 ExtensionWidth = 0; - - while(At < GlyphArray->Count) - { - kbts_glyph *AtGlyph = &Glyphs[At]; - - if(AtGlyph->Flags & KBTS_GLYPH_FLAG_STCH_ENDPOINT) + if(JoiningTypesMatchLookup & (1ull << (Glyph->JoiningType + 8 * PreviousGlyph->JoiningType))) { - EndpointWidth += AtGlyph->AdvanceX; + PreviousGlyph->JoiningFeature = (JoiningFeatureTransition >> (8 * PreviousGlyph->JoiningFeature)) & 0xFF; + PreviousGlyph->Flags = (PreviousGlyph->Flags & ~KBTS__JOINING_FEATURE_MASK) | KBTS__JOINING_FEATURE_TO_GLYPH_FLAG(PreviousGlyph->JoiningFeature); - At += 1; - } - else if(AtGlyph->Flags & KBTS_GLYPH_FLAG_STCH_EXTENSION) - { - ExtensionIndex = At; - ExtensionWidth += AtGlyph->AdvanceX; - SawExtension = 1; - - At += 1; + Glyph->JoiningFeature = KBTS_JOINING_FEATURE_FINA; } else { - break; + Glyph->JoiningFeature = KBTS_JOINING_FEATURE_ISOL; } + + if(Glyph->JoiningFeature) + { + // Be careful that this properly maps kbts_joining_feature to KBTS_GLYPH_FLAG! + Glyph->Flags = (Glyph->Flags & ~KBTS__JOINING_FEATURE_MASK) | KBTS__JOINING_FEATURE_TO_GLYPH_FLAG(Glyph->JoiningFeature); + } + + PreviousGlyph = Glyph; } + } - kbts_sn WordWidth = 0; + KBTS_INSTRUMENT_BLOCK_END(FLAG_JOINING_LETTERS); + } + break; - while(At < GlyphArray->Count) + case KBTS__OP_KIND_GPOS_METRICS: + { + KBTS_INSTRUMENT_BLOCK_BEGIN(GPOS_METRICS); + // hmtx/vmtx pass. + int ClearMarkAdvances = (Config->Shaper == KBTS_SHAPER_MYANMAR) || (Config->Shaper == KBTS_SHAPER_USE); + + kbts_u32 Orientation = KBTS_ORIENTATION_HORIZONTAL; // @Hardcoded + kbts_blob_table_id HeaTableId = KBTS_BLOB_TABLE_ID_HHEA; + kbts_blob_table_id MtxTableId = KBTS_BLOB_TABLE_ID_HMTX; + if(Orientation == KBTS_ORIENTATION_VERTICAL) + { + HeaTableId = KBTS_BLOB_TABLE_ID_VHEA; + MtxTableId = KBTS_BLOB_TABLE_ID_VMTX; + } + + kbts__hea *Hea = kbts__BlobTableDataType(Font->Blob, HeaTableId, kbts__hea); + kbts_u16 *Mtx = kbts__BlobTableDataType(Font->Blob, MtxTableId, kbts_u16); + + kbts__long_mtx *LongMetrics = 0; + // :LeftSideBearing + // kbts_s16 *ShortMetrics = 0; + if(Hea && Mtx) + { + LongMetrics = (kbts__long_mtx *)Mtx; + // :LeftSideBearing + // ShortMetrics = (kbts_s16 *)(LongMetrics + Hea->MetricCount); + } + + kbts__long_mtx DefaultMetric = {1024, 0}; + kbts__head *Head = kbts__BlobTableDataType(Font->Blob, KBTS_BLOB_TABLE_ID_HEAD, kbts__head); + if(Head) + { + DefaultMetric.Advance = Head->UnitsPerEm; + if(Orientation == KBTS_ORIENTATION_HORIZONTAL) { - kbts_glyph *AtGlyph = &Glyphs[At]; + DefaultMetric.Advance /= 2; + } + } - int Ok = 0; + KBTS__FOR_GLYPH(Storage, Glyph) + { + kbts__SetCursiveFlags(Glyph, 0); - if(!(AtGlyph->Flags & (KBTS_GLYPH_FLAG_STCH_ENDPOINT | KBTS_GLYPH_FLAG_STCH_EXTENSION)) && (AtGlyph->UnicodeFlags & KBTS_UNICODE_FLAG_PART_OF_WORD)) + kbts__long_mtx Metric = DefaultMetric; + if(LongMetrics) + { + kbts_u32 Id = Glyph->Id; + + // At the end of shaping, default ignorable glyphs that are not generated by GSUB are replaced with zero-width + // whitespace glyphs (or a zero-width empty glyph if no whitespace glyph is present). + // (By the way, we do this because Harfbuzz does it, and Harfbuzz does it probably because Uniscribe does it.) + // We handle this in two steps: + // - The first is here. We want cursive attachments, and mark-to-base attachments, and other relative placements + // to take the zero width into account, and zeroing the width right at the beginning of GPOS is the most + // straighforward way to accomplish this. + // (@Incomplete: It is likely that we also need to take the default ignorable case into account when accumulating + // cursive offsets.) + // - In POST_GPOS_FIXUP, we perform the glyph ID substitution. We have to wait until all GPOS features have been + // executed to do this because they might possibly match the original ID. + if(!(Glyph->Flags & KBTS_GLYPH_FLAG_GENERATED_BY_GSUB) && (Glyph->UnicodeFlags & KBTS_UNICODE_FLAG_DEFAULT_IGNORABLE)) { - Ok = 1; + Metric.Advance = 0; + // :LeftSideBearing + // Metric.PreviousSideBearing = 0; } - - if(Ok) + else if(Id < Hea->MetricCount) { - WordWidth += AtGlyph->AdvanceX; - - At += 1; + Metric = LongMetrics[Id]; } else { - break; + Metric.Advance = LongMetrics[Hea->MetricCount - 1].Advance; + // :LeftSideBearing + // Metric.PreviousSideBearing = ShortMetrics[Id - Hea->MetricCount]; } } - if(WordWidth > EndpointWidth) + if(!ClearMarkAdvances | (Glyph->Classes.Class != KBTS__GLYPH_CLASS_MARK)) { - kbts_sn ExtensionCount = (WordWidth - EndpointWidth) / ExtensionWidth; - if((ExtensionWidth * ExtensionCount) < (WordWidth - EndpointWidth)) + if(Orientation == KBTS_ORIENTATION_HORIZONTAL) { - ExtensionCount += 1; + // :LeftSideBearing + // Why does harfbuzz not take bearings into account in these tests? + // P.X += Metric.PreviousSideBearing; + Glyph->AdvanceX = Metric.Advance; } + else + { + // :LeftSideBearing + // Why does harfbuzz not take bearings into account in these tests? + // P.Y += Metric.PreviousSideBearing; + Glyph->AdvanceY = Metric.Advance; + } + } + } + KBTS_INSTRUMENT_BLOCK_END(GPOS_METRICS); + } + break; - (void)ExtensionCount; - (void)ExtensionIndex; - (void)SawExtension; - /* @Incomplete - kbts_glyph_adjustment *ExtensionAdjustment = &Positions[ExtensionIndex]; - ExtensionAdjustment->LastRepeatIndex = ExtensionCount - 1; - ExtensionAdjustment->RepeatOffsetX = (WordWidth - EndpointWidth - ExtensionWidth) / ExtensionCount; - */ + case KBTS__OP_KIND_GPOS_FEATURES: + { + KBTS_INSTRUMENT_BLOCK_BEGIN(GPOS_FEATURES); + kbts__gsub_gpos *Gpos = kbts__BlobTableDataType(Font->Blob, KBTS_BLOB_TABLE_ID_GPOS, kbts__gsub_gpos); + + if(kbts__BeginFeatures(Scratchpad, Config, KBTS_SHAPING_TABLE_GPOS)) + { + kbts_lookup_list *LookupList = kbts__GetLookupList(Gpos); + kbts_un LookupIndex; + kbts__skip_flags SkipFlags; + kbts_u32 GlyphFilter; + kbts__feature_set LookupFeatures; + while(kbts__NextLookupIndex(Scratchpad, Config, &LookupIndex, &SkipFlags, &GlyphFilter, &LookupFeatures)) + { + kbts__lookup *PackedLookup = kbts__GetLookup(LookupList, LookupIndex); + kbts__unpacked_lookup Lookup = kbts__UnpackLookup(kbts__BlobTableDataType(Font->Blob, KBTS_BLOB_TABLE_ID_GDEF, kbts__gdef), PackedLookup); + + kbts_glyph *Glyph = Storage->GlyphSentinel.Next; + while(kbts__GlyphIsValid(Storage, Glyph)) + { + kbts__BeginLookupApplication(Scratchpad, Glyph); + + if(kbts__GlyphIncludedInLookup(Config->Font, 1, LookupIndex, Glyph->Id) && + kbts__ConfigAllowsFeatures(Scratchpad, Config, Glyph->Config, &LookupFeatures)) + { + KBTS__FOR(SubtableIndex, 0, Lookup.SubtableCount) + { + kbts_u16 *Subtable = KBTS__POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[SubtableIndex]); + + if(kbts__DoSingleAdjustment(Scratchpad, Config, Storage, LookupList, + LookupIndex, SubtableIndex, &Lookup, Subtable, + Glyph, 0, SkipFlags)) + { + break; + } + } + } + + Glyph = kbts__EndLookupApplication(Scratchpad); + } + } + } + + KBTS_INSTRUMENT_BLOCK_END(GPOS_FEATURES); + } + break; + + case KBTS__OP_KIND_POST_GPOS_FIXUP: + { + KBTS_INSTRUMENT_BLOCK_BEGIN(POST_GPOS_FIXUP); + kbts_glyph WhitespaceGlyph = Config->Whitespace; + int ClearMarkAdvances = kbts__ShaperClearsMarkAdvancesInPostGposFixup(Config->Shaper); + + if(Scratchpad->RunDirection == KBTS_DIRECTION_RTL) + { + // Flip direction. + // This might seem like a totally superfluous thing to do, because we have to do a bunch + // of work to reverse glyph order while still preserving their relative positions. + // However, for mainly LTR documents, the anchor position will naturally be left-aligned, + // while, in RTL documents, it will naturally right-align. + // As such, going through the glyph sequence and reversing it is needed _anyway_ at some point, + // and we might as well do it here, because this is where we can take resolve attachments + // for relatively cheap, since they are always back-looking. (The next paragraph explains this + // in more detail.) + + // The unintuitive part about this pass is the glyph advances. + // Normally, when iterating over a sequence of glyphs, we see base glyphs before marks. Obviously. + // However, when flipping the sequence, we see the marks before seeing the bases, which means we + // won't have accumulated the base glyph's advance yet! So we have to go through the sequence here + // and compensate for missing advances by precomputing them and baking them into the marks. + // Another way to reach the same result would be to keep marks on the same side as their bases when + // flipping, but that is not what Harfbuzz does, and, the day we decide we want to diverge from Harfbuzz, + // we will very likely be better off not flipping the sequence at all and deleting all of this garbage code. + kbts_s32 MarkAttachAdvanceX = 0; + kbts_s32 MarkAttachAdvanceY = 0; + KBTS__FOR_GLYPH(Storage, Glyph) + { + kbts_glyph *Attach = Glyph->AttachGlyph; + if(Attach) + { + kbts_s32 AttachAdvanceX = MarkAttachAdvanceX; + kbts_s32 AttachAdvanceY = MarkAttachAdvanceY; + if(Attach->Classes.Class != KBTS__GLYPH_CLASS_MARK) + { + AttachAdvanceX = Attach->AdvanceX; + AttachAdvanceY = Attach->AdvanceY; + } + Glyph->OffsetX += AttachAdvanceX; + Glyph->OffsetY += AttachAdvanceY; + MarkAttachAdvanceX = AttachAdvanceX; + MarkAttachAdvanceY = AttachAdvanceY; + } } - GlyphIndex = At; + // Swap. + // @Speed: We could just choose the correct links when traversing instead. + kbts__DllistReverseSublist((kbts_glyph *)&Storage->GlyphSentinel, (kbts_glyph *)&Storage->GlyphSentinel); } + + // Make default ignorables that weren't explicitly created by the font invisible. + // + // It is tempting to put this loop inside of an if(WhitespaceGlyph.Id), just like we do + // for dotted circle insertion. However, Harfbuzz does not do this! + // When the font does not contain a dotted circle, nothing is inserted, but when the font + // does not contain a whitespace glyph, _we still insert an empty glyph_. + for(kbts_glyph *Glyph = Storage->GlyphSentinel.Next; + kbts__GlyphIsValid(Storage, Glyph); + ) + { + kbts_glyph *Next = Glyph->Next; + int Keep = 0; + + // It might be tempting to keep glyphs that were used in GPOS, but Harfbuzz doesn't care. + if(!(Glyph->Flags & KBTS_GLYPH_FLAG_GENERATED_BY_GSUB) && (Glyph->UnicodeFlags & KBTS_UNICODE_FLAG_DEFAULT_IGNORABLE)) + { + // This glyph is default ignorable and should be ignored. + if(WhitespaceGlyph.Id) + { + Keep = 1; + kbts__SetGlyphPreserveLinksAndUserId(Glyph, &WhitespaceGlyph); + } + } + else + { + if(ClearMarkAdvances && (Glyph->Classes.Class == KBTS__GLYPH_CLASS_MARK)) + { + Glyph->AdvanceX = Glyph->AdvanceY = 0; + } + Keep = 1; + } + + if(!Keep) + { + kbts__FreeGlyph(Scratchpad, Storage, Glyph); + } + + Glyph = Next; + } + + KBTS_INSTRUMENT_BLOCK_END(POST_GPOS_FIXUP); + } + break; + + case KBTS__OP_KIND_STCH_POSTPASS: + { + #if 0 + KBTS__FOR_GLYPH(ShapeState, Glyph) + { + if(Glyph->Flags & (KBTS_GLYPH_FLAG_STCH_ENDPOINT | KBTS_GLYPH_FLAG_STCH_EXTENSION)) + { + kbts_glyph *Extension = 0; + + kbts_s32 EndpointWidth = 0; + kbts_s32 ExtensionWidth = 0; + + while(kbts__GlyphIsValid(ShapeState, Glyph)) + { + kbts_glyph *AtGlyph = &Glyphs[At]; + + if(AtGlyph->Flags & KBTS_GLYPH_FLAG_STCH_ENDPOINT) + { + EndpointWidth += AtGlyph->AdvanceX; + + At += 1; + } + else if(AtGlyph->Flags & KBTS_GLYPH_FLAG_STCH_EXTENSION) + { + ExtensionIndex = At; + ExtensionWidth += AtGlyph->AdvanceX; + SawExtension = 1; + + At += 1; + } + else + { + break; + } + } + + kbts_sn WordWidth = 0; + + while(At < GlyphArray->Count) + { + kbts_glyph *AtGlyph = &Glyphs[At]; + + int Ok = 0; + + if(!(AtGlyph->Flags & (KBTS_GLYPH_FLAG_STCH_ENDPOINT | KBTS_GLYPH_FLAG_STCH_EXTENSION)) && (AtGlyph->UnicodeFlags & KBTS_UNICODE_FLAG_PART_OF_WORD)) + { + Ok = 1; + } + + if(Ok) + { + WordWidth += AtGlyph->AdvanceX; + + At += 1; + } + else + { + break; + } + } + + if(WordWidth > EndpointWidth) + { + kbts_sn ExtensionCount = (WordWidth - EndpointWidth) / ExtensionWidth; + if((ExtensionWidth * ExtensionCount) < (WordWidth - EndpointWidth)) + { + ExtensionCount += 1; + } + + (void)ExtensionCount; + (void)ExtensionIndex; + (void)SawExtension; + /* @Incomplete + kbts_glyph_adjustment *ExtensionAdjustment = &Positions[ExtensionIndex]; + ExtensionAdjustment->LastRepeatIndex = ExtensionCount - 1; + ExtensionAdjustment->RepeatOffsetX = (WordWidth - EndpointWidth - ExtensionWidth) / ExtensionCount; + */ + } + + GlyphIndex = At; + } + } + #endif + } + break; + } + + if(0) + { + OutOfMemory:; + Scratchpad->Error = KBTS_SHAPE_ERROR_OUT_OF_MEMORY; } } - break; - } - if(Op->Kind < KBTS_OP_KIND_GPOS_METRICS) - { - kbts_un DeltaCount = S->WrittenCount - GlyphArray->Count; - GlyphArray->Count += (kbts_u32)DeltaCount; - GlyphArray->TotalCount += (kbts_u32)DeltaCount; - } - - KBTS_INSTRUMENT_END - return 0; + KBTS_INSTRUMENT_FUNCTION_END; } -static kbts_glyph kbts_Substitute1(kbts_shape_state *ShapeState, kbts_lookup_list *LookupList, kbts_feature *Feature, kbts_skip_flags SkipFlags, kbts_glyph *Glyph) +static kbts_glyph kbts__Substitute1(kbts__shape_scratchpad *Scratchpad, kbts_shape_config *Config, kbts_glyph_storage *Storage, + kbts_lookup_list *LookupList, kbts__feature *Feature, kbts__skip_flags SkipFlags, kbts_glyph *Glyph) { kbts_glyph Result = *Glyph; + kbts_glyph TempSentinel; + TempSentinel.Prev = TempSentinel.Next = &Result; + Result.Prev = Result.Next = &TempSentinel; + kbts__glyph_list List = kbts__PushGlyphList(Storage, &Result, &Result); - kbts_glyph_array GlyphArray = kbts_GlyphArray(Glyph, 1, 1, 1); - - kbts_iterate_lookups IterateLookups = kbts_IterateLookups(LookupList, Feature); - while(kbts_NextLookup(&IterateLookups)) + kbts__iterate_lookups IterateLookups = kbts__IterateLookups(LookupList, Feature); + while(kbts__NextLookup(&IterateLookups)) { - kbts_gsub_frame Frames[8]; - Frames[0].InputGlyphCount = 1; - kbts_u32 FrameCount = 1; + kbts__gsub_frame Frames[8]; + { + kbts__gsub_frame *Frame = &Frames[0]; + *Frame = KBTS__ZERO_TYPE(kbts__gsub_frame); + Frame->LookupIndex = IterateLookups.LookupIndex; + Frame->SubtableIndex = 0; + Frame->StartIndex = 0; + Frame->InputGlyph = &Result; + } + kbts_un FrameCount = 1; while(FrameCount) { - kbts_substitution_result_flags SubstitutionResult = kbts_DoSubstitution(ShapeState, LookupList, Frames, &FrameCount, &GlyphArray, 0, SkipFlags, 0); - if(SubstitutionResult & KBTS_SUBSTITUTION_RESULT_FLAG_GROW_BUFFER) + kbts__substitution_result_flags SubstitutionResult = kbts__DoSubstitution(Scratchpad, Config, Storage, + LookupList, Frames, &FrameCount, 0, SkipFlags, 0); + if(SubstitutionResult & KBTS__SUBSTITUTION_RESULT_FLAG_TRIED_TO_INSERT_WHILE_CHECK_ONLY) { goto Done; } @@ -19887,73 +23031,78 @@ static kbts_glyph kbts_Substitute1(kbts_shape_state *ShapeState, kbts_lookup_lis } Done:; + kbts__PopGlyphList(Storage, &List); return Result; } -typedef struct kbts_attach_state +typedef struct kbts__attach_state { - kbts_syllabic_position CurrentPosition; - kbts_syllabic_position LastPositionThatWasNotPreBaseMatra; + kbts__syllabic_position CurrentPosition; + kbts__syllabic_position LastPositionThatWasNotPreBaseMatra; kbts_indic_syllabic_class LastClass; - kbts_un Start; - kbts_un OnePastLast; -} kbts_attach_state; + kbts_glyph *Start; + kbts_glyph *OnePastLast; + kbts_glyph *At; +} kbts__attach_state; -typedef struct kbts_begin_cluster_result +static kbts_glyph *kbts__BeginCluster(kbts__shape_scratchpad *Scratchpad, kbts_shape_config *Config, kbts_glyph_storage *Storage, + kbts_glyph *Glyph) { - kbts_un ClusterGlyphCount; - kbts_un InsertedGlyphCount; -} kbts_begin_cluster_result; - -static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, kbts_glyph *Glyphs, kbts_un GlyphCount) -{ - kbts_begin_cluster_result Result = KBTS_ZERO; - Result.ClusterGlyphCount = GlyphCount; - kbts_op_state *OpState = &ShapeState->OpState; - kbts_shape_config *Config = ShapeState->Config; kbts_font *Font = Config->Font; - ShapeState->RealCluster = 0; + kbts_glyph *Result = Glyph->Next; + kbts__arena_lifetime Lifetime = kbts__BeginLifetime(Scratchpad->Arena); + + Scratchpad->RealCluster = 0; switch(Config->Shaper) { case KBTS_SHAPER_INDIC: { - kbts_lookup_list *LookupList = kbts_GetLookupList(Font->ShapingTables[KBTS_SHAPING_TABLE_GSUB]); + kbts_lookup_list *LookupList = kbts__GetLookupList(kbts__BlobTableDataType(Font->Blob, KBTS_BLOB_TABLE_ID_GSUB, kbts__gsub_gpos)); - kbts_un OtherCount = 0; - while((OtherCount < GlyphCount) && ((Glyphs[OtherCount].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_OTHER) || (Glyphs[OtherCount].SyllabicClass >= KBTS_INDIC_SYLLABIC_CLASS_COUNT))) + int NonCluster = 0; + while(kbts__GlyphIsValid(Storage, Glyph) && + ((Glyph->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_OTHER) || + (Glyph->SyllabicClass >= KBTS_INDIC_SYLLABIC_CLASS_COUNT))) { - ++OtherCount; + NonCluster = 1; + Glyph = Glyph->Next; } - if(OtherCount) - { - // Not an Indic syllable. - // Just pass it along. - Result.ClusterGlyphCount = OtherCount; - } - else + Result = Glyph; + + if(!NonCluster) { kbts_un ScanGlyphIndex = 0; kbts_un State = 0; kbts_un Broken = 1; kbts_un BrokenState = 0; + kbts_glyph *FirstGlyphs[3]; - while((ScanGlyphIndex < GlyphCount) && (State < KBTS_INDIC_SYLLABIC_STATE_COUNT)) + while(kbts__GlyphIsValid(Storage, Glyph) && + (State < KBTS_INDIC_SYLLABIC_STATE_COUNT)) { - kbts_glyph *Glyph = &Glyphs[ScanGlyphIndex]; kbts_un Class = Glyph->SyllabicClass; - if(KBTS_IN_SET(Class, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_RA)(KBTS_INDIC_SYLLABIC_CLASS_CONSONANT) - (KBTS_INDIC_SYLLABIC_CLASS_VOWEL)(KBTS_INDIC_SYLLABIC_CLASS_DOTTED_CIRCLE) - (KBTS_INDIC_SYLLABIC_CLASS_PLACEHOLDER)(KBTS_INDIC_SYLLABIC_CLASS_SYMBOL)))) + if(KBTS__IN_SET(Class, KBTS__SET32((KBTS_INDIC_SYLLABIC_CLASS_RA) + (KBTS_INDIC_SYLLABIC_CLASS_CONSONANT) + (KBTS_INDIC_SYLLABIC_CLASS_VOWEL) + (KBTS_INDIC_SYLLABIC_CLASS_DOTTED_CIRCLE) + (KBTS_INDIC_SYLLABIC_CLASS_PLACEHOLDER) + (KBTS_INDIC_SYLLABIC_CLASS_SYMBOL)))) { Broken = 0; } BrokenState = (BrokenState << 1) | Broken; + if(ScanGlyphIndex < KBTS__ARRAY_LENGTH(FirstGlyphs)) + { + FirstGlyphs[ScanGlyphIndex] = Glyph; + } + State = kbts_IndicSyllabicTransition[Class][State]; State -= 1; // @Incomplete @Cleanup: Decrement every state by 1 in the transition table. + Glyph = Glyph->Next; ScanGlyphIndex += 1; } @@ -19962,6 +23111,12 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, ScanGlyphIndex -= State - KBTS_INDIC_SYLLABIC_STATE_COUNT; BrokenState >>= State - KBTS_INDIC_SYLLABIC_STATE_COUNT; + while(State > KBTS_INDIC_SYLLABIC_STATE_COUNT) + { + Glyph = Glyph->Prev; + State -= 1; + } + if(!ScanGlyphIndex) { // If we backtrack all the way to the beginning, still eat a character. @@ -19974,11 +23129,15 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, // _strongly_ recommends that shapers use the font's tables instead, ie. doing tentative lookups // with specific features. - kbts_gsub_frame *Frames = KBTS_POINTER_AFTER(kbts_gsub_frame, OpState); - kbts_glyph *OnePastLastSyllableGlyph = Glyphs + ScanGlyphIndex; + kbts__gsub_frame *Frames = kbts__PushArray(Scratchpad->Arena, kbts__gsub_frame, KBTS_LOOKUP_STACK_SIZE); + kbts_glyph *OnePastLastSyllableGlyph = Glyph; + kbts_glyph *FirstGlyph = FirstGlyphs[0]; + kbts_glyph *OneBeforeSyllableGlyph = FirstGlyph->Prev; - if((Config->Script == KBTS_SCRIPT_KANNADA) && (ScanGlyphIndex >= 3) && (Glyphs[0].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_RA) && - (Glyphs[1].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) && (Glyphs[2].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ)) + if((Config->Script == KBTS_SCRIPT_KANNADA) && (ScanGlyphIndex >= 3) && + (FirstGlyphs[0]->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_RA) && + (FirstGlyphs[1]->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) && + (FirstGlyphs[2]->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ)) { // In older versions of Unicode (~4.x, pre-2004), Ra-Virama-Zwj was recommended in Kannada // to communicate the intent of displaying (Ra + (next consonant as below-base form)). @@ -19986,42 +23145,63 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, // (next consonant as below-base form)) is Ra-Zwj-Virama. // Since Ra-Virama-Zwj is not a useful sequence that happens organically in Kannada, // we are free to transform it into Ra-Zwj-Virama here without losing information. - kbts_glyph Swap = Glyphs[1]; - Glyphs[1] = Glyphs[2]; - Glyphs[2] = Swap; + KBTS__DLLIST_SWAP(FirstGlyphs[1], FirstGlyphs[2]); + + // Also swap this, because this is used below for OnePastReph. + kbts_glyph *Swap = FirstGlyphs[1]; + FirstGlyphs[1] = FirstGlyphs[2]; + FirstGlyphs[2] = Swap; } kbts_glyph_flags RephFlags = KBTS_GLYPH_FLAG_RPHF; + kbts_glyph *OnePastReph = FirstGlyphs[0]; kbts_un OnePastRephIndex = 0; { // Reph tagging. // This first pass only figures out where the reph ends. // We delay updating glyph properties until we know whether the reph is the base or not. - kbts_glyph *First = &Glyphs[0]; - kbts_glyph *Second = &Glyphs[1]; - kbts_feature *Rphf = Config->Rphf; + kbts_glyph *Second = FirstGlyphs[1]; + kbts_glyph *Third = FirstGlyphs[2]; + kbts__feature *Rphf = Config->Rphf; switch(Config->IndicScriptProperties.RephEncoding) { - case KBTS_REPH_ENCODING_LOGICAL_REPHA: - if(First->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_REPHA) + case KBTS__REPH_ENCODING_LOGICAL_REPHA: + if(FirstGlyph->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_REPHA) { RephFlags = 0; OnePastRephIndex = 1; } break; - case KBTS_REPH_ENCODING_IMPLICIT: - if((ScanGlyphIndex >= 2) && (Second->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) && kbts_WouldSubstitute(ShapeState, LookupList, Frames, Rphf, 0, Glyphs, 2)) + case KBTS__REPH_ENCODING_IMPLICIT: + if((ScanGlyphIndex >= 2) && + (Second->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT)) { - OnePastRephIndex = 2; + kbts_glyph Scratch[2]; + Scratch[0] = *FirstGlyphs[0]; + Scratch[1] = *FirstGlyphs[1]; + + if(kbts__WouldSubstitute(Scratchpad, Config, Storage, LookupList, Frames, Rphf, 0, Scratch, 2)) + { + OnePastRephIndex = 2; + } } break; - case KBTS_REPH_ENCODING_EXPLICIT: - if((ScanGlyphIndex >= 3) && (Second->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) && (Glyphs[2].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ) && - kbts_WouldSubstitute(ShapeState, LookupList, Frames, Rphf, 0, Glyphs, 3)) + case KBTS__REPH_ENCODING_EXPLICIT: + if((ScanGlyphIndex >= 3) && + (Second->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) && + (Third->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ)) { - OnePastRephIndex = 3; + kbts_glyph Scratch[3]; + Scratch[0] = *FirstGlyphs[0]; + Scratch[1] = *FirstGlyphs[1]; + Scratch[2] = *FirstGlyphs[2]; + + if(kbts__WouldSubstitute(Scratchpad, Config, Storage, LookupList, Frames, Rphf, 0, Scratch, 3)) + { + OnePastRephIndex = 3; + } } break; } @@ -20029,29 +23209,29 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, // Extend the reph with suffixed joiners. if(OnePastRephIndex) { - while((OnePastRephIndex < ScanGlyphIndex) && KBTS_IN_SET(Glyphs[OnePastRephIndex].SyllabicClass, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_ZWJ)(KBTS_INDIC_SYLLABIC_CLASS_ZWNJ)))) + OnePastReph = FirstGlyphs[OnePastRephIndex - 1]->Next; + while(kbts__GlyphIsValid(Storage, OnePastReph) && + KBTS__IN_SET(OnePastReph->SyllabicClass, KBTS__SET32((KBTS_INDIC_SYLLABIC_CLASS_ZWJ) + (KBTS_INDIC_SYLLABIC_CLASS_ZWNJ)))) { - OnePastRephIndex += 1; + OnePastReph = OnePastReph->Next; } } } - kbts_feature *Pref = Config->Pref; - kbts_un BaseIndex = ScanGlyphIndex; - kbts_un LastConsonantIndex = 0; - kbts_syllabic_position LastConsonantPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; + kbts__feature *Pref = Config->Pref; + kbts_glyph *BaseGlyph = OnePastLastSyllableGlyph; + kbts_glyph *LastConsonant = 0; + kbts__syllabic_position LastConsonantPosition = KBTS__SYLLABIC_POSITION_SYLLABLE_BASE; if(Config->DottedCircle.Id && (BrokenState & 1)) { - // Insert a dotted circle after Reph. - for(kbts_un GlyphIndex = GlyphCount; GlyphIndex > OnePastRephIndex; --GlyphIndex) + BaseGlyph = kbts__InsertGlyphBefore(Storage, OnePastReph, &Config->DottedCircle); + if(!BaseGlyph) { - Glyphs[GlyphIndex] = Glyphs[GlyphIndex - 1]; + goto OutOfMemory; } - ScanGlyphIndex += 1; - Result.InsertedGlyphCount = 1; - Glyphs[OnePastRephIndex] = Config->DottedCircle; - BaseIndex = OnePastRephIndex; + BaseGlyph->UserIdOrCodepointIndex = OnePastReph->UserIdOrCodepointIndex; } else { @@ -20060,19 +23240,20 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, Scratch[0] = Config->Virama; Scratch[2] = Config->Virama; - kbts_feature *Locl = Config->Locl; - kbts_feature *Vatu = Config->Vatu; + kbts__feature *Locl = Config->Locl; + kbts__feature *Vatu = Config->Vatu; // pstf forms come last, then blwf. - kbts_feature *SectionFeature = Config->Pstf; - kbts_syllabic_position SectionPosition = KBTS_SYLLABIC_POSITION_POSTBASE_CONSONANT; + kbts__feature *SectionFeature = Config->Pstf; + kbts__syllabic_position SectionPosition = KBTS__SYLLABIC_POSITION_POSTBASE_CONSONANT; // If we see no consonant/matra, then surely we want to attach to the base. - kbts_syllabic_position SyllabicPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; + kbts__syllabic_position SyllabicPosition = KBTS__SYLLABIC_POSITION_SYLLABLE_BASE; kbts_indic_syllabic_class LastClass = KBTS_INDIC_SYLLABIC_CLASS_COUNT; - for(kbts_un GlyphIndex = ScanGlyphIndex; GlyphIndex > OnePastRephIndex; --GlyphIndex) + for(Glyph = OnePastLastSyllableGlyph->Prev; + ; + Glyph = Glyph->Prev) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex - 1]; kbts_indic_syllabic_class Class = Glyph->SyllabicClass; switch(Class) @@ -20082,7 +23263,7 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, case KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_WITH_STACKER: case KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_MEDIAL: // Apply locl first. - Scratch[1] = kbts_Substitute1(ShapeState, LookupList, Locl, KBTS_SKIP_FLAG_ZWNJ | KBTS_SKIP_FLAG_ZWJ, Glyph); + Scratch[1] = kbts__Substitute1(Scratchpad, Config, Storage, LookupList, Locl, KBTS__SKIP_FLAG_ZWNJ | KBTS__SKIP_FLAG_ZWJ, Glyph); // Microsoft says to "move backwards until a consonant is found that does not have a below-base // or post-base form". @@ -20091,26 +23272,29 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, // syllable base. // So, as we sweep backward, set the base index on consonants unconditionally. // @Robustness: Do we want to update Base only if we do not match Pref/Vatu? - BaseIndex = GlyphIndex - 1; + BaseGlyph = Glyph; - if(kbts_WouldSubstitute(ShapeState, LookupList, Frames, Pref, 0, Scratch, 2) || kbts_WouldSubstitute(ShapeState, LookupList, Frames, Pref, 0, Scratch + 1, 2) || - kbts_WouldSubstitute(ShapeState, LookupList, Frames, Vatu, 0, Scratch, 2) || kbts_WouldSubstitute(ShapeState, LookupList, Frames, Vatu, 0, Scratch + 1, 2)) + if(kbts__WouldSubstitute(Scratchpad, Config, Storage, LookupList, Frames, Pref, 0, Scratch, 2) || + kbts__WouldSubstitute(Scratchpad, Config, Storage, LookupList, Frames, Pref, 0, Scratch + 1, 2) || + kbts__WouldSubstitute(Scratchpad, Config, Storage, LookupList, Frames, Vatu, 0, Scratch, 2) || + kbts__WouldSubstitute(Scratchpad, Config, Storage, LookupList, Frames, Vatu, 0, Scratch + 1, 2)) { - SyllabicPosition = KBTS_SYLLABIC_POSITION_POSTBASE_CONSONANT; + SyllabicPosition = KBTS__SYLLABIC_POSITION_POSTBASE_CONSONANT; } else { for(;;) { - if(kbts_WouldSubstitute(ShapeState, LookupList, Frames, SectionFeature, 0, Scratch, 2) || kbts_WouldSubstitute(ShapeState, LookupList, Frames, SectionFeature, 0, Scratch + 1, 2)) + if(kbts__WouldSubstitute(Scratchpad, Config, Storage, LookupList, Frames, SectionFeature, 0, Scratch, 2) || + kbts__WouldSubstitute(Scratchpad, Config, Storage, LookupList, Frames, SectionFeature, 0, Scratch + 1, 2)) { SyllabicPosition = SectionPosition; break; } - else if(SectionPosition == KBTS_SYLLABIC_POSITION_POSTBASE_CONSONANT) + else if(SectionPosition == KBTS__SYLLABIC_POSITION_POSTBASE_CONSONANT) { SectionFeature = Config->Blwf; - SectionPosition = KBTS_SYLLABIC_POSITION_BELOWBASE_CONSONANT; + SectionPosition = KBTS__SYLLABIC_POSITION_BELOWBASE_CONSONANT; // Retry with Blwf. } else @@ -20120,9 +23304,9 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, } } - if(!LastConsonantIndex) + if(!LastConsonant) { - LastConsonantIndex = GlyphIndex - 1; + LastConsonant = Glyph; LastConsonantPosition = SyllabicPosition; } @@ -20132,7 +23316,7 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, case KBTS_INDIC_SYLLABIC_CLASS_VOWEL: case KBTS_INDIC_SYLLABIC_CLASS_PLACEHOLDER: case KBTS_INDIC_SYLLABIC_CLASS_DOTTED_CIRCLE: - BaseIndex = GlyphIndex - 1; + BaseGlyph = Glyph; goto DoneScanningForBase; break; @@ -20152,67 +23336,72 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, } LastClass = Class; + if(Glyph == OnePastReph) + { + break; + } } DoneScanningForBase:; } // Fix reph position now. - if(OnePastRephIndex) + if(OnePastReph != FirstGlyph) { - kbts_syllabic_position RephPosition = KBTS_SYLLABIC_POSITION_RA_TO_BECOME_REPH; + kbts__syllabic_position RephPosition = KBTS__SYLLABIC_POSITION_RA_TO_BECOME_REPH; kbts_glyph_flags Flags = RephFlags; - kbts_un OnePastLast = OnePastRephIndex; - if(BaseIndex == ScanGlyphIndex) + kbts_un RephGlyphCount = OnePastRephIndex; + if(BaseGlyph == OnePastLastSyllableGlyph) { - RephPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; + RephPosition = KBTS__SYLLABIC_POSITION_SYLLABLE_BASE; Flags = 0; - BaseIndex = 0; - OnePastRephIndex = 0; + BaseGlyph = OnePastReph = FirstGlyph; } - KBTS_FOR(GlyphIndex, 0, OnePastLast) + KBTS__FOR(GlyphIndex, 0, RephGlyphCount) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex]; - Glyph->SyllabicPosition = RephPosition; - Glyph->Flags |= Flags; + kbts_glyph *RephGlyph = FirstGlyphs[GlyphIndex]; + RephGlyph->SyllabicPosition = RephPosition; + RephGlyph->Flags |= Flags; } } - if(BaseIndex < ScanGlyphIndex) + if(BaseGlyph != OnePastLastSyllableGlyph) { - Glyphs[BaseIndex].SyllabicPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; + BaseGlyph->SyllabicPosition = KBTS__SYLLABIC_POSITION_SYLLABLE_BASE; - if(!LastConsonantIndex) + if(!LastConsonant) { - LastConsonantIndex = BaseIndex; + LastConsonant = BaseGlyph; // LastConsonantPosition is already set to SYLLABLE_BASE. } } { // Reorder marks. // @Cleanup @Speed: Supposedly, NORMALIZE already does this... - kbts_glyph *ReorderGlyph = Glyphs + ScanGlyphIndex - 1; - while(ReorderGlyph >= Glyphs) + kbts_glyph *ReorderGlyph = OnePastLastSyllableGlyph->Prev; + while(ReorderGlyph != OneBeforeSyllableGlyph) { if(ReorderGlyph->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_NUKTA) { - kbts_glyph *Prev = ReorderGlyph - 1; + kbts_glyph *Prev = ReorderGlyph->Prev; - while((Prev >= Glyphs) && KBTS_IN_SET(Prev->SyllabicClass, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_HALANT)(KBTS_INDIC_SYLLABIC_CLASS_VEDIC_SIGN)))) + while((Prev != OneBeforeSyllableGlyph) && + KBTS__IN_SET(Prev->SyllabicClass, KBTS__SET32((KBTS_INDIC_SYLLABIC_CLASS_HALANT) + (KBTS_INDIC_SYLLABIC_CLASS_VEDIC_SIGN)))) { - kbts_glyph Swap = *Prev; - *Prev = Prev[1]; - Prev[1] = Swap; + kbts_glyph *NextPrev = Prev->Prev; - Prev -= 1; + KBTS__DLLIST_SWAP(Prev, Prev->Next); + + Prev = NextPrev; } ReorderGlyph = Prev; } else { - ReorderGlyph -= 1; + ReorderGlyph = ReorderGlyph->Prev; } } } @@ -20222,12 +23411,13 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, // We want to bake this ordering into our sort, so we increase our syllabic position bits // and sub-order matras with the low nibble. (There should only be 4 matras tops, anyway.) kbts_un LeftMatraCount = 0; - KBTS_FOR(GlyphIndex, 0, ScanGlyphIndex) + for(Glyph = OneBeforeSyllableGlyph->Next; + Glyph != OnePastLastSyllableGlyph; + Glyph = Glyph->Next) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex]; Glyph->SyllabicPosition <<= 4; - if(Glyph->SyllabicPosition == (KBTS_SYLLABIC_POSITION_PREBASE_MATRA << 4)) + if(Glyph->SyllabicPosition == (KBTS__SYLLABIC_POSITION_PREBASE_MATRA << 4)) { Glyph->SyllabicPosition += (15 - LeftMatraCount++) & 0xF; } @@ -20241,20 +23431,36 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, // a pre-base+base part (right attachments), a post-base consonant part (left attachments), and // a post-consonant part (right attachments again). // This part handles right attachments. Left attachments were handled in the base syllable search. - kbts_attach_state States[2] = { - {KBTS_SYLLABIC_POSITION_RA_TO_BECOME_REPH << 4, KBTS_SYLLABIC_POSITION_RA_TO_BECOME_REPH << 4, KBTS_INDIC_SYLLABIC_CLASS_COUNT, OnePastRephIndex, BaseIndex}, - {(kbts_u8)(LastConsonantPosition << 4), (kbts_u8)(LastConsonantPosition << 4), KBTS_INDIC_SYLLABIC_CLASS_COUNT, LastConsonantIndex + 1, ScanGlyphIndex}, - }; - kbts_un Iterations = KBTS_MAX(States[0].OnePastLast - States[0].Start, States[1].OnePastLast - States[1].Start); - KBTS_FOR(GlyphIndex, 0, Iterations) - { - KBTS_FOR(StateIndex, 0, KBTS_ARRAY_LENGTH(States)) + kbts__attach_state States[2] = { { - kbts_attach_state *Attach = &States[StateIndex]; + KBTS__SYLLABIC_POSITION_RA_TO_BECOME_REPH << 4, + KBTS__SYLLABIC_POSITION_RA_TO_BECOME_REPH << 4, + KBTS_INDIC_SYLLABIC_CLASS_COUNT, + OnePastReph, + BaseGlyph, + OnePastReph, + }, + { + (kbts_u8)(LastConsonantPosition << 4), + (kbts_u8)(LastConsonantPosition << 4), + KBTS_INDIC_SYLLABIC_CLASS_COUNT, + LastConsonant ? LastConsonant->Next : OnePastLastSyllableGlyph, + OnePastLastSyllableGlyph, + LastConsonant ? LastConsonant->Next : OnePastLastSyllableGlyph, + }, + }; + for(;;) + { + int Done = 1; - if((Attach->Start + GlyphIndex) < Attach->OnePastLast) + KBTS__FOR(StateIndex, 0, KBTS__ARRAY_LENGTH(States)) + { + kbts__attach_state *Attach = &States[StateIndex]; + + if(Attach->At != Attach->OnePastLast) { - kbts_glyph *Glyph = &Glyphs[Attach->Start + GlyphIndex]; + Glyph = Attach->At; + kbts_indic_syllabic_class Class = Glyph->SyllabicClass; switch(Class) { @@ -20263,8 +23469,8 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, case KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_WITH_STACKER: case KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_MEDIAL: // This only happens in the pre-base state. - Glyph->SyllabicPosition = (KBTS_SYLLABIC_POSITION_PREBASE_CONSONANT << 4); - Attach->CurrentPosition = (KBTS_SYLLABIC_POSITION_PREBASE_CONSONANT << 4); + Glyph->SyllabicPosition = (KBTS__SYLLABIC_POSITION_PREBASE_CONSONANT << 4); + Attach->CurrentPosition = (KBTS__SYLLABIC_POSITION_PREBASE_CONSONANT << 4); break; case KBTS_INDIC_SYLLABIC_CLASS_MATRA_POST: @@ -20274,18 +23480,18 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, // and not to the consonant. if(Attach->LastClass == KBTS_INDIC_SYLLABIC_CLASS_SYLLABLE_MODIFIER) { - Glyph[-1].SyllabicPosition = Glyph->SyllabicPosition; + Glyph->Prev->SyllabicPosition = Glyph->SyllabicPosition; } case KBTS_INDIC_SYLLABIC_CLASS_MATRA: Attach->CurrentPosition = Glyph->SyllabicPosition; - if((Attach->CurrentPosition >> 4) != KBTS_SYLLABIC_POSITION_PREBASE_MATRA) + if((Attach->CurrentPosition >> 4) != KBTS__SYLLABIC_POSITION_PREBASE_MATRA) { Attach->LastPositionThatWasNotPreBaseMatra = Attach->CurrentPosition; } break; case KBTS_INDIC_SYLLABIC_CLASS_HALANT: - if((Attach->CurrentPosition >> 4) == KBTS_SYLLABIC_POSITION_PREBASE_MATRA) + if((Attach->CurrentPosition >> 4) == KBTS__SYLLABIC_POSITION_PREBASE_MATRA) { // Uniscribe does not reorder halants with pre-base matras. Not sure why. Glyph->SyllabicPosition = Attach->LastPositionThatWasNotPreBaseMatra; @@ -20298,48 +23504,55 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, Glyph->SyllabicPosition = Attach->CurrentPosition; break; } + Attach->LastClass = Class; + Attach->At = Glyph->Next; + Done = 0; } } + + if(Done) + { + break; + } } } { // Do the sort! // NOTE: It is important that we sort _now_, because some characters will be reordered across the base from // where they started, which can change which features will apply to them. - KBTS_FOR(Iteration, 0, ScanGlyphIndex) + KBTS__DLLIST_SORT(OneBeforeSyllableGlyph->Next, OnePastLastSyllableGlyph, SyllabicPosition); + +#ifdef KBTS_SANITY_CHECK { - KBTS_FOR(GlyphIndex, 1, ScanGlyphIndex) + kbts_glyph *Glyph0 = OneBeforeSyllableGlyph->Next; + if(Glyph0 != OnePastLastSyllableGlyph) { - kbts_glyph *Left = &Glyphs[GlyphIndex - 1]; - kbts_glyph *Right = &Glyphs[GlyphIndex]; - - if(Left->SyllabicPosition > Right->SyllabicPosition) + for(kbts_glyph *Glyph1 = Glyph0->Next; + kbts__GlyphIsValid(C, Glyph1); + Glyph1 = Glyph1->Next) { - kbts_glyph Swap = *Left; - *Left = *Right; - *Right = Swap; - - // Make sure we don't lose track of the base... - if(GlyphIndex == BaseIndex) + if(Glyph1 != OnePastLastSyllableGlyph) { - BaseIndex = GlyphIndex - 1; + KBTS_ASSERT(Glyph0->SyllabicPosition <= Glyph1->SyllabicPosition); } - else if((GlyphIndex - 1) == BaseIndex) + else { - BaseIndex = GlyphIndex; + break; } } } } + #endif } - { // @Temporary @Cleanup - // Revert our syllabic position shift for now. - KBTS_FOR(GlyphIndex, 0, ScanGlyphIndex) - { - Glyphs[GlyphIndex].SyllabicPosition >>= 4; - } + // @Temporary @Cleanup + // Revert our syllabic position shift for now. + for(Glyph = OneBeforeSyllableGlyph->Next; + Glyph != OnePastLastSyllableGlyph; + Glyph = Glyph->Next) + { + Glyph->SyllabicPosition >>= 4; } // This is what Harfbuzz does: @@ -20359,9 +23572,10 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, } kbts_indic_syllabic_class LastClass = 0; - for(kbts_un GlyphIndex = BaseIndex; GlyphIndex > 0; --GlyphIndex) + for(Glyph = BaseGlyph->Prev; + Glyph != OneBeforeSyllableGlyph; + Glyph = Glyph->Prev) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex - 1]; kbts_glyph_flags Flags = BaseFlags; if(LastClass != KBTS_INDIC_SYLLABIC_CLASS_ZWNJ) @@ -20375,17 +23589,17 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, } // All post-base glyphs get BLWF, ABVF, PSTF. Some get PREF. - kbts_glyph Scratch[2]; Scratch[0] = Scratch[1] = KBTS_ZERO_TYPE(kbts_glyph); + kbts_glyph Scratch[2]; Scratch[0] = Scratch[1] = KBTS__ZERO_TYPE(kbts_glyph); kbts_glyph *LastGlyph; LastGlyph = 0; - KBTS_FOR(GlyphIndex, BaseIndex + 1, ScanGlyphIndex) + for(Glyph = BaseGlyph->Next; + Glyph != OnePastLastSyllableGlyph; + Glyph = Glyph->Next) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex]; - // It is tempting to apply PREF to every glyph after the base. // However, the PREF flag is also used to find the syllable base again in EndCluster, // so we have to be precise with it. Scratch[1] = *Glyph; - if(kbts_WouldSubstitute(ShapeState, LookupList, Frames, Pref, 0, Scratch, 2)) + if(kbts__WouldSubstitute(Scratchpad, Config, Storage, LookupList, Frames, Pref, 0, Scratch, 2)) { LastGlyph->Flags |= KBTS_GLYPH_FLAG_PREF; Glyph->Flags |= KBTS_GLYPH_FLAG_PREF; @@ -20398,238 +23612,270 @@ static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, // The base only inherits stuff after it, up to whatever and not including what was grabbed by // post-base consonants. - if(BaseIndex < ScanGlyphIndex) + if(BaseGlyph != OnePastLastSyllableGlyph) { - Glyphs[BaseIndex].SyllabicPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; + BaseGlyph->SyllabicPosition = KBTS__SYLLABIC_POSITION_SYLLABLE_BASE; - kbts_u64 Classes = (1ull << KBTS_INDIC_SYLLABIC_CLASS_HALANT) | (1ull << KBTS_INDIC_SYLLABIC_CLASS_VEDIC_SIGN) | (1ull << KBTS_INDIC_SYLLABIC_CLASS_NUKTA) | - (1ull << KBTS_INDIC_SYLLABIC_CLASS_ZWJ) | (1ull << KBTS_INDIC_SYLLABIC_CLASS_ZWNJ); - kbts_glyph *Next = &Glyphs[BaseIndex + 1]; - while((Next < OnePastLastSyllableGlyph) && (Next->SyllabicPosition < KBTS_SYLLABIC_POSITION_SYLLABLE_BASE) && ((1ull << Next->SyllabicClass) & Classes)) + kbts_u64 Classes = (1ull << KBTS_INDIC_SYLLABIC_CLASS_HALANT) | + (1ull << KBTS_INDIC_SYLLABIC_CLASS_VEDIC_SIGN) | + (1ull << KBTS_INDIC_SYLLABIC_CLASS_NUKTA) | + (1ull << KBTS_INDIC_SYLLABIC_CLASS_ZWJ) | + (1ull << KBTS_INDIC_SYLLABIC_CLASS_ZWNJ); + + kbts_glyph *Next = BaseGlyph->Next; + while((Next != OnePastLastSyllableGlyph) && + (Next->SyllabicPosition < KBTS__SYLLABIC_POSITION_SYLLABLE_BASE) && + ((1ull << Next->SyllabicClass) & Classes)) { - Next->SyllabicPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; + Next->SyllabicPosition = KBTS__SYLLABIC_POSITION_SYLLABLE_BASE; - Next += 1; + Next = Next->Next; } } - Result.ClusterGlyphCount = ScanGlyphIndex; - ShapeState->RealCluster = 1; + Result = OnePastLastSyllableGlyph; + Scratchpad->RealCluster = 1; } - } - break; + } break; case KBTS_SHAPER_USE: { - kbts_un OtherCount = 0; - while((OtherCount < GlyphCount) && ((Glyphs[OtherCount].UseClass == KBTS_USE_SYLLABIC_CLASS_OTHER) || - (Glyphs[OtherCount].UseClass == KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_MOD_POST))) + int NonCluster = 0; + while(kbts__GlyphIsValid(Storage, Glyph) && + ((Glyph->UseClass == KBTS_USE_SYLLABIC_CLASS_OTHER) || + (Glyph->UseClass == KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_MOD_POST))) { - OtherCount += 1; + NonCluster = 1; + + Glyph = Glyph->Next; } - if(OtherCount) - { - Result.ClusterGlyphCount = OtherCount; - } - else + if(!NonCluster) { // Parse a real cluster. kbts_u8 State = 0; - kbts_un ScanGlyphIndex = 0; - while((ScanGlyphIndex < GlyphCount) && (State < KBTS_USE_STATE_s0)) + kbts_glyph *StartGlyph = Glyph; + while(kbts__GlyphIsValid(Storage, Glyph) && + (State < KBTS_USE_STATE_s0)) { - kbts_glyph *Glyph = &Glyphs[ScanGlyphIndex++]; State = kbts_UseTransition[Glyph->UseClass][State]; // @Incomplete: Remove this!!! State -= 1; + Glyph = Glyph->Next; } if(State >= KBTS_USE_STATE_s0) { - ScanGlyphIndex -= 1; + Glyph = Glyph->Prev; } - if((ScanGlyphIndex < GlyphCount) && (Glyphs[ScanGlyphIndex].UseClass == KBTS_USE_SYLLABIC_CLASS_ZWNJ)) + if(kbts__GlyphIsValid(Storage, Glyph) && + (Glyph->UseClass == KBTS_USE_SYLLABIC_CLASS_ZWNJ)) { - ScanGlyphIndex += 1; + Glyph = Glyph->Next; + } + if(Glyph == StartGlyph) + { + Glyph = Glyph->Next; } - if(!ScanGlyphIndex) ScanGlyphIndex = 1; - Result.ClusterGlyphCount = ScanGlyphIndex; - ShapeState->RealCluster = 1; + Scratchpad->RealCluster = 1; } + + Result = Glyph; } break; case KBTS_SHAPER_KHMER: { - kbts_un OtherCount = 0; - while((OtherCount < GlyphCount) && ((Glyphs[OtherCount].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_OTHER) || - (Glyphs[OtherCount].SyllabicClass >= KBTS_KHMER_SYLLABIC_CLASS_COUNT))) + int NonCluster = 0; + while(kbts__GlyphIsValid(Storage, Glyph) && + ((Glyph->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_OTHER) || + (Glyph->SyllabicClass >= KBTS_KHMER_SYLLABIC_CLASS_COUNT))) { - OtherCount += 1; + Glyph = Glyph->Next; + NonCluster = 1; } - if(OtherCount) - { - Result.ClusterGlyphCount = OtherCount; - } - else + Result = Glyph; + + if(!NonCluster) { kbts_u8 State = 0; - kbts_un ScanGlyphIndex = 0; - while((ScanGlyphIndex < GlyphCount) && (State < KBTS_KHMER_SYLLABIC_STATE_COUNT)) + kbts_glyph *FirstGlyph = Glyph; + kbts_glyph *OneBeforeSyllableGlyph = Glyph->Prev; + + while(kbts__GlyphIsValid(Storage, Glyph) && + (State < KBTS_KHMER_SYLLABIC_STATE_COUNT)) { - kbts_glyph *Glyph = &Glyphs[ScanGlyphIndex++]; kbts_indic_syllabic_class Class = Glyph->SyllabicClass; State = kbts_KhmerSyllabicTransition[Class][State]; // @Incomplete: Remove this! State -= 1; + Glyph = Glyph->Next; } if(State >= KBTS_KHMER_SYLLABIC_STATE_COUNT) { - ScanGlyphIndex -= 1; + Glyph = Glyph->Prev; } - if(!ScanGlyphIndex) ScanGlyphIndex = 1; + if(Glyph == FirstGlyph) + { + Glyph = Glyph->Next; + } + + kbts_glyph *OnePastLastSyllableGlyph = Glyph; if(Config->DottedCircle.Id && - !KBTS_IN_SET64(Glyphs->SyllabicClass, KBTS_SET64((KBTS_INDIC_SYLLABIC_CLASS_CONSONANT)(KBTS_INDIC_SYLLABIC_CLASS_RA) - (KBTS_INDIC_SYLLABIC_CLASS_VOWEL)(KBTS_INDIC_SYLLABIC_CLASS_DOTTED_CIRCLE) - (KBTS_INDIC_SYLLABIC_CLASS_PLACEHOLDER)))) + !KBTS__IN_SET64(FirstGlyph->SyllabicClass, KBTS__SET64((KBTS_INDIC_SYLLABIC_CLASS_CONSONANT) + (KBTS_INDIC_SYLLABIC_CLASS_RA) + (KBTS_INDIC_SYLLABIC_CLASS_VOWEL) + (KBTS_INDIC_SYLLABIC_CLASS_DOTTED_CIRCLE) + (KBTS_INDIC_SYLLABIC_CLASS_PLACEHOLDER)))) { // Broken cluster. // Insert a dotted circle. - for(kbts_un GlyphIndex = GlyphCount; GlyphIndex; --GlyphIndex) + kbts_glyph *NewFirstGlyph = kbts__InsertGlyphBefore(Storage, FirstGlyph, &Config->DottedCircle); + if(!NewFirstGlyph) { - Glyphs[GlyphIndex] = Glyphs[GlyphIndex - 1]; + goto OutOfMemory; } - ScanGlyphIndex += 1; - Result.InsertedGlyphCount = 1; - Glyphs[0] = Config->DottedCircle; + + NewFirstGlyph->UserIdOrCodepointIndex = FirstGlyph->UserIdOrCodepointIndex; + FirstGlyph = NewFirstGlyph; } // In Khmer, the first glyph is always the base. - kbts_glyph PreBaseGlyphs[3]; + kbts_glyph *PreBaseGlyphs[3]; int SawHalantRa = 0; kbts_un PreBaseGlyphCount = 0; kbts_un Classes = 0; - kbts_un WriteCursor = ScanGlyphIndex - 1; - for(kbts_un GlyphIndex = ScanGlyphIndex; GlyphIndex; --GlyphIndex) + + kbts_u32 AddFlags = KBTS_GLYPH_FLAG_ABVF | KBTS_GLYPH_FLAG_BLWF | KBTS_GLYPH_FLAG_PSTF; + + kbts_glyph *LastGlyph = OnePastLastSyllableGlyph; + for(Glyph = OnePastLastSyllableGlyph->Prev; + Glyph != OneBeforeSyllableGlyph; + Glyph = Glyph->Prev) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex - 1]; kbts_indic_syllabic_class Class = Glyph->SyllabicClass; - if(GlyphIndex > 1) {Glyph->Flags |= KBTS_GLYPH_FLAG_ABVF | KBTS_GLYPH_FLAG_BLWF | KBTS_GLYPH_FLAG_PSTF;} + if(Glyph == FirstGlyph) + { + AddFlags = 0; + } + + Glyph->Flags |= AddFlags; Classes = ((Classes << 8) | Class) & 0xFFFF; if(Class == KBTS_INDIC_SYLLABIC_CLASS_VOWEL_PRE) { - PreBaseGlyphs[PreBaseGlyphCount++] = *Glyph; + PreBaseGlyphs[PreBaseGlyphCount++] = Glyph; } else if(!SawHalantRa && (Classes == (KBTS_INDIC_SYLLABIC_CLASS_HALANT | (KBTS_INDIC_SYLLABIC_CLASS_RA << 8)))) { - kbts_glyph *Ra = &Glyphs[GlyphIndex]; Glyph->Flags |= KBTS_GLYPH_FLAG_PREF; - Ra->Flags |= KBTS_GLYPH_FLAG_PREF; + LastGlyph->Flags |= KBTS_GLYPH_FLAG_PREF; + + PreBaseGlyphs[PreBaseGlyphCount++] = Glyph; + PreBaseGlyphs[PreBaseGlyphCount++] = LastGlyph; - PreBaseGlyphs[PreBaseGlyphCount++] = *Glyph; - PreBaseGlyphs[PreBaseGlyphCount++] = *Ra; - WriteCursor += 1; // Cancel the Ra write. // All of the glyphs written so far need to be flagged with cfar. - KBTS_FOR(CfarGlyphIndex, WriteCursor, ScanGlyphIndex) + // @Speed: Detect the Halant-Ra sequence in the FSM loop. + for(kbts_glyph *PostRaGlyph = LastGlyph->Next; + PostRaGlyph != OnePastLastSyllableGlyph; + PostRaGlyph = PostRaGlyph->Next) { - Glyphs[CfarGlyphIndex].Flags |= KBTS_GLYPH_FLAG_CFAR; + PostRaGlyph->Flags |= KBTS_GLYPH_FLAG_CFAR; } + SawHalantRa = 1; } - else - { - Glyphs[WriteCursor--] = *Glyph; - } + + LastGlyph = Glyph; } - KBTS_FOR(PreBaseGlyphIndex, 0, PreBaseGlyphCount) + while(PreBaseGlyphCount) { - Glyphs[PreBaseGlyphIndex] = PreBaseGlyphs[PreBaseGlyphIndex]; + kbts_glyph *PreBaseGlyph = PreBaseGlyphs[--PreBaseGlyphCount]; + KBTS__DLLIST_REMOVE(PreBaseGlyph); + PreBaseGlyph->Prev = OneBeforeSyllableGlyph; + PreBaseGlyph->Next = OneBeforeSyllableGlyph->Next; + PreBaseGlyph->Prev->Next = PreBaseGlyph->Next->Prev = PreBaseGlyph; } - Result.ClusterGlyphCount = ScanGlyphIndex; + Result = OnePastLastSyllableGlyph; } } break; case KBTS_SHAPER_MYANMAR: { - kbts_un OtherCount = 0; - while((OtherCount < GlyphCount) && ((Glyphs[OtherCount].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_OTHER) || - (Glyphs[OtherCount].SyllabicClass >= KBTS_MYANMAR_SYLLABIC_CLASS_COUNT))) + int NonCluster = 0; + while(kbts__GlyphIsValid(Storage, Glyph) && + ((Glyph->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_OTHER) || + (Glyph->SyllabicClass >= KBTS_MYANMAR_SYLLABIC_CLASS_COUNT))) { - OtherCount += 1; + NonCluster = 1; } - if(OtherCount) - { - Result.ClusterGlyphCount = OtherCount; - } - else + if(!NonCluster) { kbts_u8 State = 0; - kbts_un ScanGlyphIndex = 0; - while((ScanGlyphIndex < GlyphCount) && (State < KBTS_MYANMAR_SYLLABIC_STATE_COUNT)) + kbts_glyph *FirstGlyph = Glyph; + while(kbts__GlyphIsValid(Storage, Glyph) && + (State < KBTS_MYANMAR_SYLLABIC_STATE_COUNT)) { - kbts_glyph *Glyph = &Glyphs[ScanGlyphIndex++]; kbts_indic_syllabic_class Class = Glyph->SyllabicClass; State = kbts_MyanmarSyllabicTransition[Class][State]; // @Incomplete: Remove this! State -= 1; + + Glyph = Glyph->Next; } if(State >= KBTS_MYANMAR_SYLLABIC_STATE_COUNT) { - ScanGlyphIndex -= 1; + Glyph = Glyph->Prev; + } + if(Glyph == FirstGlyph) + { + Glyph = Glyph->Next; } - if(!ScanGlyphIndex) ScanGlyphIndex = 1; - ShapeState->RealCluster = 1; - Result.ClusterGlyphCount = ScanGlyphIndex; + Scratchpad->RealCluster = 1; } + + Result = Glyph; } break; } + if(0) + { + OutOfMemory:; + Scratchpad->Error = KBTS_SHAPE_ERROR_OUT_OF_MEMORY; + } + + kbts__EndLifetime(&Lifetime); return Result; } -typedef struct kbts_end_cluster_result +static void kbts__EndCluster(kbts__shape_scratchpad *Scratchpad, kbts_shape_config *Config, kbts_glyph_storage *Storage) { - int InsertDottedCircle; - kbts_un DottedCircleIndex; -} kbts_end_cluster_result; - -static kbts_end_cluster_result kbts_EndCluster(kbts_shape_state *ShapeState, kbts_glyph_array *Cluster) -{ - kbts_end_cluster_result Result = KBTS_ZERO; - kbts_shape_config *Config = ShapeState->Config; - kbts_glyph *Glyphs = Cluster->Glyphs; - kbts_un GlyphCount = Cluster->Count; - switch(Config->Shaper) { case KBTS_SHAPER_INDIC: - if(GlyphCount > 1) + if(kbts__GlyphIsValid(Storage, Storage->GlyphSentinel.Next)) { // Final syllable reordering. // We are just copying Harfbuzz here, because I've read all the documentation I can and, frankly, I have no idea. - kbts_feature *Pref = Config->Pref; + kbts__feature *Pref = Config->Pref; kbts_u32 ViramaId = Config->Virama.Id; - KBTS_FOR(GlyphIndex, 0, GlyphCount) + KBTS__FOR_GLYPH(Storage, Glyph) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex]; - // Harfbuzz tests for (ligated | multiplied) here. // I don't really get why, because, supposedly, all viramas should be // classified as halants regardless. @@ -20646,44 +23892,48 @@ static kbts_end_cluster_result kbts_EndCluster(kbts_shape_state *ShapeState, kbt } // Locate the syllable base. - kbts_un BaseIndex = GlyphCount; + kbts_glyph *BaseGlyph = (kbts_glyph *)&Storage->GlyphSentinel; { - kbts_un AfterPreBaseIndex = 0; - while((AfterPreBaseIndex < GlyphCount) && (Glyphs[AfterPreBaseIndex].SyllabicPosition < KBTS_SYLLABIC_POSITION_SYLLABLE_BASE)) + kbts_glyph *AfterPreBase = Storage->GlyphSentinel.Next; + while(kbts__GlyphIsValid(Storage, AfterPreBase) && + (AfterPreBase->SyllabicPosition < KBTS__SYLLABIC_POSITION_SYLLABLE_BASE)) { - ++AfterPreBaseIndex; + AfterPreBase = AfterPreBase->Next; } - if(AfterPreBaseIndex < GlyphCount) + if(kbts__GlyphIsValid(Storage, AfterPreBase)) { - BaseIndex = AfterPreBaseIndex; + BaseGlyph = AfterPreBase; - if(Pref && ((AfterPreBaseIndex + 1) < GlyphCount)) + if(Pref && kbts__GlyphIsValid(Storage, AfterPreBase->Next)) { // If we find a pre-base-reordering ra, then the base is probably right after it! - kbts_un At = AfterPreBaseIndex + 1; - while((At < GlyphCount) && !(Glyphs[At].Flags & KBTS_GLYPH_FLAG_PREF)) + kbts_glyph *AtGlyph = AfterPreBase->Next; + while(kbts__GlyphIsValid(Storage, AtGlyph) && + !(AtGlyph->Flags & KBTS_GLYPH_FLAG_PREF)) { - ++At; + AtGlyph = AtGlyph->Next; } // If we are not a consonant, then we are attached to a consonant. // If we are a pref-able consonant, but we did not form a pref, then we should be right after the base. // Either way, we are very close to the base. - kbts_glyph *Prefable = &Glyphs[At]; - if((At < GlyphCount) && - (!(Prefable->Flags & KBTS_GLYPH_FLAG_GENERATED_BY_GSUB) || !(Prefable->Flags & KBTS_GLYPH_FLAG_LIGATURE) || (Prefable->Flags & KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION))) + kbts_glyph *Prefable = AtGlyph; // Read like "pref-able". :) + if(kbts__GlyphIsValid(Storage, Prefable) && + (!(Prefable->Flags & KBTS_GLYPH_FLAG_GENERATED_BY_GSUB) || + !(Prefable->Flags & KBTS_GLYPH_FLAG_LIGATURE) || + (Prefable->Flags & KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION))) { - while((At < GlyphCount) && (Prefable->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT)) + while(kbts__GlyphIsValid(Storage, Prefable) && + (Prefable->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT)) { - ++At; - ++Prefable; + Prefable = Prefable->Next; } - if(At < GlyphCount) + if(kbts__GlyphIsValid(Storage, Prefable)) { - Prefable->SyllabicPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; - BaseIndex = At; + Prefable->SyllabicPosition = KBTS__SYLLABIC_POSITION_SYLLABLE_BASE; + BaseGlyph = Prefable; // Fall through to the Malayalam test. } } @@ -20694,35 +23944,40 @@ static kbts_end_cluster_result kbts_EndCluster(kbts_shape_state *ShapeState, kbt // In Malayalam, the base is after below-base forms. // (We actually just give all below-base forms the base pos.) // @Speed: This would be way simpler with a null sentinel at the end of Glyphs! - kbts_un At = BaseIndex + 1; - while(At < GlyphCount) + kbts_glyph *AtGlyph = BaseGlyph->Next; + while(kbts__GlyphIsValid(Storage, AtGlyph)) { - while((At < GlyphCount) && KBTS_IN_SET(Glyphs[At].SyllabicClass, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_ZWJ)(KBTS_INDIC_SYLLABIC_CLASS_ZWNJ)))) + while(kbts__GlyphIsValid(Storage, AtGlyph) && + KBTS__IN_SET(AtGlyph->SyllabicClass, KBTS__SET32((KBTS_INDIC_SYLLABIC_CLASS_ZWJ) + (KBTS_INDIC_SYLLABIC_CLASS_ZWNJ)))) { - ++At; + AtGlyph = AtGlyph->Next; } - if((At < GlyphCount) && (Glyphs[At].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT)) + if(kbts__GlyphIsValid(Storage, AtGlyph) && + (AtGlyph->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT)) { - ++At; + AtGlyph = AtGlyph->Next; } else { break; } - while((At < GlyphCount) && KBTS_IN_SET(Glyphs[At].SyllabicClass, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_ZWJ)(KBTS_INDIC_SYLLABIC_CLASS_ZWNJ)))) + while(kbts__GlyphIsValid(Storage, AtGlyph) && + KBTS__IN_SET(AtGlyph->SyllabicClass, KBTS__SET32((KBTS_INDIC_SYLLABIC_CLASS_ZWJ) + (KBTS_INDIC_SYLLABIC_CLASS_ZWNJ)))) { - ++At; + AtGlyph = AtGlyph->Next; } - if(At < GlyphCount) + if(kbts__GlyphIsValid(Storage, AtGlyph)) { - kbts_glyph *Glyph = &Glyphs[At]; - if(kbts_SyllabicClassIsConsonant(Glyph->SyllabicClass) && (Glyph->SyllabicPosition == KBTS_SYLLABIC_POSITION_BELOWBASE_CONSONANT)) + if(kbts__SyllabicClassIsConsonant(AtGlyph->SyllabicClass) && + (AtGlyph->SyllabicPosition == KBTS__SYLLABIC_POSITION_BELOWBASE_CONSONANT)) { - Glyph->SyllabicPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; - BaseIndex = At; + AtGlyph->SyllabicPosition = KBTS__SYLLABIC_POSITION_SYLLABLE_BASE; + BaseGlyph = AtGlyph; // Do not break; keep matching below-base forms. } } @@ -20730,55 +23985,70 @@ static kbts_end_cluster_result kbts_EndCluster(kbts_shape_state *ShapeState, kbt } } - if(BaseIndex && (BaseIndex < GlyphCount) && (Glyphs[BaseIndex].SyllabicPosition > KBTS_SYLLABIC_POSITION_SYLLABLE_BASE)) + if(kbts__GlyphIsValid(Storage, BaseGlyph) && + kbts__GlyphIsValid(Storage, BaseGlyph->Prev) && + (BaseGlyph->SyllabicPosition > KBTS__SYLLABIC_POSITION_SYLLABLE_BASE)) { - BaseIndex -= 1; + BaseGlyph = BaseGlyph->Prev; } - if((BaseIndex == GlyphCount) && (Glyphs[GlyphCount - 1].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ)) + if(!kbts__GlyphIsValid(Storage, BaseGlyph) && + (BaseGlyph->Prev->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ)) { - BaseIndex = GlyphCount - 1; + BaseGlyph = BaseGlyph->Prev; } - if(BaseIndex < GlyphCount) + if(kbts__GlyphIsValid(Storage, BaseGlyph)) { - while(BaseIndex && KBTS_IN_SET(Glyphs[BaseIndex].SyllabicClass, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_NUKTA)(KBTS_INDIC_SYLLABIC_CLASS_HALANT)))) + while(kbts__GlyphIsValid(Storage, BaseGlyph->Prev) && + KBTS__IN_SET(BaseGlyph->SyllabicClass, KBTS__SET32((KBTS_INDIC_SYLLABIC_CLASS_NUKTA) + (KBTS_INDIC_SYLLABIC_CLASS_HALANT)))) { - BaseIndex -= 1; + BaseGlyph = BaseGlyph->Prev; } } } // Reorder matras. - if(BaseIndex && (GlyphCount > 1)) + if(kbts__GlyphIsValid(Storage, BaseGlyph->Prev) && + (Storage->GlyphSentinel.Prev != Storage->GlyphSentinel.Next) /* GlyphCount > 1 */) { - kbts_un ToIndex = BaseIndex - 1; - if(BaseIndex == GlyphCount) + kbts_glyph *FirstGlyph = Storage->GlyphSentinel.Next; + kbts_glyph *To = BaseGlyph->Prev; + if(!kbts__GlyphIsValid(Storage, BaseGlyph)) { - ToIndex = GlyphCount - 2; + To = To->Prev; } if((Config->Script != KBTS_SCRIPT_MALAYALAM) && (Config->Script != KBTS_SCRIPT_TAMIL)) { + kbts_glyph *LastGlyph = To->Next; + for(;;) { - while(ToIndex && !KBTS_IN_SET(Glyphs[ToIndex].SyllabicClass, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_MATRA)(KBTS_INDIC_SYLLABIC_CLASS_MATRA_POST)(KBTS_INDIC_SYLLABIC_CLASS_HALANT)))) + while((To != FirstGlyph) && + !KBTS__IN_SET(To->SyllabicClass, KBTS__SET32((KBTS_INDIC_SYLLABIC_CLASS_MATRA) + (KBTS_INDIC_SYLLABIC_CLASS_MATRA_POST) + (KBTS_INDIC_SYLLABIC_CLASS_HALANT)))) { - --ToIndex; + LastGlyph = To; + To = To->Prev; } - kbts_glyph *Glyph = &Glyphs[ToIndex]; - if((Glyph->SyllabicClass != KBTS_INDIC_SYLLABIC_CLASS_HALANT) || (Glyph->SyllabicPosition == KBTS_SYLLABIC_POSITION_PREBASE_MATRA)) + if((To->SyllabicClass != KBTS_INDIC_SYLLABIC_CLASS_HALANT) || + (To->SyllabicPosition == KBTS__SYLLABIC_POSITION_PREBASE_MATRA)) { // We have nothing to move. - ToIndex = 0; + To = FirstGlyph; break; } - else if(ToIndex && ((ToIndex + 1) < GlyphCount) && (Glyphs[ToIndex + 1].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ)) + else if((To != FirstGlyph) && + kbts__GlyphIsValid(Storage, LastGlyph) && + (LastGlyph->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ)) { // Zwj+Halant cancels matra movement when the Halant is not attached to the matra. - --ToIndex; + To = To->Prev; } else { @@ -20787,84 +24057,96 @@ static kbts_end_cluster_result kbts_EndCluster(kbts_shape_state *ShapeState, kbt } } - if(ToIndex && (Glyphs[ToIndex].SyllabicPosition != KBTS_SYLLABIC_POSITION_PREBASE_MATRA)) + if((To != FirstGlyph) && + (To->SyllabicPosition != KBTS__SYLLABIC_POSITION_PREBASE_MATRA)) { - for(kbts_un MatraIndex = ToIndex; MatraIndex; --MatraIndex) + for(kbts_glyph *Matra = To->Prev; + kbts__GlyphIsValid(Storage, Matra); + ) { - kbts_glyph *Matra = &Glyphs[MatraIndex - 1]; + kbts_glyph *MatraPrev = Matra->Prev; - if(Matra->SyllabicPosition == KBTS_SYLLABIC_POSITION_PREBASE_MATRA) + if(Matra->SyllabicPosition == KBTS__SYLLABIC_POSITION_PREBASE_MATRA) { - kbts_glyph MatraToReorder = *Matra; + KBTS__DLLIST_REMOVE(Matra); + KBTS__DLLIST_INSERT_AFTER(Matra, To); - KBTS_FOR(GlyphIndex, MatraIndex, ToIndex + 1) - { - Glyphs[GlyphIndex - 1] = Glyphs[GlyphIndex]; - } - - Glyphs[ToIndex] = MatraToReorder; - ToIndex -= 1; + To = Matra->Prev; } + + Matra = MatraPrev; } } } // Reorder reph. // We should only reorder reph when it is a single Repha glyph, and not a Ra sequence. - if((Glyphs[0].SyllabicPosition == KBTS_SYLLABIC_POSITION_RA_TO_BECOME_REPH) && (Glyphs[1].SyllabicPosition != KBTS_SYLLABIC_POSITION_RA_TO_BECOME_REPH)) + kbts_glyph *First = Storage->GlyphSentinel.Next; + kbts_glyph *Second = First->Next; + if((First->SyllabicPosition == KBTS__SYLLABIC_POSITION_RA_TO_BECOME_REPH) && + kbts__GlyphIsValid(Storage, Second) && + (Second->SyllabicPosition != KBTS__SYLLABIC_POSITION_RA_TO_BECOME_REPH)) { - kbts_reph_position RephPosition = Config->IndicScriptProperties.RephPosition; + kbts__reph_position RephPosition = Config->IndicScriptProperties.RephPosition; + kbts_glyph *To = 0; - kbts_un ToIndex = 0; - - KBTS_FOR(GlyphIndex, 0, BaseIndex) + for(kbts_glyph *Glyph = First; + Glyph != BaseGlyph; + ) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + kbts_glyph *Next = Glyph->Next; if(Glyph->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) { - ToIndex = GlyphIndex; + To = Glyph; - if((GlyphIndex + 1) < BaseIndex) + if(Next != BaseGlyph) { - kbts_u8 NextClass = Glyphs[GlyphIndex + 1].SyllabicClass; + kbts_u8 NextClass = Next->SyllabicClass; - if((NextClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ) || (NextClass == KBTS_INDIC_SYLLABIC_CLASS_ZWNJ)) + if((NextClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ) || + (NextClass == KBTS_INDIC_SYLLABIC_CLASS_ZWNJ)) { - ToIndex = GlyphIndex + 1; + To = Next; } } break; } + + Glyph = Next; } - if(!ToIndex) + if(!To) { - if(RephPosition == KBTS_REPH_POSITION_AFTER_SUBJOINED) + // @Cleanup: We can merge these loops. + if(RephPosition == KBTS__REPH_POSITION_AFTER_SUBJOINED) { - KBTS_FOR(GlyphIndex, BaseIndex, GlyphCount) + for(kbts_glyph *Glyph = BaseGlyph; + kbts__GlyphIsValid(Storage, Glyph); + Glyph = Glyph->Next) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex]; kbts_u8 SyllabicPosition = Glyph->SyllabicPosition; - if(KBTS_IN_SET(SyllabicPosition, KBTS_SET32((KBTS_SYLLABIC_POSITION_POSTBASE_CONSONANT)(KBTS_SYLLABIC_POSITION_AFTER_POST)(KBTS_SYLLABIC_POSITION_SMVD)))) + if(KBTS__IN_SET(SyllabicPosition, KBTS__SET32((KBTS__SYLLABIC_POSITION_POSTBASE_CONSONANT) + (KBTS__SYLLABIC_POSITION_AFTER_POST) + (KBTS__SYLLABIC_POSITION_SMVD)))) { - ToIndex = GlyphIndex - 1; + To = Glyph->Prev; break; } } } - else if(RephPosition == KBTS_REPH_POSITION_AFTER_MAIN) + else if(RephPosition == KBTS__REPH_POSITION_AFTER_MAIN) { - KBTS_FOR(GlyphIndex, BaseIndex, GlyphCount) + for(kbts_glyph *Glyph = BaseGlyph; + kbts__GlyphIsValid(Storage, Glyph); + Glyph = Glyph->Next) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex]; - - if(Glyph->SyllabicPosition > KBTS_SYLLABIC_POSITION_AFTER_MAIN) + if(Glyph->SyllabicPosition > KBTS__SYLLABIC_POSITION_AFTER_MAIN) { - ToIndex = GlyphIndex - 1; + To = Glyph->Prev; break; } @@ -20872,121 +24154,112 @@ static kbts_end_cluster_result kbts_EndCluster(kbts_shape_state *ShapeState, kbt } } - if(!ToIndex) + if(!To) { // As a fallback, move reph to the end of the syllable. - for(kbts_un GlyphIndex = GlyphCount; GlyphIndex; --GlyphIndex) + for(kbts_glyph *Glyph = Storage->GlyphSentinel.Prev; + kbts__GlyphIsValid(Storage, Glyph); + Glyph = Glyph->Prev) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex - 1]; - - if(Glyph->SyllabicPosition != KBTS_SYLLABIC_POSITION_SMVD) + if(Glyph->SyllabicPosition != KBTS__SYLLABIC_POSITION_SMVD) { - ToIndex = GlyphIndex - 1; + To = Glyph; break; } } // Matras will still come after reph. - kbts_glyph *Glyph = &Glyphs[ToIndex]; + kbts_glyph *Glyph = To; if(Glyph->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) { - KBTS_FOR(MatraIndex, BaseIndex + 1, ToIndex) + for(kbts_glyph *Matra = BaseGlyph->Next; + Matra != To; + Matra = Matra->Next) { - kbts_glyph *Matra = &Glyphs[MatraIndex]; kbts_u8 Class = Matra->SyllabicClass; - if(KBTS_IN_SET(Class, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_MATRA)(KBTS_INDIC_SYLLABIC_CLASS_MATRA_POST)(KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_MEDIAL)))) + if(KBTS__IN_SET(Class, KBTS__SET32((KBTS_INDIC_SYLLABIC_CLASS_MATRA) + (KBTS_INDIC_SYLLABIC_CLASS_MATRA_POST) + (KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_MEDIAL)))) { - ToIndex -= 1; + To = To->Prev; } } } } - if(ToIndex) + if(To) { // Do the reorder! - kbts_glyph Reph = Glyphs[0]; - - KBTS_FOR(GlyphIndex, 0, ToIndex) - { - Glyphs[GlyphIndex] = Glyphs[GlyphIndex + 1]; - } - - Glyphs[ToIndex] = Reph; - - if(BaseIndex && (BaseIndex <= ToIndex)) - { - BaseIndex -= 1; - } + KBTS__DLLIST_REMOVE(First); + KBTS__DLLIST_INSERT_AFTER(First, To); } } // Reorder pre-base-reordering consonants. if(Pref) { - kbts_un PrefIndex = 0; + First = Storage->GlyphSentinel.Next; + kbts_glyph *PrefGlyph = 0; - KBTS_FOR(GlyphIndex, BaseIndex + 1, GlyphCount) + for(kbts_glyph *Glyph = BaseGlyph->Next; + kbts__GlyphIsValid(Storage, Glyph); + Glyph = Glyph->Next) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex]; - if(Glyph->Flags & KBTS_GLYPH_FLAG_PREF) { - PrefIndex = GlyphIndex; + PrefGlyph = Glyph; break; } } - if(PrefIndex) + if(PrefGlyph) { - kbts_glyph PrefGlyph = Glyphs[PrefIndex]; - // Harfbuzz says the ideal is to check that this glyph was generated by the pref feature specifically, // but then just uses a generic flag like this. // The ideal solution would not be very difficult to implement! - if(PrefGlyph.Flags & KBTS_GLYPH_FLAG_GENERATED_BY_GSUB) + if(PrefGlyph->Flags & KBTS_GLYPH_FLAG_GENERATED_BY_GSUB) { - kbts_un ToIndex = 0; + kbts_glyph *To = First; - for(kbts_un GlyphIndex = BaseIndex; GlyphIndex; --GlyphIndex) + kbts_glyph *Last = BaseGlyph; + for(kbts_glyph *Glyph = BaseGlyph->Prev; + kbts__GlyphIsValid(Storage, Glyph); + Glyph = Glyph->Prev) { - kbts_u8 Class = Glyphs[GlyphIndex - 1].SyllabicClass; + kbts_u8 Class = Glyph->SyllabicClass; - if(KBTS_IN_SET(Class, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_MATRA)(KBTS_INDIC_SYLLABIC_CLASS_MATRA_POST)(KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_MEDIAL)(KBTS_INDIC_SYLLABIC_CLASS_HALANT)))) + if(KBTS__IN_SET(Class, KBTS__SET32((KBTS_INDIC_SYLLABIC_CLASS_MATRA) + (KBTS_INDIC_SYLLABIC_CLASS_MATRA_POST) + (KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_MEDIAL) + (KBTS_INDIC_SYLLABIC_CLASS_HALANT)))) { - ToIndex = GlyphIndex; + To = Last; break; } + + Last = Glyph; } - if(ToIndex && (ToIndex < GlyphCount)) + if(To != First) { - kbts_glyph *Prev = &Glyphs[ToIndex - 1]; - kbts_u8 CurrentClass = Glyphs[ToIndex].SyllabicClass; + kbts_glyph *Prev = To->Prev; + kbts_u8 CurrentClass = To->SyllabicClass; - if((Prev->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) && KBTS_IN_SET(CurrentClass, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_ZWJ)(KBTS_INDIC_SYLLABIC_CLASS_ZWNJ)))) + if((Prev->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) && + KBTS__IN_SET(CurrentClass, KBTS__SET32((KBTS_INDIC_SYLLABIC_CLASS_ZWJ) + (KBTS_INDIC_SYLLABIC_CLASS_ZWNJ)))) { - ToIndex += 1; + To = To->Next; } } // Do the reorder! - for(kbts_un GlyphIndex = PrefIndex; GlyphIndex > ToIndex; --GlyphIndex) - { - Glyphs[GlyphIndex] = Glyphs[GlyphIndex - 1]; - } - - Glyphs[ToIndex] = PrefGlyph; - - // @Cleanup: This is probably always true? - if((BaseIndex >= ToIndex) && (BaseIndex < PrefIndex)) - { - BaseIndex += 1; - } + KBTS__DLLIST_REMOVE(PrefGlyph); + KBTS__DLLIST_INSERT_BEFORE(PrefGlyph, To); } } } @@ -20994,9 +24267,9 @@ static kbts_end_cluster_result kbts_EndCluster(kbts_shape_state *ShapeState, kbt { // Mark matras at the beginning of a word for init application. // It is tempting to check for this at the same time as the reph reordering, but glyphs could have been // reordered since then and the reordering procedure is clearly defined to happen in sequential steps. - kbts_glyph *First = &Glyphs[0]; + First = Storage->GlyphSentinel.Next; // I don't think this needs to be reloaded, but you never know. - if((First->SyllabicPosition == KBTS_SYLLABIC_POSITION_PREBASE_MATRA) && ShapeState->ClusterAtStartOfWord) + if((First->SyllabicPosition == KBTS__SYLLABIC_POSITION_PREBASE_MATRA) && Scratchpad->ClusterAtStartOfWord) { First->Flags |= KBTS_GLYPH_FLAG_INIT; } @@ -21006,38 +24279,42 @@ static kbts_end_cluster_result kbts_EndCluster(kbts_shape_state *ShapeState, kbt case KBTS_SHAPER_USE: { - kbts_u64 PostBaseSet = KBTS_SET64((KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_ABOVE)(KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_BELOW) - (KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_MOD_ABOVE)(KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_MOD_BELOW) - (KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_MOD_POST)(KBTS_USE_SYLLABIC_CLASS_CONS_MED_ABOVE) - (KBTS_USE_SYLLABIC_CLASS_CONS_MED_BELOW)(KBTS_USE_SYLLABIC_CLASS_CONS_MED_POST) - (KBTS_USE_SYLLABIC_CLASS_CONS_MED_PRE)(KBTS_USE_SYLLABIC_CLASS_VOWEL_ABOVE) - (KBTS_USE_SYLLABIC_CLASS_VOWEL_BELOW)(KBTS_USE_SYLLABIC_CLASS_VOWEL_POST) - (KBTS_USE_SYLLABIC_CLASS_VOWEL_PRE)(KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_ABOVE) - (KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_BELOW)(KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_POST) + kbts_u64 PostBaseSet = KBTS__SET64((KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_ABOVE) (KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_BELOW) + (KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_MOD_ABOVE) (KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_MOD_BELOW) + (KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_MOD_POST) (KBTS_USE_SYLLABIC_CLASS_CONS_MED_ABOVE) + (KBTS_USE_SYLLABIC_CLASS_CONS_MED_BELOW) (KBTS_USE_SYLLABIC_CLASS_CONS_MED_POST) + (KBTS_USE_SYLLABIC_CLASS_CONS_MED_PRE) (KBTS_USE_SYLLABIC_CLASS_VOWEL_ABOVE) + (KBTS_USE_SYLLABIC_CLASS_VOWEL_BELOW) (KBTS_USE_SYLLABIC_CLASS_VOWEL_POST) + (KBTS_USE_SYLLABIC_CLASS_VOWEL_PRE) (KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_ABOVE) + (KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_BELOW) (KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_POST) (KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_PRE)); - kbts_u64 HalantSet = KBTS_SET64((KBTS_USE_SYLLABIC_CLASS_HALANT)(KBTS_USE_SYLLABIC_CLASS_HALANT_OR_VOWEL_MODIFIER)(KBTS_USE_SYLLABIC_CLASS_INVISIBLE_STACKER)); + kbts_u64 HalantSet = KBTS__SET64((KBTS_USE_SYLLABIC_CLASS_HALANT) + (KBTS_USE_SYLLABIC_CLASS_HALANT_OR_VOWEL_MODIFIER) + (KBTS_USE_SYLLABIC_CLASS_INVISIBLE_STACKER)); // In the reorderings below, we check for halants because that's what Harfbuzz does. // Nowhere does Microsoft mention that halants should block reorderings! - kbts_glyph Repha = Glyphs[0]; - if((Repha.UseClass == KBTS_USE_SYLLABIC_CLASS_REPHA) || (Repha.Flags & KBTS_GLYPH_FLAG_RPHF)) + kbts_glyph *Repha = Storage->GlyphSentinel.Next; + if((Repha->UseClass == KBTS_USE_SYLLABIC_CLASS_REPHA) || + (Repha->Flags & KBTS_GLYPH_FLAG_RPHF)) { - kbts_un GlyphIndex = 1; - for(; GlyphIndex < GlyphCount; ++GlyphIndex) + kbts_glyph *To = Repha->Next; + for(; + kbts__GlyphIsValid(Storage, To); + To = To->Next) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex]; - // Microsoft says that rephas are reordered "after a following full base", which is needlessly vague. // Harfbuzz reorders them in front of the first post-base glyph. - if(KBTS_IN_SET64(Glyph->UseClass, PostBaseSet) || (!(Glyph->Flags & KBTS_GLYPH_FLAG_LIGATURE) && KBTS_IN_SET64(Glyph->UseClass, HalantSet))) + if(KBTS__IN_SET64(To->UseClass, PostBaseSet) || + (!(To->Flags & KBTS_GLYPH_FLAG_LIGATURE) && + KBTS__IN_SET64(To->UseClass, HalantSet))) { break; } - - Glyphs[GlyphIndex - 1] = *Glyph; } - Glyphs[GlyphIndex - 1] = Repha; + KBTS__DLLIST_REMOVE(Repha); + KBTS__DLLIST_INSERT_BEFORE(Repha, To); } { @@ -21045,1770 +24322,2346 @@ static kbts_end_cluster_result kbts_EndCluster(kbts_shape_state *ShapeState, kbt // and, if present, before a pre-base glyph reordered via the 'pref' feature". // In practice, we tag 'pref'-generated glyphs with the VOWEL_PRE class so that they get reordered here. // Note that the final reordered glyphs end up backwards from their original order. - kbts_glyph PreBaseVowels[16]; // @Robustness: How many vowels can there realistically be in a single cluster? + kbts_glyph *PreBaseVowels[16]; // @Robustness: How many vowels can there realistically be in a single cluster? kbts_un PreBaseVowelCount = 0; kbts_u64 SawBase = 0; - for(kbts_un GlyphIndex = GlyphCount; GlyphIndex; --GlyphIndex) + for(kbts_glyph *Glyph = Storage->GlyphSentinel.Prev; + kbts__GlyphIsValid(Storage, Glyph); + Glyph = Glyph->Prev) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex - 1]; - SawBase |= KBTS_IN_SET64(Glyph->UseClass, KBTS_SET64((KBTS_USE_SYLLABIC_CLASS_BASE)(KBTS_USE_SYLLABIC_CLASS_BASE_OTHER)(KBTS_USE_SYLLABIC_CLASS_BASE_NUM))); + SawBase |= KBTS__IN_SET64(Glyph->UseClass, KBTS__SET64((KBTS_USE_SYLLABIC_CLASS_BASE) + (KBTS_USE_SYLLABIC_CLASS_BASE_OTHER) + (KBTS_USE_SYLLABIC_CLASS_BASE_NUM))); kbts_u32 Flags = Glyph->Flags; // Only accept the first glyphs produced by multiple substitutions. - if(((Flags & KBTS_GLYPH_FLAG_FIRST_IN_MULTIPLE_SUBSTITUTION) || !(Flags & KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION)) && - (KBTS_IN_SET64(Glyph->UseClass, KBTS_SET64((KBTS_USE_SYLLABIC_CLASS_VOWEL_PRE)(KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_PRE))) || - (Flags & KBTS_GLYPH_FLAG_PREF))) + if(((Flags & KBTS_GLYPH_FLAG_FIRST_IN_MULTIPLE_SUBSTITUTION) || + !(Flags & KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION)) && + (KBTS__IN_SET64(Glyph->UseClass, KBTS__SET64((KBTS_USE_SYLLABIC_CLASS_VOWEL_PRE) + (KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_PRE))) || + (Flags & KBTS_GLYPH_FLAG_PREF))) { - if(PreBaseVowelCount < KBTS_ARRAY_LENGTH(PreBaseVowels)) + if(PreBaseVowelCount < KBTS__ARRAY_LENGTH(PreBaseVowels)) { - PreBaseVowels[PreBaseVowelCount++] = *Glyph; + PreBaseVowels[PreBaseVowelCount++] = Glyph; } } - else if(!(Glyph->Flags & KBTS_GLYPH_FLAG_LIGATURE) && KBTS_IN_SET64(Glyph->UseClass, HalantSet)) + else if(!(Glyph->Flags & KBTS_GLYPH_FLAG_LIGATURE) && + KBTS__IN_SET64(Glyph->UseClass, HalantSet)) { // Reordering stops at halants, apparently. // We want to write the vowels in the reverse order they appear in the glyph sequence. // Since we are iterating backwards, they already _are_ backwards in the PreBaseVowels array, // so there's no need to do anything. - KBTS_FOR(PreBaseVowelIndex, 0, PreBaseVowelCount) + kbts_glyph *InsertAfter = Glyph; + KBTS__FOR(PreBaseVowelIndex, 0, PreBaseVowelCount) { - Glyphs[GlyphIndex + PreBaseVowelIndex] = PreBaseVowels[PreBaseVowelIndex]; + kbts_glyph *PreBaseVowel = PreBaseVowels[PreBaseVowelIndex]; + + KBTS__DLLIST_REMOVE(PreBaseVowel); + KBTS__DLLIST_INSERT_AFTER(PreBaseVowel, InsertAfter); + InsertAfter = PreBaseVowel; } PreBaseVowelCount = 0; // Valid bases only show up before halants. SawBase = 0; } - else + } + + kbts_glyph *DottedCircleInsertBefore = Storage->GlyphSentinel.Next; + + { // Flush the rest of the vowels. + kbts_glyph *InsertAfter = (kbts_glyph *)&Storage->GlyphSentinel; + KBTS__FOR(PreBaseVowelIndex, 0, PreBaseVowelCount) { - Glyphs[GlyphIndex - 1 + PreBaseVowelCount] = *Glyph; + kbts_glyph *PreBaseVowel = PreBaseVowels[PreBaseVowelIndex]; + + KBTS__DLLIST_REMOVE(PreBaseVowel); + KBTS__DLLIST_INSERT_AFTER(PreBaseVowel, InsertAfter); + + InsertAfter = PreBaseVowel; } } - // Flush the rest of the vowels. - KBTS_FOR(PreBaseVowelIndex, 0, PreBaseVowelCount) + if(Scratchpad->RealCluster && !SawBase && Config->DottedCircle.Id) { - Glyphs[PreBaseVowelIndex] = PreBaseVowels[PreBaseVowelIndex]; - } + kbts_glyph *DottedCircle = kbts__InsertGlyphBefore(Storage, DottedCircleInsertBefore, &Config->DottedCircle); + if(!DottedCircle) + { + goto OutOfMemory; + } - // We are supposed to insert a dotted circle after repha when a base is missing. - // The issue is that we have no idea whether the first glyph is a repha or not before we apply - // RPHF. - // So, this is really sucky, but I haven't found a way to merge this logic into any already- - // existing loop, so we have to eat the extra traversal for now. - if(ShapeState->RealCluster && !SawBase) - { - Result.InsertDottedCircle = 1; - Result.DottedCircleIndex = PreBaseVowelCount; + DottedCircle->UserIdOrCodepointIndex = DottedCircleInsertBefore->UserIdOrCodepointIndex; } } } break; case KBTS_SHAPER_MYANMAR: - if(ShapeState->RealCluster) + if(Scratchpad->RealCluster) { - kbts_un OnePastRephIndex = 0; - kbts_un BaseIndex = GlyphCount; - if(GlyphCount >= 3) + kbts_glyph *BaseGlyph = (kbts_glyph *)&Storage->GlyphSentinel; + kbts_glyph *First = BaseGlyph->Next; + kbts_glyph *Second = First->Next; + kbts_glyph *Third = Second->Next; + kbts_glyph *OnePastReph = First; + + kbts_un MinimumGlyphCount = 0; + + if(kbts__GlyphIsValid(Storage, First)) { - kbts_glyph *First = &Glyphs[0]; - kbts_glyph *Second = &Glyphs[1]; - kbts_glyph *Third = &Glyphs[2]; + MinimumGlyphCount += 1; - if((First->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_RA) && - (Second->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ASAT) && - (Third->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT)) + if(kbts__GlyphIsValid(Storage, Second)) { - First->SyllabicPosition = KBTS_SYLLABIC_POSITION_AFTER_MAIN; - Second->SyllabicPosition = KBTS_SYLLABIC_POSITION_AFTER_MAIN; - Third->SyllabicPosition = KBTS_SYLLABIC_POSITION_AFTER_MAIN; + MinimumGlyphCount += 1; - OnePastRephIndex = 3; - BaseIndex = 0; + if(kbts__GlyphIsValid(Storage, Third)) + { + MinimumGlyphCount += 1; + } } } - kbts_u64 BaseSet = KBTS_SET64((KBTS_INDIC_SYLLABIC_CLASS_CONSONANT) + if((MinimumGlyphCount == 3) && + (First->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_RA) && + (Second->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ASAT) && + (Third->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT)) + { + First->SyllabicPosition = KBTS__SYLLABIC_POSITION_AFTER_MAIN; + Second->SyllabicPosition = KBTS__SYLLABIC_POSITION_AFTER_MAIN; + Third->SyllabicPosition = KBTS__SYLLABIC_POSITION_AFTER_MAIN; + + OnePastReph = Third->Next; + BaseGlyph = First; + } + + kbts_u64 BaseSet = KBTS__SET64((KBTS_INDIC_SYLLABIC_CLASS_CONSONANT) (KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_WITH_STACKER) (KBTS_INDIC_SYLLABIC_CLASS_RA) (KBTS_INDIC_SYLLABIC_CLASS_VOWEL) (KBTS_INDIC_SYLLABIC_CLASS_PLACEHOLDER) (KBTS_INDIC_SYLLABIC_CLASS_DOTTED_CIRCLE)); - KBTS_FOR(GlyphIndex, OnePastRephIndex, GlyphCount) + + // Scan for a non-reph base glyph. + for(kbts_glyph *Glyph = OnePastReph; + kbts__GlyphIsValid(Storage, Glyph); + Glyph = Glyph->Next) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex]; kbts_indic_syllabic_class Class = Glyph->SyllabicClass; - if((BaseIndex == GlyphCount) && KBTS_IN_SET64(Class, BaseSet)) + if(!kbts__GlyphIsValid(Storage, BaseGlyph) && + KBTS__IN_SET64(Class, BaseSet)) { - BaseIndex = GlyphIndex; + BaseGlyph = Glyph; + break; } } - if((BaseIndex == GlyphCount) && OnePastRephIndex) + // Otherwise, reph can be the base. + // @Cleanup: I'm pretty sure this is @Duplication with the reph check above. + if(!kbts__GlyphIsValid(Storage, BaseGlyph) && + (OnePastReph != First)) { - BaseIndex = 0; + BaseGlyph = First; } - kbts_syllabic_position LastPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; - kbts_syllabic_position SectionPosition = KBTS_SYLLABIC_POSITION_AFTER_MAIN; - kbts_un LastPreBaseMatraIndex = GlyphCount; - KBTS_FOR(GlyphIndex, BaseIndex + 1, GlyphCount) + if(kbts__GlyphIsValid(Storage, BaseGlyph)) { - kbts_glyph *Glyph = &Glyphs[GlyphIndex]; - kbts_syllabic_position Position = SectionPosition; - - switch(Glyph->SyllabicClass) + kbts__syllabic_position LastPosition = KBTS__SYLLABIC_POSITION_SYLLABLE_BASE; + kbts__syllabic_position SectionPosition = KBTS__SYLLABIC_POSITION_AFTER_MAIN; + kbts_glyph *LastPreBaseMatra = (kbts_glyph *)&Storage->GlyphSentinel; + for(kbts_glyph *Glyph = BaseGlyph->Next; + kbts__GlyphIsValid(Storage, Glyph); + ) { - case KBTS_INDIC_SYLLABIC_CLASS_MEDIAL_RA: - Position = KBTS_SYLLABIC_POSITION_PREBASE_CONSONANT; - break; + kbts_glyph *Next = Glyph->Next; // Make sure we preserve the link when reversing. + kbts__syllabic_position Position = SectionPosition; - case KBTS_INDIC_SYLLABIC_CLASS_VOWEL_PRE: - { - Position = KBTS_SYLLABIC_POSITION_PREBASE_MATRA; - - // According to Unicode 15.0: - // For combining characters placed to the left of a base character, the combining characters start from the base - // character and are arranged leftward. - // Since these guys will get reordered into being pre-base, we need to flip them. - if(GlyphIndex > LastPreBaseMatraIndex) + switch(Glyph->SyllabicClass) { - kbts_un FlipCount = GlyphIndex - LastPreBaseMatraIndex + 1; - KBTS_FOR(FlipIndex, 0, FlipCount / 2) + case KBTS_INDIC_SYLLABIC_CLASS_MEDIAL_RA: + Position = KBTS__SYLLABIC_POSITION_PREBASE_CONSONANT; + break; + + case KBTS_INDIC_SYLLABIC_CLASS_VOWEL_PRE: + { + Position = KBTS__SYLLABIC_POSITION_PREBASE_MATRA; + + // According to Unicode 15.0: + // For combining characters placed to the left of a base character, the combining characters start from the base + // character and are arranged leftward. + // Since these guys will get reordered into being pre-base, we need to flip them. + if(kbts__GlyphIsValid(Storage, LastPreBaseMatra)) { - kbts_un LeftIndex = LastPreBaseMatraIndex + FlipIndex; - kbts_un RightIndex = LastPreBaseMatraIndex + FlipCount - 1 - FlipIndex; - kbts_glyph Swap = Glyphs[LeftIndex]; - Glyphs[LeftIndex] = Glyphs[RightIndex]; - Glyphs[RightIndex] = Swap; + kbts__DllistReverseSublist(LastPreBaseMatra, Glyph->Next); } + else + { + // When we reverse, this will become the "last" pre-base matra again, so we only need to set it once. + LastPreBaseMatra = Glyph; + } + } break; - // Readjust Glyph to compensate for the flip. - Glyph = &Glyphs[LastPreBaseMatraIndex]; + case KBTS_INDIC_SYLLABIC_CLASS_VARIATION_SELECTOR: + Position = LastPosition; + break; + + case KBTS_INDIC_SYLLABIC_CLASS_VOWEL_BELOW: + if(Position == KBTS__SYLLABIC_POSITION_AFTER_MAIN) + { + Position = KBTS__SYLLABIC_POSITION_BELOWBASE_CONSONANT; + } + else if(Position == KBTS__SYLLABIC_POSITION_BELOWBASE_CONSONANT) + { + Position = SectionPosition; + } + break; + + case KBTS_INDIC_SYLLABIC_CLASS_VEDIC_SIGN: + if(Position == KBTS__SYLLABIC_POSITION_BELOWBASE_CONSONANT) + { + Position = KBTS__SYLLABIC_POSITION_BEFORE_SUBJOINED; + } + break; } - LastPreBaseMatraIndex = GlyphIndex; - } break; - - case KBTS_INDIC_SYLLABIC_CLASS_VARIATION_SELECTOR: - Position = LastPosition; - break; - - case KBTS_INDIC_SYLLABIC_CLASS_VOWEL_BELOW: - if(Position == KBTS_SYLLABIC_POSITION_AFTER_MAIN) - { - Position = KBTS_SYLLABIC_POSITION_BELOWBASE_CONSONANT; - } - else if(Position == KBTS_SYLLABIC_POSITION_BELOWBASE_CONSONANT) + if((SectionPosition == KBTS__SYLLABIC_POSITION_BELOWBASE_CONSONANT) && (Glyph->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_VEDIC_SIGN)) { + SectionPosition = KBTS__SYLLABIC_POSITION_AFTER_SUBJOINED; Position = SectionPosition; } - break; - case KBTS_INDIC_SYLLABIC_CLASS_VEDIC_SIGN: - if(Position == KBTS_SYLLABIC_POSITION_BELOWBASE_CONSONANT) - { - Position = KBTS_SYLLABIC_POSITION_BEFORE_SUBJOINED; - } - break; + Glyph->SyllabicPosition = Position; + LastPosition = Position; + Glyph = Next; } - - if((SectionPosition == KBTS_SYLLABIC_POSITION_BELOWBASE_CONSONANT) && (Glyph->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_VEDIC_SIGN)) - { - SectionPosition = KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED; - Position = SectionPosition; - } - - Glyph->SyllabicPosition = Position; - LastPosition = Position; } - KBTS_FOR(Iter, 1, GlyphCount) + if(MinimumGlyphCount > 1) { - KBTS_FOR(GlyphIndex, 1, GlyphCount) - { - kbts_glyph *A = &Glyphs[GlyphIndex - 1]; - kbts_glyph *B = &Glyphs[GlyphIndex]; + KBTS__DLLIST_SORT(Storage->GlyphSentinel.Next, (kbts_glyph *)&Storage->GlyphSentinel, SyllabicPosition); - if(A->SyllabicPosition > B->SyllabicPosition) + #ifdef KBTS_SANITY_CHECK + { + kbts_glyph *Left = C->GlyphSentinel.Next; + kbts_glyph *Right = Left->Next; + while(kbts__GlyphIsValid(C, Right)) { - kbts_glyph Swap = *A; - *A = *B; - *B = Swap; + kbts_glyph *Next = Right->Next; + + KBTS_ASSERT(Left->SyllabicPosition <= Right->SyllabicPosition); + + Left = Right; + Right = Next; } } + #endif } } break; } - return Result; -} - -static kbts_op_list kbts_OpList(kbts_u8 *Ops, kbts_un Size) -{ - kbts_op_list Result = KBTS_ZERO; - Result.Ops = Ops; - Result.Length = Size; - return Result; -} -#define KBTS_OP_LIST(OpList) kbts_OpList((kbts_Ops_##OpList), KBTS_ARRAY_LENGTH(kbts_Ops_##OpList)) - -KBTS_EXPORT kbts_shape_config kbts_ShapeConfig(kbts_font *Font, kbts_script Script, kbts_language Language) -{ - kbts_shape_config Result = KBTS_ZERO; - - Result.Font = Font; - Result.Script = Script; - Result.Language = Language; - - kbts_gsub_gpos *Gsub = Font->ShapingTables[KBTS_SHAPING_TABLE_GSUB]; - - // Find the appropriate language system in GSUB/GPOS. - kbts_script_properties *ScriptProperties = &kbts_ScriptProperties[Script]; - int FoundScriptIsIndic3 = 0; - - KBTS_FOR(ShapingTableIndex, 0, KBTS_SHAPING_TABLE_COUNT) + if(0) { - kbts_gsub_gpos *ShapingTable = Font->ShapingTables[ShapingTableIndex]; - if(ShapingTable) + OutOfMemory:; + Scratchpad->Error = KBTS_SHAPE_ERROR_OUT_OF_MEMORY; + } +} + +static void *kbts__PointerPush(char **Pointer, kbts_un Size, kbts_un Align) +{ + char *At = *Pointer; + char *Aligned = KBTS__ALIGN_POINTER(char, At, Align); + *Pointer = Aligned + Size; + + void *Result = Aligned; + return Result; +} +#define kbts__PointerPushType(Pointer, Type) (Type *)kbts__PointerPush((Pointer), sizeof(Type), KBTS_ALIGNOF(Type)) +#define kbts__PointerPushArray(Pointer, Type, Count) (Type *)kbts__PointerPush((Pointer), sizeof(Type) * (Count), KBTS_ALIGNOF(Type)) + +static kbts_shape_config *kbts__PlaceShapeConfig(kbts_font *Font, kbts_script Script, kbts_language Language, void *Memory, kbts_un *Size) +{ + kbts_shape_config *Result = 0; + kbts_shape_config DummyConfig; + char *MemoryAt = (char *)Memory; + + if(Font) + { + Result = kbts__PointerPushType(&MemoryAt, kbts_shape_config); + if(!Memory) { - kbts_script_list *ScriptList = KBTS_POINTER_OFFSET(kbts_script_list, ShapingTable, ShapingTable->ScriptListOffset); + Result = &DummyConfig; + } - kbts_langsys *ChosenLangsys = 0; - kbts_u32 DesiredTag = ScriptProperties->Tag; + KBTS_MEMSET(Result, 0, sizeof(*Result)); - KBTS_FOR(ScriptIndex, 0, ScriptList->Count) + Result->Font = Font; + Result->Script = Script; + Result->Language = Language; + + kbts__gsub_gpos *ShapingTables[2] = { + kbts__BlobTableDataType(Font->Blob, KBTS_BLOB_TABLE_ID_GSUB, kbts__gsub_gpos), + kbts__BlobTableDataType(Font->Blob, KBTS_BLOB_TABLE_ID_GPOS, kbts__gsub_gpos), + }; + + kbts__gsub_gpos *Gsub = ShapingTables[0]; + + // Find the appropriate language system in GSUB/GPOS. + kbts__script_properties *ScriptProperties = &kbts__ScriptProperties[Script]; + int FoundScriptIsIndic3 = 0; + + KBTS__FOR(ShapingTableIndex, 0, KBTS_SHAPING_TABLE_COUNT) + { + kbts__gsub_gpos *ShapingTable = ShapingTables[ShapingTableIndex]; + if(ShapingTable) { - kbts_script_pointer ThisScript = kbts_GetScript(ScriptList, ScriptIndex); - kbts_u32 Tag = ThisScript.Tag; + kbts__script_list *ScriptList = KBTS__POINTER_OFFSET(kbts__script_list, ShapingTable, ShapingTable->ScriptListOffset); - // The OpenType spec does not define or even mention "Indic3" scripts at all. - // Nevertheless, Harfbuzz at least checks for '3' at the end of script tags, and, if one exists, they choose USE. - int Indic3 = (ThisScript.Tag >> 24) == '3'; - kbts_u32 MatchMask = Indic3 ? 0xFFFFFF : 0xFFFFFFFF; - int PerfectMatch = !((Tag ^ DesiredTag) & MatchMask); - if(!ScriptIndex || PerfectMatch || (Tag == KBTS_FOURCC('D', 'F', 'L', 'T'))) + kbts__langsys *ChosenLangsys = 0; + kbts_u32 DesiredTag = ScriptProperties->Tag; + + KBTS__FOR(ScriptIndex, 0, ScriptList->Count) { - kbts_langsys *Langsys = kbts_GetDefaultLangsys(ThisScript.Script); - KBTS_FOR(LangsysIndex, 0, ThisScript.Script->Count) - { - kbts_langsys_pointer LangsysPointer = kbts_GetLangsys(ThisScript.Script, LangsysIndex); + kbts__script_pointer ThisScript = kbts__GetScript(ScriptList, ScriptIndex); + kbts_u32 Tag = ThisScript.Tag; - if(LangsysPointer.Tag == Language) + // The OpenType spec does not define or even mention "Indic3" scripts at all. + // Nevertheless, Harfbuzz at least checks for '3' at the end of script tags, and, if one exists, they choose USE. + int Indic3 = (ThisScript.Tag >> 24) == '3'; + kbts_u32 MatchMask = Indic3 ? 0xFFFFFF : 0xFFFFFFFF; + int PerfectMatch = !((Tag ^ DesiredTag) & MatchMask); + if(!ScriptIndex || PerfectMatch || (Tag == KBTS_FOURCC('D', 'F', 'L', 'T'))) + { + kbts__langsys *Langsys = kbts__GetDefaultLangsys(ThisScript.Script); + KBTS__FOR(LangsysIndex, 0, ThisScript.Script->Count) + { + kbts__langsys_pointer LangsysPointer = kbts__GetLangsys(ThisScript.Script, LangsysIndex); + + if(LangsysPointer.Tag == Language) + { + Langsys = LangsysPointer.Langsys; + break; + } + } + + // It is tempting to try to look for another script if the one we want has no langsys. + // However, it is possible for a script to purposefully have no langsys at all. In that case, + // the shaper should not apply any GSUB features. + // In that case, the shaper should not apply any GSUB features. + // So, store the result _regardless_ of whether Langsys is null or not. + ChosenLangsys = Langsys; + if(ShapingTableIndex == KBTS_SHAPING_TABLE_GSUB) + { + // Apparently, it is allowed to have script-specific GSUB tables, and a huge DFLT GPOS table. + FoundScriptIsIndic3 = Indic3; + } + // And then get out if we found the appropriate script, even if the langsys is null! + if(PerfectMatch) { - Langsys = LangsysPointer.Langsys; break; } } + } - // It is tempting to try to look for another script if the one we want has no langsys. - // However, it is possible for a script to purposefully have no langsys at all. In that case, - // the shaper should not apply any GSUB features. - // In that case, the shaper should not apply any GSUB features. - // So, store the result _regardless_ of whether Langsys is null or not. - ChosenLangsys = Langsys; - if(ShapingTableIndex == KBTS_SHAPING_TABLE_GSUB) + Result->Langsys[ShapingTableIndex] = ChosenLangsys; + } + } + + Result->IndicScriptProperties = kbts__IndicScriptProperties(Script); + Result->Shaper = FoundScriptIsIndic3 ? KBTS_SHAPER_USE : ScriptProperties->Shaper; + Result->OpList = *kbts__ShaperOpLists[Result->Shaper]; + + Result->Features = KBTS__ZERO_TYPE(kbts__feature_set); + KBTS__FOR(StageIndex, 0, Result->OpList.FeatureStageCount) + { + kbts__feature_stage *Stage = &Result->OpList.FeatureStages[StageIndex]; + + KBTS__FOR(WordIndex, 0, KBTS__ARRAY_LENGTH(Result->Features.Flags)) + { + Result->Features.Flags[WordIndex] |= Stage->Features.Flags[WordIndex]; + } + } + + kbts__feature *Rclt = 0; + kbts__feature_set SyllableFeatureSet = {{KBTS__FEATURE_FLAG0(rphf) | KBTS__FEATURE_FLAG0(blwf) | KBTS__FEATURE_FLAG0(half) | KBTS__FEATURE_FLAG0(pstf) | KBTS__FEATURE_FLAG0(pref), + 0, KBTS__FEATURE_FLAG2(rclt) | KBTS__FEATURE_FLAG2(locl), KBTS__FEATURE_FLAG3(vatu)}}; + kbts__iterate_features IterateFeatures = kbts__IterateFeatures(Result, KBTS_SHAPING_TABLE_GSUB, SyllableFeatureSet); + while(kbts__NextFeature(&IterateFeatures)) + { + switch(IterateFeatures.CurrentFeatureTag) + { + case KBTS_FEATURE_TAG_blwf: Result->Blwf = IterateFeatures.Feature; break; + case KBTS_FEATURE_TAG_pref: Result->Pref = IterateFeatures.Feature; break; + case KBTS_FEATURE_TAG_pstf: Result->Pstf = IterateFeatures.Feature; break; + case KBTS_FEATURE_TAG_locl: Result->Locl = IterateFeatures.Feature; break; + case KBTS_FEATURE_TAG_rphf: Result->Rphf = IterateFeatures.Feature; break; + case KBTS_FEATURE_TAG_half: Result->Half = IterateFeatures.Feature; break; + case KBTS_FEATURE_TAG_vatu: Result->Vatu = IterateFeatures.Feature; break; + case KBTS_FEATURE_TAG_rclt: Rclt = IterateFeatures.Feature; break; + } + } + + if((Result->Shaper == KBTS_SHAPER_ARABIC) && !Rclt) + { + Result->OpList = kbts__OpList_ArabicNoRclt; + } + + if(Result->IndicScriptProperties.ViramaCodepoint) + { + kbts__shape_scratchpad DummyScratchpad = KBTS__ZERO; + kbts_glyph_storage DummyStorage = KBTS__ZERO; + KBTS__DLLIST_SENTINEL_INIT(&DummyStorage.GlyphSentinel); + KBTS__DLLIST_SENTINEL_INIT(&DummyStorage.FreeGlyphSentinel); + + // Bake the locl-ized virama. + kbts_glyph Virama = kbts_CodepointToGlyph(Font, (int)Result->IndicScriptProperties.ViramaCodepoint, 0, 0); + Result->Virama = kbts__Substitute1(&DummyScratchpad, Result, &DummyStorage, kbts__GetLookupList(Gsub), Result->Locl, KBTS__SKIP_FLAG_ZWNJ | KBTS__SKIP_FLAG_ZWJ, &Virama); + } + + if((Result->Script == KBTS_SCRIPT_THAI) || (Result->Script == KBTS_SCRIPT_LAO)) + { + kbts_u32 NikhahitCodepoint = (Result->Script == KBTS_SCRIPT_THAI) ? 0xE4D : 0xECD; + kbts_u32 SaraAaCodepoint = (Result->Script == KBTS_SCRIPT_THAI) ? 0xE32 : 0xEB2; + Result->Nikhahit = kbts_CodepointToGlyph(Font, (int)NikhahitCodepoint, 0, 0); + Result->SaraAa = kbts_CodepointToGlyph(Font, (int)SaraAaCodepoint, 0, 0); + } + + Result->DottedCircle = kbts_CodepointToGlyph(Font, 0x25CC, 0, 0); + Result->Whitespace = kbts_CodepointToGlyph(Font, ' ', 0, 0); + + if(ShapingTables[KBTS_SHAPING_TABLE_GSUB] || ShapingTables[KBTS_SHAPING_TABLE_GPOS]) + { // Initialize the per-feature lookup lists. + kbts__baked_feature_stage *BakedStages = kbts__PointerPushArray(&MemoryAt, kbts__baked_feature_stage, Result->OpList.FeatureStageCount); + + kbts_un FeatureStageIndex = 0; + KBTS__FOR(OpIndex, 0, Result->OpList.OpCount) + { + kbts__op_kind Op = Result->OpList.Ops[OpIndex]; + int UserFeaturesAllowed = KBTS__IN_SET(Op, KBTS__SET32((KBTS__OP_KIND_GSUB_FEATURES_WITH_USER) + (KBTS__OP_KIND_GPOS_FEATURES))); + + if(KBTS__IN_SET(Op, KBTS__SET32((KBTS__OP_KIND_GSUB_FEATURES) + (KBTS__OP_KIND_GSUB_FEATURES_WITH_USER) + (KBTS__OP_KIND_GPOS_FEATURES)))) + { + kbts__feature_stage *FeatureStage = &Result->OpList.FeatureStages[FeatureStageIndex]; + kbts_shaping_table ShapingTable = (kbts_shaping_table)((Op == KBTS__OP_KIND_GPOS_FEATURES) ? KBTS_SHAPING_TABLE_GPOS : KBTS_SHAPING_TABLE_GSUB); + kbts__gsub_gpos *GsubGpos = ShapingTables[ShapingTable]; + kbts__langsys *Langsys = Result->Langsys[ShapingTable]; + kbts_un BakedFeatureCount = 0; + kbts_un BakedFeatureLookupIndexCount = 0; + + kbts__baked_feature_stage *BakedStage = &BakedStages[FeatureStageIndex]; + + if(GsubGpos && Langsys) { - // Apparently, it is allowed to have script-specific GSUB tables, and a huge DFLT GPOS table. - FoundScriptIsIndic3 = Indic3; + kbts__feature_list *FeatureList = KBTS__POINTER_OFFSET(kbts__feature_list, GsubGpos, GsubGpos->FeatureListOffset); + kbts_u16 *FeatureIndices = KBTS__POINTER_AFTER(kbts_u16, Langsys); + kbts__baked_feature *BakedFeatures; + + // @Speed: Maybe we don't care about fragmentation and we just allocate Langsys->FeatureIndexCount in advance? + KBTS__FOR(FeatureIndexIndex, 0, Langsys->FeatureIndexCount) + { + kbts_un FeatureIndex = FeatureIndices[FeatureIndexIndex]; + kbts__feature_pointer Feature = kbts__GetFeature(FeatureList, FeatureIndex); + + kbts_u32 FeatureId = kbts__FeatureTagToId(Feature.Tag); + + if(Feature.Feature->LookupIndexCount && + ((UserFeaturesAllowed && + !kbts__ContainsFeature(&Result->Features, FeatureId)) || + kbts__ContainsFeature(&FeatureStage->Features, FeatureId))) + { + BakedFeatureCount += 1; + } + } + + kbts_un BakedFeatureCapacity = KBTS__MIN(BakedFeatureCount, KBTS_MAX_SIMULTANEOUS_FEATURES); + + BakedFeatures = kbts__PointerPushArray(&MemoryAt, kbts__baked_feature, BakedFeatureCapacity); + + BakedFeatureCount = 0; + + KBTS__FOR(FeatureIndexIndex, 0, Langsys->FeatureIndexCount) + { + kbts_un FeatureIndex = FeatureIndices[FeatureIndexIndex]; + kbts__feature_pointer Feature = kbts__GetFeature(FeatureList, FeatureIndex); + + kbts_u32 FeatureId = kbts__FeatureTagToId(Feature.Tag); + // We add all features indiscriminately for ops that might incorporate user features. + if(Feature.Feature->LookupIndexCount && + // We add "all" features to user feature stages, except for features that are a default part of the shaper. + // If a user asks for a default feature explicitly, it is unclear whether it should be applied now or in its + // default stage. + // Leaving the feature in its default stage seems like the better thing to do, because, supposedly, these features + // will have been designed to apply at a specific point in the pipeline, and moving them makes little sense. + ((UserFeaturesAllowed && + !kbts__ContainsFeature(&Result->Features, FeatureId)) || + kbts__ContainsFeature(&FeatureStage->Features, FeatureId))) + { + kbts__baked_feature BakedFeature = KBTS__ZERO; + BakedFeature.FeatureTag = Feature.Tag; + BakedFeature.FeatureId = FeatureId; + // CAREFUL: We use SkipFlags as a temporary index until the end of the stage. + BakedFeature.SkipFlags = kbts__SkipFlags(BakedFeature.FeatureId, Result->Shaper); + BakedFeature.Count = Feature.Feature->LookupIndexCount; + // These point directly into the file. + BakedFeature.Indices = KBTS__POINTER_AFTER(kbts_u16, Feature.Feature); + + // @Incomplete + //if(FeatureVariations) + //{ + // KBTS__FOR(VariationIndex, 0, FeatureVariations->RecordCount) + // { + // kbts__feature_variation_pointer Variation = kbts__GetFeatureVariation(FeatureVariations, VariationIndex); + // KBTS__FOR(ConditionIndex, 0, Variation.ConditionSet->Count) + // { + // kbts__condition_1 *Condition = kbts__GetCondition(Variation.ConditionSet, ConditionIndex); + // KBTS_ASSERT(0); + // } + // } + //} + + // For Myanmar, we could try and tag glyphs depending on their Indic properties in BeginCluster, just like we do for + // Indic scripts. + // However, Harfbuzz does _not_ do this, so it seems like a bunch of work that would, at best, make us diverge from + // Harfbuzz more often. + if((Result->Shaper != KBTS_SHAPER_MYANMAR) && (FeatureId >= 1) && (FeatureId <= 32)) + { + // These must properly map KBTS__FEATURE_ID to kbts_glyph_flags! + BakedFeature.GlyphFilter = (1 << (FeatureId - 1)) & KBTS__GLYPH_FEATURE_MASK; + } + + if(Memory) + { + BakedFeatures[BakedFeatureCount] = BakedFeature; + } + + BakedFeatureCount += 1; + BakedFeatureLookupIndexCount += BakedFeature.Count; + + if(BakedFeatureCount >= BakedFeatureCapacity) + { + break; + } + } + } + + kbts_u16 *OrderedFeatureIndices = kbts__PointerPushArray(&MemoryAt, kbts_u16, BakedFeatureLookupIndexCount); + kbts_u16 *BakedFeatureLookupIndicesRead = kbts__PointerPushArray(&MemoryAt, kbts_u16, BakedFeatureCount); + + if(Memory) + { + kbts_un OrderedFeatureIndicesWritten = 0; + + KBTS__FOR(BakedFeatureIndex, 0, BakedFeatureCount) + { + BakedFeatureLookupIndicesRead[BakedFeatureIndex] = 0; + } + + KBTS__FOR(OrderedLookupIndex, 0, BakedFeatureLookupIndexCount) + { + kbts_u16 LowestLookupIndex = 0xFFFF; + kbts_un BestBakedFeatureIndex = 0; + + KBTS__FOR(BakedFeatureIndex, 0, BakedFeatureCount) + { + kbts__baked_feature *BakedFeature = &BakedFeatures[BakedFeatureIndex]; + kbts_un LookupIndicesRead = BakedFeatureLookupIndicesRead[BakedFeatureIndex]; + + if(LookupIndicesRead < BakedFeature->Count) + { + kbts_u16 NextIndex = BakedFeature->Indices[LookupIndicesRead]; + + if(NextIndex < LowestLookupIndex) + { + LowestLookupIndex = NextIndex; + BestBakedFeatureIndex = BakedFeatureIndex; + } + } + } + + BakedFeatureLookupIndicesRead[BestBakedFeatureIndex] += 1; + OrderedFeatureIndices[OrderedFeatureIndicesWritten++] = (kbts_u16)BestBakedFeatureIndex; + } + + KBTS_ASSERT(OrderedFeatureIndicesWritten == BakedFeatureLookupIndexCount); + + BakedStage->FeatureCount = (kbts_u16)BakedFeatureCount; + BakedStage->FeatureIndexCount = (kbts_u16)BakedFeatureLookupIndexCount; + BakedStage->Features = BakedFeatures; + BakedStage->FeatureIndices = OrderedFeatureIndices; + } } - // And then get out if we found the appropriate script, even if the langsys is null! - if(PerfectMatch) + + KBTS_ASSERT(FeatureStageIndex < Result->OpList.FeatureStageCount); + FeatureStageIndex += 1; + } + } + + Result->FeatureStages = BakedStages; + } + } + + if(!Memory) + { + *Size = (kbts_un)(MemoryAt - (char *)Memory) + KBTS_ALIGNOF(kbts_shape_config); + Result = 0; + } + + return Result; +} + +KBTS_EXPORT int kbts_SizeOfShapeConfig(kbts_font *Font, kbts_script Script, kbts_language Language) +{ + kbts_un Size; + kbts__PlaceShapeConfig(Font, Script, Language, 0, &Size); + + return (int)Size; +} + +KBTS_EXPORT kbts_shape_config *kbts_PlaceShapeConfig(kbts_font *Font, kbts_script Script, kbts_language Language, void *Memory) +{ + kbts_un Size; + kbts_shape_config *Result = kbts__PlaceShapeConfig(Font, Script, Language, Memory, &Size); + return Result; +} + +KBTS_EXPORT kbts_shape_config *kbts_CreateShapeConfig(kbts_font *Font, kbts_script Script, kbts_language Language, kbts_allocator_function *Allocator, void *AllocatorData) +{ + if(!Allocator) + { + Allocator = kbts__DefaultAllocator; + } + + kbts_un Size; + kbts__PlaceShapeConfig(Font, Script, Language, 0, &Size); + kbts_shape_config *Result = kbts__PlaceShapeConfig(Font, Script, Language, kbts__AllocatorAllocate(Allocator, AllocatorData, Size), &Size); + if(Result) + { + Result->Allocator = Allocator; + Result->AllocatorData = AllocatorData; + } + + return Result; +} + +KBTS_EXPORT void kbts_DestroyShapeConfig(kbts_shape_config *Config) +{ + if(Config->Allocator) + { + kbts__AllocatorFree(Config->Allocator, Config->AllocatorData, Config); + } +} + +static int kbts__ReadOp(kbts__shape_scratchpad *Scratchpad, kbts_shape_config *Config, kbts__op_kind End) +{ + KBTS_INSTRUMENT_FUNCTION_BEGIN; + int Result = 0; + + if(Config) + { + kbts__op_list *OpList = &Config->OpList; + + if(Scratchpad->Ip < OpList->OpCount) + { + kbts__op_kind Kind = OpList->Ops[Scratchpad->Ip++]; + + if((Kind == KBTS__OP_KIND_GSUB_FEATURES_WITH_USER) || + (Kind == KBTS__OP_KIND_GSUB_FEATURES) || + (Kind == KBTS__OP_KIND_GPOS_FEATURES)) + { + kbts__feature_stage *FeatureStage = &OpList->FeatureStages[Scratchpad->FeatureStagesRead++]; + Scratchpad->OpFeatures = &FeatureStage->Features; + + // We only have one GPOS_FEATURES op per op list, so it's fine to add user features like this. + if((Kind == KBTS__OP_KIND_GSUB_FEATURES_WITH_USER) || + (Kind == KBTS__OP_KIND_GPOS_FEATURES)) + { + if(Kind == KBTS__OP_KIND_GSUB_FEATURES_WITH_USER) { + Kind = KBTS__OP_KIND_GSUB_FEATURES; + } + + KBTS__FOR(WordIndex, 0, KBTS__ARRAY_LENGTH(Scratchpad->ScratchFeatures.Flags)) + { + Scratchpad->ScratchFeatures.Flags[WordIndex] = Scratchpad->UserFeatures.Flags[WordIndex] | FeatureStage->Features.Flags[WordIndex]; + } + + Scratchpad->OpFeatures = &Scratchpad->ScratchFeatures; + } + } + + Scratchpad->OpKind = Kind; + Result = (Kind != End); + } + } + + KBTS_INSTRUMENT_FUNCTION_END; + return Result; +} + +KBTS_EXPORT int kbts_SizeOfShapeContext(void) +{ + int Result = sizeof(kbts_shape_context); + return Result; +} + +KBTS_EXPORT kbts_shape_context *kbts_PlaceShapeContext(kbts_allocator_function *Allocator, void *AllocatorData, void *Memory) +{ + kbts_shape_context *Result = (kbts_shape_context *)Memory; + + if(Memory) + { + if(!Allocator) + { + Allocator = kbts__DefaultAllocator; + } + + KBTS_MEMSET(Result, 0, sizeof(*Result)); + + Result->PermanentArena.Allocator = Allocator; + Result->PermanentArena.AllocatorData = AllocatorData; + + Result->FontArena.Allocator = Allocator; + Result->FontArena.AllocatorData = AllocatorData; + + Result->ConfigArena.Allocator = Allocator; + Result->ConfigArena.AllocatorData = AllocatorData; + + Result->ScratchArena.Allocator = Allocator; + Result->ScratchArena.AllocatorData = AllocatorData; + + Result->GlyphStorage.Arena.Allocator = Allocator; + Result->GlyphStorage.Arena.AllocatorData = AllocatorData; + + KBTS__DLLIST_SENTINEL_INIT(&Result->FeatureOverrideSentinel); + KBTS__DLLIST_SENTINEL_INIT(&Result->FreeFeatureOverrideSentinel); + } + + return Result; +} + +KBTS_EXPORT kbts_shape_context *kbts_PlaceShapeContextFixedMemory(void *Memory, int Size) +{ + kbts_shape_context *Result = 0; + kbts_un SizeOfShapeContext = kbts_SizeOfShapeContext(); + kbts_un ContextAndArenaSize = sizeof(kbts_arena) + SizeOfShapeContext; + + if((Size >= 0) && ((kbts_un)Size >= ContextAndArenaSize)) + { + kbts_arena *Arena = (kbts_arena *)KBTS__POINTER_OFFSET(kbts_arena, Memory, SizeOfShapeContext); + kbts__InitializeFixedMemoryArena(Arena, KBTS__POINTER_AFTER(void, Arena), (kbts_un)Size - ContextAndArenaSize); + + Result = kbts_PlaceShapeContext(kbts__ArenaAllocator, Arena, Memory); + } + + return Result; +} + +KBTS_EXPORT kbts_shape_context *kbts_CreateShapeContext(kbts_allocator_function *Allocator, void *AllocatorData) +{ + if(!Allocator) + { + Allocator = kbts__DefaultAllocator; + } + + kbts_shape_context *Result = kbts_PlaceShapeContext(Allocator, AllocatorData, kbts__AllocatorAllocate(Allocator, AllocatorData, (kbts_un)kbts_SizeOfShapeContext())); + Result->SelfAllocator = Allocator; + Result->SelfAllocatorData = AllocatorData; + return Result; +} + +KBTS_EXPORT void kbts_DestroyShapeContext(kbts_shape_context *Context) +{ + if(Context) + { + kbts__FreeArena(&Context->PermanentArena); + kbts__FreeArena(&Context->ConfigArena); + kbts__FreeArena(&Context->ScratchArena); + kbts__FreeArena(&Context->FontArena); + kbts__FreeArena(&Context->GlyphStorage.Arena); + + if(Context->SelfAllocator) + { + kbts__AllocatorFree(Context->SelfAllocator, Context->SelfAllocatorData, Context); + } + } +} + +KBTS_EXPORT kbts_direction kbts_ScriptDirection(kbts_script Script) +{ + kbts_direction Result = ((Script == KBTS_SCRIPT_ARABIC) || (Script == KBTS_SCRIPT_HEBREW)) ? KBTS_DIRECTION_RTL : KBTS_DIRECTION_LTR; + return Result; +} + +static kbts__context_font *kbts__ShapePushFont(kbts_shape_context *Context) +{ + kbts__context_font *Result = 0; + + if(!Context->Error && (Context->FontCount < KBTS_CONTEXT_MAX_FONT_COUNT)) + { + Result = &Context->Fonts[Context->FontCount++]; + Result->Font = 0; + Result->Lifetime = kbts__BeginLifetime(&Context->FontArena); + } + + return Result; +} + +KBTS_EXPORT kbts_font *kbts_ShapePushFont(kbts_shape_context *Context, kbts_font *Font) +{ + if(!Context->Error) + { + kbts__context_font *ContextFont = kbts__ShapePushFont(Context); + + if(ContextFont) + { + ContextFont->Font = Font; + } + } + + return Font; +} + +KBTS_EXPORT kbts_font *kbts_ShapePopFont(kbts_shape_context *Context) +{ + kbts_font *Result = 0; + + if(!Context->Error && Context->FontCount) + { + kbts__context_font *ContextFont = &Context->Fonts[Context->FontCount - 1]; + Result = ContextFont->Font; + + kbts__EndLifetime(&ContextFont->Lifetime); + + Context->FontCount -= 1; + } + + return Result; +} + +#ifndef KB_TEXT_SHAPE_NO_CRT +KBTS_EXPORT kbts_font *kbts_ShapePushFontFromFile(kbts_shape_context *Context, const char *FileName, int FontIndex) +{ + kbts__context_font *ContextFont = kbts__ShapePushFont(Context); + kbts_font *Result = 0; + + if(!Context->Error) + { + Result = kbts__PushType(&Context->FontArena, kbts_font); + if(Result) + { + *Result = kbts_FontFromFile(FileName, FontIndex, kbts__ArenaAllocator, &Context->FontArena, 0, 0); + + if(!Result->Error) + { + ContextFont->Font = Result; + } + else + { + kbts_ShapePopFont(Context); + Result = 0; + } + } + else + { + Context->Error = KBTS_SHAPE_ERROR_OUT_OF_MEMORY; + } + } + + return Result; +} +#endif + +KBTS_EXPORT kbts_font *kbts_ShapePushFontFromMemory(kbts_shape_context *Context, void *Memory, int Length, int FontIndex) +{ + kbts_font *Result = 0; + + if(!Context->Error && (Length > 0)) + { + kbts__context_font *ContextFont = kbts__ShapePushFont(Context); + + Result = kbts__PushType(&Context->FontArena, kbts_font); + + if(Result) + { + int ScratchSize, OutputSize; + kbts_load_font_state State = KBTS__ZERO; + kbts_load_font_error Error = kbts_LoadFont(Result, &State, Memory, Length, FontIndex, &ScratchSize, &OutputSize); + if(Error == KBTS_LOAD_FONT_ERROR_NEED_TO_CREATE_BLOB) + { + void *Scratch = kbts__PushSize(&Context->ScratchArena, (kbts_un)ScratchSize, 8); + void *Output = kbts__PushSize(&Context->FontArena, (kbts_un)OutputSize, 8); + + Error = kbts_PlaceBlob(Result, &State, Scratch, Output); + } + + if(!Error) + { + ContextFont->Font = Result; + } + else + { + kbts_ShapePopFont(Context); + Result = 0; + } + } + } + + return Result; +} + +static void kbts__EnsureGlyphStorageInitialized(kbts_glyph_storage *Storage) +{ + if(!Storage->GlyphSentinel.Next) + { + KBTS__DLLIST_SENTINEL_INIT(&Storage->GlyphSentinel); + KBTS__DLLIST_SENTINEL_INIT(&Storage->FreeGlyphSentinel); + } +} + +KBTS_EXPORT int kbts_InitializeGlyphStorage(kbts_glyph_storage *Storage, kbts_allocator_function *Allocator, void *AllocatorData) +{ + int Result = 0; + + if(Storage) + { + Result = 1; + KBTS_MEMSET(Storage, 0, sizeof(*Storage)); + + Storage->Arena.Allocator = Allocator; + Storage->Arena.AllocatorData = AllocatorData; + } + + return Result; +} + +KBTS_EXPORT int kbts_InitializeGlyphStorageFixedMemory(kbts_glyph_storage *Storage, void *Memory, int MemorySize) +{ + int Result = 0; + + if(Storage && + (MemorySize > 0)) + { + KBTS_MEMSET(Storage, 0, sizeof(*Storage)); + + Result = kbts__InitializeFixedMemoryArena(&Storage->Arena, Memory, (kbts_un)MemorySize); + } + + return Result; +} + +KBTS_EXPORT kbts_glyph_iterator kbts_ActiveGlyphIterator(kbts_glyph_storage *Storage) +{ + kbts_glyph_iterator Result = KBTS__ZERO; + + if(Storage && !Storage->Error) + { + kbts__EnsureGlyphStorageInitialized(Storage); + + Result.GlyphStorage = Storage; + Result.CurrentGlyph = Storage->GlyphSentinel.Next; + } + + return Result; +} + +KBTS_EXPORT void kbts_ClearActiveGlyphs(kbts_glyph_storage *Storage) +{ + if(!Storage->Error) + { + kbts__EnsureGlyphStorageInitialized(Storage); + + kbts_glyph *First = Storage->GlyphSentinel.Next; + kbts_glyph *Last = Storage->GlyphSentinel.Prev; + + if(kbts__GlyphIsValid(Storage, First)) + { + // Free all previous glyphs. + First->Prev = Storage->FreeGlyphSentinel.Prev; + Last->Next = &Storage->FreeGlyphSentinel; + First->Prev->Next = First; + Last->Next->Prev = Last; + } + + KBTS__DLLIST_SENTINEL_INIT(&Storage->GlyphSentinel); + } +} + +KBTS_EXPORT void kbts_FreeAllGlyphs(kbts_glyph_storage *Storage) +{ + kbts__FreeArena(&Storage->Arena); + + KBTS__DLLIST_SENTINEL_INIT(&Storage->GlyphSentinel); + KBTS__DLLIST_SENTINEL_INIT(&Storage->FreeGlyphSentinel); +} + +KBTS_EXPORT kbts_glyph *kbts_PushGlyph(kbts_glyph_storage *Storage, kbts_font *Font, int Codepoint, kbts_glyph_config *Config, int UserId) +{ + kbts_glyph *Result = 0; + + if(!Storage->Error) + { + kbts__EnsureGlyphStorageInitialized(Storage); + + kbts_glyph Template = KBTS__ZERO; + if(Font) + { + Template = kbts_CodepointToGlyph(Font, Codepoint, Config, UserId); + } + else + { + Template.Codepoint = (kbts_u32)Codepoint; + Template.Config = Config; + // We do not want to use the template's UserId here, because it is just a bag of properties! + // We want to keep the original UserId. + } + + Result = kbts__InsertGlyphBefore(Storage, &Storage->GlyphSentinel, &Template); + } + + return Result; +} + +static int kbts__FeatureOverrideIsExtra(kbts_u32 Tag, int Value) +{ + int Result = 0; + kbts__feature_id Id = kbts__FeatureTagToId(Tag); + + if(!Id || (kbts_u32)(Value > 1)) + { + Result = 1; + } + + return Result; +} + +static void kbts__AddExtraFeatureOverride(kbts_glyph_config *Config, kbts__feature_override *Extra, kbts_u32 Tag, int Value) +{ + Extra->Tag = Tag; + Extra->Value = Value; + + KBTS__DLLIST_INSERT_BEFORE(&Extra->Header, &Config->FeatureOverrideSentinel); +} + +KBTS_EXPORT int kbts_SizeOfGlyphConfig(kbts_feature_override *Overrides, int OverrideCount) +{ + kbts_un StoredOverrideCount = 0; + + if(OverrideCount > 0) + { + KBTS__FOR(OverrideIndex, 0, (kbts_un)OverrideCount) + { + kbts_feature_override *Override = &Overrides[OverrideIndex]; + + if(kbts__FeatureOverrideIsExtra(Override->Tag, Override->Value)) + { + StoredOverrideCount += 1; + } + } + } + + kbts_un Result = sizeof(kbts_glyph_config) + StoredOverrideCount * sizeof(kbts__feature_override); + return (int)Result; +} + +KBTS_EXPORT kbts_glyph_config *kbts_PlaceGlyphConfig(kbts_feature_override *Overrides, int OverrideCount, void *Memory) +{ + kbts_glyph_config *Result = (kbts_glyph_config *)Memory; + if(Memory) + { + KBTS_MEMSET(Result, 0, sizeof(*Result)); + KBTS__DLLIST_SENTINEL_INIT(&Result->FeatureOverrideSentinel); + + kbts__feature_override *ExtraOverrides = KBTS__POINTER_AFTER(kbts__feature_override, Result); + + if(OverrideCount > 0) + { + KBTS__FOR(OverrideIndex, 0, (kbts_un)OverrideCount) + { + kbts_feature_override *Override = &Overrides[OverrideIndex]; + kbts__feature_id Id = kbts__FeatureTagToId(Override->Tag); + + if(kbts__FeatureOverrideIsExtra(Override->Tag, Override->Value)) + { + kbts__feature_override *ExtraOverride = &ExtraOverrides[Result->ExtraOverrideCount++]; + + kbts__AddExtraFeatureOverride(Result, ExtraOverride, Override->Tag, Override->Value); + } + + kbts__AddFeature((Override->Value) ? &Result->EnabledFeatures : &Result->DisabledFeatures, Id); + } + + if(Result->ExtraOverrideCount) + { + kbts__feature_override *Last = &ExtraOverrides[Result->ExtraOverrideCount - 1]; + Last->Header.Next = &Result->FeatureOverrideSentinel; + Result->FeatureOverrideSentinel.Prev = &Last->Header; + } + } + } + + return Result; +} + +KBTS_EXPORT kbts_glyph_config *kbts_CreateGlyphConfig(kbts_feature_override *Overrides, int OverrideCount, kbts_allocator_function *Allocator, void *AllocatorData) +{ + if(!Allocator) + { + Allocator = kbts__DefaultAllocator; + } + + kbts_glyph_config *Result = kbts_PlaceGlyphConfig(Overrides, OverrideCount, kbts__AllocatorAllocate(Allocator, AllocatorData, (kbts_un)kbts_SizeOfGlyphConfig(Overrides, OverrideCount))); + + if(Result) + { + Result->Allocator = Allocator; + Result->AllocatorData = AllocatorData; + } + + return Result; +} + +KBTS_EXPORT void kbts_DestroyGlyphConfig(kbts_glyph_config *Config) +{ + if(Config && Config->Allocator) + { + kbts__AllocatorFree(Config->Allocator, Config->AllocatorData, Config); + } +} + +KBTS_EXPORT kbts_shape_error kbts_ShapeError(kbts_shape_context *Context) +{ + kbts_shape_error Result = Context->Error; + return Result; +} + +KBTS_EXPORT void kbts_ShapeBegin(kbts_shape_context *Context, kbts_direction ParagraphDirection, kbts_language Language) +{ + if(!Context->Error) + { + kbts__ClearArena(&Context->ScratchArena); + kbts_ClearActiveGlyphs(&Context->GlyphStorage); + + Context->BreakStartIndex = 0; + Context->CurrentGlyphConfig = 0; + Context->NeedNewGlyphConfig = 1; + + Context->ParagraphDirection = ParagraphDirection; + Context->Language = Language; + Context->UserFeatures = KBTS__ZERO_TYPE(kbts__feature_set); + + Context->InputCodepointCount = 0; + Context->NextUserId = 0; + Context->LastGraphemeBreak = 0; + Context->LastLineBreakIndex = 0; + Context->RunFont = 0; + Context->RunScript = 0; + Context->RunDirection = 0; + Context->ExistingShapeConfigCount = 0; + + kbts_BreakBegin(&Context->BreakState, ParagraphDirection, KBTS_JAPANESE_LINE_BREAK_STYLE_NORMAL, 0); + } +} + +typedef struct kbts__input_codepoint_index +{ + kbts_u32 BlockIndex; + kbts_u32 CodepointIndex; + kbts_u32 BlockCodepointCount; +} kbts__input_codepoint_index; + +static kbts__input_codepoint_index kbts__InputCodepointIndex(kbts_un FlatCodepointIndex) +{ + kbts__input_codepoint_index Result = KBTS__ZERO; + + kbts_un MsbPosition = kbts__MsbPositionOrZero32((kbts_u32)FlatCodepointIndex); + if(MsbPosition <= KBTS__INPUT_CODEPOINT_FIRST_BLOCK_MSB) + { + Result.BlockIndex = 0; + Result.CodepointIndex = (kbts_u32)FlatCodepointIndex; + Result.BlockCodepointCount = 1 << (KBTS__INPUT_CODEPOINT_FIRST_BLOCK_MSB + 1); + } + else + { + Result.BlockIndex = (kbts_u32)(MsbPosition - KBTS__INPUT_CODEPOINT_FIRST_BLOCK_MSB); + Result.CodepointIndex = (kbts_u32)(FlatCodepointIndex & ~(1 << MsbPosition)); + Result.BlockCodepointCount = (kbts_u32)(1 << MsbPosition); + } + + return Result; +} + +static kbts_shape_codepoint *kbts__InputCodepoint(kbts_shape_context *Context, kbts_un Index) +{ + kbts_shape_codepoint *Result = 0; + + if(!Context->Error) + { + kbts__input_codepoint_index InputIndex = kbts__InputCodepointIndex(Index); + + kbts_shape_codepoint *Block = Context->InputBlocks[InputIndex.BlockIndex]; + if(!Block) + { + Block = kbts__PushArray(&Context->PermanentArena, kbts_shape_codepoint, InputIndex.BlockCodepointCount); + if(!Block) + { + Context->Error = KBTS_SHAPE_ERROR_OUT_OF_MEMORY; + return Result; + } + + Context->InputBlocks[InputIndex.BlockIndex] = Block; + } + + Result = &Context->InputBlocks[InputIndex.BlockIndex][InputIndex.CodepointIndex]; + } + + return Result; +} + +static kbts_shape_codepoint_iterator kbts__InputCodepointIterator(kbts_shape_context *Context, kbts_un StartCodepointIndex, kbts_un OnePastLastCodepointIndex) +{ + kbts_shape_codepoint_iterator Result = KBTS__ZERO; + + if(Context && + !Context->Error && + (OnePastLastCodepointIndex > StartCodepointIndex)) + { + kbts__input_codepoint_index StartInputIndex = kbts__InputCodepointIndex(StartCodepointIndex); + kbts__input_codepoint_index OnePastLastInputIndex = kbts__InputCodepointIndex(OnePastLastCodepointIndex); + + Result.Context = Context; + Result.BlockIndex = StartInputIndex.BlockIndex; + Result.CodepointIndex = StartInputIndex.CodepointIndex; + Result.EndBlockIndex = OnePastLastInputIndex.BlockIndex; + Result.OnePastLastCodepointIndex = OnePastLastInputIndex.CodepointIndex; + Result.CurrentBlockCodepointCount = (Result.BlockIndex == Result.EndBlockIndex) ? Result.OnePastLastCodepointIndex : StartInputIndex.BlockCodepointCount; + Result.FlatCodepointIndex = (kbts_u32)StartCodepointIndex; + } + + return Result; +} + +KBTS_EXPORT kbts_shape_codepoint_iterator kbts_ShapeCurrentCodepointsIterator(kbts_shape_context *Context) +{ + kbts_shape_codepoint_iterator Result = kbts__InputCodepointIterator(Context, 0, Context->InputCodepointCount); + + return Result; +} + +static int kbts__NextInputCodepoint(kbts_shape_codepoint_iterator *It, int *CodepointIndex) +{ + int Result = 0; + + if(It->CodepointIndex >= It->CurrentBlockCodepointCount) + { + It->BlockIndex += 1; + It->CodepointIndex = 0; + It->CurrentBlockCodepointCount = (It->BlockIndex == It->EndBlockIndex) ? It->OnePastLastCodepointIndex : (1 << (It->BlockIndex + KBTS__INPUT_CODEPOINT_FIRST_BLOCK_MSB)); + } + + if(It->BlockIndex <= It->EndBlockIndex) + { + if(CodepointIndex) + { + *CodepointIndex = (int)It->FlatCodepointIndex; + } + + It->Codepoint = &It->Context->InputBlocks[It->BlockIndex][It->CodepointIndex++]; + It->FlatCodepointIndex += 1; + + Result = 1; + } + + return Result; +} + +KBTS_EXPORT int kbts_ShapeCodepointIteratorIsValid(kbts_shape_codepoint_iterator *It) +{ + int Result = It->Context && (It->BlockIndex <= It->EndBlockIndex); + return Result; +} + +KBTS_EXPORT int kbts_ShapeCodepointIteratorNext(kbts_shape_codepoint_iterator *It, kbts_shape_codepoint *Codepoint, int *CodepointIndex) +{ + int Result = kbts__NextInputCodepoint(It, CodepointIndex); + + if(Result) + { + *Codepoint = *It->Codepoint; + } + + return Result; +} + +KBTS_EXPORT int kbts_ShapeGetShapeCodepoint(kbts_shape_context *Context, int CodepointIndex, kbts_shape_codepoint *Codepoint) +{ + int Result = 0; + + if((CodepointIndex >= 0) && + ((kbts_un)CodepointIndex < Context->InputCodepointCount)) + { + kbts_shape_codepoint *Source = kbts__InputCodepoint(Context, (kbts_un)CodepointIndex); + *Codepoint = *Source; + + Result = 1; + } + + return Result; +} + +static void kbts__UpdateBreaks(kbts_shape_context *Context) +{ + if(!(Context->Flags & KBTS__CONTEXT_FLAG_MANUAL_SEGMENTATION)) + { + kbts_break Break; + while(kbts_Break(&Context->BreakState, &Break)) + { + // Strictly speaking, we do not need all of the flags, but we record them all anyway so we can expose them to the user. + kbts_un BreakPosition = (kbts_u32)Break.Position + Context->BreakStartIndex; + kbts_shape_codepoint *InputCodepoint = kbts__InputCodepoint(Context, BreakPosition); + + if(Break.Flags & KBTS_BREAK_FLAG_LINE_HARD) + { + Context->LastLineBreakIndex = (kbts_u32)BreakPosition; + } + + if(Break.Flags & KBTS_BREAK_FLAG_GRAPHEME) + { + // Try fonts, potentially break run. + kbts_font *MatchFont = 0; + + for(kbts_un FontIndex = Context->FontCount; + FontIndex; + --FontIndex) + { + kbts_font *Font = Context->Fonts[FontIndex - 1].Font; + kbts_font_coverage_test CoverageTest; + kbts_FontCoverageTestBegin(&CoverageTest, Font); + + kbts_shape_codepoint_iterator It = kbts__InputCodepointIterator(Context, Context->LastGraphemeBreakIndex, BreakPosition); + + while(kbts__NextInputCodepoint(&It, 0)) + { + kbts_shape_codepoint *GraphemeCodepoint = It.Codepoint; + + kbts_FontCoverageTestCodepoint(&CoverageTest, GraphemeCodepoint->Codepoint); + } + + kbts_FontCoverageTestEnd(&CoverageTest); + + if(!CoverageTest.Error) + { + MatchFont = Font; + break; } } + + Context->LastGraphemeBreak->Font = MatchFont; + Context->LastGraphemeBreak = InputCodepoint; + Context->LastGraphemeBreakIndex = (kbts_u32)BreakPosition; } - Result.Langsys[ShapingTableIndex] = ChosenLangsys; + InputCodepoint->BreakFlags |= Break.Flags; + if(Break.Flags & KBTS_BREAK_FLAG_SCRIPT) + { + InputCodepoint->Script = Break.Script; + } + if(Break.Flags & KBTS_BREAK_FLAG_DIRECTION) + { + InputCodepoint->Direction = Break.Direction; + } + if(Break.Flags & KBTS_BREAK_FLAG_PARAGRAPH_DIRECTION) + { + InputCodepoint->ParagraphDirection = Break.ParagraphDirection; + } } } +} - Result.IndicScriptProperties = kbts_IndicScriptProperties(Script); - Result.Shaper = FoundScriptIsIndic3 ? KBTS_SHAPER_USE : ScriptProperties->Shaper; - Result.OpLists[0] = kbts_ShaperOpLists[Result.Shaper]; - - switch(Result.Shaper) +KBTS_EXPORT void kbts_ShapeBeginManualRuns(kbts_shape_context *Context) +{ + if(!Context->Error) { - case KBTS_SHAPER_INDIC: - Result.OpLists[1] = KBTS_OP_LIST(Indic1); - Result.OpLists[2] = KBTS_OP_LIST(Indic2); - Result.OpLists[3] = KBTS_OP_LIST(Indic3); - break; - case KBTS_SHAPER_USE: - Result.OpLists[1] = KBTS_OP_LIST(Use1); - Result.OpLists[3] = KBTS_OP_LIST(Use3); - break; - case KBTS_SHAPER_KHMER: - Result.OpLists[1] = KBTS_OP_LIST(Khmer1); - Result.OpLists[3] = KBTS_OP_LIST(Khmer3); - break; - case KBTS_SHAPER_MYANMAR: - Result.OpLists[1] = KBTS_OP_LIST(Myanmar1); - Result.OpLists[2] = KBTS_OP_LIST(Myanmar2); - Result.OpLists[3] = KBTS_OP_LIST(Myanmar3); - break; - } - - Result.Features = &kbts_ShaperFeatures[Result.Shaper]; - - kbts_feature *Rclt = 0; - kbts_feature_set SyllableFeatureSet = {{KBTS_FEATURE_FLAG0(rphf) | KBTS_FEATURE_FLAG0(blwf) | KBTS_FEATURE_FLAG0(half) | KBTS_FEATURE_FLAG0(pstf) | KBTS_FEATURE_FLAG0(pref), - 0, KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(locl), KBTS_FEATURE_FLAG3(vatu)}}; - kbts_iterate_features IterateFeatures = kbts_IterateFeatures(&Result, KBTS_SHAPING_TABLE_GSUB, SyllableFeatureSet); - while(kbts_NextFeature(&IterateFeatures)) - { - switch(IterateFeatures.CurrentFeatureTag) + if(Context->InputCodepointCount > 0) { - case KBTS_FEATURE_TAG_blwf: Result.Blwf = IterateFeatures.Feature; break; - case KBTS_FEATURE_TAG_pref: Result.Pref = IterateFeatures.Feature; break; - case KBTS_FEATURE_TAG_pstf: Result.Pstf = IterateFeatures.Feature; break; - case KBTS_FEATURE_TAG_locl: Result.Locl = IterateFeatures.Feature; break; - case KBTS_FEATURE_TAG_rphf: Result.Rphf = IterateFeatures.Feature; break; - case KBTS_FEATURE_TAG_half: Result.Half = IterateFeatures.Feature; break; - case KBTS_FEATURE_TAG_vatu: Result.Vatu = IterateFeatures.Feature; break; - case KBTS_FEATURE_TAG_rclt: Rclt = IterateFeatures.Feature; break; + kbts_BreakEnd(&Context->BreakState); + kbts__UpdateBreaks(Context); + } + + Context->Flags |= KBTS__CONTEXT_FLAG_MANUAL_SEGMENTATION; + } +} + +KBTS_EXPORT void kbts_ShapeNextManualRun(kbts_shape_context *Context, kbts_direction Direction, kbts_script Script) +{ + if(!Context->Error && + (Context->Flags & KBTS__CONTEXT_FLAG_MANUAL_SEGMENTATION)) + { + Context->Flags |= KBTS__CONTEXT_FLAG_START_OF_MANUAL_RUN | KBTS__CONTEXT_FLAG_USE_MANUAL_BREAK_INFO; + + Context->ManualRunDirection = Direction; + Context->ManualRunScript = Script; + } +} + +KBTS_EXPORT void kbts_ShapeEndManualRuns(kbts_shape_context *Context) +{ + if(!Context->Error && + (Context->Flags & KBTS__CONTEXT_FLAG_MANUAL_SEGMENTATION)) + { + Context->Flags &= ~KBTS__CONTEXT_FLAG_MANUAL_SEGMENTATION; + + if(Context->InputCodepointCount > 0) + { + kbts_BreakBegin(&Context->BreakState, Context->ParagraphDirection, KBTS_JAPANESE_LINE_BREAK_STYLE_NORMAL, 0); + Context->BreakStartIndex = (kbts_u32)Context->InputCodepointCount; } } +} - if((Result.Shaper == KBTS_SHAPER_ARABIC) && !Rclt) +KBTS_EXPORT void kbts_ShapeManualBreak(kbts_shape_context *Context) +{ + kbts_ShapeBeginManualRuns(Context); + Context->Flags |= KBTS__CONTEXT_FLAG_START_OF_MANUAL_RUN; + kbts_ShapeEndManualRuns(Context); +} + +KBTS_EXPORT void kbts_ShapeCodepointWithUserId(kbts_shape_context *Context, int Codepoint, int UserId) +{ + if(!Context->Error) { - Result.OpLists[0] = KBTS_OP_LIST(ArabicNoRclt); + if(Context->NeedNewGlyphConfig) + { + kbts_glyph_config *Config = kbts__PushType(&Context->ScratchArena, kbts_glyph_config); + if(!Config) + { + Context->Error = KBTS_SHAPE_ERROR_OUT_OF_MEMORY; + return; + } + + *Config = KBTS__ZERO_TYPE(kbts_glyph_config); + KBTS__DLLIST_SENTINEL_INIT(&Config->FeatureOverrideSentinel); + + kbts__feature_set Features = KBTS__ZERO; + for(kbts__feature_override_header *OverrideHeader = Context->FeatureOverrideSentinel.Prev; + OverrideHeader != &Context->FeatureOverrideSentinel; + OverrideHeader = OverrideHeader->Prev) + { + kbts__feature_override *Override = (kbts__feature_override *)OverrideHeader; + kbts__feature_id Id = kbts__FeatureTagToId(Override->Tag); + + if(!Id || !kbts__ContainsFeature(&Features, Id)) + { + if(kbts__FeatureOverrideIsExtra(Override->Tag, Override->Value)) + { + kbts__feature_override *Insert = kbts__PushType(&Context->ScratchArena, kbts__feature_override); + if(!Insert) + { + Context->Error = KBTS_SHAPE_ERROR_OUT_OF_MEMORY; + return; + } + + kbts__AddExtraFeatureOverride(Config, Insert, Override->Tag, Override->Value); + } + + kbts__AddFeature(&Features, Id); + kbts__AddFeature((Override->Value) ? &Config->EnabledFeatures : &Config->DisabledFeatures, Id); + } + } + + Context->CurrentGlyphConfig = Config; + Context->NeedNewGlyphConfig = 0; + } + + { // Add the codepoint. + kbts_un FlatCodepointIndex = Context->InputCodepointCount; + kbts_shape_codepoint InputCodepoint = KBTS__ZERO; + InputCodepoint.Codepoint = Codepoint; + InputCodepoint.UserId = UserId; + InputCodepoint.Config = Context->CurrentGlyphConfig; + + // @Robustness: There is probably a saner way of doing this. + // When we do a manual break, we may have line breaks go out-of-bounds, and we + // do not want to lose that information. + if(FlatCodepointIndex && + (FlatCodepointIndex == Context->LastLineBreakIndex)) + { + InputCodepoint.BreakFlags |= KBTS_BREAK_FLAG_LINE; + } + + if(Context->Flags & KBTS__CONTEXT_FLAG_START_OF_MANUAL_RUN) + { + InputCodepoint.BreakFlags |= KBTS_BREAK_FLAG_MANUAL; + + if(Context->Flags & KBTS__CONTEXT_FLAG_USE_MANUAL_BREAK_INFO) + { + InputCodepoint.Direction = Context->ManualRunDirection; + InputCodepoint.Script = Context->ManualRunScript; + } + + Context->Flags &= ~KBTS__CONTEXT_FLAG_START_OF_MANUAL_RUN; + } + + kbts_shape_codepoint *To = kbts__InputCodepoint(Context, FlatCodepointIndex); + if(To) + { + *To = InputCodepoint; + } + + if(!Context->LastGraphemeBreak) + { + Context->LastGraphemeBreak = To; + } + + Context->InputCodepointCount += 1; + } + + if(!(Context->Flags & KBTS__CONTEXT_FLAG_MANUAL_SEGMENTATION)) + { + // Check for breaks. + kbts_BreakAddCodepoint(&Context->BreakState, Codepoint, 1, 0); + + kbts__UpdateBreaks(Context); + } } - - kbts_shape_state DummyState = KBTS_ZERO; - DummyState.Config = &Result; - - if(Result.IndicScriptProperties.ViramaCodepoint) +} +static void kbts__ShapeCodepoint(kbts_shape_context *Context, int Codepoint, int UserIdIncrement) +{ + int UserId = Context->NextUserId; + Context->NextUserId += UserIdIncrement; + kbts_ShapeCodepointWithUserId(Context, Codepoint, UserId); +} +KBTS_EXPORT void kbts_ShapeCodepoint(kbts_shape_context *Context, int Codepoint) +{ + if(!Context->Error) { - // Bake the locl-ized virama. - kbts_glyph Virama = kbts_CodepointToGlyph(Font, Result.IndicScriptProperties.ViramaCodepoint); - Result.Virama = kbts_Substitute1(&DummyState, kbts_GetLookupList(Gsub), Result.Locl, KBTS_SKIP_FLAG_ZWNJ | KBTS_SKIP_FLAG_ZWJ, &Virama); + kbts__ShapeCodepoint(Context, Codepoint, 1); } +} - if((Result.Script == KBTS_SCRIPT_THAI) || (Result.Script == KBTS_SCRIPT_LAO)) +KBTS_EXPORT void kbts_ShapeUtf32WithUserId(kbts_shape_context *Context, int *Utf32, int Length, int BaseUserId, int UserIdIncrement) +{ + if(!Context->Error && (Length > 0)) { - kbts_u32 NikhahitCodepoint = (Result.Script == KBTS_SCRIPT_THAI) ? 0xE4D : 0xECD; - kbts_u32 SaraAaCodepoint = (Result.Script == KBTS_SCRIPT_THAI) ? 0xE32 : 0xEB2; - Result.Nikhahit = kbts_CodepointToGlyph(Font, NikhahitCodepoint); - Result.SaraAa = kbts_CodepointToGlyph(Font, SaraAaCodepoint); - } + int UserId = BaseUserId; - Result.DottedCircle = kbts_CodepointToGlyph(Font, 0x25CC); - Result.Whitespace = kbts_CodepointToGlyph(Font, ' '); + KBTS__FOR(Utf32Index, 0, (kbts_un)Length) + { + int Codepoint = Utf32[Utf32Index]; + kbts_ShapeCodepointWithUserId(Context, Codepoint, UserId); + + UserId += UserIdIncrement; + } + } +} +KBTS_EXPORT void kbts_ShapeUtf32(kbts_shape_context *Context, int *Utf32, int Length) +{ + if(!Context->Error && (Length > 0)) + { + KBTS__FOR(Utf32Index, 0, (kbts_un)Length) + { + int Codepoint = Utf32[Utf32Index]; + kbts_ShapeCodepoint(Context, Codepoint); + } + } +} + +KBTS_EXPORT void kbts_ShapeUtf8WithUserId(kbts_shape_context *Context, const char *Utf8, int Length, int BaseUserId, kbts_user_id_generation_mode UserIdGenerationMode) +{ + if(!Context->Error && (Length > 0)) + { + const char *At = Utf8; + const char *End = Utf8 + Length; + int UserId = BaseUserId; + + int CodepointIncrement = (UserIdGenerationMode == KBTS_USER_ID_GENERATION_MODE_CODEPOINT_INDEX) ? 1 : 0; + int SourceCharacterMask = (UserIdGenerationMode == KBTS_USER_ID_GENERATION_MODE_SOURCE_INDEX) ? ~0 : 0; + + while(At < End) + { + kbts_decode Decode = kbts_DecodeUtf8(At, (kbts_un)(End - At)); + + if(Decode.Valid) + { + kbts_ShapeCodepointWithUserId(Context, Decode.Codepoint, UserId); + + UserId += CodepointIncrement; + } + + At += Decode.SourceCharactersConsumed; + UserId += Decode.SourceCharactersConsumed & SourceCharacterMask; + } + } +} +KBTS_EXPORT void kbts_ShapeUtf8(kbts_shape_context *Context, const char *Utf8, int Length, kbts_user_id_generation_mode UserIdGenerationMode) +{ + if(!Context->Error && (Length > 0)) + { + const char *At = Utf8; + const char *End = Utf8 + Length; + while(At < End) + { + kbts_decode Decode = kbts_DecodeUtf8(At, (kbts_un)(End - At)); + + if(Decode.Valid) + { + int Increment = 0; + if(UserIdGenerationMode == KBTS_USER_ID_GENERATION_MODE_CODEPOINT_INDEX) + { + Increment = 1; + } + else if(UserIdGenerationMode == KBTS_USER_ID_GENERATION_MODE_SOURCE_INDEX) + { + Increment = Decode.SourceCharactersConsumed; + } + + kbts__ShapeCodepoint(Context, Decode.Codepoint, Increment); + } + + At += Decode.SourceCharactersConsumed; + } + } +} + +KBTS_EXPORT void kbts_ShapePushFeature(kbts_shape_context *Context, kbts_u32 Tag, int Value) +{ + if(!Context->Error) + { + kbts__feature_override *Override; + kbts__feature_override_header *Header = Context->FreeFeatureOverrideSentinel.Prev; + if(Header != &Context->FreeFeatureOverrideSentinel) + { + Override = (kbts__feature_override *)Header; + } + else + { + Override = kbts__PushType(&Context->PermanentArena, kbts__feature_override); + } + + KBTS__DLLIST_INSERT_BEFORE(&Override->Header, &Context->FeatureOverrideSentinel); + Override->Tag = Tag; + Override->Value = Value; + + kbts__feature_id Id = kbts__FeatureTagToId(Tag); + kbts__AddFeature(&Context->UserFeaturesEnabled, Id); + + Context->NeedNewGlyphConfig = 1; + } +} + +KBTS_EXPORT int kbts_ShapePopFeature(kbts_shape_context *Context, kbts_u32 Tag) +{ + int Result = 0; + + if(!Context->Error) + { + for(kbts__feature_override_header *Header = Context->FeatureOverrideSentinel.Prev; + Header != &Context->FeatureOverrideSentinel; + Header = Header->Prev) + { + kbts__feature_override *Override = (kbts__feature_override *)Header; + + if(Override->Tag == Tag) + { + Result = 1; + + KBTS__DLLIST_REMOVE(Header); + KBTS__DLLIST_INSERT_BEFORE(Header, &Context->FreeFeatureOverrideSentinel); + + break; + } + } + + if(Result) + { + Context->NeedNewGlyphConfig = 1; + } + } return Result; } -static kbts_op kbts_ReadOp(kbts_shape_state *State, kbts_u8 *Ops) +static void kbts__ShapeDirect(kbts__shape_scratchpad *Scratchpad, kbts_shape_config *Config, kbts_glyph_storage *Storage) { - kbts_op Result = KBTS_ZERO; - Result.Kind = Ops[State->Ip++]; - - if(Result.Kind == KBTS_OP_KIND_GSUB_FEATURES_WITH_USER) - { - Result.Kind = KBTS_OP_KIND_GSUB_FEATURES; - Result.Features = State->UserFeatures; - } - - if((Result.Kind == KBTS_OP_KIND_GSUB_FEATURES) || (Result.Kind == KBTS_OP_KIND_GPOS_FEATURES)) - { - kbts_un FeatureCount = Ops[State->Ip++]; - int Rtl = (State->RunDirection == KBTS_DIRECTION_RTL); - KBTS_FOR(FeatureIndex, 0, FeatureCount) - { - kbts_u32 FeatureId = Ops[State->Ip++]; - - if((FeatureId == KBTS_FEATURE_ID_ltra) && Rtl) - { - FeatureId = KBTS_FEATURE_ID_rtla; - } - else if((FeatureId == KBTS_FEATURE_ID_ltrm) && Rtl) - { - FeatureId = KBTS_FEATURE_ID_rtlm; - } - - kbts_AddFeature(&Result.Features, FeatureId); - } - } - return Result; -} - -KBTS_EXPORT int kbts_Shape(kbts_shape_state *State, kbts_shape_config *Config, kbts_direction MainDirection, kbts_direction RunDirection, kbts_glyph *Glyphs, kbts_u32 *GlyphCount, kbts_u32 GlyphCapacity) -{ - KBTS_INSTRUMENT_FUNCTION_BEGIN - State->Config = Config; - State->MainDirection = MainDirection; - State->RunDirection = RunDirection; - - kbts_glyph_array *GlyphArray = &State->GlyphArray; - // The Glyphs array might move after a grow, so update the pointers here. - // We preserve Count information, though, because it makes it simpler not to touch anything - // when we are dealing with sub-arrays like Cluster. - GlyphArray->Glyphs = Glyphs; - GlyphArray->Capacity = GlyphCapacity; - kbts_glyph_array *Cluster = &State->ClusterGlyphArray; - Cluster->Glyphs = Glyphs + State->At; - Cluster->Capacity = GlyphCapacity - State->At; - - kbts_u32 ResumePoint = State->ResumePoint; - State->ResumePoint = 0; - switch(ResumePoint) - { - case 1: goto ResumePoint1; break; - case 2: goto ResumePoint2; break; - case 3: goto ResumePoint3; break; - case 4: goto ResumePoint4; break; - case 5: goto ResumePoint5; break; - case 6: goto ResumePoint6; break; - } - - *GlyphArray = kbts_GlyphArray(Glyphs, *GlyphCount, *GlyphCount, GlyphCapacity); + KBTS_INSTRUMENT_BLOCK_BEGIN(ReadOpLoop0); // For simple shapers, all of the shaping happens in this single loop. // For complex shapers, this loop is preparing the text for clustering logic, which happens below. - for(State->Ip = 0; State->Ip < Config->OpLists[0].Length;) + while(kbts__ReadOp(Scratchpad, Config, KBTS__OP_KIND_BEGIN_CLUSTER)) { - State->Op = kbts_ReadOp(State, Config->OpLists[0].Ops); - ResumePoint1:; - if(kbts_ExecuteOp(State, GlyphArray)) + kbts__ExecuteOp(Scratchpad, Config, Storage); + + if(Scratchpad->Error) { - State->ResumePoint = 1; - goto GrowRequest; + return; } } - if(KBTS_IN_SET(Config->Shaper, KBTS_SET32((KBTS_SHAPER_INDIC)(KBTS_SHAPER_USE)(KBTS_SHAPER_KHMER)(KBTS_SHAPER_MYANMAR)))) + KBTS_INSTRUMENT_BLOCK_END(ReadOpLoop0); + + if(Scratchpad->OpKind == KBTS__OP_KIND_BEGIN_CLUSTER) { - State->ClusterAtStartOfWord = 1; - State->At = 0; - while(State->At < GlyphArray->Count) + kbts_u32 BeginClusterIp = Scratchpad->Ip; + kbts_u32 BeginClusterFeatureStagesRead = Scratchpad->FeatureStagesRead; + kbts_glyph *TopLevelGlyph = Storage->GlyphSentinel.Next; + + Scratchpad->ClusterAtStartOfWord = 1; + + while(kbts__GlyphIsValid(Storage, TopLevelGlyph)) { - if(KBTS_IN_SET(Config->Shaper, KBTS_SET32((KBTS_SHAPER_INDIC)(KBTS_SHAPER_KHMER)))) + int WordBreak = 0; + + Scratchpad->Ip = BeginClusterIp; + Scratchpad->FeatureStagesRead = BeginClusterFeatureStagesRead; + { - // Reserve a slot in case we need to insert a dotted circle into a broken syllable. - ResumePoint2:; - if(!kbts_GrowGlyphArray(&State->ResumePoint, GlyphArray, GlyphArray->Count, 1, 2, 1)) + // We need to store this in case TopLevelGlyph is reordered. + kbts_glyph *OneBeforeFirstClusterGlyph = TopLevelGlyph->Prev; + kbts_glyph *OnePastLastClusterGlyph = kbts__BeginCluster(Scratchpad, Config, Storage, TopLevelGlyph); + + if(Scratchpad->Error) { - goto GrowRequest; + return; + } + + WordBreak = !(OnePastLastClusterGlyph->Prev->UnicodeFlags & KBTS_UNICODE_FLAG_PART_OF_WORD); + Scratchpad->Cluster = kbts__PushGlyphList(Storage, OneBeforeFirstClusterGlyph->Next, OnePastLastClusterGlyph->Prev); + } + + while(kbts__ReadOp(Scratchpad, Config, KBTS__OP_KIND_END_CLUSTER)) + { + kbts__ExecuteOp(Scratchpad, Config, Storage); + + if(Scratchpad->Error) + { + return; } } - { - kbts_begin_cluster_result BeginClusterResult = kbts_BeginCluster(State, Glyphs + State->At, GlyphArray->Count - State->At); - GlyphArray->Count += BeginClusterResult.InsertedGlyphCount; - GlyphArray->TotalCount += BeginClusterResult.InsertedGlyphCount; - State->ClusterGlyphCount = (kbts_u32)BeginClusterResult.ClusterGlyphCount; - *Cluster = kbts_GlyphArray(Glyphs + State->At, BeginClusterResult.ClusterGlyphCount, GlyphArray->Count - State->At, GlyphCapacity - State->At); - } + kbts__EndCluster(Scratchpad, Config, Storage); - kbts_glyph *LastGlyphInCluster; LastGlyphInCluster = &Glyphs[State->At + Cluster->Count - 1]; - State->WordBreak = !(LastGlyphInCluster->UnicodeFlags & KBTS_UNICODE_FLAG_PART_OF_WORD); - - for(State->Ip = 0; State->Ip < Config->OpLists[1].Length;) + while(kbts__ReadOp(Scratchpad, Config, KBTS__OP_KIND_END_SYLLABLE)) { - State->Op = kbts_ReadOp(State, Config->OpLists[1].Ops); - ResumePoint3:; - if(kbts_ExecuteOp(State, Cluster)) + kbts__ExecuteOp(Scratchpad, Config, Storage); + + if(Scratchpad->Error) { - State->ResumePoint = 3; - goto GrowRequest; + return; } } - kbts_end_cluster_result EndClusterResult; EndClusterResult = kbts_EndCluster(State, Cluster); - if(EndClusterResult.InsertDottedCircle) - { - State->DottedCircleInsertIndex = (kbts_u32)EndClusterResult.DottedCircleIndex; - ResumePoint6:; - if(!kbts_GrowGlyphArray(&State->ResumePoint, Cluster, State->DottedCircleInsertIndex, 1, 6, 0)) - { - State->RequiredGlyphCapacity = Cluster->RequiredCapacity + State->At; - goto GrowRequest; - } - Glyphs[State->At + State->DottedCircleInsertIndex] = Config->DottedCircle; - } + // Reattach the cluster to the main list. + Storage->GlyphSentinel.Next->Prev = Scratchpad->Cluster.OneBeforeFirst; + Storage->GlyphSentinel.Prev->Next = Scratchpad->Cluster.OnePastLast; + TopLevelGlyph = Scratchpad->Cluster.OnePastLast; - for(State->Ip = 0; State->Ip < Config->OpLists[2].Length;) - { - State->Op = kbts_ReadOp(State, Config->OpLists[2].Ops); - ResumePoint4:; - if(kbts_ExecuteOp(State, Cluster)) - { - State->ResumePoint = 4; - goto GrowRequest; - } - } + kbts__PopGlyphList(Storage, &Scratchpad->Cluster); - State->At += Cluster->Count; - kbts_un DeltaClusterGlyphCount = Cluster->Count - State->ClusterGlyphCount; - GlyphArray->Count += DeltaClusterGlyphCount; - GlyphArray->TotalCount += DeltaClusterGlyphCount; - State->ClusterAtStartOfWord = State->WordBreak; + Scratchpad->ClusterAtStartOfWord = WordBreak; } // Post-clustering ops work across clusters. // This is where Indic GPOS + post-passes happen. - for(State->Ip = 0; State->Ip < Config->OpLists[3].Length;) + while(kbts__ReadOp(Scratchpad, Config, 0)) { - State->Op = kbts_ReadOp(State, Config->OpLists[3].Ops); - ResumePoint5:; - if(kbts_ExecuteOp(State, GlyphArray)) + kbts__ExecuteOp(Scratchpad, Config, Storage); + + if(Scratchpad->Error) { - State->ResumePoint = 5; - goto GrowRequest; + return; } } } - if(0) + KBTS_INSTRUMENT_FUNCTION_END; +} + +KBTS_EXPORT kbts_shape_error kbts_ShapeDirect(kbts_shape_config *Config, kbts_glyph_storage *Storage, kbts_direction RunDirection, kbts_allocator_function *Allocator, void *AllocatorData, kbts_glyph_iterator *Output) +{ + if(!Allocator) { - GrowRequest:; - kbts_TransferGrowRequest(Cluster, GlyphArray); - State->RequiredGlyphCapacity = GlyphArray->RequiredCapacity; - KBTS_INSTRUMENT_END - return 1; + Allocator = kbts__DefaultAllocator; } - *GlyphCount = GlyphArray->Count; - KBTS_INSTRUMENT_END - return 0; -} + kbts_arena Arena = KBTS__ZERO; + Arena.Allocator = Allocator; + Arena.AllocatorData = AllocatorData; -KBTS_EXPORT kbts_cursor kbts_Cursor(kbts_direction Direction) -{ - kbts_cursor Result = KBTS_ZERO; - Result.Direction = Direction; - return Result; -} + kbts__shape_scratchpad *Scratchpad = kbts__PushType(&Arena, kbts__shape_scratchpad); + KBTS_MEMSET(Scratchpad, 0, sizeof(*Scratchpad)); + Scratchpad->Arena = &Arena; + Scratchpad->RunDirection = RunDirection; -KBTS_EXPORT void kbts_PositionGlyph(kbts_cursor *Cursor, kbts_glyph *Glyph, kbts_s32 *X, kbts_s32 *Y) -{ - kbts_s32 AdvanceX = Glyph->AdvanceX; - kbts_s32 AdvanceY = Glyph->AdvanceY; - kbts_s32 OffsetX = Glyph->OffsetX; - kbts_s32 OffsetY = Glyph->OffsetY; - if(Cursor->Direction != KBTS_DIRECTION_RTL) + kbts__ShapeDirect(Scratchpad, Config, Storage); + kbts_shape_error Result = Scratchpad->Error; + + if(!Result) { - *X = Cursor->X + OffsetX; - *Y = Cursor->Y + OffsetY; - - Cursor->X += AdvanceX; - Cursor->Y += AdvanceY; + *Output = kbts_ActiveGlyphIterator(Storage); } else { - // Right-to-left should, in theory, work almost identically to left-to-right: just right-align everything. - // However, the convention for glyph bounding boxes, etc., is that they are left-aligned. - // To compensate for this, we add base glyphs' advances to their positions, which should left-align them. - // We can't accumulate the advances immediately into the cursor, though, because then mark offsets will be wrong. - // - // By the way, Harfbuzz just reverses glyphs to always be left-to-right for the sake of layout. - // The reason we try to handle right-to-left somewhat properly here is that it allows the user to position one - // glyph at a time by just going through the glyph sequence, no matter the text direction. - // This should hopefully save the user from having to allocate a buffer of glyph positions and/or doing a pre-pass - // just to get the total string width, in the case of cross-direction text. - // - // The classic Harfbuzz behavior can be obtained by passing MainDirection = LTR to Shape, even for RTL text. - // (Cursor.Direction also needs to be NONE or LTR, of course, which is the default.) - if(AdvanceX) + *Output = KBTS__ZERO_TYPE(kbts_glyph_iterator); + } + + kbts__FreeArena(&Arena); + + return Result; +} + +KBTS_EXPORT kbts_shape_error kbts_ShapeDirectFixedMemory(kbts_shape_config *Config, kbts_glyph_storage *Storage, kbts_direction RunDirection, void *Memory, int MemorySize, kbts_glyph_iterator *Output) +{ + kbts_shape_error Result = 0; + + if(Config && Storage && !Storage->Error && Memory && (MemorySize > 0)) + { + kbts_arena Arena; + + if(kbts__InitializeFixedMemoryArena(&Arena, Memory, (kbts_un)MemorySize)) { - Cursor->X -= Cursor->LastAdvanceX; - Cursor->LastAdvanceX = AdvanceX; + Result = kbts_ShapeDirect(Config, Storage, RunDirection, kbts__ArenaAllocator, &Arena, Output); } + } - *X = Cursor->X - AdvanceX + OffsetX; - *Y = Cursor->Y + OffsetY; + return Result; +} - Cursor->Y += AdvanceY; +static void kbts__BeginParagraph(kbts_shape_context *Context) +{ + Context->RunFont = 0; + if(Context->FontCount) + { + Context->RunFont = Context->Fonts[Context->FontCount - 1].Font; + } + + Context->RunScript = 0; + Context->RunParagraphDirection = 0; + Context->RunDirection = 0; +} + +KBTS_EXPORT void kbts_ShapeEnd(kbts_shape_context *Context) +{ + if(!Context->Error) + { + // We check the break flags of the one-past-last codepoint, so reset it here. + kbts_shape_codepoint *OnePastLastCodepoint = kbts__InputCodepoint(Context, Context->InputCodepointCount); + *OnePastLastCodepoint = KBTS__ZERO_TYPE(kbts_shape_codepoint); + + kbts_BreakEnd(&Context->BreakState); + kbts__UpdateBreaks(Context); + + Context->RunCodepointIterator.Context = 0; + Context->DoneShapingRuns = 0; + + kbts__BeginParagraph(Context); } } -KBTS_EXPORT kbts_un kbts_ReadFontHeader(kbts_font *Font, void *Data, kbts_un Size) +KBTS_EXPORT int kbts_ShapeRun(kbts_shape_context *Context, kbts_run *Run) { - KBTS_UNUSED(Size); - kbts_un Result = 0; - if(Size >= sizeof(kbts_table_directory)) + int Result = 0; + + if(!Context->Error && + !Context->DoneShapingRuns) { - char *FileEnd = (char *)Data + Size; - Font->FileBase = (char *)Data; - Font->FileSize = Size; - kbts_table_directory *Directory = (kbts_table_directory *)Font->FileBase; + kbts_font *RunFont = Context->RunFont; + kbts_script RunScript = Context->RunScript; + kbts_direction RunParagraphDirection = Context->RunParagraphDirection; + kbts_direction RunDirection = Context->RunDirection; + kbts_language Language = Context->Language; - Directory->TableCount = kbts_ByteSwap16(Directory->TableCount); - Directory->SearchRange = kbts_ByteSwap16(Directory->SearchRange); - Directory->EntrySelector = kbts_ByteSwap16(Directory->EntrySelector); - Directory->RangeShift = kbts_ByteSwap16(Directory->RangeShift); + Run->Flags = 0; - kbts_table_record *Tables = KBTS_POINTER_AFTER(kbts_table_record, Directory); + kbts_ClearActiveGlyphs(&Context->GlyphStorage); - kbts_un ShapingTableSizes[KBTS_SHAPING_TABLE_COUNT] = {0}; - kbts_u32 GdefSize = 0; - kbts_un DirectoryTableCapacity = (FileEnd - (char *)Tables) / sizeof(kbts_table_record); - if(Directory->TableCount <= DirectoryTableCapacity) + int Initialized = 1; + + if(!Context->RunCodepointIterator.Context) { - for(kbts_un TableIndex = 0; TableIndex < Directory->TableCount; ++TableIndex) + Context->RunCodepointIterator = kbts__InputCodepointIterator(Context, 0, Context->InputCodepointCount); + Initialized = 0; + } + + kbts_shape_codepoint_iterator *It = &Context->RunCodepointIterator; + + if(kbts_ShapeCodepointIteratorIsValid(It)) + { + int InputCodepointIndex = 0; + while(kbts__NextInputCodepoint(It, &InputCodepointIndex)) { - kbts_table_record *Table = &Tables[TableIndex]; - Table->Checksum = kbts_ByteSwap32(Table->Checksum); - Table->Offset = kbts_ByteSwap32(Table->Offset); - Table->Length = kbts_ByteSwap32(Table->Length); - int TableValid = 0; + kbts_shape_codepoint *InputCodepoint = It->Codepoint; - void *TableBase = KBTS_POINTER_OFFSET(void, Font->FileBase, Table->Offset); - char *TableEnd = (char *)TableBase + Table->Length; - if(((char *)TableBase >= (char *)(Tables + Directory->TableCount)) && (TableEnd <= FileEnd)) + // Resolve neutral directions. + if((InputCodepoint->BreakFlags & KBTS_BREAK_FLAG_DIRECTION) && + (InputCodepoint->Direction == KBTS_DIRECTION_DONT_KNOW)) { - switch(Table->Tag) + InputCodepoint->Direction = RunParagraphDirection; + } + + int First = !Result; + Result = 1; + + kbts_font *CodepointFont = InputCodepoint->Font; + kbts_script CodepointScript = InputCodepoint->Script; + kbts_direction CodepointDirection = InputCodepoint->Direction; + kbts_direction CodepointParagraphDirection = InputCodepoint->ParagraphDirection; + kbts_break_flags CodepointBreakFlags = InputCodepoint->BreakFlags; + + int NewLine = !First && (CodepointBreakFlags & (KBTS_BREAK_FLAG_LINE_HARD | KBTS_BREAK_FLAG_MANUAL)); + + if(First) + { + Run->Flags = CodepointBreakFlags; + + if(CodepointBreakFlags & KBTS_BREAK_FLAG_LINE_HARD) { - case KBTS_FOURCC('h', 'e', 'a', 'd'): - { - if(Table->Length >= sizeof(kbts_head)) - { - kbts_head *Head = (kbts_head *)TableBase; - kbts_ByteSwapArray16Unchecked(&Head->Major, 2); - kbts_ByteSwapArray32Unchecked(&Head->Revision, 2); - // We do not swap the magic number. - kbts_ByteSwapArray16Unchecked(&Head->Flags, 2); - // We do not swap file times. - kbts_ByteSwapArray16Unchecked((kbts_u16 *)&Head->XMin, 9); + kbts__BeginParagraph(Context); + RunFont = Context->RunFont; + RunScript = 0; + RunDirection = 0; - Font->Head = Head; - TableValid = 1; - } - } break; - - case KBTS_FOURCC('c', 'm', 'a', 'p'): - { - if(Table->Length >= sizeof(kbts_cmap)) - { - kbts_cmap *Cmap = (kbts_cmap *)TableBase; - Cmap->Version = kbts_ByteSwap16(Cmap->Version); - Cmap->TableCount = kbts_ByteSwap16(Cmap->TableCount); - - kbts_encoding_record *Records = KBTS_POINTER_AFTER(kbts_encoding_record, Cmap); - - if((char *)(Records + Cmap->TableCount) <= TableEnd) - { - KBTS_FOR(It, 0, Cmap->TableCount) - { - kbts_encoding_record *Record = &Records[It]; - Record->EncodingId = kbts_ByteSwap16(Record->EncodingId); - Record->PlatformId = kbts_ByteSwap16(Record->PlatformId); - Record->SubtableOffset = kbts_ByteSwap32(Record->SubtableOffset); - } - - kbts_cmap_subtable_pointer PreferredSubtable = KBTS_ZERO; - kbts_u16 PreferredFormat = 1; - KBTS_FOR(It, 0, Cmap->TableCount) - { - kbts_cmap_subtable_pointer Subtable = kbts_GetCmapSubtable(Cmap, It); - if((char *)(Subtable.Subtable + 1) <= TableEnd) - { - kbts_u16 Format = kbts_ByteSwap16(*Subtable.Subtable); - - if(Format == 14) - { - if((char *)(Subtable.Subtable + sizeof(kbts_cmap_14)) <= TableEnd) - { - Font->Cmap14 = (kbts_cmap_14 *)Subtable.Subtable; - } - } - else if(!PreferredSubtable.Subtable) - { - PreferredSubtable = Subtable; - } - else if(Format < KBTS_ARRAY_LENGTH(kbts_CmapFormatPrecedence)) - { - kbts_u16 Precedence = kbts_CmapFormatPrecedence[Format]; - kbts_u16 PreferredPrecedence = kbts_CmapFormatPrecedence[PreferredFormat]; - - if((Precedence > PreferredPrecedence) || ((Precedence == PreferredPrecedence) && (Subtable.PlatformId == 3))) - { - PreferredSubtable = Subtable; - PreferredFormat = Format; - } - } - } - } - - if(PreferredSubtable.Subtable) - { - *PreferredSubtable.Subtable = kbts_ByteSwap16(*PreferredSubtable.Subtable); - switch(*PreferredSubtable.Subtable) - { - case 0: - { - kbts_cmap_0 *Cmap0 = (kbts_cmap_0 *)PreferredSubtable.Subtable; - if((char *)(Cmap0 + 1) <= TableEnd) - { - Cmap0->Length = kbts_ByteSwap16(Cmap0->Length); - Cmap0->Language = kbts_ByteSwap16(Cmap0->Language); - TableValid = 1; - } - } - break; - - case 2: - { - kbts_cmap_2 *Cmap2 = (kbts_cmap_2 *)PreferredSubtable.Subtable; - if(kbts_ByteSwapArray16(&Cmap2->Length, 258, TableEnd)) - { - kbts_un SubHeaderCount = 0; - KBTS_FOR(It, 0, 256) - { - kbts_un SubHeaderIndex = Cmap2->SubHeaderKeys[It]; - SubHeaderCount = KBTS_MAX(SubHeaderCount, SubHeaderIndex + 1); - } - - kbts_sub_header *SubHeaders = KBTS_POINTER_AFTER(kbts_sub_header, Cmap2); - if(kbts_ByteSwapArray16(&SubHeaders->FirstCode, 4 * SubHeaderCount, TableEnd)) - { - kbts_u16 *GlyphIds = (kbts_u16 *)(SubHeaders + SubHeaderCount); - - kbts_sn GlyphIdCount = 0; - KBTS_FOR(It, 0, SubHeaderCount) - { - kbts_sub_header *SubHeader = &SubHeaders[It]; - - kbts_u16 *OnePastLastGlyphId = &SubHeader->IdRangeOffset + SubHeader->IdRangeOffset / 2 + SubHeader->EntryCount; - GlyphIdCount = KBTS_MAX(GlyphIdCount, OnePastLastGlyphId - GlyphIds); - } - - if(kbts_ByteSwapArray16(GlyphIds, (kbts_un)GlyphIdCount, TableEnd)) - { - TableValid = 1; - } - } - } - } - break; - - case 4: - { - kbts_cmap_4 *Cmap4 = (kbts_cmap_4 *)PreferredSubtable.Subtable; - if(kbts_ByteSwapArray16(&Cmap4->Length, 5, TableEnd) && - kbts_ByteSwapArray16(KBTS_POINTER_AFTER(kbts_u16, Cmap4), Cmap4->SegmentCountTimesTwo * 2 + 1, TableEnd)) - { - kbts_un SegmentCount = Cmap4->SegmentCountTimesTwo / 2; - kbts_u16 *EndCodes = KBTS_POINTER_AFTER(kbts_u16, Cmap4); - kbts_u16 *StartCodes = EndCodes + SegmentCount + 1; - kbts_s16 *IdDeltas = (kbts_s16 *)(StartCodes + SegmentCount); - kbts_u16 *IdRangeOffsets = (kbts_u16 *)(IdDeltas + SegmentCount); - kbts_u16 *GlyphIds = IdRangeOffsets + SegmentCount; - - kbts_sn GlyphIdCount = 0; - - KBTS_FOR(SegmentIndex, 0, SegmentCount) - { - kbts_u16 Offset = IdRangeOffsets[SegmentIndex]; - - if(Offset) - { - kbts_u16 *IdLookup = &IdRangeOffsets[SegmentIndex] + (EndCodes[SegmentIndex] - StartCodes[SegmentIndex] + 1) + Offset / 2; - - GlyphIdCount = KBTS_MAX(GlyphIdCount, (IdLookup - GlyphIds)); - } - } - - if(kbts_ByteSwapArray16(GlyphIds, (kbts_un)GlyphIdCount, TableEnd)) - { - TableValid = 1; - } - } - } - break; - - case 6: - { - kbts_cmap_6 *Cmap6 = (kbts_cmap_6 *)PreferredSubtable.Subtable; - if(kbts_ByteSwapArray16(&Cmap6->Length, 4, TableEnd) && - kbts_ByteSwapArray16(KBTS_POINTER_AFTER(kbts_u16, Cmap6), Cmap6->EntryCount, TableEnd)) - { - TableValid = 1; - } - } - break; - - case 12: - { - kbts_cmap_12_13 *Cmap12 = (kbts_cmap_12_13 *)PreferredSubtable.Subtable; - if(kbts_ByteSwapArray32(&Cmap12->Length, 3, TableEnd) && - kbts_ByteSwapArray32(KBTS_POINTER_AFTER(kbts_u32, Cmap12), Cmap12->GroupCount * 3, TableEnd)) - { - TableValid = 1; - } - } - break; - } - - Font->Cmap = PreferredSubtable.Subtable; - } - } - } - } - break; - - case KBTS_FOURCC('G', 'D', 'E', 'F'): - { - kbts_gdef *Gdef = (kbts_gdef *)TableBase; - GdefSize = Table->Length; - - if(kbts_ByteSwapArray16(&Gdef->Major, 6, TableEnd)) - { - if(Gdef->Minor >= 2) - { - if(Table->Length >= 14) - { - Gdef->MarkGlyphSetsDefinitionOffset = kbts_ByteSwap16(Gdef->MarkGlyphSetsDefinitionOffset); - - if(Gdef->Minor == 3) - { - if(Table->Length >= sizeof(kbts_gdef)) - { - // @Incomplete - Gdef->ItemVariationStoreOffset = kbts_ByteSwap32(Gdef->ItemVariationStoreOffset); - TableValid = 1; - } - } - else - { - TableValid = 1; - } - } - } - else - { - TableValid = 1; - } - } - - Font->Gdef = Gdef; - } - break; - - case KBTS_FOURCC('G', 'S', 'U', 'B'): - case KBTS_FOURCC('G', 'P', 'O', 'S'): - { - // We do not do any bounds checking here because Gsub/Gpos tables get byteswapped later on, - // in ByteSwapGsubGposCommon. - kbts_un Index = (Table->Tag == KBTS_FOURCC('G', 'S', 'U', 'B')) ? KBTS_SHAPING_TABLE_GSUB : KBTS_SHAPING_TABLE_GPOS; - Font->ShapingTables[Index] = (kbts_gsub_gpos *)TableBase; - ShapingTableSizes[Index] = Table->Length; - TableValid = 1; - } break; - - case KBTS_FOURCC('h', 'h', 'e', 'a'): - case KBTS_FOURCC('v', 'h', 'e', 'a'): - { - kbts_un Orientation = Table->Tag == KBTS_FOURCC('h', 'h', 'e', 'a') ? KBTS_ORIENTATION_HORIZONTAL : KBTS_ORIENTATION_VERTICAL; - kbts_hea *Hea = (kbts_hea *)TableBase; - if(kbts_ByteSwapArray16((kbts_u16 *)Hea, sizeof(kbts_hea) / sizeof(kbts_u16), TableEnd)) - { - Font->Hea[Orientation] = Hea; - TableValid = 1; - } - } break; - - case KBTS_FOURCC('h', 'm', 't', 'x'): - case KBTS_FOURCC('v', 'm', 't', 'x'): - { - kbts_un Orientation = Table->Tag == KBTS_FOURCC('h', 'm', 't', 'x') ? KBTS_ORIENTATION_HORIZONTAL : KBTS_ORIENTATION_VERTICAL; - kbts_u16 *Mtx = (kbts_u16 *)TableBase; - kbts_ByteSwapArray16Unchecked(Mtx, Table->Length / sizeof(kbts_u16)); - Font->Mtx[Orientation] = Mtx; - TableValid = 1; - } break; - - case KBTS_FOURCC('m', 'a', 'x', 'p'): - { - if(Table->Length >= 6) - { - Font->Maxp = (kbts_maxp *)TableBase; - Font->Maxp->Major = kbts_ByteSwap16(Font->Maxp->Major); - Font->Maxp->Minor = kbts_ByteSwap16(Font->Maxp->Minor); - - kbts_un U16Count = 0; - if(!Font->Maxp->Major && (Font->Maxp->Minor == 0x5000)) - { - U16Count = 1; - } - else if((Font->Maxp->Major == 1) && !Font->Maxp->Minor) - { - U16Count = 14; - } - - if(kbts_ByteSwapArray16(&Font->Maxp->GlyphCount, U16Count, TableEnd)) - { - Font->GlyphCount = Font->Maxp->GlyphCount; - TableValid = 1; - } - } - } break; - - default: - { - TableValid = 1; - } break; + // If we see a bunch of whitespace at the beginning of a paragraph, + // we want to merge with the first actual text that shows up. + Initialized = 0; } } - if(!TableValid) + if((CodepointFont && (CodepointFont != RunFont)) || + (CodepointScript && (CodepointScript != RunScript)) || + (CodepointDirection && (CodepointDirection != RunDirection)) || + (CodepointParagraphDirection && (CodepointParagraphDirection != RunParagraphDirection)) || + NewLine) { - goto Error; + if(CodepointFont) + { + Context->RunFont = CodepointFont; + } + if(CodepointScript) + { + Context->RunScript = CodepointScript; + } + if(CodepointDirection) + { + Context->RunDirection = CodepointDirection; + } + if(CodepointParagraphDirection) + { + Context->RunParagraphDirection = CodepointParagraphDirection; + } + + if(Initialized || NewLine) + { + // Rewind the current codepoint. + // We could also try to peek the codepoint before advancing, but this seems fine. + if(!It->CodepointIndex) + { + It->BlockIndex -= 1; + It->CodepointIndex = (1 << (It->BlockIndex + KBTS__INPUT_CODEPOINT_FIRST_BLOCK_MSB)) - 1; + } + else + { + It->CodepointIndex -= 1; + } + + It->FlatCodepointIndex -= 1; + + goto FoundBreak; + } + else + { + // Initialize and keep matching. + RunFont = Context->RunFont; + RunScript = Context->RunScript; + RunDirection = Context->RunDirection; + RunParagraphDirection = Context->RunParagraphDirection; + + kbts_PushGlyph(&Context->GlyphStorage, RunFont, InputCodepoint->Codepoint, InputCodepoint->Config, InputCodepointIndex); + + Initialized = 1; + } + } + else + { + kbts_PushGlyph(&Context->GlyphStorage, RunFont, InputCodepoint->Codepoint, InputCodepoint->Config, InputCodepointIndex); + } + } + + FoundBreak:; + + if(Result) + { + kbts_shape_config *Config = 0; + KBTS__FOR(ExistingConfigIndex, 0, Context->ExistingShapeConfigCount) + { + kbts__existing_shape_config *Existing = &Context->ExistingShapeConfigs[ExistingConfigIndex]; + + if((Existing->Font == RunFont) && + (Existing->Script == RunScript)) + { + Config = Existing->Config; + + break; + } + } + + if(!Config) + { + Config = kbts_CreateShapeConfig(RunFont, RunScript, Language, kbts__ArenaAllocator, &Context->ScratchArena); + + if(Context->ExistingShapeConfigCount < KBTS__ARRAY_LENGTH(Context->ExistingShapeConfigs)) + { + kbts__existing_shape_config *NewExisting = &Context->ExistingShapeConfigs[Context->ExistingShapeConfigCount++]; + + NewExisting->Config = Config; + NewExisting->Font = RunFont; + NewExisting->Script = RunScript; + } + } + + if(!RunDirection) + { + RunDirection = KBTS_DIRECTION_LTR; + + if((Config->Shaper == KBTS_SHAPER_ARABIC) || + (Config->Shaper == KBTS_SHAPER_HEBREW)) + { + RunDirection = KBTS_DIRECTION_RTL; + } + } + + kbts__shape_scratchpad *Scratchpad = kbts__PushType(&Context->ScratchArena, kbts__shape_scratchpad); + KBTS_MEMSET(Scratchpad, 0, sizeof(*Scratchpad)); + Scratchpad->Arena = &Context->ScratchArena; + Scratchpad->RunDirection = RunDirection; + + kbts__ShapeDirect(Scratchpad, Config, &Context->GlyphStorage); + + if(Scratchpad->Error) + { + Context->Error = Scratchpad->Error; } } } else { - goto Error; + kbts_shape_codepoint *OnePastLast = kbts__InputCodepoint(Context, Context->InputCodepointCount); + + if(OnePastLast->BreakFlags & KBTS_BREAK_FLAG_LINE_HARD) + { + // Signal the terminating line break with a 0-sized run. + Run->Flags = OnePastLast->BreakFlags; + + Result = 1; + } + + Context->DoneShapingRuns = 1; } - if(kbts_FontIsValid(Font)) + if(Result) { - Result = sizeof(kbts_u32) * ((ShapingTableSizes[KBTS_SHAPING_TABLE_GSUB] + ShapingTableSizes[KBTS_SHAPING_TABLE_GPOS] + GdefSize) / 2); + Run->Font = RunFont; + Run->Script = RunScript; + Run->ParagraphDirection = RunParagraphDirection; + Run->Direction = RunDirection; + Run->Glyphs = kbts_ActiveGlyphIterator(&Context->GlyphStorage); } } - else - { - goto Error; - } - if(0) - { - Error:; - Font->Error = 1; - } - - return (kbts_u32)Result; -} - -KBTS_EXPORT kbts_un kbts_ReadFontData(kbts_font *Font, void *Scratch, kbts_un ScratchSize) -{ - kbts_un Result = 0; - if(kbts_FontIsValid(Font)) - { - kbts_byteswap_context ByteSwapContext = KBTS_ZERO; - ByteSwapContext.FileBase = Font->FileBase; - ByteSwapContext.FileEnd = Font->FileBase + Font->FileSize; - ByteSwapContext.PointerCapacity = ScratchSize / sizeof(kbts_u32); - ByteSwapContext.Pointers = (kbts_u32 *)Scratch; - - kbts_un TotalLookupCount = 0; - kbts_un TotalSubtableCount = 0; - - kbts_gdef *Gdef = Font->Gdef; - if(Gdef) - { - if(Gdef->ClassDefinitionOffset) - { - kbts_u16 *ClassDefBase = KBTS_POINTER_OFFSET(kbts_u16, Gdef, Gdef->ClassDefinitionOffset); - kbts_ByteSwapClassDefinition(&ByteSwapContext, ClassDefBase); - } - - if(Gdef->MarkAttachmentClassDefinitionOffset) - { - kbts_u16 *ClassDefBase = KBTS_POINTER_OFFSET(kbts_u16, Gdef, Gdef->MarkAttachmentClassDefinitionOffset); - kbts_ByteSwapClassDefinition(&ByteSwapContext, ClassDefBase); - } - - if((Gdef->Minor >= 2) && Gdef->MarkGlyphSetsDefinitionOffset) - { - kbts_mark_glyph_sets *MarkGlyphSets = KBTS_POINTER_OFFSET(kbts_mark_glyph_sets, Gdef, Gdef->MarkGlyphSetsDefinitionOffset); - kbts_ByteSwapArray16Context(&MarkGlyphSets->Format, 2, &ByteSwapContext); - if(MarkGlyphSets->Format == 1) - { - kbts_u32 *CoverageOffsets = KBTS_POINTER_AFTER(kbts_u32, MarkGlyphSets); - kbts_ByteSwapArray32Context(CoverageOffsets, MarkGlyphSets->MarkGlyphSetCount, &ByteSwapContext); - - KBTS_FOR(MarkGlyphSetIndex, 0, MarkGlyphSets->MarkGlyphSetCount) - { - kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, MarkGlyphSets, CoverageOffsets[MarkGlyphSetIndex]); - kbts_ByteSwapCoverage(&ByteSwapContext, Coverage); - } - } - } - } - - kbts_gsub_gpos *Gsub = Font->ShapingTables[KBTS_SHAPING_TABLE_GSUB]; - if(Gsub) - { - kbts_ByteSwapGsubGposCommon(&ByteSwapContext, Gsub); - - kbts_lookup_list *LookupList = kbts_GetLookupList(Gsub); - LookupList->Count = kbts_ByteSwap16(LookupList->Count); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, LookupList), LookupList->Count, &ByteSwapContext); - - TotalLookupCount += LookupList->Count; - - KBTS_FOR(LookupIndex, 0, LookupList->Count) - { - kbts_lookup *PackedLookup = kbts_GetLookup(LookupList, LookupIndex); - - KBTS_DUMPF("GSUB Lookup %llu:\n", LookupIndex); - - if(kbts_ByteSwapLookup(&ByteSwapContext, PackedLookup)) - { - kbts_unpacked_lookup Lookup = kbts_UnpackLookup(Font->Gdef, PackedLookup); - KBTS_DUMPF(" Flags %u\n", Lookup.Flags); - - KBTS_FOR(SubstitutionIndex, 0, Lookup.SubtableCount) - { - kbts_u16 *Base = KBTS_POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[SubstitutionIndex]); - - KBTS_DUMPF(" Subtable %llu:\n", SubstitutionIndex); - - kbts_ByteSwapGsubLookupSubtable(&ByteSwapContext, Lookup.Type, Base); - } - } - - TotalSubtableCount += PackedLookup->SubtableCount; - } - } - - kbts_gsub_gpos *Gpos = Font->ShapingTables[KBTS_SHAPING_TABLE_GPOS]; - if(Gpos) - { - kbts_ByteSwapGsubGposCommon(&ByteSwapContext, Gpos); - - kbts_lookup_list *LookupList = kbts_GetLookupList(Gpos); - LookupList->Count = kbts_ByteSwap16(LookupList->Count); - kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, LookupList), LookupList->Count, &ByteSwapContext); - - TotalLookupCount += LookupList->Count; - - KBTS_FOR(LookupIndex, 0, LookupList->Count) - { - kbts_lookup *PackedLookup = kbts_GetLookup(LookupList, LookupIndex); - - KBTS_DUMPF("GPOS Lookup %llu:\n", LookupIndex); - - if(kbts_ByteSwapLookup(&ByteSwapContext, PackedLookup)) - { - kbts_unpacked_lookup Lookup = kbts_UnpackLookup(Font->Gdef, PackedLookup); - - KBTS_DUMPF(" Flags %x\n", Lookup.Flags); - - KBTS_FOR(SubstitutionIndex, 0, Lookup.SubtableCount) - { - kbts_u16 *Base = KBTS_POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[SubstitutionIndex]); - - KBTS_DUMPF(" Subtable %llu:\n", (kbts_un)SubstitutionIndex); - - kbts_ByteSwapGposLookupSubtable(&ByteSwapContext, LookupList, Lookup.Type, Base); - } - } - - TotalSubtableCount += PackedLookup->SubtableCount; - } - } - - // At this point, we are done byteswapping the file, so we can start reusing the scratch memory. - - if(Gsub) - { - kbts_lookup_list *LookupList = kbts_GetLookupList(Gsub); - - // Figure out lookup recursion depth and other useful metrics. - // Most of these are not used yet, but would be useful for a streaming shaper and/or to inform GLYPH_BUFFER_GROW_MARGIN. - kbts_un MaximumBacktrackWithoutSkippingGlyphs = 0; - kbts_un MaximumLookaheadWithoutSkippingGlyphs = 0; - kbts_un MaximumLookupStackSize = 1; - kbts_un MaximumSubstitutionOutputSize = 1; - kbts_un MaximumInputSequenceLength = 1; - - // We are done byteswapping the file, so we can reclaim the scratch memory. - kbts_lookup_info_frame *Frames = (kbts_lookup_info_frame *)Scratch; - kbts_un FrameCapacity = ScratchSize / sizeof(kbts_lookup_info_frame); - - KBTS_FOR(RootLookupIndex, 0, LookupList->Count) - { - kbts_lookup *PackedRootLookup = kbts_GetLookup(LookupList, RootLookupIndex); - kbts_unpacked_lookup RootLookup = kbts_UnpackLookup(Gdef, PackedRootLookup); - - KBTS_FOR(RootSubtableIndex, 0, RootLookup.SubtableCount) - { - kbts_un FrameCount = 0; - { - kbts_lookup_info_frame First = KBTS_ZERO; - First.LookupType = RootLookup.Type; - First.Base = KBTS_POINTER_OFFSET(kbts_u16, PackedRootLookup, RootLookup.SubtableOffsets[RootSubtableIndex]); - First.StackSize = 1; - if(FrameCount < FrameCapacity) - { - Frames[FrameCount++] = First; - } - else - { - Font->Error = 1; - goto DoneGatheringLookupInfo; - } - } - - while(FrameCount) - { - kbts_lookup_info_frame Frame = Frames[--FrameCount]; - kbts_u16 LookupType = Frame.LookupType; - kbts_u16 *Base = Frame.Base; - kbts_u32 LookaheadOffset = Frame.LookaheadOffset; - kbts_u32 StackSize = Frame.StackSize; - - MaximumLookupStackSize = KBTS_MAX(MaximumLookupStackSize, StackSize); - - while(LookupType == 7) - { - kbts_extension *Subst = (kbts_extension *)Base; - - Base = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->Offset); - LookupType = Subst->LookupType; - } - - switch(LookupType) - { - case 2: - { - kbts_multiple_substitution *Subst = (kbts_multiple_substitution *)Base; - KBTS_FOR(SequenceIndex, 0, Subst->SequenceCount) - { - kbts_sequence *Sequence = kbts_GetSequence(Subst, SequenceIndex); - - MaximumSubstitutionOutputSize = KBTS_MAX(MaximumSubstitutionOutputSize, Sequence->GlyphCount); - } - } break; - - case 4: - { - kbts_ligature_substitution *Subst = (kbts_ligature_substitution *)Base; - - KBTS_FOR(SetIndex, 0, Subst->LigatureSetCount) - { - kbts_ligature_set *Set = kbts_GetLigatureSet(Subst, SetIndex); - - KBTS_FOR(LigatureIndex, 0, Set->Count) - { - kbts_ligature *Ligature = kbts_GetLigature(Set, LigatureIndex); - - MaximumLookaheadWithoutSkippingGlyphs = KBTS_MAX(MaximumLookaheadWithoutSkippingGlyphs, LookaheadOffset + Ligature->ComponentCount - 1); - } - } - } break; - - case 5: - { - if(Base[0] == 1) - { - kbts_sequence_context_1 *Subst = (kbts_sequence_context_1 *)Base; - - KBTS_FOR(SetIndex, 0, Subst->SeqRuleSetCount) - { - kbts_sequence_rule_set *Set = kbts_GetSequenceRuleSet(Subst, SetIndex); - - KBTS_FOR(RuleIndex, 0, Set->Count) - { - kbts_sequence_rule *Rule = kbts_GetSequenceRule(Set, RuleIndex); - - MaximumLookaheadWithoutSkippingGlyphs = KBTS_MAX(MaximumLookaheadWithoutSkippingGlyphs, LookaheadOffset + Rule->GlyphCount - 1); - MaximumInputSequenceLength = KBTS_MAX(MaximumInputSequenceLength, Rule->GlyphCount); - - kbts_u16 *InputSequence = KBTS_POINTER_AFTER(kbts_u16, Rule); - kbts_sequence_lookup_record *Records = (kbts_sequence_lookup_record *)(InputSequence + Rule->GlyphCount - 1); - KBTS_FOR(RecordIndex, 0, Rule->SequenceLookupCount) - { - kbts_sequence_lookup_record *Record = &Records[RecordIndex]; - if(!kbts_PushLookup(Gdef, Frames, &FrameCount, FrameCapacity, kbts_GetLookup(LookupList, Record->LookupListIndex), LookaheadOffset + Record->SequenceIndex, StackSize + RecordIndex + 1)) - { - Font->Error = 1; - goto DoneGatheringLookupInfo; - } - } - } - } - } - else if(Base[0] == 2) - { - kbts_sequence_context_2 *Subst = (kbts_sequence_context_2 *)Base; - - KBTS_FOR(SetIndex, 0, Subst->ClassSequenceRuleSetCount) - { - kbts_class_sequence_rule_set *Set = kbts_GetClassSequenceRuleSet(Subst, SetIndex); - - if(Set) - { - KBTS_FOR(RuleIndex, 0, Set->Count) - { - kbts_class_sequence_rule *Rule = kbts_GetClassSequenceRule(Set, RuleIndex); - - MaximumLookaheadWithoutSkippingGlyphs = KBTS_MAX(MaximumLookaheadWithoutSkippingGlyphs, LookaheadOffset + Rule->GlyphCount - 1); - MaximumInputSequenceLength = KBTS_MAX(MaximumInputSequenceLength, Rule->GlyphCount); - - kbts_u16 *InputSequence = KBTS_POINTER_AFTER(kbts_u16, Rule); - kbts_sequence_lookup_record *Records = (kbts_sequence_lookup_record *)(InputSequence + Rule->GlyphCount - 1); - - KBTS_FOR(RecordIndex, 0, Rule->SequenceLookupCount) - { - kbts_sequence_lookup_record *Record = &Records[RecordIndex]; - if(!kbts_PushLookup(Gdef, Frames, &FrameCount, FrameCapacity, kbts_GetLookup(LookupList, Record->LookupListIndex), LookaheadOffset + Record->SequenceIndex, StackSize + RecordIndex + 1)) - { - Font->Error = 1; - goto DoneGatheringLookupInfo; - } - } - } - } - } - } - else if(Base[0] == 3) - { - kbts_sequence_context_3 *Subst = (kbts_sequence_context_3 *)Base; - - MaximumLookaheadWithoutSkippingGlyphs = KBTS_MAX(MaximumLookaheadWithoutSkippingGlyphs, LookaheadOffset + Subst->GlyphCount - 1); - MaximumInputSequenceLength = KBTS_MAX(MaximumInputSequenceLength, Subst->GlyphCount); - - kbts_u16 *CoverageOffsets = KBTS_POINTER_AFTER(kbts_u16, Subst); - kbts_sequence_lookup_record *Records = (kbts_sequence_lookup_record *)(CoverageOffsets + Subst->GlyphCount); - - KBTS_FOR(RecordIndex, 0, Subst->SequenceLookupCount) - { - kbts_sequence_lookup_record *Record = &Records[RecordIndex]; - if(!kbts_PushLookup(Gdef, Frames, &FrameCount, FrameCapacity, kbts_GetLookup(LookupList, Record->LookupListIndex), LookaheadOffset + Record->SequenceIndex, StackSize + RecordIndex + 1)) - { - Font->Error = 1; - goto DoneGatheringLookupInfo; - } - } - } - } break; - - case 6: - { - if(Base[0] == 1) - { - kbts_chained_sequence_context_1 *Subst = (kbts_chained_sequence_context_1 *)Base; - - KBTS_FOR(SetIndex, 0, Subst->ChainedSequenceRuleSetCount) - { - kbts_chained_sequence_rule_set *Set = kbts_GetChainedSequenceRuleSet(Subst, SetIndex); - - if(Set) - { - KBTS_FOR(RuleIndex, 0, Set->Count) - { - kbts_chained_sequence_rule *Rule = kbts_GetChainedSequenceRule(Set, RuleIndex); - kbts_unpacked_chained_sequence_rule Unpacked = kbts_UnpackChainedSequenceRule(Rule, 0); - - MaximumBacktrackWithoutSkippingGlyphs = KBTS_MAX(MaximumBacktrackWithoutSkippingGlyphs, Unpacked.BacktrackCount); - MaximumLookaheadWithoutSkippingGlyphs = KBTS_MAX(MaximumLookaheadWithoutSkippingGlyphs, LookaheadOffset + Unpacked.LookaheadCount); - MaximumInputSequenceLength = KBTS_MAX(MaximumInputSequenceLength, Unpacked.InputCount); - - KBTS_FOR(RecordIndex, 0, Unpacked.RecordCount) - { - kbts_sequence_lookup_record *Record = &Unpacked.Records[RecordIndex]; - if(!kbts_PushLookup(Gdef, Frames, &FrameCount, FrameCapacity, kbts_GetLookup(LookupList, Record->LookupListIndex), LookaheadOffset + Record->SequenceIndex, StackSize + RecordIndex + 1)) - { - Font->Error = 1; - goto DoneGatheringLookupInfo; - } - } - } - } - } - } - else if(Base[0] == 2) - { - kbts_chained_sequence_context_2 *Subst = (kbts_chained_sequence_context_2 *)Base; - - KBTS_FOR(SetIndex, 0, Subst->ChainedClassSequenceRuleSetCount) - { - // @Duplication with 6.1. - kbts_chained_sequence_rule_set *Set = kbts_GetChainedClassSequenceRuleSet(Subst, SetIndex); - - if(Set) - { - KBTS_FOR(RuleIndex, 0, Set->Count) - { - kbts_chained_sequence_rule *Rule = kbts_GetChainedSequenceRule(Set, RuleIndex); - kbts_unpacked_chained_sequence_rule Unpacked = kbts_UnpackChainedSequenceRule(Rule, 0); - - MaximumBacktrackWithoutSkippingGlyphs = KBTS_MAX(MaximumBacktrackWithoutSkippingGlyphs, Unpacked.BacktrackCount); - MaximumLookaheadWithoutSkippingGlyphs = KBTS_MAX(MaximumLookaheadWithoutSkippingGlyphs, LookaheadOffset + Unpacked.LookaheadCount); - MaximumInputSequenceLength = KBTS_MAX(MaximumInputSequenceLength, Unpacked.InputCount); - - KBTS_FOR(RecordIndex, 0, Unpacked.RecordCount) - { - kbts_sequence_lookup_record *Record = &Unpacked.Records[RecordIndex]; - if(!kbts_PushLookup(Gdef, Frames, &FrameCount, FrameCapacity, kbts_GetLookup(LookupList, Record->LookupListIndex), LookaheadOffset + Record->SequenceIndex, StackSize + RecordIndex + 1)) - { - Font->Error = 1; - goto DoneGatheringLookupInfo; - } - } - } - } - } - } - else if(Base[0] == 3) - { - kbts_chained_sequence_context_3 *Subst = (kbts_chained_sequence_context_3 *)Base; - kbts_unpacked_chained_sequence_context_3 Unpacked = kbts_UnpackChainedSequenceContext3(Subst, 0); - - MaximumBacktrackWithoutSkippingGlyphs = KBTS_MAX(MaximumBacktrackWithoutSkippingGlyphs, Unpacked.BacktrackCount); - MaximumLookaheadWithoutSkippingGlyphs = KBTS_MAX(MaximumLookaheadWithoutSkippingGlyphs, LookaheadOffset + Unpacked.LookaheadCount); - MaximumInputSequenceLength = KBTS_MAX(MaximumInputSequenceLength, Unpacked.InputCount); - - KBTS_FOR(RecordIndex, 0, Unpacked.RecordCount) - { - kbts_sequence_lookup_record *Record = &Unpacked.Records[RecordIndex]; - if(!kbts_PushLookup(Gdef, Frames, &FrameCount, FrameCapacity, kbts_GetLookup(LookupList, Record->LookupListIndex), LookaheadOffset + Record->SequenceIndex, StackSize + RecordIndex + 1)) - { - Font->Error = 1; - goto DoneGatheringLookupInfo; - } - } - } - } break; - - case 8: - { - kbts_reverse_chain_substitution *Subst = (kbts_reverse_chain_substitution *)Base; - kbts_unpacked_reverse_chain_substitution Unpacked = kbts_UnpackReverseChainSubstitution(Subst, 0); - - MaximumBacktrackWithoutSkippingGlyphs = KBTS_MAX(MaximumBacktrackWithoutSkippingGlyphs, Unpacked.BacktrackCount); - MaximumLookaheadWithoutSkippingGlyphs = KBTS_MAX(MaximumLookaheadWithoutSkippingGlyphs, LookaheadOffset + Unpacked.LookaheadCount); - } break; - } - } - } - } - - DoneGatheringLookupInfo:; - Font->LookupInfo.MaximumBacktrackWithoutSkippingGlyphs = (kbts_u32)MaximumBacktrackWithoutSkippingGlyphs; - Font->LookupInfo.MaximumLookaheadWithoutSkippingGlyphs = (kbts_u32)MaximumLookaheadWithoutSkippingGlyphs; - Font->LookupInfo.MaximumSubstitutionOutputSize = (kbts_u32)MaximumSubstitutionOutputSize; - Font->LookupInfo.MaximumInputSequenceLength = (kbts_u32)MaximumInputSequenceLength; - Font->LookupInfo.MaximumLookupStackSize = (kbts_u32)MaximumLookupStackSize; - } - - Font->LookupCount = (kbts_u32)TotalLookupCount; - Font->SubtableCount = (kbts_u32)TotalSubtableCount; - - kbts_un GlyphLookupMatrixSizeInBytes = ((((TotalLookupCount * Font->GlyphCount) + 7) / 8) + 3) & ~3; - kbts_un GlyphLookupSubtableMatrixSizeInBytes = ((((TotalSubtableCount * Font->GlyphCount) + 7) / 8) + 3) & ~3; - Result = GlyphLookupMatrixSizeInBytes + GlyphLookupSubtableMatrixSizeInBytes + sizeof(kbts_u32) * TotalLookupCount + sizeof(kbts_lookup_subtable_info) * TotalSubtableCount; - - Font->Error |= ByteSwapContext.Error; - } return Result; } -KBTS_EXPORT int kbts_PostReadFontInitialize(kbts_font *Font, void *Memory, kbts_un MemorySize) +KBTS_EXPORT int kbts_GlyphIteratorIsValid(kbts_glyph_iterator *It) { - if(kbts_FontIsValid(Font) && Font->Maxp) + int Result = It->CurrentGlyph && kbts__GlyphIsValid(It->GlyphStorage, It->CurrentGlyph); + return Result; +} + +KBTS_EXPORT int kbts_GlyphIteratorNext(kbts_glyph_iterator *It, kbts_glyph **Glyph) +{ + int Result = 0; + kbts_glyph *CurrentGlyph = It->CurrentGlyph; + + if(kbts_GlyphIteratorIsValid(It)) { - // Bake table filters. - kbts_un GlyphCount = Font->GlyphCount; + *Glyph = CurrentGlyph; - kbts_un GlyphLookupMatrixSizeInBits = Font->LookupCount * GlyphCount; - kbts_un GlyphLookupMatrixSizeInBytes = (GlyphLookupMatrixSizeInBits + 7) / 8; - GlyphLookupMatrixSizeInBytes = (GlyphLookupMatrixSizeInBytes + 3) & ~3; // Align to u32 + Result = 1; + It->CurrentGlyph = CurrentGlyph->Next; + } - kbts_un GlyphLookupSubtableMatrixSizeInBits = Font->SubtableCount * GlyphCount; - kbts_un GlyphLookupSubtableMatrixSizeInBytes = (GlyphLookupSubtableMatrixSizeInBits + 7) / 8; - GlyphLookupSubtableMatrixSizeInBytes = (GlyphLookupSubtableMatrixSizeInBytes + 3) & ~3; // Align to u32 + return Result; +} - KBTS_MEMSET(Memory, 0, MemorySize); +KBTS_EXPORT int kbts_FontCount(void *Data, int Size) +{ + int Result = 0; - kbts_u32 *GlyphLookupMatrix = (kbts_u32 *)Memory; - kbts_u32 *GlyphLookupSubtableMatrix = KBTS_POINTER_OFFSET(kbts_u32, GlyphLookupMatrix, GlyphLookupMatrixSizeInBytes); - kbts_u32 *LookupSubtableIndexOffsets = KBTS_POINTER_OFFSET(kbts_u32, GlyphLookupSubtableMatrix, GlyphLookupSubtableMatrixSizeInBytes); - kbts_lookup_subtable_info *SubtableInfos = KBTS_POINTER_OFFSET(kbts_lookup_subtable_info, LookupSubtableIndexOffsets, sizeof(kbts_u32) * Font->LookupCount); - kbts_un GposLookupIndexOffset = 0; + if(Data && (Size >= 4)) + { + kbts_u32 Magic = *(kbts_u32 *)Data; - kbts_un RunningLookupIndex = 0; - kbts_un RunningSubtableIndex = 0; - - KBTS_FOR(ShapingTableIndex, 0, KBTS_SHAPING_TABLE_COUNT) + if(Magic == KBTS_FOURCC('t', 't', 'c', 'f')) { - kbts_gsub_gpos *ShapingTable = Font->ShapingTables[ShapingTableIndex]; + kbts__ttc_header *Header = (kbts__ttc_header *)Data; - if(ShapingTableIndex == KBTS_SHAPING_TABLE_GPOS) + if(Header->Magic == KBTS_FOURCC('t', 't', 'c', 'f')) { - GposLookupIndexOffset = RunningLookupIndex; + Result = (int)kbts__ByteSwap32(Header->FontCount); } + } + else if((Magic == KBTS_FOURCC('O', 'T', 'T', 'O')) || + (Magic == KBTS__U32BE(0x10000)) || + (Magic == KBTS_FOURCC('k', 'b', 't', 's'))) + { + Result = 1; + } + } - if(ShapingTable) + return Result; +} + +static kbts__cmap_subtable_pointer kbts__SelectCmapSubtable(kbts_blob_header *Header, kbts_blob_table *CmapTable, kbts__cmap_14 **Cmap14, kbts_u16 *ResultFormat) +{ + kbts__cmap_subtable_pointer Result = KBTS__ZERO; + + if(CmapTable->Length >= sizeof(kbts__cmap)) + { + char *TableEnd = KBTS__POINTER_OFFSET(char, Header, CmapTable->OffsetFromStartOfFile + CmapTable->Length); + kbts__cmap *Cmap = KBTS__POINTER_OFFSET(kbts__cmap, Header, CmapTable->OffsetFromStartOfFile); + + kbts_u16 PreferredFormat = 1; + KBTS__FOR(It, 0, Cmap->TableCount) + { + kbts__cmap_subtable_pointer Subtable = kbts__GetCmapSubtable(Cmap, It); + if((char *)(Subtable.Subtable + 1) <= TableEnd) { - kbts_lookup_list *LookupList = kbts_GetLookupList(ShapingTable); - KBTS_FOR(LookupIndex, 0, LookupList->Count) + kbts_u16 Format = *Subtable.Subtable; + + // This is kind of iffy, but the statelessness is useful for selecting + // the cmap from an already-prepared blob without having to deal with + // the byteswap context. + if((Format > 0xFF) && + ((Format >> 8) <= 14)) { - kbts_lookup *PackedLookup = kbts_GetLookup(LookupList, LookupIndex); - kbts_unpacked_lookup Lookup = kbts_UnpackLookup(Font->Gdef, PackedLookup); + Format = kbts__ByteSwap16(Format); + *Subtable.Subtable = Format; + } - LookupSubtableIndexOffsets[RunningLookupIndex] = (kbts_u32)RunningSubtableIndex; - - KBTS_FOR(SubtableIndex, 0, Lookup.SubtableCount) + if(Format == 14) + { + if((char *)(Subtable.Subtable + sizeof(kbts__cmap_14)) <= TableEnd) { - kbts_lookup_subtable_info SubtableInfo = KBTS_ZERO; - kbts_u32 LookupType = Lookup.Type; - kbts_u16 *Base = KBTS_POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[SubtableIndex]); - - while(((ShapingTableIndex == KBTS_SHAPING_TABLE_GSUB) && (LookupType == 7)) || - ((ShapingTableIndex == KBTS_SHAPING_TABLE_GPOS) && (LookupType == 9))) + if(Cmap14) { - kbts_extension *Extension = (kbts_extension *)Base; - LookupType = Extension->LookupType; - Base = KBTS_POINTER_OFFSET(kbts_u16, Extension, Extension->Offset); + *Cmap14 = (kbts__cmap_14 *)Subtable.Subtable; } - - KBTS_FOR(GlyphIndex, 0, GlyphCount) - { - kbts_glyph Glyph = KBTS_ZERO; - Glyph.Id = (kbts_u16)GlyphIndex; - Glyph.Classes = kbts_GlyphClasses(Font, Glyph.Id); - - // @Duplication - kbts_cover_glyph_result Cover = KBTS_ZERO; - Cover.Valid = kbts_GlyphPassesLookupFilter(&Glyph, &Lookup); - if(Cover.Valid && kbts_LookupBeginsWithCoverage((kbts_shaping_table)ShapingTableIndex, Lookup.Type, Base[0])) - { - kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Base, Base[1]); - Cover = kbts_CoverGlyph(Coverage, Glyph.Id); - } - - // The "primary" slot here refers to the "current glyph" when matching. - // It is the first glyph in the input sequence, not counting backtrack. - // We use the primary slot for per-feature filtering. - int InPrimary = Cover.Valid; - // The secondary slot is anything else: input sequence, lookahead, backtrack, ligature components. - // They are used for subtable filtering. - int InSecondary = 0; - - if((ShapingTableIndex == KBTS_SHAPING_TABLE_GSUB) && (LookupType == 4)) - { - kbts_ligature_substitution *Subst = (kbts_ligature_substitution *)Base; - KBTS_FOR(SetIndex, 0, Subst->LigatureSetCount) - { - kbts_ligature_set *Set = kbts_GetLigatureSet(Subst, SetIndex); - KBTS_FOR(LigatureIndex, 0, Set->Count) - { - kbts_ligature *Ligature = kbts_GetLigature(Set, LigatureIndex); - kbts_u16 *Ids = KBTS_POINTER_AFTER(kbts_u16, Ligature); - - SubtableInfo.MinimumFollowupPlusOne = KBTS_MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Ligature->ComponentCount - 1) + 1; - - KBTS_FOR(IdIndex, 1, Ligature->ComponentCount) - { - kbts_u16 LigatureGlyphId = Ids[IdIndex - 1]; - if(LigatureGlyphId == Glyph.Id) - { - InSecondary = 1; - goto DoneCheckingForInclusion; - } - } - } - } - } - else if(((ShapingTableIndex == KBTS_SHAPING_TABLE_GSUB) && (LookupType == 5)) || - ((ShapingTableIndex == KBTS_SHAPING_TABLE_GPOS) && (LookupType == 7))) - { - if(Base[0] == 1) - { - kbts_sequence_context_1 *Subst = (kbts_sequence_context_1 *)Base; - - KBTS_FOR(SetIndex, 0, Subst->SeqRuleSetCount) - { - kbts_sequence_rule_set *Set = kbts_GetSequenceRuleSet(Subst, SetIndex); - - if(Set) - { - KBTS_FOR(RuleIndex, 0, Set->Count) - { - kbts_sequence_rule *Rule = kbts_GetSequenceRule(Set, RuleIndex); - SubtableInfo.MinimumFollowupPlusOne = KBTS_MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Rule->GlyphCount - 1) + 1; - - kbts_u16 *SequenceIds = KBTS_POINTER_AFTER(kbts_u16, Rule); - KBTS_FOR(InputIndex, 1, Rule->GlyphCount) - { - kbts_u16 SequenceId = SequenceIds[InputIndex - 1]; - if(SequenceId == Glyph.Id) - { - InSecondary = 1; - goto DoneCheckingForInclusion; - } - } - } - } - } - } - else if(Base[0] == 2) - { - kbts_sequence_context_2 *Subst = (kbts_sequence_context_2 *)Base; - kbts_u16 *ClassDefBase = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->ClassDefOffset); - kbts_glyph_class_from_table_result Class = kbts_GlyphClassFromTable(ClassDefBase, Glyph.Id); - - KBTS_FOR(SetIndex, 0, Subst->ClassSequenceRuleSetCount) - { - kbts_class_sequence_rule_set *Set = kbts_GetClassSequenceRuleSet(Subst, SetIndex); - if(Set) - { - KBTS_FOR(RuleIndex, 0, Set->Count) - { - kbts_class_sequence_rule *Rule = kbts_GetClassSequenceRule(Set, RuleIndex); - kbts_u16 *SequenceClasses = KBTS_POINTER_AFTER(kbts_u16, Rule); - - SubtableInfo.MinimumFollowupPlusOne = KBTS_MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Rule->GlyphCount - 1) + 1; - - KBTS_FOR(SequenceIndex, 1, Rule->GlyphCount) - { - if(SequenceClasses[SequenceIndex - 1] == Class.Class) - { - InSecondary = 1; - goto DoneCheckingForInclusion; - } - } - } - } - } - } - else if(Base[0] == 3) - { - kbts_sequence_context_3 *Subst = (kbts_sequence_context_3 *)Base; - kbts_u16 *CoverageOffsets = KBTS_POINTER_AFTER(kbts_u16, Subst); - - SubtableInfo.MinimumFollowupPlusOne = KBTS_MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Subst->GlyphCount - 1) + 1; - - InPrimary = 0; - KBTS_FOR(CoverageIndex, 0, Subst->GlyphCount) - { - kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, CoverageOffsets[CoverageIndex]); - kbts_cover_glyph_result SequenceCover = kbts_CoverGlyph(Coverage, Glyph.Id); - if(SequenceCover.Valid) - { - if(!CoverageIndex) - { - InPrimary = 1; - } - else - { - InSecondary = 1; - } - goto DoneCheckingForInclusion; - } - } - } - } - else if(((ShapingTableIndex == KBTS_SHAPING_TABLE_GSUB) && (LookupType == 6)) || - ((ShapingTableIndex == KBTS_SHAPING_TABLE_GPOS) && (LookupType == 8))) - { - if(Base[0] == 1) - { - kbts_chained_sequence_context_1 *Subst = (kbts_chained_sequence_context_1 *)Base; - kbts_u16 *ChainedSequenceRuleSetOffsets = KBTS_POINTER_AFTER(kbts_u16, Subst); - - KBTS_FOR(SetIndex, 0, Subst->ChainedSequenceRuleSetCount) - { - kbts_chained_sequence_rule_set *Set = KBTS_POINTER_OFFSET(kbts_chained_sequence_rule_set, Subst, ChainedSequenceRuleSetOffsets[SetIndex]); - KBTS_FOR(RuleIndex, 0, Set->Count) - { - kbts_chained_sequence_rule *Rule = kbts_GetChainedClassSequenceRule(Set, RuleIndex); - kbts_unpacked_chained_sequence_rule Unpacked = kbts_UnpackChainedSequenceRule(Rule, 0); - - SubtableInfo.MinimumBacktrackPlusOne = KBTS_MIN(SubtableInfo.MinimumBacktrackPlusOne - 1, Unpacked.BacktrackCount) + 1; - SubtableInfo.MinimumFollowupPlusOne = KBTS_MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Unpacked.InputCount - 1 + Unpacked.LookaheadCount) + 1; - - KBTS_FOR(BacktrackIndex, 0, Unpacked.BacktrackCount) - { - if(Unpacked.Backtrack[BacktrackIndex] == Glyph.Id) - { - InSecondary = 1; - goto DoneCheckingForInclusion; - } - } - KBTS_FOR(InputIndex, 1, Unpacked.InputCount) - { - if(Unpacked.Input[InputIndex - 1] == Glyph.Id) - { - InSecondary = 1; - goto DoneCheckingForInclusion; - } - } - KBTS_FOR(LookaheadIndex, 0, Unpacked.LookaheadCount) - { - if(Unpacked.Lookahead[LookaheadIndex] == Glyph.Id) - { - InSecondary = 1; - goto DoneCheckingForInclusion; - } - } - } - } - } - else if(Base[0] == 2) - { - kbts_chained_sequence_context_2 *Subst = (kbts_chained_sequence_context_2 *)Base; - kbts_u16 *BacktrackClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->BacktrackClassDefOffset); - kbts_u16 *InputClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->InputClassDefOffset); - kbts_u16 *LookaheadClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->LookaheadClassDefOffset); - - kbts_u16 BacktrackClass = kbts_GlyphClassFromTable(BacktrackClassDefinition, Glyph.Id).Class; - kbts_u16 InputClass = kbts_GlyphClassFromTable(InputClassDefinition, Glyph.Id).Class; - kbts_u16 LookaheadClass = kbts_GlyphClassFromTable(LookaheadClassDefinition, Glyph.Id).Class; - - KBTS_FOR(SetIndex, 0, Subst->ChainedClassSequenceRuleSetCount) - { - kbts_chained_sequence_rule_set *Set = kbts_GetChainedClassSequenceRuleSet(Subst, SetIndex); - if(Set) - { - KBTS_FOR(RuleIndex, 0, Set->Count) - { - kbts_chained_sequence_rule *Rule = kbts_GetChainedSequenceRule(Set, RuleIndex); - kbts_unpacked_chained_sequence_rule Unpacked = kbts_UnpackChainedSequenceRule(Rule, 0); - - SubtableInfo.MinimumBacktrackPlusOne = KBTS_MIN(SubtableInfo.MinimumBacktrackPlusOne - 1, Unpacked.BacktrackCount) + 1; - SubtableInfo.MinimumFollowupPlusOne = KBTS_MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Unpacked.InputCount - 1 + Unpacked.LookaheadCount) + 1; - - KBTS_FOR(BacktrackIndex, 0, Unpacked.BacktrackCount) - { - if(Unpacked.Backtrack[BacktrackIndex] == BacktrackClass) - { - InSecondary = 1; - goto DoneCheckingForInclusion; - } - } - KBTS_FOR(InputIndex, 1, Unpacked.InputCount) - { - if(Unpacked.Input[InputIndex - 1] == InputClass) - { - InSecondary = 1; - goto DoneCheckingForInclusion; - } - } - KBTS_FOR(LookaheadIndex, 0, Unpacked.LookaheadCount) - { - if(Unpacked.Lookahead[LookaheadIndex] == LookaheadClass) - { - InSecondary = 1; - goto DoneCheckingForInclusion; - } - } - } - } - } - } - else if(Base[0] == 3) - { - kbts_chained_sequence_context_3 *Subst = (kbts_chained_sequence_context_3 *)Base; - kbts_unpacked_chained_sequence_context_3 Unpacked = kbts_UnpackChainedSequenceContext3(Subst, 0); - - SubtableInfo.MinimumBacktrackPlusOne = KBTS_MIN(SubtableInfo.MinimumBacktrackPlusOne - 1, Unpacked.BacktrackCount) + 1; - SubtableInfo.MinimumFollowupPlusOne = KBTS_MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Unpacked.InputCount - 1 + Unpacked.LookaheadCount) + 1; - - KBTS_FOR(BacktrackCoverageIndex, 0, Unpacked.BacktrackCount) - { - kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.BacktrackCoverageOffsets[BacktrackCoverageIndex]); - kbts_cover_glyph_result SequenceCover = kbts_CoverGlyph(Coverage, Glyph.Id); - if(SequenceCover.Valid) - { - InSecondary = 1; - goto DoneCheckingForInclusion; - } - } - - InPrimary = 0; - KBTS_FOR(InputCoverageIndex, 0, Unpacked.InputCount) - { - kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.InputCoverageOffsets[InputCoverageIndex]); - kbts_cover_glyph_result SequenceCover = kbts_CoverGlyph(Coverage, Glyph.Id); - if(SequenceCover.Valid) - { - if(!InputCoverageIndex) - { - InPrimary = 1; - } - else - { - InSecondary = 1; - } - goto DoneCheckingForInclusion; - } - } - - KBTS_FOR(LookaheadCoverageIndex, 0, Unpacked.LookaheadCount) - { - kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.LookaheadCoverageOffsets[LookaheadCoverageIndex]); - kbts_cover_glyph_result SequenceCover = kbts_CoverGlyph(Coverage, Glyph.Id); - if(SequenceCover.Valid) - { - InSecondary = 1; - goto DoneCheckingForInclusion; - } - } - } - } - else if((ShapingTableIndex == KBTS_SHAPING_TABLE_GSUB) && (LookupType == 8)) - { - kbts_reverse_chain_substitution *Subst = (kbts_reverse_chain_substitution *)Base; - kbts_unpacked_reverse_chain_substitution Unpacked = kbts_UnpackReverseChainSubstitution(Subst, 0); - - SubtableInfo.MinimumBacktrackPlusOne = KBTS_MIN(SubtableInfo.MinimumBacktrackPlusOne - 1, Unpacked.BacktrackCount) + 1; - SubtableInfo.MinimumFollowupPlusOne = KBTS_MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Unpacked.LookaheadCount) + 1; - - KBTS_FOR(BacktrackIndex, 0, Unpacked.BacktrackCount) - { - kbts_cover_glyph_result BacktrackCover = kbts_CoverGlyph(KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.BacktrackCoverageOffsets[BacktrackIndex]), Glyph.Id); - if(BacktrackCover.Valid) - { - InSecondary = 1; - goto DoneCheckingForInclusion; - } - } - KBTS_FOR(LookaheadIndex, 0, Unpacked.LookaheadCount) - { - kbts_cover_glyph_result LookaheadCover = kbts_CoverGlyph(KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.LookaheadCoverageOffsets[LookaheadIndex]), Glyph.Id); - if(LookaheadCover.Valid) - { - InSecondary = 1; - goto DoneCheckingForInclusion; - } - } - } - DoneCheckingForInclusion:; - - if(InPrimary) - { - kbts_un FlatIndex = RunningLookupIndex * GlyphCount + GlyphIndex; - kbts_un WordIndex = FlatIndex / 32; - kbts_un BitIndex = FlatIndex % 32; - GlyphLookupMatrix[WordIndex] |= (1 << BitIndex); - } - if(InPrimary || InSecondary) - { - kbts_un FlatIndex = RunningSubtableIndex * GlyphCount + GlyphIndex; - kbts_un WordIndex = FlatIndex / 32; - kbts_un BitIndex = FlatIndex % 32; - GlyphLookupSubtableMatrix[WordIndex] |= (1 << BitIndex); - } - } - - SubtableInfos[RunningSubtableIndex] = SubtableInfo; - RunningSubtableIndex += 1; } + } + else if(!Result.Subtable) + { + Result = Subtable; + } + else if(Format < KBTS__ARRAY_LENGTH(kbts__CmapFormatPrecedence)) + { + kbts_u16 Precedence = kbts__CmapFormatPrecedence[Format]; + kbts_u16 PreferredPrecedence = kbts__CmapFormatPrecedence[PreferredFormat]; - RunningLookupIndex += 1; + if((Precedence > PreferredPrecedence) || ((Precedence == PreferredPrecedence) && (Subtable.PlatformId == 3))) + { + Result = Subtable; + if(ResultFormat) + { + *ResultFormat = Format; + } + } + } + } + } + } + + return Result; +} + +KBTS_EXPORT kbts_load_font_error kbts_LoadFont(kbts_font *Font, kbts_load_font_state *State, void *FontData, int FontDataSize, int FontIndex, int *ScratchSize_, int *OutputSize_) +{ + kbts_load_font_error Result = 0; + kbts_un ScratchSize = 0; + kbts_un OutputSize = 0; + + if(FontDataSize >= 4) + { + char *FileEnd = (char *)FontData + FontDataSize; + kbts_u32 Magic = *(kbts_u32 *)FontData; + kbts_un DirectoryOffset = 0; + + if(Magic == KBTS_FOURCC('t', 't', 'c', 'f')) + { + Magic = 0; + + if(FontDataSize >= (int)sizeof(kbts__ttc_header)) + { + kbts__ttc_header *Header = (kbts__ttc_header *)FontData; + kbts_un FontCount = kbts__ByteSwap32(Header->FontCount); + + if(((kbts_u32)FontIndex < FontCount) && + ((kbts_un)FontDataSize >= (sizeof(kbts__ttc_header) + sizeof(kbts_u32) * FontCount))) + { + kbts_u32 *TableDirectoryOffsets = KBTS__POINTER_AFTER(kbts_u32, Header); + DirectoryOffset = kbts__ByteSwap32(TableDirectoryOffsets[FontIndex]); + + Magic = KBTS__U32BE(0x10000); } } } - Font->SubtableInfos = SubtableInfos; - Font->GlyphLookupMatrix = GlyphLookupMatrix; - Font->GlyphLookupSubtableMatrix = GlyphLookupSubtableMatrix; - Font->LookupSubtableIndexOffsets = LookupSubtableIndexOffsets; - Font->GposLookupIndexOffset = (kbts_u32)GposLookupIndexOffset; - Font->GlyphCount = (kbts_u32)GlyphCount; + if((Magic == KBTS_FOURCC('O', 'T', 'T', 'O')) || + (Magic == KBTS__U32BE(0x10000))) + { + Result = KBTS_LOAD_FONT_ERROR_NEED_TO_CREATE_BLOB; + + State->FontData = FontData; + State->FontDataSize = (kbts_u32)FontDataSize; + + kbts__table_directory *Directory = KBTS__POINTER_OFFSET(kbts__table_directory, FontData, DirectoryOffset); + kbts_un DirectoryTableCount = kbts__ByteSwap16(Directory->TableCount); + + kbts__table_record *Tables = KBTS__POINTER_AFTER(kbts__table_record, Directory); + + kbts_un DirectoryTableCapacity = (kbts_un)(FileEnd - (char *)Tables) / sizeof(kbts__table_record); + if(DirectoryTableCount <= DirectoryTableCapacity) + { + for(kbts_un TableIndex = 0; TableIndex < DirectoryTableCount; ++TableIndex) + { + kbts__table_record *Table = &Tables[TableIndex]; + kbts_u32 TableOffset = kbts__ByteSwap32(Table->Offset); + kbts_u32 TableLength = kbts__ByteSwap32(Table->Length); + + void *TableBase = KBTS__POINTER_OFFSET(void, FontData, TableOffset); + char *TableEnd = (char *)TableBase + TableLength; + if(((char *)TableBase >= (char *)(Tables + DirectoryTableCount)) && (TableEnd <= FileEnd)) + { + kbts_blob_table_id TableId = 0; + + switch(Table->Tag) + { + case KBTS_FOURCC('h', 'e', 'a', 'd'): TableId = KBTS_BLOB_TABLE_ID_HEAD; break; + case KBTS_FOURCC('c', 'm', 'a', 'p'): TableId = KBTS_BLOB_TABLE_ID_CMAP; break; + case KBTS_FOURCC('G', 'D', 'E', 'F'): TableId = KBTS_BLOB_TABLE_ID_GDEF; break; + case KBTS_FOURCC('G', 'S', 'U', 'B'): TableId = KBTS_BLOB_TABLE_ID_GSUB; break; + case KBTS_FOURCC('G', 'P', 'O', 'S'): TableId = KBTS_BLOB_TABLE_ID_GPOS; break; + case KBTS_FOURCC('h', 'h', 'e', 'a'): TableId = KBTS_BLOB_TABLE_ID_HHEA; break; + case KBTS_FOURCC('v', 'h', 'e', 'a'): TableId = KBTS_BLOB_TABLE_ID_VHEA; break; + case KBTS_FOURCC('h', 'm', 't', 'x'): TableId = KBTS_BLOB_TABLE_ID_HMTX; break; + case KBTS_FOURCC('v', 'm', 't', 'x'): TableId = KBTS_BLOB_TABLE_ID_VMTX; break; + case KBTS_FOURCC('m', 'a', 'x', 'p'): TableId = KBTS_BLOB_TABLE_ID_MAXP; break; + case KBTS_FOURCC('O', 'S', '/', '2'): TableId = KBTS_BLOB_TABLE_ID_OS2; break; + case KBTS_FOURCC('n', 'a', 'm', 'e'): TableId = KBTS_BLOB_TABLE_ID_NAME; break; + } + + if(TableId) + { + kbts_blob_table *ReadTable = &State->Tables[TableId]; + ReadTable->OffsetFromStartOfFile = TableOffset; + ReadTable->Length = TableLength; + } + } + } + } + + { + kbts_un TotalLookupCount = 0; + kbts_un TotalSubtableCount = 0; + + kbts_blob_table *GsubGposTables[] = {&State->Tables[KBTS_BLOB_TABLE_ID_GSUB], &State->Tables[KBTS_BLOB_TABLE_ID_GPOS]}; + KBTS__FOR(GsubGposTableIndex, 0, KBTS__ARRAY_LENGTH(GsubGposTables)) + { + kbts_blob_table *Table = GsubGposTables[GsubGposTableIndex]; + + if(Table->Length) + { + kbts__gsub_gpos *GsubGpos = KBTS__POINTER_OFFSET(kbts__gsub_gpos, FontData, Table->OffsetFromStartOfFile); + kbts_lookup_list *LookupList = KBTS__POINTER_OFFSET(kbts_lookup_list, GsubGpos, kbts__ByteSwap16(GsubGpos->LookupListOffset)); + kbts_u16 *LookupOffsets = KBTS__POINTER_AFTER(kbts_u16, LookupList); + kbts_un LookupCount = kbts__ByteSwap16(LookupList->Count); + + KBTS__FOR(LookupIndex, 0, LookupCount) + { + kbts__lookup *Lookup = KBTS__POINTER_OFFSET(kbts__lookup, LookupList, kbts__ByteSwap16(LookupOffsets[LookupIndex])); + + TotalSubtableCount += kbts__ByteSwap16(Lookup->SubtableCount); + } + + TotalLookupCount += LookupCount; + } + } + + State->LookupCount = (kbts_u32)TotalLookupCount; + State->LookupSubtableCount = (kbts_u32)TotalSubtableCount; + } + + { + kbts_un GlyphCount = 0; + + kbts_blob_table *MaxpTable = &State->Tables[KBTS_BLOB_TABLE_ID_MAXP]; + if(MaxpTable->Length) + { + kbts__maxp *Maxp = KBTS__POINTER_OFFSET(kbts__maxp, FontData, MaxpTable->OffsetFromStartOfFile); + + GlyphCount = kbts__ByteSwap16(Maxp->GlyphCount); + } + + State->GlyphCount = (kbts_u32)GlyphCount; + } + + ScratchSize = (State->Tables[KBTS_BLOB_TABLE_ID_GSUB].Length + + State->Tables[KBTS_BLOB_TABLE_ID_GPOS].Length + + State->Tables[KBTS_BLOB_TABLE_ID_GDEF].Length) * sizeof(kbts_u32) / 2; + + kbts_un GlyphLookupMatrixSizeInBytes = ((((State->LookupCount * State->GlyphCount) + 7) / 8) + 3) & ~3u; + kbts_un GlyphLookupSubtableMatrixSizeInBytes = ((((State->LookupSubtableCount * State->GlyphCount) + 7) / 8) + 3) & ~3u; + OutputSize = sizeof(kbts_blob_header) + + sizeof(kbts_blob_table) * KBTS_BLOB_TABLE_ID_COUNT + + GlyphLookupMatrixSizeInBytes + + GlyphLookupSubtableMatrixSizeInBytes + + sizeof(kbts_u32) * State->LookupCount + + sizeof(kbts_lookup_subtable_info) * State->LookupSubtableCount; + + KBTS__FOR(TableId, 0, KBTS_BLOB_TABLE_ID_COUNT) + { + OutputSize += State->Tables[TableId].Length; + } + + *ScratchSize_ = (int)ScratchSize; + *OutputSize_ = (int)OutputSize; + + State->ScratchSize = (kbts_u32)ScratchSize; + State->GlyphLookupMatrixSizeInBytes = (kbts_u32)GlyphLookupMatrixSizeInBytes; + State->GlyphLookupSubtableMatrixSizeInBytes = (kbts_u32)GlyphLookupSubtableMatrixSizeInBytes; + State->TotalSize = (kbts_u32)OutputSize; + } + else if(Magic == KBTS_FOURCC('k', 'b', 't', 's')) + { + kbts_blob_header *Header = (kbts_blob_header *)FontData; + + if(Header->Version != KBTS_BLOB_VERSION_CURRENT) + { + Result = KBTS_LOAD_FONT_ERROR_INVALID_FONT; + } + + // @Incomplete: Bounds check or something. + + Font->Blob = Header; + kbts__cmap_subtable_pointer PreferredSubtable = kbts__SelectCmapSubtable(Header, &Header->Tables[KBTS_BLOB_TABLE_ID_CMAP], &Font->Cmap14, 0); + Font->Cmap = PreferredSubtable.Subtable; + } } - return kbts_FontIsValid(Font); + return Result; } KBTS_EXPORT int kbts_FontIsValid(kbts_font *Font) @@ -22817,10 +26670,1172 @@ KBTS_EXPORT int kbts_FontIsValid(kbts_font *Font) return Result; } -#ifndef KB_TEXT_SHAPE_NO_CRT -KBTS_EXPORT kbts_font kbts_FontFromFile(const char *FileName) +static void kbts__MarkMatrixCoverage(kbts_u32 *Matrix, kbts_un TableIndex, kbts_un TableCount, kbts_un GlyphCount, kbts__coverage *Coverage, int SubtableMatrix) { - kbts_font Result = KBTS_ZERO; + if(Coverage) + { + if(Coverage->Format == 1) + { + kbts_u16 *GlyphIds = KBTS__POINTER_AFTER(kbts_u16, Coverage); + + KBTS__FOR(GlyphIndex, 0, Coverage->Count) + { + kbts_un GlyphId = GlyphIds[GlyphIndex]; + kbts__matrix_index MatrixIndex = SubtableMatrix ? + kbts__GlyphLookupSubtableMatrixIndex(TableIndex, TableCount, GlyphId) : + kbts__GlyphLookupMatrixIndex(TableIndex, GlyphId, GlyphCount); + + if(GlyphId < GlyphCount) + { + Matrix[MatrixIndex.WordIndex] |= 1 << MatrixIndex.BitIndex; + } + } + } + else if(Coverage->Format == 2) + { + kbts__range_record *Ranges = KBTS__POINTER_AFTER(kbts__range_record, Coverage); + + KBTS__FOR(RangeIndex, 0, Coverage->Count) + { + kbts__range_record *Range = &Ranges[RangeIndex]; + KBTS__FOR(GlyphId, Range->StartGlyphId, (kbts_un)Range->EndGlyphId + 1) + { + kbts__matrix_index MatrixIndex = SubtableMatrix ? + kbts__GlyphLookupSubtableMatrixIndex(TableIndex, TableCount, GlyphId) : + kbts__GlyphLookupMatrixIndex(TableIndex, GlyphId, GlyphCount); + + if(GlyphId < GlyphCount) + { + Matrix[MatrixIndex.WordIndex] |= 1 << MatrixIndex.BitIndex; + } + } + } + } + } +} + +static void kbts__MarkMatrixClassDef(kbts_u32 *Matrix, kbts_un SubtableIndex, kbts_un SubtableCount, kbts_un GlyphCount, kbts_u16 *ClassDefBase, kbts_u64 *ClassesIncluded, kbts_un ClassesIncludedLength) +{ + if(ClassDefBase) + { + if(*ClassDefBase == 1) + { + kbts__class_definition_1 *ClassDef = (kbts__class_definition_1 *)ClassDefBase; + kbts_u16 *GlyphClasses = KBTS__POINTER_AFTER(kbts_u16, ClassDef); + + KBTS__FOR(GlyphIndex, 0, ClassDef->GlyphCount) + { + kbts_un GlyphId = ClassDef->StartGlyphId + GlyphIndex; + kbts_un GlyphClass = GlyphClasses[GlyphIndex]; + + if((GlyphId >= (ClassesIncludedLength * 64)) || + (ClassesIncluded[GlyphClass / 64] & (1ull << (GlyphClass % 64)))) + { + kbts__matrix_index SubtableMatrixIndex = kbts__GlyphLookupSubtableMatrixIndex(SubtableIndex, SubtableCount, GlyphId); + Matrix[SubtableMatrixIndex.WordIndex] |= 1 << SubtableMatrixIndex.BitIndex; + } + } + } + else if(*ClassDefBase == 2) + { + kbts__class_definition_2 *ClassDef = (kbts__class_definition_2 *)ClassDefBase; + kbts__class_range_record *Ranges = KBTS__POINTER_AFTER(kbts__class_range_record, ClassDef); + + KBTS__FOR(RangeIndex, 0, ClassDef->Count) + { + kbts__class_range_record *Range = &Ranges[RangeIndex]; + kbts_un RangeClass = Range->Class; + + if((RangeClass >= (ClassesIncludedLength * 64)) || + (ClassesIncluded[RangeClass / 64] & (1ull << (RangeClass % 64)))) + { + kbts_un OnePastLastGlyphId = Range->EndGlyphId + 1; + if(OnePastLastGlyphId > GlyphCount) + { + OnePastLastGlyphId = GlyphCount; + } + + KBTS__FOR(GlyphId, Range->StartGlyphId, OnePastLastGlyphId) + { + kbts__matrix_index SubtableMatrixIndex = kbts__GlyphLookupSubtableMatrixIndex(SubtableIndex, SubtableCount, GlyphId); + Matrix[SubtableMatrixIndex.WordIndex] |= 1 << SubtableMatrixIndex.BitIndex; + } + } + } + } + } +} + +KBTS_EXPORT kbts_load_font_error kbts_PlaceBlob(kbts_font *Font, kbts_load_font_state *State, void *ScratchMemory, void *OutputMemory) +{ + kbts_load_font_error Result = 0; + + if(!Font) + { + Result = KBTS_LOAD_FONT_ERROR_INVALID_FONT; + } + + if(!ScratchMemory || !OutputMemory) + { + Result = KBTS_LOAD_FONT_ERROR_OUT_OF_MEMORY; + } + + if(Result == KBTS_LOAD_FONT_ERROR_NONE) + { + kbts_blob_header *Header = (kbts_blob_header *)OutputMemory; + *Header = KBTS__ZERO_TYPE(kbts_blob_header); + Header->Magic = KBTS_FOURCC('k', 'b', 't', 's'); + Header->Version = 1; + Header->LookupCount = State->LookupCount; + Header->LookupSubtableCount = State->LookupSubtableCount; + + // Stamp packed font data. + char *OutData = KBTS__POINTER_AFTER(char, Header); + KBTS__FOR(TableId, 0, KBTS_BLOB_TABLE_ID_COUNT) + { + kbts_blob_table InTable = State->Tables[TableId]; + kbts_blob_table *OutTable = &Header->Tables[TableId]; + + OutTable->OffsetFromStartOfFile = KBTS__POINTER_DIFF32(OutData, Header); + OutTable->Length = InTable.Length; + + void *InData = KBTS__POINTER_OFFSET(void, State->FontData, InTable.OffsetFromStartOfFile); + KBTS_MEMCPY(OutData, InData, InTable.Length); + + OutData += InTable.Length; + } + + // Byteswap it. + + { + kbts_blob_table *HeadTable = &Header->Tables[KBTS_BLOB_TABLE_ID_HEAD]; + + if(HeadTable->Length) + { + if(HeadTable->Length >= sizeof(kbts__head)) + { + kbts__head *Head = KBTS__POINTER_OFFSET(kbts__head, Header, HeadTable->OffsetFromStartOfFile); + + kbts__ByteSwapArray16Unchecked(&Head->Major, 2); + kbts__ByteSwapArray32Unchecked(&Head->Revision, 2); + // We do not swap the magic number. + kbts__ByteSwapArray16Unchecked(&Head->Flags, 2); + // We do not swap file times. + kbts__ByteSwapArray16Unchecked((kbts_u16 *)&Head->XMin, 9); + } + else + { + Result = KBTS_LOAD_FONT_ERROR_INVALID_FONT; + } + } + } + + Font->Blob = Header; + + { + kbts_blob_table *CmapTable = &Header->Tables[KBTS_BLOB_TABLE_ID_CMAP]; + + if(CmapTable->Length) + { + if(CmapTable->Length >= sizeof(kbts__cmap)) + { + int TableValid = 0; + char *TableEnd = KBTS__POINTER_OFFSET(char, Header, CmapTable->OffsetFromStartOfFile + CmapTable->Length); + kbts__cmap *Cmap = KBTS__POINTER_OFFSET(kbts__cmap, Header, CmapTable->OffsetFromStartOfFile); + Cmap->Version = kbts__ByteSwap16(Cmap->Version); + Cmap->TableCount = kbts__ByteSwap16(Cmap->TableCount); + + kbts__encoding_record *Records = KBTS__POINTER_AFTER(kbts__encoding_record, Cmap); + + if((char *)(Records + Cmap->TableCount) <= TableEnd) + { + KBTS__FOR(It, 0, Cmap->TableCount) + { + kbts__encoding_record *Record = &Records[It]; + Record->EncodingId = kbts__ByteSwap16(Record->EncodingId); + Record->PlatformId = kbts__ByteSwap16(Record->PlatformId); + Record->SubtableOffset = kbts__ByteSwap32(Record->SubtableOffset); + } + + kbts_u16 PreferredFormat = 1; + + kbts__cmap_subtable_pointer PreferredSubtable = kbts__SelectCmapSubtable(Header, CmapTable, &Font->Cmap14, &PreferredFormat); + if(PreferredSubtable.Subtable) + { + switch(*PreferredSubtable.Subtable) + { + case 0: + { + kbts__cmap_0 *Cmap0 = (kbts__cmap_0 *)PreferredSubtable.Subtable; + if((char *)(Cmap0 + 1) <= TableEnd) + { + Cmap0->Length = kbts__ByteSwap16(Cmap0->Length); + Cmap0->Language = kbts__ByteSwap16(Cmap0->Language); + TableValid = 1; + } + } + break; + + case 2: + { + kbts__cmap_2 *Cmap2 = (kbts__cmap_2 *)PreferredSubtable.Subtable; + if(kbts__ByteSwapArray16(&Cmap2->Length, 258, TableEnd)) + { + kbts_un SubHeaderCount = 0; + KBTS__FOR(It, 0, 256) + { + kbts_un SubHeaderIndex = Cmap2->SubHeaderKeys[It]; + SubHeaderCount = KBTS__MAX(SubHeaderCount, SubHeaderIndex + 1); + } + + kbts__sub_header *SubHeaders = KBTS__POINTER_AFTER(kbts__sub_header, Cmap2); + if(kbts__ByteSwapArray16(&SubHeaders->FirstCode, 4 * SubHeaderCount, TableEnd)) + { + kbts_u16 *GlyphIds = (kbts_u16 *)(SubHeaders + SubHeaderCount); + + kbts_sn GlyphIdCount = 0; + KBTS__FOR(It, 0, SubHeaderCount) + { + kbts__sub_header *SubHeader = &SubHeaders[It]; + + kbts_u16 *OnePastLastGlyphId = &SubHeader->IdRangeOffset + SubHeader->IdRangeOffset / 2 + SubHeader->EntryCount; + GlyphIdCount = KBTS__MAX(GlyphIdCount, OnePastLastGlyphId - GlyphIds); + } + + if(kbts__ByteSwapArray16(GlyphIds, (kbts_un)GlyphIdCount, TableEnd)) + { + TableValid = 1; + } + } + } + } + break; + + case 4: + { + kbts__cmap_4 *Cmap4 = (kbts__cmap_4 *)PreferredSubtable.Subtable; + if(kbts__ByteSwapArray16(&Cmap4->Length, 5, TableEnd) && + kbts__ByteSwapArray16(KBTS__POINTER_AFTER(kbts_u16, Cmap4), Cmap4->SegmentCountTimesTwo * 2 + 1, TableEnd)) + { + kbts_un SegmentCount = Cmap4->SegmentCountTimesTwo / 2; + kbts_u16 *EndCodes = KBTS__POINTER_AFTER(kbts_u16, Cmap4); + kbts_u16 *StartCodes = EndCodes + SegmentCount + 1; + kbts_s16 *IdDeltas = (kbts_s16 *)(StartCodes + SegmentCount); + kbts_u16 *IdRangeOffsets = (kbts_u16 *)(IdDeltas + SegmentCount); + kbts_u16 *GlyphIds = IdRangeOffsets + SegmentCount; + + kbts_sn GlyphIdCount = 0; + + KBTS__FOR(SegmentIndex, 0, SegmentCount) + { + kbts_u16 Offset = IdRangeOffsets[SegmentIndex]; + + if(Offset) + { + kbts_u16 *IdLookup = &IdRangeOffsets[SegmentIndex] + (EndCodes[SegmentIndex] - StartCodes[SegmentIndex] + 1) + Offset / 2; + + GlyphIdCount = KBTS__MAX(GlyphIdCount, (IdLookup - GlyphIds)); + } + } + + if(kbts__ByteSwapArray16(GlyphIds, (kbts_un)GlyphIdCount, TableEnd)) + { + TableValid = 1; + } + } + } + break; + + case 6: + { + kbts__cmap_6 *Cmap6 = (kbts__cmap_6 *)PreferredSubtable.Subtable; + if(kbts__ByteSwapArray16(&Cmap6->Length, 4, TableEnd) && + kbts__ByteSwapArray16(KBTS__POINTER_AFTER(kbts_u16, Cmap6), Cmap6->EntryCount, TableEnd)) + { + TableValid = 1; + } + } + break; + + case 12: + { + kbts__cmap_12_13 *Cmap12 = (kbts__cmap_12_13 *)PreferredSubtable.Subtable; + if(kbts__ByteSwapArray32(&Cmap12->Length, 3, TableEnd) && + kbts__ByteSwapArray32(KBTS__POINTER_AFTER(kbts_u32, Cmap12), Cmap12->GroupCount * 3, TableEnd)) + { + TableValid = 1; + } + } + break; + } + + Font->Cmap = PreferredSubtable.Subtable; + } + } + + if(!TableValid) + { + Result = KBTS_LOAD_FONT_ERROR_INVALID_FONT; + } + } + else + { + Result = KBTS_LOAD_FONT_ERROR_INVALID_FONT; + } + } + } + + { + kbts_blob_table *GdefTable = &Header->Tables[KBTS_BLOB_TABLE_ID_GDEF]; + + if(GdefTable->Length) + { + kbts__gdef *Gdef = KBTS__POINTER_OFFSET(kbts__gdef, Header, GdefTable->OffsetFromStartOfFile); + char *TableEnd = KBTS__POINTER_OFFSET(char, Header, GdefTable->OffsetFromStartOfFile + GdefTable->Length); + + if(kbts__ByteSwapArray16(&Gdef->Major, 6, TableEnd)) + { + if(Gdef->Minor >= 2) + { + if(GdefTable->Length >= 14) + { + Gdef->MarkGlyphSetsDefinitionOffset = kbts__ByteSwap16(Gdef->MarkGlyphSetsDefinitionOffset); + + if(Gdef->Minor == 3) + { + if(GdefTable->Length >= sizeof(kbts__gdef)) + { + // @Incomplete + Gdef->ItemVariationStoreOffset = kbts__ByteSwap32(Gdef->ItemVariationStoreOffset); + } + else + { + Result = KBTS_LOAD_FONT_ERROR_INVALID_FONT; + } + } + } + else + { + Result = KBTS_LOAD_FONT_ERROR_INVALID_FONT; + } + } + } + else + { + Result = KBTS_LOAD_FONT_ERROR_INVALID_FONT; + } + } + } + + { + kbts_blob_table_id HeaTableIds[2] = {KBTS_BLOB_TABLE_ID_HHEA, KBTS_BLOB_TABLE_ID_VHEA}; + KBTS__FOR(HeaTableIndex, 0, KBTS__ARRAY_LENGTH(HeaTableIds)) + { + kbts_blob_table *HeaTable = &Header->Tables[HeaTableIds[HeaTableIndex]]; + + if(HeaTable->Length) + { + kbts__hea *Hea = KBTS__POINTER_OFFSET(kbts__hea, Header, HeaTable->OffsetFromStartOfFile); + char *TableEnd = KBTS__POINTER_OFFSET(char, Header, HeaTable->OffsetFromStartOfFile + HeaTable->Length); + + if(!kbts__ByteSwapArray16((kbts_u16 *)Hea, sizeof(kbts__hea) / sizeof(kbts_u16), TableEnd)) + { + Result = KBTS_LOAD_FONT_ERROR_INVALID_FONT; + } + } + } + } + + { + kbts_blob_table_id MtxTableIds[2] = {KBTS_BLOB_TABLE_ID_HMTX, KBTS_BLOB_TABLE_ID_VMTX}; + + KBTS__FOR(MtxTableIndex, 0, KBTS__ARRAY_LENGTH(MtxTableIds)) + { + kbts_blob_table *MtxTable = &Header->Tables[MtxTableIds[MtxTableIndex]]; + + if(MtxTable->Length) + { + kbts_u16 *Mtx = KBTS__POINTER_OFFSET(kbts_u16, Header, MtxTable->OffsetFromStartOfFile); + kbts__ByteSwapArray16Unchecked(Mtx, MtxTable->Length / sizeof(kbts_u16)); + } + } + } + + { + kbts_blob_table *MaxpTable = &Header->Tables[KBTS_BLOB_TABLE_ID_MAXP]; + + if(MaxpTable->Length) + { + if(MaxpTable->Length >= 6) + { + kbts__maxp *Maxp = KBTS__POINTER_OFFSET(kbts__maxp, Header, MaxpTable->OffsetFromStartOfFile); + char *TableEnd = KBTS__POINTER_OFFSET(char, Header, MaxpTable->OffsetFromStartOfFile + MaxpTable->Length); + + Maxp->Major = kbts__ByteSwap16(Maxp->Major); + Maxp->Minor = kbts__ByteSwap16(Maxp->Minor); + + kbts_un U16Count = 0; + if(!Maxp->Major && (Maxp->Minor == 0x5000)) + { + U16Count = 1; + } + else if((Maxp->Major == 1) && !Maxp->Minor) + { + U16Count = 14; + } + + if(kbts__ByteSwapArray16(&Maxp->GlyphCount, U16Count, TableEnd)) + { + Header->GlyphCount = Maxp->GlyphCount; + } + else + { + Result = KBTS_LOAD_FONT_ERROR_INVALID_FONT; + } + } + else + { + Result = KBTS_LOAD_FONT_ERROR_INVALID_FONT; + } + } + } + + { + kbts_blob_table *Os2Table = &Header->Tables[KBTS_BLOB_TABLE_ID_OS2]; + + if(Os2Table->Length) + { + kbts__os2 *Os2 = KBTS__POINTER_OFFSET(kbts__os2, Header, Os2Table->OffsetFromStartOfFile); + kbts_un Length = Os2Table->Length; + + if(Length >= 68) + { + kbts__ByteSwapArray16Unchecked(&Os2->Version, 16); + kbts__ByteSwapArray32Unchecked(Os2->UnicodeRange, 4); + kbts__ByteSwapArray16Unchecked(&Os2->Selection, 3); + + kbts_un Version = Os2->Version; + + if(Length >= 78) + { + kbts__ByteSwapArray16Unchecked((kbts_u16 *)&Os2->TypoAscender, 5); + + if(Version >= 1) + { + if(Length >= 86) + { + kbts__ByteSwapArray32Unchecked(Os2->CodePageRange, 2); + + if(Version >= 2) + { + if(Length >= 96) + { + kbts__ByteSwapArray16Unchecked((kbts_u16 *)&Os2->Height, 5); + + if(Version >= 5) + { + if(Length >= 100) + { + kbts__ByteSwapArray16Unchecked(&Os2->LowerOpticalPointSize, 2); + } + else + { + Result = KBTS_LOAD_FONT_ERROR_INVALID_FONT; + } + } + } + else + { + Result = KBTS_LOAD_FONT_ERROR_INVALID_FONT; + } + } + } + else + { + Result = KBTS_LOAD_FONT_ERROR_INVALID_FONT; + } + } + } + } + else + { + Result = KBTS_LOAD_FONT_ERROR_INVALID_FONT; + } + } + // We should normally set Result to INVALID_FONT if there is no OS/2 table. + // However, one Harfbuzz test has a font with no OS/2 table. + } + + { + kbts_blob_table *NameTable = &Header->Tables[KBTS_BLOB_TABLE_ID_NAME]; + + if(NameTable->Length >= sizeof(kbts__name)) + { + kbts__name *Name = KBTS__POINTER_OFFSET(kbts__name, Header, NameTable->OffsetFromStartOfFile); + char *TableEnd = KBTS__POINTER_OFFSET(char, Name, NameTable->Length); + + kbts__ByteSwapArray16Unchecked(&Name->Version, 3); + + kbts__name_record *NameRecords = KBTS__POINTER_AFTER(kbts__name_record, Name); + + kbts_un U16Count = Name->Count * 6; + if(!kbts__ByteSwapArray16(&NameRecords->PlatformId, U16Count, TableEnd)) + { + Result = KBTS_LOAD_FONT_ERROR_INVALID_FONT; + } + } + // We should normally set Result to INVALID_FONT if there is no name table. + // However, one Harfbuzz test has a font with no name table. + } + + kbts__byteswap_context ByteSwapContext = KBTS__ZERO; + ByteSwapContext.FileBase = (char *)Header; + ByteSwapContext.FileEnd = (char *)Header + State->TotalSize; + ByteSwapContext.PointerCapacity = State->ScratchSize / sizeof(kbts_u32); + ByteSwapContext.Pointers = (kbts_u32 *)ScratchMemory; + + kbts_blob_table *GdefTable = &Header->Tables[KBTS_BLOB_TABLE_ID_GDEF]; + if(GdefTable->Length) + { + kbts__gdef *Gdef = KBTS__POINTER_OFFSET(kbts__gdef, Header, GdefTable->OffsetFromStartOfFile); + + if(Gdef->ClassDefinitionOffset) + { + kbts_u16 *ClassDefBase = KBTS__POINTER_OFFSET(kbts_u16, Gdef, Gdef->ClassDefinitionOffset); + kbts__ByteSwapClassDefinition(&ByteSwapContext, ClassDefBase); + } + + if(Gdef->MarkAttachmentClassDefinitionOffset) + { + kbts_u16 *ClassDefBase = KBTS__POINTER_OFFSET(kbts_u16, Gdef, Gdef->MarkAttachmentClassDefinitionOffset); + kbts__ByteSwapClassDefinition(&ByteSwapContext, ClassDefBase); + } + + if((Gdef->Minor >= 2) && Gdef->MarkGlyphSetsDefinitionOffset) + { + kbts__mark_glyph_sets *MarkGlyphSets = KBTS__POINTER_OFFSET(kbts__mark_glyph_sets, Gdef, Gdef->MarkGlyphSetsDefinitionOffset); + kbts__ByteSwapArray16Context(&MarkGlyphSets->Format, 2, &ByteSwapContext); + if(MarkGlyphSets->Format == 1) + { + kbts_u32 *CoverageOffsets = KBTS__POINTER_AFTER(kbts_u32, MarkGlyphSets); + kbts__ByteSwapArray32Context(CoverageOffsets, MarkGlyphSets->MarkGlyphSetCount, &ByteSwapContext); + + KBTS__FOR(MarkGlyphSetIndex, 0, MarkGlyphSets->MarkGlyphSetCount) + { + kbts__coverage *Coverage = KBTS__POINTER_OFFSET(kbts__coverage, MarkGlyphSets, CoverageOffsets[MarkGlyphSetIndex]); + kbts__ByteSwapCoverage(&ByteSwapContext, Coverage); + } + } + } + } + + kbts__gsub_gpos *Gsub = kbts__BlobTableDataType(Header, KBTS_BLOB_TABLE_ID_GSUB, kbts__gsub_gpos); + kbts__gsub_gpos *Gpos = kbts__BlobTableDataType(Header, KBTS_BLOB_TABLE_ID_GPOS, kbts__gsub_gpos); + kbts__gdef *Gdef = kbts__BlobTableDataType(Header, KBTS_BLOB_TABLE_ID_GDEF, kbts__gdef); + + if(Gsub) + { + kbts__ByteSwapGsubGposCommon(&ByteSwapContext, Gsub); + + kbts_lookup_list *LookupList = kbts__GetLookupList(Gsub); + LookupList->Count = kbts__ByteSwap16(LookupList->Count); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, LookupList), LookupList->Count, &ByteSwapContext); + + KBTS__FOR(LookupIndex, 0, LookupList->Count) + { + kbts__lookup *PackedLookup = kbts__GetLookup(LookupList, LookupIndex); + + KBTS_DUMPF("GSUB Lookup %llu:\n", LookupIndex); + + if(kbts__ByteSwapLookup(&ByteSwapContext, PackedLookup)) + { + kbts__unpacked_lookup Lookup = kbts__UnpackLookup(Gdef, PackedLookup); + KBTS_DUMPF(" Flags %u\n", Lookup.Flags); + + KBTS__FOR(SubstitutionIndex, 0, Lookup.SubtableCount) + { + kbts_u16 *Base = KBTS__POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[SubstitutionIndex]); + + KBTS_DUMPF(" Subtable %llu:\n", SubstitutionIndex); + + kbts__ByteSwapGsubLookupSubtable(&ByteSwapContext, Lookup.Type, Base); + } + } + } + } + + if(Gpos) + { + kbts__ByteSwapGsubGposCommon(&ByteSwapContext, Gpos); + + kbts_lookup_list *LookupList = kbts__GetLookupList(Gpos); + LookupList->Count = kbts__ByteSwap16(LookupList->Count); + kbts__ByteSwapArray16Context(KBTS__POINTER_AFTER(kbts_u16, LookupList), LookupList->Count, &ByteSwapContext); + + KBTS__FOR(LookupIndex, 0, LookupList->Count) + { + kbts__lookup *PackedLookup = kbts__GetLookup(LookupList, LookupIndex); + + KBTS_DUMPF("GPOS Lookup %llu:\n", LookupIndex); + + if(kbts__ByteSwapLookup(&ByteSwapContext, PackedLookup)) + { + kbts__unpacked_lookup Lookup = kbts__UnpackLookup(Gdef, PackedLookup); + + KBTS_DUMPF(" Flags %x\n", Lookup.Flags); + + KBTS__FOR(SubstitutionIndex, 0, Lookup.SubtableCount) + { + kbts_u16 *Base = KBTS__POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[SubstitutionIndex]); + + KBTS_DUMPF(" Subtable %llu:\n", (kbts_un)SubstitutionIndex); + + kbts__ByteSwapGposLookupSubtable(&ByteSwapContext, LookupList, Lookup.Type, Base); + } + } + } + } + + // At this point, we are done byteswapping the file, so we can start reusing scratch memory. + + // Bake our own data. + + if(!Result && Header->Tables[KBTS_BLOB_TABLE_ID_MAXP].Length) + { + kbts_un GlyphCount = Header->GlyphCount; + kbts_un LookupCount = Header->LookupCount; + kbts_un SubtableCount = Header->LookupSubtableCount; + + kbts_u32 *GlyphLookupMatrix = (kbts_u32 *)OutData; + kbts_u32 *GlyphLookupSubtableMatrix = KBTS__POINTER_OFFSET(kbts_u32, GlyphLookupMatrix, State->GlyphLookupMatrixSizeInBytes); + kbts_u32 *LookupSubtableIndexOffsets = KBTS__POINTER_OFFSET(kbts_u32, GlyphLookupSubtableMatrix, State->GlyphLookupSubtableMatrixSizeInBytes); + kbts_lookup_subtable_info *SubtableInfos = KBTS__POINTER_OFFSET(kbts_lookup_subtable_info, LookupSubtableIndexOffsets, sizeof(kbts_u32) * Header->LookupCount); + + KBTS_MEMSET(GlyphLookupMatrix, 0, State->GlyphLookupMatrixSizeInBytes + + State->GlyphLookupSubtableMatrixSizeInBytes + + sizeof(kbts_u32) * Header->LookupCount + + sizeof(kbts_lookup_subtable_info) * Header->LookupSubtableCount); + + kbts_un GposLookupIndexOffset = 0; + kbts_un RunningLookupIndex = 0; + kbts_un RunningSubtableIndex = 0; + + kbts_blob_table_id TableIds[2] = {KBTS_BLOB_TABLE_ID_GSUB, KBTS_BLOB_TABLE_ID_GPOS}; + KBTS__FOR(TableIdIndex, 0, KBTS__ARRAY_LENGTH(TableIds)) + { + kbts_blob_table_id TableId = TableIds[TableIdIndex]; + kbts_blob_table *Table = &Header->Tables[TableId]; + + if(Table->Length) + { + kbts__gsub_gpos *ShapingTable = KBTS__POINTER_OFFSET(kbts__gsub_gpos, Header, Table->OffsetFromStartOfFile); + int InGpos = (TableId == KBTS_BLOB_TABLE_ID_GPOS); + kbts_shaping_table ShapingTableId = (kbts_shaping_table)(InGpos ? KBTS_SHAPING_TABLE_GPOS : KBTS_SHAPING_TABLE_GSUB); + + if(InGpos) + { + GposLookupIndexOffset = RunningLookupIndex; + } + + if(ShapingTable) + { + kbts_lookup_list *LookupList = kbts__GetLookupList(ShapingTable); + KBTS__FOR(LookupIndex, 0, LookupList->Count) + { + kbts__lookup *PackedLookup = kbts__GetLookup(LookupList, LookupIndex); + kbts__unpacked_lookup Lookup = kbts__UnpackLookup(Gdef, PackedLookup); + + LookupSubtableIndexOffsets[RunningLookupIndex] = (kbts_u32)RunningSubtableIndex; + + KBTS__FOR(SubtableIndex, 0, Lookup.SubtableCount) + { + kbts_lookup_subtable_info SubtableInfo = KBTS__ZERO; + kbts_u16 LookupType = Lookup.Type; + kbts_u16 *Base = KBTS__POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[SubtableIndex]); + + while((!InGpos && (LookupType == 7)) || + (InGpos && (LookupType == 9))) + { + kbts__extension *Extension = (kbts__extension *)Base; + + // CAREFUL: Here, we remap LookupType only. + // Do not use Lookup.Type beyond this point! + LookupType = Extension->LookupType; + Base = KBTS__POINTER_OFFSET(kbts_u16, Extension, Extension->Offset); + } + + kbts__coverage *Coverage = 0; + + if(kbts__LookupBeginsWithCoverage(ShapingTableId, LookupType, Base[0])) + { + Coverage = KBTS__POINTER_OFFSET(kbts__coverage, Base, Base[1]); + } + + if(!InGpos && (LookupType == 4)) + { + kbts__ligature_substitution *Subst = (kbts__ligature_substitution *)Base; + KBTS__FOR(SetIndex, 0, Subst->LigatureSetCount) + { + kbts__ligature_set *Set = kbts__GetLigatureSet(Subst, SetIndex); + KBTS__FOR(LigatureIndex, 0, Set->Count) + { + kbts__ligature *Ligature = kbts__GetLigature(Set, LigatureIndex); + kbts_u16 *Ids = KBTS__POINTER_AFTER(kbts_u16, Ligature); + + KBTS__FOR(IdIndex, 1, Ligature->ComponentCount) + { + kbts_un GlyphId = Ids[IdIndex - 1]; + + kbts__matrix_index SubtableMatrixIndex = kbts__GlyphLookupSubtableMatrixIndex(RunningSubtableIndex, SubtableCount, GlyphId); + GlyphLookupSubtableMatrix[SubtableMatrixIndex.WordIndex] |= 1 << SubtableMatrixIndex.BitIndex; + } + + SubtableInfo.MinimumFollowupPlusOne = KBTS__MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Ligature->ComponentCount - 1) + 1; + } + } + } + else if((!InGpos && (LookupType == 5)) || + (InGpos && (LookupType == 7))) + { + switch(Base[0]) + { + case 1: + { + kbts__sequence_context_1 *Subst = (kbts__sequence_context_1 *)Base; + KBTS__FOR(SetIndex, 0, Subst->SeqRuleSetCount) + { + kbts__sequence_rule_set *Set = kbts__GetSequenceRuleSet(Subst, SetIndex); + + if(Set) + { + KBTS__FOR(RuleIndex, 0, Set->Count) + { + kbts__sequence_rule *Rule = kbts__GetSequenceRule(Set, RuleIndex); + SubtableInfo.MinimumFollowupPlusOne = KBTS__MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Rule->GlyphCount - 1) + 1; + + kbts_u16 *SequenceGlyphIds = KBTS__POINTER_AFTER(kbts_u16, Rule); + KBTS__FOR(InputIndex, 1, Rule->GlyphCount) + { + kbts_un GlyphId = SequenceGlyphIds[InputIndex - 1]; + + kbts__matrix_index SubtableMatrixIndex = kbts__GlyphLookupSubtableMatrixIndex(RunningSubtableIndex, SubtableCount, GlyphId); + GlyphLookupSubtableMatrix[SubtableMatrixIndex.WordIndex] |= 1 << SubtableMatrixIndex.BitIndex; + } + } + } + } + } break; + + case 2: + { + kbts__sequence_context_2 *Subst = (kbts__sequence_context_2 *)Base; + kbts_u16 *ClassDefBase = KBTS__POINTER_OFFSET(kbts_u16, Subst, Subst->ClassDefOffset); + + kbts_u64 ClassesIncluded[16] = KBTS__ZERO; + + KBTS__FOR(SetIndex, 0, Subst->ClassSequenceRuleSetCount) + { + kbts__class_sequence_rule_set *Set = kbts__GetClassSequenceRuleSet(Subst, SetIndex); + if(Set) + { + KBTS__FOR(RuleIndex, 0, Set->Count) + { + kbts__class_sequence_rule *Rule = kbts__GetClassSequenceRule(Set, RuleIndex); + kbts_u16 *SequenceClasses = KBTS__POINTER_AFTER(kbts_u16, Rule); + + SubtableInfo.MinimumFollowupPlusOne = KBTS__MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Rule->GlyphCount - 1) + 1; + + KBTS__FOR(SequenceIndex, 1, Rule->GlyphCount) + { + kbts_un Class = SequenceClasses[SequenceIndex - 1]; + + if(Class < (KBTS__ARRAY_LENGTH(ClassesIncluded) * 64)) + { + ClassesIncluded[Class / 64] |= 1ull << (Class % 64); + } + } + } + } + } + + kbts__MarkMatrixClassDef(GlyphLookupSubtableMatrix, RunningSubtableIndex, SubtableCount, GlyphCount, ClassDefBase, ClassesIncluded, KBTS__ARRAY_LENGTH(ClassesIncluded)); + } break; + + case 3: + { + kbts__sequence_context_3 *Subst = (kbts__sequence_context_3 *)Base; + kbts_u16 *CoverageOffsets = KBTS__POINTER_AFTER(kbts_u16, Subst); + + SubtableInfo.MinimumFollowupPlusOne = KBTS__MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Subst->GlyphCount - 1) + 1; + + KBTS__FOR(CoverageIndex, 1, Subst->GlyphCount) + { + kbts__coverage *SubstCoverage = KBTS__POINTER_OFFSET(kbts__coverage, Subst, CoverageOffsets[CoverageIndex]); + + kbts__MarkMatrixCoverage(GlyphLookupSubtableMatrix, RunningSubtableIndex, SubtableCount, GlyphCount, SubstCoverage, 1); + } + + Coverage = KBTS__POINTER_OFFSET(kbts__coverage, Subst, CoverageOffsets[0]); + } break; + } + } + else if((!InGpos && (LookupType == 6)) || + (InGpos && (LookupType == 8))) + { + switch(Base[0]) + { + case 1: + { + kbts__chained_sequence_context_1 *Subst = (kbts__chained_sequence_context_1 *)Base; + kbts_u16 *ChainedSequenceRuleSetOffsets = KBTS__POINTER_AFTER(kbts_u16, Subst); + + KBTS__FOR(SetIndex, 0, Subst->ChainedSequenceRuleSetCount) + { + kbts__chained_sequence_rule_set *Set = KBTS__POINTER_OFFSET(kbts__chained_sequence_rule_set, Subst, ChainedSequenceRuleSetOffsets[SetIndex]); + KBTS__FOR(RuleIndex, 0, Set->Count) + { + kbts__chained_sequence_rule *Rule = kbts__GetChainedClassSequenceRule(Set, RuleIndex); + kbts__unpacked_chained_sequence_rule Unpacked = kbts__UnpackChainedSequenceRule(Rule, 0); + + SubtableInfo.MinimumBacktrackPlusOne = KBTS__MIN(SubtableInfo.MinimumBacktrackPlusOne - 1, Unpacked.BacktrackCount) + 1; + SubtableInfo.MinimumFollowupPlusOne = KBTS__MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Unpacked.InputCount - 1 + Unpacked.LookaheadCount) + 1; + + KBTS__FOR(BacktrackIndex, 0, Unpacked.BacktrackCount) + { + kbts_un GlyphId = Unpacked.Backtrack[BacktrackIndex]; + kbts__matrix_index SubtableMatrixIndex = kbts__GlyphLookupSubtableMatrixIndex(RunningSubtableIndex, SubtableCount, GlyphId); + GlyphLookupSubtableMatrix[SubtableMatrixIndex.WordIndex] |= 1 << SubtableMatrixIndex.BitIndex; + } + + KBTS__FOR(InputIndex, 1, Unpacked.InputCount) + { + kbts_un GlyphId = Unpacked.Input[InputIndex - 1]; + kbts__matrix_index SubtableMatrixIndex = kbts__GlyphLookupSubtableMatrixIndex(RunningSubtableIndex, SubtableCount, GlyphId); + GlyphLookupSubtableMatrix[SubtableMatrixIndex.WordIndex] |= 1 << SubtableMatrixIndex.BitIndex; + } + + KBTS__FOR(LookaheadIndex, 0, Unpacked.LookaheadCount) + { + kbts_un GlyphId = Unpacked.Lookahead[LookaheadIndex]; + kbts__matrix_index SubtableMatrixIndex = kbts__GlyphLookupSubtableMatrixIndex(RunningSubtableIndex, SubtableCount, GlyphId); + GlyphLookupSubtableMatrix[SubtableMatrixIndex.WordIndex] |= 1 << SubtableMatrixIndex.BitIndex; + } + } + } + } break; + + case 2: + { + kbts__chained_sequence_context_2 *Subst = (kbts__chained_sequence_context_2 *)Base; + kbts_un BacktrackClassDefOffset = Subst->BacktrackClassDefOffset; + kbts_un InputClassDefOffset = Subst->InputClassDefOffset; + kbts_un LookaheadClassDefOffset = Subst->LookaheadClassDefOffset; + kbts_u16 *BacktrackClassDefinition = 0; + if(BacktrackClassDefOffset) + { + BacktrackClassDefinition = KBTS__POINTER_OFFSET(kbts_u16, Subst, BacktrackClassDefOffset); + } + kbts_u16 *InputClassDefinition = 0; + if(InputClassDefOffset) + { + InputClassDefinition = KBTS__POINTER_OFFSET(kbts_u16, Subst, InputClassDefOffset); + } + kbts_u16 *LookaheadClassDefinition = 0; + if(LookaheadClassDefOffset) + { + LookaheadClassDefinition = KBTS__POINTER_OFFSET(kbts_u16, Subst, LookaheadClassDefOffset); + } + + kbts_u64 BacktrackClassesIncluded[16] = KBTS__ZERO; + kbts_u64 InputClassesIncluded[16] = KBTS__ZERO; + kbts_u64 LookaheadClassesIncluded[16] = KBTS__ZERO; + + KBTS__FOR(SetIndex, 0, Subst->ChainedClassSequenceRuleSetCount) + { + kbts__chained_sequence_rule_set *Set = kbts__GetChainedClassSequenceRuleSet(Subst, SetIndex); + if(Set) + { + KBTS__FOR(RuleIndex, 0, Set->Count) + { + kbts__chained_sequence_rule *Rule = kbts__GetChainedSequenceRule(Set, RuleIndex); + kbts__unpacked_chained_sequence_rule Unpacked = kbts__UnpackChainedSequenceRule(Rule, 0); + + SubtableInfo.MinimumBacktrackPlusOne = KBTS__MIN(SubtableInfo.MinimumBacktrackPlusOne - 1, Unpacked.BacktrackCount) + 1; + SubtableInfo.MinimumFollowupPlusOne = KBTS__MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Unpacked.InputCount - 1 + Unpacked.LookaheadCount) + 1; + + KBTS__FOR(BacktrackIndex, 0, Unpacked.BacktrackCount) + { + kbts_un Class = Unpacked.Backtrack[BacktrackIndex]; + if(Class < (KBTS__ARRAY_LENGTH(BacktrackClassesIncluded) * 64)) + { + BacktrackClassesIncluded[Class / 64] |= 1ull << (Class % 64); + } + } + + KBTS__FOR(InputIndex, 1, Unpacked.InputCount) + { + kbts_un Class = Unpacked.Input[InputIndex - 1]; + if(Class < (KBTS__ARRAY_LENGTH(InputClassesIncluded) * 64)) + { + InputClassesIncluded[Class / 64] |= 1ull << (Class % 64); + } + } + + KBTS__FOR(LookaheadIndex, 0, Unpacked.LookaheadCount) + { + kbts_un Class = Unpacked.Lookahead[LookaheadIndex]; + if(Class < (KBTS__ARRAY_LENGTH(LookaheadClassesIncluded) * 64)) + { + LookaheadClassesIncluded[Class / 64] |= 1ull << (Class % 64); + } + } + } + } + } + + kbts__MarkMatrixClassDef(GlyphLookupSubtableMatrix, RunningSubtableIndex, SubtableCount, GlyphCount, BacktrackClassDefinition, BacktrackClassesIncluded, KBTS__ARRAY_LENGTH(BacktrackClassesIncluded)); + kbts__MarkMatrixClassDef(GlyphLookupSubtableMatrix, RunningSubtableIndex, SubtableCount, GlyphCount, InputClassDefinition, InputClassesIncluded, KBTS__ARRAY_LENGTH(InputClassesIncluded)); + kbts__MarkMatrixClassDef(GlyphLookupSubtableMatrix, RunningSubtableIndex, SubtableCount, GlyphCount, LookaheadClassDefinition, LookaheadClassesIncluded, KBTS__ARRAY_LENGTH(LookaheadClassesIncluded)); + } break; + + case 3: + { + kbts__chained_sequence_context_3 *Subst = (kbts__chained_sequence_context_3 *)Base; + kbts__unpacked_chained_sequence_context_3 Unpacked = kbts__UnpackChainedSequenceContext3(Subst, 0); + + Coverage = KBTS__POINTER_OFFSET(kbts__coverage, Subst, Unpacked.InputCoverageOffsets[0]); + + SubtableInfo.MinimumBacktrackPlusOne = KBTS__MIN(SubtableInfo.MinimumBacktrackPlusOne - 1, Unpacked.BacktrackCount) + 1; + SubtableInfo.MinimumFollowupPlusOne = KBTS__MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Unpacked.InputCount - 1 + Unpacked.LookaheadCount) + 1; + + KBTS__FOR(BacktrackCoverageIndex, 0, Unpacked.BacktrackCount) + { + kbts__coverage *SubCoverage = KBTS__POINTER_OFFSET(kbts__coverage, Subst, Unpacked.BacktrackCoverageOffsets[BacktrackCoverageIndex]); + kbts__MarkMatrixCoverage(GlyphLookupSubtableMatrix, RunningSubtableIndex, SubtableCount, GlyphCount, SubCoverage, 1); + } + + KBTS__FOR(InputCoverageIndex, 1, Unpacked.InputCount) + { + kbts__coverage *SubCoverage = KBTS__POINTER_OFFSET(kbts__coverage, Subst, Unpacked.InputCoverageOffsets[InputCoverageIndex]); + kbts__MarkMatrixCoverage(GlyphLookupSubtableMatrix, RunningSubtableIndex, SubtableCount, GlyphCount, SubCoverage, 1); + } + + + KBTS__FOR(LookaheadCoverageIndex, 0, Unpacked.LookaheadCount) + { + kbts__coverage *SubCoverage = KBTS__POINTER_OFFSET(kbts__coverage, Subst, Unpacked.LookaheadCoverageOffsets[LookaheadCoverageIndex]); + kbts__MarkMatrixCoverage(GlyphLookupSubtableMatrix, RunningSubtableIndex, SubtableCount, GlyphCount, SubCoverage, 1); + } + } break; + } + } + else if(!InGpos && (LookupType == 8)) + { + kbts__reverse_chain_substitution *Subst = (kbts__reverse_chain_substitution *)Base; + kbts__unpacked_reverse_chain_substitution Unpacked = kbts__UnpackReverseChainSubstitution(Subst, 0); + SubtableInfo.MinimumBacktrackPlusOne = KBTS__MIN(SubtableInfo.MinimumBacktrackPlusOne - 1, Unpacked.BacktrackCount) + 1; + SubtableInfo.MinimumFollowupPlusOne = KBTS__MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Unpacked.LookaheadCount) + 1; + + KBTS__FOR(BacktrackIndex, 0, Unpacked.BacktrackCount) + { + kbts__coverage *SubCoverage = KBTS__POINTER_OFFSET(kbts__coverage, Subst, Unpacked.BacktrackCoverageOffsets[BacktrackIndex]); + kbts__MarkMatrixCoverage(GlyphLookupSubtableMatrix, RunningSubtableIndex, SubtableCount, GlyphCount, SubCoverage, 1); + } + + KBTS__FOR(LookaheadIndex, 0, Unpacked.LookaheadCount) + { + kbts__coverage *SubCoverage = KBTS__POINTER_OFFSET(kbts__coverage, Subst, Unpacked.LookaheadCoverageOffsets[LookaheadIndex]); + kbts__MarkMatrixCoverage(GlyphLookupSubtableMatrix, RunningSubtableIndex, SubtableCount, GlyphCount, SubCoverage, 1); + } + } + + kbts__MarkMatrixCoverage(GlyphLookupMatrix, RunningLookupIndex, LookupCount, GlyphCount, Coverage, 0); + kbts__MarkMatrixCoverage(GlyphLookupSubtableMatrix, RunningSubtableIndex, SubtableCount, GlyphCount, Coverage, 1); + + SubtableInfos[RunningSubtableIndex] = SubtableInfo; + RunningSubtableIndex += 1; + } + + RunningLookupIndex += 1; + } + } + } + } + + Header->GposLookupIndexOffset = (kbts_u32)GposLookupIndexOffset; + Header->GlyphLookupMatrixOffsetFromStartOfFile = KBTS__POINTER_DIFF32(GlyphLookupMatrix, Header); + Header->GlyphLookupSubtableMatrixOffsetFromStartOfFile = KBTS__POINTER_DIFF32(GlyphLookupSubtableMatrix, Header); + Header->LookupSubtableIndexOffsetsOffsetFromStartOfFile = KBTS__POINTER_DIFF32(LookupSubtableIndexOffsets, Header); + Header->SubtableInfosOffsetFromStartOfFile = KBTS__POINTER_DIFF32(SubtableInfos, Header); + } + } + + if(Result != KBTS_LOAD_FONT_ERROR_NONE) + { + Font->Blob = 0; + } + Font->Error = Result; + + return Result; +} + +KBTS_EXPORT void kbts_GetFontInfo(kbts_font *Font, kbts_font_info *Info) +{ + KBTS_MEMSET(Info, 0, sizeof(*Info)); + kbts_blob_header *Blob = Font->Blob; + + if(kbts_FontIsValid(Font) && Blob) + { + kbts_blob_table *NameTable = &Blob->Tables[KBTS_BLOB_TABLE_ID_NAME]; + + if(NameTable->Length) + { + kbts__name *Name = KBTS__POINTER_OFFSET(kbts__name, Blob, NameTable->OffsetFromStartOfFile); + kbts__name_record *Records = KBTS__POINTER_AFTER(kbts__name_record, Name); + char *StringBase = KBTS__POINTER_OFFSET(char, Name, Name->StringStorageOffset); + + KBTS__FOR(RecordIndex, 0, Name->Count) + { + kbts__name_record *Record = &Records[RecordIndex]; + + if(!Record->LanguageId) + { + kbts_font_info_string_id Id = KBTS_FONT_INFO_STRING_ID_NONE; + + switch(Record->NameId) + { + case 0: Id = KBTS_FONT_INFO_STRING_ID_COPYRIGHT; break; + case 1: Id = KBTS_FONT_INFO_STRING_ID_FAMILY; break; + case 2: Id = KBTS_FONT_INFO_STRING_ID_SUBFAMILY; break; + case 3: Id = KBTS_FONT_INFO_STRING_ID_UID; break; + case 4: Id = KBTS_FONT_INFO_STRING_ID_FULL_NAME; break; + case 5: Id = KBTS_FONT_INFO_STRING_ID_VERSION; break; + case 6: Id = KBTS_FONT_INFO_STRING_ID_POSTSCRIPT_NAME; break; + case 7: Id = KBTS_FONT_INFO_STRING_ID_TRADEMARK; break; + case 8: Id = KBTS_FONT_INFO_STRING_ID_MANUFACTURER; break; + case 9: Id = KBTS_FONT_INFO_STRING_ID_DESIGNER; break; + case 10: Id = KBTS_FONT_INFO_STRING_ID_TYPOGRAPHIC_FAMILY; break; + case 11: Id = KBTS_FONT_INFO_STRING_ID_TYPOGRAPHIC_SUBFAMILY; break; + } + + if(Id) + { + Info->Strings[Id] = KBTS__POINTER_OFFSET(char, StringBase, Record->StringOffset); + Info->StringLengths[Id] = Record->Length; + } + } + } + + if(!Info->Strings[KBTS_FONT_INFO_STRING_ID_TYPOGRAPHIC_FAMILY]) + { + Info->Strings[KBTS_FONT_INFO_STRING_ID_TYPOGRAPHIC_FAMILY] = Info->Strings[KBTS_FONT_INFO_STRING_ID_FAMILY]; + Info->StringLengths[KBTS_FONT_INFO_STRING_ID_TYPOGRAPHIC_FAMILY] = Info->StringLengths[KBTS_FONT_INFO_STRING_ID_FAMILY]; + } + + if(!Info->Strings[KBTS_FONT_INFO_STRING_ID_TYPOGRAPHIC_SUBFAMILY]) + { + Info->Strings[KBTS_FONT_INFO_STRING_ID_TYPOGRAPHIC_SUBFAMILY] = Info->Strings[KBTS_FONT_INFO_STRING_ID_SUBFAMILY]; + Info->StringLengths[KBTS_FONT_INFO_STRING_ID_TYPOGRAPHIC_SUBFAMILY] = Info->StringLengths[KBTS_FONT_INFO_STRING_ID_SUBFAMILY]; + } + } + + kbts_blob_table *Os2Table = &Blob->Tables[KBTS_BLOB_TABLE_ID_OS2]; + + if(Os2Table->Length) + { + kbts__os2 *Os2 = KBTS__POINTER_OFFSET(kbts__os2, Blob, Os2Table->OffsetFromStartOfFile); + kbts_font_weight Weight = KBTS_FONT_WEIGHT_UNKNOWN; + kbts_font_width Width = KBTS_FONT_WIDTH_UNKNOWN; + kbts_font_style_flags StyleFlags = KBTS_FONT_STYLE_FLAG_NONE; + + switch(Os2->WeightClass) + { + case 100: Weight = KBTS_FONT_WEIGHT_THIN; break; + case 200: Weight = KBTS_FONT_WEIGHT_EXTRA_LIGHT; break; + case 300: Weight = KBTS_FONT_WEIGHT_LIGHT; break; + case 400: Weight = KBTS_FONT_WEIGHT_NORMAL; break; + case 500: Weight = KBTS_FONT_WEIGHT_MEDIUM; break; + case 600: Weight = KBTS_FONT_WEIGHT_SEMI_BOLD; break; + case 700: Weight = KBTS_FONT_WEIGHT_BOLD; break; + case 800: Weight = KBTS_FONT_WEIGHT_EXTRA_BOLD; break; + case 900: Weight = KBTS_FONT_WEIGHT_BLACK; break; + } + + switch(Os2->WidthClass) + { + case 1: Width = KBTS_FONT_WIDTH_ULTRA_CONDENSED; break; + case 2: Width = KBTS_FONT_WIDTH_EXTRA_CONDENSED; break; + case 3: Width = KBTS_FONT_WIDTH_CONDENSED; break; + case 4: Width = KBTS_FONT_WIDTH_SEMI_CONDENSED; break; + case 5: Width = KBTS_FONT_WIDTH_NORMAL; break; + case 6: Width = KBTS_FONT_WIDTH_SEMI_EXPANDED; break; + case 7: Width = KBTS_FONT_WIDTH_EXPANDED; break; + case 8: Width = KBTS_FONT_WIDTH_EXTRA_EXPANDED; break; + case 9: Width = KBTS_FONT_WIDTH_ULTRA_EXPANDED; break; + } + + if(Os2->Selection & (KBTS__OS2_SELECTION_FLAG_ITALIC | KBTS__OS2_SELECTION_FLAG_OBLIQUE)) + { + StyleFlags |= KBTS_FONT_STYLE_FLAG_ITALIC; + } + if(Os2->Selection & KBTS__OS2_SELECTION_FLAG_BOLD) + { + StyleFlags |= KBTS_FONT_STYLE_FLAG_BOLD; + } + if(Os2->Selection & KBTS__OS2_SELECTION_FLAG_REGULAR) + { + StyleFlags |= KBTS_FONT_STYLE_FLAG_REGULAR; + } + + Info->Weight = Weight; + Info->Width = Width; + Info->StyleFlags = StyleFlags; + } + } +} + +KBTS_EXPORT kbts_font kbts_FontFromMemory(void *FileData, int FileSize, int FontIndex, kbts_allocator_function *Allocator, void *AllocatorData) +{ + kbts_font Result = KBTS__ZERO; + + if(!Allocator) + { + Allocator = kbts__DefaultAllocator; + } + + if(FileData && (FileSize > 0)) + { + kbts_load_font_state LoadFontState = KBTS__ZERO; + int ScratchSize, OutputSize; + kbts_load_font_error Error = kbts_LoadFont(&Result, &LoadFontState, FileData, (int)FileSize, FontIndex, &ScratchSize, &OutputSize); + + if(Error == KBTS_LOAD_FONT_ERROR_NEED_TO_CREATE_BLOB) + { + void *ScratchMemory = kbts__AllocatorAllocate(Allocator, AllocatorData, (kbts_un)ScratchSize); + void *OutputMemory = kbts__AllocatorAllocate(Allocator, AllocatorData, (kbts_un)OutputSize); + + kbts_PlaceBlob(&Result, &LoadFontState, ScratchMemory, OutputMemory); + + kbts__AllocatorFree(Allocator, AllocatorData, ScratchMemory); + + Result.Allocator = Allocator; + Result.AllocatorData = AllocatorData; + } + } + + return Result; +} + +#ifndef KB_TEXT_SHAPE_NO_CRT + +KBTS_EXPORT kbts_font kbts_FontFromFile(const char *FileName, int FontIndex, kbts_allocator_function *Allocator, void *AllocatorData, void **FileData, int *FileSize_) +{ + kbts_font Result = KBTS__ZERO; + + if(!Allocator) + { + Allocator = kbts__DefaultAllocator; + } FILE *File; # ifndef _MSC_VER @@ -22835,90 +27850,189 @@ KBTS_EXPORT kbts_font kbts_FontFromFile(const char *FileName) long FileSize = ftell(File); fseek(File, 0, SEEK_SET); - void *Data = malloc((kbts_un)FileSize); - kbts_un Ok = fread(Data, (kbts_un)FileSize, 1, File); - fclose(File); - - if(Ok) + if(FileSize > 0) { - kbts_un ScratchSize = kbts_ReadFontHeader(&Result, Data, (kbts_un)FileSize); + void *Data = kbts__AllocatorAllocate(Allocator, AllocatorData, (kbts_un)FileSize); - void *Scratch = malloc(ScratchSize); - kbts_un MemorySize = kbts_ReadFontData(&Result, Scratch, ScratchSize); - - void *Memory = Scratch; - if(MemorySize > ScratchSize) + if(Data) { - free(Scratch); - Memory = malloc(MemorySize); - } + kbts_un Ok = fread(Data, (kbts_un)FileSize, 1, File); - kbts_PostReadFontInitialize(&Result, Memory, MemorySize); + if(Ok) + { + Result = kbts_FontFromMemory(Data, (int)FileSize, FontIndex, Allocator, AllocatorData); + + if(!Result.Error) + { + + if(FileData) + { + *FileData = Data; + } + else + { + kbts__AllocatorFree(Allocator, AllocatorData, Data); + } + + if(FileSize_) + { + *FileSize_ = (int)FileSize; + } + } + } + else + { + Result.Error = KBTS_LOAD_FONT_ERROR_READ_ERROR; + } + } + else + { + Result.Error = KBTS_LOAD_FONT_ERROR_OUT_OF_MEMORY; + } } + + fclose(File); + } + else + { + Result.Error = KBTS_LOAD_FONT_ERROR_COULD_NOT_OPEN_FILE; } return Result; } +#endif + KBTS_EXPORT void kbts_FreeFont(kbts_font *Font) { - if(Font->FileBase) + if(Font->Blob && Font->Allocator) { - free(Font->FileBase); - if(Font->GlyphLookupMatrix) - { - free(Font->GlyphLookupMatrix); // This frees everything else. - } + kbts__AllocatorFree(Font->Allocator, Font->AllocatorData, Font->Blob); } } -#endif -KBTS_EXPORT int kbts_BreakStateIsValid(kbts_break_state *State) +static void kbts__DoBreak(kbts_break_state *State, kbts_s32 Position, kbts_u8 Flags, kbts_direction Direction, kbts_direction ParagraphDirection, kbts_script Script) { - int Result = !(State->Flags & KBTS_BREAK_STATE_FLAG_RAN_OUT_OF_REORDER_BUFFER_SPACE); - return Result; -} - -static void kbts_DoBreak(kbts_break_state *State, kbts_s32 Position, kbts_u8 Flags, kbts_direction Direction, kbts_script Script) -{ - if(kbts_BreakStateIsValid(State) && Flags && (State->BreakCount < KBTS_BREAK_REORDER_BUFFER_SIZE)) + kbts_u32 BreakPosition = State->CurrentPosition + (kbts_u32)Position; + if(Flags && + (BreakPosition <= State->CurrentPosition)) { - if(State->BreakCount < KBTS_BREAK_REORDER_BUFFER_SIZE) + kbts_break Break = KBTS__ZERO; + Break.Position = (int)BreakPosition; + Break.Flags = Flags; + Break.Direction = Direction; + Break.ParagraphDirection = ParagraphDirection; + Break.Script = Script; + + if((Flags & KBTS_BREAK_FLAG_SCRIPT) && + (State->LastScriptBreakScript)) { - kbts_break Break = KBTS_ZERO; - Break.Position = State->CurrentPosition + (kbts_u32)Position; - Break.Flags = Flags; - Break.Direction = Direction; - Break.Script = Script; + kbts_un LastScriptBreakPosition = State->LastScriptBreakPosition; + kbts_u8 LastScriptBreakScript = State->LastScriptBreakScript; - int Matched = 0; - KBTS_FOR(BreakIndex, 0, State->BreakCount) + // Resolve bracket scripts here. + // The only span we can fully resolve is the _previous_ script, but we don't + // know when it starts, so we might as well tag all of the brackets we have stored so far. + for(kbts_un BracketIndex = State->BracketCount; + BracketIndex; + --BracketIndex) { - kbts_break *Existing = &State->Breaks[BreakIndex]; + kbts_bracket *Bracket = &State->Brackets[BracketIndex - 1]; - if(Existing->Position == Break.Position) + if(Bracket->Position >= BreakPosition) + { + Bracket->Script = (kbts_u8)Script; + } + else if(Bracket->Position >= LastScriptBreakPosition) + { + Bracket->Script = LastScriptBreakScript; + } + else { - Existing->Flags |= Break.Flags; - if(Break.Flags & KBTS_BREAK_FLAG_DIRECTION) Existing->Direction = Break.Direction; - if(Break.Flags & KBTS_BREAK_FLAG_SCRIPT) Existing->Script = Break.Script; - Matched = 1; break; } - else if(Existing->Position < Break.Position) + } + + State->LastScriptBreakPosition = BreakPosition; + State->LastScriptBreakScript = (kbts_u8)Script; + } + + if((Flags & KBTS_BREAK_FLAG_DIRECTION) && + (State->LastDirectionBreakDirection)) + { + kbts_un LastDirectionBreakPosition = State->LastDirectionBreakPosition; + kbts_u8 LastDirectionBreakDirection = State->LastDirectionBreakDirection; + + for(kbts_un BracketIndex = State->BracketCount; + BracketIndex; + --BracketIndex) + { + kbts_bracket *Bracket = &State->Brackets[BracketIndex - 1]; + + if(Bracket->Position >= BreakPosition) { - kbts_break Swap = *Existing; - *Existing = Break; - Break = Swap; + Bracket->Direction = (kbts_u8)Direction; + } + else if(Bracket->Position >= LastDirectionBreakPosition) + { + Bracket->Direction = LastDirectionBreakDirection; + } + else + { + break; } } - State->Breaks[State->BreakCount] = Break; - State->BreakCount += !Matched; + + State->LastDirectionBreakPosition = BreakPosition; + State->LastDirectionBreakDirection = (kbts_u8)Direction; } - else + + int Matched = 0; + KBTS__FOR(BreakIndex, 0, State->BreakCount) { - // This should never happen as long as we call Break() after every BreakAddCodepoint(). - State->Flags |= KBTS_BREAK_STATE_FLAG_RAN_OUT_OF_REORDER_BUFFER_SPACE; + kbts_break *Existing = &State->Breaks[BreakIndex]; + + if(Existing->Position == Break.Position) + { + Existing->Flags |= Break.Flags; + + if(Break.Flags & KBTS_BREAK_FLAG_DIRECTION) + { + Existing->Direction = Break.Direction; + } + + if(Break.Flags & KBTS_BREAK_FLAG_PARAGRAPH_DIRECTION) + { + Existing->ParagraphDirection = Break.ParagraphDirection; + } + + if(Break.Flags & KBTS_BREAK_FLAG_SCRIPT) + { + Existing->Script = Break.Script; + } + + Matched = 1; + + break; + } + else if(Existing->Position < Break.Position) + { + // We order breaks in backwards order here, because we want to simply pop them off the top in Break(). + kbts_break Swap = *Existing; + *Existing = Break; + Break = Swap; + } + else if((Break.Flags & KBTS_BREAK_FLAG_PARAGRAPH_DIRECTION) && + (Existing->Flags & KBTS_BREAK_FLAG_DIRECTION) && + !Existing->Direction) + { + // Short-circuit coerce neutral blocks to the paragraph direction. + Existing->Direction = Break.ParagraphDirection; + } } + + State->Breaks[State->BreakCount] = Break; + State->BreakCount += !Matched; } } @@ -22927,52 +28041,144 @@ static void kbts_DoBreak(kbts_break_state *State, kbts_s32 Position, kbts_u8 Fla // A required break implies an allowed break. // A priority N break implies priority 0..N-1 breaks. enum { - KBTS_LINE_BREAK_ALLOWED0 = 1, - KBTS_LINE_BREAK_ALLOWED1 = 3, - KBTS_LINE_BREAK_ALLOWED2 = 7, - KBTS_LINE_BREAK_ALLOWED3 = 0xF, - KBTS_LINE_BREAK_ALLOWED4 = 0x1F, - KBTS_LINE_BREAK_ALLOWED5 = 0x3F, - KBTS_LINE_BREAK_REQUIRED0 = (1 << 6) | KBTS_LINE_BREAK_ALLOWED0, - KBTS_LINE_BREAK_REQUIRED1 = (3 << 6) | KBTS_LINE_BREAK_ALLOWED1, - KBTS_LINE_BREAK_REQUIRED2 = (7 << 6) | KBTS_LINE_BREAK_ALLOWED2, - KBTS_LINE_BREAK_REQUIRED3 = (0xF << 6) | KBTS_LINE_BREAK_ALLOWED3, - KBTS_LINE_BREAK_REQUIRED4 = (0x1F << 6) | KBTS_LINE_BREAK_ALLOWED4, - KBTS_LINE_BREAK_REQUIRED5 = (0x3F << 6) | KBTS_LINE_BREAK_ALLOWED5, - KBTS_LINE_BREAK_REQUIRED_MASK = 0x3F << 6, - KBTS_LINE_BREAK_ALLOWED_MASK = 0x3F, - KBTS_LINE_BREAK_MASK = KBTS_LINE_BREAK_REQUIRED_MASK | KBTS_LINE_BREAK_ALLOWED_MASK, + KBTS__LINE_BREAK_ALLOWED0 = 1, + KBTS__LINE_BREAK_ALLOWED1 = 3, + KBTS__LINE_BREAK_ALLOWED2 = 7, + KBTS__LINE_BREAK_ALLOWED3 = 0xF, + KBTS__LINE_BREAK_ALLOWED4 = 0x1F, + KBTS__LINE_BREAK_ALLOWED5 = 0x3F, + KBTS__LINE_BREAK_REQUIRED0 = (1 << 6) | KBTS__LINE_BREAK_ALLOWED0, + KBTS__LINE_BREAK_REQUIRED1 = (3 << 6) | KBTS__LINE_BREAK_ALLOWED1, + KBTS__LINE_BREAK_REQUIRED2 = (7 << 6) | KBTS__LINE_BREAK_ALLOWED2, + KBTS__LINE_BREAK_REQUIRED3 = (0xF << 6) | KBTS__LINE_BREAK_ALLOWED3, + KBTS__LINE_BREAK_REQUIRED4 = (0x1F << 6) | KBTS__LINE_BREAK_ALLOWED4, + KBTS__LINE_BREAK_REQUIRED5 = (0x3F << 6) | KBTS__LINE_BREAK_ALLOWED5, + KBTS__LINE_BREAK_REQUIRED_MASK = 0x3F << 6, + KBTS__LINE_BREAK_ALLOWED_MASK = 0x3F, + KBTS__LINE_BREAK_MASK = KBTS__LINE_BREAK_REQUIRED_MASK | KBTS__LINE_BREAK_ALLOWED_MASK, }; -static void kbts_DoLineBreak(kbts_break_state *State, int Position, kbts_u64 EffectiveLineBreaks, int Rtl, kbts_script Script) +static void kbts__DoLineBreak(kbts_break_state *State, int Position, kbts_u64 EffectiveLineBreaks) { - if(EffectiveLineBreaks & KBTS_LINE_BREAK_MASK) + if(EffectiveLineBreaks & KBTS__LINE_BREAK_MASK) { kbts_u8 Flags = 0; - if(EffectiveLineBreaks & KBTS_LINE_BREAK_ALLOWED_MASK) Flags |= KBTS_BREAK_FLAG_LINE_SOFT; - if(EffectiveLineBreaks & KBTS_LINE_BREAK_REQUIRED_MASK) Flags |= KBTS_BREAK_FLAG_LINE_HARD; - kbts_DoBreak(State, Position, Flags, Rtl, Script); + if(EffectiveLineBreaks & KBTS__LINE_BREAK_ALLOWED_MASK) + { + Flags |= KBTS_BREAK_FLAG_LINE_SOFT; + } + + if(EffectiveLineBreaks & KBTS__LINE_BREAK_REQUIRED_MASK) + { + Flags |= KBTS_BREAK_FLAG_LINE_HARD; + } + + kbts__DoBreak(State, Position, Flags, 0, 0, 0); } } -static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, kbts_u32 PositionIncrement, int MaybeEndOfText) +static void kbts__BreakStateStartParagraph(kbts_break_state *State) +{ + kbts_direction ParagraphDirection = State->UserParagraphDirection; + // At the beginning of a paragraph, we want to pretend like start-of-text is an actual character + // with bidirectional data that depends on its direction. + kbts_u32 StartOfTextBidirectionalClass = KBTS_UNICODE_BIDIRECTIONAL_CLASS_NI; + kbts_u32 Flags = 0; + + if(ParagraphDirection == KBTS_DIRECTION_LTR) + { + StartOfTextBidirectionalClass = KBTS_UNICODE_BIDIRECTIONAL_CLASS_L; + } + else if(ParagraphDirection == KBTS_DIRECTION_RTL) + { + Flags = KBTS_BREAK_STATE_FLAG_SAW_R_AFTER_L; + StartOfTextBidirectionalClass = KBTS_UNICODE_BIDIRECTIONAL_CLASS_R; + } + + State->ParagraphDirection = (kbts_u8)ParagraphDirection; + State->BidirectionalClass1 = (kbts_u8)StartOfTextBidirectionalClass; + State->Flags = Flags; +} + +typedef kbts_u32 kbts__break_flush_flags; +enum kbts__break_flush_flags_enum +{ + KBTS__BREAK_FLUSH_FLAG_NONE, + KBTS__BREAK_FLUSH_FLAG_SCRIPT = (1 << 0), + KBTS__BREAK_FLUSH_FLAG_DIRECTION_2 = (1 << 1), + KBTS__BREAK_FLUSH_FLAG_DIRECTION_1 = (1 << 2), + KBTS__BREAK_FLUSH_FLAG_DIRECTION_PARAGRAPH = (1 << 3), +}; + +static void kbts__FlushDirection(kbts_break_state *State, kbts_direction *LastDirection, kbts_unicode_bidirectional_class BidirectionalClass, kbts_s16 PositionOffset) +{ + // @Incomplete: ET+ EN -> EN+ EN + kbts_break_flags BreakFlags = 0; + kbts_direction Direction = KBTS_DIRECTION_DONT_KNOW; + + switch(BidirectionalClass) + { + // @Incomplete: Surely, there are other edge cases we could handle here. + case KBTS_UNICODE_BIDIRECTIONAL_CLASS_L: + BreakFlags = KBTS_BREAK_FLAG_DIRECTION | KBTS_BREAK_FLAG_PARAGRAPH_DIRECTION; + Direction = KBTS_DIRECTION_LTR; + break; + + case KBTS_UNICODE_BIDIRECTIONAL_CLASS_R: + BreakFlags = KBTS_BREAK_FLAG_DIRECTION | KBTS_BREAK_FLAG_PARAGRAPH_DIRECTION; + Direction = KBTS_DIRECTION_RTL; + break; + + case KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN: + case KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN: + // Digits are weak LTR, i.e. they do not influence the paragraph direction. + BreakFlags = KBTS_BREAK_FLAG_DIRECTION; + Direction = KBTS_DIRECTION_LTR; + break; + + case KBTS_UNICODE_BIDIRECTIONAL_CLASS_NI: + // We've already checked the ParagraphDirection earlier, when coercing neutrals to L or R. + // If a neutral shows up here, it means that we did not find any way to resolve it to either direction. + // In this case, neutrals get the unresolved embedding direction. + BreakFlags = KBTS_BREAK_FLAG_DIRECTION; + break; + } + + if((BreakFlags & KBTS_BREAK_FLAG_DIRECTION) && + (Direction != *LastDirection)) + { + *LastDirection = Direction; + kbts__DoBreak(State, PositionOffset, KBTS_BREAK_FLAG_DIRECTION, Direction, 0, 0); + } + + if((BreakFlags & KBTS_BREAK_FLAG_PARAGRAPH_DIRECTION) && + !State->ParagraphDirection) + { + kbts_s32 StartOfParagraphOffset = (kbts_s16)(State->ParagraphStartPosition - State->CurrentPosition); + kbts__DoBreak(State, StartOfParagraphOffset, KBTS_BREAK_FLAG_PARAGRAPH_DIRECTION, 0, Direction, 0); + State->ParagraphDirection = (kbts_u8)Direction; + } +} + +static void kbts__BreakAddCodepoint(kbts_break_state *State, kbts_u32 Codepoint, kbts_u32 PositionIncrement, int MaybeEndOfText) { // In these macros, and in FlagState, and in the way we buffer our state in general, // index 0 means _after_ the codepoint currently being added, // index 1 means _before_ the codepoint currently being added. #define KBTS_BREAK(Flags, Position) do {FlagState |= ((Flags) << (8 * (Position)));} while(0) #define KBTS_BREAK2(Flags, Position0, Position1) do {FlagState |= ((Flags) << (8 * (Position0))) | ((Flags) << (8 * (Position1)));} while(0) - if(!kbts_BreakStateIsValid(State)) return; - kbts_u8 Script = kbts_GetUnicodeScript(Codepoint); - kbts_unicode_bidirectional_class BidirectionalClass = kbts_GetUnicodeBidirectionalClass(Codepoint); - kbts_u8 UnicodeFlags = kbts_GetUnicodeFlags(Codepoint); - kbts_u32 MatchingBracket = kbts_GetUnicodeMatchingBracket(Codepoint); - kbts_u8 GraphemeBreakClass = kbts_GetUnicodeGraphemeBreakClass(Codepoint); - kbts_u8 LineBreakClass = kbts_GetUnicodeLineBreakClass(Codepoint); - kbts_u8 WordBreakClass = kbts_GetUnicodeWordBreakClass(Codepoint); - kbts_u8 LastScript = State->LastScripts[0]; + kbts_unicode_bidirectional_class BidirectionalClass = kbts__GetUnicodeBidirectionalClass(Codepoint); + kbts_u8 UnicodeFlags = kbts__GetUnicodeFlags(Codepoint); + kbts_u32 MatchingBracket = kbts__GetUnicodeMirrorCodepoint(Codepoint); + kbts_u8 GraphemeBreakClass = kbts__GetUnicodeGraphemeBreakClass(Codepoint); + kbts_u8 LineBreakClass = kbts__GetUnicodeLineBreakClass(Codepoint); + kbts_u8 WordBreakClass = kbts__GetUnicodeWordBreakClass(Codepoint); + kbts_u16 CodepointScriptExtension = kbts__GetUnicodeScriptExtension(Codepoint); + kbts_u32 CodepointScriptCount = (kbts_u32)kbts__ScriptExtensionCount(CodepointScriptExtension); + kbts_u32 CodepointScriptOffset = (kbts_u32)kbts__ScriptExtensionOffset(CodepointScriptExtension); + kbts_u8 *CodepointScripts = &kbts__ScriptExtensions[CodepointScriptOffset]; kbts_u32 FlagState = State->FlagState << 8; kbts_u8 LastLineBreakClass = State->LastLineBreakClass; // Super secret cheat code for signaling end-of-text @@ -22987,6 +28193,16 @@ static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, kbts_s16 PositionOffset3 = State->PositionOffset3; kbts_u32 Flags = State->Flags; kbts_direction LastDirection = State->LastDirection; + kbts_u8 *ScriptSet = State->ScriptSet; + kbts_s16 ScriptPositionOffset = State->ScriptPositionOffset; + kbts_u32 ScriptCount = State->ScriptCount; + kbts_u32 ScriptCountAtBeginningOfUpdate = ScriptCount; + kbts_u8 BreakScript = ScriptSet[0]; + kbts__break_flush_flags FlushFlags = 0; + kbts_s16 Bidirectional1PositionOffset = State->Bidirectional1PositionOffset; + kbts_s16 Bidirectional2PositionOffset = State->Bidirectional2PositionOffset; + kbts_u8 Bidirectional2 = State->BidirectionalClass2; + kbts_u8 Bidirectional1 = State->BidirectionalClass1; if(StartOfText) { @@ -22994,28 +28210,31 @@ static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, WordBreakHistory = LastWordBreakClass = KBTS_WORD_BREAK_CLASS_SOT; } - - if((Script == KBTS_SCRIPT_DEFAULT) || (Script == KBTS_SCRIPT_DEFAULT2)) - { - Script = LastScript; - } - // Bracket pairing overrides default directions/scripts. - if(UnicodeFlags & KBTS_UNICODE_FLAG_OPEN_BRACKET) + if((UnicodeFlags & KBTS_UNICODE_FLAG_MIRRORED) == KBTS_UNICODE_FLAG_OPEN_BRACKET) { - if(State->BracketCount < KBTS_ARRAY_LENGTH(State->Brackets)) + if(State->BracketCount < KBTS__ARRAY_LENGTH(State->Brackets)) { kbts_bracket *Bracket = &State->Brackets[State->BracketCount++]; // @Incomplete: Canonicalize the bracket. Bracket->Codepoint = Codepoint; - Bracket->Direction = KBTS_DIRECTION_NONE; - Bracket->Script = Script; + Bracket->Position = State->CurrentPosition; + + // Unfortunately, because our script/direction breaks are arbitrary lookback now, + // we have to wait until DoBreak() to resolve these. + Bracket->Direction = KBTS_DIRECTION_DONT_KNOW; + Bracket->Script = KBTS_SCRIPT_DONT_KNOW; + + if(ScriptCount) + { + Bracket->Script = ScriptSet[0]; + } State->Flags |= KBTS_BREAK_STATE_FLAG_LAST_WAS_BRACKET; } } - else if(UnicodeFlags & KBTS_UNICODE_FLAG_CLOSE_BRACKET) + else if((UnicodeFlags & KBTS_UNICODE_FLAG_MIRRORED) == KBTS_UNICODE_FLAG_CLOSE_BRACKET) { if(State->BracketCount) { @@ -23023,7 +28242,7 @@ static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, kbts_bracket *FoundBracket = 0; // @Incomplete: Canonicalize the bracket. - KBTS_FOR(BracketIndex, 0, State->BracketCount) + KBTS__FOR(BracketIndex, 0, State->BracketCount) { kbts_bracket *Bracket = &State->Brackets[State->BracketCount - 1 - BracketIndex]; @@ -23038,18 +28257,129 @@ static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, if(FoundBracket) { + // In case the bracket hasn't been resolved yet, take the current values. + kbts_u8 BracketScript = FoundBracket->Script; + kbts_u8 BracketDirection = FoundBracket->Direction; + + if(!BracketScript && ScriptCount) + { + BracketScript = ScriptSet[0]; + } + + if(!BracketDirection) + { + BracketDirection = (kbts_u8)LastDirection; + } + + if(BracketDirection == KBTS_DIRECTION_LTR) + { + BidirectionalClass = KBTS_UNICODE_BIDIRECTIONAL_CLASS_L; + } + else if(BracketDirection == KBTS_DIRECTION_RTL) + { + BidirectionalClass = KBTS_UNICODE_BIDIRECTIONAL_CLASS_R; + } + BidirectionalClass = FoundBracket->Direction; - Script = FoundBracket->Script; + CodepointScriptCount = 1; + CodepointScriptOffset = BracketScript; State->BracketCount = (kbts_u32)FoundBracketIndex; } } } - { // Direction breaking. - kbts_u8 Bidirectional2 = State->BidirectionalClass2; - kbts_u8 Bidirectional1 = State->BidirectionalClass1; + // Script breaking. + if(EndOfText) + { + FlushFlags |= KBTS__BREAK_FLUSH_FLAG_SCRIPT; + } + if(CodepointScriptCount < 2) + { + // We special case this entire path because, supposedly, this is the common case. + kbts_u8 CodepointScript = (kbts_u8)CodepointScriptOffset; + + if((CodepointScript == KBTS_SCRIPT_DONT_KNOW) || + (CodepointScript == KBTS_SCRIPT_DEFAULT) || + (CodepointScript == KBTS_SCRIPT_DEFAULT2)) + { + // Nothing to do. + } + else + { + kbts_u32 ScriptSetMatch = 0; + KBTS__FOR(ScriptIndex, 0, ScriptCount) + { + ScriptSetMatch |= (ScriptSet[ScriptIndex] == CodepointScript); + } + + if(!ScriptSetMatch) + { + FlushFlags |= KBTS__BREAK_FLUSH_FLAG_SCRIPT; + } + + ScriptCount = 1; + ScriptSet[0] = CodepointScript; + } + } + else + { + // Refine the script set. + kbts_un NewScriptCount = 0; + + { + kbts_un CodepointScriptIndex = 0; + kbts_un ScriptIndex = 0; + + while((ScriptIndex < ScriptCount) && + (CodepointScriptIndex < CodepointScriptCount)) + { + kbts_u8 CodepointScript = CodepointScripts[CodepointScriptIndex]; + kbts_u8 Script = ScriptSet[ScriptIndex]; + + if(CodepointScript < Script) + { + CodepointScriptIndex += 1; + } + else if(Script < CodepointScript) + { + ScriptIndex += 1; + } + else + { + ScriptSet[NewScriptCount++] = Script; + + CodepointScriptIndex += 1; + ScriptIndex += 1; + } + } + } + + if(!NewScriptCount) + { + FlushFlags |= KBTS__BREAK_FLUSH_FLAG_SCRIPT; + + KBTS__FOR(CodepointScriptIndex, 0, CodepointScriptCount) + { + ScriptSet[CodepointScriptIndex] = CodepointScripts[CodepointScriptIndex]; + } + ScriptCount = (kbts_u32)CodepointScriptCount; + } + else + { + ScriptCount = (kbts_u32)NewScriptCount; + } + } + + // Direction breaking. + if(EndOfText) + { + BidirectionalClass = KBTS_UNICODE_BIDIRECTIONAL_CLASS_NI; + } + + if(BidirectionalClass != KBTS_UNICODE_BIDIRECTIONAL_CLASS_BN) // Formatting characters should be ignored. + { switch(BidirectionalClass) { case KBTS_UNICODE_BIDIRECTIONAL_CLASS_NSM: BidirectionalClass = Bidirectional1; break; @@ -23075,18 +28405,28 @@ static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, BidirectionalClass = KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN; goto CaseAn; } - if((Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN) && ((Bidirectional1 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_ES) || (Bidirectional1 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_CS))) + if((Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN) && + ((Bidirectional1 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_ES) || + (Bidirectional1 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_CS))) { Bidirectional1 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN; } - if(!(Flags & KBTS_BREAK_STATE_FLAG_SAW_R_AFTER_L)) + + // We test State->ParagraphDirection here because we do not want + // digits to coerce to L when the paragrpah direction is unknown. + // It might be cleaner to explicitly store the last strong direction seen, + // with DONT_KNOW as an option. + // @Cleanup + if(State->ParagraphDirection && + !(Flags & KBTS_BREAK_STATE_FLAG_SAW_R_AFTER_L)) { BidirectionalClass = KBTS_UNICODE_BIDIRECTIONAL_CLASS_L; } break; case KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN: CaseAn:; - if((Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN) && (Bidirectional1 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_CS)) + if((Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN) && + (Bidirectional1 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_CS)) { Bidirectional1 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN; } @@ -23099,57 +28439,77 @@ static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, break; } - if(KBTS_IN_SET(BidirectionalClass, KBTS_SET32((KBTS_UNICODE_BIDIRECTIONAL_CLASS_ET)(KBTS_UNICODE_BIDIRECTIONAL_CLASS_ES)(KBTS_UNICODE_BIDIRECTIONAL_CLASS_CS)))) + // This rule has a lower priority than AN CS AN -> AN AN AN, so we have to wait until slot 1 to apply it. + if(KBTS__IN_SET(Bidirectional1, KBTS__SET32((KBTS_UNICODE_BIDIRECTIONAL_CLASS_ET) + (KBTS_UNICODE_BIDIRECTIONAL_CLASS_ES) + (KBTS_UNICODE_BIDIRECTIONAL_CLASS_CS)))) { - BidirectionalClass = KBTS_UNICODE_BIDIRECTIONAL_CLASS_NI; + Bidirectional1 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_NI; } if(Bidirectional1 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_NI) { - if(KBTS_IN_SET(Bidirectional2, KBTS_SET32((KBTS_UNICODE_BIDIRECTIONAL_CLASS_R)(KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN)(KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN))) && - KBTS_IN_SET(BidirectionalClass, KBTS_SET32((KBTS_UNICODE_BIDIRECTIONAL_CLASS_R)(KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN)(KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN)))) + if(KBTS__IN_SET(BidirectionalClass, KBTS__SET32((KBTS_UNICODE_BIDIRECTIONAL_CLASS_NI) + (KBTS_UNICODE_BIDIRECTIONAL_CLASS_ET) + (KBTS_UNICODE_BIDIRECTIONAL_CLASS_ES) + (KBTS_UNICODE_BIDIRECTIONAL_CLASS_CS)))) { + // All of these input classes end up resolving to NI later on anyway if they are preceded by NI. + // We are in a situation where: + // - We have an NI in slot 1 + // - The direction in slot 0 will eventually resolve to NI due to the NI in slot 1 + // - Storing multiple NIs in our shift buffer is redundant, because no rule necessitates multiple NIs + // - NIs don't interact with anything, except that they resolve when surrounded by strong characters + // - NIs are resolved in groups. As per the Unicode specification: + // N1. A sequence of NIs takes the direction of the surrounding strong text if the text on both + // sides has the same direction. + // This means we can merge the current bidirectional class with the preceding NI, bump the offset, + // and it just works. + goto SkipDirectionBreak; + } + else if(((Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_R) || + (BidirectionalClass == KBTS_UNICODE_BIDIRECTIONAL_CLASS_R)) && + KBTS__IN_SET(Bidirectional2, KBTS__SET32((KBTS_UNICODE_BIDIRECTIONAL_CLASS_R) + (KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN) + (KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN))) && + KBTS__IN_SET(BidirectionalClass, KBTS__SET32((KBTS_UNICODE_BIDIRECTIONAL_CLASS_R) + (KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN) + (KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN)))) + { + // Note that the way we resolve digits is different from the way the Unicode standard specifies it. + // This is because the standard assumes the paragraph direction is always known, whereas in our case it isn't. + // We want neutral surrounded by uncoerced digits to resolve to the paragraph direction, which may be DONT_KNOW. Bidirectional1 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_R; } - else if((Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_L) && (BidirectionalClass == KBTS_UNICODE_BIDIRECTIONAL_CLASS_L)) + else if(((Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_L) || + (BidirectionalClass == KBTS_UNICODE_BIDIRECTIONAL_CLASS_L)) && + KBTS__IN_SET(Bidirectional2, KBTS__SET32((KBTS_UNICODE_BIDIRECTIONAL_CLASS_L) + (KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN) + (KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN))) && + KBTS__IN_SET(BidirectionalClass, KBTS__SET32((KBTS_UNICODE_BIDIRECTIONAL_CLASS_L) + (KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN) + (KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN)))) { Bidirectional1 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_L; } else { - if (State->MainDirection == KBTS_DIRECTION_LTR) Bidirectional1 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_L; - else if(State->MainDirection == KBTS_DIRECTION_RTL) Bidirectional1 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_R; + if (State->ParagraphDirection == KBTS_DIRECTION_LTR) Bidirectional1 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_L; + else if(State->ParagraphDirection == KBTS_DIRECTION_RTL) Bidirectional1 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_R; } } - // These rules happen at the very end, so we wait until the last slot to apply them. - if((Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN) || (Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN)) + FlushFlags |= KBTS__BREAK_FLUSH_FLAG_DIRECTION_2; + if(EndOfText) { - Bidirectional2 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_L; + FlushFlags |= KBTS__BREAK_FLUSH_FLAG_DIRECTION_1; } - - // @Incomplete: ET+ EN -> EN+ EN - kbts_direction Direction = KBTS_DIRECTION_NONE; - if(Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_L) Direction = KBTS_DIRECTION_LTR; - else if(Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_R) Direction = KBTS_DIRECTION_RTL; - if(Direction && (Direction != LastDirection)) - { - LastDirection = Direction; - KBTS_BREAK(KBTS_BREAK_FLAG_DIRECTION, 3); - - if(!State->MainDirection) - { - State->MainDirection = (kbts_u8)Direction; - } - } - - State->BidirectionalClass2 = Bidirectional1; - State->BidirectionalClass1 = BidirectionalClass; } - - if(Script != LastScript) + else { - KBTS_BREAK(KBTS_BREAK_FLAG_SCRIPT, 1); + SkipDirectionBreak:; + State->Bidirectional2PositionOffset -= (kbts_s16)PositionIncrement; + State->Bidirectional1PositionOffset -= (kbts_s16)PositionIncrement; } { // Grapheme breaking. @@ -23196,10 +28556,10 @@ static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, // Ignore [EX FO ZWJ] after ^[_sot_ CR LF NL]. // @Cleanup: This is the only time we explicitly use EX and FO. They can be merged. - if(KBTS_IN_SET(WordBreakClass, KBTS_SET32((KBTS_WORD_BREAK_CLASS_EX)(KBTS_WORD_BREAK_CLASS_FO)(KBTS_WORD_BREAK_CLASS_ZWJ))) && - !KBTS_IN_SET(LastWordBreakClass, KBTS_SET32((KBTS_WORD_BREAK_CLASS_SOT)(KBTS_WORD_BREAK_CLASS_CR)(KBTS_WORD_BREAK_CLASS_LF)(KBTS_WORD_BREAK_CLASS_NL)))) + if(KBTS__IN_SET(WordBreakClass, KBTS__SET32((KBTS_WORD_BREAK_CLASS_EX)(KBTS_WORD_BREAK_CLASS_FO)(KBTS_WORD_BREAK_CLASS_ZWJ))) && + !KBTS__IN_SET(LastWordBreakClass, KBTS__SET32((KBTS_WORD_BREAK_CLASS_SOT)(KBTS_WORD_BREAK_CLASS_CR)(KBTS_WORD_BREAK_CLASS_LF)(KBTS_WORD_BREAK_CLASS_NL)))) { - WordBreak2PositionOffset -= PositionIncrement; + WordBreak2PositionOffset -= (kbts_s16)PositionIncrement; State->WordBreak2PositionOffset = WordBreak2PositionOffset; } else @@ -23214,11 +28574,11 @@ static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, WordBreaks |= KBTS_WORD_BREAK_BITS(2, 1); } - if(KBTS_IN_SET(WordBreakClass, KBTS_SET32((KBTS_WORD_BREAK_CLASS_CR)(KBTS_WORD_BREAK_CLASS_LF)(KBTS_WORD_BREAK_CLASS_NL)))) + if(KBTS__IN_SET(WordBreakClass, KBTS__SET32((KBTS_WORD_BREAK_CLASS_CR)(KBTS_WORD_BREAK_CLASS_LF)(KBTS_WORD_BREAK_CLASS_NL)))) { WordBreaks |= KBTS_WORD_BREAK_BITS(1, 1) | KBTS_WORD_BREAK_BITS(1, 0); } - else if(KBTS_IN_SET(WordBreakClass, KBTS_SET32((KBTS_WORD_BREAK_CLASS_Oep)(KBTS_WORD_BREAK_CLASS_ALep)))) + else if(KBTS__IN_SET(WordBreakClass, KBTS__SET32((KBTS_WORD_BREAK_CLASS_Oep)(KBTS_WORD_BREAK_CLASS_ALep)))) { // ZWJ x {Extended_Pictographic} if(LastWordBreakClassIncludingIgnored == KBTS_WORD_BREAK_CLASS_ZWJ) @@ -23269,7 +28629,7 @@ static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, kbts_u32 EffectiveWordBreaks = WordBreaks & ~WordUnbreaks; if(EffectiveWordBreaks & KBTS_WORD_BREAK_BITS(2, 2)) { - kbts_DoBreak(State, PositionOffset2 + WordBreak2PositionOffset, KBTS_BREAK_FLAG_WORD, 0, 0); + kbts__DoBreak(State, PositionOffset2 + WordBreak2PositionOffset, KBTS_BREAK_FLAG_WORD, 0, 0, 0); } if(EndOfText) { @@ -23291,6 +28651,7 @@ static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, kbts_s16 LineBreak3PositionOffset = State->LineBreak3PositionOffset; kbts_s16 LineBreak2PositionOffset = State->LineBreak2PositionOffset; + int HardLineBreak = 0; { // Line breaking. kbts_u64 LineBreaks = State->LineBreaks << 16; kbts_u64 LineUnbreaks = State->LineUnbreaks << 16; @@ -23300,10 +28661,10 @@ static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, #define KBTS_C2(A, B) case (KBTS_LINE_BREAK_CLASS_##A << 8) | (KBTS_LINE_BREAK_CLASS_##B) #define KBTS_C3(A, B, C) case (KBTS_LINE_BREAK_CLASS_##A << 16) | (KBTS_LINE_BREAK_CLASS_##B << 8) | KBTS_LINE_BREAK_CLASS_##C #define KBTS_C4(A, B, C, D) case (KBTS_LINE_BREAK_CLASS_##A << 24) | (KBTS_LINE_BREAK_CLASS_##B << 16) | (KBTS_LINE_BREAK_CLASS_##C << 8) | KBTS_LINE_BREAK_CLASS_##D - #define KBTS_REQUIRED_LINE_BREAK(Priority, Position) do {LineBreaks |= (kbts_u64)KBTS_LINE_BREAK_REQUIRED##Priority << ((Position) * 16);} while(0) - #define KBTS_LINE_BREAK(Priority, Position) do {LineBreaks |= (kbts_u64)KBTS_LINE_BREAK_ALLOWED##Priority << ((Position) * 16);} while(0) - #define KBTS_LINE_UNBREAK(Priority, Position) do {LineUnbreaks |= (kbts_u64)KBTS_LINE_BREAK_REQUIRED##Priority << ((Position) * 16);} while(0) - #define KBTS_LINE_UNBREAK_ASYNC(Priority, Position) do {LineUnbreaksAsync |= (kbts_u64)KBTS_LINE_BREAK_REQUIRED##Priority << ((Position) * 16);} while(0) + #define KBTS_REQUIRED_LINE_BREAK(Priority, Position) do {LineBreaks |= (kbts_u64)KBTS__LINE_BREAK_REQUIRED##Priority << ((Position) * 16);} while(0) + #define KBTS_LINE_BREAK(Priority, Position) do {LineBreaks |= (kbts_u64)KBTS__LINE_BREAK_ALLOWED##Priority << ((Position) * 16);} while(0) + #define KBTS_LINE_UNBREAK(Priority, Position) do {LineUnbreaks |= (kbts_u64)KBTS__LINE_BREAK_REQUIRED##Priority << ((Position) * 16);} while(0) + #define KBTS_LINE_UNBREAK_ASYNC(Priority, Position) do {LineUnbreaksAsync |= (kbts_u64)KBTS__LINE_BREAK_REQUIRED##Priority << ((Position) * 16);} while(0) if(EndOfText) { @@ -23344,7 +28705,7 @@ static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, } else if(LineBreakClass == KBTS_LINE_BREAK_CLASS_CJ) { - LineBreakClass = State->JapaneseLineBreakStyle == KBTS_JAPANESE_LINE_BREAK_STYLE_STRICT ? KBTS_LINE_BREAK_CLASS_NSea : KBTS_LINE_BREAK_CLASS_IDea; + LineBreakClass = (kbts_u8)((State->JapaneseLineBreakStyle == KBTS_JAPANESE_LINE_BREAK_STYLE_STRICT) ? KBTS_LINE_BREAK_CLASS_NSea : KBTS_LINE_BREAK_CLASS_IDea); } } @@ -23359,7 +28720,7 @@ static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, LineBreakHistory = (LineBreakHistory << 8) | LineBreakClass; - if(EndOfText) + if(EndOfText && (State->ConfigFlags & KBTS_BREAK_CONFIG_FLAG_END_OF_TEXT_GENERATES_HARD_LINE_BREAK)) { // Always break at the end of text. KBTS_REQUIRED_LINE_BREAK(5, 1); @@ -23379,7 +28740,23 @@ static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, KBTS_C1(BK): KBTS_C1(CR): KBTS_C1(LF): - KBTS_C1(NL): KBTS_LINE_UNBREAK(4, 1); KBTS_REQUIRED_LINE_BREAK(5, 0); break; + KBTS_C1(NL): + { + KBTS_LINE_UNBREAK(4, 1); + + // This is the only place that's not the end of text where we generate hard line breaks. + // When we see a hard line break, we want to reset the direction/script state, so that + // we generate new direction/script breaks for the new paragraph. + FlushFlags |= (KBTS__BREAK_FLUSH_FLAG_SCRIPT | + KBTS__BREAK_FLUSH_FLAG_DIRECTION_2 | + KBTS__BREAK_FLUSH_FLAG_DIRECTION_1 | + KBTS__BREAK_FLUSH_FLAG_DIRECTION_PARAGRAPH); + ScriptCount = 0; + HardLineBreak = 1; + + KBTS_REQUIRED_LINE_BREAK(5, 0); + } break; + KBTS_C1(ZW): KBTS_LINE_BREAK(4, 0); KBTS_LINE_UNBREAK(4, 1); break; KBTS_C1(BB): KBTS_LINE_UNBREAK(0, 0); break; @@ -23782,16 +29159,17 @@ static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, { kbts_u64 EffectiveLineBreaks = LineBreaks & ~(LineUnbreaks | LineUnbreaksAsync); - kbts_DoLineBreak(State, PositionOffset3 + LineBreak3PositionOffset, EffectiveLineBreaks >> 48, 0, 0); + kbts__DoLineBreak(State, PositionOffset3 + LineBreak3PositionOffset, EffectiveLineBreaks >> 48); if(EndOfText) { - kbts_DoLineBreak(State, PositionOffset2 + LineBreak2PositionOffset, EffectiveLineBreaks >> 32, 0, 0); + kbts__DoLineBreak(State, PositionOffset2 + LineBreak2PositionOffset, EffectiveLineBreaks >> 32); { // @Cleanup: This is the same flag code as DoLineBreak, but we want to use FlagState buffering for this. // The only places where we want to manually call DoBreak is for asynchronous/buffered guys. - kbts_u8 FlushFlags = 0; - if((EffectiveLineBreaks >> 16) & KBTS_LINE_BREAK_ALLOWED_MASK) FlushFlags |= KBTS_BREAK_FLAG_LINE_SOFT; - if((EffectiveLineBreaks >> 16) & KBTS_LINE_BREAK_REQUIRED_MASK) FlushFlags |= KBTS_BREAK_FLAG_LINE_HARD; - KBTS_BREAK(FlushFlags, 1); + kbts_u8 FlushedLineFlags = 0; + if((EffectiveLineBreaks >> 16) & KBTS__LINE_BREAK_ALLOWED_MASK) FlushedLineFlags |= KBTS_BREAK_FLAG_LINE_SOFT; + if((EffectiveLineBreaks >> 16) & KBTS__LINE_BREAK_REQUIRED_MASK) FlushedLineFlags |= KBTS_BREAK_FLAG_LINE_HARD; + + KBTS_BREAK(FlushedLineFlags, 1); } // Lines are never broken after the end of text. } @@ -23803,91 +29181,380 @@ static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, State->LineBreak3PositionOffset = LineBreak2PositionOffset; State->LastLineBreakClass = LineBreakClass; State->LineBreakHistory = LineBreakHistory; - State->LastDirection = (kbts_u8)LastDirection; if(0) { LineBreakAbsorbCharacter:; - State->LineBreak2PositionOffset -= PositionIncrement; - State->LineBreak3PositionOffset -= PositionIncrement; + State->LineBreak2PositionOffset -= (kbts_s16)PositionIncrement; + State->LineBreak3PositionOffset -= (kbts_s16)PositionIncrement; } // This always gets updated. State->LineUnbreaksAsync = LineUnbreaksAsync; } + // We flush scripts late because hard line breaks also want to flush scripts. + // + // If we have no active script at all, then either we are at the very beginning of the text, + // or we have only seen common/inherited scripts so far. + // Either way, we want everything before us to coerce to our type, so don't actually break, + // and do not update the script break position. + if((FlushFlags & KBTS__BREAK_FLUSH_FLAG_SCRIPT) && + ScriptCountAtBeginningOfUpdate) + { + kbts__DoBreak(State, ScriptPositionOffset, KBTS_BREAK_FLAG_SCRIPT, 0, 0, BreakScript); + ScriptPositionOffset = 0; + + if(HardLineBreak) + { + // Put the next script break after the newline. + ScriptPositionOffset = (kbts_s16)PositionIncrement; + } + } + + if(FlushFlags & KBTS__BREAK_FLUSH_FLAG_DIRECTION_2) + { + kbts__FlushDirection(State, &LastDirection, Bidirectional2, Bidirectional2PositionOffset); + } + if(FlushFlags & KBTS__BREAK_FLUSH_FLAG_DIRECTION_1) + { + kbts__FlushDirection(State, &LastDirection, Bidirectional1, Bidirectional1PositionOffset); + } + + if(FlushFlags & KBTS__BREAK_FLUSH_FLAG_DIRECTION_PARAGRAPH) + { + // Reset direction state for the new paragraph. + Bidirectional1 = 0; + + // Clear direction history. + // This is necessary to uphold the invariant that the first direction break is always + // on the first character of a paragraph. + LastDirection = 0; + + // CAUTION: This needs to be updated _after_ calling kbts__FlushDirection! + // Alternatively, we could load ParagraphStartPosition into a variable at the start of this function. + State->ParagraphStartPosition = State->CurrentPosition + 1; + + kbts__BreakStateStartParagraph(State); + + if(State->UserParagraphDirection == KBTS_DIRECTION_DONT_KNOW) + { + kbts__DoBreak(State, 1, KBTS_BREAK_FLAG_PARAGRAPH_DIRECTION, 0, KBTS_DIRECTION_DONT_KNOW, 0); + } + } + + ScriptPositionOffset -= (kbts_s16)PositionIncrement; + // This is where we flush the normal breaks that don't need any special position adjustment. - kbts_DoBreak(State, PositionOffset3, (FlagState >> 24) & 0xFF, LastDirection, State->LastScripts[1]); + kbts__DoBreak(State, PositionOffset3, (FlagState >> 24) & 0xFF, 0, 0, 0); if(EndOfText) { - kbts_DoBreak(State, PositionOffset2, (FlagState >> 16) & 0xFF, 0, LastScript); - kbts_DoBreak(State, 0, (FlagState >> 8) & 0xFF, 0, Script); - kbts_DoBreak(State, PositionIncrement, FlagState & 0xFF, 0, Script); + kbts__DoBreak(State, PositionOffset2, (FlagState >> 16) & 0xFF, 0, 0, 0); + kbts__DoBreak(State, 0, (FlagState >> 8) & 0xFF, 0, 0, 0); + kbts__DoBreak(State, (int)PositionIncrement, FlagState & 0xFF, 0, 0, 0); } State->FlagState = FlagState; - State->Flags |= KBTS_BREAK_STATE_FLAG_STARTED; - if(EndOfText) State->Flags |= KBTS_BREAK_STATE_FLAG_END; + Flags |= KBTS_BREAK_STATE_FLAG_STARTED; + if(EndOfText) Flags |= KBTS_BREAK_STATE_FLAG_END; + State->Flags = Flags; State->PositionOffset2 = (kbts_s16)-(int)PositionIncrement; State->PositionOffset3 = (kbts_s16)(PositionOffset2 - (int)PositionIncrement); State->CurrentPosition += PositionIncrement; - State->LastScripts[1] = State->LastScripts[0]; - State->LastScripts[0] = Script; + if(FlushFlags & KBTS__BREAK_FLUSH_FLAG_DIRECTION_2) + { + // Only update the buffer if we've actually flushed something. + State->BidirectionalClass2 = Bidirectional1; + State->BidirectionalClass1 = BidirectionalClass; + State->Bidirectional2PositionOffset = State->Bidirectional1PositionOffset - (kbts_s16)PositionIncrement; + State->Bidirectional1PositionOffset = (kbts_s16)-(int)PositionIncrement; + } + State->LastDirection = (kbts_u8)LastDirection; + + State->ScriptPositionOffset = ScriptPositionOffset; + State->ScriptCount = ScriptCount; #undef KBTS_BREAK #undef KBTS_BREAK2 } -KBTS_EXPORT void kbts_BreakFlush(kbts_break_state *State) +KBTS_EXPORT void kbts_BreakEnd(kbts_break_state *State) { // We pass 3, aka. ASCII end-of-text, at the end of text. - kbts_BreakAddCodepoint_(State, 3, 0, 1); + kbts__BreakAddCodepoint(State, 3, 0, 1); } -KBTS_EXPORT void kbts_BreakAddCodepoint(kbts_break_state *State, kbts_u32 Codepoint, kbts_u32 PositionIncrement, int EndOfText) +KBTS_EXPORT void kbts_BreakAddCodepoint(kbts_break_state *State, int Codepoint, int PositionIncrement, int EndOfText) { - kbts_BreakAddCodepoint_(State, Codepoint, PositionIncrement, 0); - if(EndOfText) kbts_BreakFlush(State); + kbts__BreakAddCodepoint(State, Codepoint, (kbts_u32)PositionIncrement, 0); + + if(EndOfText) + { + kbts_BreakEnd(State); + } } KBTS_EXPORT int kbts_Break(kbts_break_state *State, kbts_break *Break) { int Result = 0; - kbts_un Threshold = State->Flags & KBTS_BREAK_STATE_FLAG_END ? 0 : KBTS_BREAK_REORDER_BUFFER_FLUSH_THRESHOLD; - if(kbts_BreakStateIsValid(State) && (State->BreakCount > Threshold)) + if(State->BreakCount) { - kbts_break *ToFlush = &State->Breaks[State->BreakCount - 1]; - // @Incomplete: Handle wrapping. - if(ToFlush->Position >= State->LastFlushedBreakPosition) - { - *Break = *ToFlush; - State->LastFlushedBreakPosition = ToFlush->Position; - State->BreakCount -= 1; - Result = 1; - } - else - { - State->Flags |= KBTS_BREAK_STATE_FLAG_RAN_OUT_OF_REORDER_BUFFER_SPACE; - } + kbts_break *ToFlush = &State->Breaks[--State->BreakCount]; + + *Break = *ToFlush; + Result = 1; } return Result; } -KBTS_EXPORT void kbts_BeginBreak(kbts_break_state *State, kbts_direction MainDirection, kbts_japanese_line_break_style JapaneseLineBreakStyle) +KBTS_EXPORT void kbts_GuessTextProperties(void *Text, int TextSizeInBytes, kbts_text_format Format, kbts_direction *Direction_, kbts_script *Script_) +{ + kbts_script Script = KBTS_SCRIPT_DONT_KNOW; + kbts_direction Direction = KBTS_DIRECTION_DONT_KNOW; + + if(Text && (TextSizeInBytes > 0) && Format) + { + const char *At = (const char *)Text; + const char *End = (const char *)Text + TextSizeInBytes; + + kbts_break_state BreakState; + kbts_BreakBegin(&BreakState, KBTS_DIRECTION_DONT_KNOW, KBTS_JAPANESE_LINE_BREAK_STYLE_NORMAL, 0); + + while(((Script == KBTS_SCRIPT_DONT_KNOW) || + (Direction == KBTS_DIRECTION_DONT_KNOW)) && + (At < End)) + { + kbts_u32 Codepoint = 0; + kbts_u32 PositionIncrement = 1; + + switch(Format) + { + case KBTS_TEXT_FORMAT_UTF32: + { + Codepoint = *(kbts_u32 *)At; + PositionIncrement = 4; + + } break; + + case KBTS_TEXT_FORMAT_UTF8: + { + kbts_decode Decode = kbts_DecodeUtf8(At, End - At); + + PositionIncrement = Decode.SourceCharactersConsumed; + + if(Decode.Valid) + { + Codepoint = Decode.Codepoint; + } + } break; + } + + kbts_BreakAddCodepoint(&BreakState, Codepoint, PositionIncrement, (At + PositionIncrement) == End); + kbts_break Break; + while(kbts_Break(&BreakState, &Break)) + { + if((Script == KBTS_SCRIPT_DONT_KNOW) && (Break.Flags & KBTS_BREAK_FLAG_SCRIPT)) + { + Script = Break.Script; + } + + if((Direction == KBTS_DIRECTION_DONT_KNOW) && (Break.Flags & KBTS_BREAK_FLAG_DIRECTION)) + { + Direction = Break.Direction; + } + } + + At += PositionIncrement; + } + } + + if(Script_) + { + *Script_ = Script; + } + + if(Direction_) + { + *Direction_ = Direction; + } +} + +KBTS_EXPORT void kbts_GuessTextPropertiesUtf32(const int *Utf32, int Utf32Count, kbts_direction *Direction, kbts_script *Script) +{ + kbts_GuessTextProperties((void *)Utf32, sizeof(int) * Utf32Count, KBTS_TEXT_FORMAT_UTF32, Direction, Script); +} + +KBTS_EXPORT void kbts_GuessTextPropertiesUtf8(const char *Utf8, int Utf8Length, kbts_direction *Direction, kbts_script *Script) +{ + kbts_GuessTextProperties((void *)Utf8, Utf8Length, KBTS_TEXT_FORMAT_UTF8, Direction, Script); +} + +KBTS_EXPORT void kbts_BreakBegin(kbts_break_state *State, kbts_direction ParagraphDirection, kbts_japanese_line_break_style JapaneseLineBreakStyle, kbts_break_config_flags ConfigFlags) { if(State) { + // @Speed: Clearing all the brackets isn't great. KBTS_MEMSET(State, 0, sizeof(*State)); - State->MainDirection = (kbts_u8)MainDirection; + State->UserParagraphDirection = (kbts_u8)ParagraphDirection; + State->ParagraphDirection = (kbts_u8)ParagraphDirection; State->JapaneseLineBreakStyle = JapaneseLineBreakStyle; + State->ConfigFlags = ConfigFlags; + + // Force a direction break at the start of the text. + State->LastDirection = KBTS_DIRECTION_COUNT; + + // These should be out-of-bounds while the buffers haven't filled up. + State->PositionOffset2 = -100; + State->PositionOffset3 = -100; + State->WordBreak2PositionOffset = -100; + State->LineBreak2PositionOffset = -100; + State->LineBreak3PositionOffset = -100; + State->Bidirectional1PositionOffset = -100; + State->Bidirectional2PositionOffset = -100; + + kbts__BreakStateStartParagraph(State); + + if(ParagraphDirection) + { + kbts__DoBreak(State, 0, KBTS_BREAK_FLAG_PARAGRAPH_DIRECTION, 0, ParagraphDirection, 0); + } } } +KBTS_EXPORT void kbts_BreakEntireString(kbts_direction Direction, kbts_japanese_line_break_style JapaneseLineBreakStyle, kbts_break_config_flags ConfigFlags, + const void *Input, int InputSizeInBytes, kbts_text_format InputFormat, + kbts_break *Breaks, int IBreakCapacity, int *BreakCount, + kbts_break_flags *BreakFlags, int IBreakFlagCapacity, int *BreakFlagCount) +{ + kbts_break_state BreakState = KBTS__ZERO; + kbts_BreakBegin(&BreakState, Direction, JapaneseLineBreakStyle, ConfigFlags); + + char *InputElement = (char *)Input; + char *End = (char *)Input + InputSizeInBytes; + kbts_un BreaksWritten = 0; + kbts_un MaxBreakPosition = 0; + kbts_un BreakCapacity = (kbts_un)IBreakCapacity; + kbts_un BreakFlagCapacity = (kbts_un)IBreakFlagCapacity; + + if(BreakFlags && BreakFlagCapacity) + { + KBTS_MEMSET(BreakFlags, 0, sizeof(kbts_break_flags) * BreakFlagCapacity); + } + + while(InputElement < End) + { + kbts_u32 Codepoint = 0; + kbts_un InputElementSize = 1; + kbts_un SourceCharacterCount = 1; + + switch(InputFormat) + { + case KBTS_TEXT_FORMAT_UTF32: + { + Codepoint = *(kbts_u32 *)InputElement; + + InputElementSize = sizeof(kbts_u32); + } break; + + case KBTS_TEXT_FORMAT_UTF8: + { + kbts_decode Decode = kbts_DecodeUtf8(InputElement, End - InputElement); + + if(Decode.Valid) + { + Codepoint = Decode.Codepoint; + + InputElementSize = Decode.SourceCharactersConsumed; + SourceCharacterCount = Decode.SourceCharactersConsumed; + } + } break; + } + + InputElement += InputElementSize; + + kbts_BreakAddCodepoint(&BreakState, Codepoint, (kbts_u32)SourceCharacterCount, InputElement >= End); + kbts_break Break; + while(kbts_Break(&BreakState, &Break)) + { + if(Breaks && (BreaksWritten < BreakCapacity)) + { + int Found = 0; + kbts_un ExistingBreakCount = KBTS__MIN(BreaksWritten, BreakCapacity); + + // @Speed: Binary search! + for(kbts_un ExistingBreakIndex = ExistingBreakCount; + ExistingBreakIndex; + --ExistingBreakIndex) + { + kbts_break *Existing = &Breaks[ExistingBreakIndex - 1]; + + if(Existing->Position == Break.Position) + { + Existing->Flags |= Break.Flags; + + if(Break.Flags & KBTS_BREAK_FLAG_SCRIPT) + { + Existing->Script = Break.Script; + } + + if(Break.Flags & KBTS_BREAK_FLAG_DIRECTION) + { + Existing->Direction = Break.Direction; + } + + Found = 1; + + break; + } + } + + if(!Found) + { + Breaks[BreaksWritten] = Break; + } + } + + if(BreakFlags && ((kbts_u32)Break.Position < BreakFlagCapacity)) + { + BreakFlags[Break.Position] |= Break.Flags; + } + + MaxBreakPosition = KBTS__MAX(MaxBreakPosition, (kbts_u32)Break.Position); + + BreaksWritten += 1; + } + } + + if(!Breaks && BreakCount) + { + *BreakCount = (int)BreaksWritten; + } + if(!BreakFlags && BreakFlagCount) + { + *BreakFlagCount = (int)(MaxBreakPosition + 1); + } +} + +KBTS_EXPORT void kbts_BreakEntireStringUtf32(kbts_direction Direction, kbts_japanese_line_break_style JapaneseLineBreakStyle, kbts_break_config_flags ConfigFlags, + const int *Utf32, int Utf32Count, + kbts_break *Breaks, int BreakCapacity, int *BreakCount, + kbts_break_flags *BreakFlags, int BreakFlagCapacity, int *BreakFlagCount) +{ + kbts_BreakEntireString(Direction, JapaneseLineBreakStyle, ConfigFlags, Utf32, sizeof(int) * Utf32Count, KBTS_TEXT_FORMAT_UTF32, Breaks, BreakCapacity, BreakCount, BreakFlags, BreakFlagCapacity, BreakFlagCount); +} +KBTS_EXPORT void kbts_BreakEntireStringUtf8(kbts_direction Direction, kbts_japanese_line_break_style JapaneseLineBreakStyle, kbts_break_config_flags ConfigFlags, + const char *Utf8, int Utf8Length, + kbts_break *Breaks, int BreakCapacity, int *BreakCount, + kbts_break_flags *BreakFlags, int BreakFlagCapacity, int *BreakFlagCount) +{ + kbts_BreakEntireString(Direction, JapaneseLineBreakStyle, ConfigFlags, Utf8, Utf8Length, KBTS_TEXT_FORMAT_UTF8, Breaks, BreakCapacity, BreakCount, BreakFlags, BreakFlagCapacity, BreakFlagCount); +} + KBTS_EXPORT kbts_decode kbts_DecodeUtf8(const char *Utf8, kbts_un Length) { - kbts_decode Result = KBTS_ZERO; + kbts_decode Result = KBTS__ZERO; const char *Utf8Start = Utf8; if(Length) @@ -23939,7 +29606,7 @@ KBTS_EXPORT kbts_decode kbts_DecodeUtf8(const char *Utf8, kbts_un Length) if(Length > FollowupCharacterCount) { - KBTS_FOR(FollowupCharacterIndex, 0, FollowupCharacterCount) + KBTS__FOR(FollowupCharacterIndex, 0, FollowupCharacterCount) { kbts_u8 C = (kbts_u8)*Utf8++; @@ -23966,7 +29633,42 @@ KBTS_EXPORT kbts_decode kbts_DecodeUtf8(const char *Utf8, kbts_un Length) return Result; } -KBTS_EXPORT int kbts_ShaperIsComplex(kbts_shaper Shaper) +KBTS_EXPORT kbts_encode_utf8 kbts_EncodeUtf8(int Codepoint) +{ + kbts_encode_utf8 Result = KBTS__ZERO; + + if(Codepoint <= 0x7F) + { + Result.Encoded[0] = (char)Codepoint; + Result.EncodedLength = 1; + } + else if(Codepoint <= 0x7FF) + { + Result.Encoded[1] = (Codepoint & 0x3F) | 0x80; + Result.Encoded[0] = ((Codepoint >> 6) & 0x1F) | 0xC0; + Result.EncodedLength = 2; + } + else if(Codepoint <= 0xFFFF) + { + Result.Encoded[2] = (Codepoint & 0x3F) | 0x80; + Result.Encoded[1] = ((Codepoint >> 6) & 0x3F) | 0x80; + Result.Encoded[0] = ((Codepoint >> 12) & 0xF) | 0xE0; + Result.EncodedLength = 3; + } + else if(Codepoint <= 0x10FFFF) + { + Result.Encoded[3] = (Codepoint & 0x3F) | 0x80; + Result.Encoded[2] = ((Codepoint >> 6) & 0x3F) | 0x80; + Result.Encoded[1] = ((Codepoint >> 12) & 0x3F) | 0x80; + Result.Encoded[0] = ((Codepoint >> 18) & 0x7) | 0xF0; + Result.EncodedLength = 4; + } + + Result.Valid = Result.EncodedLength > 0; + return Result; +} + +static int kbts__ShaperIsComplex(kbts_shaper Shaper) { int Result = Shaper != KBTS_SHAPER_DEFAULT; // @Incomplete? @@ -23975,8 +29677,13 @@ KBTS_EXPORT int kbts_ShaperIsComplex(kbts_shaper Shaper) KBTS_EXPORT int kbts_ScriptIsComplex(kbts_script Script) { - kbts_script_properties *Properties = &kbts_ScriptProperties[Script]; - int Result = kbts_ShaperIsComplex(Properties->Shaper); + if(Script >= KBTS_SCRIPT_COUNT) + { + Script = KBTS_SCRIPT_DONT_KNOW; + } + + kbts__script_properties *Properties = &kbts__ScriptProperties[Script]; + int Result = kbts__ShaperIsComplex(Properties->Shaper); return Result; } diff --git a/vendor/libc/README.md b/vendor/libc-shim/README.md similarity index 79% rename from vendor/libc/README.md rename to vendor/libc-shim/README.md index 1dd50c5a9..9b44984f6 100644 --- a/vendor/libc/README.md +++ b/vendor/libc-shim/README.md @@ -1,11 +1,11 @@ -# vendor:libc +# vendor:libc-shim A (very small) subset of a libc implementation over Odin libraries. This is mainly intended for use in Odin WASM builds to allow using libraries like box2d, cgltf etc. without emscripten hacks. -You can use this with clang by doing `clang -c --target=wasm32 --sysroot=$(odin root)/vendor/libc` (+ all other flags and inputs). +You can use this with clang by doing `clang -c --target=wasm32 --sysroot=$(odin root)/vendor/libc-shim` (+ all other flags and inputs). This will (if all the libc usage of the library is implemented) spit out a `.o` file you can use with the foreign import system. -If you then also make sure this package is included in the Odin side of the project (`@(require) import "vendor:libc"`) you will be able +If you then also make sure this package is included in the Odin side of the project (`@(require) import "vendor:libc-shim"`) you will be able compile to WASM like Odin expects. This is currently used by `vendor:box2d`, `vendor:stb/image`, `vendor:stb/truetype`, `vendor:stb/rect_pack`, and `vendor:cgltf`. diff --git a/vendor/libc/assert.odin b/vendor/libc-shim/assert.odin similarity index 100% rename from vendor/libc/assert.odin rename to vendor/libc-shim/assert.odin diff --git a/vendor/libc/ctype.odin b/vendor/libc-shim/ctype.odin similarity index 100% rename from vendor/libc/ctype.odin rename to vendor/libc-shim/ctype.odin diff --git a/vendor/libc/include/alloca.h b/vendor/libc-shim/include/alloca.h similarity index 100% rename from vendor/libc/include/alloca.h rename to vendor/libc-shim/include/alloca.h diff --git a/vendor/libc/include/assert.h b/vendor/libc-shim/include/assert.h similarity index 100% rename from vendor/libc/include/assert.h rename to vendor/libc-shim/include/assert.h diff --git a/vendor/libc/include/ctype.h b/vendor/libc-shim/include/ctype.h similarity index 100% rename from vendor/libc/include/ctype.h rename to vendor/libc-shim/include/ctype.h diff --git a/vendor/libc/include/inttypes.h b/vendor/libc-shim/include/inttypes.h similarity index 100% rename from vendor/libc/include/inttypes.h rename to vendor/libc-shim/include/inttypes.h diff --git a/vendor/libc/include/math.h b/vendor/libc-shim/include/math.h similarity index 97% rename from vendor/libc/include/math.h rename to vendor/libc-shim/include/math.h index fba520e4a..dd9e8e9ba 100644 --- a/vendor/libc/include/math.h +++ b/vendor/libc-shim/include/math.h @@ -43,6 +43,8 @@ double tan(double); double atan2(double, double); double modf(double, double*); +float remainderf(float x, float y); + bool __isnanf(float); bool __isnand(double); #define isnan(x) \ diff --git a/vendor/libc/include/sched.h b/vendor/libc-shim/include/sched.h similarity index 100% rename from vendor/libc/include/sched.h rename to vendor/libc-shim/include/sched.h diff --git a/vendor/libc/include/stdio.h b/vendor/libc-shim/include/stdio.h similarity index 100% rename from vendor/libc/include/stdio.h rename to vendor/libc-shim/include/stdio.h diff --git a/vendor/libc/include/stdlib.h b/vendor/libc-shim/include/stdlib.h similarity index 100% rename from vendor/libc/include/stdlib.h rename to vendor/libc-shim/include/stdlib.h diff --git a/vendor/libc/include/string.h b/vendor/libc-shim/include/string.h similarity index 93% rename from vendor/libc/include/string.h rename to vendor/libc-shim/include/string.h index 7e5e2b252..6d947858f 100644 --- a/vendor/libc/include/string.h +++ b/vendor/libc-shim/include/string.h @@ -8,7 +8,7 @@ extern "C" { void *memcpy(void *, const void *, size_t); void *memset(void *, int, size_t); -void *memmove(void *, void *, size_t); +void *memmove(void *, const void *, size_t); int memcmp(const void *, const void *, size_t); void *memchr(const void *, int, size_t); diff --git a/vendor/libc/include/time.h b/vendor/libc-shim/include/time.h similarity index 100% rename from vendor/libc/include/time.h rename to vendor/libc-shim/include/time.h diff --git a/vendor/libc-shim/libc.odin b/vendor/libc-shim/libc.odin new file mode 100644 index 000000000..a5508e14f --- /dev/null +++ b/vendor/libc-shim/libc.odin @@ -0,0 +1,26 @@ +package odin_libc + +import "base:runtime" + +import "core:mem" + +@(private) +g_ctx: runtime.Context +@(private) +g_allocator: mem.Compat_Allocator + +@(init) +init_context :: proc "contextless" () { + g_ctx = runtime.default_context() + context = g_ctx + + // Wrapping the allocator with the mem.Compat_Allocator so we can + // mimic the realloc semantics. + mem.compat_allocator_init(&g_allocator, g_ctx.allocator) + g_ctx.allocator = mem.compat_allocator(&g_allocator) +} + +// NOTE: the allocator must respect an `old_size` of `-1` on resizes! +set_context :: proc(ctx := context) { + g_ctx = ctx +} diff --git a/vendor/libc/math.odin b/vendor/libc-shim/math.odin similarity index 97% rename from vendor/libc/math.odin rename to vendor/libc-shim/math.odin index 93df1fea6..26d8a917a 100644 --- a/vendor/libc/math.odin +++ b/vendor/libc-shim/math.odin @@ -204,3 +204,8 @@ modf :: proc "c" (num: f64, iptr: ^f64) -> f64 { iptr^ = integral return fractional } + +@(require, linkage="strong", link_name="remainderf") +remainderf :: proc "c" (x, y: f32) -> f32 { + return math.remainder(x, y) +} diff --git a/vendor/libc/sched.odin b/vendor/libc-shim/sched.odin similarity index 100% rename from vendor/libc/sched.odin rename to vendor/libc-shim/sched.odin diff --git a/vendor/libc/stdio.odin b/vendor/libc-shim/stdio.odin similarity index 88% rename from vendor/libc/stdio.odin rename to vendor/libc-shim/stdio.odin index d41f790ee..b47b3f166 100644 --- a/vendor/libc/stdio.odin +++ b/vendor/libc-shim/stdio.odin @@ -4,93 +4,60 @@ package odin_libc import "base:runtime" import "core:c" -import "core:io" -import "core:os" import "core:strconv" import stb "vendor:stb/sprintf" -FILE :: uintptr +FILE :: rawptr EOF :: -1 @(require, linkage="strong", link_name="fopen") fopen :: proc "c" (path: cstring, mode: cstring) -> FILE { context = g_ctx - unimplemented("vendor/libc: fopen") + return _fopen(path, mode) } @(require, linkage="strong", link_name="fseek") fseek :: proc "c" (file: FILE, offset: c.long, whence: i32) -> i32 { context = g_ctx - handle := os.Handle(file-1) - _, err := os.seek(handle, i64(offset), int(whence)) - if err != nil { - return -1 - } - return 0 + return _fseek(file, offset, whence) } @(require, linkage="strong", link_name="ftell") ftell :: proc "c" (file: FILE) -> c.long { context = g_ctx - handle := os.Handle(file-1) - off, err := os.seek(handle, 0, os.SEEK_CUR) - if err != nil { - return -1 - } - return c.long(off) + return _ftell(file) } @(require, linkage="strong", link_name="fclose") fclose :: proc "c" (file: FILE) -> i32 { context = g_ctx - handle := os.Handle(file-1) - if os.close(handle) != nil { - return -1 - } - return 0 + return _fclose(file) } @(require, linkage="strong", link_name="fread") fread :: proc "c" (buffer: [^]byte, size: uint, count: uint, file: FILE) -> uint { context = g_ctx - handle := os.Handle(file-1) - n, _ := os.read(handle, buffer[:min(size, count)]) - return uint(max(0, n)) + return _fread(buffer, size, count, file) } @(require, linkage="strong", link_name="fwrite") fwrite :: proc "c" (buffer: [^]byte, size: uint, count: uint, file: FILE) -> uint { context = g_ctx - handle := os.Handle(file-1) - n, _ := os.write(handle, buffer[:min(size, count)]) - return uint(max(0, n)) + return _fwrite(buffer, size, count, file) } @(require, linkage="strong", link_name="putchar") putchar :: proc "c" (char: c.int) -> c.int { context = g_ctx - - n, err := os.write_byte(os.stdout, byte(char)) - if n == 0 || err != nil { - return EOF - } - return char + return _putchar(char) } @(require, linkage="strong", link_name="getchar") getchar :: proc "c" () -> c.int { - when #defined(os.stdin) { - ret: [1]byte - n, err := os.read(os.stdin, ret[:]) - if n == 0 || err != nil { - return EOF - } - return c.int(ret[0]) - } else { - return EOF - } + context = g_ctx + return _getchar() } @(require, linkage="strong", link_name="vsnprintf") @@ -109,8 +76,6 @@ vsprintf :: proc "c" (buf: [^]byte, fmt: cstring, args: ^c.va_list) -> i32 { vfprintf :: proc "c" (file: FILE, fmt: cstring, args: ^c.va_list) -> i32 { context = g_ctx - handle := os.Handle(file-1) - MAX_STACK :: 4096 buf: []byte @@ -133,12 +98,15 @@ vfprintf :: proc "c" (file: FILE, fmt: cstring, args: ^c.va_list) -> i32 { delete(buf) } - _, err := io.write_full(os.stream_from_handle(handle), buf) - if err != nil { - return -1 + written: i32 + for len(buf) > 0 { + n := _fwrite(raw_data(buf), size_of(byte), len(buf), file) + if n == 0 { break } + buf = buf[n:] + written += i32(n) } - return i32(len(buf)) + return written } /* @@ -366,7 +334,7 @@ _sscanf :: proc "c" (str, fmt: [^]byte, orig_ptrs: [^]rawptr) -> i32 { i = 0 k = t == 'c' ? width + 1 : 31 if size == .l { - unimplemented("vendor/libc: sscanf wide character support") + unimplemented("vendor/libc-shim: sscanf wide character support") } else if alloc { s = make([^]byte, k) if s == nil { diff --git a/vendor/libc-shim/stdio_js.odin b/vendor/libc-shim/stdio_js.odin new file mode 100644 index 000000000..2382ed449 --- /dev/null +++ b/vendor/libc-shim/stdio_js.odin @@ -0,0 +1,60 @@ +#+private +package odin_libc + +import "core:c" + +foreign import "odin_env" + +_fopen :: proc(path, mode: cstring) -> FILE { + unimplemented("vendor/libc: fopen in JS") +} + +_fseek :: proc(file: FILE, offset: c.long, whence: i32) -> i32 { + unimplemented("vendor/libc: fseek in JS") +} + +_ftell :: proc(file: FILE) -> c.long { + unimplemented("vendor/libc: ftell in JS") +} + +_fclose :: proc(file: FILE) -> i32 { + unimplemented("vendor/libc: fclose in JS") +} + +_fread :: proc(buffer: [^]byte, size: uint, count: uint, file: FILE) -> uint { + unimplemented("vendor/libc: fread in JS") +} + +_fwrite :: proc(buffer: [^]byte, size: uint, count: uint, file: FILE) -> uint { + fd, ok := __fd(file) + if !ok { + return 0 + } + + __write(fd, buffer[:size*count]) + return count +} + +_putchar :: proc(char: c.int) -> c.int { + __write(1, {byte(char)}) + return char +} + +_getchar :: proc() -> c.int { + return EOF +} + +@(private="file") +foreign odin_env { + @(link_name="write") + __write :: proc "contextless" (fd: u32, p: []byte) --- +} + +@(private="file") +__fd :: proc(file: FILE) -> (u32, bool) { + switch (uint(uintptr(file))) { + case 2: return 1, true // stdout + case 3: return 2, true // stderr + case: return 0, false + } +} diff --git a/vendor/libc-shim/stdio_os.odin b/vendor/libc-shim/stdio_os.odin new file mode 100644 index 000000000..f6d30a227 --- /dev/null +++ b/vendor/libc-shim/stdio_os.odin @@ -0,0 +1,104 @@ +#+build !freestanding +#+build !js +package odin_libc + +import "core:io" +import "core:c" +import "core:os" + +_fopen :: proc(path, _mode: cstring) -> FILE { + flags: os.File_Flags + + mode := string(_mode) + if len(mode) > 1 { + switch mode[0] { + case 'r': + flags += {.Read} + case 'w': + flags += {.Write, .Create, .Trunc} + case 'a': + flags += {.Write, .Create, .Append} + case: + return nil + } + + if len(mode) > 1 && mode[1] == '+' { + flags += {.Write, .Read} + } else if len(mode) > 2 && mode[1] == 'b' && mode[2] == '+' { + flags += {.Write, .Read} + } + } + + file, err := os.open(string(path), flags, os.Permissions_Read_Write_All) + if err != nil { + return nil + } + + return FILE(file) +} + +_fseek :: proc(_file: FILE, offset: c.long, whence: i32) -> i32 { + file := __file(_file) + if _, err := os.seek(file, i64(offset), io.Seek_From(whence)); err != nil { + return -1 + } + + return 0 +} + +_ftell :: proc(_file: FILE) -> c.long { + file := __file(_file) + pos, err := os.seek(file, 0, .Current) + if err != nil { + return -1 + } + + return c.long(pos) +} + +_fclose :: proc(_file: FILE) -> i32 { + file := __file(_file) + if err := os.close(file); err != nil { + return EOF + } + + return 0 +} + +_fread :: proc(buffer: [^]byte, size: uint, count: uint, _file: FILE) -> uint { + file := __file(_file) + n, _ := os.read(file, buffer[:size*count]) + return uint(max(0, n)) / size +} + +_fwrite :: proc(buffer: [^]byte, size: uint, count: uint, _file: FILE) -> uint { + file := __file(_file) + n, _ := os.write(file, buffer[:size*count]) + return uint(max(0, n)) / size +} + +_putchar :: proc(char: c.int) -> c.int { + n, err := os.write_byte(os.stdout, byte(char)) + if n == 0 || err != nil { + return EOF + } + return char +} + +_getchar :: proc() -> c.int { + ret: [1]byte + n, err := os.read(os.stdin, ret[:]) + if n == 0 || err != nil { + return EOF + } + return c.int(ret[0]) +} + +@(private="file") +__file :: proc(file: FILE) -> ^os.File { + switch (uint(uintptr(file))) { + case 2: return os.stdout + case 3: return os.stderr + case: return (^os.File)(file) + } +} diff --git a/vendor/libc/stdlib.odin b/vendor/libc-shim/stdlib.odin similarity index 99% rename from vendor/libc/stdlib.odin rename to vendor/libc-shim/stdlib.odin index cffc66ed2..5dd4c53c1 100644 --- a/vendor/libc/stdlib.odin +++ b/vendor/libc-shim/stdlib.odin @@ -5,7 +5,6 @@ import "base:intrinsics" import "base:runtime" import "core:c" -import "core:os" import "core:slice" import "core:sort" import "core:strconv" @@ -166,7 +165,7 @@ atexit :: proc "c" (function: proc "c" ()) -> i32 { @(require, linkage="strong", link_name="exit") exit :: proc "c" (exit_code: c.int) -> ! { finish_atexit() - os.exit(int(exit_code)) + runtime.exit(int(exit_code)) } @(private, fini) diff --git a/vendor/libc/string.odin b/vendor/libc-shim/string.odin similarity index 100% rename from vendor/libc/string.odin rename to vendor/libc-shim/string.odin diff --git a/vendor/libc/time.odin b/vendor/libc-shim/time.odin similarity index 100% rename from vendor/libc/time.odin rename to vendor/libc-shim/time.odin diff --git a/vendor/libc/libc.odin b/vendor/libc/libc.odin index a5508e14f..7af35b090 100644 --- a/vendor/libc/libc.odin +++ b/vendor/libc/libc.odin @@ -1,26 +1,3 @@ package odin_libc -import "base:runtime" - -import "core:mem" - -@(private) -g_ctx: runtime.Context -@(private) -g_allocator: mem.Compat_Allocator - -@(init) -init_context :: proc "contextless" () { - g_ctx = runtime.default_context() - context = g_ctx - - // Wrapping the allocator with the mem.Compat_Allocator so we can - // mimic the realloc semantics. - mem.compat_allocator_init(&g_allocator, g_ctx.allocator) - g_ctx.allocator = mem.compat_allocator(&g_allocator) -} - -// NOTE: the allocator must respect an `old_size` of `-1` on resizes! -set_context :: proc(ctx := context) { - g_ctx = ctx -} +#panic("`vendor:libc` has been moved, use `vendor:libc-shim` instead.") diff --git a/vendor/lua/5.4/include/luaconf.h b/vendor/lua/5.4/include/luaconf.h index 3ad294e4f..fbfa5781b 100644 --- a/vendor/lua/5.4/include/luaconf.h +++ b/vendor/lua/5.4/include/luaconf.h @@ -71,7 +71,7 @@ /* -@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits. +@@ LUAI_IS32INT is true if and only if (⟺) 'int' has (at least) 32 bits. */ #define LUAI_IS32INT ((UINT_MAX >> 30) >= 3) diff --git a/vendor/miniaudio/common.odin b/vendor/miniaudio/common.odin index e675cb7f6..1a3806734 100644 --- a/vendor/miniaudio/common.odin +++ b/vendor/miniaudio/common.odin @@ -20,9 +20,9 @@ foreign import lib { LIB } BINDINGS_VERSION_MAJOR :: 0 BINDINGS_VERSION_MINOR :: 11 -BINDINGS_VERSION_REVISION :: 22 +BINDINGS_VERSION_REVISION :: 24 BINDINGS_VERSION :: [3]u32{BINDINGS_VERSION_MAJOR, BINDINGS_VERSION_MINOR, BINDINGS_VERSION_REVISION} -BINDINGS_VERSION_STRING :: "0.11.22" +BINDINGS_VERSION_STRING :: "0.11.24" @(init) version_check :: proc "contextless" () { @@ -114,9 +114,9 @@ channel :: enum u8 { AUX_29 = 49, AUX_30 = 50, AUX_31 = 51, + POSITION_COUNT, LEFT = FRONT_LEFT, RIGHT = FRONT_RIGHT, - POSITION_COUNT = AUX_31 + 1, } result :: enum c.int { @@ -296,7 +296,7 @@ allocation_callbacks :: struct { } lcg :: struct { - state: i32, + state: u32, } diff --git a/vendor/miniaudio/device_io_procs.odin b/vendor/miniaudio/device_io_procs.odin index a14de807c..ced6e7403 100644 --- a/vendor/miniaudio/device_io_procs.odin +++ b/vendor/miniaudio/device_io_procs.odin @@ -1606,7 +1606,7 @@ foreign lib { ---------- pBackends (out, optional) A pointer to the buffer that will receive the enabled backends. Set to NULL to retrieve the backend count. Setting - the capacity of the buffer to `MA_BUFFER_COUNT` will guarantee it's large enough for all backends. + the capacity of the buffer to `MA_BACKEND_COUNT` will guarantee it's large enough for all backends. backendCap (in) The capacity of the `pBackends` buffer. diff --git a/vendor/miniaudio/device_io_types.odin b/vendor/miniaudio/device_io_types.odin index 9d64602f8..924bcda59 100644 --- a/vendor/miniaudio/device_io_types.odin +++ b/vendor/miniaudio/device_io_types.odin @@ -93,16 +93,16 @@ device_notification :: struct { data: struct #raw_union { started: struct { _unused: c.int, - }, + } `raw_union_tag:"type=.started"`, stopped: struct { _unused: c.int, - }, + } `raw_union_tag:"type=.stopped"`, rerouted: struct { _unused: c.int, - }, + } `raw_union_tag:"type=.rerouted"`, interruption: struct { _unused: c.int, - }, + } `raw_union_tag:"type=.interruption_began,.interruption_ended,"`, }, } @@ -698,6 +698,7 @@ context_type :: struct { snd_pcm_hw_params_set_rate_resample: proc "system" (), snd_pcm_hw_params_set_rate: proc "system" (), snd_pcm_hw_params_set_rate_near: proc "system" (), + snd_pcm_hw_params_set_rate_minmax: proc "system" (), snd_pcm_hw_params_set_buffer_size_near: proc "system" (), snd_pcm_hw_params_set_periods_near: proc "system" (), snd_pcm_hw_params_set_access: proc "system" (), @@ -1202,6 +1203,7 @@ device :: struct { /*AAudioStream**/ pStreamPlayback: rawptr, /*AAudioStream**/ pStreamCapture: rawptr, rerouteLock: mutex, + isTearingDown: b32, usage: aaudio_usage, contentType: aaudio_content_type, inputPreset: aaudio_input_preset, diff --git a/vendor/miniaudio/doc.odin b/vendor/miniaudio/doc.odin index 58b13b845..32c83cb46 100644 --- a/vendor/miniaudio/doc.odin +++ b/vendor/miniaudio/doc.odin @@ -2,7 +2,7 @@ Bindings for [[ miniaudio ; https://miniaud.io/docs ]] audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. -miniaudio - v0.11.21 - 2023-11-15 +miniaudio - v0.11.24 - 2025-09-11 David Reid - mackron@gmail.com @@ -300,7 +300,7 @@ The engine encapsulates both the resource manager and the node graph to create a use high level API. The resource manager and node graph APIs are covered in more later sections of this manual. -The code below shows how you can initialize an engine using it's default configuration. +The code below shows how you can initialize an engine using its default configuration. ```c ma_result result; @@ -388,7 +388,7 @@ Sounds are not started by default. Start a sound with `ma_sound_start()` and sto `ma_sound_stop()`. When a sound is stopped, it is not rewound to the start. Use `ma_sound_seek_to_pcm_frame(&sound, 0)` to seek back to the start of a sound. By default, starting and stopping sounds happens immediately, but sometimes it might be convenient to schedule the sound -the be started and/or stopped at a specific time. This can be done with the following functions: +to be started and/or stopped at a specific time. This can be done with the following functions: ```c ma_sound_set_start_time_in_pcm_frames() @@ -460,6 +460,11 @@ is at the end, use `ma_sound_at_end()`. Looping of a sound can be controlled wit miniaudio should work cleanly out of the box without the need to download or install any dependencies. See below for platform-specific details. +This library has been designed to be added directly to your source tree which is the preferred way +of using it, but you can compile it as a normal library if that's your preference. Be careful if +compiling as a shared object because miniaudio is not ABI compatible between any release, including +bug fix releases. It's recommended you link statically + Note that GCC and Clang require `-msse2`, `-mavx2`, etc. for SIMD optimizations. If you get errors about undefined references to `__sync_val_compare_and_swap_8`, `__atomic_load_8`, @@ -529,7 +534,7 @@ you'll need to disable run-time linking with `MA_NO_RUNTIME_LINKING` and link wi The Emscripten build emits Web Audio JavaScript directly and should compile cleanly out of the box. You cannot use `-std=c*` compiler flags, nor `-ansi`. -You can enable the use of AudioWorkets by defining `MA_ENABLE_AUDIO_WORKLETS` and then compiling +You can enable the use of AudioWorklets by defining `MA_ENABLE_AUDIO_WORKLETS` and then compiling with the following options: -sAUDIO_WORKLET=1 -sWASM_WORKERS=1 -sASYNCIFY @@ -878,7 +883,7 @@ read data within a certain range of the underlying data. To do this you can use This is useful if you have a sound bank where many sounds are stored in the same file and you want the data source to only play one of those sub-sounds. Note that once the range is set, everything -that takes a position, such as cursors and loop points, should always be relatvie to the start of +that takes a position, such as cursors and loop points, should always be relative to the start of the range. When the range is set, any previously defined loop point will be reset. Custom loop points can also be used with data sources. By default, data sources will loop after @@ -886,7 +891,7 @@ they reach the end of the data source, but if you need to loop at a specific loc the following: ```c - result = ma_data_set_loop_point_in_pcm_frames(pDataSource, loopBegInFrames, loopEndInFrames); + result = ma_data_source_set_loop_point_in_pcm_frames(pDataSource, loopBegInFrames, loopEndInFrames); if (result != MA_SUCCESS) { return result; // Failed to set the loop point. } @@ -3734,4 +3739,4 @@ See below for some tips on improving performance. - When compiling with VC6 and earlier, decoding is restricted to files less than 2GB in size. This is due to 64-bit file APIs not being available. */ -package miniaudio \ No newline at end of file +package miniaudio diff --git a/vendor/miniaudio/engine.odin b/vendor/miniaudio/engine.odin index e5364d782..0a3887d4b 100644 --- a/vendor/miniaudio/engine.odin +++ b/vendor/miniaudio/engine.odin @@ -48,6 +48,7 @@ engine_node_config :: struct { isPitchDisabled: b8, /* Pitching can be explicitly disable with MA_SOUND_FLAG_NO_PITCH to optimize processing. */ isSpatializationDisabled: b8, /* Spatialization can be explicitly disabled with MA_SOUND_FLAG_NO_SPATIALIZATION. */ pinnedListenerIndex: u8, /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */ + resampling: resampler_config, } /* Base node object for both ma_sound and ma_sound_group. */ @@ -58,7 +59,7 @@ engine_node :: struct { volumeSmoothTimeInPCMFrames: u32, monoExpansionMode: mono_expansion_mode, fader: fader, - resampler: linear_resampler, /* For pitch shift. */ + resampler: resampler, /* For pitch shift. */ spatializer: spatializer, panner: panner, volumeGainer: gainer, /* This will only be used if volumeSmoothTimeInPCMFrames is > 0. */ @@ -117,6 +118,7 @@ sound_config :: struct { endCallback: sound_end_proc, /* Fired when the sound reaches the end. Will be fired from the audio thread. Do not restart, uninitialize or otherwise change the state of the sound from here. Instead fire an event or set a variable to indicate to a different thread to change the start of the sound. Will not be fired in response to a scheduled stop with ma_sound_set_stop_time_*(). */ pEndCallbackUserData: rawptr, + pitchResampling: resampler_config, initNotifications: resource_manager_pipeline_notifications, @@ -134,6 +136,10 @@ sound :: struct { endCallback: sound_end_proc, pEndCallbackUserData: rawptr, + pProcessingCache: ^f32, + processingCacheFramesRemaining: u32, + processingCacheMap: u32, + ownsDataSource: b8, /* @@ -166,8 +172,12 @@ foreign lib { sound_get_data_source :: proc(pSound: ^sound) -> ^data_source --- sound_start :: proc(pSound: ^sound) -> result --- sound_stop :: proc(pSound: ^sound) -> result --- - sound_stop_with_fade_in_pcm_frames :: proc(pSound: ^sound, fadeLengthInFrames: u64) --- /* Will overwrite any scheduled stop and fade. */ - sound_stop_with_fade_in_milliseconds :: proc(pSound: ^sound, fadeLengthInFrames: u64) --- /* Will overwrite any scheduled stop and fade. */ + sound_stop_with_fade_in_pcm_frames :: proc(pSound: ^sound, fadeLengthInFrames: u64) --- /* Will overwrite any scheduled stop and fade. If you want to restart the sound, first reset it with `ma_sound_reset_stop_time_and_fade()`. There are plans to make this less awkward in the future. */ + sound_stop_with_fade_in_milliseconds :: proc(pSound: ^sound, fadeLengthInFrames: u64) --- /* Will overwrite any scheduled stop and fade. If you want to restart the sound, first reset it with `ma_sound_reset_stop_time_and_fade()`. There are plans to make this less awkward in the future. */ + sound_reset_start_time :: proc(pSound: ^sound) --- + sound_reset_stop_time :: proc(pSound: ^sound) --- + sound_reset_fade :: proc(pSound: ^sound) --- + sound_reset_stop_time_and_fade :: proc(pSound: ^sound) --- /* Resets fades and scheduled stop time. Does not seek back to the start. */ sound_set_volume :: proc(pSound: ^sound, volume: f32) --- sound_get_volume :: proc(pSound: ^sound) -> f32 --- sound_set_pan :: proc(pSound: ^sound, pan: f32) --- @@ -319,7 +329,7 @@ engine_config :: struct { pLog: ^log, /* When set to NULL, will use the context's log. */ listenerCount: u32, /* Must be between 1 and MA_ENGINE_MAX_LISTENERS. */ channels: u32, /* The number of channels to use when mixing and spatializing. When set to 0, will use the native channel count of the device. */ - sampleRate: u32, /* The sample rate. When set to 0 will use the native channel count of the device. */ + sampleRate: u32, /* The sample rate. When set to 0 will use the native sample rate of the device. */ periodSizeInFrames: u32, /* If set to something other than 0, updates will always be exactly this size. The underlying device may be a different size, but from the perspective of the mixer that won't matter.*/ periodSizeInMilliseconds: u32, /* Used if periodSizeInFrames is unset. */ gainSmoothTimeInFrames: u32, /* The number of frames to interpolate the gain of spatialized sounds across. If set to 0, will use gainSmoothTimeInMilliseconds. */ @@ -335,6 +345,8 @@ engine_config :: struct { pResourceManagerVFS: ^vfs, /* A pointer to a pre-allocated VFS object to use with the resource manager. This is ignored if pResourceManager is not NULL. */ onProcess: engine_process_proc, /* Fired at the end of each call to ma_engine_read_pcm_frames(). For engine's that manage their own internal device (the default configuration), this will be fired from the audio thread, and you do not need to call ma_engine_read_pcm_frames() manually in order to trigger this. */ pProcessUserData: rawptr, /* User data that's passed into onProcess. */ + resourceManagerResampling: resampler_config, /* The resampling config to use with the resource manager. */ + pitchResampling: resampler_config, /* The resampling config for the pitch and Doppler effects. You will typically want this to be a fast resampler. For high quality stuff, it's recommended that you pre-sample. */ } engine :: struct { @@ -358,6 +370,8 @@ engine :: struct { monoExpansionMode: mono_expansion_mode, onProcess: engine_process_proc, pProcessUserData: rawptr, + + pitchResamplingConfig: resampler_config, } @(default_calling_convention="c", link_prefix="ma_") diff --git a/vendor/miniaudio/lib/miniaudio.lib b/vendor/miniaudio/lib/miniaudio.lib index c9ee60979..f63ddf09d 100644 Binary files a/vendor/miniaudio/lib/miniaudio.lib and b/vendor/miniaudio/lib/miniaudio.lib differ diff --git a/vendor/miniaudio/logging.odin b/vendor/miniaudio/logging.odin index afddf8e68..135c6a9b1 100644 --- a/vendor/miniaudio/logging.odin +++ b/vendor/miniaudio/logging.odin @@ -1,6 +1,6 @@ package miniaudio -import "core:c/libc" +import "core:c" foreign import lib { LIB } @@ -48,12 +48,12 @@ log :: struct { @(default_calling_convention="c", link_prefix="ma_") foreign lib { log_callback_init :: proc(onLog: log_callback_proc, pUserData: rawptr) -> log_callback --- - + log_init :: proc(pAllocationCallbacks: ^allocation_callbacks, pLog: ^log) -> result --- log_uninit :: proc(pLog: ^log) --- log_register_callback :: proc(pLog: ^log, callback: log_callback) -> result --- log_unregister_callback :: proc(pLog: ^log, callback: log_callback) -> result --- log_post :: proc(pLog: ^log, level: u32, pMessage: cstring) -> result --- - log_postv :: proc(pLog: ^log, level: u32, pFormat: cstring, args: libc.va_list) -> result --- + log_postv :: proc(pLog: ^log, level: u32, pFormat: cstring, args: c.va_list) -> result --- log_postf :: proc(pLog: ^log, level: u32, pFormat: cstring, #c_vararg args: ..any) -> result --- } diff --git a/vendor/miniaudio/node_graph.odin b/vendor/miniaudio/node_graph.odin index 496d566f4..96138eeed 100644 --- a/vendor/miniaudio/node_graph.odin +++ b/vendor/miniaudio/node_graph.odin @@ -221,13 +221,14 @@ node_graph :: struct { foreign lib { node_graph_config_init :: proc(channels: u32) -> node_graph_config --- - node_graph_init :: proc(pConfig: ^node_graph_config, pAllocationCallbacks: ^allocation_callbacks, pNodeGraph: ^node_graph) -> result --- - node_graph_uninit :: proc(pNodeGraph: ^node_graph, pAllocationCallbacks: ^allocation_callbacks) --- - node_graph_get_endpoint :: proc(pNodeGraph: ^node_graph) -> ^node --- - node_graph_read_pcm_frames :: proc(pNodeGraph: ^node_graph, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result --- - node_graph_get_channels :: proc(pNodeGraph: ^node_graph) -> u32 --- - node_graph_get_time :: proc(pNodeGraph: ^node_graph) -> u64 --- - node_graph_set_time :: proc(pNodeGraph: ^node_graph, globalTime: u64) -> result --- + node_graph_init :: proc(pConfig: ^node_graph_config, pAllocationCallbacks: ^allocation_callbacks, pNodeGraph: ^node_graph) -> result --- + node_graph_uninit :: proc(pNodeGraph: ^node_graph, pAllocationCallbacks: ^allocation_callbacks) --- + node_graph_get_endpoint :: proc(pNodeGraph: ^node_graph) -> ^node --- + node_graph_read_pcm_frames :: proc(pNodeGraph: ^node_graph, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result --- + node_graph_get_channels :: proc(pNodeGraph: ^node_graph) -> u32 --- + node_graph_get_time :: proc(pNodeGraph: ^node_graph) -> u64 --- + node_graph_set_time :: proc(pNodeGraph: ^node_graph, globalTime: u64) -> result --- + node_graph_get_processing_size_in_frames :: proc(pNodeGraph: ^node_graph) -> u32 --- } diff --git a/vendor/miniaudio/resource_manager.odin b/vendor/miniaudio/resource_manager.odin index 4ef5778a9..1bc65227b 100644 --- a/vendor/miniaudio/resource_manager.odin +++ b/vendor/miniaudio/resource_manager.odin @@ -198,6 +198,7 @@ resource_manager_config :: struct { ppCustomDecodingBackendVTables: ^[^]decoding_backend_vtable, customDecodingBackendCount: u32, pCustomDecodingBackendUserData: rawptr, + resampling: resampler_config, } resource_manager :: struct { diff --git a/vendor/miniaudio/src/miniaudio.h b/vendor/miniaudio/src/miniaudio.h index c74bebeb3..24e676bb2 100644 --- a/vendor/miniaudio/src/miniaudio.h +++ b/vendor/miniaudio/src/miniaudio.h @@ -1,6 +1,6 @@ /* Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. -miniaudio - v0.11.22 - 2025-02-24 +miniaudio - v0.11.24 - 2026-01-17 David Reid - mackron@gmail.com @@ -12,18 +12,10 @@ GitHub: https://github.com/mackron/miniaudio /* 1. Introduction =============== -To use miniaudio, include "miniaudio.h": - - ```c - #include "miniaudio.h" - ``` - -The implementation is contained in "miniaudio.c". Just compile this like any other source file. You -can include miniaudio.c if you want to compile your project as a single translation unit: - - ```c - #include "miniaudio.c" - ``` +To use miniaudio, just include "miniaudio.h" like any other header and add "miniaudio.c" to your +source tree. If you don't want to add it to your source tree you can compile and link to it like +any other library. Note that ABI compatibility is not guaranteed between versions, even with bug +fix releases, so take care if compiling as a shared object. miniaudio includes both low level and high level APIs. The low level API is good for those who want to do all of their mixing themselves and only require a light weight interface to the underlying @@ -303,7 +295,7 @@ The engine encapsulates both the resource manager and the node graph to create a use high level API. The resource manager and node graph APIs are covered in more later sections of this manual. -The code below shows how you can initialize an engine using it's default configuration. +The code below shows how you can initialize an engine using its default configuration. ```c ma_result result; @@ -391,7 +383,7 @@ Sounds are not started by default. Start a sound with `ma_sound_start()` and sto `ma_sound_stop()`. When a sound is stopped, it is not rewound to the start. Use `ma_sound_seek_to_pcm_frame(&sound, 0)` to seek back to the start of a sound. By default, starting and stopping sounds happens immediately, but sometimes it might be convenient to schedule the sound -the be started and/or stopped at a specific time. This can be done with the following functions: +to be started and/or stopped at a specific time. This can be done with the following functions: ```c ma_sound_set_start_time_in_pcm_frames() @@ -463,6 +455,11 @@ is at the end, use `ma_sound_at_end()`. Looping of a sound can be controlled wit miniaudio should work cleanly out of the box without the need to download or install any dependencies. See below for platform-specific details. +This library has been designed to be added directly to your source tree which is the preferred way +of using it, but you can compile it as a normal library if that's your preference. Be careful if +compiling as a shared object because miniaudio is not ABI compatible between any release, including +bug fix releases. It's recommended you link statically. + Note that GCC and Clang require `-msse2`, `-mavx2`, etc. for SIMD optimizations. If you get errors about undefined references to `__sync_val_compare_and_swap_8`, `__atomic_load_8`, @@ -532,7 +529,7 @@ you'll need to disable run-time linking with `MA_NO_RUNTIME_LINKING` and link wi The Emscripten build emits Web Audio JavaScript directly and should compile cleanly out of the box. You cannot use `-std=c*` compiler flags, nor `-ansi`. -You can enable the use of AudioWorkets by defining `MA_ENABLE_AUDIO_WORKLETS` and then compiling +You can enable the use of AudioWorklets by defining `MA_ENABLE_AUDIO_WORKLETS` and then compiling with the following options: -sAUDIO_WORKLET=1 -sWASM_WORKERS=1 -sASYNCIFY @@ -881,7 +878,7 @@ read data within a certain range of the underlying data. To do this you can use This is useful if you have a sound bank where many sounds are stored in the same file and you want the data source to only play one of those sub-sounds. Note that once the range is set, everything -that takes a position, such as cursors and loop points, should always be relatvie to the start of +that takes a position, such as cursors and loop points, should always be relative to the start of the range. When the range is set, any previously defined loop point will be reset. Custom loop points can also be used with data sources. By default, data sources will loop after @@ -889,7 +886,7 @@ they reach the end of the data source, but if you need to loop at a specific loc the following: ```c - result = ma_data_set_loop_point_in_pcm_frames(pDataSource, loopBegInFrames, loopEndInFrames); + result = ma_data_source_set_loop_point_in_pcm_frames(pDataSource, loopBegInFrames, loopEndInFrames); if (result != MA_SUCCESS) { return result; // Failed to set the loop point. } @@ -3750,7 +3747,7 @@ extern "C" { #define MA_VERSION_MAJOR 0 #define MA_VERSION_MINOR 11 -#define MA_VERSION_REVISION 22 +#define MA_VERSION_REVISION 24 #define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION) #if defined(_MSC_VER) && !defined(__clang__) @@ -3857,37 +3854,65 @@ typedef ma_uint16 wchar_t; #define MA_SIZE_MAX 0xFFFFFFFF /* When SIZE_MAX is not defined by the standard library just default to the maximum 32-bit unsigned integer. */ #endif +#define MA_UINT64_MAX (((ma_uint64)0xFFFFFFFF << 32) | (ma_uint64)0xFFFFFFFF) /* Weird shifting syntax is for VC6 compatibility. */ + /* Platform/backend detection. */ -#if defined(_WIN32) || defined(__COSMOPOLITAN__) +#if defined(_WIN32) #define MA_WIN32 #if defined(MA_FORCE_UWP) || (defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_PC_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) || (defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP))) #define MA_WIN32_UWP #elif defined(WINAPI_FAMILY) && (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES) #define MA_WIN32_GDK + #elif defined(NXDK) + #define MA_WIN32_NXDK #else #define MA_WIN32_DESKTOP #endif + + /* The original Xbox. */ + #if defined(NXDK) /* <-- Add other Xbox compiler toolchains here, and then add a toolchain-specific define in case we need to discriminate between them later. */ + #define MA_XBOX + + #if defined(NXDK) + #define MA_XBOX_NXDK + #endif + #endif #endif -#if !defined(_WIN32) /* If it's not Win32, assume POSIX. */ +#if defined(__MSDOS__) || defined(MSDOS) || defined(_MSDOS) || defined(__DOS__) + #define MA_DOS + + /* No threading allowed on DOS. */ + #ifndef MA_NO_THREADING + #define MA_NO_THREADING + #endif + + /* No runtime linking allowed on DOS. */ + #ifndef MA_NO_RUNTIME_LINKING + #define MA_NO_RUNTIME_LINKING + #endif +#endif +#if !defined(MA_WIN32) && !defined(MA_DOS) /* If it's not Win32, assume POSIX. */ #define MA_POSIX - /* - Use the MA_NO_PTHREAD_IN_HEADER option at your own risk. This is intentionally undocumented. - You can use this to avoid including pthread.h in the header section. The downside is that it - results in some fixed sized structures being declared for the various types that are used in - miniaudio. The risk here is that these types might be too small for a given platform. This - risk is yours to take and no support will be offered if you enable this option. - */ - #ifndef MA_NO_PTHREAD_IN_HEADER - #include /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */ - typedef pthread_t ma_pthread_t; - typedef pthread_mutex_t ma_pthread_mutex_t; - typedef pthread_cond_t ma_pthread_cond_t; - #else - typedef ma_uintptr ma_pthread_t; - typedef union ma_pthread_mutex_t { char __data[40]; ma_uint64 __alignment; } ma_pthread_mutex_t; - typedef union ma_pthread_cond_t { char __data[48]; ma_uint64 __alignment; } ma_pthread_cond_t; + #if !defined(MA_NO_THREADING) + /* + Use the MA_NO_PTHREAD_IN_HEADER option at your own risk. This is intentionally undocumented. + You can use this to avoid including pthread.h in the header section. The downside is that it + results in some fixed sized structures being declared for the various types that are used in + miniaudio. The risk here is that these types might be too small for a given platform. This + risk is yours to take and no support will be offered if you enable this option. + */ + #ifndef MA_NO_PTHREAD_IN_HEADER + #include /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */ + typedef pthread_t ma_pthread_t; + typedef pthread_mutex_t ma_pthread_mutex_t; + typedef pthread_cond_t ma_pthread_cond_t; + #else + typedef ma_uintptr ma_pthread_t; + typedef union ma_pthread_mutex_t { char __data[40]; ma_uint64 __alignment; } ma_pthread_mutex_t; + typedef union ma_pthread_cond_t { char __data[48]; ma_uint64 __alignment; } ma_pthread_cond_t; + #endif #endif #if defined(__unix__) @@ -3914,8 +3939,11 @@ typedef ma_uint16 wchar_t; #if defined(__PROSPERO__) #define MA_PROSPERO #endif - #if defined(__NX__) - #define MA_NX + #if defined(__3DS__) + #define MA_3DS + #endif + #if defined(__SWITCH__) || defined(__NX__) + #define MA_SWITCH #endif #if defined(__BEOS__) || defined(__HAIKU__) #define MA_BEOS @@ -3925,12 +3953,13 @@ typedef ma_uint16 wchar_t; #endif #endif -#if defined(__has_c_attribute) - #if __has_c_attribute(fallthrough) - #define MA_FALLTHROUGH [[fallthrough]] - #endif +#if !defined(MA_FALLTHROUGH) && defined(__cplusplus) && __cplusplus >= 201703L + #define MA_FALLTHROUGH [[fallthrough]] #endif -#if !defined(MA_FALLTHROUGH) && defined(__has_attribute) && (defined(__clang__) || defined(__GNUC__)) +#if !defined(MA_FALLTHROUGH) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L + #define MA_FALLTHROUGH [[fallthrough]] +#endif +#if !defined(MA_FALLTHROUGH) && defined(__has_attribute) #if __has_attribute(fallthrough) #define MA_FALLTHROUGH __attribute__((fallthrough)) #endif @@ -3967,7 +3996,7 @@ typedef ma_uint16 wchar_t; #define MA_NO_INLINE __attribute__((noinline)) #else #define MA_INLINE MA_GNUC_INLINE_HINT - #define MA_NO_INLINE __attribute__((noinline)) + #define MA_NO_INLINE #endif #elif defined(__WATCOMC__) #define MA_INLINE __inline @@ -4153,9 +4182,13 @@ typedef enum MA_CHANNEL_AUX_29 = 49, MA_CHANNEL_AUX_30 = 50, MA_CHANNEL_AUX_31 = 51, + + /* Count. */ + MA_CHANNEL_POSITION_COUNT, + + /* Aliases. */ MA_CHANNEL_LEFT = MA_CHANNEL_FRONT_LEFT, MA_CHANNEL_RIGHT = MA_CHANNEL_FRONT_RIGHT, - MA_CHANNEL_POSITION_COUNT = (MA_CHANNEL_AUX_31 + 1) } _ma_channel_position; /* Do not use `_ma_channel_position` directly. Use `ma_channel` instead. */ typedef enum @@ -4350,7 +4383,7 @@ typedef struct typedef struct { - ma_int32 state; + ma_uint32 state; } ma_lcg; @@ -6569,22 +6602,18 @@ This section contains the APIs for device playback and capture. Here is where yo ************************************************************************************************************************************************************/ #ifndef MA_NO_DEVICE_IO /* Some backends are only supported on certain platforms. */ -#if defined(MA_WIN32) +#if defined(MA_WIN32) && !defined(MA_XBOX) #define MA_SUPPORT_WASAPI #if defined(MA_WIN32_DESKTOP) /* DirectSound and WinMM backends are only supported on desktops. */ #define MA_SUPPORT_DSOUND #define MA_SUPPORT_WINMM - - /* Don't enable JACK here if compiling with Cosmopolitan. It'll be enabled in the Linux section below. */ - #if !defined(__COSMOPOLITAN__) - #define MA_SUPPORT_JACK /* JACK is technically supported on Windows, but I don't know how many people use it in practice... */ - #endif + #define MA_SUPPORT_JACK /* JACK is technically supported on Windows, but I don't know how many people use it in practice... */ #endif #endif #if defined(MA_UNIX) && !defined(MA_ORBIS) && !defined(MA_PROSPERO) #if defined(MA_LINUX) - #if !defined(MA_ANDROID) && !defined(__COSMOPOLITAN__) /* ALSA is not supported on Android. */ + #if !defined(MA_ANDROID) && !defined(MA_EMSCRIPTEN) /* ALSA is not supported on Android. */ #define MA_SUPPORT_ALSA #endif #endif @@ -7426,6 +7455,7 @@ struct ma_context ma_proc snd_pcm_hw_params_set_rate_resample; ma_proc snd_pcm_hw_params_set_rate; ma_proc snd_pcm_hw_params_set_rate_near; + ma_proc snd_pcm_hw_params_set_rate_minmax; ma_proc snd_pcm_hw_params_set_buffer_size_near; ma_proc snd_pcm_hw_params_set_periods_near; ma_proc snd_pcm_hw_params_set_access; @@ -7986,6 +8016,7 @@ struct ma_device /*AAudioStream**/ ma_ptr pStreamPlayback; /*AAudioStream**/ ma_ptr pStreamCapture; ma_mutex rerouteLock; + ma_atomic_bool32 isTearingDown; ma_aaudio_usage usage; ma_aaudio_content_type contentType; ma_aaudio_input_preset inputPreset; @@ -9644,7 +9675,7 @@ Parameters ---------- pBackends (out, optional) A pointer to the buffer that will receive the enabled backends. Set to NULL to retrieve the backend count. Setting - the capacity of the buffer to `MA_BUFFER_COUNT` will guarantee it's large enough for all backends. + the capacity of the buffer to `MA_BACKEND_COUNT` will guarantee it's large enough for all backends. backendCap (in) The capacity of the `pBackends` buffer. @@ -10489,6 +10520,7 @@ typedef struct ma_decoding_backend_vtable** ppCustomDecodingBackendVTables; ma_uint32 customDecodingBackendCount; void* pCustomDecodingBackendUserData; + ma_resampler_config resampling; } ma_resource_manager_config; MA_API ma_resource_manager_config ma_resource_manager_config_init(void); @@ -10816,6 +10848,7 @@ MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void* MA_API ma_uint32 ma_node_graph_get_channels(const ma_node_graph* pNodeGraph); MA_API ma_uint64 ma_node_graph_get_time(const ma_node_graph* pNodeGraph); MA_API ma_result ma_node_graph_set_time(ma_node_graph* pNodeGraph, ma_uint64 globalTime); +MA_API ma_uint32 ma_node_graph_get_processing_size_in_frames(const ma_node_graph* pNodeGraph); @@ -11123,6 +11156,7 @@ typedef struct ma_bool8 isPitchDisabled; /* Pitching can be explicitly disabled with MA_SOUND_FLAG_NO_PITCH to optimize processing. */ ma_bool8 isSpatializationDisabled; /* Spatialization can be explicitly disabled with MA_SOUND_FLAG_NO_SPATIALIZATION. */ ma_uint8 pinnedListenerIndex; /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */ + ma_resampler_config resampling; } ma_engine_node_config; MA_API ma_engine_node_config ma_engine_node_config_init(ma_engine* pEngine, ma_engine_node_type type, ma_uint32 flags); @@ -11137,7 +11171,7 @@ typedef struct ma_uint32 volumeSmoothTimeInPCMFrames; ma_mono_expansion_mode monoExpansionMode; ma_fader fader; - ma_linear_resampler resampler; /* For pitch shift. */ + ma_resampler resampler; /* For pitch shift. */ ma_spatializer spatializer; ma_panner panner; ma_gainer volumeGainer; /* This will only be used if volumeSmoothTimeInPCMFrames is > 0. */ @@ -11193,6 +11227,7 @@ typedef struct ma_uint64 loopPointEndInPCMFrames; ma_sound_end_proc endCallback; /* Fired when the sound reaches the end. Will be fired from the audio thread. Do not restart, uninitialize or otherwise change the state of the sound from here. Instead fire an event or set a variable to indicate to a different thread to change the start of the sound. Will not be fired in response to a scheduled stop with ma_sound_set_stop_time_*(). */ void* pEndCallbackUserData; + ma_resampler_config pitchResampling; #ifndef MA_NO_RESOURCE_MANAGER ma_resource_manager_pipeline_notifications initNotifications; #endif @@ -11211,7 +11246,10 @@ struct ma_sound MA_ATOMIC(4, ma_bool32) atEnd; ma_sound_end_proc endCallback; void* pEndCallbackUserData; - ma_bool8 ownsDataSource; + float* pProcessingCache; /* Will be null if pDataSource is null. */ + ma_uint32 processingCacheFramesRemaining; + ma_uint32 processingCacheCap; + ma_bool8 ownsDataSource; /* We're declaring a resource manager data source object here to save us a malloc when loading a @@ -11255,7 +11293,7 @@ typedef struct ma_log* pLog; /* When set to NULL, will use the context's log. */ ma_uint32 listenerCount; /* Must be between 1 and MA_ENGINE_MAX_LISTENERS. */ ma_uint32 channels; /* The number of channels to use when mixing and spatializing. When set to 0, will use the native channel count of the device. */ - ma_uint32 sampleRate; /* The sample rate. When set to 0 will use the native channel count of the device. */ + ma_uint32 sampleRate; /* The sample rate. When set to 0 will use the native sample rate of the device. */ ma_uint32 periodSizeInFrames; /* If set to something other than 0, updates will always be exactly this size. The underlying device may be a different size, but from the perspective of the mixer that won't matter.*/ ma_uint32 periodSizeInMilliseconds; /* Used if periodSizeInFrames is unset. */ ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. If set to 0, will use gainSmoothTimeInMilliseconds. */ @@ -11269,6 +11307,8 @@ typedef struct ma_vfs* pResourceManagerVFS; /* A pointer to a pre-allocated VFS object to use with the resource manager. This is ignored if pResourceManager is not NULL. */ ma_engine_process_proc onProcess; /* Fired at the end of each call to ma_engine_read_pcm_frames(). For engine's that manage their own internal device (the default configuration), this will be fired from the audio thread, and you do not need to call ma_engine_read_pcm_frames() manually in order to trigger this. */ void* pProcessUserData; /* User data that's passed into onProcess. */ + ma_resampler_config resourceManagerResampling; /* The resampling config to use with the resource manager. */ + ma_resampler_config pitchResampling; /* The resampling config for the pitch and Doppler effects. You will typically want this to be a fast resampler. For high quality stuff, it's recommended that you pre-resample. */ } ma_engine_config; MA_API ma_engine_config ma_engine_config_init(void); @@ -11298,6 +11338,7 @@ struct ma_engine ma_mono_expansion_mode monoExpansionMode; ma_engine_process_proc onProcess; void* pProcessUserData; + ma_resampler_config pitchResamplingConfig; }; MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEngine); @@ -11358,8 +11399,12 @@ MA_API ma_engine* ma_sound_get_engine(const ma_sound* pSound); MA_API ma_data_source* ma_sound_get_data_source(const ma_sound* pSound); MA_API ma_result ma_sound_start(ma_sound* pSound); MA_API ma_result ma_sound_stop(ma_sound* pSound); -MA_API ma_result ma_sound_stop_with_fade_in_pcm_frames(ma_sound* pSound, ma_uint64 fadeLengthInFrames); /* Will overwrite any scheduled stop and fade. */ -MA_API ma_result ma_sound_stop_with_fade_in_milliseconds(ma_sound* pSound, ma_uint64 fadeLengthInFrames); /* Will overwrite any scheduled stop and fade. */ +MA_API ma_result ma_sound_stop_with_fade_in_pcm_frames(ma_sound* pSound, ma_uint64 fadeLengthInFrames); /* Will overwrite any scheduled stop and fade. If you want to restart the sound, first reset it with `ma_sound_reset_stop_time_and_fade()`. There are plans to make this less awkward in the future. */ +MA_API ma_result ma_sound_stop_with_fade_in_milliseconds(ma_sound* pSound, ma_uint64 fadeLengthInFrames); /* Will overwrite any scheduled stop and fade. If you want to restart the sound, first reset it with `ma_sound_reset_stop_time_and_fade()`. There are plans to make this less awkward in the future. */ +MA_API void ma_sound_reset_start_time(ma_sound* pSound); +MA_API void ma_sound_reset_stop_time(ma_sound* pSound); +MA_API void ma_sound_reset_fade(ma_sound* pSound); +MA_API void ma_sound_reset_stop_time_and_fade(ma_sound* pSound); /* Resets fades and scheduled stop time. Does not seek back to the start. */ MA_API void ma_sound_set_volume(ma_sound* pSound, float volume); MA_API float ma_sound_get_volume(const ma_sound* pSound); MA_API void ma_sound_set_pan(ma_sound* pSound, float pan); @@ -11419,11 +11464,11 @@ MA_API ma_bool32 ma_sound_is_looping(const ma_sound* pSound); MA_API ma_bool32 ma_sound_at_end(const ma_sound* pSound); MA_API ma_result ma_sound_seek_to_pcm_frame(ma_sound* pSound, ma_uint64 frameIndex); /* Just a wrapper around ma_data_source_seek_to_pcm_frame(). */ MA_API ma_result ma_sound_seek_to_second(ma_sound* pSound, float seekPointInSeconds); /* Abstraction to ma_sound_seek_to_pcm_frame() */ -MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor); -MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength); -MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor); -MA_API ma_result ma_sound_get_length_in_seconds(ma_sound* pSound, float* pLength); +MA_API ma_result ma_sound_get_data_format(const ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); +MA_API ma_result ma_sound_get_cursor_in_pcm_frames(const ma_sound* pSound, ma_uint64* pCursor); +MA_API ma_result ma_sound_get_length_in_pcm_frames(const ma_sound* pSound, ma_uint64* pLength); +MA_API ma_result ma_sound_get_cursor_in_seconds(const ma_sound* pSound, float* pCursor); +MA_API ma_result ma_sound_get_length_in_seconds(const ma_sound* pSound, float* pLength); MA_API ma_result ma_sound_set_end_callback(ma_sound* pSound, ma_sound_end_proc callback, void* pUserData); MA_API ma_result ma_sound_group_init(ma_engine* pEngine, ma_uint32 flags, ma_sound_group* pParentGroup, ma_sound_group* pGroup); @@ -11544,17 +11589,23 @@ IMPLEMENTATION #endif #if !defined(MA_WIN32) -#include -#include /* select() (used for ma_sleep()). */ -#include + #if !defined(MA_NO_THREADING) + #include + #include /* For pthreads. */ + #endif + + #include /* select() (used for ma_sleep()). */ + #include /* For nanosleep() */ + #include #endif -#ifdef MA_NX -#include /* For nanosleep() */ +/* For fstat(), etc. */ +#if defined(MA_XBOX_NXDK) + #include /* Suggestion for NXDK: Add a sys/stat.h wrapper for compatibility. */ +#else + #include #endif -#include /* For fstat(), etc. */ - #ifdef MA_EMSCRIPTEN #include #endif @@ -11606,7 +11657,7 @@ IMPLEMENTATION #endif /* Intrinsics Support */ -#if (defined(MA_X64) || defined(MA_X86)) && !defined(__COSMOPOLITAN__) +#if defined(MA_X64) || defined(MA_X86) #if defined(_MSC_VER) && !defined(__clang__) /* MSVC. */ #if _MSC_VER >= 1400 && !defined(MA_NO_SSE2) /* 2005 */ @@ -11861,7 +11912,7 @@ static MA_INLINE ma_bool32 ma_has_neon(void) #endif #ifndef MA_RESTRICT - #if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER) + #if defined(__clang__) || defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95))) #define MA_RESTRICT __restrict #else #define MA_RESTRICT @@ -11955,7 +12006,7 @@ static void ma_sleep__posix(ma_uint32 milliseconds) (void)milliseconds; MA_ASSERT(MA_FALSE); /* The Emscripten build should never sleep. */ #else - #if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L) || defined(MA_NX) + #if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L) || defined(MA_SWITCH) struct timespec ts; ts.tv_sec = milliseconds / 1000; ts.tv_nsec = milliseconds % 1000 * 1000000; @@ -11997,7 +12048,7 @@ static MA_INLINE void ma_yield(void) #endif #endif #else - __asm__ __volatile__ ("pause"); + __asm__ __volatile__ ("rep; nop"); #endif #elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || defined(_M_ARM64) || (defined(_M_ARM) && _M_ARM >= 7) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) /* ARM */ @@ -12020,7 +12071,7 @@ static MA_INLINE unsigned int ma_disable_denormals(void) { unsigned int prevState; - #if defined(_MSC_VER) + #if defined(_MSC_VER) && !defined(MA_XBOX_NXDK) { /* Older versions of Visual Studio don't support the "safe" versions of _controlfp_s(). I don't @@ -12043,7 +12094,7 @@ static MA_INLINE unsigned int ma_disable_denormals(void) } #elif defined(MA_X86) || defined(MA_X64) { - #if defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__) || defined(__COSMOPOLITAN__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ + #if defined(MA_SUPPORT_SSE2) && defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ { prevState = _mm_getcsr(); _mm_setcsr(prevState | MA_MM_DENORMALS_ZERO_MASK | MA_MM_FLUSH_ZERO_MASK); @@ -12067,7 +12118,7 @@ static MA_INLINE unsigned int ma_disable_denormals(void) static MA_INLINE void ma_restore_denormals(unsigned int prevState) { - #if defined(_MSC_VER) + #if defined(_MSC_VER) && !defined(MA_XBOX_NXDK) { /* Older versions of Visual Studio do not support _controlfp_s(). See ma_disable_denormals(). */ #if _MSC_VER <= 1200 @@ -12083,7 +12134,7 @@ static MA_INLINE void ma_restore_denormals(unsigned int prevState) } #elif defined(MA_X86) || defined(MA_X64) { - #if defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__) || defined(__COSMOPOLITAN__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ + #if defined(MA_SUPPORT_SSE2) && defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ { _mm_setcsr(prevState); } @@ -12719,6 +12770,29 @@ MA_API MA_NO_INLINE int ma_strcmp(const char* str1, const char* str2) return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0]; } +MA_API MA_NO_INLINE int ma_wcscmp(const wchar_t* str1, const wchar_t* str2) +{ + if (str1 == str2) return 0; + + /* These checks differ from the standard implementation. It's not important, but I prefer it just for sanity. */ + if (str1 == NULL) return -1; + if (str2 == NULL) return 1; + + for (;;) { + if (str1[0] == L'\0') { + break; + } + if (str1[0] != str2[0]) { + break; + } + + str1 += 1; + str2 += 1; + } + + return ((unsigned short*)str1)[0] - ((unsigned short*)str2)[0]; +} + MA_API MA_NO_INLINE int ma_strappend(char* dst, size_t dstSize, const char* srcA, const char* srcB) { int result; @@ -12736,6 +12810,22 @@ MA_API MA_NO_INLINE int ma_strappend(char* dst, size_t dstSize, const char* srcA return result; } +MA_API MA_NO_INLINE size_t ma_wcslen(const wchar_t* str) +{ + const wchar_t* end; + + if (str == NULL) { + return 0; + } + + end = str; + while (end[0] != '\0') { + end += 1; + } + + return end - str; +} + MA_API MA_NO_INLINE char* ma_copy_string(const char* src, const ma_allocation_callbacks* pAllocationCallbacks) { size_t sz; @@ -12758,7 +12848,7 @@ MA_API MA_NO_INLINE char* ma_copy_string(const char* src, const ma_allocation_ca MA_API MA_NO_INLINE wchar_t* ma_copy_string_w(const wchar_t* src, const ma_allocation_callbacks* pAllocationCallbacks) { - size_t sz = wcslen(src)+1; + size_t sz = ma_wcslen(src)+1; wchar_t* dst = (wchar_t*)ma_malloc(sz * sizeof(*dst), pAllocationCallbacks); if (dst == NULL) { return NULL; @@ -13189,7 +13279,7 @@ MA_API ma_result ma_fopen(FILE** ppFile, const char* pFilePath, const char* pOpe return MA_INVALID_ARGS; } -#if defined(_MSC_VER) && _MSC_VER >= 1400 +#if (defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(MA_XBOX_NXDK) err = fopen_s(ppFile, pFilePath, pOpenMode); if (err != 0) { return ma_result_from_errno(err); @@ -13231,7 +13321,7 @@ _wfopen() isn't always available in all compilation environments. This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs() fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support. */ -#if defined(_WIN32) +#if defined(_WIN32) && !defined(MA_XBOX_NXDK) #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) #define MA_HAS_WFOPEN #endif @@ -13247,29 +13337,34 @@ MA_API ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_ return MA_INVALID_ARGS; } -#if defined(MA_HAS_WFOPEN) + #if defined(MA_HAS_WFOPEN) { /* Use _wfopen() on Windows. */ - #if defined(_MSC_VER) && _MSC_VER >= 1400 - errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); - if (err != 0) { - return ma_result_from_errno(err); + #if defined(_MSC_VER) && _MSC_VER >= 1400 + { + errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return ma_result_from_errno(err); + } } - #else - *ppFile = _wfopen(pFilePath, pOpenMode); - if (*ppFile == NULL) { - return ma_result_from_errno(errno); + #else + { + *ppFile = _wfopen(pFilePath, pOpenMode); + if (*ppFile == NULL) { + return ma_result_from_errno(errno); + } } - #endif + #endif + (void)pAllocationCallbacks; } -#else - /* - Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can - think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for - maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility. - */ + #elif !defined(MA_XBOX_NXDK) && !defined(MA_DOS) /* If your compiler does not support wcsrtombs(), add it here. */ { + /* + Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can + think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for + maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility. + */ mbstate_t mbs; size_t lenMB; const wchar_t* pFilePathTemp = pFilePath; @@ -13310,11 +13405,16 @@ MA_API ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_ ma_free(pFilePathMB, pAllocationCallbacks); } + #else + { + /* Getting here means there is no way to open the file with a wide character string. */ + *ppFile = NULL; + } + #endif if (*ppFile == NULL) { return MA_ERROR; } -#endif return MA_SUCCESS; } @@ -13323,7 +13423,7 @@ MA_API ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_ static MA_INLINE void ma_copy_memory_64(void* dst, const void* src, ma_uint64 sizeInBytes) { -#if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX +#if MA_SIZE_MAX > 0xFFFFFFFF MA_COPY_MEMORY(dst, src, (size_t)sizeInBytes); #else while (sizeInBytes > 0) { @@ -13343,7 +13443,7 @@ static MA_INLINE void ma_copy_memory_64(void* dst, const void* src, ma_uint64 si static MA_INLINE void ma_zero_memory_64(void* dst, ma_uint64 sizeInBytes) { -#if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX +#if MA_SIZE_MAX > 0xFFFFFFFF MA_ZERO_MEMORY(dst, (size_t)sizeInBytes); #else while (sizeInBytes > 0) { @@ -13472,6 +13572,18 @@ static ma_result ma_allocation_callbacks_init_copy(ma_allocation_callbacks* pDst Logging **************************************************************************************************************************************************************/ +#ifndef ma_va_copy + #if !defined(_MSC_VER) || _MSC_VER >= 1800 + #if (defined(__GNUC__) && __GNUC__ < 3) + #define ma_va_copy(dst, src) ((dst) = (src)) /* This is untested. Not sure if this is correct for old GCC. */ + #else + #define ma_va_copy(dst, src) va_copy((dst), (src)) + #endif + #else + #define ma_va_copy(dst, src) ((dst) = (src)) + #endif +#endif + MA_API const char* ma_log_level_to_string(ma_uint32 logLevel) { switch (logLevel) @@ -13712,9 +13824,15 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat int length; char pFormattedMessageStack[1024]; char* pFormattedMessageHeap = NULL; + va_list args2; /* First try formatting into our fixed sized stack allocated buffer. If this is too small we'll fallback to a heap allocation. */ - length = vsnprintf(pFormattedMessageStack, sizeof(pFormattedMessageStack), pFormat, args); + ma_va_copy(args2, args); + { + length = vsnprintf(pFormattedMessageStack, sizeof(pFormattedMessageStack), pFormat, args2); + } + va_end(args2); + if (length < 0) { return MA_INVALID_OPERATION; /* An error occurred when trying to convert the buffer. */ } @@ -13755,17 +13873,10 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat char* pFormattedMessage = NULL; va_list args2; - #if _MSC_VER >= 1800 + ma_va_copy(args2, args); { - va_copy(args2, args); + formattedLen = ma_vscprintf(&pLog->allocationCallbacks, pFormat, args2); } - #else - { - args2 = args; - } - #endif - - formattedLen = ma_vscprintf(&pLog->allocationCallbacks, pFormat, args2); va_end(args2); if (formattedLen <= 0) { @@ -13964,7 +14075,7 @@ miniaudio's purposes. #define MA_LCG_A 48271 #define MA_LCG_C 0 -static ma_lcg g_maLCG = {MA_DEFAULT_LCG_SEED}; /* Non-zero initial seed. Use ma_seed() to use an explicit seed. */ +static ma_lcg g_maLCG = {MA_DEFAULT_LCG_SEED}; /* Non-zero initial seed. Use ma_lcg_seed() to use an explicit seed. */ static MA_INLINE void ma_lcg_seed(ma_lcg* pLCG, ma_int32 seed) { @@ -14013,7 +14124,7 @@ static MA_INLINE ma_int32 ma_lcg_rand_range_s32(ma_lcg* pLCG, ma_int32 lo, ma_in } - +#if 0 /* Currently unused. */ static MA_INLINE void ma_seed(ma_int32 seed) { ma_lcg_seed(&g_maLCG, seed); @@ -14038,6 +14149,7 @@ static MA_INLINE float ma_rand_f32(void) { return ma_lcg_rand_f32(&g_maLCG); } +#endif static MA_INLINE float ma_rand_range_f32(float lo, float hi) { @@ -14097,6 +14209,7 @@ Atomics **************************************************************************************************************************************************************/ /* c89atomic.h begin */ #ifndef ma_atomic_h +#define ma_atomic_h #if defined(__cplusplus) extern "C" { #endif @@ -14108,11 +14221,63 @@ extern "C" { #endif #endif typedef int ma_atomic_memory_order; -#define MA_ATOMIC_HAS_8 -#define MA_ATOMIC_HAS_16 -#define MA_ATOMIC_HAS_32 -#define MA_ATOMIC_HAS_64 -#if (defined(_MSC_VER) ) || defined(__WATCOMC__) || defined(__DMC__) +#if !defined(MA_ATOMIC_MODERN_MSVC) && \ + !defined(MA_ATOMIC_LEGACY_MSVC) && \ + !defined(MA_ATOMIC_LEGACY_MSVC_ASM) && \ + !defined(MA_ATOMIC_MODERN_GCC) && \ + !defined(MA_ATOMIC_LEGACY_GCC) && \ + !defined(MA_ATOMIC_LEGACY_GCC_ASM) + #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__) || defined(__BORLANDC__) + #if (defined(_MSC_VER) && _MSC_VER > 1600) + #define MA_ATOMIC_MODERN_MSVC + #else + #if defined(MA_X64) + #define MA_ATOMIC_LEGACY_MSVC + #else + #define MA_ATOMIC_LEGACY_MSVC_ASM + #endif + #endif + #elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) || defined(__clang__) + #define MA_ATOMIC_MODERN_GCC + #else + #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) + #define MA_ATOMIC_LEGACY_GCC + #else + #define MA_ATOMIC_LEGACY_GCC_ASM + #endif + #endif +#endif +#if defined(MA_ATOMIC_MODERN_MSVC) || defined(MA_ATOMIC_LEGACY_MSVC) + #include + #define ma_atomic_memory_order_relaxed 1 + #define ma_atomic_memory_order_consume 2 + #define ma_atomic_memory_order_acquire 3 + #define ma_atomic_memory_order_release 4 + #define ma_atomic_memory_order_acq_rel 5 + #define ma_atomic_memory_order_seq_cst 6 + #define MA_ATOMIC_MSVC_ARM_INTRINSIC_NORETURN(dst, src, order, intrin, ma_atomicType, msvcType) \ + switch (order) \ + { \ + case ma_atomic_memory_order_relaxed: \ + { \ + intrin##_nf((volatile msvcType*)dst, (msvcType)src); \ + } break; \ + case ma_atomic_memory_order_consume: \ + case ma_atomic_memory_order_acquire: \ + { \ + intrin##_acq((volatile msvcType*)dst, (msvcType)src); \ + } break; \ + case ma_atomic_memory_order_release: \ + { \ + intrin##_rel((volatile msvcType*)dst, (msvcType)src); \ + } break; \ + case ma_atomic_memory_order_acq_rel: \ + case ma_atomic_memory_order_seq_cst: \ + default: \ + { \ + intrin((volatile msvcType*)dst, (msvcType)src); \ + } break; \ + } #define MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, intrin, ma_atomicType, msvcType) \ ma_atomicType result; \ switch (order) \ @@ -14138,720 +14303,1501 @@ typedef int ma_atomic_memory_order; } break; \ } \ return result; - #define MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, expected, desired, order, intrin, ma_atomicType, msvcType) \ + typedef ma_uint32 ma_atomic_flag; + static MA_INLINE ma_atomic_flag ma_atomic_flag_test_and_set_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, 1, order, _InterlockedExchange, ma_atomic_flag, long); + } + #else + { + (void)order; + return (ma_atomic_flag)_InterlockedExchange((volatile long*)dst, (long)1); + } + #endif + } + static MA_INLINE void ma_atomic_flag_clear_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC_NORETURN(dst, 0, order, _InterlockedExchange, ma_atomic_flag, long); + } + #else + { + (void)order; + _InterlockedExchange((volatile long*)dst, (long)0); + } + #endif + } + static MA_INLINE ma_atomic_flag ma_atomic_flag_load_explicit(volatile const ma_atomic_flag* dst, ma_atomic_memory_order order) + { + (void)order; + return (ma_uint32)_InterlockedCompareExchange((volatile long*)dst, 0, 0); + } +#endif +#if defined(MA_ATOMIC_LEGACY_MSVC_ASM) + #define ma_atomic_memory_order_relaxed 1 + #define ma_atomic_memory_order_consume 2 + #define ma_atomic_memory_order_acquire 3 + #define ma_atomic_memory_order_release 4 + #define ma_atomic_memory_order_acq_rel 5 + #define ma_atomic_memory_order_seq_cst 6 + typedef ma_uint32 ma_atomic_flag; + static MA_INLINE ma_atomic_flag ma_atomic_flag_test_and_set_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + ma_atomic_flag result = 0; + (void)order; + __asm { + mov ecx, dst + mov eax, 1 + xchg [ecx], eax + mov result, eax + } + return result; + } + static MA_INLINE void ma_atomic_flag_clear_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov dword ptr [esi], 0 + } + } else { + __asm { + mov esi, dst + mov eax, 0 + xchg [esi], eax + } + } + } + static MA_INLINE ma_atomic_flag ma_atomic_flag_load_explicit(volatile const ma_atomic_flag* dst, ma_atomic_memory_order order) + { + ma_atomic_flag result = 0; + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov eax, [esi] + mov result, eax + } + } else if (order <= ma_atomic_memory_order_release) { + __asm { + mov esi, dst + mov eax, [esi] + lock add dword ptr [esp], 0 + mov result, eax + } + } else { + __asm { + lock add dword ptr [esp], 0 + mov esi, dst + mov eax, [esi] + mov result, eax + lock add dword ptr [esp], 0 + } + } + return result; + } +#endif +#if defined(MA_ATOMIC_MODERN_GCC) + #define ma_atomic_memory_order_relaxed __ATOMIC_RELAXED + #define ma_atomic_memory_order_consume __ATOMIC_CONSUME + #define ma_atomic_memory_order_acquire __ATOMIC_ACQUIRE + #define ma_atomic_memory_order_release __ATOMIC_RELEASE + #define ma_atomic_memory_order_acq_rel __ATOMIC_ACQ_REL + #define ma_atomic_memory_order_seq_cst __ATOMIC_SEQ_CST + typedef ma_uint32 ma_atomic_flag; + #define ma_atomic_flag_test_and_set_explicit(dst, order) __atomic_exchange_n(dst, 1, order) + #define ma_atomic_flag_clear_explicit(dst, order) __atomic_store_n(dst, 0, order) + #define ma_atomic_flag_load_explicit(dst, order) __atomic_load_n(dst, order) +#endif +#if defined(MA_ATOMIC_LEGACY_GCC) + #define ma_atomic_memory_order_relaxed 1 + #define ma_atomic_memory_order_consume 2 + #define ma_atomic_memory_order_acquire 3 + #define ma_atomic_memory_order_release 4 + #define ma_atomic_memory_order_acq_rel 5 + #define ma_atomic_memory_order_seq_cst 6 + typedef ma_uint32 ma_atomic_flag; + static MA_INLINE ma_atomic_flag ma_atomic_flag_test_and_set_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + if (order > ma_atomic_memory_order_acquire) { + __sync_synchronize(); + } + return __sync_lock_test_and_set(dst, 1); + } + static MA_INLINE void ma_atomic_flag_clear_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + if (order > ma_atomic_memory_order_release) { + __sync_synchronize(); + } + __sync_lock_release(dst); + } + static MA_INLINE ma_atomic_flag ma_atomic_flag_load_explicit(volatile const ma_atomic_flag* dst, ma_atomic_memory_order order) + { + (void)order; + return __sync_val_compare_and_swap((ma_atomic_flag*)dst, 0, 0); + } +#endif +#if defined(MA_ATOMIC_LEGACY_GCC_ASM) + #define ma_atomic_memory_order_relaxed 1 + #define ma_atomic_memory_order_consume 2 + #define ma_atomic_memory_order_acquire 3 + #define ma_atomic_memory_order_release 4 + #define ma_atomic_memory_order_acq_rel 5 + #define ma_atomic_memory_order_seq_cst 6 + #if defined(MA_X86) + #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory") + #elif defined(MA_X64) + #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addq $0, (%%rsp)" ::: "memory") + #else + #error Unsupported architecture. + #endif + #define MA_ATOMIC_XCHG_GCC_X86(instructionSizeSuffix, result, dst, src) \ + __asm__ __volatile__( \ + "xchg"instructionSizeSuffix" %0, %1" \ + : "=r"(result), \ + "=m"(*dst) \ + : "0"(src), \ + "m"(*dst) \ + : "memory" \ + ) + #define MA_ATOMIC_LOAD_RELAXED_GCC_X86(instructionSizeSuffix, result, dst) \ + __asm__ __volatile__( \ + "mov"instructionSizeSuffix" %1, %0" \ + : "=r"(result) \ + : "m"(*dst) \ + ) + #define MA_ATOMIC_LOAD_RELEASE_GCC_X86(instructionSizeSuffix, result, dst) \ + ma_atomic_thread_fence(ma_atomic_memory_order_release); \ + __asm__ __volatile__( \ + "mov"instructionSizeSuffix" %1, %0" \ + : "=r"(result) \ + : "m"(*dst) \ + : "memory" \ + ) + #define MA_ATOMIC_LOAD_SEQ_CST_GCC_X86(instructionSizeSuffix, result, dst) \ + ma_atomic_thread_fence(ma_atomic_memory_order_seq_cst); \ + __asm__ __volatile__( \ + "mov"instructionSizeSuffix" %1, %0" \ + : "=r"(result) \ + : "m"(*dst) \ + : "memory" \ + ); \ + ma_atomic_thread_fence(ma_atomic_memory_order_seq_cst) + typedef ma_uint32 ma_atomic_flag; + static MA_INLINE ma_atomic_flag ma_atomic_flag_test_and_set_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + ma_atomic_flag result; + #if defined(MA_X86) || defined(MA_X64) + { + (void)order; + MA_ATOMIC_XCHG_GCC_X86("l", result, dst, 1); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + static MA_INLINE void ma_atomic_flag_clear_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm__ __volatile__( + "movl $0, %0" + : "=m"(*dst) + ); + } else if (order == ma_atomic_memory_order_release) { + __asm__ __volatile__( + "movl $0, %0" + : "=m"(*dst) + : + : "memory" + ); + } else { + ma_atomic_flag tmp = 0; + __asm__ __volatile__( + "xchgl %0, %1" + : "=r"(tmp), + "=m"(*dst) + : "0"(tmp), + "m"(*dst) + : "memory" + ); + } + } + #else + { + #error Unsupported architecture. + } + #endif + } + static MA_INLINE ma_atomic_flag ma_atomic_flag_load_explicit(volatile const ma_atomic_flag* dst, ma_atomic_memory_order order) + { + #if defined(MA_X86) || defined(MA_X64) + { + ma_atomic_flag result; + if (order == ma_atomic_memory_order_relaxed) { + MA_ATOMIC_LOAD_RELAXED_GCC_X86("l", result, dst); + } else if (order <= ma_atomic_memory_order_release) { + MA_ATOMIC_LOAD_RELEASE_GCC_X86("l", result, dst); + } else { + MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("l", result, dst); + } + return result; + } + #else + { + #error Unsupported architecture. + } + #endif + } +#endif +#define ma_atomic_flag_test_and_set(dst) ma_atomic_flag_test_and_set_explicit(dst, ma_atomic_memory_order_acquire) +#define ma_atomic_flag_clear(dst) ma_atomic_flag_clear_explicit(dst, ma_atomic_memory_order_release) +typedef ma_atomic_flag ma_atomic_spinlock; +static MA_INLINE void ma_atomic_spinlock_lock(volatile ma_atomic_spinlock* pSpinlock) +{ + for (;;) { + if (ma_atomic_flag_test_and_set_explicit(pSpinlock, ma_atomic_memory_order_acquire) == 0) { + break; + } + while (ma_atomic_flag_load_explicit(pSpinlock, ma_atomic_memory_order_relaxed) == 1) { + } + } +} +static MA_INLINE void ma_atomic_spinlock_unlock(volatile ma_atomic_spinlock* pSpinlock) +{ + ma_atomic_flag_clear_explicit(pSpinlock, ma_atomic_memory_order_release); +} +ma_atomic_spinlock ma_atomic_global_lock; +#if defined(MA_ATOMIC_MODERN_MSVC) || defined(MA_ATOMIC_LEGACY_MSVC) || defined(MA_ATOMIC_LEGACY_MSVC_ASM) || defined(MA_ATOMIC_LEGACY_GCC) || defined(MA_ATOMIC_LEGACY_GCC_ASM) + #if defined(MA_X64) || (defined(MA_X86) && ((defined(__GNUC__) && defined(__i486__)) || (defined(_M_IX86) && _M_IX86 >= 400))) + #if defined(MA_ATOMIC_LEGACY_MSVC) && defined(MA_X64) + #else + #define MA_ATOMIC_IS_LOCK_FREE_8 1 + #define MA_ATOMIC_IS_LOCK_FREE_16 1 + #endif + #define MA_ATOMIC_IS_LOCK_FREE_32 1 + #if defined(MA_X64) || (defined(MA_X86) && ((defined(__GNUC__) && defined(__i586__)) || (defined(_M_IX86) && _M_IX86 >= 500))) + #define MA_ATOMIC_IS_LOCK_FREE_64 1 + #else + #endif + #else + #endif + #if defined(MA_ARM32) || defined(MA_ARM64) + #define MA_ATOMIC_IS_LOCK_FREE_8 1 + #define MA_ATOMIC_IS_LOCK_FREE_16 1 + #define MA_ATOMIC_IS_LOCK_FREE_32 1 + #if defined(MA_ARM64) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) + #define MA_ATOMIC_IS_LOCK_FREE_64 1 + #endif + #endif + #if defined(MA_ATOMIC_PPC32) || defined(MA_ATOMIC_PPC64) + #if (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7))) && !defined(__clang__) + #else + #define MA_ATOMIC_IS_LOCK_FREE_8 1 + #define MA_ATOMIC_IS_LOCK_FREE_16 1 + #endif + #define MA_ATOMIC_IS_LOCK_FREE_32 1 + #if defined(MA_ATOMIC_PPC64) + #define MA_ATOMIC_IS_LOCK_FREE_64 1 + #endif + #endif + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_8(volatile void* ptr) + { + (void)ptr; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + return 1; + #else + return 0; + #endif + } + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_16(volatile void* ptr) + { + (void)ptr; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + return 1; + #else + return 0; + #endif + } + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_32(volatile void* ptr) + { + (void)ptr; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + return 1; + #else + return 0; + #endif + } + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_64(volatile void* ptr) + { + (void)ptr; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + return 1; + #else + return 0; + #endif + } +#endif +#define MA_ATOMIC_COMPARE_AND_SWAP_LOCK(sizeInBits, dst, expected, replacement) \ + ma_uint##sizeInBits result; \ + ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ + { \ + result = *dst; \ + if (result == expected) { \ + *dst = replacement; \ + } \ + } \ + ma_atomic_spinlock_unlock(&ma_atomic_global_lock); \ + return result +#define MA_ATOMIC_LOAD_EXPLICIT_LOCK(sizeInBits, ptr, order) \ + ma_uint##sizeInBits result; \ + ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ + { \ + result = *ptr; \ + (void)order; \ + } \ + ma_atomic_spinlock_unlock(&ma_atomic_global_lock); \ + return result +#define MA_ATOMIC_STORE_EXPLICIT_LOCK(sizeInBits, dst, src, order) \ + ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ + { \ + *dst = src; \ + (void)order; \ + } \ + ma_atomic_spinlock_unlock(&ma_atomic_global_lock) +#define MA_ATOMIC_STORE_EXPLICIT_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, src) != oldValue); \ + (void)order +#define MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits result; \ + ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ + { \ + result = *dst; \ + *dst = src; \ + (void)order; \ + } \ + ma_atomic_spinlock_unlock(&ma_atomic_global_lock); \ + return result +#define MA_ATOMIC_EXCHANGE_EXPLICIT_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, src) != oldValue); \ + (void)order; \ + return oldValue +#define MA_ATOMIC_FETCH_ADD_LOCK(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits result; \ + ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ + { \ + result = *dst; \ + *dst += src; \ + (void)order; \ + } \ + ma_atomic_spinlock_unlock(&ma_atomic_global_lock); \ + return result +#define MA_ATOMIC_FETCH_ADD_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + ma_uint##sizeInBits newValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + newValue = oldValue + src; \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue); \ + (void)order; \ + return oldValue +#define MA_ATOMIC_FETCH_AND_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + ma_uint##sizeInBits newValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + newValue = (ma_uint##sizeInBits)(oldValue & src); \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue); \ + (void)order; \ + return oldValue +#define MA_ATOMIC_FETCH_OR_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + ma_uint##sizeInBits newValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + newValue = (ma_uint##sizeInBits)(oldValue | src); \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue); \ + (void)order; \ + return oldValue +#define MA_ATOMIC_FETCH_XOR_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + ma_uint##sizeInBits newValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + newValue = (ma_uint##sizeInBits)(oldValue ^ src); \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue); \ + (void)order; \ + return oldValue +#if defined(MA_ATOMIC_MODERN_MSVC) || defined(MA_ATOMIC_LEGACY_MSVC) + #define MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, expected, replacement, order, intrin, ma_atomicType, msvcType) \ ma_atomicType result; \ switch (order) \ { \ case ma_atomic_memory_order_relaxed: \ { \ - result = (ma_atomicType)intrin##_nf((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ + result = (ma_atomicType)intrin##_nf((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement); \ } break; \ case ma_atomic_memory_order_consume: \ case ma_atomic_memory_order_acquire: \ { \ - result = (ma_atomicType)intrin##_acq((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ + result = (ma_atomicType)intrin##_acq((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement); \ } break; \ case ma_atomic_memory_order_release: \ { \ - result = (ma_atomicType)intrin##_rel((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ + result = (ma_atomicType)intrin##_rel((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement); \ } break; \ case ma_atomic_memory_order_acq_rel: \ case ma_atomic_memory_order_seq_cst: \ default: \ { \ - result = (ma_atomicType)intrin((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ + result = (ma_atomicType)intrin((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement); \ } break; \ } \ return result; - #define ma_atomic_memory_order_relaxed 0 - #define ma_atomic_memory_order_consume 1 - #define ma_atomic_memory_order_acquire 2 - #define ma_atomic_memory_order_release 3 - #define ma_atomic_memory_order_acq_rel 4 - #define ma_atomic_memory_order_seq_cst 5 - #if _MSC_VER < 1600 && defined(MA_X86) - #define MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY - #endif - #if _MSC_VER < 1600 - #undef MA_ATOMIC_HAS_8 - #undef MA_ATOMIC_HAS_16 - #endif - #if !defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - #include - #endif - #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 desired) - { - ma_uint8 result = 0; - __asm { - mov ecx, dst - mov al, expected - mov dl, desired - lock cmpxchg [ecx], dl - mov result, al - } - return result; - } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 desired) - { - ma_uint16 result = 0; - __asm { - mov ecx, dst - mov ax, expected - mov dx, desired - lock cmpxchg [ecx], dx - mov result, ax - } - return result; - } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 desired) - { - ma_uint32 result = 0; - __asm { - mov ecx, dst - mov eax, expected - mov edx, desired - lock cmpxchg [ecx], edx - mov result, eax - } - return result; - } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) - { - ma_uint32 resultEAX = 0; - ma_uint32 resultEDX = 0; - __asm { - mov esi, dst - mov eax, dword ptr expected - mov edx, dword ptr expected + 4 - mov ebx, dword ptr desired - mov ecx, dword ptr desired + 4 - lock cmpxchg8b qword ptr [esi] - mov resultEAX, eax - mov resultEDX, edx - } - return ((ma_uint64)resultEDX << 32) | resultEAX; - } - #endif + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + #define ma_atomic_compare_and_swap_8( dst, expected, replacement) (ma_uint8 )_InterlockedCompareExchange8((volatile char*)dst, (char)replacement, (char)expected) #else - #if defined(MA_ATOMIC_HAS_8) - #define ma_atomic_compare_and_swap_8( dst, expected, desired) (ma_uint8 )_InterlockedCompareExchange8((volatile char*)dst, (char)desired, (char)expected) - #endif - #if defined(MA_ATOMIC_HAS_16) - #define ma_atomic_compare_and_swap_16(dst, expected, desired) (ma_uint16)_InterlockedCompareExchange16((volatile short*)dst, (short)desired, (short)expected) - #endif - #if defined(MA_ATOMIC_HAS_32) - #define ma_atomic_compare_and_swap_32(dst, expected, desired) (ma_uint32)_InterlockedCompareExchange((volatile long*)dst, (long)desired, (long)expected) - #endif - #if defined(MA_ATOMIC_HAS_64) - #define ma_atomic_compare_and_swap_64(dst, expected, desired) (ma_uint64)_InterlockedCompareExchange64((volatile ma_int64*)dst, (ma_int64)desired, (ma_int64)expected) - #endif + static MA_INLINE ma_uint8 __stdcall ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement); + } #endif - #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - ma_uint8 result = 0; - (void)order; - __asm { - mov ecx, dst - mov al, src - lock xchg [ecx], al - mov result, al - } - return result; - } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - ma_uint16 result = 0; - (void)order; - __asm { - mov ecx, dst - mov ax, src - lock xchg [ecx], ax - mov result, ax - } - return result; - } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - ma_uint32 result = 0; - (void)order; - __asm { - mov ecx, dst - mov eax, src - lock xchg [ecx], eax - mov result, eax - } - return result; - } - #endif + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + #define ma_atomic_compare_and_swap_16(dst, expected, replacement) (ma_uint16)_InterlockedCompareExchange16((volatile short*)dst, (short)replacement, (short)expected) #else - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { + static MA_INLINE ma_uint16 __stdcall ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement); + } + #endif + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + #define ma_atomic_compare_and_swap_32(dst, expected, replacement) (ma_uint32)_InterlockedCompareExchange((volatile long*)dst, (long)replacement, (long)expected) + #else + static MA_INLINE ma_uint32 __stdcall ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement); + } + #endif + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + #define ma_atomic_compare_and_swap_64(dst, expected, replacement) (ma_uint64)_InterlockedCompareExchange64((volatile ma_int64*)dst, (ma_int64)replacement, (ma_int64)expected) + #else + static MA_INLINE ma_uint64 __stdcall ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement); + } + #endif + static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange8, ma_uint8, char); + { + MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange8, ma_uint8, char); + } #else + { + (void)order; + return ma_atomic_compare_and_swap_8((volatile ma_uint8*)ptr, 0, 0); + } + #endif + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(8, ptr, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange16, ma_uint16, short); + } + #else + { + (void)order; + return ma_atomic_compare_and_swap_16((volatile ma_uint16*)ptr, 0, 0); + } + #endif + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(16, ptr, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange, ma_uint32, long); + } + #else + { + (void)order; + return ma_atomic_compare_and_swap_32((volatile ma_uint32*)ptr, 0, 0); + } + #endif + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(32, ptr, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange64, ma_uint64, long long); + } + #else + { + (void)order; + return ma_atomic_compare_and_swap_64((volatile ma_uint64*)ptr, 0, 0); + } + #endif + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(64, ptr, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange8, ma_uint8, char); + } + #else + { (void)order; return (ma_uint8)_InterlockedExchange8((volatile char*)dst, (char)src); - #endif } + #endif + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order); + } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { #if defined(MA_ARM) + { MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange16, ma_uint16, short); + } #else + { (void)order; return (ma_uint16)_InterlockedExchange16((volatile short*)dst, (short)src); - #endif } + #endif + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order); + } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { #if defined(MA_ARM) + { MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange, ma_uint32, long); + } #else + { (void)order; return (ma_uint32)_InterlockedExchange((volatile long*)dst, (long)src); - #endif } - #endif - #if defined(MA_ATOMIC_HAS_64) && defined(MA_64BIT) - static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange64, ma_uint64, long long); - #else - (void)order; - return (ma_uint64)_InterlockedExchange64((volatile long long*)dst, (long long)src); #endif - } - #else - #endif - #endif - #if defined(MA_ATOMIC_HAS_64) && !defined(MA_64BIT) - static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - ma_uint64 oldValue; - do { - oldValue = *dst; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, src) != oldValue); - (void)order; - return oldValue; } - #endif - #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - ma_uint8 result = 0; - (void)order; - __asm { - mov ecx, dst - mov al, src - lock xadd [ecx], al - mov result, al - } - return result; - } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order); + } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + #if defined(MA_32BIT) { - ma_uint16 result = 0; - (void)order; - __asm { - mov ecx, dst - mov ax, src - lock xadd [ecx], ax - mov result, ax - } - return result; + MA_ATOMIC_EXCHANGE_EXPLICIT_CAS(64, dst, src, order); } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - ma_uint32 result = 0; - (void)order; - __asm { - mov ecx, dst - mov eax, src - lock xadd [ecx], eax - mov result, eax - } - return result; - } - #endif - #else - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd8, ma_uint8, char); #else + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange64, ma_uint64, long long); + } + #else + { + (void)order; + return (ma_uint64)_InterlockedExchange64((volatile long long*)dst, (long long)src); + } + #endif + } + #endif + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd8, ma_uint8, char); + } + #else + { (void)order; return (ma_uint8)_InterlockedExchangeAdd8((volatile char*)dst, (char)src); - #endif } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, src, order); + } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { #if defined(MA_ARM) + { MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd16, ma_uint16, short); + } #else + { (void)order; return (ma_uint16)_InterlockedExchangeAdd16((volatile short*)dst, (short)src); - #endif } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, src, order); + } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { #if defined(MA_ARM) + { MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd, ma_uint32, long); + } #else + { (void)order; return (ma_uint32)_InterlockedExchangeAdd((volatile long*)dst, (long)src); - #endif } - #endif - #if defined(MA_ATOMIC_HAS_64) && defined(MA_64BIT) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd64, ma_uint64, long long); - #else - (void)order; - return (ma_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src); #endif - } + } #else - #endif - #endif - #if defined(MA_ATOMIC_HAS_64) && !defined(MA_64BIT) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue + src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + #if defined(MA_32BIT) + { + MA_ATOMIC_FETCH_ADD_CAS(64, dst, src, order); + } + #else + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd64, ma_uint64, long long); + } + #else + { + (void)order; + return (ma_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src); + } + #endif + } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_8(dst, (ma_uint8)(-(ma_int8)src), order); + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_16(dst, (ma_uint16)(-(ma_int16)src), order); + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_32(dst, (ma_uint32)(-(ma_int32)src), order); + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_64(dst, (ma_uint64)(-(ma_int64)src), order); + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd8, ma_uint8, char); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd16, ma_uint16, short); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd, ma_uint32, long); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd64, ma_uint64, long long); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr8, ma_uint8, char); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr16, ma_uint16, short); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr, ma_uint32, long); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr64, ma_uint64, long long); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor8, ma_uint8, char); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor16, ma_uint16, short); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor, ma_uint32, long); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor64, ma_uint64, long long); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(64, dst, src, order); + } + #endif + } + #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) + #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) + #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) + #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) + #if defined(MA_X64) + #define ma_atomic_thread_fence(order) __faststorefence(), (void)order + #elif defined(MA_ARM64) + #define ma_atomic_thread_fence(order) __dmb(_ARM64_BARRIER_ISH), (void)order + #else + static MA_INLINE void ma_atomic_thread_fence(ma_atomic_memory_order order) + { + volatile ma_uint32 barrier = 0; + ma_atomic_fetch_add_explicit_32(&barrier, 0, order); } #endif - #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - static MA_INLINE void __stdcall ma_atomic_thread_fence(ma_atomic_memory_order order) + #define ma_atomic_signal_fence(order) _ReadWriteBarrier(), (void)order +#endif +#if defined(MA_ATOMIC_LEGACY_MSVC_ASM) + static MA_INLINE ma_uint8 __stdcall ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) { + ma_uint8 result = 0; + __asm { + mov ecx, dst + mov al, expected + mov dl, replacement + lock cmpxchg [ecx], dl + mov result, al + } + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + ma_uint16 result = 0; + __asm { + mov ecx, dst + mov ax, expected + mov dx, replacement + lock cmpxchg [ecx], dx + mov result, ax + } + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + ma_uint32 result = 0; + __asm { + mov ecx, dst + mov eax, expected + mov edx, replacement + lock cmpxchg [ecx], edx + mov result, eax + } + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + ma_uint32 resultEAX = 0; + ma_uint32 resultEDX = 0; + __asm { + mov esi, dst + mov eax, dword ptr expected + mov edx, dword ptr expected + 4 + mov ebx, dword ptr replacement + mov ecx, dword ptr replacement + 4 + lock cmpxchg8b qword ptr [esi] + mov resultEAX, eax + mov resultEDX, edx + } + return ((ma_uint64)resultEDX << 32) | resultEAX; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + ma_uint8 result = 0; + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov al, [esi] + mov result, al + } + } else if (order <= ma_atomic_memory_order_release) { + __asm { + mov esi, dst + mov al, [esi] + lock add dword ptr [esp], 0 + mov result, al + } + } else { + __asm { + lock add dword ptr [esp], 0 + mov esi, dst + mov al, [esi] + mov result, al + lock add dword ptr [esp], 0 + } + } + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(8, dst, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + ma_uint16 result = 0; + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov ax, [esi] + mov result, ax + } + } else if (order <= ma_atomic_memory_order_release) { + __asm { + mov esi, dst + mov ax, [esi] + lock add dword ptr [esp], 0 + mov result, ax + } + } else { + __asm { + lock add dword ptr [esp], 0 + mov esi, dst + mov ax, [esi] + mov result, ax + lock add dword ptr [esp], 0 + } + } + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(16, dst, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + ma_uint32 result = 0; + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov eax, [esi] + mov result, eax + } + } else if (order <= ma_atomic_memory_order_release) { + __asm { + mov esi, dst + mov eax, [esi] + lock add dword ptr [esp], 0 + mov result, eax + } + } else { + __asm { + lock add dword ptr [esp], 0 + mov esi, dst + mov eax, [esi] + mov result, eax + lock add dword ptr [esp], 0 + } + } + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(32, dst, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* dst, ma_atomic_memory_order order) + { + (void)order; + return ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, 0, 0); + } + static MA_INLINE void __stdcall ma_atomic_store_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov al, src + mov [esi], al + } + } else { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + __asm { + mov esi, dst + mov al, src + xchg [esi], al + } + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(8, dst, src, order); + } + #endif + } + } + static MA_INLINE void __stdcall ma_atomic_store_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov ax, src + mov [esi], ax + } + } else { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + __asm { + mov esi, dst + mov ax, src + xchg [esi], ax + } + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(16, dst, src, order); + } + #endif + } + } + static MA_INLINE void __stdcall ma_atomic_store_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov eax, src + mov [esi], eax + } + } else { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + __asm { + mov esi, dst + mov eax, src + xchg [esi], eax + } + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(32, dst, src, order); + } + #endif + } + } + static MA_INLINE void __stdcall ma_atomic_store_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + MA_ATOMIC_STORE_EXPLICIT_CAS(64, dst, src, order); + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + ma_uint8 result = 0; (void)order; __asm { - lock add [esp], 0 + mov ecx, dst + mov al, src + lock xchg [ecx], al + mov result, al } + return result; } - #else - #if defined(MA_X64) - #define ma_atomic_thread_fence(order) __faststorefence(), (void)order - #elif defined(MA_ARM64) - #define ma_atomic_thread_fence(order) __dmb(_ARM64_BARRIER_ISH), (void)order #else - static MA_INLINE void ma_atomic_thread_fence(ma_atomic_memory_order order) - { - volatile ma_uint32 barrier = 0; - ma_atomic_fetch_add_explicit_32(&barrier, 0, order); + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + ma_uint16 result = 0; + (void)order; + __asm { + mov ecx, dst + mov ax, src + lock xchg [ecx], ax + mov result, ax } - #endif - #endif - #define ma_atomic_compiler_fence() ma_atomic_thread_fence(ma_atomic_memory_order_seq_cst) - #define ma_atomic_signal_fence(order) ma_atomic_thread_fence(order) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange8, ma_uint8, char); + return result; + } #else - (void)order; - return ma_atomic_compare_and_swap_8((volatile ma_uint8*)ptr, 0, 0); - #endif - } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange16, ma_uint16, short); + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + ma_uint32 result = 0; + (void)order; + __asm { + mov ecx, dst + mov eax, src + xchg [ecx], eax + mov result, eax + } + return result; + } #else - (void)order; - return ma_atomic_compare_and_swap_16((volatile ma_uint16*)ptr, 0, 0); - #endif - } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange, ma_uint32, long); + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + MA_ATOMIC_EXCHANGE_EXPLICIT_CAS(64, dst, src, order); + } #else - (void)order; - return ma_atomic_compare_and_swap_32((volatile ma_uint32*)ptr, 0, 0); - #endif - } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange64, ma_uint64, long long); + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + ma_uint8 result = 0; + (void)order; + __asm { + mov ecx, dst + mov al, src + lock xadd [ecx], al + mov result, al + } + return result; + } #else - (void)order; - return ma_atomic_compare_and_swap_64((volatile ma_uint64*)ptr, 0, 0); + { + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, src, order); + } #endif - } - #endif - #if defined(MA_ATOMIC_HAS_8) - #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) - #endif - #if defined(MA_ATOMIC_HAS_16) - #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) - #endif - #if defined(MA_ATOMIC_HAS_32) - #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) - #endif - #if defined(MA_ATOMIC_HAS_64) - #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) - #endif - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) { - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue - src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + ma_uint16 result = 0; (void)order; - return oldValue; + __asm { + mov ecx, dst + mov ax, src + lock xadd [ecx], ax + mov result, ax + } + return result; } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue - src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue - src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue - src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - #endif - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd8, ma_uint8, char); #else - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue & src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif - } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd16, ma_uint16, short); - #else - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue & src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, src, order); } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd, ma_uint32, long); - #else - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue & src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + ma_uint32 result = 0; (void)order; - return oldValue; - #endif + __asm { + mov ecx, dst + mov eax, src + lock xadd [ecx], eax + mov result, eax + } + return result; } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #else { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd64, ma_uint64, long long); - #else - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue & src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, src, order); } - #endif - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor8, ma_uint8, char); - #else - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue ^ src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_CAS(64, dst, src, order); } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + #else { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor16, ma_uint16, short); - #else - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue ^ src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(64, dst, src, order); } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor, ma_uint32, long); - #else - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue ^ src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + ma_uint8 result = 0; (void)order; - return oldValue; - #endif + __asm { + mov ecx, dst + mov al, src + neg al + lock xadd [ecx], al + mov result, al + } + return result; } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #else { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor64, ma_uint64, long long); - #else - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue ^ src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, (ma_uint8)(-(ma_int8)src), order); } - #endif - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr8, ma_uint8, char); - #else - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue | src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + ma_uint16 result = 0; (void)order; - return oldValue; - #endif + __asm { + mov ecx, dst + mov ax, src + neg ax + lock xadd [ecx], ax + mov result, ax + } + return result; } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + #else { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr16, ma_uint16, short); - #else - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue | src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, (ma_uint16)(-(ma_int16)src), order); } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr, ma_uint32, long); - #else - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue | src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + ma_uint32 result = 0; (void)order; - return oldValue; - #endif + __asm { + mov ecx, dst + mov eax, src + neg eax + lock xadd [ecx], eax + mov result, eax + } + return result; } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #else { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr64, ma_uint64, long long); - #else - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue | src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, (ma_uint32)(-(ma_int32)src), order); } - #endif - #if defined(MA_ATOMIC_HAS_8) - #define ma_atomic_test_and_set_explicit_8( dst, order) ma_atomic_exchange_explicit_8 (dst, 1, order) - #endif - #if defined(MA_ATOMIC_HAS_16) - #define ma_atomic_test_and_set_explicit_16(dst, order) ma_atomic_exchange_explicit_16(dst, 1, order) - #endif - #if defined(MA_ATOMIC_HAS_32) - #define ma_atomic_test_and_set_explicit_32(dst, order) ma_atomic_exchange_explicit_32(dst, 1, order) - #endif - #if defined(MA_ATOMIC_HAS_64) - #define ma_atomic_test_and_set_explicit_64(dst, order) ma_atomic_exchange_explicit_64(dst, 1, order) - #endif - #if defined(MA_ATOMIC_HAS_8) - #define ma_atomic_clear_explicit_8( dst, order) ma_atomic_store_explicit_8 (dst, 0, order) - #endif - #if defined(MA_ATOMIC_HAS_16) - #define ma_atomic_clear_explicit_16(dst, order) ma_atomic_store_explicit_16(dst, 0, order) - #endif - #if defined(MA_ATOMIC_HAS_32) - #define ma_atomic_clear_explicit_32(dst, order) ma_atomic_store_explicit_32(dst, 0, order) - #endif - #if defined(MA_ATOMIC_HAS_64) - #define ma_atomic_clear_explicit_64(dst, order) ma_atomic_store_explicit_64(dst, 0, order) - #endif - #if defined(MA_ATOMIC_HAS_8) - typedef ma_uint8 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_8(ptr, order) - #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_8(ptr, order) - #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) - #else - typedef ma_uint32 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_32(ptr, order) - #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_32(ptr, order) - #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_32(ptr, order) - #endif -#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_ADD_CAS(64, dst, (ma_uint64)(-(ma_int64)src), order); + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(64, dst, src, order); + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(64, dst, src, order); + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(64, dst, src, order); + } + static MA_INLINE void __stdcall ma_atomic_thread_fence(ma_atomic_memory_order order) + { + (void)order; + __asm { + lock add dword ptr [esp], 0 + } + } + #define ma_atomic_signal_fence(order) __asm {}; (void)order +#endif +#if defined(MA_ATOMIC_MODERN_GCC) #define MA_ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE - #define MA_ATOMIC_HAS_NATIVE_IS_LOCK_FREE - #define ma_atomic_memory_order_relaxed __ATOMIC_RELAXED - #define ma_atomic_memory_order_consume __ATOMIC_CONSUME - #define ma_atomic_memory_order_acquire __ATOMIC_ACQUIRE - #define ma_atomic_memory_order_release __ATOMIC_RELEASE - #define ma_atomic_memory_order_acq_rel __ATOMIC_ACQ_REL - #define ma_atomic_memory_order_seq_cst __ATOMIC_SEQ_CST - #define ma_atomic_compiler_fence() __asm__ __volatile__("":::"memory") #define ma_atomic_thread_fence(order) __atomic_thread_fence(order) #define ma_atomic_signal_fence(order) __atomic_signal_fence(order) #define ma_atomic_is_lock_free_8(ptr) __atomic_is_lock_free(1, ptr) #define ma_atomic_is_lock_free_16(ptr) __atomic_is_lock_free(2, ptr) #define ma_atomic_is_lock_free_32(ptr) __atomic_is_lock_free(4, ptr) #define ma_atomic_is_lock_free_64(ptr) __atomic_is_lock_free(8, ptr) - #define ma_atomic_test_and_set_explicit_8( dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_test_and_set_explicit_16(dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_test_and_set_explicit_32(dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_test_and_set_explicit_64(dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_clear_explicit_8( dst, order) __atomic_store_n(dst, 0, order) - #define ma_atomic_clear_explicit_16(dst, order) __atomic_store_n(dst, 0, order) - #define ma_atomic_clear_explicit_32(dst, order) __atomic_store_n(dst, 0, order) - #define ma_atomic_clear_explicit_64(dst, order) __atomic_store_n(dst, 0, order) #define ma_atomic_store_explicit_8( dst, src, order) __atomic_store_n(dst, src, order) #define ma_atomic_store_explicit_16(dst, src, order) __atomic_store_n(dst, src, order) #define ma_atomic_store_explicit_32(dst, src, order) __atomic_store_n(dst, src, order) @@ -14864,14 +15810,14 @@ typedef int ma_atomic_memory_order; #define ma_atomic_exchange_explicit_16(dst, src, order) __atomic_exchange_n(dst, src, order) #define ma_atomic_exchange_explicit_32(dst, src, order) __atomic_exchange_n(dst, src, order) #define ma_atomic_exchange_explicit_64(dst, src, order) __atomic_exchange_n(dst, src, order) - #define ma_atomic_compare_exchange_strong_explicit_8( dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) + #define ma_atomic_compare_exchange_strong_explicit_8( dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder) + #define ma_atomic_compare_exchange_strong_explicit_16(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder) + #define ma_atomic_compare_exchange_strong_explicit_32(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder) + #define ma_atomic_compare_exchange_strong_explicit_64(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder) #define ma_atomic_fetch_add_explicit_8( dst, src, order) __atomic_fetch_add(dst, src, order) #define ma_atomic_fetch_add_explicit_16(dst, src, order) __atomic_fetch_add(dst, src, order) #define ma_atomic_fetch_add_explicit_32(dst, src, order) __atomic_fetch_add(dst, src, order) @@ -14892,19 +15838,19 @@ typedef int ma_atomic_memory_order; #define ma_atomic_fetch_and_explicit_16(dst, src, order) __atomic_fetch_and(dst, src, order) #define ma_atomic_fetch_and_explicit_32(dst, src, order) __atomic_fetch_and(dst, src, order) #define ma_atomic_fetch_and_explicit_64(dst, src, order) __atomic_fetch_and(dst, src, order) - static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 desired) + static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) { - __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } - static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 desired) + static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) { - __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } - static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 desired) + static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) { - __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } #if defined(__clang__) @@ -14913,636 +15859,1134 @@ typedef int ma_atomic_memory_order; #pragma clang diagnostic ignored "-Watomic-alignment" #endif #endif - static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) + static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) { - __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } #if defined(__clang__) #pragma clang diagnostic pop #endif - typedef ma_uint8 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(dst, order) (ma_bool32)__atomic_test_and_set(dst, order) - #define ma_atomic_flag_clear_explicit(dst, order) __atomic_clear(dst, order) - #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) -#else - #define ma_atomic_memory_order_relaxed 1 - #define ma_atomic_memory_order_consume 2 - #define ma_atomic_memory_order_acquire 3 - #define ma_atomic_memory_order_release 4 - #define ma_atomic_memory_order_acq_rel 5 - #define ma_atomic_memory_order_seq_cst 6 - #define ma_atomic_compiler_fence() __asm__ __volatile__("":::"memory") - #if defined(__GNUC__) +#endif +#if defined(MA_ATOMIC_LEGACY_GCC) || defined(MA_ATOMIC_LEGACY_GCC_ASM) + #define ma_atomic_signal_fence(order) __asm__ __volatile__("":::"memory") + #if defined(MA_ATOMIC_LEGACY_GCC) #define ma_atomic_thread_fence(order) __sync_synchronize(), (void)order - static MA_INLINE ma_uint8 ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) { - if (order > ma_atomic_memory_order_acquire) { - __sync_synchronize(); + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + return __sync_val_compare_and_swap(dst, expected, replacement); } - return __sync_lock_test_and_set(dst, src); + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement); + } + #endif } - static MA_INLINE ma_uint16 ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) { - ma_uint16 oldValue; - do { - oldValue = *dst; - } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + return __sync_val_compare_and_swap(dst, expected, replacement); + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement); + } + #endif } - static MA_INLINE ma_uint32 ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) { - ma_uint32 oldValue; - do { - oldValue = *dst; - } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + return __sync_val_compare_and_swap(dst, expected, replacement); + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement); + } + #endif } - static MA_INLINE ma_uint64 ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) { - ma_uint64 oldValue; - do { - oldValue = *dst; - } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + return __sync_val_compare_and_swap(dst, expected, replacement); + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement); + } + #endif } - static MA_INLINE ma_uint8 ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) { - (void)order; - return __sync_fetch_and_add(dst, src); + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return ma_atomic_compare_and_swap_8((ma_uint8*)ptr, 0, 0); + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(8, ptr, order); + } + #endif } - static MA_INLINE ma_uint16 ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) { - (void)order; - return __sync_fetch_and_add(dst, src); + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return ma_atomic_compare_and_swap_16((ma_uint16*)ptr, 0, 0); + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(16, ptr, order); + } + #endif } - static MA_INLINE ma_uint32 ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) { - (void)order; - return __sync_fetch_and_add(dst, src); + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return ma_atomic_compare_and_swap_32((ma_uint32*)ptr, 0, 0); + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(32, ptr, order); + } + #endif } - static MA_INLINE ma_uint64 ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) { - (void)order; - return __sync_fetch_and_add(dst, src); - } - static MA_INLINE ma_uint8 ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_sub(dst, src); - } - static MA_INLINE ma_uint16 ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_sub(dst, src); - } - static MA_INLINE ma_uint32 ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_sub(dst, src); - } - static MA_INLINE ma_uint64 ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_sub(dst, src); - } - static MA_INLINE ma_uint8 ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_or(dst, src); - } - static MA_INLINE ma_uint16 ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_or(dst, src); - } - static MA_INLINE ma_uint32 ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_or(dst, src); - } - static MA_INLINE ma_uint64 ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_or(dst, src); - } - static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_xor(dst, src); - } - static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_xor(dst, src); - } - static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_xor(dst, src); - } - static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_xor(dst, src); - } - static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_and(dst, src); - } - static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_and(dst, src); - } - static MA_INLINE ma_uint32 ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_and(dst, src); - } - static MA_INLINE ma_uint64 ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_and(dst, src); - } - #define ma_atomic_compare_and_swap_8( dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) - #define ma_atomic_compare_and_swap_16(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) - #define ma_atomic_compare_and_swap_32(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) - #define ma_atomic_compare_and_swap_64(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) - #else - #if defined(MA_X86) - #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory", "cc") - #elif defined(MA_X64) - #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addq $0, (%%rsp)" ::: "memory", "cc") - #else - #error Unsupported architecture. Please submit a feature request. - #endif - static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 desired) - { - ma_uint8 result; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; - } - static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 desired) - { - ma_uint16 result; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; - } - static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 desired) - { - ma_uint32 result; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; - } - static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) - { - volatile ma_uint64 result; - #if defined(MA_X86) - ma_uint32 resultEAX; - ma_uint32 resultEDX; - __asm__ __volatile__("push %%ebx; xchg %5, %%ebx; lock; cmpxchg8b %0; pop %%ebx" : "+m"(*dst), "=a"(resultEAX), "=d"(resultEDX) : "a"(expected & 0xFFFFFFFF), "d"(expected >> 32), "r"(desired & 0xFFFFFFFF), "c"(desired >> 32) : "cc"); - result = ((ma_uint64)resultEDX << 32) | resultEAX; - #elif defined(MA_X64) - __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return ma_atomic_compare_and_swap_64((ma_uint64*)ptr, 0, 0); + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(64, ptr, order); + } + #endif } static MA_INLINE ma_uint8 ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - ma_uint8 result = 0; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + if (order > ma_atomic_memory_order_acquire) { + __sync_synchronize(); + } + return __sync_lock_test_and_set(dst, src); + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order); + } + #endif } static MA_INLINE ma_uint16 ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - ma_uint16 result = 0; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + if (order > ma_atomic_memory_order_acquire) { + __sync_synchronize(); + } + return __sync_lock_test_and_set(dst, src); + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order); + } + #endif } static MA_INLINE ma_uint32 ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - ma_uint32 result; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + if (order > ma_atomic_memory_order_acquire) { + __sync_synchronize(); + } + return __sync_lock_test_and_set(dst, src); + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order); + } + #endif } static MA_INLINE ma_uint64 ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - ma_uint64 result; - (void)order; - #if defined(MA_X86) - do { - result = *dst; - } while (ma_atomic_compare_and_swap_64(dst, result, src) != result); - #elif defined(MA_X64) - __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + if (order > ma_atomic_memory_order_acquire) { + __sync_synchronize(); + } + return __sync_lock_test_and_set(dst, src); + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif } + #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) + #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) + #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) + #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) static MA_INLINE ma_uint8 ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - ma_uint8 result; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return __sync_fetch_and_add(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, src, order); + } + #endif } static MA_INLINE ma_uint16 ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - ma_uint16 result; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return __sync_fetch_and_add(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, src, order); + } + #endif } static MA_INLINE ma_uint32 ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - ma_uint32 result; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return __sync_fetch_and_add(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, src, order); + } + #endif } static MA_INLINE ma_uint64 ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - #if defined(MA_X86) - ma_uint64 oldValue; - ma_uint64 newValue; - (void)order; - do { - oldValue = *dst; - newValue = oldValue + src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - return oldValue; - #elif defined(MA_X64) - ma_uint64 result; - (void)order; - __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); - return result; - #endif + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return __sync_fetch_and_add(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(64, dst, src, order); + } + #endif } static MA_INLINE ma_uint8 ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue - src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return __sync_fetch_and_sub(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, (ma_uint8)(-(ma_int8)src), order); + } + #endif } static MA_INLINE ma_uint16 ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue - src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return __sync_fetch_and_sub(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, (ma_uint16)(-(ma_int16)src), order); + } + #endif } static MA_INLINE ma_uint32 ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue - src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return __sync_fetch_and_sub(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, (ma_uint32)(-(ma_int32)src), order); + } + #endif } static MA_INLINE ma_uint64 ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue - src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return __sync_fetch_and_sub(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(64, dst, (ma_uint64)(-(ma_int64)src), order); + } + #endif } static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue & src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return __sync_fetch_and_and(dst, src); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(8, dst, src, order); + } + #endif } static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue & src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return __sync_fetch_and_and(dst, src); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(16, dst, src, order); + } + #endif } static MA_INLINE ma_uint32 ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue & src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return __sync_fetch_and_and(dst, src); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(32, dst, src, order); + } + #endif } static MA_INLINE ma_uint64 ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue & src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue ^ src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue ^ src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue ^ src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue ^ src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return __sync_fetch_and_and(dst, src); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(64, dst, src, order); + } + #endif } static MA_INLINE ma_uint8 ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue | src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return __sync_fetch_and_or(dst, src); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(8, dst, src, order); + } + #endif } static MA_INLINE ma_uint16 ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue | src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return __sync_fetch_and_or(dst, src); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(16, dst, src, order); + } + #endif } static MA_INLINE ma_uint32 ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue | src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return __sync_fetch_and_or(dst, src); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(32, dst, src, order); + } + #endif } static MA_INLINE ma_uint64 ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue | src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return __sync_fetch_and_or(dst, src); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(64, dst, src, order); + } + #endif } + static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return __sync_fetch_and_xor(dst, src); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return __sync_fetch_and_xor(dst, src); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return __sync_fetch_and_xor(dst, src); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return __sync_fetch_and_xor(dst, src); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(64, dst, src, order); + } + #endif + } + #elif defined(MA_ATOMIC_LEGACY_GCC_ASM) + #define MA_ATOMIC_CMPXCHG_GCC_X86(instructionSizeSuffix, result, dst, expected, replacement) \ + __asm__ __volatile__( \ + "lock; cmpxchg"instructionSizeSuffix" %2, %1" \ + : "=a"(result), \ + "=m"(*dst) \ + : "r"(replacement), \ + "0"(expected), \ + "m"(*dst) \ + : "cc", "memory") + #define MA_ATOMIC_XADD_GCC_X86(instructionSizeSuffix, result, dst, src) \ + __asm__ __volatile__( \ + "lock; xadd"instructionSizeSuffix" %0, %1" \ + : "=a"(result), \ + "=m"(*dst) \ + : "0"(src), \ + "m"(*dst) \ + : "cc", "memory") + static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint8 result; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_CMPXCHG_GCC_X86("b", result, dst, expected, replacement); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint16 result; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_CMPXCHG_GCC_X86("w", result, dst, expected, replacement); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint32 result; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_CMPXCHG_GCC_X86("l", result, dst, expected, replacement); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint64 result; + #if defined(MA_X86) + { + ma_uint32 resultEAX; + ma_uint32 resultEDX; + __asm__ __volatile__( + "pushl %%ebx\n" + "movl %4, %%ebx\n" + "lock cmpxchg8b (%%edi)\n" + "popl %%ebx\n" + : "=a"(resultEAX), + "=d"(resultEDX) + : "a"((ma_uint32)(expected & 0xFFFFFFFF)), + "d"((ma_uint32)(expected >> 32)), + "r"((ma_uint32)(replacement & 0xFFFFFFFF)), + "c"((ma_uint32)(replacement >> 32)), + "D"(dst) + : "memory", "cc"); + result = ((ma_uint64)resultEDX << 32) | resultEAX; + } + #elif defined(MA_X64) + { + MA_ATOMIC_CMPXCHG_GCC_X86("q", result, dst, expected, replacement); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint8 result; + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + MA_ATOMIC_LOAD_RELAXED_GCC_X86("b", result, dst); + } else if (order <= ma_atomic_memory_order_release) { + MA_ATOMIC_LOAD_RELEASE_GCC_X86("b", result, dst); + } else { + MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("b", result, dst); + } + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(8, dst, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint16 result; + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + MA_ATOMIC_LOAD_RELAXED_GCC_X86("w", result, dst); + } else if (order <= ma_atomic_memory_order_release) { + MA_ATOMIC_LOAD_RELEASE_GCC_X86("w", result, dst); + } else { + MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("w", result, dst); + } + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(16, dst, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint32 result; + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + MA_ATOMIC_LOAD_RELAXED_GCC_X86("l", result, dst); + } else if (order <= ma_atomic_memory_order_release) { + MA_ATOMIC_LOAD_RELEASE_GCC_X86("l", result, dst); + } else { + MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("l", result, dst); + } + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(32, dst, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint64 result; + #if defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + MA_ATOMIC_LOAD_RELAXED_GCC_X86("q", result, dst); + } else if (order <= ma_atomic_memory_order_release) { + MA_ATOMIC_LOAD_RELEASE_GCC_X86("q", result, dst); + } else { + MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("q", result, dst); + } + } + #elif defined(MA_X86) + { + (void)order; + return ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, 0, 0); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(64, dst, order); + } + #endif + } + static MA_INLINE ma_uint8 ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint8 result; + (void)order; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_XCHG_GCC_X86("b", result, dst, src); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint16 result; + (void)order; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_XCHG_GCC_X86("w", result, dst, src); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint32 result; + (void)order; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_XCHG_GCC_X86("l", result, dst, src); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint64 result; + (void)order; + #if defined(MA_X86) + { + MA_ATOMIC_EXCHANGE_EXPLICIT_CAS(64, dst, src, order); + } + #elif defined(MA_X64) + { + MA_ATOMIC_XCHG_GCC_X86("q", result, dst, src); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE void ma_atomic_store_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm__ __volatile__ ( + "movb %1, %0" + : "=m"(*dst) + : "r"(src) + ); + } else { + __asm__ __volatile__ ( + "xchgb %1, %0" + : "=m"(*dst) + : "r"(src) + : "memory" + ); + } + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(8, dst, src, order); + } + #endif + } + static MA_INLINE void ma_atomic_store_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm__ __volatile__ ( + "movw %1, %0" + : "=m"(*dst) + : "r"(src) + ); + } else { + __asm__ __volatile__ ( + "xchgw %1, %0" + : "=m"(*dst) + : "r"(src) + : "memory" + ); + } + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(16, dst, src, order); + } + #endif + } + static MA_INLINE void ma_atomic_store_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm__ __volatile__ ( + "movl %1, %0" + : "=m"(*dst) + : "r"(src) + ); + } else { + __asm__ __volatile__ ( + "xchgl %1, %0" + : "=m"(*dst) + : "r"(src) + : "memory" + ); + } + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(32, dst, src, order); + } + #endif + } + static MA_INLINE void ma_atomic_store_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm__ __volatile__ ( + "movq %1, %0" + : "=m"(*dst) + : "r"(src) + ); + } else { + __asm__ __volatile__ ( + "xchgq %1, %0" + : "=m"(*dst) + : "r"(src) + : "memory" + ); + } + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_CAS(64, dst, src, order); + } + #endif + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + ma_uint8 result; + (void)order; + MA_ATOMIC_XADD_GCC_X86("b", result, dst, src); + return result; + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + ma_uint16 result; + (void)order; + MA_ATOMIC_XADD_GCC_X86("w", result, dst, src); + return result; + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + ma_uint32 result; + (void)order; + MA_ATOMIC_XADD_GCC_X86("l", result, dst, src); + return result; + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) + { + MA_ATOMIC_FETCH_ADD_CAS(64, dst, src, order); + } + #elif defined(MA_X64) + { + ma_uint64 result; + MA_ATOMIC_XADD_GCC_X86("q", result, dst, src); + (void)order; + return result; + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_8(dst, (ma_uint8)(-(ma_int8)src), order); + } + static MA_INLINE ma_uint16 ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_16(dst, (ma_uint16)(-(ma_int16)src), order); + } + static MA_INLINE ma_uint32 ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_32(dst, (ma_uint32)(-(ma_int32)src), order); + } + static MA_INLINE ma_uint64 ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_64(dst, (ma_uint64)(-(ma_int64)src), order); + } + static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(64, dst, src, order); + } + static MA_INLINE ma_uint8 ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(64, dst, src, order); + } + static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(64, dst, src, order); + } + #else + #error Unsupported compiler. #endif - #define ma_atomic_signal_fence(order) ma_atomic_thread_fence(order) - static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) - { - (void)order; - return ma_atomic_compare_and_swap_8((ma_uint8*)ptr, 0, 0); - } - static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) - { - (void)order; - return ma_atomic_compare_and_swap_16((ma_uint16*)ptr, 0, 0); - } - static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) - { - (void)order; - return ma_atomic_compare_and_swap_32((ma_uint32*)ptr, 0, 0); - } - static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) - { - (void)order; - return ma_atomic_compare_and_swap_64((ma_uint64*)ptr, 0, 0); - } - #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) - #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) - #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) - #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) - #define ma_atomic_test_and_set_explicit_8( dst, order) ma_atomic_exchange_explicit_8 (dst, 1, order) - #define ma_atomic_test_and_set_explicit_16(dst, order) ma_atomic_exchange_explicit_16(dst, 1, order) - #define ma_atomic_test_and_set_explicit_32(dst, order) ma_atomic_exchange_explicit_32(dst, 1, order) - #define ma_atomic_test_and_set_explicit_64(dst, order) ma_atomic_exchange_explicit_64(dst, 1, order) - #define ma_atomic_clear_explicit_8( dst, order) ma_atomic_store_explicit_8 (dst, 0, order) - #define ma_atomic_clear_explicit_16(dst, order) ma_atomic_store_explicit_16(dst, 0, order) - #define ma_atomic_clear_explicit_32(dst, order) ma_atomic_store_explicit_32(dst, 0, order) - #define ma_atomic_clear_explicit_64(dst, order) ma_atomic_store_explicit_64(dst, 0, order) - typedef ma_uint8 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_8(ptr, order) - #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_8(ptr, order) - #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) #endif #if !defined(MA_ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_8(volatile ma_uint8* dst, ma_uint8* expected, ma_uint8 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) - { - ma_uint8 expectedValue; - ma_uint8 result; - (void)successOrder; - (void)failureOrder; - expectedValue = ma_atomic_load_explicit_8(expected, ma_atomic_memory_order_seq_cst); - result = ma_atomic_compare_and_swap_8(dst, expectedValue, desired); - if (result == expectedValue) { - return 1; - } else { - ma_atomic_store_explicit_8(expected, result, failureOrder); - return 0; - } - } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_16(volatile ma_uint16* dst, ma_uint16* expected, ma_uint16 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) - { - ma_uint16 expectedValue; - ma_uint16 result; - (void)successOrder; - (void)failureOrder; - expectedValue = ma_atomic_load_explicit_16(expected, ma_atomic_memory_order_seq_cst); - result = ma_atomic_compare_and_swap_16(dst, expectedValue, desired); - if (result == expectedValue) { - return 1; - } else { - ma_atomic_store_explicit_16(expected, result, failureOrder); - return 0; - } - } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_32(volatile ma_uint32* dst, ma_uint32* expected, ma_uint32 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) - { - ma_uint32 expectedValue; - ma_uint32 result; - (void)successOrder; - (void)failureOrder; - expectedValue = ma_atomic_load_explicit_32(expected, ma_atomic_memory_order_seq_cst); - result = ma_atomic_compare_and_swap_32(dst, expectedValue, desired); - if (result == expectedValue) { - return 1; - } else { - ma_atomic_store_explicit_32(expected, result, failureOrder); - return 0; - } - } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_64(volatile ma_uint64* dst, volatile ma_uint64* expected, ma_uint64 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) - { - ma_uint64 expectedValue; - ma_uint64 result; - (void)successOrder; - (void)failureOrder; - expectedValue = ma_atomic_load_explicit_64(expected, ma_atomic_memory_order_seq_cst); - result = ma_atomic_compare_and_swap_64(dst, expectedValue, desired); - if (result == expectedValue) { - return 1; - } else { - ma_atomic_store_explicit_64(expected, result, failureOrder); - return 0; - } - } - #endif - #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8 (dst, expected, desired, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder) -#endif -#if !defined(MA_ATOMIC_HAS_NATIVE_IS_LOCK_FREE) - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_8(volatile void* ptr) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_8(volatile ma_uint8* dst, ma_uint8* expected, ma_uint8 replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - (void)ptr; - return 1; - } - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_16(volatile void* ptr) - { - (void)ptr; - return 1; - } - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_32(volatile void* ptr) - { - (void)ptr; - return 1; - } - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_64(volatile void* ptr) - { - (void)ptr; - #if defined(MA_64BIT) - return 1; - #else - #if defined(MA_X86) || defined(MA_X64) + ma_uint8 result; + (void)successOrder; + (void)failureOrder; + result = ma_atomic_compare_and_swap_8(dst, *expected, replacement); + if (result == *expected) { return 1; - #else + } else { + *expected = result; return 0; - #endif - #endif + } } + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_16(volatile ma_uint16* dst, ma_uint16* expected, ma_uint16 replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + { + ma_uint16 result; + (void)successOrder; + (void)failureOrder; + result = ma_atomic_compare_and_swap_16(dst, *expected, replacement); + if (result == *expected) { + return 1; + } else { + *expected = result; + return 0; + } + } + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_32(volatile ma_uint32* dst, ma_uint32* expected, ma_uint32 replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + { + ma_uint32 result; + (void)successOrder; + (void)failureOrder; + result = ma_atomic_compare_and_swap_32(dst, *expected, replacement); + if (result == *expected) { + return 1; + } else { + *expected = result; + return 0; + } + } + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_64(volatile ma_uint64* dst, volatile ma_uint64* expected, ma_uint64 replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + { + ma_uint64 result; + (void)successOrder; + (void)failureOrder; + result = ma_atomic_compare_and_swap_64(dst, *expected, replacement); + if (result == *expected) { + return 1; + } else { + *expected = result; + return 0; + } + } + #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8 (dst, expected, replacement, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, replacement, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, replacement, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, replacement, successOrder, failureOrder) #endif #if defined(MA_64BIT) static MA_INLINE ma_bool32 ma_atomic_is_lock_free_ptr(volatile void** ptr) @@ -15561,17 +17005,17 @@ typedef int ma_atomic_memory_order; { return (void*)ma_atomic_exchange_explicit_64((volatile ma_uint64*)dst, (ma_uint64)src, order); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_strong_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder); + return ma_atomic_compare_exchange_strong_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)replacement, successOrder, failureOrder); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_weak_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder); + return ma_atomic_compare_exchange_weak_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)replacement, successOrder, failureOrder); } - static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired) + static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* replacement) { - return (void*)ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, (ma_uint64)expected, (ma_uint64)desired); + return (void*)ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, (ma_uint64)expected, (ma_uint64)replacement); } #elif defined(MA_32BIT) static MA_INLINE ma_bool32 ma_atomic_is_lock_free_ptr(volatile void** ptr) @@ -15590,36 +17034,26 @@ typedef int ma_atomic_memory_order; { return (void*)ma_atomic_exchange_explicit_32((volatile ma_uint32*)dst, (ma_uint32)src, order); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_strong_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder); + return ma_atomic_compare_exchange_strong_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)replacement, successOrder, failureOrder); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_weak_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder); + return ma_atomic_compare_exchange_weak_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)replacement, successOrder, failureOrder); } - static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired) + static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* replacement) { - return (void*)ma_atomic_compare_and_swap_32((volatile ma_uint32*)dst, (ma_uint32)expected, (ma_uint32)desired); + return (void*)ma_atomic_compare_and_swap_32((volatile ma_uint32*)dst, (ma_uint32)expected, (ma_uint32)replacement); } #else #error Unsupported architecture. #endif -#define ma_atomic_flag_test_and_set(ptr) ma_atomic_flag_test_and_set_explicit(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_flag_clear(ptr) ma_atomic_flag_clear_explicit(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_store_ptr(dst, src) ma_atomic_store_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_load_ptr(ptr) ma_atomic_load_explicit_ptr((volatile void**)ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_exchange_ptr(dst, src) ma_atomic_exchange_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_ptr(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_ptr((volatile void**)dst, (void**)expected, (void*)desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_ptr(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_ptr((volatile void**)dst, (void**)expected, (void*)desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_8( ptr) ma_atomic_test_and_set_explicit_8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_16(ptr) ma_atomic_test_and_set_explicit_16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_32(ptr) ma_atomic_test_and_set_explicit_32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_64(ptr) ma_atomic_test_and_set_explicit_64(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_8( ptr) ma_atomic_clear_explicit_8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_16(ptr) ma_atomic_clear_explicit_16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_32(ptr) ma_atomic_clear_explicit_32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_64(ptr) ma_atomic_clear_explicit_64(ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_store_ptr(dst, src) ma_atomic_store_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) +#define ma_atomic_load_ptr(ptr) ma_atomic_load_explicit_ptr((volatile void**)ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_exchange_ptr(dst, src) ma_atomic_exchange_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_ptr(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_ptr((volatile void**)dst, (void**)expected, (void*)replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_ptr(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_ptr((volatile void**)dst, (void**)expected, (void*)replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_8( dst, src) ma_atomic_store_explicit_8( dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_16(dst, src) ma_atomic_store_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_32(dst, src) ma_atomic_store_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) @@ -15632,14 +17066,14 @@ typedef int ma_atomic_memory_order; #define ma_atomic_exchange_16(dst, src) ma_atomic_exchange_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_32(dst, src) ma_atomic_exchange_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_64(dst, src) ma_atomic_exchange_explicit_64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_8( dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_16(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_32(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_64(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_8( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_16( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_32( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_64( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_8( dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_8( dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_16(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_32(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_64(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_8( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_8( dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_16( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_16(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_32( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_64( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_8( dst, src) ma_atomic_fetch_add_explicit_8( dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_16(dst, src) ma_atomic_fetch_add_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_32(dst, src) ma_atomic_fetch_add_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) @@ -15660,14 +17094,6 @@ typedef int ma_atomic_memory_order; #define ma_atomic_fetch_and_16(dst, src) ma_atomic_fetch_and_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_and_32(dst, src) ma_atomic_fetch_and_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_and_64(dst, src) ma_atomic_fetch_and_explicit_64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_explicit_i8( ptr, order) (ma_int8 )ma_atomic_test_and_set_explicit_8( (ma_uint8* )ptr, order) -#define ma_atomic_test_and_set_explicit_i16(ptr, order) (ma_int16)ma_atomic_test_and_set_explicit_16((ma_uint16*)ptr, order) -#define ma_atomic_test_and_set_explicit_i32(ptr, order) (ma_int32)ma_atomic_test_and_set_explicit_32((ma_uint32*)ptr, order) -#define ma_atomic_test_and_set_explicit_i64(ptr, order) (ma_int64)ma_atomic_test_and_set_explicit_64((ma_uint64*)ptr, order) -#define ma_atomic_clear_explicit_i8( ptr, order) ma_atomic_clear_explicit_8( (ma_uint8* )ptr, order) -#define ma_atomic_clear_explicit_i16(ptr, order) ma_atomic_clear_explicit_16((ma_uint16*)ptr, order) -#define ma_atomic_clear_explicit_i32(ptr, order) ma_atomic_clear_explicit_32((ma_uint32*)ptr, order) -#define ma_atomic_clear_explicit_i64(ptr, order) ma_atomic_clear_explicit_64((ma_uint64*)ptr, order) #define ma_atomic_store_explicit_i8( dst, src, order) ma_atomic_store_explicit_8( (ma_uint8* )dst, (ma_uint8 )src, order) #define ma_atomic_store_explicit_i16(dst, src, order) ma_atomic_store_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) #define ma_atomic_store_explicit_i32(dst, src, order) ma_atomic_store_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) @@ -15680,14 +17106,14 @@ typedef int ma_atomic_memory_order; #define ma_atomic_exchange_explicit_i16(dst, src, order) (ma_int16)ma_atomic_exchange_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) #define ma_atomic_exchange_explicit_i32(dst, src, order) (ma_int32)ma_atomic_exchange_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) #define ma_atomic_exchange_explicit_i64(dst, src, order) (ma_int64)ma_atomic_exchange_explicit_64((ma_uint64*)dst, (ma_uint64)src, order) -#define ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder) +#define ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)replacement, successOrder, failureOrder) #define ma_atomic_fetch_add_explicit_i8( dst, src, order) (ma_int8 )ma_atomic_fetch_add_explicit_8( (ma_uint8* )dst, (ma_uint8 )src, order) #define ma_atomic_fetch_add_explicit_i16(dst, src, order) (ma_int16)ma_atomic_fetch_add_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) #define ma_atomic_fetch_add_explicit_i32(dst, src, order) (ma_int32)ma_atomic_fetch_add_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) @@ -15708,14 +17134,6 @@ typedef int ma_atomic_memory_order; #define ma_atomic_fetch_and_explicit_i16(dst, src, order) (ma_int16)ma_atomic_fetch_and_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) #define ma_atomic_fetch_and_explicit_i32(dst, src, order) (ma_int32)ma_atomic_fetch_and_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) #define ma_atomic_fetch_and_explicit_i64(dst, src, order) (ma_int64)ma_atomic_fetch_and_explicit_64((ma_uint64*)dst, (ma_uint64)src, order) -#define ma_atomic_test_and_set_i8( ptr) ma_atomic_test_and_set_explicit_i8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_i16(ptr) ma_atomic_test_and_set_explicit_i16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_i32(ptr) ma_atomic_test_and_set_explicit_i32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_i64(ptr) ma_atomic_test_and_set_explicit_i64(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_i8( ptr) ma_atomic_clear_explicit_i8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_i16(ptr) ma_atomic_clear_explicit_i16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_i32(ptr) ma_atomic_clear_explicit_i32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_i64(ptr) ma_atomic_clear_explicit_i64(ptr, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_i8( dst, src) ma_atomic_store_explicit_i8( dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_i16(dst, src) ma_atomic_store_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_i32(dst, src) ma_atomic_store_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) @@ -15728,14 +17146,14 @@ typedef int ma_atomic_memory_order; #define ma_atomic_exchange_i16(dst, src) ma_atomic_exchange_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_i32(dst, src) ma_atomic_exchange_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_i64(dst, src) ma_atomic_exchange_explicit_i64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i8( dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i16(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i32(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i64(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i8( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i16(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i32(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i64(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_i8( dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_i16(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_i32(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_i64(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_i8( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_i16(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_i32(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_i64(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_i8( dst, src) ma_atomic_fetch_add_explicit_i8( dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_i16(dst, src) ma_atomic_fetch_add_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_i32(dst, src) ma_atomic_fetch_add_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) @@ -15812,28 +17230,28 @@ static MA_INLINE double ma_atomic_exchange_explicit_f64(volatile double* dst, do r.i = ma_atomic_exchange_explicit_64((volatile ma_uint64*)dst, x.i, order); return r.f; } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f32(volatile float* dst, float* expected, float desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f32(volatile float* dst, float* expected, float replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { ma_atomic_if32 d; - d.f = desired; + d.f = replacement; return ma_atomic_compare_exchange_strong_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, d.i, successOrder, failureOrder); } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f64(volatile double* dst, double* expected, double desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f64(volatile double* dst, double* expected, double replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { ma_atomic_if64 d; - d.f = desired; + d.f = replacement; return ma_atomic_compare_exchange_strong_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, d.i, successOrder, failureOrder); } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f32(volatile float* dst, float* expected, float desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f32(volatile float* dst, float* expected, float replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { ma_atomic_if32 d; - d.f = desired; + d.f = replacement; return ma_atomic_compare_exchange_weak_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, d.i, successOrder, failureOrder); } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f64(volatile double* dst, double* expected, double desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f64(volatile double* dst, double* expected, double replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { ma_atomic_if64 d; - d.f = desired; + d.f = replacement; return ma_atomic_compare_exchange_weak_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, d.i, successOrder, failureOrder); } static MA_INLINE float ma_atomic_fetch_add_explicit_f32(volatile float* dst, float src, ma_atomic_memory_order order) @@ -15924,10 +17342,10 @@ static MA_INLINE double ma_atomic_fetch_and_explicit_f64(volatile double* dst, d #define ma_atomic_load_f64(ptr) (double)ma_atomic_load_explicit_f64(ptr, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_f32(dst, src) (float )ma_atomic_exchange_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_f64(dst, src) (double)ma_atomic_exchange_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_f32(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_f32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_f64(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_f64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_f32(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_f32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_f64(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_f64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_f32(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_f32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_f64(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_f64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_f32(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_f32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_f64(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_f64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_f32(dst, src) ma_atomic_fetch_add_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_f64(dst, src) ma_atomic_fetch_add_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_sub_f32(dst, src) ma_atomic_fetch_sub_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) @@ -15938,39 +17356,24 @@ static MA_INLINE double ma_atomic_fetch_and_explicit_f64(volatile double* dst, d #define ma_atomic_fetch_xor_f64(dst, src) ma_atomic_fetch_xor_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_and_f32(dst, src) ma_atomic_fetch_and_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_and_f64(dst, src) ma_atomic_fetch_and_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) -static MA_INLINE float ma_atomic_compare_and_swap_f32(volatile float* dst, float expected, float desired) +static MA_INLINE float ma_atomic_compare_and_swap_f32(volatile float* dst, float expected, float replacement) { ma_atomic_if32 r; ma_atomic_if32 e, d; e.f = expected; - d.f = desired; + d.f = replacement; r.i = ma_atomic_compare_and_swap_32((volatile ma_uint32*)dst, e.i, d.i); return r.f; } -static MA_INLINE double ma_atomic_compare_and_swap_f64(volatile double* dst, double expected, double desired) +static MA_INLINE double ma_atomic_compare_and_swap_f64(volatile double* dst, double expected, double replacement) { ma_atomic_if64 r; ma_atomic_if64 e, d; e.f = expected; - d.f = desired; + d.f = replacement; r.i = ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, e.i, d.i); return r.f; } -typedef ma_atomic_flag ma_atomic_spinlock; -static MA_INLINE void ma_atomic_spinlock_lock(volatile ma_atomic_spinlock* pSpinlock) -{ - for (;;) { - if (ma_atomic_flag_test_and_set_explicit(pSpinlock, ma_atomic_memory_order_acquire) == 0) { - break; - } - while (ma_atomic_flag_load_explicit(pSpinlock, ma_atomic_memory_order_relaxed) == 1) { - } - } -} -static MA_INLINE void ma_atomic_spinlock_unlock(volatile ma_atomic_spinlock* pSpinlock) -{ - ma_atomic_flag_clear_explicit(pSpinlock, ma_atomic_memory_order_release); -} #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) #pragma GCC diagnostic pop #endif @@ -16176,7 +17579,7 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority int result; pthread_attr_t* pAttr = NULL; -#if !defined(__EMSCRIPTEN__) && !defined(__3DS__) +#if !defined(MA_EMSCRIPTEN) && !defined(MA_3DS) && !defined(MA_SWITCH) /* Try setting the thread priority. It's not critical if anything fails here. */ pthread_attr_t attr; if (pthread_attr_init(&attr) == 0) { @@ -16208,9 +17611,18 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority } #endif - if (stackSize > 0) { - pthread_attr_setstacksize(&attr, stackSize); + #if defined(_POSIX_THREAD_ATTR_STACKSIZE) && _POSIX_THREAD_ATTR_STACKSIZE >= 0 + { + if (stackSize > 0) { + pthread_attr_setstacksize(&attr, stackSize); + } } + #else + { + (void)stackSize; /* Suppress unused parameter warning. */ + } + #endif + if (scheduler != -1) { int priorityMin = sched_get_priority_min(scheduler); @@ -16218,7 +17630,7 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority int priorityStep = (priorityMax - priorityMin) / 7; /* 7 = number of priorities supported by miniaudio. */ struct sched_param sched; - if (pthread_attr_getschedparam(&attr, &sched) == 0) { + if (priorityMin != -1 && priorityMax != -1 && pthread_attr_getschedparam(&attr, &sched) == 0) { if (priority == ma_thread_priority_idle) { sched.sched_priority = priorityMin; } else if (priority == ma_thread_priority_realtime) { @@ -16267,6 +17679,21 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority } if (result != 0) { + /* + There have been reports that attempting to create a realtime thread can sometimes fail. In this case, + fall back to a normal priority thread. + + I'm including a compile-time option here to disable this functionality for those who have a hard + requirement on realtime threads and would rather an explicit failure. + */ + #ifndef MA_NO_PTHREAD_REALTIME_PRIORITY_FALLBACK + { + if(result == EPERM && priority == ma_thread_priority_realtime) { + return ma_thread_create__posix(pThread, ma_thread_priority_normal, stackSize, entryProc, pData); + } + } + #endif + return ma_result_from_errno(result); } @@ -16538,7 +17965,7 @@ static ma_result ma_event_signal__win32(ma_event* pEvent) static ma_result ma_semaphore_init__win32(int initialValue, ma_semaphore* pSemaphore) { - *pSemaphore = CreateSemaphoreW(NULL, (LONG)initialValue, LONG_MAX, NULL); + *pSemaphore = CreateSemaphore(NULL, (LONG)initialValue, LONG_MAX, NULL); if (*pSemaphore == NULL) { return ma_result_from_GetLastError(GetLastError()); } @@ -17432,10 +18859,12 @@ static MA_INLINE ma_uint16 ma_job_extract_slot(ma_uint64 toc) return (ma_uint16)(toc & 0x0000FFFF); } +#if 0 /* Currently unused, but might make use of this later. */ static MA_INLINE ma_uint16 ma_job_extract_code(ma_uint64 toc) { return (ma_uint16)((toc & 0xFFFF0000) >> 16); } +#endif static MA_INLINE ma_uint64 ma_job_toc_to_allocation(ma_uint64 toc) { @@ -17900,6 +19329,13 @@ MA_API ma_result ma_job_queue_next(ma_job_queue* pQueue, ma_job* pJob) Dynamic Linking *******************************************************************************/ +/* Disable run-time linking on certain backends and platforms. */ +#ifndef MA_NO_RUNTIME_LINKING + #if defined(MA_EMSCRIPTEN) || defined(MA_ORBIS) || defined(MA_PROSPERO) || defined(MA_SWITCH) || defined(MA_DOS) + #define MA_NO_RUNTIME_LINKING + #endif +#endif + #ifdef MA_POSIX /* No need for dlfcn.h if we're not using runtime linking. */ #ifndef MA_NO_RUNTIME_LINKING @@ -17909,104 +19345,124 @@ Dynamic Linking MA_API ma_handle ma_dlopen(ma_log* pLog, const char* filename) { -#ifndef MA_NO_RUNTIME_LINKING - ma_handle handle; + #ifndef MA_NO_RUNTIME_LINKING + { + ma_handle handle; - ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading library: %s\n", filename); + ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading library: %s\n", filename); - #ifdef MA_WIN32 - /* From MSDN: Desktop applications cannot use LoadPackagedLibrary; if a desktop application calls this function it fails with APPMODEL_ERROR_NO_PACKAGE.*/ - #if !defined(MA_WIN32_UWP) || !(defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP))) - handle = (ma_handle)LoadLibraryA(filename); + #ifdef MA_WIN32 + /* From MSDN: Desktop applications cannot use LoadPackagedLibrary; if a desktop application calls this function it fails with APPMODEL_ERROR_NO_PACKAGE.*/ + #if !defined(MA_WIN32_UWP) || !(defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP))) + handle = (ma_handle)LoadLibraryA(filename); + #else + /* *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... */ + WCHAR filenameW[4096]; + if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) { + handle = NULL; + } else { + handle = (ma_handle)LoadPackagedLibrary(filenameW, 0); + } + #endif #else - /* *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... */ - WCHAR filenameW[4096]; - if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) { - handle = NULL; - } else { - handle = (ma_handle)LoadPackagedLibrary(filenameW, 0); - } + handle = (ma_handle)dlopen(filename, RTLD_NOW); #endif - #else - handle = (ma_handle)dlopen(filename, RTLD_NOW); - #endif - /* - I'm not considering failure to load a library an error nor a warning because seamlessly falling through to a lower-priority - backend is a deliberate design choice. Instead I'm logging it as an informational message. - */ - if (handle == NULL) { - ma_log_postf(pLog, MA_LOG_LEVEL_INFO, "Failed to load library: %s\n", filename); + /* + I'm not considering failure to load a library an error nor a warning because seamlessly falling through to a lower-priority + backend is a deliberate design choice. Instead I'm logging it as an informational message. + */ + if (handle == NULL) { + ma_log_postf(pLog, MA_LOG_LEVEL_INFO, "Failed to load library: %s\n", filename); + } + + return handle; } - - return handle; -#else - /* Runtime linking is disabled. */ - (void)pLog; - (void)filename; - return NULL; -#endif + #else + { + /* Runtime linking is disabled. */ + (void)pLog; + (void)filename; + return NULL; + } + #endif } MA_API void ma_dlclose(ma_log* pLog, ma_handle handle) { -#ifndef MA_NO_RUNTIME_LINKING - #ifdef MA_WIN32 - FreeLibrary((HMODULE)handle); - #else - /* Hack for Android bug (see https://github.com/android/ndk/issues/360). Calling dlclose() pre-API 28 may segfault. */ - #if !defined(MA_ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28) + #ifndef MA_NO_RUNTIME_LINKING + { + #ifdef MA_WIN32 { - dlclose((void*)handle); + FreeLibrary((HMODULE)handle); } #else { - (void)handle; + /* Hack for Android bug (see https://github.com/android/ndk/issues/360). Calling dlclose() pre-API 28 may segfault. */ + #if !defined(MA_ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28) + { + dlclose((void*)handle); + } + #else + { + (void)handle; + } + #endif } #endif - #endif - (void)pLog; -#else - /* Runtime linking is disabled. */ - (void)pLog; - (void)handle; -#endif + (void)pLog; + } + #else + { + /* Runtime linking is disabled. */ + (void)pLog; + (void)handle; + } + #endif } MA_API ma_proc ma_dlsym(ma_log* pLog, ma_handle handle, const char* symbol) { -#ifndef MA_NO_RUNTIME_LINKING - ma_proc proc; + #ifndef MA_NO_RUNTIME_LINKING + { + ma_proc proc; - ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading symbol: %s\n", symbol); + ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading symbol: %s\n", symbol); -#ifdef _WIN32 - proc = (ma_proc)GetProcAddress((HMODULE)handle, symbol); -#else -#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wpedantic" -#endif - proc = (ma_proc)dlsym((void*)handle, symbol); -#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) - #pragma GCC diagnostic pop -#endif -#endif + #ifdef _WIN32 + { + proc = (ma_proc)GetProcAddress((HMODULE)handle, symbol); + } + #else + { + #if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpedantic" + #endif + proc = (ma_proc)dlsym((void*)handle, symbol); + #if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) + #pragma GCC diagnostic pop + #endif + } + #endif - if (proc == NULL) { - ma_log_postf(pLog, MA_LOG_LEVEL_WARNING, "Failed to load symbol: %s\n", symbol); + if (proc == NULL) { + ma_log_postf(pLog, MA_LOG_LEVEL_WARNING, "Failed to load symbol: %s\n", symbol); + } + + (void)pLog; /* It's possible for pContext to be unused. */ + return proc; } - - (void)pLog; /* It's possible for pContext to be unused. */ - return proc; -#else - /* Runtime linking is disabled. */ - (void)pLog; - (void)handle; - (void)symbol; - return NULL; -#endif + #else + { + /* Runtime linking is disabled. */ + (void)pLog; + (void)handle; + (void)symbol; + return NULL; + } + #endif } @@ -18020,13 +19476,6 @@ DEVICE I/O ************************************************************************************************************************************************************* ************************************************************************************************************************************************************/ -/* Disable run-time linking on certain backends and platforms. */ -#ifndef MA_NO_RUNTIME_LINKING - #if defined(MA_EMSCRIPTEN) || defined(MA_ORBIS) || defined(MA_PROSPERO) - #define MA_NO_RUNTIME_LINKING - #endif -#endif - #ifdef MA_APPLE #include #endif @@ -18039,12 +19488,6 @@ DEVICE I/O #ifdef MA_POSIX #include - #include - - /* No need for dlfcn.h if we're not using runtime linking. */ - #ifndef MA_NO_RUNTIME_LINKING - #include - #endif #endif /* This must be set to at least 26. */ @@ -18299,7 +19742,7 @@ MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend) -#if defined(MA_WIN32) +#if defined(MA_WIN32) && !defined(MA_XBOX) /* WASAPI error codes. */ #define MA_AUDCLNT_E_NOT_INITIALIZED ((HRESULT)0x88890001) #define MA_AUDCLNT_E_ALREADY_INITIALIZED ((HRESULT)0x88890002) @@ -18514,6 +19957,11 @@ typedef LONG (WINAPI * MA_PFN_RegCloseKey)(HKEY hKey); typedef LONG (WINAPI * MA_PFN_RegQueryValueExA)(HKEY hKey, const char* lpValueName, DWORD* lpReserved, DWORD* lpType, BYTE* lpData, DWORD* lpcbData); #endif /* MA_WIN32_DESKTOP */ +static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; +static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; +/*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ +/*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ + MA_API size_t ma_strlen_WCHAR(const WCHAR* str) { size_t len = 0; @@ -18577,7 +20025,7 @@ Timing *******************************************************************************/ #if defined(MA_WIN32) && !defined(MA_POSIX) static LARGE_INTEGER g_ma_TimerFrequency; /* <-- Initialized to zero since it's static. */ - static void ma_timer_init(ma_timer* pTimer) + static MA_INLINE void ma_timer_init(ma_timer* pTimer) { LARGE_INTEGER counter; @@ -18589,7 +20037,7 @@ Timing pTimer->counter = counter.QuadPart; } - static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) { LARGE_INTEGER counter; if (!QueryPerformanceCounter(&counter)) { @@ -18600,7 +20048,7 @@ Timing } #elif defined(MA_APPLE) && (MAC_OS_X_VERSION_MIN_REQUIRED < 101200) static ma_uint64 g_ma_TimerFrequency = 0; - static void ma_timer_init(ma_timer* pTimer) + static MA_INLINE void ma_timer_init(ma_timer* pTimer) { mach_timebase_info_data_t baseTime; mach_timebase_info(&baseTime); @@ -18609,7 +20057,7 @@ Timing pTimer->counter = mach_absolute_time(); } - static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) { ma_uint64 newTimeCounter = mach_absolute_time(); ma_uint64 oldTimeCounter = pTimer->counter; @@ -18634,15 +20082,15 @@ Timing #define MA_CLOCK_ID CLOCK_REALTIME #endif - static void ma_timer_init(ma_timer* pTimer) + static MA_INLINE void ma_timer_init(ma_timer* pTimer) { struct timespec newTime; clock_gettime(MA_CLOCK_ID, &newTime); - pTimer->counter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec; + pTimer->counter = ((ma_int64)newTime.tv_sec * 1000000000) + newTime.tv_nsec; } - static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) { ma_uint64 newTimeCounter; ma_uint64 oldTimeCounter; @@ -18650,21 +20098,21 @@ Timing struct timespec newTime; clock_gettime(MA_CLOCK_ID, &newTime); - newTimeCounter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec; + newTimeCounter = ((ma_uint64)newTime.tv_sec * 1000000000) + newTime.tv_nsec; oldTimeCounter = pTimer->counter; return (newTimeCounter - oldTimeCounter) / 1000000000.0; } #else - static void ma_timer_init(ma_timer* pTimer) + static MA_INLINE void ma_timer_init(ma_timer* pTimer) { struct timeval newTime; gettimeofday(&newTime, NULL); - pTimer->counter = (newTime.tv_sec * 1000000) + newTime.tv_usec; + pTimer->counter = ((ma_int64)newTime.tv_sec * 1000000) + newTime.tv_usec; } - static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) { ma_uint64 newTimeCounter; ma_uint64 oldTimeCounter; @@ -18672,7 +20120,7 @@ Timing struct timeval newTime; gettimeofday(&newTime, NULL); - newTimeCounter = (newTime.tv_sec * 1000000) + newTime.tv_usec; + newTimeCounter = ((ma_uint64)newTime.tv_sec * 1000000) + newTime.tv_usec; oldTimeCounter = pTimer->counter; return (newTimeCounter - oldTimeCounter) / 1000000.0; @@ -19248,14 +20696,6 @@ static MA_INLINE void ma_device__set_state(ma_device* pDevice, ma_device_state n } -#if defined(MA_WIN32) - static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; - static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; - /*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ - /*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ -#endif - - MA_API ma_uint32 ma_get_format_priority_index(ma_format format) /* Lower = better. */ { @@ -19967,7 +21407,7 @@ static ma_result ma_context_init__null(ma_context* pContext, const ma_context_co WIN32 COMMON *******************************************************************************/ -#if defined(MA_WIN32) +#if defined(MA_WIN32) && !defined(MA_XBOX) #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) #define ma_CoInitializeEx(pContext, pvReserved, dwCoInit) ((pContext->win32.CoInitializeEx) ? ((MA_PFN_CoInitializeEx)pContext->win32.CoInitializeEx)(pvReserved, dwCoInit) : ((MA_PFN_CoInitialize)pContext->win32.CoInitialize)(pvReserved)) #define ma_CoUninitialize(pContext) ((MA_PFN_CoUninitialize)pContext->win32.CoUninitialize)() @@ -19982,7 +21422,7 @@ WIN32 COMMON #define ma_PropVariantClear(pContext, pvar) PropVariantClear(pvar) #endif -#if !defined(MAXULONG_PTR) && !defined(__WATCOMC__) +#if !defined(MAXULONG_PTR) && !defined(__WATCOMC__) && !defined(MA_XBOX_NXDK) typedef size_t DWORD_PTR; #endif @@ -20409,11 +21849,21 @@ typedef enum MA_AudioCategory_Other = 0 /* <-- miniaudio is only caring about Other. */ } MA_AUDIO_STREAM_CATEGORY; +typedef enum +{ + MA_AUDCLNT_STREAMOPTIONS_NONE, + MA_AUDCLNT_STREAMOPTIONS_RAW, + MA_AUDCLNT_STREAMOPTIONS_MATCH_FORMAT, + MA_AUDCLNT_STREAMOPTIONS_AMBISONICS, + MA_AUDCLNT_STREAMOPTIONS_POST_VOLUME_LOOPBACK +} MA_AUDCLNT_STREAMOPTIONS; + typedef struct { ma_uint32 cbSize; BOOL bIsOffload; MA_AUDIO_STREAM_CATEGORY eCategory; + MA_AUDCLNT_STREAMOPTIONS Options; } ma_AudioClientProperties; /* IUnknown */ @@ -21588,6 +23038,7 @@ static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device { ma_IMMDeviceEnumerator* pDeviceEnumerator; HRESULT hr; + HRESULT CoInitializeResult; MA_ASSERT(pContext != NULL); MA_ASSERT(ppMMDevice != NULL); @@ -21601,12 +23052,17 @@ static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device The community has reported that this seems to fix the crash. There are future plans to move all WASAPI operation over to a single thread to make everything safer, but in the meantime while we wait for that to come online I'm happy enough to use this hack instead. + + CoUninitialize should only be called if we successfully initialized. S_OK and S_FALSE both mean that we need to + call CoUninitialize since the internal ref count was increased. RPC_E_CHANGED_MODE means that CoInitializeEx was + called with a different COINIT value, and we don't call CoUninitialize in that case. Other errors are possible, + so we check for S_OK and S_FALSE specifically. */ - ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); + CoInitializeResult = ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); { hr = ma_CoCreateInstance(pContext, &MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); - } - ma_CoUninitialize(pContext); + } + if (CoInitializeResult == S_OK || CoInitializeResult == S_FALSE) { ma_CoUninitialize(pContext); } if (FAILED(hr)) { /* <-- This is checking the call above to ma_CoCreateInstance(). */ ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create IMMDeviceEnumerator.\n"); @@ -21950,7 +23406,7 @@ static ma_result ma_context_get_IAudioClient__wasapi(ma_context* pContext, ma_de pActivationParams = &activationParams; /* When requesting a specific device ID we need to use a special device ID. */ - MA_COPY_MEMORY(virtualDeviceID.wasapi, MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK, (wcslen(MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK) + 1) * sizeof(wchar_t)); /* +1 for the null terminator. */ + MA_COPY_MEMORY(virtualDeviceID.wasapi, MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK, (ma_wcslen(MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK) + 1) * sizeof(wchar_t)); /* +1 for the null terminator. */ pDeviceID = &virtualDeviceID; } else { pActivationParams = NULL; /* No activation parameters required. */ @@ -26679,6 +28135,9 @@ typedef snd_pcm_channel_area_t ma_snd_pcm_channel_area_t; typedef snd_pcm_chmap_t ma_snd_pcm_chmap_t; typedef snd_pcm_state_t ma_snd_pcm_state_t; +/* snd_pcm_state_t */ +#define MA_SND_PCM_STATE_XRUN SND_PCM_STATE_XRUN + /* snd_pcm_stream_t */ #define MA_SND_PCM_STREAM_PLAYBACK SND_PCM_STREAM_PLAYBACK #define MA_SND_PCM_STREAM_CAPTURE SND_PCM_STREAM_CAPTURE @@ -26874,6 +28333,7 @@ typedef int (* ma_snd_pcm_hw_params_set_channels_minmax_proc) ( typedef int (* ma_snd_pcm_hw_params_set_rate_resample_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val); typedef int (* ma_snd_pcm_hw_params_set_rate_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val, int dir); typedef int (* ma_snd_pcm_hw_params_set_rate_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +typedef int (* ma_snd_pcm_hw_params_set_rate_minmax_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); typedef int (* ma_snd_pcm_hw_params_set_buffer_size_near_proc)(ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_uframes_t *val); typedef int (* ma_snd_pcm_hw_params_set_periods_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir); typedef int (* ma_snd_pcm_hw_params_set_access_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_access_t _access); @@ -28640,8 +30100,9 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co ma_snd_pcm_hw_params_get_format_mask_proc _snd_pcm_hw_params_get_format_mask = snd_pcm_hw_params_get_format_mask; ma_snd_pcm_hw_params_set_channels_proc _snd_pcm_hw_params_set_channels = snd_pcm_hw_params_set_channels; ma_snd_pcm_hw_params_set_channels_near_proc _snd_pcm_hw_params_set_channels_near = snd_pcm_hw_params_set_channels_near; + ma_snd_pcm_hw_params_set_channels_minmax_proc _snd_pcm_hw_params_set_channels_minmax = snd_pcm_hw_params_set_channels_minmax; ma_snd_pcm_hw_params_set_rate_resample_proc _snd_pcm_hw_params_set_rate_resample = snd_pcm_hw_params_set_rate_resample; - ma_snd_pcm_hw_params_set_rate_near _snd_pcm_hw_params_set_rate = snd_pcm_hw_params_set_rate; + ma_snd_pcm_hw_params_set_rate_proc _snd_pcm_hw_params_set_rate = snd_pcm_hw_params_set_rate; ma_snd_pcm_hw_params_set_rate_near_proc _snd_pcm_hw_params_set_rate_near = snd_pcm_hw_params_set_rate_near; ma_snd_pcm_hw_params_set_rate_minmax_proc _snd_pcm_hw_params_set_rate_minmax = snd_pcm_hw_params_set_rate_minmax; ma_snd_pcm_hw_params_set_buffer_size_near_proc _snd_pcm_hw_params_set_buffer_size_near = snd_pcm_hw_params_set_buffer_size_near; @@ -28693,9 +30154,9 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co ma_snd_pcm_info_proc _snd_pcm_info = snd_pcm_info; ma_snd_pcm_info_sizeof_proc _snd_pcm_info_sizeof = snd_pcm_info_sizeof; ma_snd_pcm_info_get_name_proc _snd_pcm_info_get_name = snd_pcm_info_get_name; - ma_snd_pcm_poll_descriptors _snd_pcm_poll_descriptors = snd_pcm_poll_descriptors; - ma_snd_pcm_poll_descriptors_count _snd_pcm_poll_descriptors_count = snd_pcm_poll_descriptors_count; - ma_snd_pcm_poll_descriptors_revents _snd_pcm_poll_descriptors_revents = snd_pcm_poll_descriptors_revents; + ma_snd_pcm_poll_descriptors_proc _snd_pcm_poll_descriptors = snd_pcm_poll_descriptors; + ma_snd_pcm_poll_descriptors_count_proc _snd_pcm_poll_descriptors_count = snd_pcm_poll_descriptors_count; + ma_snd_pcm_poll_descriptors_revents_proc _snd_pcm_poll_descriptors_revents = snd_pcm_poll_descriptors_revents; ma_snd_config_update_free_global_proc _snd_config_update_free_global = snd_config_update_free_global; pContext->alsa.snd_pcm_open = (ma_proc)_snd_pcm_open; @@ -28711,6 +30172,7 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co pContext->alsa.snd_pcm_hw_params_set_rate_resample = (ma_proc)_snd_pcm_hw_params_set_rate_resample; pContext->alsa.snd_pcm_hw_params_set_rate = (ma_proc)_snd_pcm_hw_params_set_rate; pContext->alsa.snd_pcm_hw_params_set_rate_near = (ma_proc)_snd_pcm_hw_params_set_rate_near; + pContext->alsa.snd_pcm_hw_params_set_rate_minmax = (ma_proc)_snd_pcm_hw_params_set_rate_minmax; pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (ma_proc)_snd_pcm_hw_params_set_buffer_size_near; pContext->alsa.snd_pcm_hw_params_set_periods_near = (ma_proc)_snd_pcm_hw_params_set_periods_near; pContext->alsa.snd_pcm_hw_params_set_access = (ma_proc)_snd_pcm_hw_params_set_access; @@ -29436,7 +30898,7 @@ typedef void (* ma_pa_threaded_mainloop_unlock_proc) ( typedef void (* ma_pa_threaded_mainloop_wait_proc) (ma_pa_threaded_mainloop* m); typedef void (* ma_pa_threaded_mainloop_signal_proc) (ma_pa_threaded_mainloop* m, int wait_for_accept); typedef void (* ma_pa_threaded_mainloop_accept_proc) (ma_pa_threaded_mainloop* m); -typedef int (* ma_pa_threaded_mainloop_get_retval_proc) (ma_pa_threaded_mainloop* m); +typedef int (* ma_pa_threaded_mainloop_get_retval_proc) (const ma_pa_threaded_mainloop* m); typedef ma_pa_mainloop_api* (* ma_pa_threaded_mainloop_get_api_proc) (ma_pa_threaded_mainloop* m); typedef int (* ma_pa_threaded_mainloop_in_thread_proc) (ma_pa_threaded_mainloop* m); typedef void (* ma_pa_threaded_mainloop_set_name_proc) (ma_pa_threaded_mainloop* m, const char* name); @@ -29445,13 +30907,13 @@ typedef void (* ma_pa_context_unref_proc) ( typedef int (* ma_pa_context_connect_proc) (ma_pa_context* c, const char* server, ma_pa_context_flags_t flags, const ma_pa_spawn_api* api); typedef void (* ma_pa_context_disconnect_proc) (ma_pa_context* c); typedef void (* ma_pa_context_set_state_callback_proc) (ma_pa_context* c, ma_pa_context_notify_cb_t cb, void* userdata); -typedef ma_pa_context_state_t (* ma_pa_context_get_state_proc) (ma_pa_context* c); +typedef ma_pa_context_state_t (* ma_pa_context_get_state_proc) (const ma_pa_context* c); typedef ma_pa_operation* (* ma_pa_context_get_sink_info_list_proc) (ma_pa_context* c, ma_pa_sink_info_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_context_get_source_info_list_proc) (ma_pa_context* c, ma_pa_source_info_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_context_get_sink_info_by_name_proc) (ma_pa_context* c, const char* name, ma_pa_sink_info_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_context_get_source_info_by_name_proc)(ma_pa_context* c, const char* name, ma_pa_source_info_cb_t cb, void* userdata); typedef void (* ma_pa_operation_unref_proc) (ma_pa_operation* o); -typedef ma_pa_operation_state_t (* ma_pa_operation_get_state_proc) (ma_pa_operation* o); +typedef ma_pa_operation_state_t (* ma_pa_operation_get_state_proc) (const ma_pa_operation* o); typedef ma_pa_channel_map* (* ma_pa_channel_map_init_extend_proc) (ma_pa_channel_map* m, unsigned channels, ma_pa_channel_map_def_t def); typedef int (* ma_pa_channel_map_valid_proc) (const ma_pa_channel_map* m); typedef int (* ma_pa_channel_map_compatible_proc) (const ma_pa_channel_map* m, const ma_pa_sample_spec* ss); @@ -29460,12 +30922,12 @@ typedef void (* ma_pa_stream_unref_proc) ( typedef int (* ma_pa_stream_connect_playback_proc) (ma_pa_stream* s, const char* dev, const ma_pa_buffer_attr* attr, ma_pa_stream_flags_t flags, const ma_pa_cvolume* volume, ma_pa_stream* sync_stream); typedef int (* ma_pa_stream_connect_record_proc) (ma_pa_stream* s, const char* dev, const ma_pa_buffer_attr* attr, ma_pa_stream_flags_t flags); typedef int (* ma_pa_stream_disconnect_proc) (ma_pa_stream* s); -typedef ma_pa_stream_state_t (* ma_pa_stream_get_state_proc) (ma_pa_stream* s); +typedef ma_pa_stream_state_t (* ma_pa_stream_get_state_proc) (const ma_pa_stream* s); typedef const ma_pa_sample_spec* (* ma_pa_stream_get_sample_spec_proc) (ma_pa_stream* s); typedef const ma_pa_channel_map* (* ma_pa_stream_get_channel_map_proc) (ma_pa_stream* s); typedef const ma_pa_buffer_attr* (* ma_pa_stream_get_buffer_attr_proc) (ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_set_buffer_attr_proc) (ma_pa_stream* s, const ma_pa_buffer_attr* attr, ma_pa_stream_success_cb_t cb, void* userdata); -typedef const char* (* ma_pa_stream_get_device_name_proc) (ma_pa_stream* s); +typedef const char* (* ma_pa_stream_get_device_name_proc) (const ma_pa_stream* s); typedef void (* ma_pa_stream_set_write_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); typedef void (* ma_pa_stream_set_read_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); typedef void (* ma_pa_stream_set_suspended_callback_proc) (ma_pa_stream* s, ma_pa_stream_notify_cb_t cb, void* userdata); @@ -29473,15 +30935,15 @@ typedef void (* ma_pa_stream_set_moved_callback_proc) ( typedef int (* ma_pa_stream_is_suspended_proc) (const ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_flush_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_stream_drain_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); -typedef int (* ma_pa_stream_is_corked_proc) (ma_pa_stream* s); +typedef int (* ma_pa_stream_is_corked_proc) (const ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_cork_proc) (ma_pa_stream* s, int b, ma_pa_stream_success_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_stream_trigger_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef int (* ma_pa_stream_begin_write_proc) (ma_pa_stream* s, void** data, size_t* nbytes); typedef int (* ma_pa_stream_write_proc) (ma_pa_stream* s, const void* data, size_t nbytes, ma_pa_free_cb_t free_cb, int64_t offset, ma_pa_seek_mode_t seek); typedef int (* ma_pa_stream_peek_proc) (ma_pa_stream* s, const void** data, size_t* nbytes); typedef int (* ma_pa_stream_drop_proc) (ma_pa_stream* s); -typedef size_t (* ma_pa_stream_writable_size_proc) (ma_pa_stream* s); -typedef size_t (* ma_pa_stream_readable_size_proc) (ma_pa_stream* s); +typedef size_t (* ma_pa_stream_writable_size_proc) (const ma_pa_stream* s); +typedef size_t (* ma_pa_stream_readable_size_proc) (const ma_pa_stream* s); typedef struct { @@ -29777,9 +31239,10 @@ static ma_result ma_init_pa_mainloop_and_pa_context__pulse(ma_context* pContext, } /* Now we need to connect to the context. Everything is asynchronous so we need to wait for it to connect before returning. */ - result = ma_result_from_pulse(((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pPulseContext, pServerName, (tryAutoSpawn) ? 0 : MA_PA_CONTEXT_NOAUTOSPAWN, NULL)); + result = ma_result_from_pulse(((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pPulseContext, pServerName, (tryAutoSpawn) ? MA_PA_CONTEXT_NOFLAGS : MA_PA_CONTEXT_NOAUTOSPAWN, NULL)); if (result != MA_SUCCESS) { ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio context."); + ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)((ma_pa_context*)(pPulseContext)); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop)); return result; } @@ -29788,6 +31251,7 @@ static ma_result ma_init_pa_mainloop_and_pa_context__pulse(ma_context* pContext, result = ma_wait_for_pa_context_to_connect__pulse(pContext, pMainLoop, pPulseContext); if (result != MA_SUCCESS) { ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Waiting for connection failed."); + ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)((ma_pa_context*)(pPulseContext)); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop)); return result; } @@ -30510,7 +31974,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi const ma_pa_buffer_attr* pActualAttr = NULL; const ma_pa_channel_map* pActualChannelMap = NULL; ma_uint32 iChannel; - ma_pa_stream_flags_t streamFlags; + int streamFlags; MA_ASSERT(pDevice != NULL); MA_ZERO_OBJECT(&pDevice->pulse); @@ -30568,8 +32032,13 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ss.channels = pDescriptorCapture->channels; } + /* PulseAudio has a maximum channel count of 32. We'll get a crash if this is exceeded. */ + if (ss.channels > 32) { + ss.channels = 32; + } + /* Use a default channel map. */ - ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, pConfig->pulse.channelMap); + ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, (ma_pa_channel_map_def_t)pConfig->pulse.channelMap); /* Use the requested sample rate if one was specified. */ if (pDescriptorCapture->sampleRate != 0) { @@ -30626,7 +32095,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi streamFlags |= MA_PA_STREAM_DONT_MOVE; } - error = ((ma_pa_stream_connect_record_proc)pDevice->pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, streamFlags); + error = ((ma_pa_stream_connect_record_proc)pDevice->pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, (ma_pa_stream_flags_t)streamFlags); if (error != MA_PA_OK) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio capture stream."); result = ma_result_from_pulse(error); @@ -30720,8 +32189,13 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ss.channels = pDescriptorPlayback->channels; } + /* PulseAudio has a maximum channel count of 32. We'll get a crash if this is exceeded. */ + if (ss.channels > 32) { + ss.channels = 32; + } + /* Use a default channel map. */ - ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, pConfig->pulse.channelMap); + ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, (ma_pa_channel_map_def_t)pConfig->pulse.channelMap); /* Use the requested sample rate if one was specified. */ @@ -30783,7 +32257,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi streamFlags |= MA_PA_STREAM_DONT_MOVE; } - error = ((ma_pa_stream_connect_playback_proc)pDevice->pContext->pulse.pa_stream_connect_playback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, devPlayback, &attr, streamFlags, NULL, NULL); + error = ((ma_pa_stream_connect_playback_proc)pDevice->pContext->pulse.pa_stream_connect_playback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, devPlayback, &attr, (ma_pa_stream_flags_t)streamFlags, NULL, NULL); if (error != MA_PA_OK) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio playback stream."); result = ma_result_from_pulse(error); @@ -31338,6 +32812,7 @@ typedef JackProcessCallback ma_JackProcessCallback; typedef JackBufferSizeCallback ma_JackBufferSizeCallback; typedef JackShutdownCallback ma_JackShutdownCallback; #define MA_JACK_DEFAULT_AUDIO_TYPE JACK_DEFAULT_AUDIO_TYPE +#define ma_JackNullOption JackNullOption #define ma_JackNoStartServer JackNoStartServer #define ma_JackPortIsInput JackPortIsInput #define ma_JackPortIsOutput JackPortIsOutput @@ -31352,6 +32827,7 @@ typedef int (* ma_JackProcessCallback) (ma_jack_nframes_t nframes, void* arg) typedef int (* ma_JackBufferSizeCallback)(ma_jack_nframes_t nframes, void* arg); typedef void (* ma_JackShutdownCallback) (void* arg); #define MA_JACK_DEFAULT_AUDIO_TYPE "32 bit float mono audio" +#define ma_JackNullOption 0 #define ma_JackNoStartServer 1 #define ma_JackPortIsInput 1 #define ma_JackPortIsOutput 2 @@ -31392,7 +32868,7 @@ static ma_result ma_context_open_client__jack(ma_context* pContext, ma_jack_clie maxClientNameSize = ((ma_jack_client_name_size_proc)pContext->jack.jack_client_name_size)(); /* Includes null terminator. */ ma_strncpy_s(clientName, ma_min(sizeof(clientName), maxClientNameSize), (pContext->jack.pClientName != NULL) ? pContext->jack.pClientName : "miniaudio", (size_t)-1); - pClient = ((ma_jack_client_open_proc)pContext->jack.jack_client_open)(clientName, (pContext->jack.tryStartServer) ? 0 : ma_JackNoStartServer, &status, NULL); + pClient = ((ma_jack_client_open_proc)pContext->jack.jack_client_open)(clientName, (pContext->jack.tryStartServer) ? ma_JackNullOption : ma_JackNoStartServer, &status, NULL); if (pClient == NULL) { return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } @@ -36994,7 +38470,7 @@ OSS Backend #define MA_OSS_DEFAULT_DEVICE_NAME "/dev/dsp" -static int ma_open_temp_device__oss() +static int ma_open_temp_device__oss(void) { /* The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same. */ int fd = open("/dev/mixer", O_RDONLY, 0); @@ -37834,25 +39310,30 @@ static void ma_stream_error_callback__aaudio(ma_AAudioStream* pStream, void* pUs (void)error; ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream)); + /* When we get an error, we'll assume that the stream is in an erroneous state and needs to be restarted. From the documentation, we cannot do this from the error callback. Therefore we are going to use an event thread for the AAudio backend to do this cleanly and safely. */ - job = ma_job_init(MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE); - job.data.device.aaudio.reroute.pDevice = pDevice; - - if (pStream == pDevice->aaudio.pStreamCapture) { - job.data.device.aaudio.reroute.deviceType = ma_device_type_capture; + if (ma_atomic_bool32_get(&pDevice->aaudio.isTearingDown)) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected. Tearing down device.\n"); } else { - job.data.device.aaudio.reroute.deviceType = ma_device_type_playback; - } - - result = ma_device_job_thread_post(&pDevice->pContext->aaudio.jobThread, &job); - if (result != MA_SUCCESS) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected. Failed to post job for rerouting.\n"); - return; + job = ma_job_init(MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE); + job.data.device.aaudio.reroute.pDevice = pDevice; + + if (pStream == pDevice->aaudio.pStreamCapture) { + job.data.device.aaudio.reroute.deviceType = ma_device_type_capture; + } else { + job.data.device.aaudio.reroute.deviceType = ma_device_type_playback; + } + + result = ma_device_job_thread_post(&pDevice->pContext->aaudio.jobThread, &job); + if (result != MA_SUCCESS) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected. Failed to post job for rerouting.\n"); + return; + } } } @@ -38169,7 +39650,7 @@ static ma_result ma_close_streams__aaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); - /* When re-routing, streams may have been closed and never re-opened. Hence the extra checks below. */ + /* When rerouting, streams may have been closed and never re-opened. Hence the extra checks below. */ if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); pDevice->aaudio.pStreamCapture = NULL; @@ -38186,6 +39667,12 @@ static ma_result ma_device_uninit__aaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); + /* + Note: Closing the streams may cause a timeout error, which would then trigger rerouting in our error callback. + We must not schedule a reroute when device is getting destroyed. + */ + ma_atomic_bool32_set(&pDevice->aaudio.isTearingDown, MA_TRUE); + /* Wait for any rerouting to finish before attempting to close the streams. */ ma_mutex_lock(&pDevice->aaudio.rerouteLock); { @@ -38193,7 +39680,7 @@ static ma_result ma_device_uninit__aaudio(ma_device* pDevice) } ma_mutex_unlock(&pDevice->aaudio.rerouteLock); - /* Destroy re-routing lock. */ + /* Destroy rerouting lock. */ ma_mutex_uninit(&pDevice->aaudio.rerouteLock); return MA_SUCCESS; @@ -38429,17 +39916,22 @@ static ma_result ma_device_stop__aaudio(ma_device* pDevice) static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type deviceType) { + const ma_int32 maxAttempts = 4; /* Reasonable retry limit. */ + ma_result result; - int32_t retries = 0; + ma_int32 iAttempt; MA_ASSERT(pDevice != NULL); - /* - TODO: Stop retrying if main thread is about to uninit device. - */ - ma_mutex_lock(&pDevice->aaudio.rerouteLock); - { -error_disconnected: + /* We got disconnected! Retry a few times, until we find a connected device! */ + iAttempt = 0; + while (iAttempt++ < maxAttempts) { + /* Device tearing down? No need to reroute! */ + if (ma_atomic_bool32_get(&pDevice->aaudio.isTearingDown)) { + result = MA_SUCCESS; /* Caller should continue as normal. */ + break; + } + /* The first thing to do is close the streams. */ ma_close_streams__aaudio(pDevice); @@ -38495,14 +39987,16 @@ error_disconnected: result = ma_device_init_streams__aaudio(pDevice, &deviceConfig, &descriptorPlayback, &descriptorCapture); if (result != MA_SUCCESS) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to create stream after route change."); - goto done; + /* Reroute failed! */ + break; } result = ma_device_post_init(pDevice, deviceType, &descriptorPlayback, &descriptorCapture); if (result != MA_SUCCESS) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to initialize device after route change."); ma_close_streams__aaudio(pDevice); - goto done; + /* Reroute failed! */ + break; } /* We'll only ever do this in response to a reroute. */ @@ -38513,26 +40007,23 @@ error_disconnected: if (pDevice->aaudio.noAutoStartAfterReroute == MA_FALSE) { result = ma_device_start__aaudio(pDevice); if (result != MA_SUCCESS) { - /* We got disconnected! Retry a few times, until we find a connected device! */ - retries += 1; - if (retries <= 3) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, retrying(%d)", retries); - goto error_disconnected; + if (iAttempt < maxAttempts) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, retrying(%d)", iAttempt); + } else { + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, giving up."); } - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change."); - goto done; } } else { - ma_device_stop(pDevice); /* Do a full device stop so we set internal state correctly. */ + ma_device_stop(pDevice); /* Do a full device stop so we set internal state correctly. */ } } - - result = MA_SUCCESS; - } -done: - /* Re-routing done */ - ma_mutex_unlock(&pDevice->aaudio.rerouteLock); + if (result == MA_SUCCESS) { + /* Reroute successful! */ + break; + } + } + return result; } @@ -38698,7 +40189,7 @@ static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_ static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob) { - ma_result result; + ma_result result = MA_SUCCESS; ma_device* pDevice; MA_ASSERT(pJob != NULL); @@ -38706,19 +40197,22 @@ static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob) pDevice = (ma_device*)pJob->data.device.aaudio.reroute.pDevice; MA_ASSERT(pDevice != NULL); - /* Here is where we need to reroute the device. To do this we need to uninitialize the stream and reinitialize it. */ - result = ma_device_reinit__aaudio(pDevice, (ma_device_type)pJob->data.device.aaudio.reroute.deviceType); - if (result != MA_SUCCESS) { - /* - Getting here means we failed to reroute the device. The best thing I can think of here is to - just stop the device. - */ - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[AAudio] Stopping device due to reroute failure."); - ma_device_stop(pDevice); - return result; + ma_mutex_lock(&pDevice->aaudio.rerouteLock); + { + /* Here is where we need to reroute the device. To do this we need to uninitialize the stream and reinitialize it. */ + result = ma_device_reinit__aaudio(pDevice, (ma_device_type)pJob->data.device.aaudio.reroute.deviceType); + if (result != MA_SUCCESS) { + /* + Getting here means we failed to reroute the device. The best thing I can think of here is to + just stop the device. + */ + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[AAudio] Stopping device due to reroute failure."); + ma_device_stop(pDevice); + } } + ma_mutex_unlock(&pDevice->aaudio.rerouteLock); - return MA_SUCCESS; + return result; } #else /* Getting here means there is no AAudio backend so we need a no-op job implementation. */ @@ -40269,8 +41763,11 @@ static EM_BOOL ma_audio_worklet_process_callback__webaudio(int inputCount, const frameCount = pDevice->capture.internalPeriodSizeInFrames; } + /* + If this is called by the device has not yet been started we need to return early, making sure we output silence to + the output buffer. + */ if (ma_device_get_state(pDevice) != ma_device_state_started) { - /* Fill the output buffer with zero to avoid a noise sound */ for (int i = 0; i < outputCount; i += 1) { MA_ZERO_MEMORY(pOutputs[i].data, pOutputs[i].numberOfChannels * frameCount * sizeof(float)); } @@ -40292,7 +41789,9 @@ static EM_BOOL ma_audio_worklet_process_callback__webaudio(int inputCount, const if (outputCount > 0) { /* If it's a capture-only device, we'll need to output silence. */ if (pDevice->type == ma_device_type_capture) { - MA_ZERO_MEMORY(pOutputs[0].data, frameCount * pDevice->playback.internalChannels * sizeof(float)); + for (int i = 0; i < outputCount; i += 1) { + MA_ZERO_MEMORY(pOutputs[i].data, pOutputs[i].numberOfChannels * frameCount * sizeof(float)); + } } else { ma_device_process_pcm_frames_playback__webaudio(pDevice, frameCount, pDevice->webaudio.pIntermediaryBuffer); @@ -40302,6 +41801,14 @@ static EM_BOOL ma_audio_worklet_process_callback__webaudio(int inputCount, const pOutputs[0].data[frameCount*iChannel + iFrame] = pDevice->webaudio.pIntermediaryBuffer[iFrame*pDevice->playback.internalChannels + iChannel]; } } + + /* + Just above we output data to the first output buffer. Here we just make sure we're putting silence into any + remaining output buffers. + */ + for (int i = 1; i < outputCount; i += 1) { /* <-- Note that the counter starts at 1 instead of 0. */ + MA_ZERO_MEMORY(pOutputs[i].data, pOutputs[i].numberOfChannels * frameCount * sizeof(float)); + } } } @@ -40782,8 +42289,8 @@ static ma_result ma_context_uninit__webaudio(ma_context* pContext) /* Remove the global miniaudio object from window if there are no more references to it. */ EM_ASM({ if (typeof(window.miniaudio) !== 'undefined') { - miniaudio.unlock_event_types.map(function(event_type) { - document.removeEventListener(event_type, miniaudio.unlock, true); + window.miniaudio.unlock_event_types.map(function(event_type) { + document.removeEventListener(event_type, window.miniaudio.unlock, true); }); window.miniaudio.referenceCount -= 1; @@ -41236,13 +42743,13 @@ MA_API ma_result ma_device_post_init(ma_device* pDevice, ma_device_type deviceTy static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) { ma_device* pDevice = (ma_device*)pData; -#ifdef MA_WIN32 +#if defined(MA_WIN32) && !defined(MA_XBOX) HRESULT CoInitializeResult; #endif MA_ASSERT(pDevice != NULL); -#ifdef MA_WIN32 +#if defined(MA_WIN32) && !defined(MA_XBOX) CoInitializeResult = ma_CoInitializeEx(pDevice->pContext, NULL, MA_COINIT_VALUE); #endif @@ -41333,8 +42840,8 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) ma_event_signal(&pDevice->stopEvent); } -#ifdef MA_WIN32 - if (CoInitializeResult == S_OK) { +#if defined(MA_WIN32) && !defined(MA_XBOX) + if (CoInitializeResult == S_OK || CoInitializeResult == S_FALSE) { ma_CoUninitialize(pDevice->pContext); } #endif @@ -41358,67 +42865,92 @@ static ma_bool32 ma_device__is_initialized(ma_device* pDevice) static ma_result ma_context_uninit_backend_apis__win32(ma_context* pContext) { /* For some reason UWP complains when CoUninitialize() is called. I'm just not going to call it on UWP. */ -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) - if (pContext->win32.CoInitializeResult == S_OK) { - ma_CoUninitialize(pContext); + #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) + { + /* TODO: Remove this once the new single threaded backend system is in place in 0.12. */ + #if !defined(MA_XBOX) + { + if (pContext->win32.CoInitializeResult == S_OK || pContext->win32.CoInitializeResult == S_FALSE) { + ma_CoUninitialize(pContext); /* TODO: Remove this once the new single threaded backend system is in place in 0.12. */ + } + } + #endif + + #if defined(MA_WIN32_DESKTOP) + ma_dlclose(ma_context_get_log(pContext), pContext->win32.hUser32DLL); + ma_dlclose(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL); + #endif + + ma_dlclose(ma_context_get_log(pContext), pContext->win32.hOle32DLL); + } + #else + { + (void)pContext; } - - #if defined(MA_WIN32_DESKTOP) - ma_dlclose(ma_context_get_log(pContext), pContext->win32.hUser32DLL); - ma_dlclose(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL); #endif - ma_dlclose(ma_context_get_log(pContext), pContext->win32.hOle32DLL); -#else - (void)pContext; -#endif - return MA_SUCCESS; } static ma_result ma_context_init_backend_apis__win32(ma_context* pContext) { -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) - #if defined(MA_WIN32_DESKTOP) - /* User32.dll */ - pContext->win32.hUser32DLL = ma_dlopen(ma_context_get_log(pContext), "user32.dll"); - if (pContext->win32.hUser32DLL == NULL) { + /* + TODO: Reassess all of this stuff and move everything to the relevant backends. For example, I think + GetForegroundWindow() and GetDesktopWindow() are only used by the DirectSound backend. + */ + #if (defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK)) && !defined(MA_XBOX) + { + #if defined(MA_WIN32_DESKTOP) + { + /* User32.dll */ + pContext->win32.hUser32DLL = ma_dlopen(ma_context_get_log(pContext), "user32.dll"); + if (pContext->win32.hUser32DLL == NULL) { + return MA_FAILED_TO_INIT_BACKEND; + } + + pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetForegroundWindow"); + pContext->win32.GetDesktopWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetDesktopWindow"); + + + /* Advapi32.dll */ + pContext->win32.hAdvapi32DLL = ma_dlopen(ma_context_get_log(pContext), "advapi32.dll"); + if (pContext->win32.hAdvapi32DLL == NULL) { + return MA_FAILED_TO_INIT_BACKEND; + } + + pContext->win32.RegOpenKeyExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegOpenKeyExA"); + pContext->win32.RegCloseKey = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegCloseKey"); + pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegQueryValueExA"); + } + #endif + + /* Ole32.dll */ + pContext->win32.hOle32DLL = ma_dlopen(ma_context_get_log(pContext), "ole32.dll"); + if (pContext->win32.hOle32DLL == NULL) { return MA_FAILED_TO_INIT_BACKEND; } - pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetForegroundWindow"); - pContext->win32.GetDesktopWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetDesktopWindow"); - - - /* Advapi32.dll */ - pContext->win32.hAdvapi32DLL = ma_dlopen(ma_context_get_log(pContext), "advapi32.dll"); - if (pContext->win32.hAdvapi32DLL == NULL) { - return MA_FAILED_TO_INIT_BACKEND; - } - - pContext->win32.RegOpenKeyExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegOpenKeyExA"); - pContext->win32.RegCloseKey = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegCloseKey"); - pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegQueryValueExA"); + pContext->win32.CoInitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitialize"); + pContext->win32.CoInitializeEx = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitializeEx"); + pContext->win32.CoUninitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoUninitialize"); + pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoCreateInstance"); + pContext->win32.CoTaskMemFree = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoTaskMemFree"); + pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "PropVariantClear"); + pContext->win32.StringFromGUID2 = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "StringFromGUID2"); + } + #else + { + (void)pContext; /* Unused. */ + } #endif - /* Ole32.dll */ - pContext->win32.hOle32DLL = ma_dlopen(ma_context_get_log(pContext), "ole32.dll"); - if (pContext->win32.hOle32DLL == NULL) { - return MA_FAILED_TO_INIT_BACKEND; + /* TODO: Remove this once the new single threaded backend system is in place in 0.12. */ + #if !defined(MA_XBOX) + { + pContext->win32.CoInitializeResult = ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); } + #endif - pContext->win32.CoInitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitialize"); - pContext->win32.CoInitializeEx = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitializeEx"); - pContext->win32.CoUninitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoUninitialize"); - pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoCreateInstance"); - pContext->win32.CoTaskMemFree = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoTaskMemFree"); - pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "PropVariantClear"); - pContext->win32.StringFromGUID2 = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "StringFromGUID2"); -#else - (void)pContext; /* Unused. */ -#endif - - pContext->win32.CoInitializeResult = ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); return MA_SUCCESS; } #else @@ -44016,7 +45548,7 @@ static MA_INLINE void ma_pcm_s16_to_s32__reference(void* dst, const void* src, m ma_uint64 i; for (i = 0; i < count; i += 1) { - dst_s32[i] = src_s16[i] << 16; + dst_s32[i] = (ma_int32)src_s16[i] << 16; } (void)ditherMode; @@ -49347,15 +50879,15 @@ static /*__attribute__((noinline))*/ ma_result ma_gainer_process_pcm_frames_inte a += d; } } + + pFramesOut = ma_offset_ptr(pFramesOut, interpolatedFrameCount * sizeof(float)); + pFramesIn = ma_offset_ptr(pFramesIn, interpolatedFrameCount * sizeof(float)); } + frameCount -= interpolatedFrameCount; + /* Make sure the timer is updated. */ pGainer->t = (ma_uint32)ma_min(pGainer->t + interpolatedFrameCount, pGainer->config.smoothTimeInFrames); - - /* Adjust our arguments so the next part can work normally. */ - frameCount -= interpolatedFrameCount; - pFramesOut = ma_offset_ptr(pFramesOut, interpolatedFrameCount * sizeof(float)); - pFramesIn = ma_offset_ptr(pFramesIn, interpolatedFrameCount * sizeof(float)); } /* All we need to do here is apply the new gains using an optimized path. */ @@ -50783,13 +52315,16 @@ static float ma_calculate_angular_gain(ma_vec3f dirA, ma_vec3f dirB, float coneI MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, ma_spatializer_listener* pListener, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) { - ma_channel* pChannelMapIn = pSpatializer->pChannelMapIn; - ma_channel* pChannelMapOut = pListener->config.pChannelMapOut; + ma_channel* pChannelMapIn; + ma_channel* pChannelMapOut; - if (pSpatializer == NULL) { + if (pSpatializer == NULL || pListener == NULL) { return MA_INVALID_ARGS; } + pChannelMapIn = pSpatializer->pChannelMapIn; + pChannelMapOut = pListener->config.pChannelMapOut; + /* If we're not spatializing we need to run an optimized path. */ if (ma_atomic_load_i32(&pSpatializer->attenuationModel) == ma_attenuation_model_none) { if (ma_spatializer_listener_is_enabled(pListener)) { @@ -50834,23 +52369,17 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, We'll need the listener velocity for doppler pitch calculations. The speed of sound is defined by the listener, so we'll grab that here too. */ - if (pListener != NULL) { - listenerVel = ma_spatializer_listener_get_velocity(pListener); - speedOfSound = pListener->config.speedOfSound; - } else { - listenerVel = ma_vec3f_init_3f(0, 0, 0); - speedOfSound = MA_DEFAULT_SPEED_OF_SOUND; - } + listenerVel = ma_spatializer_listener_get_velocity(pListener); + speedOfSound = pListener->config.speedOfSound; - if (pListener == NULL || ma_spatializer_get_positioning(pSpatializer) == ma_positioning_relative) { - /* There's no listener or we're using relative positioning. */ + if (ma_spatializer_get_positioning(pSpatializer) == ma_positioning_relative) { relativePos = ma_spatializer_get_position(pSpatializer); relativeDir = ma_spatializer_get_direction(pSpatializer); } else { /* - We've found a listener and we're using absolute positioning. We need to transform the - sound's position and direction so that it's relative to listener. Later on we'll use - this for determining the factors to apply to each channel to apply the panning effect. + We're using absolute positioning. We need to transform the sound's position and + direction so that it's relative to listener. Later on we'll use this for determining + the factors to apply to each channel to apply the panning effect. */ ma_spatializer_get_relative_position_and_direction(pSpatializer, pListener, &relativePos, &relativeDir); } @@ -52885,7 +54414,7 @@ static ma_bool32 ma_is_spatial_channel_position(ma_channel channelPosition) return MA_FALSE; } - if (channelPosition >= MA_CHANNEL_AUX_0 && channelPosition <= MA_CHANNEL_AUX_31) { + if (channelPosition >= MA_CHANNEL_AUX_0) { return MA_FALSE; } @@ -56408,8 +57937,12 @@ MA_API size_t ma_channel_map_to_string(const ma_channel* pChannelMap, ma_uint32 } /* Null terminate. Don't increment the length here. */ - if (pBufferOut != NULL && bufferCap > len + 1) { - pBufferOut[len] = '\0'; + if (pBufferOut != NULL) { + if (bufferCap > len) { + pBufferOut[len] = '\0'; + } else if (bufferCap > 0) { + pBufferOut[bufferCap - 1] = '\0'; + } } return len; @@ -56620,7 +58153,7 @@ MA_API ma_result ma_rb_init_ex(size_t subbufferSizeInBytes, size_t subbufferCoun Here is where we allocate our own buffer. We always want to align this to MA_SIMD_ALIGNMENT for future SIMD optimization opportunity. To do this we need to make sure the stride is a multiple of MA_SIMD_ALIGNMENT. */ - pRB->subbufferStrideInBytes = (pRB->subbufferSizeInBytes + (MA_SIMD_ALIGNMENT-1)) & ~MA_SIMD_ALIGNMENT; + pRB->subbufferStrideInBytes = ma_align(pRB->subbufferSizeInBytes, MA_SIMD_ALIGNMENT); bufferSizeInBytes = (size_t)pRB->subbufferCount*pRB->subbufferStrideInBytes; pRB->pBuffer = ma_aligned_malloc(bufferSizeInBytes, MA_SIMD_ALIGNMENT, &pRB->allocationCallbacks); @@ -59515,7 +61048,7 @@ MA_API ma_result ma_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo } -#if !defined(MA_USE_WIN32_FILEIO) && (defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) && !defined(MA_NO_WIN32_FILEIO) && !defined(MA_POSIX)) +#if !defined(MA_USE_WIN32_FILEIO) && (defined(MA_WIN32) && (defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_NXDK)) && !defined(MA_NO_WIN32_FILEIO) && !defined(MA_POSIX)) #define MA_USE_WIN32_FILEIO #endif @@ -59592,25 +61125,34 @@ static ma_result ma_default_vfs_open__win32(ma_vfs* pVFS, const char* pFilePath, static ma_result ma_default_vfs_open_w__win32(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) { - HANDLE hFile; - DWORD dwDesiredAccess; - DWORD dwShareMode; - DWORD dwCreationDisposition; + #if !defined(MA_XBOX_NXDK) + { + HANDLE hFile; + DWORD dwDesiredAccess; + DWORD dwShareMode; + DWORD dwCreationDisposition; - (void)pVFS; + (void)pVFS; - /* Load some Win32 symbols dynamically so we can dynamically check for the existence of SetFilePointerEx. */ - ma_win32_fileio_init(); + /* Load some Win32 symbols dynamically so we can dynamically check for the existence of SetFilePointerEx. */ + ma_win32_fileio_init(); - ma_default_vfs__get_open_settings_win32(openMode, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition); + ma_default_vfs__get_open_settings_win32(openMode, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition); - hFile = CreateFileW(pFilePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) { - return ma_result_from_GetLastError(GetLastError()); + hFile = CreateFileW(pFilePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + return ma_result_from_GetLastError(GetLastError()); + } + + *pFile = hFile; + return MA_SUCCESS; } - - *pFile = hFile; - return MA_SUCCESS; + #else + { + /* No CreateFileW() available. */ + return MA_NOT_IMPLEMENTED; + } + #endif } static ma_result ma_default_vfs_close__win32(ma_vfs* pVFS, ma_vfs_file file) @@ -59781,19 +61323,28 @@ static ma_result ma_default_vfs_tell__win32(ma_vfs* pVFS, ma_vfs_file file, ma_i static ma_result ma_default_vfs_info__win32(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo) { - BY_HANDLE_FILE_INFORMATION fi; - BOOL result; - (void)pVFS; - result = GetFileInformationByHandle((HANDLE)file, &fi); - if (result == 0) { - return ma_result_from_GetLastError(GetLastError()); + #if !defined(MA_XBOX_NXDK) + { + BY_HANDLE_FILE_INFORMATION fi; + BOOL result; + + result = GetFileInformationByHandle((HANDLE)file, &fi); + if (result == 0) { + return ma_result_from_GetLastError(GetLastError()); + } + + pInfo->sizeInBytes = ((ma_uint64)fi.nFileSizeHigh << 32) | ((ma_uint64)fi.nFileSizeLow); + + return MA_SUCCESS; } - - pInfo->sizeInBytes = ((ma_uint64)fi.nFileSizeHigh << 32) | ((ma_uint64)fi.nFileSizeLow); - - return MA_SUCCESS; + #else + { + /* GetFileInformationByHandle() is unavailable. */ + return MA_NOT_IMPLEMENTED; + } + #endif } #else static ma_result ma_default_vfs_open__stdio(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) @@ -60131,6 +61682,8 @@ static ma_result ma_default_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* p static ma_result ma_default_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo) { + ma_result result; + if (pInfo == NULL) { return MA_INVALID_ARGS; } @@ -60142,10 +61695,42 @@ static ma_result ma_default_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_inf } #if defined(MA_USE_WIN32_FILEIO) - return ma_default_vfs_info__win32(pVFS, file, pInfo); + result = ma_default_vfs_info__win32(pVFS, file, pInfo); #else - return ma_default_vfs_info__stdio(pVFS, file, pInfo); + result = ma_default_vfs_info__stdio(pVFS, file, pInfo); #endif + + if (result == MA_NOT_IMPLEMENTED) { + /* Not implemented. Fall back to seek/tell/seek. */ + ma_int64 cursor; + ma_int64 sizeInBytes; + + result = ma_default_vfs_tell(pVFS, file, &cursor); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_default_vfs_seek(pVFS, file, 0, ma_seek_origin_end); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_default_vfs_tell(pVFS, file, &sizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + pInfo->sizeInBytes = sizeInBytes; + + result = ma_default_vfs_seek(pVFS, file, cursor, ma_seek_origin_start); + if (result != MA_SUCCESS) { + return result; + } + + MA_ASSERT(result == MA_SUCCESS); + } + + return result; } @@ -60324,6 +61909,8 @@ Decoding and Encoding Headers. These are auto-generated from a tool. **************************************************************************************************************************************************************/ #if !defined(MA_NO_WAV) && (!defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING)) +#define MA_HAS_WAV + /* dr_wav_h begin */ #ifndef ma_dr_wav_h #define ma_dr_wav_h @@ -60333,8 +61920,8 @@ extern "C" { #define MA_DR_WAV_STRINGIFY(x) #x #define MA_DR_WAV_XSTRINGIFY(x) MA_DR_WAV_STRINGIFY(x) #define MA_DR_WAV_VERSION_MAJOR 0 -#define MA_DR_WAV_VERSION_MINOR 13 -#define MA_DR_WAV_VERSION_REVISION 18 +#define MA_DR_WAV_VERSION_MINOR 14 +#define MA_DR_WAV_VERSION_REVISION 4 #define MA_DR_WAV_VERSION_STRING MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_MAJOR) "." MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_MINOR) "." MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_REVISION) #include #define MA_DR_WAVE_FORMAT_PCM 0x1 @@ -60350,8 +61937,9 @@ MA_API void ma_dr_wav_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* p MA_API const char* ma_dr_wav_version_string(void); typedef enum { - ma_dr_wav_seek_origin_start, - ma_dr_wav_seek_origin_current + MA_DR_WAV_SEEK_SET, + MA_DR_WAV_SEEK_CUR, + MA_DR_WAV_SEEK_END } ma_dr_wav_seek_origin; typedef enum { @@ -60388,6 +61976,7 @@ MA_API ma_uint16 ma_dr_wav_fmt_get_format(const ma_dr_wav_fmt* pFMT); typedef size_t (* ma_dr_wav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); typedef size_t (* ma_dr_wav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite); typedef ma_bool32 (* ma_dr_wav_seek_proc)(void* pUserData, int offset, ma_dr_wav_seek_origin origin); +typedef ma_bool32 (* ma_dr_wav_tell_proc)(void* pUserData, ma_int64* pCursor); typedef ma_uint64 (* ma_dr_wav_chunk_proc)(void* pChunkUserData, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pReadSeekUserData, const ma_dr_wav_chunk_header* pChunkHeader, ma_dr_wav_container container, const ma_dr_wav_fmt* pFMT); typedef struct { @@ -60432,6 +62021,11 @@ typedef enum ma_dr_wav_metadata_type_list_info_genre = 1 << 15, ma_dr_wav_metadata_type_list_info_album = 1 << 16, ma_dr_wav_metadata_type_list_info_tracknumber = 1 << 17, + ma_dr_wav_metadata_type_list_info_location = 1 << 18, + ma_dr_wav_metadata_type_list_info_organization = 1 << 19, + ma_dr_wav_metadata_type_list_info_keywords = 1 << 20, + ma_dr_wav_metadata_type_list_info_medium = 1 << 21, + ma_dr_wav_metadata_type_list_info_description = 1 << 22, ma_dr_wav_metadata_type_list_all_info_strings = ma_dr_wav_metadata_type_list_info_software | ma_dr_wav_metadata_type_list_info_copyright | ma_dr_wav_metadata_type_list_info_title @@ -60440,7 +62034,12 @@ typedef enum | ma_dr_wav_metadata_type_list_info_date | ma_dr_wav_metadata_type_list_info_genre | ma_dr_wav_metadata_type_list_info_album - | ma_dr_wav_metadata_type_list_info_tracknumber, + | ma_dr_wav_metadata_type_list_info_tracknumber + | ma_dr_wav_metadata_type_list_info_location + | ma_dr_wav_metadata_type_list_info_organization + | ma_dr_wav_metadata_type_list_info_keywords + | ma_dr_wav_metadata_type_list_info_medium + | ma_dr_wav_metadata_type_list_info_description, ma_dr_wav_metadata_type_list_all_adtl = ma_dr_wav_metadata_type_list_label | ma_dr_wav_metadata_type_list_note | ma_dr_wav_metadata_type_list_labelled_cue_region, @@ -60457,8 +62056,8 @@ typedef struct { ma_uint32 cuePointId; ma_uint32 type; - ma_uint32 firstSampleByteOffset; - ma_uint32 lastSampleByteOffset; + ma_uint32 firstSampleOffset; + ma_uint32 lastSampleOffset; ma_uint32 sampleFraction; ma_uint32 playCount; } ma_dr_wav_smpl_loop; @@ -60493,7 +62092,7 @@ typedef struct ma_uint8 dataChunkId[4]; ma_uint32 chunkStart; ma_uint32 blockStart; - ma_uint32 sampleByteOffset; + ma_uint32 sampleOffset; } ma_dr_wav_cue_point; typedef struct { @@ -60595,6 +62194,7 @@ typedef struct ma_dr_wav_read_proc onRead; ma_dr_wav_write_proc onWrite; ma_dr_wav_seek_proc onSeek; + ma_dr_wav_tell_proc onTell; void* pUserData; ma_allocation_callbacks allocationCallbacks; ma_dr_wav_container container; @@ -60637,9 +62237,9 @@ typedef struct ma_bool8 isUnsigned; } aiff; } ma_dr_wav; -MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, ma_dr_wav_chunk_proc onChunk, void* pReadSeekTellUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_wav_init_write(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_dr_wav_write_proc onWrite, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_wav_init_write_sequential(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, ma_dr_wav_write_proc onWrite, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_wav_init_write_sequential_pcm_frames(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_uint64 totalPCMFrameCount, ma_dr_wav_write_proc onWrite, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); @@ -60711,9 +62311,9 @@ MA_API ma_bool32 ma_dr_wav_init_memory_write(ma_dr_wav* pWav, void** ppData, siz MA_API ma_bool32 ma_dr_wav_init_memory_write_sequential(ma_dr_wav* pWav, void** ppData, size_t* pDataSize, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_wav_init_memory_write_sequential_pcm_frames(ma_dr_wav* pWav, void** ppData, size_t* pDataSize, const ma_dr_wav_data_format* pFormat, ma_uint64 totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_WAV_NO_CONVERSION_API -MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_WAV_NO_STDIO MA_API ma_int16* ma_dr_wav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); MA_API float* ma_dr_wav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); @@ -60744,6 +62344,8 @@ MA_API ma_bool32 ma_dr_wav_fourcc_equal(const ma_uint8* a, const char* b); #endif /* MA_NO_WAV */ #if !defined(MA_NO_FLAC) && !defined(MA_NO_DECODING) +#define MA_HAS_FLAC + /* dr_flac_h begin */ #ifndef ma_dr_flac_h #define ma_dr_flac_h @@ -60753,8 +62355,8 @@ extern "C" { #define MA_DR_FLAC_STRINGIFY(x) #x #define MA_DR_FLAC_XSTRINGIFY(x) MA_DR_FLAC_STRINGIFY(x) #define MA_DR_FLAC_VERSION_MAJOR 0 -#define MA_DR_FLAC_VERSION_MINOR 12 -#define MA_DR_FLAC_VERSION_REVISION 43 +#define MA_DR_FLAC_VERSION_MINOR 13 +#define MA_DR_FLAC_VERSION_REVISION 3 #define MA_DR_FLAC_VERSION_STRING MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_MAJOR) "." MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_MINOR) "." MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_REVISION) #include #if defined(_MSC_VER) && _MSC_VER >= 1700 @@ -60817,8 +62419,9 @@ typedef enum } ma_dr_flac_container; typedef enum { - ma_dr_flac_seek_origin_start, - ma_dr_flac_seek_origin_current + MA_DR_FLAC_SEEK_SET, + MA_DR_FLAC_SEEK_CUR, + MA_DR_FLAC_SEEK_END } ma_dr_flac_seek_origin; typedef struct { @@ -60841,8 +62444,9 @@ typedef struct typedef struct { ma_uint32 type; - const void* pRawData; ma_uint32 rawDataSize; + ma_uint64 rawDataOffset; + const void* pRawData; union { ma_dr_flac_streaminfo streaminfo; @@ -60888,12 +62492,14 @@ typedef struct ma_uint32 colorDepth; ma_uint32 indexColorCount; ma_uint32 pictureDataSize; + ma_uint64 pictureDataOffset; const ma_uint8* pPictureData; } picture; } data; } ma_dr_flac_metadata; typedef size_t (* ma_dr_flac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); typedef ma_bool32 (* ma_dr_flac_seek_proc)(void* pUserData, int offset, ma_dr_flac_seek_origin origin); +typedef ma_bool32 (* ma_dr_flac_tell_proc)(void* pUserData, ma_int64* pCursor); typedef void (* ma_dr_flac_meta_proc)(void* pUserData, ma_dr_flac_metadata* pMetadata); typedef struct { @@ -60905,6 +62511,7 @@ typedef struct { ma_dr_flac_read_proc onRead; ma_dr_flac_seek_proc onSeek; + ma_dr_flac_tell_proc onTell; void* pUserData; size_t unalignedByteCount; ma_dr_flac_cache_t unalignedCache; @@ -60964,10 +62571,10 @@ typedef struct ma_dr_flac_bs bs; ma_uint8 pExtraData[1]; } ma_dr_flac; -MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); MA_API void ma_dr_flac_close(ma_dr_flac* pFlac); MA_API ma_uint64 ma_dr_flac_read_pcm_frames_s32(ma_dr_flac* pFlac, ma_uint64 framesToRead, ma_int32* pBufferOut); MA_API ma_uint64 ma_dr_flac_read_pcm_frames_s16(ma_dr_flac* pFlac, ma_uint64 framesToRead, ma_int16* pBufferOut); @@ -60981,9 +62588,9 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata_w(const wchar_t* pFileName #endif MA_API ma_dr_flac* ma_dr_flac_open_memory(const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_dr_flac* ma_dr_flac_open_memory_with_metadata(const void* pData, size_t dataSize, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_FLAC_NO_STDIO MA_API ma_int32* ma_dr_flac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_int16* ma_dr_flac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); @@ -61031,6 +62638,14 @@ MA_API ma_bool32 ma_dr_flac_next_cuesheet_track(ma_dr_flac_cuesheet_track_iterat #endif /* MA_NO_FLAC */ #if !defined(MA_NO_MP3) && !defined(MA_NO_DECODING) +#define MA_HAS_MP3 + +#ifndef MA_DR_MP3_NO_SIMD + #if (defined(MA_NO_NEON) && defined(MA_ARM)) || (defined(MA_NO_SSE2) && (defined(MA_X86) || defined(MA_X64))) + #define MA_DR_MP3_NO_SIMD + #endif +#endif + /* dr_mp3_h begin */ #ifndef ma_dr_mp3_h #define ma_dr_mp3_h @@ -61040,31 +62655,57 @@ extern "C" { #define MA_DR_MP3_STRINGIFY(x) #x #define MA_DR_MP3_XSTRINGIFY(x) MA_DR_MP3_STRINGIFY(x) #define MA_DR_MP3_VERSION_MAJOR 0 -#define MA_DR_MP3_VERSION_MINOR 6 -#define MA_DR_MP3_VERSION_REVISION 40 +#define MA_DR_MP3_VERSION_MINOR 7 +#define MA_DR_MP3_VERSION_REVISION 3 #define MA_DR_MP3_VERSION_STRING MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_MAJOR) "." MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_MINOR) "." MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_REVISION) #include #define MA_DR_MP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152 #define MA_DR_MP3_MAX_SAMPLES_PER_FRAME (MA_DR_MP3_MAX_PCM_FRAMES_PER_MP3_FRAME*2) MA_API void ma_dr_mp3_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision); MA_API const char* ma_dr_mp3_version_string(void); +#define MA_DR_MP3_MAX_BITRESERVOIR_BYTES 511 +#define MA_DR_MP3_MAX_FREE_FORMAT_FRAME_SIZE 2304 +#define MA_DR_MP3_MAX_L3_FRAME_PAYLOAD_BYTES MA_DR_MP3_MAX_FREE_FORMAT_FRAME_SIZE typedef struct { - int frame_bytes, channels, hz, layer, bitrate_kbps; + int frame_bytes, channels, sample_rate, layer, bitrate_kbps; } ma_dr_mp3dec_frame_info; typedef struct +{ + const ma_uint8 *buf; + int pos, limit; +} ma_dr_mp3_bs; +typedef struct +{ + const ma_uint8 *sfbtab; + ma_uint16 part_23_length, big_values, scalefac_compress; + ma_uint8 global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb; + ma_uint8 table_select[3], region_count[3], subblock_gain[3]; + ma_uint8 preflag, scalefac_scale, count1_table, scfsi; +} ma_dr_mp3_L3_gr_info; +typedef struct +{ + ma_dr_mp3_bs bs; + ma_uint8 maindata[MA_DR_MP3_MAX_BITRESERVOIR_BYTES + MA_DR_MP3_MAX_L3_FRAME_PAYLOAD_BYTES]; + ma_dr_mp3_L3_gr_info gr_info[4]; + float grbuf[2][576], scf[40], syn[18 + 15][2*32]; + ma_uint8 ist_pos[2][39]; +} ma_dr_mp3dec_scratch; +typedef struct { float mdct_overlap[2][9*32], qmf_state[15*2*32]; int reserv, free_format_bytes; ma_uint8 header[4], reserv_buf[511]; + ma_dr_mp3dec_scratch scratch; } ma_dr_mp3dec; MA_API void ma_dr_mp3dec_init(ma_dr_mp3dec *dec); MA_API int ma_dr_mp3dec_decode_frame(ma_dr_mp3dec *dec, const ma_uint8 *mp3, int mp3_bytes, void *pcm, ma_dr_mp3dec_frame_info *info); MA_API void ma_dr_mp3dec_f32_to_s16(const float *in, ma_int16 *out, size_t num_samples); typedef enum { - ma_dr_mp3_seek_origin_start, - ma_dr_mp3_seek_origin_current + MA_DR_MP3_SEEK_SET, + MA_DR_MP3_SEEK_CUR, + MA_DR_MP3_SEEK_END } ma_dr_mp3_seek_origin; typedef struct { @@ -61073,8 +62714,24 @@ typedef struct ma_uint16 mp3FramesToDiscard; ma_uint16 pcmFramesToDiscard; } ma_dr_mp3_seek_point; +typedef enum +{ + MA_DR_MP3_METADATA_TYPE_ID3V1, + MA_DR_MP3_METADATA_TYPE_ID3V2, + MA_DR_MP3_METADATA_TYPE_APE, + MA_DR_MP3_METADATA_TYPE_XING, + MA_DR_MP3_METADATA_TYPE_VBRI +} ma_dr_mp3_metadata_type; +typedef struct +{ + ma_dr_mp3_metadata_type type; + const void* pRawData; + size_t rawDataSize; +} ma_dr_mp3_metadata; typedef size_t (* ma_dr_mp3_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); typedef ma_bool32 (* ma_dr_mp3_seek_proc)(void* pUserData, int offset, ma_dr_mp3_seek_origin origin); +typedef ma_bool32 (* ma_dr_mp3_tell_proc)(void* pUserData, ma_int64* pCursor); +typedef void (* ma_dr_mp3_meta_proc)(void* pUserData, const ma_dr_mp3_metadata* pMetadata); typedef struct { ma_uint32 channels; @@ -61087,7 +62744,9 @@ typedef struct ma_uint32 sampleRate; ma_dr_mp3_read_proc onRead; ma_dr_mp3_seek_proc onSeek; + ma_dr_mp3_meta_proc onMeta; void* pUserData; + void* pUserDataMeta; ma_allocation_callbacks allocationCallbacks; ma_uint32 mp3FrameChannels; ma_uint32 mp3FrameSampleRate; @@ -61096,13 +62755,20 @@ typedef struct ma_uint8 pcmFrames[sizeof(float)*MA_DR_MP3_MAX_SAMPLES_PER_FRAME]; ma_uint64 currentPCMFrame; ma_uint64 streamCursor; + ma_uint64 streamLength; + ma_uint64 streamStartOffset; ma_dr_mp3_seek_point* pSeekPoints; ma_uint32 seekPointCount; + ma_uint32 delayInPCMFrames; + ma_uint32 paddingInPCMFrames; + ma_uint64 totalPCMFrameCount; + ma_bool32 isVBR; + ma_bool32 isCBR; size_t dataSize; size_t dataCapacity; size_t dataConsumed; ma_uint8* pData; - ma_bool32 atEnd : 1; + ma_bool32 atEnd; struct { const ma_uint8* pData; @@ -61110,9 +62776,12 @@ typedef struct size_t currentReadPos; } memory; } ma_dr_mp3; -MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, ma_dr_mp3_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_mp3_init_memory_with_metadata(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_MP3_NO_STDIO +MA_API ma_bool32 ma_dr_mp3_init_file_with_metadata(ma_dr_mp3* pMP3, const char* pFilePath, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_mp3_init_file_with_metadata_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_mp3_init_file(ma_dr_mp3* pMP3, const char* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_mp3_init_file_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks); #endif @@ -61125,8 +62794,8 @@ MA_API ma_uint64 ma_dr_mp3_get_mp3_frame_count(ma_dr_mp3* pMP3); MA_API ma_bool32 ma_dr_mp3_get_mp3_and_pcm_frame_count(ma_dr_mp3* pMP3, ma_uint64* pMP3FrameCount, ma_uint64* pPCMFrameCount); MA_API ma_bool32 ma_dr_mp3_calculate_seek_points(ma_dr_mp3* pMP3, ma_uint32* pSeekPointCount, ma_dr_mp3_seek_point* pSeekPoints); MA_API ma_bool32 ma_dr_mp3_bind_seek_table(ma_dr_mp3* pMP3, ma_uint32 seekPointCount, ma_dr_mp3_seek_point* pSeekPoints); -MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); MA_API float* ma_dr_mp3_open_memory_and_read_pcm_frames_f32(const void* pData, size_t dataSize, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_int16* ma_dr_mp3_open_memory_and_read_pcm_frames_s16(const void* pData, size_t dataSize, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_MP3_NO_STDIO @@ -61591,7 +63260,6 @@ static ma_result ma_decoder_init_custom_from_memory__internal(const void* pData, /* WAV */ #ifdef ma_dr_wav_h -#define MA_HAS_WAV typedef struct { @@ -61679,8 +63347,10 @@ static ma_bool32 ma_wav_dr_callback__seek(void* pUserData, int offset, ma_dr_wav MA_ASSERT(pWav != NULL); maSeekOrigin = ma_seek_origin_start; - if (origin == ma_dr_wav_seek_origin_current) { - maSeekOrigin = ma_seek_origin_current; + if (origin == MA_DR_WAV_SEEK_CUR) { + maSeekOrigin = ma_seek_origin_current; + } else if (origin == MA_DR_WAV_SEEK_END) { + maSeekOrigin = ma_seek_origin_end; } result = pWav->onSeek(pWav->pReadSeekTellUserData, offset, maSeekOrigin); @@ -61690,6 +63360,26 @@ static ma_bool32 ma_wav_dr_callback__seek(void* pUserData, int offset, ma_dr_wav return MA_TRUE; } + +static ma_bool32 ma_wav_dr_callback__tell(void* pUserData, ma_int64* pCursor) +{ + ma_wav* pWav = (ma_wav*)pUserData; + ma_result result; + + MA_ASSERT(pWav != NULL); + MA_ASSERT(pCursor != NULL); + + if (pWav->onTell == NULL) { + return MA_FALSE; /* Not implemented. */ + } + + result = pWav->onTell(pWav->pReadSeekTellUserData, pCursor); + if (result != MA_SUCCESS) { + return MA_FALSE; /* Failed to tell. */ + } + + return MA_TRUE; +} #endif static ma_result ma_wav_init_internal(const ma_decoding_backend_config* pConfig, ma_wav* pWav) @@ -61784,7 +63474,7 @@ MA_API ma_result ma_wav_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_p { ma_bool32 wavResult; - wavResult = ma_dr_wav_init(&pWav->dr, ma_wav_dr_callback__read, ma_wav_dr_callback__seek, pWav, pAllocationCallbacks); + wavResult = ma_dr_wav_init(&pWav->dr, ma_wav_dr_callback__read, ma_wav_dr_callback__seek, ma_wav_dr_callback__tell, pWav, pAllocationCallbacks); if (wavResult != MA_TRUE) { return MA_INVALID_FILE; } @@ -62275,7 +63965,6 @@ static ma_result ma_decoder_init_wav_from_memory__internal(const void* pData, si /* FLAC */ #ifdef ma_dr_flac_h -#define MA_HAS_FLAC typedef struct { @@ -62363,8 +64052,10 @@ static ma_bool32 ma_flac_dr_callback__seek(void* pUserData, int offset, ma_dr_fl MA_ASSERT(pFlac != NULL); maSeekOrigin = ma_seek_origin_start; - if (origin == ma_dr_flac_seek_origin_current) { - maSeekOrigin = ma_seek_origin_current; + if (origin == MA_DR_FLAC_SEEK_CUR) { + maSeekOrigin = ma_seek_origin_current; + } else if (origin == MA_DR_FLAC_SEEK_END) { + maSeekOrigin = ma_seek_origin_end; } result = pFlac->onSeek(pFlac->pReadSeekTellUserData, offset, maSeekOrigin); @@ -62374,6 +64065,26 @@ static ma_bool32 ma_flac_dr_callback__seek(void* pUserData, int offset, ma_dr_fl return MA_TRUE; } + +static ma_bool32 ma_flac_dr_callback__tell(void* pUserData, ma_int64* pCursor) +{ + ma_flac* pFlac = (ma_flac*)pUserData; + ma_result result; + + MA_ASSERT(pFlac != NULL); + MA_ASSERT(pCursor != NULL); + + if (pFlac->onTell == NULL) { + return MA_FALSE; /* Not implemented. */ + } + + result = pFlac->onTell(pFlac->pReadSeekTellUserData, pCursor); + if (result != MA_SUCCESS) { + return MA_FALSE; /* Failed to tell. */ + } + + return MA_TRUE; +} #endif static ma_result ma_flac_init_internal(const ma_decoding_backend_config* pConfig, ma_flac* pFlac) @@ -62425,7 +64136,7 @@ MA_API ma_result ma_flac_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_ #if !defined(MA_NO_FLAC) { - pFlac->dr = ma_dr_flac_open(ma_flac_dr_callback__read, ma_flac_dr_callback__seek, pFlac, pAllocationCallbacks); + pFlac->dr = ma_dr_flac_open(ma_flac_dr_callback__read, ma_flac_dr_callback__seek, ma_flac_dr_callback__tell, pFlac, pAllocationCallbacks); if (pFlac->dr == NULL) { return MA_INVALID_FILE; } @@ -62897,7 +64608,6 @@ static ma_result ma_decoder_init_flac_from_memory__internal(const void* pData, s /* MP3 */ #ifdef ma_dr_mp3_h -#define MA_HAS_MP3 typedef struct { @@ -62986,9 +64696,12 @@ static ma_bool32 ma_mp3_dr_callback__seek(void* pUserData, int offset, ma_dr_mp3 MA_ASSERT(pMP3 != NULL); - maSeekOrigin = ma_seek_origin_start; - if (origin == ma_dr_mp3_seek_origin_current) { - maSeekOrigin = ma_seek_origin_current; + if (origin == MA_DR_MP3_SEEK_SET) { + maSeekOrigin = ma_seek_origin_start; + } else if (origin == MA_DR_MP3_SEEK_END) { + maSeekOrigin = ma_seek_origin_end; + } else { + maSeekOrigin = ma_seek_origin_current; } result = pMP3->onSeek(pMP3->pReadSeekTellUserData, offset, maSeekOrigin); @@ -62998,6 +64711,21 @@ static ma_bool32 ma_mp3_dr_callback__seek(void* pUserData, int offset, ma_dr_mp3 return MA_TRUE; } + +static ma_bool32 ma_mp3_dr_callback__tell(void* pUserData, ma_int64* pCursor) +{ + ma_mp3* pMP3 = (ma_mp3*)pUserData; + ma_result result; + + MA_ASSERT(pMP3 != NULL); + + result = pMP3->onTell(pMP3->pReadSeekTellUserData, pCursor); + if (result != MA_SUCCESS) { + return MA_FALSE; + } + + return MA_TRUE; +} #endif static ma_result ma_mp3_init_internal(const ma_decoding_backend_config* pConfig, ma_mp3* pMP3) @@ -63098,7 +64826,7 @@ MA_API ma_result ma_mp3_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_p { ma_bool32 mp3Result; - mp3Result = ma_dr_mp3_init(&pMP3->dr, ma_mp3_dr_callback__read, ma_mp3_dr_callback__seek, pMP3, pAllocationCallbacks); + mp3Result = ma_dr_mp3_init(&pMP3->dr, ma_mp3_dr_callback__read, ma_mp3_dr_callback__seek, ma_mp3_dr_callback__tell, NULL, pMP3, pAllocationCallbacks); if (mp3Result != MA_TRUE) { return MA_INVALID_FILE; } @@ -64557,11 +66285,9 @@ static ma_result ma_decoder_init__internal(ma_decoder_read_proc onRead, ma_decod We use trial and error to open a decoder. We prioritize custom decoders so that if they implement the same encoding format they take priority over the built-in decoders. */ + result = ma_decoder_init_custom__internal(pConfig, pDecoder); if (result != MA_SUCCESS) { - result = ma_decoder_init_custom__internal(pConfig, pDecoder); - if (result != MA_SUCCESS) { - onSeek(pDecoder, 0, ma_seek_origin_start); - } + onSeek(pDecoder, 0, ma_seek_origin_start); } /* @@ -64825,14 +66551,6 @@ MA_API ma_result ma_decoder_init_memory(const void* pData, size_t dataSize, cons /* Initialization was successful. Finish up. */ result = ma_decoder__postinit(&config, pDecoder); if (result != MA_SUCCESS) { - /* - The backend was initialized successfully, but for some reason post-initialization failed. This is most likely - due to an out of memory error. We're going to abort with an error here and not try to recover. - */ - if (pDecoder->pBackendVTable != NULL && pDecoder->pBackendVTable->onUninit != NULL) { - pDecoder->pBackendVTable->onUninit(pDecoder->pBackendUserData, &pDecoder->pBackend, &pDecoder->allocationCallbacks); - } - return result; } } else { @@ -64997,14 +66715,16 @@ static ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* e ext1 = extension; ext2 = ma_path_extension_w(path); -#if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__) - return _wcsicmp(ext1, ext2) == 0; -#else - /* - I'm not aware of a wide character version of strcasecmp(). I'm therefore converting the extensions to multibyte strings and comparing those. This - isn't the most efficient way to do it, but it should work OK. - */ + #if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__)) && !defined(MA_XBOX_NXDK) { + return _wcsicmp(ext1, ext2) == 0; + } + #elif !defined(MA_XBOX_NXDK) && !defined(MA_DOS) + { + /* + I'm not aware of a wide character version of strcasecmp(). I'm therefore converting the extensions to multibyte strings and comparing those. This + isn't the most efficient way to do it, but it should work OK. + */ char ext1MB[4096]; char ext2MB[4096]; const wchar_t* pext1 = ext1; @@ -65024,7 +66744,13 @@ static ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* e return strcasecmp(ext1MB, ext2MB) == 0; } -#endif + #else + { + /* Getting here means we don't have a way to do a case-sensitive comparison for wide strings. Fall back to a simple case-sensitive comparison. */ + /* TODO: Implement our own wchar_t-to-char conversion routine and then use the char* version for comparing. */ + return ma_wcscmp(ext1, ext2) == 0; + } + #endif } #endif /* MA_HAS_PATH_API */ @@ -65125,11 +66851,9 @@ MA_API ma_result ma_decoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const We use trial and error to open a decoder. We prioritize custom decoders so that if they implement the same encoding format they take priority over the built-in decoders. */ + result = ma_decoder_init_custom__internal(&config, pDecoder); if (result != MA_SUCCESS) { - result = ma_decoder_init_custom__internal(&config, pDecoder); - if (result != MA_SUCCESS) { - ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); - } + ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); } /* @@ -65258,11 +66982,9 @@ MA_API ma_result ma_decoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, c We use trial and error to open a decoder. We prioritize custom decoders so that if they implement the same encoding format they take priority over the built-in decoders. */ + result = ma_decoder_init_custom__internal(&config, pDecoder); if (result != MA_SUCCESS) { - result = ma_decoder_init_custom__internal(&config, pDecoder); - if (result != MA_SUCCESS) { - ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); - } + ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); } /* @@ -65444,14 +67166,6 @@ MA_API ma_result ma_decoder_init_file(const char* pFilePath, const ma_decoder_co /* Initialization was successful. Finish up. */ result = ma_decoder__postinit(&config, pDecoder); if (result != MA_SUCCESS) { - /* - The backend was initialized successfully, but for some reason post-initialization failed. This is most likely - due to an out of memory error. We're going to abort with an error here and not try to recover. - */ - if (pDecoder->pBackendVTable != NULL && pDecoder->pBackendVTable->onUninit != NULL) { - pDecoder->pBackendVTable->onUninit(pDecoder->pBackendUserData, &pDecoder->pBackend, &pDecoder->allocationCallbacks); - } - return result; } } else { @@ -65594,14 +67308,6 @@ MA_API ma_result ma_decoder_init_file_w(const wchar_t* pFilePath, const ma_decod /* Initialization was successful. Finish up. */ result = ma_decoder__postinit(&config, pDecoder); if (result != MA_SUCCESS) { - /* - The backend was initialized successfully, but for some reason post-initialization failed. This is most likely - due to an out of memory error. We're going to abort with an error here and not try to recover. - */ - if (pDecoder->pBackendVTable != NULL && pDecoder->pBackendVTable->onUninit != NULL) { - pDecoder->pBackendVTable->onUninit(pDecoder->pBackendUserData, &pDecoder->pBackend, &pDecoder->allocationCallbacks); - } - return result; } } else { @@ -66119,10 +67825,18 @@ static ma_bool32 ma_encoder__internal_on_seek_wav(void* pUserData, int offset, m { ma_encoder* pEncoder = (ma_encoder*)pUserData; ma_result result; + ma_seek_origin maSeekOrigin; MA_ASSERT(pEncoder != NULL); - result = pEncoder->onSeek(pEncoder, offset, (origin == ma_dr_wav_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current); + maSeekOrigin = ma_seek_origin_start; + if (origin == MA_DR_WAV_SEEK_CUR) { + maSeekOrigin = ma_seek_origin_current; + } else if (origin == MA_DR_WAV_SEEK_END) { + maSeekOrigin = ma_seek_origin_end; + } + + result = pEncoder->onSeek(pEncoder, offset, maSeekOrigin); if (result != MA_SUCCESS) { return MA_FALSE; } else { @@ -67644,7 +69358,7 @@ static MA_INLINE ma_uint32 ma_hash_getblock(const ma_uint32* blocks, int i) ma_uint32 block; /* Try silencing a sanitization warning about unaligned access by doing a memcpy() instead of assignment. */ - MA_COPY_MEMORY(&block, ma_offset_ptr(blocks, i * sizeof(block)), sizeof(block)); + MA_COPY_MEMORY(&block, ma_offset_ptr(blocks, i * (int) sizeof(block)), sizeof(block)); if (ma_is_little_endian()) { return block; @@ -67720,7 +69434,7 @@ static ma_uint32 ma_hash_string_32(const char* str) static ma_uint32 ma_hash_string_w_32(const wchar_t* str) { - return ma_hash_32(str, (int)wcslen(str) * sizeof(*str), MA_DEFAULT_HASH_SEED); + return ma_hash_32(str, (int)ma_wcslen(str) * sizeof(*str), MA_DEFAULT_HASH_SEED); } @@ -67880,6 +69594,7 @@ static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_ return ma_resource_manager_data_buffer_node_find_min(pDataBufferNode->pChildHi); } +#if 0 /* Currently unused, but might make use of this later. */ static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_buffer_node_find_inorder_predecessor(ma_resource_manager_data_buffer_node* pDataBufferNode) { MA_ASSERT(pDataBufferNode != NULL); @@ -67887,6 +69602,7 @@ static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_ return ma_resource_manager_data_buffer_node_find_max(pDataBufferNode->pChildLo); } +#endif static ma_result ma_resource_manager_data_buffer_node_remove(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode) { @@ -68237,6 +69953,7 @@ MA_API ma_resource_manager_config ma_resource_manager_config_init(void) config.decodedSampleRate = 0; config.jobThreadCount = 1; /* A single miniaudio-managed job thread by default. */ config.jobQueueCapacity = MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_CAPACITY; + config.resampling = ma_resampler_config_init(ma_format_unknown, 0, 0, 0, ma_resample_algorithm_linear); /* Format/channels/rate doesn't matter here. */ /* Flags. */ config.flags = 0; @@ -68490,6 +70207,7 @@ static ma_decoder_config ma_resource_manager__init_decoder_config(ma_resource_ma config.ppCustomBackendVTables = pResourceManager->config.ppCustomDecodingBackendVTables; config.customBackendCount = pResourceManager->config.customDecodingBackendCount; config.pCustomBackendUserData = pResourceManager->config.pCustomDecodingBackendUserData; + config.resampling = pResourceManager->config.resampling; return config; } @@ -69009,16 +70727,19 @@ static ma_result ma_resource_manager_data_buffer_node_acquire_critical_section(m /* Failed to post job. Probably ran out of memory. */ ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE job. %s.\n", ma_result_description(result)); - /* - Fences were acquired before posting the job, but since the job was not able to - be posted, we need to make sure we release them so nothing gets stuck waiting. - */ - if (pInitFence != NULL) { ma_fence_release(pInitFence); } - if (pDoneFence != NULL) { ma_fence_release(pDoneFence); } - if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { ma_resource_manager_inline_notification_uninit(pInitNotification); } else { + /* + Fences were acquired before posting the job, but since the job was not able to + be posted, we need to make sure we release them so nothing gets stuck waiting. + + In the WAIT_INIT case, these will have already been released in ma_job_process() + so we should only release fences in this branch. + */ + if (pInitFence != NULL) { ma_fence_release(pInitFence); } + if (pDoneFence != NULL) { ma_fence_release(pDoneFence); } + /* These will have been freed by the job thread, but with WAIT_INIT they will already have happened since the job has already been handled. */ ma_free(pFilePathCopy, &pResourceManager->config.allocationCallbacks); ma_free(pFilePathWCopy, &pResourceManager->config.allocationCallbacks); @@ -69812,13 +71533,13 @@ MA_API ma_result ma_resource_manager_data_buffer_get_data_format(ma_resource_man MA_API ma_result ma_resource_manager_data_buffer_get_cursor_in_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pCursor) { - /* We cannot be using the data source after it's been uninitialized. */ - MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE); - if (pDataBuffer == NULL || pCursor == NULL) { return MA_INVALID_ARGS; } + /* We cannot be using the data source after it's been uninitialized. */ + MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE); + *pCursor = 0; switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode)) @@ -69852,13 +71573,13 @@ MA_API ma_result ma_resource_manager_data_buffer_get_cursor_in_pcm_frames(ma_res MA_API ma_result ma_resource_manager_data_buffer_get_length_in_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pLength) { - /* We cannot be using the data source after it's been uninitialized. */ - MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE); - if (pDataBuffer == NULL || pLength == NULL) { return MA_INVALID_ARGS; } + /* We cannot be using the data source after it's been uninitialized. */ + MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE); + if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_unknown) { return MA_BUSY; /* Still loading. */ } @@ -71213,8 +72934,6 @@ static ma_result ma_job_process__resource_manager__free_data_buffer_node(ma_job* return ma_resource_manager_post_job(pResourceManager, pJob); /* Out of order. */ } - ma_resource_manager_data_buffer_node_free(pResourceManager, pDataBufferNode); - /* The event needs to be signalled last. */ if (pJob->data.resourceManager.freeDataBufferNode.pDoneNotification != NULL) { ma_async_notification_signal(pJob->data.resourceManager.freeDataBufferNode.pDoneNotification); @@ -71225,6 +72944,9 @@ static ma_result ma_job_process__resource_manager__free_data_buffer_node(ma_job* } ma_atomic_fetch_add_32(&pDataBufferNode->executionPointer, 1); + + ma_resource_manager_data_buffer_node_free(pResourceManager, pDataBufferNode); + return MA_SUCCESS; } @@ -72097,6 +73819,15 @@ MA_API ma_result ma_node_graph_set_time(ma_node_graph* pNodeGraph, ma_uint64 glo return ma_node_set_time(&pNodeGraph->endpoint, globalTime); /* Global time is just the local time of the endpoint. */ } +MA_API ma_uint32 ma_node_graph_get_processing_size_in_frames(const ma_node_graph* pNodeGraph) +{ + if (pNodeGraph == NULL) { + return 0; + } + + return pNodeGraph->processingSizeInFrames; +} + #define MA_NODE_OUTPUT_BUS_FLAG_HAS_READ 0x01 /* Whether or not this bus ready to read more data. Only used on nodes with multiple output buses. */ @@ -73256,12 +74987,12 @@ MA_API ma_node_state ma_node_get_state_by_time_range(const ma_node* pNode, ma_ui its start time not having been reached yet. Also, the stop time may have also been reached in which case it'll be considered stopped. */ - if (ma_node_get_state_time(pNode, ma_node_state_started) > globalTimeBeg) { - return ma_node_state_stopped; /* Start time has not yet been reached. */ + if (ma_node_get_state_time(pNode, ma_node_state_stopped) < globalTimeBeg) { + return ma_node_state_stopped; /* End time is before the start of the range. */ } - if (ma_node_get_state_time(pNode, ma_node_state_stopped) <= globalTimeEnd) { - return ma_node_state_stopped; /* Stop time has been reached. */ + if (ma_node_get_state_time(pNode, ma_node_state_started) > globalTimeEnd) { + return ma_node_state_stopped; /* Start time is after the end of the range. */ } /* Getting here means the node is marked as started and is within its start/stop times. */ @@ -73341,14 +75072,14 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde return MA_INVALID_ARGS; /* Invalid output bus index. */ } + globalTimeBeg = globalTime; + globalTimeEnd = globalTime + frameCount; + /* Don't do anything if we're in a stopped state. */ - if (ma_node_get_state_by_time_range(pNode, globalTime, globalTime + frameCount) != ma_node_state_started) { + if (ma_node_get_state_by_time_range(pNode, globalTimeBeg, globalTimeEnd) != ma_node_state_started) { return MA_SUCCESS; /* We're in a stopped state. This is not an error - we just need to not read anything. */ } - - globalTimeBeg = globalTime; - globalTimeEnd = globalTime + frameCount; startTime = ma_node_get_state_time(pNode, ma_node_state_started); stopTime = ma_node_get_state_time(pNode, ma_node_state_stopped); @@ -73361,11 +75092,16 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde therefore need to offset it by a number of frames to accommodate. The same thing applies for the stop time. */ - timeOffsetBeg = (globalTimeBeg < startTime) ? (ma_uint32)(globalTimeEnd - startTime) : 0; + timeOffsetBeg = (globalTimeBeg < startTime) ? (ma_uint32)(startTime - globalTimeBeg) : 0; timeOffsetEnd = (globalTimeEnd > stopTime) ? (ma_uint32)(globalTimeEnd - stopTime) : 0; /* Trim based on the start offset. We need to silence the start of the buffer. */ if (timeOffsetBeg > 0) { + MA_ASSERT(timeOffsetBeg <= frameCount); + if (timeOffsetBeg > frameCount) { + timeOffsetBeg = frameCount; + } + ma_silence_pcm_frames(pFramesOut, timeOffsetBeg, ma_format_f32, ma_node_get_output_channels(pNode, outputBusIndex)); pFramesOut += timeOffsetBeg * ma_node_get_output_channels(pNode, outputBusIndex); frameCount -= timeOffsetBeg; @@ -73373,6 +75109,11 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde /* Trim based on the end offset. We don't need to silence the tail section because we'll just have a reduced value written to pFramesRead. */ if (timeOffsetEnd > 0) { + MA_ASSERT(timeOffsetEnd <= frameCount); + if (timeOffsetEnd > frameCount) { + timeOffsetEnd = frameCount; + } + frameCount -= timeOffsetEnd; } @@ -74787,12 +76528,20 @@ static void ma_sound_set_at_end(ma_sound* pSound, ma_bool32 atEnd) MA_ASSERT(pSound != NULL); ma_atomic_exchange_32(&pSound->atEnd, atEnd); + /* + When this function is called the state of the sound will not yet be in a stopped state. This makes it confusing + because an end callback will intuitively expect ma_sound_is_playing() to return false from inside the callback. + I'm therefore no longer firing the callback here and will instead fire it manually in the *next* processing step + when the state should be set to stopped as expected. + */ + #if 0 /* Fire any callbacks or events. */ if (atEnd) { if (pSound->endCallback != NULL) { pSound->endCallback(pSound->pEndCallbackUserData, pSound); } } + #endif } static ma_bool32 ma_sound_get_at_end(const ma_sound* pSound) @@ -74812,6 +76561,7 @@ MA_API ma_engine_node_config ma_engine_node_config_init(ma_engine* pEngine, ma_e config.isPitchDisabled = (flags & MA_SOUND_FLAG_NO_PITCH) != 0; config.isSpatializationDisabled = (flags & MA_SOUND_FLAG_NO_SPATIALIZATION) != 0; config.monoExpansionMode = pEngine->monoExpansionMode; + config.resampling = pEngine->pitchResamplingConfig; return config; } @@ -74838,7 +76588,7 @@ static void ma_engine_node_update_pitch_if_required(ma_engine_node* pEngineNode) if (isUpdateRequired) { float basePitch = (float)pEngineNode->sampleRate / ma_engine_get_sample_rate(pEngineNode->pEngine); - ma_linear_resampler_set_rate_ratio(&pEngineNode->resampler, basePitch * pEngineNode->oldPitch * pEngineNode->oldDopplerPitch); + ma_resampler_set_rate_ratio(&pEngineNode->resampler, basePitch * pEngineNode->oldPitch * pEngineNode->oldDopplerPitch); } } @@ -74857,22 +76607,6 @@ static ma_bool32 ma_engine_node_is_spatialization_enabled(const ma_engine_node* return !ma_atomic_load_explicit_32(&pEngineNode->isSpatializationDisabled, ma_atomic_memory_order_acquire); } -static ma_uint64 ma_engine_node_get_required_input_frame_count(const ma_engine_node* pEngineNode, ma_uint64 outputFrameCount) -{ - ma_uint64 inputFrameCount = 0; - - if (ma_engine_node_is_pitching_enabled(pEngineNode)) { - ma_result result = ma_linear_resampler_get_required_input_frame_count(&pEngineNode->resampler, outputFrameCount, &inputFrameCount); - if (result != MA_SUCCESS) { - inputFrameCount = 0; - } - } else { - inputFrameCount = outputFrameCount; /* No resampling, so 1:1. */ - } - - return inputFrameCount; -} - static ma_result ma_engine_node_set_volume(ma_engine_node* pEngineNode, float volume) { if (pEngineNode == NULL) { @@ -75014,7 +76748,7 @@ static void ma_engine_node_process_pcm_frames__general(ma_engine_node* pEngineNo ma_uint64 resampleFrameCountIn = framesAvailableIn; ma_uint64 resampleFrameCountOut = framesAvailableOut; - ma_linear_resampler_process_pcm_frames(&pEngineNode->resampler, pRunningFramesIn, &resampleFrameCountIn, pWorkingBuffer, &resampleFrameCountOut); + ma_resampler_process_pcm_frames(&pEngineNode->resampler, pRunningFramesIn, &resampleFrameCountIn, pWorkingBuffer, &resampleFrameCountOut); isWorkingBufferValid = MA_TRUE; framesJustProcessedIn = (ma_uint32)resampleFrameCountIn; @@ -75138,6 +76872,11 @@ static void ma_engine_node_process_pcm_frames__sound(ma_node* pNode, const float /* If we're marked at the end we need to stop the sound and do nothing. */ if (ma_sound_at_end(pSound)) { ma_sound_stop(pSound); + + if (pSound->endCallback != NULL) { + pSound->endCallback(pSound->pEndCallbackUserData, pSound); + } + *pFrameCountOut = 0; return; } @@ -75175,55 +76914,74 @@ static void ma_engine_node_process_pcm_frames__sound(ma_node* pNode, const float /* Keep reading until we've read as much as was requested or we reach the end of the data source. */ while (totalFramesRead < frameCount) { ma_uint32 framesRemaining = frameCount - totalFramesRead; - ma_uint32 framesToRead; ma_uint64 framesJustRead; ma_uint32 frameCountIn; ma_uint32 frameCountOut; const float* pRunningFramesIn; float* pRunningFramesOut; - /* - The first thing we need to do is read into the temporary buffer. We can calculate exactly - how many input frames we'll need after resampling. - */ - framesToRead = (ma_uint32)ma_engine_node_get_required_input_frame_count(&pSound->engineNode, framesRemaining); - if (framesToRead > tempCapInFrames) { - framesToRead = tempCapInFrames; - } + /* If there's any input frames sitting in the cache get those processed first. */ + if (pSound->processingCacheFramesRemaining > 0) { + pRunningFramesIn = pSound->pProcessingCache; + frameCountIn = pSound->processingCacheFramesRemaining; - result = ma_data_source_read_pcm_frames(pSound->pDataSource, temp, framesToRead, &framesJustRead); + pRunningFramesOut = ma_offset_pcm_frames_ptr_f32(ppFramesOut[0], totalFramesRead, ma_node_get_output_channels(pNode, 0)); + frameCountOut = framesRemaining; - /* If we reached the end of the sound we'll want to mark it as at the end and stop it. This should never be returned for looping sounds. */ - if (result == MA_AT_END) { - ma_sound_set_at_end(pSound, MA_TRUE); /* This will be set to false in ma_sound_start(). */ - } - - pRunningFramesOut = ma_offset_pcm_frames_ptr_f32(ppFramesOut[0], totalFramesRead, ma_node_get_output_channels(pNode, 0)); - - frameCountIn = (ma_uint32)framesJustRead; - frameCountOut = framesRemaining; - - /* Convert if necessary. */ - if (dataSourceFormat == ma_format_f32) { - /* Fast path. No data conversion necessary. */ - pRunningFramesIn = (float*)temp; ma_engine_node_process_pcm_frames__general(&pSound->engineNode, &pRunningFramesIn, &frameCountIn, &pRunningFramesOut, &frameCountOut); + + MA_ASSERT(frameCountIn <= pSound->processingCacheFramesRemaining); + pSound->processingCacheFramesRemaining -= frameCountIn; + + /* Move any remaining data in the cache down. */ + if (pSound->processingCacheFramesRemaining > 0) { + MA_MOVE_MEMORY(pSound->pProcessingCache, ma_offset_pcm_frames_ptr_f32(pSound->pProcessingCache, frameCountIn, dataSourceChannels), pSound->processingCacheFramesRemaining * ma_get_bytes_per_frame(ma_format_f32, dataSourceChannels)); + } + + totalFramesRead += (ma_uint32)frameCountOut; /* Safe cast. */ + + if (result != MA_SUCCESS || ma_sound_at_end(pSound)) { + break; /* Might have reached the end. */ + } } else { - /* Slow path. Need to do sample format conversion to f32. If we give the f32 buffer the same count as the first temp buffer, we're guaranteed it'll be large enough. */ - float tempf32[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* Do not do `MA_DATA_CONVERTER_STACK_BUFFER_SIZE/sizeof(float)` here like we've done in other places. */ - ma_convert_pcm_frames_format(tempf32, ma_format_f32, temp, dataSourceFormat, framesJustRead, dataSourceChannels, ma_dither_mode_none); + /* Getting here means there's nothing in the cache. Read more data from the data source. */ + if (dataSourceFormat == ma_format_f32) { + /* Fast path. No conversion to f32 necessary. */ + result = ma_data_source_read_pcm_frames(pSound->pDataSource, pSound->pProcessingCache, pSound->processingCacheCap, &framesJustRead); + } else { + /* Slow path. Need to convert to f32. */ + ma_uint64 totalFramesConverted = 0; - /* Now that we have our samples in f32 format we can process like normal. */ - pRunningFramesIn = tempf32; - ma_engine_node_process_pcm_frames__general(&pSound->engineNode, &pRunningFramesIn, &frameCountIn, &pRunningFramesOut, &frameCountOut); - } + while (totalFramesConverted < pSound->processingCacheCap) { + ma_uint64 framesConverted; + ma_uint32 framesToConvertThisIteration = pSound->processingCacheCap - (ma_uint32)totalFramesConverted; + if (framesToConvertThisIteration > tempCapInFrames) { + framesToConvertThisIteration = tempCapInFrames; + } - /* We should have processed all of our input frames since we calculated the required number of input frames at the top. */ - MA_ASSERT(frameCountIn == framesJustRead); - totalFramesRead += (ma_uint32)frameCountOut; /* Safe cast. */ + result = ma_data_source_read_pcm_frames(pSound->pDataSource, temp, framesToConvertThisIteration, &framesConverted); + if (result != MA_SUCCESS) { + break; + } - if (result != MA_SUCCESS || ma_sound_at_end(pSound)) { - break; /* Might have reached the end. */ + ma_convert_pcm_frames_format(ma_offset_pcm_frames_ptr_f32(pSound->pProcessingCache, totalFramesConverted, dataSourceChannels), ma_format_f32, temp, dataSourceFormat, framesConverted, dataSourceChannels, ma_dither_mode_none); + totalFramesConverted += framesConverted; + } + + framesJustRead = totalFramesConverted; + } + + MA_ASSERT(framesJustRead <= pSound->processingCacheCap); + pSound->processingCacheFramesRemaining = (ma_uint32)framesJustRead; + + /* If we reached the end of the sound we'll want to mark it as at the end and stop it. This should never be returned for looping sounds. */ + if (result == MA_AT_END) { + ma_sound_set_at_end(pSound, MA_TRUE); /* This will be set to false in ma_sound_start(). */ + } + + if (result != MA_SUCCESS || ma_sound_at_end(pSound)) { + break; + } } } } @@ -75246,25 +77004,6 @@ static void ma_engine_node_process_pcm_frames__group(ma_node* pNode, const float ma_engine_node_process_pcm_frames__general((ma_engine_node*)pNode, ppFramesIn, pFrameCountIn, ppFramesOut, pFrameCountOut); } -static ma_result ma_engine_node_get_required_input_frame_count__group(ma_node* pNode, ma_uint32 outputFrameCount, ma_uint32* pInputFrameCount) -{ - ma_uint64 inputFrameCount; - - MA_ASSERT(pInputFrameCount != NULL); - - /* Our pitch will affect this calculation. We need to update it. */ - ma_engine_node_update_pitch_if_required((ma_engine_node*)pNode); - - inputFrameCount = ma_engine_node_get_required_input_frame_count((ma_engine_node*)pNode, outputFrameCount); - if (inputFrameCount > 0xFFFFFFFF) { - inputFrameCount = 0xFFFFFFFF; /* Will never happen because miniaudio will only ever process in relatively small chunks. */ - } - - *pInputFrameCount = (ma_uint32)inputFrameCount; - - return MA_SUCCESS; -} - static ma_node_vtable g_ma_engine_node_vtable__sound = { @@ -75278,7 +77017,7 @@ static ma_node_vtable g_ma_engine_node_vtable__sound = static ma_node_vtable g_ma_engine_node_vtable__group = { ma_engine_node_process_pcm_frames__group, - ma_engine_node_get_required_input_frame_count__group, + NULL, /* onGetRequiredInputFrameCount */ 1, /* Groups have one input bus. */ 1, /* Groups have one output bus. */ MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES /* The engine node does resampling so should let miniaudio know about it. */ @@ -75324,9 +77063,10 @@ static ma_result ma_engine_node_get_heap_layout(const ma_engine_node_config* pCo ma_result result; size_t tempHeapSize; ma_node_config baseNodeConfig; - ma_linear_resampler_config resamplerConfig; + ma_resampler_config resamplerConfig; ma_spatializer_config spatializerConfig; ma_gainer_config gainerConfig; + ma_uint32 sampleRate; ma_uint32 channelsIn; ma_uint32 channelsOut; ma_channel defaultStereoChannelMap[2] = {MA_CHANNEL_SIDE_LEFT, MA_CHANNEL_SIDE_RIGHT}; /* <-- Consistent with the default channel map of a stereo listener. Means channel conversion can run on a fast path. */ @@ -75345,6 +77085,7 @@ static ma_result ma_engine_node_get_heap_layout(const ma_engine_node_config* pCo pHeapLayout->sizeInBytes = 0; + sampleRate = (pConfig->sampleRate > 0) ? pConfig->sampleRate : ma_engine_get_sample_rate(pConfig->pEngine); channelsIn = (pConfig->channelsIn != 0) ? pConfig->channelsIn : ma_engine_get_channels(pConfig->pEngine); channelsOut = (pConfig->channelsOut != 0) ? pConfig->channelsOut : ma_engine_get_channels(pConfig->pEngine); @@ -75364,10 +77105,13 @@ static ma_result ma_engine_node_get_heap_layout(const ma_engine_node_config* pCo /* Resmapler. */ - resamplerConfig = ma_linear_resampler_config_init(ma_format_f32, channelsIn, 1, 1); /* Input and output sample rates don't affect the calculation of the heap size. */ - resamplerConfig.lpfOrder = 0; + resamplerConfig = pConfig->resampling; + resamplerConfig.format = ma_format_f32; + resamplerConfig.channels = channelsIn; + resamplerConfig.sampleRateIn = sampleRate; + resamplerConfig.sampleRateOut = ma_engine_get_sample_rate(pConfig->pEngine); - result = ma_linear_resampler_get_heap_size(&resamplerConfig, &tempHeapSize); + result = ma_resampler_get_heap_size(&resamplerConfig, &tempHeapSize); if (result != MA_SUCCESS) { return result; /* Failed to retrieve the size of the heap for the resampler. */ } @@ -75435,7 +77179,7 @@ MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* p ma_result result; ma_engine_node_heap_layout heapLayout; ma_node_config baseNodeConfig; - ma_linear_resampler_config resamplerConfig; + ma_resampler_config resamplerConfig; ma_fader_config faderConfig; ma_spatializer_config spatializerConfig; ma_panner_config pannerConfig; @@ -75510,10 +77254,13 @@ MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* p */ /* We'll always do resampling first. */ - resamplerConfig = ma_linear_resampler_config_init(ma_format_f32, baseNodeConfig.pInputChannels[0], pEngineNode->sampleRate, ma_engine_get_sample_rate(pEngineNode->pEngine)); - resamplerConfig.lpfOrder = 0; /* <-- Need to disable low-pass filtering for pitch shifting for now because there's cases where the biquads are becoming unstable. Need to figure out a better fix for this. */ + resamplerConfig = pConfig->resampling; + resamplerConfig.format = ma_format_f32; + resamplerConfig.channels = baseNodeConfig.pInputChannels[0]; + resamplerConfig.sampleRateIn = pEngineNode->sampleRate; + resamplerConfig.sampleRateOut = ma_engine_get_sample_rate(pEngineNode->pEngine); - result = ma_linear_resampler_init_preallocated(&resamplerConfig, ma_offset_ptr(pHeap, heapLayout.resamplerOffset), &pEngineNode->resampler); + result = ma_resampler_init_preallocated(&resamplerConfig, ma_offset_ptr(pHeap, heapLayout.resamplerOffset), &pEngineNode->resampler); if (result != MA_SUCCESS) { goto error1; } @@ -75572,7 +77319,7 @@ MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* p /* No need for allocation callbacks here because we use a preallocated heap. */ error3: ma_spatializer_uninit(&pEngineNode->spatializer, NULL); -error2: ma_linear_resampler_uninit(&pEngineNode->resampler, NULL); +error2: ma_resampler_uninit(&pEngineNode->resampler, NULL); error1: ma_node_uninit(&pEngineNode->baseNode, NULL); error0: return result; } @@ -75621,7 +77368,7 @@ MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocati } ma_spatializer_uninit(&pEngineNode->spatializer, pAllocationCallbacks); - ma_linear_resampler_uninit(&pEngineNode->resampler, pAllocationCallbacks); + ma_resampler_uninit(&pEngineNode->resampler, pAllocationCallbacks); /* Free the heap last. */ if (pEngineNode->_ownsHeap) { @@ -75643,8 +77390,12 @@ MA_API ma_sound_config ma_sound_config_init_2(ma_engine* pEngine) if (pEngine != NULL) { config.monoExpansionMode = pEngine->monoExpansionMode; + config.pitchResampling = pEngine->pitchResamplingConfig; } else { config.monoExpansionMode = ma_mono_expansion_mode_default; + + config.pitchResampling = ma_resampler_config_init(ma_format_f32, 0, 0, 0, ma_resample_algorithm_linear); + config.pitchResampling.linear.lpfOrder = 0; /* <-- Need to disable low-pass filtering for pitch shifting for now because there's cases where the biquads are becoming unstable. Need to figure out a better fix for this. */ } config.rangeEndInPCMFrames = ~((ma_uint64)0); @@ -75666,8 +77417,12 @@ MA_API ma_sound_group_config ma_sound_group_config_init_2(ma_engine* pEngine) if (pEngine != NULL) { config.monoExpansionMode = pEngine->monoExpansionMode; + config.pitchResampling = pEngine->pitchResamplingConfig; } else { config.monoExpansionMode = ma_mono_expansion_mode_default; + + config.pitchResampling = ma_resampler_config_init(ma_format_f32, 0, 0, 0, ma_resample_algorithm_linear); + config.pitchResampling.linear.lpfOrder = 0; /* <-- Need to disable low-pass filtering for pitch shifting for now because there's cases where the biquads are becoming unstable. Need to figure out a better fix for this. */ } return config; @@ -75679,8 +77434,12 @@ MA_API ma_engine_config ma_engine_config_init(void) ma_engine_config config; MA_ZERO_OBJECT(&config); - config.listenerCount = 1; /* Always want at least one listener. */ - config.monoExpansionMode = ma_mono_expansion_mode_default; + config.listenerCount = 1; /* Always want at least one listener. */ + config.monoExpansionMode = ma_mono_expansion_mode_default; + config.resourceManagerResampling = ma_resampler_config_init(ma_format_unknown, 0, 0, 0, ma_resample_algorithm_linear); + + config.pitchResampling = ma_resampler_config_init(ma_format_f32, 0, 0, 0, ma_resample_algorithm_linear); + config.pitchResampling.linear.lpfOrder = 0; /* <-- Need to disable low-pass filtering for pitch shifting for now because there's cases where the biquads are becoming unstable. Need to figure out a better fix for this. */ return config; } @@ -75761,6 +77520,7 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng pEngine->defaultVolumeSmoothTimeInPCMFrames = engineConfig.defaultVolumeSmoothTimeInPCMFrames; pEngine->onProcess = engineConfig.onProcess; pEngine->pProcessUserData = engineConfig.pProcessUserData; + pEngine->pitchResamplingConfig = engineConfig.pitchResampling; ma_allocation_callbacks_init_copy(&pEngine->allocationCallbacks, &engineConfig.allocationCallbacks); #if !defined(MA_NO_RESOURCE_MANAGER) @@ -75943,6 +77703,7 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng resourceManagerConfig.decodedSampleRate = ma_engine_get_sample_rate(pEngine); ma_allocation_callbacks_init_copy(&resourceManagerConfig.allocationCallbacks, &pEngine->allocationCallbacks); resourceManagerConfig.pVFS = engineConfig.pResourceManagerVFS; + resourceManagerConfig.resampling = engineConfig.resourceManagerResampling; /* The Emscripten build cannot use threads unless it's targeting pthreads. */ #if defined(MA_EMSCRIPTEN) && !defined(__EMSCRIPTEN_PTHREADS__) @@ -76668,13 +78429,32 @@ static ma_result ma_sound_init_from_data_source_internal(ma_engine* pEngine, con } + /* + When pulling data from a data source we need a processing cache to hold onto unprocessed input data from the data source + after doing resampling. + */ + if (pSound->pDataSource != NULL) { + pSound->processingCacheFramesRemaining = 0; + pSound->processingCacheCap = ma_node_graph_get_processing_size_in_frames(&pEngine->nodeGraph); + if (pSound->processingCacheCap == 0) { + pSound->processingCacheCap = 512; + } + + pSound->pProcessingCache = (float*)ma_calloc(pSound->processingCacheCap * ma_get_bytes_per_frame(ma_format_f32, engineNodeConfig.channelsIn), &pEngine->allocationCallbacks); + if (pSound->pProcessingCache == NULL) { + ma_engine_node_uninit(&pSound->engineNode, &pEngine->allocationCallbacks); + return MA_OUT_OF_MEMORY; + } + } + + /* Apply initial range and looping state to the data source if applicable. */ if (pConfig->rangeBegInPCMFrames != 0 || pConfig->rangeEndInPCMFrames != ~((ma_uint64)0)) { ma_data_source_set_range_in_pcm_frames(ma_sound_get_data_source(pSound), pConfig->rangeBegInPCMFrames, pConfig->rangeEndInPCMFrames); } if (pConfig->loopPointBegInPCMFrames != 0 || pConfig->loopPointEndInPCMFrames != ~((ma_uint64)0)) { - ma_data_source_set_range_in_pcm_frames(ma_sound_get_data_source(pSound), pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); + ma_data_source_set_loop_point_in_pcm_frames(ma_sound_get_data_source(pSound), pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); } ma_sound_set_looping(pSound, pConfig->isLooping || ((pConfig->flags & MA_SOUND_FLAG_LOOPING) != 0)); @@ -76736,6 +78516,7 @@ MA_API ma_result ma_sound_init_from_file_internal(ma_engine* pEngine, const ma_s result = ma_resource_manager_data_source_init_ex(pEngine->pResourceManager, &resourceManagerDataSourceConfig, pSound->pResourceManagerDataSource); if (result != MA_SUCCESS) { + ma_free(pSound->pResourceManagerDataSource, &pEngine->allocationCallbacks); goto done; } @@ -76904,6 +78685,11 @@ MA_API void ma_sound_uninit(ma_sound* pSound) */ ma_engine_node_uninit(&pSound->engineNode, &pSound->engineNode.pEngine->allocationCallbacks); + if (pSound->pProcessingCache != NULL) { + ma_free(pSound->pProcessingCache, &pSound->engineNode.pEngine->allocationCallbacks); + pSound->pProcessingCache = NULL; + } + /* Once the sound is detached from the group we can guarantee that it won't be referenced by the mixer thread which means it's safe for us to destroy the data source. */ #ifndef MA_NO_RESOURCE_MANAGER if (pSound->ownsDataSource) { @@ -76999,6 +78785,27 @@ MA_API ma_result ma_sound_stop_with_fade_in_milliseconds(ma_sound* pSound, ma_ui return ma_sound_stop_with_fade_in_pcm_frames(pSound, (fadeLengthInMilliseconds * sampleRate) / 1000); } +MA_API void ma_sound_reset_start_time(ma_sound* pSound) +{ + ma_sound_set_start_time_in_pcm_frames(pSound, 0); +} + +MA_API void ma_sound_reset_stop_time(ma_sound* pSound) +{ + ma_sound_set_stop_time_in_pcm_frames(pSound, ~(ma_uint64)0); +} + +MA_API void ma_sound_reset_fade(ma_sound* pSound) +{ + ma_sound_set_fade_in_pcm_frames(pSound, 0, 1, 0); +} + +MA_API void ma_sound_reset_stop_time_and_fade(ma_sound* pSound) +{ + ma_sound_reset_stop_time(pSound); + ma_sound_reset_fade(pSound); +} + MA_API void ma_sound_set_volume(ma_sound* pSound, float volume) { if (pSound == NULL) { @@ -77541,7 +79348,12 @@ MA_API ma_uint64 ma_sound_get_time_in_pcm_frames(const ma_sound* pSound) MA_API ma_uint64 ma_sound_get_time_in_milliseconds(const ma_sound* pSound) { - return ma_sound_get_time_in_pcm_frames(pSound) * 1000 / ma_engine_get_sample_rate(ma_sound_get_engine(pSound)); + ma_uint32 sampleRate = ma_engine_get_sample_rate(ma_sound_get_engine(pSound)); + if (sampleRate == 0) { + return 0; /* Prevent a division by zero. */ + } + + return ma_sound_get_time_in_pcm_frames(pSound) * 1000 / sampleRate; } MA_API void ma_sound_set_looping(ma_sound* pSound, ma_bool32 isLooping) @@ -77625,7 +79437,7 @@ MA_API ma_result ma_sound_seek_to_second(ma_sound* pSound, float seekPointInSeco return ma_sound_seek_to_pcm_frame(pSound, frameIndex); } -MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +MA_API ma_result ma_sound_get_data_format(const ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) { if (pSound == NULL) { return MA_INVALID_ARGS; @@ -77645,7 +79457,7 @@ MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, } if (pSampleRate != NULL) { - *pSampleRate = pSound->engineNode.resampler.config.sampleRateIn; + *pSampleRate = pSound->engineNode.resampler.sampleRateIn; } if (pChannelMap != NULL) { @@ -77658,7 +79470,7 @@ MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, } } -MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor) +MA_API ma_result ma_sound_get_cursor_in_pcm_frames(const ma_sound* pSound, ma_uint64* pCursor) { ma_uint64 seekTarget; @@ -77680,7 +79492,7 @@ MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* } } -MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength) +MA_API ma_result ma_sound_get_length_in_pcm_frames(const ma_sound* pSound, ma_uint64* pLength) { if (pSound == NULL) { return MA_INVALID_ARGS; @@ -77694,7 +79506,7 @@ MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* return ma_data_source_get_length_in_pcm_frames(pSound->pDataSource, pLength); } -MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor) +MA_API ma_result ma_sound_get_cursor_in_seconds(const ma_sound* pSound, float* pCursor) { ma_result result; ma_uint64 cursorInPCMFrames; @@ -77720,7 +79532,7 @@ MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor return MA_SUCCESS; } -MA_API ma_result ma_sound_get_length_in_seconds(ma_sound* pSound, float* pLength) +MA_API ma_result ma_sound_get_length_in_seconds(const ma_sound* pSound, float* pLength) { if (pSound == NULL) { return MA_INVALID_ARGS; @@ -78539,12 +80351,12 @@ MA_PRIVATE ma_bool32 ma_dr_wav__seek_forward(ma_dr_wav_seek_proc onSeek, ma_uint ma_uint64 bytesRemainingToSeek = offset; while (bytesRemainingToSeek > 0) { if (bytesRemainingToSeek > 0x7FFFFFFF) { - if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_current)) { + if (!onSeek(pUserData, 0x7FFFFFFF, MA_DR_WAV_SEEK_CUR)) { return MA_FALSE; } bytesRemainingToSeek -= 0x7FFFFFFF; } else { - if (!onSeek(pUserData, (int)bytesRemainingToSeek, ma_dr_wav_seek_origin_current)) { + if (!onSeek(pUserData, (int)bytesRemainingToSeek, MA_DR_WAV_SEEK_CUR)) { return MA_FALSE; } bytesRemainingToSeek = 0; @@ -78555,17 +80367,17 @@ MA_PRIVATE ma_bool32 ma_dr_wav__seek_forward(ma_dr_wav_seek_proc onSeek, ma_uint MA_PRIVATE ma_bool32 ma_dr_wav__seek_from_start(ma_dr_wav_seek_proc onSeek, ma_uint64 offset, void* pUserData) { if (offset <= 0x7FFFFFFF) { - return onSeek(pUserData, (int)offset, ma_dr_wav_seek_origin_start); + return onSeek(pUserData, (int)offset, MA_DR_WAV_SEEK_SET); } - if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_start)) { + if (!onSeek(pUserData, 0x7FFFFFFF, MA_DR_WAV_SEEK_SET)) { return MA_FALSE; } offset -= 0x7FFFFFFF; for (;;) { if (offset <= 0x7FFFFFFF) { - return onSeek(pUserData, (int)offset, ma_dr_wav_seek_origin_current); + return onSeek(pUserData, (int)offset, MA_DR_WAV_SEEK_CUR); } - if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_current)) { + if (!onSeek(pUserData, 0x7FFFFFFF, MA_DR_WAV_SEEK_CUR)) { return MA_FALSE; } offset -= 0x7FFFFFFF; @@ -78588,7 +80400,7 @@ MA_PRIVATE ma_bool32 ma_dr_wav__on_seek(ma_dr_wav_seek_proc onSeek, void* pUserD if (!onSeek(pUserData, offset, origin)) { return MA_FALSE; } - if (origin == ma_dr_wav_seek_origin_start) { + if (origin == MA_DR_WAV_SEEK_SET) { *pCursor = offset; } else { *pCursor += offset; @@ -78707,12 +80519,12 @@ MA_PRIVATE ma_uint64 ma_dr_wav__read_smpl_to_metadata_obj(ma_dr_wav__metadata_pa ma_uint8 smplLoopData[MA_DR_WAV_SMPL_LOOP_BYTES]; bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead); if (bytesJustRead == sizeof(smplLoopData)) { - pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = ma_dr_wav_bytes_to_u32(smplLoopData + 0); - pMetadata->data.smpl.pLoops[iSampleLoop].type = ma_dr_wav_bytes_to_u32(smplLoopData + 4); - pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 8); - pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 12); - pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = ma_dr_wav_bytes_to_u32(smplLoopData + 16); - pMetadata->data.smpl.pLoops[iSampleLoop].playCount = ma_dr_wav_bytes_to_u32(smplLoopData + 20); + pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = ma_dr_wav_bytes_to_u32(smplLoopData + 0); + pMetadata->data.smpl.pLoops[iSampleLoop].type = ma_dr_wav_bytes_to_u32(smplLoopData + 4); + pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 8); + pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 12); + pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = ma_dr_wav_bytes_to_u32(smplLoopData + 16); + pMetadata->data.smpl.pLoops[iSampleLoop].playCount = ma_dr_wav_bytes_to_u32(smplLoopData + 20); } else { break; } @@ -78756,7 +80568,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav__read_cue_to_metadata_obj(ma_dr_wav__metadata_par pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11]; pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = ma_dr_wav_bytes_to_u32(cuePointData + 12); pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = ma_dr_wav_bytes_to_u32(cuePointData + 16); - pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = ma_dr_wav_bytes_to_u32(cuePointData + 20); + pMetadata->data.cue.pCuePoints[iCuePoint].sampleOffset = ma_dr_wav_bytes_to_u32(cuePointData + 20); } else { break; } @@ -79096,7 +80908,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parse if (pParser->stage == ma_dr_wav__metadata_parser_stage_count) { ma_uint8 buffer[4]; size_t bytesJustRead; - if (!pParser->onSeek(pParser->pReadSeekUserData, 28, ma_dr_wav_seek_origin_current)) { + if (!pParser->onSeek(pParser->pReadSeekUserData, 28, MA_DR_WAV_SEEK_CUR)) { return bytesRead; } bytesRead += 28; @@ -79191,7 +81003,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parse return bytesRead; } allocSizeNeeded += ma_dr_wav__strlen(buffer) + 1; - allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - MA_DR_WAV_BEXT_BYTES; + allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - MA_DR_WAV_BEXT_BYTES + 1; ma_dr_wav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1); pParser->metadataCount += 1; } else { @@ -79274,6 +81086,16 @@ MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parse subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_album); } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_tracknumber, "ITRK")) { subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_tracknumber); + } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_location, "IARL")) { + subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_location); + } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_organization, "ICMS")) { + subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_organization); + } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_keywords, "IKEY")) { + subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_keywords); + } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_medium, "IMED")) { + subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_medium); + } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_description, "ISBJ")) { + subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_description); } else if ((allowedMetadataTypes & ma_dr_wav_metadata_type_unknown) != 0) { subchunkBytesRead = ma_dr_wav__metadata_process_unknown_chunk(pParser, subchunkId, subchunkDataSize, listType); } @@ -79281,13 +81103,13 @@ MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parse MA_DR_WAV_ASSERT(subchunkBytesRead <= subchunkDataSize); if (subchunkBytesRead < subchunkDataSize) { ma_uint64 bytesToSeek = subchunkDataSize - subchunkBytesRead; - if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, ma_dr_wav_seek_origin_current)) { + if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, MA_DR_WAV_SEEK_CUR)) { break; } bytesRead += bytesToSeek; } if ((subchunkDataSize % 2) == 1) { - if (!pParser->onSeek(pParser->pReadSeekUserData, 1, ma_dr_wav_seek_origin_current)) { + if (!pParser->onSeek(pParser->pReadSeekUserData, 1, MA_DR_WAV_SEEK_CUR)) { break; } bytesRead += 1; @@ -79324,7 +81146,7 @@ MA_API ma_uint16 ma_dr_wav_fmt_get_format(const ma_dr_wav_fmt* pFMT) return ma_dr_wav_bytes_to_u16(pFMT->subFormat); } } -MA_PRIVATE ma_bool32 ma_dr_wav_preinit(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pReadSeekUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_PRIVATE ma_bool32 ma_dr_wav_preinit(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pReadSeekTellUserData, const ma_allocation_callbacks* pAllocationCallbacks) { if (pWav == NULL || onRead == NULL || onSeek == NULL) { return MA_FALSE; @@ -79332,7 +81154,8 @@ MA_PRIVATE ma_bool32 ma_dr_wav_preinit(ma_dr_wav* pWav, ma_dr_wav_read_proc onRe MA_DR_WAV_ZERO_MEMORY(pWav, sizeof(*pWav)); pWav->onRead = onRead; pWav->onSeek = onSeek; - pWav->pUserData = pReadSeekUserData; + pWav->onTell = onTell; + pWav->pUserData = pReadSeekTellUserData; pWav->allocationCallbacks = ma_dr_wav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) { return MA_FALSE; @@ -79546,14 +81369,14 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p fmt.channelMask = ma_dr_wav_bytes_to_u32_ex(fmtext + 2, pWav->container); ma_dr_wav_bytes_to_guid(fmtext + 6, fmt.subFormat); } else { - if (pWav->onSeek(pWav->pUserData, fmt.extendedSize, ma_dr_wav_seek_origin_current) == MA_FALSE) { + if (pWav->onSeek(pWav->pUserData, fmt.extendedSize, MA_DR_WAV_SEEK_CUR) == MA_FALSE) { return MA_FALSE; } } cursor += fmt.extendedSize; bytesReadSoFar += fmt.extendedSize; } - if (pWav->onSeek(pWav->pUserData, (int)(header.sizeInBytes - bytesReadSoFar), ma_dr_wav_seek_origin_current) == MA_FALSE) { + if (pWav->onSeek(pWav->pUserData, (int)(header.sizeInBytes - bytesReadSoFar), MA_DR_WAV_SEEK_CUR) == MA_FALSE) { return MA_FALSE; } cursor += (header.sizeInBytes - bytesReadSoFar); @@ -79704,15 +81527,26 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p return MA_FALSE; } offset = ma_dr_wav_bytes_to_u32_ex(offsetAndBlockSizeData + 0, pWav->container); - if (ma_dr_wav__seek_forward(pWav->onSeek, offset, pWav->pUserData) == MA_FALSE) { - return MA_FALSE; - } - cursor += offset; - pWav->dataChunkDataPos = cursor; + pWav->dataChunkDataPos = cursor + offset; dataChunkSize = chunkSize; - if (sequential || !isProcessingMetadata) { - break; + if (dataChunkSize > offset) { + dataChunkSize -= offset; } else { + dataChunkSize = 0; + } + if (sequential) { + if (foundChunk_fmt) { + if (ma_dr_wav__seek_forward(pWav->onSeek, offset, pWav->pUserData) == MA_FALSE) { + return MA_FALSE; + } + cursor += offset; + break; + } else { + return MA_FALSE; + } + } else { + chunkSize += header.paddingSize; + chunkSize -= sizeof(offsetAndBlockSizeData); if (ma_dr_wav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == MA_FALSE) { break; } @@ -79776,6 +81610,17 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p pWav->pMetadata = metadataParser.pMetadata; pWav->metadataCount = metadataParser.metadataCount; } + if (pWav->onTell != NULL && pWav->onSeek != NULL) { + if (pWav->onSeek(pWav->pUserData, 0, MA_DR_WAV_SEEK_END) == MA_TRUE) { + ma_int64 fileSize; + if (pWav->onTell(pWav->pUserData, &fileSize)) { + if (dataChunkSize + pWav->dataChunkDataPos > (ma_uint64)fileSize) { + dataChunkSize = (ma_uint64)fileSize - pWav->dataChunkDataPos; + } + } + } else { + } + } if (dataChunkSize == 0xFFFFFFFF && (pWav->container == ma_dr_wav_container_riff || pWav->container == ma_dr_wav_container_rifx) && pWav->isSequentialWrite == MA_FALSE) { dataChunkSize = 0; for (;;) { @@ -79795,8 +81640,14 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p pWav->sampleRate = fmt.sampleRate; pWav->channels = fmt.channels; pWav->bitsPerSample = fmt.bitsPerSample; - pWav->bytesRemaining = dataChunkSize; pWav->translatedFormatTag = translatedFormatTag; + if (!ma_dr_wav__is_compressed_format_tag(translatedFormatTag)) { + ma_uint32 bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame > 0) { + dataChunkSize -= (dataChunkSize % bytesPerFrame); + } + } + pWav->bytesRemaining = dataChunkSize; pWav->dataChunkDataSize = dataChunkSize; if (sampleCountFromFactChunk != 0) { pWav->totalPCMFrameCount = sampleCountFromFactChunk; @@ -79851,20 +81702,20 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p #endif return MA_TRUE; } -MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_wav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks); + return ma_dr_wav_init_ex(pWav, onRead, onSeek, onTell, NULL, pUserData, NULL, 0, pAllocationCallbacks); } -MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, ma_dr_wav_chunk_proc onChunk, void* pReadSeekTellUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) { - if (!ma_dr_wav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_preinit(pWav, onRead, onSeek, onTell, pReadSeekTellUserData, pAllocationCallbacks)) { return MA_FALSE; } return ma_dr_wav_init__internal(pWav, onChunk, pChunkUserData, flags); } -MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) { - if (!ma_dr_wav_preinit(pWav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_preinit(pWav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) { return MA_FALSE; } return ma_dr_wav_init__internal(pWav, NULL, NULL, flags | MA_DR_WAV_WITH_METADATA); @@ -80026,8 +81877,8 @@ MA_PRIVATE size_t ma_dr_wav__write_or_count_metadata(ma_dr_wav* pWav, ma_dr_wav_ for (iLoop = 0; iLoop < pMetadata->data.smpl.sampleLoopCount; ++iLoop) { bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].cuePointId); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].type); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleByteOffset); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleByteOffset); + bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleOffset); + bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleOffset); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].sampleFraction); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].playCount); } @@ -80061,7 +81912,7 @@ MA_PRIVATE size_t ma_dr_wav__write_or_count_metadata(ma_dr_wav* pWav, ma_dr_wav_ bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId, 4); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].blockStart); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset); + bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleOffset); } } break; case ma_dr_wav_metadata_type_acid: @@ -80147,15 +81998,20 @@ MA_PRIVATE size_t ma_dr_wav__write_or_count_metadata(ma_dr_wav* pWav, ma_dr_wav_ if (pMetadata->type & ma_dr_wav_metadata_type_list_all_info_strings) { const char* pID = NULL; switch (pMetadata->type) { - case ma_dr_wav_metadata_type_list_info_software: pID = "ISFT"; break; - case ma_dr_wav_metadata_type_list_info_copyright: pID = "ICOP"; break; - case ma_dr_wav_metadata_type_list_info_title: pID = "INAM"; break; - case ma_dr_wav_metadata_type_list_info_artist: pID = "IART"; break; - case ma_dr_wav_metadata_type_list_info_comment: pID = "ICMT"; break; - case ma_dr_wav_metadata_type_list_info_date: pID = "ICRD"; break; - case ma_dr_wav_metadata_type_list_info_genre: pID = "IGNR"; break; - case ma_dr_wav_metadata_type_list_info_album: pID = "IPRD"; break; - case ma_dr_wav_metadata_type_list_info_tracknumber: pID = "ITRK"; break; + case ma_dr_wav_metadata_type_list_info_software: pID = "ISFT"; break; + case ma_dr_wav_metadata_type_list_info_copyright: pID = "ICOP"; break; + case ma_dr_wav_metadata_type_list_info_title: pID = "INAM"; break; + case ma_dr_wav_metadata_type_list_info_artist: pID = "IART"; break; + case ma_dr_wav_metadata_type_list_info_comment: pID = "ICMT"; break; + case ma_dr_wav_metadata_type_list_info_date: pID = "ICRD"; break; + case ma_dr_wav_metadata_type_list_info_genre: pID = "IGNR"; break; + case ma_dr_wav_metadata_type_list_info_album: pID = "IPRD"; break; + case ma_dr_wav_metadata_type_list_info_tracknumber: pID = "ITRK"; break; + case ma_dr_wav_metadata_type_list_info_location: pID = "IARL"; break; + case ma_dr_wav_metadata_type_list_info_organization: pID = "ICMS"; break; + case ma_dr_wav_metadata_type_list_info_keywords: pID = "IKEY"; break; + case ma_dr_wav_metadata_type_list_info_medium: pID = "IMED"; break; + case ma_dr_wav_metadata_type_list_info_description: pID = "ISBJ"; break; default: break; } MA_DR_WAV_ASSERT(pID != NULL); @@ -80370,7 +82226,7 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init_write__internal(ma_dr_wav* pWav, const ma_dr } pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize; if (pFormat->container == ma_dr_wav_container_riff) { - ma_uint32 chunkSizeRIFF = 28 + (ma_uint32)initialDataChunkSize; + ma_uint32 chunkSizeRIFF = 36 + (ma_uint32)initialDataChunkSize; runningPos += ma_dr_wav__write(pWav, "RIFF", 4); runningPos += ma_dr_wav__write_u32ne_to_le(pWav, chunkSizeRIFF); runningPos += ma_dr_wav__write(pWav, "WAVE", 4); @@ -80493,7 +82349,31 @@ MA_PRIVATE size_t ma_dr_wav__on_write_stdio(void* pUserData, const void* pData, } MA_PRIVATE ma_bool32 ma_dr_wav__on_seek_stdio(void* pUserData, int offset, ma_dr_wav_seek_origin origin) { - return fseek((FILE*)pUserData, offset, (origin == ma_dr_wav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; + int whence = SEEK_SET; + if (origin == MA_DR_WAV_SEEK_CUR) { + whence = SEEK_CUR; + } else if (origin == MA_DR_WAV_SEEK_END) { + whence = SEEK_END; + } + return fseek((FILE*)pUserData, offset, whence) == 0; +} +MA_PRIVATE ma_bool32 ma_dr_wav__on_tell_stdio(void* pUserData, ma_int64* pCursor) +{ + FILE* pFileStdio = (FILE*)pUserData; + ma_int64 result; + MA_DR_WAV_ASSERT(pFileStdio != NULL); + MA_DR_WAV_ASSERT(pCursor != NULL); +#if defined(_WIN32) && !defined(NXDK) + #if defined(_MSC_VER) && _MSC_VER > 1200 + result = _ftelli64(pFileStdio); + #else + result = ftell(pFileStdio); + #endif +#else + result = ftell(pFileStdio); +#endif + *pCursor = result; + return MA_TRUE; } MA_API ma_bool32 ma_dr_wav_init_file(ma_dr_wav* pWav, const char* filename, const ma_allocation_callbacks* pAllocationCallbacks) { @@ -80502,7 +82382,7 @@ MA_API ma_bool32 ma_dr_wav_init_file(ma_dr_wav* pWav, const char* filename, cons MA_PRIVATE ma_bool32 ma_dr_wav_init_file__internal_FILE(ma_dr_wav* pWav, FILE* pFile, ma_dr_wav_chunk_proc onChunk, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) { ma_bool32 result; - result = ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_stdio, ma_dr_wav__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + result = ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_stdio, ma_dr_wav__on_seek_stdio, ma_dr_wav__on_tell_stdio, (void*)pFile, pAllocationCallbacks); if (result != MA_TRUE) { fclose(pFile); return result; @@ -80639,25 +82519,26 @@ MA_PRIVATE size_t ma_dr_wav__on_read_memory(void* pUserData, void* pBufferOut, s MA_PRIVATE ma_bool32 ma_dr_wav__on_seek_memory(void* pUserData, int offset, ma_dr_wav_seek_origin origin) { ma_dr_wav* pWav = (ma_dr_wav*)pUserData; + ma_int64 newCursor; MA_DR_WAV_ASSERT(pWav != NULL); - if (origin == ma_dr_wav_seek_origin_current) { - if (offset > 0) { - if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) { - return MA_FALSE; - } - } else { - if (pWav->memoryStream.currentReadPos < (size_t)-offset) { - return MA_FALSE; - } - } - pWav->memoryStream.currentReadPos += offset; + if (origin == MA_DR_WAV_SEEK_SET) { + newCursor = 0; + } else if (origin == MA_DR_WAV_SEEK_CUR) { + newCursor = (ma_int64)pWav->memoryStream.currentReadPos; + } else if (origin == MA_DR_WAV_SEEK_END) { + newCursor = (ma_int64)pWav->memoryStream.dataSize; } else { - if ((ma_uint32)offset <= pWav->memoryStream.dataSize) { - pWav->memoryStream.currentReadPos = offset; - } else { - return MA_FALSE; - } + MA_DR_WAV_ASSERT(!"Invalid seek origin"); + return MA_FALSE; } + newCursor += offset; + if (newCursor < 0) { + return MA_FALSE; + } + if ((size_t)newCursor > pWav->memoryStream.dataSize) { + return MA_FALSE; + } + pWav->memoryStream.currentReadPos = (size_t)newCursor; return MA_TRUE; } MA_PRIVATE size_t ma_dr_wav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite) @@ -80691,25 +82572,34 @@ MA_PRIVATE size_t ma_dr_wav__on_write_memory(void* pUserData, const void* pDataI MA_PRIVATE ma_bool32 ma_dr_wav__on_seek_memory_write(void* pUserData, int offset, ma_dr_wav_seek_origin origin) { ma_dr_wav* pWav = (ma_dr_wav*)pUserData; + ma_int64 newCursor; MA_DR_WAV_ASSERT(pWav != NULL); - if (origin == ma_dr_wav_seek_origin_current) { - if (offset > 0) { - if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) { - offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos); - } - } else { - if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) { - offset = -(int)pWav->memoryStreamWrite.currentWritePos; - } - } - pWav->memoryStreamWrite.currentWritePos += offset; + if (origin == MA_DR_WAV_SEEK_SET) { + newCursor = 0; + } else if (origin == MA_DR_WAV_SEEK_CUR) { + newCursor = (ma_int64)pWav->memoryStreamWrite.currentWritePos; + } else if (origin == MA_DR_WAV_SEEK_END) { + newCursor = (ma_int64)pWav->memoryStreamWrite.dataSize; } else { - if ((ma_uint32)offset <= pWav->memoryStreamWrite.dataSize) { - pWav->memoryStreamWrite.currentWritePos = offset; - } else { - pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize; - } + MA_DR_WAV_ASSERT(!"Invalid seek origin"); + return MA_FALSE; } + newCursor += offset; + if (newCursor < 0) { + return MA_FALSE; + } + if ((size_t)newCursor > pWav->memoryStreamWrite.dataSize) { + return MA_FALSE; + } + pWav->memoryStreamWrite.currentWritePos = (size_t)newCursor; + return MA_TRUE; +} +MA_PRIVATE ma_bool32 ma_dr_wav__on_tell_memory(void* pUserData, ma_int64* pCursor) +{ + ma_dr_wav* pWav = (ma_dr_wav*)pUserData; + MA_DR_WAV_ASSERT(pWav != NULL); + MA_DR_WAV_ASSERT(pCursor != NULL); + *pCursor = (ma_int64)pWav->memoryStream.currentReadPos; return MA_TRUE; } MA_API ma_bool32 ma_dr_wav_init_memory(ma_dr_wav* pWav, const void* data, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) @@ -80721,7 +82611,7 @@ MA_API ma_bool32 ma_dr_wav_init_memory_ex(ma_dr_wav* pWav, const void* data, siz if (data == NULL || dataSize == 0) { return MA_FALSE; } - if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, pWav, pAllocationCallbacks)) { + if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, ma_dr_wav__on_tell_memory, pWav, pAllocationCallbacks)) { return MA_FALSE; } pWav->memoryStream.data = (const ma_uint8*)data; @@ -80734,7 +82624,7 @@ MA_API ma_bool32 ma_dr_wav_init_memory_with_metadata(ma_dr_wav* pWav, const void if (data == NULL || dataSize == 0) { return MA_FALSE; } - if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, pWav, pAllocationCallbacks)) { + if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, ma_dr_wav__on_tell_memory, pWav, pAllocationCallbacks)) { return MA_FALSE; } pWav->memoryStream.data = (const ma_uint8*)data; @@ -80793,30 +82683,30 @@ MA_API ma_result ma_dr_wav_uninit(ma_dr_wav* pWav) } if (pWav->onSeek && !pWav->isSequentialWrite) { if (pWav->container == ma_dr_wav_container_riff) { - if (pWav->onSeek(pWav->pUserData, 4, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, 4, MA_DR_WAV_SEEK_SET)) { ma_uint32 riffChunkSize = ma_dr_wav__riff_chunk_size_riff(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount); ma_dr_wav__write_u32ne_to_le(pWav, riffChunkSize); } - if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, MA_DR_WAV_SEEK_SET)) { ma_uint32 dataChunkSize = ma_dr_wav__data_chunk_size_riff(pWav->dataChunkDataSize); ma_dr_wav__write_u32ne_to_le(pWav, dataChunkSize); } } else if (pWav->container == ma_dr_wav_container_w64) { - if (pWav->onSeek(pWav->pUserData, 16, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, 16, MA_DR_WAV_SEEK_SET)) { ma_uint64 riffChunkSize = ma_dr_wav__riff_chunk_size_w64(pWav->dataChunkDataSize); ma_dr_wav__write_u64ne_to_le(pWav, riffChunkSize); } - if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, MA_DR_WAV_SEEK_SET)) { ma_uint64 dataChunkSize = ma_dr_wav__data_chunk_size_w64(pWav->dataChunkDataSize); ma_dr_wav__write_u64ne_to_le(pWav, dataChunkSize); } } else if (pWav->container == ma_dr_wav_container_rf64) { int ds64BodyPos = 12 + 8; - if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, MA_DR_WAV_SEEK_SET)) { ma_uint64 riffChunkSize = ma_dr_wav__riff_chunk_size_rf64(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount); ma_dr_wav__write_u64ne_to_le(pWav, riffChunkSize); } - if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, MA_DR_WAV_SEEK_SET)) { ma_uint64 dataChunkSize = ma_dr_wav__data_chunk_size_rf64(pWav->dataChunkDataSize); ma_dr_wav__write_u64ne_to_le(pWav, dataChunkSize); } @@ -80863,7 +82753,7 @@ MA_API size_t ma_dr_wav_read_raw(ma_dr_wav* pWav, size_t bytesToRead, void* pBuf if (bytesToSeek > 0x7FFFFFFF) { bytesToSeek = 0x7FFFFFFF; } - if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, ma_dr_wav_seek_origin_current) == MA_FALSE) { + if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, MA_DR_WAV_SEEK_CUR) == MA_FALSE) { break; } bytesRead += bytesToSeek; @@ -80962,7 +82852,7 @@ MA_PRIVATE ma_bool32 ma_dr_wav_seek_to_first_pcm_frame(ma_dr_wav* pWav) if (pWav->onWrite != NULL) { return MA_FALSE; } - if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, ma_dr_wav_seek_origin_start)) { + if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, MA_DR_WAV_SEEK_SET)) { return MA_FALSE; } if (ma_dr_wav__is_compressed_format_tag(pWav->translatedFormatTag)) { @@ -81043,7 +82933,7 @@ MA_API ma_bool32 ma_dr_wav_seek_to_pcm_frame(ma_dr_wav* pWav, ma_uint64 targetFr } while (offset > 0) { int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset); - if (!pWav->onSeek(pWav->pUserData, offset32, ma_dr_wav_seek_origin_current)) { + if (!pWav->onSeek(pWav->pUserData, offset32, MA_DR_WAV_SEEK_CUR)) { return MA_FALSE; } pWav->readCursorInPCMFrames += offset32 / bytesPerFrame; @@ -81169,12 +83059,12 @@ MA_API ma_uint64 ma_dr_wav_write_pcm_frames(ma_dr_wav* pWav, ma_uint64 framesToW MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut) { ma_uint64 totalFramesRead = 0; - static ma_int32 adaptationTable[] = { + static const ma_int32 adaptationTable[] = { 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230 }; - static ma_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; - static ma_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; + static const ma_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; + static const ma_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; MA_DR_WAV_ASSERT(pWav != NULL); MA_DR_WAV_ASSERT(framesToRead > 0); while (pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { @@ -81193,7 +83083,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_ pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][0]; pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[0][1]; pWav->msadpcm.cachedFrameCount = 2; - if (pWav->msadpcm.predictor[0] >= ma_dr_wav_countof(coeff1Table)) { + if (pWav->msadpcm.predictor[0] >= ma_dr_wav_countof(coeff1Table) || pWav->msadpcm.predictor[0] >= ma_dr_wav_countof(coeff2Table)) { return totalFramesRead; } } else { @@ -81215,7 +83105,8 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_ pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][1]; pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[1][1]; pWav->msadpcm.cachedFrameCount = 2; - if (pWav->msadpcm.predictor[0] >= ma_dr_wav_countof(coeff1Table) || pWav->msadpcm.predictor[1] >= ma_dr_wav_countof(coeff2Table)) { + if (pWav->msadpcm.predictor[0] >= ma_dr_wav_countof(coeff1Table) || pWav->msadpcm.predictor[0] >= ma_dr_wav_countof(coeff2Table) || + pWav->msadpcm.predictor[1] >= ma_dr_wav_countof(coeff1Table) || pWav->msadpcm.predictor[1] >= ma_dr_wav_countof(coeff2Table)) { return totalFramesRead; } } @@ -81252,6 +83143,9 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_ if (pWav->channels == 1) { ma_int32 newSample0; ma_int32 newSample1; + if (pWav->msadpcm.predictor[0] >= ma_dr_wav_countof(coeff1Table) || pWav->msadpcm.predictor[0] >= ma_dr_wav_countof(coeff2Table)) { + return totalFramesRead; + } newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; newSample0 += nibble0 * pWav->msadpcm.delta[0]; newSample0 = ma_dr_wav_clamp(newSample0, -32768, 32767); @@ -81276,6 +83170,9 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_ } else { ma_int32 newSample0; ma_int32 newSample1; + if (pWav->msadpcm.predictor[0] >= ma_dr_wav_countof(coeff1Table) || pWav->msadpcm.predictor[0] >= ma_dr_wav_countof(coeff2Table)) { + return totalFramesRead; + } newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; newSample0 += nibble0 * pWav->msadpcm.delta[0]; newSample0 = ma_dr_wav_clamp(newSample0, -32768, 32767); @@ -81285,6 +83182,9 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_ } pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1]; pWav->msadpcm.prevFrames[0][1] = newSample0; + if (pWav->msadpcm.predictor[1] >= ma_dr_wav_countof(coeff1Table) || pWav->msadpcm.predictor[1] >= ma_dr_wav_countof(coeff2Table)) { + return totalFramesRead; + } newSample1 = ((pWav->msadpcm.prevFrames[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevFrames[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8; newSample1 += nibble1 * pWav->msadpcm.delta[1]; newSample1 = ma_dr_wav_clamp(newSample1, -32768, 32767); @@ -81307,11 +83207,11 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint { ma_uint64 totalFramesRead = 0; ma_uint32 iChannel; - static ma_int32 indexTable[16] = { + static const ma_int32 indexTable[16] = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 }; - static ma_int32 stepTable[89] = { + static const ma_int32 stepTable[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, @@ -81334,7 +83234,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint } pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); if (header[2] >= ma_dr_wav_countof(stepTable)) { - pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, ma_dr_wav_seek_origin_current); + pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, MA_DR_WAV_SEEK_CUR); pWav->ima.bytesRemainingInBlock = 0; return totalFramesRead; } @@ -81349,7 +83249,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint } pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); if (header[2] >= ma_dr_wav_countof(stepTable) || header[6] >= ma_dr_wav_countof(stepTable)) { - pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, ma_dr_wav_seek_origin_current); + pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, MA_DR_WAV_SEEK_CUR); pWav->ima.bytesRemainingInBlock = 0; return totalFramesRead; } @@ -81424,7 +83324,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint return totalFramesRead; } #ifndef MA_DR_WAV_NO_CONVERSION_API -static unsigned short g_ma_dr_wavAlawTable[256] = { +static const unsigned short ma_dr_wav_gAlawTable[256] = { 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580, 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0, 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600, @@ -81442,7 +83342,7 @@ static unsigned short g_ma_dr_wavAlawTable[256] = { 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0, 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350 }; -static unsigned short g_ma_dr_wavMulawTable[256] = { +static const unsigned short ma_dr_wav_gMulawTable[256] = { 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84, 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84, 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004, @@ -81462,11 +83362,11 @@ static unsigned short g_ma_dr_wavMulawTable[256] = { }; static MA_INLINE ma_int16 ma_dr_wav__alaw_to_s16(ma_uint8 sampleIn) { - return (short)g_ma_dr_wavAlawTable[sampleIn]; + return (short)ma_dr_wav_gAlawTable[sampleIn]; } static MA_INLINE ma_int16 ma_dr_wav__mulaw_to_s16(ma_uint8 sampleIn) { - return (short)g_ma_dr_wavMulawTable[sampleIn]; + return (short)ma_dr_wav_gMulawTable[sampleIn]; } MA_PRIVATE void ma_dr_wav__pcm_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { @@ -82529,6 +84429,10 @@ MA_PRIVATE ma_int16* ma_dr_wav__read_pcm_frames_and_close_s16(ma_dr_wav* pWav, u ma_int16* pSampleData; ma_uint64 framesRead; MA_DR_WAV_ASSERT(pWav != NULL); + if (pWav->channels == 0 || pWav->totalPCMFrameCount > MA_SIZE_MAX / pWav->channels / sizeof(ma_int16)) { + ma_dr_wav_uninit(pWav); + return NULL; + } sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(ma_int16); if (sampleDataSize > MA_SIZE_MAX) { ma_dr_wav_uninit(pWav); @@ -82563,6 +84467,10 @@ MA_PRIVATE float* ma_dr_wav__read_pcm_frames_and_close_f32(ma_dr_wav* pWav, unsi float* pSampleData; ma_uint64 framesRead; MA_DR_WAV_ASSERT(pWav != NULL); + if (pWav->channels == 0 || pWav->totalPCMFrameCount > MA_SIZE_MAX / pWav->channels / sizeof(float)) { + ma_dr_wav_uninit(pWav); + return NULL; + } sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float); if (sampleDataSize > MA_SIZE_MAX) { ma_dr_wav_uninit(pWav); @@ -82597,6 +84505,10 @@ MA_PRIVATE ma_int32* ma_dr_wav__read_pcm_frames_and_close_s32(ma_dr_wav* pWav, u ma_int32* pSampleData; ma_uint64 framesRead; MA_DR_WAV_ASSERT(pWav != NULL); + if (pWav->channels == 0 || pWav->totalPCMFrameCount > MA_SIZE_MAX / pWav->channels / sizeof(ma_int32)) { + ma_dr_wav_uninit(pWav); + return NULL; + } sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(ma_int32); if (sampleDataSize > MA_SIZE_MAX) { ma_dr_wav_uninit(pWav); @@ -82625,7 +84537,7 @@ MA_PRIVATE ma_int32* ma_dr_wav__read_pcm_frames_and_close_s32(ma_dr_wav* pWav, u } return pSampleData; } -MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_wav wav; if (channelsOut) { @@ -82637,12 +84549,12 @@ MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRe if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_wav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_wav wav; if (channelsOut) { @@ -82654,12 +84566,12 @@ MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_wav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_wav wav; if (channelsOut) { @@ -82671,7 +84583,7 @@ MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRe if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_wav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); @@ -83979,7 +85891,7 @@ static MA_INLINE ma_uint32 ma_dr_flac__clz_lzcnt(ma_dr_flac_cache_t x) { ma_uint64 r; __asm__ __volatile__ ( - "lzcnt{ %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc" + "rep; bsr{q %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc" ); return (ma_uint32)r; } @@ -83987,11 +85899,11 @@ static MA_INLINE ma_uint32 ma_dr_flac__clz_lzcnt(ma_dr_flac_cache_t x) { ma_uint32 r; __asm__ __volatile__ ( - "lzcnt{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc" + "rep; bsr{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc" ); return r; } - #elif defined(MA_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(__ARM_ARCH_6M__) && !defined(MA_64BIT) + #elif defined(MA_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(__ARM_ARCH_6M__) && !(defined(__thumb__) && !defined(__thumb2__)) && !defined(MA_64BIT) { unsigned int r; __asm__ __volatile__ ( @@ -84106,23 +86018,23 @@ static ma_bool32 ma_dr_flac__seek_to_byte(ma_dr_flac_bs* bs, ma_uint64 offsetFro MA_DR_FLAC_ASSERT(offsetFromStart > 0); if (offsetFromStart > 0x7FFFFFFF) { ma_uint64 bytesRemaining = offsetFromStart; - if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_start)) { + if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } bytesRemaining -= 0x7FFFFFFF; while (bytesRemaining > 0x7FFFFFFF) { - if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_current)) { + if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } bytesRemaining -= 0x7FFFFFFF; } if (bytesRemaining > 0) { - if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, ma_dr_flac_seek_origin_current)) { + if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } } } else { - if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, ma_dr_flac_seek_origin_start)) { + if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } } @@ -86600,6 +88512,7 @@ typedef struct { ma_dr_flac_read_proc onRead; ma_dr_flac_seek_proc onSeek; + ma_dr_flac_tell_proc onTell; ma_dr_flac_meta_proc onMeta; ma_dr_flac_container container; void* pUserData; @@ -86728,11 +88641,12 @@ static void ma_dr_flac__free_from_callbacks(void* p, const ma_allocation_callbac pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); } } -static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, void* pUserDataMD, ma_uint64* pFirstFramePos, ma_uint64* pSeektablePos, ma_uint32* pSeekpointCount, ma_allocation_callbacks* pAllocationCallbacks) +static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, void* pUserData, void* pUserDataMD, ma_uint64* pFirstFramePos, ma_uint64* pSeektablePos, ma_uint32* pSeekpointCount, ma_allocation_callbacks* pAllocationCallbacks) { ma_uint64 runningFilePos = 42; ma_uint64 seektablePos = 0; ma_uint32 seektableSize = 0; + (void)onTell; for (;;) { ma_dr_flac_metadata metadata; ma_uint8 isLastBlock = 0; @@ -86743,8 +88657,9 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea } runningFilePos += 4; metadata.type = blockType; - metadata.pRawData = NULL; metadata.rawDataSize = 0; + metadata.rawDataOffset = runningFilePos; + metadata.pRawData = NULL; switch (blockType) { case MA_DR_FLAC_METADATA_BLOCK_TYPE_APPLICATION: @@ -86944,53 +88859,124 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea return MA_FALSE; } if (onMeta) { - void* pRawData; - const char* pRunningData; - const char* pRunningDataEnd; - pRawData = ma_dr_flac__malloc_from_callbacks(blockSize, pAllocationCallbacks); - if (pRawData == NULL) { + ma_bool32 result = MA_TRUE; + ma_uint32 blockSizeRemaining = blockSize; + char* pMime = NULL; + char* pDescription = NULL; + void* pPictureData = NULL; + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.type, 4) != 4) { + result = MA_FALSE; + goto done_flac; + } + blockSizeRemaining -= 4; + metadata.data.picture.type = ma_dr_flac__be2host_32(metadata.data.picture.type); + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.mimeLength, 4) != 4) { + result = MA_FALSE; + goto done_flac; + } + blockSizeRemaining -= 4; + metadata.data.picture.mimeLength = ma_dr_flac__be2host_32(metadata.data.picture.mimeLength); + pMime = (char*)ma_dr_flac__malloc_from_callbacks(metadata.data.picture.mimeLength + 1, pAllocationCallbacks); + if (pMime == NULL) { + result = MA_FALSE; + goto done_flac; + } + if (blockSizeRemaining < metadata.data.picture.mimeLength || onRead(pUserData, pMime, metadata.data.picture.mimeLength) != metadata.data.picture.mimeLength) { + result = MA_FALSE; + goto done_flac; + } + blockSizeRemaining -= metadata.data.picture.mimeLength; + pMime[metadata.data.picture.mimeLength] = '\0'; + metadata.data.picture.mime = (const char*)pMime; + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.descriptionLength, 4) != 4) { + result = MA_FALSE; + goto done_flac; + } + blockSizeRemaining -= 4; + metadata.data.picture.descriptionLength = ma_dr_flac__be2host_32(metadata.data.picture.descriptionLength); + pDescription = (char*)ma_dr_flac__malloc_from_callbacks(metadata.data.picture.descriptionLength + 1, pAllocationCallbacks); + if (pDescription == NULL) { + result = MA_FALSE; + goto done_flac; + } + if (blockSizeRemaining < metadata.data.picture.descriptionLength || onRead(pUserData, pDescription, metadata.data.picture.descriptionLength) != metadata.data.picture.descriptionLength) { + result = MA_FALSE; + goto done_flac; + } + blockSizeRemaining -= metadata.data.picture.descriptionLength; + pDescription[metadata.data.picture.descriptionLength] = '\0'; + metadata.data.picture.description = (const char*)pDescription; + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.width, 4) != 4) { + result = MA_FALSE; + goto done_flac; + } + blockSizeRemaining -= 4; + metadata.data.picture.width = ma_dr_flac__be2host_32(metadata.data.picture.width); + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.height, 4) != 4) { + result = MA_FALSE; + goto done_flac; + } + blockSizeRemaining -= 4; + metadata.data.picture.height = ma_dr_flac__be2host_32(metadata.data.picture.height); + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.colorDepth, 4) != 4) { + result = MA_FALSE; + goto done_flac; + } + blockSizeRemaining -= 4; + metadata.data.picture.colorDepth = ma_dr_flac__be2host_32(metadata.data.picture.colorDepth); + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.indexColorCount, 4) != 4) { + result = MA_FALSE; + goto done_flac; + } + blockSizeRemaining -= 4; + metadata.data.picture.indexColorCount = ma_dr_flac__be2host_32(metadata.data.picture.indexColorCount); + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.pictureDataSize, 4) != 4) { + result = MA_FALSE; + goto done_flac; + } + blockSizeRemaining -= 4; + metadata.data.picture.pictureDataSize = ma_dr_flac__be2host_32(metadata.data.picture.pictureDataSize); + if (blockSizeRemaining < metadata.data.picture.pictureDataSize) { + result = MA_FALSE; + goto done_flac; + } + metadata.data.picture.pictureDataOffset = runningFilePos + (blockSize - blockSizeRemaining); + #ifndef MA_DR_FLAC_NO_PICTURE_METADATA_MALLOC + pPictureData = ma_dr_flac__malloc_from_callbacks(metadata.data.picture.pictureDataSize, pAllocationCallbacks); + if (pPictureData != NULL) { + if (onRead(pUserData, pPictureData, metadata.data.picture.pictureDataSize) != metadata.data.picture.pictureDataSize) { + result = MA_FALSE; + goto done_flac; + } + } else + #endif + { + if (!onSeek(pUserData, metadata.data.picture.pictureDataSize, MA_DR_FLAC_SEEK_CUR)) { + result = MA_FALSE; + goto done_flac; + } + } + blockSizeRemaining -= metadata.data.picture.pictureDataSize; + (void)blockSizeRemaining; + metadata.data.picture.pPictureData = (const ma_uint8*)pPictureData; + if (metadata.data.picture.pictureDataOffset != 0 || metadata.data.picture.pPictureData != NULL) { + onMeta(pUserDataMD, &metadata); + } else { + } + done_flac: + ma_dr_flac__free_from_callbacks(pMime, pAllocationCallbacks); + ma_dr_flac__free_from_callbacks(pDescription, pAllocationCallbacks); + ma_dr_flac__free_from_callbacks(pPictureData, pAllocationCallbacks); + if (result != MA_TRUE) { return MA_FALSE; } - if (onRead(pUserData, pRawData, blockSize) != blockSize) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; - } - metadata.pRawData = pRawData; - metadata.rawDataSize = blockSize; - pRunningData = (const char*)pRawData; - pRunningDataEnd = (const char*)pRawData + blockSize; - metadata.data.picture.type = ma_dr_flac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.mimeLength = ma_dr_flac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - if ((pRunningDataEnd - pRunningData) - 24 < (ma_int64)metadata.data.picture.mimeLength) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; - } - metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; - metadata.data.picture.descriptionLength = ma_dr_flac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - if ((pRunningDataEnd - pRunningData) - 20 < (ma_int64)metadata.data.picture.descriptionLength) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; - } - metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength; - metadata.data.picture.width = ma_dr_flac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.height = ma_dr_flac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.colorDepth = ma_dr_flac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.indexColorCount = ma_dr_flac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.pictureDataSize = ma_dr_flac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; - metadata.data.picture.pPictureData = (const ma_uint8*)pRunningData; - if (pRunningDataEnd - pRunningData < (ma_int64)metadata.data.picture.pictureDataSize) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; - } - onMeta(pUserDataMD, &metadata); - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); } } break; case MA_DR_FLAC_METADATA_BLOCK_TYPE_PADDING: { if (onMeta) { metadata.data.padding.unused = 0; - if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, blockSize, MA_DR_FLAC_SEEK_CUR)) { isLastBlock = MA_TRUE; } else { onMeta(pUserDataMD, &metadata); @@ -87000,7 +88986,7 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea case MA_DR_FLAC_METADATA_BLOCK_TYPE_INVALID: { if (onMeta) { - if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, blockSize, MA_DR_FLAC_SEEK_CUR)) { isLastBlock = MA_TRUE; } } @@ -87009,12 +88995,15 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea { if (onMeta) { void* pRawData = ma_dr_flac__malloc_from_callbacks(blockSize, pAllocationCallbacks); - if (pRawData == NULL) { - return MA_FALSE; - } - if (onRead(pUserData, pRawData, blockSize) != blockSize) { - ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); - return MA_FALSE; + if (pRawData != NULL) { + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + return MA_FALSE; + } + } else { + if (!onSeek(pUserData, blockSize, MA_DR_FLAC_SEEK_CUR)) { + return MA_FALSE; + } } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; @@ -87024,7 +89013,7 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea } break; } if (onMeta == NULL && blockSize > 0) { - if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, blockSize, MA_DR_FLAC_SEEK_CUR)) { isLastBlock = MA_TRUE; } } @@ -87288,6 +89277,7 @@ typedef struct { ma_dr_flac_read_proc onRead; ma_dr_flac_seek_proc onSeek; + ma_dr_flac_tell_proc onTell; void* pUserData; ma_uint64 currentBytePos; ma_uint64 firstBytePos; @@ -87306,29 +89296,29 @@ static size_t ma_dr_flac_oggbs__read_physical(ma_dr_flac_oggbs* oggbs, void* buf } static ma_bool32 ma_dr_flac_oggbs__seek_physical(ma_dr_flac_oggbs* oggbs, ma_uint64 offset, ma_dr_flac_seek_origin origin) { - if (origin == ma_dr_flac_seek_origin_start) { + if (origin == MA_DR_FLAC_SEEK_SET) { if (offset <= 0x7FFFFFFF) { - if (!oggbs->onSeek(oggbs->pUserData, (int)offset, ma_dr_flac_seek_origin_start)) { + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } oggbs->currentBytePos = offset; return MA_TRUE; } else { - if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_start)) { + if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } oggbs->currentBytePos = offset; - return ma_dr_flac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, ma_dr_flac_seek_origin_current); + return ma_dr_flac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, MA_DR_FLAC_SEEK_CUR); } } else { while (offset > 0x7FFFFFFF) { - if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_current)) { + if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } oggbs->currentBytePos += 0x7FFFFFFF; offset -= 0x7FFFFFFF; } - if (!oggbs->onSeek(oggbs->pUserData, (int)offset, ma_dr_flac_seek_origin_current)) { + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } oggbs->currentBytePos += offset; @@ -87354,7 +89344,7 @@ static ma_bool32 ma_dr_flac_oggbs__goto_next_page(ma_dr_flac_oggbs* oggbs, ma_dr continue; } if (header.serialNumber != oggbs->serialNumber) { - if (pageBodySize > 0 && !ma_dr_flac_oggbs__seek_physical(oggbs, pageBodySize, ma_dr_flac_seek_origin_current)) { + if (pageBodySize > 0 && !ma_dr_flac_oggbs__seek_physical(oggbs, pageBodySize, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } continue; @@ -87416,7 +89406,7 @@ static ma_bool32 ma_dr_flac_oggbs__seek_to_next_packet(ma_dr_flac_oggbs* oggbs) } bytesToEndOfPacketOrPage += segmentSize; } - ma_dr_flac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, ma_dr_flac_seek_origin_current); + ma_dr_flac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, MA_DR_FLAC_SEEK_CUR); oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage; if (atEndOfPage) { if (!ma_dr_flac_oggbs__goto_next_page(oggbs)) { @@ -87469,36 +89459,44 @@ static ma_bool32 ma_dr_flac__on_seek_ogg(void* pUserData, int offset, ma_dr_flac int bytesSeeked = 0; MA_DR_FLAC_ASSERT(oggbs != NULL); MA_DR_FLAC_ASSERT(offset >= 0); - if (origin == ma_dr_flac_seek_origin_start) { - if (!ma_dr_flac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, ma_dr_flac_seek_origin_start)) { + if (origin == MA_DR_FLAC_SEEK_SET) { + if (!ma_dr_flac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_fail_on_crc_mismatch)) { return MA_FALSE; } - return ma_dr_flac__on_seek_ogg(pUserData, offset, ma_dr_flac_seek_origin_current); - } - MA_DR_FLAC_ASSERT(origin == ma_dr_flac_seek_origin_current); - while (bytesSeeked < offset) { - int bytesRemainingToSeek = offset - bytesSeeked; - MA_DR_FLAC_ASSERT(bytesRemainingToSeek >= 0); - if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) { - bytesSeeked += bytesRemainingToSeek; - (void)bytesSeeked; - oggbs->bytesRemainingInPage -= bytesRemainingToSeek; - break; - } - if (oggbs->bytesRemainingInPage > 0) { - bytesSeeked += (int)oggbs->bytesRemainingInPage; - oggbs->bytesRemainingInPage = 0; - } - MA_DR_FLAC_ASSERT(bytesRemainingToSeek > 0); - if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_fail_on_crc_mismatch)) { - return MA_FALSE; + return ma_dr_flac__on_seek_ogg(pUserData, offset, MA_DR_FLAC_SEEK_CUR); + } else if (origin == MA_DR_FLAC_SEEK_CUR) { + while (bytesSeeked < offset) { + int bytesRemainingToSeek = offset - bytesSeeked; + MA_DR_FLAC_ASSERT(bytesRemainingToSeek >= 0); + if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) { + bytesSeeked += bytesRemainingToSeek; + (void)bytesSeeked; + oggbs->bytesRemainingInPage -= bytesRemainingToSeek; + break; + } + if (oggbs->bytesRemainingInPage > 0) { + bytesSeeked += (int)oggbs->bytesRemainingInPage; + oggbs->bytesRemainingInPage = 0; + } + MA_DR_FLAC_ASSERT(bytesRemainingToSeek > 0); + if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_fail_on_crc_mismatch)) { + return MA_FALSE; + } } + } else if (origin == MA_DR_FLAC_SEEK_END) { + return MA_FALSE; } return MA_TRUE; } +static ma_bool32 ma_dr_flac__on_tell_ogg(void* pUserData, ma_int64* pCursor) +{ + (void)pUserData; + (void)pCursor; + return MA_FALSE; +} static ma_bool32 ma_dr_flac_ogg__seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 pcmFrameIndex) { ma_dr_flac_oggbs* oggbs = (ma_dr_flac_oggbs*)pFlac->_oggbs; @@ -87515,7 +89513,7 @@ static ma_bool32 ma_dr_flac_ogg__seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 runningGranulePosition = 0; for (;;) { if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_recover_on_crc_mismatch)) { - ma_dr_flac_oggbs__seek_physical(oggbs, originalBytePos, ma_dr_flac_seek_origin_start); + ma_dr_flac_oggbs__seek_physical(oggbs, originalBytePos, MA_DR_FLAC_SEEK_SET); return MA_FALSE; } runningFrameBytePos = oggbs->currentBytePos - ma_dr_flac_ogg__get_page_header_size(&oggbs->currentPageHeader) - oggbs->pageDataSize; @@ -87534,7 +89532,7 @@ static ma_bool32 ma_dr_flac_ogg__seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 } } } - if (!ma_dr_flac_oggbs__seek_physical(oggbs, runningFrameBytePos, ma_dr_flac_seek_origin_start)) { + if (!ma_dr_flac_oggbs__seek_physical(oggbs, runningFrameBytePos, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_recover_on_crc_mismatch)) { @@ -87629,7 +89627,7 @@ static ma_bool32 ma_dr_flac__init_private__ogg(ma_dr_flac_init_info* pInit, ma_d if (mappingVersion[0] != 1) { return MA_FALSE; } - if (!onSeek(pUserData, 2, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, 2, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } if (onRead(pUserData, sig, 4) != 4) { @@ -87674,17 +89672,17 @@ static ma_bool32 ma_dr_flac__init_private__ogg(ma_dr_flac_init_info* pInit, ma_d return MA_FALSE; } } else { - if (!onSeek(pUserData, bytesRemainingInPage, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, bytesRemainingInPage, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } } } else { - if (!onSeek(pUserData, bytesRemainingInPage, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, bytesRemainingInPage, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } } } else { - if (!onSeek(pUserData, pageBodySize, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, pageBodySize, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } } @@ -87698,7 +89696,7 @@ static ma_bool32 ma_dr_flac__init_private__ogg(ma_dr_flac_init_info* pInit, ma_d return MA_TRUE; } #endif -static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD) +static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD) { ma_bool32 relaxed; ma_uint8 id[4]; @@ -87708,12 +89706,14 @@ static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_fla MA_DR_FLAC_ZERO_MEMORY(pInit, sizeof(*pInit)); pInit->onRead = onRead; pInit->onSeek = onSeek; + pInit->onTell = onTell; pInit->onMeta = onMeta; pInit->container = container; pInit->pUserData = pUserData; pInit->pUserDataMD = pUserDataMD; pInit->bs.onRead = onRead; pInit->bs.onSeek = onSeek; + pInit->bs.onTell = onTell; pInit->bs.pUserData = pUserData; ma_dr_flac__reset_cache(&pInit->bs); relaxed = container != ma_dr_flac_container_unknown; @@ -87736,7 +89736,7 @@ static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_fla if (flags & 0x10) { headerSize += 10; } - if (!onSeek(pUserData, headerSize, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, headerSize, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } pInit->runningFilePos += headerSize; @@ -87779,7 +89779,7 @@ static void ma_dr_flac__init_from_info(ma_dr_flac* pFlac, const ma_dr_flac_init_ pFlac->totalPCMFrameCount = pInit->totalPCMFrameCount; pFlac->container = pInit->container; } -static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD, const ma_allocation_callbacks* pAllocationCallbacks) +static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_flac_init_info init; ma_uint32 allocationSize; @@ -87794,7 +89794,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on ma_allocation_callbacks allocationCallbacks; ma_dr_flac* pFlac; ma_dr_flac__init_cpu_caps(); - if (!ma_dr_flac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) { + if (!ma_dr_flac__init_private(&init, onRead, onSeek, onTell, onMeta, container, pUserData, pUserDataMD)) { return NULL; } if (pAllocationCallbacks != NULL) { @@ -87827,6 +89827,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on MA_DR_FLAC_ZERO_MEMORY(pOggbs, sizeof(*pOggbs)); pOggbs->onRead = onRead; pOggbs->onSeek = onSeek; + pOggbs->onTell = onTell; pOggbs->pUserData = pUserData; pOggbs->currentBytePos = init.oggFirstBytePos; pOggbs->firstBytePos = init.oggFirstBytePos; @@ -87841,15 +89842,17 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on if (init.hasMetadataBlocks) { ma_dr_flac_read_proc onReadOverride = onRead; ma_dr_flac_seek_proc onSeekOverride = onSeek; + ma_dr_flac_tell_proc onTellOverride = onTell; void* pUserDataOverride = pUserData; #ifndef MA_DR_FLAC_NO_OGG if (init.container == ma_dr_flac_container_ogg) { onReadOverride = ma_dr_flac__on_read_ogg; onSeekOverride = ma_dr_flac__on_seek_ogg; + onTellOverride = ma_dr_flac__on_tell_ogg; pUserDataOverride = (void*)pOggbs; } #endif - if (!ma_dr_flac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) { + if (!ma_dr_flac__read_and_decode_metadata(onReadOverride, onSeekOverride, onTellOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) { #ifndef MA_DR_FLAC_NO_OGG ma_dr_flac__free_from_callbacks(pOggbs, &allocationCallbacks); #endif @@ -87875,6 +89878,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on pOggbs = NULL; pFlac->bs.onRead = ma_dr_flac__on_read_ogg; pFlac->bs.onSeek = ma_dr_flac__on_seek_ogg; + pFlac->bs.onTell = ma_dr_flac__on_tell_ogg; pFlac->bs.pUserData = (void*)pInternalOggbs; pFlac->_oggbs = (void*)pInternalOggbs; } @@ -87894,7 +89898,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on pFlac->pSeekpoints = (ma_dr_flac_seekpoint*)((ma_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize); MA_DR_FLAC_ASSERT(pFlac->bs.onSeek != NULL); MA_DR_FLAC_ASSERT(pFlac->bs.onRead != NULL); - if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, ma_dr_flac_seek_origin_start)) { + if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, MA_DR_FLAC_SEEK_SET)) { ma_uint32 iSeekpoint; for (iSeekpoint = 0; iSeekpoint < seekpointCount; iSeekpoint += 1) { if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints + iSeekpoint, MA_DR_FLAC_SEEKPOINT_SIZE_IN_BYTES) == MA_DR_FLAC_SEEKPOINT_SIZE_IN_BYTES) { @@ -87907,7 +89911,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on break; } } - if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, ma_dr_flac_seek_origin_start)) { + if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, MA_DR_FLAC_SEEK_SET)) { ma_dr_flac__free_from_callbacks(pFlac, &allocationCallbacks); return NULL; } @@ -87950,8 +89954,31 @@ static size_t ma_dr_flac__on_read_stdio(void* pUserData, void* bufferOut, size_t } static ma_bool32 ma_dr_flac__on_seek_stdio(void* pUserData, int offset, ma_dr_flac_seek_origin origin) { - MA_DR_FLAC_ASSERT(offset >= 0); - return fseek((FILE*)pUserData, offset, (origin == ma_dr_flac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; + int whence = SEEK_SET; + if (origin == MA_DR_FLAC_SEEK_CUR) { + whence = SEEK_CUR; + } else if (origin == MA_DR_FLAC_SEEK_END) { + whence = SEEK_END; + } + return fseek((FILE*)pUserData, offset, whence) == 0; +} +static ma_bool32 ma_dr_flac__on_tell_stdio(void* pUserData, ma_int64* pCursor) +{ + FILE* pFileStdio = (FILE*)pUserData; + ma_int64 result; + MA_DR_FLAC_ASSERT(pFileStdio != NULL); + MA_DR_FLAC_ASSERT(pCursor != NULL); +#if defined(_WIN32) && !defined(NXDK) + #if defined(_MSC_VER) && _MSC_VER > 1200 + result = _ftelli64(pFileStdio); + #else + result = ftell(pFileStdio); + #endif +#else + result = ftell(pFileStdio); +#endif + *pCursor = result; + return MA_TRUE; } MA_API ma_dr_flac* ma_dr_flac_open_file(const char* pFileName, const ma_allocation_callbacks* pAllocationCallbacks) { @@ -87960,7 +89987,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_file(const char* pFileName, const ma_allocati if (ma_fopen(&pFile, pFileName, "rb") != MA_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, ma_dr_flac__on_tell_stdio, (void*)pFile, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return NULL; @@ -87975,7 +90002,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_w(const wchar_t* pFileName, const ma_all if (ma_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != MA_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, ma_dr_flac__on_tell_stdio, (void*)pFile, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return NULL; @@ -87990,7 +90017,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata(const char* pFileName, ma_ if (ma_fopen(&pFile, pFileName, "rb") != MA_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, ma_dr_flac__on_tell_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return pFlac; @@ -88005,7 +90032,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata_w(const wchar_t* pFileName if (ma_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != MA_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, ma_dr_flac__on_tell_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return pFlac; @@ -88033,24 +90060,34 @@ static size_t ma_dr_flac__on_read_memory(void* pUserData, void* bufferOut, size_ static ma_bool32 ma_dr_flac__on_seek_memory(void* pUserData, int offset, ma_dr_flac_seek_origin origin) { ma_dr_flac__memory_stream* memoryStream = (ma_dr_flac__memory_stream*)pUserData; + ma_int64 newCursor; MA_DR_FLAC_ASSERT(memoryStream != NULL); - MA_DR_FLAC_ASSERT(offset >= 0); - if (offset > (ma_int64)memoryStream->dataSize) { + if (origin == MA_DR_FLAC_SEEK_SET) { + newCursor = 0; + } else if (origin == MA_DR_FLAC_SEEK_CUR) { + newCursor = (ma_int64)memoryStream->currentReadPos; + } else if (origin == MA_DR_FLAC_SEEK_END) { + newCursor = (ma_int64)memoryStream->dataSize; + } else { + MA_DR_FLAC_ASSERT(!"Invalid seek origin"); return MA_FALSE; } - if (origin == ma_dr_flac_seek_origin_current) { - if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) { - memoryStream->currentReadPos += offset; - } else { - return MA_FALSE; - } - } else { - if ((ma_uint32)offset <= memoryStream->dataSize) { - memoryStream->currentReadPos = offset; - } else { - return MA_FALSE; - } + newCursor += offset; + if (newCursor < 0) { + return MA_FALSE; } + if ((size_t)newCursor > memoryStream->dataSize) { + return MA_FALSE; + } + memoryStream->currentReadPos = (size_t)newCursor; + return MA_TRUE; +} +static ma_bool32 ma_dr_flac__on_tell_memory(void* pUserData, ma_int64* pCursor) +{ + ma_dr_flac__memory_stream* memoryStream = (ma_dr_flac__memory_stream*)pUserData; + MA_DR_FLAC_ASSERT(memoryStream != NULL); + MA_DR_FLAC_ASSERT(pCursor != NULL); + *pCursor = (ma_int64)memoryStream->currentReadPos; return MA_TRUE; } MA_API ma_dr_flac* ma_dr_flac_open_memory(const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) @@ -88060,7 +90097,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_memory(const void* pData, size_t dataSize, co memoryStream.data = (const ma_uint8*)pData; memoryStream.dataSize = dataSize; memoryStream.currentReadPos = 0; - pFlac = ma_dr_flac_open(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, &memoryStream, pAllocationCallbacks); + pFlac = ma_dr_flac_open(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, ma_dr_flac__on_tell_memory, &memoryStream, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } @@ -88085,7 +90122,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_memory_with_metadata(const void* pData, size_ memoryStream.data = (const ma_uint8*)pData; memoryStream.dataSize = dataSize; memoryStream.currentReadPos = 0; - pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, onMeta, ma_dr_flac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, ma_dr_flac__on_tell_memory, onMeta, ma_dr_flac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } @@ -88103,21 +90140,21 @@ MA_API ma_dr_flac* ma_dr_flac_open_memory_with_metadata(const void* pData, size_ } return pFlac; } -MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, NULL, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onTell, NULL, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); } -MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onTell, NULL, container, pUserData, pUserData, pAllocationCallbacks); } -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onMeta, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onTell, onMeta, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); } -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onTell, onMeta, container, pUserData, pUserData, pAllocationCallbacks); } MA_API void ma_dr_flac_close(ma_dr_flac* pFlac) { @@ -90345,56 +92382,41 @@ static type* ma_dr_flac__full_read_and_close_ ## extension (ma_dr_flac* pFlac, u { \ type* pSampleData = NULL; \ ma_uint64 totalPCMFrameCount; \ + type buffer[4096]; \ + ma_uint64 pcmFramesRead; \ + size_t sampleDataBufferSize = sizeof(buffer); \ \ MA_DR_FLAC_ASSERT(pFlac != NULL); \ \ - totalPCMFrameCount = pFlac->totalPCMFrameCount; \ + totalPCMFrameCount = 0; \ \ - if (totalPCMFrameCount == 0) { \ - type buffer[4096]; \ - ma_uint64 pcmFramesRead; \ - size_t sampleDataBufferSize = sizeof(buffer); \ + pSampleData = (type*)ma_dr_flac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks); \ + if (pSampleData == NULL) { \ + goto on_error; \ + } \ \ - pSampleData = (type*)ma_dr_flac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks); \ - if (pSampleData == NULL) { \ - goto on_error; \ - } \ + while ((pcmFramesRead = (ma_uint64)ma_dr_flac_read_pcm_frames_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0])/pFlac->channels, buffer)) > 0) { \ + if (((totalPCMFrameCount + pcmFramesRead) * pFlac->channels * sizeof(type)) > sampleDataBufferSize) { \ + type* pNewSampleData; \ + size_t newSampleDataBufferSize; \ \ - while ((pcmFramesRead = (ma_uint64)ma_dr_flac_read_pcm_frames_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0])/pFlac->channels, buffer)) > 0) { \ - if (((totalPCMFrameCount + pcmFramesRead) * pFlac->channels * sizeof(type)) > sampleDataBufferSize) { \ - type* pNewSampleData; \ - size_t newSampleDataBufferSize; \ - \ - newSampleDataBufferSize = sampleDataBufferSize * 2; \ - pNewSampleData = (type*)ma_dr_flac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks); \ - if (pNewSampleData == NULL) { \ - ma_dr_flac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks); \ - goto on_error; \ - } \ - \ - sampleDataBufferSize = newSampleDataBufferSize; \ - pSampleData = pNewSampleData; \ + newSampleDataBufferSize = sampleDataBufferSize * 2; \ + pNewSampleData = (type*)ma_dr_flac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks); \ + if (pNewSampleData == NULL) { \ + ma_dr_flac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks); \ + goto on_error; \ } \ \ - MA_DR_FLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type))); \ - totalPCMFrameCount += pcmFramesRead; \ + sampleDataBufferSize = newSampleDataBufferSize; \ + pSampleData = pNewSampleData; \ } \ \ + MA_DR_FLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type))); \ + totalPCMFrameCount += pcmFramesRead; \ + } \ + \ \ - MA_DR_FLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type))); \ - } else { \ - ma_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type); \ - if (dataSize > (ma_uint64)MA_SIZE_MAX) { \ - goto on_error; \ - } \ - \ - pSampleData = (type*)ma_dr_flac__malloc_from_callbacks((size_t)dataSize, &pFlac->allocationCallbacks); \ - if (pSampleData == NULL) { \ - goto on_error; \ - } \ - \ - totalPCMFrameCount = ma_dr_flac_read_pcm_frames_##extension(pFlac, pFlac->totalPCMFrameCount, pSampleData); \ - } \ + MA_DR_FLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type))); \ \ if (sampleRateOut) *sampleRateOut = pFlac->sampleRate; \ if (channelsOut) *channelsOut = pFlac->channels; \ @@ -90410,7 +92432,7 @@ on_error: MA_DR_FLAC_DEFINE_FULL_READ_AND_CLOSE(s32, ma_int32) MA_DR_FLAC_DEFINE_FULL_READ_AND_CLOSE(s16, ma_int16) MA_DR_FLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float) -MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_flac* pFlac; if (channelsOut) { @@ -90422,13 +92444,13 @@ MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc on if (totalPCMFrameCountOut) { *totalPCMFrameCountOut = 0; } - pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } return ma_dr_flac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); } -MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_flac* pFlac; if (channelsOut) { @@ -90440,13 +92462,13 @@ MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc on if (totalPCMFrameCountOut) { *totalPCMFrameCountOut = 0; } - pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } return ma_dr_flac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); } -MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_flac* pFlac; if (channelsOut) { @@ -90458,7 +92480,7 @@ MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRea if (totalPCMFrameCountOut) { *totalPCMFrameCountOut = 0; } - pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } @@ -90680,12 +92702,9 @@ MA_API const char* ma_dr_mp3_version_string(void) #define MA_DR_MP3_NO_SIMD #endif #define MA_DR_MP3_OFFSET_PTR(p, offset) ((void*)((ma_uint8*)(p) + (offset))) -#define MA_DR_MP3_MAX_FREE_FORMAT_FRAME_SIZE 2304 #ifndef MA_DR_MP3_MAX_FRAME_SYNC_MATCHES #define MA_DR_MP3_MAX_FRAME_SYNC_MATCHES 10 #endif -#define MA_DR_MP3_MAX_L3_FRAME_PAYLOAD_BYTES MA_DR_MP3_MAX_FREE_FORMAT_FRAME_SIZE -#define MA_DR_MP3_MAX_BITRESERVOIR_BYTES 511 #define MA_DR_MP3_SHORT_BLOCK_TYPE 2 #define MA_DR_MP3_STOP_BLOCK_TYPE 3 #define MA_DR_MP3_MODE_MONO 3 @@ -90735,7 +92754,7 @@ MA_API const char* ma_dr_mp3_version_string(void) #define MA_DR_MP3_VMUL_S(x, s) _mm_mul_ps(x, _mm_set1_ps(s)) #define MA_DR_MP3_VREV(x) _mm_shuffle_ps(x, x, _MM_SHUFFLE(0, 1, 2, 3)) typedef __m128 ma_dr_mp3_f4; -#if defined(_MSC_VER) || defined(MA_DR_MP3_ONLY_SIMD) +#if (defined(_MSC_VER) || defined(MA_DR_MP3_ONLY_SIMD)) && !defined(__clang__) #define ma_dr_mp3_cpuid __cpuid #else static __inline__ __attribute__((always_inline)) void ma_dr_mp3_cpuid(int CPUInfo[], const int InfoType) @@ -90851,11 +92870,6 @@ static __inline__ __attribute__((always_inline)) ma_int32 ma_dr_mp3_clip_int16_a #define MA_DR_MP3_FREE(p) free((p)) #endif typedef struct -{ - const ma_uint8 *buf; - int pos, limit; -} ma_dr_mp3_bs; -typedef struct { float scf[3*64]; ma_uint8 total_bands, stereo_bands, bitalloc[64], scfcod[64]; @@ -90864,22 +92878,6 @@ typedef struct { ma_uint8 tab_offset, code_tab_width, band_count; } ma_dr_mp3_L12_subband_alloc; -typedef struct -{ - const ma_uint8 *sfbtab; - ma_uint16 part_23_length, big_values, scalefac_compress; - ma_uint8 global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb; - ma_uint8 table_select[3], region_count[3], subblock_gain[3]; - ma_uint8 preflag, scalefac_scale, count1_table, scfsi; -} ma_dr_mp3_L3_gr_info; -typedef struct -{ - ma_dr_mp3_bs bs; - ma_uint8 maindata[MA_DR_MP3_MAX_BITRESERVOIR_BYTES + MA_DR_MP3_MAX_L3_FRAME_PAYLOAD_BYTES]; - ma_dr_mp3_L3_gr_info gr_info[4]; - float grbuf[2][576], scf[40], syn[18 + 15][2*32]; - ma_uint8 ist_pos[2][39]; -} ma_dr_mp3dec_scratch; static void ma_dr_mp3_bs_init(ma_dr_mp3_bs *bs, const ma_uint8 *data, int bytes) { bs->buf = data; @@ -91262,6 +93260,10 @@ static float ma_dr_mp3_L3_ldexp_q2(float y, int exp_q2) } while ((exp_q2 -= e) > 0); return y; } +#if (defined(__GNUC__) && (__GNUC__ >= 13)) && !defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif static void ma_dr_mp3_L3_decode_scalefactors(const ma_uint8 *hdr, ma_uint8 *ist_pos, ma_dr_mp3_bs *bs, const ma_dr_mp3_L3_gr_info *gr, float *scf, int ch) { static const ma_uint8 g_scf_partitions[3][28] = { @@ -91320,7 +93322,10 @@ static void ma_dr_mp3_L3_decode_scalefactors(const ma_uint8 *hdr, ma_uint8 *ist_ scf[i] = ma_dr_mp3_L3_ldexp_q2(gain, iscf[i] << scf_shift); } } -static const float g_ma_dr_mp3_pow43[129 + 16] = { +#if (defined(__GNUC__) && (__GNUC__ >= 13)) && !defined(__clang__) + #pragma GCC diagnostic pop +#endif +static const float ma_dr_mp3_g_pow43[129 + 16] = { 0,-1,-2.519842f,-4.326749f,-6.349604f,-8.549880f,-10.902724f,-13.390518f,-16.000000f,-18.720754f,-21.544347f,-24.463781f,-27.473142f,-30.567351f,-33.741992f,-36.993181f, 0,1,2.519842f,4.326749f,6.349604f,8.549880f,10.902724f,13.390518f,16.000000f,18.720754f,21.544347f,24.463781f,27.473142f,30.567351f,33.741992f,36.993181f,40.317474f,43.711787f,47.173345f,50.699631f,54.288352f,57.937408f,61.644865f,65.408941f,69.227979f,73.100443f,77.024898f,81.000000f,85.024491f,89.097188f,93.216975f,97.382800f,101.593667f,105.848633f,110.146801f,114.487321f,118.869381f,123.292209f,127.755065f,132.257246f,136.798076f,141.376907f,145.993119f,150.646117f,155.335327f,160.060199f,164.820202f,169.614826f,174.443577f,179.305980f,184.201575f,189.129918f,194.090580f,199.083145f,204.107210f,209.162385f,214.248292f,219.364564f,224.510845f,229.686789f,234.892058f,240.126328f,245.389280f,250.680604f,256.000000f,261.347174f,266.721841f,272.123723f,277.552547f,283.008049f,288.489971f,293.998060f,299.532071f,305.091761f,310.676898f,316.287249f,321.922592f,327.582707f,333.267377f,338.976394f,344.709550f,350.466646f,356.247482f,362.051866f,367.879608f,373.730522f,379.604427f,385.501143f,391.420496f,397.362314f,403.326427f,409.312672f,415.320884f,421.350905f,427.402579f,433.475750f,439.570269f,445.685987f,451.822757f,457.980436f,464.158883f,470.357960f,476.577530f,482.817459f,489.077615f,495.357868f,501.658090f,507.978156f,514.317941f,520.677324f,527.056184f,533.454404f,539.871867f,546.308458f,552.764065f,559.238575f,565.731879f,572.243870f,578.774440f,585.323483f,591.890898f,598.476581f,605.080431f,611.702349f,618.342238f,625.000000f,631.675540f,638.368763f,645.079578f }; @@ -91330,7 +93335,7 @@ static float ma_dr_mp3_L3_pow_43(int x) int sign, mult = 256; if (x < 129) { - return g_ma_dr_mp3_pow43[16 + x]; + return ma_dr_mp3_g_pow43[16 + x]; } if (x < 1024) { @@ -91339,7 +93344,7 @@ static float ma_dr_mp3_L3_pow_43(int x) } sign = 2*x & 64; frac = (float)((x & 63) - sign) / ((x & ~63) + sign); - return g_ma_dr_mp3_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; + return ma_dr_mp3_g_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; } static void ma_dr_mp3_L3_huffman(float *dst, ma_dr_mp3_bs *bs, const ma_dr_mp3_L3_gr_info *gr_info, const float *scf, int layer3gr_limit) { @@ -91409,7 +93414,7 @@ static void ma_dr_mp3_L3_huffman(float *dst, ma_dr_mp3_bs *bs, const ma_dr_mp3_L *dst = one*ma_dr_mp3_L3_pow_43(lsb)*((ma_int32)bs_cache < 0 ? -1: 1); } else { - *dst = g_ma_dr_mp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + *dst = ma_dr_mp3_g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; } MA_DR_MP3_FLUSH_BITS(lsb ? 1 : 0); } @@ -91437,7 +93442,7 @@ static void ma_dr_mp3_L3_huffman(float *dst, ma_dr_mp3_bs *bs, const ma_dr_mp3_L for (j = 0; j < 2; j++, dst++, leaf >>= 4) { int lsb = leaf & 0x0F; - *dst = g_ma_dr_mp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + *dst = ma_dr_mp3_g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; MA_DR_MP3_FLUSH_BITS(lsb ? 1 : 0); } MA_DR_MP3_CHECK_BITS; @@ -92245,7 +94250,6 @@ MA_API int ma_dr_mp3dec_decode_frame(ma_dr_mp3dec *dec, const ma_uint8 *mp3, int int i = 0, igr, frame_size = 0, success = 1; const ma_uint8 *hdr; ma_dr_mp3_bs bs_frame[1]; - ma_dr_mp3dec_scratch scratch; if (mp3_bytes > 4 && dec->header[0] == 0xff && ma_dr_mp3_hdr_compare(dec->header, mp3)) { frame_size = ma_dr_mp3_hdr_frame_bytes(mp3, dec->free_format_bytes) + ma_dr_mp3_hdr_padding(mp3); @@ -92268,7 +94272,7 @@ MA_API int ma_dr_mp3dec_decode_frame(ma_dr_mp3dec *dec, const ma_uint8 *mp3, int MA_DR_MP3_COPY_MEMORY(dec->header, hdr, MA_DR_MP3_HDR_SIZE); info->frame_bytes = i + frame_size; info->channels = MA_DR_MP3_HDR_IS_MONO(hdr) ? 1 : 2; - info->hz = ma_dr_mp3_hdr_sample_rate_hz(hdr); + info->sample_rate = ma_dr_mp3_hdr_sample_rate_hz(hdr); info->layer = 4 - MA_DR_MP3_HDR_GET_LAYER(hdr); info->bitrate_kbps = ma_dr_mp3_hdr_bitrate_kbps(hdr); ma_dr_mp3_bs_init(bs_frame, hdr + MA_DR_MP3_HDR_SIZE, frame_size - MA_DR_MP3_HDR_SIZE); @@ -92278,23 +94282,23 @@ MA_API int ma_dr_mp3dec_decode_frame(ma_dr_mp3dec *dec, const ma_uint8 *mp3, int } if (info->layer == 3) { - int main_data_begin = ma_dr_mp3_L3_read_side_info(bs_frame, scratch.gr_info, hdr); + int main_data_begin = ma_dr_mp3_L3_read_side_info(bs_frame, dec->scratch.gr_info, hdr); if (main_data_begin < 0 || bs_frame->pos > bs_frame->limit) { ma_dr_mp3dec_init(dec); return 0; } - success = ma_dr_mp3_L3_restore_reservoir(dec, bs_frame, &scratch, main_data_begin); + success = ma_dr_mp3_L3_restore_reservoir(dec, bs_frame, &dec->scratch, main_data_begin); if (success && pcm != NULL) { for (igr = 0; igr < (MA_DR_MP3_HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm = MA_DR_MP3_OFFSET_PTR(pcm, sizeof(ma_dr_mp3d_sample_t)*576*info->channels)) { - MA_DR_MP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float)); - ma_dr_mp3_L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels); - ma_dr_mp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, (ma_dr_mp3d_sample_t*)pcm, scratch.syn[0]); + MA_DR_MP3_ZERO_MEMORY(dec->scratch.grbuf[0], 576*2*sizeof(float)); + ma_dr_mp3_L3_decode(dec, &dec->scratch, dec->scratch.gr_info + igr*info->channels, info->channels); + ma_dr_mp3d_synth_granule(dec->qmf_state, dec->scratch.grbuf[0], 18, info->channels, (ma_dr_mp3d_sample_t*)pcm, dec->scratch.syn[0]); } } - ma_dr_mp3_L3_save_reservoir(dec, &scratch); + ma_dr_mp3_L3_save_reservoir(dec, &dec->scratch); } else { #ifdef MA_DR_MP3_ONLY_MP3 @@ -92305,15 +94309,15 @@ MA_API int ma_dr_mp3dec_decode_frame(ma_dr_mp3dec *dec, const ma_uint8 *mp3, int return ma_dr_mp3_hdr_frame_samples(hdr); } ma_dr_mp3_L12_read_scale_info(hdr, bs_frame, sci); - MA_DR_MP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float)); + MA_DR_MP3_ZERO_MEMORY(dec->scratch.grbuf[0], 576*2*sizeof(float)); for (i = 0, igr = 0; igr < 3; igr++) { - if (12 == (i += ma_dr_mp3_L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1))) + if (12 == (i += ma_dr_mp3_L12_dequantize_granule(dec->scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1))) { i = 0; - ma_dr_mp3_L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]); - ma_dr_mp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, (ma_dr_mp3d_sample_t*)pcm, scratch.syn[0]); - MA_DR_MP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float)); + ma_dr_mp3_L12_apply_scf_384(sci, sci->scf + igr, dec->scratch.grbuf[0]); + ma_dr_mp3d_synth_granule(dec->qmf_state, dec->scratch.grbuf[0], 12, info->channels, (ma_dr_mp3d_sample_t*)pcm, dec->scratch.syn[0]); + MA_DR_MP3_ZERO_MEMORY(dec->scratch.grbuf[0], 576*2*sizeof(float)); pcm = MA_DR_MP3_OFFSET_PTR(pcm, sizeof(ma_dr_mp3d_sample_t)*384*info->channels); } if (bs_frame->pos > bs_frame->limit) @@ -92491,19 +94495,41 @@ static ma_allocation_callbacks ma_dr_mp3_copy_allocation_callbacks_or_defaults(c } static size_t ma_dr_mp3__on_read(ma_dr_mp3* pMP3, void* pBufferOut, size_t bytesToRead) { - size_t bytesRead = pMP3->onRead(pMP3->pUserData, pBufferOut, bytesToRead); + size_t bytesRead; + MA_DR_MP3_ASSERT(pMP3 != NULL); + MA_DR_MP3_ASSERT(pMP3->onRead != NULL); + if (bytesToRead == 0) { + return 0; + } + bytesRead = pMP3->onRead(pMP3->pUserData, pBufferOut, bytesToRead); pMP3->streamCursor += bytesRead; return bytesRead; } +static size_t ma_dr_mp3__on_read_clamped(ma_dr_mp3* pMP3, void* pBufferOut, size_t bytesToRead) +{ + MA_DR_MP3_ASSERT(pMP3 != NULL); + MA_DR_MP3_ASSERT(pMP3->onRead != NULL); + if (pMP3->streamLength == MA_UINT64_MAX) { + return ma_dr_mp3__on_read(pMP3, pBufferOut, bytesToRead); + } else { + ma_uint64 bytesRemaining; + bytesRemaining = (pMP3->streamLength - pMP3->streamCursor); + if (bytesToRead > bytesRemaining) { + bytesToRead = (size_t)bytesRemaining; + } + return ma_dr_mp3__on_read(pMP3, pBufferOut, bytesToRead); + } +} static ma_bool32 ma_dr_mp3__on_seek(ma_dr_mp3* pMP3, int offset, ma_dr_mp3_seek_origin origin) { MA_DR_MP3_ASSERT(offset >= 0); + MA_DR_MP3_ASSERT(origin == MA_DR_MP3_SEEK_SET || origin == MA_DR_MP3_SEEK_CUR); if (!pMP3->onSeek(pMP3->pUserData, offset, origin)) { return MA_FALSE; } - if (origin == ma_dr_mp3_seek_origin_start) { + if (origin == MA_DR_MP3_SEEK_SET) { pMP3->streamCursor = (ma_uint64)offset; - } else { + } else{ pMP3->streamCursor += offset; } return MA_TRUE; @@ -92513,18 +94539,18 @@ static ma_bool32 ma_dr_mp3__on_seek_64(ma_dr_mp3* pMP3, ma_uint64 offset, ma_dr_ if (offset <= 0x7FFFFFFF) { return ma_dr_mp3__on_seek(pMP3, (int)offset, origin); } - if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, ma_dr_mp3_seek_origin_start)) { + if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, MA_DR_MP3_SEEK_SET)) { return MA_FALSE; } offset -= 0x7FFFFFFF; while (offset > 0) { if (offset <= 0x7FFFFFFF) { - if (!ma_dr_mp3__on_seek(pMP3, (int)offset, ma_dr_mp3_seek_origin_current)) { + if (!ma_dr_mp3__on_seek(pMP3, (int)offset, MA_DR_MP3_SEEK_CUR)) { return MA_FALSE; } offset = 0; } else { - if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, ma_dr_mp3_seek_origin_current)) { + if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, MA_DR_MP3_SEEK_CUR)) { return MA_FALSE; } offset -= 0x7FFFFFFF; @@ -92532,7 +94558,18 @@ static ma_bool32 ma_dr_mp3__on_seek_64(ma_dr_mp3* pMP3, ma_uint64 offset, ma_dr_ } return MA_TRUE; } -static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames) +static void ma_dr_mp3__on_meta(ma_dr_mp3* pMP3, ma_dr_mp3_metadata_type type, const void* pRawData, size_t rawDataSize) +{ + if (pMP3->onMeta) { + ma_dr_mp3_metadata metadata; + MA_DR_MP3_ZERO_OBJECT(&metadata); + metadata.type = type; + metadata.pRawData = pRawData; + metadata.rawDataSize = rawDataSize; + pMP3->onMeta(pMP3->pUserDataMeta, &metadata); + } +} +static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames, ma_dr_mp3dec_frame_info* pMP3FrameInfo, const ma_uint8** ppMP3FrameData) { ma_uint32 pcmFramesRead = 0; MA_DR_MP3_ASSERT(pMP3 != NULL); @@ -92559,7 +94596,7 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d pMP3->pData = pNewData; pMP3->dataCapacity = newDataCap; } - bytesRead = ma_dr_mp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); + bytesRead = ma_dr_mp3__on_read_clamped(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); if (bytesRead == 0) { if (pMP3->dataSize == 0) { pMP3->atEnd = MA_TRUE; @@ -92578,16 +94615,20 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d return 0; } pcmFramesRead = ma_dr_mp3dec_decode_frame(&pMP3->decoder, pMP3->pData + pMP3->dataConsumed, (int)pMP3->dataSize, pPCMFrames, &info); - if (info.frame_bytes > 0) { - pMP3->dataConsumed += (size_t)info.frame_bytes; - pMP3->dataSize -= (size_t)info.frame_bytes; - } + pMP3->dataConsumed += (size_t)info.frame_bytes; + pMP3->dataSize -= (size_t)info.frame_bytes; if (pcmFramesRead > 0) { pcmFramesRead = ma_dr_mp3_hdr_frame_samples(pMP3->decoder.header); pMP3->pcmFramesConsumedInMP3Frame = 0; pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; pMP3->mp3FrameChannels = info.channels; - pMP3->mp3FrameSampleRate = info.hz; + pMP3->mp3FrameSampleRate = info.sample_rate; + if (pMP3FrameInfo != NULL) { + *pMP3FrameInfo = info; + } + if (ppMP3FrameData != NULL) { + *ppMP3FrameData = pMP3->pData + pMP3->dataConsumed - (size_t)info.frame_bytes; + } break; } else if (info.frame_bytes == 0) { size_t bytesRead; @@ -92604,7 +94645,7 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d pMP3->pData = pNewData; pMP3->dataCapacity = newDataCap; } - bytesRead = ma_dr_mp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); + bytesRead = ma_dr_mp3__on_read_clamped(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); if (bytesRead == 0) { pMP3->atEnd = MA_TRUE; return 0; @@ -92614,7 +94655,7 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d }; return pcmFramesRead; } -static ma_uint32 ma_dr_mp3_decode_next_frame_ex__memory(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames) +static ma_uint32 ma_dr_mp3_decode_next_frame_ex__memory(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames, ma_dr_mp3dec_frame_info* pMP3FrameInfo, const ma_uint8** ppMP3FrameData) { ma_uint32 pcmFramesRead = 0; ma_dr_mp3dec_frame_info info; @@ -92630,36 +94671,44 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__memory(ma_dr_mp3* pMP3, ma_dr_m pMP3->pcmFramesConsumedInMP3Frame = 0; pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; pMP3->mp3FrameChannels = info.channels; - pMP3->mp3FrameSampleRate = info.hz; + pMP3->mp3FrameSampleRate = info.sample_rate; + if (pMP3FrameInfo != NULL) { + *pMP3FrameInfo = info; + } + if (ppMP3FrameData != NULL) { + *ppMP3FrameData = pMP3->memory.pData + pMP3->memory.currentReadPos; + } break; } else if (info.frame_bytes > 0) { pMP3->memory.currentReadPos += (size_t)info.frame_bytes; + pMP3->streamCursor += (size_t)info.frame_bytes; } else { break; } } pMP3->memory.currentReadPos += (size_t)info.frame_bytes; + pMP3->streamCursor += (size_t)info.frame_bytes; return pcmFramesRead; } -static ma_uint32 ma_dr_mp3_decode_next_frame_ex(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames) +static ma_uint32 ma_dr_mp3_decode_next_frame_ex(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames, ma_dr_mp3dec_frame_info* pMP3FrameInfo, const ma_uint8** ppMP3FrameData) { if (pMP3->memory.pData != NULL && pMP3->memory.dataSize > 0) { - return ma_dr_mp3_decode_next_frame_ex__memory(pMP3, pPCMFrames); + return ma_dr_mp3_decode_next_frame_ex__memory(pMP3, pPCMFrames, pMP3FrameInfo, ppMP3FrameData); } else { - return ma_dr_mp3_decode_next_frame_ex__callbacks(pMP3, pPCMFrames); + return ma_dr_mp3_decode_next_frame_ex__callbacks(pMP3, pPCMFrames, pMP3FrameInfo, ppMP3FrameData); } } static ma_uint32 ma_dr_mp3_decode_next_frame(ma_dr_mp3* pMP3) { MA_DR_MP3_ASSERT(pMP3 != NULL); - return ma_dr_mp3_decode_next_frame_ex(pMP3, (ma_dr_mp3d_sample_t*)pMP3->pcmFrames); + return ma_dr_mp3_decode_next_frame_ex(pMP3, (ma_dr_mp3d_sample_t*)pMP3->pcmFrames, NULL, NULL); } #if 0 static ma_uint32 ma_dr_mp3_seek_next_frame(ma_dr_mp3* pMP3) { ma_uint32 pcmFrameCount; MA_DR_MP3_ASSERT(pMP3 != NULL); - pcmFrameCount = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + pcmFrameCount = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL, NULL, NULL); if (pcmFrameCount == 0) { return 0; } @@ -92669,33 +94718,252 @@ static ma_uint32 ma_dr_mp3_seek_next_frame(ma_dr_mp3* pMP3) return pcmFrameCount; } #endif -static ma_bool32 ma_dr_mp3_init_internal(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +static ma_bool32 ma_dr_mp3_init_internal(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, ma_dr_mp3_meta_proc onMeta, void* pUserData, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks) { + ma_dr_mp3dec_frame_info firstFrameInfo; + const ma_uint8* pFirstFrameData; + ma_uint32 firstFramePCMFrameCount; + ma_uint32 detectedMP3FrameCount = 0xFFFFFFFF; MA_DR_MP3_ASSERT(pMP3 != NULL); MA_DR_MP3_ASSERT(onRead != NULL); ma_dr_mp3dec_init(&pMP3->decoder); pMP3->onRead = onRead; pMP3->onSeek = onSeek; + pMP3->onMeta = onMeta; pMP3->pUserData = pUserData; + pMP3->pUserDataMeta = pUserDataMeta; pMP3->allocationCallbacks = ma_dr_mp3_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); if (pMP3->allocationCallbacks.onFree == NULL || (pMP3->allocationCallbacks.onMalloc == NULL && pMP3->allocationCallbacks.onRealloc == NULL)) { return MA_FALSE; } - if (ma_dr_mp3_decode_next_frame(pMP3) == 0) { + pMP3->streamCursor = 0; + pMP3->streamLength = MA_UINT64_MAX; + pMP3->streamStartOffset = 0; + pMP3->delayInPCMFrames = 0; + pMP3->paddingInPCMFrames = 0; + pMP3->totalPCMFrameCount = MA_UINT64_MAX; + #if 1 + if (onSeek != NULL && onTell != NULL) { + if (onSeek(pUserData, 0, MA_DR_MP3_SEEK_END)) { + ma_int64 streamLen; + int streamEndOffset = 0; + if (onTell(pUserData, &streamLen)) { + if (streamLen > 128) { + char id3[3]; + if (onSeek(pUserData, streamEndOffset - 128, MA_DR_MP3_SEEK_END)) { + if (onRead(pUserData, id3, 3) == 3 && id3[0] == 'T' && id3[1] == 'A' && id3[2] == 'G') { + streamEndOffset -= 128; + streamLen -= 128; + if (onMeta != NULL) { + ma_uint8 tag[128]; + tag[0] = 'T'; tag[1] = 'A'; tag[2] = 'G'; + if (onRead(pUserData, tag + 3, 125) == 125) { + ma_dr_mp3__on_meta(pMP3, MA_DR_MP3_METADATA_TYPE_ID3V1, tag, 128); + } + } + } else { + } + } else { + } + } else { + } + if (streamLen > 32) { + char ape[32]; + if (onSeek(pUserData, streamEndOffset - 32, MA_DR_MP3_SEEK_END)) { + if (onRead(pUserData, ape, 32) == 32 && ape[0] == 'A' && ape[1] == 'P' && ape[2] == 'E' && ape[3] == 'T' && ape[4] == 'A' && ape[5] == 'G' && ape[6] == 'E' && ape[7] == 'X') { + ma_uint32 tagSize = + ((ma_uint32)ape[24] << 0) | + ((ma_uint32)ape[25] << 8) | + ((ma_uint32)ape[26] << 16) | + ((ma_uint32)ape[27] << 24); + if (32 + tagSize < streamLen) { + streamEndOffset -= 32 + tagSize; + streamLen -= 32 + tagSize; + if (onMeta != NULL) { + if (onSeek(pUserData, streamEndOffset, MA_DR_MP3_SEEK_END)) { + size_t apeTagSize = (size_t)tagSize + 32; + ma_uint8* pTagData = (ma_uint8*)ma_dr_mp3_malloc(apeTagSize, pAllocationCallbacks); + if (pTagData != NULL) { + if (onRead(pUserData, pTagData, apeTagSize) == apeTagSize) { + ma_dr_mp3__on_meta(pMP3, MA_DR_MP3_METADATA_TYPE_APE, pTagData, apeTagSize); + } + ma_dr_mp3_free(pTagData, pAllocationCallbacks); + } + } + } + } else { + } + } + } + } else { + } + if (!onSeek(pUserData, 0, MA_DR_MP3_SEEK_SET)) { + return MA_FALSE; + } + pMP3->streamLength = (ma_uint64)streamLen; + if (pMP3->memory.pData != NULL) { + pMP3->memory.dataSize = (size_t)pMP3->streamLength; + } + } else { + if (!onSeek(pUserData, 0, MA_DR_MP3_SEEK_SET)) { + return MA_FALSE; + } + } + } else { + } + } else { + } + #endif + #if 1 + { + char header[10]; + if (onRead(pUserData, header, 10) == 10) { + if (header[0] == 'I' && header[1] == 'D' && header[2] == '3') { + ma_uint32 tagSize = + (((ma_uint32)header[6] & 0x7F) << 21) | + (((ma_uint32)header[7] & 0x7F) << 14) | + (((ma_uint32)header[8] & 0x7F) << 7) | + (((ma_uint32)header[9] & 0x7F) << 0); + if (header[5] & 0x10) { + tagSize += 10; + } + if (onMeta != NULL) { + size_t tagSizeWithHeader = 10 + tagSize; + ma_uint8* pTagData = (ma_uint8*)ma_dr_mp3_malloc(tagSizeWithHeader, pAllocationCallbacks); + if (pTagData != NULL) { + MA_DR_MP3_COPY_MEMORY(pTagData, header, 10); + if (onRead(pUserData, pTagData + 10, tagSize) == tagSize) { + ma_dr_mp3__on_meta(pMP3, MA_DR_MP3_METADATA_TYPE_ID3V2, pTagData, tagSizeWithHeader); + } + ma_dr_mp3_free(pTagData, pAllocationCallbacks); + } + } else { + if (onSeek != NULL) { + if (!onSeek(pUserData, tagSize, MA_DR_MP3_SEEK_CUR)) { + return MA_FALSE; + } + } else { + char discard[1024]; + while (tagSize > 0) { + size_t bytesToRead = tagSize; + if (bytesToRead > sizeof(discard)) { + bytesToRead = sizeof(discard); + } + if (onRead(pUserData, discard, bytesToRead) != bytesToRead) { + return MA_FALSE; + } + tagSize -= (ma_uint32)bytesToRead; + } + } + } + pMP3->streamStartOffset += 10 + tagSize; + pMP3->streamCursor = pMP3->streamStartOffset; + } else { + if (onSeek != NULL) { + if (!onSeek(pUserData, 0, MA_DR_MP3_SEEK_SET)) { + return MA_FALSE; + } + } else { + } + } + } else { + return MA_FALSE; + } + } + #endif + firstFramePCMFrameCount = ma_dr_mp3_decode_next_frame_ex(pMP3, (ma_dr_mp3d_sample_t*)pMP3->pcmFrames, &firstFrameInfo, &pFirstFrameData); + if (firstFramePCMFrameCount > 0) { + MA_DR_MP3_ASSERT(pFirstFrameData != NULL); + #if 1 + MA_DR_MP3_ASSERT(firstFrameInfo.frame_bytes > 0); + { + ma_dr_mp3_bs bs; + ma_dr_mp3_L3_gr_info grInfo[4]; + ma_dr_mp3_bs_init(&bs, pFirstFrameData + MA_DR_MP3_HDR_SIZE, firstFrameInfo.frame_bytes - MA_DR_MP3_HDR_SIZE); + if (MA_DR_MP3_HDR_IS_CRC(pFirstFrameData)) { + ma_dr_mp3_bs_get_bits(&bs, 16); + } + if (ma_dr_mp3_L3_read_side_info(&bs, grInfo, pFirstFrameData) >= 0) { + ma_bool32 isXing = MA_FALSE; + ma_bool32 isInfo = MA_FALSE; + const ma_uint8* pTagData; + const ma_uint8* pTagDataBeg; + pTagDataBeg = pFirstFrameData + MA_DR_MP3_HDR_SIZE + (bs.pos/8); + pTagData = pTagDataBeg; + isXing = (pTagData[0] == 'X' && pTagData[1] == 'i' && pTagData[2] == 'n' && pTagData[3] == 'g'); + isInfo = (pTagData[0] == 'I' && pTagData[1] == 'n' && pTagData[2] == 'f' && pTagData[3] == 'o'); + if (isXing || isInfo) { + ma_uint32 bytes = 0; + ma_uint32 flags = pTagData[7]; + pTagData += 8; + if (flags & 0x01) { + detectedMP3FrameCount = (ma_uint32)pTagData[0] << 24 | (ma_uint32)pTagData[1] << 16 | (ma_uint32)pTagData[2] << 8 | (ma_uint32)pTagData[3]; + pTagData += 4; + } + if (flags & 0x02) { + bytes = (ma_uint32)pTagData[0] << 24 | (ma_uint32)pTagData[1] << 16 | (ma_uint32)pTagData[2] << 8 | (ma_uint32)pTagData[3]; + (void)bytes; + pTagData += 4; + } + if (flags & 0x04) { + pTagData += 100; + } + if (flags & 0x08) { + pTagData += 4; + } + if (pTagData[0]) { + pTagData += 21; + if (pTagData - pFirstFrameData + 14 < firstFrameInfo.frame_bytes) { + int delayInPCMFrames; + int paddingInPCMFrames; + delayInPCMFrames = (( (ma_uint32)pTagData[0] << 4) | ((ma_uint32)pTagData[1] >> 4)) + (528 + 1); + paddingInPCMFrames = ((((ma_uint32)pTagData[1] & 0xF) << 8) | ((ma_uint32)pTagData[2] )) - (528 + 1); + if (paddingInPCMFrames < 0) { + paddingInPCMFrames = 0; + } + pMP3->delayInPCMFrames = (ma_uint32)delayInPCMFrames; + pMP3->paddingInPCMFrames = (ma_uint32)paddingInPCMFrames; + } + } + if (isXing) { + pMP3->isVBR = MA_TRUE; + } else if (isInfo) { + pMP3->isCBR = MA_TRUE; + } + if (onMeta != NULL) { + ma_dr_mp3_metadata_type metadataType = isXing ? MA_DR_MP3_METADATA_TYPE_XING : MA_DR_MP3_METADATA_TYPE_VBRI; + size_t tagDataSize; + tagDataSize = (size_t)firstFrameInfo.frame_bytes; + tagDataSize -= (size_t)(pTagDataBeg - pFirstFrameData); + ma_dr_mp3__on_meta(pMP3, metadataType, pTagDataBeg, tagDataSize); + } + pMP3->pcmFramesRemainingInMP3Frame = 0; + pMP3->streamStartOffset += (ma_uint32)(firstFrameInfo.frame_bytes); + pMP3->streamCursor = pMP3->streamStartOffset; + ma_dr_mp3dec_init(&pMP3->decoder); + } + } else { + } + } + #endif + } else { ma_dr_mp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks); return MA_FALSE; } + if (detectedMP3FrameCount != 0xFFFFFFFF) { + pMP3->totalPCMFrameCount = detectedMP3FrameCount * firstFramePCMFrameCount; + } pMP3->channels = pMP3->mp3FrameChannels; pMP3->sampleRate = pMP3->mp3FrameSampleRate; return MA_TRUE; } -MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, ma_dr_mp3_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { if (pMP3 == NULL || onRead == NULL) { return MA_FALSE; } MA_DR_MP3_ZERO_OBJECT(pMP3); - return ma_dr_mp3_init_internal(pMP3, onRead, onSeek, pUserData, pAllocationCallbacks); + return ma_dr_mp3_init_internal(pMP3, onRead, onSeek, onTell, onMeta, pUserData, pUserData, pAllocationCallbacks); } static size_t ma_dr_mp3__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) { @@ -92716,29 +94984,39 @@ static size_t ma_dr_mp3__on_read_memory(void* pUserData, void* pBufferOut, size_ static ma_bool32 ma_dr_mp3__on_seek_memory(void* pUserData, int byteOffset, ma_dr_mp3_seek_origin origin) { ma_dr_mp3* pMP3 = (ma_dr_mp3*)pUserData; + ma_int64 newCursor; MA_DR_MP3_ASSERT(pMP3 != NULL); - if (origin == ma_dr_mp3_seek_origin_current) { - if (byteOffset > 0) { - if (pMP3->memory.currentReadPos + byteOffset > pMP3->memory.dataSize) { - byteOffset = (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos); - } - } else { - if (pMP3->memory.currentReadPos < (size_t)-byteOffset) { - byteOffset = -(int)pMP3->memory.currentReadPos; - } - } - pMP3->memory.currentReadPos += byteOffset; + if (origin == MA_DR_MP3_SEEK_SET) { + newCursor = 0; + } else if (origin == MA_DR_MP3_SEEK_CUR) { + newCursor = (ma_int64)pMP3->memory.currentReadPos; + } else if (origin == MA_DR_MP3_SEEK_END) { + newCursor = (ma_int64)pMP3->memory.dataSize; } else { - if ((ma_uint32)byteOffset <= pMP3->memory.dataSize) { - pMP3->memory.currentReadPos = byteOffset; - } else { - pMP3->memory.currentReadPos = pMP3->memory.dataSize; - } + MA_DR_MP3_ASSERT(!"Invalid seek origin"); + return MA_FALSE; } + newCursor += byteOffset; + if (newCursor < 0) { + return MA_FALSE; + } + if ((size_t)newCursor > pMP3->memory.dataSize) { + return MA_FALSE; + } + pMP3->memory.currentReadPos = (size_t)newCursor; return MA_TRUE; } -MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) +static ma_bool32 ma_dr_mp3__on_tell_memory(void* pUserData, ma_int64* pCursor) { + ma_dr_mp3* pMP3 = (ma_dr_mp3*)pUserData; + MA_DR_MP3_ASSERT(pMP3 != NULL); + MA_DR_MP3_ASSERT(pCursor != NULL); + *pCursor = (ma_int64)pMP3->memory.currentReadPos; + return MA_TRUE; +} +MA_API ma_bool32 ma_dr_mp3_init_memory_with_metadata(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_bool32 result; if (pMP3 == NULL) { return MA_FALSE; } @@ -92749,7 +95027,21 @@ MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_ pMP3->memory.pData = (const ma_uint8*)pData; pMP3->memory.dataSize = dataSize; pMP3->memory.currentReadPos = 0; - return ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_memory, ma_dr_mp3__on_seek_memory, pMP3, pAllocationCallbacks); + result = ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_memory, ma_dr_mp3__on_seek_memory, ma_dr_mp3__on_tell_memory, onMeta, pMP3, pUserDataMeta, pAllocationCallbacks); + if (result == MA_FALSE) { + return MA_FALSE; + } + if (pMP3->streamLength <= (ma_uint64)MA_SIZE_MAX) { + pMP3->memory.dataSize = (size_t)pMP3->streamLength; + } + if (pMP3->streamStartOffset > (ma_uint64)MA_SIZE_MAX) { + return MA_FALSE; + } + return MA_TRUE; +} +MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) +{ + return ma_dr_mp3_init_memory_with_metadata(pMP3, pData, dataSize, NULL, NULL, pAllocationCallbacks); } #ifndef MA_DR_MP3_NO_STDIO #include @@ -92760,36 +95052,76 @@ static size_t ma_dr_mp3__on_read_stdio(void* pUserData, void* pBufferOut, size_t } static ma_bool32 ma_dr_mp3__on_seek_stdio(void* pUserData, int offset, ma_dr_mp3_seek_origin origin) { - return fseek((FILE*)pUserData, offset, (origin == ma_dr_mp3_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; + int whence = SEEK_SET; + if (origin == MA_DR_MP3_SEEK_CUR) { + whence = SEEK_CUR; + } else if (origin == MA_DR_MP3_SEEK_END) { + whence = SEEK_END; + } + return fseek((FILE*)pUserData, offset, whence) == 0; } -MA_API ma_bool32 ma_dr_mp3_init_file(ma_dr_mp3* pMP3, const char* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) +static ma_bool32 ma_dr_mp3__on_tell_stdio(void* pUserData, ma_int64* pCursor) +{ + FILE* pFileStdio = (FILE*)pUserData; + ma_int64 result; + MA_DR_MP3_ASSERT(pFileStdio != NULL); + MA_DR_MP3_ASSERT(pCursor != NULL); +#if defined(_WIN32) && !defined(NXDK) + #if defined(_MSC_VER) && _MSC_VER > 1200 + result = _ftelli64(pFileStdio); + #else + result = ftell(pFileStdio); + #endif +#else + result = ftell(pFileStdio); +#endif + *pCursor = result; + return MA_TRUE; +} +MA_API ma_bool32 ma_dr_mp3_init_file_with_metadata(ma_dr_mp3* pMP3, const char* pFilePath, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks) { ma_bool32 result; FILE* pFile; + if (pMP3 == NULL) { + return MA_FALSE; + } + MA_DR_MP3_ZERO_OBJECT(pMP3); if (ma_fopen(&pFile, pFilePath, "rb") != MA_SUCCESS) { return MA_FALSE; } - result = ma_dr_mp3_init(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + result = ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, ma_dr_mp3__on_tell_stdio, onMeta, (void*)pFile, pUserDataMeta, pAllocationCallbacks); if (result != MA_TRUE) { fclose(pFile); return result; } return MA_TRUE; } -MA_API ma_bool32 ma_dr_mp3_init_file_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_mp3_init_file_with_metadata_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks) { ma_bool32 result; FILE* pFile; + if (pMP3 == NULL) { + return MA_FALSE; + } + MA_DR_MP3_ZERO_OBJECT(pMP3); if (ma_wfopen(&pFile, pFilePath, L"rb", pAllocationCallbacks) != MA_SUCCESS) { return MA_FALSE; } - result = ma_dr_mp3_init(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + result = ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, ma_dr_mp3__on_tell_stdio, onMeta, (void*)pFile, pUserDataMeta, pAllocationCallbacks); if (result != MA_TRUE) { fclose(pFile); return result; } return MA_TRUE; } +MA_API ma_bool32 ma_dr_mp3_init_file(ma_dr_mp3* pMP3, const char* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) +{ + return ma_dr_mp3_init_file_with_metadata(pMP3, pFilePath, NULL, NULL, pAllocationCallbacks); +} +MA_API ma_bool32 ma_dr_mp3_init_file_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) +{ + return ma_dr_mp3_init_file_with_metadata_w(pMP3, pFilePath, NULL, NULL, pAllocationCallbacks); +} #endif MA_API void ma_dr_mp3_uninit(ma_dr_mp3* pMP3) { @@ -92859,17 +95191,38 @@ static ma_uint64 ma_dr_mp3_read_pcm_frames_raw(ma_dr_mp3* pMP3, ma_uint64 frames MA_DR_MP3_ASSERT(pMP3 != NULL); MA_DR_MP3_ASSERT(pMP3->onRead != NULL); while (framesToRead > 0) { - ma_uint32 framesToConsume = (ma_uint32)MA_DR_MP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, framesToRead); + ma_uint32 framesToConsume; + if (pMP3->currentPCMFrame < pMP3->delayInPCMFrames) { + ma_uint32 framesToSkip = (ma_uint32)MA_DR_MP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, pMP3->delayInPCMFrames - pMP3->currentPCMFrame); + pMP3->currentPCMFrame += framesToSkip; + pMP3->pcmFramesConsumedInMP3Frame += framesToSkip; + pMP3->pcmFramesRemainingInMP3Frame -= framesToSkip; + } + framesToConsume = (ma_uint32)MA_DR_MP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, framesToRead); + if (pMP3->totalPCMFrameCount != MA_UINT64_MAX && pMP3->totalPCMFrameCount > pMP3->paddingInPCMFrames) { + if (pMP3->currentPCMFrame < (pMP3->totalPCMFrameCount - pMP3->paddingInPCMFrames)) { + ma_uint64 framesRemainigToPadding = (pMP3->totalPCMFrameCount - pMP3->paddingInPCMFrames) - pMP3->currentPCMFrame; + if (framesToConsume > framesRemainigToPadding) { + framesToConsume = (ma_uint32)framesRemainigToPadding; + } + } else { + break; + } + } if (pBufferOut != NULL) { - #if defined(MA_DR_MP3_FLOAT_OUTPUT) - float* pFramesOutF32 = (float*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalFramesRead * pMP3->channels); - float* pFramesInF32 = (float*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(float) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); - MA_DR_MP3_COPY_MEMORY(pFramesOutF32, pFramesInF32, sizeof(float) * framesToConsume * pMP3->channels); - #else - ma_int16* pFramesOutS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(ma_int16) * totalFramesRead * pMP3->channels); - ma_int16* pFramesInS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(ma_int16) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); - MA_DR_MP3_COPY_MEMORY(pFramesOutS16, pFramesInS16, sizeof(ma_int16) * framesToConsume * pMP3->channels); - #endif + #if defined(MA_DR_MP3_FLOAT_OUTPUT) + { + float* pFramesOutF32 = (float*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalFramesRead * pMP3->channels); + float* pFramesInF32 = (float*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(float) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); + MA_DR_MP3_COPY_MEMORY(pFramesOutF32, pFramesInF32, sizeof(float) * framesToConsume * pMP3->channels); + } + #else + { + ma_int16* pFramesOutS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(ma_int16) * totalFramesRead * pMP3->channels); + ma_int16* pFramesInS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(ma_int16) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); + MA_DR_MP3_COPY_MEMORY(pFramesOutS16, pFramesInS16, sizeof(ma_int16) * framesToConsume * pMP3->channels); + } + #endif } pMP3->currentPCMFrame += framesToConsume; pMP3->pcmFramesConsumedInMP3Frame += framesToConsume; @@ -92879,6 +95232,9 @@ static ma_uint64 ma_dr_mp3_read_pcm_frames_raw(ma_dr_mp3* pMP3, ma_uint64 frames if (framesToRead == 0) { break; } + if (pMP3->totalPCMFrameCount != MA_UINT64_MAX && pMP3->totalPCMFrameCount > pMP3->paddingInPCMFrames && pMP3->currentPCMFrame >= (pMP3->totalPCMFrameCount - pMP3->paddingInPCMFrames)) { + break; + } MA_DR_MP3_ASSERT(pMP3->pcmFramesRemainingInMP3Frame == 0); if (ma_dr_mp3_decode_next_frame(pMP3) == 0) { break; @@ -92958,7 +95314,7 @@ static ma_bool32 ma_dr_mp3_seek_to_start_of_stream(ma_dr_mp3* pMP3) { MA_DR_MP3_ASSERT(pMP3 != NULL); MA_DR_MP3_ASSERT(pMP3->onSeek != NULL); - if (!ma_dr_mp3__on_seek(pMP3, 0, ma_dr_mp3_seek_origin_start)) { + if (!ma_dr_mp3__on_seek_64(pMP3, pMP3->streamStartOffset, MA_DR_MP3_SEEK_SET)) { return MA_FALSE; } ma_dr_mp3_reset(pMP3); @@ -93024,7 +95380,7 @@ static ma_bool32 ma_dr_mp3_seek_to_pcm_frame__seek_table(ma_dr_mp3* pMP3, ma_uin seekPoint.mp3FramesToDiscard = 0; seekPoint.pcmFramesToDiscard = 0; } - if (!ma_dr_mp3__on_seek_64(pMP3, seekPoint.seekPosInBytes, ma_dr_mp3_seek_origin_start)) { + if (!ma_dr_mp3__on_seek_64(pMP3, seekPoint.seekPosInBytes, MA_DR_MP3_SEEK_SET)) { return MA_FALSE; } ma_dr_mp3_reset(pMP3); @@ -93035,7 +95391,7 @@ static ma_bool32 ma_dr_mp3_seek_to_pcm_frame__seek_table(ma_dr_mp3* pMP3, ma_uin if (iMP3Frame == seekPoint.mp3FramesToDiscard-1) { pPCMFrames = (ma_dr_mp3d_sample_t*)pMP3->pcmFrames; } - pcmFramesRead = ma_dr_mp3_decode_next_frame_ex(pMP3, pPCMFrames); + pcmFramesRead = ma_dr_mp3_decode_next_frame_ex(pMP3, pPCMFrames, NULL, NULL); if (pcmFramesRead == 0) { return MA_FALSE; } @@ -93077,7 +95433,7 @@ MA_API ma_bool32 ma_dr_mp3_get_mp3_and_pcm_frame_count(ma_dr_mp3* pMP3, ma_uint6 totalMP3FrameCount = 0; for (;;) { ma_uint32 pcmFramesInCurrentMP3Frame; - pcmFramesInCurrentMP3Frame = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + pcmFramesInCurrentMP3Frame = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL, NULL, NULL); if (pcmFramesInCurrentMP3Frame == 0) { break; } @@ -93101,10 +95457,26 @@ MA_API ma_bool32 ma_dr_mp3_get_mp3_and_pcm_frame_count(ma_dr_mp3* pMP3, ma_uint6 MA_API ma_uint64 ma_dr_mp3_get_pcm_frame_count(ma_dr_mp3* pMP3) { ma_uint64 totalPCMFrameCount; - if (!ma_dr_mp3_get_mp3_and_pcm_frame_count(pMP3, NULL, &totalPCMFrameCount)) { + if (pMP3 == NULL) { return 0; } - return totalPCMFrameCount; + if (pMP3->totalPCMFrameCount != MA_UINT64_MAX) { + totalPCMFrameCount = pMP3->totalPCMFrameCount; + if (totalPCMFrameCount >= pMP3->delayInPCMFrames) { + totalPCMFrameCount -= pMP3->delayInPCMFrames; + } else { + } + if (totalPCMFrameCount >= pMP3->paddingInPCMFrames) { + totalPCMFrameCount -= pMP3->paddingInPCMFrames; + } else { + } + return totalPCMFrameCount; + } else { + if (!ma_dr_mp3_get_mp3_and_pcm_frame_count(pMP3, NULL, &totalPCMFrameCount)) { + return 0; + } + return totalPCMFrameCount; + } } MA_API ma_uint64 ma_dr_mp3_get_mp3_frame_count(ma_dr_mp3* pMP3) { @@ -93174,7 +95546,7 @@ MA_API ma_bool32 ma_dr_mp3_calculate_seek_points(ma_dr_mp3* pMP3, ma_uint32* pSe MA_DR_MP3_ASSERT(pMP3->streamCursor >= pMP3->dataSize); mp3FrameInfo[iMP3Frame].bytePos = pMP3->streamCursor - pMP3->dataSize; mp3FrameInfo[iMP3Frame].pcmFrameIndex = runningPCMFrameCount; - pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL, NULL, NULL); if (pcmFramesInCurrentMP3FrameIn == 0) { return MA_FALSE; } @@ -93198,7 +95570,7 @@ MA_API ma_bool32 ma_dr_mp3_calculate_seek_points(ma_dr_mp3* pMP3, ma_uint32* pSe } mp3FrameInfo[MA_DR_MP3_COUNTOF(mp3FrameInfo)-1].bytePos = pMP3->streamCursor - pMP3->dataSize; mp3FrameInfo[MA_DR_MP3_COUNTOF(mp3FrameInfo)-1].pcmFrameIndex = runningPCMFrameCount; - pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL, NULL, NULL); if (pcmFramesInCurrentMP3FrameIn == 0) { pSeekPoints[iSeekPoint].seekPosInBytes = mp3FrameInfo[0].bytePos; pSeekPoints[iSeekPoint].pcmFrameIndex = nextTargetPCMFrame; @@ -93264,6 +95636,8 @@ static float* ma_dr_mp3__full_read_and_close_f32(ma_dr_mp3* pMP3, ma_dr_mp3_conf pNewFrames = (float*)ma_dr_mp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks); if (pNewFrames == NULL) { ma_dr_mp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks); + pFrames = NULL; + totalFramesRead = 0; break; } pFrames = pNewFrames; @@ -93315,6 +95689,8 @@ static ma_int16* ma_dr_mp3__full_read_and_close_s16(ma_dr_mp3* pMP3, ma_dr_mp3_c pNewFrames = (ma_int16*)ma_dr_mp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks); if (pNewFrames == NULL) { ma_dr_mp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks); + pFrames = NULL; + totalFramesRead = 0; break; } pFrames = pNewFrames; @@ -93336,18 +95712,18 @@ static ma_int16* ma_dr_mp3__full_read_and_close_s16(ma_dr_mp3* pMP3, ma_dr_mp3_c } return pFrames; } -MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_mp3 mp3; - if (!ma_dr_mp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_mp3_init(&mp3, onRead, onSeek, onTell, NULL, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_mp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount); } -MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_mp3 mp3; - if (!ma_dr_mp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_mp3_init(&mp3, onRead, onSeek, onTell, NULL, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_mp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); diff --git a/vendor/portmidi/portmidi.odin b/vendor/portmidi/portmidi.odin index 58d7c2ec2..1f2aca286 100644 --- a/vendor/portmidi/portmidi.odin +++ b/vendor/portmidi/portmidi.odin @@ -119,8 +119,8 @@ DeviceInfo :: struct { structVersion: c.int, /**< this internal structure version */ interf: cstring, /**< underlying MIDI API, e.g. MMSystem or DirectX */ name: cstring, /**< device name, e.g. USB MidiSport 1x1 */ - input: b32, /**< true iff input is available */ - output: b32, /**< true iff output is available */ + input: b32, /**< true if and only if (⟺) input is available */ + output: b32, /**< true if and only if (⟺) output is available */ opened: b32, /**< used by generic PortMidi code to do error checking on arguments */ } diff --git a/vendor/raylib/raylib.odin b/vendor/raylib/raylib.odin index 37589f165..b051f1885 100644 --- a/vendor/raylib/raylib.odin +++ b/vendor/raylib/raylib.odin @@ -91,9 +91,6 @@ import "core:c" import "core:fmt" import "core:mem" -import "core:math/linalg" -_ :: linalg - MAX_TEXTFORMAT_BUFFERS :: #config(RAYLIB_MAX_TEXTFORMAT_BUFFERS, 4) MAX_TEXT_BUFFER_LENGTH :: #config(RAYLIB_MAX_TEXT_BUFFER_LENGTH, 1024) MAX_MATERIAL_MAPS :: #config(RAYLIB_MAX_MATERIAL_MAPS, 12) @@ -128,7 +125,7 @@ when ODIN_OS == .Windows { "system:Cocoa.framework", "system:OpenGL.framework", "system:IOKit.framework", - } + } } else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 { foreign import lib { RAYLIB_WASM_LIB, @@ -142,7 +139,7 @@ VERSION_MINOR :: 5 VERSION_PATCH :: 0 VERSION :: "5.5" -PI :: 3.14159265358979323846 +PI :: 3.14159265358979323846 DEG2RAD :: PI/180.0 RAD2DEG :: 180.0/PI @@ -235,7 +232,7 @@ RenderTexture :: struct { id: c.uint, // OpenGL framebuffer object id texture: Texture, // Color buffer attachment texture depth: Texture, // Depth buffer attachment texture -} +} // RenderTexture2D type, same as RenderTexture RenderTexture2D :: RenderTexture @@ -257,7 +254,7 @@ GlyphInfo :: struct { offsetY: c.int, // Character offset Y when drawing advanceX: c.int, // Character advance position X image: Image, // Character image data -} +} // Font type, includes texture and charSet array data Font :: struct { @@ -851,7 +848,7 @@ Gesture :: enum c.uint { } Gestures :: distinct bit_set[Gesture; c.uint] -// Camera speed values +// Camera speed values CAMERA_MOVE_SPEED :: 5.4 CAMERA_ROTATION_SPEED :: 0.03 CAMERA_PAN_SPEED :: 0.2 @@ -1029,7 +1026,7 @@ foreign lib { GetScreenToWorld2D :: proc(position: Vector2, camera: Camera2D) -> Vector2 --- // Get the world space position for a 2d camera screen space position GetCameraMatrix :: proc(camera: Camera) -> Matrix --- // Get camera transform matrix (view matrix) GetCameraMatrix2D :: proc(camera: Camera2D) -> Matrix --- // Get camera 2d transform matrix - + // Timing-related functions SetTargetFPS :: proc(fps: c.int) --- // Set target FPS (maximum) @@ -1110,7 +1107,7 @@ foreign lib { ComputeMD5 :: proc (data: rawptr, dataSize: c.int) -> [^]c.uint --- // Compute MD5 hash code, returns static int[4] (16 bytes) ComputeSHA1 :: proc(data: rawptr, dataSize: c.int) -> [^]c.uint --- // Compute SHA1 hash code, returns static int[5] (20 bytes) - + // Automation events functionality LoadAutomationEventList :: proc(fileName: cstring) -> AutomationEventList --- // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS @@ -1151,14 +1148,14 @@ foreign lib { SetGamepadMappings :: proc(mappings: cstring) -> c.int --- // Set internal gamepad mappings (SDL_GameControllerDB) SetGamepadVibration :: proc(gamepad: c.int, leftMotor: f32, rightMotor: f32, duration: f32) --- // Set gamepad vibration for both motors (duration in seconds) - + // Input-related functions: mouse IsMouseButtonPressed :: proc(button: MouseButton) -> bool --- // Detect if a mouse button has been pressed once IsMouseButtonDown :: proc(button: MouseButton) -> bool --- // Detect if a mouse button is being pressed IsMouseButtonReleased :: proc(button: MouseButton) -> bool --- // Detect if a mouse button has been released once IsMouseButtonUp :: proc(button: MouseButton) -> bool --- - + GetMouseX :: proc() -> c.int --- // Returns mouse position X GetMouseY :: proc() -> c.int --- // Returns mouse position Y GetMousePosition :: proc() -> Vector2 --- // Returns mouse position XY @@ -1226,7 +1223,7 @@ foreign lib { GetShapesTexture :: proc() -> Texture2D --- // Get texture that is used for shapes drawing GetShapesTextureRectangle :: proc() -> Rectangle --- // Get texture source rectangle that is used for shapes drawing - + // Basic shapes drawing functions DrawPixel :: proc(posX, posY: c.int, color: Color) --- // Draw a pixel using geometry [Can be slow, use with care] @@ -1422,7 +1419,7 @@ foreign lib { DrawTextureNPatch :: proc(texture: Texture2D, nPatchInfo: NPatchInfo, dest: Rectangle, origin: Vector2, rotation: f32, tint: Color) --- // Draws a texture (or part of it) that stretches or shrinks nicely // Color/pixel related functions - + @(deprecated="Prefer col1 == col2") ColorIsEqual :: proc(col1, col2: Color) --- // Check if two colors are equal Fade :: proc(color: Color, alpha: f32) -> Color --- // Get color with alpha applied, alpha goes from 0.0f to 1.0f @@ -1730,15 +1727,15 @@ IsGestureDetected :: proc "c" (gesture: Gesture) -> bool { TextFormat :: proc(text: cstring, args: ..any) -> cstring { @static buffers: [MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH]byte @static index: u32 - + buffer := buffers[index][:] mem.zero_slice(buffer) - + index = (index+1)%MAX_TEXTFORMAT_BUFFERS - + str := fmt.bprintf(buffer[:len(buffer)-1], string(text), ..args) buffer[len(str)] = 0 - + return cstring(raw_data(buffer)) } @@ -1785,7 +1782,7 @@ MemAllocatorProc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, case .Free: MemFree(old_memory) return nil, nil - + case .Resize, .Resize_Non_Zeroed: ptr := MemRealloc(old_memory, c.uint(size)) if ptr == nil { @@ -1794,10 +1791,10 @@ MemAllocatorProc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, } data = mem.byte_slice(ptr, size) return - + case .Free_All, .Query_Features, .Query_Info: return nil, .Mode_Not_Implemented - } + } return nil, .Mode_Not_Implemented } diff --git a/vendor/sdl2/sdl_messagebox.odin b/vendor/sdl2/sdl_messagebox.odin index edd8422e0..5211affd8 100644 --- a/vendor/sdl2/sdl_messagebox.odin +++ b/vendor/sdl2/sdl_messagebox.odin @@ -66,7 +66,7 @@ MessageBoxData :: struct { message: cstring, /**< UTF-8 message text */ numbuttons: c.int, - buttons: ^MessageBoxButtonData, + buttons: [^]MessageBoxButtonData, colorScheme: ^MessageBoxColorScheme, /**< ::SDL_MessageBoxColorScheme, can be NULL to use system settings */ } diff --git a/vendor/sdl2/sdl_video.odin b/vendor/sdl2/sdl_video.odin index 809735414..8a98d79dc 100644 --- a/vendor/sdl2/sdl_video.odin +++ b/vendor/sdl2/sdl_video.odin @@ -237,7 +237,7 @@ foreign lib { CreateWindowFrom :: proc(data: rawptr) -> ^Window --- GetWindowID :: proc(window: ^Window) -> u32 --- GetWindowFromID :: proc(id: u32) -> ^Window --- - GetWindowFlags :: proc(window: ^Window) -> u32 --- + GetWindowFlags :: proc(window: ^Window) -> WindowFlags --- SetWindowTitle :: proc(window: ^Window, title: cstring) --- GetWindowTitle :: proc(window: ^Window) -> cstring --- SetWindowIcon :: proc(window: ^Window, icon: ^Surface) --- diff --git a/vendor/sdl3/LICENSE.txt b/vendor/sdl3/LICENSE.txt index 23abb73f2..e9adee448 100644 --- a/vendor/sdl3/LICENSE.txt +++ b/vendor/sdl3/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (C) 1997-2025 Sam Lantinga +Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/SDL3.dll b/vendor/sdl3/SDL3.dll index 63f5b22ec..080cd755d 100644 Binary files a/vendor/sdl3/SDL3.dll and b/vendor/sdl3/SDL3.dll differ diff --git a/vendor/sdl3/SDL3.lib b/vendor/sdl3/SDL3.lib index 164aeb9f1..ef10d51b9 100644 Binary files a/vendor/sdl3/SDL3.lib and b/vendor/sdl3/SDL3.lib differ diff --git a/vendor/sdl3/image/LICENSE.libpng.txt b/vendor/sdl3/image/LICENSE.libpng.txt new file mode 100644 index 000000000..ea6df986c --- /dev/null +++ b/vendor/sdl3/image/LICENSE.libpng.txt @@ -0,0 +1,134 @@ +COPYRIGHT NOTICE, DISCLAIMER, and LICENSE +========================================= + +PNG Reference Library License version 2 +--------------------------------------- + + * Copyright (c) 1995-2025 The PNG Reference Library Authors. + * Copyright (c) 2018-2025 Cosmin Truta. + * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson. + * Copyright (c) 1996-1997 Andreas Dilger. + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + +The software is supplied "as is", without warranty of any kind, +express or implied, including, without limitation, the warranties +of merchantability, fitness for a particular purpose, title, and +non-infringement. In no event shall the Copyright owners, or +anyone distributing the software, be liable for any damages or +other liability, whether in contract, tort or otherwise, arising +from, out of, or in connection with the software, or the use or +other dealings in the software, even if advised of the possibility +of such damage. + +Permission is hereby granted to use, copy, modify, and distribute +this software, or portions hereof, for any purpose, without fee, +subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you + use this software in a product, an acknowledgment in the product + documentation would be appreciated, but is not required. + + 2. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + + +PNG Reference Library License version 1 (for libpng 0.5 through 1.6.35) +----------------------------------------------------------------------- + +libpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are +Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are +derived from libpng-1.0.6, and are distributed according to the same +disclaimer and license as libpng-1.0.6 with the following individuals +added to the list of Contributing Authors: + + Simon-Pierre Cadieux + Eric S. Raymond + Mans Rullgard + Cosmin Truta + Gilles Vollant + James Yu + Mandar Sahastrabuddhe + Google Inc. + Vadim Barkov + +and with the following additions to the disclaimer: + + There is no warranty against interference with your enjoyment of + the library or against infringement. There is no warranty that our + efforts or the library will fulfill any of your particular purposes + or needs. This library is provided with all faults, and the entire + risk of satisfactory quality, performance, accuracy, and effort is + with the user. + +Some files in the "contrib" directory and some configure-generated +files that are distributed with libpng have other copyright owners, and +are released under other open source licenses. + +libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are +Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from +libpng-0.96, and are distributed according to the same disclaimer and +license as libpng-0.96, with the following individuals added to the +list of Contributing Authors: + + Tom Lane + Glenn Randers-Pehrson + Willem van Schaik + +libpng versions 0.89, June 1996, through 0.96, May 1997, are +Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, +and are distributed according to the same disclaimer and license as +libpng-0.88, with the following individuals added to the list of +Contributing Authors: + + John Bowler + Kevin Bracey + Sam Bushell + Magnus Holmgren + Greg Roelofs + Tom Tanner + +Some files in the "scripts" directory have other copyright owners, +but are released under this license. + +libpng versions 0.5, May 1995, through 0.88, January 1996, are +Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + +For the purposes of this copyright and license, "Contributing Authors" +is defined as the following set of individuals: + + Andreas Dilger + Dave Martindale + Guy Eric Schalnat + Paul Schmidt + Tim Wegner + +The PNG Reference Library is supplied "AS IS". The Contributing +Authors and Group 42, Inc. disclaim all warranties, expressed or +implied, including, without limitation, the warranties of +merchantability and of fitness for any purpose. The Contributing +Authors and Group 42, Inc. assume no liability for direct, indirect, +incidental, special, exemplary, or consequential damages, which may +result from the use of the PNG Reference Library, even if advised of +the possibility of such damage. + +Permission is hereby granted to use, copy, modify, and distribute this +source code, or portions hereof, for any purpose, without fee, subject +to the following restrictions: + + 1. The origin of this source code must not be misrepresented. + + 2. Altered versions must be plainly marked as such and must not + be misrepresented as being the original source. + + 3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + +The Contributing Authors and Group 42, Inc. specifically permit, +without fee, and encourage the use of this source code as a component +to supporting the PNG file format in commercial products. If you use +this source code in a product, acknowledgment is not required but would +be appreciated. diff --git a/vendor/sdl3/image/LICENSE.txt b/vendor/sdl3/image/LICENSE.txt index 52d0ed38b..acaf5b21b 100644 --- a/vendor/sdl3/image/LICENSE.txt +++ b/vendor/sdl3/image/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (C) 1997-2025 Sam Lantinga +Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/image/SDL3_image.dll b/vendor/sdl3/image/SDL3_image.dll index 2ba20a7cf..ea48dab75 100644 Binary files a/vendor/sdl3/image/SDL3_image.dll and b/vendor/sdl3/image/SDL3_image.dll differ diff --git a/vendor/sdl3/image/SDL3_image.lib b/vendor/sdl3/image/SDL3_image.lib index 4e9913b4c..7db2f734a 100644 Binary files a/vendor/sdl3/image/SDL3_image.lib and b/vendor/sdl3/image/SDL3_image.lib differ diff --git a/vendor/sdl3/image/include/SDL_image.h b/vendor/sdl3/image/include/SDL_image.h index 60d041fe6..19d9f2e02 100644 --- a/vendor/sdl3/image/include/SDL_image.h +++ b/vendor/sdl3/image/include/SDL_image.h @@ -1,6 +1,6 @@ /* SDL_image: An example image loading library for use with SDL - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -44,8 +44,8 @@ extern "C" { * Printable format: "%d.%d.%d", MAJOR, MINOR, MICRO */ #define SDL_IMAGE_MAJOR_VERSION 3 -#define SDL_IMAGE_MINOR_VERSION 2 -#define SDL_IMAGE_MICRO_VERSION 4 +#define SDL_IMAGE_MINOR_VERSION 4 +#define SDL_IMAGE_MICRO_VERSION 0 /** * This is the version number macro for the current SDL_image version. @@ -70,6 +70,103 @@ extern "C" { */ extern SDL_DECLSPEC int SDLCALL IMG_Version(void); +/** + * Load an image from a filesystem path into a software surface. + * + * An SDL_Surface is a buffer of pixels in memory accessible by the CPU. Use + * this if you plan to hand the data to something else or manipulate it + * further in code. + * + * There are no guarantees about what format the new SDL_Surface data will be; + * in many cases, SDL_image will attempt to supply a surface that exactly + * matches the provided image, but in others it might have to convert (either + * because the image is in a format that SDL doesn't directly support or + * because it's compressed data that could reasonably uncompress to various + * formats and SDL_image had to pick one). You can inspect an SDL_Surface for + * its specifics, and use SDL_ConvertSurface to then migrate to any supported + * format. + * + * If the image format supports a transparent pixel, SDL will set the colorkey + * for the surface. You can enable RLE acceleration on the surface afterwards + * by calling: SDL_SetSurfaceColorKey(image, SDL_RLEACCEL, + * image->format->colorkey); + * + * There is a separate function to read files from an SDL_IOStream, if you + * need an i/o abstraction to provide data from anywhere instead of a simple + * filesystem read; that function is IMG_Load_IO(). + * + * If you are using SDL's 2D rendering API, there is an equivalent call to + * load images directly into an SDL_Texture for use by the GPU without using a + * software surface: call IMG_LoadTexture() instead. + * + * When done with the returned surface, the app should dispose of it with a + * call to + * [SDL_DestroySurface](https://wiki.libsdl.org/SDL3/SDL_DestroySurface) + * (). + * + * \param file a path on the filesystem to load an image from. + * \returns a new SDL surface, or NULL on error. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_LoadTyped_IO + * \sa IMG_Load_IO + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_Load(const char *file); + +/** + * Load an image from an SDL data source into a software surface. + * + * An SDL_Surface is a buffer of pixels in memory accessible by the CPU. Use + * this if you plan to hand the data to something else or manipulate it + * further in code. + * + * There are no guarantees about what format the new SDL_Surface data will be; + * in many cases, SDL_image will attempt to supply a surface that exactly + * matches the provided image, but in others it might have to convert (either + * because the image is in a format that SDL doesn't directly support or + * because it's compressed data that could reasonably uncompress to various + * formats and SDL_image had to pick one). You can inspect an SDL_Surface for + * its specifics, and use SDL_ConvertSurface to then migrate to any supported + * format. + * + * If the image format supports a transparent pixel, SDL will set the colorkey + * for the surface. You can enable RLE acceleration on the surface afterwards + * by calling: SDL_SetSurfaceColorKey(image, SDL_RLEACCEL, + * image->format->colorkey); + * + * If `closeio` is true, `src` will be closed before returning, whether this + * function succeeds or not. SDL_image reads everything it needs from `src` + * during this call in any case. + * + * There is a separate function to read files from disk without having to deal + * with SDL_IOStream: `IMG_Load("filename.jpg")` will call this function and + * manage those details for you, determining the file type from the filename's + * extension. + * + * There is also IMG_LoadTyped_IO(), which is equivalent to this function + * except a file extension (like "BMP", "JPG", etc) can be specified, in case + * SDL_image cannot autodetect the file format. + * + * If you are using SDL's 2D rendering API, there is an equivalent call to + * load images directly into an SDL_Texture for use by the GPU without using a + * software surface: call IMG_LoadTexture_IO() instead. + * + * When done with the returned surface, the app should dispose of it with a + * call to SDL_DestroySurface(). + * + * \param src an SDL_IOStream that data will be read from. + * \param closeio true to close/free the SDL_IOStream before returning, false + * to leave it open. + * \returns a new SDL surface, or NULL on error. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_Load + * \sa IMG_LoadTyped_IO + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_Load_IO(SDL_IOStream *src, bool closeio); + /** * Load an image from an SDL data source into a software surface. * @@ -128,111 +225,11 @@ extern SDL_DECLSPEC int SDLCALL IMG_Version(void); * * \sa IMG_Load * \sa IMG_Load_IO - * \sa SDL_DestroySurface */ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadTyped_IO(SDL_IOStream *src, bool closeio, const char *type); /** - * Load an image from a filesystem path into a software surface. - * - * An SDL_Surface is a buffer of pixels in memory accessible by the CPU. Use - * this if you plan to hand the data to something else or manipulate it - * further in code. - * - * There are no guarantees about what format the new SDL_Surface data will be; - * in many cases, SDL_image will attempt to supply a surface that exactly - * matches the provided image, but in others it might have to convert (either - * because the image is in a format that SDL doesn't directly support or - * because it's compressed data that could reasonably uncompress to various - * formats and SDL_image had to pick one). You can inspect an SDL_Surface for - * its specifics, and use SDL_ConvertSurface to then migrate to any supported - * format. - * - * If the image format supports a transparent pixel, SDL will set the colorkey - * for the surface. You can enable RLE acceleration on the surface afterwards - * by calling: SDL_SetSurfaceColorKey(image, SDL_RLEACCEL, - * image->format->colorkey); - * - * There is a separate function to read files from an SDL_IOStream, if you - * need an i/o abstraction to provide data from anywhere instead of a simple - * filesystem read; that function is IMG_Load_IO(). - * - * If you are using SDL's 2D rendering API, there is an equivalent call to - * load images directly into an SDL_Texture for use by the GPU without using a - * software surface: call IMG_LoadTexture() instead. - * - * When done with the returned surface, the app should dispose of it with a - * call to - * [SDL_DestroySurface](https://wiki.libsdl.org/SDL3/SDL_DestroySurface) - * (). - * - * \param file a path on the filesystem to load an image from. - * \returns a new SDL surface, or NULL on error. - * - * \since This function is available since SDL_image 3.0.0. - * - * \sa IMG_LoadTyped_IO - * \sa IMG_Load_IO - * \sa SDL_DestroySurface - */ -extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_Load(const char *file); - -/** - * Load an image from an SDL data source into a software surface. - * - * An SDL_Surface is a buffer of pixels in memory accessible by the CPU. Use - * this if you plan to hand the data to something else or manipulate it - * further in code. - * - * There are no guarantees about what format the new SDL_Surface data will be; - * in many cases, SDL_image will attempt to supply a surface that exactly - * matches the provided image, but in others it might have to convert (either - * because the image is in a format that SDL doesn't directly support or - * because it's compressed data that could reasonably uncompress to various - * formats and SDL_image had to pick one). You can inspect an SDL_Surface for - * its specifics, and use SDL_ConvertSurface to then migrate to any supported - * format. - * - * If the image format supports a transparent pixel, SDL will set the colorkey - * for the surface. You can enable RLE acceleration on the surface afterwards - * by calling: SDL_SetSurfaceColorKey(image, SDL_RLEACCEL, - * image->format->colorkey); - * - * If `closeio` is true, `src` will be closed before returning, whether this - * function succeeds or not. SDL_image reads everything it needs from `src` - * during this call in any case. - * - * There is a separate function to read files from disk without having to deal - * with SDL_IOStream: `IMG_Load("filename.jpg")` will call this function and - * manage those details for you, determining the file type from the filename's - * extension. - * - * There is also IMG_LoadTyped_IO(), which is equivalent to this function - * except a file extension (like "BMP", "JPG", etc) can be specified, in case - * SDL_image cannot autodetect the file format. - * - * If you are using SDL's 2D rendering API, there is an equivalent call to - * load images directly into an SDL_Texture for use by the GPU without using a - * software surface: call IMG_LoadTexture_IO() instead. - * - * When done with the returned surface, the app should dispose of it with a - * call to SDL_DestroySurface(). - * - * \param src an SDL_IOStream that data will be read from. - * \param closeio true to close/free the SDL_IOStream before returning, false - * to leave it open. - * \returns a new SDL surface, or NULL on error. - * - * \since This function is available since SDL_image 3.0.0. - * - * \sa IMG_Load - * \sa IMG_LoadTyped_IO - * \sa SDL_DestroySurface - */ -extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_Load_IO(SDL_IOStream *src, bool closeio); - -/** - * Load an image from a filesystem path into a GPU texture. + * Load an image from a filesystem path into a texture. * * An SDL_Texture represents an image in GPU memory, usable by SDL's 2D Render * API. This can be significantly more efficient than using a CPU-bound @@ -255,7 +252,7 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_Load_IO(SDL_IOStream *src, bool cl * When done with the returned texture, the app should dispose of it with a * call to SDL_DestroyTexture(). * - * \param renderer the SDL_Renderer to use to create the GPU texture. + * \param renderer the SDL_Renderer to use to create the texture. * \param file a path on the filesystem to load an image from. * \returns a new texture, or NULL on error. * @@ -267,7 +264,7 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_Load_IO(SDL_IOStream *src, bool cl extern SDL_DECLSPEC SDL_Texture * SDLCALL IMG_LoadTexture(SDL_Renderer *renderer, const char *file); /** - * Load an image from an SDL data source into a GPU texture. + * Load an image from an SDL data source into a texture. * * An SDL_Texture represents an image in GPU memory, usable by SDL's 2D Render * API. This can be significantly more efficient than using a CPU-bound @@ -299,7 +296,7 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL IMG_LoadTexture(SDL_Renderer *renderer * When done with the returned texture, the app should dispose of it with a * call to SDL_DestroyTexture(). * - * \param renderer the SDL_Renderer to use to create the GPU texture. + * \param renderer the SDL_Renderer to use to create the texture. * \param src an SDL_IOStream that data will be read from. * \param closeio true to close/free the SDL_IOStream before returning, false * to leave it open. @@ -309,12 +306,11 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL IMG_LoadTexture(SDL_Renderer *renderer * * \sa IMG_LoadTexture * \sa IMG_LoadTextureTyped_IO - * \sa SDL_DestroyTexture */ extern SDL_DECLSPEC SDL_Texture * SDLCALL IMG_LoadTexture_IO(SDL_Renderer *renderer, SDL_IOStream *src, bool closeio); /** - * Load an image from an SDL data source into a GPU texture. + * Load an image from an SDL data source into a texture. * * An SDL_Texture represents an image in GPU memory, usable by SDL's 2D Render * API. This can be significantly more efficient than using a CPU-bound @@ -352,7 +348,7 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL IMG_LoadTexture_IO(SDL_Renderer *rende * When done with the returned texture, the app should dispose of it with a * call to SDL_DestroyTexture(). * - * \param renderer the SDL_Renderer to use to create the GPU texture. + * \param renderer the SDL_Renderer to use to create the texture. * \param src an SDL_IOStream that data will be read from. * \param closeio true to close/free the SDL_IOStream before returning, false * to leave it open. @@ -364,10 +360,194 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL IMG_LoadTexture_IO(SDL_Renderer *rende * * \sa IMG_LoadTexture * \sa IMG_LoadTexture_IO - * \sa SDL_DestroyTexture */ extern SDL_DECLSPEC SDL_Texture * SDLCALL IMG_LoadTextureTyped_IO(SDL_Renderer *renderer, SDL_IOStream *src, bool closeio, const char *type); +/** + * Load an image from a filesystem path into a GPU texture. + * + * An SDL_GPUTexture represents an image in GPU memory, usable by SDL's GPU + * API. Regardless of the source format of the image, this function will + * create a GPU texture with the format SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM + * with no mip levels. It can be bound as a sampled texture from a graphics or + * compute pipeline and as a a readonly storage texture in a compute pipeline. + * + * There is a separate function to read files from an SDL_IOStream, if you + * need an i/o abstraction to provide data from anywhere instead of a simple + * filesystem read; that function is IMG_LoadGPUTexture_IO(). + * + * When done with the returned texture, the app should dispose of it with a + * call to SDL_ReleaseGPUTexture(). + * + * \param device the SDL_GPUDevice to use to create the GPU texture. + * \param copy_pass the SDL_GPUCopyPass to use to upload the loaded image to + * the GPU texture. + * \param file a path on the filesystem to load an image from. + * \param width a pointer filled in with the width of the GPU texture. may be + * NULL. + * \param height a pointer filled in with the width of the GPU texture. may be + * NULL. + * \returns a new GPU texture, or NULL on error. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_LoadGPUTextureTyped_IO + * \sa IMG_LoadGPUTexture_IO + */ +extern SDL_DECLSPEC SDL_GPUTexture * SDLCALL IMG_LoadGPUTexture(SDL_GPUDevice *device, SDL_GPUCopyPass *copy_pass, const char *file, int *width, int *height); + +/** + * Load an image from an SDL data source into a GPU texture. + * + * An SDL_GPUTexture represents an image in GPU memory, usable by SDL's GPU + * API. Regardless of the source format of the image, this function will + * create a GPU texture with the format SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM + * with no mip levels. It can be bound as a sampled texture from a graphics or + * compute pipeline and as a a readonly storage texture in a compute pipeline. + * + * If `closeio` is true, `src` will be closed before returning, whether this + * function succeeds or not. SDL_image reads everything it needs from `src` + * during this call in any case. + * + * There is a separate function to read files from disk without having to deal + * with SDL_IOStream: `IMG_LoadGPUTexture(device, copy_pass, "filename.jpg", + * width, height) will call this function and manage those details for you, + * determining the file type from the filename's extension. + * + * There is also IMG_LoadGPUTextureTyped_IO(), which is equivalent to this + * function except a file extension (like "BMP", "JPG", etc) can be specified, + * in case SDL_image cannot autodetect the file format. + * + * When done with the returned texture, the app should dispose of it with a + * call to SDL_ReleaseGPUTexture(). + * + * \param device the SDL_GPUDevice to use to create the GPU texture. + * \param copy_pass the SDL_GPUCopyPass to use to upload the loaded image to + * the GPU texture. + * \param src an SDL_IOStream that data will be read from. + * \param closeio true to close/free the SDL_IOStream before returning, false + * to leave it open. + * \param width a pointer filled in with the width of the GPU texture. may be + * NULL. + * \param height a pointer filled in with the width of the GPU texture. may be + * NULL. + * \returns a new GPU texture, or NULL on error. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_LoadGPUTexture + * \sa IMG_LoadGPUTextureTyped_IO + */ +extern SDL_DECLSPEC SDL_GPUTexture * SDLCALL IMG_LoadGPUTexture_IO(SDL_GPUDevice *device, SDL_GPUCopyPass *copy_pass, SDL_IOStream *src, bool closeio, int *width, int *height); + +/** + * Load an image from an SDL data source into a GPU texture. + * + * An SDL_GPUTexture represents an image in GPU memory, usable by SDL's GPU + * API. Regardless of the source format of the image, this function will + * create a GPU texture with the format SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM + * with no mip levels. It can be bound as a sampled texture from a graphics or + * compute pipeline and as a a readonly storage texture in a compute pipeline. + * + * If `closeio` is true, `src` will be closed before returning, whether this + * function succeeds or not. SDL_image reads everything it needs from `src` + * during this call in any case. + * + * Even though this function accepts a file type, SDL_image may still try + * other decoders that are capable of detecting file type from the contents of + * the image data, but may rely on the caller-provided type string for formats + * that it cannot autodetect. If `type` is NULL, SDL_image will rely solely on + * its ability to guess the format. + * + * There is a separate function to read files from disk without having to deal + * with SDL_IOStream: `IMG_LoadGPUTexture(device, copy_pass, "filename.jpg", + * width, height) will call this function and manage those details for you, + * determining the file type from the filename's extension. + * + * There is also IMG_LoadGPUTexture_IO(), which is equivalent to this function + * except that it will rely on SDL_image to determine what type of data it is + * loading, much like passing a NULL for type. + * + * When done with the returned texture, the app should dispose of it with a + * call to SDL_ReleaseGPUTexture(). + * + * \param device the SDL_GPUDevice to use to create the GPU texture. + * \param copy_pass the SDL_GPUCopyPass to use to upload the loaded image to + * the GPU texture. + * \param src an SDL_IOStream that data will be read from. + * \param closeio true to close/free the SDL_IOStream before returning, false + * to leave it open. + * \param type a filename extension that represent this data ("BMP", "GIF", + * "PNG", etc). + * \param width a pointer filled in with the width of the GPU texture. may be + * NULL. + * \param height a pointer filled in with the width of the GPU texture. may be + * NULL. + * \returns a new GPU texture, or NULL on error. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_LoadGPUTexture + * \sa IMG_LoadGPUTexture_IO + */ +extern SDL_DECLSPEC SDL_GPUTexture * SDLCALL IMG_LoadGPUTextureTyped_IO(SDL_GPUDevice *device, SDL_GPUCopyPass *copy_pass, SDL_IOStream *src, bool closeio, const char *type, int *width, int *height); + +/** + * Get the image currently in the clipboard. + * + * When done with the returned surface, the app should dispose of it with a + * call to SDL_DestroySurface(). + * + * \returns a new SDL surface, or NULL if no supported image is available. + * + * \since This function is available since SDL_image 3.4.0. + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_GetClipboardImage(void); + +/** + * Detect ANI animated cursor data on a readable/seekable SDL_IOStream. + * + * This function attempts to determine if a file is a given filetype, reading + * the least amount possible from the SDL_IOStream (usually a few bytes). + * + * There is no distinction made between "not the filetype in question" and + * basic i/o errors. + * + * This function will always attempt to seek `src` back to where it started + * when this function was called, but it will not report any errors in doing + * so, but assuming seeking works, this means you can immediately use this + * with a different IMG_isTYPE function, or load the image without further + * seeking. + * + * You do not need to call this function to load data; SDL_image can work to + * determine file type in many cases in its standard load functions. + * + * \param src a seekable/readable SDL_IOStream to provide image data. + * \returns true if this is ANI animated cursor data, false otherwise. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_isAVIF + * \sa IMG_isBMP + * \sa IMG_isCUR + * \sa IMG_isGIF + * \sa IMG_isICO + * \sa IMG_isJPG + * \sa IMG_isJXL + * \sa IMG_isLBM + * \sa IMG_isPCX + * \sa IMG_isPNG + * \sa IMG_isPNM + * \sa IMG_isQOI + * \sa IMG_isSVG + * \sa IMG_isTIF + * \sa IMG_isWEBP + * \sa IMG_isXCF + * \sa IMG_isXPM + * \sa IMG_isXV + */ +extern SDL_DECLSPEC bool SDLCALL IMG_isANI(SDL_IOStream *src); + /** * Detect AVIF image data on a readable/seekable SDL_IOStream. * @@ -387,74 +567,31 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL IMG_LoadTextureTyped_IO(SDL_Renderer * * determine file type in many cases in its standard load functions. * * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is AVIF data, zero otherwise. + * \returns true if this is AVIF data, false otherwise. * * \since This function is available since SDL_image 3.0.0. * - * \sa IMG_isAVIF - * \sa IMG_isICO - * \sa IMG_isCUR + * \sa IMG_isANI * \sa IMG_isBMP + * \sa IMG_isCUR * \sa IMG_isGIF + * \sa IMG_isICO * \sa IMG_isJPG * \sa IMG_isJXL * \sa IMG_isLBM * \sa IMG_isPCX * \sa IMG_isPNG * \sa IMG_isPNM - * \sa IMG_isSVG * \sa IMG_isQOI + * \sa IMG_isSVG * \sa IMG_isTIF + * \sa IMG_isWEBP * \sa IMG_isXCF * \sa IMG_isXPM * \sa IMG_isXV - * \sa IMG_isWEBP */ extern SDL_DECLSPEC bool SDLCALL IMG_isAVIF(SDL_IOStream *src); -/** - * Detect ICO image data on a readable/seekable SDL_IOStream. - * - * This function attempts to determine if a file is a given filetype, reading - * the least amount possible from the SDL_IOStream (usually a few bytes). - * - * There is no distinction made between "not the filetype in question" and - * basic i/o errors. - * - * This function will always attempt to seek `src` back to where it started - * when this function was called, but it will not report any errors in doing - * so, but assuming seeking works, this means you can immediately use this - * with a different IMG_isTYPE function, or load the image without further - * seeking. - * - * You do not need to call this function to load data; SDL_image can work to - * determine file type in many cases in its standard load functions. - * - * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is ICO data, zero otherwise. - * - * \since This function is available since SDL_image 3.0.0. - * - * \sa IMG_isAVIF - * \sa IMG_isCUR - * \sa IMG_isBMP - * \sa IMG_isGIF - * \sa IMG_isJPG - * \sa IMG_isJXL - * \sa IMG_isLBM - * \sa IMG_isPCX - * \sa IMG_isPNG - * \sa IMG_isPNM - * \sa IMG_isSVG - * \sa IMG_isQOI - * \sa IMG_isTIF - * \sa IMG_isXCF - * \sa IMG_isXPM - * \sa IMG_isXV - * \sa IMG_isWEBP - */ -extern SDL_DECLSPEC bool SDLCALL IMG_isICO(SDL_IOStream *src); - /** * Detect CUR image data on a readable/seekable SDL_IOStream. * @@ -474,27 +611,28 @@ extern SDL_DECLSPEC bool SDLCALL IMG_isICO(SDL_IOStream *src); * determine file type in many cases in its standard load functions. * * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is CUR data, zero otherwise. + * \returns true if this is CUR data, false otherwise. * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_isANI * \sa IMG_isAVIF - * \sa IMG_isICO * \sa IMG_isBMP * \sa IMG_isGIF + * \sa IMG_isICO * \sa IMG_isJPG * \sa IMG_isJXL * \sa IMG_isLBM * \sa IMG_isPCX * \sa IMG_isPNG * \sa IMG_isPNM - * \sa IMG_isSVG * \sa IMG_isQOI + * \sa IMG_isSVG * \sa IMG_isTIF + * \sa IMG_isWEBP * \sa IMG_isXCF * \sa IMG_isXPM * \sa IMG_isXV - * \sa IMG_isWEBP */ extern SDL_DECLSPEC bool SDLCALL IMG_isCUR(SDL_IOStream *src); @@ -517,27 +655,28 @@ extern SDL_DECLSPEC bool SDLCALL IMG_isCUR(SDL_IOStream *src); * determine file type in many cases in its standard load functions. * * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is BMP data, zero otherwise. + * \returns true if this is BMP data, false otherwise. * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_isANI * \sa IMG_isAVIF - * \sa IMG_isICO * \sa IMG_isCUR * \sa IMG_isGIF + * \sa IMG_isICO * \sa IMG_isJPG * \sa IMG_isJXL * \sa IMG_isLBM * \sa IMG_isPCX * \sa IMG_isPNG * \sa IMG_isPNM - * \sa IMG_isSVG * \sa IMG_isQOI + * \sa IMG_isSVG * \sa IMG_isTIF + * \sa IMG_isWEBP * \sa IMG_isXCF * \sa IMG_isXPM * \sa IMG_isXV - * \sa IMG_isWEBP */ extern SDL_DECLSPEC bool SDLCALL IMG_isBMP(SDL_IOStream *src); @@ -560,30 +699,75 @@ extern SDL_DECLSPEC bool SDLCALL IMG_isBMP(SDL_IOStream *src); * determine file type in many cases in its standard load functions. * * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is GIF data, zero otherwise. + * \returns true if this is GIF data, false otherwise. * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_isANI * \sa IMG_isAVIF - * \sa IMG_isICO - * \sa IMG_isCUR * \sa IMG_isBMP + * \sa IMG_isCUR + * \sa IMG_isICO * \sa IMG_isJPG * \sa IMG_isJXL * \sa IMG_isLBM * \sa IMG_isPCX * \sa IMG_isPNG * \sa IMG_isPNM - * \sa IMG_isSVG * \sa IMG_isQOI + * \sa IMG_isSVG * \sa IMG_isTIF + * \sa IMG_isWEBP * \sa IMG_isXCF * \sa IMG_isXPM * \sa IMG_isXV - * \sa IMG_isWEBP */ extern SDL_DECLSPEC bool SDLCALL IMG_isGIF(SDL_IOStream *src); +/** + * Detect ICO image data on a readable/seekable SDL_IOStream. + * + * This function attempts to determine if a file is a given filetype, reading + * the least amount possible from the SDL_IOStream (usually a few bytes). + * + * There is no distinction made between "not the filetype in question" and + * basic i/o errors. + * + * This function will always attempt to seek `src` back to where it started + * when this function was called, but it will not report any errors in doing + * so, but assuming seeking works, this means you can immediately use this + * with a different IMG_isTYPE function, or load the image without further + * seeking. + * + * You do not need to call this function to load data; SDL_image can work to + * determine file type in many cases in its standard load functions. + * + * \param src a seekable/readable SDL_IOStream to provide image data. + * \returns true if this is ICO data, false otherwise. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_isANI + * \sa IMG_isAVIF + * \sa IMG_isBMP + * \sa IMG_isCUR + * \sa IMG_isGIF + * \sa IMG_isJPG + * \sa IMG_isJXL + * \sa IMG_isLBM + * \sa IMG_isPCX + * \sa IMG_isPNG + * \sa IMG_isPNM + * \sa IMG_isQOI + * \sa IMG_isSVG + * \sa IMG_isTIF + * \sa IMG_isWEBP + * \sa IMG_isXCF + * \sa IMG_isXPM + * \sa IMG_isXV + */ +extern SDL_DECLSPEC bool SDLCALL IMG_isICO(SDL_IOStream *src); + /** * Detect JPG image data on a readable/seekable SDL_IOStream. * @@ -603,27 +787,28 @@ extern SDL_DECLSPEC bool SDLCALL IMG_isGIF(SDL_IOStream *src); * determine file type in many cases in its standard load functions. * * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is JPG data, zero otherwise. + * \returns true if this is JPG data, false otherwise. * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_isANI * \sa IMG_isAVIF - * \sa IMG_isICO - * \sa IMG_isCUR * \sa IMG_isBMP + * \sa IMG_isCUR * \sa IMG_isGIF + * \sa IMG_isICO * \sa IMG_isJXL * \sa IMG_isLBM * \sa IMG_isPCX * \sa IMG_isPNG * \sa IMG_isPNM - * \sa IMG_isSVG * \sa IMG_isQOI + * \sa IMG_isSVG * \sa IMG_isTIF + * \sa IMG_isWEBP * \sa IMG_isXCF * \sa IMG_isXPM * \sa IMG_isXV - * \sa IMG_isWEBP */ extern SDL_DECLSPEC bool SDLCALL IMG_isJPG(SDL_IOStream *src); @@ -646,27 +831,28 @@ extern SDL_DECLSPEC bool SDLCALL IMG_isJPG(SDL_IOStream *src); * determine file type in many cases in its standard load functions. * * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is JXL data, zero otherwise. + * \returns true if this is JXL data, false otherwise. * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_isANI * \sa IMG_isAVIF - * \sa IMG_isICO - * \sa IMG_isCUR * \sa IMG_isBMP + * \sa IMG_isCUR * \sa IMG_isGIF + * \sa IMG_isICO * \sa IMG_isJPG * \sa IMG_isLBM * \sa IMG_isPCX * \sa IMG_isPNG * \sa IMG_isPNM - * \sa IMG_isSVG * \sa IMG_isQOI + * \sa IMG_isSVG * \sa IMG_isTIF + * \sa IMG_isWEBP * \sa IMG_isXCF * \sa IMG_isXPM * \sa IMG_isXV - * \sa IMG_isWEBP */ extern SDL_DECLSPEC bool SDLCALL IMG_isJXL(SDL_IOStream *src); @@ -689,27 +875,28 @@ extern SDL_DECLSPEC bool SDLCALL IMG_isJXL(SDL_IOStream *src); * determine file type in many cases in its standard load functions. * * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is LBM data, zero otherwise. + * \returns true if this is LBM data, false otherwise. * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_isANI * \sa IMG_isAVIF - * \sa IMG_isICO - * \sa IMG_isCUR * \sa IMG_isBMP + * \sa IMG_isCUR * \sa IMG_isGIF + * \sa IMG_isICO * \sa IMG_isJPG * \sa IMG_isJXL * \sa IMG_isPCX * \sa IMG_isPNG * \sa IMG_isPNM - * \sa IMG_isSVG * \sa IMG_isQOI + * \sa IMG_isSVG * \sa IMG_isTIF + * \sa IMG_isWEBP * \sa IMG_isXCF * \sa IMG_isXPM * \sa IMG_isXV - * \sa IMG_isWEBP */ extern SDL_DECLSPEC bool SDLCALL IMG_isLBM(SDL_IOStream *src); @@ -732,27 +919,28 @@ extern SDL_DECLSPEC bool SDLCALL IMG_isLBM(SDL_IOStream *src); * determine file type in many cases in its standard load functions. * * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is PCX data, zero otherwise. + * \returns true if this is PCX data, false otherwise. * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_isANI * \sa IMG_isAVIF - * \sa IMG_isICO - * \sa IMG_isCUR * \sa IMG_isBMP + * \sa IMG_isCUR * \sa IMG_isGIF + * \sa IMG_isICO * \sa IMG_isJPG * \sa IMG_isJXL * \sa IMG_isLBM * \sa IMG_isPNG * \sa IMG_isPNM - * \sa IMG_isSVG * \sa IMG_isQOI + * \sa IMG_isSVG * \sa IMG_isTIF + * \sa IMG_isWEBP * \sa IMG_isXCF * \sa IMG_isXPM * \sa IMG_isXV - * \sa IMG_isWEBP */ extern SDL_DECLSPEC bool SDLCALL IMG_isPCX(SDL_IOStream *src); @@ -775,27 +963,28 @@ extern SDL_DECLSPEC bool SDLCALL IMG_isPCX(SDL_IOStream *src); * determine file type in many cases in its standard load functions. * * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is PNG data, zero otherwise. + * \returns true if this is PNG data, false otherwise. * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_isANI * \sa IMG_isAVIF - * \sa IMG_isICO - * \sa IMG_isCUR * \sa IMG_isBMP + * \sa IMG_isCUR * \sa IMG_isGIF + * \sa IMG_isICO * \sa IMG_isJPG * \sa IMG_isJXL * \sa IMG_isLBM * \sa IMG_isPCX * \sa IMG_isPNM - * \sa IMG_isSVG * \sa IMG_isQOI + * \sa IMG_isSVG * \sa IMG_isTIF + * \sa IMG_isWEBP * \sa IMG_isXCF * \sa IMG_isXPM * \sa IMG_isXV - * \sa IMG_isWEBP */ extern SDL_DECLSPEC bool SDLCALL IMG_isPNG(SDL_IOStream *src); @@ -818,73 +1007,31 @@ extern SDL_DECLSPEC bool SDLCALL IMG_isPNG(SDL_IOStream *src); * determine file type in many cases in its standard load functions. * * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is PNM data, zero otherwise. + * \returns true if this is PNM data, false otherwise. * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_isANI * \sa IMG_isAVIF - * \sa IMG_isICO - * \sa IMG_isCUR * \sa IMG_isBMP + * \sa IMG_isCUR * \sa IMG_isGIF + * \sa IMG_isICO * \sa IMG_isJPG * \sa IMG_isJXL * \sa IMG_isLBM * \sa IMG_isPCX * \sa IMG_isPNG - * \sa IMG_isSVG * \sa IMG_isQOI + * \sa IMG_isSVG * \sa IMG_isTIF + * \sa IMG_isWEBP * \sa IMG_isXCF * \sa IMG_isXPM * \sa IMG_isXV - * \sa IMG_isWEBP */ extern SDL_DECLSPEC bool SDLCALL IMG_isPNM(SDL_IOStream *src); -/** - * Detect SVG image data on a readable/seekable SDL_IOStream. - * - * This function attempts to determine if a file is a given filetype, reading - * the least amount possible from the SDL_IOStream (usually a few bytes). - * - * There is no distinction made between "not the filetype in question" and - * basic i/o errors. - * - * This function will always attempt to seek `src` back to where it started - * when this function was called, but it will not report any errors in doing - * so, but assuming seeking works, this means you can immediately use this - * with a different IMG_isTYPE function, or load the image without further - * seeking. - * - * You do not need to call this function to load data; SDL_image can work to - * determine file type in many cases in its standard load functions. - * - * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is SVG data, zero otherwise. - * - * \since This function is available since SDL_image 3.0.0. - * - * \sa IMG_isAVIF - * \sa IMG_isICO - * \sa IMG_isCUR - * \sa IMG_isBMP - * \sa IMG_isGIF - * \sa IMG_isJPG - * \sa IMG_isJXL - * \sa IMG_isLBM - * \sa IMG_isPCX - * \sa IMG_isPNG - * \sa IMG_isPNM - * \sa IMG_isQOI - * \sa IMG_isTIF - * \sa IMG_isXCF - * \sa IMG_isXPM - * \sa IMG_isXV - * \sa IMG_isWEBP - */ -extern SDL_DECLSPEC bool SDLCALL IMG_isSVG(SDL_IOStream *src); - /** * Detect QOI image data on a readable/seekable SDL_IOStream. * @@ -904,15 +1051,16 @@ extern SDL_DECLSPEC bool SDLCALL IMG_isSVG(SDL_IOStream *src); * determine file type in many cases in its standard load functions. * * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is QOI data, zero otherwise. + * \returns true if this is QOI data, false otherwise. * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_isANI * \sa IMG_isAVIF - * \sa IMG_isICO - * \sa IMG_isCUR * \sa IMG_isBMP + * \sa IMG_isCUR * \sa IMG_isGIF + * \sa IMG_isICO * \sa IMG_isJPG * \sa IMG_isJXL * \sa IMG_isLBM @@ -921,13 +1069,57 @@ extern SDL_DECLSPEC bool SDLCALL IMG_isSVG(SDL_IOStream *src); * \sa IMG_isPNM * \sa IMG_isSVG * \sa IMG_isTIF + * \sa IMG_isWEBP * \sa IMG_isXCF * \sa IMG_isXPM * \sa IMG_isXV - * \sa IMG_isWEBP */ extern SDL_DECLSPEC bool SDLCALL IMG_isQOI(SDL_IOStream *src); +/** + * Detect SVG image data on a readable/seekable SDL_IOStream. + * + * This function attempts to determine if a file is a given filetype, reading + * the least amount possible from the SDL_IOStream (usually a few bytes). + * + * There is no distinction made between "not the filetype in question" and + * basic i/o errors. + * + * This function will always attempt to seek `src` back to where it started + * when this function was called, but it will not report any errors in doing + * so, but assuming seeking works, this means you can immediately use this + * with a different IMG_isTYPE function, or load the image without further + * seeking. + * + * You do not need to call this function to load data; SDL_image can work to + * determine file type in many cases in its standard load functions. + * + * \param src a seekable/readable SDL_IOStream to provide image data. + * \returns true if this is SVG data, false otherwise. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_isANI + * \sa IMG_isAVIF + * \sa IMG_isBMP + * \sa IMG_isCUR + * \sa IMG_isGIF + * \sa IMG_isICO + * \sa IMG_isJPG + * \sa IMG_isJXL + * \sa IMG_isLBM + * \sa IMG_isPCX + * \sa IMG_isPNG + * \sa IMG_isPNM + * \sa IMG_isQOI + * \sa IMG_isTIF + * \sa IMG_isWEBP + * \sa IMG_isXCF + * \sa IMG_isXPM + * \sa IMG_isXV + */ +extern SDL_DECLSPEC bool SDLCALL IMG_isSVG(SDL_IOStream *src); + /** * Detect TIFF image data on a readable/seekable SDL_IOStream. * @@ -947,30 +1139,75 @@ extern SDL_DECLSPEC bool SDLCALL IMG_isQOI(SDL_IOStream *src); * determine file type in many cases in its standard load functions. * * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is TIFF data, zero otherwise. + * \returns true if this is TIFF data, false otherwise. * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_isANI * \sa IMG_isAVIF - * \sa IMG_isICO - * \sa IMG_isCUR * \sa IMG_isBMP + * \sa IMG_isCUR * \sa IMG_isGIF + * \sa IMG_isICO * \sa IMG_isJPG * \sa IMG_isJXL * \sa IMG_isLBM * \sa IMG_isPCX * \sa IMG_isPNG * \sa IMG_isPNM - * \sa IMG_isSVG * \sa IMG_isQOI + * \sa IMG_isSVG + * \sa IMG_isWEBP * \sa IMG_isXCF * \sa IMG_isXPM * \sa IMG_isXV - * \sa IMG_isWEBP */ extern SDL_DECLSPEC bool SDLCALL IMG_isTIF(SDL_IOStream *src); +/** + * Detect WEBP image data on a readable/seekable SDL_IOStream. + * + * This function attempts to determine if a file is a given filetype, reading + * the least amount possible from the SDL_IOStream (usually a few bytes). + * + * There is no distinction made between "not the filetype in question" and + * basic i/o errors. + * + * This function will always attempt to seek `src` back to where it started + * when this function was called, but it will not report any errors in doing + * so, but assuming seeking works, this means you can immediately use this + * with a different IMG_isTYPE function, or load the image without further + * seeking. + * + * You do not need to call this function to load data; SDL_image can work to + * determine file type in many cases in its standard load functions. + * + * \param src a seekable/readable SDL_IOStream to provide image data. + * \returns true if this is WEBP data, false otherwise. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_isANI + * \sa IMG_isAVIF + * \sa IMG_isBMP + * \sa IMG_isCUR + * \sa IMG_isGIF + * \sa IMG_isICO + * \sa IMG_isJPG + * \sa IMG_isJXL + * \sa IMG_isLBM + * \sa IMG_isPCX + * \sa IMG_isPNG + * \sa IMG_isPNM + * \sa IMG_isQOI + * \sa IMG_isSVG + * \sa IMG_isTIF + * \sa IMG_isXCF + * \sa IMG_isXPM + * \sa IMG_isXV + */ +extern SDL_DECLSPEC bool SDLCALL IMG_isWEBP(SDL_IOStream *src); + /** * Detect XCF image data on a readable/seekable SDL_IOStream. * @@ -990,27 +1227,28 @@ extern SDL_DECLSPEC bool SDLCALL IMG_isTIF(SDL_IOStream *src); * determine file type in many cases in its standard load functions. * * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is XCF data, zero otherwise. + * \returns true if this is XCF data, false otherwise. * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_isANI * \sa IMG_isAVIF - * \sa IMG_isICO - * \sa IMG_isCUR * \sa IMG_isBMP + * \sa IMG_isCUR * \sa IMG_isGIF + * \sa IMG_isICO * \sa IMG_isJPG * \sa IMG_isJXL * \sa IMG_isLBM * \sa IMG_isPCX * \sa IMG_isPNG * \sa IMG_isPNM - * \sa IMG_isSVG * \sa IMG_isQOI + * \sa IMG_isSVG * \sa IMG_isTIF + * \sa IMG_isWEBP * \sa IMG_isXPM * \sa IMG_isXV - * \sa IMG_isWEBP */ extern SDL_DECLSPEC bool SDLCALL IMG_isXCF(SDL_IOStream *src); @@ -1033,27 +1271,28 @@ extern SDL_DECLSPEC bool SDLCALL IMG_isXCF(SDL_IOStream *src); * determine file type in many cases in its standard load functions. * * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is XPM data, zero otherwise. + * \returns true if this is XPM data, false otherwise. * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_isANI * \sa IMG_isAVIF - * \sa IMG_isICO - * \sa IMG_isCUR * \sa IMG_isBMP + * \sa IMG_isCUR * \sa IMG_isGIF + * \sa IMG_isICO * \sa IMG_isJPG * \sa IMG_isJXL * \sa IMG_isLBM * \sa IMG_isPCX * \sa IMG_isPNG * \sa IMG_isPNM - * \sa IMG_isSVG * \sa IMG_isQOI + * \sa IMG_isSVG * \sa IMG_isTIF + * \sa IMG_isWEBP * \sa IMG_isXCF * \sa IMG_isXV - * \sa IMG_isWEBP */ extern SDL_DECLSPEC bool SDLCALL IMG_isXPM(SDL_IOStream *src); @@ -1076,73 +1315,31 @@ extern SDL_DECLSPEC bool SDLCALL IMG_isXPM(SDL_IOStream *src); * determine file type in many cases in its standard load functions. * * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is XV data, zero otherwise. + * \returns true if this is XV data, false otherwise. * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_isANI * \sa IMG_isAVIF - * \sa IMG_isICO - * \sa IMG_isCUR * \sa IMG_isBMP + * \sa IMG_isCUR * \sa IMG_isGIF + * \sa IMG_isICO * \sa IMG_isJPG * \sa IMG_isJXL * \sa IMG_isLBM * \sa IMG_isPCX * \sa IMG_isPNG * \sa IMG_isPNM - * \sa IMG_isSVG * \sa IMG_isQOI + * \sa IMG_isSVG * \sa IMG_isTIF + * \sa IMG_isWEBP * \sa IMG_isXCF * \sa IMG_isXPM - * \sa IMG_isWEBP */ extern SDL_DECLSPEC bool SDLCALL IMG_isXV(SDL_IOStream *src); -/** - * Detect WEBP image data on a readable/seekable SDL_IOStream. - * - * This function attempts to determine if a file is a given filetype, reading - * the least amount possible from the SDL_IOStream (usually a few bytes). - * - * There is no distinction made between "not the filetype in question" and - * basic i/o errors. - * - * This function will always attempt to seek `src` back to where it started - * when this function was called, but it will not report any errors in doing - * so, but assuming seeking works, this means you can immediately use this - * with a different IMG_isTYPE function, or load the image without further - * seeking. - * - * You do not need to call this function to load data; SDL_image can work to - * determine file type in many cases in its standard load functions. - * - * \param src a seekable/readable SDL_IOStream to provide image data. - * \returns non-zero if this is WEBP data, zero otherwise. - * - * \since This function is available since SDL_image 3.0.0. - * - * \sa IMG_isAVIF - * \sa IMG_isICO - * \sa IMG_isCUR - * \sa IMG_isBMP - * \sa IMG_isGIF - * \sa IMG_isJPG - * \sa IMG_isJXL - * \sa IMG_isLBM - * \sa IMG_isPCX - * \sa IMG_isPNG - * \sa IMG_isPNM - * \sa IMG_isSVG - * \sa IMG_isQOI - * \sa IMG_isTIF - * \sa IMG_isXCF - * \sa IMG_isXPM - * \sa IMG_isXV - */ -extern SDL_DECLSPEC bool SDLCALL IMG_isWEBP(SDL_IOStream *src); - /** * Load a AVIF image directly. * @@ -1156,95 +1353,27 @@ extern SDL_DECLSPEC bool SDLCALL IMG_isWEBP(SDL_IOStream *src); * * \since This function is available since SDL_image 3.0.0. * - * \sa IMG_LoadICO_IO - * \sa IMG_LoadCUR_IO * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO * \sa IMG_LoadJPG_IO * \sa IMG_LoadJXL_IO * \sa IMG_LoadLBM_IO * \sa IMG_LoadPCX_IO * \sa IMG_LoadPNG_IO * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO * \sa IMG_LoadTGA_IO * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO * \sa IMG_LoadXCF_IO * \sa IMG_LoadXPM_IO * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO */ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadAVIF_IO(SDL_IOStream *src); -/** - * Load a ICO image directly. - * - * If you know you definitely have a ICO image, you can call this function, - * which will skip SDL_image's file format detection routines. Generally it's - * better to use the abstract interfaces; also, there is only an SDL_IOStream - * interface available here. - * - * \param src an SDL_IOStream to load image data from. - * \returns SDL surface, or NULL on error. - * - * \since This function is available since SDL_image 3.0.0. - * - * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadCUR_IO - * \sa IMG_LoadBMP_IO - * \sa IMG_LoadGIF_IO - * \sa IMG_LoadJPG_IO - * \sa IMG_LoadJXL_IO - * \sa IMG_LoadLBM_IO - * \sa IMG_LoadPCX_IO - * \sa IMG_LoadPNG_IO - * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO - * \sa IMG_LoadQOI_IO - * \sa IMG_LoadTGA_IO - * \sa IMG_LoadTIF_IO - * \sa IMG_LoadXCF_IO - * \sa IMG_LoadXPM_IO - * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO - */ -extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadICO_IO(SDL_IOStream *src); - -/** - * Load a CUR image directly. - * - * If you know you definitely have a CUR image, you can call this function, - * which will skip SDL_image's file format detection routines. Generally it's - * better to use the abstract interfaces; also, there is only an SDL_IOStream - * interface available here. - * - * \param src an SDL_IOStream to load image data from. - * \returns SDL surface, or NULL on error. - * - * \since This function is available since SDL_image 3.0.0. - * - * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO - * \sa IMG_LoadBMP_IO - * \sa IMG_LoadGIF_IO - * \sa IMG_LoadJPG_IO - * \sa IMG_LoadJXL_IO - * \sa IMG_LoadLBM_IO - * \sa IMG_LoadPCX_IO - * \sa IMG_LoadPNG_IO - * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO - * \sa IMG_LoadQOI_IO - * \sa IMG_LoadTGA_IO - * \sa IMG_LoadTIF_IO - * \sa IMG_LoadXCF_IO - * \sa IMG_LoadXPM_IO - * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO - */ -extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadCUR_IO(SDL_IOStream *src); - /** * Load a BMP image directly. * @@ -1259,26 +1388,60 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadCUR_IO(SDL_IOStream *src); * \since This function is available since SDL_image 3.0.0. * * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO * \sa IMG_LoadCUR_IO * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO * \sa IMG_LoadJPG_IO * \sa IMG_LoadJXL_IO * \sa IMG_LoadLBM_IO * \sa IMG_LoadPCX_IO * \sa IMG_LoadPNG_IO * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO * \sa IMG_LoadTGA_IO * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO * \sa IMG_LoadXCF_IO * \sa IMG_LoadXPM_IO * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO */ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadBMP_IO(SDL_IOStream *src); +/** + * Load a CUR image directly. + * + * If you know you definitely have a CUR image, you can call this function, + * which will skip SDL_image's file format detection routines. Generally it's + * better to use the abstract interfaces; also, there is only an SDL_IOStream + * interface available here. + * + * \param src an SDL_IOStream to load image data from. + * \returns SDL surface, or NULL on error. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_LoadAVIF_IO + * \sa IMG_LoadBMP_IO + * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO + * \sa IMG_LoadJPG_IO + * \sa IMG_LoadJXL_IO + * \sa IMG_LoadLBM_IO + * \sa IMG_LoadPCX_IO + * \sa IMG_LoadPNG_IO + * \sa IMG_LoadPNM_IO + * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO + * \sa IMG_LoadTGA_IO + * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO + * \sa IMG_LoadXCF_IO + * \sa IMG_LoadXPM_IO + * \sa IMG_LoadXV_IO + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadCUR_IO(SDL_IOStream *src); + /** * Load a GIF image directly. * @@ -1293,26 +1456,60 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadBMP_IO(SDL_IOStream *src); * \since This function is available since SDL_image 3.0.0. * * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO - * \sa IMG_LoadCUR_IO * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO + * \sa IMG_LoadICO_IO * \sa IMG_LoadJPG_IO * \sa IMG_LoadJXL_IO * \sa IMG_LoadLBM_IO * \sa IMG_LoadPCX_IO * \sa IMG_LoadPNG_IO * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO * \sa IMG_LoadTGA_IO * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO * \sa IMG_LoadXCF_IO * \sa IMG_LoadXPM_IO * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO */ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadGIF_IO(SDL_IOStream *src); +/** + * Load a ICO image directly. + * + * If you know you definitely have a ICO image, you can call this function, + * which will skip SDL_image's file format detection routines. Generally it's + * better to use the abstract interfaces; also, there is only an SDL_IOStream + * interface available here. + * + * \param src an SDL_IOStream to load image data from. + * \returns SDL surface, or NULL on error. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_LoadAVIF_IO + * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO + * \sa IMG_LoadGIF_IO + * \sa IMG_LoadJPG_IO + * \sa IMG_LoadJXL_IO + * \sa IMG_LoadLBM_IO + * \sa IMG_LoadPCX_IO + * \sa IMG_LoadPNG_IO + * \sa IMG_LoadPNM_IO + * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO + * \sa IMG_LoadTGA_IO + * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO + * \sa IMG_LoadXCF_IO + * \sa IMG_LoadXPM_IO + * \sa IMG_LoadXV_IO + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadICO_IO(SDL_IOStream *src); + /** * Load a JPG image directly. * @@ -1327,23 +1524,23 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadGIF_IO(SDL_IOStream *src); * \since This function is available since SDL_image 3.0.0. * * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO - * \sa IMG_LoadCUR_IO * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO * \sa IMG_LoadJXL_IO * \sa IMG_LoadLBM_IO * \sa IMG_LoadPCX_IO * \sa IMG_LoadPNG_IO * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO * \sa IMG_LoadTGA_IO * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO * \sa IMG_LoadXCF_IO * \sa IMG_LoadXPM_IO * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO */ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadJPG_IO(SDL_IOStream *src); @@ -1361,23 +1558,23 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadJPG_IO(SDL_IOStream *src); * \since This function is available since SDL_image 3.0.0. * * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO - * \sa IMG_LoadCUR_IO * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO * \sa IMG_LoadJPG_IO * \sa IMG_LoadLBM_IO * \sa IMG_LoadPCX_IO * \sa IMG_LoadPNG_IO * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO * \sa IMG_LoadTGA_IO * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO * \sa IMG_LoadXCF_IO * \sa IMG_LoadXPM_IO * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO */ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadJXL_IO(SDL_IOStream *src); @@ -1395,23 +1592,23 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadJXL_IO(SDL_IOStream *src); * \since This function is available since SDL_image 3.0.0. * * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO - * \sa IMG_LoadCUR_IO * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO * \sa IMG_LoadJPG_IO * \sa IMG_LoadJXL_IO * \sa IMG_LoadPCX_IO * \sa IMG_LoadPNG_IO * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO * \sa IMG_LoadTGA_IO * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO * \sa IMG_LoadXCF_IO * \sa IMG_LoadXPM_IO * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO */ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadLBM_IO(SDL_IOStream *src); @@ -1429,23 +1626,23 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadLBM_IO(SDL_IOStream *src); * \since This function is available since SDL_image 3.0.0. * * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO - * \sa IMG_LoadCUR_IO * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO * \sa IMG_LoadJPG_IO * \sa IMG_LoadJXL_IO * \sa IMG_LoadLBM_IO * \sa IMG_LoadPNG_IO * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO * \sa IMG_LoadTGA_IO * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO * \sa IMG_LoadXCF_IO * \sa IMG_LoadXPM_IO * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO */ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadPCX_IO(SDL_IOStream *src); @@ -1463,23 +1660,23 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadPCX_IO(SDL_IOStream *src); * \since This function is available since SDL_image 3.0.0. * * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO - * \sa IMG_LoadCUR_IO * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO * \sa IMG_LoadJPG_IO * \sa IMG_LoadJXL_IO * \sa IMG_LoadLBM_IO * \sa IMG_LoadPCX_IO * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO * \sa IMG_LoadTGA_IO * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO * \sa IMG_LoadXCF_IO * \sa IMG_LoadXPM_IO * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO */ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadPNG_IO(SDL_IOStream *src); @@ -1497,23 +1694,23 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadPNG_IO(SDL_IOStream *src); * \since This function is available since SDL_image 3.0.0. * * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO - * \sa IMG_LoadCUR_IO * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO * \sa IMG_LoadJPG_IO * \sa IMG_LoadJXL_IO * \sa IMG_LoadLBM_IO * \sa IMG_LoadPCX_IO * \sa IMG_LoadPNG_IO - * \sa IMG_LoadSVG_IO * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO * \sa IMG_LoadTGA_IO * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO * \sa IMG_LoadXCF_IO * \sa IMG_LoadXPM_IO * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO */ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadPNM_IO(SDL_IOStream *src); @@ -1531,10 +1728,10 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadPNM_IO(SDL_IOStream *src); * \since This function is available since SDL_image 3.0.0. * * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO - * \sa IMG_LoadCUR_IO * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO * \sa IMG_LoadJPG_IO * \sa IMG_LoadJXL_IO * \sa IMG_LoadLBM_IO @@ -1542,253 +1739,16 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadPNM_IO(SDL_IOStream *src); * \sa IMG_LoadPNG_IO * \sa IMG_LoadPNM_IO * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSizedSVG_IO * \sa IMG_LoadTGA_IO * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO * \sa IMG_LoadXCF_IO * \sa IMG_LoadXPM_IO * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO */ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadSVG_IO(SDL_IOStream *src); -/** - * Load a QOI image directly. - * - * If you know you definitely have a QOI image, you can call this function, - * which will skip SDL_image's file format detection routines. Generally it's - * better to use the abstract interfaces; also, there is only an SDL_IOStream - * interface available here. - * - * \param src an SDL_IOStream to load image data from. - * \returns SDL surface, or NULL on error. - * - * \since This function is available since SDL_image 3.0.0. - * - * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO - * \sa IMG_LoadCUR_IO - * \sa IMG_LoadBMP_IO - * \sa IMG_LoadGIF_IO - * \sa IMG_LoadJPG_IO - * \sa IMG_LoadJXL_IO - * \sa IMG_LoadLBM_IO - * \sa IMG_LoadPCX_IO - * \sa IMG_LoadPNG_IO - * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO - * \sa IMG_LoadTGA_IO - * \sa IMG_LoadTIF_IO - * \sa IMG_LoadXCF_IO - * \sa IMG_LoadXPM_IO - * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO - */ -extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadQOI_IO(SDL_IOStream *src); - -/** - * Load a TGA image directly. - * - * If you know you definitely have a TGA image, you can call this function, - * which will skip SDL_image's file format detection routines. Generally it's - * better to use the abstract interfaces; also, there is only an SDL_IOStream - * interface available here. - * - * \param src an SDL_IOStream to load image data from. - * \returns SDL surface, or NULL on error. - * - * \since This function is available since SDL_image 3.0.0. - * - * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO - * \sa IMG_LoadCUR_IO - * \sa IMG_LoadBMP_IO - * \sa IMG_LoadGIF_IO - * \sa IMG_LoadJPG_IO - * \sa IMG_LoadJXL_IO - * \sa IMG_LoadLBM_IO - * \sa IMG_LoadPCX_IO - * \sa IMG_LoadPNG_IO - * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO - * \sa IMG_LoadQOI_IO - * \sa IMG_LoadTIF_IO - * \sa IMG_LoadXCF_IO - * \sa IMG_LoadXPM_IO - * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO - */ -extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadTGA_IO(SDL_IOStream *src); - -/** - * Load a TIFF image directly. - * - * If you know you definitely have a TIFF image, you can call this function, - * which will skip SDL_image's file format detection routines. Generally it's - * better to use the abstract interfaces; also, there is only an SDL_IOStream - * interface available here. - * - * \param src an SDL_IOStream to load image data from. - * \returns SDL surface, or NULL on error. - * - * \since This function is available since SDL_image 3.0.0. - * - * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO - * \sa IMG_LoadCUR_IO - * \sa IMG_LoadBMP_IO - * \sa IMG_LoadGIF_IO - * \sa IMG_LoadJPG_IO - * \sa IMG_LoadJXL_IO - * \sa IMG_LoadLBM_IO - * \sa IMG_LoadPCX_IO - * \sa IMG_LoadPNG_IO - * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO - * \sa IMG_LoadQOI_IO - * \sa IMG_LoadTGA_IO - * \sa IMG_LoadXCF_IO - * \sa IMG_LoadXPM_IO - * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO - */ -extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadTIF_IO(SDL_IOStream *src); - -/** - * Load a XCF image directly. - * - * If you know you definitely have a XCF image, you can call this function, - * which will skip SDL_image's file format detection routines. Generally it's - * better to use the abstract interfaces; also, there is only an SDL_IOStream - * interface available here. - * - * \param src an SDL_IOStream to load image data from. - * \returns SDL surface, or NULL on error. - * - * \since This function is available since SDL_image 3.0.0. - * - * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO - * \sa IMG_LoadCUR_IO - * \sa IMG_LoadBMP_IO - * \sa IMG_LoadGIF_IO - * \sa IMG_LoadJPG_IO - * \sa IMG_LoadJXL_IO - * \sa IMG_LoadLBM_IO - * \sa IMG_LoadPCX_IO - * \sa IMG_LoadPNG_IO - * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO - * \sa IMG_LoadQOI_IO - * \sa IMG_LoadTGA_IO - * \sa IMG_LoadTIF_IO - * \sa IMG_LoadXPM_IO - * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO - */ -extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadXCF_IO(SDL_IOStream *src); - -/** - * Load a XPM image directly. - * - * If you know you definitely have a XPM image, you can call this function, - * which will skip SDL_image's file format detection routines. Generally it's - * better to use the abstract interfaces; also, there is only an SDL_IOStream - * interface available here. - * - * \param src an SDL_IOStream to load image data from. - * \returns SDL surface, or NULL on error. - * - * \since This function is available since SDL_image 3.0.0. - * - * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO - * \sa IMG_LoadCUR_IO - * \sa IMG_LoadBMP_IO - * \sa IMG_LoadGIF_IO - * \sa IMG_LoadJPG_IO - * \sa IMG_LoadJXL_IO - * \sa IMG_LoadLBM_IO - * \sa IMG_LoadPCX_IO - * \sa IMG_LoadPNG_IO - * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO - * \sa IMG_LoadQOI_IO - * \sa IMG_LoadTGA_IO - * \sa IMG_LoadTIF_IO - * \sa IMG_LoadXCF_IO - * \sa IMG_LoadXV_IO - * \sa IMG_LoadWEBP_IO - */ -extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadXPM_IO(SDL_IOStream *src); - -/** - * Load a XV image directly. - * - * If you know you definitely have a XV image, you can call this function, - * which will skip SDL_image's file format detection routines. Generally it's - * better to use the abstract interfaces; also, there is only an SDL_IOStream - * interface available here. - * - * \param src an SDL_IOStream to load image data from. - * \returns SDL surface, or NULL on error. - * - * \since This function is available since SDL_image 3.0.0. - * - * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO - * \sa IMG_LoadCUR_IO - * \sa IMG_LoadBMP_IO - * \sa IMG_LoadGIF_IO - * \sa IMG_LoadJPG_IO - * \sa IMG_LoadJXL_IO - * \sa IMG_LoadLBM_IO - * \sa IMG_LoadPCX_IO - * \sa IMG_LoadPNG_IO - * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO - * \sa IMG_LoadQOI_IO - * \sa IMG_LoadTGA_IO - * \sa IMG_LoadTIF_IO - * \sa IMG_LoadXCF_IO - * \sa IMG_LoadXPM_IO - * \sa IMG_LoadWEBP_IO - */ -extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadXV_IO(SDL_IOStream *src); - -/** - * Load a WEBP image directly. - * - * If you know you definitely have a WEBP image, you can call this function, - * which will skip SDL_image's file format detection routines. Generally it's - * better to use the abstract interfaces; also, there is only an SDL_IOStream - * interface available here. - * - * \param src an SDL_IOStream to load image data from. - * \returns SDL surface, or NULL on error. - * - * \since This function is available since SDL_image 3.0.0. - * - * \sa IMG_LoadAVIF_IO - * \sa IMG_LoadICO_IO - * \sa IMG_LoadCUR_IO - * \sa IMG_LoadBMP_IO - * \sa IMG_LoadGIF_IO - * \sa IMG_LoadJPG_IO - * \sa IMG_LoadJXL_IO - * \sa IMG_LoadLBM_IO - * \sa IMG_LoadPCX_IO - * \sa IMG_LoadPNG_IO - * \sa IMG_LoadPNM_IO - * \sa IMG_LoadSVG_IO - * \sa IMG_LoadQOI_IO - * \sa IMG_LoadTGA_IO - * \sa IMG_LoadTIF_IO - * \sa IMG_LoadXCF_IO - * \sa IMG_LoadXPM_IO - * \sa IMG_LoadXV_IO - */ -extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadWEBP_IO(SDL_IOStream *src); - /** * Load an SVG image, scaled to a specific size. * @@ -1807,9 +1767,249 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadWEBP_IO(SDL_IOStream *src); * \returns a new SDL surface, or NULL on error. * * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_LoadSVG_IO */ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadSizedSVG_IO(SDL_IOStream *src, int width, int height); +/** + * Load a QOI image directly. + * + * If you know you definitely have a QOI image, you can call this function, + * which will skip SDL_image's file format detection routines. Generally it's + * better to use the abstract interfaces; also, there is only an SDL_IOStream + * interface available here. + * + * \param src an SDL_IOStream to load image data from. + * \returns SDL surface, or NULL on error. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_LoadAVIF_IO + * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO + * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO + * \sa IMG_LoadJPG_IO + * \sa IMG_LoadJXL_IO + * \sa IMG_LoadLBM_IO + * \sa IMG_LoadPCX_IO + * \sa IMG_LoadPNG_IO + * \sa IMG_LoadPNM_IO + * \sa IMG_LoadSVG_IO + * \sa IMG_LoadTGA_IO + * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO + * \sa IMG_LoadXCF_IO + * \sa IMG_LoadXPM_IO + * \sa IMG_LoadXV_IO + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadQOI_IO(SDL_IOStream *src); + +/** + * Load a TGA image directly. + * + * If you know you definitely have a TGA image, you can call this function, + * which will skip SDL_image's file format detection routines. Generally it's + * better to use the abstract interfaces; also, there is only an SDL_IOStream + * interface available here. + * + * \param src an SDL_IOStream to load image data from. + * \returns SDL surface, or NULL on error. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_LoadAVIF_IO + * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO + * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO + * \sa IMG_LoadJPG_IO + * \sa IMG_LoadJXL_IO + * \sa IMG_LoadLBM_IO + * \sa IMG_LoadPCX_IO + * \sa IMG_LoadPNG_IO + * \sa IMG_LoadPNM_IO + * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO + * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO + * \sa IMG_LoadXCF_IO + * \sa IMG_LoadXPM_IO + * \sa IMG_LoadXV_IO + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadTGA_IO(SDL_IOStream *src); + +/** + * Load a TIFF image directly. + * + * If you know you definitely have a TIFF image, you can call this function, + * which will skip SDL_image's file format detection routines. Generally it's + * better to use the abstract interfaces; also, there is only an SDL_IOStream + * interface available here. + * + * \param src an SDL_IOStream to load image data from. + * \returns SDL surface, or NULL on error. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_LoadAVIF_IO + * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO + * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO + * \sa IMG_LoadJPG_IO + * \sa IMG_LoadJXL_IO + * \sa IMG_LoadLBM_IO + * \sa IMG_LoadPCX_IO + * \sa IMG_LoadPNG_IO + * \sa IMG_LoadPNM_IO + * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO + * \sa IMG_LoadTGA_IO + * \sa IMG_LoadWEBP_IO + * \sa IMG_LoadXCF_IO + * \sa IMG_LoadXPM_IO + * \sa IMG_LoadXV_IO + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadTIF_IO(SDL_IOStream *src); + +/** + * Load a WEBP image directly. + * + * If you know you definitely have a WEBP image, you can call this function, + * which will skip SDL_image's file format detection routines. Generally it's + * better to use the abstract interfaces; also, there is only an SDL_IOStream + * interface available here. + * + * \param src an SDL_IOStream to load image data from. + * \returns SDL surface, or NULL on error. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_LoadAVIF_IO + * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO + * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO + * \sa IMG_LoadJPG_IO + * \sa IMG_LoadJXL_IO + * \sa IMG_LoadLBM_IO + * \sa IMG_LoadPCX_IO + * \sa IMG_LoadPNG_IO + * \sa IMG_LoadPNM_IO + * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO + * \sa IMG_LoadTGA_IO + * \sa IMG_LoadTIF_IO + * \sa IMG_LoadXCF_IO + * \sa IMG_LoadXPM_IO + * \sa IMG_LoadXV_IO + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadWEBP_IO(SDL_IOStream *src); + +/** + * Load a XCF image directly. + * + * If you know you definitely have a XCF image, you can call this function, + * which will skip SDL_image's file format detection routines. Generally it's + * better to use the abstract interfaces; also, there is only an SDL_IOStream + * interface available here. + * + * \param src an SDL_IOStream to load image data from. + * \returns SDL surface, or NULL on error. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_LoadAVIF_IO + * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO + * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO + * \sa IMG_LoadJPG_IO + * \sa IMG_LoadJXL_IO + * \sa IMG_LoadLBM_IO + * \sa IMG_LoadPCX_IO + * \sa IMG_LoadPNG_IO + * \sa IMG_LoadPNM_IO + * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO + * \sa IMG_LoadTGA_IO + * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO + * \sa IMG_LoadXPM_IO + * \sa IMG_LoadXV_IO + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadXCF_IO(SDL_IOStream *src); + +/** + * Load a XPM image directly. + * + * If you know you definitely have a XPM image, you can call this function, + * which will skip SDL_image's file format detection routines. Generally it's + * better to use the abstract interfaces; also, there is only an SDL_IOStream + * interface available here. + * + * \param src an SDL_IOStream to load image data from. + * \returns SDL surface, or NULL on error. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_LoadAVIF_IO + * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO + * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO + * \sa IMG_LoadJPG_IO + * \sa IMG_LoadJXL_IO + * \sa IMG_LoadLBM_IO + * \sa IMG_LoadPCX_IO + * \sa IMG_LoadPNG_IO + * \sa IMG_LoadPNM_IO + * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO + * \sa IMG_LoadTGA_IO + * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO + * \sa IMG_LoadXCF_IO + * \sa IMG_LoadXV_IO + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadXPM_IO(SDL_IOStream *src); + +/** + * Load a XV image directly. + * + * If you know you definitely have a XV image, you can call this function, + * which will skip SDL_image's file format detection routines. Generally it's + * better to use the abstract interfaces; also, there is only an SDL_IOStream + * interface available here. + * + * \param src an SDL_IOStream to load image data from. + * \returns SDL surface, or NULL on error. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_LoadAVIF_IO + * \sa IMG_LoadBMP_IO + * \sa IMG_LoadCUR_IO + * \sa IMG_LoadGIF_IO + * \sa IMG_LoadICO_IO + * \sa IMG_LoadJPG_IO + * \sa IMG_LoadJXL_IO + * \sa IMG_LoadLBM_IO + * \sa IMG_LoadPCX_IO + * \sa IMG_LoadPNG_IO + * \sa IMG_LoadPNM_IO + * \sa IMG_LoadQOI_IO + * \sa IMG_LoadSVG_IO + * \sa IMG_LoadTGA_IO + * \sa IMG_LoadTIF_IO + * \sa IMG_LoadWEBP_IO + * \sa IMG_LoadXCF_IO + * \sa IMG_LoadXPM_IO + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_LoadXV_IO(SDL_IOStream *src); + /** * Load an XPM image from a memory array. * @@ -1848,6 +2048,67 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_ReadXPMFromArray(char **xpm); */ extern SDL_DECLSPEC SDL_Surface * SDLCALL IMG_ReadXPMFromArrayToRGB888(char **xpm); +/** + * Save an SDL_Surface into an image file. + * + * If the file already exists, it will be overwritten. + * + * For formats that accept a quality, a default quality of 90 will be used. + * + * \param surface the SDL surface to save. + * \param file path on the filesystem to write new file to. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveTyped_IO + * \sa IMG_SaveAVIF + * \sa IMG_SaveBMP + * \sa IMG_SaveCUR + * \sa IMG_SaveGIF + * \sa IMG_SaveICO + * \sa IMG_SaveJPG + * \sa IMG_SavePNG + * \sa IMG_SaveTGA + * \sa IMG_SaveWEBP + */ +extern SDL_DECLSPEC bool SDLCALL IMG_Save(SDL_Surface *surface, const char *file); + +/** + * Save an SDL_Surface into formatted image data, via an SDL_IOStream. + * + * If you just want to save to a filename, you can use IMG_Save() instead. + * + * If `closeio` is true, `dst` will be closed before returning, whether this + * function succeeds or not. + * + * For formats that accept a quality, a default quality of 90 will be used. + * + * \param surface the SDL surface to save. + * \param dst the SDL_IOStream to save the image data to. + * \param closeio true to close/free the SDL_IOStream before returning, false + * to leave it open. + * \param type a filename extension that represent this data ("BMP", "GIF", + * "PNG", etc). + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_Save + * \sa IMG_SaveAVIF_IO + * \sa IMG_SaveBMP_IO + * \sa IMG_SaveCUR_IO + * \sa IMG_SaveGIF_IO + * \sa IMG_SaveICO_IO + * \sa IMG_SaveJPG_IO + * \sa IMG_SavePNG_IO + * \sa IMG_SaveTGA_IO + * \sa IMG_SaveWEBP_IO + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveTyped_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio, const char *type); + /** * Save an SDL_Surface into a AVIF image file. * @@ -1890,7 +2151,7 @@ extern SDL_DECLSPEC bool SDLCALL IMG_SaveAVIF(SDL_Surface *surface, const char * extern SDL_DECLSPEC bool SDLCALL IMG_SaveAVIF_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio, int quality); /** - * Save an SDL_Surface into a PNG image file. + * Save an SDL_Surface into a BMP image file. * * If the file already exists, it will be overwritten. * @@ -1899,16 +2160,16 @@ extern SDL_DECLSPEC bool SDLCALL IMG_SaveAVIF_IO(SDL_Surface *surface, SDL_IOStr * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \since This function is available since SDL_image 3.0.0. + * \since This function is available since SDL_image 3.4.0. * - * \sa IMG_SavePNG_IO + * \sa IMG_SaveBMP_IO */ -extern SDL_DECLSPEC bool SDLCALL IMG_SavePNG(SDL_Surface *surface, const char *file); +extern SDL_DECLSPEC bool SDLCALL IMG_SaveBMP(SDL_Surface *surface, const char *file); /** - * Save an SDL_Surface into PNG image data, via an SDL_IOStream. + * Save an SDL_Surface into BMP image data, via an SDL_IOStream. * - * If you just want to save to a filename, you can use IMG_SavePNG() instead. + * If you just want to save to a filename, you can use IMG_SaveBMP() instead. * * If `closeio` is true, `dst` will be closed before returning, whether this * function succeeds or not. @@ -1920,11 +2181,122 @@ extern SDL_DECLSPEC bool SDLCALL IMG_SavePNG(SDL_Surface *surface, const char *f * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \since This function is available since SDL_image 3.0.0. + * \since This function is available since SDL_image 3.4.0. * - * \sa IMG_SavePNG + * \sa IMG_SaveBMP */ -extern SDL_DECLSPEC bool SDLCALL IMG_SavePNG_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio); +extern SDL_DECLSPEC bool SDLCALL IMG_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio); + +/** + * Save an SDL_Surface into a CUR image file. + * + * If the file already exists, it will be overwritten. + * + * \param surface the SDL surface to save. + * \param file path on the filesystem to write new file to. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveCUR_IO + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveCUR(SDL_Surface *surface, const char *file); + +/** + * Save an SDL_Surface into CUR image data, via an SDL_IOStream. + * + * If you just want to save to a filename, you can use IMG_SaveCUR() instead. + * + * If `closeio` is true, `dst` will be closed before returning, whether this + * function succeeds or not. + * + * \param surface the SDL surface to save. + * \param dst the SDL_IOStream to save the image data to. + * \param closeio true to close/free the SDL_IOStream before returning, false + * to leave it open. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveCUR + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveCUR_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio); + +/** + * Save an SDL_Surface into a GIF image file. + * + * If the file already exists, it will be overwritten. + * + * \param surface the SDL surface to save. + * \param file path on the filesystem to write new file to. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveGIF_IO + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveGIF(SDL_Surface *surface, const char *file); + +/** + * Save an SDL_Surface into GIF image data, via an SDL_IOStream. + * + * If you just want to save to a filename, you can use IMG_SaveGIF() instead. + * + * If `closeio` is true, `dst` will be closed before returning, whether this + * function succeeds or not. + * + * \param surface the SDL surface to save. + * \param dst the SDL_IOStream to save the image data to. + * \param closeio true to close/free the SDL_IOStream before returning, false + * to leave it open. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveGIF + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveGIF_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio); + +/** + * Save an SDL_Surface into a ICO image file. + * + * If the file already exists, it will be overwritten. + * + * \param surface the SDL surface to save. + * \param file path on the filesystem to write new file to. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveICO_IO + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveICO(SDL_Surface *surface, const char *file); + +/** + * Save an SDL_Surface into ICO image data, via an SDL_IOStream. + * + * If you just want to save to a filename, you can use IMG_SaveICO() instead. + * + * If `closeio` is true, `dst` will be closed before returning, whether this + * function succeeds or not. + * + * \param surface the SDL surface to save. + * \param dst the SDL_IOStream to save the image data to. + * \param closeio true to close/free the SDL_IOStream before returning, false + * to leave it open. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveICO + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveICO_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio); /** * Save an SDL_Surface into a JPEG image file. @@ -1968,16 +2340,134 @@ extern SDL_DECLSPEC bool SDLCALL IMG_SaveJPG(SDL_Surface *surface, const char *f extern SDL_DECLSPEC bool SDLCALL IMG_SaveJPG_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio, int quality); /** - * Animated image support + * Save an SDL_Surface into a PNG image file. * - * Currently only animated GIFs and WEBP images are supported. + * If the file already exists, it will be overwritten. + * + * \param surface the SDL surface to save. + * \param file path on the filesystem to write new file to. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_SavePNG_IO + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SavePNG(SDL_Surface *surface, const char *file); + +/** + * Save an SDL_Surface into PNG image data, via an SDL_IOStream. + * + * If you just want to save to a filename, you can use IMG_SavePNG() instead. + * + * If `closeio` is true, `dst` will be closed before returning, whether this + * function succeeds or not. + * + * \param surface the SDL surface to save. + * \param dst the SDL_IOStream to save the image data to. + * \param closeio true to close/free the SDL_IOStream before returning, false + * to leave it open. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_SavePNG + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SavePNG_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio); + +/** + * Save an SDL_Surface into a TGA image file. + * + * If the file already exists, it will be overwritten. + * + * \param surface the SDL surface to save. + * \param file path on the filesystem to write new file to. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveTGA_IO + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveTGA(SDL_Surface *surface, const char *file); + +/** + * Save an SDL_Surface into TGA image data, via an SDL_IOStream. + * + * If you just want to save to a filename, you can use IMG_SaveTGA() instead. + * + * If `closeio` is true, `dst` will be closed before returning, whether this + * function succeeds or not. + * + * \param surface the SDL surface to save. + * \param dst the SDL_IOStream to save the image data to. + * \param closeio true to close/free the SDL_IOStream before returning, false + * to leave it open. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveTGA + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveTGA_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio); + +/** + * Save an SDL_Surface into a WEBP image file. + * + * If the file already exists, it will be overwritten. + * + * \param surface the SDL surface to save. + * \param file path on the filesystem to write the new file to. + * \param quality between 0 and 100. For lossy, 0 gives the smallest size and + * 100 the largest. For lossless, this parameter is the amount + * of effort put into the compression: 0 is the fastest but + * gives larger files compared to the slowest, but best, 100. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveWEBP_IO + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveWEBP(SDL_Surface *surface, const char *file, float quality); + +/** + * Save an SDL_Surface into WEBP image data, via an SDL_IOStream. + * + * If you just want to save to a filename, you can use IMG_SaveWEBP() instead. + * + * If `closeio` is true, `dst` will be closed before returning, whether this + * function succeeds or not. + * + * \param surface the SDL surface to save. + * \param dst the SDL_IOStream to save the image data to. + * \param closeio true to close/free the SDL_IOStream before returning, false + * to leave it open. + * \param quality between 0 and 100. For lossy, 0 gives the smallest size and + * 100 the largest. For lossless, this parameter is the amount + * of effort put into the compression: 0 is the fastest but + * gives larger files compared to the slowest, but best, 100. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveWEBP + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveWEBP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio, float quality); + +/** + * Animated image support */ typedef struct IMG_Animation { - int w, h; - int count; - SDL_Surface **frames; - int *delays; + int w; /**< The width of the frames */ + int h; /**< The height of the frames */ + int count; /**< The number of frames */ + SDL_Surface **frames; /**< An array of frames */ + int *delays; /**< An array of frame delays, in milliseconds */ } IMG_Animation; /** @@ -1991,6 +2481,14 @@ typedef struct IMG_Animation * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_CreateAnimatedCursor + * \sa IMG_LoadAnimation_IO + * \sa IMG_LoadAnimationTyped_IO + * \sa IMG_LoadANIAnimation_IO + * \sa IMG_LoadAPNGAnimation_IO + * \sa IMG_LoadAVIFAnimation_IO + * \sa IMG_LoadGIFAnimation_IO + * \sa IMG_LoadWEBPAnimation_IO * \sa IMG_FreeAnimation */ extern SDL_DECLSPEC IMG_Animation * SDLCALL IMG_LoadAnimation(const char *file); @@ -2012,12 +2510,20 @@ extern SDL_DECLSPEC IMG_Animation * SDLCALL IMG_LoadAnimation(const char *file); * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_CreateAnimatedCursor + * \sa IMG_LoadAnimation + * \sa IMG_LoadAnimationTyped_IO + * \sa IMG_LoadANIAnimation_IO + * \sa IMG_LoadAPNGAnimation_IO + * \sa IMG_LoadAVIFAnimation_IO + * \sa IMG_LoadGIFAnimation_IO + * \sa IMG_LoadWEBPAnimation_IO * \sa IMG_FreeAnimation */ extern SDL_DECLSPEC IMG_Animation * SDLCALL IMG_LoadAnimation_IO(SDL_IOStream *src, bool closeio); /** - * Load an animation from an SDL datasource + * Load an animation from an SDL_IOStream. * * Even though this function accepts a file type, SDL_image may still try * other decoders that are capable of detecting file type from the contents of @@ -2040,26 +2546,101 @@ extern SDL_DECLSPEC IMG_Animation * SDLCALL IMG_LoadAnimation_IO(SDL_IOStream *s * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_CreateAnimatedCursor * \sa IMG_LoadAnimation * \sa IMG_LoadAnimation_IO + * \sa IMG_LoadANIAnimation_IO + * \sa IMG_LoadAPNGAnimation_IO + * \sa IMG_LoadAVIFAnimation_IO + * \sa IMG_LoadGIFAnimation_IO + * \sa IMG_LoadWEBPAnimation_IO * \sa IMG_FreeAnimation */ extern SDL_DECLSPEC IMG_Animation * SDLCALL IMG_LoadAnimationTyped_IO(SDL_IOStream *src, bool closeio, const char *type); /** - * Dispose of an IMG_Animation and free its resources. + * Load an ANI animation directly from an SDL_IOStream. * - * The provided `anim` pointer is not valid once this call returns. + * If you know you definitely have an ANI image, you can call this function, + * which will skip SDL_image's file format detection routines. Generally, it's + * better to use the abstract interfaces; also, there is only an SDL_IOStream + * interface available here. * - * \param anim IMG_Animation to dispose of. + * When done with the returned animation, the app should dispose of it with a + * call to IMG_FreeAnimation(). * - * \since This function is available since SDL_image 3.0.0. + * \param src an SDL_IOStream from which data will be read. + * \returns a new IMG_Animation, or NULL on error. * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_isANI * \sa IMG_LoadAnimation * \sa IMG_LoadAnimation_IO * \sa IMG_LoadAnimationTyped_IO + * \sa IMG_LoadAPNGAnimation_IO + * \sa IMG_LoadAVIFAnimation_IO + * \sa IMG_LoadGIFAnimation_IO + * \sa IMG_LoadWEBPAnimation_IO + * \sa IMG_FreeAnimation */ -extern SDL_DECLSPEC void SDLCALL IMG_FreeAnimation(IMG_Animation *anim); +extern SDL_DECLSPEC IMG_Animation *SDLCALL IMG_LoadANIAnimation_IO(SDL_IOStream *src); + +/** + * Load an APNG animation directly from an SDL_IOStream. + * + * If you know you definitely have an APNG image, you can call this function, + * which will skip SDL_image's file format detection routines. Generally, it's + * better to use the abstract interfaces; also, there is only an SDL_IOStream + * interface available here. + * + * When done with the returned animation, the app should dispose of it with a + * call to IMG_FreeAnimation(). + * + * \param src an SDL_IOStream from which data will be read. + * \returns a new IMG_Animation, or NULL on error. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_isPNG + * \sa IMG_LoadAnimation + * \sa IMG_LoadAnimation_IO + * \sa IMG_LoadAnimationTyped_IO + * \sa IMG_LoadANIAnimation_IO + * \sa IMG_LoadAVIFAnimation_IO + * \sa IMG_LoadGIFAnimation_IO + * \sa IMG_LoadWEBPAnimation_IO + * \sa IMG_FreeAnimation + */ +extern SDL_DECLSPEC IMG_Animation *SDLCALL IMG_LoadAPNGAnimation_IO(SDL_IOStream *src); + +/** + * Load an AVIF animation directly from an SDL_IOStream. + * + * If you know you definitely have an AVIF animation, you can call this + * function, which will skip SDL_image's file format detection routines. + * Generally it's better to use the abstract interfaces; also, there is only + * an SDL_IOStream interface available here. + * + * When done with the returned animation, the app should dispose of it with a + * call to IMG_FreeAnimation(). + * + * \param src an SDL_IOStream that data will be read from. + * \returns a new IMG_Animation, or NULL on error. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_isAVIF + * \sa IMG_LoadAnimation + * \sa IMG_LoadAnimation_IO + * \sa IMG_LoadAnimationTyped_IO + * \sa IMG_LoadANIAnimation_IO + * \sa IMG_LoadAPNGAnimation_IO + * \sa IMG_LoadGIFAnimation_IO + * \sa IMG_LoadWEBPAnimation_IO + * \sa IMG_FreeAnimation + */ +extern SDL_DECLSPEC IMG_Animation *SDLCALL IMG_LoadAVIFAnimation_IO(SDL_IOStream *src); /** * Load a GIF animation directly. @@ -2074,9 +2655,14 @@ extern SDL_DECLSPEC void SDLCALL IMG_FreeAnimation(IMG_Animation *anim); * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_isGIF * \sa IMG_LoadAnimation * \sa IMG_LoadAnimation_IO * \sa IMG_LoadAnimationTyped_IO + * \sa IMG_LoadANIAnimation_IO + * \sa IMG_LoadAPNGAnimation_IO + * \sa IMG_LoadAVIFAnimation_IO + * \sa IMG_LoadWEBPAnimation_IO * \sa IMG_FreeAnimation */ extern SDL_DECLSPEC IMG_Animation * SDLCALL IMG_LoadGIFAnimation_IO(SDL_IOStream *src); @@ -2094,13 +2680,643 @@ extern SDL_DECLSPEC IMG_Animation * SDLCALL IMG_LoadGIFAnimation_IO(SDL_IOStream * * \since This function is available since SDL_image 3.0.0. * + * \sa IMG_isWEBP * \sa IMG_LoadAnimation * \sa IMG_LoadAnimation_IO * \sa IMG_LoadAnimationTyped_IO + * \sa IMG_LoadANIAnimation_IO + * \sa IMG_LoadAPNGAnimation_IO + * \sa IMG_LoadAVIFAnimation_IO + * \sa IMG_LoadGIFAnimation_IO * \sa IMG_FreeAnimation */ extern SDL_DECLSPEC IMG_Animation * SDLCALL IMG_LoadWEBPAnimation_IO(SDL_IOStream *src); +/** + * Save an animation to a file. + * + * For formats that accept a quality, a default quality of 90 will be used. + * + * \param anim the animation to save. + * \param file path on the filesystem containing an animated image. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveAnimationTyped_IO + * \sa IMG_SaveANIAnimation_IO + * \sa IMG_SaveAPNGAnimation_IO + * \sa IMG_SaveAVIFAnimation_IO + * \sa IMG_SaveGIFAnimation_IO + * \sa IMG_SaveWEBPAnimation_IO + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveAnimation(IMG_Animation *anim, const char *file); + +/** + * Save an animation to an SDL_IOStream. + * + * If you just want to save to a filename, you can use IMG_SaveAnimation() + * instead. + * + * If `closeio` is true, `dst` will be closed before returning, whether this + * function succeeds or not. + * + * For formats that accept a quality, a default quality of 90 will be used. + * + * \param anim the animation to save. + * \param dst an SDL_IOStream that data will be written to. + * \param closeio true to close/free the SDL_IOStream before returning, false + * to leave it open. + * \param type a filename extension that represent this data ("GIF", etc). + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveAnimation + * \sa IMG_SaveANIAnimation_IO + * \sa IMG_SaveAPNGAnimation_IO + * \sa IMG_SaveAVIFAnimation_IO + * \sa IMG_SaveGIFAnimation_IO + * \sa IMG_SaveWEBPAnimation_IO + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveAnimationTyped_IO(IMG_Animation *anim, SDL_IOStream *dst, bool closeio, const char *type); + +/** + * Save an animation in ANI format to an SDL_IOStream. + * + * If `closeio` is true, `dst` will be closed before returning, whether this + * function succeeds or not. + * + * \param anim the animation to save. + * \param dst an SDL_IOStream from which data will be written to. + * \param closeio true to close/free the SDL_IOStream before returning, false + * to leave it open. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveAnimation + * \sa IMG_SaveAnimationTyped_IO + * \sa IMG_SaveAPNGAnimation_IO + * \sa IMG_SaveAVIFAnimation_IO + * \sa IMG_SaveGIFAnimation_IO + * \sa IMG_SaveWEBPAnimation_IO + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveANIAnimation_IO(IMG_Animation *anim, SDL_IOStream *dst, bool closeio); + +/** + * Save an animation in APNG format to an SDL_IOStream. + * + * If `closeio` is true, `dst` will be closed before returning, whether this + * function succeeds or not. + * + * \param anim the animation to save. + * \param dst an SDL_IOStream from which data will be written to. + * \param closeio true to close/free the SDL_IOStream before returning, false + * to leave it open. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveAnimation + * \sa IMG_SaveAnimationTyped_IO + * \sa IMG_SaveANIAnimation_IO + * \sa IMG_SaveAVIFAnimation_IO + * \sa IMG_SaveGIFAnimation_IO + * \sa IMG_SaveWEBPAnimation_IO + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveAPNGAnimation_IO(IMG_Animation *anim, SDL_IOStream *dst, bool closeio); + +/** + * Save an animation in AVIF format to an SDL_IOStream. + * + * If `closeio` is true, `dst` will be closed before returning, whether this + * function succeeds or not. + * + * \param anim the animation to save. + * \param dst an SDL_IOStream from which data will be written to. + * \param closeio true to close/free the SDL_IOStream before returning, false + * to leave it open. + * \param quality the desired quality, ranging between 0 (lowest) and 100 + * (highest). + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveAnimation + * \sa IMG_SaveAnimationTyped_IO + * \sa IMG_SaveANIAnimation_IO + * \sa IMG_SaveAPNGAnimation_IO + * \sa IMG_SaveGIFAnimation_IO + * \sa IMG_SaveWEBPAnimation_IO + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveAVIFAnimation_IO(IMG_Animation *anim, SDL_IOStream *dst, bool closeio, int quality); + +/** + * Save an animation in GIF format to an SDL_IOStream. + * + * If `closeio` is true, `dst` will be closed before returning, whether this + * function succeeds or not. + * + * \param anim the animation to save. + * \param dst an SDL_IOStream from which data will be written to. + * \param closeio true to close/free the SDL_IOStream before returning, false + * to leave it open. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveAnimation + * \sa IMG_SaveAnimationTyped_IO + * \sa IMG_SaveANIAnimation_IO + * \sa IMG_SaveAPNGAnimation_IO + * \sa IMG_SaveAVIFAnimation_IO + * \sa IMG_SaveWEBPAnimation_IO + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveGIFAnimation_IO(IMG_Animation *anim, SDL_IOStream *dst, bool closeio); + +/** + * Save an animation in WEBP format to an SDL_IOStream. + * + * If `closeio` is true, `dst` will be closed before returning, whether this + * function succeeds or not. + * + * \param anim the animation to save. + * \param dst an SDL_IOStream from which data will be written to. + * \param closeio true to close/free the SDL_IOStream before returning, false + * to leave it open. + * \param quality between 0 and 100. For lossy, 0 gives the smallest size and + * 100 the largest. For lossless, this parameter is the amount + * of effort put into the compression: 0 is the fastest but + * gives larger files compared to the slowest, but best, 100. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_SaveAnimation + * \sa IMG_SaveAnimationTyped_IO + * \sa IMG_SaveANIAnimation_IO + * \sa IMG_SaveAPNGAnimation_IO + * \sa IMG_SaveAVIFAnimation_IO + * \sa IMG_SaveGIFAnimation_IO + */ +extern SDL_DECLSPEC bool SDLCALL IMG_SaveWEBPAnimation_IO(IMG_Animation *anim, SDL_IOStream *dst, bool closeio, int quality); + +/** + * Create an animated cursor from an animation. + * + * \param anim an animation to use to create an animated cursor. + * \param hot_x the x position of the cursor hot spot. + * \param hot_y the y position of the cursor hot spot. + * \returns the new cursor on success or NULL on failure; call SDL_GetError() + * for more information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_LoadAnimation + * \sa IMG_LoadAnimation_IO + * \sa IMG_LoadAnimationTyped_IO + */ +extern SDL_DECLSPEC SDL_Cursor * SDLCALL IMG_CreateAnimatedCursor(IMG_Animation *anim, int hot_x, int hot_y); + +/** + * Dispose of an IMG_Animation and free its resources. + * + * The provided `anim` pointer is not valid once this call returns. + * + * \param anim IMG_Animation to dispose of. + * + * \since This function is available since SDL_image 3.0.0. + * + * \sa IMG_LoadAnimation + * \sa IMG_LoadAnimation_IO + * \sa IMG_LoadAnimationTyped_IO + * \sa IMG_LoadANIAnimation_IO + * \sa IMG_LoadAPNGAnimation_IO + * \sa IMG_LoadAVIFAnimation_IO + * \sa IMG_LoadGIFAnimation_IO + * \sa IMG_LoadWEBPAnimation_IO + */ +extern SDL_DECLSPEC void SDLCALL IMG_FreeAnimation(IMG_Animation *anim); + +/** + * An object representing the encoder context. + */ +typedef struct IMG_AnimationEncoder IMG_AnimationEncoder; + +/** + * Create an encoder to save a series of images to a file. + * + * These animation types are currently supported: + * + * - ANI + * - APNG + * - AVIFS + * - GIF + * - WEBP + * + * The file type is determined from the file extension, e.g. "file.webp" will + * be encoded using WEBP. + * + * \param file the file where the animation will be saved. + * \returns a new IMG_AnimationEncoder, or NULL on failure; call + * SDL_GetError() for more information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_CreateAnimationEncoder_IO + * \sa IMG_CreateAnimationEncoderWithProperties + * \sa IMG_AddAnimationEncoderFrame + * \sa IMG_CloseAnimationEncoder + */ +extern SDL_DECLSPEC IMG_AnimationEncoder * SDLCALL IMG_CreateAnimationEncoder(const char *file); + +/** + * Create an encoder to save a series of images to an IOStream. + * + * These animation types are currently supported: + * + * - ANI + * - APNG + * - AVIFS + * - GIF + * - WEBP + * + * If `closeio` is true, `dst` will be closed before returning if this + * function fails, or when the animation encoder is closed if this function + * succeeds. + * + * \param dst an SDL_IOStream that will be used to save the stream. + * \param closeio true to close the SDL_IOStream when done, false to leave it + * open. + * \param type a filename extension that represent this data ("WEBP", etc). + * \returns a new IMG_AnimationEncoder, or NULL on failure; call + * SDL_GetError() for more information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_CreateAnimationEncoder + * \sa IMG_CreateAnimationEncoderWithProperties + * \sa IMG_AddAnimationEncoderFrame + * \sa IMG_CloseAnimationEncoder + */ +extern SDL_DECLSPEC IMG_AnimationEncoder * SDLCALL IMG_CreateAnimationEncoder_IO(SDL_IOStream *dst, bool closeio, const char *type); + +/** + * Create an animation encoder with the specified properties. + * + * These animation types are currently supported: + * + * - ANI + * - APNG + * - AVIFS + * - GIF + * - WEBP + * + * These are the supported properties: + * + * - `IMG_PROP_ANIMATION_ENCODER_CREATE_FILENAME_STRING`: the file to save, if + * an SDL_IOStream isn't being used. This is required if + * `IMG_PROP_ANIMATION_ENCODER_CREATE_IOSTREAM_POINTER` isn't set. + * - `IMG_PROP_ANIMATION_ENCODER_CREATE_IOSTREAM_POINTER`: an SDL_IOStream + * that will be used to save the stream. This should not be closed until the + * animation encoder is closed. This is required if + * `IMG_PROP_ANIMATION_ENCODER_CREATE_FILENAME_STRING` isn't set. + * - `IMG_PROP_ANIMATION_ENCODER_CREATE_IOSTREAM_AUTOCLOSE_BOOLEAN`: true if + * closing the animation encoder should also close the associated + * SDL_IOStream. + * - `IMG_PROP_ANIMATION_ENCODER_CREATE_TYPE_STRING`: the output file type, + * e.g. "webp", defaults to the file extension if + * `IMG_PROP_ANIMATION_ENCODER_CREATE_FILENAME_STRING` is set. + * - `IMG_PROP_ANIMATION_ENCODER_CREATE_QUALITY_NUMBER`: the compression + * quality, in the range of 0 to 100. The higher the number, the higher the + * quality and file size. This defaults to a balanced value for compression + * and quality. + * - `IMG_PROP_ANIMATION_ENCODER_CREATE_TIMEBASE_NUMERATOR_NUMBER`: the + * numerator of the fraction used to multiply the pts to convert it to + * seconds. This defaults to 1. + * - `IMG_PROP_ANIMATION_ENCODER_CREATE_TIMEBASE_DENOMINATOR_NUMBER`: the + * denominator of the fraction used to multiply the pts to convert it to + * seconds. This defaults to 1000. + * + * \param props the properties of the animation encoder. + * \returns a new IMG_AnimationEncoder, or NULL on failure; call + * SDL_GetError() for more information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_CreateAnimationEncoder + * \sa IMG_CreateAnimationEncoder_IO + * \sa IMG_AddAnimationEncoderFrame + * \sa IMG_CloseAnimationEncoder + */ +extern SDL_DECLSPEC IMG_AnimationEncoder * SDLCALL IMG_CreateAnimationEncoderWithProperties(SDL_PropertiesID props); + +#define IMG_PROP_ANIMATION_ENCODER_CREATE_FILENAME_STRING "SDL_image.animation_encoder.create.filename" +#define IMG_PROP_ANIMATION_ENCODER_CREATE_IOSTREAM_POINTER "SDL_image.animation_encoder.create.iostream" +#define IMG_PROP_ANIMATION_ENCODER_CREATE_IOSTREAM_AUTOCLOSE_BOOLEAN "SDL_image.animation_encoder.create.iostream.autoclose" +#define IMG_PROP_ANIMATION_ENCODER_CREATE_TYPE_STRING "SDL_image.animation_encoder.create.type" +#define IMG_PROP_ANIMATION_ENCODER_CREATE_QUALITY_NUMBER "SDL_image.animation_encoder.create.quality" +#define IMG_PROP_ANIMATION_ENCODER_CREATE_TIMEBASE_NUMERATOR_NUMBER "SDL_image.animation_encoder.create.timebase.numerator" +#define IMG_PROP_ANIMATION_ENCODER_CREATE_TIMEBASE_DENOMINATOR_NUMBER "SDL_image.animation_encoder.create.timebase.denominator" + +#define IMG_PROP_ANIMATION_ENCODER_CREATE_AVIF_MAX_THREADS_NUMBER "SDL_image.animation_encoder.create.avif.max_threads" +#define IMG_PROP_ANIMATION_ENCODER_CREATE_AVIF_KEYFRAME_INTERVAL_NUMBER "SDL_image.animation_encoder.create.avif.keyframe_interval" +#define IMG_PROP_ANIMATION_ENCODER_CREATE_GIF_USE_LUT_BOOLEAN "SDL_image.animation_encoder.create.gif.use_lut" + +/** + * Add a frame to an animation encoder. + * + * \param encoder the receiving images. + * \param surface the surface to add as the next frame in the animation. + * \param duration the duration of the frame, usually in milliseconds but can + * be other units if the + * `IMG_PROP_ANIMATION_ENCODER_CREATE_TIMEBASE_DENOMINATOR_NUMBER` + * property is set when creating the encoder. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_CreateAnimationEncoder + * \sa IMG_CreateAnimationEncoder_IO + * \sa IMG_CreateAnimationEncoderWithProperties + * \sa IMG_CloseAnimationEncoder + */ +extern SDL_DECLSPEC bool SDLCALL IMG_AddAnimationEncoderFrame(IMG_AnimationEncoder *encoder, SDL_Surface *surface, Uint64 duration); + +/** + * Close an animation encoder, finishing any encoding. + * + * Calling this function frees the animation encoder, and returns the final + * status of the encoding process. + * + * \param encoder the encoder to close. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_CreateAnimationEncoder + * \sa IMG_CreateAnimationEncoder_IO + * \sa IMG_CreateAnimationEncoderWithProperties + */ +extern SDL_DECLSPEC bool SDLCALL IMG_CloseAnimationEncoder(IMG_AnimationEncoder *encoder); + +/** + * An enum representing the status of an animation decoder. + * + * \since This enum is available since SDL_image 3.4.0. + */ +typedef enum IMG_AnimationDecoderStatus +{ + IMG_DECODER_STATUS_INVALID = -1, /**< The decoder is invalid */ + IMG_DECODER_STATUS_OK, /**< The decoder is ready to decode the next frame */ + IMG_DECODER_STATUS_FAILED, /**< The decoder failed to decode a frame, call SDL_GetError() for more information. */ + IMG_DECODER_STATUS_COMPLETE /**< No more frames available */ +} IMG_AnimationDecoderStatus; + +/** + * An object representing animation decoder. + */ +typedef struct IMG_AnimationDecoder IMG_AnimationDecoder; + +/** + * Create a decoder to read a series of images from a file. + * + * These animation types are currently supported: + * + * - ANI + * - APNG + * - AVIFS + * - GIF + * - WEBP + * + * The file type is determined from the file extension, e.g. "file.webp" will + * be decoded using WEBP. + * + * \param file the file containing a series of images. + * \returns a new IMG_AnimationDecoder, or NULL on failure; call + * SDL_GetError() for more information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_CreateAnimationDecoder_IO + * \sa IMG_CreateAnimationDecoderWithProperties + * \sa IMG_GetAnimationDecoderFrame + * \sa IMG_ResetAnimationDecoder + * \sa IMG_CloseAnimationDecoder + */ +extern SDL_DECLSPEC IMG_AnimationDecoder * SDLCALL IMG_CreateAnimationDecoder(const char *file); + +/** + * Create a decoder to read a series of images from an IOStream. + * + * These animation types are currently supported: + * + * - ANI + * - APNG + * - AVIFS + * - GIF + * - WEBP + * + * If `closeio` is true, `src` will be closed before returning if this + * function fails, or when the animation decoder is closed if this function + * succeeds. + * + * \param src an SDL_IOStream containing a series of images. + * \param closeio true to close the SDL_IOStream when done, false to leave it + * open. + * \param type a filename extension that represent this data ("WEBP", etc). + * \returns a new IMG_AnimationDecoder, or NULL on failure; call + * SDL_GetError() for more information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_CreateAnimationDecoder + * \sa IMG_CreateAnimationDecoderWithProperties + * \sa IMG_GetAnimationDecoderFrame + * \sa IMG_ResetAnimationDecoder + * \sa IMG_CloseAnimationDecoder + */ +extern SDL_DECLSPEC IMG_AnimationDecoder * SDLCALL IMG_CreateAnimationDecoder_IO(SDL_IOStream *src, bool closeio, const char *type); + +/** + * Create an animation decoder with the specified properties. + * + * These animation types are currently supported: + * + * - ANI + * - APNG + * - AVIFS + * - GIF + * - WEBP + * + * These are the supported properties: + * + * - `IMG_PROP_ANIMATION_DECODER_CREATE_FILENAME_STRING`: the file to load, if + * an SDL_IOStream isn't being used. This is required if + * `IMG_PROP_ANIMATION_DECODER_CREATE_IOSTREAM_POINTER` isn't set. + * - `IMG_PROP_ANIMATION_DECODER_CREATE_IOSTREAM_POINTER`: an SDL_IOStream + * containing a series of images. This should not be closed until the + * animation decoder is closed. This is required if + * `IMG_PROP_ANIMATION_DECODER_CREATE_FILENAME_STRING` isn't set. + * - `IMG_PROP_ANIMATION_DECODER_CREATE_IOSTREAM_AUTOCLOSE_BOOLEAN`: true if + * closing the animation decoder should also close the associated + * SDL_IOStream. + * - `IMG_PROP_ANIMATION_DECODER_CREATE_TYPE_STRING`: the input file type, + * e.g. "webp", defaults to the file extension if + * `IMG_PROP_ANIMATION_DECODER_CREATE_FILENAME_STRING` is set. + * + * \param props the properties of the animation decoder. + * \returns a new IMG_AnimationDecoder, or NULL on failure; call + * SDL_GetError() for more information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_CreateAnimationDecoder + * \sa IMG_CreateAnimationDecoder_IO + * \sa IMG_GetAnimationDecoderFrame + * \sa IMG_ResetAnimationDecoder + * \sa IMG_CloseAnimationDecoder + */ +extern SDL_DECLSPEC IMG_AnimationDecoder * SDLCALL IMG_CreateAnimationDecoderWithProperties(SDL_PropertiesID props); + +#define IMG_PROP_ANIMATION_DECODER_CREATE_FILENAME_STRING "SDL_image.animation_decoder.create.filename" +#define IMG_PROP_ANIMATION_DECODER_CREATE_IOSTREAM_POINTER "SDL_image.animation_decoder.create.iostream" +#define IMG_PROP_ANIMATION_DECODER_CREATE_IOSTREAM_AUTOCLOSE_BOOLEAN "SDL_image.animation_decoder.create.iostream.autoclose" +#define IMG_PROP_ANIMATION_DECODER_CREATE_TYPE_STRING "SDL_image.animation_decoder.create.type" +#define IMG_PROP_ANIMATION_DECODER_CREATE_TIMEBASE_NUMERATOR_NUMBER "SDL_image.animation_decoder.create.timebase.numerator" +#define IMG_PROP_ANIMATION_DECODER_CREATE_TIMEBASE_DENOMINATOR_NUMBER "SDL_image.animation_decoder.create.timebase.denominator" + +#define IMG_PROP_ANIMATION_DECODER_CREATE_AVIF_MAX_THREADS_NUMBER "SDL_image.animation_decoder.create.avif.max_threads" +#define IMG_PROP_ANIMATION_DECODER_CREATE_AVIF_ALLOW_INCREMENTAL_BOOLEAN "SDL_image.animation_decoder.create.avif.allow_incremental" +#define IMG_PROP_ANIMATION_DECODER_CREATE_AVIF_ALLOW_PROGRESSIVE_BOOLEAN "SDL_image.animation_decoder.create.avif.allow_progressive" +#define IMG_PROP_ANIMATION_DECODER_CREATE_GIF_TRANSPARENT_COLOR_INDEX_NUMBER "SDL_image.animation_encoder.create.gif.transparent_color_index" +#define IMG_PROP_ANIMATION_DECODER_CREATE_GIF_NUM_COLORS_NUMBER "SDL_image.animation_encoder.create.gif.num_colors" + +/** + * Get the properties of an animation decoder. + * + * This function returns the properties of the animation decoder, which holds + * information about the underlying image such as description, copyright text + * and loop count. + * + * \param decoder the animation decoder. + * \returns the properties ID of the animation decoder, or 0 if there are no + * properties; call SDL_GetError() for more information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_CreateAnimationDecoder + * \sa IMG_CreateAnimationDecoder_IO + * \sa IMG_CreateAnimationDecoderWithProperties + */ +extern SDL_DECLSPEC SDL_PropertiesID SDLCALL IMG_GetAnimationDecoderProperties(IMG_AnimationDecoder* decoder); + +#define IMG_PROP_METADATA_IGNORE_PROPS_BOOLEAN "SDL_image.metadata.ignore_props" +#define IMG_PROP_METADATA_DESCRIPTION_STRING "SDL_image.metadata.description" +#define IMG_PROP_METADATA_COPYRIGHT_STRING "SDL_image.metadata.copyright" +#define IMG_PROP_METADATA_TITLE_STRING "SDL_image.metadata.title" +#define IMG_PROP_METADATA_AUTHOR_STRING "SDL_image.metadata.author" +#define IMG_PROP_METADATA_CREATION_TIME_STRING "SDL_image.metadata.creation_time" +#define IMG_PROP_METADATA_FRAME_COUNT_NUMBER "SDL_image.metadata.frame_count" +#define IMG_PROP_METADATA_LOOP_COUNT_NUMBER "SDL_image.metadata.loop_count" + +/** + * Get the next frame in an animation decoder. + * + * This function decodes the next frame in the animation decoder, returning it + * as an SDL_Surface. The returned surface should be freed with + * SDL_FreeSurface() when no longer needed. + * + * If the animation decoder has no more frames or an error occurred while + * decoding the frame, this function returns false. In that case, please call + * SDL_GetError() for more information. If SDL_GetError() returns an empty + * string, that means there are no more available frames. If SDL_GetError() + * returns a valid string, that means the decoding failed. + * + * \param decoder the animation decoder. + * \param frame a pointer filled in with the SDL_Surface for the next frame in + * the animation. + * \param duration the duration of the frame, usually in milliseconds but can + * be other units if the + * `IMG_PROP_ANIMATION_DECODER_CREATE_TIMEBASE_DENOMINATOR_NUMBER` + * property is set when creating the decoder. + * \returns true on success or false on failure and when no more frames are + * available; call IMG_GetAnimationDecoderStatus() or SDL_GetError() + * for more information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_CreateAnimationDecoder + * \sa IMG_CreateAnimationDecoder_IO + * \sa IMG_CreateAnimationDecoderWithProperties + * \sa IMG_GetAnimationDecoderStatus + * \sa IMG_ResetAnimationDecoder + * \sa IMG_CloseAnimationDecoder + */ +extern SDL_DECLSPEC bool SDLCALL IMG_GetAnimationDecoderFrame(IMG_AnimationDecoder *decoder, SDL_Surface **frame, Uint64 *duration); + +/** + * Get the decoder status indicating the current state of the decoder. + * + * \param decoder the decoder to get the status of. + * \returns the status of the underlying decoder, or + * IMG_DECODER_STATUS_INVALID if the given decoder is invalid. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_GetAnimationDecoderFrame + */ +extern SDL_DECLSPEC IMG_AnimationDecoderStatus SDLCALL IMG_GetAnimationDecoderStatus(IMG_AnimationDecoder *decoder); + +/** + * Reset an animation decoder. + * + * Calling this function resets the animation decoder, allowing it to start + * from the beginning again. This is useful if you want to decode the frame + * sequence again without creating a new decoder. + * + * \param decoder the decoder to reset. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_CreateAnimationDecoder + * \sa IMG_CreateAnimationDecoder_IO + * \sa IMG_CreateAnimationDecoderWithProperties + * \sa IMG_GetAnimationDecoderFrame + * \sa IMG_CloseAnimationDecoder + */ +extern SDL_DECLSPEC bool SDLCALL IMG_ResetAnimationDecoder(IMG_AnimationDecoder *decoder); + +/** + * Close an animation decoder, finishing any decoding. + * + * Calling this function frees the animation decoder, and returns the final + * status of the decoding process. + * + * \param decoder the decoder to close. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_image 3.4.0. + * + * \sa IMG_CreateAnimationDecoder + * \sa IMG_CreateAnimationDecoder_IO + * \sa IMG_CreateAnimationDecoderWithProperties + */ +extern SDL_DECLSPEC bool SDLCALL IMG_CloseAnimationDecoder(IMG_AnimationDecoder *decoder); + /* Ends C function definitions when using C++ */ #ifdef __cplusplus } diff --git a/vendor/sdl3/image/libavif-16.dll b/vendor/sdl3/image/libavif-16.dll index 7fef6232a..eb235450f 100644 Binary files a/vendor/sdl3/image/libavif-16.dll and b/vendor/sdl3/image/libavif-16.dll differ diff --git a/vendor/sdl3/image/libpng16-16.dll b/vendor/sdl3/image/libpng16-16.dll new file mode 100644 index 000000000..ea1e35e61 Binary files /dev/null and b/vendor/sdl3/image/libpng16-16.dll differ diff --git a/vendor/sdl3/image/libtiff-6.dll b/vendor/sdl3/image/libtiff-6.dll index 645e446b8..0dcf40a01 100644 Binary files a/vendor/sdl3/image/libtiff-6.dll and b/vendor/sdl3/image/libtiff-6.dll differ diff --git a/vendor/sdl3/image/libwebpmux-3.dll b/vendor/sdl3/image/libwebpmux-3.dll new file mode 100644 index 000000000..4294a2394 Binary files /dev/null and b/vendor/sdl3/image/libwebpmux-3.dll differ diff --git a/vendor/sdl3/image/sdl_image.odin b/vendor/sdl3/image/sdl_image.odin index 098d21de7..820a7c4da 100644 --- a/vendor/sdl3/image/sdl_image.odin +++ b/vendor/sdl3/image/sdl_image.odin @@ -11,8 +11,8 @@ when ODIN_OS == .Windows { } MAJOR_VERSION :: 3 -MINOR_VERSION :: 2 -PATCHLEVEL :: 4 +MINOR_VERSION :: 4 +PATCHLEVEL :: 0 Animation :: struct { w, h: c.int, @@ -21,6 +21,51 @@ Animation :: struct { delays: [^]c.int, } +AnimationEncoder :: struct {} + +PROP_ANIMATION_ENCODER_CREATE_FILENAME_STRING :: "SDL_image.animation_encoder.create.filename" +PROP_ANIMATION_ENCODER_CREATE_IOSTREAM_POINTER :: "SDL_image.animation_encoder.create.iostream" +PROP_ANIMATION_ENCODER_CREATE_IOSTREAM_AUTOCLOSE_BOOLEAN :: "SDL_image.animation_encoder.create.iostream.autoclose" +PROP_ANIMATION_ENCODER_CREATE_TYPE_STRING :: "SDL_image.animation_encoder.create.type" +PROP_ANIMATION_ENCODER_CREATE_QUALITY_NUMBER :: "SDL_image.animation_encoder.create.quality" +PROP_ANIMATION_ENCODER_CREATE_TIMEBASE_NUMERATOR_NUMBER :: "SDL_image.animation_encoder.create.timebase.numerator" +PROP_ANIMATION_ENCODER_CREATE_TIMEBASE_DENOMINATOR_NUMBER :: "SDL_image.animation_encoder.create.timebase.denominator" + +PROP_ANIMATION_ENCODER_CREATE_AVIF_MAX_THREADS_NUMBER :: "SDL_image.animation_encoder.create.avif.max_threads" +PROP_ANIMATION_ENCODER_CREATE_AVIF_KEYFRAME_INTERVAL_NUMBER :: "SDL_image.animation_encoder.create.avif.keyframe_interval" +PROP_ANIMATION_ENCODER_CREATE_GIF_USE_LUT_BOOLEAN :: "SDL_image.animation_encoder.create.gif.use_lut" + +AnimationDecoderStatus :: enum c.int { + INVALID = -1, + OK, + FAILED, + COMPLETE, +} + +AnimationDecoder :: struct {} + +PROP_ANIMATION_DECODER_CREATE_FILENAME_STRING :: "SDL_image.animation_decoder.create.filename" +PROP_ANIMATION_DECODER_CREATE_IOSTREAM_POINTER :: "SDL_image.animation_decoder.create.iostream" +PROP_ANIMATION_DECODER_CREATE_IOSTREAM_AUTOCLOSE_BOOLEAN :: "SDL_image.animation_decoder.create.iostream.autoclose" +PROP_ANIMATION_DECODER_CREATE_TYPE_STRING :: "SDL_image.animation_decoder.create.type" +PROP_ANIMATION_DECODER_CREATE_TIMEBASE_NUMERATOR_NUMBER :: "SDL_image.animation_decoder.create.timebase.numerator" +PROP_ANIMATION_DECODER_CREATE_TIMEBASE_DENOMINATOR_NUMBER :: "SDL_image.animation_decoder.create.timebase.denominator" + +PROP_ANIMATION_DECODER_CREATE_AVIF_MAX_THREADS_NUMBER :: "SDL_image.animation_decoder.create.avif.max_threads" +PROP_ANIMATION_DECODER_CREATE_AVIF_ALLOW_INCREMENTAL_BOOLEAN :: "SDL_image.animation_decoder.create.avif.allow_incremental" +PROP_ANIMATION_DECODER_CREATE_AVIF_ALLOW_PROGRESSIVE_BOOLEAN :: "SDL_image.animation_decoder.create.avif.allow_progressive" +PROP_ANIMATION_DECODER_CREATE_GIF_TRANSPARENT_COLOR_INDEX_NUMBER :: "SDL_image.animation_encoder.create.gif.transparent_color_index" +PROP_ANIMATION_DECODER_CREATE_GIF_NUM_COLORS_NUMBER :: "SDL_image.animation_encoder.create.gif.num_colors" + +PROP_METADATA_IGNORE_PROPS_BOOLEAN :: "SDL_image.metadata.ignore_props" +PROP_METADATA_DESCRIPTION_STRING :: "SDL_image.metadata.description" +PROP_METADATA_COPYRIGHT_STRING :: "SDL_image.metadata.copyright" +PROP_METADATA_TITLE_STRING :: "SDL_image.metadata.title" +PROP_METADATA_AUTHOR_STRING :: "SDL_image.metadata.author" +PROP_METADATA_CREATION_TIME_STRING :: "SDL_image.metadata.creation_time" +PROP_METADATA_FRAME_COUNT_NUMBER :: "SDL_image.metadata.frame_count" +PROP_METADATA_LOOP_COUNT_NUMBER :: "SDL_image.metadata.loop_count" + @(default_calling_convention="c", link_prefix="IMG_") foreign lib { Version :: proc() -> c.int --- @@ -43,7 +88,16 @@ foreign lib { LoadTexture_IO :: proc(renderer: ^SDL.Renderer, src: ^SDL.IOStream, closeio: bool) -> ^SDL.Texture --- LoadTextureTyped_IO :: proc(renderer: ^SDL.Renderer, src: ^SDL.IOStream, closeio: bool, type: cstring) -> ^SDL.Texture --- + /* Load an image directly into a GPU texture. */ + LoadGPUTexture :: proc(device: ^SDL.GPUDevice, copy_pass: ^SDL.GPUCopyPass, file: cstring, width: ^c.int, height: ^c.int) -> ^SDL.GPUTexture --- + LoadGPUTexture_IO :: proc(device: ^SDL.GPUDevice, copy_pass: ^SDL.GPUCopyPass, src: ^SDL.IOStream, closeio: bool, width: ^c.int, height: ^c.int) -> ^SDL.GPUTexture --- + LoadGPUTextureTyped_IO :: proc(device: ^SDL.GPUDevice, copy_pass: ^SDL.GPUCopyPass, src: ^SDL.IOStream, closeio: bool, type: cstring, width: ^c.int, height: ^c.int) -> ^SDL.GPUTexture --- + + /* Get the image currently in the clipboard. */ + GetClipboardImage :: proc() -> ^SDL.Surface --- + /* Functions to detect a file type, given a seekable source */ + isANI :: proc(src: ^SDL.IOStream) -> bool --- isAVIF :: proc(src: ^SDL.IOStream) -> bool --- isICO :: proc(src: ^SDL.IOStream) -> bool --- isCUR :: proc(src: ^SDL.IOStream) -> bool --- @@ -90,19 +144,63 @@ foreign lib { ReadXPMFromArrayToRGB888 :: proc(xpm: [^]cstring) -> ^SDL.Surface --- /* Individual saving functions */ - SaveAVIF :: proc(surface: ^SDL.Surface, file: cstring, quality: c.int) -> c.bool --- - SaveAVIF_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool, quality: c.int) -> c.bool --- - SavePNG :: proc(surface: ^SDL.Surface, file: cstring) -> c.bool --- - SavePNG_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool) -> c.bool --- - SaveJPG :: proc(surface: ^SDL.Surface, file: cstring, quality: c.int) -> c.bool --- - SaveJPG_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool, quality: c.int) -> c.bool --- + Save :: proc(surface: ^SDL.Surface, file: cstring) -> c.bool --- + SaveTyped_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool, type: cstring) -> c.bool --- + SaveAVIF :: proc(surface: ^SDL.Surface, file: cstring, quality: c.int) -> c.bool --- + SaveAVIF_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool, quality: c.int) -> c.bool --- + SaveBMP :: proc(surface: ^SDL.Surface, file: cstring) -> c.bool --- + SaveBMP_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool) -> c.bool --- + SaveCUR :: proc(surface: ^SDL.Surface, file: cstring) -> c.bool --- + SaveCUR_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool) -> c.bool --- + SaveGIF :: proc(surface: ^SDL.Surface, file: cstring) -> c.bool --- + SaveGIF_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool) -> c.bool --- + SaveICO :: proc(surface: ^SDL.Surface, file: cstring) -> c.bool --- + SaveICO_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool) -> c.bool --- + SaveJPG :: proc(surface: ^SDL.Surface, file: cstring, quality: c.int) -> c.bool --- + SaveJPG_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool, quality: c.int) -> c.bool --- + SavePNG :: proc(surface: ^SDL.Surface, file: cstring) -> c.bool --- + SavePNG_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool) -> c.bool --- + SaveTGA :: proc(surface: ^SDL.Surface, file: cstring) -> c.bool --- + SaveTGA_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool) -> c.bool --- + SaveWEBP :: proc(surface: ^SDL.Surface, file: cstring, quality: f32) -> c.bool --- + SaveWEBP_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool, quality: f32) -> c.bool --- LoadAnimation :: proc(file: cstring) -> ^Animation --- LoadAnimation_IO :: proc(src: ^SDL.IOStream, closeio: bool) -> ^Animation --- LoadAnimationTyped_IO :: proc(src: ^SDL.IOStream, closeio: bool, type: cstring) -> ^Animation --- + SaveAnimation :: proc(anim: ^Animation, file: cstring) -> c.bool --- + SaveAnimationTyped_IO :: proc(anim: ^Animation, dst: ^SDL.IOStream, closeio: bool, type: cstring) -> c.bool --- + CreateAnimatedCursor :: proc(anim: ^Animation, hot_x: c.int, hot_y: c.int) -> ^SDL.Cursor --- FreeAnimation :: proc(anim: ^Animation) --- + /* Animation encoder functions */ + CreateAnimationEncoder :: proc(file: cstring) -> ^AnimationEncoder --- + CreateAnimationEncoder_IO :: proc(dst: ^SDL.IOStream, closeio: bool, type: cstring) -> ^AnimationEncoder --- + CreateAnimationEncoderWithProperties :: proc(props: SDL.PropertiesID) -> ^AnimationEncoder --- + AddAnimationEncoderFrame :: proc(encoder: ^AnimationEncoder, surface: ^SDL.Surface, duration: u64) -> c.bool --- + CloseAnimationEncoder :: proc(encoder: ^AnimationEncoder) -> c.bool --- + + /* Animation decoder functions */ + CreateAnimationDecoder :: proc(file: cstring) -> ^AnimationDecoder --- + CreateAnimationDecoder_IO :: proc(src: ^SDL.IOStream, closeio: bool, type: cstring) -> ^AnimationDecoder --- + CreateAnimationDecoderWithProperties :: proc(props: SDL.PropertiesID) -> ^AnimationDecoder --- + GetAnimationDecoderProperties :: proc(decoder: ^AnimationDecoder) -> SDL.PropertiesID --- + GetAnimationDecoderFrame :: proc(decoder: ^AnimationDecoder, frame: ^^SDL.Surface, duration: ^u64) -> c.bool --- + GetAnimationDecoderStatus :: proc(decoder: ^AnimationDecoder) -> AnimationDecoderStatus --- + ResetAnimationDecoder :: proc(decoder: ^AnimationDecoder) -> c.bool --- + CloseAnimationDecoder :: proc(decoder: ^AnimationDecoder) -> c.bool --- + /* Individual loading functions */ + LoadANIAnimation_IO :: proc(src: ^SDL.IOStream) -> ^Animation --- + LoadAPNGAnimation_IO :: proc(src: ^SDL.IOStream) -> ^Animation --- + LoadAVIFAnimation_IO :: proc(src: ^SDL.IOStream) -> ^Animation --- LoadGIFAnimation_IO :: proc(src: ^SDL.IOStream) -> ^Animation --- LoadWEBPAnimation_IO :: proc(src: ^SDL.IOStream) -> ^Animation --- + + /* Individual saving functions */ + SaveANIAnimation_IO :: proc(anim: ^Animation, dst: ^SDL.IOStream, closeio: bool) -> c.bool --- + SaveAPNGAnimation_IO :: proc(anim: ^Animation, dst: ^SDL.IOStream, closeio: bool) -> c.bool --- + SaveAVIFAnimation_IO :: proc(anim: ^Animation, dst: ^SDL.IOStream, closeio: bool, quality: c.int) -> c.bool --- + SaveGIFAnimation_IO :: proc(anim: ^Animation, dst: ^SDL.IOStream, closeio: bool) -> c.bool --- + SaveWEBPAnimation_IO :: proc(anim: ^Animation, dst: ^SDL.IOStream, closeio: bool, quality: c.int) -> c.bool --- } diff --git a/vendor/sdl3/include/SDL.h b/vendor/sdl3/include/SDL.h index ed1b32483..fd13b8340 100644 --- a/vendor/sdl3/include/SDL.h +++ b/vendor/sdl3/include/SDL.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -20,7 +20,7 @@ */ /** - * Main include header for the SDL library, version 3.2.16 + * Main include header for the SDL library, version 3.4.2 * * It is almost always best to include just this one header instead of * picking out individual headers included here. There are exceptions to @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include diff --git a/vendor/sdl3/include/SDL_assert.h b/vendor/sdl3/include/SDL_assert.h index 6c90acc02..fb6746235 100644 --- a/vendor/sdl3/include/SDL_assert.h +++ b/vendor/sdl3/include/SDL_assert.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -126,20 +126,17 @@ extern "C" { */ #define SDL_TriggerBreakpoint() TriggerABreakpointInAPlatformSpecificManner -#elif defined(_MSC_VER) && _MSC_VER >= 1310 +#elif defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER >= 1310) /* Don't include intrin.h here because it contains C++ code */ extern void __cdecl __debugbreak(void); #define SDL_TriggerBreakpoint() __debugbreak() #elif defined(_MSC_VER) && defined(_M_IX86) #define SDL_TriggerBreakpoint() { _asm { int 0x03 } } -#elif defined(ANDROID) - #include - #define SDL_TriggerBreakpoint() assert(0) #elif SDL_HAS_BUILTIN(__builtin_debugtrap) #define SDL_TriggerBreakpoint() __builtin_debugtrap() #elif SDL_HAS_BUILTIN(__builtin_trap) #define SDL_TriggerBreakpoint() __builtin_trap() -#elif (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) +#elif (defined(__GNUC__) || defined(__clang__) || defined(__TINYC__) || defined(__slimcc__)) && (defined(__i386__) || defined(__x86_64__)) #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" ) #elif (defined(__GNUC__) || defined(__clang__)) && defined(__riscv) #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "ebreak\n\t" ) @@ -163,7 +160,7 @@ extern "C" { #ifdef SDL_WIKI_DOCUMENTATION_SECTION /** - * A macro that reports the current function being compiled. + * A constant that contains the current function being compiled. * * If SDL can't figure how the compiler reports this, it will use "???". * @@ -171,20 +168,58 @@ extern "C" { */ #define SDL_FUNCTION __FUNCTION__ -#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 supports __func__ as a standard. */ +#elif !defined(SDL_FUNCTION) +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 supports __func__ as a standard. */ # define SDL_FUNCTION __func__ #elif ((defined(__GNUC__) && (__GNUC__ >= 2)) || defined(_MSC_VER) || defined (__WATCOMC__)) # define SDL_FUNCTION __FUNCTION__ #else # define SDL_FUNCTION "???" #endif +#endif + +#ifdef SDL_WIKI_DOCUMENTATION_SECTION /** * A macro that reports the current file being compiled. * + * This macro is only defined if it isn't already defined, so to override it + * (perhaps with something that doesn't provide path information at all, so + * build machine information doesn't leak into public binaries), apps can + * define this macro before including SDL.h or SDL_assert.h. + * * \since This macro is available since SDL 3.2.0. */ +#define SDL_FILE __FILE_NAME__ + +#elif !defined(SDL_FILE) +#ifdef __FILE_NAME__ +#define SDL_FILE __FILE_NAME__ +#else #define SDL_FILE __FILE__ +#endif +#endif + +#ifdef SDL_WIKI_DOCUMENTATION_SECTION + +/** + * A macro that reports the current file being compiled, for use in + * assertions. + * + * This macro is only defined if it isn't already defined, so to override it + * (perhaps with something that doesn't provide path information at all, so + * build machine information doesn't leak into public binaries), apps can + * define this macro before including SDL_assert.h. For example, defining this + * to `""` will make sure no source path information is included in asserts. + * + * \since This macro is available since SDL 3.4.0. + */ +#define SDL_ASSERT_FILE SDL_FILE + +#elif !defined(SDL_ASSERT_FILE) +#define SDL_ASSERT_FILE SDL_FILE +#endif + /** * A macro that reports the current line number of the file being compiled. @@ -362,8 +397,8 @@ extern SDL_DECLSPEC SDL_AssertState SDLCALL SDL_ReportAssertion(SDL_AssertData * #define SDL_enabled_assert(condition) \ do { \ while ( !(condition) ) { \ - static struct SDL_AssertData sdl_assert_data = { 0, 0, #condition, 0, 0, 0, 0 }; \ - const SDL_AssertState sdl_assert_state = SDL_ReportAssertion(&sdl_assert_data, SDL_FUNCTION, SDL_FILE, SDL_LINE); \ + static struct SDL_AssertData sdl_assert_data = { false, 0, #condition, NULL, 0, NULL, NULL }; \ + const SDL_AssertState sdl_assert_state = SDL_ReportAssertion(&sdl_assert_data, SDL_FUNCTION, SDL_ASSERT_FILE, SDL_LINE); \ if (sdl_assert_state == SDL_ASSERTION_RETRY) { \ continue; /* go again. */ \ } else if (sdl_assert_state == SDL_ASSERTION_BREAK) { \ diff --git a/vendor/sdl3/include/SDL_asyncio.h b/vendor/sdl3/include/SDL_asyncio.h index b36cb071b..3c894d696 100644 --- a/vendor/sdl3/include/SDL_asyncio.h +++ b/vendor/sdl3/include/SDL_asyncio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -213,6 +213,8 @@ typedef struct SDL_AsyncIOQueue SDL_AsyncIOQueue; * \returns a pointer to the SDL_AsyncIO structure that is created or NULL on * failure; call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_CloseAsyncIO @@ -531,6 +533,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_SignalAsyncIOQueue(SDL_AsyncIOQueue *queue) * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_LoadFile_IO diff --git a/vendor/sdl3/include/SDL_atomic.h b/vendor/sdl3/include/SDL_atomic.h index 78b5e0fa5..1ec0753da 100644 --- a/vendor/sdl3/include/SDL_atomic.h +++ b/vendor/sdl3/include/SDL_atomic.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -596,6 +596,24 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_SetAtomicU32(SDL_AtomicU32 *a, Uint32 v); */ extern SDL_DECLSPEC Uint32 SDLCALL SDL_GetAtomicU32(SDL_AtomicU32 *a); +/** + * Add to an atomic variable. + * + * This function also acts as a full memory barrier. + * + * ***Note: If you don't know what this function is for, you shouldn't use + * it!*** + * + * \param a a pointer to an SDL_AtomicU32 variable to be modified. + * \param v the desired value to add or subtract. + * \returns the previous value of the atomic variable. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC Uint32 SDLCALL SDL_AddAtomicU32(SDL_AtomicU32 *a, int v); + /** * Set a pointer to a new value if it is currently an old value. * diff --git a/vendor/sdl3/include/SDL_audio.h b/vendor/sdl3/include/SDL_audio.h index c6acf885f..da797c6a8 100644 --- a/vendor/sdl3/include/SDL_audio.h +++ b/vendor/sdl3/include/SDL_audio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -577,6 +577,15 @@ extern SDL_DECLSPEC SDL_AudioDeviceID * SDLCALL SDL_GetAudioRecordingDevices(int /** * Get the human-readable name of a specific audio device. * + * **WARNING**: this function will work with SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK + * and SDL_AUDIO_DEVICE_DEFAULT_RECORDING, returning the current default + * physical devices' names. However, as the default device may change at any + * time, it is likely better to show a generic name to the user, like "System + * default audio device" or perhaps "default [currently %s]". Do not store + * this name to disk to reidentify the device in a later run of the program, + * as the default might change in general, and the string will be the name of + * a specific device and not the abstract system default. + * * \param devid the instance ID of the device to query. * \returns the name of the audio device, or NULL on failure; call * SDL_GetError() for more information. @@ -942,7 +951,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_CloseAudioDevice(SDL_AudioDeviceID devid); * Binding a stream to a device will set its output format for playback * devices, and its input format for recording devices, so they match the * device's settings. The caller is welcome to change the other end of the - * stream's format at any time with SDL_SetAudioStreamFormat(). + * stream's format at any time with SDL_SetAudioStreamFormat(). If the other + * end of the stream's format has never been set (the audio stream was created + * with a NULL audio spec), this function will set it to match the device + * end's format. * * \param devid an audio device to bind a stream to. * \param streams an array of audio streams to bind. @@ -1021,7 +1033,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnbindAudioStream(SDL_AudioStream *stream); /** * Query an audio stream for its currently-bound device. * - * This reports the audio device that an audio stream is currently bound to. + * This reports the logical audio device that an audio stream is currently + * bound to. * * If not bound, or invalid, this returns zero, which is not a valid device * ID. @@ -1063,6 +1076,17 @@ extern SDL_DECLSPEC SDL_AudioStream * SDLCALL SDL_CreateAudioStream(const SDL_Au /** * Get the properties associated with an audio stream. * + * The application can hang any data it wants here, but the following + * properties are understood by SDL: + * + * - `SDL_PROP_AUDIOSTREAM_AUTO_CLEANUP_BOOLEAN`: if true (the default), the + * stream be automatically cleaned up when the audio subsystem quits. If set + * to false, the streams will persist beyond that. This property is ignored + * for streams created through SDL_OpenAudioDeviceStream(), and will always + * be cleaned up. Streams that are not cleaned up will still be unbound from + * devices when the audio subsystem quits. This property was added in SDL + * 3.4.0. + * * \param stream the SDL_AudioStream to query. * \returns a valid property ID on success or 0 on failure; call * SDL_GetError() for more information. @@ -1073,6 +1097,9 @@ extern SDL_DECLSPEC SDL_AudioStream * SDLCALL SDL_CreateAudioStream(const SDL_Au */ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetAudioStreamProperties(SDL_AudioStream *stream); +#define SDL_PROP_AUDIOSTREAM_AUTO_CLEANUP_BOOLEAN "SDL.audiostream.auto_cleanup" + + /** * Query the current format of an audio stream. * @@ -1149,14 +1176,14 @@ extern SDL_DECLSPEC float SDLCALL SDL_GetAudioStreamFrequencyRatio(SDL_AudioStre * * The frequency ratio is used to adjust the rate at which input data is * consumed. Changing this effectively modifies the speed and pitch of the - * audio. A value greater than 1.0 will play the audio faster, and at a higher - * pitch. A value less than 1.0 will play the audio slower, and at a lower - * pitch. + * audio. A value greater than 1.0f will play the audio faster, and at a + * higher pitch. A value less than 1.0f will play the audio slower, and at a + * lower pitch. 1.0f means play at normal speed. * * This is applied during SDL_GetAudioStreamData, and can be continuously * changed to create various effects. * - * \param stream the stream the frequency ratio is being changed. + * \param stream the stream on which the frequency ratio is being changed. * \param ratio the frequency ratio. 1.0 is normal speed. Must be between 0.01 * and 100. * \returns true on success or false on failure; call SDL_GetError() for more @@ -1318,7 +1345,7 @@ extern SDL_DECLSPEC int * SDLCALL SDL_GetAudioStreamOutputChannelMap(SDL_AudioSt * \threadsafety It is safe to call this function from any thread, as it holds * a stream-specific mutex while running. Don't change the * stream's format to have a different number of channels from a - * a different thread at the same time, though! + * different thread at the same time, though! * * \since This function is available since SDL 3.2.0. * @@ -1332,7 +1359,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetAudioStreamInputChannelMap(SDL_AudioStre * Channel maps are optional; most things do not need them, instead passing * data in the [order that SDL expects](CategoryAudio#channel-layouts). * - * The output channel map reorders data that leaving a stream via + * The output channel map reorders data that is leaving a stream via * SDL_GetAudioStreamData. * * Each item in the array represents an input channel, and its value is the @@ -1414,6 +1441,136 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetAudioStreamOutputChannelMap(SDL_AudioStr */ extern SDL_DECLSPEC bool SDLCALL SDL_PutAudioStreamData(SDL_AudioStream *stream, const void *buf, int len); +/** + * A callback that fires for completed SDL_PutAudioStreamDataNoCopy() data. + * + * When using SDL_PutAudioStreamDataNoCopy() to provide data to an + * SDL_AudioStream, it's not safe to dispose of the data until the stream has + * completely consumed it. Often times it's difficult to know exactly when + * this has happened. + * + * This callback fires once when the stream no longer needs the buffer, + * allowing the app to easily free or reuse it. + * + * \param userdata an opaque pointer provided by the app for their personal + * use. + * \param buf the pointer provided to SDL_PutAudioStreamDataNoCopy(). + * \param buflen the size of buffer, in bytes, provided to + * SDL_PutAudioStreamDataNoCopy(). + * + * \threadsafety This callbacks may run from any thread, so if you need to + * protect shared data, you should use SDL_LockAudioStream to + * serialize access; this lock will be held before your callback + * is called, so your callback does not need to manage the lock + * explicitly. + * + * \since This datatype is available since SDL 3.4.0. + * + * \sa SDL_SetAudioStreamGetCallback + * \sa SDL_SetAudioStreamPutCallback + */ +typedef void (SDLCALL *SDL_AudioStreamDataCompleteCallback)(void *userdata, const void *buf, int buflen); + +/** + * Add external data to an audio stream without copying it. + * + * Unlike SDL_PutAudioStreamData(), this function does not make a copy of the + * provided data, instead storing the provided pointer. This means that the + * put operation does not need to allocate and copy the data, but the original + * data must remain available until the stream is done with it, either by + * being read from the stream in its entirety, or a call to + * SDL_ClearAudioStream() or SDL_DestroyAudioStream(). + * + * The data must match the format/channels/samplerate specified in the latest + * call to SDL_SetAudioStreamFormat, or the format specified when creating the + * stream if it hasn't been changed. + * + * An optional callback may be provided, which is called when the stream no + * longer needs the data. Once this callback fires, the stream will not access + * the data again. This callback will fire for any reason the data is no + * longer needed, including clearing or destroying the stream. + * + * Note that there is still an allocation to store tracking information, so + * this function is more efficient for larger blocks of data. If you're + * planning to put a few samples at a time, it will be more efficient to use + * SDL_PutAudioStreamData(), which allocates and buffers in blocks. + * + * \param stream the stream the audio data is being added to. + * \param buf a pointer to the audio data to add. + * \param len the number of bytes to add to the stream. + * \param callback the callback function to call when the data is no longer + * needed by the stream. May be NULL. + * \param userdata an opaque pointer provided to the callback for its own + * personal use. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread, but if the + * stream has a callback set, the caller might need to manage + * extra locking. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_ClearAudioStream + * \sa SDL_FlushAudioStream + * \sa SDL_GetAudioStreamData + * \sa SDL_GetAudioStreamQueued + */ +extern SDL_DECLSPEC bool SDLCALL SDL_PutAudioStreamDataNoCopy(SDL_AudioStream *stream, const void *buf, int len, SDL_AudioStreamDataCompleteCallback callback, void *userdata); + +/** + * Add data to the stream with each channel in a separate array. + * + * This data must match the format/channels/samplerate specified in the latest + * call to SDL_SetAudioStreamFormat, or the format specified when creating the + * stream if it hasn't been changed. + * + * The data will be interleaved and queued. Note that SDL_AudioStream only + * operates on interleaved data, so this is simply a convenience function for + * easily queueing data from sources that provide separate arrays. There is no + * equivalent function to retrieve planar data. + * + * The arrays in `channel_buffers` are ordered as they are to be interleaved; + * the first array will be the first sample in the interleaved data. Any + * individual array may be NULL; in this case, silence will be interleaved for + * that channel. + * + * `num_channels` specifies how many arrays are in `channel_buffers`. This can + * be used as a safety to prevent overflow, in case the stream format has + * changed elsewhere. If more channels are specified than the current input + * spec, they are ignored. If less channels are specified, the missing arrays + * are treated as if they are NULL (silence is written to those channels). If + * the count is -1, SDL will assume the array count matches the current input + * spec. + * + * Note that `num_samples` is the number of _samples per array_. This can also + * be thought of as the number of _sample frames_ to be queued. A value of 1 + * with stereo arrays will queue two samples to the stream. This is different + * than SDL_PutAudioStreamData, which wants the size of a single array in + * bytes. + * + * \param stream the stream the audio data is being added to. + * \param channel_buffers a pointer to an array of arrays, one array per + * channel. + * \param num_channels the number of arrays in `channel_buffers` or -1. + * \param num_samples the number of _samples_ per array to write to the + * stream. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread, but if the + * stream has a callback set, the caller might need to manage + * extra locking. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_ClearAudioStream + * \sa SDL_FlushAudioStream + * \sa SDL_GetAudioStreamData + * \sa SDL_GetAudioStreamQueued + */ +extern SDL_DECLSPEC bool SDLCALL SDL_PutAudioStreamPlanarData(SDL_AudioStream *stream, const void * const *channel_buffers, int num_channels, int num_samples); + /** * Get converted/resampled data from the stream. * @@ -1583,8 +1740,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PauseAudioStreamDevice(SDL_AudioStream *str * previously been paused. Once unpaused, any bound audio streams will begin * to progress again, and audio can be generated. * - * Remember, SDL_OpenAudioDeviceStream opens device in a paused state, so this - * function call is required for audio playback to begin on such device. + * SDL_OpenAudioDeviceStream opens audio devices in a paused state, so this + * function call is required for audio playback to begin on such devices. * * \param stream the audio stream associated with the audio device to resume. * \returns true on success or false on failure; call SDL_GetError() for more @@ -1841,7 +1998,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroyAudioStream(SDL_AudioStream *stream) * Also unlike other functions, the audio device begins paused. This is to map * more closely to SDL2-style behavior, since there is no extra step here to * bind a stream to begin audio flowing. The audio device should be resumed - * with `SDL_ResumeAudioStreamDevice(stream);` + * with SDL_ResumeAudioStreamDevice(). * * This function works with both playback and recording devices. * diff --git a/vendor/sdl3/include/SDL_begin_code.h b/vendor/sdl3/include/SDL_begin_code.h index a6b47cf4b..94f79099b 100644 --- a/vendor/sdl3/include/SDL_begin_code.h +++ b/vendor/sdl3/include/SDL_begin_code.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -261,9 +261,9 @@ * * On compilers without restrict support, this is defined to nothing. * - * \since This macro is available since SDL 3.2.0. + * \since This macro is available since SDL 3.4.0. */ -#define SDL_RESTRICT __restrict__ +#define SDL_RESTRICT __restrict /** * Check if the compiler supports a given builtin functionality. @@ -281,9 +281,61 @@ */ #define SDL_HAS_BUILTIN(x) __has_builtin(x) +/** + * A macro to specify data alignment. + * + * This informs the compiler that a given datatype or variable must be aligned + * to a specific byte count. + * + * For example: + * + * ```c + * // make sure this is struct is aligned to 16 bytes for SIMD access. + * typedef struct { + * float x, y, z, w; + * } SDL_ALIGNED(16) MySIMDAlignedData; + * + * // make sure this one field in a struct is aligned to 16 bytes for SIMD access. + * typedef struct { + * SomeStuff stuff; + * float SDL_ALIGNED(16) position[4]; + * SomeOtherStuff other_stuff; + * } MyStruct; + * + * // make sure this variable is aligned to 32 bytes. + * int SDL_ALIGNED(32) myval = 0; + * ``` + * + * Alignment is only guaranteed for things the compiler places: local + * variables on the stack and global/static variables. To dynamically allocate + * something that respects this alignment, use SDL_aligned_alloc() or some + * other mechanism. + * + * On compilers without alignment support, this macro is defined to an invalid + * symbol, to make it clear that the current compiler is likely to generate + * incorrect code when it sees this macro. + * + * \param x the byte count to align to, so the data's address will be a + * multiple of this value. + * + * \since This macro is available since SDL 3.4.0. + */ +#define SDL_ALIGNED(x) __attribute__((aligned(x))) + /* end of wiki documentation section. */ #endif +/* `restrict` is from C99, but __restrict works with both Visual Studio and GCC. */ +#ifndef SDL_RESTRICT +# if defined(restrict) || ((defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))) +# define SDL_RESTRICT restrict +# elif defined(_MSC_VER) || defined(__GNUC__) || defined(__clang__) +# define SDL_RESTRICT __restrict +# else +# define SDL_RESTRICT +# endif +#endif + #ifndef SDL_HAS_BUILTIN #ifdef __has_builtin #define SDL_HAS_BUILTIN(x) __has_builtin(x) @@ -379,7 +431,7 @@ #endif /* SDL_INLINE not defined */ #ifndef SDL_FORCE_INLINE -#ifdef _MSC_VER +#if defined(_MSC_VER) && (_MSC_VER >= 1200) #define SDL_FORCE_INLINE __forceinline #elif ( (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) ) #define SDL_FORCE_INLINE __attribute__((always_inline)) static __inline__ @@ -389,7 +441,7 @@ #endif /* SDL_FORCE_INLINE not defined */ #ifndef SDL_NORETURN -#ifdef __GNUC__ +#if defined(__GNUC__) #define SDL_NORETURN __attribute__((noreturn)) #elif defined(_MSC_VER) #define SDL_NORETURN __declspec(noreturn) @@ -484,3 +536,18 @@ #define SDL_ALLOC_SIZE2(p1, p2) #endif #endif /* SDL_ALLOC_SIZE2 not defined */ + +#ifndef SDL_ALIGNED +#if defined(__clang__) || defined(__GNUC__) +#define SDL_ALIGNED(x) __attribute__((aligned(x))) +#elif defined(_MSC_VER) +#define SDL_ALIGNED(x) __declspec(align(x)) +#elif defined(__cplusplus) && (__cplusplus >= 201103L) +#define SDL_ALIGNED(x) alignas(x) +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +#define SDL_ALIGNED(x) _Alignas(x) +#else +#define SDL_ALIGNED(x) PLEASE_DEFINE_SDL_ALIGNED +#endif +#endif /* SDL_ALIGNED not defined */ + diff --git a/vendor/sdl3/include/SDL_bits.h b/vendor/sdl3/include/SDL_bits.h index 7435ce6d9..ddb5cdbab 100644 --- a/vendor/sdl3/include/SDL_bits.h +++ b/vendor/sdl3/include/SDL_bits.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_blendmode.h b/vendor/sdl3/include/SDL_blendmode.h index 8f00cbcaf..84cf622cb 100644 --- a/vendor/sdl3/include/SDL_blendmode.h +++ b/vendor/sdl3/include/SDL_blendmode.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_camera.h b/vendor/sdl3/include/SDL_camera.h index 5f3911fdf..14ea647a7 100644 --- a/vendor/sdl3/include/SDL_camera.h +++ b/vendor/sdl3/include/SDL_camera.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -119,7 +119,7 @@ typedef struct SDL_CameraSpec int width; /**< Frame width */ int height; /**< Frame height */ int framerate_numerator; /**< Frame rate numerator ((num / denom) == FPS, (denom / num) == duration in seconds) */ - int framerate_denominator; /**< Frame rate demoninator ((num / denom) == FPS, (denom / num) == duration in seconds) */ + int framerate_denominator; /**< Frame rate denominator ((num / denom) == FPS, (denom / num) == duration in seconds) */ } SDL_CameraSpec; /** @@ -136,6 +136,20 @@ typedef enum SDL_CameraPosition SDL_CAMERA_POSITION_BACK_FACING } SDL_CameraPosition; +/** + * The current state of a request for camera access. + * + * \since This enum is available since SDL 3.4.0. + * + * \sa SDL_GetCameraPermissionState + */ +typedef enum SDL_CameraPermissionState +{ + SDL_CAMERA_PERMISSION_STATE_DENIED = -1, + SDL_CAMERA_PERMISSION_STATE_PENDING, + SDL_CAMERA_PERMISSION_STATE_APPROVED, +} SDL_CameraPermissionState; + /** * Use this function to get the number of built-in camera drivers. @@ -346,8 +360,9 @@ extern SDL_DECLSPEC SDL_Camera * SDLCALL SDL_OpenCamera(SDL_CameraID instance_id * on others the approval might be implicit and not alert the user at all. * * This function can be used to check the status of that approval. It will - * return 0 if still waiting for user response, 1 if the camera is approved - * for use, and -1 if the user denied access. + * return SDL_CAMERA_PERMISSION_STATE_PENDING if waiting for user response, + * SDL_CAMERA_PERMISSION_STATE_APPROVED if the camera is approved for use, and + * SDL_CAMERA_PERMISSION_STATE_DENIED if the user denied access. * * Instead of polling with this function, you can wait for a * SDL_EVENT_CAMERA_DEVICE_APPROVED (or SDL_EVENT_CAMERA_DEVICE_DENIED) event @@ -358,8 +373,9 @@ extern SDL_DECLSPEC SDL_Camera * SDLCALL SDL_OpenCamera(SDL_CameraID instance_id * SDL_CloseCamera() to dispose of it. * * \param camera the opened camera device to query. - * \returns -1 if user denied access to the camera, 1 if user approved access, - * 0 if no decision has been made yet. + * \returns an SDL_CameraPermissionState value indicating if access is + * granted, or `SDL_CAMERA_PERMISSION_STATE_PENDING` if the decision + * is still pending. * * \threadsafety It is safe to call this function from any thread. * @@ -368,7 +384,7 @@ extern SDL_DECLSPEC SDL_Camera * SDLCALL SDL_OpenCamera(SDL_CameraID instance_id * \sa SDL_OpenCamera * \sa SDL_CloseCamera */ -extern SDL_DECLSPEC int SDLCALL SDL_GetCameraPermissionState(SDL_Camera *camera); +extern SDL_DECLSPEC SDL_CameraPermissionState SDLCALL SDL_GetCameraPermissionState(SDL_Camera *camera); /** * Get the instance ID of an opened camera. diff --git a/vendor/sdl3/include/SDL_clipboard.h b/vendor/sdl3/include/SDL_clipboard.h index 0d3cbb499..696825376 100644 --- a/vendor/sdl3/include/SDL_clipboard.h +++ b/vendor/sdl3/include/SDL_clipboard.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -106,7 +106,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetClipboardText(const char *text); /** * Get UTF-8 text from the clipboard. * - * This functions returns an empty string if there was not enough memory left + * This function returns an empty string if there is not enough memory left * for a copy of the clipboard's content. * * \returns the clipboard text on success or an empty string on failure; call @@ -155,7 +155,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetPrimarySelectionText(const char *text); /** * Get UTF-8 text from the primary selection. * - * This functions returns an empty string if there was not enough memory left + * This function returns an empty string if there is not enough memory left * for a copy of the primary selection's content. * * \returns the primary selection text on success or an empty string on @@ -194,15 +194,14 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HasPrimarySelectionText(void); * clipboard is cleared or new data is set. The clipboard is automatically * cleared in SDL_Quit(). * - * \param userdata a pointer to provided user data. + * \param userdata a pointer to the provided user data. * \param mime_type the requested mime-type. * \param size a pointer filled in with the length of the returned data. * \returns a pointer to the data for the provided mime-type. Returning NULL - * or setting length to 0 will cause no data to be sent to the - * "receiver". It is up to the receiver to handle this. Essentially - * returning no data is more or less undefined behavior and may cause - * breakage in receiving applications. The returned data will not be - * freed so it needs to be retained and dealt with internally. + * or setting the length to 0 will cause zero length data to be sent + * to the "receiver", which should be able to handle this. The + * returned data will not be freed, so it needs to be retained and + * dealt with internally. * * \since This function is available since SDL 3.2.0. * @@ -211,10 +210,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HasPrimarySelectionText(void); typedef const void *(SDLCALL *SDL_ClipboardDataCallback)(void *userdata, const char *mime_type, size_t *size); /** - * Callback function that will be called when the clipboard is cleared, or new - * data is set. + * Callback function that will be called when the clipboard is cleared, or + * when new data is set. * - * \param userdata a pointer to provided user data. + * \param userdata a pointer to the provided user data. * * \since This function is available since SDL 3.2.0. * @@ -231,7 +230,7 @@ typedef void (SDLCALL *SDL_ClipboardCleanupCallback)(void *userdata); * respond with the data for the requested mime-type. * * The size of text data does not include any terminator, and the text does - * not need to be null terminated (e.g. you can directly copy a portion of a + * not need to be null-terminated (e.g., you can directly copy a portion of a * document). * * \param callback a function pointer to the function that provides the @@ -239,7 +238,8 @@ typedef void (SDLCALL *SDL_ClipboardCleanupCallback)(void *userdata); * \param cleanup a function pointer to the function that cleans up the * clipboard data. * \param userdata an opaque pointer that will be forwarded to the callbacks. - * \param mime_types a list of mime-types that are being offered. + * \param mime_types a list of mime-types that are being offered. SDL copies + * the given list. * \param num_mime_types the number of mime-types in the mime_types list. * \returns true on success or false on failure; call SDL_GetError() for more * information. @@ -269,10 +269,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetClipboardData(SDL_ClipboardDataCallback extern SDL_DECLSPEC bool SDLCALL SDL_ClearClipboardData(void); /** - * Get the data from clipboard for a given mime type. + * Get the data from the clipboard for a given mime type. * * The size of text data does not include the terminator, but the text is - * guaranteed to be null terminated. + * guaranteed to be null-terminated. * * \param mime_type the mime type to read from the clipboard. * \param size a pointer filled in with the length of the returned data. @@ -292,8 +292,8 @@ extern SDL_DECLSPEC void * SDLCALL SDL_GetClipboardData(const char *mime_type, s /** * Query whether there is data in the clipboard for the provided mime type. * - * \param mime_type the mime type to check for data for. - * \returns true if there exists data in clipboard for the provided mime type, + * \param mime_type the mime type to check for data. + * \returns true if data exists in the clipboard for the provided mime type, * false if it does not. * * \threadsafety This function should only be called on the main thread. @@ -310,7 +310,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HasClipboardData(const char *mime_type); * * \param num_mime_types a pointer filled with the number of mime types, may * be NULL. - * \returns a null terminated array of strings with mime types, or NULL on + * \returns a null-terminated array of strings with mime types, or NULL on * failure; call SDL_GetError() for more information. This should be * freed with SDL_free() when it is no longer needed. * diff --git a/vendor/sdl3/include/SDL_close_code.h b/vendor/sdl3/include/SDL_close_code.h index da1dea7fa..ad9daa6d4 100644 --- a/vendor/sdl3/include/SDL_close_code.h +++ b/vendor/sdl3/include/SDL_close_code.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_copying.h b/vendor/sdl3/include/SDL_copying.h index 747bd3570..dd9dbc7ee 100644 --- a/vendor/sdl3/include/SDL_copying.h +++ b/vendor/sdl3/include/SDL_copying.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_cpuinfo.h b/vendor/sdl3/include/SDL_cpuinfo.h index 1745bd934..5669c2373 100644 --- a/vendor/sdl3/include/SDL_cpuinfo.h +++ b/vendor/sdl3/include/SDL_cpuinfo.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -344,6 +344,27 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetSystemRAM(void); */ extern SDL_DECLSPEC size_t SDLCALL SDL_GetSIMDAlignment(void); +/** + * Report the size of a page of memory. + * + * Different platforms might have different memory page sizes. In current + * times, 4 kilobytes is not unusual, but newer systems are moving to larger + * page sizes, and esoteric platforms might have any unexpected size. + * + * Note that this function can return 0, which means SDL can't determine the + * page size on this platform. It will _not_ set an error string to be + * retrieved with SDL_GetError() in this case! In this case, defaulting to + * 4096 is often a reasonable option. + * + * \returns the size of a single page of memory, in bytes, or 0 if SDL can't + * determine this information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC int SDLCALL SDL_GetSystemPageSize(void); + /* Ends C function definitions when using C++ */ #ifdef __cplusplus } diff --git a/vendor/sdl3/include/SDL_dialog.h b/vendor/sdl3/include/SDL_dialog.h index ddb9e24d5..1e01347bf 100644 --- a/vendor/sdl3/include/SDL_dialog.h +++ b/vendor/sdl3/include/SDL_dialog.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -139,10 +139,12 @@ typedef void (SDLCALL *SDL_DialogFileCallback)(void *userdata, const char * cons * it will be invoked. * \param window the window that the dialog should be modal for, may be NULL. * Not all platforms support this option. - * \param filters a list of filters, may be NULL. Not all platforms support - * this option, and platforms that do support it may allow the - * user to ignore the filters. If non-NULL, it must remain - * valid at least until the callback is invoked. + * \param filters a list of filters, may be NULL. See the + * [`SDL_DialogFileFilter`](SDL_DialogFileFilter#code-examples) + * documentation for examples]. Not all platforms support this + * option, and platforms that do support it may allow the user + * to ignore the filters. If non-NULL, it must remain valid at + * least until the callback is invoked. * \param nfilters the number of filters. Ignored if filters is NULL. * \param default_location the default folder or file to start the dialog at, * may be NULL. Not all platforms support this option. diff --git a/vendor/sdl3/include/SDL_dlopennote.h b/vendor/sdl3/include/SDL_dlopennote.h new file mode 100644 index 000000000..299435a5d --- /dev/null +++ b/vendor/sdl3/include/SDL_dlopennote.h @@ -0,0 +1,234 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2026 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* WIKI CATEGORY: DlopenNotes */ + +/** + * # CategoryDlopenNotes + * + * This header allows you to annotate your code so external tools know about + * dynamic shared library dependencies. + * + * If you determine that your toolchain doesn't support dlopen notes, you can + * disable this feature by defining `SDL_DISABLE_DLOPEN_NOTES`. You can use + * this CMake snippet to check for support: + * + * ```cmake + * include(CheckCSourceCompiles) + * find_package(SDL3 REQUIRED CONFIG COMPONENTS Headers) + * list(APPEND CMAKE_REQUIRED_LIBRARIES SDL3::Headers) + * check_c_source_compiles([==[ + * #include + * SDL_ELF_NOTE_DLOPEN("sdl-video", + * "Support for video through SDL", + * SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + * "libSDL-1.2.so.0", "libSDL-2.0.so.0", "libSDL3.so.0" + * ) + * int main(int argc, char *argv[]) { + * return argc + argv[0][1]; + * } + * ]==] COMPILER_SUPPORTS_SDL_ELF_NOTE_DLOPEN) + * if(NOT COMPILER_SUPPORTS_SDL_ELF_NOTE_DLOPEN) + * add_compile_definitions(-DSDL_DISABLE_DLOPEN_NOTE) + * endif() + * ``` + */ + +#ifndef SDL_dlopennote_h +#define SDL_dlopennote_h + +/** + * Use this macro with SDL_ELF_NOTE_DLOPEN() to note that a dynamic shared + * library dependency is optional. + * + * Optional functionality uses the dependency, the binary will work and the + * dependency is only needed for full-featured installations. + * + * \since This macro is available since SDL 3.4.0. + * + * \sa SDL_ELF_NOTE_DLOPEN + * \sa SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED + * \sa SDL_ELF_NOTE_DLOPEN_PRIORITY_REQUIRED + */ +#define SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED "suggested" + +/** + * Use this macro with SDL_ELF_NOTE_DLOPEN() to note that a dynamic shared + * library dependency is recommended. + * + * Important functionality needs the dependency, the binary will work but in + * most cases the dependency should be provided. + * + * \since This macro is available since SDL 3.4.0. + * + * \sa SDL_ELF_NOTE_DLOPEN + * \sa SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED + * \sa SDL_ELF_NOTE_DLOPEN_PRIORITY_REQUIRED + */ +#define SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED "recommended" + +/** + * Use this macro with SDL_ELF_NOTE_DLOPEN() to note that a dynamic shared + * library dependency is required. + * + * Core functionality needs the dependency, the binary will not work if it + * cannot be found. + * + * \since This macro is available since SDL 3.4.0. + * + * \sa SDL_ELF_NOTE_DLOPEN + * \sa SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED + * \sa SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED + */ +#define SDL_ELF_NOTE_DLOPEN_PRIORITY_REQUIRED "required" + + +#if !defined(SDL_PLATFORM_UNIX) || defined(SDL_PLATFORM_ANDROID) +/* The dlopen note functionality isn't used on this platform */ +#ifndef SDL_DISABLE_DLOPEN_NOTES +#define SDL_DISABLE_DLOPEN_NOTES +#endif +#elif defined(__GNUC__) && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 1)) +/* gcc < 3.1 too old */ +#ifndef SDL_DISABLE_DLOPEN_NOTES +#define SDL_DISABLE_DLOPEN_NOTES +#endif +#endif /* SDL_PLATFORM_UNIX || SDL_PLATFORM_ANDROID */ + +#if defined(__ELF__) && !defined(SDL_DISABLE_DLOPEN_NOTES) + +#include + +#define SDL_ELF_NOTE_DLOPEN_VENDOR "FDO" +#define SDL_ELF_NOTE_DLOPEN_TYPE 0x407c0c0aU + +#define SDL_ELF_NOTE_INTERNAL2(json, variable_name) \ + __attribute__((aligned(4), used, section(".note.dlopen"))) \ + static const struct { \ + struct { \ + Uint32 n_namesz; \ + Uint32 n_descsz; \ + Uint32 n_type; \ + } nhdr; \ + char name[4]; \ + __attribute__((aligned(4))) char dlopen_json[sizeof(json)]; \ + } variable_name = { \ + { \ + sizeof(SDL_ELF_NOTE_DLOPEN_VENDOR), \ + sizeof(json), \ + SDL_ELF_NOTE_DLOPEN_TYPE \ + }, \ + SDL_ELF_NOTE_DLOPEN_VENDOR, \ + json \ + } + +#define SDL_ELF_NOTE_INTERNAL(json, variable_name) \ + SDL_ELF_NOTE_INTERNAL2(json, variable_name) + +#define SDL_DLNOTE_JSON_ARRAY1(N1) "[\"" N1 "\"]" +#define SDL_DLNOTE_JSON_ARRAY2(N1,N2) "[\"" N1 "\",\"" N2 "\"]" +#define SDL_DLNOTE_JSON_ARRAY3(N1,N2,N3) "[\"" N1 "\",\"" N2 "\",\"" N3 "\"]" +#define SDL_DLNOTE_JSON_ARRAY4(N1,N2,N3,N4) "[\"" N1 "\",\"" N2 "\",\"" N3 "\",\"" N4 "\"]" +#define SDL_DLNOTE_JSON_ARRAY5(N1,N2,N3,N4,N5) "[\"" N1 "\",\"" N2 "\",\"" N3 "\",\"" N4 "\",\"" N5 "\"]" +#define SDL_DLNOTE_JSON_ARRAY6(N1,N2,N3,N4,N5,N6) "[\"" N1 "\",\"" N2 "\",\"" N3 "\",\"" N4 "\",\"" N5 "\",\"" N6 "\"]" +#define SDL_DLNOTE_JSON_ARRAY7(N1,N2,N3,N4,N5,N6,N7) "[\"" N1 "\",\"" N2 "\",\"" N3 "\",\"" N4 "\",\"" N5 "\",\"" N6 "\",\"" N7 "\"]" +#define SDL_DLNOTE_JSON_ARRAY8(N1,N2,N3,N4,N5,N6,N7,N8) "[\"" N1 "\",\"" N2 "\",\"" N3 "\",\"" N4 "\",\"" N5 "\",\"" N6 "\",\"" N7 "\",\"" N8 "\"]" +#define SDL_DLNOTE_JSON_ARRAY_GET(N1,N2,N3,N4,N5,N6,N7,N8,NAME,...) NAME +#define SDL_DLNOTE_JSON_ARRAY(...) \ + SDL_DLNOTE_JSON_ARRAY_GET( \ + __VA_ARGS__, \ + SDL_DLNOTE_JSON_ARRAY8, \ + SDL_DLNOTE_JSON_ARRAY7, \ + SDL_DLNOTE_JSON_ARRAY6, \ + SDL_DLNOTE_JSON_ARRAY5, \ + SDL_DLNOTE_JSON_ARRAY4, \ + SDL_DLNOTE_JSON_ARRAY3, \ + SDL_DLNOTE_JSON_ARRAY2, \ + SDL_DLNOTE_JSON_ARRAY1 \ + )(__VA_ARGS__) + +/* Create "unique" variable name using __LINE__, + * so creating multiple elf notes on the same line is not supported + */ +#define SDL_DLNOTE_JOIN2(A,B) A##B +#define SDL_DLNOTE_JOIN(A,B) SDL_DLNOTE_JOIN2(A,B) +#define SDL_DLNOTE_UNIQUE_NAME SDL_DLNOTE_JOIN(s_SDL_dlopen_note_, __LINE__) + +/** + * Add a note that your application has dynamic shared library dependencies. + * + * You can do this by adding the following to the global scope: + * + * ```c + * SDL_ELF_NOTE_DLOPEN( + * "png", + * "Support for loading PNG images using libpng (required for APNG)", + * SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED, + * "libpng12.so.0" + * ) + * ``` + * + * A trailing semicolon is not needed. + * + * Or if you support multiple versions of a library, you can list them: + * + * ```c + * // Our app supports SDL1, SDL2, and SDL3 by dynamically loading them + * SDL_ELF_NOTE_DLOPEN( + * "SDL", + * "Create windows through SDL video backend", + * SDL_ELF_NOTE_DLOPEN_PRIORITY_REQUIRED + * "libSDL-1.2.so.0", "libSDL2-2.0.so.0", "libSDL3.so.0" + * ) + * ``` + * + * This macro is not available for compilers that do not support variadic + * macro's. + * + * \since This macro is available since SDL 3.4.0. + * + * \sa SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED + * \sa SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED + * \sa SDL_ELF_NOTE_DLOPEN_PRIORITY_REQUIRED + */ +#define SDL_ELF_NOTE_DLOPEN(feature, description, priority, ...) \ + SDL_ELF_NOTE_INTERNAL( \ + "[{\"feature\":\"" feature \ + "\",\"description\":\"" description \ + "\",\"priority\":\"" priority \ + "\",\"soname\":" SDL_DLNOTE_JSON_ARRAY(__VA_ARGS__) "}]", \ + SDL_DLNOTE_UNIQUE_NAME); + +#elif defined(__GNUC__) && __GNUC__ < 3 + +#define SDL_ELF_NOTE_DLOPEN(args...) + +#elif defined(_MSC_VER) && _MSC_VER < 1400 + +/* Variadic macros are not supported */ + +#else + +#define SDL_ELF_NOTE_DLOPEN(...) + +#endif + +#endif /* SDL_dlopennote_h */ diff --git a/vendor/sdl3/include/SDL_egl.h b/vendor/sdl3/include/SDL_egl.h index 65d4e967a..1371c4d01 100644 --- a/vendor/sdl3/include/SDL_egl.h +++ b/vendor/sdl3/include/SDL_egl.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_endian.h b/vendor/sdl3/include/SDL_endian.h index a34e9d4b0..957ea20c3 100644 --- a/vendor/sdl3/include/SDL_endian.h +++ b/vendor/sdl3/include/SDL_endian.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -46,7 +46,7 @@ #if defined(_MSC_VER) && (_MSC_VER >= 1400) /* As of Clang 11, '_m_prefetchw' is conflicting with the winnt.h's version, so we define the needed '_m_prefetch' here as a pseudo-header, until the issue is fixed. */ -#ifdef __clang__ +#if defined(__clang__) && !SDL_HAS_BUILTIN(_m_prefetch) #ifndef __PRFCHWINTRIN_H #define __PRFCHWINTRIN_H static __inline__ void __attribute__((__always_inline__, __nodebug__)) @@ -128,7 +128,7 @@ _m_prefetch(void *__P) * \sa SDL_BIG_ENDIAN */ #define SDL_BYTEORDER SDL_LIL_ENDIAN___or_maybe___SDL_BIG_ENDIAN -#elif defined(SDL_PLATFORM_LINUX) +#elif defined(SDL_PLATFORM_LINUX) || defined(__GLIBC__) #include #define SDL_BYTEORDER __BYTE_ORDER #elif defined(SDL_PLATFORM_SOLARIS) @@ -252,7 +252,7 @@ SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x) #elif defined(__x86_64__) SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x) { - __asm__("xchgb %b0,%h0": "=Q"(x):"0"(x)); + __asm__("xchgb %b0,%h0": "=abcd"(x):"0"(x)); return x; } #elif (defined(__powerpc__) || defined(__ppc__)) @@ -486,7 +486,7 @@ SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x) { return x_but_byteswapped; } * * \since This function is available since SDL 3.2.0. */ -SDL_FORCE_INLINE Uint32 SDL_Swap64(Uint64 x) { return x_but_byteswapped; } +SDL_FORCE_INLINE Uint64 SDL_Swap64(Uint64 x) { return x_but_byteswapped; } /** * Swap a 16-bit value from littleendian to native byte order. diff --git a/vendor/sdl3/include/SDL_error.h b/vendor/sdl3/include/SDL_error.h index 934967c1c..3453818cb 100644 --- a/vendor/sdl3/include/SDL_error.h +++ b/vendor/sdl3/include/SDL_error.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_events.h b/vendor/sdl3/include/SDL_events.h index d267f051f..d82a615f8 100644 --- a/vendor/sdl3/include/SDL_events.h +++ b/vendor/sdl3/include/SDL_events.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -30,7 +30,7 @@ * coming and going, the system changing in some way, etc. * * An app generally takes a moment, perhaps at the start of a new frame, to - * examine any events that have occured since the last time and process or + * examine any events that have occurred since the last time and process or * ignore them. This is generally done by calling SDL_PollEvent() in a loop * until it returns false (or, if using the main callbacks, events are * provided one at a time in calls to SDL_AppEvent() before the next call to @@ -127,15 +127,17 @@ typedef enum SDL_EventType SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED, /**< Display has changed desktop mode */ SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED, /**< Display has changed current mode */ SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED, /**< Display has changed content scale */ + SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED, /**< Display has changed usable bounds */ SDL_EVENT_DISPLAY_FIRST = SDL_EVENT_DISPLAY_ORIENTATION, - SDL_EVENT_DISPLAY_LAST = SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED, + SDL_EVENT_DISPLAY_LAST = SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED, /* Window events */ /* 0x200 was SDL_WINDOWEVENT, reserve the number for sdl2-compat */ /* 0x201 was SDL_SYSWMEVENT, reserve the number for sdl2-compat */ SDL_EVENT_WINDOW_SHOWN = 0x202, /**< Window has been shown */ SDL_EVENT_WINDOW_HIDDEN, /**< Window has been hidden */ - SDL_EVENT_WINDOW_EXPOSED, /**< Window has been exposed and should be redrawn, and can be redrawn directly from event watchers for this event */ + SDL_EVENT_WINDOW_EXPOSED, /**< Window has been exposed and should be redrawn, and can be redrawn directly from event watchers for this event. + data1 is 1 for live-resize expose events, 0 otherwise. */ SDL_EVENT_WINDOW_MOVED, /**< Window has been moved to data1, data2 */ SDL_EVENT_WINDOW_RESIZED, /**< Window has been resized to data1xdata2 */ SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED,/**< The pixel size of the window has changed to data1xdata2 */ @@ -174,6 +176,8 @@ typedef enum SDL_EventType SDL_EVENT_KEYBOARD_ADDED, /**< A new keyboard has been inserted into the system */ SDL_EVENT_KEYBOARD_REMOVED, /**< A keyboard has been removed */ SDL_EVENT_TEXT_EDITING_CANDIDATES, /**< Keyboard text editing candidates */ + SDL_EVENT_SCREEN_KEYBOARD_SHOWN, /**< The on-screen keyboard has been shown */ + SDL_EVENT_SCREEN_KEYBOARD_HIDDEN, /**< The on-screen keyboard has been hidden */ /* Mouse events */ SDL_EVENT_MOUSE_MOTION = 0x400, /**< Mouse moved */ @@ -214,10 +218,15 @@ typedef enum SDL_EventType SDL_EVENT_FINGER_MOTION, SDL_EVENT_FINGER_CANCELED, + /* Pinch events */ + SDL_EVENT_PINCH_BEGIN = 0x710, /**< Pinch gesture started */ + SDL_EVENT_PINCH_UPDATE, /**< Pinch gesture updated */ + SDL_EVENT_PINCH_END, /**< Pinch gesture ended */ + /* 0x800, 0x801, and 0x802 were the Gesture events from SDL2. Do not reuse these values! sdl2-compat needs them! */ /* Clipboard events */ - SDL_EVENT_CLIPBOARD_UPDATE = 0x900, /**< The clipboard or primary selection changed */ + SDL_EVENT_CLIPBOARD_UPDATE = 0x900, /**< The clipboard changed */ /* Drag and drop events */ SDL_EVENT_DROP_FILE = 0x1000, /**< The system requests a file open */ @@ -298,7 +307,7 @@ typedef struct SDL_CommonEvent */ typedef struct SDL_DisplayEvent { - SDL_EventType type; /**< SDL_DISPLAYEVENT_* */ + SDL_EventType type; /**< SDL_EVENT_DISPLAY_* */ Uint32 reserved; Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */ SDL_DisplayID displayID;/**< The associated display */ @@ -704,6 +713,10 @@ typedef struct SDL_GamepadSensorEvent /** * Audio device event structure (event.adevice.*) * + * Note that SDL will send a SDL_EVENT_AUDIO_DEVICE_ADDED event for every + * device it discovers during initialization. After that, this event will only + * arrive when a device is hotplugged during the program's run. + * * \since This struct is available since SDL 3.2.0. */ typedef struct SDL_AudioDeviceEvent @@ -781,7 +794,19 @@ typedef struct SDL_TouchFingerEvent } SDL_TouchFingerEvent; /** - * Pressure-sensitive pen proximity event structure (event.pmotion.*) + * Pinch event structure (event.pinch.*) + */ +typedef struct SDL_PinchFingerEvent +{ + SDL_EventType type; /**< ::SDL_EVENT_PINCH_BEGIN or ::SDL_EVENT_PINCH_UPDATE or ::SDL_EVENT_PINCH_END */ + Uint32 reserved; + Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */ + float scale; /**< The scale change since the last SDL_EVENT_PINCH_UPDATE. Scale < 1 is "zoom out". Scale > 1 is "zoom in". */ + SDL_WindowID windowID; /**< The window underneath the finger, if any */ +} SDL_PinchFingerEvent; + +/** + * Pressure-sensitive pen proximity event structure (event.pproximity.*) * * When a pen becomes visible to the system (it is close enough to a tablet, * etc), SDL will send an SDL_EVENT_PEN_PROXIMITY_IN event with the new pen's @@ -793,6 +818,9 @@ typedef struct SDL_TouchFingerEvent * is there." The pen touching and lifting off from the tablet while not * leaving the area are handled by SDL_EVENT_PEN_DOWN and SDL_EVENT_PEN_UP. * + * Not all platforms have a window associated with the pen during proximity + * events. Some wait until motion/button/etc events to offer this info. + * * \since This struct is available since SDL 3.2.0. */ typedef struct SDL_PenProximityEvent @@ -967,7 +995,7 @@ typedef struct SDL_QuitEvent */ typedef struct SDL_UserEvent { - Uint32 type; /**< SDL_EVENT_USER through SDL_EVENT_LAST-1, Uint32 because these are not in the SDL_EventType enumeration */ + Uint32 type; /**< SDL_EVENT_USER through SDL_EVENT_LAST, Uint32 because these are not in the SDL_EventType enumeration */ Uint32 reserved; Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */ SDL_WindowID windowID; /**< The associated window if any */ @@ -1017,6 +1045,7 @@ typedef union SDL_Event SDL_QuitEvent quit; /**< Quit request event data */ SDL_UserEvent user; /**< Custom event data */ SDL_TouchFingerEvent tfinger; /**< Touch finger event data */ + SDL_PinchFingerEvent pinch; /**< Pinch event data */ SDL_PenProximityEvent pproximity; /**< Pen proximity event data */ SDL_PenTouchEvent ptouch; /**< Pen tip touching event data */ SDL_PenMotionEvent pmotion; /**< Pen motion event data */ @@ -1043,7 +1072,7 @@ typedef union SDL_Event } SDL_Event; /* Make sure we haven't broken binary compatibility */ -SDL_COMPILE_TIME_ASSERT(SDL_Event, sizeof(SDL_Event) == sizeof(((SDL_Event *)NULL)->padding)); +SDL_COMPILE_TIME_ASSERT(SDL_Event, sizeof(SDL_Event) == sizeof((SDL_static_cast(SDL_Event *, NULL))->padding)); /* Function prototypes */ @@ -1227,15 +1256,13 @@ extern SDL_DECLSPEC void SDLCALL SDL_FlushEvents(Uint32 minType, Uint32 maxType) * Poll for currently pending events. * * If `event` is not NULL, the next event is removed from the queue and stored - * in the SDL_Event structure pointed to by `event`. The 1 returned refers to - * this event, immediately stored in the SDL Event structure -- not an event - * to follow. + * in the SDL_Event structure pointed to by `event`. * - * If `event` is NULL, it simply returns 1 if there is an event in the queue, + * If `event` is NULL, it simply returns true if there is an event in the queue, * but will not remove it from the queue. * * As this function may implicitly call SDL_PumpEvents(), you can only call - * this function in the thread that set the video mode. + * this function in the thread that initialized the video subsystem. * * SDL_PollEvent() is the favored way of receiving system events since it can * be done from the main loop and does not suspend the main loop while waiting @@ -1255,6 +1282,13 @@ extern SDL_DECLSPEC void SDLCALL SDL_FlushEvents(Uint32 minType, Uint32 maxType) * } * ``` * + * Note that Windows (and possibly other platforms) has a quirk about how it + * handles events while dragging/resizing a window, which can cause this + * function to block for significant amounts of time. Technical explanations + * and solutions are discussed on the wiki: + * + * https://wiki.libsdl.org/SDL3/AppFreezeDuringDrag + * * \param event the SDL_Event structure to be filled with the next event from * the queue, or NULL. * \returns true if this got an event or false if there are none available. @@ -1391,7 +1425,10 @@ typedef bool (SDLCALL *SDL_EventFilter)(void *userdata, SDL_Event *event); * allows selective filtering of dynamically arriving events. * * **WARNING**: Be very careful of what you do in the event filter function, - * as it may run in a different thread! + * as it may run in a different thread! The exception is handling of + * SDL_EVENT_WINDOW_EXPOSED, which is guaranteed to be sent from the OS on the + * main thread and you are expected to redraw your window in response to this + * event. * * On platforms that support it, if the quit event is generated by an * interrupt signal (e.g. pressing Ctrl-C), it will be delivered to the @@ -1404,7 +1441,7 @@ typedef bool (SDLCALL *SDL_EventFilter)(void *userdata, SDL_Event *event); * the event filter, but events pushed onto the queue with SDL_PeepEvents() do * not. * - * \param filter an SDL_EventFilter function to call when an event happens. + * \param filter a function to call when an event happens. * \param userdata a pointer that is passed to `filter`. * * \threadsafety It is safe to call this function from any thread. @@ -1567,6 +1604,38 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_RegisterEvents(int numevents); */ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_GetWindowFromEvent(const SDL_Event *event); +/** + * Generate an English description of an event. + * + * This will fill `buf` with a null-terminated string that might look + * something like this: + * + * ``` + * SDL_EVENT_MOUSE_MOTION (timestamp=1140256324 windowid=2 which=0 state=0 x=492.99 y=139.09 xrel=52 yrel=6) + * ``` + * + * The exact format of the string is not guaranteed; it is intended for + * logging purposes, to be read by a human, and not parsed by a computer. + * + * The returned value follows the same rules as SDL_snprintf(): `buf` will + * always be NULL-terminated (unless `buflen` is zero), and will be truncated + * if `buflen` is too small. The return code is the number of bytes needed for + * the complete string, not counting the NULL-terminator, whether the string + * was truncated or not. Unlike SDL_snprintf(), though, this function never + * returns -1. + * + * \param event an event to describe. May be NULL. + * \param buf the buffer to fill with the description string. May be NULL. + * \param buflen the maximum bytes that can be written to `buf`. + * \returns number of bytes needed for the full string, not counting the + * null-terminator byte. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC int SDLCALL SDL_GetEventDescription(const SDL_Event *event, char *buf, int buflen); + /* Ends C function definitions when using C++ */ #ifdef __cplusplus } diff --git a/vendor/sdl3/include/SDL_filesystem.h b/vendor/sdl3/include/SDL_filesystem.h index af3ca27e0..006293554 100644 --- a/vendor/sdl3/include/SDL_filesystem.h +++ b/vendor/sdl3/include/SDL_filesystem.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -77,6 +77,9 @@ extern "C" { * - `parent`: the containing directory of the bundle. For example: * `/Applications/SDLApp/` * + * **Android Specific Functionality**: This function returns "./", which + * allows filesystem operations to use internal storage and the asset system. + * * **Nintendo 3DS Specific Functionality**: This function returns "romfs" * directory of the application as it is uncommon to store resources outside * the executable. As such it is not a writable directory. @@ -89,6 +92,8 @@ extern "C" { * doesn't implement this functionality, call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetPrefPath @@ -134,6 +139,12 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetBasePath(void); * - ...only use letters, numbers, and spaces. Avoid punctuation like "Game * Name 2: Bad Guy's Revenge!" ... "Game Name 2" is sufficient. * + * Due to historical mistakes, `org` is allowed to be NULL or "". In such + * cases, SDL will omit the org subdirectory, including on platforms where it + * shouldn't, and including on platforms where this would make your app fail + * certification for an app store. New apps should definitely specify a real + * string for `org`. + * * The returned path is guaranteed to end with a path separator ('\\' on * Windows, '/' on most other platforms). * @@ -144,6 +155,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetBasePath(void); * etc.). This should be freed with SDL_free() when it is no longer * needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetBasePath @@ -216,6 +229,8 @@ typedef enum SDL_Folder * \returns either a null-terminated C string containing the full path to the * folder, or NULL if an error happened. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC const char * SDLCALL SDL_GetUserFolder(SDL_Folder folder); @@ -227,8 +242,7 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetUserFolder(SDL_Folder folder); * Types of filesystem entries. * * Note that there may be other sorts of items on a filesystem: devices, - * symlinks, named pipes, etc. They are currently reported as - * SDL_PATHTYPE_OTHER. + * named pipes, etc. They are currently reported as SDL_PATHTYPE_OTHER. * * \since This enum is available since SDL 3.2.0. * @@ -283,6 +297,8 @@ typedef Uint32 SDL_GlobFlags; * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_CreateDirectory(const char *path); @@ -346,6 +362,8 @@ typedef SDL_EnumerationResult (SDLCALL *SDL_EnumerateDirectoryCallback)(void *us * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback callback, void *userdata); @@ -360,6 +378,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_EnumerateDirectory(const char *path, SDL_En * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_RemovePath(const char *path); @@ -367,7 +387,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RemovePath(const char *path); /** * Rename a file or directory. * - * If the file at `newpath` already exists, it will replaced. + * If the file at `newpath` already exists, it will be replaced. * * Note that this will not copy files across filesystems/drives/volumes, as * that is a much more complicated (and possibly time-consuming) operation. @@ -383,6 +403,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RemovePath(const char *path); * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_RenamePath(const char *oldpath, const char *newpath); @@ -423,6 +445,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenamePath(const char *oldpath, const char * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread, but this + * operation is not atomic, so the app might need to protect + * access to specific paths from other threads if appropriate. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_CopyFile(const char *oldpath, const char *newpath); @@ -430,12 +456,18 @@ extern SDL_DECLSPEC bool SDLCALL SDL_CopyFile(const char *oldpath, const char *n /** * Get information about a filesystem path. * + * Symlinks, on filesystems that support them, are always followed, so you will + * always get information on what the symlink eventually points to, and not the + * symlink itself. + * * \param path the path to query. * \param info a pointer filled in with information about the path, or NULL to * check for the existence of a file. * \returns true on success or false if the file doesn't exist, or another * failure; call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_GetPathInfo(const char *path, SDL_PathInfo *info); @@ -444,10 +476,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetPathInfo(const char *path, SDL_PathInfo * Enumerate a directory tree, filtered by pattern, and return a list. * * Files are filtered out if they don't match the string in `pattern`, which - * may contain wildcard characters '\*' (match everything) and '?' (match one + * may contain wildcard characters `*` (match everything) and `?` (match one * character). If pattern is NULL, no filtering is done and all results are * returned. Subdirectories are permitted, and are specified with a path - * separator of '/'. Wildcard characters '\*' and '?' never match a path + * separator of `/`. Wildcard characters `*` and `?` never match a path * separator. * * `flags` may be set to SDL_GLOB_CASEINSENSITIVE to make the pattern matching @@ -490,6 +522,8 @@ extern SDL_DECLSPEC char ** SDLCALL SDL_GlobDirectory(const char *path, const ch * platform-dependent notation. NULL if there's a problem. This * should be freed with SDL_free() when it is no longer needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC char * SDLCALL SDL_GetCurrentDirectory(void); diff --git a/vendor/sdl3/include/SDL_gamepad.h b/vendor/sdl3/include/SDL_gamepad.h index 99f8b6593..113452535 100644 --- a/vendor/sdl3/include/SDL_gamepad.h +++ b/vendor/sdl3/include/SDL_gamepad.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -48,6 +48,9 @@ * SDL_INIT_GAMEPAD flag. This causes SDL to scan the system for gamepads, and * load appropriate drivers. * + * If you're using SDL gamepad support in a Steam game, you must call + * SteamAPI_InitEx() before calling SDL_Init(). + * * If you would like to receive gamepad updates while the application is in * the background, you should set the following hint before calling * SDL_Init(): SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS @@ -118,6 +121,7 @@ typedef enum SDL_GamepadType SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT, SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT, SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR, + SDL_GAMEPAD_TYPE_GAMECUBE, SDL_GAMEPAD_TYPE_COUNT } SDL_GamepadType; @@ -127,8 +131,9 @@ typedef enum SDL_GamepadType * For controllers that use a diamond pattern for the face buttons, the * south/east/west/north buttons below correspond to the locations in the * diamond pattern. For Xbox controllers, this would be A/B/X/Y, for Nintendo - * Switch controllers, this would be B/A/Y/X, for PlayStation controllers this - * would be Cross/Circle/Square/Triangle. + * Switch controllers, this would be B/A/Y/X, for GameCube controllers this + * would be A/X/B/Y, for PlayStation controllers this would be + * Cross/Circle/Square/Triangle. * * For controllers that don't use a diamond pattern for the face buttons, the * south/east/west/north buttons indicate the buttons labeled A, B, C, D, or @@ -163,14 +168,14 @@ typedef enum SDL_GamepadButton SDL_GAMEPAD_BUTTON_DPAD_LEFT, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, SDL_GAMEPAD_BUTTON_MISC1, /**< Additional button (e.g. Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button, Google Stadia capture button) */ - SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1, /**< Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1) */ - SDL_GAMEPAD_BUTTON_LEFT_PADDLE1, /**< Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3) */ - SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2, /**< Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2) */ - SDL_GAMEPAD_BUTTON_LEFT_PADDLE2, /**< Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4) */ + SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1, /**< Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1, DualSense Edge RB button, Right Joy-Con SR button) */ + SDL_GAMEPAD_BUTTON_LEFT_PADDLE1, /**< Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3, DualSense Edge LB button, Left Joy-Con SL button) */ + SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2, /**< Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2, DualSense Edge right Fn button, Right Joy-Con SL button) */ + SDL_GAMEPAD_BUTTON_LEFT_PADDLE2, /**< Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4, DualSense Edge left Fn button, Left Joy-Con SR button) */ SDL_GAMEPAD_BUTTON_TOUCHPAD, /**< PS4/PS5 touchpad button */ SDL_GAMEPAD_BUTTON_MISC2, /**< Additional button */ - SDL_GAMEPAD_BUTTON_MISC3, /**< Additional button */ - SDL_GAMEPAD_BUTTON_MISC4, /**< Additional button */ + SDL_GAMEPAD_BUTTON_MISC3, /**< Additional button (e.g. Nintendo GameCube left trigger click) */ + SDL_GAMEPAD_BUTTON_MISC4, /**< Additional button (e.g. Nintendo GameCube right trigger click) */ SDL_GAMEPAD_BUTTON_MISC5, /**< Additional button */ SDL_GAMEPAD_BUTTON_MISC6, /**< Additional button */ SDL_GAMEPAD_BUTTON_COUNT @@ -422,6 +427,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_AddGamepadMappingsFromFile(const char *file) * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_ReloadGamepadMappings(void); @@ -436,6 +443,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReloadGamepadMappings(void); * single allocation that should be freed with SDL_free() when it is * no longer needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC char ** SDLCALL SDL_GetGamepadMappings(int *count); @@ -448,6 +457,8 @@ extern SDL_DECLSPEC char ** SDLCALL SDL_GetGamepadMappings(int *count); * information. This should be freed with SDL_free() when it is no * longer needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickGUIDForID @@ -465,6 +476,8 @@ extern SDL_DECLSPEC char * SDLCALL SDL_GetGamepadMappingForGUID(SDL_GUID guid); * available; call SDL_GetError() for more information. This should * be freed with SDL_free() when it is no longer needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_AddGamepadMapping @@ -485,6 +498,8 @@ extern SDL_DECLSPEC char * SDLCALL SDL_GetGamepadMapping(SDL_Gamepad *gamepad); * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_AddGamepadMapping @@ -497,6 +512,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetGamepadMapping(SDL_JoystickID instance_i * * \returns true if a gamepad is connected, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepads @@ -512,6 +529,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HasGamepad(void); * call SDL_GetError() for more information. This should be freed * with SDL_free() when it is no longer needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_HasGamepad @@ -526,6 +545,8 @@ extern SDL_DECLSPEC SDL_JoystickID * SDLCALL SDL_GetGamepads(int *count); * \returns true if the given joystick is supported by the gamepad interface, * false if it isn't or it's an invalid index. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoysticks @@ -542,6 +563,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_IsGamepad(SDL_JoystickID instance_id); * \returns the name of the selected gamepad. If no name can be found, this * function returns NULL; call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadName @@ -558,6 +581,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadNameForID(SDL_JoystickID * \returns the path of the selected gamepad. If no path can be found, this * function returns NULL; call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadPath @@ -573,6 +598,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadPathForID(SDL_JoystickID * \param instance_id the joystick instance ID. * \returns the player index of a gamepad, or -1 if it's not available. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadPlayerIndex @@ -589,6 +616,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetGamepadPlayerIndexForID(SDL_JoystickID in * \returns the GUID of the selected gamepad. If called on an invalid index, * this function returns a zero GUID. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GUIDToString @@ -606,6 +635,8 @@ extern SDL_DECLSPEC SDL_GUID SDLCALL SDL_GetGamepadGUIDForID(SDL_JoystickID inst * \returns the USB vendor ID of the selected gamepad. If called on an invalid * index, this function returns zero. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadVendor @@ -623,6 +654,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetGamepadVendorForID(SDL_JoystickID inst * \returns the USB product ID of the selected gamepad. If called on an * invalid index, this function returns zero. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadProduct @@ -640,6 +673,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetGamepadProductForID(SDL_JoystickID ins * \returns the product version of the selected gamepad. If called on an * invalid index, this function returns zero. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadProductVersion @@ -655,6 +690,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetGamepadProductVersionForID(SDL_Joystic * \param instance_id the joystick instance ID. * \returns the gamepad type. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadType @@ -671,6 +708,8 @@ extern SDL_DECLSPEC SDL_GamepadType SDLCALL SDL_GetGamepadTypeForID(SDL_Joystick * \param instance_id the joystick instance ID. * \returns the gamepad type. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadTypeForID @@ -688,6 +727,8 @@ extern SDL_DECLSPEC SDL_GamepadType SDLCALL SDL_GetRealGamepadTypeForID(SDL_Joys * \returns the mapping string. Returns NULL if no mapping is available. This * should be freed with SDL_free() when it is no longer needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepads @@ -702,6 +743,8 @@ extern SDL_DECLSPEC char * SDLCALL SDL_GetGamepadMappingForID(SDL_JoystickID ins * \returns a gamepad identifier or NULL if an error occurred; call * SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_CloseGamepad @@ -717,6 +760,8 @@ extern SDL_DECLSPEC SDL_Gamepad * SDLCALL SDL_OpenGamepad(SDL_JoystickID instanc * \returns an SDL_Gamepad on success or NULL on failure or if it hasn't been * opened yet; call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_Gamepad * SDLCALL SDL_GetGamepadFromID(SDL_JoystickID instance_id); @@ -727,6 +772,8 @@ extern SDL_DECLSPEC SDL_Gamepad * SDLCALL SDL_GetGamepadFromID(SDL_JoystickID in * \param player_index the player index, which different from the instance ID. * \returns the SDL_Gamepad associated with a player index. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadPlayerIndex @@ -757,6 +804,8 @@ extern SDL_DECLSPEC SDL_Gamepad * SDLCALL SDL_GetGamepadFromPlayerIndex(int play * \returns a valid property ID on success or 0 on failure; call * SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetGamepadProperties(SDL_Gamepad *gamepad); @@ -775,6 +824,8 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetGamepadProperties(SDL_Gamepa * \returns the instance ID of the specified gamepad on success or 0 on * failure; call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_JoystickID SDLCALL SDL_GetGamepadID(SDL_Gamepad *gamepad); @@ -787,6 +838,8 @@ extern SDL_DECLSPEC SDL_JoystickID SDLCALL SDL_GetGamepadID(SDL_Gamepad *gamepad * \returns the implementation dependent name for the gamepad, or NULL if * there is no name or the identifier passed is invalid. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadNameForID @@ -801,6 +854,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadName(SDL_Gamepad *gamepad * \returns the implementation dependent path for the gamepad, or NULL if * there is no path or the identifier passed is invalid. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadPathForID @@ -814,6 +869,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadPath(SDL_Gamepad *gamepad * \returns the gamepad type, or SDL_GAMEPAD_TYPE_UNKNOWN if it's not * available. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadTypeForID @@ -827,6 +884,8 @@ extern SDL_DECLSPEC SDL_GamepadType SDLCALL SDL_GetGamepadType(SDL_Gamepad *game * \returns the gamepad type, or SDL_GAMEPAD_TYPE_UNKNOWN if it's not * available. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetRealGamepadTypeForID @@ -841,6 +900,8 @@ extern SDL_DECLSPEC SDL_GamepadType SDLCALL SDL_GetRealGamepadType(SDL_Gamepad * * \param gamepad the gamepad object to query. * \returns the player index for gamepad, or -1 if it's not available. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetGamepadPlayerIndex @@ -856,6 +917,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetGamepadPlayerIndex(SDL_Gamepad *gamepad); * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadPlayerIndex @@ -870,6 +933,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetGamepadPlayerIndex(SDL_Gamepad *gamepad, * \param gamepad the gamepad object to query. * \returns the USB vendor ID, or zero if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadVendorForID @@ -884,6 +949,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetGamepadVendor(SDL_Gamepad *gamepad); * \param gamepad the gamepad object to query. * \returns the USB product ID, or zero if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadProductForID @@ -898,6 +965,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetGamepadProduct(SDL_Gamepad *gamepad); * \param gamepad the gamepad object to query. * \returns the USB product version, or zero if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadProductVersionForID @@ -912,6 +981,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetGamepadProductVersion(SDL_Gamepad *gam * \param gamepad the gamepad object to query. * \returns the gamepad firmware version, or zero if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetGamepadFirmwareVersion(SDL_Gamepad *gamepad); @@ -924,6 +995,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetGamepadFirmwareVersion(SDL_Gamepad *ga * \param gamepad the gamepad object to query. * \returns the serial number, or NULL if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadSerial(SDL_Gamepad *gamepad); @@ -937,6 +1010,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadSerial(SDL_Gamepad *gamep * \param gamepad the gamepad object to query. * \returns the gamepad handle, or 0 if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC Uint64 SDLCALL SDL_GetGamepadSteamHandle(SDL_Gamepad *gamepad); @@ -949,6 +1024,8 @@ extern SDL_DECLSPEC Uint64 SDLCALL SDL_GetGamepadSteamHandle(SDL_Gamepad *gamepa * `SDL_JOYSTICK_CONNECTION_INVALID` on failure; call SDL_GetError() * for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_JoystickConnectionState SDLCALL SDL_GetGamepadConnectionState(SDL_Gamepad *gamepad); @@ -969,6 +1046,8 @@ extern SDL_DECLSPEC SDL_JoystickConnectionState SDLCALL SDL_GetGamepadConnection * battery. * \returns the current battery state. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_PowerState SDLCALL SDL_GetGamepadPowerInfo(SDL_Gamepad *gamepad, int *percent); @@ -981,6 +1060,8 @@ extern SDL_DECLSPEC SDL_PowerState SDLCALL SDL_GetGamepadPowerInfo(SDL_Gamepad * * \returns true if the gamepad has been opened and is currently connected, or * false if not. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_GamepadConnected(SDL_Gamepad *gamepad); @@ -1001,6 +1082,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GamepadConnected(SDL_Gamepad *gamepad); * \returns an SDL_Joystick object, or NULL on failure; call SDL_GetError() * for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_Joystick * SDLCALL SDL_GetGamepadJoystick(SDL_Gamepad *gamepad); @@ -1013,6 +1096,8 @@ extern SDL_DECLSPEC SDL_Joystick * SDLCALL SDL_GetGamepadJoystick(SDL_Gamepad *g * * \param enabled whether to process gamepad events or not. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GamepadEventsEnabled @@ -1028,6 +1113,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetGamepadEventsEnabled(bool enabled); * * \returns true if gamepad events are being processed, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetGamepadEventsEnabled @@ -1044,6 +1131,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GamepadEventsEnabled(void); * single allocation that should be freed with SDL_free() when it is * no longer needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_GamepadBinding ** SDLCALL SDL_GetGamepadBindings(SDL_Gamepad *gamepad, int *count); @@ -1055,6 +1144,8 @@ extern SDL_DECLSPEC SDL_GamepadBinding ** SDLCALL SDL_GetGamepadBindings(SDL_Gam * enabled. Under such circumstances, it will not be necessary to call this * function. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC void SDLCALL SDL_UpdateGamepads(void); @@ -1071,6 +1162,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_UpdateGamepads(void); * \returns the SDL_GamepadType enum corresponding to the input string, or * `SDL_GAMEPAD_TYPE_UNKNOWN` if no match was found. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadStringForType @@ -1085,6 +1178,8 @@ extern SDL_DECLSPEC SDL_GamepadType SDLCALL SDL_GetGamepadTypeFromString(const c * specified. The string returned is of the format used by * SDL_Gamepad mapping strings. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadTypeFromString @@ -1107,6 +1202,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadStringForType(SDL_Gamepad * \returns the SDL_GamepadAxis enum corresponding to the input string, or * `SDL_GAMEPAD_AXIS_INVALID` if no match was found. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadStringForAxis @@ -1121,6 +1218,8 @@ extern SDL_DECLSPEC SDL_GamepadAxis SDLCALL SDL_GetGamepadAxisFromString(const c * specified. The string returned is of the format used by * SDL_Gamepad mapping strings. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadAxisFromString @@ -1137,6 +1236,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadStringForAxis(SDL_Gamepad * \param axis an axis enum value (an SDL_GamepadAxis value). * \returns true if the gamepad has this axis, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GamepadHasButton @@ -1156,10 +1257,14 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GamepadHasAxis(SDL_Gamepad *gamepad, SDL_Ga * return a negative value. Note that this differs from the value reported by * the lower-level SDL_GetJoystickAxis(), which normally uses the full range. * + * Note that for invalid gamepads or axes, this will return 0. Zero is also a + * valid value in normal operation; usually it means a centered axis. + * * \param gamepad a gamepad. * \param axis an axis index (one of the SDL_GamepadAxis values). - * \returns axis state (including 0) on success or 0 (also) on failure; call - * SDL_GetError() for more information. + * \returns axis state. + * + * \threadsafety It is safe to call this function from any thread. * * \since This function is available since SDL 3.2.0. * @@ -1176,10 +1281,12 @@ extern SDL_DECLSPEC Sint16 SDLCALL SDL_GetGamepadAxis(SDL_Gamepad *gamepad, SDL_ * You do not normally need to call this function unless you are parsing * SDL_Gamepad mappings in your own code. * - * \param str string representing a SDL_Gamepad axis. + * \param str string representing a SDL_Gamepad button. * \returns the SDL_GamepadButton enum corresponding to the input string, or * `SDL_GAMEPAD_BUTTON_INVALID` if no match was found. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadStringForButton @@ -1194,6 +1301,8 @@ extern SDL_DECLSPEC SDL_GamepadButton SDLCALL SDL_GetGamepadButtonFromString(con * specified. The string returned is of the format used by * SDL_Gamepad mapping strings. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadButtonFromString @@ -1210,6 +1319,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadStringForButton(SDL_Gamep * \param button a button enum value (an SDL_GamepadButton value). * \returns true if the gamepad has this button, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GamepadHasAxis @@ -1223,6 +1334,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GamepadHasButton(SDL_Gamepad *gamepad, SDL_ * \param button a button index (one of the SDL_GamepadButton values). * \returns true if the button is pressed, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GamepadHasButton @@ -1237,6 +1350,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetGamepadButton(SDL_Gamepad *gamepad, SDL_ * \param button a button index (one of the SDL_GamepadButton values). * \returns the SDL_GamepadButtonLabel enum corresponding to the button label. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadButtonLabel @@ -1250,6 +1365,8 @@ extern SDL_DECLSPEC SDL_GamepadButtonLabel SDLCALL SDL_GetGamepadButtonLabelForT * \param button a button index (one of the SDL_GamepadButton values). * \returns the SDL_GamepadButtonLabel enum corresponding to the button label. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadButtonLabelForType @@ -1262,6 +1379,8 @@ extern SDL_DECLSPEC SDL_GamepadButtonLabel SDLCALL SDL_GetGamepadButtonLabel(SDL * \param gamepad a gamepad. * \returns number of touchpads. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetNumGamepadTouchpadFingers @@ -1276,6 +1395,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetNumGamepadTouchpads(SDL_Gamepad *gamepad) * \param touchpad a touchpad. * \returns number of supported simultaneous fingers. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadTouchpadFinger @@ -1299,6 +1420,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetNumGamepadTouchpadFingers(SDL_Gamepad *ga * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetNumGamepadTouchpadFingers @@ -1312,6 +1435,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetGamepadTouchpadFinger(SDL_Gamepad *gamep * \param type the type of sensor to query. * \returns true if the sensor exists, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadSensorData @@ -1329,6 +1454,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GamepadHasSensor(SDL_Gamepad *gamepad, SDL_ * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GamepadHasSensor @@ -1343,6 +1470,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetGamepadSensorEnabled(SDL_Gamepad *gamepa * \param type the type of sensor to query. * \returns true if the sensor is enabled, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetGamepadSensorEnabled @@ -1356,6 +1485,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GamepadSensorEnabled(SDL_Gamepad *gamepad, * \param type the type of sensor to query. * \returns the data rate, or 0.0f if the data rate is not available. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC float SDLCALL SDL_GetGamepadSensorDataRate(SDL_Gamepad *gamepad, SDL_SensorType type); @@ -1364,7 +1495,7 @@ extern SDL_DECLSPEC float SDLCALL SDL_GetGamepadSensorDataRate(SDL_Gamepad *game * Get the current state of a gamepad sensor. * * The number of values and interpretation of the data is sensor dependent. - * See SDL_sensor.h for the details for each type of sensor. + * See the remarks in SDL_SensorType for details for each type of sensor. * * \param gamepad the gamepad to query. * \param type the type of sensor to query. @@ -1373,6 +1504,8 @@ extern SDL_DECLSPEC float SDLCALL SDL_GetGamepadSensorDataRate(SDL_Gamepad *game * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_GetGamepadSensorData(SDL_Gamepad *gamepad, SDL_SensorType type, float *data, int num_values); @@ -1395,6 +1528,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetGamepadSensorData(SDL_Gamepad *gamepad, * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_RumbleGamepad(SDL_Gamepad *gamepad, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms); @@ -1421,6 +1556,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RumbleGamepad(SDL_Gamepad *gamepad, Uint16 * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_RumbleGamepad @@ -1443,6 +1580,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RumbleGamepadTriggers(SDL_Gamepad *gamepad, * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_SetGamepadLED(SDL_Gamepad *gamepad, Uint8 red, Uint8 green, Uint8 blue); @@ -1456,6 +1595,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetGamepadLED(SDL_Gamepad *gamepad, Uint8 r * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_SendGamepadEffect(SDL_Gamepad *gamepad, const void *data, int size); @@ -1466,6 +1607,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SendGamepadEffect(SDL_Gamepad *gamepad, con * \param gamepad a gamepad identifier previously returned by * SDL_OpenGamepad(). * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_OpenGamepad @@ -1480,6 +1623,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_CloseGamepad(SDL_Gamepad *gamepad); * \param button a button on the gamepad. * \returns the sfSymbolsName or NULL if the name can't be found. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadAppleSFSymbolsNameForAxis @@ -1493,6 +1638,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadAppleSFSymbolsNameForButt * \param axis an axis on the gamepad. * \returns the sfSymbolsName or NULL if the name can't be found. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadAppleSFSymbolsNameForButton diff --git a/vendor/sdl3/include/SDL_gpu.h b/vendor/sdl3/include/SDL_gpu.h index b61661909..b9e19ab54 100644 --- a/vendor/sdl3/include/SDL_gpu.h +++ b/vendor/sdl3/include/SDL_gpu.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -206,14 +206,20 @@ * underlying graphics API. While it's possible that we have done something * inefficiently, it's very unlikely especially if you are relatively * inexperienced with GPU rendering. Please see the performance tips above and - * make sure you are following them. Additionally, tools like RenderDoc can be - * very helpful for diagnosing incorrect behavior and performance issues. + * make sure you are following them. Additionally, tools like + * [RenderDoc](https://renderdoc.org/) + * can be very helpful for diagnosing incorrect behavior and performance + * issues. * * ## System Requirements * - * **Vulkan:** Supported on Windows, Linux, Nintendo Switch, and certain - * Android devices. Requires Vulkan 1.0 with the following extensions and - * device features: + * ### Vulkan + * + * SDL driver name: "vulkan" (for use in SDL_CreateGPUDevice() and + * SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING) + * + * Supported on Windows, Linux, Nintendo Switch, and certain Android devices. + * Requires Vulkan 1.0 with the following extensions and device features: * * - `VK_KHR_swapchain` * - `VK_KHR_maintenance1` @@ -222,13 +228,37 @@ * - `depthClamp` * - `shaderClipDistance` * - `drawIndirectFirstInstance` + * - `sampleRateShading` * - * **D3D12:** Supported on Windows 10 or newer, Xbox One (GDK), and Xbox - * Series X|S (GDK). Requires a GPU that supports DirectX 12 Feature Level - * 11_1. + * You can remove some of these requirements to increase compatibility with + * Android devices by using these properties when creating the GPU device with + * SDL_CreateGPUDeviceWithProperties(): * - * **Metal:** Supported on macOS 10.14+ and iOS/tvOS 13.0+. Hardware - * requirements vary by operating system: + * - SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN + * - SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN + * - SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN + * - SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN + * + * ### D3D12 + * + * SDL driver name: "direct3d12" + * + * Supported on Windows 10 or newer, Xbox One (GDK), and Xbox Series X|S + * (GDK). Requires a GPU that supports DirectX 12 Feature Level 11_0 and + * Resource Binding Tier 2 or above. + * + * You can remove the Tier 2 resource binding requirement to support Intel + * Haswell and Broadwell GPUs by using this property when creating the GPU + * device with SDL_CreateGPUDeviceWithProperties(): + * + * - SDL_PROP_GPU_DEVICE_CREATE_D3D12_ALLOW_FEWER_RESOURCE_SLOTS_BOOLEAN + * + * ### Metal + * + * SDL driver name: "metal" + * + * Supported on macOS 10.14+ and iOS/tvOS 13.0+. Hardware requirements vary by + * operating system: * * - macOS requires an Apple Silicon or * [Intel Mac2 family](https://developer.apple.com/documentation/metal/mtlfeatureset/mtlfeatureset_macos_gpufamily2_v1?language=objc) @@ -236,6 +266,26 @@ * - iOS/tvOS requires an A9 GPU or newer * - iOS Simulator and tvOS Simulator are unsupported * + * ## Coordinate System + * + * The GPU API uses a left-handed coordinate system, following the convention + * of D3D12 and Metal. Specifically: + * + * - **Normalized Device Coordinates:** The lower-left corner has an x,y + * coordinate of `(-1.0, -1.0)`. The upper-right corner is `(1.0, 1.0)`. Z + * values range from `[0.0, 1.0]` where 0 is the near plane. + * - **Viewport Coordinates:** The top-left corner has an x,y coordinate of + * `(0, 0)` and extends to the bottom-right corner at `(viewportWidth, + * viewportHeight)`. +Y is down. + * - **Texture Coordinates:** The top-left corner has an x,y coordinate of + * `(0, 0)` and extends to the bottom-right corner at `(1.0, 1.0)`. +Y is + * down. + * + * If the backend driver differs from this convention (e.g. Vulkan, which has + * an NDC that assumes +Y is down), SDL will automatically convert the + * coordinate system behind the scenes, so you don't need to perform any + * coordinate flipping logic in your shaders. + * * ## Uniform Data * * Uniforms are for passing data to shaders. The uniform data will be constant @@ -301,6 +351,39 @@ * unreferenced data in a bound resource without cycling, but overwriting a * section of data that has already been referenced will produce unexpected * results. + * + * ## Debugging + * + * At some point of your GPU journey, you will probably encounter issues that + * are not traceable with regular debugger - for example, your code compiles + * but you get an empty screen, or your shader fails in runtime. + * + * For debugging such cases, there are tools that allow visually inspecting + * the whole GPU frame, every drawcall, every bound resource, memory buffers, + * etc. They are the following, per platform: + * + * * For Windows/Linux, use + * [RenderDoc](https://renderdoc.org/) + * * For MacOS (Metal), use Xcode built-in debugger (Open XCode, go to Debug > + * Debug Executable..., select your application, set "GPU Frame Capture" to + * "Metal" in scheme "Options" window, run your app, and click the small + * Metal icon on the bottom to capture a frame) + * + * Aside from that, you may want to enable additional debug layers to receive + * more detailed error messages, based on your GPU backend: + * + * * For D3D12, the debug layer is an optional feature that can be installed + * via "Windows Settings -> System -> Optional features" and adding the + * "Graphics Tools" optional feature. + * * For Vulkan, you will need to install Vulkan SDK on Windows, and on Linux, + * you usually have some sort of `vulkan-validation-layers` system package + * that should be installed. + * * For Metal, it should be enough just to run the application from XCode to + * receive detailed errors or warnings in the output. + * + * Don't hesitate to use tools as RenderDoc when encountering runtime issues + * or unexpected output on screen, quick GPU frame inspection can usually help + * you fix the majority of such problems. */ #ifndef SDL_gpu_h_ @@ -1091,7 +1174,7 @@ typedef enum SDL_GPUCompareOp SDL_GPU_COMPAREOP_LESS_OR_EQUAL, /**< The comparison evaluates reference <= test. */ SDL_GPU_COMPAREOP_GREATER, /**< The comparison evaluates reference > test. */ SDL_GPU_COMPAREOP_NOT_EQUAL, /**< The comparison evaluates reference != test. */ - SDL_GPU_COMPAREOP_GREATER_OR_EQUAL, /**< The comparison evalutes reference >= test. */ + SDL_GPU_COMPAREOP_GREATER_OR_EQUAL, /**< The comparison evaluates reference >= test. */ SDL_GPU_COMPAREOP_ALWAYS /**< The comparison always evaluates true. */ } SDL_GPUCompareOp; @@ -1310,6 +1393,18 @@ typedef struct SDL_GPUViewport * A structure specifying parameters related to transferring data to or from a * texture. * + * If either of `pixels_per_row` or `rows_per_layer` is zero, then width and + * height of passed SDL_GPUTextureRegion to SDL_UploadToGPUTexture or + * SDL_DownloadFromGPUTexture are used as default values respectively and data + * is considered to be tightly packed. + * + * **WARNING**: On some older/integrated hardware, Direct3D 12 requires texture + * data row pitch to be 256 byte aligned, and offsets to be aligned to 512 bytes. + * If they are not, SDL will make a temporary copy of the data that is properly + * aligned, but this adds overhead to the transfer process. Apps can avoid this + * by aligning their data appropriately, or using a different GPU backend than + * Direct3D 12. + * * \since This struct is available since SDL 3.2.0. * * \sa SDL_UploadToGPUTexture @@ -1391,7 +1486,7 @@ typedef struct SDL_GPUTextureRegion */ typedef struct SDL_GPUBlitRegion { - SDL_GPUTexture *texture; /**< The texture. */ + SDL_GPUTexture *texture; /**< The texture. */ Uint32 mip_level; /**< The mip level index of the region. */ Uint32 layer_or_depth_plane; /**< The layer index or depth plane of the region. This value is treated as a layer index on 2D array and cube textures, and as a depth plane on 3D textures. */ Uint32 x; /**< The left offset of the region. */ @@ -1520,8 +1615,8 @@ typedef struct SDL_GPUSamplerCreateInfo SDL_GPUCompareOp compare_op; /**< The comparison operator to apply to fetched data before filtering. */ float min_lod; /**< Clamps the minimum of the computed LOD value. */ float max_lod; /**< Clamps the maximum of the computed LOD value. */ - bool enable_anisotropy; /**< true to enable anisotropic filtering. */ - bool enable_compare; /**< true to enable comparison against a reference value during lookups. */ + bool enable_anisotropy; /**< true to enable anisotropic filtering. */ + bool enable_compare; /**< true to enable comparison against a reference value during lookups. */ Uint8 padding1; Uint8 padding2; @@ -1549,7 +1644,7 @@ typedef struct SDL_GPUSamplerCreateInfo typedef struct SDL_GPUVertexBufferDescription { Uint32 slot; /**< The binding slot of the vertex buffer. */ - Uint32 pitch; /**< The byte pitch between consecutive elements of the vertex buffer. */ + Uint32 pitch; /**< The size of a single element + the offset between elements. */ SDL_GPUVertexInputRate input_rate; /**< Whether attribute addressing is a function of the vertex index or instance index. */ Uint32 instance_step_rate; /**< Reserved for future use. Must be set to 0. */ } SDL_GPUVertexBufferDescription; @@ -1613,6 +1708,9 @@ typedef struct SDL_GPUStencilOpState * \since This struct is available since SDL 3.2.0. * * \sa SDL_GPUColorTargetDescription + * \sa SDL_GPUBlendFactor + * \sa SDL_GPUBlendOp + * \sa SDL_GPUColorComponentFlags */ typedef struct SDL_GPUColorTargetBlendState { @@ -1623,8 +1721,8 @@ typedef struct SDL_GPUColorTargetBlendState SDL_GPUBlendFactor dst_alpha_blendfactor; /**< The value to be multiplied by the destination alpha. */ SDL_GPUBlendOp alpha_blend_op; /**< The blend operation for the alpha component. */ SDL_GPUColorComponentFlags color_write_mask; /**< A bitmask specifying which of the RGBA components are enabled for writing. Writes to all channels if enable_color_write_mask is false. */ - bool enable_blend; /**< Whether blending is enabled for the color target. */ - bool enable_color_write_mask; /**< Whether the color write mask is enabled. */ + bool enable_blend; /**< Whether blending is enabled for the color target. */ + bool enable_color_write_mask; /**< Whether the color write mask is enabled. */ Uint8 padding1; Uint8 padding2; } SDL_GPUColorTargetBlendState; @@ -1636,6 +1734,8 @@ typedef struct SDL_GPUColorTargetBlendState * \since This struct is available since SDL 3.2.0. * * \sa SDL_CreateGPUShader + * \sa SDL_GPUShaderFormat + * \sa SDL_GPUShaderStage */ typedef struct SDL_GPUShaderCreateInfo { @@ -1741,8 +1841,8 @@ typedef struct SDL_GPURasterizerState float depth_bias_constant_factor; /**< A scalar factor controlling the depth value added to each fragment. */ float depth_bias_clamp; /**< The maximum depth bias of a fragment. */ float depth_bias_slope_factor; /**< A scalar factor applied to a fragment's slope in depth calculations. */ - bool enable_depth_bias; /**< true to bias fragment depth values. */ - bool enable_depth_clip; /**< true to enable depth clip, false to enable depth clamp. */ + bool enable_depth_bias; /**< true to bias fragment depth values. */ + bool enable_depth_clip; /**< true to enable depth clip, false to enable depth clamp. */ Uint8 padding1; Uint8 padding2; } SDL_GPURasterizerState; @@ -1759,8 +1859,8 @@ typedef struct SDL_GPUMultisampleState { SDL_GPUSampleCount sample_count; /**< The number of samples to be used in rasterization. */ Uint32 sample_mask; /**< Reserved for future use. Must be set to 0. */ - bool enable_mask; /**< Reserved for future use. Must be set to false. */ - Uint8 padding1; + bool enable_mask; /**< Reserved for future use. Must be set to false. */ + bool enable_alpha_to_coverage; /**< true enables the alpha-to-coverage feature. */ Uint8 padding2; Uint8 padding3; } SDL_GPUMultisampleState; @@ -1780,9 +1880,9 @@ typedef struct SDL_GPUDepthStencilState SDL_GPUStencilOpState front_stencil_state; /**< The stencil op state for front-facing triangles. */ Uint8 compare_mask; /**< Selects the bits of the stencil values participating in the stencil test. */ Uint8 write_mask; /**< Selects the bits of the stencil values updated by the stencil test. */ - bool enable_depth_test; /**< true enables the depth test. */ - bool enable_depth_write; /**< true enables depth writes. Depth writes are always disabled when enable_depth_test is false. */ - bool enable_stencil_test; /**< true enables the stencil test. */ + bool enable_depth_test; /**< true enables the depth test. */ + bool enable_depth_write; /**< true enables depth writes. Depth writes are always disabled when enable_depth_test is false. */ + bool enable_stencil_test; /**< true enables the stencil test. */ Uint8 padding1; Uint8 padding2; Uint8 padding3; @@ -1817,7 +1917,7 @@ typedef struct SDL_GPUGraphicsPipelineTargetInfo const SDL_GPUColorTargetDescription *color_target_descriptions; /**< A pointer to an array of color target descriptions. */ Uint32 num_color_targets; /**< The number of color target descriptions in the above array. */ SDL_GPUTextureFormat depth_stencil_format; /**< The pixel format of the depth-stencil target. Ignored if has_depth_stencil_target is false. */ - bool has_depth_stencil_target; /**< true specifies that the pipeline uses a depth-stencil target. */ + bool has_depth_stencil_target; /**< true specifies that the pipeline uses a depth-stencil target. */ Uint8 padding1; Uint8 padding2; Uint8 padding3; @@ -1912,6 +2012,7 @@ typedef struct SDL_GPUComputePipelineCreateInfo * \since This struct is available since SDL 3.2.0. * * \sa SDL_BeginGPURenderPass + * \sa SDL_FColor */ typedef struct SDL_GPUColorTargetInfo { @@ -1924,8 +2025,8 @@ typedef struct SDL_GPUColorTargetInfo SDL_GPUTexture *resolve_texture; /**< The texture that will receive the results of a multisample resolve operation. Ignored if a RESOLVE* store_op is not used. */ Uint32 resolve_mip_level; /**< The mip level of the resolve texture to use for the resolve operation. Ignored if a RESOLVE* store_op is not used. */ Uint32 resolve_layer; /**< The layer index of the resolve texture to use for the resolve operation. Ignored if a RESOLVE* store_op is not used. */ - bool cycle; /**< true cycles the texture if the texture is bound and load_op is not LOAD */ - bool cycle_resolve_texture; /**< true cycles the resolve texture if the resolve texture is bound. Ignored if a RESOLVE* store_op is not used. */ + bool cycle; /**< true cycles the texture if the texture is bound and load_op is not LOAD */ + bool cycle_resolve_texture; /**< true cycles the resolve texture if the resolve texture is bound. Ignored if a RESOLVE* store_op is not used. */ Uint8 padding1; Uint8 padding2; } SDL_GPUColorTargetInfo; @@ -1970,6 +2071,9 @@ typedef struct SDL_GPUColorTargetInfo * * Note that depth/stencil targets do not support multisample resolves. * + * Due to ABI limitations, depth textures with more than 255 layers are not + * supported. + * * \since This struct is available since SDL 3.2.0. * * \sa SDL_BeginGPURenderPass @@ -1982,10 +2086,10 @@ typedef struct SDL_GPUDepthStencilTargetInfo SDL_GPUStoreOp store_op; /**< What is done with the depth results of the render pass. */ SDL_GPULoadOp stencil_load_op; /**< What is done with the stencil contents at the beginning of the render pass. */ SDL_GPUStoreOp stencil_store_op; /**< What is done with the stencil results of the render pass. */ - bool cycle; /**< true cycles the texture if the texture is bound and any load ops are not LOAD */ + bool cycle; /**< true cycles the texture if the texture is bound and any load ops are not LOAD */ Uint8 clear_stencil; /**< The value to clear the stencil component to at the beginning of the render pass. Ignored if SDL_GPU_LOADOP_CLEAR is not used. */ - Uint8 padding1; - Uint8 padding2; + Uint8 mip_level; /**< The mip level to use as the depth stencil target. */ + Uint8 layer; /**< The layer index to use as the depth stencil target. */ } SDL_GPUDepthStencilTargetInfo; /** @@ -2002,7 +2106,7 @@ typedef struct SDL_GPUBlitInfo { SDL_FColor clear_color; /**< The color to clear the destination region to before the blit. Ignored if load_op is not SDL_GPU_LOADOP_CLEAR. */ SDL_FlipMode flip_mode; /**< The flip mode for the source region. */ SDL_GPUFilter filter; /**< The filter mode used when blitting. */ - bool cycle; /**< true cycles the destination texture if it is already bound. */ + bool cycle; /**< true cycles the destination texture if it is already bound. */ Uint8 padding1; Uint8 padding2; Uint8 padding3; @@ -2031,6 +2135,8 @@ typedef struct SDL_GPUBufferBinding * * \sa SDL_BindGPUVertexSamplers * \sa SDL_BindGPUFragmentSamplers + * \sa SDL_GPUTexture + * \sa SDL_GPUSampler */ typedef struct SDL_GPUTextureSamplerBinding { @@ -2111,6 +2217,13 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GPUSupportsProperties( /** * Creates a GPU context. * + * The GPU driver name can be one of the following: + * + * - "vulkan": [Vulkan](CategoryGPU#vulkan) + * - "direct3d12": [D3D12](CategoryGPU#d3d12) + * - "metal": [Metal](CategoryGPU#metal) + * - NULL: let SDL pick the optimal driver + * * \param format_flags a bitflag indicating which shader formats the app is * able to provide. * \param debug_mode enable debug mode properties and validations. @@ -2121,6 +2234,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GPUSupportsProperties( * * \since This function is available since SDL 3.2.0. * + * \sa SDL_CreateGPUDeviceWithProperties * \sa SDL_GetGPUShaderFormats * \sa SDL_GetGPUDeviceDriver * \sa SDL_DestroyGPUDevice @@ -2140,8 +2254,31 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice( * properties and validations, defaults to true. * - `SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN`: enable to prefer * energy efficiency over maximum GPU performance, defaults to false. + * - `SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN`: enable to automatically log + * useful debug information on device creation, defaults to true. * - `SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING`: the name of the GPU driver to * use, if a specific one is desired. + * - `SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN`: Enable Vulkan + * device feature shaderClipDistance. If disabled, clip distances are not + * supported in shader code: gl_ClipDistance[] built-ins of GLSL, + * SV_ClipDistance0/1 semantics of HLSL and [[clip_distance]] attribute of + * Metal. Disabling optional features allows the application to run on some + * older Android devices. Defaults to true. + * - `SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN`: Enable + * Vulkan device feature depthClamp. If disabled, there is no depth clamp + * support and enable_depth_clip in SDL_GPURasterizerState must always be + * set to true. Disabling optional features allows the application to run on + * some older Android devices. Defaults to true. + * - `SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN`: + * Enable Vulkan device feature drawIndirectFirstInstance. If disabled, the + * argument first_instance of SDL_GPUIndirectDrawCommand must be set to + * zero. Disabling optional features allows the application to run on some + * older Android devices. Defaults to true. + * - `SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN`: Enable Vulkan + * device feature samplerAnisotropy. If disabled, enable_anisotropy of + * SDL_GPUSamplerCreateInfo must be set to false. Disabling optional + * features allows the application to run on some older Android devices. + * Defaults to true. * * These are the current shader format properties: * @@ -2158,10 +2295,56 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice( * - `SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN`: The app is able to * provide Metal shader libraries if applicable. * - * With the D3D12 renderer: + * With the D3D12 backend: * * - `SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING`: the prefix to * use for all vertex semantics, default is "TEXCOORD". + * - `SDL_PROP_GPU_DEVICE_CREATE_D3D12_ALLOW_FEWER_RESOURCE_SLOTS_BOOLEAN`: By + * default, Resourcing Binding Tier 2 is required for D3D12 support. + * However, an application can set this property to true to enable Tier 1 + * support, if (and only if) the application uses 8 or fewer storage + * resources across all shader stages. As of writing, this property is + * useful for targeting Intel Haswell and Broadwell GPUs; other hardware + * either supports Tier 2 Resource Binding or does not support D3D12 in any + * capacity. Defaults to false. + * - `SDL_PROP_GPU_DEVICE_CREATE_D3D12_AGILITY_SDK_VERSION_NUMBER`: Certain + * feature checks are only possible on Windows 11 by default. By setting + * this alongside `SDL_PROP_GPU_DEVICE_CREATE_D3D12_AGILITY_SDK_PATH_STRING` + * and vendoring D3D12Core.dll from the D3D12 Agility SDK, you can make + * those feature checks possible on older platforms. The version you provide + * must match the one given in the DLL. + * - `SDL_PROP_GPU_DEVICE_CREATE_D3D12_AGILITY_SDK_PATH_STRING`: Certain + * feature checks are only possible on Windows 11 by default. By setting + * this alongside + * `SDL_PROP_GPU_DEVICE_CREATE_D3D12_AGILITY_SDK_VERSION_NUMBER` and + * vendoring D3D12Core.dll from the D3D12 Agility SDK, you can make those + * feature checks possible on older platforms. The path you provide must be + * relative to the executable path of your app. Be sure not to put the DLL + * in the same directory as the exe; Microsoft strongly advises against + * this! + * + * With the Vulkan backend: + * + * - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_REQUIRE_HARDWARE_ACCELERATION_BOOLEAN`: + * By default, Vulkan device enumeration includes drivers of all types, + * including software renderers (for example, the Lavapipe Mesa driver). + * This can be useful if your application _requires_ SDL_GPU, but if you can + * provide your own fallback renderer (for example, an OpenGL renderer) this + * property can be set to true. Defaults to false. + * - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_OPTIONS_POINTER`: a pointer to an + * SDL_GPUVulkanOptions structure to be processed during device creation. + * This allows configuring a variety of Vulkan-specific options such as + * increasing the API version and opting into extensions aside from the + * minimal set SDL requires. + * + * With the Metal backend: - + * `SDL_PROP_GPU_DEVICE_CREATE_METAL_ALLOW_MACFAMILY1_BOOLEAN`: By default, + * macOS support requires what Apple calls "MTLGPUFamilyMac2" hardware or + * newer. However, an application can set this property to true to enable + * support for "MTLGPUFamilyMac1" hardware, if (and only if) the application + * does not write to sRGB textures. (For history's sake: MacFamily1 also does + * not support indirect command buffers, MSAA depth resolve, and stencil + * resolve/feedback, but these are not exposed features in SDL_GPU.) * * \param props the properties to use. * \returns a GPU context on success or NULL on failure; call SDL_GetError() @@ -2177,16 +2360,55 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice( extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDeviceWithProperties( SDL_PropertiesID props); -#define SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN "SDL.gpu.device.create.debugmode" -#define SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN "SDL.gpu.device.create.preferlowpower" -#define SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING "SDL.gpu.device.create.name" -#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN "SDL.gpu.device.create.shaders.private" -#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN "SDL.gpu.device.create.shaders.spirv" -#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN "SDL.gpu.device.create.shaders.dxbc" -#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN "SDL.gpu.device.create.shaders.dxil" -#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN "SDL.gpu.device.create.shaders.msl" -#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN "SDL.gpu.device.create.shaders.metallib" -#define SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING "SDL.gpu.device.create.d3d12.semantic" +#define SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN "SDL.gpu.device.create.debugmode" +#define SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN "SDL.gpu.device.create.preferlowpower" +#define SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN "SDL.gpu.device.create.verbose" +#define SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING "SDL.gpu.device.create.name" +#define SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN "SDL.gpu.device.create.feature.clip_distance" +#define SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN "SDL.gpu.device.create.feature.depth_clamping" +#define SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN "SDL.gpu.device.create.feature.indirect_draw_first_instance" +#define SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN "SDL.gpu.device.create.feature.anisotropy" +#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN "SDL.gpu.device.create.shaders.private" +#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN "SDL.gpu.device.create.shaders.spirv" +#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN "SDL.gpu.device.create.shaders.dxbc" +#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN "SDL.gpu.device.create.shaders.dxil" +#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN "SDL.gpu.device.create.shaders.msl" +#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN "SDL.gpu.device.create.shaders.metallib" +#define SDL_PROP_GPU_DEVICE_CREATE_D3D12_ALLOW_FEWER_RESOURCE_SLOTS_BOOLEAN "SDL.gpu.device.create.d3d12.allowtier1resourcebinding" +#define SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING "SDL.gpu.device.create.d3d12.semantic" +#define SDL_PROP_GPU_DEVICE_CREATE_D3D12_AGILITY_SDK_VERSION_NUMBER "SDL.gpu.device.create.d3d12.agility_sdk_version" +#define SDL_PROP_GPU_DEVICE_CREATE_D3D12_AGILITY_SDK_PATH_STRING "SDL.gpu.device.create.d3d12.agility_sdk_path" +#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_REQUIRE_HARDWARE_ACCELERATION_BOOLEAN "SDL.gpu.device.create.vulkan.requirehardwareacceleration" +#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_OPTIONS_POINTER "SDL.gpu.device.create.vulkan.options" +#define SDL_PROP_GPU_DEVICE_CREATE_METAL_ALLOW_MACFAMILY1_BOOLEAN "SDL.gpu.device.create.metal.allowmacfamily1" + + +/** + * A structure specifying additional options when using Vulkan. + * + * When no such structure is provided, SDL will use Vulkan API version 1.0 and + * a minimal set of features. The requested API version influences how the + * feature_list is processed by SDL. When requesting API version 1.0, the + * feature_list is ignored. Only the vulkan_10_physical_device_features and + * the extension lists are used. When requesting API version 1.1, the + * feature_list is scanned for feature structures introduced in Vulkan 1.1. + * When requesting Vulkan 1.2 or higher, the feature_list is additionally + * scanned for compound feature structs such as + * VkPhysicalDeviceVulkan11Features. The device and instance extension lists, + * as well as vulkan_10_physical_device_features, are always processed. + * + * \since This struct is available since SDL 3.4.0. + */ +typedef struct SDL_GPUVulkanOptions +{ + Uint32 vulkan_api_version; /**< The Vulkan API version to request for the instance. Use Vulkan's VK_MAKE_VERSION or VK_MAKE_API_VERSION. */ + void *feature_list; /**< Pointer to the first element of a chain of Vulkan feature structs. (Requires API version 1.1 or higher.)*/ + void *vulkan_10_physical_device_features; /**< Pointer to a VkPhysicalDeviceFeatures struct to enable additional Vulkan 1.0 features. */ + Uint32 device_extension_count; /**< Number of additional device extensions to require. */ + const char **device_extension_names; /**< Pointer to a list of additional device extensions to require. */ + Uint32 instance_extension_count; /**< Number of additional instance extensions to require. */ + const char **instance_extension_names; /**< Pointer to a list of additional instance extensions to require. */ +} SDL_GPUVulkanOptions; /** * Destroys a GPU context previously returned by SDL_CreateGPUDevice. @@ -2250,6 +2472,116 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGPUDeviceDriver(SDL_GPUDevice *d */ extern SDL_DECLSPEC SDL_GPUShaderFormat SDLCALL SDL_GetGPUShaderFormats(SDL_GPUDevice *device); +/** + * Get the properties associated with a GPU device. + * + * All properties are optional and may differ between GPU backends and SDL + * versions. + * + * The following properties are provided by SDL: + * + * `SDL_PROP_GPU_DEVICE_NAME_STRING`: Contains the name of the underlying + * device as reported by the system driver. This string has no standardized + * format, is highly inconsistent between hardware devices and drivers, and is + * able to change at any time. Do not attempt to parse this string as it is + * bound to fail at some point in the future when system drivers are updated, + * new hardware devices are introduced, or when SDL adds new GPU backends or + * modifies existing ones. + * + * Strings that have been found in the wild include: + * + * - GTX 970 + * - GeForce GTX 970 + * - NVIDIA GeForce GTX 970 + * - Microsoft Direct3D12 (NVIDIA GeForce GTX 970) + * - NVIDIA Graphics Device + * - GeForce GPU + * - P106-100 + * - AMD 15D8:C9 + * - AMD Custom GPU 0405 + * - AMD Radeon (TM) Graphics + * - ASUS Radeon RX 470 Series + * - Intel(R) Arc(tm) A380 Graphics (DG2) + * - Virtio-GPU Venus (NVIDIA TITAN V) + * - SwiftShader Device (LLVM 16.0.0) + * - llvmpipe (LLVM 15.0.4, 256 bits) + * - Microsoft Basic Render Driver + * - unknown device + * + * The above list shows that the same device can have different formats, the + * vendor name may or may not appear in the string, the included vendor name + * may not be the vendor of the chipset on the device, some manufacturers + * include pseudo-legal marks while others don't, some devices may not use a + * marketing name in the string, the device string may be wrapped by the name + * of a translation interface, the device may be emulated in software, or the + * string may contain generic text that does not identify the device at all. + * + * `SDL_PROP_GPU_DEVICE_DRIVER_NAME_STRING`: Contains the self-reported name + * of the underlying system driver. + * + * Strings that have been found in the wild include: + * + * - Intel Corporation + * - Intel open-source Mesa driver + * - Qualcomm Technologies Inc. Adreno Vulkan Driver + * - MoltenVK + * - Mali-G715 + * - venus + * + * `SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING`: Contains the self-reported + * version of the underlying system driver. This is a relatively short version + * string in an unspecified format. If SDL_PROP_GPU_DEVICE_DRIVER_INFO_STRING + * is available then that property should be preferred over this one as it may + * contain additional information that is useful for identifying the exact + * driver version used. + * + * Strings that have been found in the wild include: + * + * - 53.0.0 + * - 0.405.2463 + * - 32.0.15.6614 + * + * `SDL_PROP_GPU_DEVICE_DRIVER_INFO_STRING`: Contains the detailed version + * information of the underlying system driver as reported by the driver. This + * is an arbitrary string with no standardized format and it may contain + * newlines. This property should be preferred over + * SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING if it is available as it usually + * contains the same information but in a format that is easier to read. + * + * Strings that have been found in the wild include: + * + * - 101.6559 + * - 1.2.11 + * - Mesa 21.2.2 (LLVM 12.0.1) + * - Mesa 22.2.0-devel (git-f226222 2022-04-14 impish-oibaf-ppa) + * - v1.r53p0-00eac0.824c4f31403fb1fbf8ee1042422c2129 + * + * This string has also been observed to be a multiline string (which has a + * trailing newline): + * + * ``` + * Driver Build: 85da404, I46ff5fc46f, 1606794520 + * Date: 11/30/20 + * Compiler Version: EV031.31.04.01 + * Driver Branch: promo490_3_Google + * ``` + * + * \param device a GPU context to query. + * \returns a valid property ID on success or 0 on failure; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetGPUDeviceProperties(SDL_GPUDevice *device); + +#define SDL_PROP_GPU_DEVICE_NAME_STRING "SDL.gpu.device.name" +#define SDL_PROP_GPU_DEVICE_DRIVER_NAME_STRING "SDL.gpu.device.driver_name" +#define SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING "SDL.gpu.device.driver_version" +#define SDL_PROP_GPU_DEVICE_DRIVER_INFO_STRING "SDL.gpu.device.driver_info" + + /* State Creation */ /** @@ -2440,7 +2772,8 @@ extern SDL_DECLSPEC SDL_GPUShader * SDLCALL SDL_CreateGPUShader( * Creates a texture object to be used in graphics or compute workflows. * * The contents of this texture are undefined until data is written to the - * texture. + * texture, either via SDL_UploadToGPUTexture or by performing a render or + * compute pass with this texture as a target. * * Note that certain combinations of usage flags are invalid. For example, a * texture cannot have both the SAMPLER and GRAPHICS_STORAGE_READ flags. @@ -2482,6 +2815,8 @@ extern SDL_DECLSPEC SDL_GPUShader * SDLCALL SDL_CreateGPUShader( * * \sa SDL_UploadToGPUTexture * \sa SDL_DownloadFromGPUTexture + * \sa SDL_BeginGPURenderPass + * \sa SDL_BeginGPUComputePass * \sa SDL_BindGPUVertexSamplers * \sa SDL_BindGPUVertexStorageTextures * \sa SDL_BindGPUFragmentSamplers @@ -2638,6 +2973,12 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetGPUTextureName( * * Useful for debugging. * + * On Direct3D 12, using SDL_InsertGPUDebugLabel requires + * WinPixEventRuntime.dll to be in your PATH or in the same directory as your + * executable. See + * [here](https://devblogs.microsoft.com/pix/winpixeventruntime/) + * for instructions on how to obtain it. + * * \param command_buffer a command buffer. * \param text a UTF-8 string constant to insert as the label. * @@ -2648,7 +2989,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_InsertGPUDebugLabel( const char *text); /** - * Begins a debug group with an arbitary name. + * Begins a debug group with an arbitrary name. * * Used for denoting groups of calls when viewing the command buffer * callstream in a graphics debugging tool. @@ -2656,6 +2997,11 @@ extern SDL_DECLSPEC void SDLCALL SDL_InsertGPUDebugLabel( * Each call to SDL_PushGPUDebugGroup must have a corresponding call to * SDL_PopGPUDebugGroup. * + * On Direct3D 12, using SDL_PushGPUDebugGroup requires WinPixEventRuntime.dll + * to be in your PATH or in the same directory as your executable. See + * [here](https://devblogs.microsoft.com/pix/winpixeventruntime/) + * for instructions on how to obtain it. + * * On some backends (e.g. Metal), pushing a debug group during a * render/blit/compute pass will create a group that is scoped to the native * pass rather than the command buffer. For best results, if you push a debug @@ -2675,6 +3021,11 @@ extern SDL_DECLSPEC void SDLCALL SDL_PushGPUDebugGroup( /** * Ends the most-recently pushed debug group. * + * On Direct3D 12, using SDL_PopGPUDebugGroup requires WinPixEventRuntime.dll + * to be in your PATH or in the same directory as your executable. See + * [here](https://devblogs.microsoft.com/pix/winpixeventruntime/) + * for instructions on how to obtain it. + * * \param command_buffer a command buffer. * * \since This function is available since SDL 3.2.0. @@ -2816,12 +3167,15 @@ extern SDL_DECLSPEC SDL_GPUCommandBuffer * SDLCALL SDL_AcquireGPUCommandBuffer( /** * Pushes data to a vertex uniform slot on the command buffer. * - * Subsequent draw calls will use this uniform data. + * Subsequent draw calls in this command buffer will use this uniform data. * * The data being pushed must respect std140 layout conventions. In practical * terms this means you must ensure that vec3 and vec4 fields are 16-byte * aligned. * + * For detailed information about accessing uniform data from a shader, please + * refer to SDL_CreateGPUShader. + * * \param command_buffer a command buffer. * \param slot_index the vertex uniform slot to push data to. * \param data client data to write. @@ -2838,7 +3192,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_PushGPUVertexUniformData( /** * Pushes data to a fragment uniform slot on the command buffer. * - * Subsequent draw calls will use this uniform data. + * Subsequent draw calls in this command buffer will use this uniform data. * * The data being pushed must respect std140 layout conventions. In practical * terms this means you must ensure that vec3 and vec4 fields are 16-byte @@ -2860,7 +3214,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_PushGPUFragmentUniformData( /** * Pushes data to a uniform slot on the command buffer. * - * Subsequent draw calls will use this uniform data. + * Subsequent draw calls in this command buffer will use this uniform data. * * The data being pushed must respect std140 layout conventions. In practical * terms this means you must ensure that vec3 and vec4 fields are 16-byte @@ -2892,6 +3246,14 @@ extern SDL_DECLSPEC void SDLCALL SDL_PushGPUComputeUniformData( * is called. You cannot begin another render pass, or begin a compute pass or * copy pass until you have ended the render pass. * + * Using SDL_GPU_LOADOP_LOAD before any contents have been written to the + * texture subresource will result in undefined behavior. SDL_GPU_LOADOP_CLEAR + * will set the contents of the texture subresource to a single value before + * any rendering is performed. It's fine to do an empty render pass using + * SDL_GPU_STOREOP_STORE to clear a texture, but in general it's better to + * think of clearing not as an independent operation but as something that's + * done as the beginning of a render pass. + * * \param command_buffer a command buffer. * \param color_target_infos an array of texture subresources with * corresponding clear values and load/store ops. @@ -3338,7 +3700,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputePipeline( * The textures must have been created with SDL_GPU_TEXTUREUSAGE_SAMPLER. * * Be sure your shader is set up according to the requirements documented in - * SDL_CreateGPUShader(). + * SDL_CreateGPUComputePipeline(). * * \param compute_pass a compute pass handle. * \param first_slot the compute sampler slot to begin binding from. @@ -3349,7 +3711,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputePipeline( * * \since This function is available since SDL 3.2.0. * - * \sa SDL_CreateGPUShader + * \sa SDL_CreateGPUComputePipeline */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeSamplers( SDL_GPUComputePass *compute_pass, @@ -3364,7 +3726,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeSamplers( * SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ. * * Be sure your shader is set up according to the requirements documented in - * SDL_CreateGPUShader(). + * SDL_CreateGPUComputePipeline(). * * \param compute_pass a compute pass handle. * \param first_slot the compute storage texture slot to begin binding from. @@ -3373,7 +3735,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeSamplers( * * \since This function is available since SDL 3.2.0. * - * \sa SDL_CreateGPUShader + * \sa SDL_CreateGPUComputePipeline */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeStorageTextures( SDL_GPUComputePass *compute_pass, @@ -3388,7 +3750,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeStorageTextures( * SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ. * * Be sure your shader is set up according to the requirements documented in - * SDL_CreateGPUShader(). + * SDL_CreateGPUComputePipeline(). * * \param compute_pass a compute pass handle. * \param first_slot the compute storage buffer slot to begin binding from. @@ -3397,7 +3759,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeStorageTextures( * * \since This function is available since SDL 3.2.0. * - * \sa SDL_CreateGPUShader + * \sa SDL_CreateGPUComputePipeline */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeStorageBuffers( SDL_GPUComputePass *compute_pass, @@ -3514,6 +3876,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnmapGPUTransferBuffer( * \returns a copy pass handle. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_EndGPUCopyPass */ extern SDL_DECLSPEC SDL_GPUCopyPass * SDLCALL SDL_BeginGPUCopyPass( SDL_GPUCommandBuffer *command_buffer); @@ -3567,6 +3931,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_UploadToGPUBuffer( * This copy occurs on the GPU timeline. You may assume the copy has finished * in subsequent commands. * + * This function does not support copying between depth and color textures. + * For those, copy the texture to a buffer and then to the destination + * texture. + * * \param copy_pass a copy pass handle. * \param source a source texture region. * \param destination a destination texture region. @@ -3775,7 +4143,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ReleaseWindowFromGPUDevice( * supported via SDL_WindowSupportsGPUPresentMode / * SDL_WindowSupportsGPUSwapchainComposition prior to calling this function. * - * SDL_GPU_PRESENTMODE_VSYNC with SDL_GPU_SWAPCHAINCOMPOSITION_SDR are always + * SDL_GPU_PRESENTMODE_VSYNC with SDL_GPU_SWAPCHAINCOMPOSITION_SDR is always * supported. * * \param device a GPU context. @@ -3849,7 +4217,9 @@ extern SDL_DECLSPEC SDL_GPUTextureFormat SDLCALL SDL_GetGPUSwapchainTextureForma * buffer used to acquire it. * * This function will fill the swapchain texture handle with NULL if too many - * frames are in flight. This is not an error. + * frames are in flight. This is not an error. This NULL pointer should not be + * passed back into SDL. Instead, it should be considered as an indication to + * wait until the swapchain is available. * * If you use this function, it is possible to create a situation where many * command buffers are allocated while the rendering context waits for the GPU @@ -4171,6 +4541,29 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_CalculateGPUTextureFormatSize( Uint32 height, Uint32 depth_or_layer_count); +/** + * Get the SDL pixel format corresponding to a GPU texture format. + * + * \param format a texture format. + * \returns the corresponding pixel format, or SDL_PIXELFORMAT_UNKNOWN if + * there is no corresponding pixel format. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC SDL_PixelFormat SDLCALL SDL_GetPixelFormatFromGPUTextureFormat(SDL_GPUTextureFormat format); + +/** + * Get the GPU texture format corresponding to an SDL pixel format. + * + * \param format a pixel format. + * \returns the corresponding GPU texture format, or + * SDL_GPU_TEXTUREFORMAT_INVALID if there is no corresponding GPU + * texture format. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC SDL_GPUTextureFormat SDLCALL SDL_GetGPUTextureFormatFromPixelFormat(SDL_PixelFormat format); + #ifdef SDL_PLATFORM_GDK /** diff --git a/vendor/sdl3/include/SDL_guid.h b/vendor/sdl3/include/SDL_guid.h index 312c42c03..cf9df31ce 100644 --- a/vendor/sdl3/include/SDL_guid.h +++ b/vendor/sdl3/include/SDL_guid.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_haptic.h b/vendor/sdl3/include/SDL_haptic.h index a45335b28..1cd9ddc0d 100644 --- a/vendor/sdl3/include/SDL_haptic.h +++ b/vendor/sdl3/include/SDL_haptic.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -70,7 +70,7 @@ * { * SDL_Haptic *haptic; * SDL_HapticEffect effect; - * int effect_id; + * SDL_HapticEffectID effect_id; * * // Open the device * haptic = SDL_OpenHapticFromJoystick(joystick); @@ -149,6 +149,19 @@ extern "C" { */ typedef struct SDL_Haptic SDL_Haptic; +/* + * Misc defines. + */ + +/** + * Used to play a device an infinite number of times. + * + * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_RunHapticEffect + */ +#define SDL_HAPTIC_INFINITY 4294967295U + /** * \name Haptic features @@ -162,6 +175,11 @@ typedef struct SDL_Haptic SDL_Haptic; */ /* @{ */ +/** + * Type of haptic effect. + */ +typedef Uint16 SDL_HapticEffectType; + /** * Constant effect supported. * @@ -383,6 +401,11 @@ typedef struct SDL_Haptic SDL_Haptic; */ /* @{ */ +/** + * Type of coordinates used for haptic direction. + */ +typedef Uint8 SDL_HapticDirectionType; + /** * Uses polar coordinates for the direction. * @@ -426,18 +449,15 @@ typedef struct SDL_Haptic SDL_Haptic; /* @} *//* Haptic features */ -/* - * Misc defines. - */ /** - * Used to play a device an infinite number of times. + * ID for haptic effects. * - * \since This macro is available since SDL 3.2.0. + * This is -1 if the ID is invalid. * - * \sa SDL_RunHapticEffect + * \sa SDL_CreateHapticEffect */ -#define SDL_HAPTIC_INFINITY 4294967295U +typedef int SDL_HapticEffectID; /** @@ -545,8 +565,8 @@ typedef struct SDL_Haptic SDL_Haptic; */ typedef struct SDL_HapticDirection { - Uint8 type; /**< The type of encoding. */ - Sint32 dir[3]; /**< The encoded direction. */ + SDL_HapticDirectionType type; /**< The type of encoding. */ + Sint32 dir[3]; /**< The encoded direction. */ } SDL_HapticDirection; @@ -566,7 +586,7 @@ typedef struct SDL_HapticDirection typedef struct SDL_HapticConstant { /* Header */ - Uint16 type; /**< SDL_HAPTIC_CONSTANT */ + SDL_HapticEffectType type; /**< SDL_HAPTIC_CONSTANT */ SDL_HapticDirection direction; /**< Direction of the effect. */ /* Replay */ @@ -652,9 +672,9 @@ typedef struct SDL_HapticConstant typedef struct SDL_HapticPeriodic { /* Header */ - Uint16 type; /**< SDL_HAPTIC_SINE, SDL_HAPTIC_SQUARE - SDL_HAPTIC_TRIANGLE, SDL_HAPTIC_SAWTOOTHUP or - SDL_HAPTIC_SAWTOOTHDOWN */ + SDL_HapticEffectType type; /**< SDL_HAPTIC_SINE, SDL_HAPTIC_SQUARE + SDL_HAPTIC_TRIANGLE, SDL_HAPTIC_SAWTOOTHUP or + SDL_HAPTIC_SAWTOOTHDOWN */ SDL_HapticDirection direction; /**< Direction of the effect. */ /* Replay */ @@ -708,8 +728,8 @@ typedef struct SDL_HapticPeriodic typedef struct SDL_HapticCondition { /* Header */ - Uint16 type; /**< SDL_HAPTIC_SPRING, SDL_HAPTIC_DAMPER, - SDL_HAPTIC_INERTIA or SDL_HAPTIC_FRICTION */ + SDL_HapticEffectType type; /**< SDL_HAPTIC_SPRING, SDL_HAPTIC_DAMPER, + SDL_HAPTIC_INERTIA or SDL_HAPTIC_FRICTION */ SDL_HapticDirection direction; /**< Direction of the effect. */ /* Replay */ @@ -747,7 +767,7 @@ typedef struct SDL_HapticCondition typedef struct SDL_HapticRamp { /* Header */ - Uint16 type; /**< SDL_HAPTIC_RAMP */ + SDL_HapticEffectType type; /**< SDL_HAPTIC_RAMP */ SDL_HapticDirection direction; /**< Direction of the effect. */ /* Replay */ @@ -786,7 +806,7 @@ typedef struct SDL_HapticRamp typedef struct SDL_HapticLeftRight { /* Header */ - Uint16 type; /**< SDL_HAPTIC_LEFTRIGHT */ + SDL_HapticEffectType type; /**< SDL_HAPTIC_LEFTRIGHT */ /* Replay */ Uint32 length; /**< Duration of the effect in milliseconds. */ @@ -816,7 +836,7 @@ typedef struct SDL_HapticLeftRight typedef struct SDL_HapticCustom { /* Header */ - Uint16 type; /**< SDL_HAPTIC_CUSTOM */ + SDL_HapticEffectType type; /**< SDL_HAPTIC_CUSTOM */ SDL_HapticDirection direction; /**< Direction of the effect. */ /* Replay */ @@ -915,7 +935,7 @@ typedef struct SDL_HapticCustom typedef union SDL_HapticEffect { /* Common for all force feedback effects */ - Uint16 type; /**< Effect type. */ + SDL_HapticEffectType type; /**< Effect type. */ SDL_HapticConstant constant; /**< Constant effect. */ SDL_HapticPeriodic periodic; /**< Periodic effect. */ SDL_HapticCondition condition; /**< Condition effect. */ @@ -1193,7 +1213,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HapticEffectSupported(SDL_Haptic *haptic, c * \sa SDL_RunHapticEffect * \sa SDL_UpdateHapticEffect */ -extern SDL_DECLSPEC int SDLCALL SDL_CreateHapticEffect(SDL_Haptic *haptic, const SDL_HapticEffect *effect); +extern SDL_DECLSPEC SDL_HapticEffectID SDLCALL SDL_CreateHapticEffect(SDL_Haptic *haptic, const SDL_HapticEffect *effect); /** * Update the properties of an effect. @@ -1215,7 +1235,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_CreateHapticEffect(SDL_Haptic *haptic, const * \sa SDL_CreateHapticEffect * \sa SDL_RunHapticEffect */ -extern SDL_DECLSPEC bool SDLCALL SDL_UpdateHapticEffect(SDL_Haptic *haptic, int effect, const SDL_HapticEffect *data); +extern SDL_DECLSPEC bool SDLCALL SDL_UpdateHapticEffect(SDL_Haptic *haptic, SDL_HapticEffectID effect, const SDL_HapticEffect *data); /** * Run the haptic effect on its associated haptic device. @@ -1239,7 +1259,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_UpdateHapticEffect(SDL_Haptic *haptic, int * \sa SDL_StopHapticEffect * \sa SDL_StopHapticEffects */ -extern SDL_DECLSPEC bool SDLCALL SDL_RunHapticEffect(SDL_Haptic *haptic, int effect, Uint32 iterations); +extern SDL_DECLSPEC bool SDLCALL SDL_RunHapticEffect(SDL_Haptic *haptic, SDL_HapticEffectID effect, Uint32 iterations); /** * Stop the haptic effect on its associated haptic device. @@ -1254,7 +1274,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RunHapticEffect(SDL_Haptic *haptic, int eff * \sa SDL_RunHapticEffect * \sa SDL_StopHapticEffects */ -extern SDL_DECLSPEC bool SDLCALL SDL_StopHapticEffect(SDL_Haptic *haptic, int effect); +extern SDL_DECLSPEC bool SDLCALL SDL_StopHapticEffect(SDL_Haptic *haptic, SDL_HapticEffectID effect); /** * Destroy a haptic effect on the device. @@ -1269,7 +1289,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_StopHapticEffect(SDL_Haptic *haptic, int ef * * \sa SDL_CreateHapticEffect */ -extern SDL_DECLSPEC void SDLCALL SDL_DestroyHapticEffect(SDL_Haptic *haptic, int effect); +extern SDL_DECLSPEC void SDLCALL SDL_DestroyHapticEffect(SDL_Haptic *haptic, SDL_HapticEffectID effect); /** * Get the status of the current effect on the specified haptic device. @@ -1285,7 +1305,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroyHapticEffect(SDL_Haptic *haptic, int * * \sa SDL_GetHapticFeatures */ -extern SDL_DECLSPEC bool SDLCALL SDL_GetHapticEffectStatus(SDL_Haptic *haptic, int effect); +extern SDL_DECLSPEC bool SDLCALL SDL_GetHapticEffectStatus(SDL_Haptic *haptic, SDL_HapticEffectID effect); /** * Set the global gain of the specified haptic device. diff --git a/vendor/sdl3/include/SDL_hidapi.h b/vendor/sdl3/include/SDL_hidapi.h index 131b03723..90e574c41 100644 --- a/vendor/sdl3/include/SDL_hidapi.h +++ b/vendor/sdl3/include/SDL_hidapi.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -55,6 +55,7 @@ #include #include +#include #include /* Set up for C function definitions, even when using C++ */ @@ -283,6 +284,24 @@ extern SDL_DECLSPEC SDL_hid_device * SDLCALL SDL_hid_open(unsigned short vendor_ */ extern SDL_DECLSPEC SDL_hid_device * SDLCALL SDL_hid_open_path(const char *path); +/** + * Get the properties associated with an SDL_hid_device. + * + * The following read-only properties are provided by SDL: + * + * - `SDL_PROP_HIDAPI_LIBUSB_DEVICE_HANDLE_POINTER`: the libusb_device_handle + * associated with the device, if it was opened using libusb. + * + * \param dev a device handle returned from SDL_hid_open(). + * \returns a valid property ID on success or 0 on failure; call + * SDL_GetError() for more information. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_hid_get_properties(SDL_hid_device *dev); + +#define SDL_PROP_HIDAPI_LIBUSB_DEVICE_HANDLE_POINTER "SDL.hidapi.libusb.device.handle" + /** * Write an Output report to a HID device. * diff --git a/vendor/sdl3/include/SDL_hints.h b/vendor/sdl3/include/SDL_hints.h index a08153571..857dfcec1 100644 --- a/vendor/sdl3/include/SDL_hints.h +++ b/vendor/sdl3/include/SDL_hints.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -391,12 +391,46 @@ extern "C" { * concept, so it applies to a physical audio device in this case, and not an * SDL_AudioStream, nor an SDL logical audio device. * + * For Windows WASAPI audio, the following roles are supported, and map to + * `AUDIO_STREAM_CATEGORY`: + * + * - "Other" (default) + * - "Communications" - Real-time communications, such as VOIP or chat + * - "Game" - Game audio + * - "GameChat" - Game chat audio, similar to "Communications" except that + * this will not attenuate other audio streams + * - "Movie" - Music or sound with dialog + * - "Media" - Music or sound without dialog + * + * If your application applies its own echo cancellation, gain control, and + * noise reduction it should also set SDL_HINT_AUDIO_DEVICE_RAW_STREAM. + * * This hint should be set before an audio device is opened. * * \since This hint is available since SDL 3.2.0. */ #define SDL_HINT_AUDIO_DEVICE_STREAM_ROLE "SDL_AUDIO_DEVICE_STREAM_ROLE" +/** + * Specify whether this audio device should do audio processing. + * + * Some operating systems perform echo cancellation, gain control, and noise + * reduction as needed. If your application already handles these, you can set + * this hint to prevent the OS from doing additional audio processing. + * + * This corresponds to the WASAPI audio option `AUDCLNT_STREAMOPTIONS_RAW`. + * + * The variable can be set to the following values: + * + * - "0": audio processing can be done by the OS. (default) + * - "1": audio processing is done by the application. + * + * This hint should be set before an audio device is opened. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_AUDIO_DEVICE_RAW_STREAM "SDL_AUDIO_DEVICE_RAW_STREAM" + /** * Specify the input file when recording audio using the disk audio driver. * @@ -595,7 +629,7 @@ extern "C" { * A variable that limits what CPU features are available. * * By default, SDL marks all features the current CPU supports as available. - * This hint allows to limit these to a subset. + * This hint allows the enabled features to be limited to a subset. * * When the hint is unset, or empty, SDL will enable all detected CPU * features. @@ -685,6 +719,21 @@ extern "C" { */ #define SDL_HINT_DISPLAY_USABLE_BOUNDS "SDL_DISPLAY_USABLE_BOUNDS" +/** + * Set the level of checking for invalid parameters passed to SDL functions. + * + * The variable can be set to the following values: + * + * - "1": Enable fast parameter error checking, e.g. quick NULL checks, etc. + * - "2": Enable full parameter error checking, e.g. validating objects are + * the correct type, etc. (default) + * + * This hint can be set anytime. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_INVALID_PARAM_CHECKS "SDL_INVALID_PARAM_CHECKS" + /** * Disable giving back control to the browser automatically when running with * asyncify. @@ -711,8 +760,6 @@ extern "C" { * * This hint only applies to the emscripten platform. * - * The default value is "#canvas" - * * This hint should be set before creating a window. * * \since This hint is available since SDL 3.2.0. @@ -726,7 +773,7 @@ extern "C" { * * The variable can be one of: * - * - "#window": the javascript window object (default) + * - "#window": the javascript window object * - "#document": the javascript document object * - "#screen": the javascript window.screen object * - "#canvas": the WebGL canvas element @@ -1037,6 +1084,21 @@ extern "C" { */ #define SDL_HINT_HIDAPI_LIBUSB "SDL_HIDAPI_LIBUSB" + +/** + * A variable to control whether HIDAPI uses libusb for GameCube adapters. + * + * The variable can be set to the following values: + * + * - "0": HIDAPI will not use libusb for GameCube adapters. + * - "1": HIDAPI will use libusb for GameCube adapters if available. (default) + * + * This hint should be set before SDL is initialized. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_HIDAPI_LIBUSB_GAMECUBE "SDL_HIDAPI_LIBUSB_GAMECUBE" + /** * A variable to control whether HIDAPI uses libusb only for whitelisted * devices. @@ -1143,8 +1205,8 @@ extern "C" { #define SDL_HINT_IME_IMPLEMENTED_UI "SDL_IME_IMPLEMENTED_UI" /** - * A variable controlling whether the home indicator bar on iPhone X should be - * hidden. + * A variable controlling whether the home indicator bar on iPhone X and later + * should be hidden. * * The variable can be set to the following values: * @@ -1716,13 +1778,106 @@ extern "C" { * A variable controlling whether the HIDAPI driver for HORI licensed Steam * controllers should be used. * - * This variable can be set to the following values: "0" - HIDAPI driver is - * not used "1" - HIDAPI driver is used + * The variable can be set to the following values: * - * The default is the value of SDL_HINT_JOYSTICK_HIDAPI + * - "0": HIDAPI driver is not used. + * - "1": HIDAPI driver is used. + * + * The default is the value of SDL_HINT_JOYSTICK_HIDAPI. + * + * This hint should be set before initializing joysticks and gamepads. + * + * \since This hint is available since SDL 3.2.0. */ #define SDL_HINT_JOYSTICK_HIDAPI_STEAM_HORI "SDL_JOYSTICK_HIDAPI_STEAM_HORI" +/** + * A variable controlling whether the HIDAPI driver for some Logitech wheels + * should be used. + * + * The variable can be set to the following values: + * + * - "0": HIDAPI driver is not used. + * - "1": HIDAPI driver is used. + * + * The default is the value of SDL_HINT_JOYSTICK_HIDAPI. + * + * This hint should be set before initializing joysticks and gamepads. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_JOYSTICK_HIDAPI_LG4FF "SDL_JOYSTICK_HIDAPI_LG4FF" + +/** + * A variable controlling whether the HIDAPI driver for 8BitDo controllers + * should be used. + * + * The variable can be set to the following values: + * + * - "0": HIDAPI driver is not used. + * - "1": HIDAPI driver is used. + * + * The default is the value of SDL_HINT_JOYSTICK_HIDAPI. + * + * This hint should be set before initializing joysticks and gamepads. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_JOYSTICK_HIDAPI_8BITDO "SDL_JOYSTICK_HIDAPI_8BITDO" + +/** + * A variable controlling whether the HIDAPI driver for SInput controllers + * should be used. + * + * More info - https://github.com/HandHeldLegend/SInput-HID + * + * The variable can be set to the following values: + * + * - "0": HIDAPI driver is not used. + * - "1": HIDAPI driver is used. + * + * The default is the value of SDL_HINT_JOYSTICK_HIDAPI. + * + * This hint should be set before initializing joysticks and gamepads. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_JOYSTICK_HIDAPI_SINPUT "SDL_JOYSTICK_HIDAPI_SINPUT" + +/** + * A variable controlling whether the HIDAPI driver for ZUIKI controllers + * should be used. + * + * The variable can be set to the following values: + * + * - "0": HIDAPI driver is not used. + * - "1": HIDAPI driver is used. + * + * The default is the value of SDL_HINT_JOYSTICK_HIDAPI. + * + * This hint should be set before initializing joysticks and gamepads. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_JOYSTICK_HIDAPI_ZUIKI "SDL_JOYSTICK_HIDAPI_ZUIKI" + +/** + * A variable controlling whether the HIDAPI driver for Flydigi controllers + * should be used. + * + * The variable can be set to the following values: + * + * - "0": HIDAPI driver is not used. + * - "1": HIDAPI driver is used. + * + * The default is the value of SDL_HINT_JOYSTICK_HIDAPI. + * + * This hint should be set before initializing joysticks and gamepads. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_JOYSTICK_HIDAPI_FLYDIGI "SDL_JOYSTICK_HIDAPI_FLYDIGI" + /** * A variable controlling whether the HIDAPI driver for Nintendo Switch * controllers should be used. @@ -1774,6 +1929,23 @@ extern "C" { */ #define SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED "SDL_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED" +/** + * A variable controlling whether the HIDAPI driver for Nintendo Switch 2 + * controllers should be used. + * + * The variable can be set to the following values: + * + * - "0": HIDAPI driver is not used. + * - "1": HIDAPI driver is used. + * + * The default is the value of SDL_HINT_JOYSTICK_HIDAPI. + * + * This hint should be set before initializing joysticks and gamepads. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_JOYSTICK_HIDAPI_SWITCH2 "SDL_JOYSTICK_HIDAPI_SWITCH2" + /** * A variable controlling whether Nintendo Switch Joy-Con controllers will be * in vertical mode when using the HIDAPI driver. @@ -1926,6 +2098,41 @@ extern "C" { */ #define SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED "SDL_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED" +/** + * A variable controlling whether the new HIDAPI driver for wired Xbox One + * (GIP) controllers should be used. + * + * The variable can be set to the following values: + * + * - "0": HIDAPI driver is not used. + * - "1": HIDAPI driver is used. + * + * The default is the value of SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE. + * + * This hint should be set before initializing joysticks and gamepads. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_JOYSTICK_HIDAPI_GIP "SDL_JOYSTICK_HIDAPI_GIP" + +/** + * A variable controlling whether the new HIDAPI driver for wired Xbox One + * (GIP) controllers should reset the controller if it can't get the metadata + * from the controller. + * + * The variable can be set to the following values: + * + * - "0": Assume this is a generic controller. + * - "1": Reset the controller to get metadata. + * + * By default the controller is not reset. + * + * This hint should be set before initializing joysticks and gamepads. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_JOYSTICK_HIDAPI_GIP_RESET_FOR_METADATA "SDL_JOYSTICK_HIDAPI_GIP_RESET_FOR_METADATA" + /** * A variable controlling whether IOKit should be used for controller * handling. @@ -2126,8 +2333,8 @@ extern "C" { * * The variable can be set to the following values: * - * - "0": WGI is not used. - * - "1": WGI is used. (default) + * - "0": WGI is not used. (default) + * - "1": WGI is used. * * This hint should be set before SDL is initialized. * @@ -2228,9 +2435,9 @@ extern "C" { * pressing the 1 key would yield the keycode SDLK_1, or '1', instead of * SDLK_AMPERSAND, or '&' * - "latin_letters": For keyboards using non-Latin letters, such as Russian - * or Thai, the letter keys generate keycodes as though it had an en_US - * layout. e.g. pressing the key associated with SDL_SCANCODE_A on a Russian - * keyboard would yield 'a' instead of a Cyrillic letter. + * or Thai, the letter keys generate keycodes as though it had an English + * QWERTY layout. e.g. pressing the key associated with SDL_SCANCODE_A on a + * Russian keyboard would yield 'a' instead of a Cyrillic letter. * * The default value for this hint is "french_numbers,latin_letters" * @@ -2289,6 +2496,27 @@ extern "C" { */ #define SDL_HINT_KMSDRM_REQUIRE_DRM_MASTER "SDL_KMSDRM_REQUIRE_DRM_MASTER" +/** + * A variable that controls whether KMSDRM will use "atomic" functionality. + * + * The KMSDRM backend can use atomic commits, if both DRM_CLIENT_CAP_ATOMIC + * and DRM_CLIENT_CAP_UNIVERSAL_PLANES is supported by the system. As of SDL + * 3.4.0, it will favor this functionality, but in case this doesn't work well + * on a given system or other surprises, this hint can be used to disable it. + * + * This hint can not enable the functionality if it isn't available. + * + * The variable can be set to the following values: + * + * - "0": SDL will not use the KMSDRM "atomic" functionality. + * - "1": SDL will allow usage of the KMSDRM "atomic" functionality. (default) + * + * This hint should be set before SDL is initialized. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_KMSDRM_ATOMIC "SDL_KMSDRM_ATOMIC" + /** * A variable controlling the default SDL log levels. * @@ -2309,6 +2537,11 @@ extern "C" { * * `app=info,assert=warn,test=verbose,*=error` * + * If the `DEBUG_INVOCATION` environment variable is set to "1", the default + * log levels are equivalent to: + * + * `assert=warn,test=verbose,*=debug` + * * This hint can be set anytime. * * \since This hint is available since SDL 3.2.0. @@ -2410,6 +2643,21 @@ extern "C" { */ #define SDL_HINT_MAC_SCROLL_MOMENTUM "SDL_MAC_SCROLL_MOMENTUM" +/** + * A variable controlling whether holding down a key will repeat the pressed + * key or open the accents menu on macOS. + * + * The variable can be set to the following values: + * + * - "0": Holding a key will repeat the pressed key. + * - "1": Holding a key will open the accents menu for that key. (default) + * + * This hint needs to be set before SDL_Init(). + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_MAC_PRESS_AND_HOLD "SDL_MAC_PRESS_AND_HOLD" + /** * Request SDL_AppIterate() be called at a specific rate. * @@ -2430,6 +2678,10 @@ extern "C" { * This defaults to 0, and specifying NULL for the hint's value will restore * the default. * + * This doesn't have to be an integer value. For example, "59.94" won't be + * rounded to an integer rate; the digits after the decimal are actually + * respected. + * * This hint can be set anytime. * * \since This hint is available since SDL 3.2.0. @@ -2485,6 +2737,24 @@ extern "C" { */ #define SDL_HINT_MOUSE_DEFAULT_SYSTEM_CURSOR "SDL_MOUSE_DEFAULT_SYSTEM_CURSOR" +/** + * A variable setting whether we should scale cursors by the current display + * scale. + * + * The variable can be set to the following values: + * + * - "0": Cursors will not change size based on the display content scale. + * (default) + * - "1": Cursors will automatically match the display content scale (e.g. a + * 2x sized cursor will be used when the window is on a monitor with 200% + * scale). This is currently implemented on Windows and Wayland. + * + * This hint needs to be set before creating cursors. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_MOUSE_DPI_SCALE_CURSORS "SDL_MOUSE_DPI_SCALE_CURSORS" + /** * A variable controlling whether warping a hidden mouse cursor will activate * relative mouse mode. @@ -2493,7 +2763,7 @@ extern "C" { * the window center occur within a short time period, SDL will emulate mouse * warps using relative mouse mode. This can provide smoother and more * reliable mouse motion for some older games, which continuously calculate - * the distance travelled by the mouse pointer and warp it back to the center + * the distance traveled by the mouse pointer and warp it back to the center * of the window, rather than using relative mouse motion. * * Note that relative mouse mode may have different mouse acceleration @@ -2736,6 +3006,46 @@ extern "C" { */ #define SDL_HINT_OPENGL_ES_DRIVER "SDL_OPENGL_ES_DRIVER" +/** + * A variable controlling whether to force an sRGB-capable OpenGL context. + * + * At OpenGL context creation time, some platforms can request an sRGB-capable + * context. However, sometimes any form of the request can cause surprising + * results on some drivers, platforms, and hardware. Usually the surprise is + * in the form of rendering that is either a little darker or a little + * brighter than intended. + * + * This hint allows the user to override the app's sRGB requests and either + * force a specific value, or avoid requesting anything at all, depending on + * what makes things work correctly for their system. + * + * This is meant as a fail-safe; apps should probably not explicitly set this, + * and most users should not, either. + * + * Note that some platforms cannot make this request at all, and on all + * platforms this request can be denied by the operating system. + * + * In addition to attempting to obtain the type of sRGB-capable OpenGL context + * requested by this hint, SDL will try to force the state of + * GL_FRAMEBUFFER_SRGB on the new context, if appropriate. + * + * The variable can be set to the following values: + * + * - "0": Force a request for an OpenGL context that is _not_ sRGB-capable. + * - "1": Force a request for an OpenGL context that _is_ sRGB-capable. + * - "skip": Don't make any request for an sRGB-capable context + * (don't specify the attribute at all during context creation time). + * - any other string is undefined behavior. + * + * If unset, or set to an empty string, SDL will make a request using the + * value the app specified with the SDL_GL_FRAMEBUFFER_SRGB_CAPABLE attribute. + * + * This hint should be set before an OpenGL context is created. + * + * \since This hint is available since SDL 3.4.2. + */ +#define SDL_HINT_OPENGL_FORCE_SRGB_FRAMEBUFFER "SDL_OPENGL_FORCE_SRGB_FRAMEBUFFER" + /** * Mechanism to specify openvr_api library location * @@ -2859,6 +3169,24 @@ extern "C" { */ #define SDL_HINT_RENDER_DIRECT3D11_DEBUG "SDL_RENDER_DIRECT3D11_DEBUG" +/** + * A variable controlling whether to use the Direct3D 11 WARP software + * rasterizer. + * + * For more information, see: + * https://learn.microsoft.com/en-us/windows/win32/direct3darticles/directx-warp + * + * The variable can be set to the following values: + * + * - "0": Disable WARP rasterizer. (default) + * - "1": Enable WARP rasterizer. + * + * This hint should be set before creating a renderer. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_RENDER_DIRECT3D11_WARP "SDL_RENDER_DIRECT3D11_WARP" + /** * A variable controlling whether to enable Vulkan Validation Layers. * @@ -3041,6 +3369,49 @@ extern "C" { */ #define SDL_HINT_ROG_GAMEPAD_MICE_EXCLUDED "SDL_ROG_GAMEPAD_MICE_EXCLUDED" +/** + * A variable controlling the width of the PS2's framebuffer in pixels. + * + * By default, the variable is "640". + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_PS2_GS_WIDTH "SDL_PS2_GS_WIDTH" + +/** + * A variable controlling the height of the PS2's framebuffer in pixels. + * + * By default, the variable is "448". + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_PS2_GS_HEIGHT "SDL_PS2_GS_HEIGHT" + +/** + * A variable controlling whether the signal is interlaced or progressive. + * + * The variable can be set to the following values: + * + * - "0": Image is interlaced. (default) + * - "1": Image is progressive. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_PS2_GS_PROGRESSIVE "SDL_PS2_GS_PROGRESSIVE" + +/** + * A variable controlling the video mode of the console. + * + * The variable can be set to the following values: + * + * - "": Console-native. (default) + * - "NTSC": 60hz region. + * - "PAL": 50hz region. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_PS2_GS_MODE "SDL_PS2_GS_MODE" + /** * A variable controlling which Dispmanx layer to use on a Raspberry PI. * @@ -3267,10 +3638,12 @@ extern "C" { * prioritized in the list of displays, as exposed by calling * SDL_GetDisplays(), with the first listed becoming the primary display. The * naming convention can vary depending on the environment, but it is usually - * a connector name (e.g. 'DP-1', 'DP-2', 'HDMI-A-1',etc...). + * a connector name (e.g. 'DP-1', 'DP-2', 'HDMI-A-1', etc...). * - * On Wayland and X11 desktops, the connector names associated with displays - * can typically be found by using the `xrandr` utility. + * On Wayland desktops, the connector names associated with displays can be + * found in the `name` property of the info output from `wayland-info -i + * wl_output`. On X11 desktops, the `xrandr` utility can be used to retrieve + * the connector names associated with displays. * * This hint is currently supported on the following drivers: * @@ -3407,6 +3780,43 @@ extern "C" { */ #define SDL_HINT_VIDEO_MAC_FULLSCREEN_MENU_VISIBILITY "SDL_VIDEO_MAC_FULLSCREEN_MENU_VISIBILITY" +/** + * A variable indicating whether the metal layer drawable size should be + * updated for the SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED event on macOS. + * + * The variable can be set to the following values: + * + * - "0": the metal layer drawable size will not be updated on the + * SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED event. + * - "1": the metal layer drawable size will be updated on the + * SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED event. (default) + * + * This hint should be set before SDL_Metal_CreateView called. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_VIDEO_METAL_AUTO_RESIZE_DRAWABLE "SDL_VIDEO_METAL_AUTO_RESIZE_DRAWABLE" + +/** + * A variable controlling whether SDL will attempt to automatically set the + * destination display to a mode most closely matching that of the previous + * display if an exclusive fullscreen window is moved onto it. + * + * The variable can be set to the following values: + * + * - "0": SDL will not attempt to automatically set a matching mode on the + * destination display. If an exclusive fullscreen window is moved to a new + * display, the window will become fullscreen desktop. + * - "1": SDL will attempt to automatically set a mode on the destination + * display that most closely matches the mode of the display that the + * exclusive fullscreen window was previously on. (default) + * + * This hint can be set anytime. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_VIDEO_MATCH_EXCLUSIVE_MODE_ON_MOVE "SDL_VIDEO_MATCH_EXCLUSIVE_MODE_ON_MOVE" + /** * A variable controlling whether fullscreen windows are minimized when they * lose focus. @@ -3414,8 +3824,10 @@ extern "C" { * The variable can be set to the following values: * * - "0": Fullscreen windows will not be minimized when they lose focus. - * (default) * - "1": Fullscreen windows are minimized when they lose focus. + * - "auto": Fullscreen windows are minimized when they lose focus if they use + * exclusive fullscreen modes, so the desktop video mode is restored. + * (default) * * This hint can be set anytime. * @@ -4061,15 +4473,14 @@ extern "C" { * * The variable can be set to the following values: * - * - "0": GameInput is not used for raw keyboard and mouse events. + * - "0": GameInput is not used for raw keyboard and mouse events. (default) * - "1": GameInput is used for raw keyboard and mouse events, if available. - * (default) * * This hint should be set before SDL is initialized. * * \since This hint is available since SDL 3.2.0. */ -#define SDL_HINT_WINDOWS_GAMEINPUT "SDL_WINDOWS_GAMEINPUT" +#define SDL_HINT_WINDOWS_GAMEINPUT "SDL_WINDOWS_GAMEINPUT" /** * A variable controlling whether raw keyboard events are used on Windows. @@ -4085,6 +4496,28 @@ extern "C" { */ #define SDL_HINT_WINDOWS_RAW_KEYBOARD "SDL_WINDOWS_RAW_KEYBOARD" +/** + * A variable controlling whether or not the RIDEV_NOHOTKEYS flag is set when + * enabling Windows raw keyboard events. + * + * This blocks any hotkeys that have been registered by applications from + * having any effect beyond generating raw WM_INPUT events. + * + * This flag does not affect system-hotkeys like ALT-TAB or CTRL-ALT-DEL, but + * does affect the Windows Logo key since it is a userland hotkey registered + * by explorer.exe. + * + * The variable can be set to the following values: + * + * - "0": Hotkeys are not excluded. (default) + * - "1": Hotkeys are excluded. + * + * This hint can be set anytime. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_WINDOWS_RAW_KEYBOARD_EXCLUDE_HOTKEYS "SDL_WINDOWS_RAW_KEYBOARD_EXCLUDE_HOTKEYS" + /** * A variable controlling whether SDL uses Kernel Semaphores on Windows. * @@ -4114,7 +4547,7 @@ extern "C" { * * \since This hint is available since SDL 3.2.0. */ -#define SDL_HINT_WINDOWS_INTRESOURCE_ICON "SDL_WINDOWS_INTRESOURCE_ICON" +#define SDL_HINT_WINDOWS_INTRESOURCE_ICON "SDL_WINDOWS_INTRESOURCE_ICON" /** * A variable to specify custom icon resource id from RC file on Windows @@ -4287,7 +4720,6 @@ extern "C" { */ #define SDL_HINT_PEN_TOUCH_EVENTS "SDL_PEN_TOUCH_EVENTS" - /** * An enumeration of hint priorities. * @@ -4386,19 +4818,14 @@ extern SDL_DECLSPEC void SDLCALL SDL_ResetHints(void); * \param name the hint to query. * \returns the string value of a hint or NULL if the hint isn't set. * - * \threadsafety It is safe to call this function from any thread, however the - * return value only remains valid until the hint is changed; if - * another thread might do so, the app should supply locks - * and/or make a copy of the string. Note that using a hint - * callback instead is always thread-safe, as SDL holds a lock - * on the thread subsystem during the callback. + * \threadsafety It is safe to call this function from any thread. * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetHint * \sa SDL_SetHintWithPriority */ -extern SDL_DECLSPEC const char * SDLCALL SDL_GetHint(const char *name); +extern SDL_DECLSPEC const char *SDLCALL SDL_GetHint(const char *name); /** * Get the boolean value of a hint variable. @@ -4474,8 +4901,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_AddHintCallback(const char *name, SDL_HintC * \sa SDL_AddHintCallback */ extern SDL_DECLSPEC void SDLCALL SDL_RemoveHintCallback(const char *name, - SDL_HintCallback callback, - void *userdata); + SDL_HintCallback callback, + void *userdata); /* Ends C function definitions when using C++ */ #ifdef __cplusplus diff --git a/vendor/sdl3/include/SDL_init.h b/vendor/sdl3/include/SDL_init.h index 27ebe4b0e..d75ccc31d 100644 --- a/vendor/sdl3/include/SDL_init.h +++ b/vendor/sdl3/include/SDL_init.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -101,7 +101,7 @@ typedef Uint32 SDL_InitFlags; * to run. * * See - * [Main callbacks in SDL3](https://wiki.libsdl.org/SDL3/README/main-functions#main-callbacks-in-sdl3) + * [Main callbacks in SDL3](https://wiki.libsdl.org/SDL3/README-main-functions#main-callbacks-in-sdl3) * for complete details. * * \since This enum is available since SDL 3.2.0. @@ -224,6 +224,8 @@ typedef void (SDLCALL *SDL_AppQuit_func)(void *appstate, SDL_AppResult result); * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function should only be called on the main thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetAppMetadata @@ -244,6 +246,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_Init(SDL_InitFlags flags); * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function should only be called on the main thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_Init @@ -260,6 +264,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_InitSubSystem(SDL_InitFlags flags); * * \param flags any of the flags used by SDL_Init(); see SDL_Init for details. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_InitSubSystem @@ -274,6 +280,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_QuitSubSystem(SDL_InitFlags flags); * \returns a mask of all initialized subsystems if `flags` is 0, otherwise it * returns the initialization status of the specified subsystems. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_Init @@ -292,6 +300,8 @@ extern SDL_DECLSPEC SDL_InitFlags SDLCALL SDL_WasInit(SDL_InitFlags flags); * application is shutdown, but it is not wise to do this from a library or * other dynamically loaded code. * + * \threadsafety This function should only be called on the main thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_Init diff --git a/vendor/sdl3/include/SDL_intrin.h b/vendor/sdl3/include/SDL_intrin.h index bac6d7ad4..59a3831e2 100644 --- a/vendor/sdl3/include/SDL_intrin.h +++ b/vendor/sdl3/include/SDL_intrin.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -268,6 +268,7 @@ _m_prefetch(void *__P) #endif /* compiler version */ #ifdef SDL_WIKI_DOCUMENTATION_SECTION + /** * A macro to decide if the compiler supports `__attribute__((target))`. * @@ -280,12 +281,14 @@ _m_prefetch(void *__P) * \sa SDL_TARGETING */ #define SDL_HAS_TARGET_ATTRIBS - +#elif defined(__loongarch64) && defined(__GNUC__) && (__GNUC__ >= 15) +/* LoongArch requires GCC 15+ for target attribute support */ +# define SDL_HAS_TARGET_ATTRIBS #elif defined(__clang__) && defined(__has_attribute) # if __has_attribute(target) # define SDL_HAS_TARGET_ATTRIBS # endif -#elif defined(__GNUC__) && (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) /* gcc >= 4.9 */ +#elif defined(__GNUC__) && !defined(__loongarch64) && (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) /* gcc >= 4.9 */ # define SDL_HAS_TARGET_ATTRIBS #elif defined(__ICC) && __ICC >= 1600 # define SDL_HAS_TARGET_ATTRIBS diff --git a/vendor/sdl3/include/SDL_iostream.h b/vendor/sdl3/include/SDL_iostream.h index 4ca16093e..f369fde17 100644 --- a/vendor/sdl3/include/SDL_iostream.h +++ b/vendor/sdl3/include/SDL_iostream.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -111,7 +111,7 @@ typedef struct SDL_IOStreamInterface /** * Read up to `size` bytes from the data stream to the area pointed - * at by `ptr`. + * at by `ptr`. `size` will always be > 0. * * On an incomplete read, you should set `*status` to a value from the * SDL_IOStatus enum. You do not have to explicitly set this on @@ -123,7 +123,7 @@ typedef struct SDL_IOStreamInterface /** * Write exactly `size` bytes from the area pointed at by `ptr` - * to data stream. + * to data stream. `size` will always be > 0. * * On an incomplete write, you should set `*status` to a value from the * SDL_IOStatus enum. You do not have to explicitly set this on @@ -203,6 +203,8 @@ typedef struct SDL_IOStream SDL_IOStream; * - "w": Create an empty file for writing. If a file with the same name * already exists its content is erased and the file is treated as a new * empty file. + * - "wx": Create an empty file for writing. If a file with the same name + * already exists, the call fails. * - "a": Append to a file. Writing operations append data at the end of the * file. The file is created if it does not exist. * - "r+": Open a file for update both reading and writing. The file must @@ -210,6 +212,8 @@ typedef struct SDL_IOStream SDL_IOStream; * - "w+": Create an empty file for both reading and writing. If a file with * the same name already exists its content is erased and the file is * treated as a new empty file. + * - "w+x": Create an empty file for both reading and writing. If a file with + * the same name already exists, the call fails. * - "a+": Open a file for reading and appending. All writing operations are * performed at the end of the file, protecting the previous content to be * overwritten. You can reposition (fseek, rewind) the internal pointer to @@ -260,7 +264,7 @@ typedef struct SDL_IOStream SDL_IOStream; * \returns a pointer to the SDL_IOStream structure that is created or NULL on * failure; call SDL_GetError() for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety It is safe to call this function from any thread. * * \since This function is available since SDL 3.2.0. * @@ -286,8 +290,7 @@ extern SDL_DECLSPEC SDL_IOStream * SDLCALL SDL_IOFromFile(const char *file, cons * certain size, for both read and write access. * * This memory buffer is not copied by the SDL_IOStream; the pointer you - * provide must remain valid until you close the stream. Closing the stream - * will not free the original buffer. + * provide must remain valid until you close the stream. * * If you need to make sure the SDL_IOStream never writes to the memory * buffer, you should use SDL_IOFromConstMem() with a read-only buffer of @@ -300,6 +303,13 @@ extern SDL_DECLSPEC SDL_IOStream * SDLCALL SDL_IOFromFile(const char *file, cons * - `SDL_PROP_IOSTREAM_MEMORY_SIZE_NUMBER`: this will be the `size` parameter * that was passed to this function. * + * Additionally, the following properties are recognized: + * + * - `SDL_PROP_IOSTREAM_MEMORY_FREE_FUNC_POINTER`: if this property is set to + * a non-NULL value it will be interpreted as a function of SDL_free_func + * type and called with the passed `mem` pointer when closing the stream. By + * default it is unset, i.e., the memory will not be freed. + * * \param mem a pointer to a buffer to feed an SDL_IOStream stream. * \param size the buffer size, in bytes. * \returns a pointer to a new SDL_IOStream structure or NULL on failure; call @@ -321,6 +331,7 @@ extern SDL_DECLSPEC SDL_IOStream * SDLCALL SDL_IOFromMem(void *mem, size_t size) #define SDL_PROP_IOSTREAM_MEMORY_POINTER "SDL.iostream.memory.base" #define SDL_PROP_IOSTREAM_MEMORY_SIZE_NUMBER "SDL.iostream.memory.size" +#define SDL_PROP_IOSTREAM_MEMORY_FREE_FUNC_POINTER "SDL.iostream.memory.free" /** * Use this function to prepare a read-only memory buffer for use with @@ -333,8 +344,7 @@ extern SDL_DECLSPEC SDL_IOStream * SDLCALL SDL_IOFromMem(void *mem, size_t size) * without writing to the memory buffer. * * This memory buffer is not copied by the SDL_IOStream; the pointer you - * provide must remain valid until you close the stream. Closing the stream - * will not free the original buffer. + * provide must remain valid until you close the stream. * * If you need to write to a memory buffer, you should use SDL_IOFromMem() * with a writable buffer of memory instead. @@ -346,6 +356,13 @@ extern SDL_DECLSPEC SDL_IOStream * SDLCALL SDL_IOFromMem(void *mem, size_t size) * - `SDL_PROP_IOSTREAM_MEMORY_SIZE_NUMBER`: this will be the `size` parameter * that was passed to this function. * + * Additionally, the following properties are recognized: + * + * - `SDL_PROP_IOSTREAM_MEMORY_FREE_FUNC_POINTER`: if this property is set to + * a non-NULL value it will be interpreted as a function of SDL_free_func + * type and called with the passed `mem` pointer when closing the stream. By + * default it is unset, i.e., the memory will not be freed. + * * \param mem a pointer to a read-only buffer to feed an SDL_IOStream stream. * \param size the buffer size, in bytes. * \returns a pointer to a new SDL_IOStream structure or NULL on failure; call @@ -452,7 +469,7 @@ extern SDL_DECLSPEC SDL_IOStream * SDLCALL SDL_OpenIO(const SDL_IOStreamInterfac * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. * @@ -467,7 +484,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_CloseIO(SDL_IOStream *context); * \returns a valid property ID on success or 0 on failure; call * SDL_GetError() for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -487,7 +504,7 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetIOProperties(SDL_IOStream *c * \param context the SDL_IOStream to query. * \returns an SDL_IOStatus enum with the current state. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -501,7 +518,7 @@ extern SDL_DECLSPEC SDL_IOStatus SDLCALL SDL_GetIOStatus(SDL_IOStream *context); * negative error code on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -528,7 +545,7 @@ extern SDL_DECLSPEC Sint64 SDLCALL SDL_GetIOSize(SDL_IOStream *context); * \returns the final offset in the data stream after the seek or -1 on * failure; call SDL_GetError() for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. * @@ -548,7 +565,7 @@ extern SDL_DECLSPEC Sint64 SDLCALL SDL_SeekIO(SDL_IOStream *context, Sint64 offs * \returns the current offset in the stream, or -1 if the information can not * be determined. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. * @@ -567,13 +584,17 @@ extern SDL_DECLSPEC Sint64 SDLCALL SDL_TellIO(SDL_IOStream *context); * the stream is not at EOF, SDL_GetIOStatus() will return a different error * value and SDL_GetError() will offer a human-readable message. * + * A request for zero bytes on a valid stream will return zero immediately + * without accessing the stream, so the stream status (EOF, err, etc) will not + * change. + * * \param context a pointer to an SDL_IOStream structure. * \param ptr a pointer to a buffer to read data into. * \param size the number of bytes to read from the data source. * \returns the number of bytes read, or 0 on end of file or other failure; * call SDL_GetError() for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. * @@ -596,13 +617,17 @@ extern SDL_DECLSPEC size_t SDLCALL SDL_ReadIO(SDL_IOStream *context, void *ptr, * recoverable, such as a non-blocking write that can simply be retried later, * or a fatal error. * + * A request for zero bytes on a valid stream will return zero immediately + * without accessing the stream, so the stream status (EOF, err, etc) will not + * change. + * * \param context a pointer to an SDL_IOStream structure. * \param ptr a pointer to a buffer containing data to write. * \param size the number of bytes to write. * \returns the number of bytes written, which will be less than `size` on * failure; call SDL_GetError() for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. * @@ -626,7 +651,7 @@ extern SDL_DECLSPEC size_t SDLCALL SDL_WriteIO(SDL_IOStream *context, const void * \returns the number of bytes written or 0 on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. * @@ -646,7 +671,7 @@ extern SDL_DECLSPEC size_t SDLCALL SDL_IOprintf(SDL_IOStream *context, SDL_PRINT * \returns the number of bytes written or 0 on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. * @@ -666,7 +691,7 @@ extern SDL_DECLSPEC size_t SDLCALL SDL_IOvprintf(SDL_IOStream *context, SDL_PRIN * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. * @@ -692,7 +717,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FlushIO(SDL_IOStream *context); * \returns the data or NULL on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. * @@ -715,7 +740,7 @@ extern SDL_DECLSPEC void * SDLCALL SDL_LoadFile_IO(SDL_IOStream *src, size_t *da * \returns the data or NULL on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety It is safe to call this function from any thread. * * \since This function is available since SDL 3.2.0. * @@ -736,7 +761,7 @@ extern SDL_DECLSPEC void * SDLCALL SDL_LoadFile(const char *file, size_t *datasi * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. * @@ -755,7 +780,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SaveFile_IO(SDL_IOStream *src, const void * * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety It is safe to call this function from any thread. * * \since This function is available since SDL 3.2.0. * @@ -784,7 +809,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SaveFile(const char *file, const void *data * \returns true on success or false on failure or EOF; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -803,7 +828,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadU8(SDL_IOStream *src, Uint8 *value); * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -823,10 +848,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadS8(SDL_IOStream *src, Sint8 *value); * * \param src the stream from which to read data. * \param value a pointer filled in with the data read. - * \returns true on successful write or false on failure; call SDL_GetError() + * \returns true on successful read or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -846,10 +871,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadU16LE(SDL_IOStream *src, Uint16 *value) * * \param src the stream from which to read data. * \param value a pointer filled in with the data read. - * \returns true on successful write or false on failure; call SDL_GetError() + * \returns true on successful read or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -869,10 +894,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadS16LE(SDL_IOStream *src, Sint16 *value) * * \param src the stream from which to read data. * \param value a pointer filled in with the data read. - * \returns true on successful write or false on failure; call SDL_GetError() + * \returns true on successful read or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -892,10 +917,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadU16BE(SDL_IOStream *src, Uint16 *value) * * \param src the stream from which to read data. * \param value a pointer filled in with the data read. - * \returns true on successful write or false on failure; call SDL_GetError() + * \returns true on successful read or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -915,10 +940,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadS16BE(SDL_IOStream *src, Sint16 *value) * * \param src the stream from which to read data. * \param value a pointer filled in with the data read. - * \returns true on successful write or false on failure; call SDL_GetError() + * \returns true on successful read or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -938,10 +963,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadU32LE(SDL_IOStream *src, Uint32 *value) * * \param src the stream from which to read data. * \param value a pointer filled in with the data read. - * \returns true on successful write or false on failure; call SDL_GetError() + * \returns true on successful read or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -961,10 +986,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadS32LE(SDL_IOStream *src, Sint32 *value) * * \param src the stream from which to read data. * \param value a pointer filled in with the data read. - * \returns true on successful write or false on failure; call SDL_GetError() + * \returns true on successful read or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -984,10 +1009,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadU32BE(SDL_IOStream *src, Uint32 *value) * * \param src the stream from which to read data. * \param value a pointer filled in with the data read. - * \returns true on successful write or false on failure; call SDL_GetError() + * \returns true on successful read or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1007,10 +1032,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadS32BE(SDL_IOStream *src, Sint32 *value) * * \param src the stream from which to read data. * \param value a pointer filled in with the data read. - * \returns true on successful write or false on failure; call SDL_GetError() + * \returns true on successful read or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1030,10 +1055,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadU64LE(SDL_IOStream *src, Uint64 *value) * * \param src the stream from which to read data. * \param value a pointer filled in with the data read. - * \returns true on successful write or false on failure; call SDL_GetError() + * \returns true on successful read or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1053,10 +1078,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadS64LE(SDL_IOStream *src, Sint64 *value) * * \param src the stream from which to read data. * \param value a pointer filled in with the data read. - * \returns true on successful write or false on failure; call SDL_GetError() + * \returns true on successful read or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1076,10 +1101,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadU64BE(SDL_IOStream *src, Uint64 *value) * * \param src the stream from which to read data. * \param value a pointer filled in with the data read. - * \returns true on successful write or false on failure; call SDL_GetError() + * \returns true on successful read or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1101,7 +1126,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadS64BE(SDL_IOStream *src, Sint64 *value) * \returns true on successful write or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1115,7 +1140,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteU8(SDL_IOStream *dst, Uint8 value); * \returns true on successful write or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1134,7 +1159,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteS8(SDL_IOStream *dst, Sint8 value); * \returns true on successful write or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1153,7 +1178,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteU16LE(SDL_IOStream *dst, Uint16 value) * \returns true on successful write or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1171,7 +1196,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteS16LE(SDL_IOStream *dst, Sint16 value) * \returns true on successful write or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1189,7 +1214,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteU16BE(SDL_IOStream *dst, Uint16 value) * \returns true on successful write or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1208,7 +1233,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteS16BE(SDL_IOStream *dst, Sint16 value) * \returns true on successful write or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1227,7 +1252,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteU32LE(SDL_IOStream *dst, Uint32 value) * \returns true on successful write or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1245,7 +1270,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteS32LE(SDL_IOStream *dst, Sint32 value) * \returns true on successful write or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1263,7 +1288,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteU32BE(SDL_IOStream *dst, Uint32 value) * \returns true on successful write or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1282,7 +1307,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteS32BE(SDL_IOStream *dst, Sint32 value) * \returns true on successful write or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1301,7 +1326,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteU64LE(SDL_IOStream *dst, Uint64 value) * \returns true on successful write or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1319,7 +1344,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteS64LE(SDL_IOStream *dst, Sint64 value) * \returns true on successful write or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ @@ -1337,7 +1362,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteU64BE(SDL_IOStream *dst, Uint64 value) * \returns true on successful write or false on failure; call SDL_GetError() * for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety Do not use the same SDL_IOStream from two threads at once. * * \since This function is available since SDL 3.2.0. */ diff --git a/vendor/sdl3/include/SDL_joystick.h b/vendor/sdl3/include/SDL_joystick.h index d15668b66..c93b35210 100644 --- a/vendor/sdl3/include/SDL_joystick.h +++ b/vendor/sdl3/include/SDL_joystick.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -29,8 +29,8 @@ * instead. * * The term "instance_id" is the current instantiation of a joystick device in - * the system, if the joystick is removed and then re-inserted then it will - * get a new instance_id, instance_id's are monotonically increasing + * the system. If the joystick is removed and then re-inserted then it will + * get a new instance_id. instance_id's are monotonically increasing * identifiers of a joystick plugged in. * * The term "player_index" is the number assigned to a player on a specific @@ -48,6 +48,14 @@ * If you would like to receive joystick updates while the application is in * the background, you should set the following hint before calling * SDL_Init(): SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS + * + * SDL can provide virtual joysticks as well: the app defines an imaginary + * controller with SDL_AttachVirtualJoystick(), and then can provide inputs + * for it via SDL_SetJoystickVirtualAxis(), SDL_SetJoystickVirtualButton(), + * etc. As this data is supplied, it will look like a normal joystick to SDL, + * just not backed by a hardware driver. This has been used to make unusual + * devices, like VR headset controllers, look like normal joysticks, or + * provide recording/playback of game inputs, etc. */ #ifndef SDL_joystick_h_ @@ -107,6 +115,10 @@ typedef Uint32 SDL_JoystickID; * This is by no means a complete list of everything that can be plugged into * a computer. * + * You may refer to + * [XInput Controller Types](https://learn.microsoft.com/en-us/windows/win32/xinput/xinput-and-controller-subtypes) + * table for a general understanding of each joystick type. + * * \since This enum is available since SDL 3.2.0. */ typedef enum SDL_JoystickType @@ -170,6 +182,8 @@ typedef enum SDL_JoystickConnectionState * joysticks while processing to guarantee that the joystick list won't change * and joystick and gamepad events will not be delivered. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC void SDLCALL SDL_LockJoysticks(void) SDL_ACQUIRE(SDL_joystick_lock); @@ -177,6 +191,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_LockJoysticks(void) SDL_ACQUIRE(SDL_joystic /** * Unlocking for atomic access to the joystick API. * + * \threadsafety This should be called from the same thread that called + * SDL_LockJoysticks(). + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC void SDLCALL SDL_UnlockJoysticks(void) SDL_RELEASE(SDL_joystick_lock); @@ -186,6 +203,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnlockJoysticks(void) SDL_RELEASE(SDL_joyst * * \returns true if a joystick is connected, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoysticks @@ -201,6 +220,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HasJoystick(void); * call SDL_GetError() for more information. This should be freed * with SDL_free() when it is no longer needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_HasJoystick @@ -217,6 +238,8 @@ extern SDL_DECLSPEC SDL_JoystickID * SDLCALL SDL_GetJoysticks(int *count); * \returns the name of the selected joystick. If no name can be found, this * function returns NULL; call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickName @@ -233,6 +256,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetJoystickNameForID(SDL_JoystickID * \returns the path of the selected joystick. If no path can be found, this * function returns NULL; call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickPath @@ -248,6 +273,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetJoystickPathForID(SDL_JoystickID * \param instance_id the joystick instance ID. * \returns the player index of a joystick, or -1 if it's not available. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickPlayerIndex @@ -264,6 +291,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetJoystickPlayerIndexForID(SDL_JoystickID i * \returns the GUID of the selected joystick. If called with an invalid * instance_id, this function returns a zero GUID. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickGUID @@ -281,6 +310,8 @@ extern SDL_DECLSPEC SDL_GUID SDLCALL SDL_GetJoystickGUIDForID(SDL_JoystickID ins * \returns the USB vendor ID of the selected joystick. If called with an * invalid instance_id, this function returns 0. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickVendor @@ -298,6 +329,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetJoystickVendorForID(SDL_JoystickID ins * \returns the USB product ID of the selected joystick. If called with an * invalid instance_id, this function returns 0. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickProduct @@ -315,6 +348,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetJoystickProductForID(SDL_JoystickID in * \returns the product version of the selected joystick. If called with an * invalid instance_id, this function returns 0. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickProductVersion @@ -332,6 +367,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetJoystickProductVersionForID(SDL_Joysti * invalid instance_id, this function returns * `SDL_JOYSTICK_TYPE_UNKNOWN`. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickType @@ -349,6 +386,8 @@ extern SDL_DECLSPEC SDL_JoystickType SDLCALL SDL_GetJoystickTypeForID(SDL_Joysti * \returns a joystick identifier or NULL on failure; call SDL_GetError() for * more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_CloseJoystick @@ -362,6 +401,8 @@ extern SDL_DECLSPEC SDL_Joystick * SDLCALL SDL_OpenJoystick(SDL_JoystickID insta * \returns an SDL_Joystick on success or NULL on failure or if it hasn't been * opened yet; call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_Joystick * SDLCALL SDL_GetJoystickFromID(SDL_JoystickID instance_id); @@ -373,6 +414,8 @@ extern SDL_DECLSPEC SDL_Joystick * SDLCALL SDL_GetJoystickFromID(SDL_JoystickID * \returns an SDL_Joystick on success or NULL on failure; call SDL_GetError() * for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickPlayerIndex @@ -465,13 +508,33 @@ SDL_COMPILE_TIME_ASSERT(SDL_VirtualJoystickDesc_SIZE, /** * Attach a new virtual joystick. * + * Apps can create virtual joysticks, that exist without hardware directly + * backing them, and have program-supplied inputs. Once attached, a virtual + * joystick looks like any other joystick that SDL can access. These can be + * used to make other things look like joysticks, or provide pre-recorded + * input, etc. + * + * Once attached, the app can send joystick inputs to the new virtual joystick + * using SDL_SetJoystickVirtualAxis(), etc. + * + * When no longer needed, the virtual joystick can be removed by calling + * SDL_DetachVirtualJoystick(). + * * \param desc joystick description, initialized using SDL_INIT_INTERFACE(). * \returns the joystick instance ID, or 0 on failure; call SDL_GetError() for * more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_DetachVirtualJoystick + * \sa SDL_SetJoystickVirtualAxis + * \sa SDL_SetJoystickVirtualButton + * \sa SDL_SetJoystickVirtualBall + * \sa SDL_SetJoystickVirtualHat + * \sa SDL_SetJoystickVirtualTouchpad + * \sa SDL_SetJoystickVirtualSensorData */ extern SDL_DECLSPEC SDL_JoystickID SDLCALL SDL_AttachVirtualJoystick(const SDL_VirtualJoystickDesc *desc); @@ -483,6 +546,8 @@ extern SDL_DECLSPEC SDL_JoystickID SDLCALL SDL_AttachVirtualJoystick(const SDL_V * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_AttachVirtualJoystick @@ -495,6 +560,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_DetachVirtualJoystick(SDL_JoystickID instan * \param instance_id the joystick instance ID. * \returns true if the joystick is virtual, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_IsJoystickVirtual(SDL_JoystickID instance_id); @@ -518,7 +585,15 @@ extern SDL_DECLSPEC bool SDLCALL SDL_IsJoystickVirtual(SDL_JoystickID instance_i * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_SetJoystickVirtualButton + * \sa SDL_SetJoystickVirtualBall + * \sa SDL_SetJoystickVirtualHat + * \sa SDL_SetJoystickVirtualTouchpad + * \sa SDL_SetJoystickVirtualSensorData */ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickVirtualAxis(SDL_Joystick *joystick, int axis, Sint16 value); @@ -538,7 +613,15 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickVirtualAxis(SDL_Joystick *joysti * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_SetJoystickVirtualAxis + * \sa SDL_SetJoystickVirtualButton + * \sa SDL_SetJoystickVirtualHat + * \sa SDL_SetJoystickVirtualTouchpad + * \sa SDL_SetJoystickVirtualSensorData */ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickVirtualBall(SDL_Joystick *joystick, int ball, Sint16 xrel, Sint16 yrel); @@ -557,7 +640,15 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickVirtualBall(SDL_Joystick *joysti * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_SetJoystickVirtualAxis + * \sa SDL_SetJoystickVirtualBall + * \sa SDL_SetJoystickVirtualHat + * \sa SDL_SetJoystickVirtualTouchpad + * \sa SDL_SetJoystickVirtualSensorData */ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickVirtualButton(SDL_Joystick *joystick, int button, bool down); @@ -576,7 +667,15 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickVirtualButton(SDL_Joystick *joys * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_SetJoystickVirtualAxis + * \sa SDL_SetJoystickVirtualButton + * \sa SDL_SetJoystickVirtualBall + * \sa SDL_SetJoystickVirtualTouchpad + * \sa SDL_SetJoystickVirtualSensorData */ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickVirtualHat(SDL_Joystick *joystick, int hat, Uint8 value); @@ -602,7 +701,15 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickVirtualHat(SDL_Joystick *joystic * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_SetJoystickVirtualAxis + * \sa SDL_SetJoystickVirtualButton + * \sa SDL_SetJoystickVirtualBall + * \sa SDL_SetJoystickVirtualHat + * \sa SDL_SetJoystickVirtualSensorData */ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickVirtualTouchpad(SDL_Joystick *joystick, int touchpad, int finger, bool down, float x, float y, float pressure); @@ -624,7 +731,15 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickVirtualTouchpad(SDL_Joystick *jo * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_SetJoystickVirtualAxis + * \sa SDL_SetJoystickVirtualButton + * \sa SDL_SetJoystickVirtualBall + * \sa SDL_SetJoystickVirtualHat + * \sa SDL_SetJoystickVirtualTouchpad */ extern SDL_DECLSPEC bool SDLCALL SDL_SendJoystickVirtualSensorData(SDL_Joystick *joystick, SDL_SensorType type, Uint64 sensor_timestamp, const float *data, int num_values); @@ -648,6 +763,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SendJoystickVirtualSensorData(SDL_Joystick * \returns a valid property ID on success or 0 on failure; call * SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetJoystickProperties(SDL_Joystick *joystick); @@ -665,6 +782,8 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetJoystickProperties(SDL_Joyst * \returns the name of the selected joystick. If no name can be found, this * function returns NULL; call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickNameForID @@ -678,6 +797,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetJoystickName(SDL_Joystick *joyst * \returns the path of the selected joystick. If no path can be found, this * function returns NULL; call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickPathForID @@ -693,6 +814,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetJoystickPath(SDL_Joystick *joyst * \param joystick the SDL_Joystick obtained from SDL_OpenJoystick(). * \returns the player index, or -1 if it's not available. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetJoystickPlayerIndex @@ -708,6 +831,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetJoystickPlayerIndex(SDL_Joystick *joystic * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickPlayerIndex @@ -724,6 +849,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickPlayerIndex(SDL_Joystick *joysti * this function returns a zero GUID; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickGUIDForID @@ -739,6 +866,8 @@ extern SDL_DECLSPEC SDL_GUID SDLCALL SDL_GetJoystickGUID(SDL_Joystick *joystick) * \param joystick the SDL_Joystick obtained from SDL_OpenJoystick(). * \returns the USB vendor ID of the selected joystick, or 0 if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickVendorForID @@ -753,6 +882,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetJoystickVendor(SDL_Joystick *joystick) * \param joystick the SDL_Joystick obtained from SDL_OpenJoystick(). * \returns the USB product ID of the selected joystick, or 0 if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickProductForID @@ -767,6 +898,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetJoystickProduct(SDL_Joystick *joystick * \param joystick the SDL_Joystick obtained from SDL_OpenJoystick(). * \returns the product version of the selected joystick, or 0 if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickProductVersionForID @@ -782,6 +915,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetJoystickProductVersion(SDL_Joystick *j * \returns the firmware version of the selected joystick, or 0 if * unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetJoystickFirmwareVersion(SDL_Joystick *joystick); @@ -795,6 +930,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetJoystickFirmwareVersion(SDL_Joystick * * \returns the serial number of the selected joystick, or NULL if * unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC const char * SDLCALL SDL_GetJoystickSerial(SDL_Joystick *joystick); @@ -805,6 +942,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetJoystickSerial(SDL_Joystick *joy * \param joystick the SDL_Joystick obtained from SDL_OpenJoystick(). * \returns the SDL_JoystickType of the selected joystick. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickTypeForID @@ -824,6 +963,8 @@ extern SDL_DECLSPEC SDL_JoystickType SDLCALL SDL_GetJoystickType(SDL_Joystick *j * \param crc16 a pointer filled in with a CRC used to distinguish different * products with the same VID/PID, or 0 if not available. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickGUIDForID @@ -837,6 +978,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_GetJoystickGUIDInfo(SDL_GUID guid, Uint16 * * \returns true if the joystick has been opened, false if it has not; call * SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_JoystickConnected(SDL_Joystick *joystick); @@ -848,6 +991,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_JoystickConnected(SDL_Joystick *joystick); * \returns the instance ID of the specified joystick on success or 0 on * failure; call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_JoystickID SDLCALL SDL_GetJoystickID(SDL_Joystick *joystick); @@ -863,6 +1008,8 @@ extern SDL_DECLSPEC SDL_JoystickID SDLCALL SDL_GetJoystickID(SDL_Joystick *joyst * \returns the number of axis controls/number of axes on success or -1 on * failure; call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickAxis @@ -884,6 +1031,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetNumJoystickAxes(SDL_Joystick *joystick); * \returns the number of trackballs on success or -1 on failure; call * SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickBall @@ -900,6 +1049,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetNumJoystickBalls(SDL_Joystick *joystick); * \returns the number of POV hats on success or -1 on failure; call * SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickHat @@ -916,6 +1067,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetNumJoystickHats(SDL_Joystick *joystick); * \returns the number of buttons on success or -1 on failure; call * SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickButton @@ -934,6 +1087,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetNumJoystickButtons(SDL_Joystick *joystick * * \param enabled whether to process joystick events or not. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_JoystickEventsEnabled @@ -950,6 +1105,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetJoystickEventsEnabled(bool enabled); * * \returns true if joystick events are being processed, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetJoystickEventsEnabled @@ -962,6 +1119,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_JoystickEventsEnabled(void); * This is called automatically by the event loop if any joystick events are * enabled. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC void SDLCALL SDL_UpdateJoysticks(void); @@ -984,6 +1143,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_UpdateJoysticks(void); * \returns a 16-bit signed integer representing the current position of the * axis or 0 on failure; call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetNumJoystickAxes @@ -1002,6 +1163,8 @@ extern SDL_DECLSPEC Sint16 SDLCALL SDL_GetJoystickAxis(SDL_Joystick *joystick, i * \param state upon return, the initial value is supplied here. * \returns true if this axis has any initial value, or false if not. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_GetJoystickAxisInitialState(SDL_Joystick *joystick, int axis, Sint16 *state); @@ -1021,6 +1184,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetJoystickAxisInitialState(SDL_Joystick *j * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetNumJoystickBalls @@ -1036,6 +1201,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetJoystickBall(SDL_Joystick *joystick, int * \param hat the hat index to get the state from; indices start at index 0. * \returns the current hat position. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetNumJoystickHats @@ -1060,6 +1227,8 @@ extern SDL_DECLSPEC Uint8 SDLCALL SDL_GetJoystickHat(SDL_Joystick *joystick, int * index 0. * \returns true if the button is pressed, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetNumJoystickButtons @@ -1083,6 +1252,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetJoystickButton(SDL_Joystick *joystick, i * \param duration_ms the duration of the rumble effect, in milliseconds. * \returns true, or false if rumble isn't supported on this joystick. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_RumbleJoystick(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms); @@ -1110,6 +1281,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RumbleJoystick(SDL_Joystick *joystick, Uint * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_RumbleJoystick @@ -1132,6 +1305,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RumbleJoystickTriggers(SDL_Joystick *joysti * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue); @@ -1145,6 +1320,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickLED(SDL_Joystick *joystick, Uint * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_SendJoystickEffect(SDL_Joystick *joystick, const void *data, int size); @@ -1154,6 +1331,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SendJoystickEffect(SDL_Joystick *joystick, * * \param joystick the joystick device to close. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_OpenJoystick @@ -1168,6 +1347,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_CloseJoystick(SDL_Joystick *joystick); * `SDL_JOYSTICK_CONNECTION_INVALID` on failure; call SDL_GetError() * for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_JoystickConnectionState SDLCALL SDL_GetJoystickConnectionState(SDL_Joystick *joystick); @@ -1189,6 +1370,8 @@ extern SDL_DECLSPEC SDL_JoystickConnectionState SDLCALL SDL_GetJoystickConnectio * \returns the current battery state or `SDL_POWERSTATE_ERROR` on failure; * call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_PowerState SDLCALL SDL_GetJoystickPowerInfo(SDL_Joystick *joystick, int *percent); diff --git a/vendor/sdl3/include/SDL_keyboard.h b/vendor/sdl3/include/SDL_keyboard.h index afa77b6c2..d14ab6fb2 100644 --- a/vendor/sdl3/include/SDL_keyboard.h +++ b/vendor/sdl3/include/SDL_keyboard.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -174,8 +174,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ResetKeyboard(void); /** * Get the current key modifier state for the keyboard. * - * \returns an OR'd combination of the modifier keys for the keyboard. See - * SDL_Keymod for details. + * \returns an OR'd combination of the modifier keys for the keyboard. * * \threadsafety It is safe to call this function from any thread. * diff --git a/vendor/sdl3/include/SDL_keycode.h b/vendor/sdl3/include/SDL_keycode.h index 61b68e794..1818ee3e4 100644 --- a/vendor/sdl3/include/SDL_keycode.h +++ b/vendor/sdl3/include/SDL_keycode.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -45,12 +45,16 @@ * `SDLK_*` constant for those keys that do not generate characters. * * A special exception is the number keys at the top of the keyboard which map - * to SDLK_0...SDLK_9 on AZERTY layouts. + * by default to SDLK_0...SDLK_9 on AZERTY layouts. * * Keys with the `SDLK_EXTENDED_MASK` bit set do not map to a scancode or - * unicode code point. + * Unicode code point. + * + * Many common keycodes are listed below, but this list is not exhaustive. * * \since This datatype is available since SDL 3.2.0. + * + * \sa SDL_HINT_KEYCODE_OPTIONS */ typedef Uint32 SDL_Keycode; diff --git a/vendor/sdl3/include/SDL_loadso.h b/vendor/sdl3/include/SDL_loadso.h index f8649d758..51d0d8811 100644 --- a/vendor/sdl3/include/SDL_loadso.h +++ b/vendor/sdl3/include/SDL_loadso.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_locale.h b/vendor/sdl3/include/SDL_locale.h index 902843e81..9f03aa90d 100644 --- a/vendor/sdl3/include/SDL_locale.h +++ b/vendor/sdl3/include/SDL_locale.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -102,6 +102,8 @@ typedef struct SDL_Locale * allocation that should be freed with SDL_free() when it is no * longer needed. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_Locale ** SDLCALL SDL_GetPreferredLocales(int *count); diff --git a/vendor/sdl3/include/SDL_log.h b/vendor/sdl3/include/SDL_log.h index 3fd7ec2ed..2ae0963c2 100644 --- a/vendor/sdl3/include/SDL_log.h +++ b/vendor/sdl3/include/SDL_log.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -206,6 +206,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_ResetLogPriorities(void); * SDL_LOG_PRIORITY_WARN and higher have a prefix showing their priority, e.g. * "WARNING: ". * + * This function makes a copy of its string argument, **prefix**, so it is not + * necessary to keep the value of **prefix** alive after the call returns. + * * \param priority the SDL_LogPriority to modify. * \param prefix the prefix to use for that log priority, or NULL to use no * prefix. @@ -263,7 +266,6 @@ extern SDL_DECLSPEC void SDLCALL SDL_Log(SDL_PRINTF_FORMAT_STRING const char *fm * \sa SDL_LogInfo * \sa SDL_LogMessage * \sa SDL_LogMessageV - * \sa SDL_LogTrace * \sa SDL_LogVerbose * \sa SDL_LogWarn */ diff --git a/vendor/sdl3/include/SDL_main.h b/vendor/sdl3/include/SDL_main.h index 905d78e96..ee4d9ca71 100644 --- a/vendor/sdl3/include/SDL_main.h +++ b/vendor/sdl3/include/SDL_main.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -47,7 +47,7 @@ * * For more information, see: * - * https://wiki.libsdl.org/SDL3/README/main-functions + * https://wiki.libsdl.org/SDL3/README-main-functions */ #ifndef SDL_main_h_ @@ -68,7 +68,7 @@ * proper entry point for the platform, and all the other magic details * needed, like manually calling SDL_SetMainReady. * - * Please see [README/main-functions](README/main-functions), (or + * Please see [README-main-functions](README-main-functions), (or * docs/README-main-functions.md in the source tree) for a more detailed * explanation. * @@ -85,7 +85,7 @@ * SDL_AppQuit. The app should not provide a `main` function in this case, and * doing so will likely cause the build to fail. * - * Please see [README/main-functions](README/main-functions), (or + * Please see [README-main-functions](README-main-functions), (or * docs/README-main-functions.md in the source tree) for a more detailed * explanation. * @@ -110,7 +110,8 @@ * Even if available, an app can define SDL_MAIN_HANDLED and provide their * own, if they know what they're doing. * - * This macro is used internally by SDL, and apps probably shouldn't rely on it. + * This macro is used internally by SDL, and apps probably shouldn't rely on + * it. * * \since This macro is available since SDL 3.2.0. */ @@ -125,10 +126,11 @@ * This macro is defined by `SDL_main.h`, which is not automatically included * by `SDL.h`. * - * Even if required, an app can define SDL_MAIN_HANDLED and provide their - * own, if they know what they're doing. + * Even if required, an app can define SDL_MAIN_HANDLED and provide their own, + * if they know what they're doing. * - * This macro is used internally by SDL, and apps probably shouldn't rely on it. + * This macro is used internally by SDL, and apps probably shouldn't rely on + * it. * * \since This macro is available since SDL 3.2.0. */ @@ -165,12 +167,10 @@ */ #define SDL_MAIN_NEEDED - #elif defined(SDL_PLATFORM_IOS) - /* On iOS SDL provides a main function that creates an application delegate - and starts the iOS application run loop. + #elif defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS) + /* On iOS and tvOS SDL provides a main function that creates an application delegate and starts the application run loop. - To use it, just #include SDL_main.h in the source file that contains your - main() function. + To use it, just #include in the source file that contains your main() function. See src/video/uikit/SDL_uikitappdelegate.m for more details. */ @@ -333,6 +333,8 @@ extern "C" { * \returns SDL_APP_FAILURE to terminate with an error, SDL_APP_SUCCESS to * terminate with success, SDL_APP_CONTINUE to continue. * + * \threadsafety This function is called once by SDL, at startup, on a single thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_AppIterate @@ -347,10 +349,10 @@ extern SDLMAIN_DECLSPEC SDL_AppResult SDLCALL SDL_AppInit(void **appstate, int a * Apps implement this function when using SDL_MAIN_USE_CALLBACKS. If using a * standard "main" function, you should not supply this. * - * This function is called repeatedly by SDL after SDL_AppInit returns 0. The - * function should operate as a single iteration the program's primary loop; - * it should update whatever state it needs and draw a new frame of video, - * usually. + * This function is called repeatedly by SDL after SDL_AppInit returns + * SDL_APP_CONTINUE. The function should operate as a single iteration the + * program's primary loop; it should update whatever state it needs and draw a + * new frame of video, usually. * * On some platforms, this function will be called at the refresh rate of the * display (which might change during the life of your app!). There are no @@ -449,8 +451,8 @@ extern SDLMAIN_DECLSPEC SDL_AppResult SDLCALL SDL_AppEvent(void *appstate, SDL_E * * This function is called once by SDL before terminating the program. * - * This function will be called no matter what, even if SDL_AppInit requests - * termination. + * This function will be called in all cases, even if SDL_AppInit requests + * termination at startup. * * This function should not go into an infinite mainloop; it should * deinitialize any resources necessary, perform whatever shutdown activities, @@ -512,7 +514,7 @@ typedef int (SDLCALL *SDL_main_func)(int argc, char *argv[]); * SDL_MAIN_USE_CALLBACKS. * * Program startup is a surprisingly complex topic. Please see - * [README/main-functions](README/main-functions), (or + * [README-main-functions](README-main-functions), (or * docs/README-main-functions.md in the source tree) for a more detailed * explanation. * @@ -537,6 +539,8 @@ extern SDLMAIN_DECLSPEC int SDLCALL SDL_main(int argc, char *argv[]); * will not be changed it is necessary to define SDL_MAIN_HANDLED before * including SDL.h. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_Init @@ -553,6 +557,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetMainReady(void); * using SDL_main (like when using SDL_MAIN_HANDLED). When using this, you do * *not* need SDL_SetMainReady(). * + * If `argv` is NULL, SDL will provide command line arguments, either by + * querying the OS for them if possible, or supplying a filler array if not. + * * \param argc the argc parameter from the application's main() function, or 0 * if the platform's main-equivalent has no argc. * \param argv the argv parameter from the application's main() function, or @@ -615,16 +622,19 @@ extern SDL_DECLSPEC int SDLCALL SDL_EnterAppMainCallbacks(int argc, char *argv[] * Most applications do not need to, and should not, call this directly; SDL * will call it when initializing the video subsystem. * + * If `name` is NULL, SDL currently uses `(CS_BYTEALIGNCLIENT | CS_OWNDC)` for + * the style, regardless of what is specified here. + * * \param name the window class name, in UTF-8 encoding. If NULL, SDL * currently uses "SDL_app" but this isn't guaranteed. - * \param style the value to use in WNDCLASSEX::style. If `name` is NULL, SDL - * currently uses `(CS_BYTEALIGNCLIENT | CS_OWNDC)` regardless of - * what is specified here. + * \param style the value to use in WNDCLASSEX::style. * \param hInst the HINSTANCE to use in WNDCLASSEX::hInstance. If zero, SDL * will use `GetModuleHandle(NULL)` instead. * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_RegisterApp(const char *name, Uint32 style, void *hInst); @@ -642,6 +652,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RegisterApp(const char *name, Uint32 style, * deregistered when the registration counter in SDL_RegisterApp decrements to * zero through calls to this function. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC void SDLCALL SDL_UnregisterApp(void); @@ -654,6 +666,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnregisterApp(void); * This function is only needed for Xbox GDK support; all other platforms will * do nothing and set an "unsupported" error message. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC void SDLCALL SDL_GDKSuspendComplete(void); diff --git a/vendor/sdl3/include/SDL_main_impl.h b/vendor/sdl3/include/SDL_main_impl.h index 14ebb4291..bf5f58363 100644 --- a/vendor/sdl3/include/SDL_main_impl.h +++ b/vendor/sdl3/include/SDL_main_impl.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_messagebox.h b/vendor/sdl3/include/SDL_messagebox.h index 365ae36a5..af604e2c7 100644 --- a/vendor/sdl3/include/SDL_messagebox.h +++ b/vendor/sdl3/include/SDL_messagebox.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -168,6 +168,8 @@ typedef struct SDL_MessageBoxData * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function should only be called on the main thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_ShowSimpleMessageBox @@ -210,6 +212,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ShowMessageBox(const SDL_MessageBoxData *me * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function should only be called on the main thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_ShowMessageBox diff --git a/vendor/sdl3/include/SDL_metal.h b/vendor/sdl3/include/SDL_metal.h index 14b1bc87a..6b0e171b4 100644 --- a/vendor/sdl3/include/SDL_metal.h +++ b/vendor/sdl3/include/SDL_metal.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -65,6 +65,8 @@ typedef void *SDL_MetalView; * \param window the window. * \returns handle NSView or UIView. * + * \threadsafety This function should only be called on the main thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_Metal_DestroyView @@ -80,6 +82,8 @@ extern SDL_DECLSPEC SDL_MetalView SDLCALL SDL_Metal_CreateView(SDL_Window *windo * * \param view the SDL_MetalView object. * + * \threadsafety This function should only be called on the main thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_Metal_CreateView @@ -92,6 +96,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_Metal_DestroyView(SDL_MetalView view); * \param view the SDL_MetalView object. * \returns a pointer. * + * \threadsafety This function should only be called on the main thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC void * SDLCALL SDL_Metal_GetLayer(SDL_MetalView view); diff --git a/vendor/sdl3/include/SDL_misc.h b/vendor/sdl3/include/SDL_misc.h index 3dd6fcddd..654c00558 100644 --- a/vendor/sdl3/include/SDL_misc.h +++ b/vendor/sdl3/include/SDL_misc.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -65,6 +65,8 @@ extern "C" { * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function should only be called on the main thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_OpenURL(const char *url); diff --git a/vendor/sdl3/include/SDL_mouse.h b/vendor/sdl3/include/SDL_mouse.h index 864135d2b..fb03c0178 100644 --- a/vendor/sdl3/include/SDL_mouse.h +++ b/vendor/sdl3/include/SDL_mouse.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -130,6 +130,17 @@ typedef enum SDL_MouseWheelDirection SDL_MOUSEWHEEL_FLIPPED /**< The scroll direction is flipped / natural */ } SDL_MouseWheelDirection; +/** + * Animated cursor frame info. + * + * \since This struct is available since SDL 3.4.0. + */ +typedef struct SDL_CursorFrameInfo +{ + SDL_Surface *surface; /**< The surface data for this frame */ + Uint32 duration; /**< The frame duration in milliseconds (a duration of 0 is infinite) */ +} SDL_CursorFrameInfo; + /** * A bitmask of pressed mouse buttons, as reported by SDL_GetMouseState, etc. * @@ -160,6 +171,44 @@ typedef Uint32 SDL_MouseButtonFlags; #define SDL_BUTTON_X1MASK SDL_BUTTON_MASK(SDL_BUTTON_X1) #define SDL_BUTTON_X2MASK SDL_BUTTON_MASK(SDL_BUTTON_X2) +/** + * A callback used to transform mouse motion delta from raw values. + * + * This is called during SDL's handling of platform mouse events to scale the + * values of the resulting motion delta. + * + * \param userdata what was passed as `userdata` to + * SDL_SetRelativeMouseTransform(). + * \param timestamp the associated time at which this mouse motion event was + * received. + * \param window the associated window to which this mouse motion event was + * addressed. + * \param mouseID the associated mouse from which this mouse motion event was + * emitted. + * \param x pointer to a variable that will be treated as the resulting x-axis + * motion. + * \param y pointer to a variable that will be treated as the resulting y-axis + * motion. + * + * \threadsafety This callback is called by SDL's internal mouse input + * processing procedure, which may be a thread separate from the + * main event loop that is run at realtime priority. Stalling + * this thread with too much work in the callback can therefore + * potentially freeze the entire system. Care should be taken + * with proper synchronization practices when adding other side + * effects beyond mutation of the x and y values. + * + * \since This datatype is available since SDL 3.4.0. + * + * \sa SDL_SetRelativeMouseTransform + */ +typedef void (SDLCALL *SDL_MouseMotionTransformCallback)( + void *userdata, + Uint64 timestamp, + SDL_Window *window, + SDL_MouseID mouseID, + float *x, float *y +); /* Function prototypes */ @@ -380,6 +429,24 @@ extern SDL_DECLSPEC void SDLCALL SDL_WarpMouseInWindow(SDL_Window *window, */ extern SDL_DECLSPEC bool SDLCALL SDL_WarpMouseGlobal(float x, float y); +/** + * Set a user-defined function by which to transform relative mouse inputs. + * + * This overrides the relative system scale and relative speed scale hints. + * Should be called prior to enabling relative mouse mode, fails otherwise. + * + * \param callback a callback used to transform relative mouse motion, or NULL + * for default behavior. + * \param userdata a pointer that will be passed to `callback`. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC bool SDLCALL SDL_SetRelativeMouseTransform(SDL_MouseMotionTransformCallback callback, void *userdata); + /** * Set relative mouse mode for a window. * @@ -509,6 +576,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_CaptureMouse(bool enabled); * * \since This function is available since SDL 3.2.0. * + * \sa SDL_CreateAnimatedCursor * \sa SDL_CreateColorCursor * \sa SDL_CreateSystemCursor * \sa SDL_DestroyCursor @@ -522,15 +590,17 @@ extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_CreateCursor(const Uint8 *data, /** * Create a color cursor. * - * If this function is passed a surface with alternate representations, the - * surface will be interpreted as the content to be used for 100% display - * scale, and the alternate representations will be used for high DPI - * situations. For example, if the original surface is 32x32, then on a 2x - * macOS display or 200% display scale on Windows, a 64x64 version of the - * image will be used, if available. If a matching version of the image isn't - * available, the closest larger size image will be downscaled to the - * appropriate size and be used instead, if available. Otherwise, the closest - * smaller image will be upscaled and be used instead. + * If this function is passed a surface with alternate representations added + * with SDL_AddSurfaceAlternateImage(), the surface will be interpreted as the + * content to be used for 100% display scale, and the alternate + * representations will be used for high DPI situations if + * SDL_HINT_MOUSE_DPI_SCALE_CURSORS is enabled. For example, if the original + * surface is 32x32, then on a 2x macOS display or 200% display scale on + * Windows, a 64x64 version of the image will be used, if available. If a + * matching version of the image isn't available, the closest larger size + * image will be downscaled to the appropriate size and be used instead, if + * available. Otherwise, the closest smaller image will be upscaled and be + * used instead. * * \param surface an SDL_Surface structure representing the cursor image. * \param hot_x the x position of the cursor hot spot. @@ -542,6 +612,8 @@ extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_CreateCursor(const Uint8 *data, * * \since This function is available since SDL 3.2.0. * + * \sa SDL_AddSurfaceAlternateImage + * \sa SDL_CreateAnimatedCursor * \sa SDL_CreateCursor * \sa SDL_CreateSystemCursor * \sa SDL_DestroyCursor @@ -551,6 +623,57 @@ extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_CreateColorCursor(SDL_Surface *surf int hot_x, int hot_y); +/** + * Create an animated color cursor. + * + * Animated cursors are composed of a sequential array of frames, specified as + * surfaces and durations in an array of SDL_CursorFrameInfo structs. The hot + * spot coordinates are universal to all frames, and all frames must have the + * same dimensions. + * + * Frame durations are specified in milliseconds. A duration of 0 implies an + * infinite frame time, and the animation will stop on that frame. To create a + * one-shot animation, set the duration of the last frame in the sequence to + * 0. + * + * If this function is passed surfaces with alternate representations added + * with SDL_AddSurfaceAlternateImage(), the surfaces will be interpreted as + * the content to be used for 100% display scale, and the alternate + * representations will be used for high DPI situations. For example, if the + * original surfaces are 32x32, then on a 2x macOS display or 200% display + * scale on Windows, a 64x64 version of the image will be used, if available. + * If a matching version of the image isn't available, the closest larger size + * image will be downscaled to the appropriate size and be used instead, if + * available. Otherwise, the closest smaller image will be upscaled and be + * used instead. + * + * If the underlying platform does not support animated cursors, this function + * will fall back to creating a static color cursor using the first frame in + * the sequence. + * + * \param frames an array of cursor images composing the animation. + * \param frame_count the number of frames in the sequence. + * \param hot_x the x position of the cursor hot spot. + * \param hot_y the y position of the cursor hot spot. + * \returns the new cursor on success or NULL on failure; call SDL_GetError() + * for more information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_AddSurfaceAlternateImage + * \sa SDL_CreateCursor + * \sa SDL_CreateColorCursor + * \sa SDL_CreateSystemCursor + * \sa SDL_DestroyCursor + * \sa SDL_SetCursor + */ +extern SDL_DECLSPEC SDL_Cursor *SDLCALL SDL_CreateAnimatedCursor(SDL_CursorFrameInfo *frames, + int frame_count, + int hot_x, + int hot_y); + /** * Create a system cursor. * @@ -608,7 +731,7 @@ extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_GetCursor(void); * You do not have to call SDL_DestroyCursor() on the return value, but it is * safe to do so. * - * \returns the default cursor on success or NULL on failuree; call + * \returns the default cursor on success or NULL on failure; call * SDL_GetError() for more information. * * \threadsafety This function should only be called on the main thread. @@ -629,6 +752,7 @@ extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_GetDefaultCursor(void); * * \since This function is available since SDL 3.2.0. * + * \sa SDL_CreateAnimatedCursor * \sa SDL_CreateColorCursor * \sa SDL_CreateCursor * \sa SDL_CreateSystemCursor diff --git a/vendor/sdl3/include/SDL_mutex.h b/vendor/sdl3/include/SDL_mutex.h index c88ec1531..e477e2d30 100644 --- a/vendor/sdl3/include/SDL_mutex.h +++ b/vendor/sdl3/include/SDL_mutex.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -308,6 +308,8 @@ typedef struct SDL_Mutex SDL_Mutex; * \returns the initialized and unlocked mutex or NULL on failure; call * SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_DestroyMutex @@ -334,6 +336,8 @@ extern SDL_DECLSPEC SDL_Mutex * SDLCALL SDL_CreateMutex(void); * * \param mutex the mutex to lock. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_TryLockMutex @@ -355,12 +359,14 @@ extern SDL_DECLSPEC void SDLCALL SDL_LockMutex(SDL_Mutex *mutex) SDL_ACQUIRE(mut * \param mutex the mutex to try to lock. * \returns true on success, false if the mutex would block. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_LockMutex * \sa SDL_UnlockMutex */ -extern SDL_DECLSPEC bool SDLCALL SDL_TryLockMutex(SDL_Mutex *mutex) SDL_TRY_ACQUIRE(0, mutex); +extern SDL_DECLSPEC bool SDLCALL SDL_TryLockMutex(SDL_Mutex *mutex) SDL_TRY_ACQUIRE(true, mutex); /** * Unlock the mutex. @@ -374,6 +380,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_TryLockMutex(SDL_Mutex *mutex) SDL_TRY_ACQU * * \param mutex the mutex to unlock. * + * \threadsafety This call must be paired with a previous locking call on the same thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_LockMutex @@ -392,6 +400,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnlockMutex(SDL_Mutex *mutex) SDL_RELEASE(m * * \param mutex the mutex to destroy. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_CreateMutex @@ -457,6 +467,8 @@ typedef struct SDL_RWLock SDL_RWLock; * \returns the initialized and unlocked read/write lock or NULL on failure; * call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_DestroyRWLock @@ -497,6 +509,8 @@ extern SDL_DECLSPEC SDL_RWLock * SDLCALL SDL_CreateRWLock(void); * * \param rwlock the read/write lock to lock. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_LockRWLockForWriting @@ -528,6 +542,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_LockRWLockForReading(SDL_RWLock *rwlock) SD * * \param rwlock the read/write lock to lock. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_LockRWLockForReading @@ -553,13 +569,15 @@ extern SDL_DECLSPEC void SDLCALL SDL_LockRWLockForWriting(SDL_RWLock *rwlock) SD * \param rwlock the rwlock to try to lock. * \returns true on success, false if the lock would block. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_LockRWLockForReading * \sa SDL_TryLockRWLockForWriting * \sa SDL_UnlockRWLock */ -extern SDL_DECLSPEC bool SDLCALL SDL_TryLockRWLockForReading(SDL_RWLock *rwlock) SDL_TRY_ACQUIRE_SHARED(0, rwlock); +extern SDL_DECLSPEC bool SDLCALL SDL_TryLockRWLockForReading(SDL_RWLock *rwlock) SDL_TRY_ACQUIRE_SHARED(true, rwlock); /** * Try to lock a read/write lock _for writing_ without blocking. @@ -583,13 +601,15 @@ extern SDL_DECLSPEC bool SDLCALL SDL_TryLockRWLockForReading(SDL_RWLock *rwlock) * \param rwlock the rwlock to try to lock. * \returns true on success, false if the lock would block. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_LockRWLockForWriting * \sa SDL_TryLockRWLockForReading * \sa SDL_UnlockRWLock */ -extern SDL_DECLSPEC bool SDLCALL SDL_TryLockRWLockForWriting(SDL_RWLock *rwlock) SDL_TRY_ACQUIRE(0, rwlock); +extern SDL_DECLSPEC bool SDLCALL SDL_TryLockRWLockForWriting(SDL_RWLock *rwlock) SDL_TRY_ACQUIRE(true, rwlock); /** * Unlock the read/write lock. @@ -607,6 +627,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_TryLockRWLockForWriting(SDL_RWLock *rwlock) * * \param rwlock the rwlock to unlock. * + * \threadsafety This call must be paired with a previous locking call on the same thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_LockRWLockForReading @@ -627,6 +649,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnlockRWLock(SDL_RWLock *rwlock) SDL_RELEAS * * \param rwlock the rwlock to destroy. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_CreateRWLock @@ -670,6 +694,8 @@ typedef struct SDL_Semaphore SDL_Semaphore; * \returns a new semaphore or NULL on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_DestroySemaphore @@ -689,6 +715,8 @@ extern SDL_DECLSPEC SDL_Semaphore * SDLCALL SDL_CreateSemaphore(Uint32 initial_v * * \param sem the semaphore to destroy. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_CreateSemaphore @@ -707,6 +735,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroySemaphore(SDL_Semaphore *sem); * * \param sem the semaphore wait on. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SignalSemaphore @@ -726,6 +756,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_WaitSemaphore(SDL_Semaphore *sem); * \param sem the semaphore to wait on. * \returns true if the wait succeeds, false if the wait would block. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SignalSemaphore @@ -746,6 +778,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_TryWaitSemaphore(SDL_Semaphore *sem); * indefinitely. * \returns true if the wait succeeds or false if the wait times out. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SignalSemaphore @@ -759,6 +793,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WaitSemaphoreTimeout(SDL_Semaphore *sem, Si * * \param sem the semaphore to increment. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_TryWaitSemaphore @@ -773,6 +809,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_SignalSemaphore(SDL_Semaphore *sem); * \param sem the semaphore to query. * \returns the current value of the semaphore. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC Uint32 SDLCALL SDL_GetSemaphoreValue(SDL_Semaphore *sem); @@ -806,6 +844,8 @@ typedef struct SDL_Condition SDL_Condition; * \returns a new condition variable or NULL on failure; call SDL_GetError() * for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_BroadcastCondition @@ -821,6 +861,8 @@ extern SDL_DECLSPEC SDL_Condition * SDLCALL SDL_CreateCondition(void); * * \param cond the condition variable to destroy. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_CreateCondition @@ -942,7 +984,7 @@ typedef enum SDL_InitStatus * Here is an example of using this: * * ```c - * static SDL_AtomicInitState init; + * static SDL_InitState init; * * bool InitSystem(void) * { diff --git a/vendor/sdl3/include/SDL_oldnames.h b/vendor/sdl3/include/SDL_oldnames.h index c93607e3f..b9f88b295 100644 --- a/vendor/sdl3/include/SDL_oldnames.h +++ b/vendor/sdl3/include/SDL_oldnames.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_opengl.h b/vendor/sdl3/include/SDL_opengl.h index d1b8b02a3..733f2b51a 100644 --- a/vendor/sdl3/include/SDL_opengl.h +++ b/vendor/sdl3/include/SDL_opengl.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_opengles.h b/vendor/sdl3/include/SDL_opengles.h index 4fb9a4b70..227f51be4 100644 --- a/vendor/sdl3/include/SDL_opengles.h +++ b/vendor/sdl3/include/SDL_opengles.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_opengles2.h b/vendor/sdl3/include/SDL_opengles2.h index 365898a65..2c746143f 100644 --- a/vendor/sdl3/include/SDL_opengles2.h +++ b/vendor/sdl3/include/SDL_opengles2.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_pen.h b/vendor/sdl3/include/SDL_pen.h index 5182eeb0c..978e0b6fd 100644 --- a/vendor/sdl3/include/SDL_pen.h +++ b/vendor/sdl3/include/SDL_pen.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -28,12 +28,37 @@ * handling, e.g., for input and drawing tablets or suitably equipped mobile / * tablet devices. * - * To get started with pens, simply handle SDL_EVENT_PEN_* events. When a pen - * starts providing input, SDL will assign it a unique SDL_PenID, which will - * remain for the life of the process, as long as the pen stays connected. + * To get started with pens, simply handle pen events: + * + * - SDL_EVENT_PEN_PROXIMITY_IN, SDL_EVENT_PEN_PROXIMITY_OUT + * (SDL_PenProximityEvent) + * - SDL_EVENT_PEN_DOWN, SDL_EVENT_PEN_UP (SDL_PenTouchEvent) + * - SDL_EVENT_PEN_MOTION (SDL_PenMotionEvent) + * - SDL_EVENT_PEN_BUTTON_DOWN, SDL_EVENT_PEN_BUTTON_UP (SDL_PenButtonEvent) + * - SDL_EVENT_PEN_AXIS (SDL_PenAxisEvent) * * Pens may provide more than simple touch input; they might have other axes, * such as pressure, tilt, rotation, etc. + * + * When a pen starts providing input, SDL will assign it a unique SDL_PenID, + * which will remain for the life of the process, as long as the pen stays + * connected. A pen leaving proximity (being taken far enough away from the + * digitizer tablet that it no longer reponds) and then coming back should + * fire proximity events, but the SDL_PenID should remain consistent. + * Unplugging the digitizer and reconnecting may cause future input to have a + * new SDL_PenID, as SDL may not know that this is the same hardware. + * + * Please note that various platforms vary wildly in how (and how well) they + * support pen input. If your pen supports some piece of functionality but SDL + * doesn't seem to, it might actually be the operating system's fault. For + * example, some platforms can manage multiple devices at the same time, but + * others will make any connected pens look like a single logical device, much + * how all USB mice connected to a computer will move the same system cursor. + * cursor. Other platforms might not support pen buttons, or the distance + * axis, etc. Very few platforms can even report _what_ functionality the pen + * supports in the first place, so best practices is to either build UI to let + * the user configure their pens, or be prepared to handle new functionality + * for a pen the first time an event is reported. */ #ifndef SDL_pen_h_ @@ -43,6 +68,7 @@ #include #include +#include /* Set up for C function definitions, even when using C++ */ #ifdef __cplusplus extern "C" { @@ -55,7 +81,12 @@ extern "C" { * * These show up in pen events when SDL sees input from them. They remain * consistent as long as SDL can recognize a tool to be the same pen; but if a - * pen physically leaves the area and returns, it might get a new ID. + * pen's digitizer table is physically detached from the computer, it might + * get a new ID when reconnected, as SDL won't know it's the same device. + * + * These IDs are only stable within a single run of a program; the next time a + * program is run, the pen's ID will likely be different, even if the hardware + * hasn't been disconnected, etc. * * \since This datatype is available since SDL 3.2.0. */ @@ -75,7 +106,6 @@ typedef Uint32 SDL_PenID; */ #define SDL_PEN_TOUCHID ((SDL_TouchID)-2) - /** * Pen input flags, as reported by various pen events' `pen_state` field. * @@ -83,13 +113,14 @@ typedef Uint32 SDL_PenID; */ typedef Uint32 SDL_PenInputFlags; -#define SDL_PEN_INPUT_DOWN (1u << 0) /**< pen is pressed down */ -#define SDL_PEN_INPUT_BUTTON_1 (1u << 1) /**< button 1 is pressed */ -#define SDL_PEN_INPUT_BUTTON_2 (1u << 2) /**< button 2 is pressed */ -#define SDL_PEN_INPUT_BUTTON_3 (1u << 3) /**< button 3 is pressed */ -#define SDL_PEN_INPUT_BUTTON_4 (1u << 4) /**< button 4 is pressed */ -#define SDL_PEN_INPUT_BUTTON_5 (1u << 5) /**< button 5 is pressed */ -#define SDL_PEN_INPUT_ERASER_TIP (1u << 30) /**< eraser tip is used */ +#define SDL_PEN_INPUT_DOWN (1u << 0) /**< pen is pressed down */ +#define SDL_PEN_INPUT_BUTTON_1 (1u << 1) /**< button 1 is pressed */ +#define SDL_PEN_INPUT_BUTTON_2 (1u << 2) /**< button 2 is pressed */ +#define SDL_PEN_INPUT_BUTTON_3 (1u << 3) /**< button 3 is pressed */ +#define SDL_PEN_INPUT_BUTTON_4 (1u << 4) /**< button 4 is pressed */ +#define SDL_PEN_INPUT_BUTTON_5 (1u << 5) /**< button 5 is pressed */ +#define SDL_PEN_INPUT_ERASER_TIP (1u << 30) /**< eraser tip is used */ +#define SDL_PEN_INPUT_IN_PROXIMITY (1u << 31) /**< pen is in proximity (since SDL 3.4.0) */ /** * Pen axis indices. @@ -118,10 +149,50 @@ typedef enum SDL_PenAxis SDL_PEN_AXIS_COUNT /**< Total known pen axis types in this version of SDL. This number may grow in future releases! */ } SDL_PenAxis; +/** + * An enum that describes the type of a pen device. + * + * A "direct" device is a pen that touches a graphic display (like an Apple + * Pencil on an iPad's screen). "Indirect" devices touch an external tablet + * surface that is connected to the machine but is not a display (like a + * lower-end Wacom tablet connected over USB). + * + * Apps may use this information to decide if they should draw a cursor; if + * the pen is touching the screen directly, a cursor doesn't make sense and + * can be in the way, but becomes necessary for indirect devices to know where + * on the display they are interacting. + * + * \since This enum is available since SDL 3.4.0. + */ +typedef enum SDL_PenDeviceType +{ + SDL_PEN_DEVICE_TYPE_INVALID = -1, /**< Not a valid pen device. */ + SDL_PEN_DEVICE_TYPE_UNKNOWN, /**< Don't know specifics of this pen. */ + SDL_PEN_DEVICE_TYPE_DIRECT, /**< Pen touches display. */ + SDL_PEN_DEVICE_TYPE_INDIRECT /**< Pen touches something that isn't the display. */ +} SDL_PenDeviceType; + +/** + * Get the device type of the given pen. + * + * Many platforms do not supply this information, so an app must always be + * prepared to get an SDL_PEN_DEVICE_TYPE_UNKNOWN result. + * + * \param instance_id the pen instance ID. + * \returns the device type of the given pen, or SDL_PEN_DEVICE_TYPE_INVALID + * on failure; call SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC SDL_PenDeviceType SDLCALL SDL_GetPenDeviceType(SDL_PenID instance_id); + /* Ends C function definitions when using C++ */ #ifdef __cplusplus } #endif +#include #endif /* SDL_pen_h_ */ diff --git a/vendor/sdl3/include/SDL_pixels.h b/vendor/sdl3/include/SDL_pixels.h index 39596c1c9..475e5f9c3 100644 --- a/vendor/sdl3/include/SDL_pixels.h +++ b/vendor/sdl3/include/SDL_pixels.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -451,7 +451,7 @@ typedef enum SDL_PackedLayout * expressions with side-effects here. * * \param format an SDL_PixelFormat to check. - * \returns true if the format is 10-bit, false otherwise. + * \returns true if the format is a floating point, false otherwise. * * \threadsafety It is safe to call this macro from any thread. * @@ -1096,7 +1096,7 @@ typedef enum SDL_Colorspace SDL_CHROMA_LOCATION_LEFT), */ SDL_COLORSPACE_RGB_DEFAULT = SDL_COLORSPACE_SRGB, /**< The default colorspace for RGB surfaces if no colorspace is specified */ - SDL_COLORSPACE_YUV_DEFAULT = SDL_COLORSPACE_JPEG /**< The default colorspace for YUV surfaces if no colorspace is specified */ + SDL_COLORSPACE_YUV_DEFAULT = SDL_COLORSPACE_BT601_LIMITED /**< The default colorspace for YUV surfaces if no colorspace is specified */ } SDL_Colorspace; /** @@ -1379,7 +1379,7 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_MapRGBA(const SDL_PixelFormatDetails *for * (e.g., a completely white pixel in 16-bit RGB565 format would return [0xff, * 0xff, 0xff] not [0xf8, 0xfc, 0xf8]). * - * \param pixel a pixel value. + * \param pixelvalue a pixel value. * \param format a pointer to SDL_PixelFormatDetails describing the pixel * format. * \param palette an optional palette for indexed formats, may be NULL. @@ -1397,7 +1397,7 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_MapRGBA(const SDL_PixelFormatDetails *for * \sa SDL_MapRGB * \sa SDL_MapRGBA */ -extern SDL_DECLSPEC void SDLCALL SDL_GetRGB(Uint32 pixel, const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 *r, Uint8 *g, Uint8 *b); +extern SDL_DECLSPEC void SDLCALL SDL_GetRGB(Uint32 pixelvalue, const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 *r, Uint8 *g, Uint8 *b); /** * Get RGBA values from a pixel in the specified format. @@ -1410,7 +1410,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_GetRGB(Uint32 pixel, const SDL_PixelFormatD * If the surface has no alpha component, the alpha will be returned as 0xff * (100% opaque). * - * \param pixel a pixel value. + * \param pixelvalue a pixel value. * \param format a pointer to SDL_PixelFormatDetails describing the pixel * format. * \param palette an optional palette for indexed formats, may be NULL. @@ -1429,7 +1429,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_GetRGB(Uint32 pixel, const SDL_PixelFormatD * \sa SDL_MapRGB * \sa SDL_MapRGBA */ -extern SDL_DECLSPEC void SDLCALL SDL_GetRGBA(Uint32 pixel, const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a); +extern SDL_DECLSPEC void SDLCALL SDL_GetRGBA(Uint32 pixelvalue, const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a); /* Ends C function definitions when using C++ */ diff --git a/vendor/sdl3/include/SDL_platform.h b/vendor/sdl3/include/SDL_platform.h index e40f009ba..9ad380bab 100644 --- a/vendor/sdl3/include/SDL_platform.h +++ b/vendor/sdl3/include/SDL_platform.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -51,6 +51,8 @@ extern "C" { * \returns the name of the platform. If the correct platform name is not * available, returns a string beginning with the text "Unknown". * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC const char * SDLCALL SDL_GetPlatform(void); diff --git a/vendor/sdl3/include/SDL_platform_defines.h b/vendor/sdl3/include/SDL_platform_defines.h index 6b240a8be..79631491d 100644 --- a/vendor/sdl3/include/SDL_platform_defines.h +++ b/vendor/sdl3/include/SDL_platform_defines.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -190,7 +190,7 @@ #if TARGET_OS_VISION /** - * A preprocessor macro that is only defined if compiling for VisionOS. + * A preprocessor macro that is only defined if compiling for visionOS. * * \since This macro is available since SDL 3.2.0. * @@ -202,7 +202,7 @@ #if TARGET_OS_IPHONE /** - * A preprocessor macro that is only defined if compiling for iOS. + * A preprocessor macro that is only defined if compiling for iOS or visionOS. * * \since This macro is available since SDL 3.2.0. * @@ -317,7 +317,7 @@ #define SDL_PLATFORM_CYGWIN 1 #endif -#if defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN) +#if (defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)) && !defined(__NGAGE__) /** * A preprocessor macro that is only defined if compiling for Windows. @@ -473,4 +473,25 @@ #define SDL_PLATFORM_3DS 1 #endif +#ifdef __NGAGE__ + +/** + * A preprocessor macro that is only defined if compiling for the Nokia + * N-Gage. + * + * \since This macro is available since SDL 3.4.0. + */ +#define SDL_PLATFORM_NGAGE 1 +#endif + +#ifdef __GNU__ + +/** + * A preprocessor macro that is only defined if compiling for GNU/Hurd. + * + * \since This macro is available since SDL 3.4.0. + */ +#define SDL_PLATFORM_HURD 1 +#endif + #endif /* SDL_platform_defines_h_ */ diff --git a/vendor/sdl3/include/SDL_power.h b/vendor/sdl3/include/SDL_power.h index 694fb0924..0616cc275 100644 --- a/vendor/sdl3/include/SDL_power.h +++ b/vendor/sdl3/include/SDL_power.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -88,11 +88,13 @@ typedef enum SDL_PowerState * can't determine a value or there is no battery. * \param percent a pointer filled in with the percentage of battery life * left, between 0 and 100, or NULL to ignore. This will be - * filled in with -1 we can't determine a value or there is no - * battery. + * filled in with -1 when we can't determine a value or there + * is no battery. * \returns the current battery state or `SDL_POWERSTATE_ERROR` on failure; * call SDL_GetError() for more information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_PowerState SDLCALL SDL_GetPowerInfo(int *seconds, int *percent); diff --git a/vendor/sdl3/include/SDL_process.h b/vendor/sdl3/include/SDL_process.h index 511b2f9c5..b797890d8 100644 --- a/vendor/sdl3/include/SDL_process.h +++ b/vendor/sdl3/include/SDL_process.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -166,6 +166,9 @@ typedef enum SDL_ProcessIO * - `SDL_PROP_PROCESS_CREATE_ENVIRONMENT_POINTER`: an SDL_Environment * pointer. If this property is set, it will be the entire environment for * the process, otherwise the current environment is used. + * - `SDL_PROP_PROCESS_CREATE_WORKING_DIRECTORY_STRING`: a UTF-8 encoded + * string representing the working directory for the process, defaults to + * the current working directory. * - `SDL_PROP_PROCESS_CREATE_STDIN_NUMBER`: an SDL_ProcessIO value describing * where standard input for the process comes from, defaults to * `SDL_PROCESS_STDIO_NULL`. @@ -192,6 +195,12 @@ typedef enum SDL_ProcessIO * run in the background. In this case the default input and output is * `SDL_PROCESS_STDIO_NULL` and the exitcode of the process is not * available, and will always be 0. + * - `SDL_PROP_PROCESS_CREATE_CMDLINE_STRING`: a string containing the program + * to run and any parameters. This string is passed directly to + * `CreateProcess` on Windows, and does nothing on other platforms. This + * property is only important if you want to start programs that does + * non-standard command-line processing, and in most cases using + * `SDL_PROP_PROCESS_CREATE_ARGS_POINTER` is sufficient. * * On POSIX platforms, wait() and waitpid(-1, ...) should not be called, and * SIGCHLD should not be ignored or handled because those would prevent SDL @@ -219,6 +228,7 @@ extern SDL_DECLSPEC SDL_Process * SDLCALL SDL_CreateProcessWithProperties(SDL_Pr #define SDL_PROP_PROCESS_CREATE_ARGS_POINTER "SDL.process.create.args" #define SDL_PROP_PROCESS_CREATE_ENVIRONMENT_POINTER "SDL.process.create.environment" +#define SDL_PROP_PROCESS_CREATE_WORKING_DIRECTORY_STRING "SDL.process.create.working_directory" #define SDL_PROP_PROCESS_CREATE_STDIN_NUMBER "SDL.process.create.stdin_option" #define SDL_PROP_PROCESS_CREATE_STDIN_POINTER "SDL.process.create.stdin_source" #define SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER "SDL.process.create.stdout_option" @@ -227,6 +237,7 @@ extern SDL_DECLSPEC SDL_Process * SDLCALL SDL_CreateProcessWithProperties(SDL_Pr #define SDL_PROP_PROCESS_CREATE_STDERR_POINTER "SDL.process.create.stderr_source" #define SDL_PROP_PROCESS_CREATE_STDERR_TO_STDOUT_BOOLEAN "SDL.process.create.stderr_to_stdout" #define SDL_PROP_PROCESS_CREATE_BACKGROUND_BOOLEAN "SDL.process.create.background" +#define SDL_PROP_PROCESS_CREATE_CMDLINE_STRING "SDL.process.create.cmdline" /** * Get the properties associated with a process. diff --git a/vendor/sdl3/include/SDL_properties.h b/vendor/sdl3/include/SDL_properties.h index 1f47d5f4a..abd7b2aa5 100644 --- a/vendor/sdl3/include/SDL_properties.h +++ b/vendor/sdl3/include/SDL_properties.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -59,7 +59,7 @@ extern "C" { #endif /** - * SDL properties ID + * An ID that represents a properties set. * * \since This datatype is available since SDL 3.2.0. */ @@ -80,12 +80,39 @@ typedef enum SDL_PropertyType SDL_PROPERTY_TYPE_BOOLEAN } SDL_PropertyType; +/** + * A generic property for naming things. + * + * This property is intended to be added to any SDL_PropertiesID that needs a + * generic name associated with the property set. It is not guaranteed that + * any property set will include this key, but it is convenient to have a + * standard key that any piece of code could reasonably agree to use. + * + * For example, the properties associated with an SDL_Texture might have a + * name string of "player sprites", or an SDL_AudioStream might have + * "background music", etc. This might also be useful for an SDL_IOStream to + * list the path to its asset. + * + * There is no format for the value set with this key; it is expected to be + * human-readable and informational in nature, possibly for logging or + * debugging purposes. + * + * SDL does not currently set this property on any objects it creates, but + * this may change in later versions; it is currently expected that apps and + * external libraries will take advantage of it, when appropriate. + * + * \since This macro is available since SDL 3.4.0. + */ +#define SDL_PROP_NAME_STRING "SDL.name" + /** * Get the global SDL properties. * * \returns a valid property ID on success or 0 on failure; call * SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetGlobalProperties(void); @@ -119,7 +146,9 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_CreateProperties(void); * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety It is safe to call this function from any thread. + * \threadsafety It is safe to call this function from any thread. This + * function acquires simultaneous mutex locks on both the source + * and destination property sets. * * \since This function is available since SDL 3.2.0. */ diff --git a/vendor/sdl3/include/SDL_rect.h b/vendor/sdl3/include/SDL_rect.h index eb2d34a69..883ca8d6c 100644 --- a/vendor/sdl3/include/SDL_rect.h +++ b/vendor/sdl3/include/SDL_rect.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -88,8 +88,11 @@ typedef struct SDL_Rect /** - * A rectangle, with the origin at the upper left (using floating point - * values). + * A rectangle stored using floating point values. + * + * The origin of the coordinate space is in the top-left, with increasing + * values moving down and right. The properties `x` and `y` represent the + * coordinates of the top-left corner of the rectangle. * * \since This struct is available since SDL 3.2.0. * @@ -125,10 +128,10 @@ typedef struct SDL_FRect */ SDL_FORCE_INLINE void SDL_RectToFRect(const SDL_Rect *rect, SDL_FRect *frect) { - frect->x = (float)rect->x; - frect->y = (float)rect->y; - frect->w = (float)rect->w; - frect->h = (float)rect->h; + frect->x = SDL_static_cast(float, rect->x); + frect->y = SDL_static_cast(float, rect->y); + frect->w = SDL_static_cast(float, rect->w); + frect->h = SDL_static_cast(float, rect->h); } /** @@ -234,6 +237,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HasRectIntersection(const SDL_Rect *A, cons * rectangles `A` and `B`. * \returns true if there is an intersection, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_HasRectIntersection @@ -250,6 +255,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRectIntersection(const SDL_Rect *A, cons * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_GetRectUnion(const SDL_Rect *A, const SDL_Rect *B, SDL_Rect *result); @@ -269,6 +276,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRectUnion(const SDL_Rect *A, const SDL_R * \returns true if any points were enclosed or false if all the points were * outside of the clipping rectangle. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_GetRectEnclosingPoints(const SDL_Point *points, int count, const SDL_Rect *clip, SDL_Rect *result); @@ -289,6 +298,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRectEnclosingPoints(const SDL_Point *poi * \param Y2 a pointer to the ending Y-coordinate of the line. * \returns true if there is an intersection, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_GetRectAndLineIntersection(const SDL_Rect *rect, int *X1, int *Y1, int *X2, int *Y2); @@ -324,7 +335,7 @@ SDL_FORCE_INLINE bool SDL_PointInRectFloat(const SDL_FPoint *p, const SDL_FRect } /** - * Determine whether a floating point rectangle can contain any point. + * Determine whether a floating point rectangle takes no space. * * A rectangle is considered "empty" for this function if `r` is NULL, or if * `r`'s width and/or height are < 0.0f. @@ -420,6 +431,8 @@ SDL_FORCE_INLINE bool SDL_RectsEqualFloat(const SDL_FRect *a, const SDL_FRect *b * \param B an SDL_FRect structure representing the second rectangle. * \returns true if there is an intersection, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetRectIntersection @@ -437,6 +450,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HasRectIntersectionFloat(const SDL_FRect *A * rectangles `A` and `B`. * \returns true if there is an intersection, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_HasRectIntersectionFloat @@ -453,6 +468,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRectIntersectionFloat(const SDL_FRect *A * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_GetRectUnionFloat(const SDL_FRect *A, const SDL_FRect *B, SDL_FRect *result); @@ -473,6 +490,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRectUnionFloat(const SDL_FRect *A, const * \returns true if any points were enclosed or false if all the points were * outside of the clipping rectangle. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_GetRectEnclosingPointsFloat(const SDL_FPoint *points, int count, const SDL_FRect *clip, SDL_FRect *result); @@ -494,6 +513,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRectEnclosingPointsFloat(const SDL_FPoin * \param Y2 a pointer to the ending Y-coordinate of the line. * \returns true if there is an intersection, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_GetRectAndLineIntersectionFloat(const SDL_FRect *rect, float *X1, float *Y1, float *X2, float *Y2); diff --git a/vendor/sdl3/include/SDL_render.h b/vendor/sdl3/include/SDL_render.h index c9d184cc0..87257d115 100644 --- a/vendor/sdl3/include/SDL_render.h +++ b/vendor/sdl3/include/SDL_render.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -39,9 +39,9 @@ * may also be stretched with linear interpolation. * * This API is designed to accelerate simple 2D operations. You may want more - * functionality such as polygons and particle effects and in that case you - * should use SDL's OpenGL/Direct3D support, the SDL3 GPU API, or one of the - * many good 3D engines. + * functionality such as 3D polygons and particle effects, and in that case + * you should use SDL's OpenGL/Direct3D support, the SDL3 GPU API, or one of + * the many good 3D engines. * * These functions must be called from the main thread. See this bug for * details: https://github.com/libsdl-org/SDL/issues/986 @@ -59,6 +59,7 @@ #include #include #include +#include #include /* Set up for C function definitions, even when using C++ */ @@ -73,6 +74,13 @@ extern "C" { */ #define SDL_SOFTWARE_RENDERER "software" +/** + * The name of the GPU renderer. + * + * \since This macro is available since SDL 3.4.0. + */ +#define SDL_GPU_RENDERER "gpu" + /** * Vertex structure. * @@ -97,6 +105,25 @@ typedef enum SDL_TextureAccess SDL_TEXTUREACCESS_TARGET /**< Texture can be used as a render target */ } SDL_TextureAccess; +/** + * The addressing mode for a texture when used in SDL_RenderGeometry(). + * + * This affects how texture coordinates are interpreted outside of [0, 1] + * + * Texture wrapping is always supported for power of two texture sizes, and is + * supported for other texture sizes if + * SDL_PROP_RENDERER_TEXTURE_WRAPPING_BOOLEAN is set to true. + * + * \since This enum is available since SDL 3.4.0. + */ +typedef enum SDL_TextureAddressMode +{ + SDL_TEXTURE_ADDRESS_INVALID = -1, + SDL_TEXTURE_ADDRESS_AUTO, /**< Wrapping is enabled if texture coordinates are outside [0, 1], this is the default */ + SDL_TEXTURE_ADDRESS_CLAMP, /**< Texture coordinates are clamped to the [0, 1] range */ + SDL_TEXTURE_ADDRESS_WRAP /**< The texture is repeated (tiled) */ +} SDL_TextureAddressMode; + /** * How the logical size is mapped to the output. * @@ -106,7 +133,7 @@ typedef enum SDL_RendererLogicalPresentation { SDL_LOGICAL_PRESENTATION_DISABLED, /**< There is no logical size in effect */ SDL_LOGICAL_PRESENTATION_STRETCH, /**< The rendered content is stretched to the output resolution */ - SDL_LOGICAL_PRESENTATION_LETTERBOX, /**< The rendered content is fit to the largest dimension and the other dimension is letterboxed with black bars */ + SDL_LOGICAL_PRESENTATION_LETTERBOX, /**< The rendered content is fit to the largest dimension and the other dimension is letterboxed with the clear color */ SDL_LOGICAL_PRESENTATION_OVERSCAN, /**< The rendered content is fit to the smallest dimension and the other dimension extends beyond the output bounds */ SDL_LOGICAL_PRESENTATION_INTEGER_SCALE /**< The rendered content is scaled up by integer multiples to fit the output resolution */ } SDL_RendererLogicalPresentation; @@ -267,6 +294,17 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window *window * present synchronized with the refresh rate. This property can take any * value that is supported by SDL_SetRenderVSync() for the renderer. * + * With the SDL GPU renderer (since SDL 3.4.0): + * + * - `SDL_PROP_RENDERER_CREATE_GPU_DEVICE_POINTER`: the device to use with the + * renderer, optional. + * - `SDL_PROP_RENDERER_CREATE_GPU_SHADERS_SPIRV_BOOLEAN`: the app is able to + * provide SPIR-V shaders to SDL_GPURenderState, optional. + * - `SDL_PROP_RENDERER_CREATE_GPU_SHADERS_DXIL_BOOLEAN`: the app is able to + * provide DXIL shaders to SDL_GPURenderState, optional. + * - `SDL_PROP_RENDERER_CREATE_GPU_SHADERS_MSL_BOOLEAN`: the app is able to + * provide MSL shaders to SDL_GPURenderState, optional. + * * With the vulkan renderer: * * - `SDL_PROP_RENDERER_CREATE_VULKAN_INSTANCE_POINTER`: the VkInstance to use @@ -303,6 +341,10 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRendererWithProperties(SDL_ #define SDL_PROP_RENDERER_CREATE_SURFACE_POINTER "SDL.renderer.create.surface" #define SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER "SDL.renderer.create.output_colorspace" #define SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER "SDL.renderer.create.present_vsync" +#define SDL_PROP_RENDERER_CREATE_GPU_DEVICE_POINTER "SDL.renderer.create.gpu.device" +#define SDL_PROP_RENDERER_CREATE_GPU_SHADERS_SPIRV_BOOLEAN "SDL.renderer.create.gpu.shaders_spirv" +#define SDL_PROP_RENDERER_CREATE_GPU_SHADERS_DXIL_BOOLEAN "SDL.renderer.create.gpu.shaders_dxil" +#define SDL_PROP_RENDERER_CREATE_GPU_SHADERS_MSL_BOOLEAN "SDL.renderer.create.gpu.shaders_msl" #define SDL_PROP_RENDERER_CREATE_VULKAN_INSTANCE_POINTER "SDL.renderer.create.vulkan.instance" #define SDL_PROP_RENDERER_CREATE_VULKAN_SURFACE_NUMBER "SDL.renderer.create.vulkan.surface" #define SDL_PROP_RENDERER_CREATE_VULKAN_PHYSICAL_DEVICE_POINTER "SDL.renderer.create.vulkan.physical_device" @@ -310,6 +352,53 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRendererWithProperties(SDL_ #define SDL_PROP_RENDERER_CREATE_VULKAN_GRAPHICS_QUEUE_FAMILY_INDEX_NUMBER "SDL.renderer.create.vulkan.graphics_queue_family_index" #define SDL_PROP_RENDERER_CREATE_VULKAN_PRESENT_QUEUE_FAMILY_INDEX_NUMBER "SDL.renderer.create.vulkan.present_queue_family_index" +/** + * Create a 2D GPU rendering context. + * + * The GPU device to use is passed in as a parameter. If this is NULL, then a + * device will be created normally and can be retrieved using + * SDL_GetGPURendererDevice(). + * + * The window to use is passed in as a parameter. If this is NULL, then this + * will become an offscreen renderer. In that case, you should call + * SDL_SetRenderTarget() to setup rendering to a texture, and then call + * SDL_RenderPresent() normally to complete drawing a frame. + * + * \param device the GPU device to use with the renderer, or NULL to create a + * device. + * \param window the window where rendering is displayed, or NULL to create an + * offscreen renderer. + * \returns a valid rendering context or NULL if there was an error; call + * SDL_GetError() for more information. + * + * \threadsafety If this function is called with a valid GPU device, it should + * be called on the thread that created the device. If this + * function is called with a valid window, it should be called + * on the thread that created the window. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_CreateRendererWithProperties + * \sa SDL_GetGPURendererDevice + * \sa SDL_CreateGPUShader + * \sa SDL_CreateGPURenderState + * \sa SDL_SetGPURenderState + */ +extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateGPURenderer(SDL_GPUDevice *device, SDL_Window *window); + +/** + * Return the GPU device used by a renderer. + * + * \param renderer the rendering context. + * \returns the GPU device used by the renderer, or NULL if the renderer is + * not a GPU renderer; call SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_GetGPURendererDevice(SDL_Renderer *renderer); + /** * Create a 2D software rendering context for a surface. * @@ -323,7 +412,7 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRendererWithProperties(SDL_ * \returns a valid rendering context or NULL if there was an error; call * SDL_GetError() for more information. * - * \threadsafety This function should only be called on the main thread. + * \threadsafety It is safe to call this function from any thread. * * \since This function is available since SDL 3.2.0. * @@ -389,6 +478,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetRendererName(SDL_Renderer *rende * - `SDL_PROP_RENDERER_TEXTURE_FORMATS_POINTER`: a (const SDL_PixelFormat *) * array of pixel formats, terminated with SDL_PIXELFORMAT_UNKNOWN, * representing the available texture formats for this renderer. + * - `SDL_PROP_RENDERER_TEXTURE_WRAPPING_BOOLEAN`: true if the renderer + * supports SDL_TEXTURE_ADDRESS_WRAP on non-power-of-two textures. * - `SDL_PROP_RENDERER_OUTPUT_COLORSPACE_NUMBER`: an SDL_Colorspace value * describing the colorspace for output to the display, defaults to * SDL_COLORSPACE_SRGB. @@ -465,6 +556,7 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetRendererProperties(SDL_Rende #define SDL_PROP_RENDERER_VSYNC_NUMBER "SDL.renderer.vsync" #define SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER "SDL.renderer.max_texture_size" #define SDL_PROP_RENDERER_TEXTURE_FORMATS_POINTER "SDL.renderer.texture_formats" +#define SDL_PROP_RENDERER_TEXTURE_WRAPPING_BOOLEAN "SDL.renderer.texture_wrapping" #define SDL_PROP_RENDERER_OUTPUT_COLORSPACE_NUMBER "SDL.renderer.output_colorspace" #define SDL_PROP_RENDERER_HDR_ENABLED_BOOLEAN "SDL.renderer.HDR_enabled" #define SDL_PROP_RENDERER_SDR_WHITE_POINT_FLOAT "SDL.renderer.SDR_white_point" @@ -601,6 +693,9 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureFromSurface(SDL_Rende * pixels, required * - `SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER`: the height of the texture in * pixels, required + * - `SDL_PROP_TEXTURE_CREATE_PALETTE_POINTER`: an SDL_Palette to use with + * palettized texture formats. This can be set later with + * SDL_SetTexturePalette() * - `SDL_PROP_TEXTURE_CREATE_SDR_WHITE_POINT_FLOAT`: for HDR10 and floating * point textures, this defines the value of 100% diffuse white, with higher * values being displayed in the High Dynamic Range headroom. This defaults @@ -673,9 +768,24 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureFromSurface(SDL_Rende * * With the vulkan renderer: * - * - `SDL_PROP_TEXTURE_CREATE_VULKAN_TEXTURE_NUMBER`: the VkImage with layout - * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL associated with the texture, if - * you want to wrap an existing texture. + * - `SDL_PROP_TEXTURE_CREATE_VULKAN_TEXTURE_NUMBER`: the VkImage associated + * with the texture, if you want to wrap an existing texture. + * - `SDL_PROP_TEXTURE_CREATE_VULKAN_LAYOUT_NUMBER`: the VkImageLayout for the + * VkImage, defaults to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL. + * + * With the GPU renderer: + * + * - `SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_POINTER`: the SDL_GPUTexture + * associated with the texture, if you want to wrap an existing texture. + * - `SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_UV_NUMBER`: the SDL_GPUTexture + * associated with the UV plane of an NV12 texture, if you want to wrap an + * existing texture. + * - `SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_U_NUMBER`: the SDL_GPUTexture + * associated with the U plane of a YUV texture, if you want to wrap an + * existing texture. + * - `SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_V_NUMBER`: the SDL_GPUTexture + * associated with the V plane of a YUV texture, if you want to wrap an + * existing texture. * * \param renderer the rendering context. * \param props the properties to use. @@ -695,29 +805,35 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureFromSurface(SDL_Rende */ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_PropertiesID props); -#define SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER "SDL.texture.create.colorspace" -#define SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER "SDL.texture.create.format" -#define SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER "SDL.texture.create.access" -#define SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER "SDL.texture.create.width" -#define SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER "SDL.texture.create.height" -#define SDL_PROP_TEXTURE_CREATE_SDR_WHITE_POINT_FLOAT "SDL.texture.create.SDR_white_point" -#define SDL_PROP_TEXTURE_CREATE_HDR_HEADROOM_FLOAT "SDL.texture.create.HDR_headroom" -#define SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_POINTER "SDL.texture.create.d3d11.texture" -#define SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_U_POINTER "SDL.texture.create.d3d11.texture_u" -#define SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_V_POINTER "SDL.texture.create.d3d11.texture_v" -#define SDL_PROP_TEXTURE_CREATE_D3D12_TEXTURE_POINTER "SDL.texture.create.d3d12.texture" -#define SDL_PROP_TEXTURE_CREATE_D3D12_TEXTURE_U_POINTER "SDL.texture.create.d3d12.texture_u" -#define SDL_PROP_TEXTURE_CREATE_D3D12_TEXTURE_V_POINTER "SDL.texture.create.d3d12.texture_v" -#define SDL_PROP_TEXTURE_CREATE_METAL_PIXELBUFFER_POINTER "SDL.texture.create.metal.pixelbuffer" -#define SDL_PROP_TEXTURE_CREATE_OPENGL_TEXTURE_NUMBER "SDL.texture.create.opengl.texture" -#define SDL_PROP_TEXTURE_CREATE_OPENGL_TEXTURE_UV_NUMBER "SDL.texture.create.opengl.texture_uv" -#define SDL_PROP_TEXTURE_CREATE_OPENGL_TEXTURE_U_NUMBER "SDL.texture.create.opengl.texture_u" -#define SDL_PROP_TEXTURE_CREATE_OPENGL_TEXTURE_V_NUMBER "SDL.texture.create.opengl.texture_v" -#define SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_NUMBER "SDL.texture.create.opengles2.texture" -#define SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_UV_NUMBER "SDL.texture.create.opengles2.texture_uv" -#define SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_U_NUMBER "SDL.texture.create.opengles2.texture_u" -#define SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_V_NUMBER "SDL.texture.create.opengles2.texture_v" -#define SDL_PROP_TEXTURE_CREATE_VULKAN_TEXTURE_NUMBER "SDL.texture.create.vulkan.texture" +#define SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER "SDL.texture.create.colorspace" +#define SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER "SDL.texture.create.format" +#define SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER "SDL.texture.create.access" +#define SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER "SDL.texture.create.width" +#define SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER "SDL.texture.create.height" +#define SDL_PROP_TEXTURE_CREATE_PALETTE_POINTER "SDL.texture.create.palette" +#define SDL_PROP_TEXTURE_CREATE_SDR_WHITE_POINT_FLOAT "SDL.texture.create.SDR_white_point" +#define SDL_PROP_TEXTURE_CREATE_HDR_HEADROOM_FLOAT "SDL.texture.create.HDR_headroom" +#define SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_POINTER "SDL.texture.create.d3d11.texture" +#define SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_U_POINTER "SDL.texture.create.d3d11.texture_u" +#define SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_V_POINTER "SDL.texture.create.d3d11.texture_v" +#define SDL_PROP_TEXTURE_CREATE_D3D12_TEXTURE_POINTER "SDL.texture.create.d3d12.texture" +#define SDL_PROP_TEXTURE_CREATE_D3D12_TEXTURE_U_POINTER "SDL.texture.create.d3d12.texture_u" +#define SDL_PROP_TEXTURE_CREATE_D3D12_TEXTURE_V_POINTER "SDL.texture.create.d3d12.texture_v" +#define SDL_PROP_TEXTURE_CREATE_METAL_PIXELBUFFER_POINTER "SDL.texture.create.metal.pixelbuffer" +#define SDL_PROP_TEXTURE_CREATE_OPENGL_TEXTURE_NUMBER "SDL.texture.create.opengl.texture" +#define SDL_PROP_TEXTURE_CREATE_OPENGL_TEXTURE_UV_NUMBER "SDL.texture.create.opengl.texture_uv" +#define SDL_PROP_TEXTURE_CREATE_OPENGL_TEXTURE_U_NUMBER "SDL.texture.create.opengl.texture_u" +#define SDL_PROP_TEXTURE_CREATE_OPENGL_TEXTURE_V_NUMBER "SDL.texture.create.opengl.texture_v" +#define SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_NUMBER "SDL.texture.create.opengles2.texture" +#define SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_UV_NUMBER "SDL.texture.create.opengles2.texture_uv" +#define SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_U_NUMBER "SDL.texture.create.opengles2.texture_u" +#define SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_V_NUMBER "SDL.texture.create.opengles2.texture_v" +#define SDL_PROP_TEXTURE_CREATE_VULKAN_TEXTURE_NUMBER "SDL.texture.create.vulkan.texture" +#define SDL_PROP_TEXTURE_CREATE_VULKAN_LAYOUT_NUMBER "SDL.texture.create.vulkan.layout" +#define SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_POINTER "SDL.texture.create.gpu.texture" +#define SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_UV_POINTER "SDL.texture.create.gpu.texture_uv" +#define SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_U_POINTER "SDL.texture.create.gpu.texture_u" +#define SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_V_POINTER "SDL.texture.create.gpu.texture_v" /** * Get the properties associated with a texture. @@ -797,6 +913,17 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureWithProperties(SDL_Re * - `SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_TARGET_NUMBER`: the GLenum for the * texture target (`GL_TEXTURE_2D`, `GL_TEXTURE_EXTERNAL_OES`, etc) * + * With the gpu renderer: + * + * - `SDL_PROP_TEXTURE_GPU_TEXTURE_POINTER`: the SDL_GPUTexture associated + * with the texture + * - `SDL_PROP_TEXTURE_GPU_TEXTURE_UV_POINTER`: the SDL_GPUTexture associated + * with the UV plane of an NV12 texture + * - `SDL_PROP_TEXTURE_GPU_TEXTURE_U_POINTER`: the SDL_GPUTexture associated + * with the U plane of a YUV texture + * - `SDL_PROP_TEXTURE_GPU_TEXTURE_V_POINTER`: the SDL_GPUTexture associated + * with the V plane of a YUV texture + * * \param texture the texture to query. * \returns a valid property ID on success or 0 on failure; call * SDL_GetError() for more information. @@ -833,6 +960,10 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetTextureProperties(SDL_Textur #define SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_V_NUMBER "SDL.texture.opengles2.texture_v" #define SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_TARGET_NUMBER "SDL.texture.opengles2.target" #define SDL_PROP_TEXTURE_VULKAN_TEXTURE_NUMBER "SDL.texture.vulkan.texture" +#define SDL_PROP_TEXTURE_GPU_TEXTURE_POINTER "SDL.texture.gpu.texture" +#define SDL_PROP_TEXTURE_GPU_TEXTURE_UV_POINTER "SDL.texture.gpu.texture_uv" +#define SDL_PROP_TEXTURE_GPU_TEXTURE_U_POINTER "SDL.texture.gpu.texture_u" +#define SDL_PROP_TEXTURE_GPU_TEXTURE_V_POINTER "SDL.texture.gpu.texture_v" /** * Get the renderer that created an SDL_Texture. @@ -864,6 +995,43 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_GetRendererFromTexture(SDL_Textur */ extern SDL_DECLSPEC bool SDLCALL SDL_GetTextureSize(SDL_Texture *texture, float *w, float *h); +/** + * Set the palette used by a texture. + * + * Setting the palette keeps an internal reference to the palette, which can + * be safely destroyed afterwards. + * + * A single palette can be shared with many textures. + * + * \param texture the texture to update. + * \param palette the SDL_Palette structure to use. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_CreatePalette + * \sa SDL_GetTexturePalette + */ +extern SDL_DECLSPEC bool SDLCALL SDL_SetTexturePalette(SDL_Texture *texture, SDL_Palette *palette); + +/** + * Get the palette used by a texture. + * + * \param texture the texture to query. + * \returns a pointer to the palette used by the texture, or NULL if there is + * no palette used. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_SetTexturePalette + */ +extern SDL_DECLSPEC SDL_Palette * SDLCALL SDL_GetTexturePalette(SDL_Texture *texture); + /** * Set an additional color value multiplied into render copy operations. * @@ -1386,14 +1554,6 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_GetRenderTarget(SDL_Renderer *rend * specific dimensions but to make fonts look sharp, the app turns off logical * presentation while drawing text, for example. * - * For the renderer's window, letterboxing is drawn into the framebuffer if - * logical presentation is enabled during SDL_RenderPresent; be sure to - * reenable it before presenting if you were toggling it, otherwise the - * letterbox areas might have artifacts from previous frames (or artifacts - * from external overlays, etc). Letterboxing is never drawn into texture - * render targets; be sure to call SDL_RenderClear() before drawing into the - * texture so the letterboxing areas are cleared, if appropriate. - * * You can convert coordinates in an event into rendering coordinates using * SDL_ConvertEventToRenderCoordinates(). * @@ -1418,15 +1578,16 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderLogicalPresentation(SDL_Renderer * * Get device independent resolution and presentation mode for rendering. * * This function gets the width and height of the logical rendering output, or - * the output size in pixels if a logical resolution is not enabled. + * 0 if a logical resolution is not enabled. * * Each render target has its own logical presentation state. This function * gets the state for the current render target. * * \param renderer the rendering context. - * \param w an int to be filled with the width. - * \param h an int to be filled with the height. - * \param mode the presentation mode used. + * \param w an int filled with the logical presentation width. + * \param h an int filled with the logical presentation height. + * \param mode a variable filled with the logical presentation mode being + * used. * \returns true on success or false on failure; call SDL_GetError() for more * information. * @@ -1545,8 +1706,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderCoordinatesToWindow(SDL_Renderer *ren * * \param renderer the rendering context. * \param event the event to modify. - * \returns true on success or false on failure; call SDL_GetError() for more - * information. + * \returns true if the event is converted or doesn't need conversion, or + * false on failure; call SDL_GetError() for more information. * * \threadsafety This function should only be called on the main thread. * @@ -2231,9 +2392,48 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderTextureTiled(SDL_Renderer *renderer, * \since This function is available since SDL 3.2.0. * * \sa SDL_RenderTexture + * \sa SDL_RenderTexture9GridTiled */ extern SDL_DECLSPEC bool SDLCALL SDL_RenderTexture9Grid(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, float left_width, float right_width, float top_height, float bottom_height, float scale, const SDL_FRect *dstrect); +/** + * Perform a scaled copy using the 9-grid algorithm to the current rendering + * target at subpixel precision. + * + * The pixels in the texture are split into a 3x3 grid, using the different + * corner sizes for each corner, and the sides and center making up the + * remaining pixels. The corners are then scaled using `scale` and fit into + * the corners of the destination rectangle. The sides and center are then + * tiled into place to cover the remaining destination rectangle. + * + * \param renderer the renderer which should copy parts of a texture. + * \param texture the source texture. + * \param srcrect the SDL_Rect structure representing the rectangle to be used + * for the 9-grid, or NULL to use the entire texture. + * \param left_width the width, in pixels, of the left corners in `srcrect`. + * \param right_width the width, in pixels, of the right corners in `srcrect`. + * \param top_height the height, in pixels, of the top corners in `srcrect`. + * \param bottom_height the height, in pixels, of the bottom corners in + * `srcrect`. + * \param scale the scale used to transform the corner of `srcrect` into the + * corner of `dstrect`, or 0.0f for an unscaled copy. + * \param dstrect a pointer to the destination rectangle, or NULL for the + * entire rendering target. + * \param tileScale the scale used to transform the borders and center of + * `srcrect` into the borders and middle of `dstrect`, or + * 1.0f for an unscaled copy. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_RenderTexture + * \sa SDL_RenderTexture9Grid + */ +extern SDL_DECLSPEC bool SDLCALL SDL_RenderTexture9GridTiled(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, float left_width, float right_width, float top_height, float bottom_height, float scale, const SDL_FRect *dstrect, float tileScale); + /** * Render a list of triangles, optionally using a texture and indices into the * vertex array Color and alpha modulation is done per vertex @@ -2255,6 +2455,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderTexture9Grid(SDL_Renderer *renderer, * \since This function is available since SDL 3.2.0. * * \sa SDL_RenderGeometryRaw + * \sa SDL_SetRenderTextureAddressMode */ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometry(SDL_Renderer *renderer, SDL_Texture *texture, @@ -2287,6 +2488,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometry(SDL_Renderer *renderer, * \since This function is available since SDL 3.2.0. * * \sa SDL_RenderGeometry + * \sa SDL_SetRenderTextureAddressMode */ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometryRaw(SDL_Renderer *renderer, SDL_Texture *texture, @@ -2296,6 +2498,48 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometryRaw(SDL_Renderer *renderer, int num_vertices, const void *indices, int num_indices, int size_indices); +/** + * Set the texture addressing mode used in SDL_RenderGeometry(). + * + * \param renderer the rendering context. + * \param u_mode the SDL_TextureAddressMode to use for horizontal texture + * coordinates in SDL_RenderGeometry(). + * \param v_mode the SDL_TextureAddressMode to use for vertical texture + * coordinates in SDL_RenderGeometry(). + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_RenderGeometry + * \sa SDL_RenderGeometryRaw + * \sa SDL_GetRenderTextureAddressMode + */ +extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderTextureAddressMode(SDL_Renderer *renderer, SDL_TextureAddressMode u_mode, SDL_TextureAddressMode v_mode); + +/** + * Get the texture addressing mode used in SDL_RenderGeometry(). + * + * \param renderer the rendering context. + * \param u_mode a pointer filled in with the SDL_TextureAddressMode to use + * for horizontal texture coordinates in SDL_RenderGeometry(), + * may be NULL. + * \param v_mode a pointer filled in with the SDL_TextureAddressMode to use + * for vertical texture coordinates in SDL_RenderGeometry(), may + * be NULL. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_SetRenderTextureAddressMode + */ +extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderTextureAddressMode(SDL_Renderer *renderer, SDL_TextureAddressMode *u_mode, SDL_TextureAddressMode *v_mode); + /** * Read pixels from the current rendering target. * @@ -2347,8 +2591,7 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_RenderReadPixels(SDL_Renderer *ren * should not be done; you are only required to change back the rendering * target to default via `SDL_SetRenderTarget(renderer, NULL)` afterwards, as * textures by themselves do not have a concept of backbuffers. Calling - * SDL_RenderPresent while rendering to a texture will still update the screen - * with any current drawing that has been done _to the window itself_. + * SDL_RenderPresent while rendering to a texture will fail. * * \param renderer the rendering context. * \returns true on success or false on failure; call SDL_GetError() for more @@ -2577,8 +2820,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderVSync(SDL_Renderer *renderer, int * Among these limitations: * * - It accepts UTF-8 strings, but will only renders ASCII characters. - * - It has a single, tiny size (8x8 pixels). One can use logical presentation - * or scaling to adjust it, but it will be blurry. + * - It has a single, tiny size (8x8 pixels). You can use logical presentation + * or SDL_SetRenderScale() to adjust it. * - It uses a simple, hardcoded bitmap font. It does not allow different font * selections and it does not support truetype, for proper scaling. * - It does no word-wrapping and does not treat newline characters as a line @@ -2612,7 +2855,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugText(SDL_Renderer *renderer, flo * Draw debug text to an SDL_Renderer. * * This function will render a printf()-style format string to a renderer. - * Note that this is a convinence function for debugging, with severe + * Note that this is a convenience function for debugging, with severe * limitations, and is not intended to be used for production apps and games. * * For the full list of limitations and other useful information, see @@ -2636,6 +2879,148 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugText(SDL_Renderer *renderer, flo */ extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugTextFormat(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(4); +/** + * Set default scale mode for new textures for given renderer. + * + * When a renderer is created, scale_mode defaults to SDL_SCALEMODE_LINEAR. + * + * \param renderer the renderer to update. + * \param scale_mode the scale mode to change to for new textures. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_GetDefaultTextureScaleMode + */ +extern SDL_DECLSPEC bool SDLCALL SDL_SetDefaultTextureScaleMode(SDL_Renderer *renderer, SDL_ScaleMode scale_mode); + +/** + * Get default texture scale mode of the given renderer. + * + * \param renderer the renderer to get data from. + * \param scale_mode a SDL_ScaleMode filled with current default scale mode. + * See SDL_SetDefaultTextureScaleMode() for the meaning of + * the value. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_SetDefaultTextureScaleMode + */ +extern SDL_DECLSPEC bool SDLCALL SDL_GetDefaultTextureScaleMode(SDL_Renderer *renderer, SDL_ScaleMode *scale_mode); + +/** + * A structure specifying the parameters of a GPU render state. + * + * \since This struct is available since SDL 3.4.0. + * + * \sa SDL_CreateGPURenderState + */ +typedef struct SDL_GPURenderStateCreateInfo +{ + SDL_GPUShader *fragment_shader; /**< The fragment shader to use when this render state is active */ + + Sint32 num_sampler_bindings; /**< The number of additional fragment samplers to bind when this render state is active */ + const SDL_GPUTextureSamplerBinding *sampler_bindings; /**< Additional fragment samplers to bind when this render state is active */ + + Sint32 num_storage_textures; /**< The number of storage textures to bind when this render state is active */ + SDL_GPUTexture *const *storage_textures; /**< Storage textures to bind when this render state is active */ + + Sint32 num_storage_buffers; /**< The number of storage buffers to bind when this render state is active */ + SDL_GPUBuffer *const *storage_buffers; /**< Storage buffers to bind when this render state is active */ + + SDL_PropertiesID props; /**< A properties ID for extensions. Should be 0 if no extensions are needed. */ +} SDL_GPURenderStateCreateInfo; + +/** + * A custom GPU render state. + * + * \since This struct is available since SDL 3.4.0. + * + * \sa SDL_CreateGPURenderState + * \sa SDL_SetGPURenderStateFragmentUniforms + * \sa SDL_SetGPURenderState + * \sa SDL_DestroyGPURenderState + */ +typedef struct SDL_GPURenderState SDL_GPURenderState; + +/** + * Create custom GPU render state. + * + * \param renderer the renderer to use. + * \param createinfo a struct describing the GPU render state to create. + * \returns a custom GPU render state or NULL on failure; call SDL_GetError() + * for more information. + * + * \threadsafety This function should be called on the thread that created the + * renderer. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_SetGPURenderStateFragmentUniforms + * \sa SDL_SetGPURenderState + * \sa SDL_DestroyGPURenderState + */ +extern SDL_DECLSPEC SDL_GPURenderState * SDLCALL SDL_CreateGPURenderState(SDL_Renderer *renderer, const SDL_GPURenderStateCreateInfo *createinfo); + +/** + * Set fragment shader uniform variables in a custom GPU render state. + * + * The data is copied and will be pushed using + * SDL_PushGPUFragmentUniformData() during draw call execution. + * + * \param state the state to modify. + * \param slot_index the fragment uniform slot to push data to. + * \param data client data to write. + * \param length the length of the data to write. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * renderer. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC bool SDLCALL SDL_SetGPURenderStateFragmentUniforms(SDL_GPURenderState *state, Uint32 slot_index, const void *data, Uint32 length); + +/** + * Set custom GPU render state. + * + * This function sets custom GPU render state for subsequent draw calls. This + * allows using custom shaders with the GPU renderer. + * + * \param renderer the renderer to use. + * \param state the state to to use, or NULL to clear custom GPU render state. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * renderer. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC bool SDLCALL SDL_SetGPURenderState(SDL_Renderer *renderer, SDL_GPURenderState *state); + +/** + * Destroy custom GPU render state. + * + * \param state the state to destroy. + * + * \threadsafety This function should be called on the thread that created the + * renderer. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_CreateGPURenderState + */ +extern SDL_DECLSPEC void SDLCALL SDL_DestroyGPURenderState(SDL_GPURenderState *state); + /* Ends C function definitions when using C++ */ #ifdef __cplusplus } diff --git a/vendor/sdl3/include/SDL_revision.h b/vendor/sdl3/include/SDL_revision.h index 9fb9937d9..3441b119c 100644 --- a/vendor/sdl3/include/SDL_revision.h +++ b/vendor/sdl3/include/SDL_revision.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -48,9 +48,9 @@ */ #define SDL_REVISION "Some arbitrary string decided at SDL build time" #elif defined(SDL_VENDOR_INFO) -#define SDL_REVISION "release-3.2.16-0-gc9a6709bd (" SDL_VENDOR_INFO ")" +#define SDL_REVISION "SDL-release-3.4.2-0-g683181b47 (" SDL_VENDOR_INFO ")" #else -#define SDL_REVISION "release-3.2.16-0-gc9a6709bd" +#define SDL_REVISION "SDL-release-3.4.2-0-g683181b47" #endif #endif /* SDL_revision_h_ */ diff --git a/vendor/sdl3/include/SDL_scancode.h b/vendor/sdl3/include/SDL_scancode.h index 9650a6cfe..cd5a1376a 100644 --- a/vendor/sdl3/include/SDL_scancode.h +++ b/vendor/sdl3/include/SDL_scancode.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -208,7 +208,7 @@ typedef enum SDL_Scancode SDL_SCANCODE_NONUSBACKSLASH = 100, /**< This is the additional key that ISO * keyboards have over ANSI ones, - * located between left shift and Y. + * located between left shift and Z. * Produces GRAVE ACCENT and TILDE in a * US or UK Mac layout, REVERSE SOLIDUS * (backslash) and VERTICAL LINE in a diff --git a/vendor/sdl3/include/SDL_sensor.h b/vendor/sdl3/include/SDL_sensor.h index b220f0538..bf890472f 100644 --- a/vendor/sdl3/include/SDL_sensor.h +++ b/vendor/sdl3/include/SDL_sensor.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -138,7 +138,8 @@ typedef enum SDL_SensorType SDL_SENSOR_ACCEL_L, /**< Accelerometer for left Joy-Con controller and Wii nunchuk */ SDL_SENSOR_GYRO_L, /**< Gyroscope for left Joy-Con controller */ SDL_SENSOR_ACCEL_R, /**< Accelerometer for right Joy-Con controller */ - SDL_SENSOR_GYRO_R /**< Gyroscope for right Joy-Con controller */ + SDL_SENSOR_GYRO_R, /**< Gyroscope for right Joy-Con controller */ + SDL_SENSOR_COUNT } SDL_SensorType; diff --git a/vendor/sdl3/include/SDL_stdinc.h b/vendor/sdl3/include/SDL_stdinc.h index 7df253fec..1c4d8da63 100644 --- a/vendor/sdl3/include/SDL_stdinc.h +++ b/vendor/sdl3/include/SDL_stdinc.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -49,10 +49,37 @@ #include #include -#include #include #include +/* Most everything except Visual Studio 2008 and earlier has stdint.h now */ +#if defined(_MSC_VER) && (_MSC_VER < 1600) +typedef signed __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef signed __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef signed __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; +#ifndef _INTPTR_T_DEFINED +#ifdef _WIN64 +typedef __int64 intptr_t; +#else +typedef int intptr_t; +#endif +#endif +#ifndef _UINTPTR_T_DEFINED +#ifdef _WIN64 +typedef unsigned __int64 uintptr_t; +#else +typedef unsigned int uintptr_t; +#endif +#endif +#else +#include +#endif + #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ defined(SDL_INCLUDE_INTTYPES_H) #include @@ -227,12 +254,6 @@ void *alloca(size_t); /** * Macro useful for building other macros with strings in them. * - * For example: - * - * ```c - * #define LOG_ERROR(X) OutputDebugString(SDL_STRINGIFY_ARG(__FUNCTION__) ": " X "\n")` - * ``` - * * \param arg the text to turn into a string literal. * * \since This macro is available since SDL 3.2.0. @@ -492,7 +513,7 @@ typedef uint64_t Uint64; * and SDL_SECONDS_TO_NS(), and between Windows FILETIME values with * SDL_TimeToWindows() and SDL_TimeFromWindows(). * - * \since This macro is available since SDL 3.2.0. + * \since This datatype is available since SDL 3.2.0. * * \sa SDL_MAX_SINT64 * \sa SDL_MIN_SINT64 @@ -1164,7 +1185,7 @@ typedef struct SDL_alignment_test void *b; } SDL_alignment_test; SDL_COMPILE_TIME_ASSERT(struct_alignment, sizeof(SDL_alignment_test) == (2 * sizeof(void *))); -SDL_COMPILE_TIME_ASSERT(two_s_complement, (int)~(int)0 == (int)(-1)); +SDL_COMPILE_TIME_ASSERT(two_s_complement, SDL_static_cast(int, ~SDL_static_cast(int, 0)) == SDL_static_cast(int, -1)); #endif /* DOXYGEN_SHOULD_IGNORE_THIS */ /** \endcond */ @@ -2119,7 +2140,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_abs(int x); * * \param x the first value to compare. * \param y the second value to compare. - * \returns the lesser of `x` and `y`. + * \returns the greater of `x` and `y`. * * \threadsafety It is safe to call this macro from any thread. * @@ -2640,7 +2661,7 @@ extern SDL_DECLSPEC void * SDLCALL SDL_memset4(void *dst, Uint32 val, size_t dwo * \since This macro is available since SDL 3.2.0. * * \sa SDL_zero - * \sa SDL_zeroa + * \sa SDL_zerop */ #define SDL_zeroa(x) SDL_memset((x), 0, sizeof((x))) @@ -3426,7 +3447,7 @@ extern SDL_DECLSPEC size_t SDLCALL SDL_utf8strnlen(const char *str, size_t bytes * Convert an integer into a string. * * This requires a radix to specified for string format. Specifying 10 - * produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2 + * produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2 * to 36. * * Note that this function will overflow a buffer if `str` is not large enough @@ -3454,7 +3475,7 @@ extern SDL_DECLSPEC char * SDLCALL SDL_itoa(int value, char *str, int radix); * Convert an unsigned integer into a string. * * This requires a radix to specified for string format. Specifying 10 - * produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2 + * produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2 * to 36. * * Note that this function will overflow a buffer if `str` is not large enough @@ -3482,7 +3503,7 @@ extern SDL_DECLSPEC char * SDLCALL SDL_uitoa(unsigned int value, char *str, int * Convert a long integer into a string. * * This requires a radix to specified for string format. Specifying 10 - * produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2 + * produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2 * to 36. * * Note that this function will overflow a buffer if `str` is not large enough @@ -3510,7 +3531,7 @@ extern SDL_DECLSPEC char * SDLCALL SDL_ltoa(long value, char *str, int radix); * Convert an unsigned long integer into a string. * * This requires a radix to specified for string format. Specifying 10 - * produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2 + * produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2 * to 36. * * Note that this function will overflow a buffer if `str` is not large enough @@ -3540,7 +3561,7 @@ extern SDL_DECLSPEC char * SDLCALL SDL_ultoa(unsigned long value, char *str, int * Convert a long long integer into a string. * * This requires a radix to specified for string format. Specifying 10 - * produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2 + * produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2 * to 36. * * Note that this function will overflow a buffer if `str` is not large enough @@ -3568,7 +3589,7 @@ extern SDL_DECLSPEC char * SDLCALL SDL_lltoa(long long value, char *str, int rad * Convert an unsigned long long integer into a string. * * This requires a radix to specified for string format. Specifying 10 - * produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2 + * produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2 * to 36. * * Note that this function will overflow a buffer if `str` is not large enough @@ -3923,7 +3944,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_strcasecmp(const char *str1, const char *str extern SDL_DECLSPEC int SDLCALL SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen); /** - * Searches a string for the first occurence of any character contained in a + * Searches a string for the first occurrence of any character contained in a * breakset, and returns a pointer from the string to that character. * * \param str The null-terminated string to be searched. Must not be NULL, and @@ -3931,7 +3952,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_strncasecmp(const char *str1, const char *st * \param breakset A null-terminated string containing the list of characters * to look for. Must not be NULL, and must not overlap with * `str`. - * \returns A pointer to the location, in str, of the first occurence of a + * \returns A pointer to the location, in str, of the first occurrence of a * character present in the breakset, or NULL if none is found. * * \threadsafety It is safe to call this function from any thread. @@ -4722,7 +4743,7 @@ extern SDL_DECLSPEC float SDLCALL SDL_atan2f(float y, float x); /** * Compute the ceiling of `x`. * - * The ceiling of `x` is the smallest integer `y` such that `y > x`, i.e `x` + * The ceiling of `x` is the smallest integer `y` such that `y >= x`, i.e `x` * rounded up to the nearest integer. * * Domain: `-INF <= x <= INF` @@ -4750,7 +4771,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_ceil(double x); /** * Compute the ceiling of `x`. * - * The ceiling of `x` is the smallest integer `y` such that `y > x`, i.e `x` + * The ceiling of `x` is the smallest integer `y` such that `y >= x`, i.e `x` * rounded up to the nearest integer. * * Domain: `-INF <= x <= INF` @@ -4992,7 +5013,7 @@ extern SDL_DECLSPEC float SDLCALL SDL_fabsf(float x); /** * Compute the floor of `x`. * - * The floor of `x` is the largest integer `y` such that `y > x`, i.e `x` + * The floor of `x` is the largest integer `y` such that `y <= x`, i.e `x` * rounded down to the nearest integer. * * Domain: `-INF <= x <= INF` @@ -5020,7 +5041,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_floor(double x); /** * Compute the floor of `x`. * - * The floor of `x` is the largest integer `y` such that `y > x`, i.e `x` + * The floor of `x` is the largest integer `y` such that `y <= x`, i.e `x` * rounded down to the nearest integer. * * Domain: `-INF <= x <= INF` @@ -5794,6 +5815,8 @@ typedef struct SDL_iconv_data_t *SDL_iconv_t; * \returns a handle that must be freed with SDL_iconv_close, or * SDL_ICONV_ERROR on failure. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_iconv @@ -5809,6 +5832,8 @@ extern SDL_DECLSPEC SDL_iconv_t SDLCALL SDL_iconv_open(const char *tocode, * \param cd The character set conversion handle. * \returns 0 on success, or -1 on failure. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_iconv @@ -5821,7 +5846,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_iconv_close(SDL_iconv_t cd); * This function converts text between encodings, reading from and writing to * a buffer. * - * It returns the number of succesful conversions on success. On error, + * It returns the number of successful conversions on success. On error, * SDL_ICONV_E2BIG is returned when the output buffer is too small, or * SDL_ICONV_EILSEQ is returned when an invalid input sequence is encountered, * or SDL_ICONV_EINVAL is returned when an incomplete input sequence is @@ -5847,6 +5872,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_iconv_close(SDL_iconv_t cd); * \param outbytesleft The number of bytes in the output buffer. * \returns the number of conversions on success, or a negative error code. * + * \threadsafety Do not use the same SDL_iconv_t from two threads at once. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_iconv_open @@ -5882,6 +5909,8 @@ extern SDL_DECLSPEC size_t SDLCALL SDL_iconv(SDL_iconv_t cd, const char **inbuf, * \param inbytesleft the size of the input string _in bytes_. * \returns a new string, converted to the new encoding, or NULL on error. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_iconv_open @@ -5905,6 +5934,8 @@ extern SDL_DECLSPEC char * SDLCALL SDL_iconv_string(const char *tocode, * \param S the string to convert. * \returns a new string, converted to the new encoding, or NULL on error. * + * \threadsafety It is safe to call this macro from any thread. + * * \since This macro is available since SDL 3.2.0. */ #define SDL_iconv_utf8_locale(S) SDL_iconv_string("", "UTF-8", S, SDL_strlen(S)+1) @@ -5919,9 +5950,11 @@ extern SDL_DECLSPEC char * SDLCALL SDL_iconv_string(const char *tocode, * \param S the string to convert. * \returns a new string, converted to the new encoding, or NULL on error. * + * \threadsafety It is safe to call this macro from any thread. + * * \since This macro is available since SDL 3.2.0. */ -#define SDL_iconv_utf8_ucs2(S) (Uint16 *)SDL_iconv_string("UCS-2", "UTF-8", S, SDL_strlen(S)+1) +#define SDL_iconv_utf8_ucs2(S) SDL_reinterpret_cast(Uint16 *, SDL_iconv_string("UCS-2", "UTF-8", S, SDL_strlen(S)+1)) /** * Convert a UTF-8 string to UCS-4. @@ -5933,9 +5966,11 @@ extern SDL_DECLSPEC char * SDLCALL SDL_iconv_string(const char *tocode, * \param S the string to convert. * \returns a new string, converted to the new encoding, or NULL on error. * + * \threadsafety It is safe to call this macro from any thread. + * * \since This macro is available since SDL 3.2.0. */ -#define SDL_iconv_utf8_ucs4(S) (Uint32 *)SDL_iconv_string("UCS-4", "UTF-8", S, SDL_strlen(S)+1) +#define SDL_iconv_utf8_ucs4(S) SDL_reinterpret_cast(Uint32 *, SDL_iconv_string("UCS-4", "UTF-8", S, SDL_strlen(S)+1)) /** * Convert a wchar_t string to UTF-8. @@ -5947,9 +5982,11 @@ extern SDL_DECLSPEC char * SDLCALL SDL_iconv_string(const char *tocode, * \param S the string to convert. * \returns a new string, converted to the new encoding, or NULL on error. * + * \threadsafety It is safe to call this macro from any thread. + * * \since This macro is available since SDL 3.2.0. */ -#define SDL_iconv_wchar_utf8(S) SDL_iconv_string("UTF-8", "WCHAR_T", (char *)S, (SDL_wcslen(S)+1)*sizeof(wchar_t)) +#define SDL_iconv_wchar_utf8(S) SDL_iconv_string("UTF-8", "WCHAR_T", SDL_reinterpret_cast(const char *, S), (SDL_wcslen(S)+1)*sizeof(wchar_t)) /* force builds using Clang's static analysis tools to use literal C runtime @@ -5974,6 +6011,10 @@ size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t size); size_t wcslcat(wchar_t *dst, const wchar_t *src, size_t size); #endif +#if !defined(HAVE_STRTOK_R) && !defined(strtok_r) +char *strtok_r(char *str, const char *delim, char **saveptr); +#endif + #ifndef _WIN32 /* strdup is not ANSI but POSIX, and its prototype might be hidden... */ /* not for windows: might conflict with string.h where strdup may have diff --git a/vendor/sdl3/include/SDL_storage.h b/vendor/sdl3/include/SDL_storage.h index 6837ebaac..71d403c74 100644 --- a/vendor/sdl3/include/SDL_storage.h +++ b/vendor/sdl3/include/SDL_storage.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -334,6 +334,10 @@ typedef struct SDL_Storage SDL_Storage; /** * Opens up a read-only container for the application's filesystem. * + * By default, SDL_OpenTitleStorage uses the generic storage implementation. + * When the path override is not provided, the generic implementation will use + * the output of SDL_GetBasePath as the base path. + * * \param override a path to override the backend's default title root. * \param props a property list that may contain backend-specific information. * \returns a title storage container on success or NULL on failure; call diff --git a/vendor/sdl3/include/SDL_surface.h b/vendor/sdl3/include/SDL_surface.h index 15fce042f..885f8f5d9 100644 --- a/vendor/sdl3/include/SDL_surface.h +++ b/vendor/sdl3/include/SDL_surface.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -29,12 +29,16 @@ * provides a reasonable toolbox for transforming the data, including copying * between surfaces, filling rectangles in the image data, etc. * - * There is also a simple .bmp loader, SDL_LoadBMP(). SDL itself does not - * provide loaders for various other file formats, but there are several - * excellent external libraries that do, including its own satellite library, - * SDL_image: + * There is also a simple .bmp loader, SDL_LoadBMP(), and a simple .png + * loader, SDL_LoadPNG(). SDL itself does not provide loaders for other file + * formats, but there are several excellent external libraries that do, + * including its own satellite library, + * [SDL_image](https://wiki.libsdl.org/SDL3_image) + * . * - * https://github.com/libsdl-org/SDL_image + * In general these functions are thread-safe in that they can be called on + * different threads with different surfaces. You should not try to modify any + * surface from two threads simultaneously. */ #ifndef SDL_surface_h_ @@ -83,8 +87,9 @@ typedef Uint32 SDL_SurfaceFlags; typedef enum SDL_ScaleMode { SDL_SCALEMODE_INVALID = -1, - SDL_SCALEMODE_NEAREST, /**< nearest pixel sampling */ - SDL_SCALEMODE_LINEAR /**< linear filtering */ + SDL_SCALEMODE_NEAREST, /**< nearest pixel sampling */ + SDL_SCALEMODE_LINEAR, /**< linear filtering */ + SDL_SCALEMODE_PIXELART /**< nearest pixel sampling with improved scaling for pixel art, available since SDL 3.4.0 */ } SDL_ScaleMode; /** @@ -94,9 +99,10 @@ typedef enum SDL_ScaleMode */ typedef enum SDL_FlipMode { - SDL_FLIP_NONE, /**< Do not flip */ - SDL_FLIP_HORIZONTAL, /**< flip horizontally */ - SDL_FLIP_VERTICAL /**< flip vertically */ + SDL_FLIP_NONE, /**< Do not flip */ + SDL_FLIP_HORIZONTAL, /**< flip horizontally */ + SDL_FLIP_VERTICAL, /**< flip vertically */ + SDL_FLIP_HORIZONTAL_AND_VERTICAL = (SDL_FLIP_HORIZONTAL | SDL_FLIP_VERTICAL) /**< flip horizontally and vertically (not a diagonal flip) */ } SDL_FlipMode; #ifndef SDL_INTERNAL @@ -235,6 +241,12 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroySurface(SDL_Surface *surface); * left edge of the image, if this surface is being used as a cursor. * - `SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER`: the hotspot pixel offset from the * top edge of the image, if this surface is being used as a cursor. + * - `SDL_PROP_SURFACE_ROTATION_FLOAT`: the number of degrees a surface's data + * is meant to be rotated clockwise to make the image right-side up. Default + * 0. This is used by the camera API, if a mobile device is oriented + * differently than what its camera provides (i.e. - the camera always + * provides portrait images but the phone is being held in landscape + * orientation). Since SDL 3.4.0. * * \param surface the SDL_Surface structure to query. * \returns a valid property ID on success or 0 on failure; call @@ -251,6 +263,7 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surfac #define SDL_PROP_SURFACE_TONEMAP_OPERATOR_STRING "SDL.surface.tonemap" #define SDL_PROP_SURFACE_HOTSPOT_X_NUMBER "SDL.surface.hotspot.x" #define SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER "SDL.surface.hotspot.y" +#define SDL_PROP_SURFACE_ROTATION_FLOAT "SDL.surface.rotation" /** * Set the colorspace used by a surface. @@ -264,7 +277,8 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surfac * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -283,7 +297,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceColorspace(SDL_Surface *surface, * \returns the colorspace used by the surface, or SDL_COLORSPACE_UNKNOWN if * the surface is NULL. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -313,7 +328,8 @@ extern SDL_DECLSPEC SDL_Colorspace SDLCALL SDL_GetSurfaceColorspace(SDL_Surface * the surface didn't have an index format); call SDL_GetError() for * more information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -324,6 +340,9 @@ extern SDL_DECLSPEC SDL_Palette * SDLCALL SDL_CreateSurfacePalette(SDL_Surface * /** * Set the palette used by a surface. * + * Setting the palette keeps an internal reference to the palette, which can + * be safely destroyed afterwards. + * * A single palette can be shared with many surfaces. * * \param surface the SDL_Surface structure to update. @@ -331,7 +350,8 @@ extern SDL_DECLSPEC SDL_Palette * SDLCALL SDL_CreateSurfacePalette(SDL_Surface * * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -372,7 +392,8 @@ extern SDL_DECLSPEC SDL_Palette * SDLCALL SDL_GetSurfacePalette(SDL_Surface *sur * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -415,7 +436,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SurfaceHasAlternateImages(SDL_Surface *surf * failure; call SDL_GetError() for more information. This should be * freed with SDL_free() when it is no longer needed. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -433,7 +455,8 @@ extern SDL_DECLSPEC SDL_Surface ** SDLCALL SDL_GetSurfaceImages(SDL_Surface *sur * * \param surface the SDL_Surface structure to update. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -459,9 +482,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_RemoveSurfaceAlternateImages(SDL_Surface *s * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. The locking referred to by - * this function is making the pixels available for direct - * access, not thread-safe locking. + * \threadsafety This function can be called on different threads with + * different surfaces. The locking referred to by this function + * is making the pixels available for direct access, not + * thread-safe locking. * * \since This function is available since SDL 3.2.0. * @@ -485,6 +509,46 @@ extern SDL_DECLSPEC bool SDLCALL SDL_LockSurface(SDL_Surface *surface); */ extern SDL_DECLSPEC void SDLCALL SDL_UnlockSurface(SDL_Surface *surface); +/** + * Load a BMP or PNG image from a seekable SDL data stream. + * + * The new surface should be freed with SDL_DestroySurface(). Not doing so + * will result in a memory leak. + * + * \param src the data stream for the surface. + * \param closeio if true, calls SDL_CloseIO() on `src` before returning, even + * in the case of an error. + * \returns a pointer to a new SDL_Surface structure or NULL on failure; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_DestroySurface + * \sa SDL_LoadSurface + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_LoadSurface_IO(SDL_IOStream *src, bool closeio); + +/** + * Load a BMP or PNG image from a file. + * + * The new surface should be freed with SDL_DestroySurface(). Not doing so + * will result in a memory leak. + * + * \param file the file to load. + * \returns a pointer to a new SDL_Surface structure or NULL on failure; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_DestroySurface + * \sa SDL_LoadSurface_IO + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_LoadSurface(const char *file); + /** * Load a BMP image from a seekable SDL data stream. * @@ -543,7 +607,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_LoadBMP(const char *file); * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -553,7 +618,7 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_LoadBMP(const char *file); extern SDL_DECLSPEC bool SDLCALL SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio); /** - * Save a surface to a file. + * Save a surface to a file in BMP format. * * Surfaces with a 24-bit, 32-bit and paletted 8-bit format get saved in the * BMP directly. Other RGB formats with 8-bit or higher get converted to a @@ -566,7 +631,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStre * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -575,6 +641,94 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStre */ extern SDL_DECLSPEC bool SDLCALL SDL_SaveBMP(SDL_Surface *surface, const char *file); +/** + * Load a PNG image from a seekable SDL data stream. + * + * This is intended as a convenience function for loading images from trusted + * sources. If you want to load arbitrary images you should use libpng or + * another image loading library designed with security in mind. + * + * The new surface should be freed with SDL_DestroySurface(). Not doing so + * will result in a memory leak. + * + * \param src the data stream for the surface. + * \param closeio if true, calls SDL_CloseIO() on `src` before returning, even + * in the case of an error. + * \returns a pointer to a new SDL_Surface structure or NULL on failure; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_DestroySurface + * \sa SDL_LoadPNG + * \sa SDL_SavePNG_IO + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_LoadPNG_IO(SDL_IOStream *src, bool closeio); + +/** + * Load a PNG image from a file. + * + * This is intended as a convenience function for loading images from trusted + * sources. If you want to load arbitrary images you should use libpng or + * another image loading library designed with security in mind. + * + * The new surface should be freed with SDL_DestroySurface(). Not doing so + * will result in a memory leak. + * + * \param file the PNG file to load. + * \returns a pointer to a new SDL_Surface structure or NULL on failure; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_DestroySurface + * \sa SDL_LoadPNG_IO + * \sa SDL_SavePNG + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_LoadPNG(const char *file); + +/** + * Save a surface to a seekable SDL data stream in PNG format. + * + * \param surface the SDL_Surface structure containing the image to be saved. + * \param dst a data stream to save to. + * \param closeio if true, calls SDL_CloseIO() on `dst` before returning, even + * in the case of an error. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function can be called on different threads with + * different surfaces. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_LoadPNG_IO + * \sa SDL_SavePNG + */ +extern SDL_DECLSPEC bool SDLCALL SDL_SavePNG_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio); + +/** + * Save a surface to a file in PNG format. + * + * \param surface the SDL_Surface structure containing the image to be saved. + * \param file a file to save to. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function can be called on different threads with + * different surfaces. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_LoadPNG + * \sa SDL_SavePNG_IO + */ +extern SDL_DECLSPEC bool SDLCALL SDL_SavePNG(SDL_Surface *surface, const char *file); + /** * Set the RLE acceleration hint for a surface. * @@ -586,7 +740,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SaveBMP(SDL_Surface *surface, const char *f * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -628,7 +783,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SurfaceHasRLE(SDL_Surface *surface); * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -693,7 +849,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceColorKey(SDL_Surface *surface, Ui * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -713,7 +870,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceColorMod(SDL_Surface *surface, Ui * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -735,7 +893,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceColorMod(SDL_Surface *surface, Ui * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -773,7 +932,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceAlphaMod(SDL_Surface *surface, Ui * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -812,7 +972,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceBlendMode(SDL_Surface *surface, S * \returns true if the rectangle intersects the surface, otherwise false and * blits will be completely clipped. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -833,7 +994,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceClipRect(SDL_Surface *surface, co * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -849,12 +1011,42 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceClipRect(SDL_Surface *surface, SD * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_FlipSurface(SDL_Surface *surface, SDL_FlipMode flip); +/** + * Return a copy of a surface rotated clockwise a number of degrees. + * + * The angle of rotation can be negative for counter-clockwise rotation. + * + * When the rotation isn't a multiple of 90 degrees, the resulting surface is + * larger than the original, with the background filled in with the colorkey, + * if available, or RGBA 255/255/255/0 if not. + * + * If `surface` has the SDL_PROP_SURFACE_ROTATION_FLOAT property set on it, + * the new copy will have the adjusted value set: if the rotation property is + * 90 and `angle` was 30, the new surface will have a property value of 60 + * (that is: to be upright vs gravity, this surface needs to rotate 60 more + * degrees). However, note that further rotations on the new surface in this + * example will produce unexpected results, since the image will have resized + * and padded to accommodate the not-90 degree angle. + * + * \param surface the surface to rotate. + * \param angle the rotation angle, in degrees. + * \returns a rotated copy of the surface or NULL on failure; call + * SDL_GetError() for more information. + * + * \threadsafety This function can be called on different threads with + * different surfaces. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_RotateSurface(SDL_Surface *surface, float angle); + /** * Creates a new surface identical to the existing surface. * @@ -867,7 +1059,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FlipSurface(SDL_Surface *surface, SDL_FlipM * \returns a copy of the surface or NULL on failure; call SDL_GetError() for * more information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -888,7 +1081,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_DuplicateSurface(SDL_Surface *surf * \returns a copy of the surface or NULL on failure; call SDL_GetError() for * more information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -915,7 +1109,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_ScaleSurface(SDL_Surface *surface, * \returns the new SDL_Surface structure that is created or NULL on failure; * call SDL_GetError() for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -943,7 +1138,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_ConvertSurface(SDL_Surface *surfac * \returns the new SDL_Surface structure that is created or NULL on failure; * call SDL_GetError() for more information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -1046,7 +1242,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PremultiplyAlpha(int width, int height, SDL * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. */ @@ -1058,7 +1255,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PremultiplySurfaceAlpha(SDL_Surface *surfac * This function handles all surface formats, and ignores any clip rectangle. * * If the surface is YUV, the color is assumed to be in the sRGB colorspace, - * otherwise the color is assumed to be in the colorspace of the suface. + * otherwise the color is assumed to be in the colorspace of the surface. * * \param surface the SDL_Surface to clear. * \param r the red component of the pixel, normally in the range 0-1. @@ -1068,7 +1265,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PremultiplySurfaceAlpha(SDL_Surface *surfac * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. */ @@ -1093,7 +1291,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ClearSurface(SDL_Surface *surface, float r, * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -1120,7 +1319,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FillSurfaceRect(SDL_Surface *dst, const SDL * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -1411,7 +1611,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurface9Grid(SDL_Surface *src, const SD * \param b the blue component of the pixel in the range 0-255. * \returns a pixel value. * - * \threadsafety It is safe to call this function from any thread. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -1444,7 +1645,8 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_MapSurfaceRGB(SDL_Surface *surface, Uint8 * \param a the alpha component of the pixel in the range 0-255. * \returns a pixel value. * - * \threadsafety It is safe to call this function from any thread. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. * @@ -1475,7 +1677,8 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_MapSurfaceRGBA(SDL_Surface *surface, Uint * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. */ @@ -1501,7 +1704,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadSurfacePixel(SDL_Surface *surface, int * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. */ @@ -1526,7 +1730,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadSurfacePixelFloat(SDL_Surface *surface, * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. */ @@ -1548,7 +1753,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteSurfacePixel(SDL_Surface *surface, int * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety This function is not thread safe. + * \threadsafety This function can be called on different threads with + * different surfaces. * * \since This function is available since SDL 3.2.0. */ diff --git a/vendor/sdl3/include/SDL_system.h b/vendor/sdl3/include/SDL_system.h index 294089ff4..ec23a1fe7 100644 --- a/vendor/sdl3/include/SDL_system.h +++ b/vendor/sdl3/include/SDL_system.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -86,6 +86,8 @@ typedef bool (SDLCALL *SDL_WindowsMessageHook)(void *userdata, MSG *msg); * \param callback the SDL_WindowsMessageHook function to call. * \param userdata a pointer to pass to every iteration of `callback`. * + * \threadsafety This function should only be called on the main thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_WindowsMessageHook @@ -169,6 +171,8 @@ typedef bool (SDLCALL *SDL_X11EventHook)(void *userdata, XEvent *xevent); * \param callback the SDL_X11EventHook function to call. * \param userdata a pointer to pass to every iteration of `callback`. * + * \threadsafety This function should only be called on the main thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC void SDLCALL SDL_SetX11EventHook(SDL_X11EventHook callback, void *userdata); @@ -186,6 +190,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetX11EventHook(SDL_X11EventHook callback, * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_SetLinuxThreadPriority(Sint64 threadID, int priority); @@ -202,6 +208,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetLinuxThreadPriority(Sint64 threadID, int * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_SetLinuxThreadPriorityAndPolicy(Sint64 threadID, int sdlPriority, int schedPolicy); @@ -247,14 +255,14 @@ typedef void (SDLCALL *SDL_iOSAnimationCallback)(void *userdata); * * For more information see: * - * https://wiki.libsdl.org/SDL3/README/ios + * https://wiki.libsdl.org/SDL3/README-ios * * Note that if you use the "main callbacks" instead of a standard C `main` * function, you don't have to use this API, as SDL will manage this for you. * * Details on main callbacks are here: * - * https://wiki.libsdl.org/SDL3/README/main-functions + * https://wiki.libsdl.org/SDL3/README-main-functions * * \param window the window for which the animation callback should be set. * \param interval the number of frames after which **callback** will be @@ -264,6 +272,8 @@ typedef void (SDLCALL *SDL_iOSAnimationCallback)(void *userdata); * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function should only be called on the main thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetiOSEventPump @@ -277,6 +287,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetiOSAnimationCallback(SDL_Window *window, * * \param enabled true to enable the event pump, false to disable it. * + * \threadsafety This function should only be called on the main thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetiOSAnimationCallback @@ -370,6 +382,8 @@ extern SDL_DECLSPEC void * SDLCALL SDL_GetAndroidActivity(void); * * \returns the Android API level. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC int SDLCALL SDL_GetAndroidSDKVersion(void); @@ -379,6 +393,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetAndroidSDKVersion(void); * * \returns true if this is a Chromebook, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_IsChromebook(void); @@ -388,6 +404,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_IsChromebook(void); * * \returns true if this is a DeX docking station, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_IsDeXMode(void); @@ -605,6 +623,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SendAndroidMessage(Uint32 command, int para * * \returns true if the device is a tablet, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_IsTablet(void); @@ -616,6 +636,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_IsTablet(void); * * \returns true if the device is a TV, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_IsTV(void); diff --git a/vendor/sdl3/include/SDL_test.h b/vendor/sdl3/include/SDL_test.h index 8b285807c..59a3dd846 100644 --- a/vendor/sdl3/include/SDL_test.h +++ b/vendor/sdl3/include/SDL_test.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_test_assert.h b/vendor/sdl3/include/SDL_test_assert.h index c067608a5..ff41b31b9 100644 --- a/vendor/sdl3/include/SDL_test_assert.h +++ b/vendor/sdl3/include/SDL_test_assert.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_test_common.h b/vendor/sdl3/include/SDL_test_common.h index 91efe8ac3..6afd85779 100644 --- a/vendor/sdl3/include/SDL_test_common.h +++ b/vendor/sdl3/include/SDL_test_common.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -153,6 +153,10 @@ typedef struct SDL_Rect confine; bool hide_cursor; + /* Misc. */ + int quit_after_ms_interval; + SDL_TimerID quit_after_ms_timer; + /* Options info */ SDLTest_ArgumentParser common_argparser; SDLTest_ArgumentParser video_argparser; diff --git a/vendor/sdl3/include/SDL_test_compare.h b/vendor/sdl3/include/SDL_test_compare.h index 7ff247793..58e55134e 100644 --- a/vendor/sdl3/include/SDL_test_compare.h +++ b/vendor/sdl3/include/SDL_test_compare.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -52,6 +52,7 @@ extern "C" { * \returns 0 if comparison succeeded, >0 (=number of pixels for which the comparison failed) if comparison failed, -1 if any of the surfaces were NULL, -2 if the surface sizes differ. */ int SDLCALL SDLTest_CompareSurfaces(SDL_Surface *surface, SDL_Surface *referenceSurface, int allowable_error); +int SDLCALL SDLTest_CompareSurfacesIgnoreTransparentPixels(SDL_Surface *surface, SDL_Surface *referenceSurface, int allowable_error); /** * Compares 2 memory blocks for equality diff --git a/vendor/sdl3/include/SDL_test_crc32.h b/vendor/sdl3/include/SDL_test_crc32.h index 94fe1a345..f563d5dd2 100644 --- a/vendor/sdl3/include/SDL_test_crc32.h +++ b/vendor/sdl3/include/SDL_test_crc32.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_test_font.h b/vendor/sdl3/include/SDL_test_font.h index fb4079497..f5b567454 100644 --- a/vendor/sdl3/include/SDL_test_font.h +++ b/vendor/sdl3/include/SDL_test_font.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_test_fuzzer.h b/vendor/sdl3/include/SDL_test_fuzzer.h index caf11f252..e8ebc45c9 100644 --- a/vendor/sdl3/include/SDL_test_fuzzer.h +++ b/vendor/sdl3/include/SDL_test_fuzzer.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_test_harness.h b/vendor/sdl3/include/SDL_test_harness.h index 5d4963e77..37710455b 100644 --- a/vendor/sdl3/include/SDL_test_harness.h +++ b/vendor/sdl3/include/SDL_test_harness.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_test_log.h b/vendor/sdl3/include/SDL_test_log.h index 0d48044a0..13933da95 100644 --- a/vendor/sdl3/include/SDL_test_log.h +++ b/vendor/sdl3/include/SDL_test_log.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -42,6 +42,14 @@ extern "C" { #endif +/** + * Prints given message with a timestamp in the TEST category and given priority. + * + * \param priority Priority of the message + * \param fmt Message to be logged + */ +void SDLCALL SDLTest_LogMessage(SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, ...); + /** * Prints given message with a timestamp in the TEST category and INFO priority. * diff --git a/vendor/sdl3/include/SDL_test_md5.h b/vendor/sdl3/include/SDL_test_md5.h index e9d96398a..7b86b05f7 100644 --- a/vendor/sdl3/include/SDL_test_md5.h +++ b/vendor/sdl3/include/SDL_test_md5.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_test_memory.h b/vendor/sdl3/include/SDL_test_memory.h index 1bd946674..f07f1cba9 100644 --- a/vendor/sdl3/include/SDL_test_memory.h +++ b/vendor/sdl3/include/SDL_test_memory.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_thread.h b/vendor/sdl3/include/SDL_thread.h index e981b5429..f74317cc6 100644 --- a/vendor/sdl3/include/SDL_thread.h +++ b/vendor/sdl3/include/SDL_thread.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -37,7 +37,8 @@ * will report failure without doing anything. * * If you're going to work with threads, you almost certainly need to have a - * good understanding of [CategoryMutex](CategoryMutex) as well. + * good understanding of thread safety measures: locking and synchronization + * mechanisms are handled by the functions in SDL_mutex.h. */ #include @@ -207,6 +208,8 @@ typedef int (SDLCALL *SDL_ThreadFunction) (void *data); * new thread could not be created; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_CreateThreadWithProperties @@ -273,6 +276,8 @@ extern SDL_DECLSPEC SDL_Thread * SDLCALL SDL_CreateThread(SDL_ThreadFunction fn, * new thread could not be created; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_CreateThread @@ -328,6 +333,8 @@ extern SDL_DECLSPEC SDL_Thread * SDLCALL SDL_CreateThreadWithProperties(SDL_Prop * new thread could not be created; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_Thread * SDLCALL SDL_CreateThreadRuntime(SDL_ThreadFunction fn, const char *name, void *data, SDL_FunctionPointer pfnBeginThread, SDL_FunctionPointer pfnEndThread); @@ -342,6 +349,8 @@ extern SDL_DECLSPEC SDL_Thread * SDLCALL SDL_CreateThreadRuntime(SDL_ThreadFunct * new thread could not be created; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_Thread * SDLCALL SDL_CreateThreadWithPropertiesRuntime(SDL_PropertiesID props, SDL_FunctionPointer pfnBeginThread, SDL_FunctionPointer pfnEndThread); @@ -362,6 +371,8 @@ extern SDL_DECLSPEC SDL_Thread * SDLCALL SDL_CreateThreadWithPropertiesRuntime(S * \returns a pointer to a UTF-8 string that names the specified thread, or * NULL if it doesn't have a name. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC const char * SDLCALL SDL_GetThreadName(SDL_Thread *thread); @@ -378,6 +389,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetThreadName(SDL_Thread *thread); * * \returns the ID of the current thread. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetThreadID @@ -395,6 +408,8 @@ extern SDL_DECLSPEC SDL_ThreadID SDLCALL SDL_GetCurrentThreadID(void); * \returns the ID of the specified thread, or the ID of the current thread if * `thread` is NULL. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetCurrentThreadID @@ -412,6 +427,8 @@ extern SDL_DECLSPEC SDL_ThreadID SDLCALL SDL_GetThreadID(SDL_Thread *thread); * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_SetCurrentThreadPriority(SDL_ThreadPriority priority); @@ -444,6 +461,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetCurrentThreadPriority(SDL_ThreadPriority * function by its 'return', or -1 if the thread has been * detached or isn't valid, may be NULL. * + * \threadsafety It is safe to call this function from any thread, but only + * a single thread can wait any specific thread to finish. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_CreateThread @@ -458,6 +478,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_WaitThread(SDL_Thread *thread, int *status) * \returns the current state of a thread, or SDL_THREAD_UNKNOWN if the thread * isn't valid. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_ThreadState @@ -490,6 +512,8 @@ extern SDL_DECLSPEC SDL_ThreadState SDLCALL SDL_GetThreadState(SDL_Thread *threa * * It is safe to pass NULL to this function; it is a no-op. * + * \threadsafety It is safe to call this function from any thread. + * * \param thread the SDL_Thread pointer that was returned from the * SDL_CreateThread() call that started this thread. * diff --git a/vendor/sdl3/include/SDL_time.h b/vendor/sdl3/include/SDL_time.h index b6d3f6d0d..2ae6022f9 100644 --- a/vendor/sdl3/include/SDL_time.h +++ b/vendor/sdl3/include/SDL_time.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer -Copyright (C) 1997-2025 Sam Lantinga +Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -106,6 +106,8 @@ typedef enum SDL_TimeFormat * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_GetDateTimeLocalePreferences(SDL_DateFormat *dateFormat, SDL_TimeFormat *timeFormat); @@ -118,6 +120,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetDateTimeLocalePreferences(SDL_DateFormat * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_GetCurrentTime(SDL_Time *ticks); @@ -134,6 +138,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetCurrentTime(SDL_Time *ticks); * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_TimeToDateTime(SDL_Time ticks, SDL_DateTime *dt, bool localTime); @@ -149,6 +155,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_TimeToDateTime(SDL_Time ticks, SDL_DateTime * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_DateTimeToTime(const SDL_DateTime *dt, SDL_Time *ticks); @@ -165,6 +173,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_DateTimeToTime(const SDL_DateTime *dt, SDL_ * \param dwHighDateTime a pointer filled in with the high portion of the * Windows FILETIME value. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC void SDLCALL SDL_TimeToWindows(SDL_Time ticks, Uint32 *dwLowDateTime, Uint32 *dwHighDateTime); @@ -180,6 +190,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_TimeToWindows(SDL_Time ticks, Uint32 *dwLow * \param dwHighDateTime the high portion of the Windows FILETIME value. * \returns the converted SDL time. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_Time SDLCALL SDL_TimeFromWindows(Uint32 dwLowDateTime, Uint32 dwHighDateTime); @@ -192,6 +204,8 @@ extern SDL_DECLSPEC SDL_Time SDLCALL SDL_TimeFromWindows(Uint32 dwLowDateTime, U * \returns the number of days in the requested month or -1 on failure; call * SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC int SDLCALL SDL_GetDaysInMonth(int year, int month); @@ -205,6 +219,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetDaysInMonth(int year, int month); * \returns the day of year [0-365] if the date is valid or -1 on failure; * call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC int SDLCALL SDL_GetDayOfYear(int year, int month, int day); @@ -218,6 +234,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetDayOfYear(int year, int month, int day); * \returns a value between 0 and 6 (0 being Sunday) if the date is valid or * -1 on failure; call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC int SDLCALL SDL_GetDayOfWeek(int year, int month, int day); diff --git a/vendor/sdl3/include/SDL_timer.h b/vendor/sdl3/include/SDL_timer.h index cf94881d5..dfeec31f2 100644 --- a/vendor/sdl3/include/SDL_timer.h +++ b/vendor/sdl3/include/SDL_timer.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -34,7 +34,7 @@ * This category covers measuring time elapsed (SDL_GetTicks(), * SDL_GetPerformanceCounter()), putting a thread to sleep for a certain * amount of time (SDL_Delay(), SDL_DelayNS(), SDL_DelayPrecise()), and firing - * a callback function after a certain amount of time has elasped + * a callback function after a certain amount of time has elapsed * (SDL_AddTimer(), etc). * * There are also useful macros to convert between time units, like @@ -185,14 +185,18 @@ extern "C" { #define SDL_NS_TO_US(NS) ((NS) / SDL_NS_PER_US) /** - * Get the number of milliseconds since SDL library initialization. + * Get the number of milliseconds that have elapsed since the SDL library + * initialization. * - * \returns an unsigned 64-bit value representing the number of milliseconds - * since the SDL library initialized. + * \returns an unsigned 64‑bit integer that represents the number of + * milliseconds that have elapsed since the SDL library was + * initialized (typically via a call to SDL_Init). * * \threadsafety It is safe to call this function from any thread. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_GetTicksNS */ extern SDL_DECLSPEC Uint64 SDLCALL SDL_GetTicks(void); diff --git a/vendor/sdl3/include/SDL_touch.h b/vendor/sdl3/include/SDL_touch.h index 64845a156..e5576a5bc 100644 --- a/vendor/sdl3/include/SDL_touch.h +++ b/vendor/sdl3/include/SDL_touch.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_tray.h b/vendor/sdl3/include/SDL_tray.h index 1780b0ba5..688278a1d 100644 --- a/vendor/sdl3/include/SDL_tray.h +++ b/vendor/sdl3/include/SDL_tray.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/vendor/sdl3/include/SDL_version.h b/vendor/sdl3/include/SDL_version.h index 435b3f95f..7587a6e69 100644 --- a/vendor/sdl3/include/SDL_version.h +++ b/vendor/sdl3/include/SDL_version.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -53,7 +53,7 @@ extern "C" { * * \since This macro is available since SDL 3.2.0. */ -#define SDL_MINOR_VERSION 2 +#define SDL_MINOR_VERSION 4 /** * The current micro (or patchlevel) version of the SDL headers. @@ -62,7 +62,7 @@ extern "C" { * * \since This macro is available since SDL 3.2.0. */ -#define SDL_MICRO_VERSION 16 +#define SDL_MICRO_VERSION 2 /** * This macro turns the version numbers into a numeric value. @@ -85,6 +85,8 @@ extern "C" { * * \param version the version number. * + * \threadsafety It is safe to call this macro from any thread. + * * \since This macro is available since SDL 3.2.0. */ #define SDL_VERSIONNUM_MAJOR(version) ((version) / 1000000) @@ -96,6 +98,8 @@ extern "C" { * * \param version the version number. * + * \threadsafety It is safe to call this macro from any thread. + * * \since This macro is available since SDL 3.2.0. */ #define SDL_VERSIONNUM_MINOR(version) (((version) / 1000) % 1000) @@ -107,6 +111,8 @@ extern "C" { * * \param version the version number. * + * \threadsafety It is safe to call this macro from any thread. + * * \since This macro is available since SDL 3.2.0. */ #define SDL_VERSIONNUM_MICRO(version) ((version) % 1000) @@ -114,6 +120,8 @@ extern "C" { /** * This is the version number macro for the current SDL version. * + * \threadsafety It is safe to call this macro from any thread. + * * \since This macro is available since SDL 3.2.0. * * \sa SDL_GetVersion @@ -124,6 +132,8 @@ extern "C" { /** * This macro will evaluate to true if compiled with SDL at least X.Y.Z. * + * \threadsafety It is safe to call this macro from any thread. + * * \since This macro is available since SDL 3.2.0. */ #define SDL_VERSION_ATLEAST(X, Y, Z) \ @@ -141,6 +151,8 @@ extern "C" { * * \returns the version of the linked library. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetRevision @@ -148,13 +160,14 @@ extern "C" { extern SDL_DECLSPEC int SDLCALL SDL_GetVersion(void); /** - * Get the code revision of SDL that is linked against your program. + * Get the code revision of the SDL library that is linked against your + * program. * - * This value is the revision of the code you are linked with and may be + * This value is the revision of the code you are linking against and may be * different from the code you are compiling with, which is found in the - * constant SDL_REVISION. + * constant SDL_REVISION if you explicitly include SDL_revision.h * - * The revision is arbitrary string (a hash value) uniquely identifying the + * The revision is an arbitrary string (a hash value) uniquely identifying the * exact revision of the SDL library in use, and is only useful in comparing * against other revisions. It is NOT an incrementing number. * @@ -167,6 +180,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetVersion(void); * \returns an arbitrary string, uniquely identifying the exact revision of * the SDL library in use. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetVersion diff --git a/vendor/sdl3/include/SDL_video.h b/vendor/sdl3/include/SDL_video.h index 877b9adde..2f062959f 100644 --- a/vendor/sdl3/include/SDL_video.h +++ b/vendor/sdl3/include/SDL_video.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2026 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -97,6 +97,8 @@ typedef Uint32 SDL_WindowID; * uninitialized will either return the user provided value, if one was set * prior to initialization, or NULL. See docs/README-wayland.md for more * information. + * + * \since This macro is available since SDL 3.2.0. */ #define SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER "SDL.video.wayland.wl_display" @@ -180,6 +182,12 @@ typedef struct SDL_Window SDL_Window; * changed on existing windows by the app, and some of it might be altered by * the user or system outside of the app's control. * + * When creating windows with `SDL_WINDOW_RESIZABLE`, SDL will constrain + * resizable windows to the dimensions recommended by the compositor to fit it + * within the usable desktop space, although some compositors will do this + * automatically without intervention as well. Use `SDL_SetWindowResizable` + * after creation instead if you wish to create a window with a specific size. + * * \since This datatype is available since SDL 3.2.0. * * \sa SDL_GetWindowFlags @@ -207,6 +215,7 @@ typedef Uint64 SDL_WindowFlags; #define SDL_WINDOW_TOOLTIP SDL_UINT64_C(0x0000000000040000) /**< window should be treated as a tooltip and does not get mouse or keyboard focus, requires a parent window */ #define SDL_WINDOW_POPUP_MENU SDL_UINT64_C(0x0000000000080000) /**< window should be treated as a popup menu, requires a parent window */ #define SDL_WINDOW_KEYBOARD_GRABBED SDL_UINT64_C(0x0000000000100000) /**< window has grabbed keyboard input */ +#define SDL_WINDOW_FILL_DOCUMENT SDL_UINT64_C(0x0000000000200000) /**< window is in fill-document mode (Emscripten only), since SDL 3.4.0 */ #define SDL_WINDOW_VULKAN SDL_UINT64_C(0x0000000010000000) /**< window usable for Vulkan surface */ #define SDL_WINDOW_METAL SDL_UINT64_C(0x0000000020000000) /**< window usable for Metal view */ #define SDL_WINDOW_TRANSPARENT SDL_UINT64_C(0x0000000040000000) /**< window with transparent buffer */ @@ -220,6 +229,8 @@ typedef Uint64 SDL_WindowFlags; * SDL_WINDOWPOS_UNDEFINED or SDL_WINDOWPOS_UNDEFINED_DISPLAY. * * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_SetWindowPosition */ #define SDL_WINDOWPOS_UNDEFINED_MASK 0x1FFF0000u @@ -232,6 +243,8 @@ typedef Uint64 SDL_WindowFlags; * \param X the SDL_DisplayID of the display to use. * * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_SetWindowPosition */ #define SDL_WINDOWPOS_UNDEFINED_DISPLAY(X) (SDL_WINDOWPOS_UNDEFINED_MASK|(X)) @@ -241,6 +254,8 @@ typedef Uint64 SDL_WindowFlags; * This always uses the primary display. * * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_SetWindowPosition */ #define SDL_WINDOWPOS_UNDEFINED SDL_WINDOWPOS_UNDEFINED_DISPLAY(0) @@ -250,6 +265,8 @@ typedef Uint64 SDL_WindowFlags; * \param X the window position value. * * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_SetWindowPosition */ #define SDL_WINDOWPOS_ISUNDEFINED(X) (((X)&0xFFFF0000) == SDL_WINDOWPOS_UNDEFINED_MASK) @@ -260,6 +277,8 @@ typedef Uint64 SDL_WindowFlags; * SDL_WINDOWPOS_CENTERED or SDL_WINDOWPOS_CENTERED_DISPLAY. * * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_SetWindowPosition */ #define SDL_WINDOWPOS_CENTERED_MASK 0x2FFF0000u @@ -272,6 +291,8 @@ typedef Uint64 SDL_WindowFlags; * \param X the SDL_DisplayID of the display to use. * * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_SetWindowPosition */ #define SDL_WINDOWPOS_CENTERED_DISPLAY(X) (SDL_WINDOWPOS_CENTERED_MASK|(X)) @@ -281,6 +302,8 @@ typedef Uint64 SDL_WindowFlags; * This always uses the primary display. * * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_SetWindowPosition */ #define SDL_WINDOWPOS_CENTERED SDL_WINDOWPOS_CENTERED_DISPLAY(0) @@ -290,6 +313,8 @@ typedef Uint64 SDL_WindowFlags; * \param X the window position value. * * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_GetWindowPosition */ #define SDL_WINDOWPOS_ISCENTERED(X) \ (((X)&0xFFFF0000) == SDL_WINDOWPOS_CENTERED_MASK) @@ -307,12 +332,30 @@ typedef enum SDL_FlashOperation SDL_FLASH_UNTIL_FOCUSED /**< Flash the window until it gets focus */ } SDL_FlashOperation; +/** + * Window progress state + * + * \since This enum is available since SDL 3.2.8. + */ +typedef enum SDL_ProgressState +{ + SDL_PROGRESS_STATE_INVALID = -1, /**< An invalid progress state indicating an error; check SDL_GetError() */ + SDL_PROGRESS_STATE_NONE, /**< No progress bar is shown */ + SDL_PROGRESS_STATE_INDETERMINATE, /**< The progress bar is shown in a indeterminate state */ + SDL_PROGRESS_STATE_NORMAL, /**< The progress bar is shown in a normal state */ + SDL_PROGRESS_STATE_PAUSED, /**< The progress bar is shown in a paused state */ + SDL_PROGRESS_STATE_ERROR /**< The progress bar is shown in a state indicating the application had an error */ +} SDL_ProgressState; + /** * An opaque handle to an OpenGL context. * * \since This datatype is available since SDL 3.2.0. * * \sa SDL_GL_CreateContext + * \sa SDL_GL_SetAttribute + * \sa SDL_GL_MakeCurrent + * \sa SDL_GL_DestroyContext */ typedef struct SDL_GLContextState *SDL_GLContext; @@ -448,7 +491,7 @@ typedef enum SDL_GLAttr SDL_GL_CONTEXT_FLAGS, /**< some combination of 0 or more of elements of the SDL_GLContextFlag enumeration; defaults to 0. */ SDL_GL_CONTEXT_PROFILE_MASK, /**< type of GL context (Core, Compatibility, ES). See SDL_GLProfile; default value depends on platform. */ SDL_GL_SHARE_WITH_CURRENT_CONTEXT, /**< OpenGL context sharing; defaults to 0. */ - SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, /**< requests sRGB capable visual; defaults to 0. */ + SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, /**< requests sRGB-capable visual if 1. Defaults to -1 ("don't care"). This is a request; GL drivers might not comply! */ SDL_GL_CONTEXT_RELEASE_BEHAVIOR, /**< sets context the release behavior. See SDL_GLContextReleaseFlag; defaults to FLUSH. */ SDL_GL_CONTEXT_RESET_NOTIFICATION, /**< set context reset notification. See SDL_GLContextResetNotification; defaults to NO_NOTIFICATION. */ SDL_GL_CONTEXT_NO_ERROR, @@ -530,7 +573,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetNumVideoDrivers(void); * to be proper names. * * \param index the index of a video driver. - * \returns the name of the video driver with the given **index**. + * \returns the name of the video driver with the given **index**, or NULL if + * index is out of bounds. * * \threadsafety This function should only be called on the main thread. * @@ -617,6 +661,16 @@ extern SDL_DECLSPEC SDL_DisplayID SDLCALL SDL_GetPrimaryDisplay(void); * responsible for any coordinate transformations needed to conform to the * requested display orientation. * + * On Wayland: + * + * - `SDL_PROP_DISPLAY_WAYLAND_WL_OUTPUT_POINTER`: the wl_output associated + * with the display + * + * On Windows: + * + * - `SDL_PROP_DISPLAY_WINDOWS_HMONITOR_POINTER`: the monitor handle + * (HMONITOR) associated with the display + * * \param displayID the instance ID of the display to query. * \returns a valid property ID on success or 0 on failure; call * SDL_GetError() for more information. @@ -629,6 +683,8 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetDisplayProperties(SDL_Displa #define SDL_PROP_DISPLAY_HDR_ENABLED_BOOLEAN "SDL.display.HDR_enabled" #define SDL_PROP_DISPLAY_KMSDRM_PANEL_ORIENTATION_NUMBER "SDL.display.KMSDRM.panel_orientation" +#define SDL_PROP_DISPLAY_WAYLAND_WL_OUTPUT_POINTER "SDL.display.wayland.wl_output" +#define SDL_PROP_DISPLAY_WINDOWS_HMONITOR_POINTER "SDL.display.windows.hmonitor" /** * Get the name of a display in UTF-8 encoding. @@ -1049,8 +1105,6 @@ extern SDL_DECLSPEC SDL_Window ** SDLCALL SDL_GetWindows(int *count); * * - `SDL_WINDOW_FULLSCREEN`: fullscreen window at desktop resolution * - `SDL_WINDOW_OPENGL`: window usable with an OpenGL context - * - `SDL_WINDOW_OCCLUDED`: window partially or completely obscured by another - * window * - `SDL_WINDOW_HIDDEN`: window is not visible * - `SDL_WINDOW_BORDERLESS`: no window decoration * - `SDL_WINDOW_RESIZABLE`: window can be resized @@ -1078,7 +1132,8 @@ extern SDL_DECLSPEC SDL_Window ** SDLCALL SDL_GetWindows(int *count); * - `SDL_WINDOW_TRANSPARENT`: window with transparent buffer * - `SDL_WINDOW_NOT_FOCUSABLE`: window should not be focusable * - * The SDL_Window is implicitly shown if SDL_WINDOW_HIDDEN is not set. + * The SDL_Window will be shown if SDL_WINDOW_HIDDEN is not set. If hidden at + * creation time, SDL_ShowWindow() can be used to show it later. * * On Apple's macOS, you **must** set the NSHighResolutionCapable Info.plist * property to YES, otherwise you will not receive a High-DPI OpenGL canvas. @@ -1167,6 +1222,16 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindow(const char *title, int * Popup windows implicitly do not have a border/decorations and do not appear * on the taskbar/dock or in lists of windows such as alt-tab menus. * + * By default, popup window positions will automatically be constrained to + * keep the entire window within display bounds. This can be overridden with + * the `SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN` property. + * + * By default, popup menus will automatically grab keyboard focus from the + * parent when shown. This behavior can be overridden by setting the + * `SDL_WINDOW_NOT_FOCUSABLE` flag, setting the + * `SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN` property to false, or toggling + * it after creation via the `SDL_SetWindowFocusable()` function. + * * If a parent window is hidden or destroyed, any child popup windows will be * recursively hidden or destroyed as well. Child popup windows not explicitly * hidden will be restored when the parent is shown. @@ -1207,6 +1272,10 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreatePopupWindow(SDL_Window *paren * be always on top * - `SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN`: true if the window has no * window decoration + * - `SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN`: true if the "tooltip" + * and "menu" window types should be automatically constrained to be + * entirely within display bounds (default), false if no constraints on the + * position are desired. * - `SDL_PROP_WINDOW_CREATE_EXTERNAL_GRAPHICS_CONTEXT_BOOLEAN`: true if the * window will be used with an externally managed graphics context. * - `SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN`: true if the window should @@ -1263,12 +1332,18 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreatePopupWindow(SDL_Window *paren * - `SDL_PROP_WINDOW_CREATE_COCOA_VIEW_POINTER`: the `(__unsafe_unretained)` * NSView associated with the window, defaults to `[window contentView]` * + * These are additional supported properties on iOS, tvOS, and visionOS: + * + * - `SDL_PROP_WINDOW_CREATE_WINDOWSCENE_POINTER`: the `(__unsafe_unretained)` + * UIWindowScene associated with the window, defaults to the active window + * scene. + * * These are additional supported properties on Wayland: * * - `SDL_PROP_WINDOW_CREATE_WAYLAND_SURFACE_ROLE_CUSTOM_BOOLEAN` - true if * the application wants to use the Wayland surface for a custom role and * does not want it attached to an XDG toplevel window. See - * [README/wayland](README/wayland) for more information on using custom + * [README-wayland](README-wayland) for more information on using custom * surfaces. * - `SDL_PROP_WINDOW_CREATE_WAYLAND_CREATE_EGL_WINDOW_BOOLEAN` - true if the * application wants an associated `wl_egl_window` object to be created and @@ -1276,7 +1351,7 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreatePopupWindow(SDL_Window *paren * property or `SDL_WINDOW_OPENGL` flag set. * - `SDL_PROP_WINDOW_CREATE_WAYLAND_WL_SURFACE_POINTER` - the wl_surface * associated with the window, if you want to wrap an existing window. See - * [README/wayland](README/wayland) for more information. + * [README-wayland](README-wayland) for more information. * * These are additional supported properties on Windows: * @@ -1292,8 +1367,22 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreatePopupWindow(SDL_Window *paren * * The window is implicitly shown if the "hidden" property is not set. * - * Windows with the "tooltip" and "menu" properties are popup windows and have - * the behaviors and guidelines outlined in SDL_CreatePopupWindow(). + * These are additional supported properties with Emscripten: + * + * - `SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_CANVAS_ID_STRING`: the id given to the + * canvas element. This should start with a '#' sign + * - `SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING`: override the + * binding element for keyboard inputs for this canvas. The variable can be + * one of: + * - "#window": the javascript window object (default) + * - "#document": the javascript document object + * - "#screen": the javascript window.screen object + * - "#canvas": the WebGL canvas element + * - "#none": Don't bind anything at all + * - any other string without a leading # sign applies to the element on the + * page with that ID. Windows with the "tooltip" and "menu" properties are + * popup windows and have the behaviors and guidelines outlined in + * SDL_CreatePopupWindow(). * * If this window is being created to be used with an SDL_Renderer, you should * not add a graphics API specific property @@ -1321,6 +1410,7 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindowWithProperties(SDL_Prop #define SDL_PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN "SDL.window.create.always_on_top" #define SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN "SDL.window.create.borderless" +#define SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN "SDL.window.create.constrain_popup" #define SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN "SDL.window.create.focusable" #define SDL_PROP_WINDOW_CREATE_EXTERNAL_GRAPHICS_CONTEXT_BOOLEAN "SDL.window.create.external_graphics_context" #define SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER "SDL.window.create.flags" @@ -1347,12 +1437,15 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindowWithProperties(SDL_Prop #define SDL_PROP_WINDOW_CREATE_Y_NUMBER "SDL.window.create.y" #define SDL_PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER "SDL.window.create.cocoa.window" #define SDL_PROP_WINDOW_CREATE_COCOA_VIEW_POINTER "SDL.window.create.cocoa.view" +#define SDL_PROP_WINDOW_CREATE_WINDOWSCENE_POINTER "SDL.window.create.uikit.windowscene" #define SDL_PROP_WINDOW_CREATE_WAYLAND_SURFACE_ROLE_CUSTOM_BOOLEAN "SDL.window.create.wayland.surface_role_custom" #define SDL_PROP_WINDOW_CREATE_WAYLAND_CREATE_EGL_WINDOW_BOOLEAN "SDL.window.create.wayland.create_egl_window" #define SDL_PROP_WINDOW_CREATE_WAYLAND_WL_SURFACE_POINTER "SDL.window.create.wayland.wl_surface" #define SDL_PROP_WINDOW_CREATE_WIN32_HWND_POINTER "SDL.window.create.win32.hwnd" #define SDL_PROP_WINDOW_CREATE_WIN32_PIXEL_FORMAT_HWND_POINTER "SDL.window.create.win32.pixel_format_hwnd" #define SDL_PROP_WINDOW_CREATE_X11_WINDOW_NUMBER "SDL.window.create.x11.window" +#define SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_CANVAS_ID_STRING "SDL.window.create.emscripten.canvas_id" +#define SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING "SDL.window.create.emscripten.keyboard_element" /** * Get the numeric ID of a window. @@ -1460,12 +1553,12 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_GetWindowParent(SDL_Window *window) * - `SDL_PROP_WINDOW_COCOA_WINDOW_POINTER`: the `(__unsafe_unretained)` * NSWindow associated with the window * - `SDL_PROP_WINDOW_COCOA_METAL_VIEW_TAG_NUMBER`: the NSInteger tag - * assocated with metal views on the window + * associated with metal views on the window * * On OpenVR: * - * - `SDL_PROP_WINDOW_OPENVR_OVERLAY_ID`: the OpenVR Overlay Handle ID for the - * associated overlay window. + * - `SDL_PROP_WINDOW_OPENVR_OVERLAY_ID_NUMBER`: the OpenVR Overlay Handle ID + * for the associated overlay window. * * On Vivante: * @@ -1517,6 +1610,13 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_GetWindowParent(SDL_Window *window) * - `SDL_PROP_WINDOW_X11_WINDOW_NUMBER`: the X11 Window associated with the * window * + * On Emscripten: + * + * - `SDL_PROP_WINDOW_EMSCRIPTEN_CANVAS_ID_STRING`: the id the canvas element + * will have + * - `SDL_PROP_WINDOW_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING`: the keyboard + * element that associates keyboard events to this window + * * \param window the window to query. * \returns a valid property ID on success or 0 on failure; call * SDL_GetError() for more information. @@ -1543,7 +1643,7 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetWindowProperties(SDL_Window #define SDL_PROP_WINDOW_KMSDRM_GBM_DEVICE_POINTER "SDL.window.kmsdrm.gbm_dev" #define SDL_PROP_WINDOW_COCOA_WINDOW_POINTER "SDL.window.cocoa.window" #define SDL_PROP_WINDOW_COCOA_METAL_VIEW_TAG_NUMBER "SDL.window.cocoa.metal_view_tag" -#define SDL_PROP_WINDOW_OPENVR_OVERLAY_ID "SDL.window.openvr.overlay_id" +#define SDL_PROP_WINDOW_OPENVR_OVERLAY_ID_NUMBER "SDL.window.openvr.overlay_id" #define SDL_PROP_WINDOW_VIVANTE_DISPLAY_POINTER "SDL.window.vivante.display" #define SDL_PROP_WINDOW_VIVANTE_WINDOW_POINTER "SDL.window.vivante.window" #define SDL_PROP_WINDOW_VIVANTE_SURFACE_POINTER "SDL.window.vivante.surface" @@ -1562,6 +1662,8 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetWindowProperties(SDL_Window #define SDL_PROP_WINDOW_X11_DISPLAY_POINTER "SDL.window.x11.display" #define SDL_PROP_WINDOW_X11_SCREEN_NUMBER "SDL.window.x11.screen" #define SDL_PROP_WINDOW_X11_WINDOW_NUMBER "SDL.window.x11.window" +#define SDL_PROP_WINDOW_EMSCRIPTEN_CANVAS_ID_STRING "SDL.window.emscripten.canvas_id" +#define SDL_PROP_WINDOW_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING "SDL.window.emscripten.keyboard_element" /** * Get the window flags. @@ -1579,6 +1681,7 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetWindowProperties(SDL_Window * \sa SDL_MinimizeWindow * \sa SDL_SetWindowFullscreen * \sa SDL_SetWindowMouseGrab + * \sa SDL_SetWindowFillDocument * \sa SDL_ShowWindow */ extern SDL_DECLSPEC SDL_WindowFlags SDLCALL SDL_GetWindowFlags(SDL_Window *window); @@ -1619,15 +1722,16 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetWindowTitle(SDL_Window *window); /** * Set the icon for a window. * - * If this function is passed a surface with alternate representations, the - * surface will be interpreted as the content to be used for 100% display - * scale, and the alternate representations will be used for high DPI - * situations. For example, if the original surface is 32x32, then on a 2x - * macOS display or 200% display scale on Windows, a 64x64 version of the - * image will be used, if available. If a matching version of the image isn't - * available, the closest larger size image will be downscaled to the - * appropriate size and be used instead, if available. Otherwise, the closest - * smaller image will be upscaled and be used instead. + * If this function is passed a surface with alternate representations added + * using SDL_AddSurfaceAlternateImage(), the surface will be interpreted as + * the content to be used for 100% display scale, and the alternate + * representations will be used for high DPI situations. For example, if the + * original surface is 32x32, then on a 2x macOS display or 200% display scale + * on Windows, a 64x64 version of the image will be used, if available. If a + * matching version of the image isn't available, the closest larger size + * image will be downscaled to the appropriate size and be used instead, if + * available. Otherwise, the closest smaller image will be upscaled and be + * used instead. * * \param window the window to change. * \param icon an SDL_Surface structure containing the icon for the window. @@ -1637,6 +1741,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetWindowTitle(SDL_Window *window); * \threadsafety This function should only be called on the main thread. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_AddSurfaceAlternateImage */ extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowIcon(SDL_Window *window, SDL_Surface *icon); @@ -1763,6 +1869,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowSize(SDL_Window *window, int w, in * \sa SDL_GetRenderOutputSize * \sa SDL_GetWindowSizeInPixels * \sa SDL_SetWindowSize + * \sa SDL_EVENT_WINDOW_RESIZED */ extern SDL_DECLSPEC bool SDLCALL SDL_GetWindowSize(SDL_Window *window, int *w, int *h); @@ -1774,7 +1881,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetWindowSize(SDL_Window *window, int *w, i * notches, TV overscan, etc. This function provides the area of the window * which is safe to have interactable content. You should continue rendering * into the rest of the window, but it should not contain visually important - * or interactible content. + * or interactable content. * * \param window the window to query. * \param rect a pointer filled in with the client area that is safe for @@ -1830,7 +1937,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetWindowSafeArea(SDL_Window *window, SDL_R extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowAspectRatio(SDL_Window *window, float min_aspect, float max_aspect); /** - * Get the size of a window's client area. + * Get the aspect ratio of a window's client area. * * \param window the window to query the width and height from. * \param min_aspect a pointer filled in with the minimum aspect ratio of the @@ -2044,6 +2151,37 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowResizable(SDL_Window *window, bool */ extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowAlwaysOnTop(SDL_Window *window, bool on_top); +/** + * Set the window to fill the current document space (Emscripten only). + * + * This will add or remove the window's `SDL_WINDOW_FILL_DOCUMENT` flag. + * + * Currently this flag only applies to the Emscripten target. + * + * When enabled, the canvas element fills the entire document. Resize events + * will be generated as the browser window is resized, as that will adjust the + * canvas size as well. The canvas will cover anything else on the page, + * including any controls provided by Emscripten in its generated HTML file + * (in fact, any elements on the page that aren't the canvas will be moved + * into a hidden `div` element). + * + * Often times this is desirable for a browser-based game, but it means + * several things that we expect of an SDL window on other platforms might not + * work as expected, such as minimum window sizes and aspect ratios. + * + * \param window the window of which to change the fill-document state. + * \param fill true to set the window to fill the document, false to disable. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_GetWindowFlags + */ +extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowFillDocument(SDL_Window *window, bool fill); + /** * Show a window. * @@ -2457,7 +2595,6 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowKeyboardGrab(SDL_Window *window, b * * \sa SDL_GetWindowMouseRect * \sa SDL_SetWindowMouseRect - * \sa SDL_SetWindowMouseGrab * \sa SDL_SetWindowKeyboardGrab */ extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowMouseGrab(SDL_Window *window, bool grabbed); @@ -2802,6 +2939,62 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowShape(SDL_Window *window, SDL_Surf */ extern SDL_DECLSPEC bool SDLCALL SDL_FlashWindow(SDL_Window *window, SDL_FlashOperation operation); +/** + * Sets the state of the progress bar for the given window’s taskbar icon. + * + * \param window the window whose progress state is to be modified. + * \param state the progress state. `SDL_PROGRESS_STATE_NONE` stops displaying + * the progress bar. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowProgressState(SDL_Window *window, SDL_ProgressState state); + +/** + * Get the state of the progress bar for the given window’s taskbar icon. + * + * \param window the window to get the current progress state from. + * \returns the progress state, or `SDL_PROGRESS_STATE_INVALID` on failure; + * call SDL_GetError() for more information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC SDL_ProgressState SDLCALL SDL_GetWindowProgressState(SDL_Window *window); + +/** + * Sets the value of the progress bar for the given window’s taskbar icon. + * + * \param window the window whose progress value is to be modified. + * \param value the progress value in the range of [0.0f - 1.0f]. If the value + * is outside the valid range, it gets clamped. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowProgressValue(SDL_Window *window, float value); + +/** + * Get the value of the progress bar for the given window’s taskbar icon. + * + * \param window the window to get the current progress value from. + * \returns the progress value in the range of [0.0f - 1.0f], or -1.0f on + * failure; call SDL_GetError() for more information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC float SDLCALL SDL_GetWindowProgressValue(SDL_Window *window); + /** * Destroy a window. * @@ -3037,8 +3230,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_GL_ResetAttributes(void); * SDL_GL_GetAttribute() to check the values after creating the OpenGL * context, since the values obtained can differ from the requested ones. * - * \param attr an SDL_GLAttr enum value specifying the OpenGL attribute to - * set. + * \param attr an enum value specifying the OpenGL attribute to set. * \param value the desired value for the attribute. * \returns true on success or false on failure; call SDL_GetError() for more * information. @@ -3047,6 +3239,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_GL_ResetAttributes(void); * * \since This function is available since SDL 3.2.0. * + * \sa SDL_GL_CreateContext * \sa SDL_GL_GetAttribute * \sa SDL_GL_ResetAttributes */ @@ -3073,6 +3266,12 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GL_GetAttribute(SDL_GLAttr attr, int *value /** * Create an OpenGL context for an OpenGL window, and make it current. * + * The OpenGL context will be created with the current states set through + * SDL_GL_SetAttribute(). + * + * The SDL_Window specified must have been created with the SDL_WINDOW_OPENGL + * flag, or context creation will fail. + * * Windows users new to OpenGL should note that, for historical reasons, GL * functions added after OpenGL version 1.1 are not available by default. * Those functions must be loaded at run-time, either with an OpenGL diff --git a/vendor/sdl3/include/SDL_vulkan.h b/vendor/sdl3/include/SDL_vulkan.h index 710afbe63..e91e14842 100644 --- a/vendor/sdl3/include/SDL_vulkan.h +++ b/vendor/sdl3/include/SDL_vulkan.h @@ -51,14 +51,14 @@ extern "C" { #endif -/* Avoid including vulkan.h, don't define VkInstance if it's already included */ -#ifdef VULKAN_H_ +/* Avoid including vulkan_core.h, don't define VkInstance if it's already included */ +#ifdef VULKAN_CORE_H_ #define NO_SDL_VULKAN_TYPEDEFS #endif #ifndef NO_SDL_VULKAN_TYPEDEFS #define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; -#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) || (defined(__riscv) && __riscv_xlen == 64) #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; #else #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; diff --git a/vendor/sdl3/mixer/LICENSE.gme.txt b/vendor/sdl3/mixer/LICENSE.gme.txt new file mode 100644 index 000000000..5ab7695ab --- /dev/null +++ b/vendor/sdl3/mixer/LICENSE.gme.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/vendor/sdl3/mixer/LICENSE.ogg-vorbis.txt b/vendor/sdl3/mixer/LICENSE.ogg-vorbis.txt new file mode 100644 index 000000000..fb456a87b --- /dev/null +++ b/vendor/sdl3/mixer/LICENSE.ogg-vorbis.txt @@ -0,0 +1,28 @@ +Copyright (c) 2002-2020 Xiph.org Foundation + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of the Xiph.org Foundation nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/sdl3/mixer/LICENSE.opus.txt b/vendor/sdl3/mixer/LICENSE.opus.txt new file mode 100644 index 000000000..9c739c34a --- /dev/null +++ b/vendor/sdl3/mixer/LICENSE.opus.txt @@ -0,0 +1,44 @@ +Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic, + Jean-Marc Valin, Timothy B. Terriberry, + CSIRO, Gregory Maxwell, Mark Borgerding, + Erik de Castro Lopo + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Opus is subject to the royalty-free patent licenses which are +specified at: + +Xiph.Org Foundation: +https://datatracker.ietf.org/ipr/1524/ + +Microsoft Corporation: +https://datatracker.ietf.org/ipr/1914/ + +Broadcom Corporation: +https://datatracker.ietf.org/ipr/1526/ diff --git a/vendor/sdl3/mixer/LICENSE.opusfile.txt b/vendor/sdl3/mixer/LICENSE.opusfile.txt new file mode 100644 index 000000000..7b53d665d --- /dev/null +++ b/vendor/sdl3/mixer/LICENSE.opusfile.txt @@ -0,0 +1,28 @@ +Copyright (c) 1994-2013 Xiph.Org Foundation and contributors + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of the Xiph.Org Foundation nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/sdl3/mixer/LICENSE.txt b/vendor/sdl3/mixer/LICENSE.txt new file mode 100644 index 000000000..acaf5b21b --- /dev/null +++ b/vendor/sdl3/mixer/LICENSE.txt @@ -0,0 +1,17 @@ +Copyright (C) 1997-2026 Sam Lantinga + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. diff --git a/vendor/sdl3/mixer/LICENSE.wavpack.txt b/vendor/sdl3/mixer/LICENSE.wavpack.txt new file mode 100644 index 000000000..a0136963e --- /dev/null +++ b/vendor/sdl3/mixer/LICENSE.wavpack.txt @@ -0,0 +1,25 @@ + Copyright (c) 1998 - 2025 David Bryant + All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/sdl3/mixer/LICENSE.xmp.txt b/vendor/sdl3/mixer/LICENSE.xmp.txt new file mode 100644 index 000000000..ed3491ee5 --- /dev/null +++ b/vendor/sdl3/mixer/LICENSE.xmp.txt @@ -0,0 +1,20 @@ +Extended Module Player +Copyright (C) 1996-2024 Claudio Matsuoka and Hipolito Carraro Jr + +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/vendor/sdl3/mixer/SDL3_mixer.dll b/vendor/sdl3/mixer/SDL3_mixer.dll new file mode 100644 index 000000000..fba705818 --- /dev/null +++ b/vendor/sdl3/mixer/SDL3_mixer.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8708c991962cee6fa30e69969d0261eb1c2bba1f5609f21cd096681664406a25 +size 434176 diff --git a/vendor/sdl3/mixer/SDL3_mixer.lib b/vendor/sdl3/mixer/SDL3_mixer.lib new file mode 100644 index 000000000..eef40ba35 --- /dev/null +++ b/vendor/sdl3/mixer/SDL3_mixer.lib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fc07725d580297402884da96999a63ed844b3359e98b9ed257c20fef9f492a99 +size 22380 diff --git a/vendor/sdl3/mixer/include/SDL_mixer.h b/vendor/sdl3/mixer/include/SDL_mixer.h new file mode 100644 index 000000000..8eca47369 --- /dev/null +++ b/vendor/sdl3/mixer/include/SDL_mixer.h @@ -0,0 +1,3347 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2026 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* WIKI CATEGORY: SDLMixer */ + +/** + * # CategorySDLMixer + * + * SDL_mixer is a library to make complicated audio processing tasks easier. + * + * It offers audio file decoding, mixing multiple sounds together, basic 3D + * positional audio, and various audio effects. + * + * It can mix sound to multiple audio devices in real time, or generate mixed + * audio data to a memory buffer for any other use. It can do both at the same + * time! + * + * To use the library, first call MIX_Init(). Then create a mixer with + * MIX_CreateMixerDevice() (or MIX_CreateMixer() to render to memory). + * + * Once you have a mixer, you can load sound data with MIX_LoadAudio(), + * MIX_LoadAudio_IO(), or MIX_LoadAudioWithProperties(). Data gets loaded once + * and can be played over and over. + * + * When loading audio, SDL_mixer can parse out several metadata tag formats, + * such as ID3 and APE tags, and exposes this information through the + * MIX_GetAudioProperties() function. + * + * To play audio, you create a track with MIX_CreateTrack(). You need one + * track for each sound that will be played simultaneously; think of tracks as + * individual sliders on a mixer board. You might have loaded hundreds of + * audio files, but you probably only have a handful of tracks that you assign + * those loaded files to when they are ready to play, and reuse those tracks + * with different audio later. Tracks take their input from a MIX_Audio + * (static data to be played multiple times) or an SDL_AudioStream (streaming + * PCM audio the app supplies, possibly as needed). A third option is to + * supply an SDL_IOStream, to load and decode on the fly, which might be more + * efficient for background music that is only used once, etc. + * + * Assign input to a MIX_Track with MIX_SetTrackAudio(), + * MIX_SetTrackAudioStream(), or MIX_SetTrackIOStream(). + * + * Once a track has an input, start it playing with MIX_PlayTrack(). There are + * many options to this function to dictate mixing features: looping, fades, + * etc. + * + * Tracks can be tagged with arbitrary strings, like "music" or "ingame" or + * "ui". These tags can be used to start, stop, and pause a selection of + * tracks at the same moment. + * + * All significant portions of the mixing pipeline have callbacks, so that an + * app can hook in to the appropriate locations to examine or modify audio + * data as it passes through the mixer: a "raw" callback for raw PCM data + * decoded from an audio file without any modifications, a "cooked" callback + * for that same data after all transformations (fade, positioning, etc) have + * been processed, a "stopped" callback for when the track finishes mixing, a + * "postmix" callback for the final mixed audio about to be sent to the audio + * hardware to play. Additionally, you can use MIX_Group objects to mix a + * subset of playing tracks and access the data before it is mixed in with + * other tracks. All of this is optional, but allows for powerful access and + * control of the mixing process. + * + * SDL_mixer can also be used for decoding audio files without actually + * rendering a mix. This is done with MIX_AudioDecoder. Even though SDL_mixer + * handles decoding transparently when used as the audio engine for an app, + * and probably won't need this interface in that normal scenario, this can be + * useful when using a different audio library to access many file formats. + * + * This library offers several features on top of mixing sounds together: a + * track can have its own gain, to adjust its volume, in addition to a master + * gain applied as well. One can set the "frequency ratio" of a track or the + * final mixed output, to speed it up or slow it down, which also adjusts its + * pitch. A channel map can also be applied per-track, to change what speaker + * a given channel of audio is output to. + * + * Almost all timing in SDL_mixer is in _sample frames_. Stereo PCM audio data + * in Sint16 format takes 4 bytes per sample frame (2 bytes per sample times 2 + * channels), for example. This allows everything in SDL_mixer to run at + * sample-perfect accuracy, and it lets it run without concern for wall clock + * time--you can produce audio faster than real-time, if desired. The problem, + * though, is different pieces of audio at different _sample rates_ will + * produce a different number of sample frames for the same length of time. To + * deal with this, conversion routines are offered: MIX_TrackMSToFrames(), + * MIX_TrackFramesToMS(), etc. Functions that operate on multiple tracks at + * once will deal with time in milliseconds, so it can do these conversions + * internally; be sure to read the documentation for these small quirks! + * + * SDL_mixer offers basic positional audio: a simple 3D positioning API + * through MIX_SetTrack3DPosition() and MIX_SetTrackStereo(). The former will + * do simple distance attenuation and spatialization--on a stereo setup, you + * will hear sounds move from left to right--and on a surround-sound + * configuration, individual tracks can move around the user. The latter, + * MIX_SetTrackStereo(), will force a sound to the Front Left and Front Right + * speakers and let the app pan it left and right as desired. Either effect + * can be useful for different situations. SDL_mixer is not meant to be a full + * 3D audio engine, but rather Good Enough for many purposes; if something + * more powerful in terms of 3D audio is needed, consider a proper 3D library + * like OpenAL. + */ + +#ifndef SDL_MIXER_H_ +#define SDL_MIXER_H_ + +#include +#include + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * An opaque object that represents a mixer. + * + * The MIX_Mixer is the toplevel object for this library. To use SDL_mixer, + * you must have at least one, but are allowed to have several. Each mixer is + * responsible for generating a single output stream of mixed audio, usually + * to an audio device for realtime playback. + * + * Mixers are either created to feed an audio device (through + * MIX_CreateMixerDevice()), or to generate audio to a buffer in memory, where + * it can be used for anything (through MIX_CreateMixer()). + * + * \since This datatype is available since SDL_mixer 3.0.0. + */ +typedef struct MIX_Mixer MIX_Mixer; + +/** + * An opaque object that represents audio data. + * + * Generally you load audio data (in whatever file format) into SDL_mixer with + * MIX_LoadAudio() or one of its several variants, producing a MIX_Audio + * object. + * + * A MIX_Audio represents static audio data; it could be background music, or + * maybe a laser gun sound effect. It is loaded into RAM and can be played + * multiple times, possibly on different tracks at the same time. + * + * Unlike most other objects, MIX_Audio objects can be shared between mixers. + * + * \since This datatype is available since SDL_mixer 3.0.0. + */ +typedef struct MIX_Audio MIX_Audio; + +/** + * An opaque object that represents a source of sound output to be mixed. + * + * A MIX_Mixer has an arbitrary number of tracks, and each track manages its + * own unique audio to be mixed together. + * + * Tracks also have other properties: gain, loop points, fading, 3D position, + * and other attributes that alter the produced sound; many can be altered + * during playback. + * + * \since This datatype is available since SDL_mixer 3.0.0. + */ +typedef struct MIX_Track MIX_Track; + +/** + * An opaque object that represents a grouping of tracks. + * + * SDL_mixer offers callbacks at various stages of the mixing pipeline to + * allow apps to view and manipulate data as it is transformed. Sometimes it + * is useful to hook in at a point where several tracks--but not all tracks-- + * have been mixed. For example, when a game is in some options menu, perhaps + * adjusting game audio but not UI sounds could be useful. + * + * SDL_mixer allows you to assign several tracks to a group, and receive a + * callback when that group has finished mixing, with a buffer of just that + * group's mixed audio, before it mixes into the final output. + * + * \since This datatype is available since SDL_mixer 3.0.0. + */ +typedef struct MIX_Group MIX_Group; + +/** + * The current major version of SDL_mixer headers. + * + * If this were SDL_mixer version 3.2.1, this value would be 3. + * + * \since This macro is available since SDL_mixer 3.0.0. + */ +#define SDL_MIXER_MAJOR_VERSION 3 + +/** + * The current minor version of the SDL_mixer headers. + * + * If this were SDL_mixer version 3.2.1, this value would be 2. + * + * \since This macro is available since SDL_mixer 3.0.0. + */ +#define SDL_MIXER_MINOR_VERSION 2 + +/** + * The current micro (or patchlevel) version of the SDL_mixer headers. + * + * If this were SDL_mixer version 3.2.1, this value would be 1. + * + * \since This macro is available since SDL_mixer 3.0.0. + */ +#define SDL_MIXER_MICRO_VERSION 0 + +/** + * This is the current version number macro of the SDL_mixer headers. + * + * \since This macro is available since SDL_mixer 3.0.0. + * + * \sa MIX_Version + */ +#define SDL_MIXER_VERSION SDL_VERSIONNUM(SDL_MIXER_MAJOR_VERSION, SDL_MIXER_MINOR_VERSION, SDL_MIXER_MICRO_VERSION) + +/** + * This macro will evaluate to true if compiled with SDL_mixer at least X.Y.Z. + * + * \since This macro is available since SDL_mixer 3.0.0. + */ +#define SDL_MIXER_VERSION_ATLEAST(X, Y, Z) \ + ((SDL_MIXER_MAJOR_VERSION >= X) && \ + (SDL_MIXER_MAJOR_VERSION > X || SDL_MIXER_MINOR_VERSION >= Y) && \ + (SDL_MIXER_MAJOR_VERSION > X || SDL_MIXER_MINOR_VERSION > Y || SDL_MIXER_MICRO_VERSION >= Z)) + +/** + * Get the version of SDL_mixer that is linked against your program. + * + * If you are linking to SDL_mixer dynamically, then it is possible that the + * current version will be different than the version you compiled against. + * This function returns the current version, while SDL_MIXER_VERSION is the + * version you compiled with. + * + * This function may be called safely at any time, even before MIX_Init(). + * + * \returns the version of the linked library. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa SDL_MIXER_VERSION + */ +extern SDL_DECLSPEC int SDLCALL MIX_Version(void); + +/** + * Initialize the SDL_mixer library. + * + * This must be successfully called once before (almost) any other SDL_mixer + * function can be used. + * + * It is safe to call this multiple times; the library will only initialize + * once, and won't deinitialize until MIX_Quit() has been called a matching + * number of times. Extra attempts to init report success. + * + * \returns true on success, false on error; call SDL_GetError() for details. + * + * \threadsafety This function is not thread safe. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_Quit + */ +extern SDL_DECLSPEC bool SDLCALL MIX_Init(void); + +/** + * Deinitialize the SDL_mixer library. + * + * This must be called when done with the library, probably at the end of your + * program. + * + * It is safe to call this multiple times; the library will only deinitialize + * once, when this function is called the same number of times as MIX_Init was + * successfully called. + * + * Once you have successfully deinitialized the library, it is safe to call + * MIX_Init to reinitialize it for further use. + * + * On successful deinitialization, SDL_mixer will destroy almost all created + * objects, including objects of type: + * + * - MIX_Mixer + * - MIX_Track + * - MIX_Audio + * - MIX_Group + * - MIX_AudioDecoder + * + * ...which is to say: it's possible a single call to this function will clean + * up anything it allocated, stop all audio output, close audio devices, etc. + * Don't attempt to destroy objects after this call. The app is still + * encouraged to manage their resources carefully and clean up first, treating + * this function as a safety net against memory leaks. + * + * \threadsafety This function is not thread safe. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_Init + */ +extern SDL_DECLSPEC void SDLCALL MIX_Quit(void); + +/** + * Report the number of audio decoders available for use. + * + * An audio decoder is what turns specific audio file formats into usable PCM + * data. For example, there might be an MP3 decoder, or a WAV decoder, etc. + * SDL_mixer probably has several decoders built in. + * + * The return value can be used to call MIX_GetAudioDecoder() in a loop. + * + * The number of decoders available is decided during MIX_Init() and does not + * change until the library is deinitialized. + * + * \returns the number of decoders available. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_GetAudioDecoder + */ +extern SDL_DECLSPEC int SDLCALL MIX_GetNumAudioDecoders(void); + +/** + * Report the name of a specific audio decoders. + * + * An audio decoder is what turns specific audio file formats into usable PCM + * data. For example, there might be an MP3 decoder, or a WAV decoder, etc. + * SDL_mixer probably has several decoders built in. + * + * The names are capital English letters and numbers, low-ASCII. They don't + * necessarily map to a specific file format; Some decoders, like "XMP" + * operate on multiple file types, and more than one decoder might handle the + * same file type, like "DRMP3" vs "MPG123". Note that in that last example, + * neither decoder is called "MP3". + * + * The index of a specific decoder is decided during MIX_Init() and does not + * change until the library is deinitialized. Valid indices are between zero + * and the return value of MIX_GetNumAudioDecoders(). + * + * The returned pointer is const memory owned by SDL_mixer; do not free it. + * + * \param index the index of the decoder to query. + * \returns a UTF-8 (really, ASCII) string of the decoder's name, or NULL if + * `index` is invalid. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_GetNumAudioDecoders + */ +extern SDL_DECLSPEC const char * SDLCALL MIX_GetAudioDecoder(int index); + +/** + * Create a mixer that plays sound directly to an audio device. + * + * This is usually the function you want, vs MIX_CreateMixer(). + * + * You can choose a specific device ID to open, following SDL's usual rules, + * but often the correct choice is to specify + * SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK and let SDL figure out what device to use + * (and seamlessly transition you to new hardware if the default changes). + * + * Only playback devices make sense here. Attempting to open a recording + * device will fail. + * + * This will call SDL_Init(SDL_INIT_AUDIO) internally; it's safe to call + * SDL_Init() before this call, too, if you intend to enumerate audio devices + * to choose one to open here. + * + * An audio format can be requested, and the system will try to set the + * hardware to those specifications, or as close as possible, but this is just + * a hint. SDL_mixer will handle all data conversion behind the scenes in any + * case, and specifying a NULL spec is a reasonable choice. The best reason to + * specify a format is because you know all your data is in that format and it + * might save some unnecessary CPU time on conversion. + * + * The actual device format chosen is available through MIX_GetMixerFormat(). + * + * Once a mixer is created, next steps are usually to load audio (through + * MIX_LoadAudio() and friends), create a track (MIX_CreateTrack()), and play + * that audio through that track. + * + * When done with the mixer, it can be destroyed with MIX_DestroyMixer(). + * + * \param devid the device to open for playback, or + * SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK for the default. + * \param spec the audio format to request from the device. May be NULL. + * \returns a mixer that can be used to play audio, or NULL on failure; call + * SDL_GetError() for more information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_CreateMixer + * \sa MIX_DestroyMixer + */ +extern SDL_DECLSPEC MIX_Mixer * SDLCALL MIX_CreateMixerDevice(SDL_AudioDeviceID devid, const SDL_AudioSpec *spec); + +/** + * Create a mixer that generates audio to a memory buffer. + * + * Usually you want MIX_CreateMixerDevice() instead of this function. The + * mixer created here can be used with MIX_Generate() to produce more data on + * demand, as fast as desired. + * + * An audio format must be specified. This is the format it will output in. + * This cannot be NULL. + * + * Once a mixer is created, next steps are usually to load audio (through + * MIX_LoadAudio() and friends), create a track (MIX_CreateTrack()), and play + * that audio through that track. + * + * When done with the mixer, it can be destroyed with MIX_DestroyMixer(). + * + * \param spec the audio format that mixer will generate. + * \returns a mixer that can be used to generate audio, or NULL on failure; + * call SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_CreateMixerDevice + * \sa MIX_DestroyMixer + */ +extern SDL_DECLSPEC MIX_Mixer * SDLCALL MIX_CreateMixer(const SDL_AudioSpec *spec); + +/** + * Free a mixer. + * + * If this mixer was created with MIX_CreateMixerDevice(), this function will + * also close the audio device and call SDL_QuitSubSystem(SDL_INIT_AUDIO). + * + * Any MIX_Group or MIX_Track created for this mixer will also be destroyed. + * Do not access them again or attempt to destroy them after the device is + * destroyed. MIX_Audio objects will not be destroyed, since they can be + * shared between mixers (but those will all be destroyed during MIX_Quit()). + * + * \param mixer the mixer to destroy. + * + * \threadsafety If this is used with a MIX_Mixer from MIX_CreateMixerDevice, + * then this function should only be called on the main thread. + * If this is used with a MIX_Mixer from MIX_CreateMixer, then + * it is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_CreateMixerDevice + * \sa MIX_CreateMixer + */ +extern SDL_DECLSPEC void SDLCALL MIX_DestroyMixer(MIX_Mixer *mixer); + + +/** + * Get the properties associated with a mixer. + * + * The following read-only properties are provided by SDL_mixer: + * + * - `MIX_PROP_MIXER_DEVICE_NUMBER`: the SDL_AudioDeviceID that this mixer has + * opened for playback. This will be zero (no device) if the mixer was + * created with Mix_CreateMixer() instead of Mix_CreateMixerDevice(). + * + * \param mixer the mixer to query. + * \returns a valid property ID on success or 0 on failure; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC SDL_PropertiesID SDLCALL MIX_GetMixerProperties(MIX_Mixer *mixer); + +#define MIX_PROP_MIXER_DEVICE_NUMBER "SDL_mixer.mixer.device" + + +/** + * Get the audio format a mixer is generating. + * + * Generally you don't need this information, as SDL_mixer will convert data + * as necessary between inputs you provide and its output format, but it might + * be useful if trying to match your inputs to reduce conversion and + * resampling costs. + * + * For mixers created with MIX_CreateMixerDevice(), this is the format of the + * audio device (and may change later if the device itself changes; SDL_mixer + * will seamlessly handle this change internally, though). + * + * For mixers created with MIX_CreateMixer(), this is the format that + * MIX_Generate() will produce, as requested at create time, and does not + * change. + * + * Note that internally, SDL_mixer will work in SDL_AUDIO_F32 format before + * outputting the format specified here, so it would be more efficient to + * match input data to that, not the final output format. + * + * \param mixer the mixer to query. + * \param spec where to store the mixer audio format. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL MIX_GetMixerFormat(MIX_Mixer *mixer, SDL_AudioSpec *spec); + +/** + * Lock a mixer by obtaining its internal mutex. + * + * While locked, the mixer will not be able to mix more audio or change its + * internal state in another thread. Those other threads will block until the + * mixer is unlocked again. + * + * Under the hood, this function calls SDL_LockMutex(), so all the same rules + * apply: the lock can be recursive, it must be unlocked the same number of + * times from the same thread that locked it, etc. + * + * Just about every SDL_mixer API _also_ locks the mixer while doing its work, + * as does the SDL audio device thread while actual mixing is in progress, so + * basic use of this library never requires the app to explicitly lock the + * device to be thread safe. There are two scenarios where this can be useful, + * however: + * + * - The app has a provided a callback that the mixing thread might call, and + * there is some app state that needs to be protected against race + * conditions as changes are made and mixing progresses simultaneously. Any + * lock can be used for this, but this is a conveniently-available lock. + * - The app wants to make multiple, atomic changes to the mix. For example, + * to start several tracks at the exact same moment, one would lock the + * mixer, call MIX_PlayTrack multiple times, and then unlock again; all the + * tracks will start mixing on the same sample frame. + * + * Each call to this function must be paired with a call to MIX_UnlockMixer + * from the same thread. It is safe to lock a mixer multiple times; it remains + * locked until the final matching unlock call. + * + * Do not lock the mixer for significant amounts of time, or it can cause + * audio dropouts. Just do simply things quickly and unlock again. + * + * Locking a NULL mixer is a safe no-op. + * + * \param mixer the mixer to lock. May be NULL. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_UnlockMixer + */ +extern SDL_DECLSPEC void SDLCALL MIX_LockMixer(MIX_Mixer *mixer); + +/** + * Unlock a mixer previously locked by a call to MIX_LockMixer(). + * + * While locked, the mixer will not be able to mix more audio or change its + * internal state another thread. Those other threads will block until the + * mixer is unlocked again. + * + * Under the hood, this function calls SDL_LockMutex(), so all the same rules + * apply: the lock can be recursive, it must be unlocked the same number of + * times from the same thread that locked it, etc. + * + * Unlocking a NULL mixer is a safe no-op. + * + * \param mixer the mixer to unlock. May be NULL. + * + * \threadsafety This call must be paired with a previous MIX_LockMixer call + * on the same thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_LockMixer + */ +extern SDL_DECLSPEC void SDLCALL MIX_UnlockMixer(MIX_Mixer *mixer); + +/** + * Load audio for playback from an SDL_IOStream. + * + * In normal usage, apps should load audio once, maybe at startup, then play + * it multiple times. + * + * When loading audio, it will be cached fully in RAM in its original data + * format. Each time it plays, the data will be decoded. For example, an MP3 + * will be stored in memory in MP3 format and be decompressed on the fly + * during playback. This is a tradeoff between i/o overhead and memory usage. + * + * If `predecode` is true, the data will be decompressed during load and + * stored as raw PCM data. This might dramatically increase loading time and + * memory usage, but there will be no need to decompress data during playback. + * + * (One could also use MIX_SetTrackIOStream() to bypass loading the data into + * RAM upfront at all, but this offers still different tradeoffs. The correct + * approach depends on the app's needs and employing different approaches in + * different situations can make sense.) + * + * MIX_Audio objects can be shared between mixers. This function takes a + * MIX_Mixer, to imply this is the most likely place it will be used and + * loading should try to match its audio format, but the resulting audio can + * be used elsewhere. If `mixer` is NULL, SDL_mixer will set reasonable + * defaults. + * + * Once a MIX_Audio is created, it can be assigned to a MIX_Track with + * MIX_SetTrackAudio(), or played without any management with MIX_PlayAudio(). + * + * When done with a MIX_Audio, it can be freed with MIX_DestroyAudio(). + * + * This function loads data from an SDL_IOStream. There is also a version that + * loads from a path on the filesystem (MIX_LoadAudio()), and one that accepts + * properties for ultimate control (MIX_LoadAudioWithProperties()). + * + * The SDL_IOStream provided must be able to seek, or loading will fail. If + * the stream can't seek (data is coming from an HTTP connection, etc), + * consider caching the data to memory or disk first and creating a new stream + * to read from there. + * + * \param mixer a mixer this audio is intended to be used with. May be NULL. + * \param io the SDL_IOStream to load data from. + * \param predecode if true, data will be fully uncompressed before returning. + * \param closeio true if SDL_mixer should close `io` before returning + * (success or failure). + * \returns an audio object that can be used to make sound on a mixer, or NULL + * on failure; call SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_DestroyAudio + * \sa MIX_SetTrackAudio + * \sa MIX_LoadAudio + * \sa MIX_LoadAudioWithProperties + */ +extern SDL_DECLSPEC MIX_Audio * SDLCALL MIX_LoadAudio_IO(MIX_Mixer *mixer, SDL_IOStream *io, bool predecode, bool closeio); + +/** + * Load audio for playback from a file. + * + * This is equivalent to calling: + * + * ```c + * MIX_LoadAudio_IO(mixer, SDL_IOFromFile(path, "rb"), predecode, true); + * ``` + * + * This function loads data from a path on the filesystem. There is also a + * version that loads from an SDL_IOStream (MIX_LoadAudio_IO()), and one that + * accepts properties for ultimate control (MIX_LoadAudioWithProperties()). + * + * \param mixer a mixer this audio is intended to be used with. May be NULL. + * \param path the path on the filesystem to load data from. + * \param predecode if true, data will be fully uncompressed before returning. + * \returns an audio object that can be used to make sound on a mixer, or NULL + * on failure; call SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_DestroyAudio + * \sa MIX_SetTrackAudio + * \sa MIX_LoadAudio_IO + * \sa MIX_LoadAudioWithProperties + */ +extern SDL_DECLSPEC MIX_Audio * SDLCALL MIX_LoadAudio(MIX_Mixer *mixer, const char *path, bool predecode); + +/** + * Load audio for playback from a memory buffer without making a copy. + * + * When loading audio through most other LoadAudio functions, the data will be + * cached fully in RAM in its original data format, for decoding on-demand. + * This function does most of the same work as those functions, but instead + * uses a buffer of memory provided by the app that it does not make a copy + * of. + * + * This buffer must live for the entire time the returned MIX_Audio lives, as + * the mixer will access the buffer whenever it needs to mix more data. + * + * This function is meant to maximize efficiency: if the data is already in + * memory and can remain there, don't copy it. This data can be in any + * supported audio file format (WAV, MP3, etc); it will be decoded on the fly + * while mixing. Unlike MIX_LoadAudio(), there is no `predecode` option + * offered here, as this is meant to optimize for data that's already in + * memory and intends to exist there for significant time; since predecoding + * would only need the file format data once, upfront, one could simply wrap + * it in SDL_CreateIOFromConstMem() and pass that to MIX_LoadAudio_IO(). + * + * MIX_Audio objects can be shared between multiple mixers. The `mixer` + * parameter just suggests the most likely mixer to use this audio, in case + * some optimization might be applied, but this is not required, and a NULL + * mixer may be specified. + * + * If `free_when_done` is true, SDL_mixer will call `SDL_free(data)` when the + * returned MIX_Audio is eventually destroyed. This can be useful when the + * data is not static, but rather loaded elsewhere for this specific MIX_Audio + * and simply wants to avoid the extra copy. + * + * As audio format information is obtained from the file format metadata, this + * isn't useful for raw PCM data; in that case, use MIX_LoadRawAudioNoCopy() + * instead, which offers an SDL_AudioSpec. + * + * Once a MIX_Audio is created, it can be assigned to a MIX_Track with + * MIX_SetTrackAudio(), or played without any management with MIX_PlayAudio(). + * + * When done with a MIX_Audio, it can be freed with MIX_DestroyAudio(). + * + * \param mixer a mixer this audio is intended to be used with. May be NULL. + * \param data the buffer where the audio data lives. + * \param datalen the size, in bytes, of the buffer. + * \param free_when_done if true, `data` will be given to SDL_free() when the + * MIX_Audio is destroyed. + * \returns an audio object that can be used to make sound on a mixer, or NULL + * on failure; call SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_DestroyAudio + * \sa MIX_SetTrackAudio + * \sa MIX_LoadRawAudioNoCopy + * \sa MIX_LoadAudio_IO + */ +extern SDL_DECLSPEC MIX_Audio * SDLCALL MIX_LoadAudioNoCopy(MIX_Mixer *mixer, const void *data, size_t datalen, bool free_when_done); + +/** + * Load audio for playback through a collection of properties. + * + * Please see MIX_LoadAudio_IO() for a description of what the various + * LoadAudio functions do. This function uses properties to dictate how it + * operates, and exposes functionality the other functions don't provide. + * + * SDL_PropertiesID are discussed in + * [SDL's documentation](https://wiki.libsdl.org/SDL3/CategoryProperties) + * . + * + * These are the supported properties: + * + * - `MIX_PROP_AUDIO_LOAD_IOSTREAM_POINTER`: a pointer to an SDL_IOStream to + * be used to load audio data. Required. This stream must be able to seek! + * - `MIX_PROP_AUDIO_LOAD_CLOSEIO_BOOLEAN`: true if SDL_mixer should close the + * SDL_IOStream before returning (success or failure). + * - `MIX_PROP_AUDIO_LOAD_PREDECODE_BOOLEAN`: true if SDL_mixer should fully + * decode and decompress the data before returning. Otherwise it will be + * stored in its original state and decompressed on demand. + * - `MIX_PROP_AUDIO_LOAD_PREFERRED_MIXER_POINTER`: a pointer to a MIX_Mixer, + * in case steps can be made to match its format when decoding. Optional. + * - `MIX_PROP_AUDIO_LOAD_SKIP_METADATA_TAGS_BOOLEAN`: true to skip parsing + * metadata tags, like ID3 and APE tags. This can be used to speed up + * loading _if the data definitely doesn't have these tags_. Some decoders + * will fail if these tags are present when this property is true. + * - `MIX_PROP_AUDIO_DECODER_STRING`: the name of the decoder to use for this + * data. Optional. If not specified, SDL_mixer will examine the data and + * choose the best decoder. These names are the same returned from + * MIX_GetAudioDecoder(). + * + * Specific decoders might accept additional custom properties, such as where + * to find soundfonts for MIDI playback, etc. + * + * \param props a set of properties on how to load audio. + * \returns an audio object that can be used to make sound on a mixer, or NULL + * on failure; call SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_DestroyAudio + * \sa MIX_SetTrackAudio + * \sa MIX_LoadAudio + * \sa MIX_LoadAudio_IO + */ +extern SDL_DECLSPEC MIX_Audio * SDLCALL MIX_LoadAudioWithProperties(SDL_PropertiesID props); + +#define MIX_PROP_AUDIO_LOAD_IOSTREAM_POINTER "SDL_mixer.audio.load.iostream" +#define MIX_PROP_AUDIO_LOAD_CLOSEIO_BOOLEAN "SDL_mixer.audio.load.closeio" +#define MIX_PROP_AUDIO_LOAD_PREDECODE_BOOLEAN "SDL_mixer.audio.load.predecode" +#define MIX_PROP_AUDIO_LOAD_PREFERRED_MIXER_POINTER "SDL_mixer.audio.load.preferred_mixer" +#define MIX_PROP_AUDIO_LOAD_SKIP_METADATA_TAGS_BOOLEAN "SDL_mixer.audio.load.skip_metadata_tags" +#define MIX_PROP_AUDIO_DECODER_STRING "SDL_mixer.audio.decoder" + +/** + * Load raw PCM data from an SDL_IOStream. + * + * There are other options for _streaming_ raw PCM: an SDL_AudioStream can be + * connected to a track, as can an SDL_IOStream, and will read from those + * sources on-demand when it is time to mix the audio. This function is useful + * for loading static audio data that is meant to be played multiple times. + * + * This function will load the raw data in its entirety and cache it in RAM. + * + * MIX_Audio objects can be shared between multiple mixers. The `mixer` + * parameter just suggests the most likely mixer to use this audio, in case + * some optimization might be applied, but this is not required, and a NULL + * mixer may be specified. + * + * \param mixer a mixer this audio is intended to be used with. May be NULL. + * \param io the SDL_IOStream to load data from. + * \param spec what format the raw data is in. + * \param closeio true if SDL_mixer should close `io` before returning + * (success or failure). + * \returns an audio object that can be used to make sound on a mixer, or NULL + * on failure; call SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_DestroyAudio + * \sa MIX_SetTrackAudio + * \sa MIX_LoadRawAudio + * \sa MIX_LoadRawAudioNoCopy + * \sa MIX_LoadAudio_IO + */ +extern SDL_DECLSPEC MIX_Audio * SDLCALL MIX_LoadRawAudio_IO(MIX_Mixer *mixer, SDL_IOStream *io, const SDL_AudioSpec *spec, bool closeio); + +/** + * Load raw PCM data from a memory buffer. + * + * There are other options for _streaming_ raw PCM: an SDL_AudioStream can be + * connected to a track, as can an SDL_IOStream, and will read from those + * sources on-demand when it is time to mix the audio. This function is useful + * for loading static audio data that is meant to be played multiple times. + * + * This function will load the raw data in its entirety and cache it in RAM, + * allocating a copy. If the original data will outlive the created MIX_Audio, + * you can use MIX_LoadRawAudioNoCopy() to avoid extra allocations and copies. + * + * MIX_Audio objects can be shared between multiple mixers. The `mixer` + * parameter just suggests the most likely mixer to use this audio, in case + * some optimization might be applied, but this is not required, and a NULL + * mixer may be specified. + * + * \param mixer a mixer this audio is intended to be used with. May be NULL. + * \param data the raw PCM data to load. + * \param datalen the size, in bytes, of the raw PCM data. + * \param spec what format the raw data is in. + * \returns an audio object that can be used to make sound on a mixer, or NULL + * on failure; call SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_DestroyAudio + * \sa MIX_SetTrackAudio + * \sa MIX_LoadRawAudio_IO + * \sa MIX_LoadRawAudioNoCopy + * \sa MIX_LoadAudio_IO + */ +extern SDL_DECLSPEC MIX_Audio * SDLCALL MIX_LoadRawAudio(MIX_Mixer *mixer, const void *data, size_t datalen, const SDL_AudioSpec *spec); + +/** + * Load raw PCM data from a memory buffer without making a copy. + * + * This buffer must live for the entire time the returned MIX_Audio lives, as + * the mixer will access the buffer whenever it needs to mix more data. + * + * This function is meant to maximize efficiency: if the data is already in + * memory and can remain there, don't copy it. But it can also lead to some + * interesting tricks, like changing the buffer's contents to alter multiple + * playing tracks at once. (But, of course, be careful when being too clever.) + * + * MIX_Audio objects can be shared between multiple mixers. The `mixer` + * parameter just suggests the most likely mixer to use this audio, in case + * some optimization might be applied, but this is not required, and a NULL + * mixer may be specified. + * + * If `free_when_done` is true, SDL_mixer will call `SDL_free(data)` when the + * returned MIX_Audio is eventually destroyed. This can be useful when the + * data is not static, but rather composed dynamically for this specific + * MIX_Audio and simply wants to avoid the extra copy. + * + * \param mixer a mixer this audio is intended to be used with. May be NULL. + * \param data the buffer where the raw PCM data lives. + * \param datalen the size, in bytes, of the buffer. + * \param spec what format the raw data is in. + * \param free_when_done if true, `data` will be given to SDL_free() when the + * MIX_Audio is destroyed. + * \returns an audio object that can be used to make sound on a mixer, or NULL + * on failure; call SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_DestroyAudio + * \sa MIX_SetTrackAudio + * \sa MIX_LoadRawAudio + * \sa MIX_LoadRawAudio_IO + * \sa MIX_LoadAudio_IO + */ +extern SDL_DECLSPEC MIX_Audio * SDLCALL MIX_LoadRawAudioNoCopy(MIX_Mixer *mixer, const void *data, size_t datalen, const SDL_AudioSpec *spec, bool free_when_done); + +/** + * Create a MIX_Audio that generates a sinewave. + * + * This is useful just to have _something_ to play, perhaps for testing or + * debugging purposes. + * + * You specify its frequency in Hz (determines the pitch of the sinewave's + * audio) and amplitude (determines the volume of the sinewave: 1.0f is very + * loud, 0.0f is silent). + * + * A number of milliseconds of audio to generate can be specified. Specifying + * a value less than zero will generate infinite audio (when assigned to a + * MIX_Track, the sinewave will play forever). + * + * MIX_Audio objects can be shared between multiple mixers. The `mixer` + * parameter just suggests the most likely mixer to use this audio, in case + * some optimization might be applied, but this is not required, and a NULL + * mixer may be specified. + * + * \param mixer a mixer this audio is intended to be used with. May be NULL. + * \param hz the sinewave's frequency in Hz. + * \param amplitude the sinewave's amplitude from 0.0f to 1.0f. + * \param ms the maximum number of milliseconds of audio to generate, or less + * than zero to generate infinite audio. + * \returns an audio object that can be used to make sound on a mixer, or NULL + * on failure; call SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_DestroyAudio + * \sa MIX_SetTrackAudio + * \sa MIX_LoadAudio_IO + */ +extern SDL_DECLSPEC MIX_Audio * SDLCALL MIX_CreateSineWaveAudio(MIX_Mixer *mixer, int hz, float amplitude, Sint64 ms); + + +/** + * Get the properties associated with a MIX_Audio. + * + * SDL_mixer offers some properties of its own, but this can also be a + * convenient place to store app-specific data. + * + * A SDL_PropertiesID is created the first time this function is called for a + * given MIX_Audio, if necessary. + * + * The following read-only properties are provided by SDL_mixer: + * + * - `MIX_PROP_METADATA_TITLE_STRING`: the audio's title ("Smells Like Teen + * Spirit"). + * - `MIX_PROP_METADATA_ARTIST_STRING`: the audio's artist name ("Nirvana"). + * - `MIX_PROP_METADATA_ALBUM_STRING`: the audio's album name ("Nevermind"). + * - `MIX_PROP_METADATA_COPYRIGHT_STRING`: the audio's copyright info + * ("Copyright (c) 1991") + * - `MIX_PROP_METADATA_TRACK_NUMBER`: the audio's track number on the album + * (1) + * - `MIX_PROP_METADATA_TOTAL_TRACKS_NUMBER`: the total tracks on the album + * (13) + * - `MIX_PROP_METADATA_YEAR_NUMBER`: the year the audio was released (1991) + * - `MIX_PROP_METADATA_DURATION_FRAMES_NUMBER`: The sample frames worth of + * PCM data that comprise this audio. It might be off by a little if the + * decoder only knows the duration as a unit of time. + * - `MIX_PROP_METADATA_DURATION_INFINITE_BOOLEAN`: if true, audio never runs + * out of sound to generate. This isn't necessarily always known to + * SDL_mixer, though. + * + * Other properties, documented with MIX_LoadAudioWithProperties(), may also + * be present. + * + * Note that the metadata properties are whatever SDL_mixer finds in things + * like ID3 tags, and they often have very little standardized formatting, may + * be missing, and can be completely wrong if the original data is + * untrustworthy (like an MP3 from a P2P file sharing service). + * + * \param audio the audio to query. + * \returns a valid property ID on success or 0 on failure; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC SDL_PropertiesID SDLCALL MIX_GetAudioProperties(MIX_Audio *audio); + +#define MIX_PROP_METADATA_TITLE_STRING "SDL_mixer.metadata.title" +#define MIX_PROP_METADATA_ARTIST_STRING "SDL_mixer.metadata.artist" +#define MIX_PROP_METADATA_ALBUM_STRING "SDL_mixer.metadata.album" +#define MIX_PROP_METADATA_COPYRIGHT_STRING "SDL_mixer.metadata.copyright" +#define MIX_PROP_METADATA_TRACK_NUMBER "SDL_mixer.metadata.track" +#define MIX_PROP_METADATA_TOTAL_TRACKS_NUMBER "SDL_mixer.metadata.total_tracks" +#define MIX_PROP_METADATA_YEAR_NUMBER "SDL_mixer.metadata.year" +#define MIX_PROP_METADATA_DURATION_FRAMES_NUMBER "SDL_mixer.metadata.duration_frames" +#define MIX_PROP_METADATA_DURATION_INFINITE_BOOLEAN "SDL_mixer.metadata.duration_infinite" + + +/** + * Get the length of a MIX_Audio's playback in sample frames. + * + * This information is also available via the + * MIX_PROP_METADATA_DURATION_FRAMES_NUMBER property, but it's common enough + * to provide a simple accessor function. + * + * This reports the length of the data in _sample frames_, so sample-perfect + * mixing can be possible. Sample frames are only meaningful as a measure of + * time if the sample rate (frequency) is also known. To convert from sample + * frames to milliseconds, use MIX_AudioFramesToMS(). + * + * Not all audio file formats can report the complete length of the data they + * will produce through decoding: some can't calculate it, some might produce + * infinite audio. + * + * Also, some file formats can only report duration as a unit of time, which + * means SDL_mixer might have to estimate sample frames from that information. + * With less precision, the reported duration might be off by a few sample + * frames in either direction. + * + * This will return a value >= 0 if a duration is known. It might also return + * MIX_DURATION_UNKNOWN or MIX_DURATION_INFINITE. + * + * \param audio the audio to query. + * \returns the length of the audio in sample frames, or MIX_DURATION_UNKNOWN + * or MIX_DURATION_INFINITE. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC Sint64 SDLCALL MIX_GetAudioDuration(MIX_Audio *audio); + +#define MIX_DURATION_UNKNOWN -1 +#define MIX_DURATION_INFINITE -2 + + +/** + * Query the initial audio format of a MIX_Audio. + * + * Note that some audio files can change format in the middle; some explicitly + * support this, but a more common example is two MP3 files concatenated + * together. In many cases, SDL_mixer will correctly handle these sort of + * files, but this function will only report the initial format a file uses. + * + * \param audio the audio to query. + * \param spec on success, audio format details will be stored here. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL MIX_GetAudioFormat(MIX_Audio *audio, SDL_AudioSpec *spec); + +/** + * Destroy the specified audio. + * + * MIX_Audio is reference-counted internally, so this function only unrefs it. + * If doing so causes the reference count to drop to zero, the MIX_Audio will + * be deallocated. This allows the system to safely operate if the audio is + * still assigned to a MIX_Track at the time of destruction. The actual + * destroying will happen when the track stops using it. + * + * But from the caller's perspective, once this function is called, it should + * assume the `audio` pointer has become invalid. + * + * Destroying a NULL MIX_Audio is a legal no-op. + * + * \param audio the audio to destroy. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC void SDLCALL MIX_DestroyAudio(MIX_Audio *audio); + +/** + * Create a new track on a mixer. + * + * A track provides a single source of audio. All currently-playing tracks + * will be processed and mixed together to form the final output from the + * mixer. + * + * There are no limits to the number of tracks one may create, beyond running + * out of memory, but in normal practice there are a small number of tracks + * that are reused between all loaded audio as appropriate. + * + * Tracks are unique to a specific MIX_Mixer and can't be transferred between + * them. + * + * \param mixer the mixer on which to create this track. + * \returns a new MIX_Track on success, NULL on error; call SDL_GetError() for + * more informations. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_DestroyTrack + */ +extern SDL_DECLSPEC MIX_Track * SDLCALL MIX_CreateTrack(MIX_Mixer *mixer); + +/** + * Destroy the specified track. + * + * If the track is currently playing, it will be stopped immediately, without + * any fadeout. If there is a callback set through + * MIX_SetTrackStoppedCallback(), it will _not_ be called. + * + * If the mixer is currently mixing in another thread, this will block until + * it finishes. + * + * Destroying a NULL MIX_Track is a legal no-op. + * + * \param track the track to destroy. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC void SDLCALL MIX_DestroyTrack(MIX_Track *track); + +/** + * Get the properties associated with a track. + * + * Currently SDL_mixer assigns no properties of its own to a track, but this + * can be a convenient place to store app-specific data. + * + * A SDL_PropertiesID is created the first time this function is called for a + * given track. + * + * \param track the track to query. + * \returns a valid property ID on success or 0 on failure; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC SDL_PropertiesID SDLCALL MIX_GetTrackProperties(MIX_Track *track); + +/** + * Get the MIX_Mixer that owns a MIX_Track. + * + * This is the mixer pointer that was passed to MIX_CreateTrack(). + * + * \param track the track to query. + * \returns the mixer associated with the track, or NULL on error; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC MIX_Mixer * SDLCALL MIX_GetTrackMixer(MIX_Track *track); + +/** + * Set a MIX_Track's input to a MIX_Audio. + * + * A MIX_Audio is audio data stored in RAM (possibly still in a compressed + * form). One MIX_Audio can be assigned to multiple tracks at once. + * + * Once a track has a valid input, it can start mixing sound by calling + * MIX_PlayTrack(), or possibly MIX_PlayTag(). + * + * Calling this function with a NULL audio input is legal, and removes any + * input from the track. If the track was currently playing, the next time the + * mixer runs, it'll notice this and mark the track as stopped, calling any + * assigned MIX_TrackStoppedCallback. + * + * It is legal to change the input of a track while it's playing, however some + * states, like loop points, may cease to make sense with the new audio. In + * such a case, one can call MIX_PlayTrack again to adjust parameters. + * + * The track will hold a reference to the provided MIX_Audio, so it is safe to + * call MIX_DestroyAudio() on it while the track is still using it. The track + * will drop its reference (and possibly free the resources) once it is no + * longer using the MIX_Audio. + * + * \param track the track on which to set a new audio input. + * \param audio the new audio input to set. May be NULL. + * \returns true on success, false on error; call SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetTrackAudio(MIX_Track *track, MIX_Audio *audio); + +/** + * Set a MIX_Track's input to an SDL_AudioStream. + * + * Using an audio stream allows the application to generate any type of audio, + * in any format, possibly procedurally or on-demand, and mix in with all + * other tracks. + * + * When a track uses an audio stream, it will call SDL_GetAudioStreamData as + * it needs more audio to mix. The app can either buffer data to the stream + * ahead of time, or set a callback on the stream to provide data as needed. + * Please refer to SDL's documentation for details. + * + * A given audio stream may only be assigned to a single track at a time; + * duplicate assignments won't return an error, but assigning a stream to + * multiple tracks will cause each track to read from the stream arbitrarily, + * causing confusion and incorrect mixing. + * + * Once a track has a valid input, it can start mixing sound by calling + * MIX_PlayTrack(), or possibly MIX_PlayTag(). + * + * Calling this function with a NULL audio stream is legal, and removes any + * input from the track. If the track was currently playing, the next time the + * mixer runs, it'll notice this and mark the track as stopped, calling any + * assigned MIX_TrackStoppedCallback. + * + * It is legal to change the input of a track while it's playing, however some + * states, like loop points, may cease to make sense with the new audio. In + * such a case, one can call MIX_PlayTrack again to adjust parameters. + * + * The provided audio stream must remain valid until the track no longer needs + * it (either by changing the track's input or destroying the track). + * + * \param track the track on which to set a new audio input. + * \param stream the audio stream to use as the track's input. + * \returns true on success, false on error; call SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetTrackAudioStream(MIX_Track *track, SDL_AudioStream *stream); + +/** + * Set a MIX_Track's input to an SDL_IOStream. + * + * This is not the recommended way to set a track's input, but this can be + * useful for a very specific scenario: a large file, to be played once, that + * must be read from disk in small chunks as needed. In most cases, however, + * it is preferable to create a MIX_Audio ahead of time and use + * MIX_SetTrackAudio() instead. + * + * The stream supplied here should provide an audio file in a supported + * format. SDL_mixer will parse it during this call to make sure it's valid, + * and then will read file data from the stream as it needs to decode more + * during mixing. + * + * The stream must be able to seek through the complete set of data, or this + * function will fail. + * + * A given IOStream may only be assigned to a single track at a time; + * duplicate assignments won't return an error, but assigning a stream to + * multiple tracks will cause each track to read from the stream arbitrarily, + * causing confusion, incorrect mixing, or failure to decode. + * + * Once a track has a valid input, it can start mixing sound by calling + * MIX_PlayTrack(), or possibly MIX_PlayTag(). + * + * Calling this function with a NULL stream is legal, and removes any input + * from the track. If the track was currently playing, the next time the mixer + * runs, it'll notice this and mark the track as stopped, calling any assigned + * MIX_TrackStoppedCallback. + * + * It is legal to change the input of a track while it's playing, however some + * states, like loop points, may cease to make sense with the new audio. In + * such a case, one can call MIX_PlayTrack again to adjust parameters. + * + * The provided stream must remain valid until the track no longer needs it + * (either by changing the track's input or destroying the track). + * + * \param track the track on which to set a new audio input. + * \param io the new i/o stream to use as the track's input. + * \param closeio if true, close the stream when done with it. + * \returns true on success, false on error; call SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_SetTrackRawIOStream + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetTrackIOStream(MIX_Track *track, SDL_IOStream *io, bool closeio); + +/** + * Set a MIX_Track's input to an SDL_IOStream providing raw PCM data. + * + * This is not the recommended way to set a track's input, but this can be + * useful for a very specific scenario: a large file, to be played once, that + * must be read from disk in small chunks as needed. In most cases, however, + * it is preferable to create a MIX_Audio ahead of time and use + * MIX_SetTrackAudio() instead. + * + * Also, an MIX_SetTrackAudioStream() can _also_ provide raw PCM audio to a + * track, via an SDL_AudioStream, which might be preferable unless the data is + * already coming directly from an SDL_IOStream. + * + * The stream supplied here should provide an audio in raw PCM format. + * + * A given IOStream may only be assigned to a single track at a time; + * duplicate assignments won't return an error, but assigning a stream to + * multiple tracks will cause each track to read from the stream arbitrarily, + * causing confusion and incorrect mixing. + * + * Once a track has a valid input, it can start mixing sound by calling + * MIX_PlayTrack(), or possibly MIX_PlayTag(). + * + * Calling this function with a NULL stream is legal, and removes any input + * from the track. If the track was currently playing, the next time the mixer + * runs, it'll notice this and mark the track as stopped, calling any assigned + * MIX_TrackStoppedCallback. + * + * It is legal to change the input of a track while it's playing, however some + * states, like loop points, may cease to make sense with the new audio. In + * such a case, one can call MIX_PlayTrack again to adjust parameters. + * + * The provided stream must remain valid until the track no longer needs it + * (either by changing the track's input or destroying the track). + * + * \param track the track on which to set a new audio input. + * \param io the new i/o stream to use as the track's input. + * \param spec the format of the PCM data that the SDL_IOStream will provide. + * \param closeio if true, close the stream when done with it. + * \returns true on success, false on error; call SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_SetTrackAudioStream + * \sa MIX_SetTrackIOStream + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetTrackRawIOStream(MIX_Track *track, SDL_IOStream *io, const SDL_AudioSpec *spec, bool closeio); + + +/** + * Assign an arbitrary tag to a track. + * + * A tag can be any valid C string in UTF-8 encoding. It can be useful to + * group tracks in various ways. For example, everything in-game might be + * marked as "game", so when the user brings up the settings menu, the app can + * pause all tracks involved in gameplay at once, but keep background music + * and menu sound effects running. + * + * A track can have as many tags as desired, until the machine runs out of + * memory. + * + * It's legal to add the same tag to a track more than once; the extra + * attempts will report success but not change anything. + * + * Tags can later be removed with MIX_UntagTrack(). + * + * \param track the track to add a tag to. + * \param tag the tag to add. + * \returns true on success, false on error; call SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_UntagTrack + */ +extern SDL_DECLSPEC bool SDLCALL MIX_TagTrack(MIX_Track *track, const char *tag); + +/** + * Remove an arbitrary tag from a track. + * + * A tag can be any valid C string in UTF-8 encoding. It can be useful to + * group tracks in various ways. For example, everything in-game might be + * marked as "game", so when the user brings up the settings menu, the app can + * pause all tracks involved in gameplay at once, but keep background music + * and menu sound effects running. + * + * It's legal to remove a tag that the track doesn't have; this function + * doesn't report errors, so this simply does nothing. + * + * Specifying a NULL tag will remove all tags on a track. + * + * \param track the track from which to remove a tag. + * \param tag the tag to remove, or NULL to remove all current tags. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_TagTrack + */ +extern SDL_DECLSPEC void SDLCALL MIX_UntagTrack(MIX_Track *track, const char *tag); + +/** + * Get the tags currently associated with a track. + * + * Tags are not provided in any guaranteed order. + * + * \param track the track to query. + * \param count a pointer filled in with the number of tags returned, can be + * NULL. + * \returns an array of the tags, NULL-terminated, or NULL on failure; call + * SDL_GetError() for more information. This is a single allocation + * that should be freed with SDL_free() when it is no longer needed. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC char ** SDLCALL MIX_GetTrackTags(MIX_Track *track, int *count); + +/** + * Get all tracks with a specific tag. + * + * Tracks are not provided in any guaranteed order. + * + * \param mixer the mixer to query. + * \param tag the tag to search. + * \param count a pointer filled in with the number of tracks returned, can be + * NULL. + * \returns an array of the tracks, NULL-terminated, or NULL on failure; call + * SDL_GetError() for more information. The returned pointer should + * be freed with SDL_free() when it is no longer needed. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC MIX_Track ** SDLCALL MIX_GetTaggedTracks(MIX_Mixer *mixer, const char *tag, int *count); + +/** + * Seek a playing track to a new position in its input. + * + * (Not to be confused with MIX_SetTrack3DPosition(), which is positioning of + * the track in 3D space, not the playback position of its audio data.) + * + * On a playing track, the next time the mixer runs, it will start mixing from + * the new position. + * + * Position is defined in _sample frames_ of decoded audio, not units of time, + * so that sample-perfect mixing can be achieved. To instead operate in units + * of time, use MIX_TrackMSToFrames() to get the approximate sample frames for + * a given tick. + * + * This function requires an input that can seek (so it can not be used if the + * input was set with MIX_SetTrackAudioStream()), and a audio file format that + * allows seeking. SDL_mixer's decoders for some file formats do not offer + * seeking, or can only seek to times, not exact sample frames, in which case + * the final position may be off by some amount of sample frames. Please check + * your audio data and file bug reports if appropriate. + * + * It's legal to call this function on a track that is stopped, but a future + * call to MIX_PlayTrack() will reset the start position anyhow. Paused tracks + * will resume at the new input position. + * + * \param track the track to change. + * \param frames the sample frame position to seek to. + * \returns true on success, false on error; call SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_GetTrackPlaybackPosition + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetTrackPlaybackPosition(MIX_Track *track, Sint64 frames); + +/** + * Get the current input position of a playing track. + * + * (Not to be confused with MIX_GetTrack3DPosition(), which is positioning of + * the track in 3D space, not the playback position of its audio data.) + * + * Position is defined in _sample frames_ of decoded audio, not units of time, + * so that sample-perfect mixing can be achieved. To instead operate in units + * of time, use MIX_TrackFramesToMS() to convert the return value to + * milliseconds. + * + * Stopped and paused tracks will report the position when they halted. + * Playing tracks will report the current position, which will change over + * time. + * + * \param track the track to change. + * \returns the track's current sample frame position, or -1 on error; call + * SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_SetTrackPlaybackPosition + */ +extern SDL_DECLSPEC Sint64 SDLCALL MIX_GetTrackPlaybackPosition(MIX_Track *track); + +/** + * Query whether a given track is fading. + * + * This specifically checks if the track is _not stopped_ (paused or playing), + * and it is fading in or out, and returns the number of frames remaining in + * the fade. + * + * If fading out, the returned value will be negative. When fading in, the + * returned value will be positive. If not fading, this function returns zero. + * + * On various errors (MIX_Init() was not called, the track is NULL), this + * returns 0, but there is no mechanism to distinguish errors from tracks that + * aren't fading. + * + * \param track the track to query. + * \returns less than 0 if the track is fading out, greater than 0 if fading + * in, zero otherwise. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC Sint64 SDLCALL MIX_GetTrackFadeFrames(MIX_Track *track); + +/** + * Query how many loops remain for a given track. + * + * This returns the number of loops still pending; if a track will eventually + * complete and loop to play again one more time, this will return 1. If a + * track _was_ looping but is on its final iteration of the loop (will stop + * when this iteration completes), this will return zero. + * + * A track that is looping infinitely will return -1. This value does not + * report an error in this case. + * + * A track that is stopped (not playing and not paused) will have zero loops + * remaining. + * + * On various errors (MIX_Init() was not called, the track is NULL), this + * returns zero, but there is no mechanism to distinguish errors from + * non-looping tracks. + * + * \param track the track to query. + * \returns the number of pending loops, zero if not looping, and -1 if + * looping infinitely. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC int SDLCALL MIX_GetTrackLoops(MIX_Track *track); + +/** + * Change the number of times a currently-playing track will loop. + * + * This replaces any previously-set remaining loops. A value of 1 will loop to + * the start of playback one time. Zero will not loop at all. A value of -1 + * requests infinite loops. If the input is not seekable and `num_loops` isn't + * zero, this function will report success but the track will stop at the + * point it should loop. + * + * The new loop count replaces any previous state, even if the track has + * already looped. + * + * This has no effect on a track that is stopped, or rather, starting a + * stopped track later will set a new loop count, replacing this value. + * Stopped tracks can specify a loop count while starting via + * MIX_PROP_PLAY_LOOPS_NUMBER. This function is intended to alter that count + * in the middle of playback. + * + * \param track the track to configure. + * \param num_loops new number of times to loop. Zero to disable looping, -1 + * to loop infinitely. + * \returns true on success, false on error; call SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_GetTrackLoops + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetTrackLoops(MIX_Track *track, int num_loops); + +/** + * Query the MIX_Audio assigned to a track. + * + * This returns the MIX_Audio object currently assigned to `track` through a + * call to MIX_SetTrackAudio(). If there is none assigned, or the track has an + * input that isn't a MIX_Audio (such as an SDL_AudioStream or SDL_IOStream), + * this will return NULL. + * + * On various errors (MIX_Init() was not called, the track is NULL), this + * returns NULL, but there is no mechanism to distinguish errors from tracks + * without a valid input. + * + * \param track the track to query. + * \returns a MIX_Audio if available, NULL if not. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_GetTrackAudioStream + */ +extern SDL_DECLSPEC MIX_Audio * SDLCALL MIX_GetTrackAudio(MIX_Track *track); + +/** + * Query the SDL_AudioStream assigned to a track. + * + * This returns the SDL_AudioStream object currently assigned to `track` + * through a call to MIX_SetTrackAudioStream(). If there is none assigned, or + * the track has an input that isn't an SDL_AudioStream (such as a MIX_Audio + * or SDL_IOStream), this will return NULL. + * + * On various errors (MIX_Init() was not called, the track is NULL), this + * returns NULL, but there is no mechanism to distinguish errors from tracks + * without a valid input. + * + * \param track the track to query. + * \returns an SDL_AudioStream if available, NULL if not. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_GetTrackAudio + */ +extern SDL_DECLSPEC SDL_AudioStream * SDLCALL MIX_GetTrackAudioStream(MIX_Track *track); + +/** + * Return the number of sample frames remaining to be mixed in a track. + * + * If the track is playing or paused, and its total duration is known, this + * will report how much audio is left to mix. If the track is playing, future + * calls to this function will report different values. + * + * Remaining audio is defined in _sample frames_ of decoded audio, not units + * of time, so that sample-perfect mixing can be achieved. To instead operate + * in units of time, use MIX_TrackFramesToMS() to convert the return value to + * milliseconds. + * + * This function does not take into account fade-outs or looping, just the + * current mixing position vs the duration of the track. + * + * If the duration of the track isn't known, or `track` is NULL, this function + * returns -1. A stopped track reports 0. + * + * \param track the track to query. + * \returns the total sample frames still to be mixed, or -1 if unknown. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC Sint64 SDLCALL MIX_GetTrackRemaining(MIX_Track *track); + +/** + * Convert milliseconds to sample frames for a track's current format. + * + * This calculates time based on the track's current input format, which can + * change when its input does, and also if that input changes formats + * mid-stream (for example, if decoding a file that is two MP3s concatenated + * together). + * + * On various errors (MIX_Init() was not called, the track is NULL), this + * returns -1. If the track has no input, this returns -1. If `ms` is < 0, + * this returns -1. + * + * \param track the track to query. + * \param ms the milliseconds to convert to track-specific sample frames. + * \returns Converted number of sample frames, or -1 for errors/no input; call + * SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_TrackFramesToMS + */ +extern SDL_DECLSPEC Sint64 SDLCALL MIX_TrackMSToFrames(MIX_Track *track, Sint64 ms); + +/** + * Convert sample frames for a track's current format to milliseconds. + * + * This calculates time based on the track's current input format, which can + * change when its input does, and also if that input changes formats + * mid-stream (for example, if decoding a file that is two MP3s concatenated + * together). + * + * Sample frames are more precise than milliseconds, so out of necessity, this + * function will approximate by rounding down to the closest full millisecond. + * + * On various errors (MIX_Init() was not called, the track is NULL), this + * returns -1. If the track has no input, this returns -1. If `frames` is < 0, + * this returns -1. + * + * \param track the track to query. + * \param frames the track-specific sample frames to convert to milliseconds. + * \returns Converted number of milliseconds, or -1 for errors/no input; call + * SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_TrackMSToFrames + */ +extern SDL_DECLSPEC Sint64 SDLCALL MIX_TrackFramesToMS(MIX_Track *track, Sint64 frames); + +/** + * Convert milliseconds to sample frames for a MIX_Audio's format. + * + * This calculates time based on the audio's initial format, even if the + * format would change mid-stream. + * + * If `ms` is < 0, this returns -1. + * + * \param audio the audio to query. + * \param ms the milliseconds to convert to audio-specific sample frames. + * \returns Converted number of sample frames, or -1 for errors/no input; call + * SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_AudioFramesToMS + */ +extern SDL_DECLSPEC Sint64 SDLCALL MIX_AudioMSToFrames(MIX_Audio *audio, Sint64 ms); + +/** + * Convert sample frames for a MIX_Audio's format to milliseconds. + * + * This calculates time based on the audio's initial format, even if the + * format would change mid-stream. + * + * Sample frames are more precise than milliseconds, so out of necessity, this + * function will approximate by rounding down to the closest full millisecond. + * + * If `frames` is < 0, this returns -1. + * + * \param audio the audio to query. + * \param frames the audio-specific sample frames to convert to milliseconds. + * \returns Converted number of milliseconds, or -1 for errors/no input; call + * SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_AudioMSToFrames + */ +extern SDL_DECLSPEC Sint64 SDLCALL MIX_AudioFramesToMS(MIX_Audio *audio, Sint64 frames); + +/** + * Convert milliseconds to sample frames at a specific sample rate. + * + * If `sample_rate` is <= 0, this returns -1. If `ms` is < 0, this returns -1. + * + * \param sample_rate the sample rate to use for conversion. + * \param ms the milliseconds to convert to rate-specific sample frames. + * \returns Converted number of sample frames, or -1 for errors; call + * SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_FramesToMS + */ +extern SDL_DECLSPEC Sint64 SDLCALL MIX_MSToFrames(int sample_rate, Sint64 ms); + +/** + * Convert sample frames, at a specific sample rate, to milliseconds. + * + * Sample frames are more precise than milliseconds, so out of necessity, this + * function will approximate by rounding down to the closest full millisecond. + * + * If `sample_rate` is <= 0, this returns -1. If `frames` is < 0, this returns + * -1. + * + * \param sample_rate the sample rate to use for conversion. + * \param frames the rate-specific sample frames to convert to milliseconds. + * \returns Converted number of milliseconds, or -1 for errors; call + * SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_MSToFrames + */ +extern SDL_DECLSPEC Sint64 SDLCALL MIX_FramesToMS(int sample_rate, Sint64 frames); + + +/* operations that deal with actual mixing/playback... */ + +/** + * Start (or restart) mixing a track for playback. + * + * The track will use whatever input was last assigned to it when playing; an + * input must be assigned to this track or this function will fail. Inputs are + * assigned with calls to MIX_SetTrackAudio(), MIX_SetTrackAudioStream(), or + * MIX_SetTrackIOStream(). + * + * If the track is already playing, or paused, this will restart the track + * with the newly-specified parameters. + * + * As there are several parameters, and more may be added in the future, they + * are specified with an SDL_PropertiesID. The parameters have reasonable + * defaults, and specifying a 0 for `options` will choose defaults for + * everything. + * + * SDL_PropertiesID are discussed in + * [SDL's documentation](https://wiki.libsdl.org/SDL3/CategoryProperties) + * . + * + * These are the supported properties: + * + * - `MIX_PROP_PLAY_LOOPS_NUMBER`: The number of times to loop the track when + * it reaches the end. A value of 1 will loop to the start one time. Zero + * will not loop at all. A value of -1 requests infinite loops. If the input + * is not seekable and this value isn't zero, this function will report + * success but the track will stop at the point it should loop. Default 0. + * - `MIX_PROP_PLAY_MAX_FRAME_NUMBER`: Mix at most to this sample frame + * position in the track. This will be treated as if the input reach EOF at + * this point in the audio file. If -1, mix all available audio without a + * limit. Default -1. + * - `MIX_PROP_PLAY_MAX_MILLISECONDS_NUMBER`: The same as using the + * MIX_PROP_PLAY_MAX_FRAME_NUMBER property, but the value is specified in + * milliseconds instead of sample frames. If both properties are specified, + * the sample frames value is favored. Default -1. + * - `MIX_PROP_PLAY_START_FRAME_NUMBER`: Start mixing from this sample frame + * position in the track's input. A value <= 0 will begin from the start of + * the track's input. If the input is not seekable and this value is > 0, + * this function will report failure. Default 0. + * - `MIX_PROP_PLAY_START_MILLISECOND_NUMBER`: The same as using the + * MIX_PROP_PLAY_START_FRAME_NUMBER property, but the value is specified in + * milliseconds instead of sample frames. If both properties are specified, + * the sample frames value is favored. Default 0. + * - `MIX_PROP_PLAY_LOOP_START_FRAME_NUMBER`: If the track is looping, this is + * the sample frame position that the track will loop back to; this lets one + * play an intro at the start of a track on the first iteration, but have a + * loop point somewhere in the middle thereafter. A value <= 0 will begin + * the loop from the start of the track's input. Default 0. + * - `MIX_PROP_PLAY_LOOP_START_MILLISECOND_NUMBER`: The same as using the + * MIX_PROP_PLAY_LOOP_START_FRAME_NUMBER property, but the value is + * specified in milliseconds instead of sample frames. If both properties + * are specified, the sample frames value is favored. Default 0. + * - `MIX_PROP_PLAY_FADE_IN_FRAMES_NUMBER`: The number of sample frames over + * which to fade in the newly-started track. The track will begin mixing + * silence and reach full volume smoothly over this many sample frames. If + * the track loops before the fade-in is complete, it will continue to fade + * correctly from the loop point. A value <= 0 will disable fade-in, so the + * track starts mixing at full volume. Default 0. + * - `MIX_PROP_PLAY_FADE_IN_MILLISECONDS_NUMBER`: The same as using the + * MIX_PROP_PLAY_FADE_IN_FRAMES_NUMBER property, but the value is specified + * in milliseconds instead of sample frames. If both properties are + * specified, the sample frames value is favored. Default 0. + * - `MIX_PROP_PLAY_FADE_IN_START_GAIN_FLOAT`: If fading in, start fading from + * this volume level. 0.0f is silence and 1.0f is full volume, every in + * between is a linear change in gain. The specified value will be clamped + * between 0.0f and 1.0f. Default 0.0f. + * - `MIX_PROP_PLAY_APPEND_SILENCE_FRAMES_NUMBER`: At the end of mixing this + * track, after all loops are complete, append this many sample frames of + * silence as if it were part of the audio file. This allows for apps to + * implement effects in callbacks, like reverb, that need to generate + * samples past the end of the stream's audio, or perhaps introduce a delay + * before starting a new sound on the track without having to manage it + * directly. A value <= 0 generates no silence before stopping the track. + * Default 0. + * - `MIX_PROP_PLAY_APPEND_SILENCE_MILLISECONDS_NUMBER`: The same as using the + * MIX_PROP_PLAY_APPEND_SILENCE_FRAMES_NUMBER property, but the value is + * specified in milliseconds instead of sample frames. If both properties + * are specified, the sample frames value is favored. Default 0. + * - `MIX_PROP_PLAY_HALT_WHEN_EXHAUSTED_BOOLEAN`: If true, when input is + * completely consumed for the track, the mixer will mark the track as + * stopped (and call any appropriate MIX_TrackStoppedCallback, etc); to play + * more, the track will need to be restarted. If false, the track will just + * not contribute to the mix, but it will not be marked as stopped. There + * may be clever logic tricks this exposes generally, but this property is + * specifically useful when the track's input is an SDL_AudioStream assigned + * via MIX_SetTrackAudioStream(). Setting this property to true can be + * useful when pushing a complete piece of audio to the stream that has a + * definite ending, as the track will operate like any other audio was + * applied. Setting to false means as new data is added to the stream, the + * mixer will start using it as soon as possible, which is useful when audio + * should play immediately as it drips in: new VoIP packets, etc. Note that + * in this situation, if the audio runs out when needed, there _will_ be + * gaps in the mixed output, so try to buffer enough data to avoid this when + * possible. Note that a track is not consider exhausted until all its loops + * and appended silence have been mixed (and also, that loops don't mean + * anything when the input is an AudioStream). Default true. + * + * If this function fails, mixing of this track will not start (or restart, if + * it was already started). + * + * \param track the track to start (or restart) mixing. + * \param options a set of properties that control playback. May be zero. + * \returns true on success, false on error; call SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_PlayTag + * \sa MIX_PlayAudio + * \sa MIX_StopTrack + * \sa MIX_PauseTrack + * \sa MIX_TrackPlaying + */ +extern SDL_DECLSPEC bool SDLCALL MIX_PlayTrack(MIX_Track *track, SDL_PropertiesID options); + +#define MIX_PROP_PLAY_LOOPS_NUMBER "SDL_mixer.play.loops" +#define MIX_PROP_PLAY_MAX_FRAME_NUMBER "SDL_mixer.play.max_frame" +#define MIX_PROP_PLAY_MAX_MILLISECONDS_NUMBER "SDL_mixer.play.max_milliseconds" +#define MIX_PROP_PLAY_START_FRAME_NUMBER "SDL_mixer.play.start_frame" +#define MIX_PROP_PLAY_START_MILLISECOND_NUMBER "SDL_mixer.play.start_millisecond" +#define MIX_PROP_PLAY_LOOP_START_FRAME_NUMBER "SDL_mixer.play.loop_start_frame" +#define MIX_PROP_PLAY_LOOP_START_MILLISECOND_NUMBER "SDL_mixer.play.loop_start_millisecond" +#define MIX_PROP_PLAY_FADE_IN_FRAMES_NUMBER "SDL_mixer.play.fade_in_frames" +#define MIX_PROP_PLAY_FADE_IN_MILLISECONDS_NUMBER "SDL_mixer.play.fade_in_milliseconds" +#define MIX_PROP_PLAY_FADE_IN_START_GAIN_FLOAT "SDL_mixer.play.fade_in_start_gain" +#define MIX_PROP_PLAY_APPEND_SILENCE_FRAMES_NUMBER "SDL_mixer.play.append_silence_frames" +#define MIX_PROP_PLAY_APPEND_SILENCE_MILLISECONDS_NUMBER "SDL_mixer.play.append_silence_milliseconds" +#define MIX_PROP_PLAY_HALT_WHEN_EXHAUSTED_BOOLEAN "SDL_mixer.play.halt_when_exhausted" + +/** + * Start (or restart) mixing all tracks with a specific tag for playback. + * + * This function follows all the same rules as MIX_PlayTrack(); please refer + * to its documentation for the details. Unlike that function, MIX_PlayTag() + * operates on multiple tracks at once that have the specified tag applied, + * via MIX_TagTrack(). + * + * If all of your tagged tracks have different sample rates, it would make + * sense to use the `*_MILLISECONDS_NUMBER` properties in your `options`, + * instead of `*_FRAMES_NUMBER`, and let SDL_mixer figure out how to apply it + * to each track. + * + * This function returns true if all tagged tracks are started (or restarted). + * If any track fails, this function returns false, but all tracks that could + * start will still be started even when this function reports failure. + * + * From the point of view of the mixing process, all tracks that successfully + * (re)start will do so at the exact same moment. + * + * \param mixer the mixer on which to look for tagged tracks. + * \param tag the tag to use when searching for tracks. + * \param options the set of options that will be applied to each track. + * \returns true on success, false on error; call SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_PlayTrack + * \sa MIX_TagTrack + * \sa MIX_StopTrack + * \sa MIX_PauseTrack + * \sa MIX_TrackPlaying + */ +extern SDL_DECLSPEC bool SDLCALL MIX_PlayTag(MIX_Mixer *mixer, const char *tag, SDL_PropertiesID options); + +/** + * Play a MIX_Audio from start to finish without any management. + * + * This is what we term a "fire-and-forget" sound. Internally, SDL_mixer will + * manage a temporary track to mix the specified MIX_Audio, cleaning it up + * when complete. No options can be provided for how to do the mixing, like + * MIX_PlayTrack() offers, and since the track is not available to the caller, + * no adjustments can be made to mixing over time. + * + * This is not the function to build an entire game of any complexity around, + * but it can be convenient to play simple, one-off sounds that can't be + * stopped early. An example would be a voice saying "GAME OVER" during an + * unpausable endgame sequence. + * + * There are no limits to the number of fire-and-forget sounds that can mix at + * once (short of running out of memory), and SDL_mixer keeps an internal pool + * of temporary tracks it creates as needed and reuses when available. + * + * \param mixer the mixer on which to play this audio. + * \param audio the audio input to play. + * \returns true if the track has begun mixing, false on error; call + * SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_PlayTrack + * \sa MIX_LoadAudio + */ +extern SDL_DECLSPEC bool SDLCALL MIX_PlayAudio(MIX_Mixer *mixer, MIX_Audio *audio); + +/** + * Halt a currently-playing track, possibly fading out over time. + * + * If `fade_out_frames` is > 0, the track does not stop mixing immediately, + * but rather fades to silence over that many sample frames before stopping. + * Sample frames are specific to the input assigned to the track, to allow for + * sample-perfect mixing. MIX_TrackMSToFrames() can be used to convert + * milliseconds to an appropriate value here. + * + * If the track ends normally while the fade-out is still in progress, the + * audio stops there; the fade is not adjusted to be shorter if it will last + * longer than the audio remaining. + * + * Once a track has completed any fadeout and come to a stop, it will call its + * MIX_TrackStoppedCallback, if any. It is legal to assign the track a new + * input and/or restart it during this callback. + * + * It is legal to halt a track that's already stopped. It does nothing, and + * returns true. + * + * \param track the track to halt. + * \param fade_out_frames the number of sample frames to spend fading out to + * silence before halting. 0 to stop immediately. + * \returns true if the track has stopped, false on error; call SDL_GetError() + * for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_PlayTrack + */ +extern SDL_DECLSPEC bool SDLCALL MIX_StopTrack(MIX_Track *track, Sint64 fade_out_frames); + +/** + * Halt all currently-playing tracks, possibly fading out over time. + * + * If `fade_out_ms` is > 0, the tracks do not stop mixing immediately, but + * rather fades to silence over that many milliseconds before stopping. Note + * that this is different than MIX_StopTrack(), which wants sample frames; + * this function takes milliseconds because different tracks might have + * different sample rates. + * + * If a track ends normally while the fade-out is still in progress, the audio + * stops there; the fade is not adjusted to be shorter if it will last longer + * than the audio remaining. + * + * Once a track has completed any fadeout and come to a stop, it will call its + * MIX_TrackStoppedCallback, if any. It is legal to assign the track a new + * input and/or restart it during this callback. This function does not + * prevent new play requests from being made. + * + * \param mixer the mixer on which to stop all tracks. + * \param fade_out_ms the number of milliseconds to spend fading out to + * silence before halting. 0 to stop immediately. + * \returns true on success, false on error; call SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_StopTrack + */ +extern SDL_DECLSPEC bool SDLCALL MIX_StopAllTracks(MIX_Mixer *mixer, Sint64 fade_out_ms); + +/** + * Halt all tracks with a specific tag, possibly fading out over time. + * + * If `fade_out_ms` is > 0, the tracks do not stop mixing immediately, but + * rather fades to silence over that many milliseconds before stopping. Note + * that this is different than MIX_StopTrack(), which wants sample frames; + * this function takes milliseconds because different tracks might have + * different sample rates. + * + * If a track ends normally while the fade-out is still in progress, the audio + * stops there; the fade is not adjusted to be shorter if it will last longer + * than the audio remaining. + * + * Once a track has completed any fadeout and come to a stop, it will call its + * MIX_TrackStoppedCallback, if any. It is legal to assign the track a new + * input and/or restart it during this callback. This function does not + * prevent new play requests from being made. + * + * \param mixer the mixer on which to stop tracks. + * \param tag the tag to use when searching for tracks. + * \param fade_out_ms the number of milliseconds to spend fading out to + * silence before halting. 0 to stop immediately. + * \returns true on success, false on error; call SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_StopTrack + * \sa MIX_TagTrack + */ +extern SDL_DECLSPEC bool SDLCALL MIX_StopTag(MIX_Mixer *mixer, const char *tag, Sint64 fade_out_ms); + +/** + * Pause a currently-playing track. + * + * A paused track is not considered "stopped," so its MIX_TrackStoppedCallback + * will not fire if paused, but it won't change state by default, generate + * audio, or generally make progress, until it is resumed. + * + * It is legal to pause a track that's in any state (playing, already paused, + * or stopped). Unless the track is currently playing, pausing does nothing, + * and returns true. A false return is only used to signal errors here (such + * as MIX_Init not being called or `track` being NULL). + * + * \param track the track to pause. + * \returns true if the track has paused, false on error; call SDL_GetError() + * for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_ResumeTrack + */ +extern SDL_DECLSPEC bool SDLCALL MIX_PauseTrack(MIX_Track *track); + +/** + * Pause all currently-playing tracks. + * + * A paused track is not considered "stopped," so its MIX_TrackStoppedCallback + * will not fire if paused, but it won't change state by default, generate + * audio, or generally make progress, until it is resumed. + * + * This function makes all tracks on the specified mixer that are currently + * playing move to a paused state. They can later be resumed. + * + * \param mixer the mixer on which to pause all tracks. + * \returns true on success, false on error; call SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_ResumeTrack + * \sa MIX_ResumeAllTracks + */ +extern SDL_DECLSPEC bool SDLCALL MIX_PauseAllTracks(MIX_Mixer *mixer); + +/** + * Pause all tracks with a specific tag. + * + * A paused track is not considered "stopped," so its MIX_TrackStoppedCallback + * will not fire if paused, but it won't change state by default, generate + * audio, or generally make progress, until it is resumed. + * + * This function makes all currently-playing tracks on the specified mixer, + * with a specific tag, move to a paused state. They can later be resumed. + * + * Tracks that match the specified tag that aren't currently playing are + * ignored. + * + * \param mixer the mixer on which to pause tracks. + * \param tag the tag to use when searching for tracks. + * \returns true on success, false on error; call SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_PauseTrack + * \sa MIX_ResumeTrack + * \sa MIX_ResumeTag + * \sa MIX_TagTrack + */ +extern SDL_DECLSPEC bool SDLCALL MIX_PauseTag(MIX_Mixer *mixer, const char *tag); + +/** + * Resume a currently-paused track. + * + * A paused track is not considered "stopped," so its MIX_TrackStoppedCallback + * will not fire if paused, but it won't change state by default, generate + * audio, or generally make progress, until it is resumed. + * + * It is legal to resume a track that's in any state (playing, paused, or + * stopped). Unless the track is currently paused, resuming does nothing, and + * returns true. A false return is only used to signal errors here (such as + * MIX_Init not being called or `track` being NULL). + * + * \param track the track to resume. + * \returns true if the track has resumed, false on error; call SDL_GetError() + * for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_PauseTrack + */ +extern SDL_DECLSPEC bool SDLCALL MIX_ResumeTrack(MIX_Track *track); + +/** + * Resume all currently-paused tracks. + * + * A paused track is not considered "stopped," so its MIX_TrackStoppedCallback + * will not fire if paused, but it won't change state by default, generate + * audio, or generally make progress, until it is resumed. + * + * This function makes all tracks on the specified mixer that are currently + * paused move to a playing state. + * + * \param mixer the mixer on which to resume all tracks. + * \returns true on success, false on error; call SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_PauseTrack + * \sa MIX_PauseAllTracks + */ +extern SDL_DECLSPEC bool SDLCALL MIX_ResumeAllTracks(MIX_Mixer *mixer); + +/** + * Resume all tracks with a specific tag. + * + * A paused track is not considered "stopped," so its MIX_TrackStoppedCallback + * will not fire if paused, but it won't change state by default, generate + * audio, or generally make progress, until it is resumed. + * + * This function makes all currently-paused tracks on the specified mixer, + * with a specific tag, move to a playing state. + * + * Tracks that match the specified tag that aren't currently paused are + * ignored. + * + * \param mixer the mixer on which to resume tracks. + * \param tag the tag to use when searching for tracks. + * \returns true on success, false on error; call SDL_GetError() for details. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_ResumeTrack + * \sa MIX_PauseTrack + * \sa MIX_PauseTag + * \sa MIX_TagTrack + */ +extern SDL_DECLSPEC bool SDLCALL MIX_ResumeTag(MIX_Mixer *mixer, const char *tag); + +/** + * Query if a track is currently playing. + * + * If this returns true, the track is currently contributing to the mixer's + * output (it's "playing"). It is not stopped nor paused. + * + * On various errors (MIX_Init() was not called, the track is NULL), this + * returns false, but there is no mechanism to distinguish errors from + * non-playing tracks. + * + * \param track the track to query. + * \returns true if playing, false otherwise. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_PlayTrack + * \sa MIX_PauseTrack + * \sa MIX_ResumeTrack + * \sa MIX_StopTrack + * \sa MIX_TrackPaused + */ +extern SDL_DECLSPEC bool SDLCALL MIX_TrackPlaying(MIX_Track *track); + +/** + * Query if a track is currently paused. + * + * If this returns true, the track is not currently contributing to the + * mixer's output but will when resumed (it's "paused"). It is not playing nor + * stopped. + * + * On various errors (MIX_Init() was not called, the track is NULL), this + * returns false, but there is no mechanism to distinguish errors from + * non-playing tracks. + * + * \param track the track to query. + * \returns true if paused, false otherwise. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_PlayTrack + * \sa MIX_PauseTrack + * \sa MIX_ResumeTrack + * \sa MIX_StopTrack + * \sa MIX_TrackPlaying + */ +extern SDL_DECLSPEC bool SDLCALL MIX_TrackPaused(MIX_Track *track); + + +/* volume control... */ + +/** + * Set a mixer's master gain control. + * + * Each mixer has a master gain, to adjust the volume of the entire mix. Each + * sample passing through the pipeline is modulated by this gain value. A gain + * of zero will generate silence, 1.0f will not change the mixed volume, and + * larger than 1.0f will increase the volume. Negative values are illegal. + * There is no maximum gain specified, but this can quickly get extremely + * loud, so please be careful with this setting. + * + * A mixer's master gain defaults to 1.0f. + * + * This value can be changed at any time to adjust the future mix. + * + * \param mixer the mixer to adjust. + * \param gain the new gain value. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_GetMixerGain + * \sa MIX_SetTrackGain + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetMixerGain(MIX_Mixer *mixer, float gain); + +/** + * Get a mixer's master gain control. + * + * This returns the last value set through MIX_SetMixerGain(), or 1.0f if no + * value has ever been explicitly set. + * + * \param mixer the mixer to query. + * \returns the mixer's current master gain. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_SetMixerGain + * \sa MIX_GetTrackGain + */ +extern SDL_DECLSPEC float SDLCALL MIX_GetMixerGain(MIX_Mixer *mixer); + +/** + * Set a track's gain control. + * + * Each track has its own gain, to adjust its overall volume. Each sample from + * this track is modulated by this gain value. A gain of zero will generate + * silence, 1.0f will not change the mixed volume, and larger than 1.0f will + * increase the volume. Negative values are illegal. There is no maximum gain + * specified, but this can quickly get extremely loud, so please be careful + * with this setting. + * + * A track's gain defaults to 1.0f. + * + * This value can be changed at any time to adjust the future mix. + * + * \param track the track to adjust. + * \param gain the new gain value. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_GetTrackGain + * \sa MIX_SetMixerGain + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetTrackGain(MIX_Track *track, float gain); + +/** + * Get a track's gain control. + * + * This returns the last value set through MIX_SetTrackGain(), or 1.0f if no + * value has ever been explicitly set. + * + * \param track the track to query. + * \returns the track's current gain. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_SetTrackGain + * \sa MIX_GetMixerGain + */ +extern SDL_DECLSPEC float SDLCALL MIX_GetTrackGain(MIX_Track *track); + +/** + * Set the gain control of all tracks with a specific tag. + * + * Each track has its own gain, to adjust its overall volume. Each sample from + * this track is modulated by this gain value. A gain of zero will generate + * silence, 1.0f will not change the mixed volume, and larger than 1.0f will + * increase the volume. Negative values are illegal. There is no maximum gain + * specified, but this can quickly get extremely loud, so please be careful + * with this setting. + * + * A track's gain defaults to 1.0f. + * + * This will change the gain control on tracks on the specified mixer that + * have the specified tag. + * + * From the point of view of the mixing process, all tracks that successfully + * change gain values will do so at the exact same moment. + * + * This value can be changed at any time to adjust the future mix. + * + * \param mixer the mixer on which to look for tagged tracks. + * \param tag the tag to use when searching for tracks. + * \param gain the new gain value. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_GetTrackGain + * \sa MIX_SetTrackGain + * \sa MIX_SetMixerGain + * \sa MIX_TagTrack + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetTagGain(MIX_Mixer *mixer, const char *tag, float gain); + + +/* frequency ratio ... */ + +/** + * Set a mixer's master frequency ratio. + * + * Each mixer has a master frequency ratio, that affects the entire mix. This + * can cause the final output to change speed and pitch. A value greater than + * 1.0f will play the audio faster, and at a higher pitch. A value less than + * 1.0f will play the audio slower, and at a lower pitch. 1.0f is normal + * speed. + * + * Each track _also_ has a frequency ratio; it will be applied when mixing + * that track's audio regardless of the master setting. The master setting + * affects the final output after all mixing has been completed. + * + * A mixer's master frequency ratio defaults to 1.0f. + * + * This value can be changed at any time to adjust the future mix. + * + * \param mixer the mixer to adjust. + * \param ratio the frequency ratio. Must be between 0.01f and 100.0f. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_GetMixerFrequencyRatio + * \sa MIX_SetTrackFrequencyRatio + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetMixerFrequencyRatio(MIX_Mixer *mixer, float ratio); + +/** + * Get a mixer's master frequency ratio. + * + * This returns the last value set through MIX_SetMixerFrequencyRatio(), or + * 1.0f if no value has ever been explicitly set. + * + * \param mixer the mixer to query. + * \returns the mixer's current master frequency ratio. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_SetMixerFrequencyRatio + * \sa MIX_GetTrackFrequencyRatio + */ +extern SDL_DECLSPEC float SDLCALL MIX_GetMixerFrequencyRatio(MIX_Mixer *mixer); + + +/** + * Change the frequency ratio of a track. + * + * The frequency ratio is used to adjust the rate at which audio data is + * consumed. Changing this effectively modifies the speed and pitch of the + * track's audio. A value greater than 1.0f will play the audio faster, and at + * a higher pitch. A value less than 1.0f will play the audio slower, and at a + * lower pitch. 1.0f is normal speed. + * + * The default value is 1.0f. + * + * This value can be changed at any time to adjust the future mix. + * + * \param track the track on which to change the frequency ratio. + * \param ratio the frequency ratio. Must be between 0.01f and 100.0f. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_GetTrackFrequencyRatio + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetTrackFrequencyRatio(MIX_Track *track, float ratio); + +/** + * Query the frequency ratio of a track. + * + * The frequency ratio is used to adjust the rate at which audio data is + * consumed. Changing this effectively modifies the speed and pitch of the + * track's audio. A value greater than 1.0f will play the audio faster, and at + * a higher pitch. A value less than 1.0f will play the audio slower, and at a + * lower pitch. 1.0f is normal speed. + * + * The default value is 1.0f. + * + * On various errors (MIX_Init() was not called, the track is NULL), this + * returns 0.0f. Since this is not a valid value to set, this can be seen as + * an error state. + * + * \param track the track on which to query the frequency ratio. + * \returns the current frequency ratio, or 0.0f on failure; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_GetTrackFrequencyRatio + */ +extern SDL_DECLSPEC float SDLCALL MIX_GetTrackFrequencyRatio(MIX_Track *track); + + +/* channel maps... */ + +/** + * Set the current output channel map of a track. + * + * Channel maps are optional; most things do not need them, instead passing + * data in the order that SDL expects. + * + * The output channel map reorders track data after transformations and before + * it is mixed into a mixer group. This can be useful for reversing stereo + * channels, for example. + * + * Each item in the array represents an input channel, and its value is the + * channel that it should be remapped to. To reverse a stereo signal's left + * and right values, you'd have an array of `{ 1, 0 }`. It is legal to remap + * multiple channels to the same thing, so `{ 1, 1 }` would duplicate the + * right channel to both channels of a stereo signal. An element in the + * channel map set to -1 instead of a valid channel will mute that channel, + * setting it to a silence value. + * + * You cannot change the number of channels through a channel map, just + * reorder/mute them. + * + * Tracks default to no remapping applied. Passing a NULL channel map is + * legal, and turns off remapping. + * + * SDL_mixer will copy the channel map; the caller does not have to save this + * array after this call. + * + * \param track the track to change. + * \param chmap the new channel map, NULL to reset to default. + * \param count The number of channels in the map. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetTrackOutputChannelMap(MIX_Track *track, const int *chmap, int count); + + +/* positional audio... */ + +/** + * A set of per-channel gains for tracks using MIX_SetTrackStereo(). + * + * When forcing a track to stereo, the app can specify a per-channel gain, to + * further adjust the left or right outputs. + * + * When mixing audio that has been forced to stereo, each channel is modulated + * by these values. A value of 1.0f produces no change, 0.0f produces silence. + * + * A simple panning effect would be to set `left` to the desired value and + * `right` to `1.0f - left`. + * + * \since This struct is available since SDL_mixer 3.0.0. + * + * \sa MIX_SetTrackStereo + */ +typedef struct MIX_StereoGains +{ + float left; /**< left channel gain */ + float right; /**< right channel gain */ +} MIX_StereoGains; + +/** + * Force a track to stereo output, with optionally left/right panning. + * + * This will cause the output of the track to convert to stereo, and then mix + * it only onto the Front Left and Front Right speakers, regardless of the + * speaker configuration. The left and right channels are modulated by + * `gains`, which can be used to produce panning effects. This function may be + * called to adjust the gains at any time. + * + * If `gains` is not NULL, this track will be switched into forced-stereo + * mode. If `gains` is NULL, this will disable spatialization (both the + * forced-stereo mode of this function and full 3D spatialization of + * MIX_SetTrack3DPosition()). + * + * Negative gains are clamped to zero; there is no clamp for maximum, so one + * could set the value > 1.0f to make a channel louder. + * + * The track's 3D position, reported by MIX_GetTrack3DPosition(), will be + * reset to (0, 0, 0). + * + * \param track the track to adjust. + * \param gains the per-channel gains, or NULL to disable spatialization. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_SetTrack3DPosition + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetTrackStereo(MIX_Track *track, const MIX_StereoGains *gains); + + +/** + * 3D coordinates for MIX_SetTrack3DPosition. + * + * The coordinates use a "right-handed" coordinate system, like OpenGL and + * OpenAL. + * + * \since This struct is available since SDL_mixer 3.0.0. + * + * \sa MIX_SetTrack3DPosition + */ +typedef struct MIX_Point3D +{ + float x; /**< X coordinate (negative left, positive right). */ + float y; /**< Y coordinate (negative down, positive up). */ + float z; /**< Z coordinate (negative forward, positive back). */ +} MIX_Point3D; + +/** + * Set a track's position in 3D space. + * + * (Please note that SDL_mixer is not intended to be a extremely powerful 3D + * API. It lacks 3D features that other APIs like OpenAL offer: there's no + * doppler effect, distance models, rolloff, etc. This is meant to be Good + * Enough for games that can use some positional sounds and can even take + * advantage of surround-sound configurations.) + * + * If `position` is not NULL, this track will be switched into 3D positional + * mode. If `position` is NULL, this will disable positional mixing (both the + * full 3D spatialization of this function and forced-stereo mode of + * MIX_SetTrackStereo()). + * + * In 3D positional mode, SDL_mixer will mix this track as if it were + * positioned in 3D space, including distance attenuation (quieter as it gets + * further from the listener) and spatialization (positioned on the correct + * speakers to suggest direction, either with stereo outputs or full surround + * sound). + * + * For a mono speaker output, spatialization is effectively disabled but + * distance attenuation will still work, which is all you can really do with a + * single speaker. + * + * The coordinate system operates like OpenGL or OpenAL: a "right-handed" + * coordinate system. See MIX_Point3D for the details. + * + * The listener is always at coordinate (0,0,0) and can't be changed. + * + * The track's input will be converted to mono (1 channel) so it can be + * rendered across the correct speakers. + * + * \param track the track for which to set 3D position. + * \param position the new 3D position for the track. May be NULL. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_GetTrack3DPosition + * \sa MIX_SetTrackStereo + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetTrack3DPosition(MIX_Track *track, const MIX_Point3D *position); + +/** + * Get a track's current position in 3D space. + * + * If 3D positioning isn't enabled for this track, through a call to + * MIX_SetTrack3DPosition(), this will return (0,0,0). + * + * \param track the track to query. + * \param position on successful return, will contain the track's position. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_SetTrack3DPosition + */ +extern SDL_DECLSPEC bool SDLCALL MIX_GetTrack3DPosition(MIX_Track *track, MIX_Point3D *position); + + +/* Mix groups... */ + +/** + * Create a mixing group. + * + * Tracks are assigned to a mixing group (or if unassigned, they live in a + * mixer's internal default group). All tracks in a group are mixed together + * and the app can access this mixed data before it is mixed with all other + * groups to produce the final output. + * + * This can be a useful feature, but is completely optional; apps can ignore + * mixing groups entirely and still have a full experience with SDL_mixer. + * + * After creating a group, assign tracks to it with MIX_SetTrackGroup(). Use + * MIX_SetGroupPostMixCallback() to access the group's mixed data. + * + * A mixing group can be destroyed with MIX_DestroyGroup() when no longer + * needed. Destroying the mixer will also destroy all its still-existing + * mixing groups. + * + * \param mixer the mixer on which to create a mixing group. + * \returns a newly-created mixing group, or NULL on error; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_DestroyGroup + * \sa MIX_SetTrackGroup + * \sa MIX_SetGroupPostMixCallback + */ +extern SDL_DECLSPEC MIX_Group * SDLCALL MIX_CreateGroup(MIX_Mixer *mixer); + +/** + * Destroy a mixing group. + * + * Any tracks currently assigned to this group will be reassigned to the + * mixer's internal default group. + * + * \param group the mixing group to destroy. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_CreateGroup + */ +extern SDL_DECLSPEC void SDLCALL MIX_DestroyGroup(MIX_Group *group); + +/** + * Get the properties associated with a group. + * + * Currently SDL_mixer assigns no properties of its own to a group, but this + * can be a convenient place to store app-specific data. + * + * A SDL_PropertiesID is created the first time this function is called for a + * given group. + * + * \param group the group to query. + * \returns a valid property ID on success or 0 on failure; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC SDL_PropertiesID SDLCALL MIX_GetGroupProperties(MIX_Group *group); + +/** + * Get the MIX_Mixer that owns a MIX_Group. + * + * This is the mixer pointer that was passed to MIX_CreateGroup(). + * + * \param group the group to query. + * \returns the mixer associated with the group, or NULL on error; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC MIX_Mixer * SDLCALL MIX_GetGroupMixer(MIX_Group *group); + +/** + * Assign a track to a mixing group. + * + * All tracks in a group are mixed together, and that output is made available + * to the app before it is mixed into the final output. + * + * Tracks can only be in one group at a time, and the track and group must + * have been created on the same MIX_Mixer. + * + * Setting a track to a NULL group will remove it from any app-created groups, + * and reassign it to the mixer's internal default group. + * + * \param track the track to set mixing group assignment. + * \param group the new mixing group to assign to. May be NULL. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_CreateGroup + * \sa MIX_SetGroupPostMixCallback + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetTrackGroup(MIX_Track *track, MIX_Group *group); + + + +/* Hooks... */ + +/** + * A callback that fires when a MIX_Track is stopped. + * + * This callback is fired when a track completes playback, either because it + * ran out of data to mix (and all loops were completed as well), or it was + * explicitly stopped by the app. Pausing a track will not fire this callback. + * + * It is legal to adjust the track, including changing its input and + * restarting it. If this is done because it ran out of data in the middle of + * mixing, the mixer will start mixing the new track state in its current run + * without any gap in the audio. + * + * This callback will not fire when a playing track is destroyed. + * + * \param userdata an opaque pointer provided by the app for its personal use. + * \param track the track that has stopped. + * + * \since This datatype is available since SDL_mixer 3.0.0. + * + * \sa MIX_SetTrackStoppedCallback + */ +typedef void (SDLCALL *MIX_TrackStoppedCallback)(void *userdata, MIX_Track *track); + +/** + * Set a callback that fires when a MIX_Track is stopped. + * + * When a track completes playback, either because it ran out of data to mix + * (and all loops were completed as well), or it was explicitly stopped by the + * app, it will fire the callback specified here. + * + * Each track has its own unique callback. + * + * Passing a NULL callback here is legal; it disables this track's callback. + * + * Pausing a track will not fire the callback, nor will the callback fire on a + * playing track that is being destroyed. + * + * It is legal to adjust the track, including changing its input and + * restarting it. If this is done because it ran out of data in the middle of + * mixing, the mixer will start mixing the new track state in its current run + * without any gap in the audio. + * + * \param track the track to assign this callback to. + * \param cb the function to call when the track stops. May be NULL. + * \param userdata an opaque pointer provided to the callback for its own + * personal use. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_TrackStoppedCallback + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetTrackStoppedCallback(MIX_Track *track, MIX_TrackStoppedCallback cb, void *userdata); + +/** + * A callback that fires when a MIX_Track is mixing at various stages. + * + * This callback is fired for different parts of the mixing pipeline, and + * gives the app visbility into the audio data that is being generated at + * various stages. + * + * The audio data passed through here is _not_ const data; the app is + * permitted to change it in any way it likes, and those changes will + * propagate through the mixing pipeline. + * + * An audiospec is provided. Different tracks might be in different formats, + * and an app needs to be able to handle that, but SDL_mixer always does its + * mixing work in 32-bit float samples, even if the inputs or final output are + * not floating point. As such, `spec->format` will always be `SDL_AUDIO_F32` + * and `pcm` hardcoded to be a float pointer. + * + * `samples` is the number of float values pointed to by `pcm`: samples, not + * sample frames! There are no promises how many samples will be provided + * per-callback, and this number can vary wildly from call to call, depending + * on many factors. + * + * Making changes to the track during this callback is undefined behavior. + * Change the data in `pcm` but not the track itself. + * + * \param userdata an opaque pointer provided by the app for its personal use. + * \param track the track that is being mixed. + * \param spec the format of the data in `pcm`. + * \param pcm the raw PCM data in float32 format. + * \param samples the number of float values pointed to by `pcm`. + * + * \since This datatype is available since SDL_mixer 3.0.0. + * + * \sa MIX_SetTrackRawCallback + * \sa MIX_SetTrackCookedCallback + */ +typedef void (SDLCALL *MIX_TrackMixCallback)(void *userdata, MIX_Track *track, const SDL_AudioSpec *spec, float *pcm, int samples); + +/** + * Set a callback that fires when a MIX_Track has initial decoded audio. + * + * As a track needs to mix more data, it pulls from its input (a MIX_Audio, an + * SDL_AudioStream, etc). This input might be a compressed file format, like + * MP3, so a little more data is uncompressed from it. + * + * Once the track has PCM data to start operating on, it can fire a callback + * before _any_ changes to the raw PCM input have happened. This lets an app + * view the data before it has gone through transformations such as gain, 3D + * positioning, fading, etc. It can also change the data in any way it pleases + * during this callback, and the mixer will continue as if this data came + * directly from the input. + * + * Each track has its own unique raw callback. + * + * Passing a NULL callback here is legal; it disables this track's callback. + * + * \param track the track to assign this callback to. + * \param cb the function to call when the track mixes. May be NULL. + * \param userdata an opaque pointer provided to the callback for its own + * personal use. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_TrackMixCallback + * \sa MIX_SetTrackCookedCallback + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetTrackRawCallback(MIX_Track *track, MIX_TrackMixCallback cb, void *userdata); + +/** + * Set a callback that fires when the mixer has transformed a track's audio. + * + * As a track needs to mix more data, it pulls from its input (a MIX_Audio, an + * SDL_AudioStream, etc). This input might be a compressed file format, like + * MP3, so a little more data is uncompressed from it. + * + * Once the track has PCM data to start operating on, and its raw callback has + * completed, it will begin to transform the audio: gain, fading, frequency + * ratio, 3D positioning, etc. + * + * A callback can be fired after all these transformations, but before the + * transformed data is mixed into other tracks. This lets an app view the data + * at the last moment that it is still a part of this track. It can also + * change the data in any way it pleases during this callback, and the mixer + * will continue as if this data came directly from the input. + * + * Each track has its own unique cooked callback. + * + * Passing a NULL callback here is legal; it disables this track's callback. + * + * \param track the track to assign this callback to. + * \param cb the function to call when the track mixes. May be NULL. + * \param userdata an opaque pointer provided to the callback for its own + * personal use. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_TrackMixCallback + * \sa MIX_SetTrackRawCallback + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetTrackCookedCallback(MIX_Track *track, MIX_TrackMixCallback cb, void *userdata); + +/** + * A callback that fires when a MIX_Group has completed mixing. + * + * This callback is fired when a mixing group has finished mixing: all tracks + * in the group have mixed into a single buffer and are prepared to be mixed + * into all other groups for the final mix output. + * + * The audio data passed through here is _not_ const data; the app is + * permitted to change it in any way it likes, and those changes will + * propagate through the mixing pipeline. + * + * An audiospec is provided. Different groups might be in different formats, + * and an app needs to be able to handle that, but SDL_mixer always does its + * mixing work in 32-bit float samples, even if the inputs or final output are + * not floating point. As such, `spec->format` will always be `SDL_AUDIO_F32` + * and `pcm` hardcoded to be a float pointer. + * + * `samples` is the number of float values pointed to by `pcm`: samples, not + * sample frames! There are no promises how many samples will be provided + * per-callback, and this number can vary wildly from call to call, depending + * on many factors. + * + * \param userdata an opaque pointer provided by the app for its personal use. + * \param group the group that is being mixed. + * \param spec the format of the data in `pcm`. + * \param pcm the raw PCM data in float32 format. + * \param samples the number of float values pointed to by `pcm`. + * + * \since This datatype is available since SDL_mixer 3.0.0. + * + * \sa MIX_SetGroupPostMixCallback + */ +typedef void (SDLCALL *MIX_GroupMixCallback)(void *userdata, MIX_Group *group, const SDL_AudioSpec *spec, float *pcm, int samples); + +/** + * Set a callback that fires when a mixer group has completed mixing. + * + * After all playing tracks in a mixer group have pulled in more data from + * their inputs, transformed it, and mixed together into a single buffer, a + * callback can be fired. This lets an app view the data at the last moment + * that it is still a part of this group. It can also change the data in any + * way it pleases during this callback, and the mixer will continue as if this + * data came directly from the group's mix buffer. + * + * Each group has its own unique callback. Tracks that aren't in an explicit + * MIX_Group are mixed in an internal grouping that is not available to the + * app. + * + * Passing a NULL callback here is legal; it disables this group's callback. + * + * \param group the mixing group to assign this callback to. + * \param cb the function to call when the group mixes. May be NULL. + * \param userdata an opaque pointer provided to the callback for its own + * personal use. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_GroupMixCallback + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetGroupPostMixCallback(MIX_Group *group, MIX_GroupMixCallback cb, void *userdata); + +/** + * A callback that fires when all mixing has completed. + * + * This callback is fired when the mixer has completed all its work. If this + * mixer was created with MIX_CreateMixerDevice(), the data provided by this + * callback is what is being sent to the audio hardware, minus last + * conversions for format requirements. If this mixer was created with + * MIX_CreateMixer(), this is what is being output from MIX_Generate(), after + * final conversions. + * + * The audio data passed through here is _not_ const data; the app is + * permitted to change it in any way it likes, and those changes will replace + * the final mixer pipeline output. + * + * An audiospec is provided. SDL_mixer always does its mixing work in 32-bit + * float samples, even if the inputs or final output are not floating point. + * As such, `spec->format` will always be `SDL_AUDIO_F32` and `pcm` hardcoded + * to be a float pointer. + * + * `samples` is the number of float values pointed to by `pcm`: samples, not + * sample frames! There are no promises how many samples will be provided + * per-callback, and this number can vary wildly from call to call, depending + * on many factors. + * + * \param userdata an opaque pointer provided by the app for its personal use. + * \param mixer the mixer that is generating audio. + * \param spec the format of the data in `pcm`. + * \param pcm the raw PCM data in float32 format. + * \param samples the number of float values pointed to by `pcm`. + * + * \since This datatype is available since SDL_mixer 3.0.0. + * + * \sa MIX_SetPostMixCallback + */ +typedef void (SDLCALL *MIX_PostMixCallback)(void *userdata, MIX_Mixer *mixer, const SDL_AudioSpec *spec, float *pcm, int samples); + +/** + * Set a callback that fires when all mixing has completed. + * + * After all mixer groups have processed, their buffers are mixed together + * into a single buffer for the final output, at which point a callback can be + * fired. This lets an app view the data at the last moment before mixing + * completes. It can also change the data in any way it pleases during this + * callback, and the mixer will continue as if this data is the final output. + * + * Each mixer has its own unique callback. + * + * Passing a NULL callback here is legal; it disables this mixer's callback. + * + * \param mixer the mixer to assign this callback to. + * \param cb the function to call when the mixer mixes. May be NULL. + * \param userdata an opaque pointer provided to the callback for its own + * personal use. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_PostMixCallback + */ +extern SDL_DECLSPEC bool SDLCALL MIX_SetPostMixCallback(MIX_Mixer *mixer, MIX_PostMixCallback cb, void *userdata); + + +/* Audio generation without an audio device... */ + +/** + * Generate mixer output when not driving an audio device. + * + * SDL_mixer allows the creation of MIX_Mixer objects that are not connected + * to an audio device, by calling MIX_CreateMixer() instead of + * MIX_CreateMixerDevice(). Such mixers will not generate output until + * explicitly requested through this function. + * + * The caller may request as much audio as desired, so long as `buflen` is a + * multiple of the sample frame size specified when creating the mixer (for + * example, if requesting stereo Sint16 audio, buflen must be a multiple of 4: + * 2 bytes-per-channel times 2 channels). + * + * The mixer will mix as quickly as possible; since it works in sample frames + * instead of time, it can potentially generate enormous amounts of audio in a + * small amount of time. + * + * On success, this always fills `buffer` with `buflen` bytes of audio; if all + * playing tracks finish mixing, it will fill the remaining buffer with + * silence. + * + * Each call to this function will pick up where it left off, playing tracks + * will continue to mix from the point the previous call completed, etc. The + * mixer state can be changed between each call in any way desired: tracks can + * be added, played, stopped, changed, removed, etc. Effectively this function + * does the same thing SDL_mixer does internally when the audio device needs + * more audio to play. + * + * This function can not be used with mixers from MIX_CreateMixerDevice(); + * those generate audio as needed internally. + * + * This function returns the number of _bytes_ of real audio mixed, which + * might be less than `buflen`. While all `buflen` bytes of `buffer` will be + * initialized, if available tracks to mix run out, the end of the buffer will + * be initialized with silence; this silence will not be counted in the return + * value, so the caller has the option to identify how much of the buffer has + * legimitate contents vs appended silence. As such, any value >= 0 signifies + * success. A return value of -1 means failure (out of memory, invalid + * parameters, etc). + * + * \param mixer the mixer for which to generate more audio. + * \param buffer a pointer to a buffer to store audio in. + * \param buflen the number of bytes to store in buffer. + * \returns The number of bytes of mixed audio, discounting appended silence, + * on success, or -1 on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_CreateMixer + */ +extern SDL_DECLSPEC int SDLCALL MIX_Generate(MIX_Mixer *mixer, void *buffer, int buflen); + + +/* Decode audio files directly without a mixer ... */ + +/** + * An opaque object that represents an audio decoder. + * + * Most apps won't need this, as SDL_mixer's usual interfaces will decode + * audio as needed. However, if one wants to decode an audio file into a + * memory buffer without playing it, this interface offers that. + * + * These objects are created with MIX_CreateAudioDecoder() or + * MIX_CreateAudioDecoder_IO(), and then can use MIX_DecodeAudio() to retrieve + * the raw PCM data. + * + * \since This struct is available since SDL_mixer 3.0.0. + */ +typedef struct MIX_AudioDecoder MIX_AudioDecoder; + +/** + * Create a MIX_AudioDecoder from a path on the filesystem. + * + * Most apps won't need this, as SDL_mixer's usual interfaces will decode + * audio as needed. However, if one wants to decode an audio file into a + * memory buffer without playing it, this interface offers that. + * + * This function allows properties to be specified. This is intended to supply + * file-specific settings, such as where to find SoundFonts for a MIDI file, + * etc. In most cases, the caller should pass a zero to specify no extra + * properties. + * + * SDL_PropertiesID are discussed in + * [SDL's documentation](https://wiki.libsdl.org/SDL3/CategoryProperties) + * . + * + * When done with the audio decoder, it can be destroyed with + * MIX_DestroyAudioDecoder(). + * + * This function requires SDL_mixer to have been initialized with a successful + * call to MIX_Init(), but does not need an actual MIX_Mixer to have been + * created. + * + * \param path the path on the filesystem from which to load data. + * \param props decoder-specific properties. May be zero. + * \returns an audio decoder, ready to decode. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_CreateAudioDecoder_IO + * \sa MIX_DecodeAudio + * \sa MIX_DestroyAudioDecoder + */ +extern SDL_DECLSPEC MIX_AudioDecoder * SDLCALL MIX_CreateAudioDecoder(const char *path, SDL_PropertiesID props); + +/** + * Create a MIX_AudioDecoder from an SDL_IOStream. + * + * Most apps won't need this, as SDL_mixer's usual interfaces will decode + * audio as needed. However, if one wants to decode an audio file into a + * memory buffer without playing it, this interface offers that. + * + * This function allows properties to be specified. This is intended to supply + * file-specific settings, such as where to find SoundFonts for a MIDI file, + * etc. In most cases, the caller should pass a zero to specify no extra + * properties. + * + * If `closeio` is true, then `io` will be closed when this decoder is done + * with it. If this function fails and `closeio` is true, then `io` will be + * closed before this function returns. + * + * When done with the audio decoder, it can be destroyed with + * MIX_DestroyAudioDecoder(). + * + * This function requires SDL_mixer to have been initialized with a successful + * call to MIX_Init(), but does not need an actual MIX_Mixer to have been + * created. + * + * \param io the i/o stream from which to load data. + * \param closeio if true, close the i/o stream when done with it. + * \param props decoder-specific properties. May be zero. + * \returns an audio decoder, ready to decode. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_CreateAudioDecoder_IO + * \sa MIX_DecodeAudio + * \sa MIX_DestroyAudioDecoder + */ +extern SDL_DECLSPEC MIX_AudioDecoder * SDLCALL MIX_CreateAudioDecoder_IO(SDL_IOStream *io, bool closeio, SDL_PropertiesID props); + +/** + * Destroy the specified audio decoder. + * + * Destroying a NULL MIX_AudioDecoder is a legal no-op. + * + * \param audiodecoder the audio to destroy. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC void SDLCALL MIX_DestroyAudioDecoder(MIX_AudioDecoder *audiodecoder); + +/** + * Get the properties associated with a MIX_AudioDecoder. + * + * SDL_mixer offers some properties of its own, but this can also be a + * convenient place to store app-specific data. + * + * A SDL_PropertiesID is created the first time this function is called for a + * given MIX_AudioDecoder, if necessary. + * + * The file-specific metadata exposed through this function is identical to + * those available through MIX_GetAudioProperties(). Please refer to that + * function's documentation for details. + * + * \param audiodecoder the audio decoder to query. + * \returns a valid property ID on success or 0 on failure; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + * + * \sa MIX_GetAudioProperties + */ +extern SDL_DECLSPEC SDL_PropertiesID SDLCALL MIX_GetAudioDecoderProperties(MIX_AudioDecoder *audiodecoder); + +/** + * Query the initial audio format of a MIX_AudioDecoder. + * + * Note that some audio files can change format in the middle; some explicitly + * support this, but a more common example is two MP3 files concatenated + * together. In many cases, SDL_mixer will correctly handle these sort of + * files, but this function will only report the initial format a file uses. + * + * \param audiodecoder the audio decoder to query. + * \param spec on success, audio format details will be stored here. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL MIX_GetAudioDecoderFormat(MIX_AudioDecoder *audiodecoder, SDL_AudioSpec *spec); + +/** + * Decode more audio from a MIX_AudioDecoder. + * + * Data is decoded on demand in whatever format is requested. The format is + * permitted to change between calls. + * + * This function will return the number of bytes decoded, which may be less + * than requested if there was an error or end-of-file. A return value of zero + * means the entire file was decoded, -1 means an unrecoverable error + * happened. + * + * \param audiodecoder the decoder from which to retrieve more data. + * \param buffer the memory buffer to store decoded audio. + * \param buflen the maximum number of bytes to store to `buffer`. + * \param spec the format that audio data will be stored to `buffer`. + * \returns number of bytes decoded, or -1 on error; call SDL_GetError() for + * more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_mixer 3.0.0. + */ +extern SDL_DECLSPEC int SDLCALL MIX_DecodeAudio(MIX_AudioDecoder *audiodecoder, void *buffer, int buflen, const SDL_AudioSpec *spec); + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif +#include + +#endif /* SDL_MIXER_H_ */ diff --git a/vendor/sdl3/mixer/libgme.dll b/vendor/sdl3/mixer/libgme.dll new file mode 100644 index 000000000..6d1ef9ca7 --- /dev/null +++ b/vendor/sdl3/mixer/libgme.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50b739c925702d381e163e66887699eb980e03681577d8d7a19cd9972a315dea +size 445440 diff --git a/vendor/sdl3/mixer/libogg-0.dll b/vendor/sdl3/mixer/libogg-0.dll new file mode 100644 index 000000000..d2de59965 --- /dev/null +++ b/vendor/sdl3/mixer/libogg-0.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:76344182f53695db65fca5921ab4e478cdf2f954d86628b27dab0fb9327bf2e7 +size 32768 diff --git a/vendor/sdl3/mixer/libopus-0.dll b/vendor/sdl3/mixer/libopus-0.dll new file mode 100644 index 000000000..3f7865d5d --- /dev/null +++ b/vendor/sdl3/mixer/libopus-0.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:064aaa2aee76ac93df0f9ec78a670a49954e3f4ac1bc1fd70ebda2f035ccc073 +size 367616 diff --git a/vendor/sdl3/mixer/libopusfile-0.dll b/vendor/sdl3/mixer/libopusfile-0.dll new file mode 100644 index 000000000..c664cf7f4 --- /dev/null +++ b/vendor/sdl3/mixer/libopusfile-0.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e2e7edcdfb87f12763508b0234e2f945b6e8a3706bda740911e0d1a8ef24c758 +size 48640 diff --git a/vendor/sdl3/mixer/libwavpack-1.dll b/vendor/sdl3/mixer/libwavpack-1.dll new file mode 100644 index 000000000..2278390c9 --- /dev/null +++ b/vendor/sdl3/mixer/libwavpack-1.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e07f0623d14cbf19f6f3ee75ed6f45191088033e7167877a8ccbb41f1589f1a1 +size 178688 diff --git a/vendor/sdl3/mixer/libxmp.dll b/vendor/sdl3/mixer/libxmp.dll new file mode 100644 index 000000000..5923fd353 --- /dev/null +++ b/vendor/sdl3/mixer/libxmp.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7a5f1198d976d7ea5aeb8433905c47a71906c2c9b0733166d88ec4a4525e0dee +size 417792 diff --git a/vendor/sdl3/mixer/sdl3_mixer.odin b/vendor/sdl3/mixer/sdl3_mixer.odin new file mode 100644 index 000000000..36e5ecd1e --- /dev/null +++ b/vendor/sdl3/mixer/sdl3_mixer.odin @@ -0,0 +1,168 @@ +package sdl3_mixer + +import "core:c" + +import SDL "vendor:sdl3" + +when ODIN_OS == .Windows { + foreign import lib "SDL3_mixer.lib" +} else { + foreign import lib "system:SDL3_mixer" +} + +Mixer :: struct {} +Audio :: struct {} +Track :: struct {} +Group :: struct {} + +StereoGains :: struct { + left, right: c.float, +} +Point3D :: struct { + x, y, z: c.float, +} + +TrackStoppedCallback :: #type proc(userdata: rawptr, track: ^Track) +TrackMixCallback :: #type proc(userdata: rawptr, track: ^Track, spec: ^SDL.AudioSpec, pcm: ^c.float, samples: c.int) +GroupMixCallback :: #type proc(userdata: rawptr, group: ^Group, spec: ^SDL.AudioSpec, pcm: ^c.float, samples: c.int) +PostMixCallback :: #type proc( userdata: rawptr, mixer: ^Mixer, spec: ^SDL.AudioSpec, pcm: ^c.float, samples: c.int) + +AudioDecoder :: struct {} + +MAJOR_VERSION :: 3 +MINOR_VERSION :: 2 +MICRO_VERSION :: 0 + +PROP_MIXER_DEVICE_NUMBER :: "SDL_mixer.mixer.device" + +PROP_AUDIO_LOAD_IOSTREAM_POINTER :: "SDL_mixer.audio.load.iostream" +PROP_AUDIO_LOAD_CLOSEIO_BOOLEAN :: "SDL_mixer.audio.load.closeio" +PROP_AUDIO_LOAD_PREDECODE_BOOLEAN :: "SDL_mixer.audio.load.predecode" +PROP_AUDIO_LOAD_PREFERRED_MIXER_POINTER :: "SDL_mixer.audio.load.preferred_mixer" +PROP_AUDIO_LOAD_SKIP_METADATA_TAGS_BOOLEAN :: "SDL_mixer.audio.load.skip_metadata_tags" +PROP_AUDIO_DECODER_STRING :: "SDL_mixer.audio.decoder" + +PROP_METADATA_TITLE_STRING :: "SDL_mixer.metadata.title" +PROP_METADATA_ARTIST_STRING :: "SDL_mixer.metadata.artist" +PROP_METADATA_ALBUM_STRING :: "SDL_mixer.metadata.album" +PROP_METADATA_COPYRIGHT_STRING :: "SDL_mixer.metadata.copyright" +PROP_METADATA_TRACK_NUMBER :: "SDL_mixer.metadata.track" +PROP_METADATA_TOTAL_TRACKS_NUMBER :: "SDL_mixer.metadata.total_tracks" +PROP_METADATA_YEAR_NUMBER :: "SDL_mixer.metadata.year" +PROP_METADATA_DURATION_FRAMES_NUMBER :: "SDL_mixer.metadata.duration_frames" +PROP_METADATA_DURATION_INFINITE_BOOLEAN :: "SDL_mixer.metadata.duration_infinite" + +PROP_PLAY_LOOPS_NUMBER :: "SDL_mixer.play.loops" +PROP_PLAY_MAX_FRAME_NUMBER :: "SDL_mixer.play.max_frame" +PROP_PLAY_MAX_MILLISECONDS_NUMBER :: "SDL_mixer.play.max_milliseconds" +PROP_PLAY_START_FRAME_NUMBER :: "SDL_mixer.play.start_frame" +PROP_PLAY_START_MILLISECOND_NUMBER :: "SDL_mixer.play.start_millisecond" +PROP_PLAY_LOOP_START_FRAME_NUMBER :: "SDL_mixer.play.loop_start_frame" +PROP_PLAY_LOOP_START_MILLISECOND_NUMBER :: "SDL_mixer.play.loop_start_millisecond" +PROP_PLAY_FADE_IN_FRAMES_NUMBER :: "SDL_mixer.play.fade_in_frames" +PROP_PLAY_FADE_IN_MILLISECONDS_NUMBER :: "SDL_mixer.play.fade_in_milliseconds" +PROP_PLAY_FADE_IN_START_GAIN_FLOAT :: "SDL_mixer.play.fade_in_start_gain" +PROP_PLAY_APPEND_SILENCE_FRAMES_NUMBER :: "SDL_mixer.play.append_silence_frames" +PROP_PLAY_APPEND_SILENCE_MILLISECONDS_NUMBER :: "SDL_mixer.play.append_silence_milliseconds" +PROP_PLAY_HALT_WHEN_EXHAUSTED_BOOLEAN :: "SDL_mixer.play.halt_when_exhausted" + +DURATION_UNKNOWN :: -1 +DURATION_INFINITE :: -2 + +@(default_calling_convention = "c", link_prefix = "MIX_", require_results) +foreign lib { + Version :: proc() -> c.int --- + Init :: proc() -> c.bool --- + Quit :: proc() --- + GetNumAudioDecoders :: proc() -> c.int --- + GetAudioDecoder :: proc(index: c.int) -> cstring --- + CreateMixerDevice :: proc(devid: SDL.AudioDeviceID, #by_ptr spec: SDL.AudioSpec) -> ^Mixer --- + CreateMixer :: proc(#by_ptr spec: SDL.AudioSpec) -> ^Mixer --- + DestroyMixer :: proc(mixer: ^Mixer) --- + GetMixerProperties :: proc(mixer: ^Mixer) -> SDL.PropertiesID --- + GetMixerFormat :: proc(mixer: ^Mixer, spec: ^SDL.AudioSpec) -> c.bool --- + LockMixer :: proc(mixer: ^Mixer) --- + UnlockMixer :: proc(mixer: ^Mixer) --- + LoadAudio_IO :: proc(mixer: ^Mixer, io: ^SDL.IOStream, predecode, closeio: c.bool) -> ^Audio --- + LoadAudio :: proc(mixer: ^Mixer, path: cstring, predecode: c.bool) -> ^Audio --- + LoadAudioNoCopy :: proc(mixer: ^Mixer, data: rawptr, datalen: c.size_t, free_when_done: c.bool) -> ^Audio --- + LoadAudioWithProperties :: proc(props: SDL.PropertiesID) -> ^Audio --- + LoadRawAudio_IO :: proc(mixer: ^Mixer, io: ^SDL.IOStream, #by_ptr spec: SDL.AudioSpec, closeio: c.bool) -> ^Audio --- + LoadRawAudio :: proc(mixer: ^Mixer, data: rawptr, datalen: c.size_t, #by_ptr spec: SDL.AudioSpec) -> ^Audio --- + LoadRawAudioNoCopy :: proc(mixer: ^Mixer, data: rawptr, datalen: c.size_t, #by_ptr spec: SDL.AudioSpec, free_when_done: c.bool) -> ^Audio --- + CreateSineWaveAudio :: proc(mixer: ^Mixer, hz: c.int, amplitude: c.float, ms: SDL.Sint64) -> ^Audio --- + GetAudioProperties :: proc(audio: ^Audio) -> SDL.PropertiesID --- + GetAudioDuration :: proc(audio: ^Audio) -> SDL.Sint64 --- + GetAudioFormat :: proc(audio: ^Audio, spec: ^SDL.AudioSpec) -> c.bool --- + DestroyAudio :: proc(audio: ^Audio) --- + CreateTrack :: proc(mixer: ^Mixer) -> ^Track --- + DestroyTrack :: proc(track: ^Track) --- + GetTrackProperties :: proc(track: ^Track) -> SDL.PropertiesID --- + GetTrackMixer :: proc(track: ^Track) -> ^Mixer --- + SetTrackAudio :: proc(track: ^Track, audio: ^Audio) -> c.bool --- + SetTrackAudioStream :: proc(track: ^Track, stream: ^SDL.AudioStream) -> c.bool --- + SetTrackIOStream :: proc(track: ^Track, io: ^SDL.IOStream, closeio: c.bool) -> c.bool --- + SetTrackRawIOStream :: proc(track: ^Track, io: ^SDL.IOStream, #by_ptr spec: SDL.AudioSpec, closeio: c.bool) -> c.bool --- + TagTrack :: proc(track: ^Track, tag: cstring) -> c.bool --- + UntagTrack :: proc(track: ^Track, tag: cstring) --- + GetTrackTags :: proc(track: ^Track, count: ^c.int) -> [^]cstring --- + GetTaggedTracks :: proc(mixer: ^Mixer, tag: cstring, count: ^c.int) -> [^]^Track --- + SetTrackPlaybackPosition :: proc(track: ^Track, frames: SDL.Sint64) -> c.bool --- + GetTrackPlaybackPosition :: proc(track: ^Track) -> SDL.Sint64 --- + GetTrackFadeFrames :: proc(track: ^Track) -> SDL.Sint64 --- + GetTrackLoops :: proc(track: ^Track) -> c.int --- + SetTrackLoops :: proc(track: ^Track, num_loops: c.int) -> c.bool --- + GetTrackAudio :: proc(track: ^Track) -> ^Audio --- + GetTrackAudioStream :: proc(track: ^Track) -> ^SDL.AudioStream --- + GetTrackRemaining :: proc(track: ^Track) -> SDL.Sint64 --- + TrackMSToFrames :: proc(track: ^Track, ms: SDL.Sint64) -> SDL.Sint64 --- + TrackFramesToMS :: proc(track: ^Track, frames: SDL.Sint64) -> SDL.Sint64 --- + AudioMSToFrames :: proc(audio: ^Audio, ms: SDL.Sint64) -> SDL.Sint64 --- + AudioFramesToMS :: proc(audio: ^Audio, frames: SDL.Sint64) -> SDL.Sint64 --- + MSToFrames :: proc(sample_rate: c.int, ms: SDL.Sint64) -> SDL.Sint64 --- + FramesToMS :: proc(sample_rate: c.int, frames: SDL.Sint64) -> SDL.Sint64 --- + PlayTrack :: proc(track: ^Track, options: SDL.PropertiesID) -> c.bool --- + PlayTag :: proc(mixer: ^Mixer, tag: cstring, options: SDL.PropertiesID) -> c.bool --- + PlayAudio :: proc(mixer: ^Mixer, audio: ^Audio) -> c.bool --- + StopTrack :: proc(track: ^Track, fade_out_frames: SDL.Sint64) -> c.bool --- + StopAllTracks :: proc(mixer: ^Mixer, fade_out_ms: SDL.Sint64) -> c.bool --- + StopTag :: proc(mixer: ^Mixer, tag: cstring, fade_out_ms: SDL.Sint64) -> c.bool --- + PauseTrack :: proc(track: ^Track) -> c.bool --- + PauseAllTracks :: proc(mixer: ^Mixer) -> c.bool --- + PauseTag :: proc(mixer: ^Mixer, tag: cstring) -> c.bool --- + ResumeTrack :: proc(track: ^Track) -> c.bool --- + ResumeAllTracks :: proc(mixer: ^Mixer) -> c.bool --- + ResumeTag :: proc(mixer: ^Mixer, tag: cstring) -> c.bool --- + TrackPlaying :: proc(track: ^Track) -> c.bool --- + TrackPaused :: proc(track: ^Track) -> c.bool --- + SetMixerGain :: proc(mixer: ^Mixer, gain: c.float) -> c.bool --- + GetMixerGain :: proc(mixer: ^Mixer) -> c.float --- + SetTrackGain :: proc(track: ^Track, gain: c.float) -> c.bool --- + GetTrackGain :: proc(track: ^Track) -> c.float --- + SetTagGain :: proc(mixer: ^Mixer, tag: cstring, gain: c.float) -> c.bool --- + SetMixerFrequencyRatio :: proc(mixer: ^Mixer, ratio: c.float) -> c.bool --- + GetMixerFrequencyRatio :: proc(mixer: ^Mixer) -> c.float --- + SetTrackFrequencyRatio :: proc(track: ^Track, ratio: c.float) -> c.bool --- + GetTrackFrequencyRatio :: proc(track: ^Track) -> c.float --- + SetTrackOutputChannelMap :: proc(track: ^Track, chmap: [^]c.int, count: c.int) -> c.bool --- + SetTrackStereo :: proc(track: ^Track, #by_ptr gains: StereoGains) -> c.bool --- + SetTrack3DPosition :: proc(track: ^Track, #by_ptr position: Point3D) -> c.bool --- + GetTrack3DPosition :: proc(track: ^Track, position: ^Point3D) -> c.bool --- + CreateGroup :: proc(mixer: ^Mixer) -> ^Group --- + DestroyGroup :: proc(group: ^Group) --- + GetGroupProperties :: proc(group: ^Group) -> SDL.PropertiesID --- + GetGroupMixer :: proc(group: ^Group) -> ^Mixer --- + SetTrackGroup :: proc(track: ^Track, group: ^Group) -> c.bool --- + SetTrackStoppedCallback :: proc(track: ^Track, cb: TrackStoppedCallback, userdata: rawptr) -> c.bool --- + SetTrackRawCallback :: proc(track: ^Track, cb: TrackMixCallback, userdata: rawptr) -> c.bool --- + SetTrackCookedCallback :: proc(track: ^Track, cb: TrackMixCallback, userdata: rawptr) -> c.bool --- + SetGroupPostMixCallback :: proc(group: ^Group, cb: GroupMixCallback, userdata: rawptr) -> c.bool --- + SetPostMixCallback :: proc(mixer: ^Mixer, cb: PostMixCallback, userdata: rawptr) -> c.bool --- + Generate :: proc(mixer: ^Mixer, buffer: rawptr, buflen: c.int) -> c.int --- + CreateAudioDecoder :: proc(path: cstring, props: SDL.PropertiesID) -> ^AudioDecoder --- + CreateAudioDecoder_IO :: proc(io: ^SDL.IOStream, closeio: c.bool, props: SDL.PropertiesID) -> ^AudioDecoder --- + DestroyAudioDecoder :: proc(audiodecoder: ^AudioDecoder) --- + GetAudioDecoderProperties :: proc(audiodecoder: ^AudioDecoder) -> SDL.PropertiesID --- + GetAudioDecoderFormat :: proc(audiodecoder: ^AudioDecoder, spec: ^SDL.AudioSpec) -> c.bool --- + DecodeAudio :: proc(audiodecoder: ^AudioDecoder, buffer: rawptr, buflen: c.int, #by_ptr spec: SDL.AudioSpec) -> c.int --- +} diff --git a/vendor/sdl3/sdl3_atomic.odin b/vendor/sdl3/sdl3_atomic.odin index 178a44a5b..fefe8c861 100644 --- a/vendor/sdl3/sdl3_atomic.odin +++ b/vendor/sdl3/sdl3_atomic.odin @@ -36,7 +36,8 @@ foreign lib { CompareAndSwapAtomicU32 :: proc(a: ^AtomicU32, oldval, newval: Uint32) -> bool --- SetAtomicU32 :: proc(a: ^AtomicU32, v: Uint32) -> Uint32 --- GetAtomicU32 :: proc(a: ^AtomicU32) -> Uint32 --- + AddAtomicU32 :: proc(a: ^AtomicU32) -> Uint32 --- CompareAndSwapAtomicPointer :: proc(a: ^rawptr, oldval, newval: rawptr) -> bool --- SetAtomicPointer :: proc(a: ^rawptr, v: rawptr) -> rawptr --- GetAtomicPointer :: proc(a: ^rawptr) -> rawptr --- -} \ No newline at end of file +} diff --git a/vendor/sdl3/sdl3_audio.odin b/vendor/sdl3/sdl3_audio.odin index 045f4780e..277aefde7 100644 --- a/vendor/sdl3/sdl3_audio.odin +++ b/vendor/sdl3/sdl3_audio.odin @@ -67,8 +67,11 @@ AUDIO_FRAMESIZE :: proc "c" (x: AudioSpec) -> c.int { AudioStream :: struct {} -AudioStreamCallback :: #type proc "c" (userdata: rawptr, stream: ^AudioStream, additional_amount, total_amount: c.int) -AudioPostmixCallback :: #type proc "c" (userdata: rawptr, spec: ^AudioSpec, buffer: [^]f32, buflen: c.int) +AudioStreamCallback :: #type proc "c" (userdata: rawptr, stream: ^AudioStream, additional_amount, total_amount: c.int) +AudioStreamDataCompleteCallback :: #type proc "c" (userdata: rawptr, buf: rawptr, buflen: c.int) +AudioPostmixCallback :: #type proc "c" (userdata: rawptr, spec: ^AudioSpec, buffer: [^]f32, buflen: c.int) + +AUDIOSTREAM_AUTO_CLEANUP_BOOLEAN :: "SDL.audiostream.auto_cleanup" @(default_calling_convention="c", link_prefix="SDL_") foreign lib { @@ -107,6 +110,8 @@ foreign lib { SetAudioStreamInputChannelMap :: proc(stream: ^AudioStream, chmap: [^]c.int, count: c.int) -> bool --- SetAudioStreamOutputChannelMap :: proc(stream: ^AudioStream, chmap: [^]c.int, count: c.int) -> bool --- PutAudioStreamData :: proc(stream: ^AudioStream, buf: rawptr, len: c.int) -> bool --- + PutAudioStreamDataNoCopy :: proc(stream: ^AudioStream, buf: rawptr, len: c.int, callback: AudioStreamDataCompleteCallback, userdata: rawptr) -> bool --- + PutAudioStreamPlanarData :: proc(stream: ^AudioStream, channel_buffers: [^]rawptr, num_channels, num_samples: c.int) -> bool --- GetAudioStreamData :: proc(stream: ^AudioStream, buf: rawptr, len: c.int) -> c.int --- GetAudioStreamAvailable :: proc(stream: ^AudioStream) -> c.int --- GetAudioStreamQueued :: proc(stream: ^AudioStream) -> c.int --- @@ -128,4 +133,4 @@ foreign lib { ConvertAudioSamples :: proc(src_spec: ^AudioSpec, src_data: [^]Uint8, src_len: c.int, dst_spec: ^AudioSpec, dst_data: ^[^]Uint8, dst_len: ^c.int) -> bool --- GetAudioFormatName :: proc(format: AudioFormat) -> cstring --- GetSilenceValueForFormat :: proc(format: AudioFormat) -> c.int --- -} \ No newline at end of file +} diff --git a/vendor/sdl3/sdl3_camera.odin b/vendor/sdl3/sdl3_camera.odin index 7d46bd2bd..a6a895245 100644 --- a/vendor/sdl3/sdl3_camera.odin +++ b/vendor/sdl3/sdl3_camera.odin @@ -21,6 +21,12 @@ CameraPosition :: enum c.int { BACK_FACING, } +CameraPermissionState :: enum c.int { + DENIED = -1, + PENDING, + APPROVED, +} + @(default_calling_convention="c", link_prefix="SDL_") foreign lib { GetNumCameraDrivers :: proc() -> c.int --- @@ -31,11 +37,11 @@ foreign lib { GetCameraName :: proc(instance_id: CameraID) -> cstring --- GetCameraPosition :: proc(instance_id: CameraID) -> CameraPosition --- OpenCamera :: proc(instance_id: CameraID, spec: ^CameraSpec) -> ^Camera --- - GetCameraPermissionState :: proc(camera: ^Camera) -> c.int --- + GetCameraPermissionState :: proc(camera: ^Camera) -> CameraPermissionState --- GetCameraID :: proc(camera: ^Camera) -> CameraID --- GetCameraProperties :: proc(camera: ^Camera) -> PropertiesID --- GetCameraFormat :: proc(camera: ^Camera, spec: ^CameraSpec) -> bool --- AcquireCameraFrame :: proc(camera: ^Camera, timestampNS: ^Uint64) -> ^Surface --- ReleaseCameraFrame :: proc(camera: ^Camera, frame: ^Surface) --- CloseCamera :: proc(camera: ^Camera) --- -} \ No newline at end of file +} diff --git a/vendor/sdl3/sdl3_cpuinfo.odin b/vendor/sdl3/sdl3_cpuinfo.odin index 959286c71..a97a5a324 100644 --- a/vendor/sdl3/sdl3_cpuinfo.odin +++ b/vendor/sdl3/sdl3_cpuinfo.odin @@ -24,4 +24,5 @@ foreign lib { HasLASX :: proc() -> bool --- GetSystemRAM :: proc() -> c.int --- GetSIMDAlignment :: proc() -> uint --- -} \ No newline at end of file + GetSystemPageSize :: proc() -> c.int --- +} diff --git a/vendor/sdl3/sdl3_events.odin b/vendor/sdl3/sdl3_events.odin index 3f64f85fa..7e871156e 100644 --- a/vendor/sdl3/sdl3_events.odin +++ b/vendor/sdl3/sdl3_events.odin @@ -46,9 +46,10 @@ EventType :: enum Uint32 { DISPLAY_MOVED, /**< Display has changed position */ DISPLAY_DESKTOP_MODE_CHANGED, /**< Display has changed desktop mode */ DISPLAY_CURRENT_MODE_CHANGED, /**< Display has changed current mode */ - DISPLAY_CONTENT_SCALE_CHANGED, /**< Display has changed content scale */ + DISPLAY_CONTENT_SCALE_CHANGED, /**< Display has changed usable bounds */ + DISPLAY_USABLE_BOUNDS_CHANGED, DISPLAY_FIRST = DISPLAY_ORIENTATION, - DISPLAY_LAST = DISPLAY_CONTENT_SCALE_CHANGED, + DISPLAY_LAST = DISPLAY_USABLE_BOUNDS_CHANGED, /* Window events */ /* 0x200 was SDL_WINDOWEVENT, reserve the number for sdl2-compat */ @@ -94,6 +95,8 @@ EventType :: enum Uint32 { KEYBOARD_ADDED, /**< A new keyboard has been inserted into the system */ KEYBOARD_REMOVED, /**< A keyboard has been removed */ TEXT_EDITING_CANDIDATES, /**< Keyboard text editing candidates */ + SCREEN_KEYBOARD_SHOWN, /**< The on-screen keyboard has been shown */ + SCREEN_KEYBOARD_HIDDEN, /**< The on-screen keyboard has been hidden */ /* Mouse events */ MOUSE_MOTION = 0x400, /**< Mouse moved */ @@ -134,10 +137,15 @@ EventType :: enum Uint32 { FINGER_MOTION, FINGER_CANCELED, + /* Pinch events */ + PINCH_BEGIN = 0x710, /**< Pinch gesture started */ + PINCH_UPDATE, /**< Pinch gesture updated */ + PINCH_END, /**< Pinch gesture ended */ + /* 0x800, 0x801, and 0x802 were the Gesture events from SDL2. Do not reuse these values! sdl2-compat needs them! */ /* Clipboard events */ - CLIPBOARD_UPDATE = 0x900, /**< The clipboard or primary selection changed */ + CLIPBOARD_UPDATE = 0x900, /**< The clipboard changed */ /* Drag and drop events */ DROP_FILE = 0x1000, /**< The system requests a file open */ @@ -431,6 +439,12 @@ TouchFingerEvent :: struct { windowID: WindowID, /**< The window underneath the finger, if any */ } +PinchFingerEvent :: struct { + using commonEvent: CommonEvent, + scale: f32, /**< The scale change since the last SDL_EVENT_PINCH_UPDATE. Scale < 1 is "zoom out". Scale > 1 is "zoom in". */ + windowID: WindowID, /**< The window underneath the finger, if any */ +} + PenProximityEvent :: struct { using commonEvent: CommonEvent, /**< SDL_EVENT_PEN_PROXIMITY_IN or SDL_EVENT_PEN_PROXIMITY_OUT */ windowID: WindowID, /**< The window with pen focus, if any */ @@ -508,7 +522,7 @@ QuitEvent :: struct { } UserEvent :: struct { - using commonEvent: CommonEvent, /**< SDL_EVENT_USER through SDL_EVENT_LAST-1, Uint32 because these are not in the SDL_EventType enumeration */ + using commonEvent: CommonEvent, /**< SDL_EVENT_USER through SDL_EVENT_LAST, Uint32 because these are not in the SDL_EventType enumeration */ windowID: WindowID, /**< The associated window if any */ code: Sint32, /**< User defined event code */ data1: rawptr, /**< User defined data pointer */ @@ -519,44 +533,84 @@ UserEvent :: struct { Event :: struct #raw_union { - type: EventType, /**< Event type, shared with all events, Uint32 to cover user events which are not in the SDL_EventType enumeration */ - common: CommonEvent, /**< Common event data */ - display: DisplayEvent, /**< Display event data */ - window: WindowEvent, /**< Window event data */ - kdevice: KeyboardDeviceEvent, /**< Keyboard device change event data */ - key: KeyboardEvent, /**< Keyboard event data */ - edit: TextEditingEvent, /**< Text editing event data */ - edit_candidates: TextEditingCandidatesEvent, /**< Text editing candidates event data */ - text: TextInputEvent, /**< Text input event data */ - mdevice: MouseDeviceEvent, /**< Mouse device change event data */ - motion: MouseMotionEvent, /**< Mouse motion event data */ - button: MouseButtonEvent, /**< Mouse button event data */ - wheel: MouseWheelEvent, /**< Mouse wheel event data */ - jdevice: JoyDeviceEvent, /**< Joystick device change event data */ - jaxis: JoyAxisEvent, /**< Joystick axis event data */ - jball: JoyBallEvent, /**< Joystick ball event data */ - jhat: JoyHatEvent, /**< Joystick hat event data */ - jbutton: JoyButtonEvent, /**< Joystick button event data */ - jbattery: JoyBatteryEvent, /**< Joystick battery event data */ - gdevice: GamepadDeviceEvent, /**< Gamepad device event data */ - gaxis: GamepadAxisEvent, /**< Gamepad axis event data */ - gbutton: GamepadButtonEvent, /**< Gamepad button event data */ - gtouchpad: GamepadTouchpadEvent, /**< Gamepad touchpad event data */ - gsensor: GamepadSensorEvent, /**< Gamepad sensor event data */ - adevice: AudioDeviceEvent, /**< Audio device event data */ - cdevice: CameraDeviceEvent, /**< Camera device event data */ - sensor: SensorEvent, /**< Sensor event data */ - quit: QuitEvent, /**< Quit request event data */ - user: UserEvent, /**< Custom event data */ - tfinger: TouchFingerEvent, /**< Touch finger event data */ - pproximity: PenProximityEvent, /**< Pen proximity event data */ - ptouch: PenTouchEvent, /**< Pen tip touching event data */ - pmotion: PenMotionEvent, /**< Pen motion event data */ - pbutton: PenButtonEvent, /**< Pen button event data */ - paxis: PenAxisEvent, /**< Pen axis event data */ - render: RenderEvent, /**< Render event data */ - drop: DropEvent, /**< Drag and drop event data */ - clipboard: ClipboardEvent, /**< Clipboard event data */ + /**< Event type, shared with all events, Uint32 to cover user events which are not in the SDL_EventType enumeration */ + type: EventType `raw_union_tag:"type=FIRST"`, + /**< Common event data */ + common: CommonEvent `raw_union_tag:"type=TERMINATE,LOW_MEMORY,WILL_ENTER_BACKGROUND,DID_ENTER_BACKGROUND,WILL_ENTER_FOREGROUND,DID_ENTER_FOREGROUND,LOCALE_CHANGED,SYSTEM_THEME_CHANGED,POLL_SENTINEL"`, + /**< Display event data */ + display: DisplayEvent `raw_union_tag:"type=DISPLAY_ORIENTATION,DISPLAY_ADDED,DISPLAY_REMOVED,DISPLAY_MOVED,DISPLAY_DESKTOP_MODE_CHANGED,DISPLAY_CURRENT_MODE_CHANGED,DISPLAY_CONTENT_SCALE_CHANGED"`, + /**< Window event data */ + window: WindowEvent `raw_union_tag:"type=WINDOW_SHOWN,WINDOW_HIDDEN,WINDOW_EXPOSED,WINDOW_MOVED,WINDOW_RESIZED,WINDOW_PIXEL_SIZE_CHANGED,WINDOW_METAL_VIEW_RESIZED,WINDOW_MINIMIZED,WINDOW_MAXIMIZED,WINDOW_RESTORED,WINDOW_MOUSE_ENTER,WINDOW_MOUSE_LEAVE,WINDOW_FOCUS_GAINED,WINDOW_FOCUS_LOST,WINDOW_CLOSE_REQUESTED,WINDOW_HIT_TEST,WINDOW_ICCPROF_CHANGED,WINDOW_DISPLAY_CHANGED,WINDOW_DISPLAY_SCALE_CHANGED,WINDOW_SAFE_AREA_CHANGED,WINDOW_OCCLUDED,WINDOW_ENTER_FULLSCREEN,WINDOW_LEAVE_FULLSCREEN,WINDOW_DESTROYED"`, + /**< Keyboard device change event data */ + kdevice: KeyboardDeviceEvent `raw_union_tag:"type=KEYMAP_CHANGED,KEYBOARD_ADDED,KEYBOARD_REMOVED"`, + /**< Keyboard event data */ + key: KeyboardEvent `raw_union_tag:"type=KEY_DOWN,KEY_UP"`, + /**< Text editing event data */ + edit: TextEditingEvent `raw_union_tag:"type=TEXT_EDITING"`, + /**< Text editing candidates event data */ + edit_candidates: TextEditingCandidatesEvent `raw_union_tag:"type=TEXT_EDITING_CANDIDATES"`, + /**< Text input event data */ + text: TextInputEvent `raw_union_tag:"type=TEXT_INPUT"`, + /**< Mouse device change event data */ + mdevice: MouseDeviceEvent `raw_union_tag:"type=MOUSE_ADDED,MOUSE_REMOVED"`, + /**< Mouse motion event data */ + motion: MouseMotionEvent `raw_union_tag:"type=MOUSE_MOTION"`, + /**< Mouse button event data */ + button: MouseButtonEvent `raw_union_tag:"type=MOUSE_BUTTON_DOWN,MOUSE_BUTTON_UP"`, + /**< Mouse wheel event data */ + wheel: MouseWheelEvent `raw_union_tag:"type=MOUSE_WHEEL"`, + /**< Joystick device change event data */ + jdevice: JoyDeviceEvent `raw_union_tag:"type=JOYSTICK_ADDED,JOYSTICK_REMOVED,JOYSTICK_UPDATE_COMPLETE"`, + /**< Joystick axis event data */ + jaxis: JoyAxisEvent `raw_union_tag:"type=JOYSTICK_AXIS_MOTION"`, + /**< Joystick ball event data */ + jball: JoyBallEvent `raw_union_tag:"type=JOYSTICK_BALL_MOTION"`, + /**< Joystick hat event data */ + jhat: JoyHatEvent `raw_union_tag:"type=JOYSTICK_HAT_MOTION"`, + /**< Joystick button event data */ + jbutton: JoyButtonEvent `raw_union_tag:"type=JOYSTICK_BUTTON_DOWN,JOYSTICK_BUTTON_UP"`, + /**< Joystick battery event data */ + jbattery: JoyBatteryEvent `raw_union_tag:"type=JOYSTICK_BATTERY_UPDATED"`, + /**< Gamepad device event data */ + gdevice: GamepadDeviceEvent `raw_union_tag:"type=GAMEPAD_ADDED,GAMEPAD_REMOVED,GAMEPAD_REMAPPED,GAMEPAD_UPDATE_COMPLETE,GAMEPAD_STEAM_HANDLE_UPDATED"`, + /**< Gamepad axis event data */ + gaxis: GamepadAxisEvent `raw_union_tag:"type=GAMEPAD_AXIS_MOTION"`, + /**< Gamepad button event data */ + gbutton: GamepadButtonEvent `raw_union_tag:"type=GAMEPAD_BUTTON_DOWN,GAMEPAD_BUTTON_UP"`, + /**< Gamepad touchpad event data */ + gtouchpad: GamepadTouchpadEvent `raw_union_tag:"type=GAMEPAD_TOUCHPAD_DOWN,GAMEPAD_TOUCHPAD_MOTION,GAMEPAD_TOUCHPAD_UP"`, + /**< Gamepad sensor event data */ + gsensor: GamepadSensorEvent `raw_union_tag:"type=GAMEPAD_SENSOR_UPDATE"`, + /**< Audio device event data */ + adevice: AudioDeviceEvent `raw_union_tag:"type=AUDIO_DEVICE_ADDED,AUDIO_DEVICE_REMOVED,AUDIO_DEVICE_FORMAT_CHANGED"`, + /**< Camera device event data */ + cdevice: CameraDeviceEvent `raw_union_tag:"type=CAMERA_DEVICE_ADDED,CAMERA_DEVICE_REMOVED,CAMERA_DEVICE_APPROVED,CAMERA_DEVICE_DENIED"`, + /**< Sensor event data */ + sensor: SensorEvent `raw_union_tag:"type=SENSOR_UPDATE"`, + /**< Quit request event data */ + quit: QuitEvent `raw_union_tag:"type=QUIT"`, + /**< Custom event data */ + user: UserEvent `raw_union_tag:"type=USER"`, + /**< Touch finger event data */ + tfinger: TouchFingerEvent `raw_union_tag:"type=FINGER_DOWN,FINGER_UP,FINGER_MOTION,FINGER_CANCELED"`, + /**< Pinch event data */ + pinch: PinchFingerEvent `raw_union_tag:"type=PINCH_BEGIN,PINCH_UPDATE,PINCH_END"`, + /**< Pen proximity event data */ + pproximity: PenProximityEvent `raw_union_tag:"type=PEN_PROXIMITY_IN,PEN_PROXIMITY_OUT"`, + /**< Pen tip touching event data */ + ptouch: PenTouchEvent `raw_union_tag:"type=PEN_DOWN,PEN_UP"`, + /**< Pen motion event data */ + pmotion: PenMotionEvent `raw_union_tag:"type=PEN_MOTION"`, + /**< Pen button event data */ + pbutton: PenButtonEvent `raw_union_tag:"type=PEN_BUTTON_DOWN,PEN_BUTTON_UP"`, + /**< Pen axis event data */ + paxis: PenAxisEvent `raw_union_tag:"type=PEN_AXIS"`, + /**< Render event data */ + render: RenderEvent `raw_union_tag:"type=RENDER_TARGETS_RESET,RENDER_DEVICE_RESET,RENDER_DEVICE_LOST"`, + /**< Drag and drop event data */ + drop: DropEvent `raw_union_tag:"type=DROP_FILE,DROP_TEXT,DROP_BEGIN,DROP_COMPLETE,DROP_POSITION"`, + /**< Clipboard event data */ + clipboard: ClipboardEvent `raw_union_tag:"type=CLIPBOARD_UPDATE"`, /* This is necessary for ABI compatibility between Visual C++ and GCC. Visual C++ will respect the push pack pragma and use 52 bytes (size of @@ -588,23 +642,24 @@ EventFilter :: proc "c" (userdata: rawptr, event: ^Event) -> bool @(default_calling_convention="c", link_prefix="SDL_", require_results) foreign lib { - PumpEvents :: proc() --- - PeepEvents :: proc(events: [^]Event, numevents: c.int, action: EventAction, minType, maxType: EventType) -> int --- - HasEvent :: proc(type: EventType) -> bool --- - HasEvents :: proc(minType, maxType: EventType) -> bool --- - FlushEvent :: proc(type: EventType) --- - FlushEvents :: proc(minType, maxType: EventType) --- - PollEvent :: proc(event: ^Event) -> bool --- - WaitEvent :: proc(event: ^Event) -> bool --- - WaitEventTimeout :: proc(event: ^Event, timeoutMS: Sint32) -> bool --- - PushEvent :: proc(event: ^Event) -> bool --- - SetEventFilter :: proc(filter: EventFilter, userdata: rawptr) --- - GetEventFilter :: proc(filter: ^EventFilter, userdata: ^rawptr) -> bool --- - AddEventWatch :: proc(filter: EventFilter, userdata: rawptr) -> bool --- - RemoveEventWatch :: proc(filter: EventFilter, userdata: rawptr) --- - FilterEvents :: proc(filter: EventFilter, userdata: rawptr) --- - SetEventEnabled :: proc(type: EventType, enabled: bool) --- - EventEnabled :: proc(type: EventType) -> bool --- - RegisterEvents :: proc(numevents: c.int) -> Uint32 --- - GetWindowFromEvent :: proc(#by_ptr event: Event) -> ^Window --- -} \ No newline at end of file + PumpEvents :: proc() --- + PeepEvents :: proc(events: [^]Event, numevents: c.int, action: EventAction, minType, maxType: EventType) -> int --- + HasEvent :: proc(type: EventType) -> bool --- + HasEvents :: proc(minType, maxType: EventType) -> bool --- + FlushEvent :: proc(type: EventType) --- + FlushEvents :: proc(minType, maxType: EventType) --- + PollEvent :: proc(event: ^Event) -> bool --- + WaitEvent :: proc(event: ^Event) -> bool --- + WaitEventTimeout :: proc(event: ^Event, timeoutMS: Sint32) -> bool --- + PushEvent :: proc(event: ^Event) -> bool --- + SetEventFilter :: proc(filter: EventFilter, userdata: rawptr) --- + GetEventFilter :: proc(filter: ^EventFilter, userdata: ^rawptr) -> bool --- + AddEventWatch :: proc(filter: EventFilter, userdata: rawptr) -> bool --- + RemoveEventWatch :: proc(filter: EventFilter, userdata: rawptr) --- + FilterEvents :: proc(filter: EventFilter, userdata: rawptr) --- + SetEventEnabled :: proc(type: EventType, enabled: bool) --- + EventEnabled :: proc(type: EventType) -> bool --- + RegisterEvents :: proc(numevents: c.int) -> Uint32 --- + GetWindowFromEvent :: proc(#by_ptr event: Event) -> ^Window --- + GetEventDescription :: proc(#by_ptr event: Event, buf: [^]u8, buflen: c.int) -> c.int --- +} diff --git a/vendor/sdl3/sdl3_gamepad.odin b/vendor/sdl3/sdl3_gamepad.odin index 225accaee..2366f8704 100644 --- a/vendor/sdl3/sdl3_gamepad.odin +++ b/vendor/sdl3/sdl3_gamepad.odin @@ -81,29 +81,29 @@ GamepadBindingType :: enum c.int { GamepadBinding :: struct { input_type: GamepadBindingType, input: struct #raw_union { - button: c.int, + button: c.int `raw_union_tag:"input_type=.BUTTON"`, axis: struct { axis: c.int, axis_min: c.int, axis_max: c.int, - }, + } `raw_union_tag:"input_type=.AXIS"`, hat: struct { hat: c.int, hat_mask: c.int, - }, + } `raw_union_tag:"input_type=.HAT"`, }, output_type: GamepadBindingType, output: struct #raw_union { - button: GamepadButton, + button: GamepadButton `raw_union_tag:"output_type=.BUTTON"`, axis: struct { axis: GamepadAxis, axis_min: c.int, axis_max: c.int, - }, + } `raw_union_tag:"output_type=.AXIS"`, }, } diff --git a/vendor/sdl3/sdl3_gpu.odin b/vendor/sdl3/sdl3_gpu.odin index def222739..18b872e95 100644 --- a/vendor/sdl3/sdl3_gpu.odin +++ b/vendor/sdl3/sdl3_gpu.odin @@ -624,10 +624,10 @@ GPURasterizerState :: struct { GPUMultisampleState :: struct { - sample_count: GPUSampleCount, /**< The number of samples to be used in rasterization. */ - sample_mask: Uint32, /**< Reserved for future use. Must be set to 0. */ - enable_mask: bool, /**< Reserved for future use. Must be set to false. */ - _: Uint8, + sample_count: GPUSampleCount, /**< The number of samples to be used in rasterization. */ + sample_mask: Uint32, /**< Reserved for future use. Must be set to 0. */ + enable_mask: bool, /**< Reserved for future use. Must be set to false. */ + enable_alpha_to_coverage: bool, /**< true enables the alpha-to-coverage feature. */ _: Uint8, _: Uint8, } @@ -718,8 +718,8 @@ GPUDepthStencilTargetInfo :: struct { stencil_store_op: GPUStoreOp, /**< What is done with the stencil results of the render pass. */ cycle: bool, /**< true cycles the texture if the texture is bound and any load ops are not LOAD */ clear_stencil: Uint8, /**< The value to clear the stencil component to at the beginning of the render pass. Ignored if GPU_LOADOP_CLEAR is not used. */ - _: Uint8, - _: Uint8, + mip_level: Uint8, /**< The mip level to use as the depth stencil target. */ + layer: Uint8, /**< The layer index to use as the depth stencil target. */ } @@ -765,16 +765,37 @@ GPUStorageTextureReadWriteBinding :: struct { } -PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN :: "SDL.gpu.device.create.debugmode" -PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN :: "SDL.gpu.device.create.preferlowpower" -PROP_GPU_DEVICE_CREATE_NAME_STRING :: "SDL.gpu.device.create.name" -PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN :: "SDL.gpu.device.create.shaders.private" -PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN :: "SDL.gpu.device.create.shaders.spirv" -PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN :: "SDL.gpu.device.create.shaders.dxbc" -PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN :: "SDL.gpu.device.create.shaders.dxil" -PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN :: "SDL.gpu.device.create.shaders.msl" -PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN :: "SDL.gpu.device.create.shaders.metallib" -PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING :: "SDL.gpu.device.create.d3d12.semantic" +PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN :: "SDL.gpu.device.create.debugmode" +PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN :: "SDL.gpu.device.create.preferlowpower" +PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN :: "SDL.gpu.device.create.verbose" +PROP_GPU_DEVICE_CREATE_NAME_STRING :: "SDL.gpu.device.create.name" +PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN :: "SDL.gpu.device.create.feature.clip_distance" +PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN :: "SDL.gpu.device.create.feature.depth_clamping" +PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN :: "SDL.gpu.device.create.feature.indirect_draw_first_instance" +PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN :: "SDL.gpu.device.create.feature.anisotropy" +PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN :: "SDL.gpu.device.create.shaders.private" +PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN :: "SDL.gpu.device.create.shaders.spirv" +PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN :: "SDL.gpu.device.create.shaders.dxbc" +PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN :: "SDL.gpu.device.create.shaders.dxil" +PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN :: "SDL.gpu.device.create.shaders.msl" +PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN :: "SDL.gpu.device.create.shaders.metallib" +PROP_GPU_DEVICE_CREATE_D3D12_ALLOW_FEWER_RESOURCE_SLOTS_BOOLEAN :: "SDL.gpu.device.create.d3d12.allowtier1resourcebinding" +PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING :: "SDL.gpu.device.create.d3d12.semantic" +PROP_GPU_DEVICE_CREATE_D3D12_AGILITY_SDK_VERSION_NUMBER :: "SDL.gpu.device.create.d3d12.agility_sdk_version" +PROP_GPU_DEVICE_CREATE_D3D12_AGILITY_SDK_PATH_STRING :: "SDL.gpu.device.create.d3d12.agility_sdk_path" +PROP_GPU_DEVICE_CREATE_VULKAN_REQUIRE_HARDWARE_ACCELERATION_BOOLEAN :: "SDL.gpu.device.create.vulkan.requirehardwareacceleration" +PROP_GPU_DEVICE_CREATE_VULKAN_OPTIONS_POINTER :: "SDL.gpu.device.create.vulkan.options" +PROP_GPU_DEVICE_CREATE_METAL_ALLOW_MACFAMILY1_BOOLEAN :: "SDL.gpu.device.create.metal.allowmacfamily1" + +GPUVulkanOptions :: struct { + vulkan_api_version: Uint32, /**< The Vulkan API version to request for the instance. Use Vulkan's VK_MAKE_VERSION or VK_MAKE_API_VERSION. */ + feature_list: rawptr, /**< Pointer to the first element of a chain of Vulkan feature structs. (Requires API version 1.1 or higher.)*/ + vulkan_10_physical_device_features: rawptr, /**< Pointer to a VkPhysicalDeviceFeatures struct to enable additional Vulkan 1.0 features. */ + device_extension_count: Uint32, /**< Number of additional device extensions to require. */ + device_extension_names: [^]cstring, /**< Pointer to a list of additional device extensions to require. */ + instance_extension_count: Uint32, /**< Number of additional instance extensions to require. */ + instance_extension_names: [^]cstring, /**< Pointer to a list of additional instance extensions to require. */ +} PROP_GPU_COMPUTEPIPELINE_CREATE_NAME_STRING :: "SDL.gpu.computepipeline.create.name" PROP_GPU_GRAPHICSPIPELINE_CREATE_NAME_STRING :: "SDL.gpu.graphicspipeline.create.name" @@ -790,6 +811,11 @@ PROP_GPU_TEXTURE_CREATE_NAME_STRING :: "SDL.gpu.texture.create.na PROP_GPU_BUFFER_CREATE_NAME_STRING :: "SDL.gpu.buffer.create.name" PROP_GPU_TRANSFERBUFFER_CREATE_NAME_STRING :: "SDL.gpu.transferbuffer.create.name" +PROP_GPU_DEVICE_NAME_STRING :: "SDL.gpu.device.name" +PROP_GPU_DEVICE_DRIVER_NAME_STRING :: "SDL.gpu.device.driver_name" +PROP_GPU_DEVICE_DRIVER_VERSION_STRING :: "SDL.gpu.device.driver_version" +PROP_GPU_DEVICE_DRIVER_INFO_STRING :: "SDL.gpu.device.driver_info" + @(default_calling_convention="c", link_prefix="SDL_", require_results) foreign lib { GPUSupportsShaderFormats :: proc(format_flags: GPUShaderFormat, name: cstring) -> bool --- @@ -801,6 +827,7 @@ foreign lib { GetGPUDriver :: proc(index: c.int) -> cstring --- GetGPUDeviceDriver :: proc(device: ^GPUDevice) -> cstring --- GetGPUShaderFormats :: proc(device: ^GPUDevice) -> GPUShaderFormat --- + GetGPUDeviceProperties :: proc(device: ^GPUDevice) -> PropertiesID --- CreateGPUComputePipeline :: proc(device: ^GPUDevice, #by_ptr createinfo: GPUComputePipelineCreateInfo) -> ^GPUComputePipeline --- CreateGPUGraphicsPipeline :: proc(device: ^GPUDevice, #by_ptr createinfo: GPUGraphicsPipelineCreateInfo) -> ^GPUGraphicsPipeline --- CreateGPUSampler :: proc(device: ^GPUDevice, #by_ptr createinfo: GPUSamplerCreateInfo) -> ^GPUSampler --- @@ -884,6 +911,8 @@ foreign lib { GPUTextureSupportsFormat :: proc(device: ^GPUDevice, format: GPUTextureFormat, type: GPUTextureType, usage: GPUTextureUsageFlags) -> bool --- GPUTextureSupportsSampleCount :: proc(device: ^GPUDevice, format: GPUTextureFormat, sample_count: GPUSampleCount) -> bool --- CalculateGPUTextureFormatSize :: proc(format: GPUTextureFormat, width, height: Uint32, depth_or_layer_count: Uint32) -> Uint32 --- + GetPixelFormatFromGPUTextureFormat :: proc(format: GPUTextureFormat) -> PixelFormat --- + GetGPUTextureFormatFromPixelFormat :: proc(format: PixelFormat) -> GPUTextureFormat --- } diff --git a/vendor/sdl3/sdl3_haptic.odin b/vendor/sdl3/sdl3_haptic.odin index d5efadcf3..adf055ee6 100644 --- a/vendor/sdl3/sdl3_haptic.odin +++ b/vendor/sdl3/sdl3_haptic.odin @@ -5,6 +5,7 @@ import "core:c" Haptic :: struct {} HapticType :: Uint16 +HapticEffectId :: c.int HAPTIC_CONSTANT :: 1<<0 HAPTIC_SINE :: 1<<1 @@ -215,12 +216,12 @@ foreign lib { GetHapticFeatures :: proc(haptic: ^Haptic) -> Uint32 --- GetNumHapticAxes :: proc(haptic: ^Haptic) -> c.int --- HapticEffectSupported :: proc(haptic: ^Haptic, #by_ptr effect: HapticEffect) -> bool --- - CreateHapticEffect :: proc(haptic: ^Haptic, #by_ptr effect: HapticEffect) -> c.int --- - UpdateHapticEffect :: proc(haptic: ^Haptic, effect: c.int, #by_ptr data: HapticEffect) -> bool --- - RunHapticEffect :: proc(haptic: ^Haptic, effect: c.int, iterations: Uint32) -> bool --- - StopHapticEffect :: proc(haptic: ^Haptic, effect: c.int) -> bool --- - DestroyHapticEffect :: proc(haptic: ^Haptic, effect: c.int) --- - GetHapticEffectStatus :: proc(haptic: ^Haptic, effect: c.int) -> bool --- + CreateHapticEffect :: proc(haptic: ^Haptic, #by_ptr effect: HapticEffect) -> HapticEffectId --- + UpdateHapticEffect :: proc(haptic: ^Haptic, effect: HapticEffectId, #by_ptr data: HapticEffect) -> bool --- + RunHapticEffect :: proc(haptic: ^Haptic, effect: HapticEffectId, iterations: Uint32) -> bool --- + StopHapticEffect :: proc(haptic: ^Haptic, effect: HapticEffectId) -> bool --- + DestroyHapticEffect :: proc(haptic: ^Haptic, effect: HapticEffectId) --- + GetHapticEffectStatus :: proc(haptic: ^Haptic, effect: HapticEffectId) -> bool --- SetHapticGain :: proc(haptic: ^Haptic, gain: c.int) -> bool --- SetHapticAutocenter :: proc(haptic: ^Haptic, autocenter: c.int) -> bool --- PauseHaptic :: proc(haptic: ^Haptic) -> bool --- @@ -230,4 +231,4 @@ foreign lib { InitHapticRumble :: proc(haptic: ^Haptic) -> bool --- PlayHapticRumble :: proc(haptic: ^Haptic, strength: f32, length: Uint32) -> bool --- StopHapticRumble :: proc(haptic: ^Haptic) -> bool --- -} \ No newline at end of file +} diff --git a/vendor/sdl3/sdl3_hidapi.odin b/vendor/sdl3/sdl3_hidapi.odin index 6817bffa2..71286cb3d 100644 --- a/vendor/sdl3/sdl3_hidapi.odin +++ b/vendor/sdl3/sdl3_hidapi.odin @@ -75,6 +75,7 @@ hid_device_info :: struct { next: ^hid_device_info, } +PROP_HIDAPI_LIBUSB_DEVICE_HANDLE_POINTER :: "SDL.hidapi.libusb.device.handle" @(default_calling_convention="c", link_prefix="SDL_", require_results) foreign lib { @@ -85,6 +86,7 @@ foreign lib { hid_free_enumeration :: proc(devs: ^hid_device_info) --- hid_open :: proc(vendor_id, product_id: c.ushort, serial_number: [^]c.wchar_t) -> ^hid_device --- hid_open_path :: proc(path: cstring) -> ^hid_device --- + hid_get_properties :: proc(dev: ^hid_device) -> PropertiesID --- hid_write :: proc(dev: ^hid_device, data: [^]byte, length: uint) -> c.int --- hid_read_timeout :: proc(dev: ^hid_device, data: [^]byte, length: uint, milliseconds: c.int) -> c.int --- hid_read :: proc(dev: ^hid_device, data: [^]byte, length: uint) -> c.int --- @@ -100,4 +102,4 @@ foreign lib { hid_get_device_info :: proc(dev: ^hid_device) -> ^hid_device_info --- hid_get_report_descriptor :: proc(dev: ^hid_device, buf: [^]byte, buf_size: uint) -> c.int --- hid_ble_scan :: proc(active: bool) --- -} \ No newline at end of file +} diff --git a/vendor/sdl3/sdl3_hints.odin b/vendor/sdl3/sdl3_hints.odin index 987010c57..ba7e55d3d 100644 --- a/vendor/sdl3/sdl3_hints.odin +++ b/vendor/sdl3/sdl3_hints.odin @@ -95,9 +95,15 @@ HINT_JOYSTICK_HIDAPI_STEAM :: "SDL_JOYSTICK_HIDAPI_STEAM" HINT_JOYSTICK_HIDAPI_STEAM_HOME_LED :: "SDL_JOYSTICK_HIDAPI_STEAM_HOME_LED" HINT_JOYSTICK_HIDAPI_STEAMDECK :: "SDL_JOYSTICK_HIDAPI_STEAMDECK" HINT_JOYSTICK_HIDAPI_STEAM_HORI :: "SDL_JOYSTICK_HIDAPI_STEAM_HORI" +HINT_JOYSTICK_HIDAPI_LG4FF :: "SDL_JOYSTICK_HIDAPI_LG4FF" +HINT_JOYSTICK_HIDAPI_8BITDO :: "SDL_JOYSTICK_HIDAPI_8BITDO" +HINT_JOYSTICK_HIDAPI_SINPUT :: "SDL_JOYSTICK_HIDAPI_SINPUT" +HINT_JOYSTICK_HIDAPI_ZUIKI :: "SDL_JOYSTICK_HIDAPI_ZUIKI" +HINT_JOYSTICK_HIDAPI_FLYDIGI :: "SDL_JOYSTICK_HIDAPI_FLYDIGI" HINT_JOYSTICK_HIDAPI_SWITCH :: "SDL_JOYSTICK_HIDAPI_SWITCH" HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED :: "SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED" HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED :: "SDL_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED" +HINT_JOYSTICK_HIDAPI_SWITCH2 :: "SDL_JOYSTICK_HIDAPI_SWITCH2" HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS :: "SDL_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS" HINT_JOYSTICK_HIDAPI_WII :: "SDL_JOYSTICK_HIDAPI_WII" HINT_JOYSTICK_HIDAPI_WII_PLAYER_LED :: "SDL_JOYSTICK_HIDAPI_WII_PLAYER_LED" @@ -107,6 +113,8 @@ HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED :: "SDL_JOYSTICK_HIDAPI_XBOX_360_PL HINT_JOYSTICK_HIDAPI_XBOX_360_WIRELESS :: "SDL_JOYSTICK_HIDAPI_XBOX_360_WIRELESS" HINT_JOYSTICK_HIDAPI_XBOX_ONE :: "SDL_JOYSTICK_HIDAPI_XBOX_ONE" HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED :: "SDL_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED" +HINT_JOYSTICK_HIDAPI_GIP :: "SDL_JOYSTICK_HIDAPI_GIP" +HINT_JOYSTICK_HIDAPI_GIP_RESET_FOR_METADATA :: "SDL_JOYSTICK_HIDAPI_GIP_RESET_FOR_METADATA" HINT_JOYSTICK_IOKIT :: "SDL_JOYSTICK_IOKIT" HINT_JOYSTICK_LINUX_CLASSIC :: "SDL_JOYSTICK_LINUX_CLASSIC" HINT_JOYSTICK_LINUX_DEADZONES :: "SDL_JOYSTICK_LINUX_DEADZONES" @@ -127,17 +135,20 @@ HINT_JOYSTICK_HAPTIC_AXES :: "SDL_JOYSTICK_HAPTIC_AXES" HINT_KEYCODE_OPTIONS :: "SDL_KEYCODE_OPTIONS" HINT_KMSDRM_DEVICE_INDEX :: "SDL_KMSDRM_DEVICE_INDEX" HINT_KMSDRM_REQUIRE_DRM_MASTER :: "SDL_KMSDRM_REQUIRE_DRM_MASTER" +HINT_KMSDRM_ATOMIC :: "SDL_KMSDRM_ATOMIC" HINT_LOGGING :: "SDL_LOGGING" HINT_MAC_BACKGROUND_APP :: "SDL_MAC_BACKGROUND_APP" HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK :: "SDL_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK" HINT_MAC_OPENGL_ASYNC_DISPATCH :: "SDL_MAC_OPENGL_ASYNC_DISPATCH" HINT_MAC_OPTION_AS_ALT :: "SDL_MAC_OPTION_AS_ALT" HINT_MAC_SCROLL_MOMENTUM :: "SDL_MAC_SCROLL_MOMENTUM" +HINT_MAC_PRESS_AND_HOLD :: "SDL_MAC_PRESS_AND_HOLD" HINT_MAIN_CALLBACK_RATE :: "SDL_MAIN_CALLBACK_RATE" HINT_MOUSE_AUTO_CAPTURE :: "SDL_MOUSE_AUTO_CAPTURE" HINT_MOUSE_DOUBLE_CLICK_RADIUS :: "SDL_MOUSE_DOUBLE_CLICK_RADIUS" HINT_MOUSE_DOUBLE_CLICK_TIME :: "SDL_MOUSE_DOUBLE_CLICK_TIME" HINT_MOUSE_DEFAULT_SYSTEM_CURSOR :: "SDL_MOUSE_DEFAULT_SYSTEM_CURSOR" +HINT_MOUSE_DPI_SCALE_CURSORS :: "SDL_MOUSE_DPI_SCALE_CURSORS" HINT_MOUSE_EMULATE_WARP_WITH_RELATIVE :: "SDL_MOUSE_EMULATE_WARP_WITH_RELATIVE" HINT_MOUSE_FOCUS_CLICKTHROUGH :: "SDL_MOUSE_FOCUS_CLICKTHROUGH" HINT_MOUSE_NORMAL_SPEED_SCALE :: "SDL_MOUSE_NORMAL_SPEED_SCALE" @@ -152,6 +163,7 @@ HINT_NO_SIGNAL_HANDLERS :: "SDL_NO_SIGNAL_HANDLERS" HINT_OPENGL_LIBRARY :: "SDL_OPENGL_LIBRARY" HINT_EGL_LIBRARY :: "SDL_EGL_LIBRARY" HINT_OPENGL_ES_DRIVER :: "SDL_OPENGL_ES_DRIVER" +HINT_OPENGL_FORCE_SRGB_FRAMEBUFFER :: "SDL_OPENGL_FORCE_SRGB_FRAMEBUFFER" HINT_OPENVR_LIBRARY :: "SDL_OPENVR_LIBRARY" HINT_ORIENTATIONS :: "SDL_ORIENTATIONS" HINT_POLL_SENTINEL :: "SDL_POLL_SENTINEL" @@ -159,6 +171,7 @@ HINT_PREFERRED_LOCALES :: "SDL_PREFERRED_LOCALES" HINT_QUIT_ON_LAST_WINDOW_CLOSE :: "SDL_QUIT_ON_LAST_WINDOW_CLOSE" HINT_RENDER_DIRECT3D_THREADSAFE :: "SDL_RENDER_DIRECT3D_THREADSAFE" HINT_RENDER_DIRECT3D11_DEBUG :: "SDL_RENDER_DIRECT3D11_DEBUG" +HINT_RENDER_DIRECT3D11_WARP :: "SDL_RENDER_DIRECT3D11_WARP" HINT_RENDER_VULKAN_DEBUG :: "SDL_RENDER_VULKAN_DEBUG" HINT_RENDER_GPU_DEBUG :: "SDL_RENDER_GPU_DEBUG" HINT_RENDER_GPU_LOW_POWER :: "SDL_RENDER_GPU_LOW_POWER" @@ -169,6 +182,10 @@ HINT_RENDER_VSYNC :: "SDL_RENDER_VSYNC" HINT_RETURN_KEY_HIDES_IME :: "SDL_RETURN_KEY_HIDES_IME" HINT_ROG_GAMEPAD_MICE :: "SDL_ROG_GAMEPAD_MICE" HINT_ROG_GAMEPAD_MICE_EXCLUDED :: "SDL_ROG_GAMEPAD_MICE_EXCLUDED" +HINT_PS2_GS_WIDTH :: "SDL_PS2_GS_WIDTH" +HINT_PS2_GS_HEIGHT :: "SDL_PS2_GS_HEIGHT" +HINT_PS2_GS_PROGRESSIVE :: "SDL_PS2_GS_PROGRESSIVE" +HINT_PS2_GS_MODE :: "SDL_PS2_GS_MODE" HINT_RPI_VIDEO_LAYER :: "SDL_RPI_VIDEO_LAYER" HINT_SCREENSAVER_INHIBIT_ACTIVITY_NAME :: "SDL_SCREENSAVER_INHIBIT_ACTIVITY_NAME" HINT_SHUTDOWN_DBUS_ON_QUIT :: "SDL_SHUTDOWN_DBUS_ON_QUIT" @@ -189,6 +206,8 @@ HINT_VIDEO_EGL_ALLOW_GETDISPLAY_FALLBACK :: "SDL_VIDEO_EGL_ALLOW_GETDISPLAY_ HINT_VIDEO_FORCE_EGL :: "SDL_VIDEO_FORCE_EGL" HINT_VIDEO_MAC_FULLSCREEN_SPACES :: "SDL_VIDEO_MAC_FULLSCREEN_SPACES" HINT_VIDEO_MAC_FULLSCREEN_MENU_VISIBILITY :: "SDL_VIDEO_MAC_FULLSCREEN_MENU_VISIBILITY" +HINT_VIDEO_METAL_AUTO_RESIZE_DRAWABLE :: "SDL_VIDEO_METAL_AUTO_RESIZE_DRAWABLE" +HINT_VIDEO_MATCH_EXCLUSIVE_MODE_ON_MOVE :: "SDL_VIDEO_MATCH_EXCLUSIVE_MODE_ON_MOVE" HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS :: "SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS" HINT_VIDEO_OFFSCREEN_SAVE_FRAMES :: "SDL_VIDEO_OFFSCREEN_SAVE_FRAMES" HINT_VIDEO_SYNC_WINDOW_OPERATIONS :: "SDL_VIDEO_SYNC_WINDOW_OPERATIONS" @@ -263,4 +282,4 @@ foreign lib { ResetHints :: proc() --- AddHintCallback :: proc(name: cstring, callback: HintCallback, userdata: rawptr) -> bool --- RemoveHintCallback :: proc(name: cstring, callback: HintCallback, userdata: rawptr) --- -} \ No newline at end of file +} diff --git a/vendor/sdl3/sdl3_iostream.odin b/vendor/sdl3/sdl3_iostream.odin index 2f89c2ba6..f57dc947d 100644 --- a/vendor/sdl3/sdl3_iostream.odin +++ b/vendor/sdl3/sdl3_iostream.odin @@ -44,6 +44,7 @@ PROP_IOSTREAM_FILE_DESCRIPTOR_NUMBER :: "SDL.iostream.file_descriptor" PROP_IOSTREAM_ANDROID_AASSET_POINTER :: "SDL.iostream.android.aasset" PROP_IOSTREAM_MEMORY_POINTER :: "SDL.iostream.memory.base" PROP_IOSTREAM_MEMORY_SIZE_NUMBER :: "SDL.iostream.memory.size" +PROP_IOSTREAM_MEMORY_FREE_FUNC_POINTER :: "SDL.iostream.memory.free" PROP_IOSTREAM_DYNAMIC_MEMORY_POINTER :: "SDL.iostream.dynamic.memory" PROP_IOSTREAM_DYNAMIC_CHUNKSIZE_NUMBER :: "SDL.iostream.dynamic.chunksize" diff --git a/vendor/sdl3/sdl3_mouse.odin b/vendor/sdl3/sdl3_mouse.odin index 3bc3aa57f..2a087a34c 100644 --- a/vendor/sdl3/sdl3_mouse.odin +++ b/vendor/sdl3/sdl3_mouse.odin @@ -34,6 +34,11 @@ MouseWheelDirection :: enum c.int { FLIPPED, /**< The scroll direction is flipped / natural */ } +CursorFrameInfo :: struct { + surface: ^Surface, + duration: Uint32, +} + MouseButtonFlags :: distinct bit_set[MouseButtonFlag; Uint32] MouseButtonFlag :: enum Uint32 { LEFT = 1 - 1, @@ -55,6 +60,8 @@ BUTTON_RMASK :: MouseButtonFlags{.RIGHT} BUTTON_X1MASK :: MouseButtonFlags{.X1} BUTTON_X2MASK :: MouseButtonFlags{.X2} +MouseMotionTransformCallback :: #type proc "c" (userdata: rawptr, timestamp: Uint64, window: ^Window, mouseID: MouseID, x, y: ^f32) + @(default_calling_convention="c", link_prefix="SDL_", require_results) foreign lib { HasMouse :: proc() -> bool --- @@ -66,11 +73,13 @@ foreign lib { GetRelativeMouseState :: proc(x, y: ^f32) -> MouseButtonFlags --- WarpMouseInWindow :: proc(window: ^Window, x, y: f32) --- WarpMouseGlobal :: proc(x, y: f32) -> bool --- + SetRelativeMouseTransform :: proc(callback: MouseMotionTransformCallback, userdata: rawptr) -> bool --- SetWindowRelativeMouseMode :: proc(window: ^Window, enabled: bool) -> bool --- GetWindowRelativeMouseMode :: proc(window: ^Window) -> bool --- CaptureMouse :: proc(enabled: bool) -> bool --- CreateCursor :: proc(data: [^]byte, mask: [^]Uint8, w, h, hot_x, hot_y: c.int) -> ^Cursor --- CreateColorCursor :: proc(surface: ^Surface, hot_x, hot_y: c.int) -> ^Cursor --- + CreateAnimatedCursor :: proc(frames: [^]CursorFrameInfo, frame_count, hot_x, hot_y: c.int) -> ^Cursor --- CreateSystemCursor :: proc(id: SystemCursor) -> ^Cursor --- SetCursor :: proc(cursor: ^Cursor) -> bool --- GetCursor :: proc() -> ^Cursor --- @@ -79,4 +88,4 @@ foreign lib { ShowCursor :: proc() -> bool --- HideCursor :: proc() -> bool --- CursorVisible :: proc() -> bool --- -} \ No newline at end of file +} diff --git a/vendor/sdl3/sdl3_pen.odin b/vendor/sdl3/sdl3_pen.odin index 81e820e6b..d96848fed 100644 --- a/vendor/sdl3/sdl3_pen.odin +++ b/vendor/sdl3/sdl3_pen.odin @@ -10,13 +10,14 @@ PEN_TOUCHID :: TouchID(1<<64 - 2) PenInputFlags :: distinct bit_set[PenInputFlag; Uint32] PenInputFlag :: enum Uint32 { - DOWN = 0, /**< pen is pressed down */ - BUTTON_1 = 1, /**< button 1 is pressed */ - BUTTON_2 = 2, /**< button 2 is pressed */ - BUTTON_3 = 3, /**< button 3 is pressed */ - BUTTON_4 = 4, /**< button 4 is pressed */ - BUTTON_5 = 5, /**< button 5 is pressed */ - ERASER_TIP = 30, /**< eraser tip is used */ + DOWN = 0, /**< pen is pressed down */ + BUTTON_1 = 1, /**< button 1 is pressed */ + BUTTON_2 = 2, /**< button 2 is pressed */ + BUTTON_3 = 3, /**< button 3 is pressed */ + BUTTON_4 = 4, /**< button 4 is pressed */ + BUTTON_5 = 5, /**< button 5 is pressed */ + ERASER_TIP = 30, /**< eraser tip is used */ + IN_PROXIMITY = 31, /**< pen is in proximity (since SDL 3.4.0) */ } PenAxis :: enum c.int { @@ -27,4 +28,16 @@ PenAxis :: enum c.int { ROTATION, /**< Pen barrel rotation. Bidirectional: -180 to 179.9 (clockwise, 0 is facing up, -180.0 is facing down). */ SLIDER, /**< Pen finger wheel or slider (e.g., Airbrush Pen). Unidirectional: 0 to 1.0 */ TANGENTIAL_PRESSURE, /**< Pressure from squeezing the pen ("barrel pressure"). */ -} \ No newline at end of file +} + +PenDeviceType :: enum c.int { + INVALID = -1, /**< Not a valid pen device. */ + UNKNOWN, /**< Don't know specifics of this pen. */ + DIRECT, /**< Pen touches display. */ + INDIRECT, /**< Pen touches something that isn't the display. */ +} + +@(default_calling_convention="c", link_prefix="SDL_", require_results) +foreign lib { + GetPenDeviceType :: proc(instance_id: PenID) --- +} diff --git a/vendor/sdl3/sdl3_pixels.odin b/vendor/sdl3/sdl3_pixels.odin index a636d13ff..e3a1c1537 100644 --- a/vendor/sdl3/sdl3_pixels.odin +++ b/vendor/sdl3/sdl3_pixels.odin @@ -518,7 +518,7 @@ Colorspace :: enum c.int { SDL_CHROMA_LOCATION_LEFT), */ RGB_DEFAULT = SRGB, /**< The default colorspace for RGB surfaces if no colorspace is specified */ - YUV_DEFAULT = JPEG, /**< The default colorspace for YUV surfaces if no colorspace is specified */ + YUV_DEFAULT = BT601_LIMITED, /**< The default colorspace for YUV surfaces if no colorspace is specified */ } Color :: distinct [4]Uint8 @@ -561,6 +561,6 @@ foreign lib { DestroyPalette :: proc(palette: ^Palette) --- MapRGB :: proc(format: ^PixelFormatDetails, palette: ^Palette, r, g, b: Uint8) -> Uint32 --- MapRGBA :: proc(format: ^PixelFormatDetails, palette: ^Palette, r, g, b, a: Uint8) -> Uint32 --- - GetRGB :: proc(pixel: Uint32, format: ^PixelFormatDetails, palette: ^Palette, r, g, b: ^Uint8) --- - GetRGBA :: proc(pixel: Uint32, format: ^PixelFormatDetails, palette: ^Palette, r, g, b, a: ^Uint8) --- + GetRGB :: proc(pixelvalue: Uint32, format: ^PixelFormatDetails, palette: ^Palette, r, g, b: ^Uint8) --- + GetRGBA :: proc(pixelvalue: Uint32, format: ^PixelFormatDetails, palette: ^Palette, r, g, b, a: ^Uint8) --- } diff --git a/vendor/sdl3/sdl3_process.odin b/vendor/sdl3/sdl3_process.odin index d3ba6f2ba..71686a444 100644 --- a/vendor/sdl3/sdl3_process.odin +++ b/vendor/sdl3/sdl3_process.odin @@ -13,6 +13,7 @@ ProcessIO :: enum c.int { PROP_PROCESS_CREATE_ARGS_POINTER :: "SDL.process.create.args" PROP_PROCESS_CREATE_ENVIRONMENT_POINTER :: "SDL.process.create.environment" +PROP_PROCESS_CREATE_WORKING_DIRECTORY_STRING :: "SDL.process.create.working_directory" PROP_PROCESS_CREATE_STDIN_NUMBER :: "SDL.process.create.stdin_option" PROP_PROCESS_CREATE_STDIN_POINTER :: "SDL.process.create.stdin_source" PROP_PROCESS_CREATE_STDOUT_NUMBER :: "SDL.process.create.stdout_option" @@ -21,6 +22,7 @@ PROP_PROCESS_CREATE_STDERR_NUMBER :: "SDL.process.create.stderr_op PROP_PROCESS_CREATE_STDERR_POINTER :: "SDL.process.create.stderr_source" PROP_PROCESS_CREATE_STDERR_TO_STDOUT_BOOLEAN :: "SDL.process.create.stderr_to_stdout" PROP_PROCESS_CREATE_BACKGROUND_BOOLEAN :: "SDL.process.create.background" +PROP_PROCESS_CREATE_CMDLINE_STRING :: "SDL.process.create.cmdline" PROP_PROCESS_PID_NUMBER :: "SDL.process.pid" PROP_PROCESS_STDIN_POINTER :: "SDL.process.stdin" @@ -39,4 +41,4 @@ foreign lib { KillProcess :: proc(process: ^Process, force: bool) -> bool --- WaitProcess :: proc(process: ^Process, block: bool, exitcode: ^c.int) -> bool --- DestroyProcess :: proc(process: ^Process) --- -} \ No newline at end of file +} diff --git a/vendor/sdl3/sdl3_properties.odin b/vendor/sdl3/sdl3_properties.odin index 73372c290..01bdff59b 100644 --- a/vendor/sdl3/sdl3_properties.odin +++ b/vendor/sdl3/sdl3_properties.odin @@ -4,6 +4,8 @@ import "core:c" PropertiesID :: distinct Uint32 +PROP_NAME_STRING :: "SDL.name" + PropertyType :: enum c.int { INVALID, POINTER, @@ -41,4 +43,4 @@ foreign lib { ClearProperty :: proc(props: PropertiesID, name: cstring) -> bool --- EnumerateProperties :: proc(props: PropertiesID, callback: EnumeratePropertiesCallback, userdata: rawptr) -> bool --- DestroyProperties :: proc(props: PropertiesID) --- -} \ No newline at end of file +} diff --git a/vendor/sdl3/sdl3_render.odin b/vendor/sdl3/sdl3_render.odin index 5af4bb055..fd5b0705e 100644 --- a/vendor/sdl3/sdl3_render.odin +++ b/vendor/sdl3/sdl3_render.odin @@ -4,6 +4,7 @@ import "core:c" SOFTWARE_RENDERER :: "software" +GPU_RENDER :: "gpu" Vertex :: struct { position: FPoint, /**< Vertex position, in SDL_Renderer coordinates */ @@ -17,6 +18,13 @@ TextureAccess :: enum c.int { TARGET, /**< Texture can be used as a render target */ } +TextureAddressMode :: enum c.int { + INVALID = -1, + AUTO, /**< Wrapping is enabled if texture coordinates are outside [0, 1], this is the default */ + CLAMP, /**< Texture coordinates are clamped to the [0, 1] range */ + WRAP, /**< The texture is repeated (tiled) */ +} + RendererLogicalPresentation :: enum c.int { DISABLED, /**< There is no logical size in effect */ STRETCH, /**< The rendered content is stretched to the output resolution */ @@ -40,6 +48,10 @@ PROP_RENDERER_CREATE_WINDOW_POINTER :: "SDL.renderer PROP_RENDERER_CREATE_SURFACE_POINTER :: "SDL.renderer.create.surface" PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER :: "SDL.renderer.create.output_colorspace" PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER :: "SDL.renderer.create.present_vsync" +PROP_RENDERER_CREATE_GPU_DEVICE_POINTER :: "SDL.renderer.create.gpu.device" +PROP_RENDERER_CREATE_GPU_SHADERS_SPIRV_BOOLEAN :: "SDL.renderer.create.gpu.shaders_spirv" +PROP_RENDERER_CREATE_GPU_SHADERS_DXIL_BOOLEAN :: "SDL.renderer.create.gpu.shaders_dxil" +PROP_RENDERER_CREATE_GPU_SHADERS_MSL_BOOLEAN :: "SDL.renderer.create.gpu.shaders_msl" PROP_RENDERER_CREATE_VULKAN_INSTANCE_POINTER :: "SDL.renderer.create.vulkan.instance" PROP_RENDERER_CREATE_VULKAN_SURFACE_NUMBER :: "SDL.renderer.create.vulkan.surface" PROP_RENDERER_CREATE_VULKAN_PHYSICAL_DEVICE_POINTER :: "SDL.renderer.create.vulkan.physical_device" @@ -53,6 +65,7 @@ PROP_RENDERER_SURFACE_POINTER :: "SDL.renderer.surface PROP_RENDERER_VSYNC_NUMBER :: "SDL.renderer.vsync" PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER :: "SDL.renderer.max_texture_size" PROP_RENDERER_TEXTURE_FORMATS_POINTER :: "SDL.renderer.texture_formats" +PROP_RENDERER_TEXTURE_WRAPPING_BOOLEAN :: "SDL.renderer.texture_wrapping" PROP_RENDERER_OUTPUT_COLORSPACE_NUMBER :: "SDL.renderer.output_colorspace" PROP_RENDERER_HDR_ENABLED_BOOLEAN :: "SDL.renderer.HDR_enabled" PROP_RENDERER_SDR_WHITE_POINT_FLOAT :: "SDL.renderer.SDR_white_point" @@ -72,29 +85,35 @@ PROP_RENDERER_VULKAN_PRESENT_QUEUE_FAMILY_INDEX_NUMBER :: "SDL.renderer.vulkan. PROP_RENDERER_VULKAN_SWAPCHAIN_IMAGE_COUNT_NUMBER :: "SDL.renderer.vulkan.swapchain_image_count" PROP_RENDERER_GPU_DEVICE_POINTER :: "SDL.renderer.gpu.device" -PROP_TEXTURE_CREATE_COLORSPACE_NUMBER :: "SDL.texture.create.colorspace" -PROP_TEXTURE_CREATE_FORMAT_NUMBER :: "SDL.texture.create.format" -PROP_TEXTURE_CREATE_ACCESS_NUMBER :: "SDL.texture.create.access" -PROP_TEXTURE_CREATE_WIDTH_NUMBER :: "SDL.texture.create.width" -PROP_TEXTURE_CREATE_HEIGHT_NUMBER :: "SDL.texture.create.height" -PROP_TEXTURE_CREATE_SDR_WHITE_POINT_FLOAT :: "SDL.texture.create.SDR_white_point" -PROP_TEXTURE_CREATE_HDR_HEADROOM_FLOAT :: "SDL.texture.create.HDR_headroom" -PROP_TEXTURE_CREATE_D3D11_TEXTURE_POINTER :: "SDL.texture.create.d3d11.texture" -PROP_TEXTURE_CREATE_D3D11_TEXTURE_U_POINTER :: "SDL.texture.create.d3d11.texture_u" -PROP_TEXTURE_CREATE_D3D11_TEXTURE_V_POINTER :: "SDL.texture.create.d3d11.texture_v" -PROP_TEXTURE_CREATE_D3D12_TEXTURE_POINTER :: "SDL.texture.create.d3d12.texture" -PROP_TEXTURE_CREATE_D3D12_TEXTURE_U_POINTER :: "SDL.texture.create.d3d12.texture_u" -PROP_TEXTURE_CREATE_D3D12_TEXTURE_V_POINTER :: "SDL.texture.create.d3d12.texture_v" -PROP_TEXTURE_CREATE_METAL_PIXELBUFFER_POINTER :: "SDL.texture.create.metal.pixelbuffer" -PROP_TEXTURE_CREATE_OPENGL_TEXTURE_NUMBER :: "SDL.texture.create.opengl.texture" -PROP_TEXTURE_CREATE_OPENGL_TEXTURE_UV_NUMBER :: "SDL.texture.create.opengl.texture_uv" -PROP_TEXTURE_CREATE_OPENGL_TEXTURE_U_NUMBER :: "SDL.texture.create.opengl.texture_u" -PROP_TEXTURE_CREATE_OPENGL_TEXTURE_V_NUMBER :: "SDL.texture.create.opengl.texture_v" -PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_NUMBER :: "SDL.texture.create.opengles2.texture" -PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_UV_NUMBER :: "SDL.texture.create.opengles2.texture_uv" -PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_U_NUMBER :: "SDL.texture.create.opengles2.texture_u" -PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_V_NUMBER :: "SDL.texture.create.opengles2.texture_v" -PROP_TEXTURE_CREATE_VULKAN_TEXTURE_NUMBER :: "SDL.texture.create.vulkan.texture" +PROP_TEXTURE_CREATE_COLORSPACE_NUMBER :: "SDL.texture.create.colorspace" +PROP_TEXTURE_CREATE_FORMAT_NUMBER :: "SDL.texture.create.format" +PROP_TEXTURE_CREATE_ACCESS_NUMBER :: "SDL.texture.create.access" +PROP_TEXTURE_CREATE_WIDTH_NUMBER :: "SDL.texture.create.width" +PROP_TEXTURE_CREATE_HEIGHT_NUMBER :: "SDL.texture.create.height" +PROP_TEXTURE_CREATE_PALETTE_POINTER :: "SDL.texture.create.palette" +PROP_TEXTURE_CREATE_SDR_WHITE_POINT_FLOAT :: "SDL.texture.create.SDR_white_point" +PROP_TEXTURE_CREATE_HDR_HEADROOM_FLOAT :: "SDL.texture.create.HDR_headroom" +PROP_TEXTURE_CREATE_D3D11_TEXTURE_POINTER :: "SDL.texture.create.d3d11.texture" +PROP_TEXTURE_CREATE_D3D11_TEXTURE_U_POINTER :: "SDL.texture.create.d3d11.texture_u" +PROP_TEXTURE_CREATE_D3D11_TEXTURE_V_POINTER :: "SDL.texture.create.d3d11.texture_v" +PROP_TEXTURE_CREATE_D3D12_TEXTURE_POINTER :: "SDL.texture.create.d3d12.texture" +PROP_TEXTURE_CREATE_D3D12_TEXTURE_U_POINTER :: "SDL.texture.create.d3d12.texture_u" +PROP_TEXTURE_CREATE_D3D12_TEXTURE_V_POINTER :: "SDL.texture.create.d3d12.texture_v" +PROP_TEXTURE_CREATE_METAL_PIXELBUFFER_POINTER :: "SDL.texture.create.metal.pixelbuffer" +PROP_TEXTURE_CREATE_OPENGL_TEXTURE_NUMBER :: "SDL.texture.create.opengl.texture" +PROP_TEXTURE_CREATE_OPENGL_TEXTURE_UV_NUMBER :: "SDL.texture.create.opengl.texture_uv" +PROP_TEXTURE_CREATE_OPENGL_TEXTURE_U_NUMBER :: "SDL.texture.create.opengl.texture_u" +PROP_TEXTURE_CREATE_OPENGL_TEXTURE_V_NUMBER :: "SDL.texture.create.opengl.texture_v" +PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_NUMBER :: "SDL.texture.create.opengles2.texture" +PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_UV_NUMBER :: "SDL.texture.create.opengles2.texture_uv" +PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_U_NUMBER :: "SDL.texture.create.opengles2.texture_u" +PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_V_NUMBER :: "SDL.texture.create.opengles2.texture_v" +PROP_TEXTURE_CREATE_VULKAN_TEXTURE_NUMBER :: "SDL.texture.create.vulkan.texture" +PROP_TEXTURE_CREATE_VULKAN_LAYOUT_NUMBER :: "SDL.texture.create.vulkan.layout" +PROP_TEXTURE_CREATE_GPU_TEXTURE_POINTER :: "SDL.texture.create.gpu.texture" +PROP_TEXTURE_CREATE_GPU_TEXTURE_UV_POINTER :: "SDL.texture.create.gpu.texture_uv" +PROP_TEXTURE_CREATE_GPU_TEXTURE_U_POINTER :: "SDL.texture.create.gpu.texture_u" +PROP_TEXTURE_CREATE_GPU_TEXTURE_V_POINTER :: "SDL.texture.create.gpu.texture_v" PROP_TEXTURE_COLORSPACE_NUMBER :: "SDL.texture.colorspace" PROP_TEXTURE_FORMAT_NUMBER :: "SDL.texture.format" @@ -122,6 +141,10 @@ PROP_TEXTURE_OPENGLES2_TEXTURE_U_NUMBER :: "SDL.texture.opengles2.textur PROP_TEXTURE_OPENGLES2_TEXTURE_V_NUMBER :: "SDL.texture.opengles2.texture_v" PROP_TEXTURE_OPENGLES2_TEXTURE_TARGET_NUMBER :: "SDL.texture.opengles2.target" PROP_TEXTURE_VULKAN_TEXTURE_NUMBER :: "SDL.texture.vulkan.texture" +PROP_TEXTURE_GPU_TEXTURE_POINTER :: "SDL.texture.gpu.texture" +PROP_TEXTURE_GPU_TEXTURE_UV_POINTER :: "SDL.texture.gpu.texture_uv" +PROP_TEXTURE_GPU_TEXTURE_U_POINTER :: "SDL.texture.gpu.texture_u" +PROP_TEXTURE_GPU_TEXTURE_V_POINTER :: "SDL.texture.gpu.texture_v" RENDERER_VSYNC_DISABLED :: 0 RENDERER_VSYNC_ADAPTIVE :: -1 @@ -134,6 +157,8 @@ foreign lib { GetRenderDriver :: proc(index: c.int) -> cstring --- CreateRenderer :: proc(window: ^Window, name: cstring) -> ^Renderer --- CreateRendererWithProperties :: proc(props: PropertiesID) -> ^Renderer --- + CreateGPURenderer :: proc(device: ^GPUDevice, window: ^Window) -> ^Renderer --- + GetGPURendererDevice :: proc(device: ^Renderer) -> ^GPUDevice --- CreateSoftwareRenderer :: proc(surface: ^Surface) -> ^Renderer --- GetRenderer :: proc(window: ^Window) -> ^Renderer --- GetRenderWindow :: proc(renderer: ^Renderer) -> ^Window --- @@ -158,6 +183,8 @@ foreign lib { GetRenderOutputSize :: proc(renderer: ^Renderer, w, h: ^c.int) -> bool --- GetCurrentRenderOutputSize :: proc(renderer: ^Renderer, w, h: ^c.int) -> bool --- GetTextureSize :: proc(texture: ^Texture, w, h: ^f32) -> bool --- + SetTexturePalette :: proc(texture: ^Texture, palette: ^Palette) -> bool --- + GetTexturePalette :: proc(texture: ^Texture) -> ^Palette --- SetTextureColorMod :: proc(texture: ^Texture, r, g, b: Uint8) -> bool --- SetTextureColorModFloat :: proc(texture: ^Texture, r, g, b: f32) -> bool --- GetTextureColorMod :: proc(texture: ^Texture, r, g, b: ^Uint8) -> bool --- @@ -208,12 +235,15 @@ foreign lib { RenderFillRect :: proc(renderer: ^Renderer, rect: Maybe(^FRect)) -> bool --- RenderFillRects :: proc(renderer: ^Renderer, rects: [^]FRect, count: c.int) -> bool --- RenderTexture :: proc(renderer: ^Renderer, texture: ^Texture, srcrect, dstrect: Maybe(^FRect)) -> bool --- - RenderTextureRotated :: proc(renderer: ^Renderer, texture: ^Texture, srcrect, dstrect: Maybe(^FRect), angle: f64, #by_ptr center: FPoint, flip: FlipMode) -> bool --- + RenderTextureRotated :: proc(renderer: ^Renderer, texture: ^Texture, srcrect, dstrect: Maybe(^FRect), angle: f64, center: Maybe(^FPoint), flip: FlipMode) -> bool --- RenderTextureAffine :: proc(renderer: ^Renderer, texture: ^Texture, srcrect: Maybe(^FRect), origin, right, down: Maybe(^FPoint)) -> bool --- RenderTextureTiled :: proc(renderer: ^Renderer, texture: ^Texture, srcrect: Maybe(^FRect), scale: f32, dstrect: Maybe(^FRect)) -> bool --- RenderTexture9Grid :: proc(renderer: ^Renderer, texture: ^Texture, srcrect: Maybe(^FRect), left_width, right_width, top_height, bottom_height: f32, scale: f32, dstrect: Maybe(^FRect)) -> bool --- + RenderTexture9GridTiled :: proc(renderer: ^Renderer, texture: ^Texture, srcrect: Maybe(^FRect), left_width, right_width, top_height, bottom_height: f32, scale: f32, dstrect: Maybe(^FRect), tileScale: f32) -> bool --- RenderGeometry :: proc(renderer: ^Renderer, texture: ^Texture, vertices: [^]Vertex, num_vertices: c.int, indices: [^]c.int, num_indices: c.int) -> bool --- RenderGeometryRaw :: proc(renderer: ^Renderer, texture: ^Texture, xy: [^]f32, xy_stride: c.int, color: [^]FColor, color_stride: c.int, uv: [^]f32, uv_stride: c.int, num_vertices: c.int, indices: rawptr, num_indices: c.int, size_indices: c.int) -> bool --- + SetRenderTextureAddressMode :: proc(renderer: ^Renderer, u_mode, v_mode: TextureAddressMode) -> bool --- + GetRenderTextureAddressMode :: proc(renderer: ^Renderer, u_mode, v_mode: ^TextureAddressMode) -> bool --- RenderPresent :: proc(renderer: ^Renderer) -> bool --- DestroyTexture :: proc(texture: ^Texture) --- DestroyRenderer :: proc(renderer: ^Renderer) --- @@ -223,4 +253,28 @@ foreign lib { GetRenderVSync :: proc(renderer: ^Renderer, vsync: ^c.int) -> bool --- RenderDebugText :: proc(renderer: ^Renderer, x, y: f32, str: cstring) -> bool --- RenderDebugTextFormat :: proc(renderer: ^Renderer, x, y: f32, fmt: cstring, #c_vararg args: ..any) -> bool --- -} \ No newline at end of file + SetDefaultTextureAddressMode :: proc(renderer: ^Renderer, scale_mode: ScaleMode) -> bool --- + GetDefaultTextureAddressMode :: proc(renderer: ^Renderer, scale_mode: ^ScaleMode) -> bool --- +} + + +GPURenderStateCreateInfo :: struct { + fragment_shader: ^GPUShader, /**< The fragment shader to use when this render state is active */ + num_sampler_bindings: Sint32, /**< The number of additional fragment samplers to bind when this render state is active */ + sampler_bindings: [^]GPUTextureSamplerBinding, /**< Additional fragment samplers to bind when this render state is active */ + num_storage_textures: Sint32, /**< The number of storage textures to bind when this render state is active */ + storage_textures: [^]^GPUTexture, /**< Storage textures to bind when this render state is active */ + num_storage_buffers: Sint32, /**< The number of storage buffers to bind when this render state is active */ + storage_buffers: [^]^GPUBuffer, /**< Storage buffers to bind when this render state is active */ + props: PropertiesID, /**< A properties ID for extensions. Should be 0 if no extensions are needed. */ +} + +GPURenderState :: struct {} + +@(default_calling_convention="c", link_prefix="SDL_", require_results) +foreign lib { + CreateGPURenderState :: proc(renderer: ^Renderer, #by_ptr createinfo: GPURenderStateCreateInfo) -> ^GPURenderState --- + SetGPURenderStateFragmentUniforms :: proc(state: ^GPURenderState, slot_index: Uint32, data: rawptr, length: Uint32) -> bool --- + SetGPURenderState :: proc(renderer: ^Renderer, state: ^GPURenderState) -> bool --- + DestroyGPURenderState :: proc(renderer: ^Renderer) --- +} diff --git a/vendor/sdl3/sdl3_surface.odin b/vendor/sdl3/sdl3_surface.odin index 526940147..9aaf54cec 100644 --- a/vendor/sdl3/sdl3_surface.odin +++ b/vendor/sdl3/sdl3_surface.odin @@ -23,14 +23,16 @@ MUSTLOCK :: proc "c" (S: ^Surface) -> bool { ScaleMode :: enum c.int { INVALID = -1, - NEAREST, /**< nearest pixel sampling */ - LINEAR, /**< linear filtering */ + NEAREST, /**< nearest pixel sampling */ + LINEAR, /**< linear filtering */ + PIXELART, /**< nearest pixel sampling with improved scaling for pixel art, available since SDL 3.4.0 */ } FlipMode :: enum c.int { - NONE, /**< Do not flip */ - HORIZONTAL, /**< flip horizontally */ - VERTICAL, /**< flip vertically */ + NONE, /**< Do not flip */ + HORIZONTAL, /**< flip horizontally */ + VERTICAL, /**< flip vertically */ + HORIZONTAL_AND_VERTICAL = HORIZONTAL | VERTICAL, /**< flip horizontally and vertically (not a diagonal flip) */ } Surface :: struct { @@ -51,6 +53,7 @@ PROP_SURFACE_HDR_HEADROOM_FLOAT :: "SDL.surface.HDR_headroom" PROP_SURFACE_TONEMAP_OPERATOR_STRING :: "SDL.surface.tonemap" PROP_SURFACE_HOTSPOT_X_NUMBER :: "SDL.surface.hotspot.x" PROP_SURFACE_HOTSPOT_Y_NUMBER :: "SDL.surface.hotspot.y" +PROP_SURFACE_ROTATION_FLOAT :: "SDL.surface.rotation" @(default_calling_convention="c", link_prefix="SDL_") foreign lib { @@ -69,10 +72,16 @@ foreign lib { RemoveSurfaceAlternateImages :: proc(surface: ^Surface) --- LockSurface :: proc(surface: ^Surface) -> bool --- UnlockSurface :: proc(surface: ^Surface) --- + LoadSurface_IO :: proc(src: ^IOStream, closeio: bool) -> ^Surface --- + LoadSurface :: proc(file: cstring) -> ^Surface --- LoadBMP_IO :: proc(src: ^IOStream, closeio: bool) -> ^Surface --- LoadBMP :: proc(file: cstring) -> ^Surface --- SaveBMP_IO :: proc(surface: ^Surface, dst: ^IOStream, closeio: bool) -> bool --- SaveBMP :: proc(surface: ^Surface, file: cstring) -> bool --- + LoadPNG_IO :: proc(src: ^IOStream, closeio: bool) -> ^Surface --- + LoadPNG :: proc(file: cstring) -> ^Surface --- + SavePNG_IO :: proc(surface: ^Surface, dst: ^IOStream, closeio: bool) -> bool --- + SavePNG :: proc(surface: ^Surface, file: cstring) -> bool --- SetSurfaceRLE :: proc(surface: ^Surface, enabled: bool) -> bool --- SurfaceHasRLE :: proc(surface: ^Surface) -> bool --- SetSurfaceColorKey :: proc(surface: ^Surface, enabled: bool, key: Uint32) -> bool --- @@ -87,6 +96,7 @@ foreign lib { SetSurfaceClipRect :: proc(surface: ^Surface, rect: Maybe(^Rect)) -> bool --- GetSurfaceClipRect :: proc(surface: ^Surface, rect: ^Rect) -> bool --- FlipSurface :: proc(surface: ^Surface, flip: FlipMode) -> bool --- + RotateSurface :: proc(surface: ^Surface, angle: f32) -> ^Surface --- DuplicateSurface :: proc(surface: ^Surface) -> ^Surface --- ScaleSurface :: proc(surface: ^Surface, width, height: c.int, scaleMode: ScaleMode) -> ^Surface --- ConvertSurface :: proc(surface: ^Surface, format: PixelFormat) -> ^Surface --- @@ -112,4 +122,4 @@ foreign lib { ReadSurfacePixelFloat :: proc(surface: ^Surface, x, y: c.int, r, g, b, a: ^f32) -> bool --- WriteSurfacePixel :: proc(surface: ^Surface, x, y: c.int, r, g, b, a: Uint8) -> bool --- WriteSurfacePixelFloat :: proc(surface: ^Surface, x, y: c.int, r, g, b, a: f32) -> bool --- -} \ No newline at end of file +} diff --git a/vendor/sdl3/sdl3_version.odin b/vendor/sdl3/sdl3_version.odin index fbc90e220..271771a4b 100644 --- a/vendor/sdl3/sdl3_version.odin +++ b/vendor/sdl3/sdl3_version.odin @@ -3,8 +3,8 @@ package sdl3 import "core:c" MAJOR_VERSION :: 3 -MINOR_VERSION :: 2 -MICRO_VERSION :: 16 +MINOR_VERSION :: 4 +MICRO_VERSION :: 2 @(require_results) VERSIONNUM :: #force_inline proc "c" (major, minor, patch: c.int) -> c.int { return (major * 1000000) + (minor * 1000) + patch } @(require_results) VERSIONNUM_MAJOR :: #force_inline proc "c" (version: c.int) -> c.int { return version / 1000000 } diff --git a/vendor/sdl3/sdl3_video.odin b/vendor/sdl3/sdl3_video.odin index 6761bee56..e4547d991 100644 --- a/vendor/sdl3/sdl3_video.odin +++ b/vendor/sdl3/sdl3_video.odin @@ -61,6 +61,7 @@ WindowFlag :: enum Uint64 { TOOLTIP = 18, POPUP_MENU = 19, KEYBOARD_GRABBED = 20, + FILL_DOCUMENT = 21, VULKAN = 28, METAL = 29, @@ -133,6 +134,15 @@ FlashOperation :: enum c.int { UNTIL_FOCUSED, /**< Flash the window until it gets focus */ } +ProgressState :: enum c.int { + INVALID = -1, /**< An invalid progress state indicating an error; check SDL_GetError() */ + NONE, /**< No progress bar is shown */ + INDETERMINATE, /**< The progress bar is shown in a indeterminate state */ + NORMAL, /**< The progress bar is shown in a normal state */ + PAUSED, /**< The progress bar is shown in a paused state */ + ERROR, /**< The progress bar is shown in a state indicating the application had an error */ +} + GLContextState :: struct {} GLContext :: ^GLContextState EGLDisplay :: distinct rawptr @@ -167,7 +177,7 @@ GLAttr :: enum c.int { CONTEXT_FLAGS, /**< some combination of 0 or more of elements of the SDL_GLContextFlag enumeration; defaults to 0. */ CONTEXT_PROFILE_MASK, /**< type of GL context (Core, Compatibility, ES). See SDL_GLProfile; default value depends on platform. */ SHARE_WITH_CURRENT_CONTEXT, /**< OpenGL context sharing; defaults to 0. */ - FRAMEBUFFER_SRGB_CAPABLE, /**< requests sRGB capable visual; defaults to 0. */ + FRAMEBUFFER_SRGB_CAPABLE, /**< requests sRGB-capable visual if 1. Defaults to -1 ("don't care"). This is a request; GL drivers might not comply! */ CONTEXT_RELEASE_BEHAVIOR, /**< sets context the release behavior. See SDL_GLContextReleaseFlag; defaults to FLUSH. */ CONTEXT_RESET_NOTIFICATION, /**< set context reset notification. See SDL_GLContextResetNotification; defaults to NO_NOTIFICATION. */ CONTEXT_NO_ERROR, @@ -275,12 +285,15 @@ PROP_WINDOW_CREATE_X_NUMBER :: "SDL.window.create.x" PROP_WINDOW_CREATE_Y_NUMBER :: "SDL.window.create.y" PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER :: "SDL.window.create.cocoa.window" PROP_WINDOW_CREATE_COCOA_VIEW_POINTER :: "SDL.window.create.cocoa.view" +PROP_WINDOW_CREATE_WINDOWSCENE_POINTER :: "SDL.window.create.uikit.windowscene" PROP_WINDOW_CREATE_WAYLAND_SURFACE_ROLE_CUSTOM_BOOLEAN :: "SDL.window.create.wayland.surface_role_custom" PROP_WINDOW_CREATE_WAYLAND_CREATE_EGL_WINDOW_BOOLEAN :: "SDL.window.create.wayland.create_egl_window" PROP_WINDOW_CREATE_WAYLAND_WL_SURFACE_POINTER :: "SDL.window.create.wayland.wl_surface" PROP_WINDOW_CREATE_WIN32_HWND_POINTER :: "SDL.window.create.win32.hwnd" PROP_WINDOW_CREATE_WIN32_PIXEL_FORMAT_HWND_POINTER :: "SDL.window.create.win32.pixel_format_hwnd" PROP_WINDOW_CREATE_X11_WINDOW_NUMBER :: "SDL.window.create.x11.window" +PROP_WINDOW_CREATE_EMSCRIPTEN_CANVAS_ID_STRING :: "SDL.window.create.emscripten.canvas_id" +PROP_WINDOW_CREATE_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING :: "SDL.window.create.emscripten.keyboard_element" PROP_WINDOW_SHAPE_POINTER :: "SDL.window.shape" PROP_WINDOW_HDR_ENABLED_BOOLEAN :: "SDL.window.HDR_enabled" @@ -298,7 +311,7 @@ PROP_WINDOW_KMSDRM_DRM_FD_NUMBER :: "SDL.window.kmsdrm.drm_ PROP_WINDOW_KMSDRM_GBM_DEVICE_POINTER :: "SDL.window.kmsdrm.gbm_dev" PROP_WINDOW_COCOA_WINDOW_POINTER :: "SDL.window.cocoa.window" PROP_WINDOW_COCOA_METAL_VIEW_TAG_NUMBER :: "SDL.window.cocoa.metal_view_tag" -PROP_WINDOW_OPENVR_OVERLAY_ID :: "SDL.window.openvr.overlay_id" +PROP_WINDOW_OPENVR_OVERLAY_ID_NUMBER :: "SDL.window.openvr.overlay_id" PROP_WINDOW_VIVANTE_DISPLAY_POINTER :: "SDL.window.vivante.display" PROP_WINDOW_VIVANTE_WINDOW_POINTER :: "SDL.window.vivante.window" PROP_WINDOW_VIVANTE_SURFACE_POINTER :: "SDL.window.vivante.surface" @@ -317,6 +330,8 @@ PROP_WINDOW_WAYLAND_XDG_POSITIONER_POINTER :: "SDL.window.wayland.xdg PROP_WINDOW_X11_DISPLAY_POINTER :: "SDL.window.x11.display" PROP_WINDOW_X11_SCREEN_NUMBER :: "SDL.window.x11.screen" PROP_WINDOW_X11_WINDOW_NUMBER :: "SDL.window.x11.window" +PROP_WINDOW_EMSCRIPTEN_CANVAS_ID_STRING :: "SDL.window.emscripten.canvas_id" +PROP_WINDOW_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING :: "SDL.window.emscripten.keyboard_element" WINDOW_SURFACE_VSYNC_DISABLED :: 0 WINDOW_SURFACE_VSYNC_ADAPTIVE :: -1 @@ -377,6 +392,7 @@ foreign lib { SetWindowBordered :: proc(window: ^Window, bordered: bool) -> bool --- SetWindowResizable :: proc(window: ^Window, resizable: bool) -> bool --- SetWindowAlwaysOnTop :: proc(window: ^Window, on_top: bool) -> bool --- + SetWindowFillDocument :: proc(window: ^Window, fill: bool) -> bool --- ShowWindow :: proc(window: ^Window) -> bool --- HideWindow :: proc(window: ^Window) -> bool --- RaiseWindow :: proc(window: ^Window) -> bool --- @@ -427,6 +443,10 @@ foreign lib { SetWindowHitTest :: proc(window: ^Window, callback: HitTest, callback_data: rawptr) -> bool --- SetWindowShape :: proc(window: ^Window, shape: ^Surface) -> bool --- FlashWindow :: proc(window: ^Window, operation: FlashOperation) -> bool --- + SetWindowProgressState :: proc(window: ^Window, state: ProgressState) -> bool --- + GetWindowProgressState :: proc(window: ^Window) -> ProgressState --- + SetWindowProgressValue :: proc(window: ^Window, value: f32) -> bool --- + GetWindowProgressValue :: proc(window: ^Window) -> f32 --- DestroyWindow :: proc(window: ^Window) --- ScreenSaverEnabled :: proc() -> bool --- EnableScreenSaver :: proc() -> bool --- @@ -461,4 +481,4 @@ foreign lib { // Used by vendor:OpenGL gl_set_proc_address :: proc(p: rawptr, name: cstring) { (^FunctionPointer)(p)^ = GL_GetProcAddress(name) -} \ No newline at end of file +} diff --git a/vendor/stb/image/stb_image_wasm.odin b/vendor/stb/image/stb_image_wasm.odin index f43012383..cfad4725a 100644 --- a/vendor/stb/image/stb_image_wasm.odin +++ b/vendor/stb/image/stb_image_wasm.odin @@ -1,4 +1,4 @@ #+build wasm32, wasm64p32 package stb_image -@(require) import _ "vendor:libc" +@(require) import _ "vendor:libc-shim" diff --git a/vendor/stb/lib/stb_vorbis_wasm.o b/vendor/stb/lib/stb_vorbis_wasm.o new file mode 100644 index 000000000..156696d78 Binary files /dev/null and b/vendor/stb/lib/stb_vorbis_wasm.o differ diff --git a/vendor/stb/rect_pack/stb_rect_pack_wasm.odin b/vendor/stb/rect_pack/stb_rect_pack_wasm.odin index c4e2e5160..c9b6f3de8 100644 --- a/vendor/stb/rect_pack/stb_rect_pack_wasm.odin +++ b/vendor/stb/rect_pack/stb_rect_pack_wasm.odin @@ -1,4 +1,4 @@ #+build wasm32, wasm64p32 package stb_rect_pack -@(require) import _ "vendor:libc" +@(require) import _ "vendor:libc-shim" diff --git a/vendor/stb/src/Makefile b/vendor/stb/src/Makefile index 194ea5e75..521eead93 100644 --- a/vendor/stb/src/Makefile +++ b/vendor/stb/src/Makefile @@ -8,12 +8,13 @@ endif wasm: mkdir -p ../lib - $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image.c -o ../lib/stb_image_wasm.o -DSTBI_NO_STDIO - $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image_write.c -o ../lib/stb_image_write_wasm.o -DSTBI_WRITE_NO_STDIO - $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image_resize.c -o ../lib/stb_image_resize_wasm.o - $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_truetype.c -o ../lib/stb_truetype_wasm.o - # $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_vorbis.c -o ../lib/stb_vorbis_wasm.o -DSTB_VORBIS_NO_STDIO - $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_rect_pack.c -o ../lib/stb_rect_pack_wasm.o + $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc-shim stb_image.c -o ../lib/stb_image_wasm.o -DSTBI_NO_STDIO + $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc-shim stb_image_write.c -o ../lib/stb_image_write_wasm.o -DSTBI_WRITE_NO_STDIO + $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc-shim stb_image_resize.c -o ../lib/stb_image_resize_wasm.o + $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc-shim stb_truetype.c -o ../lib/stb_truetype_wasm.o + # Pretends to be emscripten so stb vorbis takes the right code path for including alloca.h + $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc-shim stb_vorbis.c -o ../lib/stb_vorbis_wasm.o -DSTB_VORBIS_NO_STDIO -D__EMSCRIPTEN__ + $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc-shim stb_rect_pack.c -o ../lib/stb_rect_pack_wasm.o $(CC) -c -Os --target=wasm32 stb_sprintf.c -o ../lib/stb_sprintf_wasm.o unix: diff --git a/vendor/stb/truetype/stb_truetype_wasm.odin b/vendor/stb/truetype/stb_truetype_wasm.odin index f36239086..727ba3ef0 100644 --- a/vendor/stb/truetype/stb_truetype_wasm.odin +++ b/vendor/stb/truetype/stb_truetype_wasm.odin @@ -1,4 +1,4 @@ #+build wasm32, wasm64p32 package stb_truetype -@(require) import _ "vendor:libc" +@(require) import _ "vendor:libc-shim" diff --git a/vendor/stb/vorbis/stb_vorbis.odin b/vendor/stb/vorbis/stb_vorbis.odin index 38bba4f29..7dbfafab8 100644 --- a/vendor/stb/vorbis/stb_vorbis.odin +++ b/vendor/stb/vorbis/stb_vorbis.odin @@ -1,13 +1,14 @@ // Bindings for [[ stb_vorbis.c ; https://github.com/nothings/stb/blob/master/stb_vorbis.c ]]. package stb_vorbis -import c "core:c/libc" +import c "core:c" @(private) LIB :: ( "../lib/stb_vorbis.lib" when ODIN_OS == .Windows else "../lib/stb_vorbis.a" when ODIN_OS == .Linux else "../lib/darwin/stb_vorbis.a" when ODIN_OS == .Darwin + else "../lib/stb_vorbis_wasm.o" when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 else "" ) @@ -15,12 +16,18 @@ when LIB != "" { when !#exists(LIB) { #panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`") } +} +when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 { + foreign import lib "../lib/stb_vorbis_wasm.o" +} else when LIB != "" { foreign import lib { LIB } } else { foreign import lib "system:stb_vorbis" } +NO_STDIO :: ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 + /////////// THREAD SAFETY // Individual stb_vorbis* handles are not thread-safe; you cannot decode from @@ -190,11 +197,13 @@ foreign lib { @(default_calling_convention="c", link_prefix="stb_vorbis_") foreign lib { - // decode an entire file and output the data interleaved into a malloc()ed - // buffer stored in *output. The return value is the number of samples - // decoded, or -1 if the file could not be opened or was not an ogg vorbis file. - // When you're done with it, just free() the pointer returned in *output. - decode_filename :: proc(filename: cstring, channels, sample_rate: ^c.int, output: ^[^]c.short) -> c.int --- + when !NO_STDIO { + // decode an entire file and output the data interleaved into a malloc()ed + // buffer stored in *output. The return value is the number of samples + // decoded, or -1 if the file could not be opened or was not an ogg vorbis file. + // When you're done with it, just free() the pointer returned in *output. + decode_filename :: proc(filename: cstring, channels, sample_rate: ^c.int, output: ^[^]c.short) -> c.int --- + } decode_memory :: proc(mem: [^]byte, len: c.int, channels, sample_rate: ^c.int, output: ^[^]c.short) -> c.int --- @@ -204,28 +213,30 @@ foreign lib { open_memory :: proc(data: [^]byte, len: c.int, error: ^Error, alloc_buffer: ^vorbis_alloc) -> ^vorbis --- - // create an ogg vorbis decoder from a filename via fopen(). on failure, - // returns NULL and sets *error (possibly to VORBIS_file_open_failure). - open_filename :: proc(filename: cstring, - error: ^Error, alloc_buffer: ^vorbis_alloc) -> ^vorbis --- + when !NO_STDIO { + // create an ogg vorbis decoder from a filename via fopen(). on failure, + // returns NULL and sets *error (possibly to VORBIS_file_open_failure). + open_filename :: proc(filename: cstring, + error: ^Error, alloc_buffer: ^vorbis_alloc) -> ^vorbis --- - // create an ogg vorbis decoder from an open FILE *, looking for a stream at - // the _current_ seek point (ftell). on failure, returns NULL and sets *error. - // note that stb_vorbis must "own" this stream; if you seek it in between - // calls to stb_vorbis, it will become confused. Moreover, if you attempt to - // perform stb_vorbis_seek_*() operations on this file, it will assume it - // owns the _entire_ rest of the file after the start point. Use the next - // function, stb_vorbis_open_file_section(), to limit it. - open_file :: proc(f: ^c.FILE, close_handle_on_close: b32, - error: ^Error, alloc_buffer: ^vorbis_alloc) -> ^vorbis --- + // create an ogg vorbis decoder from an open FILE *, looking for a stream at + // the _current_ seek point (ftell). on failure, returns NULL and sets *error. + // note that stb_vorbis must "own" this stream; if you seek it in between + // calls to stb_vorbis, it will become confused. Moreover, if you attempt to + // perform stb_vorbis_seek_*() operations on this file, it will assume it + // owns the _entire_ rest of the file after the start point. Use the next + // function, stb_vorbis_open_file_section(), to limit it. + open_file :: proc(f: ^c.FILE, close_handle_on_close: b32, + error: ^Error, alloc_buffer: ^vorbis_alloc) -> ^vorbis --- - // create an ogg vorbis decoder from an open FILE *, looking for a stream at - // the _current_ seek point (ftell); the stream will be of length 'len' bytes. - // on failure, returns NULL and sets *error. note that stb_vorbis must "own" - // this stream; if you seek it in between calls to stb_vorbis, it will become - // confused. - open_file_section :: proc(f: ^c.FILE, close_handle_on_close: b32, - error: ^Error, alloc_buffer: ^vorbis_alloc, len: c.uint) -> ^vorbis --- + // create an ogg vorbis decoder from an open FILE *, looking for a stream at + // the _current_ seek point (ftell); the stream will be of length 'len' bytes. + // on failure, returns NULL and sets *error. note that stb_vorbis must "own" + // this stream; if you seek it in between calls to stb_vorbis, it will become + // confused. + open_file_section :: proc(f: ^c.FILE, close_handle_on_close: b32, + error: ^Error, alloc_buffer: ^vorbis_alloc, len: c.uint) -> ^vorbis --- + } // these functions seek in the Vorbis file to (approximately) 'sample_number'. // after calling seek_frame(), the next call to get_frame_*() will include diff --git a/vendor/stb/vorbis/stb_vorbis_wasm.odin b/vendor/stb/vorbis/stb_vorbis_wasm.odin new file mode 100644 index 000000000..324b7e025 --- /dev/null +++ b/vendor/stb/vorbis/stb_vorbis_wasm.odin @@ -0,0 +1,4 @@ +#+build wasm32, wasm64p32 +package stb_vorbis + +@(require) import _ "vendor:libc-shim" diff --git a/vendor/wasm/WebGL/webgl.odin b/vendor/wasm/WebGL/webgl.odin index 5616f3660..6338d6271 100644 --- a/vendor/wasm/WebGL/webgl.odin +++ b/vendor/wasm/WebGL/webgl.odin @@ -3,6 +3,7 @@ package webgl foreign import "webgl" import glm "core:math/linalg/glsl" +import "base:runtime" Enum :: distinct u32 @@ -25,6 +26,12 @@ ContextAttribute :: enum u32 { } ContextAttributes :: distinct bit_set[ContextAttribute; u32] +ActiveInfo :: struct { + size: int, + type: Enum, + name: string, +} + DEFAULT_CONTEXT_ATTRIBUTES :: ContextAttributes{} @(default_calling_convention="contextless") @@ -45,6 +52,7 @@ foreign webgl { GetError :: proc() -> Enum --- IsExtensionSupported :: proc(name: string) -> bool --- + GetExtension :: proc(name: string) --- ActiveTexture :: proc(x: Enum) --- AttachShader :: proc(program: Program, shader: Shader) --- @@ -106,10 +114,12 @@ foreign webgl { Flush :: proc() --- FramebufferRenderbuffer :: proc(target, attachment, renderbufertarget: Enum, renderbuffer: Renderbuffer) --- FramebufferTexture2D :: proc(target, attachment, textarget: Enum, texture: Texture, level: i32) --- + CheckFramebufferStatus :: proc(target: Enum) -> Enum --- FrontFace :: proc(mode: Enum) --- GenerateMipmap :: proc(target: Enum) --- + GetBufferParameter :: proc(target, name: Enum) -> int --- GetAttribLocation :: proc(program: Program, name: string) -> i32 --- GetUniformLocation :: proc(program: Program, name: string) -> i32 --- GetVertexAttribOffset :: proc(index: i32, pname: Enum) -> uintptr --- @@ -260,7 +270,6 @@ UniformMatrix4fv :: proc "contextless" (location: i32, m: glm.mat4) { value := transmute([4*4]f32)m _UniformMatrix4fv(location, &value[0]) } - GetShaderiv :: proc "contextless" (shader: Shader, pname: Enum) -> (p: i32) { foreign webgl { @(link_name="GetShaderiv") @@ -270,6 +279,79 @@ GetShaderiv :: proc "contextless" (shader: Shader, pname: Enum) -> (p: i32) { return } +GetActiveAttribBuf :: proc "contextless" (program: Program, index: u32, name_buf: []byte) -> (info: ActiveInfo) { + foreign webgl { + @(link_name="GetActiveAttrib") + _GetActiveAttrib :: proc "contextless" (shader: Program, index: u32, size: ^int, type: ^Enum, name_buf: []byte, name_len: ^int) --- + } + name_len: int + _GetActiveAttrib(program, index, &info.size, &info.type, name_buf, &name_len) + info.name = string(name_buf[:name_len]) + return +} + +GetActiveAttribAlloc :: proc(program: Program, index: u32, allocator: runtime.Allocator, loc := #caller_location) -> (info: ActiveInfo) { + foreign webgl { + @(link_name="GetActiveAttrib") + _GetActiveAttrib :: proc "contextless" (shader: Program, index: u32, size: ^int, type: ^Enum, name_buf: []byte, name_len: ^int) --- + } + + name_len: int + + // Passing {} to the buf but giving it a name_len ptr will write the needed len into that int + _GetActiveAttrib(program, index, &info.size, &info.type, {}, &name_len) + + if name_len > 0 { + name_buf := make([]byte, name_len, allocator, loc) + _GetActiveAttrib(program, index, &info.size, &info.type, name_buf, &name_len) + assert(name_len == len(name_buf)) + info.name = string(name_buf[:name_len]) + } + + return +} + +GetActiveAttrib :: proc { + GetActiveAttribBuf, + GetActiveAttribAlloc, +} + +GetActiveUniformBuf :: proc "contextless" (program: Program, index: u32, name_buf: []byte) -> (info: ActiveInfo) { + foreign webgl { + @(link_name="GetActiveUniform") + _GetActiveUniform :: proc "contextless" (shader: Program, index: u32, size: ^int, type: ^Enum, name_buf: []byte, name_len: ^int) --- + } + name_len: int + _GetActiveUniform(program, index, &info.size, &info.type, name_buf, &name_len) + info.name = string(name_buf[:name_len]) + return +} + +GetActiveUniformAlloc :: proc(program: Program, index: u32, allocator: runtime.Allocator, loc := #caller_location) -> (info: ActiveInfo) { + foreign webgl { + @(link_name="GetActiveUniform") + _GetActiveUniform :: proc "contextless" (shader: Program, index: u32, size: ^int, type: ^Enum, name_buf: []byte, name_len: ^int) --- + } + + name_len: int + + // Passing {} to the buf but giving it a name_len ptr will write the needed len into that int + _GetActiveUniform(program, index, &info.size, &info.type, {}, &name_len) + + if name_len > 0 { + name_buf := make([]byte, name_len, allocator, loc) + _GetActiveUniform(program, index, &info.size, &info.type, name_buf, &name_len) + assert(name_len == len(name_buf)) + info.name = string(name_buf[:name_len]) + } + + return +} + +GetActiveUniform :: proc { + GetActiveUniformBuf, + GetActiveUniformAlloc, +} GetProgramInfoLog :: proc "contextless" (program: Program, buf: []byte) -> string { foreign webgl { @@ -293,7 +375,21 @@ GetShaderInfoLog :: proc "contextless" (shader: Shader, buf: []byte) -> string { return string(buf[:length]) } +IterateSupportedExtensions :: proc(index: ^int, buf: []byte) -> (string, bool) { + foreign webgl { + @(link_name="GetSupportedExtensionFromIndex") + _GetSupportedExtensionFromIndex :: proc "contextless" (index: int, buf: []byte, length: ^int) -> bool --- + } + length: int + if !_GetSupportedExtensionFromIndex(index^, buf[:], &length) { + return "", false + } + + index^ += 1 + + return string(buf[:length]), true +} BufferDataSlice :: proc "contextless" (target: Enum, slice: $S/[]$E, usage: Enum) { BufferData(target, len(slice)*size_of(E), raw_data(slice), usage) diff --git a/vendor/wasm/WebGL/webgl2.odin b/vendor/wasm/WebGL/webgl2.odin index 66a739303..677287bd1 100644 --- a/vendor/wasm/WebGL/webgl2.odin +++ b/vendor/wasm/WebGL/webgl2.odin @@ -3,6 +3,7 @@ package webgl foreign import "webgl2" import "base:intrinsics" +import "base:runtime" import glm "core:math/linalg/glsl" Query :: distinct u32 @@ -34,6 +35,7 @@ foreign webgl2 { RenderbufferStorageMultisample :: proc(target: Enum, samples: i32, internalformat: Enum, width, height: i32) --- /* Texture objects */ + TexStorage2D :: proc(target: Enum, levels: i32, internalformat: Enum, width, height: i32) --- TexStorage3D :: proc(target: Enum, levels: i32, internalformat: Enum, width, height, depth: i32) --- TexImage3D :: proc(target: Enum, level: i32, internalformat: Enum, width, height, depth: i32, border: i32, format, type: Enum, size: int, data: rawptr) --- TexSubImage3D :: proc(target: Enum, level: i32, xoffset, yoffset, zoffset, width, height, depth: i32, format, type: Enum, size: int, data: rawptr) --- @@ -103,14 +105,21 @@ foreign webgl2 { GetUniformBlockIndex :: proc(program: Program, uniformBlockName: string) -> i32 --- UniformBlockBinding :: proc(program: Program, uniformBlockIndex: i32, uniformBlockBinding: i32) --- + // if `pname` is `UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES` then an array will be written at + // `params`, in that case the length `params` need to have is given first querying using `pname` + // `UNIFORM_BLOCK_ACTIVE_UNIFORMS`. + GetActiveUniformBlockParameter :: proc(program: Program, uniformBlockIndex: i32, pname: Enum, params: [^]i32) --- + GetActiveUniforms :: proc(program: Program, uniformIndices: []u32, pname: Enum, res: [^]i32) --- + CreateVertexArray :: proc() -> VertexArrayObject --- DeleteVertexArray :: proc(vertexArray: VertexArrayObject) --- IsVertexArray :: proc(vertexArray: VertexArrayObject) -> bool --- BindVertexArray :: proc(vertexArray: VertexArrayObject) --- } -GetActiveUniformBlockName :: proc(program: Program, uniformBlockIndex: i32, buf: []byte) -> string { +GetActiveUniformBlockNameBuf :: proc(program: Program, uniformBlockIndex: i32, buf: []byte) -> string { foreign webgl2 { + @(link_name="GetActiveUniformBlockName") _GetActiveUniformBlockName :: proc "contextless" (program: Program, uniformBlockIndex: i32, buf: []byte, length: ^int) --- } n: int @@ -118,6 +127,28 @@ GetActiveUniformBlockName :: proc(program: Program, uniformBlockIndex: i32, buf: return string(buf[:n]) } +GetActiveUniformBlockNameAlloc :: proc(program: Program, uniformBlockIndex: i32, allocator: runtime.Allocator, loc := #caller_location) -> string { + foreign webgl2 { + @(link_name="GetActiveUniformBlockName") + _GetActiveUniformBlockName :: proc "contextless" (program: Program, uniformBlockIndex: i32, buf: []byte, length: ^int) --- + } + n: int + _GetActiveUniformBlockName(program, uniformBlockIndex, {}, &n) + + if n > 0 { + buf := make([]byte, n, allocator, loc) + _GetActiveUniformBlockName(program, uniformBlockIndex, buf, &n) + assert(n == len(buf)) + return string(buf[:n]) + } + + return "" +} + +GetActiveUniformBlockName :: proc { + GetActiveUniformBlockNameBuf, + GetActiveUniformBlockNameAlloc, +} Uniform1uiv :: proc "contextless" (location: i32, v: u32) { Uniform1ui(location, v) @@ -134,6 +165,7 @@ Uniform4uiv :: proc "contextless" (location: i32, v: glm.uvec4) { UniformMatrix3x2fv :: proc "contextless" (location: i32, m: glm.mat3x2) { foreign webgl2 { + @(link_name="UniformMatrix3x2fv") _UniformMatrix3x2fv :: proc "contextless" (location: i32, addr: [^]f32) --- } array := intrinsics.matrix_flatten(m) @@ -141,6 +173,7 @@ UniformMatrix3x2fv :: proc "contextless" (location: i32, m: glm.mat3x2) { } UniformMatrix4x2fv :: proc "contextless" (location: i32, m: glm.mat4x2) { foreign webgl2 { + @(link_name="UniformMatrix4x2fv") _UniformMatrix4x2fv :: proc "contextless" (location: i32, addr: [^]f32) --- } array := intrinsics.matrix_flatten(m) @@ -148,6 +181,7 @@ UniformMatrix4x2fv :: proc "contextless" (location: i32, m: glm.mat4x2) { } UniformMatrix2x3fv :: proc "contextless" (location: i32, m: glm.mat2x3) { foreign webgl2 { + @(link_name="UniformMatrix2x3fv") _UniformMatrix2x3fv :: proc "contextless" (location: i32, addr: [^]f32) --- } array := intrinsics.matrix_flatten(m) @@ -155,6 +189,7 @@ UniformMatrix2x3fv :: proc "contextless" (location: i32, m: glm.mat2x3) { } UniformMatrix4x3fv :: proc "contextless" (location: i32, m: glm.mat4x3) { foreign webgl2 { + @(link_name="UniformMatrix4x3fv") _UniformMatrix4x3fv :: proc "contextless" (location: i32, addr: [^]f32) --- } array := intrinsics.matrix_flatten(m) @@ -162,6 +197,7 @@ UniformMatrix4x3fv :: proc "contextless" (location: i32, m: glm.mat4x3) { } UniformMatrix2x4fv :: proc "contextless" (location: i32, m: glm.mat2x4) { foreign webgl2 { + @(link_name="UniformMatrix2x4fv") _UniformMatrix2x4fv :: proc "contextless" (location: i32, addr: [^]f32) --- } array := intrinsics.matrix_flatten(m) @@ -169,6 +205,7 @@ UniformMatrix2x4fv :: proc "contextless" (location: i32, m: glm.mat2x4) { } UniformMatrix3x4fv :: proc "contextless" (location: i32, m: glm.mat3x4) { foreign webgl2 { + @(link_name="UniformMatrix3x4fv") _UniformMatrix3x4fv :: proc "contextless" (location: i32, addr: [^]f32) --- } array := intrinsics.matrix_flatten(m) diff --git a/vendor/wgpu/wgpu.js b/vendor/wgpu/wgpu.js index 6104417df..df3be2e2d 100644 --- a/vendor/wgpu/wgpu.js +++ b/vendor/wgpu/wgpu.js @@ -3265,6 +3265,10 @@ class WebGPUObjectManager { * @returns {number} */ create(object) { + if (object === null) { + return 0; + } + this.objects[this.idx] = { references: 1, object }; this.idx += 1; return this.idx; @@ -3280,6 +3284,10 @@ class WebGPUObjectManager { /** @param {number} idx */ release(idx) { + if (idx === 0) { + return; + } + this.objects[idx-1].references -= 1; if (this.objects[idx-1].references == 0) { delete this.objects[idx-1]; @@ -3288,6 +3296,10 @@ class WebGPUObjectManager { /** @param {number} idx */ reference(idx) { + if (idx === 0) { + return; + } + this.objects[idx-1].references += 1; } diff --git a/vendor/x11/xlib/xlib_keysym.odin b/vendor/x11/xlib/xlib_keysym.odin index 61284c723..267b77b1c 100644 --- a/vendor/x11/xlib/xlib_keysym.odin +++ b/vendor/x11/xlib/xlib_keysym.odin @@ -1,7 +1,7 @@ #+build linux, freebsd, openbsd package xlib -KeySym :: enum u32 { +KeySym :: enum uint { XK_BackSpace = 0xff08, /* Back space, back char */ XK_Tab = 0xff09, XK_Linefeed = 0xff0a, /* Linefeed, LF */ diff --git a/vendor/x11/xlib/xlib_procs.odin b/vendor/x11/xlib/xlib_procs.odin index c33c6d351..3ab4acd17 100644 --- a/vendor/x11/xlib/xlib_procs.odin +++ b/vendor/x11/xlib/xlib_procs.odin @@ -13,7 +13,8 @@ foreign xcursor { cursorGetDefaultSize :: proc(display: ^Display) -> i32 --- cursorLibraryLoadCursor :: proc(display: ^Display, name: cstring) -> Cursor --- cursorLibraryLoadImage :: proc(name: cstring, theme: cstring, size: i32) -> rawptr --- - cursorImageLoadCursor :: proc(display: ^Display, img: rawptr) -> Cursor --- + cursorImageCreate :: proc(width: i32, height: i32) -> ^CursorImage --- + cursorImageLoadCursor :: proc(display: ^Display, img: ^CursorImage) -> Cursor --- cursorImageDestroy :: proc(img: rawptr) --- } @@ -234,14 +235,14 @@ foreign xlib { display: ^Display, window: Window, attr_mask: WindowAttributeMask, - attr: ^XWindowAttributes, + attr: ^XSetWindowAttributes, ) --- SetWindowBackground :: proc( display: ^Display, window: Window, pixel: uint, ) --- - SetWindowBackgroundMap :: proc( + SetWindowBackgroundPixmap :: proc( display: ^Display, window: Window, pixmap: Pixmap, @@ -1112,15 +1113,15 @@ foreign xlib { SetAfterFunction :: proc( display: ^Display, procedure: #type proc "c" (display: ^Display) -> i32, - ) -> i32 --- + ) -> proc "c" (display: ^Display) -> i32 --- Synchronize :: proc( display: ^Display, onoff: b32, - ) -> i32 --- + ) -> proc "c" (display: ^Display) -> i32 --- // Error handling SetErrorHandler :: proc( handler: #type proc "c" (display: ^Display, event: ^XErrorEvent) -> i32, - ) -> i32 --- + ) -> proc "c" (display: ^Display, event: ^XErrorEvent) -> i32 --- GetErrorText :: proc( display: ^Display, code: i32, @@ -1138,7 +1139,7 @@ foreign xlib { DisplayName :: proc(string: cstring) -> cstring --- SetIOErrorHandler :: proc( handler: #type proc "c" (display: ^Display) -> i32, - ) -> i32 --- + ) -> proc "c" (display: ^Display) -> i32 --- // Pointer grabbing GrabPointer :: proc( display: ^Display, @@ -2068,7 +2069,7 @@ foreign xlib { Xutf8LookupString :: proc( ic: XIC, event: ^XKeyPressedEvent, - buffer_return: ^cstring, + buffer_return: cstring, bytes_buffer: i32, keysym_return: ^KeySym, status_return: ^LookupStringStatus, diff --git a/vendor/x11/xlib/xlib_types.odin b/vendor/x11/xlib/xlib_types.odin index a73b8e8b8..bdbaf441e 100644 --- a/vendor/x11/xlib/xlib_types.odin +++ b/vendor/x11/xlib/xlib_types.odin @@ -2257,3 +2257,16 @@ XIRawEvent :: struct { raw_values: [^]f64, } +CursorUInt :: u32 +CursorDim :: u32 +CursorPixel :: u32 +CursorImage :: struct { + version: CursorDim, + size: CursorDim, + width: CursorDim, + height: CursorDim, + xhot: CursorDim, + yhot: CursorDim, + delay: CursorUInt, + pixels: ^CursorPixel, // ARGB +}